5.29.2011

C++: Convert array to vector

C++: 配列からvectorへの変換

Top Coder のプラグインで使われているテクニックの応用。
空の配列には対応していない。

   1: #include <vector>
   2: #define VECTOR(a) VECTOR_((a), sizeof(a) / sizeof(a[0]))
   3: template <typename T>
   4: std::vector<T> VECTOR_(T *array, std::size_t size) {
   5:   return std::vector<T>(array, array + size);
   6: }
・使用例
   1: int x[] = {1, 2, 3, 4, 5};
   2: std::string y[] = {"aa", "bb", "cc"};
   3:  
   4: std::vector<int> vx = VECTOR(x);
   5: std::vector<std::string> vy = VECTOR(y);
   6:  
   7: std::cout << vx[2] << vy[2] << std::endl;  // "3cc"

Windows: STOP error in NDIS.sys

Windows: NDIS.sys STOPエラー

Windows XP3 + 無線ドライバの相性の問題でブルースクリーン(DRIVER_IRQL_NOT_LESS_OR_EQUAL)が発生。

参考:
http://dynabook.com/assistpc/faq/pcdata/008137.htm
http://www.sacnoha.com/?p=702
http://www.whlgcy.com/2011/01/0x000000d1-ndissys.html

Available length of user password in Solaris

Solaris: ログインパスワードの有効文字数

Solaris におけるユーザのパスワードは、デフォルトでは 8文字以内でしか利用できない。
9文字以上のパスワードを設定しても、実際にチェックされるのは先頭8文字だけである。

・パスワード設定

   1: # passwd root
   2: 新しいパスワード: 「password1234」と入力
   3: 新しいパスワードを再入力してください: 「password1234」と入力
   4: passwd: root のパスワードが変更されました

・パスワード確認

   1: $ su -
   2: パスワード: 「password」と入力
   3: Sun Microsystems Inc.   SunOS 5.10      Generic January 2005
   4: # id
   5: uid=0(root) gid=0(root)

このように、su でも telnet でも ftp でも、先頭8文字さえわかればログインできてしまうのだ。

9文字以上のパスワードを正しく使えるようにするためには、パスワード暗号アルゴリズムを変更する必要がある。

まず、どのアルゴリズムが使用できるか、crypt.conf を確認する。
下記の例だと、「1」が「MD5」となっていることがわかる。 (2a: Blowfish, md5: Sun MD5, 5: sha256, 6: sha512)

・/etc/security/crypt.conf

   1: # cat /etc/security/crypt.conf
   2: #
   3: # Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
   4: # Use is subject to license terms.
   5: #
   6: #ident  "@(#)crypt.conf 1.2     08/05/14 SMI"
   7: #
   8: # The algorithm name __unix__ is reserved.
   9:  
  10: 1       crypt_bsdmd5.so.1
  11: 2a      crypt_bsdbf.so.1
  12: md5     crypt_sunmd5.so.1
  13: 5       crypt_sha256.so.1
  14: 6       crypt_sha512.so.1

そして、policy.conf を編集する。

・/etc/security/policy.conf

CRYPT_DEFAULT=__unix__

  ↓

CRYPT_DEFAULT=1

この段階ではまだ、既存のパスワードは古い暗号化のままなので、パスワードを再設定する。

   1: # grep root /etc/shadow
   2: root:K6pbRTjC7L0A6:15122::::::
   3: # passwd root
   4: 新しいパスワード:「password1234」と入力
   5: 新しいパスワードを再入力してください:「password1234」と入力
   6: passwd: root のパスワードが変更されました
   7: # grep root /etc/shadow
   8: root:$1$z6atQD7B$3P25WD9Y/TC8ThO7l9u8D.:15122::::::

/etc/shadow を見ると暗号化アルゴリズムが変わり、セキュリティが強化されたことがわかる。

最後に、先頭8文字だけではログインできないことを確認。

   1: $ su -
   2: パスワード: 「password」と入力
   3: su: Sorry

 

参考:
http://pooh.gr.jp/?p=841
http://d.hatena.ne.jp/matoken/20090129/1233239258

5.26.2011

Note for introducing Firefox

Firefox 初期セットアップ覚え書き

