mirror of
https://github.com/tiennm99/tiennm99bot.git
synced 2026-10-11 03:13:46 +00:00
feat(amlich): hint ambiguous leap-month input and flag disputed month boundaries
- /duonglich appends a nhuan hint when the queried month is also that lunar year's leap month and the exact leap date exists - both commands append a caveat when the result falls in a lunar month starting or ending on one of the seven razor-edge boundaries from 2072 on (new moon within ~2 minutes of UTC+7 midnight) - freeze the verified 1800-2199 month structure as golden testdata so a self-consistent engine change cannot silently shift boundaries - close known-issues open questions 1 and 2
This commit is contained in:
1 parent
f475a5cb46
commit
86c52170de
7 files changed
+669
-12
No files matched your search
+23
-12
@@ -35,8 +35,11 @@ Both dates are pinned in `lunar_test.go` `knownDates` so a future
|
|||||||
**Razor-edge lunations from 2072 on.** New moon within ~2 minutes of UTC+7
|
**Razor-edge lunations from 2072 on.** New moon within ~2 minutes of UTC+7
|
||||||
midnight, so the month boundary — and therefore output within roughly 30 days
|
midnight, so the month boundary — and therefore output within roughly 30 days
|
||||||
of it — may differ by one day from future official tables: 09/12/2072,
|
of it — may differ by one day from future official tables: 09/12/2072,
|
||||||
15/11/2077, 07/05/2130, 26/05/2150, 17/05/2159, 22/01/2175, 26/01/2199. Not
|
15/11/2077, 07/05/2130, 26/05/2150, 17/05/2159, 22/01/2175, 26/01/2199. Those
|
||||||
fixable today, only documentable. The bot gives no caveat for these dates.
|
are the disputed new-moon days themselves; the engine begins each of these
|
||||||
|
months on the following day (`disputedMonthStarts` in `lunar.go`). Not fixable
|
||||||
|
today. Both commands append a caveat when the result falls in a lunar month
|
||||||
|
that starts or ends on one of these boundaries.
|
||||||
|
|
||||||
**ΔT extrapolation drift.** The two-branch polynomial diverges from actual
|
**ΔT extrapolation drift.** The two-branch polynomial diverges from actual
|
||||||
Earth rotation (ΔT has been roughly flat near 69 s since ~2016 against
|
Earth rotation (ΔT has been roughly flat near 69 s since ~2016 against
|
||||||
@@ -64,7 +67,9 @@ source will see a mismatch that is not an error.
|
|||||||
**`/duonglich` defaults inside leap months.** A bare day argument fills in the
|
**`/duonglich` defaults inside leap months.** A bare day argument fills in the
|
||||||
current month as a regular month; the leap month requires the explicit `nhuan`
|
current month as a regular month; the leap month requires the explicit `nhuan`
|
||||||
flag. In leap years such as 2028 (leap 5) and 2031 (leap 3) this is ambiguous
|
flag. In leap years such as 2028 (leap 5) and 2031 (leap 3) this is ambiguous
|
||||||
to the user, but the output is correct for what was entered.
|
to the user, but the output is correct for what was entered. When the queried
|
||||||
|
month is also that year's leap month (and the exact leap date exists), the
|
||||||
|
reply appends a hint suggesting the `nhuan` flag.
|
||||||
|
|
||||||
## Handled, with regression tests
|
## Handled, with regression tests
|
||||||
|
|
||||||
@@ -77,14 +82,20 @@ to the user, but the output is correct for what was entered.
|
|||||||
|
|
||||||
## Open questions
|
## Open questions
|
||||||
|
|
||||||
1. Should the seven razor-edge lunations from 2072 on carry a caveat in the
|
1. ~~Should the seven razor-edge lunations carry a caveat?~~ Resolved: both
|
||||||
bot's reply? Currently silent.
|
commands append a caveat for results in the lunar months touching those
|
||||||
2. Should pre-1968 UTC+8 be modelled explicitly? The current algorithm matches
|
boundaries — months only, not the whole lunar year.
|
||||||
the published record on both known razor-edge cases by numeric coincidence
|
2. ~~Should pre-1968 UTC+8 be modelled explicitly?~~ Closed: don't build. Per
|
||||||
rather than by rule. An explicit UTC+8 mode would change roughly 1/24 of
|
Hồ Ngọc Đức's historic-calendar notes it is not even a single rule — the
|
||||||
pre-1968 month boundaries and diverge from the standard everyone else uses —
|
North used UTC+8 from 1945–67, but the South used UTC+7 until 1959 and
|
||||||
not worth doing unless a user reports a concrete mismatch.
|
UTC+8 only from 1960–67, with dynastic tables before 1945. Any concrete
|
||||||
|
user-reported mismatch gets a doc note, not a mode.
|
||||||
3. Revisit the ΔT model if the flat IERS trend persists. A data-driven update
|
3. Revisit the ΔT model if the flat IERS trend persists. A data-driven update
|
||||||
only pays off near razor-edge boundaries.
|
only pays off near razor-edge boundaries — and would diverge from the
|
||||||
|
reference algorithm the whole ecosystem runs, so it needs official tables
|
||||||
|
as cover before it is worth it.
|
||||||
4. Watch for state calendar bureau tables published past 2100; they would be
|
4. Watch for state calendar bureau tables published past 2100; they would be
|
||||||
the first ground truth for the 2072+ disputes.
|
the first ground truth for the 2072+ disputes. Related far-future
|
||||||
|
uncertainty in the same bucket: the CGPM votes in late 2026 on abolishing
|
||||||
|
the leap second, which would let civil UTC+7 drift slowly from the
|
||||||
|
astronomical time the algorithm models.
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
package amlich
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var update = flag.Bool("update", false, "regenerate golden files")
|
||||||
|
|
||||||
|
// goldenTable renders every lunar year in the supported range as one line:
|
||||||
|
// "YYYY L n1 n2 ... nN" — L is the leap month number (0 = none) and n* are the
|
||||||
|
// month lengths in chronological order starting at tháng 1, with the leap
|
||||||
|
// month in sequence (12 entries for a normal year, 13 for a leap year).
|
||||||
|
func goldenTable(t *testing.T) string {
|
||||||
|
t.Helper()
|
||||||
|
var b strings.Builder
|
||||||
|
for year := minLunarYear; year <= maxLunarYear; year++ {
|
||||||
|
type monthStart struct {
|
||||||
|
jd, month int
|
||||||
|
leap bool
|
||||||
|
}
|
||||||
|
var starts []monthStart
|
||||||
|
for m := 1; m <= 12; m++ {
|
||||||
|
dd, mm, yy, err := lunarToSolar(1, m, year, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("lunarToSolar(1, %d, %d): %v", m, year, err)
|
||||||
|
}
|
||||||
|
starts = append(starts, monthStart{jdFromDate(dd, mm, yy), m, false})
|
||||||
|
if dd, mm, yy, err := lunarToSolar(1, m, year, true); err == nil {
|
||||||
|
starts = append(starts, monthStart{jdFromDate(dd, mm, yy), m, true})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Slice(starts, func(i, j int) bool { return starts[i].jd < starts[j].jd })
|
||||||
|
// The last month of year Y ends where tháng 1 of Y+1 begins. For
|
||||||
|
// maxLunarYear this evaluates the engine one year past the supported
|
||||||
|
// range, which the astronomy handles fine — only the bot commands
|
||||||
|
// enforce the bounds.
|
||||||
|
dd, mm, yy, err := lunarToSolar(1, 1, year+1, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("lunarToSolar(1, 1, %d): %v", year+1, err)
|
||||||
|
}
|
||||||
|
nextYearStart := jdFromDate(dd, mm, yy)
|
||||||
|
leapMonth := 0
|
||||||
|
for _, s := range starts {
|
||||||
|
if s.leap {
|
||||||
|
leapMonth = s.month
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if want := 12; (leapMonth == 0 && len(starts) != want) || (leapMonth != 0 && len(starts) != want+1) {
|
||||||
|
t.Fatalf("year %d: %d month starts with leap month %d", year, len(starts), leapMonth)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&b, "%d %d", year, leapMonth)
|
||||||
|
for i, s := range starts {
|
||||||
|
end := nextYearStart
|
||||||
|
if i+1 < len(starts) {
|
||||||
|
end = starts[i+1].jd
|
||||||
|
}
|
||||||
|
if length := end - s.jd; length != 29 && length != 30 {
|
||||||
|
t.Fatalf("year %d month %d (leap=%v): length %d days", year, s.month, s.leap, length)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(&b, " %d", length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.WriteByte('\n')
|
||||||
|
}
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestGoldenTable compares the engine's full 1800–2199 month structure against
|
||||||
|
// the committed golden file. The round-trip test proves the two conversion
|
||||||
|
// directions agree with each other; this pins the verified boundary placement
|
||||||
|
// itself, so a future engine change cannot shift months while staying
|
||||||
|
// self-consistent. Regenerate deliberately with:
|
||||||
|
//
|
||||||
|
// go test ./internal/modules/amlich/ -run TestGoldenTable -update
|
||||||
|
func TestGoldenTable(t *testing.T) {
|
||||||
|
got := goldenTable(t)
|
||||||
|
golden := filepath.Join("testdata", "lunar-years-1800-2199.txt")
|
||||||
|
if *update {
|
||||||
|
if err := os.WriteFile(golden, []byte(got), 0o644); err != nil {
|
||||||
|
t.Fatalf("write golden file: %v", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
want, err := os.ReadFile(golden)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("read golden file (regenerate with -update): %v", err)
|
||||||
|
}
|
||||||
|
if got == string(want) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
gotLines := strings.Split(got, "\n")
|
||||||
|
wantLines := strings.Split(string(want), "\n")
|
||||||
|
for i := 0; i < len(gotLines) && i < len(wantLines); i++ {
|
||||||
|
if gotLines[i] != wantLines[i] {
|
||||||
|
t.Fatalf("golden mismatch at line %d:\n got: %s\nwant: %s", i+1, gotLines[i], wantLines[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Fatalf("golden mismatch: got %d lines, want %d", len(gotLines), len(wantLines))
|
||||||
|
}
|
||||||
@@ -27,6 +27,15 @@ const duonglichUsage = `Cách dùng: /duonglich <dd[/mm[/yyyy]]> [nhuan] — đ
|
|||||||
// next to the algorithm it protects.
|
// next to the algorithm it protects.
|
||||||
var yearRangeMessage = fmt.Sprintf("Chỉ hỗ trợ các năm từ %d đến %d.", minLunarYear, maxLunarYear)
|
var yearRangeMessage = fmt.Sprintf("Chỉ hỗ trợ các năm từ %d đến %d.", minLunarYear, maxLunarYear)
|
||||||
|
|
||||||
|
// leapHintFormat is appended to a /duonglich reply when the queried month is
|
||||||
|
// also that year's leap month and the user gave no "nhuan" flag — the input
|
||||||
|
// was ambiguous, and the answer shown is for the regular month.
|
||||||
|
const leapHintFormat = `Lưu ý: năm âm lịch %d có tháng %d nhuận — thêm "nhuan" nếu ý bạn là tháng nhuận.`
|
||||||
|
|
||||||
|
// disputedCaveat is appended when the result falls in a lunar month whose
|
||||||
|
// boundary is astronomically too close to call (see disputedMonthStarts).
|
||||||
|
const disputedCaveat = "Lưu ý: ngày này gần ranh giới tháng âm lịch chưa chắc chắn; kết quả có thể lệch 1 ngày so với lịch chính thức sau này."
|
||||||
|
|
||||||
func amlichCommand() modules.Command {
|
func amlichCommand() modules.Command {
|
||||||
return modules.Command{
|
return modules.Command{
|
||||||
Name: "amlich",
|
Name: "amlich",
|
||||||
@@ -55,6 +64,9 @@ func amlichCommand() modules.Command {
|
|||||||
lunarDay, lunarMonth, lunarYear, leap := solarToLunar(day, month, year)
|
lunarDay, lunarMonth, lunarYear, leap := solarToLunar(day, month, year)
|
||||||
text := fmt.Sprintf("Dương lịch %02d/%02d/%d là ngày %d tháng %d%s năm %s %d âm lịch.",
|
text := fmt.Sprintf("Dương lịch %02d/%02d/%d là ngày %d tháng %d%s năm %s %d âm lịch.",
|
||||||
day, month, year, lunarDay, lunarMonth, leapLabel(leap), canChiYear(lunarYear), lunarYear)
|
day, month, year, lunarDay, lunarMonth, leapLabel(leap), canChiYear(lunarYear), lunarYear)
|
||||||
|
if nearDisputedBoundary(jdFromDate(day, month, year)) {
|
||||||
|
text += "\n" + disputedCaveat
|
||||||
|
}
|
||||||
return chathelper.Reply(ctx, b, update.Message, text)
|
return chathelper.Reply(ctx, b, update.Message, text)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -102,6 +114,17 @@ func duonglichCommand() modules.Command {
|
|||||||
}
|
}
|
||||||
text := fmt.Sprintf("Âm lịch ngày %d tháng %d%s năm %s %d là %02d/%02d/%d dương lịch.",
|
text := fmt.Sprintf("Âm lịch ngày %d tháng %d%s năm %s %d là %02d/%02d/%d dương lịch.",
|
||||||
day, month, leapLabel(leap), canChiYear(year), year, solarDay, solarMonth, solarYear)
|
day, month, leapLabel(leap), canChiYear(year), year, solarDay, solarMonth, solarYear)
|
||||||
|
// A bare month is ambiguous when the year also has that month as a
|
||||||
|
// leap month and the exact leap date exists; probing lunarToSolar
|
||||||
|
// reuses its validation (a 29-day leap month can't hide a day 30).
|
||||||
|
if !leap {
|
||||||
|
if _, _, _, hintErr := lunarToSolar(day, month, year, true); hintErr == nil {
|
||||||
|
text += "\n" + fmt.Sprintf(leapHintFormat, year, month)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if nearDisputedBoundary(jdFromDate(solarDay, solarMonth, solarYear)) {
|
||||||
|
text += "\n" + disputedCaveat
|
||||||
|
}
|
||||||
return chathelper.Reply(ctx, b, update.Message, text)
|
return chathelper.Reply(ctx, b, update.Message, text)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -202,6 +202,56 @@ func TestDuonglich_RejectsWrongLeapMonth(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A bare month that is also the year's leap month is ambiguous input; the
|
||||||
|
// reply must carry the disambiguation hint — and only then.
|
||||||
|
func TestDuonglich_LeapMonthHint(t *testing.T) {
|
||||||
|
solarDay, solarMonth, solarYear, err := lunarToSolar(5, 5, 2028, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("lunarToSolar(5/5/2028): %v", err)
|
||||||
|
}
|
||||||
|
want := fmt.Sprintf("Âm lịch ngày 5 tháng 5 năm Mậu Thân 2028 là %02d/%02d/%d dương lịch.\n", solarDay, solarMonth, solarYear) +
|
||||||
|
`Lưu ý: năm âm lịch 2028 có tháng 5 nhuận — thêm "nhuan" nếu ý bạn là tháng nhuận.`
|
||||||
|
if got := replyFor(t, "/duonglich 5/5/2028"); got != want {
|
||||||
|
t.Errorf("reply = %q, want %q", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDuonglich_NoHintWhenNhuanExplicit(t *testing.T) {
|
||||||
|
if got := replyFor(t, "/duonglich 5/5/2028 nhuan"); strings.Contains(got, "Lưu ý") {
|
||||||
|
t.Errorf("explicit nhuan reply = %q, want no hint", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDuonglich_NoHintWithoutLeapMonth(t *testing.T) {
|
||||||
|
if got := replyFor(t, "/duonglich 5/5/2027"); strings.Contains(got, "Lưu ý") {
|
||||||
|
t.Errorf("non-leap-year reply = %q, want no hint", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dates inside a lunar month touching a disputed boundary (see
|
||||||
|
// disputedMonthStarts) must carry the caveat; nearby ordinary dates must not.
|
||||||
|
// Absence on modern dates is also pinned by the exact-string assertions in
|
||||||
|
// TestAmlich_ConvertsKnownDate and TestDuonglich_ConvertsKnownDate.
|
||||||
|
func TestAmlich_DisputedBoundaryCaveat(t *testing.T) {
|
||||||
|
if got := replyFor(t, "/amlich 20/12/2072"); !strings.HasSuffix(got, "\n"+disputedCaveat) {
|
||||||
|
t.Errorf("reply = %q, want disputed-boundary caveat", got)
|
||||||
|
}
|
||||||
|
if got := replyFor(t, "/amlich 01/06/2072"); strings.Contains(got, "Lưu ý") {
|
||||||
|
t.Errorf("reply = %q, want no caveat", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDuonglich_DisputedBoundaryCaveat(t *testing.T) {
|
||||||
|
lunarDay, lunarMonth, lunarYear, leap := solarToLunar(20, 12, 2072)
|
||||||
|
cmd := fmt.Sprintf("/duonglich %d/%d/%d", lunarDay, lunarMonth, lunarYear)
|
||||||
|
if leap {
|
||||||
|
cmd += " nhuan"
|
||||||
|
}
|
||||||
|
if got := replyFor(t, cmd); !strings.HasSuffix(got, "\n"+disputedCaveat) {
|
||||||
|
t.Errorf("reply for %q = %q, want disputed-boundary caveat", cmd, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestDuonglich_InvalidInputRepliesUsage(t *testing.T) {
|
func TestDuonglich_InvalidInputRepliesUsage(t *testing.T) {
|
||||||
for _, text := range []string{
|
for _, text := range []string{
|
||||||
"/duonglich",
|
"/duonglich",
|
||||||
|
|||||||
@@ -251,6 +251,36 @@ func lunarToSolar(day, month, year int, leap bool) (dd, mm, yy int, err error) {
|
|||||||
return dd, mm, yy, nil
|
return dd, mm, yy, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// disputedMonthStarts holds the Julian day numbers of the lunar-month starts
|
||||||
|
// whose defining new moon falls within ~2 minutes of UTC+7 midnight, where
|
||||||
|
// ΔT uncertainty exceeds the margin — the true boundary may sit one day
|
||||||
|
// earlier in future official tables (see docs/amlich-known-issues.md, which
|
||||||
|
// lists the disputed new-moon days themselves; this engine begins each of
|
||||||
|
// these months on the following day). Conversions touching these months carry
|
||||||
|
// a caveat in the bot's reply.
|
||||||
|
var disputedMonthStarts = map[int]bool{
|
||||||
|
jdFromDate(10, 12, 2072): true,
|
||||||
|
jdFromDate(16, 11, 2077): true,
|
||||||
|
jdFromDate(8, 5, 2130): true,
|
||||||
|
jdFromDate(27, 5, 2150): true,
|
||||||
|
jdFromDate(18, 5, 2159): true,
|
||||||
|
jdFromDate(23, 1, 2175): true,
|
||||||
|
jdFromDate(27, 1, 2199): true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// nearDisputedBoundary reports whether the lunar month containing the solar
|
||||||
|
// day jdn starts or ends on a disputed boundary — i.e. whether the conversion
|
||||||
|
// result for that day could shift by one day against future official tables.
|
||||||
|
func nearDisputedBoundary(jdn int) bool {
|
||||||
|
k := floorInt((float64(jdn) - jdNewMoonEpoch) / newMoonCycle)
|
||||||
|
monthStart := getNewMoonDay(k + 1)
|
||||||
|
for monthStart > jdn {
|
||||||
|
k--
|
||||||
|
monthStart = getNewMoonDay(k + 1)
|
||||||
|
}
|
||||||
|
return disputedMonthStarts[monthStart] || disputedMonthStarts[getNewMoonDay(k+2)]
|
||||||
|
}
|
||||||
|
|
||||||
// canNames and chiNames are the sexagesimal-cycle stems and branches used to
|
// canNames and chiNames are the sexagesimal-cycle stems and branches used to
|
||||||
// name lunar years (Giáp Thìn, Ất Tỵ, …).
|
// name lunar years (Giáp Thìn, Ất Tỵ, …).
|
||||||
var canNames = [...]string{"Giáp", "Ất", "Bính", "Đinh", "Mậu", "Kỷ", "Canh", "Tân", "Nhâm", "Quý"}
|
var canNames = [...]string{"Giáp", "Ất", "Bính", "Đinh", "Mậu", "Kỷ", "Canh", "Tân", "Nhâm", "Quý"}
|
||||||
|
|||||||
@@ -203,6 +203,44 @@ func TestLeapMonthTable(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestDisputedMonthStarts_AreMonthStarts verifies every entry in the disputed
|
||||||
|
// set is an actual lunar-month start per the engine — a mistyped or off-by-one
|
||||||
|
// date would silently flag the wrong month.
|
||||||
|
func TestDisputedMonthStarts_AreMonthStarts(t *testing.T) {
|
||||||
|
if len(disputedMonthStarts) != 7 {
|
||||||
|
t.Fatalf("disputed set has %d entries, want 7", len(disputedMonthStarts))
|
||||||
|
}
|
||||||
|
for jd := range disputedMonthStarts {
|
||||||
|
dd, mm, yy := jdToDate(jd)
|
||||||
|
day, _, _, _ := solarToLunar(dd, mm, yy)
|
||||||
|
if day != 1 {
|
||||||
|
t.Errorf("%02d/%02d/%d (jd %d) is lunar day %d, want month start (day 1)", dd, mm, yy, jd, day)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestNearDisputedBoundary covers the month starting on a disputed boundary,
|
||||||
|
// the month ending on one, and ordinary dates on both sides.
|
||||||
|
func TestNearDisputedBoundary(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
dd, mm, yy int
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{10, 12, 2072, true}, // first day of the disputed month
|
||||||
|
{20, 12, 2072, true}, // inside the month starting on the disputed boundary
|
||||||
|
{9, 12, 2072, true}, // last day of the month ending on the disputed boundary
|
||||||
|
{1, 12, 2072, true}, // inside the month ending on the disputed boundary
|
||||||
|
{1, 6, 2072, false}, // same year, far from the boundary
|
||||||
|
{1, 2, 2073, false}, // after the disputed month
|
||||||
|
{29, 1, 2025, false}, // ordinary modern date
|
||||||
|
}
|
||||||
|
for _, tc := range cases {
|
||||||
|
if got := nearDisputedBoundary(jdFromDate(tc.dd, tc.mm, tc.yy)); got != tc.want {
|
||||||
|
t.Errorf("nearDisputedBoundary(%02d/%02d/%d) = %v, want %v", tc.dd, tc.mm, tc.yy, got, tc.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCanChiYear(t *testing.T) {
|
func TestCanChiYear(t *testing.T) {
|
||||||
for year, want := range map[int]string{
|
for year, want := range map[int]string{
|
||||||
2024: "Giáp Thìn",
|
2024: "Giáp Thìn",
|
||||||
|
|||||||
@@ -0,0 +1,400 @@
|
|||||||
|
1800 4 30 29 30 29 30 30 29 30 29 30 29 29 30
|
||||||
|
1801 0 29 30 30 29 30 29 30 30 29 30 29 30
|
||||||
|
1802 0 29 29 30 29 30 29 30 30 29 30 30 29
|
||||||
|
1803 2 30 29 29 30 29 30 29 30 30 29 30 30 29
|
||||||
|
1804 0 30 29 29 30 29 29 30 30 29 30 30 30
|
||||||
|
1805 7 29 30 29 29 30 29 29 30 29 30 30 30 29
|
||||||
|
1806 0 30 30 29 29 30 29 29 30 29 30 30 29
|
||||||
|
1807 0 30 30 30 29 29 30 29 29 30 29 30 29
|
||||||
|
1808 5 30 30 30 29 30 29 30 29 29 30 29 30 29
|
||||||
|
1809 0 30 30 29 30 30 29 30 29 30 29 29 30
|
||||||
|
1810 0 29 30 29 30 30 29 30 29 30 30 29 30
|
||||||
|
1811 3 29 29 30 29 30 29 30 30 29 30 30 29 30
|
||||||
|
1812 0 29 29 30 29 30 29 30 29 30 30 30 29
|
||||||
|
1813 0 30 29 29 30 29 29 30 29 30 30 30 29
|
||||||
|
1814 2 30 30 29 29 30 29 29 30 29 30 30 29 30
|
||||||
|
1815 0 30 30 29 29 30 29 29 30 29 30 29 30
|
||||||
|
1816 6 30 30 29 30 29 30 29 29 30 29 30 29 30
|
||||||
|
1817 0 30 29 30 30 29 30 29 29 30 29 30 29
|
||||||
|
1818 0 30 29 30 30 29 30 30 29 30 29 29 30
|
||||||
|
1819 4 29 30 29 30 29 30 30 29 30 30 29 30 29
|
||||||
|
1820 0 29 30 29 30 29 30 29 30 30 29 30 30
|
||||||
|
1821 0 29 29 30 29 29 30 29 30 30 30 29 30
|
||||||
|
1822 3 30 29 29 30 29 29 30 29 30 30 29 30 30
|
||||||
|
1823 0 30 29 29 30 29 29 30 29 30 29 30 30
|
||||||
|
1824 7 30 29 30 29 30 29 29 30 29 30 29 30 30
|
||||||
|
1825 0 29 30 30 29 30 29 29 30 29 30 29 30
|
||||||
|
1826 0 29 30 30 30 29 30 29 29 30 29 30 29
|
||||||
|
1827 5 30 29 30 30 29 30 29 30 29 30 29 30 29
|
||||||
|
1828 0 30 29 30 29 30 29 30 30 29 30 29 30
|
||||||
|
1829 0 29 30 29 30 29 30 29 30 30 29 30 30
|
||||||
|
1830 4 29 29 30 29 29 30 29 30 30 29 30 30 30
|
||||||
|
1831 0 29 29 30 29 29 30 29 30 29 30 30 30
|
||||||
|
1832 9 29 30 29 30 29 29 30 29 30 29 30 30 30
|
||||||
|
1833 0 29 30 29 30 29 29 30 29 30 29 30 30
|
||||||
|
1834 0 29 30 30 29 30 29 29 30 29 30 29 30
|
||||||
|
1835 6 29 30 30 29 30 30 29 29 30 29 30 29 30
|
||||||
|
1836 0 29 30 29 30 30 29 30 29 30 29 30 29
|
||||||
|
1837 0 30 29 30 29 30 29 30 30 29 30 29 30
|
||||||
|
1838 4 29 30 29 29 30 29 30 30 29 30 30 29 30
|
||||||
|
1839 0 29 30 29 29 30 29 30 29 30 30 30 29
|
||||||
|
1840 0 30 29 30 29 29 30 29 30 29 30 30 30
|
||||||
|
1841 3 29 30 29 30 29 29 30 29 29 30 30 29 30
|
||||||
|
1842 0 30 30 29 30 29 29 30 29 29 30 30 29
|
||||||
|
1843 7 30 30 29 30 30 29 29 30 29 30 29 30 29
|
||||||
|
1844 0 30 29 30 30 29 30 29 30 29 30 29 30
|
||||||
|
1845 0 29 30 29 30 29 30 30 29 30 29 30 29
|
||||||
|
1846 5 30 29 29 30 30 29 30 29 30 30 29 30 29
|
||||||
|
1847 0 30 29 29 30 29 30 29 30 30 30 29 30
|
||||||
|
1848 0 29 30 29 29 30 29 30 29 30 30 29 30
|
||||||
|
1849 4 30 29 30 29 29 30 29 29 30 30 29 30 30
|
||||||
|
1850 0 30 29 30 29 29 30 29 29 30 30 29 30
|
||||||
|
1851 8 30 30 29 30 29 29 30 29 29 30 29 30 30
|
||||||
|
1852 0 30 29 30 29 30 29 30 29 29 30 29 30
|
||||||
|
1853 0 30 29 30 30 29 30 29 30 29 30 29 30
|
||||||
|
1854 7 29 29 30 30 29 30 30 29 30 29 30 29 30
|
||||||
|
1855 0 29 29 30 29 30 30 29 30 30 29 30 29
|
||||||
|
1856 0 30 29 29 30 29 30 29 30 30 29 30 30
|
||||||
|
1857 5 29 30 29 29 30 29 29 30 30 29 30 30 30
|
||||||
|
1858 0 29 30 29 29 30 29 29 30 29 30 30 30
|
||||||
|
1859 0 30 29 30 29 29 30 29 29 30 29 30 30
|
||||||
|
1860 3 30 29 30 30 29 29 30 29 29 30 29 30 30
|
||||||
|
1861 0 29 30 30 29 30 29 30 29 29 30 29 30
|
||||||
|
1862 8 29 30 30 29 30 30 29 30 29 30 29 29 30
|
||||||
|
1863 0 29 30 29 30 30 29 30 30 29 30 29 30
|
||||||
|
1864 0 29 29 30 29 30 29 30 30 29 30 30 29
|
||||||
|
1865 5 30 29 29 30 29 30 29 30 29 30 30 30 29
|
||||||
|
1866 0 30 29 29 30 29 29 30 29 30 30 30 30
|
||||||
|
1867 0 29 30 29 29 30 29 29 30 29 30 30 30
|
||||||
|
1868 4 29 30 30 29 29 30 29 29 30 29 30 30 29
|
||||||
|
1869 0 30 30 29 30 29 30 29 29 30 29 30 29
|
||||||
|
1870 10 30 30 30 29 30 29 30 29 29 30 29 30 29
|
||||||
|
1871 0 30 30 29 30 30 29 30 29 30 29 29 30
|
||||||
|
1872 0 29 30 29 30 30 29 30 29 30 30 29 30
|
||||||
|
1873 6 29 29 30 29 30 29 30 30 29 30 30 29 30
|
||||||
|
1874 0 29 29 30 29 29 30 30 29 30 30 30 29
|
||||||
|
1875 0 30 29 29 30 29 29 30 29 30 30 30 29
|
||||||
|
1876 5 30 30 29 29 30 29 29 30 29 30 30 29 30
|
||||||
|
1877 0 30 30 29 29 30 29 29 30 29 30 29 30
|
||||||
|
1878 0 30 30 29 30 29 30 29 29 30 29 30 29
|
||||||
|
1879 3 30 30 29 30 30 29 30 29 29 30 29 30 29
|
||||||
|
1880 0 30 29 30 30 29 30 29 30 29 30 29 30
|
||||||
|
1881 7 29 30 29 30 29 30 30 29 30 29 30 29 30
|
||||||
|
1882 0 29 30 29 30 29 30 29 30 30 29 30 30
|
||||||
|
1883 0 29 29 30 29 29 30 29 30 30 30 29 30
|
||||||
|
1884 5 30 29 29 30 29 29 30 29 30 30 29 30 30
|
||||||
|
1885 0 30 29 29 30 29 29 30 29 30 29 30 30
|
||||||
|
1886 0 30 29 30 29 30 29 29 30 29 30 29 30
|
||||||
|
1887 4 30 29 30 30 29 30 29 29 30 29 30 29 30
|
||||||
|
1888 0 29 30 30 29 30 30 29 29 30 29 30 29
|
||||||
|
1889 0 30 29 30 30 29 30 29 30 29 30 29 30
|
||||||
|
1890 2 29 30 29 30 29 30 29 30 30 29 30 29 30
|
||||||
|
1891 0 29 30 29 29 30 30 29 30 30 29 30 29
|
||||||
|
1892 6 30 29 30 29 29 30 29 30 30 29 30 30 29
|
||||||
|
1893 0 30 29 30 29 29 30 29 30 29 30 30 30
|
||||||
|
1894 0 29 30 29 30 29 29 30 29 30 29 30 30
|
||||||
|
1895 5 29 30 30 29 30 29 29 30 29 30 29 30 29
|
||||||
|
1896 0 30 30 30 29 30 29 29 30 29 30 29 30
|
||||||
|
1897 0 29 30 30 29 30 29 30 29 30 29 30 29
|
||||||
|
1898 3 30 29 30 29 30 30 29 30 29 30 29 30 29
|
||||||
|
1899 0 30 29 30 29 30 29 30 30 29 30 29 30
|
||||||
|
1900 8 29 30 29 29 30 29 30 30 29 30 30 29 30
|
||||||
|
1901 0 29 30 29 29 30 29 30 29 30 30 30 29
|
||||||
|
1902 0 30 29 30 29 29 30 29 30 29 30 30 29
|
||||||
|
1903 5 30 30 29 30 29 29 30 29 29 30 30 29 30
|
||||||
|
1904 0 30 30 29 30 29 29 30 29 29 30 30 29
|
||||||
|
1905 0 30 30 29 30 30 29 29 30 29 29 30 30
|
||||||
|
1906 4 29 30 29 30 30 29 30 29 30 29 30 29 30
|
||||||
|
1907 0 29 30 29 30 29 30 30 29 30 29 30 29
|
||||||
|
1908 0 30 29 29 30 29 30 30 29 30 30 29 30
|
||||||
|
1909 2 29 30 29 29 30 29 30 29 30 30 30 29 30
|
||||||
|
1910 0 29 30 29 29 30 29 30 29 30 30 29 30
|
||||||
|
1911 6 30 29 30 29 29 30 29 29 30 30 29 30 30
|
||||||
|
1912 0 30 29 30 29 29 30 29 29 30 30 29 30
|
||||||
|
1913 0 30 30 29 30 29 29 30 29 29 30 29 30
|
||||||
|
1914 5 30 30 29 30 29 30 29 30 29 29 30 29 30
|
||||||
|
1915 0 30 29 30 30 29 30 29 30 29 30 29 29
|
||||||
|
1916 0 30 29 30 30 29 30 30 29 30 29 30 29
|
||||||
|
1917 3 30 29 29 30 29 30 30 29 30 30 29 30 29
|
||||||
|
1918 0 30 29 29 30 29 30 29 30 30 29 30 30
|
||||||
|
1919 7 29 30 29 29 30 29 29 30 30 29 30 30 30
|
||||||
|
1920 0 29 30 29 29 30 29 29 30 29 30 30 30
|
||||||
|
1921 0 30 29 30 29 29 30 29 29 30 29 30 30
|
||||||
|
1922 6 30 29 30 30 29 29 30 29 29 30 29 30 30
|
||||||
|
1923 0 29 30 30 29 30 29 30 29 29 30 29 30
|
||||||
|
1924 0 29 30 30 29 30 30 29 30 29 30 29 29
|
||||||
|
1925 4 30 29 30 29 30 30 29 30 30 29 30 29 30
|
||||||
|
1926 0 29 29 30 29 30 29 30 30 29 30 30 29
|
||||||
|
1927 0 30 29 29 30 29 30 29 30 29 30 30 30
|
||||||
|
1928 2 29 30 29 29 30 29 29 30 29 30 30 30 30
|
||||||
|
1929 0 29 30 29 29 30 29 29 30 29 30 30 30
|
||||||
|
1930 6 29 30 30 29 29 30 29 29 30 29 30 30 29
|
||||||
|
1931 0 30 30 29 30 29 30 29 29 30 29 30 29
|
||||||
|
1932 0 30 30 30 29 30 29 30 29 29 30 29 30
|
||||||
|
1933 5 29 30 30 29 30 29 30 30 29 29 30 29 30
|
||||||
|
1934 0 29 30 29 30 30 29 30 29 30 30 29 29
|
||||||
|
1935 0 30 29 30 29 30 29 30 30 29 30 30 29
|
||||||
|
1936 3 30 29 29 30 29 29 30 30 29 30 30 29 30
|
||||||
|
1937 0 30 29 29 30 29 29 30 29 30 30 30 29
|
||||||
|
1938 8 30 30 29 29 30 29 29 30 29 30 30 29 30
|
||||||
|
1939 0 30 29 30 29 30 29 29 30 29 30 29 30
|
||||||
|
1940 0 30 30 29 30 29 30 29 29 30 29 30 29
|
||||||
|
1941 6 30 30 29 30 30 29 30 29 29 30 29 30 29
|
||||||
|
1942 0 30 29 30 30 29 30 29 30 29 30 29 30
|
||||||
|
1943 0 29 30 29 30 29 30 30 29 30 29 30 29
|
||||||
|
1944 4 30 29 30 29 30 29 30 29 30 30 29 30 30
|
||||||
|
1945 0 29 29 30 29 29 30 29 30 30 30 29 30
|
||||||
|
1946 0 30 29 29 30 29 29 30 29 30 30 29 30
|
||||||
|
1947 2 30 29 30 29 30 29 29 30 29 30 29 30 30
|
||||||
|
1948 0 30 29 30 29 30 29 29 30 29 30 29 30
|
||||||
|
1949 7 30 29 30 30 29 30 29 29 30 29 30 29 30
|
||||||
|
1950 0 29 30 30 29 30 29 30 29 30 29 30 29
|
||||||
|
1951 0 30 29 30 29 30 30 29 30 29 30 29 30
|
||||||
|
1952 5 29 30 29 30 29 30 29 30 30 29 30 29 30
|
||||||
|
1953 0 29 30 29 29 30 29 30 30 30 29 30 29
|
||||||
|
1954 0 30 29 30 29 29 30 29 30 30 29 30 30
|
||||||
|
1955 3 29 30 29 30 29 29 30 29 30 29 30 30 30
|
||||||
|
1956 0 29 30 29 30 29 29 30 29 29 30 30 30
|
||||||
|
1957 8 29 30 30 29 30 29 29 30 29 29 30 30 29
|
||||||
|
1958 0 30 30 30 29 30 29 29 30 29 30 29 30
|
||||||
|
1959 0 29 30 30 29 30 29 30 29 30 29 30 29
|
||||||
|
1960 6 30 29 30 29 30 30 29 30 29 30 29 30 29
|
||||||
|
1961 0 30 29 29 30 30 29 30 30 29 30 29 30
|
||||||
|
1962 0 29 30 29 29 30 29 30 30 29 30 30 29
|
||||||
|
1963 4 30 29 30 29 29 30 29 30 29 30 30 30 29
|
||||||
|
1964 0 30 29 30 29 29 30 29 29 30 30 30 29
|
||||||
|
1965 0 30 30 29 30 29 29 30 29 29 30 30 29
|
||||||
|
1966 3 30 30 30 29 30 29 29 30 29 29 30 30 29
|
||||||
|
1967 0 30 30 29 30 30 29 29 30 29 29 30 29
|
||||||
|
1968 7 30 30 29 30 30 29 30 29 30 29 30 29 29
|
||||||
|
1969 0 30 30 29 30 29 30 30 29 30 29 30 29
|
||||||
|
1970 0 30 29 29 30 29 30 30 29 30 30 29 30
|
||||||
|
1971 5 29 30 29 29 30 29 30 29 30 30 30 29 30
|
||||||
|
1972 0 29 30 29 29 30 29 30 29 30 30 29 30
|
||||||
|
1973 0 30 29 30 29 29 30 29 29 30 30 29 30
|
||||||
|
1974 4 30 30 29 30 29 29 30 29 29 30 29 30 30
|
||||||
|
1975 0 30 29 30 30 29 29 30 29 29 30 29 30
|
||||||
|
1976 8 30 30 29 30 29 30 29 30 29 29 30 29 30
|
||||||
|
1977 0 30 29 30 30 29 30 29 30 29 30 29 29
|
||||||
|
1978 0 30 29 30 30 29 30 29 30 30 29 30 29
|
||||||
|
1979 6 29 30 29 30 29 30 30 29 30 30 29 30 29
|
||||||
|
1980 0 30 29 29 30 29 30 29 30 30 29 30 30
|
||||||
|
1981 0 29 30 29 29 30 29 29 30 30 29 30 30
|
||||||
|
1982 4 30 29 30 29 29 30 29 29 30 29 30 30 30
|
||||||
|
1983 0 30 29 30 29 29 30 29 29 30 29 30 30
|
||||||
|
1984 0 30 29 30 29 30 29 30 29 29 30 29 30
|
||||||
|
1985 2 30 29 30 30 29 30 29 30 29 29 30 29 30
|
||||||
|
1986 0 29 30 30 29 30 30 29 30 29 29 30 29
|
||||||
|
1987 7 30 29 30 29 30 30 29 30 30 29 30 29 29
|
||||||
|
1988 0 30 29 30 29 30 29 30 30 29 30 30 29
|
||||||
|
1989 0 30 29 29 30 29 29 30 30 29 30 30 30
|
||||||
|
1990 5 29 30 29 29 30 29 29 30 29 30 30 30 30
|
||||||
|
1991 0 29 30 29 29 30 29 29 30 29 30 30 30
|
||||||
|
1992 0 29 30 30 29 29 30 29 29 30 29 30 30
|
||||||
|
1993 3 29 30 30 29 30 29 30 29 29 30 29 30 29
|
||||||
|
1994 0 30 30 30 29 30 29 30 29 29 30 29 30
|
||||||
|
1995 8 29 30 30 29 30 29 30 29 30 29 30 29 30
|
||||||
|
1996 0 29 30 29 30 29 30 30 29 30 29 30 29
|
||||||
|
1997 0 30 29 30 29 30 29 30 29 30 30 29 30
|
||||||
|
1998 5 30 29 29 30 29 29 30 30 29 30 30 29 30
|
||||||
|
1999 0 30 29 29 30 29 29 30 29 30 30 30 29
|
||||||
|
2000 0 30 30 29 29 30 29 29 30 29 30 30 29
|
||||||
|
2001 4 30 30 29 30 29 30 29 29 30 29 30 29 30
|
||||||
|
2002 0 30 30 29 30 29 30 29 29 30 29 30 29
|
||||||
|
2003 0 30 30 29 30 30 29 30 29 29 30 29 30
|
||||||
|
2004 2 29 30 29 30 30 29 30 29 30 29 30 29 30
|
||||||
|
2005 0 29 30 29 30 29 30 30 29 30 29 30 29
|
||||||
|
2006 7 30 29 30 29 29 30 30 29 30 30 29 30 29
|
||||||
|
2007 0 30 29 30 29 29 30 29 30 30 30 29 30
|
||||||
|
2008 0 30 29 29 30 29 29 30 29 30 29 30 30
|
||||||
|
2009 5 30 29 30 29 30 29 29 30 29 30 29 30 30
|
||||||
|
2010 0 30 29 30 29 30 29 29 30 29 30 29 30
|
||||||
|
2011 0 30 29 30 30 29 30 29 29 30 29 30 29
|
||||||
|
2012 4 30 29 30 30 29 30 29 30 29 30 29 30 29
|
||||||
|
2013 0 30 29 30 29 30 30 29 30 29 30 29 30
|
||||||
|
2014 9 29 30 29 30 29 30 29 30 30 29 30 29 30
|
||||||
|
2015 0 29 30 29 29 30 29 30 30 30 29 30 29
|
||||||
|
2016 0 30 29 30 29 29 30 29 30 30 29 30 30
|
||||||
|
2017 6 29 30 29 30 29 29 30 29 30 29 30 30 30
|
||||||
|
2018 0 29 30 29 30 29 29 30 29 29 30 30 30
|
||||||
|
2019 0 29 30 30 29 30 29 29 30 29 29 30 30
|
||||||
|
2020 4 29 30 30 30 29 30 29 29 30 29 29 30 30
|
||||||
|
2021 0 29 30 30 29 30 29 30 29 30 29 30 29
|
||||||
|
2022 0 30 29 30 29 30 30 29 30 29 30 29 30
|
||||||
|
2023 2 29 30 29 29 30 30 29 30 30 29 30 29 30
|
||||||
|
2024 0 29 30 29 29 30 29 30 30 29 30 30 29
|
||||||
|
2025 6 30 29 30 29 29 30 29 30 29 30 30 30 29
|
||||||
|
2026 0 30 29 30 29 29 30 29 29 30 30 30 29
|
||||||
|
2027 0 30 30 29 30 29 29 30 29 29 30 30 29
|
||||||
|
2028 5 30 30 30 29 30 29 29 30 29 29 30 30 29
|
||||||
|
2029 0 30 30 29 30 29 30 29 30 29 29 30 29
|
||||||
|
2030 0 30 30 29 30 30 29 30 29 30 29 30 29
|
||||||
|
2031 3 29 30 29 30 30 29 30 30 29 30 29 30 29
|
||||||
|
2032 0 29 30 29 30 29 30 30 29 30 30 29 30
|
||||||
|
2033 11 29 30 29 29 30 29 30 29 30 30 30 29 30
|
||||||
|
2034 0 29 30 29 29 30 29 29 30 30 30 29 30
|
||||||
|
2035 0 30 29 30 29 29 30 29 29 30 30 29 30
|
||||||
|
2036 6 30 30 29 30 29 29 30 29 29 30 29 30 30
|
||||||
|
2037 0 30 29 30 30 29 29 30 29 29 30 29 30
|
||||||
|
2038 0 30 29 30 30 29 30 29 30 29 29 30 29
|
||||||
|
2039 5 30 30 29 30 30 29 30 29 30 29 29 30 29
|
||||||
|
2040 0 30 29 30 30 29 30 29 30 30 29 30 29
|
||||||
|
2041 0 29 30 29 30 29 30 29 30 30 30 29 30
|
||||||
|
2042 2 29 30 29 29 30 29 30 29 30 30 29 30 30
|
||||||
|
2043 0 29 30 29 29 30 29 29 30 30 29 30 30
|
||||||
|
2044 7 30 29 30 29 29 30 29 29 30 29 30 30 30
|
||||||
|
2045 0 30 29 30 29 29 30 29 29 30 29 30 30
|
||||||
|
2046 0 30 29 30 29 30 29 30 29 29 30 29 30
|
||||||
|
2047 5 30 29 30 30 29 30 29 30 29 29 30 29 30
|
||||||
|
2048 0 29 30 30 29 30 30 29 30 29 29 30 29
|
||||||
|
2049 0 30 29 30 29 30 30 29 30 29 30 30 29
|
||||||
|
2050 3 29 30 29 30 29 30 29 30 30 29 30 30 29
|
||||||
|
2051 0 29 30 29 30 29 29 30 30 29 30 30 30
|
||||||
|
2052 8 29 30 29 29 30 29 29 30 29 30 30 30 29
|
||||||
|
2053 0 30 30 29 29 30 29 29 30 29 30 30 30
|
||||||
|
2054 0 29 30 30 29 29 30 29 29 30 29 30 30
|
||||||
|
2055 6 29 30 30 29 30 29 30 29 29 30 29 30 29
|
||||||
|
2056 0 30 30 29 30 30 29 30 29 29 30 29 30
|
||||||
|
2057 0 29 30 29 30 30 29 30 29 30 29 30 29
|
||||||
|
2058 4 30 29 30 29 30 29 30 30 29 30 29 30 29
|
||||||
|
2059 0 30 29 30 29 30 29 30 29 30 30 29 30
|
||||||
|
2060 0 29 30 29 30 29 29 30 29 30 30 30 29
|
||||||
|
2061 3 30 30 29 29 30 29 29 30 29 30 30 30 29
|
||||||
|
2062 0 30 30 29 29 30 29 29 30 29 30 29 30
|
||||||
|
2063 7 30 30 29 30 29 30 29 29 30 29 30 29 30
|
||||||
|
2064 0 30 30 29 30 29 30 29 29 30 29 30 29
|
||||||
|
2065 0 30 30 29 30 30 29 29 30 29 30 29 30
|
||||||
|
2066 5 29 30 29 30 30 29 30 29 30 29 30 29 30
|
||||||
|
2067 0 29 30 29 30 29 30 30 29 30 29 30 29
|
||||||
|
2068 0 30 29 30 29 29 30 30 29 30 30 29 30
|
||||||
|
2069 4 29 30 29 30 29 29 30 29 30 30 30 29 30
|
||||||
|
2070 0 29 30 29 30 29 29 30 29 30 29 30 30
|
||||||
|
2071 8 30 29 30 29 30 29 29 30 29 30 29 30 30
|
||||||
|
2072 0 30 29 30 29 30 29 29 30 29 30 29 30
|
||||||
|
2073 0 30 29 30 30 29 30 29 29 30 29 29 30
|
||||||
|
2074 6 30 29 30 30 29 30 29 30 29 30 29 30 29
|
||||||
|
2075 0 30 29 30 29 30 30 29 30 29 30 29 30
|
||||||
|
2076 0 29 30 29 30 29 30 29 30 30 29 30 29
|
||||||
|
2077 4 30 29 30 29 29 30 29 30 30 30 29 30 29
|
||||||
|
2078 0 30 29 30 29 29 30 29 30 29 30 30 30
|
||||||
|
2079 0 29 30 29 30 29 29 30 29 30 29 30 30
|
||||||
|
2080 3 30 29 30 29 30 29 29 29 30 29 30 30 30
|
||||||
|
2081 0 29 30 30 29 30 29 29 30 29 29 30 30
|
||||||
|
2082 7 29 30 30 29 30 29 30 29 30 29 29 30 30
|
||||||
|
2083 0 29 30 30 29 30 29 30 29 30 29 30 29
|
||||||
|
2084 0 30 29 30 29 30 30 29 30 29 30 29 30
|
||||||
|
2085 5 29 29 30 29 30 30 29 30 29 30 30 29 30
|
||||||
|
2086 0 29 29 30 29 30 29 30 30 29 30 30 29
|
||||||
|
2087 0 30 29 30 29 29 30 29 30 29 30 30 30
|
||||||
|
2088 4 29 30 29 30 29 29 29 30 29 30 30 30 29
|
||||||
|
2089 0 30 30 29 30 29 29 29 30 29 30 30 29
|
||||||
|
2090 8 30 30 30 29 30 29 29 30 29 29 30 29 30
|
||||||
|
2091 0 30 30 29 30 29 30 29 30 29 29 30 29
|
||||||
|
2092 0 30 30 29 30 30 29 30 29 30 29 29 30
|
||||||
|
2093 6 29 30 29 30 30 29 30 30 29 30 29 30 29
|
||||||
|
2094 0 29 30 29 30 29 30 30 29 30 30 29 30
|
||||||
|
2095 0 29 29 30 29 30 29 30 29 30 30 30 29
|
||||||
|
2096 4 30 29 30 29 29 30 29 29 30 30 30 29 30
|
||||||
|
2097 0 30 29 30 29 29 29 30 29 30 30 29 30
|
||||||
|
2098 0 30 30 29 30 29 29 29 30 29 30 29 30
|
||||||
|
2099 2 30 30 29 30 29 30 29 29 30 29 30 29 30
|
||||||
|
2100 0 30 29 30 30 29 30 29 30 29 29 30 29
|
||||||
|
2101 7 30 30 29 30 29 30 30 29 30 29 29 30 29
|
||||||
|
2102 0 30 29 30 29 30 30 29 30 30 29 30 29
|
||||||
|
2103 0 29 30 29 30 29 30 29 30 30 29 30 30
|
||||||
|
2104 5 29 29 30 29 30 29 30 29 30 30 29 30 30
|
||||||
|
2105 0 29 30 29 29 29 30 29 30 30 29 30 30
|
||||||
|
2106 0 30 29 30 29 29 29 30 29 30 29 30 30
|
||||||
|
2107 4 30 29 30 30 29 29 29 30 29 30 29 30 30
|
||||||
|
2108 0 30 29 30 29 30 29 29 30 29 30 29 30
|
||||||
|
2109 9 30 29 30 30 29 30 29 30 29 29 30 29 30
|
||||||
|
2110 0 29 30 30 29 30 29 30 30 29 29 30 29
|
||||||
|
2111 0 30 29 30 29 30 30 29 30 29 30 29 30
|
||||||
|
2112 6 29 30 29 30 29 30 29 30 30 29 30 30 29
|
||||||
|
2113 0 29 30 29 30 29 29 30 30 29 30 30 30
|
||||||
|
2114 0 29 30 29 29 29 30 29 30 29 30 30 30
|
||||||
|
2115 4 29 30 30 29 29 29 30 29 30 29 30 30 30
|
||||||
|
2116 0 29 30 29 30 29 29 30 29 30 29 30 30
|
||||||
|
2117 0 29 30 30 29 30 29 29 30 29 30 29 30
|
||||||
|
2118 3 29 30 30 29 30 30 29 29 30 29 30 29 30
|
||||||
|
2119 0 29 30 29 30 30 29 30 29 30 29 30 29
|
||||||
|
2120 7 30 29 30 29 30 29 30 30 29 30 29 30 29
|
||||||
|
2121 0 30 29 30 29 29 30 30 29 30 30 29 30
|
||||||
|
2122 0 29 30 29 29 30 29 30 29 30 30 30 29
|
||||||
|
2123 5 30 29 30 29 29 30 29 30 29 30 30 30 29
|
||||||
|
2124 0 30 29 30 29 29 30 29 30 29 30 29 30
|
||||||
|
2125 0 30 30 29 30 29 29 30 29 30 29 30 29
|
||||||
|
2126 4 30 30 30 29 30 29 29 30 29 30 29 30 29
|
||||||
|
2127 0 30 30 29 30 29 30 29 30 29 30 29 30
|
||||||
|
2128 11 29 30 29 30 30 29 30 29 30 29 30 29 30
|
||||||
|
2129 0 29 30 29 30 29 30 30 29 30 29 30 29
|
||||||
|
2130 0 30 29 30 29 29 30 30 29 30 30 29 30
|
||||||
|
2131 6 29 30 29 29 30 29 30 29 30 30 29 30 30
|
||||||
|
2132 0 29 30 29 29 30 29 30 29 30 29 30 30
|
||||||
|
2133 0 30 29 30 29 30 29 29 29 30 30 29 30
|
||||||
|
2134 5 30 30 29 30 29 29 30 29 29 30 29 30 30
|
||||||
|
2135 0 30 29 30 30 29 29 30 29 30 29 29 30
|
||||||
|
2136 0 30 29 30 30 29 30 29 30 29 30 29 30
|
||||||
|
2137 2 29 30 29 30 29 30 30 29 30 29 30 29 30
|
||||||
|
2138 0 29 30 29 29 30 30 29 30 30 29 30 29
|
||||||
|
2139 7 30 29 29 30 29 30 29 30 30 29 30 30 29
|
||||||
|
2140 0 30 29 29 30 29 30 29 30 29 30 30 30
|
||||||
|
2141 0 29 30 29 29 30 29 29 30 30 29 30 30
|
||||||
|
2142 5 30 29 30 29 30 29 29 29 30 29 30 30 30
|
||||||
|
2143 0 29 30 30 29 29 30 29 29 30 29 30 30
|
||||||
|
2144 0 29 30 30 29 30 29 30 29 30 29 29 30
|
||||||
|
2145 4 30 29 30 30 29 30 29 30 29 30 29 29 30
|
||||||
|
2146 0 29 30 30 29 30 29 30 30 29 30 29 30
|
||||||
|
2147 0 29 29 30 29 30 29 30 30 29 30 30 29
|
||||||
|
2148 1 30 29 29 30 29 30 29 30 30 29 30 30 29
|
||||||
|
2149 0 30 29 29 30 29 30 29 30 29 30 30 30
|
||||||
|
2150 6 29 30 29 30 29 29 29 30 29 30 30 30 29
|
||||||
|
2151 0 30 30 29 30 29 29 29 30 29 30 30 29
|
||||||
|
2152 0 30 30 30 29 29 30 29 29 30 29 30 29
|
||||||
|
2153 5 30 30 30 29 30 29 30 29 30 29 29 30 29
|
||||||
|
2154 0 30 30 29 30 30 29 30 29 30 29 29 30
|
||||||
|
2155 0 29 30 29 30 30 29 30 30 29 30 29 30
|
||||||
|
2156 3 29 29 30 29 30 29 30 30 29 30 30 29 30
|
||||||
|
2157 0 29 29 30 29 30 29 30 29 30 30 30 29
|
||||||
|
2158 7 30 29 29 30 29 29 30 29 30 30 30 29 30
|
||||||
|
2159 0 30 29 30 29 29 29 30 29 30 30 29 30
|
||||||
|
2160 0 30 30 29 29 30 29 29 30 29 30 29 30
|
||||||
|
2161 6 30 30 29 30 29 30 29 29 30 29 30 29 30
|
||||||
|
2162 0 30 29 30 30 29 30 29 29 30 29 30 29
|
||||||
|
2163 0 30 29 30 30 29 30 30 29 30 29 29 30
|
||||||
|
2164 4 29 30 29 30 29 30 30 29 30 30 29 29 30
|
||||||
|
2165 0 29 30 29 30 29 30 29 30 30 29 30 30
|
||||||
|
2166 10 29 29 30 29 29 30 29 30 30 30 29 30 30
|
||||||
|
2167 0 29 29 30 29 29 30 29 30 30 29 30 30
|
||||||
|
2168 0 30 29 29 30 29 29 30 29 30 29 30 30
|
||||||
|
2169 6 30 29 30 29 30 29 29 30 29 30 29 30 30
|
||||||
|
2170 0 29 30 30 29 30 29 29 30 29 30 29 30
|
||||||
|
2171 0 29 30 30 30 29 30 29 29 30 29 30 29
|
||||||
|
2172 5 30 29 30 30 29 30 29 30 29 30 29 30 29
|
||||||
|
2173 0 30 29 30 29 30 30 29 30 29 30 29 30
|
||||||
|
2174 0 29 30 29 30 29 30 29 30 30 29 30 30
|
||||||
|
2175 3 29 29 30 29 29 30 29 30 30 29 30 30 30
|
||||||
|
2176 0 29 29 30 29 29 30 29 30 29 30 30 30
|
||||||
|
2177 7 29 30 29 30 29 29 30 29 30 29 30 30 30
|
||||||
|
2178 0 29 30 29 30 29 29 30 29 30 29 30 30
|
||||||
|
2179 0 29 30 30 29 30 29 29 30 29 30 29 30
|
||||||
|
2180 6 29 30 30 29 30 30 29 29 30 29 30 29 30
|
||||||
|
2181 0 29 30 29 30 30 29 30 29 30 29 30 29
|
||||||
|
2182 0 30 29 30 29 30 29 30 30 29 30 29 30
|
||||||
|
2183 4 29 30 29 30 29 29 30 30 29 30 30 29 30
|
||||||
|
2184 0 29 30 29 29 30 29 30 29 30 30 30 29
|
||||||
|
2185 0 30 29 30 29 29 30 29 30 29 30 30 30
|
||||||
|
2186 2 29 30 29 30 29 29 30 29 29 30 30 29 30
|
||||||
|
2187 0 30 30 29 30 29 29 30 29 29 30 30 29
|
||||||
|
2188 6 30 30 30 29 30 29 29 30 29 30 29 30 29
|
||||||
|
2189 0 30 30 29 30 29 30 29 30 29 30 29 30
|
||||||
|
2190 0 29 30 29 30 30 29 30 29 30 29 30 29
|
||||||
|
2191 5 30 29 30 29 30 29 30 29 30 30 29 30 29
|
||||||
|
2192 0 30 29 29 30 29 30 29 30 30 30 29 30
|
||||||
|
2193 0 29 30 29 29 30 29 30 29 30 30 29 30
|
||||||
|
2194 3 30 29 30 29 29 30 29 29 30 30 29 30 30
|
||||||
|
2195 0 30 29 30 29 29 30 29 29 30 30 29 30
|
||||||
|
2196 7 30 30 29 30 29 29 30 29 29 30 29 30 30
|
||||||
|
2197 0 30 29 30 30 29 29 30 29 29 30 29 30
|
||||||
|
2198 0 30 29 30 30 29 30 29 30 29 30 29 30
|
||||||
|
2199 6 29 30 29 30 29 30 30 29 30 29 30 29 30
|
||||||
Reference in new issue
Block a user