HTML 4.01 StrictでCSSが反映されない

今回の内容は、Webに携わっている人の中で0.01%に関係あるかどうかわからないほど、ニッチな話題です。

ちょっと特殊な環境でHTMLを書いていたのですが、HTML 4.01 StrictのDOCTYPE宣言を書くと外部CSSが適用されないという状況に陥りました。
IE 6では適用されるのですが、FirefoxOpera(手元にあったブラウザ)では適用されませんでした。

ちなみに、書いたHTML/CSSは次のようなものです。

main.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
 "http://www.w3.org/TR/html4/strict.dtd">
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Style-Type" content="text/css">
<link rel="stylesheet" href="style.css" type="text/css">
<title>うまくいかないよ</title>
</head>
<body>
<h1>見出し!</h1>
<p>
本文!
</p>
</body>
</html>

style.css

@charset "utf-8";
body {
  color: red;
}

CSSが適用されれば全文が赤くなる。
それだけです。

しかしこれが、適用されない。
ファイルの配置に失敗しているわけでもなく、Firefoxでソースを表示して、style.cssのリンクになったところをクリックしたりすると、内容を見られます。

さて、原因ですがstyle.cssのContent-Typeが誤ってtext/htmlになっていたというものでした。
このContent-TypeはHTTPレスポンスのヘッダ情報です。

この問題はApacheとかIISとか、ちゃんとしたWebサーバを使っていれば絶対に起き得ないものですが、相当古い or 特殊なものを使っていると、困る可能性があります。

私の場合はちょっと特殊な環境で、自前で開発したものを使っていたため、このような現象に悩まされました。

そこで、拡張子で判断を行い、CSSファイルに対してはContent-Typeにtext/cssを適切に設定してあげるようにしたところ、きちんとCSSが適用されるようになりました。

今回の問題の解析過程です。

1. HTML 4.01 Strictの場合だけ発生するが、文法的にあやしいところはない。
2. ローカルで試したらうまくいった。(早く気付けよー)
3. Wiresharkでパケットを見ると、CSSファイルのレスポンスヘッダがおかしかった。

以上です。

冒頭にも書いたとおり、ほとんどの方には関係ない問題と思いますが、こういうこともある、という雑学として楽しんで頂けたなら幸いです。
同じ問題に直面して困った方の解決になれば、なおのことです。

分散共分散行列の違い

Rで書かれたとあるプログラムをOpenCV(C++ interface)に移植中なのですが、
分散共分散行列を求める2つの関数で出力される値が違うのに困惑していました。

OpenCVでは cv::calcCovarMatrix で、Rでは var です。

7 4 7
2 3 8
3 6 2

みたいな行列(値に意味は一切ありません)を与えたとき

cv::calcCovarMatrixでは、

4.666667 0.000000 1.000000
0.000000 1.555556 -3.222222
1.000000 -3.222222 6.888889

Rでは

7.000000 0.000000 1.500000
0.000000 2.333333 -4.833333
1.500000 -4.833333 10.333333

といった出力になっていました。
どうも係数(1.5)がかかっているようです。
しかしこれが常にそうなのか?というところが疑問で困っていたところだったのですが

Variance=\frac{\sum^n_{i=1}{(x_{i}-\bar{x})^2}}{n}

Unbiased Variance=\frac{\sum^n_{i=1}{(x_{i}-\bar{x})^2}}{n-1}

という標本分散と不偏分散の定義の違いだと気付きました。(すぐに気付けよというところですが。。。)

今回、Rの方が移植元なので

cv::calcCovarMatrix(data, vx, mean, CV_COVAR_NORMAL | CV_COVAR_ROWS | CV_COVAR_SCALE, CV_32F);
vx *= (double)data.cols / (data.cols - 1);

というふうにすることで対応できました。
C++ interfaceは便利ですね。

まぁ、数値そのものはおそらく重要でないので、標本分散でもいいのかもしれません。

std::vectorでハマった。

今日はC++で作業していたのですが、std::vectorでハマりました。

最初、次のようなコードを書いていました。(イメージです)

struct SomeStruct {
  int number;
  float array[2];
};

void function(std::vector<SomeStruct> &struct_list) {
  for (int i = 0; i < N; i++) {
    SomeStruct some_struct; // SomeStructを作って
    some_struct.number = i; // 値をいろいろ入れて
    some_struct.array[0] = (float)i / N;
    some_struct.array[1] = (float)N / (i + 1);
    struct_list.push_back(some_struct); // vectorに入れる
  }
}

しかし、これではstruct_listの内容がどうもおかしいということに気付きました。
なんというか、SomeStruct::arrayの中身が激しく壊れています。

