ちょっとややこしいdocument、window、screenの話

jQueryで画面の高さを取得する時、取得方法がいろいろあって
どれを使うべきか悩むことがあります。
主に

  • $(document).height()
  • $(window).height()
  • screen.height
  • screen.availHeight

これらはそれぞれ

$(document).height(): 読み込んだページの全高さ
$(window).height(): ブラウザ中のスクロール部分の高さ
screen.height: デバイスの画面のサイズ
screen.availHeight: デバイスの画面サイズからOSのメニューバーやタスクバーを引いた高さ

なので、
$(document).height() > $(window).height()のときに、すべてを表示しようとすると、画面のスクロールが必要となります。

$(window).height()はブラウザのディベロッパーツールを表示したり、ブラウザのツールバーを表示するとサイズが小さくなります。


参照元

javascript - Difference between screen.availHeight and window.height() - Stack Overflow

Ruby拡張ライブラリをデバッグする

静的リンクもしくは動的リンクでデバッグする方法があるようです。

今回は動的リンクでやってみました。
題材はpcaprubというRubyからpcapファイルを使うためのライブラリです。
ライブラリを使うa.rbから、test.pcapファイルを読み込むためにpcaprubを使います。

デバッグシンボルはあったほうがデバッグしやすいので、
拡張ライブラリを-gつきでコンパイルしておきます

gdbを起動します

$ gdb ruby 

とりあえずmainにブレークポイントをはって、起動します

(gdb) b main
(gdb) r a.rb test.pcap

Ruby は dln_loadでライブラリを読み込むようです
そこにもブレークポイントをはって、実行を再開します

(gdb) b dln_load
(gdb) c

ライブラリのロード部分でブレークします
encdb.soが読み込まれました

Breakpoint 2, dln_load (file=0x737400 "/home/yu74n/.../enc/encdb.so") at dln.c:1250

確認してみましょう*1

(gdb) i sharedlibrary
From                To                  Syms Read   Shared Object Library
(*snip*)
0x00007ffff619b680  0x00007ffff619c2b8  Yes         /home/yu74n/.../enc/encdb.so

デバッグしたい拡張ライブラリが現れるまでスキップします

(gdb) c
Continuing.

Breakpoint 2, dln_load (file=0x8a9b90 "/home/yu74n/.../pcaprub.so") at dln.c:1250

現れたので確認してみます

(gdb) i sharedlibrary
0x00007ffff5d918c0  0x00007ffff5d94058  Yes         /home/yu74n/.../pcaprub.so

ありましたね

あとはデバッグしたい場所にブレークポイントをはると
ブレークします

(gdb) b rbpcap_next_packet
Breakpoint 3 at 0x7ffff5d92520: file pcaprub.c, line 802.
(gdb) c
Continuing.

