はてなのキーワードのバグ?

はてなダイアリープラスを使って、このブログ以外にもう1個ブログを書いています。

そこで、あるキーワードが、はてなのキーワードのページで、言及されているページの一覧から一見するとたどれるようになっているのですが、それが、このブログを指示しています。

副ブログは、はてなIDの後ろに+hogeという感じのものをつくのだが、どうも、+よりも後ろの部分が欠落しているようだ。


というわけで、はてなideaに登録しておきました。idea:27544

使い方がよくわからない。。。。。

さくらのレンサバで、example.co.jpをwww.example.co.jpにリダイレクトする方法

さくらのサーバー設定のドメイン設定で、
www.example.co.jp と example.co.jpを「wwwを付与せずマルチドメインとして使用する(上級者向け)」として用意しておく。

で、それぞれ公開するディレクトリを別にしておく。
たとえば、
www.example.co.jpは、~/www
example.co.jpは、^/www/redir/
としておく。

で、~/www/redir以下に.htaccessファイルをつくり1行書き加える。

Redirect 301 / http://www.example.co.jp/

でできあがり。

Pythonでベイジアンフィルターを実装してみた

久々にPythonアルゴリズムです。

Web+DB Vol56でPerlでかかれていた、ベイジアンフィルターをPythonで実装してみました。
ほぼ、本に忠実に実装しています。

恒例によって、結果の保存とかはしてません。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import MeCab
import math

class Bayesian(object):
    term_count = {}
    cat_count = {}

    def __init__(self):
        pass

    def MecabSpliter(self, text):
        m = MeCab.Tagger("-Ochasen")
        n = m.parseToNode(text.encode('utf-8'))
        words = {}
        while n.next is not None:
            if n.posid == 1 or n.posid == 2 or n.posid == 3 or n.posid == 4 or n
.posid == 5:
                words.setdefault(n.surface.lower(), 0)
                words[n.surface.lower()] += 1
            n = n.next
        return words

    def text2vec(self, text, spliter=None):
        if spliter is None:
            return self.MecabSpliter(text)
        else:
            return spliter(text)

    def train(self, wv, cat):
        for term, cnt in wv.iteritems():
            print term, cnt
            if not self.term_count.has_key(term):
                self.term_count[term] = {}
            if term in self.term_count[term]:
                self.term_count[term][cat] += cnt
            else:
                self.term_count[term][cat] = cnt 

            if term in self.cat_count:
                self.cat_count[cat] += 1
            else:
                self.cat_count[cat] = 1
    def catProb(self, cat):
        total = 0
        for k in self.cat_count:
            total += self.cat_count[k]
        return 1.0 * self.cat_count[cat] / total

    def termCnt(self, term, cat):
        if term in self.term_count:
            if cat in self.term_count[term]:
                return self.term_count[term][cat]
            else:
                return 0
        else:
            return 0

    def termProb(self, term, cat):
        return self.termCnt(term, cat) / self.cat_count[cat]

    def predict(self, vec):
        scores = {}
        for cat in self.cat_count:
            scores[cat] = self.score(vec, cat)
        return scores

    def score(self, vec, cat):
        print "tt", self.catProb(cat)
        cat_prob = math.log(self.catProb(cat) * 1.0)
        not_likely = 1.0 / (self.total_term_count() * 10)
        doc_prob = 0
        for term, count in vec.items():
            print term, count
            doc_prob += math.log(self.termProb(term, cat) or not_likely) * count
        return cat_prob + doc_prob

    def total_term_count(self):
        cnt = 0
        for k in self.cat_count:
            cnt += self.cat_count[k]
        return cnt

if __name__ == '__main__':
    filter = Bayesian()
    words = filter.text2vec(u'PerlやPythonはスクリプト言語です', filter.MecabSpl
iter)
    filter.train(words, "it")
    words = filter.text2vec(u'Perlでベイジアンフィルタを作りました。')
    filter.train(words, "it")
    words = filter.text2vec(u'pythonはニシキヘビ科の総称です。')
    filter.train(words, "science")

    words = filter.text2vec(u'Perlは楽しい')
    porb = filter.predict(words)
    print porb

    words = filter.text2vec(u'PythonとPerl')
    porb = filter.predict(words)
    print porb

    words = filter.text2vec(u'pythonはヘビ')
    porb = filter.predict(words)
    print porb

