トルコ旅行記 1日目
トルコ旅行の初日。成田空港までは高速バスで移動。出発がお昼なので、それほど早起きが必要なくて気楽な出発でした。
飛行機は、トルコ航空の直行便で行きは約12時間のフライトです。自分としては今までで最長のフライト時間でしたが、国内便とは違って席が多少大きく余裕があったので、それほど疲れずに済みました。飛行機の中では、途中眠りつつ Inception、Cars、The Day After Tomorrow の映画を視聴。日本語吹き替え版なので安心のクオリティでした。
Inceptionは、設定は面白いんだけど内容は「う〜ん」と言った微妙な感じ。ハリウッドならではの映像は凄かった。街が逆さになるところとか。Carsは嫁さんの勧めで見たけど、いいお話だった。The Day After Tomorrow も映像は凄かったけど、話し的にはいつものハリウッド映画って感想。
飛行機の中の食事は、もちろんトルコ料理。メインやサラダはオリーブオイルが多めだけれど美味しい。パンも美味しかったのだけど、デザートが甘すぎる。ちょっと口を付けただけでギブアップしてしまい、ちょっと申し訳ない気分に。それにしても、この甘さが序章に過ぎないことに気づくのはそんなに時間はかからなかった。。。
さて、イスタンブールに到着し 12時出発の便で12時間フライトしたのに何故か 18時*1に到着し、入国審査の長蛇の列で待ち、そのままホテルへ。ホテルはイスタンブール郊外の新しめのところで、いい所でした。ここまでは、ツアーなのでガイドさんはもちろん日本語だし、ホテルでも日本語もしくは英語で済むので、トルコ語とはあまり接する機会はなし。
そんな訳で2日目へ続く。
*1:まあ、日本との時差が6時間あるだけなんですが
トルコ旅行記 総感
転職することになったため、長めの休みが取れたのでトルコへ旅行に行ってきました。
色々な場所に行き、トルコを堪能してきたので1日づつEntryを分けて書いていこうと思います。
今日のEntryは全体の感想を。
ツアー旅行*1だったのですが、ツアーとして立ち寄るところは結構日本語が通じてびっくりしました。「こんにちは」「ありがとう」などの挨拶や、値段も「いち」「に」など日本語で話してくれるところが多くて買い物もスムーズでした。日本語が通じない場合でも、英語はなんとか通じる感じでした。しかし、街歩きをしていてその辺のお店に寄ったら、英語も日本語もほとんど通じなくて、これが普通なんだろうな、と*2安心?しました。
それにしても、トルコの人達は基本的に陽気な人が多くて、日本人にはさらに親切なのでいいところでした。たまに嫁さんが一緒に写真を撮って欲しいと頼まれていたりしていました。
また、ぷよぷよ7 れんしゅうノート シミュレータ のバグフィックス バージョン0.4.4に更新
http://d.hatena.ne.jp/Horiuchi_H/20110611/1307794890#c にて、またバグ報告を頂いたので修正しました。今回は、ぷよの繋がりを調べる処理にバグがあり、繋がっているはずなのに消えないことがあるというものでした。例えば、 あゆけいああけあこあう のパスワードで表示されるような形でぷよが残ってしまっていました。
まおべりるさん、今回も報告ありがとうございました。
さて、ぷよぷよ!! 20th anniversaryが発売されましたね。私も発売日に買って楽しんでます。
今回のれんしゅうノートはぷよぷよSUNに対応したので、いくつか変更点がありました。まず、大きいのが太陽ぷよが置けるようになったので、パスワードで太陽ぷよの対応が必要です。当然ぷよSUNのレート対応も必要ですが、14行目に置けるようになっているのも大きいですね*1。
これらも対応していきたいですが、まだ時間がかかりそうです。
ぷよぷよ7 れんしゅうノート シミュレータ を バージョン0.4.3に更新
http://d.hatena.ne.jp/Horiuchi_H/20091007/1254908069#c にて、バグ報告があったので修正しました。原因は、複数同時消しをした際の色数を計算する処理にバグがありました。同じ色を2つ消して2色と扱われてしまっていました。公開して1年以上経っているんですが、まだこんなバグが放置されていたんですね。
報告ありがとうございます。
InheritableThreadLocal の使い方で、ハマったのでメモ。
Oracle Technology Network for Java Developers | Oracle Technology Network | Oracle
Javaでセッションの情報などを、ThreadLocalに保存しておいて後から参照するのは良くある使い方だと思います。しかし、今回では1セッション中にスレッドを作って処理を分散させる必要がありました。
そのためにお誂え向きな機能が JDKに用意されていて、それが表題の InheritableThreadLocalクラスになります。具体的には、あるスレッドで InheritableThreadLocalクラスのインスタンスを生成した場合に、そのスレッドから新規に作成されたスレッドに対して InheritableThreadLocalの情報が引き継がれます。その点が Inheritableなんですね。それ以外の部分は、ThreadLocalを継承している通り各スレッドで別々のインスタンスが生成されることになります。
さて、今回このクラスを使った際に問題が起きたコードは以下のものです。
import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; public class InheritableThreadLocalSample { private static final InheritableThreadLocal<Map<String, String>> info = new InheritableThreadLocal<Map<String, String>>() { @Override protected Map<String, String> initialValue() { return new TreeMap<String, String>(); } }; public static String get(String key) { return info.get().get(key); } public static void put(String key, String value) { info.get().put(key, value); } public static String getAll() { StringBuilder builder = new StringBuilder(); builder.append('['); for (Entry<String, String> entry : info.get().entrySet()) { builder.append(entry.getKey()).append('=').append(entry.getValue()).append(','); } builder.append(']'); return builder.toString(); } }
普通のThreadLocalでは、まったく問題がなさそうな実装なのですが、情報が引き継がれるところでバグが起きてしまいました。
InheritableThreadLocalクラスは、ThreadLocalを継承しているのですがメソッドが1つ追加されています。それが childValueメソッドです。あるスレッドから別のスレッドが作成された際に、このメソッドが呼び出されて情報が引き継がれます。そして、デフォルトの実装では前の値をそのまま返すだけになっています。
そんな訳で、今回のバグは ThreadLocalのつもりだったMapのインスタンスがそのまま別のスレッドに渡されて使われてしまっていた。さらに、そのMapのインスタンスが Mainスレッドで生成されたものが全てのスレッドに渡されていたため、無関係だと思っていた場所での変更が波及してしまっていた、というものでした。
修正するのは簡単で、上記の childValueメソッドをオーバーライドして新たなインスタンスを作るだけでした。修正後のソースは以下の通り。
import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; public class InheritableThreadLocalSample { private static final InheritableThreadLocal<Map<String, String>> info = new InheritableThreadLocal<Map<String, String>>() { @Override protected Map<String, String> initialValue() { return new TreeMap<String, String>(); } @Override protected Map<String, String> childValue(Map<String, String> parentValue) { return new TreeMap<String, String>(parentValue); } }; public static String get(String key) { return info.get().get(key); } public static void put(String key, String value) { info.get().put(key, value); } public static String getAll() { StringBuilder builder = new StringBuilder(); builder.append('['); for (Entry<String, String> entry : info.get().entrySet()) { builder.append(entry.getKey()).append('=').append(entry.getValue()).append(','); } builder.append(']'); return builder.toString(); } }
今日の地震は酷かった。
さすがに震度5の揺れは、まじめに避難しないとと思わされました。初めて、ビルから避難して外へ出ました。
しかし、深夜に電車が復旧したおかげでなんとか帰ってこれたけれど、震度6規模の地震がきたら本当に帰宅難民になるのが実感できました。
eclipse3.6(Helios)でのプラグイン開発 - メニュー
仕事で eclipseのプラグインを作ることになったので、そのために調べたことのまとめです。
今回は、メニュー及びポップアップメニューの出し方になります。
Help - Eclipse Platform
メニューは、eclipse3.3から IHandler*1を実装したクラスを使うことになったようで、調べていると Actionクラスを使っているものが多くてややこしいことになってました。そのため、自分のために Heliosでのやり方をまとめておきたいと思います。
まずは、今回の関連する拡張ポイント。
- org.eclipse.ui.commands
- 以下で使用する commandIdを定義するためのもの
- org.eclipse.ui.handlers
- 上記の IHandlerを実装したクラスと commandIdを結びつける定義
- org.eclipse.ui.bindings
- commandIdに対して、キーのバインディングを結びつける定義
- org.eclipse.ui.menus
- どこにどんなメニューを表示して、そのメニューと commandIdを結びつける定義
org.eclipse.ui.commands
この拡張ポイントの定義は簡単で、commandId(XML上は command/@id) を定義するためのものです。
実際には以下のように categoryの定義も必要になってきます。
<extension point="org.eclipse.ui.commands"> <category name="SampleCategory" id="SamplePluginGUI.commands.category"> </category> <command name="SampleCommand" categoryId="SamplePluginGUI.commands.category" id="SamplePluginGUI.commands.sampleCommand"> </command> </extension>
org.eclipse.ui.handlers
Handlerの定義も単純で、以下のように handlerタグで上記で定義した commandIdと実際の IHandlerを実装したクラスを結び付けます。
<extension point="org.eclipse.ui.handlers"> <handler commandId="SamplePluginGUI.commands.sampleCommand" class="ch.jpn.taoe.eclipse.sampleplugingui.handlers.SampleHandler"> </handler> </extension>
org.eclipse.ui.bindings
キーバインディングの定義は必須でないので、必要がなければ不要です。定義自体は、以下のように commandIdに対してsequence(これがショートカットキーの定義)を決めます。
contextIdは、「org.eclipse.ui.contexts.window」を設定しておくと決まっているようです。将来的に拡張予定だそうだそうですが、今のところ選択肢はないので気にしないでいいかと。
schemeIdは、eclipseの設定画面の「一般>キー」を開くと一番上にあるschemeに対応しています。基本的には「org.eclipse.ui.defaultAcceleratorConfiguration」を選んでおけばいいかと思います。
<extension point="org.eclipse.ui.bindings"> <key commandId="SamplePluginGUI.commands.sampleCommand" contextId="org.eclipse.ui.contexts.window" sequence="M3+6" schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"> </key> </extension>
sequenceには、キー名を記述することになります。特殊キーの対応は以下の通り。
修飾キーは、M1=ALT, M2=COMMAND, M3=CTRL, M4=SHIFT になります。
その他に以下の特殊名が定義されています。ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT, ARROW_UP, BREAK, BS, CAPS_LOCK, CR, ENTER, RETURN, DEL, END, ESC, ESCAPE, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, FF, HOME, INSERT, LF, NUL, NUM_LOCK, NUMPAD_0, NUMPAD_1, NUMPAD_2, NUMPAD_3, NUMPAD_4, NUMPAD_5, NUMPAD_6, NUMPAD_7, NUMPAD_8, NUMPAD_9, NUMPAD_ADD, NUMPAD_DECIMAL, NUMPAD_DIVIDE, NUMPAD_ENTER, NUMPAD_EQUAL, NUMPAD_MULTIPLY, NUMPAD_SUBTRACT, PAGE_UP, PAGE_DOWN, PAUSE, PRINT_SCREEN, SCROLL_LOCK, SPACE, TAB, VT *2
org.eclipse.ui.menus
ようやく真打の登場です。ここでどのメニューにどういう項目を表示するかを定義します。定義のxmlは、以下のようにmenuContribution タグの locationURIでメニューの追加場所を定義し、その下に commandタグで 実行するcommandIdを登録したり、サブメニューのために menuタグを追加したりできます。さらに、menuタグやcommandタグに visibleWhenタグを付けることで表示する条件を指定できます。
しかし、メニューと言われているものは具体的には3つあり、メニュー・ツールバー・ポップアップメニューに分かれます。さらに、windowに対するメニューやらviewのメニューなどがあり、何がどこに対応しているかわかり辛いですので下の画像を参考にしてください。
<extension point="org.eclipse.ui.menus"> <!-- windowのメニューに追加 --> <menuContribution locationURI="menu:org.eclipse.ui.main.menu?after=additions"> <menu label="サンプル・メニュー" mnemonic="M" id="SamplePluginGUI.menus.sampleMenu"> <command commandId="SamplePluginGUI.commands.sampleCommand" mnemonic="S" id="SamplePluginGUI.menus.sampleCommand"> </command> </menu> <command commandId="SamplePluginGUI.commands.sampleCommand" mnemonic="S" id="SamplePluginGUI.menus.sampleCommand"> </command> </menuContribution> <!-- 右クリックの全ポップアップメニューに追加 --> <menuContribution locationURI="popup:org.eclipse.ui.popup.any?after=additions"> <menu label="サンプル・メニュー" mnemonic="M" id="SamplePluginGUI.menus.sampleMenu"> <command commandId="SamplePluginGUI.commands.sampleCommand" mnemonic="S" id="SamplePluginGUI.menus.sampleCommand"> </command> </menu> </menuContribution> <!-- windowのツールバーに追加 --> <menuContribution locationURI="toolbar:org.eclipse.ui.main.toolbar?after=additions"> <toolbar id="SamplePluginGUI.toolbars.sampleToolbar"> <command commandId="SamplePluginGUI.commands.sampleCommand" icon="icons/sample.gif" tooltip="Say hello world" id="SamplePluginGUI.toolbars.sampleCommand"> </command> </toolbar> </menuContribution> </extension>
結局、locationURI によって様々な場所に表示されることになるので、その値が重要になります。locationURI の値は、以下のような書式で指定します。
"[Scheme]:[ID]?[ArgList]"
- Scheme
- "menu", "popup", "toolbar" のいずれかを指定します。
- ID
- 表示する対象のIDを指定します。Viewのメニューやツールバーの場合は ViewのIDを指定します。windowのメニューの場合は "org.eclipse.ui.main.menu"、windowsのツールバーは "org.eclipse.ui.main.toolbar"、全Viewのポップアップを対象とする場合は "org.eclipse.ui.popup.any" を指定します。
- ArgList
- 対象のメニューのどこに追加するのかを指定します。さらに "[placement]=[id]" と分かれます。placementには "after", "before", "endof" を指定します。id にはメニューの中にある、menuタグの id、もしくは commandタグの idを指定することになります。ただし、"additions"というIDは常に存在するので、場所を気にしない場合にはこのIDを指定することになります。