Entries

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Snow Leopard所感

タグ: Mac

MBP Late 2008をLeopardからSnow Leopardにアップデート。
うーん、細かなところで使い勝手が合わない……

Finderのサムネイル表示は速くなった。特にNASにあるGIFファイル。
アイコンのサイズ変更が容易になり、Quick Lookよりも手早くファイルの概要を確認できるようになったのは良い。

カラム表示されたFinderウィンドウで「フォルダをハイライトさせて『すべてを選択(Cmd+A)』」したときの挙動が変わった。
Leopardでは「ハイライトされているフォルダ内の全ての項目が選択」されるが、Snow Leopardでは「フォルダをクリックしてハイライトさせた場合を除き、ハイライトされているフォルダを含むフォルダ内の全ての項目が選択」される。
この挙動は「Stackにあるダウンロードフォルダを開いて中身をすべてゴミ箱に捨てよう」というときに鬱陶しい。
(ダウンロードフォルダ内の全ファイルを選択したいのに、ホームフォルダ内の全フォルダが選択される)

Exposéのウィンドウ配置がグリッド状になり、大きなウィンドウは小さく、小さなウィンドウは大きく表示するようになった。
正直、見づらい。

Exposé前画像 Exposé中画像

下の2つのウィンドウ、場所取りすぎだろう('A`)

「スリープ」や「スクリーンセーバー」解除後にパスワードを要求する設定が、「ディスプレイのスリープ」にも適用されるようになった。
処理を流したまま「離籍する」か「離籍はしないが画面を暗くする」かで「スクリーンセーバー」と「ディスプレイのスリープ」を使い分けていた自分にとってこの変更は嬉しくない。
「規定時間以上のスリープから復帰したときのみパスワードを要求する」ように設定ができるようになったのは良いが……

64ビットアプリケーションではATOK2006が使えない。
うん、まあこれはいつまでATOK2006引っ張って使ってるんだという話なので、ATOK2009を入れる。

そのATOK2009だが、文字変換中にCtrl+数字を押すと、Leopardでは「辞書セット指定変換ショートカット」が機能するが、Snow LeopardではSpacesの「特定のスペースへの切り替え」が優先される。
辞書セット指定変換については、Ctrl+1?4ではなく、F1?F4を使えということか。

Xcodeは入れ直し。
iPhone SDKを入れる場合、まずSnow LeopardのInstall DVDでXcodeを入れ、その後でSnow Leopard用のiPhone SDKを入れる。

Leopardの時にMacPortsで入れた諸々は、動くものもあるにはある。
が、多分完全に入れ直した方が(一度uninstall --follow-dependents installedしてinstallし直した方が)すっきりするだろう。

RedmineからSubversionのリポジトリを見られない

Redmine 0.8.4で、Redmineを動かしているのとは異なるサーバにあるSubversionリポジトリを設定してリポジトリタグを開いたら

リポジトリに、エントリ/リビジョンが存在しません。

というエラーが出た。
エラー発生時のRedmineのログを見たところこの記事の状況に近い。
なので試しに

lib/redmine/scm/adapters/subversion_adapter.rb

#cmd = "#{SVN_BIN} list --xml #{target(URI.escape(path))}@#{identifier}"
cmd = "#{SVN_BIN} list --xml #{target(URI.escape(path))}@#{identifier} 2>1&"

という変更を加えてからリポジトリタグを開いてエラーを出し、再度ログを見てみると……

-----------------------------------------------------------------------
**注意**  認証領域

   <http://www.example.com> Subversion Repositories

のパスワードは暗号化されていないディスクに保存されるだけです! 可能なら、
Subversion がパスワードを暗号化して保存できるよう、システムを設定するこ
とをお勧めします。詳しくはドキュメントを参照してください。

'/home/user/.subversion/servers' の 'store-plaintext-passwords' オプションの値を 'yes' または 'no'
に設定すると、この警告がこれ以上現れないようにすることができます。
-----------------------------------------------------------------------
暗号化されていないパスワードを保存しますか (yes/no)? svn: 標準入力を読めません: End of file found
Rendering template within layouts/base

おおぅ……Subversion 1.6のPrompting before storing passwords in plaintext formに引っかかっていたのか。
ちゃんとパスワードをキャッシュしない設定にしないと……いや、というかそもそも手を抜いてホームディレクトリを持つユーザでMongrelサーバを動かしてるのがいけないんだな(;´∀`)

Boost.Spirit V2.1用Shift JISパーサ

タグ: C++ Boost

Boost.SpiritにV2が導入されてからしばらく経つし、そろそろclassicじゃないSpiritにも手を出してみよう(`・ω・´)
ただし使用するのは1.36.0?1.40.0 β1 RC1に入っているV2ではなく、trunk@55547のV2.1。
boost::spirit::qi::int_parserの実装を参考に、まずはShift JIS1文字にマッチするプリミティブパーサを作ってみる。

#include <boost/static_assert.hpp>
#include <boost/spirit/include/qi.hpp>

namespace client {

struct sjis_parser_impl : boost::spirit::qi::primitive_parser<sjis_parser_impl>
{
    template <typename Context, typename Iterator>
    struct attribute
    {
        typedef unsigned short type;
    };

    template <typename Iterator, typename Context, typename Skipper, typename Attribute>
    bool parse(Iterator& first, Iterator const& last, Context& /*context*/, Skipper const& skipper, Attribute& attr) const
    {
        // wchar_t とか渡されても(´・ω・`)知らんがな
        BOOST_STATIC_ASSERT(sizeof(typename std::iterator_traits<Iterator>::value_type) == 1);

        boost::spirit::qi::skip_over(first, last, skipper);
        if (first == last)
            return false;

        const unsigned char high = *first;
        if ((high & ~0x7f) == 0 || (high >= 0xa1 && high <= 0xdf))
        {
            // 1バイト文字(ASCIIおよび半角カナ)にマッチ
            attr = high;
            ++first;
            return true;
        }
        else if ((high >= 0x81 && high <= 0x9f) || (high >= 0xe0 && high <= 0xef))
        {
            // 2バイト文字上位1バイトにマッチ
            const Iterator save = first++;
            if (first != last)
            {
                const unsigned char low = *first;
                if (low != 0x7f && (low >= 0x40 && low <= 0xfc))
                {
                    // 2バイト文字下位1バイトにもマッチ
                    attr = ((high << 8) | low);
                    ++first;
                    return true;
                }
            }
            first = save;
        }
        return false;
    }
};

struct sjis_parser : boost::proto::terminal<sjis_parser_impl>::type {};

} // namespace client

V2とV2.1ではプリミティブパーサの実装が違っているので、上記のコードはV2(現行リリース版)では使えない。
ま、いずれV2.1になるさ。いずれ……

#include <string.h>
#include <vector>
#include <string>
#include <iostream>
#include <iterator>
#include <algorithm>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
// この辺でsjis_parserを実装(実装をインクルード)

namespace client {

void test()
{
    const char source[] =
#if 0
        "ヽ(・∀・)ノ";
#else
        { -127, 82, 40, -91, -127, -51, -91, 41, -125, 109, 0 };
#endif

    const char* first = source;
    const char* last = source + strlen(source);

    using boost::spirit::qi::parse;
    using boost::spirit::qi::_1;

    // セマンティックアクションで標準出力に出力
    std::cout << std::hex;
    parse(first, last, *sjis_parser()[std::cout << _1 << ',']);
    std::cout << std::endl;

    using boost::phoenix::push_back;
    using boost::phoenix::ref;

    std::vector<int> codes;
    // セマンティックアクションでcodesにpush_back
    first = source;
    parse(first, last, *sjis_parser()[push_back(ref(codes), _1)]);
    std::copy(codes.begin(), codes.end(), std::ostream_iterator<int>(std::cout, ","));
    std::cout << std::endl;

    // パーサの属性が1つ(この場合std::vector<unsigned short>)ならこうも書ける
    first = source;
    parse(first, last, *sjis_parser(), codes);
    std::copy(codes.begin(), codes.end(), std::ostream_iterator<int>(std::cout, ","));
    std::cout << std::endl;

    std::string str("low bytes -> ");
    // std::stringにpush_backすると上位バイトが欠ける
    first = source;
    parse(first, last, *sjis_parser(), str);
    std::cout << str << std::endl;

    using boost::spirit::qi::raw;

    // rawディレクティブを使うと、マッチした範囲をiterator_rangeで求められる
    first = source;
    parse(first, last, raw[*sjis_parser()], str);
    std::cout << str << std::endl;
}

} // namespace client
8152,28,a5,81cd,a5,29,836d,
8152,28,a5,81cd,a5,29,836d,
8152,28,a5,81cd,a5,29,836d,8152,28,a5,81cd,a5,29,836d,
low bytes -> R(・ヘ・)m
ヽ(・∀・)ノ

TortoiseSVN 1.6.3のTSVNCacheが重い

タグ: C++

どうも最近、Windows起動後にTSVNCacheがCPUリソースを100%使っている期間が昔(とても重かった時代のTortoiseSVN)みたいに長くなってるなぁと思ったら、

RE: TSVNCache slowness after upgrading to 1.6.3.16613

> Previously I was using 1.6.1 and upgraded to 1.6.3.16613 some days ago.
>
> Since then, *any* folder on Windows Explorer will take a long time to
> show up and during this time TSVNCache.exe uses 100% of one CPU [snip]

There have been several TSVNCache bugs discussed here and fixed in the latest nightly builds, ready for the next formal release of TortoiseSVN.

TortoiseSVN 1.6.3のバグだった。

RE: Re: High CPU usage caused by TSVNCache.exe at startup

I think I can see a problem in the source. Specifically, a test of the form

GetTickCount() - DRIVETYPETIMEOUT > drivetypeticker

is wrong for DRIVETYPETIMEOUT milliseconds after system start-up, and again every 49.7 days or so. But re-ordering as

GetTickCount() - drivetypeticker > DRIVETYPETIMEOUT

works better, provided the measured interval never exceeds 49.7 days.

GetTickCount()の戻り値型は「DWORD(unsigned long)」。
DRIVETYPETIMEOUTは「整数リテラル」で「300000」。
drivetypetickerは「DWORD型」で初期値「0」。

仮にGetTickCount()の戻り値が60000(起動1分)だとすると、上の式は次のように展開、評価される。

60000UL - 300000 > 0UL

通常の算術変換により、減算式の両項とその結果の型はunsigned longとなる。

(unsigned long)(60000UL - 300000UL) > 0UL
             (unsigned long)-240000 > 0UL

-240000はunsigned longで表現できない値なので、表現できる最大値より1大きい数を法とした剰余を演算結果とする。
(ただしC言語系の%演算では剰余も負数になるので、ここでは新しい型で表現しうる最大の数に1加えた数を加えることにする)

(unsigned long)(-240000 + ULONG_MAX + 1) > 0UL
                            4294727296UL > 0UL

「-240000 > 0」でfalseとなるはずのところが、「4294727296 > 0」でtrueになってしまった。
このように、上の式では、GetTickCount()が300000以上を返すようになる(起動後5分以上経過する……ちょうどTSVNCacheが落ち着く頃合だ)まで正しい評価を行うことができない。

符合なし整数型でこのような評価を行う場合、「閾値で引いて基準値と比較する」のではなく、「基準値で引いて閾値と比較する」ようにしなければならない。

60000UL - 0UL > 300000
      60000UL > 300000UL

起動から49.7日が経過するとGetTickCount()は0に戻るが、その場合でもこの式の評価は大概正しい。

                          0UL - 4294727296UL > 300000
                  (unsigned long)-4294727296 > 300000
(unsigned long)(-4294727296 + ULONG_MAX + 1) > 300000
                                    240000UL > 300000UL

この辺、符号なし変数型の「面白い」ところであり、「けどむしろ間違いの元になることの方が多いから嫌」なところである。

Appendix

タグ

Blog内検索

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。