あと、雑誌に書いてあるとおりに設定されたMeCabが必要です。
apt-getで入れたものを使う場合、多少変更が必要です。

WEB+DB PRESS Vol.56

WEB+DB PRESS Vol.56

32bit Protect Mode

ようやく完全に32bitに移行できたので、その記録。

まずは、IPL。

.code16gcc

_start:
	JMP entry

	// for FAT12
	.byte   0x90
	.ascii  "HelloIpl"
	.word   512
	.byte   1
	.word   1
	.byte   2
	.word   224
	.word   2880
	.byte   0xf0
	.word   9
	.word   18
	.word   2
	.int    0
	.int    2880
	.byte   0,0,0x29
	.int    0xffffffff
	.ascii  "HELLO-OS   "
	.ascii  "FAT12   "
	.skip   18,0
	
entry:
	// レジスタの初期化
	movw	$0x0, %ax
	movw	%ax, %ss
	movw	%ax, %dx
	movw	%ax, %ds
	movw	%ax, %es

	// 0x7c00に読み込まれるので、SPを0x7c00にしないとアドレスの
	// 設定が煩雑になるため。
	movw  	$0x7c00, %sp

	// フロッピーディスクを読み込む
	// 読み込む先を設定する。
	movw	$0x0820, %ax
	movw	%ax, %es

	// シリンダ0 ヘッド0 セクタ2
	movb	$0x0, %ch
	movb	$0x0, %dh
	movb	$0x02, %cl

	//10シリンダ分読み込む
readloop:
	// エラーカウンター
	movw	$0x00, %si

retry:	
	//Disk読み出しのBIOSコール
	movb	$0x02, %ah
	movb	$0x01, %al
	movw	$0x00, %bx
	movb	$0x00, %dl
	int	$0x13
	jnc	next

	//エラー処理
	addw	$0x01, %si
	// retry5回でエラー終了
	cmp	$0x05, %si
	jae	error
	// ドライブを初期化
	mov	$0x00, %ah
	mov	$0x00, %dl
	jmp	retry

next:
	//格納場所のアドレスを0x0020進める
	movw	%es, %ax
	addw	$0x0020, %ax
	movw	%ax, %es
	
	add	$0x01, %cl
	cmp	$18, %cl
	jbe	readloop
	
	movb	$0x01, %cl
	addb	$0x01, %dh
	cmp	$0x02, %dh
	jb	readloop
	
	movb	$0x01, %dh
	add	$0x01, %ch
	cmpb	$10, %ch
	jb	readloop

	// カーネルイメージが、読み込まれている
	// アドレスにジャンプする
	jmp	0x00c200

fin:
	hlt
	jmp     fin

error:	
	movw	$err_msg, %si
	call	printstr
	jmp	fin
	
printstr:
	nop
putloop:
	// SIで指定された文字列を
	// 1文字ずつ取り出す。
	movb   	(%si), %al
	addw	$0x01, %si
	// NULL文字か比較
	cmpb 	$0x00, %al
	je      putloop_end
	// SystemCallの設定
	movb   	$0x0E, %ah
	movw	$0x0015, %bx
	int	$0x10
	jmp     putloop
putloop_end:
	ret
	
err_msg:
	.byte   0x0a,0x0a
	.ascii  "Disk Error\r\n"
	.byte	0x00

	.org    0x1fe
	.byte   0x55,0xaa

iplである程度、kernelに相当する部分をメモリ上に読み込んでおく。

        .code16
        .global _start

_start:
        // レジスタを初期化する                                                        
        movw    $0x00, %ax
        movw    %ax, %ds
        movw    %ax, %es
        movw    %ax, %ss
        // 32ビットモードを有効にするために                                            
        // PICをマスクする                                                             
        movb    $0xff, %al
        outb    %al, $0x21
        nop
        outb    %al, $0xa1

        // 割り込みフラグをクリア                                                      
        cli

        // A20Gateを有効にする。                                                       
        //割り込みを禁止する                                                           
        call    waitkbout
        movb    $0xd1, %al
        outb    %al, $0x64
        call    waitkbout
        movb    $0xdf, %al
        outb    %al, $0x60
        call    waitkbout

        .arch   i486
