• libxml-rubyで [BUG] object allocation during garbage collection phase

    gemでlibxml-ruby(0.5.4)をインストールして使っていた。
    いつからか、以下のようなメッセージでクラッシュしたりしなかったり、という事象が出始めた。
    [BUG] object allocation during garbage collection phase
    ・・・という問題に悩んでいたのだけど、そのものズバリの答えが。
    [ruby-dev:35157] Re: error: Ruby 1.8.7 object allocation during garbage collection phase
    クラッシュといっては心外な話しか。
    新しいrubyだと問題を検出して[BUG]を出す、ということだそう。

    原因はわかったが、とりあえず手元のlibxml-ruby前提で書いたツールをどうするか。

    libxml-rubyのパッチを書く?
    とコードを眺めたものの早々にあきらめた。これはすぐにどうこう出来そうもない。。

    REXMLで書き直す?
    そもそもREXMLが遅いので、libxml-rubyにしただけにこれは避けたい。

    perlのLibXMLで書き直す?
    んー、時間もかかるし同じものをもう一回書くのもな。

    で、jruby
    REXMLを使うとスタート地点に戻ってしまうので、javaのDOM・XPath APIを使うことに。

    とりあえず、libxml-rubyで使ってるインタフェースだけラッパーを用意。
    ツール側のコードはほぼ変更がなかった。
    libxml2の軽快さには遠いがjrubyありがとうって感じ。

    jruby:1.1.2
    Sun Java: 1.6.0_05
    OS:CentOS 5.1

      $KCODE='u'
    require 'java'

    class WrapNode
    attr_reader :node

    def initialize(e)
    @node = e
    @xpath = nil
    end

    def to_s
    @node.nodeValue.to_s
    end

    def wrap(e)
    if e == nil
    return nil
    end
    WrapNode.new(e)
    end

    def next
    self.wrap(@node.nextSibling)
    end

    def text?
    @node.nodeType == org.w3c.dom.Node::TEXT_NODE
    end

    def [](name)
    @node.getAttribute(name)
    end

    def parent
    self.wrap @node.parentNode
    end

    def child
    self.wrap @node.firstChild
    end

    def xpath
    if !@xpath
    factory = javax.xml.xpath.XPathFactory.newInstance()
    @xpath = factory.newXPath()
    end

    @xpath
    end

    def find(expr)
    nodelist = self.xpath.evaluate(expr, @node, javax.xml.xpath.XPathConstants::NODESET)

    ret = []
    for i in 0 .. (nodelist.length - 1)
    ret.push(WrapNode.new(nodelist.item(i)))
    end
    ret
    end
    end

    class WrapDocument < WrapNode
    def initialize(e)
    super(e)
    end

    def root
    self.wrap(@node.documentElement)
    end
    end

    # 指定されたファイルをopenしてXML文書を返す
    #
    # fn_in::
    # ファイル名。nilの場合、stdinを適用
    def build_doc(fn_in)
    st = java.lang.System.in
    if fn_in
    st = java.io.FileInputStream.new(fn_in)
    end

    factory = javax.xml.parsers.DocumentBuilderFactory.newInstance()
    builder = factory.newDocumentBuilder()
    WrapDocument.new(builder.parse(st))
    end

    doc = build_doc("foo.xml")
    doc.find("//bar").each { |e|
    puts e["name"]
    }

  • CentOSが 5.2になった

    何気にyum updateしたら、update対象パッケージが200以上。
    なんじゃこりゃー、と思ったら5.2になってた。

    $ rpm -q firefox
    firefox-3.0-0.beta5.6.el5.centos

    beta5て(^^)、CentOS的にアリなの?



  • Virtual Server 2005で 仮想IDEディスクを SCSIに移行する

    Virtual PC Guyいわく。

    So with all of this in mind, my recommendation is this:

    • If you are running Windows NT, 2000, XP, 2003 with Virtual Machine Additions installed; use SCSI.
    • If you are running any other configuration; use IDE unless you specifically use more than 4 disks, or larger than 128gb disks
    Virtual PC Guy's WebLog : IDE vs SCSI under Virtual Server
    ということで、SCSIがおすすめらしい。
    MSのKB「Virtual Server 2005 performance tips」にもIDEよりSCSI仮想ディスクのが20%ベターだ、という記述がある。


    新規に作成する仮想マシンは仮想SCSIディスクを選び、OSセットアップ時の青画面でF6キーを押して、仮想フロッピー「SCSI Shunt Driver.vfd」を読み込ませることで対処できる。


    問題は、既に仮想IDEディスクでセットアップしてしまった仮想マシン。
    次のURLでダウンロードできる文書に仮想IDEディスクからSCSIディスクへの移行手順が書いてあった。
    Download details: Virtual Server 2005 - IDE to SCSI Virtual Machine Migration


    仮想ディスク(vhd)は、IDEでもSCSIでも共通らしく、バスを変更すればそのまま使えてしまうらしい。
    うーん、すごいな。


    手順メモ:

    VM環境:
     Virtual Server 2005 R2 SP1
    ゲストOS:
     Windows 2003 Server Enterprise Edition R2 SP2
     仮想マシン追加機能インストール済み
     仮想ディスク1台を1つのパーティションとして使用
     undo disk未使用

    • ゲストOSをシャットダウンし電源オフ
    • ゲストの仮想ディスクをバックアップ
      • 復元ディスクを使っている場合、マージするかバックアップする(らしいんだけど、復元ディスクを使っていなかったので何もせず)
    • VirtualServer管理ウェブサイト→当該仮想マシンの「構成の編集」を開く
      • 「SCSIアダプタ」をクリック→「SCSIアダプタの追加」→OKボタン
    • 当該仮想マシンの電源オン
      • ゲストOSが起動し、Plug&Playで追加したSCSIアダプタが認識される
    • 再びゲストOSをシャットダウンし電源オフ
      • VirtualServer管理ウェブサイト→当該仮想マシンの「構成の編集」を開く
      • 「ハードディスク」をクリック
      • 「接続」をSCSIアダプタの任意SCSI IDに変更(ここではID 0にした)→OKボタン
    • 当該仮想マシンの電源オン
    • ディスクが複数接続されている場合、BIOS画面からブート順を変えるなどの手当が必要だが、ここでは一台しか接続されていないので特に何もしなかった。

    • OSが起動すると、構成が変わったからアクティベーションしなおせ、と言われたので、そのように。

    • SCSIアダプタのドライバを仮想マシン追加機能で提供されているドライバに更新する
    • コンパネ→システム→ハードウェア→デバイスマネージャ
      • 「SCSIとRAIDコントローラ」ノードを開くと「Adapter AIC-7870 PCI SCSI Controller」があるはずなので、右クリック→「ドライバの更新」
      • 「いいえ、今回は接続しません」を選んで「次へ」ボタン
      • 「一覧または特定の場所からインストールする」を選んで「次へ」ボタン
      • 「次の場所を含める」に仮想マシン追加機能のインストール先を選択(ここではC:\Program Files\Virtual Machine Additionsだった)→「次へ」
      • で、ドライバがインストールされる。
    • SCSIデバイスが「Microsoft Virtual Machine PCI SCSI Controller」に変わる
    scsi.png


    Virtual PCはSCSIをサポートしない。

  • Excelで VBAマクロをいじってるうちに不調になる話

    excelでVBAマクロを編集→保存しつつ実行ということを繰り返していると、突然エクセル(というかブック)が不調になってしまうことがある。
    ※個人的には「xlsブックが腐った」と呼んでいる。

    • ブックを開くだけで「ご不便をおかけして申し訳ありません。」ダイアログが表示され死んでしまう。
      →腹いせにエラー報告しまくったけど、どうなるものでもなく・・・。
      Faulting application excel.exe, version 11.0.8211.0, stamp 47dcb10b,
      faulting module vbe6.dll, version 6.5.10.24, stamp 464105f1, debug? 0,
      fault address 0x001ec79a.
    • コードを変更していないにも関わらず、実行できたりできなかったりする
      →同じコードなのに、「コンパイルエラー」が出るようになる
    • コードを変更していないにも関わらず、実行できたりエクセルごと落ちたりする

    ツールをお客様の前でデモってるときに、エクセルごと落ちてしまい、「自分の環境では動くんだけど」を地で行く展開に・・・。
    頭が痛い。

    こんなときのgoogle先生頼み。
    が、excelが落ちる話はよく出てくるけど、同じコードで実行できたりできなかったり、という話は見つけられなかった。

    再現コードは追及できていない。
    状況・事情は以下のとおり。
    • 運用時はExcel 2000
    • Excel 2003 SP3/Excel XP(いずれもWin XP Pro SP2)で再現
      →2000ではいまのところ未経験
    • データを入れるxlsブックと、マクロを格納するxlaに分けている
    • xlaが開かれるタイミングで自ツール用のメニューを追加する
      →いろいろ経緯があってこういうことに
      →ブックを開いた状態でxlaを開くと機能が有効になる、という使い方
    • VBA中で新しいブックを作成し、一部シートを削除している
      →MSのKBに、(Excel 2000だけど)シートの削除やブック保存と関連のありそうなものがあったから
      http://support.microsoft.com/default.aspx?scid=kb;ja;JP199212
    • クラスモジュールを使っている
    • フォームモジュールを使っている

    結局原因はまったくわかっていない。

    調査の過程で、
    • xlaを開く→ツール-マクロ-Visual Basic Editor→CTRL+Sで保存→Excel終了、を繰り返すだけでxlaアドインのファイルサイズが変わる。
      →何も変更しない状態で上書き保存を繰り返す。本事象の場合、290KB~400KBの間で変化した。
    • 更にウォッチしたら「xlaを開く→エクセル終了する」だけでファイルの中身が変わる
      →具体的な違いは分からないが、sha1ハッシュが変化することで確認した。Tortoise SVNで変更のチェックにひっかからないのは、ファイルの更新時刻が変化しないからか。
    ということに気付いた。

    全く根拠のない想像だけど、何かしらの内部状態・中間状態(parseとか?)をブックの中に保存しているんだろう、そしてこの部分に火種が潜んでるんだろう、と考えた。

    だったら、保存できなくしてしまえ、ということで、xlaファイルを「読み取り専用」にしたら、ハッシュ値の変化はなくなった。当然ながら。

    現在のところマクロ死亡は再現していない。
    これならいける、かも???



    元々、リリース候補の作成を、nantを使って1手順化していたのが幸いだ。
    1. マクロ編集
    2. 実行・確認(NGなら1に戻る)
    3. リリース候補作成
    4. テスト
    という流れ。
    nantスクリプトでattrib要素を用い、xlaファイルを読み取り専用にする。
    4でエクセルが落ちる現象が出た場合は、1に戻って保存で再挑戦。内部状態がまとも?になるまで繰り返す(うへ)。

    読み取り専用でも上書きは可能なので、マクロの差し替えもなんとかなる、と。

     
  • マクロでOutlookの予定表を iCalendar形式 (ics)で出力する

    予定表アイテムを別のカレンダーアプリケーションへインポートするために、Outlookの予定表をiCal形式で出力したい。

    ■前提
    • 既定以外の予定表フォルダも指定したい
    • 出力処理を自動化したい(警告ダイアログは困る)
    • セキュリティ警告周辺の設定をいじらないで済ませたい
    • Outlook 2003でも使いたい
    てな条件でjscriptで書いてみた。

    ol2ics.txt
    (コンテキストメニューから保存。拡張子を.jsに)

    cscript.exe ol2ics.js [/folder:folder_path] 出力ファイル.ics

    /folder:予定表フォルダのpath。

    • エクスポート時点で、終了時刻が過ぎていない予定が出力される
    • 定期的な予定は未対応
      インポート先アプリケーションが繰り返し予定のインポートに対応していない(手入力はできるのに・・)ので、まぁいい。
    • SaveAsしないのは、
      →OL2003で↓警告が出たから。次項のAppointmentItem.Bodyと関係ある?
      ol_caution.png

      →OL2007だとデフォルトでは、以下のような設定になっていて、アンチウイルスが有効なら警告されないみたい。試しにアンチウイルスをoffにしてから試行したら警告が出た。
      ol_sc.png
    • DESCRIPTIONを出力していないのは、
      →AppointmentItem.Bodyを参照すると上記の警告ダイアログが出たから。(OL2003)
      →インポート先アプリケーションのUIを勘案して、SUMMARYだけ反映できれば十分と割り切ることに。。
    • OL2007だと、Folderに対してSaveAs出来るようだけど、OL2003でも使うので見送りに。

    OutlookからUIを用いてics形式で保存すると、UIDの桁数がかなり多く、AppointmentItem.EntryIDの値とは異なる。
    AppointmentItem.EntryIDのリファレンスには"The EntryID property returns a MAPI long-term Entry ID. "とあるけど。