釣られてみた

question:1194699919

回答 3 に釣られてみた。

再生テスト
t120o4l4v15@3 cdefgab<c
空行を無視した場合
t120o4l4v12@3
ffdga-a-b-g-dd-o3o2o8d-b-o8o1fdcb-aa-dg-fa-dga-b-db-a-dgdb-ga-b-eddgdgb-a-b-a-cdgg-a-b-gd-b-

d-gg-o8o7o6o2o2eg-cg-a-g-gd-b-g-o6d-gg-a-eb-g-dcgb-eo5d-b-g-



bba-dco6cacgo1ea-g-caa-o2fa-dcabb-dcb-agbcb-g-a-abggggga-g-ca-g


cabdao8gca-fg-a-dcb-a-abbcaab-abca-g-cd-o1o3ea-g-bco7g-o6gabcg-a-bage

bg-efg-bcdfb-o8o8o8b-a-fo2ceab

cga-abca-gcaa-cab-a-gg-cb-g-b-b-a-a-b-ca-cb-baa-a-d-b-a-d-g-o4


caco1o7fg-a-abgcb-gacb-g-o0fcb-a-cgba-cb-b-egg-ca-b-b-

fa-cbagco8go8cb-a-fa-a-b-a-a-go7a-feo1cgacbaab-agbcda-bagb-gcba-afa-o8

cabcacda-dfggbco1o2o4a


abcaa-b-ggab-g-o2o1o7fo2g-a-o7gbaa-cb-o8gafcga-baca-bagagba-bbea-

cgbga-b-b-aab-g-bgb-g-ba-o3g-g-g-a-b-o7a-fg-a-bcba-b-a-b-a-a-a-gag-b-d-o1


gabg-d

g-ao5ba-a-g-g-bcgcga-g-o6o8o1a-g-gceg-g-g-bacacao6o5gaea-g-a-ca-ggafca-a-ao0
連続空行をトラックの区切りとした場合
t120o4l4v12@3
ffdga-a-b-g-dd-o3o2o8d-b-o8o1fdcb-aa-dg-fa-dga-b-db-a-dgdb-ga-b-eddgdgb-a-b-a-cdgg-a-b-gd-b-

d-gg-o8o7o6o2o2eg-cg-a-g-gd-b-g-o6d-gg-a-eb-g-dcgb-eo5d-b-g-


;
t120o4l4v12@3
bba-dco6cacgo1ea-g-caa-o2fa-dcabb-dcb-agbcb-g-a-abggggga-g-ca-g


;
t120o4l4v12@3
cabdao8gca-fg-a-dcb-a-abbcaab-abca-g-cd-o1o3ea-g-bco7g-o6gabcg-a-bage

bg-efg-bcdfb-o8o8o8b-a-fo2ceab

cga-abca-gcaa-cab-a-gg-cb-g-b-b-a-a-b-ca-cb-baa-a-d-b-a-d-g-o4


;
t120o4l4v12@3
caco1o7fg-a-abgcb-gacb-g-o0fcb-a-cgba-cb-b-egg-ca-b-b-

fa-cbagco8go8cb-a-fa-a-b-a-a-go7a-feo1cgacbaab-agbcda-bagb-gcba-afa-o8

cabcacda-dfggbco1o2o4a


;
t120o4l4v12@3
abcaa-b-ggab-g-o2o1o7fo2g-a-o7gbaa-cb-o8gafcga-baca-bagagba-bbea-

cgbga-b-b-aab-g-bgb-g-ba-o3g-g-g-a-b-o7a-fg-a-bcba-b-a-b-a-a-a-gag-b-d-o1


;
t120o4l4v12@3
gabg-d

g-ao5ba-a-g-g-bcgcga-g-o6o8o1a-g-gceg-g-g-bacacao6o5gaea-g-a-ca-ggafca-a-ao0

汚染源は McAfee SiteAdvisor だった!!

Mozex 1.9.5 が動かないのも Make Link 3.0.2 が動かないのも、McAfee SiteAdvisor が Array クラス*1を汚染しているのが原因だった。
McAfee SiteAdvisor は、起動されると https://sadownload.mcafee.com/products/sa/firefox/search.dat をダウンロードするのだが、実はこの中身は JavaScript スクリプトで、これを eval することでスクリプトを拡張している。
しかし、この search.dat はグローバル空間を汚染しまくっており、中でも Mozex や Make Link が動かない原因になっているのが、次の部分だ。