Breakpoint 3, rbpcap_next_packet (self=8914880) at pcaprub.c:802
warning: Source file is more recent than executable.
802	{	

ソースを見てみます

(gdb) l
797	* If the next_packet() is unsuccessful, Null is returned.
798	*/
799	
800	static VALUE
801	rbpcap_next_packet(VALUE self)
802	{	
803		rbpcap_t *rbp;
804		rbpcapjob_t job;
805		char eb[PCAP_ERRBUF_SIZE];
806		int ret;	

*1:ブレークしてしばらくnextで進んだ後に実行してください

mongo shellから検索クエリはわかるけど、Rubyドライバでの書き方がわからんときの解決法

BSONなので、BSON経由で変換すればいい話ですね。
例えば、下のようなMongoDBドキュメントがあったとします。

{
        "_id" : ObjectId("51b6f5414eba1e94ba5bf762"),
        "info" : {
                "category" : "file",
                "started" : "2013-06-11 18:59:52",
                "ended" : "2013-06-11 19:00:48",
                "version" : "0.5",
                "duration" : "55 seconds",
                "id" : 3921
        }
}

info.startedは開始日時を表しており、これを使ってフィルタをかけたいとします。
mongo shell で書くとこんな感じです。

{ "info.started": {$gte: "2013-06-10",$lt: "2013-06-11"}}

当たり前ですが
Rubyドライバで以下のようにすると、データ量にもよりますが死ぬほど時間がかかります。

coll.find().each do |doc|
  # ここでフィルタ
end

find()の第1引数でフィルタをかけるべきですが、複雑なMongoDBドキュメントになればなるほど、
どういうふうに書けばいいかわからなくなります。
ドキュメントには基本的な構文しか載っていません。

MongoDBの検索クエリはBSON形式なので、mongo shellで書いた検索クエリをBSON形式に変換し、
Rubyドライバでデシリアライズすればよさそうです。

mongo shellはJavaScriptなので、JS用のドライバで検索クエリをシリアライズします。
MongoDBにはjs-bsonというライブラリがついていて、ブラウザからも使えます。

js-bson
https://github.com/mongodb/js-bson


browser_build/bson.jsを適当な場所に配置して、同じフォルダに以下のファイルを置きます。
js-bsonのREADMEに書いてあったものを持ってきて、コンソール出力するように修正しただけです。

<head>
  <script src="./bson.js">
  </script>
</head>
<body onload="start();">
<script>
  function start() {
    var BSON = bson().BSON;
    var Long = bson().Long;

    var doc = {//ここに検索クエリを書く}
    // 例えばこんな感じ
    // var doc = {"info.started": {$gte: "2013-06-10",$lt: "2013-06-11"}}

    var data = BSON.serialize(doc, false, true, false);
    console.log(data)
        
  }
</script>
</body>

これでBSON形式の検索クエリがブラウザのコンソールに出力されます。
ChromeであればF12キーを押して、consoleタブに移動するだけです。

BSON形式のバイナリは10進数の配列で表示されます。
16進数でRubyでデシリアライズできる形式に変更したいので、Rubyで成型します。

require 'bson'
# ブラウザに表示された配列をコピーしてirbの変数に代入します。
bson = [65, 0, 0, 0, 3, 105, 110, 102, 111, 46, 115, 116, 97, 114, 116, 101, 100, 0, 46, 0, 0, 0, 2, 36, 103, 116, 101, 0, 11, 0, 0, 0, 50, 48, 49, 51, 45, 48, 54, 45, 49, 48, 0, 2, 36, 108, 116, 0, 11, 0, 0, 0, 50, 48, 49, 51, 45, 48, 54, 45, 49, 49, 0, 0, 0]
# 16進数に変換します
hex = bson.map {|x| "%02X" % x}
# 結合します
msg << hex.join
# Rubyのバイナリ形式に変換します
bin = msg.pack("H*")
# BSON形式をデシリアライズします
BSON.deserialize(bin.unpack("C*"))
# => {"info.started"=>{"$gte"=>"2013-06-10", "$lt"=>"2013-06-11"}}

あとはこの検索クエリをRubyドライバから使うだけです。

*nix系OSの起動時のデーモン(サービス)起動について

はじめに

デーモンとして起動するmongodbのオプションを追加/変更したかったのだけど、
*nix弱者で、*nix系OSの起動時の仕組みがよくわかっていないので、メモしておきます。

結論

textSearchEnabledを設定ファイルに書けって話ですね。

結論としては/etc/init/mongodb.confのstart-stop-daemonの--execの部分を変更すればいいってとこに落ち着いたけど、あってるかは不明。

# Text Searchを有効にするなら
if [ "x$ENABLE_MONGODB" = "xyes" ]; then exec start-stop-daemon \
--start --quiet --chuid mongodb --exec  /usr/bin/mongod -- \
--setParameter textSearchEnabled=true --config /etc/mongodb.conf; fi

init.d

起動時にOSがごにょごにょして/etc/init.dの下にあるスクリプトが実行されるようです。
スクリプトを見てみます。

ちなみにmongodbのスクリプトを見てみます。

...
INITSCRIPT="$(basename "$0")"
JOB="${INITSCRIPT%.sh}"
...

$(basename "$0")はコマンド置換ですね。
$0は位置パラメータという組み込み変数でスクリプト名に置換されます。

# INITSCRIPT="$(basename "$0")" は
# INITSCRIPT="$(basename "/etc/init.d/mongodb")" になり
# INITSCRIPT="mongodb" になる
INITSCRIPT="$(basename "$0")"

${}はパターン照合演算子というやつで
${val#pattern}はvalの先頭からpatternに一致した最も短い部分を削除し、残りを返す
${val%pattern}はvalの末尾からpatternに一致した最も短い部分を削除し、残りを返す

# JOB="${INITSCRIPT%.sh}" は
# 末尾に.shがあれば、それを削除して残りの部分を返す

起動の部分がみたいので、startの所を見てみる。

# $COMMAND には/etc/init.d/mongodb start でいうstartがはいり
# $JOB にはmongodbが入る
# start mongodb が実行される
$COMMAND "$JOB"

startっていうコマンドがあるらしい。
man startをしてみるとinitctl(8)が表示された。
/sbin/startはinitctlへのシンボリックリンク

file `which start`

UpStart

これはUpStartっていうらしい

# /etc/init.d/mongodb はupstart-jobへのシンボリックリンク
/etc/init.d/mongodb -> /lib/init/upstart-job

んで、UpStartの設定として、ジョブ定義というものがあるらしい
ubuntuの場合は/etc/init/mongodb.confになる
その中にscript 〜 script endと書くことでシェルスクリプトをそのまま書けるらしい

script
  ENABLE_MONGODB="yes"
  if [ -f /etc/default/mongodb ]; then . /etc/default/mongodb; fi
  if [ "x$ENABLE_MONGODB" = "xyes" ]; then exec start-stop-daemon \
--start --quiet --chuid mongodb --exec  /usr/bin/mongod -- \
--config /etc/mongodb.conf; fi
end script

ENABLE_MONGODB="yes"は意味がわからなかった。
/etc/defaultは追加設定を置いておく場所らしい。
その後、start-stop-daemonが実行される。これはプログラムを簡単にデーモン化するものらしい。

ubuntuでLauncher起動のショートカットキーを変更する

備忘です。

ubuntuホスト上でWindowsゲストを動かすとき、Superキー(Windowsキー)にLauncherの起動が割り当てられていると何かと不便なため、他のキーに割り当てたくなります。

# ファイル名を指定して実行(Win+R)のときにLauncherが起動して不便というのが一番大きい

結論からいうとCan I define keyboard shortcuts using the Super key?に解決方法は書いてあるのですが、alt+f2からabout::configとしてもなにも起こらなかったので、自分用にめもっておきます。

compizconfig-settings-manager パッケージのインストール

sudo apt-get install compizconfig-settings-manager

を実行

CompizConfig設定マネージャーの起動

Launcherを起動してComと入力すると「CompizConfig設定マネージャー」が見つかるので起動する。

キーの変更

CompizConfig設定マネージャーのデスクトップ項目にあるUbuntu Unity Pluginを選択し、Behaviourタブの「Key to show the launcher」を変更したいキーに設定する。

WDKドライバ開発 - Visual Studio の設定

おことわり

こういう自分用めもは非公開にすべきなのですが
はてな Blog では記事ごとの公開/非公開設定ができないみたいなので、
最初に言っておきます
VC++をドライバ開発環境にするの自分用めもです。
参照元のサイトのほうが画像つきで丁寧なので、そちらを参照してもらったほうがよいです。

環境

  • Visual Studio 2010 (高価な専門ツールです)
  • Windows Driver Kit Version 7.1.0
  • ddkbuild_cmd 2009-11-28@04-38-36

下準備

  • WDKは入っている前提
  • 適当な場所(UACでとめられない場所が望ましい)に作業用ディレクトリを作成しとく(スペースとか全角文字とかは含まれないようにしとく)
  • DLしたddkbuild.cmdをwdkディレクトリの下に置く(まぁどこでもよいのだが)
  • ddkbuild.cmd の @echo off の下にビルドする環境に合わせて、以下のような設定を書いておく
@set W7BASE=C:\WinDDK\7600.16385.1 

プロジェクトの作成

新しいプロジェクトを作成からメイクファイル プロジェクトを選択する

ウィザードで値を設定する

ddkbuild.cmdの絶対パスはダブルクォートで囲まないこと
UACが有効ならユーザー権限でアクセスできる場所にプロジェクトを作成すること

  • ビルドコマンドライン
(ddkbuild.cmdの絶対パス) -W7 checked $(ProjectDir)
  • リビルドコマンドライン

一時ファイルを削除するように-cZをつける

(ddkbuild.cmdの絶対パス) -W7 checked $(ProjectDir) -cZ

リリースビルドの場合は checked の代わりに free をつける

デバッグビルド/リリースビルド

_X86_;DBG

そのほかのファイル

ソースファイルを.cファイルとして作成

ビルドするためなら、DriverEntryだけ書いておけば、とりあえず通る

#include <ntddk.h>
#include <wdm.h>

NTSTATUS DriverEntry( PDRIVER_OBJECT pDriverObject,
                      PUNICODE_STRING RegistryPath )
{
    DbgPrint("Hello World\n");
    return STATUS_SUCCESS;
}

makefile

MINIMUM_NT_TARGET_VERSION=$(_NT_TARGET_VERSION_VISTA)
!INCLUDE $(NTMAKEENV)\makefile.def

sources

TARGETNAME はプロジェクト名
TARGETTYPE はドライバ作成の場合はDRIVER
TARGETLIBS はドライバ作成で使うライブラリを書いておく
SOURCES はビルドするファイルを書いておく
USE_PDB はないと後(デバッグ時)から泣くことになるので入れておく

TARGETNAME=test
TARGETTYPE=DRIVER
TARGETLIBS=$(SDK_LIB_PATH)\advapi32.lib \
            $(SDK_LIB_PATH)\ntdll.lib \
            $(SDK_LIB_PATH)\kernel32.lib \
            $(DDK_LIB_PATH)\ntoskrnl.lib \
            $(DDK_LIB_PATH)\ndis.lib \

SOURCES=\
        driver.c       \

USE_PDB=1

makefileとsourcesファイルに.txt拡張子をつけないようにする

インテリセンスを有効にする

プロジェクトのプロパティを開き、NMAKE->インクルードの検索パスに(WDKのパス)\inc\ddkを追加する

ドライバのロード

わざわざローダを書くのが面倒な場合は
Driver Loader(OSR Online に登録が必要)を使いましょう
ただし Windows XP までしか対応していません

Windows XP 用にドライバを作成するには

  • ddkbuild.cmd の W7BASE を WXPBASE に変更する
  • ビルド/リビルドコマンドラインの -W7 を -WXP に変更する
  • makefile を MINIMUM_NT_TARGET_VERSION=$(_NT_TARGET_VERSION_WINXP) に変更する

ロードの確認

Sysinternals Suite の DbgView を使いましょう
メニューの Capture->Capture Kernel を有効にする