Google Chrome に見切りをつけようかと考えている今日のこの頃。

1. まず導入するアドオン

 ・AutoPager
 https://addons.mozilla.org/ja/firefox/addon/autopager/
 nクリックを1クリックにすると商売になる。1クリックを0クリックにすると、発明となる。

 ・FireGestures
 https://addons.mozilla.org/ja/firefox/addon/firegestures/
 「戻る」、「上の階層へ移動」といったオペレーションを、マウスジェスチャーのみで実現できる。

 ・Speed Dial
 https://addons.mozilla.org/ja/firefox/addon/speed-dial/
 ブックマークの進化系。ページのイメージがサムネールで表示され、1クリックで目的のページにアクセスできる。

 ・テキストリンク
 https://addons.mozilla.org/ja/firefox/addon/text-link/
 リンクになっていないURI文字列をダブルクリックで開けるようにする。

2. about:config 設定

 URLに「about:config」と入力すると、Firefoxの詳細なパラメータを変更できる。

 ・browser.search.openintab false => true
 検索バーを使用したとき、常に新しいタブで開く。Alt+Enterを押せば、同じタブで開く。

 ・mousewheel.withnokey.numlines 6 => 8
  mousewheel.withnokey.sysnumlines true => false
 マウスホイールの移動量を増やす。

 ・browser.tabs.closeWindowWithLastTab true => false
 最後のタブを閉じたときに、ウィンドウごと閉じられてしまうのを防ぐ。

 ・network.http.pipelining false => true
  network.http.pipelining.maxrequests 4 => 8
  network.http.proxy.pipelining false => true
 パイプライン処理(一度に多数のHTTPリクエストを送りつける)を行うことで、ブラウジングを高速化する。

 ・[新規] nglayout.initialpaint.delay 0 (整数値)
 描画開始までの待ち時間を無くして、さらに高速化。

参考:
http://www.mozilla.org/projects/netlib/http/pipelining-faq.html

5.24.2011

How to find slow SQL in Oracle

Oracle: 時間のかかるSQLを調べる方法

何かOracleの挙動がおかしいが、どのSQLに問題があるのか分からない。
そんなとき、SQL*Plusを使って調査する方法の一例。

※この記事は Oracle 10g について記載しています。9i 以前では一部コマンドが正しく動作しませんのでご注意ください。

ライブラリ・キャッシュ内に残っているSQLは、
動的パフォーマンスビュー「v$sql」を参照することで直近の状態を把捉できる。

1. 事象の発生した時間が特定できる場合

 最後にアクティブになった時刻「last_active_time」を「to_char」で文字列に変換し、
 それを比較することでレコードを抽出する。

 ①件数のカウント

  例1) 最後にアクティブになった時刻が「2011/5/24 19:31:00~19:31:59」のSQLをカウント

   1: select count(*)
   2:   from v$sql
   3:  where to_char(last_active_time, 'yyyymmddhh24mi') = '201105241931';

  例2) 最後にアクティブになった時刻が「2011/5/24 19:31:20~19:31:29」のSQLをカウント
  (like で文字列を比較することで、10秒の範囲を抽出できる)
   1: select count(*)
   2:   from v$sql
   3:  where to_char(last_active_time, 'yyyymmddhh24miss') like '2011052419312%';

 

 ②SQL情報の取り出し

  例3) 最後にアクティブになった時刻が「2011/5/24 19:31:00~19:31:59」のSQLを調べる

   1: select to_char(last_active_time, 'yyyy/mm/dd hh24:mi:ss'),
   2:        sql_id,
   3:        hash_value,
   4:        sql_text,
   5:        round(cpu_time/1000000,2),
   6:        round(elapsed_time/1000000,2),
   7:        executions,
   8:        buffer_gets,
   9:        disk_reads
  10:   from v$sql
  11:  where to_char(last_active_time, 'yyyymmddhh24mi') = '201105241931';

  出力結果は、順に
   (1) 最後にアクティブになった時刻
   (2) SQL ID
   (3) ハッシュ値  ※SQL IDとともに実行計画などの更なる調査に利用
   (4) SQL文       ※長いSQLの場合は全文が表示されないことがある => その場合は 「sql_fulltext」を参照
   (5) 累計のCPU時間(秒)    ※単位を「マイクロ秒」から「秒」に変換するために10の6乗で割り算を行い、
   (6) 累計の経過時間(秒)     さらに小数点以下の丸めを行っている
   (7) 実行回数
   (8) 累計のバッファ取得回数    ※1回に取得するサイズは、初期パラメータのブロックサイズと同じ
   (9) 累計のディスク読み込み回数
  となる。

 