なんだこれ、としばらく考えたあと、ちょっと検証を行って分かった事実が
SomeStructデストラクタが呼ばれているということでした。

よくよく考えてみればそれは当たり前で、ループ内のsome_structの寿命はループブロックの終わりまでです。
デストラクタが呼ばれるのも当然です。

当たり前のことでも、JavaとかC#とかの「基本的に参照で確保して、GCで回収」な言語を使っているとウッカリ忘れがちですね。

注意したいなと思った日でした。

あ、今回どのように修正したかというと、このように修正しました。
たぶんもっとスマートな方法があると思いますので、もしご存知でしたら教えていただけると幸いです。
(それこそスマートポインタの出番でしょうか?)

// ポインタを渡すようにした
// 解放は呼び出し側が責任をもって行う必要がある
void function(std::vector<SomeStruct*> &struct_list) {
  for (int i = 0; i < N; i++) {
    SomeStruct *some_struct = new SomeStruct();
    some_struct->number = i;
    some_struct->array[0] = (float)i / N;
    some_struct->array[1] = (float)N / (i + 1);
    struct_list.push_back(some_struct);
  }
}

Visual Studio 2010でsdfとipchの保存場所を変更する

Visual Studio 2010から、インクルードファイルを先読みすることによってインテリセンスを強化する仕組みが導入されました。

これまで補完が効かなかった部分でも補完が有効になり、大変便利なのですがそのために作られるデータベースが非常にでかいという問題があります。

特に、この問題はDropboxなどの容量に制限があるオンラインストレージを使っていたりすると大変です。
1プロジェクトあたり100MB程度(インクルードパスが通っているヘッダの数、インクルードするヘッダの数によると思いますが)がデータベースとして消費されることによって、簡単に容量が食いつぶされてしまいます。

そこで、この便利だけど困ったちゃんであるデータベース(sdf、ipch)をプロジェクトとは別のフォルダに追い出します。

今回の問題の対処には、次のサイト(Q&A)が参考になりました。

Why does Visual Studio 2010 create ipch folder and .sdf file? | wronso.com

まず、Visual Studioを開きます。

次に、メニューから「ツール」→「オプション」でオプション画面を開きます。

そして、「テキスト エディター」→「C/C++」→「詳細」と進むと、フォールバック位置という項目があります。

この「常にフォールバック位置を使用」をTrueに変更し、「フォールバック位置」に適当なフォルダ(D:\Visual_Studio_Fallback とか)を指定してやれば完了です。

これでえらい重いsdfやipchはここで指定したフォルダに保存されることになり、オンラインストレージの圧迫を防ぐことができます。

もちろんですが、この設定にしているとこれらのデータベースは同期されませんので注意してください。

openSUSEを入れてデュアルブート環境にしたらVistaでスリープ/休止状態に移行できなくなった


早速今週問題になっていたことをば。

私は家での作業PCにWindows Vistaを使っています。
そして興味本位でLinuxのひとつ、openSUSEのインストールを行いました。

インストールの際、nVidiaのドライバでいくつか問題が出ましたが、フェールセーフモードYaST2からドライバを指定してインストールしてやったりすることで解消できました。

…しかし、Vistaからスリープ(ハイブリッドスリープ)に移行することができなくなってしまいましたorz
休止状態についても同様です。

スリープについては前にも苦労したことがあったので、「あれ、設定はちゃんとしてるはずだけど…」という思いでした。

とりあえず、以下のことを試しました。

  • 電源オプションの確認とデバイスマネージャの確認
  • BIOSの更新と、設定の確認
  • Wakeupに関係しそうなUSB機器、LANケーブルの取り外し

しかし、問題は解決せず。
やはりデュアルブート環境自体が問題だなあ、と結論しました。

そういえば、openSUSEをインストールする際、ブートに利用するパーティションMBRから見えない可能性がある、みたいなことが書いてあったことを思い出しました。
んー、なるほど。
おそらく、スリープに移行する際にブートレコードへの書き込みができず、移行に失敗していたのだと思います。

そのため、泣く泣くブートセクタとMBRの復旧を行いました。

復旧はVistaのインストールディスクを用意して、下記の記事を参考に行いました。
MBRうっかり消しちゃって再作成が必要な事例 Windows7編 - Javaプログラマ ぬるぽの刑 -

その結果、無事ブートセクタが復旧し(=GRUBが削除され)無事にスリープができるようになりました。
こういった特殊事情にならないように、デュアルブート環境の構築時は気を付けないといけないですね。

はじめまして。

実はこのblogスペースは6年以上?前から持ってたのですが、長い時を経て有効活用してみようと思います。

基本的に三日坊主属性なので、定期的な更新とかは最初から考えずにぶらぶらやっていこうと考えています。

それでは、よろしくお願いします。