Array.prototype.inArray = function (value)
{
	var i;
	for (i=0; i < this.length; i++) {
		if (this[i] === value) {
			return true;
		}
	}
	return false;
};

これにより、for...in 命令の結果が変わってしまう。

ary = new Array();
ary["apple"] = 100;
ary["orange"] = 120;
for (var i in ary) {
	alert(ary[i]);
}

実行結果

100
120
function (value) {
	var i;
	for (i=0; i < this.length; i++) {
		if (this[i] === value) {
			return true;
		}
	}
	return false;
}

まったく、困ったもんだね (`ω´♯)
という訳で、McAfee SiteAdvisor は ポイッ(/--)/ ⌒● した。

*1:JavaScript では、オブジェクトと表現するのが正しい?

Make Link 3.0.2 が動かない

Mozex 1.9.5 と同様 Make Link 3.0.2 も動かない。
調べてみると、動かない箇所も同様だ。

    info['title'] = getPageDescription( window.content.document );
}
if (useEntities) {
    for (i in info) {
        info[i] = info[i].replace(/&/g, "&amp;") // ←ここ

これまた同様に書き換えてみると、正常に動くようになった。

    info['title'] = getPageDescription( window.content.document );
}
if (useEntities) {
    for (var i = 0; i < info.length; i++) { // ←ここ
        info[i] = info[i].replace(/&/g, "&amp;")

パッチ

--- makelink.js.ORG	2007-03-31 00:39:06.000000000 +0900
+++ makelink.js	2007-10-27 19:27:06.000000000 +0900
@@ -141,7 +141,7 @@
 			info['title'] = getPageDescription( window.content.document );
 		}
 		if (useEntities) {
-			for (i in info) {
+			for (var i = 0; i < info.length; i++) {
 				info[i] = info[i].replace(/&/g, "&amp;")
 								 .replace(/</g, "&lt;")
 								 .replace(/>/g, "&gt;")

原因?

別のマシン*1でも同じ現象が起きるので、プロファイルが壊れている可能性は低い。そこで他の拡張機能が影響しているのかと思い無効化と再起動を繰り返していくと、どうやら McAfee SiteAdvisor をインストール&有効にしていると、問題が起きることがわかった。
衝突するような拡張機能ではないと思うので、やっぱり Firefox のバグなのかなぁ……?

P.S.

ちなみに、McAfee問い合わせ Web フォームから現象を報告すると、以下のような回答を頂いた*2
MCSupport-tech@nac-support.com wrote:

大変申し訳ございません。
ご利用いただいております、McAfee SiteAdvisor につきましては、
サポート対象外の製品となります。

*1:OS は Windows 2000

*2:それなら、問い合わせ製品名の選択肢に入れるなよ <(`^´)>

悪質回答者の排除

question:1192856662

今回も悪質回答者を排除する目的で回答者を「はてな質問者」に限定したが、id:amagami さんから「門前払い」ではないかというご意見を頂いた。また、id:goldwell さんからは「ダイアリー市民」に限定してはどうかというご意見を頂いた。
以前から、対象ユーザーを一種類ではなく複数種類選択したいと思っていたのだが、複数選択が可能になれば「はてな質問者」or「ダイアリー市民」等として悪質回答者を排除しつつ非悪質回答者を回答可能にする目的でも利用できるのではないかと思った。
そこで、アイデアを追加しようとしたのだが、既にそのようなアイデアが追加されていたので、残り少ないアイデアポイント*1で株を購入しておいた。

*1:株を運用する才能はないようだ(ノ∀`)っていうか、そもそも儲ける(ポイントを増やす)目的で購入しているわけじゃないんだけどね(^^;

matrix ライブラリーの使い方

question:1191841779

matrix ライブラリーの使い方が少しわかったので、それを使って書き直してみた。

require 'matrix'

class Vector2 < Vector
  DIMENSION = 2

  def self.[](*array)
    self.Raise ErrDimensionMismatch if array.size != DIMENSION
    super
  end

  def self.elements(array, copy = true)
    self.Raise ErrDimensionMismatch if array.size != DIMENSION
    super
  end

  def rotate(angle)
    cos = Math.cos(angle)
    sin = Math.sin(angle)
    mat = Matrix[[cos, -sin],
                 [sin,  cos]]
    mat * self # .class == Vector...orz
  end
end

x = 13.0
y = 6.0
angle_degree = 47.0

angle = angle_degree * Math::PI / 180.0 # convert degrees into radians
p Vector2[x, y].rotate(angle)           # => Vector[4.47785647109746, 13.5995882814242]
p Vector2.elements([x, y]).rotate(angle)# => Vector[4.47785647109746, 13.5995882814242]

復帰値が Vector クラスのインスタンスになってしまうのが痛い(ノ∀`)……*1