2. 一回あたりの経過時間が長いSQLを抽出する

 「elapsed_time / executions / 1000000」で1回あたりの経過時間(秒)を算出することができる。
 ゼロ除算を防ぐため、「executions > 0」という条件は必須。

 ①件数のカウント

  例4) 1回あたり60秒以上かかったSQLをカウント

   1: select count(*)
   2:   from v$sql
   3:  where executions > 0
   4:    and elapsed_time/executions/1000000 >= 60;

 ②SQL情報の取り出し

  例5) 1回あたり60秒以上かかったSQLを調べる

   1: select to_char(last_active_time, 'yyyy/mm/dd hh24:mi:ss'),
   2:        sql_id,
   3:        hash_value,
   4:        sql_text,
   5:        round(cpu_time/1000000,2),
   6:        round(elapsed_time/1000000,2),
   7:        executions,
   8:        buffer_gets,
   9:        disk_reads
  10:   from v$sql
  11:  where executions > 0
  12:    and elapsed_time/executions/1000000 >= 60;

参考:
http://otndnld.oracle.co.jp/document/products/oracle10g/102/doc_cd/server.102/B19228-04/dynviews_2.htm

5.22.2011

Python unit testing

Python: ユニットテストの実行

このページ(Dive Into Python)が分かりやすかった。
http://diveintopython3-ja.rdy.jp/unit-testing.html

Pythonでは、テスト駆動開発(TDD/Test-Driven Development)に必要なツールが標準で用意されている。

以下の手順で実行。

・unittest モジュールをインポート
・「unittest.TestCase」を継承するクラスを作成
・「test」で始まる名前のクラスメソッドを作成
・そのメソッドの中でテストしたい処理を実行 ⇒ 例外が発生せずメソッドが完了すれば、テストOKとなる
・同値性の確認:self.assertEqual(first, second)
・特定の例外が発生することの確認:self.assertRaises(excClass)
  ⇒ with ステートメントを使うと非常にスマートなコーディングができる。
・unittest.main() を実行

以上を踏まえ、将棋の駒クラスのユニットテストを実装。

・test_piece.py

#!/usr/bin/python2.7
# Copyright (c) 2011 Mog Project. All rights reserved.
from shogi.piece import Piece
from shogi.piece import PieceError
import unittest