to_protect:
	// Protectモードにする                                                         
        lgdtl   (gtr0)
        movl    %cr0, %eax
	and     $0x7ffffff, %eax
        or      $0x0000001, %eax
        movl    %eax, %cr0
        jmp     pipelineflash

pipelineflash:
        movw    $0x8, %ax
        movw    %ax, %ds
        movw    %ax, %es
        movw    %ax, %fs
	movw    %ax, %gs
        movw    %ax, %ss

        // osmainを0x00280000にコピー                                                  
	movl    $osmain, %esi
        movl    $0x00280000, %edi
        movl    $512 * 1024 / 4, %ecx
        call    _memcpy

        jmp     $0x10, $0x00000001

_fin:
        hlt
        jmp     _fin
waitkbout:
        inb     $0x64, %al
        andb    $0x02, %al
        jnz     waitkbout
        ret

        // Memory Copy                                                                 
        // Source : esi                                                                
        // Destination: edi                                                            
        // Counter: ecx                                                                
_memcpy:
        movl    (%esi), %eax
        add     $4, %esi
        movl    %eax, (%edi)
        add     $4, %edi
        sub     $1, %ecx
        jnz     _memcpy

        ret

        .align  8
gdt0:
        // GlobalDescriptor Table                                                      
        // Null Selecter                                                               
        .skip   8, 0x00
        // 1st GDT                                                                     
        .word 0xffff, 0x0000, 0x9200, 0x00cf
        // 2nd GDT                                                                     
        .word 0xffff, 0x0000, 0x9a28, 0x0047
        // Last GDT                                                                    
        .word   0x0000
gtr0:
        .word   8 * 3 - 1
        .int    gdt0

osmain:
	nop
	hlt
	jmp	osmain

動作確認には、bochsを利用。

00442040000i[CPU0 ] CPU is in protected mode (halted)
00442040000i[CPU0 ] CS.d_b = 32 bit
00442040000i[CPU0 ] SS.d_b = 32 bit
00442040000i[CPU0 ] EFER   = 0x00000000
00442040000i[CPU0 ] | RAX=0000000000000000  RBX=0000000000000015
00442040000i[CPU0 ] | RCX=0000000000000000  RDX=0000000000000100
00442040000i[CPU0 ] | RSP=0000000000007c00  RBP=0000000000000000
00442040000i[CPU0 ] | RSI=000000000008c2a8  RDI=0000000000300000
00442040000i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00442040000i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00442040000i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00442040000i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00442040000i[CPU0 ] | IOPL=0 id vip vif ac vm rf nt of df if tf sf ZF af PF cf
00442040000i[CPU0 ] | SEG selector     base    limit G D
00442040000i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00442040000i[CPU0 ] |  CS:0010( 0002| 0|  0) 00280000 0007ffff 0 1
00442040000i[CPU0 ] |  DS:0008( 0001| 0|  0) 00000000 ffffffff 1 1
00442040000i[CPU0 ] |  SS:0008( 0001| 0|  0) 00000000 ffffffff 1 1
00442040000i[CPU0 ] |  ES:0008( 0001| 0|  0) 00000000 ffffffff 1 1
00442040000i[CPU0 ] |  FS:0008( 0001| 0|  0) 00000000 ffffffff 1 1
00442040000i[CPU0 ] |  GS:0008( 0001| 0|  0) 00000000 ffffffff 1 1

で、どこでハマっていたかというと、far jmpするところ。far jmpがうまくいかずにコードセグメントがなかなか32bitになってくれませんでした。

QEMUとGDBを使ったデバッグ

OSのデバッグ手法。

32bitモードに突入してしまうと、printfも簡単にはできなくなってしまいます。

そこで、GDBを使った、デバッグ

qemu -S -s -m32 -localtime -fda os.img &
で、起動して
$ gdb
(gdb) target remote localhost:1234
(gdb) set architecture i8086
(gdb) break *0x07c00
(gdb) c
こんな感じで、IPLからデバッグできます。

参考図書

30日でできる! OS自作入門

30日でできる! OS自作入門

GDBハンドブック

GDBハンドブック

画面モードの切り替えまで

画面をグラフィックモードにするところまで出来ました。

