2014年9月15日 (月)

コドク・クロニクル(蠱毒伝奇?)

日本の伝承とクトゥルー神話の融合、だそうです。

ジャンルはゲームなのですがVisual Novelとも書かれており、まぁたぶんゲーム性は少なくて物語重視の作品なのでしょう。Yes/Noという選択を迫っている画面があったり、あと戦闘システムの説明もあったりするので、全くの一本道というわけでもなさそうです。

現在、kickstarterで出資者を募っており、わりとゆっくりと資金が集まっているようです。最初のゴールである8,000英ポンドには届くと思うのですが、それだと日本語版が出ないんですよね…。日本語版を作ってもらうには、20,000ポンド集まらないといけない。これは、結構苦しいんじゃないかと思いまして、極めて微力ながら、この場でも宣伝する次第です。

Db5408c8e41888ea825d9521c930f26a_la24ce1387a153e638f532ee70a65ab8e0_la

因みに下の画像のテキストは「ねぇ、正直に答えて。本当にここから逃げ出せると思ってる? はい - いいえ」みたいな感じですかね。

5ポンドから出資できますので、こういうの好きな方は、ぜひ。

Kodoku Chronicles by Carnivore Studio

https://www.kickstarter.com/projects/1347225956/kodoku-chronicles

2014年9月 8日 (月)

DotNetZipでEPUBファイルを作る

C#でEPUBファイル作ろうと思い、DotNetZipを使ってみた。

mimetypeを先頭に置いているのに、EPUBっぽくならない。ぐぐってみると、「EPUBではmimetypeは圧縮してはいけないが、DotNetZipは必ず圧縮する。そこで、適当なEPUBファイルを持ってきて、その先頭のmimetypeだけコピーして、云々」なんていう記事を発見。

いや、そんなことないでしょ、ZipEntry.CompressionMethodっていうプロパティがあって、これをNoneにすれば非圧縮メンバーを作れる。それでもEPUBにならなくて困ってるんだよ、こっちは、みたいな。

仕方ないので、ファイルを16進ダンプして良く見たら、ファイルヘッダーにextended fieldがついている。中身は「NTFS形式ファイルスタンプ」であった。

なるほど。

これを止めるには、ZipEntry.EmitTimesInWindowsFormatWhenSavingをfalseにすればよい。(Linux/Monoで動かすなら、ZipEntry.EmitTimesInUnixFormatWhenSavingをfalseにする。いちいちプラットフォームを調べる必要はなくて、常に両方ともfalseにしちゃうのが無難だと思う。)

つまり、こんな感じ。

	var mimetypeEntry = zipfile.Add("mimetype");
	mimetypeEntry.CompressionMethod = CompressionMethod.None;
	mimetypeEntry.EmitTimesInWindowsFormatWhenSaving = false;
	mimetypeEntry.EmitTimesInUnixFormatWhenSaving = false;

これで、cygwinのfile コマンドが"EPUB documen"と言ってくれるようになった。

2014年9月 6日 (土)

意味のわからないウェブの記載

楽天市場で買い物しようとすると、意味の全くわからない注意書きが多い。意図がわからないんじゃなくて、そもそも日本語の文として、何をいいたいのかさっぱりわからないのだ。

まとめWIKIみたいなものを読んでいても、意味のわからない文が多い。何を言いたいのかさっぱりわからない。

今まで、それは、文章を書いている人のセイだと思っていたのだ。要は、文章を書くのがヘタな人たちが書いた、意味がわかるように書けていない文章なんだと。ところが、今日、そのなかの一つのサイトが「記載が丁寧でわかりやすい」という評価を、複数の人たちから受けていることを知った。

おどろいた。

これはつまり、意味がわからないのはが悪いということなんじゃないのか。普通の人が「わかりやすい」と感じる文章を理解できないんじゃないのか。

なんというか、実は私は年寄りなのでありまして、実にプログラマ歴40年なわけですよ。たぶん、熱心にまとめWIKIなんかを書いている人たちとか、楽天市場に出店している店長さんたちの中心層とかとは、大分年齢が離れている。同じ日本語とは言え、表現方法とかが違っちゃっているんではないか、などと思う次第。

# それが事実だとすると、たぶん逆も成立するので、自分ではわかりやすいつもりのこのブログも、今の若者には意味が全くわからない謎の文章でしかないのかもしれないなぁ、などとも思いつつ。

2014年8月12日 (火)

Office のマネージド COM アドインの DLL のバージョン番号

は、1.0.0.0 より大きくないといけないらしい。つまり、先頭を「0」にしてはいけないらしい。

これは、つまり、RegAsm で登録する DLL の VersionInfo に書くバージョン番号で、もともとは Visual Studio のプロジェクトのプロパティの Assembly Info... に書くバージョン番号だ。