*1:クラス名を決め打ちにするのは止めて欲しい。

関数へのポインターの出力(C++ 編)

fptostr.c を、C++ で書き直してみた。
これで、「CHAR_BIT が 4 の倍数の場合にしか対応していない」という制限は無くなった。

fptostr.cpp

#include <bitset>
#include <cstring>
#include <limits>
#include <string>
#include <iostream>

typedef int (*funcptr_t)();

std::string fptostr(funcptr_t p)
{
    static const char *xdigits = "0123456789abcdef";
    const int bom = 1;
    const bool is_little_endian = *reinterpret_cast<const char *>(&bom) == 1;
    const std::size_t u_char_bits = std::numeric_limits<unsigned char>::digits;
    const std::size_t funcptr_t_bits = sizeof(funcptr_t) * u_char_bits;
    const std::size_t funcptr_t_digits = (funcptr_t_bits+3)/4;
    const std::bitset<funcptr_t_bits> mask = 0xf;

    unsigned char cary[sizeof(p)];
    std::memcpy(cary, &p, sizeof(p));
    std::bitset<funcptr_t_bits> bits;
    if ( is_little_endian ) {
        bits = cary[sizeof(p)-1];
        for ( int i = sizeof(p)-2; i >= 0; --i ) {
            bits <<= u_char_bits;
            bits |= cary[i];
        }
    }
    else {
        bits = cary[0];
        for ( int i = 1; i < sizeof(p); ++i ) {
            bits <<= u_char_bits;
            bits |= cary[i];
        }
    }

    std::string str;
    str.reserve(2+funcptr_t_digits);
    str.insert(str.begin(), xdigits[(bits & mask).to_ulong()]);
    for ( int i = 1; i < funcptr_t_digits; ++i ) {
        bits >>= 4;
        str.insert(str.begin(), xdigits[(bits & mask).to_ulong()]);
    }

    return str.insert(0, "0x");
}

int main()
{
    static const funcptr_t fps[] = {
        reinterpret_cast<funcptr_t>(main)
        , reinterpret_cast<funcptr_t>(fptostr)
        , NULL
    };

    for ( int i = 0; fps[i]; ++i ) {
        std::cout
            << "----\n"
            << "(void*) => " << (const void *)fps[i] << "\n"
            << "fptostr => " << fptostr(fps[i]) << "\n";
    }
}

実行例(i386/FreeBSD 6.2/g++ 3.4.6)

----
(void*) => 0x8048d6c
fptostr => 0x08048d6c
----
(void*) => 0x8048ad8
fptostr => 0x08048ad8

実行例(i686/CYGWIN_NT-5.1/g++ 3.4.4)

----
(void*) => 0x4014d6
fptostr => 0x004014d6
----
(void*) => 0x401150
fptostr => 0x00401150

実行例(i686/Windows XP/Visual Studio 2005)

----
(void*) => 00401250
fptostr => 0x00401250
----
(void*) => 00401000
fptostr => 0x00401000

関数へのポインターの出力(回答編)

question:1185077855

回答が 1 件しか付かなくて残念。しかし、コメント欄への書き込みも含めて、printf 系関数で変換指定子"%p"を使う方法しか出なかったので、やはり関数へのポインターを void へのポインターへ常に変換できると思っている人は多いのではないかと思われる。

CプログラミングFAQ―Cプログラミングのよく尋ねられる質問 (アジソン ウェスレイ・トッパン 情報化学シリーズ)

4.13
質問: 包括的な汎用ポインタ型は何か。関数へのポインタを void * に突っ込んだらコンパイラにしかられた。
回答: “包括的な汎用ポインタ型”は存在しない。void * に保障されていることはオブジェクト(すなわちデータ)を指すポインタを格納できることだけだ。関数ポインタを void * に変換することは移植性が高くない。(マシンによっては関数ポインタは非常に大きい。どのデータポインタよりも大きい。)

