support show parent ticket at worktime view.
@@ -4,6 +4,7 @@ | ||
4 | 4 | from datetime import datetime |
5 | 5 | from pkg_resources import resource_filename |
6 | 6 | from trac.log import logger_factory |
7 | +from trac.config import BoolOption | |
7 | 8 | from trac.core import * |
8 | 9 | from trac.util import Markup |
9 | 10 | from trac.util.datefmt import utc, to_utimestamp |
@@ -19,6 +20,8 @@ | ||
19 | 20 | |
20 | 21 | class WorktimeRecorder(Component): |
21 | 22 | implements(INavigationContributor, IRequestHandler, ITemplateProvider) |
23 | + | |
24 | + show_parent_ticket = BoolOption('steinschart', 'show_parent_ticket', 'false', """Show parent ticket (needs subtickets plugin).(default: false)""") | |
22 | 25 | |
23 | 26 | def __init__(self): |
24 | 27 | locale_dir = resource_filename('tracsteinschart', 'locale') |
@@ -81,7 +84,7 @@ | ||
81 | 84 | add_warning(req,"チケット#%sの残り作業時間%sが実数ではありません。" % (id ,p[property])) |
82 | 85 | except ValueError: |
83 | 86 | pass |
84 | - self.log.info(params) | |
87 | + self.log.debug(params) | |
85 | 88 | if len(errors)==0: |
86 | 89 | self.update_tickets(req,cursor,db,params) |
87 | 90 | user = req.authname |
@@ -88,20 +91,34 @@ | ||
88 | 91 | def addMessage(s): |
89 | 92 | messages.extend([s]); |
90 | 93 | |
91 | - tickets = self.get_tickets(req, cursor) | |
92 | - # replace error fields | |
93 | - self.log.info(errors) | |
94 | - self.log.info(tickets) | |
95 | - for e in errors: | |
96 | - id = int(e['id']) | |
97 | - for ticket in tickets: | |
98 | - if ticket['id']==id: | |
99 | - ticket[e['name']]=e['value'] | |
94 | + show_parent_ticket = self.config.getbool('steinschart','show_parent_ticket') | |
95 | + if show_parent_ticket: | |
96 | + tickets = self.get_nested_tickets(req, cursor) | |
97 | +# for e in errors: | |
98 | +# id = int(e['id']) | |
99 | +# for ptickets in tickets.values(): | |
100 | +# for ntickets in ptickets.values(): | |
101 | +# for ticket in ntickets: | |
102 | +# if ticket['id']==id: | |
103 | +# ticket[e['name']]=e['value'] | |
104 | + | |
105 | + | |
106 | + else: | |
107 | + tickets = self.get_tickets(req, cursor) | |
108 | +# for e in errors: | |
109 | +# id = int(e['id']) | |
110 | +# for ticket in tickets: | |
111 | +# if ticket['id']==id: | |
112 | +# ticket[e['name']]=e['value'] | |
113 | + | |
100 | 114 | |
101 | 115 | add_script(req, 'steinschart/js/worktime.js') |
102 | 116 | add_stylesheet(req, 'common/css/report.css') |
103 | - return 'worktime.html', {'tickets':tickets, 'req':req, 'today': datetime.today()}, None | |
104 | - | |
117 | + if show_parent_ticket: | |
118 | + return 'worktime_nestedticket.html', {'tickets':tickets, 'req':req, 'today': datetime.today()}, None | |
119 | + else: | |
120 | + return 'worktime.html', {'tickets':tickets, 'req':req, 'today': datetime.today()}, None | |
121 | + | |
105 | 122 | def update_tickets(self, req, cursor, db, params): |
106 | 123 | change_time = datetime.now(utc) |
107 | 124 | for ticket_id in params: |
@@ -127,7 +144,7 @@ | ||
127 | 144 | (ticket_id, to_utimestamp(change_time), req.authname, hours)) |
128 | 145 | if abs(current_estimatedhours - estimatedhours) >= 0.01: |
129 | 146 | changed = True |
130 | - self.log.info("change estimatedhours: %s -> %s" % | |
147 | + self.log.debug("change estimatedhours: %s -> %s" % | |
131 | 148 | (current_estimatedhours, estimatedhours)) |
132 | 149 | ticket["estimatedhours"] = str(estimatedhours) |
133 | 150 |
@@ -148,6 +165,75 @@ | ||
148 | 165 | ticket.save_changes(author=req.authname, when=change_time) |
149 | 166 | db.commit() |
150 | 167 | |
168 | + def get_nested_tickets(self, req, cursor): | |
169 | + sql = """SELECT t.milestone ,sub.parent ,parent.summary ,t.id ,t.type ,t.owner, t.summary ,t.priority ,cth.value ,cbil.value , cest.value FROM ticket t | |
170 | + JOIN ticket_custom cth ON t.id=cth.ticket | |
171 | + JOIN ticket_custom cbil ON t.id=cbil.ticket | |
172 | + JOIN ticket_custom cest ON t.id=cest.ticket | |
173 | + LEFT JOIN subtickets sub ON t.id=sub.child | |
174 | + LEFT JOIN ticket parent ON parent.id=sub.parent | |
175 | + WHERE t.status <> 'closed' AND t.owner='%s' AND | |
176 | + cth.name='totalhours' AND cbil.name='billable' AND cest.name='estimatedhours' | |
177 | + ORDER BY t.milestone, sub.parent""" % req.authname | |
178 | + cursor.execute(sql) | |
179 | + tickets = [] | |
180 | + ptickets = {} | |
181 | + current_milestone='' | |
182 | + current_psummary='' | |
183 | + current_pid=0 | |
184 | + mtickets = {} | |
185 | + for milestone, pid, psummary, id, type, owner, summary, priority, totalhours, billable, estimatedhours in cursor: | |
186 | + # 初回のループの場合、初期化 | |
187 | + if current_pid == 0: | |
188 | + current_milestone = milestone | |
189 | + current_pid = pid | |
190 | + current_psummary = psummary | |
191 | + if not pid: | |
192 | + current_psummary = u'その他(親チケットなし)' | |
193 | + | |
194 | + billable = 'true' if billable=='1' else 'false' | |
195 | + totalhours = totalhours if totalhours!='' else '0' | |
196 | + estimatedhours = estimatedhours if totalhours!='' else '0' | |
197 | + t = {'pid':pid, 'psummary':psummary, 'id':id ,'type':type, 'owner': owner, 'summary':summary, 'priority': priority , 'milestone':milestone, 'totalhours': totalhours, 'billable': billable, 'estimatedhours': estimatedhours} | |
198 | + if milestone == current_milestone: | |
199 | + if pid!= current_pid: | |
200 | + ptickets[(current_pid, current_psummary)]=tickets; | |
201 | + tickets = [] | |
202 | + tickets.append(t) | |
203 | + current_pid = pid | |
204 | + current_psummary = psummary | |
205 | + if not pid: | |
206 | + current_psummary = u'その他(親チケットなし)' | |
207 | + else: | |
208 | + ptickets[(current_pid, current_psummary)]=tickets; | |
209 | + mtickets[current_milestone] = ptickets | |
210 | + ptickets = {} | |
211 | + tickets = [] | |
212 | + current_milestone = milestone | |
213 | + current_pid = pid | |
214 | + current_psummary = psummary | |
215 | + if not pid: | |
216 | + current_psummary = u'その他(親チケットなし)' | |
217 | + tickets.append(t) | |
218 | + | |
219 | + ptickets[(current_pid, current_psummary)]=tickets; | |
220 | + mtickets[current_milestone] = ptickets | |
221 | + t = datetime.today() | |
222 | + t = datetime(t.year,t.month,t.day) | |
223 | + start = int(time.mktime(t.timetuple())*1e6) | |
224 | + end = int(time.mktime(t.timetuple())*1e6+24*60*60*1e6) | |
225 | + for ptickets in mtickets.values(): | |
226 | + for tickets in ptickets.values(): | |
227 | + for ticket in tickets: | |
228 | + sql = "SELECT * from ticket_change WHERE ticket='%s' AND field='totalhours' AND time > %s AND time < %s" % (ticket['id'], start, end) | |
229 | + self.log.debug(sql) | |
230 | + cursor.execute(sql) | |
231 | + row = cursor.fetchone() | |
232 | + if row: | |
233 | + ticket['reported'] = True | |
234 | + else: | |
235 | + ticket['reported'] = False | |
236 | + return mtickets | |
151 | 237 | |
152 | 238 | def get_tickets(self, req, cursor): |
153 | 239 | sql = """SELECT t.id ,t.type ,t.owner, t.summary ,t.priority ,t.milestone ,cth.value ,cbil.value , cest.value FROM ticket t |
@@ -172,7 +258,7 @@ | ||
172 | 258 | |
173 | 259 | for ticket in tickets: |
174 | 260 | sql = "SELECT * from ticket_change WHERE ticket='%s' AND field='totalhours' AND time > %s AND time < %s" % (ticket['id'], start, end) |
175 | - self.log.info(sql) | |
261 | + self.log.debug(sql) | |
176 | 262 | cursor.execute(sql) |
177 | 263 | row = cursor.fetchone() |
178 | 264 | if row: |
@@ -1,43 +1,57 @@ | ||
1 | -= シュタインズチャートプラグイン = | |
2 | -このプラグインは、Tracにスクラムのバーンダウンチャート機能を追加します。シュタインズチャートという名前に特に意味はありません。 | |
1 | += 繧キ繝・繧ソ繧、繝ウ繧コ繝√Ε繝シ繝医?繝ゥ繧ー繧、繝ウ = | |
2 | +縺薙?繝励Λ繧ー繧、繝ウ縺ッ縲ゝrac縺ォ繧ケ繧ッ繝ゥ繝?縺ョ繝舌?繝ウ繝?繧ヲ繝ウ繝√Ε繝シ繝域ゥ溯?繧定ソス蜉?縺励∪縺吶?ゅす繝・繧ソ繧、繝ウ繧コ繝√Ε繝シ繝医→縺?≧蜷榊燕縺ォ迚ケ縺ォ諢丞袖縺ッ縺ゅj縺セ縺帙s縲 | |
3 | 3 | |
4 | -プロジェクト全体のバーンダウンチャートと、チーム個別のバーンダウンチャートを表示することができます。 | |
5 | -複数のチームで開発している場合は、全てのチームのバーンダウンチャートを重ねて表示することもできます; | |
4 | +繝励Ο繧ク繧ァ繧ッ繝亥?菴薙?繝舌?繝ウ繝?繧ヲ繝ウ繝√Ε繝シ繝医→縲√メ繝シ繝?蛟句挨縺ョ繝舌?繝ウ繝?繧ヲ繝ウ繝√Ε繝シ繝医r陦ィ遉コ縺吶k縺薙→縺後〒縺阪∪縺吶? | |
5 | +隍?焚縺ョ繝√?繝?縺ァ髢狗匱縺励※縺?k蝣エ蜷医?縲∝?縺ヲ縺ョ繝√?繝?縺ョ繝舌?繝ウ繝?繧ヲ繝ウ繝√Ε繝シ繝医r驥阪?縺ヲ陦ィ遉コ縺吶k縺薙→繧ゅ〒縺阪∪縺呻シ | |
6 | 6 | |
7 | -日本の企業向けにカスタマイズしており、作業時間を入力していくことにより、同時にチームメンバーの稼動時間も管理できるようにしています。うるさいマネージャ対策として、稼動時間の表示は無効にすることもできます。 | |
7 | +譌・譛ャ縺ョ莨∵・ュ蜷代¢縺ォ繧ォ繧ケ繧ソ繝槭う繧コ縺励※縺翫j縲∽ス懈・ュ譎る俣繧貞?蜉帙@縺ヲ縺?¥縺薙→縺ォ繧医j縲∝酔譎ゅ↓繝√?繝?繝。繝ウ繝舌?縺ョ遞シ蜍墓凾髢薙b邂。逅?〒縺阪k繧医≧縺ォ縺励※縺?∪縺吶?ゅ≧繧九&縺??繝阪?繧ク繝」蟇セ遲悶→縺励※縲∫ィシ蜍墓凾髢薙?陦ィ遉コ縺ッ辟。蜉ケ縺ォ縺吶k縺薙→繧ゅ〒縺阪∪縺吶? | |
8 | 8 | |
9 | -== 特徴 == | |
10 | -=== バーンダウンチャートの表示 === | |
11 | -実績のバーンダウンを表示することができます。また、休日を考慮した目標残作業時間も表示します。 | |
9 | +== 迚ケ蠕エ == | |
10 | +=== 繝舌?繝ウ繝?繧ヲ繝ウ繝√Ε繝シ繝医?陦ィ遉コ === | |
11 | +螳溽クセ縺ョ繝舌?繝ウ繝?繧ヲ繝ウ繧定。ィ遉コ縺吶k縺薙→縺後〒縺阪∪縺吶?ゅ∪縺溘?∽シ第律繧定???縺励◆逶ョ讓呎ョ倶ス懈・ュ譎る俣繧り。ィ遉コ縺励∪縺吶? | |
12 | 12 | |
13 | -=== 複数チームに対応 === | |
14 | -コンポーネントにチームを割り当てることで、複数のチームの管理を行うことができます。もちろん、1つのチームでもご利用頂けます。複数のチームのバーンダウンを重ね合わせて全体の進捗を管理する機能も持っています。 | |
13 | +=== 隍?焚繝√?繝?縺ォ蟇セ蠢 === | |
14 | +繧ウ繝ウ繝昴?繝阪Φ繝医↓繝√?繝?繧貞牡繧雁ス薙※繧九%縺ィ縺ァ縲∬、?焚縺ョ繝√?繝?縺ョ邂。逅?r陦後≧縺薙→縺後〒縺阪∪縺吶?ゅb縺。繧阪s縲?縺、縺ョ繝√?繝?縺ァ繧ゅ#蛻ゥ逕ィ鬆ゅ¢縺セ縺吶?り、?焚縺ョ繝√?繝?縺ョ繝舌?繝ウ繝?繧ヲ繝ウ繧帝?縺ュ蜷医o縺帙※蜈ィ菴薙?騾イ謐励r邂。逅?☆繧区ゥ溯?繧よ戟縺」縺ヲ縺?∪縺吶? | |
15 | 15 | |
16 | -=== プロジェクトマネージャ用の分析機能 === | |
17 | -本来スクラムプロセスでは、プロジェクトマネージャは存在しません。しかしながら、多くの日本企業には部長、課長という役職が存在し、残念ながら彼らはスクラムマスターやチームメンバーになり得まず、スクラムから外れた存在になってしまいます。タイムライン分析機能や、稼動時間の集計機能など、彼ら向けの機能を提供することにより日本の現場により導入し易くなります。 | |
16 | +=== 繝励Ο繧ク繧ァ繧ッ繝医?繝阪?繧ク繝」逕ィ縺ョ蛻?梵讖溯? === | |
17 | +譛ャ譚・繧ケ繧ッ繝ゥ繝?繝励Ο繧サ繧ケ縺ァ縺ッ縲√?繝ュ繧ク繧ァ繧ッ繝医?繝阪?繧ク繝」縺ッ蟄伜惠縺励∪縺帙s縲ゅ@縺九@縺ェ縺後i縲∝、壹¥縺ョ譌・譛ャ莨∵・ュ縺ォ縺ッ驛ィ髟キ縲∬ェイ髟キ縺ィ縺?≧蠖ケ閨キ縺悟ュ伜惠縺励?∵ョ句ソオ縺ェ縺後i蠖シ繧峨?繧ケ繧ッ繝ゥ繝?繝槭せ繧ソ繝シ繧?メ繝シ繝?繝。繝ウ繝舌?縺ォ縺ェ繧雁セ励∪縺壹?√せ繧ッ繝ゥ繝?縺九i螟悶l縺溷ュ伜惠縺ォ縺ェ縺」縺ヲ縺励∪縺?∪縺吶?ゅち繧、繝?繝ゥ繧、繝ウ蛻?梵讖溯?繧??∫ィシ蜍墓凾髢薙?髮?ィ域ゥ溯?縺ェ縺ゥ縲∝スシ繧牙髄縺代?讖溯?繧呈署萓帙☆繧九%縺ィ縺ォ繧医j譌・譛ャ縺ョ迴セ蝣エ縺ォ繧医j蟆主?縺玲?縺上↑繧翫∪縺吶? | |
18 | 18 | |
19 | -== バーンダウンチャートの実績からタイムラインを参照可能 == | |
20 | -ある日のバーンダウンが急激に上昇した場合、プロジェクトで何らかの問題が発生したことが予想されます。Steins;Chartでは、バーンダウンチャート上にプロットされた点をクリックすることにより、その日のタイムラインを表示することができ、問題を確認することができます。 | |
19 | +== 繝舌?繝ウ繝?繧ヲ繝ウ繝√Ε繝シ繝医?螳溽クセ縺九i繧ソ繧、繝?繝ゥ繧、繝ウ繧貞盾辣ァ蜿ッ閭ス == | |
20 | +縺ゅk譌・縺ョ繝舌?繝ウ繝?繧ヲ繝ウ縺梧?・豼?縺ォ荳頑?縺励◆蝣エ蜷医?√?繝ュ繧ク繧ァ繧ッ繝医〒菴輔i縺九?蝠城。後′逋コ逕溘@縺溘%縺ィ縺御コ域Φ縺輔l縺セ縺吶?4teins;Chart縺ァ縺ッ縲√ヰ繝シ繝ウ繝?繧ヲ繝ウ繝√Ε繝シ繝井ク翫↓繝励Ο繝?ヨ縺輔l縺溽せ繧偵け繝ェ繝?け縺吶k縺薙→縺ォ繧医j縲√◎縺ョ譌・縺ョ繧ソ繧、繝?繝ゥ繧、繝ウ繧定。ィ遉コ縺吶k縺薙→縺後〒縺阪?∝撫鬘後r遒コ隱阪☆繧九%縺ィ縺後〒縺阪∪縺吶? | |
21 | 21 | |
22 | -== 稼働時間の集計が可能 == | |
23 | -チームメンバがタスクの稼動時間を入力していくことにより、チームメンバの稼動時間を集計することができます。また、稼動時間の入力に負荷を掛けないように、1画面でその日の稼動時間を入力できる一括入力ビューを提供しています。 | |
22 | +== 遞シ蜒肴凾髢薙?髮?ィ医′蜿ッ閭ス == | |
23 | +繝√?繝?繝。繝ウ繝舌′繧ソ繧ケ繧ッ縺ョ遞シ蜍墓凾髢薙r蜈・蜉帙@縺ヲ縺?¥縺薙→縺ォ繧医j縲√メ繝シ繝?繝。繝ウ繝舌?遞シ蜍墓凾髢薙r髮?ィ医☆繧九%縺ィ縺後〒縺阪∪縺吶?ゅ∪縺溘?∫ィシ蜍墓凾髢薙?蜈・蜉帙↓雋?闕キ繧呈寺縺代↑縺?h縺?↓縲?逕サ髱「縺ァ縺昴?譌・縺ョ遞シ蜍墓凾髢薙r蜈・蜉帙〒縺阪k荳?諡ャ蜈・蜉帙ン繝・繝シ繧呈署萓帙@縺ヲ縺?∪縺吶? | |
24 | 24 | |
25 | -== ScrumBurndownプラグイン互換 == | |
26 | -既にTracでスクラムのバーンダウンチャートを利用するためのプラグインとしてScrumBurndownPluginが提供されています。Steins;Chartプラグインは既にScrumBurndownPluginを利用している場合、置き換えて利用することができます(Steins;Chartプラグインを利用する場合、ScrumBurndownPluginは必ず無効にしてください) | |
25 | +== ScrumBurndown繝励Λ繧ー繧、繝ウ莠呈鋤 == | |
26 | +譌「縺ォTrac縺ァ繧ケ繧ッ繝ゥ繝?縺ョ繝舌?繝ウ繝?繧ヲ繝ウ繝√Ε繝シ繝医r蛻ゥ逕ィ縺吶k縺溘a縺ョ繝励Λ繧ー繧、繝ウ縺ィ縺励※ScrumBurndownPlugin縺梧署萓帙&繧後※縺?∪縺吶?4teins;Chart繝励Λ繧ー繧、繝ウ縺ッ譌「縺ォScrumBurndownPlugin繧貞茜逕ィ縺励※縺?k蝣エ蜷医?∫スョ縺肴鋤縺医※蛻ゥ逕ィ縺吶k縺薙→縺後〒縺阪∪縺?Steins;Chart繝励Λ繧ー繧、繝ウ繧貞茜逕ィ縺吶k蝣エ蜷医?ヾcrumBurndownPlugin縺ッ蠢?★辟。蜉ケ縺ォ縺励※縺上□縺輔>) | |
27 | 27 | |
28 | -== 前提条件 == | |
29 | -timingandestimateプラグインを利用することを前提としています。 | |
30 | -また、subticketsプラグインを利用するとプロダクトバックログとスプリントバックログの紐付けができて便利です。必須ではありませんが、subticketsプラグインの利用を推奨します。 | |
28 | +== 蜑肴署譚。莉カ == | |
29 | +timingandestimate繝励Λ繧ー繧、繝ウ繧貞茜逕ィ縺吶k縺薙→繧貞燕謠舌→縺励※縺?∪縺吶? | |
30 | +縺セ縺溘?《ubtickets繝励Λ繧ー繧、繝ウ繧貞茜逕ィ縺吶k縺ィ繝励Ο繝?繧ッ繝医ヰ繝?け繝ュ繧ー縺ィ繧ケ繝励Μ繝ウ繝医ヰ繝?け繝ュ繧ー縺ョ邏蝉サ倥¢縺後〒縺阪※萓ソ蛻ゥ縺ァ縺吶?ょソ??医〒縺ッ縺ゅj縺セ縺帙s縺後?《ubtickets繝励Λ繧ー繧、繝ウ縺ョ蛻ゥ逕ィ繧呈耳螂ィ縺励∪縺吶? | |
31 | 31 | |
32 | -バーンダウンの表示は、billable(集計に含める?)フィールドにチェックが入っているチケットが対象です。必ずチェックを入れてください。 | |
32 | +繝舌?繝ウ繝?繧ヲ繝ウ縺ョ陦ィ遉コ縺ッ縲|illable(髮?ィ医↓蜷ォ繧√k?)繝輔ぅ繝シ繝ォ繝峨↓繝√ぉ繝?け縺悟?縺」縺ヲ縺?k繝√こ繝?ヨ縺悟ッセ雎。縺ァ縺吶?ょソ?★繝√ぉ繝?け繧貞?繧後※縺上□縺輔>縲 | |
33 | 33 | |
34 | -== インストール == | |
34 | +== 繧、繝ウ繧ケ繝医?繝ォ == | |
35 | 35 | {{{ |
36 | 36 | > svn co http://****/ |
37 | 37 | > python setup.py install |
38 | 38 | }}} |
39 | 39 | |
40 | +== 險ュ螳 == | |
41 | +=== 隕ェ繝√こ繝?ヨ縺ョ陦ィ遉コ == | |
42 | +繧キ繝・繧ソ繧、繝ウ繧コ繝サ繝√Ε繝シ繝医?縲∽ス懈・ュ蜈・蜉帛?蜉帷判髱「縺ョ繝√こ繝?ヨ陦ィ遉コ縺ァ隕ェ繝√こ繝?ヨ繧定。ィ遉コ縺吶k縺薙→縺後〒縺阪∪縺吶?ゅ%縺ョ讖溯?縺ッ繧ケ繧ッ繝ゥ繝?縺ァ繧ケ繝医?繝ェ縺ィ繧ソ繧ケ繧ッ繧呈律繧ゆサ倥¢縺ヲ陦ィ遉コ縺励◆縺?→縺堺セソ蛻ゥ縺ァ縺吶? | |
43 | +隕ェ繧ソ繧ケ繧ッ繧定。ィ遉コ縺吶k縺ォ縺ッ縲》rac.ini繝輔ぃ繧、繝ォ縺ァ谺。縺ョ繧医≧縺ォ險ュ螳壹@縺ヲ縺上□縺輔>縲 | |
40 | 44 | |
45 | +[steinschart] | |
46 | +show_parent_ticket=true | |
41 | 47 | |
42 | 48 | |
49 | +=== 菴懈・ュ譎る俣縺ョ陦ィ遉コ === | |
50 | +繧キ繝・繧ソ繧、繝ウ繧コ繝√Ε繝シ繝医〒縺ッ縲√ヰ繝シ繝ウ繝?繧ヲ繝ウ繝√Ε繝シ繝医?逕サ髱「縺ァ蜷?メ繝シ繝?繝。繝ウ繝舌?菴懈・ュ譎る俣繧定。ィ遉コ縺吶k縺薙→縺後〒縺阪∪縺吶? | |
51 | +荳?闊ャ逧?↓繧「繧ク繝」繧、繝ォ髢狗匱縺ァ縺ッ蜷?メ繝シ繝?繝。繝ウ繝舌?菴懈・ュ譎る俣繧帝寔險医☆繧九%縺ィ縺ッ螂ス縺セ繧後∪縺帙s縺後?√◎縺ョ繧医≧縺ェ繝九?繧コ繧ゅ≠繧九→閠?∴縲√%縺ョ讖溯?繧呈戟縺」縺ヲ縺?∪縺吶?ゅョ繝輔か繝ォ繝医〒縺ッ辟。蜉ケ縺ォ縺ェ縺」縺ヲ縺?∪縺吶′縲∵ャ。縺ョ繧医≧縺ォtrac.ini縺ォ險ュ螳壹☆繧九%縺ィ縺ォ繧医j譛牙柑縺ォ縺吶k縺薙→縺後〒縺阪∪縺吶? | |
43 | 52 | |
53 | +[steinschart] | |
54 | +draw_worktime=true | |
55 | + | |
56 | + | |
57 | + |