[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]
『開始時刻と終了時刻を表示させたい』(いろは)
いつもお世話になっております。 作業に行き詰ってしまいましたので、ご教授願いたいです。
A B C D E F EU 1 開始時刻 終了時刻 08:00 08:10 08:20 08:30・・・07:50 2 08:00 08:21 1 1 3 08:30 08:30 1 . . . 8000 上記のようにデータがあります。 開始時刻と、終了時刻に該当すればセルに"1"という数字を表示させたいです。 時刻の分け方としては、00分〜09分、10分〜19分という区切りにしたいです。
表示の例として、2行目で開始時間が"08:00"なので"C2"に"1"を表示させて、 終了時刻が"08:21"なので"E2"に"1"を表示させたいです。
IF関数で何とか考えたのですが、1時間ごとにしか設定できませんでした。 開始時刻は表示させられても、終了時刻を入れる事ができませんでした。
*A列は8000行あります。 *A列の開始時刻と、終了時刻は初めから入っています。 *マクロの知識は少しだけあります。
難しいのは重々承知しておりますが、ご教授願えませんでしょうか? よろしくお願いいたします。
OS:WindowsXP Excel:2003
C2=IF(OR(C$1=FLOOR($A2,"0:10"),C$1=FLOOR($B2,"0:10")),1,"") と入力して、必要分右と下にフィルコピーしてみてください。
(ROUGE)
前スレと同じことを訊ねますけど 1行目は手入力ですか、数式ですか、オートフィルですか?
8000行もあるんならA列はまさかの手入力じゃないでしょう。 どうやって作ったんですか?
それと「1」を立てて、そのあと何をするんですか? 最終的な目的は何なのでしょうか?
(よみびとしらず)
ROUGEさん
素早い回答ありがとうございます。 08:00から11:00まで10分間間隔で時刻を並べて数式を入れて見ましたが、 08:50と10:00・20・30、50が表示されませんでした。
よみびとしらずさん
>前スレと同じことを訊ねますけど >1行目は手入力ですか、数式ですか、オートフィルですか?
1行目はC1・08:00と、D1・08:10は手入力して後は横へコピーして10分間隔で表示してあります。
>8000行もあるんならA列はまさかの手入力じゃないでしょう。 >どうやって作ったんですか?
A列手入力ではありません。 上司からデータのみをもらってるのでどのように出力されいるのかは不明です。 すみません。
>それと「1」を立てて、そのあと何をするんですか? >最終的な目的は何なのでしょうか?
最終目的では、条件付書式を使用して、"1"が入っているところに色をつけたいと思います。 なので、最終的に関数は消えてしまい、値コピーで"1"のみ残す予定です。 開始時刻と終了時刻を一覧として、可視化させるのが最終目的です。
(いろは)
演算誤差があるのかな?
C2=IF(OR(FLOOR(C$1,"0:10")=FLOOR($A2,"0:10"),FLOOR(C$1,"0:10")=FLOOR($B2,"0:10")),1,"")
としたらどうなりますか?
(ROUGE)
関連スレ張っときます。(とおりすがり) [[20100226110407]]
> C2=IF(OR(FLOOR(C$1,"0:10")=FLOOR($A2,"0:10"),FLOOR(C$1,"0:10")=FLOOR($B2,"0:10")),1,"")
↑でも、例えば 16:30 で誤差が出ませんか? 横に150列、縦に8000行もあるような表でしょう。 それの各行2つだけ色がついているところを眺めて 何の役に立つのだろうかと局外者は首をかしげてしまうのでありますが。
ピボットテーブルで時間帯別の集計をした方が いいんじゃないですか?
(よみびとしらず)
ロジックはともかく、8000行あるとめちゃくちゃ重いですよ。
2007形式で7MB 互換性保存で39MBでした。
最終データのみしか必要ないならマクロで処理しちゃったほうが私はいいと思うのですが…
(通りすがり)
時間の計算は面倒なので [A] [B] [C] [D] [E] [F] [G] [H] [1] T 480 490 500 510 ←★ [2] S1 E1 開始時刻 終了時刻 8:00 8:10 8:20 8:30 [3] 480 501 8:00 8:21 1 1 [4] 510 510 8:30 8:30 1 ↑★ ↑★ ★の様なセルを作って、一旦分単位に直した後で 時間の比較をする事にすると、何とかなるかもしれません。
24時以降の時間帯がそれぞれどの様に成っているのか分かりませんが。。。 A3セルは =ROUND(C3*24*60,0) E3セルは =IF(OR(AND(E$1<=$A3,$A3<F$1),AND(E$1<=$B3,$B3<F$1)),1,"")
と言う式を入れてみました。
EU列(最後の列)の一つ隣り(EV列)に、最後の時間の次の区分の時間まで 入力が必要です。
(HANA)
HANAさんと衝突!
すべてを検証することなく数式をアップしていました。。。
C2=OR(INT(ROUND(C$1*24*60,0)/10)=INT(ROUND($A2*24*60,0)/10),INT(ROUND(C$1*24*60,0)/10)=INT(ROUND($B2*24*60,0)/10)),1,"")
ならどうでしょうか。
もっとも、よみびとしらずさん、通りすがりさんの仰るとおり、処理自体に必要性が感じられませんし、 必要だとしてもマクロが適切なのかもしれませんね。
(ROUGE)
そう言えば、A,Bの段階で1行目と同じにしておけば良いですよね。。。 (EV列に時間の入力も不要に成りますし。) A3に =ROUNDDOWN(ROUND(C3*24*60,0),-1) そしたら、E3セルの式が =IF(OR($A3=E$1,$B3=E$1),1,"")
時間のばらつきが無い と言うのが前提で そのばらつきを見たいと思ったら 色が付いていると見た目に分かりやすいと思いますけどね。。。
(HANA)
よみびとしらずさん >何の役に立つのだろうかと 「このJOBは何時から何時まで動いているのか〜」というのがひと目で知りたいようです。
>ピボットテーブルで時間帯別の集計をした方が >いいんじゃないですか?
何時から何時までということなので、ピボットでは作成できないのです。
通りすがりさん >最終データのみしか必要ないならマクロで処理しちゃったほうが私はいいと思うのですが…
マクロが一番だとは思うのですが、私の力では作成できませんでした。。。
(いろは)
なんでピボットじゃあかんのですか? 作業列作って、単純にFLOORで丸めてあげて、行ラベルに丸めた作業列入れてあげれば個数でますよ?
(通りすがり)
通りすがりさん
個数を求めたいわけではないのです。 "1"を入れるというのは、条件つき書式のためで、"1"でなくても何か入ればいいんです。
(いろは)
なんとなく、欲しい最終形態はガンチャートなのかな?とか。 以下参考。私には高度過ぎて応用が利く範囲なのかも不明ですが。(こまごま)
『工程表の進捗線をオートシェイプの矢印で表示させたい。。』(きらり)
回答でもなく、とっても細かいことで申し訳ないですけど
>なんとなく、欲しい最終形態はガンチャートなのかな?とか。 ガントチャートでは? (てつろう)
>てつろうさん 本当ですね。今の今までgoogle先生の好意で気付いていませんでした。 (こまごま)
こまごまさん
ありがとうございます。 まさにこのようなものを作成したかったです。
これを加工してみたいと思います。 長くなってしまいすみません。
なんだか丸くおさまってるけど、どうしても誤差が取れない…
Sub test() Dim tbl Set hani = Range("a1:ep1000") Range("c2:ep8000").ClearContents tbl = hani.Value For i = 3 To UBound(tbl, 2) For ii = 2 To UBound(tbl, 1) If Int(WorksheetFunction.Floor(tbl(1, i) * 60 * 24, 10)) = _ Int(WorksheetFunction.Floor(tbl(ii, 1) * 60 * 24, 10)) _ Or Int(WorksheetFunction.Floor(tbl(1, i) * 60 * 24, 10)) = _ Int(WorksheetFunction.Floor(tbl(ii, 2) * 60 * 24, 10)) Then tbl(ii, i) = 1 End If Next Next hani.Value = tbl End Sub
どうすればいいんだーTwT (通りすがり)
Sub TEST2()
Dim i As Integer
Range("C2:EP8000").ClearContents For i = 2 To Range("A" & Rows.Count).End(xlUp).Row Cells(i, Int((Cells(i, 1).Value - TimeValue("8:0:0")) / TimeValue("0:10:0")) + 3).Interior.ColorIndex = 3 Cells(i, Int((Cells(i, 2).Value - TimeValue("8:0:0")) / TimeValue("0:10:0")) + 3).Interior.ColorIndex = 3 Next i End Sub
面白そうなのでちょっとやってみました。
・誤差を無くすのにHour関数とMinute関数で処理してみました。 シリアル値の誤差で悩むのでしたらどうでしょうか?
・keiさんと同じく、いきなり塗りつぶしています。
・日付跨ぎ(?)というか8時跨ぎにも対応してみました。
どうですかね?
Sub test() Dim tbl As Variant, i As Long, myCol(1 To 2) As Long With Range("A1").CurrentRegion .Interior.ColorIndex = xlNone tbl = .Columns("A:B").Value End With For i = 2 To UBound(tbl) If tbl(i, 1) <> "" And tbl(i, 2) <> "" Then myCol(1) = TimeToColumn(tbl(i, 1)) myCol(2) = TimeToColumn(tbl(i, 2)) If myCol(1) > myCol(2) Then Range(Cells(i, myCol(1)), Range("EP" & i)).Interior.ColorIndex = 3 Range(Range("C" & i), Cells(i, myCol(2))).Interior.ColorIndex = 3 Else Range(Cells(i, myCol(1)), Cells(i, myCol(2))).Interior.ColorIndex = 3 End If End If Next i End Sub
Function TimeToColumn(ByVal myTime As Date) As Long Dim myHour As Long, myMinute As Long myHour = Hour(myTime) myMinute = Minute(myTime) \ 10 TimeToColumn = (myHour - 8 + IIf(myHour < 8, 24, 0)) * 6 + myMinute + 3 End Function
(momo)
おふたりのコードちゃんと誤差がなおってましたー
6時半から飲まされっぱなしで頭ガンガンするので明日じっくりみさせてください
うううぅぅx (通りすがり)
面白そうなんで寄せてくらはい。 8:00跨ぎは○で示しております。 また、C列からEP列をオートフィットさせておきますと、ええ塩梅に→三個が収まり ます。 (弥太郎) '------------------ Sub iroha() Dim i As Long, n As Integer, u As Integer, s_data, e_data, tbl, tbl1 tbl = Range("a1").Resize(Range("a" & Rows.Count).End(xlUp).Row, 146) ReDim tbl1(3 To UBound(tbl, 2)) For n = 3 To UBound(tbl, 2) tbl1(n) = Left(Format(tbl(1, n), "hh:mm"), 4) Next n For i = 2 To UBound(tbl, 1) s_data = Application.Match(Left(Format(tbl(i, 1), "hh:mm"), 4), tbl1, 0) + 2 e_data = Application.Match(Left(Format(tbl(i, 2), "hh:mm"), 4), tbl1, 0) + 2 If s_data <= e_data Then For n = s_data To e_data tbl(i, n) = "→→→" Next n Else For u = s_data To 146 tbl(i, u) = IIf(u = 146, "→→○", "→→→") Next For u = 3 To e_data tbl(i, u) = IIf(u = 3, "○→→", "→→→") Next u End If Next i Range("c2:ep" & UBound(tbl, 1)).ClearContents Range("a1").Resize(UBound(tbl, 1), UBound(tbl, 2)) = tbl End Sub
小数演算誤差の問題ですね
参考までに
C2=IF(OR(LOOKUP(TEXT($A2,"hmm"),TEXT($C$1:$EUI$1,"hmm"))=TEXT(C$1,"hmm"),LOOKUP(TEXT($B2,"hmm"),TEXT($C$1:$EU$1,"hmm"))=TEXT(C$1,"hmm")),1,"")
keiさん なぜか8:10-8:10が塗りつぶされてないんですよね…。 いまいちロジックが理解できなくてこれ以上私言えないんですが…
momoさん 他人のスレですが、やっぱり気になったので聞いちゃいました。 これFunctionで処理してるのは、引数をDate型で受け取るための工夫ですか?
>TimeToColumn = (myHour - 8 + IIf(myHour < 8, 24, 0)) * 6 + myMinute + 3 この部分なんですが ~~~ ~~~~~~~~~~~~~~~~~~ ~~~ ~~~ それぞれ何の為の計算なのかわからないのです。。。 出来たら教えていただけたらと思います。
弥太郎さん うわー弥太郎さんやっぱり発想が飛びぬけてますね…。 そうですよね、10分単位の切り捨てなんだから、丸めずに文字列で左から4つ取り出せば誤差なんて ないですもんね…。 >s_data = Application.Match(Left(Format(tbl(i, 1), "hh:mm"), 4), tbl1, 0) + 2 この部分なんですが ~~~~ ~~~ 検索範囲を配列にした場合、tbl1は3〜始まってても、最初にHitすると1 3番目なら3を返すのですか? だから+2で直してるって解釈であってますかね。。。?
勉強不足でお恥ずかしい限りですが、よろしければ教えてください。 (通りすがり)
>だから+2で直してるって解釈であってますかね。。。? 仰るとおりです。 ここらへんは如何様にもアジャストできますからねぇ。 また、hhmm 3でマッチさせてもええですわなぁ。
ついでにこっちの方が見やすいかナ? (弥太郎) '--------------------- Sub iroha2() Dim i As Long, n As Integer, u As Integer, s_data, e_data, tbl, tbl1 Range("c2:ep" & Range("a" & Rows.Count).End(xlUp).Row).ClearContents tbl = Range("a1").Resize(Range("a" & Rows.Count).End(xlUp).Row, 146) ReDim tbl1(3 To UBound(tbl, 2)) For n = 3 To UBound(tbl, 2) tbl1(n) = Left(Format(tbl(1, n), "hhmm"), 3) Next n For i = 2 To UBound(tbl, 1) s_data = Application.Match(Left(Format(tbl(i, 1), "hhmm"), 3), tbl1, 0) + 2 e_data = Application.Match(Left(Format(tbl(i, 2), "hhmm"), 3), tbl1, 0) + 2 If s_data <= e_data Then For n = s_data To e_data tbl(i, n) = IIf(s_data = e_data, " |→|", IIf(n = s_data, " |→→", IIf(n = e_data, "→→|", "→→→"))) Next n Else For u = s_data To 146 tbl(i, u) = IIf(u = 146, "→→○", IIf(u = s_data, " |→→", "→→→")) Next For u = 3 To e_data tbl(i, u) = IIf(u = 3, "○→→", IIf(u = e_data, "→→|", "→→→")) Next u End If Next i Range("a1").Resize(UBound(tbl, 1), UBound(tbl, 2)) = tbl End Sub
あ、ミスショット! フォアーーー!! っちゅうことで↑のコード訂正 (汗 (弥太郎)
コードまで書いて頂きありがとうございます! 早速いただいたコードをモジュールに入れて実行したのですが、 エラーが出てしまいました。。
実行したものは、弥太郎さんの"Sub iroha2()"です。
s_data = Application.Match(Left(Format(tbl(i, 1), "hhmm"), 3), tbl1, 0) + 2
のところで、"tbl(i, 1)"が"エラー=2042"と出ています。 マクロ初心者のためこのエラーの対応方法が分かりません。 教えていただけませんでしょうか?
(いろは)
データ範囲内にデータがないんじゃないですかね? EP列までびっしり詰まってますか? もしくは、空白がまぎれていたりエラー値があったりしませんか?? (通りすがり)
通りすがりはん、フォローおおきに〜。 えと、マクロが止まったその黄色のtbl(i,1)にそっとマウスを近づけてみてくらはい。 何と表示されます? (弥太郎)
通りすがりさん 空白がまぎれてました。。
空白行を削除して実行したら見事に出来上がり、感動いたしました。 弥太郎さん本当にありがとうございました!
後は、ほかのメンバーも使用できるように別シートにボタンを作って ボタンを押せば誰でもできるように加工してみます!
ご指導いただき、ありがとうございました。
(いろは)
>momoさん >他人のスレですが、やっぱり気になったので聞いちゃいました。 >これFunctionで処理してるのは、引数をDate型で受け取るための工夫ですか? > >>TimeToColumn = (myHour - 8 + IIf(myHour < 8, 24, 0)) * 6 + myMinute + 3 >この部分なんですが ~~~ ~~~~~~~~~~~~~~~~~~ ~~~ ~~~ >それぞれ何の為の計算なのかわからないのです。。。 >出来たら教えていただけたらと思います。
返事が遅くなりました。
Functionで処理しているのは、単に開始時間と終了時間で同じ処理をするので Functionにしてコードを簡素化しているだけです。
>TimeToColumn = (myHour - 8 + IIf(myHour < 8, 24, 0)) * 6 + myMinute + 3 は、分解して考えてみましょう
myHour - 8 の部分は1行目が8:00からなので先頭列から何列目かを出すのに8を引いています。
IIf(myHour < 8, 24, 0)) はmyHourが8時未満の場合は終わりの列の方になるので 24時間分足します(すると24時以降の列となります)8時以上の場合は0を足す(つまり何もしない)
* 6 は1時間で6列使うので1時間増えるごとに6列右にするために時間×6とします。
myMinute + 3 最後に10分単位で右にずらすためにmyMinute(10分単位の十の位の数値)を足して さらにC列から始まるので3列分を足します。
するとTimeToColumnの値はその時間の該当する列番号を返します。
という感じで御理解いただけるでしょうか? (momo)
momoさん 丁寧なご説明ありがとうございました。 8はきっと8時のことなんだろうけど、なんで引くのかなぁと説明されるまでずっとわかりませんでした *6も12時間の半分のこと…?とか、+3は30分…?とか悩んでいたことがすっかり解消できました。
ありがとうございます。
ちょっと便利そうなので、弥太郎さんのコードまるまるお借りして自社向けに作り直しました。
人に見せられるようなものではないですが、変更して使っているのに報告しないのは 気が咎めましたので報告までに… [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [1] No 工程 名前 開始時間 終了時間 6:30 6:40 6:50 7:00 7:10 [2] 1 配達 斎藤 6:00 8:30 [3] 2 配達 鈴木 9:00 9:30 [4] 3 配達 田中 9:30 9:30 [5] 4 配達 佐藤 9:30 10:00 [6] 5 配達 伊藤 10:10 10:20 [7] 6 配達 長嶋 10:20 13:47 [8] 7 配達 小林 13:50 14:35 [9] 8 配達 中村 14:40 15:22 [10] 9 配達 渋谷 15:30 16:40 [11] 10 配達 大野 8:00 9:00 [12] 11 フロア 新堀 9:00 9:30 [13] 12 フロア 澤田 9:30 9:30 [14] 13 フロア 松本 9:30 10:00 [15] 14 フロア 山崎 10:10 10:20 [16] 15 フロア 島崎 10:20 13:47 [17] 16 フロア 長沢 13:50 14:35 [18] 17 フロア 今井 14:40 15:22 [19] 18 フロア 青木 15:30 16:40 [20] 19 フロア 益山 10:20 13:47 [21] 20 フロア 飯島 13:50 14:35
Sub 弥太郎さんから借りました() Dim WS1 As Worksheet, WS2 As Worksheet, WS3 As Worksheet
'=====ユーザー設定 ここから===== Const Col_Cri As Integer = 1 '-------------------------------------------列項目の行数 Const Row_Cri1 As Integer = 4 '------------------------------------------行項目開始時間の列数 Const Row_Cri2 As Integer = 5 '------------------------------------------行項目終了時間の列数 Const One_Sec As String = "[→]" '---------------------------------------1区間のみの表示 Const Sta_Sec As String = "├" '-----------------------------------------区間開始の表示 Const End_Sec As String = "┤" '-----------------------------------------区間終了の表示 Const Con_Sec As String = "─" '-----------------------------------------連続区間の表示 Const EtS_Sec As String = "⇒" '-----------------------------------------前日跨ぎ区間の表示 Const StE_Sec As String = "⇒" '-----------------------------------------翌日跨ぎ区間の表示 Const Row_Ind As Long = 3 '----------------------------------------------集計項目行番号 Set WS1 = Worksheets("sheet1") Set WS2 = Worksheets("sheet2") '=====ユーザー設定 ここまで===== Dim i As Long, n As Integer, u As Integer '------------------------------繰り返し処理の為の変数 Dim tbl '----------------------------------------------------------------全体の配列変数 Dim tbl1 '---------------------------------------------------------------開始時間終了時間の配列変数 Dim MyRng As Range, End_Col As Long, End_Row As Long '-------------------繰り返し処理の為の変数 Dim Sta_Tim As String, End_Tim As String '-------------------------------使い捨て変数 Dim Sta_Dat As Long, End_Dat As Long '-----------------------------------使い捨て変数 Dim Result Dim r As Long, c As Long, m As Long
End_Row = Cells(Rows.Count, Row_Cri1).End(xlUp).Row '--------------------変数End_Rowに最終行番号取得 End_Col = Cells(Col_Cri, Columns.Count).End(xlToLeft).Column '-----------変数End_Colに最終列番号取得 Set MyRng = Range(Cells(Col_Cri, Row_Cri1), Cells(End_Row, End_Col)) '---変数MeRngに範囲の取得 MyRng.Offset(1, 2).Resize(, End_Col - (2 + (Row_Cri1 - 1))).ClearContents '出力範囲のクリア tbl = MyRng '------------------------------------------------------------Rangeとしてテーブル取得 ReDim tbl1(Row_Cri1 To UBound(tbl, 2)) '---------------------------------配列tbl1の要素数を変更
For n = Row_Cri2 + 1 To UBound(tbl, 2) '---------------------------------配列tbl1に列項目のhhmmの頭3文字をhhmを格納 tbl1(n) = Left(Format(tbl(1, n), "hhmm"), 3) Next n
For i = Col_Cri + 1 To UBound(tbl, 1) Sta_Tim = Left(Format(tbl(i, 1), "hhmm"), 3) '-----------------------変数Sta_Timに開始時間を文字列のhmmの3文字として格納 End_Tim = Left(Format(tbl(i, 2), "hhmm"), 3) '-----------------------変数End_Timに終了時間を文字列のhmmの3文字として格納 Sta_Dat = Application.Match(Sta_Tim, tbl1, 0) + Row_Cri1 - 1 '-------開始時間の行項目が列項目にあった場合、行番号を返す End_Dat = Application.Match(End_Tim, tbl1, 0) + Row_Cri1 - 1 '-------終了時間の表項目が列項目にあった場合、行番号を返す If Sta_Dat <= End_Dat Then '-----------------------------------------開始時間が終了時間以下の場合 For n = Sta_Dat To End_Dat tbl(i, n) = IIf(Sta_Dat = End_Dat, One_Sec, IIf(n = Sta_Dat, Sta_Sec, IIf(n = End_Dat, End_Sec, Con_Sec))) ' 開始と終了が同じなら、1区間 nと開始が同じなら区間開始 nと終了が同じなら区間終了、そうじゃなければ連続区間 Next n Else For u = Sta_Dat To End_Col - (Row_Cri1 - 1) tbl(i, u) = IIf(u = End_Col - (Row_Cri1 - 1), EtS_Sec, IIf(u = Sta_Dat, Sta_Sec, Con_Sec)) ' uが最後のセルと同じなら前日跨ぎ uが開始と同じなら翌日跨ぎ そうじゃないければ連続区間 Next For u = Row_Cri1 - 1 To End_Dat tbl(i, u) = IIf(u = Row_Cri1 - 1, StE_Sec, IIf(u = End_Dat, End_Sec, Con_Sec)) ' uが終了と同じなら区間終了 そうじゃなければ連続区間 Next u End If Next i MyRng = tbl 'おまけ If MsgBox(WS2.Name & "に時間別作業者一覧を出力しますか?", vbYesNo) = vbNo Then Exit Sub End If tbl = MyRng.Offset(, -(Row_Cri1 - 1)).Resize(, End_Col + Row_Cri1 - 1) ReDim Result(1 To UBound(tbl, 2), 1 To UBound(tbl, 2)) WS2.Cells.ClearContents For c = Row_Cri2 + 1 To UBound(tbl, 2) m = 2 For r = Col_Cri + 1 To UBound(tbl, 1) If Result(1, c - Row_Cri2) = Empty Then Result(1, c - Row_Cri2) = tbl(Col_Cri, c) If tbl(r, c) <> Empty Then Result(m, c - Row_Cri2) = tbl(r, Row_Ind): m = m + 1 Next Next WS2.Cells(1, 1).Resize(UBound(Result, 2), UBound(Result, 1)).Value = WorksheetFunction.Transpose(Result) End Sub
(通りすがり)
[ 一覧(最新更新順) ]
YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki.
Modified by kazu.