when_exe 0.2.100 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE.ja.txt +25 -25
- data/LICENSE.txt +31 -31
- data/bin/irb.rc +5 -0
- data/bin/locales.rb +2 -2
- data/bin/when.rb +16 -0
- data/bin/when.rb.config +7 -0
- data/lib/when_exe.rb +616 -14
- data/lib/when_exe/basictypes.rb +615 -0
- data/lib/when_exe/calendartypes.rb +1700 -0
- data/lib/when_exe/coordinates.rb +1936 -0
- data/lib/when_exe/core/compatibility.rb +54 -0
- data/lib/when_exe/core/duration.rb +72 -72
- data/lib/when_exe/core/extension.rb +382 -0
- data/lib/when_exe/ephemeris.rb +1845 -0
- data/lib/when_exe/googlecalendar.rb +140 -0
- data/lib/when_exe/icalendar.rb +1587 -0
- data/lib/when_exe/inspect.rb +1237 -0
- data/lib/when_exe/locales/af.rb +90 -0
- data/lib/when_exe/locales/ar.rb +145 -0
- data/lib/when_exe/locales/az.rb +90 -0
- data/lib/when_exe/locales/bg.rb +90 -0
- data/lib/when_exe/locales/bn.rb +94 -0
- data/lib/when_exe/locales/bs.rb +121 -0
- data/lib/when_exe/locales/ca.rb +92 -0
- data/lib/when_exe/locales/cs.rb +107 -0
- data/lib/when_exe/locales/cy.rb +150 -0
- data/lib/when_exe/locales/da.rb +84 -0
- data/lib/when_exe/locales/de.rb +92 -0
- data/lib/when_exe/locales/de_AT.rb +92 -0
- data/lib/when_exe/locales/de_CH.rb +92 -0
- data/lib/when_exe/locales/el.rb +93 -0
- data/lib/when_exe/locales/en.rb +88 -0
- data/lib/when_exe/locales/en_AU.rb +88 -0
- data/lib/when_exe/locales/en_CA.rb +88 -0
- data/lib/when_exe/locales/en_GB.rb +88 -0
- data/lib/when_exe/locales/en_IN.rb +88 -0
- data/lib/when_exe/locales/en_NZ.rb +88 -0
- data/lib/when_exe/locales/eo.rb +89 -0
- data/lib/when_exe/locales/es.rb +84 -0
- data/lib/when_exe/locales/es_419.rb +84 -0
- data/lib/when_exe/locales/es_AR.rb +84 -0
- data/lib/when_exe/locales/es_CL.rb +84 -0
- data/lib/when_exe/locales/es_CO.rb +84 -0
- data/lib/when_exe/locales/es_MX.rb +84 -0
- data/lib/when_exe/locales/es_PE.rb +85 -0
- data/lib/when_exe/locales/es_VE.rb +84 -0
- data/lib/when_exe/locales/et.rb +94 -0
- data/lib/when_exe/locales/eu.rb +95 -0
- data/lib/when_exe/locales/fa.rb +80 -0
- data/lib/when_exe/locales/fi.rb +89 -0
- data/lib/when_exe/locales/fr.rb +88 -0
- data/lib/when_exe/locales/fr_CA.rb +88 -0
- data/lib/when_exe/locales/fr_CH.rb +88 -0
- data/lib/when_exe/locales/gl.rb +81 -0
- data/lib/when_exe/locales/he.rb +84 -0
- data/lib/when_exe/locales/hi.rb +80 -0
- data/lib/when_exe/locales/hi_IN.rb +84 -0
- data/lib/when_exe/locales/hr.rb +128 -0
- data/lib/when_exe/locales/hu.rb +84 -0
- data/lib/when_exe/locales/id.rb +89 -0
- data/lib/when_exe/locales/is.rb +89 -0
- data/lib/when_exe/locales/it.rb +87 -0
- data/lib/when_exe/locales/it_CH.rb +87 -0
- data/lib/when_exe/locales/ja.rb +78 -0
- data/lib/when_exe/locales/kn.rb +86 -0
- data/lib/when_exe/locales/ko.rb +78 -0
- data/lib/when_exe/locales/links.rb +2342 -0
- data/lib/when_exe/locales/lo.rb +123 -0
- data/lib/when_exe/locales/locales.rb +91 -0
- data/lib/when_exe/locales/lt.rb +111 -0
- data/lib/when_exe/locales/lv.rb +118 -0
- data/lib/when_exe/locales/mk.rb +93 -0
- data/lib/when_exe/locales/mn.rb +80 -0
- data/lib/when_exe/locales/nb.rb +81 -0
- data/lib/when_exe/locales/ne.rb +81 -0
- data/lib/when_exe/locales/nl.rb +92 -0
- data/lib/when_exe/locales/nn.rb +73 -0
- data/lib/when_exe/locales/or.rb +84 -0
- data/lib/when_exe/locales/pl.rb +128 -0
- data/lib/when_exe/locales/pt.rb +88 -0
- data/lib/when_exe/locales/pt_BR.rb +88 -0
- data/lib/when_exe/locales/rm.rb +143 -0
- data/lib/when_exe/locales/ro.rb +105 -0
- data/lib/when_exe/locales/ru.rb +128 -0
- data/lib/when_exe/locales/sk.rb +109 -0
- data/lib/when_exe/locales/sl.rb +122 -0
- data/lib/when_exe/locales/sr.rb +122 -0
- data/lib/when_exe/locales/sv.rb +83 -0
- data/lib/when_exe/locales/sw.rb +89 -0
- data/lib/when_exe/locales/th.rb +78 -0
- data/lib/when_exe/locales/tl.rb +99 -0
- data/lib/when_exe/locales/tr.rb +96 -0
- data/lib/when_exe/locales/uk.rb +128 -0
- data/lib/when_exe/locales/uz.rb +128 -0
- data/lib/when_exe/locales/vi.rb +94 -0
- data/lib/when_exe/locales/wo.rb +82 -0
- data/lib/when_exe/locales/zh_CN.rb +77 -0
- data/lib/when_exe/locales/zh_HK.rb +77 -0
- data/lib/when_exe/locales/zh_TW.rb +77 -0
- data/lib/when_exe/mini_application.rb +252 -0
- data/lib/when_exe/parts/enumerator.rb +472 -0
- data/lib/when_exe/parts/geometric_complex.rb +379 -0
- data/lib/when_exe/parts/locale.rb +513 -0
- data/lib/when_exe/parts/method_cash.rb +207 -0
- data/lib/when_exe/parts/resource.rb +806 -0
- data/lib/when_exe/parts/timezone.rb +182 -0
- data/lib/when_exe/region/bahai.rb +145 -0
- data/lib/when_exe/region/balinese.rb +627 -0
- data/lib/when_exe/region/chinese.rb +896 -0
- data/lib/when_exe/region/chinese_calendar.rb +919 -0
- data/lib/when_exe/region/chinese_epoch.rb +1245 -0
- data/lib/when_exe/region/christian.rb +644 -0
- data/lib/when_exe/region/far_east.rb +192 -0
- data/lib/when_exe/region/french.rb +66 -0
- data/lib/when_exe/region/geologicalage.rb +639 -0
- data/lib/when_exe/region/indian.rb +1066 -0
- data/lib/when_exe/region/iranian.rb +66 -0
- data/lib/when_exe/region/islamic.rb +105 -0
- data/lib/when_exe/region/japanese.rb +851 -0
- data/lib/when_exe/region/japanese_notes.rb +964 -0
- data/lib/when_exe/region/japanese_residues.rb +1149 -0
- data/lib/when_exe/region/javanese.rb +228 -0
- data/lib/when_exe/region/jewish.rb +127 -0
- data/lib/when_exe/region/korean.rb +267 -0
- data/lib/when_exe/region/m17n.rb +115 -0
- data/lib/when_exe/region/martian.rb +215 -0
- data/lib/when_exe/region/mayan.rb +122 -0
- data/lib/when_exe/region/moon.rb +333 -0
- data/lib/when_exe/region/nihon_shoki.rb +73 -0
- data/lib/when_exe/region/planets.rb +585 -0
- data/lib/when_exe/region/pope.rb +298 -0
- data/lib/when_exe/region/residue.rb +229 -0
- data/lib/when_exe/region/roman.rb +325 -0
- data/lib/when_exe/region/ryukyu.rb +98 -0
- data/lib/when_exe/region/shire.rb +254 -0
- data/lib/when_exe/region/sun.rb +210 -0
- data/lib/when_exe/region/thai.rb +227 -0
- data/lib/when_exe/region/tibetan.rb +233 -0
- data/lib/when_exe/region/v50.rb +111 -0
- data/lib/when_exe/region/vietnamese.rb +173 -0
- data/lib/when_exe/region/world.rb +197 -0
- data/lib/when_exe/timestandard.rb +547 -0
- data/lib/when_exe/tmduration.rb +330 -330
- data/lib/when_exe/tmobjects.rb +1295 -0
- data/lib/when_exe/tmposition.rb +1955 -0
- data/lib/when_exe/tmreference.rb +1547 -0
- data/lib/when_exe/version.rb +10 -3
- data/link_to_online_documents +4 -0
- data/test/examples/JapanHolidays.ics +456 -0
- data/test/examples/Millennium.ics +17 -0
- data/test/examples/NewYork.ics +61 -0
- data/test/examples/Residue.m17n +135 -0
- data/test/examples/Spatial.m17n +179 -0
- data/test/examples/Terms.m17n +39 -0
- data/test/examples/Test.ics +53 -0
- data/test/examples/USA-DST.ics +61 -0
- data/test/examples/geometric_complex.rb +41 -0
- data/test/examples/sample.xml +14 -0
- data/test/examples/today.rb +61 -0
- data/test/test.rb +54 -19
- data/test/test.rb.config +1 -0
- data/test/test/basictypes.rb +368 -0
- data/test/test/calendartypes.rb +57 -0
- data/test/test/coordinates.rb +380 -0
- data/test/test/ephemeris.rb +127 -0
- data/test/test/googlecalendar.rb +167 -0
- data/test/test/icalendar.rb +848 -0
- data/test/test/inspect.rb +115 -0
- data/test/test/parts.rb +480 -0
- data/test/test/region/chinese.rb +161 -0
- data/test/test/region/french.rb +33 -0
- data/test/test/region/geologicalage.rb +14 -0
- data/test/test/region/indian.rb +55 -0
- data/test/test/region/iran.rb +54 -0
- data/test/test/region/islamic.rb +18 -0
- data/test/test/region/japanese.rb +62 -0
- data/test/test/region/jewish.rb +61 -0
- data/test/test/region/m17n.rb +181 -0
- data/test/test/region/mayan.rb +78 -0
- data/test/test/region/moon.rb +14 -0
- data/test/test/region/planets.rb +14 -0
- data/test/test/region/residue.rb +123 -0
- data/test/test/region/sun.rb +14 -0
- data/test/test/region/thai.rb +94 -0
- data/test/test/region/tibetan.rb +30 -0
- data/test/test/tmobjects.rb +356 -57
- data/test/test/tmposition.rb +237 -0
- data/test/test/tmreference.rb +95 -0
- data/when_exe.gemspec +2 -2
- metadata +187 -7
- data/doc/COPYING +0 -31
- data/doc/COPYING.ja +0 -25
- data/doc/document_url +0 -1
|
@@ -0,0 +1,1700 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
=begin
|
|
3
|
+
Copyright (C) 2011-2013 Takashi SUGA
|
|
4
|
+
|
|
5
|
+
You may use and/or modify this file according to the license described in the LICENSE.txt file included in this archive.
|
|
6
|
+
=end
|
|
7
|
+
|
|
8
|
+
autoload :Rational, 'Rational' unless Object.const_defined?(:Rational)
|
|
9
|
+
|
|
10
|
+
#
|
|
11
|
+
# 具体的な When::TM::ReferenceSystem のサブクラスの実装
|
|
12
|
+
#
|
|
13
|
+
module When::CalendarTypes
|
|
14
|
+
|
|
15
|
+
#
|
|
16
|
+
# Universal Time, Coordinated
|
|
17
|
+
#
|
|
18
|
+
class UTC < When::TM::Clock
|
|
19
|
+
|
|
20
|
+
# この時法の時刻をUTC時刻に変換する
|
|
21
|
+
#
|
|
22
|
+
# Description of an operation for
|
|
23
|
+
# converting a time on this clock to a UTC time
|
|
24
|
+
#
|
|
25
|
+
# @param [When::TM::ClockTime] u_time
|
|
26
|
+
# @return [When::TM::ClockTime]
|
|
27
|
+
#
|
|
28
|
+
def utc_trans(u_time)
|
|
29
|
+
return u_time
|
|
30
|
+
end
|
|
31
|
+
alias :utcTrans :utc_trans
|
|
32
|
+
|
|
33
|
+
# UTC時刻をこの時法の時刻に変換する
|
|
34
|
+
#
|
|
35
|
+
# Description of an operation for
|
|
36
|
+
# converting a UTC time to a time on this clock
|
|
37
|
+
#
|
|
38
|
+
# @param [When::TM::ClockTime] clk_time
|
|
39
|
+
# @return [When::TM::ClockTime]
|
|
40
|
+
#
|
|
41
|
+
def clk_trans(clk_time)
|
|
42
|
+
return clk_time
|
|
43
|
+
end
|
|
44
|
+
alias :clkTrans :clk_trans
|
|
45
|
+
|
|
46
|
+
#
|
|
47
|
+
# Zone 名
|
|
48
|
+
#
|
|
49
|
+
# @return [String]
|
|
50
|
+
#
|
|
51
|
+
def zone
|
|
52
|
+
@label.to_s
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
# オブジェクトの正規化
|
|
58
|
+
def _normalize(args=[], options={})
|
|
59
|
+
@label ||= m17n('Z')
|
|
60
|
+
@indices ||= When::Coordinates::DefaultTimeIndex
|
|
61
|
+
@note ||= 'JulianDayNotes'
|
|
62
|
+
_normalize_temporal
|
|
63
|
+
@second = (@second||128).to_f
|
|
64
|
+
@zone = '+00:00'
|
|
65
|
+
@time_standard ||= When.Resource('_t:UniversalTime')
|
|
66
|
+
@utc_reference = When::TM::ClockTime.new([0,0,0,0], {:frame=>self})
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
#
|
|
71
|
+
# Local Mean Time
|
|
72
|
+
#
|
|
73
|
+
class LMT < UTC
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
|
|
77
|
+
# オブジェクトの正規化
|
|
78
|
+
def _normalize(args=[], options={})
|
|
79
|
+
@label = m17n('LMT')
|
|
80
|
+
@time_standard = When.Resource("_t:LocalMeanTime?location=_l:long=#{@long||0}%26lat=0")
|
|
81
|
+
super
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
#
|
|
86
|
+
# Local Apparent Time
|
|
87
|
+
#
|
|
88
|
+
class LAT < UTC
|
|
89
|
+
|
|
90
|
+
private
|
|
91
|
+
|
|
92
|
+
# オブジェクトの正規化
|
|
93
|
+
def _normalize(args=[], options={})
|
|
94
|
+
@label = m17n('LAT')
|
|
95
|
+
@time_standard = When.Resource("_t:LocalApparentTime?location=_l:long=#{@long||0}%26lat=0")
|
|
96
|
+
super
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
#
|
|
101
|
+
# Temporal Hour System
|
|
102
|
+
#
|
|
103
|
+
class THS < UTC
|
|
104
|
+
|
|
105
|
+
private
|
|
106
|
+
|
|
107
|
+
# オブジェクトの正規化
|
|
108
|
+
def _normalize(args=[], options={})
|
|
109
|
+
@label = m17n('THS')
|
|
110
|
+
@time_standard = When.Resource("_t:TemporalHourSystem?location=_l:long=#{@long||0}%26lat=#{@lat||0}")
|
|
111
|
+
super
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# 月日の配当パターンの種類が限定されている暦の抽象基底クラス
|
|
116
|
+
#
|
|
117
|
+
# Calendar which has some fixed arrangement rules for under year
|
|
118
|
+
#
|
|
119
|
+
# 新年の日付が専用メソッドで与えられ、月日の配当が1年の日数等
|
|
120
|
+
# で決まる暦。いわゆる Rule-Based な暦はほとんど該当します。
|
|
121
|
+
class TableBased < When::TM::Calendar
|
|
122
|
+
|
|
123
|
+
# 年月日 -> 通日
|
|
124
|
+
#
|
|
125
|
+
# @param [Numeric] y 年
|
|
126
|
+
# @param [Integer] m 月 (0 始まり)
|
|
127
|
+
# @param [Integer] d 日 (0 始まり)
|
|
128
|
+
#
|
|
129
|
+
# @return [Integer] 通日
|
|
130
|
+
#
|
|
131
|
+
def _coordinates_to_number(y, m, d)
|
|
132
|
+
sdn = _sdn([+y])
|
|
133
|
+
rule = _rule(_key([+y]))
|
|
134
|
+
sdn += d + rule['Offset'][m]
|
|
135
|
+
return sdn if d >= 0
|
|
136
|
+
return sdn + rule['Length'][m % rule['Length'].length]
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# 通日 - > 年月日
|
|
140
|
+
#
|
|
141
|
+
# @param [Integer] sdn 通日
|
|
142
|
+
#
|
|
143
|
+
# @return [Array<Integer>] [ y, m, d ]
|
|
144
|
+
# y 年
|
|
145
|
+
# m 月 (0 始まり)
|
|
146
|
+
# d 日 (0 始まり)
|
|
147
|
+
#
|
|
148
|
+
def _number_to_coordinates(sdn)
|
|
149
|
+
y, d = Residue.mod(sdn) {|n| _sdn([n])}
|
|
150
|
+
rule = _rule(_key([y]))
|
|
151
|
+
(rule['Months']-1).downto(0) do |m|
|
|
152
|
+
if d >=rule['Offset'][m]
|
|
153
|
+
d -= rule['Offset'][m]
|
|
154
|
+
return [y, m, d]
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
return nil
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# 暦要素数
|
|
161
|
+
#
|
|
162
|
+
# @overload _length(date)
|
|
163
|
+
# @param [Array<Integer>] date ( y )
|
|
164
|
+
#
|
|
165
|
+
# y 年
|
|
166
|
+
#
|
|
167
|
+
# @return [Integer] その年の月数
|
|
168
|
+
#
|
|
169
|
+
# @overload _length(date)
|
|
170
|
+
# @param [Array<Integer>] date ( y, m )
|
|
171
|
+
#
|
|
172
|
+
# y 年
|
|
173
|
+
#
|
|
174
|
+
# m 月 (0 始まり)
|
|
175
|
+
#
|
|
176
|
+
# @return [Integer] その年月の日数
|
|
177
|
+
#
|
|
178
|
+
def _length(date)
|
|
179
|
+
y, m = date
|
|
180
|
+
if (m)
|
|
181
|
+
# 指定した月に含まれる日の数を返します。
|
|
182
|
+
return @unit[2] if @unit[2]
|
|
183
|
+
rule = _rule(_key([y]))
|
|
184
|
+
return rule['Length'][m % rule['Length'].length]
|
|
185
|
+
else
|
|
186
|
+
# 指定した年に含まれる月の数を返します。
|
|
187
|
+
return @unit[1] if @unit[1]
|
|
188
|
+
return _rule(_key([y]))['Months']
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
private
|
|
193
|
+
|
|
194
|
+
# オブジェクトの正規化
|
|
195
|
+
def _normalize(args=[], options={})
|
|
196
|
+
super
|
|
197
|
+
|
|
198
|
+
# rule_table
|
|
199
|
+
# @rule_table = @rule_table.dup
|
|
200
|
+
@rule_table = {'T' => {'Rule' => @rule_table }} if (@rule_table.kind_of?(Array))
|
|
201
|
+
@_m_cash_ = {}
|
|
202
|
+
@_m_cash_["_rule"] = @rule_table
|
|
203
|
+
|
|
204
|
+
# unit length
|
|
205
|
+
unit = @unit[1..2]
|
|
206
|
+
@rule_table.each do |key, rule|
|
|
207
|
+
_make_rule(key, rule, unit) if rule.kind_of?(Hash)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# mean month length
|
|
211
|
+
if @entry_key
|
|
212
|
+
::Rational
|
|
213
|
+
@mean_month = Rational(@rule_table[@entry_key]['Days'], @rule_table[@entry_key]['Months'])
|
|
214
|
+
@mean_year = Rational(@rule_table[@entry_key]['Days'], @rule_table[@entry_key]['Years' ])
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# rule の正規化
|
|
219
|
+
def _make_rule(key, rule, unit=[])
|
|
220
|
+
# @rule_table[key]['Years', 'Months', 'Offset', 'Days']
|
|
221
|
+
rule['IDs'] = Pair._en_pair_array(rule['IDs']) if rule['IDs'].kind_of?(String)
|
|
222
|
+
rule['Years'] ||= 1
|
|
223
|
+
rule['Months'] ||= (rule['IDs']||rule['Length']).length
|
|
224
|
+
rule['Offset'] = []
|
|
225
|
+
sum, len = 0, rule['Length'].length
|
|
226
|
+
rule['Months'].times do |k|
|
|
227
|
+
rule['Offset'] << sum
|
|
228
|
+
sum += rule['Length'][k % len]
|
|
229
|
+
end
|
|
230
|
+
rule['Days'] ||= sum
|
|
231
|
+
|
|
232
|
+
# Months in Year
|
|
233
|
+
unit[0] ||= rule['Months']
|
|
234
|
+
unit[0] = 0 unless (unit[0]==rule['Months'])
|
|
235
|
+
|
|
236
|
+
# Days in Month
|
|
237
|
+
len = rule['Length'][0]
|
|
238
|
+
if rule['Length'].length == 1 && (rule['Days'] % len) == 0
|
|
239
|
+
unit[1] ||= len
|
|
240
|
+
unit[1] = 0 unless (unit[1]==len)
|
|
241
|
+
else
|
|
242
|
+
unit[1] = 0
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
# 年初の通日によるセットアップ
|
|
247
|
+
def _sdn_setup(c_key, c_date)
|
|
248
|
+
n_date = c_date.dup
|
|
249
|
+
n_date[-1] += 1
|
|
250
|
+
n_key = (n_date.length<=1) ? n_date[0] : n_date
|
|
251
|
+
c_sdn = (@_m_cash_["_sdn"][c_key] ||= _sdn_(c_date))
|
|
252
|
+
n_sdn = (@_m_cash_["_sdn"][n_key] ||= _sdn_(n_date))
|
|
253
|
+
key = n_sdn - c_sdn
|
|
254
|
+
rule = (@_m_cash_["_rule"][key] ||= _rule_(key))
|
|
255
|
+
@_m_cash_["_key"] ||= {}
|
|
256
|
+
@_m_cash_["_ids"] ||= {}
|
|
257
|
+
@_m_cash_["_key"][c_key] ||= key
|
|
258
|
+
@_m_cash_["_ids"][c_key] ||= rule['IDs']
|
|
259
|
+
return c_sdn
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# 年初の通日
|
|
263
|
+
# このメソッドは subclass で定義します
|
|
264
|
+
#
|
|
265
|
+
# @param [Array<Numeric>] date ( 年 )
|
|
266
|
+
#
|
|
267
|
+
# @return [Integer] 年初の通日
|
|
268
|
+
#
|
|
269
|
+
def _sdn_(date)
|
|
270
|
+
raise TypeError, "Abstract TableBased Calendar Type"
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# 暦日表のキー取得
|
|
274
|
+
#
|
|
275
|
+
# @param [Array<Numeric>] date ( 年 )
|
|
276
|
+
#
|
|
277
|
+
# @return [Integer] 暦日表のキー 本暦法では当該年の日数を暦日表のキーとします
|
|
278
|
+
#
|
|
279
|
+
def _key_(date)
|
|
280
|
+
n_date = date.dup
|
|
281
|
+
n_date[-1] += 1
|
|
282
|
+
_sdn(n_date) - _sdn(date)
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
# 日時要素の翻訳表の取得
|
|
286
|
+
#
|
|
287
|
+
# @param [Array<Numeric>] date ( 年 )
|
|
288
|
+
#
|
|
289
|
+
# @return [Array<When::Coordinates::Pair>] 日時要素の翻訳表
|
|
290
|
+
#
|
|
291
|
+
def _ids_(date)
|
|
292
|
+
_rule(_key(date))['IDs']
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
# 暦要素数
|
|
296
|
+
#
|
|
297
|
+
# @param [Array<Numeric>] date ( 年 )
|
|
298
|
+
#
|
|
299
|
+
# @return [Integer] その年の日数
|
|
300
|
+
#
|
|
301
|
+
def _sum_(date)
|
|
302
|
+
return _rule(_key([date[0]]))['Days']
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
# 月日の配当
|
|
306
|
+
#
|
|
307
|
+
# @param [Numeric] year 年
|
|
308
|
+
#
|
|
309
|
+
# @return [Array<Integer>] [ 月の日数 ]
|
|
310
|
+
#
|
|
311
|
+
def month_arrangement_(year)
|
|
312
|
+
_rule(_key([year * 1 - @origin_of_MSC]))['Length']
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
# rule の遅延生成
|
|
316
|
+
def _rule_(key)
|
|
317
|
+
rule = {
|
|
318
|
+
'Years' => 1,
|
|
319
|
+
'Months' => key.length,
|
|
320
|
+
'Days' => key.length * 29 + key.gsub(/[a-z]/,'').length,
|
|
321
|
+
'IDs' => [],
|
|
322
|
+
'Length' => [],
|
|
323
|
+
'Offset' => []
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
key.length.times do |k|
|
|
327
|
+
rule['Length'] << (key[k,1] =~ /[a-z]/ ? 29 : 30)
|
|
328
|
+
rule['Offset'] << (k == 0 ? 0 : rule['Offset'][k-1]+rule['Length'][k-1])
|
|
329
|
+
trunk = key.upcase[k]
|
|
330
|
+
branch = (trunk == key.upcase[k-1]) ? 1 : 0
|
|
331
|
+
trunk = trunk.ord if (trunk.kind_of?(String))
|
|
332
|
+
trunk -= 64
|
|
333
|
+
rule['IDs'] << ((branch==0) ? trunk : When::Coordinates::Pair.new(trunk, branch))
|
|
334
|
+
end
|
|
335
|
+
return rule
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
# 表引きにより実現する太陰太陽暦
|
|
340
|
+
#
|
|
341
|
+
# Luni-Solar calendar which uses year / month /day table
|
|
342
|
+
#
|
|
343
|
+
class PatternTableBasedLuniSolar < TableBased
|
|
344
|
+
|
|
345
|
+
private
|
|
346
|
+
|
|
347
|
+
# new で指定された月日配当規則をプログラムで利用可能にします。
|
|
348
|
+
#
|
|
349
|
+
# key 年月日配当規則のハッシュキー
|
|
350
|
+
# rule 年月日配当規則
|
|
351
|
+
#
|
|
352
|
+
# インスタンス変数 ハッシュのハッシュ@rule_table の要素
|
|
353
|
+
# Years => the period length / year
|
|
354
|
+
# Months => the period length / month
|
|
355
|
+
# Days => the period length / day
|
|
356
|
+
# Rule => Array of sub rules' key and offset
|
|
357
|
+
def _make_rule(key, rule, unit=nil)
|
|
358
|
+
|
|
359
|
+
mm, dd = 0, 0
|
|
360
|
+
rule['Rule'].each_index do |k|
|
|
361
|
+
subkey = rule['Rule'][k]
|
|
362
|
+
case subkey
|
|
363
|
+
when String ; rule['Rule'][k] = [subkey, dd, mm]
|
|
364
|
+
when Array ; subkey, dd, mm = rule['Rule'][k]
|
|
365
|
+
else ; raise TypeError, "Irregal subkey type"
|
|
366
|
+
end
|
|
367
|
+
mm += subkey.length
|
|
368
|
+
dd += subkey.length * 29 + subkey.gsub(/[a-z]/,'').length
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
rule['Years'] ||= rule['Rule'].length
|
|
372
|
+
rule['Months'] ||= mm
|
|
373
|
+
rule['Days'] ||= dd
|
|
374
|
+
|
|
375
|
+
@entry_key ||= key
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
# 年初の通日によるセットアップ
|
|
379
|
+
def _sdn_setup(c_key, c_date)
|
|
380
|
+
root_rule = @rule_table[@entry_key]
|
|
381
|
+
count, year = c_date[0].divmod(root_rule['Years'])
|
|
382
|
+
key, dd, mm = root_rule['Rule'][year]
|
|
383
|
+
rule = (@_m_cash_["_rule"][key] ||= _rule_(key))
|
|
384
|
+
@_m_cash_["_key"] ||= {}
|
|
385
|
+
@_m_cash_["_ids"] ||= {}
|
|
386
|
+
@_m_cash_["_key"][c_key] ||= key
|
|
387
|
+
@_m_cash_["_ids"][c_key] ||= rule['IDs']
|
|
388
|
+
@_m_cash_["_sdn"][c_key] ||= @origin_of_LSC + dd + count * root_rule['Days']
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
# 年初の通日
|
|
392
|
+
#
|
|
393
|
+
# @param [Array<Numeric>] date ( y )
|
|
394
|
+
#
|
|
395
|
+
# y 年
|
|
396
|
+
#
|
|
397
|
+
# @return [Integer] 年初の通日
|
|
398
|
+
#
|
|
399
|
+
def _sdn_(date)
|
|
400
|
+
rule = @rule_table[@entry_key]
|
|
401
|
+
count, year = date[0].divmod(rule['Years'])
|
|
402
|
+
return @origin_of_LSC + rule['Rule'][year][1] + count * rule['Days']
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
# 暦日表のキー取得
|
|
406
|
+
#
|
|
407
|
+
# @param [Array<Numeric>] date ( y )
|
|
408
|
+
#
|
|
409
|
+
# y 年
|
|
410
|
+
#
|
|
411
|
+
# @return [Integer] 暦日表のキー
|
|
412
|
+
#
|
|
413
|
+
def _key_(date)
|
|
414
|
+
rule = @rule_table[@entry_key]
|
|
415
|
+
count, year = date[0].divmod(rule['Years'])
|
|
416
|
+
return rule['Rule'][year][0]
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
# オブジェクトの正規化
|
|
420
|
+
#
|
|
421
|
+
# @note インスタンス変数 @note は to_a でデフォルトとして用いる暦注
|
|
422
|
+
#
|
|
423
|
+
def _normalize(args=[], options={})
|
|
424
|
+
@note ||= When.CalendarNote('ChineseNotes') # See when.rb
|
|
425
|
+
super
|
|
426
|
+
end
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
# 年の配当パターンが限定されている暦
|
|
430
|
+
#
|
|
431
|
+
# Calendar which has some fixed arrangement rules of year pattern
|
|
432
|
+
#
|
|
433
|
+
class CyclicTableBased < TableBased
|
|
434
|
+
|
|
435
|
+
# 通日 - > 年月日
|
|
436
|
+
#
|
|
437
|
+
# @param [Integer] sdn 通日
|
|
438
|
+
#
|
|
439
|
+
# @return [Array<Integer>] [ y, m, d ]
|
|
440
|
+
# y 年
|
|
441
|
+
# m 月 (0 始まり)
|
|
442
|
+
# d 日 (0 始まり)
|
|
443
|
+
#
|
|
444
|
+
def _number_to_coordinates(sdn)
|
|
445
|
+
root_rule = @rule_table[@entry_key]
|
|
446
|
+
count, value = (sdn-@origin_of_LSC).divmod(root_rule['Days'])
|
|
447
|
+
y, d, key = _read_period(@entry_key,
|
|
448
|
+
'Days', value,
|
|
449
|
+
'Years', count * root_rule['Years'])
|
|
450
|
+
rule = _rule(key)
|
|
451
|
+
(rule['Months']-1).downto(0) do |m|
|
|
452
|
+
if d >=rule['Offset'][m]
|
|
453
|
+
d -= rule['Offset'][m]
|
|
454
|
+
return [y, m, d]
|
|
455
|
+
end
|
|
456
|
+
end
|
|
457
|
+
return nil
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
private
|
|
461
|
+
|
|
462
|
+
#
|
|
463
|
+
# new で指定された月日配当規則をプログラムで利用可能にします。
|
|
464
|
+
#
|
|
465
|
+
# key 年月日配当規則のハッシュキー
|
|
466
|
+
# rule 年月日配当規則
|
|
467
|
+
#
|
|
468
|
+
# インスタンス変数 ハッシュのハッシュ@rule_table の要素
|
|
469
|
+
# Years => the period length / year
|
|
470
|
+
# Months => the period length / month
|
|
471
|
+
# Days => the period length / day
|
|
472
|
+
# Rule => Array of sub rules' key
|
|
473
|
+
#
|
|
474
|
+
def _make_rule(key, rule, unit=nil)
|
|
475
|
+
if rule.key?('Rule') # Table of Many Years
|
|
476
|
+
['Years', 'Months', 'Days'].each do |u|
|
|
477
|
+
rule[u] ||=
|
|
478
|
+
begin
|
|
479
|
+
s = 0
|
|
480
|
+
rule['Rule'].each do |part|
|
|
481
|
+
subkey, count = part
|
|
482
|
+
subrule = @rule_table[subkey]
|
|
483
|
+
_make_rule(subkey, subrule, unit) unless subrule[u]
|
|
484
|
+
s += (count||1) * subrule[u]
|
|
485
|
+
end
|
|
486
|
+
s
|
|
487
|
+
end
|
|
488
|
+
end
|
|
489
|
+
if !@entry_key ||
|
|
490
|
+
@rule_table[@entry_key]['Days'] < rule['Days']
|
|
491
|
+
@entry_key = key
|
|
492
|
+
end
|
|
493
|
+
else # Table of One Year
|
|
494
|
+
super
|
|
495
|
+
end
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
# 年初の通日によるセットアップ
|
|
499
|
+
def _sdn_setup(c_key, c_date)
|
|
500
|
+
root_rule = @rule_table[@entry_key]
|
|
501
|
+
count, value = c_date[0].divmod(root_rule['Years'])
|
|
502
|
+
sdn, y, key = _read_period(@entry_key,
|
|
503
|
+
'Years', value,
|
|
504
|
+
'Days', @origin_of_LSC + count * root_rule['Days'])
|
|
505
|
+
@_m_cash_["_key"] ||= {}
|
|
506
|
+
@_m_cash_["_ids"] ||= {}
|
|
507
|
+
@_m_cash_["_key"][c_key] ||= key
|
|
508
|
+
@_m_cash_["_ids"][c_key] ||= @_m_cash_["_rule"][key]['IDs']
|
|
509
|
+
@_m_cash_["_sdn"][c_key] ||= sdn
|
|
510
|
+
end
|
|
511
|
+
|
|
512
|
+
# 年初の通日
|
|
513
|
+
#
|
|
514
|
+
# @param [Array<Numeric>] date ( y )
|
|
515
|
+
#
|
|
516
|
+
# y 年
|
|
517
|
+
#
|
|
518
|
+
# @return [Integer] 年初の通日
|
|
519
|
+
#
|
|
520
|
+
def _sdn_(date)
|
|
521
|
+
root_rule = @rule_table[@entry_key]
|
|
522
|
+
count, value = date[0].divmod(root_rule['Years'])
|
|
523
|
+
sdn, y, key = _read_period(@entry_key,
|
|
524
|
+
'Years', value,
|
|
525
|
+
'Days', @origin_of_LSC + count * root_rule['Days'])
|
|
526
|
+
return sdn
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
# 暦日表のキー取得
|
|
530
|
+
#
|
|
531
|
+
# @param [Array<Numeric>] date ( y )
|
|
532
|
+
#
|
|
533
|
+
# y 年
|
|
534
|
+
#
|
|
535
|
+
# @return [Integer] 暦日表のキー
|
|
536
|
+
#
|
|
537
|
+
def _key_(date)
|
|
538
|
+
root_rule = @rule_table[@entry_key]
|
|
539
|
+
count, value = date[0].divmod(root_rule['Years'])
|
|
540
|
+
sdn, y, key = _read_period(@entry_key,
|
|
541
|
+
'Years', value,
|
|
542
|
+
'Days', @origin_of_LSC + count * root_rule['Days'])
|
|
543
|
+
return key
|
|
544
|
+
end
|
|
545
|
+
|
|
546
|
+
# 年の配当規則を読み出します。
|
|
547
|
+
#
|
|
548
|
+
# key 年の配当規則のキー
|
|
549
|
+
# akey 入力が'Days'か'Years'かを指定
|
|
550
|
+
# avalue 入力の'Days'または'Years'の値
|
|
551
|
+
# zkey 出力が'Years'か'Days'かを指定
|
|
552
|
+
# zvalue 出力の'Years'または'Days'の値
|
|
553
|
+
def _read_period(key, akey, avalue, zkey, zvalue)
|
|
554
|
+
rule = @rule_table
|
|
555
|
+
rule[key]['Rule'].each do |part|
|
|
556
|
+
subkey, count, = [*part] << 1
|
|
557
|
+
if avalue >= count * rule[subkey][akey]
|
|
558
|
+
avalue -= count * rule[subkey][akey]
|
|
559
|
+
zvalue += count * rule[subkey][zkey]
|
|
560
|
+
else
|
|
561
|
+
count, avalue = avalue.divmod(rule[subkey][akey])
|
|
562
|
+
zvalue += count * rule[subkey][zkey]
|
|
563
|
+
return zvalue, avalue, subkey unless rule[subkey].key?('Rule')
|
|
564
|
+
return _read_period(subkey, akey, avalue, zkey, zvalue)
|
|
565
|
+
end
|
|
566
|
+
end
|
|
567
|
+
end
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
#
|
|
571
|
+
# 年初を太陽黄経で決定する暦
|
|
572
|
+
#
|
|
573
|
+
class YearLengthTableBased < TableBased
|
|
574
|
+
|
|
575
|
+
# 時間帯
|
|
576
|
+
#
|
|
577
|
+
# @return [Array<Numeric>]
|
|
578
|
+
#
|
|
579
|
+
attr_reader :timezone
|
|
580
|
+
|
|
581
|
+
# 天体暦アルゴリズム
|
|
582
|
+
#
|
|
583
|
+
# @return [Array<When::Ephemeris::Formula>]
|
|
584
|
+
#
|
|
585
|
+
attr_reader :formula
|
|
586
|
+
|
|
587
|
+
#protected
|
|
588
|
+
|
|
589
|
+
private
|
|
590
|
+
|
|
591
|
+
# 年初の通日
|
|
592
|
+
#
|
|
593
|
+
# @param [Array<Numeric>] date ( y )
|
|
594
|
+
#
|
|
595
|
+
# y 年
|
|
596
|
+
#
|
|
597
|
+
# @return [Integer] 年初の通日
|
|
598
|
+
#
|
|
599
|
+
def _sdn_(date)
|
|
600
|
+
y = +date[0]
|
|
601
|
+
t = @formula[0].cn_to_time(y.to_f + @cycle_offset)
|
|
602
|
+
return (t + 0.5 + @day_offset + @timezone[0]).floor
|
|
603
|
+
end
|
|
604
|
+
|
|
605
|
+
# オブジェクトの正規化
|
|
606
|
+
#
|
|
607
|
+
# YearLengthTableBased+オブジェクトの性質定義を初期設定します。
|
|
608
|
+
#
|
|
609
|
+
def _normalize(args=[], options={})
|
|
610
|
+
|
|
611
|
+
Rational
|
|
612
|
+
@cycle_offset = (@cycle_offset||0).to_r
|
|
613
|
+
@day_offset = (@day_offset||0).to_r
|
|
614
|
+
@timezone = (@timezone||0).to_r
|
|
615
|
+
@formula = 'Formula?formula=1S'
|
|
616
|
+
|
|
617
|
+
super
|
|
618
|
+
end
|
|
619
|
+
end
|
|
620
|
+
|
|
621
|
+
# 月日の配当が太陽または月の位置によって決定される暦
|
|
622
|
+
#
|
|
623
|
+
# Calendar based on the ephemeris of the Sun or the Moon
|
|
624
|
+
#
|
|
625
|
+
class EphemerisBased < When::TM::Calendar
|
|
626
|
+
|
|
627
|
+
# 天体暦
|
|
628
|
+
#
|
|
629
|
+
# @return [When::Ephmeris::Formula]
|
|
630
|
+
#
|
|
631
|
+
attr_reader :formula
|
|
632
|
+
|
|
633
|
+
#protected
|
|
634
|
+
|
|
635
|
+
# 年月日 -> 通日
|
|
636
|
+
#
|
|
637
|
+
# @param [Numeric] y 年
|
|
638
|
+
# @param [Integer] m 月 (0 始まり)
|
|
639
|
+
# @param [Integer] d 日 (0 始まり)
|
|
640
|
+
#
|
|
641
|
+
# @return [Integer] 通日
|
|
642
|
+
#
|
|
643
|
+
def _coordinates_to_number(y, m, d)
|
|
644
|
+
_new_month(@months_in_year * (+y) + m) + d
|
|
645
|
+
end
|
|
646
|
+
|
|
647
|
+
# 通日 - > 年月日
|
|
648
|
+
#
|
|
649
|
+
# @param [Integer] sdn 通日
|
|
650
|
+
#
|
|
651
|
+
# @return [Array<Integer>] [ y, m, d ]
|
|
652
|
+
# y 年
|
|
653
|
+
# m 月 (0 始まり)
|
|
654
|
+
# d 日 (0 始まり)
|
|
655
|
+
#
|
|
656
|
+
def _number_to_coordinates(sdn)
|
|
657
|
+
m, d = Residue.mod(sdn) {|m| _new_month(m)}
|
|
658
|
+
y, m = m.divmod(@months_in_year)
|
|
659
|
+
return y, m, d
|
|
660
|
+
end
|
|
661
|
+
|
|
662
|
+
# 暦要素数
|
|
663
|
+
#
|
|
664
|
+
# @overload _length(date)
|
|
665
|
+
# @param [Array<Integer>] date ( y )
|
|
666
|
+
#
|
|
667
|
+
# y 年
|
|
668
|
+
#
|
|
669
|
+
# @return [Integer] その年の月数
|
|
670
|
+
#
|
|
671
|
+
# @overload _length(date)
|
|
672
|
+
# @param [Array<Integer>] date ( y, m )
|
|
673
|
+
#
|
|
674
|
+
# y 年
|
|
675
|
+
#
|
|
676
|
+
# m 月 (0 始まり)
|
|
677
|
+
#
|
|
678
|
+
# @return [Integer] その年月の日数
|
|
679
|
+
#
|
|
680
|
+
def _length(date)
|
|
681
|
+
y, m = date
|
|
682
|
+
if (m)
|
|
683
|
+
# 指定した月に含まれる日の数を返します。
|
|
684
|
+
m += @months_in_year * +y
|
|
685
|
+
return _new_month(m+1) - _new_month(m)
|
|
686
|
+
else
|
|
687
|
+
# 指定した年に含まれる月の数を返します。
|
|
688
|
+
return @months_in_year
|
|
689
|
+
end
|
|
690
|
+
end
|
|
691
|
+
|
|
692
|
+
# 暦要素数
|
|
693
|
+
#
|
|
694
|
+
# @param [Array<Numeric>] date ( y )
|
|
695
|
+
#
|
|
696
|
+
# y 年
|
|
697
|
+
#
|
|
698
|
+
# @return [Integer] その年の日数
|
|
699
|
+
#
|
|
700
|
+
def _sum_(date)
|
|
701
|
+
y, = date
|
|
702
|
+
m = @months_in_year * +y
|
|
703
|
+
return _new_month(m+@months_in_year) - _new_month(m)
|
|
704
|
+
end
|
|
705
|
+
|
|
706
|
+
private
|
|
707
|
+
|
|
708
|
+
# オブジェクトの正規化
|
|
709
|
+
#
|
|
710
|
+
# @months_in_year = 1年の月の数
|
|
711
|
+
#
|
|
712
|
+
def _normalize(args=[], options={})
|
|
713
|
+
@months_in_year ||= 12
|
|
714
|
+
super
|
|
715
|
+
end
|
|
716
|
+
end
|
|
717
|
+
|
|
718
|
+
# 月日の配当が太陽の位置によって決定される太陽暦
|
|
719
|
+
#
|
|
720
|
+
# Calendar based on the ephemeris of the Sun
|
|
721
|
+
#
|
|
722
|
+
class EphemerisBasedSolar < EphemerisBased
|
|
723
|
+
|
|
724
|
+
# 時間帯
|
|
725
|
+
#
|
|
726
|
+
# @return [Array<Numeric>]
|
|
727
|
+
#
|
|
728
|
+
attr_reader :timezone
|
|
729
|
+
|
|
730
|
+
#protected
|
|
731
|
+
|
|
732
|
+
# 月初の通日
|
|
733
|
+
#
|
|
734
|
+
# @param [Integer] m 通月
|
|
735
|
+
#
|
|
736
|
+
# @return [Integer] 月初の通日
|
|
737
|
+
#
|
|
738
|
+
def _new_month_(m)
|
|
739
|
+
return (@formula[0].cn_to_time(m + @cycle_offset) + 0.5 + @timezone[0]).floor
|
|
740
|
+
end
|
|
741
|
+
|
|
742
|
+
private
|
|
743
|
+
|
|
744
|
+
# オブジェクトの正規化
|
|
745
|
+
# @cycle_offset = 位相のオフセット / 1か月分の角度
|
|
746
|
+
# @formula = 位相の計算に用いる太陽の Formula
|
|
747
|
+
#
|
|
748
|
+
def _normalize(args=[], options={})
|
|
749
|
+
@cycle_offset ||= -1.5
|
|
750
|
+
@formula ||= "Formula?formula=#{@months_in_year||12}S"
|
|
751
|
+
super
|
|
752
|
+
end
|
|
753
|
+
end
|
|
754
|
+
|
|
755
|
+
# 月日の配当が月の位相によって決定される純太陰暦
|
|
756
|
+
#
|
|
757
|
+
# Calendar based on the ephemeris of the Moon
|
|
758
|
+
#
|
|
759
|
+
class EphemerisBasedLunar < EphemerisBased
|
|
760
|
+
|
|
761
|
+
# 時間帯
|
|
762
|
+
#
|
|
763
|
+
# @return [Array<Numeric, (Numeric)>]
|
|
764
|
+
#
|
|
765
|
+
attr_reader :timezone
|
|
766
|
+
|
|
767
|
+
#protected
|
|
768
|
+
|
|
769
|
+
# 月初の通日
|
|
770
|
+
#
|
|
771
|
+
# @param [Integer] m 通月
|
|
772
|
+
#
|
|
773
|
+
# @return [Integer] 月初の通日
|
|
774
|
+
#
|
|
775
|
+
def _new_month_(m)
|
|
776
|
+
return (@formula[-1].cn_to_time(m + @cycle_offset) + 0.5 + @timezone[-1]).floor
|
|
777
|
+
end
|
|
778
|
+
|
|
779
|
+
private
|
|
780
|
+
|
|
781
|
+
# オブジェクトの正規化
|
|
782
|
+
# @cycle_offset = Goldstein Number に対する暦元の補正
|
|
783
|
+
#
|
|
784
|
+
def _normalize(args=[], options={})
|
|
785
|
+
@cycle_offset ||= 1671 * 12 + 4
|
|
786
|
+
super
|
|
787
|
+
end
|
|
788
|
+
end
|
|
789
|
+
|
|
790
|
+
# 月日の配当が太陽および月の位置によって決定される太陰太陽暦
|
|
791
|
+
#
|
|
792
|
+
# Calendar based on the ephemeris of the Sun and the Moon
|
|
793
|
+
#
|
|
794
|
+
class EphemerisBasedLuniSolar < EphemerisBasedSolar
|
|
795
|
+
|
|
796
|
+
# 計算方法
|
|
797
|
+
# @return [Array<When::Ephemeris::Formula>]
|
|
798
|
+
attr_reader :formula
|
|
799
|
+
|
|
800
|
+
#protected
|
|
801
|
+
|
|
802
|
+
# 年月日 -> 通日
|
|
803
|
+
#
|
|
804
|
+
# @param [Numeric] yy 年
|
|
805
|
+
# @param [Integer] mm 月 (0 始まり)
|
|
806
|
+
# @param [Integer] dd 日 (0 始まり)
|
|
807
|
+
#
|
|
808
|
+
# @return [Integer] 通日
|
|
809
|
+
#
|
|
810
|
+
def _coordinates_to_number(yy, mm=0, dd=0)
|
|
811
|
+
_new_month(_new_year_month(+yy) + mm) + dd
|
|
812
|
+
end
|
|
813
|
+
|
|
814
|
+
# 通日 - > 年月日
|
|
815
|
+
#
|
|
816
|
+
# @param [Integer] sdn 通日
|
|
817
|
+
#
|
|
818
|
+
# @return [Array<Integer>] ( y, m, d )
|
|
819
|
+
# [ y 年 ]
|
|
820
|
+
# [ m 月 (0 始まり) ]
|
|
821
|
+
# [ d 日 (0 始まり) ]
|
|
822
|
+
#
|
|
823
|
+
def _number_to_coordinates(sdn)
|
|
824
|
+
nn, dd = Residue.mod(sdn) {|m| _new_month(m)}
|
|
825
|
+
yy, mm = Residue.mod(nn) {|y| _new_year_month(y)}
|
|
826
|
+
[yy, mm, dd]
|
|
827
|
+
end
|
|
828
|
+
|
|
829
|
+
# 暦要素数
|
|
830
|
+
#
|
|
831
|
+
# @overload _length(date)
|
|
832
|
+
# @param [Array<Integer>] date ( 年 )
|
|
833
|
+
# @return [Integer] その年の月数
|
|
834
|
+
#
|
|
835
|
+
# @overload _length(date)
|
|
836
|
+
# @param [Array<Integer>] date ( 年, 月 )
|
|
837
|
+
# @note 月は 0 始まり
|
|
838
|
+
# @return [Integer] その年月の日数
|
|
839
|
+
#
|
|
840
|
+
def _length(date)
|
|
841
|
+
y, m = date
|
|
842
|
+
if (m)
|
|
843
|
+
# 指定した月に含まれる日の数を返します。
|
|
844
|
+
m += _new_year_month(+y)
|
|
845
|
+
return _new_month(m+1) - _new_month(m)
|
|
846
|
+
else
|
|
847
|
+
# 指定した年に含まれる月の数を返します。
|
|
848
|
+
return _ids([y]).length
|
|
849
|
+
end
|
|
850
|
+
end
|
|
851
|
+
|
|
852
|
+
private
|
|
853
|
+
|
|
854
|
+
# 暦要素数
|
|
855
|
+
#
|
|
856
|
+
# @param [Array<Numeric>] date ( y )
|
|
857
|
+
#
|
|
858
|
+
# y 年
|
|
859
|
+
#
|
|
860
|
+
# @return [Integer] その年の日数
|
|
861
|
+
#
|
|
862
|
+
def _sum_(date)
|
|
863
|
+
y = +date[0]
|
|
864
|
+
return _new_month(_new_year_month(y+1)) - _new_month(_new_year_month(y))
|
|
865
|
+
end
|
|
866
|
+
|
|
867
|
+
# 太陽月初の通日
|
|
868
|
+
#
|
|
869
|
+
#
|
|
870
|
+
alias :_new_epoch_ :_new_month_
|
|
871
|
+
|
|
872
|
+
# 太陰月初の通日
|
|
873
|
+
#
|
|
874
|
+
# @param [Integer] m 通月
|
|
875
|
+
#
|
|
876
|
+
# @return [Integer] 月初の通日
|
|
877
|
+
#
|
|
878
|
+
def _new_month_(m)
|
|
879
|
+
(@formula[-1].cn_to_time(m) + 0.5 + @timezone[-1]).floor
|
|
880
|
+
end
|
|
881
|
+
|
|
882
|
+
# 年初の通月
|
|
883
|
+
#
|
|
884
|
+
# @param [Integer] y 年
|
|
885
|
+
#
|
|
886
|
+
# @return [Integer] 年初の通月
|
|
887
|
+
#
|
|
888
|
+
def _new_year_month_(y)
|
|
889
|
+
raise TypeError, 'EphemerisBasedLuniSolar is abstract class'
|
|
890
|
+
end
|
|
891
|
+
|
|
892
|
+
# オブジェクトの正規化
|
|
893
|
+
#
|
|
894
|
+
# @cycle_offset = 雨水の場合 -1
|
|
895
|
+
# @formula = 位相の計算に用いる太陽と月の Formula
|
|
896
|
+
# @timezone[1] = 進朔量
|
|
897
|
+
# @notes = to_a でデフォルトとして用いる暦注
|
|
898
|
+
#
|
|
899
|
+
def _normalize(args=[], options={})
|
|
900
|
+
@formula ||= ['Formula?formula=12S', 'Formula?formula=1L']
|
|
901
|
+
super
|
|
902
|
+
end
|
|
903
|
+
end
|
|
904
|
+
|
|
905
|
+
#
|
|
906
|
+
# 日時要素の境界 - Border
|
|
907
|
+
#
|
|
908
|
+
class Border < When::TM::ReferenceSystem
|
|
909
|
+
#
|
|
910
|
+
# 境界の振舞
|
|
911
|
+
#
|
|
912
|
+
# @return [Numeric]
|
|
913
|
+
#
|
|
914
|
+
# Pair(-1,+1) - 暦年/暦日が進む(境界が前年/日にあり、境界後が当年/日の扱いになる)
|
|
915
|
+
#
|
|
916
|
+
# Pair( 0, 0) - 暦年/暦日が戻る(境界が当年/日にあり、境界前が前年/日の扱いになる)
|
|
917
|
+
#
|
|
918
|
+
def behavior
|
|
919
|
+
@border[0]
|
|
920
|
+
end
|
|
921
|
+
|
|
922
|
+
# 境界の取得
|
|
923
|
+
#
|
|
924
|
+
# @param [Array<Numeric>] date 境界を計算する年/日
|
|
925
|
+
# @param [When::TM::ReferenceSystem] frame 使用する暦法/時法
|
|
926
|
+
#
|
|
927
|
+
# @return [Array<Numeric>] その年/日の境界
|
|
928
|
+
#
|
|
929
|
+
def border(date=[], frame=nil)
|
|
930
|
+
last = date.length-1
|
|
931
|
+
return @border if (last<0)
|
|
932
|
+
bDate = date[0..last] + @border[(last+1)..-1]
|
|
933
|
+
branch = @border[last] * 0
|
|
934
|
+
return bDate if (branch==0)
|
|
935
|
+
bDate[last] = When::Coordinates::Pair.new(+date[last]-branch, branch)
|
|
936
|
+
return bDate
|
|
937
|
+
end
|
|
938
|
+
|
|
939
|
+
# 境界の正規化
|
|
940
|
+
#
|
|
941
|
+
# @param [Array<Numeric>] date 境界を計算する年/日
|
|
942
|
+
# @param [When::TM::ReferenceSystem] frame 使用する暦法/時法
|
|
943
|
+
#
|
|
944
|
+
# @return [Array<Numeric>] その年/日の境界
|
|
945
|
+
#
|
|
946
|
+
def _adjust_epoch(date, frame=nil)
|
|
947
|
+
s_date = date.dup
|
|
948
|
+
e_date = border(date[0..0], frame)
|
|
949
|
+
branch = behavior * 0
|
|
950
|
+
branch += 1 if ((s_date[1..-1] <=> e_date[1..-1]) < 0)
|
|
951
|
+
s_date[0] = When::Coordinates::Pair.new(+s_date[0]-branch, branch)
|
|
952
|
+
return s_date
|
|
953
|
+
end
|
|
954
|
+
|
|
955
|
+
private
|
|
956
|
+
|
|
957
|
+
# 要素の正規化
|
|
958
|
+
def _normalize(args=[], options={})
|
|
959
|
+
@border = When::Coordinates::Pair._en_pair_date_time(@border) if (@border.kind_of?(String))
|
|
960
|
+
end
|
|
961
|
+
end
|
|
962
|
+
|
|
963
|
+
#
|
|
964
|
+
# 日時要素の境界 - 年/日によって、異なる境界を使用する場合
|
|
965
|
+
#
|
|
966
|
+
class MultiBorder < Border
|
|
967
|
+
|
|
968
|
+
#
|
|
969
|
+
# 境界の配列
|
|
970
|
+
# @return [Array<When::CalendarTypes::Border>]
|
|
971
|
+
attr_reader :borders
|
|
972
|
+
|
|
973
|
+
#
|
|
974
|
+
# 境界の振舞
|
|
975
|
+
#
|
|
976
|
+
# @return [Numeric]
|
|
977
|
+
#
|
|
978
|
+
# Pair(-1,+1) - 暦年/暦日が進む(境界が前年/日にあり、境界後が当年/日の扱いになる)
|
|
979
|
+
#
|
|
980
|
+
# Pair( 0, 0) - 暦年/暦日が戻る(境界が当年/日にあり、境界前が前年/日の扱いになる)
|
|
981
|
+
#
|
|
982
|
+
def behavior
|
|
983
|
+
@borders[0][:border].behavior
|
|
984
|
+
end
|
|
985
|
+
|
|
986
|
+
# 境界の取得
|
|
987
|
+
#
|
|
988
|
+
# @param [Array<Numeric>] date 境界を計算する年/日
|
|
989
|
+
# @param [When::TM::ReferenceSystem] frame 使用する暦法/時法
|
|
990
|
+
#
|
|
991
|
+
# @return [Array<Numeric>] その年/日の境界
|
|
992
|
+
#
|
|
993
|
+
def border(date=[], frame=nil)
|
|
994
|
+
last = date.length-1
|
|
995
|
+
return @borders[0][:boder] if (last<0)
|
|
996
|
+
@borders.each do |border|
|
|
997
|
+
return border[:border].border(date, frame) if date[0] >= border[:key]
|
|
998
|
+
end
|
|
999
|
+
date[0..last]
|
|
1000
|
+
end
|
|
1001
|
+
|
|
1002
|
+
# 境界の正規化
|
|
1003
|
+
#
|
|
1004
|
+
# @param [Array<Numeric>] date 境界を計算する年/日
|
|
1005
|
+
# @param [When::TM::ReferenceSystem] frame 使用する暦法/時法
|
|
1006
|
+
#
|
|
1007
|
+
# @return [Array<Numeric>] その年/日の境界
|
|
1008
|
+
#
|
|
1009
|
+
def _adjust_epoch(date, frame=nil)
|
|
1010
|
+
@borders.each do |border|
|
|
1011
|
+
next unless date[0] >= border[:key]
|
|
1012
|
+
s_date = date.dup
|
|
1013
|
+
e_date = border[:border].border(date[0..0], frame)
|
|
1014
|
+
branch = border[:border].behavior * 0
|
|
1015
|
+
branch += 1 if ((s_date[1..-1] <=> e_date[1..-1]) < 0)
|
|
1016
|
+
s_date[0] = When::Coordinates::Pair.new(+s_date[0]-branch, branch)
|
|
1017
|
+
return s_date
|
|
1018
|
+
end
|
|
1019
|
+
date
|
|
1020
|
+
end
|
|
1021
|
+
|
|
1022
|
+
private
|
|
1023
|
+
|
|
1024
|
+
# 要素の正規化
|
|
1025
|
+
def _normalize(args=[], options={})
|
|
1026
|
+
if @borders.kind_of?(String)
|
|
1027
|
+
list = @borders.split(/(\(.+?\))/)
|
|
1028
|
+
list.shift if list[0]==''
|
|
1029
|
+
list.unshift(-Float::MAX) unless list[0] =~ /\(/
|
|
1030
|
+
list.push('0-1-1') if list[-1] =~ /\(/
|
|
1031
|
+
@borders = []
|
|
1032
|
+
loop do
|
|
1033
|
+
key, border, *list = list
|
|
1034
|
+
break unless key
|
|
1035
|
+
key = $1.to_i if key.kind_of?(String) && /\((.+?)\)/ =~ key
|
|
1036
|
+
border = "_c:Border?border=#{border}" unless border =~ /^[A-Z_]/i
|
|
1037
|
+
border = When.Calendar(border)
|
|
1038
|
+
@borders << {:key=>key, :border=>border}
|
|
1039
|
+
end
|
|
1040
|
+
end
|
|
1041
|
+
@borders = @borders.sort_by {|border| -border[:key]}
|
|
1042
|
+
end
|
|
1043
|
+
end
|
|
1044
|
+
|
|
1045
|
+
#
|
|
1046
|
+
# 日時要素の境界 - 日の出,日の入り
|
|
1047
|
+
#
|
|
1048
|
+
class DayBorder < Border
|
|
1049
|
+
|
|
1050
|
+
# 境界の取得
|
|
1051
|
+
#
|
|
1052
|
+
# @param [Array<Numeric>] date 境界を計算する日
|
|
1053
|
+
# @param [When::TM::ReferenceSystem] clock 使用する時法
|
|
1054
|
+
#
|
|
1055
|
+
# @return [Array<Numeric>] その日の境界
|
|
1056
|
+
#
|
|
1057
|
+
# @note 属性 @event によって境界を計算する (see {When::Ephemeris::Formula#day_event})
|
|
1058
|
+
#
|
|
1059
|
+
def border(date=[], clock=When.utc)
|
|
1060
|
+
return @border unless date[0] && clock.formula
|
|
1061
|
+
|
|
1062
|
+
clock._encode(
|
|
1063
|
+
clock._number_to_coordinates(clock.second *
|
|
1064
|
+
clock.time_standard.from_dynamical_time(
|
|
1065
|
+
When::TM::JulianDate._d_to_t(
|
|
1066
|
+
clock.formula[-1].day_event(
|
|
1067
|
+
clock.time_standard.to_dynamical_date(date[0]), @event, When.Resource('_ep:Sun'), @height
|
|
1068
|
+
)))), false)
|
|
1069
|
+
end
|
|
1070
|
+
end
|
|
1071
|
+
|
|
1072
|
+
#
|
|
1073
|
+
# 日時要素の境界 - 日の出
|
|
1074
|
+
#
|
|
1075
|
+
class SunRise < DayBorder
|
|
1076
|
+
|
|
1077
|
+
private
|
|
1078
|
+
|
|
1079
|
+
# 要素の正規化
|
|
1080
|
+
def _normalize(args=[], options={})
|
|
1081
|
+
@border = [0,0,0,0]
|
|
1082
|
+
@event = -1
|
|
1083
|
+
@height ||= '0'
|
|
1084
|
+
end
|
|
1085
|
+
end
|
|
1086
|
+
|
|
1087
|
+
#
|
|
1088
|
+
# 日時要素の境界 - 日の入り
|
|
1089
|
+
#
|
|
1090
|
+
class SunSet < DayBorder
|
|
1091
|
+
|
|
1092
|
+
private
|
|
1093
|
+
|
|
1094
|
+
# 要素の正規化
|
|
1095
|
+
def _normalize(args=[], options={})
|
|
1096
|
+
@border = [When::Coordinates::Pair.new(+1,-1),0,0,0]
|
|
1097
|
+
@event = +1
|
|
1098
|
+
@height ||= '0'
|
|
1099
|
+
end
|
|
1100
|
+
end
|
|
1101
|
+
|
|
1102
|
+
#
|
|
1103
|
+
# 暦注 - Calendar Note
|
|
1104
|
+
#
|
|
1105
|
+
class CalendarNote < When::TM::ReferenceSystem
|
|
1106
|
+
|
|
1107
|
+
#
|
|
1108
|
+
# 暦注要素への名前アクセス機能提供
|
|
1109
|
+
#
|
|
1110
|
+
module LabelAccess
|
|
1111
|
+
attr_reader :_pool
|
|
1112
|
+
|
|
1113
|
+
#
|
|
1114
|
+
# 暦注要素への名前(label)によるアクセス
|
|
1115
|
+
#
|
|
1116
|
+
# @param [Numeric] key 配列インデックスと見なしてアクセス
|
|
1117
|
+
# @param [String] key 名前(label)と見なしてアクセス
|
|
1118
|
+
#
|
|
1119
|
+
# @return [Object] 暦注要素
|
|
1120
|
+
#
|
|
1121
|
+
def [](key)
|
|
1122
|
+
return super if key.kind_of?(Numeric)
|
|
1123
|
+
@_pool ||= Hash[*(inject([]) {|pair, v| pair << v.label.to_s << v})]
|
|
1124
|
+
@_pool[key]
|
|
1125
|
+
end
|
|
1126
|
+
end
|
|
1127
|
+
|
|
1128
|
+
#
|
|
1129
|
+
# 暦注要素のひな形クラス
|
|
1130
|
+
#
|
|
1131
|
+
class NoteElement < When::BasicTypes::Object
|
|
1132
|
+
#
|
|
1133
|
+
# _m17n_form のための要素生成
|
|
1134
|
+
#
|
|
1135
|
+
# @param [Hash] options 未使用
|
|
1136
|
+
#
|
|
1137
|
+
def _to_hash_value(options={})
|
|
1138
|
+
label
|
|
1139
|
+
end
|
|
1140
|
+
end
|
|
1141
|
+
|
|
1142
|
+
# デフォルトイベント名
|
|
1143
|
+
#
|
|
1144
|
+
# @return [String]
|
|
1145
|
+
#
|
|
1146
|
+
# @note イベント名の後ろに数字が使われている場合、数字部分以降はイベントメソッドの引数になります。
|
|
1147
|
+
# SolarTermsクラスで 'term180' は、太陽黄経180度のイベントすなわち秋分を意味します。
|
|
1148
|
+
#
|
|
1149
|
+
attr_accessor :event
|
|
1150
|
+
protected :event=
|
|
1151
|
+
|
|
1152
|
+
# デフォルトイベントの指定
|
|
1153
|
+
#
|
|
1154
|
+
# @param [String] event 指定値を@eventとした新しいオブジェクトを作る
|
|
1155
|
+
#
|
|
1156
|
+
# @return [When::CalendarTypes::CalendarNote]
|
|
1157
|
+
#
|
|
1158
|
+
def copy(event)
|
|
1159
|
+
c = self.clone
|
|
1160
|
+
c.event = event
|
|
1161
|
+
c
|
|
1162
|
+
end
|
|
1163
|
+
|
|
1164
|
+
# 典型的なイベントの発生間隔
|
|
1165
|
+
#
|
|
1166
|
+
# @param [String] event
|
|
1167
|
+
#
|
|
1168
|
+
# @return [When::TM::PeriodDuration]
|
|
1169
|
+
#
|
|
1170
|
+
def duration(event=@event)
|
|
1171
|
+
void, event, parameter = event.split(/^([^\d]+)/)
|
|
1172
|
+
send((event+'_delta').downcase.to_sym, parameter)
|
|
1173
|
+
end
|
|
1174
|
+
|
|
1175
|
+
# 指定の日時が指定イベントに該当するか?
|
|
1176
|
+
#
|
|
1177
|
+
# @param [When::TM::TemporalPosition] date チェックされる日時
|
|
1178
|
+
# @param [String] event チェックするイベント名
|
|
1179
|
+
#
|
|
1180
|
+
# @return [Boolean]
|
|
1181
|
+
# [ true - 該当する ]
|
|
1182
|
+
# [ false - 該当しない ]
|
|
1183
|
+
#
|
|
1184
|
+
def include?(date, event=@event)
|
|
1185
|
+
enum_for(date, :forward, event.downcase).next.include?(date)
|
|
1186
|
+
end
|
|
1187
|
+
|
|
1188
|
+
# Enumeratorの生成
|
|
1189
|
+
#
|
|
1190
|
+
# @param [When::TM::TemporalPosition] first 始点
|
|
1191
|
+
# @param [Symbol] direction
|
|
1192
|
+
# [:forward] 昇順
|
|
1193
|
+
# [:reverse] 降順
|
|
1194
|
+
# @param [String] event イベント名
|
|
1195
|
+
# @param [Integer] count_limit 繰り返し回数(デフォルトは指定なし)
|
|
1196
|
+
#
|
|
1197
|
+
# @return [Enumerator]
|
|
1198
|
+
#
|
|
1199
|
+
def enum_for(first, direction=:forward, event=@event, count_limit=nil)
|
|
1200
|
+
Enumerator.new(self, first, direction, event, count_limit)
|
|
1201
|
+
end
|
|
1202
|
+
alias :to_enum :enum_for
|
|
1203
|
+
|
|
1204
|
+
# 暦注の計算
|
|
1205
|
+
#
|
|
1206
|
+
# @param [When::TM::TemporalPosition] date 暦注を計算する日時
|
|
1207
|
+
# @param [When::TM::TemporalPosition 以外] date When::TM::TemporalPosition に変換して使用する
|
|
1208
|
+
# @param [String] options { :notes => String } という Hash の指定と等価
|
|
1209
|
+
# @param [Integer] options { :indices => Integer} という Hash の指定と等価
|
|
1210
|
+
# @param [Hash] options 下記のとおり
|
|
1211
|
+
# @option options [Integer] :indices Integerで指定した暦座標の暦注を計算
|
|
1212
|
+
# [ When::DAY ( 0) - 日 ]
|
|
1213
|
+
# [ When::MONTH(-1) - 月 ]
|
|
1214
|
+
# [ When::YEAR (-2) - 年 ]
|
|
1215
|
+
#
|
|
1216
|
+
# @option options [Array<Integer>] :indices Integerで指定したすべて暦座標の暦注を計算
|
|
1217
|
+
# @option options [nil] :indices すべての暦座標の暦注を計算(デフォルト)
|
|
1218
|
+
# @option options [String] :notes 計算する暦注名(日の暦注)
|
|
1219
|
+
# @option options [Integer] :notes 計算する暦注のビット配列(日の暦注)
|
|
1220
|
+
# @option options [Array<Array<String>>] :notes 計算する暦注名の Array の Array
|
|
1221
|
+
# @option options [Array<Integer>] :notes 計算する暦注のビット配列の Array
|
|
1222
|
+
# @option options [:all] :notes すべての暦注を計算
|
|
1223
|
+
# @option options [:prime, nil] :notes @prime に登録した暦注を計算、@prime未登録なら :all と同じ(デフォルト)
|
|
1224
|
+
# @option options [Hash] :conditions 暦注計算の条件
|
|
1225
|
+
# [ :location => 暦注計算の基準となる場所(String or When::Coordinates::Spatial) ]
|
|
1226
|
+
# [ その他のキー => 個々の暦注クラスごとにその他のキーを使用できる ]
|
|
1227
|
+
#
|
|
1228
|
+
# @option options [Hash] その他のキー date を When::TM::TemporalPosition に変換するために使用する
|
|
1229
|
+
# see {When::TM::TemporalPosition._instance}
|
|
1230
|
+
#
|
|
1231
|
+
# @note 暦注のビットアドレスは、暦注サブクラスのNoteObjects定数の中の定義順序による。
|
|
1232
|
+
# When::CalendarTypes::CalendarNote クラスの場合 new の引数とした暦注要素リストの定義順序による。
|
|
1233
|
+
# ビットアドレスの値が 1 の暦注が計算対象となる。
|
|
1234
|
+
#
|
|
1235
|
+
# @return [Hash] :notes が String の場合、指定の暦注の計算結果を返す。
|
|
1236
|
+
# @return [Array<Hash>] 上記に該当せず、:indices が Integer の場合、指定の暦座標の暦注計算結果を返す。
|
|
1237
|
+
# @return [Array<Array<Hash>>] 上記のいずれにも該当しない場合、暦注計算結果を返す。
|
|
1238
|
+
# [ :note => 暦注要素 (When::Coordinates::Residue, String, When::BasicTypes::M17n) ]
|
|
1239
|
+
# [ :value => 暦注の値 (When::Coordinates::Residue, String, When::BasicTypes::M17n, When::TM::TemporalPosition) ]
|
|
1240
|
+
#
|
|
1241
|
+
# @note
|
|
1242
|
+
# 戻り値の :value が When::TM::TemporalPosition の場合、その日時オブジェクトの events[0] に暦注名の入った
|
|
1243
|
+
# 暦注に該当する日付である。(例) Christian クラス で easter を計算した場合、当該年の復活祭の日付オブジェクトが返る。
|
|
1244
|
+
# @note
|
|
1245
|
+
# 暦注サブクラスの場合、暦注要素が増えたり、:note の暦注要素の型が変わったりすることがある。
|
|
1246
|
+
#
|
|
1247
|
+
def notes(date, options={})
|
|
1248
|
+
dates, indices, notes, conditions, options = _parse(date, options)
|
|
1249
|
+
_result(indices.map {|i|
|
|
1250
|
+
next [] unless i <= date.precision
|
|
1251
|
+
_note_values(dates, notes[i-1], _all_keys[i-1], _elements[i-1]) do |dates, focused_notes, notes_hash|
|
|
1252
|
+
focused_notes.each do |note|
|
|
1253
|
+
unless notes_hash[note]
|
|
1254
|
+
void, event, *parameter = note.split(/^([^\d]+)/)
|
|
1255
|
+
method = event.downcase
|
|
1256
|
+
notes_hash[note] =
|
|
1257
|
+
if respond_to?(method)
|
|
1258
|
+
send(method, dates, *parameter)
|
|
1259
|
+
else
|
|
1260
|
+
_elements[i-1][note].send(When::Coordinates::PRECISION_NAME[i].downcase, dates)
|
|
1261
|
+
end
|
|
1262
|
+
end
|
|
1263
|
+
end
|
|
1264
|
+
notes_hash
|
|
1265
|
+
end
|
|
1266
|
+
}, options)
|
|
1267
|
+
end
|
|
1268
|
+
|
|
1269
|
+
#
|
|
1270
|
+
# 暦注の一致 or 不一致
|
|
1271
|
+
#
|
|
1272
|
+
# @param [When::TM::TemporalPosition] date 暦注を確認する日時
|
|
1273
|
+
# @param [When::TM::TemporalPosition 以外] date When::TM::TemporalPosition に変換して使用する
|
|
1274
|
+
# @param [String] options { :notes => String } または { :value => String } という Hash の指定と等価
|
|
1275
|
+
# (指定の notes が存在する場合は前者、しない場合は後者)
|
|
1276
|
+
# @param [Integer] options { :indices => Integer } という Hash の指定と等価
|
|
1277
|
+
# @param [Hash] options 下記のとおり
|
|
1278
|
+
# @option options [暦注の値] :value 確認する暦注の値
|
|
1279
|
+
# @option options [それぞれ] その他 {When::CalendarTypes::CalendarNote#notes} を参照
|
|
1280
|
+
#
|
|
1281
|
+
# @return [Boolean]
|
|
1282
|
+
# [ true - 暦注が一致 ]
|
|
1283
|
+
# [ false - 暦注が不一致 ]
|
|
1284
|
+
#
|
|
1285
|
+
def note?(date, options={})
|
|
1286
|
+
options = _find_note(options) if options.kind_of?(String)
|
|
1287
|
+
value = options.delete(:value) if options.kind_of?(Hash)
|
|
1288
|
+
result = notes(date, options)
|
|
1289
|
+
result = [result] unless result.kind_of?(Array)
|
|
1290
|
+
result = result.flatten.compact
|
|
1291
|
+
return false unless result.size > 0
|
|
1292
|
+
return true unless value
|
|
1293
|
+
result.each do |hash|
|
|
1294
|
+
return true if value == hash[:value]
|
|
1295
|
+
end
|
|
1296
|
+
return false
|
|
1297
|
+
end
|
|
1298
|
+
|
|
1299
|
+
# 年の名前を暦注として返す
|
|
1300
|
+
# @method year
|
|
1301
|
+
# @return [When::BasicTypes::M17n]
|
|
1302
|
+
|
|
1303
|
+
# 月の名前を暦注として返す
|
|
1304
|
+
# @method month
|
|
1305
|
+
# @return [When::BasicTypes::M17n]
|
|
1306
|
+
|
|
1307
|
+
# 日の名前を暦注として返す
|
|
1308
|
+
# @method day
|
|
1309
|
+
# @return [When::BasicTypes::M17n]
|
|
1310
|
+
|
|
1311
|
+
#
|
|
1312
|
+
# 標準的な暦注として、暦座標の値の名前を暦注として返すメソッドを登録
|
|
1313
|
+
#
|
|
1314
|
+
# @private
|
|
1315
|
+
['year', 'month', 'day'].each do |c|
|
|
1316
|
+
module_eval %Q{
|
|
1317
|
+
def #{c}(date)
|
|
1318
|
+
date.name('#{c}')
|
|
1319
|
+
end
|
|
1320
|
+
}
|
|
1321
|
+
end
|
|
1322
|
+
|
|
1323
|
+
private
|
|
1324
|
+
|
|
1325
|
+
#
|
|
1326
|
+
# オブジェクトの正規化
|
|
1327
|
+
#
|
|
1328
|
+
def _normalize(args=[], options={})
|
|
1329
|
+
@_elements = (args.size == 0 && self.class.const_defined?(:NoteObjects)) ?
|
|
1330
|
+
When::SourceURI + self.class.to_s.split(/::/)[1..-1].join('/') + '/NoteObjects' :
|
|
1331
|
+
_to_iri(args, options[:prefix] || '_co:')
|
|
1332
|
+
if @_elements.kind_of?(Array)
|
|
1333
|
+
@_elements.each do |e|
|
|
1334
|
+
e.extend LabelAccess
|
|
1335
|
+
end
|
|
1336
|
+
end
|
|
1337
|
+
end
|
|
1338
|
+
|
|
1339
|
+
# 暦注要素
|
|
1340
|
+
#
|
|
1341
|
+
# @return [Array<Array<When::Parts::Resource>>]
|
|
1342
|
+
#
|
|
1343
|
+
def _elements
|
|
1344
|
+
@_elements = When.Resource(@_elements) if @_elements.kind_of?(String)
|
|
1345
|
+
@_elements
|
|
1346
|
+
end
|
|
1347
|
+
|
|
1348
|
+
#
|
|
1349
|
+
# [[暦注名]](全暦注)
|
|
1350
|
+
#
|
|
1351
|
+
# @return [Array<Array<String, When::BasicTypes::M17n>>]
|
|
1352
|
+
#
|
|
1353
|
+
def _all_keys
|
|
1354
|
+
@_all_keys ||= _elements.map { |c|
|
|
1355
|
+
c.map {|n|
|
|
1356
|
+
n.label.to_s
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
end
|
|
1360
|
+
|
|
1361
|
+
#
|
|
1362
|
+
# [[暦注名]](主要暦注)
|
|
1363
|
+
#
|
|
1364
|
+
# @return [Array<Array<When::Parts::Resource>>]
|
|
1365
|
+
#
|
|
1366
|
+
def _prime_keys
|
|
1367
|
+
@prime ||= _all_keys
|
|
1368
|
+
end
|
|
1369
|
+
|
|
1370
|
+
#
|
|
1371
|
+
# notes メソッドの引数を parse する
|
|
1372
|
+
#
|
|
1373
|
+
# @return [Array] dates, indices, notes
|
|
1374
|
+
#
|
|
1375
|
+
def _parse(date, options)
|
|
1376
|
+
options =
|
|
1377
|
+
case options
|
|
1378
|
+
when Hash ; options
|
|
1379
|
+
when String ; {:notes => options}
|
|
1380
|
+
when Integer ; {:indices => options}
|
|
1381
|
+
else ; {}
|
|
1382
|
+
end
|
|
1383
|
+
conditions = options.delete(:conditions) || {}
|
|
1384
|
+
_opt = options.dup
|
|
1385
|
+
notes = _notes(_opt.delete(:notes) || :prime)
|
|
1386
|
+
indices = _indices(_opt.delete(:indices), notes)
|
|
1387
|
+
date = When.when?(date, _opt) unless date.kind_of?(When::TM::TemporalPosition)
|
|
1388
|
+
[_to_date_for_note(date), indices, notes, conditions, options]
|
|
1389
|
+
end
|
|
1390
|
+
|
|
1391
|
+
#
|
|
1392
|
+
# notes メソッドの 文字列引数の意味を解釈する
|
|
1393
|
+
#
|
|
1394
|
+
# @return [Hash] options for note String
|
|
1395
|
+
#
|
|
1396
|
+
def _find_note(note)
|
|
1397
|
+
_elements.each_index do |index|
|
|
1398
|
+
return {:notes=>note, :indices => [-index]} if _elements[-1-index]._pool[note]
|
|
1399
|
+
end
|
|
1400
|
+
{:value => note}
|
|
1401
|
+
end
|
|
1402
|
+
|
|
1403
|
+
#
|
|
1404
|
+
# 計算する暦注
|
|
1405
|
+
#
|
|
1406
|
+
# @return [Array<Array<String>, Integer>]
|
|
1407
|
+
#
|
|
1408
|
+
def _notes(notes)
|
|
1409
|
+
case notes
|
|
1410
|
+
when :all ; _all_keys
|
|
1411
|
+
when :prime ; _prime_keys
|
|
1412
|
+
when Integer ; [notes]
|
|
1413
|
+
when String ; [[notes]]
|
|
1414
|
+
else ; notes
|
|
1415
|
+
end
|
|
1416
|
+
end
|
|
1417
|
+
|
|
1418
|
+
#
|
|
1419
|
+
# 暦注を計算する暦座標の配列
|
|
1420
|
+
#
|
|
1421
|
+
# @return [Array<Integer>]
|
|
1422
|
+
#
|
|
1423
|
+
def _indices(indices, notes)
|
|
1424
|
+
case indices
|
|
1425
|
+
when nil ; (0...notes.size).to_a.reverse.map {|i| -i}
|
|
1426
|
+
when Range ; indices.to_a
|
|
1427
|
+
when Array ; indices
|
|
1428
|
+
else ; [indices.to_i]
|
|
1429
|
+
end
|
|
1430
|
+
end
|
|
1431
|
+
|
|
1432
|
+
#
|
|
1433
|
+
# notes メソッドの結果を後処理する
|
|
1434
|
+
#
|
|
1435
|
+
# @return [Array<Array>, Array, String]
|
|
1436
|
+
#
|
|
1437
|
+
def _result(result, options)
|
|
1438
|
+
return result[0][0] if options[:notes].kind_of?(String)
|
|
1439
|
+
return result[0] if options[:indices].kind_of?(Numeric)
|
|
1440
|
+
return result
|
|
1441
|
+
end
|
|
1442
|
+
|
|
1443
|
+
#
|
|
1444
|
+
# 年月日暦注計算の共通処理 - コールバック元
|
|
1445
|
+
#
|
|
1446
|
+
def _note_values(dates, focused_notes, all_notes, note_objects)
|
|
1447
|
+
return [] unless dates && all_notes
|
|
1448
|
+
|
|
1449
|
+
# prepare focused notes
|
|
1450
|
+
case focused_notes
|
|
1451
|
+
when Integer
|
|
1452
|
+
bits = focused_notes << 1
|
|
1453
|
+
focused_notes = all_notes.dup.delete_if { (bits>>=1)[0] == 1 }
|
|
1454
|
+
when []
|
|
1455
|
+
focused_notes = all_notes
|
|
1456
|
+
when nil
|
|
1457
|
+
focused_notes = []
|
|
1458
|
+
end
|
|
1459
|
+
not_focused_notes = all_notes - focused_notes
|
|
1460
|
+
notes = {}
|
|
1461
|
+
not_focused_notes.each do |note|
|
|
1462
|
+
notes[note] = true
|
|
1463
|
+
end
|
|
1464
|
+
focused_notes.each do |note|
|
|
1465
|
+
notes[note] = nil
|
|
1466
|
+
end
|
|
1467
|
+
|
|
1468
|
+
# update notes
|
|
1469
|
+
notes = yield(dates, focused_notes, notes)
|
|
1470
|
+
notes.keys.each do |note|
|
|
1471
|
+
notes.delete(note) unless focused_notes.include?(note)
|
|
1472
|
+
end
|
|
1473
|
+
|
|
1474
|
+
# return Array of Hash
|
|
1475
|
+
focused_notes.map {|note|
|
|
1476
|
+
next nil unless notes[note]
|
|
1477
|
+
if note_objects[note].respond_to?(:to_note_hash)
|
|
1478
|
+
note_objects[note].to_note_hash(notes[note], dates)
|
|
1479
|
+
else
|
|
1480
|
+
{:note=>note_objects[note].label, :value=>notes[note]}
|
|
1481
|
+
end
|
|
1482
|
+
}.compact
|
|
1483
|
+
end
|
|
1484
|
+
|
|
1485
|
+
#
|
|
1486
|
+
# 再帰的に配列の中を Resource化する
|
|
1487
|
+
#
|
|
1488
|
+
def _to_iri(args, prefix)
|
|
1489
|
+
args.map {|arg|
|
|
1490
|
+
case arg
|
|
1491
|
+
when String
|
|
1492
|
+
arg, method = $1, $2 if (arg =~ /^(.+)#([_A-Z0-9]+)$/i)
|
|
1493
|
+
obj = When.Resource(arg, prefix)
|
|
1494
|
+
obj = obj.copy(method) if method
|
|
1495
|
+
obj
|
|
1496
|
+
when Array
|
|
1497
|
+
_to_iri(arg, prefix)
|
|
1498
|
+
else
|
|
1499
|
+
arg
|
|
1500
|
+
end
|
|
1501
|
+
}
|
|
1502
|
+
end
|
|
1503
|
+
|
|
1504
|
+
#
|
|
1505
|
+
# 暦日を当該暦注計算用クラスに変換
|
|
1506
|
+
#
|
|
1507
|
+
# 基底クラスである本クラスでは何もしないで、引数をそのまま返す
|
|
1508
|
+
#
|
|
1509
|
+
def _to_date_for_note(date)
|
|
1510
|
+
date
|
|
1511
|
+
end
|
|
1512
|
+
|
|
1513
|
+
#
|
|
1514
|
+
# イベントを取得する Enumerator
|
|
1515
|
+
#
|
|
1516
|
+
class Enumerator < When::Parts::Enumerator
|
|
1517
|
+
|
|
1518
|
+
#
|
|
1519
|
+
# 次のイベントを得る
|
|
1520
|
+
#
|
|
1521
|
+
# @return [When::TM::TemporalPosition]
|
|
1522
|
+
#
|
|
1523
|
+
def _succ
|
|
1524
|
+
@current = (@current==:first) ? @first : event_eval(@current + @delta)
|
|
1525
|
+
end
|
|
1526
|
+
|
|
1527
|
+
# オブジェクトの生成
|
|
1528
|
+
#
|
|
1529
|
+
# @param [When::CalendarTypes::CalendarNote] parent 暦注アルゴリズム
|
|
1530
|
+
# @param [When::TM::TemporalPosition] first 始点
|
|
1531
|
+
# @param [Symbol] direction
|
|
1532
|
+
# [:forward] 昇順
|
|
1533
|
+
# [:reverse] 降順
|
|
1534
|
+
# @param [String] event イベント名
|
|
1535
|
+
# @param [Integer] count_limit 繰り返し回数(デフォルトは指定なし)
|
|
1536
|
+
#
|
|
1537
|
+
def initialize(parent, first, direction, event, count_limit=nil)
|
|
1538
|
+
@parent = parent
|
|
1539
|
+
void, @event, @parameter = event.split(/^([^\d]+)/)
|
|
1540
|
+
@delta = @parent.send((@event+'_delta').to_sym, @parameter)
|
|
1541
|
+
instance_eval %Q{
|
|
1542
|
+
def event_eval(date)
|
|
1543
|
+
@parent.#{@event}(date, @parameter)
|
|
1544
|
+
end
|
|
1545
|
+
}
|
|
1546
|
+
date = event_eval(first)
|
|
1547
|
+
if direction == :reverse
|
|
1548
|
+
@delta = -@delta
|
|
1549
|
+
date = event_eval(first + @delta) if first.to_i < date.to_i
|
|
1550
|
+
else
|
|
1551
|
+
date = event_eval(first + @delta) if first.to_i > date.to_i
|
|
1552
|
+
end
|
|
1553
|
+
super(@parent, date, direction, count_limit)
|
|
1554
|
+
end
|
|
1555
|
+
end
|
|
1556
|
+
end
|
|
1557
|
+
|
|
1558
|
+
class CalendarNote
|
|
1559
|
+
#
|
|
1560
|
+
# 太陽と月の位置によるイベント
|
|
1561
|
+
#
|
|
1562
|
+
class LuniSolarPositions < self
|
|
1563
|
+
|
|
1564
|
+
# 座標の分子
|
|
1565
|
+
#
|
|
1566
|
+
# @return [Numeric]
|
|
1567
|
+
#
|
|
1568
|
+
attr_reader :num
|
|
1569
|
+
|
|
1570
|
+
# 座標の分母
|
|
1571
|
+
#
|
|
1572
|
+
# @return [Numeric]
|
|
1573
|
+
#
|
|
1574
|
+
attr_reader :den
|
|
1575
|
+
|
|
1576
|
+
# 計算アルゴリズム
|
|
1577
|
+
#
|
|
1578
|
+
# @return [When::Ephemeris::Formula]
|
|
1579
|
+
#
|
|
1580
|
+
attr_reader :formula
|
|
1581
|
+
|
|
1582
|
+
# enumerator の周期
|
|
1583
|
+
#
|
|
1584
|
+
# @return [Numeric]
|
|
1585
|
+
#
|
|
1586
|
+
attr_reader :delta
|
|
1587
|
+
|
|
1588
|
+
# 没滅計算用の補正
|
|
1589
|
+
#
|
|
1590
|
+
# @return [Numeric]
|
|
1591
|
+
#
|
|
1592
|
+
attr_reader :margin
|
|
1593
|
+
|
|
1594
|
+
# イベントの日時
|
|
1595
|
+
#
|
|
1596
|
+
# @param [When::TM::TemporalPosition] date イベントを探す基準とする日時
|
|
1597
|
+
# @param [Array<Numeric>] parameter 座標の分子と分母( num, den)
|
|
1598
|
+
#
|
|
1599
|
+
# num 座標の分子 (デフォルト @num)
|
|
1600
|
+
#
|
|
1601
|
+
# den 座標の分母 (デフォルト @den)
|
|
1602
|
+
#
|
|
1603
|
+
# @param [String] parameter 座標の分子と分母("#{ num }/#{ den }" の形式)
|
|
1604
|
+
# @param [Integer] precision 取得したい時間位置の分解能(デフォルト date の分解能)
|
|
1605
|
+
#
|
|
1606
|
+
# @return [When::TM::CalDate] date またはその直後のイベントの日時
|
|
1607
|
+
#
|
|
1608
|
+
def term(date, parameter=nil, precision=date.precision)
|
|
1609
|
+
precision = nil if precision == When::SYSTEM
|
|
1610
|
+
num, den = parameter.kind_of?(String) ? parameter.split(/\//, 2) : parameter
|
|
1611
|
+
num = (num || @num).to_f
|
|
1612
|
+
den = (den || @den).to_f
|
|
1613
|
+
date = date.floor(precision) if precision
|
|
1614
|
+
options = date._attr
|
|
1615
|
+
quot, mod = (@formula.time_to_cn(date)*30.0).divmod(den)
|
|
1616
|
+
cycle = quot * den + num
|
|
1617
|
+
cycle += den if mod > num
|
|
1618
|
+
time = When::TM::JulianDate._d_to_t(@formula.cn_to_time(cycle/30.0))
|
|
1619
|
+
time = date.time_standard.from_dynamical_time(time) if @formula.is_dynamical
|
|
1620
|
+
date = date.frame.jul_trans(When::TM::JulianDate.universal_time(time), options)
|
|
1621
|
+
precision ? date.floor(precision) : date
|
|
1622
|
+
end
|
|
1623
|
+
|
|
1624
|
+
# 日付に対応する座標
|
|
1625
|
+
#
|
|
1626
|
+
# @param [When::TM::TemporalPosition] date 日付
|
|
1627
|
+
# @param [Numeric] delta 周期の補正(下弦,上弦の場合 0.5, その他は0(デフォルト))
|
|
1628
|
+
#
|
|
1629
|
+
# @return [Array<Integer>] Array< Integer, 0 or 1 or 2 >
|
|
1630
|
+
#
|
|
1631
|
+
# [Integer] 対応する座標
|
|
1632
|
+
#
|
|
1633
|
+
# [0 or 1 or 2] 座標の進み(0 なら 没日, 2 なら滅)
|
|
1634
|
+
#
|
|
1635
|
+
def position(date, delta=0)
|
|
1636
|
+
date = date.floor
|
|
1637
|
+
p0, p1 = [date, date.succ].map {|d| (@formula.time_to_cn(d)*30.0-@margin+delta).floor}
|
|
1638
|
+
[p1 % @den, p1-p0]
|
|
1639
|
+
end
|
|
1640
|
+
|
|
1641
|
+
#
|
|
1642
|
+
# イベントの標準的な間隔を返す
|
|
1643
|
+
#
|
|
1644
|
+
# @param [String] parameter 座標の分子と分母("#{ num }/#{ den }" の形式)
|
|
1645
|
+
#
|
|
1646
|
+
# @return [When::TM::IntervalLength]
|
|
1647
|
+
def term_delta(parameter=nil)
|
|
1648
|
+
return @delta unless parameter
|
|
1649
|
+
num, den = parameter.split(/\//, 2)
|
|
1650
|
+
When::TM::IntervalLength.new([(den || @den).to_f-1,1].max, 'day')
|
|
1651
|
+
end
|
|
1652
|
+
end
|
|
1653
|
+
|
|
1654
|
+
#
|
|
1655
|
+
# 二十四節気
|
|
1656
|
+
#
|
|
1657
|
+
class SolarTerms < LuniSolarPositions
|
|
1658
|
+
|
|
1659
|
+
private
|
|
1660
|
+
|
|
1661
|
+
# オブジェクトの正規化
|
|
1662
|
+
# num - 太陽黄経/度の分子 (デフォルト 0 - 春分)
|
|
1663
|
+
# den - 太陽黄経/度の分母 (デフォルト 360 - 1年)
|
|
1664
|
+
# formula - 計算アルゴリズム(デフォルト '_ep:Formula?formula=12S')
|
|
1665
|
+
# delta - enumerator の周期 (デフォルト (den/360)年)
|
|
1666
|
+
# margin - 没滅計算用の補正 (デフォルト 1E-8)
|
|
1667
|
+
def _normalize(args=[], options={})
|
|
1668
|
+
num, den, formula, delta, margin = args
|
|
1669
|
+
@num = (num || @num || 0).to_f
|
|
1670
|
+
@den = (den || @den || 360).to_f
|
|
1671
|
+
@formula = When.Resource(formula || @formula ||'Formula?formula=12S', '_ep:')
|
|
1672
|
+
@delta = When.Duration(delta || @delta || When::TM::IntervalLength.new(@den/360, 'year'))
|
|
1673
|
+
@margin = (margin || @margin || 1E-8).to_f
|
|
1674
|
+
end
|
|
1675
|
+
end
|
|
1676
|
+
|
|
1677
|
+
#
|
|
1678
|
+
# 月の位相
|
|
1679
|
+
#
|
|
1680
|
+
class LunarPhases < LuniSolarPositions
|
|
1681
|
+
|
|
1682
|
+
private
|
|
1683
|
+
|
|
1684
|
+
# オブジェクトの正規化
|
|
1685
|
+
# num - 月の位相/12度の分子 (デフォルト 0 - 朔)
|
|
1686
|
+
# den - 月の位相/12度の分母 (デフォルト 30 - 1月)
|
|
1687
|
+
# formula - 計算アルゴリズム(デフォルト '_ep:Formula?formula=1L')
|
|
1688
|
+
# delta - enumerator の周期 (デフォルト (den/30)月)
|
|
1689
|
+
# margin - 没滅計算用の補正 (デフォルト 1E-8)
|
|
1690
|
+
def _normalize(args=[], options={})
|
|
1691
|
+
num, den, formula, delta, margin = args
|
|
1692
|
+
@num = (num || @num || 0).to_f
|
|
1693
|
+
@den = (den || @den || 30).to_f
|
|
1694
|
+
@formula = When.Resource(formula || @formula ||'Formula?formula=1L', '_ep:')
|
|
1695
|
+
@delta = When.Duration(delta || @delta || When::TM::IntervalLength.new(@den/30, 'month'))
|
|
1696
|
+
@margin = (margin || @margin || 1E-8).to_f
|
|
1697
|
+
end
|
|
1698
|
+
end
|
|
1699
|
+
end
|
|
1700
|
+
end
|