これを 0.8.0.0 にしたら、Excel が、アドインの初期化を途中で止めて LoadBehavior を 2 に変更しちゃうようになってしまったのだった。(それに気づくのに4時間くらいかかったよ…。)

ウソでした。

バージョン番号だけ変えて試すと、0.X.X.X は全滅で、1.0.0.0 にすると動いたので、上に書いたような秘密の仕様があるのだと思い込んでしまったのですが、そういうことではありませんでした。

(原因不明のトラブルで苦しみ、午前0時ころにやっと動き、その後1時間ほどかけて原因の切り分けをして、ついにわかった、と思ってしまったわけです。一晩寝て、疲れが取れた頭でもう一度考えたら、おかしい気がしたのです。それを検証したら(昨夜はそこまでやらなかった;疲れていたので)やはりダメだったという…。ま、言い訳ですが。)

ということで、あいかわらず未解決なのですが、RegAsmとcodebaseとバージョン番号との関係がうまく行っていない(というか、たぶん私が何かを誤解している)のは間違いなく、Excelは無実だろうと、今は考えています。

と、いうことで、今回の教訓:「トラブルシュートが深夜まで長引いて、やっとうごいて『これで解決』と思っても、すぐブログに書かず、一晩寝て頭を冷やして翌日もう一回よく考えよう。」

追記

本件は、結局、アセンブリのバージョンが1.0.0.0以外の値だとRegAsmしたときに変なcodebaseレジストリエントリが作られてしまうというNetOfficeのバグに、私のテスト手順が悪かったことが複合したことによる謎動作だった、というのが、私の結論です。Excelは無実だと今は確信しています。

2014年6月21日 (土)

自作のXmlWriterをXslCompiledTransformにわたす

XmlWriterを自分で直接実装することはなくても、XmlTextWriterのサブクラスを作るのは、よくやりますよね。

あれ、やらない?変だなぁ。じゃぁ、みんな、こんなの作るときどうやってるんだろう。「セルの中で改行したいときには、コンテント(内容)中で普通に改行するんじゃなくて、
って書きなさい」っていう謎仕様なんですけど。あ、いや、上のリンク先には書いてありませんが。でも、そうなの。仕様なの。

単にLinq to XMLで書き出すだけなら何も問題ないんですけど、XSLTで処理した結果を自作XmlWriterで出力しようとしてハマったので、その回避方法を書いておきます。

自作したXmlWriterクラスのインスタンスを、いったん XmlWriter.Create(XmlWriter, XmlWriterSettings) にわたし、返ってきたインスタンスを XslCompiledTransform.Transform にわたす。これでOK。

ただし、注意点がひとつだけあって、それは、自作XmlWriterクラスのSettingsプロパティは、常にnullを返すようになっていなければいけない。まぁ、XmlWriterのSettingsのデフォルト実装は一律nullを返すので、そのままにしておけばいいだけなんですけど。

えー、なんちゅうか、ですね、これに気づくまで2ヶ月悩み続けた、という。XslCompiledTransformとXmlWriterの間には、公開されていない秘密のインターフェースがあって、一般人が使えるXmlWriterのサブクラスはそのインターフェースを使ってないので、XslCompiledTransformと組み合わせると激しく誤動作する(例えば、xsl:output で doctype-public 指定してるのに DOCTYPE 宣言が生成されないとか)というのはすぐに気づいたが、回避方法がわからなかったんですよ。まさか、XmlWriterSettingsに秘密の(internalの)プロパティがあって、そこにdoctype-publicが入っているので、XmlWriter側の責任でそのinternalのdoctype-publicを読み取って、XmlWriter.WriteDocTypeが呼ばれなくても正しいタイミング(つまり、文書ルート要素に対するWriteStartElementの直前)で勝手にDOCTYPE宣言を作らなければならない、なんていう仕様、これをなんとか実装しようとしていたんです。2ヶ月間。

でも、それはハズレの道だったんですね。

たぶん、マイクロソフトも、こんな仕様をクラスライブラリの外側で実装できるわけがないことはわかっていて、ちゃんと救済策を用意してくれていたわけです。それが、っていうか、そのためだけの目的で作られたと思われる XmlWriter.Create(XmlWriter, XmlWriterSettings) なわけです。

だったら、どうしてちゃんとドキュメントに書いておいてくれないんだ、せめてヒントだけでも、って思うわけですが、答えがわかってからドキュメント読んだら書いてありました。本当にヒントだけですが。

This method allows you add additional features to an underlying XmlWriter object.

訳:このメソッドにより、元のXmlWriterオブジェクトに追加機能を加えることができます。

この「additional features」っていうのが、XslCompiledTransformとXmlWriterとの間の非公開の様々なインターフェースの処理(上でかいたDOCTYPEの件以外にもたくさんある様子)ということを控えめに表現したものらしい。

