changeset 0:223b71206888

Initial import
author thib
date Fri, 01 Aug 2008 16:32:45 +0000
parents
children b753afeb3f34
files Makefile.in README aclocal.m4 autogen.sh clear_ipc config.guess config.h.in config.sub configure.in font/Makefile.in font/codeconv.cc font/codeconv.h font/codeconv_tbl.h font/font.h font/font_face.cc font/font_face.h font/font_layout.cc font/font_peer.h font/font_peer_fn.cc font/font_peer_ft2.cc font/font_peer_x11.cc font/text.h font/text_stream.cc install.sh linux.m4 music2/Makefile.in music2/koedec.cc music2/koedec_ogg.cc music2/movie.cc music2/music.cc music2/music.h music2/nwatowav.cc music2/wavfile.cc music2/wavfile.h scn2k/Makefile.in scn2k/gandump.cc scn2k/scn2k.h scn2k/scn2k_cmd.cc scn2k/scn2k_grp.cc scn2k/scn2k_impl.cc scn2k/scn2k_impl.h scn2k/scn2k_text.cc scn2k/scn2kdump.cc scn2k/test.cc system/Makefile.in system/file.cc system/file.h system/file_impl.h system/system_config.cc system/system_config.h system/visarc.cc window/Makefile.in window/SDL_rotozoom.cc window/SDL_rotozoom.h window/button.cc window/event.cc window/event.h window/menuitem.cc window/menuitem.h window/picture.cc window/picture.h window/rect.cc window/rect.h window/render.cc window/runlengh.cc window/surface.h window/system.cc window/system.h window/widget.cc window/widget.h xlovesys.cc
diffstat 71 files changed, 34955 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,57 @@
+@SET_MAKE@
+CC		= @CC@
+CXX		= @CXX@
+LD		= @CXX@
+RANLIB		= @RANLIB@
+
+CFLAGS= -I. $(LOCAL_DEF) @CFLAGS@ @DEFS@ @SDL_CFLAGS@ @SMPEG_CFLAGS@ @FT2_CFLAGS@ @X_CFLAGS@ -pthread -O2
+CXXFLAGS	= $(CFLAGS)
+LDFLAGS = @LDFLAGS@ @FT2_LIBS@ @SDL_LIBS@ -lSDL_mixer @SMPEG_LIBS@ @X_LIBS@ @LIBS@ -pthread
+
+SRCS	= xlovesys.cc
+
+OBJS	 = ${SRCS:.cc=.o}
+
+all: xclannad
+
+xclannad: xlovesys.o system/libsystem.a scn2k/libscn2k.a window/libwindow.a font/libfont.a music2/libmusic.a
+	$(LD) -o xclannad xlovesys.o system/libsystem.a scn2k/libscn2k.a window/libwindow.a font/libfont.a music2/libmusic.a $(LDFLAGS)
+
+install: xclannad music2/nwatowav
+	mkdir -p /usr/local/bin
+	cp xclannad music2/nwatowav /usr/local/bin
+
+clean:
+	rm -f xclannad xlovesys ${OBJS} *.bak
+	(cd font && $(MAKE) clean);
+	(cd system && $(MAKE) clean);
+	(cd window && $(MAKE) clean);
+	(cd music2 && $(MAKE) clean);
+	(cd scn2k && $(MAKE) clean);
+
+music2/nwatowav:
+	(cd music2 && $(MAKE) nwatowav);
+
+.c.o:
+	$(CC) -c $(CFLAGS) -o $@ $<
+
+.cc.o:
+	$(CXX) -c $(CFLAGS) -o $@ $<
+
+font/libfont.a: FORCE
+	cd font && $(MAKE) libfont.a
+
+system/libsystem.a: FORCE
+	cd system && $(MAKE) libsystem.a
+
+scn2k/libscn2k.a: FORCE
+	cd scn2k && $(MAKE) libscn2k.a
+
+window/libwindow.a: FORCE
+	cd window && $(MAKE) libwindow.a
+
+music2/libmusic.a: FORCE
+	cd music2 && $(MAKE) libmusic.a
+
+FORCE:
+
new file mode 100644
--- /dev/null
+++ b/README
@@ -0,0 +1,153 @@
++-------------------------------------------------------------------+
+|                                                                   |
+|        xclannad (RealLive for X) version. 0.07h                   |
+|                                                                   |
+|               Copyright (C) 2004-2008  Kazunori Ueno(JAGARL)      |
+|                                      <jagarl@creator.club.ne.jp>  |
+|                                                                   |
++-------------------------------------------------------------------+
+
+インストール
+	0,必要なライブラリ等
+		SDL と SDL_mixer : 画面描画と音楽再生に使います。必須です。
+		FreeType2 : TrueType font を使用する場合、必要です。
+		smpeg : オープニング等の MPEG 動画の再生、MP3 再生に使用します。
+		mad : BGM ファイルが MP3 形式の場合、SMPEG の代わりに使用することができます。
+		ogg / vorbis / vorbisfile : BGM ファイルが OGG 形式の場合、必要です。
+		tremor (vorbisidec) : BGM ファイルが OGG 形式の場合、vorbisfile の代わりに使用することができます。
+
+		tremor を使用する場合、 --enable-tremor を configure  のオプションに指定する
+		必要があります。それ以外のライブラリは自動的に検索し、使用します。
+
+	1,./xlovesys.cc 冒頭の二行を編集し、フォント名とゲームの
+	  インストールされたディレクトリ名を設定します
+	2,./configure; make;
+	3,make install すると xclannad と nwatowav (BGM再生に必要)が
+	    /usr/local/bin にインストールされます。 xclannad を実行すると
+	    ゲームが開始します
+
+操作方法
+	・マウスの右クリック、またはキーボードの ESC キーでメニューが出ます。
+	・SHIFT キーを押しっぱなしにすると、早送りモードになります。
+	・ホイールの上下(マウスのボタン4,5)でバックログが見れます。
+	・セーブデータは ~/.xkanon/ に作成されます。
+
+	・よく落ちます。
+	・ALT+リターン、または F11 で全画面モードに入れるはずですが、SDL の機嫌がよくないと
+	 ダメなようです。
+
+	・キーボードの"L"キーでロード画面が、"S"キーでセーブ画面が出てきます。
+
+オプション
+	-f	フルスクリーンモードで起動
+	-d	SDL をダブル・バッファモードで起動
+	-t <font name>	フォント名指定 (既定値:msgothic.ttc)
+			( TrueType フォントのファイル名、もしくは X のフォント名を指定する)
+	-r <path>  ゲームのインストールされたディレクトリ(既定値:/mnt/KEY/CLANNAD)
+	-v	バージョン表示して終了
+	-h	簡易ヘルプ表示
+
+注意点
+	・クラナド、プリンセス・ブライド、彼女たちの流儀の冒頭と一部シナリオのみ動作確認してあります。
+	・智代アフターはゲームを起動するところまで確認してあります。
+	・他のゲームが動く保証はありません。
+
+著作権
+	ソースは全体的に jagarl が書いたものです
+
+	font/ 以下の FreeType とのインターフェースは澤田さん(Samyさん)が作成して
+	下さった xkanon へのパッチに由来します
+	window/SDL_rotozoom.cc は A. Schifflerさん製作の SDL_gfx 2.0.9 内のコードを
+	ほぼそのまま使用しています。
+
+謝辞
+	上記、各パッチ等を作製くださった皆様、xkanon の開発にあたりお世話になった皆様、
+	ありがとうございます。xclannad は xkanon の延長線上にあるものです。
+
+	CAT さん(http://www.baywell.ne.jp/users/cat/)には、初期の RealLive の解析情報、
+	コマンドリストをいただきました。ありがとうございます。
+
+再配布等
+	・xkanonの一部を引きずっているのでソフトウェア全体のライセンスは GPL です。
+	・ソースは大部分BSD Licence です。BSD Licence のソースについては再利用はご自由に。
+
+	このプログラムの配布元は現在、
+		http://www.creator.club.ne.jp/~jagarl/xclannad.html
+	です。
+
+履歴
+	2008/1/6	0.07h
+		し〜くるさんの Zaurus 版のパッチを merge
+		libmad / tremor (libvorbisidec) に対応する
+	2007/8/26	0.07g
+		リトルバスターズ!:戦闘画面の動作を修正(不安定版)
+	2007/8/18	0.07f
+		リトルバスターズ!:戦闘画面をひととおり処理できるようになる
+	2007/7/30	0.07e
+		リトルバスターズ!:スクリプト処理のうち script error が出る部分を修正し、
+		音楽ファイルのデコード処理に対応。nwatowav でリトルバスターズ!の
+		音楽もデコードできるようにする
+	2007/7/26	0.07d
+		彼女たちの流儀:ED、おまけモードに対応
+	2006/12/3	0.07c
+		彼女たちの流儀:テキストウィンドウ位置が「画面下側」設定に対応
+		彼女たちの流儀:名前ウィンドウが顔グラウィンドウの下に来るのを回避
+		彼女たちの流儀:バックログで顔表示がされるようにする
+		Back Screen Object (次の画面切り替え後のobject設定)用に従来 FORE_GRPフラグで
+		対応していたのを変更、GrpImpl::grpobj[] 以外に back screen object 情報管理
+		専用の GrpImpl::bs_obj[] を新設
+		選択肢巻き戻し、オートモードを追加
+		ウィンドウ管理系のバグ修正(画面切り替え時に画像チップの一部が切れるバグ)
+	2006/9/10	0.07b
+		智代アフター用:テキストウィンドウ、ボタン等を実装
+		智代アフター用:.nwk 形式の音声に対応
+		Shake の画像効果(CLANNAD; クマ攻撃時)
+		オブジェクトへのテキスト色を実装
+	2006/8/25	0.07a
+		healethさんの掲示板で指摘されたバグを修正(ボタンのON/OFFが変になっていた)
+		movie 終了時の処理を改善
+	2006/8/19	0.07
+		SDL_mixer 版を公開
+		healeth さんによるパッチを取り込む
+			http://dev.haeleth.net/xclannad.shtml
+			- クラナドのリターンパッチ除去
+			- 既読フラグ (RealLive ver. 1.2.5 以降)
+			- 演算子の優先順位
+			- 変数読み書きと文字列操作
+		MacOSX 用に big endian でもある程度動くように修正 (thanx to 黒川さん)
+		智代アフターを見た目は動くようにする(メニュー用はほとんど動かない)
+	2005/06/04	0.06
+		簡易バックログ実装
+	2005/05/01	0.05f(未公開)
+		Shish さんによるパッチ適用
+		起動用オプションをいくつか追加
+	2005/04/03	0.05e
+		バグフィクス版公開
+		ムービー再生に暫定対応
+		「パルフェ」のアーカイブ形式に対応
+		ogg-vorbis 形式の音声・効果音に対応
+	2005/03/07	0.05d
+		バグフィクス版公開
+		CG回想用に見たCGを保存するようにする (回想モードは未実装)
+	2005/02/26	0.05c
+		バグフィクス版公開
+	2005/02/26	0.05b
+		バグフィクス版公開
+	2005/02/20	0.05a
+		バグフィクス版公開
+	2005/01/20	0.05
+		スキップモード、「タイトルに戻る」など実装
+	2005/01/15	0.04
+		ロード・セーブメニューの作成(独自仕様)
+		CLANNADのロード・セーブ画面が動くようにする
+	2004/11/23	0.03
+		画像オブジェクト関連の命令を追加
+		CLANNAD のメニューが動くようになる(見かけのみ)
+		テキストウィンドウ背景の描画モード修正
+		半角文字が英字として表示されるようにする
+	2004/9/16	0.02
+		CLANNADが動いたので 0.02 公開
+	2004/9/3	0.01
+		READMEを書いて 0.01 公開
+	2004/8/31	xxxx
+		とりあえず完成
new file mode 100644
--- /dev/null
+++ b/aclocal.m4
@@ -0,0 +1,561 @@
+# generated automatically by aclocal 1.9.5 -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005  Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 8
+
+# AM_CONFIG_HEADER is obsolete.  It has been replaced by AC_CONFIG_HEADERS.
+AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)])
+
+# Configure paths for FreeType2
+# Marcelo Magallon 2001-10-26, based on gtk.m4 by Owen Taylor
+#
+# Copyright 2001, 2003 by
+# David Turner, Robert Wilhelm, and Werner Lemberg.
+#
+# This file is part of the FreeType project, and may only be used, modified,
+# and distributed under the terms of the FreeType project license,
+# LICENSE.TXT.  By continuing to use, modify, or distribute this file you
+# indicate that you have read the license and understand and accept it
+# fully.
+#
+# serial 2
+
+# AC_CHECK_FT2([MINIMUM-VERSION [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+# Test for FreeType 2, and define FT2_CFLAGS and FT2_LIBS.
+# MINIMUM-VERSION is what libtool reports; the default is `7.0.1' (this is
+# FreeType 2.0.4).
+#
+AC_DEFUN([AC_CHECK_FT2],
+  [# Get the cflags and libraries from the freetype-config script
+   #
+   AC_ARG_WITH([ft-prefix],
+     dnl don't quote AS_HELP_STRING!
+     AS_HELP_STRING([--with-ft-prefix=PREFIX],
+                    [Prefix where FreeType is installed (optional)]),
+     [ft_config_prefix="$withval"],
+     [ft_config_prefix=""])
+
+   AC_ARG_WITH([ft-exec-prefix],
+     dnl don't quote AS_HELP_STRING!
+     AS_HELP_STRING([--with-ft-exec-prefix=PREFIX],
+                    [Exec prefix where FreeType is installed (optional)]),
+     [ft_config_exec_prefix="$withval"],
+     [ft_config_exec_prefix=""])
+
+   AC_ARG_ENABLE([freetypetest],
+     dnl don't quote AS_HELP_STRING!
+     AS_HELP_STRING([--disable-freetypetest],
+                    [Do not try to compile and run a test FreeType program]),
+     [],
+     [enable_fttest=yes])
+
+   if test x$ft_config_exec_prefix != x ; then
+     ft_config_args="$ft_config_args --exec-prefix=$ft_config_exec_prefix"
+     if test x${FT2_CONFIG+set} != xset ; then
+       FT2_CONFIG=$ft_config_exec_prefix/bin/freetype-config
+     fi
+   fi
+
+   if test x$ft_config_prefix != x ; then
+     ft_config_args="$ft_config_args --prefix=$ft_config_prefix"
+     if test x${FT2_CONFIG+set} != xset ; then
+       FT2_CONFIG=$ft_config_prefix/bin/freetype-config
+     fi
+   fi
+
+   AC_PATH_PROG([FT2_CONFIG], [freetype-config], [no])
+
+   min_ft_version=m4_if([$1], [], [7.0.1], [$1])
+   AC_MSG_CHECKING([for FreeType -- version >= $min_ft_version])
+   no_ft=""
+   if test "$FT2_CONFIG" = "no" ; then
+     no_ft=yes
+   else
+     FT2_CFLAGS=`$FT2_CONFIG $ft_config_args --cflags`
+     FT2_LIBS=`$FT2_CONFIG $ft_config_args --libs`
+     ft_config_major_version=`$FT2_CONFIG $ft_config_args --version | \
+       sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+     ft_config_minor_version=`$FT2_CONFIG $ft_config_args --version | \
+       sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+     ft_config_micro_version=`$FT2_CONFIG $ft_config_args --version | \
+       sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+     ft_min_major_version=`echo $min_ft_version | \
+       sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+     ft_min_minor_version=`echo $min_ft_version | \
+       sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+     ft_min_micro_version=`echo $min_ft_version | \
+       sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+     if test x$enable_fttest = xyes ; then
+       ft_config_is_lt=""
+       if test $ft_config_major_version -lt $ft_min_major_version ; then
+         ft_config_is_lt=yes
+       else
+         if test $ft_config_major_version -eq $ft_min_major_version ; then
+           if test $ft_config_minor_version -lt $ft_min_minor_version ; then
+             ft_config_is_lt=yes
+           else
+             if test $ft_config_minor_version -eq $ft_min_minor_version ; then
+               if test $ft_config_micro_version -lt $ft_min_micro_version ; then
+                 ft_config_is_lt=yes
+               fi
+             fi
+           fi
+         fi
+       fi
+       if test x$ft_config_is_lt = xyes ; then
+         no_ft=yes
+       else
+         ac_save_CFLAGS="$CFLAGS"
+         ac_save_LIBS="$LIBS"
+         CFLAGS="$CFLAGS $FT2_CFLAGS"
+         LIBS="$FT2_LIBS $LIBS"
+
+         #
+         # Sanity checks for the results of freetype-config to some extent.
+         #
+         AC_RUN_IFELSE([
+             AC_LANG_SOURCE([[
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main()
+{
+  FT_Library library;
+  FT_Error  error;
+
+  error = FT_Init_FreeType(&library);
+
+  if (error)
+    return 1;
+  else
+  {
+    FT_Done_FreeType(library);
+    return 0;
+  }
+}
+
+             ]])
+           ],
+           [],
+           [no_ft=yes],
+           [echo $ECHO_N "cross compiling; assuming OK... $ECHO_C"])
+
+         CFLAGS="$ac_save_CFLAGS"
+         LIBS="$ac_save_LIBS"
+       fi             # test $ft_config_version -lt $ft_min_version
+     fi               # test x$enable_fttest = xyes
+   fi                 # test "$FT2_CONFIG" = "no"
+
+   if test x$no_ft = x ; then
+     AC_MSG_RESULT([yes])
+     m4_if([$2], [], [:], [$2])
+   else
+     AC_MSG_RESULT([no])
+     if test "$FT2_CONFIG" = "no" ; then
+       AC_MSG_WARN([
+
+  The freetype-config script installed by FreeType 2 could not be found.
+  If FreeType 2 was installed in PREFIX, make sure PREFIX/bin is in
+  your path, or set the FT2_CONFIG environment variable to the
+  full path to freetype-config.
+       ])
+     else
+       if test x$ft_config_is_lt = xyes ; then
+         AC_MSG_WARN([
+
+  Your installed version of the FreeType 2 library is too old.
+  If you have different versions of FreeType 2, make sure that
+  correct values for --with-ft-prefix or --with-ft-exec-prefix
+  are used, or set the FT2_CONFIG environment variable to the
+  full path to freetype-config.
+         ])
+       else
+         AC_MSG_WARN([
+
+  The FreeType test program failed to run.  If your system uses
+  shared libraries and they are installed outside the normal
+  system library path, make sure the variable LD_LIBRARY_PATH
+  (or whatever is appropiate for your system) is correctly set.
+         ])
+       fi
+     fi
+
+     FT2_CFLAGS=""
+     FT2_LIBS=""
+     m4_if([$3], [], [:], [$3])
+   fi
+
+   AC_SUBST([FT2_CFLAGS])
+   AC_SUBST([FT2_LIBS])])
+
+# end of freetype2.m4
+
+# Configure paths for SDL
+# Sam Lantinga 9/21/99
+# stolen from Manish Singh
+# stolen back from Frank Belew
+# stolen from Manish Singh
+# Shamelessly stolen from Owen Taylor
+
+dnl AM_PATH_SDL([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl Test for SDL, and define SDL_CFLAGS and SDL_LIBS
+dnl
+AC_DEFUN([AM_PATH_SDL],
+[dnl 
+dnl Get the cflags and libraries from the sdl-config script
+dnl
+AC_ARG_WITH(sdl-prefix,[  --with-sdl-prefix=PFX   Prefix where SDL is installed (optional)],
+            sdl_prefix="$withval", sdl_prefix="")
+AC_ARG_WITH(sdl-exec-prefix,[  --with-sdl-exec-prefix=PFX Exec prefix where SDL is installed (optional)],
+            sdl_exec_prefix="$withval", sdl_exec_prefix="")
+AC_ARG_ENABLE(sdltest, [  --disable-sdltest       Do not try to compile and run a test SDL program],
+		    , enable_sdltest=yes)
+
+  if test x$sdl_exec_prefix != x ; then
+     sdl_args="$sdl_args --exec-prefix=$sdl_exec_prefix"
+     if test x${SDL_CONFIG+set} != xset ; then
+        SDL_CONFIG=$sdl_exec_prefix/bin/sdl-config
+     fi
+  fi
+  if test x$sdl_prefix != x ; then
+     sdl_args="$sdl_args --prefix=$sdl_prefix"
+     if test x${SDL_CONFIG+set} != xset ; then
+        SDL_CONFIG=$sdl_prefix/bin/sdl-config
+     fi
+  fi
+
+  AC_REQUIRE([AC_CANONICAL_TARGET])
+  PATH="$prefix/bin:$prefix/usr/bin:$PATH"
+  AC_PATH_PROG(SDL_CONFIG, sdl-config, no, [$PATH])
+  min_sdl_version=ifelse([$1], ,0.11.0,$1)
+  AC_MSG_CHECKING(for SDL - version >= $min_sdl_version)
+  no_sdl=""
+  if test "$SDL_CONFIG" = "no" ; then
+    no_sdl=yes
+  else
+    SDL_CFLAGS=`$SDL_CONFIG $sdlconf_args --cflags`
+    SDL_LIBS=`$SDL_CONFIG $sdlconf_args --libs`
+
+    sdl_major_version=`$SDL_CONFIG $sdl_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+    sdl_minor_version=`$SDL_CONFIG $sdl_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+    sdl_micro_version=`$SDL_CONFIG $sdl_config_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+    if test "x$enable_sdltest" = "xyes" ; then
+      ac_save_CFLAGS="$CFLAGS"
+      ac_save_LIBS="$LIBS"
+      CFLAGS="$CFLAGS $SDL_CFLAGS"
+      LIBS="$LIBS $SDL_LIBS"
+dnl
+dnl Now check if the installed SDL is sufficiently new. (Also sanity
+dnl checks the results of sdl-config to some extent
+dnl
+      rm -f conf.sdltest
+      AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "SDL.h"
+
+char*
+my_strdup (char *str)
+{
+  char *new_str;
+  
+  if (str)
+    {
+      new_str = (char *)malloc ((strlen (str) + 1) * sizeof(char));
+      strcpy (new_str, str);
+    }
+  else
+    new_str = NULL;
+  
+  return new_str;
+}
+
+int main (int argc, char *argv[])
+{
+  int major, minor, micro;
+  char *tmp_version;
+
+  /* This hangs on some systems (?)
+  system ("touch conf.sdltest");
+  */
+  { FILE *fp = fopen("conf.sdltest", "a"); if ( fp ) fclose(fp); }
+
+  /* HP/UX 9 (%@#!) writes to sscanf strings */
+  tmp_version = my_strdup("$min_sdl_version");
+  if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3) {
+     printf("%s, bad version string\n", "$min_sdl_version");
+     exit(1);
+   }
+
+   if (($sdl_major_version > major) ||
+      (($sdl_major_version == major) && ($sdl_minor_version > minor)) ||
+      (($sdl_major_version == major) && ($sdl_minor_version == minor) && ($sdl_micro_version >= micro)))
+    {
+      return 0;
+    }
+  else
+    {
+      printf("\n*** 'sdl-config --version' returned %d.%d.%d, but the minimum version\n", $sdl_major_version, $sdl_minor_version, $sdl_micro_version);
+      printf("*** of SDL required is %d.%d.%d. If sdl-config is correct, then it is\n", major, minor, micro);
+      printf("*** best to upgrade to the required version.\n");
+      printf("*** If sdl-config was wrong, set the environment variable SDL_CONFIG\n");
+      printf("*** to point to the correct copy of sdl-config, and remove the file\n");
+      printf("*** config.cache before re-running configure\n");
+      return 1;
+    }
+}
+
+],, no_sdl=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+     fi
+  fi
+  if test "x$no_sdl" = x ; then
+     AC_MSG_RESULT(yes)
+     ifelse([$2], , :, [$2])     
+  else
+     AC_MSG_RESULT(no)
+     if test "$SDL_CONFIG" = "no" ; then
+       echo "*** The sdl-config script installed by SDL could not be found"
+       echo "*** If SDL was installed in PREFIX, make sure PREFIX/bin is in"
+       echo "*** your path, or set the SDL_CONFIG environment variable to the"
+       echo "*** full path to sdl-config."
+     else
+       if test -f conf.sdltest ; then
+        :
+       else
+          echo "*** Could not run SDL test program, checking why..."
+          CFLAGS="$CFLAGS $SDL_CFLAGS"
+          LIBS="$LIBS $SDL_LIBS"
+          AC_TRY_LINK([
+#include <stdio.h>
+#include "SDL.h"
+
+int main(int argc, char *argv[])
+{ return 0; }
+#undef  main
+#define main K_and_R_C_main
+],      [ return 0; ],
+        [ echo "*** The test program compiled, but did not run. This usually means"
+          echo "*** that the run-time linker is not finding SDL or finding the wrong"
+          echo "*** version of SDL. If it is not finding SDL, you'll need to set your"
+          echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+          echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+          echo "*** is required on your system"
+	  echo "***"
+          echo "*** If you have an old version installed, it is best to remove it, although"
+          echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+        [ echo "*** The test program failed to compile or link. See the file config.log for the"
+          echo "*** exact error that occured. This usually means SDL was incorrectly installed"
+          echo "*** or that you have moved SDL since it was installed. In the latter case, you"
+          echo "*** may want to edit the sdl-config script: $SDL_CONFIG" ])
+          CFLAGS="$ac_save_CFLAGS"
+          LIBS="$ac_save_LIBS"
+       fi
+     fi
+     SDL_CFLAGS=""
+     SDL_LIBS=""
+     ifelse([$3], , :, [$3])
+  fi
+  AC_SUBST(SDL_CFLAGS)
+  AC_SUBST(SDL_LIBS)
+  rm -f conf.sdltest
+])
+
+# Configure paths for SMPEG
+# Nicolas Vignal 11/19/2000
+# stolen from Sam Lantinga
+# stolen from Manish Singh
+# stolen back from Frank Belew
+# stolen from Manish Singh
+# Shamelessly stolen from Owen Taylor
+
+dnl AM_PATH_SMPEG([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl Test for SMPEG, and define SMPEG_CFLAGS and SMPEG_LIBS
+dnl
+AC_DEFUN(AM_PATH_SMPEG,
+[dnl
+dnl Get the cflags and libraries from the smpeg-config script
+dnl
+AC_ARG_WITH(smpeg-prefix,[  --with-smpeg-prefix=PFX   Prefix where SMPEG is installed (optional)],
+            smpeg_prefix="$withval", smpeg_prefix="")
+AC_ARG_WITH(smpeg-exec-prefix,[  --with-smpeg-exec-prefix=PFX Exec prefix where SMPEG is installed (optional)],
+            smpeg_exec_prefix="$withval", smpeg_exec_prefix="")
+AC_ARG_ENABLE(smpegtest, [  --disable-smpegtest       Do not try to compile and run a test SMPEG program],
+                    , enable_smpegtest=yes)
+
+  if test x$smpeg_exec_prefix != x ; then
+     smpeg_args="$smpeg_args --exec-prefix=$smpeg_exec_prefix"
+     if test x${SMPEG_CONFIG+set} != xset ; then
+        SMPEG_CONFIG=$smpeg_exec_prefix/bin/smpeg-config
+     fi
+  fi
+  if test x$smpeg_prefix != x ; then
+     smpeg_args="$smpeg_args --prefix=$smpeg_prefix"
+     if test x${SMPEG_CONFIG+set} != xset ; then
+        SMPEG_CONFIG=$smpeg_prefix/bin/smpeg-config
+     fi
+  fi
+
+  AC_PATH_PROG(SMPEG_CONFIG, smpeg-config, no)
+  min_smpeg_version=ifelse([$1], ,0.2.7,$1)
+  AC_MSG_CHECKING(for SMPEG - version >= $min_smpeg_version)
+  no_smpeg=""
+  if test "$SMPEG_CONFIG" = "no" ; then
+    no_smpeg=yes
+  else
+    SMPEG_CFLAGS=`$SMPEG_CONFIG $smpegconf_args --cflags`
+    SMPEG_LIBS=`$SMPEG_CONFIG $smpegconf_args --libs`
+
+    smpeg_major_version=`$SMPEG_CONFIG $smpeg_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+    smpeg_minor_version=`$SMPEG_CONFIG $smpeg_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+    smpeg_micro_version=`$SMPEG_CONFIG $smpeg_config_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+    if test "x$enable_smpegtest" = "xyes" ; then
+      ac_save_CFLAGS="$CFLAGS"
+      ac_save_LIBS="$LIBS"
+      CFLAGS="$CFLAGS $SMPEG_CFLAGS $SDL_CFLAGS"
+      LIBS="$LIBS $SMPEG_LIBS $SDL_LIBS"
+dnl
+dnl Now check if the installed SMPEG is sufficiently new. (Also sanity
+dnl checks the results of smpeg-config to some extent
+dnl
+      rm -f conf.smpegtest
+      AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "smpeg.h"
+
+char*
+my_strdup (char *str)
+{
+  char *new_str;
+
+  if (str)
+    {
+      new_str = (char *)malloc ((strlen (str) + 1) * sizeof(char));
+      strcpy (new_str, str);
+    }
+  else
+    new_str = NULL;
+
+  return new_str;
+}
+
+int main (int argc, char *argv[])
+{
+  int major, minor, micro;
+  char *tmp_version;
+
+  /* This hangs on some systems (?)
+  system ("touch conf.smpegtest");
+  */
+  { FILE *fp = fopen("conf.smpegtest", "a"); if ( fp ) fclose(fp); }
+
+  /* HP/UX 9 (%@#!) writes to sscanf strings */
+  tmp_version = my_strdup("$min_smpeg_version");
+  if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3) {
+     printf("%s, bad version string\n", "$min_smpeg_version");
+     exit(1);
+   }
+
+   if (($smpeg_major_version > major) ||
+      (($smpeg_major_version == major) && ($smpeg_minor_version > minor)) ||
+      (($smpeg_major_version == major) && ($smpeg_minor_version == minor) 
+&& ($smpeg_micro_version >= micro)))
+    {
+      return 0;
+    }
+  else
+    {
+      printf("\n*** 'smpeg-config --version' returned %d.%d.%d, but the minimum version\n", $smpeg_major_version, $smpeg_minor_version, 
+$smpeg_micro_version);
+      printf("*** of SMPEG required is %d.%d.%d. If smpeg-config is correct, then it is\n", major, minor, micro);
+      printf("*** best to upgrade to the required version.\n");
+      printf("*** If smpeg-config was wrong, set the environment variable SMPEG_CONFIG\n");
+      printf("*** to point to the correct copy of smpeg-config, and remove the file\n");
+      printf("*** config.cache before re-running configure\n");
+      return 1;
+    }
+}
+
+],, no_smpeg=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+     fi
+  fi
+  if test "x$no_smpeg" = x ; then
+     AC_MSG_RESULT(yes)
+     ifelse([$2], , :, [$2])
+  else
+     AC_MSG_RESULT(no)
+     if test "$SMPEG_CONFIG" = "no" ; then
+       echo "*** The smpeg-config script installed by SMPEG could not be found"
+       echo "*** If SMPEG was installed in PREFIX, make sure PREFIX/bin is in"
+       echo "*** your path, or set the SMPEG_CONFIG environment variable to the"
+       echo "*** full path to smpeg-config."
+     else
+       if test -f conf.smpegtest ; then
+        :
+       else
+          echo "*** Could not run SMPEG test program, checking why..."
+          CFLAGS="$CFLAGS $SMPEG_CFLAGS $SDL_CFLAGS"
+          LIBS="$LIBS $SMPEG_LIBS $SDL_LIBS"
+          AC_TRY_LINK([
+#include <stdio.h>
+#include "smpeg.h"
+],      [ return 0; ],
+        [ echo "*** The test program compiled, but did not run. This usually means"
+          echo "*** that the run-time linker is not finding SMPEG or finding the wrong"
+          echo "*** version of SMPEG. If it is not finding SMPEG, you'll need to set your"
+          echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+          echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+          echo "*** is required on your system"
+          echo "***"
+          echo "*** If you have an old version installed, it is best to remove it, although"
+          echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+        [ echo "*** The test program failed to compile or link. See the file config.log for the"
+          echo "*** exact error that occured. This usually means SMPEG was incorrectly installed"
+          echo "*** or that you have moved SMPEG since it was installed. In the latter case, you"
+          echo "*** may want to edit the smpeg-config script: $SMPEG_CONFIG" ])
+          CFLAGS="$ac_save_CFLAGS"
+          LIBS="$ac_save_LIBS"
+       fi
+     fi
+     SMPEG_CFLAGS=""
+     SMPEG_LIBS=""
+     ifelse([$3], , :, [$3])
+  fi
+  AC_SUBST(SMPEG_CFLAGS)
+  AC_SUBST(SMPEG_LIBS)
+  rm -f conf.smpegtest
+])
+
new file mode 100755
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+autoheader
+aclocal -I . -I /usr/local/share/aclocal
+autoconf
+# gcc 3.0.2 用の修正
+# gtkmm の autoconf が変でエラーが出るので
+# 強制的にエラーの元になる行を削除
+#sed -e 's/^extern "C" void exit(int);//' -e "s/',//" configure > configure.new
+#cp configure.new configure
+#rm -f configure.new
+./configure $*
new file mode 100755
--- /dev/null
+++ b/clear_ipc
@@ -0,0 +1,8 @@
+#!/bin/sh
+# IPC のmessage queue/shared memory が残ってしまっている
+# 時に、それを全部消去するためのスクリプト
+
+killall -KILL test xlovesys xclannad
+ipcs | grep '^q' | awk '{print $2;}' | perl -ne 'chomp; system "ipcrm -q $_";'
+ipcs | grep '^m' | awk '{print $2;}' | perl -ne 'chomp; system "ipcrm -m $_";'
+ipcs | grep '^s' | awk '{print $2;}' | perl -ne 'chomp; system "ipcrm -s $_";'
new file mode 100644
--- /dev/null
+++ b/config.guess
@@ -0,0 +1,1407 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+timestamp='2003-07-02'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Per Bothner <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit 0 ;;
+    --version | -v )
+       echo "$version" ; exit 0 ;;
+    --help | --h* | -h )
+       echo "$usage"; exit 0 ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+	for c in cc gcc c89 c99 ; do
+	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+	     CC_FOR_BUILD="$c"; break ;
+	  fi ;
+	done ;
+	if test x"$CC_FOR_BUILD" = x ; then
+	  CC_FOR_BUILD=no_compiler_found ;
+	fi
+	;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+	# NetBSD (nbsd) targets should (where applicable) match one or
+	# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+	# switched to ELF, *-*-netbsd* would select the old
+	# object file format.  This provides both forward
+	# compatibility and a consistent mechanism for selecting the
+	# object file format.
+	#
+	# Note: NetBSD doesn't particularly care about the vendor
+	# portion of the name.  We always set it to "unknown".
+	sysctl="sysctl -n hw.machine_arch"
+	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+	case "${UNAME_MACHINE_ARCH}" in
+	    armeb) machine=armeb-unknown ;;
+	    arm*) machine=arm-unknown ;;
+	    sh3el) machine=shl-unknown ;;
+	    sh3eb) machine=sh-unknown ;;
+	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+	esac
+	# The Operating System including object format, if it has switched
+	# to ELF recently, or will in the future.
+	case "${UNAME_MACHINE_ARCH}" in
+	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+		eval $set_cc_for_build
+		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+			| grep __ELF__ >/dev/null
+		then
+		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+		    # Return netbsd for either.  FIX?
+		    os=netbsd
+		else
+		    os=netbsdelf
+		fi
+		;;
+	    *)
+	        os=netbsd
+		;;
+	esac
+	# The OS release
+	# Debian GNU/NetBSD machines have a different userland, and
+	# thus, need a distinct triplet. However, they do not need
+	# kernel version information, so it can be replaced with a
+	# suitable tag, in the style of linux-gnu.
+	case "${UNAME_VERSION}" in
+	    Debian*)
+		release='-gnu'
+		;;
+	    *)
+		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+		;;
+	esac
+	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+	# contains redundant information, the shorter form:
+	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+	echo "${machine}-${os}${release}"
+	exit 0 ;;
+    amiga:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    arc:OpenBSD:*:*)
+	echo mipsel-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    hp300:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    mac68k:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    macppc:OpenBSD:*:*)
+	echo powerpc-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    mvme68k:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    mvme88k:OpenBSD:*:*)
+	echo m88k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    mvmeppc:OpenBSD:*:*)
+	echo powerpc-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    pmax:OpenBSD:*:*)
+	echo mipsel-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    sgi:OpenBSD:*:*)
+	echo mipseb-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    sun3:OpenBSD:*:*)
+	echo m68k-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    wgrisc:OpenBSD:*:*)
+	echo mipsel-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    *:OpenBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE}
+	exit 0 ;;
+    alpha:OSF1:*:*)
+	if test $UNAME_RELEASE = "V4.0"; then
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+	fi
+	# According to Compaq, /usr/sbin/psrinfo has been available on
+	# OSF/1 and Tru64 systems produced since 1995.  I hope that
+	# covers most systems running today.  This code pipes the CPU
+	# types through head -n 1, so we only detect the type of CPU 0.
+	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+	case "$ALPHA_CPU_TYPE" in
+	    "EV4 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV4.5 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "LCA4 (21066/21068)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV5 (21164)")
+		UNAME_MACHINE="alphaev5" ;;
+	    "EV5.6 (21164A)")
+		UNAME_MACHINE="alphaev56" ;;
+	    "EV5.6 (21164PC)")
+		UNAME_MACHINE="alphapca56" ;;
+	    "EV5.7 (21164PC)")
+		UNAME_MACHINE="alphapca57" ;;
+	    "EV6 (21264)")
+		UNAME_MACHINE="alphaev6" ;;
+	    "EV6.7 (21264A)")
+		UNAME_MACHINE="alphaev67" ;;
+	    "EV6.8CB (21264C)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8AL (21264B)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8CX (21264D)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.9A (21264/EV69A)")
+		UNAME_MACHINE="alphaev69" ;;
+	    "EV7 (21364)")
+		UNAME_MACHINE="alphaev7" ;;
+	    "EV7.9 (21364A)")
+		UNAME_MACHINE="alphaev79" ;;
+	esac
+	# A Vn.n version is a released version.
+	# A Tn.n version is a released field test version.
+	# A Xn.n version is an unreleased experimental baselevel.
+	# 1.2 uses "1.2" for uname -r.
+	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	exit 0 ;;
+    Alpha*:OpenVMS:*:*)
+	echo alpha-hp-vms
+	exit 0 ;;
+    Alpha\ *:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# Should we change UNAME_MACHINE based on the output of uname instead
+	# of the specific Alpha model?
+	echo alpha-pc-interix
+	exit 0 ;;
+    21064:Windows_NT:50:3)
+	echo alpha-dec-winnt3.5
+	exit 0 ;;
+    Amiga*:UNIX_System_V:4.0:*)
+	echo m68k-unknown-sysv4
+	exit 0;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-amigaos
+	exit 0 ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-morphos
+	exit 0 ;;
+    *:OS/390:*:*)
+	echo i370-ibm-openedition
+	exit 0 ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit 0;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+	echo hppa1.1-hitachi-hiuxmpp
+	exit 0;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+	# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit 0 ;;
+    NILE*:*:*:dcosx)
+	echo pyramid-pyramid-svr4
+	exit 0 ;;
+    DRS?6000:unix:4.0:6*)
+	echo sparc-icl-nx6
+	exit 0 ;;
+    DRS?6000:UNIX_SV:4.2*:7*)
+	case `/usr/bin/uname -p` in
+	    sparc) echo sparc-icl-nx7 && exit 0 ;;
+	esac ;;
+    sun4H:SunOS:5.*:*)
+	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    i86pc:SunOS:5.*:*)
+	echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    sun4*:SunOS:*:*)
+	case "`/usr/bin/arch -k`" in
+	    Series*|S4*)
+		UNAME_RELEASE=`uname -v`
+		;;
+	esac
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit 0 ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit 0 ;;
+    sun*:*:4.2BSD:*)
+	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+	case "`/bin/arch`" in
+	    sun3)
+		echo m68k-sun-sunos${UNAME_RELEASE}
+		;;
+	    sun4)
+		echo sparc-sun-sunos${UNAME_RELEASE}
+		;;
+	esac
+	exit 0 ;;
+    aushp:SunOS:*:*)
+	echo sparc-auspex-sunos${UNAME_RELEASE}
+	exit 0 ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit 0 ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit 0 ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit 0 ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit 0 ;;
+    powerpc:machten:*:*)
+	echo powerpc-apple-machten${UNAME_RELEASE}
+	exit 0 ;;
+    RISC*:Mach:*:*)
+	echo mips-dec-mach_bsd4.3
+	exit 0 ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit 0 ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit 0 ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+	echo clipper-intergraph-clix${UNAME_RELEASE}
+	exit 0 ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+	int main (int argc, char *argv[]) {
+#else
+	int main (argc, argv) int argc; char *argv[]; {
+#endif
+	#if defined (host_mips) && defined (MIPSEB)
+	#if defined (SYSTYPE_SYSV)
+	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_SVR4)
+	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+	#endif
+	#endif
+	  exit (-1);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c \
+	  && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+	  && exit 0
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit 0 ;;
+    Motorola:PowerMAX_OS:*:*)
+	echo powerpc-motorola-powermax
+	exit 0 ;;
+    Motorola:*:4.3:PL8-*)
+	echo powerpc-harris-powermax
+	exit 0 ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+	echo powerpc-harris-powermax
+	exit 0 ;;
+    Night_Hawk:Power_UNIX:*:*)
+	echo powerpc-harris-powerunix
+	exit 0 ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit 0 ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit 0 ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit 0 ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+	then
+	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+	       [ ${TARGET_BINARY_INTERFACE}x = x ]
+	    then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	    else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	    fi
+	else
+	    echo i586-dg-dgux${UNAME_RELEASE}
+	fi
+ 	exit 0 ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit 0 ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit 0 ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit 0 ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit 0 ;;
+    *:IRIX*:*:*)
+	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+	exit 0 ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+	echo romp-ibm-aix      # uname -m gives an 8 hex-code CPU id
+	exit 0 ;;              # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+	echo i386-ibm-aix
+	exit 0 ;;
+    ia64:AIX:*:*)
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+	exit 0 ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		eval $set_cc_for_build
+		sed 's/^		//' << EOF >$dummy.c
+		#include <sys/systemcfg.h>
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		$CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0
+		echo rs6000-ibm-aix3.2.5
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit 0 ;;
+    *:AIX:*:[45])
+	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit 0 ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit 0 ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+	echo romp-ibm-bsd4.4
+	exit 0 ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+	exit 0 ;;                           # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit 0 ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit 0 ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit 0 ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit 0 ;;
+    9000/[34678]??:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/[678][0-9][0-9])
+		if [ -x /usr/bin/getconf ]; then
+		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                    case "${sc_cpu_version}" in
+                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                      532)                      # CPU_PA_RISC2_0
+                        case "${sc_kernel_bits}" in
+                          32) HP_ARCH="hppa2.0n" ;;
+                          64) HP_ARCH="hppa2.0w" ;;
+			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+                        esac ;;
+                    esac
+		fi
+		if [ "${HP_ARCH}" = "" ]; then
+		    eval $set_cc_for_build
+		    sed 's/^              //' << EOF >$dummy.c
+
+              #define _HPUX_SOURCE
+              #include <stdlib.h>
+              #include <unistd.h>
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+              	{
+              	case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+              	case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+              	case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+              	    switch (bits)
+              		{
+              		case 64: puts ("hppa2.0w"); break;
+              		case 32: puts ("hppa2.0n"); break;
+              		default: puts ("hppa2.0"); break;
+              		} break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+              	    puts ("hppa2.0"); break;
+              #endif
+              	default: puts ("hppa1.0"); break;
+              	}
+                  exit (0);
+              }
+EOF
+		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+		    test -z "$HP_ARCH" && HP_ARCH=hppa
+		fi ;;
+	esac
+	if [ ${HP_ARCH} = "hppa2.0w" ]
+	then
+	    # avoid double evaluation of $set_cc_for_build
+	    test -n "$CC_FOR_BUILD" || eval $set_cc_for_build
+	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null
+	    then
+		HP_ARCH="hppa2.0w"
+	    else
+		HP_ARCH="hppa64"
+	    fi
+	fi
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit 0 ;;
+    ia64:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ia64-hp-hpux${HPUX_REV}
+	exit 0 ;;
+    3050*:HI-UX:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <unistd.h>
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0
+	echo unknown-hitachi-hiuxwe2
+	exit 0 ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit 0 ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit 0 ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+	echo hppa1.0-hp-mpeix
+	exit 0 ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit 0 ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit 0 ;;
+    i*86:OSF1:*:*)
+	if [ -x /usr/sbin/sysversion ] ; then
+	    echo ${UNAME_MACHINE}-unknown-osf1mk
+	else
+	    echo ${UNAME_MACHINE}-unknown-osf1
+	fi
+	exit 0 ;;
+    parisc*:Lites*:*:*)
+	echo hppa1.1-hp-lites
+	exit 0 ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+        exit 0 ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+        exit 0 ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+        exit 0 ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+        exit 0 ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+        exit 0 ;;
+    CRAY*Y-MP:*:*:*)
+	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit 0 ;;
+    CRAY*[A-Z]90:*:*:*)
+	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+	      -e 's/\.[^.]*$/.X/'
+	exit 0 ;;
+    CRAY*TS:*:*:*)
+	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit 0 ;;
+    CRAY*T3E:*:*:*)
+	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit 0 ;;
+    CRAY*SV1:*:*:*)
+	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit 0 ;;
+    *:UNICOS/mp:*:*)
+	echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' 
+	exit 0 ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit 0 ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+	exit 0 ;;
+    sparc*:BSD/OS:*:*)
+	echo sparc-unknown-bsdi${UNAME_RELEASE}
+	exit 0 ;;
+    *:BSD/OS:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit 0 ;;
+    *:FreeBSD:*:*|*:GNU/FreeBSD:*:*)
+	# Determine whether the default compiler uses glibc.
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <features.h>
+	#if __GLIBC__ >= 2
+	LIBC=gnu
+	#else
+	LIBC=
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+	# GNU/FreeBSD systems have a "k" prefix to indicate we are using
+	# FreeBSD's kernel, but not the complete OS.
+	case ${LIBC} in gnu) kernel_only='k' ;; esac
+	echo ${UNAME_MACHINE}-unknown-${kernel_only}freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC}
+	exit 0 ;;
+    i*:CYGWIN*:*)
+	echo ${UNAME_MACHINE}-pc-cygwin
+	exit 0 ;;
+    i*:MINGW*:*)
+	echo ${UNAME_MACHINE}-pc-mingw32
+	exit 0 ;;
+    i*:PW*:*)
+	echo ${UNAME_MACHINE}-pc-pw32
+	exit 0 ;;
+    x86:Interix*:[34]*)
+	echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//'
+	exit 0 ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+	echo i${UNAME_MACHINE}-pc-mks
+	exit 0 ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+	# UNAME_MACHINE based on the output of uname instead of i386?
+	echo i586-pc-interix
+	exit 0 ;;
+    i*:UWIN*:*)
+	echo ${UNAME_MACHINE}-pc-uwin
+	exit 0 ;;
+    p*:CYGWIN*:*)
+	echo powerpcle-unknown-cygwin
+	exit 0 ;;
+    prep*:SunOS:5.*:*)
+	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit 0 ;;
+    *:GNU:*:*)
+	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit 0 ;;
+    i*86:Minix:*:*)
+	echo ${UNAME_MACHINE}-pc-minix
+	exit 0 ;;
+    arm*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit 0 ;;
+    cris:Linux:*:*)
+	echo cris-axis-linux-gnu
+	exit 0 ;;
+    ia64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit 0 ;;
+    m68*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit 0 ;;
+    mips:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef mips
+	#undef mipsel
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=mipsel
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=mips
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+	test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0
+	;;
+    mips64:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef mips64
+	#undef mips64el
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=mips64el
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=mips64
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+	test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0
+	;;
+    ppc:Linux:*:*)
+	echo powerpc-unknown-linux-gnu
+	exit 0 ;;
+    ppc64:Linux:*:*)
+	echo powerpc64-unknown-linux-gnu
+	exit 0 ;;
+    alpha:Linux:*:*)
+	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+	  EV5)   UNAME_MACHINE=alphaev5 ;;
+	  EV56)  UNAME_MACHINE=alphaev56 ;;
+	  PCA56) UNAME_MACHINE=alphapca56 ;;
+	  PCA57) UNAME_MACHINE=alphapca56 ;;
+	  EV6)   UNAME_MACHINE=alphaev6 ;;
+	  EV67)  UNAME_MACHINE=alphaev67 ;;
+	  EV68*) UNAME_MACHINE=alphaev68 ;;
+        esac
+	objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+	if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+	exit 0 ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+	# Look for CPU level
+	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+	  PA7*) echo hppa1.1-unknown-linux-gnu ;;
+	  PA8*) echo hppa2.0-unknown-linux-gnu ;;
+	  *)    echo hppa-unknown-linux-gnu ;;
+	esac
+	exit 0 ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-gnu
+	exit 0 ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+	echo ${UNAME_MACHINE}-ibm-linux
+	exit 0 ;;
+    sh64*:Linux:*:*)
+    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit 0 ;;
+    sh*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit 0 ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit 0 ;;
+    x86_64:Linux:*:*)
+	echo x86_64-unknown-linux-gnu
+	exit 0 ;;
+    i*86:Linux:*:*)
+	# The BFD linker knows what the default object file format is, so
+	# first see if it will tell us. cd to the root directory to prevent
+	# problems with other programs or directories called `ld' in the path.
+	# Set LC_ALL=C to ensure ld outputs messages in English.
+	ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+			 | sed -ne '/supported targets:/!d
+				    s/[ 	][ 	]*/ /g
+				    s/.*supported targets: *//
+				    s/ .*//
+				    p'`
+        case "$ld_supported_targets" in
+	  elf32-i386)
+		TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+		;;
+	  a.out-i386-linux)
+		echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+		exit 0 ;;
+	  coff-i386)
+		echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+		exit 0 ;;
+	  "")
+		# Either a pre-BFD a.out linker (linux-gnuoldld) or
+		# one that does not give us useful --help.
+		echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+		exit 0 ;;
+	esac
+	# Determine whether the default compiler is a.out or elf
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <features.h>
+	#ifdef __ELF__
+	# ifdef __GLIBC__
+	#  if __GLIBC__ >= 2
+	LIBC=gnu
+	#  else
+	LIBC=gnulibc1
+	#  endif
+	# else
+	LIBC=gnulibc1
+	# endif
+	#else
+	#ifdef __INTEL_COMPILER
+	LIBC=gnu
+	#else
+	LIBC=gnuaout
+	#endif
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+	test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0
+	test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
+	;;
+    i*86:DYNIX/ptx:4*:*)
+	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+	# earlier versions are messed up and put the nodename in both
+	# sysname and nodename.
+	echo i386-sequent-sysv4
+	exit 0 ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+	# I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+	exit 0 ;;
+    i*86:OS/2:*:*)
+	# If we were able to find `uname', then EMX Unix compatibility
+	# is probably installed.
+	echo ${UNAME_MACHINE}-pc-os2-emx
+	exit 0 ;;
+    i*86:XTS-300:*:STOP)
+	echo ${UNAME_MACHINE}-unknown-stop
+	exit 0 ;;
+    i*86:atheos:*:*)
+	echo ${UNAME_MACHINE}-unknown-atheos
+	exit 0 ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+	echo i386-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    i*86:*DOS:*:*)
+	echo ${UNAME_MACHINE}-pc-msdosdjgpp
+	exit 0 ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+	else
+		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+	fi
+	exit 0 ;;
+    i*86:*:5:[78]*)
+	case `/bin/uname -X | grep "^Machine"` in
+	    *486*)	     UNAME_MACHINE=i486 ;;
+	    *Pentium)	     UNAME_MACHINE=i586 ;;
+	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+	esac
+	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+	exit 0 ;;
+    i*86:*:3.2:*)
+	if test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+	elif /bin/uname -X 2>/dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+			&& UNAME_MACHINE=i586
+		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-pc-sysv32
+	fi
+	exit 0 ;;
+    pc:*:*:*)
+	# Left here for compatibility:
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i386.
+	echo i386-pc-msdosdjgpp
+        exit 0 ;;
+    Intel:Mach:3*:*)
+	echo i386-pc-mach3
+	exit 0 ;;
+    paragon:*:*:*)
+	echo i860-intel-osf1
+	exit 0 ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit 0 ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit 0 ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+	echo m68k-convergent-sysv
+	exit 0 ;;
+    M680?0:D-NIX:5.3:*)
+	echo m68k-diab-dnix
+	exit 0 ;;
+    M68*:*:R3V[567]*:*)
+	test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+    3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0)
+	OS_REL=''
+	test -r /etc/.relid \
+	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	  && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && echo i486-ncr-sysv4 && exit 0 ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+	echo m68k-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit 0 ;;
+    TSUNAMI:LynxOS:2.*:*)
+	echo sparc-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    rs6000:LynxOS:2.*:*)
+	echo rs6000-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+	echo powerpc-unknown-lynxos${UNAME_RELEASE}
+	exit 0 ;;
+    SM[BE]S:UNIX_SV:*:*)
+	echo mips-dde-sysv${UNAME_RELEASE}
+	exit 0 ;;
+    RM*:ReliantUNIX-*:*:*)
+	echo mips-sni-sysv4
+	exit 0 ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit 0 ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit 0 ;;
+    PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                      # says <Richard.M.Bartel@ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit 0 ;;
+    *:UNIX_System_V:4*:FTX*)
+	# From Gerald Hewes <hewes@openmarket.com>.
+	# How about differentiating between stratus architectures? -djm
+	echo hppa1.1-stratus-sysv4
+	exit 0 ;;
+    *:*:*:FTX*)
+	# From seanf@swdc.stratus.com.
+	echo i860-stratus-sysv4
+	exit 0 ;;
+    *:VOS:*:*)
+	# From Paul.Green@stratus.com.
+	echo hppa1.1-stratus-vos
+	exit 0 ;;
+    mc68*:A/UX:*:*)
+	echo m68k-apple-aux${UNAME_RELEASE}
+	exit 0 ;;
+    news*:NEWS-OS:6*:*)
+	echo mips-sony-newsos6
+	exit 0 ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+	if [ -d /usr/nec ]; then
+	        echo mips-nec-sysv${UNAME_RELEASE}
+	else
+	        echo mips-unknown-sysv${UNAME_RELEASE}
+	fi
+        exit 0 ;;
+    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
+	echo powerpc-be-beos
+	exit 0 ;;
+    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
+	echo powerpc-apple-beos
+	exit 0 ;;
+    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
+	echo i586-pc-beos
+	exit 0 ;;
+    SX-4:SUPER-UX:*:*)
+	echo sx4-nec-superux${UNAME_RELEASE}
+	exit 0 ;;
+    SX-5:SUPER-UX:*:*)
+	echo sx5-nec-superux${UNAME_RELEASE}
+	exit 0 ;;
+    SX-6:SUPER-UX:*:*)
+	echo sx6-nec-superux${UNAME_RELEASE}
+	exit 0 ;;
+    Power*:Rhapsody:*:*)
+	echo powerpc-apple-rhapsody${UNAME_RELEASE}
+	exit 0 ;;
+    *:Rhapsody:*:*)
+	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+	exit 0 ;;
+    *:Darwin:*:*)
+	case `uname -p` in
+	    *86) UNAME_PROCESSOR=i686 ;;
+	    powerpc) UNAME_PROCESSOR=powerpc ;;
+	esac
+	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+	exit 0 ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+	UNAME_PROCESSOR=`uname -p`
+	if test "$UNAME_PROCESSOR" = "x86"; then
+		UNAME_PROCESSOR=i386
+		UNAME_MACHINE=pc
+	fi
+	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+	exit 0 ;;
+    *:QNX:*:4*)
+	echo i386-pc-qnx
+	exit 0 ;;
+    NSR-[DGKLNPTVW]:NONSTOP_KERNEL:*:*)
+	echo nsr-tandem-nsk${UNAME_RELEASE}
+	exit 0 ;;
+    *:NonStop-UX:*:*)
+	echo mips-compaq-nonstopux
+	exit 0 ;;
+    BS2000:POSIX*:*:*)
+	echo bs2000-siemens-sysv
+	exit 0 ;;
+    DS/*:UNIX_System_V:*:*)
+	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+	exit 0 ;;
+    *:Plan9:*:*)
+	# "uname -m" is not consistent, so use $cputype instead. 386
+	# is converted to i386 for consistency with other x86
+	# operating systems.
+	if test "$cputype" = "386"; then
+	    UNAME_MACHINE=i386
+	else
+	    UNAME_MACHINE="$cputype"
+	fi
+	echo ${UNAME_MACHINE}-unknown-plan9
+	exit 0 ;;
+    *:TOPS-10:*:*)
+	echo pdp10-unknown-tops10
+	exit 0 ;;
+    *:TENEX:*:*)
+	echo pdp10-unknown-tenex
+	exit 0 ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+	echo pdp10-dec-tops20
+	exit 0 ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+	echo pdp10-xkl-tops20
+	exit 0 ;;
+    *:TOPS-20:*:*)
+	echo pdp10-unknown-tops20
+	exit 0 ;;
+    *:ITS:*:*)
+	echo pdp10-unknown-its
+	exit 0 ;;
+    SEI:*:*:SEIUX)
+        echo mips-sei-seiux${UNAME_RELEASE}
+	exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+	  ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+	printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+	printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+	echo c1-convex-bsd
+	exit 0 ;;
+    c2*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit 0 ;;
+    c34*)
+	echo c34-convex-bsd
+	exit 0 ;;
+    c38*)
+	echo c38-convex-bsd
+	exit 0 ;;
+    c4*)
+	echo c4-convex-bsd
+	exit 0 ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+    ftp://ftp.gnu.org/pub/gnu/config/
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
new file mode 100644
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,151 @@
+/* config.h.in.  Generated from configure.in by autoheader.  */
+/* gettext 用 */
+#undef ENABLE_NLS
+#undef HAVE_CATGETS
+#undef HAVE_GETTEXT
+#undef HAVE_LC_MESSAGES
+#undef HAVE_STPCPY
+#undef PACKAGE
+#undef VERSION
+
+/* default display size */
+#undef DISPSIZE
+
+/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
+   */
+#undef HAVE_DIRENT_H
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have the `getpagesize' function. */
+#undef HAVE_GETPAGESIZE
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `intl' library (-lintl). */
+#undef HAVE_LIBINTL
+
+/* Define to 1 if you have the `jpeg' library (-ljpeg). */
+#undef HAVE_LIBJPEG
+
+/* Define to 1 if you have the `mad' library (-lmad). */
+#undef HAVE_LIBMAD
+
+/* Define to 1 if you have the `ogg' library (-logg). */
+#undef HAVE_LIBOGG
+
+/* Define to 1 if you have the `png' library (-lpng). */
+#undef HAVE_LIBPNG
+
+/* Define to 1 if you have the `vorbis' library (-lvorbis). */
+#undef HAVE_LIBVORBIS
+
+/* Define to 1 if you have the `vorbisfile' library (-lvorbisfile). */
+#undef HAVE_LIBVORBISFILE
+
+/* Define to 1 if you have the `vorbisidec' library (-lvorbisidec). */
+#undef HAVE_LIBVORBISIDEC
+
+/* Define to 1 if you have the `z' library (-lz). */
+#undef HAVE_LIBZ
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `mkdir' function. */
+#undef HAVE_MKDIR
+
+/* Define to 1 if you have a working `mmap' system call. */
+#undef HAVE_MMAP
+
+/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
+#undef HAVE_NDIR_H
+
+/* Define to 1 if you have the `snprintf' function. */
+#undef HAVE_SNPRINTF
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
+   */
+#undef HAVE_SYS_DIR_H
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
+   */
+#undef HAVE_SYS_NDIR_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#undef RETSIGTYPE
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+#undef TM_IN_SYS_TIME
+
+/* smpeg library is used */
+#undef USE_SMPEG
+
+/* X11 library is used */
+#undef USE_X11
+
+/* Define to 1 if your processor stores words with the most significant byte
+   first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+/* Define to 1 if the X Window System is missing or not being used. */
+#undef X_DISPLAY_MISSING
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#undef size_t
new file mode 100644
--- /dev/null
+++ b/config.sub
@@ -0,0 +1,1504 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+timestamp='2003-07-04'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit 0 ;;
+    --version | -v )
+       echo "$version" ; exit 0 ;;
+    --help | --h* | -h )
+       echo "$usage"; exit 0 ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit 0;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | kfreebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+	-sun*os*)
+		# Prevent following clause from handling this invalid input.
+		;;
+	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+	-apple | -axis)
+		os=
+		basic_machine=$1
+		;;
+	-sim | -cisco | -oki | -wec | -winbond)
+		os=
+		basic_machine=$1
+		;;
+	-scout)
+		;;
+	-wrs)
+		os=-vxworks
+		basic_machine=$1
+		;;
+	-chorusos*)
+		os=-chorusos
+		basic_machine=$1
+		;;
+ 	-chorusrdb)
+ 		os=-chorusrdb
+		basic_machine=$1
+ 		;;
+	-hiux*)
+		os=-hiuxwe2
+		;;
+	-sco5)
+		os=-sco3.2v5
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco4)
+		os=-sco3.2v4
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2v[4-9]*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco*)
+		os=-sco3.2v2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-udk*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-isc)
+		os=-isc2.2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-clix*)
+		basic_machine=clipper-intergraph
+		;;
+	-isc*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-lynx*)
+		os=-lynxos
+		;;
+	-ptx*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+		;;
+	-windowsnt*)
+		os=`echo $os | sed -e 's/windowsnt/winnt/'`
+		;;
+	-psos*)
+		os=-psos
+		;;
+	-mint | -mint[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+	# Recognize the basic CPU types without company name.
+	# Some are omitted here because they have special meanings below.
+	1750a | 580 \
+	| a29k \
+	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
+	| c4x | clipper \
+	| d10v | d30v | dlx | dsp16xx \
+	| fr30 | frv \
+	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+	| i370 | i860 | i960 | ia64 \
+	| ip2k \
+	| m32r | m68000 | m68k | m88k | mcore \
+	| mips | mipsbe | mipseb | mipsel | mipsle \
+	| mips16 \
+	| mips64 | mips64el \
+	| mips64vr | mips64vrel \
+	| mips64orion | mips64orionel \
+	| mips64vr4100 | mips64vr4100el \
+	| mips64vr4300 | mips64vr4300el \
+	| mips64vr5000 | mips64vr5000el \
+	| mipsisa32 | mipsisa32el \
+	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa64 | mipsisa64el \
+	| mipsisa64sb1 | mipsisa64sb1el \
+	| mipsisa64sr71k | mipsisa64sr71kel \
+	| mipstx39 | mipstx39el \
+	| mn10200 | mn10300 \
+	| msp430 \
+	| ns16k | ns32k \
+	| openrisc | or32 \
+	| pdp10 | pdp11 | pj | pjl \
+	| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+	| pyramid \
+	| sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
+	| sh64 | sh64le \
+	| sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \
+	| strongarm \
+	| tahoe | thumb | tic4x | tic80 | tron \
+	| v850 | v850e \
+	| we32k \
+	| x86 | xscale | xstormy16 | xtensa \
+	| z8k)
+		basic_machine=$basic_machine-unknown
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12)
+		# Motorola 68HC11/12.
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+		;;
+
+	# We use `pc' rather than `unknown'
+	# because (1) that's what they normally are, and
+	# (2) the word "unknown" tends to confuse beginning users.
+	i*86 | x86_64)
+	  basic_machine=$basic_machine-pc
+	  ;;
+	# Object if more than one company name word.
+	*-*-*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+	# Recognize the basic CPU types with company name.
+	580-* \
+	| a29k-* \
+	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+	| alphapca5[67]-* | alpha64pca5[67]-* | amd64-* | arc-* \
+	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+	| avr-* \
+	| bs2000-* \
+	| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+	| clipper-* | cydra-* \
+	| d10v-* | d30v-* | dlx-* \
+	| elxsi-* \
+	| f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
+	| h8300-* | h8500-* \
+	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+	| i*86-* | i860-* | i960-* | ia64-* \
+	| ip2k-* \
+	| m32r-* \
+	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+	| m88110-* | m88k-* | mcore-* \
+	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+	| mips16-* \
+	| mips64-* | mips64el-* \
+	| mips64vr-* | mips64vrel-* \
+	| mips64orion-* | mips64orionel-* \
+	| mips64vr4100-* | mips64vr4100el-* \
+	| mips64vr4300-* | mips64vr4300el-* \
+	| mips64vr5000-* | mips64vr5000el-* \
+	| mipsisa32-* | mipsisa32el-* \
+	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa64-* | mipsisa64el-* \
+	| mipsisa64sb1-* | mipsisa64sb1el-* \
+	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
+	| mipstx39-* | mipstx39el-* \
+	| msp430-* \
+	| none-* | np1-* | nv1-* | ns16k-* | ns32k-* \
+	| orion-* \
+	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+	| pyramid-* \
+	| romp-* | rs6000-* \
+	| sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \
+	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+	| sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \
+	| sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
+	| tahoe-* | thumb-* \
+	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+	| tron-* \
+	| v850-* | v850e-* | vax-* \
+	| we32k-* \
+	| x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \
+	| xtensa-* \
+	| ymp-* \
+	| z8k-*)
+		;;
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	386bsd)
+		basic_machine=i386-unknown
+		os=-bsd
+		;;
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		basic_machine=m68000-att
+		;;
+	3b*)
+		basic_machine=we32k-att
+		;;
+	a29khif)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	adobe68k)
+		basic_machine=m68010-adobe
+		os=-scout
+		;;
+	alliant | fx80)
+		basic_machine=fx80-alliant
+		;;
+	altos | altos3068)
+		basic_machine=m68k-altos
+		;;
+	am29k)
+		basic_machine=a29k-none
+		os=-bsd
+		;;
+	amd64)
+		basic_machine=x86_64-pc
+		;;
+	amdahl)
+		basic_machine=580-amdahl
+		os=-sysv
+		;;
+	amiga | amiga-*)
+		basic_machine=m68k-unknown
+		;;
+	amigaos | amigados)
+		basic_machine=m68k-unknown
+		os=-amigaos
+		;;
+	amigaunix | amix)
+		basic_machine=m68k-unknown
+		os=-sysv4
+		;;
+	apollo68)
+		basic_machine=m68k-apollo
+		os=-sysv
+		;;
+	apollo68bsd)
+		basic_machine=m68k-apollo
+		os=-bsd
+		;;
+	aux)
+		basic_machine=m68k-apple
+		os=-aux
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	c90)
+		basic_machine=c90-cray
+		os=-unicos
+		;;
+	convex-c1)
+		basic_machine=c1-convex
+		os=-bsd
+		;;
+	convex-c2)
+		basic_machine=c2-convex
+		os=-bsd
+		;;
+	convex-c32)
+		basic_machine=c32-convex
+		os=-bsd
+		;;
+	convex-c34)
+		basic_machine=c34-convex
+		os=-bsd
+		;;
+	convex-c38)
+		basic_machine=c38-convex
+		os=-bsd
+		;;
+	cray | j90)
+		basic_machine=j90-cray
+		os=-unicos
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	cris | cris-* | etrax*)
+		basic_machine=cris-axis
+		;;
+	da30 | da30-*)
+		basic_machine=m68k-da30
+		;;
+	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+		basic_machine=mips-dec
+		;;
+	decsystem10* | dec10*)
+		basic_machine=pdp10-dec
+		os=-tops10
+		;;
+	decsystem20* | dec20*)
+		basic_machine=pdp10-dec
+		os=-tops20
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		basic_machine=m68k-motorola
+		;;
+	delta88)
+		basic_machine=m88k-motorola
+		os=-sysv3
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	ebmon29k)
+		basic_machine=a29k-amd
+		os=-ebmon
+		;;
+	elxsi)
+		basic_machine=elxsi-elxsi
+		os=-bsd
+		;;
+	encore | umax | mmax)
+		basic_machine=ns32k-encore
+		;;
+	es1800 | OSE68k | ose68k | ose | OSE)
+		basic_machine=m68k-ericsson
+		os=-ose
+		;;
+	fx2800)
+		basic_machine=i860-alliant
+		;;
+	genix)
+		basic_machine=ns32k-ns
+		;;
+	gmicro)
+		basic_machine=tron-gmicro
+		os=-sysv
+		;;
+	go32)
+		basic_machine=i386-pc
+		os=-go32
+		;;
+	h3050r* | hiux*)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	h8300hms)
+		basic_machine=h8300-hitachi
+		os=-hms
+		;;
+	h8300xray)
+		basic_machine=h8300-hitachi
+		os=-xray
+		;;
+	h8500hms)
+		basic_machine=h8500-hitachi
+		os=-hms
+		;;
+	harris)
+		basic_machine=m88k-harris
+		os=-sysv3
+		;;
+	hp300-*)
+		basic_machine=m68k-hp
+		;;
+	hp300bsd)
+		basic_machine=m68k-hp
+		os=-bsd
+		;;
+	hp300hpux)
+		basic_machine=m68k-hp
+		os=-hpux
+		;;
+	hp3k9[0-9][0-9] | hp9[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		basic_machine=m68000-hp
+		;;
+	hp9k3[2-9][0-9])
+		basic_machine=m68k-hp
+		;;
+	hp9k6[0-9][0-9] | hp6[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k7[0-79][0-9] | hp7[0-79][0-9])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k78[0-9] | hp78[0-9])
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][13679] | hp8[0-9][13679])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hppa-next)
+		os=-nextstep3
+		;;
+	hppaosf)
+		basic_machine=hppa1.1-hp
+		os=-osf
+		;;
+	hppro)
+		basic_machine=hppa1.1-hp
+		os=-proelf
+		;;
+	i370-ibm* | ibm*)
+		basic_machine=i370-ibm
+		;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+	i*86v32)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv32
+		;;
+	i*86v4*)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv4
+		;;
+	i*86v)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv
+		;;
+	i*86sol2)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-solaris2
+		;;
+	i386mach)
+		basic_machine=i386-mach
+		os=-mach
+		;;
+	i386-vsta | vsta)
+		basic_machine=i386-unknown
+		os=-vsta
+		;;
+	iris | iris4d)
+		basic_machine=mips-sgi
+		case $os in
+		    -irix*)
+			;;
+		    *)
+			os=-irix4
+			;;
+		esac
+		;;
+	isi68 | isi)
+		basic_machine=m68k-isi
+		os=-sysv
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+	mingw32)
+		basic_machine=i386-pc
+		os=-mingw32
+		;;
+	miniframe)
+		basic_machine=m68000-convergent
+		;;
+	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+	mips3*-*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+		;;
+	mips3*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+		;;
+	mmix*)
+		basic_machine=mmix-knuth
+		os=-mmixware
+		;;
+	monitor)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	morphos)
+		basic_machine=powerpc-unknown
+		os=-morphos
+		;;
+	msdos)
+		basic_machine=i386-pc
+		os=-msdos
+		;;
+	mvs)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+	ncr3000)
+		basic_machine=i486-ncr
+		os=-sysv4
+		;;
+	netbsd386)
+		basic_machine=i386-unknown
+		os=-netbsd
+		;;
+	netwinder)
+		basic_machine=armv4l-rebel
+		os=-linux
+		;;
+	news | news700 | news800 | news900)
+		basic_machine=m68k-sony
+		os=-newsos
+		;;
+	news1000)
+		basic_machine=m68030-sony
+		os=-newsos
+		;;
+	news-3600 | risc-news)
+		basic_machine=mips-sony
+		os=-newsos
+		;;
+	necv70)
+		basic_machine=v70-nec
+		os=-sysv
+		;;
+	next | m*-next )
+		basic_machine=m68k-next
+		case $os in
+		    -nextstep* )
+			;;
+		    -ns2*)
+		      os=-nextstep2
+			;;
+		    *)
+		      os=-nextstep3
+			;;
+		esac
+		;;
+	nh3000)
+		basic_machine=m68k-harris
+		os=-cxux
+		;;
+	nh[45]000)
+		basic_machine=m88k-harris
+		os=-cxux
+		;;
+	nindy960)
+		basic_machine=i960-intel
+		os=-nindy
+		;;
+	mon960)
+		basic_machine=i960-intel
+		os=-mon960
+		;;
+	nonstopux)
+		basic_machine=mips-compaq
+		os=-nonstopux
+		;;
+	np1)
+		basic_machine=np1-gould
+		;;
+	nv1)
+		basic_machine=nv1-cray
+		os=-unicosmp
+		;;
+	nsr-tandem)
+		basic_machine=nsr-tandem
+		;;
+	op50n-* | op60c-*)
+		basic_machine=hppa1.1-oki
+		os=-proelf
+		;;
+	or32 | or32-*)
+		basic_machine=or32-unknown
+		os=-coff
+		;;
+	OSE68000 | ose68000)
+		basic_machine=m68000-ericsson
+		os=-ose
+		;;
+	os68k)
+		basic_machine=m68k-none
+		os=-os68k
+		;;
+	pa-hitachi)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	paragon)
+		basic_machine=i860-intel
+		os=-osf
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+	pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pentium | p5 | k5 | k6 | nexgen | viac3)
+		basic_machine=i586-pc
+		;;
+	pentiumpro | p6 | 6x86 | athlon | athlon_*)
+		basic_machine=i686-pc
+		;;
+	pentiumii | pentium2 | pentiumiii | pentium3)
+		basic_machine=i686-pc
+		;;
+	pentium4)
+		basic_machine=i786-pc
+		;;
+	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumpro-* | p6-* | 6x86-* | athlon-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium4-*)
+		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	power)	basic_machine=power-ibm
+		;;
+	ppc)	basic_machine=powerpc-unknown
+		;;
+	ppc-*)	basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppcle | powerpclittle | ppc-le | powerpc-little)
+		basic_machine=powerpcle-unknown
+		;;
+	ppcle-* | powerpclittle-*)
+		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64)	basic_machine=powerpc64-unknown
+		;;
+	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+		basic_machine=powerpc64le-unknown
+		;;
+	ppc64le-* | powerpc64little-*)
+		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ps2)
+		basic_machine=i386-ibm
+		;;
+	pw32)
+		basic_machine=i586-unknown
+		os=-pw32
+		;;
+	rom68k)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	rm[46]00)
+		basic_machine=mips-siemens
+		;;
+	rtpc | rtpc-*)
+		basic_machine=romp-ibm
+		;;
+	s390 | s390-*)
+		basic_machine=s390-ibm
+		;;
+	s390x | s390x-*)
+		basic_machine=s390x-ibm
+		;;
+	sa29200)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	sb1)
+		basic_machine=mipsisa64sb1-unknown
+		;;
+	sb1el)
+		basic_machine=mipsisa64sb1el-unknown
+		;;
+	sei)
+		basic_machine=mips-sei
+		os=-seiux
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	sh64)
+		basic_machine=sh64-unknown
+		;;
+	sparclite-wrs | simso-wrs)
+		basic_machine=sparclite-wrs
+		os=-vxworks
+		;;
+	sps7)
+		basic_machine=m68k-bull
+		os=-sysv2
+		;;
+	spur)
+		basic_machine=spur-unknown
+		;;
+	st2000)
+		basic_machine=m68k-tandem
+		;;
+	stratus)
+		basic_machine=i860-stratus
+		os=-sysv4
+		;;
+	sun2)
+		basic_machine=m68000-sun
+		;;
+	sun2os3)
+		basic_machine=m68000-sun
+		os=-sunos3
+		;;
+	sun2os4)
+		basic_machine=m68000-sun
+		os=-sunos4
+		;;
+	sun3os3)
+		basic_machine=m68k-sun
+		os=-sunos3
+		;;
+	sun3os4)
+		basic_machine=m68k-sun
+		os=-sunos4
+		;;
+	sun4os3)
+		basic_machine=sparc-sun
+		os=-sunos3
+		;;
+	sun4os4)
+		basic_machine=sparc-sun
+		os=-sunos4
+		;;
+	sun4sol2)
+		basic_machine=sparc-sun
+		os=-solaris2
+		;;
+	sun3 | sun3-*)
+		basic_machine=m68k-sun
+		;;
+	sun4)
+		basic_machine=sparc-sun
+		;;
+	sun386 | sun386i | roadrunner)
+		basic_machine=i386-sun
+		;;
+	sv1)
+		basic_machine=sv1-cray
+		os=-unicos
+		;;
+	symmetry)
+		basic_machine=i386-sequent
+		os=-dynix
+		;;
+	t3e)
+		basic_machine=alphaev5-cray
+		os=-unicos
+		;;
+	t90)
+		basic_machine=t90-cray
+		os=-unicos
+		;;
+	tic54x | c54x*)
+		basic_machine=tic54x-unknown
+		os=-coff
+		;;
+	tic55x | c55x*)
+		basic_machine=tic55x-unknown
+		os=-coff
+		;;
+	tic6x | c6x*)
+		basic_machine=tic6x-unknown
+		os=-coff
+		;;
+	tx39)
+		basic_machine=mipstx39-unknown
+		;;
+	tx39el)
+		basic_machine=mipstx39el-unknown
+		;;
+	toad1)
+		basic_machine=pdp10-xkl
+		os=-tops20
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	udi29k)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	ultra3)
+		basic_machine=a29k-nyu
+		os=-sym1
+		;;
+	v810 | necv810)
+		basic_machine=v810-nec
+		os=-none
+		;;
+	vaxv)
+		basic_machine=vax-dec
+		os=-sysv
+		;;
+	vms)
+		basic_machine=vax-dec
+		os=-vms
+		;;
+	vpp*|vx|vx-*)
+		basic_machine=f301-fujitsu
+		;;
+	vxworks960)
+		basic_machine=i960-wrs
+		os=-vxworks
+		;;
+	vxworks68)
+		basic_machine=m68k-wrs
+		os=-vxworks
+		;;
+	vxworks29k)
+		basic_machine=a29k-wrs
+		os=-vxworks
+		;;
+	w65*)
+		basic_machine=w65-wdc
+		os=-none
+		;;
+	w89k-*)
+		basic_machine=hppa1.1-winbond
+		os=-proelf
+		;;
+	xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	z8k-*-coff)
+		basic_machine=z8k-unknown
+		os=-sim
+		;;
+	none)
+		basic_machine=none-none
+		os=-none
+		;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+	w89k)
+		basic_machine=hppa1.1-winbond
+		;;
+	op50n)
+		basic_machine=hppa1.1-oki
+		;;
+	op60c)
+		basic_machine=hppa1.1-oki
+		;;
+	romp)
+		basic_machine=romp-ibm
+		;;
+	rs6000)
+		basic_machine=rs6000-ibm
+		;;
+	vax)
+		basic_machine=vax-dec
+		;;
+	pdp10)
+		# there are many clones, so DEC is not a safe bet
+		basic_machine=pdp10-unknown
+		;;
+	pdp11)
+		basic_machine=pdp11-dec
+		;;
+	we32k)
+		basic_machine=we32k-att
+		;;
+	sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele)
+		basic_machine=sh-unknown
+		;;
+	sh64)
+		basic_machine=sh64-unknown
+		;;
+	sparc | sparcv9 | sparcv9b)
+		basic_machine=sparc-sun
+		;;
+	cydra)
+		basic_machine=cydra-cydrome
+		;;
+	orion)
+		basic_machine=orion-highlevel
+		;;
+	orion105)
+		basic_machine=clipper-highlevel
+		;;
+	mac | mpw | mac-mpw)
+		basic_machine=m68k-apple
+		;;
+	pmac | pmac-mpw)
+		basic_machine=powerpc-apple
+		;;
+	*-unknown)
+		# Make sure to match an already-canonicalized machine name.
+		;;
+	*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+	*-digital*)
+		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+		;;
+	*-commodore*)
+		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+	# -solaris* is a basic system type, with this one exception.
+	-solaris1 | -solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	-solaris)
+		os=-solaris2
+		;;
+	-svr4*)
+		os=-sysv4
+		;;
+	-unixware*)
+		os=-sysv4.2uw
+		;;
+	-gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+		;;
+	# First accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative MUST END IN A *, to match a version number.
+	# -sysv* is not here because it comes later, after sysvr4.
+	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+	      | -aos* \
+	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -netbsd* | -openbsd* | -kfreebsd* | -freebsd* | -riscix* \
+	      | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+	      | -chorusos* | -chorusrdb* \
+	      | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
+	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei*)
+	# Remember, each alternative MUST END IN *, to match a version number.
+		;;
+	-qnx*)
+		case $basic_machine in
+		    x86-* | i*86-*)
+			;;
+		    *)
+			os=-nto$os
+			;;
+		esac
+		;;
+	-nto-qnx*)
+		;;
+	-nto*)
+		os=`echo $os | sed -e 's|nto|nto-qnx|'`
+		;;
+	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
+	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+		;;
+	-mac*)
+		os=`echo $os | sed -e 's|mac|macos|'`
+		;;
+	-linux*)
+		os=`echo $os | sed -e 's|linux|linux-gnu|'`
+		;;
+	-sunos5*)
+		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+		;;
+	-sunos6*)
+		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+		;;
+	-opened*)
+		os=-openedition
+		;;
+	-wince*)
+		os=-wince
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-atheos*)
+		os=-atheos
+		;;
+	-386bsd)
+		os=-bsd
+		;;
+	-ctix* | -uts*)
+		os=-sysv
+		;;
+	-nova*)
+		os=-rtmk-nova
+		;;
+	-ns2 )
+		os=-nextstep2
+		;;
+	-nsk*)
+		os=-nsk
+		;;
+	# Preserve the version number of sinix5.
+	-sinix5.*)
+		os=`echo $os | sed -e 's|sinix|sysv|'`
+		;;
+	-sinix*)
+		os=-sysv4
+		;;
+	-triton*)
+		os=-sysv3
+		;;
+	-oss*)
+		os=-sysv3
+		;;
+	-svr4)
+		os=-sysv4
+		;;
+	-svr3)
+		os=-sysv3
+		;;
+	-sysvr4)
+		os=-sysv4
+		;;
+	# This must come after -sysvr4.
+	-sysv*)
+		;;
+	-ose*)
+		os=-ose
+		;;
+	-es1800*)
+		os=-ose
+		;;
+	-xenix)
+		os=-xenix
+		;;
+	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+		os=-mint
+		;;
+	-aros*)
+		os=-aros
+		;;
+	-kaos*)
+		os=-kaos
+		;;
+	-none)
+		;;
+	*)
+		# Get rid of the `-' at the beginning of $os.
+		os=`echo $os | sed 's/[^-]*-//'`
+		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+	*-acorn)
+		os=-riscix1.2
+		;;
+	arm*-rebel)
+		os=-linux
+		;;
+	arm*-semi)
+		os=-aout
+		;;
+    c4x-* | tic4x-*)
+        os=-coff
+        ;;
+	# This must come before the *-dec entry.
+	pdp10-*)
+		os=-tops20
+		;;
+	pdp11-*)
+		os=-none
+		;;
+	*-dec | vax-*)
+		os=-ultrix4.2
+		;;
+	m68*-apollo)
+		os=-domain
+		;;
+	i386-sun)
+		os=-sunos4.0.2
+		;;
+	m68000-sun)
+		os=-sunos3
+		# This also exists in the configure program, but was not the
+		# default.
+		# os=-sunos4
+		;;
+	m68*-cisco)
+		os=-aout
+		;;
+	mips*-cisco)
+		os=-elf
+		;;
+	mips*-*)
+		os=-elf
+		;;
+	or32-*)
+		os=-coff
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=-sysv3
+		;;
+	sparc-* | *-sun)
+		os=-sunos4.1.1
+		;;
+	*-be)
+		os=-beos
+		;;
+	*-ibm)
+		os=-aix
+		;;
+	*-wec)
+		os=-proelf
+		;;
+	*-winbond)
+		os=-proelf
+		;;
+	*-oki)
+		os=-proelf
+		;;
+	*-hp)
+		os=-hpux
+		;;
+	*-hitachi)
+		os=-hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=-sysv
+		;;
+	*-cbm)
+		os=-amigaos
+		;;
+	*-dg)
+		os=-dgux
+		;;
+	*-dolphin)
+		os=-sysv3
+		;;
+	m68k-ccur)
+		os=-rtu
+		;;
+	m88k-omron*)
+		os=-luna
+		;;
+	*-next )
+		os=-nextstep
+		;;
+	*-sequent)
+		os=-ptx
+		;;
+	*-crds)
+		os=-unos
+		;;
+	*-ns)
+		os=-genix
+		;;
+	i370-*)
+		os=-mvs
+		;;
+	*-next)
+		os=-nextstep3
+		;;
+	*-gould)
+		os=-sysv
+		;;
+	*-highlevel)
+		os=-bsd
+		;;
+	*-encore)
+		os=-bsd
+		;;
+	*-sgi)
+		os=-irix
+		;;
+	*-siemens)
+		os=-sysv4
+		;;
+	*-masscomp)
+		os=-rtu
+		;;
+	f30[01]-fujitsu | f700-fujitsu)
+		os=-uxpv
+		;;
+	*-rom68k)
+		os=-coff
+		;;
+	*-*bug)
+		os=-coff
+		;;
+	*-apple)
+		os=-macos
+		;;
+	*-atari*)
+		os=-mint
+		;;
+	*)
+		os=-none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+	*-unknown)
+		case $os in
+			-riscix*)
+				vendor=acorn
+				;;
+			-sunos*)
+				vendor=sun
+				;;
+			-aix*)
+				vendor=ibm
+				;;
+			-beos*)
+				vendor=be
+				;;
+			-hpux*)
+				vendor=hp
+				;;
+			-mpeix*)
+				vendor=hp
+				;;
+			-hiux*)
+				vendor=hitachi
+				;;
+			-unos*)
+				vendor=crds
+				;;
+			-dgux*)
+				vendor=dg
+				;;
+			-luna*)
+				vendor=omron
+				;;
+			-genix*)
+				vendor=ns
+				;;
+			-mvs* | -opened*)
+				vendor=ibm
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+			-vxsim* | -vxworks* | -windiss*)
+				vendor=wrs
+				;;
+			-aux*)
+				vendor=apple
+				;;
+			-hms*)
+				vendor=hitachi
+				;;
+			-mpw* | -macos*)
+				vendor=apple
+				;;
+			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+				vendor=atari
+				;;
+			-vos*)
+				vendor=stratus
+				;;
+		esac
+		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+		;;
+esac
+
+echo $basic_machine$os
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
new file mode 100644
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,154 @@
+dnl >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+dnl
+dnl First definition
+AC_INIT(scn2k)
+
+dnl Software version
+PACKAGE=xclannad
+VERSION=scn2k
+
+dnl I do not use automake ; It is too difficult for me ...
+dnl AM_INIT_AUTOMAKE($PACKAGE, $VERSION)
+
+dnl Specify a configuretion file
+AM_CONFIG_HEADER(config.h)
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_PROG_CXX
+AC_PROG_LN_S
+AC_PROG_RANLIB
+dnl AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+
+dnl dnl On FreeBSD 3.0 (and perhaps some other systems) GNU m4 is
+dnl dnl called `gm4' where `m4' is the system's own m4.
+dnl AC_CHECK_PROGS(M4, gm4 m4, m4)
+dnl 
+dnl if test "$M4" = "m4"; then
+dnl   AC_MSG_CHECKING(whether m4 is GNU m4)
+dnl   if $M4 --version < /dev/null 2>/dev/null | grep '^GNU m4 ' >/dev/null ; then
+dnl 	  AC_MSG_RESULT(yes)
+dnl   else
+dnl 	  AC_MSG_RESULT(no)
+dnl 	  if test "$host_vendor" = "sun"; then
+dnl 		  AC_MSG_ERROR("SUN m4 does not work for building Gtk--. Please install GNU m4")
+dnl 	  fi
+dnl   fi
+dnl fi
+dnl 
+dnl dnl Check that this is GNU m4 - if not, exit with error if this is a SUN
+dnl dnl
+
+dnl Checks for header files.
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_CHECK_HEADERS(fcntl.h sys/ioctl.h sys/time.h unistd.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_SIZE_T
+AC_HEADER_TIME
+AC_STRUCT_TM
+#X_LIBS="$X_LIBS -lX11 -lXext -L/usr/X11R6/lib"
+
+
+
+dnl Checks for library functions.
+AC_PROG_GCC_TRADITIONAL
+AC_FUNC_MEMCMP
+AC_FUNC_MMAP
+AC_TYPE_SIGNAL
+AC_CHECK_FUNCS(gettimeofday mkdir snprintf)
+#ac_save_LIBS="$LIBS"
+#LIBS="$LIBS -pthread"
+#AC_CHECK_FUNCS(_thread_sys_sigaltstack)
+#LIBS="$ac_save_LIBS"
+AC_C_BIGENDIAN
+
+dnl for gettext
+dnl ALL_LINGUAS="ja"
+dnl AM_GNU_GETTEXT
+AC_CHECK_FUNC(gettext,,AC_CHECK_LIB(intl, gettext))
+
+dnl >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+dnl
+dnl Check libraries
+
+AC_CHECK_LIB(z, zlibVersion)
+AC_CHECK_LIB(png, png_write_end)
+AC_CHECK_LIB(jpeg, jpeg_start_decompress)
+dnl ogg vobis
+AC_ARG_ENABLE(tremor,
+	[ --enable-tremor	enable tremor (integer-only implementation for vorbisfile) [ default no]])
+AC_CHECK_LIB(ogg, ogg_stream_init)
+AC_CHECK_LIB(vorbis,  vorbis_book_decode,,,-logg)
+if test X$enable_tremor = X"yes"; then
+	AC_CHECK_LIB(vorbisidec,  ov_read,,,-logg -lvorbis)
+else
+	AC_CHECK_LIB(vorbisfile,  ov_read,,,-logg -lvorbis)
+fi
+
+dnl SDL config
+AM_PATH_SDL()
+AC_SUBST(SDL_CFLAGS)
+AC_SUBST(SDL_LIBS)
+
+dnl SMPEG & MAD config
+AM_PATH_SMPEG()
+AC_SUBST(SMPEG_CFLAGS)
+AC_SUBST(SMPEG_LIBS)
+if test X"$SMPEG_LIBS" = X ; then
+	USE_SMPEG=0
+else
+	USE_SMPEG=1
+fi
+AC_ARG_ENABLE(mad,
+	[ --disable-mad		disable mad (integer-only implementation for mpeg decoding) [ default yes]])
+if test X$enable_mad != X"no"; then
+	AC_CHECK_LIB(mad, mad_decoder_run)
+fi
+
+AC_DEFINE_UNQUOTED(USE_SMPEG,$USE_SMPEG, [smpeg library is used])
+
+dnl FreeType2
+AC_CHECK_FT2()
+AC_SUBST(FT2_CFLAGS)
+AC_SUBST(FT2_LIBS)
+
+
+dnl >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+dnl
+dnl Check option ... Zaurus or embed machines
+USE_X11=1
+DISPSIZE="no"
+
+AC_ARG_ENABLE(zaurus,
+	[ --enable-zaurus	compile for zaurus environment [ default no]])
+if test X$enable_zaurus = X"yes"; then
+	USE_X11=0
+	DISPSIZE="320x240"
+fi
+
+AC_ARG_ENABLE(x11,
+	[ --disable-x11		turn off using X11 library [default enable]])
+if test X$x11 = X"no"; then
+	USE_X11=0
+else
+	AC_PATH_X
+	AC_PATH_XTRA
+	X_LIBS="$X_LIBS -lX11 -lXext -L/usr/X11R6/lib"
+	LIBS="$LIBS $X_LIBS"
+fi
+
+AC_ARG_ENABLE(displaysize,
+	[ --enable-displaysize=SIZE  change default display size, for example --enable-displaysize=320x240],
+	displaysize=$enableval)
+if test X$displaysize != X; then
+	DISPSIZE=$displaysize
+fi
+
+AC_DEFINE_UNQUOTED(USE_X11,$USE_X11, [X11 library is used])
+AC_DEFINE_UNQUOTED(DISPSIZE, "$DISPSIZE", [default display size])
+
+AC_OUTPUT(Makefile system/Makefile font/Makefile window/Makefile music2/Makefile scn2k/Makefile)
new file mode 100644
--- /dev/null
+++ b/font/Makefile.in
@@ -0,0 +1,38 @@
+@SET_MAKE@
+CC		= @CC@
+CXX		= @CXX@
+LD		= @CC@
+AR		= ar
+RANLIB		= @RANLIB@
+
+CFLAGS= -I.. $(LOCAL_DEF) @CFLAGS@ @DEFS@ @FT2_CFLAGS@ -pthread -O2
+CXXFLAGS	= $(CFLAGS)
+LDFLAGS = @LDFLAGS@ @FT2_LIBS@ @LIBS@ -pthread
+
+SRCS	 = font_face.cc \
+	   font_peer_fn.cc \
+	   font_peer_ft2.cc \
+	   font_peer_x11.cc \
+	   font_layout.cc \
+	   codeconv.cc \
+	   text_stream.cc \
+#	   render.c
+
+OBJS	 = ${SRCS:.cc=.o}
+
+all: libfont.a
+
+libfont.a: ${OBJS}
+	rm -f libfont.a
+	${AR} clq libfont.a ${OBJS}
+	$(RANLIB) libfont.a
+
+clean:
+	rm -f libfont.a ${OBJS} *.bak *.core
+
+.c.o:
+	$(CC) -c $(CFLAGS) -o $@ $<
+
+.cc.o:
+	$(CXX) -c $(CFLAGS) -o $@ $<
+
new file mode 100644
--- /dev/null
+++ b/font/codeconv.cc
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2000 Yuki Sawada
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "codeconv.h"
+#include "codeconv_tbl.h"
+
+static unsigned int
+codeconv_euc_to_jis(unsigned int euc)
+{
+  unsigned int hi, low;
+
+  hi = (euc >> 8) & 0xff;
+  low = euc & 0xff;
+
+  if (hi < 0x81) {
+    hi = 0;
+  } else if (low == 0x8e)
+    hi = 0;
+  else {
+    hi -= 0x80;
+    low -= 0x80;
+  }
+
+  return (hi << 8) | low;
+}
+
+static unsigned int
+codeconv_jis_to_unicode(unsigned int jis)
+{
+  int k0, k1;
+
+  if (jis < 0x80) return jis; // ASCII
+  k0 = (jis >> 8) - 0x20;
+  if (k0 < 1 || k0 > 92)
+    return 0;
+
+  k1 = (jis % 0x100) - 0x20;
+  if (k1 < 1 || k1 > 94)
+    return 0;
+
+  return unicode_tbl[k0 - 1][k1 - 1];
+}
+
+unsigned int
+codeconv_euc_to_unicode(unsigned int euc)
+{
+  unsigned int jis, unicode;
+
+  jis = codeconv_euc_to_jis(euc);
+  unicode = codeconv_jis_to_unicode(jis);
+
+  return unicode;
+}
+
+static unsigned int
+codeconv_unicode_to_jis(unsigned int unicode)
+{
+  int k0, k1;
+  unsigned int jis;
+
+  k0 = (unicode >> 8) & 0xff;
+  k1 = unicode & 0xff;
+  jis = unicode_rev_table[k0][k1];
+    
+  return jis;
+}
+
+static unsigned int
+codeconv_jis_to_euc(unsigned int jis)
+{
+  unsigned int hi, low;
+
+  hi = (jis >> 8) & 0x7f | 0x80;
+  low = jis & 0x7f | 0x80;
+
+  return (hi << 8) | low;
+}
+
+unsigned int
+codeconv_unicode_to_euc(unsigned int unicode)
+{
+  unsigned int jis, euc;
+
+  if (unicode >= 0xff61 && unicode <= 0xff9f)
+    return unicode - 0xff61 + 0x8ea1;
+
+  jis = codeconv_unicode_to_jis(unicode);
+  if (jis == 0)
+    return 0x7878;
+  euc = codeconv_jis_to_euc(jis);
+
+  return euc;
+}
+
+static unsigned int
+codeconv_jis_to_sjis(unsigned int jis)
+{
+  unsigned int hi, low;
+
+  hi = (jis >> 8) & 0xff;
+  low = jis & 0xff;
+
+  low += (hi & 0x01) ? 0x1f : 0x7d;
+  if (low >= 0x7f)
+    low++;
+  hi = ((hi - 0x21) >> 1) + 0x81;
+  if (hi > 0x9f)
+    hi += 0x40;
+
+  return (hi << 8) | low;
+}
+
+unsigned int
+codeconv_euc_to_sjis(unsigned int euc)
+{
+  unsigned int jis, sjis;
+
+  jis = codeconv_euc_to_jis(euc);
+  sjis = codeconv_jis_to_sjis(jis);
+
+  return sjis;
+}
+
+static unsigned int
+codeconv_sjis_to_jis(unsigned int sjis)
+{
+  unsigned int hi, low;
+
+  hi = (sjis >> 8) & 0xff;
+  low = sjis & 0xff;
+
+  hi -= (hi <= 0x9f) ? 0x71 : 0xb1;
+  hi = (hi << 1) + 1;
+  if (low > 0x7f)
+    low--;
+  if (low >= 0x9e) {
+    low -= 0x7d;
+    hi++;
+  } else
+    low -= 0x1f;
+  
+  return (hi << 8) | low;
+}
+
+unsigned int
+codeconv_sjis_to_euc(unsigned int sjis)
+{
+  unsigned int jis, euc;
+
+  jis = codeconv_sjis_to_jis(sjis);
+  euc = codeconv_jis_to_euc(jis);
+
+  return euc;
+}
+
+unsigned int
+codeconv_euc_to_latin1(unsigned int euc)
+{
+	int high = (euc>>8) & 0xff;
+	if (high) return 0;
+	return euc & 0xff;
+}
new file mode 100644
--- /dev/null
+++ b/font/codeconv.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2000, 2001 Yuki Sawada
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __FONT_CODECONV_H__
+#define __FONT_CODECONV_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+unsigned int codeconv_euc_to_latin1(unsigned int);
+
+unsigned int codeconv_euc_to_unicode(unsigned int);
+unsigned int codeconv_unicode_to_euc(unsigned int);
+
+unsigned int codeconv_euc_to_sjis(unsigned int);
+unsigned int codeconv_sjis_to_euc(unsigned int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
new file mode 100644
--- /dev/null
+++ b/font/codeconv_tbl.h
@@ -0,0 +1,4720 @@
+unsigned short unicode_tbl[][94] = {
+{ /* category 01 */
+0x0000, 0x3001, 0x3002, 0xFF0C, 0xFF0E, 0x30FB, 0xFF1A, 0xFF1B,
+0xFF1F, 0xFF01, 0x309B, 0x309C, 0x00B4, 0xFF40, 0x00A8, 0xFF3E,
+0xFFE3, 0xFF3F, 0x30FD, 0x30FE, 0x309D, 0x309E, 0x3003, 0x4EDD,
+0x3005, 0x3006, 0x3007, 0x30FC, 0x2015, 0x2010, 0xFF0F, 0xFF3C,
+0xFF5E, 0x2225, 0xFF5C, 0x2026, 0x2025, 0x2018, 0x2019, 0x201C,
+0x201D, 0xFF08, 0xFF09, 0x3014, 0x3015, 0xFF3B, 0xFF3D, 0xFF5B,
+0xFF5D, 0x3008, 0x3009, 0x300A, 0x300B, 0x300C, 0x300D, 0x300E,
+0x300F, 0x3010, 0x3011, 0xFF0B, 0xFF0D, 0x00B1, 0x00D7, 0x00F7,
+0xFF1D, 0x2260, 0xFF1C, 0xFF1E, 0x2266, 0x2267, 0x221E, 0x2234,
+0x2642, 0x2640, 0x00B0, 0x2032, 0x2033, 0x2103, 0xFFE5, 0xFF04,
+0xFFE0, 0xFFE1, 0xFF05, 0xFF03, 0xFF06, 0xFF0A, 0xFF20, 0x00A7,
+0x2606, 0x2605, 0x25CB, 0x25CF, 0x25CE, 0x25C7},
+{ /* category 02 */
+0x25C6, 0x25A1, 0x25A0, 0x25B3, 0x25B2, 0x25BD, 0x25BC, 0x203B,
+0x3012, 0x2192, 0x2190, 0x2191, 0x2193, 0x3013, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x2208, 0x220B, 0x2286, 0x2287, 0x2282, 0x2283, 0x222A,
+0x2229, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x2227, 0x2228, 0xFFE2, 0x21D2, 0x21D4, 0x2200, 0x2203,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x2220, 0x22A5, 0x2312, 0x2202, 0x2207,
+0x2261, 0x2252, 0x226A, 0x226B, 0x221A, 0x223D, 0x221D, 0x2235,
+0x222B, 0x222C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x212B, 0x2030, 0x266F, 0x266D, 0x266A, 0x2020, 0x2021, /**/
+0x00B6, 0x0000, 0x0000, 0x0000, 0x0000, 0x25EF},
+{ /* category 03 */
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFF10,
+0xFF11, 0xFF12, 0xFF13, 0xFF14, 0xFF15, 0xFF16, 0xFF17, 0xFF18,
+0xFF19, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0xFF21, 0xFF22, 0xFF23, 0xFF24, 0xFF25, 0xFF26, 0xFF27, 0xFF28,
+0xFF29, 0xFF2A, 0xFF2B, 0xFF2C, 0xFF2D, 0xFF2E, 0xFF2F, 0xFF30,
+0xFF31, 0xFF32, 0xFF33, 0xFF34, 0xFF35, 0xFF36, 0xFF37, 0xFF38,
+0xFF39, 0xFF3A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48,
+0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F, 0xFF50,
+0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58,
+0xFF59, 0xFF5A, 0x0000, 0x0000, 0x0000, 0x0000},
+{ /* category 04 */
+0x3041, 0x3042, 0x3043, 0x3044, 0x3045, 0x3046, 0x3047, 0x3048,
+0x3049, 0x304A, 0x304B, 0x304C, 0x304D, 0x304E, 0x304F, 0x3050,
+0x3051, 0x3052, 0x3053, 0x3054, 0x3055, 0x3056, 0x3057, 0x3058,
+0x3059, 0x305A, 0x305B, 0x305C, 0x305D, 0x305E, 0x305F, 0x3060,
+0x3061, 0x3062, 0x3063, 0x3064, 0x3065, 0x3066, 0x3067, 0x3068,
+0x3069, 0x306A, 0x306B, 0x306C, 0x306D, 0x306E, 0x306F, 0x3070,
+0x3071, 0x3072, 0x3073, 0x3074, 0x3075, 0x3076, 0x3077, 0x3078,
+0x3079, 0x307A, 0x307B, 0x307C, 0x307D, 0x307E, 0x307F, 0x3080,
+0x3081, 0x3082, 0x3083, 0x3084, 0x3085, 0x3086, 0x3087, 0x3088,
+0x3089, 0x308A, 0x308B, 0x308C, 0x308D, 0x308E, 0x308F, 0x3090,
+0x3091, 0x3092, 0x3093, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+{ /* category 05 */
+0x30A1, 0x30A2, 0x30A3, 0x30A4, 0x30A5, 0x30A6, 0x30A7, 0x30A8,
+0x30A9, 0x30AA, 0x30AB, 0x30AC, 0x30AD, 0x30AE, 0x30AF, 0x30B0,
+0x30B1, 0x30B2, 0x30B3, 0x30B4, 0x30B5, 0x30B6, 0x30B7, 0x30B8,
+0x30B9, 0x30BA, 0x30BB, 0x30BC, 0x30BD, 0x30BE, 0x30BF, 0x30C0,
+0x30C1, 0x30C2, 0x30C3, 0x30C4, 0x30C5, 0x30C6, 0x30C7, 0x30C8,
+0x30C9, 0x30CA, 0x30CB, 0x30CC, 0x30CD, 0x30CE, 0x30CF, 0x30D0,
+0x30D1, 0x30D2, 0x30D3, 0x30D4, 0x30D5, 0x30D6, 0x30D7, 0x30D8,
+0x30D9, 0x30DA, 0x30DB, 0x30DC, 0x30DD, 0x30DE, 0x30DF, 0x30E0,
+0x30E1, 0x30E2, 0x30E3, 0x30E4, 0x30E5, 0x30E6, 0x30E7, 0x30E8,
+0x30E9, 0x30EA, 0x30EB, 0x30EC, 0x30ED, 0x30EE, 0x30EF, 0x30F0,
+0x30F1, 0x30F2, 0x30F3, 0x30F4, 0x30F5, 0x30F6, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+{ /* category 06 */
+0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398,
+0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0,
+0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8,
+0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0,
+0x03C1, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+{ /* category 07 */
+0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0401, 0x0416,
+0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
+0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426,
+0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E,
+0x042F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0451, 0x0436,
+0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E,
+0x043F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446,
+0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E,
+0x044F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+{ /* category 08 */
+0x2500, 0x2502, 0x250C, 0x2510, 0x2518, 0x2514, 0x251C, 0x252C,
+0x2524, 0x2534, 0x253C, 0x2501, 0x2503, 0x250F, 0x2513, 0x251B,
+0x2517, 0x2523, 0x2533, 0x252B, 0x253B, 0x254B, 0x2520, 0x252F,
+0x2528, 0x2537, 0x253F, 0x251D, 0x2530, 0x2525, 0x2538, 0x2542,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+{ /* category 09 */
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+{ /* category 10 */
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+{ /* category 11 */
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+{ /* category 12 */
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+{ /* category 13 */
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+{ /* category 14 */
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+{ /* category 15 */
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+{ /* category 16 */
+0x4E9C, 0x5516, 0x5A03, 0x963F, 0x54C0, 0x611B, 0x6328, 0x59F6,
+0x9022, 0x8475, 0x831C, 0x7A50, 0x60AA, 0x63E1, 0x6E25, 0x65ED,
+0x8466, 0x82A6, 0x9BF5, 0x6893, 0x5727, 0x65A1, 0x6271, 0x5B9B,
+0x59D0, 0x867B, 0x98F4, 0x7D62, 0x7DBE, 0x9B8E, 0x6216, 0x7C9F,
+0x88B7, 0x5B89, 0x5EB5, 0x6309, 0x6697, 0x6848, 0x95C7, 0x978D,
+0x674F, 0x4EE5, 0x4F0A, 0x4F4D, 0x4F9D, 0x5049, 0x56F2, 0x5937,
+0x59D4, 0x5A01, 0x5C09, 0x60DF, 0x610F, 0x6170, 0x6613, 0x6905,
+0x70BA, 0x754F, 0x7570, 0x79FB, 0x7DAD, 0x7DEF, 0x80C3, 0x840E,
+0x8863, 0x8B02, 0x9055, 0x907A, 0x533B, 0x4E95, 0x4EA5, 0x57DF,
+0x80B2, 0x90C1, 0x78EF, 0x4E00, 0x58F1, 0x6EA2, 0x9038, 0x7A32,
+0x8328, 0x828B, 0x9C2F, 0x5141, 0x5370, 0x54BD, 0x54E1, 0x56E0,
+0x59FB, 0x5F15, 0x98F2, 0x6DEB, 0x80E4, 0x852D},
+{ /* category 17 */
+0x9662, 0x9670, 0x96A0, 0x97FB, 0x540B, 0x53F3, 0x5B87, 0x70CF,
+0x7FBD, 0x8FC2, 0x96E8, 0x536F, 0x9D5C, 0x7ABA, 0x4E11, 0x7893,
+0x81FC, 0x6E26, 0x5618, 0x5504, 0x6B1D, 0x851A, 0x9C3B, 0x59E5,
+0x53A9, 0x6D66, 0x74DC, 0x958F, 0x5642, 0x4E91, 0x904B, 0x96F2,
+0x834F, 0x990C, 0x53E1, 0x55B6, 0x5B30, 0x5F71, 0x6620, 0x66F3,
+0x6804, 0x6C38, 0x6CF3, 0x6D29, 0x745B, 0x76C8, 0x7A4E, 0x9834,
+0x82F1, 0x885B, 0x8A60, 0x92ED, 0x6DB2, 0x75AB, 0x76CA, 0x99C5,
+0x60A6, 0x8B01, 0x8D8A, 0x95B2, 0x698E, 0x53AD, 0x5186, 0x5712,
+0x5830, 0x5944, 0x5BB4, 0x5EF6, 0x6028, 0x63A9, 0x63F4, 0x6CBF,
+0x6F14, 0x708E, 0x7114, 0x7159, 0x71D5, 0x733F, 0x7E01, 0x8276,
+0x82D1, 0x8597, 0x9060, 0x925B, 0x9D1B, 0x5869, 0x65BC, 0x6C5A,
+0x7525, 0x51F9, 0x592E, 0x5965, 0x5F80, 0x5FDC},
+{ /* category 18 */
+0x62BC, 0x65FA, 0x6A2A, 0x6B27, 0x6BB4, 0x738B, 0x7FC1, 0x8956,
+0x9D2C, 0x9D0E, 0x9EC4, 0x5CA1, 0x6C96, 0x837B, 0x5104, 0x5C4B,
+0x61B6, 0x81C6, 0x6876, 0x7261, 0x4E59, 0x4FFA, 0x5378, 0x6069,
+0x6E29, 0x7A4F, 0x97F3, 0x4E0B, 0x5316, 0x4EEE, 0x4F55, 0x4F3D,
+0x4FA1, 0x4F73, 0x52A0, 0x53EF, 0x5609, 0x590F, 0x5AC1, 0x5BB6,
+0x5BE1, 0x79D1, 0x6687, 0x679C, 0x67B6, 0x6B4C, 0x6CB3, 0x706B,
+0x73C2, 0x798D, 0x79BE, 0x7A3C, 0x7B87, 0x82B1, 0x82DB, 0x8304,
+0x8377, 0x83EF, 0x83D3, 0x8766, 0x8AB2, 0x5629, 0x8CA8, 0x8FE6,
+0x904E, 0x971E, 0x868A, 0x4FC4, 0x5CE8, 0x6211, 0x7259, 0x753B,
+0x81E5, 0x82BD, 0x86FE, 0x8CC0, 0x96C5, 0x9913, 0x99D5, 0x4ECB,
+0x4F1A, 0x89E3, 0x56DE, 0x584A, 0x58CA, 0x5EFB, 0x5FEB, 0x602A,
+0x6094, 0x6062, 0x61D0, 0x6212, 0x62D0, 0x6539},
+{ /* category 19 */
+0x9B41, 0x6666, 0x68B0, 0x6D77, 0x7070, 0x754C, 0x7686, 0x7D75,
+0x82A5, 0x87F9, 0x958B, 0x968E, 0x8C9D, 0x51F1, 0x52BE, 0x5916,
+0x54B3, 0x5BB3, 0x5D16, 0x6168, 0x6982, 0x6DAF, 0x788D, 0x84CB,
+0x8857, 0x8A72, 0x93A7, 0x9AB8, 0x6D6C, 0x99A8, 0x86D9, 0x57A3,
+0x67FF, 0x86CE, 0x920E, 0x5283, 0x5687, 0x5404, 0x5ED3, 0x62E1,
+0x64B9, 0x683C, 0x6838, 0x6BBB, 0x7372, 0x78BA, 0x7A6B, 0x899A,
+0x89D2, 0x8D6B, 0x8F03, 0x90ED, 0x95A3, 0x9694, 0x9769, 0x5B66,
+0x5CB3, 0x697D, 0x984D, 0x984E, 0x639B, 0x7B20, 0x6A2B, 0x6A7F,
+0x68B6, 0x9C0D, 0x6F5F, 0x5272, 0x559D, 0x6070, 0x62EC, 0x6D3B,
+0x6E07, 0x6ED1, 0x845B, 0x8910, 0x8F44, 0x4E14, 0x9C39, 0x53F6,
+0x691B, 0x6A3A, 0x9784, 0x682A, 0x515C, 0x7AC3, 0x84B2, 0x91DC,
+0x938C, 0x565B, 0x9D28, 0x6822, 0x8305, 0x8431},
+{ /* category 20 */
+0x7CA5, 0x5208, 0x82C5, 0x74E6, 0x4E7E, 0x4F83, 0x51A0, 0x5BD2,
+0x520A, 0x52D8, 0x52E7, 0x5DFB, 0x559A, 0x582A, 0x59E6, 0x5B8C,
+0x5B98, 0x5BDB, 0x5E72, 0x5E79, 0x60A3, 0x611F, 0x6163, 0x61BE,
+0x63DB, 0x6562, 0x67D1, 0x6853, 0x68FA, 0x6B3E, 0x6B53, 0x6C57,
+0x6F22, 0x6F97, 0x6F45, 0x74B0, 0x7518, 0x76E3, 0x770B, 0x7AFF,
+0x7BA1, 0x7C21, 0x7DE9, 0x7F36, 0x7FF0, 0x809D, 0x8266, 0x839E,
+0x89B3, 0x8ACC, 0x8CAB, 0x9084, 0x9451, 0x9593, 0x9591, 0x95A2,
+0x9665, 0x97D3, 0x9928, 0x8218, 0x4E38, 0x542B, 0x5CB8, 0x5DCC,
+0x73A9, 0x764C, 0x773C, 0x5CA9, 0x7FEB, 0x8D0B, 0x96C1, 0x9811,
+0x9854, 0x9858, 0x4F01, 0x4F0E, 0x5371, 0x559C, 0x5668, 0x57FA,
+0x5947, 0x5B09, 0x5BC4, 0x5C90, 0x5E0C, 0x5E7E, 0x5FCC, 0x63EE,
+0x673A, 0x65D7, 0x65E2, 0x671F, 0x68CB, 0x68C4},
+{ /* category 21 */
+0x6A5F, 0x5E30, 0x6BC5, 0x6C17, 0x6C7D, 0x757F, 0x7948, 0x5B63,
+0x7A00, 0x7D00, 0x5FBD, 0x898F, 0x8A18, 0x8CB4, 0x8D77, 0x8ECC,
+0x8F1D, 0x98E2, 0x9A0E, 0x9B3C, 0x4E80, 0x507D, 0x5100, 0x5993,
+0x5B9C, 0x622F, 0x6280, 0x64EC, 0x6B3A, 0x72A0, 0x7591, 0x7947,
+0x7FA9, 0x87FB, 0x8ABC, 0x8B70, 0x63AC, 0x83CA, 0x97A0, 0x5409,
+0x5403, 0x55AB, 0x6854, 0x6A58, 0x8A70, 0x7827, 0x6775, 0x9ECD,
+0x5374, 0x5BA2, 0x811A, 0x8650, 0x9006, 0x4E18, 0x4E45, 0x4EC7,
+0x4F11, 0x53CA, 0x5438, 0x5BAE, 0x5F13, 0x6025, 0x6551, 0x673D,
+0x6C42, 0x6C72, 0x6CE3, 0x7078, 0x7403, 0x7A76, 0x7AAE, 0x7B08,
+0x7D1A, 0x7CFE, 0x7D66, 0x65E7, 0x725B, 0x53BB, 0x5C45, 0x5DE8,
+0x62D2, 0x62E0, 0x6319, 0x6E20, 0x865A, 0x8A31, 0x8DDD, 0x92F8,
+0x6F01, 0x79A6, 0x9B5A, 0x4EA8, 0x4EAB, 0x4EAC},
+{ /* category 22 */
+0x4F9B, 0x4FA0, 0x50D1, 0x5147, 0x7AF6, 0x5171, 0x51F6, 0x5354,
+0x5321, 0x537F, 0x53EB, 0x55AC, 0x5883, 0x5CE1, 0x5F37, 0x5F4A,
+0x602F, 0x6050, 0x606D, 0x631F, 0x6559, 0x6A4B, 0x6CC1, 0x72C2,
+0x72ED, 0x77EF, 0x80F8, 0x8105, 0x8208, 0x854E, 0x90F7, 0x93E1,
+0x97FF, 0x9957, 0x9A5A, 0x4EF0, 0x51DD, 0x5C2D, 0x6681, 0x696D,
+0x5C40, 0x66F2, 0x6975, 0x7389, 0x6850, 0x7C81, 0x50C5, 0x52E4,
+0x5747, 0x5DFE, 0x9326, 0x65A4, 0x6B23, 0x6B3D, 0x7434, 0x7981,
+0x79BD, 0x7B4B, 0x7DCA, 0x82B9, 0x83CC, 0x887F, 0x895F, 0x8B39,
+0x8FD1, 0x91D1, 0x541F, 0x9280, 0x4E5D, 0x5036, 0x53E5, 0x533A,
+0x72D7, 0x7396, 0x77E9, 0x82E6, 0x8EAF, 0x99C6, 0x99C8, 0x99D2,
+0x5177, 0x611A, 0x865E, 0x55B0, 0x7A7A, 0x5076, 0x5BD3, 0x9047,
+0x9685, 0x4E32, 0x6ADB, 0x91E7, 0x5C51, 0x5C48},
+{ /* category 23 */
+0x6398, 0x7A9F, 0x6C93, 0x9774, 0x8F61, 0x7AAA, 0x718A, 0x9688,
+0x7C82, 0x6817, 0x7E70, 0x6851, 0x936C, 0x52F2, 0x541B, 0x85AB,
+0x8A13, 0x7FA4, 0x8ECD, 0x90E1, 0x5366, 0x8888, 0x7941, 0x4FC2,
+0x50BE, 0x5211, 0x5144, 0x5553, 0x572D, 0x73EA, 0x578B, 0x5951,
+0x5F62, 0x5F84, 0x6075, 0x6176, 0x6167, 0x61A9, 0x63B2, 0x643A,
+0x656C, 0x666F, 0x6842, 0x6E13, 0x7566, 0x7A3D, 0x7CFB, 0x7D4C,
+0x7D99, 0x7E4B, 0x7F6B, 0x830E, 0x834A, 0x86CD, 0x8A08, 0x8A63,
+0x8B66, 0x8EFD, 0x981A, 0x9D8F, 0x82B8, 0x8FCE, 0x9BE8, 0x5287,
+0x621F, 0x6483, 0x6FC0, 0x9699, 0x6841, 0x5091, 0x6B20, 0x6C7A,
+0x6F54, 0x7A74, 0x7D50, 0x8840, 0x8A23, 0x6708, 0x4EF6, 0x5039,
+0x5026, 0x5065, 0x517C, 0x5238, 0x5263, 0x55A7, 0x570F, 0x5805,
+0x5ACC, 0x5EFA, 0x61B2, 0x61F8, 0x62F3, 0x6372},
+{ /* category 24 */
+0x691C, 0x6A29, 0x727D, 0x72AC, 0x732E, 0x7814, 0x786F, 0x7D79,
+0x770C, 0x80A9, 0x898B, 0x8B19, 0x8CE2, 0x8ED2, 0x9063, 0x9375,
+0x967A, 0x9855, 0x9A13, 0x9E78, 0x5143, 0x539F, 0x53B3, 0x5E7B,
+0x5F26, 0x6E1B, 0x6E90, 0x7384, 0x73FE, 0x7D43, 0x8237, 0x8A00,
+0x8AFA, 0x9650, 0x4E4E, 0x500B, 0x53E4, 0x547C, 0x56FA, 0x59D1,
+0x5B64, 0x5DF1, 0x5EAB, 0x5F27, 0x6238, 0x6545, 0x67AF, 0x6E56,
+0x72D0, 0x7CCA, 0x88B4, 0x80A1, 0x80E1, 0x83F0, 0x864E, 0x8A87,
+0x8DE8, 0x9237, 0x96C7, 0x9867, 0x9F13, 0x4E94, 0x4E92, 0x4F0D,
+0x5348, 0x5449, 0x543E, 0x5A2F, 0x5F8C, 0x5FA1, 0x609F, 0x68A7,
+0x6A8E, 0x745A, 0x7881, 0x8A9E, 0x8AA4, 0x8B77, 0x9190, 0x4E5E,
+0x9BC9, 0x4EA4, 0x4F7C, 0x4FAF, 0x5019, 0x5016, 0x5149, 0x516C,
+0x529F, 0x52B9, 0x52FE, 0x539A, 0x53E3, 0x5411},
+{ /* category 25 */
+0x540E, 0x5589, 0x5751, 0x57A2, 0x597D, 0x5B54, 0x5B5D, 0x5B8F,
+0x5DE5, 0x5DE7, 0x5DF7, 0x5E78, 0x5E83, 0x5E9A, 0x5EB7, 0x5F18,
+0x6052, 0x614C, 0x6297, 0x62D8, 0x63A7, 0x653B, 0x6602, 0x6643,
+0x66F4, 0x676D, 0x6821, 0x6897, 0x69CB, 0x6C5F, 0x6D2A, 0x6D69,
+0x6E2F, 0x6E9D, 0x7532, 0x7687, 0x786C, 0x7A3F, 0x7CE0, 0x7D05,
+0x7D18, 0x7D5E, 0x7DB1, 0x8015, 0x8003, 0x80AF, 0x80B1, 0x8154,
+0x818F, 0x822A, 0x8352, 0x884C, 0x8861, 0x8B1B, 0x8CA2, 0x8CFC,
+0x90CA, 0x9175, 0x9271, 0x783F, 0x92FC, 0x95A4, 0x964D, 0x9805,
+0x9999, 0x9AD8, 0x9D3B, 0x525B, 0x52AB, 0x53F7, 0x5408, 0x58D5,
+0x62F7, 0x6FE0, 0x8C6A, 0x8F5F, 0x9EB9, 0x514B, 0x523B, 0x544A,
+0x56FD, 0x7A40, 0x9177, 0x9D60, 0x9ED2, 0x7344, 0x6F09, 0x8170,
+0x7511, 0x5FFD, 0x60DA, 0x9AA8, 0x72DB, 0x8FBC},
+{ /* category 26 */
+0x6B64, 0x9803, 0x4ECA, 0x56F0, 0x5764, 0x58BE, 0x5A5A, 0x6068,
+0x61C7, 0x660F, 0x6606, 0x6839, 0x68B1, 0x6DF7, 0x75D5, 0x7D3A,
+0x826E, 0x9B42, 0x4E9B, 0x4F50, 0x53C9, 0x5506, 0x5D6F, 0x5DE6,
+0x5DEE, 0x67FB, 0x6C99, 0x7473, 0x7802, 0x8A50, 0x9396, 0x88DF,
+0x5750, 0x5EA7, 0x632B, 0x50B5, 0x50AC, 0x518D, 0x6700, 0x54C9,
+0x585E, 0x59BB, 0x5BB0, 0x5F69, 0x624D, 0x63A1, 0x683D, 0x6B73,
+0x6E08, 0x707D, 0x91C7, 0x7280, 0x7815, 0x7826, 0x796D, 0x658E,
+0x7D30, 0x83DC, 0x88C1, 0x8F09, 0x969B, 0x5264, 0x5728, 0x6750,
+0x7F6A, 0x8CA1, 0x51B4, 0x5742, 0x962A, 0x583A, 0x698A, 0x80B4,
+0x54B2, 0x5D0E, 0x57FC, 0x7895, 0x9DFA, 0x4F5C, 0x524A, 0x548B,
+0x643E, 0x6628, 0x6714, 0x67F5, 0x7A84, 0x7B56, 0x7D22, 0x932F,
+0x685C, 0x9BAD, 0x7B39, 0x5319, 0x518A, 0x5237},
+{ /* category 27 */
+0x5BDF, 0x62F6, 0x64AE, 0x64E6, 0x672D, 0x6BBA, 0x85A9, 0x96D1,
+0x7690, 0x9BD6, 0x634C, 0x9306, 0x9BAB, 0x76BF, 0x6652, 0x4E09,
+0x5098, 0x53C2, 0x5C71, 0x60E8, 0x6492, 0x6563, 0x685F, 0x71E6,
+0x73CA, 0x7523, 0x7B97, 0x7E82, 0x8695, 0x8B83, 0x8CDB, 0x9178,
+0x9910, 0x65AC, 0x66AB, 0x6B8B, 0x4ED5, 0x4ED4, 0x4F3A, 0x4F7F,
+0x523A, 0x53F8, 0x53F2, 0x55E3, 0x56DB, 0x58EB, 0x59CB, 0x59C9,
+0x59FF, 0x5B50, 0x5C4D, 0x5E02, 0x5E2B, 0x5FD7, 0x601D, 0x6307,
+0x652F, 0x5B5C, 0x65AF, 0x65BD, 0x65E8, 0x679D, 0x6B62, 0x6B7B,
+0x6C0F, 0x7345, 0x7949, 0x79C1, 0x7CF8, 0x7D19, 0x7D2B, 0x80A2,
+0x8102, 0x81F3, 0x8996, 0x8A5E, 0x8A69, 0x8A66, 0x8A8C, 0x8AEE,
+0x8CC7, 0x8CDC, 0x96CC, 0x98FC, 0x6B6F, 0x4E8B, 0x4F3C, 0x4F8D,
+0x5150, 0x5B57, 0x5BFA, 0x6148, 0x6301, 0x6642},
+{ /* category 28 */
+0x6B21, 0x6ECB, 0x6CBB, 0x723E, 0x74BD, 0x75D4, 0x78C1, 0x793A,
+0x800C, 0x8033, 0x81EA, 0x8494, 0x8F9E, 0x6C50, 0x9E7F, 0x5F0F,
+0x8B58, 0x9D2B, 0x7AFA, 0x8EF8, 0x5B8D, 0x96EB, 0x4E03, 0x53F1,
+0x57F7, 0x5931, 0x5AC9, 0x5BA4, 0x6089, 0x6E7F, 0x6F06, 0x75BE,
+0x8CEA, 0x5B9F, 0x8500, 0x7BE0, 0x5072, 0x67F4, 0x829D, 0x5C61,
+0x854A, 0x7E1E, 0x820E, 0x5199, 0x5C04, 0x6368, 0x8D66, 0x659C,
+0x716E, 0x793E, 0x7D17, 0x8005, 0x8B1D, 0x8ECA, 0x906E, 0x86C7,
+0x90AA, 0x501F, 0x52FA, 0x5C3A, 0x6753, 0x707C, 0x7235, 0x914C,
+0x91C8, 0x932B, 0x82E5, 0x5BC2, 0x5F31, 0x60F9, 0x4E3B, 0x53D6,
+0x5B88, 0x624B, 0x6731, 0x6B8A, 0x72E9, 0x73E0, 0x7A2E, 0x816B,
+0x8DA3, 0x9152, 0x9996, 0x5112, 0x53D7, 0x546A, 0x5BFF, 0x6388,
+0x6A39, 0x7DAC, 0x9700, 0x56DA, 0x53CE, 0x5468},
+{ /* category 29 */
+0x5B97, 0x5C31, 0x5DDE, 0x4FEE, 0x6101, 0x62FE, 0x6D32, 0x79C0,
+0x79CB, 0x7D42, 0x7E4D, 0x7FD2, 0x81ED, 0x821F, 0x8490, 0x8846,
+0x8972, 0x8B90, 0x8E74, 0x8F2F, 0x9031, 0x914B, 0x916C, 0x96C6,
+0x919C, 0x4EC0, 0x4F4F, 0x5145, 0x5341, 0x5F93, 0x620E, 0x67D4,
+0x6C41, 0x6E0B, 0x7363, 0x7E26, 0x91CD, 0x9283, 0x53D4, 0x5919,
+0x5BBF, 0x6DD1, 0x795D, 0x7E2E, 0x7C9B, 0x587E, 0x719F, 0x51FA,
+0x8853, 0x8FF0, 0x4FCA, 0x5CFB, 0x6625, 0x77AC, 0x7AE3, 0x821C,
+0x99FF, 0x51C6, 0x5FAA, 0x65EC, 0x696F, 0x6B89, 0x6DF3, 0x6E96,
+0x6F64, 0x76FE, 0x7D14, 0x5DE1, 0x9075, 0x9187, 0x9806, 0x51E6,
+0x521D, 0x6240, 0x6691, 0x66D9, 0x6E1A, 0x5EB6, 0x7DD2, 0x7F72,
+0x66F8, 0x85AF, 0x85F7, 0x8AF8, 0x52A9, 0x53D9, 0x5973, 0x5E8F,
+0x5F90, 0x6055, 0x92E4, 0x9664, 0x50B7, 0x511F},
+{ /* category 30 */
+0x52DD, 0x5320, 0x5347, 0x53EC, 0x54E8, 0x5546, 0x5531, 0x5617,
+0x5968, 0x59BE, 0x5A3C, 0x5BB5, 0x5C06, 0x5C0F, 0x5C11, 0x5C1A,
+0x5E84, 0x5E8A, 0x5EE0, 0x5F70, 0x627F, 0x6284, 0x62DB, 0x638C,
+0x6377, 0x6607, 0x660C, 0x662D, 0x6676, 0x677E, 0x68A2, 0x6A1F,
+0x6A35, 0x6CBC, 0x6D88, 0x6E09, 0x6E58, 0x713C, 0x7126, 0x7167,
+0x75C7, 0x7701, 0x785D, 0x7901, 0x7965, 0x79F0, 0x7AE0, 0x7B11,
+0x7CA7, 0x7D39, 0x8096, 0x83D6, 0x848B, 0x8549, 0x885D, 0x88F3,
+0x8A1F, 0x8A3C, 0x8A54, 0x8A73, 0x8C61, 0x8CDE, 0x91A4, 0x9266,
+0x937E, 0x9418, 0x969C, 0x9798, 0x4E0A, 0x4E08, 0x4E1E, 0x4E57,
+0x5197, 0x5270, 0x57CE, 0x5834, 0x58CC, 0x5B22, 0x5E38, 0x60C5,
+0x64FE, 0x6761, 0x6756, 0x6D44, 0x72B6, 0x7573, 0x7A63, 0x84B8,
+0x8B72, 0x91B8, 0x9320, 0x5631, 0x57F4, 0x98FE},
+{ /* category 31 */
+0x62ED, 0x690D, 0x6B96, 0x71ED, 0x7E54, 0x8077, 0x8272, 0x89E6,
+0x98DF, 0x8755, 0x8FB1, 0x5C3B, 0x4F38, 0x4FE1, 0x4FB5, 0x5507,
+0x5A20, 0x5BDD, 0x5BE9, 0x5FC3, 0x614E, 0x632F, 0x65B0, 0x664B,
+0x68EE, 0x699B, 0x6D78, 0x6DF1, 0x7533, 0x75B9, 0x771F, 0x795E,
+0x79E6, 0x7D33, 0x81E3, 0x82AF, 0x85AA, 0x89AA, 0x8A3A, 0x8EAB,
+0x8F9B, 0x9032, 0x91DD, 0x9707, 0x4EBA, 0x4EC1, 0x5203, 0x5875,
+0x58EC, 0x5C0B, 0x751A, 0x5C3D, 0x814E, 0x8A0A, 0x8FC5, 0x9663,
+0x976D, 0x7B25, 0x8ACF, 0x9808, 0x9162, 0x56F3, 0x53A8, 0x9017,
+0x5439, 0x5782, 0x5E25, 0x63A8, 0x6C34, 0x708A, 0x7761, 0x7C8B,
+0x7FE0, 0x8870, 0x9042, 0x9154, 0x9310, 0x9318, 0x968F, 0x745E,
+0x9AC4, 0x5D07, 0x5D69, 0x6570, 0x67A2, 0x8DA8, 0x96DB, 0x636E,
+0x6749, 0x6919, 0x83C5, 0x9817, 0x96C0, 0x88FE},
+{ /* category 32 */
+0x6F84, 0x647A, 0x5BF8, 0x4E16, 0x702C, 0x755D, 0x662F, 0x51C4,
+0x5236, 0x52E2, 0x59D3, 0x5F81, 0x6027, 0x6210, 0x653F, 0x6574,
+0x661F, 0x6674, 0x68F2, 0x6816, 0x6B63, 0x6E05, 0x7272, 0x751F,
+0x76DB, 0x7CBE, 0x8056, 0x58F0, 0x88FD, 0x897F, 0x8AA0, 0x8A93,
+0x8ACB, 0x901D, 0x9192, 0x9752, 0x9759, 0x6589, 0x7A0E, 0x8106,
+0x96BB, 0x5E2D, 0x60DC, 0x621A, 0x65A5, 0x6614, 0x6790, 0x77F3,
+0x7A4D, 0x7C4D, 0x7E3E, 0x810A, 0x8CAC, 0x8D64, 0x8DE1, 0x8E5F,
+0x78A9, 0x5207, 0x62D9, 0x63A5, 0x6442, 0x6298, 0x8A2D, 0x7A83,
+0x7BC0, 0x8AAC, 0x96EA, 0x7D76, 0x820C, 0x8749, 0x4ED9, 0x5148,
+0x5343, 0x5360, 0x5BA3, 0x5C02, 0x5C16, 0x5DDD, 0x6226, 0x6247,
+0x64B0, 0x6813, 0x6834, 0x6CC9, 0x6D45, 0x6D17, 0x67D3, 0x6F5C,
+0x714E, 0x717D, 0x65CB, 0x7A7F, 0x7BAD, 0x7DDA},
+{ /* category 33 */
+0x7E4A, 0x7FA8, 0x817A, 0x821B, 0x8239, 0x85A6, 0x8A6E, 0x8CCE,
+0x8DF5, 0x9078, 0x9077, 0x92AD, 0x9291, 0x9583, 0x9BAE, 0x524D,
+0x5584, 0x6F38, 0x7136, 0x5168, 0x7985, 0x7E55, 0x81B3, 0x7CCE,
+0x564C, 0x5851, 0x5CA8, 0x63AA, 0x66FE, 0x66FD, 0x695A, 0x72D9,
+0x758F, 0x758E, 0x790E, 0x7956, 0x79DF, 0x7C97, 0x7D20, 0x7D44,
+0x8607, 0x8A34, 0x963B, 0x9061, 0x9F20, 0x50E7, 0x5275, 0x53CC,
+0x53E2, 0x5009, 0x55AA, 0x58EE, 0x594F, 0x723D, 0x5B8B, 0x5C64,
+0x531D, 0x60E3, 0x60F3, 0x635C, 0x6383, 0x633F, 0x63BB, 0x64CD,
+0x65E9, 0x66F9, 0x5DE3, 0x69CD, 0x69FD, 0x6F15, 0x71E5, 0x4E89,
+0x75E9, 0x76F8, 0x7A93, 0x7CDF, 0x7DCF, 0x7D9C, 0x8061, 0x8349,
+0x8358, 0x846C, 0x84BC, 0x85FB, 0x88C5, 0x8D70, 0x9001, 0x906D,
+0x9397, 0x971C, 0x9A12, 0x50CF, 0x5897, 0x618E},
+{ /* category 34 */
+0x81D3, 0x8535, 0x8D08, 0x9020, 0x4FC3, 0x5074, 0x5247, 0x5373,
+0x606F, 0x6349, 0x675F, 0x6E2C, 0x8DB3, 0x901F, 0x4FD7, 0x5C5E,
+0x8CCA, 0x65CF, 0x7D9A, 0x5352, 0x8896, 0x5176, 0x63C3, 0x5B58,
+0x5B6B, 0x5C0A, 0x640D, 0x6751, 0x905C, 0x4ED6, 0x591A, 0x592A,
+0x6C70, 0x8A51, 0x553E, 0x5815, 0x59A5, 0x60F0, 0x6253, 0x67C1,
+0x8235, 0x6955, 0x9640, 0x99C4, 0x9A28, 0x4F53, 0x5806, 0x5BFE,
+0x8010, 0x5CB1, 0x5E2F, 0x5F85, 0x6020, 0x614B, 0x6234, 0x66FF,
+0x6CF0, 0x6EDE, 0x80CE, 0x817F, 0x82D4, 0x888B, 0x8CB8, 0x9000,
+0x902E, 0x968A, 0x9EDB, 0x9BDB, 0x4EE3, 0x53F0, 0x5927, 0x7B2C,
+0x918D, 0x984C, 0x9DF9, 0x6EDD, 0x7027, 0x5353, 0x5544, 0x5B85,
+0x6258, 0x629E, 0x62D3, 0x6CA2, 0x6FEF, 0x7422, 0x8A17, 0x9438,
+0x6FC1, 0x8AFE, 0x8338, 0x51E7, 0x86F8, 0x53EA},
+{ /* category 35 */
+0x53E9, 0x4F46, 0x9054, 0x8FB0, 0x596A, 0x8131, 0x5DFD, 0x7AEA,
+0x8FBF, 0x68DA, 0x8C37, 0x72F8, 0x9C48, 0x6A3D, 0x8AB0, 0x4E39,
+0x5358, 0x5606, 0x5766, 0x62C5, 0x63A2, 0x65E6, 0x6B4E, 0x6DE1,
+0x6E5B, 0x70AD, 0x77ED, 0x7AEF, 0x7BAA, 0x7DBB, 0x803D, 0x80C6,
+0x86CB, 0x8A95, 0x935B, 0x56E3, 0x58C7, 0x5F3E, 0x65AD, 0x6696,
+0x6A80, 0x6BB5, 0x7537, 0x8AC7, 0x5024, 0x77E5, 0x5730, 0x5F1B,
+0x6065, 0x667A, 0x6C60, 0x75F4, 0x7A1A, 0x7F6E, 0x81F4, 0x8718,
+0x9045, 0x99B3, 0x7BC9, 0x755C, 0x7AF9, 0x7B51, 0x84C4, 0x9010,
+0x79E9, 0x7A92, 0x8336, 0x5AE1, 0x7740, 0x4E2D, 0x4EF2, 0x5B99,
+0x5FE0, 0x62BD, 0x663C, 0x67F1, 0x6CE8, 0x866B, 0x8877, 0x8A3B,
+0x914E, 0x92F3, 0x99D0, 0x6A17, 0x7026, 0x732A, 0x82E7, 0x8457,
+0x8CAF, 0x4E01, 0x5146, 0x51CB, 0x558B, 0x5BF5},
+{ /* category 36 */
+0x5E16, 0x5E33, 0x5E81, 0x5F14, 0x5F35, 0x5F6B, 0x5FB4, 0x61F2,
+0x6311, 0x66A2, 0x671D, 0x6F6E, 0x7252, 0x753A, 0x773A, 0x8074,
+0x8139, 0x8178, 0x8776, 0x8ABF, 0x8ADC, 0x8D85, 0x8DF3, 0x929A,
+0x9577, 0x9802, 0x9CE5, 0x52C5, 0x6357, 0x76F4, 0x6715, 0x6C88,
+0x73CD, 0x8CC3, 0x93AE, 0x9673, 0x6D25, 0x589C, 0x690E, 0x69CC,
+0x8FFD, 0x939A, 0x75DB, 0x901A, 0x585A, 0x6802, 0x63B4, 0x69FB,
+0x4F43, 0x6F2C, 0x67D8, 0x8FBB, 0x8526, 0x7DB4, 0x9354, 0x693F,
+0x6F70, 0x576A, 0x58F7, 0x5B2C, 0x7D2C, 0x722A, 0x540A, 0x91E3,
+0x9DB4, 0x4EAD, 0x4F4E, 0x505C, 0x5075, 0x5243, 0x8C9E, 0x5448,
+0x5824, 0x5B9A, 0x5E1D, 0x5E95, 0x5EAD, 0x5EF7, 0x5F1F, 0x608C,
+0x62B5, 0x633A, 0x63D0, 0x68AF, 0x6C40, 0x7887, 0x798E, 0x7A0B,
+0x7DE0, 0x8247, 0x8A02, 0x8AE6, 0x8E44, 0x9013},
+{ /* category 37 */
+0x90B8, 0x912D, 0x91D8, 0x9F0E, 0x6CE5, 0x6458, 0x64E2, 0x6575,
+0x6EF4, 0x7684, 0x7B1B, 0x9069, 0x93D1, 0x6EBA, 0x54F2, 0x5FB9,
+0x64A4, 0x8F4D, 0x8FED, 0x9244, 0x5178, 0x586B, 0x5929, 0x5C55,
+0x5E97, 0x6DFB, 0x7E8F, 0x751C, 0x8CBC, 0x8EE2, 0x985B, 0x70B9,
+0x4F1D, 0x6BBF, 0x6FB1, 0x7530, 0x96FB, 0x514E, 0x5410, 0x5835,
+0x5857, 0x59AC, 0x5C60, 0x5F92, 0x6597, 0x675C, 0x6E21, 0x767B,
+0x83DF, 0x8CED, 0x9014, 0x90FD, 0x934D, 0x7825, 0x783A, 0x52AA,
+0x5EA6, 0x571F, 0x5974, 0x6012, 0x5012, 0x515A, 0x51AC, 0x51CD,
+0x5200, 0x5510, 0x5854, 0x5858, 0x5957, 0x5B95, 0x5CF6, 0x5D8B,
+0x60BC, 0x6295, 0x642D, 0x6771, 0x6843, 0x68BC, 0x68DF, 0x76D7,
+0x6DD8, 0x6E6F, 0x6D9B, 0x706F, 0x71C8, 0x5F53, 0x75D8, 0x7977,
+0x7B49, 0x7B54, 0x7B52, 0x7CD6, 0x7D71, 0x5230},
+{ /* category 38 */
+0x8463, 0x8569, 0x85E4, 0x8A0E, 0x8B04, 0x8C46, 0x8E0F, 0x9003,
+0x900F, 0x9419, 0x9676, 0x982D, 0x9A30, 0x95D8, 0x50CD, 0x52D5,
+0x540C, 0x5802, 0x5C0E, 0x61A7, 0x649E, 0x6D1E, 0x77B3, 0x7AE5,
+0x80F4, 0x8404, 0x9053, 0x9285, 0x5CE0, 0x9D07, 0x533F, 0x5F97,
+0x5FB3, 0x6D9C, 0x7279, 0x7763, 0x79BF, 0x7BE4, 0x6BD2, 0x72EC,
+0x8AAD, 0x6803, 0x6A61, 0x51F8, 0x7A81, 0x6934, 0x5C4A, 0x9CF6,
+0x82EB, 0x5BC5, 0x9149, 0x701E, 0x5678, 0x5C6F, 0x60C7, 0x6566,
+0x6C8C, 0x8C5A, 0x9041, 0x9813, 0x5451, 0x66C7, 0x920D, 0x5948,
+0x90A3, 0x5185, 0x4E4D, 0x51EA, 0x8599, 0x8B0E, 0x7058, 0x637A,
+0x934B, 0x6962, 0x99B4, 0x7E04, 0x7577, 0x5357, 0x6960, 0x8EDF,
+0x96E3, 0x6C5D, 0x4E8C, 0x5C3C, 0x5F10, 0x8FE9, 0x5302, 0x8CD1,
+0x8089, 0x8679, 0x5EFF, 0x65E5, 0x4E73, 0x5165},
+{ /* category 39 */
+0x5982, 0x5C3F, 0x97EE, 0x4EFB, 0x598A, 0x5FCD, 0x8A8D, 0x6FE1,
+0x79B0, 0x7962, 0x5BE7, 0x8471, 0x732B, 0x71B1, 0x5E74, 0x5FF5,
+0x637B, 0x649A, 0x71C3, 0x7C98, 0x4E43, 0x5EFC, 0x4E4B, 0x57DC,
+0x56A2, 0x60A9, 0x6FC3, 0x7D0D, 0x80FD, 0x8133, 0x81BF, 0x8FB2,
+0x8997, 0x86A4, 0x5DF4, 0x628A, 0x64AD, 0x8987, 0x6777, 0x6CE2,
+0x6D3E, 0x7436, 0x7834, 0x5A46, 0x7F75, 0x82AD, 0x99AC, 0x4FF3,
+0x5EC3, 0x62DD, 0x6392, 0x6557, 0x676F, 0x76C3, 0x724C, 0x80CC,
+0x80BA, 0x8F29, 0x914D, 0x500D, 0x57F9, 0x5A92, 0x6885, 0x6973,
+0x7164, 0x72FD, 0x8CB7, 0x58F2, 0x8CE0, 0x966A, 0x9019, 0x877F,
+0x79E4, 0x77E7, 0x8429, 0x4F2F, 0x5265, 0x535A, 0x62CD, 0x67CF,
+0x6CCA, 0x767D, 0x7B94, 0x7C95, 0x8236, 0x8584, 0x8FEB, 0x66DD,
+0x6F20, 0x7206, 0x7E1B, 0x83AB, 0x99C1, 0x9EA6},
+{ /* category 40 */
+0x51FD, 0x7BB1, 0x7872, 0x7BB8, 0x8087, 0x7B48, 0x6AE8, 0x5E61,
+0x808C, 0x7551, 0x7560, 0x516B, 0x9262, 0x6E8C, 0x767A, 0x9197,
+0x9AEA, 0x4F10, 0x7F70, 0x629C, 0x7B4F, 0x95A5, 0x9CE9, 0x567A,
+0x5859, 0x86E4, 0x96BC, 0x4F34, 0x5224, 0x534A, 0x53CD, 0x53DB,
+0x5E06, 0x642C, 0x6591, 0x677F, 0x6C3E, 0x6C4E, 0x7248, 0x72AF,
+0x73ED, 0x7554, 0x7E41, 0x822C, 0x85E9, 0x8CA9, 0x7BC4, 0x91C6,
+0x7169, 0x9812, 0x98EF, 0x633D, 0x6669, 0x756A, 0x76E4, 0x78D0,
+0x8543, 0x86EE, 0x532A, 0x5351, 0x5426, 0x5983, 0x5E87, 0x5F7C,
+0x60B2, 0x6249, 0x6279, 0x62AB, 0x6590, 0x6BD4, 0x6CCC, 0x75B2,
+0x76AE, 0x7891, 0x79D8, 0x7DCB, 0x7F77, 0x80A5, 0x88AB, 0x8AB9,
+0x8CBB, 0x907F, 0x975E, 0x98DB, 0x6A0B, 0x7C38, 0x5099, 0x5C3E,
+0x5FAE, 0x6787, 0x6BD8, 0x7435, 0x7709, 0x7F8E},
+{ /* category 41 */
+0x9F3B, 0x67CA, 0x7A17, 0x5339, 0x758B, 0x9AED, 0x5F66, 0x819D,
+0x83F1, 0x8098, 0x5F3C, 0x5FC5, 0x7562, 0x7B46, 0x903C, 0x6867,
+0x59EB, 0x5A9B, 0x7D10, 0x767E, 0x8B2C, 0x4FF5, 0x5F6A, 0x6A19,
+0x6C37, 0x6F02, 0x74E2, 0x7968, 0x8868, 0x8A55, 0x8C79, 0x5EDF,
+0x63CF, 0x75C5, 0x79D2, 0x82D7, 0x9328, 0x92F2, 0x849C, 0x86ED,
+0x9C2D, 0x54C1, 0x5F6C, 0x658C, 0x6D5C, 0x7015, 0x8CA7, 0x8CD3,
+0x983B, 0x654F, 0x74F6, 0x4E0D, 0x4ED8, 0x57E0, 0x592B, 0x5A66,
+0x5BCC, 0x51A8, 0x5E03, 0x5E9C, 0x6016, 0x6276, 0x6577, 0x65A7,
+0x666E, 0x6D6E, 0x7236, 0x7B26, 0x8150, 0x819A, 0x8299, 0x8B5C,
+0x8CA0, 0x8CE6, 0x8D74, 0x961C, 0x9644, 0x4FAE, 0x64AB, 0x6B66,
+0x821E, 0x8461, 0x856A, 0x90E8, 0x5C01, 0x6953, 0x98A8, 0x847A,
+0x8557, 0x4F0F, 0x526F, 0x5FA9, 0x5E45, 0x670D},
+{ /* category 42 */
+0x798F, 0x8179, 0x8907, 0x8986, 0x6DF5, 0x5F17, 0x6255, 0x6CB8,
+0x4ECF, 0x7269, 0x9B92, 0x5206, 0x543B, 0x5674, 0x58B3, 0x61A4,
+0x626E, 0x711A, 0x596E, 0x7C89, 0x7CDE, 0x7D1B, 0x96F0, 0x6587,
+0x805E, 0x4E19, 0x4F75, 0x5175, 0x5840, 0x5E63, 0x5E73, 0x5F0A,
+0x67C4, 0x4E26, 0x853D, 0x9589, 0x965B, 0x7C73, 0x9801, 0x50FB,
+0x58C1, 0x7656, 0x78A7, 0x5225, 0x77A5, 0x8511, 0x7B86, 0x504F,
+0x5909, 0x7247, 0x7BC7, 0x7DE8, 0x8FBA, 0x8FD4, 0x904D, 0x4FBF,
+0x52C9, 0x5A29, 0x5F01, 0x97AD, 0x4FDD, 0x8217, 0x92EA, 0x5703,
+0x6355, 0x6B69, 0x752B, 0x88DC, 0x8F14, 0x7A42, 0x52DF, 0x5893,
+0x6155, 0x620A, 0x66AE, 0x6BCD, 0x7C3F, 0x83E9, 0x5023, 0x4FF8,
+0x5305, 0x5446, 0x5831, 0x5949, 0x5B9D, 0x5CF0, 0x5CEF, 0x5D29,
+0x5E96, 0x62B1, 0x6367, 0x653E, 0x65B9, 0x670B},
+{ /* category 43 */
+0x6CD5, 0x6CE1, 0x70F9, 0x7832, 0x7E2B, 0x80DE, 0x82B3, 0x840C,
+0x84EC, 0x8702, 0x8912, 0x8A2A, 0x8C4A, 0x90A6, 0x92D2, 0x98FD,
+0x9CF3, 0x9D6C, 0x4E4F, 0x4EA1, 0x508D, 0x5256, 0x574A, 0x59A8,
+0x5E3D, 0x5FD8, 0x5FD9, 0x623F, 0x66B4, 0x671B, 0x67D0, 0x68D2,
+0x5192, 0x7D21, 0x80AA, 0x81A8, 0x8B00, 0x8C8C, 0x8CBF, 0x927E,
+0x9632, 0x5420, 0x982C, 0x5317, 0x50D5, 0x535C, 0x58A8, 0x64B2,
+0x6734, 0x7267, 0x7766, 0x7A46, 0x91E6, 0x52C3, 0x6CA1, 0x6B86,
+0x5800, 0x5E4C, 0x5954, 0x672C, 0x7FFB, 0x51E1, 0x76C6, 0x6469,
+0x78E8, 0x9B54, 0x9EBB, 0x57CB, 0x59B9, 0x6627, 0x679A, 0x6BCE,
+0x54E9, 0x69D9, 0x5E55, 0x819C, 0x6795, 0x9BAA, 0x67FE, 0x9C52,
+0x685D, 0x4EA6, 0x4FE3, 0x53C8, 0x62B9, 0x672B, 0x6CAB, 0x8FC4,
+0x4FAD, 0x7E6D, 0x9EBF, 0x4E07, 0x6162, 0x6E80},
+{ /* category 44 */
+0x6F2B, 0x8513, 0x5473, 0x672A, 0x9B45, 0x5DF3, 0x7B95, 0x5CAC,
+0x5BC6, 0x871C, 0x6E4A, 0x84D1, 0x7A14, 0x8108, 0x5999, 0x7C8D,
+0x6C11, 0x7720, 0x52D9, 0x5922, 0x7121, 0x725F, 0x77DB, 0x9727,
+0x9D61, 0x690B, 0x5A7F, 0x5A18, 0x51A5, 0x540D, 0x547D, 0x660E,
+0x76DF, 0x8FF7, 0x9298, 0x9CF4, 0x59EA, 0x725D, 0x6EC5, 0x514D,
+0x68C9, 0x7DBF, 0x7DEC, 0x9762, 0x9EBA, 0x6478, 0x6A21, 0x8302,
+0x5984, 0x5B5F, 0x6BDB, 0x731B, 0x76F2, 0x7DB2, 0x8017, 0x8499,
+0x5132, 0x6728, 0x9ED9, 0x76EE, 0x6762, 0x52FF, 0x9905, 0x5C24,
+0x623B, 0x7C7E, 0x8CB0, 0x554F, 0x60B6, 0x7D0B, 0x9580, 0x5301,
+0x4E5F, 0x51B6, 0x591C, 0x723A, 0x8036, 0x91CE, 0x5F25, 0x77E2,
+0x5384, 0x5F79, 0x7D04, 0x85AC, 0x8A33, 0x8E8D, 0x9756, 0x67F3,
+0x85AE, 0x9453, 0x6109, 0x6108, 0x6CB9, 0x7652},
+{ /* category 45 */
+0x8AED, 0x8F38, 0x552F, 0x4F51, 0x512A, 0x52C7, 0x53CB, 0x5BA5,
+0x5E7D, 0x60A0, 0x6182, 0x63D6, 0x6709, 0x67DA, 0x6E67, 0x6D8C,
+0x7336, 0x7337, 0x7531, 0x7950, 0x88D5, 0x8A98, 0x904A, 0x9091,
+0x90F5, 0x96C4, 0x878D, 0x5915, 0x4E88, 0x4F59, 0x4E0E, 0x8A89,
+0x8F3F, 0x9810, 0x50AD, 0x5E7C, 0x5996, 0x5BB9, 0x5EB8, 0x63DA,
+0x63FA, 0x64C1, 0x66DC, 0x694A, 0x69D8, 0x6D0B, 0x6EB6, 0x7194,
+0x7528, 0x7AAF, 0x7F8A, 0x8000, 0x8449, 0x84C9, 0x8981, 0x8B21,
+0x8E0A, 0x9065, 0x967D, 0x990A, 0x617E, 0x6291, 0x6B32, 0x6C83,
+0x6D74, 0x7FCC, 0x7FFC, 0x6DC0, 0x7F85, 0x87BA, 0x88F8, 0x6765,
+0x83B1, 0x983C, 0x96F7, 0x6D1B, 0x7D61, 0x843D, 0x916A, 0x4E71,
+0x5375, 0x5D50, 0x6B04, 0x6FEB, 0x85CD, 0x862D, 0x89A7, 0x5229,
+0x540F, 0x5C65, 0x674E, 0x68A8, 0x7406, 0x7483},
+{ /* category 46 */
+0x75E2, 0x88CF, 0x88E1, 0x91CC, 0x96E2, 0x9678, 0x5F8B, 0x7387,
+0x7ACB, 0x844E, 0x63A0, 0x7565, 0x5289, 0x6D41, 0x6E9C, 0x7409,
+0x7559, 0x786B, 0x7C92, 0x9686, 0x7ADC, 0x9F8D, 0x4FB6, 0x616E,
+0x65C5, 0x865C, 0x4E86, 0x4EAE, 0x50DA, 0x4E21, 0x51CC, 0x5BEE,
+0x6599, 0x6881, 0x6DBC, 0x731F, 0x7642, 0x77AD, 0x7A1C, 0x7CE7,
+0x826F, 0x8AD2, 0x907C, 0x91CF, 0x9675, 0x9818, 0x529B, 0x7DD1,
+0x502B, 0x5398, 0x6797, 0x6DCB, 0x71D0, 0x7433, 0x81E8, 0x8F2A,
+0x96A3, 0x9C57, 0x9E9F, 0x7460, 0x5841, 0x6D99, 0x7D2F, 0x985E,
+0x4EE4, 0x4F36, 0x4F8B, 0x51B7, 0x52B1, 0x5DBA, 0x601C, 0x73B2,
+0x793C, 0x82D3, 0x9234, 0x96B7, 0x96F6, 0x970A, 0x9E97, 0x9F62,
+0x66A6, 0x6B74, 0x5217, 0x52A3, 0x70C8, 0x88C2, 0x5EC9, 0x604B,
+0x6190, 0x6F23, 0x7149, 0x7C3E, 0x7DF4, 0x806F},
+{ /* category 47 */
+0x84EE, 0x9023, 0x932C, 0x5442, 0x9B6F, 0x6AD3, 0x7089, 0x8CC2,
+0x8DEF, 0x9732, 0x52B4, 0x5A41, 0x5ECA, 0x5F04, 0x6717, 0x697C,
+0x6994, 0x6D6A, 0x6F0F, 0x7262, 0x72FC, 0x7BED, 0x8001, 0x807E,
+0x874B, 0x90CE, 0x516D, 0x9E93, 0x7984, 0x808B, 0x9332, 0x8AD6,
+0x502D, 0x548C, 0x8A71, 0x6B6A, 0x8CC4, 0x8107, 0x60D1, 0x67A0,
+0x9DF2, 0x4E99, 0x4E98, 0x9C10, 0x8A6B, 0x85C1, 0x8568, 0x6900,
+0x6E7E, 0x7897, 0x8155, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+{ /* category 48 */
+0x5F0C, 0x4E10, 0x4E15, 0x4E2A, 0x4E31, 0x4E36, 0x4E3C, 0x4E3F,
+0x4E42, 0x4E56, 0x4E58, 0x4E82, 0x4E85, 0x8C6B, 0x4E8A, 0x8212,
+0x5F0D, 0x4E8E, 0x4E9E, 0x4E9F, 0x4EA0, 0x4EA2, 0x4EB0, 0x4EB3,
+0x4EB6, 0x4ECE, 0x4ECD, 0x4EC4, 0x4EC6, 0x4EC2, 0x4ED7, 0x4EDE,
+0x4EED, 0x4EDF, 0x4EF7, 0x4F09, 0x4F5A, 0x4F30, 0x4F5B, 0x4F5D,
+0x4F57, 0x4F47, 0x4F76, 0x4F88, 0x4F8F, 0x4F98, 0x4F7B, 0x4F69,
+0x4F70, 0x4F91, 0x4F6F, 0x4F86, 0x4F96, 0x5118, 0x4FD4, 0x4FDF,
+0x4FCE, 0x4FD8, 0x4FDB, 0x4FD1, 0x4FDA, 0x4FD0, 0x4FE4, 0x4FE5,
+0x501A, 0x5028, 0x5014, 0x502A, 0x5025, 0x5005, 0x4F1C, 0x4FF6,
+0x5021, 0x5029, 0x502C, 0x4FFE, 0x4FEF, 0x5011, 0x5006, 0x5043,
+0x5047, 0x6703, 0x5055, 0x5050, 0x5048, 0x505A, 0x5056, 0x506C,
+0x5078, 0x5080, 0x509A, 0x5085, 0x50B4, 0x50B2},
+{ /* category 49 */
+0x50C9, 0x50CA, 0x50B3, 0x50C2, 0x50D6, 0x50DE, 0x50E5, 0x50ED,
+0x50E3, 0x50EE, 0x50F9, 0x50F5, 0x5109, 0x5101, 0x5102, 0x5116,
+0x5115, 0x5114, 0x511A, 0x5121, 0x513A, 0x5137, 0x513C, 0x513B,
+0x513F, 0x5140, 0x5152, 0x514C, 0x5154, 0x5162, 0x7AF8, 0x5169,
+0x516A, 0x516E, 0x5180, 0x5182, 0x56D8, 0x518C, 0x5189, 0x518F,
+0x5191, 0x5193, 0x5195, 0x5196, 0x51A4, 0x51A6, 0x51A2, 0x51A9,
+0x51AA, 0x51AB, 0x51B3, 0x51B1, 0x51B2, 0x51B0, 0x51B5, 0x51BD,
+0x51C5, 0x51C9, 0x51DB, 0x51E0, 0x8655, 0x51E9, 0x51ED, 0x51F0,
+0x51F5, 0x51FE, 0x5204, 0x520B, 0x5214, 0x520E, 0x5227, 0x522A,
+0x522E, 0x5233, 0x5239, 0x524F, 0x5244, 0x524B, 0x524C, 0x525E,
+0x5254, 0x526A, 0x5274, 0x5269, 0x5273, 0x527F, 0x527D, 0x528D,
+0x5294, 0x5292, 0x5271, 0x5288, 0x5291, 0x8FA8},
+{ /* category 50 */
+0x8FA7, 0x52AC, 0x52AD, 0x52BC, 0x52B5, 0x52C1, 0x52CD, 0x52D7,
+0x52DE, 0x52E3, 0x52E6, 0x98ED, 0x52E0, 0x52F3, 0x52F5, 0x52F8,
+0x52F9, 0x5306, 0x5308, 0x7538, 0x530D, 0x5310, 0x530F, 0x5315,
+0x531A, 0x5323, 0x532F, 0x5331, 0x5333, 0x5338, 0x5340, 0x5346,
+0x5345, 0x4E17, 0x5349, 0x534D, 0x51D6, 0x535E, 0x5369, 0x536E,
+0x5918, 0x537B, 0x5377, 0x5382, 0x5396, 0x53A0, 0x53A6, 0x53A5,
+0x53AE, 0x53B0, 0x53B6, 0x53C3, 0x7C12, 0x96D9, 0x53DF, 0x66FC,
+0x71EE, 0x53EE, 0x53E8, 0x53ED, 0x53FA, 0x5401, 0x543D, 0x5440,
+0x542C, 0x542D, 0x543C, 0x542E, 0x5436, 0x5429, 0x541D, 0x544E,
+0x548F, 0x5475, 0x548E, 0x545F, 0x5471, 0x5477, 0x5470, 0x5492,
+0x547B, 0x5480, 0x5476, 0x5484, 0x5490, 0x5486, 0x54C7, 0x54A2,
+0x54B8, 0x54A5, 0x54AC, 0x54C4, 0x54C8, 0x54A8},
+{ /* category 51 */
+0x54AB, 0x54C2, 0x54A4, 0x54BE, 0x54BC, 0x54D8, 0x54E5, 0x54E6,
+0x550F, 0x5514, 0x54FD, 0x54EE, 0x54ED, 0x54FA, 0x54E2, 0x5539,
+0x5540, 0x5563, 0x554C, 0x552E, 0x555C, 0x5545, 0x5556, 0x5557,
+0x5538, 0x5533, 0x555D, 0x5599, 0x5580, 0x54AF, 0x558A, 0x559F,
+0x557B, 0x557E, 0x5598, 0x559E, 0x55AE, 0x557C, 0x5583, 0x55A9,
+0x5587, 0x55A8, 0x55DA, 0x55C5, 0x55DF, 0x55C4, 0x55DC, 0x55E4,
+0x55D4, 0x5614, 0x55F7, 0x5616, 0x55FE, 0x55FD, 0x561B, 0x55F9,
+0x564E, 0x5650, 0x71DF, 0x5634, 0x5636, 0x5632, 0x5638, 0x566B,
+0x5664, 0x562F, 0x566C, 0x566A, 0x5686, 0x5680, 0x568A, 0x56A0,
+0x5694, 0x568F, 0x56A5, 0x56AE, 0x56B6, 0x56B4, 0x56C2, 0x56BC,
+0x56C1, 0x56C3, 0x56C0, 0x56C8, 0x56CE, 0x56D1, 0x56D3, 0x56D7,
+0x56EE, 0x56F9, 0x5700, 0x56FF, 0x5704, 0x5709},
+{ /* category 52 */
+0x5708, 0x570B, 0x570D, 0x5713, 0x5718, 0x5716, 0x55C7, 0x571C,
+0x5726, 0x5737, 0x5738, 0x574E, 0x573B, 0x5740, 0x574F, 0x5769,
+0x57C0, 0x5788, 0x5761, 0x577F, 0x5789, 0x5793, 0x57A0, 0x57B3,
+0x57A4, 0x57AA, 0x57B0, 0x57C3, 0x57C6, 0x57D4, 0x57D2, 0x57D3,
+0x580A, 0x57D6, 0x57E3, 0x580B, 0x5819, 0x581D, 0x5872, 0x5821,
+0x5862, 0x584B, 0x5870, 0x6BC0, 0x5852, 0x583D, 0x5879, 0x5885,
+0x58B9, 0x589F, 0x58AB, 0x58BA, 0x58DE, 0x58BB, 0x58B8, 0x58AE,
+0x58C5, 0x58D3, 0x58D1, 0x58D7, 0x58D9, 0x58D8, 0x58E5, 0x58DC,
+0x58E4, 0x58DF, 0x58EF, 0x58FA, 0x58F9, 0x58FB, 0x58FC, 0x58FD,
+0x5902, 0x590A, 0x5910, 0x591B, 0x68A6, 0x5925, 0x592C, 0x592D,
+0x5932, 0x5938, 0x593E, 0x7AD2, 0x5955, 0x5950, 0x594E, 0x595A,
+0x5958, 0x5962, 0x5960, 0x5967, 0x596C, 0x5969},
+{ /* category 53 */
+0x5978, 0x5981, 0x599D, 0x4F5E, 0x4FAB, 0x59A3, 0x59B2, 0x59C6,
+0x59E8, 0x59DC, 0x598D, 0x59D9, 0x59DA, 0x5A25, 0x5A1F, 0x5A11,
+0x5A1C, 0x5A09, 0x5A1A, 0x5A40, 0x5A6C, 0x5A49, 0x5A35, 0x5A36,
+0x5A62, 0x5A6A, 0x5A9A, 0x5ABC, 0x5ABE, 0x5ACB, 0x5AC2, 0x5ABD,
+0x5AE3, 0x5AD7, 0x5AE6, 0x5AE9, 0x5AD6, 0x5AFA, 0x5AFB, 0x5B0C,
+0x5B0B, 0x5B16, 0x5B32, 0x5AD0, 0x5B2A, 0x5B36, 0x5B3E, 0x5B43,
+0x5B45, 0x5B40, 0x5B51, 0x5B55, 0x5B5A, 0x5B5B, 0x5B65, 0x5B69,
+0x5B70, 0x5B73, 0x5B75, 0x5B78, 0x6588, 0x5B7A, 0x5B80, 0x5B83,
+0x5BA6, 0x5BB8, 0x5BC3, 0x5BC7, 0x5BC9, 0x5BD4, 0x5BD0, 0x5BE4,
+0x5BE6, 0x5BE2, 0x5BDE, 0x5BE5, 0x5BEB, 0x5BF0, 0x5BF6, 0x5BF3,
+0x5C05, 0x5C07, 0x5C08, 0x5C0D, 0x5C13, 0x5C20, 0x5C22, 0x5C28,
+0x5C38, 0x5C39, 0x5C41, 0x5C46, 0x5C4E, 0x5C53},
+{ /* category 54 */
+0x5C50, 0x5C4F, 0x5B71, 0x5C6C, 0x5C6E, 0x4E62, 0x5C76, 0x5C79,
+0x5C8C, 0x5C91, 0x5C94, 0x599B, 0x5CAB, 0x5CBB, 0x5CB6, 0x5CBC,
+0x5CB7, 0x5CC5, 0x5CBE, 0x5CC7, 0x5CD9, 0x5CE9, 0x5CFD, 0x5CFA,
+0x5CED, 0x5D8C, 0x5CEA, 0x5D0B, 0x5D15, 0x5D17, 0x5D5C, 0x5D1F,
+0x5D1B, 0x5D11, 0x5D14, 0x5D22, 0x5D1A, 0x5D19, 0x5D18, 0x5D4C,
+0x5D52, 0x5D4E, 0x5D4B, 0x5D6C, 0x5D73, 0x5D76, 0x5D87, 0x5D84,
+0x5D82, 0x5DA2, 0x5D9D, 0x5DAC, 0x5DAE, 0x5DBD, 0x5D90, 0x5DB7,
+0x5DBC, 0x5DC9, 0x5DCD, 0x5DD3, 0x5DD2, 0x5DD6, 0x5DDB, 0x5DEB,
+0x5DF2, 0x5DF5, 0x5E0B, 0x5E1A, 0x5E19, 0x5E11, 0x5E1B, 0x5E36,
+0x5E37, 0x5E44, 0x5E43, 0x5E40, 0x5E4E, 0x5E57, 0x5E54, 0x5E5F,
+0x5E62, 0x5E64, 0x5E47, 0x5E75, 0x5E76, 0x5E7A, 0x9EBC, 0x5E7F,
+0x5EA0, 0x5EC1, 0x5EC2, 0x5EC8, 0x5ED0, 0x5ECF},
+{ /* category 55 */
+0x5ED6, 0x5EE3, 0x5EDD, 0x5EDA, 0x5EDB, 0x5EE2, 0x5EE1, 0x5EE8,
+0x5EE9, 0x5EEC, 0x5EF1, 0x5EF3, 0x5EF0, 0x5EF4, 0x5EF8, 0x5EFE,
+0x5F03, 0x5F09, 0x5F5D, 0x5F5C, 0x5F0B, 0x5F11, 0x5F16, 0x5F29,
+0x5F2D, 0x5F38, 0x5F41, 0x5F48, 0x5F4C, 0x5F4E, 0x5F2F, 0x5F51,
+0x5F56, 0x5F57, 0x5F59, 0x5F61, 0x5F6D, 0x5F73, 0x5F77, 0x5F83,
+0x5F82, 0x5F7F, 0x5F8A, 0x5F88, 0x5F91, 0x5F87, 0x5F9E, 0x5F99,
+0x5F98, 0x5FA0, 0x5FA8, 0x5FAD, 0x5FBC, 0x5FD6, 0x5FFB, 0x5FE4,
+0x5FF8, 0x5FF1, 0x5FDD, 0x60B3, 0x5FFF, 0x6021, 0x6060, 0x6019,
+0x6010, 0x6029, 0x600E, 0x6031, 0x601B, 0x6015, 0x602B, 0x6026,
+0x600F, 0x603A, 0x605A, 0x6041, 0x606A, 0x6077, 0x605F, 0x604A,
+0x6046, 0x604D, 0x6063, 0x6043, 0x6064, 0x6042, 0x606C, 0x606B,
+0x6059, 0x6081, 0x608D, 0x60E7, 0x6083, 0x609A},
+{ /* category 56 */
+0x6084, 0x609B, 0x6096, 0x6097, 0x6092, 0x60A7, 0x608B, 0x60E1,
+0x60B8, 0x60E0, 0x60D3, 0x60B4, 0x5FF0, 0x60BD, 0x60C6, 0x60B5,
+0x60D8, 0x614D, 0x6115, 0x6106, 0x60F6, 0x60F7, 0x6100, 0x60F4,
+0x60FA, 0x6103, 0x6121, 0x60FB, 0x60F1, 0x610D, 0x610E, 0x6147,
+0x613E, 0x6128, 0x6127, 0x614A, 0x613F, 0x613C, 0x612C, 0x6134,
+0x613D, 0x6142, 0x6144, 0x6173, 0x6177, 0x6158, 0x6159, 0x615A,
+0x616B, 0x6174, 0x616F, 0x6165, 0x6171, 0x615F, 0x615D, 0x6153,
+0x6175, 0x6199, 0x6196, 0x6187, 0x61AC, 0x6194, 0x619A, 0x618A,
+0x6191, 0x61AB, 0x61AE, 0x61CC, 0x61CA, 0x61C9, 0x61F7, 0x61C8,
+0x61C3, 0x61C6, 0x61BA, 0x61CB, 0x7F79, 0x61CD, 0x61E6, 0x61E3,
+0x61F6, 0x61FA, 0x61F4, 0x61FF, 0x61FD, 0x61FC, 0x61FE, 0x6200,
+0x6208, 0x6209, 0x620D, 0x620C, 0x6214, 0x621B},
+{ /* category 57 */
+0x621E, 0x6221, 0x622A, 0x622E, 0x6230, 0x6232, 0x6233, 0x6241,
+0x624E, 0x625E, 0x6263, 0x625B, 0x6260, 0x6268, 0x627C, 0x6282,
+0x6289, 0x627E, 0x6292, 0x6293, 0x6296, 0x62D4, 0x6283, 0x6294,
+0x62D7, 0x62D1, 0x62BB, 0x62CF, 0x62FF, 0x62C6, 0x64D4, 0x62C8,
+0x62DC, 0x62CC, 0x62CA, 0x62C2, 0x62C7, 0x629B, 0x62C9, 0x630C,
+0x62EE, 0x62F1, 0x6327, 0x6302, 0x6308, 0x62EF, 0x62F5, 0x6350,
+0x633E, 0x634D, 0x641C, 0x634F, 0x6396, 0x638E, 0x6380, 0x63AB,
+0x6376, 0x63A3, 0x638F, 0x6389, 0x639F, 0x63B5, 0x636B, 0x6369,
+0x63BE, 0x63E9, 0x63C0, 0x63C6, 0x63E3, 0x63C9, 0x63D2, 0x63F6,
+0x63C4, 0x6416, 0x6434, 0x6406, 0x6413, 0x6426, 0x6436, 0x651D,
+0x6417, 0x6428, 0x640F, 0x6467, 0x646F, 0x6476, 0x644E, 0x652A,
+0x6495, 0x6493, 0x64A5, 0x64A9, 0x6488, 0x64BC},
+{ /* category 58 */
+0x64DA, 0x64D2, 0x64C5, 0x64C7, 0x64BB, 0x64D8, 0x64C2, 0x64F1,
+0x64E7, 0x8209, 0x64E0, 0x64E1, 0x62AC, 0x64E3, 0x64EF, 0x652C,
+0x64F6, 0x64F4, 0x64F2, 0x64FA, 0x6500, 0x64FD, 0x6518, 0x651C,
+0x6505, 0x6524, 0x6523, 0x652B, 0x6534, 0x6535, 0x6537, 0x6536,
+0x6538, 0x754B, 0x6548, 0x6556, 0x6555, 0x654D, 0x6558, 0x655E,
+0x655D, 0x6572, 0x6578, 0x6582, 0x6583, 0x8B8A, 0x659B, 0x659F,
+0x65AB, 0x65B7, 0x65C3, 0x65C6, 0x65C1, 0x65C4, 0x65CC, 0x65D2,
+0x65DB, 0x65D9, 0x65E0, 0x65E1, 0x65F1, 0x6772, 0x660A, 0x6603,
+0x65FB, 0x6773, 0x6635, 0x6636, 0x6634, 0x661C, 0x664F, 0x6644,
+0x6649, 0x6641, 0x665E, 0x665D, 0x6664, 0x6667, 0x6668, 0x665F,
+0x6662, 0x6670, 0x6683, 0x6688, 0x668E, 0x6689, 0x6684, 0x6698,
+0x669D, 0x66C1, 0x66B9, 0x66C9, 0x66BE, 0x66BC},
+{ /* category 59 */
+0x66C4, 0x66B8, 0x66D6, 0x66DA, 0x66E0, 0x663F, 0x66E6, 0x66E9,
+0x66F0, 0x66F5, 0x66F7, 0x670F, 0x6716, 0x671E, 0x6726, 0x6727,
+0x9738, 0x672E, 0x673F, 0x6736, 0x6741, 0x6738, 0x6737, 0x6746,
+0x675E, 0x6760, 0x6759, 0x6763, 0x6764, 0x6789, 0x6770, 0x67A9,
+0x677C, 0x676A, 0x678C, 0x678B, 0x67A6, 0x67A1, 0x6785, 0x67B7,
+0x67EF, 0x67B4, 0x67EC, 0x67B3, 0x67E9, 0x67B8, 0x67E4, 0x67DE,
+0x67DD, 0x67E2, 0x67EE, 0x67B9, 0x67CE, 0x67C6, 0x67E7, 0x6A9C,
+0x681E, 0x6846, 0x6829, 0x6840, 0x684D, 0x6832, 0x684E, 0x68B3,
+0x682B, 0x6859, 0x6863, 0x6877, 0x687F, 0x689F, 0x688F, 0x68AD,
+0x6894, 0x689D, 0x689B, 0x6883, 0x6AAE, 0x68B9, 0x6874, 0x68B5,
+0x68A0, 0x68BA, 0x690F, 0x688D, 0x687E, 0x6901, 0x68CA, 0x6908,
+0x68D8, 0x6922, 0x6926, 0x68E1, 0x690C, 0x68CD},
+{ /* category 60 */
+0x68D4, 0x68E7, 0x68D5, 0x6936, 0x6912, 0x6904, 0x68D7, 0x68E3,
+0x6925, 0x68F9, 0x68E0, 0x68EF, 0x6928, 0x692A, 0x691A, 0x6923,
+0x6921, 0x68C6, 0x6979, 0x6977, 0x695C, 0x6978, 0x696B, 0x6954,
+0x697E, 0x696E, 0x6939, 0x6974, 0x693D, 0x6959, 0x6930, 0x6961,
+0x695E, 0x695D, 0x6981, 0x696A, 0x69B2, 0x69AE, 0x69D0, 0x69BF,
+0x69C1, 0x69D3, 0x69BE, 0x69CE, 0x5BE8, 0x69CA, 0x69DD, 0x69BB,
+0x69C3, 0x69A7, 0x6A2E, 0x6991, 0x69A0, 0x699C, 0x6995, 0x69B4,
+0x69DE, 0x69E8, 0x6A02, 0x6A1B, 0x69FF, 0x6B0A, 0x69F9, 0x69F2,
+0x69E7, 0x6A05, 0x69B1, 0x6A1E, 0x69ED, 0x6A14, 0x69EB, 0x6A0A,
+0x6A12, 0x6AC1, 0x6A23, 0x6A13, 0x6A44, 0x6A0C, 0x6A72, 0x6A36,
+0x6A78, 0x6A47, 0x6A62, 0x6A59, 0x6A66, 0x6A48, 0x6A38, 0x6A22,
+0x6A90, 0x6A8D, 0x6AA0, 0x6A84, 0x6AA2, 0x6AA3},
+{ /* category 61 */
+0x6A97, 0x8617, 0x6ABB, 0x6AC3, 0x6AC2, 0x6AB8, 0x6AB3, 0x6AAC,
+0x6ADE, 0x6AD1, 0x6ADF, 0x6AAA, 0x6ADA, 0x6AEA, 0x6AFB, 0x6B05,
+0x8616, 0x6AFA, 0x6B12, 0x6B16, 0x9B31, 0x6B1F, 0x6B38, 0x6B37,
+0x76DC, 0x6B39, 0x98EE, 0x6B47, 0x6B43, 0x6B49, 0x6B50, 0x6B59,
+0x6B54, 0x6B5B, 0x6B5F, 0x6B61, 0x6B78, 0x6B79, 0x6B7F, 0x6B80,
+0x6B84, 0x6B83, 0x6B8D, 0x6B98, 0x6B95, 0x6B9E, 0x6BA4, 0x6BAA,
+0x6BAB, 0x6BAF, 0x6BB2, 0x6BB1, 0x6BB3, 0x6BB7, 0x6BBC, 0x6BC6,
+0x6BCB, 0x6BD3, 0x6BDF, 0x6BEC, 0x6BEB, 0x6BF3, 0x6BEF, 0x9EBE,
+0x6C08, 0x6C13, 0x6C14, 0x6C1B, 0x6C24, 0x6C23, 0x6C5E, 0x6C55,
+0x6C62, 0x6C6A, 0x6C82, 0x6C8D, 0x6C9A, 0x6C81, 0x6C9B, 0x6C7E,
+0x6C68, 0x6C73, 0x6C92, 0x6C90, 0x6CC4, 0x6CF1, 0x6CD3, 0x6CBD,
+0x6CD7, 0x6CC5, 0x6CDD, 0x6CAE, 0x6CB1, 0x6CBE},
+{ /* category 62 */
+0x6CBA, 0x6CDB, 0x6CEF, 0x6CD9, 0x6CEA, 0x6D1F, 0x884D, 0x6D36,
+0x6D2B, 0x6D3D, 0x6D38, 0x6D19, 0x6D35, 0x6D33, 0x6D12, 0x6D0C,
+0x6D63, 0x6D93, 0x6D64, 0x6D5A, 0x6D79, 0x6D59, 0x6D8E, 0x6D95,
+0x6FE4, 0x6D85, 0x6DF9, 0x6E15, 0x6E0A, 0x6DB5, 0x6DC7, 0x6DE6,
+0x6DB8, 0x6DC6, 0x6DEC, 0x6DDE, 0x6DCC, 0x6DE8, 0x6DD2, 0x6DC5,
+0x6DFA, 0x6DD9, 0x6DE4, 0x6DD5, 0x6DEA, 0x6DEE, 0x6E2D, 0x6E6E,
+0x6E2E, 0x6E19, 0x6E72, 0x6E5F, 0x6E3E, 0x6E23, 0x6E6B, 0x6E2B,
+0x6E76, 0x6E4D, 0x6E1F, 0x6E43, 0x6E3A, 0x6E4E, 0x6E24, 0x6EFF,
+0x6E1D, 0x6E38, 0x6E82, 0x6EAA, 0x6E98, 0x6EC9, 0x6EB7, 0x6ED3,
+0x6EBD, 0x6EAF, 0x6EC4, 0x6EB2, 0x6ED4, 0x6ED5, 0x6E8F, 0x6EA5,
+0x6EC2, 0x6E9F, 0x6F41, 0x6F11, 0x704C, 0x6EEC, 0x6EF8, 0x6EFE,
+0x6F3F, 0x6EF2, 0x6F31, 0x6EEF, 0x6F32, 0x6ECC},
+{ /* category 63 */
+0x6F3E, 0x6F13, 0x6EF7, 0x6F86, 0x6F7A, 0x6F78, 0x6F81, 0x6F80,
+0x6F6F, 0x6F5B, 0x6FF3, 0x6F6D, 0x6F82, 0x6F7C, 0x6F58, 0x6F8E,
+0x6F91, 0x6FC2, 0x6F66, 0x6FB3, 0x6FA3, 0x6FA1, 0x6FA4, 0x6FB9,
+0x6FC6, 0x6FAA, 0x6FDF, 0x6FD5, 0x6FEC, 0x6FD4, 0x6FD8, 0x6FF1,
+0x6FEE, 0x6FDB, 0x7009, 0x700B, 0x6FFA, 0x7011, 0x7001, 0x700F,
+0x6FFE, 0x701B, 0x701A, 0x6F74, 0x701D, 0x7018, 0x701F, 0x7030,
+0x703E, 0x7032, 0x7051, 0x7063, 0x7099, 0x7092, 0x70AF, 0x70F1,
+0x70AC, 0x70B8, 0x70B3, 0x70AE, 0x70DF, 0x70CB, 0x70DD, 0x70D9,
+0x7109, 0x70FD, 0x711C, 0x7119, 0x7165, 0x7155, 0x7188, 0x7166,
+0x7162, 0x714C, 0x7156, 0x716C, 0x718F, 0x71FB, 0x7184, 0x7195,
+0x71A8, 0x71AC, 0x71D7, 0x71B9, 0x71BE, 0x71D2, 0x71C9, 0x71D4,
+0x71CE, 0x71E0, 0x71EC, 0x71E7, 0x71F5, 0x71FC},
+{ /* category 64 */
+0x71F9, 0x71FF, 0x720D, 0x7210, 0x721B, 0x7228, 0x722D, 0x722C,
+0x7230, 0x7232, 0x723B, 0x723C, 0x723F, 0x7240, 0x7246, 0x724B,
+0x7258, 0x7274, 0x727E, 0x7282, 0x7281, 0x7287, 0x7292, 0x7296,
+0x72A2, 0x72A7, 0x72B9, 0x72B2, 0x72C3, 0x72C6, 0x72C4, 0x72CE,
+0x72D2, 0x72E2, 0x72E0, 0x72E1, 0x72F9, 0x72F7, 0x500F, 0x7317,
+0x730A, 0x731C, 0x7316, 0x731D, 0x7334, 0x732F, 0x7329, 0x7325,
+0x733E, 0x734E, 0x734F, 0x9ED8, 0x7357, 0x736A, 0x7368, 0x7370,
+0x7378, 0x7375, 0x737B, 0x737A, 0x73C8, 0x73B3, 0x73CE, 0x73BB,
+0x73C0, 0x73E5, 0x73EE, 0x73DE, 0x74A2, 0x7405, 0x746F, 0x7425,
+0x73F8, 0x7432, 0x743A, 0x7455, 0x743F, 0x745F, 0x7459, 0x7441,
+0x745C, 0x7469, 0x7470, 0x7463, 0x746A, 0x7476, 0x747E, 0x748B,
+0x749E, 0x74A7, 0x74CA, 0x74CF, 0x74D4, 0x73F1},
+{ /* category 65 */
+0x74E0, 0x74E3, 0x74E7, 0x74E9, 0x74EE, 0x74F2, 0x74F0, 0x74F1,
+0x74F8, 0x74F7, 0x7504, 0x7503, 0x7505, 0x750C, 0x750E, 0x750D,
+0x7515, 0x7513, 0x751E, 0x7526, 0x752C, 0x753C, 0x7544, 0x754D,
+0x754A, 0x7549, 0x755B, 0x7546, 0x755A, 0x7569, 0x7564, 0x7567,
+0x756B, 0x756D, 0x7578, 0x7576, 0x7586, 0x7587, 0x7574, 0x758A,
+0x7589, 0x7582, 0x7594, 0x759A, 0x759D, 0x75A5, 0x75A3, 0x75C2,
+0x75B3, 0x75C3, 0x75B5, 0x75BD, 0x75B8, 0x75BC, 0x75B1, 0x75CD,
+0x75CA, 0x75D2, 0x75D9, 0x75E3, 0x75DE, 0x75FE, 0x75FF, 0x75FC,
+0x7601, 0x75F0, 0x75FA, 0x75F2, 0x75F3, 0x760B, 0x760D, 0x7609,
+0x761F, 0x7627, 0x7620, 0x7621, 0x7622, 0x7624, 0x7634, 0x7630,
+0x763B, 0x7647, 0x7648, 0x7646, 0x765C, 0x7658, 0x7661, 0x7662,
+0x7668, 0x7669, 0x766A, 0x7667, 0x766C, 0x7670},
+{ /* category 66 */
+0x7672, 0x7676, 0x7678, 0x767C, 0x7680, 0x7683, 0x7688, 0x768B,
+0x768E, 0x7696, 0x7693, 0x7699, 0x769A, 0x76B0, 0x76B4, 0x76B8,
+0x76B9, 0x76BA, 0x76C2, 0x76CD, 0x76D6, 0x76D2, 0x76DE, 0x76E1,
+0x76E5, 0x76E7, 0x76EA, 0x862F, 0x76FB, 0x7708, 0x7707, 0x7704,
+0x7729, 0x7724, 0x771E, 0x7725, 0x7726, 0x771B, 0x7737, 0x7738,
+0x7747, 0x775A, 0x7768, 0x776B, 0x775B, 0x7765, 0x777F, 0x777E,
+0x7779, 0x778E, 0x778B, 0x7791, 0x77A0, 0x779E, 0x77B0, 0x77B6,
+0x77B9, 0x77BF, 0x77BC, 0x77BD, 0x77BB, 0x77C7, 0x77CD, 0x77D7,
+0x77DA, 0x77DC, 0x77E3, 0x77EE, 0x77FC, 0x780C, 0x7812, 0x7926,
+0x7820, 0x792A, 0x7845, 0x788E, 0x7874, 0x7886, 0x787C, 0x789A,
+0x788C, 0x78A3, 0x78B5, 0x78AA, 0x78AF, 0x78D1, 0x78C6, 0x78CB,
+0x78D4, 0x78BE, 0x78BC, 0x78C5, 0x78CA, 0x78EC},
+{ /* category 67 */
+0x78E7, 0x78DA, 0x78FD, 0x78F4, 0x7907, 0x7912, 0x7911, 0x7919,
+0x792C, 0x792B, 0x7940, 0x7960, 0x7957, 0x795F, 0x795A, 0x7955,
+0x7953, 0x797A, 0x797F, 0x798A, 0x799D, 0x79A7, 0x9F4B, 0x79AA,
+0x79AE, 0x79B3, 0x79B9, 0x79BA, 0x79C9, 0x79D5, 0x79E7, 0x79EC,
+0x79E1, 0x79E3, 0x7A08, 0x7A0D, 0x7A18, 0x7A19, 0x7A20, 0x7A1F,
+0x7980, 0x7A31, 0x7A3B, 0x7A3E, 0x7A37, 0x7A43, 0x7A57, 0x7A49,
+0x7A61, 0x7A62, 0x7A69, 0x9F9D, 0x7A70, 0x7A79, 0x7A7D, 0x7A88,
+0x7A97, 0x7A95, 0x7A98, 0x7A96, 0x7AA9, 0x7AC8, 0x7AB0, 0x7AB6,
+0x7AC5, 0x7AC4, 0x7ABF, 0x9083, 0x7AC7, 0x7ACA, 0x7ACD, 0x7ACF,
+0x7AD5, 0x7AD3, 0x7AD9, 0x7ADA, 0x7ADD, 0x7AE1, 0x7AE2, 0x7AE6,
+0x7AED, 0x7AF0, 0x7B02, 0x7B0F, 0x7B0A, 0x7B06, 0x7B33, 0x7B18,
+0x7B19, 0x7B1E, 0x7B35, 0x7B28, 0x7B36, 0x7B50},
+{ /* category 68 */
+0x7B7A, 0x7B04, 0x7B4D, 0x7B0B, 0x7B4C, 0x7B45, 0x7B75, 0x7B65,
+0x7B74, 0x7B67, 0x7B70, 0x7B71, 0x7B6C, 0x7B6E, 0x7B9D, 0x7B98,
+0x7B9F, 0x7B8D, 0x7B9C, 0x7B9A, 0x7B8B, 0x7B92, 0x7B8F, 0x7B5D,
+0x7B99, 0x7BCB, 0x7BC1, 0x7BCC, 0x7BCF, 0x7BB4, 0x7BC6, 0x7BDD,
+0x7BE9, 0x7C11, 0x7C14, 0x7BE6, 0x7BE5, 0x7C60, 0x7C00, 0x7C07,
+0x7C13, 0x7BF3, 0x7BF7, 0x7C17, 0x7C0D, 0x7BF6, 0x7C23, 0x7C27,
+0x7C2A, 0x7C1F, 0x7C37, 0x7C2B, 0x7C3D, 0x7C4C, 0x7C43, 0x7C54,
+0x7C4F, 0x7C40, 0x7C50, 0x7C58, 0x7C5F, 0x7C64, 0x7C56, 0x7C65,
+0x7C6C, 0x7C75, 0x7C83, 0x7C90, 0x7CA4, 0x7CAD, 0x7CA2, 0x7CAB,
+0x7CA1, 0x7CA8, 0x7CB3, 0x7CB2, 0x7CB1, 0x7CAE, 0x7CB9, 0x7CBD,
+0x7CC0, 0x7CC5, 0x7CC2, 0x7CD8, 0x7CD2, 0x7CDC, 0x7CE2, 0x9B3B,
+0x7CEF, 0x7CF2, 0x7CF4, 0x7CF6, 0x7CFA, 0x7D06},
+{ /* category 69 */
+0x7D02, 0x7D1C, 0x7D15, 0x7D0A, 0x7D45, 0x7D4B, 0x7D2E, 0x7D32,
+0x7D3F, 0x7D35, 0x7D46, 0x7D73, 0x7D56, 0x7D4E, 0x7D72, 0x7D68,
+0x7D6E, 0x7D4F, 0x7D63, 0x7D93, 0x7D89, 0x7D5B, 0x7D8F, 0x7D7D,
+0x7D9B, 0x7DBA, 0x7DAE, 0x7DA3, 0x7DB5, 0x7DC7, 0x7DBD, 0x7DAB,
+0x7E3D, 0x7DA2, 0x7DAF, 0x7DDC, 0x7DB8, 0x7D9F, 0x7DB0, 0x7DD8,
+0x7DDD, 0x7DE4, 0x7DDE, 0x7DFB, 0x7DF2, 0x7DE1, 0x7E05, 0x7E0A,
+0x7E23, 0x7E21, 0x7E12, 0x7E31, 0x7E1F, 0x7E09, 0x7E0B, 0x7E22,
+0x7E46, 0x7E66, 0x7E3B, 0x7E35, 0x7E39, 0x7E43, 0x7E37, 0x7E32,
+0x7E3A, 0x7E67, 0x7E5D, 0x7E56, 0x7E5E, 0x7E59, 0x7E5A, 0x7E79,
+0x7E6A, 0x7E69, 0x7E7C, 0x7E7B, 0x7E83, 0x7DD5, 0x7E7D, 0x8FAE,
+0x7E7F, 0x7E88, 0x7E89, 0x7E8C, 0x7E92, 0x7E90, 0x7E93, 0x7E94,
+0x7E96, 0x7E8E, 0x7E9B, 0x7E9C, 0x7F38, 0x7F3A},
+{ /* category 70 */
+0x7F45, 0x7F4C, 0x7F4D, 0x7F4E, 0x7F50, 0x7F51, 0x7F55, 0x7F54,
+0x7F58, 0x7F5F, 0x7F60, 0x7F68, 0x7F69, 0x7F67, 0x7F78, 0x7F82,
+0x7F86, 0x7F83, 0x7F88, 0x7F87, 0x7F8C, 0x7F94, 0x7F9E, 0x7F9D,
+0x7F9A, 0x7FA3, 0x7FAF, 0x7FB2, 0x7FB9, 0x7FAE, 0x7FB6, 0x7FB8,
+0x8B71, 0x7FC5, 0x7FC6, 0x7FCA, 0x7FD5, 0x7FD4, 0x7FE1, 0x7FE6,
+0x7FE9, 0x7FF3, 0x7FF9, 0x98DC, 0x8006, 0x8004, 0x800B, 0x8012,
+0x8018, 0x8019, 0x801C, 0x8021, 0x8028, 0x803F, 0x803B, 0x804A,
+0x8046, 0x8052, 0x8058, 0x805A, 0x805F, 0x8062, 0x8068, 0x8073,
+0x8072, 0x8070, 0x8076, 0x8079, 0x807D, 0x807F, 0x8084, 0x8086,
+0x8085, 0x809B, 0x8093, 0x809A, 0x80AD, 0x5190, 0x80AC, 0x80DB,
+0x80E5, 0x80D9, 0x80DD, 0x80C4, 0x80DA, 0x80D6, 0x8109, 0x80EF,
+0x80F1, 0x811B, 0x8129, 0x8123, 0x812F, 0x814B},
+{ /* category 71 */
+0x968B, 0x8146, 0x813E, 0x8153, 0x8151, 0x80FC, 0x8171, 0x816E,
+0x8165, 0x8166, 0x8174, 0x8183, 0x8188, 0x818A, 0x8180, 0x8182,
+0x81A0, 0x8195, 0x81A4, 0x81A3, 0x815F, 0x8193, 0x81A9, 0x81B0,
+0x81B5, 0x81BE, 0x81B8, 0x81BD, 0x81C0, 0x81C2, 0x81BA, 0x81C9,
+0x81CD, 0x81D1, 0x81D9, 0x81D8, 0x81C8, 0x81DA, 0x81DF, 0x81E0,
+0x81E7, 0x81FA, 0x81FB, 0x81FE, 0x8201, 0x8202, 0x8205, 0x8207,
+0x820A, 0x820D, 0x8210, 0x8216, 0x8229, 0x822B, 0x8238, 0x8233,
+0x8240, 0x8259, 0x8258, 0x825D, 0x825A, 0x825F, 0x8264, 0x8262,
+0x8268, 0x826A, 0x826B, 0x822E, 0x8271, 0x8277, 0x8278, 0x827E,
+0x828D, 0x8292, 0x82AB, 0x829F, 0x82BB, 0x82AC, 0x82E1, 0x82E3,
+0x82DF, 0x82D2, 0x82F4, 0x82F3, 0x82FA, 0x8393, 0x8303, 0x82FB,
+0x82F9, 0x82DE, 0x8306, 0x82DC, 0x8309, 0x82D9},
+{ /* category 72 */
+0x8335, 0x8334, 0x8316, 0x8332, 0x8331, 0x8340, 0x8339, 0x8350,
+0x8345, 0x832F, 0x832B, 0x8317, 0x8318, 0x8385, 0x839A, 0x83AA,
+0x839F, 0x83A2, 0x8396, 0x8323, 0x838E, 0x8387, 0x838A, 0x837C,
+0x83B5, 0x8373, 0x8375, 0x83A0, 0x8389, 0x83A8, 0x83F4, 0x8413,
+0x83EB, 0x83CE, 0x83FD, 0x8403, 0x83D8, 0x840B, 0x83C1, 0x83F7,
+0x8407, 0x83E0, 0x83F2, 0x840D, 0x8422, 0x8420, 0x83BD, 0x8438,
+0x8506, 0x83FB, 0x846D, 0x842A, 0x843C, 0x855A, 0x8484, 0x8477,
+0x846B, 0x84AD, 0x846E, 0x8482, 0x8469, 0x8446, 0x842C, 0x846F,
+0x8479, 0x8435, 0x84CA, 0x8462, 0x84B9, 0x84BF, 0x849F, 0x84D9,
+0x84CD, 0x84BB, 0x84DA, 0x84D0, 0x84C1, 0x84C6, 0x84D6, 0x84A1,
+0x8521, 0x84FF, 0x84F4, 0x8517, 0x8518, 0x852C, 0x851F, 0x8515,
+0x8514, 0x84FC, 0x8540, 0x8563, 0x8558, 0x8548},
+{ /* category 73 */
+0x8541, 0x8602, 0x854B, 0x8555, 0x8580, 0x85A4, 0x8588, 0x8591,
+0x858A, 0x85A8, 0x856D, 0x8594, 0x859B, 0x85EA, 0x8587, 0x859C,
+0x8577, 0x857E, 0x8590, 0x85C9, 0x85BA, 0x85CF, 0x85B9, 0x85D0,
+0x85D5, 0x85DD, 0x85E5, 0x85DC, 0x85F9, 0x860A, 0x8613, 0x860B,
+0x85FE, 0x85FA, 0x8606, 0x8622, 0x861A, 0x8630, 0x863F, 0x864D,
+0x4E55, 0x8654, 0x865F, 0x8667, 0x8671, 0x8693, 0x86A3, 0x86A9,
+0x86AA, 0x868B, 0x868C, 0x86B6, 0x86AF, 0x86C4, 0x86C6, 0x86B0,
+0x86C9, 0x8823, 0x86AB, 0x86D4, 0x86DE, 0x86E9, 0x86EC, 0x86DF,
+0x86DB, 0x86EF, 0x8712, 0x8706, 0x8708, 0x8700, 0x8703, 0x86FB,
+0x8711, 0x8709, 0x870D, 0x86F9, 0x870A, 0x8734, 0x873F, 0x8737,
+0x873B, 0x8725, 0x8729, 0x871A, 0x8760, 0x875F, 0x8778, 0x874C,
+0x874E, 0x8774, 0x8757, 0x8768, 0x876E, 0x8759},
+{ /* category 74 */
+0x8753, 0x8763, 0x876A, 0x8805, 0x87A2, 0x879F, 0x8782, 0x87AF,
+0x87CB, 0x87BD, 0x87C0, 0x87D0, 0x96D6, 0x87AB, 0x87C4, 0x87B3,
+0x87C7, 0x87C6, 0x87BB, 0x87EF, 0x87F2, 0x87E0, 0x880F, 0x880D,
+0x87FE, 0x87F6, 0x87F7, 0x880E, 0x87D2, 0x8811, 0x8816, 0x8815,
+0x8822, 0x8821, 0x8831, 0x8836, 0x8839, 0x8827, 0x883B, 0x8844,
+0x8842, 0x8852, 0x8859, 0x885E, 0x8862, 0x886B, 0x8881, 0x887E,
+0x889E, 0x8875, 0x887D, 0x88B5, 0x8872, 0x8882, 0x8897, 0x8892,
+0x88AE, 0x8899, 0x88A2, 0x888D, 0x88A4, 0x88B0, 0x88BF, 0x88B1,
+0x88C3, 0x88C4, 0x88D4, 0x88D8, 0x88D9, 0x88DD, 0x88F9, 0x8902,
+0x88FC, 0x88F4, 0x88E8, 0x88F2, 0x8904, 0x890C, 0x890A, 0x8913,
+0x8943, 0x891E, 0x8925, 0x892A, 0x892B, 0x8941, 0x8944, 0x893B,
+0x8936, 0x8938, 0x894C, 0x891D, 0x8960, 0x895E},
+{ /* category 75 */
+0x8966, 0x8964, 0x896D, 0x896A, 0x896F, 0x8974, 0x8977, 0x897E,
+0x8983, 0x8988, 0x898A, 0x8993, 0x8998, 0x89A1, 0x89A9, 0x89A6,
+0x89AC, 0x89AF, 0x89B2, 0x89BA, 0x89BD, 0x89BF, 0x89C0, 0x89DA,
+0x89DC, 0x89DD, 0x89E7, 0x89F4, 0x89F8, 0x8A03, 0x8A16, 0x8A10,
+0x8A0C, 0x8A1B, 0x8A1D, 0x8A25, 0x8A36, 0x8A41, 0x8A5B, 0x8A52,
+0x8A46, 0x8A48, 0x8A7C, 0x8A6D, 0x8A6C, 0x8A62, 0x8A85, 0x8A82,
+0x8A84, 0x8AA8, 0x8AA1, 0x8A91, 0x8AA5, 0x8AA6, 0x8A9A, 0x8AA3,
+0x8AC4, 0x8ACD, 0x8AC2, 0x8ADA, 0x8AEB, 0x8AF3, 0x8AE7, 0x8AE4,
+0x8AF1, 0x8B14, 0x8AE0, 0x8AE2, 0x8AF7, 0x8ADE, 0x8ADB, 0x8B0C,
+0x8B07, 0x8B1A, 0x8AE1, 0x8B16, 0x8B10, 0x8B17, 0x8B20, 0x8B33,
+0x97AB, 0x8B26, 0x8B2B, 0x8B3E, 0x8B28, 0x8B41, 0x8B4C, 0x8B4F,
+0x8B4E, 0x8B49, 0x8B56, 0x8B5B, 0x8B5A, 0x8B6B},
+{ /* category 76 */
+0x8B5F, 0x8B6C, 0x8B6F, 0x8B74, 0x8B7D, 0x8B80, 0x8B8C, 0x8B8E,
+0x8B92, 0x8B93, 0x8B96, 0x8B99, 0x8B9A, 0x8C3A, 0x8C41, 0x8C3F,
+0x8C48, 0x8C4C, 0x8C4E, 0x8C50, 0x8C55, 0x8C62, 0x8C6C, 0x8C78,
+0x8C7A, 0x8C82, 0x8C89, 0x8C85, 0x8C8A, 0x8C8D, 0x8C8E, 0x8C94,
+0x8C7C, 0x8C98, 0x621D, 0x8CAD, 0x8CAA, 0x8CBD, 0x8CB2, 0x8CB3,
+0x8CAE, 0x8CB6, 0x8CC8, 0x8CC1, 0x8CE4, 0x8CE3, 0x8CDA, 0x8CFD,
+0x8CFA, 0x8CFB, 0x8D04, 0x8D05, 0x8D0A, 0x8D07, 0x8D0F, 0x8D0D,
+0x8D10, 0x9F4E, 0x8D13, 0x8CCD, 0x8D14, 0x8D16, 0x8D67, 0x8D6D,
+0x8D71, 0x8D73, 0x8D81, 0x8D99, 0x8DC2, 0x8DBE, 0x8DBA, 0x8DCF,
+0x8DDA, 0x8DD6, 0x8DCC, 0x8DDB, 0x8DCB, 0x8DEA, 0x8DEB, 0x8DDF,
+0x8DE3, 0x8DFC, 0x8E08, 0x8E09, 0x8DFF, 0x8E1D, 0x8E1E, 0x8E10,
+0x8E1F, 0x8E42, 0x8E35, 0x8E30, 0x8E34, 0x8E4A},
+{ /* category 77 */
+0x8E47, 0x8E49, 0x8E4C, 0x8E50, 0x8E48, 0x8E59, 0x8E64, 0x8E60,
+0x8E2A, 0x8E63, 0x8E55, 0x8E76, 0x8E72, 0x8E7C, 0x8E81, 0x8E87,
+0x8E85, 0x8E84, 0x8E8B, 0x8E8A, 0x8E93, 0x8E91, 0x8E94, 0x8E99,
+0x8EAA, 0x8EA1, 0x8EAC, 0x8EB0, 0x8EC6, 0x8EB1, 0x8EBE, 0x8EC5,
+0x8EC8, 0x8ECB, 0x8EDB, 0x8EE3, 0x8EFC, 0x8EFB, 0x8EEB, 0x8EFE,
+0x8F0A, 0x8F05, 0x8F15, 0x8F12, 0x8F19, 0x8F13, 0x8F1C, 0x8F1F,
+0x8F1B, 0x8F0C, 0x8F26, 0x8F33, 0x8F3B, 0x8F39, 0x8F45, 0x8F42,
+0x8F3E, 0x8F4C, 0x8F49, 0x8F46, 0x8F4E, 0x8F57, 0x8F5C, 0x8F62,
+0x8F63, 0x8F64, 0x8F9C, 0x8F9F, 0x8FA3, 0x8FAD, 0x8FAF, 0x8FB7,
+0x8FDA, 0x8FE5, 0x8FE2, 0x8FEA, 0x8FEF, 0x9087, 0x8FF4, 0x9005,
+0x8FF9, 0x8FFA, 0x9011, 0x9015, 0x9021, 0x900D, 0x901E, 0x9016,
+0x900B, 0x9027, 0x9036, 0x9035, 0x9039, 0x8FF8},
+{ /* category 78 */
+0x904F, 0x9050, 0x9051, 0x9052, 0x900E, 0x9049, 0x903E, 0x9056,
+0x9058, 0x905E, 0x9068, 0x906F, 0x9076, 0x96A8, 0x9072, 0x9082,
+0x907D, 0x9081, 0x9080, 0x908A, 0x9089, 0x908F, 0x90A8, 0x90AF,
+0x90B1, 0x90B5, 0x90E2, 0x90E4, 0x6248, 0x90DB, 0x9102, 0x9112,
+0x9119, 0x9132, 0x9130, 0x914A, 0x9156, 0x9158, 0x9163, 0x9165,
+0x9169, 0x9173, 0x9172, 0x918B, 0x9189, 0x9182, 0x91A2, 0x91AB,
+0x91AF, 0x91AA, 0x91B5, 0x91B4, 0x91BA, 0x91C0, 0x91C1, 0x91C9,
+0x91CB, 0x91D0, 0x91D6, 0x91DF, 0x91E1, 0x91DB, 0x91FC, 0x91F5,
+0x91F6, 0x921E, 0x91FF, 0x9214, 0x922C, 0x9215, 0x9211, 0x925E,
+0x9257, 0x9245, 0x9249, 0x9264, 0x9248, 0x9295, 0x923F, 0x924B,
+0x9250, 0x929C, 0x9296, 0x9293, 0x929B, 0x925A, 0x92CF, 0x92B9,
+0x92B7, 0x92E9, 0x930F, 0x92FA, 0x9344, 0x932E},
+{ /* category 79 */
+0x9319, 0x9322, 0x931A, 0x9323, 0x933A, 0x9335, 0x933B, 0x935C,
+0x9360, 0x937C, 0x936E, 0x9356, 0x93B0, 0x93AC, 0x93AD, 0x9394,
+0x93B9, 0x93D6, 0x93D7, 0x93E8, 0x93E5, 0x93D8, 0x93C3, 0x93DD,
+0x93D0, 0x93C8, 0x93E4, 0x941A, 0x9414, 0x9413, 0x9403, 0x9407,
+0x9410, 0x9436, 0x942B, 0x9435, 0x9421, 0x943A, 0x9441, 0x9452,
+0x9444, 0x945B, 0x9460, 0x9462, 0x945E, 0x946A, 0x9229, 0x9470,
+0x9475, 0x9477, 0x947D, 0x945A, 0x947C, 0x947E, 0x9481, 0x947F,
+0x9582, 0x9587, 0x958A, 0x9594, 0x9596, 0x9598, 0x9599, 0x95A0,
+0x95A8, 0x95A7, 0x95AD, 0x95BC, 0x95BB, 0x95B9, 0x95BE, 0x95CA,
+0x6FF6, 0x95C3, 0x95CD, 0x95CC, 0x95D5, 0x95D4, 0x95D6, 0x95DC,
+0x95E1, 0x95E5, 0x95E2, 0x9621, 0x9628, 0x962E, 0x962F, 0x9642,
+0x964C, 0x964F, 0x964B, 0x9677, 0x965C, 0x965E},
+{ /* category 80 */
+0x965D, 0x965F, 0x9666, 0x9672, 0x966C, 0x968D, 0x9698, 0x9695,
+0x9697, 0x96AA, 0x96A7, 0x96B1, 0x96B2, 0x96B0, 0x96B4, 0x96B6,
+0x96B8, 0x96B9, 0x96CE, 0x96CB, 0x96C9, 0x96CD, 0x894D, 0x96DC,
+0x970D, 0x96D5, 0x96F9, 0x9704, 0x9706, 0x9708, 0x9713, 0x970E,
+0x9711, 0x970F, 0x9716, 0x9719, 0x9724, 0x972A, 0x9730, 0x9739,
+0x973D, 0x973E, 0x9744, 0x9746, 0x9748, 0x9742, 0x9749, 0x975C,
+0x9760, 0x9764, 0x9766, 0x9768, 0x52D2, 0x976B, 0x9771, 0x9779,
+0x9785, 0x977C, 0x9781, 0x977A, 0x9786, 0x978B, 0x978F, 0x9790,
+0x979C, 0x97A8, 0x97A6, 0x97A3, 0x97B3, 0x97B4, 0x97C3, 0x97C6,
+0x97C8, 0x97CB, 0x97DC, 0x97ED, 0x9F4F, 0x97F2, 0x7ADF, 0x97F6,
+0x97F5, 0x980F, 0x980C, 0x9838, 0x9824, 0x9821, 0x9837, 0x983D,
+0x9846, 0x984F, 0x984B, 0x986B, 0x986F, 0x9870},
+{ /* category 81 */
+0x9871, 0x9874, 0x9873, 0x98AA, 0x98AF, 0x98B1, 0x98B6, 0x98C4,
+0x98C3, 0x98C6, 0x98E9, 0x98EB, 0x9903, 0x9909, 0x9912, 0x9914,
+0x9918, 0x9921, 0x991D, 0x991E, 0x9924, 0x9920, 0x992C, 0x992E,
+0x993D, 0x993E, 0x9942, 0x9949, 0x9945, 0x9950, 0x994B, 0x9951,
+0x9952, 0x994C, 0x9955, 0x9997, 0x9998, 0x99A5, 0x99AD, 0x99AE,
+0x99BC, 0x99DF, 0x99DB, 0x99DD, 0x99D8, 0x99D1, 0x99ED, 0x99EE,
+0x99F1, 0x99F2, 0x99FB, 0x99F8, 0x9A01, 0x9A0F, 0x9A05, 0x99E2,
+0x9A19, 0x9A2B, 0x9A37, 0x9A45, 0x9A42, 0x9A40, 0x9A43, 0x9A3E,
+0x9A55, 0x9A4D, 0x9A5B, 0x9A57, 0x9A5F, 0x9A62, 0x9A65, 0x9A64,
+0x9A69, 0x9A6B, 0x9A6A, 0x9AAD, 0x9AB0, 0x9ABC, 0x9AC0, 0x9ACF,
+0x9AD1, 0x9AD3, 0x9AD4, 0x9ADE, 0x9ADF, 0x9AE2, 0x9AE3, 0x9AE6,
+0x9AEF, 0x9AEB, 0x9AEE, 0x9AF4, 0x9AF1, 0x9AF7},
+{ /* category 82 */
+0x9AFB, 0x9B06, 0x9B18, 0x9B1A, 0x9B1F, 0x9B22, 0x9B23, 0x9B25,
+0x9B27, 0x9B28, 0x9B29, 0x9B2A, 0x9B2E, 0x9B2F, 0x9B32, 0x9B44,
+0x9B43, 0x9B4F, 0x9B4D, 0x9B4E, 0x9B51, 0x9B58, 0x9B74, 0x9B93,
+0x9B83, 0x9B91, 0x9B96, 0x9B97, 0x9B9F, 0x9BA0, 0x9BA8, 0x9BB4,
+0x9BC0, 0x9BCA, 0x9BB9, 0x9BC6, 0x9BCF, 0x9BD1, 0x9BD2, 0x9BE3,
+0x9BE2, 0x9BE4, 0x9BD4, 0x9BE1, 0x9C3A, 0x9BF2, 0x9BF1, 0x9BF0,
+0x9C15, 0x9C14, 0x9C09, 0x9C13, 0x9C0C, 0x9C06, 0x9C08, 0x9C12,
+0x9C0A, 0x9C04, 0x9C2E, 0x9C1B, 0x9C25, 0x9C24, 0x9C21, 0x9C30,
+0x9C47, 0x9C32, 0x9C46, 0x9C3E, 0x9C5A, 0x9C60, 0x9C67, 0x9C76,
+0x9C78, 0x9CE7, 0x9CEC, 0x9CF0, 0x9D09, 0x9D08, 0x9CEB, 0x9D03,
+0x9D06, 0x9D2A, 0x9D26, 0x9DAF, 0x9D23, 0x9D1F, 0x9D44, 0x9D15,
+0x9D12, 0x9D41, 0x9D3F, 0x9D3E, 0x9D46, 0x9D48},
+{ /* category 83 */
+0x9D5D, 0x9D5E, 0x9D64, 0x9D51, 0x9D50, 0x9D59, 0x9D72, 0x9D89,
+0x9D87, 0x9DAB, 0x9D6F, 0x9D7A, 0x9D9A, 0x9DA4, 0x9DA9, 0x9DB2,
+0x9DC4, 0x9DC1, 0x9DBB, 0x9DB8, 0x9DBA, 0x9DC6, 0x9DCF, 0x9DC2,
+0x9DD9, 0x9DD3, 0x9DF8, 0x9DE6, 0x9DED, 0x9DEF, 0x9DFD, 0x9E1A,
+0x9E1B, 0x9E1E, 0x9E75, 0x9E79, 0x9E7D, 0x9E81, 0x9E88, 0x9E8B,
+0x9E8C, 0x9E92, 0x9E95, 0x9E91, 0x9E9D, 0x9EA5, 0x9EA9, 0x9EB8,
+0x9EAA, 0x9EAD, 0x9761, 0x9ECC, 0x9ECE, 0x9ECF, 0x9ED0, 0x9ED4,
+0x9EDC, 0x9EDE, 0x9EDD, 0x9EE0, 0x9EE5, 0x9EE8, 0x9EEF, 0x9EF4,
+0x9EF6, 0x9EF7, 0x9EF9, 0x9EFB, 0x9EFC, 0x9EFD, 0x9F07, 0x9F08,
+0x76B7, 0x9F15, 0x9F21, 0x9F2C, 0x9F3E, 0x9F4A, 0x9F52, 0x9F54,
+0x9F63, 0x9F5F, 0x9F60, 0x9F61, 0x9F66, 0x9F67, 0x9F6C, 0x9F6A,
+0x9F77, 0x9F72, 0x9F76, 0x9F95, 0x9F9C, 0x9FA0},
+{ /* category 84 */
+0x582F, 0x69C7, 0x9059, 0x7464, 0x51DC, 0x7199, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+{ /* category 85 */
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+{ /* category 86 */
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+{ /* category 87 */
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+{ /* category 88 */
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+{ /* category 89 */
+0x7E8A, 0x891C, 0x9348, 0x9288, 0x84DC, 0x4FC9, 0x70BB, 0x6631,
+0x68C8, 0x92F9, 0x66FB, 0x5F45, 0x4E28, 0x4EE1, 0x4EFC, 0x4F00,
+0x4F03, 0x4F39, 0x4F56, 0x4F92, 0x4F8A, 0x4F9A, 0x4F94, 0x4FCD,
+0x5040, 0x5022, 0x4FFF, 0x501E, 0x5046, 0x5070, 0x5042, 0x5094,
+0x50F4, 0x50D8, 0x514A, 0x5164, 0x519D, 0x51BE, 0x51EC, 0x5215,
+0x529C, 0x52A6, 0x52C0, 0x52DB, 0x5300, 0x5307, 0x5324, 0x5372,
+0x5393, 0x53B2, 0x53DD, 0xFA0E, 0x549C, 0x548A, 0x54A9, 0x54FF,
+0x5586, 0x5759, 0x5765, 0x57AC, 0x57C8, 0x57C7, 0xFA0F, 0xFA10,
+0x589E, 0x58B2, 0x590B, 0x5953, 0x595B, 0x595D, 0x5963, 0x59A4,
+0x59BA, 0x5B56, 0x5BC0, 0x752F, 0x5BD8, 0x5BEC, 0x5C1E, 0x5CA6,
+0x5CBA, 0x5CF5, 0x5D27, 0x5D53, 0xFA11, 0x5D42, 0x5D6D, 0x5DB8,
+0x5DB9, 0x5DD0, 0x5F21, 0x5F34, 0x5F67, 0x5FB7},
+{ /* category 90 */
+0x5FDE, 0x605D, 0x6085, 0x608A, 0x60DE, 0x60D5, 0x6120, 0x60F2,
+0x6111, 0x6137, 0x6130, 0x6198, 0x6213, 0x62A6, 0x63F5, 0x6460,
+0x649D, 0x64CE, 0x654E, 0x6600, 0x6615, 0x663B, 0x6609, 0x662E,
+0x661E, 0x6624, 0x6665, 0x6657, 0x6659, 0xFA12, 0x6673, 0x6699,
+0x66A0, 0x66B2, 0x66BF, 0x66FA, 0x670E, 0xF929, 0x6766, 0x67BB,
+0x6852, 0x67C0, 0x6801, 0x6844, 0x68CF, 0xFA13, 0x6968, 0xFA14,
+0x6998, 0x69E2, 0x6A30, 0x6A6B, 0x6A46, 0x6A73, 0x6A7E, 0x6AE2,
+0x6AE4, 0x6BD6, 0x6C3F, 0x6C5C, 0x6C86, 0x6C6F, 0x6CDA, 0x6D04,
+0x6D87, 0x6D6F, 0x6D96, 0x6DAC, 0x6DCF, 0x6DF8, 0x6DF2, 0x6DFC,
+0x6E39, 0x6E5C, 0x6E27, 0x6E3C, 0x6EBF, 0x6F88, 0x6FB5, 0x6FF5,
+0x7005, 0x7007, 0x7028, 0x7085, 0x70AB, 0x710F, 0x7104, 0x715C,
+0x7146, 0x7147, 0xFA15, 0x71C1, 0x71FE, 0x72B1},
+{ /* category 91 */
+0x72BE, 0x7324, 0xFA16, 0x7377, 0x73BD, 0x73C9, 0x73D6, 0x73E3,
+0x73D2, 0x7407, 0x73F5, 0x7426, 0x742A, 0x7429, 0x742E, 0x7462,
+0x7489, 0x749F, 0x7501, 0x756F, 0x7682, 0x769C, 0x769E, 0x769B,
+0x76A6, 0xFA17, 0x7746, 0x52AF, 0x7821, 0x784E, 0x7864, 0x787A,
+0x7930, 0xFA18, 0xFA19, 0xFA1A, 0x7994, 0xFA1B, 0x799B, 0x7AD1,
+0x7AE7, 0xFA1C, 0x7AEB, 0x7B9E, 0xFA1D, 0x7D48, 0x7D5C, 0x7DB7,
+0x7DA0, 0x7DD6, 0x7E52, 0x7F47, 0x7FA1, 0xFA1E, 0x8301, 0x8362,
+0x837F, 0x83C7, 0x83F6, 0x8448, 0x84B4, 0x8553, 0x8559, 0x856B,
+0xFA1F, 0x85B0, 0xFA20, 0xFA21, 0x8807, 0x88F5, 0x8A12, 0x8A37,
+0x8A79, 0x8AA7, 0x8ABE, 0x8ADF, 0xFA22, 0x8AF6, 0x8B53, 0x8B7F,
+0x8CF0, 0x8CF4, 0x8D12, 0x8D76, 0xFA23, 0x8ECF, 0xFA24, 0xFA25,
+0x9067, 0x90DE, 0xFA26, 0x9115, 0x9127, 0x91DA},
+{ /* category 92 */
+0x91D7, 0x91DE, 0x91ED, 0x91EE, 0x91E4, 0x91E5, 0x9206, 0x9210,
+0x920A, 0x923A, 0x9240, 0x923C, 0x924E, 0x9259, 0x9251, 0x9239,
+0x9267, 0x92A7, 0x9277, 0x9278, 0x92E7, 0x92D7, 0x92D9, 0x92D0,
+0xFA27, 0x92D5, 0x92E0, 0x92D3, 0x9325, 0x9321, 0x92FB, 0xFA28,
+0x931E, 0x92FF, 0x931D, 0x9302, 0x9370, 0x9357, 0x93A4, 0x93C6,
+0x93DE, 0x93F8, 0x9431, 0x9445, 0x9448, 0x9592, 0xF9DC, 0xFA29,
+0x969D, 0x96AF, 0x9733, 0x973B, 0x9743, 0x974D, 0x974F, 0x9751,
+0x9755, 0x9857, 0x9865, 0xFA2A, 0xFA2B, 0x9927, 0xFA2C, 0x999E,
+0x9A4E, 0x9AD9, 0x9ADC, 0x9B75, 0x9B72, 0x9B8F, 0x9BB1, 0x9BBB,
+0x9C00, 0x9D70, 0x9D6B, 0xFA2D, 0x9E19, 0x9ED1, 0x0000, 0x0000,
+0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177,
+0x2178, 0x2179, 0xFFE2, 0xFFE4, 0xFF07, 0xFF02}
+};
+unsigned short unicode_rev_table_null[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table0[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x2178,
+	0x212f,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x216b,0x215e,0x0000,0x0000,0x212d,0x0000,0x2279,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x215f,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x2160,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table3[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x2621,0x2622,0x2623,0x2624,0x2625,0x2626,0x2627,
+	0x2628,0x2629,0x262a,0x262b,0x262c,0x262d,0x262e,0x262f,
+	0x2630,0x2631,0x0000,0x2632,0x2633,0x2634,0x2635,0x2636,
+	0x2637,0x2638,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x2641,0x2642,0x2643,0x2644,0x2645,0x2646,0x2647,
+	0x2648,0x2649,0x264a,0x264b,0x264c,0x264d,0x264e,0x264f,
+	0x2650,0x2651,0x0000,0x2652,0x2653,0x2654,0x2655,0x2656,
+	0x2657,0x2658,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table4[] = {
+	0x0000,0x2727,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x2721,0x2722,0x2723,0x2724,0x2725,0x2726,0x2728,0x2729,
+	0x272a,0x272b,0x272c,0x272d,0x272e,0x272f,0x2730,0x2731,
+	0x2732,0x2733,0x2734,0x2735,0x2736,0x2737,0x2738,0x2739,
+	0x273a,0x273b,0x273c,0x273d,0x273e,0x273f,0x2740,0x2741,
+	0x2751,0x2752,0x2753,0x2754,0x2755,0x2756,0x2758,0x2759,
+	0x275a,0x275b,0x275c,0x275d,0x275e,0x275f,0x2760,0x2761,
+	0x2762,0x2763,0x2764,0x2765,0x2766,0x2767,0x2768,0x2769,
+	0x276a,0x276b,0x276c,0x276d,0x276e,0x276f,0x2770,0x2771,
+	0x0000,0x2757,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table32[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x213e,0x0000,0x0000,0x0000,0x0000,0x213d,0x0000,0x0000,
+	0x2146,0x2147,0x0000,0x0000,0x2148,0x2149,0x0000,0x0000,
+	0x2277,0x2278,0x0000,0x0000,0x0000,0x2145,0x2144,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x2273,0x0000,0x216c,0x216d,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x2228,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table33[] = {
+	0x0000,0x0000,0x0000,0x216e,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x2272,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x7c71,0x7c72,0x7c73,0x7c74,0x7c75,0x7c76,0x7c77,0x7c78,
+	0x7c79,0x7c7a,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x222b,0x222c,0x222a,0x222d,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x224d,0x0000,0x224e,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table34[] = {
+	0x224f,0x0000,0x225f,0x2250,0x0000,0x0000,0x0000,0x2260,
+	0x223a,0x0000,0x0000,0x223b,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x2265,0x0000,0x0000,0x2267,0x2167,0x0000,
+	0x225c,0x0000,0x0000,0x0000,0x0000,0x2142,0x0000,0x224a,
+	0x224b,0x2241,0x2240,0x2269,0x226a,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x2168,0x2268,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x2266,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x2262,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x2162,0x2261,0x0000,0x0000,0x0000,0x0000,0x2165,0x2166,
+	0x0000,0x0000,0x2263,0x2264,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x223e,0x223f,0x0000,0x0000,0x223c,0x223d,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x225d,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table35[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x225e,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table37[] = {
+	0x2821,0x282c,0x2822,0x282d,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x2823,0x0000,0x0000,0x282e,
+	0x2824,0x0000,0x0000,0x282f,0x2826,0x0000,0x0000,0x2831,
+	0x2825,0x0000,0x0000,0x2830,0x2827,0x283c,0x0000,0x0000,
+	0x2837,0x0000,0x0000,0x2832,0x2829,0x283e,0x0000,0x0000,
+	0x2839,0x0000,0x0000,0x2834,0x2828,0x0000,0x0000,0x2838,
+	0x283d,0x0000,0x0000,0x2833,0x282a,0x0000,0x0000,0x283a,
+	0x283f,0x0000,0x0000,0x2835,0x282b,0x0000,0x0000,0x283b,
+	0x0000,0x0000,0x2840,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x2836,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x2223,0x2222,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x2225,0x2224,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x2227,0x2226,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x2221,0x217e,
+	0x0000,0x0000,0x0000,0x217b,0x0000,0x0000,0x217d,0x217c,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x227e,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table38[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x217a,0x2179,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x216a,0x0000,0x2169,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x2276,0x0000,0x0000,0x2275,0x0000,0x2274,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table48[] = {
+	0x0000,0x2122,0x2123,0x2137,0x0000,0x2139,0x213a,0x213b,
+	0x2152,0x2153,0x2154,0x2155,0x2156,0x2157,0x2158,0x2159,
+	0x215a,0x215b,0x2229,0x222e,0x214c,0x214d,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x2421,0x2422,0x2423,0x2424,0x2425,0x2426,0x2427,
+	0x2428,0x2429,0x242a,0x242b,0x242c,0x242d,0x242e,0x242f,
+	0x2430,0x2431,0x2432,0x2433,0x2434,0x2435,0x2436,0x2437,
+	0x2438,0x2439,0x243a,0x243b,0x243c,0x243d,0x243e,0x243f,
+	0x2440,0x2441,0x2442,0x2443,0x2444,0x2445,0x2446,0x2447,
+	0x2448,0x2449,0x244a,0x244b,0x244c,0x244d,0x244e,0x244f,
+	0x2450,0x2451,0x2452,0x2453,0x2454,0x2455,0x2456,0x2457,
+	0x2458,0x2459,0x245a,0x245b,0x245c,0x245d,0x245e,0x245f,
+	0x2460,0x2461,0x2462,0x2463,0x2464,0x2465,0x2466,0x2467,
+	0x2468,0x2469,0x246a,0x246b,0x246c,0x246d,0x246e,0x246f,
+	0x2470,0x2471,0x2472,0x2473,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x212b,0x212c,0x2135,0x2136,0x0000,
+	0x0000,0x2521,0x2522,0x2523,0x2524,0x2525,0x2526,0x2527,
+	0x2528,0x2529,0x252a,0x252b,0x252c,0x252d,0x252e,0x252f,
+	0x2530,0x2531,0x2532,0x2533,0x2534,0x2535,0x2536,0x2537,
+	0x2538,0x2539,0x253a,0x253b,0x253c,0x253d,0x253e,0x253f,
+	0x2540,0x2541,0x2542,0x2543,0x2544,0x2545,0x2546,0x2547,
+	0x2548,0x2549,0x254a,0x254b,0x254c,0x254d,0x254e,0x254f,
+	0x2550,0x2551,0x2552,0x2553,0x2554,0x2555,0x2556,0x2557,
+	0x2558,0x2559,0x255a,0x255b,0x255c,0x255d,0x255e,0x255f,
+	0x2560,0x2561,0x2562,0x2563,0x2564,0x2565,0x2566,0x2567,
+	0x2568,0x2569,0x256a,0x256b,0x256c,0x256d,0x256e,0x256f,
+	0x2570,0x2571,0x2572,0x2573,0x2574,0x2575,0x2576,0x0000,
+	0x0000,0x0000,0x0000,0x2126,0x213c,0x2133,0x2134,0x0000,
+	0};
+unsigned short unicode_rev_table78[] = {
+	0x306c,0x437a,0x0000,0x3c37,0x0000,0x0000,0x0000,0x4b7c,
+	0x3e66,0x3b30,0x3e65,0x323c,0x0000,0x4954,0x4d3f,0x0000,
+	0x5022,0x312f,0x0000,0x0000,0x336e,0x5023,0x4024,0x5242,
+	0x3556,0x4a3a,0x0000,0x0000,0x0000,0x0000,0x3e67,0x0000,
+	0x0000,0x4e3e,0x0000,0x0000,0x0000,0x0000,0x4a42,0x0000,
+	0x792d,0x0000,0x5024,0x0000,0x0000,0x4366,0x0000,0x0000,
+	0x0000,0x5025,0x367a,0x0000,0x0000,0x0000,0x5026,0x0000,
+	0x345d,0x4330,0x0000,0x3c67,0x5027,0x0000,0x0000,0x5028,
+	0x0000,0x0000,0x5029,0x4735,0x0000,0x3557,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x4737,0x0000,0x4663,0x3843,0x4b33,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x6949,0x502a,0x3e68,
+	0x502b,0x3235,0x0000,0x0000,0x0000,0x3665,0x3870,0x4c69,
+	0x0000,0x0000,0x5626,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x4d70,0x0000,0x467d,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3425,0x0000,
+	0x3535,0x0000,0x502c,0x0000,0x0000,0x502d,0x4e3b,0x0000,
+	0x4d3d,0x4168,0x502f,0x3b76,0x4673,0x0000,0x5032,0x0000,
+	0x0000,0x313e,0x385f,0x0000,0x385e,0x3066,0x0000,0x0000,
+	0x4f4b,0x4f4a,0x0000,0x3a33,0x3021,0x0000,0x5033,0x5034,
+	0x5035,0x4b34,0x5036,0x0000,0x3872,0x3067,0x4b72,0x0000,
+	0x357c,0x0000,0x0000,0x357d,0x357e,0x4462,0x4e3c,0x0000,
+	0x5037,0x0000,0x0000,0x5038,0x0000,0x0000,0x5039,0x0000,
+	0x0000,0x0000,0x3f4d,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x3d3a,0x3f4e,0x503e,0x0000,0x503c,0x0000,0x503d,0x3558,
+	0x0000,0x0000,0x3a23,0x3270,0x0000,0x503b,0x503a,0x4a29,
+	0x0000,0x0000,0x0000,0x0000,0x3b46,0x3b45,0x423e,0x503f,
+	0x4955,0x4067,0x0000,0x0000,0x0000,0x2138,0x5040,0x5042,
+	0x0000,0x792e,0x0000,0x4265,0x4e61,0x304a,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x5041,0x323e,0x0000,
+	0x3644,0x0000,0x4367,0x0000,0x0000,0x0000,0x376f,0x5043,
+	0x0000,0x0000,0x0000,0x4724,0x792f,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table79[] = {
+	0x7930,0x346b,0x0000,0x7931,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x5044,0x304b,0x0000,0x0000,0x3860,0x346c,0x497a,
+	0x4832,0x3559,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x3271,0x0000,0x5067,0x4541,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x476c,
+	0x5046,0x0000,0x0000,0x0000,0x483c,0x0000,0x4e62,0x0000,
+	0x3f2d,0x7932,0x3b47,0x0000,0x3b77,0x3240,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x4451,0x0000,0x0000,0x4322,0x504a,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x304c,0x4463,0x3d3b,
+	0x3a34,0x4d24,0x0000,0x424e,0x0000,0x323f,0x7933,0x5049,
+	0x0000,0x4d3e,0x5045,0x5047,0x3a6e,0x5048,0x5524,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x5050,0x0000,0x0000,0x0000,0x0000,0x0000,0x5053,
+	0x5051,0x0000,0x0000,0x3242,0x0000,0x4a3b,0x504b,0x0000,
+	0x0000,0x0000,0x0000,0x504f,0x3873,0x0000,0x0000,0x3b48,
+	0x0000,0x0000,0x0000,0x3426,0x0000,0x0000,0x5054,0x0000,
+	0x504c,0x0000,0x7935,0x4e63,0x0000,0x3b78,0x0000,0x504d,
+	0x0000,0x5052,0x7934,0x0000,0x7937,0x0000,0x5055,0x0000,
+	0x504e,0x0000,0x7936,0x3621,0x0000,0x304d,0x0000,0x0000,
+	0x3622,0x3241,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x5525,0x0000,0x4b79,0x496e,0x3874,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x3f2f,0x4e37,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4a58,
+	0x0000,0x0000,0x3738,0x4225,0x3264,0x0000,0x0000,0x0000,
+	0x0000,0x7926,0x3d53,0x0000,0x0000,0x7938,0x5059,0x0000,
+	0x505e,0x505c,0x0000,0x0000,0x5057,0x0000,0x0000,0x422f,
+	0x505a,0x0000,0x505d,0x505b,0x0000,0x4a5d,0x0000,0x5058,
+	0x0000,0x3f2e,0x0000,0x4b73,0x505f,0x5060,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3d24,0x506d,
+	0x0000,0x0000,0x0000,0x4750,0x0000,0x4936,0x5068,0x0000,
+	0x4a70,0x0000,0x3236,0x0000,0x0000,0x0000,0x506c,0x793b,
+	0};
+unsigned short unicode_rev_table80[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x5066,0x506f,0x0000,
+	0x0000,0x4152,0x0000,0x3844,0x0000,0x475c,0x0000,0x6047,
+	0x0000,0x506e,0x455d,0x0000,0x5063,0x0000,0x3876,0x0000,
+	0x0000,0x3875,0x5061,0x0000,0x0000,0x0000,0x793c,0x3c5a,
+	0x0000,0x5069,0x793a,0x4a6f,0x434d,0x5065,0x3771,0x0000,
+	0x5062,0x506a,0x5064,0x4e51,0x506b,0x4f41,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3666,0x0000,
+	0x0000,0x3770,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x7939,0x0000,0x793f,0x5070,0x0000,0x0000,0x793d,0x5071,
+	0x5075,0x304e,0x0000,0x0000,0x0000,0x0000,0x0000,0x4a50,
+	0x5074,0x0000,0x0000,0x0000,0x0000,0x5073,0x5077,0x0000,
+	0x0000,0x0000,0x5076,0x0000,0x4464,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x3772,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x5078,0x0000,0x0000,0x0000,
+	0x793e,0x0000,0x3c45,0x0000,0x4226,0x4465,0x3676,0x0000,
+	0x5079,0x0000,0x0000,0x0000,0x0000,0x3536,0x0000,0x0000,
+	0x507a,0x0000,0x0000,0x0000,0x0000,0x507c,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x4b35,0x0000,0x0000,
+	0x0000,0x3766,0x0000,0x0000,0x7940,0x0000,0x0000,0x0000,
+	0x3b31,0x4877,0x507b,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x3a45,0x4d43,0x0000,0x0000,
+	0x0000,0x0000,0x507e,0x5123,0x507d,0x3a44,0x0000,0x3d7d,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3739,0x0000,
+	0x0000,0x0000,0x5124,0x0000,0x0000,0x364f,0x0000,0x0000,
+	0x0000,0x5121,0x5122,0x0000,0x0000,0x462f,0x0000,0x417c,
+	0x0000,0x3623,0x0000,0x0000,0x0000,0x4b4d,0x5125,0x0000,
+	0x7942,0x0000,0x4e3d,0x0000,0x0000,0x0000,0x5126,0x0000,
+	0x0000,0x0000,0x0000,0x5129,0x0000,0x5127,0x0000,0x414e,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x5128,0x512a,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x7941,0x512c,0x0000,0x0000,
+	0x0000,0x512b,0x0000,0x4a48,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table81[] = {
+	0x3537,0x512e,0x512f,0x0000,0x322f,0x0000,0x0000,0x0000,
+	0x0000,0x512d,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x3c74,0x0000,0x5132,0x5131,0x5130,0x0000,
+	0x5056,0x0000,0x5133,0x0000,0x0000,0x0000,0x0000,0x3d7e,
+	0x0000,0x5134,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x4d25,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x4c59,0x0000,0x0000,0x0000,0x0000,0x5136,
+	0x0000,0x0000,0x5135,0x5138,0x5137,0x0000,0x0000,0x5139,
+	0x513a,0x3074,0x0000,0x3835,0x373b,0x3d3c,0x437b,0x3624,
+	0x4068,0x3877,0x7943,0x396e,0x513c,0x4c48,0x4546,0x0000,
+	0x3b79,0x0000,0x513b,0x0000,0x513d,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x455e,0x0000,0x3375,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x513e,0x0000,0x7944,0x467e,0x0000,0x0000,
+	0x4134,0x5140,0x5141,0x482c,0x3878,0x4f3b,0x5142,0x0000,
+	0x0000,0x3626,0x0000,0x0000,0x0000,0x4a3c,0x4236,0x3671,
+	0x4535,0x0000,0x0000,0x0000,0x3773,0x0000,0x0000,0x0000,
+	0x5143,0x0000,0x5144,0x0000,0x0000,0x4662,0x315f,0x0000,
+	0x0000,0x5147,0x3a7d,0x0000,0x5146,0x3a46,0x0000,0x5148,
+	0x666e,0x5149,0x4b41,0x514a,0x0000,0x514b,0x514c,0x3e69,
+	0x0000,0x3c4c,0x0000,0x0000,0x0000,0x7945,0x0000,0x0000,
+	0x3427,0x0000,0x514f,0x0000,0x514d,0x4c3d,0x514e,0x0000,
+	0x495a,0x5150,0x5151,0x5152,0x455f,0x0000,0x0000,0x0000,
+	0x5156,0x5154,0x5155,0x5153,0x3a63,0x5157,0x4c6a,0x4e64,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x5158,0x7946,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x4028,0x5159,0x3d5a,0x0000,
+	0x0000,0x515a,0x0000,0x437c,0x4e3f,0x4560,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x5245,0x0000,
+	0x0000,0x0000,0x0000,0x515b,0x7425,0x3645,0x0000,0x0000,
+	0x515c,0x4b5e,0x0000,0x0000,0x0000,0x0000,0x3d68,0x427c,
+	0x0000,0x515e,0x4664,0x0000,0x7947,0x515f,0x0000,0x0000,
+	0x5160,0x332e,0x0000,0x0000,0x0000,0x5161,0x3627,0x0000,
+	0x464c,0x317a,0x3d50,0x0000,0x0000,0x4821,0x5162,0x0000,
+	0};
+unsigned short unicode_rev_table82[] = {
+	0x4561,0x0000,0x0000,0x3f4f,0x5163,0x0000,0x4a2c,0x405a,
+	0x3422,0x0000,0x3429,0x5164,0x0000,0x0000,0x5166,0x0000,
+	0x0000,0x373a,0x0000,0x0000,0x5165,0x7948,0x0000,0x4e73,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x3d69,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x483d,0x4a4c,0x0000,0x5167,
+	0x0000,0x4d78,0x5168,0x0000,0x0000,0x0000,0x5169,0x0000,
+	0x457e,0x0000,0x0000,0x516a,0x0000,0x0000,0x4029,0x3a7e,
+	0x3774,0x516b,0x3b49,0x396f,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x4466,0x516d,0x0000,0x0000,0x4227,
+	0x0000,0x0000,0x3a6f,0x516e,0x516f,0x4130,0x0000,0x516c,
+	0x0000,0x0000,0x0000,0x0000,0x5171,0x0000,0x4b36,0x0000,
+	0x0000,0x0000,0x0000,0x3964,0x0000,0x0000,0x5170,0x0000,
+	0x0000,0x0000,0x0000,0x3775,0x3a5e,0x476d,0x0000,0x0000,
+	0x0000,0x5174,0x5172,0x0000,0x0000,0x0000,0x0000,0x497b,
+	0x3e6a,0x517b,0x3364,0x5175,0x5173,0x414f,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x5177,0x0000,0x5176,
+	0x0000,0x0000,0x0000,0x3344,0x0000,0x0000,0x0000,0x3760,
+	0x517c,0x4e2d,0x0000,0x0000,0x0000,0x5178,0x0000,0x0000,
+	0x0000,0x517d,0x517a,0x0000,0x5179,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x4e4f,0x7949,0x0000,0x0000,0x3879,
+	0x3243,0x0000,0x0000,0x4e74,0x0000,0x0000,0x794a,0x0000,
+	0x0000,0x3d75,0x4558,0x3965,0x5222,0x5223,0x0000,0x7b3c,
+	0x0000,0x4e65,0x0000,0x0000,0x4f2b,0x5225,0x0000,0x0000,
+	0x0000,0x387a,0x0000,0x0000,0x5224,0x0000,0x332f,0x0000,
+	0x794b,0x5226,0x0000,0x4b56,0x0000,0x443c,0x0000,0x4d26,
+	0x0000,0x4a59,0x0000,0x0000,0x0000,0x5227,0x0000,0x0000,
+	0x0000,0x0000,0x7055,0x0000,0x0000,0x4630,0x0000,0x5228,
+	0x342a,0x4c33,0x0000,0x794c,0x0000,0x3e21,0x5229,0x4a67,
+	0x522d,0x0000,0x402a,0x522a,0x3650,0x0000,0x522b,0x342b,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x372e,0x522e,0x0000,0x522f,0x0000,0x0000,
+	0x5230,0x5231,0x3c5b,0x0000,0x0000,0x0000,0x387b,0x4c5e,
+	0};
+unsigned short unicode_rev_table83[] = {
+	0x794d,0x4c68,0x4677,0x0000,0x0000,0x4a71,0x5232,0x794e,
+	0x5233,0x0000,0x0000,0x0000,0x0000,0x5235,0x0000,0x5237,
+	0x5236,0x0000,0x0000,0x0000,0x0000,0x5238,0x323d,0x4b4c,
+	0x0000,0x3a7c,0x5239,0x0000,0x0000,0x4159,0x0000,0x0000,
+	0x3e22,0x3629,0x0000,0x523a,0x794f,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x485b,0x0000,0x0000,0x0000,0x0000,0x523b,
+	0x0000,0x523c,0x0000,0x523d,0x0000,0x0000,0x0000,0x0000,
+	0x523e,0x4924,0x3668,0x3065,0x0000,0x0000,0x0000,0x463f,
+	0x523f,0x3d3d,0x0000,0x4069,0x0000,0x5241,0x5240,0x3e23,
+	0x3861,0x5243,0x483e,0x0000,0x0000,0x5244,0x0000,0x0000,
+	0x0000,0x485c,0x4234,0x426e,0x3628,0x0000,0x0000,0x466e,
+	0x4331,0x0000,0x476e,0x0000,0x4b4e,0x0000,0x5246,0x0000,
+	0x406a,0x0000,0x0000,0x0000,0x0000,0x0000,0x3735,0x0000,
+	0x0000,0x5247,0x0000,0x0000,0x0000,0x0000,0x5248,0x312c,
+	0x3075,0x346d,0x7950,0x4228,0x3551,0x4d71,0x0000,0x524b,
+	0x3237,0x0000,0x0000,0x524a,0x0000,0x0000,0x0000,0x362a,
+	0x0000,0x0000,0x524c,0x0000,0x4c71,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x7951,0x0000,0x0000,0x524d,0x0000,
+	0x4e52,0x0000,0x387c,0x0000,0x0000,0x0000,0x0000,0x3836,
+	0x524e,0x0000,0x0000,0x0000,0x0000,0x5250,0x524f,0x0000,
+	0x3f5f,0x3139,0x0000,0x0000,0x0000,0x315e,0x5251,0x0000,
+	0x5252,0x0000,0x7952,0x3837,0x0000,0x0000,0x5253,0x0000,
+	0x0000,0x0000,0x0000,0x356e,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x3b32,0x5254,0x0000,0x0000,0x0000,0x0000,
+	0x4b74,0x3a35,0x355a,0x4d27,0x4150,0x483f,0x3c7d,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x3d47,0x0000,0x3c68,0x3c75,
+	0x0000,0x3d76,0x0000,0x4840,0x0000,0x7953,0x0000,0x5257,
+	0x0000,0x3143,0x4151,0x387d,0x3845,0x3667,0x0000,0x0000,
+	0x525b,0x4321,0x427e,0x362b,0x3e24,0x525c,0x525a,0x3244,
+	0x4266,0x3c38,0x3b4b,0x3126,0x0000,0x0000,0x3370,0x3966,
+	0x3b4a,0x0000,0x525d,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table84[] = {
+	0x0000,0x525e,0x0000,0x3549,0x3346,0x0000,0x0000,0x0000,
+	0x3967,0x3548,0x445f,0x3125,0x4631,0x4c3e,0x3921,0x4d79,
+	0x4547,0x387e,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x372f,0x0000,0x5267,0x0000,0x3663,
+	0x4b4a,0x0000,0x0000,0x0000,0x0000,0x0000,0x485d,0x0000,
+	0x0000,0x5266,0x0000,0x345e,0x5261,0x5262,0x5264,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x5265,0x0000,
+	0x355b,0x3f61,0x0000,0x4a2d,0x5263,0x525f,0x3863,0x0000,
+	0x5260,0x0000,0x4f24,0x0000,0x0000,0x0000,0x4a72,0x0000,
+	0x4468,0x3862,0x3970,0x0000,0x0000,0x0000,0x5268,0x0000,
+	0x0000,0x465d,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x526c,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x3c7e,0x0000,0x3c76,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x526f,0x526d,0x0000,0x4c23,0x0000,0x526a,0x5273,0x526e,
+	0x0000,0x0000,0x0000,0x5271,0x3846,0x4c3f,0x0000,0x0000,
+	0x5272,0x0000,0x0000,0x0000,0x5274,0x0000,0x5276,0x0000,
+	0x0000,0x0000,0x7956,0x3a70,0x4f42,0x0000,0x526b,0x5269,
+	0x5275,0x0000,0x5270,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x7955,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x5278,0x0000,0x5323,0x527a,0x0000,0x0000,
+	0x527e,0x7957,0x0000,0x5321,0x527b,0x0000,0x0000,0x533e,
+	0x0000,0x0000,0x3a69,0x3331,0x0000,0x0000,0x0000,0x0000,
+	0x5279,0x0000,0x0000,0x0000,0x5325,0x3076,0x5324,0x0000,
+	0x3025,0x494a,0x5322,0x0000,0x527c,0x0000,0x0000,0x5277,
+	0x527d,0x3a48,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x5326,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x3077,0x532f,0x0000,0x0000,0x5327,0x5328,0x0000,
+	0x3e25,0x4b69,0x0000,0x0000,0x0000,0x532d,0x532c,0x0000,
+	0x0000,0x0000,0x452f,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x532e,0x0000,0x0000,0x532b,0x0000,0x7958,
+	0};
+unsigned short unicode_rev_table85[] = {
+	0x0000,0x0000,0x0000,0x0000,0x3134,0x0000,0x3a36,0x3f30,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x5329,
+	0x4562,0x0000,0x0000,0x0000,0x532a,0x0000,0x3022,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x5334,0x4d23,
+	0x0000,0x3e27,0x0000,0x533a,0x0000,0x0000,0x0000,0x0000,
+	0x5339,0x5330,0x0000,0x0000,0x0000,0x0000,0x4243,0x0000,
+	0x5331,0x0000,0x0000,0x0000,0x426f,0x5336,0x3e26,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x5333,0x0000,0x0000,0x4c64,
+	0x0000,0x0000,0x0000,0x373c,0x0000,0x0000,0x5337,0x5338,
+	0x0000,0x0000,0x0000,0x0000,0x5335,0x533b,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x5332,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x5341,0x5346,0x0000,0x5342,0x0000,
+	0x533d,0x0000,0x0000,0x5347,0x4131,0x0000,0x7959,0x5349,
+	0x0000,0x3922,0x533f,0x437d,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x5343,0x533c,0x342d,0x0000,0x346e,0x3365,0x5344,0x5340,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3776,
+	0x534a,0x5348,0x4153,0x354a,0x362c,0x0000,0x5345,0x0000,
+	0x3674,0x0000,0x0000,0x0000,0x0000,0x0000,0x3144,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x534e,0x534c,0x0000,0x5427,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x5351,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x534b,0x0000,0x534f,0x0000,0x0000,0x534d,
+	0x0000,0x0000,0x0000,0x3b4c,0x5350,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x5353,
+	0x0000,0x5358,0x0000,0x0000,0x0000,0x5356,0x5355,0x0000,
+	0};
+unsigned short unicode_rev_table86[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4332,0x0000,
+	0x0000,0x3245,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x5352,0x0000,0x5354,0x3e28,
+	0x3133,0x0000,0x0000,0x5357,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x325e,0x0000,0x0000,0x0000,0x0000,0x0000,0x5362,
+	0x0000,0x3e7c,0x535e,0x0000,0x535c,0x0000,0x535d,0x0000,
+	0x535f,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x313d,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x4139,0x0000,0x5359,0x0000,
+	0x535a,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x337a,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x5361,0x0000,0x0000,0x0000,
+	0x346f,0x0000,0x5364,0x5360,0x5363,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x4a2e,0x0000,0x0000,0x0000,
+	0x4655,0x0000,0x4838,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x5366,0x0000,0x0000,0x0000,0x0000,0x0000,0x5365,0x3345,
+	0x0000,0x0000,0x5367,0x0000,0x0000,0x0000,0x0000,0x536a,
+	0x0000,0x0000,0x0000,0x0000,0x5369,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x5368,0x0000,0x4739,0x0000,0x0000,0x536b,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x536c,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x536e,0x0000,0x536d,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x5370,0x0000,0x0000,0x0000,
+	0x5373,0x5371,0x536f,0x5372,0x0000,0x0000,0x0000,0x0000,
+	0x5374,0x0000,0x0000,0x0000,0x0000,0x0000,0x5375,0x0000,
+	0x0000,0x5376,0x0000,0x5377,0x0000,0x0000,0x0000,0x5378,
+	0x5145,0x0000,0x3c7c,0x3b4d,0x0000,0x0000,0x3273,0x0000,
+	0x3078,0x0000,0x0000,0x4344,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x5379,0x0000,
+	0x3a24,0x0000,0x304f,0x3f5e,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x537a,0x3847,0x0000,0x0000,0x3971,0x0000,0x537c,
+	0};
+unsigned short unicode_rev_table87[] = {
+	0x537b,0x0000,0x0000,0x4a60,0x537d,0x0000,0x0000,0x0000,
+	0x5421,0x537e,0x0000,0x5422,0x0000,0x5423,0x0000,0x3777,
+	0x0000,0x0000,0x3160,0x5424,0x0000,0x0000,0x5426,0x0000,
+	0x5425,0x0000,0x0000,0x0000,0x5428,0x0000,0x0000,0x455a,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x5429,0x3035,
+	0x3a5f,0x0000,0x0000,0x0000,0x0000,0x373d,0x0000,0x0000,
+	0x434f,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x542a,
+	0x542b,0x0000,0x0000,0x542d,0x0000,0x0000,0x0000,0x0000,
+	0x542e,0x0000,0x3a64,0x0000,0x0000,0x0000,0x0000,0x3651,
+	0x0000,0x0000,0x4b37,0x0000,0x0000,0x0000,0x542c,0x542f,
+	0x3a41,0x3923,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x795a,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x5433,0x0000,0x0000,0x3a25,0x795b,0x4333,0x0000,
+	0x0000,0x5430,0x445a,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x5434,
+	0x0000,0x0000,0x3f62,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x5432,0x5435,0x0000,0x373f,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x5436,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x5437,0x0000,0x3924,0x3340,0x5439,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x543a,0x0000,0x795c,0x0000,0x0000,0x0000,
+	0x543b,0x0000,0x0000,0x5438,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x5431,0x0000,0x0000,0x543c,0x0000,0x0000,0x543d,0x795e,
+	0x795d,0x0000,0x0000,0x4b64,0x0000,0x0000,0x3e6b,0x0000,
+	0x0000,0x0000,0x543f,0x5440,0x543e,0x0000,0x5442,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x4738,0x0000,0x0000,0x3068,
+	0x4956,0x0000,0x0000,0x5443,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x3e7d,0x0000,0x0000,0x3c39,
+	0x0000,0x475d,0x3470,0x0000,0x3a6b,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table88[] = {
+	0x4b59,0x0000,0x4632,0x0000,0x0000,0x3778,0x424f,0x0000,
+	0x0000,0x0000,0x5441,0x5444,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x4244,0x0000,0x0000,
+	0x0000,0x5445,0x0000,0x0000,0x0000,0x5446,0x0000,0x0000,
+	0x0000,0x5448,0x0000,0x0000,0x4469,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x342e,0x0000,0x0000,0x0000,0x0000,0x7421,
+	0x3161,0x4a73,0x0000,0x0000,0x3e6c,0x4548,0x0000,0x0000,
+	0x0000,0x0000,0x3a66,0x0000,0x0000,0x544e,0x0000,0x0000,
+	0x4a3d,0x4e5d,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x3274,0x544a,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x413a,0x544d,0x0000,0x4563,0x0000,0x0000,0x4549,
+	0x4564,0x4839,0x444d,0x0000,0x0000,0x0000,0x3a49,0x0000,
+	0x0000,0x0000,0x5449,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x3176,0x0000,0x4536,0x0000,0x0000,0x0000,0x0000,
+	0x544b,0x0000,0x5447,0x0000,0x0000,0x3f50,0x0000,0x0000,
+	0x0000,0x544f,0x0000,0x0000,0x0000,0x0000,0x3d4e,0x0000,
+	0x0000,0x0000,0x0000,0x362d,0x0000,0x5450,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x4a68,0x0000,0x0000,0x0000,0x417d,
+	0x0000,0x0000,0x0000,0x0000,0x4446,0x0000,0x7961,0x5452,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x4b4f,0x0000,0x0000,0x5453,0x0000,0x0000,0x5458,0x0000,
+	0x0000,0x0000,0x7962,0x4a2f,0x0000,0x0000,0x0000,0x0000,
+	0x5457,0x5451,0x5454,0x5456,0x0000,0x0000,0x3a26,0x0000,
+	0x0000,0x4a49,0x0000,0x0000,0x0000,0x5459,0x0000,0x4345,
+	0x0000,0x0000,0x3275,0x0000,0x3e6d,0x0000,0x0000,0x0000,
+	0x0000,0x545b,0x0000,0x545a,0x0000,0x3968,0x0000,0x545c,
+	0x545e,0x545d,0x0000,0x0000,0x5460,0x0000,0x5455,0x5462,
+	0x0000,0x0000,0x0000,0x0000,0x5461,0x545f,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x3b4e,0x3f51,0x0000,0x4154,0x5463,
+	0x403c,0x306d,0x4764,0x0000,0x0000,0x0000,0x0000,0x445b,
+	0x0000,0x5465,0x5464,0x5466,0x5467,0x5468,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table89[] = {
+	0x0000,0x0000,0x5469,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x4a51,0x546a,0x7963,0x0000,0x0000,0x0000,0x3246,
+	0x546b,0x0000,0x0000,0x0000,0x0000,0x4d3c,0x3330,0x0000,
+	0x5249,0x3d48,0x423f,0x546c,0x4c6b,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x4c34,0x0000,0x0000,0x546e,0x0000,0x4267,
+	0x0000,0x4537,0x4240,0x4957,0x546f,0x5470,0x317b,0x0000,
+	0x0000,0x3c3a,0x5471,0x0000,0x0000,0x0000,0x0000,0x3050,
+	0x5472,0x0000,0x0000,0x0000,0x0000,0x0000,0x5473,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x3162,0x0000,0x0000,0x3471,
+	0x4660,0x4a74,0x0000,0x0000,0x0000,0x0000,0x5477,0x4155,
+	0x5476,0x3740,0x0000,0x7964,0x4b5b,0x5475,0x0000,0x4565,
+	0x5479,0x0000,0x5478,0x7965,0x0000,0x7966,0x0000,0x0000,
+	0x547b,0x0000,0x547a,0x7967,0x0000,0x317c,0x0000,0x547c,
+	0x3e29,0x547e,0x4325,0x0000,0x547d,0x0000,0x4a33,0x0000,
+	0x0000,0x0000,0x0000,0x3d77,0x455b,0x0000,0x0000,0x0000,
+	0x5521,0x0000,0x0000,0x0000,0x0000,0x3925,0x0000,0x0000,
+	0x0000,0x5522,0x4721,0x485e,0x4c51,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x4725,0x0000,0x0000,0x552b,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x3538,0x0000,0x0000,0x4d45,0x0000,
+	0x0000,0x4c2f,0x0000,0x562c,0x0000,0x5523,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x5526,0x7968,0x4245,0x0000,0x0000,
+	0x4b38,0x0000,0x0000,0x0000,0x454a,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x5527,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x4b65,0x7969,0x3a4a,0x0000,0x0000,0x3e2a,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x5528,0x0000,
+	0x0000,0x3b50,0x0000,0x3b4f,0x0000,0x0000,0x0000,0x0000,
+	0x3039,0x3848,0x0000,0x402b,0x3051,0x0000,0x0000,0x0000,
+	0x0000,0x552c,0x552d,0x0000,0x552a,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x3138,0x342f,0x0000,
+	0x5529,0x0000,0x4c45,0x4931,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3028,0x0000,
+	0x0000,0x0000,0x0000,0x3079,0x0000,0x0000,0x0000,0x3b51,
+	0};
+unsigned short unicode_rev_table90[] = {
+	0x0000,0x3052,0x0000,0x3023,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x5532,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x5530,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x4c3c,0x0000,0x5533,0x0000,0x5531,0x0000,0x0000,0x552f,
+	0x3f31,0x0000,0x0000,0x0000,0x0000,0x552e,0x0000,0x0000,
+	0x0000,0x4a5a,0x0000,0x0000,0x0000,0x0000,0x0000,0x3864,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x5537,0x5538,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x3e2b,0x0000,0x0000,0x0000,
+	0x5534,0x4f2c,0x0000,0x0000,0x0000,0x0000,0x474c,0x0000,
+	0x0000,0x5536,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x3a27,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x5539,0x0000,0x0000,0x0000,0x4958,0x0000,
+	0x0000,0x0000,0x553a,0x0000,0x5535,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4c3b,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x475e,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x553b,0x4932,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x553c,0x5540,0x553d,0x0000,
+	0x0000,0x3247,0x553f,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x3c3b,0x0000,0x553e,0x3779,0x0000,0x0000,0x0000,
+	0x554c,0x0000,0x0000,0x0000,0x0000,0x0000,0x5545,0x5542,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x4364,0x0000,0x5541,0x0000,0x0000,0x5543,0x0000,
+	0x0000,0x5544,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x5546,0x5547,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table91[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x3472,0x0000,0x5549,0x5548,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x554a,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x3e6e,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x554d,0x0000,0x445c,0x0000,0x0000,0x0000,
+	0x3145,0x0000,0x554b,0x0000,0x0000,0x0000,0x554e,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x554f,0x0000,
+	0x5552,0x0000,0x0000,0x5550,0x0000,0x5551,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x3b52,0x5553,0x0000,0x0000,0x3926,0x5554,0x796a,0x3b7a,
+	0x4238,0x0000,0x5555,0x5556,0x3b5a,0x3927,0x0000,0x4c52,
+	0x0000,0x0000,0x0000,0x3528,0x3849,0x5557,0x3358,0x0000,
+	0x0000,0x5558,0x0000,0x4239,0x0000,0x0000,0x0000,0x0000,
+	0x5559,0x5623,0x0000,0x555a,0x0000,0x555b,0x0000,0x0000,
+	0x555c,0x0000,0x555e,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x555f,0x0000,0x0000,0x5560,0x0000,0x4270,0x0000,0x3127,
+	0x3c69,0x3042,0x0000,0x4157,0x3430,0x3c35,0x0000,0x3928,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x4566,0x0000,0x3d21,
+	0x3431,0x4368,0x446a,0x3038,0x3539,0x4a75,0x0000,0x3c42,
+	0x0000,0x0000,0x3552,0x406b,0x3c3c,0x4d28,0x5561,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x355c,0x0000,
+	0x3a4b,0x0000,0x0000,0x3332,0x3163,0x3e2c,0x3248,0x0000,
+	0x5562,0x4d46,0x0000,0x0000,0x0000,0x0000,0x0000,0x3d49,
+	0x796b,0x0000,0x3c64,0x5563,0x3473,0x4652,0x4c29,0x5564,
+	0x0000,0x5565,0x0000,0x0000,0x4959,0x0000,0x0000,0x0000,
+	0x5567,0x0000,0x3428,0x3677,0x5566,0x0000,0x0000,0x0000,
+	0x796d,0x0000,0x0000,0x3432,0x0000,0x3f32,0x556b,0x3b21,
+	0x0000,0x3249,0x556a,0x0000,0x5568,0x556c,0x5569,0x472b,
+	0x5c4d,0x3f33,0x0000,0x556d,0x796e,0x0000,0x4e40,0x0000,
+	0x556e,0x0000,0x0000,0x5570,0x0000,0x437e,0x556f,0x0000,
+	0x4023,0x0000,0x3b7b,0x0000,0x0000,0x0000,0x4250,0x3c77,
+	0};
+unsigned short unicode_rev_table92[] = {
+	0x0000,0x4975,0x406c,0x0000,0x3c4d,0x5571,0x3e2d,0x5572,
+	0x5573,0x3053,0x423a,0x3f52,0x0000,0x5574,0x4633,0x3e2e,
+	0x0000,0x3e2f,0x0000,0x5575,0x0000,0x0000,0x406d,0x0000,
+	0x0000,0x0000,0x3e30,0x0000,0x0000,0x0000,0x796f,0x0000,
+	0x5576,0x0000,0x5577,0x0000,0x4c60,0x0000,0x0000,0x0000,
+	0x5578,0x0000,0x0000,0x0000,0x0000,0x3646,0x0000,0x0000,
+	0x0000,0x3d22,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x5579,0x557a,0x3c5c,0x3f2c,0x4674,0x3f54,0x4878,0x4722,
+	0x3649,0x557b,0x0000,0x0000,0x0000,0x356f,0x557c,0x0000,
+	0x367e,0x0000,0x464f,0x3230,0x0000,0x3b53,0x557d,0x5622,
+	0x5621,0x367d,0x0000,0x557e,0x0000,0x4538,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4230,0x0000,
+	0x454b,0x3c48,0x0000,0x0000,0x4158,0x4d7a,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x5624,0x0000,0x5625,0x4656,
+	0x0000,0x3b33,0x0000,0x0000,0x0000,0x0000,0x5627,0x0000,
+	0x0000,0x5628,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x5629,0x0000,0x0000,0x0000,
+	0x3474,0x562a,0x0000,0x0000,0x562b,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x322c,0x0000,0x0000,0x0000,0x0000,0x7970,0x0000,
+	0x413b,0x3464,0x0000,0x562d,0x4c28,0x0000,0x0000,0x0000,
+	0x0000,0x4252,0x0000,0x3359,0x0000,0x0000,0x562f,0x5631,
+	0x345f,0x0000,0x7971,0x562e,0x5630,0x0000,0x5633,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x5632,0x0000,0x5634,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x5635,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x463d,0x362e,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x3265,0x5636,0x563b,0x0000,0x0000,0x5639,0x0000,0x4a77,
+	0x4a76,0x0000,0x0000,0x0000,0x0000,0x7972,0x4567,0x0000,
+	0x0000,0x0000,0x5638,0x3d54,0x0000,0x5637,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table93[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3f72,
+	0x0000,0x0000,0x0000,0x563c,0x0000,0x0000,0x3a6a,0x0000,
+	0x0000,0x5642,0x0000,0x0000,0x5643,0x563d,0x3333,0x563e,
+	0x5647,0x5646,0x5645,0x5641,0x0000,0x0000,0x0000,0x5640,
+	0x0000,0x0000,0x5644,0x0000,0x0000,0x0000,0x0000,0x7973,
+	0x0000,0x4a78,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x7976,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x564b,0x5648,0x0000,0x564a,0x0000,
+	0x4d72,0x0000,0x5649,0x7974,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x563f,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x3f73,0x0000,0x0000,0x564c,0x7977,0x0000,0x3a37,
+	0x0000,0x0000,0x0000,0x564d,0x0000,0x0000,0x564e,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x5651,0x0000,0x5650,0x0000,0x0000,0x564f,
+	0x0000,0x0000,0x0000,0x4568,0x563a,0x0000,0x0000,0x0000,
+	0x5657,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x5653,0x0000,0x0000,
+	0x0000,0x0000,0x5652,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x5654,0x0000,0x5655,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x5658,
+	0x7978,0x7979,0x4e66,0x0000,0x5659,0x5656,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x565a,0x0000,0x0000,0x3460,0x565b,0x0000,0x0000,
+	0x797a,0x0000,0x565d,0x565c,0x0000,0x0000,0x565e,0x0000,
+	0x0000,0x0000,0x0000,0x565f,0x0000,0x406e,0x3d23,0x0000,
+	0x0000,0x3d64,0x0000,0x4163,0x0000,0x3929,0x3a38,0x392a,
+	0x3570,0x0000,0x0000,0x5660,0x0000,0x0000,0x3a39,0x0000,
+	0x0000,0x384a,0x5661,0x4c26,0x4743,0x5662,0x0000,0x392b,
+	0x0000,0x0000,0x0000,0x342c,0x0000,0x4327,0x3652,0x0000,
+	0};
+unsigned short unicode_rev_table94[] = {
+	0x0000,0x0000,0x3b54,0x495b,0x0000,0x0000,0x4841,0x0000,
+	0x0000,0x0000,0x0000,0x5663,0x3475,0x0000,0x0000,0x0000,
+	0x0000,0x5666,0x0000,0x0000,0x0000,0x0000,0x4421,0x0000,
+	0x0000,0x5665,0x5664,0x5667,0x0000,0x446b,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x3f63,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x3b55,0x0000,0x404a,0x0000,0x4253,
+	0x3522,0x0000,0x0000,0x4422,0x0000,0x0000,0x5668,0x5669,
+	0x3e6f,0x0000,0x0000,0x0000,0x0000,0x4b39,0x0000,0x0000,
+	0x566c,0x0000,0x0000,0x566b,0x566a,0x497d,0x0000,0x5673,
+	0x0000,0x0000,0x0000,0x0000,0x4b5a,0x0000,0x566d,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x566f,0x4b6b,0x0000,0x566e,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x5670,
+	0x0000,0x4828,0x5671,0x4a3e,0x5672,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x3433,0x4a3f,0x472f,0x5674,0x5675,0x0000,
+	0x392c,0x3434,0x5676,0x3838,0x4d44,0x4d29,0x3476,0x5678,
+	0x0000,0x4423,0x0000,0x392d,0x3e31,0x0000,0x0000,0x485f,
+	0x0000,0x0000,0x3e32,0x0000,0x0000,0x0000,0x0000,0x3d78,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x446c,0x4a79,0x4539,
+	0x0000,0x0000,0x392e,0x0000,0x495c,0x0000,0x0000,0x0000,
+	0x5679,0x0000,0x0000,0x0000,0x0000,0x0000,0x4559,0x3a42,
+	0x0000,0x0000,0x0000,0x384b,0x0000,0x446d,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x3043,0x3d6e,0x392f,
+	0x4d47,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x567a,0x567b,0x4751,0x0000,0x0000,0x0000,0x0000,
+	0x567c,0x4e77,0x4f2d,0x0000,0x0000,0x0000,0x0000,0x567e,
+	0x567d,0x0000,0x0000,0x3347,0x0000,0x0000,0x5721,0x0000,
+	0x0000,0x0000,0x5724,0x5725,0x0000,0x5723,0x0000,0x4940,
+	0x3e33,0x5727,0x5726,0x5722,0x0000,0x0000,0x0000,0x0000,
+	0x5728,0x5729,0x0000,0x0000,0x572a,0x0000,0x0000,0x0000,
+	0x572d,0x572b,0x0000,0x572c,0x572e,0x0000,0x3164,0x446e,
+	0x572f,0x0000,0x377a,0x3276,0x4736,0x0000,0x5730,0x467b,
+	0};
+unsigned short unicode_rev_table95[] = {
+	0x0000,0x4a5b,0x0000,0x5731,0x4f2e,0x0000,0x0000,0x0000,
+	0x0000,0x5732,0x4a40,0x5735,0x5021,0x5031,0x0000,0x3c30,
+	0x4675,0x5736,0x0000,0x355d,0x4424,0x307a,0x5737,0x4a26,
+	0x3930,0x0000,0x0000,0x4350,0x0000,0x0000,0x0000,0x446f,
+	0x0000,0x797b,0x0000,0x0000,0x0000,0x4c6f,0x3839,0x384c,
+	0x0000,0x5738,0x0000,0x0000,0x0000,0x5739,0x0000,0x573f,
+	0x0000,0x3c65,0x0000,0x0000,0x797c,0x4425,0x0000,0x362f,
+	0x573a,0x0000,0x0000,0x0000,0x492b,0x0000,0x4346,0x0000,
+	0x0000,0x573b,0x0000,0x0000,0x0000,0x792c,0x0000,0x0000,
+	0x573c,0x0000,0x3630,0x0000,0x573d,0x0000,0x573e,0x0000,
+	0x0000,0x5740,0x0000,0x4576,0x0000,0x0000,0x5741,0x5742,
+	0x0000,0x5743,0x0000,0x0000,0x5734,0x5733,0x0000,0x0000,
+	0x0000,0x5744,0x3741,0x0000,0x0000,0x0000,0x4927,0x797d,
+	0x0000,0x3a4c,0x4937,0x4426,0x494b,0x5745,0x0000,0x0000,
+	0x3e34,0x3146,0x0000,0x5746,0x0000,0x0000,0x0000,0x5747,
+	0x0000,0x4c72,0x0000,0x0000,0x4860,0x0000,0x0000,0x574a,
+	0x317d,0x402c,0x5749,0x5748,0x3742,0x4254,0x0000,0x574e,
+	0x574c,0x0000,0x574b,0x4e27,0x3865,0x0000,0x0000,0x0000,
+	0x3d79,0x574d,0x454c,0x3d3e,0x0000,0x0000,0x0000,0x4640,
+	0x5751,0x5750,0x0000,0x0000,0x0000,0x0000,0x574f,0x0000,
+	0x5752,0x3866,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x5753,0x497c,0x3d5b,0x0000,0x0000,0x5754,0x4879,0x0000,
+	0x0000,0x0000,0x0000,0x4641,0x4427,0x0000,0x0000,0x797e,
+	0x0000,0x4530,0x0000,0x0000,0x5755,0x352b,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x3f34,0x0000,0x492c,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x3477,0x4726,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x5756,0x3b56,
+	0x4b3a,0x4b3b,0x0000,0x0000,0x317e,0x575b,0x7a21,0x0000,
+	0x4369,0x0000,0x0000,0x0000,0x5758,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x3277,0x0000,0x0000,0x0000,0x0000,
+	0x582d,0x575a,0x0000,0x0000,0x0000,0x4730,0x0000,0x0000,
+	0x5759,0x0000,0x0000,0x5757,0x0000,0x397a,0x0000,0x575d,
+	0};
+unsigned short unicode_rev_table96[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x5763,0x5769,
+	0x5761,0x0000,0x455c,0x0000,0x0000,0x5766,0x495d,0x0000,
+	0x0000,0x5760,0x0000,0x5765,0x4e67,0x3b57,0x0000,0x0000,
+	0x4255,0x575e,0x0000,0x0000,0x0000,0x355e,0x5768,0x402d,
+	0x3165,0x5762,0x3278,0x5767,0x0000,0x0000,0x0000,0x3631,
+	0x0000,0x5764,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x576a,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x576c,0x5776,0x5774,0x0000,0x0000,0x5771,0x0000,
+	0x0000,0x0000,0x5770,0x4e78,0x0000,0x5772,0x0000,0x0000,
+	0x3632,0x0000,0x3931,0x0000,0x0000,0x3d7a,0x0000,0x0000,
+	0x0000,0x5779,0x576b,0x0000,0x0000,0x7a22,0x0000,0x576f,
+	0x575f,0x0000,0x327a,0x5773,0x5775,0x4351,0x0000,0x0000,
+	0x3a28,0x3238,0x576d,0x5778,0x5777,0x3633,0x0000,0x4229,
+	0x3366,0x0000,0x0000,0x0000,0x0000,0x3743,0x0000,0x576e,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x577a,0x0000,0x577d,0x5821,0x7a23,0x0000,0x0000,
+	0x0000,0x3c3d,0x7a24,0x5827,0x4470,0x577b,0x0000,0x0000,
+	0x0000,0x0000,0x5825,0x0000,0x3279,0x0000,0x5823,0x5824,
+	0x0000,0x0000,0x577e,0x5822,0x0000,0x0000,0x0000,0x3867,
+	0x4d2a,0x0000,0x0000,0x3435,0x0000,0x0000,0x3159,0x5826,
+	0x0000,0x473a,0x302d,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x4861,0x575c,0x582c,0x5830,0x4c65,0x0000,
+	0x5829,0x0000,0x0000,0x0000,0x4569,0x582e,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x3e70,0x582f,0x4657,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x4f47,0x0000,0x582b,0x0000,0x7a26,0x0000,0x0000,
+	0x5831,0x0000,0x397b,0x0000,0x404b,0x0000,0x7a25,0x3054,
+	0x582a,0x5828,0x0000,0x415a,0x0000,0x0000,0x0000,0x577c,
+	0x3b34,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x4246,0x583d,0x7a28,0x415b,0x5838,0x0000,0x5835,0x5836,
+	0x0000,0x3c66,0x5839,0x583c,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table97[] = {
+	0x5837,0x3d25,0x0000,0x583a,0x0000,0x0000,0x5834,0x0000,
+	0x4c7c,0x4c7b,0x0000,0x0000,0x0000,0x583e,0x583f,0x3055,
+	0x0000,0x7a29,0x0000,0x0000,0x0000,0x5833,0x0000,0x0000,
+	0x0000,0x0000,0x3672,0x3026,0x0000,0x0000,0x0000,0x3436,
+	0x7a27,0x583b,0x0000,0x0000,0x0000,0x0000,0x0000,0x5843,
+	0x5842,0x0000,0x0000,0x0000,0x5847,0x0000,0x0000,0x0000,
+	0x7a2b,0x0000,0x0000,0x0000,0x5848,0x0000,0x0000,0x7a2a,
+	0x0000,0x0000,0x0000,0x0000,0x5846,0x5849,0x5841,0x5845,
+	0x0000,0x0000,0x584a,0x0000,0x584b,0x0000,0x0000,0x5840,
+	0x3b7c,0x0000,0x5844,0x4256,0x3932,0x5832,0x3f35,0x0000,
+	0x0000,0x0000,0x0000,0x5858,0x0000,0x4a69,0x0000,0x0000,
+	0x584e,0x584f,0x5850,0x0000,0x0000,0x5857,0x0000,0x5856,
+	0x0000,0x0000,0x4b7d,0x3437,0x0000,0x5854,0x0000,0x3745,
+	0x3334,0x0000,0x0000,0x5851,0x0000,0x0000,0x4e38,0x5853,
+	0x3056,0x5855,0x0000,0x584c,0x5852,0x5859,0x3744,0x584d,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4d5d,0x0000,
+	0x0000,0x0000,0x4d2b,0x0000,0x0000,0x0000,0x0000,0x585c,
+	0x0000,0x0000,0x5860,0x0000,0x0000,0x0000,0x417e,0x0000,
+	0x4e79,0x5861,0x0000,0x0000,0x585e,0x0000,0x585b,0x0000,
+	0x7a2c,0x585a,0x585f,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x4a30,0x0000,0x0000,0x4634,
+	0x0000,0x3746,0x0000,0x5862,0x585d,0x0000,0x5863,0x0000,
+	0x0000,0x0000,0x377b,0x0000,0x0000,0x0000,0x3231,0x0000,
+	0x0000,0x0000,0x586b,0x0000,0x0000,0x0000,0x3438,0x0000,
+	0x0000,0x0000,0x0000,0x5869,0x0000,0x0000,0x586a,0x3a29,
+	0x5868,0x5866,0x5865,0x586c,0x5864,0x586e,0x0000,0x0000,
+	0x327b,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x5870,0x0000,0x0000,0x586f,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x4428,0x0000,0x5873,0x0000,0x5871,0x5867,
+	0x377c,0x0000,0x5872,0x0000,0x5876,0x5875,0x5877,0x5874,
+	0};
+unsigned short unicode_rev_table98[] = {
+	0x5878,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x5879,0x587a,0x4a6a,0x0000,0x587c,0x587b,0x3d3f,0x0000,
+	0x402e,0x3266,0x327c,0x7a2d,0x587d,0x0000,0x303f,0x0000,
+	0x0000,0x0000,0x404c,0x587e,0x0000,0x6c43,0x5921,0x3761,
+	0x0000,0x5922,0x0000,0x0000,0x0000,0x0000,0x406f,0x0000,
+	0x0000,0x0000,0x5923,0x0000,0x0000,0x0000,0x5924,0x353a,
+	0x5925,0x0000,0x5926,0x5927,0x4257,0x0000,0x0000,0x0000,
+	0x384d,0x0000,0x0000,0x4c61,0x0000,0x0000,0x0000,0x4b3c,
+	0x3d6a,0x5928,0x0000,0x0000,0x0000,0x0000,0x0000,0x4070,
+	0x6e3d,0x4862,0x0000,0x3c6a,0x0000,0x3a4d,0x5929,0x0000,
+	0x0000,0x0000,0x0000,0x4247,0x0000,0x4a27,0x0000,0x0000,
+	0x4271,0x0000,0x0000,0x592c,0x0000,0x0000,0x592a,0x0000,
+	0x592d,0x0000,0x0000,0x592b,0x0000,0x0000,0x0000,0x0000,
+	0x592e,0x0000,0x0000,0x0000,0x0000,0x0000,0x4a31,0x0000,
+	0x0000,0x3037,0x0000,0x0000,0x0000,0x0000,0x495e,0x0000,
+	0x0000,0x4863,0x0000,0x0000,0x592f,0x0000,0x5932,0x3e35,
+	0x353b,0x0000,0x5930,0x5937,0x3e36,0x0000,0x0000,0x0000,
+	0x0000,0x5931,0x4744,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x4d5e,0x5933,0x5934,0x5938,0x456a,0x5935,0x3933,
+	0x405e,0x0000,0x0000,0x5946,0x4834,0x0000,0x4272,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x7a2e,0x0000,
+	0x0000,0x0000,0x0000,0x4864,0x5a2d,0x0000,0x0000,0x0000,
+	0x0000,0x4a7a,0x0000,0x0000,0x0000,0x4471,0x0000,0x0000,
+	0x0000,0x4b75,0x0000,0x593b,0x3221,0x436a,0x0000,0x0000,
+	0x0000,0x0000,0x5944,0x0000,0x0000,0x4334,0x593e,0x5945,
+	0x5940,0x5947,0x5943,0x0000,0x5942,0x476f,0x0000,0x593c,
+	0x327d,0x593a,0x3571,0x4273,0x5936,0x0000,0x0000,0x5939,
+	0x3934,0x405b,0x0000,0x3e37,0x5941,0x4752,0x0000,0x0000,
+	0x3572,0x3348,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x3367,0x3f21,0x5949,0x594e,
+	0x0000,0x594a,0x0000,0x377d,0x0000,0x594f,0x3b22,0x3969,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3d26,0x593d,
+	0};
+unsigned short unicode_rev_table99[] = {
+	0x0000,0x3b7d,0x594c,0x0000,0x0000,0x0000,0x0000,0x3b58,
+	0x594d,0x3044,0x0000,0x0000,0x5948,0x0000,0x0000,0x0000,
+	0x0000,0x4429,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x3573,0x0000,0x0000,0x0000,0x0000,0x0000,0x3634,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x594b,
+	0x3027,0x0000,0x0000,0x3a43,0x0000,0x0000,0x0000,0x3f36,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x4472,0x0000,0x0000,0x4854,0x5951,0x415e,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x422a,0x0000,0x0000,0x3b2b,0x5952,0x0000,0x5954,
+	0x5950,0x0000,0x0000,0x0000,0x0000,0x4a61,0x0000,0x443d,
+	0x0000,0x0000,0x0000,0x0000,0x415c,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4a7b,
+	0x3c4e,0x5960,0x0000,0x595f,0x0000,0x0000,0x3f78,0x0000,
+	0x0000,0x0000,0x377e,0x0000,0x0000,0x0000,0x5959,0x3e39,
+	0x0000,0x0000,0x4668,0x4731,0x0000,0x0000,0x0000,0x0000,
+	0x5957,0x0000,0x0000,0x415d,0x0000,0x0000,0x0000,0x0000,
+	0x3c78,0x595c,0x0000,0x0000,0x3e38,0x0000,0x5956,0x595b,
+	0x0000,0x0000,0x4753,0x0000,0x0000,0x0000,0x5955,0x0000,
+	0x3721,0x0000,0x0000,0x335d,0x0000,0x0000,0x0000,0x595d,
+	0x4e2b,0x3a4e,0x4335,0x595a,0x0000,0x405c,0x0000,0x3935,
+	0x3f64,0x3166,0x413c,0x5958,0x3545,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x3747,0x0000,0x444f,0x595e,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x415f,0x0000,0x0000,0x5961,0x0000,
+	0x5963,0x0000,0x0000,0x4237,0x5969,0x0000,0x5964,0x0000,
+	0x0000,0x5966,0x0000,0x0000,0x0000,0x0000,0x0000,0x4941,
+	0x4473,0x0000,0x5967,0x0000,0x0000,0x0000,0x4d2c,0x0000,
+	0x0000,0x0000,0x4d48,0x3439,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x302e,0x0000,0x5965,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x5962,0x0000,0x0000,0x0000,0x0000,0x3478,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x3167,0x7a2f,0x5968,0x0000,
+	0x0000,0x0000,0x4d49,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table100[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x596c,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x423b,0x0000,0x5973,
+	0x0000,0x0000,0x0000,0x596d,0x0000,0x0000,0x596a,0x5971,
+	0x0000,0x0000,0x0000,0x0000,0x5953,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x596e,0x0000,
+	0x5972,0x0000,0x0000,0x0000,0x4842,0x456b,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x596b,0x0000,0x596f,0x0000,
+	0x0000,0x0000,0x3748,0x0000,0x0000,0x0000,0x3a71,0x0000,
+	0x0000,0x0000,0x405d,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x5977,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x4526,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x7a30,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x5974,
+	0x0000,0x4b60,0x0000,0x0000,0x0000,0x0000,0x0000,0x5975,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x5976,0x0000,
+	0x4c4e,0x0000,0x4022,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x3762,0x0000,0x0000,0x0000,0x0000,
+	0x597d,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x3b35,0x597a,0x0000,0x5979,0x0000,0x0000,
+	0x0000,0x0000,0x4732,0x0000,0x0000,0x7a31,0x4635,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x4531,0x597b,0x0000,0x0000,
+	0x0000,0x597c,0x0000,0x496f,0x0000,0x4745,0x3b23,0x0000,
+	0x4071,0x0000,0x4b50,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x3349,0x0000,0x5a25,0x597e,0x0000,0x0000,0x0000,
+	0x0000,0x4d4a,0x5a27,0x0000,0x0000,0x5a23,0x0000,0x5a24,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x4160,0x7a32,0x0000,
+	0x0000,0x0000,0x5a22,0x0000,0x593f,0x0000,0x0000,0x0000,
+	0x5a26,0x0000,0x5a21,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x5a2b,0x5a2c,0x4527,0x5a2e,0x0000,0x0000,0x3b24,0x5a29,
+	0x0000,0x0000,0x0000,0x0000,0x353c,0x0000,0x0000,0x5a2f,
+	0x0000,0x5a28,0x5a33,0x0000,0x5a32,0x0000,0x5a31,0x0000,
+	0x0000,0x0000,0x5a34,0x0000,0x0000,0x5a36,0x3e71,0x0000,
+	0};
+unsigned short unicode_rev_table101[] = {
+	0x5a35,0x0000,0x0000,0x0000,0x0000,0x5a39,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x5a37,0x0000,0x0000,0x0000,0x5a38,0x5970,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x5a3b,0x5a3a,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x5978,0x5a3c,0x5a30,0x0000,0x0000,0x3b59,
+	0x0000,0x0000,0x0000,0x0000,0x5a3d,0x5a3e,0x5a40,0x5a3f,
+	0x5a41,0x327e,0x0000,0x3936,0x0000,0x0000,0x4a7c,0x402f,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x384e,0x0000,0x0000,
+	0x5a43,0x0000,0x0000,0x0000,0x0000,0x5a46,0x7a33,0x4952,
+	0x0000,0x355f,0x0000,0x0000,0x0000,0x5a45,0x5a44,0x4754,
+	0x5a47,0x3635,0x0000,0x0000,0x0000,0x5a49,0x5a48,0x0000,
+	0x0000,0x0000,0x343a,0x3b36,0x0000,0x0000,0x4658,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x3749,0x0000,0x0000,0x0000,
+	0x3f74,0x0000,0x5a4a,0x0000,0x4030,0x4528,0x0000,0x495f,
+	0x5a4b,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x5a4c,0x5a4d,0x0000,0x0000,0x0000,0x4a38,
+	0x555d,0x4046,0x0000,0x0000,0x494c,0x0000,0x3a58,0x0000,
+	0x4865,0x4843,0x0000,0x0000,0x0000,0x0000,0x0000,0x454d,
+	0x0000,0x4e41,0x0000,0x5a4f,0x3c50,0x0000,0x0000,0x5a50,
+	0x0000,0x3036,0x0000,0x0000,0x3654,0x404d,0x0000,0x4960,
+	0x0000,0x0000,0x0000,0x5a51,0x3b42,0x4347,0x0000,0x3b5b,
+	0x3f37,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x5a52,
+	0x0000,0x4a7d,0x0000,0x0000,0x3177,0x3b5c,0x0000,0x0000,
+	0x0000,0x5a55,0x0000,0x5a53,0x5a56,0x4e39,0x5a54,0x0000,
+	0x0000,0x0000,0x0000,0x407b,0x5a57,0x0000,0x0000,0x4232,
+	0x0000,0x0000,0x5a58,0x0000,0x0000,0x0000,0x0000,0x347a,
+	0x0000,0x5a5a,0x0000,0x5a59,0x0000,0x0000,0x0000,0x0000,
+	0x5a5b,0x5a5c,0x347b,0x0000,0x0000,0x467c,0x4336,0x356c,
+	0x3b5d,0x4161,0x0000,0x0000,0x3d5c,0x3030,0x0000,0x0000,
+	0x0000,0x5a5d,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x3222,0x5a61,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table102[] = {
+	0x7a34,0x0000,0x3937,0x5a60,0x0000,0x0000,0x3a2b,0x3e3a,
+	0x0000,0x7a37,0x5a5f,0x0000,0x3e3b,0x0000,0x4c40,0x3a2a,
+	0x0000,0x0000,0x0000,0x3057,0x404e,0x7a35,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x5a66,0x0000,0x7a39,0x4031,
+	0x3147,0x0000,0x0000,0x0000,0x7a3a,0x3d55,0x0000,0x4b66,
+	0x3a72,0x0000,0x0000,0x0000,0x0000,0x3e3c,0x7a38,0x4027,
+	0x0000,0x7928,0x0000,0x0000,0x5a65,0x5a63,0x5a64,0x0000,
+	0x0000,0x0000,0x0000,0x7a36,0x436b,0x0000,0x0000,0x5b26,
+	0x0000,0x5a6a,0x3b7e,0x3938,0x5a68,0x0000,0x0000,0x0000,
+	0x0000,0x5a69,0x0000,0x3f38,0x0000,0x0000,0x0000,0x5a67,
+	0x0000,0x0000,0x3b2f,0x0000,0x0000,0x0000,0x0000,0x7a3c,
+	0x0000,0x7a3d,0x0000,0x0000,0x0000,0x5a6c,0x5a6b,0x5a70,
+	0x0000,0x0000,0x5a71,0x0000,0x5a6d,0x7a3b,0x3322,0x5a6e,
+	0x5a6f,0x4855,0x0000,0x0000,0x0000,0x0000,0x4961,0x374a,
+	0x5a72,0x0000,0x0000,0x7a3f,0x4032,0x0000,0x3e3d,0x0000,
+	0x0000,0x0000,0x4352,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x3647,0x0000,0x5a73,0x5a77,0x0000,0x0000,0x324b,
+	0x5a74,0x5a76,0x0000,0x0000,0x0000,0x0000,0x5a75,0x0000,
+	0x0000,0x3d6b,0x0000,0x0000,0x0000,0x0000,0x4348,0x3045,
+	0x5a78,0x7a40,0x0000,0x0000,0x0000,0x5a79,0x0000,0x0000,
+	0x7a41,0x0000,0x442a,0x0000,0x0000,0x0000,0x4e71,0x0000,
+	0x0000,0x0000,0x0000,0x3b43,0x0000,0x0000,0x4a6b,0x0000,
+	0x0000,0x0000,0x7a42,0x0000,0x4b3d,0x0000,0x0000,0x0000,
+	0x5b22,0x5a7b,0x0000,0x0000,0x5a7e,0x0000,0x5a7d,0x7a43,
+	0x0000,0x5a7a,0x0000,0x0000,0x5b21,0x0000,0x0000,0x465e,
+	0x0000,0x5a7c,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x5b23,0x0000,
+	0x0000,0x3d6c,0x5b24,0x0000,0x4d4b,0x4778,0x0000,0x0000,
+	0x5b25,0x0000,0x0000,0x0000,0x0000,0x0000,0x5b27,0x0000,
+	0x0000,0x5b28,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x5b29,0x0000,0x364a,0x3148,0x3939,0x5b2a,0x0000,0x5b2b,
+	0x3d71,0x4162,0x7a44,0x792b,0x5258,0x413e,0x413d,0x4258,
+	0};
+unsigned short unicode_rev_table103[] = {
+	0x3a47,0x0000,0x0000,0x5072,0x0000,0x0000,0x0000,0x0000,
+	0x376e,0x4d2d,0x0000,0x4a7e,0x0000,0x497e,0x7a45,0x5b2c,
+	0x0000,0x0000,0x0000,0x0000,0x3a73,0x443f,0x5b2d,0x4f2f,
+	0x0000,0x0000,0x0000,0x4b3e,0x0000,0x442b,0x5b2e,0x347c,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x5b2f,0x5b30,
+	0x4c5a,0x0000,0x4c24,0x4b76,0x4b5c,0x3b25,0x5b32,0x0000,
+	0x0000,0x3c6b,0x0000,0x0000,0x4b51,0x0000,0x5b34,0x5b37,
+	0x5b36,0x0000,0x3479,0x0000,0x0000,0x3560,0x0000,0x5b33,
+	0x0000,0x5b35,0x0000,0x0000,0x0000,0x0000,0x5b38,0x0000,
+	0x0000,0x3f79,0x0000,0x0000,0x0000,0x0000,0x4d7b,0x3049,
+	0x3a60,0x423c,0x0000,0x3c5d,0x0000,0x0000,0x3e73,0x0000,
+	0x0000,0x5b3b,0x0000,0x0000,0x454e,0x0000,0x5b39,0x422b,
+	0x5b3a,0x3e72,0x4c5d,0x5b3c,0x5b3d,0x4d68,0x7a47,0x0000,
+	0x0000,0x0000,0x5b42,0x0000,0x0000,0x393a,0x0000,0x4755,
+	0x5b3f,0x456c,0x5a5e,0x5a62,0x0000,0x354f,0x0000,0x4747,
+	0x0000,0x0000,0x0000,0x0000,0x5b41,0x0000,0x3e3e,0x4844,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x5b47,0x0000,0x487a,
+	0x0000,0x5b3e,0x0000,0x5b44,0x5b43,0x0000,0x0000,0x0000,
+	0x404f,0x0000,0x0000,0x0000,0x0000,0x4b6d,0x0000,0x4e53,
+	0x0000,0x0000,0x4b67,0x0000,0x324c,0x3b5e,0x0000,0x0000,
+	0x4f48,0x5b46,0x3f75,0x0000,0x0000,0x0000,0x5b45,0x0000,
+	0x0000,0x5b40,0x0000,0x0000,0x0000,0x0000,0x0000,0x384f,
+	0x0000,0x0000,0x0000,0x5b4c,0x5b4a,0x0000,0x324d,0x5b48,
+	0x5b4e,0x5b54,0x0000,0x7a48,0x0000,0x0000,0x0000,0x0000,
+	0x7a4a,0x4248,0x0000,0x0000,0x4a41,0x0000,0x5b56,0x0000,
+	0x0000,0x0000,0x4922,0x0000,0x0000,0x0000,0x5b55,0x4770,
+	0x4b3f,0x343b,0x0000,0x4077,0x3d40,0x0000,0x0000,0x0000,
+	0x4453,0x0000,0x4d2e,0x0000,0x0000,0x5b51,0x5b50,0x0000,
+	0x0000,0x0000,0x5b52,0x0000,0x5b4f,0x0000,0x0000,0x5b57,
+	0x0000,0x5b4d,0x0000,0x0000,0x5b4b,0x0000,0x5b53,0x5b49,
+	0x0000,0x436c,0x0000,0x4c78,0x3c46,0x3a74,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x3a3a,0x0000,0x0000,0x4b6f,0x3341,
+	0};
+unsigned short unicode_rev_table104[] = {
+	0x0000,0x7a4b,0x444e,0x464a,0x3149,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x4072,0x0000,0x0000,0x4034,0x372a,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x5b59,0x0000,
+	0x0000,0x393b,0x337c,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x5b5b,0x3374,0x5b61,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x5b5e,0x0000,0x4073,0x0000,0x0000,0x0000,
+	0x334b,0x3a2c,0x0000,0x0000,0x334a,0x3a4f,0x0000,0x0000,
+	0x5b5c,0x3765,0x374b,0x456d,0x7a4c,0x0000,0x5b5a,0x0000,
+	0x3046,0x0000,0x0000,0x0000,0x0000,0x5b5d,0x5b5f,0x0000,
+	0x364d,0x372c,0x7a49,0x343c,0x354b,0x0000,0x0000,0x0000,
+	0x0000,0x5b62,0x0000,0x0000,0x3a79,0x4b71,0x0000,0x3b37,
+	0x0000,0x0000,0x0000,0x5b63,0x0000,0x0000,0x0000,0x4930,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x5b6f,0x0000,0x3233,0x5b64,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x5b75,0x5b65,
+	0x0000,0x4e42,0x0000,0x5b6c,0x0000,0x475f,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x5b74,0x0000,0x5b67,
+	0x0000,0x0000,0x0000,0x3034,0x5b69,0x0000,0x0000,0x393c,
+	0x0000,0x0000,0x0000,0x5b6b,0x0000,0x5b6a,0x0000,0x5b66,
+	0x5b71,0x0000,0x3e3f,0x0000,0x0000,0x0000,0x546d,0x3868,
+	0x4d7c,0x0000,0x0000,0x0000,0x0000,0x5b68,0x0000,0x4474,
+	0x3323,0x3a2d,0x0000,0x5b60,0x0000,0x5b70,0x3361,0x0000,
+	0x0000,0x5b6e,0x5b72,0x0000,0x456e,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x347e,0x0000,0x5c32,0x0000,
+	0x7929,0x4c49,0x5b77,0x347d,0x0000,0x5b7e,0x0000,0x7a4d,
+	0x0000,0x0000,0x4b40,0x0000,0x5c21,0x5c23,0x0000,0x5c27,
+	0x5b79,0x0000,0x432a,0x0000,0x0000,0x0000,0x0000,0x456f,
+	0x5c2b,0x5b7c,0x0000,0x5c28,0x0000,0x0000,0x0000,0x5c22,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3f39,0x5c2c,
+	0x0000,0x0000,0x4033,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x5c2a,0x343d,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table105[] = {
+	0x4f50,0x5b76,0x0000,0x0000,0x5c26,0x3058,0x0000,0x0000,
+	0x5b78,0x0000,0x0000,0x4c3a,0x5b7d,0x3f22,0x4447,0x5b73,
+	0x0000,0x0000,0x5c25,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x3f7a,0x5c2f,0x3371,0x3821,0x0000,0x0000,0x0000,
+	0x0000,0x5c31,0x5b7a,0x5c30,0x0000,0x5c29,0x5b7b,0x0000,
+	0x5c2d,0x0000,0x5c2e,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x5c3f,0x0000,0x0000,0x0000,0x464e,0x0000,0x5c24,0x0000,
+	0x0000,0x5c3b,0x0000,0x0000,0x0000,0x5c3d,0x0000,0x4458,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x4d4c,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x4976,0x5c38,0x424a,0x0000,0x0000,
+	0x0000,0x5c3e,0x413f,0x0000,0x5c35,0x5c42,0x5c41,0x0000,
+	0x466f,0x5c40,0x466a,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x7a4f,0x0000,0x5c44,0x5c37,0x0000,0x3648,0x5c3a,0x3d5d,
+	0x0000,0x0000,0x0000,0x4760,0x5c3c,0x364b,0x0000,0x5c34,
+	0x5c36,0x5c33,0x0000,0x0000,0x4f30,0x335a,0x5c39,0x0000,
+	0x0000,0x5c43,0x3335,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x3a67,0x0000,0x0000,0x0000,0x315d,0x0000,
+	0x0000,0x5c54,0x0000,0x0000,0x4f31,0x5c57,0x0000,0x0000,
+	0x7a51,0x0000,0x0000,0x3f3a,0x5c56,0x0000,0x0000,0x0000,
+	0x5c55,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x5c52,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x5c46,0x0000,
+	0x0000,0x5c63,0x5c45,0x0000,0x5c58,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x5c50,0x0000,0x0000,0x5c4b,0x5c48,
+	0x0000,0x5c49,0x0000,0x5c51,0x0000,0x0000,0x0000,0x7422,
+	0x0000,0x0000,0x5c4e,0x393d,0x4448,0x4164,0x5c4c,0x0000,
+	0x5c47,0x0000,0x0000,0x5c4a,0x0000,0x0000,0x0000,0x0000,
+	0x4d4d,0x4b6a,0x0000,0x0000,0x0000,0x5c4f,0x5c59,0x0000,
+	0x0000,0x0000,0x7a52,0x0000,0x0000,0x0000,0x0000,0x5c61,
+	0x5c5a,0x0000,0x0000,0x5c67,0x0000,0x5c65,0x0000,0x0000,
+	0x0000,0x0000,0x5c60,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x5c5f,0x0000,0x4450,0x0000,0x4165,0x0000,0x5c5d,
+	0};
+unsigned short unicode_rev_table106[] = {
+	0x0000,0x0000,0x5c5b,0x0000,0x0000,0x5c62,0x0000,0x0000,
+	0x0000,0x0000,0x5c68,0x4875,0x5c6e,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x5c69,0x5c6c,0x5c66,0x0000,0x0000,0x4374,
+	0x0000,0x4938,0x0000,0x5c5c,0x0000,0x0000,0x5c64,0x3e40,
+	0x0000,0x4c4f,0x5c78,0x5c6b,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x3822,0x3223,0x335f,0x0000,0x0000,0x5c53,0x0000,
+	0x7a53,0x0000,0x0000,0x0000,0x0000,0x3e41,0x5c70,0x0000,
+	0x5c77,0x3c79,0x3372,0x0000,0x0000,0x432e,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x5c6d,0x0000,0x7a55,0x5c72,
+	0x5c76,0x0000,0x0000,0x3636,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x354c,0x5c74,0x0000,0x0000,0x0000,0x0000,0x0000,0x3521,
+	0x0000,0x464b,0x5c73,0x0000,0x0000,0x0000,0x5c75,0x0000,
+	0x0000,0x0000,0x0000,0x7a54,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x5c6f,0x7a56,0x0000,0x0000,0x0000,0x0000,
+	0x5c71,0x0000,0x0000,0x0000,0x0000,0x0000,0x7a57,0x3360,
+	0x4349,0x0000,0x0000,0x0000,0x5c7c,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x5c7a,0x3869,0x0000,
+	0x5c79,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x5d21,
+	0x0000,0x0000,0x0000,0x0000,0x5b58,0x0000,0x0000,0x0000,
+	0x5c7b,0x0000,0x5c7d,0x5c7e,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x5d2c,0x0000,0x5d28,0x0000,0x5b6d,0x0000,
+	0x0000,0x0000,0x0000,0x5d27,0x0000,0x0000,0x0000,0x0000,
+	0x5d26,0x0000,0x0000,0x5d23,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x5c6a,0x5d25,0x5d24,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x5d2a,0x0000,0x4f26,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x5d2d,0x367b,0x0000,0x0000,0x5d29,0x5d2b,
+	0x0000,0x0000,0x7a58,0x0000,0x7a59,0x0000,0x0000,0x0000,
+	0x4827,0x0000,0x5d2e,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x5d32,0x5d2f,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table107[] = {
+	0x0000,0x0000,0x0000,0x0000,0x4d73,0x5d30,0x0000,0x0000,
+	0x0000,0x0000,0x5c5e,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x5d33,0x0000,0x0000,0x0000,0x5d34,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x3135,0x0000,0x5d36,
+	0x3767,0x3c21,0x0000,0x3655,0x0000,0x0000,0x0000,0x3224,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x4d5f,0x0000,0x0000,0x0000,0x0000,0x5d38,
+	0x5d37,0x5d3a,0x353d,0x0000,0x0000,0x3656,0x343e,0x0000,
+	0x0000,0x0000,0x0000,0x5d3d,0x0000,0x0000,0x0000,0x5d3c,
+	0x0000,0x5d3e,0x0000,0x0000,0x324e,0x0000,0x4337,0x0000,
+	0x5d3f,0x0000,0x0000,0x343f,0x5d41,0x0000,0x0000,0x0000,
+	0x0000,0x5d40,0x0000,0x5d42,0x0000,0x0000,0x0000,0x5d43,
+	0x0000,0x5d44,0x3b5f,0x4035,0x3a21,0x0000,0x4970,0x0000,
+	0x0000,0x4a62,0x4f44,0x0000,0x0000,0x0000,0x0000,0x3b75,
+	0x0000,0x0000,0x0000,0x3a50,0x4e72,0x0000,0x0000,0x0000,
+	0x5d45,0x5d46,0x0000,0x3b60,0x0000,0x0000,0x0000,0x5d47,
+	0x5d48,0x0000,0x0000,0x5d4a,0x5d49,0x0000,0x4b58,0x0000,
+	0x0000,0x3d5e,0x3c6c,0x3b44,0x0000,0x5d4b,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x5d4d,0x3f23,0x0000,
+	0x5d4c,0x0000,0x0000,0x0000,0x0000,0x0000,0x5d4e,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x5d4f,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x5d50,0x5d51,0x0000,0x0000,0x0000,0x5d52,
+	0x0000,0x5d54,0x5d53,0x5d55,0x3225,0x434a,0x0000,0x5d56,
+	0x0000,0x0000,0x3b26,0x334c,0x5d57,0x0000,0x0000,0x4542,
+	0x544c,0x0000,0x0000,0x0000,0x0000,0x3523,0x5d58,0x0000,
+	0x0000,0x0000,0x0000,0x5d59,0x0000,0x4a6c,0x4b68,0x0000,
+	0x0000,0x0000,0x4647,0x5d5a,0x4866,0x0000,0x7a5a,0x0000,
+	0x487b,0x0000,0x0000,0x4c53,0x0000,0x0000,0x0000,0x5d5b,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x5d5d,0x5d5c,0x0000,0x0000,0x5d5f,
+	0x0000,0x0000,0x0000,0x5d5e,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table108[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x5d61,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3b61,
+	0x0000,0x4c31,0x0000,0x5d62,0x5d63,0x0000,0x0000,0x3524,
+	0x0000,0x0000,0x0000,0x5d64,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x5d66,0x5d65,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x3f65,0x0000,0x0000,0x4939,
+	0x314a,0x0000,0x0000,0x0000,0x0000,0x0000,0x4845,0x7a5b,
+	0x4475,0x3d41,0x3561,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4846,0x0000,
+	0x3c2e,0x0000,0x0000,0x0000,0x0000,0x5d68,0x0000,0x3440,
+	0x0000,0x0000,0x3178,0x0000,0x7a5c,0x4672,0x5d67,0x393e,
+	0x4353,0x0000,0x5d69,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x5d71,0x0000,0x5d6a,0x0000,0x0000,0x0000,0x0000,0x7a5e,
+	0x4241,0x0000,0x3562,0x5d72,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x3768,0x0000,0x0000,0x3525,0x5d70,0x0000,
+	0x0000,0x5d6e,0x5d6b,0x4d60,0x0000,0x0000,0x7a5d,0x0000,
+	0x4440,0x0000,0x0000,0x0000,0x4659,0x5d6c,0x0000,0x0000,
+	0x5d74,0x0000,0x5d73,0x3723,0x0000,0x0000,0x322d,0x0000,
+	0x0000,0x3a3b,0x5d6d,0x5d6f,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x4b57,0x4274,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x4b77,0x0000,0x0000,0x5d7c,0x0000,
+	0x0000,0x5d7d,0x0000,0x324f,0x0000,0x0000,0x0000,0x0000,
+	0x4a28,0x4c7d,0x5e21,0x3c23,0x3e42,0x5d78,0x5d7e,0x3168,
+	0x0000,0x3637,0x0000,0x0000,0x5d75,0x5d7a,0x0000,0x0000,
+	0x0000,0x4074,0x4771,0x0000,0x4867,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x5d77,0x0000,0x4b21,0x0000,0x5d79,
+	0x0000,0x5e24,0x7a5f,0x5e22,0x0000,0x5d7b,0x0000,0x0000,
+	0x0000,0x4b22,0x4748,0x3563,0x0000,0x4525,0x0000,0x0000,
+	0x436d,0x0000,0x5e25,0x0000,0x0000,0x0000,0x0000,0x5e23,
+	0x4259,0x5d76,0x0000,0x314b,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table109[] = {
+	0x0000,0x0000,0x0000,0x0000,0x7a60,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x4d4e,0x5e30,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x5e2f,0x0000,0x0000,0x0000,0x0000,0x4076,
+	0x0000,0x5e2c,0x0000,0x4d6c,0x0000,0x0000,0x4636,0x5e26,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x4445,0x0000,0x0000,
+	0x0000,0x314c,0x393f,0x5e29,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x3d27,0x5e2e,0x0000,0x5e2d,0x5e28,0x0000,
+	0x5e2b,0x0000,0x0000,0x3368,0x0000,0x5e2a,0x4749,0x0000,
+	0x0000,0x4e2e,0x0000,0x0000,0x3e74,0x4075,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x5e36,0x5e34,0x0000,0x494d,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x5e31,0x5e33,0x0000,0x313a,0x0000,
+	0x0000,0x3940,0x4f32,0x0000,0x333d,0x0000,0x4962,0x7a62,
+	0x0000,0x0000,0x0000,0x0000,0x4d61,0x0000,0x0000,0x3324,
+	0x3f3b,0x5e35,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x5e3a,0x0000,0x7a61,
+	0x3e43,0x0000,0x0000,0x0000,0x4d30,0x0000,0x5e37,0x0000,
+	0x0000,0x0000,0x0000,0x5e32,0x0000,0x5e38,0x7a63,0x0000,
+	0x0000,0x4e5e,0x0000,0x4573,0x4642,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x7a64,0x0000,0x0000,0x3336,
+	0x0000,0x0000,0x3155,0x0000,0x0000,0x5e3e,0x0000,0x0000,
+	0x5e41,0x0000,0x0000,0x0000,0x4e43,0x0000,0x0000,0x0000,
+	0x4d64,0x0000,0x0000,0x0000,0x0000,0x5e48,0x5e42,0x5e3f,
+	0x0000,0x0000,0x0000,0x4e54,0x5e45,0x0000,0x0000,0x7a65,
+	0x0000,0x3d4a,0x5e47,0x0000,0x0000,0x5e4c,0x0000,0x0000,
+	0x4571,0x5e4a,0x0000,0x0000,0x0000,0x0000,0x5e44,0x0000,
+	0x0000,0x4338,0x0000,0x0000,0x5e4b,0x0000,0x5e40,0x0000,
+	0x5e46,0x0000,0x5e4d,0x307c,0x5e43,0x0000,0x5e4e,0x0000,
+	0x0000,0x3f3c,0x7a67,0x3d5f,0x0000,0x4a25,0x0000,0x3a2e,
+	0x7a66,0x5e3b,0x5e49,0x453a,0x7a68,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table110[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x4036,0x0000,0x3369,
+	0x3a51,0x3e44,0x5e3d,0x3d42,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x374c,0x0000,0x5e3c,0x0000,0x0000,
+	0x0000,0x5e52,0x3d6d,0x383a,0x0000,0x5e61,0x0000,0x5e5b,
+	0x3574,0x454f,0x0000,0x5e56,0x5e5f,0x302f,0x3132,0x7a6b,
+	0x0000,0x3239,0x0000,0x5e58,0x422c,0x5e4f,0x5e51,0x3941,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x5e62,0x7a69,0x5e5d,0x0000,0x7a6c,0x0000,0x5e55,0x0000,
+	0x0000,0x0000,0x0000,0x5e5c,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x4c2b,0x0000,0x0000,0x5e5a,0x5e5e,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3850,0x0000,
+	0x3e45,0x0000,0x0000,0x4339,0x7a6a,0x0000,0x0000,0x5e54,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4d2f,
+	0x0000,0x0000,0x0000,0x5e57,0x0000,0x0000,0x5e50,0x4572,
+	0x0000,0x0000,0x5e53,0x0000,0x0000,0x0000,0x5e59,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4f51,0x3c3e,
+	0x4b7e,0x0000,0x5e63,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x482e,0x0000,0x0000,0x5e6f,
+	0x383b,0x0000,0x0000,0x0000,0x0000,0x0000,0x3d60,0x0000,
+	0x5e65,0x0000,0x0000,0x0000,0x4e2f,0x3942,0x0000,0x5e72,
+	0x0000,0x0000,0x306e,0x0000,0x0000,0x5e70,0x0000,0x0000,
+	0x0000,0x0000,0x5e64,0x0000,0x0000,0x0000,0x0000,0x5e6a,
+	0x0000,0x0000,0x5e6c,0x0000,0x0000,0x0000,0x4d4f,0x5e67,
+	0x0000,0x0000,0x452e,0x0000,0x0000,0x5e69,0x0000,0x7a6d,
+	0x0000,0x0000,0x5e71,0x0000,0x5e6b,0x4c47,0x0000,0x0000,
+	0x0000,0x5e66,0x0000,0x3c22,0x5e7e,0x0000,0x0000,0x0000,
+	0x0000,0x336a,0x0000,0x5e68,0x5e6d,0x5e6e,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x426c,0x425a,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x5e76,0x0000,0x0000,0x5e7c,
+	0x0000,0x0000,0x5e7a,0x0000,0x4529,0x0000,0x0000,0x5f23,
+	0x5e77,0x0000,0x0000,0x0000,0x0000,0x0000,0x5e78,0x5e60,
+	0};
+unsigned short unicode_rev_table111[] = {
+	0x0000,0x3579,0x493a,0x0000,0x0000,0x0000,0x3c3f,0x0000,
+	0x0000,0x3977,0x0000,0x0000,0x0000,0x0000,0x0000,0x4f33,
+	0x0000,0x5e74,0x0000,0x5f22,0x3169,0x4166,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x4779,0x0000,0x3441,0x4e7a,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x4c21,0x4452,0x0000,0x0000,0x0000,
+	0x0000,0x5e7b,0x5e7d,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x4132,0x0000,0x0000,0x0000,0x0000,0x0000,0x5f21,0x5e79,
+	0x0000,0x5e73,0x0000,0x0000,0x0000,0x3443,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x3769,0x0000,0x0000,0x0000,
+	0x5f2f,0x0000,0x0000,0x5f2a,0x4078,0x0000,0x0000,0x3363,
+	0x0000,0x0000,0x0000,0x0000,0x3d61,0x0000,0x5f33,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x5f2c,0x442c,0x5f29,
+	0x4459,0x0000,0x0000,0x0000,0x5f4c,0x0000,0x0000,0x0000,
+	0x5f26,0x0000,0x5f25,0x0000,0x5f2e,0x0000,0x0000,0x0000,
+	0x5f28,0x5f27,0x5f2d,0x0000,0x4021,0x0000,0x5f24,0x0000,
+	0x7a6e,0x0000,0x0000,0x0000,0x0000,0x0000,0x5f30,0x0000,
+	0x0000,0x5f31,0x0000,0x0000,0x0000,0x0000,0x0000,0x3442,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x5f36,0x0000,0x5f35,0x5f37,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x5f3a,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x4543,0x0000,0x5f34,0x0000,0x7a6f,0x0000,0x0000,
+	0x0000,0x5f38,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x3763,0x4279,0x5f32,0x473b,0x0000,0x0000,0x5f39,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x5f3e,0x5f3c,0x0000,0x0000,
+	0x5f3f,0x0000,0x0000,0x5f42,0x0000,0x0000,0x0000,0x5f3b,
+	0x396a,0x4728,0x0000,0x0000,0x5e39,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x4d74,0x5f3d,0x0000,0x5f41,0x4275,
+	0x0000,0x5f40,0x0000,0x5f2b,0x0000,0x7a70,0x6f69,0x0000,
+	0x0000,0x0000,0x5f45,0x0000,0x0000,0x0000,0x5f49,0x0000,
+	0};
+unsigned short unicode_rev_table112[] = {
+	0x0000,0x5f47,0x0000,0x0000,0x0000,0x7a71,0x0000,0x7a72,
+	0x0000,0x5f43,0x0000,0x5f44,0x0000,0x0000,0x0000,0x5f48,
+	0x0000,0x5f46,0x0000,0x0000,0x0000,0x494e,0x0000,0x0000,
+	0x5f4e,0x0000,0x5f4b,0x5f4a,0x0000,0x5f4d,0x4654,0x5f4f,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4375,0x426d,
+	0x7a73,0x0000,0x0000,0x0000,0x4025,0x0000,0x0000,0x0000,
+	0x5f50,0x0000,0x5f52,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x5f51,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x5e75,0x0000,0x0000,0x0000,
+	0x0000,0x5f53,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x4667,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x5f54,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x3250,0x0000,0x0000,0x0000,0x4574,
+	0x3325,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x3564,0x0000,0x0000,0x0000,0x3c5e,0x3a52,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x7a74,0x0000,0x0000,
+	0x0000,0x4f27,0x3f66,0x0000,0x0000,0x0000,0x316a,0x0000,
+	0x0000,0x0000,0x5f56,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x5f55,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x7a75,0x5f59,0x433a,0x5f5c,0x5f57,
+	0x0000,0x0000,0x0000,0x5f5b,0x0000,0x0000,0x0000,0x0000,
+	0x5f5a,0x4540,0x3059,0x7927,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x4e75,0x0000,0x0000,0x5f5e,0x0000,0x0000,0x0000,0x3128,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x5f60,0x0000,0x0000,0x0000,0x5f5f,0x0000,0x5f5d,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x5f58,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x4b23,0x0000,0x0000,0x0000,0x5f62,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table113[] = {
+	0x0000,0x0000,0x0000,0x0000,0x7a77,0x0000,0x0000,0x0000,
+	0x0000,0x5f61,0x0000,0x0000,0x0000,0x0000,0x0000,0x7a76,
+	0x0000,0x0000,0x0000,0x0000,0x316b,0x0000,0x0000,0x0000,
+	0x0000,0x5f64,0x4a32,0x0000,0x5f63,0x0000,0x0000,0x0000,
+	0x0000,0x4c35,0x0000,0x0000,0x0000,0x0000,0x3e47,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4133,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x3e46,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x7a79,0x7a7a,
+	0x0000,0x4e7b,0x0000,0x0000,0x5f6a,0x0000,0x4079,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x5f66,0x5f6b,0x0000,
+	0x0000,0x316c,0x0000,0x0000,0x7a78,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x5f69,0x0000,0x4761,0x5f65,0x5f68,0x3e48,
+	0x0000,0x4851,0x0000,0x0000,0x5f6c,0x0000,0x3c51,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x407a,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x5f6f,0x0000,0x0000,0x0000,
+	0x5f67,0x0000,0x3727,0x0000,0x0000,0x0000,0x0000,0x5f6d,
+	0x0000,0x0000,0x0000,0x0000,0x4d50,0x5f70,0x0000,0x0000,
+	0x0000,0x7426,0x0000,0x0000,0x0000,0x0000,0x0000,0x3d4f,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x5f71,0x0000,0x0000,0x0000,0x5f72,0x0000,0x0000,0x0000,
+	0x0000,0x472e,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x5f74,0x0000,0x0000,0x0000,0x0000,0x5f75,0x0000,
+	0x0000,0x7a7c,0x0000,0x4733,0x0000,0x0000,0x0000,0x0000,
+	0x4575,0x5f77,0x0000,0x0000,0x0000,0x0000,0x5f79,0x0000,
+	0x4e55,0x0000,0x5f76,0x0000,0x5f78,0x316d,0x0000,0x5f73,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x535b,
+	0x5f7a,0x0000,0x0000,0x0000,0x0000,0x4167,0x3b38,0x5f7c,
+	0x0000,0x0000,0x0000,0x0000,0x5f7b,0x3f24,0x5259,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x5f7d,0x0000,0x0000,
+	0x0000,0x6021,0x0000,0x5f6e,0x5f7e,0x0000,0x7a7d,0x6022,
+	0};
+unsigned short unicode_rev_table114[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x477a,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x6023,0x0000,0x0000,
+	0x6024,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x6025,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x6026,0x0000,0x445e,0x0000,0x6028,0x6027,0x0000,0x0000,
+	0x6029,0x0000,0x602a,0x0000,0x0000,0x3c5f,0x4963,0x0000,
+	0x0000,0x0000,0x4c6c,0x602b,0x602c,0x4156,0x3c24,0x602d,
+	0x602e,0x0000,0x0000,0x0000,0x0000,0x0000,0x602f,0x4a52,
+	0x4847,0x0000,0x0000,0x6030,0x4757,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x442d,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x6031,0x3267,0x0000,0x356d,0x0000,0x4c46,0x0000,0x4c36,
+	0x0000,0x3234,0x4f34,0x0000,0x0000,0x0000,0x0000,0x4b52,
+	0x0000,0x4a2a,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x4037,0x0000,0x6032,0x0000,0x0000,0x0000,
+	0x0000,0x4643,0x0000,0x0000,0x0000,0x3823,0x6033,0x0000,
+	0x3a54,0x6035,0x6034,0x0000,0x0000,0x0000,0x0000,0x6036,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6037,0x0000,0x0000,0x0000,0x6038,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x353e,0x0000,0x6039,0x0000,0x0000,0x0000,0x0000,0x603a,
+	0x0000,0x0000,0x0000,0x0000,0x3824,0x0000,0x0000,0x4848,
+	0x0000,0x7a7e,0x603c,0x0000,0x0000,0x0000,0x3e75,0x0000,
+	0x0000,0x603b,0x0000,0x0000,0x0000,0x0000,0x7b21,0x0000,
+	0x0000,0x0000,0x3638,0x603d,0x603f,0x0000,0x603e,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6040,0x0000,
+	0x3851,0x0000,0x6041,0x0000,0x0000,0x0000,0x0000,0x3669,
+	0x0000,0x4140,0x0000,0x397d,0x0000,0x0000,0x0000,0x0000,
+	0x6043,0x6044,0x6042,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x3c6d,0x0000,0x0000,0x4648,0x3639,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6046,
+	0x432c,0x6045,0x0000,0x0000,0x4f35,0x4762,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table115[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6049,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x604b,0x6048,
+	0x0000,0x0000,0x0000,0x4c54,0x604a,0x604c,0x0000,0x4e44,
+	0x0000,0x0000,0x0000,0x0000,0x7b22,0x6050,0x0000,0x0000,
+	0x0000,0x604f,0x4376,0x472d,0x0000,0x0000,0x3825,0x604e,
+	0x0000,0x0000,0x0000,0x0000,0x604d,0x0000,0x4d31,0x4d32,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6051,0x316e,
+	0x0000,0x0000,0x0000,0x0000,0x3976,0x3b62,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6052,0x6053,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6055,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x3d43,0x0000,0x0000,0x0000,0x0000,
+	0x6057,0x0000,0x6056,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x6058,0x0000,0x334d,0x0000,0x0000,0x605a,0x0000,0x7b24,
+	0x6059,0x0000,0x605c,0x605b,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x383c,0x0000,0x0000,0x4e28,
+	0x0000,0x364c,0x0000,0x3226,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x366a,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x3461,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x4e68,0x605e,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x6060,0x0000,0x7b25,0x0000,0x0000,
+	0x6061,0x0000,0x3251,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x605d,0x7b26,0x3b39,0x0000,0x0000,0x4441,0x605f,0x0000,
+	0x0000,0x0000,0x7b29,0x0000,0x0000,0x0000,0x7b27,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6064,0x0000,
+	0x3c6e,0x0000,0x0000,0x7b28,0x0000,0x6062,0x0000,0x0000,
+	0x0000,0x0000,0x373e,0x0000,0x0000,0x4849,0x6063,0x0000,
+	0x0000,0x607e,0x0000,0x0000,0x0000,0x7b2b,0x0000,0x0000,
+	0x6069,0x0000,0x0000,0x0000,0x0000,0x0000,0x383d,0x0000,
+	0};
+unsigned short unicode_rev_table116[] = {
+	0x0000,0x0000,0x0000,0x3565,0x0000,0x6066,0x4d7d,0x7b2a,
+	0x0000,0x4e30,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x4276,0x0000,0x0000,0x6068,0x7b2c,0x0000,
+	0x0000,0x7b2e,0x7b2d,0x0000,0x0000,0x0000,0x7b2f,0x0000,
+	0x0000,0x0000,0x606a,0x4e56,0x3657,0x487c,0x474a,0x0000,
+	0x0000,0x0000,0x606b,0x0000,0x0000,0x0000,0x0000,0x606d,
+	0x0000,0x6070,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x606c,0x0000,0x0000,
+	0x0000,0x606f,0x386a,0x314d,0x6071,0x0000,0x3f70,0x606e,
+	0x4e5c,0x0000,0x7b30,0x6074,0x7424,0x0000,0x0000,0x0000,
+	0x0000,0x6072,0x6075,0x0000,0x0000,0x0000,0x0000,0x6067,
+	0x6073,0x0000,0x0000,0x3a3c,0x0000,0x0000,0x6076,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6077,0x0000,
+	0x0000,0x0000,0x0000,0x4d7e,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x7b31,0x0000,0x6078,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6079,0x7b32,
+	0x0000,0x0000,0x6065,0x0000,0x0000,0x0000,0x0000,0x607a,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x3444,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x3c25,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x607b,0x0000,0x0000,0x0000,0x0000,0x607c,
+	0x0000,0x0000,0x0000,0x0000,0x607d,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x313b,0x0000,0x0000,0x0000,
+	0x6121,0x0000,0x493b,0x6122,0x0000,0x0000,0x3424,0x6123,
+	0x0000,0x6124,0x0000,0x0000,0x0000,0x0000,0x6125,0x0000,
+	0x6127,0x6128,0x6126,0x0000,0x0000,0x0000,0x4953,0x612a,
+	0x6129,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table117[] = {
+	0x0000,0x7b33,0x0000,0x612c,0x612b,0x612d,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x612e,0x6130,0x612f,0x0000,
+	0x0000,0x3979,0x0000,0x6132,0x0000,0x6131,0x0000,0x0000,
+	0x3445,0x0000,0x3f53,0x0000,0x453c,0x0000,0x6133,0x4038,
+	0x0000,0x0000,0x0000,0x3b3a,0x0000,0x3179,0x6134,0x0000,
+	0x4d51,0x0000,0x0000,0x4a63,0x6135,0x0000,0x0000,0x796c,
+	0x4544,0x4d33,0x3943,0x3f3d,0x0000,0x0000,0x0000,0x434b,
+	0x5234,0x0000,0x442e,0x3268,0x6136,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x6137,0x0000,0x613c,0x0000,
+	0x0000,0x613a,0x6139,0x5a42,0x3326,0x6138,0x0000,0x305a,
+	0x0000,0x482a,0x0000,0x0000,0x484a,0x0000,0x0000,0x0000,
+	0x0000,0x4e31,0x613d,0x613b,0x435c,0x4026,0x0000,0x0000,
+	0x482b,0x0000,0x492d,0x0000,0x613f,0x4e2c,0x374d,0x6140,
+	0x0000,0x613e,0x4856,0x6141,0x0000,0x6142,0x0000,0x7b34,
+	0x305b,0x0000,0x0000,0x3e76,0x6147,0x0000,0x6144,0x466d,
+	0x6143,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3526,
+	0x0000,0x0000,0x614a,0x0000,0x0000,0x0000,0x6145,0x6146,
+	0x0000,0x6149,0x6148,0x4925,0x0000,0x0000,0x4142,0x4141,
+	0x0000,0x353f,0x0000,0x0000,0x614b,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x614c,0x0000,0x0000,0x614d,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x614f,0x0000,0x614e,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x3156,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x6157,0x4868,0x6151,0x0000,0x6153,0x0000,0x0000,
+	0x6155,0x3f3e,0x0000,0x0000,0x6156,0x6154,0x3c40,0x0000,
+	0x0000,0x0000,0x6150,0x6152,0x0000,0x4942,0x0000,0x3e49,
+	0x0000,0x0000,0x6159,0x0000,0x0000,0x6158,0x0000,0x0000,
+	0x0000,0x0000,0x615a,0x0000,0x3c26,0x3a2f,0x0000,0x0000,
+	0x4577,0x615b,0x0000,0x444b,0x0000,0x0000,0x615d,0x0000,
+	0x0000,0x0000,0x4e21,0x615c,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x4169,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x6162,0x0000,0x6164,0x6165,0x4354,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6163,0x0000,0x6160,0x0000,0x615e,0x615f,
+	0};
+unsigned short unicode_rev_table118[] = {
+	0x0000,0x6161,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x6168,0x0000,0x6166,0x0000,0x6167,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6169,
+	0x616b,0x616c,0x616d,0x0000,0x616e,0x0000,0x0000,0x616a,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x6170,0x0000,0x0000,0x0000,0x616f,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x6171,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x4e45,0x0000,0x0000,0x0000,0x6174,0x6172,
+	0x6173,0x0000,0x0000,0x0000,0x3462,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x4c7e,0x0000,0x0000,0x0000,0x4a4a,0x0000,
+	0x6176,0x0000,0x0000,0x0000,0x6175,0x0000,0x0000,0x0000,
+	0x0000,0x6177,0x6178,0x0000,0x0000,0x0000,0x0000,0x617c,
+	0x6179,0x617a,0x617b,0x0000,0x617d,0x0000,0x0000,0x0000,
+	0x617e,0x0000,0x6221,0x0000,0x0000,0x0000,0x6222,0x0000,
+	0x6223,0x0000,0x482f,0x4550,0x6224,0x4772,0x4934,0x0000,
+	0x6225,0x0000,0x7b35,0x6226,0x452a,0x0000,0x3327,0x3944,
+	0x6227,0x0000,0x0000,0x6228,0x0000,0x0000,0x6229,0x0000,
+	0x3b29,0x0000,0x0000,0x622b,0x0000,0x0000,0x622a,0x0000,
+	0x0000,0x622c,0x622d,0x7b38,0x7b36,0x0000,0x7b37,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x7b39,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4869,0x0000,
+	0x622e,0x0000,0x0000,0x0000,0x622f,0x0000,0x0000,0x7369,
+	0x6230,0x6231,0x6232,0x0000,0x0000,0x0000,0x0000,0x3b2e,
+	0x0000,0x0000,0x6233,0x4756,0x0000,0x0000,0x4b5f,0x0000,
+	0x314e,0x0000,0x3157,0x0000,0x0000,0x6234,0x0000,0x0000,
+	0x0000,0x0000,0x6236,0x0000,0x0000,0x0000,0x6235,0x4570,
+	0x0000,0x0000,0x0000,0x4039,0x5d39,0x0000,0x6237,0x4c41,
+	0x0000,0x6238,0x0000,0x3446,0x4857,0x6239,0x0000,0x623a,
+	0x0000,0x0000,0x623b,0x0000,0x0000,0x0000,0x4c5c,0x0000,
+	0x0000,0x0000,0x4c55,0x0000,0x443e,0x0000,0x0000,0x0000,
+	0x416a,0x0000,0x0000,0x623d,0x0000,0x0000,0x3d62,0x0000,
+	0};
+unsigned short unicode_rev_table119[] = {
+	0x0000,0x3e4a,0x0000,0x0000,0x6240,0x0000,0x0000,0x623f,
+	0x623e,0x487d,0x0000,0x3447,0x3829,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x6246,0x0000,0x0000,0x6243,0x3f3f,
+	0x4c32,0x0000,0x0000,0x0000,0x6242,0x6244,0x6245,0x0000,
+	0x0000,0x6241,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6247,
+	0x6248,0x0000,0x442f,0x0000,0x3463,0x0000,0x0000,0x0000,
+	0x4365,0x0000,0x0000,0x0000,0x0000,0x0000,0x7b3b,0x6249,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x624a,0x624d,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x3f67,0x0000,0x4644,0x0000,0x624e,0x4b53,0x0000,
+	0x624b,0x0000,0x0000,0x624c,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x6251,0x0000,0x0000,0x0000,0x0000,0x6250,0x624f,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x6253,0x0000,0x0000,0x6252,0x0000,
+	0x0000,0x6254,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6256,0x0000,
+	0x6255,0x0000,0x0000,0x0000,0x0000,0x4a4d,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x3d56,0x4e46,0x0000,0x0000,
+	0x6257,0x0000,0x0000,0x4637,0x0000,0x0000,0x6258,0x0000,
+	0x0000,0x6259,0x0000,0x625d,0x625b,0x625c,0x0000,0x625a,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x625e,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x625f,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6260,
+	0x0000,0x0000,0x6261,0x4c37,0x6262,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x4c70,0x6263,0x0000,0x434e,0x0000,0x476a,
+	0x0000,0x366b,0x0000,0x0000,0x0000,0x433b,0x6264,0x363a,
+	0x0000,0x0000,0x0000,0x4050,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x6265,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table120[] = {
+	0x0000,0x0000,0x3a3d,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x6266,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6267,0x0000,0x3826,0x3a55,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x6269,0x7b3d,0x0000,0x0000,0x0000,0x4556,0x3a56,0x354e,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x4b24,0x0000,0x474b,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x4557,0x0000,0x0000,0x0000,0x0000,0x395c,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x626b,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x7b3e,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x3e4b,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x7b3f,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x4e32,0x3945,0x0000,0x0000,0x3827,
+	0x0000,0x0000,0x4823,0x0000,0x626d,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x7b40,0x0000,0x626f,0x0000,0x0000,0x0000,
+	0x0000,0x386b,0x0000,0x0000,0x0000,0x0000,0x626e,0x4476,
+	0x0000,0x0000,0x0000,0x0000,0x6271,0x3337,0x626c,0x0000,
+	0x0000,0x486a,0x0000,0x3130,0x0000,0x3a6c,0x0000,0x4f52,
+	0x0000,0x0000,0x6270,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x6272,0x0000,0x0000,0x0000,0x4a4b,
+	0x0000,0x4059,0x6274,0x0000,0x0000,0x0000,0x0000,0x6275,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x6273,0x0000,0x0000,
+	0x0000,0x0000,0x334e,0x0000,0x627b,0x0000,0x627a,0x0000,
+	0x0000,0x3c27,0x0000,0x0000,0x0000,0x627c,0x6277,0x0000,
+	0x0000,0x0000,0x627d,0x6278,0x0000,0x0000,0x0000,0x0000,
+	0x4858,0x6276,0x0000,0x0000,0x6279,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6322,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6321,
+	0x4b61,0x0000,0x0000,0x0000,0x627e,0x0000,0x0000,0x306b,
+	0x0000,0x0000,0x0000,0x0000,0x6324,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x6323,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table121[] = {
+	0x0000,0x3e4c,0x0000,0x0000,0x0000,0x0000,0x0000,0x6325,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4143,0x0000,
+	0x0000,0x6327,0x6326,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x6328,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6268,0x0000,
+	0x0000,0x0000,0x626a,0x632a,0x6329,0x0000,0x0000,0x0000,
+	0x7b41,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x3c28,0x0000,0x4e69,0x0000,0x3c52,0x0000,
+	0x632b,0x3737,0x0000,0x0000,0x0000,0x0000,0x0000,0x3540,
+	0x3527,0x3b63,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x4d34,0x0000,0x0000,0x6331,0x0000,0x6330,0x4144,0x632d,
+	0x0000,0x0000,0x632f,0x0000,0x0000,0x3d4b,0x3f40,0x632e,
+	0x632c,0x0000,0x472a,0x0000,0x0000,0x3e4d,0x0000,0x0000,
+	0x493c,0x0000,0x0000,0x0000,0x0000,0x3a57,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4578,
+	0x0000,0x0000,0x6332,0x0000,0x0000,0x0000,0x0000,0x6333,
+	0x6349,0x3658,0x0000,0x0000,0x4f3d,0x4135,0x0000,0x0000,
+	0x0000,0x0000,0x6334,0x0000,0x0000,0x3252,0x4477,0x4a21,
+	0x0000,0x0000,0x0000,0x0000,0x7b45,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x7b47,0x0000,0x6335,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x357a,0x6336,
+	0x0000,0x0000,0x6338,0x0000,0x0000,0x0000,0x6339,0x0000,
+	0x4729,0x0000,0x0000,0x633a,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x633b,0x633c,0x0000,0x0000,0x3659,0x3253,0x4645,
+	0x3d28,0x3b64,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x633d,0x0000,0x3d29,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x324a,0x4943,0x0000,0x0000,0x633e,0x0000,0x0000,
+	0x486b,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4145,
+	0x0000,0x6341,0x0000,0x6342,0x4769,0x0000,0x3f41,0x633f,
+	0x0000,0x4361,0x0000,0x0000,0x6340,0x0000,0x0000,0x0000,
+	0x3e4e,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x305c,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table122[] = {
+	0x3529,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x6343,0x0000,0x0000,0x4478,0x0000,0x6344,0x4047,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x4c2d,0x0000,0x0000,0x4923,
+	0x6345,0x6346,0x4355,0x0000,0x4e47,0x0000,0x0000,0x6348,
+	0x6347,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3c6f,0x0000,
+	0x0000,0x634a,0x3070,0x0000,0x0000,0x0000,0x0000,0x634d,
+	0x0000,0x0000,0x0000,0x634b,0x3254,0x374e,0x634c,0x3946,
+	0x3972,0x0000,0x4a66,0x634e,0x0000,0x0000,0x4b54,0x0000,
+	0x0000,0x6350,0x0000,0x0000,0x0000,0x4051,0x314f,0x323a,
+	0x302c,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x634f,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x6351,0x6352,0x3e77,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x6353,0x0000,0x334f,0x0000,0x0000,0x0000,0x0000,
+	0x6355,0x0000,0x0000,0x0000,0x376a,0x0000,0x3566,0x0000,
+	0x0000,0x6356,0x3675,0x0000,0x0000,0x6357,0x0000,0x407c,
+	0x0000,0x464d,0x0000,0x4060,0x3a75,0x0000,0x0000,0x0000,
+	0x6358,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x4362,0x416b,0x0000,0x635a,0x635c,0x6359,
+	0x635b,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3722,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x635d,0x3726,0x0000,0x0000,0x0000,0x3567,0x4d52,
+	0x635f,0x0000,0x0000,0x0000,0x0000,0x0000,0x6360,0x0000,
+	0x0000,0x0000,0x312e,0x0000,0x0000,0x0000,0x0000,0x6363,
+	0x0000,0x0000,0x0000,0x3376,0x6362,0x6361,0x0000,0x6365,
+	0x635e,0x0000,0x6366,0x4e29,0x0000,0x6367,0x0000,0x6368,
+	0x0000,0x7b48,0x5474,0x636a,0x0000,0x6369,0x0000,0x0000,
+	0x0000,0x636b,0x636c,0x0000,0x4e35,0x636d,0x0000,0x706f,
+	0x3e4f,0x636e,0x636f,0x3d57,0x0000,0x4638,0x6370,0x7b49,
+	0x0000,0x0000,0x4328,0x7b4b,0x0000,0x6371,0x0000,0x433c,
+	0x6372,0x0000,0x0000,0x0000,0x0000,0x0000,0x3625,0x0000,
+	0x513f,0x435d,0x3c33,0x0000,0x0000,0x0000,0x0000,0x3448,
+	0};
+unsigned short unicode_rev_table123[] = {
+	0x0000,0x0000,0x6373,0x0000,0x6422,0x0000,0x6376,0x0000,
+	0x3568,0x0000,0x6375,0x6424,0x0000,0x0000,0x0000,0x6374,
+	0x0000,0x3e50,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x6378,0x6379,0x0000,0x452b,0x0000,0x0000,0x637a,0x0000,
+	0x335e,0x0000,0x0000,0x0000,0x0000,0x3f5a,0x4964,0x0000,
+	0x637c,0x0000,0x0000,0x0000,0x4268,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x6377,0x0000,0x637b,0x637d,0x0000,
+	0x0000,0x3a7b,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x6426,0x492e,0x0000,
+	0x4826,0x4579,0x0000,0x365a,0x6425,0x6423,0x0000,0x4835,
+	0x637e,0x435e,0x457b,0x0000,0x457a,0x0000,0x3a76,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x6438,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x6428,0x0000,0x642a,
+	0x0000,0x0000,0x0000,0x0000,0x642d,0x0000,0x642e,0x0000,
+	0x642b,0x642c,0x0000,0x0000,0x6429,0x6427,0x0000,0x0000,
+	0x0000,0x0000,0x6421,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4a4f,0x3255,
+	0x0000,0x0000,0x0000,0x6435,0x0000,0x6432,0x0000,0x6437,
+	0x0000,0x0000,0x6436,0x0000,0x4773,0x4c27,0x0000,0x3b3b,
+	0x6430,0x6439,0x6434,0x0000,0x6433,0x642f,0x7b4c,0x6431,
+	0x0000,0x3449,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x433d,0x0000,0x0000,0x407d,0x0000,0x0000,
+	0x0000,0x4822,0x0000,0x0000,0x643e,0x0000,0x0000,0x0000,
+	0x4824,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x4061,0x643b,0x0000,0x0000,0x484f,0x0000,0x643f,0x4a53,
+	0x0000,0x435b,0x0000,0x643a,0x643c,0x0000,0x0000,0x643d,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x6440,0x0000,0x0000,
+	0x3c44,0x0000,0x0000,0x0000,0x4646,0x6445,0x6444,0x0000,
+	0x0000,0x6441,0x0000,0x0000,0x0000,0x4f36,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x644a,0x0000,0x0000,0x644e,0x644b,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table124[] = {
+	0x6447,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6448,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x644d,0x0000,0x0000,
+	0x0000,0x6442,0x5255,0x6449,0x6443,0x0000,0x0000,0x644c,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6452,
+	0x0000,0x344a,0x0000,0x644f,0x0000,0x0000,0x0000,0x6450,
+	0x0000,0x0000,0x6451,0x6454,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6453,
+	0x4876,0x0000,0x0000,0x0000,0x0000,0x6455,0x4e7c,0x4a6d,
+	0x645a,0x0000,0x0000,0x6457,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x6456,0x4052,0x0000,0x6459,
+	0x645b,0x0000,0x0000,0x0000,0x6458,0x0000,0x645f,0x0000,
+	0x645c,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x645d,
+	0x6446,0x0000,0x0000,0x0000,0x645e,0x6460,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x6461,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x4a46,0x0000,0x6462,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4c62,0x0000,
+	0x0000,0x364e,0x3729,0x6463,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x4a34,0x0000,0x3f68,0x0000,0x4c30,0x0000,0x0000,
+	0x6464,0x0000,0x4e33,0x0000,0x0000,0x4774,0x0000,0x4146,
+	0x4734,0x0000,0x0000,0x3d4d,0x0000,0x0000,0x0000,0x3040,
+	0x0000,0x6469,0x6467,0x0000,0x6465,0x3421,0x0000,0x3e51,
+	0x646a,0x0000,0x0000,0x6468,0x0000,0x6466,0x646e,0x0000,
+	0x0000,0x646d,0x646c,0x646b,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x646f,0x0000,0x0000,0x0000,0x6470,0x403a,0x0000,
+	0x6471,0x0000,0x6473,0x0000,0x0000,0x6472,0x0000,0x0000,
+	0x0000,0x0000,0x3852,0x0000,0x0000,0x0000,0x4138,0x0000,
+	0x0000,0x0000,0x6475,0x0000,0x0000,0x0000,0x457c,0x0000,
+	0x6474,0x0000,0x0000,0x0000,0x6476,0x0000,0x4a35,0x416c,
+	0x3947,0x0000,0x6477,0x0000,0x0000,0x0000,0x0000,0x4e48,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6479,
+	0x0000,0x0000,0x647a,0x0000,0x647b,0x0000,0x647c,0x0000,
+	0x3b65,0x0000,0x647d,0x374f,0x0000,0x0000,0x356a,0x0000,
+	0};
+unsigned short unicode_rev_table125[] = {
+	0x352a,0x0000,0x6521,0x0000,0x4c73,0x3948,0x647e,0x0000,
+	0x0000,0x0000,0x6524,0x4c66,0x0000,0x473c,0x0000,0x0000,
+	0x4933,0x0000,0x0000,0x0000,0x3d63,0x6523,0x0000,0x3c53,
+	0x3949,0x3b66,0x3569,0x4a36,0x6522,0x0000,0x0000,0x0000,
+	0x4147,0x4b42,0x3a77,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x3b67,0x445d,0x0000,0x6527,0x4e5f,
+	0x3a59,0x0000,0x6528,0x3f42,0x0000,0x652a,0x0000,0x0000,
+	0x0000,0x3e52,0x3a30,0x0000,0x0000,0x0000,0x0000,0x6529,
+	0x0000,0x0000,0x3d2a,0x383e,0x4148,0x6525,0x652b,0x0000,
+	0x7b4e,0x0000,0x0000,0x6526,0x3750,0x0000,0x652e,0x6532,
+	0x376b,0x0000,0x0000,0x0000,0x0000,0x0000,0x652d,0x0000,
+	0x0000,0x0000,0x0000,0x6536,0x7b4f,0x0000,0x394a,0x0000,
+	0x0000,0x4d6d,0x303c,0x6533,0x0000,0x0000,0x356b,0x0000,
+	0x6530,0x0000,0x0000,0x0000,0x0000,0x0000,0x6531,0x0000,
+	0x0000,0x457d,0x652f,0x652c,0x0000,0x3328,0x4064,0x0000,
+	0x0000,0x3828,0x0000,0x0000,0x0000,0x6538,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x6535,0x0000,0x0000,0x0000,0x0000,0x0000,0x6537,
+	0x0000,0x0000,0x0000,0x6534,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x3751,0x4233,0x6539,0x416e,0x0000,0x0000,0x6546,
+	0x7b51,0x0000,0x6542,0x653c,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x6540,0x3c7a,0x305d,0x653b,0x6543,
+	0x6547,0x394b,0x4c56,0x0000,0x4456,0x653d,0x0000,0x7b50,
+	0x6545,0x0000,0x653a,0x433e,0x0000,0x653f,0x303d,0x4c4a,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x653e,
+	0x0000,0x0000,0x365b,0x486c,0x0000,0x0000,0x0000,0x416d,
+	0x0000,0x4e50,0x3d6f,0x0000,0x0000,0x656e,0x7b52,0x0000,
+	0x6548,0x0000,0x407e,0x0000,0x6544,0x6549,0x654b,0x0000,
+	0x4479,0x654e,0x0000,0x0000,0x654a,0x0000,0x0000,0x0000,
+	0x4a54,0x344b,0x0000,0x0000,0x4c4b,0x0000,0x0000,0x305e,
+	0x0000,0x0000,0x654d,0x0000,0x4e7d,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x654c,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table126[] = {
+	0x0000,0x316f,0x0000,0x0000,0x466c,0x654f,0x0000,0x0000,
+	0x0000,0x6556,0x6550,0x6557,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6553,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x477b,0x0000,0x0000,0x3c4a,0x6555,
+	0x0000,0x6552,0x6558,0x6551,0x0000,0x0000,0x3d44,0x0000,
+	0x0000,0x0000,0x0000,0x4b25,0x0000,0x0000,0x3d4c,0x0000,
+	0x0000,0x6554,0x6560,0x0000,0x0000,0x655c,0x0000,0x655f,
+	0x0000,0x655d,0x6561,0x655b,0x0000,0x6541,0x4053,0x0000,
+	0x0000,0x484b,0x0000,0x655e,0x0000,0x0000,0x6559,0x0000,
+	0x0000,0x0000,0x4121,0x3752,0x0000,0x3d2b,0x0000,0x0000,
+	0x0000,0x0000,0x7b53,0x0000,0x3f25,0x4136,0x6564,0x0000,
+	0x0000,0x6566,0x6567,0x0000,0x0000,0x6563,0x6565,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x655a,0x6562,
+	0x0000,0x656a,0x6569,0x0000,0x0000,0x4b7a,0x0000,0x0000,
+	0x372b,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x6568,0x0000,0x656c,0x656b,0x656f,0x0000,0x6571,
+	0x0000,0x0000,0x3b3c,0x656d,0x0000,0x0000,0x0000,0x0000,
+	0x6572,0x6573,0x7921,0x0000,0x6574,0x0000,0x657a,0x453b,
+	0x6576,0x0000,0x6575,0x6577,0x6578,0x0000,0x6579,0x0000,
+	0x0000,0x0000,0x0000,0x657b,0x657c,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table127[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x344c,0x0000,
+	0x657d,0x0000,0x657e,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x6621,0x0000,0x7b54,
+	0x0000,0x0000,0x0000,0x0000,0x6622,0x6623,0x6624,0x0000,
+	0x6625,0x6626,0x0000,0x0000,0x6628,0x6627,0x0000,0x0000,
+	0x6629,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x662a,
+	0x662b,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x662e,
+	0x662c,0x662d,0x3a61,0x3753,0x0000,0x0000,0x4356,0x0000,
+	0x4833,0x0000,0x3d70,0x0000,0x0000,0x474d,0x0000,0x486d,
+	0x662f,0x586d,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6630,0x6632,0x0000,0x4d65,0x6631,0x6634,
+	0x6633,0x0000,0x4d53,0x0000,0x6635,0x0000,0x487e,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x6636,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6639,0x0000,0x0000,0x6638,0x6637,0x0000,
+	0x0000,0x7b55,0x0000,0x663a,0x3732,0x0000,0x0000,0x0000,
+	0x4122,0x3541,0x0000,0x0000,0x0000,0x0000,0x663e,0x663b,
+	0x0000,0x0000,0x663c,0x0000,0x0000,0x0000,0x663f,0x0000,
+	0x6640,0x663d,0x0000,0x0000,0x0000,0x3129,0x0000,0x0000,
+	0x0000,0x3227,0x0000,0x0000,0x0000,0x6642,0x6643,0x0000,
+	0x0000,0x0000,0x6644,0x0000,0x4d62,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x3d2c,0x0000,0x6646,0x6645,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x3f69,0x6647,0x0000,0x0000,0x0000,0x0000,0x6648,0x0000,
+	0x0000,0x6649,0x0000,0x3465,0x0000,0x0000,0x0000,0x0000,
+	0x344d,0x0000,0x0000,0x664a,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x664b,0x0000,0x4b5d,0x4d63,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table128[] = {
+	0x4d54,0x4f37,0x0000,0x394d,0x664e,0x3c54,0x664d,0x0000,
+	0x0000,0x0000,0x0000,0x664f,0x3c29,0x0000,0x0000,0x0000,
+	0x4251,0x0000,0x6650,0x0000,0x0000,0x394c,0x0000,0x4c57,
+	0x6651,0x6652,0x0000,0x0000,0x6653,0x0000,0x0000,0x0000,
+	0x0000,0x6654,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x6655,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x3c2a,0x0000,0x0000,0x4c6d,0x0000,
+	0x0000,0x0000,0x0000,0x6657,0x0000,0x433f,0x0000,0x6656,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6659,0x0000,
+	0x0000,0x0000,0x6658,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x665a,0x0000,0x0000,0x0000,0x403b,0x0000,
+	0x665b,0x0000,0x665c,0x0000,0x0000,0x0000,0x4a39,0x665d,
+	0x0000,0x416f,0x665e,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x665f,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4e7e,
+	0x6662,0x0000,0x6661,0x6660,0x4430,0x0000,0x6663,0x3f26,
+	0x0000,0x6664,0x0000,0x0000,0x0000,0x6665,0x4f38,0x6666,
+	0x0000,0x0000,0x0000,0x0000,0x6667,0x6669,0x6668,0x4825,
+	0x0000,0x4679,0x0000,0x4f3e,0x4829,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x666b,0x0000,0x0000,0x3e53,0x0000,
+	0x492a,0x0000,0x666c,0x666a,0x0000,0x344e,0x0000,0x0000,
+	0x0000,0x3854,0x3b68,0x0000,0x0000,0x486e,0x0000,0x0000,
+	0x0000,0x382a,0x4b43,0x0000,0x666f,0x666d,0x0000,0x394e,
+	0x0000,0x394f,0x3069,0x0000,0x3a68,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x4759,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x305f,0x6674,0x0000,0x4340,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x4758,0x0000,0x425b,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6676,0x0000,
+	0x0000,0x6672,0x6675,0x6670,0x0000,0x6673,0x4b26,0x0000,
+	0x0000,0x3855,0x0000,0x0000,0x307d,0x6671,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6678,
+	0x0000,0x6679,0x0000,0x0000,0x4639,0x0000,0x0000,0x0000,
+	0x363b,0x0000,0x0000,0x0000,0x6726,0x473d,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table129[] = {
+	0x0000,0x0000,0x3b69,0x0000,0x0000,0x363c,0x4048,0x4f46,
+	0x4c2e,0x6677,0x4054,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x3553,0x667a,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x667c,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x667b,0x0000,0x0000,0x0000,0x0000,0x0000,0x667d,
+	0x0000,0x4326,0x0000,0x473e,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x4431,0x0000,0x0000,0x0000,0x0000,0x6723,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6722,0x0000,
+	0x0000,0x0000,0x0000,0x667e,0x0000,0x0000,0x3f55,0x0000,
+	0x4965,0x6725,0x0000,0x6724,0x3950,0x4f53,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6735,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x6729,0x672a,0x0000,
+	0x0000,0x0000,0x0000,0x3c70,0x0000,0x0000,0x6728,0x0000,
+	0x3978,0x6727,0x0000,0x0000,0x672b,0x0000,0x0000,0x0000,
+	0x4432,0x4a22,0x4123,0x0000,0x0000,0x0000,0x0000,0x425c,
+	0x672f,0x0000,0x6730,0x672c,0x0000,0x0000,0x0000,0x0000,
+	0x672d,0x0000,0x672e,0x0000,0x0000,0x0000,0x0000,0x3951,
+	0x0000,0x0000,0x0000,0x6736,0x0000,0x6732,0x0000,0x0000,
+	0x0000,0x0000,0x4966,0x0000,0x4b6c,0x4928,0x0000,0x0000,
+	0x6731,0x0000,0x0000,0x6734,0x6733,0x0000,0x0000,0x0000,
+	0x4b44,0x6737,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x6738,0x0000,0x0000,0x4137,0x0000,0x6739,0x0000,0x0000,
+	0x673b,0x0000,0x673f,0x0000,0x0000,0x673c,0x673a,0x473f,
+	0x673d,0x0000,0x673e,0x0000,0x0000,0x0000,0x3232,0x0000,
+	0x6745,0x6740,0x0000,0x0000,0x0000,0x6741,0x0000,0x0000,
+	0x0000,0x6742,0x0000,0x4221,0x0000,0x0000,0x0000,0x0000,
+	0x6744,0x6743,0x6746,0x0000,0x0000,0x0000,0x0000,0x6747,
+	0x6748,0x0000,0x0000,0x3f43,0x0000,0x3269,0x0000,0x6749,
+	0x4e57,0x0000,0x3c2b,0x0000,0x0000,0x3d2d,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x3b6a,0x4357,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x674a,0x674b,0x3131,0x0000,0x674c,0x0000,
+	0};
+unsigned short unicode_rev_table130[] = {
+	0x0000,0x674d,0x674e,0x0000,0x0000,0x674f,0x0000,0x6750,
+	0x363d,0x5a2a,0x6751,0x0000,0x4065,0x6752,0x3c4b,0x0000,
+	0x6753,0x0000,0x5030,0x0000,0x0000,0x0000,0x6754,0x4a5e,
+	0x345c,0x0000,0x0000,0x4124,0x3d58,0x0000,0x4971,0x3d2e,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x6755,0x3952,0x6756,0x484c,0x0000,0x6764,0x0000,
+	0x0000,0x0000,0x0000,0x6758,0x0000,0x4249,0x4775,0x383f,
+	0x6757,0x4125,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x6759,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x447a,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x675b,0x675a,0x675d,0x0000,0x0000,0x675c,0x0000,0x675e,
+	0x0000,0x0000,0x6760,0x0000,0x675f,0x0000,0x344f,0x0000,
+	0x6761,0x0000,0x6762,0x6763,0x0000,0x0000,0x3a31,0x4e49,
+	0x0000,0x6765,0x3f27,0x0000,0x0000,0x0000,0x3170,0x6766,
+	0x6767,0x0000,0x0000,0x0000,0x0000,0x0000,0x6768,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x3072,0x0000,0x6769,0x0000,0x0000,
+	0x0000,0x0000,0x676a,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x4967,0x0000,0x0000,0x0000,0x3c47,0x0000,0x676c,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x3329,0x3032,0x0000,
+	0x0000,0x0000,0x0000,0x676b,0x676e,0x474e,0x0000,0x3f44,
+	0x0000,0x3256,0x0000,0x4b27,0x0000,0x0000,0x0000,0x0000,
+	0x375d,0x365c,0x0000,0x676d,0x0000,0x326a,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x3423,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x3171,0x6772,0x4e6a,0x425d,0x0000,0x0000,0x4944,
+	0x0000,0x677e,0x0000,0x3257,0x677c,0x0000,0x677a,0x6771,
+	0x0000,0x676f,0x0000,0x6770,0x0000,0x3c63,0x366c,0x4377,
+	0x0000,0x0000,0x0000,0x4651,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x3151,0x0000,0x6774,0x6773,0x0000,0x0000,0x0000,
+	0x0000,0x6779,0x6775,0x6778,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table131[] = {
+	0x0000,0x7b57,0x4c50,0x6777,0x3258,0x337d,0x677b,0x0000,
+	0x0000,0x677d,0x0000,0x0000,0x0000,0x0000,0x3754,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6823,0x682c,
+	0x682d,0x0000,0x0000,0x0000,0x302b,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x6834,0x0000,0x0000,0x0000,0x0000,
+	0x3071,0x0000,0x0000,0x682b,0x0000,0x0000,0x0000,0x682a,
+	0x0000,0x6825,0x6824,0x0000,0x6822,0x6821,0x4363,0x0000,
+	0x427b,0x6827,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x6826,0x0000,0x0000,0x0000,0x0000,0x6829,0x0000,0x0000,
+	0x0000,0x4170,0x3755,0x0000,0x0000,0x0000,0x0000,0x3141,
+	0x6828,0x0000,0x3953,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x4171,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x7b58,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x683a,0x0000,0x683b,0x0000,0x3259,
+	0x0000,0x0000,0x0000,0x322e,0x6838,0x0000,0x0000,0x7b59,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x682e,0x0000,0x6836,
+	0x0000,0x683d,0x6837,0x0000,0x0000,0x0000,0x6835,0x0000,
+	0x0000,0x0000,0x0000,0x6776,0x0000,0x0000,0x6833,0x0000,
+	0x0000,0x0000,0x682f,0x0000,0x0000,0x0000,0x3450,0x6831,
+	0x683c,0x0000,0x6832,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x683e,0x0000,0x6830,0x477c,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x4d69,0x0000,0x0000,0x0000,0x6839,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x684f,0x0000,0x0000,
+	0x0000,0x6847,0x0000,0x0000,0x0000,0x3f7b,0x0000,0x7b5a,
+	0x0000,0x0000,0x3546,0x0000,0x365d,0x0000,0x6842,0x0000,
+	0x0000,0x0000,0x0000,0x325b,0x0000,0x0000,0x3e54,0x0000,
+	0x6845,0x0000,0x0000,0x0000,0x3a5a,0x0000,0x0000,0x4551,
+	0x684a,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x4a6e,0x0000,0x6841,0x0000,0x0000,0x0000,0x325a,
+	0x3856,0x4929,0x684b,0x0000,0x683f,0x0000,0x7b5b,0x6848,
+	0x0000,0x0000,0x0000,0x6852,0x0000,0x6843,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table132[] = {
+	0x0000,0x0000,0x0000,0x6844,0x463a,0x0000,0x0000,0x6849,
+	0x0000,0x0000,0x0000,0x6846,0x4b28,0x684c,0x3060,0x0000,
+	0x0000,0x0000,0x0000,0x6840,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x684e,0x0000,0x684d,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x476b,0x6854,0x0000,0x685f,0x0000,0x0000,0x0000,
+	0x0000,0x337e,0x0000,0x0000,0x0000,0x6862,0x0000,0x0000,
+	0x6850,0x0000,0x0000,0x0000,0x6855,0x4d6e,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x685e,0x0000,
+	0x7b5c,0x4d55,0x0000,0x0000,0x0000,0x0000,0x4e2a,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4378,
+	0x0000,0x0000,0x0000,0x336b,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x4972,0x6864,0x4621,0x0000,0x0000,0x3031,0x0000,
+	0x0000,0x685d,0x0000,0x6859,0x4172,0x6853,0x685b,0x6860,
+	0x0000,0x472c,0x0000,0x0000,0x0000,0x302a,0x0000,0x6858,
+	0x0000,0x6861,0x4978,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x685c,0x0000,0x6857,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x3e55,0x0000,0x0000,0x0000,0x0000,
+	0x3d2f,0x0000,0x0000,0x0000,0x3c2c,0x0000,0x0000,0x0000,
+	0x0000,0x4c58,0x0000,0x0000,0x4947,0x0000,0x0000,0x6867,
+	0x0000,0x6870,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x685a,0x0000,0x0000,
+	0x0000,0x0000,0x3377,0x0000,0x7b5d,0x0000,0x0000,0x0000,
+	0x3e78,0x6865,0x0000,0x686a,0x4173,0x0000,0x0000,0x6866,
+	0x0000,0x686d,0x0000,0x0000,0x435f,0x0000,0x686e,0x0000,
+	0x0000,0x4d56,0x6863,0x3338,0x0000,0x6869,0x0000,0x0000,
+	0x686c,0x4c2c,0x0000,0x0000,0x0000,0x0000,0x686f,0x0000,
+	0x0000,0x6868,0x686b,0x0000,0x7925,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x4b29,0x0000,0x4f21,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x6873,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x687a,0x0000,0x0000,0x6872,
+	0};
+unsigned short unicode_rev_table133[] = {
+	0x3c43,0x0000,0x0000,0x0000,0x0000,0x0000,0x6851,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x4a4e,0x0000,0x4c22,0x6879,0x6878,0x0000,0x6874,
+	0x6875,0x0000,0x3136,0x0000,0x0000,0x0000,0x0000,0x6877,
+	0x0000,0x6871,0x0000,0x0000,0x0000,0x0000,0x4455,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x6876,0x307e,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x4222,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x4a43,0x0000,0x0000,
+	0x687b,0x6921,0x0000,0x4859,0x0000,0x0000,0x0000,0x0000,
+	0x687e,0x3e56,0x3c49,0x6923,0x0000,0x0000,0x363e,0x0000,
+	0x0000,0x0000,0x0000,0x7b5e,0x0000,0x6924,0x0000,0x4979,
+	0x687d,0x7b5f,0x6856,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x687c,0x0000,0x0000,0x0000,0x0000,
+	0x4f4f,0x4622,0x4973,0x7b60,0x0000,0x692b,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6931,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6932,0x0000,
+	0x6925,0x0000,0x0000,0x0000,0x4776,0x0000,0x0000,0x692f,
+	0x6927,0x0000,0x6929,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x6933,0x6928,0x0000,0x0000,0x692c,0x0000,0x0000,0x3172,
+	0x0000,0x4665,0x0000,0x692d,0x6930,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x6926,0x0000,0x4126,0x0000,
+	0x692a,0x3b27,0x3f45,0x3730,0x4c74,0x0000,0x4c79,0x3d72,
+	0x7b62,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x6937,0x6935,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x4f4e,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x6934,0x0000,0x0000,0x0000,0x4d75,0x0000,0x6936,
+	0x6938,0x0000,0x0000,0x0000,0x0000,0x6939,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x693c,0x693a,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x4623,0x693b,0x0000,0x0000,
+	0x0000,0x484d,0x692e,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3d73,
+	0x0000,0x693d,0x6942,0x4174,0x0000,0x0000,0x6941,0x0000,
+	0};
+unsigned short unicode_rev_table134[] = {
+	0x0000,0x0000,0x6922,0x0000,0x0000,0x0000,0x6943,0x4149,
+	0x0000,0x0000,0x693e,0x6940,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x693f,0x0000,0x0000,0x5d31,0x5d22,
+	0x0000,0x0000,0x6945,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6944,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x4d76,0x0000,0x623c,
+	0x6946,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6947,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x6948,0x3857,0x0000,
+	0x3554,0x0000,0x0000,0x0000,0x694a,0x515d,0x0000,0x0000,
+	0x0000,0x0000,0x3575,0x0000,0x4e3a,0x0000,0x3673,0x694b,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x694c,
+	0x0000,0x0000,0x0000,0x436e,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x694d,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x467a,0x0000,0x303a,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x3263,0x6952,0x6953,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x694e,0x0000,0x3b3d,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x694f,0x4742,0x0000,0x0000,0x0000,
+	0x0000,0x6950,0x6951,0x695b,0x0000,0x0000,0x0000,0x6955,
+	0x6958,0x0000,0x0000,0x0000,0x0000,0x0000,0x6954,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x6956,0x0000,0x6957,0x3c58,
+	0x0000,0x6959,0x0000,0x4341,0x0000,0x3756,0x3342,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x695c,0x0000,0x0000,0x0000,
+	0x0000,0x333f,0x0000,0x6961,0x0000,0x0000,0x695d,0x6960,
+	0x0000,0x0000,0x0000,0x0000,0x483a,0x0000,0x0000,0x0000,
+	0x0000,0x695e,0x0000,0x0000,0x695f,0x4948,0x485a,0x6962,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x427d,0x696c,0x0000,0x6968,0x0000,0x0000,0x326b,0x0000,
+	0};
+unsigned short unicode_rev_table135[] = {
+	0x6966,0x0000,0x4b2a,0x6967,0x0000,0x0000,0x6964,0x0000,
+	0x6965,0x696a,0x696d,0x0000,0x0000,0x696b,0x0000,0x0000,
+	0x0000,0x6969,0x6963,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x4358,0x0000,0x6974,0x0000,0x4c2a,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x6972,0x0000,0x0000,
+	0x0000,0x6973,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x696e,0x0000,0x0000,0x6970,
+	0x0000,0x0000,0x0000,0x6971,0x0000,0x0000,0x0000,0x696f,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x4066,0x0000,0x4f39,0x6978,0x0000,0x6979,0x0000,
+	0x0000,0x0000,0x0000,0x6a21,0x0000,0x3f2a,0x0000,0x697b,
+	0x0000,0x697e,0x0000,0x0000,0x0000,0x0000,0x0000,0x6976,
+	0x6975,0x0000,0x0000,0x6a22,0x0000,0x0000,0x325c,0x0000,
+	0x697c,0x0000,0x6a23,0x0000,0x0000,0x0000,0x697d,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x697a,0x0000,0x4433,0x0000,
+	0x6977,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4768,
+	0x0000,0x0000,0x6a27,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x4d3b,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6a26,
+	0x0000,0x0000,0x6a25,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x6a2e,0x0000,0x0000,0x0000,0x6a28,
+	0x0000,0x0000,0x0000,0x6a30,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x4d66,0x6a33,0x0000,0x6a2a,0x0000,0x0000,
+	0x6a2b,0x0000,0x0000,0x0000,0x6a2f,0x0000,0x6a32,0x6a31,
+	0x0000,0x0000,0x0000,0x6a29,0x0000,0x0000,0x0000,0x0000,
+	0x6a2c,0x0000,0x6a3d,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x6a36,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6a34,
+	0x0000,0x0000,0x6a35,0x0000,0x0000,0x0000,0x6a3a,0x6a3b,
+	0x0000,0x332a,0x0000,0x3542,0x0000,0x0000,0x6a39,0x0000,
+	0};
+unsigned short unicode_rev_table136[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x6a24,0x0000,0x7b65,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x6a38,0x6a3c,0x6a37,
+	0x0000,0x6a3e,0x0000,0x0000,0x0000,0x6a40,0x6a3f,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x6a42,0x6a41,0x695a,0x0000,0x0000,0x0000,0x6a46,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x6a43,0x0000,0x0000,0x0000,0x0000,0x6a44,0x0000,
+	0x0000,0x6a45,0x0000,0x6a47,0x0000,0x0000,0x0000,0x0000,
+	0x376c,0x0000,0x6a49,0x0000,0x6a48,0x0000,0x3d30,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x3954,0x5e27,0x0000,0x0000,
+	0x0000,0x0000,0x6a4a,0x3d51,0x0000,0x0000,0x0000,0x3339,
+	0x0000,0x6a4b,0x0000,0x3152,0x0000,0x3e57,0x6a4c,0x0000,
+	0x0000,0x3955,0x6a4d,0x3061,0x0000,0x0000,0x0000,0x0000,
+	0x493d,0x0000,0x0000,0x6a4e,0x0000,0x0000,0x0000,0x0000,
+	0x3f6a,0x0000,0x6a55,0x0000,0x0000,0x6a52,0x0000,0x436f,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x6a53,0x6a50,0x365e,
+	0x0000,0x6a4f,0x6a56,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x3736,0x0000,0x0000,0x425e,0x0000,0x6a5c,0x0000,0x0000,
+	0x0000,0x0000,0x6a58,0x0000,0x0000,0x0000,0x4235,0x6a57,
+	0x0000,0x6a5a,0x0000,0x0000,0x0000,0x0000,0x6a51,0x0000,
+	0x0000,0x0000,0x6a5b,0x0000,0x6a5d,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x486f,0x0000,0x0000,0x6a59,0x0000,
+	0x6a5e,0x6a60,0x0000,0x0000,0x3853,0x6a54,0x0000,0x3041,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6a5f,
+	0x0000,0x3a5b,0x4e76,0x6a61,0x6a62,0x4175,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4e22,
+	0x0000,0x0000,0x0000,0x0000,0x6a63,0x4d35,0x0000,0x0000,
+	0x6a64,0x6a65,0x0000,0x0000,0x4a64,0x6a66,0x0000,0x3a40,
+	0x0000,0x4e23,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x6a6b,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6a6c,0x3e58,0x6a6a,0x7b66,0x0000,0x0000,
+	0x4d67,0x6a67,0x0000,0x0000,0x6a69,0x403d,0x3f7e,0x0000,
+	0};
+unsigned short unicode_rev_table137[] = {
+	0x0000,0x0000,0x6a68,0x0000,0x6a6d,0x0000,0x0000,0x4a23,
+	0x0000,0x0000,0x6a6f,0x0000,0x6a6e,0x0000,0x0000,0x0000,
+	0x336c,0x0000,0x4b2b,0x6a70,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x7922,0x6a7c,0x6a72,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x6a73,0x0000,0x0000,
+	0x0000,0x0000,0x6a74,0x6a75,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6a79,0x0000,
+	0x6a7a,0x0000,0x0000,0x6a78,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x6a76,0x0000,0x6a71,0x6a77,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x6a7b,0x7037,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3228,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6a7e,0x365f,
+	0x6a7d,0x0000,0x0000,0x0000,0x6b22,0x0000,0x6b21,0x0000,
+	0x0000,0x0000,0x6b24,0x0000,0x0000,0x6b23,0x0000,0x6b25,
+	0x0000,0x0000,0x3d31,0x0000,0x6b26,0x0000,0x0000,0x6b27,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6b28,0x403e,
+	0x0000,0x4d57,0x0000,0x6b29,0x0000,0x0000,0x4a24,0x4746,
+	0x6b2a,0x0000,0x6b2b,0x382b,0x0000,0x0000,0x0000,0x352c,
+	0x0000,0x0000,0x0000,0x6b2c,0x0000,0x0000,0x3b6b,0x4741,
+	0x6b2d,0x0000,0x3350,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x6b2e,0x0000,0x0000,0x0000,0x0000,0x6b30,0x4d77,
+	0x0000,0x6b2f,0x3f46,0x0000,0x6b31,0x0000,0x0000,0x6b32,
+	0x0000,0x0000,0x6b33,0x3451,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6b34,0x0000,0x0000,0x6b35,0x0000,0x6b36,
+	0x6b37,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x3351,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6b38,0x0000,0x6b39,0x6b3a,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x3272,0x0000,0x0000,0x3f28,0x6b3b,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x6b3c,0x0000,0x0000,0x0000,
+	0x6b3d,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table138[] = {
+	0x3840,0x0000,0x447b,0x6b3e,0x0000,0x0000,0x0000,0x0000,
+	0x3757,0x0000,0x3f56,0x0000,0x6b41,0x0000,0x4624,0x0000,
+	0x6b40,0x0000,0x7b67,0x3731,0x0000,0x0000,0x6b3f,0x4277,
+	0x352d,0x0000,0x0000,0x6b42,0x0000,0x6b43,0x0000,0x3e59,
+	0x0000,0x0000,0x0000,0x376d,0x0000,0x6b44,0x0000,0x0000,
+	0x0000,0x0000,0x4b2c,0x0000,0x0000,0x405f,0x0000,0x0000,
+	0x0000,0x3576,0x0000,0x4c75,0x414a,0x0000,0x6b45,0x7b68,
+	0x0000,0x0000,0x3f47,0x4370,0x3e5a,0x0000,0x0000,0x0000,
+	0x0000,0x6b46,0x0000,0x0000,0x0000,0x0000,0x6b49,0x0000,
+	0x6b4a,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x3a3e,0x4242,0x6b48,0x0000,0x3e5b,0x493e,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x6b47,0x0000,0x0000,0x3b6c,0x0000,
+	0x3153,0x0000,0x6b4e,0x3758,0x0000,0x0000,0x3b6e,0x0000,
+	0x0000,0x3b6d,0x0000,0x4f4d,0x6b4d,0x6b4c,0x4127,0x0000,
+	0x354d,0x4f43,0x333a,0x3e5c,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x7b69,0x0000,0x0000,0x6b4b,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6b50,0x0000,0x6b51,0x6b4f,0x0000,0x3858,
+	0x0000,0x4d40,0x0000,0x0000,0x3b6f,0x4727,0x0000,0x0000,
+	0x0000,0x6b54,0x0000,0x4040,0x0000,0x4342,0x0000,0x0000,
+	0x4d36,0x0000,0x6b57,0x0000,0x0000,0x0000,0x386c,0x0000,
+	0x403f,0x6b53,0x0000,0x6b58,0x386d,0x6b55,0x6b56,0x7b6a,
+	0x6b52,0x0000,0x0000,0x0000,0x4062,0x4649,0x0000,0x0000,
+	0x432f,0x0000,0x325d,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x4870,0x0000,0x0000,0x3543,0x0000,0x7b6b,0x4434,
+	0x0000,0x0000,0x6b5b,0x0000,0x6b59,0x0000,0x0000,0x434c,
+	0x0000,0x0000,0x0000,0x4041,0x3452,0x6b5a,0x0000,0x3f5b,
+	0x0000,0x0000,0x4e4a,0x0000,0x0000,0x0000,0x4f40,0x0000,
+	0x0000,0x0000,0x6b5c,0x6b67,0x4435,0x0000,0x6b66,0x7b6c,
+	0x6b63,0x6b6b,0x6b64,0x0000,0x6b60,0x0000,0x447c,0x6b5f,
+	0x0000,0x0000,0x0000,0x6b5d,0x0000,0x4d21,0x3b70,0x0000,
+	0x0000,0x6b61,0x0000,0x6b5e,0x0000,0x0000,0x7b6e,0x6b65,
+	0x3d74,0x0000,0x3841,0x0000,0x0000,0x0000,0x427a,0x0000,
+	0};
+unsigned short unicode_rev_table139[] = {
+	0x4b45,0x315a,0x3062,0x0000,0x4625,0x0000,0x0000,0x6b69,
+	0x0000,0x0000,0x0000,0x0000,0x6b68,0x0000,0x4666,0x0000,
+	0x6b6d,0x0000,0x0000,0x0000,0x6b62,0x0000,0x6b6c,0x6b6e,
+	0x0000,0x382c,0x6b6a,0x3956,0x0000,0x3c55,0x0000,0x0000,
+	0x6b6f,0x4d58,0x0000,0x0000,0x0000,0x0000,0x6b72,0x0000,
+	0x6b75,0x0000,0x0000,0x6b73,0x4935,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x6b70,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x3660,0x0000,0x0000,0x0000,0x0000,0x6b74,0x0000,
+	0x0000,0x6b76,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x6b7a,0x0000,0x0000,0x6b77,0x0000,0x6b79,0x6b78,
+	0x0000,0x0000,0x0000,0x7b6f,0x0000,0x0000,0x6b7b,0x0000,
+	0x3c31,0x0000,0x6b7d,0x6b7c,0x4968,0x0000,0x0000,0x6c21,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3759,0x0000,
+	0x0000,0x0000,0x0000,0x6b7e,0x6c22,0x0000,0x0000,0x6c23,
+	0x3544,0x6641,0x3e79,0x0000,0x6c24,0x0000,0x0000,0x386e,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x6c25,0x0000,0x7b70,
+	0x6c26,0x0000,0x0000,0x3b3e,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x5a4e,0x0000,0x6c27,0x0000,0x6c28,0x0000,
+	0x3d32,0x0000,0x6c29,0x6c2a,0x0000,0x0000,0x6c2b,0x0000,
+	0x0000,0x6c2c,0x6c2d,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table140[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x432b,
+	0x0000,0x0000,0x6c2e,0x0000,0x0000,0x0000,0x0000,0x6c30,
+	0x0000,0x6c2f,0x0000,0x0000,0x0000,0x0000,0x4626,0x0000,
+	0x6c31,0x0000,0x4b2d,0x0000,0x6c32,0x0000,0x6c33,0x0000,
+	0x6c34,0x0000,0x0000,0x0000,0x0000,0x6c35,0x0000,0x0000,
+	0x0000,0x0000,0x465a,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x3e5d,0x6c36,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x396b,0x502e,0x6c37,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x6c38,0x493f,0x6c39,0x0000,0x6c41,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6c3a,0x0000,0x0000,0x6c3c,0x0000,0x0000,
+	0x0000,0x6c3b,0x6c3d,0x0000,0x4b46,0x6c3e,0x6c3f,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x6c40,0x0000,0x0000,0x0000,
+	0x6c42,0x0000,0x0000,0x0000,0x0000,0x332d,0x4467,0x0000,
+	0x4969,0x3a62,0x3957,0x0000,0x0000,0x0000,0x0000,0x494f,
+	0x325f,0x484e,0x6c45,0x3453,0x4055,0x6c44,0x6c49,0x4379,
+	0x4c63,0x0000,0x6c47,0x6c48,0x352e,0x0000,0x6c4a,0x4763,
+	0x425f,0x0000,0x0000,0x4871,0x453d,0x6c46,0x0000,0x4b47,
+	0x326c,0x6c4c,0x4f28,0x4442,0x4f45,0x0000,0x0000,0x3b71,
+	0x6c4b,0x0000,0x4231,0x0000,0x0000,0x6c5c,0x4128,0x0000,
+	0x0000,0x4678,0x0000,0x4950,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6c4f,0x3b3f,0x3b72,0x0000,0x3e5e,0x0000,
+	0x4765,0x0000,0x382d,0x6c4e,0x6c4d,0x0000,0x496a,0x0000,
+	0x0000,0x0000,0x3c41,0x0000,0x0000,0x4552,0x0000,0x0000,
+	0x7b71,0x0000,0x0000,0x0000,0x7b72,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6c51,0x6c52,0x3958,0x6c50,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table141[] = {
+	0x0000,0x0000,0x0000,0x0000,0x6c53,0x6c54,0x0000,0x6c56,
+	0x4223,0x0000,0x6c55,0x3466,0x0000,0x6c58,0x0000,0x6c57,
+	0x6c59,0x0000,0x7b73,0x6c5b,0x6c5d,0x0000,0x6c5e,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x4056,0x0000,0x3c4f,0x6c5f,
+	0x0000,0x0000,0x0000,0x3352,0x0000,0x6c60,0x0000,0x0000,
+	0x4176,0x6c61,0x0000,0x6c62,0x496b,0x0000,0x7b74,0x352f,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x6c63,0x0000,0x0000,0x0000,0x4436,0x0000,0x0000,
+	0x0000,0x0000,0x315b,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x6c64,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x3c71,0x0000,0x0000,0x0000,0x0000,
+	0x3f76,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x422d,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6c67,0x0000,0x0000,0x0000,0x6c66,0x0000,
+	0x0000,0x0000,0x6c65,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x6c6d,0x6c6b,0x0000,0x0000,0x6c68,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6c6a,0x0000,
+	0x0000,0x0000,0x6c69,0x6c6c,0x0000,0x3577,0x0000,0x6c70,
+	0x0000,0x4057,0x0000,0x6c71,0x0000,0x0000,0x0000,0x0000,
+	0x3859,0x0000,0x6c6e,0x6c6f,0x0000,0x0000,0x0000,0x4f29,
+	0x0000,0x0000,0x0000,0x4437,0x0000,0x4129,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x6c72,0x0000,0x0000,0x6c75,
+	0};
+unsigned short unicode_rev_table142[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x6c73,0x6c74,0x4d59,0x0000,0x0000,0x0000,0x0000,0x4627,
+	0x6c78,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x6c76,0x6c77,0x6c79,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6d29,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x6c7c,0x0000,0x0000,0x0000,0x6c7d,0x6c7b,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6c7a,0x0000,0x447d,0x0000,0x0000,0x6d21,
+	0x6d25,0x6d22,0x6c7e,0x0000,0x6d23,0x0000,0x0000,0x0000,
+	0x6d24,0x0000,0x0000,0x0000,0x0000,0x6d2b,0x0000,0x0000,
+	0x0000,0x6d26,0x0000,0x0000,0x0000,0x0000,0x0000,0x4058,
+	0x6d28,0x0000,0x0000,0x6d2a,0x6d27,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6d2d,0x0000,0x3d33,0x0000,0x6d2c,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x6d2e,0x0000,0x0000,0x0000,
+	0x0000,0x6d2f,0x0000,0x0000,0x6d32,0x6d31,0x0000,0x6d30,
+	0x0000,0x0000,0x6d34,0x6d33,0x0000,0x4c76,0x0000,0x0000,
+	0x0000,0x6d36,0x0000,0x6d35,0x6d37,0x0000,0x0000,0x0000,
+	0x0000,0x6d38,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x6d3a,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6d39,0x3f48,0x6d3b,0x0000,0x0000,0x366d,
+	0x6d3c,0x6d3e,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6d3f,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x6d40,0x6d3d,0x0000,
+	0x6d41,0x0000,0x3c56,0x6d42,0x3530,0x3733,0x0000,0x7b76,
+	0x0000,0x0000,0x382e,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x6d43,0x0000,0x0000,0x0000,0x4670,
+	0x0000,0x0000,0x453e,0x6d44,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x6d47,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x3c34,0x0000,0x0000,0x6d46,0x6d45,0x375a,0x6d48,0x0000,
+	0};
+unsigned short unicode_rev_table143[] = {
+	0x0000,0x0000,0x0000,0x3353,0x0000,0x6d4a,0x0000,0x0000,
+	0x0000,0x3a5c,0x6d49,0x0000,0x6d52,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6d4c,0x6d4e,0x4a65,0x6d4b,0x0000,0x0000,
+	0x0000,0x6d4d,0x0000,0x6d51,0x6d4f,0x3531,0x0000,0x6d50,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6d53,0x0000,
+	0x0000,0x475a,0x4e58,0x0000,0x0000,0x0000,0x0000,0x3d34,
+	0x0000,0x0000,0x0000,0x6d54,0x0000,0x0000,0x0000,0x0000,
+	0x4d22,0x6d56,0x0000,0x6d55,0x0000,0x0000,0x6d59,0x4d41,
+	0x0000,0x0000,0x6d58,0x0000,0x336d,0x6d57,0x6d5c,0x0000,
+	0x0000,0x6d5b,0x0000,0x0000,0x6d5a,0x4532,0x6d5d,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6d5e,
+	0x0000,0x0000,0x0000,0x0000,0x6d5f,0x0000,0x0000,0x396c,
+	0x0000,0x3725,0x6d60,0x6d61,0x6d62,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x3f49,0x6d63,0x0000,0x3c2d,0x6d64,
+	0x0000,0x0000,0x0000,0x6d65,0x0000,0x0000,0x0000,0x5221,
+	0x517e,0x0000,0x0000,0x0000,0x0000,0x6d66,0x6570,0x6d67,
+	0x4324,0x3f2b,0x4740,0x0000,0x0000,0x0000,0x0000,0x6d68,
+	0x0000,0x0000,0x4a55,0x4454,0x397e,0x0000,0x0000,0x4329,
+	0x0000,0x0000,0x312a,0x0000,0x4b78,0x3f57,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x375e,0x0000,
+	0x0000,0x3661,0x0000,0x0000,0x4a56,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6d69,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6d6b,0x0000,0x0000,0x6d6a,0x3260,0x0000,
+	0x0000,0x4676,0x6d6c,0x4777,0x0000,0x4533,0x0000,0x6d6d,
+	0x3d52,0x0000,0x0000,0x0000,0x6d6f,0x0000,0x0000,0x4c42,
+	0x6d7e,0x6d71,0x6d72,0x0000,0x0000,0x4449,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table144[] = {
+	0x4260,0x4177,0x0000,0x4628,0x0000,0x6d70,0x3555,0x0000,
+	0x0000,0x0000,0x0000,0x6d79,0x0000,0x6d76,0x6e25,0x4629,
+	0x4360,0x6d73,0x0000,0x447e,0x4553,0x6d74,0x6d78,0x3f60,
+	0x0000,0x4767,0x444c,0x0000,0x0000,0x4042,0x6d77,0x422e,
+	0x4224,0x6d75,0x3029,0x4f22,0x0000,0x0000,0x0000,0x6d7a,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4261,0x0000,
+	0x0000,0x3d35,0x3f4a,0x0000,0x0000,0x6d7c,0x6d7b,0x0000,
+	0x306f,0x6d7d,0x0000,0x0000,0x492f,0x0000,0x6e27,0x0000,
+	0x0000,0x465b,0x3f6b,0x0000,0x0000,0x4359,0x0000,0x3678,
+	0x0000,0x6e26,0x4d37,0x313f,0x0000,0x4a57,0x3261,0x6e21,
+	0x6e22,0x6e23,0x6e24,0x463b,0x4323,0x3063,0x6e28,0x0000,
+	0x6e29,0x7423,0x0000,0x0000,0x423d,0x0000,0x6e2a,0x0000,
+	0x3173,0x414c,0x0000,0x382f,0x0000,0x4d5a,0x0000,0x7b79,
+	0x6e2b,0x452c,0x0000,0x0000,0x0000,0x4178,0x3c57,0x6e2c,
+	0x0000,0x0000,0x6e2f,0x0000,0x0000,0x3d65,0x6e2d,0x412b,
+	0x412a,0x0000,0x3064,0x0000,0x4e4b,0x6e31,0x0000,0x4872,
+	0x6e33,0x6e32,0x6e30,0x6364,0x3454,0x0000,0x0000,0x6d6e,
+	0x0000,0x6e35,0x6e34,0x0000,0x0000,0x0000,0x0000,0x6e36,
+	0x0000,0x4d38,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x4661,0x0000,0x0000,0x4b2e,0x0000,
+	0x6e37,0x0000,0x3c59,0x0000,0x0000,0x0000,0x0000,0x6e38,
+	0x0000,0x6e39,0x0000,0x0000,0x0000,0x6e3a,0x0000,0x0000,
+	0x4521,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x306a,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x3959,0x0000,0x0000,0x0000,0x4f3a,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x6e3e,0x0000,0x0000,0x7b7a,0x0000,
+	0x0000,0x3734,0x6e3b,0x0000,0x6e3c,0x0000,0x0000,0x0000,
+	0x4974,0x0000,0x0000,0x0000,0x0000,0x3354,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x4d39,0x0000,0x363f,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x4554,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table145[] = {
+	0x0000,0x0000,0x6e3f,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6e40,0x0000,0x0000,0x7b7c,0x0000,0x0000,
+	0x0000,0x6e41,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x7b7d,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x4522,0x0000,0x0000,
+	0x6e43,0x0000,0x6e42,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x4653,0x6e44,0x3d36,0x3c60,0x475b,0x4371,0x0000,
+	0x0000,0x0000,0x3c72,0x0000,0x3f6c,0x0000,0x6e45,0x0000,
+	0x6e46,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x3f5d,0x6e47,0x0000,0x6e48,0x0000,0x0000,
+	0x0000,0x6e49,0x4d6f,0x0000,0x3d37,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6e4b,0x6e4a,0x0000,0x395a,0x0000,0x3973,
+	0x3b40,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6e4e,0x0000,0x0000,0x0000,0x0000,0x3d66,
+	0x0000,0x6e4d,0x0000,0x6e4c,0x0000,0x4269,0x0000,0x0000,
+	0x386f,0x0000,0x4043,0x0000,0x0000,0x0000,0x0000,0x4830,
+	0x0000,0x0000,0x0000,0x0000,0x3d39,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6e4f,0x0000,0x3e5f,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6e52,0x6e50,0x0000,0x0000,0x0000,0x6e51,
+	0x0000,0x0000,0x0000,0x0000,0x6e54,0x6e53,0x0000,0x0000,
+	0x3e7a,0x0000,0x6e55,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x6e56,0x6e57,0x0000,0x0000,0x0000,0x0000,0x4850,0x3a53,
+	0x3c61,0x6e58,0x0000,0x6e59,0x4e24,0x3d45,0x4c6e,0x4e4c,
+	0x6e5a,0x3662,0x0000,0x0000,0x0000,0x0000,0x6e5b,0x7c21,
+	0x4523,0x0000,0x7b7e,0x6e5e,0x3378,0x3f4b,0x7c22,0x6e5c,
+	0x0000,0x6e5d,0x0000,0x4460,0x7c25,0x7c26,0x4b55,0x367c,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x7c23,0x7c24,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x6e60,0x6e61,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x6e5f,0x0000,0x0000,0x6e63,
+	0};
+unsigned short unicode_rev_table146[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x7c27,0x0000,
+	0x0000,0x0000,0x7c29,0x0000,0x0000,0x465f,0x3343,0x0000,
+	0x7c28,0x6e67,0x0000,0x0000,0x6e64,0x6e66,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6e62,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x6f4f,0x0000,0x0000,0x6e65,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x4e6b,0x0000,0x0000,0x385a,
+	0x0000,0x7c30,0x7c2a,0x0000,0x7c2c,0x0000,0x0000,0x6e6f,
+	0x7c2b,0x0000,0x0000,0x0000,0x4534,0x6e6a,0x0000,0x0000,
+	0x6e6d,0x6e6b,0x0000,0x6e70,0x0000,0x0000,0x7c2d,0x0000,
+	0x6e71,0x7c2f,0x0000,0x0000,0x0000,0x0000,0x0000,0x6e69,
+	0x0000,0x7c2e,0x6e76,0x3174,0x0000,0x0000,0x6e68,0x0000,
+	0x0000,0x0000,0x482d,0x0000,0x6e6c,0x0000,0x3e60,0x7c31,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x395b,0x0000,0x0000,0x0000,0x0000,0x0000,0x7c33,
+	0x7c34,0x0000,0x0000,0x0000,0x0000,0x0000,0x4b48,0x0000,
+	0x3664,0x0000,0x0000,0x3d46,0x0000,0x463c,0x0000,0x0000,
+	0x7924,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x412d,0x0000,0x6e74,0x0000,0x6e6e,0x6e73,0x0000,
+	0x4c43,0x0000,0x4438,0x6e75,0x6e72,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x7c32,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x412c,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6e79,
+	0x0000,0x6e78,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6e77,
+	0x7c38,0x0000,0x4b2f,0x7c3c,0x0000,0x7c3a,0x0000,0x7c36,
+	0x0000,0x7c37,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x7c3b,0x0000,0x0000,0x0000,0x3d7b,0x0000,0x0000,0x7c35,
+	0x0000,0x6e7a,0x4a5f,0x0000,0x0000,0x3154,0x0000,0x0000,
+	0x0000,0x0000,0x4946,0x4372,0x0000,0x0000,0x0000,0x0000,
+	0x3578,0x792a,0x6e7c,0x7c3f,0x395d,0x0000,0x0000,0x7c42,
+	0};
+unsigned short unicode_rev_table147[] = {
+	0x0000,0x0000,0x7c44,0x0000,0x0000,0x0000,0x3b2c,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x6e7b,
+	0x3f6d,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x3f6e,0x6f21,0x6f23,0x0000,0x0000,0x7c43,0x7c41,0x0000,
+	0x3e7b,0x7c3e,0x6f22,0x6f24,0x0000,0x7c3d,0x3653,0x0000,
+	0x4945,0x0000,0x0000,0x3c62,0x4f23,0x0000,0x6e7e,0x3a78,
+	0x0000,0x0000,0x4f3f,0x0000,0x0000,0x6f26,0x0000,0x0000,
+	0x0000,0x0000,0x6f25,0x6f27,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x6e7d,0x0000,0x0000,0x0000,
+	0x7923,0x0000,0x0000,0x4669,0x0000,0x4555,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x4457,0x0000,0x6f2c,0x7c46,
+	0x0000,0x0000,0x0000,0x4343,0x6f28,0x0000,0x0000,0x0000,
+	0x6f29,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x372d,0x0000,0x6f2b,0x0000,
+	0x7c45,0x0000,0x0000,0x0000,0x0000,0x3830,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x6f2a,0x0000,0x3e61,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x3379,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x6f30,0x0000,0x3a3f,0x4179,
+	0x0000,0x0000,0x444a,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x7c47,0x0000,0x0000,0x333b,
+	0x0000,0x0000,0x0000,0x0000,0x6f2e,0x6f2f,0x4443,0x0000,
+	0x6f2d,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x6f31,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x6f37,0x0000,0x0000,0x7c48,0x0000,
+	0x6f3a,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x6f39,0x452d,0x0000,0x0000,0x0000,0x0000,0x6f32,0x6f33,
+	0x6f36,0x0000,0x0000,0x0000,0x0000,0x6f38,0x7c49,0x0000,
+	0x0000,0x3640,0x0000,0x0000,0x6f3b,0x6f35,0x0000,0x0000,
+	0x6f34,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x7c4a,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table148[] = {
+	0x0000,0x0000,0x0000,0x6f3f,0x0000,0x0000,0x0000,0x6f40,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x6f41,0x0000,0x0000,0x6f3e,0x6f3d,0x0000,0x0000,0x0000,
+	0x3e62,0x462a,0x6f3c,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x6f45,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x6f43,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x7c4b,0x0000,0x0000,0x0000,0x6f44,0x6f42,0x0000,
+	0x4278,0x0000,0x6f46,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x6f47,0x0000,0x0000,0x6f49,0x7c4c,0x0000,0x0000,
+	0x7c4d,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x3455,0x6f48,0x4c7a,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6f54,0x6f4a,0x0000,0x0000,0x6f4d,0x0000,
+	0x6f4b,0x0000,0x6f4c,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x6f4e,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x6f50,0x0000,0x0000,0x0000,0x0000,0x6f51,0x0000,0x6f52,
+	0x0000,0x0000,0x0000,0x0000,0x6f55,0x6f53,0x6f56,0x6f58,
+	0x0000,0x6f57,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table149[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4439,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x4c67,0x0000,0x6f59,0x412e,0x0000,0x0000,0x0000,0x6f5a,
+	0x0000,0x4a44,0x6f5b,0x332b,0x0000,0x0000,0x0000,0x313c,
+	0x0000,0x3457,0x7c4e,0x3456,0x6f5c,0x0000,0x6f5d,0x0000,
+	0x6f5e,0x6f5f,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x6f60,0x0000,0x3458,0x3355,0x395e,0x4836,0x0000,0x6f62,
+	0x6f61,0x0000,0x0000,0x0000,0x0000,0x6f63,0x0000,0x0000,
+	0x0000,0x0000,0x315c,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x6f66,0x0000,0x6f65,0x6f64,0x0000,0x6f67,0x0000,
+	0x0000,0x0000,0x0000,0x6f6a,0x0000,0x0000,0x0000,0x3047,
+	0x0000,0x0000,0x6f68,0x0000,0x6f6c,0x6f6b,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x6f6e,0x6f6d,0x6f6f,0x0000,
+	0x462e,0x0000,0x0000,0x0000,0x6f70,0x0000,0x0000,0x0000,
+	0x0000,0x6f71,0x6f73,0x0000,0x0000,0x6f72,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table150[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x496c,0x0000,0x0000,0x0000,
+	0x0000,0x6f74,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x6f75,0x0000,0x3a65,0x0000,0x0000,0x0000,0x6f76,0x6f77,
+	0x0000,0x0000,0x4b49,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x414b,0x0000,0x0000,0x0000,0x3024,
+	0x424b,0x0000,0x6f78,0x0000,0x496d,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x6f7b,0x6f79,0x395f,0x0000,0x6f7a,
+	0x3842,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x4a45,0x6f7d,0x7021,0x6f7e,0x7022,
+	0x0000,0x0000,0x3121,0x3f58,0x3d7c,0x3459,0x7023,0x0000,
+	0x0000,0x0000,0x4766,0x0000,0x7025,0x0000,0x0000,0x0000,
+	0x3122,0x0000,0x7024,0x4444,0x0000,0x4e4d,0x462b,0x6f7c,
+	0x4e26,0x0000,0x3831,0x0000,0x0000,0x4d5b,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x3679,0x4e34,0x0000,
+	0x3728,0x0000,0x4262,0x6721,0x0000,0x7026,0x332c,0x3f6f,
+	0x0000,0x0000,0x0000,0x0000,0x3356,0x7028,0x0000,0x7029,
+	0x7027,0x3764,0x0000,0x3a5d,0x3e63,0x7c51,0x0000,0x0000,
+	0x3123,0x0000,0x0000,0x4e59,0x0000,0x0000,0x0000,0x702b,
+	0x6e2e,0x0000,0x702a,0x0000,0x0000,0x0000,0x0000,0x7c52,
+	0x702e,0x702c,0x702d,0x0000,0x702f,0x0000,0x7030,0x4e6c,
+	0x7031,0x7032,0x0000,0x4049,0x483b,0x0000,0x0000,0x0000,
+	0x3f7d,0x3467,0x0000,0x0000,0x4d3a,0x326d,0x3d38,0x385b,
+	0x0000,0x7035,0x0000,0x7034,0x3b73,0x7036,0x7033,0x0000,
+	0x0000,0x3b28,0x0000,0x0000,0x0000,0x703a,0x6a2d,0x0000,
+	0x0000,0x5256,0x0000,0x3f77,0x7038,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x4e25,0x4671,0x0000,0x0000,0x0000,0x0000,
+	0x312b,0x0000,0x4063,0x3c36,0x0000,0x0000,0x0000,0x0000,
+	0x4a37,0x0000,0x3140,0x0000,0x0000,0x0000,0x4e6d,0x4d6b,
+	0x0000,0x703b,0x0000,0x4545,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table151[] = {
+	0x3c7b,0x0000,0x0000,0x0000,0x703c,0x0000,0x703d,0x3f4c,
+	0x703e,0x0000,0x4e6e,0x0000,0x0000,0x7039,0x7040,0x7042,
+	0x0000,0x7041,0x0000,0x703f,0x0000,0x0000,0x7043,0x0000,
+	0x0000,0x7044,0x0000,0x0000,0x417a,0x0000,0x3262,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x7045,0x0000,0x0000,0x4c38,
+	0x0000,0x0000,0x7046,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x7047,0x0000,0x4f2a,0x7c53,0x0000,0x0000,0x0000,0x0000,
+	0x5b31,0x7048,0x0000,0x7c54,0x0000,0x7049,0x704a,0x0000,
+	0x0000,0x0000,0x704e,0x7c55,0x704b,0x0000,0x704c,0x0000,
+	0x704d,0x704f,0x0000,0x0000,0x0000,0x7c56,0x0000,0x7c57,
+	0x0000,0x7c58,0x4044,0x0000,0x0000,0x7c59,0x4c77,0x0000,
+	0x0000,0x4045,0x0000,0x0000,0x7050,0x0000,0x4873,0x0000,
+	0x7051,0x7353,0x4c4c,0x0000,0x7052,0x0000,0x7053,0x0000,
+	0x7054,0x3357,0x0000,0x7056,0x0000,0x3f59,0x0000,0x0000,
+	0x0000,0x7057,0x0000,0x0000,0x3724,0x0000,0x0000,0x0000,
+	0x0000,0x7058,0x705c,0x0000,0x705a,0x0000,0x0000,0x0000,
+	0x0000,0x705b,0x0000,0x0000,0x3373,0x7059,0x705d,0x0000,
+	0x0000,0x0000,0x0000,0x705e,0x0000,0x3048,0x0000,0x705f,
+	0x7060,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x3e64,0x0000,0x0000,0x0000,0x7061,0x0000,0x0000,0x0000,
+	0x3547,0x0000,0x0000,0x7064,0x0000,0x0000,0x7063,0x0000,
+	0x7062,0x0000,0x0000,0x6b71,0x0000,0x4a5c,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x7065,0x7066,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x7067,0x0000,0x0000,0x7068,0x0000,
+	0x7069,0x0000,0x0000,0x706a,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x345a,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x706b,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x706c,0x4723,0x0000,
+	0x0000,0x0000,0x706e,0x323b,0x0000,0x7071,0x7070,0x0000,
+	0x0000,0x0000,0x0000,0x3124,0x0000,0x0000,0x0000,0x3641,
+	0};
+unsigned short unicode_rev_table152[] = {
+	0x0000,0x4a47,0x443a,0x3a22,0x0000,0x3960,0x3d67,0x0000,
+	0x3f5c,0x0000,0x0000,0x0000,0x7073,0x0000,0x0000,0x7072,
+	0x4d42,0x3468,0x4852,0x465c,0x0000,0x0000,0x0000,0x3f7c,
+	0x4e4e,0x0000,0x375b,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x7076,0x0000,0x0000,0x7075,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x4b4b,0x462c,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x3150,0x0000,0x0000,0x7077,
+	0x7074,0x0000,0x0000,0x4951,0x4d6a,0x7078,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x7079,0x0000,
+	0x0000,0x0000,0x0000,0x707b,0x426a,0x335b,0x335c,0x707a,
+	0x0000,0x0000,0x0000,0x0000,0x3469,0x3832,0x0000,0x7c5a,
+	0x346a,0x0000,0x0000,0x453f,0x0000,0x0000,0x4e60,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x7c5b,0x0000,0x385c,
+	0x0000,0x0000,0x0000,0x707c,0x0000,0x0000,0x0000,0x707d,
+	0x707e,0x7121,0x0000,0x7123,0x7122,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x4977,0x0000,0x7124,0x0000,0x0000,0x0000,0x0000,0x7125,
+	0x0000,0x7126,0x0000,0x0000,0x0000,0x0000,0x7127,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x7129,0x7128,0x0000,0x712a,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x4874,0x664c,0x0000,0x0000,0x3f29,
+	0x0000,0x0000,0x3532,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x712b,0x0000,0x712c,0x0000,0x522c,0x5d3b,0x4853,
+	0x0000,0x0000,0x307b,0x0000,0x303b,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x3b74,0x4b30,0x3e7e,0x0000,
+	0};
+unsigned short unicode_rev_table153[] = {
+	0x0000,0x0000,0x0000,0x712d,0x0000,0x4c5f,0x0000,0x0000,
+	0x0000,0x712e,0x4d5c,0x0000,0x3142,0x0000,0x0000,0x0000,
+	0x3b41,0x0000,0x712f,0x326e,0x7130,0x0000,0x0000,0x0000,
+	0x7131,0x0000,0x0000,0x0000,0x0000,0x7133,0x7134,0x0000,
+	0x7136,0x7132,0x0000,0x0000,0x7135,0x0000,0x0000,0x7c5e,
+	0x345b,0x0000,0x0000,0x0000,0x7137,0x0000,0x7138,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x7139,0x713a,0x0000,
+	0x0000,0x0000,0x713b,0x0000,0x0000,0x713d,0x0000,0x0000,
+	0x0000,0x713c,0x0000,0x713f,0x7142,0x0000,0x0000,0x0000,
+	0x713e,0x7140,0x7141,0x0000,0x0000,0x7143,0x0000,0x3642,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3c73,0x7144,
+	0x7145,0x3961,0x0000,0x0000,0x0000,0x0000,0x7c60,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x7146,0x0000,0x0000,
+	0x333e,0x0000,0x0000,0x0000,0x474f,0x7147,0x7148,0x0000,
+	0x0000,0x0000,0x0000,0x435a,0x466b,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x7149,0x0000,0x0000,0x0000,
+	0x0000,0x477d,0x0000,0x0000,0x424c,0x3158,0x366e,0x0000,
+	0x366f,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x4373,0x714e,0x3670,0x0000,0x0000,0x326f,0x0000,0x0000,
+	0x714d,0x0000,0x0000,0x714b,0x0000,0x714c,0x0000,0x714a,
+	0x0000,0x0000,0x7158,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x714f,0x7150,0x0000,
+	0x0000,0x7151,0x7152,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x7154,0x0000,0x0000,0x7153,0x0000,0x0000,0x0000,0x3d59,
+	0};
+unsigned short unicode_rev_table154[] = {
+	0x0000,0x7155,0x0000,0x0000,0x0000,0x7157,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3533,0x7156,
+	0x0000,0x0000,0x417b,0x3833,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x7159,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x424d,0x0000,0x0000,0x715a,0x0000,0x0000,0x0000,0x0000,
+	0x462d,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x715b,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x7160,0x0000,
+	0x715e,0x0000,0x715d,0x715f,0x0000,0x715c,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x7162,0x7c61,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x7161,0x0000,0x7164,
+	0x0000,0x0000,0x3643,0x7163,0x0000,0x0000,0x0000,0x7165,
+	0x0000,0x0000,0x7166,0x0000,0x7168,0x7167,0x0000,0x0000,
+	0x0000,0x7169,0x716b,0x716a,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x397c,0x0000,0x0000,0x0000,0x0000,0x716c,0x0000,0x0000,
+	0x716d,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x333c,0x0000,0x0000,0x0000,0x716e,0x0000,0x0000,0x0000,
+	0x716f,0x0000,0x0000,0x0000,0x3f71,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x7170,
+	0x0000,0x7171,0x0000,0x7172,0x7173,0x0000,0x0000,0x0000,
+	0x3962,0x7c62,0x0000,0x0000,0x7c63,0x0000,0x7174,0x7175,
+	0x0000,0x0000,0x7176,0x7177,0x0000,0x0000,0x7178,0x0000,
+	0x0000,0x0000,0x4831,0x717a,0x0000,0x4926,0x717b,0x7179,
+	0x0000,0x717d,0x0000,0x0000,0x717c,0x0000,0x0000,0x717e,
+	0x0000,0x0000,0x0000,0x7221,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table155[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x7222,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x7223,0x0000,0x7224,0x0000,0x0000,0x0000,0x0000,0x7225,
+	0x0000,0x0000,0x7226,0x7227,0x0000,0x7228,0x0000,0x7229,
+	0x722a,0x722b,0x722c,0x0000,0x0000,0x0000,0x722d,0x722e,
+	0x0000,0x5d35,0x722f,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x6478,0x3534,0x0000,0x0000,0x0000,
+	0x0000,0x3321,0x3a32,0x7231,0x7230,0x4c25,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x7233,0x7234,0x7232,
+	0x0000,0x7235,0x0000,0x0000,0x4b62,0x0000,0x0000,0x0000,
+	0x7236,0x0000,0x357b,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4f25,
+	0x0000,0x0000,0x7c65,0x0000,0x7237,0x7c64,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x7239,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x303e,0x7c66,
+	0x0000,0x723a,0x4a2b,0x7238,0x0000,0x0000,0x723b,0x723c,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x723d,
+	0x723e,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x723f,0x0000,0x4b6e,0x3b2d,0x0000,0x3a7a,0x412f,0x0000,
+	0x0000,0x7c67,0x0000,0x0000,0x7240,0x0000,0x0000,0x0000,
+	0x0000,0x7243,0x0000,0x7c68,0x0000,0x0000,0x0000,0x0000,
+	0x7241,0x0000,0x0000,0x0000,0x0000,0x0000,0x7244,0x0000,
+	0x0000,0x3871,0x7242,0x0000,0x0000,0x0000,0x0000,0x7245,
+	0x0000,0x7246,0x7247,0x0000,0x724b,0x0000,0x3b2a,0x0000,
+	0x0000,0x0000,0x0000,0x4264,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x724c,0x7249,0x7248,0x724a,0x0000,0x0000,0x0000,
+	0x375f,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x7250,0x724f,0x724e,0x0000,0x0000,0x3033,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table156[] = {
+	0x7c69,0x0000,0x0000,0x0000,0x725a,0x0000,0x7256,0x0000,
+	0x7257,0x7253,0x7259,0x0000,0x7255,0x3362,0x0000,0x0000,
+	0x4f4c,0x0000,0x7258,0x7254,0x7252,0x7251,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x725c,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x725f,0x0000,0x0000,0x725e,0x725d,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x4949,0x725b,0x3073,
+	0x7260,0x0000,0x7262,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x336f,0x724d,0x3137,0x0000,0x0000,0x7264,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x7263,0x7261,
+	0x432d,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x4b70,0x0000,0x0000,0x0000,0x0000,0x4e5a,
+	0x0000,0x0000,0x7265,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x7266,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x7267,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x7268,0x0000,
+	0x7269,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x443b,0x0000,0x726a,
+	0x0000,0x4837,0x0000,0x726f,0x726b,0x0000,0x0000,0x0000,
+	0x726c,0x0000,0x0000,0x4b31,0x4c44,0x0000,0x4650,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table157[] = {
+	0x0000,0x0000,0x0000,0x7270,0x0000,0x0000,0x7271,0x463e,
+	0x726e,0x726d,0x0000,0x0000,0x0000,0x0000,0x322a,0x0000,
+	0x0000,0x0000,0x7279,0x0000,0x0000,0x7278,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x3175,0x0000,0x0000,0x0000,0x7276,
+	0x0000,0x0000,0x0000,0x7275,0x0000,0x0000,0x7273,0x0000,
+	0x337b,0x0000,0x7272,0x3c32,0x3229,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x3963,0x0000,0x0000,0x727c,0x727b,
+	0x0000,0x727a,0x0000,0x0000,0x7277,0x0000,0x727d,0x0000,
+	0x727e,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x7325,0x7324,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x7326,0x0000,0x0000,0x312d,0x7321,0x7322,0x0000,
+	0x3974,0x4c39,0x0000,0x0000,0x7323,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x7c6b,0x4b32,0x0000,0x0000,0x732b,
+	0x7c6a,0x0000,0x7327,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x732c,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x7329,
+	0x0000,0x7328,0x0000,0x0000,0x0000,0x0000,0x0000,0x375c,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x732d,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x732e,0x0000,0x0000,0x0000,
+	0x0000,0x732f,0x0000,0x732a,0x0000,0x0000,0x0000,0x7274,
+	0x0000,0x0000,0x7330,0x0000,0x4461,0x0000,0x0000,0x0000,
+	0x7334,0x0000,0x7335,0x7333,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x7332,0x7338,0x0000,0x7331,0x0000,0x7336,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x7337,
+	0x0000,0x0000,0x0000,0x733a,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x7339,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x733c,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x733d,0x0000,0x733e,
+	0x0000,0x0000,0x4f49,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x733b,0x426b,0x3a6d,0x0000,0x0000,0x733f,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table158[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x7c6d,0x7340,0x7341,0x0000,0x0000,0x7342,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x7343,0x0000,0x0000,
+	0x3834,0x7344,0x0000,0x0000,0x0000,0x7345,0x0000,0x3c2f,
+	0x0000,0x7346,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x7347,0x0000,0x0000,0x7348,0x7349,0x0000,0x0000,0x0000,
+	0x0000,0x734c,0x734a,0x4f3c,0x0000,0x734b,0x0000,0x4e6f,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x734d,0x0000,0x4e5b,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x734e,0x477e,0x0000,
+	0x0000,0x734f,0x7351,0x0000,0x0000,0x7352,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x7350,0x396d,0x4c4d,0x4b63,0x5677,0x0000,0x5d60,0x4b7b,
+	0x0000,0x0000,0x0000,0x0000,0x322b,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x7354,0x3550,0x7355,0x7356,
+	0x7357,0x7c6e,0x3975,0x0000,0x7358,0x0000,0x0000,0x0000,
+	0x6054,0x4c5b,0x0000,0x4263,0x7359,0x735b,0x735a,0x0000,
+	0x735c,0x0000,0x0000,0x0000,0x0000,0x735d,0x0000,0x0000,
+	0x735e,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x735f,
+	0x0000,0x0000,0x0000,0x0000,0x7360,0x0000,0x7361,0x7362,
+	0x0000,0x7363,0x0000,0x7364,0x7365,0x7366,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table159[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x7367,
+	0x7368,0x0000,0x0000,0x0000,0x0000,0x0000,0x4524,0x0000,
+	0x0000,0x0000,0x0000,0x385d,0x0000,0x736a,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x414d,0x736b,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x736c,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x4921,0x0000,0x0000,0x736d,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x736e,0x6337,0x0000,0x0000,0x6c5a,0x706d,
+	0x0000,0x0000,0x736f,0x0000,0x7370,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x7372,
+	0x7373,0x7374,0x4e70,0x7371,0x0000,0x0000,0x7375,0x7376,
+	0x0000,0x0000,0x7378,0x0000,0x7377,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x737a,0x0000,0x0000,0x0000,0x737b,0x7379,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x4e36,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x737c,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x737d,0x6354,0x0000,0x0000,
+	0x737e,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table249[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x7a46,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x7c4f,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table250[] = {
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x7954,0x795f,
+	0x7960,0x7975,0x7a3e,0x7a4e,0x7a50,0x7a7b,0x7b23,0x7b3a,
+	0x7b42,0x7b43,0x7b44,0x7b46,0x7b4a,0x7b4d,0x7b56,0x7b61,
+	0x7b63,0x7b64,0x7b6d,0x7b75,0x7b77,0x7b78,0x7b7b,0x7c39,
+	0x7c40,0x7c50,0x7c5c,0x7c5d,0x7c5f,0x7c6c,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short unicode_rev_table255[] = {
+	0x0000,0x212a,0x7c7e,0x2174,0x2170,0x2173,0x2175,0x7c7d,
+	0x214a,0x214b,0x2176,0x215c,0x2124,0x215d,0x2125,0x213f,
+	0x2330,0x2331,0x2332,0x2333,0x2334,0x2335,0x2336,0x2337,
+	0x2338,0x2339,0x2127,0x2128,0x2163,0x2161,0x2164,0x2129,
+	0x2177,0x2341,0x2342,0x2343,0x2344,0x2345,0x2346,0x2347,
+	0x2348,0x2349,0x234a,0x234b,0x234c,0x234d,0x234e,0x234f,
+	0x2350,0x2351,0x2352,0x2353,0x2354,0x2355,0x2356,0x2357,
+	0x2358,0x2359,0x235a,0x214e,0x2140,0x214f,0x2130,0x2132,
+	0x212e,0x2361,0x2362,0x2363,0x2364,0x2365,0x2366,0x2367,
+	0x2368,0x2369,0x236a,0x236b,0x236c,0x236d,0x236e,0x236f,
+	0x2370,0x2371,0x2372,0x2373,0x2374,0x2375,0x2376,0x2377,
+	0x2378,0x2379,0x237a,0x2150,0x2143,0x2151,0x2141,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x2171,0x2172,0x7c7b,0x2131,0x7c7c,0x216f,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+	0};
+unsigned short* unicode_rev_table[] = {
+	unicode_rev_table0, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table3, 
+	unicode_rev_table4, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table32, 
+	unicode_rev_table33, 
+	unicode_rev_table34, 
+	unicode_rev_table35, 
+	unicode_rev_table_null, 
+	unicode_rev_table37, 
+	unicode_rev_table38, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table48, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table78, 
+	unicode_rev_table79, 
+	unicode_rev_table80, 
+	unicode_rev_table81, 
+	unicode_rev_table82, 
+	unicode_rev_table83, 
+	unicode_rev_table84, 
+	unicode_rev_table85, 
+	unicode_rev_table86, 
+	unicode_rev_table87, 
+	unicode_rev_table88, 
+	unicode_rev_table89, 
+	unicode_rev_table90, 
+	unicode_rev_table91, 
+	unicode_rev_table92, 
+	unicode_rev_table93, 
+	unicode_rev_table94, 
+	unicode_rev_table95, 
+	unicode_rev_table96, 
+	unicode_rev_table97, 
+	unicode_rev_table98, 
+	unicode_rev_table99, 
+	unicode_rev_table100, 
+	unicode_rev_table101, 
+	unicode_rev_table102, 
+	unicode_rev_table103, 
+	unicode_rev_table104, 
+	unicode_rev_table105, 
+	unicode_rev_table106, 
+	unicode_rev_table107, 
+	unicode_rev_table108, 
+	unicode_rev_table109, 
+	unicode_rev_table110, 
+	unicode_rev_table111, 
+	unicode_rev_table112, 
+	unicode_rev_table113, 
+	unicode_rev_table114, 
+	unicode_rev_table115, 
+	unicode_rev_table116, 
+	unicode_rev_table117, 
+	unicode_rev_table118, 
+	unicode_rev_table119, 
+	unicode_rev_table120, 
+	unicode_rev_table121, 
+	unicode_rev_table122, 
+	unicode_rev_table123, 
+	unicode_rev_table124, 
+	unicode_rev_table125, 
+	unicode_rev_table126, 
+	unicode_rev_table127, 
+	unicode_rev_table128, 
+	unicode_rev_table129, 
+	unicode_rev_table130, 
+	unicode_rev_table131, 
+	unicode_rev_table132, 
+	unicode_rev_table133, 
+	unicode_rev_table134, 
+	unicode_rev_table135, 
+	unicode_rev_table136, 
+	unicode_rev_table137, 
+	unicode_rev_table138, 
+	unicode_rev_table139, 
+	unicode_rev_table140, 
+	unicode_rev_table141, 
+	unicode_rev_table142, 
+	unicode_rev_table143, 
+	unicode_rev_table144, 
+	unicode_rev_table145, 
+	unicode_rev_table146, 
+	unicode_rev_table147, 
+	unicode_rev_table148, 
+	unicode_rev_table149, 
+	unicode_rev_table150, 
+	unicode_rev_table151, 
+	unicode_rev_table152, 
+	unicode_rev_table153, 
+	unicode_rev_table154, 
+	unicode_rev_table155, 
+	unicode_rev_table156, 
+	unicode_rev_table157, 
+	unicode_rev_table158, 
+	unicode_rev_table159, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table249, 
+	unicode_rev_table250, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table_null, 
+	unicode_rev_table255, 
+	unicode_rev_table_null};
new file mode 100644
--- /dev/null
+++ b/font/font.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2004  Kazunori "jagarl" Ueno
+ * Copyright (c) 2000, 2001 Yuki Sawada
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __FONT_TYPES_H__
+#define __FONT_TYPES_H__
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include<vector>
+
+class TextHorizLayout;
+class TextStream;
+class TextGlyphStream;
+
+namespace XKFont {
+class Font;
+class Face;
+class Peer;
+class Glyph;
+class Cache;
+
+struct Font {
+public:
+	Font(const char* fontname, int size);
+	~Font();
+	Face* FaceLoad(double scale);
+	int vsize;
+private:
+	class FontImpl* pimpl;
+};
+
+struct Face {
+public:
+	Face(const char *name, int index, int hsize, int vsize);
+	~Face();
+	Glyph* GlyphLoad(unsigned int code);
+
+private:
+	Cache* cache;
+	typedef std::vector<Peer*>::iterator iterator;
+	std::vector<Peer*> peer;
+};
+
+struct Peer {
+	Peer(void) {}
+	virtual ~Peer() {};
+	virtual bool GlyphCreate(unsigned int code, Glyph* glyph) = 0;
+};
+
+struct Glyph {
+  int bitmap_left;
+  int bitmap_top;
+  struct _bitmap {
+    int width;
+    int rows;
+    unsigned char *buffer;
+    _bitmap() : buffer(0) {}
+    ~_bitmap() { delete[] buffer;}
+  } bitmap;
+#if 0
+  struct _metrics {
+    int ascender;
+    int descender;
+  } metrics;
+#endif
+  struct _advance {
+    int x;
+    int y;
+  } advance;
+  Glyph() : bitmap() {}
+  ~Glyph() {}
+};
+
+struct HorizLayout {
+	HorizLayout(const char* fontname, int size);
+	~HorizLayout();
+	void Layout(::TextStream& stream, ::TextGlyphStream& glyph, std::vector<int>& lineheights, int width);
+	::TextGlyphStream Layout(const char* str, int width, int r=0xff, int g=0xff, int b=0xff);
+private:
+	Font* font;
+	class ::TextHorizLayout* pimpl;
+};
+
+}; /* end of namespace XKFont */
+
+#endif
new file mode 100644
--- /dev/null
+++ b/font/font_face.cc
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2000, 2001 Yuki Sawada
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include"font.h"
+#include"font_peer.h"
+#include <map>
+#include <string>
+#include <iostream>
+
+namespace XKFont {
+
+class Cache : public std::map<unsigned int, Glyph*> {
+public:
+	Cache() {}
+	~Cache() {
+		iterator it;
+		for (it = begin(); it != end(); it++)
+			delete (it->second);
+	}
+};
+
+Face::Face(const char *name_orig, int index, int hsize, int vsize)
+{
+	cache = new Cache;
+
+	/* name: ';' 区切りで複数指定可能 */
+	char* name = new char[strlen(name_orig)+1];
+	while(*name_orig != 0) {
+		const char* next_name = strchr(name_orig, ';');
+		if (next_name) {
+			strncpy(name, name_orig, next_name - name_orig);
+			name[next_name-name_orig] = 0;
+			name_orig = next_name + 1;
+		} else {
+			strcpy(name, name_orig);
+			name_orig += strlen(name_orig);
+		}
+		if (strstr(name, "fn.dat")) {
+			peer.push_back(new PeerFn(name, index, hsize, vsize));
+		} else if (strstr(name, ".ttf") || strstr(name, ".ttc")) {
+			peer.push_back(new PeerFt2(name, index, hsize, vsize));
+#if USE_X11
+		} else {
+			peer.push_back(new PeerX11(name, index, hsize, vsize));
+#endif
+		}
+	}
+	return;
+}
+
+Face::~Face() {
+	delete cache;
+}
+
+Glyph*
+Face::GlyphLoad(unsigned int code) {
+	if (cache->count(code))
+		return (*cache)[code];
+
+	Glyph* g = new Glyph;
+	iterator it;
+	for (it=peer.begin(); it != peer.end(); it++) {
+		if ( (*it)->GlyphCreate(code, g)) break;
+	}
+	if (it == peer.end()) {
+		fprintf(stderr,"Cannot find glyph, code %04x\n",code);
+		g->bitmap_left = 0;
+		g->bitmap_top = 0;
+		g->bitmap.width = 0;
+		g->bitmap.rows = 0;
+		g->bitmap.buffer = new unsigned char[1];
+		g->bitmap.buffer[0] = 0;
+		g->advance.x = 0;
+		g->advance.y = 0;
+	}
+	(*cache)[code] = g;
+	return g;
+}
+
+class FontImpl {
+public:
+	std::map<int, Face*> cache;
+	std::string fontname;
+	int size;
+	~FontImpl();
+};
+
+FontImpl::~FontImpl() {
+	std::map<int,Face*>::iterator it;
+	for (it=cache.begin(); it!=cache.end(); it++) delete it->second;
+}
+
+Font::Font(const char* name, int size) {
+	pimpl = new FontImpl;
+	pimpl->fontname = name;
+	pimpl->size = size;
+	vsize = size;
+};
+Font::~Font() {
+	delete pimpl;
+}
+Face*
+Font::FaceLoad(double scale) {
+	std::map<int, Face*>& cache = pimpl->cache;
+	int size = int(scale * pimpl->size);
+	if (cache.find(size) != cache.end()) return cache[size];
+	try {
+		Face* face = new Face(pimpl->fontname.c_str(), 0, size, size);
+		cache[size] = face;
+		return face;
+	} catch(...) {
+		std::cerr << "Cannot create font face; font "<<pimpl->fontname<<", size "<<size<<std::endl;
+		/* 別の大きさを探す */
+		int i;
+		for (i=0; i<size; i++) {
+			if (cache.find(size-i) != cache.end()) return cache[size-i];
+			if (cache.find(size+i) != cache.end()) return cache[size+i];
+			try {
+				Face* face = new Face(pimpl->fontname.c_str(), 0, size-i, size-i);
+				cache[size-i] = face;
+				return face;
+			} catch(...) {};
+			try {
+				Face* face = new Face(pimpl->fontname.c_str(), 0, size+i, size+i);
+				cache[size+i] = face;
+				return face;
+			} catch(...) {};
+		}
+		/* 見つからない */
+		throw;
+	}
+}
+
+} /* namespace XKFont */
new file mode 100644
--- /dev/null
+++ b/font/font_face.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000, 2001 Yuki Sawada
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __FONT_FACE_H__
+#define __FONT_FACE_H__
+
+#include "font.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  
+struct Gdk_Window;
+/* Construct face */
+FontFace *font_face_new(const char *name, int index, struct Gdk_Window* window, int hsize, int vsize);
+
+/* Destruct face */
+void font_face_destroy(FontFace *face);
+
+FontGlyph *font_glyph_load(FontFace *face, unsigned int code);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/font/font_layout.cc
@@ -0,0 +1,546 @@
+/*  layout2.cc
+ *     テキストの禁則処理、レイアウトなどを行う
+ */
+/*
+ * Copyright (c) 2004-2006  Kazunori "jagarl" Ueno
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include<vector>
+#include<map>
+#include<iostream>
+
+using namespace std;
+
+#include"font.h"
+#include"text.h"
+
+const int line_skip = 1; // 行と行の間の間隔
+const int ruby_textskip = 0; // 文字とルビの間の間隔
+const int ruby_lineskip = 1; // ルビがあるときに行間に加える値
+const double ruby_scale = 0.4; // ルビのスケール
+
+class TextGlyphStreamHelper;
+
+enum KinsokuType { KinsokuHead = 1, KinsokuTail = 2};
+static int kinsoku_table1[] = {
+/* 0 1 2 3 4 5 6 7     0 1 2 3 4 5 6 7 */
+   0,0,2,2,2,2,0,0, /* X 、。,.・: */
+   0,2,2,0,0,0,0,0, /* ;?!゛゜´`¨ */
+   0,0,0,0,0,0,0,0, /* ^ ̄_ヽヾゝゞ〃 */
+   0,0,0,0,2,0,0,0, /* 仝々〆〇ー―‐/ */
+   0,2,0,0,2,2,1,2, /* \〜‖|…‥‘’ */
+   1,2,1,2,1,2,1,2, /* “”()〔〕[] */
+   1,2,1,2,1,2,1,2, /* {}〈〉《》「」 */
+   1,2,1,2,0,0,0,0, /* 『』【】+−±× */
+   0,0,0,0,0,0,0,0, /* ÷=≠<>≦≧∞ */
+   0,0,0,0,0,0,0,0, /* ∴♂♀°′″℃¥ */
+   0,0,0,0,0,0,0,0, /* $¢£%#&*@ */
+   0,0,0,0,0,0,0,0, /* §☆★○●◎◇X */
+   0
+};
+static int kinsoku_table2[] = {
+  0,2,0,2,0,2,0,2,0,2,0,0,0,0,0,0, /*  ぁあぃいぅうぇえぉおかがきぎく */
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ぐけげこごさざしじすずせぜそぞた */
+  0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0, /* だちぢっつづてでとどなにぬねのは */
+  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ばぱひびぴふぶぷへべぺほぼぽまみ */
+  0,0,0,2,0,2,0,2,0,0,0,0,0,0,2,0, /* むめもゃやゅゆょよらりるれろゎわ */
+  0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0, /* ゐゑをんヴヵヶ */
+  0
+};
+
+inline int Kinsoku(int code) {
+	if ( (code&0xff80) == 0xa180) return kinsoku_table1[ (code&0xff) - 0xa0];
+	if ( (code&0xfe80) == 0xa480) return kinsoku_table2[ (code&0xff) - 0xa0]; /* code = 0xa400 / 0xa500 */
+	return 0;
+}
+
+class TextGlyphStreamHelper {
+	typedef TextStream::Iterator Iterator;
+	typedef TextGlyphStream::iterator iterator;
+
+	TextGlyphStream* data;
+
+	// information for rendering
+	unsigned char r, g, b;
+	XKFont::Face* face;
+	XKFont::Face* ruby_face;
+	XKFont::Font* font;
+
+public:
+	int min_lineheight;
+	TextGlyphStreamHelper(XKFont::Font* font);
+	// helper functions
+	void Init(TextGlyphStream* data);
+	Iterator Add(int& x, Iterator begin, Iterator end, int max_x = 0);
+	Iterator AddRuby(int& x, Iterator begin, Iterator end);
+	int CharWidth(int code);
+	void SetGroup(iterator begin, iterator end);
+	void CalcHeight(int& ascent, int& descent, iterator begin, iterator end);
+	void AdjustPosition(int xstart_add, int xend_add, int y_add, iterator begin, iterator end);
+};
+
+TextGlyphStreamHelper::TextGlyphStreamHelper(XKFont::Font* __font) {
+	font = __font;
+	face = font->FaceLoad(1.0);
+	ruby_face = 0;
+	r = 255; g = 255; b = 255;
+	min_lineheight = font->vsize;
+}
+
+void TextGlyphStreamHelper::Init(TextGlyphStream* __data) {
+	r = 255; g = 255; b = 255;
+	face = font->FaceLoad(1.0);
+	data = __data;
+	data->clear();
+	data->font = font;
+}
+
+TextGlyphStreamHelper::Iterator
+TextGlyphStreamHelper::Add(int& x, TextGlyphStreamHelper::Iterator begin, TextGlyphStreamHelper::Iterator end, int max_x) {
+	/* text を glyph に変換する */
+	TextGlyph gl;
+	Iterator it;
+	gl.x = x; gl.y = 0; gl.r = r; gl.g = g; gl.b = b; gl.flag = TextGlyph::Flag(0); gl.is_rev = false;
+	for (it = begin; it != end; it++) {
+		if (it->type != TextElem::glyph) {
+			if (it->type == TextElem::color) {
+				gl.r = r = it->impl.Color.r;
+				gl.g = g = it->impl.Color.g;
+				gl.b = b = it->impl.Color.b;
+			} else if (it->type == TextElem::size) {
+				face = font->FaceLoad(it->impl.Size.scale);
+			} else if (it->type == TextElem::escape) {
+				x = gl.x;
+				return it;
+			}
+			continue;
+		}
+		try {
+			gl.glyph = face->GlyphLoad(it->impl.Glyph.code);
+			if (max_x > 0 && gl.x + gl.glyph->advance.x > max_x) {
+				x = gl.x;
+				return it;
+			}
+			if ( Kinsoku(it->impl.Glyph.code) == KinsokuTail)
+				gl.flag = TextGlyph::Flag(gl.flag | TextGlyph::Kinsoku);
+			else
+				gl.flag = TextGlyph::Flag(0);
+			data->push_back(gl);
+			gl.x += gl.glyph->advance.x;
+		} catch(...) {}
+	}
+	x = gl.x;
+	return it;
+}
+
+TextGlyphStreamHelper::Iterator TextGlyphStreamHelper::AddRuby(int& x, TextGlyphStreamHelper::Iterator sbegin, TextGlyphStreamHelper::Iterator send) {
+	Iterator it;
+	it = sbegin;
+	if (it == send) return it;
+	if (it->type != TextElem::escape || it->impl.Escape.type != TextElem::ruby_start) return sbegin;
+	it++;
+	/* まず、本文描画 */
+	int str_firstpos = data->size();
+	int str_width = 0;
+	it = Add(str_width, it, send);
+	if (it == send || it->type != TextElem::escape || it->impl.Escape.type != TextElem::ruby_startruby) {
+		// ありえないはずだが、取り合えずなにもしないで終了
+		cerr << "TextGlyphStream::AddRuby : invalid operation; fallback to the upeer level"<<endl;
+		data->erase(data->begin()+str_firstpos, data->end());
+		return sbegin+1;
+	}
+	it++;
+	int str_lastpos = data->size()-1;
+	TextGlyph& str_first = data->begin()[str_firstpos];
+	TextGlyph& str_last = data->back();
+	// 次に、フォントを取りかえてルビ描画
+	int ruby_firstpos = data->size();
+	XKFont::Face* save_font = face;
+	if (ruby_face == 0) ruby_face = font->FaceLoad(ruby_scale);
+	face = ruby_face;
+	int ruby_width = 0;
+	it = Add(ruby_width, it, send);
+	if (it->type != TextElem::escape || it->impl.Escape.type != TextElem::ruby_end) {
+		/* ありえないはずだが、取り合えずなにもしないで終了 */
+		cerr << "TextGlyphStream::AddRuby : invalid operation; fallback to the upeer level"<<endl;
+		data->erase(data->begin()+str_firstpos, data->end());
+		return sbegin+1;
+	}
+	it++;
+	face = save_font;
+	TextGlyph& ruby_first = (*data)[ruby_firstpos];
+	TextGlyph& ruby_last = data->back();
+
+	/* ルビを移動すべき高さを求める */
+	int dummy, str_ascent, ruby_descent;
+	CalcHeight(str_ascent, dummy, data->begin()+str_firstpos, data->begin()+ruby_firstpos);
+	CalcHeight(dummy, ruby_descent, data->begin()+ruby_firstpos, data->end());
+	int ruby_height = str_ascent + ruby_descent + ruby_textskip;
+
+	/* センタリングした場合の、ルビの左側、右側のマージン */
+	int leftmergin, rightmergin;
+	leftmergin = str_first.glyph->advance.x/2 - (ruby_first.glyph->advance.x+1)/2;
+	rightmergin = str_last.glyph->advance.x/2 - (ruby_last.glyph->advance.x+1)/2;
+
+	/* ルビ、本文の横方向の移動 */
+	int ruby_xstart_add = 0, ruby_xend_add = 0, str_xstart_add=0, str_xend_add = 0;
+	if (ruby_width+leftmergin+rightmergin <= str_width) { // ルビの方が小さい
+		ruby_xstart_add = leftmergin;
+		ruby_xend_add = str_width-rightmergin-ruby_width;
+	} else if (ruby_width <= str_width) { // マージンを減らす必要あり
+		leftmergin = (str_width-ruby_width)/2;
+		ruby_xstart_add = leftmergin;
+		ruby_xend_add = str_width-leftmergin-ruby_width;
+	} else { // ルビの方が大きい
+		int str_count = ruby_firstpos - str_firstpos;
+		str_xstart_add = ruby_width/str_count/2 - str_first.glyph->advance.x/2;
+		str_xend_add = (ruby_width-str_width) - (ruby_width/str_count/2-str_last.glyph->advance.x/2);
+		str_width = ruby_width;
+	}
+	AdjustPosition(str_xstart_add+x, str_xend_add+x, 0, data->begin()+str_firstpos, data->begin()+ruby_firstpos);
+	AdjustPosition(ruby_xstart_add+x, ruby_xend_add+x, -ruby_height, data->begin()+ruby_firstpos, data->end());
+
+	/* 本文が一文字ずつ表示されるように glyph の順番を入れかえ、グループ化 */
+	vector<TextGlyph> save;
+	save.assign(data->begin()+str_firstpos, data->end());
+	iterator it_str = save.begin();
+	iterator it_ruby = save.begin()+(ruby_firstpos-str_firstpos);
+	iterator dit = data->begin()+str_firstpos;
+	int str_count = it_ruby-it_str;
+	int ruby_count = save.end()-it_ruby;
+	int i,j = 0;
+	for (i=0; i<str_count; i++) {
+		iterator charstart = dit;
+		int jend = (i+1)*ruby_count/str_count;
+		for (; j<jend; j++) {
+			*dit++ = *it_ruby++;
+		}
+		*dit++ = *it_str++;
+		SetGroup(charstart, dit);
+	}
+	x += str_width;
+	return it;
+}
+
+
+void TextGlyphStreamHelper::SetGroup(TextGlyphStreamHelper::iterator begin, TextGlyphStreamHelper::iterator end) {
+	iterator it;
+	for (it = begin; it+1 != end; it++)
+		it->flag = TextGlyph::Flag(it->flag |TextGlyph::Group);
+	it->flag = TextGlyph::Flag(it->flag & ~TextGlyph::Group);
+	return;
+}
+
+void TextGlyphStreamHelper::AdjustPosition(int xstart_add, int xend_add, int y_add, TextGlyphStreamHelper::iterator begin, TextGlyphStreamHelper::iterator end) {
+	iterator it;
+	/* 文字数を数える */
+	int total_count = 0;
+	for (it = begin; it != end; it++) {
+		if (it->flag & TextGlyph::Group) continue;
+		total_count++;
+	}
+	/* 文字間のギャップを変更 */
+	int incr = 0;
+	if (total_count != 1) incr = (xend_add - xstart_add) * 256 / (total_count-1);
+	int cur = xstart_add * 256;
+	for (it = begin; it != end; it++) {
+		it->x += cur / 256;
+		it->y += y_add;
+		if (it->flag & TextGlyph::Group) continue;
+		cur += incr;
+	}
+	return;
+}
+void TextGlyphStreamHelper::CalcHeight(int& ascent_r, int& descent_r, TextGlyphStreamHelper::iterator begin, TextGlyphStreamHelper::iterator end) {
+	iterator it;
+	/* 最大の descent, ascent を計算 */
+	int ascent = 0;
+	int descent = 0;
+	for (it = begin; it != end; it++) {
+
+		int y_top = it->y - it->glyph->bitmap_top;
+		int y_bottom = it->y + it->glyph->bitmap.rows - it->glyph->bitmap_top;
+
+		if (descent < y_bottom) descent = y_bottom;
+		if (ascent < -y_top) ascent = -y_top;
+	}
+	ascent_r = ascent;
+	descent_r = descent;
+	return;
+}
+
+int TextGlyphStreamHelper::CharWidth(int code) {
+	try {
+		XKFont::Glyph* g = face->GlyphLoad(code);
+		return g->advance.x;
+	} catch(...) {
+		return 0;
+	}
+}
+
+class TextHorizLayout {
+	typedef TextStream::Iterator Iterator;
+
+	Iterator pos;
+	Iterator end;
+	TextGlyphStream* data;
+	TextGlyphStreamHelper helper;
+	int tab_width;
+	int cur_y;
+
+	void SetName(void);
+	void SetLineHead(void);
+	void MakeLine(int line_first, int width, vector<int>& lineheights);
+public:
+	TextHorizLayout(XKFont::Font* font);
+	void Layout(TextStream& stream, TextGlyphStream& glyph, vector<int>& lineheights, int width);
+};
+
+TextHorizLayout::TextHorizLayout(XKFont::Font* font) :
+	helper(font), tab_width(0), cur_y(0) {
+}
+
+void TextHorizLayout::Layout(TextStream& stream, TextGlyphStream& glyph, vector<int>& lineheights, int width) {
+	pos = stream.container.begin();
+	end = stream.container.end();
+	data = &glyph;
+
+	helper.Init(data);
+	tab_width = 0;
+	cur_y = 0;
+	int prev_y = 0;
+	int line_start = glyph.size();
+	while(pos != end) {
+/*
+if (pos->type == TextElem::glyph) { int c = pos->impl.Glyph.code; char cc[3]={0,0,0};cc[0]=c>>8;cc[1]=c;cout<<"glyph "<<cc<<endl;}
+if (pos->type == TextElem::escape) { cout<<"escape "<<pos->impl.Escape.type<<endl;}
+*/
+		SetName();
+		SetLineHead();
+		MakeLine(line_start, width, lineheights);
+		if (line_start != glyph.size()) {
+			data->back().flag = TextGlyph::Flag(data->back().flag | TextGlyph::PhraseEnd | TextGlyph::LineEnd);
+		}
+		prev_y = cur_y;
+		if (pos != end && pos->type == TextElem::escape && pos->impl.Escape.type == TextElem::ret) pos++;
+		line_start = glyph.size();
+	}
+	return;
+}
+
+void TextHorizLayout::SetName(void) {
+	Iterator it;
+
+	tab_width = 0;
+	/* 行頭が名前なら、処理開始 */
+	for (; pos != end; pos++) {
+		if (pos->type == TextElem::escape || pos->type == TextElem::glyph) break;
+		int x = 0;
+		helper.Add(x, pos, pos+1);
+	}
+
+	if (pos->type != TextElem::escape || pos->impl.Escape.type != TextElem::name_start) return;
+
+	/* 名前をセットし、行頭の「の分を含めてタブ幅を設定する */
+	pos++;
+	for (it = pos; it != end; it++) {
+		if (it->type == TextElem::escape && it->impl.Escape.type == TextElem::name_end) break;
+	}
+	if (it == end) return;
+	int line_firstpos = data->size();
+	pos = helper.Add(tab_width, pos, it);
+	pos++;
+	helper.SetGroup(data->begin() + line_firstpos, data->end());
+
+	// 行頭の「分を開ける
+	try {
+		tab_width += helper.CharWidth(0xa1d6); /* 「 */
+	} catch(...) {}
+	
+	return;
+};
+
+void TextHorizLayout::SetLineHead(void) {
+
+	/* 行頭は 「などか? */
+
+	for (; pos != end; pos++) {
+		if (pos->type == TextElem::escape || pos->type == TextElem::glyph) break;
+		int x = 0;
+		helper.Add(x, pos, pos+1);
+	}
+	if (pos->type != TextElem::glyph || Kinsoku(pos->impl.Glyph.code) != KinsokuHead) return;
+
+	/* 「なので、処理する */
+	if (tab_width != 0) tab_width -= helper.CharWidth(pos->impl.Glyph.code);
+	int line_firstpos = data->size();
+	pos = helper.Add(tab_width, pos, pos+1);
+	return;
+}
+
+void TextHorizLayout::MakeLine(int line_start, int width, vector<int>& lineheights) {
+	
+	int x = tab_width;
+	/* まず、全文字描画する */
+	while(pos != end) {
+		pos = helper.Add(x, pos, end);
+		if (pos->type == TextElem::escape && pos->impl.Escape.type == TextElem::ruby_start) { 
+			pos = helper.AddRuby(x, pos, end);
+		}
+		if (pos != end && pos->type == TextElem::escape) {
+			if (pos->impl.Escape.type == TextElem::ret) break;
+			if (pos->impl.Escape.type != TextElem::ruby_start) pos++;
+		}
+	}
+	/* 行に分割していく */
+	TextGlyphStream::iterator it_start = data->begin() + line_start;
+	TextGlyphStream::iterator it_end = data->end();
+	TextGlyphStream::iterator it = it_start;
+
+	TextGlyphStream::iterator group_head = it_start;
+	int xstart = tab_width;
+	int xend = width;
+	while(it != it_end) {
+		// この行の終わりを決める
+		bool is_ruby = false;
+		TextGlyphStream::iterator it_line_start = it;
+		for (; it != it_end; it++) {
+			if (it->x + it->glyph->advance.x > xend) break;
+			if (it->flag & TextGlyph::Group) is_ruby = true;
+			if (!(it->flag & TextGlyph::Group)) group_head = it;
+		}
+		// 水平移動の大きさを決める。デフォルトでタブ位置まで戻す
+		int xadd_start = -xstart + tab_width;
+		int xadd_end = xadd_start;
+		// it == 次行の先頭なので、今行の末尾へ戻す
+		// ただし、 最低一文字の表示は保証
+		if (it != it_line_start && it != it_line_start+1 && it != it_end) it--;
+		if (it != it_end) {
+			// グループ化されている文字で終了したら、前の文字に戻す
+			if (it->flag & TextGlyph::Group) it = group_head;
+			// 次が行頭禁則文字ならこの行に入れる
+			if ( (it+1) != it_end && (it+1)->flag & TextGlyph::Kinsoku) it++;
+			// 移動する大きさを決める
+			// 行端ぞろえ、行末文字なら半文字分だけ突き出る
+			int glyph_xend = it->x + it->glyph->advance.x;
+			if (it != it_line_start && (it-1)->flag & TextGlyph::Group) { // グループ化文字の場合、1文字前も見る
+				if (glyph_xend < (it-1)->x + (it-1)->glyph->advance.x)
+					glyph_xend = (it-1)->x + (it-1)->glyph->advance.x;
+			}
+			xadd_end += xend - glyph_xend;
+			if (it->flag & TextGlyph::Kinsoku)
+				xadd_end += it->glyph->advance.x / 2;
+		}
+		if (it != it_end) {
+			it->flag = TextGlyph::Flag(it->flag | TextGlyph::LineEnd);
+			it++; // it == 次行の先頭へ
+		}
+		int ascent, descent;
+		helper.CalcHeight(ascent, descent, it_start, it);
+		if (ascent+descent < helper.min_lineheight) {
+			int dif = helper.min_lineheight-(ascent+descent);
+			ascent += dif/2;
+			descent += dif-(dif/2);
+		}
+		if (is_ruby) ascent+=ruby_lineskip;
+		helper.AdjustPosition(xadd_start, xadd_end, cur_y+ascent+1, it_start, it);
+		cur_y += ascent + descent + line_skip;
+		lineheights.push_back(ascent+descent+line_skip);
+
+		/* 次の行へ */
+		if (it != it_end) {
+			it_start = it;
+			group_head = it_start;
+			/* 1文字目がグループ化されていれば、グループの先頭文字にする */
+			xstart = it->x;
+			if (it->flag & TextGlyph::Group) {
+				TextGlyphStream::iterator jit;
+				for (jit = it; jit != it_end; jit++) {
+					if (xstart > jit->x) xstart = jit->x;
+					if (!(jit->flag & TextGlyph::Group)) break;
+				}
+			}
+			xend = it->x + width-tab_width;
+		}
+	}
+	return;
+}
+
+namespace XKFont {
+
+HorizLayout::HorizLayout(const char* fontname, int size) {
+	font = new Font(fontname, size);
+	pimpl = new ::TextHorizLayout(font);
+}
+
+HorizLayout::~HorizLayout() {
+	delete pimpl;
+	delete font;
+}
+
+void HorizLayout::Layout(TextStream& stream, TextGlyphStream& glyph, vector<int>& lineheights, int width) {
+	pimpl->Layout(stream, glyph, lineheights, width);
+};
+TextGlyphStream HorizLayout::Layout(const char* str, int width, int r, int gc, int b) {
+	TextStream s;
+	s.SetColor(r,gc,b);
+	s.Add(str);
+	TextGlyphStream g;
+	vector<int> h;
+	Layout(s, g, h, width);
+	return g;
+}
+
+};
+
+int TextGlyphStream::width(void) {
+	if (empty()) return 0;
+	iterator it;
+	int xmax = 0;
+	for (it=begin(); it!=end(); it++) {
+		int x = it->x + it->glyph->advance.x;
+		if (x > xmax) xmax = x;
+	}
+	return xmax + 1;
+}
+
+int TextGlyphStream::height(void) {
+	if (empty()) return 0;
+	iterator it;
+	int ymax = 0;
+	it = end();
+	while(1) {
+		it--;
+		int y = it->y + it->glyph->bitmap.rows - it->glyph->bitmap_top;
+		if (ymax < y) ymax = y;
+		if (it == begin()) break;
+		if (it->flag & TextGlyph::LineEnd) {
+			if (!(it->flag & TextGlyph::PhraseEnd)) break; // PhraseEnd は最後の文字
+		}
+	}
+	return ymax + 1;
+}
+
new file mode 100644
--- /dev/null
+++ b/font/font_peer.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2004  Kazunori "jagarl" Ueno
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __FONT_PEER_H__
+#define __FONT_PEER_H__
+
+#include "font.h"
+
+namespace XKFont {
+
+class PeerFn : public Peer {
+public:
+	PeerFn(const char* name, int index, int hsize, int vsize);
+	~PeerFn();
+	bool GlyphCreate(unsigned int code, Glyph* g);
+private:
+	unsigned char *buffer;
+};
+
+}
+
+#include <ft2build.h> 
+#include FT_FREETYPE_H 
+
+namespace XKFont {
+typedef unsigned int (*FontCodeConverter)(unsigned int);
+class PeerFt2 : public Peer {
+public:
+	PeerFt2(const char *name, int index, int hsize, int vsize);
+	~PeerFt2();
+	bool GlyphCreate(unsigned int code, Glyph* glyph);
+private:
+	FT_Face face;
+	FontCodeConverter conv_func;
+};
+
+}
+
+#if USE_X11
+#include <X11/Xlib.h>
+#include <X11/extensions/XShm.h>
+
+namespace XKFont {
+class PeerX11 : public Peer {
+public:
+	PeerX11(const char *name, int index, int hsize, int vsize);
+	~PeerX11();
+	bool GlyphCreate(unsigned int code, Glyph* g);
+	static void InitDisplay(Display*);
+	static void OpenDisplay(void);
+private:
+	static Display* display;
+
+	XFontSet fontset;
+	GC gc;
+	Visual* visual;
+	unsigned long white, black;
+	Pixmap canvas;
+	XShmSegmentInfo x_shm_info;
+	bool use_shm;
+	XImage* image;
+	int width, height, ascent;
+	int mask, shift;
+	int* colortable;
+};
+
+}; /* namespace XKFont */
+#endif /* USE_X11 */
+
+#endif /* __FONT_PEER_H__ */
new file mode 100644
--- /dev/null
+++ b/font/font_peer_fn.cc
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2001 Yuki Sawada
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This code uses some parts of AVG32 for Macintosh by Kenjo.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdexcept>
+#include <string>
+
+using namespace std;
+
+#include "font.h"
+#include "font_peer.h"
+
+namespace XKFont {
+
+#define FN_DAT_SIZE  2544768
+
+PeerFn::PeerFn(const char *name, int index, int hsize, int vsize) : buffer(0)
+{
+  FILE *fp = 0;
+
+  buffer = new unsigned char[FN_DAT_SIZE];
+  fp = fopen(name, "rb");
+  if (!fp) {
+	delete[] buffer;
+	buffer = 0;
+	string err = string("XKFont::PeerFn::PeerFn : Cannot open font file ")+name;
+	throw std::invalid_argument(err);
+  }
+  fread(buffer, 1, FN_DAT_SIZE, fp);
+  fclose(fp);
+  
+  return;
+}
+
+
+PeerFn::~PeerFn() {
+	delete[] buffer;
+}
+
+static unsigned int
+font_glyph_fn_codeconv_euc_to_jis(unsigned int euc)
+{
+  unsigned int h, l;
+
+  h = (euc >> 8) & 0xff;
+  l = euc & 0xff;
+
+  if (h < 0x81) {
+    l = h;
+    h = 0;
+  } else if (l == 0x8e)
+    h = 0;
+  else {
+    h -= 0x80;
+    l -= 0x80;
+  }
+  
+  return (h << 8) | l;
+}
+
+bool
+PeerFn::GlyphCreate(unsigned int code, Glyph* glyph)
+{
+  unsigned char *p1, *p2;
+  unsigned int h, l, offset;
+  int x, y;
+
+  l = font_glyph_fn_codeconv_euc_to_jis(code);
+  l -= 0x2121;
+  h = l >> 8;
+  l &= 0xff;
+  offset = (h * 0x5e + l) * 12 * 24;
+  if (offset > FN_DAT_SIZE - 12 * 24)
+    offset = 0;
+
+  glyph->bitmap_left = 0;
+  glyph->bitmap_top = 21;
+  glyph->bitmap.width = 24;
+  glyph->bitmap.rows = 24;
+
+#if 0
+  glyph->metrics.ascender = private->vsize - 4;
+  glyph->metrics.descender = -4;
+#endif
+  glyph->advance.x = 24 + 1;
+  glyph->advance.y = 24 + 1;
+
+  glyph->bitmap.buffer = new unsigned char[24*24];
+
+  p1 = glyph->bitmap.buffer;
+  p2 = buffer + offset;
+  for (y = 0; y < 24; y++) {
+    for (x = 0; x < 12; x++) {
+      unsigned char c = ~*p2++;
+      unsigned char c1;
+      c1 = (c)   & 0x0f; *p1++ = (c1<<4) | c1;
+      c1 = (c>>4)& 0x0f; *p1++ = (c1<<4) | c1;
+    }
+  }
+  return true;
+}
+
+} /* end of namespace XKFont */
new file mode 100644
--- /dev/null
+++ b/font/font_peer_ft2.cc
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2004  Kazunori "jagarl" Ueno
+ * Copyright (c) 2000, 2001 Yuki Sawada
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdexcept>
+#include <string>
+
+using namespace std;
+
+#include "font.h"
+#include "font_peer.h"
+#include "codeconv.h"
+
+namespace XKFont {
+
+typedef struct _FontLibrary {
+  FT_Library super;
+  int ref_count;
+  char **paths;
+  int num_paths;
+} FontLibrary;
+
+static FontLibrary *library = NULL;
+
+static char *default_paths[] = {
+  ".",
+  "/",
+  "/usr/X11R6/lib/X11/fonts/TrueType",
+  "/usr/local/share/fonts/TrueType",
+  "/usr//share/fonts/TrueType",
+  "/usr//share/fonts/tt",
+  NULL
+};
+
+static void font_library_ft2_add_path(const char *path);
+static void font_library_ft2_remove_path(const char *path);
+static void font_library_ft2_add_path(const char *path);
+static char *font_library_ft2_build_path(const char *base, const char *name);
+
+static int
+font_library_ft2_alloc()
+{
+  int i;
+  
+  if (!library) {
+    library = (FontLibrary*) calloc(sizeof(FontLibrary), 1);
+    if (library) {
+      if (FT_Init_FreeType(&library->super))
+	goto _1;
+      fprintf(stderr, "XKFont::font_library_ft2_alloc : FreeType allocated successfully.\n");
+      for (i = 0; default_paths[i]; i++)
+	font_library_ft2_add_path(default_paths[i]);
+    }
+  }
+
+  library->ref_count++;
+  return 1;
+
+ _1:
+  free(library);
+  library = NULL;
+  fprintf(stderr, "XKFont::font_library_ft2_alloc: Couldn't allocate FreeType.\n");
+  return 0;
+}
+
+static void
+font_library_ft2_free()
+{
+  int i;
+  
+  if (!library || library->ref_count <= 0)
+    return;
+  if (--library->ref_count == 0) {
+    FT_Done_FreeType(library->super);
+    for (i = 0; i < library->num_paths; i++)
+      free(library->paths[i]);
+    free(library->paths);
+    free(library);
+    library = NULL;
+    fprintf(stderr, "XKFont::font_library_ft2_free : FreeType done.\n");
+  }
+}
+
+static void
+font_library_ft2_add_path(const char *path)
+{
+  library->num_paths++;
+  if (!library->paths)
+    library->paths = (char**) malloc(sizeof(char *));
+  else
+    library->paths = (char**) realloc( (void*)library->paths,
+			     library->num_paths * sizeof(char *));
+  library->paths[library->num_paths - 1] = strdup(path);
+}
+
+static void
+font_library_ft2_remove_path(const char *path)
+{
+  int i, j;
+
+  for (i = 0; i < library->num_paths; i++) {
+    if (!strcmp(path, library->paths[i])) {
+      library->num_paths--;
+      for (j = i; j < library->num_paths; j++)
+	library->paths[j] = library->paths[j + 1];
+      if (library->num_paths > 0)
+	library->paths = (char**) realloc(library->paths,
+				 library->num_paths * sizeof(char *));
+      else {
+	free(library->paths);
+	library->paths = NULL;
+      }
+    }
+  }
+}
+
+typedef struct _FontEncoding {
+  FT_UShort platform_id;
+  FT_Encoding encoding;
+  FontCodeConverter conv_func;
+} FontEncoding;
+
+static FontEncoding encodings[] = {
+  { 3, (FT_Encoding)ft_encoding_unicode, codeconv_euc_to_unicode },
+  { 3, (FT_Encoding)ft_encoding_sjis, codeconv_euc_to_sjis },
+  { 1, (FT_Encoding)ft_encoding_apple_roman, codeconv_euc_to_latin1 },
+  { (FT_UShort)-1, (FT_Encoding)-1, NULL }
+};
+
+static char *
+font_library_ft2_build_path(const char *base, const char *name)
+{
+  char *path;
+  const char *strs[] = { base, "/", name, NULL };
+  int i = 0;
+  
+  path = (char*) calloc(sizeof(char), strlen(base) + strlen(name) + 2);
+  if (path) 
+    while (strs[i])
+      strcat(path, strs[i++]);
+    
+  return path;
+}
+
+PeerFt2::PeerFt2(const char *name, int index, int hsize, int vsize)
+{
+  int i,j;
+
+  font_library_ft2_alloc();
+  
+  for (i = 0; i < library->num_paths; i++) {
+    char *path = font_library_ft2_build_path(library->paths[i], name);
+    if (path) {
+	if (FT_New_Face(library->super, path, index, &face))
+	  face = NULL;
+	free(path);
+    }
+    if (face)
+	break;
+  }
+  
+  if (!face) {
+	string err = string("XKFont::PeerFt2::PeerFt : Cannot open font(TrueType) : ")+name;
+	throw std::invalid_argument(err);
+  }
+  
+  conv_func = 0;
+  for (i=0; encodings[i].conv_func != 0; i++) {
+	FT_UShort platform_id = encodings[i].platform_id;
+    	FT_Encoding encoding = encodings[i].encoding;
+    	for (j = 0; j < face->num_charmaps; j++) {
+      		FT_CharMap cmap = face->charmaps[j];
+      		if (cmap->platform_id == platform_id && cmap->encoding == encoding) {
+      			if (FT_Set_Charmap(face, cmap) == 0) {
+       				conv_func = encodings[i].conv_func;
+				break;
+      			}
+    		}
+    	}
+	if (conv_func) break;
+  }
+  if (conv_func == 0) {
+	FT_Done_Face(face);
+	fprintf(stderr,"cannot find charmap\n");
+	string err = string("XKFont::PeerFt2::PeerFt : No supported code converter of font (TrueType) ")+name;
+	throw std::invalid_argument(err);
+  }
+  FT_Set_Pixel_Sizes(face, hsize, vsize);
+
+}
+
+PeerFt2::~PeerFt2() {
+	FT_Done_Face(face);
+	font_library_ft2_free();
+}
+
+bool
+PeerFt2::GlyphCreate(unsigned int code, Glyph* glyph)
+{
+  FT_GlyphSlot slot;
+  FT_UInt index;
+  int bmsize;
+
+  if (face == 0) return false;
+  code = conv_func(code);
+  if (code == 0) return false;
+  index = FT_Get_Char_Index(face, code);
+  if (index == 0) return false;
+
+  /* Don't consider error */
+  slot = face->glyph;
+  if (slot) {
+    // if (! FT_Load_Glyph(face, index, FT_LOAD_DEFAULT)) {
+// BITMAP だと なぜか render してくれない……
+// LOAD_DEFAULT でも、下に対応コードを付けたので一応は大丈夫
+    if (! FT_Load_Glyph(face, index, FT_LOAD_NO_BITMAP)) {
+    	FT_Render_Glyph(slot, ft_render_mode_normal);
+    }
+  }
+  
+  glyph->bitmap_left = slot->bitmap_left;
+  glyph->bitmap_top = slot->bitmap_top;
+  glyph->bitmap.width = slot->bitmap.width;
+  glyph->bitmap.rows = slot->bitmap.rows;
+
+/*
+  glyph->metrics.ascender = private->face->size->metrics.ascender >> 6;
+  glyph->metrics.descender = private->face->size->metrics.descender >> 6;
+*/
+
+  glyph->advance.x = slot->advance.x >> 6;
+  glyph->advance.y = slot->advance.y >> 6;
+
+  bmsize = glyph->bitmap.width * glyph->bitmap.rows;
+  if (bmsize > 0) {
+    glyph->bitmap.buffer = new unsigned char[bmsize];
+    memcpy(glyph->bitmap.buffer, slot->bitmap.buffer, bmsize);
+  }
+// なぜか Render したのに MONO なことがある……
+/* for freetype < 2.1.3, use ``ft_pixel_mode_mono'' */
+if (slot->bitmap.pixel_mode == ft_pixel_mode_mono) {int i,j;
+// if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {int i,j;
+	char* d = (char*)slot->bitmap.buffer;
+	for (i=0; i<glyph->bitmap.rows; i++) {
+		int flag = *d++; int len = 8;
+		unsigned char* buf = glyph->bitmap.buffer + i*slot->bitmap.width;
+		for (j=0; j<glyph->bitmap.width; j++) {
+			if (len == 0) {
+				flag = *d++;
+				len = 8;
+			}
+			if (flag & 0x80) *buf++ = 0xff;
+			else *buf++ = 0;
+			flag <<= 1;
+			len--;
+		}
+	}
+}
+
+  return true;
+
+}
+
+} /* end of namespace XKFont */
+
new file mode 100644
--- /dev/null
+++ b/font/font_peer_x11.cc
@@ -0,0 +1,420 @@
+/*
+ * Copyright (c) 2004  Kazunor "jagarl" Ueno
+ * Copyright (c) 2000, 2001 Yuki Sawada
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+
+#include "font.h"
+#include "font_peer.h"
+
+#if USE_X11
+
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/extensions/XShm.h>
+#include <stdio.h>
+#include<iostream>
+
+#include<vector>
+#include<map>
+//#include<iostream>
+#include<sstream>
+#include <string>
+#include <stdexcept>
+
+using namespace std;
+
+namespace XKFont {
+inline int read_little_endian_int(const char* buf) {
+	const unsigned char *p = (const unsigned char *) buf;
+	return (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0];
+}
+
+/***********************************
+**
+** Fontinfo / FontSetInfo
+**
+**   fontset から特定 pixel size を持つ
+**   別のfontsetを作成するためのクラス
+*/
+struct FontInfo {
+	std::map<int, string> fontlist;
+	FontInfo(Display* display, const char* fontname_orig);
+	string Search(int pixsize);
+};
+struct FontSetInfo {
+	std::vector<FontInfo*> fontlist;
+	FontSetInfo(Display* display, const char* fontset_orig);
+	string Search(int pixsize);
+	~FontSetInfo();
+};
+
+
+/***********************************
+**
+** Methods of Fontinfo / FontSetInfo
+**
+*/
+FontInfo::FontInfo(Display* display, const char* fontname_orig) {
+	/* フォントの大きさ関係の情報を消去 */
+	int i;
+	char* fontname = new char[strlen(fontname_orig)+50];
+	int minus_count = 0; bool is_skip = false; int fc = 0;
+	for (i=0; fontname_orig[i]!=0; i++) {
+		if (fontname_orig[i] == '-') {
+			minus_count++;
+			if (minus_count >= 7 && minus_count <= 12) {
+				fontname[fc++] = '-';
+				fontname[fc++] = '*';
+				is_skip = true;
+			} else {
+				is_skip = false;
+			}
+		}
+		if (! is_skip) fontname[fc++] = fontname_orig[i];
+	}
+	/* フォント情報を得る */
+	fontname[fc] = 0;
+	int count;
+	char** fontnamelist = XListFonts(display, fontname, 100, &count);
+	for (i=0; i<count; i++) {
+		char* curfont = fontnamelist[i];
+		/* fontname から pixel size 情報を得る */
+		int j; int minus_count = 0;
+		for (j=0; curfont[j] != 0; j++) {
+			if (curfont[j] == '-') minus_count++;
+			if (minus_count == 7) {
+				int pixsize = atoi(curfont+j+1);
+				if (fontlist.find(pixsize) == fontlist.end()) {
+					fontlist[pixsize] = string(curfont);
+				}
+				break;
+			}
+		}
+	}
+	/* 検索に失敗した場合、とりあえず fontname を入れておく */
+	if (fontlist.find(0) == fontlist.end()) {
+		fontlist[0] = string(fontname);
+	}
+	XFreeFontNames(fontnamelist);
+	delete[] fontname;
+	return;
+}
+string FontInfo::Search(int pixsize) {
+	int i;
+	/* pixsize に近いフォントが(あれば)帰す */
+	if (fontlist.find(pixsize) != fontlist.end()) return fontlist[pixsize];
+	for (i=1; i<4; i++) {
+		if (fontlist.find(pixsize-i) != fontlist.end()) return fontlist[pixsize-i];
+		if (fontlist.find(pixsize+i) != fontlist.end()) return fontlist[pixsize+i];
+	}
+	/* 見つからない:fontlist[0] を加工して帰す */
+	/* pt/xres/yres などのフィールドに '-0-' というのがあれば '-*-'に変換
+	** pixsize は与えられた pixsize にする
+	*/
+	string basefont_s = fontlist[0];
+	const char* basefont = basefont_s.c_str();
+	char* retfont = new char[strlen(basefont)+50];
+	int minus_count = 0; int rc = 0; bool is_skip = false;
+	for (i=0; basefont[i] != 0; i++) {
+		if (basefont[i] == '-') {
+			minus_count++;
+			is_skip = false;
+			if (minus_count == 7) {
+				sprintf(retfont+rc, "-%d", pixsize);
+				rc = strlen(retfont);
+				is_skip = true;
+			} else if (minus_count > 7 && minus_count <= 12) {
+				if (basefont[i+1] == '0' && basefont[i+2] == '-') {
+					retfont[rc++]='-';
+					retfont[rc++]='*';
+					is_skip = true;
+				}
+			}
+		}
+		if (! is_skip) retfont[rc++] = basefont[i];
+	}
+	retfont[rc] = 0;
+	string retfont_str = string(retfont);
+	delete[] retfont;
+	return retfont_str;
+}
+
+FontSetInfo::FontSetInfo(Display* display, const char* fontset_orig) {
+	char* fontset = new char[strlen(fontset_orig)+1];
+	strcpy(fontset, fontset_orig);
+	char* cur = fontset;
+	while(strchr(cur, ',')) {
+		char* font = cur;
+		cur = strchr(cur, ',');
+		*cur++ = '\0';
+		fontlist.push_back(new FontInfo(display, font));
+	}
+	fontlist.push_back(new FontInfo(display, cur));
+	delete[] fontset;
+	return;
+}
+FontSetInfo::~FontSetInfo() {
+	std::vector<FontInfo*>::iterator it;
+	for (it=fontlist.begin(); it != fontlist.end(); it++) {
+		delete (*it);
+	}
+	return;
+}
+string FontSetInfo::Search(int pixsize) {
+	stringstream s;
+	std::vector<FontInfo*>::iterator it;
+	for (it=fontlist.begin(); it != fontlist.end(); it++) {
+		if (it != fontlist.begin()) s << ",";
+		s << (*it)->Search(pixsize);
+	}
+	s<<ends;
+	return string(s.str());
+}
+
+/****************************************
+**
+** FontPeerX11
+*/
+Display* PeerX11::display = 0;
+void PeerX11::InitDisplay(Display* _d) {
+	/* d = ((GdkWindowPrivate*)(top_window.gdkobj()))->xdisplay; */
+	display = _d;
+}
+
+void PeerX11::OpenDisplay(void) {
+	if (display) return;
+
+	char* display_name = getenv("DISPLAY");
+	if (display_name == 0) display_name = ":0";
+
+	display = XOpenDisplay(display_name);
+
+	if (display == 0) {
+		string err = string("XKFont::PeerX11:OpenDisplay() : Cannot open X display ") + display_name;
+		throw std::invalid_argument(err);
+	}
+}
+
+inline int MAX(int a, int b) {
+	if (a > b) return a;
+	else return b;
+}
+
+PeerX11::PeerX11(const char* fontname, int index, int fontsize, int _vsize) :
+	fontset(0), gc(0), canvas(0), image(0), colortable(0) {
+	OpenDisplay();
+
+	int scr = DefaultScreen(display);
+	Window w = RootWindow(display, scr);
+	Colormap cmap = DefaultColormap(display, scr);
+	visual = DefaultVisual(display, scr);
+
+	if (visual->c_class != TrueColor  && visual->c_class != DirectColor) {
+		string err = "XKFont::PeerX11:PeerX11() : No supported Color mode of X : neither TrueColor nor DirectColor";
+		throw std::runtime_error(err);
+	}
+	/* 色の初期化 */
+	white = visual->red_mask | visual->green_mask | visual->blue_mask;
+	black = 0;
+	if (visual->green_mask == 0) {
+		string err = "XKFont::PeerX11:PeerX11() : Invalid Visual on X";
+		throw std::runtime_error(err);
+	}
+	shift = 0;
+	mask = visual->green_mask;
+	while(mask & 0x01) { shift++; mask >>= 1; }
+
+	int tablesize = mask+1;
+	colortable = new int[tablesize];
+	int i; for (i=0; i< tablesize; i++) {
+		colortable[i] = i*255/tablesize;
+	}
+XSupportsLocale();
+
+	/* font 読み込み */
+	FontSetInfo fsinfo(display,fontname);
+	string fontset_name = fsinfo.Search(fontsize);
+	char** missing_cl; int missing_cc; char* def_s;
+printf("fontset %s\n",fontset_name.c_str());
+	fontset = XCreateFontSet(display, fontset_name.c_str(), &missing_cl, &missing_cc, &def_s);
+
+	if (fontset == 0) {
+		delete[] colortable;
+		string err = string("XKFont::PeerX11:PeerX11() : Cannot create fontset ");
+		err += fontset_name; err += " (font name "; err += fontname; err += ")";
+		throw std::invalid_argument(err);
+	}
+
+	if (missing_cc != 0) {
+		cerr << "XKFont::PeerX11:PeerX11() : Cannot found some fonts in the fontset"<<endl;
+		cerr << "   fontset: "<<fontset_name<<endl;
+		cerr << "   not found fonts:"<<endl;
+		int i; for (i=0; i<missing_cc; i++) {
+			cerr << "        " << missing_cl[i] << endl;
+		}
+	}
+
+	XFontSetExtents* extents = XExtentsOfFontSet(fontset);
+
+	width = extents->max_ink_extent.width;
+	height = extents->max_ink_extent.height;
+
+	/* calculate ascent / descent */
+	XFontStruct** font_structs; char** font_names;
+	int num_fonts = XFontsOfFontSet(fontset, &font_structs, &font_names);
+printf("locale %s\n",XLocaleOfOM(XOMOfOC(fontset)));
+
+	ascent = 0;
+	for (i=0; i<num_fonts; i++) {
+		ascent = MAX(ascent, font_structs[i]->ascent);
+	}
+	
+	/* 描画用の pixmap を作成 */
+	XGCValues gc_values; unsigned int gc_values_mask;
+	gc_values.function = GXcopy;
+	gc_values.fill_style = FillSolid;
+	gc_values.arc_mode = ArcPieSlice;
+	gc_values.subwindow_mode = ClipByChildren;
+	gc_values.graphics_exposures = False;
+	gc_values.foreground = white;
+	gc_values.background = black;
+	gc_values_mask = GCFunction | GCFillStyle | GCArcMode | GCSubwindowMode | GCGraphicsExposures | GCForeground | GCBackground;
+	gc = XCreateGC(display, w, gc_values_mask, &gc_values);
+
+	canvas = XCreatePixmap(display, w, width, height, DefaultDepth(display, scr));
+
+	/* イメージ転送用の image の作成 */
+	int ignore;
+	use_shm = false;
+	if (XShmQueryExtension(display) == True) {
+		x_shm_info.shmid = -1;
+		x_shm_info.shmaddr = (char*)-1;
+		image = XShmCreateImage(display, visual, DefaultDepth(display, scr), ZPixmap, NULL, &x_shm_info, width, height);
+		if (image) {
+			x_shm_info.shmid = shmget(IPC_PRIVATE, image->bytes_per_line*image->height, IPC_CREAT | 0600);
+			if (x_shm_info.shmid == -1) {
+				XDestroyImage(image);
+				image = 0;
+				goto no_shm;
+			}
+			x_shm_info.readOnly = False;
+			x_shm_info.shmaddr = (char*) shmat(x_shm_info.shmid, 0, 0);
+			image->data = x_shm_info.shmaddr;
+			if (x_shm_info.shmaddr == (char*) -1) {
+				XDestroyImage(image);
+				shmctl(x_shm_info.shmid, IPC_RMID, 0);
+				image = 0;
+				goto no_shm;
+			}
+			XShmAttach(display, &x_shm_info);
+			XSync(display, False);
+			shmctl(x_shm_info.shmid, IPC_RMID, 0);
+			use_shm = true;
+		}
+	}
+no_shm:
+	if (image == 0) {
+		use_shm = false;
+		image = XCreateImage(display, visual, DefaultDepth(display, scr), ZPixmap, 0, 0, width, height, 32, 0);
+		image->data = (char*)malloc(image->bytes_per_line * image->height);
+		if (image->data == 0) {
+			XDestroyImage(image);
+			image = 0;
+			throw bad_alloc();
+		}
+	}
+Glyph g;
+GlyphCreate(0xa1a2,&g);
+GlyphCreate(0xa4a3,&g);
+}
+
+PeerX11::~PeerX11() {
+	if (display) {
+		if (fontset) XFreeFontSet(display, fontset);
+		if (gc) XFlushGC(display, gc);
+		if (canvas) XFreePixmap(display, canvas);
+		if (image) {
+			if (use_shm) XShmDetach(display, &x_shm_info);
+			XDestroyImage(image);
+			if (use_shm) shmdt(x_shm_info.shmaddr);
+		}
+		if (colortable) delete[] colortable;
+	}
+}
+
+bool PeerX11::GlyphCreate(unsigned int code, Glyph* glyph) {
+	XRectangle ink, logic;
+
+	char str[3]={0,0,0};
+
+	if ( (code>>8)&0xff){
+		str[0]=code>>8;
+		str[1]=code & 0xff;
+	} else {
+		str[0]=code;
+	}
+
+	XmbTextExtents(fontset, str, strlen(str),&ink,&logic);
+	int cwidth = logic.width;
+	XmbDrawImageString(display, canvas, fontset, gc, 0, -logic.y, str, strlen(str));
+	if (use_shm) {
+		XShmGetImage(display, canvas, image, 0, 0, AllPlanes);
+	} else {
+		XGetSubImage(display, canvas, 0, 0, width, height, AllPlanes, ZPixmap, image, 0, 0);
+	}
+	XSync(display, False);
+	glyph->bitmap.buffer = new unsigned char[logic.width*logic.height];
+	int i;
+	unsigned char* mem = (unsigned char*) image->data;
+	unsigned char* dest = glyph->bitmap.buffer;
+	int bpp = image->bytes_per_line/width;
+	int bpl = image->bytes_per_line;
+	for (i=0; i<logic.height; i++) {
+		unsigned char* m = mem;
+		int j; for (j=0; j<cwidth; j++) {
+			*dest = colortable[((read_little_endian_int((char*)m))>>shift) & mask];
+			dest++;
+			m += bpp;
+		}
+		mem += bpl;
+	}
+	glyph->bitmap_left = logic.x;
+	glyph->bitmap_top  = -logic.y;
+	glyph->bitmap.width = logic.width;
+	glyph->bitmap.rows = logic.height;
+	glyph->advance.x = logic.width + 1;
+	glyph->advance.y = logic.height+ 1;
+
+	return true;
+}
+};
+
+#endif /* USE_X11 */
new file mode 100644
--- /dev/null
+++ b/font/text.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2004  Kazunori "jagarl" Ueno
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __TEXT_H__
+#define __TEXT_H__
+
+#include<vector>
+#include<string>
+
+struct TextElem {
+	typedef enum {glyph, escape, color, size} ElemType;
+	typedef enum { ret, pos_reset, name_start, name_end, ruby_start, ruby_startruby, ruby_end} EscapeType;
+	ElemType type;
+	union Impl {
+		struct {
+			int code;
+		} Glyph;
+		struct {
+			EscapeType type;
+		} Escape;
+		struct {
+			unsigned char r, g, b;
+		} Color;
+		struct {
+			float scale;
+		} Size;
+	} impl;
+};
+			
+struct TextStream {
+	std::vector<TextElem> container;
+	typedef std::vector<TextElem>::iterator Iterator;
+	enum {sjis, euc} kanji_type;
+
+	std::string Save(void);
+	void Load(const std::string&);
+
+	void SetSize(double size);
+	void SetColor(unsigned char r, unsigned char g, unsigned char b);
+	void SetDefaultColor(unsigned char r, unsigned char g, unsigned char b);
+	void InsertColor(int begin_pos, int end_pos, unsigned char r, unsigned char g, unsigned char b);
+	void Clear(void);
+	void Add(const char* str);
+	void AddReturn(void);
+	void AddName(const char* name);
+	void AddRuby(const char* str, const char* ruby);
+
+	void RemoveName(char* name, int namelen);
+
+	TextStream(void);
+	TextStream& operator =(const TextStream& from) {
+		container = from.container;
+		kanji_type = from.kanji_type;
+		return *this;
+	}
+};
+
+namespace XKFont {
+	class Glyph;
+	class Font;
+};
+
+struct TextGlyph {
+	int x,y;
+	enum Flag { Group = 1, LineEnd = 2, Kinsoku = 4, PhraseEnd = 8} flag;
+	unsigned char r, g, b;
+	bool is_rev;
+	XKFont::Glyph* glyph;
+};
+
+struct TextGlyphStream : public std::vector<TextGlyph> {
+	XKFont::Font* font;
+	int width(void);
+	int height(void);
+	void SetColor(int r, int g, int b);
+	void SetReverse(bool rev);
+};
+
+#endif /* __TEXT_H__ */
new file mode 100644
--- /dev/null
+++ b/font/text_stream.cc
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2004  Kazunori "jagarl" Ueno
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "text.h"
+#include "codeconv.h"
+#include<stdio.h>
+
+/************************************************************************
+**
+**	TextStream
+**
+*/
+
+TextStream::TextStream(void) {
+	kanji_type = euc;
+}
+void TextStream::SetSize(double scale) {
+	TextElem elem;
+	elem.type = TextElem::size;
+	elem.impl.Size.scale = scale;
+	container.push_back(elem);
+}
+void TextStream::SetColor(unsigned char r, unsigned char g, unsigned char b) {
+	TextElem elem;
+	elem.type = TextElem::color;
+	elem.impl.Color.r = r;
+	elem.impl.Color.g = g;
+	elem.impl.Color.b = b;
+	container.push_back(elem);
+}
+void TextStream::InsertColor(int begin_pos, int end_pos, unsigned char r, unsigned char g, unsigned char b) {
+	TextElem elem;
+	if (begin_pos < 0) begin_pos = 0;
+	if (begin_pos > container.size()) begin_pos = container.size();
+	if (end_pos < 0) end_pos = 0;
+	if (end_pos > container.size()) end_pos = container.size();
+	if (begin_pos >= end_pos) return;
+
+	elem.type = TextElem::color;
+	elem.impl.Color.r = 255;
+	elem.impl.Color.g = 255;
+	elem.impl.Color.b = 255;
+	container.insert(container.begin()+end_pos, elem);
+	elem.impl.Color.r = r;
+	elem.impl.Color.g = g;
+	elem.impl.Color.b = b;
+	container.insert(container.begin()+begin_pos, elem);
+	Iterator it = container.begin()+begin_pos+1;
+	Iterator end = container.begin()+end_pos+1;
+	for (; it != end; it++) {
+		if (it->type == TextElem::color) {
+			TextElem& elem = *it;
+			if (elem.impl.Color.r == 255 && elem.impl.Color.g == 255 && elem.impl.Color.b == 255) {
+				elem.impl.Color.r = r;
+				elem.impl.Color.g = g;
+				elem.impl.Color.b = b;
+			}
+		}
+	}
+}
+void TextStream::Clear(void) {
+	container.clear();
+}
+void TextStream::Add(const char* str) {
+	TextElem elem;
+	for (; *str; str++) {
+		if (*str >= 0x20) {
+			elem.type = TextElem::glyph;
+			elem.impl.Glyph.code = *str;
+		} else if (*str < 0 && str[1] != 0) {
+			elem.type = TextElem::glyph;
+			elem.impl.Glyph.code = ((int(*(unsigned char*)str))<<8) | int(*(unsigned char*)(str+1));
+			if (kanji_type == sjis) elem.impl.Glyph.code = codeconv_sjis_to_euc(elem.impl.Glyph.code);
+			str++;
+		} else {
+			continue;
+		}
+		container.push_back(elem);
+	}
+}
+void TextStream::AddReturn(void) {
+	TextElem elem;
+	elem.type = TextElem::escape;
+	elem.impl.Escape.type = TextElem::ret;
+	container.push_back(elem);
+}
+void TextStream::AddName(const char* str) {
+	TextElem elem;
+	elem.type = TextElem::escape;
+	elem.impl.Escape.type = TextElem::name_start;
+	container.push_back(elem);
+	Add(str);
+	elem.impl.Escape.type = TextElem::name_end;
+	container.push_back(elem);
+}
+
+void TextStream::AddRuby(const char* str, const char* ruby) {
+	TextElem elem;
+	elem.type = TextElem::escape;
+	elem.impl.Escape.type = TextElem::ruby_start;
+	container.push_back(elem);
+	Add(str);
+	elem.impl.Escape.type = TextElem::ruby_startruby;
+	container.push_back(elem);
+	Add(ruby);
+	elem.impl.Escape.type = TextElem::ruby_end;
+	container.push_back(elem);
+}
+
+void TextStream::RemoveName(char* name, int namelen) {
+	Iterator it;
+	for (it = container.begin(); it != container.end(); it++) {
+		if (it->type == TextElem::escape && it->impl.Escape.type == TextElem::name_start) {
+			// 行頭の名前?
+			int pt = it - container.begin();
+			Iterator name_start = it;
+			for (; it != container.end(); it++) {
+				if (it->type == TextElem::escape && it->impl.Escape.type == TextElem::name_end) break;
+			}
+			if (it != container.end()) {
+				// 名前が見つかったので削除
+				if (name) { // 保存先があるなら保存する
+					Iterator name_end = it;
+					int pos = 0;
+					namelen--;
+					for (it=name_start; it != name_end; it++) {
+						if (it->type == TextElem::glyph) {
+							unsigned int code = it->impl.Glyph.code;
+							if (code < 0x100) {
+								if (pos < namelen) name[pos++] = code;
+							} else {
+								if (pos < namelen) name[pos++] = code>>8;
+								if (pos < namelen) name[pos++] = code;
+							}
+						}
+					}
+					name[pos] = 0;
+					name = 0; // 最初に出た名前のみ保存する
+				}
+				it++;
+				container.erase(name_start, it);
+				it = container.begin() + pt;
+			}
+		}
+		for (;it != container.end(); it++) {
+			if (it->type == TextElem::escape && it->impl.Escape.type == TextElem::ret) break;
+		}
+		if (it == container.end()) break;
+	}
+}
+
+/************************************************************************
+**
+**	TextStream::Save
+**
+*/
+
+/* escape sequence : '=XX' ; x < 0x30 || 'x>0x39 && x<0x40' (symbols) */
+/*  !"#$%&'()*+,-./:;<=>? */
+
+void TextStream::Load(const std::string& from_s) {
+	/* kigou :  !"#$%&'()*+,-./:;<=>? */
+	const char* s = from_s.c_str();
+	container.clear();
+	if (*s == '=' && *s == 'e') {kanji_type = euc; s+=2;}
+
+	TextElem e;
+	while(s && *s) {
+		e.type = TextElem::glyph;
+		if (*s == '=') {
+			if (s[1] >= 'A' && s[1] <= 'Q' && s[2] >= 'A' && s[2] <= 'Q') { // symbols
+				e.type = TextElem::glyph;
+				e.impl.Glyph.code = (s[1]-'A')*16 + (s[2]-'A');
+				s += 3;
+			} else if (s[1] == 'x') {
+				e.type = TextElem::escape;
+				e.impl.Escape.type = TextElem::EscapeType(s[2]-'A');
+				s += 3;
+			} else if (s[1] == 'c') {
+				int c;
+				e.type = TextElem::color;
+				sscanf(s+2, "%x", &c);
+				e.impl.Color.r = (c>>16)&0xff;
+				e.impl.Color.g = (c>>8)&0xff;
+				e.impl.Color.b = (c)&0xff;
+				s = strchr(s, '.');
+				if (s) s++;
+			} else if (s[1] == 's') {
+				e.impl.Size.scale = TextElem::size;
+				sscanf(s+2, "%f", &e.impl.Size.scale);
+				s = strchr(s, '.');
+				if (s) s++;
+			} else {
+				fprintf(stderr,"TextStream::Load(): Cannot convert text-stream from Serialized-data\n");
+				s++;
+			}
+		} else {
+			if (*s < 0) { // kanji-code
+				if (s[1] == 0) break;
+				if (s[1] >= 0 && s[1] < 0x40) break; // not EUC nor SJIS
+				e.type = TextElem::glyph;
+				e.impl.Glyph.code = codeconv_sjis_to_euc(int(*(unsigned char*)(s))*0x100 + int(*(unsigned char*)(s+1)));
+				s += 2;
+			} else { // ascii-code
+				if (s[0] < 0x30) break; // must be escaped
+				if (s[0] > 0x39 && s[0] < 0x40) break; // must be escaped
+				e.type = TextElem::glyph;
+				e.impl.Glyph.code = s[0];
+				s++;
+			}
+		}
+		container.push_back(e);
+	}
+}
+
+std::string TextStream::Save(void) {
+	/* kigou :  !"#$%&'()*+,-./:;<=>? */
+	Iterator it;
+	std::string ret_s;
+	char buf_orig[1024];
+	char* buf = buf_orig;
+	for (it=container.begin(); it != container.end(); it++) {
+		TextElem& e = *it;
+		switch(e.type) {
+		case TextElem::glyph: {
+			int code = e.impl.Glyph.code;
+			if (code < 0x30 || (code > 0x39 && code < 0x40)) {
+				*buf++ = '=';
+				*buf++ = (code/0x10) + 'A';
+				*buf++ = (code%0x10) + 'A';
+			} else {
+				code = codeconv_euc_to_sjis(code); // save file の漢字コードはSJIS
+				*buf++ = code/256;
+				*buf++ = code%256;
+			}
+			break;
+			}
+		case TextElem::escape:
+			sprintf(buf, "=x%c", e.impl.Escape.type+'A');
+			buf += 3;
+			break;
+		case TextElem::color:
+			sprintf(buf, "=c%x.",int(e.impl.Color.r)*256*256+int(e.impl.Color.g)*256+e.impl.Color.b);
+			buf += strlen(buf);
+			break;
+		case TextElem::size:
+			sprintf(buf, "=s%f.", e.impl.Size.scale);
+			buf += strlen(buf);
+			break;
+		}
+		if (buf-buf_orig > 1000) {
+			*buf = 0;
+			ret_s += buf_orig;
+			buf = buf_orig;
+		}
+	}
+	*buf = 0;
+	ret_s += buf_orig;
+	buf = buf_orig;
+	return ret_s;
+}
+
+/************************************************************************
+**
+**	TextGlyphStream
+**
+*/
+
+void TextGlyphStream::SetColor(int r, int g, int b) {
+	iterator it;
+	for (it=begin(); it != end(); it++) {
+	//	if (it->r == 255 && it->g == 255 && it->b == 255) {
+			it->r = r;
+			it->g = g;
+			it->b = b;
+	//	}
+	}
+}
+void TextGlyphStream::SetReverse(bool is_rev) {
+	iterator it;
+	for (it=begin(); it != end(); it++) {
+		it->is_rev = is_rev;
+	}
+}
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/linux.m4
@@ -0,0 +1,344 @@
+dnl aclocal.m4 generated automatically by aclocal 1.4
+
+dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+dnl PARTICULAR PURPOSE.
+
+dnl Configure Paths for Alsa
+dnl Some modifications by Richard Boulton <richard-alsa@tartarus.org>
+dnl Christopher Lansdown <lansdoct@cs.alfred.edu>
+dnl Jaroslav Kysela <perex@suse.cz>
+dnl Last modification: $Id: alsa.m4,v 1.24 2004/09/15 18:48:07 tiwai Exp $
+dnl AM_PATH_ALSA([MINIMUM-VERSION [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl Test for libasound, and define ALSA_CFLAGS and ALSA_LIBS as appropriate.
+dnl enables arguments --with-alsa-prefix=
+dnl                   --with-alsa-enc-prefix=
+dnl                   --disable-alsatest
+dnl
+dnl For backwards compatibility, if ACTION_IF_NOT_FOUND is not specified,
+dnl and the alsa libraries are not found, a fatal AC_MSG_ERROR() will result.
+dnl
+AC_DEFUN([AM_PATH_ALSA],
+[dnl Save the original CFLAGS, LDFLAGS, and LIBS
+alsa_save_CFLAGS="$CFLAGS"
+alsa_save_LDFLAGS="$LDFLAGS"
+alsa_save_LIBS="$LIBS"
+alsa_found=yes
+
+dnl
+dnl Get the cflags and libraries for alsa
+dnl
+AC_ARG_WITH(alsa-prefix,
+[  --with-alsa-prefix=PFX  Prefix where Alsa library is installed(optional)],
+[alsa_prefix="$withval"], [alsa_prefix=""])
+
+AC_ARG_WITH(alsa-inc-prefix,
+[  --with-alsa-inc-prefix=PFX  Prefix where include libraries are (optional)],
+[alsa_inc_prefix="$withval"], [alsa_inc_prefix=""])
+
+dnl FIXME: this is not yet implemented
+AC_ARG_ENABLE(alsatest,
+[  --disable-alsatest      Do not try to compile and run a test Alsa program],
+[enable_alsatest="$enableval"],
+[enable_alsatest=yes])
+
+dnl Add any special include directories
+AC_MSG_CHECKING(for ALSA CFLAGS)
+if test "$alsa_inc_prefix" != "" ; then
+	ALSA_CFLAGS="$ALSA_CFLAGS -I$alsa_inc_prefix"
+	CFLAGS="$CFLAGS -I$alsa_inc_prefix"
+fi
+AC_MSG_RESULT($ALSA_CFLAGS)
+CFLAGS="$alsa_save_CFLAGS"
+
+dnl add any special lib dirs
+AC_MSG_CHECKING(for ALSA LDFLAGS)
+if test "$alsa_prefix" != "" ; then
+	ALSA_LIBS="$ALSA_LIBS -L$alsa_prefix"
+	LDFLAGS="$LDFLAGS $ALSA_LIBS"
+fi
+
+dnl add the alsa library
+ALSA_LIBS="$ALSA_LIBS -lasound -lm -ldl -lpthread"
+LIBS="$ALSA_LIBS $LIBS"
+AC_MSG_RESULT($ALSA_LIBS)
+
+dnl Check for a working version of libasound that is of the right version.
+min_alsa_version=ifelse([$1], ,0.1.1,$1)
+AC_MSG_CHECKING(for libasound headers version >= $min_alsa_version)
+no_alsa=""
+    alsa_min_major_version=`echo $min_alsa_version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+    alsa_min_minor_version=`echo $min_alsa_version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+    alsa_min_micro_version=`echo $min_alsa_version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+
+AC_LANG_SAVE
+AC_LANG_C
+AC_TRY_COMPILE([
+#include <alsa/asoundlib.h>
+], [
+/* ensure backward compatibility */
+#if !defined(SND_LIB_MAJOR) && defined(SOUNDLIB_VERSION_MAJOR)
+#define SND_LIB_MAJOR SOUNDLIB_VERSION_MAJOR
+#endif
+#if !defined(SND_LIB_MINOR) && defined(SOUNDLIB_VERSION_MINOR)
+#define SND_LIB_MINOR SOUNDLIB_VERSION_MINOR
+#endif
+#if !defined(SND_LIB_SUBMINOR) && defined(SOUNDLIB_VERSION_SUBMINOR)
+#define SND_LIB_SUBMINOR SOUNDLIB_VERSION_SUBMINOR
+#endif
+
+#  if(SND_LIB_MAJOR > $alsa_min_major_version)
+  exit(0);
+#  else
+#    if(SND_LIB_MAJOR < $alsa_min_major_version)
+#       error not present
+#    endif
+
+#   if(SND_LIB_MINOR > $alsa_min_minor_version)
+  exit(0);
+#   else
+#     if(SND_LIB_MINOR < $alsa_min_minor_version)
+#          error not present
+#      endif
+
+#      if(SND_LIB_SUBMINOR < $alsa_min_micro_version)
+#        error not present
+#      endif
+#    endif
+#  endif
+exit(0);
+],
+  [AC_MSG_RESULT(found.)],
+  [AC_MSG_RESULT(not present.)
+   ifelse([$3], , [AC_MSG_ERROR(Sufficiently new version of libasound not found.)])
+   alsa_found=no]
+)
+AC_LANG_RESTORE
+
+dnl Now that we know that we have the right version, let's see if we have the library and not just the headers.
+if test "x$enable_alsatest" = "xyes"; then
+AC_CHECK_LIB([asound], [snd_ctl_open],,
+	[ifelse([$3], , [AC_MSG_ERROR(No linkable libasound was found.)])
+	 alsa_found=no]
+)
+fi
+
+LDFLAGS="$alsa_save_LDFLAGS"
+LIBS="$alsa_save_LIBS"
+
+if test "x$alsa_found" = "xyes" ; then
+   ifelse([$2], , :, [$2])
+else
+   ALSA_CFLAGS=""
+   ALSA_LIBS=""
+   ifelse([$3], , :, [$3])
+fi
+
+dnl That should be it.  Now just export out symbols:
+AC_SUBST(ALSA_CFLAGS)
+AC_SUBST(ALSA_LIBS)
+])
+
+# Configure paths for ESD
+# Manish Singh    98-9-30
+# stolen back from Frank Belew
+# stolen from Manish Singh
+# Shamelessly stolen from Owen Taylor
+
+dnl AM_PATH_ESD([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl Test for ESD, and define ESD_CFLAGS and ESD_LIBS
+dnl
+AC_DEFUN([AM_PATH_ESD],
+[dnl 
+dnl Get the cflags and libraries from the esd-config script
+dnl
+AC_ARG_WITH(esd-prefix,[  --with-esd-prefix=PFX   Prefix where ESD is installed (optional)],
+            esd_prefix="$withval", esd_prefix="")
+AC_ARG_WITH(esd-exec-prefix,[  --with-esd-exec-prefix=PFX Exec prefix where ESD is installed (optional)],
+            esd_exec_prefix="$withval", esd_exec_prefix="")
+AC_ARG_ENABLE(esdtest, [  --disable-esdtest       Do not try to compile and run a test ESD program],
+		    , enable_esdtest=yes)
+
+  if test x$esd_exec_prefix != x ; then
+     esd_args="$esd_args --exec-prefix=$esd_exec_prefix"
+     if test x${ESD_CONFIG+set} != xset ; then
+        ESD_CONFIG=$esd_exec_prefix/bin/esd-config
+     fi
+  fi
+  if test x$esd_prefix != x ; then
+     esd_args="$esd_args --prefix=$esd_prefix"
+     if test x${ESD_CONFIG+set} != xset ; then
+        ESD_CONFIG=$esd_prefix/bin/esd-config
+     fi
+  fi
+
+  AC_PATH_PROG(ESD_CONFIG, esd-config, no)
+  min_esd_version=ifelse([$1], ,0.2.7,$1)
+  AC_MSG_CHECKING(for ESD - version >= $min_esd_version)
+  no_esd=""
+  if test "$ESD_CONFIG" = "no" ; then
+    no_esd=yes
+  else
+    AC_LANG_SAVE
+    AC_LANG_C
+    ESD_CFLAGS=`$ESD_CONFIG $esdconf_args --cflags`
+    ESD_LIBS=`$ESD_CONFIG $esdconf_args --libs`
+
+    esd_major_version=`$ESD_CONFIG $esd_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+    esd_minor_version=`$ESD_CONFIG $esd_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+    esd_micro_version=`$ESD_CONFIG $esd_config_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+    if test "x$enable_esdtest" = "xyes" ; then
+      ac_save_CFLAGS="$CFLAGS"
+      ac_save_LIBS="$LIBS"
+      CFLAGS="$CFLAGS $ESD_CFLAGS"
+      LIBS="$LIBS $ESD_LIBS"
+dnl
+dnl Now check if the installed ESD is sufficiently new. (Also sanity
+dnl checks the results of esd-config to some extent
+dnl
+      rm -f conf.esdtest
+      AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <esd.h>
+
+char*
+my_strdup (char *str)
+{
+  char *new_str;
+  
+  if (str)
+    {
+      new_str = malloc ((strlen (str) + 1) * sizeof(char));
+      strcpy (new_str, str);
+    }
+  else
+    new_str = NULL;
+  
+  return new_str;
+}
+
+int main ()
+{
+  int major, minor, micro;
+  char *tmp_version;
+
+  system ("touch conf.esdtest");
+
+  /* HP/UX 9 (%@#!) writes to sscanf strings */
+  tmp_version = my_strdup("$min_esd_version");
+  if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3) {
+     printf("%s, bad version string\n", "$min_esd_version");
+     exit(1);
+   }
+
+   if (($esd_major_version > major) ||
+      (($esd_major_version == major) && ($esd_minor_version > minor)) ||
+      (($esd_major_version == major) && ($esd_minor_version == minor) && ($esd_micro_version >= micro)))
+    {
+      return 0;
+    }
+  else
+    {
+      printf("\n*** 'esd-config --version' returned %d.%d.%d, but the minimum version\n", $esd_major_version, $esd_minor_version, $esd_micro_version);
+      printf("*** of ESD required is %d.%d.%d. If esd-config is correct, then it is\n", major, minor, micro);
+      printf("*** best to upgrade to the required version.\n");
+      printf("*** If esd-config was wrong, set the environment variable ESD_CONFIG\n");
+      printf("*** to point to the correct copy of esd-config, and remove the file\n");
+      printf("*** config.cache before re-running configure\n");
+      return 1;
+    }
+}
+
+],, no_esd=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+       AC_LANG_RESTORE
+     fi
+  fi
+  if test "x$no_esd" = x ; then
+     AC_MSG_RESULT(yes)
+     ifelse([$2], , :, [$2])     
+  else
+     AC_MSG_RESULT(no)
+     if test "$ESD_CONFIG" = "no" ; then
+       echo "*** The esd-config script installed by ESD could not be found"
+       echo "*** If ESD was installed in PREFIX, make sure PREFIX/bin is in"
+       echo "*** your path, or set the ESD_CONFIG environment variable to the"
+       echo "*** full path to esd-config."
+     else
+       if test -f conf.esdtest ; then
+        :
+       else
+          echo "*** Could not run ESD test program, checking why..."
+          CFLAGS="$CFLAGS $ESD_CFLAGS"
+          LIBS="$LIBS $ESD_LIBS"
+          AC_LANG_SAVE
+          AC_LANG_C
+          AC_TRY_LINK([
+#include <stdio.h>
+#include <esd.h>
+],      [ return 0; ],
+        [ echo "*** The test program compiled, but did not run. This usually means"
+          echo "*** that the run-time linker is not finding ESD or finding the wrong"
+          echo "*** version of ESD. If it is not finding ESD, you'll need to set your"
+          echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+          echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+          echo "*** is required on your system"
+	  echo "***"
+          echo "*** If you have an old version installed, it is best to remove it, although"
+          echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+        [ echo "*** The test program failed to compile or link. See the file config.log for the"
+          echo "*** exact error that occured. This usually means ESD was incorrectly installed"
+          echo "*** or that you have moved ESD since it was installed. In the latter case, you"
+          echo "*** may want to edit the esd-config script: $ESD_CONFIG" ])
+          CFLAGS="$ac_save_CFLAGS"
+          LIBS="$ac_save_LIBS"
+          AC_LANG_RESTORE
+       fi
+     fi
+     ESD_CFLAGS=""
+     ESD_LIBS=""
+     ifelse([$3], , :, [$3])
+  fi
+  AC_SUBST(ESD_CFLAGS)
+  AC_SUBST(ESD_LIBS)
+  rm -f conf.esdtest
+])
+
+dnl AM_ESD_SUPPORTS_MULTIPLE_RECORD([ACTION-IF-SUPPORTS [, ACTION-IF-NOT-SUPPORTS]])
+dnl Test, whether esd supports multiple recording clients (version >=0.2.21)
+dnl
+AC_DEFUN([AM_ESD_SUPPORTS_MULTIPLE_RECORD],
+[dnl
+  AC_MSG_NOTICE([whether installed esd version supports multiple recording clients])
+  ac_save_ESD_CFLAGS="$ESD_CFLAGS"
+  ac_save_ESD_LIBS="$ESD_LIBS"
+  AM_PATH_ESD(0.2.21,
+    ifelse([$1], , [
+      AM_CONDITIONAL(ESD_SUPPORTS_MULTIPLE_RECORD, true)
+      AC_DEFINE(ESD_SUPPORTS_MULTIPLE_RECORD, 1,
+	[Define if you have esound with support of multiple recording clients.])],
+    [$1]),
+    ifelse([$2], , [AM_CONDITIONAL(ESD_SUPPORTS_MULTIPLE_RECORD, false)], [$2])
+    if test "x$ac_save_ESD_CFLAGS" != x ; then
+       ESD_CFLAGS="$ac_save_ESD_CFLAGS"
+    fi
+    if test "x$ac_save_ESD_LIBS" != x ; then
+       ESD_LIBS="$ac_save_ESD_LIBS"
+    fi
+  )
+])
new file mode 100644
--- /dev/null
+++ b/music2/Makefile.in
@@ -0,0 +1,33 @@
+# Linux でPCMのドライバとして OSS を使用する場合、は -DUSE_OSS が必要
+
+# OSS 以外にも ALSA(Advanced Linux Sound Architecture) と ESD(Enligtenment Sound Daemon)も
+# 動くと思われるが、未テスト。その辺についてはxsystem35 の README.music を参照。
+
+CFLAGS= -I.. $(LOCAL_DEF) @CFLAGS@ @DEFS@ @SDL_CFLAGS@ -pthread -O2 # -ggdb -O0
+CXXFLAGS	= $(CFLAGS)
+
+@SET_MAKE@
+CC              = @CC@
+CXX             = @CXX@
+LD              = @CXX@
+AR              = ar
+RANLIB          = @RANLIB@
+
+all: libmusic.a nwatowav
+
+@AUDIO_IO@.o: @AUDIO_IO@.c @ALSAMIX_H@
+
+libmusic.a: config.h music.o koedec.o koedec_ogg.o wavfile.o movie.o nwatowav.o
+	rm -f libmusic.a
+	$(AR) clq libmusic.a music.o koedec.o koedec_ogg.o wavfile.o movie.o nwatowav.o
+	$(RANLIB) libmusic.a
+
+nwatowav: nwatowav.cc
+	$(LD) -o nwatowav -DUSE_MAIN nwatowav.cc
+
+config.h:
+	ln -s ../config.h .
+
+clean:
+	rm -f *.o *.a *.core *.bak config.h nwatowav
+
new file mode 100644
--- /dev/null
+++ b/music2/koedec.cc
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 2004-2006  Kazunori "jagarl" Ueno
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include<stdio.h>
+#include<stdlib.h>
+#include<string.h>
+#include <vector>
+#include <list>
+#include <algorithm>
+#include"music.h"
+#include"system/file.h"
+
+using namespace std;
+
+/*********************************************
+**
+**	FindKoe -- RealLiveの音声アーカイブ処理
+**
+*/
+
+/* 声ファイルのアーカイブ用のキャッシュ */
+#define koe_cache_size 7
+struct AvgKoeTable {
+	int koe_num;
+	int length;
+	int offset;
+	AvgKoeTable(int _num, int _len, int _off) :
+		koe_num(_num), length(_len), offset(_off) {}
+	bool operator <(int number) const {
+		return koe_num < number;
+	}
+	bool operator <(const AvgKoeTable& to) const {
+		return koe_num < to.koe_num;
+	}
+	bool operator ==(const AvgKoeTable& to) const {
+		return koe_num == to.koe_num;
+	}
+	bool operator ==(const int to) const {
+		return koe_num == to;
+	}
+};
+struct AvgKoeHead {
+	FILE* stream;
+	int file_number;
+	int rate;
+	KoeType type;
+	vector<AvgKoeTable> table;
+	AvgKoeHead(FILE* stream, int file_number, KoeType type);
+	AvgKoeHead(const AvgKoeHead& from);
+	~AvgKoeHead();
+	AvgKoeTable* Find(int koe_num);
+	bool operator !=(int num) const { return file_number != num; }
+	bool operator ==(int num) const { return file_number == num; }
+};
+struct AvgKoeCache {
+	list<AvgKoeHead> cache;
+	AvgKoeInfo Find(int file_number, int index);
+};
+static AvgKoeCache koe_cache;
+
+AvgKoeInfo FindKoe(int file_number, int index) {
+	return koe_cache.Find(file_number, index);
+};
+
+AvgKoeInfo AvgKoeCache::Find(int file_number, int index) {
+	AvgKoeInfo info;
+	info.stream = 0; info.length = 0; info.offset = 0;
+
+	list<AvgKoeHead>::iterator it;
+	it = find(cache.begin(), cache.end(), file_number);
+	if (it == cache.end()) {
+		/* 新たに head を作る */
+		char fname[100];
+		KoeType type = koe_unknown;
+		sprintf(fname, "z%03d.koe", file_number);
+		ARCINFO* arcinfo = file_searcher.Find(FILESEARCH::KOE,fname,".koe");
+		if (arcinfo == 0) {
+			type = koe_nwk;
+			sprintf(fname, "z%04d.nwk", file_number);
+			arcinfo = file_searcher.Find(FILESEARCH::KOE,fname,".nwk");
+		}
+		if (arcinfo == 0) {
+			type = koe_ovk;
+			sprintf(fname, "z%04d.ovk", file_number);
+			arcinfo = file_searcher.Find(FILESEARCH::KOE,fname,".ovk");
+		}
+		if (arcinfo == 0) return info;
+		FILE* stream = arcinfo->OpenFile();
+		delete arcinfo;
+		if (stream == 0) return info;
+		cache.push_front(AvgKoeHead(stream, file_number, type));
+		if (cache.size() >= koe_cache_size) cache.pop_back();
+		it = cache.begin();
+	}
+	if (it->file_number != file_number) return info; // 番号がおかしい
+	AvgKoeTable* table = it->Find(index);
+	if (table == 0) return info; // index が見付からない
+	// info を作成する
+	info.length = table->length;
+	info.offset = table->offset;
+	info.rate = it->rate;
+	info.type = it->type;
+	int new_fd = dup(fileno(it->stream));
+	if (new_fd == -1) info.stream = 0;
+	else info.stream = fdopen(new_fd, "rb");
+	return info;
+}
+
+AvgKoeHead::AvgKoeHead(const AvgKoeHead& from) {
+	if (from.stream) {
+		int new_fd = dup(fileno(from.stream));
+		if (new_fd == -1) stream = 0;
+		else stream = fdopen(new_fd, "rb");
+	}
+	file_number = from.file_number;
+	rate = from.rate;
+	table = from.table;
+	type = from.type;
+}
+AvgKoeHead::AvgKoeHead(FILE* _s, int _file_number, KoeType _type) {
+	char head[0x20];
+	stream = _s; file_number = _file_number;
+	int offset = ftell(stream);
+	rate = 22050;
+	type = _type;
+	if (stream == 0) return;
+	/* header 読み込み */
+	if (type == koe_nwk) { // 新しい形式 : .nwk file
+		rate = 44100;
+		fread(head, 4, 1, stream);
+		int table_len = read_little_endian_int(head);
+		table.reserve(table_len);
+		int i;
+		for (i=0; i<table_len; i++) {
+			fread(head, 12, 1, stream);
+			int sz = read_little_endian_int(head);
+			int off = read_little_endian_int(head+4);
+			int cnt = read_little_endian_int(head+8);
+			table.push_back(AvgKoeTable(cnt, sz, off));
+		}
+	} else if (type == koe_ovk) { // Little Busters! : .ovk file
+		rate = 44100;
+		fread(head, 4, 1, stream);
+		int table_len = read_little_endian_int(head);
+		table.reserve(table_len);
+		int i;
+		for (i=0; i<table_len; i++) {
+			fread(head, 16, 1, stream);
+			int sz = read_little_endian_int(head);
+			int off = read_little_endian_int(head+4);
+			int cnt = read_little_endian_int(head+8);
+			table.push_back(AvgKoeTable(cnt, sz, off));
+		}
+	} else { // .koe file
+		fread(head, 0x20, 1, stream);
+		if (strncmp(head, "KOEPAC", 7) != 0) { // invalid header
+			stream = 0;
+			return;
+		}
+		int table_len = read_little_endian_int(head+0x10);
+		rate = read_little_endian_int(head+0x18);
+		if (rate == 0) rate = 22050;
+		/* table 読み込み */
+		table.reserve(table_len);
+		char* buf = new char[table_len*8];
+		fread(buf, table_len, 8, stream);
+		int i; for (i=0; i<table_len; i++) {
+			int cnt = read_little_endian_short(buf+i*8);
+			int sz  = read_little_endian_short(buf+i*8+2);
+			int off = read_little_endian_int(buf+i*8+4);
+			table.push_back(AvgKoeTable(cnt, sz, off));
+		}
+	}
+	sort(table.begin(), table.end());
+}
+
+AvgKoeHead::~AvgKoeHead(void) {
+	if (stream) fclose(stream);
+	stream = 0;
+}
+AvgKoeTable* AvgKoeHead::Find(int koe_num) {
+	if (table.empty()) return 0;
+	vector<AvgKoeTable>::iterator it;
+	it = lower_bound(table.begin(), table.end(), koe_num);
+	if (it == table.end() || it->koe_num != koe_num) return 0;
+	return &table[it-table.begin()];
+}
+
+/*********************************************
+**
+**	MakeWavHeader : koe ファイルに wave header を付ける
+**
+*/
+
+static unsigned char orig_header[0x2c] = {
+	0x52, 0x49, 0x46, 0x46,	/* +00 "RIFF" */
+	0x00, 0x00, 0x00, 0x00, /* +04 file size - 8 */
+	0x57, 0x41, 0x56, 0x45, 0x66, 0x6d, 0x74, 0x20, /* +08 "WAVEfmt " */
+	0x10, 0x00, 0x00, 0x00, /* +10 fmt size */
+	0x01, 0x00,             /* +14 wFormatTag */
+	0x02, 0x00,             /* +16 Channels */
+	0x44, 0xac, 0x00, 0x00, /* +18 rate */
+	0x10, 0xb1, 0x02, 0x00, /* +1c BytesPerSec = rate * BlockAlign */
+	0x04, 0x00,             /* +20 BlockAlign = channels*BytesPerSample */
+	0x10, 0x00,             /* +22 BitsPerSample */
+	0x64, 0x61, 0x74, 0x61, /* +24 "data" */
+	0x00, 0x00, 0x00, 0x00  /* +28 filesize - 0x2c */
+};
+
+const char* MakeWavHeader(int rate, int ch, int bps, int size) {
+	static char header[0x2c];
+	memcpy(header, (const char*)orig_header, 0x2c);
+	write_little_endian_int(header+0x04, size-8);
+	write_little_endian_int(header+0x28, size-0x2c);
+	write_little_endian_int(header+0x18, rate);
+	write_little_endian_int(header+0x1c, rate*ch*bps);
+	header[0x16] = ch;
+	header[0x20] = ch*bps;
+	header[0x22] = bps*8;
+	return header;
+}
+
+/*********************************************
+**
+**	decode_koe -- 音声データ展開
+**
+*/
+
+extern char* decode_koe(AvgKoeInfo info, int* len);
+
+/* 8bit -> 16bit への変換テーブル。本来は signed short だが
+** とりあえず unsigned で扱っている
+*/
+
+unsigned short koe_8bit_trans_tbl[256] = {
+  0x8000,0x81ff,0x83f9,0x85ef,0x87e1,0x89cf,0x8bb9,0x8d9f,
+  0x8f81,0x915f,0x9339,0x950f,0x96e1,0x98af,0x9a79,0x9c3f,
+  0x9e01,0x9fbf,0xa179,0xa32f,0xa4e1,0xa68f,0xa839,0xa9df,
+  0xab81,0xad1f,0xaeb9,0xb04f,0xb1e1,0xb36f,0xb4f9,0xb67f,
+  0xb801,0xb97f,0xbaf9,0xbc6f,0xbde1,0xbf4f,0xc0b9,0xc21f,
+  0xc381,0xc4df,0xc639,0xc78f,0xc8e1,0xca2f,0xcb79,0xccbf,
+  0xce01,0xcf3f,0xd079,0xd1af,0xd2e1,0xd40f,0xd539,0xd65f,
+  0xd781,0xd89f,0xd9b9,0xdacf,0xdbe1,0xdcef,0xddf9,0xdeff,
+  0xe001,0xe0ff,0xe1f9,0xe2ef,0xe3e1,0xe4cf,0xe5b9,0xe69f,
+  0xe781,0xe85f,0xe939,0xea0f,0xeae1,0xebaf,0xec79,0xed3f,
+  0xee01,0xeebf,0xef79,0xf02f,0xf0e1,0xf18f,0xf239,0xf2df,
+  0xf381,0xf41f,0xf4b9,0xf54f,0xf5e1,0xf66f,0xf6f9,0xf77f,
+  0xf801,0xf87f,0xf8f9,0xf96f,0xf9e1,0xfa4f,0xfab9,0xfb1f,
+  0xfb81,0xfbdf,0xfc39,0xfc8f,0xfce1,0xfd2f,0xfd79,0xfdbf,
+  0xfe01,0xfe3f,0xfe79,0xfeaf,0xfee1,0xff0f,0xff39,0xff5f,
+  0xff81,0xff9f,0xffb9,0xffcf,0xffe1,0xffef,0xfff9,0xffff,
+  0x0000,0x0001,0x0007,0x0011,0x001f,0x0031,0x0047,0x0061,
+  0x007f,0x00a1,0x00c7,0x00f1,0x011f,0x0151,0x0187,0x01c1,
+  0x01ff,0x0241,0x0287,0x02d1,0x031f,0x0371,0x03c7,0x0421,
+  0x047f,0x04e1,0x0547,0x05b1,0x061f,0x0691,0x0707,0x0781,
+  0x07ff,0x0881,0x0907,0x0991,0x0a1f,0x0ab1,0x0b47,0x0be1,
+  0x0c7f,0x0d21,0x0dc7,0x0e71,0x0f1f,0x0fd1,0x1087,0x1141,
+  0x11ff,0x12c1,0x1387,0x1451,0x151f,0x15f1,0x16c7,0x17a1,
+  0x187f,0x1961,0x1a47,0x1b31,0x1c1f,0x1d11,0x1e07,0x1f01,
+  0x1fff,0x2101,0x2207,0x2311,0x241f,0x2531,0x2647,0x2761,
+  0x287f,0x29a1,0x2ac7,0x2bf1,0x2d1f,0x2e51,0x2f87,0x30c1,
+  0x31ff,0x3341,0x3487,0x35d1,0x371f,0x3871,0x39c7,0x3b21,
+  0x3c7f,0x3de1,0x3f47,0x40b1,0x421f,0x4391,0x4507,0x4681,
+  0x47ff,0x4981,0x4b07,0x4c91,0x4e1f,0x4fb1,0x5147,0x52e1,
+  0x547f,0x5621,0x57c7,0x5971,0x5b1f,0x5cd1,0x5e87,0x6041,
+  0x61ff,0x63c1,0x6587,0x6751,0x691f,0x6af1,0x6cc7,0x6ea1,
+  0x707f,0x7261,0x7447,0x7631,0x781f,0x7a11,0x7c07,0x7fff
+};
+
+/* ADPCM・・・じゃないらしい。ただのDPCMのナめたテーブル。
+** 自動生成すりゃいいんだけど256byteだったら
+** テーブルでも問題ないでしょ
+*/
+
+char koe_ad_trans_tbl[256] = {
+  0x00,0xff,0x01,0xfe,0x02,0xfd,0x03,0xfc,0x04,0xfb,0x05,0xfa,0x06,0xf9,0x07,0xf8,
+  0x08,0xf7,0x09,0xf6,0x0a,0xf5,0x0b,0xf4,0x0c,0xf3,0x0d,0xf2,0x0e,0xf1,0x0f,0xf0,
+  0x10,0xef,0x11,0xee,0x12,0xed,0x13,0xec,0x14,0xeb,0x15,0xea,0x16,0xe9,0x17,0xe8,
+  0x18,0xe7,0x19,0xe6,0x1a,0xe5,0x1b,0xe4,0x1c,0xe3,0x1d,0xe2,0x1e,0xe1,0x1f,0xe0,
+  0x20,0xdf,0x21,0xde,0x22,0xdd,0x23,0xdc,0x24,0xdb,0x25,0xda,0x26,0xd9,0x27,0xd8,
+  0x28,0xd7,0x29,0xd6,0x2a,0xd5,0x2b,0xd4,0x2c,0xd3,0x2d,0xd2,0x2e,0xd1,0x2f,0xd0,
+  0x30,0xcf,0x31,0xce,0x32,0xcd,0x33,0xcc,0x34,0xcb,0x35,0xca,0x36,0xc9,0x37,0xc8,
+  0x38,0xc7,0x39,0xc6,0x3a,0xc5,0x3b,0xc4,0x3c,0xc3,0x3d,0xc2,0x3e,0xc1,0x3f,0xc0,
+  0x40,0xbf,0x41,0xbe,0x42,0xbd,0x43,0xbc,0x44,0xbb,0x45,0xba,0x46,0xb9,0x47,0xb8,
+  0x48,0xb7,0x49,0xb6,0x4a,0xb5,0x4b,0xb4,0x4c,0xb3,0x4d,0xb2,0x4e,0xb1,0x4f,0xb0,
+  0x50,0xaf,0x51,0xae,0x52,0xad,0x53,0xac,0x54,0xab,0x55,0xaa,0x56,0xa9,0x57,0xa8,
+  0x58,0xa7,0x59,0xa6,0x5a,0xa5,0x5b,0xa4,0x5c,0xa3,0x5d,0xa2,0x5e,0xa1,0x5f,0xa0,
+  0x60,0x9f,0x61,0x9e,0x62,0x9d,0x63,0x9c,0x64,0x9b,0x65,0x9a,0x66,0x99,0x67,0x98,
+  0x68,0x97,0x69,0x96,0x6a,0x95,0x6b,0x94,0x6c,0x93,0x6d,0x92,0x6e,0x91,0x6f,0x90,
+  0x70,0x8f,0x71,0x8e,0x72,0x8d,0x73,0x8c,0x74,0x8b,0x75,0x8a,0x76,0x89,0x77,0x88,
+  0x78,0x87,0x79,0x86,0x7a,0x85,0x7b,0x84,0x7c,0x83,0x7d,0x82,0x7e,0x81,0x7f,0x80
+};
+
+extern int is_koe_ogg(char* head);
+extern char* decode_koe_ogg(AvgKoeInfo info, int* dest_len);
+
+char* decode_koe(AvgKoeInfo info, int* dest_len) {
+	char buf[1024]; char* table;
+	unsigned char* src_orig, *src;
+	unsigned short* dest_orig, *dest;
+	int all_len; int i,j;
+	if (info.stream == NULL) {
+		return NULL;
+	}
+	fseek(info.stream, info.offset, 0);
+	if (info.type == koe_nwk) {
+		return decode_koe_nwa(info, dest_len);
+	}
+	fread(buf, 1, 0x20, info.stream);
+	if (is_koe_ogg(buf)) {
+		fseek(info.stream, -20, 1);
+		return decode_koe_ogg(info, dest_len);
+	}
+	/* avg32 の声データ展開 */
+	table = (char*)malloc(info.length*2);
+	fseek(info.stream, info.offset, 0);
+	fread(table, 2, info.length, info.stream);
+
+	all_len = 0;
+	for (i=0; i<info.length; i++)
+		all_len += read_little_endian_short(table + i*2);
+	/* データ読み込み */
+	src_orig  = (unsigned char*) malloc(all_len);
+	dest_orig = (unsigned short*)malloc(info.length * 0x1000 + 0x2c);
+	if (src_orig == NULL || dest_orig == NULL) return NULL;
+	src = src_orig;
+	fread(src, 1, all_len, info.stream);
+	*dest_len = info.length * 0x400 * 4;
+	const char* header = MakeWavHeader(info.rate, 2, 2, *dest_len);
+	memcpy(dest_orig, header, 0x2c);
+	dest = dest_orig + 0x2c;
+	/* memset(dest_data, 0, table_len * 0x1000); */
+	
+	/* 展開 */
+	for (i=0; i<info.length; i++) {
+		int slen = read_little_endian_short(table+i*2);
+		if (slen == 0) { // do nothing
+			memset(dest, 0, 0x1000);
+			dest += 0x800; src += 0;
+		} else if (slen == 0x400) { // table 変換
+			for (j=0; j<0x400; j++) {
+				write_little_endian_short((char*)(dest+0), koe_8bit_trans_tbl[*src]);
+				write_little_endian_short((char*)(dest+1), koe_8bit_trans_tbl[*src]);
+				dest += 2; src++;
+			}
+		} else { // DPCM
+			char d = 0; short o2;
+			int k,j; for (j=0, k=0; j<slen && k < 0x800; j++) {
+				unsigned char s = src[j];
+				if ( (s+1) & 0x0f) {
+					d -= koe_ad_trans_tbl[s & 0x0f];
+				} else {
+					unsigned char s2;
+					s >>= 4; s &= 0x0f; s2 = s;
+					s = src[++j]; s2 |= (s<<4) & 0xf0;
+					d -= koe_ad_trans_tbl[s2];
+				}
+				o2 = koe_8bit_trans_tbl[ (unsigned char)d];
+				write_little_endian_short((char*)(dest+k), o2);
+				write_little_endian_short((char*)(dest+k+1), o2);
+				k+=2;
+				s >>= 4;
+				if ((s+1) & 0x0f) {
+					d -= koe_ad_trans_tbl[s & 0x0f];
+				} else {
+					d -= koe_ad_trans_tbl[ src[++j] ];
+				}
+				o2 = koe_8bit_trans_tbl[ (unsigned char)d];
+				write_little_endian_short((char*)(dest+k), o2);
+				write_little_endian_short((char*)(dest+k+1), o2);
+				k+=2;
+			}
+			dest += 0x800; src += slen;
+		}
+	}
+	free( (void*) table);
+	free( (void*) src_orig);
+	return (char*)dest_orig;
+}
+
+
new file mode 100644
--- /dev/null
+++ b/music2/koedec_ogg.cc
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2004-2006  Kazunori "jagarl" Ueno
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include<stdio.h>
+#include<string.h>
+#include<stdlib.h>
+#include"music.h"
+#include"wavfile.h"
+
+extern int is_koe_ogg(char* head);
+extern char* decode_koe_ogg(AvgKoeInfo info, int* dest_len);
+
+extern int is_koe_ogg(char* head) {
+#if HAVE_LIBVORBISFILE || HAVE_LIBVORBISIDEC
+	if (strncmp(head, "OggS", 4) == 0) return 1;
+	else
+#endif
+		return 0;
+}
+
+#if HAVE_LIBVORBISFILE || HAVE_LIBVORBISIDEC
+
+#if HAVE_LIBVORBISFILE
+#include<vorbis/vorbisfile.h>
+#else /* HAVE_LIBVORBISIDEC */
+#include<tremor/ivorbiscodec.h>
+#include<tremor/ivorbisfile.h>
+#endif
+
+#define INITSIZE 65536
+
+static int cur_size = 0;
+static char* out = 0;
+static void Resize(void) {
+	char* new_out = (char*)realloc(out, cur_size+INITSIZE);
+	if (new_out == 0) {
+		new_out = (char*)malloc(cur_size+INITSIZE);
+		memcpy(new_out, out, cur_size);
+		free(out);
+	}
+	out = new_out;
+	cur_size += INITSIZE;
+}
+
+struct OggInfo {
+	FILE* stream;
+	int length;
+	int offset;
+};
+/* ogg stream 読み込み用の dummy callback */
+static size_t ogg_readfunc(void* ptr, size_t size, size_t nmemb, void* datasource) {
+	OggInfo* info = (OggInfo*)datasource;
+	int pt = ftell(info->stream) - info->offset;
+	if (pt+size*nmemb > info->length) {
+		nmemb = (info->length-pt) / size;
+	}
+	return fread(ptr, size, nmemb, info->stream);
+}
+static int ogg_seekfunc(void* datasource, ogg_int64_t new_offset, int whence) {
+	int pt;
+	OggInfo* info = (OggInfo*)datasource;
+	if (whence == SEEK_SET) pt = info->offset + new_offset;
+	else if (whence == SEEK_CUR) pt = ftell(info->stream) + new_offset;
+	else if (whence == SEEK_END) pt = info->offset + info->length + new_offset;
+	int r = fseek(info->stream, pt, 0);
+	return r;
+}
+static long ogg_tellfunc(void* datasource) {
+	OggInfo* info = (OggInfo*)datasource;
+	int pos = ftell(info->stream);
+	if (pos == -1) return -1;
+	return pos-info->offset;
+}
+static int ogg_closefunc(void* datasource) {
+	return 0;
+}
+
+extern char* decode_koe_ogg(AvgKoeInfo info, int* dest_len) {
+	if (info.stream == 0) return 0;
+	// Voice ファイルを直接指定すると全ストリームを再生してしまうので
+	// 必要な部分だけ切り出して callback 経由で帰す
+	fseek(info.stream, info.offset, 0);
+
+	ov_callbacks callback;
+	callback.read_func = &ogg_readfunc;
+	callback.seek_func = &ogg_seekfunc;
+	callback.close_func = &ogg_closefunc;
+	callback.tell_func = &ogg_tellfunc;
+
+	OggInfo oinfo;
+	oinfo.stream = info.stream;
+	oinfo.length = info.length;
+	oinfo.offset = info.offset;
+
+	OggVorbis_File vf;
+	int r = ov_open_callbacks((void*)&oinfo, &vf, 0, 0, callback);
+	if (r != 0) {
+		fprintf(stderr,"ogg stream err: %d\n",r);
+		return 0;
+	}
+	vorbis_info* vinfo = ov_info(&vf, 0);
+	info.rate = vinfo->rate;
+	int channels = vinfo->channels;
+
+	int cur = 0x2c;
+	cur_size = INITSIZE;
+	out = (char*)malloc(cur_size);
+
+	int current_section;
+	do {
+#if HAVE_LIBVORBISFILE
+		r = ov_read(&vf, out+cur, cur_size-cur, 0, 2, 1, 0); 
+#else /* HAVE_LIBVORBISIDEC */
+		r = ov_read(&vf, out+cur, cur_size-cur, &current_section); 
+#endif
+		if (r <= 0) break;
+		cur += r;
+		if (cur_size-INITSIZE/4 < cur) Resize();
+	} while(1);
+	ov_clear(&vf);
+
+	*dest_len = cur; // うまくコンバートできてるのかなあ……
+	const char* header = MakeWavHeader(info.rate, channels, 2, cur);
+	memcpy(out, header, 0x2c);
+	
+	char* ret = out;
+	out = 0;
+
+	return ret;
+}
+struct OggFILE_impl {
+	OggVorbis_File vf;
+	ov_callbacks callback;
+	OggInfo oinfo;
+	OggFILE_impl(FILE*, int);
+};
+
+OggFILE_impl::OggFILE_impl(FILE* stream, int length) {
+	callback.read_func = &ogg_readfunc;
+	callback.seek_func = &ogg_seekfunc;
+	callback.close_func = &ogg_closefunc;
+	callback.tell_func = &ogg_tellfunc;
+	oinfo.stream = stream;
+	oinfo.length = length;
+	oinfo.offset = ftell(stream);
+}
+
+OggFILE::OggFILE(FILE* stream, int len) {
+	pimpl = new OggFILE_impl(stream, len);
+	int r = ov_open_callbacks( (void*)&(pimpl->oinfo), &(pimpl->vf), 0, 0, pimpl->callback);
+	if (r != 0) {
+		delete pimpl;
+		pimpl = 0;
+		return;
+	}
+	vorbis_info* vinfo = ov_info(&(pimpl->vf), 0);
+	wavinfo.SamplingRate = vinfo->rate;
+	wavinfo.Channels = vinfo->channels;
+	wavinfo.DataBits = 16;
+}
+OggFILE::~OggFILE() {
+	if (pimpl) {
+		ov_clear(&(pimpl->vf));
+		fclose(pimpl->oinfo.stream);
+		delete pimpl;
+	}
+}
+int OggFILE::Read(char* buf, int blksize, int blklen) {
+	if (pimpl == 0) return -1;
+	int current_section;
+#if HAVE_LIBVORBISFILE
+	int r = ov_read( &(pimpl->vf), buf, blksize*blklen, 0, 2, 1, 0);
+#else /* HAVE_LIBVORBISIDEC */
+	int r = ov_read( &(pimpl->vf), buf, blksize*blklen, &current_section);
+#endif
+	if (r <= 0) { // end of file
+		return -1;
+	}
+	while(r < blksize*blklen) {
+#if HAVE_LIBVORBISFILE
+		int dr = ov_read(&(pimpl->vf), buf+r, blksize*blklen-r, 0, 2, 1, 0);
+#else /* HAVE_LIBVORBISIDEC */
+		int dr = ov_read(&(pimpl->vf), buf+r, blksize*blklen-r, &current_section);
+#endif
+		if (dr <= 0) break;
+		r += dr;
+	}
+	return r / blksize;
+}
+void OggFILE::Seek(int count) {
+	ov_pcm_seek(&(pimpl->vf), count);
+	return;
+}
+#else
+extern char* decode_koe_ogg(AvgKoeInfo info, int* dest_len) {
+	return 0;
+}
+OggFILE::OggFILE(FILE* stream, int a) {pimpl = 0;}
+OggFILE::~OggFILE(){}
+void OggFILE::Seek(int count){}
+int OggFILE::Read(char* buf, int blksize, int blklen){return -1;}
+#endif
new file mode 100644
--- /dev/null
+++ b/music2/movie.cc
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2004-2006  Kazunori "jagarl" Ueno
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * movie.cc  smpeg による動画再生
+ *
+*/
+
+#include<stdio.h>
+#include"music.h"
+#include<SDL.h>
+#include<SDL_mixer.h>
+#include<string.h>
+#include<ctype.h>
+#include<stdlib.h>
+#include"system/file.h"
+#include"window/system.h"
+
+#if USE_SMPEG
+#include<smpeg/smpeg.h>
+
+static SMPEG* smpeg_handle = 0;
+const char* FindMovieFile(const char* path);
+void MuSys::PlayMovie(const char* path, int x1, int y1, int x2, int y2, int loop_count) {
+	if (!pcm_enable) return;
+	FinalizeMusic();
+	SMPEG_Info info;
+	const char* find_path = FindMovieFile(path);
+	if (find_path == 0) return;
+	smpeg_handle = SMPEG_new(find_path, &info, true);
+	//SMPEG_enableaudio(smpeg_handle,  true);
+	//SMPEG_enablevideo(smpeg_handle,  true);
+	SMPEG_enableaudio(smpeg_handle,  true);
+	SMPEG_enablevideo(smpeg_handle,  true);
+	SDL_Surface* surface = SDL_GetVideoSurface();
+	System::Main::DisableVideo();
+	SMPEG_setdisplay(smpeg_handle,surface,0,0);
+	// if (loop_c > 1) SMPEG_loop(smpeg_handle, true);
+	//if (x1 != 0 || x2 != 0) SMPEG_setdisplayregion(smpeg_handle,x1, y1, x2-x1, y1-y2);
+	SMPEG_play(smpeg_handle);
+#if 0
+	while(SMPEG_status(smpeg_handle) != SMPEG_PLAYING) {
+           	SDL_Delay( 10 );
+	}
+#endif
+	return;
+err:
+	StopMovie();
+	return;
+}
+const char* FindMovieFile(const char* path) {
+	ARCINFO* info = file_searcher.Find(FILESEARCH::MOV,path,"avi");
+	if (info == 0) 
+		info = file_searcher.Find(FILESEARCH::MOV,path,"mpg");
+	if (info == 0) return 0;
+	const char* file = info->Path();
+	delete info;
+	return file;
+}
+
+void MuSys::StopMovie(void) {
+	if (smpeg_handle) {
+		if (SMPEG_status(smpeg_handle) == SMPEG_PLAYING)
+			SMPEG_stop(smpeg_handle);
+		while(SMPEG_status(smpeg_handle) == SMPEG_PLAYING) {
+            		SDL_Delay( 10 );
+		}
+		SMPEG_delete(smpeg_handle);
+	}
+	smpeg_handle = 0;
+	System::Main::EnableVideo();
+	InitMusic();
+}
+bool MuSys::IsStopMovie(void) {
+	if (!smpeg_handle) return true;
+	if (SMPEG_status(smpeg_handle) == SMPEG_PLAYING) return false;
+	return true;
+}
+
+#else /* USE_SMPEG */
+void MuSys::PlayMovie(const char* path, int x1, int y1, int x2, int y2, int loop_count) {
+}
+void MuSys::StopMovie(void) {
+}
+bool MuSys::IsStopMovie(void) {
+	return true;
+}
+#endif
new file mode 100644
--- /dev/null
+++ b/music2/music.cc
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 2004-2006  Kazunori "jagarl" Ueno
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*  music.cc	SDL_mixer を用いた音楽再生ルーチン */
+
+
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <signal.h>
+#include"system/system_config.h"
+#include"system/file.h"
+#include "music.h"
+#include<SDL.h>
+#include<SDL_mixer.h>
+#include"wavfile.h"
+
+using namespace std;
+
+int pcm_enable   = 0;
+Mix_Chunk *play_chunk[MIX_PCM_SIZE];
+
+MuSys::MuSys(AyuSysConfig& _config) : config(_config), movie_id(-1), music_enable(1) {
+	int i;
+	for (i=0; i<MIX_PCM_SIZE; i++)
+		play_chunk[i] = 0;
+	cdrom_track[0] = 0;
+	effec_track[0] = 0;
+}
+
+
+// #define delete fprintf(stderr,"smus.cc: %d.",__LINE__), delete
+
+void bgm_start(const char* path, int loop_pt);
+void effec_start(int chn, const char* path, int loop, int fadein_time);
+void bgm_fadeout(int time);
+
+void MuSys::PlayCDROM(char* name, int play_count) {
+	char wave[128]; wave[127] = '\0'; wave[0] = '\0';
+
+	strcpy(cdrom_track, name);
+
+	StopCDROM(0);
+	strcpy(cdrom_track, name);
+
+	/* name -> track */
+	int track =config.track_name.CDTrack(name);
+	if (track == -1) track = atoi(name);
+	if (config.track_name.WaveTrack(name) != 0) strncpy(wave, config.track_name.WaveTrack(name), 127);
+	if (wave[0] == 0 && track != 0) { /* DSTRACK が見つからない場合、CDTRACKを使用する */
+		sprintf(wave, "audio_%02d",track);
+	}
+	if (wave == 0) return;
+	// BGM 再生
+	if (!pcm_enable) return;
+	if (play_count == 0)
+		bgm_start(wave, -1);
+	else
+		bgm_start(wave, config.track_name.TrackStart(name));
+	return;
+}
+
+void MuSys::StopCDROM(int time)
+{
+	cdrom_track[0] = '\0';
+	if (!pcm_enable) return;
+	bgm_fadeout(time);
+}
+
+void MuSys::PlaySE(const char* se, int loop_flag, int channel) {
+	if (! pcm_enable) return;
+	if (loop_flag)
+		effec_start(MIX_PCM_EFFEC, se, 10000, 0);
+	else
+		effec_start(MIX_PCM_EFFEC, se, 0, 0);
+	return;
+}
+void MuSys::PlaySE(int number) {
+	if (! pcm_enable) return;
+	const char* se_name = config.track_name.SETrack(number);
+	if (se_name == 0) return;
+	effec_start(MIX_PCM_EFFEC, se_name, 0, 0);
+	return;
+}
+void MuSys::StopSE(int time) {
+	if (! pcm_enable) return;
+	if (time == 0) 
+		Mix_HaltChannel(MIX_PCM_EFFEC);
+	else
+		Mix_FadeOutChannel(MIX_PCM_EFFEC, time);
+}
+bool MuSys::IsStopSE(void) {
+	if (! pcm_enable) return true;
+	if (Mix_Playing(MIX_PCM_EFFEC) != 0) return false;
+	return true;
+}
+
+void MuSys::StopKoe(int time) {
+	if (! pcm_enable) return;
+	if (time == 0) Mix_HaltChannel(MIX_PCM_KOE);
+	else Mix_FadeOutChannel(MIX_PCM_KOE, time);
+}
+
+void MuSys::InitMusic(void)
+{
+	if (music_enable != 1) return;
+	cdrom_track[0] = '\0';
+	if ( Mix_OpenAudio( 44100, MIX_DEFAULT_FORMAT, MIX_DEFAULT_CHANNELS, DEFAULT_AUDIOBUF ) < 0 ){
+//	if ( Mix_OpenAudio( 48000, MIX_DEFAULT_FORMAT, MIX_DEFAULT_CHANNELS, DEFAULT_AUDIOBUF ) < 0 ){
+		return;
+	}
+	int freq, channels; Uint16 format;
+	if ( Mix_QuerySpec(&freq, &format, &channels) ) {
+		WAVFILE::freq = freq;
+		WAVFILE::format = format;
+		WAVFILE::channels = channels;
+	}
+	pcm_enable = 1;
+	Mix_AllocateChannels( MIX_PCM_SIZE);
+	music_enable = 2;
+	return;
+}
+void MuSys::FinalizeMusic(void)
+{
+	if (music_enable != 2) return;
+	int i;
+	for (i=0; i<MIX_PCM_SIZE; i++) {
+		Mix_HaltChannel(i);
+		if (play_chunk[i]) {
+			Mix_FreeChunk(play_chunk[i]);
+		}
+		play_chunk[i] = 0;
+	}
+	Mix_HaltMusic();
+	Mix_HookMusic(0,0);
+	Mix_CloseAudio();
+	pcm_enable = 0;
+	music_enable = 1;
+}
+
+/*************************************************************************
+**
+** ファイル読み込み / 外部コマンド呼び出し
+*/
+
+struct WavChunk {
+	WAVFILE* wav;
+	int loop_pt;
+	static void callback(void* userdata, Uint8* stream, int len);
+};
+WavChunk wav_playing;
+static int fadetime_total;
+static int fadecount;
+
+void WavChunk::callback(void *userdata, Uint8 *stream, int len)
+{
+	WavChunk* chunk = (WavChunk*)userdata;
+	int count;
+	if (chunk->loop_pt == -2) { // 再生終了後
+		memset(stream, 0, len);
+		return;
+	}
+	count = chunk->wav->Read( (char*)stream, 4, len/4);
+
+	if (count != len/4) {
+		memset(stream+count*4, 0, len-count*4);
+		// 最後まで再生した
+		if (chunk->loop_pt == -1) { // 終了
+			chunk->loop_pt = -2;
+		} else {
+			chunk->wav->Seek(chunk->loop_pt);
+			chunk->wav->Read( (char*)(stream+count*4), 4, len/4-count);
+		}
+	}
+	if (fadetime_total) {
+		// 音楽を停止中 (fade out)
+		int count_total = fadetime_total*(WAVFILE::freq/1000);
+		if (fadecount > count_total || fadetime_total == 1) { // 音楽停止
+			chunk->loop_pt = -2;
+			memset(stream, 0, len);
+			return;
+		}
+		// int cur_vol = 256*(count_total-fadecount)/count_total;
+		int cur_vol = SDL_MIX_MAXVOLUME*(count_total-fadecount)/count_total;
+		char* stream_dup = new char[len];
+		memcpy(stream_dup, stream, len);
+		memset(stream, 0, len);
+		SDL_MixAudio(stream, (Uint8*)stream_dup, len, cur_vol);
+		fadecount += len/4;
+	}
+	return;
+}
+void bgm_fadeout(int time) {
+	fadecount = 0;
+	if (time <= 0) time = 1;
+	fadetime_total = time;
+}
+
+static SDL_RWops* OpenSDLRW(const char* path);
+static WAVFILE* OpenWaveFile(const char* path);
+void bgm_start(const char* path, int loop_pt) {
+	if (! pcm_enable) return;
+fprintf(stderr,"bgm start %s\n",path);
+	WAVFILE* wav = OpenWaveFile(path);
+	if (wav == 0) return;
+	Mix_PauseMusic();
+	Mix_HaltMusic();
+	Mix_HookMusic(0,0);
+	/* 前に再生していたのを終了 */
+	if (wav_playing.wav) {
+		delete wav_playing.wav;
+		wav_playing.wav = 0;
+	}
+	wav_playing.wav = wav;
+	wav_playing.loop_pt = loop_pt;
+	fadetime_total = 0;
+	fadecount = 0;
+	Mix_HookMusic( &(WavChunk::callback), (void*)&wav_playing);
+	Mix_VolumeMusic(128);
+	return;
+}
+
+void effec_start(int chn, const char* path, int loop, int fadein_time) {
+	if (! pcm_enable) return;
+	SDL_RWops* op = OpenSDLRW(path);
+	if (op == 0) { // ファイルが見付からない
+		return;
+	}
+	Mix_Pause(chn);
+
+	if (play_chunk[chn]) {
+		Mix_FreeChunk(play_chunk[chn]);
+	}
+	play_chunk[chn] = Mix_LoadWAV_RW(op, 1);
+	if (fadein_time <= 0) {
+		Mix_Volume(chn, 128);
+		Mix_PlayChannel(chn, play_chunk[chn],loop);
+	} else {
+		Mix_Volume(chn, 128);
+		Mix_FadeInChannel(chn, play_chunk[chn],loop,fadein_time);
+	}
+	return;
+}
+
+void MuSys::PlayKoe(const char* path) {
+	if (! pcm_enable) return;
+	static char* playing_koedata = 0;
+	int len = 0;
+	AvgKoeInfo koeinfo;
+	int chn = MIX_PCM_KOE;
+
+	Mix_Pause(chn);
+	Mix_HaltChannel(chn); // これで RWop が解放されるはず…
+	if (play_chunk[chn]) {
+		Mix_FreeChunk(play_chunk[chn]);
+		play_chunk[chn] = 0;
+	}
+
+	if (playing_koedata) {
+		delete[] playing_koedata;
+		playing_koedata = 0;
+	}
+
+	koeinfo = OpenKoeFile(path);
+
+	if (koeinfo.stream == 0) return;
+	playing_koedata = decode_koe(koeinfo, &len);
+	fclose(koeinfo.stream);
+	if (playing_koedata == 0) {
+		return;
+	}
+	Mix_Volume(chn, 128);
+	play_chunk[chn] = Mix_LoadWAV_RW(SDL_RWFromMem(playing_koedata, len+0x2c), 1);
+	Mix_PlayChannel(chn, play_chunk[chn],0);
+	return;
+}
+AvgKoeInfo OpenKoeFile(const char* path) {
+	int radix = 10000;
+	/* if (global_system.Version() >= 2) */ radix *= 10;
+	AvgKoeInfo info;
+	info.stream = 0; info.length = 0; info.offset = 0;
+	if (isdigit(path[0]) && strchr(path,'.') == 0) { // 数値 (拡張子等なし)
+		/* avg32 形式の音声アーカイブのキャッシュを検索 */
+		int pointer = atoi(path);
+		int file_no = pointer / radix;
+		int index = pointer % radix;
+		info = FindKoe(file_no, index);
+	} else { // ファイル
+		int length;
+		ARCINFO* arcinfo = file_searcher.Find(FILESEARCH::KOE,path,".WPD");
+		if (arcinfo == 0) return info;
+		info.stream = arcinfo->OpenFile(&length);
+		info.rate = 22050;
+		info.length = length;
+		info.offset = ftell(info.stream);
+		info.type = koe_unknown;
+		delete arcinfo;
+	}
+	return info;
+}
+
+static SDL_RWops* OpenSDLRW(const char* path) {
+	char cmdline_buf[1024];
+	/* まず wav ファイルを探す */
+	ARCINFO* info = file_searcher.Find(FILESEARCH::WAV,path,".wav");
+	if (info == 0) {
+		info = file_searcher.Find(FILESEARCH::WAV,path,".nwa");
+		if (info == 0) info = file_searcher.Find(FILESEARCH::BGM,path,"nwa");
+		if (info) { // read NWA file
+
+			static char* nwa_buffer = 0;
+			int dummy;
+			FILE* f = info->OpenFile(&dummy);
+			static char* d = 0;
+			int sz;
+			if (d != 0) delete[] d;
+			d = NWAFILE::ReadAll(f, sz);
+			return SDL_RWFromMem(d, sz);
+		}
+	}
+	if (info == 0) info = file_searcher.Find(FILESEARCH::BGM,path,"wav");
+	if (info == 0) info = file_searcher.Find(FILESEARCH::WAV,path,".ogg");
+	if (info) {
+		int dummy;
+		FILE* f = info->OpenFile(&dummy);
+		delete info;
+		if (f == 0) return 0;
+		SDL_RWops* op = SDL_RWFromFP(f, 1);
+		return op;
+	}
+	return 0;
+}
+
+static WAVFILE* OpenWaveFile(const char* path) {
+	char cmdline_buf[1024];
+	/* まず wav ファイルを探す */
+	ARCINFO* info = file_searcher.Find(FILESEARCH::WAV,path,".wav");
+	if (info == 0) info = file_searcher.Find(FILESEARCH::BGM,path,"wav");
+	if (info) {
+		int size;
+		FILE* f = info->OpenFile(&size);
+		delete info;
+		if (f == 0) return 0;
+		WAVFILE* w = WAVFILE::MakeConverter(new WAVFILE_Stream(f, size));
+		return w;
+	}
+	/* 次に nwa ファイル */
+	info = file_searcher.Find(FILESEARCH::WAV,path,".nwa");
+	if (info == 0) info = file_searcher.Find(FILESEARCH::BGM,path,"nwa");
+	if (info) {
+		int size;
+		FILE* f = info->OpenFile(&size);
+		delete info;
+		if (f == 0) return 0;
+		WAVFILE* w = WAVFILE::MakeConverter(new NWAFILE(f));
+		return w;
+	}
+
+	/* 次に mp3 ファイル */
+	info = file_searcher.Find(FILESEARCH::WAV,path,".mp3");
+	if (info == 0) info = file_searcher.Find(FILESEARCH::BGM,path,"mp3");
+	if (info) {
+		int size;
+		FILE* f = info->OpenFile(&size);
+		delete info;
+		if (f == 0) return 0;
+		MP3FILE* w = new MP3FILE(f, size);
+		if (w->pimpl) {
+			return WAVFILE::MakeConverter(w);
+		}
+		delete w;
+	}
+
+	/* 次に ogg ファイル */
+	info = file_searcher.Find(FILESEARCH::WAV,path,".ogg");
+	if (info == 0) info = file_searcher.Find(FILESEARCH::BGM,path,"ogg");
+	if (info) {
+		int size;
+		FILE* f = info->OpenFile(&size);
+		delete info;
+		if (f == 0) return 0;
+		OggFILE* w = new OggFILE(f, size);
+		if (w->pimpl) {
+			return WAVFILE::MakeConverter(w);
+		}
+		delete w;
+	}
+	return 0;
+}
+
new file mode 100644
--- /dev/null
+++ b/music2/music.h
@@ -0,0 +1,59 @@
+#ifndef __MUSIC__ /* __MUSIC__ */
+#define __MUSIC__
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include<sys/types.h>
+#include<sys/time.h>
+
+#define MIX_PCM_BGM	4
+#define MIX_PCM_EFFEC	5
+#define MIX_PCM_KOE	6
+#define MIX_PCM_SIZE	8
+
+#define DEFAULT_AUDIOBUF	4096
+
+enum KoeType { koe_unknown, koe_nwk, koe_ovk};
+typedef struct {
+	FILE* stream;
+	int length;
+	int offset;
+	int rate;
+	KoeType type;
+}AvgKoeInfo;
+
+extern int pcm_enable;
+
+/* koedec.cc */
+extern AvgKoeInfo OpenKoeFile(const char* path);
+extern char* decode_koe(AvgKoeInfo info, int* len);
+extern char* decode_koe_nwa(AvgKoeInfo info, int* len);
+extern const char* MakeWavHeader(int rate, int ch, int bps, int size);
+extern AvgKoeInfo FindKoe(int file_number, int index);
+
+#include<unistd.h>
+struct MuSys {
+	class AyuSysConfig& config;
+	char cdrom_track[128]; char effec_track[128];
+	int movie_id;
+	int music_enable;
+	MuSys(AyuSysConfig& _config);
+
+	void PlayCDROM(char* name, int play_count);
+	void StopCDROM(int time);
+	void PlaySE(const char* name, int loop_flag=0, int channel=0);
+	void PlaySE(int number);
+	void StopSE(int time = 0);
+	bool IsStopSE(void);
+	void PlayKoe(const char* fname);
+	void StopKoe(int time);
+	void PlayMovie(const char* fname, int x1, int y1, int x2, int y2, int loop_count);
+	void StopMovie(void);
+	bool IsStopMovie(void);
+	void InitMusic(void);
+	void FinalizeMusic(void);
+};
+
+#endif /* __MUSIC__ */
new file mode 100644
--- /dev/null
+++ b/music2/nwatowav.cc
@@ -0,0 +1,866 @@
+/* nwatowav : Visual Arts 系のゲームのデモで使われる nwa 形式の
+**            ファイルを wav 形式に変換する
+**
+**     compile : gcc -O2 -o nwatowav nwatowav.cc
+**     usage : nwatowav [nwa-file [outfile]]
+**	       nwatowav [nwk-file [outfile]]
+**     example : nwatowav HM06.nwa HM06.wav	# BGMファイル。HM06.wav に展開される
+**		 nwatowav z2813.nwk z2813	# 音声ファイル。 z2813-100.wav などのファイル名で展開される
+**		 nwatowav z0513.ovk z0513	# 音声ファイル。 z0513-100.ogg などのファイル名で展開される
+**
+**
+** 2004.5.19 小松さん<s1100089@u-aizu.ac.jp> から CLANNAD の無圧縮nwa形式に対応する
+**           パッチをいただいたので、適用しました。ありがとうございます。
+** 2006.9.10 「智代アフター」の音声ファイル形式 (complevel = 5) をサポート
+**	     .nwk という拡張子を持つファイルを受け取ると音声ファイルとして
+**	     解釈、分割して展開するようにする
+** 2007.7.28 「リトルバスターズ!」の音声ファイル形式 (*.ovk; ogg 連結型)
+**		をサポート。.ovk という拡張子をもつファイルを受け取ると
+**		音声ファイルとして解釈、分割して展開するようにする
+**	     「リトルバスターズ!」のBGMファイルに多量のノイズが乗る問題も
+**	      解決(ランレングス圧縮の処理が不必要だった)
+*/
+
+/*
+ * Copyright 2001-2007  jagarl / Kazunori Ueno <jagarl@creator.club.ne.jp>
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * このプログラムの作者は jagarl です。
+ *
+ * このプログラム、及びコンパイルによって生成したバイナリは
+ * プログラムを変更する、しないにかかわらず再配布可能です。
+ * その際、上記 Copyright 表示を保持するなどの条件は課しま
+ * せん。対応が面倒なのでバグ報告を除き、メールで連絡をする
+ * などの必要もありません。ソースの一部を流用することを含め、
+ * ご自由にお使いください。
+ *
+ * THIS SOFTWARE IS PROVIDED BY KAZUNORI 'jagarl' UENO ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL KAZUNORI UENO BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * 
+ */
+
+/********************************************
+**
+**	nwa フォーマットについて
+**
+**		全体としては以下の構造を持つ
+**		NWA Header
+**		data offset index
+**		data block<0>
+**		data block<1>
+**		...
+**		data block<N>
+**
+**	NWA Header: ファイル先頭から 44 bytes
+**		magic number などはないのでnwa ファイルかは
+**		データの整合性から判断する必要がある
+**		データは全て little endian で、
+**		short(signed 2byte)または int(signed 4byte) である。
+**
+**		+00 short   channel 数(1/2)
+**		+02 short   sample 一つあたりの bit 数(16)
+**		+04 int     周波数(一秒あたりのデータ数)
+**		+08 int     圧縮レベル:-1~5.2で最小のデータ、0で最大の復元度(-1は無圧縮rawデータとみなされる)
+**		+12 int     ?
+**		+16 int     ブロック数
+**		+20 int     展開後のデータの大きさ(バイト単位)
+**		+24 int     圧縮時のデータの大きさ(nwa ファイルの大きさ。バイト単位)
+**		+28 int     サンプル数:展開後のデータ数(16bit dataなら short 単位==サンプル単位のデータの大きさ)
+**		+32 int     データ1ブロックを展開した時のサンプル単位のデータ数
+**		+36 int     最終ブロックを展開した時のサンプル単位のデータ数
+**		+40 int     ?
+**		
+**	data offset index
+**		全ブロック数 x 4 byte のデータ
+**		それぞれ int のデータが全ブロック数続いている
+**
+**		データブロックの先頭を指すファイル先頭からの位置(オフセット)
+**		が格納されている
+**
+**	data block
+**		長さは可変。展開することで一定の大きさをもつデータに展開される。
+**		データはDPCM形式。元 PCM データが a,b,c ならば (a),b-a, c-b と
+**		いった差分データが、仮数3-5bit,指数3bitの形式で保存されている。
+**		結果的に、16bit のデータが多くの場合 6-8bit で格納される。
+**		仮数のビット数は圧縮レベル0で5bit、圧縮レベル2で3bitとなる。
+**		以下、圧縮レベル2の場合について話を進める。
+**		モノラルの場合:
+**			+00 short  ブロック内の最初のデータ
+**			+02- bit stream
+**		ステレオの場合:
+**			+00 short  左(?)チャンネルの最初のデータ
+**			+02 short  右(?)チャンネルの最初のデータ
+**			+04- bit stream
+**
+**		差分データの精度が高くないので各ブロックの先頭で
+**		正確なデータにより補正される(?)
+**
+**	bit stream
+**		little endian
+**		+0 - +2 : 指数
+**		+3 - +5 : 仮数
+**		の形式。例えば a,b,c という8bitデータがあれば、
+**		a&0x07 : データ1の指数
+**		(a>>3)&0x07 : データ1の仮数(signed ; 
+**		((b<<2)|(a>>6))&0x07 : データ2の指数
+**		(b>>1)&0x07 : データ2の仮数
+**		となる。
+**		ただし、指数の値により仮数のbit数が変化することがある。
+**		指数 = 1 - 6 の場合:
+**			a=指数、b=仮数、p=前のデータとして、今回のデータd は
+**			bの2bit目が立っている場合:
+**				d = p - (b&3)<<(4+a)
+**			立ってない場合:
+**				d = p + (b&3)<<(4+a)
+**		指数 = 0 の場合:仮数は存在しない(データは3bitとなる)
+**			d = p
+**			「智代アフター」の音声ファイル (complevel == 5) ではランレングス圧縮用に使われている。
+**		指数 = 7
+**			次の bit が立っている場合:
+**				d = 0 (現在未使用)
+**				(データは4bitとなる)
+**			次の bit が立ってない場合:
+**				complevel = 0,1,2:
+**				   仮数 b = 6bit
+**				   b の 5bit 目が立っている場合:
+**					d = p - (b&0x1f)<<(4+7)
+**				   立ってない場合:
+**					d = p + (b&0x1f)<<(4+7)
+**				   (データは10bitとなる)
+**				complevel = 3,4,5:
+**				   仮数 b = 8bit
+**				   b の 7bit 目が立っている場合:
+**					d = p - (b&0x7f)<<9
+**				   立ってない場合:
+**					d = p + (b&0x1f)<<9
+**				   (データは10bitとなる)
+**
+**		圧縮レベルが異なる場合、たとえば圧縮レベル==0で
+**			指数==1~6でdの最上位bitが立っている場合
+**				d = p - (b&0x0f)<<(2+a)
+**			指数==7でdの最上位bitが立っている場合
+**				d = p - (b&0x7f)<<(2+7)
+**				(b : 8bitなのでデータは12bitとなる)
+**		のように、精度だけが変化するようになっている。
+**
+**	ヘッダ読み込みについてはNWAData::ReadHeader()参照
+**	bit stream からのデータ展開については NWADecode()参照
+**************************************************************
+*/
+
+// #define NDEBUG /* なぜか assertが入った方が速い、、、 */
+
+#include<stdio.h>
+#include<stdlib.h>
+#include<unistd.h>	// for isatty() function
+#include<sys/stat.h>
+#include<string.h>
+
+
+#ifdef WORDS_BIGENDIAN
+#error Sorry, This program does not support BIG-ENDIAN system yet.
+/* もし big endian のシステムに対応させる場合
+** 以下の *_little_endian_* 及び
+** getbits() 関数を変更する必要がある
+*/
+#endif
+
+inline int read_little_endian_int(const char* buf) {
+	return *(int*)buf;
+}
+
+inline int read_little_endian_short(const char* buf) {
+	return *(short*)buf;
+}
+
+inline int write_little_endian_int(char* buf, int number) {
+	int c = *(int*)buf; *(int*)buf = number; return c;
+}
+
+inline int write_little_endian_short(char* buf, int number) {
+	int c = *(short*)buf; *(short*)buf = number; return c;
+}
+inline int getbits(const char*& data, int& shift, int bits) {
+	if (shift > 8) { data++; shift-=8;}
+	int ret = read_little_endian_short(data)>>shift;
+	shift += bits;
+	return ret & ((1<<bits)-1); /* mask */
+}
+
+/* 指定された形式のヘッダをつくる */
+const char* make_wavheader(int size, int channels, int bps, int freq) {
+	static char wavheader[0x2c] = {
+		'R','I','F','F',
+		0,0,0,0, /* +0x04: riff size*/
+		'W','A','V','E',
+		'f','m','t',' ',
+		16,0,0,0, /* +0x10 : fmt size=0x10 */
+		1, 0,    /* +0x14 : tag : pcm = 1 */
+		2, 0,    /* +0x16 : channels */
+		0,0,0,0, /* +0x18 : samples per second */
+		0,0,0,0, /* +0x1c : average bytes per second */
+		0,0,     /* +0x20 : block alignment */
+		0,0,     /* +0x22 : bits per sample */
+		'd','a','t','a',
+		0,0,0,0};/* +0x28 : data size */
+	write_little_endian_int(wavheader+0x04, size+0x24);
+	write_little_endian_int(wavheader+0x28, size);
+	write_little_endian_short(wavheader+0x16, channels);
+	write_little_endian_short(wavheader+0x22, bps);
+	write_little_endian_int(wavheader+0x18, freq);
+	int byps = (bps+7)>>3;
+	write_little_endian_int(wavheader+0x1c, freq*byps*channels);
+	write_little_endian_short(wavheader+0x20, byps*channels);
+	return wavheader;
+}
+
+/* NWA の bitstream展開に必要となる情報 */
+class NWAInfo {
+	int channels;
+	int bps;
+	int complevel;
+	bool use_runlength;
+public:
+	NWAInfo(int c,int b,int cl) {
+		channels=c;
+		bps=b;
+		complevel=cl;
+		use_runlength = false;
+		if (cl == 5) {
+			use_runlength = true; // Tomoyo After (.nwk koe file)
+			if (channels == 2) use_runlength = false; // BGM*.nwa in Little Busters!
+		}
+	}
+	int Channels(void) const{return channels;}
+	int Bps(void) const { return bps;}
+	int CompLevel(void) const { return complevel;}
+	int UseRunLength(void) const { return use_runlength; }
+};
+
+template<class NWAI> void NWADecode(const NWAI& info,const char* data, char* outdata, int datasize, int outdatasize) {
+	int d[2];
+	int i,j;
+	int shift = 0;
+	const char* dataend = data+datasize;
+	/* 最初のデータを読み込む */
+	if (info.Bps() == 8) {d[0] = *data++; datasize--;}
+	else /* info.Bps() == 16 */ {d[0] = read_little_endian_short(data); data+=2; datasize-=2;}
+	if (info.Channels() == 2) {
+		if (info.Bps() == 8) {d[1] = *data++; datasize--;}
+		else /* info.Bps() == 16 */ {d[1] = read_little_endian_short(data); data+=2; datasize-=2;}
+	}
+	int dsize = outdatasize / (info.Bps()/8);
+	int flip_flag = 0; /* stereo 用 */
+	int runlength = 0;
+	for (i=0; i<dsize; i++) {
+		if (data >= dataend) break;
+		if (runlength == 0) { // コピーループ中でないならデータ読み込み
+			int type = getbits(data, shift, 3);
+			/* type により分岐:0, 1-6, 7 */
+			if (type == 7) {
+				/* 7 : 大きな差分 */
+				/* RunLength() 有効時(CompLevel==5, 音声ファイル) では無効 */
+				if (getbits(data, shift, 1) == 1) {
+					d[flip_flag] = 0; /* 未使用 */
+				} else {
+					int BITS, SHIFT;
+					if (info.CompLevel() >= 3) {
+						BITS = 8;
+						SHIFT = 9;
+					} else {
+						BITS = 8-info.CompLevel();
+						SHIFT = 2+7+info.CompLevel();
+					}
+					const int MASK1 = (1<<(BITS-1));
+					const int MASK2 = (1<<(BITS-1))-1;
+					int b = getbits(data, shift, BITS);
+					if (b&MASK1)
+						d[flip_flag] -= (b&MASK2)<<SHIFT;
+					else
+						d[flip_flag] += (b&MASK2)<<SHIFT;
+				}
+			} else if (type != 0) {
+				/* 1-6 : 通常の差分 */
+				int BITS, SHIFT;
+				if (info.CompLevel() >= 3) {
+					BITS = info.CompLevel()+3;
+					SHIFT = 1+type;
+				} else {
+					BITS = 5-info.CompLevel();
+					SHIFT = 2+type+info.CompLevel();
+				}
+				const int MASK1 = (1<<(BITS-1));
+				const int MASK2 = (1<<(BITS-1))-1;
+				int b = getbits(data, shift, BITS);
+				if (b&MASK1)
+					d[flip_flag] -= (b&MASK2)<<SHIFT;
+				else
+					d[flip_flag] += (b&MASK2)<<SHIFT;
+			} else { /* type == 0 */
+				/* ランレングス圧縮なしの場合はなにもしない */
+				if (info.UseRunLength() == true) {
+					/* ランレングス圧縮ありの場合 */
+					runlength = getbits(data,shift,1);
+					if (runlength==1) {
+						runlength = getbits(data,shift,2);
+						if (runlength == 3) {
+							runlength = getbits(data, shift, 8);
+						}
+					}
+				}
+			}
+		} else {
+			runlength--;
+		}
+		if (info.Bps() == 8) {
+			*outdata++ = d[flip_flag];
+		} else {
+			write_little_endian_short(outdata, d[flip_flag]);
+			outdata += 2;
+		}
+		if (info.Channels() == 2) flip_flag ^= 1; /* channel 切り替え */
+	}
+	return;
+};
+
+class NWAData {
+public:
+	int channels;
+	int bps; /* bits per sample */
+	int freq; /* samples per second */
+private:
+	int complevel; /* compression level */
+	int dummy; /* ? : 0x00 */
+public:
+	int blocks; /* block count */
+	int datasize; /* all data size */
+private:
+	int compdatasize; /* compressed data size */
+	int samplecount; /* all samples */
+	int blocksize; /* samples per block */
+	int restsize; /* samples of the last block */
+	int dummy2; /* ? : 0x89 */
+	int curblock;
+	int* offsets;
+	int offset_start;
+	int filesize;
+	char* tmpdata;
+public:
+	void ReadHeader(FILE* in, int file_size=-1);
+	int CheckHeader(void); /* false: invalid true: valid */
+	NWAData(void) {
+		offsets = 0;
+		tmpdata = 0;
+	}
+	~NWAData(void) {
+		if (offsets) delete[] offsets;
+		if (tmpdata) delete[] tmpdata;
+	}
+	int BlockLength(void) {
+		if (complevel != -1) {
+			if (offsets == 0) return false;
+			if (tmpdata == 0) return false;
+		}
+		return blocksize * (bps/8);
+	}
+	/* data は BlockLength 以上の長さを持つこと
+	** 返り値は作成したデータの長さ。終了時は 0。
+	** エラー時は -1
+	*/
+	int Decode(FILE* in, char* data, int& skip_count);
+	void Rewind(FILE* in);
+};
+
+void NWAData::ReadHeader(FILE* in, int _file_size) {
+	char header[0x2c];
+	struct stat sb;
+	int i;
+	if (offsets) delete[] offsets;
+	if (tmpdata) delete[] tmpdata;
+	offsets = 0;
+	tmpdata = 0;
+	filesize = 0;
+	offset_start = ftell(in);
+	if (offset_start == -1) offset_start = 0;
+	if (_file_size != -1) filesize = _file_size;
+	curblock = -1;
+	/* header 読み込み */
+	if (in == 0 || feof(in) || ferror(in)) {
+		fprintf(stderr,"invalid stream\n");
+		return;
+	}
+	fread(header, 0x2c, 1, in);
+	if (feof(in) || ferror(in)) {
+		fprintf(stderr,"invalid stream\n");
+		return;
+	}
+	channels = read_little_endian_short(header+0x00);
+	bps = read_little_endian_short(header+0x02);
+	freq = read_little_endian_int(header+0x04);
+	complevel = read_little_endian_int(header+0x08);
+	dummy = read_little_endian_int(header+0x0c);
+	blocks = read_little_endian_int(header+0x10);
+	datasize = read_little_endian_int(header+0x14);
+	compdatasize = read_little_endian_int(header+0x18);
+	samplecount = read_little_endian_int(header+0x1c);
+	blocksize = read_little_endian_int(header+0x20);
+	restsize = read_little_endian_int(header+0x24);
+	dummy2 = read_little_endian_int(header+0x28);
+	if (complevel == -1) {	/* 無圧縮rawデータ */
+		/* 適当に決め打ちする */
+		blocksize = 65536;
+		restsize = (datasize % (blocksize * (bps/8))) / (bps/8);
+		blocks = datasize / (blocksize * (bps/8)) + (restsize > 0 ? 1 : 0);
+	}
+	if (blocks <= 0 || blocks > 1000000) {
+		/* 1時間を超える曲ってのはないでしょ*/
+		fprintf(stderr,"too large blocks : %d\n",blocks);
+		return;
+	}
+	/* regular file なら filesize 読み込み */
+	if (filesize == 0 && fstat(fileno(in), &sb)==0 && (sb.st_mode&S_IFMT) == S_IFREG) {
+		int pos = ftell(in);
+		fseek(in, 0, 2);
+		filesize = ftell(in);
+		fseek(in, pos, 0);
+		if (pos+blocks*4 >= filesize) {
+			fprintf(stderr,"offset block is not exist\n");
+			return;
+		}
+	}
+	if (complevel == -1) return;
+	/* offset index 読み込み */
+	offsets = new int[blocks];
+	fread(offsets, blocks, 4, in);
+	for (i=0; i<blocks; i++) {
+		offsets[i] = read_little_endian_int((char*)(offsets+i));
+	}
+	if (feof(in) || ferror(in)) {
+		fprintf(stderr,"invalid stream\n");
+		delete[] offsets;
+		offsets = 0;
+		return;
+	}
+	return;
+}
+void NWAData::Rewind(FILE* in) {
+	curblock = -1;
+	fseek(in, 0x2c, 0);
+	if (offsets) fseek(in, blocks*4, 1);
+}
+int NWAData::CheckHeader(void) {
+	if (complevel != -1 && offsets == 0) return false;
+	/* データそのもののチェック */
+	if (channels != 1 && channels != 2) {
+		fprintf(stderr,"This program only supports mono / stereo data : data have %d channels.\n",channels);
+		return false;
+	}
+	if (bps != 8 && bps != 16) {
+		fprintf(stderr,"This program only supports 8 / 16bit data : data is %d bits\n",bps);
+		return false;
+	}
+	if (complevel == -1) {
+		int byps = bps/8; /* bytes per sample */
+		if (datasize != samplecount*byps) {
+			fprintf(stderr,"invalid datasize : datasize %d != samplecount %d * samplesize %d\n",datasize,samplecount,byps);
+			return false;
+		}
+		if (samplecount != (blocks-1)*blocksize+restsize ) {
+			fprintf(stderr,"total sample count is invalid : samplecount %d != %d*%d+%d(block*blocksize+lastblocksize).\n",samplecount,blocks-1,blocksize,restsize);
+			return false;
+		}
+		else
+			return true;
+	}
+	//if (complevel < 0 || complevel > 2) {
+	if (complevel < 0 || complevel > 5) {
+		fprintf(stderr,"This program only supports -1,0,1,2 compression level : the level of data is %d\n",complevel);
+		return false;
+	}
+	/* 整合性チェック */
+	if (filesize != 0 && filesize != compdatasize) {
+		fprintf(stderr,"file size is invalid : %d != %d\n",filesize,compdatasize);
+		return false;
+	}
+	if (offsets[blocks-1] >= compdatasize) {
+		fprintf(stderr,"the last offset overruns the file.\n");
+		return false;
+	}
+	int byps = bps/8; /* bytes per sample */
+	if (datasize != samplecount*byps) {
+		fprintf(stderr,"invalid datasize : datasize %d != samplecount %d * samplesize %d\n",datasize,samplecount,byps);
+		return false;
+	}
+	if (samplecount != (blocks-1)*blocksize+restsize ) {
+		fprintf(stderr,"total sample count is invalid : samplecount %d != %d*%d+%d(block*blocksize+lastblocksize).\n",samplecount,blocks-1,blocksize,restsize);
+		return false;
+	}
+	tmpdata = new char[blocksize*byps*2]; /* これ以上の大きさはないだろう、、、 */
+	return true;
+}
+
+class NWAInfo_sw2 {
+public:
+	int Channels(void) const{return 2;}
+	int Bps(void) const { return 16;}
+	int CompLevel(void) const { return 2;}
+	int UseRunLength(void) const { return false; }
+};
+int NWAData::Decode(FILE* in, char* data, int& skip_count) {
+	if (complevel == -1) {		/* 無圧縮時の処理 */
+		if (feof(in) || ferror(in)) return -1;
+		if (curblock == -1) {
+			/* 最初のブロックなら、wave header 出力 */
+			memcpy(data, make_wavheader(datasize, channels, bps, freq), 0x2c);
+			curblock++;
+			fseek(in, offset_start + 0x2c, SEEK_SET);
+			return 0x2c;
+		}
+		if (skip_count > blocksize/channels) {
+			skip_count -= blocksize/channels;
+			fseek(in, blocksize*(bps/8), SEEK_CUR);
+			curblock++;
+			return -2;
+		}
+		if (curblock < blocks) {
+			int readsize = blocksize;
+			if (skip_count) {
+				fseek(in, skip_count*channels*(bps/8), SEEK_CUR);
+				readsize -= skip_count * channels;
+				skip_count = 0;
+			}
+			int err = fread(data, 1, readsize * (bps/8), in);
+			curblock++;
+			return err;
+		}
+		return -1;
+	}
+	if (offsets == 0 || tmpdata == 0) return -1;
+	if (blocks == curblock) return 0;
+	if (feof(in) || ferror(in)) return -1;
+	if (curblock == -1) {
+		/* 最初のブロックなら、wave header 出力 */
+		memcpy(data, make_wavheader(datasize, channels, bps, freq), 0x2c);
+		curblock++;
+		return 0x2c;
+	}
+	/* 今回読み込む/デコードするデータの大きさを得る */
+	int curblocksize, curcompsize;
+	if (curblock != blocks-1) {
+		curblocksize = blocksize * (bps/8);
+		curcompsize = offsets[curblock+1] - offsets[curblock];
+		if (curblocksize >= blocksize*(bps/8)*2) return -1; // Fatal error
+	} else {
+		curblocksize = restsize * (bps/8);
+		curcompsize = blocksize*(bps/8)*2;
+	}
+	if (skip_count > blocksize/channels) {
+		skip_count -= blocksize/channels;
+		fseek(in, curcompsize, SEEK_CUR);
+		curblock++;
+		return -2;
+	}
+	/* データ読み込み */
+	fread(tmpdata, 1, curcompsize, in);
+	/* 展開 */
+	if (channels == 2 && bps == 16 && complevel == 2) {
+		NWAInfo_sw2 info;
+		NWADecode(info, tmpdata, data, curcompsize, curblocksize);
+	} else {
+		NWAInfo info(channels, bps, complevel);
+		NWADecode(info, tmpdata, data, curcompsize, curblocksize);
+	}
+	int retsize = curblocksize;
+	if (skip_count) {
+		int skip_c = skip_count * channels * (bps/8);
+		retsize -= skip_c;
+		memmove(data, data+skip_c, skip_c);
+		skip_count = 0;
+	}
+	curblock++;
+	return retsize;
+}
+
+#ifdef USE_MAIN
+
+void conv(FILE* in, FILE* out, int skip_count, int in_size = -1) {
+	NWAData h;
+	h.ReadHeader(in, in_size);
+	h.CheckHeader();
+	int bs = h.BlockLength();
+	char* d = new char[bs];
+	int err;
+	while( (err=h.Decode(in, d, skip_count)) != 0) {
+		if (err == -1) break;
+		if (err == -2) continue;
+		fwrite(d, err, 1, out);
+	}
+	return;
+}
+int main(int argc, char** argv) {
+	int skip_count = 0;
+
+	if (argc > 2 && strcmp(argv[1], "--skip") == 0) {
+		skip_count = atoi(argv[2]);
+		argc -= 2;
+		argv[1] = argv[3];
+		argv[2] = argv[4];
+	}
+	if (argc != 2 && argc != 3) {
+		fprintf(stderr,"usage : nwatowav [inputfile [outputfile]]\n");
+		return -1;
+	}
+	if (strstr(argv[1], ".nwk") != 0 || strstr(argv[1], ".ovk") != 0) {
+		bool is_ovk;
+		int headblk_sz;
+		char* out_ext;
+
+		char* outpath = new char[strlen(argv[1])+10];
+		char buf[1024];
+		memset(buf, 0, 1024);
+		FILE* in = fopen(argv[1], "rb");
+		if (in == 0) {
+			fprintf(stderr,"Cannot open file : %s\n",argv[1]);
+			return -1;
+		}
+		if (strstr(argv[1], ".ovk") != 0) {
+			is_ovk = true;
+			headblk_sz = 16; 
+			out_ext = "ogg";
+		} else {
+			is_ovk = false;
+			headblk_sz = 12;
+			out_ext = "wav";
+		}
+		fread(buf, 1, 4, in);
+		int index = read_little_endian_int(buf);
+		if (index <= 0) { 
+			if (is_ovk)
+				fprintf(stderr,"Invalid Ogg-ovk file : %s : index = %d\n",argv[1],index);
+			else
+				fprintf(stderr,"Invalid Koe-nwk file : %s : index = %d\n",argv[1],index);
+			return -1;
+		}
+		int* tbl_off = new int[index];
+		int* tbl_siz = new int[index];
+		int* tbl_cnt = new int[index];
+		int* tbl_origsiz = new int[index];
+		int i;
+		for (i=0; i<index; i++) {
+			fread(buf, 1, headblk_sz, in);
+			tbl_siz[i] = read_little_endian_int(buf);
+			tbl_off[i] = read_little_endian_int(buf+4);
+			tbl_cnt[i] = read_little_endian_int(buf+8);
+			tbl_origsiz[i] = read_little_endian_int(buf+12);
+		}
+		fseek(in, 0, 2);
+		int fsize = ftell(in);
+		for (i=0; i<index; i++) {
+			if (tbl_off[i] <= 0 || tbl_siz[i] <= 0 || tbl_off[i]+tbl_siz[i] > fsize) {
+				fprintf(stderr,"Invalid table[%d] : cnt %d off %d size %d / %d\n",i,tbl_cnt[i],tbl_off[i],tbl_siz[i],fsize);
+				continue;
+			}
+			if (argc == 2)
+				sprintf(outpath, "%s-%d.%s", argv[1], tbl_cnt[i],out_ext);
+			else
+				sprintf(outpath, "%s-%d.%s", argv[2], tbl_cnt[i],out_ext);
+			FILE* out = fopen(outpath, "wb");
+			if (out == 0) {
+				fprintf(stderr,"Cannot open output file %s\n",outpath);
+				continue;
+			}
+			fprintf(stderr,"Writing file %s...\n",outpath);
+			fseek(in, tbl_off[i], 0);
+			if (is_ovk) { // copy file
+				int sz = tbl_siz[i];
+				char buf[32*1024];
+				while(sz > 32*1024) {
+					fread(buf, 32*1024, 1, in);
+					fwrite(buf, 32*1024, 1, out);
+					sz -= 1024*32;
+				}
+				if (sz > 0) {
+					fread(buf, sz, 1, in);
+					fwrite(buf, sz, 1, out);
+				}
+			} else { // .nwk
+				conv(in, out, 0, tbl_siz[i]);
+			}
+			fclose(out);
+		}
+		fclose(in);
+		return 0;
+	}
+	FILE* in = fopen(argv[1],"rb");
+	if (in == 0) {
+		fprintf(stderr,"Cannot open file : %s\n",argv[1]);
+		return -1;
+	}
+	FILE* out;
+	if (argc != 3 && (!isatty(fileno(stdout)))) {	// wave file is written to stdout if stdout is redirected to a file
+		out = stdout;
+	} else {					// make a new file or use argv[2] for output file name
+		char* outpath = new char[strlen(argv[1])+10];
+		sprintf(outpath, "%s.wav",argv[1]);
+		if (argc == 3) outpath = argv[2];
+		out = fopen(outpath, "wb");
+		if (out == 0) {
+			fprintf(stderr,"Cannot open file : %s\n",outpath);
+			return -1;
+		}
+	}
+	conv(in, out, skip_count);
+	fclose(in);
+	if (out != stdout) fclose(out);
+	return 0;
+}
+#else
+
+#include"wavfile.h"
+
+void NWAFILE::Seek(int count) {
+	if (data == 0) data = new char[block_size];
+	nwa->Rewind(stream);
+	int dmy = 0;
+	nwa->Decode(stream, data, dmy); // skip wav header
+	data_len = 0;
+	skip_count = count;
+}
+NWAFILE::NWAFILE(FILE* _stream) {
+	skip_count = 0;
+	data = 0;
+	stream = _stream;
+	nwa = new NWAData;
+	nwa->ReadHeader(stream);
+	if (!nwa->CheckHeader()) {
+		return;
+	}
+	block_size = nwa->BlockLength();
+	data = new char[block_size];
+	data_len = 0;
+
+	wavinfo.SamplingRate = nwa->freq;
+	wavinfo.Channels = nwa->channels;
+	wavinfo.DataBits = nwa->bps;
+
+	int dmy = 0;
+	data_len = nwa->Decode(stream, data, dmy); // skip wav header
+
+	return;
+}
+NWAFILE::~NWAFILE() {
+	if (stream) fclose(stream);
+	if (data) delete[] data;
+	if (nwa) delete nwa;
+}
+int NWAFILE::Read(char* buf, int blksize, int blklen) {
+	if (data == 0) return -1; // end of file
+
+	if (data_len > blksize * blklen) {
+		int len = blksize * blklen;
+		memcpy(buf, data, len);
+		memmove(data, data+len, data_len-len);
+		data_len -= len;
+		return blklen;
+	}
+	memcpy(buf, data, data_len);
+	int copied_length = data_len;
+	data_len = 0;
+
+	if (stream == 0) {
+		delete[] data;
+		data = 0;
+		return copied_length / blksize;
+	}
+
+	// read
+	do {
+		int err;
+retry:
+		err = nwa->Decode(stream, data, skip_count);
+		if (err == 0 || err == -1) { // eof or error
+			delete[] data;
+			data = 0;
+			return copied_length / blksize;
+		}
+		if (err == -2) goto retry; // EAGAIN
+		data_len = err;
+		if (copied_length + data_len < blklen*blksize) {
+			memcpy(buf+copied_length, data, data_len);
+			copied_length += data_len;
+			goto retry;
+		}
+	} while(0);
+
+	// determine return length
+	int datablks = (data_len+copied_length)/blksize;
+	if (datablks <= 0) return 0;
+	if (datablks > blklen) datablks = blklen;
+	int rest_len = datablks * blksize - copied_length;
+	if (rest_len) {
+		memcpy(buf+copied_length, data, rest_len);
+		memmove(data, data+rest_len, data_len-rest_len);
+		data_len -= rest_len;
+	}
+	return datablks;
+}
+
+char* NWAFILE::ReadAll(FILE* in, int& total_size) {
+	NWAData h;
+	if (in == 0) return 0;
+	h.ReadHeader(in);
+	h.CheckHeader();
+	int bs = h.BlockLength();
+	total_size = h.datasize+0x2c;
+	char* d = new char[total_size + bs*2];
+	int dcur = 0;
+	int err;
+	int skip = 0;
+	while(dcur < total_size+bs && (err=h.Decode(in, d+dcur, skip)) != 0) {
+		if (err == -1) break;
+		if (err == -2) continue;
+		dcur += err;
+	}
+	return d;
+}
+
+#include"music.h"
+
+char* decode_koe_nwa(AvgKoeInfo info, int* data_len) {
+	NWAData h;
+	if (info.stream == 0) return 0;
+	fseek(info.stream, info.offset, 0);
+	h.ReadHeader(info.stream, info.length);
+	if (h.CheckHeader() == false) return 0;
+	int bs = h.BlockLength();
+	int total = h.datasize + 0x2c;
+	char* d = new char[total + bs*2];
+	int dcur = 0;
+	int err;
+	int skip = 0;
+	while(dcur < total+bs && (err=h.Decode(info.stream, d+dcur, skip)) != 0) {
+		if (err == -1) break;
+		if (err == -2) continue;
+		dcur += err;
+	}
+	if (data_len) {
+		*data_len = dcur;
+		if (*data_len > total) *data_len = total;
+	}
+	return d;
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/music2/wavfile.cc
@@ -0,0 +1,808 @@
+/*
+ * wavfile.c  WAV file check
+ *
+ *  Copyright: wavfile.c (c) Erik de Castro Lopo  erikd@zip.com.au
+ *
+ *  Modified : 1997-1998 Masaki Chikama (Wren) <chikama@kasumi.ipl.mech.nagoya-u.ac.jp>
+ *             1998-                           <masaki-c@is.aist-nara.ac.jp>
+ *             2000-     Kazunori Ueno(JAGARL) <jagarl@createor.club.ne.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+*/
+
+#include        <stdarg.h>
+#include  	<stdio.h>
+#include  	<stdlib.h>
+#include	<errno.h>
+#include	<sys/types.h>
+#include	<unistd.h>
+#include  	<string.h>
+#include        "wavfile.h"
+#include        "system/file.h"
+#include        "music.h"
+
+#define		BUFFERSIZE   		1024
+#define		PCM_WAVE_FORMAT   	1
+
+/*******************************************************
+**
+**	WAVE Header
+*/
+
+inline int LittleEndian_getDW(const char *b,int index) {
+	int c0, c1, c2, c3;
+	int d0, d1;
+	c0 = *(const unsigned char*)(b + index + 0);
+	c1 = *(const unsigned char*)(b + index + 1);
+	c2 = *(const unsigned char*)(b + index + 2);
+	c3 = *(const unsigned char*)(b + index + 3);
+	d0 = c0 + (c1 << 8);
+	d1 = c2 + (c3 << 8);
+	return d0 + (d1 << 16);
+}
+
+inline int LittleEndian_get3B(const char *b,int index) {
+	int c0, c1, c2;
+	c0 = *(const unsigned char*)(b + index + 0);
+	c1 = *(const unsigned char*)(b + index + 1);
+	c2 = *(const unsigned char*)(b + index + 2);
+	return c0 + (c1 << 8) + (c2 << 16);
+}
+
+inline int LittleEndian_getW(const char *b,int index) {
+	int c0, c1;
+	c0 = *(const unsigned char*)(b + index + 0);
+	c1 = *(const unsigned char*)(b + index + 1);
+	return c0 + (c1 << 8);
+}
+
+inline void LittleEndian_putW(int num, char *b, int index) {
+	int c0, c1;
+	num %= 65536;
+	c0 = num % 256;
+	c1 = num / 256;
+	b[index] = c0; b[index+1] = c1;
+}
+
+typedef  struct
+{	u_long     dwSize ;
+	u_short    wFormatTag ;
+	u_short    wChannels ;
+	u_long     dwSamplesPerSec ;
+	u_long     dwAvgBytesPerSec ;
+	u_short    wBlockAlign ;
+	u_short    wBitsPerSample ;
+} WAVEFORMAT ;
+
+typedef  struct
+{	char    	RiffID [4] ;
+	u_long    	RiffSize ;
+	char    	WaveID [4] ;
+	char    	FmtID  [4] ;
+	u_long    	FmtSize ;
+	u_short   	wFormatTag ;
+	u_short   	nChannels ;
+	u_long		nSamplesPerSec ;
+	u_long		nAvgBytesPerSec ;
+	u_short		nBlockAlign ;
+	u_short		wBitsPerSample ;
+	char		DataID [4] ;
+	u_long		nDataBytes ;
+} WAVE_HEADER ;
+
+
+static void waveFormatCopy( WAVEFORMAT* wav, char *ptr );
+static char*  findchunk (char* s1, char* s2, size_t n) ;
+
+static int  WaveHeaderCheck  (char *wave_buf,int* channels, u_long* samplerate, int* samplebits, u_long* samples,u_long* datastart)
+{	
+	static  WAVEFORMAT  waveformat ;
+	char*   ptr ;
+	u_long  databytes ;
+
+	if (findchunk (wave_buf, "RIFF", BUFFERSIZE) != wave_buf) {
+		fprintf(stderr, "Bad format: Cannot find RIFF file marker");
+		return  WR_BADRIFF ;
+	}
+
+	if (! findchunk (wave_buf, "WAVE", BUFFERSIZE)) {
+		fprintf(stderr, "Bad format: Cannot find WAVE file marker");
+		return  WR_BADWAVE ;
+	}
+
+	ptr = findchunk (wave_buf, "fmt ", BUFFERSIZE) ;
+
+	if (! ptr) {
+		fprintf(stderr, "Bad format: Cannot find 'fmt' file marker");
+		return  WR_BADFORMAT ;
+	}
+
+	ptr += 4 ;	/* Move past "fmt ".*/
+	waveFormatCopy( &waveformat, ptr );
+	
+	if (waveformat.dwSize != (sizeof (WAVEFORMAT) - sizeof (u_long))) {
+		/* fprintf(stderr, "Bad format: Bad fmt size"); */
+		/* return  WR_BADFORMATSIZE ; */
+	}
+
+	if (waveformat.wFormatTag != PCM_WAVE_FORMAT) {
+		fprintf(stderr, "Only supports PCM wave format");
+		return  WR_NOTPCMFORMAT ;
+	}
+
+	ptr = findchunk (wave_buf, "data", BUFFERSIZE) ;
+
+	if (! ptr) {
+		fprintf(stderr,"Bad format: unable to find 'data' file marker");
+		return  WR_NODATACHUNK ;
+	}
+
+	ptr += 4 ;	/* Move past "data".*/
+	databytes = LittleEndian_getDW(ptr, 0);
+	
+	/* Everything is now cool, so fill in output data.*/
+
+	*channels   = waveformat.wChannels;
+	*samplerate = waveformat.dwSamplesPerSec ;
+	*samplebits = waveformat.wBitsPerSample ;
+	*samples    = databytes / waveformat.wBlockAlign ;
+	
+	*datastart  = (u_long)(ptr) + 4;
+
+	if (waveformat.dwSamplesPerSec != waveformat.dwAvgBytesPerSec / waveformat.wBlockAlign) {
+		fprintf(stderr, "Bad file format");
+		return  WR_BADFORMATDATA ;
+	}
+
+	if (waveformat.dwSamplesPerSec != waveformat.dwAvgBytesPerSec / waveformat.wChannels / ((waveformat.wBitsPerSample == 16) ? 2 : 1)) {
+		fprintf(stderr, "Bad file format");
+		return  WR_BADFORMATDATA ;
+	}
+
+	return  0 ;
+} ; /* WaveHeaderCheck*/
+
+
+static char* findchunk  (char* pstart, char* fourcc, size_t n)
+{	char	*pend ;
+	int		k, test ;
+
+	pend = pstart + n ;
+
+	while (pstart < pend)
+	{ 
+		if (*pstart == *fourcc)       /* found match for first char*/
+		{	test = 1 ;
+			for (k = 1 ; fourcc [k] != 0 ; k++)
+				test = (test ? ( pstart [k] == fourcc [k] ) : 0) ;
+			if (test)
+				return  pstart ;
+			} ; /* if*/
+		pstart ++ ;
+		} ; /* while lpstart*/
+
+	return  NULL ;
+} ; /* findchuck*/
+
+static void waveFormatCopy( WAVEFORMAT* wav, char *ptr ) {
+	wav->dwSize           = LittleEndian_getDW( ptr,  0 );
+	wav->wFormatTag       = LittleEndian_getW(  ptr,  4 );
+	wav->wChannels        = LittleEndian_getW(  ptr,  6 );
+	wav->dwSamplesPerSec  = LittleEndian_getDW( ptr,  8 );
+	wav->dwAvgBytesPerSec = LittleEndian_getDW( ptr, 12 );
+	wav->wBlockAlign      = LittleEndian_getW(  ptr, 16 );
+	wav->wBitsPerSample   = LittleEndian_getW(  ptr, 18 );
+}
+
+static char* WavGetInfo(WAVFILE* wfile, char *data) {
+	int e;					/* Saved errno value */
+	int channels;				/* Channels recorded in this wav file */
+	u_long samplerate;			/* Sampling rate */
+	int sample_bits;			/* data bit size (8/12/16) */
+	u_long samples;				/* The number of samples in this file */
+	u_long datastart;			/* The offset to the wav data */
+
+	if ( (e = WaveHeaderCheck(data,
+				  &channels,&samplerate,
+				  &sample_bits,&samples,&datastart) != 0 )) {
+		fprintf(stderr,"WavGetInfo(): Reading WAV header\n");
+		return 0;
+	}
+	
+	/*
+	 * Copy WAV data over to WAVFILE struct:
+	 */
+	wfile->wavinfo.Channels = channels;
+
+	wfile->wavinfo.SamplingRate = (unsigned int) samplerate;
+	wfile->wavinfo.DataBits = (unsigned short) sample_bits;
+
+	return (char *) datastart;
+}
+
+/************************************************************:
+**
+**	WAVFILE stream reader
+*/
+
+#include<SDL_mixer.h>
+WAVFILE::WAVFILE(void) {
+	wavinfo.SamplingRate=0;
+	wavinfo.Channels=1;
+	wavinfo.DataBits=0;
+}
+
+int WAVFILE_Stream::Read(char* in_buf, int blksize, int length) {
+	/* ファイルの読み込み */
+	if (data_length == 0 && stream_length == 0) return -1;
+	/* wf->data にデータの残りがあればそれも読み込む */
+	if (data_length > blksize*length) {
+		memcpy(in_buf, data, blksize*length);
+		data += blksize * length;
+		data_length -= blksize * length;
+		return length;
+	}
+	memcpy(in_buf, data, data_length);
+	if (stream_length != -1 && stream_length < blksize*length-data_length) {
+		length = (stream_length+data_length+blksize-1)/blksize;
+	}
+	int read_len = 0;
+	if (blksize*length-data_length > 0) {
+		read_len = fread(in_buf+data_length, 1, blksize*length-data_length, stream);
+		if (stream_length != -1 && stream_length > read_len) stream_length -= read_len;
+		if (feof(stream)) stream_length = 0; // end of file
+	} else {
+		stream_length = 0; // all data were read
+	}
+	int blklen = (read_len + data_length) / blksize;
+	data_length = 0;
+	return blklen;
+}
+void WAVFILE_Stream::Seek(int count) {
+        int blksize = 1;
+        /* block size の設定 */
+	blksize *= wavinfo.Channels * (wavinfo.DataBits/8);
+	data_length = 0;
+	stream_length = stream_length_orig - stream_top - count*blksize;
+	fseek(stream, count*blksize+stream_top, 0);
+}
+WAVFILE_Stream::WAVFILE_Stream(FILE* _stream, int _length) {
+	stream = _stream;
+	stream_length = _length;
+	stream_length_orig = _length;
+	data_orig = new char[1024];
+	data = data_orig;
+	data_length = 1024;
+	if (stream_length != -1 && stream_length < data_length) {
+		data_length = stream_length;
+	}
+	fread(data, data_length, 1, stream);
+	if (stream_length != -1)
+		stream_length -= data_length;
+	data = WavGetInfo(this, data);
+	if (data == 0) {
+		stream_length = 0;
+		data_length = 0;
+		return;
+	}
+	stream_top = data - data_orig;
+	data_length -= data - data_orig;
+	return;
+}
+WAVFILE_Stream::~WAVFILE_Stream() {
+	if (data_orig) delete data_orig;
+	if (stream) fclose(stream);
+	return;
+}
+/************************************************************:
+**
+**	WAVE format converter with SDL_audio
+*/
+WAVFILE* WAVFILE::MakeConverter(WAVFILE* new_reader) {
+	bool need = false;
+	if (new_reader->wavinfo.SamplingRate != freq) need = true;
+	if (new_reader->wavinfo.Channels != channels) need = true;
+	if (format == AUDIO_S8) {
+		if (new_reader->wavinfo.DataBits != 8) need = true;
+	} else if (format == AUDIO_S16) {
+		if (new_reader->wavinfo.DataBits != 16) need = true;
+	} else {
+		need = true;
+	}
+	if (!need) return new_reader;
+	/* 変換もとのフォーマットを得る */
+	int from_format;
+	if (new_reader->wavinfo.DataBits == 8) from_format = AUDIO_S8;
+	else from_format = AUDIO_S16;
+	SDL_AudioCVT* cvt = new SDL_AudioCVT;
+	int ret = SDL_BuildAudioCVT(cvt, from_format, new_reader->wavinfo.Channels, freq,
+		format, 2, freq);
+	if (ret == -1) {
+		delete cvt;
+		fprintf(stderr,"Cannot make wave file converter!!!\n");
+		return new_reader;
+	}
+	WAVFILE_Converter* conv = new WAVFILE_Converter(new_reader, cvt);
+	return conv;
+}
+WAVFILE_Converter::WAVFILE_Converter(WAVFILE* _orig, SDL_AudioCVT* _cvt) {
+	original = _orig;
+	cvt = _cvt;
+	//datasize = 4096*4;
+	datasize = 48000;
+	cvt->buf = new Uint8[datasize*cvt->len_mult];
+	cvt->len = 0;
+	tmpbuf = new char[datasize*cvt->len_mult + 1024];
+	memset(tmpbuf, 0, datasize*cvt->len_mult+1024);
+};
+
+static int conv_wave_rate(short* in_buf, int length, int in_rate, int out_rate, char* tmpbuf);
+WAVFILE_Converter::~WAVFILE_Converter() {
+	if (cvt) {
+		if (cvt->buf) delete cvt->buf;
+		delete cvt;
+		cvt = 0;
+	}
+	if (original) delete original;
+	original = 0;
+}
+int WAVFILE_Converter::Read(char* buf, int blksize, int blklen) {
+	if (original == 0 || cvt == 0) return -1;
+	int copied_length = 0;
+	if (cvt->len < blksize*blklen) {
+		memcpy(buf, cvt->buf, cvt->len);
+		copied_length += cvt->len;
+		do {
+			int cnt = original->Read((char*)cvt->buf, 1, datasize);
+			if (cnt <= 0) {
+				cvt->len = 0;
+				break;
+			}
+			cvt->len = cnt;
+			SDL_ConvertAudio(cvt);
+			if (freq < original->wavinfo.SamplingRate) { // rate conversion は SDL_ConvertAudio ではうまく行かない
+				// 48000Hz -> 44100Hz or 22050Hz などを想定
+				// 長さは短くなるはずなので、特に処理はなし
+				cvt->len = conv_wave_rate( (short*)(cvt->buf), cvt->len_cvt/4, original->wavinfo.SamplingRate, freq, tmpbuf);
+				cvt->len *= 4;
+			} else {
+				cvt->len = cvt->len_cvt;
+			}
+			if (cvt->len+copied_length > blksize*blklen) break;
+			memcpy(buf+copied_length, cvt->buf, cvt->len);
+			copied_length += cvt->len;
+		} while(1);
+	}
+	if (cvt->len == 0 && copied_length == 0) return -1;
+	else if (cvt->len > 0) {
+		int len = blksize * blklen - copied_length;
+		memcpy(buf+copied_length, cvt->buf, len);
+		memmove(cvt->buf, cvt->buf+len, cvt->len-len);
+		copied_length += len;
+		cvt->len -= len;
+	}
+	return copied_length / blksize;
+}
+/* format は signed, 16bit, little endian, stereo と決めうち
+** 場合によっていは big endian になることもあるかも。
+*/
+static int conv_wave_rate(short* in_buf, int length, int in_rate, int out_rate, char* tmpbuf) {
+	int input_rate = in_rate;
+	int output_rate = out_rate;
+	double input_rate_d = input_rate, output_rate_d = output_rate;
+	double dtime; int outlen; short* out, * out_orig; int next_sample1, next_sample2;
+	short* in_buf_orig = in_buf;
+	int i; int time;
+
+	if (input_rate == output_rate) return length;
+	if (length <= 0) return 0;
+	/* 一般の周波数変換:線型補完 */
+	int& first_flag = *(int*)(tmpbuf);
+	int& prev_time = *(int*)(tmpbuf+4);
+	int& prev_sample1 = *(int*)(tmpbuf+8);
+	int& prev_sample2 = *(int*)(tmpbuf+12);
+	out = (short*)(tmpbuf+16);
+	/* 初めてならデータを初期化 */
+	if (first_flag == 0) {
+		first_flag = 1;
+		prev_time = 0;
+		prev_sample1 = short(read_little_endian_short((char*)(in_buf++)));
+		prev_sample2 = short(read_little_endian_short((char*)(in_buf++)));
+		length--;
+	}
+	/* 今回作成するデータ量を得る */
+	dtime = prev_time + length * output_rate_d;
+	outlen = (int)(dtime / input_rate_d);
+	out_orig = out;
+	if (first_flag == 1) {
+		write_little_endian_short((char*)out, prev_sample1);
+		out++;
+		write_little_endian_short((char*)out, prev_sample2);
+		out++;
+	}
+	dtime -= input_rate_d*outlen; /* 次の prev_time */
+
+	time=0;
+	next_sample1 = short(read_little_endian_short((char*)(in_buf++)));
+	next_sample2 = short(read_little_endian_short((char*)(in_buf++)));
+	for (i=0; i<outlen; i++) {
+		/* double で計算してみたけどそう簡単には高速化は無理らしい */
+		/* なお、変換は 1分のデータに1秒程度かかる(Celeron 700MHz) */
+		time += input_rate;
+		while(time-prev_time>output_rate) {
+			prev_sample1 = next_sample1;
+			next_sample1 = short(read_little_endian_short((char*)(in_buf++)));
+			prev_sample2 = next_sample2;
+			next_sample2 = short(read_little_endian_short((char*)(in_buf++)));
+			prev_time += output_rate;
+		}
+		write_little_endian_short((char*)out,
+			((time-prev_time)*next_sample1 +
+			(input_rate-time+prev_time)*prev_sample1) / input_rate);
+		out++;
+		write_little_endian_short((char*)out,
+			((time-prev_time)*next_sample2 +
+			(input_rate-time+prev_time)*prev_sample2) / input_rate);
+		*out++;
+	}
+	prev_time += output_rate; prev_time -= input_rate * outlen;
+	prev_sample1 = next_sample1; prev_sample2 = next_sample2;
+	if (first_flag == 1) {
+		outlen++; first_flag = 2;
+	}
+	memcpy(in_buf_orig, out_orig, outlen*2*sizeof(short));
+	return outlen;
+}
+
+
+/************************************************************:
+**
+**	MP3FILE stream reader
+*/
+
+int WAVFILE::freq = 48000;
+int WAVFILE::channels = 2;
+int WAVFILE::format = MIX_DEFAULT_FORMAT;
+
+#if HAVE_LIBMAD
+
+#include<mad.h>
+#define MPEG_BUFSZ       40000   /* 2.5 s at 128 kbps; 1 s at 320 kbps */
+struct MP3FILE_impl {
+	enum { PREPARE, RUN, WRITE, DONE} status;
+	struct mad_decoder decoder;
+	char* data;
+	int data_len;
+	char* write_data;
+	unsigned int write_data_len;
+	unsigned int write_pointer;
+	unsigned int src_pointer;
+	FILE* stream;
+	MP3FILE_impl(FILE*);
+	~MP3FILE_impl();
+	static enum mad_flow callback_read(void *data, struct mad_stream *stream);
+	static enum mad_flow callback_error(void *data, struct mad_stream *stream, struct mad_frame *frame);
+	static enum mad_flow callback_write(void *data, struct mad_header const *header, struct mad_pcm *pcm);
+	enum mad_flow callback_write_impl(struct mad_pcm *pcm);
+	void run(void);
+};
+
+MP3FILE_impl::MP3FILE_impl(FILE* _stream) {
+	stream = _stream;
+	data = new char[MPEG_BUFSZ];
+	data_len = 0;
+	src_pointer = 0;
+	write_data = 0;
+	write_data_len = 0;
+	write_pointer = 0;
+
+	/* initialize decoder */
+	mad_decoder_init(&decoder, (void*)this, callback_read, 0 /* header */, 0 /* filter */, callback_write,
+ 			callback_error, 0 /* message */);
+	/* prepare stream */
+	status = PREPARE;
+	*(void**)(&decoder.sync) = malloc(sizeof(*decoder.sync));
+
+	mad_stream_init(&decoder.sync->stream);
+	mad_frame_init(&decoder.sync->frame);
+	mad_synth_init(&decoder.sync->synth);
+
+	mad_stream_options(&decoder.sync->stream, decoder.options);
+
+	while(status != WRITE && status != DONE) run();
+}
+MP3FILE_impl::~MP3FILE_impl() {
+	free(decoder.sync);
+	mad_decoder_finish(&decoder);
+	delete[] data;
+	return;
+}
+
+void MP3FILE_impl::run(void) {
+	if (status == DONE) return;
+	struct mad_stream *stream = &decoder.sync->stream;
+	struct mad_frame *frame = &decoder.sync->frame;
+	struct mad_synth *synth = &decoder.sync->synth;
+	if (status == PREPARE) {
+		switch (decoder.input_func(decoder.cb_data, stream)) {
+		case MAD_FLOW_STOP:
+		case MAD_FLOW_BREAK:
+			goto done;
+		case MAD_FLOW_CONTINUE:
+			status = RUN;
+		case MAD_FLOW_IGNORE:
+			break;
+		}
+		return;
+	}
+	if (status == RUN) {
+		if (mad_frame_decode(frame, stream) == -1) {
+			if (!MAD_RECOVERABLE(stream->error)) {
+				status = PREPARE;
+				return;
+			}
+			switch (decoder.error_func((void*)this, stream, frame)) {
+			case MAD_FLOW_STOP:
+			case MAD_FLOW_BREAK:
+				goto done;
+			case MAD_FLOW_IGNORE:
+				status = PREPARE;
+				return;
+			case MAD_FLOW_CONTINUE:
+			default:
+				return;
+			}
+		}
+
+		mad_synth_frame(synth, frame);
+		src_pointer = 0;
+		status = WRITE;
+		return;
+	}
+	if (status == WRITE) {
+		switch (decoder.output_func(decoder.cb_data, &frame->header, &synth->pcm)) {
+		case MAD_FLOW_STOP:
+		case MAD_FLOW_BREAK:
+			goto done;
+		case MAD_FLOW_IGNORE:
+			return;
+		case MAD_FLOW_CONTINUE:
+			status = RUN;
+			break;
+		}
+		if (stream->error == MAD_ERROR_BUFLEN) {
+			stream->error = MAD_ERROR_NONE;
+			status = PREPARE;
+		}
+		return;
+	}
+done:
+	status = DONE;
+	mad_synth_finish(&decoder.sync->synth);
+	mad_frame_finish(&decoder.sync->frame);
+	mad_stream_finish(&decoder.sync->stream);
+	return;
+}
+
+enum mad_flow MP3FILE_impl::callback_read(void *data, struct mad_stream *stream)
+{
+	MP3FILE_impl* impl = (MP3FILE_impl*)data;
+	if (stream->next_frame) {
+		impl->data_len -= (char*)stream->next_frame - impl->data;
+		memmove(impl->data, (char*)stream->next_frame, impl->data_len);
+	} else {
+		impl->data_len = 0;
+	}
+	int count;
+	if (feof(impl->stream)) {
+		if (stream->next_frame && (char*)stream->next_frame - impl->data > 0) {
+			// There is under processing data
+			count = 0;
+		} else {
+			// all data were processed
+			return MAD_FLOW_STOP;
+		}
+	} else {
+		count = fread(impl->data + impl->data_len, 1, MPEG_BUFSZ-impl->data_len, impl->stream);
+		if (count <= 0) {
+			return MAD_FLOW_BREAK;
+		}
+	}
+	impl->data_len += count;
+	if (impl->data_len < MPEG_BUFSZ) {
+		memset(impl->data + impl->data_len, 0, MPEG_BUFSZ-impl->data_len);
+	}
+	mad_stream_buffer(stream, (unsigned char*)impl->data, impl->data_len);
+	return MAD_FLOW_CONTINUE;
+}
+
+enum mad_flow MP3FILE_impl::callback_error(void *data, struct mad_stream *stream, struct mad_frame *frame)
+{
+	MP3FILE_impl* impl = (MP3FILE_impl*)data;
+	fprintf(stdout, "decoding error 0x%04x (%s) at byte offset %u\n",
+	  stream->error, mad_stream_errorstr(stream),
+	  ftell(impl->stream) - ((impl->data+impl->data_len)-(char*)stream->this_frame));
+	/* return MAD_FLOW_BREAK here to stop decoding (and propagate an error) */
+	return MAD_FLOW_CONTINUE;
+}
+signed int scale(mad_fixed_t sample)
+{
+	/* round */
+	sample += (1L << (MAD_F_FRACBITS - 16));
+
+	/* clip */
+	if (sample >= MAD_F_ONE)
+		sample = MAD_F_ONE - 1;
+	else if (sample < -MAD_F_ONE)
+		sample = -MAD_F_ONE;
+
+	/* quantize */
+	return sample >> (MAD_F_FRACBITS + 1 - 16);
+}
+enum mad_flow MP3FILE_impl::callback_write(void *data, struct mad_header const *header, struct mad_pcm *pcm)
+{
+	MP3FILE_impl* pimpl = (MP3FILE_impl*)data;
+	return pimpl->callback_write_impl(pcm);
+}
+enum mad_flow MP3FILE_impl::callback_write_impl(struct mad_pcm *pcm)
+{
+	if (write_data_len == 0) return MAD_FLOW_IGNORE;
+	mad_fixed_t const *left_ch = pcm->samples[0] + src_pointer;
+	mad_fixed_t const *right_ch = pcm->samples[1] + src_pointer;
+
+	unsigned int nchannels = pcm->channels;
+	unsigned int nsamples = pcm->length - src_pointer;
+	if (write_pointer + nsamples * nchannels * 2 > write_data_len) {
+		nsamples = (write_data_len - write_pointer) / nchannels / 2;
+	}
+	write_data_len &= ~(nchannels*2-1);	/* write_data_len はあらかじめ丸めておく */
+	src_pointer += nsamples;
+	if (write_data == 0) { // skip data write
+		write_pointer += nsamples*2*2;
+	} else while(nsamples--) {
+		signed int sample = scale(*left_ch++);
+		write_data[write_pointer++] = sample & 0xff;
+		write_data[write_pointer++] = (sample>>8) & 0xff;
+		if (nchannels == 2) {
+			sample = scale(*right_ch++);
+		}
+		write_data[write_pointer++] = sample & 0xff;
+		write_data[write_pointer++] = (sample>>8) & 0xff;
+	}
+	if (write_pointer >= write_data_len) return MAD_FLOW_IGNORE;
+	else return MAD_FLOW_CONTINUE;
+}
+
+MP3FILE::MP3FILE(FILE* stream, int len) {
+	pimpl = new MP3FILE_impl(stream);
+	if (pimpl->status == MP3FILE_impl::DONE) {
+		delete pimpl;
+		pimpl = 0;
+		fclose(stream);
+		return;
+	}
+	wavinfo.SamplingRate = pimpl->decoder.sync->synth.pcm.samplerate;
+	wavinfo.Channels = 2;
+	wavinfo.DataBits = 16;
+}
+MP3FILE::~MP3FILE() {
+	if (pimpl) {
+		FILE* s = pimpl->stream;
+		delete pimpl;
+		fclose(s);
+	}
+	pimpl = 0;
+}
+int MP3FILE::Read(char* buf, int blksize, int blklen) {
+	if (pimpl == 0) return -1;
+	pimpl->write_data = buf;
+	pimpl->write_data_len = blksize*blklen;
+	pimpl->write_pointer = 0;
+	do {
+		pimpl->run();
+	} while(pimpl->status != MP3FILE_impl::DONE && pimpl->write_pointer < pimpl->write_data_len);
+	return pimpl->write_pointer / blksize;
+}
+void MP3FILE::Seek(int count) {
+	FILE* stream = pimpl->stream;
+	delete pimpl;
+	fseek(stream,0,0);
+	pimpl = new MP3FILE_impl(stream);
+	if (pimpl->status == MP3FILE_impl::DONE) {
+		delete pimpl;
+		pimpl = 0;
+		fclose(stream);
+		return;
+	}
+	int blksize = 1;
+	blksize *= wavinfo.Channels * (wavinfo.DataBits/8);
+	pimpl->write_data = 0;
+	pimpl->write_data_len = count * blksize;
+	pimpl->write_pointer = 0;
+	do {
+		pimpl->run();
+	} while(pimpl->status != MP3FILE_impl::DONE && pimpl->write_pointer < pimpl->write_data_len);
+	return;
+}
+#elif USE_SMPEG
+#include<smpeg/smpeg.h>
+
+struct MP3FILE_impl {
+	SMPEG* info;
+	FILE* stream;
+	MP3FILE_impl(FILE*);
+};
+
+MP3FILE_impl::MP3FILE_impl(FILE* _stream) {
+	stream = _stream;
+	info = SMPEG_new_descr(fileno(stream), NULL, 0);
+fprintf(stderr,"mp3 %x\n",info);
+	if (info && SMPEG_error(info) ) info = 0;
+	SMPEG_enableaudio(info, 0);
+	SMPEG_enableaudio(info, 1);
+	SMPEG_play(info);
+}
+
+MP3FILE::MP3FILE(FILE* stream, int len) {
+	pimpl = new MP3FILE_impl(stream);
+	if (pimpl->info == 0) {
+		delete pimpl;
+		fclose(stream);
+		return;
+	}
+	SDL_AudioSpec fmt;
+	SMPEG_wantedSpec(pimpl->info, &fmt);
+	wavinfo.SamplingRate = fmt.freq;
+	wavinfo.Channels = fmt.channels;
+	wavinfo.DataBits = (fmt.format == AUDIO_S8) ? 8:16;
+}
+MP3FILE::~MP3FILE() {
+	if (pimpl && pimpl->info) {
+		if (SMPEG_status(pimpl->info) == SMPEG_PLAYING) SMPEG_stop(pimpl->info);
+		SMPEG_delete(pimpl->info);
+	}
+	if (pimpl) {
+		fclose(pimpl->stream);
+		delete pimpl;
+		pimpl = 0;
+	}
+}
+int MP3FILE::Read(char* buf, int blksize, int blklen) {
+	if (pimpl == 0 || pimpl->info == 0) return -1;
+	int r = SMPEG_playAudio(pimpl->info, (Uint8*)buf, blksize*blklen);
+	if (r <= 0) { // end of file
+		return -1;
+	}
+	return r / blksize;
+}
+void MP3FILE::Seek(int count) {
+	if (pimpl == 0 || pimpl->info == 0) return;
+	SMPEG_stop(pimpl->info);
+	SMPEG_rewind(pimpl->info);
+	SMPEG_play(pimpl->info);
+	count /= 4;
+	count *= 4; // reduce noise; possibly SMPEG error
+	char* d = new char[count*channels*2];
+	Read(d,count,channels*2);
+	delete[] d;
+	return;
+}
+#else /* SMPEG */
+MP3FILE::MP3FILE(FILE* stream, int len) {pimpl = 0;}
+MP3FILE::~MP3FILE(){}
+void MP3FILE::Seek(int count){}
+int MP3FILE::Read(char* buf, int blksize, int blklen){return -1;}
+#endif /* SMPEG */
new file mode 100644
--- /dev/null
+++ b/music2/wavfile.h
@@ -0,0 +1,121 @@
+/*
+ * wavfile.h  WAV file関連
+ *
+ *  Copyright: wavfile.c (c) Erik de Castro Lopo  erikd@zip.com.au
+ *
+ *  Modified : 1997-1998 Masaki Chikama (Wren) <chikama@kasumi.ipl.mech.nagoya-u.ac.jp>
+ *             1998-                           <masaki-c@is.aist-nara.ac.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+*/
+#ifndef __WAVEFILE__
+#define __WAVEFILE__
+
+#define WW_BADOUTPUTFILE	1
+#define WW_BADWRITEHEADER	2
+
+#define WR_BADALLOC		3
+#define WR_BADSEEK		4
+#define WR_BADRIFF		5
+#define WR_BADWAVE		6
+#define WR_BADFORMAT		7
+#define WR_BADFORMATSIZE	8
+
+#define WR_NOTPCMFORMAT		9
+#define WR_NODATACHUNK		10
+#define WR_BADFORMATDATA	11
+
+/*
+ * These values represent values found in/or destined for a
+ * WAV file.
+ */
+typedef struct {
+	unsigned int	SamplingRate;			/* Sampling rate in Hz */
+	int	Channels;			/* Mono or Stereo */
+	unsigned short	DataBits;			/* Sample bit size (8/12/16) */
+} WAVINF;
+
+struct WAVFILE{
+	WAVINF wavinfo;                         /* WAV file hdr info */
+	WAVFILE(void);
+	static int freq;
+	static int format;
+	static int channels;
+	virtual ~WAVFILE() {};
+	virtual int Read(char* buf, int blksize, int blklen) = 0;
+	virtual void Seek(int count) = 0;
+	static WAVFILE* MakeConverter(WAVFILE* new_reader);
+};
+
+struct WAVFILE_Converter : WAVFILE {
+	WAVFILE* original;
+	struct SDL_AudioCVT* cvt;
+	int datasize;
+	char* tmpbuf;
+	int Read(char* buf, int blksize, int blklen);
+	void Seek(int count) { original->Seek(count);}
+	WAVFILE_Converter(WAVFILE* orig, struct SDL_AudioCVT* cvt);
+	~WAVFILE_Converter();
+};
+
+struct WAVFILE_Stream : WAVFILE{
+	char *data;                             /* real data */ 
+	char *data_orig;
+	int data_length;
+	FILE* stream;
+	int stream_length;
+	int stream_length_orig;
+	int stream_top;
+	int Read(char* buf, int blksize, int blklen);
+	void Seek(int count);
+	WAVFILE_Stream(FILE* stream, int length);
+	~WAVFILE_Stream();
+};
+
+struct NWAFILE : WAVFILE {
+	int skip_count;
+	FILE* stream;
+	struct NWAData* nwa;
+	char* data;
+	int block_size;
+	int data_len;
+
+	NWAFILE(FILE* stream);
+	~NWAFILE();
+	void Seek(int count);
+	int Read(char* buf, int blksize, int blklen);
+	static char* ReadAll(FILE* stream, int& size);
+};
+
+struct OggFILE : WAVFILE {
+	struct OggFILE_impl* pimpl;
+
+	OggFILE(FILE* stream, int size);
+	~OggFILE();
+	void Seek(int count);
+	int Read(char* buf, int blksize, int blklen);
+};
+
+struct MP3FILE : WAVFILE {
+	struct MP3FILE_impl* pimpl;
+
+	MP3FILE(FILE* stream, int size);
+	~MP3FILE();
+	void Seek(int count);
+	int Read(char* buf, int blksize, int blklen);
+};
+
+#endif /* !__WAVEFILE__ */
new file mode 100644
--- /dev/null
+++ b/scn2k/Makefile.in
@@ -0,0 +1,40 @@
+@SET_MAKE@
+CC		= @CC@
+CXX		= @CXX@
+LD		= @CC@
+AR		= ar
+RANLIB		= @RANLIB@
+
+CFLAGS=  -I.. $(LOCAL_DEF) @CFLAGS@ @DEFS@ @SDL_CFLAGS@ -pthread -O2
+CXXFLAGS	= $(CFLAGS)
+LDFLAGS = @LDFLAGS@ -ljpeg @SDL_LIBS@  -lSDL_mixer @SMPEG_LIBS@ @FT2_LIBS@ @LIBS@ -pthread
+
+SRCS	 = scn2k_cmd.cc scn2k_text.cc scn2k_grp.cc scn2k_impl.cc
+
+OBJS	 = ${SRCS:.cc=.o}
+
+all: test libscn2k.a scn2kdump gandump
+
+test: test.o $(OBJS)
+	$(LD) -o test test.o $(OBJS) ../window/libwindow.a ../music2/libmusic.a ../system/libsystem.a ../font/libfont.a  $(LDFLAGS)
+
+scn2kdump: scn2kdump.o
+	$(LD) -o scn2kdump scn2kdump.o ../system/libsystem.a $(LDFLAGS)
+
+gandump: gandump.o
+	$(LD) -o gandump gandump.o $(LDFLAGS)
+
+libscn2k.a: ${OBJS}
+	rm -f libscn2k.a
+	${AR} clq libscn2k.a ${OBJS}
+	$(RANLIB) libscn2k.a
+
+clean:
+	rm -f test libscn2k.a ${OBJS} *.bak *.core gandump scn2kdump
+
+.c.o:
+	$(CC) -c $(CFLAGS) -o $@ $<
+
+.cc.o:
+	$(CXX) -c $(CFLAGS) -o $@ $<
+
new file mode 100644
--- /dev/null
+++ b/scn2k/gandump.cc
@@ -0,0 +1,45 @@
+#include<stdio.h>
+#include<string.h>
+
+char* ganname[6] = {"ptn", "x", "y", "time", "alpha", "?"};
+int main(int argc, char** argv) {
+	if (argc != 2) return 0;
+	FILE* f = fopen(argv[1],"rb");
+	if (f==0) return 0;
+	fseek(f,0,2); int sz=ftell(f); fseek(f,0,0);
+	char* buf = new char[sz];
+	char* bufo = buf;
+	fread(buf,1,sz,f);
+	fclose(f);
+
+	int i;
+	for (i=0; i<16; i++) {
+		printf("%02x ",int(buf[i])&0xff);
+	}
+	printf("\n");
+	buf+=16;
+	printf("file '%s'\n",buf);
+	buf += strlen(buf)+1;
+	printf("N1 = %3d\n", *(int*)buf); buf+=4;
+	int ptns = *(int*)buf; buf += 4;
+	for (i=0; i<ptns; i++) {
+		int j;
+		printf("\tN2 = %3d\n",*(int*)buf); buf += 4;
+		int n = *(int*)buf; buf += 4;
+		for (j=0; j<n; j++) {
+			printf("\t%3d: ",j);
+			int k; int d1,d2;
+			for (k=0; k<6; k++) {
+				d1 = *(int*)(buf+k*8);
+				d2 = *(int*)(buf+k*8+4);
+				if (d1 != 30100+k) printf("err: d1 %d\n",d1);
+				printf("%s: %5d, ",ganname[k],d2);
+			}
+			printf("\n");
+			buf += 6*8;
+			int d = *(int*)buf; buf += 4;
+			if (d != 999999) printf("err: dd %d\n",d);
+		}
+	}
+	if (buf != bufo+sz) { printf("orig sz %d read %d\n",sz,buf-bufo);}
+}
new file mode 100644
--- /dev/null
+++ b/scn2k/scn2k.h
@@ -0,0 +1,236 @@
+#ifndef __SCN2k_H__
+#define __SCN2k_H__
+
+#include<vector>
+#include<string>
+#include<map>
+#include<set>
+
+/*
+namespace Widget {
+	class Text;
+	class Button;
+	class TextButton;
+	class Label;
+	class Dialog;
+	class AnmTime;
+}
+*/
+	class WidText;
+	class WidButton;
+	class WidTextButton;
+	class WidLabel;
+	class WidDialog;
+	class WidAnmTime;
+namespace Event {
+	class Container;
+}
+class PicBase;
+class PicContainer;
+class AyuSysConfig;
+class Surface;
+
+void dprintf(const char* fmt, ...);
+void eprintf(const char* fmt, ...);
+
+struct VarInfo {
+#define TYPE_NONSYSVARMAX 5
+#define TYPE_VARMAX 9
+#define TYPE_VARLOCSTR 10
+#define TYPE_VARSYSSTR 12
+#define TYPE_VARSTR 18
+#define TYPE_STR 58
+#define TYPE_VAL 68
+#define TYPE_SYS 0xc8
+#define TYPE_END 0x7f
+
+#define TYPE_SYS_SYS 0
+#define TYPE_SYS_SKIPMODE 1
+	int type;
+	int number;
+	int value;
+	VarInfo() { type = TYPE_VAL; value = 0;}
+	VarInfo(int n) { type = TYPE_VAL; value = n;}
+	VarInfo(const VarInfo& i) { type = i.type; number = i.number; value = i.value;}
+};
+class Flags {
+/* flag:
+**  type 0-5 : ローカル整数、各2000個
+**  type 6, 25 : グローバル整数、2000個
+**      type 10,11: ローカル整数??、各2000個
+**	type 12 : グローバル文字列、2000個 (今は無視しても良いが)
+**	type 18 : ローカル文字列、2000個
+**	type 25: システム変数(マウス座標など?) 1000 個?
+**  type 26-32, 51 : 1-bit access to 0-6, 25
+**  type 52-58, 77 : 2-bit access to 0-6, 25
+**  type 78-84, 103 : 4-bit access to 0-6, 25
+**  type 104-110, 129 : 8-bit access to 0-6, 25
+*/
+	typedef unsigned int uint;
+	int sys;
+	int var[TYPE_VARMAX+1][2000];
+	std::string str[2000];
+	std::string sys_str[2000];
+	std::string loc_str[3];
+public:
+	Flags(void);
+	int operator () () const;
+	int operator () (VarInfo info) const;
+	void Str(int type, unsigned int number, char* buf, int sz) const;
+	std::string Str(int type, unsigned int number) const;
+	std::set<int> cgm_data;
+
+	bool IsInt(int type) const;
+	int MaxIndex(int type) const;
+
+	void Set(VarInfo info, int value);
+	int Get(int type, int number) const;
+	void SetSys(int value);
+	void SetStr(VarInfo info, std::string val);
+
+	bool Exec(class Cmd& cmd);
+
+	void Save(std::string& str);
+	void Load(const char* str);
+
+	void SaveSys(std::string& str);
+	void LoadSys(const char* str);
+};
+
+/* commands */
+#define STRHEAP_SIZE 10000
+enum Cmdtype {
+	CMD_NOP, CMD_FLAGS, CMD_JMP, CMD_TEXT, CMD_OTHER, CMD_SYSVAR,
+	CMD_TEXTEND,
+	CMD_SAVECMDGRP, CMD_SAVECMDGRP_START, CMD_SAVECMDGRP_ONCE, CMD_SAVECMD_ONCE, CMD_WAITFRAMEUPDATE,CMD_SAVEPOINT, CMD_ROLLBACKPOINT,
+	CMD_SAVEREQ, CMD_SAVE,
+	CMD_LOADREQ, CMD_LOAD,
+	CMD_MENUREQ,
+	CMD_BACKLOGREQ, CMD_BACKLOGREQ_FWD,
+	CMD_END};
+struct CmdSimplified { // Cmd 保存用
+	int type, cmd1, cmd2, cmd3, cmd4, argc;
+	char* args;
+	void Save(std::string& save);
+	void Load(const char* save, char*& args_buffer);
+	void copy(const CmdSimplified& from, char*& args_buffer);
+};
+class Cmd {
+public:
+	Cmdtype cmd_type;
+	int cmd1, cmd2, cmd3, cmd4;
+	int argc;
+	int pos, scn;
+	const char* rawdata;
+	char cmdstr[1024];
+	std::vector<VarInfo> args;
+
+private:
+	const Flags& flags;
+	bool errorflag;
+	int system_version;
+
+	int GetArgs(const char*& d);
+	int GetArgsSpecial(int normal_args,const char*& d);
+	void GetSelection(const char*& d);
+	int GetSwitch(const char*& d);
+	int GetSimpleSwitch(const char*& d);
+	int GetExpression(const char*& d, struct VarInfo* info = 0);
+	int GetExpressionCond(const char*& d);
+	int GetLeftToken(const char*& d, struct VarInfo& info);
+	int GetString(const char*& d);
+	int CopyString(const char* d);
+	int StrVar(int type, int number);
+	static char strtype[256];
+	static int StrType(const char* d) { return strtype[*(unsigned const char*)d];}
+public:
+	const char* Str(const VarInfo& info) const {
+		if (info.type != TYPE_STR && info.type != TYPE_VARSTR && info.type != TYPE_VARLOCSTR && info.type != TYPE_VARSYSSTR) return "";
+		int pt = info.value;
+		if (pt < 0 || pt >= STRHEAP_SIZE) return "";
+		return strheap + pt;
+	}
+	int AddStr(char* s) {
+		// 1-0a-0064 はこういうものが必要らしい
+		int start = strend;
+		while (*s) strheap[strend++] = *s++;
+		strheap[strend++] = 0;
+		return start;
+	}
+private:
+	char strheap[STRHEAP_SIZE];
+	int strend;
+	void SetError(void) { errorflag = true;}
+	void ResetString(void) {
+		strend = 0;
+	}
+public:
+	void GetCmd(Flags& f, const char*& d);
+	void SetSysvar(int n, int v);
+	void SetSysvar(int v) { SetSysvar(TYPE_SYS_SYS, v); }
+	void SetFlagvar(VarInfo info, int v);
+	void SetStrvar(VarInfo info, const std::string& s);
+	bool IsError() { return errorflag;}
+	void clear(void);
+	Cmd(const Flags& f, int _sys_ver) : flags(f), system_version(_sys_ver) { cmd_type = CMD_NOP; argc = 0; errorflag = false; cmdstr[0] = 0; strend = 0; pos = -1;}
+	void read(const CmdSimplified& cmd);
+	void write(CmdSimplified& cmd, char*& args_buffer) const;
+};
+
+enum SkipMode {SKIP_NO=0, SKIP_TEXT=1, SKIP_GRP_FAST=16, SKIP_GRP_NOEFFEC=32, SKIP_GRP_NODRAW=64, SKIPEND_TEXT=256, SKIPEND_KEY=512,
+	SKIP_IN_MENU=1024};
+
+#include"font/text.h"
+
+struct BacklogItem {
+	enum {SaveSelect = -2};
+	int scn, pos;
+	int koe;
+	std::string face;
+	struct TextStream text;
+	BacklogItem(void);
+	void Clear(void);
+	void AddTextPos(Cmd&);
+	void DeleteTextPos();
+	void SetSavepos(int pos);
+	BacklogItem& operator =(const BacklogItem&);
+};
+class Text {
+	class TextImpl* pimpl;
+public:
+	std::vector<BacklogItem> backlog;
+	BacklogItem backlog_item;
+	Text(Event::Container& _event, PicContainer& _parent, AyuSysConfig& config);
+	~Text();
+	void InitWindow(void);
+	void Exec(Cmd& cmd);
+	bool Wait(unsigned int current_time, Cmd& cmd);
+	void SetSkipMode(SkipMode mode);
+	void hide(void);
+	void show(void);
+	void show(int num);
+	void Save(std::string& str, bool rollback_save);
+	void Load(const char* str);
+	void DrawBacklog(BacklogItem& item, Cmd& cmd);
+};
+
+#include"../window/rect.h"
+
+class Grp {
+	class GrpImpl* pimpl;
+public:
+	Grp(Event::Container& _event, PicContainer& _parent, const Flags& f, std::set<int>& _cgm_data, class MuSys& mu, AyuSysConfig& config);
+	~Grp();
+	bool Wait(unsigned int current_time, Cmd& cmd);
+	void Exec(Cmd& cmd);
+	void SetSkipMode(SkipMode mode);
+	void InitSel(AyuSysConfig& config);
+	void Save(std::string& str);
+	void Load(const char* str);
+	void SaveSys(std::string& str);
+	void LoadSys(const char* str);
+};
+
+void dprintf(const char* fmt, ...); // debug 用
+void eprintf(const char* fmt, ...); // コマンド実行(XXXexec)追跡用
+#endif
new file mode 100644
--- /dev/null
+++ b/scn2k/scn2k_cmd.cc
@@ -0,0 +1,1749 @@
+/*
+ * Copyright (c) 2004-2006  Kazunori "jagarl" Ueno
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include"scn2k.h"
+
+#include<stdlib.h>
+#include<stdarg.h>
+#include<stdio.h>
+#include<string.h>
+#include<string>
+#include"system/file.h"
+
+using namespace std;
+
+
+// #define SCN_DUMP
+/* 注意点: @@@ で表記 */
+
+
+
+//bool debug_flag = true;
+bool debug_flag = false;
+void dprintf(const char* fmt, ...) {
+	if (debug_flag) {
+		va_list ap; va_start(ap, fmt);
+		vprintf(fmt, ap);
+		va_end(ap);
+	}
+}
+
+
+void eprintf(const char* fmt, ...) {
+	va_list ap; va_start(ap, fmt);
+//	vprintf(fmt, ap);
+	va_end(ap);
+}
+
+/**************************************************************
+**	Flag
+*/
+
+Flags::Flags(void) {
+	int i,j;
+	for (i=0; i<=TYPE_VARMAX; i++) {
+		for (j=0; j<2000; j++) {
+			var[i][j] = 0;
+		}
+	}
+	sys = 0;
+}
+
+bool Flags::IsInt(int type) const {
+	int v = type % 26;
+	return v >= 0 && v < 7 || v == 25;
+}
+
+int Flags::MaxIndex(int type) const {
+	switch (type / 26) {
+		case 1:
+			return 63999;
+		case 2:
+			return 31999;
+		case 3:
+			return 15999;
+		case 4:
+			return 7999;
+		default:
+			return 1999;
+	}
+}
+
+int Flags::operator()() const {
+	return sys; // rand() % 10000;
+}
+
+int Flags::operator() (VarInfo info) const {
+	return Get(info.type, info.number);
+}
+
+int Flags::Get(int type, int number) const {
+	int index = type % 26;
+	type /= 26;
+	if (index == 25) {
+		if (var[7][number] != 0) return var[7][number];
+		if (cgm_data.find(number) == cgm_data.end()) return 0;
+		else return 1;
+	}
+	if (index == 10) index = 8;
+	if (index == 11) index = 9;
+	if (index > TYPE_VARMAX || uint(type) > 4) return 0;
+	if (type == 0) {
+		// A[]..G[], Z[] を直に読む
+		if (uint(number) >= 2000) return 0;
+		return var[index][number];
+	} else {
+		// Ab[]..G4b[], Z8b[] などを読む
+		int factor = 1 << (type - 1);
+		int eltsize = 32 / factor;
+		if (uint(number) >= (64000 / factor)) return 0;
+		return (var[index][number / eltsize] >> ((number % eltsize) * factor)) & ((1 << factor) - 1);
+	}
+}
+
+void Flags::Set(VarInfo info, int value) {
+	int type = info.type / 26;
+	int index = info.type % 26;
+	if (index == 25) {
+		if (uint(info.number) >= 2000) return;
+		if (value == 0)
+			cgm_data.erase(info.number);
+		else
+			cgm_data.insert(info.number);
+		index = 7;
+	}
+	if (index == 10) index = 8;
+	if (index == 11) index = 9;
+	if (index < 0 || index > TYPE_VARMAX) {
+		fprintf(stderr,"Error: invalid access to Var<%d>[%d]\n",info.type,info.number);
+	}
+	if (type == 0) {
+		// A[]..G[], Z[] を直に書く
+		if (uint(info.number) >= 2000) return;
+		var[index][info.number] = value;
+	} else {
+		// Ab[]..G4b[], Z8b[] などを書く
+		int factor = 1 << (type - 1);
+		int eltsize = 32 / factor;
+		int eltmask = (1 << factor) - 1;
+		int shift = (info.number % eltsize) * factor;
+		if (uint(info.number) >= (64000 / factor)) return;
+		var[index][info.number / eltsize] =
+			(var[index][info.number / eltsize] & ~(eltmask << shift))
+		  | (value & eltmask) << shift;
+	}
+}
+
+void Flags::SetSys(int value) {
+	sys = value;
+}
+void Flags::SetStr(VarInfo info, string val) {
+	switch(info.type) {
+	case TYPE_VARLOCSTR:
+		if (info.number >= 3) return;
+		loc_str[info.number] = val;
+		break;
+	case TYPE_VARSYSSTR:
+		if (info.number >= 2000) return;
+		sys_str[info.number] = val;
+		break;
+	case TYPE_VARSTR:
+		if (info.number >= 2000) return;
+		str[info.number] = val;
+		break;
+	}
+	return;
+}
+void Flags::Str(int type, unsigned int number, char* buf, int sz) const {
+	if (sz <= 0) return;
+	buf[0] = 0;
+	const string* sptr;
+	switch(type) {
+	case TYPE_VARLOCSTR:
+		if (number >= 3) return;
+		sptr = &loc_str[number];
+		break;
+	case TYPE_VARSYSSTR:
+		if (number >= 2000) return;
+		sptr = &sys_str[number];
+		break;
+	case TYPE_VARSTR:
+		if (number >= 2000) return;
+		sptr = &str[number];
+		break;
+	}
+
+	int len = sptr->length();
+	if (sz-1 > len) sz = len;
+	sptr->copy(buf, sz, 0);
+	buf[sz] = 0;
+	return;
+}
+string Flags::Str(int type, unsigned int number) const {
+	switch(type) {
+	case TYPE_VARLOCSTR:
+		if (number >= 3) return "";
+		return loc_str[number];
+	case TYPE_VARSYSSTR:
+		if (number >= 2000) return "";
+		return sys_str[number];
+	case TYPE_VARSTR:
+		if (number >= 2000) return "";
+		return str[number];
+	}
+	return "";
+}
+
+void Flags::Save(string& save) {
+	char buf[1024];
+	save = "\n[Flags]\n";
+	int i,j;
+	for (i=0; i<=TYPE_NONSYSVARMAX; i++) {
+		for (j=0; j<2000; j++) {
+			if (var[i][j] != 0) {
+				sprintf(buf, "V<%d>[%04d]=%d\n",i,j,var[i][j]);
+				save += buf;
+			}
+		}
+	}
+	for (j=0; j<2000; j++) {
+		if (str[j].length() != 0) {
+			sprintf(buf, "V<C>[%04d]=%s\n", j, str[j].c_str());
+			save += buf;
+		}
+	}
+}
+void Flags::Load(const char* save) {
+	int i,j;
+	for (i=0; i<=TYPE_NONSYSVARMAX; i++) {
+		for (j=0; j<2000; j++) {
+			var[i][j] = 0;
+		}
+	}
+	sys = 0;
+	for (j=0; j<2000; j++) {
+		str[j] = "";
+	}
+
+	save = strstr(save, "\n[Flags]\n");
+
+	if (save) {
+		save += strlen("\n[Flags]\n");
+		do {
+			if (save[0] == '[') break; // next section
+			if (strncmp(save, "V<",2) == 0) {
+				if (strncmp(save, "V<C>[",5) == 0) { // string
+					char buf[1024];
+					int n;
+					if (sscanf(save, "V<C>[%04d]=",&n) == 1) {
+						char* s = strchr(save, '=');
+						s++;
+						char* send = strchr(s, '\n');
+						int slen = send - s;
+						strncpy(buf, s, slen);
+						buf[slen] = 0;
+						if (n >= 0 && n < 2000) str[n] = buf;
+					}
+				} else if (save[2] >= '0' && save[2] <= '9') {
+					int c,n,v;
+					if (sscanf(save, "V<%d>[%04d]=%d\n",&c,&n,&v) == 3) {
+						if (c >= 0 && c <= TYPE_NONSYSVARMAX && n >= 0 && n < 2000)
+							var[c][n] = v;
+					}
+				}
+			}
+			save = strchr(save, '\n');
+			if (save) save++;
+		} while (save);
+	}
+	return;
+}
+
+void Flags::SaveSys(string& save) {
+	char buf[1024];
+	int j;
+	save = "\n[Flags]\n";
+		for (j=0; j<2000; j++) {
+		if (var[6][j] != 0) {
+			sprintf(buf, "V<6>[%04d]=%d\n",j,var[6][j]);
+				save += buf;
+			}
+		}
+	for (j=0; j<2000; j++) {
+		if (var[7][j] != 0) {
+			sprintf(buf, "V<25>[%04d]=%d\n",j,var[7][j]);
+			save += buf;
+		}
+	}
+	for (j=0; j<2000; j++) {
+		if (sys_str[j].length() != 0) {
+			sprintf(buf, "V<M>[%04d]=%s\n", j, sys_str[j].c_str());
+			save += buf;
+		}
+	}
+}
+void Flags::LoadSys(const char* save) {
+	int i,j;
+	for (i=6; i<=7; i++) {
+		for (j=0; j<2000; j++) {
+			var[i][j] = 0;
+		}
+	}
+	for (j=0; j<2000; j++) {
+		sys_str[j] = "";
+	}
+	sys = 0;
+
+	save = strstr(save, "\n[Flags]\n");
+
+	if (save) {
+		save += strlen("\n[Flags]\n");
+		do {
+			if (save[0] == '[') break; // next section
+			if (strncmp(save, "V<",2) == 0) {
+				if (strncmp(save, "V<M>[",5) == 0) { // string
+					char buf[1024];
+					int n;
+					if (sscanf(save, "V<M>[%04d]=",&n) == 1) {
+						char* s = strchr(save, '=');
+						s++;
+						char* send = strchr(s, '\n');
+						int slen = send - s;
+						strncpy(buf, s, slen);
+						buf[slen] = 0;
+						if (n >= 0 && n < 2000) sys_str[n] = buf;
+					}
+				} else if (save[2] >= '0' && save[2] <= '9') {
+					int c,n,v;
+					if (sscanf(save, "V<%d>[%04d]=%d\n",&c,&n,&v) == 3) {
+						if (c == 6 && n >= 0 && n < 2000)
+							var[6][n] = v;
+						else if (c == 25 && n >= 0 && n < 2000)
+							var[7][n] = v;
+					}
+				}
+			}
+			save = strchr(save, '\n');
+			if (save) save++;
+		} while (save);
+	}
+	return;
+}
+
+bool Flags::Exec(Cmd& cmd) {
+	if (cmd.cmd_type == CMD_FLAGS) { // 代入演算
+		if (cmd.args.size() != 2) return false;
+		Set(cmd.args[0], cmd.args[1].value);
+		cmd.clear();
+		return true;
+	}
+	if (cmd.cmd1 == 1 && cmd.cmd2 == 0x0a) { // 文字列演算
+		VarInfo arg1 = cmd.args[0];
+		switch(cmd.cmd3) {
+		case 0:
+			if (cmd.cmd4 == 0) {
+				SetStr(arg1, cmd.Str(cmd.args[1]));
+			} else if (cmd.cmd4 == 1) {
+				string s = cmd.Str(cmd.args[1]);
+				const char* sc = s.c_str();
+				int len = cmd.args[2].value;
+				int i;for (i=0; i<sc[i]!=0 && len != 0; i++, len--) {
+					if (sc[i]<0 && sc[i+1]!=0) i++;
+				}
+				s.erase(i); // 全角で len 文字まで切り詰める
+				SetStr(arg1, s);
+// fprintf(stderr,"Set[%d,%d]<-%s\n",arg1.type,arg1.number,s.c_str());
+			} else break;
+			cmd.clear();
+			break;
+		case 1:
+			if (cmd.cmd4 == 0) {
+				SetStr(arg1, "");
+				cmd.clear();
+			} else if (cmd.cmd4 == 1) {
+				// 領域指定で文字列クリア
+				VarInfo v1 = cmd.args[0];
+				VarInfo v2 = cmd.args[1];
+				eprintf("memclear(str). Var[%d]<%d> - Var[%d]<%d>\n",v1.type, v1.number, v2.type, v2.number);
+				if (v1.type != v2.type || (v1.type != TYPE_VARSTR && v1.type != TYPE_VARSYSSTR && v1.type != TYPE_VARLOCSTR)) {
+					eprintf("   error: bad args\n");
+				} else {
+					if (v1.number < 0) v1.number = 0;
+					if (v2.number > 2000) v2.number = 2000;
+					for (; v1.number <= v2.number; v1.number++) {
+						SetStr(v1, "");
+					}
+				}
+				cmd.clear();
+			}
+		case 2:
+			SetStr(arg1, Str(arg1.type,arg1.number) + cmd.Str(cmd.args[1]));
+// fprintf(stderr,"Append[%d,%d]<-%s(%d:%d)\n",arg1.type,arg1.number,Str(arg1.type,arg1.number).c_str(),cmd.args[1].type,cmd.args[1].number);
+			cmd.clear();
+			break;
+		case 3:
+			SetSys(strlen(cmd.Str(cmd.args[0])));
+			cmd.clear();
+			break;
+		case 4:
+			{ int v = strcmp(cmd.Str(cmd.args[0]), cmd.Str(cmd.args[1]));
+// string s1=cmd.Str(cmd.args[0]);
+// string s2=cmd.Str(cmd.args[1]);
+// fprintf(stderr,"Cmp %s(%d:%d):%s(%d:%d):%d\n",s1.c_str(),cmd.args[0].type,cmd.args[0].number,s2.c_str(),cmd.args[1].type,cmd.args[1].number,v);
+			if (v < 0) SetSys(-1);
+			else if (v > 0) SetSys(1);
+			else SetSys(0);
+			cmd.clear();
+			break; }
+		case 5: // substring, index from left
+		case 6: // substring, index from right
+			// 全角対応らしい
+			{ int offset = cmd.args[2].value;
+			int len = strlen(cmd.Str(cmd.args[1]));
+			string str = cmd.Str(cmd.args[1]);
+			const char* s = str.c_str();
+			if (cmd.cmd3 == 6) offset = len - offset;
+			if (offset < 0) offset = 0;			
+			// 先頭 N 文字を読み飛ばす
+			int i;
+			int offset_top = 0;
+			for (i=0; i<offset && s[offset_top] != 0; i++) {
+				if (s[offset_top] < 0 && s[offset_top+1] != 0) offset_top += 2;
+				else offset_top += 1;
+			}
+			if (s[offset_top] == 0) {
+				SetStr(arg1, "");
+			} else if (cmd.cmd4 == 0) { // 長さ制限なし
+				SetStr(arg1, string(s, offset_top));
+			} else { // cmd.cmd4 == 1
+				int slen = cmd.args[3].value;
+				int offset_end = offset_top;
+				for (i=0; i<slen && s[offset_end] != 0; i++) {
+					if (s[offset_end] < 0 && s[offset_end]+1 != 0) offset_end += 2;
+					else offset_end += 1;
+				}
+				string result(s, offset_top, offset_end-offset_top);
+				SetStr(arg1, result);
+			}
+			cmd.clear();
+			break; }
+		case 7: {// strlen w/ kanji
+			const char* s = cmd.Str(cmd.args[0]); int i;
+			for (i=0; *s != 0; i++) {
+				if (*s < 0 && s[1] != 0) s += 2;
+				else s++;
+			}
+			SetSys(i);
+			cmd.clear();
+			break; }
+		case 8: // 文字列を切って短くする
+			if (cmd.args[1].value <= 0) {
+				SetStr(arg1, "");
+			} else if (cmd.args[1].value < strlen(cmd.Str(cmd.args[1]))) {
+				Str(arg1.type,arg1.number).erase(cmd.args[1].value);
+			}
+			cmd.clear();
+			break;
+		case 0x0e: // 漢字モードでitoa
+			{
+			int arg1 = cmd.args[0].value;
+			string result;
+			char wc[3]; wc[2]=0;
+			char buf[20];
+			if (cmd.cmd4 == 0) {
+				sprintf(buf, "%d", arg1);
+			} else { // cmd.cmd4 == 1
+				char fmt[20];
+				sprintf(fmt, "%%%dd", cmd.args[2].value);
+				sprintf(buf, fmt, arg1);
+			}
+			int i;
+			for (i=0; buf[i] != 0; i++) {
+				if (buf[i] == ' ') {
+					wc[0] = 0x81;
+					wc[0] = 0x40;
+				} else if (buf[i] == '-') {
+					wc[0] = 0x81;
+					wc[0] = 0x7c;
+				} else if (isdigit(buf[i])) {
+					wc[0] = 0x82;
+					wc[1] = buf[i] - '0' + 0x4f;
+				} else {
+					continue;
+				}
+				result += wc;
+			}
+			SetStr(cmd.args[1], result);
+			cmd.clear();
+			}
+			break;
+		case 0x0f: case 0x11: // itoa (0x11 の方は zero padding するっぽい)
+			if (cmd.cmd4 == 0) {
+				int arg1 = cmd.args[0].value;
+				char buf[1024]; sprintf(buf, "%d", arg1);
+				SetStr(cmd.args[1], buf);
+				cmd.clear();
+			} else if (cmd.cmd4 == 1) {
+				// 漢字(SJIS) : 82 [4f+N]
+				// やはり漢字じゃない?
+				int arg1 = cmd.args[0].value;
+				char buf[1024]; char fmt[1024];
+				if (cmd.cmd3 == 0x0f) {
+					sprintf(fmt, "%%%dd",cmd.args[2].value); /* 空白でパディング */
+				} else {
+					sprintf(fmt, "%%0%dd",cmd.args[2].value);
+				}
+				sprintf(buf, fmt, arg1);
+				SetStr(cmd.args[1], buf);
+				cmd.clear();
+			}
+			break;
+		case 0x64: // 文字列の表示 : 引数をテキストウィンドウに表示
+			if (cmd.cmd4 == 1) {
+				char buf[256];
+				snprintf(buf, 255, "%d", Get(cmd.args[0].type, cmd.args[0].number));
+				cmd.args[0].type = TYPE_STR;
+				cmd.args[0].value = cmd.AddStr(buf);
+				cmd.cmd4 = 0;
+			}
+
+#if 0
+@@@
+save 27
+ともよメガネのところ
+- オブジェクト関連:seen9061:0 呼び出しで黒い背景画をかさねるところ、変になる
+@@@
+%Xで置換する名前の設定。0x51e で読みだし。セーブファイルごとに保存されるはずなので実装を考えること
+%は0-3 (4 以降は使ってない)で、渚、秋生、渚、伊吹先生、など
+StrVar を拡張して代入すること
+初期値はこの辺
+Text側に納め、セーブファイルでも同じようにすべきだろうなあ
+        args:0,"渚"
+        args:1,"秋生"
+        args:2,"渚"
+        args:3,"伊吹先生"
+        args:4,"朋也くん"
+        args:5,"岡崎さん"
+
+
+106737 :  0x23 - cmd 01-04:051f:00[ 2] 
+        args:0,"古河"
+106758 : line 1712
+106761 :  0x23 - cmd 01-04:051f:00[ 2] 
+        args:2,"古河"
+106782 : line 1713
+106785 :  0x23 - cmd 01-04:051f:00[ 2] 
+        args:4,"岡崎さん"
+
+47382 :  0x23 - cmd 01-04:051e:00[ 2] 
+        args:4,V<18>[0](=0)
+
+47408 :  0x23 - cmd 01-0a:0004:00[ 2] 
+        args:V<18>[0](=0),"岡崎さん"
+47437 : expr: V<0>[1000](=0)=V<sys>
+47451 :  0x23 - cmd 01-0a:0004:00[ 2] 
+        args:V<18>[0](=0),"朋也くん"
+47480 : expr: V<0>[1001](=0)=V<sys>
+47494 :         V<0>[1000](=0)==0(=true)-> 47589
+47526 :  0x23 - cmd 01-04:0514:00[ 2] 
+        args:0,V<18>[0](=0)		/* NAME.A を帰す */
+47552 :  0x23 - cmd 01-0a:0002:00[ 2] 
+        args:V<18>[0](=0),"さん"
+47577 :         jmp -> 47672
+47589 :         V<0>[1001](=0)==0(=true)-> 47672
+47621 :  0x23 - cmd 01-04:0514:00[ 2] 
+        args:1,V<18>[0](=0)		/* NAME.B を帰す */
+47647 :  0x23 - cmd 01-0a:0002:00[ 2] 
+        args:V<18>[0](=0),"くん"
+47672 : pos. 279
+47675 :  0x23 - cmd 01-0a:0064:00[ 1] 
+        args:V<18>[0](=0)
+
+#endif
+			cmd.cmd_type = CMD_TEXT;
+			break;
+		}
+	}
+	if (cmd.cmd1 == 1 && cmd.cmd2 == 0x0b) { // 数値変数演算
+		if (cmd.cmd3 == 0 && cmd.cmd4 == 0) {
+			/* 複数の変数をセット */
+			VarInfo v1 = cmd.args[0];
+			eprintf("set multiple-var Var[%d]<%d> <- ",v1.type, v1.number);
+			int i;
+			if (cmd.args.size() < cmd.argc) {
+				eprintf("   error: argsize changed %d -> %d\n",cmd.argc, cmd.args.size());
+				cmd.argc = cmd.args.size();
+			}
+			for (i=0; i<cmd.argc; i++) {
+				eprintf("%d, ",cmd.args[i+1].value);
+				Set(v1, cmd.args[i+1].value);
+				v1.number++;
+			}
+			eprintf("\n");
+			cmd.clear();
+		} else if (cmd.cmd3 == 1 && cmd.cmd4 == 0) {
+			/* 領域指定で変数をクリア */
+			VarInfo v1 = cmd.args[0];
+			VarInfo v2 = cmd.args[1];
+			eprintf("memclear. Var[%d]<%d> - Var[%d]<%d>\n",v1.type, v1.number, v2.type, v2.number);
+			if (v1.type != v2.type || !IsInt(v1.type)) eprintf("   error: bad args\n");
+			else {
+				if (v1.number < 0) v1.number = 0;
+				if (v2.number > MaxIndex(v2.type)) v2.number = MaxIndex(v2.type);
+				for (; v1.number <= v2.number; v1.number++)
+					Set(v1, 0);
+			}
+			cmd.clear();
+		} else if (cmd.cmd3 == 1 && cmd.cmd4 == 1) {
+			/* 領域指定で変数をセット */
+			VarInfo v1 = cmd.args[0];
+			VarInfo v2 = cmd.args[1];
+			int value = cmd.args[2].value;
+			eprintf("memset. Var[%d]<%d> - Var[%d]<%d> <- %d\n",v1.type, v1.number, v2.type, v2.number, value);
+			if (v1.type != v2.type || !IsInt(v1.type)) eprintf("   error: bad args\n");
+			else {
+				if (v1.number < 0) v1.number = 0;
+				if (v2.number > MaxIndex(v2.type)) v2.number = MaxIndex(v2.type);
+				for (; v1.number <= v2.number; v1.number++)
+					Set(v1, value);
+			}
+			cmd.clear();
+		} else if (cmd.cmd3 == 4 && cmd.cmd4 == 1) { // 領域クリア(sysfunc.txt)
+			VarInfo v1 = cmd.args[0];
+			int step = cmd.args[1].value;
+			int deal = cmd.args[2].value;
+			int val = cmd.args[3].value;
+			eprintf("memclear. Var[%d]<%d> step %d deal %d <- val %d\n",v1.type, v1.number, step, deal, val);
+			int i; for (i=0; i<deal; i++) {
+				Set(v1, val);
+				v1.number += step;
+			}
+			cmd.clear();
+		} else if (cmd.cmd3 == 0x64 && cmd.cmd4 == 0) { //領域で数値を合計する
+			VarInfo v1 = cmd.args[0];
+			VarInfo v2 = cmd.args[1];
+			eprintf("sum var. Var[%d]<%d> - Var[%d]<%d>\n",v1.type, v1.number, v2.type, v2.number);
+			int sum = 0;
+			if (v1.type != v2.type || !IsInt(v1.type)) eprintf("   error: bad args\n");
+			else {
+				if (v1.number < 0) v1.number = 0;
+				if (v2.number > MaxIndex(v2.type)) v2.number = MaxIndex(v2.type);
+				for (; v1.number <= v2.number; v1.number++)
+					sum += (*this)(v1);
+			}
+			eprintf("    ret %d\n",sum);
+			cmd.SetSysvar(sum);
+		}
+	}
+	return false;
+}
+
+/*********************************************************************
+**   Cmd
+*/
+
+/* 数値 num := 0x24 0xff <int num> */
+/* 変数 var := 0x24 <uchar type> 0x5b <exp> 0x5d */
+/* 項 token := num | var | 0x28 <exp> 0x29 | <plus|minus> token */
+
+int Cmd::GetLeftToken(const char*& d, VarInfo& info) {
+	bool var_flag = true;
+	int minus_flag = 0;
+	int value = 0;
+	if (d[0] == 0x5c && (d[1] == 1 || d[1] == 0) ) {
+		if (d[1] == 1)	{dprintf("minus-"); minus_flag ^= 1;}
+		else dprintf("plus-");
+		d += 2;
+		var_flag = false;
+	}
+	if (d[0] == 0x24 && ((unsigned const char*)d)[1] == 0xff) {
+	// if ( (d[0] == 0x30 || d[0] == 0x31) && d[1] == 0x24 && ((unsigned const char*)d)[2] == 0xff) 	/* @@@ not supported; selection 内で、0x30|0x31 が付随することがある */
+		// numerical atom
+		d += 6;
+		value = read_little_endian_int(d-4);
+		dprintf("%d",value);
+		var_flag = false;
+	} else if (d[0] == 0x24 && *(unsigned char*)(d+1) == 0xc8) {
+		dprintf("V<sys>");
+		d += 2;
+		info.type = TYPE_SYS; info.number = 0;
+		value = info.value =  flags();
+	} else if (d[0] == 0x24 && d[2] == 0x5b) {
+		// 0x24,<type>,0x5b,<expr>,0x5d-terminated term
+		info.type = *(unsigned char*)(d+1);
+		d += 3;
+		dprintf("V<%d>[",info.type);
+		info.number = GetExpression(d);
+		dprintf("]");
+		if (*d == 0x5d) d++;
+		else SetError();
+		if (info.type == TYPE_VARSTR || info.type == TYPE_VARSYSSTR || info.type == TYPE_VARLOCSTR) {
+			value = 0;
+			info.value = StrVar(info.type, info.number);
+		} else {
+			value = info.value = flags(info);
+		}
+		dprintf("(=%d)",value);
+	} else SetError();
+
+	if (minus_flag) value = -value;
+	if (!var_flag) {
+		info.type = TYPE_VAL;
+		info.value = value;
+	}
+	return value;
+}
+
+static char* op_str[70] = {
+//	 0      1      2      3      4      5      6      7      8     9
+	"+",   "-",   "*",   "/",   "%",   "&",   "|",   "^",   "<<",  ">>",	// +00
+	"err.","err.","err.","err.","err.","err.","err.","err.","err.","err.",	// +10
+	"+=",  "-=",  "*=",  "/=",  "%=",  "&=",  "|=",  "^=",  "<<=", ">>=",	// +20
+	"=",   "err.","err.","err.","err.","err.","err.","err.","err.","err.",	// +30
+	"==",  "!=",  "<=",  "<",   ">=",  ">",   "err.","err.","err.","err.",	// +40
+	"err.","err.","err.","err.","err.","err.","err.","err.","err.","err.",	// +50
+	"&&",  "||",  "err.","err.","err.","err.","err.","err.","err.","err.",	// +60
+};
+
+static int op_pri_tbl[12] = {
+//	+  -  *  /  %  &  |  ^ << >>
+	2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 10, 10};
+
+inline int op_pri(int op) {
+	if (op > 11) return 10;
+	return op_pri_tbl[op];
+}
+inline int op_pri_cond(int op) {
+	if (op <= 11) return op_pri_tbl[op];
+	else if (op < 50) return 7;
+	else if (op == 60) return 8;
+	else if (op == 61) return 8;
+	else return 10;
+}
+
+
+inline int eval(int v1, int op, int v2) {
+	switch(op) {
+		case 0: return v1+v2;
+		case 1: return v1-v2;
+		case 2: return v1*v2;
+		case 3: return v2!=0 ? v1/v2 : v1;
+		case 4: return v2!=0 ? v1%v2 : v1;
+		case 5: return v1&v2;
+		case 6: return v1|v2;
+		case 7: return v1^v2;
+		case 8: return v1<<v2;
+		case 9: return v1>>v2;
+		case 40: return v1 == v2;
+		case 41: return v1 != v2;
+		case 42: return v1 <= v2;
+		case 43: return v1 <  v2;
+		case 44: return v1 >= v2;
+		case 45: return v1 >  v2;
+		case 60: return v1 && v2;
+		case 61: return v1 || v2;
+	}
+	return v2;
+}
+
+/* 演算子 op := 0x5c <uchar op> */
+/* 数式 exp: [op] <token> [op <token> [...]] */
+int Cmd::GetExpression(const char*& d, VarInfo* info_ptr) {
+#define STACK_DEPTH 1024
+#define OP_LB 11
+	char op_stack[STACK_DEPTH];
+	int val_stack[STACK_DEPTH];
+	int stack_count = 0;
+	
+	// 第一項の読み込み
+	while(*d == 0x28) {
+		d++;
+		dprintf("(");
+		op_stack[stack_count++] = OP_LB;
+	}
+	VarInfo info;
+	int value = GetLeftToken(d, info);
+	
+	while(*d == 0x29 && stack_count > 0 && op_stack[stack_count-1] == OP_LB) {
+		d++;
+		dprintf(")");
+		stack_count--;
+	}
+	
+	if (*d != 0x5c && stack_count == 0) {
+		if (info_ptr) *info_ptr = info;
+		return value; // 単純なleft-termはここで終了。有効なinfo_ptrを帰す(可能性がある)
+	}
+	
+	while(*d == 0x5c) {
+		int op_type = *(unsigned char*)(d+1);
+		d += 2;
+		if (op_type < 70) dprintf("%s",op_str[op_type]);
+		else dprintf("err.");
+		if (op_type >= 10) SetError();
+		int cur_pri = op_pri(op_type);
+		while(stack_count != 0 && op_pri(op_stack[stack_count-1]) <= cur_pri) {
+			// 優先順位の高い、先行する演算を行う
+			value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value);
+			stack_count--;
+		}
+		val_stack[stack_count] = value;
+		op_stack[stack_count++] = op_type;
+		while(*d == 0x28) {
+			d++;
+			dprintf("(");
+			op_stack[stack_count++] = OP_LB;
+		}
+		if (stack_count >= STACK_DEPTH) SetError();
+		value = GetLeftToken(d, info);
+
+		while (*d != 0x5c && stack_count > 0) {
+			// 未実行の演算を終わらせる
+			if (op_stack[stack_count-1] != OP_LB) {
+				value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value);
+				stack_count--;
+			} else if (*d == 0x29) { /* op_stack == OP_LB */
+			// bracket 終端があれば、閉じておく
+				d++;
+				dprintf(")");
+				stack_count--;
+			} else break; // error
+		}
+	}
+	if (stack_count) SetError(); // unbalanced bracket
+	dprintf("(=%d)",value);
+	if (info_ptr) {
+		info_ptr->type = TYPE_VAL;
+		info_ptr->value = value;
+	}
+	return value;
+}
+
+// 条件分岐専用に、条件演算と算術演算の混合を検知できる専用ルーチン(本来はGetExpressionで差し支えない)
+int Cmd::GetExpressionCond(const char*& d) {
+	char op_stack[STACK_DEPTH];
+	int val_stack[STACK_DEPTH];
+	int valattr_stack[STACK_DEPTH];
+#define ATTR_VAL 0
+#define ATTR_FLAG 1
+	int stack_count = 0;
+	
+	// 第一項の読み込み
+	while(*d == 0x28) {
+		d++;
+		dprintf("(");
+		op_stack[stack_count++] = OP_LB;
+	}
+	VarInfo info;
+	int value = GetLeftToken(d, info);
+	while(*d == 0x29 && stack_count > 0 && op_stack[stack_count-1] == OP_LB) {
+		d++;
+		dprintf(")");
+		stack_count--;
+	}
+	bool valattr = ATTR_VAL;
+	
+	while(*d == 0x5c) {
+		int op_type = *(unsigned char*)(d+1);
+		d += 2;
+		if (op_type < 70) dprintf("%s",op_str[op_type]);
+		else dprintf("err.");
+		int cur_pri = op_pri_cond(op_type);
+		while(stack_count != 0 && op_pri_cond(op_stack[stack_count-1]) <= cur_pri) {
+			// 優先順位の高い、先行する演算を行う
+			if (op_stack[stack_count-1] >= 60) {
+				if (valattr_stack[stack_count-1] != ATTR_FLAG || valattr != ATTR_FLAG) SetError();
+			} else {
+				if (valattr_stack[stack_count-1] != ATTR_VAL || valattr != ATTR_VAL) SetError();
+			}
+			value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value);
+			if (op_stack[stack_count-1] >= 40) valattr = ATTR_FLAG;
+			stack_count--;
+		}
+		val_stack[stack_count] = value;
+		valattr_stack[stack_count] = valattr;
+		op_stack[stack_count++] = op_type;
+		while(*d == 0x28) {
+			d++;
+			dprintf("(");
+			op_stack[stack_count++] = OP_LB;
+		}
+		if (stack_count >= STACK_DEPTH) SetError();
+		value = GetLeftToken(d, info);
+		valattr = ATTR_VAL;
+
+		while (*d != 0x5c && stack_count > 0) {
+			// 未実行の演算を終わらせる
+			if (op_stack[stack_count-1] != OP_LB) {
+				if (op_stack[stack_count-1] >= 60) {
+					if (valattr_stack[stack_count-1] != ATTR_FLAG || valattr != ATTR_FLAG) SetError();
+				} else {
+					if (valattr_stack[stack_count-1] != ATTR_VAL || valattr != ATTR_VAL) SetError();
+				}
+				value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value);
+				if (op_stack[stack_count-1] >= 40) valattr = ATTR_FLAG;
+				stack_count--;
+			// bracket 終端があれば、閉じておく
+			} else if (*d == 0x29) { /* op_stack == OP_LB */
+				d++;
+				dprintf(")");
+				stack_count--;
+			} else break; // error
+		}
+	}
+	if (stack_count) SetError(); // unbalanced bracket
+	if (value) dprintf("(=true)");
+	else dprintf("(=false)");
+	return value;
+}
+
+
+/*
+str = 
+arg = 
+args = 0x28 <exp> [[0x2c] <exp> [[0x2c] <exp> [...] ]]
+*/
+
+int Cmd::GetArgs(const char*& d) {
+	if (*d != 0x28) return 0; /* 引数なし */
+	d++;
+	dprintf("args:");
+	VarInfo var;
+	int i; for (i=0; i<100 ; i++) {
+		/* number, variable, string の種別なく値を得る */
+		if (*d == 0x61) { // よくわからない(智代アフター)
+			dprintf("*%d*",d[1]);
+			d += 2;
+			if (*d == 0x28) {
+				dprintf("{");
+				GetArgs(d); // (A,B,C)節が含まれることがある
+				dprintf("}");
+			} else {
+				dprintf("{}");
+			}
+		} else if (d[0] == 0x0a || d[0] == 0x40) { // よくわからない (Little Busters!)
+			int var;
+			if (system_version == 0) { var = read_little_endian_int(d+1); d += 5;}
+			else { var = read_little_endian_short(d+1); d += 3;}
+			dprintf("line %d; ",var);
+		} else if (*d == 0x24 || (*d == 0x5c && (d[1] == 1 || d[1] == 0)) || *d == 0x28) {
+			GetExpression(d, &var);
+			args.push_back(var);
+		} else if (StrType(d)) {
+			var.type = TYPE_STR;
+			var.value = GetString(d);
+			args.push_back(var);
+		} else SetError();
+		if (*d == 0x29) break;
+		if (*d == 0x2c) {d++;} // 次の arg が演算子で始まる、などがなければ存在しない
+		dprintf(",");
+	}
+	if (*d == 0x29) d++;
+	else SetError();
+	return i;
+}
+
+int Cmd::GetArgsSpecial(int normal_args,const char*& d) {
+	if (*d != 0x28) return 0; /* 引数なし */
+	d++;
+	dprintf("args:");
+	int i; for (i=0; i<normal_args; i++) {
+		/* number, variable, string の種別なく値を得る */
+		if (*d == 0x24 || (*d == 0x5c && (d[1] == 1 || d[1] == 0)) || *d == 0x28) {
+			GetExpression(d);
+		} else if (StrType(d)) {
+			GetString(d);
+		} else SetError();
+		if (*d == 0x29) break;
+		if (*d == 0x2c) {d++;} // 次の arg が演算子で始まる、などがなければ存在しない
+		dprintf(",");
+	}
+	for (i=0; i<argc ; i++) {
+		if (*d == 0x28) {
+/*
+** cmd 01-22:0c1c, 01-22:0835
+** Princess Bride のカードが落ちるアニメの場面
+** なお、_PBCARDANM* の画像はこのコマンドでのみ使われているので、特殊処理として無視することも可能
+**
+** cmd 01-04:0276, 026c, 0270
+** 複数の enum が args の数だけ続く処理。特殊処理として分離する
+*/
+dprintf("enum.<");
+			/* (...) は列挙型 or 構造体の可能性がある */
+			const char* d_orig = d;
+			int pt = args.size(); args.push_back(VarInfo(0));
+			int count = GetArgs(d);
+			args[pt] = VarInfo(count);
+dprintf(">");
+		} else if (*d == 0x61 && (d[1] >= 0x00 && d[1] <= 0x04) && d[2] == 0x28 ) {
+			/* 使われるコマンドは 01-21:004b, 01-28:0064 のいずれか(R,C,PB,LO)
+			** それらのコマンドは
+			** arg1: 画像ファイル名
+			** arg2 : Sel 番号
+			** らしく、arg3 以降が 0x61 <00-04> (a,b,c,...) となる(ダンプ上は enum と表記される)
+			** () 内の引数はさまざまで、a のみ(画像ファイル名)、
+			** a,b b=SEL?
+			** a,b,c (b,c)=座標?
+			** a,(b,c,d,e,f,g) b-g = src / dest?
+			** らしい
+			*/
+			dprintf("kasane. #%d <",d[1]);
+			d += 2;
+			int pt = args.size(); args.push_back(VarInfo(0));
+			int count = GetArgs(d);
+			args[pt] = VarInfo(count);
+			dprintf(">");
+		} else if (*d == 0x24 || (*d == 0x5c && (d[1] == 1 || d[1] == 0))) {
+			/* cmd 01-15:0028 ; 始めに 0x24 節があり、続いて 0x28 節になる */
+			VarInfo var;
+			GetExpression(d, &var);
+			args.push_back(var);
+			i--; // この引数はargc の数には入らない
+		} else SetError();
+		if (d[0] == 0x0a || d[0] == 0x40) {
+			/* cmd 01-15:0028 ; 0x28 節の後に毎回 0x0a 節が来る */
+			int var;
+			if (system_version == 0) { var = read_little_endian_int(d+1); d += 5;}
+			else { var = read_little_endian_short(d+1); d += 3;}
+			dprintf("line %d; ",var);
+		}
+		if (*d == 0x29) break;
+		if (*d == 0x2c) {d++;} // 次の arg が演算子で始まる、などがなければ存在しない
+		dprintf(",");
+	}
+	if (*d == 0x29) d++;
+	else SetError();
+	return 0;
+}
+
+/* switch
+	<exp>
+	0x7b
+		<exp> <int>
+		...
+	0x7d
+*/
+
+int Cmd::GetSwitch(const char*& d) {
+	if (*d != 0x28) {SetError(); return -1;}
+	d++;
+	dprintf("switch. ");
+	int var = GetExpression(d);
+	if (*d != 0x29) {SetError(); return -1;}
+	d++;
+	dprintf("->\n");
+	if (*d == 0x7b) {
+		d++;
+	} else SetError();
+
+	int default_jmp = -1; int jmpto = -1;
+	int i; for (i=0; i<argc; i++) {
+		dprintf("\t");
+		if (*d++ != 0x28) {SetError(); return -1;}
+		int item = -1; // default
+		if (*d != 0x29) {
+			int item = GetExpression(d);
+			if (*d++ != 0x29) {SetError(); return -1;}
+			int jmp = read_little_endian_int(d);
+			if (var == item) {
+				dprintf("(selected)");
+				jmpto = jmp;
+			}
+			dprintf(" -> %d\n", jmp);
+		} else {
+			d++;
+			default_jmp = read_little_endian_int(d);
+		}
+		d += 4;
+	}
+	if (default_jmp != -1) {
+		dprintf("default -> %d\n",default_jmp);
+		if (jmpto == -1) jmpto = default_jmp;
+	}
+	if (*d == 0x7d) {
+		d++;
+	} else SetError();
+	return jmpto;
+}
+/* simple switch
+	<exp>
+	0x7b
+		<int>
+		...
+	0x7d
+*/
+int Cmd::GetSimpleSwitch(const char*& d) {
+	if (*d != 0x28) {SetError(); return -1;}
+	d++;
+	dprintf("simple switch. ");
+	int var = GetExpression(d);
+	if (*d != 0x29) {SetError(); return -1;}
+	d++;
+	dprintf(" ->\n");
+	int jumpto = -1;
+	if (*d == 0x7b) {
+		d++;
+	} else SetError();
+	int i; for (i=0; i<argc; i++) {
+		int j = read_little_endian_int(d);
+		d += 4;
+		dprintf("\t%d -> %d\n", i+1, j);
+		if (var == i) jumpto = j;
+	}
+	if (*d == 0x7d) {
+		d++;
+	} else SetError();
+	return jumpto;
+}
+
+/*
+selection
+	? <exp>
+	0x7b
+		<0x0a|0x40> <ushort | uint> 
+*/
+void Cmd::GetSelection(const char*& d) {
+	dprintf("selection. ");
+	if (*d == 0x28) {
+		d++;
+		GetExpression(d);
+		if (*d != 0x29) { SetError(); return;}
+		d++;
+	}
+	if (*d == 0x7b) {
+		d++;
+		dprintf("{\n\t");
+	} else SetError();
+	int arg_count = 0;
+	string text = "";
+	int cond_result = false;
+	int sel_no = 0;
+	while(*d != 0x7d) {
+		if (d[0] == 0x0a || d[0] == 0x40) {
+			int var;
+			if (system_version == 0) { var = read_little_endian_int(d+1); d += 5;}
+			else { var = read_little_endian_short(d+1); d += 3;}
+			dprintf("Line %d; ",var);
+			if (text.length() != 0) {
+				if (cond_result) ; // 条件節が true なら表示しない
+				else {
+					const char* str = text.c_str();
+					VarInfo var;
+					var.type = TYPE_STR;
+					var.value = CopyString(str);
+					args.push_back(var);
+					var.type = TYPE_VAL;
+					var.value = sel_no;
+					args.push_back(var);
+				}
+				sel_no++;
+			}
+			text = "";
+			cond_result = false;
+		} else if (d[0] == 0x2c) {
+			dprintf(":comma:");
+		} else if (d[0] == 0x28) {
+			dprintf(":cond:");
+			d++;
+			while(d[0] != 0x29) {
+				int result = GetExpressionCond(d); // PRINT- 節でないばあい、条件表示。次は文字節、またはPRINT節のはず
+				if (*d == 0x32) { // 0x32 なら、現在の条件節を表示しない
+					d++; dprintf("##");
+					cond_result = result;
+				} else if (*d == 0x31) { // 0x31 なら、現在の条件節を表示する
+						// Little Busters! : この条件で正しいかは未検証
+					d++; dprintf("***");
+					cond_result = !result;
+				}
+				dprintf(":");
+			}
+			d++;
+		} else if (StrType(d)) {
+			int strpt = GetString(d);
+			text += strheap + strpt;
+			arg_count++;
+			dprintf("\n\t");
+		} else if (*d == 0x23 && strncmp(d,"###PRINT",8) == 0) {
+			d += 8;
+			if (d[0] != 0x28) SetError();
+			else { // 文字変数の内容の表示
+				d++;
+				dprintf("Print.");
+				VarInfo info;
+				GetLeftToken(d, info);
+				if (d[0] != 0x29 || info.type == -1) SetError();
+				d++;
+				dprintf(";");
+				// 数値を全角文字に変換して登録
+				char str[10], str2[20]; // itoa
+				sprintf(str, "%d", info.value);
+				int i; for (i=0; str[i] != 0; i++) {
+					str2[i*2] = 0xa3;
+					str2[i*2+1] = 0xb0 + str[i]-'0';
+				}
+				str2[i*2] = 0;
+				text += str2;
+			}
+		} else { SetError(); break;}
+	}
+	d++;
+	/* @@@ */
+	/* 一致しない場合があるのでコメントアウト */
+	// if (arg_count != argc) SetError();
+	dprintf("\n}\n");
+	return;
+}
+
+static char* op_str3[11] = { "+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=", "<<=", ">>=", "="};
+void Cmd::GetCmd(Flags& flags_orig, const char*& d ) {
+	if (d == 0) { SetError(); return;}
+	if (cmd_type != CMD_NOP) return;
+
+	cmdstr[0] = 0;
+	rawdata = d;
+	if (*d == 0x23) { /* コマンド */
+		cmd_type = CMD_OTHER;
+		cmd1 = *(unsigned const char*)(d+1);
+		cmd2 = *(unsigned const char*)(d+2);
+		cmd3 = read_little_endian_short(d+3);
+		argc = read_little_endian_short(d+5);
+		cmd4 = *(unsigned const char*)(d+7);
+		d += 8;
+		/* verbose */
+			// dprintf(" 0x23 - cmd %02x-%02x:%04x:%02x[%2d] \n",cmd1,cmd2,cmd3,cmd4,argc);
+			sprintf(cmdstr, "%02x-%02x:%04x:%02x",cmd1,cmd2,cmd3,cmd4);
+		/* 引数を得る */
+		/* 特殊引数のもの */
+		int is_special = 0;
+		if (cmd1 == 0) {
+			if (cmd2 == 1) {
+				int jump_arg = -1;
+				if (cmd3 == 0 || cmd3 == 5) {
+					/* gosub / goto */
+					jump_arg =read_little_endian_int(d);
+					d += 4;
+					if (cmd3 == 0)
+						dprintf("\tjmp -> %d\n", jump_arg);
+					else /* cmd3 == 5 */
+						dprintf("\tcall -> %d\n", jump_arg);
+					is_special = 1;
+				} else if (cmd3 == 1 || cmd3 == 2) {
+					/* conditional jump (if / unless) */
+					if (*d++ != 0x28) { SetError(); return;}
+					dprintf("\t");
+					int cond = GetExpressionCond(d);
+					if (cmd3 == 1) cond = !cond; // 逆になる
+					if (*d++ != 0x29) { SetError(); return; }
+					int jumpto = read_little_endian_int(d);
+					d += 4;
+					dprintf("-> %d\n", jumpto);
+					if (! cond) jump_arg = jumpto; /* condition が満たされない場合、ジャンプ */
+					is_special = 1;
+				} else if (cmd3 == 4) {
+					/* switch to */
+					jump_arg = GetSwitch(d);
+					is_special = 1;
+				} else if (cmd3 == 8 || cmd3 == 3) {
+					/* switch to */
+					jump_arg = GetSimpleSwitch(d);
+					is_special = 1;
+				} else if (cmd3 == 16) { // call with parameters
+					GetArgs(d);
+					jump_arg = read_little_endian_int(d);
+					d += 4;
+					is_special = 1;
+				} else goto retry;
+				if (jump_arg == -1) {
+					cmd_type = CMD_NOP;
+				}
+				else {
+					cmd_type = CMD_JMP;
+					args.push_back(VarInfo(jump_arg));
+				}
+			} else if (cmd2 == 2 && (cmd3 == 0 || cmd3 == 1 || cmd3 == 2 || cmd3 == 3 || cmd3 == 0x0d) ) {
+				/* selection */
+				GetSelection(d);
+				is_special = 1;
+			}
+		}
+retry:
+		/* 一般引数のもの */
+		if (!is_special) {
+			dprintf(" 0x23 - cmd %02x-%02x:%04x:%02x[%2d] \n",cmd1,cmd2,cmd3,cmd4,argc);
+			dprintf("\t");
+			if (cmd1 == 1 && cmd2 == 0x22 && (cmd3 == 0xc1c || cmd3 == 0x835)) GetArgsSpecial(3, d);
+			else if (cmd1 == 1 && cmd2 == 0x0b && cmd3 == 0x65) GetArgsSpecial(0, d);
+			else if (cmd1 == 1 && cmd2 == 0x15 && cmd3 == 0x28) GetArgsSpecial(0, d);
+			else if (cmd1 == 1 && cmd2 == 4 && (cmd3 == 0x26c || cmd3 == 0x26d || cmd3 == 0x270 || cmd3 == 0x276)) GetArgsSpecial(0, d);
+			else if (cmd1 == 1 && cmd2 == 4 && cmd3 == 0x586) GetArgsSpecial(1, d);
+			else if (cmd1 == 1 && (cmd2 == 0x21 && cmd3 == 0x4b) || (cmd2 == 0x28 && cmd3 == 0x64)) GetArgsSpecial(2,d);
+			else GetArgs(d);
+			dprintf("\n");
+
+		}
+	} else if (*d == 0x24) { /* 代入演算 */
+		if (d[1] == 0x12 || d[2] != 0x5b) SetError();
+		dprintf("expr: ");
+		sprintf(cmdstr, "expr");
+
+		VarInfo info;
+		int value = GetLeftToken(d, info);
+		if (d[0] != 0x5c) SetError();
+		int type = d[1];
+		if (type < 20 || type > 30) SetError();
+		else dprintf("%s",op_str[type]);
+		d += 2;
+		int value2 = GetExpression(d);
+		// 代入情報を埋め込む
+		if (type != 30) value2 = eval(value, type-20, value2);
+		cmd_type = CMD_FLAGS;
+		args.push_back(info);
+		args.push_back(value2);
+		dprintf("\n");
+	} else if (StrType(d)) { /* 文字出力 */
+		VarInfo info;
+		info.type = TYPE_STR;
+		info.value = GetString(d);
+		args.push_back(info);
+		cmd_type = CMD_TEXT;
+		dprintf("\n");
+	} else if (*d == 0x0a || *d == 0x40 || *d == 0x21) { /* デバッグ用データと既読フラグ */
+		cmd_type = CMD_NOP;
+		if (*d == 0x0a) {
+			dprintf("line ");
+			d++;
+			int l;
+			if (system_version == 0) {
+				l = read_little_endian_int(d);
+				d += 4;
+			} else {
+				l = read_little_endian_short(d);
+				d += 2;
+			}
+			dprintf("%d\n", l);
+		} else { /* 0x40, 0x21 */
+			// 既読マーカーらしい。エントリーポイントとセーブポイントも使われる。
+			// RealLive 1.2.5から、0x40はセーブポイント、0x21はエントリーポイント。
+			// 1.2.5以前、どちらも0x40が使われる。
+			int kidoku_index;
+			d++;
+			if (system_version == 0) {
+				kidoku_index = read_little_endian_int(d);
+				d += 4;
+			} else {
+				kidoku_index = read_little_endian_short(d);
+				d += 2;
+			}
+			dprintf("kidoku marker %d\n", kidoku_index);
+			// text_readflagは、このkidoku_indexを使ったら良いかな。
+		}
+	} else if (*d == 0x2c) { /* ??? */
+		dprintf("commd;0x2c\n"); // conditional jump の行き先によくあるらしい(常に、かはわからない)
+		d++;
+	} else { 
+		SetError();
+	}
+	return;
+}
+void Cmd::clear(void) {
+	cmd_type = CMD_NOP;
+	ResetString();
+	args.clear();
+	errorflag = false;
+	pos = -1;
+}
+
+char Cmd::strtype[256] = {
+	0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +00 */
+	0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +10 */ // 0123456789ABCDEF
+	1,0,3,0, 0,0,0,1, 0,0,0,0, 0,1,1,0, /* +20 */ //  !"#$%&'()*+,-./
+	1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,1, /* +30 */ // 0123456789:;<=>?
+	0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, /* +40 */ // @ABCDEFGHIJKLMNO
+	1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,1, /* +50 */ // PQRSTUVWXYZ[\]^_
+	0,0,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, /* +60 */ // `abcdefghijklmno
+	1,1,1,1, 1,1,1,1, 1,1,1,1, 0,0,0,0, /* +70 */ // pqrstuvwxyz{|}~
+	2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, /* +80 */
+	2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, /* +90 */
+	0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +A0 */
+	0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +B0 */
+	0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +C0 */
+	0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +D0 */
+	2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, /* +E0 */
+	2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,0,0  /* +F0 */
+};
+
+int Cmd::GetString(const char*& d) {
+	int retnum = -1;
+	bool quote_flag = false;
+	int stype;
+	retnum = strend;
+	while(1) {
+		if (*d == '\\') {
+			d++;
+			strheap[strend++] = *d++;
+		} else if (*d == '"') {
+			if (quote_flag) quote_flag = false;
+			else quote_flag = true;
+			d++;
+		} else if (quote_flag) {
+			strheap[strend++] = *d++;
+		} else if (stype = StrType(d)) {
+			strheap[strend++] = *d++;
+			if (stype == 2) strheap[strend++] = *d++;
+		} else break;
+	}
+	strheap[strend++] = 0;
+	dprintf("\"%s\"", strheap + retnum);
+	if (strend >= STRHEAP_SIZE) {
+		dprintf("Error: string heap overflow\n");
+	}
+	return retnum;
+}
+
+int Cmd::CopyString(const char* d) {
+	int retnum = strend;
+	int len = strlen(d);
+	memcpy(strheap+strend, d, len+1);
+	strend += len+1;
+	d += len+1;
+	return retnum;
+}
+
+int Cmd::StrVar(int type, int var_num) {
+	int retnum = strend;
+	flags.Str(type, var_num, strheap+strend, STRHEAP_SIZE-strend);
+	strend += strlen(strheap+strend)+1;
+	return retnum;
+}
+
+void Cmd::SetSysvar(int n, int val) {
+	VarInfo info;
+	if (cmd_type != CMD_SYSVAR) {
+		args.clear();
+	}
+	cmd_type = CMD_SYSVAR;
+
+	info.type = TYPE_SYS;
+	info.number = n;
+	info.value = val;
+	args.push_back(info);
+}
+void Cmd::SetFlagvar(VarInfo info, int val) {
+	if (cmd_type != CMD_SYSVAR) {
+		args.clear();
+	}
+	cmd_type = CMD_SYSVAR;
+
+	info.value = val;
+	args.push_back(info);
+}
+
+void Cmd::SetStrvar(VarInfo info, const string& s) {
+	if (cmd_type != CMD_SYSVAR) {
+		args.clear();
+	}
+
+	cmd_type = CMD_SYSVAR;
+	const char* ss = s.c_str();
+	info.value = CopyString(ss);
+	args.push_back(info);
+}
+
+void Cmd::read(const CmdSimplified& from) {
+	errorflag = false;
+	ResetString();
+
+	cmd_type = Cmdtype(from.type);
+	cmd1 = from.cmd1;
+	cmd2 = from.cmd2;
+	cmd3 = from.cmd3;
+	cmd4 = from.cmd4;
+	argc = from.argc;
+	/* args の読み込み */
+	args.clear();
+	char* d = from.args;
+	if (d == 0) return;
+	while(*d != TYPE_END) {
+		VarInfo info;
+		switch(*d) {
+		case TYPE_VAL:
+			info.type = TYPE_VAL;
+			info.number = 0;
+			info.value = read_little_endian_int(d+1);
+			d += 5;
+			args.push_back(info);
+			break;
+		case TYPE_STR:
+			info.type = TYPE_STR;
+			info.number = 0;
+			d++;
+			info.value = CopyString( d);
+			d += strlen(d)+1;
+			args.push_back(info);
+			break;
+		default:
+			fprintf(stderr,"Cmd::read: Invalid Load Data\n");
+			*d = TYPE_END;
+		}
+	}
+	return;
+}
+void Cmd::write(CmdSimplified& to, char*& buffer) const {
+/*
+	if (cmd_type != CMD_OTHER) {
+		fprintf(stderr,"Cmd::write: Invalid Cmd during Saving Data\n");
+		to.cmd1 = 0; to.cmd2 = 0; to.cmd3 = 0; to.cmd4 = 0; to.argc = 0; to.args = 0;
+		return;
+	}
+*/
+	to.type = cmd_type;
+	to.cmd1 = cmd1;
+	to.cmd2 = cmd2;
+	to.cmd3 = cmd3;
+	to.cmd4 = cmd4;
+	to.argc = argc;
+	/* args の書き込み */
+	if (args.empty()) {
+		to.args = 0;
+	} else {
+		to.args = buffer;
+		char* d = to.args;
+		vector<VarInfo>::const_iterator it;
+		for (it = args.begin(); it != args.end(); it++) {
+			int type = it->type;
+			if ( (type >= 0 && type < 7) || type == TYPE_VAL || type == char(TYPE_SYS)) { // digits
+				*d++ = TYPE_VAL;
+				write_little_endian_int(d, it->value);
+				d += 4;
+			} else if (type == TYPE_VARSTR || type == TYPE_VARSYSSTR || type == TYPE_VARLOCSTR || type == TYPE_STR) { // string
+				*d++ = TYPE_STR;
+				const char* s = Str(*it);
+				int len = strlen(s);
+				memcpy(d, s, len+1);
+				d += len+1;
+			} else {
+				fprintf(stderr,"Cmd::write: Invalid Cmd args during Saving Data\n");
+			}
+		}
+		*d++ = TYPE_END;
+		buffer = d;
+	}
+}
+void CmdSimplified::copy(const CmdSimplified& from, char*& args_buffer) {
+	*this = from;
+	if (args == 0) return;
+	char* args_old = from.args;
+	/* args のコピー */
+	while(*args_old != TYPE_END) {
+		if (*args_old == TYPE_VAL) {
+			args_old += 5;
+		} else { /* TYPE_STR */
+			args_old += strlen(args_old)+1;
+		}
+	}
+	args_old++;
+	int args_len = args_old - from.args;
+	memmove(args_buffer, from.args, args_len);
+	args = args_buffer;
+	args_buffer += args_len;
+}
+void CmdSimplified::Save(string& saveret) {
+	char buf[1024];
+	sprintf(buf, "%02x-%02x:%04x:%02x(%02d),", cmd1, cmd2, cmd3, cmd4, argc);
+	saveret += buf;
+	
+	/* args のコピー */
+	char* d = args;
+	while(d && *d != TYPE_END) {
+		if (*d == TYPE_VAL) {
+			d++;
+			sprintf(buf, "%d,", read_little_endian_int(d));
+			d += 4;
+		} else { /* TYPE_STR と仮定 */
+			d++;
+			if (strlen(d) > 1000) d[1000] = 0; // ありえない・・・
+			int i; int cnt = 0;
+			buf[cnt++] = '"';
+			for (i=0; d[i] != 0; i++) {
+				if (d[i] == '"') buf[cnt++] = '"';
+				buf[cnt++] = d[i];
+			}
+			buf[cnt++]='"';
+			buf[cnt++] = ',';
+			buf[cnt++] = 0;
+			d += strlen(d)+1;
+		}
+		saveret += buf;
+	}
+	saveret += 'E';
+}
+
+void CmdSimplified::Load(const char* save, char*& args_buffer) {
+	args = args_buffer;
+
+	type = CMD_OTHER;
+	sscanf(save, "%02x-%02x:%04x:%02x(%02d),", &cmd1, &cmd2, &cmd3, &cmd4, &argc);
+	save = strchr(save, ',');
+	if (save == 0) {
+		*args_buffer++ = TYPE_END;
+		return;
+	}
+	save++;
+	while(*save != 'E' && *save != '\n' && *save != '\0') {
+		if (isdigit(*save)) {
+			int v;
+			sscanf(save,"%d,",&v);
+			*args_buffer++ = TYPE_VAL;
+			write_little_endian_int(args_buffer, v);
+			args_buffer+= 4;
+			save = strchr(save, ',');
+			if (save) save++;
+		} else { // *save == '"'
+			save++;
+			*args_buffer++ = TYPE_STR;
+			while(1) {
+				if (*save == 0) break;
+				if (*save == '"') {
+					if (save[1] != '"') break;
+					save++;
+				}
+				*args_buffer++ = *save++;
+			}
+			save += 2;
+			*args_buffer++ = 0;
+		}
+	}
+	*args_buffer++ = TYPE_END;
+	return;
+}
+
+#ifdef SCN_DUMP
+void usage(void) {
+	fprintf(stderr,"usage : scn2kdump [inputfile] [outputfile]\n");
+	fprintf(stderr,"  inputfile:  seen.txt(default)\n");
+	fprintf(stderr,"  outputfile: seen.txt_out(default)\n");
+	exit(-1);
+}
+int main(int argc, char** argv) {
+	/* determine file names */
+	bool verbose = false;
+	char* inname = "seen.txt";
+	char* outname = 0;
+	if (argc > 2 && strcmp(argv[1],"-v") == 0) {
+		int i; for (i=1; i<argc; i++) argv[i] = argv[i+1];
+		argc--;
+		verbose = true;
+	}
+	switch(argc) {
+	case 1: break;
+	case 2: inname = argv[1]; break;
+	case 3: inname = argv[1]; outname = argv[2]; break;
+	default: usage();
+	}
+	/* open output file */
+	FILE* outstream = stdout;
+	/* create archive instance */
+	SCN2kFILE archive(inname);
+	archive.Init();
+	if (archive.Deal() == 0) {
+		fprintf(stderr,"Cannot open / Invalid archive file %s\n",inname);
+		usage();
+	}
+	/* dump files */
+	archive.InitList();
+	char* fname;
+	fprintf(stderr,"Dump start\n");
+	int system_version = 0;
+	while( (fname = archive.ListItem()) != 0) {
+		ARCINFO* info = archive.Find(fname,"");
+		if (info == 0) continue;
+		char* data = info->CopyRead();
+		char* d = data;
+		char* dend = d + info->Size();
+		/* version 確認 */
+		if (read_little_endian_int(d) == 0x1cc) {
+			system_version = 0;
+		} else if (read_little_endian_int(d) == 0x1d0) {
+			system_version = 1;
+		} else {
+			continue;
+		}
+		if (read_little_endian_int(d+4) == 0x1adb2) ; // little busters!
+		else if (read_little_endian_int(d+4) != 0x2712) continue;
+		int header_size;
+		if (system_version == 0) {
+			header_size = 0x1cc + read_little_endian_int(d+0x20) * 4;
+		} else {
+			header_size = read_little_endian_int(d+0x20);
+		}
+		d += header_size;
+
+		const char* dcur = d;
+		const char* dstart = d;
+		fprintf(stderr,"Dumping %s\n",fname);
+		Flags flags;
+		/* 最初から最後までコマンド取得 -> 出力を繰り返す */
+		while(dcur<dend) {
+			const char* dprev = dcur;
+			Cmd cmd(flags, system_version); cmd.ClearError();
+
+			/* end? */
+			if (*dcur == -1) {
+				/* 0xff x 32byte + 0x00 : end sign */
+				int i; for (i=0; i<0x20; i++)
+					if (dcur[i] != -1) break;
+				if (i == 0x20 && dcur[i] == 0) break;
+			}
+			dprintf("%d : ",dcur-dstart);
+			cmd.GetCmd(flags, dcur);
+			if (cmd.IsError()) {
+				fprintf(outstream, "Error at %6d\n",dprev-dstart);
+				while(dcur < dend) {
+					if (*dcur == 0x29 && dcur[1] == 0x0a) {dcur++;break;}
+					dcur++;
+				}
+				dprev -= 2*16;
+				int ilen = (dcur-dprev+15)/16;
+				int i; for (i=0; i<ilen; i++) {
+					fprintf(outstream, "%6d: ",dprev-dstart);
+					int j; for (j=0; j<16; j++) {
+						if (dprev >= dend) break;
+						if (dprev < data) continue;
+						fprintf(outstream, "%02x ",*(unsigned char*)(dprev));
+						dprev++;
+					}
+					fprintf(outstream, "\n");
+				}
+			}
+		}
+		delete info;
+	}
+	return 0;
+}
+#endif
+
new file mode 100644
--- /dev/null
+++ b/scn2k/scn2k_grp.cc
@@ -0,0 +1,2259 @@
+/*
+ * Copyright (c) 2004-2006  Kazunori "jagarl" Ueno
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include"scn2k.h"
+#include"window/widget.h"
+#include"system/file.h"
+#include"system/system_config.h"
+#include"font/text.h"
+#include<set>
+
+using namespace std;
+
+extern void DSurfaceFill(Surface* dest, const Rect& rect, int r, int g, int b, int a=0xff);
+extern void DSurfaceMove(Surface* src_o, const Rect& srcrect, Surface* dst_o, const Rect& dstpos);
+extern Rect DSurfaceRenderText(TextGlyphStream::iterator start, TextGlyphStream::iterator end, const Rect& srcrect,
+        Surface* dst, const Rect& dstrect);
+extern XKFont::HorizLayout* DefaultLayout(int text_size);
+
+/*******************************************************************
+** GrpObj(interface)
+*/
+
+struct SEL {
+	Rect from;
+	Rect to;
+	int time;
+	int sel_no;
+	int args[8];
+	SEL() : from(0,0), to(0,0) {}
+};
+
+struct GrpObj {
+	string name;
+	string gan_name;
+	PicContainer* pic_parent;
+	PicBase* picture;
+	WidAnmTime* anm;
+	int _posx, _posy;
+	int posx[9],posy[9];
+	Rect clip_area;
+	unsigned char alpha;
+	int order;
+	int surface_num;
+
+	string print_moji;
+	int print_size, print_r, print_b, print_g;
+
+	int dig_number, dig_digit;
+
+	// zoom / rotate 関係
+	int zoom; // 256 で 1 倍
+	int rotate; // 0-360度
+
+	vector<Rect> src_pos;
+	enum GrpType { FILLRECT = 1, FILE = 2, GAN = 3, MOJI = 4, DIGIT = 5} gtype;
+	enum Attribute { NONE=0, WIPEON=1, SATURATE=2, HIDDEN=4, HIDDEN_GROUP=8,
+		UPDATE_PICTURE = 8, UPDATE_POS = 16, UPDATE_ALPHA = 32, UPDATE_SNUM = 64, UPDATE_CLIP = 128, UPDATE_VISIBLE = 256,
+		UPDATE_ALL = (8|16|32|64|128|256),
+		ANM_PLAYSTART = 0x8000, ANM_PLAYING = 0x10000,
+		DIG_ZERO = 0x10000*2, DIG_SIGN = 0x10000*4, DIG_PACK=0x10000*8,DIG_SPACE=0x10000*16
+		};
+	Attribute attr;
+
+	GrpImpl* parent_pimpl;
+
+	GrpObj(void);
+	~GrpObj(void);
+
+	void SetPos(int index, int x, int y);
+	void GetPos(int index, int& x, int& y);
+	int PosX(void);
+	int PosY(void);
+	void SetAlpha(void);
+	void SetAlpha(int alpha);
+	void SetSurfaceNum(int num = -1);
+	void SetZoomRotate(int zoom=-1, int rotate=-1);
+	void SetClipArea(int x, int y, int width, int height);
+	void GetSrcGeom(int& width, int& height);
+	void SetUpdate(void);
+	TextStream ParseMoji(const char* str, int def_r ,int def_g, int def_b, int def_size);
+	void UpdateMoji(void);
+	void UpdateDigit(void);
+	void UpdateSurface(void);
+	void ZoomRotate(void);
+	void Update(void);
+	void CreateSurface(PicContainer* parent);
+	void CreateGan(Event::Container& event, int event_number);
+	void CreateGanSpecial(Event::Container& event, int event_number, int time);
+	PicBase* DeletePic(void);
+};
+
+/*******************************************************************
+** GrpObj(interface)
+*/
+
+
+struct GrpObjMap : std::map<int, GrpObj> {
+	typedef pair<const int, GrpObj> value_type;
+	class GrpImpl* parent;
+	GrpObj& operator[](const int& k) {
+		iterator it = lower_bound(k);
+		if (it == end() || it->first != k) {
+			GrpObj obj;
+			obj.parent_pimpl = parent;
+			it = insert(it, value_type(k, obj));
+		}
+		return it->second;
+	}
+	GrpObjMap(class GrpImpl* p) {
+		parent = p;
+	}
+};
+
+class GrpImpl {
+#define MAXPDT 256
+#define WORKPDT 255
+	Event::Container& event;
+	const Flags& flags;
+	PicBase* screen;
+	PicBase* screen_front;
+	Surface* surface, *surface_update;
+
+	Surface* dsurface[MAXPDT]; // 書き込み可能な Surface
+	Surface* ssurface[MAXPDT]; // ファイルの内容等、読み込みのみ可能な状態の Surface
+	PicContainer& parent;
+
+	// 画像効果の保存用
+	WidAnmTime* anm1, *anm2;
+	typedef enum { NORMAL, WAIT_ANM, WAIT_SHAKE, WAIT_SE, WAIT_MOVIE} Status;
+	Status status;
+	SkipMode skip_mode;
+
+	std::string bg_name;
+	std::map<int, SEL> anmtype;
+	GrpObjMap grpobj;
+	GrpObjMap bs_obj;
+	void CreateObj(int number);
+	void ZMoveObj(int number);
+	void SetObjChanged(int number);
+	void SetObjChangedGroup(int number);
+	void SwapObj(int a1, int a2);
+	void DeleteObjPic(int num);// object の surface のみ削除
+	void DeleteObj(int num);
+	void DeleteObjRange(int num_b, int num_e);
+
+	std::set<int> changed_obj;
+	string reserved_load_surface0;
+	vector<PicBase*> deleted_pic;
+	void RefreshObj(void);
+
+	Surface* Dsurface(int pdt);
+	Surface* Ssurface(int pdt);
+
+	// cgmode 用画像処理関連
+	void LoadCgm(AyuSysConfig& config);
+	std::map<std::string, int> cgm_info;
+	set<int>& cgm_data;
+	
+	class MuSys& music;
+
+public:
+	AyuSysConfig& config;
+	void LoadSurface(const char* str, int pdt);
+private:
+	void LoadSurface(const char* str);
+	void LoadSurface(void);
+	void AddSurface(const char* str);
+
+	void StartAnm(int type);
+	void StartShake(int total, const int* pattern);
+	void AbortAnm(void);
+	static bool Pressed(int x, int y, void* pointer);
+public:
+	GrpImpl(Event::Container& _event, PicContainer& _parent, const Flags& _flag, set<int>& _cgm_data, class MuSys& mu, AyuSysConfig& config);
+	~GrpImpl();
+	bool Wait(unsigned int current_time, Cmd& cmd);
+	void Exec(Cmd& cmd);
+	void InitSel(AyuSysConfig& config);
+	void Save(std::string& str);
+	void Load(const char* str);
+	void SaveSys(std::string& str);
+	void LoadSys(const char* str);
+	void SetSkipMode(SkipMode _mode);
+};
+/*******************************************************************
+** GrpObj(implementation)
+*/
+
+GrpObj::GrpObj(void) :
+	name(""), gan_name(""), pic_parent(0), picture(0), anm(0),
+	_posx(0), _posy(0), clip_area(0,0,0,0),
+	alpha(255), order(0), surface_num(0), print_moji(""), print_size(0), print_r(-1),print_g(-1),print_b(-1),
+	dig_number(0), dig_digit(0),
+	zoom(-1), rotate(-1), attr(GrpObj::HIDDEN), parent_pimpl(0) {
+	int i;
+	for (i=0; i<9; i++) {
+		posx[i] = posy[i] = 0;
+	}
+}
+GrpObj::~GrpObj() {
+	if (picture) delete picture;
+	if (parent_pimpl == 0) {
+		fprintf(stderr,"\n**************\nFATAL : UNINITIALIZED GrpObj IS FOUND!!! \n**************\n");
+	}
+}
+int GrpObj::PosX() {
+	return _posx;
+}
+int GrpObj::PosY() {
+	return _posy;
+}
+void GrpObj::SetUpdate(void) {
+	attr = Attribute (attr | UPDATE_PICTURE);
+}
+void GrpObj::SetPos(int index, int x,int y) {
+	if (index < 0 || index > 8) {
+		fprintf(stderr,"GrpObj::SetPos: Invalid index %d <- %d,%d\n",index,x,y);
+		return;
+	}
+	if (x == posx[index] && y == posy[index]) return;
+	attr = Attribute(attr | UPDATE_POS);
+	_posx += x-posx[index];
+	_posy += y-posy[index];
+	posx[index] = x;
+	posy[index] = y;
+}
+void GrpObj::GetPos(int index, int& x, int& y) {
+	if (index < 0 || index > 8) {
+		fprintf(stderr,"GrpObj::GetPos: Invalid index %d\n",index);
+		x = 0; y = 0;
+		return;
+	}
+	x = posx[index];
+	y = posy[index];
+	return;
+}
+void GrpObj::SetAlpha(int new_alpha) {
+	if (alpha == new_alpha) return;
+	alpha = new_alpha;
+	attr = Attribute(attr | UPDATE_ALPHA);
+	return;
+}
+void GrpObj::SetSurfaceNum(int num) {
+	if (num != -1) {
+		if (surface_num == num) return;
+		surface_num = num;
+	}
+	attr = Attribute(attr | UPDATE_SNUM);
+	return;
+}
+
+void GrpObj::SetClipArea(int x, int y, int w, int h) {
+	Rect new_clip(x,y,x+w,y+h);
+	if (clip_area == new_clip) return;
+	clip_area = new_clip;
+	attr = Attribute(attr | UPDATE_CLIP);
+	return;
+}
+PicBase* GrpObj::DeletePic(void) {
+	PicBase* p = picture;
+	anm = 0;
+	picture = 0;
+	src_pos.clear();
+	attr = Attribute(attr & (HIDDEN | HIDDEN_GROUP));
+	return p;
+}
+void GrpObj::GetSrcGeom(int& width, int& height) {
+	if (src_pos.empty()) {
+		width = 0; height = 0;
+		if (name.length() == 0) {
+			return;
+		}
+		/* ボタンの位置情報を求める */
+		/* g00 ファイルのヘッダ部分に位置情報は入っている */
+		string path(name);
+		path += ".g00";
+		ARCINFO* info = file_searcher.Find(FILESEARCH::PDT, path.c_str(), "g00");
+		if (info == 0) { // ファイルが見つからない
+			fprintf(stderr,"GrpObj::GetSrcGeom : Cannot find file %s\n", path.c_str());
+			return;
+		}
+		const char* data = info->Read();
+		int srclen = read_little_endian_int(data+5);
+		if (data && *data == 2) { // 画像ファイル内にボタン情報が存在する
+			int srclen = read_little_endian_int(data+5);
+			int i;
+			for (i=0; i<srclen; i++) {
+				int x1 = read_little_endian_int(data+9+i*24+0);
+				int y1 = read_little_endian_int(data+9+i*24+4);
+				int x2 = read_little_endian_int(data+9+i*24+8);
+				int y2 = read_little_endian_int(data+9+i*24+12);
+				src_pos.push_back(Rect(x1, y1, x2+1, y2+1));
+				if (width < src_pos.back().width()) width = src_pos.back().width();
+				if (height < src_pos.back().height()) height = src_pos.back().height();
+			}
+		} else { // 画像ファイルから大きさ取得
+			width = read_little_endian_short(data+1);
+			height = read_little_endian_short(data+3);
+			src_pos.push_back(Rect(0,0,width,height));
+		}
+		delete info;
+	}
+	int sn = surface_num;
+	if (sn < 0 || sn > src_pos.size()) sn = 0;
+	width = src_pos[sn].width();
+	height = src_pos[sn].height();
+	return;
+}
+void GrpObj::Update(void) {
+	if (attr & UPDATE_PICTURE) {
+		UpdateSurface();
+		attr = Attribute( (attr | UPDATE_ALL) & (~UPDATE_PICTURE));
+	}
+	if (picture == 0) return;
+	if (attr & UPDATE_POS) {
+		if (attr & SATURATE) {
+			int w=0, h=0;
+			GetSrcGeom(w,h);
+			picture->Move(_posx-w/2, _posy-h/2);
+		} else {
+			picture->Move(_posx, _posy);
+		}
+	}
+	if (attr & UPDATE_ALPHA) {
+		if (alpha <= 0) {
+			picture->SetSurfaceAlpha(0, Rect(0,0));
+			picture->hide();
+		} else if (alpha >= ALPHA_MAX) {
+			picture->SetSurfaceAlpha(0, Rect(0,0));
+			if (attr & HIDDEN) picture->hide();
+			else picture->show();
+		} else {
+			picture->SetSurfaceAlpha(&alpha, Rect(0,0,1,1));
+			if (attr & HIDDEN) picture->hide();
+			else picture->show();
+		}
+	}
+	if ( (attr & UPDATE_SNUM) && (!src_pos.empty())) {
+		if (surface_num < 0 || surface_num >= src_pos.size()) surface_num = 0;
+		picture->SetSurfacePos(src_pos[surface_num].lx, src_pos[surface_num].ty);
+	}
+	if (attr & UPDATE_CLIP) {
+		picture->SetClipArea(clip_area);
+	}
+	attr = Attribute(attr & (~UPDATE_ALL));
+	if (attr & ANM_PLAYSTART) {
+		if (anm) {
+			anm->Play();
+			attr = Attribute(attr | ANM_PLAYING);
+		}
+		attr = Attribute(attr & (~ANM_PLAYSTART));
+	}
+}
+void GrpObj::CreateSurface(PicContainer* parent) {
+	if (picture) {
+		PicBase* p = DeletePic();
+		delete p;
+	}
+	src_pos.clear();
+	// picture を作成
+	pic_parent = parent;
+	picture = parent->create_leaf(Rect(_posx,_posy,_posx+1,_posy+1), 0);
+	picture->hide();
+	UpdateSurface();
+}
+  
+void GrpObj::UpdateSurface(void) {
+	if (pic_parent == 0 || picture == 0) return;
+	int width = 0, height = 0;
+	if (gtype == FILE || gtype == GAN) {
+		if (name.length() == 0) return;
+		// ファイル名が存在する場合、ファイルを読み込み
+		GetSrcGeom(width, height);
+		if (width <= 0 || height <= 0) return;
+		// surface の設定
+		if (surface_num == 0 && ( (zoom > 0 && zoom != 256) || rotate > 0)) {
+			ZoomRotate();
+		} else {
+			// 普通に surface を設定
+			string path(name);
+			path += ".g00";
+			picture->SetSurface(path.c_str(), 0, 0);
+			picture->SetSurfaceRect(Rect(0,0,width,height));
+		}
+		if (attr & SATURATE)
+			picture->SetSurfaceAttribute(PicBase::BLIT_SATURATE);
+	} else if (gtype == MOJI) { // テキスト描画
+		if (print_moji.length() == 0) return;
+		UpdateMoji();
+	} else if (gtype == DIGIT) { // 数値を画像表示
+		UpdateDigit();
+	}
+}
+void GrpObj::ZoomRotate(void) {
+	picture->SetSurface( (Surface*)0,0,0);
+
+	// 回転、縮小拡大は座標原点が画像の中心になる
+	string path(name);
+	path += ".g00";
+	Surface* surface_orig = pic_parent->Root().NewSurface(path.c_str());
+	if (surface_orig == 0) return;
+
+	Surface* zoom_surface = pic_parent->Root().RotZoomSurface(surface_orig, double(zoom)/256.0, rotate);
+	Rect zoom_r (*zoom_surface);
+	picture->SetSurface(zoom_surface, 0, 0);
+	picture->SetSurfaceFreeFlag();
+	//picture->Move(PosX() + - zoom_r.width()/2, PosY() + - zoom_r.height()/2);
+// 中心座標がわからん・・・
+	picture->Move(320 - zoom_r.width()/2, 240 - zoom_r.height()/2);
+	picture->SetSurfaceRect(Rect(0, 0, zoom_r.width(), zoom_r.height()));
+
+	pic_parent->Root().DeleteSurface(surface_orig);
+}
+
+static char* wstrchr(const char* s, unsigned int chr) {
+	int ws, wc;
+	while(*s != 0) {
+		if (*s < 0 && s[1] != 0) {
+			wc = int((unsigned char)(s[0]))*0x100 + int((unsigned char)(s[1]));
+			ws = 2;
+		} else {
+			wc = (unsigned char)(s[0]);
+			ws = 1;
+		}
+		if (wc == chr) return (char*)s;
+		s += ws;
+	}
+	return 0;
+}
+TextStream GrpObj::ParseMoji(const char* str, int def_r ,int def_g, int def_b, int def_size) { // 制御シーケンス付き文字列をparse
+	TextStream ts;
+	ts.kanji_type = TextStream::sjis;
+	ts.SetColor(def_r, def_g, def_b);
+	char* copy_str = new char[strlen(str)+1];
+	char* next_str;
+	char* retptr;
+	int var;
+
+	while( (next_str = wstrchr(str, '#')) != 0) {
+		int len = next_str - str;
+		strncpy(copy_str, str, len);
+		copy_str[len] = 0;
+		ts.Add(copy_str);
+		str = next_str + 1;
+
+		switch(str[0]) {
+		case '#': // separator
+			str += 1;
+			break;
+		case 'D': case 'd': // return
+			ts.AddReturn();
+			str += 1;
+			break;
+		case 'C': case 'c': // color
+			str += 1;
+			var = strtol(str, &next_str,10);
+			if (var == 0 && str == next_str) { // no parameter
+				ts.SetColor(def_r, def_g, def_b);
+			} else {
+				int r,g,b; char key[1024];
+				sprintf(key, "#COLOR_TABLE.%03d", var);
+				if (parent_pimpl->config.GetParam(key, 3, &r, &g, &b)) { // color not found
+					r = g = b = 0;
+				}
+				ts.SetColor(r,g,b);
+				str = next_str;
+			}
+			break;
+		case 'S': case 's': // size
+			str += 1;
+			var = strtol(str, &next_str, 10);
+			if (var == 0 && str == next_str) { // no parameter
+				ts.SetSize(1);
+			} else {
+				if (def_size == 0) def_size = 20;
+				if (var <= 0) var = 1;
+				ts.SetSize(double(var)/def_size);
+			}
+			break;
+		case 'X': case 'x': // xpos : not supported
+		case 'Y': case 'y': // ypos : not supported
+		default:
+			ts.Add("#");
+			break;
+		}
+	}
+	ts.Add(str);
+	return ts;
+}
+void GrpObj::UpdateMoji(void) { // 文字の大きさ、色などを変更
+	if (print_moji.length() == 0) return;
+	if (pic_parent == 0) return;
+	/* テキストの大きさを得る */
+	int r, g, b;
+	if (print_r == -1 || print_g == -1 || print_b == -1) {// 色設定なし
+		r = g = b = 0;  // とりあえず黒(clannad のSave/Loadメニュー用)
+	} else {
+		r = print_r;
+		g = print_g;
+		b = print_b;
+	}
+	TextStream ts = ParseMoji(print_moji.c_str(), r, g, b, print_size);
+	TextGlyphStream gs;
+	vector<int> lh;
+	// とりあえず drawable width は充分に大きく(2048)取る
+	DefaultLayout(print_size-2)->Layout(ts, gs, lh, 2048); // print_size そのままだと弱干大きすぎるので -2
+	int width = gs.width();
+	int height = gs.height();
+	Surface* surface = pic_parent->Root().NewSurface(width, height, ALPHA_MASK);
+	DSurfaceFill(surface, Rect(*surface), 0, 0, 0, 0);
+	DSurfaceRenderText(gs.begin(), gs.end(), Rect(0, 0, width, height), surface, Rect(0,0));
+	picture->SetSurface(surface, 0, 0);
+	picture->SetSurfaceRect(Rect(0,0,width,height));
+	picture->SetSurfaceFreeFlag();
+}
+void GrpObj::UpdateDigit(void) {
+	// 画像表示の数値文字列を表示する
+	if (name.length() == 0) return;
+	// ファイル名が存在する場合、ファイルを読み込み
+	string path(name);
+	path += ".g00";
+	Surface* surface_orig = pic_parent->Root().NewSurface(path.c_str());
+	if (surface_orig == 0) return;
+
+	int width, height;
+	int i;
+	GetSrcGeom(width, height);
+	if (width <= 0 || height <= 0) return;
+	if (src_pos.size() < 14) {
+		// 必要な数の object がない
+		// 表示できない分の空の rect を追加しておく
+		for (i=src_pos.size(); i<14; i++)
+			src_pos.push_back(Rect(0,0,0,0));
+		pic_parent->Root().DeleteSurface(surface_orig);
+		return;
+	}
+	// 桁数の計算
+	char num_str[20];
+	if (dig_number < 0) sprintf(num_str, "%d", -dig_number);
+	else sprintf(num_str, "%d", dig_number);
+	int sign_count = 0;
+	int space_count = 0;
+	int total_count;
+	int dig_count = strlen(num_str);
+	if (dig_number < 0 && (attr&DIG_SIGN) == 0) dig_count++;
+	if (dig_count < dig_digit) space_count = dig_digit - dig_count;
+	if (attr & DIG_SIGN) sign_count = 1;
+	total_count = dig_count + space_count + sign_count;
+
+	Surface* surface = pic_parent->Root().NewSurface(width*total_count, height, ALPHA_MASK);
+	DSurfaceFill(surface, Rect(*surface), 0, 0, 0, 0);
+
+	/* surface にコピーする */
+	int cur_x = 0;
+	if ( (attr & DIG_PACK) && !(attr & DIG_ZERO)) { // 始めに空白を挿入
+		cur_x += space_count * width;
+	}
+	int plus = 10, minus = 11, plusminus = 12;
+	if (dig_number < 0) {
+		DSurfaceMove(surface, src_pos[minus], surface, Rect(cur_x,0));
+		cur_x += width;
+	} else if (attr & DIG_SIGN) {
+		if (dig_number == 0)
+			DSurfaceMove(surface, src_pos[plusminus], surface, Rect(cur_x,0));
+		else
+			DSurfaceMove(surface, src_pos[plus], surface, Rect(cur_x,0));
+		cur_x += width;
+	}
+	if (attr & DIG_ZERO) { // ゼロ・パディング
+		for (i=0; i<space_count; i++) {
+			DSurfaceMove(surface, src_pos[0], surface, Rect(cur_x, 0));
+			cur_x += width;;
+		}
+	} else if (!(attr & DIG_PACK)) { // PACK オプションなし
+		cur_x += space_count * width;
+	}
+	for (i=0; num_str[i] != 0; i++) {
+		DSurfaceMove(surface_orig, src_pos[num_str[i]-'0'], surface, Rect(cur_x, 0));
+		cur_x += width;
+	}
+	
+	/* picture に設定 */
+	picture->SetSurface(surface, 0, 0);
+	picture->SetSurfaceRect(Rect(0,0,width*total_count,height));
+	picture->SetSurfaceFreeFlag();
+
+	pic_parent->Root().DeleteSurface(surface_orig);
+}
+void GrpObj::CreateGan(Event::Container& event, int event_number) {
+	if (picture == 0) {
+		fprintf(stderr,"GrpObj::CreateGan() is called before Create()\n");
+		return;
+	}
+	if (anm) {
+		anm->Abort();
+		delete anm;
+	}
+	if (gan_name.empty()) return;
+	/* アニーメション情報 (.GAN ファイル)を求める */
+	string path(gan_name);
+	path += ".gan";
+	ARCINFO* info = file_searcher.Find(FILESEARCH::GAN, path.c_str(), "gan");
+	if (info == 0) {
+		fprintf(stderr,"GrpObj::CreateGan: Cannot Find 'GAN' file %s\n", path.c_str());
+		return;
+	}
+	const char* data = info->Read();
+	if (read_little_endian_int(data) != 10000 || read_little_endian_int(data+4) != 10000) {
+		fprintf(stderr,"GrpObj::CreateGan: Invalid'GAN' file %s\n", path.c_str());
+		delete info;
+		return;
+	}
+
+	picture->SetSurfaceAttribute(PicBase::BLIT_SATURATE);
+	attr = Attribute(attr | UPDATE_POS | SATURATE);
+
+	const char* buf = data + 16;
+	buf += strlen(buf) + 1; // 画像ファイル名が入っている
+	buf += 4; // 定数 20000
+	int pics = read_little_endian_int(buf); buf += 4; // 複数のアニメーション情報が入っている場合、情報数 
+	// 以下、pics 回繰り返し
+	// アニメーションを行う実体を作成
+	AnmAlphaMove* wid = new AnmAlphaMove(event, picture);
+
+	if (event_number && event_number < pics) { // 複数のアニメーション情報がある場合、先の情報を読み飛ばす */
+		int i; for (i=0; i<event_number; i++) {
+			buf += 4; // 定数 30000
+			int ptns = read_little_endian_int(buf); buf += 4;
+			buf += ptns*52;
+		}
+	}
+	buf += 4; // 定数 30000
+	int ptns = read_little_endian_int(buf); buf += 4;
+	int total_time = 0;
+	int i;
+	for (i=0; i<ptns; i++) {
+		int p = read_little_endian_int(buf+i*52+0*8+4);
+		int x = read_little_endian_int(buf+i*52+1*8+4);
+		int y = read_little_endian_int(buf+i*52+2*8+4);
+		int t = read_little_endian_int(buf+i*52+3*8+4);
+		int a = read_little_endian_int(buf+i*52+4*8+4);
+		x += PosX();
+		y += PosY();
+		if (p == -1) { a = 0; p = 0; } // p == -1 ならなにも表示しない
+		if (p >= src_pos.size()) {
+			fprintf(stderr,"Reading GAN file %s (G00 %s) : not enough pictures in .G00 file\n", path.c_str(), name.c_str());
+			a = 0; p = 0;
+		}
+		total_time += t;
+		wid->ptns.push_back(AnmAlphaMove::Ptn(Rect(x,y), src_pos[p], a, total_time));
+	}
+	wid->SetPtn(); // パターン登録終了
+	attr = Attribute(attr | ANM_PLAYSTART);
+	anm = wid;
+};
+void GrpObj::CreateGanSpecial(Event::Container& event, int event_number, int time) {
+	if (picture == 0) {
+		fprintf(stderr,"GrpObj::CreateGan() is called before Create()\n");
+		return;
+	}
+	if (anm) {
+		anm->Abort();
+		delete anm;
+	}
+
+	// アニメーションを行う実体を作成
+	AnmAlphaMove* wid = new AnmAlphaMove(event, picture);
+
+	int i;
+	switch(event_number) {
+	case 0: // pattern を 0 から最後まで変化させる
+		for (i=0; i<src_pos.size(); i++) {
+			wid->ptns.push_back(AnmAlphaMove::Ptn(Rect(PosX(), PosY()), src_pos[i], 255, time*i));
+		}
+		wid->SetPtn(); // パターン登録終了
+		anm = wid;
+		attr = Attribute(attr | ANM_PLAYSTART);
+		break;
+	default:
+		break;
+	}
+	return;
+};
+
+void GrpObj::SetZoomRotate(int new_zoom, int new_rotate) {
+	if (zoom == new_zoom && rotate == new_rotate) return;
+	if (new_zoom != -1) zoom = new_zoom;
+	if (new_rotate != -1) rotate = new_rotate;
+	if (zoom < 0) zoom = 256;
+	if (rotate < 0) rotate = 0;
+	else if (rotate > 360) rotate %= 360;
+
+	attr = Attribute(attr | UPDATE_PICTURE);
+	return;
+}
+/******************************************************************
+**
+**	class ScnGrp*
+*/
+/* Princess Bride: 背景画の一部のみ移動、の実装 */
+struct ScnGrpMove : public WidAnmTime {
+	Surface* dest;
+	Surface* src;
+	PicRoot& root;
+	Rect dest_r, from, to;
+	ScnGrpMove(Event::Container& container, PicBase* _pic, PicRoot& root, Surface* dest, const Rect& _dest_r, Surface* src, const Rect& from, const Rect& to, int total_time);
+	void Exec(int count);
+};
+ScnGrpMove::ScnGrpMove(Event::Container& container, PicBase* _pic, PicRoot& _root, Surface* _dest, const Rect& _dest_r, Surface* _src, const Rect& _from, const Rect& _to, int total_time) :
+	WidAnmTime(container, _pic, total_time),
+	dest(_dest), src(_src), root(_root),dest_r(_dest_r), from(_from), to(_to) {
+	int dx = to.lx - from.lx;
+	int dy = to.ty - from.ty;
+	if (dx < 0) dx = -dx;
+	if (dy < 0) dy = -dy;
+	if (dx < dy) dx = dy;
+	if (dx == 0) dx = 1;
+	SetAllCount(dx);
+}
+void ScnGrpMove::Exec(int count) {
+	Rect r(0,0,dest_r.width(),dest_r.height());
+	int dx = to.lx - from.lx;
+	int dy = to.ty - from.ty;
+	int x = dx*count/all_count + from.lx;
+	int y = dy*count/all_count + from.ty;
+	r.rmove(x, y);
+	root.BlitSurface(src, r, dest, dest_r);
+	iterator it;
+	for (it=pic.begin(); it!=pic.end(); it++)
+		(*it)->SetSurface(dest, 0, 0);
+}
+
+/* Princess Bride: カードがおちるアニメーション */
+
+struct ScnGrpAnmAtom {
+	string name;
+	int time;
+	ScnGrpAnmAtom(const char* _n, int _t) : name(_n), time(_t) {}
+};
+struct ScnGrpAnm : public WidAnmTime, vector<ScnGrpAnmAtom> {
+	GrpImpl& owner;
+	ScnGrpAnm(Event::Container& container, PicBase* _pic, GrpImpl& _owner) :
+		WidAnmTime(container, _pic, 0), owner(_owner) {
+	}
+	void CalcTotal(void);
+	void Exec(int count);
+};
+void ScnGrpAnm::CalcTotal(void) {
+	/* total time を計算 */
+	if (empty()) return;
+	int tm = 0;
+	vector<ScnGrpAnmAtom>::iterator it;
+	for (it=begin(); it != end(); it++) tm += it->time;
+	total_time = tm;
+	SetAllCount(tm);
+}
+void ScnGrpAnm::Exec(int count) {
+	int tm = 0; vector<ScnGrpAnmAtom>::iterator it;
+	for (it=begin(); it != end(); it++) {
+		tm += it->time;
+		if (count < tm) break;
+	}
+	if (it == end()) it--;
+	owner.LoadSurface(it->name.c_str(), 0);
+}
+
+
+/*****************************************************
+*
+*  GrpImpl(implementation) : 定義
+*
+*/
+
+#include"music2/music.h"
+
+GrpImpl::GrpImpl(Event::Container& _event, PicContainer& _parent, const Flags& f, set<int>& _cgm_data, class MuSys& _mu, AyuSysConfig& _config) :
+	event(_event),
+	flags(f), 
+	parent(_parent),
+	status(NORMAL),
+	skip_mode(SKIP_NO),
+	music(_mu),
+	cgm_data(_cgm_data),
+	grpobj(this),
+	bs_obj(this),
+	config(_config)
+{
+	int i;
+	for (i=0; i<MAXPDT; i++) {
+		ssurface[i] = 0;
+		dsurface[i] = 0;
+	}
+	screen = parent.create_leaf(Rect(0, 0, parent.Width(), parent.Height()), 0);
+	screen_front = parent.create_leaf(Rect(0, 0, parent.Width(), parent.Height()), 0);
+	surface = parent.Root().NewSurface(parent.Width(), parent.Height(), NO_MASK);
+	surface_update = parent.Root().NewSurface(parent.Width(), parent.Height(), NO_MASK);
+	DSurfaceFill(surface, Rect(*surface), 0, 0, 0);
+	DSurfaceFill(surface_update, Rect(*surface), 0, 0, 0);
+	screen->SetSurface(surface, 0, 0);
+	screen->show();
+	screen_front->hide();
+	screen_front->ZMove(screen);
+
+	LoadCgm(config);
+
+	anm1 = 0; anm2 = 0;
+}
+
+GrpImpl::~GrpImpl() {
+
+	map<int,GrpObj>::iterator it;
+	for (it=grpobj.begin(); it!=grpobj.end(); it++) {
+		PicBase* p = it->second.DeletePic();
+		delete p;
+	}
+
+	delete screen;
+	delete screen_front;
+	parent.Root().DeleteSurface(surface);
+	int i;
+	for (i=0; i<MAXPDT; i++) {
+		if (ssurface[i]) parent.Root().DeleteSurface(ssurface[i]);
+		if (dsurface[i]) parent.Root().DeleteSurface(dsurface[i]);
+	}
+}
+
+Surface* GrpImpl::Dsurface(int pdt) {
+	if (pdt == 0) return surface;
+	if (dsurface[pdt] == 0) { // とりあえず画面の大きさということにする
+		if (pdt == WORKPDT)
+			dsurface[pdt] = parent.Root().NewSurface(parent.Width(), parent.Height(), ALPHA_MASK);
+		else
+			dsurface[pdt] = parent.Root().NewSurface(parent.Width(), parent.Height(), NO_MASK);
+	}
+	if (ssurface[pdt]) { // ssurface が存在すれば、dsurface にコピーして返す
+		DSurfaceMove(ssurface[pdt], Rect(*ssurface[pdt]), dsurface[pdt], Rect(0,0));
+		parent.Root().DeleteSurface(ssurface[pdt]);
+		ssurface[pdt] = 0;
+	}
+	return dsurface[pdt];
+}
+#include<SDL.h>
+Surface* GrpImpl::Ssurface(int pdt) {
+	if (pdt == 0) return surface;
+	if (ssurface[pdt]) {
+		return ssurface[pdt];
+	}
+	return Dsurface(pdt);
+}
+
+void GrpImpl::LoadSurface(const char* str, int pdt) {
+	string s = str;
+	if (cgm_info.find(s) != cgm_info.end()) {
+		cgm_data.insert(cgm_info[s]);
+	}
+	Surface* bg = parent.Root().NewSurface(s.c_str());
+	if (bg == 0) {
+		s += ".g00";
+		bg = parent.Root().NewSurface(s.c_str());
+	}
+	if (bg) {
+		if (ssurface[pdt]) parent.Root().DeleteSurface(ssurface[pdt]);
+		ssurface[pdt] = bg;
+		if (pdt == 0) {
+			/* とりあえず Princess Bride のアニメーション効果専用 */
+			Rect r(*ssurface[0]);
+			Rect dr(*surface);
+			int x = (dr.width()-r.width())/2;
+			int y = (dr.height()-r.height())/2;
+			DSurfaceMove(ssurface[0], r, surface, Rect(x,y));
+			parent.Root().DeleteSurface(ssurface[0]);
+			ssurface[0] = 0;
+			screen->SetSurface(surface, 0, 0);
+		}
+	} else {
+		if (str[0] != 0)
+			fprintf(stderr,"Cannot find surface %d <- '%s'\n",pdt,str);
+	}
+	return;
+}
+void GrpImpl::InitSel(AyuSysConfig& config) {
+	int i; int args[16]; char key[1024];
+	for (i=0; i<999; i++) {
+		sprintf(key, "#SEL.%03d",i);
+		if (config.GetParam(key, 15, &args[0], &args[1],
+			&args[2], &args[3], &args[4], &args[5], &args[6], &args[7],
+			&args[8], &args[9], &args[10], &args[11], &args[12], &args[13],
+			&args[14])) {
+
+			sprintf(key, "#SELR.%03d", i);
+			if (config.GetParam(key, 16, &args[0], &args[1],
+				&args[2], &args[3], &args[4], &args[5], &args[6], &args[7],
+				&args[8], &args[9], &args[10], &args[11], &args[12], &args[13],
+				&args[14], &args[15]))  continue;
+		}
+		SEL& s = anmtype[i];
+		s.from = Rect(args[0], args[1], args[2]+1, args[3]+1);
+		s.to = Rect(args[4], args[5]);
+		s.time = args[6];
+		s.sel_no = args[7];
+		int j; for (j=0; j<8; j++) s.args[j] = args[8+j];
+	}
+	return;
+}
+void GrpImpl::SetSkipMode(SkipMode _mode) {
+	if ( (skip_mode & SKIP_IN_MENU) && (_mode & SKIP_IN_MENU) == 0) {
+		RefreshObj();
+	} else if ( (skip_mode & SKIP_IN_MENU) == 0 && (_mode & SKIP_IN_MENU) ) {
+	}
+	skip_mode = _mode;
+}
+void GrpImpl::SetObjChanged(int num) {
+	changed_obj.insert(num);
+}
+void GrpImpl::SetObjChangedGroup(int num) {
+	if (num % 1000 != 0) {
+		SetObjChanged(num);
+		return;
+	}
+	std::map<int, GrpObj>::iterator begin,end,it;
+	begin = grpobj.lower_bound(num);
+	end = grpobj.lower_bound(num+1000);
+	for (it=begin;it!=end;it++) {
+		changed_obj.insert(it->first);
+	}
+}
+void GrpImpl::RefreshObj(void) {
+	if (!deleted_pic.empty()) {
+		vector<PicBase*>::iterator it;
+		for (it=deleted_pic.begin(); it!=deleted_pic.end(); it++) {
+			if (*it) delete *it;
+		}
+		deleted_pic.clear();
+	}
+	if (!changed_obj.empty()) {
+		set<int>::iterator it;
+		for (it=changed_obj.begin(); it != changed_obj.end(); it++) {
+			if (grpobj.find(*it) == grpobj.end()) continue;
+			GrpObj& obj = grpobj[*it];
+			GrpObj& parent_obj = grpobj[ ((*it)/1000) * 1000];
+			if (obj.picture == 0) continue;
+			if (obj.alpha == 0 || (obj.attr & GrpObj::HIDDEN) || (parent_obj.attr & GrpObj::HIDDEN_GROUP) ) {
+				if (obj.attr & GrpObj::ANM_PLAYING) {
+					obj.attr = GrpObj::Attribute(obj.attr & ~(GrpObj::ANM_PLAYING));
+					if (obj.anm) obj.anm->Abort();
+				}
+				obj.picture->hide();
+			} else {
+				obj.Update();
+				obj.picture->show();
+			}
+		}
+		changed_obj.clear();
+	}
+	if (reserved_load_surface0.length() != 0) {
+		LoadSurface(reserved_load_surface0.c_str(), 0);
+		reserved_load_surface0 = "";
+	}
+	screen->ReBlit();
+}
+
+
+#include<SDL.h>
+void GrpImpl::StartAnm(int type) {
+	SEL sel;
+
+	if (anmtype.find(type) == anmtype.end()) {
+		if (anmtype.find(0) == anmtype.end()) {
+			sel.sel_no = 1;
+			sel.from = Rect(*surface);
+			sel.to = Rect(0,0);
+			sel.time = 0;
+		} else {
+			sel = anmtype[0];
+		}
+	} else {
+		sel = anmtype[type];
+	}
+	if (anm1) {
+		fprintf(stderr,"Warning: StartAnm() called before anm1 finished\n");
+		anm1->Abort();
+		delete anm1;
+		anm1 = 0;
+	}
+	map<int,GrpObj>::iterator it;
+	// 現在表示中のobjectを消去
+	deleted_pic.push_back(screen);
+	for (it=grpobj.begin(); it!=grpobj.end(); it++) {
+		if (! (it->second.attr & GrpObj::WIPEON)) { // 画像切り替え時に object 削除
+			deleted_pic.push_back(it->second.DeletePic());
+		} else {
+			GrpObj& new_obj = bs_obj[it->first];
+			if (new_obj.name.empty()) { // 新しい object が存在しなければ内容を引き継ぐ
+				new_obj = it->second;
+				it->second.DeletePic();
+			} else {
+				new_obj.attr = GrpObj::Attribute(new_obj.attr | GrpObj::WIPEON);
+				deleted_pic.push_back(it->second.DeletePic());
+			}
+		}
+	}
+	grpobj.clear(); // 全オブジェクト削除
+
+	// 全画像オブジェクトの前にscreen 移動
+	// 新しい screen_front を作成しておく
+	screen = screen_front;
+	screen->hide();
+	screen->SetSurface(surface_update, 0, 0);
+	parent.Root().BlitSurface(Dsurface(1), Rect(*surface_update), surface_update, Rect(0,0));
+
+	screen_front = parent.create_leaf(Rect(0, 0, parent.Width(), parent.Height()), 0);
+	screen_front->hide();
+	screen_front->ZMove(screen);
+	
+	// 新しい object へ更新、surface_update へ新しい object を表示
+	// (object 作成時は picture は hide されている)
+	for (it=bs_obj.begin(); it!=bs_obj.end(); it++) {
+		grpobj[it->first] = it->second;
+		it->second.DeletePic();
+		CreateObj(it->first);
+		GrpObj& g = grpobj[it->first];
+		GrpObj& parent_obj = grpobj[ (it->first/1000) * 1000];
+		if (g.picture) {
+			g.Update();
+			if (g.alpha == 0 || (g.attr & GrpObj::HIDDEN) || (parent_obj.attr & GrpObj::HIDDEN_GROUP) ) ;
+			else g.picture->SimpleBlit(surface_update);
+			g.picture->hide();
+		}
+	}
+	bs_obj.clear();
+	// 画像効果開始
+	switch(sel.sel_no) {
+		default:
+		case 0: case 50: // 0 と 50 の違いが良くわからない
+			if (skip_mode & SKIP_GRP_NOEFFEC)
+				anm1 = new WidAnmAlpha(event, screen, ALPHA_MAX, ALPHA_MAX, 0);
+			else if (skip_mode & SKIP_GRP_FAST)
+				anm1 = new WidAnmAlpha(event, screen, 0, ALPHA_MAX, sel.time/4);
+			else
+				anm1 = new WidAnmAlpha(event, screen, 0, ALPHA_MAX, sel.time);
+			break;
+	}
+	if (anm1) anm1->Play();
+	if (skip_mode & SKIP_GRP_NOEFFEC) AbortAnm();
+}
+void GrpImpl::StartShake(int total, const int* pattern) {
+	if (anm2) {
+		fprintf(stderr,"Warning: StartShake() called before another animation finished\n");
+		anm2->Abort();
+		delete anm2;
+		anm2 = 0;
+	}
+	if (skip_mode & SKIP_GRP_NOEFFEC) return;
+	AnmAlphaMove* new_anm = new AnmAlphaMove(event, &parent); // shake screen では元画面の座標を揺らす
+	int i; int tm = 0;
+	for (i=0; i<total; i+=3) {
+		int x = pattern[i];
+		int y = pattern[i+1];
+		new_anm->ptns.push_back(AnmAlphaMove::Ptn(Rect(x,y), Rect(0,0), 255, tm));
+		tm += pattern[i+2];
+	}
+	new_anm->ptns.push_back(AnmAlphaMove::Ptn(Rect(0,0), Rect(0,0), 255, tm));
+	new_anm->SetPtn(); // パターン登録終了
+	new_anm->Play();
+	anm2 = new_anm;
+}
+void GrpImpl::AbortAnm(void) {
+	if (anm1 == 0) return;
+	anm1->Abort();
+	delete anm1;
+	anm1 = 0;
+	/* 画像効果終了 */
+	/* 古い画面への画像効果があれば消去 */
+	if (anm2 && anm2->pic[0] != screen) {
+		anm2->Abort();
+		delete anm2;
+		anm2 = 0;
+	}
+	/* pdt1 -> pdt0 へコピー */
+	DSurfaceMove(dsurface[1], Rect(*dsurface[1]), surface, Rect(0,0));
+	screen->SetSurface(surface, 0, 0);
+	// 画像効果開始時に存在したobjectを消去
+	// 新しい object 表示
+	RefreshObj();
+	return;
+}
+void GrpImpl::LoadSurface(const char* str) {
+	if (anm1) AbortAnm(); // 前の描画が終わってなければ強制終了
+	LoadSurface(str, 1);
+	bg_name = str;
+}
+void GrpImpl::LoadSurface(void) {
+	if (anm1) AbortAnm(); // 前の描画が終わってなければ強制終了
+	LoadSurface(bg_name.c_str(), 1);
+}
+void GrpImpl::AddSurface(const char* str) {
+	if (anm1) AbortAnm(); // 前の描画が終わってなければ強制終了
+	LoadSurface(bg_name.c_str());
+
+	string s = str;
+	Surface* front = parent.Root().NewSurface(s.c_str());
+	if (front == 0) {
+		s += ".g00";
+		front = parent.Root().NewSurface(s.c_str());
+	}
+	if (front) {
+		parent.Root().BlitSurface(front, Rect(*front), Dsurface(1), Rect(0,0));
+		parent.Root().DeleteSurface(front);
+	} else {
+		fprintf(stderr,"Cannot find surface %s\n",str);
+	}
+}
+
+void GrpImpl::CreateObj(int index) {
+	std::map<int, GrpObj>::iterator cur = grpobj.find(index);
+	if (cur == grpobj.end()) return;
+	GrpObj& g = grpobj[index];
+	g.CreateSurface(&parent);
+	g.order = index;
+	if (g.picture == 0) return; // エラー:surface が存在しない
+	g.picture->hide();
+	SetObjChanged(index);
+	ZMoveObj(index);
+	return;
+}
+void GrpImpl::ZMoveObj(int index) {
+	std::map<int, GrpObj>::iterator cur = grpobj.find(index);
+	if (cur == grpobj.end()) return;
+	GrpObj& g = grpobj[index];
+	if (g.picture == 0) return;
+	// 自分より前に object があれば、その前に表示
+	// そうでなければ screen の前に表示
+	std::map<int, GrpObj>::iterator cur_backobj = grpobj.end();
+	std::map<int, GrpObj>::iterator it;
+	for (it = grpobj.begin(); it != grpobj.end(); it++) {
+		if (it == cur) continue;
+		if (it->second.picture == 0) continue;
+		if (it->second.order < g.order) {
+			if (cur_backobj == grpobj.end()) {
+				cur_backobj = it;
+			} else if (cur_backobj->second.order < it->second.order) {
+				cur_backobj = it;
+			}
+		}
+	}
+	if (cur_backobj == grpobj.end()) {
+		g.picture->ZMove(screen);
+	} else {
+		g.picture->ZMove(cur_backobj->second.picture);
+	}
+	return;
+}
+void GrpImpl::SwapObj(int index1, int index2) {
+	// デフォルト値から order が変更されていた場合のみ、order は保存される
+	// まずは両方のobjectをswap
+	if (grpobj.find(index1) == grpobj.end()) {
+		if (grpobj.find(index2) == grpobj.end()) return; // どちらの object も存在しない
+		grpobj[index1] = grpobj[index2];
+		if (grpobj[index1].order == index2)
+			grpobj[index1].order = index1;
+		grpobj[index2].DeletePic();
+		grpobj.erase(index2);
+		ZMoveObj(index1);
+		return;
+	} else if (grpobj.find(index2) == grpobj.end()) { // index2 が存在しない場合
+		grpobj[index2] = grpobj[index1];
+		if (grpobj[index2].order == index1)
+			grpobj[index2].order = index2;
+		grpobj[index1].DeletePic();
+		grpobj.erase(index1);
+		ZMoveObj(index2);
+		return;
+	} else {
+		GrpObj obj = grpobj[index1];
+		grpobj[index1] = grpobj[index2];
+		grpobj[index2].DeletePic();
+		if (grpobj[index1].order == index2)
+			grpobj[index1].order = index1;
+		ZMoveObj(index1);
+		grpobj[index2] = obj;
+		if (grpobj[index2].order == index1)
+			grpobj[index2].order = index2;
+		ZMoveObj(index2);
+		obj.DeletePic();
+	}
+}
+
+bool GrpImpl::Pressed(int x, int y, void* pointer) { // マウスクリックでキャンセル
+	GrpImpl* g = (GrpImpl*)pointer;
+	if (g->status == WAIT_MOVIE)
+		g->music.StopMovie();
+	if (g->status == WAIT_ANM)
+		g->AbortAnm();
+	if (g->status == WAIT_SHAKE && g->anm2 != 0) {
+		delete g->anm2;
+		g->anm2 = 0;
+	}
+	return false; // event deleted
+}
+
+/* mode.cgm の decode 用 */
+static unsigned char decode_char[256] = {
+	0x8b, 0xe5, 0x5d, 0xc3, 0xa1, 0xe0, 0x30, 0x44, 
+	0x00, 0x85, 0xc0, 0x74, 0x09, 0x5f, 0x5e, 0x33, 
+	0xc0, 0x5b, 0x8b, 0xe5, 0x5d, 0xc3, 0x8b, 0x45, 
+	0x0c, 0x85, 0xc0, 0x75, 0x14, 0x8b, 0x55, 0xec, 
+	0x83, 0xc2, 0x20, 0x52, 0x6a, 0x00, 0xe8, 0xf5, 
+	0x28, 0x01, 0x00, 0x83, 0xc4, 0x08, 0x89, 0x45, 
+	0x0c, 0x8b, 0x45, 0xe4, 0x6a, 0x00, 0x6a, 0x00, 
+	0x50, 0x53, 0xff, 0x15, 0x34, 0xb1, 0x43, 0x00, 
+	0x8b, 0x45, 0x10, 0x85, 0xc0, 0x74, 0x05, 0x8b, 
+	0x4d, 0xec, 0x89, 0x08, 0x8a, 0x45, 0xf0, 0x84, 
+	0xc0, 0x75, 0x78, 0xa1, 0xe0, 0x30, 0x44, 0x00, 
+	0x8b, 0x7d, 0xe8, 0x8b, 0x75, 0x0c, 0x85, 0xc0, 
+	0x75, 0x44, 0x8b, 0x1d, 0xd0, 0xb0, 0x43, 0x00, 
+	0x85, 0xff, 0x76, 0x37, 0x81, 0xff, 0x00, 0x00, 
+	0x04, 0x00, 0x6a, 0x00, 0x76, 0x43, 0x8b, 0x45, 
+	0xf8, 0x8d, 0x55, 0xfc, 0x52, 0x68, 0x00, 0x00, 
+	0x04, 0x00, 0x56, 0x50, 0xff, 0x15, 0x2c, 0xb1, 
+	0x43, 0x00, 0x6a, 0x05, 0xff, 0xd3, 0xa1, 0xe0, 
+	0x30, 0x44, 0x00, 0x81, 0xef, 0x00, 0x00, 0x04, 
+	0x00, 0x81, 0xc6, 0x00, 0x00, 0x04, 0x00, 0x85, 
+	0xc0, 0x74, 0xc5, 0x8b, 0x5d, 0xf8, 0x53, 0xe8, 
+	0xf4, 0xfb, 0xff, 0xff, 0x8b, 0x45, 0x0c, 0x83, 
+	0xc4, 0x04, 0x5f, 0x5e, 0x5b, 0x8b, 0xe5, 0x5d, 
+	0xc3, 0x8b, 0x55, 0xf8, 0x8d, 0x4d, 0xfc, 0x51, 
+	0x57, 0x56, 0x52, 0xff, 0x15, 0x2c, 0xb1, 0x43, 
+	0x00, 0xeb, 0xd8, 0x8b, 0x45, 0xe8, 0x83, 0xc0, 
+	0x20, 0x50, 0x6a, 0x00, 0xe8, 0x47, 0x28, 0x01, 
+	0x00, 0x8b, 0x7d, 0xe8, 0x89, 0x45, 0xf4, 0x8b, 
+	0xf0, 0xa1, 0xe0, 0x30, 0x44, 0x00, 0x83, 0xc4, 
+	0x08, 0x85, 0xc0, 0x75, 0x56, 0x8b, 0x1d, 0xd0, 
+	0xb0, 0x43, 0x00, 0x85, 0xff, 0x76, 0x49, 0x81, 
+	0xff, 0x00, 0x00, 0x04, 0x00, 0x6a, 0x00, 0x76
+};
+
+void GrpImpl::LoadCgm(AyuSysConfig& config) {
+	/* cgm ファイル読み込み */
+	const char* fname = config.GetParaStr("#CGTABLE_FILE");
+	if (fname == 0) return;
+	ARCINFO* info = file_searcher.Find(FILESEARCH::ALL, fname, "");
+	if (info == 0) return;
+	char* data = info->CopyRead();
+	int sz = info->Size();
+	delete info;
+
+	
+	if ( strncmp(data, "CGTABLE", 7) != 0) return;
+	int cgm_size = read_little_endian_int(data+0x10);
+
+	int i,j;
+	// xor 解除
+	for (i=0;i<sz-0x20; i++) {
+		data[i+0x20]^=decode_char[i&0xff];
+	}
+	// 展開
+	int dest_size = cgm_size * 36;
+	char* dest = new char[dest_size+1024];
+	char* src = data + 0x28;
+	char* dest_orig = dest;
+	ARCINFO::Extract2k(dest,src,dest+dest_size,data+sz);
+	dest = dest_orig;
+	for (i=0; i<cgm_size; i++) {
+		char* s = dest + i * 36;
+		int n = read_little_endian_int(dest + i * 36 + 32);
+		cgm_info[s] = n;
+	}
+	delete[] dest_orig;
+}
+
+/*****************************************************
+*
+*   GrpImpl :: Save, Load : セーブファイル処理
+*
+*/
+void GrpImpl::Save(std::string& str) {
+}
+void GrpImpl::Load(const char* str) {
+	status = NORMAL;
+	if (anm1) {
+		AbortAnm();
+	}
+	if (anm2) {
+		anm2->Abort();
+		delete anm2;
+		anm2 = 0;
+	}
+	map<int,GrpObj>::iterator it;
+	for (it=grpobj.begin(); it!=grpobj.end(); it++) {
+		PicBase* p = it->second.DeletePic();
+		delete p;
+	}
+	grpobj.clear();
+	
+	bg_name = "";
+	music.StopCDROM(100);
+}
+void GrpImpl::SaveSys(string& save) {
+	char buf[1024];
+	save = "\n[Graphics]\n";
+	save += "CGM_CG=";
+
+	set<int>::iterator it;
+	for (it=cgm_data.begin(); it != cgm_data.end(); it++) {
+		sprintf(buf,"%d,",*it);
+		save += buf;
+	}
+	save += "\n";
+}
+void GrpImpl::LoadSys(const char* save) {
+	cgm_data.clear();
+	save = strstr(save, "\n[Graphics]\n");
+
+	if (save) {
+		save += strlen("\n[Graphics]\n");
+		do {
+			if (save[0] == '[') break; // next section
+			if (strncmp(save, "CGM_CG=",7) == 0) {
+				save += 7;
+				while(isdigit(*save)) {
+					int n = atoi(save);
+					cgm_data.insert(n);
+					save = strchr(save, ',');
+					if (save) save++;
+				}
+			}
+			save = strchr(save, '\n');
+			if (save) save++;
+		} while (save);
+	}
+	return;
+}
+
+
+/*****************************************************
+*
+*   GrpImpl :: Wait , Exec : コマンド実行部
+*
+*/
+static vector<int> drawn_images;
+static int draw_n = 0;
+extern bool grpdump_req;
+bool GrpImpl::Wait(unsigned int current_time, Cmd& cmd) {
+	if (grpdump_req) {
+		grpdump_req = 0;
+		std::map<int,GrpObj>::iterator it;
+		fprintf(stderr,"front %08x(%d) / %08x(%d)\n",screen,screen->IsHidden(),screen_front,screen_front->IsHidden());
+		for (it=grpobj.begin(); it != grpobj.end(); it++) {
+			GrpObj& obj = it->second;
+			GrpObj& parent_obj = grpobj[ ((it->first)/1000) * 1000];
+			if (obj.picture) {
+				if (!obj.name.empty()) {
+					fprintf(stderr,"obj %06d(%08x): name %10s  pos %d,%d alpha %d (%d/%d/%d)\n",
+					it->first,obj.picture,obj.name.c_str(),
+					obj.PosX(),obj.PosY(),obj.alpha,obj.attr&GrpObj::HIDDEN ? 1 : 0,parent_obj.attr&GrpObj::HIDDEN_GROUP ? 1 : 0,obj.picture->IsHidden());
+				} else if (!obj.print_moji.empty()) {
+					fprintf(stderr,"obj %06d(%08x): name %10s  pos %d,%d alpha %d (%d/%d/%d)\n",
+					it->first,obj.picture,obj.print_moji.c_str(),
+					obj.PosX(),obj.PosY(),obj.alpha,obj.attr&GrpObj::HIDDEN ? 1 : 0,parent_obj.attr&GrpObj::HIDDEN_GROUP ? 1 : 0,obj.picture->IsHidden());
+				} else {
+					fprintf(stderr,"obj %06d(%08x): name %10s  pos %d,%d alpha %d (%d/%d/%d)\n",
+					it->first,obj.picture,"<EMPTY>",
+					obj.PosX(),obj.PosY(),obj.alpha,obj.attr&GrpObj::HIDDEN ? 1 : 0,parent_obj.attr&GrpObj::HIDDEN_GROUP ? 1 : 0,obj.picture->IsHidden());
+				}
+			}
+		}
+		std::list<PicBase*>::iterator it2;
+		for (it2=parent.children.begin(); it2!=parent.children.end();it2++) {
+			fprintf(stderr,"%08x(%d)\n",*it2,(*it2)->IsHidden());
+		}
+		RefreshObj();
+
+	}
+#if 0
+	if (event.presscount(MOUSE_UP)) {
+        	std::list<PicBase*>::iterator lit;
+		draw_n++; int i=0;
+		for (lit=parent.children.end(); lit!=parent.children.begin(); ) {
+			lit--;
+			(*lit)->hide();
+			i++;
+			if (i >= draw_n) break;
+		}
+		if (drawn_images.empty()) {
+			map<int, GrpObj>::iterator it;
+			for (it=grpobj.begin(); it!=grpobj.end(); it++) {
+				if (it->second.picture) {
+					drawn_images.push_back(it->first);
+					PicBase* p = it->second.DeletePic();
+					delete p;
+				}
+			}
+		} else {
+			vector<int>::iterator it;
+			for (it=drawn_images.begin(); it!=drawn_images.end(); it++) {
+				CreateObj(*it);
+			}
+			drawn_images.clear();
+		}
+	}
+#endif
+	if (status == WAIT_ANM) {
+		if (anm1) {
+			if (!anm1->IsEnd()) return true;
+			AbortAnm();
+		}
+	} else if (status == WAIT_SHAKE) {
+		if (anm2) {
+			if (!anm2->IsEnd()) return true;
+			delete anm2;
+			anm2 = 0;
+		}
+		status = NORMAL;
+	} else if (status == WAIT_SE) {
+		if (music.IsStopSE()) status = NORMAL;
+		return true;
+	} else if (status == WAIT_MOVIE) {
+		if (music.IsStopMovie()) {
+			music.StopMovie();
+			status = NORMAL;
+			screen->ReBlit();
+		}
+		return true;
+	}
+	if (anm2) {
+		if (anm2->IsEnd()) {
+			delete anm2;
+			anm2 = 0;
+		}
+	}
+	return false;
+}
+
+void GrpImpl::DeleteObjPic(int num) { // object の surface のみ削除
+	if (grpobj.find(num) == grpobj.end()) return;
+	deleted_pic.push_back(grpobj[num].DeletePic());
+}
+void GrpImpl::DeleteObj(int num) {
+	if (grpobj.find(num) == grpobj.end()) return;
+	deleted_pic.push_back(grpobj[num].DeletePic());
+	grpobj.erase(num);
+}
+void GrpImpl::DeleteObjRange(int num_first, int num_end) {
+	std::map<int, GrpObj>::iterator begin,end,it;
+	begin = grpobj.lower_bound(num_first);
+	end = grpobj.lower_bound(num_end);
+	for (it=begin;it!=end;it++) {
+		deleted_pic.push_back(it->second.DeletePic());
+	}
+	grpobj.erase(begin, end);
+}
+void GrpImpl::Exec(Cmd& cmd) {
+	if (cmd.cmd_type == CMD_TEXTEND) {
+		music.StopKoe(500); // テキスト終了で声を止める
+		cmd.clear();
+		return;
+	}
+	if (cmd.cmd_type == CMD_WAITFRAMEUPDATE) {
+		// wait する場合は RefreshObj() しておく
+		RefreshObj();
+	}
+	if (cmd.cmd_type != CMD_OTHER) return;
+	if (cmd.cmd1 == 1 && cmd.cmd2 == 0x1e && cmd.cmd3 == 0) {
+		cmd.cmd_type = CMD_SAVECMDGRP_START; // grp stack clear
+	}
+	if (cmd.cmd1 == 1 && cmd.cmd2 == 0x21) {
+		if (cmd.cmd3 == 0x46) {
+			const char* name = cmd.Str(cmd.args[0]);
+			int pdt = cmd.args[1].value;
+			eprintf("load surface %s pdt %d\n",name, pdt);
+			if (pdt == 0)
+				reserved_load_surface0 = name; // 画像読み込みは 01-1f:0000 まで待つ
+			else if (pdt == 1)
+				LoadSurface(name); // 背景絵読み込み?
+			else
+				LoadSurface(name, pdt);
+			cmd.cmd_type = CMD_SAVECMDGRP;
+		} else if (cmd.cmd3 == 0x49) {
+			const char* name = cmd.Str(cmd.args[0]);
+			int sel = cmd.args[1].value;
+			eprintf("set background %s sel %d\n",name, sel);
+			if (name[0] == '?') {
+				LoadSurface();
+			} else {
+				LoadSurface(name);
+			}
+			StartAnm(sel);
+			status = WAIT_ANM;
+			event.RegisterGlobalPressFunc(&Pressed, (void*)this);
+			if (name[0] == '?')
+				cmd.cmd_type = CMD_SAVECMDGRP_ONCE;
+			else
+				cmd.cmd_type = CMD_SAVECMDGRP_START;
+		} else if (cmd.cmd3 == 0x4b) {
+			int pos = cmd.args[0].value;
+			const char* name = cmd.Str(cmd.args[1]);
+			int sel = cmd.args[2].value;
+			eprintf("set foreground %s sel %d pos %d\n",name, sel, pos);
+			AddSurface(name);
+			StartAnm(sel);
+			event.RegisterGlobalPressFunc(&Pressed, (void*)this);
+			status = WAIT_ANM;
+			cmd.cmd_type = CMD_SAVECMDGRP_ONCE;
+		} else if (cmd.cmd3 == 0x4c) {
+			/* 0x46 との違いがわからない */
+			/* とりあえず bg として登録しないでみる */
+			/* 735 / 19438 : unsupported command; 0x23 - cmd 01-21:004c:00[ 2] 
+        		** "?",0
+			*/
+			/* arg1 = "?" arg2 = 0 */
+			const char* name = cmd.Str(cmd.args[0]);
+			int sel = cmd.args[1].value;
+			if (name[0] == '?') {
+				LoadSurface();
+			} else {
+				LoadSurface(name, 1);
+			}
+			StartAnm(sel);
+			status = WAIT_ANM;
+			event.RegisterGlobalPressFunc(&Pressed, (void*)this);
+			if (name[0] == '?')
+				cmd.cmd_type = CMD_SAVECMDGRP_ONCE;
+			else
+				cmd.cmd_type = CMD_SAVECMDGRP_START;
+		} else if (cmd.cmd3 == 0x20) {
+			// shake screen
+			char key[1024];
+			sprintf(key, "#SHAKE.%03d", cmd.args[0].value);
+			if (config.SearchParam(key) != 2) {
+				fprintf(stderr,"Cannot find shake pattern %d; use default pattern\n",cmd.args[0].value);
+				strcpy(key, "#SHAKE.000"); // default key
+			}
+			int num; const int* pattern;
+			pattern = config.GetParamArray(key, num);
+			if (pattern) {
+				StartShake(num, pattern);
+				status = WAIT_SHAKE;
+			}
+			cmd.clear();
+		} else if (cmd.cmd3 == 0x64 && cmd.cmd4 == 2) { // copy (KANOGI)
+			int sx = cmd.args[0].value;
+			int sy = cmd.args[1].value;
+			int w = cmd.args[2].value - sx;
+			int h = cmd.args[3].value - sy;
+			Rect rect(sx, sy, sx+w, sy+h);
+			int src = cmd.args[4].value;
+			int dx = cmd.args[5].value;
+			int dy = cmd.args[6].value;
+			int dest = cmd.args[7].value;
+			unsigned char alpha;
+			eprintf("copy surface %d:(%d,%d) size(%d,%d) -> %d:(%d,%d)\n",src,sx,sy,w,h,dest,dx,dy);
+			printf("copy surface %d:(%d,%d) size(%d,%d) -> %d:(%d,%d)\n",src,sx,sy,w,h,dest,dx,dy);
+			if (src == dest) {
+				DSurfaceMove(Ssurface(src), rect, Dsurface(WORKPDT), rect);
+				src = WORKPDT;
+			}
+			parent.Root().BlitSurface(Ssurface(src), rect, Dsurface(dest), Rect(dx,dy));
+			if (dest == 0) screen->ReBlit(Rect(dx,dy,dx+w,dy+h));
+			cmd.clear();
+		} else if (cmd.cmd3 == 0x4b1 && cmd.cmd4 == 2) {
+			int x = cmd.args[0].value;
+			int y = cmd.args[1].value;
+			int w = cmd.args[2].value;
+			int h = cmd.args[3].value;
+			Rect rect(x,y,x+w,y+w);
+			int pdt = cmd.args[4].value;
+			int r = cmd.args[5].value;
+			int g = cmd.args[6].value;
+			int b = cmd.args[7].value;
+			eprintf("clear %d:(%d,%d) size (%d,%d) r %d g %d b %d\n",pdt,x,y,w,h,r,g,b);
+			DSurfaceFill(Dsurface(pdt), rect, r, g, b, 0xff);
+			// if (pdt == 0) screen->ReBlit(rect);
+			cmd.cmd_type = CMD_SAVECMDGRP;
+		} else if (cmd.cmd3 == 0x4b1 && cmd.cmd4 == 3) { // alpha つきfill
+			int x = cmd.args[0].value;
+			int y = cmd.args[1].value;
+			int w = cmd.args[2].value;
+			int h = cmd.args[3].value;
+			Rect rect(x,y,x+w,y+h);
+			int pdt = cmd.args[4].value;
+			int r = cmd.args[5].value;
+			int g = cmd.args[6].value;
+			int b = cmd.args[7].value;
+			int a = cmd.args[8].value;
+			eprintf("alpha-clear %d:(%d,%d) size (%d,%d) r %d g %d b %d a %d\n",pdt,x,y,w,h,r,g,b,a);
+			if (a <= 0) ;
+			else if (a >= 255) DSurfaceFill(Dsurface(pdt), rect, r, g, b);
+			else {
+				DSurfaceFill(Dsurface(WORKPDT), rect, r, g, b, a);
+				parent.Root().BlitSurface(Dsurface(WORKPDT), rect, Dsurface(pdt), rect);
+			}
+			// if (pdt == 0) screen->ReBlit(rect);
+			cmd.clear();
+		} else if (cmd.cmd3 == 0x44c && cmd.cmd4 == 2) {
+			int sx = cmd.args[0].value;
+			int sy = cmd.args[1].value;
+			int w = cmd.args[2].value;
+			int h = cmd.args[3].value;
+			int src = cmd.args[4].value;
+			int dx = cmd.args[5].value;
+			int dy = cmd.args[6].value;
+			int dest = cmd.args[7].value;
+			eprintf("copy surface %d:(%d,%d) size(%d,%d) -> %d:(%d,%d)\n",src,sx,sy,w,h,dest,dx,dy);
+			parent.Root().BlitSurface(Ssurface(src), Rect(sx,sy,sx+w,sy+h), Dsurface(dest), Rect(dx,dy));
+			//DSurfaceMove(Ssurface(src), Rect(sx,sy,sx+w,sy+h), Dsurface(dest), Rect(dx,dy));
+			// if (dest == 0) screen->ReBlit(Rect(dx,dy,dx+w,dy+h));
+			cmd.cmd_type = CMD_SAVECMDGRP;
+		} else if (cmd.cmd3 == 0x44c && cmd.cmd4 == 3) { // alpha つきcopy
+			int sx = cmd.args[0].value;
+			int sy = cmd.args[1].value;
+			int w = cmd.args[2].value;
+			int h = cmd.args[3].value;
+			Rect rect(sx, sy, sx+w, sy+h);
+			int src = cmd.args[4].value;
+			int dx = cmd.args[5].value;
+			int dy = cmd.args[6].value;
+			int dest = cmd.args[7].value;
+			unsigned char alpha;
+			if (cmd.args[8].value < 0) alpha = 0;
+			else if (cmd.args[8].value > 255) alpha = 255;
+			else alpha = cmd.args[8].value;
+			eprintf("copy surface %d:(%d,%d) size(%d,%d) -> %d:(%d,%d)\n",src,sx,sy,w,h,dest,dx,dy);
+			if (src == dest) {
+				DSurfaceMove(Ssurface(src), rect, Dsurface(WORKPDT), rect);
+				src = WORKPDT;
+			}
+			if (alpha != 0)
+				parent.Root().BlitSurface(Ssurface(src), rect, &alpha, Rect(0,0,1,1), Dsurface(dest), Rect(dx,dy), 0);
+			// if (dest == 0) screen->ReBlit(Rect(dx,dy,dx+w,dy+h));
+			cmd.clear();
+		} else if (cmd.cmd3 == 0x640 && cmd.cmd4 == 3) { // saturate mode で alpha 付き copy
+			int sx = cmd.args[0].value;
+			int sy = cmd.args[1].value;
+			int w = cmd.args[2].value;
+			int h = cmd.args[3].value;
+			Rect rect(sx, sy, sx+w, sy+h);
+			int src = cmd.args[4].value;
+			int dx = cmd.args[5].value;
+			int dy = cmd.args[6].value;
+			int dest = cmd.args[7].value;
+			unsigned char alpha;
+			if (cmd.args[8].value < 0) alpha = 0;
+			else if (cmd.args[8].value > 255) alpha = 255;
+			else alpha = cmd.args[8].value;
+			eprintf("copy surface w/ saturate %d:(%d,%d) size(%d,%d) -> %d:(%d,%d)\n",src,sx,sy,w,h,dest,dx,dy);
+			if (src == dest) {
+				DSurfaceMove(Ssurface(src), rect, Dsurface(WORKPDT), rect);
+				src = WORKPDT;
+			}
+			if (alpha != 0) {
+				// saturate mode : screen (picture) を一時的に作成
+				PicBase* screen_tmp = parent.create_leaf(Rect(0, 0, parent.Width(), parent.Height()), 0);
+				screen_tmp->SetSurface(Ssurface(src), 0, 0, PicBase::BLIT_SATURATE);
+				screen_tmp->SetSurfaceRect(rect);
+				screen_tmp->Move(dx, dy);
+				screen_tmp->SetSurfaceAlpha(&alpha, Rect(0,0,1,1));
+				screen_tmp->SimpleBlit(Dsurface(dest));
+				delete screen_tmp;
+			}
+			cmd.clear();
+		} else if (cmd.cmd3 == 0x196 && cmd.cmd4 == 0) {
+			Rect r_from(cmd.args[0].value, cmd.args[1].value);
+			Rect r_to(cmd.args[2].value, cmd.args[3].value);
+			int src_pdt = cmd.args[4].value;
+			Rect r(cmd.args[5].value,cmd.args[6].value,cmd.args[7].value+1,cmd.args[8].value+1);
+			int tm = cmd.args[9].value;
+			fprintf(stderr,"??? cmd time %d\n",tm);
+			// anm1 = new ScnGrpMove(event, screen, parent.Root(), surface, r, Ssurface(2), r_from, r_to, tm);
+			// status = WAIT_ANM;
+		}
+	}
+	if (cmd.cmd1 == 1 && cmd.cmd2 == 0x22) {
+		if (cmd.cmd3 == 0x0c30 && cmd.cmd4 == 0) { // スクロールする画像効果(Princess Bride)
+			if (anm2) {
+				anm2->Abort();
+				delete anm2;
+			}
+			PicBase* pic; Surface* s;
+			Rect r(cmd.args[1].value, cmd.args[2].value, cmd.args[3].value+1, cmd.args[4].value+1);
+			const char* name = cmd.Str(cmd.args[5]);
+			Rect sr_start(cmd.args[6].value,cmd.args[7].value);
+			Rect sr_end(cmd.args[8].value,cmd.args[9].value);
+			int tm = cmd.args[10].value;
+			LoadSurface(name, 2); /* PDT2 に読み込み、と決め打ち */
+			
+			anm2 = new ScnGrpMove(event, screen, parent.Root(), Dsurface(1), r, Ssurface(2), sr_start, sr_end, tm);
+			cmd.cmd_type = CMD_SAVECMDGRP;
+		}
+		if ( (cmd.cmd3 == 0xc1c && cmd.cmd4 == 0) || (cmd.cmd3 == 0x835 && cmd.cmd4 == 0) ) {
+			// カードが落ちるアニメーション
+			int i;
+			ScnGrpAnm* new_anm = new ScnGrpAnm(event, screen, *this);
+			if (cmd.cmd3 == 0x835) {
+				AbortAnm();
+				anm1 = new_anm;
+				status = WAIT_ANM;
+				event.RegisterGlobalPressFunc(&Pressed, (void*)this);
+			} else {
+ 				anm2 = new_anm;
+			}
+			for (i=0; i<cmd.argc; i++) {
+				const char* name = cmd.Str(cmd.args[i*3+1]);
+				int tm = cmd.args[i*3+2].value;
+				new_anm->push_back(ScnGrpAnmAtom(name,tm));
+			}
+			new_anm->CalcTotal();
+			cmd.clear();
+		}
+	}
+	if (cmd.cmd1 == 1 && cmd.cmd2 == 4) {
+		if (cmd.cmd3 == 0xd8 || cmd.cmd3 == 0xd3 || cmd.cmd3 == 0xd2 || cmd.cmd3 == 0xd7) {
+			cmd.clear(); // いつも 0xd8 / 0xd7 と組で出てくる
+		}
+		if (cmd.cmd3 == 0x5e0) { // 画像既視フラグを得る
+			string s = cmd.Str(cmd.args[0]);
+			if (cgm_info.find(s) == cgm_info.end()) {
+				fprintf(stderr,"cmd 01-04:05e0 : cannot find cgm-info of '%s'\n",s.c_str());
+				return;
+			}
+			int n = cgm_info[s];
+			if (cgm_data.find(n) == cgm_data.end()) cmd.SetSysvar(0);
+			else cmd.SetSysvar(1);
+		}
+	}
+#if 1
+	/* object 操作 */
+	if ( (cmd.cmd1 == 1 || cmd.cmd1 == 2)  && (cmd.cmd2 == 0x3d || cmd.cmd2 == 0x3e) && (cmd.cmd3 == 0x0a || cmd.cmd3 == 0x0b || cmd.cmd3 == 0x0e)) { // clear object
+		if (cmd.cmd3 == 0x0a || cmd.cmd3 == 0x0b) {
+			if (cmd.cmd1 == 2 && cmd.args.size() == 2) {
+				int num = cmd.args[0].value*1000 + cmd.args[1].value + 500;
+				DeleteObj(num);
+			} else if (cmd.args.size() == 1) { // group ごと消去
+				int num_first = cmd.args[0].value * 1000;
+				int num_end = num_first+1000;
+				DeleteObjRange(num_first, num_end);
+			}
+		} else { // 0x0e
+			if (cmd.cmd1 == 1 && cmd.args.size() == 2) {
+				SwapObj(cmd.args[0].value * 1000, cmd.args[1].value * 1000);
+			} else if (cmd.cmd1 == 2 && cmd.args.size() == 3) {
+				int v1 = cmd.args[0].value*1000 + cmd.args[1].value + 500;
+				int v2 = cmd.args[0].value*1000 + cmd.args[2].value + 500;
+				SwapObj(v1, v2);
+			}
+		}
+		cmd.clear();
+	}
+	if (cmd.cmd1 == 1 && cmd.cmd2 == 0x3c && cmd.cmd3 == 0x01) { // ??? : CLANNAD
+		cmd.clear();
+	}
+	if (cmd.cmd1 == 1 && cmd.cmd2 == 0x3c && cmd.cmd3 == 0) { // ??? : KANOGI : 画像オブジェクトの削除?
+		DeleteObjPic(cmd.args[0].value * 1000); // 旧ファイル名のsurfaceを削除
+		GrpObj& g = grpobj[cmd.args[0].value * 1000];
+		g.attr = GrpObj::Attribute(g.attr | GrpObj::HIDDEN);
+		cmd.clear();
+	}
+	if ( (cmd.cmd1 == 1 || cmd.cmd1 == 2) && (cmd.cmd2 == 0x47 || cmd.cmd2 == 0x48|| cmd.cmd2 == 0x49 || cmd.cmd2 == 0x51 || cmd.cmd2 == 0x52 || cmd.cmd2 == 0x54)) {
+		if (cmd.cmd1 == 1) {
+			if (cmd.args.size() >= 1) cmd.args[0].value *= 1000; // とりあえず 1000倍しておく
+		} else { // cmd.cmd2 == 2
+			// オブジェクト番号を指定するコマンド引数が一つ増えているのを消去
+                        vector<VarInfo> args = cmd.args;
+			cmd.args.clear();
+			if (args.size() >= 2) {
+				cmd.args.push_back(args[0].value*1000 + args[1].value + 500);
+				cmd.args.insert(cmd.args.end(), args.begin()+2, args.end());
+			}
+		}
+		if (cmd.cmd2 == 0x47) {
+			/**************:
+				0x47 : オブジェクト内容の設定
+					0x3e8: G00 ファイル
+					0x3eb: GAN ファイル
+					0x44c: 矩形領域
+					0x4b0: 文字列
+					0x514: 天候効果
+					0x578: 数字の画像表示
+			*/
+			int base_argc = 0;
+			DeleteObjPic(cmd.args[0].value); // 旧ファイル名のsurfaceを削除
+			GrpObj& g = grpobj[cmd.args[0].value];
+			if (cmd.cmd3 == 0x3e8) { /* ファイル名設定 */
+				g.gtype = GrpObj::FILE;
+				string name = cmd.Str(cmd.args[1]);
+				if (name.find('?') != -1) {
+					name.erase(name.find('?')); // '?' 以降の意味がわからない
+				}
+				g.name = name;
+			} else if (cmd.cmd3 == 0x3eb) { /* ファイル名設定(GAN含む) */
+				g.gtype = GrpObj::GAN;
+				if (cmd.Str(cmd.args[1]) == string("???"))
+					g.name = cmd.Str(cmd.args[2]);
+				else
+					g.name = cmd.Str(cmd.args[1]);
+				g.gan_name = cmd.Str(cmd.args[2]);
+			} else if (cmd.cmd3 == 0x4b0) { // 画像を文字列として指定
+				g.gtype = GrpObj::MOJI;
+				g.print_moji = cmd.Str(cmd.args[1]);
+				g.attr = GrpObj::Attribute(g.attr & (~GrpObj::HIDDEN)); // 常に表示がデフォルト?
+				cmd.clear();
+			} else if (cmd.cmd3 == 0x578) { // 数値を画像として表示
+				g.gtype = GrpObj::DIGIT;
+				g.name = cmd.Str(cmd.args[1]);
+			}
+			CreateObj(cmd.args[0].value);
+			if (cmd.cmd3 == 0x3e8 || cmd.cmd3 == 0x3eb || cmd.cmd3 == 0x4b0 || cmd.cmd3 == 0x578) {
+				// FILE, GAN, MOJI, DIGIT ならば座標等の設定を行う
+				if (cmd.cmd4 >= 1+base_argc) {
+					if (cmd.args[2+base_argc].value == 0) {
+						if (cmd.cmd1 == 1)
+							g.attr = GrpObj::Attribute(g.attr | GrpObj::HIDDEN | GrpObj::HIDDEN_GROUP);
+						else
+							g.attr = GrpObj::Attribute(g.attr | GrpObj::HIDDEN);
+					} else {
+						if (cmd.cmd1 == 1)
+							g.attr = GrpObj::Attribute(g.attr & (~(GrpObj::HIDDEN | GrpObj::HIDDEN_GROUP)));
+						else
+							g.attr = GrpObj::Attribute(g.attr & (~GrpObj::HIDDEN));
+					}
+					if (cmd.cmd1 == 1)
+						SetObjChangedGroup(cmd.args[0].value);
+				}
+				if (cmd.cmd4 >= 2+base_argc) { // 座標等も設定
+					g.SetPos(0,cmd.args[3+base_argc].value, cmd.args[4+base_argc].value);
+				}
+				if ( (cmd.cmd3 == 0x3e8 || cmd.cmd3 == 0x3eb) && cmd.cmd4 >= 4+base_argc) { // pattern 番号も設定
+					g.SetSurfaceNum(cmd.args[5+base_argc].value);
+					base_argc++; // 0x3e8 (FILE) / 0x3eb (GAN) の場合のみこのオプションは存在する
+				}
+				cmd.clear();
+			} else {
+				fprintf(stderr,"CreateObj : cmd.cmd3 = %04x ; not supported!\n",cmd.cmd3);
+			}
+		} else if (cmd.cmd2 == 0x48) {
+			// 画面切り替え後の object (back screen object) 設定
+			if (cmd.cmd3 == 0x3e8) {
+				// cmd.cmd4 == 0 : args = 2, CLANNAD : cg mode
+				// cmd.cmd4 == 1 : args = 3, CLANNAD :  春原回想?のところで画面が黒くなってしまうので、とりあえず。
+				// cmd.cmd4 == 2 : args = 5, KANOGI : Fore Graphics
+				// cmd.cmd4 == 3 : args = 6, KANOGI : CG mode
+				GrpObj& g = bs_obj[cmd.args[0].value];
+				string name = cmd.Str(cmd.args[1]);
+				if (name.find('?') != -1) {
+					name.erase(name.find('?')); // '?' 以降の意味がわからない
+				}
+				g.gtype = GrpObj::FILE;
+				g.name = name;
+				if (cmd.cmd4 >= 1 && cmd.args[2].value == 0)
+					g.attr =  GrpObj::Attribute(g.attr | GrpObj::HIDDEN);
+				else
+					g.attr =  GrpObj::Attribute(g.attr & ~(GrpObj::HIDDEN));
+				if (cmd.cmd4 >= 2)
+					g.SetPos(0,cmd.args[3].value, cmd.args[4].value);
+				if (cmd.cmd4 >= 3)
+					g.SetSurfaceNum(cmd.args[5].value);
+				if (cmd.cmd4 <= 3)
+					cmd.cmd_type = CMD_SAVECMDGRP;
+			}
+		} else if (cmd.cmd2 == 0x49) {
+			if (cmd.cmd3 == 0) {  // アニメーションを強制終了
+				GrpObj& g = grpobj[cmd.args[0].value];
+				if (g.anm == 0 || g.anm->IsEnd()) ;
+				else g.anm->Abort();
+			} else if (cmd.cmd3 == 3) { // アニメーション中か?
+				GrpObj& g = grpobj[cmd.args[0].value];
+				if (g.anm == 0 || g.anm->IsEnd()) {
+					cmd.SetSysvar(0);
+				} else {
+					cmd.SetSysvar(1);
+				}
+			} else if (cmd.cmd3 == 1000) {
+				// アニメーションを途中で停止した状態にする
+				GrpObj& g = grpobj[cmd.args[0].value];
+				if (g.anm == 0 || g.anm->IsEnd()) {
+					// fprintf(stderr,"AnimPause : no animation in %d (%d)\n",cmd.args[0].value, cmd.args[1].value);
+					g.SetSurfaceNum(cmd.args[1].value);
+				} else {
+					g.anm->Abort();
+					g.SetSurfaceNum(cmd.args[1].value);
+				}
+				SetObjChanged(cmd.args[0].value);
+				cmd.clear();
+			} else if (cmd.cmd3 == 0x7d3) { // surface を増加させる画像効果
+				GrpObj& g = grpobj[cmd.args[0].value];
+				g.CreateGanSpecial(event, 0, cmd.args[1].value);
+				// g.attr = GrpObj::Attribute(g.attr & (~GrpObj::HIDDEN));
+				SetObjChanged(cmd.args[0].value);
+				cmd.clear();
+			} else if (cmd.cmd3 == 0xbbd || cmd.cmd3 == 0xbbb || cmd.cmd3 == 0xbb9) { // アニメーション開始
+				GrpObj& g = grpobj[cmd.args[0].value];
+				g.CreateGan(event, cmd.args[1].value);
+				// g.attr = GrpObj::Attribute(g.attr & (~GrpObj::HIDDEN));
+				SetObjChanged(cmd.args[0].value);
+				cmd.clear();
+			}
+		} else if (cmd.cmd2 == 0x51 || cmd.cmd2 == 0x52) {
+			GrpObj& g = (cmd.cmd2 == 0x51) ?
+				grpobj[cmd.args[0].value] :
+				bs_obj[cmd.args[0].value];
+			if (cmd.cmd3 == 0x3e8) { /* 座標設定 */
+				g.SetPos(0,cmd.args[1].value, cmd.args[2].value);
+				cmd.clear();
+			} else if (cmd.cmd3 == 0x3e9 || cmd.cmd3 == 0x3ea) { /* x / y 座標のみ設定 */
+				int x0, y0;
+				g.GetPos(0, x0, y0);
+				if (cmd.cmd3 == 0x3e9)
+					g.SetPos(0,cmd.args[1].value, y0);
+				else
+					g.SetPos(0,x0, cmd.args[1].value);
+				cmd.clear();
+			} else if (cmd.cmd3 == 0x3eb) { /* alpha */
+				g.SetAlpha(cmd.args[1].value);
+				cmd.clear();
+			} else if (cmd.cmd3 == 0x3ec) { /* visible flag */
+				if (cmd.cmd1 == 1) {
+					if (cmd.args[1].value) g.attr = GrpObj::Attribute(g.attr & (~(GrpObj::HIDDEN | GrpObj::HIDDEN_GROUP)));
+					else g.attr = GrpObj::Attribute(g.attr | GrpObj::HIDDEN | GrpObj::HIDDEN_GROUP);
+				} else {
+					if (cmd.args[1].value) g.attr = GrpObj::Attribute(g.attr & (~GrpObj::HIDDEN));
+					else g.attr = GrpObj::Attribute(g.attr | GrpObj::HIDDEN);
+				}
+				g.attr = GrpObj::Attribute(g.attr | GrpObj::UPDATE_VISIBLE);
+ 				// グループ単位で次の RefreshObj で表示・消去
+				if (cmd.cmd2 == 0x51 && cmd.cmd1 == 1)
+					SetObjChangedGroup(cmd.args[0].value);
+				cmd.clear();
+			} else if (cmd.cmd3 == 0x3ee || cmd.cmd3 == 0x7d6) { /* 座標設定その2? */
+					/* 0x7d6 : 画像側の基準座標を args[4,5] に入れているのかもしれない */
+				int index = cmd.args[1].value;
+				int x = cmd.args[2].value;
+				int y = cmd.args[3].value;
+				g.SetPos(index+1, x, y);
+				cmd.clear();
+			} else if (cmd.cmd3 == 0x3f8) { // 画像を文字列として設定:色の設定
+				g.print_r = cmd.args[1].value;
+				g.print_g = cmd.args[2].value;
+				g.print_b = cmd.args[3].value;
+				g.SetUpdate();
+				// grpobj[cmd.args[0].value].print_a = cmd.args[4].value;
+				/* args:229,18,minus-1,0,99,255,-1 */
+				/* args:102,26,minus-1,0,99,0,255 */
+				cmd.clear();
+			} else if (cmd.cmd3 == 0x3fd) { // centering mode などを設定?
+				if (cmd.args[1].value == 1) {
+					g.attr = GrpObj::Attribute(g.attr | GrpObj::SATURATE);
+					cmd.clear();
+				} else if (cmd.args[1].value == 0) {
+					g.attr = GrpObj::Attribute(g.attr & (~GrpObj::SATURATE));
+					cmd.clear();
+				}
+				g.SetUpdate();
+/* cmd3 == 0x41c : ゲームの進行とともに
+        args:10,105
+        args:10,133
+        args:10,144
+        args:10,144
+ と変化
+
+  cmd3 == 0x418 :
+	args: 10, 400 -> 100
+	と、alpha の増加とともに変化
+*/
+/*
+487 / 8047 : unsupported command; 0x23 - cmd 01-51:0419:00[ 2] 
+        81,-40,
+	第二引数の 1/10 がオブジェクトの回転角
+*/
+			} else if (cmd.cmd3 == 0x400) { // 画像を文字列として指定
+				g.print_moji = cmd.Str(cmd.args[1]);
+				g.SetUpdate();
+				cmd.clear();
+			} else if (cmd.cmd3 == 0x401) { // 画像を文字列として設定:文字の大きさなど
+				/* args: size, xspace, yspace, vertical, color, shadow */
+				/*
+        			args:17, 0,0,-1,  0,-1 DT in Tomoyo
+        			args:17, 0,0,-1,200,-1 Save/Load in Tomoyo
+        			args:20, 0,0, 0,255,-1 "──ありがとう…。" (勝平Ed付近)
+        			args:16,-1,0,99,255,-1 "やあ、久しぶり──…。" (同上,Save/Load Menu)
+        			args:26,-1,0,99,  0,255 Kuma in CLANNAD
+				*/
+				g.print_size = cmd.args[1].value;
+				/* 前景色を得る */
+				int cr,cg,cb; char key[1024];
+				sprintf(key, "#COLOR_TABLE.%03d", cmd.args[5].value);
+				if (config.GetParam(key, 3, &cr, &cg, &cb)) { // color not found
+					cr = cg = cb = 0;
+				}
+				g.print_r = cr;
+				g.print_g = cg;
+				g.print_b = cb;
+				g.SetUpdate();
+				cmd.clear();
+			} else if (cmd.cmd3 == 0x408) { // set order
+				int order = cmd.args[1].value;
+				if (cmd.cmd1 == 1) order *= 1000; // order も 1000 倍する必要がある?
+				g.order = order;
+				ZMoveObj(cmd.args[0].value);
+				cmd.clear();
+			} else if (cmd.cmd3 == 0x40a && cmd.cmd4 == 1) { // set surface geometry?
+				// オブジェクトのどの部分を画面に表示するか(クリップ領域)の設定
+				int rx = cmd.args[1].value;
+				int ry = cmd.args[2].value;
+				g.SetClipArea(cmd.args[1].value, cmd.args[2].value, cmd.args[3].value,cmd.args[4].value);
+				cmd.clear();
+			} else if (cmd.cmd3 == 0x40d) { // set digit number
+				g.dig_number = cmd.args[1].value;
+				g.SetUpdate();
+				cmd.clear();
+			} else if (cmd.cmd3 == 0x40e) { // set digit option
+				g.dig_digit = cmd.args[1].value;
+				int attr = g.attr;
+				attr &= ~(GrpObj::DIG_ZERO | GrpObj::DIG_SIGN | GrpObj::DIG_PACK);
+				if (cmd.args[2].value) attr |= GrpObj::DIG_ZERO;
+				if (cmd.args[3].value) attr |= GrpObj::DIG_SIGN;
+				if (cmd.args[4].value) attr |= GrpObj::DIG_PACK;
+				g.attr = GrpObj::Attribute(attr);
+				g.SetUpdate();
+				cmd.clear();
+			} else if (cmd.cmd3 == 0x40f) { /* set surface number */
+				g.SetSurfaceNum(cmd.args[1].value);
+				cmd.clear();
+			} else if (cmd.cmd3 == 0x416) { // オブジェクトの拡大率設定
+				int zoom = (cmd.args[1].value + cmd.args[2].value)/2; // x,y 別に設定できるらしい
+				zoom = zoom*256/100;
+				g.SetZoomRotate(zoom, -1);
+				cmd.clear();
+			} else if (cmd.cmd3 == 0x419) { // オブジェクトの回転設定
+				int angle = cmd.args[1].value;
+				angle /= 10;
+				if (angle < 0) {
+					angle %= 360;
+					angle += 360;
+				}
+				angle %= 360;
+				g.SetZoomRotate(-1, angle);
+				cmd.clear();
+			}
+			if (cmd.cmd2 == 0x51 && (g.attr & GrpObj::UPDATE_ALL)) {
+				SetObjChanged(cmd.args[0].value);
+			}
+		} else if (cmd.cmd2 == 0x54) {
+			/* 座標取得 */
+			if (cmd.cmd3 == 0x3e8) {
+				GrpObj& obj = grpobj[cmd.args[0].value];
+				VarInfo arg1 = cmd.args[1];
+				VarInfo arg2 = cmd.args[2];
+				int x0, y0;
+				obj.GetPos(0,x0, y0);
+				cmd.SetFlagvar(arg1, x0);
+				cmd.SetFlagvar(arg2, y0);
+			} else if (cmd.cmd3 == 0x44c) {
+				int w, h;
+				GrpObj& obj = grpobj[cmd.args[0].value];
+				obj.GetSrcGeom(w, h);
+				VarInfo arg1 = cmd.args[1];
+				VarInfo arg2 = cmd.args[2];
+				cmd.SetFlagvar(arg1, w);
+				cmd.SetFlagvar(arg2, h);
+			}
+		}
+		// セーブ用にコマンドを元に戻す
+		if (cmd.args.size() != 0 && (cmd.cmd_type == CMD_SAVECMDGRP || cmd.cmd_type == CMD_SAVECMDGRP_ONCE)) {
+			if (cmd.cmd1 == 1) cmd.args[0].value /= 1000;
+			else if (cmd.cmd1 == 2) {
+				vector<VarInfo> args = cmd.args;
+				int value = args[0].value;
+				cmd.args.clear();
+				args[0].value = value / 1000;
+				cmd.args.push_back(args[0]);
+				args[0].value = value % 1000 - 500;
+				cmd.args.push_back(args[0]);
+				cmd.args.insert(cmd.args.end(), args.begin()+1, args.end());
+			}
+		}
+	}
+#endif
+	if (cmd.cmd1 == 1 && cmd.cmd2 == 0x1f) { // 本来は grpstack clear らしい
+		RefreshObj();
+		// Princess Bride の中途 Staff roll
+		// このタイミングで描画するのが都合がいいので、
+		//シナリオループを抜けて描画を起動
+		cmd.cmd_type = CMD_WAITFRAMEUPDATE;
+	}
+
+/* XXX : GiGiGi */
+/* 122 :  0x23 - cmd 01-04:0924:00[ 0] : V<sys> にBGM再生モードを返す (0/1)
+** 256 :  0x23 - cmd 01-04:091a:00[ 0] : V<sys> にBGM音量を返す (0-255?)
+** 278 :  0x23 - cmd 01-04:0926:00[ 0] : V<sys> にEff再生モードを返す (0/1)
+** 412 :  0x23 - cmd 01-04:091c:00[ 0] : V<sys> にEff音量を返す (0-255?)
+** 434 :  0x23 - cmd 01-04:0927:00[ 0] : V<sys> にSE 再生モードを返す (0/1)
+** 568 :  0x23 - cmd 01-04:091d:00[ 0] : V<sys> にSE 音量を返す (0-255?)
+
+** 122 :  0x23 - cmd 01-04:08c0:00[ 0] : V<sys> にBGM再生モードを設定 (0/1)
+** 256 :  0x23 - cmd 01-04:08b6:00[ 0] : V<sys> にBGM音量を設定 (0-255?)
+** 278 :  0x23 - cmd 01-04:08c2:00[ 0] : V<sys> にEff再生モードを設定 (0/1)
+** 412 :  0x23 - cmd 01-04:08b8:00[ 0] : V<sys> にEff音量を設定 (0-255?)
+** 434 :  0x23 - cmd 01-04:08c3:00[ 0] : V<sys> にSE 再生モードを設定 (0/1)
+** 568 :  0x23 - cmd 01-04:08b9:00[ 0] : V<sys> にSE 音量を設定 (0-255?)
+*/
+	// 本来は音楽関連のコマンド
+	if (cmd.cmd1 == 1 && cmd.cmd2 == 0x14) {
+		if (cmd.cmd3 == 0 && cmd.cmd4 == 0) {
+			eprintf("play bgm %s\n",cmd.Str(cmd.args[0]));
+			music.PlayCDROM( (char*)cmd.Str(cmd.args[0]), 10000);
+			cmd.cmd_type = CMD_SAVECMD_ONCE;
+		}
+		if (cmd.cmd3 == 2 && (cmd.cmd4 == 2 || cmd.cmd4 == 0) ) { /* ??? : ことみシナリオラストの音楽再生 */
+			eprintf("play bgm %s\n",cmd.Str(cmd.args[0]));
+			music.PlayCDROM( (char*)cmd.Str(cmd.args[0]), 1);
+			cmd.cmd_type = CMD_SAVECMD_ONCE;
+		}
+		if (cmd.cmd3 == 0 && cmd.cmd4 == 2) {
+			eprintf("fade bgm %d? and play bgm %s; %d\n",cmd.args[1].value, cmd.Str(cmd.args[0]), cmd.args[2].value);
+			// music.PlayCDROM( (char*)cmd.Str(cmd.args[0]), 10000, cmd.args[2].value);
+			music.PlayCDROM( (char*)cmd.Str(cmd.args[0]), 10000);
+			cmd.cmd_type = CMD_SAVECMD_ONCE;
+		}
+		if ( (cmd.cmd3 == 5 || cmd.cmd3 == 0x69) && cmd.cmd4 == 0) {
+			if (cmd.cmd3 == 5) {
+				music.StopCDROM(0);
+				eprintf("stop bgm\n");
+			} else {
+				music.StopCDROM(cmd.args[0].value);
+				eprintf("fade bgm %d\n",cmd.args[0].value);
+			}
+			cmd.cmd_type = CMD_SAVECMD_ONCE;
+		}
+	}
+	if (cmd.cmd1 == 1 && cmd.cmd2 == 0x15) {
+		if ((cmd.cmd3 == 2) || (cmd.cmd3 == 0 && cmd.cmd4 == 1) || (cmd.cmd3 == 0 && cmd.cmd4 == 0)) {
+			eprintf("play SE %s\n",cmd.Str(cmd.args[0]));
+			if (cmd.cmd3 == 2) {
+				music.PlaySE(cmd.Str(cmd.args[0]),1);
+				cmd.cmd_type = CMD_SAVECMD_ONCE;
+			} else {
+				music.PlaySE(cmd.Str(cmd.args[0]));
+				cmd.clear();
+			}
+		} else if (cmd.cmd3 == 5) {
+			eprintf("Stop SE\n");
+			music.StopSE();
+			cmd.cmd_type = CMD_SAVECMD_ONCE;
+		} else if (cmd.cmd3 == 0x69) {
+			eprintf("Stop SE with fade %d\n",cmd.args[0].value);
+			music.StopSE(cmd.args[0].value);
+			cmd.cmd_type = CMD_SAVECMD_ONCE;
+		}
+	}
+	if (cmd.cmd1 == 1 && cmd.cmd2 == 4 && (cmd.cmd3 == 0x4bb || cmd.cmd3 == 0x4bc) ) {
+		// 音楽を待ってみる(絶対に違うが)。本来、04-803 に対応してなにかの終わりをwaitするっぽい(風子/智代Ed付近)
+		// EnableSyscom らしいが、よくわからない (rldev)
+//		if (!music.IsStopSE()) status = WAIT_SE;
+		cmd.clear();
+	}
+	if (cmd.cmd1 == 1 && cmd.cmd2 == 4 && (cmd.cmd3 == 0x8b6 || cmd.cmd3 == 0x91a) ) {
+		// 音楽モードで音量を上げるためのコマンド (SetBgmVolume)
+		// とりあえず未実装
+		cmd.clear();
+	}
+
+	if (cmd.cmd1 == 1 && cmd.cmd2 == 0x16) {
+		if (cmd.cmd3 == 0 && cmd.cmd4 == 0) {
+			eprintf("play SE %d\n",cmd.args[0].value);
+			music.PlaySE(cmd.args[0].value);
+			cmd.clear();
+		}
+	}
+	if (cmd.cmd1 == 1 && cmd.cmd2 == 0x17) {
+		if (cmd.cmd3 == 0) {
+			eprintf("play koe %d",cmd.args[0].value);
+			if (cmd.cmd4 == 1) {
+				eprintf(", para? %d",cmd.args[1].value);
+			}
+			eprintf("\n");
+			char buf[1024]; sprintf(buf, "%d",cmd.args[0].value);
+			if ( !(skip_mode & SKIP_TEXT)) music.PlayKoe(buf);
+			cmd.clear();
+		}
+	}
+	if (cmd.cmd1 == 1 && cmd.cmd2 == 0x1a) {
+		if ( (cmd.cmd3 == 0x14 || cmd.cmd3 == 1) && cmd.cmd4 == 0) {
+			const char* str = cmd.Str(cmd.args[0]);
+			int x = cmd.args[1].value;
+			int y = cmd.args[2].value;
+			int x2 = cmd.args[3].value;
+			int y2 = cmd.args[4].value;
+			eprintf("play movie ; name %s pos %d,%d - %d,%d\n",str,x,y,x2,y2);
+			music.PlayMovie(str, x, y, x2, y2,1);
+			status = WAIT_MOVIE;
+			event.RegisterGlobalPressFunc(&Pressed, (void*)this);
+			cmd.clear();
+		}
+	}
+	return;
+}
+
+
+/********************************************************
+**
+**	class Grp
+*/
+
+Grp::Grp(Event::Container& _event, PicContainer& _parent, const Flags& f, set<int>& _cgm,class MuSys& mu, AyuSysConfig& config) {
+	pimpl = new GrpImpl(_event, _parent, f, _cgm, mu, config);
+};
+Grp::~Grp() {
+	delete pimpl;
+}
+
+bool Grp::Wait(unsigned int current_time, Cmd& cmd) {
+	return pimpl->Wait(current_time, cmd);
+}
+void Grp::Exec(Cmd& cmd) {
+	pimpl->Exec(cmd);
+}
+void Grp::SetSkipMode(SkipMode mode) {
+	pimpl->SetSkipMode(mode);
+}
+void Grp::InitSel(AyuSysConfig& config) {
+	pimpl->InitSel(config);
+}
+void Grp::Save(std::string& str) {
+	pimpl->Save(str);
+}
+
+void Grp::Load(const char* str) {
+	pimpl->Load(str);
+}
+void Grp::SaveSys(std::string& str) {
+	pimpl->SaveSys(str);
+}
+
+void Grp::LoadSys(const char* str) {
+	pimpl->LoadSys(str);
+}
new file mode 100644
--- /dev/null
+++ b/scn2k/scn2k_impl.cc
@@ -0,0 +1,1909 @@
+/*
+ * Copyright (c) 2004-2006  Kazunori "jagarl" Ueno
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdexcept>
+#include"scn2k_impl.h"
+#include"system/file.h"
+#include"system/system_config.h"
+#include"window/picture.h"
+#include"window/system.h"
+
+// #define DEBUG 1
+
+using namespace std;
+
+/**********************************************
+** Scn2k
+*/
+
+void kconv(const unsigned char* src, unsigned char* dest);
+void kconv_rev(const unsigned char* src, unsigned char* dest);
+string kconv(const string& s);
+string kconv_rev(const string& s);
+
+Scn2k::Scn2k(Event::Container& _event, PicContainer& _parent, class MuSys& mu, AyuSysConfig& _config) :
+	Event::Time(_event),
+	event(_event),
+	parent(_parent),
+	config(_config),
+	text_exec(_event, _parent, config),
+	grp_exec(_event, _parent, flag, flag.cgm_data, mu, config)
+{
+	system_version = 0;
+	skip_mode = SKIP_NO;
+
+	script_start = 0;
+	script = 0;
+	script_end = 0;
+
+	backlog_script_scn = -1;
+	backlog_script_start = 0;
+	backlog_script_end = 0;
+
+	save_scn = 0;
+	save_point = 0;
+	scn_number = 0;
+	scn_point = 0;
+	cmd_stack_str = cmd_stack_str_orig;
+
+	dialog = 0;
+	dialog_type = CMD_NOP;
+	menu = 0;
+	menu_mouseshown = false;
+
+	/* マウスカーソルを作成 */
+	mouse_type = 0;
+	mouse_surface = 0;
+	mouse_pressed = 0;
+	ShowCursor();
+
+	LoadSys();
+	text_exec.InitWindow();
+	grp_exec.InitSel(config);
+}
+
+Scn2k::~Scn2k() {
+	HideCursor();
+	SaveSys();
+}
+
+char* Scn2k::OpenScript(int new_scn_number, char*& end, int* call_vec, int& system_version) {
+	char fname[1024];
+	const char* data;
+	char* ret_data;
+	int offset = 0;
+	int scenario_magic;
+
+	sprintf(fname, "SEEN%04d.TXT", new_scn_number);
+	ARCINFO* info = file_searcher.Find(FILESEARCH::SCN, fname, "");
+	if (info == 0) goto err;
+	data = info->Read();
+
+	/* version 確認 */
+	scenario_magic = read_little_endian_int(data + 4);
+	if (scenario_magic != 0x2712 && scenario_magic != 0x1adb2) {
+		fprintf(stderr,"Invalid scenario header : scenario number %d\n",new_scn_number);
+		goto err;
+	}
+	if (read_little_endian_int(data) == 0x1cc) {
+		system_version = 0;
+		offset = 0x1cc + read_little_endian_int(data+0x20) + 4;
+	} else if (read_little_endian_int(data) == 0x1d0) {
+		system_version = 1;
+		offset = read_little_endian_int(data + 0x20);
+	} else {
+		fprintf(stderr,"Invalid scenario header : scenario number %d\n",new_scn_number);
+		goto err;
+	}
+	/* header から subroutine number とりだし */
+	if (call_vec) {
+		int i;
+		for (i=0; i<100; i++) {
+			call_vec[i] = read_little_endian_int(data + 0x34 + i * 4);
+		}
+	}
+	ret_data = new char[info->Size() - offset + 1024];
+	memcpy(ret_data, data+offset, info->Size()-offset);
+	memset(ret_data+info->Size()-offset, 0, 1024);
+	end = ret_data + info->Size() - offset;
+	delete info;
+	return ret_data;
+
+err:
+	delete info;
+	fprintf(stderr,"Cannot open scenario number %d\n",new_scn_number);
+	throw std::invalid_argument("Scn2k::OpenScript");
+
+	return false;
+}
+bool Scn2k::ChangeScript(int new_scn_number, int call_no) {
+	int old_scn_number = scn_number;
+	int old_scn_pt = script - script_start;
+	int scn_pt = 0;
+
+	if (script_start) delete[] script_start;
+	script_start = 0;
+	script = 0;
+	script_end = 0;
+
+	int call_vec[100];
+
+	try {
+		script_start = OpenScript(new_scn_number, script_end, call_vec, system_version);
+	} catch(...) {
+		fprintf(stderr,"\tFrom script %d pt %d\n",old_scn_number, old_scn_pt);
+		throw;
+	}
+	if (call_no > 0 && call_no < 100) {
+		scn_pt = call_vec[call_no];
+		if (scn_pt == 0) {
+			fprintf(stderr,"Invalid subroutine number: scn %d sub %d\n",new_scn_number, call_no);
+			scn_pt = 0;
+		}
+	} else if (call_no < 0) {
+		scn_pt = -call_no; // デバッグ用
+	}
+
+	scn_number = new_scn_number;
+	scn_point = scn_pt;
+	script = script_start + scn_pt;
+	if (script < script_start || script >= script_end) 
+		fprintf(stderr,"scn %d pt %d: Cannot jump to %d:%d; fall back to the top\n",old_scn_number, old_scn_pt, scn_number, scn_pt);
+	return true;
+}
+bool Scn2k::ReadCmdAt(Cmd& cmd, int scn, int pt) {
+	const char* d;
+	if (scn ==scn_number) {
+		d = script_start + pt;
+		if (d < script_start || d >= script_end) {
+			fprintf(stderr,"Cannot read script at current scn %d pt %d\n", scn, pt);
+			return false;
+		}
+	} else {
+		if (backlog_script_scn != scn) {
+			if (backlog_script_start) delete[] backlog_script_start;
+			backlog_script_start = OpenScript(scn, backlog_script_end, 0, system_version);
+		}
+		d = backlog_script_start + pt;
+		if (d < backlog_script_start || d >= backlog_script_end) {
+			fprintf(stderr,"Cannot read script at scn %d pt %d\n", scn, pt);
+			return false;
+		}
+	}
+	
+	cmd.GetCmd(flag, d);
+	return true;
+}
+
+extern bool save_req, load_req; // キーボードからセーブ・ロードできるように
+extern bool pressAreq;
+
+void Scn2k::Elapsed(unsigned int current_time) {
+	SetWakeup(current_time + 10); // 10msに一回シナリオスクリプト解釈
+	if (script == 0) return;
+//VarInfo info; info.type = 6; info.number = 0; // PB の「一回ゲームを開始したことがある」フラグ
+//flag.Set(info,1);
+//info.type = 0; info.number = 604; // Princess Bride: クリア対象設定フラグ (聖)
+//flag.Set(info, 1); 
+
+
+	Cmd cmd(flag, system_version);
+	int cnt1;
+	int cnt2 = 1000; // flag / jump / flag 系コマンドの最大実行回数
+
+	/* XXX */
+	if (save_req) {
+		save_req = false;
+		load_req = false;
+		cmd.cmd_type = CMD_SAVEREQ;
+	} else if (load_req) {
+		load_req = false;
+		save_req = false;
+		cmd.cmd_type = CMD_LOADREQ;
+	}
+	if (pressAreq) {
+		pressAreq = false;
+		LoadRollback(cmd);
+		return;
+	}
+
+	/* キー入力などに対応 */
+	// メニュー内以外で shift キーが押されたらスキップ開始
+	if ( (skip_mode&SKIP_IN_MENU) == 0) {
+		if (event.pressed(KEY_SHIFT)) {
+			if (skip_mode & SKIP_TEXT) {
+				; // スキップ中ならなにもしない
+			} else {
+				SetSkipMode(SkipMode(SKIP_TEXT | SKIP_GRP_NOEFFEC | SKIPEND_KEY));
+			}
+		} else {
+			if ( skip_mode & SKIPEND_KEY) {
+				if ( (skip_mode & SKIPEND_TEXT) && (skip_mode & SKIP_TEXT)) {
+					SkipMode new_skip_mode = SkipMode(skip_mode & (~SKIPEND_KEY));
+					if ( (new_skip_mode & SKIP_GRP_FAST) || (new_skip_mode & SKIP_GRP_NODRAW)) {
+						new_skip_mode = SkipMode(skip_mode & (~SKIP_GRP_NOEFFEC));
+					}
+					SetSkipMode(new_skip_mode);
+				} else {
+					SetSkipMode(SKIP_NO);
+				}
+			}
+		}
+	}
+
+	for (cnt1=0; cnt1<20; cnt1++) { // 一回につき 20 個のコマンド実行
+		// 他のコマンド実行中なら終了
+		if ( (cmd.cmd_type == CMD_NOP && SysWait(cmd)) ||
+		     // (cmd.cmd_type == CMD_NOP && text_exec.Wait(current_time, cmd)) ||
+		     // (cmd.cmd_type == CMD_NOP && grp_exec.Wait(current_time, cmd))) {
+		     (cmd.cmd_type == CMD_NOP && grp_exec.Wait(current_time, cmd)) ||
+		     (cmd.cmd_type == CMD_NOP && text_exec.Wait(current_time, cmd))) {
+			break;
+		}
+		// コマンド読み込み
+		for (; cnt2 > 0; cnt2--) {
+			scn_point = script - script_start;
+			eprintf("%d / %d :", script - script_start, script_end-script_start);
+// fprintf(stderr,"%d: %d / %d :",scn_number,  script - script_start, script_end-script_start);
+			cmd.GetCmd(flag, script);
+//		if (cmd.cmd_type != CMD_NOP) {
+if (0) {
+			fprintf(stderr,"%d / %d : 0x23 - cmd %02x-%02x:%04x:%02x[%2d] \n",
+				scn_point, script_end-script_start,
+				cmd.cmd1,cmd.cmd2,cmd.cmd3,cmd.cmd4,cmd.argc);
+			int i; for (i=0; i<cmd.args.size(); i++) {
+				if (i == 0) fprintf(stderr,"\t");
+				VarInfo info = cmd.args[i];
+				if (info.type == TYPE_STR || info.type == TYPE_VARSTR)
+					fprintf(stderr,"\"%s\",", cmd.Str(info));
+				else
+					fprintf(stderr,"%d,",info.value);
+			}
+			fprintf(stderr,"\n");
+		}
+			cmd.scn = scn_number;
+			cmd.pos = scn_point;
+			if (cmd.IsError()) break;
+			if (cmd.cmd_type == CMD_NOP) continue;
+			if (cmd.cmd_type == CMD_JMP) {
+				// local jump
+				if (cmd.cmd1 == 0 && cmd.cmd2 == 1 && cmd.cmd3 == 16) {
+					int i;
+					for (i=0; i<cmd.args.size()-1; i++) {
+						VarInfo var;
+						var.type = 11;
+						var.number = i;
+						flag.Set(var, cmd.args[i].value);
+					}
+					cmd.args[0].value = cmd.args[i].value;
+				}
+				if ( cmd.cmd1 == 0 && cmd.cmd2 == 1 && (cmd.cmd3 == 5 || cmd.cmd3 == 8 || cmd.cmd3 == 16) ) { // local call / simple switch
+					int scn_pt = script - script_start;
+// fprintf(stderr,"\nlocal call %d:%d from %d\n",scn_number,cmd.args[0].value,scn_pt);
+					stack.push_back(StackItem(-1, scn_pt));
+				}
+if (cmd.cmd1 == 0 && cmd.cmd2 == 1 && cmd.cmd3 == 1) {
+	fprintf(stderr,"***  unsupported: cond 1\n");
+}
+				script = script_start + cmd.args[0].value;
+				if (script < script_start || script >= script_end) {
+					fprintf(stderr,"scn %d pt %d: Cannot jump to %d; fall back to the top\n",scn_number, cmd.args[0].value);
+					script = script_start;
+				}
+				cmd.clear();
+				continue;
+			}
+			if (flag.Exec(cmd)) continue;
+			break;
+		}
+		if (cmd.IsError()) {
+fprintf(stderr,"cmd error occured: scn %d pt %d / cur %d",scn_number,scn_point,script-script_start);
+			while(script < script_end) {
+				if (*script == 0x29 && script[1] == 0x0a) {script++;break;}
+				if (*script == 0 && script[1] == 0x0a) {script++;break;}
+				if (*script == 0 && script[1] == 0x23) {script++;break;}
+				script++;
+fprintf(stderr," -> fall back to %d\n",script-script_start);
+			}
+			const char* dprev = script - 0x60;
+			if (dprev < script_start) dprev = script_start;
+			int ilen = (script-dprev+65)/16;
+			int i; for (i=0; i<ilen; i++) {
+				fprintf(stderr, "%6d: ",dprev-script_start);
+				int j; for (j=0; j<16; j++) {
+					if (dprev >= script_end) break;
+					fprintf(stderr, "%02x ",*(unsigned char*)(dprev));
+					dprev++;
+				}
+				fprintf(stderr, "\n");
+			}
+			break;
+		}
+		if (cmd.cmd_type == CMD_NOP) continue;
+
+		if (cmd.cmd_type == CMD_TEXT && cmd.pos != -1) {
+			set<int>& readflag = text_readflag[scn_number];
+			if (readflag.find(cmd.pos) == readflag.end()) { // 未読テキスト発見
+				readflag.insert(cmd.pos);
+				if (skip_mode & SKIPEND_TEXT) {
+					if (!(skip_mode & SKIPEND_KEY)) SetSkipMode(SKIP_NO);
+				}
+			}
+		}
+		text_exec.Exec(cmd);
+		grp_exec.Exec(cmd);
+		SysExec(cmd);
+		if (cmd.cmd_type == CMD_WAITFRAMEUPDATE) {
+			SetWakeup(Event::Time::FRAME_UPDATE);
+			break;
+		} else if (cmd.cmd_type != CMD_NOP) {
+#if DEBUG
+			fprintf(stderr,"%d-%d / %d : unsupported command; 0x23 - cmd %02x-%02x:%04x:%02x[%2d] \n",
+				cmd.scn, script - script_start, script_end-script_start,
+				cmd.cmd1,cmd.cmd2,cmd.cmd3,cmd.cmd4,cmd.argc);
+			int i; for (i=0; i<cmd.args.size(); i++) {
+				if (i == 0) fprintf(stderr,"\t");
+				VarInfo info = cmd.args[i];
+				if (info.type == TYPE_STR || info.type == TYPE_VARSTR)
+					fprintf(stderr,"\"%s\",", cmd.Str(info));
+				else
+					fprintf(stderr,"%d,",info.value);
+			}
+			fprintf(stderr,"\n");
+#endif
+			cmd.clear();
+		}
+	}
+	return;
+}
+
+void Scn2k::ShowCursor(void) {
+	HideCursor();
+	char key[1024];
+	sprintf(key, "#MOUSE_CURSOR.%03d.NAME",mouse_type);
+	const char* name = config.GetParaStr(key);
+	if (name == 0 || name[0] == 0) mouse_surface = DEFAULT_MOUSECURSOR;
+	else {
+		mouse_surface = parent.Root().NewSurface(name, COLOR_MASK);
+	}
+	if (mouse_surface == 0) mouse_surface = DEFAULT_MOUSECURSOR;
+	System::Main::SetCursor(mouse_surface, Rect(8, 8, 8+32, 8+32));
+}
+
+void Scn2k::HideCursor(void) {
+	if (mouse_surface) {
+		System::Main::SetCursor(0, Rect(0,0));
+		if (mouse_surface != DEFAULT_MOUSECURSOR)
+			parent.Root().DeleteSurface(mouse_surface);
+		mouse_surface = 0;
+	}
+	return;
+}
+
+bool Scn2k::SysWait(Cmd& cmd) {
+
+	if (menu) {
+		menu->Exec(cmd);
+		if (menu->status & Scn2kMenu::MENU_DELETE || menu->pimpl == 0) {
+			delete menu;
+			menu = 0;
+			if (! menu_mouseshown) HideCursor();
+			else ShowCursor();
+			SetSkipMode(SkipMode(skip_mode & (~SKIP_IN_MENU) ));
+		}
+		if (cmd.cmd_type == CMD_NOP) return true;
+		else return false; /* exec command */
+	}
+	return false;
+}
+
+void DllCall_LB(Cmd& cmd, Flags& flags);
+void Scn2k::SysExec(Cmd& cmd) {
+	if (cmd.cmd_type == CMD_SYSVAR) {
+		int i;
+		for (i=0; i<cmd.args.size(); i++) {
+			if (cmd.args[i].type == TYPE_SYS) {
+				if (cmd.args[i].number == TYPE_SYS_SYS) {
+					flag.SetSys(cmd.args[i].value);
+				} else if (cmd.args[i].number == TYPE_SYS_SKIPMODE) {
+					SetSkipMode(SkipMode(cmd.args[i].value));
+				}
+			} else if (cmd.args[i].type == TYPE_VARSTR) {
+				flag.SetStr(cmd.args[i].number, cmd.Str(cmd.args[i]));
+			} else {
+				flag.Set(cmd.args[i], cmd.args[i].value);
+			}
+		}
+		cmd.clear();
+	}
+	if (cmd.cmd_type == CMD_SAVEPOINT || cmd.cmd_type == CMD_ROLLBACKPOINT) {
+		if (text_exec.backlog_item.scn != -1) {
+			text_exec.backlog.push_back(text_exec.backlog_item);
+			text_exec.backlog_item.Clear();
+		}
+		save_scn = scn_number;
+		save_point = scn_point;
+		if (!new_rollback_save.empty()) {
+			rollback_save.push_back(new_rollback_save);
+			new_rollback_save = "";
+		}
+		if (cmd.cmd_type == CMD_ROLLBACKPOINT) SaveRollback();
+		cmd.clear();
+	}
+	if (cmd.cmd_type == CMD_SAVEREQ || cmd.cmd_type == CMD_SAVE) {
+		Save(cmd);
+		return;
+	}
+	if (cmd.cmd_type == CMD_LOADREQ || cmd.cmd_type == CMD_LOAD) {
+		Load(cmd);
+		return;
+	}
+	if (cmd.cmd_type == CMD_BACKLOGREQ || cmd.cmd_type == CMD_BACKLOGREQ_FWD) {
+		if (menu) {
+			fprintf(stderr,"BACKLOG_REQ requested!!!\n");
+			return;
+		}
+		if (cmd.cmd_type == CMD_BACKLOGREQ_FWD) {
+			cmd.clear(); // backlog mode 以外で fwd を押されてもなにもしない
+			return;
+		}
+		SetSkipMode(SKIP_IN_MENU); // テキストスキップ等はここで中断
+		menu = new Scn2kMenu(Scn2kMenu::MENU_BACKLOG, *this, flag, text_exec, system_version);
+		menu->InitPanel(event, parent);
+		menu->InitTitle(Scn2kSaveTitle(*this));
+		if (mouse_surface) menu_mouseshown = true;
+		else menu_mouseshown = false;
+		ShowCursor();
+		return;
+	}
+	if (cmd.cmd_type == CMD_MENUREQ) {
+		int scn=0, pt=0;
+		config.GetParam("#CANCELCALL", 2, &scn, &pt);
+		if (scn) {
+			// 右クリックされたら global call を行う
+			cmd.cmd_type = CMD_OTHER;
+			cmd.cmd1 = 0;
+			cmd.cmd2 = 1;
+			cmd.cmd3 = 0x0c;
+			cmd.cmd4 = 1;
+			cmd.args.clear();
+			cmd.args.push_back(VarInfo(SCN_INFO_MENU));
+			cmd.args.push_back(0);
+			SetSkipMode(SKIP_IN_MENU); // テキストスキップ等はここで中断
+		}
+	}
+	if (cmd.cmd_type == CMD_SAVECMDGRP || cmd.cmd_type == CMD_SAVECMDGRP_START || cmd.cmd_type == CMD_SAVECMDGRP_ONCE || cmd.cmd_type == CMD_SAVECMD_ONCE) {
+		// 画像コマンド等はスタックに保存し、セーブ時に保存できるようにする
+		if (cmd.cmd_type == CMD_SAVECMDGRP_START) {
+			vector<CmdSimplified>::iterator it, cur;
+			cur = cmd_stack.begin();
+			cmd_stack_str = cmd_stack_str_orig;
+			/* 画像関連コマンド以外を別にする */
+			for (it=cmd_stack.begin(); it != cmd_stack.end(); it++) {
+				if (it->type != CMD_SAVECMDGRP && it->type != CMD_SAVECMDGRP_START && it->type != CMD_SAVECMDGRP_ONCE) {
+					cur->copy(*it, cmd_stack_str);
+					cur++;
+				}
+			}
+			cmd_stack.erase(cur, cmd_stack.end());
+		}
+		if (cmd.cmd_type == CMD_SAVECMD_ONCE || cmd.cmd_type == CMD_SAVECMDGRP_ONCE) { // 同じコマンドがあれば削除する
+			vector<CmdSimplified>::iterator it;
+			for (it = cmd_stack.end(); it != cmd_stack.begin(); ) {
+				--it;
+				if (it->cmd1 == cmd.cmd1 && it->cmd2 == cmd.cmd2 && it->cmd3 == cmd.cmd3 && it->cmd4 == cmd.cmd4) {
+					cmd_stack.erase(it);
+					break;
+				}
+			}
+		}
+		CmdSimplified cmd_item;
+		cmd.write(cmd_item, cmd_stack_str);
+		cmd_stack.push_back(cmd_item);
+		cmd.clear();
+		if (cmd_stack_str > cmd_stack_str_orig + 30000) { // char cmd_stack_str_orig[32768]
+			fprintf(stderr,"Error in Scn2k::SysExec: too long cmdstack (%d): stack string overflow\n",cmd_stack.size());
+			cmd_stack_str = cmd_stack_str_orig;
+			cmd_stack.clear();
+		}
+	}
+	if (cmd.cmd_type != CMD_OTHER) return;
+	if (cmd.cmd1 == 0 && cmd.cmd2 == 1) {
+		if (cmd.cmd3 == 0x0b) { // global jump
+			eprintf("global jump to %d\n",cmd.args[0].value);
+			if (! ChangeScript(cmd.args[0].value, 0)) return; // 読み込めない; abort.
+			cmd.clear();
+		} else if (cmd.cmd3 == 0x0c || cmd.cmd3 == 0x12) { // call (0x12 の方は微妙)
+			int new_scn = cmd.args[0].value;
+			int new_pt = 0;
+			if (cmd.args.size() >= 1) { // subroutine number が付く
+					// 引数が付くのもあるらしい
+				new_pt = cmd.args[1].value;
+			}
+			if (new_scn == SCN_INFO_MENU) { // menu call
+				config.GetParam("#CANCELCALL", 2, &new_scn, &new_pt);
+				stack.push_back(StackItem(SCN_INFO, SCN_INFO_MENU)); // menu call を示す特殊な記号
+			} else {
+				int i;
+				VarInfo var;
+				// ローカル変数を伴う subroutine call
+				var.type = 11;
+				var.number = 0;
+				int saved_vars = 0;
+				for (i=0; i<40; i++) {
+					int val = flag.Get(var.type, i);
+					if (val != 0) {
+						stack.push_back(StackItem(SCN_INFO_LOCALS + i, val));
+						saved_vars++;
+					}
+				}
+				var.type = TYPE_VARLOCSTR;
+				for (i=0; i<3; i++) {
+					string s = flag.Str(var.type, i);
+					if (s.size()) {
+						int sp = stack_strbuffer.size();
+						stack.push_back(StackItem(SCN_INFO_LOCALSTR+i, sp));
+						stack_strbuffer.push_back(s);
+						saved_vars++;
+					}
+				}
+				stack.push_back(StackItem(SCN_INFO, SCN_INFO_LOCALS + saved_vars));
+					
+				var.type = 11;
+				var.number = 0;
+				// 特殊な subroutine call なので、余計な情報を引数に渡す
+				for (i=2; i<cmd.args.size(); i++) {
+					flag.Set(var, cmd.args[i].value);
+// fprintf(stderr,"<%d:%d>=%d;",var.type,var.number,cmd.args[i].value);
+					var.number++;
+				}
+// fprintf(stderr,"%d; ",stack.size());
+			}
+			int scn_pt = script - script_start;
+			stack.push_back(StackItem(scn_number, scn_pt));
+// fprintf(stderr,"\nglobal call %d:%d from %d:%d\n",new_scn,new_pt,scn_number,scn_pt);
+			eprintf("global call to %d, %d\n",new_scn, new_pt);
+			if (! ChangeScript(new_scn, new_pt)) return; // 読み込めない; abort.
+			cmd.clear();
+		} else if (cmd.cmd3 == 0x65) { // 文字列の返り値をセットする
+			int arg1 = cmd.args[0].value;
+			string s = cmd.Str(cmd.args[1]);
+			int sp = stack_strbuffer.size();
+			stack.push_back(StackItem(SCN_INFO_RETSTR+arg1, sp));
+			stack_strbuffer.push_back(s);
+			cmd.clear();
+		} else if (cmd.cmd3 == 0x0d || cmd.cmd3 == 0x0a || cmd.cmd3 == 0x11 || cmd.cmd3 == 0x13) { // return (0a: local return) (0x13はよくわからない)
+// fprintf(stderr,"global return : stack size %d\n",stack.size());
+			if (stack.empty()) {
+				cmd.clear();
+				return; // スタックがおかしい:abort
+			}
+			map<int, string> retstr;
+			while( (!stack.empty()) && stack.back().scn_number >= SCN_INFO_RETSTR) {
+				int ret_num = stack.back().scn_number - SCN_INFO_RETSTR;
+// fprintf(stderr,"\nRetStr;");
+				string str = stack_strbuffer.back();
+				stack_strbuffer.pop_back();
+				retstr[ret_num] = str;
+				stack.pop_back();
+			}
+			if (stack.empty()) {
+				cmd.clear();
+				return; // スタックがおかしい:abort
+			}
+			StackItem s = stack.back();
+			stack.pop_back();
+			bool localvar_init = false;
+			while( (!stack.empty()) && stack.back().scn_number == SCN_INFO) {
+				int mode = stack.back().scn_pt;
+				stack.pop_back();
+				if (mode == SCN_INFO_MENU) {
+// fprintf(stderr,"\nInfo Menu;");
+					// menu モード終了
+					SetSkipMode(SkipMode(skip_mode & (~SKIP_IN_MENU) ));
+				} else if (mode >= SCN_INFO_LOCALS && mode <= SCN_INFO_LOCALS+50) {
+// fprintf(stderr,"\nInfo Local;");
+					int i;
+					// ローカル変数を元に戻す
+					VarInfo var;
+					var.type = 11;
+					var.number = 0;
+					for (i=0; i<40; i++) {
+						var.number = i;
+						flag.Set(var, 0);
+					}
+					var.type = TYPE_VARLOCSTR;
+					for (i=0; i<3; i++) {
+						var.number = i;
+						flag.SetStr(var, "");
+					}
+					int args = mode - SCN_INFO_LOCALS;
+// fprintf(stderr," args = %d; ",args);
+					for (i=0; i<args; i++) {
+						if (stack.empty() || stack.back().scn_number < SCN_INFO) {
+							fprintf(stderr,"Fatal : Invalid stack found in preserved local variables!\n");
+							break;
+						}
+						var.number = stack.back().scn_number;
+// fprintf(stderr,"%d:%d; ",stack.back().scn_number,stack.back().scn_pt);
+						if (var.number >= SCN_INFO_LOCALS && var.number < SCN_INFO_LOCALSTR) {
+							var.type = 11;
+							var.number -=  SCN_INFO_LOCALS;
+							flag.Set(var, stack.back().scn_pt);
+						} else if (var.number >= SCN_INFO_LOCALSTR && var.number < SCN_INFO_RETSTR) {
+							var.type = TYPE_VARLOCSTR;
+							var.number -= SCN_INFO_LOCALSTR;
+							flag.SetStr(var, stack_strbuffer.back());
+							stack_strbuffer.pop_back();
+						}
+						stack.pop_back();
+					}
+				}
+// fprintf(stderr,"stack size %d string size %d\n",stack.size(),stack_strbuffer.size());
+			}
+			if (cmd.cmd3 == 0x11 || cmd.cmd3 == 0x13) {
+// fprintf(stderr,"\nSet RetLocal;");
+				// 返り値をセットする
+				map<int,string>::iterator it;
+				VarInfo var;
+				var.type = TYPE_VARLOCSTR;
+				for (it=retstr.begin(); it!=retstr.end(); it++) {
+					var.number = it->first;
+					flag.SetStr(var, it->second);
+				}
+				var.type = 11;
+// fprintf(stderr,"return : cmd.cmd3 == 0x11; size %d\n",cmd.args.size());
+				if (cmd.args.size() == 1) {
+// fprintf(stderr,"return value %d\n",cmd.args[0].value);
+					flag.SetSys(cmd.args[0].value);
+				} else {
+					int i;for (i=0; i<cmd.args.size(); i++) {
+						var.number = i;
+						flag.Set(var, cmd.args[i].value);
+					}
+				}
+			}
+// fprintf(stderr,"global return : return to %d:%d\n",s.scn_number,s.scn_pt);
+// fprintf(stderr,"\nglobal return %d:%d from %d:%d\n",s.scn_number,s.scn_pt,scn_number, script - script_start);
+			if (s.scn_number != -1) {
+				if (! ChangeScript(s.scn_number, 0)) return; // 読み込めない; abort.
+			}
+			script = script_start + s.scn_pt;
+			cmd.clear();
+		}
+	} else if (cmd.cmd1 == 2 && cmd.cmd2 == 1 && cmd.cmd3 == 12) { // DLL Call
+		const char* regname = config.GetParaStr("#REGNAME");
+		const char key_lb[] = "KEY\\LittleBusters";
+		if (strcmp(regname, key_lb) == 0) {
+			DllCall_LB(cmd, flag);
+			cmd.clear();
+		}
+	} else if (cmd.cmd1 == 0 && cmd.cmd2 == 0x04) { // メニューモード
+		if (cmd.cmd3 == 300 || cmd.cmd3 == 301 || cmd.cmd3 == 302) {
+			// メニューからのreturn
+			cmd.cmd2 = 1;
+			cmd.cmd3 = 0x0d;
+			SysExec(cmd);
+		}
+	} else if (cmd.cmd1 == 1 && cmd.cmd2 == 0x04) {
+		if (cmd.cmd3 == 0 && cmd.cmd4 == 0) { // タイトル名設定
+			const char* name = cmd.Str(cmd.args[0]);
+			if (name == 0) name = "";
+			window_title = name;
+			const char* config_name = config.GetParaStr("#CAPTION");
+			if (config_name == 0) config_name = "";
+			string setname = kconv(string(config_name) + "  " + window_title);
+			parent.Root().SetWindowCaption(setname.c_str());
+			cmd.clear();
+		} else if (cmd.cmd3 == 0x82 && cmd.cmd4 == 0) {
+			/* cmd.cmd3 == 0x82 : マウスの press 状態クリアかも */
+			event.presscount(MOUSE_LEFT);
+			event.presscount(MOUSE_RIGHT);
+			cmd.clear();
+		} else if (cmd.cmd3 == 0x85 && cmd.cmd4 == 0) {
+			int x,y,left,right;
+			event.MousePos(x,y);
+			if (event.presscount(MOUSE_LEFT)) left = 2;
+			else if (event.pressed(MOUSE_LEFT)) left = 1;
+			else left = 0;
+			
+			if (event.presscount(MOUSE_RIGHT)) right = 2;
+			else if (event.pressed(MOUSE_RIGHT)) right = 1;
+			else right = 0;
+			
+			// eprintf("mouse pos\n");
+			flag.Set(cmd.args[0], x);
+			flag.Set(cmd.args[1], y);
+			flag.Set(cmd.args[2], left);
+			flag.Set(cmd.args[3], right);
+			cmd.clear();
+		} else if (cmd.cmd3 == 0x15e || cmd.cmd3 == 0x161 || cmd.cmd3 == 0x162 || cmd.cmd3 == 0x14c || cmd.cmd3 == 0x7d1) {
+/* 15e, 161, 162, 14c, 7d1 : なんらかのシステム情報を返す(skip modeなど?) */
+/* 7d1: == 1 || 14c: == 1 || (15e==1&&161==1&&162==0) || (press_val == 2) : スキップ中? タイトル画面のアニメーション終了 */
+			flag.SetSys(0);
+			cmd.clear();
+		} else if (cmd.cmd3 == 0x4b0) { // 終了
+			System::Main::Quit();
+			script = 0; script_start = 0; script_end = 0;
+			cmd.clear();
+			cmd.cmd_type = CMD_WAITFRAMEUPDATE;
+		} else if (cmd.cmd3 == 0x4b4 || cmd.cmd3 == 0x4b5) { // 選択肢巻き戻し
+			LoadRollback(cmd);
+		} else if (cmd.cmd3 == 0x58d) {
+        		// 前にロード|セーブされた番号を返す。
+			flag.SetSys(-1);
+		} else if (cmd.cmd3 == 0x585) {
+        		// 第一引数の記録された日付、タイトルなどが返される
+        		// データがないなら sys に 0が、あるなら 1 が返る
+			int y,m,d,wd,h,min,s,ms;
+			string title;
+fprintf(stderr,"StatSave %d:",cmd.args[0].value+1);
+			if (StatSaveFile(cmd.args[0].value+1,y,m,d,wd,h,min,s,ms,title) == true) {
+				flag.Set(cmd.args[1], y);
+				flag.Set(cmd.args[2], m);
+				flag.Set(cmd.args[3], d);
+				flag.Set(cmd.args[4], wd);
+				flag.Set(cmd.args[5], h);
+				flag.Set(cmd.args[6], min);
+				flag.Set(cmd.args[7], s);
+				flag.Set(cmd.args[8], ms);
+				if (cmd.args[9].type == TYPE_VARSTR) {
+					flag.SetStr(cmd.args[9].number, kconv_rev(title));
+				}
+				flag.SetSys(1);
+			} else {
+				flag.SetSys(0);
+			}
+			cmd.clear();
+		} else if (cmd.cmd3 == 0xc23) { // save
+			Save(cmd);
+		} else if (cmd.cmd3 == 0xc25) { // load
+			Load(cmd);
+		} else if (cmd.cmd3 == 0x4b1 || cmd.cmd3 == 0x4b3) { // menu へ戻る (4b3: バッドエンド)
+			int scn_start;
+			if (config.GetParam("#SEEN_MENU", 1, &scn_start) == 0) {
+				ChangeScript(scn_start, 0);
+				save_scn = 0;
+				save_point = 0;
+				window_title = "";
+				const char* window_title_config = config.GetParaStr("#CAPTION");
+				if (window_title_config) window_title = window_title_config;
+				parent.Root().SetWindowCaption(kconv(window_title).c_str());
+				stack.clear();
+				cmd_stack.clear();
+				cmd_stack_str = cmd_stack_str_orig;
+				flag.Load("");
+				text_exec.Load("");
+				grp_exec.Load("");
+				SetSkipMode(SKIP_NO);
+			}
+		} else if (cmd.cmd3 == 0xcc) {
+			eprintf("show mouse cursor\n");
+			ShowCursor();
+			cmd.clear();
+		} else if (cmd.cmd3 == 0xcd) {
+			eprintf("hide mouse cursor\n");
+			HideCursor();
+			cmd.clear();
+		} else if (cmd.cmd3 == 0xcf) {
+			mouse_type = cmd.args[0].value;
+			eprintf("change mouse cursor : %d\n", mouse_type);
+			if (mouse_surface) ShowCursor();
+			cmd.clear();
+		}
+	}
+
+}
+
+#include<sys/types.h>
+#include<sys/stat.h>
+#include<errno.h>
+#include<unistd.h>
+
+// セーブファイルの名前をつくる
+string Scn2k::MakeSaveFile(void) const {
+	struct stat sstatus;
+	string dir = "~/.xkanon";
+
+	if (dir.c_str()[0] == '~' && dir.c_str()[1] == '/') {
+		char* home = getenv("HOME");
+		if (home != 0) {
+			string new_dir = string(home) + (dir.c_str()+1);
+			dir = new_dir;
+		}
+	}
+	// savepathにファイル名が入っていれば、それをセーブファイルとして使う
+	if (stat(dir.c_str(), &sstatus) == -1) {
+		if (errno != ENOENT) {
+			fprintf(stderr,"Cannot open save file; dir %s is not directory\n",dir.c_str());
+			return "";
+		}
+		if (mkdir(dir.c_str(), S_IRWXU) != 0 && errno != EEXIST) {
+			fprintf(stderr, "Cannot create directory %s ; Please create manually!!\n",dir.c_str());
+		}
+	} else {
+		if ( (sstatus.st_mode & S_IFMT) == S_IFREG) {
+			return dir;
+		}
+	}
+	// ファイル名を作る
+	const char* regname = config.GetParaStr("#REGNAME");
+
+	char* fname = new char[strlen(regname)+1];
+	/* レジストリ名をファイル名として有効なものにする */
+	int i; for (i=0; regname[i]!=0; i++) {
+		char c = regname[i];
+		if (c == '\\' || c == '/' || c == ':' || c <= 0x20) c = '_';
+		fname[i] = tolower(c);
+	}
+	fname[i] = 0;
+	dir += "/save.";
+	dir += fname;
+	return dir;
+}
+// セーブファイルの名前をつくる
+string Scn2kSaveTitle::operator() (int number) const {
+	int y,m,d,wd,h,min,sec,msec;
+	string title;
+	if (! impl.StatSaveFile(number, y,m,d,wd,h,min,sec,msec,title)) {
+		return "";
+	} else {
+		char buf[1024];
+		sprintf(buf, "%2d/%2d %2d:%2d ",m,d,h,min);
+		return string(buf) + title;
+	}
+};
+
+void Scn2k::SaveSys(void) {
+	char buf[1024];
+	string save;
+	string path = MakeSaveFile();
+	
+	sprintf(buf, "KEY=%s\n", config.GetParaStr("#REGNAME")); save += buf;
+	string save_config;
+	config.DiffOriginal(save_config);
+	save += "CONFIG=";
+	save += save_config;
+	save += "\n";
+	string save_flag; flag.SaveSys(save_flag);
+	save += save_flag;
+	string save_grp; grp_exec.SaveSys(save_grp);
+	save += save_grp;
+	map<int,set<int> >::iterator it;
+	save += "[TextRead]\n";
+	for (it=text_readflag.begin(); it != text_readflag.end(); it++) {
+		set<int>& read_flag = it->second;
+		set<int>::iterator jt;
+		char buf[1024];
+		sprintf(buf,"T<%05d>=",it->first);
+		string save_readflag = buf;
+		for (jt=read_flag.begin(); jt != read_flag.end(); jt++) {
+			sprintf(buf, "%d,", *jt);
+			save_readflag += buf;
+		}
+		save_readflag += "\n";
+		save += save_readflag;
+	}
+
+	path += ".0";
+	FILE* f = fopen(path.c_str(), "w");
+	if (f == 0) {
+		fprintf(stderr,"Cannot open save file %s\n",path.c_str());
+		return;
+	}
+	fwrite(save.c_str(), save.length(), 1, f);
+	fclose(f);
+	return;
+}
+
+void Scn2k::LoadSys(void) {
+	char buf[1024];
+	string path = MakeSaveFile();
+	path += ".0";
+	FILE* f = fopen(path.c_str(), "r");
+	if (f == 0) {
+		fprintf(stderr, "Cannot open save file %s\n",path.c_str());
+	} else {
+		fseek(f,0,2);
+		int sz = ftell(f);
+		fseek(f,0,0);
+		char* savedata = new char[sz+1];
+		fread(savedata, sz, 1, f);
+		savedata[sz] = 0;
+		fclose(f);
+
+		sprintf(buf, "KEY=%s\n", config.GetParaStr("#REGNAME"));
+		if (strncmp(savedata, buf, strlen(buf)) != 0) {
+			fprintf(stderr,"Invalid header in save file %s: it must be started with \"%s\"\n",buf);
+		} else  {
+			char* config_str = strstr(savedata, "\nCONFIG=");
+			if (config_str) {
+				config_str += strlen("\nCONFIG=");
+				char* strend = strchr(config_str, '\n');
+				if (strend) {
+					int l = strend - config_str;
+					char* config_copy = new char[l+1];
+					strncpy(config_copy, config_str, l);
+					config_copy[l] = 0;
+					config.PatchOriginal(config_copy);
+					delete[] config_copy;
+				}
+			}
+			flag.LoadSys(savedata);
+			grp_exec.LoadSys(savedata);
+			char* save = strstr(savedata, "\n[TextRead]\n");
+			if (save) {
+				save += strlen("\n[TextRead]\n");
+				do {
+					if (save[0] == '[') break; // next section
+					char* next_save = strchr(save, '\n');
+					if (next_save) {
+						*next_save++ = 0;
+					}
+					// T<XXXXX>=YYY,YYY,YYY,...
+					if (strncmp(save,"T<",2) == 0) {
+						int scn_num = atoi(save+2);
+						set<int>& read_flag = text_readflag[scn_num];
+						save += strlen("T<XXXXX>=");
+						while(save && *save) {
+							if (save[0] >= '0' && save[0] <= '9') {
+								int num = atoi(save);
+								read_flag.insert(num);
+							}
+							save = strchr(save, ',');
+							if (save) save++;
+						}
+					}
+					save = next_save;		
+				} while(save);
+			}
+
+		}
+		delete[] savedata;
+	}
+
+	/* 初期化 */
+	int scn_start; config.GetParam("#SEEN_START", 1, &scn_start);
+	ChangeScript(scn_start, 0);
+	save_scn = 0;
+	save_point = 0;
+	window_title = "";
+	const char* window_title_config = config.GetParaStr("#CAPTION");
+	if (window_title_config) window_title = window_title_config;
+	parent.Root().SetWindowCaption(kconv(window_title).c_str());
+	stack.clear();
+	cmd_stack.clear();
+	cmd_stack_str = cmd_stack_str_orig;
+
+	return;
+}
+
+bool Scn2k::StatSaveFile(int num, int& year, int& month, int& day, int& wday, int& hour,int& min, int& sec, int& msec, string& title) const {
+	char buf[1024];
+	string path = MakeSaveFile();
+	if (num <= 0 || num > 99) return false;
+	sprintf(buf,".%d",num);
+	path += buf;
+
+	struct stat sb;
+	if (stat(path.c_str(), &sb) == -1) return false;
+	struct tm* t = localtime(&sb.st_mtime);
+	month = t->tm_mon + 1;
+	day = t->tm_mday;
+	hour = t->tm_hour;
+	min = t->tm_min;
+	/* タイトルの取得 */
+	FILE* savefile = fopen(path.c_str(), "rb");
+	if (savefile == 0) return false;
+	char regname[1024];
+	sprintf(regname, "KEY=%s\n", config.GetParaStr("#REGNAME"));
+	fgets(buf,1000,savefile);
+	if (strncmp(regname, buf, strlen(regname)) != 0) {
+		fprintf(stderr,"invalid save file %s (registory name is not %s)\n",path.c_str(),regname);
+		fclose(savefile);
+		return false;
+	}
+	title="none";
+	while(!feof(savefile)) {
+		fgets(buf,1000,savefile);
+		if (strncmp(buf,"Title=",6) == 0) {
+			if (buf[strlen(buf)-2] == 0x0a) buf[strlen(buf)-2] = 0;
+			if (strlen(buf) > 20) buf[20] = 0, buf[21] = 0;
+			title = kconv(buf+6);
+			break;
+		}
+	}
+	fclose(savefile);
+	return true;
+}
+
+void Scn2k::SaveRollback(void) {
+fprintf(stderr,"Save rollback\n");
+	new_rollback_save = "";
+	string save_sys; SaveImpl(save_sys);
+	string save_flag; flag.Save(save_flag);
+	string save_text; text_exec.Save(save_text, true);
+	string save_grp; grp_exec.Save(save_grp);
+	new_rollback_save += save_sys;
+	new_rollback_save += save_flag;
+	new_rollback_save += save_text;
+	new_rollback_save += save_grp;
+}
+
+void Scn2k::LoadRollback(Cmd& cmd) {
+	if (rollback_save.empty()) return;
+	new_rollback_save = "";
+	string savedata = rollback_save.back();
+	rollback_save.pop_back();
+	LoadImpl(savedata.c_str());
+	flag.Load(savedata.c_str());
+	text_exec.Load(savedata.c_str());
+	grp_exec.Load(savedata.c_str());
+
+	/* 画面の回復など */
+	SetSkipMode(SKIP_NO);
+	vector<CmdSimplified>::iterator it;
+	cmd.clear();
+	for (it = cmd_stack.begin(); it != cmd_stack.end(); it++) {
+		cmd.read(*it);
+		cmd.cmd_type = CMD_OTHER;
+		flag.Exec(cmd);
+		text_exec.Exec(cmd);
+		grp_exec.Exec(cmd);
+	}
+	cmd.clear();
+	return;
+}
+
+void Scn2k::Save(Cmd& cmd) {
+	if (cmd.cmd_type == CMD_SAVEREQ) {
+		if (menu == 0) {
+			SetSkipMode(SKIP_IN_MENU); // テキストスキップ等はここで中断
+			menu = new Scn2kMenu(Scn2kMenu::MENU_SAVE, *this, flag, text_exec, system_version);
+			menu->InitPanel(event, parent);
+			menu->InitTitle(Scn2kSaveTitle(*this));
+			if (mouse_surface) menu_mouseshown = true;
+			else menu_mouseshown = false;
+			ShowCursor();
+			return;
+		}
+	}
+	char buf[1024];
+	string save;
+	FILE* f = 0;
+	if (save_scn == 0) {
+		fprintf(stderr,"Cannot decide save point\n");
+		return; // セーブ位置が保存されてない
+	}
+	string path = MakeSaveFile();
+	int file_number = 1;
+	if (cmd.args.size() == 1)
+		file_number = cmd.args[0].value + 1;
+	if (file_number <= 0) {
+		fprintf(stderr, "Cannot open save file %s\n",path.c_str());
+		return;
+	}
+	sprintf(buf, ".%d",file_number);
+	path += buf;
+
+	/* セーブファイル確認 */
+	
+	sprintf(buf, "KEY=%s\n", config.GetParaStr("#REGNAME")); save += buf;
+	string save_sys; SaveImpl(save_sys);
+	string save_flag; flag.Save(save_flag);
+	string save_text; text_exec.Save(save_text, false);
+	string save_grp; grp_exec.Save(save_grp);
+	save += save_sys;
+	save += save_flag;
+	save += save_text;
+	save += save_grp;
+	vector<string>::iterator it;
+	for (it=rollback_save.begin(); it != rollback_save.end(); it++) {
+		save += "[Rollback Data]\n";
+		save += *it;
+		save += "[Rollback End]\n";
+	}
+
+	f = fopen(path.c_str(), "w");
+	if (f == 0) {
+		fprintf(stderr,"Cannot open save file %s\n",path.c_str());
+		return;
+	}
+	fwrite(save.c_str(), save.length(), 1, f);
+	fclose(f);
+	cmd.clear();
+	return;
+}
+
+void Scn2k::Load(Cmd& cmd) {
+	if (cmd.cmd_type == CMD_LOADREQ) {
+		if (menu == 0) {
+			menu = new Scn2kMenu(Scn2kMenu::MENU_LOAD, *this, flag, text_exec, system_version);
+			menu->InitPanel(event, parent);
+			menu->InitTitle(Scn2kSaveTitle(*this));
+			SetSkipMode(SKIP_IN_MENU); // テキストスキップ等はここで中断
+			if (mouse_surface) menu_mouseshown = true;
+			else menu_mouseshown = false;
+			ShowCursor();
+			return;
+		}
+	}
+	char buf[1024];
+	string path = MakeSaveFile();
+	int file_number = 1;
+	if (cmd.args.size() == 1)
+		file_number = cmd.args[0].value + 1;
+	sprintf(buf, ".%d",file_number);
+	path += buf;
+	FILE* f = 0;
+	if (file_number > 0) f = fopen(path.c_str(), "r");
+	if (f == 0) {
+		fprintf(stderr, "Cannot open save file %s\n",path.c_str());
+		return;
+	}
+	
+	fseek(f,0,2);
+	int sz = ftell(f);
+	fseek(f,0,0);
+	char* savedata = new char[sz+1];
+	fread(savedata, sz, 1, f);
+	savedata[sz] = 0;
+	fclose(f);
+
+	sprintf(buf, "KEY=%s\n", config.GetParaStr("#REGNAME"));
+	if (strncmp(savedata, buf, strlen(buf)) != 0) {
+		fprintf(stderr,"Invalid header in save file %s: it must be started with \"%s\"\n",buf);
+		delete[] savedata;
+		return;
+	}
+	LoadImpl(savedata);
+	flag.Load(savedata);
+	text_exec.Load(savedata);
+	grp_exec.Load(savedata);
+	rollback_save.clear();
+	new_rollback_save = "";
+	char* rollback_data = savedata;
+	while( (rollback_data = strstr(rollback_data,"[Rollback Data]\n")) != 0) {
+		rollback_data += strlen("[Rollback Data]\n");
+		char* rollback_end = strstr(rollback_data, "[Rollback End]\n");
+		if (rollback_end == 0) rollback_end = rollback_data + strlen(rollback_data);
+		string s(rollback_data, rollback_end);
+		rollback_save.push_back(s);
+		rollback_data = rollback_end;
+	}
+
+	/* 画面の回復など */
+	SetSkipMode(SKIP_NO);
+	vector<CmdSimplified>::iterator it;
+	for (it = cmd_stack.begin(); it != cmd_stack.end(); it++) {
+		cmd.read(*it);
+		cmd.cmd_type = CMD_OTHER;
+		flag.Exec(cmd);
+		text_exec.Exec(cmd);
+		grp_exec.Exec(cmd);
+	}
+	cmd.clear();
+	return;
+}
+
+void Scn2k::SaveImpl(string& save) {
+	char buf[1024];
+
+	/* save point */
+	sprintf(buf, "\n[SCENARIO]\nScn=%d\nPoint=%d\n",save_scn, save_point); save += buf;
+	sprintf(buf, "Title=%s\nMouseType=%d\nMouseShown=1\n",window_title.c_str(), mouse_type); save += buf;
+	vector<StackItem>::iterator sit;
+	for (sit=stack.begin(); sit!=stack.end(); sit++) {
+		if (sit->scn_number == SCN_INFO && sit->scn_pt == SCN_INFO_MENU) break; // メニューに入る直前までのスタックを保存
+		sprintf(buf, "Stack=%d,%d\n",sit->scn_number,sit->scn_pt);
+		save += buf;
+	}
+	vector<string>::reverse_iterator ssit;
+	for (ssit=stack_strbuffer.rbegin(); ssit != stack_strbuffer.rend(); ssit++) {
+		sprintf(buf, "StackStr=%s\n",ssit->c_str());
+		save += buf;
+	}
+	vector<CmdSimplified>::iterator cit;
+	for (cit=cmd_stack.begin(); cit != cmd_stack.end(); cit++) {
+		if (cit->type == CMD_SAVECMDGRP || cit->type == CMD_SAVECMDGRP_ONCE || cit->type == CMD_SAVECMDGRP_START) {
+			save += "CmdG=";
+		} else {
+			save += "Cmd=";
+		}
+		string s; cit->Save(s);
+		save += s;
+		save += "\n";
+	}
+}
+
+void Scn2k::LoadImpl(const char* save) {
+	char buf[1024];
+	save_scn = 0;
+	save_point = 0;
+	window_title = "";
+	stack.clear();
+	cmd_stack.clear();
+	cmd_stack_str = cmd_stack_str_orig;
+
+	save = strstr(save, "\n[SCENARIO]\n");
+	if (save == 0) return;
+	save += strlen("\n[SCENARIO]\n");
+	while(save[0] != 0 && save[0] != '[') { // while next section start
+		if (strncmp(save, "Scn=", 4) == 0) {
+			sscanf(save, "Scn=%d", &save_scn);
+		} else if (strncmp(save, "Point=", 6) == 0) {
+			sscanf(save, "Point=%d", &save_point);
+		} else if (strncmp(save, "Title=", 6) == 0) {
+			save += 6;
+			char* s = strchr(save, '\n');
+			if (s == 0) window_title = save;
+			else window_title.assign(save, s-save);
+			const char* config_name = config.GetParaStr("#CAPTION");
+			if (config_name == 0) config_name = "";
+			string setname = kconv(string(config_name)+"  "+window_title);
+			parent.Root().SetWindowCaption(setname.c_str());
+		} else if (strncmp(save, "MouseType=", 10) == 0) {
+			sscanf(save, "MouseType=%d", &mouse_type);
+		} else if (strncmp(save, "MouseShown=", 11) == 0) {
+			int v;
+			sscanf(save, "MouseShown=%d", &v);
+			if (v) ShowCursor();
+			else HideCursor();
+		} else if (strncmp(save, "Stack=", 6) == 0) {
+			int scn, pt;
+			sscanf(save, "Stack=%d,%d", &scn, &pt);
+			stack.push_back( StackItem(scn, pt));
+		} else if (strncmp(save, "StackStr=", 9) == 0) {
+			save += 9;
+			char* s = strchr(save, '\n');
+			if (s == 0) stack_strbuffer.push_back("");
+			else stack_strbuffer.push_back(string(save, s-save));
+		} else if (strncmp(save, "Cmd=", 4) == 0) {
+			CmdSimplified cmd;
+			cmd.Load(save+4, cmd_stack_str);
+			cmd_stack.push_back(cmd);
+		} else if (strncmp(save, "CmdG=", 5) == 0) {
+			CmdSimplified cmd;
+			cmd.Load(save+5, cmd_stack_str);
+			cmd.type = CMD_SAVECMDGRP;
+			cmd_stack.push_back(cmd);
+		}
+		save = strchr(save, '\n');
+		if (save != 0) save++;
+	}
+	ChangeScript(save_scn, 0);
+	script = script_start + save_point;
+	return;
+}
+void Scn2k::SetSkipMode(SkipMode mode) {
+	if (skip_mode != mode) {
+		skip_mode = mode;
+		text_exec.SetSkipMode(mode);
+		grp_exec.SetSkipMode(mode);
+	}
+}
+
+/***********************************************************
+**
+**	DLL Call Implementation
+**
+**/
+static double* lb_ef_param = 0;
+void DLLCall_LB_EF00_0(Cmd& cmd, Flags& flags) { // エフェクトの設定
+	if (lb_ef_param == 0) {
+		lb_ef_param = new double[sizeof(double) * 0x60 * 8];
+	}
+	int i,j;
+	int param_top, param_size;
+	if (cmd.args[2].value == 1) {
+		param_top = 0;
+		param_size = 0x20;
+	} else {
+		param_top = cmd.args[3].value;
+		param_size = cmd.args[4].value;
+		if (param_top < 0) param_top = 0;
+		if (param_top > 0x20) param_top = 0x20;
+		if (param_size+param_top > 0x20) param_size = 0x20 - param_top;
+	}
+	for (i=0; i<8; i++) {
+		double* param = lb_ef_param + i*0x60 + param_top*3;
+		for (j=0; j<param_size; j++) {	
+			*param++ = random() % 800 - 400;
+			*param++ = random() % 600 - 300;
+			*param++ = random() % 700 - 350;
+		}
+	}
+	if (cmd.args[5].value != 1) return;
+static int random_dirtable[] = {
+		0, 2, 1, 3, 0, 2, 1, 3,
+		1, 3, 2, 0, 1, 3, 2, 0,
+		0, 0, 0, 0, 3, 1, 2, 0,
+		3, 1, 3, 1, 0, 2, 3, 1
+	};
+	int* dir = &random_dirtable[(random()&3) * 8];
+	for (i=0; i<8; i++) {
+		double* param = lb_ef_param + i*0x60;
+		double x = random()%600 - 300;
+		double y = random()%480-240;
+		if (x < 0) x -= 80;
+		else x += 80;
+		if (y < 0) y -= 80;
+		else y += 80;
+		switch(*dir++) {
+		case 0:
+			if (x < 0) x = -x;
+			if (y < 0) y = -y;
+			break;
+		case 1:
+			if (x > 0) x = -x;
+			if (y < 0) y = -y;
+			break;
+		case 2:
+			if (x < 0) x = -x;
+			if (y > 0) y = -y;
+			break;
+		case 4:
+			if (x > 0) x = -x;
+			if (y > 0) y = -y;
+			break;
+		}
+		param[9] = x*1.2;
+		param[10] = y*1.2;
+		param[11] *= 1.2;
+		param[12] *= -0.08;
+		param[13] *= -0.08;
+		param[14] *= -0.08;
+		param[15] = -param[9];
+		param[16] = -param[10];
+		param[17] = -param[11];
+	}
+	return;
+}
+void DLLCall_LB_EF00_1(Cmd& cmd, Flags& flags) { // 計算を行う
+	if (lb_ef_param == 0) {
+		fprintf(stderr,"Warning : DLLCall_LB_EF00_1 : Script error : effect calculation was called before setting\n");
+		return;
+	}
+	int index = cmd.args[2].value;
+	int v5_1154 = flags.Get(5, 1154+index);
+	int j = ((v5_1154) & 0x1f) + index * 0x20;
+	int k = ((v5_1154+1) & 0x1f) + index * 0x20;
+	int l = ((v5_1154+2) & 0x1f) + index * 0x20;
+	int m = ((v5_1154+3) & 0x1f) + index * 0x20;
+	j *= 3;
+	k *= 3;
+	l *= 3;
+	m *= 3;
+
+	// 0 < x < 1
+	// va - vd は 0-1 の範囲で対称性を持つ3次関数
+	double x = double(flags.Get(5, 1162 + index)) * 0.001;
+	double va = (x * x * x)/6;
+	double vb = (-x*x*x + 3*x*x - 3*x + 1) / 6;
+	double vc = (3*x*x*x - 6*x*x + 4) / 6;
+	double vd = (-3*x*x*x+3*x*x+3*x+1) / 6;
+
+	double r1 = va * lb_ef_param[m+3] + vd * lb_ef_param[l+3] + vc * lb_ef_param[k+3] + vb * lb_ef_param[j+3];
+	double r2 = va * lb_ef_param[m+2] + vd * lb_ef_param[l+2] + vc * lb_ef_param[k+2] + vb * lb_ef_param[j+2];
+	double r3 = va * lb_ef_param[m+1] + vd * lb_ef_param[l+1] + vc * lb_ef_param[k+1] + vb * lb_ef_param[j+1];
+	if (r1 != 400) {
+		r2 = r2 * 800 / (400-r1);
+		r3 = r3 * 700 / (400-r1);
+	}
+	VarInfo var;
+	var.type = 5;
+	var.number = 1151;
+	flags.Set(var, int(r2));
+	var.number = 1152;
+	flags.Set(var, int(r3));
+	var.number = 1153;
+	flags.Set(var, int(r1));
+	return;
+}
+
+
+void DllCall_LB(Cmd& cmd, Flags& flags) {	// リトルバスターズ!の EF00.dll をエミュレート
+	if (cmd.args[0].value == 1) {
+		// "EF00.dll"
+		if (cmd.args[1].value == 0) { // エフェクトの設定
+			DLLCall_LB_EF00_0(cmd, flags);
+		} else if (cmd.args[1].value == 1) { // 計算を行う
+			DLLCall_LB_EF00_1(cmd, flags);
+		}
+	} else {
+		fprintf(stderr,"Unsupported DLL call for DLL<%d>\n",cmd.args[0].value);
+	}
+	return;
+}
+
+/**********************************************************
+**
+**	MenuImpl
+**
+*/
+
+#include"window/widget.h"
+#include"window/menuitem.h"
+
+void DSurfaceFill(Surface* src, const Rect& rect, int r, int g, int b, int a = 0xff);
+
+struct Scn2kMenuImpl {
+	Scn2kMenu& interface;
+	MenuItem* menu;
+	Event::Container* pevent;
+	PicContainer* pparent;
+
+	virtual void InitPanel(Event::Container& event, PicContainer& parent) = 0;
+	virtual void InitTitle(const SaveTitle&) = 0;
+	virtual void Cancel(void) = 0;
+	virtual void Exec(Cmd& cmd) = 0;
+	Scn2kMenuImpl(Scn2kMenu& _interface) : interface(_interface) {
+		menu = 0;
+		pevent = 0;
+		pparent = 0;
+	}
+	virtual ~Scn2kMenuImpl() {
+		if (menu) delete menu;
+		menu = 0;
+	}
+};
+
+struct LoadMenu : Scn2kMenuImpl {
+	vector<string> title;
+	vector<int> title_valid;
+	RadioButton* btn_local;
+	RadioButton* btn_page;
+	RadioButton* btn_set;
+	Scale* btn_scale;
+	Dialog* awk_dialog;
+	int btn_page_val, btn_set_val, btn_local_val, select_page, select_value;
+	LoadMenu(Scn2kMenu& _interface);
+	~LoadMenu();
+	void InitPanel(Event::Container& event, PicContainer& parent);
+	void InitTitle(const SaveTitle&);
+	void Cancel(void);
+	void Exec(Cmd& cmd);
+	static void ChangeBtnPage(void* pointer, MenuItem* widget);
+	static void ChangeBtnLocal(void* pointer, MenuItem* widget);
+	static void ChangeBtnScale(void* pointer, Scale* widget);
+	static void ChangeBtnSet(void* pointer, MenuItem* widget);
+	static void ChangeDialog(void* pointer, Dialog* widget);
+	bool in_setpage;
+	void SetPage(int new_page);
+	void SetValue(int new_value);
+	void PressOk(void);
+};
+LoadMenu::LoadMenu(Scn2kMenu& _interface) : Scn2kMenuImpl(_interface) {
+	btn_local = 0;
+	btn_scale = 0;
+	btn_set = 0;
+	btn_page_val = 0;
+	btn_set_val = -1;
+	btn_local_val = -1;
+	awk_dialog = 0;
+	in_setpage = false;
+	select_page = 0;
+	select_value = -1;
+}
+LoadMenu::~LoadMenu() {
+	if (awk_dialog) delete awk_dialog;
+}
+void LoadMenu::InitPanel(Event::Container& event, PicContainer& parent) {
+	pevent = &event;
+	pparent = &parent;
+
+	if (menu) delete menu;
+	menu = 0;
+	menu = new MenuItem(&parent, Rect(80,30,560, 450), 1, 3, 0);
+	Surface* surface = parent.Root().NewSurface(menu->Pic()->Width(), menu->Pic()->Height(), ALPHA_MASK);
+	if (interface.type == Scn2kMenu::MENU_LOAD) {
+		menu->SetLabelTop(new Label(menu->PicNode(), Rect(0,0), true, "Load", 26), Rect(0,0,10,0), Rect(0,0,0,20));
+		DSurfaceFill(surface, Rect(*surface), 0, 0, 0x80, 0x80);
+	} else {
+		menu->SetLabelTop(new Label(menu->PicNode(), Rect(0,0), true, "Save", 26), Rect(0,0,10,0), Rect(0,0,0,20));
+		DSurfaceFill(surface, Rect(*surface), 0, 0x80, 0, 0x80);
+	}
+	menu->Pic()->SetSurface(surface, 0, 0);
+	menu->Pic()->SetSurfaceFreeFlag();
+
+	btn_page = new RadioButton(event, menu->PicNode(), Rect(0, 0, 480, 40), 10, 1, &btn_page_val,
+		Rect(0,0,0,0), 18, Color(0,0,0),Color(0xff,0,0),Color(0xff,0x80,0));
+	btn_page->set_func = &ChangeBtnPage;
+	btn_page->set_pointer = this;
+	btn_page->SetLabelLeft(new Label(btn_page->PicNode(), Rect(0,0), true, "Page", 18), Rect(0, 0, 180, 0), Rect(0,0));
+	btn_page->Add(" 1 ");
+	btn_page->Add(" 2 ");
+	btn_page->Add(" 3 ");
+	btn_page->Add(" 4 ");
+	btn_page->Add(" 5 ");
+	btn_page->Add(" 6 ");
+	btn_page->Add(" 7 ");
+	btn_page->Add(" 8 ");
+	btn_page->Add(" 9 ");
+	btn_page->Add(" 10 ");
+	btn_page->pack();
+/*
+	surface = parent.Root().NewSurface(btn_page->Pic()->Width(), btn_page->Pic()->Height(), ALPHA_MASK);
+	DSurfaceFill(surface, Rect(*surface), 0xff, 0, 0, 0x80);
+	btn_page->Pic()->SetSurface(surface, 0, 0);
+	btn_page->Pic()->SetSurfaceFreeFlag();
+*/
+	menu->item[0] = btn_page;
+	btn_set = new RadioButton(event, menu->PicNode(), Rect(0, 0, 480, 40), 2, 1, &btn_set_val,
+		Rect(0,0,0,0), 18, Color(0,0,0),Color(0xff,0,0),Color(0xff,0x80,0));
+	btn_set->set_func = &ChangeBtnSet;
+	btn_set->set_pointer = this;
+	btn_set->SetLabelLeft(new Label(btn_set->PicNode(), Rect(0,0)), Rect(0,0,200,0), Rect(0,0));
+	if (interface.type == Scn2kMenu::MENU_LOAD) {
+		btn_set->Add(" Load ");
+	} else {
+		btn_set->Add(" Save ");
+	}
+	btn_set->Add(" Cancel ");
+	btn_set->pack();
+/*
+	surface = parent.Root().NewSurface(btn_set->Pic()->Width(), btn_set->Pic()->Height(), ALPHA_MASK);
+	DSurfaceFill(surface, Rect(*surface), 0, 0, 0xff, 0x80);
+	btn_set->Pic()->SetSurface(surface, 0, 0);
+	btn_set->Pic()->SetSurfaceFreeFlag();
+*/
+	menu->item[2] = btn_set;
+	// void btn_set_press(void* pointer, MenuItem* widget);
+	// btn_set->set_func = btn_set_press;
+	// btn_set->set_pointer = this;
+	btn_local = new RadioButton(*pevent, menu->PicNode(), Rect(0, 0, 480, 300), 1, 100, &btn_local_val,
+		Rect(0,0,300,30), 18, Color(0,0,0),Color(0xff,0,0),Color(0xff,0x80,0));
+	btn_local->set_func = &ChangeBtnLocal;
+	btn_local->set_pointer = this;
+/*
+	surface = pparent->Root().NewSurface(btn_local->Pic()->Width(), btn_local->Pic()->Height(), ALPHA_MASK);
+	DSurfaceFill(surface, Rect(*surface), 0, 0xff, 0, 0x80);
+	btn_local->Pic()->SetSurface(surface, 0, 0);
+	btn_local->Pic()->SetSurfaceFreeFlag();
+*/
+	menu->item[1] = btn_local;
+	int i;
+	for (i=0; i<12; i++)
+		btn_local->Add("",false);
+	btn_local->pack();
+	btn_local->show_all();
+	menu->pack();
+
+	PicBase* local_pic = btn_local->Pic();
+	int local_x2 = local_pic->PosX() + local_pic->Width();
+	int local_y2 = local_pic->PosY() + local_pic->Height();
+	btn_scale = new Scale(*pevent, menu->PicNode(), Rect(local_x2-16, local_pic->PosY(), local_x2, local_y2), Color(0xff, 0x80, 0), true);
+	btn_scale->SetRange(0, 900);
+	btn_scale->InitCursor(1024/10);
+	btn_scale->SetValue(0);
+	btn_scale->change_func = &ChangeBtnScale;
+	btn_scale->change_pointer = this;
+
+	menu->PicNode()->show_all();
+}
+
+void LoadMenu::InitTitle(const SaveTitle& title_op) {
+	title.clear();
+	int i;
+	for (i=1; i<=100; i++) {
+		char buf[100];
+		sprintf(buf,"%2d:",i);
+		string t = title_op(i);
+		string s = string(buf) + t;
+		if (t.length() == 0) {
+			string s = string(buf) + "--------";
+			title_valid.push_back(0);
+		} else {
+			title_valid.push_back(1);
+		}
+		title.push_back(s);
+	}
+	if (btn_local==0) return;
+	for (i=0; i<10; i++) {
+		TextButton* button = dynamic_cast<TextButton*>(btn_local->item[i]);
+		if (button) button->SetText(title[i].c_str());
+	}
+}
+
+void LoadMenu::SetPage(int new_page) {
+	if (new_page < 0) new_page = 0;
+	if (new_page > 900) new_page = 900;
+	if (select_page == new_page) return;
+	if (in_setpage) return;
+	in_setpage = true;
+	
+	int prev_page = select_page / 10;
+	int cur_page = new_page / 10;
+	int prev_point = select_page%10;
+	int new_point = new_page%10;
+	select_page = new_page;
+	if (prev_page != cur_page) {
+		int i;
+		for (i=0; i<12; i++) {
+			TextButton* button = dynamic_cast<TextButton*>(btn_local->item[i]);
+			if (button) {
+				if (cur_page+i < title.size()) button->SetText(title[cur_page+i].c_str());
+				else button->SetText("----");
+			}
+		}
+		// ボタンの内容を変更する
+		if (select_value < cur_page || select_value > cur_page+12)
+			btn_local->SetValue(-1);
+		else
+			btn_local->SetValue(select_value - cur_page);
+	}
+	if (prev_point != new_point) {
+		int i;
+		for (i=0; i<12; i++) {
+			int old_x = btn_local->item[i]->Pic()->PosX();
+			btn_local->item[i]->Pic()->Move(old_x, i*30-new_point*3);
+		}
+	}
+	if (btn_page) {
+		if (select_page%100 == 0) btn_page->SetValue(select_page/100);
+		else btn_page->SetValue(-1);
+	}
+	if (btn_scale) {
+		btn_scale->SetValue(select_page);
+	}
+	in_setpage = false;
+	return;
+}
+void LoadMenu::SetValue(int new_value) {
+	if (in_setpage) return;
+	in_setpage = true;
+
+	if (new_value < 0 || new_value > title.size() ||
+	    (interface.type == Scn2kMenu::MENU_LOAD && title_valid[new_value] == 0) ) { // 無効な選択肢
+		if (select_value < select_page/10 || select_value > select_page/10+12)
+			btn_local->SetValue(-1);
+		else
+			btn_local->SetValue(select_value-select_page/10);
+	} else { // 選択肢を変更する
+		if (select_value == new_value) {
+			PressOk(); // ダブルクリック
+		} else {
+			select_value = new_value;
+			if (interface.type == Scn2kMenu::MENU_SAVE && title_valid[select_value] == 0) {
+				PressOk(); // 新しいセーブデータなら無条件に選択
+			}
+		}
+	}
+
+	in_setpage = false;
+	return;
+}
+void LoadMenu::PressOk(void) {
+	if (select_value == -1) {
+		btn_set->SetValue(-1); // なにもしない
+		return;
+	}
+	menu->deactivate();
+	if (interface.type == Scn2kMenu::MENU_LOAD) {
+		interface.cmd.cmd_type = CMD_LOAD;
+		interface.cmd.args.push_back(VarInfo(select_value));
+		awk_dialog = new Dialog(*pevent, pparent, "ファイルをロードしますか?", true);
+		awk_dialog->set_pointer = this;
+		awk_dialog->set_func = ChangeDialog;
+	} else {// MENU_SAVE
+		interface.cmd.cmd_type = CMD_SAVE;
+		interface.cmd.args.push_back(VarInfo(select_value));
+		if (title_valid[select_value] == 0) { // 新しいセーブデータ
+			interface.status = Scn2kMenu::MenuStatus(Scn2kMenu::MENU_CMD | Scn2kMenu::MENU_DELETE);
+		} else { // セーブデータを上書き:確認
+			awk_dialog = new Dialog(*pevent, pparent, "データを上書きしますか?", true);
+			awk_dialog->set_pointer = this;
+			awk_dialog->set_func = ChangeDialog;
+		}
+	}
+}
+void LoadMenu::Cancel(void) {
+	if (awk_dialog) { // ダイアログのキャンセル
+		awk_dialog->status = Dialog::CANCEL;
+		ChangeDialog(this, awk_dialog);
+	} else { // 一般キャンセル
+		btn_set->SetValue(1);
+	}
+}
+void LoadMenu::Exec(Cmd& cmd) {
+}
+void LoadMenu::ChangeBtnPage(void* pointer, MenuItem* widget) {
+	LoadMenu* instance = (LoadMenu*)pointer;
+	if (instance->btn_page_val == -1) return;
+	instance->SetPage(instance->btn_page_val*100);
+}
+void LoadMenu::ChangeBtnScale(void* pointer, Scale* from) {
+	LoadMenu* instance = (LoadMenu*)pointer;
+	int value = from->GetValue();
+	instance->SetPage(value);
+}
+void LoadMenu::ChangeBtnSet(void* pointer, MenuItem* widget) {
+	LoadMenu* instance = (LoadMenu*)pointer;
+	if (instance->btn_set_val == 1) { // cancel
+		instance->interface.status = Scn2kMenu::MENU_DELETE;
+		return;
+	} else if (instance->btn_set_val == 0) { // OK
+		instance->PressOk();
+	}
+}
+void LoadMenu::ChangeDialog(void* pointer, Dialog* widget) {
+	LoadMenu* instance = (LoadMenu*)pointer;
+	if (widget->status == Dialog::CANCEL) {
+		// ダイアログ消去、OK ボタン復帰
+		delete instance->awk_dialog;
+		instance->awk_dialog = 0;
+		instance->menu->activate();
+		instance->btn_set->SetValue(-1);
+		return;
+	} else if (widget->status == Dialog::OK) {
+		instance->interface.status = Scn2kMenu::MenuStatus(Scn2kMenu::MENU_CMD | Scn2kMenu::MENU_DELETE);
+		return;
+	}
+}
+void LoadMenu::ChangeBtnLocal(void* pointer, MenuItem* widget) {
+	LoadMenu* instance = (LoadMenu*)pointer;
+	if (instance->btn_local_val == -1) return;
+	instance->SetValue( (instance->select_page/10) + instance->btn_local_val);
+}
+
+struct BacklogMenu : Scn2kMenuImpl {
+	Scn2k& scn_impl;
+	Text& text_exec;
+	bool backlog_update;
+	int backlog_cnt;
+	BacklogMenu(Scn2kMenu& _interface, Scn2k& scn_impl, Text& text_exec);
+	~BacklogMenu();
+	void InitPanel(Event::Container& event, PicContainer& parent);
+	void InitTitle(const SaveTitle&);
+	void Cancel(void);
+	void Exec(Cmd& cmd);
+};
+BacklogMenu::BacklogMenu(Scn2kMenu& _interface, Scn2k& _scn, Text& parent_text_exec) : Scn2kMenuImpl(_interface), scn_impl(_scn), text_exec(parent_text_exec) {
+	backlog_cnt = -1;
+	backlog_update = false;
+}
+BacklogMenu::~BacklogMenu() {
+}
+void BacklogMenu::InitPanel(Event::Container& event, PicContainer& parent) {
+	pevent = &event;
+}
+
+void BacklogMenu::InitTitle(const SaveTitle& title_op) {
+}
+void BacklogMenu::Cancel(void) {
+	interface.status = Scn2kMenu::MenuStatus(Scn2kMenu::MENU_DELETE);
+}
+void BacklogMenu::Exec(Cmd& cmd) {
+	int command_direction = 0; // forward
+	if (cmd.cmd_type == CMD_NOP) text_exec.Wait(0xffffffffUL, cmd);
+	if (cmd.cmd_type == CMD_BACKLOGREQ || pevent->presscount(MOUSE_UP)) {
+		if (cmd.cmd_type == CMD_BACKLOGREQ) cmd.clear();
+		backlog_cnt++;
+		backlog_update = false;
+		command_direction = 1;
+	}
+	if (cmd.cmd_type == CMD_BACKLOGREQ_FWD || pevent->presscount(MOUSE_DOWN)) {
+		if (cmd.cmd_type == CMD_BACKLOGREQ_FWD) cmd.clear();
+		backlog_cnt--;
+		backlog_update = false;
+		if (backlog_cnt == -2 || (
+		   (backlog_cnt == -1 && text_exec.backlog_item.scn == -1 && text_exec.backlog_item.pos == -1)) ){
+			Cancel();
+			return;
+		}
+		command_direction = -1;
+	}
+	if (cmd.cmd_type != CMD_NOP) return;
+	if (backlog_update) return;
+	// backlog を最新の状態に更新
+	cmd.clear();
+	BacklogItem item;
+
+retry:
+	if (backlog_cnt < -1) backlog_cnt = -1;
+	if (backlog_cnt >= int(text_exec.backlog.size())) backlog_cnt = text_exec.backlog.size() - 1;
+
+	if (backlog_cnt == -1) {
+		if (text_exec.backlog_item.scn == -1 && text_exec.backlog_item.pos == -1) {
+			if (text_exec.backlog.size() == 0 || command_direction < 0) {
+				Cancel();
+				return;
+			}
+			item = text_exec.backlog.back();
+			backlog_cnt = 0;
+		} else {
+			// item = text_exec.backlog.back();
+			item = text_exec.backlog_item;
+		}
+	} else {
+		item = text_exec.backlog[text_exec.backlog.size()-1-backlog_cnt];
+	}
+	if (item.scn ==  BacklogItem::SaveSelect) { // select marker ; skip this item
+		if (command_direction == 0) command_direction = 1;
+		backlog_cnt += command_direction;
+		goto retry;
+	}
+	if (item.scn == 0 && item.pos == -1) ; // not read cmd
+	else {
+		scn_impl.ReadCmdAt(cmd, item.scn, item.pos);
+	}
+	text_exec.DrawBacklog(item, cmd);
+	cmd.clear();
+	backlog_update = true;
+}
+
+/*******************************************************************************
+**
+**
+*/
+
+Scn2kMenu::Scn2kMenu(MenuType _type, Scn2k& scn_impl, const Flags& flags, Text& text_exec, int system_version) :
+	cmd(flags, system_version), type(_type) {
+	pimpl = 0;
+	status = MENU_CONTINUE;
+	switch(type) {
+	case MENU_LOAD: pimpl = new LoadMenu(*this); break;
+	case MENU_SAVE: pimpl = new LoadMenu(*this); break;
+	case MENU_BACKLOG: pimpl = new BacklogMenu(*this, scn_impl, text_exec); break;
+	}
+	return;
+}
+Scn2kMenu::~Scn2kMenu() {
+	if (pimpl) delete pimpl;
+	pimpl = 0;
+}
+void Scn2kMenu::InitPanel(Event::Container& event, PicContainer& parent) {
+	if (pimpl) pimpl->InitPanel(event, parent);
+}
+void Scn2kMenu::InitTitle(const SaveTitle& t) {
+	if (pimpl) pimpl->InitTitle(t);
+}
+void Scn2kMenu::Cancel(void) {
+	if (pimpl) pimpl->Cancel();
+}
+void Scn2kMenu::Exec(Cmd& ret_cmd) {
+	if (pimpl == 0) return;
+	pimpl->Exec(ret_cmd);
+	if (pimpl->pevent->presscount(MOUSE_RIGHT)) {
+		Cancel();
+	}
+	if (status & MENU_CMD && cmd.cmd_type != CMD_NOP) {
+		status = Scn2kMenu::MenuStatus(status & (~Scn2kMenu::MENU_CMD) );
+		CmdSimplified tmp_cmd;
+		char cmd_str[32768];
+		char* tmp_cmd_str = cmd_str;
+		cmd.write(tmp_cmd, tmp_cmd_str);
+		ret_cmd.read(tmp_cmd);
+	}
+}
+void Scn2kMenu::activate(void) {
+	if (pimpl && pimpl->menu) pimpl->menu->activate();
+}
+void Scn2kMenu::deactivate(void) {
+	if (pimpl && pimpl->menu) pimpl->menu->deactivate();
+}
+
new file mode 100644
--- /dev/null
+++ b/scn2k/scn2k_impl.h
@@ -0,0 +1,118 @@
+#ifndef __SCN2k_IMPL_H__
+#define __SCN2k_IMPL_H__
+
+#include"scn2k.h"
+#include"window/widget.h"
+#include"window/event.h"
+#include<vector>
+#include<string>
+#include<map>
+#include<set>
+
+struct StackItem {
+	int scn_number;
+	int scn_pt;
+	StackItem(int number, int pt) : scn_number(number), scn_pt(pt) {}
+};
+
+struct SaveTitle {
+	virtual std::string operator()(int number) const = 0;
+};
+
+struct Scn2kMenu {
+	Cmd cmd;
+	class Scn2kMenuImpl* pimpl;
+	enum MenuType { MENU_LOAD, MENU_SAVE, MENU_CONFIG, MENU_BACKLOG, MENU_BACKLOG2};
+	MenuType type;
+	enum MenuStatus { MENU_CONTINUE=0, MENU_CMD=1, MENU_DELETE=2};
+	MenuStatus status;
+	void InitPanel(Event::Container& event, PicContainer& parent);
+	void InitTitle(const SaveTitle&);
+	void Cancel(void);
+	void Exec(Cmd& cmd);
+	void activate(void);
+	void deactivate(void);
+	Scn2kMenu(MenuType type, class Scn2k& scn_impl, const Flags& flags, Text& text, int system_version);
+	~Scn2kMenu();
+};
+
+struct Scn2kSaveTitle : SaveTitle {
+	const class Scn2k& impl;
+	std::string operator() (int number) const;
+	Scn2kSaveTitle(const Scn2k& _impl) : impl(_impl) {}
+};
+
+class Scn2k : Event::Time {
+	Event::Container& event;
+	PicContainer& parent;
+	AyuSysConfig& config;
+	WidMouseCursor* mcursor;
+	Flags flag;
+	Text text_exec;
+	Grp grp_exec;
+	int system_version;
+	SkipMode skip_mode;
+	int scn_number;
+	int scn_point;
+	enum {SCN_INFO=999999, SCN_INFO_MENU=10000001, SCN_INFO_LOCALS = 10000100, SCN_INFO_LOCALSTR = 10000200, SCN_INFO_RETSTR = 10000300}; // stack に積まれる特殊な番号
+
+	int save_scn, save_point;
+
+	char* script_start;
+	char* script_end;
+	const char* script;
+
+	int backlog_script_scn;
+	char* backlog_script_start;
+	char* backlog_script_end;
+
+	std::string window_title;
+	std::vector<StackItem> stack;
+	std::vector<std::string> stack_strbuffer;
+	std::vector<CmdSimplified> cmd_stack;
+	std::vector<std::string> rollback_save;
+	std::string new_rollback_save;
+	std::map<int, std::set<int> > text_readflag;
+	char* cmd_stack_str;
+	char cmd_stack_str_orig[32768];
+
+	Cmdtype dialog_type;
+	class WidDialog* dialog;
+	Scn2kMenu* menu;
+	bool menu_mouseshown;
+
+	Surface* mouse_surface;
+	int mouse_type;
+	int mouse_pressed;
+	void ShowCursor();
+	void HideCursor();
+
+	void SetSkipMode(SkipMode mode);
+
+	virtual void Elapsed(unsigned int current_time);
+
+	// セーブ関連
+	std::string MakeSaveFile(void) const;
+	bool StatSaveFile(int num, int& year, int& month, int& day, int& wday, int& hour,int& min, int& sec, int& msec, std::string& title) const;
+	void SaveImpl(std::string& s);
+	void LoadImpl(const char* s);
+	void Save(Cmd& cmd);
+	void Load(Cmd& cmd);
+	void SaveRollback(void);
+	void LoadRollback(Cmd& cmd);
+	void SaveSys(void);
+	void LoadSys(void);
+public:
+	Scn2k(Event::Container& _event, PicContainer& _parent, class MuSys& mu, AyuSysConfig& config);
+	~Scn2k();
+	static char* OpenScript(int scn_number, char*& end, int* call_vec, int& system_version);
+	bool ChangeScript(int scn_number, int call_no);
+	bool ReadCmdAt(Cmd& cmd, int scn, int pt);
+	void show_textwindow(int type);
+	void hide_textwindow(void);
+	void SysExec(Cmd& cmd);
+	bool SysWait(Cmd& cmd);
+
+	friend struct Scn2kSaveTitle;
+};
+#endif
new file mode 100644
--- /dev/null
+++ b/scn2k/scn2k_text.cc
@@ -0,0 +1,2031 @@
+/*
+TODO:
+	日付のラベルが画面切り替え時に欠けるのを修正
+	画像効果 : 人間の入れ換わりなど
+	kcursor の操作を WidText クラスに任せる
+	WidText クラスには新たに以下の操作を加える
+		・ウェイト終了後、クリアなしに新たなテキストを追加、新たにstart-waitする
+		・文字の描画 (Start) と Wait(カーソル表示待ち)の分離。
+			Start すると文字を描画開始する。クリックで全描画。
+			Flush するとバッファ内の文字をすべて描画する
+			Wait すると全描画後、クリックされるまでカーソルを表示するまで待つ
+		TextImpl 側の状態としては Wait のみを持つ (PREPAREに戻るのを待つ)
+		ただし、Skip の権利はどっちがもつ?(現状は?)
+
+	GrpObj: NextObj と GrpObj を分離。CreateObj は現状通り、Visible=1 時に行う。
+		それぞれ num=0 (screen) の枝leaf として実装。delete時は親のdeleteのみを
+		行い、子はGrpObjの実体だけを削除する
+		Visible 後のhide は実際に hide とする
+		ExecReservedCmd() はなくせるはず。Delete() もなくなる。
+	カノギ:ReBlit() がうまくいかないせいで名前ウィンドウが消えた時の背景がなくなる
+
+	くら:回想表示
+	SEL画像効果
+DONE:
+	ともよのテキストウィンドウ実装、ボタン実装
+	shake の画像効果
+	オブジェクト内のテキスト色の実装
+	画像効果の改善
+*/
+
+/*
+ * Copyright (c) 2004-2006  Kazunori "jagarl" Ueno
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include"window/event.h"
+#include"window/picture.h"
+#include"window/widget.h"
+#include"system/file.h"
+#include"system/system_config.h"
+#include"scn2k.h"
+
+#include<string>
+using namespace std;
+
+// kanji conv : デバッグ表示用
+void kconv(const unsigned char* src, unsigned char* dest);
+void kconv_rev(const unsigned char* src, unsigned char* dest);
+string kconv(const string& s);
+string kconv_rev(const string& s);
+// render.cc
+void DSurfaceFillA(Surface* src, const Rect& rect, int r, int g, int b, int a); // テキストウィンドウ背景の設定
+void DSurfaceMove(Surface* src_o, const Rect& srcrect, Surface* dst_o, const Rect& dstrect); // コピー
+
+/**************************************************************::
+**
+**	TextImpl(interface)
+*/
+struct TimerAtom {
+	int from;
+	int to;
+	unsigned int start_time;
+	unsigned int total_time;
+};
+
+struct TextWindow {
+/* @@@ : SetWindowColor での surface 再設定に注意 */
+	WidText* wid;
+	bool name_visible;
+	WidLabel* name;
+	PicContainer* name_container;
+	PicBase* face;
+	PicBase* face_pics[8];
+	TextWindow(PicContainer& parent, Event::Container& event, int window_no, const AyuSysConfig& config, void* callback);
+	~TextWindow() {
+		if (name_container) delete name_container;
+		int i; for (i=0; i<8; i++) {
+			if (face_pics[i]) delete face_pics[i];
+		}
+		if (wid) delete wid;
+	}
+	Rect WakuSize(PicContainer& pic, int waku_no, const AyuSysConfig& config);
+	void MakeWaku(PicContainer& pic, Event::Container& event, int waku_no,int window_no, bool* use_btn, const AyuSysConfig& config, void* callback);
+	void show(void) {
+		wid->show();
+		if (name_container && name_visible) name_container->show();
+		if (face) face->show();
+	}
+	void hide(void) {
+		wid->hide();
+		if (name_container) name_container->hide();
+		if (face) face->hide();
+	}
+	void ShowFace(const char* path) {
+		if (!face) return;
+		face->SetSurface( path, 0,0);
+	}
+	void ResetFace(void) {
+		if (!face) return;
+		face->SetSurface( (Surface*)0, 0,0);
+	}
+	void StartText(const TextStream& _stream) {
+		wid->Clear();
+		wid->stream = _stream;
+		if (name_container) {
+			char namestr[1024];
+			namestr[0] = 0;
+			wid->stream.RemoveName(namestr, 1024);
+			if (namestr[0] == 0) {
+				name_container->hide();
+			} else {
+				if (name) {
+					name_container->show_all();
+					name->SetText(namestr);
+				}
+			}
+		}
+		wid->Start();
+	}
+	void SetName(const char* n) {
+		if (name_container && name) {
+			if (n[0]) {
+				name_container->show();
+				name->SetText(n);
+				name_visible = true;
+			} else {
+				name_container->hide();
+				name_visible = false;
+			}
+		}
+	}
+};
+
+class TextImpl {
+private:
+public:
+	TextWindow* text;
+	typedef enum {NORMAL=0, WAIT_TEXT=1, WAIT=2, WAIT_CLICK=3, WAIT_ABORT=4, WAIT_CLICK_MOUSEPOS = 5, WAIT_CLICK_MOUSEPOSEND_L = 6, WAIT_CLICK_MOUSEPOSEND_R = 7,
+		WAIT_SELECT_INBOX = 10, WAIT_SELECT_OUTBOX=11, WAIT_SELECT_VALUE = 12,
+		WAIT_EXTRN_MASK = 64, SAVEMASK = 128, LOADMASK = 256, SKIPMASK = 512,
+		CLEARSCR_MASK = 1024, STATSAVE_MASK = 2048, CLEARSCR_WAIT_MASK=(1<<12),
+		SKIPEND_MASK = (1<<13), BACKLOG_MASK=(1<<14), BACKLOG_MASK_FWD=(1<<15), BACKLOG_MASK_KOE=(1<<16), BACKLOG_WAIT_MASK=(1<<17),
+		ALLMASK = (CLEARSCR_MASK | WAIT_EXTRN_MASK | SAVEMASK | LOADMASK | SKIPMASK | BACKLOG_MASK | BACKLOG_MASK_FWD | BACKLOG_MASK_KOE | BACKLOG_WAIT_MASK | STATSAVE_MASK | CLEARSCR_WAIT_MASK | SKIPEND_MASK)
+	} Status;
+	Status status, status_saved, status_mask;
+private:
+	std::string ruby_text;
+	bool ruby_text_flag;
+	unsigned int wait_time;
+	unsigned int old_time;
+	unsigned int base_time;
+	int text_window_number;
+	bool text_parsing;
+	TextStream text_stream;
+	SkipMode skip_mode;
+	int save_selectcount;
+
+	std::map<int, TimerAtom> timer_var;
+	std::vector<WidTextButton*> selects;
+	std::vector<int> sel_backlog_pos;
+	string replace_name[26];
+	string replace_name2[26];
+	PicContainer* sel_widget;
+	PicWidget* backlog_widget;
+
+	vector<BacklogItem>& backlog;
+	BacklogItem& backlog_item;
+	BacklogItem cur_backlog_item;
+	BacklogItem drawn_backlog_item;
+
+public:
+	PicContainer& parent;
+	Event::Container& event;
+	AyuSysConfig& config;
+private:
+	TextWindow* widgets[32];
+	WidTimeCursor* kcursor;
+	Surface* sel_bg1;
+	Surface* sel_bg2;
+	Rect sel_bg_rect;
+
+	void SetCursor(int num);
+	VarInfo wait_savedvar[2];
+
+public:
+	void AddText(const char* str);
+
+	static void PressFuncSkip(void* pointer, WidButton* from);
+	static void PressFuncLoad(void* pointer, WidButton* from);
+	static void PressFuncSave(void* pointer, WidButton* from);
+	static void PressFuncBacklog(void* pointer, WidButton* from);
+	static void PressFuncBacklogFwd(void* pointer, WidButton* from);
+private:
+	static void PressFuncButton(void* pointer, WidButton* from);
+	static bool PressFunc(int x, int y, void* pointer);
+
+public:
+	TextImpl(Event::Container& _event, PicContainer& _parent, AyuSysConfig& config, vector<BacklogItem>& parent_backlog, BacklogItem& parent_backlog_item);
+	~TextImpl();
+	void InitWindow(void);
+	void SetWindowColor(int r, int g, int b, int a, bool is_transparent);
+	void SetTextSpeed(int new_speed);
+	void SetTextWait(int new_wait);
+	void CreateSelect(Cmd& cmd);
+	void Exec(Cmd& cmd);
+	bool Wait(unsigned int current_time, Cmd& cmd);
+	void hide(void);
+	void show(void) { show(text_window_number); }
+	void show(int num);
+	void DrawBacklog(BacklogItem& item, Cmd& cmd);
+	void Save(std::string& str, bool select_save);
+	void Load(const char* str);
+	void SetSkipMode(SkipMode _mode);
+	void CreateSelBG(void);
+};
+
+/**************************************************************::
+**
+**	TextImpl(implementation)
+*/
+TextImpl::TextImpl(Event::Container& _event, PicContainer& _parent, AyuSysConfig& _config, vector<BacklogItem>& parent_backlog, BacklogItem& parent_backlog_item) :
+	text(0),status(TextImpl::NORMAL), status_saved(TextImpl::NORMAL), status_mask(TextImpl::NORMAL), ruby_text_flag(false),
+	old_time(0), base_time(0), text_window_number(0), text_parsing(false), skip_mode(SKIP_NO), save_selectcount(0), sel_widget(0),
+	backlog_widget(0), backlog(parent_backlog), backlog_item(parent_backlog_item), parent(_parent), event(_event), config(_config),
+	kcursor(0), sel_bg1(0), sel_bg2(0), sel_bg_rect(0,0,0,0) {
+	int i;
+	for (i=0; i<32; i++) {
+		widgets[i] = 0;
+	}
+	text_stream.kanji_type = TextStream::sjis;
+	event.RegisterGlobalPressFunc(&PressFunc, (void*)this);
+}
+
+TextImpl::~TextImpl() {
+	if (sel_widget) delete sel_widget;
+	int i;
+	for (i=0; i<32; i++) {
+		if (widgets[i]) delete widgets[i];
+	}
+	if (backlog_widget) delete backlog_widget;
+	if (sel_bg1) parent.Root().DeleteSurface(sel_bg1);
+	if (sel_bg2) parent.Root().DeleteSurface(sel_bg2);
+	event.DeleteGlobalPressFunc(&PressFunc, (void*)this);
+}
+
+bool TextImpl::PressFunc(int x, int y, void* pointer) {
+	TextImpl* t = (TextImpl*)pointer;
+	if (t->status == WAIT_CLICK) {
+		t->status = WAIT_ABORT;
+	} else if (t->status == WAIT_CLICK_MOUSEPOS) {
+		t->status = WAIT_CLICK_MOUSEPOSEND_L;
+	} else if (t->status_mask & CLEARSCR_WAIT_MASK) {
+		t->status_mask = Status(t->status_mask & (~CLEARSCR_WAIT_MASK));
+		if (t->text) t->text->show();
+		if (t->kcursor) {
+			if (t->status == WAIT_TEXT) t->kcursor->show();
+		}
+		if (t->sel_widget) t->sel_widget->show();
+		if (t->backlog_widget) t->backlog_widget->show();
+	} else if (t->status_mask & BACKLOG_WAIT_MASK) {
+		t->status_mask = Status(t->status_mask | BACKLOG_MASK_KOE);
+	} else if ( (t->skip_mode & SKIP_TEXT) && (!(t->skip_mode & SKIP_IN_MENU)) ) {
+		if (t->status == WAIT_SELECT_INBOX) ;
+		else if (t->status == WAIT_SELECT_OUTBOX) ;
+		else if (t->status == WAIT_SELECT_VALUE) ;
+		else t->status_mask = Status(t->status_mask | SKIPEND_MASK);
+	}
+	return true; // event not deleted
+}
+void TextImpl::PressFuncButton(void* pointer, WidButton* from) {
+	TextImpl* t = (TextImpl*)pointer;
+	if (t->status != WAIT_SELECT_INBOX && t->status != WAIT_SELECT_OUTBOX) return;
+	vector<WidTextButton*>::iterator it;
+	int sel = 0;
+	for (it=t->selects.begin(); it != t->selects.end(); it++, sel++) {
+		if (from == *it) break;
+	}
+	if (it == t->selects.end()) {
+		fprintf(stderr,"TextImpl::PressFuncButton: Cannot find select widget\n");
+		return;
+	}
+	t->status = Status(WAIT_SELECT_VALUE + sel);
+	return;
+}
+
+void TextImpl::SetSkipMode(SkipMode _mode) {
+	if ( (skip_mode & SKIP_IN_MENU) && (_mode & SKIP_IN_MENU) == 0) {
+		if (status_mask & BACKLOG_WAIT_MASK) { // backlog mode から復帰
+			status_mask = Status(status_mask & (~(BACKLOG_MASK|BACKLOG_MASK_FWD|BACKLOG_MASK_KOE|BACKLOG_WAIT_MASK)));
+			text->wid->Clear();
+			if (status == WAIT_TEXT && text != 0) {
+				text->StartText(text_stream);
+				text->ShowFace(backlog_item.face.c_str());
+				text->wid->Flush();
+				if (kcursor) kcursor->show();
+			}
+			drawn_backlog_item.Clear();
+		}
+		if (text) text->wid->activate();
+		if (sel_widget) {
+			sel_widget->show();
+			if (kcursor) kcursor->hide();
+		}
+		if (backlog_widget) backlog_widget->show();
+		if (status_mask & STATSAVE_MASK) {
+			status_mask = Status(status_mask & (~STATSAVE_MASK));
+			status = status_saved;
+		}
+	} else if ( (skip_mode & SKIP_IN_MENU) == 0 && (_mode & SKIP_IN_MENU) ) {
+		if (text) text->wid->deactivate();
+		if (sel_widget) sel_widget->hide();
+		if (backlog_widget) backlog_widget->hide();
+	}
+	skip_mode = _mode;
+}
+
+/* hash_map が欲しい……*/
+#include<map>
+#include<list>
+struct SaveFaceHash { // バックログセーブ時の顔画像管理を行う
+	map<string, int> facetonum;
+	typedef pair<string,int> Node;
+	typedef list<Node> List;
+	List container;
+	int id_max;
+	static int size_max;
+	SaveFaceHash() : id_max(0) {
+	}
+	void NewNode(string face, int face_id) {
+		facetonum[face] = face_id;
+		container.push_front(Node(face, face_id));
+		if (container.size() > size_max) {
+			Node remove = container.back();
+			container.pop_back();
+			facetonum.erase(remove.first);
+		}
+	}
+	int Add(string face) {
+		int id; int ret = -1;
+		int i; List::iterator it;
+		if (face.empty()) return -1;
+		if (facetonum.find(face) == facetonum.end()) {
+			id = ++id_max;
+			NewNode(face, id);
+			ret = -1;
+		} else {
+			id = facetonum[face];
+			for (i=0, it=container.begin(); it != container.end(); i++, it++) {
+				if (it->second == id) {
+					ret = i;
+					Node n = *it;
+					container.erase(it);
+					container.push_front(n);
+					break;
+				}
+			}
+		}
+		return ret;
+	}
+	string Get(int num) {
+		if (num < 0) return "";
+		List::iterator it = container.begin();
+		for (; it != container.end(); it++) {
+			if (num == 0) return it->first;
+			num--;
+		}
+		return "";
+	}
+};
+int SaveFaceHash::size_max = 20;
+
+void TextImpl::Save(string& str, bool rollback_save) {
+	char buf[1024];
+	str = "\n";
+	str += "[TextImpl Window]\n";
+	sprintf(buf, "TextImplWindow=%d\n",text_window_number);
+	str += buf;
+	if (rollback_save) {
+		++save_selectcount;
+		BacklogItem save_item;
+		save_item.SetSavepos(save_selectcount);
+		backlog.push_back(save_item);
+	}
+	sprintf(buf, "SaveSelectCount=%d\n",save_selectcount);
+
+	str += buf;
+	int i;
+	for (i=0; i<26; i++) {
+		if (replace_name2[i].empty()) continue;
+		sprintf(buf, "RName.%c=%s\n",i+'A',replace_name2[i].c_str());
+		str += buf;
+	}
+	int cnt = 0;
+	vector<BacklogItem>::iterator it;
+	it = backlog.begin();
+	if (!rollback_save) {
+		SaveFaceHash face_log;
+		do {
+		int cur_scn = -1; int cur_pos = -1;
+		sprintf(buf, "Backlog.%d=",++cnt);
+		str += buf;
+		for (; it != backlog.end(); it++) {
+			buf[0] = 0; int buflen = 0;
+			if (it->scn == -1) continue;
+			if (it->pos == -1 && it->scn != 0) continue;
+
+			buf[buflen++] = ';';
+			if (it->scn == 0 && it->pos == -1) {
+				buflen += snprintf(buf+buflen, 1000-buflen, "\"%s\".", it->text.Save().c_str());
+			} else {
+				if (cur_scn != -1 && cur_scn != it->scn) break; // scn change
+				if (cur_pos != -1 && cur_pos/5000 != it->pos/5000) break; // pos exceeded
+				if (!it->text.container.empty()) {
+					buflen += snprintf(buf+buflen, 1000-buflen, "\"%s\"", it->text.Save().c_str());
+				}
+				if (cur_scn == -1) { // scene change
+					buflen += snprintf(buf+buflen, 1000-buflen, ":%d:%d",it->scn,it->pos);
+					cur_scn = it->scn;
+				} else {
+					buflen += snprintf(buf+buflen, 1000-buflen, "%d",it->pos);
+				}
+				cur_pos = it->pos;
+			}
+			if (it->koe != -1)
+				buflen += snprintf(buf+buflen, 1000-buflen, ",%d",it->koe);
+			if (!it->face.empty()) {
+				if (it->koe == -1) buf[buflen++] = ',';
+				int face_num = face_log.Add(it->face);
+				if (face_num >= 0 && face_num < 20)
+					buflen += snprintf(buf+buflen, 1000-buflen, ",%c", 'A'+face_num);
+				else
+					buflen += snprintf(buf+buflen, 1000-buflen, ",\"%s\"", it->face.c_str());
+			}
+			buf[buflen++] = '\0';
+			if (buflen >= 1000) { // 万が一、バックログ1アイテムの大きさが 1000byte を越えるとき
+				fprintf(stderr,"Fatal : Cannot save backlog crrectly; Please send bug report to the author.\n");
+			} else str += buf;
+		}
+		str += "\n";
+	} while(it != backlog.end());
+	}
+	return;
+}
+void TextImpl::Load(const char* str) {
+	if (text) text->wid->Clear();
+	hide();
+	text_window_number = 0;
+	save_selectcount = 0;
+	if (sel_widget) {
+		selects.clear();
+		sel_backlog_pos.clear();
+		delete sel_widget;
+		sel_widget = 0;
+	}
+	if (backlog_widget) {
+		delete backlog_widget;
+		backlog_widget = 0;
+	}
+	status = NORMAL;
+	status_mask = NORMAL;
+	status_saved = NORMAL;
+	text_parsing = false;
+	text_stream.Clear();
+	// backlog.clear();
+	vector<BacklogItem> new_backlog;
+	backlog_item.Clear();
+	cur_backlog_item.Clear();
+	drawn_backlog_item.Clear();
+
+	str = strstr(str, "\n[TextImpl Window]\n");
+
+	if (str) {
+		SaveFaceHash face_log;
+		str += strlen("\n[TextImpl Window]\n");
+		const char* strend = str;
+		do {
+			str = strend;
+
+			strend = strchr(str, '\n');
+			if (strend == 0) strend = str + strlen(str);
+			else strend++;
+
+			if (str[0] == '[') break; // next section
+			if (strncmp(str, "TextImplWindow=",15) == 0) {
+				str += 15;
+				sscanf(str, "%d", &text_window_number);
+			} else if (strncmp(str, "SaveSelectCount=",16) == 0) {
+				str += 16;
+				sscanf(str, "%d", &save_selectcount);
+			} else if (strncmp(str, "RName.", 6) == 0) {
+				int n = str[6]-'A';
+				if (n >= 0 && n < 26 && str[7] == '=') {
+					const char* s = strchr(str, '\n');
+					int len = -1;
+					if (s) len = s-(str+8);
+					if (len > 0) {
+						replace_name2[n].assign(str+8, len);
+					}
+				}
+			} else if (strncmp(str, "Backlog.", 8) == 0) {
+				int cur_scn = -1;
+				int n = -1;
+				sscanf(str+8, "%d", &n); /* not used */
+				const char* next_str = strchr(str, ';');
+				while(next_str != 0 && next_str < strend) {
+					str = next_str + 1;
+					next_str = strchr(str, ';');
+					if (next_str == 0) next_str = strend;
+
+					BacklogItem item;
+					if (str[0] == '"') {
+						const char* send = strchr(str+1, '"');
+						if (send == 0 || send > next_str) continue;
+						string tmp_str; tmp_str.assign(str+1, send-str-1);
+						item.DeleteTextPos();
+						item.text.Load(tmp_str);
+						str = send + 1;
+					}
+					if (str[0] == '.') {
+						item.DeleteTextPos();
+						str++;
+					} else if (str[0] == ':') {
+						sscanf(str, ":%d:%d", &item.scn, &item.pos);
+						cur_scn = item.scn;
+						
+					} else {
+						item.scn = cur_scn;
+						sscanf(str, "%d", &item.pos);
+					}
+					str = strchr(str, ',');
+					if (str == 0 || str > next_str) goto backlog_store;
+					str++;
+					if (str[0] == ';' || str[0] == ',')
+						item.koe = -1;
+					else
+						sscanf(str, "%d", &item.koe);
+					str = strchr(str, ',');
+					if (str == 0 || str > next_str) goto backlog_store;
+					str++;
+					if (*str == '"') {
+						const char* send = strchr(str+1, '"');
+						if (send) {
+							item.face.assign(str+1, send-str-1);
+						}
+					} else if (*str >= 'A' && *str <= 'Z') {
+						item.face = face_log.Get(*str - 'A');
+					}
+					face_log.Add(item.face);
+				backlog_store:
+					new_backlog.push_back(item);
+				}
+			}
+		} while (*strend != 0);
+	}
+	if (new_backlog.empty() && (!backlog.empty())) { // empty なら save_selectcount まで backlog を巻き戻す
+		vector<BacklogItem>::iterator it = backlog.end();
+		do {
+			it--;
+			if (it->scn == BacklogItem::SaveSelect && it->pos == save_selectcount) {
+				// Save 位置を見つけたらそれ以降を erase
+				backlog.erase(it, backlog.end());
+				break;
+			}
+		} while(it != backlog.begin());
+		--save_selectcount;
+	} else {
+		backlog.swap(new_backlog);
+	}
+	// backlog.clear();
+	return;
+}
+
+void TextImpl::hide(void) {
+	if (text) text->hide();
+	if (kcursor) kcursor->hide();
+	text = 0;
+}
+void TextImpl::show(int num) {
+	if (num != text_window_number) {
+		hide();
+		if (num >= 0 && num < 32 && widgets[num] != 0) {
+			text_window_number = num;
+		}
+	}
+	text = widgets[text_window_number];
+	text->show();
+	if (kcursor) {
+		int kx, ky, d;
+		char key[1024];
+		sprintf(key, "#WINDOW.%03d.KEYCUR_MOD", text_window_number);
+		config.GetParam(key, 3, &d, &kx, &ky);
+		// 正しくない気がする
+		kx += text->wid->Pic()->PosX();
+		ky += text->wid->Pic()->PosY();
+		// 微妙に下にする
+		ky += 8;
+		kcursor->Pic()->Move(kx, ky);
+	}
+}
+void TextImpl::DrawBacklog(BacklogItem& item, Cmd& cmd) {
+	text->show();
+	text->wid->deactivate();
+	status_mask = Status(status_mask | BACKLOG_WAIT_MASK);
+	drawn_backlog_item = item;
+	if (item.text.container.empty()) {
+		// cmd から text 内容を再構成
+		TextStream saved_text = text_stream;
+		text_stream.Clear();
+		AddText(cmd.Str(cmd.args[0]));
+		item.text = text_stream;
+		text_stream = saved_text;
+	}
+	char namestr[1024];
+	namestr[0] = 0;
+	item.text.RemoveName(namestr, 1024);
+	text->SetName(namestr);
+	item.text.InsertColor(0, item.text.container.size(), 0xff,0xff,0);
+	text->wid->Clear();
+	text->wid->stream = item.text;
+	text->wid->Start();
+	text->wid->Flush();
+	if (item.face.empty()) text->ResetFace();
+	else text->ShowFace(item.face.c_str());
+	if (kcursor) kcursor->hide();
+}
+
+void TextImpl::CreateSelBG(void) {
+	if (sel_bg1 != 0 || sel_bg2 != 0) return;
+
+	const char* btnfile1 = config.GetParaStr("#SELBTN.000.NAME");
+	const char* btnfile2 = config.GetParaStr("#SELBTN.000.BACK");
+	char path[1024];
+	strcpy(path, btnfile1);
+	sel_bg1 = parent.Root().NewSurface(path);
+	if (sel_bg1 == 0) {
+		sprintf(path,"%s.g00",btnfile1);
+		sel_bg1 = parent.Root().NewSurface(path);
+	}
+	strcpy(path, btnfile2);
+	sel_bg2 = parent.Root().NewSurface(path);
+	if (sel_bg2 == 0) {
+		sprintf(path,"%s.g00",btnfile2);
+		sel_bg2 = parent.Root().NewSurface(path);
+	}
+	sel_bg_rect = Rect(0,0,0,0);
+	if (sel_bg1) sel_bg_rect.join(Rect(*sel_bg1));
+	if (sel_bg2) sel_bg_rect.join(Rect(*sel_bg2));
+	return;
+}
+
+void TextImpl::CreateSelect(Cmd& cmd) {
+	char key[1024];
+	sprintf(key, "#WINDOW.%03d.SELCOM_USE",text_window_number);
+	int sel_type = 0;
+	config.GetParam(key, 1, &sel_type);
+
+	int sel_size = cmd.args.size() / 2;
+	int i;
+	// cur_backlog_item に次にbacklogに入るべき内容を作成
+	// CreateSelect() 後、SAVEPOINT なので現在のbacklogの内容(前のメッセージ)が
+	// backlog に代入される。その後、backlog_item に cur_backlog_item の内容がセットされる(Wait()内)
+	char backlog_sel_text[11] = {0x81,0x69,0x91,0x49,0x91,0xf0,0x8e,0x88,0x81,0x6a,0x00};
+	cur_backlog_item.Clear();
+	cur_backlog_item.AddTextPos(cmd);
+	cur_backlog_item.text.Add(backlog_sel_text);
+	cur_backlog_item.text.AddReturn();
+	sel_backlog_pos.clear();
+	for (i=0; i<sel_size; i++) {
+		sel_backlog_pos.push_back(cur_backlog_item.text.container.size());
+		cur_backlog_item.text.Add(cmd.Str(cmd.args[i*2]));
+		cur_backlog_item.text.AddReturn();
+	}
+	sel_backlog_pos.push_back(cur_backlog_item.text.container.size());
+
+	if (sel_type == 0) { // Princess Bride: 選択ウィンドウを別表示
+External_select:
+		CreateSelBG();
+		hide(); // なので、テキストウィンドウは消去
+		int baseposx, baseposy, repposx, repposy;
+		int mojisize, col1, col2;
+		config.GetParam("#SELBTN.000.BASEPOS", 2, &baseposx, &baseposy);
+		config.GetParam("#SELBTN.000.REPPOS", 2, &repposx, &repposy);
+		config.GetParam("#SELBTN.000.MOJISIZE", 1, &mojisize);
+		config.GetParam("#SELBTN.000.MOJIDEFAULTCOL", 1, &col1);
+		config.GetParam("#SELBTN.000.MOJISELECTCOL", 1, &col2);
+		if (col1 == col2) col2 = 1; // CLANNAD でとりあえず。
+		int r, g, b;
+		sprintf(key, "#COLOR_TABLE.%03d", col1);
+		config.GetParam(key, 3, &r, &g, &b);
+		Color fore(r,g,b);
+		sprintf(key, "#COLOR_TABLE.%03d", col2);
+		config.GetParam(key, 3, &r, &g, &b);
+		Color seled(r,g,b);
+
+		/* ウィジット作成 */
+		/* ウィンドウ背景の大きさを求める */
+		if (baseposx == 0 && sel_bg_rect.width() != 0)
+			baseposx = (parent.Width()-sel_bg_rect.width()) / 2; // ボタン位置をセンタリング
+
+		sel_widget = parent.create_node( Rect(0, 0, parent.Width(), parent.Height()),0);
+
+		for (i=0; i<sel_size; i++) {
+			PicBase* p;
+			// 背景作成
+			if (sel_bg2) {
+				p = sel_widget->create_node(Rect(baseposx, baseposy, baseposx+sel_bg_rect.width(), baseposy+sel_bg_rect.height()),0);
+				p->SetSurface(sel_bg2, 0, 0);
+			}
+			if (sel_bg1) {
+				p = sel_widget->create_node(Rect(baseposx, baseposy, baseposx+sel_bg_rect.width(), baseposy+sel_bg_rect.height()),0);
+				p->SetSurface(sel_bg1, 0, 0);
+			}
+			/* ボタン作成 */
+			const char* str = cmd.Str(cmd.args[i*2]);
+			int value = cmd.args[i*2+1].value;
+			while(selects.size() <= value) selects.push_back(0); // vector の大きさを広げる
+
+			kconv( (const unsigned char*)str, (unsigned char*)key);
+			selects[value] = new WidTextButton(event, sel_widget, key, mojisize, WidTextButton::CENTER,
+				Rect(baseposx, baseposy, baseposx+sel_bg_rect.width(), baseposy+sel_bg_rect.height()), 1, fore, seled, Color(0,0,0,0));
+			selects[value]->press_func = &PressFuncButton;
+			selects[value]->press_pointer = (void*)this;
+
+			baseposx += repposx;
+			baseposy += repposy;
+		}
+		sel_widget->show_all();
+		status = WAIT_SELECT_OUTBOX;
+	} else { // CLANNAD: テキストウィンドウ内に選択肢表示
+		int mojisize;
+		config.GetParam("#SELBTN.000.MOJISIZE", 1, &mojisize);
+		Color fore(0xff,0xff,0xff);
+		Color seled(0xff,0xff,0xff);
+
+		show();
+		if (text == 0) goto External_select; // テキスト・ウィンドウを表示できなければ外部選択肢にする
+		text->wid->Clear();
+		if (kcursor) kcursor->hide();
+		/* ウィジット作成  : テキスト表示範囲と同じ*/
+		int posx = text->wid->pictext->PosX();
+		int posy = text->wid->pictext->PosY();
+		int sel_w = text->wid->pictext->Width();
+		int sel_h = text->wid->pictext->Height();
+		sel_widget = text->wid->PicNode()->create_node(Rect(posx, posy, posx+sel_w, posy+sel_h), 0);
+
+		int sel_y = 0;
+		for (i=0; i<sel_size; i++) {
+			PicBase* p;
+			/* ボタン作成 */
+			const char* str = cmd.Str(cmd.args[i*2]);
+			int value = cmd.args[i*2+1].value;
+			while(selects.size() <= value) selects.push_back(0); // vector の大きさを広げる
+
+			kconv( (const unsigned char*)str, (unsigned char*)key);
+			selects[value] = new WidTextButton(event, sel_widget, key, mojisize, WidTextButton::Attribute(WidTextButton::REVERSE | WidTextButton::NOPADDING),
+				Rect(0, sel_y, sel_w, sel_y), 1, fore, seled, Color(0,0,0,0));
+			selects[value]->press_func = &PressFuncButton;
+			selects[value]->press_pointer = (void*)this;
+
+			sel_y += selects[value]->Pic()->Height() + 1;
+		}
+		sel_widget->show_all();
+		status = WAIT_SELECT_INBOX;
+	}
+}
+
+void TextImpl::AddText(const char* str_o) {
+	char str[10001];
+	if (text == 0) return;
+	/* まず、replace string を変換 */
+	int i;
+	int cnt = 0;
+	/* * = 81 96 A-Z = 0x82 [0x60-0x79] */
+	/* % = 81 93 A-Z = 0x82 [0x60-0x79] */
+	for (i=0; cnt<10000 && str_o[i] != 0; i++) {
+		if (str_o[i] < 0) {
+			if ( (unsigned char)str_o[i] == 0x81 && (unsigned char)str_o[i+1] == 0x96 && (unsigned char)str_o[i+2] == 0x82) {
+				int c = str_o[i+3];
+				if (c >= 0x60 && c <= 0x79 && replace_name[c-0x60].length() != 0) { // 名前変換
+					i += 3;
+					strcpy(str+cnt, replace_name[c-0x60].c_str());
+					cnt += replace_name[c-0x60].length();
+					continue;
+				}
+			} else if ( (unsigned char)str_o[i] == 0x81 && (unsigned char)str_o[i+1] == 0x93 && (unsigned char)str_o[i+2] == 0x82) {
+				int c = str_o[i+3];
+				if (c >= 0x60 && c <= 0x79 && replace_name2[c-0x60].length() != 0) { // 名前変換2
+					i += 3;
+					strcpy(str+cnt, replace_name2[c-0x60].c_str());
+					cnt += replace_name2[c-0x60].length();
+					continue;
+				}
+			}
+			str[cnt++] = str_o[i++];
+		}
+		str[cnt++] = str_o[i];
+	}
+	str[cnt] = 0;
+	str[10000] = 0;
+	char* str_top = str;
+
+	for (char* s = str_top; *s != 0; s++) {
+		// if (*(unsigned char*)s == 0xa1 && *(unsigned char*)(s+1) == 0xda) { /* euc */
+		if (*(unsigned char*)s == 0x81 && *(unsigned char*)(s+1) == 0x79) { /* sjis */
+			// 名前
+			*s = 0;
+			if (s != str_top) text_stream.Add(str_top);
+			s += 2;
+			char* name_top = s;
+			for (; *s != 0; s++) {
+				// if (*(unsigned char*)s == 0xa1 && *(unsigned char*)(s+1) == 0xdb) { /* euc */
+				if (*(unsigned char*)s == 0x81 && *(unsigned char*)(s+1) == 0x7a) { /* sjis */
+					*s = 0;
+					s += 2;
+					text_stream.AddName(name_top);
+					break;
+				}
+				if (*s < 0 && s[1] != 0) s++; // 全角文字なら2字飛ばす
+			}
+			str_top = s;
+		}
+		if (*s == 0x0a) {
+			*s = 0;
+			text_stream.Add(str_top);
+			text_stream.AddReturn();
+			str_top = s;
+		} else if (*s < 0 && s[1] != 0) s++;
+	}
+	text_stream.Add(str_top);
+	return;
+}
+
+void TextImpl::Exec(Cmd& cmd) {
+	if (cmd.cmd_type == CMD_TEXT) {
+		if (text == 0) {
+			show();
+		}
+		if (cmd.args.size() != 1) return;
+		if (ruby_text_flag) {
+			ruby_text = cmd.Str(cmd.args[0]);
+			ruby_text_flag = 0;
+			cmd.clear();
+			return;
+		}
+		cur_backlog_item.AddTextPos(cmd);
+		AddText(cmd.Str(cmd.args[0]));
+		char debug[1024];
+		kconv( (unsigned char*)cmd.Str(cmd.args[0]), (unsigned char*)debug);
+		eprintf("text: %s\n",debug);
+		if (text_parsing)
+			cmd.clear();
+		else
+			cmd.cmd_type = CMD_SAVEPOINT;
+		text_parsing = true; /* テキスト待ち直後のテキスト位置=セーブ位置 */
+		return;
+	}
+	if (cmd.cmd_type != CMD_OTHER) return;
+	/* テキストウィンドウを消去するコマンド類をチェックする */
+	if (cmd.cmd1 == 1 && cmd.cmd2 == 0x21) {
+		if (cmd.cmd3 == 0x49 || cmd.cmd3 == 0x4b || cmd.cmd3 == 0x4c) {
+			if (text) text->ResetFace();
+			cur_backlog_item.face = "";
+			hide();
+		}
+	}
+	if (cmd.cmd1 == 1 && cmd.cmd2 == 0x17 && cmd.cmd3 == 0 && cmd.cmd4 == 1) { 
+		// PlayKoe ; 声出力コマンドをチェックする */
+		cur_backlog_item.koe = cmd.args[0].value;
+	}
+	if (cmd.cmd1 == 0 && cmd.cmd2 == 3 && cmd.cmd3 == 0x97) { // いいのかなー
+		
+		if (text) {
+			text->ResetFace();
+			text->wid->Clear();
+		}
+		cur_backlog_item.face = "";
+		text_stream.Clear();
+		hide();
+	}
+	if (cmd.cmd1 == 0 && cmd.cmd2 == 3) {
+		if (cmd.cmd3 == 0x11) { // テキスト表示、クリック待ち
+			if (text) {
+				eprintf("start\n");
+				text->StartText(text_stream);
+				if (skip_mode & SKIP_TEXT) text->wid->Flush();
+				else if (kcursor) kcursor->show();
+				status = WAIT_TEXT;
+				text_parsing = false;
+			}
+			backlog_item = cur_backlog_item;
+			if (cur_backlog_item.scn == 0 && cur_backlog_item.pos == -1) backlog_item.text = text_stream;
+			cur_backlog_item.Clear();
+
+			cmd.clear();
+			cmd.cmd_type = CMD_WAITFRAMEUPDATE; // 画像描画に戻る(skip時にテキストが描画されやすくするため)
+				// これだと1フレーム1テキストしか表示されなくなるので注意
+		} else if (cmd.cmd3 == 3 || cmd.cmd3 == 0xc9) { // リターン挿入
+			text_stream.AddReturn();
+			cur_backlog_item.DeleteTextPos();
+			cmd.clear();
+		} else if (cmd.cmd3 == 0x3e8 || cmd.cmd3 == 0x3e9) { // 顔グラフィック変更
+			if (text == 0) {
+				show();
+			}
+			if (cmd.cmd3 == 0x3e8) {
+				string s = cmd.Str(cmd.args[0]);
+				s += ".g00";
+				if (text) text->ShowFace(s.c_str());
+				cur_backlog_item.face = s;
+				cmd.cmd_type = CMD_SAVECMD_ONCE;
+			} else if (cmd.cmd3 == 0x3e9) { // 顔グラフィック消去
+				if (text) text->ResetFace();
+				cur_backlog_item.face = "";
+				cmd.cmd_type = CMD_SAVECMD_ONCE;
+			}
+		} else if (cmd.cmd3 == 0x78) { // ルビ関連
+			if (text == 0) {
+				show();
+			}
+			if (cmd.cmd4 == 1) {
+				ruby_text_flag = true;
+				eprintf("SetRubyTextImpl.");
+				cmd.clear();
+			} else if (cmd.cmd4 == 0) {
+				if (ruby_text.length() == 0) { // ルビを振るテキストがない
+					eprintf("Cannot find ruby text.\n");
+					return;
+				}
+				if (cmd.args.size() != 1) return;
+				char debug1[1024], debug2[1024];
+				kconv( (unsigned char*)ruby_text.c_str(), (unsigned char*)debug1);
+				kconv( (unsigned char*)cmd.Str(cmd.args[0]), (unsigned char*)debug2);
+				eprintf("SetRuby. %s, %s",debug1, debug2);
+				text_stream.AddRuby(ruby_text.c_str(), cmd.Str(cmd.args[0]));
+				cur_backlog_item.DeleteTextPos();
+				cmd.clear();
+			}
+		} else if (cmd.cmd3 == 0x66) { // テキストウィンドウの形
+			if (cmd.cmd4 == 0) {
+				eprintf("set text window <- %d\n",cmd.args[0].value);
+				if (text) show(cmd.args[0].value);
+				else text_window_number = cmd.args[0].value;
+			} else if (cmd.cmd4 == 1) { // default value
+				eprintf("set text window <- default\n");
+				if (text) show(0);
+				else text_window_number = 0;
+			}
+			cmd.clear();
+		} else if (cmd.cmd3 == 0x67) { // テキストウィンドウ表示?
+			show();
+// 表示の際はテキストをクリアしない?
+//			if (text) text->wid->Clear();
+//			text_stream.Clear();
+			cmd.clear();
+		} else if (cmd.cmd3 == 0x68) { // テキスト表示?
+			// 全テキスト表示
+			if (text) {
+				text->StartText(text_stream);
+				text->wid->Flush();
+			}
+			cmd.clear();
+		} else if (cmd.cmd3 == 0x98) { // テキストウィンドウクリア?
+			show();
+			if (text) text->wid->Clear();
+			text_stream.Clear();
+			cmd.clear();
+		}
+	} else if (cmd.cmd1 == 0 && cmd.cmd2 == 2 && (cmd.cmd3 == 1 || cmd.cmd3 == 3) && cmd.cmd4 == 0) {
+		// 選択肢
+		CreateSelect(cmd);
+		cmd.cmd_type = CMD_ROLLBACKPOINT; /* 選択肢はセーブ位置 / シナリオ巻き戻し位置 */
+		// cmd.clear();
+	} else if (cmd.cmd1 == 0 && cmd.cmd2 == 4) {
+		if (cmd.cmd3 == 0x44c) { // テキストスキップ開始
+			status_mask = Status(SKIPMASK | status_mask);
+			cmd.clear();
+		} else if (cmd.cmd3 == 0x3e8) { // ウィンドウ消去
+			status_mask = Status(CLEARSCR_MASK | status_mask);
+			cmd.clear();
+		}
+	} else if (cmd.cmd1 == 1 && cmd.cmd2 == 0x04) {
+		/* ウェイト関連命令 */
+		if (cmd.cmd3 == 0x64 || cmd.cmd3 == 0x6f || cmd.cmd3 == 0x79) {
+			eprintf("wait %dmsec\n",cmd.args[0].value);
+			if (cmd.cmd3 == 0x64 && text) {
+				/* 0x64 だと文字描画中の待ちに使うことがある */
+				text->StartText(text_stream);
+				text->wid->Flush();
+			}
+			if (cmd.cmd3 == 0x6f || cmd.cmd3 == 0x79) wait_time = base_time + cmd.args[0].value;
+			else wait_time = old_time + cmd.args[0].value;
+			status = WAIT;
+			cmd.cmd_type = CMD_WAITFRAMEUPDATE; // 画像描画に戻る(skip時にテキストが描画されやすくするため)
+		} else if (cmd.cmd3 == 0x65 || cmd.cmd3 == 0x70) {
+			eprintf("wait %dmsec(click stop)\n",cmd.args[0].value);
+			if (cmd.cmd3 == 0x70) wait_time = base_time + cmd.args[0].value;
+			else wait_time = old_time + cmd.args[0].value;
+			status = WAIT_CLICK;
+			cmd.cmd_type = CMD_WAITFRAMEUPDATE; // 画像描画に戻る(skip時にテキストが描画されやすくするため)
+		} else if (cmd.cmd3 == 0x83) {
+			/* マウスがクリックされるまで待つ */
+			eprintf("wait and get mouse pos at click\n");
+			wait_time = old_time + 1000 * 1000;
+			status = WAIT_CLICK_MOUSEPOS;
+			wait_savedvar[0] = cmd.args[0];
+			wait_savedvar[1] = cmd.args[1];
+			cmd.clear();
+		} else if (cmd.cmd3 == 0x1fe) {
+			eprintf("get timer value[%d]\n",cmd.args[0].value);
+			if (timer_var.find(cmd.args[0].value) == timer_var.end()) {
+				cmd.SetSysvar(0);
+			} else {
+				TimerAtom& atom = timer_var[cmd.args[0].value];
+				if (atom.total_time <= 0) atom.total_time = 1;
+				int cur_tm = old_time - atom.start_time;
+				if (cur_tm < 0) cur_tm = atom.total_time; // エラーなら最終時間に合わせる
+				if (cur_tm > atom.total_time) cur_tm = atom.total_time;
+				// use 'long long'(64bit) or 'double'(80bit) type, since total_time, to and from is 32 bit.
+				int v = atom.from + (long long)(atom.to-atom.from)*cur_tm/int(atom.total_time);
+				cmd.SetSysvar(v);
+			}
+/* From rldev-1.40, reallive.kfn
+0x72  fun Timer           (store) <1:Sys:00114, 1> ('counter') ()
+0x73  fun CmpTimer        (store) <1:Sys:00115, 1> ('time')    ('time', 'counter')
+0x74  fun SetTimer                <1:Sys:00116, 1> ('time')    ('time', 'counter')
+
+0x78  fun ResetExTimer            <1:Sys:00120, 1> ('counter') ()
+0x79  fun timeEx                  <1:Sys:00121, 1> ('time')    ('time', 'counter')
+0x7a  fun timeExC         (store) <1:Sys:00122, 1> ('time')    ('time', 'counter')
+0x7b  fun timeExC2        (store) <1:Sys:00123, 1> ('time')    ('time', 'counter') // UNDOCUMENTED
+0x7c  fun ExTimer         (store) <1:Sys:00124, 1> ('counter') ()
+0x7d  fun CmpExTimer      (store) <1:Sys:00125, 1> ('time')    ('time', 'counter')
+0x7e  fun SetExTimer              <1:Sys:00126, 1> ('time')    ('time', 'counter')
+*/
+
+		} else if (cmd.cmd3 == 0x6e || cmd.cmd3 == 0x78) { // set basetime
+			if (cmd.cmd4 == 1) {
+				eprintf("set basetime\n");
+				base_time = old_time;
+				cmd.clear();
+			} else if (cmd.cmd4 == 0) { // n-th base time
+				int index = cmd.args[0].value;
+				eprintf("set basetime (%d)\n",index);
+				TimerAtom& atom = timer_var[index];
+				atom.from = 0;
+				atom.to = 0;
+				atom.total_time = 0;
+				atom.start_time = old_time;
+				cmd.clear();
+			}
+		} else if (cmd.cmd3 == 0x72 || cmd.cmd3 == 0x7c) { // get time
+			if (cmd.cmd4 == 1) { // get time
+				eprintf("get time\n");
+				cmd.SetSysvar(old_time - base_time);
+			} else if (cmd.cmd4 == 0) { // n-th get time
+				int index = cmd.args[0].value;
+				eprintf("get time %dth\n",index);
+				if (timer_var.find(index) == timer_var.end()) cmd.SetSysvar(0);
+				else cmd.SetSysvar(old_time - timer_var[index].start_time);
+			}
+		} else if (cmd.cmd3 == 0x26c || cmd.cmd3 == 0x270) { // set basetime(multi)
+			int j = 0;
+			eprintf("set basetime\n");
+			int i; for (i=0; i<cmd.argc; i++) {
+				int cnt = cmd.args[j++].value; // 3なので無視
+				int num = cmd.args[j++].value;
+				TimerAtom& atom = timer_var[num];
+				atom.from = cmd.args[j++].value;
+				atom.to = cmd.args[j++].value;
+				atom.total_time = cmd.args[j++].value;
+				atom.start_time = old_time;
+			}
+			cmd.clear();
+		} else if (cmd.cmd3 == 0x276) { // get time (multi)
+			int j = 0;
+			eprintf("get timer value\n");
+			vector<VarInfo> args = cmd.args;
+			vector<VarInfo>::iterator it = args.begin();
+			int argc = cmd.argc;
+			int active_timers = 0;
+			int i; for (i=0; i<argc; i++) {
+				int cnt = (it++)->value;
+				int num = (it++)->value;
+				
+				if (timer_var.find(num) == timer_var.end()) {
+					cmd.SetFlagvar(*it++, 0);
+				} else {
+					TimerAtom& atom = timer_var[num];
+					if (atom.total_time <= 0) atom.total_time = 1;
+					int cur_tm = old_time - atom.start_time;
+					if (cur_tm < 0) cur_tm = atom.total_time; // エラーなら最終時間に合わせる
+					if (cur_tm > atom.total_time) cur_tm = atom.total_time;
+					// use 'long long'(64bit) or 'double'(80bit) type, since total_time, to and from is 32 bit.
+					int v = atom.from + (long long)(atom.to-atom.from)*cur_tm/int(atom.total_time);
+					cmd.SetFlagvar(*it++, v);
+					if (atom.total_time != -1 && cur_tm < atom.total_time) active_timers++;
+				}
+			}
+			if (active_timers) active_timers = 1;
+			cmd.SetSysvar(active_timers);
+		} else if (cmd.cmd3 == 0x1f4) {
+			TimerAtom& atom = timer_var[cmd.args[0].value];
+			atom.from = cmd.args[1].value;
+			atom.to = cmd.args[2].value;
+			atom.total_time = cmd.args[3].value;
+			atom.start_time = old_time;
+			cmd.clear();
+		} else if (cmd.cmd3 == 0x3e8) {
+			/* rand() */
+			int min = 0, max;
+			if (cmd.args.size() == 2) {
+				min = cmd.args[0].value;
+				max = cmd.args[1].value;
+			} else {
+				max = cmd.args[1].value;
+			}
+			if (min > max) {
+				int tmp = max;
+				max = min;
+				min = tmp;
+			}
+			int r = random();
+			if (min == max) r = min;
+			else r = (r % (max-min)) + min;
+			cmd.SetSysvar(r);
+		} else if (cmd.cmd3 == 0x3ea) {
+			int val = cmd.args[0].value;
+			if (val < 0) val = -val;
+			cmd.SetSysvar(val);
+		} else if (cmd.cmd3 == 0x3ec) {
+			/* min だよなあ・・・*/
+			int min = cmd.args[0].value;
+			int max = cmd.args[1].value;
+			if (max < min) min = max;
+			cmd.SetSysvar(min);
+		} else if (cmd.cmd3 == 0x3ef) {
+			/* min */
+			int min = cmd.args[0].value;
+			int max = cmd.args[1].value;
+			if (max < min) min = max;
+			cmd.SetSysvar(min);
+		} else if (cmd.cmd3 == 0x320) {
+			/* range conversion : 比率に丸める */
+			// アルゴリズムは間違えてるような気がする
+			// 
+			if (cmd.args.size() >= 7) {
+				int val = cmd.args[0].value;
+				int offset = cmd.args[1].value;
+				int r_min = cmd.args[2].value;
+				int v_min = cmd.args[3].value;
+				int v_max = cmd.args[4].value;
+				int r_max = cmd.args[5].value;
+				int mode = cmd.args[6].value;
+				// rldev : mode == 1,3 : 'acceralating curve', 2,3: 'decelerating curve'
+				// 複数の引数リスト(r_minからmodeまでのリスト)もつこともあり、その場合は
+				// "cancel out in some way" らしい
+				if (mode == 1 || mode == 3) val += offset;
+				else if (mode == 2 || mode == 4) val -= offset;
+if (cmd.args.size() != 7)
+	fprintf(stderr,"\n%d/%d: cmd 01-04:0320 : XXXX NOT SUPPORTED LIST : DOUBLE RANGE CONVERSION!   XXXXXXXXXXX\n",cmd.scn,cmd.pos);
+				if (val < v_min) val = v_min;
+				if (val > v_max) val = v_max;
+				val = (r_max-r_min)*(val-v_min)/(v_max-v_min) + r_min;
+				cmd.SetSysvar(val);
+			}
+		} else if (cmd.cmd3 == 0x3f1) {
+			/* range 内に丸める */
+			int min = cmd.args[0].value;
+			int val = cmd.args[1].value;
+			int max = cmd.args[2].value;
+			if (min > max) {
+				int tmp = max;
+				max = min;
+				min = tmp;
+			}
+			if (val < min) val = min;
+			if (val > max) val = max;
+			cmd.SetSysvar(val);
+		} else if (cmd.cmd3 == 0x16c && cmd.cmd4 == 0) {
+		/* なんかよくわからないけどカーソル形状変更にしとく */
+			SetCursor(cmd.args[0].value);
+			cmd.clear();
+		} else if (cmd.cmd3 == 0x0bc1) { // メニューからのロード
+			cmd.cmd_type = CMD_LOADREQ;
+		} else if ( (cmd.cmd3 >= 0x8d4 && cmd.cmd3 <= 0x8d8) || cmd.cmd3 == 0x8db || cmd.cmd3 == 0x93f || cmd.cmd3 == 0xa39) {
+			// テキストウィンドウの色設定
+			int r, g, b, a, flag;
+			if (cmd.cmd3 == 0xa39) { // 元設定を取り出す
+				config.GetOriginalParam("#WINDOW_ATTR", 5, &r, &g, &b, &a, &flag);
+			} else {
+				config.GetParam("#WINDOW_ATTR", 5, &r, &g, &b, &a, &flag);
+			}
+			if (cmd.cmd3 == 0xa39 || cmd.cmd3 == 0x93f) { // 設定を変数に取り出す
+				if (cmd.args.size() != 5) {
+					fprintf(stderr,"cmd 01-04:%4d : invalid arg size\n", cmd.cmd3);
+				} else {
+					vector<VarInfo> args(cmd.args);
+					cmd.SetFlagvar(args[0], r);
+					cmd.SetFlagvar(args[1], g);
+					cmd.SetFlagvar(args[2], b);
+					cmd.SetFlagvar(args[3], a);
+					cmd.SetFlagvar(args[4], flag);
+				}
+			} else {
+				switch(cmd.cmd3) {
+				case 0x8d4: r = cmd.args[0].value; break;
+				case 0x8d5: g = cmd.args[0].value; break;
+				case 0x8d6: b = cmd.args[0].value; break;
+				case 0x8d7: a = cmd.args[0].value; break;
+				case 0x8d8: flag = cmd.args[0].value; break;
+				case 0x8db: 
+					r = cmd.args[0].value;
+					g = cmd.args[1].value;
+					b = cmd.args[2].value;
+					a = cmd.args[3].value;
+					flag = cmd.args[4].value;
+					break;
+				}
+				config.SetParam("#WINDOW_ATTR", 5, r, g, b, a, flag);
+				SetWindowColor(r, g, b, a, flag);
+				cmd.clear();
+			}
+		} else if (cmd.cmd3 == 0xa28 || cmd.cmd3 == 0xa29 || cmd.cmd3 == 0xa2c || cmd.cmd3 == 0xa2d || cmd.cmd3 == 0xa2e) {
+			int v = 0;
+			switch(cmd.cmd3) {
+			case 0xa28: case 0xa2d: config.GetOriginalParam("#INIT_MESSAGE_SPEED", 1, &v); break;
+			case 0xa29: config.GetOriginalParam("#INIT_MESSAGE_SPEED_MOD", 1, &v); break;
+			case 0xa2c: config.GetOriginalParam("#MESSAGE_KEY_WAIT_USE", 1, &v); break;
+			case 0xa2e: config.GetOriginalParam("#MESSAGE_KEY_WAIT_TIME", 1, &v); break;
+			}
+			cmd.SetSysvar(v);
+		} else if (cmd.cmd3 == 0x913 || cmd.cmd3 == 0x914 || cmd.cmd3 == 0x92f || cmd.cmd3 == 0x8af || cmd.cmd3 == 0x8b0 || cmd.cmd3 == 0x8cb) {
+			// テキスト表示速度関連
+			int m, speed;
+			config.GetParam("#INIT_MESSAGE_SPEED", 1, &speed);
+			config.GetParam("#INIT_MESSAGE_SPEED_MOD", 1, &m);
+if (cmd.cmd3 == 0x913 || cmd.cmd3 == 0x92f) fprintf(stderr,"TEXT speed %d\n",speed);
+else if (cmd.cmd3 == 0x914) fprintf(stderr,"TEXT mode %d\n",m);
+else if (cmd.cmd3 == 0x8af || cmd.cmd3 == 0x8cb) fprintf(stderr,"TEXT %d, %d <- speed %d\n",m,speed,cmd.args[0].value);
+else fprintf(stderr,"TEXT %d, %d <- mode %d\n",m,speed,cmd.args[0].value);
+			if (cmd.cmd3 == 0x913 || cmd.cmd3 == 0x92f) cmd.SetSysvar(speed);
+			else if (cmd.cmd3 == 0x914) cmd.SetSysvar(m);
+			else {
+				if (cmd.cmd3 == 0x8af || cmd.cmd3 == 0x8cb) speed = cmd.args[0].value;
+				else m = cmd.args[0].value;
+				if (speed < 10) speed = 10;
+				else if (speed > 1000) speed = 1000;
+				config.SetParam("#INIT_MESSAGE_SPEED", 1, speed);
+				config.SetParam("#INIT_MESSAGE_SPEED_MOD", 1, m);
+				if (m) speed = -1;
+				SetTextSpeed(speed);
+				cmd.clear();
+			}
+		} else if (cmd.cmd3 == 0x92e || cmd.cmd3 == 0x930 || cmd.cmd3 == 0x8ca || cmd.cmd3 == 0x8cc) {
+			// テキストオートモード関連
+			int m, wait;
+			config.GetParam("#MESSAGE_KEY_WAIT_USE", 1, &m);
+			config.GetParam("#MESSAGE_KEY_WAIT_TIME", 1, &wait);
+if (cmd.cmd3 == 0x92e) fprintf(stderr,"AUTO mode %d\n",m);
+else if (cmd.cmd3 == 0x930) fprintf(stderr,"AUTO wait %d\n",wait);
+else if (cmd.cmd3 == 0x8ca) fprintf(stderr,"AUTO %d,%d <- mode %d\n",m,wait,cmd.args[0].value);
+else fprintf(stderr,"AUTO %d,%d <- wait %d\n",m,wait,cmd.args[0].value);
+
+			if (cmd.cmd3 == 0x92e) cmd.SetSysvar(m);
+			else if (cmd.cmd3 == 0x930) cmd.SetSysvar(wait);
+			else {
+				if (cmd.cmd3 == 0x8ca) m = cmd.args[0].value;
+				else wait = cmd.args[1].value;
+				if (wait < 0) wait = 0;
+				else if (wait > 60000) wait = 60000;
+				config.SetParam("#MESSAGE_KEY_WAIT_USE", 1, m);
+				config.SetParam("#MESSAGE_KEY_WAIT_TIME", 1, wait);
+				if (m) SetTextWait(wait);
+				else SetTextWait(-1);
+				cmd.clear();
+			}
+		} else if (cmd.cmd3 == 0x51f && cmd.cmd4 == 0) { // replace_name2 の設定
+			int n = cmd.args[0].value;
+			if (n>=0 && n<26) {
+				replace_name2[n] = cmd.Str(cmd.args[1]);
+			}
+			cmd.clear();
+		} else if (cmd.cmd3 == 0x51e && cmd.cmd4 == 0) { // replace_name2 を得る
+			int n = cmd.args[0].value;
+			if (n >= 0 && n < 26) {
+				cmd.SetStrvar(cmd.args[1], replace_name2[n]);
+			} else {
+				cmd.SetStrvar(cmd.args[1], "");
+			}
+		} else if (cmd.cmd3 == 0x514 && cmd.cmd4 == 0) { // replace_name を得る
+			int n = cmd.args[0].value;
+			if (n >= 0 && n < 26) {
+				cmd.SetStrvar(cmd.args[1], replace_name[n]);
+			} else {
+				cmd.SetStrvar(cmd.args[1], "");
+			}
+		}
+	}
+
+	return;
+}
+extern int print_blit;
+bool TextImpl::Wait(unsigned int current_time, Cmd& cmd) {
+	if (current_time != 0xffffffffUL) old_time = current_time;
+/*
+if (event.presscount(MOUSE_UP)) {
+if (text) text->Pic()->ReBlit();
+}
+if (event.presscount(MOUSE_DOWN)) {
+print_blit^=1;
+}
+*/
+
+	if (status == NORMAL && status_mask == NORMAL) return false;
+	
+	if (status_mask & WAIT_EXTRN_MASK) return true;
+	if (status_mask & (BACKLOG_MASK|BACKLOG_MASK_FWD) ) {
+		if (status_mask & BACKLOG_WAIT_MASK) ;
+		else {
+			if ( (status == WAIT_TEXT && text != 0) || status == WAIT_SELECT_INBOX || status == WAIT_SELECT_OUTBOX) {
+				if(text && text->wid->status != WidText::PREPARE && text->wid->status != WidText::WAIT && text->wid->status != WidText::WAIT2) {
+					text->wid->Flush(); // 表示を最後の状態にする
+				}
+				if (status == WAIT_TEXT && text != 0 && kcursor) kcursor->show();
+			}
+		}
+		if (status_mask & BACKLOG_MASK) {
+			cmd.cmd_type = CMD_BACKLOGREQ;
+		} else {
+			cmd.cmd_type = CMD_BACKLOGREQ_FWD;
+		}
+		status_mask = Status(status_mask & ~(BACKLOG_MASK|BACKLOG_MASK_FWD));
+		return false;
+	}
+	if ( (status_mask & BACKLOG_WAIT_MASK) && (status_mask & BACKLOG_MASK_KOE)) {
+		if (drawn_backlog_item.koe != -1) {
+			cmd.cmd_type = CMD_OTHER;
+			cmd.cmd1 = 1;
+			cmd.cmd2 = 0x17;
+			cmd.cmd3 = 0;
+			cmd.cmd4 = 1;
+			cmd.args.clear();
+			cmd.args.push_back(VarInfo(drawn_backlog_item.koe));
+			cmd.args.push_back(VarInfo(0));
+		}
+		status_mask = Status(status_mask & ~BACKLOG_MASK_KOE);
+		return false;
+	}
+	if (skip_mode & SKIP_IN_MENU) return false;
+	if (status_mask & SAVEMASK) {
+		cmd.cmd_type = CMD_SAVEREQ;
+		status_mask = Status(status_mask & ~SAVEMASK);
+		return false;
+	}
+	if (status_mask & LOADMASK) {
+		cmd.cmd_type = CMD_LOADREQ;
+		status_mask = Status(status_mask & ~LOADMASK);
+		return false;
+	}
+	if (status_mask & SKIPEND_MASK) {
+		if ( (skip_mode & SKIP_TEXT) && (skip_mode & SKIPEND_TEXT)) {
+			if (skip_mode & SKIPEND_KEY) { // shift skip 中
+				SkipMode new_mode = SkipMode(skip_mode & (~SKIPEND_TEXT));
+				if (new_mode & (SKIP_GRP_NOEFFEC || SKIP_GRP_NODRAW))
+					new_mode = SkipMode(new_mode & (~SKIP_GRP_FAST));
+				cmd.SetSysvar(TYPE_SYS_SKIPMODE, new_mode);
+			} else {
+				cmd.SetSysvar(TYPE_SYS_SKIPMODE, SKIP_NO);
+			}
+		}
+		status_mask = Status(status_mask & ~SKIPEND_MASK);
+	}
+	if (status_mask & SKIPMASK) {
+		if (skip_mode != SKIP_NO) {
+			cmd.SetSysvar(TYPE_SYS_SKIPMODE, skip_mode | SKIPEND_TEXT);
+		} else {
+			cmd.SetSysvar(TYPE_SYS_SKIPMODE, SKIP_TEXT | SKIP_GRP_FAST | SKIPEND_TEXT);
+		}
+		status_mask = Status(status_mask & ~SKIPMASK);
+		return false;
+	}
+	if (event.presscount(MOUSE_RIGHT)) {
+		if ( (status == WAIT_TEXT && text != 0) || status == WAIT_SELECT_INBOX || status == WAIT_SELECT_OUTBOX) {
+			if(text && text->wid->status != WidText::PREPARE && text->wid->status != WidText::WAIT && text->wid->status != WidText::WAIT2) {
+				text->wid->Flush(); // 表示を最後の状態にする
+			}
+			cmd.cmd_type = CMD_MENUREQ;
+			if (!(status_mask & STATSAVE_MASK)) {
+				status_saved = status;
+				status_mask = Status(status_mask | STATSAVE_MASK);
+			}
+			return false;
+		} else if (status == WAIT_CLICK_MOUSEPOS) {
+			status = WAIT_CLICK_MOUSEPOSEND_R;
+		}
+	}
+	if (event.presscount(MOUSE_UP)) {
+		if ( (status == WAIT_TEXT && text != 0) || status == WAIT_SELECT_INBOX || status == WAIT_SELECT_OUTBOX) {
+			if(text && text->wid->status != WidText::PREPARE && text->wid->status != WidText::WAIT && text->wid->status != WidText::WAIT2) {
+				text->wid->Flush(); // 表示を最後の状態にする
+			}
+			cmd.cmd_type = CMD_BACKLOGREQ;
+			if (!(status_mask & STATSAVE_MASK)) {
+				status_saved = status;
+				status_mask = Status(status_mask | STATSAVE_MASK);
+			}
+			return false;
+		}
+	}
+	if (status_mask & CLEARSCR_MASK) {
+		if ( (status == WAIT_TEXT && text != 0 ) || status == WAIT_SELECT_INBOX || status == WAIT_SELECT_OUTBOX) {
+			if (skip_mode) skip_mode = SKIP_NO;
+			if (text && text->wid->status != WidText::PREPARE && text->wid->status != WidText::WAIT && text->wid->status != WidText::WAIT2) {
+				text->wid->Flush(); // 表示を最後の状態にする
+				return true;
+			}
+			status_mask = Status(status_mask & (~CLEARSCR_MASK) | CLEARSCR_WAIT_MASK);
+			if (text) text->hide();
+			if (kcursor) kcursor->hide();
+			if (sel_widget) sel_widget->hide();
+			if (backlog_widget) backlog_widget->hide();
+			return true;
+		}
+		status_mask = Status(status_mask & (~CLEARSCR_MASK));
+		return false;
+	}
+	if (status_mask & CLEARSCR_WAIT_MASK) {
+		return true;
+	}
+	if (status == WAIT_TEXT) {
+		if (text == 0) { status = NORMAL; return false;}
+		if (skip_mode & SKIP_TEXT) {
+		} else if (text->wid->status != WidText::PREPARE) {
+			return true;
+		}
+		if (kcursor) kcursor->hide();
+		text_stream.Clear();
+		status = NORMAL;
+		cmd.cmd_type = CMD_TEXTEND;
+		return false;
+	}
+	if (status == WAIT) {
+		if (skip_mode & SKIP_TEXT) ;
+		else if (wait_time > current_time) return true;
+		status = NORMAL;
+	} else if (status == WAIT_CLICK) {
+		if (skip_mode & SKIP_TEXT) ;
+		else if (wait_time > current_time) return true;
+		status = NORMAL;
+		cmd.SetSysvar(0);
+	} else if (status == WAIT_ABORT) {
+		cmd.SetSysvar(1);
+		status = NORMAL;
+	} else if (status == WAIT_CLICK_MOUSEPOS || status == WAIT_CLICK_MOUSEPOSEND_L || status == WAIT_CLICK_MOUSEPOSEND_R) {
+		if (status == WAIT_CLICK_MOUSEPOS && (skip_mode & SKIP_TEXT) == 0) return true; // keep wait
+		else {
+			int x, y;
+			event.MousePos(x,y);
+			if (status == WAIT_CLICK_MOUSEPOS) x = y = 0; // skip mode
+			cmd.clear();
+			cmd.SetFlagvar(wait_savedvar[0], x);
+			cmd.SetFlagvar(wait_savedvar[1], y);
+			if (status == WAIT_CLICK_MOUSEPOSEND_R) cmd.SetSysvar(-1);
+			else cmd.SetSysvar(0);
+			status = NORMAL;
+		}
+	} else if (status == WAIT_SELECT_INBOX || status == WAIT_SELECT_OUTBOX) {
+		return true;
+	} else if ( int(status) >= WAIT_SELECT_VALUE) {
+		int sel_val = int(status) - WAIT_SELECT_VALUE;
+		cmd.SetSysvar(sel_val);
+		selects.clear();
+		delete sel_widget;
+		sel_widget = 0;
+		status = NORMAL;
+		// CreateSelect() で作成された cur_backlog_item を backlog_item へ反映させる
+		cur_backlog_item.text.InsertColor(sel_backlog_pos[sel_val], sel_backlog_pos[sel_val+1], 0xff, 0, 0);
+		backlog_item = cur_backlog_item;
+		cur_backlog_item.Clear();
+	}
+	return false;
+}
+
+void clearbtn_press(void* pointer, WidButton* button) {
+	if (pointer == 0) return;
+	TextImpl* t = (TextImpl*)pointer;
+	t->status_mask = TextImpl::Status(t->status_mask | TextImpl::CLEARSCR_MASK);
+	return;
+}
+void TextImpl::PressFuncSkip(void* pointer, WidButton* from) {
+	if (pointer == 0) return;
+	TextImpl* t = (TextImpl*)pointer;
+	t->status_mask = TextImpl::Status(t->status_mask | TextImpl::SKIPMASK);
+	return;
+}
+void TextImpl::PressFuncLoad(void* pointer, WidButton* from) {
+	if (pointer == 0) return;
+	TextImpl* t = (TextImpl*)pointer;
+	t->status_mask = TextImpl::Status(t->status_mask | TextImpl::LOADMASK);
+	return;
+}
+void TextImpl::PressFuncSave(void* pointer, WidButton* from) {
+	if (pointer == 0) return;
+	TextImpl* t = (TextImpl*)pointer;
+	t->status_mask = TextImpl::Status(t->status_mask | TextImpl::SAVEMASK);
+	return;
+}
+void TextImpl::PressFuncBacklog(void* pointer, WidButton* from) {
+	if (pointer == 0) return;
+	TextImpl* t = (TextImpl*)pointer;
+	t->status_mask = TextImpl::Status(t->status_mask | TextImpl::BACKLOG_MASK);
+	return;
+}
+void TextImpl::PressFuncBacklogFwd(void* pointer, WidButton* from) {
+	if (pointer == 0) return;
+	TextImpl* t = (TextImpl*)pointer;
+	t->status_mask = TextImpl::Status(t->status_mask | TextImpl::BACKLOG_MASK_FWD);
+	return;
+}
+void movebtn_drag(int from_x, int from_y, int x, int y, void* pointer, WidButton* button) {
+	if (pointer == 0) return;
+	fprintf(stderr,"drag.\n");
+}
+#define BTNCNT 10
+static char* btnname[BTNCNT] = {
+	"MOVE",
+	"CLEAR",
+	"READJUMP",
+	"AUTOMODE",
+	"MSGBK",
+	"MSGBKLEFT",
+	"MSGBKRIGHT",
+	"EXBTN_000",
+	"EXBTN_001",
+	"EXBTN_002"
+};
+static int btnpos[BTNCNT] = { // g00 ファイル内のボタン情報の位置
+//	0, 1, 13, 12, 2, 3, 4, 5, 6, 7 // princess bride?
+	0, 1, 13, 14, 2, 3, 4, 5, 6, 7 // tomoyo after?
+};
+static WidButton::PressFunc btnpress[BTNCNT] = {
+	0, clearbtn_press, &TextImpl::PressFuncSkip,0,&TextImpl::PressFuncBacklogFwd,&TextImpl::PressFuncBacklog,&TextImpl::PressFuncBacklogFwd,&TextImpl::PressFuncSave,&TextImpl::PressFuncLoad,0
+};
+static WidButton::DragFunc btndrag[BTNCNT] = {
+	movebtn_drag, 0,0,0,0, 0,0,0,0, 0
+};
+
+void TextImpl::SetTextSpeed(int speed) {
+	// 100 : 10char / sec
+	// 10 : 100char / sec
+	// text widget:
+	if (speed <= 0) speed = -1;
+	else if (speed > 1000) speed = 1;
+	else speed = 1000 / speed;
+	int i;
+	for (i=0; i<32; i++)
+		if (widgets[i]) widgets[i]->wid->SetSpeed(speed);
+}
+void TextImpl::SetTextWait(int wait) {
+	int i;
+	for (i=0; i<32; i++)
+		if (widgets[i]) widgets[i]->wid->SetWait(wait);
+}
+
+void TextImpl::SetWindowColor(int r, int g, int b, int a, bool is_transparent) {
+	char key[1024];
+	int w;
+
+	for (w=0; w<32; w++) {
+		if (widgets[w] == 0) continue;
+		sprintf(key, "#WAKU.%03d.000.BACK", w);
+		const char* back = config.GetParaStr(key);
+		if (back == 0 || back[0] == 0) continue;
+		sprintf(key, "%s.g00", back);
+		Surface* back_s = parent.Root().NewSurface(key);
+		if (back_s == 0) continue;
+		Rect rect(*back_s);
+		Surface* new_s = parent.Root().NewSurface(rect.width(), rect.height(), ALPHA_MASK);
+		DSurfaceMove(back_s, rect, new_s, rect);
+		DSurfaceFillA(new_s, rect, r, g, b, a);
+		widgets[w]->wid->Pic()->SetSurface(new_s, 0, 0);
+		widgets[w]->wid->Pic()->SetSurfaceFreeFlag(1);
+		if (!is_transparent)
+			widgets[w]->wid->Pic()->SetSurfaceAttribute(PicBase::BLIT_MULTIPLY);
+		parent.Root().DeleteSurface(back_s);
+	}
+	return;
+}
+
+void TextImpl::SetCursor(int cursor_no) {
+	char key[1024];
+	sprintf(key, "#CURSOR.%03d.NAME", cursor_no);
+	string path = config.GetParaStr(key);
+	if (path.length() == 0) return; // 名前なし
+	path += ".pdt";
+	int w,h,cont,speed;
+	sprintf(key, "#CURSOR.%03d.SIZE", cursor_no);
+	config.GetParam(key, 2, &w, &h);
+	sprintf(key, "#CURSOR.%03d.CONT", cursor_no);
+	config.GetParam(key, 1, &cont);
+	sprintf(key, "#CURSOR.%03d.SPEED", cursor_no);
+	config.GetParam(key, 1, &speed);
+
+	// speed で1周、cont 回変化
+	if (kcursor) delete kcursor;
+
+	kcursor = new WidTimeCursor(event, speed/cont, &parent, path.c_str(), 0, 0, w, 0, cont, Rect(0,0,w,h));
+	int i;
+	for (i=0; i<32; i++) {
+		if (widgets[i]) widgets[i]->wid->SetCursor(kcursor);
+	}
+}
+
+void kconv(const unsigned char* src, unsigned char* dest) {
+	/* input : sjis output: euc */
+	while(*src) {
+		unsigned int high = *src++;
+		if (high < 0x80) {
+			/* ASCII */
+			*dest++ = high; continue;
+		} else if (high < 0xa0) {
+			/* SJIS */
+			high -= 0x71;
+		} else if (high < 0xe0) {
+			/* hankaku KANA */
+			*dest++ = 0x8e; *dest++ = high;
+			continue;
+		} else { /* high >= 0xe0 : SJIS */
+			high -= 0xb1;
+		}
+		/* SJIS convert */
+		high = (high<<1) + 1;
+
+		unsigned int low = *src++;
+		if (low == 0) break; /* incorrect code */
+		if (low > 0x7f) low--;
+		if (low >= 0x9e) {
+			low -= 0x7d;
+			high++;
+		} else {
+			low -= 0x1f;
+		}
+		*dest++ = high | 0x80; *dest++ = low | 0x80;
+	}
+	*dest = 0;
+}
+void kconv_rev(const unsigned char* src, unsigned char* dest) {
+	/* input : euc output: sjis */
+	while(*src) {
+		unsigned int high = *src++;
+		if (high < 0x80) {
+			/* ASCII */
+			*dest++ = high; continue;
+		} else if (high == 0x8e) { /* hankaku KANA */
+			high = *src;
+			if (high >= 0xa0 && high < 0xe0)
+				*dest++ = *src++;
+			continue;
+		} else {
+			unsigned int low = *src++;
+			if (low == 0) break; /* incorrect code , EOS */
+			if (low < 0x80) continue; /* incorrect code */
+			/* convert */
+			low &= 0x7f; high &= 0x7f;
+			low += (high & 1) ? 0x1f : 0x7d;
+			high = (high-0x21)>>1;
+			high += (high > 0x1e) ? 0xc1 : 0x81;
+			*dest++ = high;
+			if (low > 0x7f) low++;
+			*dest++ = low;
+		}
+	}
+	*dest = 0;
+}
+string kconv(const string& s) {
+	char* out = new char[s.length()*2+100];
+	kconv((const unsigned char*)s.c_str(), (unsigned char*)out);
+	string ret = out;
+	delete[] out;
+	return ret;
+}
+string kconv_rev(const string& s) {
+	char* out = new char[s.length()*2+100];
+	kconv_rev((const unsigned char*)s.c_str(), (unsigned char*)out);
+	string ret = out;
+	delete[] out;
+	return ret;
+}
+
+/**************************************************************::
+**
+**	Text
+*/
+Text::Text(Event::Container& _event, PicContainer& _parent, AyuSysConfig& config) {
+	pimpl = new TextImpl(_event, _parent, config, backlog, backlog_item);
+}
+Text::~Text() {
+	delete pimpl;
+}
+void Text::InitWindow(void) {
+	pimpl->InitWindow();
+}
+void Text::Exec(Cmd& cmd) {
+	pimpl->Exec(cmd);
+}
+bool Text::Wait(unsigned int current_time, Cmd& cmd) {
+	return pimpl->Wait(current_time, cmd);
+}
+void Text::SetSkipMode(SkipMode mode) {
+	pimpl->SetSkipMode(mode);
+}
+void Text::Save(std::string& str, bool select_save) {
+	pimpl->Save(str, select_save);
+}
+void Text::Load(const char* str) {
+	pimpl->Load(str);
+}
+
+void Text::hide(void) {
+	pimpl->hide();
+}
+void Text::show(void) {
+	pimpl->show();
+}
+void Text::show(int num) {
+	pimpl->show(num);
+}
+void Text::DrawBacklog(BacklogItem& item, Cmd& cmd) {
+	pimpl->DrawBacklog(item, cmd);
+}
+/**************************************************************::
+**
+**	BacklogItem
+*/
+
+BacklogItem::BacklogItem(void) {
+	scn = -1;
+	pos = -1;
+	koe = -1;
+	face = "";
+	text.kanji_type = TextStream::sjis;
+}
+void BacklogItem::Clear(void) {
+	scn = -1;
+	pos = -1;
+	koe = -1;
+	text.Clear();
+}
+void BacklogItem::AddTextPos(Cmd& cmd) {
+	if (scn == -1 && pos == -1) {
+		scn = cmd.scn;
+		pos = cmd.pos;
+		return;
+	}
+	DeleteTextPos();
+}
+void BacklogItem::DeleteTextPos(void) {
+	scn = 0;
+	pos = -1;
+}
+BacklogItem& BacklogItem::operator =(const BacklogItem& p) {
+	scn = p.scn;
+	pos = p.pos;
+	koe = p.koe;
+	face = p.face;
+	text = p.text;
+}
+void BacklogItem::SetSavepos(int p) {
+	Clear();
+	scn = SaveSelect;
+	pos = p;
+}
+
+Rect TextWindow::WakuSize(PicContainer& pic, int waku_no, const AyuSysConfig& config) {
+	char key[1024];
+	sprintf(key, "#WAKU.%03d.000.NAME", waku_no);
+	const char* name = config.GetParaStr(key);
+	if (!name) return Rect(0,0,0,0);
+	std::string str = name; str += ".g00";
+	Surface* s = pic.Root().NewSurface(str.c_str());
+	if (!s) return Rect(0,0,0,0);
+	Rect r(*s);
+	pic.Root().DeleteSurface(s);
+	return r;
+}
+void TextWindow::MakeWaku(PicContainer& pic, Event::Container& event, int waku_no, int window_no, bool* use_btn, const AyuSysConfig& config, void* callback) {
+	char key[1024];
+	std::string str;
+	/* 枠を作成 */
+	sprintf(key, "#WAKU.%03d.000.NAME", waku_no);
+	const char* name = config.GetParaStr(key);
+	if (name && name[0] == 0) name = 0;
+	sprintf(key, "#WAKU.%03d.000.BACK", waku_no);
+	const char* back = config.GetParaStr(key);
+	if (back && back[0] == 0) back = 0;
+	sprintf(key, "#WAKU.%03d.000.BTN", waku_no);
+	const char* btn = config.GetParaStr(key);
+	if (btn && btn[0] == 0) btn = 0;
+
+	if (name == 0 && back == 0 && btn == 0) return;
+
+	/* まず、テキスト背景を設定 */
+	if (back) {
+		str = back; str += ".g00";
+		int rc,gc,bc,ac, flag;
+		char key[1024];
+		sprintf(key, "#WINDOW.%03d.ATTR", window_no);
+		if (config.GetParam(key, 5, &rc, &gc, &bc, &ac, &flag) == -1) {
+			config.GetParam("#WINDOW_ATTR", 5, &rc, &gc, &bc, &ac, &flag);
+		}
+		Surface* back_s = pic.Root().NewSurface(str.c_str());
+		if (back_s) {
+			Rect rect(*back_s);
+			Surface* s = pic.Root().NewSurface(rect.width(), rect.height(), ALPHA_MASK);
+			DSurfaceMove(back_s, rect, s, rect);
+			DSurfaceFillA(s, rect, rc, gc, bc, ac); // 透明度設定
+			pic.SetSurface(s, 0, 0);
+			pic.SetSurfaceFreeFlag(1);
+			if (flag == 0) wid->Pic()->SetSurfaceAttribute(PicBase::BLIT_MULTIPLY);
+			pic.Root().DeleteSurface(back_s);
+		}
+	}
+	/* その前に枠飾りを設定 */
+	if (name) {
+		str = name; str += ".g00";
+		Surface* s = pic.Root().NewSurface(str.c_str());
+		if (s) {
+			Rect rect(*s);
+			pic.Root().DeleteSurface(s);
+			PicBase* p = pic.create_leaf(Rect(0, 0, rect.width(), rect.height()),0);
+			p->SetSurface(str.c_str(), 0, 0);
+			p->ZMove(ZMOVE_BOTTOM);
+			p->show();
+		}
+	}
+	if (btn == 0) return;
+	if (use_btn == 0) return;
+	// ボタンの作成
+	// 使用するボタンについては、必要に応じて show() すること
+
+	/* ボタンの位置情報を求める */
+	str = btn; str += ".g00";
+	ARCINFO* info = file_searcher.Find(FILESEARCH::PDT, str.c_str(), "g00");
+	if (info == 0) return; // cannot find file
+	const char* data = info->Read();
+	/* g00 ファイルのヘッダ部分に位置情報は入っている */
+	/* 存在しなければボタン画像ではない */
+	if (data == 0 || *data != 2) {
+		delete info;
+		return;
+	}
+	int index_count = read_little_endian_int(data+5); // 0x70 == 112 ( 8 個ずつグループなので、14個のボタン ) が標準
+	int i;
+	for (i=0; i<BTNCNT; i++) {
+		if (!use_btn[i]) continue;
+		if (btnpos[i]*8 >= index_count) {
+			continue; // ボタンが存在しない
+		}
+		int x, y, w, h;
+		sprintf(key, "#WAKU.%03d.000.%s_BOX", waku_no, btnname[i]);
+		if (config.GetParam(key, 5, 0, &x, &y, &w, &h) == -1) continue;
+		int sx, sy, sdx, sdy, cnt;
+		const char* d = data + 9 + btnpos[i]*24*8;
+		sx = read_little_endian_int(d);
+		sy = read_little_endian_int(d+4);
+		sdx = read_little_endian_int(d+24) - sx;
+		sdy = read_little_endian_int(d+24 + 4) - sy;
+		cnt = 2;
+		if (sx+sdx*2 == read_little_endian_int(d+2*24) && sy+sdy*2 == read_little_endian_int(d+2*24+4)) cnt = 3;
+		WidButton* wid = new WidButton(event, &pic, str.c_str(), sx, sy, sdx, sdy, cnt, Rect(x, y, x+w, y+h), 1);
+		if (btnpress[i]) { wid->press_func = btnpress[i]; wid->press_pointer = callback;}
+		if (btndrag[i]) { wid->drag_func = btndrag[i]; wid->drag_pointer = callback;}
+	}
+	delete info;
+	return;
+}
+
+TextWindow::TextWindow(PicContainer& parent, Event::Container& event, int win_no, const AyuSysConfig& config, void* callback) :
+	wid(0), name_visible(true),name(0),name_container(0), face(0) {
+	int i; for (i=0; i<8; i++) face_pics[i]=0;
+	char key[1024];
+	bool use_btn[BTNCNT];
+	int size, rep1, rep2, cntw, cnth, mposx, mposy, posd, posx, posy, minx, miny, waku_no, ruby;
+	sprintf(key, "#WINDOW.%03d.MOJI_SIZE", win_no); if (config.GetParam(key, 1, &size) == -1) return;
+	sprintf(key, "#WINDOW.%03d.MOJI_REP", win_no);  if (config.GetParam(key, 2, &rep1, &rep2) == -1) return;
+	sprintf(key, "#WINDOW.%03d.MOJI_CNT", win_no);  if (config.GetParam(key, 2, &cntw, &cnth) == -1) return;
+	sprintf(key, "#WINDOW.%03d.POS", win_no);       if (config.GetParam(key, 3, &posd, &posx, &posy) == -1) return;
+	sprintf(key, "#WINDOW.%03d.MOJI_POS", win_no);  if (config.GetParam(key, 4, &mposy, 0, &mposx, 0) == -1) return;
+	sprintf(key, "#WINDOW.%03d.MOJI_MIN", win_no);  if (config.GetParam(key, 2, &minx, &miny) == -1) return;
+	sprintf(key, "#WINDOW.%03d.WAKU_SETNO", win_no);if (config.GetParam(key, 1, &waku_no) == -1) return;
+	sprintf(key, "#WINDOW.%03d.LUBY_SIZE", win_no); if (config.GetParam(key, 1, &ruby) == -1) return;
+
+	/* テキストウィジット:画面の右下一杯まで使用 */
+	/* posd == 2 なら画面下にひっつくように配置 */
+	Rect r(0,0);
+	if (posd == 2) {
+		r = WakuSize(parent, waku_no, config);
+		r = Rect(0, parent.Height()-r.height(), r.width(), parent.Height());
+		posx = 0;
+		posy = parent.Height()-r.height();
+	} else /* posd == 0 ? */
+		r = Rect(posx, posy, parent.Width(), parent.Height());
+
+	/* テキストウィンドウの作成 */
+	int w = size*cntw; int h = (size+ruby+2)*cnth;
+	wid = new WidText(event, &parent, r, Rect(mposx, mposy, mposx+w, mposy+h), size);
+	wid->stream.kanji_type = TextStream::sjis;
+	/* 顔ウィンドウの作成 */
+	for (i=0; i<8; i++) {
+		int x,y;
+		sprintf(key, "#WINDOW.%03d.FACE.%03d", win_no, i);
+		if (config.GetParam(key, 2, &x, &y) == -1) continue;
+		/* 顔ウィンドウを作成する */
+		if (x >= 0 && y >= 0) {
+			face_pics[i] = wid->PicNode()->create_leaf(Rect(x,y), PicBase::FIT_SURFACE);
+		} else {
+			face_pics[i] = parent.create_leaf(Rect(x+posx,y+posy), PicBase::FIT_SURFACE);
+		}
+		face_pics[i]->show();
+	}
+	face = face_pics[0];
+	// ボタンの設定
+	for (i=0; i<BTNCNT; i++) {
+		int num;
+		sprintf(key, "#WINDOW.%03d.%s_USE", win_no, btnname[i]);
+		config.GetParam(key, 1, &num);
+		use_btn[i] = (num==0) ? false : true;
+	}
+	// make name window
+	int shadow, name_mod, name_size, name_min, name_center, name_posx, name_posy, name_mposx, name_mposy;
+	sprintf(key, "#WINDOW.%03d.MOJI_SHADOW", win_no);  config.GetParam(key, 1, &shadow);
+	sprintf(key, "#WINDOW.%03d.NAME_MOD", win_no);  config.GetParam(key, 1, &name_mod);
+	sprintf(key, "#WINDOW.%03d.NAME_MOJI_SIZE", win_no);  config.GetParam(key, 1, &name_size);
+	sprintf(key, "#WINDOW.%03d.NAME_MOJI_MIN", win_no);  config.GetParam(key, 1, &name_min);
+	sprintf(key, "#WINDOW.%03d.NAME_MOJI_POS", win_no);  config.GetParam(key, 2, &name_mposx, &name_mposy);
+	sprintf(key, "#WINDOW.%03d.NAME_CENTERING", win_no);  config.GetParam(key, 1, &name_center);
+	sprintf(key, "#WINDOW.%03d.NAME_POS", win_no);  config.GetParam(key, 2, &name_posx, &name_posy);
+	// if name_mode==0 name is in the text window
+	// if name_mode == 1 open name window
+	// if name_mode == 2 name is not used
+	if (name_mod) {
+		if (name_mod == 1) {
+			int w = name_size*name_min; int h = name_size;
+			int name_waku;
+			sprintf(key, "#WINDOW.%03d.NAME_WAKU_SETNO", win_no);
+			if (config.GetParam(key, 1, &name_waku) != -1 && name_waku != -1) {
+				Rect waku_r = WakuSize(parent, name_waku, config);
+				waku_r.rmove(r.lx, r.ty); // テキストウィンドウ位置に動かす
+				waku_r.rmove(name_posx, name_posy-waku_r.height()); // NAME_POS へ位置補正
+				name_container = parent.create_node(waku_r, 0);
+				MakeWaku(*name_container, event, name_waku, win_no, 0, config, callback);
+				Rect name_r(0,0,w,h);
+				name_r.rmove(name_mposx, name_mposy);
+				name = new WidLabel(name_container, name_r, true, 0, name_size);
+				name->show();
+			} else { // 名前専用枠なし
+				Rect name_r(0, 0, w, h);
+				name_r.rmove(r.lx, r.ty);
+				name_r.rmove(name_posx, name_posy-name_size);
+				name_container = parent.create_node(name_r, 0);
+				name = new WidLabel(name_container, Rect(0,0,w,h), true, 0, name_size);
+				name->show();
+				name_container->show();
+			}
+		} else { // name_mod == 2 or 3
+			name_container = parent.create_node( Rect(0,0,1,1), 0);
+		}
+	}
+	MakeWaku(*wid->PicNode(), event,waku_no, win_no, use_btn, config, callback);
+}
+void TextImpl::InitWindow(void) {
+	int i,j,k;
+	int w;
+	std::string str;
+
+	for (w=0; w<32; w++) {
+		widgets[w] = new TextWindow(parent, event, w, config, (void*)this);
+		if (widgets[w]->wid == 0) {
+			delete widgets[w];
+			widgets[w] = 0;
+		}
+	}
+	SetCursor(0);
+	for (i=0; i<26; i++) {
+		char buf[1024];
+		sprintf(buf, "#NAME.%c", i+'A');
+		const char* s = config.GetParaStr(buf);
+		if (s) replace_name[i] = s;
+	}
+	// replace_name2 : 初期設定
+	// 渚、秋生、渚 (CLANNAD)
+	char name_nagisa[3] = {0x8f,0x8d,0};
+	char name_akio[5] = {0x8f, 0x48, 0x90, 0xb6, 0};
+	replace_name2[0] = name_nagisa;
+	replace_name2[1] = name_akio;
+	replace_name2[2] = name_nagisa;
+	text = 0;
+	/* テキスト速度の設定 */
+	int speed, mod, wait, auto_mod;
+	config.GetParam("#INIT_MESSAGE_SPEED", 1, &speed);
+	config.GetParam("#INIT_MESSAGE_SPEED_MOD", 1, &mod);
+	config.GetParam("#MESSAGE_KEY_WAIT_USE", 1, &auto_mod);
+	config.GetParam("#MESSAGE_KEY_WAIT_TIME", 1, &wait);
+	if (mod) speed = -1;
+	if (!auto_mod) wait = -1;
+	SetTextSpeed(speed);
+	SetTextWait(wait);
+	return;
+}
new file mode 100644
--- /dev/null
+++ b/scn2k/scn2kdump.cc
@@ -0,0 +1,1360 @@
+/*
+ *
+ *  Copyright (C) 2002-   Kazunori Ueno(JAGARL) <jagarl@creator.club.ne.jp>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+*/
+
+#include<stdlib.h>
+#include<stdarg.h>
+#include<stdio.h>
+#include<string.h>
+#include<string>
+#include<vector>
+#include<map>
+
+using namespace std;
+
+#include"system/file.h"
+#include"system/file_impl.h"
+
+/* 注意点: @@@ で表記 */
+
+struct VarInfo {
+#define TYPE_VARSTR 18
+#define TYPE_VARMAX 7
+#define TYPE_STR 58
+#define TYPE_VAL 68
+#define TYPE_SYS 0xc8
+	int type;
+	int number;
+	int value;
+	VarInfo() { type = TYPE_VAL; value = 0;}
+	VarInfo(int n) { type = TYPE_VAL; value = n;}
+	VarInfo(const VarInfo& i) { type = i.type; number = i.number; value = i.value;}
+};
+class Flags {
+/* flag:
+**  type 0-5 : ローカル整数、各2000個
+**  type 6, 25 : グローバル整数、2000個
+**	type 12 : グローバル文字列、2000個 (今は無視しても良いが)
+**	type 18 : ローカル文字列、2000個
+**	type 25: システム変数(マウス座標など?) 1000 個?
+**  type 26-32, 51 : 1-bit access to 0-6, 25
+**  type 52-58, 77 : 2-bit access to 0-6, 25
+**  type 78-84, 103 : 4-bit access to 0-6, 25
+**  type 104-110, 129 : 8-bit access to 0-6, 25
+*/
+	typedef unsigned int uint;
+	int sys;
+	int var[8][2000];
+	string str[2000];
+public:
+	int operator () () const;
+	int operator () (VarInfo info) const;
+	void Str(unsigned int number, char* buf, int sz) const;
+
+	bool IsInt(int type) const;
+	int MaxIndex(int type) const;
+
+	void Set(VarInfo info, int value);
+ 	int Get(int type, int number) const;
+	void SetSys(int value);
+	void SetStr(unsigned int number, string val);
+};
+
+bool Flags::IsInt(int type) const {
+	int v = type % 26;
+	return v >= 0 && v < 7 || v == 25;
+}
+
+int Flags::MaxIndex(int type) const {
+	switch (type / 26) {
+		case 1:
+			return 63999;
+		case 2:
+			return 31999;
+		case 3:
+			return 15999;
+		case 4:
+			return 7999;
+		default:
+			return 1999;
+	}
+}
+
+int Flags::operator()() const {
+	return rand() % 10000;
+}
+int Flags::operator() (VarInfo info) const {
+	return Get(info.type, info.number);
+}
+ int Flags::Get(int type, int number) const {
+	int index = type % 26;
+	type /= 26;
+	if (index == 25) index = 7;
+	if (index > 7 || uint(type) > 4) return 0;
+	if (type == 0) {
+		// A[]..G[], Z[] を直に読む
+		if (uint(number) >= 2000) return 0;
+		return var[index][number];
+	} else {
+		// Ab[]..G4b[], Z8b[] などを読む
+		int factor = 1 << (type - 1);
+		int eltsize = 32 / factor;
+		if (uint(number) >= (64000 / factor)) return 0;
+		return (var[index][number / eltsize] >> ((number % eltsize) * factor)) & ((1 << factor) - 1);
+	}
+ }
+
+void Flags::Set(VarInfo info, int value) {
+	int type = info.type / 26;
+	int index = info.type % 26;
+	if (index == 25) index = 7;
+	if (type == 0) {
+		// A[]..G[], Z[] を直に書く
+		if (uint(info.number) >= 2000) return;
+		var[index][info.number] = value;
+	} else {
+		// Ab[]..G4b[], Z8b[] などを書く
+		int factor = 1 << (type - 1);
+		int eltsize = 32 / factor;
+		int eltmask = (1 << factor) - 1;
+		int shift = (info.number % eltsize) * factor;
+		if (uint(info.number) >= (64000 / factor)) return;
+		var[index][info.number / eltsize] =
+			(var[index][info.number / eltsize] & ~(eltmask << shift))
+		  | (value & eltmask) << shift;
+	}
+}
+
+void Flags::SetSys(int value) {
+	sys = value;
+}
+void Flags::SetStr(unsigned int number, string val) {
+	if (number >= 2000) return;
+	str[number] = val;
+}
+void Flags::Str(unsigned int number, char* buf, int sz) const {
+	if (number >= 2000) {if(sz>0) buf[0] = 0; return;}
+	const string& s = str[number];
+	int len = s.length();
+	if (sz-1 > len) sz = len;
+	s.copy(buf, sz, 0);
+	buf[sz] = 0;
+	return;
+}
+
+/* commands */
+enum Cmdtype { CMD_FLAGS, CMD_JMP, CMD_TEXT, CMD_OTHER};
+class Cmd {
+	Cmdtype cmd_type;
+	int cmd1, cmd2, cmd3, cmd4;
+	int argc;
+	bool errorflag;
+	char cmdstr[1024];
+	const Flags& flags;
+	vector<VarInfo> args;
+
+	int GetArgs(const char*& d);
+	int GetArgsSpecial(int normal_args,const char*& d);
+	void GetSelection(const char*& d);
+	int GetSwitch(const char*& d);
+	int GetSimpleSwitch(const char*& d);
+	int GetExpression(const char*& d, struct VarInfo* info = 0);
+	int GetExpressionCond(const char*& d);
+	int GetLeftToken(const char*& d, struct VarInfo& info);
+	static int GetString(const char*& d);
+	int StrVar(int number);
+	static char strtype[256];
+	static int StrType(const char* d) { return strtype[*(unsigned const char*)d];}
+	int AddStr(char* s) {
+		// 1-0a-0064 はこういうものが必要らしい
+		int start = strend;
+		while (*s) strheap[strend++] = *s++;
+		strheap[strend++] = 0;
+		return start;
+	}
+#define STRHEAP_SIZE 10000
+	static char strheap[STRHEAP_SIZE];
+	static int strend;
+	void SetError(void) { errorflag = true;}
+	static void ResetString(void) {
+		strend = 0;
+	}
+	static map<int, struct CmdDescrItem*> cmd_descr;
+	const char* CmdDescr(int cmd1, int cmd2, int cmd3, int cmd4);
+public:
+	void GetCmd(Flags& f, const char*& d);
+	bool IsError() { return errorflag;}
+	bool ClearError() { errorflag = false;}
+	Cmd(const Flags& f) : flags(f) { argc = 0; errorflag = false; cmdstr[0] = 0;}
+
+};
+
+bool debug_flag = false;
+void dprintf(const char* fmt, ...) {
+	if (debug_flag) {
+		va_list ap; va_start(ap, fmt);
+		vprintf(fmt, ap);
+		va_end(ap);
+	}
+}
+
+
+#define SCN_DUMP
+
+int system_version = 0;
+bool ruby_flag = false;
+bool ret_flag = false;
+bool text_flag = false;
+bool selection_flag = false;
+char Cmd::strheap[STRHEAP_SIZE];
+int Cmd::strend = 0;
+
+/* 数値 num := 0x24 0xff <int num> */
+/* 変数 var := 0x24 <uchar type> 0x5b <exp> 0x5d */
+/* 項 token := num | var | 0x28 <exp> 0x29 | <plus|minus> token */
+
+int Cmd::GetLeftToken(const char*& d, VarInfo& info) {
+	bool var_flag = true;
+	int minus_flag = 0;
+	int value = 0;
+	if (d[0] == 0x5c && (d[1] == 1 || d[1] == 0) ) {
+		if (d[1] == 1)	{dprintf("minus-"); minus_flag ^= 1;}
+		else dprintf("plus-");
+		d += 2;
+		var_flag = false;
+	}
+	if (d[0] == 0x24 && ((unsigned const char*)d)[1] == 0xff) {
+	// if ( (d[0] == 0x30 || d[0] == 0x31) && d[1] == 0x24 && ((unsigned const char*)d)[2] == 0xff) 	/* @@@ not supported; selection 内で、0x30|0x31 が付随することがある */
+		// numerical atom
+		d += 6;
+		value = read_little_endian_int(d-4);
+		dprintf("%d",value);
+		var_flag = false;
+	} else if (d[0] == 0x24 && *(unsigned char*)(d+1) == 0xc8) {
+		dprintf("V<sys>");
+		d += 2;
+		info.type = TYPE_SYS; info.number = 0;
+		value = info.value =  flags();
+	} else if (d[0] == 0x24 && d[2] == 0x5b) {
+		// 0x24,<type>,0x5b,<expr>,0x5d-terminated term
+		info.type = *(unsigned char*)(d+1);
+		d += 3;
+		dprintf("V<%d>[",info.type);
+		info.number = GetExpression(d);
+		dprintf("]");
+		if (*d == 0x5d) d++;
+		else SetError();
+		if (info.type == TYPE_VARSTR) {
+			value = 0;
+			info.value = StrVar(info.number);
+		} else {
+			value = info.value = flags(info);
+		}
+		dprintf("(=%d)",value);
+	} else SetError();
+
+	if (minus_flag) value = -value;
+	if (!var_flag) {
+		info.type = TYPE_VAL;
+		info.value = value;
+	}
+	return value;
+}
+
+static char* op_str[70] = {
+//	 0      1      2      3      4      5      6      7      8     9
+	"+",   "-",   "*",   "/",   "%",   "&",   "|",   "^",   "<<",  ">>",	// +00
+	"err.","err.","err.","err.","err.","err.","err.","err.","err.","err.",	// +10
+	"+=",  "-=",  "*=",  "/=",  "%=",  "&=",  "|=",  "^=",  "<<=", ">>=",	// +20
+	"=",   "err.","err.","err.","err.","err.","err.","err.","err.","err.",	// +30
+	"==",  "!=",  "<=",  "<",   ">=",  ">",   "err.","err.","err.","err.",	// +40
+	"err.","err.","err.","err.","err.","err.","err.","err.","err.","err.",	// +50
+	"&&",  "||",  "err.","err.","err.","err.","err.","err.","err.","err.",	// +60
+};
+
+static int op_pri_tbl[12] = {
+//	+  -  *  /  %  &  |  ^ << >>
+	1, 1, 0, 0, 0, 3, 5, 4, 2, 2, 10, 10};
+
+inline int op_pri(int op) {
+	if (op > 11) return 10;
+	return op_pri_tbl[op];
+}
+inline int op_pri_cond(int op) {
+	if (op <= 11) return op_pri_tbl[op];
+	else if (op < 50) return 7;
+	else if (op == 60) return 8;
+	else if (op == 61) return 9;
+	else return 10;
+}
+
+
+inline int eval(int v1, int op, int v2) {
+	switch(op) {
+		case 0: return v1+v2;
+		case 1: return v1-v2;
+		case 2: return v1*v2;
+		case 3: return v2!=0 ? v1/v2 : v1;
+		case 4: return v2!=0 ? v1%v2 : v1;
+		case 5: return v1&v2;
+		case 6: return v1|v2;
+		case 7: return v1^v2;
+		case 8: return v1<<v2;
+		case 9: return v1>>v2;
+		case 40: return v1 == v2;
+		case 41: return v1 != v2;
+		case 42: return v1 <= v2;
+		case 43: return v1 <  v2;
+		case 44: return v1 >= v2;
+		case 45: return v1 >  v2;
+		case 60: return v1 && v2;
+		case 61: return v1 || v2;
+	}
+	return v2;
+}
+
+/* 演算子 op := 0x5c <uchar op> */
+/* 数式 exp: [op] <token> [op <token> [...]] */
+int Cmd::GetExpression(const char*& d, VarInfo* info_ptr) {
+#define STACK_DEPTH 1024
+#define OP_LB 11
+	char op_stack[STACK_DEPTH];
+	int val_stack[STACK_DEPTH];
+	int stack_count = 0;
+	
+	// 第一項の読み込み
+	while(*d == 0x28) {
+		d++;
+		dprintf("(");
+		op_stack[stack_count++] = OP_LB;
+	}
+	VarInfo info;
+	int value = GetLeftToken(d, info);
+	
+	while(*d == 0x29 && stack_count > 0 && op_stack[stack_count-1] == OP_LB) {
+		d++;
+		dprintf(")");
+		stack_count--;
+	}
+	
+	if (*d != 0x5c && stack_count == 0) {
+		if (info_ptr) *info_ptr = info;
+		return value; // 単純なleft-termはここで終了。有効なinfo_ptrを帰す(可能性がある)
+	}
+	
+	while(*d == 0x5c) {
+		int op_type = *(unsigned char*)(d+1);
+		d += 2;
+		if (op_type < 70) dprintf("%s",op_str[op_type]);
+		else dprintf("err.");
+		if (op_type >= 10) SetError();
+		int cur_pri = op_pri(op_type);
+		while(stack_count != 0 && op_pri(op_stack[stack_count-1]) <= cur_pri) {
+			// 優先順位の高い、先行する演算を行う
+			value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value);
+			stack_count--;
+		}
+		val_stack[stack_count] = value;
+		op_stack[stack_count++] = op_type;
+		while(*d == 0x28) {
+			d++;
+			dprintf("(");
+			op_stack[stack_count++] = OP_LB;
+		}
+		if (stack_count >= STACK_DEPTH) SetError();
+		value = GetLeftToken(d, info);
+
+		while (*d != 0x5c && stack_count > 0) {
+			// 未実行の演算を終わらせる
+			if (op_stack[stack_count-1] != OP_LB) {
+				value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value);
+				stack_count--;
+			} else if (*d == 0x29) { /* op_stack == OP_LB */
+			// bracket 終端があれば、閉じておく
+				d++;
+				dprintf(")");
+				stack_count--;
+			} else break; // error
+		}
+	}
+	if (stack_count) SetError(); // unbalanced bracket
+	dprintf("(=%d)",value);
+	if (info_ptr) {
+		info_ptr->type = TYPE_VAL;
+		info_ptr->value = value;
+	}
+	return value;
+}
+
+// 条件分岐専用に、条件演算と算術演算の混合を検知できる専用ルーチン(本来はGetExpressionで差し支えない)
+int Cmd::GetExpressionCond(const char*& d) {
+	char op_stack[STACK_DEPTH];
+	int val_stack[STACK_DEPTH];
+	int valattr_stack[STACK_DEPTH];
+#define ATTR_VAL 0
+#define ATTR_FLAG 1
+	int stack_count = 0;
+	
+	// 第一項の読み込み
+	while(*d == 0x28) {
+		d++;
+		dprintf("(");
+		op_stack[stack_count++] = OP_LB;
+	}
+	VarInfo info;
+	int value = GetLeftToken(d, info);
+	bool valattr = ATTR_VAL;
+	
+	while(*d == 0x5c) {
+		int op_type = *(unsigned char*)(d+1);
+		d += 2;
+		if (op_type < 70) dprintf("%s",op_str[op_type]);
+		else dprintf("err.");
+		int cur_pri = op_pri_cond(op_type);
+		while(stack_count != 0 && op_pri_cond(op_stack[stack_count-1]) <= cur_pri) {
+			// 優先順位の高い、先行する演算を行う
+			if (op_stack[stack_count-1] >= 60) {
+				if (valattr_stack[stack_count-1] != ATTR_FLAG || valattr != ATTR_FLAG) SetError();
+			} else {
+				if (valattr_stack[stack_count-1] != ATTR_VAL || valattr != ATTR_VAL) SetError();
+			}
+			value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value);
+			if (op_stack[stack_count-1] >= 40) valattr = ATTR_FLAG;
+			stack_count--;
+		}
+		val_stack[stack_count] = value;
+		valattr_stack[stack_count] = valattr;
+		op_stack[stack_count++] = op_type;
+		while(*d == 0x28) {
+			d++;
+			dprintf("(");
+			op_stack[stack_count++] = OP_LB;
+		}
+		if (stack_count >= STACK_DEPTH) SetError();
+		value = GetLeftToken(d, info);
+		valattr = ATTR_VAL;
+
+		while (*d != 0x5c && stack_count > 0) {
+			// 未実行の演算を終わらせる
+			if (op_stack[stack_count-1] != OP_LB) {
+				if (op_stack[stack_count-1] >= 60) {
+					if (valattr_stack[stack_count-1] != ATTR_FLAG || valattr != ATTR_FLAG) SetError();
+				} else {
+					if (valattr_stack[stack_count-1] != ATTR_VAL || valattr != ATTR_VAL) SetError();
+				}
+				value = eval(val_stack[stack_count-1], op_stack[stack_count-1], value);
+				if (op_stack[stack_count-1] >= 40) valattr = ATTR_FLAG;
+				stack_count--;
+			// bracket 終端があれば、閉じておく
+			} else if (*d == 0x29) { /* op_stack == OP_LB */
+				d++;
+				dprintf(")");
+				stack_count--;
+			} else break; // error
+		}
+	}
+	if (stack_count) SetError(); // unbalanced bracket
+	if (value) dprintf("(=true)");
+	else dprintf("(=false)");
+	return value;
+}
+
+
+/*
+str = 
+arg = 
+args = 0x28 <exp> [[0x2c] <exp> [[0x2c] <exp> [...] ]]
+*/
+
+int Cmd::GetArgs(const char*& d) {
+	if (*d != 0x28) return 0; /* 引数なし */
+	d++;
+	dprintf("args:");
+	VarInfo var;
+	int i; for (i=0; i<100 ; i++) {
+		/* number, variable, string の種別なく値を得る */
+		if (*d == 0x61) { // よくわからない(智代アフター)
+			dprintf("@%d",d[1]);
+			d += 2;
+			if (*d == 0x28) {
+				dprintf("{");
+				GetArgs(d); // (A,B,C)節が含まれることがある
+				dprintf("}");
+			} else {
+				dprintf("{}");
+			}
+		} else if (d[0] == 0x0a || d[0] == 0x40) { // よくわからない (Little Busters!)
+			int var;
+			if (system_version == 0) { var = read_little_endian_int(d+1); d += 5;}
+			else { var = read_little_endian_short(d+1); d += 3;}
+			dprintf("line %d; ",var);
+		} else if (*d == 0x24 || (*d == 0x5c && (d[1] == 1 || d[1] == 0)) || *d == 0x28) {
+			GetExpression(d, &var);
+			args.push_back(var);
+		} else if (StrType(d)) {
+			var.type = TYPE_STR;
+			var.value = GetString(d);
+			args.push_back(var);
+		} else SetError();
+		if (*d == 0x29) break;
+		if (*d == 0x2c) {d++;} // 次の arg が演算子で始まる、などがなければ存在しない
+		dprintf(",");
+	}
+	if (*d == 0x29) d++;
+	else SetError();
+	return i;
+}
+
+int Cmd::GetArgsSpecial(int normal_args,const char*& d) {
+	if (*d != 0x28) return 0; /* 引数なし */
+	d++;
+	dprintf("args:");
+	int i; for (i=0; i<normal_args; i++) {
+		/* number, variable, string の種別なく値を得る */
+		if (*d == 0x24 || (*d == 0x5c && (d[1] == 1 || d[1] == 0)) || *d == 0x28) {
+			GetExpression(d);
+		} else if (StrType(d)) {
+			GetString(d);
+		} else SetError();
+		if (*d == 0x29) break;
+		if (*d == 0x2c) {d++;} // 次の arg が演算子で始まる、などがなければ存在しない
+		dprintf(",");
+	}
+	for (i=0; i<argc ; i++) {
+		if (*d == 0x28) {
+/*
+** cmd 01-22:0c1c, 01-22:0835
+** Princess Bride のカードが落ちるアニメの場面
+** なお、_PBCARDANM* の画像はこのコマンドでのみ使われているので、特殊処理として無視することも可能
+**
+** cmd 01-04:0276, 026c, 0270
+** 複数の enum が args の数だけ続く処理。特殊処理として分離する
+*/
+dprintf("enum.<");
+			/* (...) は列挙型 or 構造体の可能性がある */
+			const char* d_orig = d;
+			int pt = args.size(); args.push_back(VarInfo(0));
+			int count = GetArgs(d);
+			args[pt] = VarInfo(count);
+dprintf(">");
+		} else if (*d == 0x61 && (d[1] >= 0x00 && d[1] <= 0x04) && d[2] == 0x28 ) {
+			/* 使われるコマンドは 01-21:004b, 01-28:0064 のいずれか(R,C,PB,LO)
+			** それらのコマンドは
+			** arg1: 画像ファイル名
+			** arg2 : Sel 番号
+			** らしく、arg3 以降が 0x61 <00-04> (a,b,c,...) となる(ダンプ上は enum と表記される)
+			** () 内の引数はさまざまで、a のみ(画像ファイル名)、
+			** a,b b=SEL?
+			** a,b,c (b,c)=座標?
+			** a,(b,c,d,e,f,g) b-g = src / dest?
+			** らしい
+			*/
+			dprintf("kasane. #%d <",d[1]);
+			d += 2;
+			int pt = args.size(); args.push_back(VarInfo(0));
+			int count = GetArgs(d);
+			args[pt] = VarInfo(count);
+			dprintf(">");
+		} else if (*d == 0x24 || (*d == 0x5c && (d[1] == 1 || d[1] == 0))) {
+			/* cmd 01-15:0028 ; 始めに 0x24 節があり、続いて 0x28 節になる */
+			VarInfo var;
+			GetExpression(d, &var);
+			args.push_back(var);
+			i--; // この引数はargc の数には入らない
+		} else SetError();
+		if (d[0] == 0x0a || d[0] == 0x40) {
+			/* cmd 01-15:0028 ; 0x28 節の後に毎回 0x0a 節が来る */
+			int var;
+			if (system_version == 0) { var = read_little_endian_int(d+1); d += 5;}
+			else { var = read_little_endian_short(d+1); d += 3;}
+			dprintf("line %d; ",var);
+		}
+		if (*d == 0x29) break;
+		if (*d == 0x2c) {d++;} // 次の arg が演算子で始まる、などがなければ存在しない
+		dprintf(",");
+	}
+	if (*d == 0x29) d++;
+	else SetError();
+	return 0;
+}
+
+/* switch
+	<exp>
+	0x7b
+		<exp> <int>
+		...
+	0x7d
+*/
+
+int Cmd::GetSwitch(const char*& d) {
+	if (*d != 0x28) {SetError(); return -1;}
+	d++;
+	dprintf("switch. ");
+	int var = GetExpression(d);
+	if (*d != 0x29) {SetError(); return -1;}
+	d++;
+	dprintf("->\n");
+	if (*d == 0x7b) {
+		d++;
+	} else SetError();
+
+	int default_jmp = -1; int jmpto = -1;
+	int i; for (i=0; i<argc; i++) {
+		dprintf("\t");
+		if (*d++ != 0x28) {SetError(); return -1;}
+		int item = -1; // default
+		if (*d != 0x29) {
+			int item = GetExpression(d);
+			if (*d++ != 0x29) {SetError(); return -1;}
+			int jmp = read_little_endian_int(d);
+			if (var == item) {
+				dprintf("(selected)");
+				jmpto = jmp;
+			}
+			dprintf(" -> %d\n", jmp);
+		} else {
+			d++;
+			default_jmp = read_little_endian_int(d);
+		}
+		d += 4;
+	}
+	if (default_jmp != -1) {
+		dprintf("default -> %d\n",default_jmp);
+		if (jmpto == -1) jmpto = default_jmp;
+	}
+	if (*d == 0x7d) {
+		d++;
+	} else SetError();
+	return jmpto;
+}
+/* simple switch
+	<exp>
+	0x7b
+		<int>
+		...
+	0x7d
+*/
+int Cmd::GetSimpleSwitch(const char*& d) {
+	if (*d != 0x28) {SetError(); return -1;}
+	d++;
+	dprintf("simple switch. ");
+	int var = GetExpression(d);
+	if (*d != 0x29) {SetError(); return -1;}
+	d++;
+	dprintf(" ->\n");
+	int jumpto = -1;
+	if (*d == 0x7b) {
+		d++;
+	} else SetError();
+	int i; for (i=0; i<argc; i++) {
+		int j = read_little_endian_int(d);
+		d += 4;
+		dprintf("\t%d -> %d\n", i+1, j);
+		if (var == i+1) jumpto = j;
+	}
+	if (*d == 0x7d) {
+		d++;
+	} else SetError();
+	return jumpto;
+}
+
+/*
+selection
+	? <exp>
+	0x7b
+		<0x0a|0x40> <ushort | uint> 
+*/
+void Cmd::GetSelection(const char*& d) {
+	dprintf("selection. ");
+	if (*d == 0x28) {
+		d++;
+		GetExpression(d);
+		if (*d != 0x29) { SetError(); return;}
+		d++;
+	}
+	if (*d == 0x7b) {
+		d++;
+		dprintf("{\n\t");
+	} else SetError();
+	int arg_count = 0;
+	while(*d != 0x7d) {
+		if (d[0] == 0x0a || d[0] == 0x40) {
+			int var;
+			if (system_version == 0) { var = read_little_endian_int(d+1); d += 5;}
+			else { var = read_little_endian_short(d+1); d += 3;}
+			dprintf("line %d; ",var);
+		} else if (d[0] == 0x2c) {
+			dprintf(":comma:");
+		} else if (d[0] == 0x28) {
+			dprintf(":cond:");
+			d++;
+			while(d[0] != 0x29) {
+				GetExpressionCond(d); // PRINT- 節でないばあい、条件表示。次は文字節、またはPRINT節のはず
+				if (IsError()) break;
+				if (*d == 0x32) { d++; dprintf("##");} // 0x32 なら、現在の条件節を表示しない
+				if (*d == 0x31) { d++; dprintf("**");} // 0x31 なら、現在の条件節を表示する(Little Busters! : 処理が正しいかは分からない)
+				dprintf(":");
+			}
+			d++;
+		} else if (StrType(d)) {
+			GetString(d);
+			arg_count++;
+			dprintf("\n\t");
+		} else if (*d == 0x23 && strncmp(d,"###PRINT",8) == 0) {
+			d += 8;
+			if (d[0] != 0x28) SetError();
+			else { // 文字変数の内容の表示
+				d++;
+				dprintf("Print.");
+				VarInfo info;
+				GetLeftToken(d, info);
+				if (d[0] != 0x29 || info.type == -1) SetError();
+				d++;
+				dprintf(";");
+			}
+		} else { SetError(); break;}
+	}
+	d++;
+	/* @@@ */
+	/* 一致しない場合があるのでコメントアウト */
+	// if (arg_count != argc) SetError();
+	dprintf("\n}\n");
+	return;
+}
+
+char* op_str3[11] = { "+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=", "<<=", ">>=", "="};
+void Cmd::GetCmd(Flags& flags_orig, const char*& d ) {
+	ResetString();
+
+	cmdstr[0] = 0;
+	debug_flag = true;
+	if (*d == 0x23) { /* コマンド */
+		cmd_type = CMD_OTHER;
+		cmd1 = *(unsigned const char*)(d+1);
+		cmd2 = *(unsigned const char*)(d+2);
+		cmd3 = read_little_endian_short(d+3);
+		argc = read_little_endian_short(d+5);
+		cmd4 = *(unsigned const char*)(d+7);
+		d += 8;
+		/* verbose */
+			// dprintf(" 0x23 - cmd %02x-%02x:%04x:%02x[%2d] \n",cmd1,cmd2,cmd3,cmd4,argc);
+			sprintf(cmdstr, "%02x-%02x:%04x:%02x  : %s",cmd1,cmd2,cmd3,cmd4,CmdDescr(cmd1,cmd2,cmd3,cmd4));
+		/* 引数を得る */
+		/* 特殊引数のもの */
+		int is_special = 0;
+		if (cmd1 == 0) {
+			if (cmd2 == 1) {
+				int jump_arg = -1;
+				if (cmd3 == 0 || cmd3 == 5) {
+					/* gosub / goto */
+					jump_arg =read_little_endian_int(d);
+					d += 4;
+					dprintf("\tjmp -> %d\n", jump_arg);
+					is_special = 1;
+				} else if (cmd3 == 1 || cmd3 == 2) {
+					/* conditional jump (if / unless) */
+					if (*d++ != 0x28) { SetError(); return;}
+					dprintf("\t");
+					int cond = GetExpressionCond(d);
+					if (IsError()) return;
+					if (*d++ != 0x29) { SetError(); return; }
+					int jumpto = read_little_endian_int(d);
+					d += 4;
+					dprintf("-> %d\n", jumpto);
+					if (cond) jump_arg = jumpto;
+					is_special = 1;
+				} else if (cmd3 == 4) {
+					/* switch to */
+					jump_arg = GetSwitch(d);
+					is_special = 1;
+				} else if (cmd3 == 16) {
+					dprintf("local call with paramters;\n");
+					GetArgs(d);
+					int jumpto = read_little_endian_int(d);
+					d += 4;
+					dprintf("\tjmp -> %d\n",jumpto);
+					is_special = 1;
+				} else if (cmd3 == 8 || cmd3 == 3) {
+					/* switch to */
+					jump_arg = GetSimpleSwitch(d);
+					dprintf("\tjmp -> %d\n",jump_arg);
+					is_special = 1;
+				}
+				cmd_type = CMD_OTHER;
+				args.push_back(VarInfo(jump_arg));
+			} else if (cmd2 == 2 && (cmd3 == 0 || cmd3 == 1 || cmd3 == 2 || cmd3 == 3 || cmd3 == 0x0d) ) {
+				/* selection */
+				GetSelection(d);
+				is_special = 1;
+			}
+		}
+		/* 一般引数のもの */
+		if (!is_special) {
+			dprintf(" 0x23 - cmd %02x-%02x:%04x:%02x[%2d]  : %s\n",cmd1,cmd2,cmd3,cmd4,argc,CmdDescr(cmd1,cmd2,cmd3,cmd4));
+			dprintf("\t");
+			if (cmd1 == 1 && cmd2 == 0x22 && (cmd3 == 0xc1c || cmd3 == 0x835)) GetArgsSpecial(3, d);
+			else if (cmd1 == 1 && cmd2 == 0x0b && cmd3 == 0x65) GetArgsSpecial(0, d);
+			else if (cmd1 == 1 && cmd2 == 0x15 && cmd3 == 0x28) GetArgsSpecial(0, d);
+			else if (cmd1 == 1 && cmd2 == 4 && (cmd3 == 0x26c || cmd3 == 0x26d || cmd3 == 0x270 || cmd3 == 0x276)) GetArgsSpecial(0, d);
+			else if (cmd1 == 1 && (cmd2 == 0x21 && cmd3 == 0x4b) || (cmd2 == 0x28 && cmd3 == 0x64)) GetArgsSpecial(2,d);
+			else GetArgs(d);
+			dprintf("\n");
+
+		}
+		if (cmd2 == 3 && cmd3 == 0x78 && cmd4 == 0) ruby_flag = true;
+		if (cmd2 == 3 && cmd3 == 0x11) ret_flag = true;
+	} else if (*d == 0x24) { /* 代入演算 */
+		if (d[1] == 0x12 || d[2] != 0x5b) SetError();
+		dprintf("expr: ");
+		sprintf(cmdstr, "expr");
+
+		VarInfo info;
+		int value = GetLeftToken(d, info);
+		if (d[0] != 0x5c) SetError();
+		int type = d[1];
+		if (type < 20 || type > 30) SetError();
+		else dprintf("%s",op_str[type]);
+		d += 2;
+		int value2 = GetExpression(d);
+		// 代入情報を埋め込む
+		if (type != 30) value2 = eval(value, type-20, value2);
+		cmd_type = CMD_FLAGS;
+		args.push_back(info);
+		args.push_back(value2);
+		dprintf("\n");
+	} else if (StrType(d)) { /* 文字出力 */
+		VarInfo info;
+		info.type = TYPE_STR;
+		info.value = GetString(d);
+		args.push_back(info);
+		cmd_type = CMD_TEXT;
+		text_flag = true;
+		dprintf("\n");
+	} else if (*d == 0x0a || *d == 0x40 || *d == 0x21) { /* デバッグ用データと既読フラグ */
+		cmd_type = CMD_OTHER;
+		if (*d == 0x0a) {
+			dprintf("line ");
+			d++;
+			int l;
+			if (system_version == 0) {
+				l = read_little_endian_int(d);
+				d += 4;
+			} else {
+				l = read_little_endian_short(d);
+				d += 2;
+			}
+			dprintf("%d\n", l);
+		} else { /* 0x40, 0x21 */
+			// 既読マーカーらしい。エントリーポイントとセーブポイントも使われる。
+			// RealLive 1.2.5から、0x40はセーブポイント、0x21はエントリーポイント。
+			// 1.2.5以前、どちらも0x40が使われる。
+			int kidoku_index;
+			d++;
+			if (system_version == 0) {
+				kidoku_index = read_little_endian_int(d);
+				d += 4;
+			} else {
+				kidoku_index = read_little_endian_short(d);
+				d += 2;
+			}
+			dprintf("kidoku marker %d\n", kidoku_index);
+			// text_readflagは、このkidoku_indexを使ったら良いかな。
+		}
+	} else if (*d == 0x2c) { /* ??? */
+		dprintf("commd;0x2c\n"); // conditional jump の行き先によくあるらしい(常に、かはわからない)
+		d++;
+	} else { 
+		SetError();
+	}
+	return;
+}
+
+char Cmd::strtype[256] = {
+	0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +00 */
+	0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +10 */
+	0,0,3,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +20 */
+	1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,1, /* +30 */
+	0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, /* +40 */
+	1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,1, /* +50 */
+	0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +60 */
+	0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +70 */
+	2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, /* +80 */
+	2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, /* +90 */
+	0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +A0 */
+	0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +B0 */
+	0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +C0 */
+	0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* +D0 */
+	2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, /* +E0 */
+	2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,0,0  /* +F0 */
+};
+
+int Cmd::GetString(const char*& d) {
+	int retnum = -1;
+	while(1) {
+		if (*d == '\\') {
+			d++;
+			strheap[strend++] = *d++;
+		} else if (*d == '"') {
+			d++;
+			if (retnum == -1) retnum = strend;
+			while(*d != '"') strheap[strend++] = *d++;
+			d++;
+		} else if (StrType(d)) {
+			if (retnum == -1) retnum = strend;
+			int stype;
+			while( (stype = StrType(d)) ) {
+				if (stype == 3) break; // 文中に '"' が現れた場合
+				strheap[strend++] = *d++;
+				if (stype == 2) strheap[strend++] = *d++;
+			}
+		} else break;
+	}
+	if (retnum != -1) strheap[strend++] = 0;
+	dprintf("\"%s\"", strheap + retnum);
+	if (strend >= STRHEAP_SIZE) {
+		dprintf("Error: string heap overflow\n");
+	}
+	return retnum;
+}
+
+int Cmd::StrVar(int var_num) {
+	int retnum = strend;
+	flags.Str(var_num, strheap+strend, STRHEAP_SIZE-strend);
+	strend += strlen(strheap+strend)+1;
+	return retnum;
+}
+
+void usage(void) {
+	fprintf(stderr,"usage : scn2kdump [inputfile] [outputfile]\n");
+	fprintf(stderr,"  inputfile:  seen.txt(default)\n");
+	fprintf(stderr,"  outputfile: seen.txt_out(default)\n");
+	exit(-1);
+}
+int main(int argc, char** argv) {
+	/* determine file names */
+	bool verbose = false;
+	char* inname = "seen.txt";
+	char* outname = 0;
+	if (argc > 2 && strcmp(argv[1],"-v") == 0) {
+		int i; for (i=1; i<argc; i++) argv[i] = argv[i+1];
+		argc--;
+		verbose = true;
+	}
+	switch(argc) {
+	case 1: break;
+	case 2: inname = argv[1]; break;
+	case 3: inname = argv[1]; outname = argv[2]; break;
+	default: usage();
+	}
+	/* open output file */
+	FILE* outstream = stdout;
+	/* create archive instance */
+	SCN2kFILE archive(inname);
+	archive.Init();
+	if (archive.Deal() == 0) {
+		fprintf(stderr,"Cannot open / Invalid archive file %s\n",inname);
+		usage();
+	}
+	/* dump files */
+	archive.InitList();
+	char* fname;
+	fprintf(stderr,"Dump start\n");
+	while( (fname = archive.ListItem()) != 0) {
+		ARCINFO* info = archive.Find(fname,"");
+		if (info == 0) continue;
+		char* data = info->CopyRead();
+		char* d = data;
+		char* dend = d + info->Size();
+		/* version 確認 */
+		if (read_little_endian_int(d) == 0x1cc) {
+			system_version = 0;
+		} else if (read_little_endian_int(d) == 0x1d0) {
+			system_version = 1;
+		} else {
+			continue;
+		}
+		if (read_little_endian_int(d+4) == 0x1adb2) ; // little busters!
+		else if (read_little_endian_int(d+4) != 0x2712) continue;
+		int header_size;
+		if (system_version == 0) {
+			header_size = 0x1cc + read_little_endian_int(d+0x20) * 4;
+		} else {
+			header_size = read_little_endian_int(d+0x20);
+		}
+		d += header_size;
+
+		const char* dcur = d;
+		const char* dstart = d;
+		fprintf(stderr,"Dumping %s\n",fname);
+		fprintf(stdout,"Dumping %s\n",fname);
+{ int i; for (i=0; i<100; i++) {
+		int n = read_little_endian_int(data + 0x34 + i*4);
+		if (n != 6) fprintf(stdout,"subroutine table %2d: %6d\n",i,n);
+}}
+		Flags flags;
+		/* 最初から最後までコマンド取得 -> 出力を繰り返す */
+		while(dcur<dend) {
+			const char* dprev = dcur;
+			Cmd cmd(flags); cmd.ClearError();
+
+			/* end? */
+			if (*dcur == -1) {
+				/* 0xff x 32byte + 0x00 : end sign */
+				int i; for (i=0; i<0x20; i++)
+					if (dcur[i] != -1) break;
+				if (i == 0x20 && dcur[i] == 0) break;
+			}
+			dprintf("%d : ",dcur-dstart);
+			cmd.GetCmd(flags, dcur);
+			if (cmd.IsError()) {
+				fprintf(outstream, "Error at %6d\n",dprev-dstart);
+				while(dcur < dend) {
+					if (*dcur == 0x29 && dcur[1] == 0x0a) {dcur++;break;}
+					if (*dcur == 0 && dcur[1] == 0x0a) {dcur++;break;}
+					if (*dcur == 0 && dcur[1] == 0x23) {dcur++;break;}
+					dcur++;
+				}
+				dprev -= 2*16;
+				int ilen = (dcur-dprev+15)/16;
+				int i; for (i=0; i<ilen; i++) {
+					fprintf(outstream, "%6d: ",dprev-dstart);
+					int j; for (j=0; j<16; j++) {
+						if (dprev >= dend) break;
+						if (dprev < data) continue;
+						fprintf(outstream, "%02x ",*(unsigned char*)(dprev));
+						dprev++;
+					}
+					fprintf(outstream, "\n");
+				}
+			}
+		}
+		delete info;
+	}
+	return 0;
+}
+
+/*
+SetStr
+	0x23 - cmd 01-0a:0000:00[ 2] 
+	args:V<18>[17],"PB47"
+CatStr
+	0x23 - cmd 01-0a:0002:00[ 2] 
+	args:V<18>[17],V<18>[20]
+
+WaitClick
+	0x23 - cmd 00-03:0011:00[ 0] 
+	
+ChangeFaceGraphics
+	0x23 - cmd 00-03:03e8:00[ 1] 
+	args:V<18>[17]
+DeleteFaceGraphics
+	0x23 - cmd 00-03:03e9:01[ 0] 
+KoePlay
+	0x23 - cmd 01-17:0000:01[ 2] 
+	args:100000026,5
+DrawGraphics(前景画あり)
+	0x23 - cmd 01-21:004b:00[ 1] 
+	args:V<18>[1],10,kasane. #1 <args:V<18>[17],11>
+
+DrawGraphics(背景のみ)
+	0x23 - cmd 01-21:0049:00[ 2] 
+	args:V<18>[1],10
+	
+Ruby
+	0x23 - cmd 00-03:0078:01[ 0] 
+	"理由"
+	0x23 - cmd 00-03:0078:00[ 1] 
+	"わけ"
+SetTitle
+	0x23 - cmd 01-04:0000:00[ 1] 
+	args:"Long Long Time Ago..."
+WaitTime
+	0x23 - cmd 01-14:0069:00[ 1] 
+	args:3000
+ChangeBGM	数値引数はフェードアウト、インの時間と推測
+0x23 - cmd 01-14:0000:02[ 3] 
+	args:"BGM18",700,700
+*/
+
+struct CmdDescrItem {
+	CmdDescrItem* next;
+	int cmd4;
+	int cmd1;
+	int cmd2;
+	int cmd3;
+	const char* cmd_descr;
+};
+CmdDescrItem cmd_descr_orig[] = {
+	// scn2k_impl.cc; Scn2k::SysExec()
+	{0,0,0x00,0x01,0x0a, "local return"},
+	{0,0,0x00,0x01,0x0b, "global jump"},
+	{0,0,0x00,0x01,0x0c, "global call"},
+	{0,0,0x00,0x01,0x0d, "global return"},
+	{0,0,0x00,0x01,0x12, "global call"},
+	{0,0,0x00,0x01,0x13, "global return(?)"},
+	{0,0,0x00,0x04,0x0d, "Menu_return"},
+	{0,0,0x01,0x04,0x00, "SetWindowCaption"},
+	{0,0,0x01,0x04,0x82, "ClearMousePress"},
+	{0,0,0x01,0x04,0x83, "GetMouse(2)"},
+	{0,0,0x01,0x04,0x85, "GetMouse"},
+	{0,0,0x01,0x04,0x4b0,"QuitGame"},
+	{0,0,0x01,0x04,0x58d,"PrevSaveNumber"},
+	{0,0,0x01,0x04,0x585,"SavedDate"},
+	{0,0,0x01,0x04,0xc23,"Save"},
+	{0,0,0x01,0x04,0xc25,"Load"},
+	{0,0,0x01,0x04,0x4b1,"GoMenu"},
+	{0,0,0x01,0x04,0x4b3,"GoMenu_Badend"},
+	{0,0,0x01,0x04,0xcc, "ShowMouseCursor"},
+	{0,0,0x01,0x04,0xcd, "HideMouseCursor"},
+	{0,0,0x01,0x04,0xcf, "SetCursorType"},
+	// scn2k_cmd.cc; Cmd::GetCmd()
+	{0,0,0x00,0x01,0,    "local jump"},
+	{0,0,0x00,0x01,1,    "local jump-if"},
+	{0,0,0x00,0x01,2,    "local jump-unless"},
+	{0,0,0x00,0x01,3,    "local jump-switch??"},
+	{0,0,0x00,0x01,4,    "local switch"},
+	{0,0,0x00,0x01,5,    "local call"},
+	{0,0,0x00,0x01,8,    "local switch(simple form)"},
+	{0,0,0x01,0x0b,0,    "set multiple variables"},
+	{0,0,0x01,0x0b,1,    "set variables in a range"},
+	{0,0,0x01,0x0b,4,    "clear variables in a range"},
+	{0,0,0x01,0x0b,0x64, "get summation of variables in a range"},
+	// scn2k_cmd.cc; Flags::Exec()
+	{0,0,0x01,0x0a,0,    "SetStr"},
+	{0,0,0x01,0x0a,1,    "ClearStr"},
+	{0,0,0x01,0x0a,2,    "AppendStr"},
+	{0,0,0x01,0x0a,3,    "StrLen"},
+	{0,0,0x01,0x0a,4,    "StrCmp"},
+	{0,0,0x01,0x0a,5,    "SubStrL"},
+	{0,0,0x01,0x0a,6,    "SubStrR"},
+	{0,0,0x01,0x0a,7,    "StrLenWideChar"},
+	{0,0,0x01,0x0a,8,    "TrimStr"},
+	{0,0,0x01,0x0a,0x0f, "IntToStr"},
+	{0,0,0x01,0x0a,0x11, "IntToStr_Fill"},
+	{0,0,0x01,0x0a,0x64, "ShowStr"},
+	// scn2k_text.cc; TextImpl::Exec()
+	{0,0,0x01,0x21,0x49, "SetFaceGraphic"},
+	{0,0,0x01,0x21,0x4b, "SetFaceGraphic"},
+	{0,0,0x01,0x21,0x4c, "SetFaceGraphic"},
+	{0,0,0x00,0x03,0x97, "CloseTextWindow"},
+	{0,0,0x00,0x03,0x11, "WaitText"},
+	{0,0,0x00,0x03,0x03, "TextReturn"},
+	{0,0,0x00,0x03,0xc9, "TextReturn"},
+	{0,0,0x00,0x03,0x3e8,"SetFaceGraphic"},
+	{0,0,0x00,0x03,0x3e9,"SetFaceGraphic"},
+	{0,0,0x00,0x03,0x78, "TextRuby"},
+	{0,0,0x00,0x03,0x66, "SetTextWindowType"},
+	{0,0,0x00,0x03,0x67, "OpenTextWindow"},
+	{0,0,0x00,0x03,0x98, "ClearTextWindow"},
+	{0,0,0x00,0x03,0x68, "ShowText"},
+	{0,0,0x00,0x02,0x01, "Select"},
+	{0,0,0x00,0x02,0x03, "Select"},
+	{0,0,0x00,0x04,0x44c,"TextSkipStart"},
+	{0,0,0x00,0x04,0x3e8,"CloseTextWindow"},
+	{0,0,0x01,0x04,0x64, "WaitTime"},
+	{0,0,0x01,0x04,0x6f, "WaitTime"},
+	{0,0,0x01,0x04,0x79, "WaitTime"},
+	{0,0,0x01,0x04,0x65, "WaitTime w/ Cancel"},
+	{0,0,0x01,0x04,0x70, "WaitTime w/ Cancel"},
+	{0,0,0x01,0x04,0x1fe,"GetTimer"},
+	{0,0,0x01,0x04,0x201,"ResetTimer (unsupported; see rldev)"},
+	{0,0,0x01,0x04,0x202,"ResetTimerAll (unsupported; see rldev)"},
+	{0,0,0x01,0x04,0x72, "GetTimer"},
+	{0,0,0x01,0x04,0x7c, "GetTimer(2)"},
+	{0,0,0x01,0x04,0x6e, "ClearTimer"},
+	{0,0,0x01,0x04,0x78, "ClearTimer(2)"},
+	{0,0,0x01,0x04,0x26c,"ClearTimer(multi)"},
+	{0,0,0x01,0x04,0x270,"ClearTimer(multi)"},
+	{0,0,0x01,0x04,0x276,"GetTimer(multi)"},
+	{0,0,0x01,0x04,0x1f4,"SetTimer"},
+	{0,0,0x01,0x04,0x3e8,"rand(x,y)"},
+	{0,0,0x01,0x04,0x3ec,"min(x,y)"},
+	{0,0,0x01,0x04,0x3ef,"min(x,y)"},
+	{0,0,0x01,0x04,0x320,"range conversion(V,?,ResultMin,ValMin,ValMax,ResultMax,?)"},
+	{0,0,0x01,0x04,0x3f1,"in_range(x,y,a)"},
+	{0,0,0x01,0x04,0x16c,"SetCursorType?"},
+	{0,0,0x01,0x04,0xbc1,"LoadFromMenu"},
+	{0,0,0x01,0x04,0x8d4,"SetTextWindowColor"},
+	{0,0,0x01,0x04,0x8d5,"SetTextWindowColor"},
+	{0,0,0x01,0x04,0x8d6,"SetTextWindowColor"},
+	{0,0,0x01,0x04,0x8d7,"SetTextWindowColor"},
+	{0,0,0x01,0x04,0x8d8,"SetTextWindowColor"},
+	{0,0,0x01,0x04,0x8db,"SetTextWindowColor"},
+	{0,0,0x01,0x04,0x93f,"SetTextWindowColor"},
+	{0,0,0x01,0x04,0xa39,"SetTextWindowColor"},
+	{0,0,0x01,0x04,0xa28,"Get #INIT_MESSAGE_SPEED (original) from gameexe.ini"},
+	{0,0,0x01,0x04,0xa29,"Get #INIT_MESSAGE_SPEED (original) from gameexe.ini"},
+	{0,0,0x01,0x04,0xa2c,"Get #MESSAGE_KEY_WAIT_USE (original) from gameexe.ini"},
+	{0,0,0x01,0x04,0xa2d,"Get #INIT_MESSAGE_SPEED (original) from gameexe.ini"},
+	{0,0,0x01,0x04,0xa2e,"Get #MESSAGE_KEY_WAIT_TIME (original) from gameexe.ini"},
+	{0,0,0x01,0x04,0x913,"Get #INIT_MESSAGE_SPEED"},
+	{0,0,0x01,0x04,0x914,"Get #INIT_MESSAGE_SPEED_MOD"},
+	{0,0,0x01,0x04,0x92e,"Get #MESSAGE_KEY_WAIT_USE"},
+	{0,0,0x01,0x04,0x92f,"Get #INIT_MESSAGE_SPEED_MOD"},
+	{0,0,0x01,0x04,0x930,"Get #MESSAGE_KEY_WAIT_TIME"},
+	{0,0,0x01,0x04,0x8af,"Set #INIT_MESSAGE_SPEED"},
+	{0,0,0x01,0x04,0x8b0,"Set #INIT_MESSAGE_SPEED_MOD"},
+	{0,0,0x01,0x04,0x8ca,"Set #MESSAGE_KEY_WAIT_USE"},
+	{0,0,0x01,0x04,0x8cb,"Set #INIT_MESSAGE_SPEED_MOD"},
+	{0,0,0x01,0x04,0x8cc,"Set #MESSAGE_KEY_WAIT_USE"},
+	{0,0,0x01,0x04,0x51f,"Set Name Text"},
+	{0,0,0x01,0x04,0x51e,"Get Name Text"},
+	{0,0,0x01,0x04,0x514,"Get Name Text"},
+	// scn2k_grp.cc; GrpImpl::Exec()
+	// music commands
+	{0,0,0x01,0x14,0,    "PlayBGM"},
+	{0,0,0x01,0x14,2,    "PlayBGM"},
+	{0,0,0x01,0x14,0x05, "StopBGM"},
+	{0,0,0x01,0x14,0x69, "FadeBGM"},
+	{0,0,0x01,0x15,0,    "PlaySE"},
+	{0,0,0x01,0x15,2,    "PlaySE"},
+	{0,0,0x01,0x17,0,    "PlayKoe"},
+	{0,0,0x01,0x1a,1,    "PlayMovie"},
+	{0,0,0x01,0x1a,0x14, "PlayMovie"},
+	// graphic commands
+	{0,0,0x01,0x1e,0,    "GraphicStackClear"},
+	{0,0,0x01,0x1f,0,    "GraphicStackClear"},
+	{0,0,0x01,0x21,0x46, "LoadSurface"},
+	{0,0,0x01,0x21,0x49, "LoadBackSurface"},
+	{0,0,0x01,0x21,0x4b, "LoadForeSurface"},
+	{0,0,0x01,0x21,0x4c, "LoadSurface"},
+	{0,0,0x01,0x21,0x64, "CopySurface"},
+	{0,0,0x01,0x21,0x4b1,"ClearSurface"},
+	{0,0,0x01,0x21,0x44c,"AlphaCopy"},
+	{0,0,0x01,0x21,0x640,"SaturateCopy"},
+	{0,0,0x01,0x21,0x196,"??? grp"},
+	{0,0,0x01,0x22,0xc30,"ScrollEffect (Princess Bride)"},
+	{0,0,0x01,0x22,0xc1c,"FallEffect (Princess Bride)"},
+	{0,0,0x01,0x22,0x835,"FallEffect (Princess Bride)"},
+	// grphic object commands
+	{0,0,0x01,0x04,0xd2, "??? grp"},
+	{0,0,0x01,0x04,0xd3, "??? grp"},
+	{0,0,0x01,0x04,0xd7, "??? grp"},
+	{0,0,0x01,0x04,0xd8, "??? grp"},
+	{0,0,0x01,0x04,0x5e0,"GetShownGrpFlag"},
+	{0,0,0x01,0x3d,0x0a, "ClearGrpObj"},
+	{0,0,0x01,0x3d,0x0b, "ClearGrpObj"},
+	{0,0,0x01,0x3e,0x0a, "ClearGrpObj"},
+	{0,0,0x01,0x3e,0x0a, "ClearGrpObj"},
+	{0,0,0x01,0x3c,0x01, "??? grp (CLANNAD)"},
+	{0,0,0x01,0x47,0x3e8,"SetGrpObj_Fname"},
+	{0,0,0x01,0x47,0x3eb,"SetGrpObj_GANname"},
+	{0,0,0x01,0x47,0x4b0,"SetGrpObj_Text"},
+	{0,0,0x01,0x48,0x3e8,"SetGrpObj_ForeGrp?"},
+	{0,0,0x01,0x49,0,    "StopAnimation"},
+	{0,0,0x01,0x49,3,    "QueryExecAnimation"},
+	{0,0,0x01,0x49,0x7d3,"SetGrpObj_GAN?"},
+	{0,0,0x01,0x49,0xbb9,"StartAnimation"},
+	{0,0,0x01,0x49,0xbbb,"StartAnimation"},
+	{0,0,0x01,0x49,0xbbd,"StartAnimation"},
+	{0,0,0x01,0x51,0x3e8,"SetGrpObj_xy"},
+	{0,0,0x01,0x51,0x3e9,"SetGrpObj_x"},
+	{0,0,0x01,0x51,0x3ea,"SetGrpObj_y"},
+	{0,0,0x01,0x51,0x3eb,"SetGrpObj_alpha"},
+	{0,0,0x01,0x51,0x3ec,"SetGrpObj_visible"},
+	{0,0,0x01,0x51,0x3ee,"SetGrpObj_xy?"},
+	{0,0,0x01,0x51,0x3fd,"SetGrpObj_centering?"},
+	{0,0,0x01,0x51,0x401,"SetGrpObj_textsize"},
+	{0,0,0x01,0x51,0x40a,"SetGrpObj_clipregion"},
+	{0,0,0x01,0x51,0x40f,"SetGrpObj_surfacenum"},
+	{0,0,0x01,0x51,0x416,"SetGrpObj_expand"},
+	{0,0,0x01,0x51,0x419,"SetGrpObj_rotate"},
+	{0,0,0x01,0x52,0x3e8,"SetGrpObj_xy(2)"},
+	{0,0,0x01,0x52,0x3ea,"SetGrpObj_y(2)"},
+	{0,0,0x01,0x52,0x3eb,"SetGrpObj_alpha(2)"},
+	{0,0,0x01,0x52,0x3ec,"SetGrpObj_visible(2)"},
+	{0,0,0x01,0x52,0x3ee,"SetGrpObj_xy?(2)"},
+	{0,0,0x01,0x52,0x3fd,"SetGrpObj_centering?(2)"},
+	{0,0,0x01,0x52,0x401,"SetGrpObj_textsize(2)"},
+	{0,0,0x01,0x52,0x408,"SetGrpObj_order (not supported)"},
+	{0,0,0x01,0x52,0x40a,"SetGrpObj_clipregion(2)"},
+	{0,0,0x01,0x52,0x40f,"SetGrpObj_surfacenum(2)"},
+	{0,0,0x01,0x52,0x416,"SetGrpObj_expand(2)"},
+	{0,0,0x01,0x52,0x419,"SetGrpObj_rotate(2)"},
+	{0,0,0x01,0x54,0x3e8,"GetGrpObj_xy"},
+	{0,0,0x01,0x54,0x44c,"GetGrpObj_wh"},
+
+	{0,0,0x02,0x3d,0x0a, "ClearGrpObj(2)"},
+	{0,0,0x02,0x3d,0x0b, "ClearGrpObj(2)"},
+	{0,0,0x02,0x3e,0x0a, "ClearGrpObj(2)"},
+	{0,0,0x02,0x3e,0x0a, "ClearGrpObj(2)"},
+	{0,0,0x02,0x3c,0x01, "??? grp (CLANNAD)(2)"},
+	{0,0,0x02,0x47,0x3e8,"SetGrpObj_Fname(2)"},
+	{0,0,0x02,0x47,0x3eb,"SetGrpObj_GANname(2)"},
+	{0,0,0x02,0x47,0x4b0,"SetGrpObj_Text(2)"},
+	{0,0,0x02,0x48,0x3e8,"SetGrpObj_ForeGrp?(2)"},
+	{0,0,0x02,0x49,0,    "StopAnimation(2)"},
+	{0,0,0x02,0x49,3,    "QueryExecAnimation(2)"},
+	{0,0,0x02,0x49,0x7d3,"SetGrpObj_GAN?(2)"},
+	{0,0,0x02,0x49,0xbb9,"StartAnimation(2)"},
+	{0,0,0x02,0x49,0xbbb,"StartAnimation(2)"},
+	{0,0,0x02,0x49,0xbbd,"StartAnimation(2)"},
+	{0,0,0x02,0x51,0x3e8,"SetGrpObj_xy(2)"},
+	{0,0,0x02,0x51,0x3ea,"SetGrpObj_y(2)"},
+	{0,0,0x02,0x51,0x3eb,"SetGrpObj_alpha(2)"},
+	{0,0,0x02,0x51,0x3ec,"SetGrpObj_visible(2)"},
+	{0,0,0x02,0x51,0x3ee,"SetGrpObj_xy?(2)"},
+	{0,0,0x02,0x51,0x3fd,"SetGrpObj_centering?(2)"},
+	{0,0,0x02,0x51,0x401,"SetGrpObj_textsize(2)"},
+	{0,0,0x02,0x51,0x40a,"SetGrpObj_clipregion(2)"},
+	{0,0,0x02,0x51,0x40f,"SetGrpObj_surfacenum(2)"},
+	{0,0,0x02,0x51,0x416,"SetGrpObj_expand(2)"},
+	{0,0,0x02,0x51,0x419,"SetGrpObj_rotate(2)"},
+	{0,0,0x02,0x52,0x3e8,"SetGrpObj_xy(2)(2)"},
+	{0,0,0x02,0x52,0x3ea,"SetGrpObj_y(2)(2)"},
+	{0,0,0x02,0x52,0x3eb,"SetGrpObj_alpha(2)(2)"},
+	{0,0,0x02,0x52,0x3ec,"SetGrpObj_visible(2)(2)"},
+	{0,0,0x02,0x52,0x3ee,"SetGrpObj_xy?(2)(2)"},
+	{0,0,0x02,0x52,0x3fd,"SetGrpObj_centering?(2)(2)"},
+	{0,0,0x02,0x52,0x401,"SetGrpObj_textsize(2)(2)"},
+	{0,0,0x02,0x52,0x40a,"SetGrpObj_clipregion(2)(2)"},
+	{0,0,0x02,0x52,0x40f,"SetGrpObj_surfacenum(2)(2)"},
+	{0,0,0x02,0x52,0x416,"SetGrpObj_expand(2)(2)"},
+	{0,0,0x02,0x52,0x419,"SetGrpObj_rotate(2)(2)"},
+	{0,0,0x02,0x54,0x3e8,"GetGrpObj_xy(2)"},
+	{0,0,0x02,0x54,0x44c,"GetGrpObj_wh(2)"},
+	{0,0,0,0,0,0}
+};
+map<int, CmdDescrItem*> Cmd::cmd_descr;
+const char* Cmd::CmdDescr(int cmd1, int cmd2, int cmd3, int cmd4) {
+	if (cmd_descr.empty()) {
+		int i;
+		for (i=0; cmd_descr_orig[i].cmd_descr != 0; i++) {
+			CmdDescrItem& cur = cmd_descr_orig[i];
+			int item_num = cur.cmd1*1000000+cur.cmd2*10000+cur.cmd3;
+			map<int,CmdDescrItem*>::iterator it = cmd_descr.find(item_num);
+			if (it == cmd_descr.end()) cmd_descr[item_num] = &cur;
+			else {
+				cur.next = it->second;
+				it->second = &cur;
+			}
+		}
+	}
+	int item_num = cmd1*1000000+cmd2*10000+cmd3;
+	map<int,CmdDescrItem*>::iterator it = cmd_descr.find(item_num);
+	if (it == cmd_descr.end()) return "No descr (unsupported)";
+	CmdDescrItem* cur = it->second;
+	do {
+		if (cur->cmd1 == cmd1 && cur->cmd2 == cmd2 && cur->cmd3 == cmd3) {
+			return cur->cmd_descr;
+		}
+		cur = cur->next;
+	} while(cur != 0);
+	return "No descr (unsupported)";
+}
new file mode 100644
--- /dev/null
+++ b/scn2k/test.cc
@@ -0,0 +1,67 @@
+#include<stdio.h>
+#include<stdlib.h>
+#include<unistd.h>
+
+#include<SDL.h>
+#include<vector>
+
+#include"system/file.h"
+#include"system/system_config.h"
+#include"window/widget.h"
+#include"window/system.h"
+
+#include"music2/music.h"
+
+#include"scn2k.h"
+#include"scn2k_impl.h"
+
+using namespace std;
+
+extern char* diag;
+extern char* diag2;
+
+int main(void) {
+	AyuSysConfig config;
+	printf("%s\n",setlocale(LC_ALL,""));
+	//file_searcher.InitRoot("/home/uenok/pb");
+	file_searcher.InitRoot("/mnt/KEY/CLANNAD");
+	config.LoadInitFile();
+
+	MuSys mu(config);
+	mu.InitMusic();
+	SetFont("msgothic.ttc");
+	
+	SDL_Init(SDL_INIT_VIDEO);
+	SDL_SetVideoMode(640, 480, 0, SDL_HWSURFACE /*| SDL_FULLSCREEN */);
+	System::Main main;
+
+	PicContainer* main_panel = main.root.create_node(Rect(0, 0, main.root.width, main.root.height), 0);
+	main_panel->show();
+	Scn2k scn(main.event, *main_panel, mu, config);
+	// MouseCursor* cursor = new MouseCursor
+	// scn.OpenScript(1002, -19482); // ラブ生〜
+	//scn.OpenScript(1002, -18240); // ラブ生シーン開始
+	// scn.OpenScript(1002, -59528); // ラブ生シーン開始
+	// scn.OpenScript(2, 0);
+	// scn.OpenScript(320, 0);
+	//scn.OpenScript(320, -4269); // オープニング(Chap.2)
+	//scn.OpenScript(320, -2523);
+	//scn.OpenScript(320, -7549);
+	// scn.OpenScript(310, 0); // エンディング(Wed.day)
+	//scn.OpenScript(311, 0); // エンディング
+	// scn.OpenScript(100, -2244); // 選択肢
+	// scn.OpenScript(100, -9008); // 選択肢
+	//scn.OpenScript(1001, -118520 ); // 選択肢:葛城クン
+	// scn.OpenScript(1, 0); // 開始
+	// scn.OpenScript(414,380); // 開始
+	// scn.OpenScript(9142,0); // 開始
+	// config.SetParam("#SEEN_START", 1, 9140);
+	//scn.show_textwindow(0);
+	
+	main.Mainloop();
+
+	mu.FinalizeMusic();
+
+	SDL_Quit();
+}
+
new file mode 100644
--- /dev/null
+++ b/system/Makefile.in
@@ -0,0 +1,35 @@
+@SET_MAKE@
+CC		= @CC@
+CXX		= @CXX@
+LD		= @CXX@
+AR		= ar
+RANLIB		= @RANLIB@
+
+CFLAGS= -I.. $(LOCAL_DEF) @CFLAGS@ @DEFS@ -pthread -O2
+CXXFLAGS	= $(CFLAGS)
+LDFLAGS = @LDFLAGS@ @LIBS@ -pthread
+
+SRCS	 = file.cc \
+	   system_config.cc
+
+OBJS	 = ${SRCS:.cc=.o}
+
+all: visarc libsystem.a
+
+libsystem.a: ${OBJS}
+	rm -f libsystem.a
+	${AR} clq libsystem.a ${OBJS}
+	$(RANLIB) libsystem.a
+
+visarc: visarc.o libsystem.a
+	$(LD) -o visarc visarc.o libsystem.a $(LDFLAGS)
+
+clean:
+	rm -f visarc libsystem.a ${OBJS} *.bak
+
+.c.o:
+	$(CC) -c $(CFLAGS) -o $@ $<
+
+.cc.o:
+	$(CXX) -c $(CFLAGS) -o $@ $<
+
new file mode 100644
--- /dev/null
+++ b/system/file.cc
@@ -0,0 +1,1846 @@
+bool init_end=false;
+/*  file.cc  : KANON の圧縮ファイル・PDT ファイル(画像ファイル)の展開の
+ *            ためのメソッド
+ *     class ARCFILE : 書庫ファイル全体を扱うクラス
+ *     class ARCINFO : 書庫ファイルの中の1つのファイルを扱うクラス
+ *     class PDTCONV : PDT ファイルの展開を行う。
+ *
+ */
+
+/*
+ *
+ *  Copyright (C) 2000-   Kazunori Ueno(JAGARL) <jagarl@creator.club.ne.jp>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+*/
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#ifdef HAVE_MMAP
+#  ifdef MACOSX
+#    undef HAVE_MMAP
+#  endif /* MACOSX */
+#endif /* HAVE_MMAP */
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <vector>
+#include <algorithm>
+#if HAVE_MMAP
+#include<sys/mman.h>
+#endif /* HAVE_MMAP */
+#if HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# if HAVE_SYS_NDIR_H
+#  include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+#  include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+#  include <ndir.h>
+# endif
+#endif
+
+#if HAVE_LIBZ
+#include<zlib.h>
+#endif
+#if HAVE_LIBPNG
+#include<png.h>
+#endif
+#if HAVE_LIBJPEG
+extern "C" {
+#include<jpeglib.h>
+}
+#endif
+
+#include "file.h"
+#include "file_impl.h"
+
+using namespace std;
+
+FILESEARCH file_searcher;
+// #define delete fprintf(stderr,"file.cc: %d.",__LINE__), delete
+
+/* FILESEARCH class の default の振る舞い */
+FILESEARCH::ARCTYPE FILESEARCH::default_is_archived[TYPEMAX] = {
+	ATYPE_DIR, ATYPE_DIR, ATYPE_DIR, ATYPE_DIR,
+	ATYPE_ARC, ATYPE_ARC, ATYPE_ARC, ATYPE_ARC,
+	ATYPE_DIR, ATYPE_DIR, ATYPE_DIR, ATYPE_DIR,
+	ATYPE_DIR, ATYPE_DIR
+};
+char* FILESEARCH::default_dirnames[TYPEMAX] = {
+	0, 0, "", "pdt", 
+	"seen.txt", "allanm.anl", "allard.ard", "allcur.cur", 
+	0, 0, "koe", "bgm", "mov", "gan"};
+
+/*********************************************
+**  ARCFILE / DIRFILE:
+**	書庫ファイル、あるいはディレクトリの
+**	全体を管理するクラス
+**
+**	書庫ファイルからファイルの抜き出しはFind()
+**	Find したものをReadすると内容が得られる。
+*/
+
+ARCFILE::ARCFILE(char* aname) {
+	struct stat sb;
+	/* 変数初期化 */
+	arcname = 0;
+	list_point = 0;
+	filenames_orig = 0;
+	next = 0;
+	if (aname[0] == '\0') {arcname=new char[1]; arcname[0]='\0';return;} // NULFILE
+	/* ディレクトリか否かのチェック */
+	if (stat(aname,&sb) == -1) { /* error */
+		perror("stat");
+	}
+	if ( (sb.st_mode&S_IFMT) == S_IFDIR) {
+		int l = strlen(aname);
+		arcname = new char[l+2]; strcpy(arcname, aname);
+		if (arcname[l-1] != DIR_SPLIT) {
+			arcname[l] = DIR_SPLIT;
+			arcname[l+1] = 0;
+		}
+	} else if ( (sb.st_mode&S_IFMT) == S_IFREG) {
+		arcname = new char[strlen(aname)+1];
+		strcpy(arcname,aname);
+		if (arcname[strlen(arcname)-1] == DIR_SPLIT)
+			arcname[strlen(arcname)-1] = '\0';
+	}
+	return;
+}
+
+void ARCFILE::Init(void) {
+	int i;
+	if (! arc_atom.empty()) return;
+	if (arcname == 0) return;
+	/* ファイル数を得る */
+	int slen = CheckFileDeal();
+	/* ファイル名のセット */
+	ListupFiles(slen);
+	if ( (!arc_atom.empty()) && arc_atom[0].filename) filenames_orig = arc_atom[0].filename;
+	sort(arc_atom.begin(), arc_atom.end());
+}
+ARCFILE::~ARCFILE() {
+	if (filenames_orig) delete[] filenames_orig;
+	delete[] arcname;
+}
+
+ARCFILE::iterator ARCFILE::SearchName(const char* f, const char* ext) {
+	char buf[1024]; char buf_ext[1024];
+	iterator it;
+	Init();
+	if (f == 0) return arc_atom.end();
+	if (arc_atom.empty()) return arc_atom.end();
+	/* エラーチェック */
+	if (strlen(f)>500) return arc_atom.end();
+	if (ext && strlen(ext)>500) return arc_atom.end();
+
+	/* 検索 */
+	strncpy(buf, f, 1000);
+	buf[1000]=0;
+	it = lower_bound(arc_atom.begin(), arc_atom.end(), (char*)buf);
+	if (it != arc_atom.end() && strcmp(it->filename_lower, buf) == 0) return it;
+	// 拡張子をつけて検索
+	if (ext) {
+		strcpy(buf_ext, buf);
+		char* ext_pt = strrchr(buf_ext, '.');
+		if (ext_pt == 0 || ext_pt == buf_ext) ext_pt = buf_ext + strlen(buf_ext);
+		*ext_pt++ = '.';
+		while(*ext=='.') ext++;
+		strcat(buf_ext, ext);
+		it = lower_bound(arc_atom.begin(), arc_atom.end(), (char*)buf_ext);
+		if (it != arc_atom.end() && strcmp(it->filename_lower, buf_ext) == 0) return it;
+	}
+
+	/* 小文字にして 検索 */
+	int i; int l = strlen(f);
+	if (l > 500) l = 500;
+	for (i=0; i<l; i++)
+		buf[i] = tolower(f[i]);
+	buf[i++] = 0;
+	it = lower_bound(arc_atom.begin(), arc_atom.end(), (char*)buf);
+	if (it != arc_atom.end() && strcmp(it->filename_lower, buf) == 0) return it;
+
+	// 拡張子をつけて検索
+	if (ext == 0) return arc_atom.end();
+	strcpy(buf_ext, buf);
+	char* ext_pt = strrchr(buf_ext, '.');
+	if (ext_pt == 0 || ext_pt == buf_ext) ext_pt = buf_ext + strlen(buf_ext);
+	*ext_pt++ = '.';
+	/* 拡張子の長さを得る */
+	l = strlen(ext);
+	for (i=0; i<l; i++)
+		ext_pt[i] = tolower(*ext++);
+	ext_pt[i] = 0;
+	it = lower_bound(arc_atom.begin(), arc_atom.end(), (char*)buf_ext);
+	if (it != arc_atom.end() && strcmp(it->filename_lower, buf_ext) == 0) return it;
+	return arc_atom.end();
+}
+
+ARCINFO* ARCFILE::Find(const char* fname, const char* ext) {
+	Init();
+	iterator atom = SearchName(fname,ext);
+	if (atom == arc_atom.end()) {
+		if (next) return next->Find(fname, ext);
+		else return 0;
+	}
+	return MakeARCINFO(*atom);
+}
+ARCINFO* ARCFILE::MakeARCINFO(ARCFILE_ATOM& atom) {
+	if (atom.arcsize == atom.filesize)
+		return new ARCINFO(arcname, atom);
+	else // 圧縮付
+		return new ARCINFO_AVG32(arcname, atom);
+}
+ARCINFO* NULFILE::MakeARCINFO(ARCFILE_ATOM& atom) {
+	fprintf(stderr,"NULFILE::MakeARCINFO is invalid call!\n");
+	return 0;
+}
+ARCINFO* SCN2kFILE::MakeARCINFO(ARCFILE_ATOM& atom) {
+	return new ARCINFO2k(arcname, atom);
+}
+ARCINFO* DIRFILE::MakeARCINFO(ARCFILE_ATOM& atom) {
+	char* name = atom.filename;
+	char* new_path = new char[strlen(arcname)+strlen(name)+1];
+	strcpy(new_path,arcname); strcat(new_path, name);
+	ARCINFO* ret = new ARCINFO(new_path, atom);
+	delete[] new_path;
+	return ret;
+}
+
+FILE* DIRFILE::Open(const char* fname) {
+	iterator atom = SearchName(fname);
+	if (atom == arc_atom.end()) return 0;
+	char* name = atom->filename;
+	// make FILE*
+	char* new_path = new char[strlen(arcname)+strlen(name)+1];
+	strcpy(new_path,arcname); strcat(new_path, name);
+	FILE* ret = fopen(new_path, "rb+");
+	fseek(ret, 0, 0);
+	delete[] new_path;
+	return ret;
+}
+
+char* DIRFILE::SearchFile(const char* fname) {
+	iterator atom = SearchName(fname);
+	if (atom == arc_atom.end()) return 0;
+	char* name = atom->filename;
+	char* new_path = new char[strlen(arcname)+strlen(name)+1];
+	strcpy(new_path,arcname); strcat(new_path, name);
+	struct stat sb;
+	if (stat(new_path, &sb) == 0 &&
+		( (sb.st_mode&S_IFMT) == S_IFREG ||
+		  (sb.st_mode&S_IFMT) == S_IFDIR)) {
+		return new_path;
+	}
+	delete[] new_path;
+	return 0;
+}
+
+void ARCFILE::ListFiles(FILE* out) {
+	int i;
+	Init();
+	if (arc_atom.empty()) return;
+	// list file name...
+	fprintf(out,"%16s %10s %10s %10s\n", "Filename", 
+		"pointer","arcsize", "filesize");
+	vector<ARCFILE_ATOM>::iterator it;
+	for (it=arc_atom.begin(); it!=arc_atom.end(); it++) {
+		fprintf(out,"%16s %10d %10d %10d\n",
+			it->filename,it->offset,it->arcsize,it->filesize);
+	}
+	return;
+}
+
+void ARCFILE::InitList(void) {
+	Init();
+	list_point = 0;
+}
+char* ARCFILE::ListItem(void) {
+	if (list_point < 0) return 0;
+	if (list_point >= arc_atom.size()) return 0;
+	char* fname = arc_atom[list_point].filename;
+	if (fname == 0) return 0;
+	char* ret = new char[strlen(fname)+1];
+	strcpy(ret, fname);
+	list_point++;
+	return ret;
+}
+
+int ARCFILE::CheckFileDeal(void) {
+	char buf[0x20];
+	/* ヘッダのチェック */
+	FILE* stream = fopen(arcname, "rb");
+	if (stream == 0) {
+		fprintf(stderr, "Cannot open archive file : %s\n",arcname);
+		return 0;
+	}
+	fseek(stream, 0, 2); size_t arc_size = ftell(stream);
+	fseek(stream, 0, 0);
+	if (arc_size < 0x20) {
+		fclose(stream);
+		return 0;
+	}
+	fread(buf, 0x20, 1, stream);
+	if (strncmp(buf, "PACL", 4) != 0) {
+		fclose(stream);
+		return 0;
+	}
+	int len = read_little_endian_int(buf+0x10);
+	if (arc_size < size_t(0x20 + len*0x20)) {
+		fclose(stream);
+		return 0;
+	}
+	int i; int slen = 0;
+	for (i=0; i<len; i++) {
+		fread(buf, 0x20, 1, stream);
+		slen += strlen(buf)+1;
+	}
+	fclose(stream);
+	return slen;
+}
+void ARCFILE::ListupFiles(int fname_len) {
+	int i; char fbuf[0x20];
+	fname_len *= 2;
+	char* buf = new char[fname_len];
+	FILE* stream = fopen(arcname, "rb");
+	if (stream == 0) {
+		fprintf(stderr, "Cannot open archive file : %s\n",arcname);
+		return;
+	}
+	fread(fbuf,0x20,1,stream);
+	int len = read_little_endian_int(fbuf+0x10);
+	ARCFILE_ATOM atom;
+	for (i=0; i<len; i++) {
+		fread(fbuf, 0x20, 1, stream);
+		int l = strlen(fbuf);
+		if (l*2+2 > fname_len) {
+			break;
+		}
+		atom.offset = read_little_endian_int(fbuf+0x10);
+		atom.arcsize = read_little_endian_int(fbuf+0x14);
+		atom.filesize = read_little_endian_int(fbuf+0x18);
+		int j; for (j=0; j<l; j++) {
+			buf[j] = fbuf[j];
+			buf[j+l+1] = tolower(fbuf[j]);
+		}
+		buf[j] = buf[j+l+1] = 0;
+		atom.filename = buf;
+		atom.filename_lower = buf+l+1;
+		arc_atom.push_back(atom);
+		buf += l*2+2; fname_len -= l*2+2;
+	}
+	fclose(stream);
+	return;
+}
+int DIRFILE::CheckFileDeal(void) {
+	DIR* dir; struct dirent* ent;
+	int flen = 0;
+	dir = opendir(arcname);
+	if (dir == 0) {
+		fprintf(stderr, "Cannot open dir file : %s\n",arcname);
+		return 0;
+	}
+	int count = 0;
+	while( (ent = readdir(dir)) != NULL) {
+		count++;
+		flen += strlen(ent->d_name)+1;
+	}
+	closedir(dir);
+	return flen;
+}
+void DIRFILE::ListupFiles(int fname_len) {
+	DIR* dir; int i;
+	fname_len *= 2;
+	dir = opendir(arcname);
+	if (dir == 0) { 
+		fprintf(stderr, "Cannot open dir file : %s\n",arcname);
+		return;
+	}
+	/* 一時的に arcname のディレクトリに移動する */
+	int old_dir_fd = open(".",O_RDONLY);
+	if (old_dir_fd < 0) {
+		closedir(dir);
+		return;
+	}
+	if (chdir(arcname) != 0) {
+		fprintf(stderr, "Cannot open dir file : %s\n",arcname);
+		closedir(dir);
+		close(old_dir_fd);
+		return;
+	};
+	
+	char* buf = new char[fname_len];
+	ARCFILE_ATOM atom;
+	struct stat sb;
+	struct dirent* ent;
+	while( (ent = readdir(dir)) != NULL) {
+		if (stat(ent->d_name, &sb) == -1) continue;
+		if ( (sb.st_mode & S_IFMT) == S_IFREG) {
+			atom.offset = 0;
+			atom.arcsize = sb.st_size;
+			atom.filesize = sb.st_size;
+		} else if ( (sb.st_mode & S_IFMT) == S_IFDIR) {
+			atom.offset = 0;
+			atom.arcsize = atom.filesize = 0;
+		} else {
+			continue;
+		}
+		int l = strlen(ent->d_name);
+		if (l*2+2 > fname_len) {
+			break;
+		}
+		int j; for (j=0; j<l+1; j++) {
+			buf[j] = ent->d_name[j];
+			buf[j+l+1] = tolower(ent->d_name[j]);
+		}
+		atom.filename = buf; atom.filename_lower = buf+l+1;
+		arc_atom.push_back(atom);
+		buf += l*2+2; fname_len -= l*2+2;
+	}
+	/* chdir() したのを元に戻る */
+	closedir(dir);
+	fchdir(old_dir_fd); close(old_dir_fd);
+	return;
+}
+int NULFILE::CheckFileDeal(void) {
+	return 20;
+}
+void NULFILE::ListupFiles(int fname_len) {
+	char* s = new char[40];
+	ARCFILE_ATOM atom;
+	atom.offset = 0; atom.arcsize = 0; atom.filesize = 0;
+	strcpy(s, "** null dummy **");
+	atom.filename = s;
+	atom.filename_lower = s;
+	arc_atom.push_back(atom);
+}
+int SCN2kFILE::CheckFileDeal(void) {
+	/* ヘッダのチェック */
+	FILE* stream = fopen(arcname, "rb");
+	if (stream == 0) {
+		fprintf(stderr, "Cannot open archive file : %s\n",arcname);
+		return 0;
+	}
+	fseek(stream, 0, 2); size_t arc_size = ftell(stream);
+	fseek(stream, 0, 0);
+	if (arc_size < 10000*8) {
+		fclose(stream);
+		return 0;
+	}
+	char* buf = new char[10000*8];
+	fread(buf, 10000, 8, stream);
+	/* size == 0 のデータは存在しない */
+	int count = 0;
+	int i; for (i=0; i<10000; i++) {
+		int tmp_offset = read_little_endian_int(buf+i*8);
+		int tmp_size = read_little_endian_int(buf+i*8+4);
+		if (tmp_size <= 0 || tmp_offset < 0 || tmp_offset+tmp_size > int(arc_size) ) continue;
+		count++;
+	}
+	fclose(stream);
+	delete[] buf;
+	return count*13; /* ファイル名は seenXXXX.txt だから、一つ12文字+null */
+}
+void SCN2kFILE::ListupFiles(int fname_len) {
+	FILE* stream = fopen(arcname, "rb");
+	if (stream == 0) {
+		fprintf(stderr, "Cannot open archive file : %s\n",arcname);
+		return;
+	}
+	char* sbuf = new char[fname_len];
+	char* buf = new char[10000*8];
+	fread(buf, 10000, 8, stream);
+	fseek(stream, 0, 2); size_t arc_size = ftell(stream);
+	ARCFILE_ATOM atom;
+	int i; for (i=0; i<10000; i++) {
+		char header[0x200];
+		int tmp_offset = read_little_endian_int(buf+i*8);
+		int tmp_size = read_little_endian_int(buf+i*8+4);
+		if (tmp_size <= 0 || tmp_offset < 0 || tmp_offset+tmp_size > int(arc_size) ) continue;
+		/* header を得て圧縮形式などを調べる */
+		fseek(stream, tmp_offset, 0);
+		fread(header, 0x200, 1, stream);
+		int header_top = read_little_endian_int(header+0);
+		int file_version = read_little_endian_int(header+4);
+
+		if (file_version == 0x1adb2) ; // Little Busters!
+		else if (file_version != 0x2712) continue; /* system version が違う */
+
+		if (header_top == 0x1cc) { /* 古い形式 : avg2000 */
+			int header_size = read_little_endian_int(header+0)+read_little_endian_int(header+0x20)*4;
+			int data_size = read_little_endian_int(header+0x24);
+			atom.arcsize = data_size + header_size;
+			atom.filesize = data_size + header_size;
+			atom.private_data = header_size;
+
+		} else if (header_top == 0x1b8) { /* 初夜献上 */
+			int header_size = read_little_endian_int(header+0)+read_little_endian_int(header+0x08)*4;
+			int data_size = read_little_endian_int(header+0x0c);
+			int compdata_size = read_little_endian_int(header+0x10);
+			atom.arcsize = compdata_size + header_size;
+			atom.filesize = data_size + header_size;
+			atom.private_data = header_size;
+			
+		} else if (header_top == 0x1d0) { /* 新しい形式: reallive */
+			int header_size = read_little_endian_int(header+0x20);
+			int data_size = read_little_endian_int(header+0x24);
+			int compdata_size = read_little_endian_int(header+0x28);
+			atom.arcsize = compdata_size + header_size;
+			atom.filesize = data_size + header_size;
+			atom.private_data = header_size;
+		} else {
+			fprintf(stderr,"invalid header top; %x : not supported\n",header_top);
+			continue; /* サポートしない形式 */
+		}
+
+		atom.offset = tmp_offset;
+		atom.filename = sbuf;
+		atom.filename_lower = sbuf;
+		arc_atom.push_back(atom);
+		sprintf(sbuf, "seen%04d.txt",i); sbuf += 13;
+	}
+	fclose(stream);
+	return;
+}
+
+/********************************************************
+** FILESEARCH クラスの実装
+*/
+
+FILESEARCH::FILESEARCH(void) {
+	int i;
+	root_dir = 0; dat_dir = 0;
+	for (i=0; i<TYPEMAX; i++) {
+		searcher[i] = 0;
+		filenames[i] = default_dirnames[i];
+		is_archived[i] = default_is_archived[i];
+	}
+}
+FILESEARCH::~FILESEARCH(void) {
+	int i;
+	for (i=0; i<TYPEMAX; i++) {
+		if (filenames[i] != 0 && filenames[i] != default_dirnames[i]) delete[] filenames[i];
+		if (searcher[i] && searcher[i] != dat_dir && searcher[i] != root_dir) {
+			delete searcher[i];
+		}
+	}
+	if (dat_dir && dat_dir != root_dir) delete dat_dir;
+	if (root_dir) delete root_dir;
+}
+
+int FILESEARCH::InitRoot(char* root) {
+	/* 必要に応じて ~/ を展開 */
+	if (root[0] == '~' && root[1] == '/') {
+		char* home = getenv("HOME");
+		if (home != 0) {
+			char* new_root = new char[strlen(home)+strlen(root)];
+			strcpy(new_root, home);
+			strcat(new_root, root+1);
+			root = new_root;
+		}
+	}
+	/* 古いデータを消す */
+	int i;
+	for (i=0; i<TYPEMAX; i++) {
+		if (searcher[i] != 0 &&
+			searcher[i] != root_dir &&
+			searcher[i] != dat_dir) {
+				delete searcher[i];
+		}
+		searcher[i] = 0;
+	}
+	if (dat_dir && root_dir != dat_dir) delete dat_dir;
+	if (root_dir) delete root_dir;
+	dat_dir = 0;
+
+	/* 新しいディレクトリのもとで初期化 */
+	root_dir = new DIRFILE(root);
+	root_dir->Init();
+	/* dat/ を検索 */
+	char* dat_path = root_dir->SearchFile("dat");
+	if (dat_path == 0) {
+		/* 見つからなかったら root を dat の代わりにつかう */
+		dat_dir = root_dir;
+	} else {
+		dat_dir = new DIRFILE(dat_path);
+		dat_dir->Init();
+	}
+	searcher[ALL] = dat_dir;
+	searcher[ROOT] = root_dir;
+	return 0;
+}
+
+void FILESEARCH::SetFileInformation(FILETYPE tp, ARCTYPE is_arc, char* filename) {
+	int type = tp;
+	if (type < 0 || type >= TYPEMAX) return;
+	ARCFILE* next_arc = 0;
+	/* すでに searcher が存在すれば解放 */
+	if (searcher[type] != 0 &&
+	  searcher[type] != root_dir &&
+	  searcher[type] != dat_dir) {
+		next_arc = searcher[type]->Next();
+		delete searcher[type];
+	}
+	searcher[type] = 0;
+	/* 適当に初期化 */
+	if (filenames[type] != 0 &&
+		filenames[type] != default_dirnames[type]) delete[] filenames[type];
+	filenames[type] = new char[strlen(filename)+1];
+	strcpy(filenames[type], filename);
+	is_archived[type] = is_arc;
+	searcher[type] = MakeARCFILE(is_arc, filename);
+	if (searcher[type] && next_arc)
+		searcher[type]->SetNext(next_arc);
+	return;
+}
+void FILESEARCH::AppendFileInformation(FILETYPE tp, ARCTYPE is_arc, char* filename) {
+	int type = tp;
+	if (type < 0 || type >= TYPEMAX) return;
+	/* searcher がまだ割り当てられてない場合 */
+	if (searcher[type] == 0 ||
+	  searcher[type] == root_dir ||
+	  searcher[type] == dat_dir) {
+		searcher[type] = MakeARCFILE(is_archived[type], filenames[type]);
+		if (searcher[type] == 0) { /* 作成できなかった場合 */
+			/* この型情報を FileInformation とする */
+			SetFileInformation(tp, is_arc, filename);
+			return;
+		}
+	}
+	/* 初期化 */
+	ARCFILE* arc = MakeARCFILE(is_arc, filename);
+	/* append */
+	ARCFILE* cur;
+	for (cur=searcher[type]; cur->Next() != 0; cur = cur->Next()) ;
+	cur->SetNext(arc);
+	return;
+}
+
+ARCFILE* FILESEARCH::MakeARCFILE(ARCTYPE tp, char* filename) {
+	ARCFILE* arc = 0;
+	char* file;
+	if (filename == 0) goto err;
+	if (tp == ATYPE_DIR) {
+		file = root_dir->SearchFile(filename);
+	} else {
+		file = dat_dir->SearchFile(filename);
+		if (file == 0)
+			file = root_dir->SearchFile(filename);
+	}
+	if (file == 0) goto err;
+	switch(tp) {
+		case ATYPE_DIR: arc = new DIRFILE(file); break;
+		case ATYPE_SCN2k:
+		case ATYPE_ARC: {
+			FILE* f = fopen(file, "rb");
+			if (f == 0) goto err;
+			char header[32];
+			memset(header, 0, 32);
+			fread(header, 32, 1, f);
+			fclose(f);
+			char magic_raf[8] = {'C','A','P','F',1,0,0,0};
+			if (strncmp(header, "PACL", 4) == 0) arc = new ARCFILE(file);
+			else arc = new SCN2kFILE(file);
+			}
+			break;
+		default: fprintf(stderr,"FILESEARCH::MAKEARCFILE : invalid archive type; type %d name %s\n",tp,filename);
+			delete[] file;
+			goto err;
+	}
+	delete[] file;
+	return arc;
+err:
+	arc = new NULFILE;
+	return arc;
+	
+}
+
+ARCINFO* FILESEARCH::Find(FILETYPE type, const char* fname, const char* ext) {
+	if (searcher[type] == 0) {
+		/* searcher 作成 */
+		if (filenames[type] == 0) {
+			searcher[type] = dat_dir;
+		} else {
+			searcher[type] = MakeARCFILE(is_archived[type], filenames[type]);
+			if (searcher[type] == 0) {
+				fprintf(stderr,"FILESEARCH::Find : invalid archive type; type %d name %s\n",type,fname);
+				return 0;
+			}
+		}
+	}
+	return searcher[type]->Find(fname,ext);
+}
+
+char** FILESEARCH::ListAll(FILETYPE type) {
+	int i;
+	/* とりあえず searcher を初期化 */
+	Find(type, "THIS FILENAME MAY NOT EXIST IN THE FILE SYSTEM !!!");
+	if (searcher[type] == 0) return 0;
+	/* 全ファイルのリストアップ */
+	int deal = 0;
+	ARCFILE* file;
+	for (file = searcher[type]; file != 0; file = file->Next())
+		deal += file->Deal();
+	if (deal <= 0) return 0;
+	char** ret_list = new char*[deal+1];
+	int count = 0;
+	for (file = searcher[type]; file != 0; file = file->Next()) {
+		file->InitList();
+		char* f;
+		while( (f = file->ListItem() ) != 0) {
+			ret_list[count] = new char[strlen(f)+1];
+			strcpy(ret_list[count], f);
+			count++;
+		}
+	}
+	ret_list[count] = 0;
+	return ret_list;
+}
+
+ARCINFO::ARCINFO(const char* __arcname, ARCFILE_ATOM& atom) : info(atom) {
+	arcfile = new char[strlen(__arcname)+1];
+	strcpy(arcfile, __arcname);
+	use_mmap = false;
+	mmapped_memory = 0;
+	data = 0;
+	fd = -1;
+}
+
+ARCINFO::~ARCINFO() {
+#ifdef HAVE_MMAP
+	if (mmapped_memory) munmap(mmapped_memory, info.arcsize);
+#endif /* HAVE_MMAP */
+	if (fd != -1) close(fd);
+	if (data != mmapped_memory) delete[] data;
+	delete[] arcfile;
+}
+
+int ARCINFO::Size(void) const {
+	return info.filesize;
+}
+
+/* コピーを返す */
+char* ARCINFO::CopyRead(void) {
+	const char* d = Read();
+	if (d == 0) return 0;
+	int s = Size();
+	if (s <= 0) return 0;
+	char* ret = new char[s]; memcpy(ret, d, s);
+	return ret;
+}
+
+const char* ARCINFO::Path(void) const {
+	if (info.offset != 0) return 0; /* archive file なのでパスを帰せない */
+	char* ret = new char[strlen(arcfile)+1];
+	strcpy(ret, arcfile);
+	return ret;
+}
+/* 互換性専用 */
+FILE* ARCINFO::OpenFile(int* length) const {
+	FILE* f = fopen(arcfile, "rb");
+	if (info.offset) lseek(fileno(f), info.offset, SEEK_SET);
+	if (length) *length = info.arcsize;
+	return f;
+}
+
+// 展開処理はなし
+bool ARCINFO::ExecExtract(void) {
+	return true;
+}
+/* 読み込みを開始する */
+const char* ARCINFO::Read(void) {
+	// すでにデータを読み込み済みなら何もしない
+	if (data) return data;
+
+	if (info.offset < 0 || info.arcsize <= 0) {
+		return 0;
+	}
+	/* ファイルを開く */
+	fd = open(arcfile, O_RDONLY);
+	if (fd < 0) {
+		return 0;
+	}
+	if (lseek(fd, info.offset, 0) != info.offset) {
+		close(fd); fd = -1; return 0;
+	}
+	/* mmap を試みる */
+#ifdef HAVE_MMAP
+	mmapped_memory = (char*)mmap(0, info.arcsize, PROT_READ, MAP_SHARED, fd, info.offset);
+	if (mmapped_memory != MAP_FAILED) {
+		use_mmap = true;
+		data = (const char*)mmapped_memory;
+	} else
+#endif /* HAVE_MMAP */
+	{
+		/* 失敗:普通にファイルを読み込み */
+		char* d = new char[info.arcsize];
+		read(fd, d, info.arcsize);
+		close(fd);
+		fd = -1;
+		use_mmap = false;
+		data = d;
+	}
+	/* 展開する */
+	if (! ExecExtract()) {
+		// 失敗
+#ifdef HAVE_MMAP
+		if (use_mmap) {
+			munmap(mmapped_memory, info.arcsize);
+			if (data == (const char*)mmapped_memory) data = 0;
+		}
+#endif /* HAVE_MMAP */
+		delete[] (char*)data;
+		close(fd);
+		fd = -1; data = 0;
+		return 0;
+	}
+#ifdef HAVE_MMAP
+	if (use_mmap && data != (const char*)mmapped_memory) {
+		// すでに mmap は必要ない
+		munmap(mmapped_memory, info.arcsize);
+		close(fd);
+		fd = -1;
+		use_mmap = false;
+	}
+#endif /* HAVE_MMAP */
+	return data;
+}
+
+/**********************************************
+**
+**	画像展開系クラスの定義、実装
+**
+***********************************************
+*/
+GRPCONV::GRPCONV(void) {
+	filename = 0;
+	data = 0;
+}
+GRPCONV::~GRPCONV() {
+	if (filename) delete[] filename;
+}
+void GRPCONV::Init(const char* f, const char* d, int dlen, int w, int h, bool is_m) {
+	if (filename) delete[] filename;
+	if (f == 0) {
+		char* fn = new char[1];
+		fn[0] = 0;
+		filename = fn;
+	} else {
+		char* fn = new char[strlen(f)+1];
+		strcpy(fn,f);
+		filename = fn;
+	}
+
+	data = d;
+	datalen = dlen;
+	width = w;
+	height = h;
+	is_mask = is_m;
+}
+class PDTCONV : public GRPCONV {
+	bool Read_PDT10(char* image);
+	bool Read_PDT11(char* image);
+public:
+	PDTCONV(const char* _inbuf, int inlen, const char* fname);
+	~PDTCONV() {}
+	bool Read(char* image);
+};
+class G00CONV : public GRPCONV {
+	struct REGION {
+		int x1, y1, x2, y2;
+		int Width() { return x2-x1+1;}
+		int Height() { return y2-y1+1;}
+		void FixVar(int& v, int& w) {
+			if (v < 0) v = 0;
+			if (v >= w) v = w-1;
+		}
+		void Fix(int w, int h) {
+			FixVar(x1,w);
+			FixVar(x2,w);
+			FixVar(y1,h);
+			FixVar(y2,h);
+			if (x1 > x2) x2 = x1;
+			if (y1 > y2) y2 = y1;
+		}
+	};
+
+	void Copy_16bpp(char* image, int x, int y, const char* src, int bpl, int h);
+	void Copy_32bpp(char* image, int x, int y, const char* src, int bpl, int h);
+	bool Read_Type0(char* image);
+	bool Read_Type1(char* image);
+	bool Read_Type2(char* image);
+public:
+	G00CONV(const char* _inbuf, int _inlen, const char* fname);
+	~G00CONV() { }
+	bool Read(char* image);
+};
+
+class BMPCONV : public GRPCONV {
+public:
+	BMPCONV(const char* _inbuf, int _inlen, const char* fname);
+	~BMPCONV() {};
+	bool Read(char* image);
+};
+#if HAVE_LIBPNG
+class PNGCONV : public GRPCONV {
+	const char* png_data;
+	static void png_read(png_structp, png_bytep, png_size_t);
+
+public:
+	PNGCONV(const char* _inbuf, int _inlen, const char* fname);
+	~PNGCONV() {};
+	bool Read(char* image);
+};
+#endif
+
+#if HAVE_LIBJPEG
+class JPEGCONV : public GRPCONV {
+
+public:
+	JPEGCONV(const char* _inbuf, int _inlen, const char* fname);
+	~JPEGCONV() {};
+	bool Read(char* image);
+	void SetupSrc(struct jpeg_decompress_struct* cinfo, const char* data, int size);
+	static void init_source(j_decompress_ptr cinfo);
+	static boolean fill_input_buffer(j_decompress_ptr cinfo);
+	static void skip_input_data(j_decompress_ptr cinfo, long num_bytes);
+	static boolean resync_to_restart(j_decompress_ptr cinfo, int desired);
+	static void term_source(j_decompress_ptr cinf);
+};
+#endif
+
+GRPCONV* GRPCONV::AssignConverter(const char* inbuf, int inlen, const char* fname) {
+	/* ファイルの内容に応じたコンバーターを割り当てる */
+	GRPCONV* conv = 0;
+	if (inlen < 10) return 0; /* invalid file */
+	if (conv == 0 && strncmp(inbuf, "PDT10", 5) == 0 || strncmp(inbuf, "PDT11", 5) == 0) { /* PDT10 or PDT11 */
+		conv = new PDTCONV(inbuf, inlen, fname);
+		if (conv->data == 0) { delete conv; conv = 0;}
+	}
+#if HAVE_LIBPNG
+	unsigned char png_magic[4] = {0x89, 'P', 'N', 'G'};
+	if (conv == 0 && memcmp(inbuf, png_magic,4) == 0) {
+		conv = new PNGCONV(inbuf, inlen, fname);
+		if (conv->data == 0) { delete conv; conv = 0;}
+	}
+#endif
+#if HAVE_LIBJPEG
+	if ( conv == 0 && *(unsigned char*)inbuf == 0xff && *(unsigned char*)(inbuf+1) == 0xd8 &&
+		(strncmp(inbuf+6, "JFIF",4) == 0 || strncmp(inbuf+6,"Exif",4) == 0)) {
+		conv = new JPEGCONV(inbuf, inlen, fname);
+		if (conv->data == 0) { delete conv; conv = 0;}
+	}
+#endif
+	if (conv == 0 && inbuf[0]=='B' && inbuf[1]=='M' && read_little_endian_int(inbuf+10)==0x36 && read_little_endian_int(inbuf+14) == 0x28) { // Windows BMP
+		conv = new BMPCONV(inbuf, inlen, fname);
+		if (conv->data == 0) { delete conv; conv = 0;}
+	}
+	if (conv == 0 && (inbuf[0] == 0 || inbuf[0] == 1 || inbuf[0] == 2)) { /* G00 */
+		conv = new G00CONV(inbuf, inlen, fname);
+		if (conv->data == 0) { delete conv; conv = 0;}
+	}
+	return conv;
+}
+
+PDTCONV::PDTCONV(const char* _inbuf, int _inlen,const char* filename) {
+//	PDT FILE のヘッダ
+//	+00 'PDT10'	(PDT11 は未対応)
+//	+08 ファイルサイズ (無視)
+//	+0C width (ほぼすべて、640)
+//	+10 height(ほぼすべて、480)
+//	+14 (mask の) x 座標 (実際は無視・・・全ファイルで 0 )
+//	+1c (mask の) y座標 (実際は無視 ・・・全ファイルで 0 )
+//	+20 mask が存在すれば、mask へのポインタ
+
+	/* ヘッダチェック */
+	if (_inlen < 0x20) {
+		fprintf(stderr, "Invalid PDT file %s : size is too small\n",filename);
+		return;
+	}
+	if (strncmp(_inbuf, "PDT10", 5) != 0 && strncmp(_inbuf, "PDT11", 5) != 0) {
+		fprintf(stderr, "Invalid PDT file %s : not 'PDT10 / PDT11' file.\n", filename);
+		return;
+	}
+	if (size_t(_inlen) != size_t(read_little_endian_int(_inbuf+0x08))) {
+		fprintf(stderr, "Invalid archive file %s : invalid header.(size)\n",
+			filename);
+		return;
+	}
+
+	int w = read_little_endian_int(_inbuf+0x0c);
+	int h = read_little_endian_int(_inbuf+0x10);
+	int mask_pt = read_little_endian_int(_inbuf + 0x1c);
+	Init(filename, _inbuf, _inlen, w, h, mask_pt ? true : false);
+
+	return;
+}
+
+
+G00CONV::G00CONV(const char* _inbuf, int _inlen, const char* filename) {
+//	G00 FILE のヘッダ
+//	+00 type (1, 2)
+//	+01: width(word)
+//	+03: height(word)
+//	type 1: (color table 付き LZ 圧縮 ; PDT11 に対応)
+//		+05: 圧縮サイズ(dword) ; +5 するとデータ全体のサイズ
+//		+09: 展開後サイズ(dword)
+//	type 2: (マスク可、画像を矩形領域に分割してそれぞれ圧縮)
+//		+05: index size
+//		+09: index table(each size is 0x18)
+//			+00
+//			
+//		+09+0x18*size+00: data size
+//		+09+0x18*size+04: out size
+//		+09+0x18*size+08: (data top)
+//
+
+	/* データから情報読み込み */
+	int type = *_inbuf;
+
+	int w = read_little_endian_short(_inbuf+1);
+	int h = read_little_endian_short(_inbuf+3);
+	if (w < 0 || h < 0) return;
+
+	if (type == 0 || type == 1) { // color table 付き圧縮
+		if (_inlen < 13) {
+			fprintf(stderr, "Invalid G00 file %s : size is too small\n",filename);
+			return;
+		}
+		int data_sz = read_little_endian_int(_inbuf+5);
+
+		if (_inlen != data_sz+5) {
+			fprintf(stderr, "Invalid archive file %s : invalid header.(size)\n",
+				filename);
+			return;
+		}
+		Init(filename, _inbuf, _inlen, w, h, false);
+	} else if (type == 2) { // color table なし、マスク付き可の圧縮
+
+		int head_size = read_little_endian_short(_inbuf+5);
+		if (head_size < 0 || head_size*24 > _inlen) return;
+
+		const char* data_top = _inbuf + 9 + head_size*24;
+		int data_sz = read_little_endian_int(data_top);
+		if (_inbuf + _inlen != data_top + data_sz) {
+			fprintf(stderr, "Invalid archive file %s : invalid header.(size)\n",
+				filename);
+			return;
+		}
+		Init(filename, _inbuf, _inlen, w, h, true);
+	}
+	return;
+}
+
+bool G00CONV::Read(char* image) {
+	if (data == 0) return false;
+	/* header 識別 */
+	int type = *data;
+	if (type == 0) return Read_Type0(image);
+	else if (type == 1) return Read_Type1(image);
+	else if (type == 2) return Read_Type2(image);
+}
+
+/* 一般的な LZ 圧縮の展開ルーチン */
+/* datasize はデータの大きさ、char / short / int を想定 */
+/* datatype は Copy1Pixel (1データのコピー)及び ExtractData(LZ 圧縮の情報を得る
+** というメソッドを実装したクラス */
+static int bitrev_table[256] = {
+	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff};
+template<class DataType, class DataSize> inline int lzExtract(DataType& datatype,const char*& src, char*& dest, const char* srcend, char* destend) {
+	int count = 0;
+	const char* lsrcend = srcend; char* ldestend = destend;
+	const char* lsrc = src; char* ldest = dest;
+
+	if (lsrc+50 < lsrcend && ldest+1024 < ldestend) {
+		/* まず、範囲チェックを緩くして高速なルーチンを使う */
+		lsrcend -= 50;
+		ldestend += 1024;
+		while (ldest < ldestend && lsrc < lsrcend) {
+			count += 8;
+			int flag = int(*(unsigned char*)lsrc++);
+			if (datatype.IsRev()) flag = bitrev_table[flag];
+			int i; for (i=0; i<8; i++) {
+				if (flag & 0x80) {
+					datatype.Copy1Pixel(lsrc, ldest);
+				} else {
+					int data, size;
+					datatype.ExtractData(lsrc, data, size);
+					DataSize* p_dest = ((DataSize*)ldest) - data;
+					int k; for (k=0; k<size; k++) {
+						p_dest[data] = *p_dest;
+						p_dest++;
+					}
+					ldest += size*sizeof(DataSize);
+				}
+				flag <<= 1;
+			}
+		}
+		lsrcend += 50;
+		ldestend += 1024;
+	}
+	/* 残りを変換 */
+	while (ldest < ldestend && lsrc < lsrcend) {
+		count += 8;
+		int flag = int(*(unsigned char*)lsrc++);
+		if (datatype.IsRev()) flag = bitrev_table[flag];
+		int i; for (i=0; i<8 && ldest < ldestend && lsrc < lsrcend; i++) {
+			if (flag & 0x80) {
+				datatype.Copy1Pixel(lsrc, ldest);
+			} else {
+				int data, size;
+				datatype.ExtractData(lsrc, data, size);
+				DataSize* p_dest = ((DataSize*)ldest) - data;
+				int k; for (k=0; k<size; k++) {
+					p_dest[data] = *p_dest;
+					p_dest++;
+				}
+				ldest += size*sizeof(DataSize);
+			}
+			flag <<= 1;
+		}
+	}
+	dest=ldest; src=lsrc;
+	return 0;
+}
+/* 引数を減らすためのwrapper */
+template<class DataType, class DataSize> inline int lzExtract(DataType datatype, DataSize datasize ,const char*& src, char*& dest, const char* srcend, char* destend) {
+	return lzExtract<DataType, DataSize>(datatype,src,dest,srcend,destend);
+}
+
+/* 普通の PDT */
+class Extract_DataType {
+public:
+	static void ExtractData(const char*& lsrc, int& data, int& size) {
+		data = read_little_endian_short(lsrc) & 0xffff;
+		size = (data & 0x0f) + 1;
+		data = (data>>4)+1;
+		lsrc += 2;
+	}
+	static void Copy1Pixel(const char*& lsrc, char*& ldest) {
+#ifdef WORDS_BIGENDIAN
+		ldest[3] = lsrc[0];
+		ldest[2] = lsrc[1];
+		ldest[1] = lsrc[2];
+		ldest[0] = 0;
+#else
+		*(int*)ldest = read_little_endian_int(lsrc); ldest[3]=0;
+#endif
+		lsrc += 3; ldest += 4;
+	}
+	static int IsRev(void) { return 0; }
+};
+
+/* PDT11 の第一段階変換 */
+class Extract_DataType_PDT11 {
+	int* index_table;
+public:
+	Extract_DataType_PDT11(int* it) { index_table = it; }
+	void ExtractData(const char*& lsrc, int& data, int& size) {
+		data = int(*(const unsigned char*)lsrc);
+		size = (data>>4) + 2;
+		data = index_table[data&0x0f];
+		lsrc++;
+	}
+	static void Copy1Pixel(const char*& lsrc, char*& ldest) {
+		*ldest = *lsrc;
+		ldest++; lsrc++;
+	}
+	static int IsRev(void) { return 0; }
+};
+/* マスク用 */
+class Extract_DataType_Mask {
+public:
+	void ExtractData(const char*& lsrc, int& data, int& size) {
+		int d = read_little_endian_short(lsrc) & 0xffff;
+		size = (d & 0xff) + 2;
+		data = (d>>8)+1;
+		lsrc += 2;
+	}
+	static void Copy1Pixel(const char*& lsrc, char*& ldest) {
+		*ldest = *lsrc;
+		ldest++; lsrc++;
+	}
+	static int IsRev(void) { return 0; }
+};
+/* 書庫用 */
+class Extract_DataType_ARC {
+public:
+	void ExtractData(const char*& lsrc, int& data, int& size) {
+		data = read_little_endian_short(lsrc) & 0xffff;
+		size = (data&0x0f) + 2;
+		data = (data>>4) + 1;
+		lsrc+= 2;
+	}
+	static void Copy1Pixel(const char*& lsrc, char*& ldest) {
+		*ldest = *lsrc;
+		ldest++; lsrc++;
+	}
+	static int IsRev(void) { return 0; }
+};
+/* avg2000 のシナリオ用 */
+class Extract_DataType_SCN2k {
+public:
+	void ExtractData(const char*& lsrc, int& data, int& size) {
+		data = read_little_endian_short(lsrc) & 0xffff;
+		size = (data&0x0f) + 2;
+		data = (data>>4);
+		lsrc+= 2;
+	}
+	static void Copy1Pixel(const char*& lsrc, char*& ldest) {
+		*ldest = *lsrc;
+		ldest++; lsrc++;
+	}
+	static int IsRev(void) { return 1; }
+};
+/* ReadLive の type0 */
+class Extract_DataType_G00Type0 {
+public:
+	static void ExtractData(const char*& lsrc, int& data, int& size) {
+		data = read_little_endian_short(lsrc) & 0xffff;
+		size = ((data & 0x0f)+ 1) * 3;
+		data = (data>>4) * 3;
+		lsrc += 2;
+	}
+	static void Copy1Pixel(const char*& lsrc, char*& ldest) {
+#ifdef WORDS_BIGENDIAN
+		ldest[0] = lsrc[0];
+		ldest[1] = lsrc[1];
+		ldest[2] = lsrc[2];
+#else /* LITTLE ENDIAN / intel architecture */
+		*(int*)ldest = *(int*)lsrc;
+#endif
+		lsrc += 3; ldest += 3;
+	}
+	static int IsRev(void) { return 1; }
+};
+
+
+bool PDTCONV::Read(char* image) {
+	if (data == 0) return false;
+
+	if (strncmp(data, "PDT10", 5) == 0) {
+		if (! Read_PDT10(image)) return false;
+	} else if (strncmp(data, "PDT11", 5) == 0) {
+		if (! Read_PDT11(image)) return false;
+	}
+	if (! is_mask) return true;
+	// マスク読み込み
+	int mask_pt = read_little_endian_int(data + 0x1c);
+	char* buf = new char[width*height+1024];
+	const char* src = data + mask_pt;
+	const char* srcend = data + datalen;
+	char* dest = buf;
+	char* destend = buf + width*height;
+	while(lzExtract(Extract_DataType_Mask(), char(), src, dest, srcend, destend)) ;
+	int i; int len = width*height;
+	src = buf; dest = image;
+	for (i=0; i<len; i++) {
+		*(int*)dest |= int(*(unsigned char*)src) << 24;
+		src++;
+		dest += 4;
+	}
+	delete[] buf;
+	return true;
+}
+
+
+bool PDTCONV::Read_PDT10(char* image) {
+	int mask_pt = read_little_endian_int(data + 0x1c);
+
+	const char* src = data + 0x20;
+	const char* srcend;
+	if (mask_pt == 0) srcend = data + datalen;
+	else srcend = data + mask_pt;
+
+	char* dest = image;
+	char* destend;
+
+	destend = image + width*height*4;
+	while(lzExtract(Extract_DataType(), int(), src, dest, srcend, destend)) ;
+	return true;
+}
+bool PDTCONV::Read_PDT11(char* image) {
+	int index_table[16];
+	int color_table[256];
+	int i;
+	for (i=0; i<16; i++)
+		index_table[i] = read_little_endian_int(data + 0x420 + i*4);
+
+	int mask_pt = read_little_endian_int(data + 0x1c);
+
+	const char* src = data + 0x460;
+	const char* srcend;
+	if (mask_pt == 0) srcend = data + datalen;
+	else srcend = data + mask_pt;
+
+	char* dest = image;
+	char* destend = image + width*height;
+
+	while(lzExtract(Extract_DataType_PDT11(index_table), char(), src, dest, srcend, destend)) ;
+
+	const char* cur = data + 0x20;
+	for (i=0; i<256; i++) {
+		color_table[i] =  read_little_endian_int(cur);
+		cur += 4;
+	}
+	src = image + width*height;
+	int* desti = (int*)(image + width*height*4);
+	while(desti != (int*)image)
+		*--desti = color_table[*(unsigned char*)--src];
+	return true;
+}
+
+/* dest は dest_end よりも 256 byte 以上先まで
+** 書き込み可能であること。
+*/
+void ARCINFO::Extract(char*& dest_start, char*& src_start, char* dest_end, char* src_end) {
+	const char* src = src_start;
+	while (lzExtract(Extract_DataType_ARC(), char(), src, dest_start, src_end, dest_end)) ;
+	src_start = (char*)src;
+	return;
+}
+void ARCINFO::Extract2k(char*& dest_start, char*& src_start, char* dest_end, char* src_end) {
+	const char* src = src_start;
+	while (lzExtract(Extract_DataType_SCN2k(), char(), src, dest_start, src_end, dest_end)) ;
+	src_start = (char*)src;
+	return;
+}
+
+bool ARCINFO_AVG32::ExecExtract(void) {
+	// ヘッダのチェック
+	if (strncmp(data, "PACK", 4) != 0) return false;
+	if (read_little_endian_int(data+8) != info.filesize) return false;
+	if (read_little_endian_int(data+12) != info.arcsize) return false;
+
+	// ファイルを展開する
+	char* ret_data = new char[info.filesize+1024];
+
+	const char* s = data + 0x10;
+	const char* send = data + info.arcsize;
+	char* d = ret_data;
+	char* dend = ret_data + info.filesize;
+	while(lzExtract(Extract_DataType_ARC(), char(), s, d, send, dend)) ;
+	if (! use_mmap) delete[] data;
+	data = ret_data;
+	return true;
+}
+
+char ARCINFO2k::decode_seed[256] ={
+ 0x8b ,0xe5 ,0x5d ,0xc3 ,0xa1 ,0xe0 ,0x30 ,0x44 ,0x00 ,0x85 ,0xc0 ,0x74 ,0x09 ,0x5f ,0x5e ,0x33
+,0xc0 ,0x5b ,0x8b ,0xe5 ,0x5d ,0xc3 ,0x8b ,0x45 ,0x0c ,0x85 ,0xc0 ,0x75 ,0x14 ,0x8b ,0x55 ,0xec
+,0x83 ,0xc2 ,0x20 ,0x52 ,0x6a ,0x00 ,0xe8 ,0xf5 ,0x28 ,0x01 ,0x00 ,0x83 ,0xc4 ,0x08 ,0x89 ,0x45
+,0x0c ,0x8b ,0x45 ,0xe4 ,0x6a ,0x00 ,0x6a ,0x00 ,0x50 ,0x53 ,0xff ,0x15 ,0x34 ,0xb1 ,0x43 ,0x00
+,0x8b ,0x45 ,0x10 ,0x85 ,0xc0 ,0x74 ,0x05 ,0x8b ,0x4d ,0xec ,0x89 ,0x08 ,0x8a ,0x45 ,0xf0 ,0x84
+,0xc0 ,0x75 ,0x78 ,0xa1 ,0xe0 ,0x30 ,0x44 ,0x00 ,0x8b ,0x7d ,0xe8 ,0x8b ,0x75 ,0x0c ,0x85 ,0xc0
+,0x75 ,0x44 ,0x8b ,0x1d ,0xd0 ,0xb0 ,0x43 ,0x00 ,0x85 ,0xff ,0x76 ,0x37 ,0x81 ,0xff ,0x00 ,0x00
+,0x04 ,0x00 ,0x6a ,0x00 ,0x76 ,0x43 ,0x8b ,0x45 ,0xf8 ,0x8d ,0x55 ,0xfc ,0x52 ,0x68 ,0x00 ,0x00
+,0x04 ,0x00 ,0x56 ,0x50 ,0xff ,0x15 ,0x2c ,0xb1 ,0x43 ,0x00 ,0x6a ,0x05 ,0xff ,0xd3 ,0xa1 ,0xe0
+,0x30 ,0x44 ,0x00 ,0x81 ,0xef ,0x00 ,0x00 ,0x04 ,0x00 ,0x81 ,0xc6 ,0x00 ,0x00 ,0x04 ,0x00 ,0x85
+,0xc0 ,0x74 ,0xc5 ,0x8b ,0x5d ,0xf8 ,0x53 ,0xe8 ,0xf4 ,0xfb ,0xff ,0xff ,0x8b ,0x45 ,0x0c ,0x83
+,0xc4 ,0x04 ,0x5f ,0x5e ,0x5b ,0x8b ,0xe5 ,0x5d ,0xc3 ,0x8b ,0x55 ,0xf8 ,0x8d ,0x4d ,0xfc ,0x51
+,0x57 ,0x56 ,0x52 ,0xff ,0x15 ,0x2c ,0xb1 ,0x43 ,0x00 ,0xeb ,0xd8 ,0x8b ,0x45 ,0xe8 ,0x83 ,0xc0
+,0x20 ,0x50 ,0x6a ,0x00 ,0xe8 ,0x47 ,0x28 ,0x01 ,0x00 ,0x8b ,0x7d ,0xe8 ,0x89 ,0x45 ,0xf4 ,0x8b
+,0xf0 ,0xa1 ,0xe0 ,0x30 ,0x44 ,0x00 ,0x83 ,0xc4 ,0x08 ,0x85 ,0xc0 ,0x75 ,0x56 ,0x8b ,0x1d ,0xd0
+,0xb0 ,0x43 ,0x00 ,0x85 ,0xff ,0x76 ,0x49 ,0x81 ,0xff ,0x00 ,0x00 ,0x04 ,0x00 ,0x6a ,0x00 ,0x76};
+char ARCINFO2k::decode_seed2[16] = {
+	0xa8, 0x28, 0xfd, 0x66,
+	0xa0, 0x23, 0x77, 0x69,
+	0xf9, 0x45, 0xf8, 0x2c,
+	0x7c, 0x00, 0xad, 0xf4
+};
+
+bool ARCINFO2k::ExecExtract(void) {
+	int i;
+	char* ret_data = new char[info.filesize + 1024];
+	char* decoded_data = new char[info.arcsize + 1024];
+	
+	/* header のコピー */
+	memcpy(ret_data, data, info.private_data);
+
+	/* まず、xor の暗号化を解く */
+	const char* s; const char* send;
+	char* d; char* dend;
+
+	s = data + info.private_data;
+	send = data + info.arcsize;
+	d = decoded_data + info.private_data;
+	dend = decoded_data + info.arcsize;
+	i = 0;
+	while(s != send)
+		*d++ = *s++ ^ decode_seed[(i++)&0xff];
+
+	if (info.filesize == info.arcsize) {
+		memcpy(ret_data+info.private_data, decoded_data + info.private_data + 8, info.arcsize - info.private_data - 8);
+	} else {
+		/* 圧縮されているなら、それを展開 */
+		s = (const char*)(decoded_data + info.private_data + 8);
+		send = (const char*)(decoded_data + info.arcsize);
+		d = ret_data + info.private_data;
+		dend = ret_data + info.filesize;
+		while(lzExtract(Extract_DataType_SCN2k(), char(), s, d, send, dend)) ;
+	}
+	if (read_little_endian_int(data+4) == 0x1adb2) { // Little Busters!
+		int header_size = info.private_data;
+		for (i=0x100; i<=0x200 && header_size+i < info.filesize; i++) {
+			ret_data[header_size+i] ^= decode_seed2[i&0x0f];
+		}
+	}
+	delete[] decoded_data;
+	if (! use_mmap) delete[] data;
+	data = ret_data;
+	return true;
+}
+
+bool G00CONV::Read_Type0(char* image) {
+	int uncompress_size = read_little_endian_int(data+9);
+	char* uncompress_data = new char[uncompress_size+1024];
+
+	// まず展開
+	const char* src = data + 13;
+	const char* srcend = data + datalen;
+	char* dest = uncompress_data;
+	char* dstend = uncompress_data + uncompress_size;
+	while(lzExtract(Extract_DataType_G00Type0(), char(), src, dest, srcend, dstend));
+	// image にコピー
+	CopyRGB(image, uncompress_data);
+	delete[] uncompress_data;
+	return true;
+}
+bool G00CONV::Read_Type1(char* image) {
+	int i;
+	int uncompress_size = read_little_endian_int(data+9) + 1;
+	char* uncompress_data = new char[uncompress_size + 1024];
+
+	// まず、展開
+	const char* src = data + 13;
+	const char* srcend = data + datalen;
+	char* dest = uncompress_data;
+	char* destend = uncompress_data + uncompress_size;
+
+	while(lzExtract(Extract_DataType_SCN2k(), char(), src, dest, srcend, destend));
+
+	int colortable[256];
+	memset(colortable, 0, sizeof(int)*256);
+	int colortable_len = read_little_endian_short(uncompress_data);
+	if (colortable_len > 256) colortable_len = 256;
+	if (colortable_len < 0) colortable_len = 0;
+	for (i=0; i<colortable_len; i++) {
+		colortable[i] = read_little_endian_int(uncompress_data+2+i*4);
+	}
+	src = uncompress_data + 2 + read_little_endian_short(uncompress_data)*4;
+	srcend = uncompress_data + uncompress_size;
+	dest = image; destend = image + width*height*4;
+	while(dest < destend && src < srcend) {
+		*(int*)dest = colortable[*(unsigned char*)src];
+		dest += 4; src ++;
+	}
+	delete[] uncompress_data;
+	return true;
+}
+
+bool G00CONV::Read_Type2(char* image) {
+	memset(image, 0, width*height*4);
+	/* 分割領域を得る */
+	int region_deal = read_little_endian_int(data+5);
+	REGION* region_table = new REGION[region_deal];
+
+	const char* head = data + 9;
+	int i; for (i=0; i<region_deal; i++) {
+		region_table[i].x1 = read_little_endian_int(head+0);
+		region_table[i].y1 = read_little_endian_int(head+4);
+		region_table[i].x2 = read_little_endian_int(head+8);
+		region_table[i].y2 = read_little_endian_int(head+12);
+		region_table[i].Fix(width, height);
+		head += 24;
+	}
+
+	// 展開
+	int uncompress_size = read_little_endian_int(head+4);
+	char* uncompress_data = new char[uncompress_size + 1024];
+
+	const char* src = head + 8;
+	const char* srcend = data + datalen;
+	char* dest = uncompress_data;
+	char* destend = uncompress_data + uncompress_size;
+	while(lzExtract(Extract_DataType_SCN2k(), char(), src, dest, srcend, destend));
+
+	/* region_deal2 == region_deal のはず……*/
+	int region_deal2 = read_little_endian_int(uncompress_data);
+	if (region_deal > region_deal2) region_deal = region_deal2;
+
+	for (i=0; i < region_deal; i++) {
+		int offset = read_little_endian_int(uncompress_data + i*8 + 4);
+		int length = read_little_endian_int(uncompress_data + i*8 + 8);
+		src = (const char*)(uncompress_data + offset + 0x74);
+		srcend = (const char*)(uncompress_data + offset + length);
+		while(src < srcend) {
+			int x, y, w, h;
+			/* コピーする領域を得る */
+			x = read_little_endian_short(src);
+			y = read_little_endian_short(src+2);
+			w = read_little_endian_short(src+6);
+			h = read_little_endian_short(src+8);
+			src += 0x5c;
+
+			x += region_table[i].x1;
+			y += region_table[i].y1;
+
+			Copy_32bpp(image, x, y, src, w*4, h);
+
+			src += w*h*4;
+		}
+	}
+	delete[] uncompress_data;
+	return true;
+}
+
+void G00CONV::Copy_32bpp(char* image, int x, int y, const char* src, int bpl, int h) {
+	int i;
+	int* dest = (int*)(image + x*4 + y*4*width);
+	int w = bpl / 4;
+	for (i=0; i<h; i++) {
+		const char* s = src;
+		int* d = dest;
+		int j; for (j=0; j<w; j++) {
+			*d++ = read_little_endian_int(s);
+			s += 4;
+		}
+		src += bpl; dest += width;
+	}
+}
+
+void GRPCONV::CopyRGBA_rev(char* image, const char* buf) {
+	int mask = is_mask ? 0 : 0xff000000;
+	/* 色変換を行う */
+	int len = width * height;
+	int i;
+	unsigned char* s = (unsigned char*)buf;
+	int* d = (int*)image;
+	for(i=0; i<len; i++) {
+		*d = (int(s[2])) | (int(s[1])<<8) | (int(s[0])<<16) | (int(s[3])<<24) | mask;
+		d++; s += 4;
+	}
+	return;
+}
+
+void GRPCONV::CopyRGBA(char* image, const char* buf) {
+	if (!is_mask) {
+		CopyRGB(image, buf);
+		return;
+	}
+	/* 色変換を行う */
+	int len = width * height;
+	int i;
+	int* outbuf = (int*)image;
+	for(i=0; i<len; i++) {
+		*outbuf++ =  read_little_endian_int(buf);
+		buf += 4;
+	}
+	return;
+}
+void GRPCONV::CopyRGB(char* image, const char* buf) {
+	/* 色変換を行う */
+	int len = width * height;
+	int i;
+	unsigned char* s = (unsigned char*)buf;
+	int* d = (int*)image;
+	for(i=0; i<len; i++) {
+		*d = (int(s[0])) | (int(s[1])<<8) | (int(s[2])<<16) | 0xff000000;
+		d++; s+=3;
+	}
+	return;
+}
+
+#if HAVE_LIBPNG
+PNGCONV::PNGCONV(const char* _inbuf, int _inlen, const char* _filename) {
+	int w,h,type;
+	png_structp png_ptr = 0;
+	png_infop info_ptr = 0;
+	png_infop end_info = 0;
+
+	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
+	if (!png_ptr) return;
+
+	info_ptr = png_create_info_struct(png_ptr);
+	if (!info_ptr) goto err;
+
+	end_info = png_create_info_struct(png_ptr);
+	if (!end_info) goto err;
+
+        if (setjmp(png_jmpbuf(png_ptr))) {
+                /* error occured !! */
+		goto err;
+        }
+
+	/* initialize I/O */
+	png_data = _inbuf;
+	png_set_read_fn(png_ptr, (png_voidp)this, &png_read);
+
+	png_read_info(png_ptr, info_ptr);
+
+	w = png_get_image_width(png_ptr, info_ptr);
+	h = png_get_image_height(png_ptr, info_ptr);
+	type = png_get_color_type(png_ptr, info_ptr);
+
+	if (type == PNG_COLOR_TYPE_GRAY || type == PNG_COLOR_TYPE_GRAY_ALPHA) goto err; // not supported
+
+	Init(filename, _inbuf, _inlen, w, h, type == PNG_COLOR_TYPE_RGB_ALPHA ? true : false);
+
+err:
+	if (png_ptr) {
+		if (end_info)
+			png_destroy_read_struct(&png_ptr, &info_ptr,&end_info);
+		else if (info_ptr)
+			png_destroy_read_struct(&png_ptr, &info_ptr,(png_infopp)0);
+		else
+			png_destroy_read_struct(&png_ptr, (png_infopp) 0,(png_infopp)0);
+	}
+	return;
+}
+
+bool PNGCONV::Read(char* image) {
+	if (data == 0) return false;
+	bool retcode = false;
+	int bpp = is_mask ? 4 : 3;
+	int i;
+	char* buf;
+	png_bytepp row_pointers = 0;
+
+	png_structp png_ptr = 0;
+	png_infop info_ptr = 0;
+	png_infop end_info = 0;
+
+	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
+	if (!png_ptr) goto err;
+	info_ptr = png_create_info_struct(png_ptr);
+	if (!info_ptr) goto err;
+	end_info = png_create_info_struct(png_ptr);
+	if (!end_info) goto err;
+
+        if (setjmp(png_jmpbuf(png_ptr))) {
+                /* error occured !! */
+		goto err;
+        }
+
+	buf= new char[width*height*4];
+	/* initialize I/O */
+	png_data = data;
+	png_set_read_fn(png_ptr, (png_voidp)this, &png_read);
+	
+	row_pointers = (png_bytepp)png_malloc(png_ptr, height*sizeof(png_bytep));
+	for (i=0; i<height; i++) row_pointers[i] = (png_bytep)(buf + width*bpp*i);
+	png_set_rows(png_ptr, info_ptr, row_pointers);
+
+	png_read_png(png_ptr, info_ptr,
+           PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_BGR,0);
+
+	if (buf != image) {
+		CopyRGBA(image, buf);
+		delete[] buf;
+	}
+	png_free(png_ptr, (png_voidp)row_pointers);
+
+	retcode = true;
+err:
+	if (png_ptr) {
+		if (end_info)
+			png_destroy_read_struct(&png_ptr, &info_ptr,&end_info);
+		else if (info_ptr)
+			png_destroy_read_struct(&png_ptr, &info_ptr,(png_infopp)0);
+		else
+			png_destroy_read_struct(&png_ptr, (png_infopp) 0,(png_infopp)0);
+	}
+	return retcode;
+}
+
+void PNGCONV::png_read(png_structp png_ptr, png_bytep d, png_size_t sz) {
+	PNGCONV* orig = (PNGCONV*)png_get_io_ptr(png_ptr);
+	memcpy(d, orig->png_data, sz);
+	orig->png_data += sz;
+	return;
+}
+#endif /* HAVE_LIBPNG */
+
+#if HAVE_LIBJPEG
+JPEGCONV::JPEGCONV(const char* _inbuf, int _inlen, const char* _filename) {
+	int w,h,type;
+	JSAMPARRAY rows, rows_orig; int i;
+	char* buf = 0;
+
+	struct jpeg_decompress_struct cinfo;
+	struct jpeg_error_mgr jerr;
+	cinfo.err = jpeg_std_error(&jerr);
+	jpeg_create_decompress(&cinfo);
+	cinfo.src = new jpeg_source_mgr;
+	SetupSrc(&cinfo, _inbuf, _inlen);
+
+	if (jpeg_read_header(&cinfo, TRUE) == JPEG_HEADER_OK)  {
+		Init(filename, _inbuf, _inlen, cinfo.image_width, cinfo.image_height, false);
+	}
+	delete cinfo.src;
+	cinfo.src = 0;
+	jpeg_destroy_decompress(&cinfo);
+	return;
+}
+		
+bool JPEGCONV::Read(char* image) {
+	if (data == 0) return false;
+	bool retcode = false;
+	JSAMPARRAY rows, rows_orig; int i;
+	char* buf = 0;
+
+	struct jpeg_decompress_struct cinfo;
+	struct jpeg_error_mgr jerr;
+	cinfo.err = jpeg_std_error(&jerr);
+	jpeg_create_decompress(&cinfo);
+	cinfo.src = new jpeg_source_mgr;
+	SetupSrc(&cinfo, data, datalen);
+
+	if (jpeg_read_header(&cinfo, TRUE) != JPEG_HEADER_OK) goto err;
+
+	cinfo.out_color_space = JCS_RGB;
+	
+	jpeg_start_decompress(&cinfo);
+
+	rows = new JSAMPROW[height];
+	rows_orig = rows;
+	buf = new char[width*height*3];
+	for (i=0; i<height; i++) rows[i] = (JSAMPROW)(buf+width*3*i);
+
+	for (i=0; i<height; ) {
+		int cnt = jpeg_read_scanlines(&cinfo, rows, height-i);
+		rows += cnt;
+		i += cnt;
+	}
+	delete[] rows_orig;
+	CopyRGBA_rev(image, buf);
+	delete[] buf;
+	
+	jpeg_finish_decompress(&cinfo);
+	retcode = true;
+err:
+	delete cinfo.src;
+	cinfo.src = 0;
+	jpeg_destroy_decompress(&cinfo);
+	return retcode;
+}
+
+void JPEGCONV::init_source(j_decompress_ptr cinfo) {
+}
+boolean JPEGCONV::fill_input_buffer(j_decompress_ptr cinfo) {
+	static char dummy[1024];
+	memset(dummy, 0, 1024);
+	cinfo->src->next_input_byte = (const JOCTET*)dummy;
+	cinfo->src->bytes_in_buffer = 1024;
+	fprintf(stderr,"JPEGCONV::fill_input_buffer: warning corrupted jpeg stream\n");
+	return TRUE;
+}
+void JPEGCONV::skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
+	if (cinfo->src->bytes_in_buffer > num_bytes) {
+		cinfo->src->next_input_byte += num_bytes;
+		cinfo->src->bytes_in_buffer -= num_bytes;
+	}
+}
+boolean JPEGCONV::resync_to_restart(j_decompress_ptr cinfo, int desired) {
+	return jpeg_resync_to_restart(cinfo, desired);
+}
+void JPEGCONV::term_source(j_decompress_ptr cinf) {
+}
+
+void JPEGCONV::SetupSrc(struct jpeg_decompress_struct* cinfo, const char* data, int size) {
+	cinfo->src->next_input_byte = (const JOCTET*) data;
+	cinfo->src->bytes_in_buffer = size;
+	cinfo->src->init_source = init_source;
+	cinfo->src->fill_input_buffer = fill_input_buffer;
+	cinfo->src->skip_input_data = skip_input_data;
+	cinfo->src->resync_to_restart = resync_to_restart;
+	cinfo->src->term_source = term_source;
+}
+#endif /* HAVE_LIBJPEG */
+BMPCONV::BMPCONV(const char* _inbuf, int _inlen, const char* _filename) {
+	/* データから情報読み込み */
+	int w = read_little_endian_int(_inbuf + 0x12);
+	int h = read_little_endian_int(_inbuf + 0x16);
+	if (h < 0) h = -h;
+	int bpp = read_little_endian_short(_inbuf + 0x1c);
+	int comp = read_little_endian_int(_inbuf + 0x1e);
+	Init(filename, _inbuf, _inlen, w, h, bpp==32 ? true : false);
+	return;
+}
+
+bool BMPCONV::Read(char* image) {
+	if (data == 0) return false;
+
+	/* マスクのチェック */
+	int bpp = read_little_endian_short(data+0x1c);
+	int h = read_little_endian_int(data + 0x16);
+	int dsz = read_little_endian_int(data + 0x22);
+	bpp /= 8;
+
+	int bpl = dsz / height;
+	if (bpl == 0) bpl = bpp*width;
+	bpl = bpp * width;
+	bpl = (bpl+3) & (~3);
+	
+
+	int i;
+	char* buf = new char[width*height*bpp+1024];
+	const char* src = data + 0x36;
+	char* dest = buf;
+	if (h < 0) {
+		for (i=0; i<height; i++) {
+			memcpy(dest+i*width*bpp, src+i*bpl, width*bpp);
+		}
+	} else {
+		for (i=0; i<height; i++) {
+			memcpy(dest+i*width*bpp, src+(height-i-1)*bpl, width*bpp);
+		}
+	}
+	if (bpp == 3) CopyRGB(image, buf);
+	else /* bpp == 4 */ CopyRGBA(image, buf);
+	delete[] buf;
+	return true;
+}
+
new file mode 100644
--- /dev/null
+++ b/system/file.h
@@ -0,0 +1,225 @@
+/*  file.h  : KANON の圧縮ファイル・PDT ファイル(画像ファイル)の展開の
+ *            ためのクラス
+ *     class FILESEARCH : ファイルの管理を行う
+ *     class ARCINFO : 書庫ファイルの中の1つのファイルを扱うクラス
+ *     class PDTCONV : PDT ファイルの展開を行う。
+ */
+
+/*
+ *
+ *  Copyright (C) 2000-   Kazunori Ueno(JAGARL) <jagarl@creator.club.ne.jp>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+*/
+
+#ifndef __KANON_FILE_H__
+#define __KANON_FILE_H__
+
+#ifndef DIR_SPLIT
+#define DIR_SPLIT '/'	/* UNIX */
+#endif
+
+// read 'KANON' compressed file
+
+#include<stdio.h>
+#include<stdlib.h>
+#include<string.h>
+#include<sys/types.h>
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#if defined(__sparc) || defined(sparc)
+#  if !defined(WORDS_BIGENDIAN)
+#    define WORDS_BIGENDIAN 1
+#  endif
+#endif
+
+#define INT_SIZE 4
+
+static int read_little_endian_int(const char* buf) {
+	const unsigned char *p = (const unsigned char *) buf;
+	return (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0];
+}
+
+static int read_little_endian_short(const char* buf) {
+	const unsigned char *p = (const unsigned char *) buf;
+	return (p[1] << 8) | p[0];
+}
+
+static int write_little_endian_int(char* buf, int number) {
+	int c = read_little_endian_int(buf);
+	unsigned char *p = (unsigned char *) buf;
+	unsigned int unum = (unsigned int) number;
+	p[0] = unum & 255;
+	unum >>= 8;
+	p[1] = unum & 255;
+	unum >>= 8;
+	p[2] = unum & 255;
+	unum >>= 8;
+	p[3] = unum & 255;
+	return c;
+}
+
+static int write_little_endian_short(char* buf, int number) {
+	int c = read_little_endian_short(buf);
+	unsigned char *p = (unsigned char *) buf;
+	unsigned int unum = (unsigned int) number;
+	p[0] = unum & 255;
+	unum >>= 8;
+	p[1] = unum & 255;
+	return c;
+}
+
+
+/*********************************************
+**  FILESEARCH:
+**	書庫ファイル/ディレクトリを含め、
+**	全ファイルの管理を行う。
+**
+**	最初に、設定ファイルからファイルの種類ごとに
+**	実際に入っているディレクトリ、書庫を設定する
+**
+**	以降はFind() メソッドで実際のファイルの内容を得る
+**
+*/
+
+/* ARCFILE と DIRFILE はファイル種類ごとの情報 */
+class ARCFILE;
+class DIRFILE;
+class SCN2kFILE;
+/* ARCINFO はファイルを読み込むために必要 */
+class ARCINFO;
+class ARCFILE_ATOM;
+class FILESEARCH {
+public:
+#define TYPEMAX 14
+	enum FILETYPE {
+		/* 一応、0 - 15 まで reserved */
+		ALL = 1, /* dat/ 以下のファイル(デフォルトの検索先) */
+		ROOT= 2, /* ゲームのインストールディレクトリ */
+		PDT = 3, /* default: PDT/ */
+		SCN = 4, /* default: DAT/SEEN.TXT */
+		ANM = 5, /* default: DAT/ALLANM.ANL */
+		ARD = 6, /* default: DAT/ALLARD.ARD */
+		CUR = 7, /* default: DAT/ALLCUR.CUR */
+		MID = 8, /* default: ALL */
+		WAV = 9, /* default: ALL */
+		KOE = 10, /* default: KOE/ */
+		BGM = 11, /* default: BGM */
+		MOV = 12, /* default : MOV */
+		GAN = 13  /* default : MOV */
+	};
+	enum ARCTYPE {ATYPE_DIR, ATYPE_ARC, ATYPE_SCN2k};
+private:
+	/* InitRoot() の時点で初期化される変数 */
+	DIRFILE* root_dir;
+	DIRFILE* dat_dir;
+	ARCFILE* searcher[TYPEMAX];
+	/* ファイルの存在位置の information */
+	ARCTYPE is_archived[TYPEMAX];
+	char* filenames[TYPEMAX];
+	/* デフォルトの information */
+	static ARCTYPE default_is_archived[TYPEMAX];
+	static char* default_dirnames[TYPEMAX];
+public:
+	FILESEARCH(void);
+	~FILESEARCH();
+	/* 初めにゲームのデータがあるディレクトリを設定する必要がある */
+	int InitRoot(char* root);
+	/* ファイルの型ごとの情報をセットする */
+	void SetFileInformation(FILETYPE type, ARCTYPE is_arc,
+		char* filename);
+	/* 複数のファイルを一つの型に関連づける */
+	void AppendFileInformation(FILETYPE type, ARCTYPE is_arc,
+		char* filename);
+	ARCFILE* MakeARCFILE(ARCTYPE tp, char* filename);
+	/* fname で指定された名前のファイルを検索 */
+	class ARCINFO* Find(FILETYPE type, const char* fname, const char* ext=0);
+	/* ある種類のファイルをすべてリストアップ
+	** 末尾は NULL pointer
+	*/
+	char** ListAll(FILETYPE type);
+};
+
+class ARCINFO {
+protected:
+	/* ファイルそのものの情報 */
+	ARCFILE_ATOM& info;
+	char* arcfile;
+	/* mmap している場合、その情報 */
+	bool use_mmap;
+	char* mmapped_memory;
+	int fd;
+	/* ファイル内容の入っているバッファ */
+	const char* data;
+
+protected:
+	ARCINFO(const char* arcfile, ARCFILE_ATOM& from); // only from ARCFILE
+	friend class ARCFILE;
+	friend class DIRFILE;
+
+	virtual bool ExecExtract(void);
+public:
+	/* dest は256byte 程度の余裕があること */
+	static void Extract(char*& dest, char*& src, char* destend, char* srcend);
+	static void Extract2k(char*& dest, char*& src, char* destend, char* srcend);
+	virtual ~ARCINFO();
+	/* 必要なら Read 前に呼ぶことで処理を分割できる */
+	int Size(void) const;
+	char* CopyRead(void); /* Read() して内容のコピーを返す */
+	const char* Read(void);
+	/* ファイルが regular file の場合、ファイル名を帰す */
+	/* そうでないなら 0 を帰す */
+	const char* Path(void) const;
+	FILE* OpenFile(int* length=0) const; /* 互換性のため:raw file の場合、ファイルを開く */
+};
+
+class GRPCONV {
+public:
+	int width;
+	int height;
+	bool is_mask;
+
+	const char* filename;
+	const char* data;
+	int datalen;
+
+	int Width(void) { return width;}
+	int Height(void) { return height;}
+	bool IsMask(void) { return is_mask;}
+
+	GRPCONV(void);
+	virtual ~GRPCONV();
+	void Init(const char* fname, const char* data, int dlen, int width, int height, bool is_mask);
+
+	virtual bool Read(char* image) = 0;
+	static GRPCONV* AssignConverter(const char* inbuf, int inlen, const char* fname);
+	static GRPCONV* AssignConverter(ARCINFO* info) {
+		const char* dat = info->Read();
+		if (dat == 0) return 0;
+		return AssignConverter(dat, info->Size(), "???");
+	}
+	void CopyRGBA(char* image, const char* from);
+	void CopyRGB(char* image, const char* from);
+	void CopyRGBA_rev(char* image, const char* from);
+	void CopyRGB_rev(char* image, const char* from);
+};
+
+extern FILESEARCH file_searcher;
+
+#endif // !defined(__KANON_FILE_H__)
new file mode 100644
--- /dev/null
+++ b/system/file_impl.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2004  Kazunori "jagarl" Ueno
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+
+#ifndef __FILE_IMPL_H__
+#define __FILE_IMPL_H__
+
+#include<vector>
+
+struct ARCFILE_ATOM {
+	char* filename;
+	char* filename_lower;
+	off_t offset;
+	int arcsize;
+	int filesize;
+	int private_data;
+	bool operator <(const ARCFILE_ATOM& to) const {
+		return strcmp(filename_lower, to.filename_lower) < 0;
+	}
+	bool operator <(char* const to) const {
+		return strcmp(filename_lower, to) < 0;
+	}
+};
+
+class ARCFILE {
+protected:
+	char* arcname;
+	char* filenames_orig;
+	int list_point;
+	std::vector<ARCFILE_ATOM> arc_atom;
+	typedef std::vector<ARCFILE_ATOM>::iterator iterator;
+	ARCFILE* next; /* FILESEARCH の一つの型が複数の ARCFILE を持つとき、リストをつくる */
+	/* arcname に指定されたファイル/ディレクトリの内容チェック */
+	virtual int CheckFileDeal(void);
+	virtual void ListupFiles(int fname_len);
+	virtual ARCINFO* MakeARCINFO(ARCFILE_ATOM&);
+	iterator SearchName(const char* f, const char* ext=0);
+public:
+	ARCFILE(char* fname);
+	void SetNext(ARCFILE* _next) { next = _next;}
+	ARCFILE* Next(void) { return next; }
+	void Init(void);
+	virtual ~ARCFILE();
+	/* ファイル検索 */
+	class ARCINFO* Find(const char* fname, const char* ext);
+	/* ファイルリストの出力 */
+	int Deal(void) { Init(); return arc_atom.size(); }
+	void ListFiles(FILE* out);
+	void InitList(void);
+	char* ListItem(void);
+};
+
+class SCN2kFILE : public ARCFILE {
+protected:
+	virtual int CheckFileDeal(void);
+	virtual void ListupFiles(int fname_len);
+	virtual ARCINFO* MakeARCINFO(ARCFILE_ATOM& atom);
+public:
+	SCN2kFILE(char* fname) : ARCFILE(fname) {}
+	virtual ~SCN2kFILE() {}
+};
+
+class CattleyaFILE : public ARCFILE {
+	bool is_compress;
+	/* header の Huffman 木構築用 */
+	char* bitbuf;
+	char* bitbuf_end;
+	int ltree[0x400];
+	int rtree[0x400];
+	int treecnt;
+	int bitcnt;
+	int GetBit(void);
+	int GetCh(void);
+	void SetBuf(char* buf, int len);
+	int MakeTree(void);
+	int Decode(int seed);
+
+protected:
+	virtual int CheckFileDeal(void);
+	virtual void ListupFiles(int fname_len);
+	virtual ARCINFO* MakeARCINFO(ARCFILE_ATOM& atom);
+public:
+	CattleyaFILE(char* fname) : ARCFILE(fname) {is_compress = false;}
+	virtual ~CattleyaFILE() {}
+};
+
+class NULFILE : public ARCFILE {
+protected:
+	virtual int CheckFileDeal(void);
+	virtual void ListupFiles(int fname_len);
+	virtual ARCINFO* MakeARCINFO(ARCFILE_ATOM& atom);
+public:
+	NULFILE() : ARCFILE("") {}
+	virtual ~NULFILE() {}
+};
+class DIRFILE : public ARCFILE {
+protected:
+	virtual int CheckFileDeal(void);
+	virtual void ListupFiles(int fname_len);
+	virtual ARCINFO* MakeARCINFO(ARCFILE_ATOM& atom);
+public:
+	DIRFILE(char* fname) : ARCFILE(fname) {}
+	virtual ~DIRFILE() {}
+	FILE* Open(const char* fname); /* FILE* を開く */
+	char* SearchFile(const char* dirname); /* ファイル検索 */
+};
+class ARCINFO_AVG32 : public ARCINFO {
+	ARCINFO_AVG32(const char* name, ARCFILE_ATOM& atom) : ARCINFO(name, atom) {
+	}
+	virtual bool ExecExtract(void);
+	friend class ARCFILE;
+};
+class ARCINFO2k : public ARCINFO {
+	static char decode_seed[256];
+	static char decode_seed2[16];
+protected:
+	ARCINFO2k(const char* name, ARCFILE_ATOM& atom) : ARCINFO(name,atom) {
+	}
+	virtual bool ExecExtract(void);
+	friend class SCN2kFILE;
+};
+
+class ARCINFOZ : public ARCINFO {
+protected:
+	ARCINFOZ(const char* name, ARCFILE_ATOM& atom) : ARCINFO(name, atom) {
+	}
+	virtual bool ExecExtract(void);
+	friend class DaemonBaneFILE;
+	friend class CattleyaFILE;
+};
+
+#endif /* __FILE_IMPL_H__ */
new file mode 100644
--- /dev/null
+++ b/system/system_config.cc
@@ -0,0 +1,1219 @@
+/*  system_config.cc
+ *      gameexe.ini ファイルの読み込み
+ */
+
+/*
+ *
+ *  Copyright (C) 2000-   Kazunori Ueno(JAGARL) <jagarl@creator.club.ne.jp>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <map>
+#include <string>
+#include "system_config.h"
+#include "../system/file.h"
+
+using namespace std;
+
+// #define DEBUG_CONFIG
+#ifdef DEBUG_CONFIG
+# define dprintf(X) printf X
+#else
+# define dprintf(X)
+#endif /* DEBUG_CONFIG */
+
+#define MAXTOKEN 10 /* = で区切られた領域の最大数 */
+#define MAXVARS 32 /* , で区切られた数値の最大数 */
+
+// 初期化ファイルの読み込み
+/* config は 文字列、数列、その複合など、いろいろな形式がありうる */
+/* 文字列と数列は一般に AyuSys_Config クラスに含める */
+
+
+/**********************************************************/
+/* とりあえずハッシュ比較付き文字列 */
+class HashStr {
+	const char* str;
+	unsigned int hash;
+public:
+	HashStr(const char*);
+	HashStr(const HashStr& orig);
+	~HashStr() {
+		if (str) delete[] str;
+	}
+	const char* c_str(void) const { return str; }
+	friend inline int operator<(const HashStr& a, const HashStr& b) {
+		if (a.hash == b.hash) {
+			if (a.str == 0) return 1;
+			else if (b.str == 0) return 0;
+			else return strcmp(a.str, b.str);
+		}
+		else return a.hash < b.hash;
+	}
+};
+HashStr::HashStr(const char* s ) {
+	if (s == 0 || s[0] == '\0') {
+		str = 0; hash = 0; return; /* invalid string */
+	}
+	char* new_str = new char[strlen(s)+1];
+	strcpy(new_str, s);
+	str = new_str;
+	/* calc hash... 適当 */
+	int h = strlen(s);
+	while(*s != 0) {
+		h = *s + ((h * (0x9449+*s))>>7);
+		s++;
+	}
+	hash = (unsigned int)h;
+}
+HashStr::HashStr(const HashStr& orig) {
+	if (orig.str == 0 || orig.str[0] == '\0') {
+		str = 0; hash = 0; return; /* invalid */
+	}
+	char* new_str = new char[strlen(orig.str)+1];
+	strcpy(new_str, orig.str);
+	str = new_str;
+	hash = orig.hash;
+}
+
+/**********************************************************
+**AyuSys_Config_[String | Intlist] :
+** 設定の本体
+**	original : 元設定
+**	old_data : 前回 ClearDiff() したときの設定
+**	new_data : ClearDiff() 以降に設定した内容を保存
+**	データ設定:
+**	Init() : 元設定を作成
+**	Set() : 設定を変更
+**	Get() : 最も新しい設定を得る
+**
+**	変更の記録:
+**	Diff() : 前回のClearDiff() から変更した内容を得る
+**	DiffLen() : Diff() で必要な文字列長を得る
+**	ClearDiff() : 変更記録を消す
+**	PatchOld() : Diff() で得た記録に基づき、変更前の状態に戻す
+**	PatchNew() : Diff() で得た記録に基づき、変更後の状態に戻す
+**
+**	元設定からの変更の記録:
+**	SetOriginal() : 元設定に戻す
+**	DiffOriginal() : 元設定から現在の設定の変更を得る
+**	DiffOriginalLen() : DiffOriginal() で必要な文字列長を得る
+**	PatchOriginal() : DiffOriginal() で得た記録に基づき、設定を復旧する
+*/
+
+/************************************************
+** AyuSysConfigStringItem
+** 文字列をデータとしてもつ設定項目
+*/
+class AyuSysConfigStringItem {
+	char* original_data;
+	char* old_data;
+	char* new_data;
+public:
+	AyuSysConfigStringItem(void) {
+		original_data = 0;
+		old_data = 0;
+		new_data = 0;
+	}
+	AyuSysConfigStringItem(const AyuSysConfigStringItem& o) {
+		original_data = 0; old_data = 0; new_data = 0;
+		if (o.original_data) {
+			original_data = new char[strlen(o.original_data)+1];
+			strcpy(original_data, o.original_data);
+		}
+		if (o.old_data) {
+			old_data = new char[strlen(o.old_data)+1];
+			strcpy(old_data, o.old_data);
+		}
+		if (o.new_data) {
+			new_data = new char[strlen(o.new_data)+1];
+			strcpy(new_data, o.new_data);
+		}
+	}
+	/* 設定:Init で初期化、Set で変更、Get で変更を優先して取り出す */
+	void Init(int deal, const char* str) { /* deal は無視 */
+		if (original_data) delete[] original_data;
+		int len = strlen(str);
+		original_data = new char[len+1];
+		strcpy(original_data, str);
+		original_data[len] = '\0';
+	}
+	void Set(int deal, const char* str) { /* deal は無視 */
+		if (new_data) delete[] new_data;
+		int len = strlen(str);
+		new_data = new char[len+1];
+		strcpy(new_data, str);
+		new_data[len] = '\0';
+	}
+	const char* Get(int deal) const {/* deal は無視 */
+		if (new_data) return new_data;
+		else if (old_data) return old_data;
+		return original_data;
+	}
+	const char* GetOriginal(int deal) const {
+		return original_data;
+	}
+	int Deal(void) const {
+		return 1;
+	}
+	/* オリジナルからの変化の調査 :
+	** DiffOriginal で変化を文字列で取り出し、PatchOriginal で
+	** 変化を反映
+	*/
+	int DiffOriginalLen(void) {
+		if (new_data == 0) return 0;
+		return strlen(new_data)+1;
+	}
+	void DiffOriginal(string& data) {
+		if (new_data == 0) { /* あり得ない */
+			fprintf(stderr,"AyuSysConfigStringItem::DiffOriginal : this method must not called if not required!\n");
+			return;
+		}
+		char* out_data = new char[strlen(new_data)*2+1];
+		char* buf = out_data;
+		int i;
+		for (i=0; new_data[i]!=0; i++) {
+			switch(new_data[i]) {
+				case '?': *buf++ = '?'; *buf++ = '0'; break;
+				case '"': *buf++ = '?'; *buf++ = '1'; break;
+				case '\'': *buf++ = '?'; *buf++ = '2'; break;
+				case ',': *buf++ = '?'; *buf++ = '3'; break;
+				case '.': *buf++ = '?'; *buf++ = '4'; break;
+				case ':': *buf++ = '?'; *buf++ = '5'; break;
+				case ';': *buf++ = '?'; *buf++ = '6'; break;
+				case '=': *buf++ = '?'; *buf++ = '7'; break;
+				case '<': *buf++ = '?'; *buf++ = '8'; break;
+				case '>': *buf++ = '?'; *buf++ = '9'; break;
+				default: *buf++ = new_data[i]; break;
+			}
+		}
+		*buf++ = 0;
+		data += out_data;
+		delete[] out_data;
+		return;
+	}
+	const char* PatchOriginal(const char* data) {
+		static char* table = "?\"',.:;=<>";
+		if (new_data) delete[] new_data;
+		if (old_data) delete[] old_data;
+		new_data = 0; old_data = 0;
+		new_data = new char[1024];
+		int i,j = 0;
+		for (i=0; i<1020; i++) {
+			switch(data[j]) {
+			case '?':
+				if (data[j+1] >= '0' && data[j+1] <= '9') {
+					new_data[i] = table[ data[j+1] - '0'];
+					j += 2;
+					break;
+				}
+			case '"': case '\'': case ',': case '.': case ':':
+			case ';': case '=':  case '<': case '>':
+				goto for_end;
+			default: new_data[i] = data[j++]; break;
+			}
+		}
+	for_end:
+		new_data[i] = 0;
+		return data;
+	}
+	void SetOriginal(void) {
+		if (new_data) delete[] new_data;
+		if (old_data) delete[] old_data;
+		new_data = 0; old_data = 0;
+	}
+	void Dump(FILE* f) const {
+		if (original_data) fprintf(f, "original %s ",original_data);
+		if (old_data) fprintf(f, "old_data %s ",old_data);
+		if (new_data) fprintf(f, "new_data %s ",new_data);
+		fprintf(f, "\n");
+	}
+};
+
+/************************************************
+** AyuSysConfigIntlistItem
+** 数値列をデータとしてもつ設定項目
+*/
+class AyuSysConfigIntlistItem {
+	int item_deal;
+	int* original_data;
+	int* old_data;
+	int* new_data;
+public:
+	AyuSysConfigIntlistItem(void) {
+		item_deal = 0;
+		original_data = 0;
+		old_data = 0;
+		new_data = 0;
+	}
+	AyuSysConfigIntlistItem(const AyuSysConfigIntlistItem& o) {
+		item_deal = o.item_deal;
+		original_data = 0; old_data = 0; new_data = 0;
+		if (o.original_data) {
+			original_data = new int[item_deal];
+			memcpy(original_data, o.original_data, sizeof(int)*item_deal);
+		}
+		if (o.old_data) {
+			old_data = new int[item_deal];
+			memcpy(old_data, o.old_data, sizeof(int)*item_deal);
+		}
+		if (o.new_data) {
+			new_data = new int[item_deal];
+			memcpy(new_data, o.new_data, sizeof(int)*item_deal);
+		}
+	}
+	/* 設定:Init で初期化、Set で変更、Get で変更を優先して取り出す */
+	void Init(int deal, const int* list) { /* deal は無視 */
+		if (original_data) delete[] original_data;
+		original_data = 0;
+		if (deal <= 0) {
+			item_deal = 0; return;
+		}
+		item_deal = deal;
+		original_data = new int[item_deal];
+		memcpy(original_data, list, sizeof(int)*deal);
+	}
+	void Set(int deal, const int* list) { /* deal は無視 */
+		item_deal = deal;
+		if (new_data) delete[] new_data;
+		new_data = new int[item_deal];
+		memcpy(new_data, list, sizeof(int)*item_deal);
+	}
+	const int* Get(int deal) const {/* deal は無視 */
+		if (item_deal == 0) return 0;
+		if (deal > item_deal) {
+			fprintf(stderr,"AyuSysConfigIntlistItem::Get : invalid items deal %d (correct: %d)\n",deal,item_deal);
+			return 0;
+		}
+		if (new_data) return new_data;
+		else if (old_data) return old_data;
+		return original_data;
+	}
+	const int* GetOriginal(int deal) const {/* deal は無視 */
+		if (item_deal == 0) return 0;
+		if (deal > item_deal) {
+			fprintf(stderr,"AyuSysConfigIntlistItem::Get : invalid items deal %d (correct: %d)\n",deal,item_deal);
+			return 0;
+		}
+		return original_data;
+	}
+	int Deal(void) const {
+		return item_deal;
+	}
+	/* オリジナルからの変化の調査 :
+	** DiffOriginal で変化を文字列で取り出し、PatchOriginal で
+	** 変化を反映
+	*/
+	int DiffOriginalLen(void) {
+		if (new_data == 0) return 0;
+		return  12 * item_deal + 1;
+	}
+	void DiffOriginal(string& data) {
+		if (new_data == 0) { /* あり得ない */
+			fprintf(stderr,"AyuSysConfigStringItem::DiffOriginal : this method must not called if not required!\n");
+			return;
+		}
+		int i; char buf[1024];
+		for (i=0; i<item_deal; i++) {
+			sprintf(buf, "%d,",new_data[i]);
+			data += buf;
+		}
+		return;
+	}
+	const char* PatchOriginal(const char* data) {
+		if (old_data) delete[] old_data;
+		if (new_data) delete[] new_data;
+		old_data = 0; new_data = 0;
+		new_data = new int[item_deal];
+		int i;
+		for (i=0; i<item_deal; i++) {
+			new_data[i] = atoi(data);
+			if (strchr(data, ',') == 0) break;
+			data = strchr(data, ',') + 1;
+		}
+		return data;
+	}
+	void SetOriginal(void) {
+		if (new_data) delete[] new_data;
+		if (old_data) delete[] old_data;
+		new_data = 0; old_data = 0;
+	}
+	void Dump(FILE* f) const {
+		fprintf(f, "item deal %d, ",item_deal);
+		if (original_data) {
+			fprintf(f, "(%d", original_data[0]);
+			int i;for (i=1; i<item_deal; i++) {
+				fprintf(f, ",%d",original_data[i]);
+			}
+			fprintf(f, ") ");
+		}
+		if (old_data) {
+			fprintf(f, "old %08x(%d", (unsigned int)(old_data), old_data[0]);
+			int i;for (i=1; i<item_deal; i++) {
+				fprintf(f, ",%d",old_data[i]);
+			}
+			fprintf(f, ") ");
+		}
+		if (new_data) {
+			fprintf(f, "new %08x(%d", (unsigned int)(new_data), new_data[0]);
+			int i;for (i=1; i<item_deal; i++) {
+				fprintf(f, ",%d",new_data[i]);
+			}
+			fprintf(f, ") ");
+		}
+		fprintf(f, "\n");
+	}
+};
+
+// template map<HashStr, AyuSysConfigStringItem>;
+// template map<HashStr, AyuSysConfigIntlistItem>;
+
+/************************************************
+** AyuSysConfigItem
+** データ名 -> データ本体の map と、map 全体に
+** 様々な操作を行うためのメソッド
+*/
+
+template<class ItemType, class DataType> class AyuSysConfigItem {
+	typedef map<HashStr,ItemType> maptype;
+	typedef typename maptype::iterator mapiterator;
+	typedef typename maptype::const_iterator const_mapiterator;
+	maptype data;
+public:
+	void SetOrig(HashStr& name, int deal, const DataType* str) {
+		if (str == 0) return; /* 無効 */
+		data[name].Init(deal, str);
+	}
+	void Set(HashStr& name, int deal, const DataType* new_data) {
+		if (new_data == 0) return; /* 無効 */
+		/* 設定を検索 */
+		mapiterator it = data.find(name);
+		/* 設定が元設定に見つからないなら失敗 */
+		if (it == data.end()) {
+			fprintf(stderr,"AyuSysConfigItem::Set : there is no '%s' parameter\n",name.c_str());
+			return;
+		}
+		/* 設定を変更 */
+		it->second.Set(deal, new_data);
+	}
+	/* 新しい設定を優先して返す */
+	const DataType* Get(int deal, HashStr& name) const {
+		const_mapiterator it = data.find(name);
+		if (it == data.end()) return 0;
+		return it->second.Get(deal);
+	}
+	const DataType* GetOriginal(int deal, HashStr& name) const {
+		const_mapiterator it = data.find(name);
+		if (it == data.end()) return 0;
+		return it->second.GetOriginal(deal);
+	}
+	int Deal(HashStr& name) const {
+		const_mapiterator it = data.find(name);
+		if (it == data.end()) return 0;
+		return it->second.Deal();
+	}
+	/* オリジナルからの変化の調査 :
+	** DiffOriginal で変化を文字列で取り出し、PatchOriginal で
+	** 変化を反映
+	*/
+	void DiffOriginal(string& ret_str) {
+		mapiterator it = data.begin();
+		for (; it != data.end(); it++) {
+			int len = it->second.DiffOriginalLen();
+			if (len) {
+				ret_str += it->first.c_str();
+				ret_str += "=";
+				it->second.DiffOriginal(ret_str);
+				ret_str += ";";
+			}
+		}
+		ret_str += ";";
+		return;
+	}
+	const char* PatchOriginal(const char* diff_data) {
+		while(*diff_data != ';') {
+			char name[1024];
+			const char* data_start = strchr(diff_data, '=');
+			if (data_start == 0) break;
+			strncpy(name, diff_data, data_start-diff_data);
+			name[data_start-diff_data] = 0;
+			data_start++;
+			mapiterator it = data.find(name);
+			if (it != data.end()) {
+				diff_data = data_start;
+				it->second.PatchOriginal(diff_data);
+			}
+			diff_data = strchr(diff_data, ';');
+			if (diff_data) diff_data++;
+		}
+		if (*diff_data == ';') {
+			diff_data++;
+		} else {
+			fprintf(stderr,"AyusysConfigItem::PatchOriginal: invalid data %s\n",diff_data);
+		}
+		return diff_data;
+	}
+	void SetOriginal(void) {
+		mapiterator it = data.begin();
+		for (; it != data.end(); it++) {
+			it->second.SetOriginal();
+		}
+	}
+	void Dump(FILE* f) const {
+		const_mapiterator it = data.begin();
+		for (; it != data.end(); it++) {
+			fprintf(f, "name %s: ",it->first.c_str());
+			it->second.Dump(f);
+		}
+	}
+};
+// template AyuSysConfigItem<AyuSysConfigStringItem, char>;
+// template AyuSysConfigItem<AyuSysConfigIntlistItem, int>;
+
+/************************************************/
+/* ラッパ */
+struct AyuSysConfigString {
+	AyuSysConfigItem<AyuSysConfigStringItem,char> orig;
+	void Dump(FILE* f) const {
+		fprintf(f, "string config:\n");
+		orig.Dump(f);
+	}
+};
+struct AyuSysConfigIntlist {
+	AyuSysConfigItem<AyuSysConfigIntlistItem, int> orig;
+	void Dump(FILE* f) const {
+		fprintf(f, "integer array config:\n");
+		orig.Dump(f);
+	}
+};
+
+/************************************************/
+/* AyuSysConfig クラス */
+int AyuSysConfig::SearchParam(const char* name) const{
+	HashStr str(name);
+	if (str_config->orig.Get(1, str)) return 1; /* char* のパラメータ */
+	else if (int_config->orig.Get(1, str)) return 2; /* int のパラメータ */
+	/* XXX.015.XXX の類のキー名を XXX.000.XXX の形に規格化して再検索 */
+	char name_copy[1024];
+	strncpy(name_copy, name, 1000);
+	name_copy[1000] = 0;
+	char* s;
+	for (s=name_copy; s != 0; s = strchr(s,'.')) {
+		if (isdigit(s[1]) && isdigit(s[2]) && isdigit(s[3])) {
+			s[1] = '0'; s[2] = '0'; s[3] = '0';
+		}
+		s++;
+	}
+	HashStr str2(name_copy);
+	if (str_config->orig.Get(1, str2)) return 1; /* char* のパラメータ */
+	else if (int_config->orig.Get(1, str2)) return 2; /* int のパラメータ */
+	else return 0;
+}
+const char* AyuSysConfig::GetParaStr(const char* name) const{
+	HashStr str(name);
+	const char* ret = str_config->orig.Get(1,str);
+	if (ret == 0) {
+		// fprintf(stderr,"Cannot find config name '%s'\n",name);
+	}
+	return ret;
+}
+int AyuSysConfig::GetParam(const char* name, int deal, ...) const{
+	HashStr str(name);
+	va_list va; int i;
+	const int* vars = int_config->orig.Get(deal, str);
+	if (vars == 0) {
+		// fprintf(stderr,"Cannot find config name '%s'\n",name);
+		va_start(va, deal);
+		for (i=0; i<deal; i++) {
+			int* var = va_arg(va, int*);
+			if (var) *var = 0;
+		}
+		return -1;
+	} else {
+		va_start(va, deal);
+		for (i=0; i<deal; i++) {
+			int* var = va_arg(va, int*);
+			if (var) *var = vars[i];
+		}
+	}
+	return 0;
+}
+int AyuSysConfig::GetOriginalParam(const char* name, int deal, ...) const{
+	HashStr str(name);
+	va_list va; int i;
+	const int* vars = int_config->orig.GetOriginal(deal, str);
+	if (vars == 0) {
+		// fprintf(stderr,"Cannot find config name '%s'\n",name);
+		va_start(va, deal);
+		for (i=0; i<deal; i++) {
+			int* var = va_arg(va, int*);
+			if (var) *var = 0;
+		}
+		return -1;
+	} else {
+		va_start(va, deal);
+		for (i=0; i<deal; i++) {
+			int* var = va_arg(va, int*);
+			if (var) *var = vars[i];
+		}
+	}
+	return 0;
+}
+const int* AyuSysConfig::GetParamArray(const char* name, int& deal) const{
+	HashStr str(name);
+	if (int_config->orig.Deal(str) == 0) { deal = 0; return 0; }
+	deal = int_config->orig.Deal(str);
+	const int* vars = int_config->orig.Get(deal, str);
+	if (vars == 0) { deal = 0; return 0; }
+	return vars;
+}
+void AyuSysConfig::SetParaStr(const char* name, const char* var) {
+	HashStr str(name);
+	dirty_flag = 1; change_flag = 1;
+	str_config->orig.Set(str, 1, var);
+}
+void AyuSysConfig::SetParam(const char* name, int deal, ...) {
+	if (deal >= MAXVARS) return ;
+	HashStr str(name);
+	int vars[MAXVARS]; va_list va; int i;
+	va_start(va, deal);
+	for (i=0; i<deal; i++) vars[i] = va_arg(va, int);
+	int_config->orig.Set(str, deal, vars);
+	dirty_flag = 1; change_flag = 1;
+	return;
+}
+void AyuSysConfig::SetOrigParaStr(const char* name, const char* var) {
+	HashStr str(name);
+	str_config->orig.SetOrig(str, 1, var);
+	change_flag = 1;
+}
+void AyuSysConfig::SetOrigParam(const char* name, int deal, ...) {
+	if (deal >= MAXVARS) return;
+	HashStr str(name);
+	int vars[MAXVARS]; va_list va; int i;
+	va_start(va, deal);
+	for(i=0; i<deal; i++) vars[i] = va_arg(va, int);
+	int_config->orig.SetOrig(str, deal, vars);
+	change_flag = 1;
+}
+void AyuSysConfig::SetOrigParamArray(const char* name, int deal, int* array) {
+	HashStr str(name);
+	int_config->orig.SetOrig(str, deal, array);
+}
+void AyuSysConfig::SetOriginal(void) {
+	/* 全ての設定を元に戻す */
+	str_config->orig.SetOriginal();
+	int_config->orig.SetOriginal();
+	change_flag = 1;
+}
+void AyuSysConfig::DiffOriginal(string& data) {
+	str_config->orig.DiffOriginal(data);
+	int_config->orig.DiffOriginal(data);
+	return;
+}
+const char* AyuSysConfig::PatchOriginal(const char* data) {
+	data = str_config->orig.PatchOriginal(data);
+	data = int_config->orig.PatchOriginal(data);
+	return data;
+}
+
+void AyuSysConfig::Dump(FILE* f) const {
+	str_config->Dump(f);
+	int_config->Dump(f);
+}
+
+/************************************************
+** AyuSysConfig のコンストラクタ:
+** 全ての config 項目を初期化する
+*/
+AyuSysConfig::AyuSysConfig(void) {
+	int i;
+
+	change_flag = 1; dirty_flag = 0;
+	str_config = new AyuSysConfigString;
+	int_config = new AyuSysConfigIntlist;
+
+	/****** 文字列 *******/
+	SetOrigParaStr("#WAKUPDT", "GRDAT");	/* 枠、マウスカーソルなどの画像ファイル */
+	SetOrigParaStr("#REGNAME", "xclannad");	/* レジストリ名。セーブファイルの作成に使う */
+	SetOrigParaStr("#CAPTION", "xclannad");	/* ウィンドウのタイトル */
+	SetOrigParaStr("#SAVENAME","SAVE.INI");	/* セーブファイルの名前 */
+	SetOrigParaStr("#SAVETITLE", "This is save file"); /* セーブファイルの先頭の文字列 */
+	SetOrigParaStr("#SAVENOTITLE", "-----------------"); /* 使われてないセーブデータの名前 */
+	SetOrigParaStr("#CGM_FILE", "MODE.CGM");/* CG mode の設定が保存されたファイル名 */
+	SetOrigParaStr("#CGTABLE_FILE", "MODE.CGM");/* CG mode の設定が保存されたファイル名 */
+
+	SetOrigParaStr("#WAKU.000.000.NAME", ""); // テキストウィンドウの窓飾り画像名
+	SetOrigParaStr("#WAKU.000.000.BACK", ""); // テキストウィンドウのテキスト背景画像名
+	SetOrigParaStr("#WAKU.000.000.BTN", ""); // テキストウィンドウのボタン画像名
+
+	SetOrigParaStr("#MOUSE_CURSOR.000.NAME", ""); // マウスカーソルのファイル名
+	SetOrigParaStr("#CURSOR.000.NAME", ""); // リターンカーソルのファイル名
+	SetOrigParaStr("#SELBTN.000.NAME", ""); // 選択肢背景
+	SetOrigParaStr("#SELBTN.000.BACK", ""); // 選択肢背景
+
+	char name_str[8] = "#NAME.A";
+	for (i='A'; i<='Z'; i++) {
+		name_str[6] = i;
+		SetOrigParaStr(name_str, "");
+	}
+
+	/****** 数値列 *******/
+	SetOrigParam("#CANCELCALL", 2, 0,0); /* キャンセルボタン(右クリック)したときに呼び出されるサブルーチン番号(メニュー) */
+	SetOrigParam("#COM2_TITLE", 1, 1); /* ? */
+	SetOrigParam("#COM2_TITLE_COLOR", 1, 2); /* 選択肢タイトルの色 */
+	SetOrigParam("#COM2_TITLE_INDENT", 1, 2); /* ? */
+	SetOrigParam("#SAVEFILETIME", 1, 24); /* セーブする場所の数 */
+	SetOrigParam("#SEEN_START", 1, 0); /* ゲームを開始するシナリオ番号 */
+	SetOrigParam("#SEEN_SRT", 1, 0); /* ゲームを開始するシナリオ番号(好き好き大好き) */
+	SetOrigParam("#SEEN_MENU",  1, 0); /* メニューのシナリオ番号 */
+	SetOrigParam("#SEEN_TEXT_CURRENT",  1, 0); /* seen.txt を root directory に置くか */
+	SetOrigParam("#FADE_TIME", 1, 40); /* 画面のフェード・アウトの速度 */
+	SetOrigParam("#NVL_SYSTEM",1, 0); /* テキストウィンドウが全画面か否か */
+	SetOrigParam("#WINDOW_ATTR", 5, -1, 128,128, 190, 0); /* テキストウィンドウの色 */
+	SetOrigParam("#WINDOW_ATTR_AREA", 4, 4,4,4,4); /* テキストウィンドウの範囲 */
+	SetOrigParam("#WINDOW_ATTR_TYPE", 1, 0); /* テキストウィンドウを半透明にするか */
+	SetOrigParam("#WINDOW_MSG_POS", 2, 22, 350); /* テキストウィンドウの位置 */
+	SetOrigParam("#WINDOW_COM_POS", 2,450, 250); /* 選択ウィンドウの位置 */
+	SetOrigParam("#WINDOW_GRP_POS", 2, 16, 100); /* なにかのウィンドウの位置 */
+	SetOrigParam("#WINDOW_SUB_POS", 2, 48, 100); /* なにかのウィンドウの位置 */
+	SetOrigParam("#WINDOW_SYS_POS", 2, 32, 100); /* なにかのウィンドウの位置 */
+	SetOrigParam("#WINDOW_WAKU_TYPE", 1, 0); /* テキストウィンドウの枠の種類。xkanon 独自設定 */
+	SetOrigParam("#RETN_CONT", 1, 16); /* リターンカーソルの数 */
+	SetOrigParam("#RETN_SPEED",1,100); /* リターンカーソルの動く速度 */
+	SetOrigParam("#RETN_XSIZE", 1, 16); /* リターンカーソルの大きさ */
+	SetOrigParam("#RETN_YSIZE", 1, 16); /* リターンカーソルの大きさ */
+	SetOrigParam("#FONT_SIZE", 1, 26); /* フォントの大きさ */
+	SetOrigParam("#FONT_WEIGHT", 1, 100); /* フォントの weight */
+	SetOrigParam("#MSG_MOJI_SIZE", 2, 12, 29); /* 文字の大きさ(半角) */
+	SetOrigParam("#MESSAGE_SIZE", 2, 23, 3); /* メッセージウィンドウの文字数 */
+	SetOrigParam("#COM_MESSAGE_SIZE", 2, 23, 3); /* メッセージウィンドウの文字数 */
+	SetOrigParam("#INIT_MESSAGE_SPEED", 1, 30); /* テキスト表示速度 */
+	SetOrigParam("#INIT_MESSAGE_SPEED_MOD", 1, 0); /* テキスト表示 no wait */
+	SetOrigParam("#MESSAGE_KEY_WAIT_USE", 1, 0); /* テキスト進行オートモード */
+	SetOrigParam("#MESSAGE_KEY_WAIT_TIME", 1, 1500); /* オートモードでのキー待ち時間 */
+
+	SetOrigParam("#GRP_DC_TIMES", 1, 4); /* 裏画面の数 */
+	SetOrigParam("#MUSIC_LINEAR_PAC",1,0); /* PCM データの 8bit -> 16bit 変換を行うか */
+	SetOrigParam("#MUSIC_TYPE",1,0); /* PCM データの種類 */
+	SetOrigParam("#WINDOW_MSGBK_BOX",1,0); /* バックログ用のボタン */
+	SetOrigParam("#WINDOW_MSGBK_LBOX_POS",4,15,7,8,0); /* バックログ用のボタン(左)の位置 */
+	SetOrigParam("#WINDOW_MSGBK_RBOX_POS",4,7,7,0,0); /* バックログ用のボタン(左)の位置 */
+	SetOrigParam("#MSGBK_MOD",1,0); /* バックログ用のボタンを使用するか */
+
+	SetOrigParam("#WAKU.000.000.TYPE", 1, 5);
+	SetOrigParam("#WAKU.000.000.MOVE_BOX", 5, 0, 0, 0, 0, 0); // テキストウィンドウの移動用ボタン位置
+	SetOrigParam("#WAKU.000.000.CLEAR_BOX", 5, 0, 0, 0, 0, 0); //    一時消去用ボタン位置
+	SetOrigParam("#WAKU.000.000.READJUMP_BOX", 5, 0, 0, 0, 0, 0); // スキップ用ボタン位置
+	SetOrigParam("#WAKU.000.000.AUTOMODE_BOX", 5, 0, 0, 0, 0, 0); // オート用ボタン位置
+	SetOrigParam("#WAKU.000.000.MSGBK_BOX", 5, 0, 0, 0, 0, 0); // バックログボタン位置
+	SetOrigParam("#WAKU.000.000.MSGBKLEFT_BOX", 5, 0, 0, 0, 0, 0); // バックログ(進める)ボタン位置
+	SetOrigParam("#WAKU.000.000.MSGBKRIGHT_BOX", 5, 0, 0, 0, 0, 0); // バックログ(戻る)ボタン位置
+	SetOrigParam("#WAKU.000.000.EXBTN_000_BOX", 5, 0, 0, 0, 0, 0); // その他ボタン0位置
+	SetOrigParam("#WAKU.000.000.EXBTN_001_BOX", 5, 0, 0, 0, 0, 0); // その他ボタン1位置
+	SetOrigParam("#WAKU.000.000.EXBTN_002_BOX", 5, 0, 0, 0, 0, 0); // その他ボタン2位置
+
+	SetOrigParam("#WINDOW.000.MOJI_SIZE", 1, 21); // 文字サイズ
+	SetOrigParam("#WINDOW.000.MOJI_REP", 2, -1, 2); // 文字の余裕
+	SetOrigParam("#WINDOW.000.MOJI_CNT", 2, 20, 3); // ウィンドウ内の文字数
+	SetOrigParam("#WINDOW.000.MOJI_POS", 4, 100, 0, 180, 40); // テキスト位置。3つ目がx で1つ目がyらしい
+	SetOrigParam("#WINDOW.000.MOJI_SHADOW", 1, 0); // 文字に影を付けるか
+	SetOrigParam("#WINDOW.000.LUBY_SIZE", 1, 8); // ルビの文字サイズ
+	SetOrigParam("#WINDOW.000.MOJI_MIN", 2, 8, 1); // 文字同士の隙間?
+	SetOrigParam("#WINDOW.000.SELCOM_USE", 1, 0); // 選択肢の実装方法
+	SetOrigParam("#WINDOW.000.POS", 4, 100, 0, 0, 260); // ウィンドウ位置
+	SetOrigParam("#WINDOW.000.ATTR_MOD", 1, 0); // ウィンドウ色
+	SetOrigParam("#WINDOW.000.ATTR", 5, -1, -1, -1, -1, -1); // ウィンドウ色
+	/* SELCOM はよくわからんので無視 */
+	SetOrigParam("#WINDOW.000.OPEN_ANM_MOD", 1, 0); // ウィンドウを開くときの効果らしい
+	SetOrigParam("#WINDOW.000.OPEN_ANM_TIME", 1, 500);
+	SetOrigParam("#WINDOW.000.CLOSE_ANM_MOD", 1, 0); // ウィンドウを閉じるときの効果らしい
+	SetOrigParam("#WINDOW.000.CLOSE_ANM_TIME", 1, 500);
+	SetOrigParam("#WINDOW.000.WAKU_SETNO", 1, 0); // 枠の種類
+	SetOrigParam("#WINDOW.000.MOVE_USE", 1, 0); // ウィンドウ枠移動ボタン使用の可否
+	SetOrigParam("#WINDOW.000.CLEAR_USE", 1, 0); // ウィンドウ枠消去ボタン使用の可否
+	SetOrigParam("#WINDOW.000.READJUMP_USE", 1, 0); // スキップボタン使用の可否
+	SetOrigParam("#WINDOW.000.AUTOMODE_USE", 1, 0); // スキップボタン使用の可否
+	SetOrigParam("#WINDOW.000.MSGBK_USE", 1, 0); // バックログボタン使用の可否
+	SetOrigParam("#WINDOW.000.MSGBKLEFT_USE", 1, 0); // バックログ(進む)ボタン使用の可否
+	SetOrigParam("#WINDOW.000.MSGBKRIGHT_USE", 1, 0); // バックログ(戻る)ボタン使用の可否
+	SetOrigParam("#WINDOW.000.EXBTN_000_USE", 1, 0); // その他ボタン0使用の可否
+	SetOrigParam("#WINDOW.000.EXBTN_001_USE", 1, 0); // その他ボタン1使用の可否
+	SetOrigParam("#WINDOW.000.EXBTN_002_USE", 1, 0); // その他ボタン2使用の可否
+	SetOrigParam("#WINDOW.000.NAME_MOD", 1, 0); // 名前ウィンドウを別途使用するか
+	SetOrigParam("#WINDOW.000.NAME_MOJI_SIZE", 1, 20); // 名前フォントのサイズ
+	SetOrigParam("#WINDOW.000.NAME_MOJI_POS", 2, 0, 0); // 名前ウィンドウの文字の位置
+	SetOrigParam("#WINDOW.000.NAME_MOJI_MIN", 1, 0); // 名前ウィンドウの幅
+	SetOrigParam("#WINDOW.000.NAME_CENTERING", 1, 1); // 名前のセンタリングの有無
+	SetOrigParam("#WINDOW.000.NAME_POS", 2, 159, 78); // 名前ウィンドウ位置(左下位置らしい)
+	SetOrigParam("#WINDOW.000.NAME_WAKU_SETNO", 1, -1); // 名前ウィンドウ位置(左下位置らしい)
+	SetOrigParam("#WINDOW.000.FACE.000", 5, 0, 0, 1, 1, 1); // 顔ウィンドウ位置(始め2つがx,y、MOJI_POSからの相対位置なのに注意)
+	SetOrigParam("#WINDOW.000.KEYCUR_MOD", 3, 0, 0, 0); // リターンカーソルの位置
+
+
+	SetOrigParam("#CURSOR.000.SIZE", 2, 0, 0); // リターンカーソルの大きさ
+	SetOrigParam("#CURSOR.000.CONT", 1, 50); // リターンカーソルの繰り返し数
+	SetOrigParam("#CURSOR.000.SPEED", 1, 1000); // ブリンクする速さ
+
+	SetOrigParam("#SELBTN.000.BASEPOS", 2, 0, 0); // 選択肢ウィンドウの位置
+	SetOrigParam("#SELBTN.000.REPPOS", 2, 0, 50); // 選択肢ウィンドウの次の位置(相対)
+	SetOrigParam("#SELBTN.000.MOJISIZE", 4, 26, 0,0,0); // 文字の大きさ
+	SetOrigParam("#SELBTN.000.MOJIDEFAULTCOL", 1, 0); // 非選択時の文字色
+	SetOrigParam("#SELBTN.000.MOJISELECTCOL", 1, 0); // 選択時の文字色
+
+	SetOrigParam("#COLOR_TABLE.000", 3, 255,255,255);
+	SetOrigParam("#SHAKE.000", 3, 0,0,0);
+
+	SetOrigParam("#SELR.000",16,0,0,640,480,0,0,500,50,0,0,0,0,0,0,255,0);
+	SetOrigParam("#SEL.000", 15,0,0,639,479,0,0, 32, 4,0,0,0,0,0,0,0); 
+
+	SetOrigParam("#SCREENSIZE_MOD", 1, 0); /* 0 = 640x480; 1 = 800x600 */
+}
+
+static int SplitVar(const char* str, int* ret_var, int ret_size) {
+	/* , あるいは ),:( をセパレータとして、-?[0-9]+ の
+	** フォーマットの数値列を読み込む。先頭に (、末尾に ) が付きうる。
+	** (),-[0-9] 以外の文字があったらそこで終了
+	** 得られたデータ数を返す
+	*/
+	if (*str == '(') str++;
+	int i; for (i=0; i<ret_size; i++) {
+		int c; int is_positive = 1;
+		/* セパレータの読み飛ばし */
+		c = *str;
+		if (c == ',' || c == ':') {
+			str++;
+		} else if (c == ')' && str[1] == '(') {
+			str += 2;
+		}
+		/* - を parse */
+		c = *str;
+		if (c == '-' && isdigit(str[1])) {
+			is_positive = -1; str++;
+		} else if (! isdigit(c)) {
+			return i; /* 異常な文字を見つけた:終了 */
+		}
+		int number = 0;
+		/* 数字読み込み */
+		while(isdigit( (c=*str) )) {
+			number *= 10;
+			number += c-'0';
+			str++;
+		}
+		ret_var[i] = is_positive * number;
+	}
+	return i;
+}
+/* 決められた数の引数を得る。-1 ならエラーが生じた */
+static inline int SplitVar(const char* str, int& var1) {
+	if (SplitVar(str, &var1, 1) != 1) return -1;
+	return 0;
+}
+static inline int SplitVar(const char* str, int& var1, int& var2) {
+	int vars[2];
+	if (SplitVar(str, vars, 2) != 2) return -1;
+	var1 = vars[0]; var2 = vars[1];
+	return 0;
+}
+static inline int SplitVar(const char* str, int& var1, int& var2, int& var3) {
+	int vars[3];
+	if (SplitVar(str, vars, 3) != 3) return -1;
+	var1 = vars[0]; var2 = vars[1]; var3 = vars[2];
+	return 0;
+}
+static inline int SplitVar(const char* str, int& var1, int& var2, int& var3, int& var4) {
+	int vars[4];
+	if (SplitVar(str, vars, 4) != 4) return -1;
+	var1 = vars[0]; var2 = vars[1]; var3 = vars[2]; var4 = vars[3];
+	return 0;
+}
+
+bool AyuSysConfig::LoadInitFile(void)
+{
+	char buf[1024]; int i;
+	char* tokens[MAXTOKEN]; int token_deal; int buf_ptr;
+	int numbers[MAXVARS];
+
+	ARCINFO* info = file_searcher.Find(FILESEARCH::ROOT, "gameexe.ini");
+	if (info == NULL) return false;
+	int size = info->Size();
+	unsigned char* buf_orig = (unsigned char*)info->Read();
+	if (size <= 0 || buf_orig == 0) {
+		delete info; return false;
+	}
+	unsigned char* buf_end = buf_orig + size;
+	int line_count = 0;
+	while(buf_orig < buf_end) {
+		/* buf_orig から一行読み込む */
+		/* その際に、
+		** ・頭が # 以外なら次の行までとばす
+		** ・"" 外のスペース、TABを初めとする制御文字 (0x20 以下のASCIIコード)を削除
+		** ・= で区切る。区切りは最大で10個で、tokens に代入される
+		** などの操作を行う
+		*/
+
+		/* # チェック */
+		if (*buf_orig != '#') {
+			/* 次の '\n' まで読み飛ばし */
+			while(buf_orig < buf_end &&
+				*buf_orig != '\n' && *buf_orig != '\r') buf_orig++;
+			if (buf_orig < buf_end-1 && *buf_orig == '\r' && buf_orig[1] == '\n') buf_orig += 2;
+			else if (*buf_orig == '\r' || *buf_orig == '\n') buf_orig++;
+			line_count++;
+			continue;
+		}
+		/* 初期化 */
+		token_deal = 1; tokens[0] = buf; buf_ptr = 0;
+		int in_quote = 0;
+
+		while(buf_orig < buf_end && buf_ptr < 1023) {
+			if (in_quote) {
+				/* "" の中 */
+				int c = *buf_orig;
+				if (c == '\n' || c == '\r') {
+					break;
+				} else if (c == '\"') {
+					in_quote = 0;
+				} else {
+					buf[buf_ptr++] = c;
+				}
+				buf_orig++;
+			} else { /* quote されてない */
+				/* 制御文字を読み飛ばす */
+				while(*buf_orig <= 0x20 && buf_orig < buf_end &&
+					*buf_orig != '\n' && *buf_orig != '\r') buf_orig++;
+				int c = *buf_orig;
+				if (c == '\n' || c == '\r') break;
+				/* = なら次の token */
+				if (c == '=') {
+					c = 0; tokens[token_deal++] = buf+buf_ptr+1;
+					if (token_deal >= MAXTOKEN) break;
+				} else if (c == '\"') {
+					in_quote = 1; buf_orig++; continue;
+				}
+				buf[buf_ptr++] = c;
+				buf_orig++;
+			}
+		}
+		buf[buf_ptr] = '\0';
+		/* 末尾の \r\n を消去 */
+		if (buf_orig < buf_end-1 && buf_orig[0] == '\r' && buf_orig[1] == '\n') buf_orig += 2;
+		else if (buf_orig < buf_end && (buf_orig[0] == '\r' || buf_orig[0] == '\n')) buf_orig++;
+		/* 必要なら parse 内容を出力 */
+		dprintf(("line %3d ",line_count));
+		for (i=0; i<token_deal; i++) {
+			dprintf(("%d:\"%s\", ",i,tokens[i]));
+		}
+		dprintf(("\n"));
+		if (in_quote) {
+			fprintf(stderr, "Warning : open quote is found while parsing gameexe.ini, line %d\n",line_count);
+		}
+
+
+		/* 得られた内容を parse */
+
+		/* #NAME=<文字列> */
+		int type = SearchParam(tokens[0]);
+		if (type == 1) { /* #NAME=<文字列> */
+			if (token_deal != 2) {
+				dprintf(("Parse error, line %d, %s\n",line_count, tokens[0]));
+				goto parse_error;
+			}
+			SetOrigParaStr(tokens[0], tokens[1]);
+			goto parse_end;
+		} else if (type == 2) { /* #NAME=<数値列> */
+			if (token_deal != 2) {
+				dprintf(("Parse error, line %d, %s\n",line_count, tokens[0]));
+				goto parse_error;
+			}
+			int number_deal = SplitVar(tokens[1], numbers, MAXVARS);
+			SetOrigParamArray(tokens[0], number_deal, numbers);
+			goto parse_end;
+		}
+		/* 一般的な設定以外 : cdrom track など */
+		if (strncmp(tokens[0],"#NAME.", 6) == 0) {
+			if (token_deal != 2) goto parse_error;
+			SetOrigParaStr(tokens[0], tokens[1]);
+			goto parse_end;
+		} else if (strncmp(tokens[0],"#DIRC.",6) == 0) {
+			if (token_deal != 3) goto parse_error;
+			/* ファイル形式の指定 */
+			FILESEARCH::FILETYPE type;
+			char* name = tokens[0]+6;
+			if (strcmp(name, "PDT") == 0) type = FILESEARCH::PDT;
+			else if (strcmp(name, "G00") == 0) type = FILESEARCH::PDT;
+			else if (strcmp(name, "GRP") == 0) type = FILESEARCH::PDT;
+			else if (strcmp(name, "TXT") == 0) type = FILESEARCH::SCN;
+			else if (strcmp(name, "ANM") == 0) type = FILESEARCH::ANM; 
+			else if (strcmp(name, "ARD") == 0) type = FILESEARCH::ARD;
+			else if (strcmp(name, "CUR") == 0) type = FILESEARCH::CUR;
+			else if (strcmp(name, "WAV") == 0) type = FILESEARCH::WAV;
+			else if (strcmp(name, "KOE") == 0) type = FILESEARCH::KOE;
+			else if (strcmp(name, "GAN") == 0) type = FILESEARCH::GAN;
+			else goto parse_error; /* 他に ALL,ROOT,MID,KOE,BGM。たぶん、存在しない */
+			if (tokens[2][0] == 'N') { /* directory */
+				file_searcher.SetFileInformation(type, FILESEARCH::ATYPE_DIR, tokens[1]);
+				dprintf(("set file directory; type %s, directory %s\n",name,tokens[1]));
+			} else if (tokens[2][0] == 'P' && tokens[2][1] == ':') { /* アーカイブ */
+				file_searcher.SetFileInformation(type, FILESEARCH::ATYPE_ARC, tokens[2]+2);
+				dprintf(("set file archive; type %s, file %s\n",name,tokens[2]+2));
+			} else goto parse_error;
+			goto parse_end;
+		}
+		if (strncmp(tokens[0],"#ADRC.",6) == 0) {
+			if (token_deal != 3) goto parse_error;
+			/* ファイル形式の指定 */
+			FILESEARCH::FILETYPE type;
+			char* name = tokens[0]+6;
+			if (strcmp(name, "PDT") == 0) type = FILESEARCH::PDT;
+			else if (strcmp(name, "G00") == 0) type = FILESEARCH::PDT;
+			else if (strcmp(name, "GRP") == 0) type = FILESEARCH::PDT;
+			else if (strcmp(name, "TXT") == 0) type = FILESEARCH::SCN;
+			else if (strcmp(name, "ANM") == 0) type = FILESEARCH::ANM; 
+			else if (strcmp(name, "ARD") == 0) type = FILESEARCH::ARD;
+			else if (strcmp(name, "CUR") == 0) type = FILESEARCH::CUR;
+			else if (strcmp(name, "WAV") == 0) type = FILESEARCH::WAV;
+			else if (strcmp(name, "KOE") == 0) type = FILESEARCH::KOE;
+			else if (strcmp(name, "GAN") == 0) type = FILESEARCH::GAN;
+			else goto parse_error; /* 他に ALL,ROOT,MID,KOE,BGM。たぶん、存在しない */
+			if (tokens[2][0] == 'N') { /* directory */
+				file_searcher.AppendFileInformation(type, FILESEARCH::ATYPE_DIR, tokens[1]);
+				dprintf(("set file directory; type %s, directory %s\n",name,tokens[1]));
+			} else if (tokens[2][0] == 'P' && tokens[2][1] == ':') { /* アーカイブ */
+				file_searcher.AppendFileInformation(type, FILESEARCH::ATYPE_ARC, tokens[2]+2);
+				dprintf(("set file archive; type %s, file %s\n",name,tokens[2]+2));
+			} else if (tokens[2][0] == 'R' && tokens[2][1] == ':') { /* それ散るアーカイブ */
+				file_searcher.AppendFileInformation(type, FILESEARCH::ATYPE_ARC, tokens[2]+2);
+				dprintf(("set file archive; type %s, file %s\n",name,tokens[2]+2));
+			} else goto parse_error;
+			goto parse_end;
+		}
+		if (strncmp(tokens[0],"#FOLDNAME.",10) == 0) {
+			if (token_deal != 3) goto parse_error;
+			/* ファイル形式の指定 */
+			FILESEARCH::FILETYPE type;
+			char* name = tokens[0]+10;
+			if (strcmp(name, "PDT") == 0) type = FILESEARCH::PDT;
+			else if (strcmp(name, "G00") == 0) type = FILESEARCH::PDT;
+			else if (strcmp(name, "GRP") == 0) type = FILESEARCH::PDT;
+			else if (strcmp(name, "TXT") == 0) type = FILESEARCH::SCN;
+			else if (strcmp(name, "ANM") == 0) type = FILESEARCH::ANM; 
+			else if (strcmp(name, "ARD") == 0) type = FILESEARCH::ARD;
+			else if (strcmp(name, "CUR") == 0) type = FILESEARCH::CUR;
+			else if (strcmp(name, "WAV") == 0) type = FILESEARCH::WAV;
+			else if (strcmp(name, "BGM") == 0) type = FILESEARCH::BGM;
+			else if (strcmp(name, "GAN") == 0) type = FILESEARCH::GAN;
+			else goto parse_error; /* 他に ALL,ROOT,MID,KOE,BGM。たぶん、存在しない */
+			if (tokens[2][0] == '0') { /* directory */
+				file_searcher.AppendFileInformation(type, FILESEARCH::ATYPE_DIR, tokens[1]);
+				dprintf(("set file directory; type %s, directory %s\n",name,tokens[1]));
+			} else if (tokens[2][0] == '1' && tokens[2][1] == ':') { /* アーカイブ */
+				file_searcher.AppendFileInformation(type, FILESEARCH::ATYPE_SCN2k, tokens[2]+2);
+				dprintf(("set file archive; type %s, file %s\n",name,tokens[2]+2));
+			} else goto parse_error;
+			goto parse_end;
+		}
+		if (strcmp(tokens[0], "#CDTRACK") == 0) {
+			if (token_deal != 3) goto parse_error;
+			track_name.AddCDROM(tokens[2], atoi(tokens[1]));
+			dprintf(("Set CDTRACK, name %s, track %d\n",tokens[2], atoi(tokens[1])));
+			goto parse_end;
+		}
+		if (strcmp(tokens[0], "#DSTRACK") == 0) {
+			/* #DSTRACK=00000000-99999000-00782556="filename"   ="name"       */
+			/* #DSTRACK=00000000-99999000-00782556="name"       */
+			/* 第二トークンの3つめのパラメータを得る(繰り返しの時の再生開始位置) */
+			int start_pt = 0;
+			const char* tk1 = strchr(tokens[1], '-');
+			const char* tk2 = 0;
+			if (tk1 && *tk1) tk2 = strchr(tk1+1, '-');
+			if (tk2 && *tk2) start_pt = atoi(tk2+1);
+			if (token_deal == 3) {
+				track_name.AddWave(tokens[2], tokens[2], start_pt);
+				dprintf(("Set Wave track, name %s\n",tokens[2]));
+			} else if (token_deal == 4) {
+				track_name.AddWave(tokens[3], tokens[2], start_pt);
+				dprintf(("Set Wave track, name %s, file %s\n",tokens[3], tokens[2]));
+			} else goto parse_error;
+			goto parse_end;
+		}
+		if (strncmp(tokens[0], "#SE.", 4) == 0) {
+			/* SE.XXX="XXX"=X */
+			if (token_deal == 2) {
+				track_name.AddSE(atoi(tokens[0]+4), tokens[1]);
+			} else if (token_deal == 3) {
+				if (atoi(tokens[2]) != 0) {
+					track_name.AddSE(atoi(tokens[0]+4), tokens[1]);
+				}
+			}
+			dprintf(("Set SE %d, name %s\n",atoi(tokens[0]+4), tokens[1]));
+			goto parse_end;
+		}
+		/* 設定項目が見つからなかった */
+		dprintf(("Cannot find configuration name: %s\n",tokens[0]));
+	parse_error:
+	parse_end:
+		line_count++;
+	}
+	delete info;
+	/* デフォルトのオプションを指定する */
+	// set_game(GetParaStr("#REGNAME"), *this);
+	return true;
+}
+
+TrackName::TrackName(void) {
+	deal = 1;
+	track = new char*[deal];
+	track_wave = new char*[deal];
+	track_num = new int[deal];
+	track_start = new int[deal];
+	int i; for (i=0; i<deal; i++) track[i] = 0;
+	for (i=0; i<deal; i++) track_wave[i] = 0;
+	se_deal = 10;
+	se_track = new char*[se_deal];
+	for (i=0; i<se_deal; i++) se_track[i] = 0;
+}
+
+TrackName::~TrackName() {
+	int i; for (i=0; i<deal; i++) {
+		if (track[i] != 0) delete[] track[i];
+		if (track_wave[i] != 0) delete[] track_wave[i];
+	}
+	for (i=0; i<se_deal; i++) {
+		if (se_track[i]) delete[] se_track[i];
+	}
+	delete[] track;
+	delete[] track_wave;
+	delete[] track_num;
+	delete[] track_start;
+	delete[] se_track;
+}
+void TrackName::Expand(void) {
+	int new_deal = deal * 2;
+	int* new_track_num = new int[new_deal];
+	int* new_track_start = new int[new_deal];
+	char** new_track = new char*[new_deal];
+	char** new_track_wave = new char*[new_deal];
+	int i; for (i=0; i<deal; i++) {
+		new_track_num[i] = track_num[i];
+		new_track_start[i] = track_start[i];
+		new_track[i] = track[i];
+		new_track_wave[i] = track_wave[i];
+	}
+	for (; i<new_deal; i++) { 
+		new_track_num[i] = 0;
+		new_track_start[i] = 0;
+		new_track[i] = 0;
+		new_track_wave[i] = 0;
+	}
+	deal = new_deal;
+	delete[] track; track = new_track;
+	delete[] track_num; track_num= new_track_num;
+	delete[] track_start; track_start= new_track_start;
+	delete[] track_wave; track_wave = new_track_wave;
+}
+void TrackName::ExpandSE(int n) {
+	if (n < 0) return;
+	n += 10;
+	if (se_deal >= n) return;
+	char** new_se = new char*[n];
+	int i; for (i=0; i<se_deal; i++) new_se[i] = se_track[i];
+	for (; i<n; i++) new_se[i] = 0;
+	delete[] se_track;
+	se_deal = n; se_track = new_se;
+}
+void TrackName::AddCDROM(char* name, int tk) {
+	if (CDTrack(name) != -1) return;
+	int i; for (i=0; i<deal; i++) {
+		if (track[i] == 0) break;
+	}
+	int num = i;
+	if (i == deal) Expand();
+	track[num] = new char[strlen(name)+1];
+	for (i=0; name[i] != 0; i++) track[num][i] = tolower(name[i]);
+	track[num][i] = 0;
+	track_num[num] = tk;
+}
+void TrackName::AddWave(char* name, char* file, int pt) {
+	if (CDTrack(name) != -1) return;
+	int i; for (i=0; i<deal; i++) {
+		if (track[i] == 0) break;
+	}
+	int num = i;
+	if (i == deal) Expand();
+	track_num[num] = 0;
+	track_start[num] = pt;
+	track[num] = new char[strlen(name)+1];
+	for (i=0; name[i] != 0; i++) track[num][i] = tolower(name[i]);
+	track[num][i] = 0;
+	track_wave[num] = new char[strlen(file)+1]; strcpy(track_wave[num], file);
+}
+int TrackName::CDTrack(char* name) {
+	char buf[1024];
+	int i;
+	for (i=0; name[i]!=0; i++) buf[i]=tolower(name[i]);
+	buf[i]=0;
+	for (i=0; i<deal; i++) {
+		if (track[i] == 0) return -1;
+		if (strcmp(track[i],  buf) == 0) {
+			return track_num[i];
+		}
+	}
+	return -1;
+}
+int TrackName::TrackStart(char* name) {
+	char buf[1024];
+	int i;
+	for (i=0; name[i]!=0; i++) buf[i]=tolower(name[i]);
+	buf[i]=0;
+	for (i=0; i<deal; i++) {
+		if (track[i] == 0) return -1;
+		if (strcmp(track[i],  buf) == 0) {
+			return track_start[i];
+		}
+	}
+	return 0;
+}
+const char* TrackName::WaveTrack(char* name) {
+	char buf[1024];
+	int i;
+	for (i=0; name[i]!=0; i++) buf[i]=tolower(name[i]);
+	buf[i]=0;
+	for (i=0; i<deal; i++) {
+		if (track[i] == 0) return 0;
+		if (strcmp(track[i],  buf) == 0) {
+			return track_wave[i];
+		}
+	}
+	return 0;
+}
+const char* TrackName::SETrack(int n) {
+	if (n < 0 || n >= se_deal) return 0;
+	return se_track[n];
+}
+void TrackName::AddSE(int n, char* file) {
+	if (se_deal <= n) ExpandSE(n);
+	if (se_track[n]) delete[] se_track[n];
+	se_track[n] = new char[strlen(file)+1];
+	strcpy(se_track[n], file);
+}
+
new file mode 100644
--- /dev/null
+++ b/system/system_config.h
@@ -0,0 +1,83 @@
+#include<string>
+
+/* CD Track 名 <-> Track 番号の変換を行う */
+class TrackName {
+	char** track;
+	int* track_num;
+	char** track_wave;
+	int* track_start;
+	int deal;
+	void Expand(void);
+	char** se_track;
+	int se_deal;
+	void ExpandSE(int num);
+public:
+	TrackName(void);
+	~TrackName(void);
+	void AddCDROM(char* name, int track);
+	void AddWave(char* name, char* wave, int start_pt);
+	void AddSE(int num, char* se);
+	int CDTrack(char* name);
+	int TrackStart(char* name);
+	const char* WaveTrack(char* name);
+	const char* SETrack(int num);
+};
+/* gameexe.ini で設定されるパラメータ */
+/* まず初めに、設定項目を SetOrigPara* でセットする
+** ただし、設定名は255文字以下である必要がある。
+**
+** SetPara* で設定項目は変更できる
+** また、GetPara* で設定項目を得られる。
+*/
+
+class AyuSysConfig {
+	friend class Conf2; /* テスト用のクラス */
+	int change_flag;
+	int dirty_flag;
+	class AyuSysConfigString* str_config;
+	class AyuSysConfigIntlist* int_config;
+
+public:
+	TrackName track_name;
+
+public:
+	AyuSysConfig(void);
+	bool LoadInitFile(void);
+	/* パラメータを検索する */
+	/* str なら 1, int なら 2, 見つからないなら 0 */
+	int SearchParam(const char* name) const;
+	/* パラメータを得る */
+	const char* GetParaStr(const char* name) const; /* str */
+	int GetParam(const char* name, int deal, ...) const; /* int, error -> return -1, no error -> return 0 */
+	int GetOriginalParam(const char* name, int deal, ...) const; /* int, error -> return -1, no error -> return 0 */
+	int GetParaInt(const char* name) const {
+		int n;
+		if (GetParam(name,1,&n)) return 0;
+		return n;
+	}
+	const int* GetParamArray(const char* name, int& deal) const;
+	/* パラメータを変更する */
+	void SetParaStr(const char* name, const char* var); /* str */
+	void SetParam(const char* name, int deal, ...); /* int */
+private:
+	friend class AyuSys;
+	/* 元設定を行う */
+	/* AyuSys からのみ可能 */
+	void SetOrigParaStr(const char* name, const char* var); /* str */
+	void SetOrigParam(const char* name, int para_deal, ...); /* int */
+	void SetOrigParamArray(const char* name, int deal, int* array); /* 上とおなじ */
+public:
+
+	/* オリジナルの設定関係
+	** SetOriginal : 全ての設定を初めの状態に戻す
+	** DiffOriginal : 初めの状態と現在の状態の変更分を得る
+	** PatchOriginal: DiffOriginal で得た文字列を引数に
+	**   渡す。DiffOriginal 呼び出し時の状態に戻す
+	*/
+	void SetOriginal(void);
+	void DiffOriginal(std::string&);
+	const char* PatchOriginal(const char*);
+	/* config の内容を表示する */
+	void Dump(FILE* f) const;
+};
+
new file mode 100644
--- /dev/null
+++ b/system/visarc.cc
@@ -0,0 +1,296 @@
+#define CMDNAME "visarc"
+#define VERSION "1.00"
+
+/*****************************************
+**	Visual Arts の圧縮書庫ファイルを
+**	展開する
+**
+**	usage : visarc x <arcfile> <file> [<file> ...]
+**		visarc l <arcfile>
+**		visarc g <arcfile> <graphic file>
+**		visarc m <arcfile> <mask file>
+**
+******************************************
+*/
+/*
+ *
+ *  Copyright (C) 2000-   Kazunori Ueno(JAGARL) <jagarl@creator.club.ne.jp>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+*/
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+// use only file subsystem
+#include "file.h"
+#include "file_impl.h"
+// #include "file.cc"
+
+#ifdef HAVE_LIBPNG
+#include <png.h>
+#endif
+
+void usage(void) {
+	fprintf(stderr, "usage : visarc <cmd> <arcfile> [<file1> [<file2> [...] ]]\n");
+	fprintf(stderr, "           cmd :   x : extract\n");
+	fprintf(stderr, "                   l : list all files\n");
+	fprintf(stderr, "\n");
+#ifdef HAVE_LIBPNG
+	fprintf(stderr, "usage2: visarc <cmd> <pdt-file> [<output-file>]\n");
+	fprintf(stderr, "           cmd     p : unpack pdt file and save as png file\n");
+#endif /* HAVE_LIBPNG */ 
+	fprintf(stderr, "\n");
+}
+
+void List(char* path) {
+	ARCFILE* file;
+	FILE* f = fopen(path, "rb");
+	if (f == 0) return;
+	char header[32];
+	fread(header, 32, 1, f);
+	fclose(f);
+	char magic_raf[8] = {'C','A','P','F',1,0,0,0};
+	if (strncmp(header, "PACL", 4) == 0) file = new ARCFILE(path);
+	else file = new SCN2kFILE(path);
+	file->Init();
+	file->ListFiles(stdout);
+	delete file;
+	return;
+}
+
+void ExtractOne(ARCFILE* arc, char* file) {
+	ARCINFO* info = arc->Find(file,"");
+	if (info == 0) {
+		fprintf(stderr, "Cannot find file %s in archive\n",file);
+		return;
+	}
+	FILE* out = fopen(file, "w");
+	if (out == 0) {
+		delete info;
+		fprintf(stderr, "Cannot open output file %s\n",file);
+		return;
+	}
+	
+	fprintf(stdout, "Extracting %s ... ",file);
+	int size = info->Size();
+	const char* data = info->Read();
+	fwrite(data, size, 1, out);
+	fclose(out);
+	fprintf(stdout, "done\n");
+	delete info;
+	return;
+}
+
+void Extract(char* path, char** files, int fnum) {
+	ARCFILE* file;
+	FILE* f = fopen(path, "rb");
+	if (f == 0) return;
+	char header[32];
+	fread(header, 32, 1, f);
+	fclose(f);
+	char magic_raf[8] = {'C','A','P','F',1,0,0,0};
+	if (strncmp(header, "PACL", 4) == 0) file = new ARCFILE(path);
+	else file = new SCN2kFILE(path);
+	file->Init();
+	if (files != 0 && fnum != 0) {
+		int i; for (i=0; i<fnum; i++) {
+			ExtractOne(file, files[i]);
+		}
+	} else {
+		file->InitList();
+		char* path; while( (path=file->ListItem()) != 0) {
+			ExtractOne(file, path);
+		}
+	}
+	delete file;
+	return;
+}
+
+void ChangeExt(char* path, char* new_ext, char* buf) {
+	char* name = strrchr(path, DIR_SPLIT);
+	if (name == 0) name = path;
+	else name++;
+	int path_len = name - path;
+
+	char* ext = strrchr(name, '.');
+	int ext_len;
+	if (ext) ext_len = ext - name;
+	else ext_len = strlen(name);
+
+	strncpy(buf, path, path_len+ext_len);
+	strcpy(buf+path_len+ext_len, new_ext);
+}
+
+char* ReadFile(char* fname, int* len) {
+	FILE* in = fopen(fname, "rb");
+	if (in == 0) return 0;
+	fseek(in,0,2); size_t s = ftell(in); fseek(in,0,0);
+	char* buf = new char[s];
+	fread(buf,s,1,in);
+	fclose(in);
+	if (len) *len = s;
+	return buf;
+}
+
+
+#ifdef HAVE_LIBPNG
+void create_png(FILE* stream, char* path, char* desc, int width, int height, char* data) {
+	png_structp png_ptr;
+	png_infop info_ptr;
+
+	/* create struct */
+	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+	if (png_ptr == NULL) return;
+
+	/* initialize information */
+	info_ptr = png_create_info_struct(png_ptr);
+	if (info_ptr == NULL) {
+		png_destroy_write_struct(&png_ptr, (png_infop*)NULL);
+		return;
+	}
+
+	if (setjmp(png_jmpbuf(png_ptr))) {
+		/* error occured !! */
+		png_destroy_write_struct(&png_ptr,&info_ptr);
+		fprintf(stderr, "Get error while processing PNG from file %s\n",path);
+		return;
+	}
+
+	/* initialize I/O (for stream) */
+	png_init_io(png_ptr, stream);
+
+	/* initialize headers */
+	png_set_IHDR(png_ptr, info_ptr,
+		width, height, 8 /* bit_dept */,
+		PNG_COLOR_TYPE_RGB_ALPHA,
+		PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+	/* create text information */
+	png_text info_text[3];
+	info_text[0].key = "Title";
+	info_text[0].text= path;
+	info_text[0].compression = PNG_TEXT_COMPRESSION_NONE;
+	info_text[1].key = "Author";
+	info_text[1].text= CMDNAME " version " VERSION;
+	info_text[1].compression = PNG_TEXT_COMPRESSION_NONE;
+	info_text[2].key = "Description";
+	info_text[2].text= desc;
+	info_text[2].compression = PNG_TEXT_COMPRESSION_NONE;
+	png_set_text(png_ptr, info_ptr, info_text, 3);
+
+	/* write information */
+	png_write_info(png_ptr, info_ptr);
+
+	/* write body */
+	/* rgba image ; input/output is 32bpp.*/
+	char* row = new char[width*4];
+	int i; for (i=0; i<height; i++) {
+		char* row_ptr = row;
+		int j; for (j=0; j<width; j++) {
+			row_ptr[0] = data[2];
+			row_ptr[1] = data[1];
+			row_ptr[2] = data[0];
+			row_ptr[3] = data[3];
+			row_ptr += 4; data += 4;
+		}
+		png_write_rows(png_ptr, (png_byte**)&row, 1);
+	}
+	png_write_end(png_ptr, info_ptr);
+	png_destroy_write_struct(&png_ptr, &info_ptr);
+	return;
+}
+
+void ExtractPngRgbaGraphic(char* path,char* outpath = 0) {
+	char buf[1024]; char* fname = buf;
+	int len;
+	char* dat = ReadFile(path, &len);
+	if (dat == 0) {
+		fprintf(stderr, "Cannot open PDT file : %s\n",path);
+		return;
+	}
+	GRPCONV* conv = GRPCONV::AssignConverter(dat, len, path);
+	if (conv == 0) {
+		fprintf(stderr, "Invalid format\n");
+		return;
+	}
+	bool masked = conv->IsMask();
+	char* data = new char[conv->Width() * conv->Height() * 4 + 1024];
+	if (! conv->Read(data)) {
+		fprintf(stderr, "Insufficient memory\n");
+		delete conv;
+		return;
+	}
+	if (! masked) {
+		for (int i = 0; i < conv->Width() * conv->Height(); i++) {
+			data[4*i+3] = 0xff;	// 不透明度を最大にする
+		}
+	}
+	if (outpath == 0) ChangeExt(path,".png", buf); // path をつくる
+	else fname = outpath;
+	FILE* out = fopen(fname, "wb"); // ファイルを開く
+	if (out == 0) {
+		fprintf(stderr, "Cannot open raw file : %s\n",buf);
+		delete conv;
+		return;
+	}
+	create_png(out, path, "", conv->Width(), conv->Height(), data);
+  	fclose(out);
+  	
+	delete conv;
+}
+#endif /* HAVE_LIBPNG */
+
+int main(int argc, char* argv[]) {
+	int i; 
+	fprintf(stderr, "%s version %s\n", CMDNAME, VERSION);
+	if (argc < 3) { 
+		usage(); return -1;
+	}
+	if (strlen(argv[1]) != 1) {
+		usage(); return -1;
+	}
+	for (i=2; i<argc; i++) {
+		/* option を削る */
+		argc--;
+		int j; for (j=i; j<argc; j++) argv[j] = argv[j+1];
+	}
+	switch(argv[1][0]) {
+		case 'x': case 'X':
+			if (argc < 4) Extract(argv[2], 0, -1);
+			else Extract(argv[2], argv+3, argc-3);
+			break;
+		case 'l': case 'L':
+			List(argv[2]);
+			break;
+#ifdef HAVE_LIBPNG
+		case 'p': case 'P':
+		case 'a': case 'A':
+			if (argc < 4)
+				ExtractPngRgbaGraphic(argv[2]);
+			else
+				ExtractPngRgbaGraphic(argv[2],argv[3]);
+			break;
+#endif /* HAVE_LIBPNG */
+		default:
+			usage(); return -1;
+	}
+	return 0;
+}
new file mode 100644
--- /dev/null
+++ b/window/Makefile.in
@@ -0,0 +1,46 @@
+@SET_MAKE@
+CC		= @CC@
+CXX		= @CXX@
+LD		= @CXX@
+AR		= ar
+RANLIB		= @RANLIB@
+
+CFLAGS= -I.. $(LOCAL_DEF) @CFLAGS@ @DEFS@ @SDL_CFLAGS@ -pthread -O2
+CXXFLAGS	= $(CFLAGS)
+LDFLAGS = @LDFLAGS@ @FT2_LIBS@ @SDL_LIBS@ @LIBS@ -pthread
+
+SRCS	= render.cc \
+	event.cc \
+	system.cc \
+	picture.cc \
+	widget.cc \
+	button.cc \
+	menuitem.cc \
+	SDL_rotozoom.cc \
+	rect.cc
+
+OBJS	 = ${SRCS:.cc=.o}
+
+all: libwindow.a test
+
+libwindow.a: ${OBJS}
+	rm -f libwindow.a
+	${AR} clq libwindow.a ${OBJS}
+	$(RANLIB) libwindow.a
+
+clean:
+	rm -f libwindow.a ${OBJS} *.bak *.core
+
+.c.o:
+	$(CC) -c $(CFLAGS) -o $@ $<
+
+.cc.o:
+	$(CXX) -c $(CFLAGS) -o $@ $<
+
+test: $(OBJS) test.o
+	$(LD) -o test test.o $(OBJS) ../font/libfont.a ../system/libsystem.a $(LDFLAGS)
+
+.png.bin:
+	pngtopnm $<.png | ppmtopgm | dd bs=1 skip=15 > $@
+.bin.txt: runlength
+	./runlength $< > $@
new file mode 100644
--- /dev/null
+++ b/window/SDL_rotozoom.cc
@@ -0,0 +1,939 @@
+/*  
+
+  SDL_rotozoom.c - rotozoomer for 32bit or 8bit surfaces
+
+  LGPL (c) A. Schiffler
+
+*/
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "SDL_rotozoom.h"
+
+#define MAX(a,b)    (((a) > (b)) ? (a) : (b))
+
+/* 
+ 
+ 32bit Zoomer with optional anti-aliasing by bilinear interpolation.
+
+ Zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
+ 
+*/
+
+int zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int smooth)
+{
+    int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy, ex, ey, t1, t2, sstep;
+    tColorRGBA *c00, *c01, *c10, *c11;
+    tColorRGBA *sp, *csp, *dp;
+    int sgap, dgap;
+
+    /*
+     * Variable setup 
+     */
+    if (smooth) {
+	/*
+	 * For interpolation: assume source dimension is one pixel 
+	 */
+	/*
+	 * smaller to avoid overflow on right and bottom edge.     
+	 */
+	sx = (int) (65536.0 * (float) (src->w - 1) / (float) dst->w);
+	sy = (int) (65536.0 * (float) (src->h - 1) / (float) dst->h);
+    } else {
+	sx = (int) (65536.0 * (float) src->w / (float) dst->w);
+	sy = (int) (65536.0 * (float) src->h / (float) dst->h);
+    }
+
+    /*
+     * Allocate memory for row increments 
+     */
+    if ((sax = (int *) malloc((dst->w + 1) * sizeof(Uint32))) == NULL) {
+	return (-1);
+    }
+    if ((say = (int *) malloc((dst->h + 1) * sizeof(Uint32))) == NULL) {
+	free(sax);
+	return (-1);
+    }
+
+    /*
+     * Precalculate row increments 
+     */
+    csx = 0;
+    csax = sax;
+    for (x = 0; x <= dst->w; x++) {
+	*csax = csx;
+	csax++;
+	csx &= 0xffff;
+	csx += sx;
+    }
+    csy = 0;
+    csay = say;
+    for (y = 0; y <= dst->h; y++) {
+	*csay = csy;
+	csay++;
+	csy &= 0xffff;
+	csy += sy;
+    }
+
+    /*
+     * Pointer setup 
+     */
+    sp = csp = (tColorRGBA *) src->pixels;
+    dp = (tColorRGBA *) dst->pixels;
+    sgap = src->pitch - src->w * 4;
+    dgap = dst->pitch - dst->w * 4;
+
+    /*
+     * Switch between interpolating and non-interpolating code 
+     */
+    if (smooth) {
+
+	/*
+	 * Interpolating Zoom 
+	 */
+
+	/*
+	 * Scan destination 
+	 */
+	csay = say;
+	for (y = 0; y < dst->h; y++) {
+	    /*
+	     * Setup color source pointers 
+	     */
+	    c00 = csp;
+	    c01 = csp;
+	    c01++;
+	    c10 = (tColorRGBA *) ((Uint8 *) csp + src->pitch);
+	    c11 = c10;
+	    c11++;
+	    csax = sax;
+	    for (x = 0; x < dst->w; x++) {
+
+		/*
+		 * Interpolate colors 
+		 */
+		ex = (*csax & 0xffff);
+		ey = (*csay & 0xffff);
+		t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
+		t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
+		dp->r = (((t2 - t1) * ey) >> 16) + t1;
+		t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
+		t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
+		dp->g = (((t2 - t1) * ey) >> 16) + t1;
+		t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
+		t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
+		dp->b = (((t2 - t1) * ey) >> 16) + t1;
+		t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
+		t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
+		dp->a = (((t2 - t1) * ey) >> 16) + t1;
+
+		/*
+		 * Advance source pointers 
+		 */
+		csax++;
+		sstep = (*csax >> 16);
+		c00 += sstep;
+		c01 += sstep;
+		c10 += sstep;
+		c11 += sstep;
+		/*
+		 * Advance destination pointer 
+		 */
+		dp++;
+	    }
+	    /*
+	     * Advance source pointer 
+	     */
+	    csay++;
+	    csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
+	    /*
+	     * Advance destination pointers 
+	     */
+	    dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
+	}
+
+    } else {
+
+	/*
+	 * Non-Interpolating Zoom 
+	 */
+
+	csay = say;
+	for (y = 0; y < dst->h; y++) {
+	    sp = csp;
+	    csax = sax;
+	    for (x = 0; x < dst->w; x++) {
+		/*
+		 * Draw 
+		 */
+		*dp = *sp;
+		/*
+		 * Advance source pointers 
+		 */
+		csax++;
+		sp += (*csax >> 16);
+		/*
+		 * Advance destination pointer 
+		 */
+		dp++;
+	    }
+	    /*
+	     * Advance source pointer 
+	     */
+	    csay++;
+	    csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
+	    /*
+	     * Advance destination pointers 
+	     */
+	    dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
+	}
+
+    }
+
+    /*
+     * Remove temp arrays 
+     */
+    free(sax);
+    free(say);
+
+    return (0);
+}
+
+/* 
+ 
+ 8bit Zoomer without smoothing.
+
+ Zoomes 8bit palette/Y 'src' surface to 'dst' surface.
+ 
+*/
+
+int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
+{
+    Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
+    Uint8 *sp, *dp, *csp;
+    int dgap;
+
+    /*
+     * Variable setup 
+     */
+    sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
+    sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
+
+    /*
+     * Allocate memory for row increments 
+     */
+    if ((sax = (Uint32 *) malloc(dst->w * sizeof(Uint32))) == NULL) {
+	return (-1);
+    }
+    if ((say = (Uint32 *) malloc(dst->h * sizeof(Uint32))) == NULL) {
+	if (sax != NULL) {
+	    free(sax);
+	}
+	return (-1);
+    }
+
+    /*
+     * Precalculate row increments 
+     */
+    csx = 0;
+    csax = sax;
+    for (x = 0; x < dst->w; x++) {
+	csx += sx;
+	*csax = (csx >> 16);
+	csx &= 0xffff;
+	csax++;
+    }
+    csy = 0;
+    csay = say;
+    for (y = 0; y < dst->h; y++) {
+	csy += sy;
+	*csay = (csy >> 16);
+	csy &= 0xffff;
+	csay++;
+    }
+
+    csx = 0;
+    csax = sax;
+    for (x = 0; x < dst->w; x++) {
+	csx += (*csax);
+	csax++;
+    }
+    csy = 0;
+    csay = say;
+    for (y = 0; y < dst->h; y++) {
+	csy += (*csay);
+	csay++;
+    }
+
+    /*
+     * Pointer setup 
+     */
+    sp = csp = (Uint8 *) src->pixels;
+    dp = (Uint8 *) dst->pixels;
+    dgap = dst->pitch - dst->w;
+
+    /*
+     * Draw 
+     */
+    csay = say;
+    for (y = 0; y < dst->h; y++) {
+	csax = sax;
+	sp = csp;
+	for (x = 0; x < dst->w; x++) {
+	    /*
+	     * Draw 
+	     */
+	    *dp = *sp;
+	    /*
+	     * Advance source pointers 
+	     */
+	    sp += (*csax);
+	    csax++;
+	    /*
+	     * Advance destination pointer 
+	     */
+	    dp++;
+	}
+	/*
+	 * Advance source pointer (for row) 
+	 */
+	csp += ((*csay) * src->pitch);
+	csay++;
+	/*
+	 * Advance destination pointers 
+	 */
+	dp += dgap;
+    }
+
+    /*
+     * Remove temp arrays 
+     */
+    free(sax);
+    free(say);
+
+    return (0);
+}
+
+/* 
+ 
+ 32bit Rotozoomer with optional anti-aliasing by bilinear interpolation.
+
+ Rotates and zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
+ 
+*/
+
+void transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int smooth)
+{
+    int x, y, t1, t2, dx, dy, xd, yd, sdx, sdy, ax, ay, ex, ey, sw, sh;
+    tColorRGBA c00, c01, c10, c11;
+    tColorRGBA *pc, *sp, *spb;
+    int gap;
+
+    /*
+     * Variable setup 
+     */
+    xd = ((src->w - dst->w) << 15);
+    yd = ((src->h - dst->h) << 15);
+    ax = (cx << 16) - (icos * cx);
+    ay = (cy << 16) - (isin * cx);
+    sw = src->w - 1;
+    sh = src->h - 1;
+    pc = (tColorRGBA*)(dst->pixels);
+    gap = dst->pitch - dst->w * 4;
+
+    /*
+     * Switch between interpolating and non-interpolating code 
+     */
+    if (smooth) {
+	for (y = 0; y < dst->h; y++) {
+	    dy = cy - y;
+	    sdx = (ax + (isin * dy)) + xd;
+	    sdy = (ay - (icos * dy)) + yd;
+	    for (x = 0; x < dst->w; x++) {
+		dx = (sdx >> 16);
+		dy = (sdy >> 16);
+		if ((dx >= -1) && (dy >= -1) && (dx < src->w) && (dy < src->h)) {
+		    if ((dx >= 0) && (dy >= 0) && (dx < sw) && (dy < sh)) {
+			sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
+			sp += dx;
+			c00 = *sp;
+			sp += 1;
+			c01 = *sp;
+			sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
+			sp -= 1;
+			c10 = *sp;
+			sp += 1;
+			c11 = *sp;
+		    } else if ((dx == sw) && (dy == sh)) {
+			sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
+			sp += dx;
+			c00 = *sp;
+			c01 = *sp;
+			c10 = *sp;
+			c11 = *sp;
+		    } else if ((dx == -1) && (dy == -1)) {
+			sp = (tColorRGBA *) (src->pixels);
+			c00 = *sp;
+			c01 = *sp;
+			c10 = *sp;
+			c11 = *sp;
+		    } else if ((dx == -1) && (dy == sh)) {
+			sp = (tColorRGBA *) (src->pixels);
+			sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
+			c00 = *sp;
+			c01 = *sp;
+			c10 = *sp;
+			c11 = *sp;
+		    } else if ((dx == sw) && (dy == -1)) {
+			sp = (tColorRGBA *) (src->pixels);
+			sp += dx;
+			c00 = *sp;
+			c01 = *sp;
+			c10 = *sp;
+			c11 = *sp;
+		    } else if (dx == -1) {
+			sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
+			c00 = *sp;
+			c01 = *sp;
+			c10 = *sp;
+			sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
+			c11 = *sp;
+		    } else if (dy == -1) {
+			sp = (tColorRGBA *) (src->pixels);
+			sp += dx;
+			c00 = *sp;
+			c01 = *sp;
+			c10 = *sp;
+			sp += 1;
+			c11 = *sp;
+		    } else if (dx == sw) {
+			sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
+			sp += dx;
+			c00 = *sp;
+			c01 = *sp;
+			sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch);
+			c10 = *sp;
+			c11 = *sp;
+		    } else if (dy == sh) {
+			sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
+			sp += dx;
+			c00 = *sp;
+			sp += 1;
+			c01 = *sp;
+			c10 = *sp;
+			c11 = *sp;
+		    }
+		    /*
+		     * Interpolate colors 
+		     */
+		    ex = (sdx & 0xffff);
+		    ey = (sdy & 0xffff);
+		    t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
+		    t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
+		    pc->r = (((t2 - t1) * ey) >> 16) + t1;
+		    t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff;
+		    t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff;
+		    pc->g = (((t2 - t1) * ey) >> 16) + t1;
+		    t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff;
+		    t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff;
+		    pc->b = (((t2 - t1) * ey) >> 16) + t1;
+		    t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff;
+		    t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff;
+		    pc->a = (((t2 - t1) * ey) >> 16) + t1;
+		}
+		sdx += icos;
+		sdy += isin;
+		pc++;
+	    }
+	    pc = (tColorRGBA *) ((Uint8 *) pc + gap);
+	}
+    } else {
+	for (y = 0; y < dst->h; y++) {
+	    dy = cy - y;
+	    sdx = (ax + (isin * dy)) + xd;
+	    sdy = (ay - (icos * dy)) + yd;
+	    for (x = 0; x < dst->w; x++) {
+		dx = (short) (sdx >> 16);
+		dy = (short) (sdy >> 16);
+		if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
+		    sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy);
+		    sp += dx;
+		    *pc = *sp;
+		}
+		sdx += icos;
+		sdy += isin;
+		pc++;
+	    }
+	    pc = (tColorRGBA *) ((Uint8 *) pc + gap);
+	}
+    }
+}
+
+/* 
+ 
+ 8bit Rotozoomer without smoothing
+
+ Rotates and zoomes 8bit palette/Y 'src' surface to 'dst' surface.
+ 
+*/
+
+void transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos)
+{
+    int x, y, dx, dy, xd, yd, sdx, sdy, ax, ay, sw, sh;
+    tColorY *pc, *sp;
+    int gap;
+
+    /*
+     * Variable setup 
+     */
+    xd = ((src->w - dst->w) << 15);
+    yd = ((src->h - dst->h) << 15);
+    ax = (cx << 16) - (icos * cx);
+    ay = (cy << 16) - (isin * cx);
+    sw = src->w - 1;
+    sh = src->h - 1;
+    pc = (tColorY*)(dst->pixels);
+    gap = dst->pitch - dst->w;
+    /*
+     * Clear surface to colorkey 
+     */
+    memset(pc, (unsigned char) (src->format->colorkey & 0xff), dst->pitch * dst->h);
+    /*
+     * Iterate through destination surface 
+     */
+    for (y = 0; y < dst->h; y++) {
+	dy = cy - y;
+	sdx = (ax + (isin * dy)) + xd;
+	sdy = (ay - (icos * dy)) + yd;
+	for (x = 0; x < dst->w; x++) {
+	    dx = (short) (sdx >> 16);
+	    dy = (short) (sdy >> 16);
+	    if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) {
+		sp = (tColorY *) (src->pixels);
+		sp += (src->pitch * dy + dx);
+		*pc = *sp;
+	    }
+	    sdx += icos;
+	    sdy += isin;
+	    pc++;
+	}
+	pc += gap;
+    }
+}
+
+/* 
+ 
+ rotozoomSurface()
+
+ Rotates and zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
+ 'angle' is the rotation in degrees. 'zoom' a scaling factor. If 'smooth' is 1
+ then the destination 32bit surface is anti-aliased. If the surface is not 8bit
+ or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
+
+*/
+
+#define VALUE_LIMIT	0.001
+
+
+/* Local rotozoom-size function with trig result return */
+
+void rotozoomSurfaceSizeTrig(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight,
+			     double *canglezoom, double *sanglezoom)
+{
+    double x, y, cx, cy, sx, sy;
+    double radangle;
+    int dstwidthhalf, dstheighthalf;
+
+    /*
+     * Determine destination width and height by rotating a centered source box 
+     */
+    radangle = angle * (M_PI / 180.0);
+    *sanglezoom = sin(radangle);
+    *canglezoom = cos(radangle);
+    *sanglezoom *= zoom;
+    *canglezoom *= zoom;
+    x = width / 2;
+    y = height / 2;
+    cx = *canglezoom * x;
+    cy = *canglezoom * y;
+    sx = *sanglezoom * x;
+    sy = *sanglezoom * y;
+    dstwidthhalf = MAX((int)
+		       ceil(MAX(MAX(MAX(fabs(cx + sy), fabs(cx - sy)), fabs(-cx + sy)), fabs(-cx - sy))), 1);
+    dstheighthalf = MAX((int)
+			ceil(MAX(MAX(MAX(fabs(sx + cy), fabs(sx - cy)), fabs(-sx + cy)), fabs(-sx - cy))), 1);
+    *dstwidth = 2 * dstwidthhalf;
+    *dstheight = 2 * dstheighthalf;
+}
+
+
+/* Publically available rotozoom-size function */
+
+void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight)
+{
+    double dummy_sanglezoom, dummy_canglezoom;
+
+    rotozoomSurfaceSizeTrig(width, height, angle, zoom, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom);
+}
+
+
+/* Publically available rotozoom function */
+
+SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth)
+{
+    SDL_Surface *rz_src;
+    SDL_Surface *rz_dst;
+    double zoominv;
+    double sanglezoom, canglezoom, sanglezoominv, canglezoominv;
+    int dstwidthhalf, dstwidth, dstheighthalf, dstheight;
+    double x, y, cx, cy, sx, sy;
+    int is32bit;
+    int i, src_converted;
+
+    /*
+     * Sanity check 
+     */
+    if (src == NULL)
+	return (NULL);
+
+    /*
+     * Determine if source surface is 32bit or 8bit 
+     */
+    is32bit = (src->format->BitsPerPixel == 32);
+    if ((is32bit) || (src->format->BitsPerPixel == 8)) {
+	/*
+	 * Use source surface 'as is' 
+	 */
+	rz_src = src;
+	src_converted = 0;
+    } else {
+	/*
+	 * New source surface is 32bit with a defined RGBA ordering 
+	 */
+	rz_src =
+	    SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
+	SDL_BlitSurface(src, NULL, rz_src, NULL);
+	src_converted = 1;
+	is32bit = 1;
+    }
+
+    /*
+     * Sanity check zoom factor 
+     */
+    if (zoom < VALUE_LIMIT) {
+	zoom = VALUE_LIMIT;
+    }
+    zoominv = 65536.0 / (zoom * zoom);
+
+    /*
+     * Check if we have a rotozoom or just a zoom 
+     */
+    if (fabs(angle) > VALUE_LIMIT) {
+
+	/*
+	 * Angle!=0: full rotozoom 
+	 */
+	/*
+	 * ----------------------- 
+	 */
+
+	/* Determine target size */
+	rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, zoom, &dstwidth, &dstheight, &canglezoom, &sanglezoom);
+
+	/*
+	 * Calculate target factors from sin/cos and zoom 
+	 */
+	sanglezoominv = sanglezoom;
+	canglezoominv = canglezoom;
+	sanglezoominv *= zoominv;
+	canglezoominv *= zoominv;
+
+	/* Calculate half size */
+	dstwidthhalf = dstwidth / 2;
+	dstheighthalf = dstheight / 2;
+
+	/*
+	 * Alloc space to completely contain the rotated surface 
+	 */
+	rz_dst = NULL;
+	if (is32bit) {
+	    /*
+	     * Target surface is 32bit with source RGBA/ABGR ordering 
+	     */
+	    rz_dst =
+		SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
+				     rz_src->format->Rmask, rz_src->format->Gmask,
+				     rz_src->format->Bmask, rz_src->format->Amask);
+	} else {
+	    /*
+	     * Target surface is 8bit 
+	     */
+	    rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
+	}
+
+	/*
+	 * Lock source surface 
+	 */
+	SDL_LockSurface(rz_src);
+	/*
+	 * Check which kind of surface we have 
+	 */
+	if (is32bit) {
+	    /*
+	     * Call the 32bit transformation routine to do the rotation (using alpha) 
+	     */
+	    transformSurfaceRGBA(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
+				 (int) (sanglezoominv), (int) (canglezoominv), smooth);
+	    /*
+	     * Turn on source-alpha support 
+	     */
+	    SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
+	} else {
+	    /*
+	     * Copy palette and colorkey info 
+	     */
+	    for (i = 0; i < rz_src->format->palette->ncolors; i++) {
+		rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
+	    }
+	    rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
+	    /*
+	     * Call the 8bit transformation routine to do the rotation 
+	     */
+	    transformSurfaceY(rz_src, rz_dst, dstwidthhalf, dstheighthalf,
+			      (int) (sanglezoominv), (int) (canglezoominv));
+	    SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
+	}
+	/*
+	 * Unlock source surface 
+	 */
+	SDL_UnlockSurface(rz_src);
+
+    } else {
+
+	/*
+	 * Angle=0: Just a zoom 
+	 */
+	/*
+	 * -------------------- 
+	 */
+
+	/*
+	 * Calculate target size
+	 */
+	zoomSurfaceSize(rz_src->w, rz_src->h, zoom, zoom, &dstwidth, &dstheight);
+
+	/*
+	 * Alloc space to completely contain the zoomed surface 
+	 */
+	rz_dst = NULL;
+	if (is32bit) {
+	    /*
+	     * Target surface is 32bit with source RGBA/ABGR ordering 
+	     */
+	    rz_dst =
+		SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
+				     rz_src->format->Rmask, rz_src->format->Gmask,
+				     rz_src->format->Bmask, rz_src->format->Amask);
+	} else {
+	    /*
+	     * Target surface is 8bit 
+	     */
+	    rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
+	}
+
+	/*
+	 * Lock source surface 
+	 */
+	SDL_LockSurface(rz_src);
+	/*
+	 * Check which kind of surface we have 
+	 */
+	if (is32bit) {
+	    /*
+	     * Call the 32bit transformation routine to do the zooming (using alpha) 
+	     */
+	    zoomSurfaceRGBA(rz_src, rz_dst, smooth);
+	    /*
+	     * Turn on source-alpha support 
+	     */
+	    SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
+	} else {
+	    /*
+	     * Copy palette and colorkey info 
+	     */
+	    for (i = 0; i < rz_src->format->palette->ncolors; i++) {
+		rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
+	    }
+	    rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
+	    /*
+	     * Call the 8bit transformation routine to do the zooming 
+	     */
+	    zoomSurfaceY(rz_src, rz_dst);
+	    SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
+	}
+	/*
+	 * Unlock source surface 
+	 */
+	SDL_UnlockSurface(rz_src);
+    }
+
+    /*
+     * Cleanup temp surface 
+     */
+    if (src_converted) {
+	SDL_FreeSurface(rz_src);
+    }
+
+    /*
+     * Return destination surface 
+     */
+    return (rz_dst);
+}
+
+/* 
+ 
+ zoomSurface()
+
+ Zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
+ 'zoomx' and 'zoomy' are scaling factors for width and height. If 'smooth' is 1
+ then the destination 32bit surface is anti-aliased. If the surface is not 8bit
+ or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
+
+*/
+
+#define VALUE_LIMIT	0.001
+
+void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight)
+{
+    /*
+     * Sanity check zoom factors 
+     */
+    if (zoomx < VALUE_LIMIT) {
+	zoomx = VALUE_LIMIT;
+    }
+    if (zoomy < VALUE_LIMIT) {
+	zoomy = VALUE_LIMIT;
+    }
+
+    /*
+     * Calculate target size 
+     */
+    *dstwidth = (int) ((double) width * zoomx);
+    *dstheight = (int) ((double) height * zoomy);
+    if (*dstwidth < 1) {
+	*dstwidth = 1;
+    }
+    if (*dstheight < 1) {
+	*dstheight = 1;
+    }
+}
+
+SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth)
+{
+    SDL_Surface *rz_src;
+    SDL_Surface *rz_dst;
+    int dstwidth, dstheight;
+    int is32bit;
+    int i, src_converted;
+
+    /*
+     * Sanity check 
+     */
+    if (src == NULL)
+	return (NULL);
+
+    /*
+     * Determine if source surface is 32bit or 8bit 
+     */
+    is32bit = (src->format->BitsPerPixel == 32);
+    if ((is32bit) || (src->format->BitsPerPixel == 8)) {
+	/*
+	 * Use source surface 'as is' 
+	 */
+	rz_src = src;
+	src_converted = 0;
+    } else {
+	/*
+	 * New source surface is 32bit with a defined RGBA ordering 
+	 */
+	rz_src =
+	    SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
+	SDL_BlitSurface(src, NULL, rz_src, NULL);
+	src_converted = 1;
+	is32bit = 1;
+    }
+
+    /* Get size if target */
+    zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight);
+
+    /*
+     * Alloc space to completely contain the zoomed surface 
+     */
+    rz_dst = NULL;
+    if (is32bit) {
+	/*
+	 * Target surface is 32bit with source RGBA/ABGR ordering 
+	 */
+	rz_dst =
+	    SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32,
+				 rz_src->format->Rmask, rz_src->format->Gmask,
+				 rz_src->format->Bmask, rz_src->format->Amask);
+    } else {
+	/*
+	 * Target surface is 8bit 
+	 */
+	rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0);
+    }
+
+    /*
+     * Lock source surface 
+     */
+    SDL_LockSurface(rz_src);
+    /*
+     * Check which kind of surface we have 
+     */
+    if (is32bit) {
+	/*
+	 * Call the 32bit transformation routine to do the zooming (using alpha) 
+	 */
+	zoomSurfaceRGBA(rz_src, rz_dst, smooth);
+	/*
+	 * Turn on source-alpha support 
+	 */
+	SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255);
+    } else {
+	/*
+	 * Copy palette and colorkey info 
+	 */
+	for (i = 0; i < rz_src->format->palette->ncolors; i++) {
+	    rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i];
+	}
+	rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors;
+	/*
+	 * Call the 8bit transformation routine to do the zooming 
+	 */
+	zoomSurfaceY(rz_src, rz_dst);
+	SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey);
+    }
+    /*
+     * Unlock source surface 
+     */
+    SDL_UnlockSurface(rz_src);
+
+    /*
+     * Cleanup temp surface 
+     */
+    if (src_converted) {
+	SDL_FreeSurface(rz_src);
+    }
+
+    /*
+     * Return destination surface 
+     */
+    return (rz_dst);
+}
new file mode 100644
--- /dev/null
+++ b/window/SDL_rotozoom.h
@@ -0,0 +1,99 @@
+
+/*
+
+ SDL_rotozoom - rotozoomer
+
+ LGPL (c) A. Schiffler
+
+*/
+
+#ifndef _SDL_rotozoom_h
+#define _SDL_rotozoom_h
+
+#include <math.h>
+
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef M_PI
+#define M_PI	3.141592654
+#endif
+
+#include <SDL.h>
+
+/* ---- Defines */
+
+#define SMOOTHING_OFF		0
+#define SMOOTHING_ON		1
+
+/* ---- Structures */
+
+    typedef struct tColorRGBA {
+	Uint8 r;
+	Uint8 g;
+	Uint8 b;
+	Uint8 a;
+    } tColorRGBA;
+
+    typedef struct tColorY {
+	Uint8 y;
+    } tColorY;
+
+
+/* ---- Prototypes */
+
+#ifdef WIN32
+#ifdef BUILD_DLL
+#define DLLINTERFACE __declspec(dllexport)
+#else
+#define DLLINTERFACE __declspec(dllimport)
+#endif
+#else
+#define DLLINTERFACE
+#endif
+
+/* 
+ 
+ rotozoomSurface()
+
+ Rotates and zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
+ 'angle' is the rotation in degrees. 'zoom' a scaling factor. If 'smooth' is 1
+ then the destination 32bit surface is anti-aliased. If the surface is not 8bit
+ or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
+
+*/
+
+    DLLINTERFACE SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth);
+
+
+/* Returns the size of the target surface for a rotozoomSurface() call */
+
+    DLLINTERFACE void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth,
+					  int *dstheight);
+
+/* 
+ 
+ zoomSurface()
+
+ Zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
+ 'zoomx' and 'zoomy' are scaling factors for width and height. If 'smooth' is 1
+ then the destination 32bit surface is anti-aliased. If the surface is not 8bit
+ or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly.
+
+*/
+
+    DLLINTERFACE SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth);
+
+/* Returns the size of the target surface for a zoomSurface() call */
+
+    DLLINTERFACE void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight);
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+};
+#endif
+
+#endif				/* _SDL_rotozoom_h */
new file mode 100644
--- /dev/null
+++ b/window/button.cc
@@ -0,0 +1,692 @@
+/*
+ * Copyright (c) 2004-2006  Kazunori "jagarl" Ueno
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* r,g,b の基本色で number (0:left 1:right 2:up 3:down)の矢印のビットマップを作成する
+** width/heightのどちらかを-1にすると、それにあわせてスケール
+*/
+extern char* create_button(int number, int& width, int& height, int r, int g, int b);
+extern char* create_box(int& width, int& height, int r, int g, int b);
+
+// ボタンのbitmap
+// ランレングスで簡易圧縮
+static int buttonleft_cnt = 990;
+static char buttonleft[991] = {
+	0x00,0x10,0x04,0x7e,0x39,0x00,0x22,0x04,0x7f,0x59,0x00,0x1e,0x04,0x81,0x79,0x00,
+	0x1a,0x04,0x83,0x99,0x00,0x17,0x04,0x84,0xb9,0x00,0x14,0x04,0x85,0xc9,0x00,0x11,
+	0x04,0x87,0xd9,0xf8,0x04,0x88,0xe9,0xd8,0x04,0x89,0xf9,0xc8,0x04,0x89,0x01,0x10,
+	0xa8,0x04,0x10,0x02,0x7a,0x01,0x11,0x88,0xfc,0x02,0x7e,0x01,0x10,0x78,0xdc,0x02,
+	0x83,0xd9,0x68,0xdc,0x02,0x85,0xd9,0x48,0xdc,0x02,0x87,0xd9,0x38,0xcc,0x02,0x89,
+	0xc9,0x28,0xcc,0x02,0x11,0x03,0x69,0x02,0x11,0xb9,0x28,0xbc,0xea,0x03,0x70,0xea,
+	0xc9,0x18,0xbc,0xca,0x03,0x75,0xca,0xb9,0x18,0xac,0xca,0x03,0x77,0xca,0xa9,0x18,
+	0xac,0xba,0x03,0x79,0xba,0xb9,0x9c,0xba,0x03,0x7b,0xaa,0xb9,0x9c,0xaa,0x03,0x7c,
+	0xba,0xa9,0x9c,0xaa,0x03,0x7d,0xaa,0xa9,0x9c,0x9a,0x03,0x7e,0xba,0x99,0x9c,0x9a,
+	0x03,0x4e,0x39,0x03,0x2e,0xaa,0x99,0x9c,0x9a,0x03,0x4c,0x69,0x03,0x2d,0xaa,0x99,
+	0x9c,0x9a,0x03,0x49,0xb9,0x03,0x2b,0xaa,0x99,0x9c,0x8a,0x03,0x48,0xe9,0x03,0x2a,
+	0xaa,0x99,0x9c,0x8a,0x03,0x45,0x01,0x13,0x03,0x28,0xaa,0x99,0x9c,0x8a,0x03,0x43,
+	0x01,0x16,0x03,0x27,0xaa,0x99,0x9c,0x8a,0x03,0x40,0x01,0x1b,0x03,0x25,0xaa,0x99,
+	0x9c,0x8a,0x03,0x3e,0x01,0x1b,0x3a,0x03,0x24,0xaa,0x99,0x9c,0x8a,0x03,0x3b,0x01,
+	0x1b,0x8a,0x03,0x22,0xaa,0x99,0x9c,0x8a,0x03,0x39,0x01,0x1b,0x1d,0xaa,0x03,0x21,
+	0xaa,0x99,0x9c,0x8a,0x03,0x37,0x01,0x1a,0x4d,0xaa,0x03,0x21,0xaa,0x99,0x9c,0x8a,
+	0x03,0x34,0x01,0x1b,0x6d,0xaa,0x03,0x21,0xaa,0x99,0x9c,0x8a,0x03,0x32,0x01,0x1a,
+	0x9d,0xaa,0x03,0x21,0xaa,0x99,0x9c,0x8a,0x03,0x2f,0x01,0x1b,0xbd,0xaa,0x03,0x21,
+	0xaa,0x99,0x9c,0x8a,0x03,0x2d,0x01,0x1b,0xdd,0xaa,0x03,0x21,0xaa,0x99,0x9c,0x8a,
+	0x03,0x2a,0x01,0x1b,0x05,0x10,0xaa,0x03,0x21,0xaa,0x99,0x9c,0x8a,0x03,0x28,0x01,
+	0x1b,0x05,0x12,0xaa,0x03,0x21,0xaa,0x99,0x9c,0x8a,0x03,0x25,0x01,0x1b,0x05,0x15,
+	0xaa,0x03,0x21,0xaa,0x99,0x9c,0x8a,0x03,0x23,0x01,0x1b,0x05,0x17,0xaa,0x03,0x21,
+	0xaa,0x99,0x9c,0x8a,0x03,0x20,0x01,0x1b,0x05,0x1a,0xaa,0x03,0x21,0xaa,0x99,0x9c,
+	0x8a,0x03,0x1e,0x01,0x1b,0x05,0x1c,0xaa,0x03,0x21,0xaa,0x99,0x9c,0x8a,0x03,0x1c,
+	0x01,0x1a,0x05,0x1f,0xaa,0x03,0x21,0xaa,0x99,0x9c,0x8a,0x03,0x19,0x01,0x1b,0x05,
+	0x21,0xaa,0x03,0x21,0xaa,0x99,0x9c,0x8a,0x03,0x17,0x01,0x1a,0x05,0x24,0xaa,0x03,
+	0x21,0xaa,0x99,0x9c,0x8a,0x03,0x14,0x01,0x1b,0x05,0x26,0xaa,0x03,0x21,0xaa,0x99,
+	0x9c,0x8a,0x03,0x12,0x01,0x1b,0x05,0x28,0xaa,0x03,0x21,0xaa,0x99,0x9c,0x8a,0xfb,
+	0x01,0x1b,0x05,0x2b,0xaa,0x03,0x21,0xaa,0x99,0x9c,0x8a,0xdb,0x01,0x1b,0x05,0x2d,
+	0xaa,0x03,0x21,0xaa,0x99,0x9c,0x8a,0xcb,0x01,0x19,0x05,0x30,0xaa,0x03,0x21,0xaa,
+	0x99,0x9c,0x8a,0xcb,0x01,0x17,0x05,0x32,0xaa,0x03,0x21,0xaa,0x99,0x9c,0x8a,0xcb,
+	0x01,0x14,0x4a,0x05,0x31,0xaa,0x03,0x21,0xaa,0x99,0x9c,0x8a,0xcb,0x01,0x12,0x9a,
+	0x05,0x2e,0xaa,0x03,0x21,0xaa,0x99,0x9c,0x8a,0xcb,0xf9,0xea,0x05,0x2c,0xaa,0x03,
+	0x21,0xaa,0x99,0x9c,0x8a,0xfb,0xa9,0x02,0x13,0x05,0x29,0xaa,0x03,0x21,0xaa,0x99,
+	0x9c,0x8a,0x03,0x12,0x69,0x02,0x16,0x05,0x27,0xaa,0x03,0x21,0xaa,0x99,0x9c,0x8a,
+	0x03,0x16,0x19,0x02,0x19,0x05,0x25,0xaa,0x03,0x21,0xaa,0x99,0x9c,0x8a,0x03,0x18,
+	0x02,0x1b,0x05,0x22,0xaa,0x03,0x21,0xaa,0x99,0x9c,0x8a,0x03,0x1b,0x02,0x1a,0x05,
+	0x20,0xaa,0x03,0x21,0xaa,0x99,0x9c,0x8a,0x03,0x1d,0x02,0x1b,0x05,0x1d,0xaa,0x03,
+	0x21,0xaa,0x99,0x9c,0x8a,0x03,0x20,0x02,0x1a,0x05,0x1b,0xaa,0x03,0x21,0xaa,0x99,
+	0x9c,0x8a,0x03,0x22,0x02,0x1a,0x05,0x19,0xaa,0x03,0x21,0xaa,0x99,0x9c,0x8a,0x03,
+	0x24,0x02,0x1b,0x05,0x16,0xaa,0x03,0x21,0xaa,0x99,0x9c,0x8a,0x03,0x27,0x02,0x1a,
+	0x05,0x14,0xaa,0x03,0x21,0xaa,0x99,0x9c,0x8a,0x03,0x29,0x02,0x1b,0x05,0x11,0xaa,
+	0x03,0x21,0xaa,0x99,0x9c,0x8a,0x03,0x2c,0x02,0x1a,0xfd,0xaa,0x03,0x21,0xaa,0x99,
+	0x9c,0x8a,0x03,0x2e,0x02,0x1b,0xcd,0xaa,0x03,0x21,0xaa,0x99,0x9c,0x8a,0x03,0x31,
+	0x02,0x1a,0xad,0xaa,0x03,0x21,0xaa,0x99,0x9c,0x8a,0x03,0x33,0x02,0x1a,0x8d,0xaa,
+	0x03,0x21,0xaa,0x99,0x9c,0x8a,0x03,0x35,0x02,0x1b,0x5d,0xaa,0x03,0x21,0xaa,0x99,
+	0x9c,0x8a,0x03,0x38,0x02,0x1a,0x3d,0xaa,0x03,0x21,0xaa,0x99,0x9c,0x8a,0x03,0x3a,
+	0x02,0x25,0x03,0x21,0xaa,0x99,0x9c,0x8a,0x03,0x3d,0x02,0x22,0x03,0x21,0xaa,0x99,
+	0x9c,0x8a,0x03,0x3f,0x02,0x20,0x03,0x21,0xaa,0x99,0x9c,0x8a,0x03,0x41,0x02,0x1e,
+	0x03,0x21,0xaa,0x99,0x9c,0x8a,0x03,0x44,0x02,0x1b,0x03,0x21,0xaa,0x99,0x9c,0x8a,
+	0x03,0x46,0x02,0x19,0x03,0x21,0xaa,0x99,0x9c,0x9a,0x03,0x48,0x02,0x16,0x03,0x21,
+	0xaa,0x99,0x9c,0x9a,0x03,0x4a,0x02,0x14,0x03,0x21,0xaa,0x99,0x9c,0x9a,0x03,0x4d,
+	0x02,0x10,0x03,0x22,0xaa,0x99,0x9c,0x9a,0x03,0x4f,0xca,0x03,0x24,0xaa,0x99,0x9c,
+	0x9a,0x03,0x51,0x8a,0x03,0x25,0xba,0x99,0x9c,0xaa,0x03,0x53,0x3a,0x03,0x27,0xaa,
+	0xa9,0x9c,0xaa,0x03,0x7c,0xba,0xa9,0x9c,0xba,0x03,0x7b,0xba,0xa9,0x9c,0xca,0x03,
+	0x79,0xba,0xb9,0xac,0xca,0x03,0x77,0xca,0xb9,0xbc,0xda,0x03,0x73,0xea,0xa9,0x28,
+	0xac,0x02,0x10,0x03,0x6d,0x02,0x10,0xb9,0x28,0xac,0x02,0x8c,0xb9,0x38,0xbc,0x02,
+	0x8a,0xc9,0x38,0xcc,0x02,0x89,0xc9,0x48,0xcc,0x02,0x86,0xd9,0x58,0xdc,0x02,0x84,
+	0xe9,0x68,0xdc,0x02,0x82,0xe9,0x78,0xfc,0x02,0x7d,0x01,0x10,0x98,0x04,0x10,0x02,
+	0x78,0x01,0x12,0xb8,0xfc,0x01,0x8a,0xb8,0xfc,0x01,0x89,0xd8,0xec,0x01,0x88,0xf8,
+	0xdc,0x01,0x86,0x00,0x13,0xbc,0x01,0x85,0x00,0x15,0xac,0x01,0x84,0x00,0x17,0x9c,
+	0x01,0x82,0x00,0x1b,0x7c,0x01,0x7f,0x00,0x1f,0x6c,0x01,0x7d,0x00,0x13,
+	0xff};
+static int buttonright_cnt = 978;
+static char buttonright[979] = {
+	0x00,0x13,0x04,0x81,0x00,0x21,0x04,0x84,0x00,0x1e,0x04,0x88,0x00,0x19,0x04,0x8c,
+	0x00,0x17,0x04,0x8f,0x00,0x14,0x04,0x91,0x00,0x11,0x04,0x94,0xf8,0x04,0x96,0xd8,
+	0x04,0x98,0xb8,0x04,0x9a,0xa8,0x04,0x11,0x02,0x7a,0x04,0x10,0x88,0xfc,0x02,0x7f,
+	0xfc,0x68,0xec,0x02,0x83,0xdc,0x68,0xdc,0x02,0x85,0xdc,0x48,0xdc,0x02,0x87,0xcc,
+	0x48,0xcc,0x02,0x89,0xcc,0x28,0xcc,0x02,0x11,0x03,0x11,0x02,0x11,0x03,0x47,0x02,
+	0x11,0xbc,0x28,0xbc,0xea,0x03,0x71,0xea,0xbc,0x18,0xbc,0xca,0x03,0x75,0xca,0x04,
+	0x16,0xca,0x03,0x77,0xca,0x04,0x15,0xba,0x03,0x79,0xba,0x04,0x14,0xba,0x03,0x7b,
+	0xba,0x99,0xac,0xaa,0x03,0x7d,0xaa,0x99,0xac,0xaa,0x03,0x7d,0xaa,0x99,0x9c,0xaa,
+	0x03,0x7f,0x9a,0x99,0x9c,0xaa,0x03,0x7f,0x9a,0x99,0x9c,0xaa,0x03,0x2c,0x4a,0x03,
+	0x4f,0x9a,0x99,0x9c,0xaa,0x03,0x2b,0x8a,0x03,0x4c,0x9a,0x99,0x9c,0x9a,0x03,0x2a,
+	0x29,0xba,0x03,0x4a,0x8a,0x99,0x9c,0x9a,0x03,0x29,0x39,0xda,0x03,0x48,0x8a,0x99,
+	0x9c,0x9a,0x03,0x27,0x59,0x02,0x10,0x03,0x45,0x8a,0x99,0x9c,0x9a,0x03,0x26,0x69,
+	0x02,0x12,0x03,0x43,0x8a,0x99,0x9c,0x9a,0x03,0x24,0x89,0x02,0x15,0x03,0x40,0x8a,
+	0x99,0x9c,0x9a,0x03,0x23,0x99,0x02,0x17,0x03,0x3e,0x8a,0x99,0x9c,0x9a,0x03,0x23,
+	0x99,0x02,0x1a,0x03,0x3b,0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,0x1d,0x02,0x1b,0x03,
+	0x39,0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,0x3d,0x02,0x1c,0x03,0x36,0x8a,0x99,0x9c,
+	0x9a,0x03,0x23,0x99,0x6d,0x02,0x1c,0x03,0x33,0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,
+	0x8d,0x02,0x1c,0x03,0x31,0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,0xbd,0x02,0x1c,0x03,
+	0x2e,0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,0xed,0x02,0x1b,0x03,0x2c,0x8a,0x99,0x9c,
+	0x9a,0x03,0x23,0x99,0x05,0x10,0x02,0x1c,0x03,0x29,0x8a,0x99,0x9c,0x9a,0x03,0x23,
+	0x99,0x05,0x13,0x02,0x1b,0x03,0x27,0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,0x05,0x15,
+	0x02,0x1c,0x03,0x24,0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,0x05,0x18,0x02,0x1b,0x03,
+	0x22,0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,0x05,0x1a,0x02,0x1c,0x03,0x1f,0x8a,0x99,
+	0x9c,0x9a,0x03,0x23,0x99,0x05,0x1d,0x02,0x1c,0x03,0x1c,0x8a,0x99,0x9c,0x9a,0x03,
+	0x23,0x99,0x05,0x1f,0x02,0x1c,0x03,0x1a,0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,0x05,
+	0x22,0x02,0x1c,0x03,0x17,0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,0x05,0x25,0x02,0x1a,
+	0x03,0x16,0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,0x05,0x27,0x02,0x18,0x03,0x16,0x8a,
+	0x99,0x9c,0x9a,0x03,0x23,0x99,0x05,0x2a,0x02,0x15,0x03,0x16,0x8a,0x99,0x9c,0x9a,
+	0x03,0x23,0x99,0x05,0x2c,0x02,0x13,0x03,0x16,0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,
+	0x05,0x2f,0x02,0x10,0x03,0x16,0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,0x05,0x31,0xea,
+	0x03,0x16,0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,0x05,0x30,0xfa,0x03,0x16,0x8a,0x99,
+	0x9c,0x9a,0x03,0x23,0x99,0x05,0x2e,0x02,0x11,0x03,0x16,0x8a,0x99,0x9c,0x9a,0x03,
+	0x23,0x99,0x05,0x2b,0x02,0x14,0x03,0x16,0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,0x05,
+	0x29,0x02,0x16,0x03,0x16,0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,0x05,0x27,0x02,0x17,
+	0x03,0x17,0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,0x05,0x24,0x02,0x1a,0x03,0x17,0x8a,
+	0x99,0x9c,0x9a,0x03,0x23,0x99,0x05,0x22,0x02,0x1a,0x03,0x19,0x8a,0x99,0x9c,0x9a,
+	0x03,0x23,0x99,0x05,0x1f,0x02,0x1b,0x03,0x1b,0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,
+	0x05,0x1d,0x02,0x1a,0x03,0x1e,0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,0x05,0x1b,0x02,
+	0x1a,0x03,0x20,0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,0x05,0x18,0x02,0x1b,0x03,0x22,
+	0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,0x05,0x16,0x02,0x1a,0x03,0x25,0x8a,0x99,0x9c,
+	0x9a,0x03,0x23,0x99,0x05,0x13,0x02,0x1b,0x03,0x27,0x8a,0x99,0x9c,0x9a,0x03,0x23,
+	0x99,0x05,0x11,0x02,0x1a,0x03,0x2a,0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,0xed,0x02,
+	0x1b,0x03,0x2c,0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,0xcd,0x02,0x1a,0x03,0x2f,0x8a,
+	0x99,0x9c,0x9a,0x03,0x23,0x99,0xad,0x02,0x1a,0x03,0x31,0x8a,0x99,0x9c,0x9a,0x03,
+	0x23,0x99,0x7d,0x02,0x1b,0x03,0x33,0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,0x5d,0x02,
+	0x1a,0x03,0x36,0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,0x2d,0x02,0x1b,0x03,0x38,0x8a,
+	0x99,0x9c,0x9a,0x03,0x23,0x99,0x02,0x1a,0x03,0x3b,0x8a,0x99,0x9c,0x9a,0x03,0x23,
+	0x99,0x02,0x18,0x03,0x3d,0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,0x02,0x16,0x03,0x3f,
+	0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,0x02,0x13,0x03,0x42,0x8a,0x99,0x9c,0x9a,0x03,
+	0x23,0x99,0x02,0x11,0x03,0x44,0x8a,0x99,0x9c,0x9a,0x03,0x23,0x99,0xea,0x03,0x47,
+	0x8a,0x99,0x9c,0xaa,0x03,0x22,0x99,0xca,0x03,0x48,0x9a,0x99,0x9c,0xaa,0x03,0x22,
+	0x99,0x9a,0x03,0x4b,0x9a,0x99,0x9c,0xaa,0x03,0x22,0x99,0x7a,0x03,0x4d,0x9a,0x99,
+	0x9c,0xaa,0x03,0x24,0x79,0x5a,0x03,0x4f,0x9a,0x99,0x9c,0xaa,0x03,0x26,0x59,0x2a,
+	0x03,0x51,0xaa,0x01,0x13,0xaa,0x03,0x27,0x39,0x03,0x53,0xaa,0x01,0x13,0xaa,0x03,
+	0x7c,0xba,0x01,0x13,0xba,0x03,0x7b,0xba,0x01,0x14,0xba,0x03,0x79,0xca,0x01,0x14,
+	0xca,0x03,0x77,0xba,0xb9,0x18,0xa9,0xea,0x03,0x73,0xda,0xb9,0x18,0xb9,0x02,0x10,
+	0x03,0x6d,0x02,0x10,0xa9,0x28,0xc9,0x02,0x8b,0xb9,0x38,0xb9,0x02,0x8b,0xb9,0x38,
+	0xc9,0x02,0x89,0xb9,0x48,0xe9,0x02,0x86,0xc9,0x58,0xe9,0x02,0x84,0xd9,0x68,0xe9,
+	0x02,0x82,0xd9,0x88,0x01,0x10,0x02,0x7d,0xe9,0x98,0x01,0x13,0x02,0x78,0x01,0x10,
+	0xa8,0x01,0x99,0xc8,0x01,0x97,0xe8,0x01,0x95,0x00,0x10,0x01,0x93,0x00,0x13,0x01,
+	0x90,0x00,0x15,0x01,0x8e,0x00,0x18,0x01,0x8a,0x00,0x1d,0x01,0x86,0x00,0x20,0x01,
+	0x83,0xe8,
+	0xff};
+static int buttonup_cnt = 1288;
+static char buttonup[1289] = {
+	0x00,0x10,0x04,0x4c,0x00,0x20,0x04,0x52,0x00,0x1a,0x04,0x56,0x00,0x17,0x04,0x59,
+	0x00,0x14,0x04,0x5b,0x00,0x12,0x04,0x5e,0xe8,0x04,0x61,0xd8,0x04,0x62,0xb8,0x04,
+	0x64,0x98,0x04,0x10,0x02,0x45,0x04,0x10,0x88,0xfc,0x02,0x48,0x04,0x10,0x78,0xdc,
+	0x02,0x4c,0xfc,0x58,0xdc,0x02,0x4f,0xdc,0x48,0xdc,0x02,0x51,0xdc,0x38,0xcc,0x02,
+	0x53,0xcc,0x38,0xbc,0x02,0x55,0x04,0x18,0x02,0x57,0x04,0x17,0x02,0x10,0x03,0x35,
+	0x02,0x12,0x04,0x16,0xda,0x03,0x3e,0xea,0x04,0x15,0xba,0x03,0x42,0xca,0x04,0x14,
+	0xba,0x03,0x44,0xca,0x99,0xac,0xaa,0x03,0x46,0xba,0x99,0xac,0x9a,0x03,0x48,0xaa,
+	0x99,0xac,0x8a,0x03,0x49,0xaa,0x99,0xac,0x8a,0x03,0x4a,0x9a,0x99,0xac,0x8a,0x03,
+	0x4a,0x9a,0x99,0xac,0x7a,0x03,0x4c,0x8a,0x99,0xac,0x7a,0x03,0x4c,0x8a,0x99,0xac,
+	0x7a,0x03,0x4c,0x8a,0x99,0xac,0x6a,0x03,0x25,0x59,0x03,0x23,0x8a,0x99,0xac,0x6a,
+	0x03,0x24,0x69,0x03,0x23,0x8a,0x99,0xac,0x6a,0x03,0x24,0x69,0x03,0x23,0x8a,0x99,
+	0xac,0x6a,0x03,0x23,0x89,0x03,0x22,0x8a,0x99,0xac,0x6a,0x03,0x23,0x89,0x03,0x22,
+	0x8a,0x99,0xac,0x6a,0x03,0x23,0x89,0x03,0x22,0x8a,0x99,0xac,0x6a,0x03,0x22,0xa9,
+	0x03,0x21,0x8a,0x99,0xac,0x6a,0x03,0x22,0xa9,0x03,0x21,0x8a,0x99,0xac,0x6a,0x03,
+	0x21,0xb9,0x03,0x21,0x8a,0x99,0xac,0x6a,0x03,0x21,0xb9,0x03,0x21,0x8a,0x99,0xac,
+	0x6a,0x03,0x21,0xc9,0x03,0x20,0x8a,0x99,0xac,0x6a,0x03,0x20,0xd9,0x03,0x20,0x8a,
+	0x99,0xac,0x6a,0x03,0x20,0xb9,0x3a,0x03,0x1f,0x8a,0x99,0xac,0x6a,0x03,0x1f,0xb9,
+	0x4a,0x03,0x1f,0x8a,0x99,0xac,0x6a,0x03,0x1f,0xb9,0x4a,0x03,0x1f,0x8a,0x99,0xac,
+	0x6a,0x03,0x1f,0xa9,0x6a,0x03,0x1e,0x8a,0x99,0xac,0x6a,0x03,0x1e,0xb9,0x6a,0x03,
+	0x1e,0x8a,0x99,0xac,0x6a,0x03,0x1e,0xb9,0x7a,0x03,0x1d,0x8a,0x99,0xac,0x6a,0x03,
+	0x1d,0xb9,0x8a,0x03,0x1d,0x8a,0x99,0xac,0x6a,0x03,0x1d,0xb9,0x8a,0x03,0x1d,0x8a,
+	0x99,0xac,0x6a,0x03,0x1d,0xa9,0xaa,0x03,0x1c,0x8a,0x99,0xac,0x6a,0x03,0x1c,0xb9,
+	0xaa,0x03,0x1c,0x8a,0x99,0xac,0x6a,0x03,0x1c,0xb9,0xba,0x03,0x1b,0x8a,0x99,0xac,
+	0x6a,0x03,0x1b,0xb9,0x1d,0xba,0x03,0x1b,0x8a,0x99,0xac,0x6a,0x03,0x1b,0xb9,0x2d,
+	0xba,0x03,0x1a,0x8a,0x99,0xac,0x6a,0x03,0x1b,0xa9,0x3d,0xba,0x03,0x1a,0x8a,0x99,
+	0xac,0x6a,0x03,0x1a,0xb9,0x3d,0xba,0x03,0x1a,0x8a,0x99,0xac,0x6a,0x03,0x1a,0xb9,
+	0x4d,0xba,0x03,0x19,0x8a,0x99,0xac,0x6a,0x03,0x19,0xb9,0x5d,0xba,0x03,0x19,0x8a,
+	0x99,0xac,0x6a,0x03,0x19,0xb9,0x6d,0xba,0x03,0x18,0x8a,0x99,0xac,0x6a,0x03,0x18,
+	0xb9,0x7d,0xba,0x03,0x18,0x8a,0x99,0xac,0x6a,0x03,0x18,0xb9,0x7d,0xba,0x03,0x18,
+	0x8a,0x99,0xac,0x6a,0x03,0x18,0xb9,0x8d,0xba,0x03,0x17,0x8a,0x99,0xac,0x6a,0x03,
+	0x17,0xb9,0x9d,0xba,0x03,0x17,0x8a,0x99,0xac,0x6a,0x03,0x17,0xb9,0xad,0xba,0x03,
+	0x16,0x8a,0x99,0xac,0x6a,0x03,0x16,0xb9,0xbd,0xba,0x03,0x16,0x8a,0x99,0xac,0x6a,
+	0x03,0x16,0xb9,0xcd,0xaa,0x03,0x16,0x8a,0x99,0xac,0x6a,0x03,0x16,0xb9,0xcd,0xba,
+	0x03,0x15,0x8a,0x99,0xac,0x6a,0x03,0x15,0xb9,0xdd,0xba,0x03,0x15,0x8a,0x99,0xac,
+	0x6a,0x03,0x15,0xb9,0xed,0xba,0x03,0x14,0x8a,0x99,0xac,0x6a,0x03,0x14,0xb9,0xfd,
+	0xba,0x03,0x14,0x8a,0x99,0xac,0x6a,0x03,0x14,0xb9,0x05,0x10,0xba,0x03,0x13,0x8a,
+	0x99,0xac,0x6a,0x03,0x14,0xa9,0x05,0x11,0xba,0x03,0x13,0x8a,0x99,0xac,0x6a,0x03,
+	0x13,0xb9,0x05,0x11,0xba,0x03,0x13,0x8a,0x99,0xac,0x6a,0x03,0x13,0xb9,0x05,0x12,
+	0xba,0x03,0x12,0x8a,0x99,0xac,0x6a,0x03,0x12,0xb9,0x05,0x13,0xba,0x03,0x12,0x8a,
+	0x99,0xac,0x6a,0x03,0x12,0xb9,0x05,0x14,0xba,0x03,0x11,0x8a,0x99,0xac,0x6a,0x03,
+	0x12,0xa9,0x05,0x15,0xba,0x03,0x11,0x8a,0x99,0xac,0x6a,0x03,0x11,0xb9,0x05,0x16,
+	0xaa,0x03,0x11,0x8a,0x99,0xac,0x6a,0x03,0x11,0xb9,0x05,0x16,0xba,0x03,0x10,0x8a,
+	0x99,0xac,0x6a,0x03,0x10,0xb9,0x05,0x17,0xba,0x03,0x10,0x8a,0x99,0xac,0x6a,0x03,
+	0x10,0xb9,0x05,0x18,0xba,0xfb,0x8a,0x99,0xac,0x6a,0xfb,0xb9,0x05,0x19,0xba,0xfb,
+	0x8a,0x99,0xac,0x6a,0xfb,0xb9,0x05,0x1a,0xba,0xeb,0x8a,0x99,0xac,0x6a,0xfb,0xb9,
+	0x05,0x1a,0xba,0xeb,0x8a,0x99,0xac,0x6a,0xeb,0xb9,0x05,0x1b,0xba,0xeb,0x8a,0x99,
+	0xac,0x6a,0xeb,0xb9,0x05,0x1c,0xba,0xdb,0x8a,0x99,0xac,0x6a,0xdb,0xb9,0x05,0x1d,
+	0xba,0xdb,0x8a,0x99,0xac,0x6a,0xdb,0xb9,0x05,0x1e,0xba,0xcb,0x8a,0x99,0xac,0x6a,
+	0xdb,0xb9,0x05,0x1e,0xba,0xcb,0x8a,0x99,0xac,0x6a,0xcb,0xb9,0x05,0x1f,0xba,0xcb,
+	0x8a,0x99,0xac,0x6a,0xcb,0xb9,0x05,0x20,0xba,0xbb,0x8a,0x99,0xac,0x6a,0xbb,0xb9,
+	0x05,0x21,0xba,0xbb,0x8a,0x99,0xac,0x6a,0xbb,0xb9,0x05,0x22,0xba,0xab,0x8a,0x99,
+	0xac,0x6a,0xbb,0xb9,0x05,0x22,0xba,0xab,0x8a,0x99,0xac,0x6a,0xab,0xb9,0x05,0x24,
+	0xaa,0xab,0x8a,0x99,0xac,0x6a,0xab,0xb9,0x05,0x24,0xba,0x9b,0x8a,0x99,0xac,0x6a,
+	0x9b,0xb9,0x05,0x25,0xba,0x9b,0x8a,0x99,0xac,0x6a,0x9b,0xb9,0x05,0x26,0xba,0x8b,
+	0x8a,0x99,0xac,0x6a,0x9b,0xa9,0x05,0x27,0xba,0x8b,0x8a,0x99,0xac,0x6a,0xab,0x99,
+	0x05,0x28,0xba,0x7b,0x8a,0x99,0xac,0x6a,0xab,0x99,0x05,0x28,0xba,0x7b,0x8a,0x99,
+	0xac,0x6a,0xbb,0x79,0x05,0x29,0xba,0x7b,0x8a,0x99,0xac,0x6a,0xcb,0x69,0x02,0x35,
+	0x6b,0x8a,0x99,0xac,0x6a,0xcb,0x59,0x02,0x36,0x6b,0x8a,0x99,0xac,0x6a,0xdb,0x49,
+	0x02,0x36,0x6b,0x8a,0x99,0xac,0x6a,0xeb,0x39,0x02,0x35,0x7b,0x8a,0x99,0xac,0x6a,
+	0xeb,0x29,0x02,0x36,0x7b,0x8a,0x99,0xac,0x6a,0xfb,0x19,0x02,0x35,0x8b,0x8a,0x99,
+	0xac,0x6a,0x03,0x10,0x02,0x35,0x8b,0x8a,0x99,0xac,0x6a,0x03,0x10,0x02,0x34,0x9b,
+	0x8a,0x99,0xac,0x6a,0x03,0x11,0x02,0x33,0x9b,0x8a,0x99,0xac,0x6a,0x03,0x12,0x02,
+	0x31,0xab,0x8a,0x99,0xac,0x6a,0x03,0x4d,0x8a,0x99,0xac,0x6a,0x03,0x4d,0x8a,0x99,
+	0xac,0x6a,0x03,0x4d,0x8a,0x99,0xac,0x6a,0x03,0x4d,0x8a,0x99,0xac,0x6a,0x03,0x4d,
+	0x8a,0x99,0xac,0x6a,0x03,0x4d,0x8a,0x99,0xac,0x6a,0x03,0x4d,0x8a,0x99,0xac,0x6a,
+	0x03,0x4d,0x8a,0x99,0xac,0x6a,0x03,0x4d,0x8a,0x99,0xac,0x6a,0x03,0x4d,0x8a,0x99,
+	0xac,0x6a,0x03,0x4d,0x8a,0x99,0xac,0x6a,0x03,0x4d,0x8a,0x99,0xac,0x6a,0x03,0x4d,
+	0x8a,0x99,0xac,0x6a,0x03,0x4d,0x8a,0x99,0xac,0x6a,0x03,0x4d,0x8a,0x99,0xac,0x6a,
+	0x03,0x4d,0x8a,0x99,0xac,0x6a,0x03,0x4d,0x8a,0x99,0xac,0x6a,0x03,0x4d,0x8a,0x99,
+	0xac,0x6a,0x03,0x4d,0x8a,0x99,0xac,0x6a,0x03,0x4d,0x8a,0x99,0xac,0x6a,0x03,0x4d,
+	0x8a,0x99,0xac,0x6a,0x03,0x4d,0x8a,0x99,0xac,0x7a,0x03,0x4c,0x8a,0x99,0xac,0x7a,
+	0x03,0x4c,0x8a,0x99,0xac,0x7a,0x03,0x4b,0x9a,0x99,0xac,0x8a,0x03,0x4a,0x9a,0x99,
+	0xac,0x8a,0x03,0x4a,0x9a,0x99,0xac,0x8a,0x03,0x49,0xaa,0x99,0xac,0x9a,0x03,0x48,
+	0x9a,0xa9,0xac,0xaa,0x03,0x46,0xaa,0x01,0x15,0xaa,0x03,0x44,0xba,0x01,0x15,0xba,
+	0x03,0x41,0xca,0x01,0x17,0xda,0x03,0x3c,0xea,0xb9,0x18,0xb9,0x02,0x10,0x03,0x35,
+	0x02,0x12,0xa9,0x28,0xb9,0x02,0x56,0xb9,0x38,0xb9,0x02,0x54,0xc9,0x38,0xc9,0x02,
+	0x52,0xc9,0x58,0xc9,0x02,0x51,0xc9,0x58,0xd9,0x02,0x4e,0xd9,0x78,0xe9,0x02,0x4b,
+	0xe9,0x78,0xf9,0x02,0x49,0xe9,0x98,0x01,0x11,0x02,0x43,0x01,0x10,0xb8,0x01,0x12,
+	0x02,0x3e,0x01,0x13,0xc8,0x01,0x61,0xe8,0x01,0x5f,0x00,0x10,0x01,0x5d,0x00,0x12,
+	0x01,0x5b,0x00,0x14,0x01,0x58,0x00,0x18,0x01,0x55,0x00,0x1b,0x01,0x51,0x00,0x1f,
+	0x01,0x4d,0x00,0x22,0x01,0x49,0x00,0x13,
+	0xff};
+static int buttondown_cnt = 1445;
+static char buttondown[1446] = {
+	0x1e,0x00,0x12,0x04,0x45,0x59,0x00,0x11,0x1e,0xf8,0x04,0x48,0x89,0xe8,0x1e,0xd8,
+	0x04,0x4a,0xa9,0xc8,0x1e,0xb8,0x04,0x4c,0xb9,0xb8,0x1e,0xa8,0x04,0x4d,0xc9,0xa8,
+	0x1e,0x88,0x04,0x4f,0xe9,0x88,0x1e,0x78,0x04,0x50,0xf9,0x78,0x1e,0x68,0x04,0x51,
+	0x01,0x10,0x68,0x1e,0x68,0x04,0x51,0x01,0x11,0x58,0x1e,0x58,0x04,0x12,0x02,0x40,
+	0x01,0x11,0x58,0x1e,0x48,0x04,0x10,0x02,0x46,0xf9,0x48,0x1e,0x38,0xec,0x02,0x4b,
+	0xe9,0x38,0x1e,0x38,0xdc,0x02,0x4d,0xd9,0x38,0x1e,0x28,0xdc,0x02,0x4f,0xd9,0x28,
+	0x1e,0x28,0xcc,0x02,0x51,0xc9,0x28,0x1e,0x18,0xcc,0x02,0x53,0xc9,0x18,0x1e,0x18,
+	0xbc,0x02,0x55,0xb9,0x18,0x1e,0x18,0xbc,0x02,0x56,0xa9,0x18,0x1e,0x18,0xac,0xfa,
+	0x03,0x39,0xfa,0xb9,0x1e,0xbc,0xca,0x03,0x3f,0xca,0xb9,0x1e,0xac,0xba,0x03,0x42,
+	0xca,0xa9,0x1e,0xac,0xaa,0x03,0x45,0xaa,0xa9,0x1e,0x9c,0xaa,0x03,0x47,0x9a,0xa9,
+	0x1e,0x9c,0x9a,0x03,0x48,0xaa,0x99,0x1e,0x9c,0x9a,0x03,0x49,0x9a,0x99,0x1e,0x9c,
+	0x8a,0x03,0x4a,0x9a,0x99,0x1e,0x9c,0x8a,0x03,0x4b,0x8a,0x99,0x1e,0x9c,0x8a,0x03,
+	0x4b,0x8a,0x99,0x1e,0x9c,0x7a,0x03,0x4c,0x8a,0x99,0x1e,0x9c,0x7a,0x03,0x4c,0x8a,
+	0x99,0x1e,0x9c,0x7a,0x03,0x4d,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x4d,0x7a,0x99,0x1e,
+	0x9c,0x7a,0x03,0x4d,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x4d,0x7a,0x99,0x1e,0x9c,0x7a,
+	0x03,0x4d,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x4d,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x4d,
+	0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x4d,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x4d,0x7a,0x99,
+	0x1e,0x9c,0x7a,0x03,0x4d,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x4d,0x7a,0x99,0x1e,0x9c,
+	0x7a,0x03,0x4d,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x4d,0x7a,0x99,0x1e,0x9c,0x7a,0x03,
+	0x4d,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x4d,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x4d,0x7a,
+	0x99,0x1e,0x9c,0x7a,0x03,0x4d,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x4d,0x7a,0x99,0x1e,
+	0x9c,0x7a,0x03,0x4d,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x4d,0x7a,0x99,0x1e,0x9c,0x7a,
+	0x03,0x4d,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x4d,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x11,
+	0x01,0x32,0xab,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x10,0x01,0x33,0xab,0x7a,0x99,0x1e,
+	0x9c,0x7a,0xfb,0x01,0x35,0x9b,0x7a,0x99,0x1e,0x9c,0x7a,0xfb,0x01,0x35,0x9b,0x7a,
+	0x99,0x1e,0x9c,0x7a,0xeb,0x01,0x37,0x8b,0x7a,0x99,0x1e,0x9c,0x7a,0xdb,0x01,0x38,
+	0x8b,0x7a,0x99,0x1e,0x9c,0x7a,0xdb,0x01,0x39,0x7b,0x7a,0x99,0x1e,0x9c,0x7a,0xcb,
+	0x01,0x3a,0x7b,0x7a,0x99,0x1e,0x9c,0x7a,0xbb,0x01,0x3b,0x7b,0x7a,0x99,0x1e,0x9c,
+	0x7a,0xbb,0x89,0x05,0x28,0xba,0x7b,0x7a,0x99,0x1e,0x9c,0x7a,0xab,0x99,0x05,0x28,
+	0xaa,0x8b,0x7a,0x99,0x1e,0x9c,0x7a,0x9b,0xa9,0x05,0x27,0xba,0x8b,0x7a,0x99,0x1e,
+	0x9c,0x7a,0x9b,0xb9,0x05,0x26,0xba,0x8b,0x7a,0x99,0x1e,0x9c,0x7a,0x9b,0xb9,0x05,
+	0x25,0xba,0x9b,0x7a,0x99,0x1e,0x9c,0x7a,0x9b,0xc9,0x05,0x24,0xba,0x9b,0x7a,0x99,
+	0x1e,0x9c,0x7a,0xab,0xb9,0x05,0x23,0xba,0xab,0x7a,0x99,0x1e,0x9c,0x7a,0xab,0xb9,
+	0x05,0x23,0xba,0xab,0x7a,0x99,0x1e,0x9c,0x7a,0xbb,0xb9,0x05,0x22,0xba,0xab,0x7a,
+	0x99,0x1e,0x9c,0x7a,0xbb,0xb9,0x05,0x21,0xba,0xbb,0x7a,0x99,0x1e,0x9c,0x7a,0xcb,
+	0xa9,0x05,0x21,0xba,0xbb,0x7a,0x99,0x1e,0x9c,0x7a,0xcb,0xb9,0x05,0x1f,0xba,0xcb,
+	0x7a,0x99,0x1e,0x9c,0x7a,0xcb,0xb9,0x05,0x1f,0xba,0xcb,0x7a,0x99,0x1e,0x9c,0x7a,
+	0xdb,0xb9,0x05,0x1e,0xba,0xcb,0x7a,0x99,0x1e,0x9c,0x7a,0xdb,0xb9,0x05,0x1d,0xba,
+	0xdb,0x7a,0x99,0x1e,0x9c,0x7a,0xeb,0xa9,0x05,0x1d,0xba,0xdb,0x7a,0x99,0x1e,0x9c,
+	0x7a,0xeb,0xb9,0x05,0x1b,0xba,0xeb,0x7a,0x99,0x1e,0x9c,0x7a,0xeb,0xb9,0x05,0x1b,
+	0xba,0xeb,0x7a,0x99,0x1e,0x9c,0x7a,0xfb,0xb9,0x05,0x1a,0xaa,0xfb,0x7a,0x99,0x1e,
+	0x9c,0x7a,0xfb,0xb9,0x05,0x19,0xba,0xfb,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x10,0xa9,
+	0x05,0x19,0xba,0xfb,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x10,0xb9,0x05,0x17,0xba,0x03,
+	0x10,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x10,0xb9,0x05,0x17,0xba,0x03,0x10,0x7a,0x99,
+	0x1e,0x9c,0x7a,0x03,0x11,0xb9,0x05,0x15,0xba,0x03,0x11,0x7a,0x99,0x1e,0x9c,0x7a,
+	0x03,0x11,0xb9,0x05,0x15,0xba,0x03,0x11,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x12,0xa9,
+	0x05,0x15,0xba,0x03,0x11,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x12,0xb9,0x05,0x13,0xba,
+	0x03,0x12,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x12,0xb9,0x05,0x13,0xba,0x03,0x12,0x7a,
+	0x99,0x1e,0x9c,0x7a,0x03,0x13,0xb9,0x05,0x11,0xba,0x03,0x13,0x7a,0x99,0x1e,0x9c,
+	0x7a,0x03,0x13,0xb9,0x05,0x11,0xba,0x03,0x13,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x13,
+	0xb9,0x05,0x11,0xaa,0x03,0x14,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x14,0xb9,0xfd,0xba,
+	0x03,0x14,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x14,0xb9,0xfd,0xba,0x03,0x14,0x7a,0x99,
+	0x1e,0x9c,0x7a,0x03,0x15,0xa9,0xed,0xba,0x03,0x15,0x7a,0x99,0x1e,0x9c,0x7a,0x03,
+	0x15,0xb9,0xdd,0xba,0x03,0x15,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x15,0xb9,0xcd,0xba,
+	0x03,0x16,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x16,0xb9,0xbd,0xba,0x03,0x16,0x7a,0x99,
+	0x1e,0x9c,0x7a,0x03,0x16,0xb9,0xbd,0xba,0x03,0x16,0x7a,0x99,0x1e,0x9c,0x7a,0x03,
+	0x17,0xa9,0xad,0xba,0x03,0x17,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x17,0xb9,0x9d,0xba,
+	0x03,0x17,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x17,0xb9,0x8d,0xba,0x03,0x18,0x7a,0x99,
+	0x1e,0x9c,0x7a,0x03,0x18,0xb9,0x7d,0xba,0x03,0x18,0x7a,0x99,0x1e,0x9c,0x7a,0x03,
+	0x18,0xb9,0x7d,0xba,0x03,0x18,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x18,0xb9,0x6d,0xba,
+	0x03,0x19,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x18,0xc9,0x5d,0xba,0x03,0x19,0x7a,0x99,
+	0x1e,0x9c,0x7a,0x03,0x19,0xb9,0x4d,0xba,0x03,0x1a,0x7a,0x99,0x1e,0x9c,0x7a,0x03,
+	0x19,0xc9,0x3d,0xba,0x03,0x1a,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x1a,0xb9,0x3d,0xaa,
+	0x03,0x1b,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x1a,0xb9,0x2d,0xba,0x03,0x1b,0x7a,0x99,
+	0x1e,0x9c,0x7a,0x03,0x1b,0xb9,0x1d,0xba,0x03,0x1b,0x7a,0x99,0x1e,0x9c,0x7a,0x03,
+	0x1b,0xb9,0xba,0x03,0x1c,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x1c,0xa9,0xba,0x03,0x1c,
+	0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x1c,0x99,0xba,0x03,0x1d,0x7a,0x99,0x1e,0x9c,0x7a,
+	0x03,0x1c,0x99,0xba,0x03,0x1d,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x1d,0x89,0xba,0x03,
+	0x1d,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x1d,0x89,0xaa,0x03,0x1e,0x7a,0x99,0x1e,0x9c,
+	0x7a,0x03,0x1e,0x69,0xba,0x03,0x1e,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x1e,0x59,0xba,
+	0x03,0x1f,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x1e,0x59,0xba,0x03,0x1f,0x7a,0x99,0x1e,
+	0x9c,0x7a,0x03,0x1f,0x39,0xca,0x03,0x1f,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x1f,0x39,
+	0xba,0x03,0x20,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x20,0x29,0xba,0x03,0x20,0x7a,0x99,
+	0x1e,0x9c,0x7a,0x03,0x20,0x19,0xba,0x03,0x21,0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x4d,
+	0x7a,0x99,0x1e,0x9c,0x7a,0x03,0x4d,0x7a,0x99,0x1e,0xac,0x6a,0x03,0x4d,0x7a,0x99,
+	0x1e,0xac,0x6a,0x03,0x4d,0x7a,0x99,0x1e,0xac,0x6a,0x03,0x4d,0x7a,0x99,0x1e,0xac,
+	0x6a,0x03,0x4d,0x7a,0x99,0x1e,0xac,0x6a,0x03,0x4d,0x7a,0x99,0x1e,0xac,0x6a,0x03,
+	0x4d,0x7a,0x99,0x1e,0xac,0x6a,0x03,0x4d,0x7a,0x99,0x1e,0xac,0x6a,0x03,0x4d,0x7a,
+	0x99,0x1e,0xac,0x6a,0x03,0x4d,0x7a,0x99,0x1e,0xac,0x6a,0x03,0x4c,0x8a,0x99,0x1e,
+	0xac,0x7a,0x03,0x4b,0x8a,0x99,0x1e,0xac,0x7a,0x03,0x4b,0x8a,0x99,0x1e,0xac,0x7a,
+	0x03,0x4a,0x9a,0x99,0x1e,0xac,0x7a,0x03,0x4a,0x9a,0x99,0x1e,0xac,0x8a,0x03,0x48,
+	0xaa,0x99,0x1e,0xac,0x9a,0x03,0x47,0xaa,0x99,0x1e,0xac,0xaa,0x03,0x45,0xba,0x99,
+	0x1e,0xac,0xba,0x03,0x43,0xca,0x99,0x1e,0xac,0xca,0x03,0x40,0xda,0xa9,0x1e,0xbc,
+	0xea,0x03,0x3a,0x02,0x10,0xa9,0x1e,0xbc,0x02,0x57,0xb9,0x1e,0x18,0xbc,0x02,0x56,
+	0xb9,0x1e,0x18,0xcc,0x02,0x54,0xc9,0x1e,0x28,0xcc,0x02,0x52,0xc9,0x18,0x1e,0x28,
+	0xdc,0x02,0x50,0xd9,0x18,0x1e,0x38,0xdc,0x02,0x4e,0xd9,0x28,0x1e,0x38,0xfc,0x02,
+	0x4a,0xf9,0x28,0x1e,0x48,0xfc,0x02,0x46,0x01,0x11,0x38,0x1e,0x58,0xec,0x01,0x56,
+	0x48,0x1e,0x68,0xdc,0x01,0x55,0x58,0x1e,0x78,0xcc,0x01,0x55,0x58,0x1e,0x78,0xcc,
+	0x01,0x53,0x78,0x1e,0x98,0xac,0x01,0x52,0x88,0x1e,0xa8,0x9c,0x01,0x51,0x98,0x1e,
+	0xb8,0x8c,0x01,0x4f,0xb8,0x1e,0xd8,0x6c,0x01,0x4d,0xd8,0x1e,0xf8,0x4c,0x01,0x4a,
+	0x00,0x10,0x1e,0x00,0x6d,
+	0xff};
+
+static char* extract_button(int number, int& width, int& height) {
+	int size;
+	char* data;
+
+	switch(number) {
+	case 0: data = buttonleft; size = buttonleft_cnt; width = 164; height = 110; break;
+	case 1: data = buttonright; size = buttonright_cnt; width = 164; height = 110; break;
+	case 2: data = buttonup; size = buttonup_cnt; width = 110; height = 164; break;
+	case 3: data = buttondown; size = buttondown_cnt; width = 110; height = 164; break;
+	default: return 0;
+	}
+
+	char* out = new char[width*height];
+	int outc = 0;
+	int i;
+	// ランレングスの展開
+	for (i=0; i<size; i++) {
+		int c = *(unsigned char*)(data+i);
+		int s = 0;
+		if (c == 0xff) break;
+		if (c&0x08) {
+			s = c>>4;
+			c &= 7;
+		} else {
+			i++;
+			s = *(unsigned char*)(data + i);
+		}
+		int j; for (j=0; j<s; j++) out[outc++] = c;
+	}
+	return out;
+}
+
+// R,G,B の指定色を基底色に、明るさを変えた色を RGB -> HLS -> RGB 変換で作成する
+struct ButtonColor {
+	int rs[8];
+	int gs[8];
+	int bs[8];
+	int as[8];
+	int* c_min, *c_mid, *c_max; // rgb->hls->rgb変換用。r,g,b を高い順にmax,mid,minに割り当てる
+	bool is_gray;
+	int hc, hd, l, s; // h,l,s 系。h 要素は上の c_min|mid|maxにも入る
+	ButtonColor(int _r, int _g, int _b);
+	void SetBrightness1(int n, int c1);
+	void SetBrightness(int c1, int c2, int c3, int c4, int c5);
+};
+ButtonColor::ButtonColor(int r, int g, int b) {
+	is_gray = false;
+	if (r == g && r == b) {
+		is_gray = true;
+		l = r;
+		return;
+	}
+	*rs = r; *bs = b; *gs = g;
+	
+	// r,g,b の昇順にmax,mid,minをrs,gs,bsに割り当てる
+	if (r > g) {
+		if (r > b) { // r = max
+			c_max = rs;
+			if (b > g) { // r>b>g
+				c_mid = bs;
+				c_min = gs;
+			} else { // r>g>b
+				c_mid = gs;
+				c_min = bs;
+			}
+		} else { // b>r>g
+			c_max = bs;
+			c_mid = rs;
+			c_min = gs;
+		}
+	} else if (g > b) { // g = max
+		c_max = gs;
+		if (r > b) { // g > r > b
+			c_mid = rs;
+			c_min = bs;
+		} else { // g > b > r
+			c_mid = bs;
+			c_min = rs;
+		}
+	} else { // b > g > r
+		c_max = bs;
+		c_mid = gs;
+		c_min = rs;
+	}
+	int min = *c_min;
+	int mid = *c_mid;
+	int max = *c_max;
+	l = (max+min)/2;
+	hd = max-min;
+	hc = mid - min;
+	if (l < 128) s = (hd*255)/(max+min);
+	else s = (hd*255) / (510-(max+min));
+}
+void ButtonColor::SetBrightness1(int n, int c1) {
+	if (n < 1 || n > 7) return;
+	as[n] = 255;
+	if (is_gray) {
+		rs[n] = c1 * l / 256;
+		gs[n] = c1 * l / 256;
+		bs[n] = c1 * l / 256;
+		return;
+	}
+	int m1, m2;
+
+	int light = (l * c1 * 2) / 256;
+	if (light > 255) light = 255;
+
+	if (light < 128) m2 = light*(255+s)/255;
+	else m2 = light+s-(light*s/255);
+	m1 = light*2 - m2;
+
+	c_max[n] = m2;
+	c_mid[n] = (hc*m2 + (hd-hc)*m1) / hd;
+	c_min[n] = m1;
+
+	return;
+}
+void ButtonColor::SetBrightness(int c1, int c2, int c3, int c4, int c5) {
+	rs[0] = bs[0] = gs[0] = as[0] = 0;
+	SetBrightness1(1, c1);
+	SetBrightness1(2, c2);
+	SetBrightness1(3, c3);
+	SetBrightness1(4, c4);
+	SetBrightness1(5, c5);
+}
+
+#include"rect.h"
+#include<string.h>
+
+static void draw_button(char* rdata, int width, int height, char* bdata, int bwidth, int bheight, const ButtonColor& color) {
+	const int* rs = color.rs;
+	const int* gs = color.gs;
+	const int* bs = color.bs;
+	const int* as = color.as;
+
+	struct ScaleData {int r,g,b,a,c;};
+	ScaleData* data = new ScaleData[width*height];
+	memset(data, 0, sizeof(ScaleData)*width*height);
+
+	int bx,by;
+	int x=0, y=0;
+	int x2 = 0, y2 = 0;
+	int xadd = width*65536/bwidth;
+	int yadd = height*65536/bheight;
+
+	// 元のビットマップに着色しながら縮小する
+	for (by=0; by<bheight; by++) {
+		ScaleData* d = data + y*width;
+		char* s = bdata + by*bwidth;
+		x = 0; x2 = 0;
+		for (bx=0; bx<bwidth; bx++) {
+			int c = *s++;
+			d[x].r += rs[c];
+			d[x].g += gs[c];
+			d[x].b += bs[c];
+			d[x].a += as[c];
+			d[x].c++;
+			x2 += xadd;
+			x += x2>>16;
+			x2 &= 0xffff;
+		}
+
+		y2 += yadd;
+		y += y2>>16;
+		y2 &= 0xffff;
+	}
+
+	for (y=0; y<height; y++) {
+		ScaleData* d = data + y*width;
+		char* rd = rdata + y*width*4;
+		for (x=0; x<width; x++) {
+			if (d->c == 0) *(int*)rd = 0;
+			else *(int*)rd = (int(d->b / d->c)&0xff)| ((int(d->g / d->c)&0xff)<<8)| ((int(d->r / d->c)&0xff)<<16)| ((int(d->a / d->c)&0xff)<<24);
+			rd += 4;
+			d++;
+		}
+	}
+	delete[] data;
+	return;
+}
+char* create_button(int number, int& width, int& height, int r, int g, int b) {
+	int bwidth, bheight;
+	char* bdata = extract_button(number, bwidth, bheight);
+	if (bdata == 0) return 0;
+	// 拡大率に合わせてwidth,heightをセット
+	if (width == -1 && height == -1) width = bwidth, height = bheight;
+	else if (width == -1) width = bwidth * height / bheight;
+	else if (height == -1) height = bheight * width / bwidth;
+	if (width > bwidth) width = bwidth;
+	if (height > bheight) height = bheight;
+
+	// 色を設定する
+	ButtonColor color(r,g,b);
+	// 描画
+	char* rdata = (char*)malloc(width*height*4*3);
+	color.SetBrightness(0x60, 0xa0, 0xc0, 0xe0, 0xe0);
+	draw_button(rdata, width, height, bdata, bwidth, bheight, color);
+	color.SetBrightness(0x60, 0xa0, 0xe0, 0xe0, 0xe0);
+	draw_button(rdata+width*height*4, width, height, bdata, bwidth, bheight, color);
+	color.SetBrightness(0xe0, 0xc0, 0xa0, 0x60, 0xa0);
+	draw_button(rdata+width*height*8, width, height, bdata, bwidth, bheight, color);
+	return rdata;
+}
+
+static void drawbox(char* buf, const Rect& region, int width, int r, int g, int b, int a) {
+	buf += region.ty*width*4 + region.lx*4;
+	int i,j;
+	int h = region.height();
+	int w = region.width();
+	int col = (b&0xff) | ((g&0xff)<<8)| ((r&0xff)<<16)| ((a&0xff)<<24);
+	for (i=0; i<h; i++) {
+		char* c = buf;
+		for (j=0; j<w; j++) {
+			*(int*)c = col;
+			c += 4;
+		}
+		buf += width*4;
+	}
+	return;
+}
+static void draw_box(char* buf, int width, int height, int kage_w1, int kage_w2, const ButtonColor& color) {
+	const int* rs = color.rs;
+	const int* gs = color.gs;
+	const int* bs = color.bs;
+	const int* as = color.as;
+	// まず、豆腐を書く
+	drawbox(buf, Rect(0,0,width,height), width, rs[3],gs[3],bs[3],as[3]);
+	// 影
+	if (height > 2) {
+		drawbox(buf, Rect(0,0,width,kage_w1), width, rs[4], gs[4], bs[4],as[4]);
+		drawbox(buf, Rect(0,height-kage_w1,width,height), width, rs[1], gs[1], bs[1],as[1]);
+	}
+	if (width >  2) {
+		drawbox(buf, Rect(0,0,kage_w1, height), width, rs[4], gs[4], bs[4],as[4]);
+		drawbox(buf, Rect(width-kage_w1,0,width,height), width, rs[1], gs[1], bs[1],as[1]);
+	}
+	if (height > 4) {
+		drawbox(buf, Rect(kage_w2, height-kage_w2, width-kage_w1, height-kage_w1), width, rs[2], gs[2], bs[2], as[2]);
+	}
+	if (width > 4) {
+		drawbox(buf, Rect(width-kage_w2, kage_w2, width-kage_w1, height-kage_w1), width, rs[2], gs[2], bs[2], as[2]);
+	}
+}
+char* create_box(int& width, int& height, int r, int g, int b) {
+	ButtonColor color(r,g,b);
+	// scale のカーソル
+	if (width == -1 && height == -1) width = 32, height = 48;
+	else if (width == -1) width = height*3/2;
+	else if (height == -1) height = width * 3/2;
+	int kage_w1 = (width<height ? width : height)/14;
+	int kage_w2 = (width<height ? width : height)*2/14;
+	if (kage_w1 <= 0) kage_w1 = 1;
+	if (kage_w2 <= 1) kage_w2 = 2;
+	
+	char* buf = (char*)malloc(width*height*4*3);
+	// 描画
+	color.SetBrightness(0x60, 0xa0, 0xc0, 0xe0, 0xe0);
+	draw_box(buf, width, height, kage_w1, kage_w2, color);
+	color.SetBrightness(0x60, 0xa0, 0xe0, 0xe0, 0xe0);
+	draw_box(buf+width*height*4, width, height, kage_w1, kage_w2, color);
+	color.SetBrightness(0xe0, 0xc0, 0xa0, 0x60, 0xa0);
+	draw_box(buf+width*height*8, width, height, kage_w1, kage_w2, color);
+	return buf;
+}
+
+#if 0
+#include<stdio.h>
+#include <png.h>
+
+void create_png(FILE* stream,int width, int height, char* data) {
+	png_structp png_ptr;
+	png_infop info_ptr;
+
+	/* create struct */
+	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+	if (png_ptr == NULL) return;
+
+	/* initialize information */
+	info_ptr = png_create_info_struct(png_ptr);
+	if (info_ptr == NULL) {
+		png_destroy_write_struct(&png_ptr, (png_infop*)NULL);
+		return;
+	}
+
+	if (setjmp(png_jmpbuf(png_ptr))) {
+		/* error occured !! */
+		png_destroy_write_struct(&png_ptr,&info_ptr);
+		return;
+	}
+
+	/* initialize I/O (for stream) */
+	png_init_io(png_ptr, stream);
+
+	/* initialize headers */
+	png_set_IHDR(png_ptr, info_ptr,
+		width, height, 8 /* bit_dept */,
+		PNG_COLOR_TYPE_RGB_ALPHA,
+		PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+	/* create text information */
+	png_text info_text[3];
+	info_text[0].key = "Title";
+	info_text[0].text= "file";
+	info_text[0].compression = PNG_TEXT_COMPRESSION_NONE;
+	info_text[1].key = "Author";
+	info_text[1].text="";
+	info_text[1].compression = PNG_TEXT_COMPRESSION_NONE;
+	info_text[2].key = "Description";
+	info_text[2].text= "";
+	info_text[2].compression = PNG_TEXT_COMPRESSION_NONE;
+	png_set_text(png_ptr, info_ptr, info_text, 3);
+
+	/* write information */
+	png_write_info(png_ptr, info_ptr);
+
+	/* write body */
+	/* rgba image ; input/output is 32bpp.*/
+	char* row = new char[width*4];
+	int i; for (i=0; i<height; i++) {
+		char* row_ptr = row;
+		int j; for (j=0; j<width; j++) {
+			row_ptr[0] = data[2];
+			row_ptr[1] = data[1];
+			row_ptr[2] = data[0];
+			row_ptr[3] = data[3];
+			row_ptr += 4; data += 4;
+		}
+		png_write_rows(png_ptr, (png_byte**)&row, 1);
+	}
+	png_write_end(png_ptr, info_ptr);
+	png_destroy_write_struct(&png_ptr, &info_ptr);
+	return;
+}
+int main(void) {
+	int w=128,h=-1;
+	char* c = create_button(2, w,h,0x20,0x60,0xc0);
+//	char* c = create_box(w,h,0xff,0xff,0xff);
+	int i;
+	FILE* f=fopen("bt.png","wb");
+	if(f==0)return 0;
+	create_png(f,w,h*3,c);
+	for (i=0;i<w*h;i++) {
+		printf("%08x,",*(int*)(c+i*4));
+		if ( (i&7)==7) printf("\n");
+	}
+	return 0;
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/window/event.cc
@@ -0,0 +1,570 @@
+/*
+ * Copyright (c) 2004-2006  Kazunori "jagarl" Ueno
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include"SDL.h"
+#include"event.h"
+#include<vector>
+#include<list>
+#include<algorithm>
+#include<iostream>
+#include<sys/stat.h>
+
+using namespace std;
+
+extern bool save_req = false, load_req = false, grpdump_req = false; //  scn2k/scn2k_impl.cc: キーボードからセーブ・ロードできるように
+extern bool pressAreq=false,pressFreq=false,pressDreq=false;
+namespace Event {
+/* Impl: struct Event::Video */
+
+Video::Video(Container& container) : region(0, 0, 0, 0), z(0), parent(container) {
+	activated = false;
+	parent.Add(this);
+}
+Video::Video(Container& container, const Rect& init_rect) : region(init_rect), z(0), parent(container) {
+	activated = false;
+	parent.Add(this);
+}
+Video::Video(Container& container, const Rect& init_rect, int _z) : region(init_rect), z(_z), parent(container) {
+	activated = false;
+	parent.Add(this);
+}
+Video::~Video() {
+	parent.Delete(this);
+};
+void Video::SetRegion(const Rect& new_rect) {
+	region = new_rect;
+}
+void Video::SetZ(int new_z) {
+	z = new_z;
+}
+void Video::activate(void) {
+	activated = true;
+}
+void Video::deactivate(void) {
+	activated = false;
+}
+inline int Video::point_in(int x, int y) {
+	if (!activated) return -1;
+	if (region.point_in(x,y)) return z;
+	else return -1;
+}
+
+/* カーソルの動く順序:上、左の順に準位付け */
+bool operator <(const Video& pos1, const Video& pos2) {
+	if (pos1.region.ty < pos2.region.ty) return true;
+	if (pos1.region.ty == pos2.region.ty) return pos1.region.lx < pos2.region.lx;
+	if (pos1.region.by >= pos2.region.by) return pos1.region.lx <= pos2.region.lx;
+	return false;
+}
+
+
+/* Impl: struct Event::Time */
+Time::Time(Container& container) : wakeup_time(container.current_time), parent(container) {
+	parent.Add(this);
+}
+Time::~Time() {
+	parent.Delete(this);
+}
+/* Define: struct Event::ContainerImpl */
+
+struct ContainerImplTime_Item {
+	Time* instance;
+	bool valid;
+	bool operator ==(Time* const& to) const {
+		return to == instance;
+	}
+	ContainerImplTime_Item(Time* _time) :
+		instance(_time), valid(true) {
+	}
+};
+
+class ContainerImplTime : private vector<ContainerImplTime_Item> {
+public:
+	ContainerImplTime(void);
+	bool Exec(unsigned int current_time);
+	void Add(Time* new_event);
+	void Delete(Time* delete_event);
+private:
+	static vector<ContainerImplTime_Item> new_item;
+	unsigned int prev_execed_time;
+	static bool is_invalid(const_reference value) {
+		return !value.valid;
+	}
+};
+
+vector<ContainerImplTime_Item> ContainerImplTime::new_item;
+
+ContainerImplTime::ContainerImplTime(void) {
+	prev_execed_time = 0;
+}
+void ContainerImplTime::Add(Time* event) {
+	ContainerImplTime_Item item(event);
+	new_item.push_back(item);
+}
+void ContainerImplTime::Delete(Time* delete_event) {
+	iterator it = find(begin(), end(), delete_event);
+	if (it != end()) {
+		it->valid = false;
+		it->instance = 0;
+		return;
+	}
+	it = find(new_item.begin(), new_item.end(), delete_event);
+	if (it != end()) {
+		it->valid = false;
+		it->instance = 0;
+		return;
+	}
+	return;
+}
+bool ContainerImplTime::Exec(unsigned int current_time) {
+	if (current_time == Time::NEVER_WAKE) return true;
+	// 呼び出しまでに作製されたitemを追加 
+	insert(end(), new_item.begin(), new_item.end());
+	new_item.clear();
+	if (empty()) return true;
+	if (current_time == Time::FRAME_UPDATE) { // ビデオフレームの更新時
+		for (iterator it = begin(); it != end(); it++) {
+			if (! it->valid) continue;
+			
+			unsigned tm = it->instance->Wakeup();
+			if (tm == Time::FRAME_UPDATE) {
+				it->instance->Elapsed(prev_execed_time);
+			}
+		}
+	} else { // 時間変化時
+		if (current_time < prev_execed_time) prev_execed_time = 0; /* 時間が一回りして0に戻ったとき */
+		for (iterator it = begin(); it != end(); it++) {
+			if (! it->valid) continue;
+			unsigned tm = it->instance->Wakeup();
+			if (tm >= prev_execed_time && tm < current_time) {
+				it->instance->Elapsed(current_time);
+			}
+		}
+		prev_execed_time = current_time;
+	}
+	// 処理中に削除された item を実際に削除
+	erase(remove_if(begin(), end(), is_invalid), end());
+	return true;
+}
+
+
+class ContainerImplVideo : private vector<Video*> {
+public:
+	bool Exec(void);
+
+	ContainerImplVideo(void);
+	~ContainerImplVideo();
+	void Add(Video* item);
+	void Delete(Video* item);
+	void RegisterGlobalMotionFunc(Container::motionfunc, void* pointer);
+	void DeleteGlobalMotionFunc(Container::motionfunc, void* pointer);
+	void RegisterGlobalPressFunc(Container::motionfunc, void* pointer);
+	void DeleteGlobalPressFunc(Container::motionfunc, void* pointer);
+private:
+	struct Motionfunc {
+		Container::motionfunc func;
+		void* pointer;
+		bool operator ==(const Motionfunc& m) const { return func == m.func && pointer == m.pointer;}
+	};
+	list<Motionfunc> motion_vec;
+	list<Motionfunc> press_vec;
+	typedef list<Motionfunc>::iterator MotionIterator;
+	bool is_sorted;
+public:
+	int button_pressed;
+	int button_released;
+	int mouse_x, mouse_y;
+	int new_mouse_x, new_mouse_y;
+private:
+	void SetChanged(void);
+	static bool SortLess(const Video* pos1, const Video* pos2) {
+		return pos1 < pos2;
+	}
+	void Sort(void);
+	void Motion(int x, int y); // mouse motion
+	void Press(void);
+	void TakeScreenshot(void);
+	iterator cur_pos;
+	Video* cur_item; // 現在のフォーカス位置
+	int cur_pressed_x, cur_pressed_y;
+};
+
+void ContainerImplVideo::SetChanged(void) {
+	if (is_sorted) {
+		if (cur_item) {
+			cur_pos = find(begin(), end(), cur_item);
+			if (cur_pos == end()) cur_item = 0;
+		}
+		is_sorted = false;
+	}
+}
+
+void ContainerImplVideo::Sort(void) {
+	sort(begin(), end(), SortLess);
+	if (cur_item) {
+		cur_pos = lower_bound(begin(), end(), cur_item, SortLess);
+	} else {
+		cur_pos = end();
+	}
+	is_sorted = true;
+}
+
+ContainerImplVideo::ContainerImplVideo(void) {
+	is_sorted = false;
+	button_pressed = 0;
+	button_released = 0;
+	cur_item = 0;
+	mouse_x = 0; mouse_y = 0;
+	new_mouse_x = 0; new_mouse_y = 0;
+}
+ContainerImplVideo::~ContainerImplVideo(void) {
+};
+void ContainerImplVideo::Add(Video* event) {
+	push_back(event);
+	SetChanged();
+}
+void ContainerImplVideo::Delete(Video* delete_event) {
+	iterator it = find(begin(), end(), delete_event);
+	if (it != end()) {
+		erase(it);
+		SetChanged();
+	} else {
+		fprintf(stderr,"\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n");
+		fprintf(stderr,"X  ContainerImplVideo: Cannot delete node %x\n",delete_event);
+		fprintf(stderr,"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n\n");
+		fprintf(stderr,"vector from:\n");
+		for(it=begin(); it!=end(); it++) {
+			fprintf(stderr,"%x, ",*it);
+		}
+		fprintf(stderr,"\n");
+	}
+	if (delete_event == cur_item) {
+		cur_pos = end();
+		cur_item = 0;
+		Motion(mouse_x, mouse_y);
+	}
+	return;
+}
+void ContainerImplVideo::RegisterGlobalMotionFunc(Container::motionfunc func, void* pointer) {
+	Motionfunc f;
+	f.func = func;
+	f.pointer = pointer;
+	if (find(motion_vec.begin(), motion_vec.end(), f) == motion_vec.end()) {
+		motion_vec.push_back(f);
+	}
+}
+void ContainerImplVideo::DeleteGlobalMotionFunc(Container::motionfunc func, void* pointer) {
+	Motionfunc f;
+	f.func = func;
+	f.pointer = pointer;
+	list<Motionfunc>::iterator it = find(motion_vec.begin(), motion_vec.end(), f);
+	if (it != motion_vec.end())
+		motion_vec.erase(it);
+	return;
+}
+void ContainerImplVideo::RegisterGlobalPressFunc(Container::motionfunc func, void* pointer) {
+	Motionfunc f;
+	f.func = func;
+	f.pointer = pointer;
+	if (find(press_vec.begin(), press_vec.end(), f) == press_vec.end()) {
+		press_vec.push_back(f);
+	}
+}
+void ContainerImplVideo::DeleteGlobalPressFunc(Container::motionfunc func, void* pointer) {
+	Motionfunc f;
+	f.func = func;
+	f.pointer = pointer;
+	list<Motionfunc>::iterator it = find(press_vec.begin(), press_vec.end(), f);
+	if (it != press_vec.end())
+		press_vec.erase(it);
+	return;
+}
+void ContainerImplVideo::Motion(int x, int y) {
+	mouse_x = x; mouse_y = y;
+	MotionIterator mit;
+	for (mit=motion_vec.begin(); mit != motion_vec.end();) {
+		MotionIterator mit_next = mit;
+		mit_next++;
+		if (!(*mit->func)(x, y, mit->pointer)) motion_vec.erase(mit);
+		mit = mit_next;
+	
+	}
+	
+	/* @@@ ドラッグ処理とマウスを押す処理のバッティングで「二回ボタンを押さないと云々」関連のバグの可能性あり */
+	if (button_pressed & (1<<MOUSE_LEFT)) {
+		if (cur_item) cur_item->Drag(cur_pressed_x, cur_pressed_y, x, y);
+		return;
+	}
+	if (cur_item) cur_item->Motion(x,y);
+	int z = -1; iterator z_it;
+	iterator it;
+	for (it = begin(); it != end(); it++) {
+		int new_z = (*it)->point_in(x, y);
+		if (z < new_z) {
+			z = new_z;
+			z_it = it;
+		}
+	}
+	if (z != -1) {
+		if (cur_item == *z_it) return;
+		if (cur_item) cur_item->Out();
+		cur_pos = z_it;
+		cur_item = *z_it;
+		cur_item->In();
+		return;
+	} else {
+		if (cur_item) cur_item->Out();
+		cur_pos = end();
+		cur_item = 0;
+	}
+	return;
+}
+
+void ContainerImplVideo::Press(void) {
+	if (cur_item) {
+		cur_pressed_x = mouse_x;
+		cur_pressed_y = mouse_y;
+		cur_item->Press();
+		return;
+	}
+	MotionIterator mit;
+	for (mit=press_vec.begin(); mit != press_vec.end(); ) {
+		MotionIterator mit_next = mit;
+		mit_next++;
+		if (!(*mit->func)(mouse_x, mouse_y, mit->pointer)) {
+			press_vec.erase(mit);
+		}
+		mit = mit_next;
+	}
+}
+void ContainerImplVideo::TakeScreenshot(void) {
+	int n=0;
+	char filename[1024];
+	struct stat buffer;
+	for(n=0; n<9999; n++) {
+		// XXX: put screenshots in a seperate dir?
+		sprintf(filename, "xclannad_%04i.bmp", n);
+		if(stat(filename, &buffer) == -1) break;
+	}
+	SDL_SaveBMP(SDL_GetVideoSurface(), filename);
+}
+bool ContainerImplVideo::Exec(void) {
+
+	bool is_mouse_motion = false;
+	int motion_x = 0, motion_y = 0;
+	SDL_Event event;
+	SDL_PumpEvents();
+	while(SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_ALLEVENTS) == 1) {
+		switch(event.type) {
+		case SDL_QUIT: return false; // @@@ なにかやらないと
+		case SDL_ACTIVEEVENT: // なにもしない
+			// cout<<"active : gain "<<int(event.active.gain)<<", state "<<int(event.active.state)<<endl;
+			break;
+		case SDL_KEYDOWN:
+			if (!is_sorted) Sort();
+			switch(event.key.keysym.sym) {
+			case SDLK_F12:
+			case SDLK_PRINT:
+			case SDLK_p:  // for Zaurus
+				TakeScreenshot();
+				break;
+			// Some window managers (eg enlightenment) use Alt-Enter for
+			// themselves, F11 is a good alternative
+			case SDLK_F11:
+				SDL_WM_ToggleFullScreen(SDL_GetVideoSurface());
+				break;
+			case SDLK_RETURN:
+				if (SDL_GetModState() & KMOD_ALT) {
+					SDL_WM_ToggleFullScreen(SDL_GetVideoSurface());
+					break;
+				}
+			case SDLK_SPACE:
+				Press();
+				break;
+			case SDLK_TAB: // move to next widget
+				if (cur_pos != end())  cur_pos++;
+				if (cur_pos == end()) cur_pos = begin();
+				if (cur_pos != end())  {
+					cur_item = *cur_pos;
+					cur_item->In();
+				} else {
+					cur_item = 0;
+				}
+				break;
+			case SDLK_LEFT: if (cur_pos != end()) (*cur_pos)->KeyLeft(); break;
+			case SDLK_RIGHT:if (cur_pos != end()) (*cur_pos)->KeyRight(); break;
+			case SDLK_LSHIFT: case SDLK_RSHIFT: button_pressed |= (1<<KEY_SHIFT); break;
+			case SDLK_ESCAPE: button_pressed |= (1<<MOUSE_RIGHT); break; /* for Zaurus */
+			case SDLK_s: save_req = true; break;
+			case SDLK_l: load_req = true; break;
+			case SDLK_g: grpdump_req = true; break;
+			case SDLK_a: pressAreq = true; break;
+			case SDLK_d: pressDreq = true; break;
+			case SDLK_f: pressFreq = true; break;
+			}
+			break;
+		case SDL_KEYUP:
+			// cout << "keyup which "<<int(event.key.which)<<", sym "<<int(event.key.keysym.sym)<<endl;
+			switch(event.key.keysym.sym) {
+			case SDLK_RETURN: case SDLK_SPACE:
+				if (cur_item) cur_item->Release();
+			case SDLK_LSHIFT: case SDLK_RSHIFT: button_pressed &= ~(1<<KEY_SHIFT); button_released |= 1<<KEY_SHIFT; break;
+			case SDLK_ESCAPE: button_pressed &= ~(1<<MOUSE_RIGHT); button_released |= 1<<MOUSE_RIGHT; break; /* for Zaurus */
+			}
+			break;
+		case  SDL_MOUSEMOTION:
+			motion_x = event.motion.x;
+			motion_y = event.motion.y;
+			is_mouse_motion = true;
+			// Motion(event.motion.x, event.motion.y);
+			// cout<< "motion which "<<int(event.motion.which)<<
+			//	"x "<<event.motion.x << "y "<<event.motion.y<<endl;
+			break;
+		case SDL_MOUSEBUTTONUP:
+			if (event.button.button == 1) {
+				Motion(event.button.x, event.button.y);
+				is_mouse_motion = false;
+				if (cur_item) cur_item->Release();
+			}
+			switch(event.button.button) {
+			case 1: button_pressed &= ~(1<<MOUSE_LEFT); button_released |= 1<<MOUSE_LEFT; break;
+			case 2: button_pressed &= ~(1<<MOUSE_MIDDLE); button_released |= 1<<MOUSE_MIDDLE; break;
+			case 3: button_pressed &= ~(1<<MOUSE_RIGHT); button_released |= 1<<MOUSE_RIGHT; break;
+			case 4: button_pressed &= ~(1<<MOUSE_UP); button_released |= 1<<MOUSE_UP; break;
+			case 5: button_pressed &= ~(1<<MOUSE_DOWN); button_released |= 1<<MOUSE_DOWN; break;
+			}
+			break;
+		case SDL_MOUSEBUTTONDOWN:
+			if (event.button.button == 1) {
+				Motion(event.button.x, event.button.y);
+				is_mouse_motion = false;
+				Press();
+			}
+			switch(event.button.button) {
+			case 1: button_pressed |= (1<<MOUSE_LEFT); break;
+			case 2: button_pressed |= (1<<MOUSE_MIDDLE); break;
+			case 3: button_pressed |= (1<<MOUSE_RIGHT); break;
+			case 4: button_pressed |= (1<<MOUSE_UP); break;
+			case 5: button_pressed |= (1<<MOUSE_DOWN); break;
+			}
+			// cout << "mouse which "<<int(event.button.which)<<"button "<<int(event.button.button)<<
+			//	"state "<<int(event.button.state)<<"x "<<event.button.x << "y "<<event.button.y<<endl;
+			break;
+		case SDL_VIDEOEXPOSE: // redraw の必要がある?
+			// cout<<"expose."<<endl;
+			break;
+		}
+	}
+	// Motion 呼び出しは一回だけ
+	if (is_mouse_motion)
+		Motion(motion_x, motion_y);
+	return true;
+};
+/* Impl: struct Event::Container */
+Container::Container(void) {
+	pimpl_video = new ContainerImplVideo;
+	try {
+		pimpl_time = new ContainerImplTime;
+	} catch(...) {
+		delete pimpl_video;
+		throw;
+	}
+	button_pressed = 0;
+	current_time = 0;
+	int i; for (i=0; i<BUTTON_MAX; i++) button_presscount[i] = 0;
+	return;
+}
+Container::~Container(void) {
+	delete pimpl_video;
+	delete pimpl_time;
+}
+void Container::Add(Video* item) {
+	pimpl_video->Add(item);
+}
+void Container::Delete(Video* item) {
+	pimpl_video->Delete(item);
+}
+void Container::Add(Time* item) {
+	pimpl_time->Add(item);
+}
+void Container::Delete(Time* item) {
+	pimpl_time->Delete(item);
+}
+void Container::RegisterGlobalMotionFunc(Container::motionfunc f, void* pointer) {
+	pimpl_video->RegisterGlobalMotionFunc(f, pointer);
+}
+void Container::DeleteGlobalMotionFunc(Container::motionfunc f, void* pointer) {
+	pimpl_video->DeleteGlobalMotionFunc(f, pointer);
+}
+void Container::RegisterGlobalPressFunc(Container::motionfunc f, void* pointer) {
+	pimpl_video->RegisterGlobalPressFunc(f, pointer);
+}
+void Container::DeleteGlobalPressFunc(Container::motionfunc f, void* pointer) {
+	pimpl_video->DeleteGlobalPressFunc(f, pointer);
+}
+bool Container::Exec(unsigned int time) {
+	current_time = time;
+	bool ret = true;
+	ret = ret && pimpl_video->Exec();
+	ret = ret && pimpl_time->Exec(time);
+	int i; int mask = 1;
+	int new_button_pressed = pimpl_video->button_pressed;
+	for (i=0; i<BUTTON_MAX; i++) {
+		if (pimpl_video->button_released&mask) {
+			button_presscount[i]++;
+		}
+		mask <<= 1;
+	}
+	pimpl_video->button_released = 0;
+	button_pressed = pimpl_video->button_pressed;
+	return ret;
+}
+
+void Container::MousePos(int& x, int& y) {
+	x = pimpl_video->mouse_x;
+	y = pimpl_video->mouse_y;
+}
+
+bool Container::pressed(int mask) {
+	if (mask < 0 || mask >= BUTTON_MAX) return 0;
+	return (button_pressed & (1<<mask)) != 0;
+}
+bool Container::presscount(int mask) {
+	if (mask < 0 || mask >= BUTTON_MAX) return 0;
+	int count = button_presscount[mask];
+	button_presscount[mask] = 0;
+	return count;
+}
+
+}; /* end of namespace Container */
+
+// 問題:
+// z 軸と xy 軸の相互干渉;高速化
+// 移動するウィジット描画の高速化
+// キャッシュ
+// 文字列の一部のみ更新の高速化
+// 「階層 z で x なる領域無効化、y なる領域生成」で良い?>Expose
new file mode 100644
--- /dev/null
+++ b/window/event.h
@@ -0,0 +1,99 @@
+#ifndef __EVENT__
+#define __EVENT__
+
+#include"rect.h"
+#include"SDL.h"
+
+namespace Event {
+
+class Video;
+class Time;
+class Container;
+
+/*
+** マウスの press, ドラッグ、in/out を検出できる
+** focus がある時の left/right/space(==press) のキーを判別できる
+*/
+struct Video {
+	virtual void Press(void) {}
+	virtual void Release(void) {}
+	virtual void Drag(int x_from, int y_from, int x_to, int y_to) {}
+	virtual void Motion(int x, int y) {}
+	virtual void In(void) {}
+	virtual void Out(void) {}
+	virtual void KeyLeft(void) {}
+	virtual void KeyRight(void) {}
+
+	int point_in(int x, int y); /* z or -1 を返す。大きいほど高いところにある */
+
+	Video(Container& container);
+	Video(Container& container, const Rect& init_rect);
+	Video(Container& container, const Rect& init_rect, int z);
+	void SetRegion(const Rect& new_rect);
+	void SetZ(int new_z);
+	void activate(void);
+	void deactivate(void);
+	virtual ~Video();
+
+	Rect Region(void) const { return region;}
+private:
+	Rect region;
+	int z;
+	Container& parent;
+	bool activated;
+	friend bool operator <(const Video& position1, const Video& position2);
+};
+
+struct Time {
+	enum { NEVER_WAKE = 0xffffffff, FRAME_UPDATE = 0xfffffffe};
+	virtual void Elapsed(unsigned int current_time) {wakeup_time = NEVER_WAKE; }; /* next: never elapsed */
+	void SetWakeup(unsigned int new_wakeup_time) { wakeup_time = new_wakeup_time; }
+	unsigned  Wakeup(void) const { return wakeup_time; }
+
+	Time(Container& container);
+	~Time();
+private:
+	unsigned int wakeup_time;
+	Container& parent;
+};
+
+struct Container {
+#define MOUSE_LEFT 0
+#define MOUSE_MIDDLE 1
+#define MOUSE_RIGHT 2
+#define MOUSE_UP 3
+#define MOUSE_DOWN 4
+#define KEY_SHIFT 10
+#define BUTTON_MAX 32
+	int button_pressed;
+	int button_presscount[BUTTON_MAX];
+	int current_time;
+
+	void MousePos(int& x, int& y);
+	bool Exec(unsigned int current_time);
+
+	void Add(Video* item);
+	void Delete(Video* item);
+
+	void Add(Time* item);
+	void Delete(Time* item);
+
+	typedef bool (*motionfunc)(int x, int y, void* pointer);
+	void RegisterGlobalMotionFunc(motionfunc, void* pointer); // マウスの移動のたびに呼び出される関数を登録する
+	void DeleteGlobalMotionFunc(motionfunc, void* pointer);
+	void RegisterGlobalPressFunc(motionfunc, void* pointer); // マウスのクリックのたびに呼び出される関数を登録する
+	void DeleteGlobalPressFunc(motionfunc, void* pointer);
+
+	Container(void);
+	~Container(void);
+	bool pressed(int mask);
+	bool presscount(int mask);
+private:
+	class ContainerImplVideo* pimpl_video;
+	class ContainerImplTime* pimpl_time;
+};
+
+}; /* end of namespace Event */
+
+
+#endif
new file mode 100644
--- /dev/null
+++ b/window/menuitem.cc
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2004-2006  Kazunori "jagarl" Ueno
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include"menuitem.h"
+
+#define Button WidButton
+#define Scale WidScale
+#define Label WidLabel
+#define TextButton WidTextButton
+#define Text WidText
+
+#define MenuItem WidMenuItem
+#define RadioGroup WidRadioGroup
+#define ScaleMenu WidScaleMenu
+void fill(Surface* src, const Rect& rect, int r, int g, int b, int a = 0xff);
+
+MenuItem::MenuItem(PicContainer* parent, const Rect& r_orig, int _x_size, int _y_size, int* _value_ptr) :
+		x_size(_x_size), y_size(_y_size), value_ptr(_value_ptr), set_func(0), set_pointer(0) {
+	SetPic(parent->create_node(r_orig, 0));
+	menu_width = r_orig.width();
+	menu_height = r_orig.height();
+	label = 0;
+	lb_width  = 0; lb_right = 0;
+	lb_left = -1; lb_bottom = -1;
+	int i;
+	for (i=0; i<x_size*y_size; i++) item.push_back(0);
+};
+void MenuItem::SetLabelLeft(PicWidget* lb, const Rect& min_rect, const Rect& min_margin) {
+	lb_width = min_rect.width();
+	lb_right = min_margin.width();
+	lb_left = -1;
+	lb_bottom = -1;
+	label = lb;
+}
+void MenuItem::SetLabelTop(PicWidget* lb, const Rect& left_margin, const Rect& bottom_margin) {
+	lb_left = left_margin.width();
+	lb_bottom = bottom_margin.height();
+	lb_width = -1;
+	lb_right = -1;
+	label = lb;
+}
+void MenuItem::SetValue(int new_value) {
+	SetValueImpl(new_value);
+	if (value_ptr) *value_ptr = new_value;
+	if (set_func) (*set_func)(set_pointer, this);
+}
+void MenuItem::activate(void) {
+	iterator it;
+	for (it=item.begin(); it!=item.end(); it++) {
+		if (*it == 0) continue;
+		(*it)->activate();
+	}
+}
+void MenuItem::deactivate(void) {
+	iterator it;
+	for (it=item.begin(); it!=item.end(); it++) {
+		if (*it == 0) continue;
+		(*it)->deactivate();
+	}
+}
+void MenuItem::pack(void) {
+	int x_min = 0, y_min = 0;
+	if (lb_width == -1) { // 上にラベルを貼る
+		if (lb_left < 0) lb_left = 0;
+		if (lb_bottom < 0) lb_bottom = 0;
+		if (label && label->Pic()) {
+			label->Pic()->Move(lb_left, 0);
+			y_min = lb_bottom + label->Pic()->Height();
+		} else {
+			y_min = lb_bottom;
+		}
+	} else { // 左にラベルを貼る
+		if (lb_right < 0) lb_right = 0;
+		if (label && label->Pic()) {
+			int label_width = label->Pic()->Width();
+			int label_height = label->Pic()->Height();
+			if (label_width > lb_width - lb_right) {
+				x_min = label_width + lb_right;
+			} else {
+				x_min = lb_width;
+			}
+		} else {
+			x_min = lb_width;
+		}
+	}
+	int* item_width = new int[x_size];
+	int* item_height = new int[y_size];
+	int* item_x = new int[x_size];
+	int* item_y = new int[y_size];
+	int i,j;
+	for (i=0; i<x_size; i++) item_width[i]=0;
+	for (i=0; i<y_size; i++) item_height[i]=0;
+	
+	iterator it = item.begin();
+	for (i=0; i<y_size; i++) {
+		for (j=0; j<x_size; j++) {
+			if (*it != 0 && (*it)->Pic() != 0) {
+				PicBase* pic = (*it)->Pic();
+				if (item_width[j] < pic->Width()) item_width[j] = pic->Width();
+				if (item_height[i] < pic->Height()) item_height[i] = pic->Height();
+			}
+			it++;
+		}
+	}
+	int width=0, height=0;
+	for (i=0; i<x_size; i++) {
+		width += item_width[i];
+	}
+	for (i=0; i<y_size; i++) {
+		height += item_height[i];
+	}
+
+	int x=x_min, y=y_min;
+	// width / height の再割り当て
+	if (menu_width > width + x_min) {
+		int dif = menu_width - width - x_min;
+		int n = x_size + 1;
+		x += dif/n;
+		for (i=0; i<x_size; i++) {
+			item_x[i] = x + item_width[i] / 2;
+			x += item_width[i] + dif*(i+2)/n - dif*(i+1)/n;
+		}
+	} else {
+		if (menu_width == 0) {
+			Pic()->SetSurfaceRect(Rect(0, 0, width+x_min, Pic()->Height()));
+		}
+		for (i=0; i<x_size; i++) {
+			item_x[i] = x + item_width[i] / 2;
+			x += item_width[i];
+		}
+	}
+	if (menu_height > height+y_min) {
+		int dif = menu_height - height - y_min;
+		int n = y_size + 1;
+		y += dif/n;
+		for (i=0; i<y_size; i++) {
+			item_y[i] = y + item_height[i] / 2;
+			y += item_height[i] + dif*(i+2)/n - dif*(i+1)/n;
+		}
+	} else {
+		if (menu_height == 0) {
+			Pic()->SetSurfaceRect(Rect(0, 0, Pic()->Width(), height+y_min));
+		}
+		for (i=0; i<y_size; i++) {
+			item_y[i] = y + item_height[i] / 2;
+			y += item_height[i];
+		}
+	}
+	// 位置の再割り当て
+	it = item.begin();
+	for (i=0; i<y_size; i++) {
+		for (j=0; j<x_size; j++) {
+			if (*it != 0 && (*it)->Pic() != 0) {
+				PicBase* pic = (*it)->Pic();
+				int x0 = item_x[j]-pic->Width()/2;
+				int y0 = item_y[i]-pic->Height()/2;
+				pic->Move(x0, y0);
+			}
+			it++;
+		}
+	}
+	// 左にラベルがある場合、ラベルの高さ方向のセンタリング
+	if (label && label->Pic() && lb_width != -1) {
+		int label_width = label->Pic()->Width();
+		int label_height = label->Pic()->Height();
+		label->Pic()->Move(x_min-label_width-lb_right, (Pic()->Height() - label_height) / 2);
+	}
+
+	delete[] item_width;
+	delete[] item_height;
+	delete[] item_x;
+	delete[] item_y;
+};
+
+RadioButton::RadioButton(Event::Container& _container, PicContainer* _parent, const Rect& r_orig, int _x_size, int _y_size, int* _value_ptr, const Rect& _button_r, int _text_size, const Color& _fore, const Color& _pressed, const Color& _back) :
+	MenuItem(_parent, r_orig, _x_size, _y_size,_value_ptr),
+	container(_container), parent(_parent), text_size(_text_size), button_rect(_button_r), buttons(0),
+	fore_color(_fore), pressed_color(_pressed), back_color(_back) {
+}
+void RadioButton::Add(const char* s, bool is_center) {
+	Add(s, fore_color, pressed_color, back_color, is_center);
+}
+void RadioButton::Add(const char* s, const Color& fore, const Color& pressed, const Color& back, bool is_center) {
+	if (buttons >= x_size*y_size) {
+		fprintf(stderr,"too many buttons (%d/%d) in RadioButton::Add ; text = %s\n",x_size,y_size,s);
+		return;
+	}
+	TextButton* wid = new TextButton(container, PicNode(), s, text_size, TextButton::Attribute(is_center ? TextButton::CENTER : 0), button_rect, 1, fore, pressed, back);
+
+	wid->press_func = &PressCallback;
+	wid->press_pointer = (void*)this;
+
+	if (value_ptr && buttons == *value_ptr) wid->Toggle(true);
+	int x_pos, y_pos;
+	if (y_size == 0) x_pos=buttons;
+	else x_pos = buttons / y_size, y_pos = buttons % y_size;
+	item[x_pos + y_pos*x_size] = wid;
+	buttons++;
+};
+void RadioButton::PressCallback(void* pointer, Button* from) {
+	RadioButton* wid = (RadioButton*)pointer;
+	int i;
+	for (i=0; i<wid->x_size*wid->y_size; i++) {
+		if (from == wid->item[i]) {
+			wid->SetValue(i);
+			return;
+		}
+	}
+	return;
+}
+void RadioButton::SetValueImpl(int new_value) {
+	int i;
+	for (i=0; i<x_size*y_size; i++) {
+		Button* wid = dynamic_cast<Button*>(item[i]);
+		if (wid) {
+			if (i == new_value) wid->Toggle(true);
+			else wid->Toggle(false);
+		}
+	}
+}
new file mode 100644
--- /dev/null
+++ b/window/menuitem.h
@@ -0,0 +1,64 @@
+#ifndef __MENUITEM_H__
+#define __MENUITEM_H__
+
+#include"widget.h"
+
+#define MenuItem WidMenuItem
+#define MenuRadioButton WidMenuRadioButton
+#define MenuScale WidMenuScale
+
+// 必要なもの:
+//	
+//	ラベル:surfaceも貼れた方がよいが、まあいいや
+//	ラベル位置:ボタンの上、もしくは右
+//		右の場合:右中央へjustify するので、ラベル全体の幅と右マージンが必要
+//		上の場合:左下へjustify するので、左マージンと下マージンが必要
+
+//	内容:x,y個数を指定、その中で中央割り当て
+
+//		ラベル位置情報:上なら左下にjustify, 右なら右中央にjustify
+//		なので、下へのマージンと上へのマージン、
+//	ラベル+四角ボタン(チェックボックス)
+//		ボタンが押されるとdeactivateされる
+//
+//	ラジオボタン
+//		テキストボタンの集合体。x,y の個数を指定
+//	スケール
+
+struct MenuItem : PicWidget {
+	int x_size, y_size;
+	int menu_width, menu_height;
+	int lb_width, lb_right, lb_left, lb_bottom;
+	PicWidget* label;
+	int* value_ptr;
+	std::vector<PicWidget*> item;
+	typedef std::vector<PicWidget*>::iterator iterator;
+	MenuItem(PicContainer* parent, const Rect& r_orig, int x_size, int y_size, int* value_ptr);
+	void SetLabelLeft(PicWidget* lb, const Rect& min_rect, const Rect& min_margin);
+	void SetLabelTop(PicWidget* lb, const Rect& left_margin, const Rect& bottom_margin);
+	void pack(void);
+	void activate(void);
+	void deactivate(void);
+	// callback
+	typedef void (*SetFunc)(void* pointer, MenuItem* widget);
+	SetFunc set_func;
+	void* set_pointer;
+	void SetValue(int new_value);
+	virtual void SetValueImpl(int new_value) {};
+};
+
+struct RadioButton : MenuItem {
+	Event::Container& container;
+	PicContainer* parent;
+	int text_size;
+	Rect button_rect;
+	int buttons;
+	Color fore_color, pressed_color, back_color;
+	RadioButton(Event::Container& container, PicContainer* parent, const Rect& r_orig, int x_size, int y_size, int* value_ptr, const Rect& button_r, int text_size, const Color& fore, const Color& pressed, const Color& back);
+	void Add(const char* s, bool is_center = true);
+	void Add(const char* s, const Color& fore, const Color& pressed, const Color& back, bool is_center = true);
+	static void PressCallback(void* pointer, Button* from);
+	void SetValueImpl(int new_value);
+};
+
+#endif /* __MENUITEM_H__ */
new file mode 100644
--- /dev/null
+++ b/window/picture.cc
@@ -0,0 +1,1060 @@
+/*
+ * Copyright (c) 2004-2006  Kazunori "jagarl" Ueno
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include<stdio.h>
+#include<vector>
+#include<list>
+#include<algorithm>
+
+#include"rect.h"
+#include"event.h"
+#include"font/font.h"
+#include"font/text.h"
+#include"SDL_rotozoom.h"
+#include"system/file.h"
+
+#include"picture.h"
+
+using namespace std;
+
+int print_blit=0;
+inline void dprintf(const char* fmt, ...) {}
+/* render.cc */
+void DSurfaceBlitAlpha(Surface* src_o, const Rect& srcrect_o, Surface* dst_o, const Rect& dstrect_o, const unsigned char* alpha, const Rect& alpharect);
+void DSurfaceBlitSaturate(Surface* src_o, const Rect& srcrect, Surface* dst_o, const Rect& dstrect, unsigned char alpha);
+void DSurfaceBlitMultiply(Surface* src_o, const Rect& srcrect, Surface* dst_o, const Rect& dstrect);
+void DSurfaceFill(Surface* src, const Rect& rect, int r, int g, int b, int a=0xff); // クリア
+#if 0 /* DEBUG */
+#include<sys/types.h>
+#include<sys/time.h>
+#define dprintf printf
+static struct timeval tv;
+void gettm(void) {
+	gettimeofday(&tv, 0);
+}
+int calctm(void) {
+	struct timeval tv2;
+	gettimeofday(&tv2, 0);
+	int n = (tv2.tv_sec-tv.tv_sec)*100000 + (tv2.tv_usec-tv.tv_usec)/10;
+	return n;
+}
+#endif
+
+/******************************************
+** PicBase
+*/
+PicBase::PicBase(const Rect& _rel_pos, PicContainer* _parent, int _attr) :
+		parent(_parent), rel_pos(_rel_pos), rel_solid_area(0,0,0,0), clip_area(0,0,0,0),
+		is_hidden(true), is_hidden_now(true), is_cached(false),  attribute(_attr), surface_alpha_rect(0,0) {
+
+	if (parent) root = parent->root;
+	else root = 0;
+	surface_back = 0;
+	surface_own = 0;
+	surface_alpha = 0;
+	surface_x = 0; surface_y = 0;
+	surface_w = -1; surface_h = -1;
+	widget = 0;
+	attribute |= NO_PICTURE;
+	if ( (attribute & CACHE_BACK) && root) {
+		surface_back = root->NewSurface(rel_pos.width(), rel_pos.height(), NO_MASK);
+	}
+	
+	if (parent) {
+		parent->children.push_back(this);
+		z_pos = parent->children.end(); z_pos--;
+		distance_root = parent->DistanceRoot() + 1;
+	} else {
+		distance_root = 1;
+	}
+}
+PicBase::~PicBase() {
+	ClearAnm();
+	if (widget) {
+		fprintf(stderr,"Warning: PicBase::~PicBase: surface is disallocated but widget is still alive.\n");
+		widget->deactivate();
+	}
+	if (surface_back) root->DeleteSurface(surface_back);
+	if (surface_own && (attribute & SURFACE_FREE)) root->DeleteSurface(surface_own);
+	if (surface_alpha && (attribute & ALPHA_FREE)) delete surface_alpha;
+	iterator it;
+	if (parent) { // 自分を親から削除
+		parent->children.remove(this);
+		// root の update 情報から自分を削除
+		parent->Root().DeleteUpdatePic(this);
+		// 自分の領域を書き直す
+		Rect old_ppos = rel_pos;
+		parent->QueryAbsPos(old_ppos);
+		parent->ReBlit(old_ppos);
+	}
+}
+void PicBase::Blit(const Rect& rpos_orig) {
+	// 実際に描画する領域を得る
+	Rect rpos = rpos_orig;
+	// 親widget上に設定されたclip area 内に描画を限定する
+	if (clip_area.width() != 0) {
+		Rect clip = clip_area;
+		clip = child_pos(clip, this);
+		rpos.intersect(clip);
+	}
+	Rect apos = QueryAbsPos(rpos);
+	if (rpos.empty()) return;
+	// 必要に応じて保存、描画
+	if (attribute & CACHE_BACK) root->BlitSurface(root->surface, apos, surface_back, rpos);
+	if (! (attribute & NO_PICTURE)) {
+		rpos.rmove(surface_x, surface_y);
+		if (surface_w >= 0 && surface_h >= 0) {
+			Rect clip(surface_x, surface_y, surface_x+surface_w, surface_y+surface_h);
+			rpos.intersect(clip);
+		}
+//if (apos.ty < 200) fprintf(stderr,"Blit: %08x : (%d,%d,%d,%d) -> (%d,%d,%d,%d)\n",surface_own,rpos_orig.lx,rpos_orig.ty,rpos_orig.rx,rpos_orig.by,apos.lx,apos.ty,apos.rx,apos.by);
+		root->BlitSurface(surface_own, rpos, surface_alpha, surface_alpha_rect, root->surface, apos, attribute);
+		rpos.rmove(-surface_x, -surface_y);
+	} else if (parent == 0) { // 親がいないなら背景消去の責任をもつ
+		DSurfaceFill(root->surface, apos, 0, 0, 0);
+	}
+	PicContainer* cur = dynamic_cast<PicContainer*>(this);
+	if (cur && (!cur->children.empty())) {
+		cur->BlitChildren(rpos);
+	}
+}
+void PicBase::SimpleBlit(Surface* screen) {
+	// 実際に描画する領域を得る
+	Rect rpos(0, 0, rel_pos.width(), rel_pos.height());
+	Rect apos = QueryAbsPos(rpos);
+	if (rpos.empty()) return;
+	rpos.rmove(surface_x, surface_y);
+	if (surface_w >= 0 && surface_h >= 0) {
+		Rect clip(surface_x, surface_y, surface_x+surface_w, surface_y+surface_h);
+		rpos.intersect(clip);
+	}
+//if (apos.ty < 200) fprintf(stderr,"S-Blit: %08x : (%d,%d,%d,%d) -> (%d,%d,%d,%d)\n",surface_own,rel_pos.lx,rel_pos.ty,rel_pos.rx,rel_pos.by,apos.lx,apos.ty,apos.rx,apos.by);
+	root->BlitSurface(surface_own, rpos, surface_alpha, surface_alpha_rect, screen, apos, attribute);
+}
+
+Rect PicBase::QueryAbsPos(Rect& rpos) {
+	rpos.intersect(Rect(0, 0, rel_pos.width(), rel_pos.height()));
+	if (parent == 0) { // root container
+		return rpos;
+	}
+	// 親の座標に変換後、Query する
+	Rect ppos = parent_pos(rpos);
+	Rect apos = parent->QueryAbsPos(ppos);
+	rpos = child_pos(ppos, this);
+	return apos;
+};
+void PicBase::ReBlit(const Rect& rpos_c) {
+	Rect rpos = rpos_c;
+	Rect apos = QueryAbsPos(rpos);
+	
+	root->Update(this, rpos, apos);
+}
+void PicBase::ExecReBlit(const Rect& rpos_c) {
+	Rect rpos = rpos_c;
+	Rect abs_r = QueryAbsPos(rpos);
+	Rect ppos = parent_pos(rpos);
+if(print_blit) fprintf(stderr,"back.");
+	if (parent) parent->BlitBack(z_pos, ppos);
+if(print_blit) fprintf(stderr,"self.");
+	if (!is_hidden_now) Blit(rpos);
+if(print_blit) fprintf(stderr,"front.");
+	if (parent) parent->BlitFront(z_pos, ppos);
+if(print_blit) fprintf(stderr,"end.");
+}
+
+void PicBase::ZMove(PicBase* move_to) {
+	if (parent == 0) {
+		fprintf(stderr,"Warning: PicBase::ZMove is called by root.\n");
+		return;
+	}
+	if (move_to == ZMOVE_TOP) {
+		if (this == parent->children.back()) return;
+	} else if (move_to == ZMOVE_BOTTOM) {
+		if (this == parent->children.front()) return;
+	} else if (move_to == this) {
+		fprintf(stderr,"Error: PicBase::ZMove : move in front of itself!\n");
+		return;
+	} else if (move_to && move_to->parent != parent) {
+		fprintf(stderr,"Error: PicBase::ZMove was called with a no-brother picture\n");
+		return;
+	}
+	// move_to と zpos のうち、後ろの方の picture から書きなおす必要がある
+	iterator redraw_zpos = z_pos; redraw_zpos++;
+	if (move_to == ZMOVE_BOTTOM) { // 最背面へ
+		parent->children.erase(z_pos);
+		parent->children.push_front(this);
+		z_pos = parent->children.begin();
+		redraw_zpos = parent->children.begin();
+	} else if (move_to == ZMOVE_TOP) { // 最前面へ
+		redraw_zpos = z_pos; redraw_zpos++;
+		parent->children.erase(z_pos);
+		parent->children.push_back(this);
+		z_pos = parent->children.end(); z_pos--;
+	} else {
+	int dis_to = distance(move_to->parent->children.begin(), move_to->z_pos);
+	int dis_cur = distance(parent->children.begin(), z_pos);
+		if (dis_cur < dis_to) redraw_zpos = move_to->z_pos;
+		parent->children.erase(z_pos);
+		iterator insert_pos = move_to->z_pos; insert_pos++;
+		parent->children.insert(insert_pos, this);
+		z_pos = move_to->z_pos; z_pos++;
+	}
+	if (! is_hidden_now) {
+		is_cached = false;
+		ReBlit();
+		/* @@@ parent->Blit() と Blit() の違いが分からないので修正 06/12/02
+		Rect ppos = rel_pos;
+		parent->QueryAbsPos(ppos);
+		parent->ReBlit(ppos);
+		*/
+	}
+};
+void PicBase::RMove(int add_x, int add_y) {
+	Rect old_ppos = rel_pos;
+	rel_pos.rmove(add_x, add_y);
+	parent->QueryAbsPos(old_ppos);
+	parent->ReBlit(old_ppos);
+	ReBlit();
+
+	if (widget) {
+		Rect new_ppos = rel_pos;
+		Rect new_apos = parent->QueryAbsPos(new_ppos);
+		widget->SetRegion(new_apos);
+	}
+}
+void PicBase::Move(int new_rx, int new_ry) {
+	RMove(new_rx-rel_pos.lx, new_ry-rel_pos.ty);
+}
+void PicBase::SetEventWidget(PicWidget* new_widget) {
+	widget = new_widget;
+	if (widget) {
+		Rect new_ppos = rel_pos;
+		Rect apos = parent->QueryAbsPos(new_ppos);
+		widget->SetRegion(apos);
+	}
+}
+void PicBase::show_all(void) {
+	PicContainer*  cont = dynamic_cast<PicContainer*>(this);
+	if (cont && (!cont->children.empty())) cont->set_showflag();
+	show();
+}
+bool PicBase::IsParent(PicBase* to) {
+	if (parent == 0) return false;
+	if (parent == to) return true;
+	return parent->IsParent(to);
+}
+void PicBase::show(void) {
+	/* 自分の親がすべて shown か? */
+	PicContainer* cur;
+	for (cur = parent; cur != 0; cur = cur->parent)
+		if (cur->is_hidden) break;
+	if (cur) { // 親が隠れているので表示はしない
+		is_hidden = false;
+		is_hidden_now = true;
+		return;
+	}
+	if (is_hidden == false) return; // すでに表示されているのでなにもしない
+	if (widget) {
+		widget->activate();
+	}
+	is_hidden = false;
+	is_hidden_now = false;
+	is_cached = false;
+	cur = dynamic_cast<PicContainer*>(this);
+	if (cur && (!cur->children.empty())) cur->set_nowhiddenflag(false);
+	ReBlit();
+}
+void PicBase::hide(void) {
+	if (is_hidden) return;
+	if (widget) {
+		widget->deactivate();
+	}
+	is_hidden = true;
+	is_hidden_now = true;
+	is_cached = false;
+	PicContainer* cur = dynamic_cast<PicContainer*>(this);
+	if (cur && (!cur->children.empty())) cur->set_nowhiddenflag(true);
+	ReBlit();
+}
+void PicBase::SetSurfaceAlpha(const unsigned char* alpha, const Rect& alpha_r) {
+	if (attribute & ALPHA_FREE) {
+		if (surface_alpha) delete[] surface_alpha;
+		surface_alpha = 0;
+	}
+	surface_alpha = alpha;
+	surface_alpha_rect = alpha_r;
+	if (!is_hidden) ReBlit();
+}
+void PicBase::SetSurfaceColorKey(int r, int g, int b) {
+	surface_alpha = 0;
+	surface_alpha_rect = Rect(0,0);
+	attribute &= ~(BLIT_SATURATE | BLIT_MULTIPLY);
+	if (surface_own) {
+		int key = SDL_MapRGB( ((SDL_Surface*)surface_own)->format, r, g, b);
+		key |= 0xff000000;
+		SDL_SetColorKey( (SDL_Surface*)surface_own, SDL_SRCCOLORKEY, key);
+	}
+	if (!is_hidden) ReBlit();
+}
+void PicBase::SetSurfaceAlphaFile(const char* file) {
+
+	/* ファイルを元に alpha 画像を作成する */
+	/* ファイル: パルフェの 'fil' ファイル */
+	ARCINFO* info = file_searcher.Find(FILESEARCH::PDT, file,"fil");
+	if (info == 0) return;
+	char* new_alpha = info->CopyRead();
+	int alpha_size = info->Size();
+	delete info;
+	Rect sr(0,0); int w,h;
+	if (surface_own == 0 || new_alpha == 0) {
+err_ret:
+		if (new_alpha) delete[] new_alpha;
+		SetSurfaceAlpha(0,Rect(0,0));
+		return;
+	}
+	sr = Rect(*surface_own);
+	w = sr.width();
+	h = sr.height();
+	if (alpha_size < w*h) goto err_ret;
+	int i,j;
+	if ( ((SDL_Surface*)surface_own)->format->Amask == 0) { // mask を surface に繰り込む
+		Surface* dest = root->NewSurface(w,h, ALPHA_MASK);
+		for (i=0; i<h; i++) {
+			char* a = new_alpha + w*i;
+			char* s = (char*)((SDL_Surface*)surface_own)->pixels + ((SDL_Surface*)surface_own)->pitch*i;
+			char* d = (char*)((SDL_Surface*)dest)->pixels + ((SDL_Surface*)dest)->pitch*i;
+			int sbpp = ((SDL_Surface*)surface_own)->format->BytesPerPixel;
+			int dbpp = ((SDL_Surface*)dest)->format->BytesPerPixel;
+
+			for (j=0; j<w; j++) {
+				int d = read_little_endian_int(s);
+				d &= 0xffffff;
+				if (d == 0) ;
+				else if (*a == 0) d |= 0xff000000;
+				else d |= (int(*a) << 24);
+				s += sbpp; d += dbpp; a++;
+			}
+		}
+		delete new_alpha;
+		root->DeleteSurface(surface_own);
+		surface_own = dest;
+		SetSurfaceAlpha(0, Rect(0,0));
+	} else { // 外部にマスク作成
+		/* マスクのうち、0xff であるべき部分を画像から判別、変更する */
+		for (i=0; i<h; i++) {
+			char* a = new_alpha + w*i;
+			char* s = (char*)((SDL_Surface*)surface_own)->pixels + ((SDL_Surface*)surface_own)->pitch*i;
+			int bpp = ((SDL_Surface*)surface_own)->format->BytesPerPixel;
+			for (j=0; j<w; j++) {
+				if ( ((*(int*)s) & 0xffffff) == 0) *a = 0;
+				else if (*a == 0) *a = 0xff;
+				s += bpp; a++;
+			}
+		}
+		SetSurfaceAlpha( (unsigned char*)new_alpha, Rect(0,0,w,h));
+		attribute |= ALPHA_FREE;
+	}
+}
+void PicBase::SetSurface(const char* filename, int x, int y) {
+	Surface* s = root->NewSurface(filename);
+	SetSurface(s, x, y, SURFACE_FREE);
+}
+void PicBase::SetSurface(Surface* new_surface, int x, int y, int new_attr) {
+	if (surface_own && (attribute & SURFACE_FREE)) {
+		root->DeleteSurface(surface_own);
+	}
+	attribute &= ~(SURFACE_FREE | BLIT_SATURATE | BLIT_MULTIPLY | NO_PICTURE | SOLID);
+	attribute |= new_attr;
+	surface_own = new_surface;
+	surface_x = x;
+	surface_y = y;
+	surface_w = -1;
+	surface_h = -1;
+
+	if (attribute & FIT_SURFACE) {
+		// surface の大きさに自分の大きさを変更
+		parent->ReBlit(rel_pos);
+		if (surface_own == 0) {
+			rel_pos = Rect(rel_pos.lx, rel_pos.ty);
+		} else {
+			Rect r(*surface_own);
+			int w = r.width(), h = r.height();
+			w -= x; h -= y;
+			rel_pos = Rect(rel_pos.lx, rel_pos.ty, rel_pos.lx+w, rel_pos.ty+h);
+		}
+	}
+
+	rel_solid_area = Rect(0,0,0,0);
+	if (! surface_own) attribute |= NO_PICTURE;
+	else if (root->with_mask(surface_own) == 0) {
+		attribute |= SOLID;
+		rel_solid_area = rel_pos;
+	}
+	if (!is_hidden) ReBlit();
+}
+void PicBase::SetSurfacePos(int x, int y) {
+	if (surface_x == x && surface_y == y && surface_w == -1 && surface_h == -1) return;
+	surface_x = x; surface_y = y;
+	surface_w = -1; surface_h = -1;
+	if (!is_hidden_now) ReBlit();
+}
+int PicBase::SurfacePosX(void) {
+	return surface_x;
+}
+int PicBase::SurfacePosY(void) {
+	return surface_y;
+}
+void PicBase::SetSurfaceRect(const Rect& r) {
+	if (surface_x == r.lx && surface_y == r.ty && surface_w == r.width() && surface_h == r.height()) return;
+	surface_x = r.lx; surface_y = r.ty;
+	surface_w = r.width(); surface_h = r.height();
+	parent->ReBlit(rel_pos);
+	rel_pos = Rect(rel_pos.lx, rel_pos.ty, rel_pos.lx+surface_w, rel_pos.ty+surface_h);
+	if (widget) {
+		Rect new_ppos = rel_pos;
+		Rect apos = parent->QueryAbsPos(new_ppos);
+		widget->SetRegion(apos);
+	}
+	if (!is_hidden_now) ReBlit();
+}
+void PicBase::SetClipArea(const Rect& r) {
+	if (clip_area == r) return;
+	clip_area = r;
+	parent->ReBlit(rel_pos);
+}
+
+void PicBase::SetSurfaceAttribute(int new_attribute) {
+	attribute &= ~(BLIT_SATURATE | BLIT_MULTIPLY);
+	attribute |= new_attribute & (BLIT_SATURATE | BLIT_MULTIPLY);
+	if (new_attribute & (BLIT_SATURATE | BLIT_MULTIPLY)) {
+		rel_solid_area = Rect(0,0);
+	}
+}
+void PicBase::SetSurfaceFreeFlag(bool flag) {
+	if (flag) attribute |= SURFACE_FREE;
+	else attribute &= ~SURFACE_FREE;
+
+}
+
+/******************************************
+** PicContainer
+*/
+PicContainer::PicContainer(const Rect& rel_pos, PicContainer* parent, int attr) :
+	PicBase(rel_pos, parent, attr) {
+}
+PicContainer::~PicContainer() {
+	iterator end = children.end();
+	for (iterator it = children.begin(); it != end; ) {
+		iterator it_next = it; it_next++;
+		if ((*it)->widget) delete (*it)->widget; // picture にwidget が付属しているなら、そちらをdelete
+		else delete (*it);
+		it = it_next;
+	}
+}
+void PicContainer::BlitBack(iterator z, Rect rpos) {
+	rpos.intersect(Rect(0, 0, rel_pos.width(), rel_pos.height()));
+	if (rpos.empty()) return;
+	iterator end = children.end(), begin = children.begin(); iterator it = begin;
+
+	Rect ppos = parent_pos(rpos);
+	if (is_hidden_now) goto parent_redraw;
+	// cache されている領域を探す
+	// z自身がキャッシュしていれば、ここで終了
+	if ( ((*z)->attribute & CACHE_BACK) && ( (*z)->is_cached) && (*z)->rel_pos.is_inner(rpos)) {
+		Rect cpos = child_pos(rpos, *z);
+		Rect apos = (*z)->QueryAbsPos(cpos);
+		root->BlitSurface( (*z)->surface_back, cpos, root->surface, apos);
+		return;
+	}
+	// z より下の子がキャッシュ、あるいは SOLID 描画できないか?
+	for (it = z; it != begin;) { // 子がcontainerの場合のチェックは省略
+		it--;
+		if ( (*it)->is_hidden_now) continue;
+		if ( (*it)->rel_pos.is_crossed(rpos)) {
+			if ( ((*it)->attribute & CACHE_BACK) && ((*it)->is_cached) && (*it)->rel_pos.is_inner(rpos)) {
+				Rect cpos = child_pos(rpos, *it);
+				Rect apos = (*it)->QueryAbsPos(cpos);
+				root->BlitSurface( (*it)->surface_back, cpos, root->surface, apos);
+				goto children_redraw;
+			}
+			if ( (*it)->rel_solid_area.is_inner(rpos)) {
+				goto children_redraw;
+			}
+		}
+	}
+	// 自分自身がキャッシュ、あるいは SOLID 描画できないか?
+	if (rel_solid_area.is_inner(ppos)) {
+		goto self_redraw;
+	}
+	if ( (attribute & CACHE_BACK) && is_cached) {
+		Rect cpos = child_pos(rpos, *z);
+		Rect apos = (*z)->QueryAbsPos(cpos);
+		Rect draw_rpos = (*z)->parent_pos(cpos);
+if(print_blit) fprintf(stderr,"cahce.");
+		root->BlitSurface(surface_back, draw_rpos, root->surface, apos);
+		goto self_redraw;
+	}
+parent_redraw:
+	if (parent) {
+		Rect ppos = parent_pos(rpos);
+if(print_blit) fprintf(stderr,"parent-back.");
+		parent->BlitBack(z_pos, ppos);
+	}
+	if (is_hidden_now) return;
+self_redraw:
+if(print_blit) fprintf(stderr,"back-self.");
+	BlitSelf(rpos); // 子は描画せず、自分だけ描画
+children_redraw:
+	for (; it != z; it++) {
+		if ( (*it)->is_hidden_now) continue;
+		if ( (*it)->rel_pos.is_crossed(rpos)) {
+			Rect cpos = child_pos(rpos, *it);
+			(*it)->Blit(cpos);
+		}
+	}
+}
+void PicContainer::BlitChildren(Rect rpos) {
+if (print_blit) fprintf(stderr,"bc.");
+	iterator end = children.end();
+	for (iterator it = children.begin(); it != end; it++) {
+if ( (*it)->is_hidden_now) if(print_blit) fprintf(stderr,"bch %08x;",*it);
+		if ( (*it)->is_hidden_now) continue;
+		if ( (*it)->rel_pos.is_crossed(rpos)) {
+			Rect cpos = child_pos(rpos, *it);
+			(*it)->Blit(cpos);
+		}
+	}
+}
+void PicContainer::BlitFront(iterator z, Rect rpos) {
+	rpos.intersect(Rect(0, 0, rel_pos.width(), rel_pos.height()));
+	if (rpos.empty()) return;
+	iterator end = children.end(); iterator it;
+	z++;
+	for (it = z; it != end; it++) {
+		if ( (*it)->is_hidden_now) continue;
+		if ( (*it)->rel_pos.is_crossed(rpos)) {
+			Rect cpos = child_pos(rpos, *it);
+			(*it)->Blit(cpos);
+		}
+	}
+	if (parent) {
+		Rect ppos = parent_pos(rpos);
+		parent->BlitFront(z_pos, ppos);
+	}
+};
+void PicContainer::BlitSelf(Rect rpos) {
+	// 実際に描画する領域を得る
+	rpos.intersect(Rect(0, 0, rel_pos.width(), rel_pos.height()));
+	if (rpos.empty()) return;
+	Rect apos = QueryAbsPos(rpos);
+	// 必要に応じて保存、描画
+if(print_blit) fprintf(stderr,"self-back.");
+	if (attribute & CACHE_BACK) root->BlitSurface(root->surface, apos, surface_back, rpos);
+	if (! (attribute & NO_PICTURE)) {
+		rpos.rmove(surface_x, surface_y);
+		if (surface_w >= 0 && surface_h >= 0) {
+			Rect clip(0, 0, surface_w, surface_h);
+			clip.rmove(rpos.lx, rpos.ty);
+			rpos.intersect(clip);
+		}
+if(print_blit) fprintf(stderr,"self-blit.");
+		root->BlitSurface(surface_own, rpos, surface_alpha, surface_alpha_rect, root->surface, apos, attribute);
+	} else if (parent == 0) { // 親がいないなら背景消去の責任をもつ
+		DSurfaceFill(root->surface, apos, 0, 0, 0);
+	}
+}
+
+void PicContainer::set_showflag(void) {
+	iterator end = children.end();
+	for (iterator it = children.begin(); it != end; it++) {
+		(*it)->is_hidden = false;
+		PicContainer* next = dynamic_cast<PicContainer*>(*it);
+		if (next && (!next->children.empty())) next->set_showflag();
+	}
+}
+void PicContainer::set_nowhiddenflag(bool is_hide) {
+	iterator end = children.end();
+	for (iterator it = children.begin(); it != end; it++) {
+		if (is_hide) (*it)->is_hidden_now = true;
+		else (*it)->is_hidden_now = (*it)->is_hidden;
+		if ( (*it)->widget) {
+			if ((*it)->is_hidden_now) (*it)->widget->deactivate();
+			else (*it)->widget->activate();
+		}
+		PicContainer* next = dynamic_cast<PicContainer*>(*it);
+		if (next && (!next->children.empty())) next->set_nowhiddenflag(is_hide);
+	}
+}
+void PicContainer::RMove(int add_x, int add_y) { // event widget の移動があり得るので子についてもRMoveを呼び出す
+	PicBase::RMove(add_x, add_y);
+	iterator end = children.end();
+	for (iterator it = children.begin(); it != end; it++) {
+		(*it)->RMove(0,0);
+	}
+}
+
+PicBase* PicContainer::create_leaf(const Rect& rel_pos, int attr) {
+	return new PicBase(rel_pos, this, attr);
+}
+PicContainer* PicContainer::create_node(const Rect& rel_pos, int attr) {
+	return new PicContainer(rel_pos, this, attr);
+}
+
+/***************************************************************
+**
+** PicWidget
+*/
+
+PicWidget::PicWidget(void) {
+	pic = 0;
+}
+PicWidget::~PicWidget() {
+	if (pic) {
+		pic->SetEventWidget(0);
+		delete pic;
+	}
+	pic = 0;
+}
+void PicWidget::SetPic(PicBase* new_pic) {
+	if (pic) {
+		pic->SetEventWidget(0);
+		delete pic;
+	}
+	pic = new_pic;
+	if (pic) pic->SetEventWidget(this);
+}
+PicBase* PicWidget::Pic(void) {
+	if (pic == 0) {
+		fprintf(stderr,"Error: PicWidget::Pic returns zero.\n");
+	}
+	return pic;
+}
+PicContainer* PicWidget::PicNode(void) {
+	PicContainer* node = dynamic_cast<PicContainer*>(pic);
+	if (node == 0) {
+		fprintf(stderr,"Error: PicWidget::PicNode returns zero.\n");
+	}
+	return node;
+}
+
+/******************************************
+** FileToSurface
+*/
+
+#include<list>
+#include<map>
+#include<string>
+using namespace std;
+struct SurfaceIndex {
+	typedef list<SurfaceIndex*>::iterator qiterator;
+	string filename;
+	Surface* surface;
+	qiterator qpos;
+	int ref_count;
+};
+
+class FileToSurface {
+	typedef list<SurfaceIndex*>::iterator qiterator;
+
+	list<SurfaceIndex*> queue;
+	map<string, SurfaceIndex*> findex;
+	map<Surface*, SurfaceIndex*> mindex;
+	int count;
+	int count_max;
+	const PicRoot& root;
+	bool DeleteData(SurfaceIndex* data);
+	Surface* LoadSurface(string name, char*& mem);
+public:
+	FileToSurface(const PicRoot& root);
+	~FileToSurface(void);
+	Surface* Load(string name);
+	bool Free(Surface* s);
+};
+
+FileToSurface::FileToSurface(const PicRoot& _root) : root(_root) {
+	count = 0;
+	count_max = 32; // キャッシュ量(決め打ち)
+};
+FileToSurface::~FileToSurface() {
+	qiterator it;
+	for (it=queue.begin(); it != queue.end(); it++) {
+		if ( (*it)->ref_count) {
+			fprintf(stderr, "Warning: FileToSurface: delete referenced surface named '%s'\n",(*it)->filename.c_str());
+		}
+		root.DeleteSurfaceImpl( (*it)->surface);
+		delete *it;
+	}
+}
+inline bool FileToSurface::DeleteData(SurfaceIndex* data) {
+	if ( data->ref_count) return false;
+	findex.erase(data->filename);
+	mindex.erase(data->surface);
+	queue.erase(data->qpos);
+	root.DeleteSurfaceImpl(data->surface);
+	delete data;
+	count--;
+	return true;
+}
+inline Surface* FileToSurface::LoadSurface(string name, char*& mem) {
+	ARCINFO* info = file_searcher.Find(FILESEARCH::PDT, name.c_str(),"pdt");
+	if (info == 0) return 0;
+	GRPCONV* conv = GRPCONV::AssignConverter(info);
+	if (conv == 0) { delete info;return 0;}
+	mem = (char*)malloc(conv->Width() * conv->Height() * 4 + 1024);
+	Surface* s = 0;
+	if (conv->Read(mem)) {
+		MaskType is_mask = conv->IsMask() ? ALPHA_MASK : NO_MASK;
+		if (is_mask == ALPHA_MASK) { // alpha がすべて 0xff ならマスク無しとする
+			int len = conv->Width()*conv->Height();
+			unsigned int* d = (unsigned int*)mem;
+			int i; for (i=0; i<len; i++) {
+				if ( (*d&0xff000000) != 0xff000000) break;
+				d++;
+			}
+			if (i == len) {
+				is_mask = NO_MASK;
+			}
+		}
+		s = root.NewSurfaceFromRGBAData(conv->Width(), conv->Height(), mem, is_mask);
+	}
+	delete conv; delete info; // delete data;
+	return s;
+}
+Surface* FileToSurface::Load(string name) {
+	if (findex.find(name) != findex.end()) {
+		findex[name]->ref_count++;
+		return findex[name]->surface;
+	}
+	char* mem;
+	Surface* surface = LoadSurface(name, mem);
+	if (surface == 0) return 0;
+
+	while (count >= count_max) { // count_max 以上のデータを可能なら削除する
+		qiterator it;
+		for (it=queue.begin(); it != queue.end(); it++) {
+			if (DeleteData(*it)) break;
+		}
+		if (it == queue.end()) break; // 全データが使用中なら終了
+	}
+	SurfaceIndex* new_index = new SurfaceIndex;
+	new_index->filename = name;
+	new_index->surface = surface;
+	findex[name] = new_index;
+	mindex[surface] = new_index;
+	queue.push_back(new_index);
+	new_index->qpos = queue.end(); new_index->qpos--;
+	new_index->ref_count = 1;
+	count++;
+	return surface;
+}
+bool FileToSurface::Free(Surface* s) {
+	if (mindex.find(s) == mindex.end()) {
+		return false;
+	}
+	SurfaceIndex* index = mindex[s];
+	if (index->ref_count == 0) DeleteData(index);
+	else index->ref_count--;
+	return true;
+}
+
+/******************************************
+** PicRoot
+*/
+#include<SDL.h>
+
+#include"surface.h"
+
+#define DefaultRmask 0xff0000
+#define DefaultGmask 0xff00
+#define DefaultBmask 0xff
+#define DefaultAmask 0xff000000
+#define DefaultBpp 32
+
+PicRoot::PicRoot(void) {
+	hw_surface = (Surface*)SDL_GetVideoSurface();
+	SDL_PixelFormat* fmt_SDL = hw_surface->format;
+	if (fmt_SDL->BitsPerPixel == DefaultBpp && fmt_SDL->Rmask == DefaultRmask && fmt_SDL->Gmask == DefaultGmask && fmt_SDL->Bmask == DefaultBmask) { 
+		surface = hw_surface;
+	} else {
+		surface = (Surface*)SDL_CreateRGBSurface(0, hw_surface->w, hw_surface->h, DefaultBpp, DefaultRmask, DefaultGmask, DefaultBmask, 0);
+	}
+
+	Rect rpos(0, 0, surface->w, surface->h);
+	root = new PicContainer(rpos, 0, 0);
+	root->InitRoot(this);
+	root->show();
+	ftosurface = new FileToSurface(*this);
+	width = surface->w;
+	height = surface->h;
+	return;
+}
+PicRoot::~PicRoot() {
+	// if (surface) DeleteSurfaceImpl(surface); // SDL_GetVideoSurface() した surface は開放の必要がないらしい
+	surface = 0;
+	delete root;
+	delete ftosurface;
+}
+void PicRoot::Update(PicBase* pic, const Rect& rpos, const Rect& apos) {
+	update_rects.push_back(UpdateItem(pic, rpos, apos));
+}
+bool PicRoot::UpdateItem::less(const PicRoot::UpdateItem& a, const PicRoot::UpdateItem& b) {
+	return a.pic->DistanceRoot() < b.pic->DistanceRoot();
+}
+void PicRoot::DeleteUpdatePic(PicBase* pic) {
+	vector<UpdateItem>::iterator it = update_rects.begin();
+	while(it != update_rects.end()) {
+		if (it->pic == pic) {
+			update_rects.erase(it);
+			it = update_rects.begin();
+			continue;
+		}
+		it++;
+	}
+	return;
+}
+void PicRoot::ExecUpdate(void) {
+	/* 共通する領域を消去する */
+	sort(update_rects.begin(), update_rects.end(), UpdateItem::less);
+	vector<UpdateItem>::iterator it;
+	vector<UpdateItem>::iterator end = update_rects.end();
+if(print_blit){
+	fprintf(stderr,"ExecUpdate Start: \n\t");
+	for (it=update_rects.begin(); it != end; it++) {
+		fprintf(stderr,"(%d,%d,%d,%d), ",it->apos.lx,it->apos.ty,it->apos.rx,it->apos.by);
+	}
+	fprintf(stderr,"\n");
+}
+	for (it=update_rects.begin(); it != end; it++) {
+		if (it->rpos.width() == 0) continue;
+
+		Rect apos = it->apos;
+		PicBase* pic = it->pic;
+
+		vector<UpdateItem>::iterator jt = it; jt++;
+		for (; jt != end; jt++) {
+			if (apos.is_inner(jt->apos)) {
+				if (jt->pic == pic || jt->pic->IsParent(pic)) { // 親が共通、かつ領域も共通
+					jt->rpos = Rect(0,0); // empty rect をセット
+					jt->apos = Rect(0,0);
+				}
+			} else if (jt->apos.is_inner(apos)) { // 相手に自分が包含される
+				if (jt->pic == pic || jt->pic->IsParent(pic)) { // 親が共通、かつ領域も共通
+					it->rpos = Rect(0,0);
+					it->apos = Rect(0,0);
+					break;
+				}
+			}
+		}
+	}
+if(print_blit){
+	fprintf(stderr,"->\t");
+	for (it=update_rects.begin(); it != end; it++) {
+		fprintf(stderr,"(%d,%d,%d,%d), ",it->apos.lx,it->apos.ty,it->apos.rx,it->apos.by);
+	}
+	fprintf(stderr,"\n");
+}
+
+	int num = update_rects.size();
+	SDL_Rect* r = new SDL_Rect[num];
+	Rect confine = Rect(0, 0, surface->w, surface->h);
+	int n = 0;
+	int i;
+	for (i=0; i<num; i++) {
+		UpdateItem& item = update_rects[i];
+		Rect& ur = item.apos;
+		if (ur.width() == 0) continue;
+if(print_blit)fprintf(stderr,"%08x: %d,%d,%d,%d",item.pic, item.apos.lx, item.apos.ty, item.apos.rx, item.apos.by);
+
+		item.pic->ExecReBlit(item.rpos);
+if(print_blit)fprintf(stderr,"\n");
+		ur.intersect(confine);
+		r[n].x = ur.lx;
+		r[n].y = ur.ty;
+		r[n].w = ur.rx - ur.lx;
+		r[n].h = ur.by - ur.ty;
+		if (surface != hw_surface) SDL_BlitSurface(surface, &r[n], hw_surface, &r[n]);
+		n++;
+	}
+if(print_blit)fprintf(stderr,"\n");
+	SDL_UpdateRects(hw_surface, n, r);
+	delete[] r; update_rects.clear();
+}
+
+Surface* PicRoot::NewSurface(int w, int h, MaskType with_mask) const {
+	Surface* s;
+	if (with_mask == ALPHA_MASK) {
+		s = (Surface*)SDL_CreateRGBSurface(SDL_SRCALPHA, w, h, DefaultBpp, DefaultRmask, DefaultGmask, DefaultBmask, DefaultAmask);
+	} else {
+		s = (Surface*)SDL_CreateRGBSurface(0, w, h, DefaultBpp, DefaultRmask, DefaultGmask, DefaultBmask, 0);
+	}
+	return s;
+}
+
+Surface* PicRoot::NewSurfaceFromRGBAData(int w, int h, char* data, MaskType with_mask) const {
+	int amask = (with_mask == ALPHA_MASK) ? DefaultAmask : 0;
+	Surface* s = (Surface*)SDL_CreateRGBSurfaceFrom(data, w, h, DefaultBpp, w*4, DefaultRmask, DefaultGmask, DefaultBmask, amask);
+	s->flags &= ~SDL_PREALLOC;
+	return s;
+};
+Surface* PicRoot::NewSurface(const char* f, MaskType with_mask) {
+	if (f == 0) return 0;
+	Surface* s = ftosurface->Load(f);
+	if (s == 0) return 0;
+	if (with_mask == COLOR_MASK) {
+		SDL_SetColorKey( (SDL_Surface*)s, SDL_SRCCOLORKEY, *(Uint32*)s->pixels);
+	}
+	/* xkanon の残骸 */
+	if (strcmp(f, "grdat") == 0)
+        	SDL_SetColorKey(s, SDL_SRCCOLORKEY, 0x55aa66);
+	return s;
+}
+Surface* PicRoot::RotZoomSurface(Surface* from, double zoom, double rotate) {
+	Surface* ret = (Surface*)rotozoomSurface( (SDL_Surface*)from, rotate, zoom, SMOOTHING_OFF);
+	return ret;
+}
+void PicRoot::DeleteSurfaceImpl(Surface* s) const {
+	SDL_FreeSurface(s);
+}
+void PicRoot::DeleteSurface(Surface* s) {
+	if (!ftosurface->Free(s))
+		DeleteSurfaceImpl(s);
+}
+inline SDL_Rect SDLed(const Rect& rect) {
+	SDL_Rect r;
+	r.x = rect.lx;
+	r.y = rect.ty;
+	r.w = rect.rx-rect.lx;
+	r.h = rect.by-rect.ty;
+	return r;
+}
+
+#ifndef ALPHA_MAX
+#define ALPHA_MAX 255
+#endif
+void PicRoot::BlitSurface(Surface* src, const Rect& src_r, const unsigned char* alpha, const Rect& alpha_r, Surface* dest, const Rect& dest_r, int attribute) const {
+if (print_blit) fprintf(stderr," s %08x %d:%d:%d:%d;",src, dest_r.lx, dest_r.ty, dest_r.rx, dest_r.by);
+	SDL_Rect sr = SDLed(src_r); SDL_Rect dr = SDLed(dest_r);
+special_blit:
+	if (attribute & PicBase::BLIT_MULTIPLY) {
+if (print_blit) fprintf(stderr,"M");
+		DSurfaceBlitMultiply(src, src_r, dest, dest_r);
+		return;
+	} else if (attribute & PicBase::BLIT_SATURATE) {
+		if (src->format->Amask != 0) goto normal_blit;
+if (print_blit) fprintf(stderr,"S");
+		unsigned char a = 255;
+		if (alpha && alpha_r.width() >= 1 && alpha_r.height() >= 1) a = *alpha;
+		DSurfaceBlitSaturate(src, src_r, dest, dest_r, a);
+		return;
+	}
+normal_blit:
+if (print_blit) fprintf(stderr,"N");
+	if (alpha == 0 || alpha_r.width() == 0) { // simple blit
+if (print_blit) fprintf(stderr,"X");
+		SDL_BlitSurface(src, &sr, dest, &dr);
+		return;
+	}
+	if (alpha_r.width() == 1 && alpha_r.height() == 1) {
+		if (*alpha == 255) {
+if (print_blit) fprintf(stderr,"Y");
+			SDL_BlitSurface(src, &sr, dest, &dr);
+			return;
+		}
+		if (src->format->Amask == 0) { // use per-surface alpha
+if (print_blit) fprintf(stderr,"Z");
+			SDL_SetAlpha(src, SDL_SRCALPHA, *alpha);
+			SDL_BlitSurface(src, &sr, dest, &dr);
+			SDL_SetAlpha(src, 0, 0);
+			return;
+		}
+	}
+	// generic alpha blit
+if (print_blit) fprintf(stderr,"W");
+	DSurfaceBlitAlpha(src, src_r, dest, dest_r, alpha, alpha_r);
+	return;
+}
+
+bool PicRoot::with_mask(Surface* s) {
+	return s->format->Amask != 0;
+}
+
+#if USE_X11
+#include<SDL_syswm.h>
+#include<X11/Xlib.h>
+#include<X11/Xutil.h>
+#endif /* USE_X11 */
+void PicRoot::SetWindowCaption(const char* caption) {
+#if USE_X11
+//	SDL_WM_SetCaption(caption, 0);
+	// SDLの関数では2バイト文字をサポートしてくれないので、同等の内容に修正
+	SDL_SysWMinfo info;
+	memset(&info,0,sizeof(info));
+	SDL_VERSION(&(info.version));
+	if (SDL_GetWMInfo(&info) == 1) {
+		Display* display = info.info.x11.display;
+		Window wm = info.info.x11.wmwindow;
+		if (wm == 0) wm = info.info.x11.window;
+		if (wm != 0) {
+			XTextProperty titleprop;
+			XmbTextListToTextProperty(display, (char**)&caption, 1, XCompoundTextStyle, &titleprop);
+			XSetWMName(display, wm, &titleprop);
+			XSetWMIconName(display, wm, &titleprop);
+			XFree(titleprop.value);
+		}
+		XSync(display, False);
+	}
+#endif /* USE_X11 */
+}
+
+/************************************************************
+** PicAnm
+*/
+
+void PicBase::ClearAnm(void) {
+	while(!anm.empty()) {
+		delete anm.back();
+	}
+}
+PicAnm::PicAnm(PicBase* _pic) {
+	pic.push_back(_pic);
+	pic[0]->anm.push_back(this);
+	return;
+	
+}
+PicAnm::PicAnm(vector<PicBase*> _pic) : pic(_pic) {
+	if (pic.empty()) return;
+	pic[0]->anm.push_back(this);
+	return;
+}
+PicAnm::~PicAnm() {
+	vector<PicAnm*>::iterator it = find(pic[0]->anm.begin(), pic[0]->anm.end(), this);
+	if (it == pic[0]->anm.end()) {
+		fprintf(stderr,"Cannot found this in PicAnm::~PicAnm()");
+	} else {
+		pic[0]->anm.erase(it);
+	}
+}
new file mode 100644
--- /dev/null
+++ b/window/picture.h
@@ -0,0 +1,226 @@
+#ifndef __PICTURE__
+#define __PICTURE__
+
+#include<vector>
+#include<list>
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+class PicBase;
+class PicContainer;
+class PicRoot;
+
+class Surface;
+
+namespace Event {
+	class Video;
+}
+
+/* PicBase の内容をイベントと連動させるためのインターフェース */
+class PicAnm {
+public:
+	typedef std::vector<PicBase*>::iterator iterator;
+	std::vector<PicBase*> pic;
+	PicAnm(PicBase* pic);
+	PicAnm(std::vector<PicBase*> pic);
+	virtual ~PicAnm();
+};
+
+class PicBase {
+	friend class PicContainer;
+	friend class PicWidget;
+
+	typedef std::list<PicBase*> List;
+	typedef std::list<PicBase*>::iterator iterator;
+
+	PicContainer* parent;
+	class PicWidget* widget;
+	Rect rel_pos; // relative position to the parent
+	Rect rel_solid_area; // solid area(not alpha-blended) to the parent
+	Rect clip_area; // clip area on the parent
+	bool is_hidden;
+	bool is_hidden_now;
+	bool is_cached;
+public:
+	enum { /*MOBILE=1,*/ CACHE_BACK=2, /* CACHE_SELF=4,*/ NO_PICTURE=8, SOLID = 16, SURFACE_FREE = 32, FIT_SURFACE = 64, BLIT_SATURATE = 128, BLIT_MULTIPLY = 256, ALPHA_FREE=512};
+private:
+	int attribute;
+
+	PicRoot* root;
+	iterator z_pos;
+	int surface_x, surface_y, surface_w, surface_h;
+	Surface* surface_back;
+	Surface* surface_own;
+	const unsigned char* surface_alpha;
+	Rect surface_alpha_rect;
+	int distance_root;
+
+	void Blit(const Rect& rpos);
+	void Blit(void) {
+		is_cached = true;
+		Blit(Rect(0, 0, rel_pos.width(), rel_pos.height()));
+	}
+	/*
+	** rpos : relative position to the widget
+	** ppos : relative position to the parent
+	**	ppos = parent_pos(rpos)
+	**	rpos = child_pos(ppos, parent->this_widget)
+	** cpos : relative position to a child widget
+	**	cpos = child_pos(rpos, a_child_widget)
+	** apos : absolute position in the screen
+	**	apos = QueryAbsPos(rpos);
+	**	or
+	**	Rect ppos = rel_pos;
+	**	apos = parent->QueryAbsPos(ppos);
+	**		the latter form is used for 'rel_pos',
+	**		because rel_pos is defined as the relative position to the parent
+	*/
+	Rect QueryAbsPos(Rect& ppos); // この picture 内の rel_pos を表示するのに実際に必要な絶対座標を得る
+
+	static Rect child_pos(Rect rpos, PicBase* child) { /* return 'cpos' */
+		rpos.intersect(child->rel_pos);
+		rpos.rmove( -(child->rel_pos.lx), -(child->rel_pos.ty));
+		return rpos;
+	}
+	Rect parent_pos(Rect rpos) { /* return 'ppos' */
+		rpos.rmove(rel_pos.lx, rel_pos.ty);
+		rpos.intersect(rel_pos);
+		return rpos;
+	}
+	void SetEventWidget(class PicWidget* widget);
+public:
+	PicBase(const Rect& rel_pos, PicContainer* parent, int attr);
+	virtual ~PicBase();
+	void InitRoot(PicRoot* r) { root = r;} // only called from PicRoot::PicRoot
+
+	void ReBlit(const Rect& rpos);
+	void ReBlit(void) { ReBlit(Rect(0, 0, rel_pos.width(), rel_pos.height()));}
+	void ExecReBlit(const Rect& rpos);
+	void SimpleBlit(Surface* screen);
+
+	virtual void RMove(int add_x, int add_y);
+	void Move(int new_rx, int new_ry);
+	#define ZMOVE_TOP ((PicBase*)0xffff00ff) /* 最前面へ */
+	#define ZMOVE_BOTTOM ((PicBase*)0xffff0fff) /* 最背面へ */
+	void ZMove(PicBase* back); // back の前に移動(back と自分は同じ親を持つこと)
+
+	void SetSurface(Surface* new_surface, int x, int y, int attribute = 0);
+	void SetSurface(const char* new_surface, int x, int y);
+	void SetSurfacePos(int x, int y);
+	int SurfacePosX(void);
+	int SurfacePosY(void);
+	void SetSurfaceRect(const Rect& r);
+	void SetSurfaceAlpha(const unsigned char* alpha, const Rect& rect);
+	void SetSurfaceAlphaFile(const char* file);
+	void SetSurfaceColorKey(int r, int g, int b);
+	void SetSurfaceAttribute(int attribute);
+	void SetSurfaceFreeFlag(bool flag=true);
+	void SetClipArea(const Rect& r);
+
+	void hide(void);
+	void show_all(void);
+	void show(void);
+
+	int PosX(void) const { return rel_pos.lx;}
+	int PosY(void) const { return rel_pos.ty;}
+	int Width(void) const { return rel_pos.width();}
+	int Height(void) const { return rel_pos.height();}
+	int DistanceRoot(void) const { return distance_root; }
+	bool IsHidden(void) { return is_hidden_now;}
+	bool IsParent(PicBase* pic);
+
+	std::vector<PicAnm*> anm;
+	void ClearAnm(void);
+};
+
+class PicContainer : public PicBase {
+	friend class PicBase;
+
+	void BlitBack(iterator z, Rect rpos); // z より後ろの領域を描画
+	void BlitFront(iterator z, Rect rpos); // z を含め、zより前の領域を描画
+	void BlitChildren(Rect rpos);
+	void BlitSelf(Rect rpos);
+	void BlitSelf(void) {
+		is_cached = true;
+		BlitSelf(Rect(0, 0, rel_pos.width(), rel_pos.height()));
+	}
+public:
+	List children;
+private:
+
+	void set_showflag(void);
+	void set_nowhiddenflag(bool is_hide);
+public:
+	PicContainer(const Rect& rel_pos, PicContainer* parent, int attr);
+	~PicContainer();
+	PicBase* create_leaf(const Rect& rel_pos, int attr);
+	PicContainer* create_node(const Rect& rel_pos, int attr);
+	PicRoot& Root(void) { return *root;}
+	void RMove(int add_x, int add_y);
+};
+
+typedef enum { NO_MASK, ALPHA_MASK, COLOR_MASK} MaskType;
+struct PicRoot {
+	class PicContainer* root;
+private:
+	class FileToSurface* ftosurface;
+	struct UpdateItem {
+		PicBase* pic;
+		Rect rpos;
+		Rect apos;
+		static bool less(const UpdateItem&, const UpdateItem&);
+		UpdateItem(PicBase* p, const Rect& _rpos, const Rect& _apos) : pic(p), rpos(_rpos), apos(_apos) {}
+	};
+	std::vector<UpdateItem> update_rects;
+
+	friend class FileToSurface;
+	void DeleteSurfaceImpl(Surface* s) const;
+public:
+	void Update(PicBase* pic, const Rect& rpos, const Rect& apos);
+	void DeleteUpdatePic(PicBase* pic);
+	void ExecUpdate(void);
+	void SetWindowCaption(const char* caption);
+
+	// Surface 操作
+	Surface* NewSurfaceFromRGBAData(int w, int h, char* data, MaskType with_mask) const; // data は malloc されたものであること(SDLの内部仕様)
+	Surface* NewSurface(int w, int h, MaskType with_mask) const;
+	Surface* NewSurface(const char* filename, MaskType with_mask = ALPHA_MASK);
+	Surface* RotZoomSurface(Surface* from, double zoom, double rotate_angle);
+	void DeleteSurface(Surface* s);
+	void BlitSurface(Surface* src, const Rect& src_rpos, const unsigned char* alpha, const Rect& alpha_r,  Surface* dest, const Rect& dest_rpos, int attribute) const;
+	void BlitSurface(Surface* src, const Rect& src_rpos, Surface* dest, const Rect& dest_rpos) const {
+		BlitSurface(src, src_rpos, 0, Rect(0,0), dest, dest_rpos, 0);
+	}
+	static bool with_mask(Surface* src);
+
+	Surface* surface;
+	Surface* hw_surface;
+	int width, height;
+	PicRoot(void);
+	~PicRoot();
+	PicBase* create_leaf(const Rect& apos, int attr) {
+		return root->create_leaf(apos, attr);
+	}
+	PicContainer* create_node(const Rect& apos, int attr) {
+		return root->create_node(apos, attr);
+	}
+};
+
+class PicWidget {
+	PicBase* pic; /* 本来継承するべきだが、遅延初期化したいので instance */
+public:
+	PicWidget(void);
+	virtual ~PicWidget();
+	void SetPic(PicBase* new_pic);
+	PicBase* Pic(void);
+	PicContainer* PicNode(void);
+	virtual void activate(void);
+	virtual void deactivate(void);
+	virtual void SetRegion(const Rect& apos);
+	void show(void);
+	void hide(void);
+	void show_all(void);
+};
+
+#endif /* PICTURE */
new file mode 100644
--- /dev/null
+++ b/window/rect.cc
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2004-2006  Kazunori "jagarl" Ueno
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "rect.h"
+
+using namespace std;
+
+inline int MAX(int a, int b) {
+	if (a>b) return a;
+	return b;
+}
+inline int MIN(int a, int b) {
+	if (a>b) return b;
+	return a;
+}
+
+Rect::Rect(int x1, int y1) {
+	lx = rx = x1;
+	ty = by = y1;
+}
+Rect::Rect(int x1, int y1, int x2, int y2) {
+	lx = MIN(x1,x2);
+	rx = MAX(x1,x2);
+	ty = MIN(y1,y2);
+	by = MAX(y1,y2);
+}
+Rect::Rect(const Rect& r) {
+	lx = r.lx;
+	rx = r.rx;
+	ty = r.ty;
+	by = r.by;
+}
+
+bool Rect::is_inner(const Rect& inner_rect) const {
+	Rect r = *this;
+	r.intersect(inner_rect);
+	return r == inner_rect;
+}
+bool Rect::is_nearly_inner(const Rect& inner_rect, int delta) const {
+	Rect r = *this;
+	r.lx -= delta;
+	r.ty -= delta;
+	r.rx += delta;
+	r.by += delta;
+	r.intersect(inner_rect);
+	return r == inner_rect;
+}
+bool Rect::is_crossed(const Rect& rect) const {
+	Rect r = *this;
+	r.intersect(rect);
+	return !(r.empty());
+}
+void Rect::intersect(const Rect& r) {
+	if (lx > r.rx) rx = lx;
+	else if (rx < r.lx) lx = rx;
+	else {
+		lx = MAX(lx, r.lx);
+		rx = MIN(rx, r.rx);
+	}
+
+	if (ty > r.by) by = ty;
+	else if (by < r.ty) ty = by;
+	else {
+		ty = MAX(ty, r.ty);
+		by = MIN(by, r.by);
+	}
+}
+void Rect::join(const Rect& r) {
+	lx = MIN(lx, r.lx);
+	rx = MAX(rx, r.rx);
+	ty = MIN(ty, r.ty);
+	by = MAX(by, r.by);
+}
+void Rect::rmove(int add_x, int add_y) {
+	lx += add_x;
+	rx += add_x;
+	ty += add_y;
+	by += add_y;
+}
+void Rect::subtract(const Rect& rect, vector<Rect>& ret_array) const {
+	Rect r = *this;
+	r.intersect(rect);
+	if (r.empty()) { // not intersect the rects
+		ret_array.push_back(*this);
+		return;
+	}
+	if (r ==*this) { // identical; no rect rests
+		return;
+	}
+	// push top area
+	if (ty != r.ty) {
+		ret_array.push_back(Rect(lx, ty, rx, r.ty));
+	}
+	// push bottom area
+	if (by != r.by) {
+		ret_array.push_back(Rect(lx, r.by, rx, by));
+	}
+	// push left area
+	if (lx != r.lx) {
+		ret_array.push_back(Rect(lx, r.ty, r.lx, r.by));
+	}
+	// push right area
+	if (rx != r.rx) {
+		ret_array.push_back(Rect(r.rx, r.ty, rx, r.by));
+	}
+	return;
+}
new file mode 100644
--- /dev/null
+++ b/window/rect.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2004-2006  Kazunori "jagarl" Ueno
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef __RECT_H__
+#define __RECT_H__
+
+#include<vector>
+
+struct Rect {
+	int lx, rx; // x = [lx,rx)
+	int ty, by; // y = [ty,by)
+
+	Rect(int x1, int y1);
+	Rect(int x1, int y1, int x2, int y2);
+	Rect(const Rect& rect);
+	Rect(const class Surface& rect);
+	Rect(const class TextGlyph& glyph);
+	void intersect(const Rect& rect);
+	bool is_crossed(const Rect& rect) const;
+	bool is_inner(const Rect& inner_rect) const;
+	bool is_nearly_inner(const Rect& inner_rect, int delta) const;
+	void join(const Rect& rect);
+	void rmove(int add_x, int add_y);
+	/** Subtracts rect from this. The resulting area is the set of pixels contained in this but not in the rect.
+	  * result will be push_backed to ret_array.
+	  */
+	void subtract(const Rect& rect, std::vector<Rect>& ret_array) const;
+	bool point_in(int x, int y) const;
+	bool empty(void) const {
+		return (lx == rx) || (ty == by);
+	}
+	int width(void) const {
+		return rx-lx;
+	}
+	int height(void) const {
+		return by-ty;
+	}
+};
+
+inline bool operator ==(const Rect& r1, const Rect& r2) {
+	return (r1.lx == r2.lx && r1.rx == r2.rx && r1.ty == r2.ty && r1.by == r2.by);
+}
+inline bool Rect::point_in(int x, int y) const {
+	return (lx <= x && x < rx && ty <= y && y < by);
+}
+
+struct Color {
+	int r,g,b,a;
+	Color(int _r, int _g, int _b) : r(_r),g(_g),b(_b),a(0xff) {}
+	Color(int _r, int _g, int _b, int _a) : r(_r),g(_g),b(_b),a(_a) {}
+};
+#endif
new file mode 100644
--- /dev/null
+++ b/window/render.cc
@@ -0,0 +1,474 @@
+/*
+ * Copyright (c) 2004-2006  Kazunori "jagarl" Ueno
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include"font/font.h"
+#include"font/text.h"
+#include"rect.h"
+#include"SDL.h"
+#include"surface.h"
+#include<stdio.h>
+
+Rect DSurfaceRenderText(TextGlyphStream::iterator start, TextGlyphStream::iterator end, const Rect& srcrect,
+	Surface* dst, const Rect& dstrect); // 文字描画
+void DSurfaceFill(Surface* src, const Rect& rect, int r, int g, int b, int a); // クリア
+void DSurfaceFillA(Surface* src, const Rect& rect, int r, int g, int b, int a); // テキストウィンドウ背景の設定
+void DSurfaceMove(Surface* src_o, const Rect& srcrect, Surface* dst_o, const Rect& dstrect); // コピー
+void DSurfaceBlitAlpha(Surface* src_o, const Rect& srcrect_o, Surface* dst_o, const Rect& dstrect_o, const unsigned char* alpha, const Rect& alpharect);
+void DSurfaceBlitSaturate(Surface* src_o, const Rect& srcrect, Surface* dst_o, const Rect& dstrect, unsigned char alpha);
+void DSurfaceBlitMultiply(Surface* src_o, const Rect& srcrect_o, Surface* dst_o, const Rect& dstrect_o);
+
+#ifndef ALPHA_MAX
+#define ALPHA_MAX 255
+#endif
+
+Rect::Rect(const TextGlyph& letter) {
+	lx = letter.x + letter.glyph->bitmap_left;
+	rx = lx + letter.glyph->bitmap.width;
+
+	ty = letter.y - letter.glyph->bitmap_top;
+	by = ty + letter.glyph->bitmap.rows;
+}
+
+Rect::Rect(const class Surface& so) {
+	SDL_Surface* s = (SDL_Surface*)(&so);
+	lx = 0; ty = 0;
+	rx = s->w; by = s->h;
+}
+inline Rect _Rect(const SDL_Rect& r) {
+	return Rect(r.x, r.y, r.x+r.w, r.y+r.h);
+};
+inline SDL_Rect SDLed(const Rect& rect) {
+	SDL_Rect r;
+	r.x = rect.lx;
+	r.y = rect.ty;
+	r.w = rect.rx-rect.lx;
+	r.h = rect.by-rect.ty;
+	return r;
+}
+
+Rect DSurfaceRenderText(TextGlyphStream::iterator start, TextGlyphStream::iterator end, const Rect& srcrect,
+	Surface* dst_o, const Rect& dstrect) {
+
+	SDL_Surface* dst = (SDL_Surface*)dst_o;
+	Rect confine_to(srcrect);
+	Rect dst_clip(_Rect(dst->clip_rect));
+	Rect drawn_rect(0,0,0,0);
+
+	int dif_x = dstrect.lx - srcrect.lx;
+	int dif_y = dstrect.ty - srcrect.ty;
+
+	dst_clip.rmove(-dif_x, -dif_y);
+	confine_to.intersect(dst_clip);
+
+	TextGlyphStream::iterator it;
+	SDL_PixelFormat& fmt = *dst->format;
+	int ashift = fmt.Ashift - fmt.Aloss; int amask = fmt.Amask;
+	int dbpl = dst->pitch;
+	int dbpp = fmt.BytesPerPixel;
+
+	SDL_LockSurface(dst);
+	for (it=start; it!=end; it++) {
+		Rect letter_r(*it);
+		letter_r.intersect(confine_to);
+		if (letter_r.empty()) continue;
+		drawn_rect.join(letter_r);
+
+		int w = letter_r.width();
+		int h = letter_r.height();
+		int sbpl = it->glyph->bitmap.width;
+
+		unsigned char* smem = it->glyph->bitmap.buffer +
+			(letter_r.ty - (it->y-it->glyph->bitmap_top)) * sbpl +
+			(letter_r.lx - (it->x+it->glyph->bitmap_left));
+		char* dmem = (char*)dst->pixels + 
+			(letter_r.ty + dif_y) * dbpl +
+			(letter_r.lx + dif_x) * dbpp;
+		Uint32 pixel = ((int(it->r)<<fmt.Rshift)&fmt.Rmask) |((int(it->g)<<fmt.Gshift)&fmt.Gmask) |((int(it->b)<<fmt.Bshift)&fmt.Bmask);
+		int i,j;
+		if (!it->is_rev) {
+			if (dbpp == 4) {
+				for (i=0; i<h; i++) {
+					for (j=0; j<w; j++) {
+						int alpha = smem[j];
+						((Uint32*)dmem)[j] = pixel | ((alpha << ashift)&amask);
+					}
+					smem += sbpl; dmem += dbpl;
+				}
+			} else if (dbpp == 2) {
+				for (i=0; i<h; i++) {
+					for (j=0; j<w; j++) {
+						int alpha = smem[j];
+						((Uint16*)dmem)[j] = pixel | ((alpha << ashift)&amask);
+					}
+					smem += sbpl; dmem += dbpl;
+				}
+			} else abort();
+		} else { /* reversed */
+			if (dbpp == 4) {
+				for (i=0; i<h; i++) {
+					for (j=0; j<w; j++) {
+						int alpha = 255 - smem[j];
+						((Uint32*)dmem)[j] = pixel | ((alpha << ashift)&amask);
+					}
+					smem += sbpl; dmem += dbpl;
+				}
+			} else if (dbpp == 2) {
+				for (i=0; i<h; i++) {
+					for (j=0; j<w; j++) {
+						int alpha = 255 - smem[j];
+						((Uint16*)dmem)[j] = pixel | ((alpha << ashift)&amask);
+					}
+					smem += sbpl; dmem += dbpl;
+				}
+			} else abort();
+		}
+	}
+	SDL_UnlockSurface(dst);
+	drawn_rect.rmove(dif_x, dif_y);
+	return drawn_rect;
+}
+void DSurfaceFill(Surface* src_o, const Rect& rect, int r, int g, int b, int a) {
+	SDL_Rect sr = SDLed(rect); 
+	SDL_Surface* src = (SDL_Surface*)src_o;
+	SDL_FillRect( src, &sr, SDL_MapRGBA(src->format, r, g, b, a));
+	return;
+}
+
+static void clip_rect(Rect& srcrect, Rect& dstrect, SDL_Surface* dstsurf) {
+	Rect confine_to(srcrect);
+	Rect dst_clip(_Rect(dstsurf->clip_rect));
+
+	int dif_x = dstrect.lx - srcrect.lx;
+	int dif_y = dstrect.ty - srcrect.ty;
+
+	dst_clip.rmove(-dif_x, -dif_y);
+	confine_to.intersect(dst_clip);
+
+	srcrect = confine_to;
+	dstrect = confine_to;
+	dstrect.rmove(dif_x, dif_y);
+}
+
+void DSurfaceMove(Surface* src_o, const Rect& srcrect_o, Surface* dst_o, const Rect& dstrect_o) {
+
+	SDL_Surface* dst = (SDL_Surface*)dst_o;
+	SDL_Surface* src = (SDL_Surface*)src_o;
+
+	if (dst->format->BytesPerPixel != src->format->BytesPerPixel) return; // RGB変換はできない
+
+	Rect srcrect(srcrect_o), dstrect(dstrect_o);
+	clip_rect(srcrect, dstrect, dst);
+
+	SDL_LockSurface(dst); SDL_LockSurface(src);
+	int sbpl = src->pitch;
+	int dbpl = dst->pitch;
+	int bpp = dst->format->BytesPerPixel;
+	int width = bpp * srcrect.width();
+	int height = srcrect.height();
+	char* smem = src_o->mem(srcrect);
+	char* dmem = dst_o->mem(dstrect);
+	char* smem_end = src_o->mem_end(srcrect);
+	char* dmem_end = dst_o->mem_end(dstrect);
+
+	// メモリに重なりがあり、src が上位側の場合、コピー方向を逆転する
+	if (smem < dmem && dmem < smem_end) {
+		int i,j;
+		for (i=0; i<height; i++) {
+			char* s = smem_end; char* d = dmem_end;
+			for (j=0; j<width; j++)
+				*--d = *--s;
+			dmem_end -= dbpl; smem_end -= sbpl;
+		}
+	} else {
+		int i;
+		for (i=0; i<height; i++) {
+			memcpy(dmem, smem, width);
+			dmem += dbpl; smem += sbpl;
+		}
+	}
+	SDL_UnlockSurface(dst);
+	SDL_UnlockSurface(src);
+	return;
+}
+
+void DSurfaceFillA(Surface* dsto, const Rect& rect, int r, int g, int b, int a) {
+	SDL_Surface* dst = (SDL_Surface*)dsto;
+	SDL_LockSurface( dst);
+	int dbpl = dst->pitch;
+	int bpp = dst->format->BytesPerPixel;
+	int width = rect.width();
+	int height = rect.height();
+	int amask = dst->format->Amask;
+	int ashift = dst->format->Ashift - dst->format->Aloss;
+
+	char* dmem = (char*)(dst->pixels) + rect.ty*dbpl + rect.lx*bpp;
+	unsigned int pixel = SDL_MapRGBA(dst->format, r, g, b, 0);
+	unsigned int pixela = SDL_MapRGBA(dst->format, r, g, b, a);
+	a += a>>7; /* 0-256 にする */
+	int i,j;
+	for (i=0; i<height; i++) {
+		char* d = dmem;
+		if (bpp == 4) {
+			for (j=0; j<width; j++) {
+				int alpha = (*(Uint32*)d)>>ashift;
+				if (alpha == 0) (*(Uint32*)d) = pixel;
+				else if (alpha == 255) *((Uint32*)d) = pixela;
+				else { *((Uint32*)d) = pixel | ((((alpha*a)>>8)<<ashift)&amask); }
+				d += bpp;
+			}
+		} else if (bpp == 2) {
+			for (j=0; j<width; j++) {
+				int alpha = (*(Uint16*)d)>>ashift;
+				if (alpha == 0) *((Uint16*)d) = pixel;
+				else if (alpha == 255) *((Uint16*)d) = pixela;
+				else { *((Uint16*)d) = pixel | ((((alpha*a)>>8)<<ashift)&amask); }
+				d += bpp;
+			}
+		}
+		dmem += dbpl;
+	}
+	SDL_UnlockSurface( dst);
+	return;
+}
+
+#define ASHIFT 24
+#define CMASK1 0xff00ff
+#define CMASK2 0x00ff00
+
+inline void blit_pixel(Uint32* dmem, Uint32* smem, const unsigned char* amem, bool use_srcalpha) {
+	Uint32 d = *dmem;
+	Uint32 s = *smem;
+	Uint32 as = s>>ASHIFT;
+	if (as == 255 || (!use_srcalpha) ) {
+		as = *amem;
+	} else {
+		as += as>>7; /* 0-0xff -> 0-0x100 */
+		as *= *amem;
+		as >>= 8;
+	}
+	as += as>>7;
+	Uint32 s1 = s & CMASK1;
+	Uint32 d1 = d & CMASK1;
+	d1 = (d1 + (((s1-d1) * as) >> 8)) & CMASK1;
+	s &= CMASK2;
+	d &= CMASK2;
+	d = (d + (((s-d) * as) >> 8)) & CMASK2;
+	*dmem = d1 | d | 0xff000000;
+}
+static void blit_line(Uint32* dmem, Uint32* smem, const unsigned char* amem,int ax0, int ax1, int awidth, int aj0, int aj1, bool use_srcalpha) {
+	int j;
+	int ax = ax0;
+	const unsigned char* a = amem + ax0;
+	Uint32* d = dmem;
+	Uint32* s = smem;
+	if (awidth == 1) { //  わりとよくあるので最適化
+		for (j=aj0; j < aj1; j++) {
+			blit_pixel(d++, s++, amem, use_srcalpha);
+		}
+	} else {
+		for (j=aj0; j < aj1; j++) {
+			for (; ax<awidth; ax++)
+				blit_pixel(d++, s++, a++, use_srcalpha);
+			ax = 0;
+			a = amem;
+		}
+		for (; ax < ax1; ax++) blit_pixel(d++, s++, a++, use_srcalpha);
+	}
+}
+
+void DSurfaceBlitAlpha(Surface* src_o, const Rect& srcrect_o, Surface* dst_o, const Rect& dstrect_o, const unsigned char* alpha, const Rect& alpharect) {
+	SDL_Surface* dst = (SDL_Surface*)dst_o;
+	SDL_Surface* src = (SDL_Surface*)src_o;
+	SDL_PixelFormat& fmt = *dst->format;
+
+	Rect srcrect(srcrect_o), dstrect(dstrect_o);
+	clip_rect(srcrect, dstrect, dst);
+
+	int awidth = alpharect.width();
+	int aheight = alpharect.height();
+	if (awidth == 0 || aheight == 0) return;
+	int ax0 = srcrect.lx % awidth;
+	int ay0 = srcrect.ty % aheight;
+	int aj0 = srcrect.lx / awidth;
+	int ai0 = srcrect.ty / aheight;
+	int ax1 = srcrect.rx % awidth;
+	int ay1 = srcrect.by % aheight;
+	int aj1 = srcrect.rx / awidth;
+	int ai1 = srcrect.by / aheight;
+
+	SDL_LockSurface(dst);
+	SDL_LockSurface(src);
+	int dbpl = dst->pitch;
+	int sbpl = src->pitch;
+	int bpp = dst->format->BytesPerPixel;
+
+	char* dmem = dst_o->mem(dstrect);
+	char* smem = src_o->mem(srcrect);
+
+	const unsigned char* amem = alpha + ay0 * awidth;
+	int i;
+	int ay = ay0;
+	for (i = ai0; i < ai1; i++) {
+		for (; ay < aheight; ay++) {
+			if (src->format->Amask == 0)
+				blit_line( (Uint32*)dmem, (Uint32*)smem, amem,ax0, ax1, awidth, aj0, aj1, false);
+			else
+				blit_line( (Uint32*)dmem, (Uint32*)smem, amem,ax0, ax1, awidth, aj0, aj1, true);
+			amem += awidth; dmem += dbpl; smem += sbpl;
+		}
+		ay = 0; amem = alpha;
+	}
+	for (; ay < ay1; ay++) {
+		if (src->format->Amask == 0)
+			blit_line( (Uint32*)dmem, (Uint32*)smem, amem,ax0, ax1, awidth, aj0, aj1, false);
+		else
+			blit_line( (Uint32*)dmem, (Uint32*)smem, amem,ax0, ax1, awidth, aj0, aj1, true);
+		amem += awidth; dmem += dbpl; smem += sbpl;
+	}
+	SDL_UnlockSurface(src);
+	SDL_UnlockSurface(dst);
+	return;
+}
+void DSurfaceBlitSaturate(Surface* src_o, const Rect& srcrect_o, Surface* dst_o, const Rect& dstrect_o, unsigned char alpha) {
+	SDL_Surface* dst = (SDL_Surface*)dst_o;
+	SDL_Surface* src = (SDL_Surface*)src_o;
+
+	if (dst->format->BytesPerPixel != src->format->BytesPerPixel) return; // RGB変換はできない
+
+	Rect srcrect(srcrect_o), dstrect(dstrect_o);
+	clip_rect(srcrect, dstrect, dst);
+
+	SDL_LockSurface(dst); SDL_LockSurface(src);
+	int sbpl = src->pitch;
+	int dbpl = dst->pitch;
+	int bpp = dst->format->BytesPerPixel;
+	int width = srcrect.width();
+	int height = srcrect.height();
+	char* smem = src_o->mem(srcrect);
+	char* dmem = dst_o->mem(dstrect);
+	char* smem_end = src_o->mem_end(srcrect);
+	char* dmem_end = dst_o->mem_end(dstrect);
+
+	SDL_PixelFormat& fmt = *dst->format;
+	int rshift = fmt.Rshift - fmt.Rloss; int rmask = fmt.Rmask;
+	int gshift = fmt.Gshift - fmt.Gloss; int gmask = fmt.Gmask;
+	int bshift = fmt.Bshift - fmt.Bloss; int bmask = fmt.Bmask;
+	int allmask = rmask | gmask | bmask;
+	int i;
+	for (i=0; i<height; i++) {
+		char* d = dmem; char* s = smem;
+		int j; for (j=0; j<width; j++) {
+			Uint32 sd = *(Uint32*)s;
+			Uint32 dd = *(Uint32*)d;
+			if (sd&allmask) {
+				Uint32 sr = (sd&rmask)>>rshift;
+				Uint32 sg = (sd&gmask)>>gshift;
+				Uint32 sb = (sd&bmask)>>bshift;
+				if (alpha != ALPHA_MAX) {
+					sr = (sr*alpha)>>8;
+					sg = (sg*alpha)>>8;
+					sb = (sb*alpha)>>8;
+				}
+				Uint32 dr = sr + ((dd&rmask)>>rshift);
+				Uint32 dg = sg + ((dd&gmask)>>gshift);
+				Uint32 db = sb + ((dd&bmask)>>bshift);
+				if (dr > 255) dr = 255;
+				if (dg > 255) dg = 255;
+				if (db > 255) db = 255;
+				*(Uint32*)d = ((dr<<rshift)&rmask)| ((dg<<gshift)&gmask)| ((db<<bshift)&bmask);
+			}
+			s += bpp; d += bpp;
+		}
+		dmem += dbpl; smem += sbpl;
+	}
+	SDL_UnlockSurface(src);
+	SDL_UnlockSurface(dst);
+	return;
+}
+void DSurfaceBlitMultiply(Surface* src_o, const Rect& srcrect_o, Surface* dst_o, const Rect& dstrect_o) {
+	SDL_Surface* dst = (SDL_Surface*)dst_o;
+	SDL_Surface* src = (SDL_Surface*)src_o;
+
+	Rect srcrect(srcrect_o), dstrect(dstrect_o);
+	clip_rect(srcrect, dstrect, dst);
+
+	SDL_LockSurface(dst);
+	SDL_LockSurface(src);
+	int dbpl = dst->pitch;
+	int sbpl = src->pitch;
+	int bpp = dst->format->BytesPerPixel;
+	int width = srcrect.width();
+	int height = srcrect.height();
+	char* dmem = dst_o->mem(dstrect);
+	char* smem = src_o->mem(srcrect);
+
+	SDL_PixelFormat& fmt = *dst->format;
+	/* dst の 0-255 を 0-pixel に変換する(積算) */
+	int i;
+	int table1[256], table2[256], table3[256];
+	Uint32 src_pixel = *(Uint32*)smem;
+	src_pixel |= 0xff000000;
+	int c1=src_pixel&255, c2=(src_pixel>>8)&255, c3=(src_pixel>>16)&255;
+	for (i=0; i<256; i++) {
+		int n = i + (i>>7);
+		table1[i] = (c1*n)>>8;
+		table2[i] = (c2*n)&0xff00;
+		table3[i] = ((c3*n)<<8) & 0xff0000;
+	}
+	int err_count = 0;
+	for (i=0; i<height; i++) {
+		Uint32* d = (Uint32*)dmem;
+		Uint32* s = (Uint32*)smem;
+		int j; for (j=0; j<width; j++) {
+			Uint32 dd = *d;
+			Uint32 ss = *s;
+			if (ss == src_pixel) {
+				*(Uint32*)d = table1[ dd & 0xff] | table2[ (dd>>8) & 0xff] | table3[ (dd>>16) & 0xff];
+			} else if ( ((ss^src_pixel) & 0xffffff) == 0) { // r,g,b of ss == src_pixel
+				Uint32 as = ss>>ASHIFT;
+				as += as>>7;
+				ss = table1[ dd & 0xff] | table2[ (dd>>8) & 0xff] | table3[ (dd>>16) & 0xff];
+				Uint32 s1 = ss&CMASK1;
+				Uint32 d1 = dd&CMASK1;
+				d1 = (d1 + (((s1-d1) * as) >> 8)) & CMASK1;
+				ss &= CMASK2;
+				dd &= CMASK2;
+				dd = (dd + (((ss-dd) * as) >> 8)) & CMASK2;
+				*(Uint32*)d = d1 | dd | 0xff000000;
+			} else err_count++;
+			d++; s++;
+		}
+		dmem += dbpl; smem += sbpl;
+	}
+	if (err_count) {
+		fprintf(stderr,"multipy_blit : surface does not have unique color(%08x); %d pixels in width %d, height %d\n",
+			src_pixel, err_count, width, height);
+	}
+	SDL_UnlockSurface(dst);
+	SDL_UnlockSurface(src);
+	return;
+}
new file mode 100644
--- /dev/null
+++ b/window/runlengh.cc
@@ -0,0 +1,47 @@
+#include<stdio.h>
+
+int main(int argc, char** argv) {
+	if (argc != 2) return 0;
+	FILE* f = fopen(argv[1],"rb");
+	if (f==0) return 0;
+	int i,j;
+	fseek(f,0,2);
+	int sz=ftell(f);
+	fseek(f,0,0);
+	char* buf=new char[sz];
+	char* out = new char[sz];
+	fread(buf,sz,1,f);
+	fclose(f);
+	int oc=0;
+	for (i=0; i<sz; i++) {
+		int d = buf[i];
+		int c = d & 0xff;
+		switch(c) {
+		case 0x61: c=1; break;
+		case 0xa2: c=2; break;
+		case 0xc1: c=3; break;
+		case 0xdf: c=4; break;
+		case 0xde: c=5; break;
+		case 0xff: c=6; break;
+		}
+		for (j=i; j<sz; j++)
+			if (buf[j] != d) break;
+		int cnt = j-i;
+		if (cnt < 16) {
+			out[oc++] = c | 0x08 | (cnt<<4);
+		} else if (cnt < 256){
+			out[oc++] = c;
+			out[oc++] = cnt;
+		} else fprintf(stderr,"cnt %d\n",cnt);
+		if (j == sz) break;
+		i = j-1;
+	}
+	printf("int button1_cnt = %d;\nchar button1[%d] = {\n\t",oc,oc+1);
+	for (i=0; i<oc; i++) {
+		printf("0x%02x,",int(out[i])&0xff);
+		if ( (i&15) == 15) printf("\n\t");
+	}
+	printf("\n\t0xff};\n");
+	return 0;
+}
+/* 2834bytes*/
new file mode 100644
--- /dev/null
+++ b/window/surface.h
@@ -0,0 +1,16 @@
+#ifndef __SURFACE_H__
+#define __SURFACE_H__
+
+#include<SDL.h>
+#include"rect.h"
+
+struct Surface : public SDL_Surface {
+	char* mem(const Rect& r) {
+		return (char*)(pixels) + r.ty * pitch + r.lx * format->BytesPerPixel;
+	}
+	char* mem_end(const Rect& r) {
+		return (char*)(pixels) + (r.by-1) * pitch + r.rx * format->BytesPerPixel;
+	}
+};
+
+#endif /* __SURFACE_H__ */
new file mode 100644
--- /dev/null
+++ b/window/system.cc
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2004-2006  Kazunori "jagarl" Ueno
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include<SDL.h>
+#include"system.h"
+#include<iostream>
+#include<stdio.h>
+
+using namespace std;
+
+// void SDL_SetEventFilter(SDL_EventFilter filter);
+// typedef int (*SDL_EventFilter)(const SDL_Event *event);
+namespace System {
+
+Main* Main::instance = 0;
+
+int Main::event_filter(const SDL_Event* event) {
+	return 1; /* throw all event */
+}
+
+Main::Main(void) {
+	instance = this;
+	framerate = 20;
+	cursor = 0;
+}
+Main::~Main() {
+	if (cursor) delete cursor;
+}
+void Main::Quit(void) {
+	is_exit = true;
+}
+void Main::EnableVideo(void) {
+	is_video_update = true;
+}
+void Main::DisableVideo(void) {
+	is_video_update = false;
+}
+bool Main::is_exit = false;
+bool Main::is_video_update = true;
+
+void Main::Mainloop(void) {
+	SDL_SetEventFilter(&event_filter);
+	Uint32 old_time = 0;
+	while(!is_exit) {
+		Uint32 start_time = SDL_GetTicks();
+		if (! event.Exec(start_time)) break;
+		if (start_time - old_time > 1000/framerate) {
+			if (is_video_update) root.ExecUpdate();
+			event.Exec(Event::Time::FRAME_UPDATE);
+			cout.flush();
+			old_time = start_time;
+		}
+
+// 問題:
+// z 軸と xy 軸の相互干渉;高速化
+// 移動するウィジット描画の高速化
+// キャッシュ
+// 文字列の一部のみ更新の高速化
+// 「階層 z で x なる領域無効化、y なる領域生成」で良い?>Expose
+/*
+		Uint32 end_time = SDL_GetTicks();
+		Uint32 delay = (end_time-start_time);
+		if(delay < 1000/framerate) SDL_Delay(1000/framerate - delay);
+		else SDL_Delay(0);
+*/
+		SDL_Delay(0);
+	};
+}
+
+void Main::SetCursor(Surface* s, const Rect& r) {
+	if (instance == 0) return;
+	if (instance->cursor) delete instance->cursor;
+	if (s == 0) { // カーソル消去
+		instance->cursor = 0;
+	} else if (s == DEFAULT_MOUSECURSOR) {
+		instance->cursor = 0;
+		SDL_ShowCursor(SDL_ENABLE);
+	} else {
+		instance->cursor = new WidMouseCursor(instance->event, instance->root.root, s, r.lx, r.ty, r.width(), r.height());
+		instance->cursor->show();
+		SDL_ShowCursor(SDL_DISABLE);
+	}
+}
+}
new file mode 100644
--- /dev/null
+++ b/window/system.h
@@ -0,0 +1,31 @@
+#ifndef __SYSTEM__
+#define __SYSTEM__
+
+#include<SDL.h>
+#include"event.h"
+#include"picture.h"
+#include"widget.h"
+
+namespace System {
+struct Main {
+	int framerate;
+	static int event_filter(const SDL_Event* event);
+	static bool is_exit;
+	static bool is_video_update;
+	static Main* instance;
+	WidMouseCursor* cursor;
+public:
+	Event::Container event;
+	PicRoot root;
+	Main(void);
+	~Main();
+	void Mainloop(void);
+	static void Quit(void);
+	static void DisableVideo(void);
+	static void EnableVideo(void);
+#define DEFAULT_MOUSECURSOR (Surface*)0xffff0000
+	static void SetCursor(Surface* s, const Rect& r);
+};
+};
+
+#endif /* __SYSTEM__ */
new file mode 100644
--- /dev/null
+++ b/window/widget.cc
@@ -0,0 +1,1299 @@
+/*
+ * Copyright (c) 2004-2006  Kazunori "jagarl" Ueno
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include"widget.h"
+#include<algorithm>
+#include<map>
+#include<string>
+
+Rect DSurfaceRenderText(TextGlyphStream::iterator start, TextGlyphStream::iterator end, const Rect& srcrect,
+	Surface* dst, const Rect& dstrect);
+void DSurfaceFill(Surface* src, const Rect& rect, int r, int g, int b, int a = 0xff);
+void DSurfaceMove(Surface* src, const Rect& srcrect, Surface* dst_o, const Rect& dstrect);
+
+//static char* wdefault_font_orig = "msgothic.ttc;times.ttf;";
+static std::map<int, XKFont::HorizLayout*> size_to_layout;
+static char* wdefault_font_orig = "times.ttf;msgothic.ttc";
+static std::string wdefault_font = wdefault_font_orig;
+
+void SetFont(const char* font) {
+	if (font == 0) return;
+	std::map<int,XKFont::HorizLayout*>::iterator it;
+	for (it=size_to_layout.begin(); it != size_to_layout.end(); it++) {
+		delete it->second;
+	}
+	size_to_layout.clear();
+	wdefault_font = font;
+}
+// namespace Widget {
+#define TimeCursor WidTimeCursor
+#define MouseCursor WidMouseCursor
+#define Button WidButton
+#define Scale WidScale
+#define TextButton WidTextButton
+#define Text WidText
+#define AnmTime WidAnmTime
+#define AnmMove WidAnmMove
+#define AnmAlpha WidAnmAlpha
+#define AnmPtnSolid WidAnmPtnSolid
+#define AnmPtnAlpha WidAnmPtnAlpha
+
+XKFont::HorizLayout* DefaultLayout(int text_size) {
+	if (size_to_layout.find(text_size) == size_to_layout.end()) {
+		size_to_layout[text_size] = new XKFont::HorizLayout(wdefault_font.c_str(), text_size);
+	}
+	return size_to_layout[text_size];
+}
+
+void PicWidget::activate(void) {
+}
+void PicWidget::deactivate(void) {
+}
+void PicWidget::SetRegion(const Rect& apos) {
+}
+void PicWidget::show(void) {
+	Pic()->show();
+}
+void PicWidget::hide(void) {
+	Pic()->hide();
+}
+void PicWidget::show_all(void) {
+	Pic()->show_all();
+}
+
+TimeCursor::TimeCursor(Event::Container& container, int _interval, PicContainer* parent, const char* s, int _sx, int _sy, int _sdx, int _sdy, int _nptn, const Rect& r) :
+	Time(container) {
+	interval = _interval;
+	if (interval < 0) interval = 100;
+	nptn = _nptn;
+	if (nptn < 0) nptn = 1;
+	count = 0; old_time = 0;
+
+	x = _sx; y = _sy; dx = _sdx; dy = _sdy;
+	SetPic(parent->create_leaf(r, PicBase::CACHE_BACK));
+	Pic()->SetSurface(s, _sx, _sy);
+};
+void TimeCursor::Elapsed(unsigned int current_time) {
+	int move = (current_time-old_time)/interval;
+	if (move) {
+		old_time += move*interval;
+		count += move;
+		count %= nptn;
+		Pic()->SetSurfacePos(x + count*dx, y + count*dy);
+	}
+	if (current_time > old_time+interval) SetWakeup(current_time);
+	else SetWakeup(old_time+interval);
+}
+
+MouseCursor::MouseCursor(Event::Container& _container, PicContainer* parent, const char* s, int x, int y, int w, int h) :
+	Event::Video(_container), container(_container) {
+	int sx, sy;
+	_container.MousePos(sx, sy);
+	SetPic(parent->create_leaf(Rect(sx, sy, sx+w, sy+h), 0));
+	Pic()->SetSurface(s, x, y);
+	x = 0; y = 0;
+	container.RegisterGlobalMotionFunc(&Motionfunc, (void*)this);
+}
+MouseCursor::MouseCursor(Event::Container& _container, PicContainer* parent, Surface* s, int x, int y, int w, int h) :
+	Event::Video(_container), container(_container) {
+	int sx, sy;
+	_container.MousePos(sx, sy);
+	SetPic(parent->create_leaf(Rect(sx, sy, sx+w, sy+h), 0));
+	Pic()->SetSurface(s, x, y);
+	x = 0; y = 0;
+	container.RegisterGlobalMotionFunc(&Motionfunc, (void*)this);
+}
+
+MouseCursor::~MouseCursor() {
+	container.DeleteGlobalMotionFunc(&Motionfunc, (void*)this);
+}
+
+bool MouseCursor::Motionfunc(int x, int y, void* pointer) {
+	MouseCursor* _this = (MouseCursor*)pointer;
+	// 左上がカーソルポイントの場合
+	// _this->Pic()->Move(x,y);
+	// 左下がカーソルポイントの場合
+	_this->Pic()->Move(x,y-_this->Pic()->Height());
+	return true;
+}
+
+Button::Button(Event::Container& container, PicContainer* parent, const char* s, int _sx, int _sy, int _sdx, int _sdy, int _nptn, const Rect& r, int _z) : sx(_sx), sy(_sy), sdx(_sdx), sdy(_sdy), nptn(_nptn) ,Event::Video(container,r, _z) {
+	SetPic(parent->create_leaf(r, 0));
+	Pic()->SetSurface(s, _sx, _sy);
+	show();
+	is_in = false;
+	is_toggled = false;
+	press_func = 0;
+	press_pointer = 0;
+	drag_func = 0;
+	drag_pointer = 0;
+	is_toggle_switch = false;
+}
+Button::Button(Event::Container& container, PicContainer* parent, Surface* s, int _sx, int _sy, int _sdx, int _sdy, int _nptn, const Rect& r, int _z) : sx(_sx), sy(_sy), sdx(_sdx), sdy(_sdy), nptn(_nptn) ,Event::Video(container,r, _z) {
+	SetPic(parent->create_leaf(r, 0));
+	Pic()->SetSurface(s, _sx, _sy);
+	show();
+	is_in = false;
+	is_toggled = false;
+	press_func = 0;
+	press_pointer = 0;
+	drag_func = 0;
+	drag_pointer = 0;
+	is_toggle_switch = false;
+}
+Button::~Button() {
+}
+void Button::In(void) {
+	is_in = true;
+	if (nptn > 1)
+		if (! is_toggled)
+			Pic()->SetSurfacePos(sx+sdx, sy+sdy);
+}
+void Button::Out(void) {
+	is_in = false;
+	if (!is_toggled)
+		Pic()->SetSurfacePos(sx, sy);
+}
+void Button::Toggle(bool new_toggle) {
+	if (is_toggled == new_toggle) {
+		return;
+	}
+	is_toggled = new_toggle;
+	// if (is_in) return; // is_in に関わらずウィジットの表示を変更することにする
+	if (is_toggled) {
+		if (nptn > 2)
+			Pic()->SetSurfacePos(sx+sdx*2, sy+sdy*2);
+		else if (nptn > 1)
+			Pic()->SetSurfacePos(sx+sdx, sy+sdy);
+		else
+			Pic()->SetSurfacePos(sx, sy);
+	} else {
+		Pic()->SetSurfacePos(sx, sy);
+	}
+}
+void Button::Press(void) {
+	is_in = true;
+	if (is_toggled) ;
+	else if (nptn > 2)
+		Pic()->SetSurfacePos(sx+sdx*2, sy+sdy*2);
+	else if (nptn > 1)
+		Pic()->SetSurfacePos(sx+sdx, sy+sdy);
+	if (press_func) press_func(press_pointer, this);
+	if (is_toggle_switch) Toggle(!is_toggled);
+}
+void Button::Release(void) {
+	if (is_toggled) ;
+	else if (nptn > 1 && is_in)
+		Pic()->SetSurfacePos(sx+sdx, sy+sdy);
+	else if (nptn > 1)
+		Pic()->SetSurfacePos(sx, sy);
+}
+void Button::Drag(int x_from, int y_from, int x_to, int y_to) {
+	if (drag_func) drag_func(x_from,y_from,x_to, y_to,drag_pointer, this);
+}
+
+Scale::Scale(Event::Container& _container, PicContainer* _parent, const Rect& r_orig, const Color& _color, bool _is_vertical) :
+	Event::Video(_container,Rect(0,0), 1),
+	container(_container), parent(_parent), cursor_color(_color),
+	mouse_x(0), mouse_y(0), max(0), min(0),
+	value(0), value_add(0), value_dragstart(0), is_vertical(_is_vertical),
+	change_func(0), change_pointer(0) {
+
+	arrow_down = 0;
+	arrow_up = 0;
+	cursor = 0;
+	panel = 0;
+
+	Init(r_orig);
+}
+
+extern char* create_button(int number, int& width, int& height, int r, int g, int b);
+extern char* create_box(int& width, int& height, int r, int g, int b);
+void Scale::Init(Rect r_orig) {
+	int r=cursor_color.r, g=cursor_color.g, b=cursor_color.b;
+	// 矢印
+	int arrow_width = -1;
+	cursor_width = -1;
+	char* button1;
+	char* button2;
+	if (is_vertical) {
+		// 矢印に必要な領域確保
+		int arrow_height = r_orig.width();
+		button1 = create_button(2, arrow_height, arrow_width, r, g, b);
+		button2 = create_button(3, arrow_height, arrow_width, r, g, b);
+		if (r_orig.height() < arrow_width*4) {
+			if (r_orig.height() < 8) r_orig.by = r_orig.ty + 8; // 小さすぎる場合は強制変更
+			free( (void*)button1);
+			free( (void*)button2);
+			arrow_width = r_orig.height()/4;
+			// 再割り当て
+			button1 = create_button(2, arrow_height, arrow_width, r, g, b);
+			button2 = create_button(3, arrow_height, arrow_width, r, g, b);
+		}
+		// 矢印ボタンの作成
+		Surface* a1s = parent->Root().NewSurfaceFromRGBAData(arrow_height, arrow_width*3, button1, ALPHA_MASK);
+		int x = r_orig.lx; int y = r_orig.ty;
+		arrow_up = new Button(container, parent, a1s, 0, 0, 0, arrow_width, 3, Rect(x,y,x+arrow_height,y+arrow_width),1);
+		arrow_up->Pic()->SetSurfaceFreeFlag();
+		Surface* a2s = parent->Root().NewSurfaceFromRGBAData(arrow_height, arrow_width*3, button2, ALPHA_MASK);
+		x = r_orig.rx - arrow_height; y = r_orig.by - arrow_width;
+		arrow_down = new Button(container, parent, a2s, 0, 0, 0, arrow_width, 3, Rect(x,y,x+arrow_height,y+arrow_width),1);
+		arrow_down->Pic()->SetSurfaceFreeFlag();
+		// picture作成(ボタンの動く領域)
+		Rect r = r_orig;
+		r.ty += arrow_width;
+		r.by -= arrow_width;
+		panel = parent->create_node(r, 0);
+		SetPic(panel);
+		// ボタンの中心線を描画、設定
+		Surface* s = parent->Root().NewSurface(r.width()/2, r.height(), ALPHA_MASK);
+		DSurfaceFill(s, Rect(0,0,r.width()/2,r.height()), 0, 0, 0, 0xff);
+		Pic()->SetSurface(s, -r.width()/4, 0, 0);
+		Pic()->SetSurfaceFreeFlag();
+	} else {
+		// 矢印に必要な領域確保
+		int arrow_height = r_orig.height();
+		button1 = create_button(0, arrow_width, arrow_height, r, g, b);
+		button2 = create_button(1, arrow_width, arrow_height, r, g, b);
+		if (r_orig.width() < arrow_width*4) {
+			if (r_orig.width() < 8) r_orig.rx = r_orig.lx + 8; // 小さすぎる場合は強制変更
+			free( (void*)button1);
+			free( (void*)button2);
+			arrow_width = r_orig.width()/4;
+			// 再割り当て
+			button1 = create_button(2, arrow_width, arrow_height, r, g, b);
+			button2 = create_button(3, arrow_width, arrow_height, r, g, b);
+		}
+		// 矢印ボタンの作成
+		Surface* a1s = parent->Root().NewSurfaceFromRGBAData(arrow_width, arrow_height*3, button1, ALPHA_MASK);
+		int x = r_orig.lx; int y = r_orig.ty;
+		arrow_up = new Button(container, parent, a1s, 0, 0, 0, arrow_height, 3, Rect(x,y,x+arrow_width,y+arrow_height),1);
+		arrow_up->Pic()->SetSurfaceFreeFlag();
+		Surface* a2s = parent->Root().NewSurfaceFromRGBAData(arrow_width, arrow_height*3, button2, ALPHA_MASK);
+		x = r_orig.rx - arrow_width; y = r_orig.by - arrow_height;
+		arrow_down = new Button(container, parent, a2s, 0, 0, 0, arrow_height, 3, Rect(x,y,x+arrow_width,y+arrow_height),1);
+		arrow_down->Pic()->SetSurfaceFreeFlag();
+		// picture作成(ボタンの動く領域)
+		Rect r = r_orig;
+		r.lx += arrow_width;
+		r.rx -= arrow_width;
+		panel = parent->create_node(r, 0);
+		SetPic(panel);
+		// ボタンの中心線を描画、設定
+		Surface* s = parent->Root().NewSurface(r.width(), r.height()/2, ALPHA_MASK);
+		DSurfaceFill(s, Rect(0,0,r.width(),r.height()/2), 0, 0, 0, 0xff);
+		Pic()->SetSurface(s, 0, -r.height()/4, 0);
+		Pic()->SetSurfaceFreeFlag();
+	}
+	arrow_up->press_func = &Scale::PressArrowUp;
+	arrow_up->press_pointer = (void*)this;
+	arrow_down->press_func = &Scale::PressArrowDown;
+	arrow_down->press_pointer = (void*)this;
+	arrow_up->show();
+	arrow_down->show();
+	panel->show();
+	InitCursor(0);
+}
+
+void Scale::InitCursor(int width_ratio) {
+	int r=cursor_color.r, g=cursor_color.g, b=cursor_color.b;
+	if (cursor) delete cursor;
+	cursor = 0;
+	Rect region(0,0);
+	if (width_ratio < 0) width_ratio = 0;
+	else if (width_ratio > 1024) width_ratio = 1024;
+	if (is_vertical) {
+		if (width_ratio == 0) cursor_width = Pic()->Width() * 3 / 2; // 幅の1.5倍
+		else cursor_width = Pic()->Height()*width_ratio/1024;
+		if (cursor_width <= 0) return; // カーソルなし(いいのか?)
+		region = Rect(0, 0, Pic()->Width(), cursor_width);
+	} else { // horizontal
+		if (width_ratio == 0) cursor_width = Pic()->Height() * 3 / 2; // 高さの1.5倍
+		else cursor_width = Pic()->Width()*width_ratio/1024;
+		if (cursor_width <= 0) return; // カーソルなし(いいのか?)
+		region = Rect(0, 0, cursor_width, Pic()->Height());
+	}
+
+	int height = region.height();
+	int width = region.width();
+	char* box = create_box(width, height, r, g, b);
+	Surface* boxs = parent->Root().NewSurfaceFromRGBAData(width, height*3, box, ALPHA_MASK);
+	cursor = new Button(container, panel, boxs, 0, 0, 0, height, 3, region, 2);
+	cursor->Pic()->SetSurfaceFreeFlag();
+
+	cursor->press_func = &Scale::PressCursor;
+	cursor->press_pointer = (void*)this;
+	cursor->drag_func = &Scale::DragCursor;
+	cursor->drag_pointer = (void*)this;
+	cursor->show();
+
+	// 矢印等をクリックしたときの移動量計算
+	int bar_width;
+	if (is_vertical) bar_width = Pic()->Height();
+	else bar_width = Pic()->Width();
+	if (bar_width <= 0) value_add = max-min;
+	else if (cursor_width == 0) value_add = 2;
+	else value_add = scale_max*cursor_width/bar_width;
+
+	return;
+}
+
+void Scale::PressArrowDown(void* pointer, Button* from) {
+	Scale* self = (Scale*)pointer;
+	self->SetScaleValue(self->value + self->value_add);
+}
+void Scale::PressArrowUp(void* pointer, Button* from){
+	Scale* self = (Scale*)pointer;
+	self->SetScaleValue(self->value - self->value_add);
+}
+void Scale::PressCursor(void* pointer, Button* from){
+	Scale* self = (Scale*)pointer;
+	self->value_dragstart = self->value;
+}
+void Scale::DragCursor(int x_from, int y_from,int x, int y, void* pointer, Button* from){
+	Scale* self = (Scale*)pointer;
+	int dx, w;
+	if (self->is_vertical) {
+		dx = y-y_from;
+		w = self->Event::Video::Region().height();
+	} else {
+		dx = x-x_from;
+		w = self->Event::Video::Region().width();
+	}
+	if (w == 0) return;
+	self->SetScaleValue(self->value_dragstart + dx*scale_max/w);
+}
+int Scale::CalcValue(void) {
+	Rect own_region = Event::Video::Region();
+	int x, w;
+	if (is_vertical) {
+		w = own_region.height();
+		x = mouse_y - own_region.ty;
+	} else {
+		w = own_region.width();
+		x = mouse_x - own_region.lx;
+	}
+	if (w == 0) return 0;
+	if (x < 0) x = 0;
+	else if (x > w) x = w;
+	return x*scale_max/w;
+}
+void Scale::Press(void){
+	int v = CalcValue();
+	if (v < value) SetScaleValue(value-value_add);
+	else SetScaleValue(value+value_add);
+	return;
+}
+void Scale::Motion(int x, int y){
+	mouse_x = x;
+	mouse_y = y;
+}
+
+void Scale::SetRange(int new_min, int new_max) {
+	min = new_min;
+	max = new_max;
+	SetValue(value);
+	return;
+}
+void Scale::SetValue(int new_value) {
+	if (min == max) {
+		value = min;
+		SetScaleValue(0);
+		return;
+	}
+	int scale_value = (new_value-min) * scale_max / (max-min);
+	SetScaleValue(scale_value);
+}
+int Scale::GetValue(void) const{
+	return min + value * (max-min) / scale_max;
+}
+void Scale::SetScaleValue(int new_value) {
+	if (new_value < 0) value = 0;
+	else if (new_value > scale_max) value = scale_max;
+	else value = new_value;
+	if (is_vertical) {
+		int h = Pic()->Height();
+		int y = (h-cursor_width) * value / scale_max;
+		if (y < 0) y = 0;
+		cursor->Pic()->Move(0, y);
+	} else { // horizontal
+		int w = Pic()->Width();
+		int x = (w-cursor_width) * value / scale_max;
+		if (x < 0) x = 0;
+		cursor->Pic()->Move(x, 0);
+	}
+	if (change_func) {
+		(*change_func)(change_pointer, this);
+	}
+	return;
+}
+
+TextButton::TextButton(Event::Container& container, PicContainer* parent, const char* text, int _text_size, Attribute attr, const Rect& r_orig, int _z, const Color& _fore, const Color& _pressed, const Color& _back) :
+	Button(container, parent, (Surface*)0, 0, 0, 0, 0, 0, r_orig, _z),
+	root(parent->Root()), surface(0), attribute(attr), text_size(_text_size),
+	fore(_fore), pressed(_pressed), back(_back)
+{
+	bool rect_changed = false;
+	// まず、テキスト領域の広さを得る
+	Rect r(r_orig);
+
+	if (text == 0) text = "";
+	int width = r.width(); int height = r.height();
+	if (width == 0) width = parent->Width() - r.lx;
+
+	TextGlyphStream gs = DefaultLayout(text_size)->Layout(text, width);
+
+	if (r.width() == 0) { // 文字に合わせてウィジット作成
+		rect_changed = true;
+		width = gs.width() + text_size;
+		r.rx = r.lx + gs.width();
+		attribute = Attribute(attribute | CENTER);
+	}
+	if (r.height() == 0) {
+		rect_changed = true;
+		if (attribute & NOPADDING) r.by = r.ty + gs.height();
+		else r.by = r.ty + gs.height() + text_size/2;
+	}
+
+	if (rect_changed) {
+		// 大きさ変更
+		Pic()->SetSurfaceRect(r);
+	}
+
+	sx = 0; sy = 0; sdx = 0; sdy = r.height(); nptn = 3;
+	int x = 0, y = 0;
+	if (attribute & CENTER)
+		x = (Pic()->Width() - gs.width()) / 2;
+	y = (Pic()->Height() - gs.height()) / 2;
+
+	if (back.a == 0) { // 背景なし、もしくはボタン押の状態のみ背景あり
+		surface = root.NewSurface(r.width(), r.height()*2, ALPHA_MASK);
+		DSurfaceFill(surface, Rect(*surface), 0, 0, 0, 0);
+		if (attribute & REVERSE) {
+			DSurfaceFill(surface, Rect(0,r.height(),r.width(),r.height()*2), pressed.r, pressed.g, pressed.b, 0xff);
+		}
+		gs.SetColor(fore.r, fore.g, fore.b);
+		DSurfaceRenderText(gs.begin(), gs.end(), Rect(0,0,gs.width(),gs.height()), surface, Rect(x,y));
+		gs.SetColor(pressed.r, pressed.g, pressed.b);
+		if (attribute & REVERSE) {
+			gs.SetReverse(true);
+			DSurfaceRenderText(gs.begin(), gs.end(), Rect(0,0,gs.width(),gs.height()), surface, Rect(x,y+r.height()));
+			gs.SetReverse(false);
+		} else {
+			DSurfaceRenderText(gs.begin(), gs.end(), Rect(0,0,gs.width(),gs.height()), surface, Rect(x,y+r.height()));
+		}
+		nptn = 2;
+	} else { // ボタン型の背景あり
+		/* ラベル用の Surface を作る */
+		width = r.width(); height = r.height();
+		char* box = create_box(width, height, back.r, back.g, back.b);
+		surface = root.NewSurfaceFromRGBAData(r.width(), r.height()*3, box, ALPHA_MASK);
+	
+		Surface* text_surface = root.NewSurface(r.width(), r.height(), ALPHA_MASK);
+		DSurfaceFill(text_surface, Rect(*text_surface), 0, 0, 0, 0);
+	
+		gs.SetColor(fore.r, fore.g, fore.b);
+		DSurfaceRenderText(gs.begin(), gs.end(), Rect(0,0,gs.width(),gs.height()), text_surface, Rect(x,y));
+		root.BlitSurface(text_surface, Rect(0,0,width,height), surface, Rect(0,0));
+		gs.SetColor(pressed.r, pressed.g, pressed.b);
+		DSurfaceRenderText(gs.begin(), gs.end(), Rect(0,0,gs.width(),gs.height()), text_surface, Rect(x,y));
+		root.BlitSurface(text_surface, Rect(0,0,width,height), surface, Rect(0,height));
+		root.BlitSurface(text_surface, Rect(0,0,width,height), surface, Rect(0,height*2));
+		root.DeleteSurface(text_surface);
+	}
+
+	Pic()->SetSurface(surface, 0, 0);
+	show();
+}
+void TextButton::SetText(const char* text, const Color& _fore, const Color& _pressed, const Color& _back)
+{
+	int width = Pic()->Width(); int height = Pic()->Height();
+	// まず、テキスト領域の広さを得る
+	if (text == 0) text = "";
+
+	TextGlyphStream gs = DefaultLayout(text_size)->Layout(text, width);
+
+	int x = 0, y = 0;
+	if (attribute & CENTER) {
+		x = (width - gs.width()) / 2;
+		y = (height - gs.height()) / 2;
+	}
+	int surf_x = Pic()->SurfacePosX();
+	int surf_y = Pic()->SurfacePosY();
+	Pic()->SetSurface( (Surface*)0,0,0);
+	root.DeleteSurface(surface);
+	surface = 0;
+
+	if (back.a == 0) { // 背景なし
+		surface = root.NewSurface(width, height*2, ALPHA_MASK);
+		DSurfaceFill(surface, Rect(*surface), 0, 0, 0, 0);
+		if (attribute & REVERSE) {
+			DSurfaceFill(surface, Rect(0,height,width,height*2), pressed.r, pressed.g, pressed.b, 0xff);
+		}
+		gs.SetColor(_fore.r, _fore.g, _fore.b);
+		DSurfaceRenderText(gs.begin(), gs.end(), Rect(0,0,gs.width(),gs.height()), surface, Rect(x,y));
+		gs.SetColor(_pressed.r, _pressed.g, _pressed.b);
+		gs.SetReverse(true);
+		DSurfaceRenderText(gs.begin(), gs.end(), Rect(0,0,gs.width(),gs.height()), surface, Rect(x,y+height));
+		gs.SetReverse(false);
+		nptn = 2;
+	} else {
+		/* ラベル用の Surface を作る */
+		char* box = create_box(width, height, _back.r, _back.g, _back.b);
+		surface = root.NewSurfaceFromRGBAData(width, height*3, box, ALPHA_MASK);
+	
+		Surface* text_surface = root.NewSurface(width, height, ALPHA_MASK);
+		DSurfaceFill(text_surface, Rect(*text_surface), 0, 0, 0, 0);
+	
+		gs.SetColor(_fore.r, _fore.g, _fore.b);
+		DSurfaceRenderText(gs.begin(), gs.end(), Rect(0,0,gs.width(),gs.height()), text_surface, Rect(x,y));
+		root.BlitSurface(text_surface, Rect(0,0,width,height), surface, Rect(0,0));
+		gs.SetColor(_pressed.r, _pressed.g, _pressed.b);
+		DSurfaceRenderText(gs.begin(), gs.end(), Rect(0,0,gs.width(),gs.height()), text_surface, Rect(x,y));
+		root.BlitSurface(text_surface, Rect(0,0,width,height), surface, Rect(0,height));
+		root.BlitSurface(text_surface, Rect(0,0,width,height), surface, Rect(0,height*2));
+		root.DeleteSurface(text_surface);
+	}
+
+	Pic()->SetSurface(surface, surf_x, surf_y);
+	show();
+}
+
+TextButton::~TextButton() {
+	if (surface) root.DeleteSurface(surface);
+	surface = 0;
+	return;
+}
+
+Text::Text(Event::Container& container, PicContainer* parent, const Rect& r, const Rect& text_r, int _fontsize) :
+	Event::Video(container),
+	Event::Time(container),
+	event(container),
+	srcrect(0,0,0,0),
+	layout(wdefault_font.c_str(), _fontsize), fontsize(_fontsize) {
+
+	SetPic(parent->create_node(r, 0));
+	surface = parent->Root().NewSurface(text_r.width(), text_r.height(), ALPHA_MASK);
+	pictext = PicNode()->create_leaf(text_r, PicBase::CACHE_BACK);
+	pictext->SetSurface(surface, 0, 0);
+	pictext->show();
+	cursor = 0;
+	cursor_activated = false;
+	window_activated = false;
+
+	event.RegisterGlobalPressFunc(&Pressed, (void*)this);
+
+	speed = 10;
+	wait_delay = -1;
+	status = PREPARE;
+	old_time = wait_starttime = 0;
+}
+
+Text::~Text() {
+	event.DeleteGlobalPressFunc(&Pressed, (void*)this);
+	PicNode()->Root().DeleteSurface(surface);
+}
+
+void Text::SetSpeed(int new_speed) {
+	speed = new_speed;
+}
+void Text::SetWait(int new_wait) {
+	if (new_wait < 0) new_wait = 100000000;
+	wait_delay = new_wait;
+}
+
+int Text::CalcScrollHeight(void) {
+	int i;
+	int len = bottom_pos.size();
+	int y0 = bottom_pos[line_number];
+	int height = Rect(*surface).height();
+	for (i=line_number; i<len; i++)
+		if (bottom_pos[i] - y0 > height) break;
+	if (i == line_number) i = line_number + 1;
+	return i - line_number - 1;
+}
+void Text::Elapsed(unsigned int current_time) {
+	SetWakeup(current_time + 50);
+	if (status == PREPARE) {
+		old_time = current_time;
+		return;
+	}
+	int nChar = speed * (current_time - old_time) / 1000;
+	if (speed == -1 || press_count) nChar = -1;
+	if (nChar == 0) return;
+	if (speed == -1) old_time = current_time;
+	else old_time += nChar * 1000 / speed;
+
+	switch(status) {
+	case WAIT: goto label_wait;
+	case SCROLL: goto label_scroll;
+	case DRAW2: goto label_draw2;
+	case WAIT2: goto label_wait2;
+	}
+
+	status = DRAW;
+	if (press_count) {
+		nChar = -1;
+		press_count = 0;
+	}
+	DrawText(nChar);
+	if (nChar == 0) return;
+	status = WAIT;
+	cursor_activated = true;
+	if (cursor_activated && window_activated && cursor) cursor->show();
+	wait_starttime = current_time;
+label_wait:
+	if (current_time < wait_starttime + wait_delay && press_count == 0) return;
+	press_count = 0;
+	nChar = 0;
+	cursor_activated = false;
+	if (cursor) cursor->hide();
+	while(cur_pos != gstream.end()) {
+		// スクロールしては次行描画、を繰り返す
+		for (scroll_height = CalcScrollHeight(); scroll_height > 0; scroll_height--) {
+			status = SCROLL;
+label_scroll:
+			if (press_count) break;
+			Scrollup(nChar);
+			if (nChar == 0) return;
+			status = DRAW2;
+label_draw2:
+			if (press_count) break;
+			DrawText(nChar);
+			if (nChar == 0) return;
+		}
+		if (nChar != 0 && scroll_height) {
+			nChar = 100000;
+			if (status == SCROLL) Scrollup(nChar);
+			DrawText(nChar);
+			scroll_height--;
+			for (; scroll_height > 0; scroll_height--) {
+				Scrollup(nChar);
+				DrawText(nChar);
+			}
+		}
+		press_count = 0;
+		status = WAIT2;
+		cursor_activated = true;
+		if (cursor_activated && window_activated && cursor) cursor->show();
+		wait_starttime = current_time;
+label_wait2:
+		if (current_time < wait_starttime + wait_delay && press_count == 0) return;
+		press_count = 0;
+		nChar = 0;
+		cursor_activated = false;
+		if (cursor) cursor->hide();
+	}
+	status = PREPARE;
+	return;
+}
+
+bool Text::Pressed(int x, int y, void* pointer) {
+	Text* wid = (Text*)pointer;
+	if (wid->Pic()->IsHidden()) return true;
+	wid->press_count++;
+	return true;
+}
+
+void Text::Clear(void) {
+	stream.container.clear();
+	DSurfaceFill(surface, Rect(*surface), 0, 0, 0, 0);
+	pictext->ReBlit();
+	status = PREPARE;
+}
+
+void Text::Flush(void) {
+	int nChar = -1;
+	DrawText(nChar);
+}
+
+void Text::Start(void) {
+	gstream.clear();
+	bottom_pos.clear();
+	layout.Layout(stream, gstream, bottom_pos, pictext->Width()-fontsize/2);
+
+	// height の積算値として bottom_pos を計算
+	std::vector<int>::iterator it;
+	int pos = 0;
+	for (it = bottom_pos.begin(); it != bottom_pos.end(); it++) {
+		pos += *it;
+		*it = pos;
+	}
+
+	cur_pos = gstream.begin();
+	line_number = 0;
+	scrolled_count = 0;
+	srcrect = Rect(0, 0, pictext->Width(), pictext->Height());
+	press_count = 0;
+
+	status = DRAW;
+	cursor_activated = false;
+	if (cursor) cursor->hide();
+}
+
+void Text::DrawText(int& nChar) {
+	// 描画範囲を得る
+	iterator end = gstream.end();
+	iterator it = cur_pos;
+	while(nChar && it != end) { // nChar < 0 なら出来るだけの文字を描画
+		if (! (it->flag & TextGlyph::Group)) nChar--;
+		if (it->flag & TextGlyph::LineEnd) {
+			if (bottom_pos[line_number+1] > srcrect.by) { //改行すると画面から出てしまう
+				it++;
+				if (nChar == 0) nChar = 1;
+				break;
+			}
+			line_number++;
+		}
+		it++;
+	}
+	// 描画する
+	Rect r = DSurfaceRenderText(cur_pos, it, srcrect, surface, Rect(0,0,0,0));
+	pictext->ReBlit(r);
+	cur_pos = it;
+	return;
+}
+
+void Text::Scrollup(int& nChar) {
+	if (nChar < 0) { // 一画面分スクロールする
+		DSurfaceFill(surface, Rect(*surface), 0, 0, 0, 0);
+		pictext->ReBlit();
+		srcrect = Rect(*surface);
+		srcrect.rmove(0, bottom_pos[line_number]);
+		line_number++;
+		scrolled_count = 0;
+		return;
+	}
+	// スクロール幅を求める
+	const int max_scroll_count = 8;
+	int dy = bottom_pos[line_number+1] - bottom_pos[line_number];
+	int cur_dy;
+	if (scrolled_count+nChar >= max_scroll_count) {
+		cur_dy = dy - (scrolled_count*dy/max_scroll_count);
+		nChar -= max_scroll_count-scrolled_count;
+		nChar++;
+		scrolled_count = 0;
+		line_number++;
+		srcrect.rmove(0, dy);
+	} else {
+		cur_dy = (scrolled_count+nChar)*dy/max_scroll_count;
+		cur_dy -=(scrolled_count*dy/max_scroll_count);
+		scrolled_count += nChar;
+		nChar = 0;
+	}
+	Rect r(*surface);
+	DSurfaceMove(surface, r, surface, Rect(0, -cur_dy, 0, 0));
+	r.ty = r.by-cur_dy;
+	DSurfaceFill(surface, r, 0, 0, 0, 0);
+	pictext->ReBlit();
+	return;
+}
+
+void Text::activate(void) {
+	event.RegisterGlobalPressFunc(&Pressed, (void*)this);
+	Event::Video::activate();
+	window_activated = true;
+	if (cursor_activated && window_activated && cursor) cursor->show();
+}
+void Text::deactivate(void) {
+	event.DeleteGlobalPressFunc(&Pressed, (void*)this);
+	Event::Video::deactivate();
+	window_activated = false;
+	if (cursor) cursor->hide();
+}
+void Text::SetCursor(TimeCursor* c) {
+	cursor = c;
+	if (c) {
+		if (cursor_activated && window_activated) c->show();
+		else c->hide();
+	}
+}
+
+Label::Label(PicContainer* parent, const Rect& r_orig, bool _is_center, const char* text, int _text_size) :
+	is_center(_is_center),
+	root(parent->Root()),
+	text_size(_text_size) {
+	Rect r(r_orig);
+
+	if (text == 0) text = "";
+	int width = r.width(); int height = r.height();
+	if (width == 0) width = parent->Width() - r.lx;
+
+	TextGlyphStream gs = DefaultLayout(text_size)->Layout(text, width);
+
+	if (r.width() == 0) { // 文字に合わせてウィジット作成
+		width = gs.width();
+		r.rx = r.lx + gs.width();
+	}
+	if (r.height() == 0) {
+		r.by = r.ty + gs.height();
+	}
+
+	SetPic(parent->create_leaf(r, 0));
+
+	/* ラベル用の Surface を作る */
+	surface = parent->Root().NewSurface(r.width(), r.height(), ALPHA_MASK);
+	
+	DSurfaceFill(surface, Rect(*surface), 0, 0, 0, 0);
+	int x = 0, y = 0;
+	if (is_center) {
+		x = (Pic()->Width() - gs.width()) / 2;
+		y = (Pic()->Height() - gs.height()) / 2;
+	}
+
+	DSurfaceRenderText(gs.begin(), gs.end(), Rect(*surface), surface, Rect(x,y));
+
+	Pic()->SetSurface(surface, 0, 0);
+	show();
+}
+Label::~Label() {
+	root.DeleteSurface(surface);
+}
+void Label::SetText(const char* text) {
+	if (text == 0) text = "";
+	TextGlyphStream gs = DefaultLayout(text_size)->Layout(text, Pic()->Width());
+	DSurfaceFill(surface, Rect(*surface), 0, 0, 0, 0);
+	int x = 0, y = 0;
+	if (is_center) {
+		x = (Pic()->Width() - gs.width()) / 2;
+		y = (Pic()->Height() - gs.height()) / 2;
+	}
+
+	DSurfaceRenderText(gs.begin(), gs.end(), Rect(*surface), surface, Rect(x,y));
+	Pic()->ReBlit();
+}
+
+Dialog::Dialog(Event::Container& container, PicContainer* parent, const char* text, bool with_cancel) :
+	Event::Video(container) {
+
+	int x,y;
+	status = WAIT;
+	set_func = 0;
+	set_pointer = 0;
+
+	XKFont::HorizLayout& layout = *DefaultLayout(26);
+	int dialog_width = parent->Width() / 2;
+	TextGlyphStream s_ok = layout.Layout("OK", dialog_width);
+	TextGlyphStream s_cancel = layout.Layout("取消", dialog_width);
+	TextGlyphStream s_text = layout.Layout(text, dialog_width);
+
+	Rect r_text(0, 0, s_text.width(), s_text.height());
+	Rect r_ok(0, 0, s_ok.width(), s_ok.height());
+	Rect r_cancel(0, 0, s_cancel.width(), s_cancel.height());
+
+	/* ダイアログボックスの Surface を作る */
+	int dwidth = r_text.width() + (r_text.width()/10)*2 + 6;
+	int dheight = r_text.height() + r_ok.height() + r_cancel.height()*3 + 4;
+	surface_diag = parent->Root().NewSurface(dwidth, dheight, NO_MASK); // alpha なし
+	DSurfaceFill(surface_diag, Rect(*surface_diag), 0xf0, 0xd0, 0xa0);
+	DrawBox(surface_diag, Rect(0,0,dwidth,dheight));
+
+	Surface* surface_text = parent->Root().NewSurface(r_text.width(), r_text.height(), ALPHA_MASK);
+	s_text.SetColor(0x38, 0x20, 0x18);
+	DSurfaceRenderText(s_text.begin(), s_text.end(), r_text, surface_text, Rect(0, 0, 0, 0));
+	x = r_text.width()/10 + 3;
+	y = r_cancel.height()+2;
+	parent->Root().BlitSurface(surface_text, r_text, surface_diag, Rect(x, y, x+r_text.width(), y+r_text.height()));
+	parent->Root().DeleteSurface(surface_text);
+
+	/* panel をつくる */
+	x = (parent->Width()-dwidth)/2;
+	y = (parent->Height()-dheight)/2;
+	SetPic(parent->create_node(Rect(x, y, x+dwidth, y+dheight), 0));
+
+	/* ボタンを作成する */
+	/* f8d8c8 背景(明)*/
+	/* f0d0a0 背景*/
+	/* b08040 枠(明)*/
+	/* 805010 枠*/
+	/* 382018 黒*/
+	/* 9890f8 青*/ 
+	/* dc6448 赤*/
+	/* 各ボタンは左右にボタン幅の 1/4, 上下にボタン幅の 1/4 のマージンを持つ */
+	Rect r_btn(r_ok); r_btn.join(r_cancel);
+	int btn_width = r_btn.width() * 3 / 2;
+	int btn_height = r_btn.height() * 3 / 2;
+	surface_btn = parent->Root().NewSurface(btn_width, btn_height*4, ALPHA_MASK);
+	DSurfaceFill(surface_btn, Rect(*surface_btn), 0, 0, 0, 0);
+	s_ok.SetColor(0x38, 0x20, 0x18);
+	DSurfaceRenderText(s_ok.begin(), s_ok.end(), r_ok, surface_btn, Rect( (btn_width-r_ok.width())/2,(btn_height-r_ok.height())/2));
+	s_ok.SetColor(0x98, 0x90, 0xf8);
+	DSurfaceRenderText(s_ok.begin(), s_ok.end(), r_ok, surface_btn, Rect( (btn_width-r_ok.width())/2,(btn_height-r_ok.height())/2 + btn_height));
+	s_cancel.SetColor(0x38, 0x20, 0x18);
+	DSurfaceRenderText(s_cancel.begin(), s_cancel.end(), r_cancel, surface_btn, Rect( (btn_width-r_cancel.width())/2,(btn_height-r_cancel.height())/2 + btn_height*2));
+	s_cancel.SetColor(0xdc, 0x64, 0x48);
+	DSurfaceRenderText(s_cancel.begin(), s_cancel.end(), r_cancel, surface_btn, Rect( (btn_width-r_cancel.width())/2,(btn_height-r_cancel.height())/2 + btn_height*3));
+
+	x = (dwidth - btn_width*2) / 3;;
+	y = r_cancel.height()*3/2 + r_text.height() + 2;
+	if (!with_cancel) x = (dwidth - btn_width) / 2;
+	Button* b_ok = new Button(container, PicNode(), surface_btn, 0, 0, 0, btn_height, 2, Rect(x, y, x+btn_width, y+btn_height), 1);
+	DrawBox(surface_diag, Rect(x-3,y-2,x+btn_width+3,y+btn_height+2));
+	b_ok->press_pointer = (void*)this;
+	b_ok->press_func = &press_ok;
+	if (with_cancel) {
+		x += x + btn_width;
+		Button* b_cancel = new Button(container, PicNode(), surface_btn, 0, btn_height*2, 0, btn_height, 2, Rect(x, y, x+btn_width, y+btn_height), 1);
+		DrawBox(surface_diag, Rect(x-3,y-2,x+btn_width+3,y+btn_height+2));
+		b_cancel->press_pointer = (void*)this;
+		b_cancel->press_func = &press_cancel;
+	}
+
+	Pic()->SetSurface(surface_diag, 0, 0);
+	Pic()->ZMove(ZMOVE_TOP);
+
+	show_all();
+}
+Dialog::~Dialog() {
+	PicRoot& root = PicNode()->Root();
+	SetPic(0);
+	root.DeleteSurface(surface_btn);
+	root.DeleteSurface(surface_diag);
+	return;
+}
+
+void Dialog::press_ok(void* pointer, Button* btn) {
+	if (pointer) {
+		Dialog* wid = (Dialog*)pointer;
+		wid->status = OK;
+		if (wid->set_func) {
+			(*wid->set_func)(wid->set_pointer, wid);
+		}
+	}
+}
+void Dialog::press_cancel(void* pointer, Button* btn) {
+	if (pointer) {
+		Dialog* wid = (Dialog*)pointer;
+		wid->status = CANCEL;
+		if (wid->set_func) {
+			(*wid->set_func)(wid->set_pointer, wid);
+		}
+	}
+}
+
+void Dialog::DrawBox(Surface* s, const Rect& r) {
+	DSurfaceFill(s, Rect(r.lx, r.ty, r.rx, r.ty+1), 0x80, 0x50, 0x10);
+	DSurfaceFill(s, Rect(r.lx, r.ty+1, r.rx, r.ty+2), 0x38, 0x20, 0x18);
+	DSurfaceFill(s, Rect(r.lx, r.by-2, r.rx, r.by-1), 0x80, 0x50, 0x10);
+	DSurfaceFill(s, Rect(r.lx, r.by-1, r.rx, r.by), 0x38, 0x20, 0x18);
+
+	DSurfaceFill(s, Rect(r.lx, r.ty, r.lx+1, r.by), 0xb0, 0x80, 0x40);
+	DSurfaceFill(s, Rect(r.lx+1, r.ty+1, r.lx+2, r.by-1), 0x80, 0x50, 0x10);
+	DSurfaceFill(s, Rect(r.lx+1, r.ty+2, r.lx+2, r.by-2), 0x38, 0x20, 0x18);
+	DSurfaceFill(s, Rect(r.rx-3, r.ty+2, r.rx-2, r.by-2), 0xb0, 0x80, 0x40);
+	DSurfaceFill(s, Rect(r.rx-2, r.ty+1, r.rx-1, r.by-1), 0x80, 0x50, 0x10);
+	DSurfaceFill(s, Rect(r.rx-1, r.ty, r.rx, r.by), 0x38, 0x20, 0x18);
+}
+
+AnmTime::AnmTime(Event::Container& container, PicBase* _pic, int _total_time, int _all_count) :
+	Event::Time(container),
+	PicAnm(_pic), start_time(0), total_time(_total_time), all_count(_all_count) {
+	status = FINISHED;
+	if (total_time == 0) total_time = 1;
+}
+AnmTime::AnmTime(Event::Container& container, std::vector<PicBase*> _pic, int _total_time, int _all_count) :
+	Event::Time(container),
+	PicAnm(_pic), start_time(0), total_time(_total_time), all_count(_all_count) {
+	status = FINISHED;
+	if (total_time == 0) total_time = 1;
+}
+void AnmTime::Elapsed(unsigned int current_time) {
+	if (total_time == 0) return;
+	if (status == FINISHED || current_time == 0) {SetWakeup(current_time+1); return;}
+	if (start_time == 0) {
+		start_time = current_time;
+		Start();
+	}
+	unsigned int time_elapsed = current_time - start_time;
+	if (time_elapsed < total_time) {
+		int count = time_elapsed * all_count / total_time;
+		Exec(count);
+		int next_time = start_time + (count+1) * total_time / all_count;
+		SetWakeup(next_time);
+	} else {
+		Exec(all_count);
+		Finish();
+		status = FINISHED;
+	}
+	return;
+}
+void AnmTime::Abort(void) { 
+	if (status == FINISHED) return;
+	if (start_time == 0) {
+		Start();
+		Exec(all_count);
+	}
+	if (total_time) {
+		Finish();
+	}
+	status = FINISHED;
+}
+bool AnmTime::IsEnd(void) {
+	return status == FINISHED;
+}
+AnmMove::AnmMove(Event::Container& container, PicBase* _pic, const Rect& _to, int total_time) :
+	AnmTime(container, _pic, total_time),
+	from(0,0), to(_to) {
+	from.lx = _pic->PosX();
+	from.ty = _pic->PosY();
+	from.rx = from.lx + _pic->Width();
+	from.by = from.ty + _pic->Height();
+
+	int dx = to.lx - from.lx;
+	int dy = to.ty - from.ty;
+	if (dx < 0) dx = -dx;
+	if (dy < 0) dy = -dy;
+	if (dx < dy) dx = dy;
+	if (dx == 0) dx = 1;
+	SetAllCount(dx);
+}
+void AnmMove::Exec(int count) {
+	Rect r(from);
+	int dx = to.lx - from.lx;
+	int dy = to.ty - from.ty;
+	r.rmove(dx*count/all_count, dy*count/all_count);
+	iterator it;
+	for (it=pic.begin(); it!=pic.end(); it++) (*it)->Move(r.lx, r.ty);
+}
+AnmAlpha::AnmAlpha(Event::Container& container, PicBase* _pic, int alpha_from, int alpha_to, int total_time) :
+	AnmTime(container, _pic, total_time),
+	from(alpha_from), to(alpha_to), alpha_r(0,0,1,1) {
+	if (from < 0) from = 0;
+	if (from >= ALPHA_MAX) from = ALPHA_MAX;
+	if (to < 0) to = 0;
+	if (to >= ALPHA_MAX) to = ALPHA_MAX;
+	int c = from - to;	
+	if (c < 0) c = -c;
+	if (c == 0) c = 1;
+	SetAllCount(c);
+}
+AnmAlpha::AnmAlpha(Event::Container& container, std::vector<PicBase*> _pic, int alpha_from, int alpha_to, int total_time) :
+	AnmTime(container, _pic, total_time),
+	from(alpha_from), to(alpha_to), alpha_r(0,0,1,1) {
+	if (from < 0) from = 0;
+	if (from >= ALPHA_MAX) from = ALPHA_MAX;
+	if (to < 0) to = 0;
+	if (to >= ALPHA_MAX) to = ALPHA_MAX;
+	int c = from - to;	
+	if (c < 0) c = -c;
+	if (c == 0) c = 1;
+	SetAllCount(c);
+}
+void AnmAlpha::Start(void) {
+	iterator it;
+	for (it=pic.begin(); it!=pic.end(); it++) (*it)->show();
+}
+void AnmAlpha::Exec(int count) {
+	alpha = (from * (all_count-count) + (to-from) * count) / all_count;
+	iterator it;
+	for (it=pic.begin(); it!=pic.end(); it++) (*it)->SetSurfaceAlpha(&alpha, alpha_r);
+}
+void AnmAlpha::Finish(void) {
+	iterator it;
+	for (it=pic.begin(); it!=pic.end(); it++) {
+		if (to == 0) (*it)->hide();
+		else if (to != ALPHA_MAX) fprintf(stderr,"Warning in AnmAlpha::Finish: alpha value suddenly changed.\n");
+		(*it)->SetSurfaceAlpha(0,Rect(0,0));
+	}
+}
+AnmAlphaMove::AnmAlphaMove(Event::Container& container, PicBase* _pic) :
+	AnmTime(container, _pic, 0) {
+}
+void AnmAlphaMove::SetPtn(void) {
+	int total = 0;
+	std::vector<Ptn>::iterator it;
+	for (it=ptns.begin(); it!=ptns.end(); it++) {
+		if (total < it->next_tick) total = it->next_tick;
+	}
+	SetAllCount(total);
+	SetTotalTime(total);
+	cur_count = 0;
+}
+void AnmAlphaMove::Exec(int count) {
+	if (ptns.empty()) return;
+	if (cur_count != 0 && ptns[cur_count].next_tick > count) return;
+	if (cur_count >= ptns.size()) return;
+	// 次のパターンを探す
+	// count <= it->next_tick なる条件を満たす最後の it を探す
+	std::vector<Ptn>::iterator it;
+	for (it=ptns.begin()+cur_count; it != ptns.end(); it++) {
+		if (count <= it->next_tick) break;
+	}
+	if (it == ptns.end()) {
+		fprintf(stderr,"end\n");
+		it = ptns.end() - 1;
+	}
+	cur_count = it - ptns.begin();
+
+	iterator p;
+	for (p=pic.begin(); p!=pic.end(); p++) {
+		// move
+		(*p)->Move(it->pos.lx, it->pos.ty);
+		(*p)->SetSurfacePos(it->surface_pos.lx, it->surface_pos.ty);
+		// alpha set
+		if (it->alpha == 0) (*p)->hide();
+		else if (it->alpha == ALPHA_MAX) { (*p)->show(); (*p)->SetSurfaceAlpha(0, Rect(0,0)); }
+		else { (*p)->show(); (*p)->SetSurfaceAlpha( &(it->alpha), Rect(0,0,1,1)); }
+	}
+}
+void AnmAlphaMove::Finish(void) {
+	if (ptns.empty()) return;
+	if (cur_count >= ptns.size() - 1) return;
+	cur_count = ptns.size() - 1;
+	Exec(ptns[cur_count].next_tick); // 最後の pattern の状態にする
+}
+
+AnmPtnSolid::AnmPtnSolid(Event::Container& container, PicBase* _pic, const unsigned char* _ptn, const Rect& _alpha_r, int total_time) :
+	AnmTime(container, _pic, total_time),
+	ptn(_ptn), alpha_r(_alpha_r)
+{
+	ptn_len = alpha_r.width() * alpha_r.height();
+	alpha = new unsigned char[ptn_len];
+	int max_a = 0;
+	for (int i=0; i<ptn_len; i++) {
+		if (ptn[i] > max_a) max_a = ptn[i];
+	}
+	if (max_a == 0) max_a = 1;
+	SetAllCount(max_a);
+}
+
+AnmPtnAlpha::AnmPtnAlpha(Event::Container& container, PicBase* _pic, const unsigned char* _ptn, const Rect& _alpha_r, int _band_width, int total_time) :
+	AnmTime(container, _pic, total_time),
+	ptn(_ptn), band(_band_width), alpha_r(_alpha_r)
+{
+	ptn_len = alpha_r.width() * alpha_r.height();
+	alpha = new unsigned char[ptn_len];
+	if (band <= 0) band = 1;
+	SetAllCount(ALPHA_MAX+band);
+}
+
+void AnmPtnSolid::Exec(int count) {
+	int i;
+	for (i=0; i<ptn_len; i++) {
+		if (ptn[i] <= count) alpha[i] = ALPHA_MAX;
+		else alpha[i] = 0;
+	}
+	iterator it;
+	for (it=pic.begin(); it!=pic.end(); it++) (*it)->SetSurfaceAlpha(alpha, alpha_r);
+}
+void AnmPtnAlpha::Exec(int count) {
+	int i;
+	int ptn_zero = count;
+	int ptn_max = count - band;
+	for (i=0; i<ptn_len; i++) {
+		if (ptn[i] >= ptn_zero) alpha[i] = 0;
+		else if (ptn[i] < ptn_max) alpha[i] = ALPHA_MAX;
+		else alpha[i] = (ptn_zero-ptn[i])*ALPHA_MAX/band;
+	}
+	iterator it;
+	for (it=pic.begin(); it!=pic.end(); it++) (*it)->SetSurfaceAlpha(alpha, alpha_r);
+}
+
+void AnmPtnSolid::Start(void) {
+	iterator it;
+	for (it=pic.begin(); it!=pic.end(); it++) (*it)->show();
+}
+void AnmPtnSolid::Finish(void) {
+	iterator it;
+	for (it=pic.begin(); it!=pic.end(); it++) (*it)->SetSurfaceAlpha(0, Rect(0,0));
+}
+void AnmPtnAlpha::Start(void) {
+	iterator it;
+	for (it=pic.begin(); it!=pic.end(); it++) (*it)->show();
+}
+void AnmPtnAlpha::Finish(void) {
+	iterator it;
+	for (it=pic.begin(); it!=pic.end(); it++) (*it)->SetSurfaceAlpha(0, Rect(0,0));
+}
+
+/*
+
+Widget の種類
+	Mouse: マウス位置に連動する。Surface と origin が必須
+	Panel : なにも存在しないところに張りつけていく
+		背景張りつけも可能
+		ButtonPanel : 無効化可能。Group の Button がカーソルに入ったら、全Button / Label が「カーソル下」状態になる
+			同一変数を扱うボタンは原則、同一ButtonPanel の下に入ること(同期する。高速化可能)
+			そうでない場合、ボタンの GlobalVariable フラグを立てる必要がある
+		背景種類:Window
+			内部の透明度と枠形を別々に指定可能。枠形は全枠、部分枠どちらの形でも可能
+			(部分枠なら、内部的には上枠、下枠、左右枠と別 Surface で管理する)
+		DragButton
+			Panel 全体をドラッグし、場所変更できるボタン。
+	Button: 無効化>通常>カーソル下>ボタン押下 のpicture / animation
+		Toggle Button にできる(Group化すればRadioButtonにもできる)
+	Label : 無効化>通常>カーソル下 のanimation
+		animation は
+		・上への変化
+		・下への変化
+		・常時変形
+		の3つの形式をもつ。
+		形式は
+		・x / y increment による(全領域と x,y の大きさを指定すると左上から右上、左下、という方へ勝手に領域を変更していく)
+		・色変化(明度変化)。色テーブルを指定する。Surface は alpha のみとする
+			どちらも、一つのラベルに使う時間の長さを指定する
+		・callback による。指定した一定時間以上が立つとCallBack が呼び出され、新たなSurface , origin を指定する。
+
+		・Surface は
+			普通の画像
+			文字列(適当に仮想化)
+			画像数値列
+		のいずれか
+	Cursor
+		リターンカーソル。Label の一種。
+	Number
+		数字を表示する。フォントの大きさ、もしくは画像数値列
+	Text
+		テキストを表示する
+		パネルの大きさだけ指定すると適当にやってくれる
+		カーソルの位置(文字の次/最終)を指定すること
+		機能:文字送り速度設定、読み飛ばし設定(常に最高速で押しっぱなし)
+	ProgressBar など
+		バーの長さ、あるいは位置で変数の大きさを示す。
+		Tick, Max を指定、変数の変化には適当に対応できるようにする
+		バーの方向として縦/横。Surface は繰り返しで使う(速度上、32pixel くらいあったほうがいいかも?)
+		バーの代わりにボタンも使える。Surface 指定のメソッドが違うだけ。
+		オプション:バーのどこかをクリックされたとき、そこに移動するかそこに向かって移動するか
+		オプション?:矢印ボタン(いらないか)
+	ScrollBar
+		横/縦。Panel と連動する(専用, ProgressBar の一種として実装)
+		(Panel 側で「見えない部分はdelete, 見える部分は自動で作成」機能をつける?:バックログ)
+
+	
+	
+メニューの出し方
+	右クリック
+	ボタンを押す
+	上の方、右の方など領域に行くとヌっと出てくる
+メニューモード内
+	ボタンを押して終了
+	マップを作っておき、各メニューに名前を割り振ると二次元に広がったメニューになる
+	名前を割り振ると上に名前リストがでてくる
+	名前を割り振ると横に名前リストが出てくる
+
+*/
+// }
new file mode 100644
--- /dev/null
+++ b/window/widget.h
@@ -0,0 +1,299 @@
+#ifndef __WIDGET_H__
+#define __WIDGET_H__
+
+#include<vector>
+#include"font/font.h"
+#include"font/text.h"
+#include"event.h"
+#include"picture.h"
+
+#define TimeCursor WidTimeCursor
+#define MouseCursor WidMouseCursor
+#define Button WidButton
+#define Scale WidScale
+#define Label WidLabel
+#define Dialog WidDialog
+#define TextButton WidTextButton
+#define Text WidText
+#define AnmTime WidAnmTime
+#define AnmMove WidAnmMove
+#define AnmAlpha WidAnmAlpha
+#define AnmPtnSolid WidAnmPtnSolid
+#define AnmPtnAlpha WidAnmPtnAlpha
+
+// namespace Widget {
+
+struct TimeCursor : public Event::Time, PicWidget {
+	int x,y,dx,dy, nptn;
+	int old_time, count, interval;
+	TimeCursor(Event::Container& container, int _interval, PicContainer* parent, const char* fname, int sx, int sy, int sdx, int sdy, int nptn, const Rect& r);
+	void Elapsed(unsigned int current_time);
+};
+
+struct MouseCursor : public Event::Video, PicWidget {
+	int x, y;
+	Event::Container& container;
+	MouseCursor(Event::Container& container, PicContainer* parent, const char* s, int x, int y, int w, int h);
+	MouseCursor(Event::Container& container, PicContainer* parent, Surface* s, int x, int y, int w, int h);
+	~MouseCursor();
+	static bool Motionfunc(int x, int y, void* pointer);
+};
+
+struct Button : public Event::Video, PicWidget {
+	int sx, sy, sdx, sdy, nptn;
+	bool is_in;
+	bool is_toggled;
+	bool is_toggle_switch;
+	Button(Event::Container& container, PicContainer* parent, const char* s, int sx, int sy, int sdx, int sdy, int nptn, const Rect& r, int _z);
+	Button(Event::Container& container, PicContainer* parent, Surface* s, int sx, int sy, int sdx, int sdy, int nptn, const Rect& r, int _z);
+	~Button();
+	void Press(void);
+	void Release(void);
+	void Drag(int x_from, int y_from, int x_to, int y_to);
+	void In(void);
+	void Out(void);
+	void Toggle(bool new_toggle);
+	typedef void (*PressFunc)(void* pointer, Button* from);
+	typedef void (*DragFunc)(int x_from, int y_from, int x_to, int y_to, void* pointer, Button* from);
+	PressFunc press_func;
+	void* press_pointer;
+	DragFunc drag_func;
+	void* drag_pointer;
+
+	/* 継承 */
+	void activate(void) { Event::Video::activate();}
+	void deactivate(void) { Event::Video::deactivate();}
+	void SetRegion(const Rect& new_rect) { Event::Video::SetRegion(new_rect);}
+};
+struct Scale : Event::Video, PicWidget {
+private:
+	Button* arrow_down, *arrow_up;
+	Button* cursor;
+	PicContainer* panel;
+	Event::Container& container;
+	PicContainer* parent;
+	Color cursor_color;
+
+	int mouse_x, mouse_y;
+	enum {scale_max = 65536};
+	int min, max;
+	int value;
+	int value_add;
+	int value_dragstart;
+	int cursor_width;
+	bool is_vertical;
+
+public:
+
+	Scale(Event::Container& container, PicContainer* parent, const Rect& r_orig, const Color& cursor_color, bool _is_vertical);
+	void InitCursor(int cursor_width_ratio); // 1024=max
+	void SetRange(int min, int max);
+	void SetValue(int value);
+	int GetValue(void) const;
+	typedef void (*ChangeFunc)(void* pointer, Scale* from);
+	ChangeFunc change_func;
+	void* change_pointer;
+private:
+	void Init(Rect r_orig);
+	int CalcValue(void);
+	void SetScaleValue(int value);
+
+	// callback
+	static void PressArrowDown(void* pointer, Button* from);
+	static void PressArrowUp(void* pointer, Button* from);
+	static void PressCursor(void* pointer, Button* from);
+	static void DragCursor(int x_from, int y_from,int x, int y, void* pointer, Button* from);
+
+	// 継承:Event::Video
+	void Press(void);
+	void Motion(int x, int y);
+
+	/* 継承 : PicWidget */
+	void activate(void) { Event::Video::activate();}
+	void deactivate(void) { Event::Video::deactivate();}
+	void SetRegion(const Rect& new_rect) { Event::Video::SetRegion(new_rect);}
+};
+
+struct TextButton : public Button {
+	enum Attribute {CENTER=1, REVERSE=2, NOPADDING=4};
+	PicRoot& root;
+	Surface* surface;
+	Attribute attribute;
+	int text_size;
+	Color fore, pressed, back;
+	TextButton(Event::Container& container, PicContainer* parent, const char* s, int text_size, Attribute attr, const Rect& r, int _z, const Color& fore, const Color& pressed, const Color& back);
+	void SetText(const char* s, const Color& fore, const Color& pressed, const Color& back);
+	void SetText(const char* s) {
+		SetText(s, fore, pressed, back);
+	}
+	~TextButton();
+};
+
+struct Text : public Event::Video, Event::Time, PicWidget {
+	typedef TextGlyphStream::iterator iterator;
+
+private:
+	Event::Container& event;
+public:
+	PicBase* pictext;
+private:
+	TimeCursor* cursor;
+	Surface* surface;
+	TextGlyphStream gstream;
+	std::vector<int> bottom_pos; // 行高さ(height)の累計値
+	XKFont::HorizLayout layout;
+	int fontsize;
+
+	iterator cur_pos;
+	int line_number;
+	Rect srcrect;
+	int press_count;
+	int scrolled_count;
+	int scroll_height;
+	bool window_activated;
+	bool cursor_activated;
+
+	int speed; // chars / sec or -1
+	int wait_delay; // msec
+	int old_time;
+	int wait_starttime;
+
+	int CalcScrollHeight(void);
+	void DrawText(int& nChar);
+	void Scrollup(int& nChar);
+public:
+	Text(Event::Container& container, PicContainer* parent, const Rect& r, const Rect& text_r, int fontsize);
+	~Text();
+
+	TextStream stream;
+	enum {PREPARE, DRAW, WAIT, SCROLL, DRAW2, WAIT2} status;
+
+	void Clear(void);
+	void Start(void);
+	void Flush(void);
+
+	void Elapsed(unsigned int current_time);
+	static bool Pressed(int x, int y, void* pointer);
+	void activate(void);
+	void deactivate(void);
+	void SetSpeed(int new_speed);
+	void SetWait(int new_wait);
+
+	void SetCursor(TimeCursor* cursor);
+};
+
+extern void SetFont(const char* fontname);
+
+struct Label : PicWidget{
+private:
+	Surface* surface;
+	bool is_center;
+	PicRoot& root;
+	int text_size;
+public:
+	Label(PicContainer* parent, const Rect& r_orig, bool is_center=true, const char* text=0, int textsize = 26);
+	~Label();
+	void SetText(const char* text);
+};
+
+class Dialog : public Event::Video, PicWidget {
+	Surface* surface_btn;
+	Surface* surface_diag;
+public:
+	enum { WAIT, OK, CANCEL} status;
+	Dialog(Event::Container& container, PicContainer* parent, const char* text, bool with_cancel);
+	~Dialog();
+	static void press_ok(void* pointer, Button* btn);
+	static void press_cancel(void* pointer, Button* btn);
+	static void DrawBox(Surface* s, const Rect& r);
+	typedef void (*SetFunc)(void* pointer, Dialog* from);
+	SetFunc set_func;
+	void* set_pointer;
+};
+
+struct AnmTime : public Event::Time, PicAnm {
+	enum { PLAYING=1, FINISHED=3 } status;
+	unsigned int start_time;
+	unsigned int total_time;
+	int all_count;
+	
+	AnmTime(Event::Container& container, PicBase* _pic, int total_time, int all_count = 0);
+	AnmTime(Event::Container& container, std::vector<PicBase*> _pic, int total_time, int all_count = 0);
+	virtual ~AnmTime() {}
+	void SetAllCount(int new_all_count) { all_count = new_all_count; }
+	void SetTotalTime(int new_total) { total_time = new_total; }
+	void Elapsed(unsigned int current_time);
+	void Play(void) {
+		start_time = 0;
+		status = PLAYING;
+	}
+
+	virtual void Start(void) {};
+	virtual void Exec(int count) = 0;
+	virtual void Finish(void) {};
+	void Abort(void);
+	bool IsEnd(void);
+};
+
+struct AnmMove : public AnmTime {
+	Rect from, to;
+	AnmMove(Event::Container& container, PicBase* _pic, const Rect& to, int total_time);
+	void Exec(int count);
+};
+#define ALPHA_MAX 255
+struct AnmAlpha : public AnmTime {
+	int from, to;
+	unsigned char alpha; Rect alpha_r;
+	AnmAlpha(Event::Container& container, PicBase* _pic,  int alpha_from, int alpha_to, int total_time);
+	AnmAlpha(Event::Container& container, std::vector<PicBase*> _pic,  int alpha_from, int alpha_to, int total_time);
+	void Start(void);
+	void Exec(int count);
+	void Finish(void);
+};
+struct AnmAlphaMove : public AnmTime {
+	struct Ptn {
+		Rect pos;
+		Rect surface_pos;
+		unsigned char alpha;
+		unsigned int next_tick;
+		Ptn(const Rect& _r, const Rect& _surface_r, unsigned char _a, unsigned int _n) :
+			pos(_r), surface_pos(_surface_r), alpha(_a), next_tick(_n) {}
+	};
+	std::vector<Ptn> ptns;
+	int cur_count;
+	AnmAlphaMove(Event::Container& container, PicBase* _pic);
+	void SetPtn(void);
+	void Exec(int count);
+	void Finish(void);
+};
+struct AnmPtnSolid : public AnmTime {
+	AnmPtnSolid(Event::Container& container, PicBase* _pic, const unsigned char* ptn, const Rect& alpha_r, int total_time);
+	~AnmPtnSolid() { delete[] alpha; }
+	const unsigned char* ptn;
+	int ptn_len;
+	unsigned char* alpha;
+	Rect alpha_r;
+	
+	void Start(void);
+	void Exec(int count);
+	void Finish(void);
+};
+struct AnmPtnAlpha : public AnmTime {
+	AnmPtnAlpha(Event::Container& container, PicBase* _pic, const unsigned char* ptn, const Rect& alpha_r, int alpha_bandwidth, int total_time);
+	~AnmPtnAlpha() { delete[] alpha; }
+	const unsigned char* ptn;
+	int ptn_len;
+	int band;
+	unsigned char* alpha;
+	Rect alpha_r;
+	void Start(void);
+	void Exec(int count);
+	void Finish(void);
+};
+
+// } /* end of namespace Widget */
+
+#undef Text
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/xlovesys.cc
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2004-2006  Kazunori "jagarl" Ueno
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// #define ROOTPATH "/mnt/KEY/CLANNAD"
+// #define ROOTPATH "/home/uenok/pb"
+// #define FONT "msgothic.ttc"
+	/* kochi-mincho-subst.ttf あるいは -*-*-*-r-*--24-*-*-*-*-*-jisx0208.1983-* など */
+	/* TrueType Font は /usr/X11R6/lib/X11/fonts/TrueType/ などに存在する必要がある */
+
+#include<stdio.h>
+#include<stdlib.h>
+#include<unistd.h>
+#include<locale.h>
+
+#include<SDL.h>
+#include<vector>
+#include<getopt.h>
+
+#include"system/file.h"
+#include"system/system_config.h"
+#include"window/widget.h"
+#include"window/system.h"
+
+#include"music2/music.h"
+
+#include"scn2k/scn2k.h"
+#include"scn2k/scn2k_impl.h"
+
+const char key_lb_orig[] = {0x4b, 0x45, 0x59, 0x5c, 0x83, 0x8a, 0x83, 0x67, 0x83, 0x8b, 0x83, 0x6f, 0x83, 0x58, 0x83, 0x5e, 0x81, 0x5b, 0x83, 0x59, 0x81, 0x49, 0};
+
+const char key_lb_new[] = "KEY\\LittleBusters";
+
+
+extern "C" int main(int argc, char* argv[]); /* SDL.h で定義されるので必要ないはずなんだけど…… */
+
+int main(int argc, char *argv[]) {
+	AyuSysConfig config;
+	int opt = 0, end = 0, screenmode = 0;
+	char rootPath[1024]  = "/mnt/KEY/CLANNAD";
+	char font[1024]      = "msgothic.ttc";
+	Uint32 videoOptions  = SDL_HWSURFACE;
+
+	while(1) {
+		opt = getopt(argc, argv, "fdt:c:r:vh?");
+		if(opt == -1) {break;}
+
+		switch(opt) {
+			case 'f':
+				videoOptions |= SDL_FULLSCREEN;
+				break;
+			case 'd':
+				videoOptions |= SDL_DOUBLEBUF;
+				break;
+			case 't':
+				strncpy(font, optarg, 1023);
+				break;
+			case 'r':
+				strncpy(rootPath, optarg, 1023);
+				break;
+			case 'v':
+				// FIXME: "VERSION" undeclared?
+				// printf("xclannad %s\n", VERSION);
+				printf("xclannad 0.05e\n");
+				end = 1;
+				break;
+			case 'h':
+			case '?':
+				printf("\nUsage: %s [OPTIONS]\n\n", argv[0]);
+				printf("  -f    : full screen mode\n");
+				printf("  -d    : double buffer mode\n");
+				printf("  -t    : set font (typeface)\n");
+				printf("  -r    : set root path (default /mnt/KEY/CLANNAD)\n");
+				printf("  -v    : show version and exit\n");
+				printf("  -h -? : show help and exit\n\n");
+				end = 1;
+				break;
+		}
+	}
+	if(end == 1) return 0;
+
+	printf("Settings:\n");
+	printf("  Locale    : %s\n", setlocale(LC_ALL, ""));
+	printf("  Root Path : %s\n", rootPath);
+	printf("  Font      : %s\n", font);
+	printf("\n");
+	
+	file_searcher.InitRoot(rootPath);
+	config.LoadInitFile();
+	const char* regname = config.GetParaStr("#REGNAME");
+	if (strcmp(regname, key_lb_orig) == 0) { // "リトルバスターズ! -> LittleBustersに#REGNAMEを変更
+		config.SetParaStr("#REGNAME", key_lb_new);
+	}
+	SetFont(font);
+
+	MuSys mu(config);
+	mu.InitMusic();
+
+	if(SDL_Init(SDL_INIT_VIDEO)) {
+		printf("Unable to init SDL: %s\n", SDL_GetError());
+	        return 1;
+	}
+	atexit(SDL_Quit);
+
+	config.GetParam("#SCREENSIZE_MOD", 1, &screenmode);
+	if (screenmode == 1) {
+		SDL_SetVideoMode(800, 600, 0, videoOptions);
+	} else {
+		SDL_SetVideoMode(640, 480, 0, videoOptions);
+	}
+	// SDL_SetVideoMode(640, 480, 0, videoOptions);
+	// SDL_SetVideoMode(800, 600, 0, SDL_HWSURFACE /*| SDL_FULLSCREEN */);
+	{
+		System::Main main_sys;
+		PicContainer* main_panel = main_sys.root.create_node(Rect(0, 0, main_sys.root.width, main_sys.root.height), 0);
+		main_panel->show();
+		try {
+			Scn2k scn(main_sys.event, *main_panel, mu, config);
+			main_sys.Mainloop();
+		} catch(...) {
+			fprintf(stderr,"System faulted; exit now.\n");
+		}
+		delete main_panel;
+	}
+
+	mu.FinalizeMusic();
+
+	SDL_Quit();
+}
+