class Test(unittest.TestCase):
  # csa, owner, type, origin, reverse, promote
  all_pieces = (
      (None, ' ', '* ', ' * ', ' * ', None),
      (' * ', ' ', '* ', ' * ', ' * ', None),
      (' XX', ' ', '* ', ' * ', ' * ', None),
      ('+FU', '+', 'FU', '+FU', '-FU', '+TO'),
      ('+KY', '+', 'KY', '+KY', '-KY', '+NY'),
      ('+KE', '+', 'KE', '+KE', '-KE', '+NK'),
      ('+GI', '+', 'GI', '+GI', '-GI', '+NG'),
      ('+KI', '+', 'KI', '+KI', '-KI', None),
      ('+KA', '+', 'KA', '+KA', '-KA', '+UM'),
      ('+HI', '+', 'HI', '+HI', '-HI', '+RY'),
      ('+OU', '+', 'OU', '+OU', '-OU', None),
      ('+TO', '+', 'TO', '+FU', '-TO', None),
      ('+NY', '+', 'NY', '+KY', '-NY', None),
      ('+NK', '+', 'NK', '+KE', '-NK', None),
      ('+NG', '+', 'NG', '+GI', '-NG', None),
      ('+UM', '+', 'UM', '+KA', '-UM', None),
      ('+RY', '+', 'RY', '+HI', '-RY', None),
      ('-FU', '-', 'FU', '-FU', '+FU', '-TO'),
      ('-KY', '-', 'KY', '-KY', '+KY', '-NY'),
      ('-KE', '-', 'KE', '-KE', '+KE', '-NK'),
      ('-GI', '-', 'GI', '-GI', '+GI', '-NG'),
      ('-KI', '-', 'KI', '-KI', '+KI', None),
      ('-KA', '-', 'KA', '-KA', '+KA', '-UM'),
      ('-HI', '-', 'HI', '-HI', '+HI', '-RY'),
      ('-OU', '-', 'OU', '-OU', '+OU', None),
      ('-TO', '-', 'TO', '-FU', '+TO', None),
      ('-NY', '-', 'NY', '-KY', '+NY', None),
      ('-NK', '-', 'NK', '-KE', '+NK', None),
      ('-NG', '-', 'NG', '-GI', '+NG', None),
      ('-UM', '-', 'UM', '-KA', '+UM', None),
      ('-RY', '-', 'RY', '-HI', '+RY', None),
      )

  def test_all(self):
    print '[All pieces]'
    for csa, owner, type_, origin, reverse, promote in self.all_pieces:
      print csa, owner, type_, origin, reverse, promote
      p = Piece() if not csa else Piece(csa)
      self.assertEqual(str(p), '%s%s' % (owner, type_))
      self.assertEqual(repr(p), "Piece('%s%s')" % (owner, type_))
      self.assertEqual(p.owner(), owner)
      self.assertEqual(p.type_(), type_)
      self.assertEqual(p.origin(), Piece(origin))
      self.assertEqual(p.reverse(), Piece(reverse))
      self.assertEqual(p.is_promotable(), promote != None)
      if promote:
        self.assertEqual(p.promote(), Piece(promote))

  def test_initialize_error(self):
    print '[Initialize errors]'
    for csa in ('', ' ', '-', 'SPAM', '=FU', '+Fu', 0):
      with self.assertRaises(PieceError) as cm:
        Piece(csa)
      print cm.exception

  def test_modify_error(self):
    print '[Modify error]'
    with self.assertRaises(TypeError) as cm:
      x = Piece('+FU')
      x.csa = '-FU'
    print cm.exception

  def test_delete_error(self):
    print '[Delete error]'
    with self.assertRaises(TypeError) as cm:
      x = Piece('+FU')
      del x.csa
    print cm.exception

  def test_promote_error(self):
    print '[Promote errors]'
    for x in (None, '+', '-'):
      for y in ('OU', 'KI', 'TO', 'NY', 'NK', 'NG', 'UM', 'RY'):
        with self.assertRaises(PieceError) as cm:
          if not x:
            Piece().promote()
          else:
            Piece(x + y).promote()
        print cm.exception
        if not x: break


if __name__ == "__main__":
  unittest.main()


・出力結果(Eclipse + Pydev で実行)

pydev debugger: warning: psyco not available for speedups (the debugger will still work correctly, but a bit slower)
pydev debugger: starting
Finding files... done.
Importing test modules ... done.

[All pieces]
None   *   *   *  None
*    *   *   *  None
XX   *   *   *  None
+FU + FU +FU -FU +TO
+KY + KY +KY -KY +NY
+KE + KE +KE -KE +NK
+GI + GI +GI -GI +NG
+KI + KI +KI -KI None
+KA + KA +KA -KA +UM
+HI + HI +HI -HI +RY
+OU + OU +OU -OU None
+TO + TO +FU -TO None
+NY + NY +KY -NY None
+NK + NK +KE -NK None
+NG + NG +GI -NG None
+UM + UM +KA -UM None
+RY + RY +HI -RY None
-FU - FU -FU +FU -TO
-KY - KY -KY +KY -NY
-KE - KE -KE +KE -NK
-GI - GI -GI +GI -NG
-KI - KI -KI +KI None
-KA - KA -KA +KA -UM
-HI - HI -HI +HI -RY
-OU - OU -OU +OU None
-TO - TO -FU +TO None
-NY - NY -KY +NY None
-NK - NK -KE +NK None
-NG - NG -GI +NG None
-UM - UM -KA +UM None
-RY - RY -HI +RY None
[Delete error]
piece object is read-only
[Initialize errors]
piece type error ('')
piece type error (' ')
piece type error ('-')
piece type error ('SPAM')
piece type error ('=FU')
piece type error ('+Fu')
piece type error (0)
[Modify error]
piece object is read-only
[Promote errors]
unpromotable piece ( * )
unpromotable piece (+OU)
unpromotable piece (+KI)
unpromotable piece (+TO)
unpromotable piece (+NY)
unpromotable piece (+NK)
unpromotable piece (+NG)
unpromotable piece (+UM)
unpromotable piece (+RY)
unpromotable piece (-OU)
unpromotable piece (-KI)
unpromotable piece (-TO)
unpromotable piece (-NY)
unpromotable piece (-NK)
unpromotable piece (-NG)
unpromotable piece (-UM)
unpromotable piece (-RY)
----------------------------------------------------------------------
Ran 5 tests in 0.058s