うーん、なんちゅうかなぁ。

2014年6月14日 (土)

使えないハッカー

ハッカーというのはツールが大好きだ。何かというとすぐにツールを作る。

ちゃんとしたハッカーは、普通に手作業でやると30分かかる作業を数秒で実行するスクリプトを5分で書いたり、普通にやると1日かかる作業を30分で終わらせるための専用ツールを1時間で作ったりする。

「だって、そのほうが結局早いし、変なミスもしないでしょ。」というわけだ。

ダメなハッカーは、30分の作業を一瞬で実行するスクリプトを5分で書くつもりで書き始めるが、なかなか思ったような動作にならず、なんとか一通り動くスクリプトができるまでに30分以上かかっちゃったりする。それでも一部不具合が残っており、結果のファイルをエディタで一部書き換えなければならなかったりする。

ダメじゃないけど使えないハッカーは、5分でスクリプトを書きあげるのだが、「この程度の処理で3秒もかかるなんて、やっぱり(ピー)じゃだめだな。Cで書き直そう」とか言って書き直し始める。30分ほどで動くようになるが、「処理は一瞬で終わるようになったけどメモリ食いすぎだな。しかも、こことここで同じような処理を二度書いてるのもみっともないな。」などと言ってさらに改良をはじめ、結局満足できるツールになるまでに数時間かける。(で、その「完成」したツールは、当然ながらもう二度と使わない。)

2014年6月 1日 (日)

食洗日記をひさしぶりに更新

じつは2ヶ月近く食洗日記を更新していなかったのですが、先ほどまとめてアップロードしておきました。

つまり、写真自体は撮影してあったのです。

まぁ、誰も待っていなかっただろうとは思いますが。いちおうお知らせでした。

2014年5月 3日 (土)

LINQ to XMLには「空のテキストノード」が存在する

Linq to XMLを使ってXMLツリーを生成し、XElement.Save() でXML文書として書き出すときの話。new XText("") ってやると、内容が空文字列であるXTextオブジェクトができる。しかも、これを要素の(唯一の)内容にしても、自動的に消えたりせずに保存される。

例を示そう。

new XElement("foo", new XText("")).Save("foo.xml");

とやると、

<foo></foo>

という文書ができる。(実際にはXML宣言が付くが省略。)

他方、

new XElement("foo").Save("foo.xm");

だと

<foo />

になる。

つまり、空のテキストノードがあるのか、何もないのかが区別されているのだ。

これは、本来のXMLのインフォセットというかデータモデルというか、それとは違うわけで、気持ち悪いのだが、しかし、これを積極的に利用すると、シリアライズ後に空要素を<foo />にするか<foo></foo>にするかをプログラムで(個々の要素インスタンスごとに)選べる、ということでもある。

それはそれで便利な気がする。

※ 因みに、マイクロソフトにはめずらしく、このことはドキュメントに明記されている。私はずっと気づいてなかったけど。

2014年4月25日 (金)

Visual Studio ExpressでNSISを使う

ProjectのPropertiesのBuildEventsのPost-Build event command lineに、こう書く。

<pre>if "$(Configuration)"=="Release" "C:\Program Files (x86)\NSIS\makensis.exe" install.nsi</pre>

Run the post-build eventはOn successful buildのままで。

これで、Visual StudioでReleaseビルドすると、自動的にNSISインストーラーが出来るようになります。

目からウロコというか、コロンブスの卵というか、実は単に頭が悪いだけかもしれませんけど、数年間、ずっとあきらめて、ビルドした後、手でコマンド打つということを繰り返しておりました。ははは。

なお、install.nsiは、プロジェクトフォルダに普通のソースファイルと一緒に置いておくわけですが、Copy to Output Directory を Copy if newerにしておきます。

2014年4月 9日 (水)

USB 3.0 のUSBメモリ

SEITECという、少なくとも私は聞いたことのないメーカー(ブランド)の、C102という、なんだかやる気が感じられない名前・型番のUSBメモリをあきばおーで購入。128GBで6534円(消費税8%込み)ということで、安かったので。

この容量で最安値ではなかったが、最安値の品が「50MB/s」と主張しているのに対してこちらは「UP TO 210MB/s」と書いてあり、差が数百円だったのでこっちにしてみた。

だったら、ベンチマークしなきゃだめでしょ、ということで。

そしたら、こんな感じだった。(画像クリックで拡大。)

Usb3

うむ。これはしっかり速いんじゃないかな。シーケンシャルアクセスに限れば、秋葉原に出回りだした最初のころのSSDよりはずっと速い。512KB単位のランダムアクセスで、リードとライトの差が大きすぎるような気もするが、これはバッファ(キャッシュ)が小さいとか、そういうことなのかなぁ。

«SAT Solverでナンプレを解くのにかかる時間