ipl.s

// kawas Initial Program Loader                                                             
// This program is going to be loaded at 0x7c00                                             

cyls = 10

base_address:
        .code16

        JMP entry

        // for FAT12                                                                        
        .byte   0x90
        .ascii  "HelloIpl"
        .word   512
        .byte   1
        .word   1
        .byte   2
        .word   224
        .word   2880
        .byte   0xf0
	.word   9
	.word   18
	.word   2
	.int    0
        .int    2880
        .byte   0,0,0x29
	.int    0xffffffff
        .ascii  "HELLO-OS   "
	.ascii  "FAT12   "
        .skip   18,0

entry:
        // Set Stack Segment to 0                                                           
	movw    $0, %ax
        movw    %ax, %ss

        movw    $0x7c00, %sp
        movw    %ax, %dx

        // Read the disk                                                                    
        movw    $0x0820, %ax
        movw    %ax, %es

        // set Sylinder 0 header 0 sector 2                                                 
        movb    $0, %ch
        movb    $0, %dh
        movb    $2, %cl

readloop:
        // clear error counter                                                              
	movw    $0, %si

retry:
        movb    $0x02, %ah
	movb    $1, %al
        movw    $0, %bx
        movb    $0x00, %dl
	int     $0x13
        jnc     next

        // add error counter                                                                
        add     $1, %si
        // if error counter is over 5, print error message                                  
	cmp     $5, %si
        jae     error

        movb    $0x00, %ah
        mov     $0x00, %dl
        int     $0x13
        jmp     retry

next:
        // 0x200 address is advanced.                                                       
        movw    %es, %ax
	add     $0x0020, %ax
	movw    %ax, %es
        add     $1, %cl
	cmp     $18, %cl
	jbe     readloop
        movb    $1, %cl
        add     $1, %dh
	cmp     $2, %dh
	jb      readloop
        movb    $0, %dh
        add     $1, %ch
        cmp     $cyls, %ch

        movw    $cyls, 0x0ff0

        // Jump to main program                                                             
        JB      readloop
        jmp     0xc200
fin:
        hlt
        jmp     fin

error:
      	movw    $0x00, %ax
	movw    %ax, %es
	movw    $msg, %si


putloop:
        movb    (%si), %al
	add     $0x01, %si
	cmpb    $0x00, %al
	je      fin
        movb    $0x0e, %ah
        movw    $0x0015, %bx
      	int     $0x10
        jmp     putloop

msg:
    	.byte   0x0a,0x0a
        .ascii  "load error"
        .byte   0x0a
        .byte   0x00

	.org    0x1fe
        .byte   0x55,0xaa

ipl.ls

OUTPUT_FORMAT(binary)

OUTPUT_ARCH(i386)

SECTIONS {
 . = 0x7c00;
 .text : { *(.text) }
}

main.s

// Set VGA to 320 x 200 x 8bit                                                      
	movb    $0x13, %al
	movb    $0x00, %ah
	int     $0x10

main.ls

OUTPUT_FORMAT(binary)

OUTPUT_ARCH(i386)

SECTIONS {
 . = 0xc200;
 .text : { *(.text) }
}

で、

as ipl.s -o ipl.o
as main.s -o main.o
ld ipl.o -T ipl.ls -o ipl.bin
ld main.o -T main.ls -o main.bin
mfotmat -f 1440 -C -B ipl.bin -i osimage.img ::
mcopy -i osimage.img  main.bin

こんな感じで。

レジスタのお勉強

とりあえず、自作OSにアセンブラを使うが、だいぶ、忘れてしまったので、復習をかねて。いまさらアセンブラかよ!

レジスタ
32ビット(DoubleWord)
EAX(アキュレータ(累積演算))
ECX(カウンタ)
EDX(データ)
EBX(ベース)
ESP(スタックポインタ)
EBP(ベースポインタ)
ESI(ソースインデックス)
EDI(ディストネーションインデックス)

16ビット(Word)
AX
CX
DX
BX
SP
BP
SI
DI

8ビット(Byte)
AL,AH
CL,CH
DL,DH
BL,BH

セグメントレジスタ
ES(エクストラセグメント)
CS(コードセグメント)
SS(スタックセグメント)
DS(データセグメント)
FS
GS