まあ、今時のマシンなら実際変換できる処理系は多いのだろうけど、変換できない場合にも使える方法(プログラム)を考えてみた。
ただし、次の 2 点の制限がある。

  • CHAR_BIT が 4 の倍数の場合にしか対応していない
  • 複雑なエンディアンには対応していない*1
fptostr.c
#include <limits.h>
#include <string.h>
#include <stdio.h>

#if (CHAR_BIT & 3) != 0
#  error error: fptostr requires (CHAR_BIT & 3) == 0 to be compiled
#endif

#define FUNCPTR_DIGITINBYTE (CHAR_BIT>>2)
typedef int (*funcptr_t)();
#define FUNCPTR_STRSIZE (2+sizeof(funcptr_t)*FUNCPTR_DIGITINBYTE)
#define FUNCPTR_BYTETOSTR(cary,ci,c,di,sp) \
    do { \
        c = cary[ci]; \
        for ( di = 0; di < FUNCPTR_DIGITINBYTE; ++di ) { \
            *sp = xdigits[c & 0xf]; \
            c >>= 4; \
            --sp; \
        } \
    } \
    while ( 0 )

int fptostr(funcptr_t p, char str[], size_t len)
{
    static const char *xdigits = "0123456789abcdef";
    const int bom = 1;
    const int is_little_endian = *(const char *)&bom == 1;
    unsigned char cary[sizeof(p)];
    unsigned char c;
    char *sp;
    int ci, di;

    if ( !str || len <= FUNCPTR_STRSIZE ) return -1;

    memcpy(cary, &p, sizeof(p));
    sp = str;
    *sp = '0'; ++sp; *sp = 'x';
    sp = str + FUNCPTR_STRSIZE;
    *sp = '\0';
    --sp;
    if ( is_little_endian ) {
        for ( ci = 0; ci < sizeof(p); ++ci ) {
            FUNCPTR_BYTETOSTR(cary, ci, c, di, sp);
        }
    }
    else {
        for ( ci = sizeof(p)-1; ci >= 0; --ci ) {
            FUNCPTR_BYTETOSTR(cary, ci, c, di, sp);
        }
    }

    return 0;
}

int main()
{
    char fpstr[FUNCPTR_STRSIZE+1];
    static const funcptr_t fps[] = {
        (funcptr_t)main
        , (funcptr_t)printf
        , (funcptr_t)fptostr
        , NULL
    };
    int i;

    printf("FUNCPTR_DIGITINBYTE = %d\n", FUNCPTR_DIGITINBYTE);
    printf("FUNCPTR_STRSIZE     = %d\n", FUNCPTR_STRSIZE);
    for ( i = 0; fps[i]; ++i ) {
        printf("----\n");
        printf("%%p      => %p\n", (const void *)fps[i]);
        if ( fptostr(fps[i], fpstr, sizeof(fpstr)) != 0 ) return 1;
        printf("fptostr => %s\n", fpstr);
    }

    return 0;
}
実行例(i386/FreeBSD 6.2/gcc 3.4.6)
FUNCPTR_DIGITINBYTE = 2
FUNCPTR_STRSIZE     = 10
----
%p      => 0x8048660
fptostr => 0x08048660
----
%p      => 0x80483b0
fptostr => 0x080483b0
----
%p      => 0x804852c
fptostr => 0x0804852c
実行例(i686/CYGWIN_NT-5.1/gcc 3.4.4)
FUNCPTR_DIGITINBYTE = 2
FUNCPTR_STRSIZE     = 10
----
%p      => 0x40118b
fptostr => 0x0040118b
----
%p      => 0x401310
fptostr => 0x00401310
----
%p      => 0x401050
fptostr => 0x00401050
実行例(i686/Windows XP/Visual Studio 2005)
FUNCPTR_DIGITINBYTE = 2
FUNCPTR_STRSIZE     = 10
----
%p      => 00401160
fptostr => 0x00401160
----
%p      => 00401219
fptostr => 0x00401219
----
%p      => 00401000
fptostr => 0x00401000

*1:ミドルエンディアンってどういう利点があるんだろう…?