OK

5.15.2011

Python: TypeError: unhashable type

将棋の駒として、手番+駒の種類を保持するクラスを作る。
そして、そのクラスのインスタンスを持ち駒の数を保持するディクショナリのキーとして使ってみる。

まず単純にクラスを作っただけでは、ディクショナリそのものが正しく動作しない。(KeyError が発生)
これは比較処理においてインスタンスのアドレスが利用されるため。
同じ駒であっても、インスタンスを作るたびにアドレスが変わってしまうため、Key が不定となってしまう。

そこで演算子オーバーロードで「__eq__」、「__ne__」をカスタマイズすると、今度は「unhashable type」エラーが
発生する。
ディクショナリのキーにはハッシュ関数の適用が必須であるためである。

演算子オーバーロードで「__hash__」をカスタマイズ。
これで問題ないかと思ったが、クラスが変更可能なオブジェクトを定義している場合には「__hash__」を定義しては
いけないらしい。ディクショナリの実装においてハッシュ値が変更不能であることが要求されているためで、
オブジェクトのハッシュ値が変化すると、キーが誤ったハッシュバケツに入っていることになってしまうとのこと。
ごもっともな話だ。

最終的に、クラスを文字列やタプルのような immutable な設計にすることとした。
プロトタイピングは以下のような形。

_TURNS = frozenset(['+', '-'])
_PIECE_TYPES = frozenset([
    '* ', 'FU', 'KY', 'KE', 'GI', 'KI', 'KA', 'HI',
    'OU', 'TO', 'NY', 'NK', 'NG', 'UM', 'RY'
    ])
_PIECE_HANDS = frozenset(['FU', 'KY', 'KE', 'GI', 'KI', 'KA', 'HI'])
_PIECE_PROMOTE = {
    'FU':'TO', 'KY':'NY', 'KE':'NK', 'GI':'NG', 'KA':'UM', 'HI':'RY'
    }
_NULL_PIECE = ' * '

class PieceError(Exception): pass

class Piece(object):
  """Manages owner and type of the piece.
  This is an immutable class.
  """
  _mutable = False
  def __init__(self, csa=' * '):
    self._mutable = True
    self.csa = csa
    self._mutable = False

  def __setattr__(self, name, value):
    if self._mutable or name == '_mutable':
      super(Piece, self).__setattr__(name, value)
    else:
      raise TypeError("Can't modify immutable instance")
  def __delattr__(self, name):
    raise TypeError("Can't modify immutable instance")

  def __str__(self):
    return self.csa
  def __repr__(self):
    return 'Piece(%s)' % self.csa
  def __eq__(self, other):
    return self.csa == other.csa
  def __ne__(self, other):
    return self.csa != other.csa
  def __hash__(self):
    return self.csa.__hash__()

  def owner(self):
    return self.csa[0]
  def type_(self):
    return self.csa[1:]
  def promote(self):
    if not self.type_() in _PIECE_PROMOTE.keys():
      raise PieceError('Unpromotable piece (%s)' % self.csa)
    return Piece(self.owner() + _PIECE_PROMOTE[self.type_()])
  def demote(self):
    pass  # now thinking...

参考:
・Python リファレンスマニュアル
http://www.python.jp/doc/2.5/ref/customization.html
・Immutable object
http://code.activestate.com/recipes/577207-immutable-objectsubclass/