「xml」を含む日記 RSS

はてなキーワード: xmlとは

2008-03-20

[]gcc-xmlVisual Studio 2005を使いたい!

gcc-xmlって何?

gccの構文解析の結果(構文木)を、XMLとして出力してくれるツールです。C++の構文解析はやたらと面倒らしいので、こういうのがあるとうれしいみたいよ。

何でわざわざビルドするの?

Py++」というC++のPytyonバインディングで使われていたので、必要になりました。gcc-xml 0.6はバイナリで配布されてるんだけど、MSVC7.1までしか対応してないようで、Visual Studio 2005だと使えませんでした。うーん、困った。というわけで、最新版のソース一式を取得してビルドしてみます。

CMakeをインストールしよう

gcc-xmlビルドには、CMakeというツールが必要になります。CMakeは、オープンソースクロスプラットフォームビルドシステムなんだとか。CMakeの公式サイトから、Windows版のインストーラーをダウンロードしてインストールしよう。

実は最初は、ここでcygwinのsetup.exe経由でのインストールをしてたんですけど、これだとgcc-xmlビルドの段階でエラーが発生しちゃいました。この原因がどうしてもわかんなかったので、あきらめて公式サイトインストーラーを使うことにした次第です。

gcc-xmlソース一式を取得しよう

ソース一式はCVSから取得できます。CVSクライアントはいろんなのがあるので、好きなクライアントを使って取得しよう。ここではcygwinCVSを使って、シェルから以下の命令を実行して取得しました。40MBくらいあるみたい。

$ cvs -d :pserver:anoncvs@www.gccxml.org:/cvsroot/GCC_XML co gccxml

gcc-xmlビルドしよう その1

Visual Studio 2005 コマンドプロンプト」を起動してください。起動したら、さきほど取得したソース一式が格納されているディレクトリに移動して、以下の命令を実行します。

$ cmake .

cmake.exeにはあらかじめパスを通しておくか、パスを直接指定するのを忘れずにね。

gcc-xmlビルドしよう その2

gcc-xmlビルドはまだ終了してなかった! 一度ビルドが終了しても、第二第三のビルドが必要となって…。などと恐れおののきましたが、二段階でいいみたい。

さきほどの処理が終了すると、同じディレクトリに"gccxml.sln"というソリューションファイルが新しくできあがっているかと思います。これをVisual Studio 2005から開いて、Releaseビルドしよう。ビルドが終了したら、以下の5つの実行ファイルができあがっているはずです。

  • bin/release/gccxml.exe
  • bin/release/gccxml_cc1plus.exe
  • bin/release/gccxml_vcconfig.exe
  • bin/release/gxsysEncodeExecutable.exe
  • bin/release/gxsysProcessFwd9x.exe

gcc-xmlVisual Studio 2005を使えるように設定しよう

まずは環境変数の設定です。Visual Studio 2005を使っていることを、gcc-xmlに高らかに宣言しておこう。

$ set GCCXML_COMPILER=msvc8

つぎに、gccからVisual Studio 2005のインクルードファイルを使えるよう、パッチをあてます。ありがたいことに、"GCC_XML/VcInstall"ディレクトリ以下にVisual Studioバージョンによってパッチが用意されています。そのディレクトリと、パッチを当てたファイルを出力するディレクトリ("gccxml.exe"が置いてあるディレクトリ)を指定して、"gccxml_vcconfig.exe"を実行してください。

$ bin/release/gccxml_vcconfig GCC_XML/VcInstall/ bin/release

gcc-xmlを使ってみよう

あとはbin/releaseにパスを通せば、gcc-xmlが使えるようになったはずです。bin/release以下をどこか適当ディレクトリコピーして、そこにパスを通してもオッケイです。やったね! というわけで、さっそく試してみましょう。

$ gccxml eample1.cpp -fxml=example1.xml

ここでは、解析するC++ソースファイルとしてeample1.cpp入力し、eample1.xmlを出力しています。ちゃんと出力できたかな? できたー! やったー!

以上で終わりです。

2008-03-15

[][]PythonからSWIG経由でVisual Studio 2005を使って困ったこと

以上のような組み合わせで出くわした困ったことと、その解決策をメモしておきます。

setup.py を実行するとエラーが表示された!

Python was built with Visual Studio 2003;

extensions must be built with a compiler than can generate compatible binaries.

Visual Studio 2003 was not found on this system. If you have Cygwin installed,

you can try compiling with MingW32, by passing "-c mingw32" to setup.py.

setup.pyに.iファイルとか.cppファイルを記述して実行すると、こんな感じのエラーメッセージが表示されました。うーん、困った!

http://labs.cybozu.co.jp/blog/mitsunari/2007/08/vc2005boostpython.html

上記のページを参考にして、"%Pythonインストールしたフォルダ%/Lib/distutils/msvcompiler.py"を以下のように修正してみたら解決できました。ありがとうありがとう

--- msvccompiler.py    2007-04-04 17:17:12.000000000 +0900
+++ 
@@ -126,7 +126,7 @@
         self.set_macro("FrameworkDir", net, "installroot")
         try:
             if version > 7.0:
-                self.set_macro("FrameworkSDKDir", net, "sdkinstallrootv1.1")
+                self.set_macro("FrameworkSDKDir", net, "sdkinstallrootv2.0")
             else:
                 self.set_macro("FrameworkSDKDir", net, "sdkinstallroot")
         except KeyError, exc: #
@@ -252,7 +252,10 @@

     def initialize(self):
         self.__paths = []
-        if os.environ.has_key("DISTUTILS_USE_SDK") and os.environ.has_key("MSSdk") and self.find_exe("cl.exe"):
+        if self.__version >= 7.1 or (
+            os.environ.has_key("DISTUTILS_USE_SDK") and
+            os.environ.has_key("MSSdk") and
+            self.find_exe("cl.exe")):
             # Assume that the SDK set up everything alright; don't try to be
             # smarter
             self.cc = "cl.exe"
@@ -288,10 +291,16 @@

         self.preprocess_options = None
         if self.__arch == "Intel":
-            self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GX' ,
-                                     '/DNDEBUG']
-            self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GX',
-                                          '/Z7', '/D_DEBUG']
+            if self.__version >= 7.1:
+                self.compile_options = [
+                    '/nologo', '/Ox', '/MD',  '/W3', '/EHsc', '/DNDEBUG']
+                self.compile_options_debug = [
+                    '/nologo', '/Od', '/MDd', '/W3', '/EHsc', '/Z7', '/D_DEBUG']
+            else:
+                self.compile_options = [
+                    '/nologo', '/Ox', '/MD',  '/W3', '/GX',  '/DNDEBUG']
+                self.compile_options_debug = [
+                    '/nologo', '/Od', '/MDd', '/W3', '/GX', '/Z7', '/D_DEBUG']
         else:
             # Win64

cl.exeが見つからないと言われた!

setup.pyを実行するとcl.exeが見つからないみたいなエラーが表示されました。これは、アレだ。「パス通せ!」ということですね。bashを起動するときのバッチファイル(たぶん"cygwin.bat"とか)で、以下のような行を入れてやれば解決しました。

call "%VS80COMNTOOLS%vsvars32.bat"

setup.pyを実行したときに"basetsd.h"が開けないと言われた!

d:\python25\include\pyconfig.h(189) : fatal error C1083: include ファイルを開けません。'basetsd.h': No such file or directory

error: command 'cl.exe' failed with exit status 2

setup.pyを実行すると、上のようなエラーが表示されました。

http://d.hatena.ne.jp/ousttrue/20070531/1180556273

上記のサイトを見るとインクルードパスが通っていない場所に"basetsd.h"があるのが原因なので、"cygwin.bat"にインクルードパスの設定をしておきました。

call "%VS80COMNTOOLS%vsvars32.bat"
set INCLUDE=C:\Program Files\Microsoft Platform SDK\Include;%INCLUDE%

setup.pyを実行したときのリンク時にエラーが発生した!

link: extra operand `/INCREMENTAL:NO'

詳しくは `link --help' を実行して下さい.

error: command 'link.exe' failed with exit status 1

これは、cygwinのほうのlink.exeが実行されてるのが原因でした。スマートな解決策ではありませんが、cygwinのほうのlink.exeをリネームして解決。パスの設定順序とかでどうにかできるといいんだけど、どうすればいいんかな。

MSVCR80.dllが見つからないと言われた!

MSVCR80.dllが見つからなかったため、このアプリケーションを開始できませんでした。アプリケーションインストールし直すとこの問題は解決される場合があります。

SWIGが生成した.pyファイルをimportしたら、こんな感じのエラーダイアログが表示されたよ。うーん、困った!

http://d.hatena.ne.jp/moriyoshi/20070525

上記のページを参考にして、"%Pythonインストールしたフォルダ%/python.exe.manifest"として以下のようなファイルを新しく作ったら、解決できました。ありがとうありがとう

あとこれ、bashから実行したらエラーダイアログが表示されず、importするモジュールが見つからないみたいなエラーメッセージが出力されるだけだったよ。

<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity type='win32' name='Microsoft.VC80.CRT' version='8.0.50608.0' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' />
    </dependentAssembly>
  </dependency>
</assembly>

2008-01-31

web混沌を愛せないかな

キーワード検索のやり方も知らず、リンクアンカーで彷徨った末に胡散臭い情報商材に引っかかる初心者

・数万通のメールを送信して金持ちになるスパマー

・自サイトのスペースをドット単位で販売して100万ドルを手に入れた男。

スネオの髪型を洒落でニセ立体化してみたらニュースに載るほどの騒ぎに。

アダルトサイト迷宮のようなリンクアンカー

mixi犯罪自慢して人生オワタする若い人。

・その人を個人情報保護なんて糞喰らえな勢いで「祭る」匿名の人たち。

・例え裁判所から命令されてもお金を出す気は全くないどっかの管理人さん。

ウイルスを作ってもそれを罰する規則が存在しないので別件逮捕

リミックスされまくって、もはや元ネタの追跡すら難しいMAD動画

・自サイトローカルルールを絶対化するサイト管理人

無断リンク禁止サイト押しかけて正義を気取るモヒカンさん。

・新しいwebサービスには恐ろしいスピードで飛びつくが、意外と普通の人がよく使うページを知らなかったりするGeekたち。

これらの全てを許容する、今のこのWorld Wide Webが大好きだ。

web混沌を常にはらんでいる。

多様性は混沌も生むが、進化も生む。

多様性の結果として混沌と大量のゴミが生まれたとしても、その中から進化が1個でも生まれればそれは進化としては正しい。

----

すべてを整えようとするのは理系技術屋の性なのかな。

技術屋ができるのはあくまで情報の生成から整理までであって、管理はできない気がする。

Googleがやっているのは整理。ティム・バーナーズ・リーがやろうとしたのは管理に近い。(ただし強制力はない。web情報機械意味を持たせて整理しようとしたXHTML(XML)規格は、BlogをはじめとしたCMSのおかげである程度普及したが、Webを席巻する程には至らなかった)

※しかも、Geekから見ると整理されているように見えるものでも、同じものが初心者からは複雑怪奇(というか超難解)に見えたりもするので、事態がますますややこしくなっているように見える。

2008-01-25

XMLの閉タグは名前を省略出来るべき

例えば </body> は

</>

みたいに。

2007-12-17

XMLという存在への懐疑はWWWの今後への懐疑である。

XMLという存在への懐疑は、WWWの今後への懐疑である。

そして、誰もこれを懐疑することを否定も肯定もできない。

そして、「WWWは正しいか?」という問いかけをすることも否定も肯定もできない。

が、インフラとなった技術存在意義を懐疑されない。

OSもそう。コンパイラもそう。

人工言語プログラミング言語)の自然言語日本語英語等)への影響がどんどん大きくなっていく。

そろそろ、その意味を考えなければならない。

2007-12-02

ここで勝手言語論争ごっこ

一番使い勝手の良いプログラミング言語Perlどぅわ!

C/C++/C#なんて気軽に文字列処理できないし、

Windowsでしか使えないVisualほにゃらら

メモリの確保、解放なんてしたくない

だいたい、セグメンテーションフォルトを起こすような言語は嫌い

DirectXOpenGLとお友達になりたくない

Haskelわけわかんないし

Java重苦しいし、いちいちclass Hogehoge { public static void main() { ... } }書くのがめんどくさいし、API多すぎ

オブジェクト指向したくなるような複雑なプログラムは最初から考えない(作れない)

GUI作りたくなるような言語はめんどくさい

言語が提供するGUIのツールはOSとは別に独自のレイヤー世界感を持っててとっつきにくい

マルチスレッド、排他処理を扱うようなプログラム脳味噌がついて行かないので書かない

CGIにしか使えないようなPHP

Ruby、、、そもそもLL言語で大規模でオブジェクト指向プログラム書きたくない。小規模ならオブジェクト指向要らない。

俺のマシンで実行できないAda/Basic/Fortran/Pascal その他いろいろ

VHDLVerilogFPGAやゲートアレイなんて持ってない、持ちたくない(苦手だもん)

データベースなんかいじってたまる

HTMLXML日本語タグが入り乱れるので、そのつど日本語入力の切替えが死ぬほど嫌になった。

だから、HTMLXMLは全部手入力なんて真似は絶対してやらねえ。

Flex(Action Script)はコンパイラJavaで実装されてて重すぎる。(シェルを使えばまし)

JavaScriptブラウザごとの挙動の違いを吸収しきれる自身が無いので使わない。

1プログラムにつき、(コメント含めて)250行以上書きたくない

複雑なプログラムを最後まで書ける連中が羨ましい。

排他制御にとちって、デスロックしてしまえ。

(本文には触ったこともない言語を思い込みで罵倒しているなど、嘘、おおげさ、紛らわしいが多数混入しています。それが全部わかった貴方プログラミング言語マスターです。)

2007-11-22

むしろおれが炎ジョイから発想したことは

今後、はてブ炎ジョイのような形で

サイト管理者が管理できない別レイヤーコンテンツが記述される

レイヤーコンテンツ

とでもいうようなものが流行っていってしまうのかもしれないなぁということ。

もちろん、サイト管理者が管理できないのも問題だけど、それ以外にも

どうやってすべてのレイヤー情報を1つにまとめるか、というのも問題になってくるわけで、

検索エンジンに噛ませたい場合、ある規格にそって記述してもらうとか(なんらかのXMLRSSのように)、

なんらかの統一規格があったほうがよいのかもなぁとか、そんなことを思うわけです。

2007-11-08

60行テンプレートエンジンがパワーアップしてレイアウト機能に対応

前の60行テンプレートエンジンを改良して、レイアウトテンプレート機能を追加してみた(それでも全部で90行)。

レイアウトテンプレート機能とは、例えば個別のテンプレートが<table>...</table>を出力して、それをレイアウトテンプレートが<html><body>...</body></html>で囲って出力するとかそんなの。

詳しくは終わりの方のサンプルをみてくれ。

これは Ruby on Rails(とその仲間たち)にある便利機能のひとつ。

ついでにいうとSmartyにはない機能のひとつ。

今まで知らなかった人はぜひ試してくれ。チョー便利だから。

前回はたくさんのブックマークありがと。

コメントで「男前テンプレート」と名前がついてたので、勝手採用

名前がキモいっていわれるよ?でもそんなのカンケイネー

あと、これ以上の機能追加はしないので、各自勝手に改造して使ってくれ(そのためにコメントをつけてるから)。何でも人任せにするな。

コード

<?php
/*
 *  OtokomaeTemplate.php -- レイアウトテンプレートに対応した90行のテンプレートエンジン
 *
 *  - レイアウトテンプレート中で echo $_content; とすると中身が表示される。
 *  - テンプレート中で設定した変数レイアウトテンプレートで使うことが可能。
 *  - レイアウトテンプレート名をテンプレート側で指定することも可能。
 *  - 使い方:
 *      require_once('OtokomaeTemplate.php');
 *      $TEMPLATE_DIR    = 'templates';  // 省略可、パーミッションに注意
 *      $LAYOUT_TEMPLATE = 'layout.php'; // 省略可
 *      $context = array('title'=>'Example',
 *                       'list'=>array(10,'<A&amp;B>',NULL));
 *      include_template('template.php', $context);
 *  - 要 PHP 5.1 or later
 *  - ライセンス: public domain (自由に改造してね)
 */

/*
 *  設定用のグローバル変数
 */
$TEMPLATE_DIR    = NULL;   /* テンプレートを探すディレクトリ */
$LAYOUT_TEMPLATE = NULL;   /* レイアウトテンプレートファイル名 */

/*
 *  テンプレートを読み込んで実行する。
 *  $_context は変数名をキー、値を要素とする連想配列。
 *  $_layout はレイアウトテンプレートファイル名。
 *  - NULL または省略した場合は $LAYOUT_TEMPLATE を使う。
 *  - FALSE ならレイアウトテンプレートを使わない。
 *  - $_context['_layout'] = '...'; とすればテンプレート側でも指定可能。
 */
function include_template($_filename, $_context, $_layout=NULL) {
    global $LAYOUT_TEMPLATE;
    $_content = render_template($_filename, $_context);
    if (@$_context['_layout'] !== NULL)   // テンプレート側で指定された場合は
        $_layout = $_context['_layout'];  // それを使う。
    elseif ($_layout === NULL)            // 引数で指定されなかった場合は
        $_layout = $LAYOUT_TEMPLATE;      // デフォルトファイル名を使う。
    if ($_layout) {
        $_context['_content'] = $_content;  // レイアウトテンプレート中で使う変数
        $_content = render_template($_layout, $_context);
    }
    echo $_content;   // or return $_content;
}

/*
 *  テンプレートを読み込んで実行し、その結果を文字列で返す。
 *  include_template() の実体。
 */
function render_template($_filename, &amp;$_context) {
    $_cachename = convert_template($_filename);
    extract($_context);     // 連想配列ローカル変数に展開
    ob_start();
    include($_cachename);   // テンプレートを読み込んで実行
    return ob_get_clean();
}

/*
 *  テンプレートファイルを読み込み、convert_string() で置換してから
 *  キャッシュファイルに書き込む。読み込み時のロックは省略。
 *  (file_get_contents() もファイルロックできるようにしてほしいなあ。)
 */
function convert_template($filename) {
    global $TEMPLATE_DIR;
    if (! file_exists($filename) &amp;&amp; $TEMPLATE_DIR)
        $filename = "$TEMPLATE_DIR/$filename";
    $cachename = $filename . '.cache';
    if (! file_exists($cachename) || filemtime($cachename) < filemtime($filename)) {
        $s = file_get_contents($filename);
        $s = convert_string($s);
        file_put_contents($cachename, $s, LOCK_EX); // LOCK_EX サポートは 5.1.0 から
    }
    return $cachename;
}

/*
 *  テンプレートの中身を置換する。
 *  - '#{...}' を 'echo ...;' に置換
 *  - '%{...}' を 'echo htmlspecialchars(...);' に置換
 *  - ついでにXML宣言も置換
 */
function convert_string($s) {
    $s = preg_replace('/^<\?xml/', '<<?php ?>?xml', $s);
    $s = preg_replace('/#\{(.*?)\}/', '<?php echo $1; ?>', $s);
    $s = preg_replace('/%\{(.*?)\}/', '<?php echo htmlspecialchars($1); ?>', $s);
    return $s;
}
?>

サンプルPHPコード:

<?php
require_once('OtokomaeTemplate.php');
$TEMPLATE_DIR    = 'templates';
$LAYOUT_TEMPLATE = 'layout.php';
$context = array('list'=>array(10,'<A&amp;B>',NULL));
include_template('template.php', $context);
?>

レイアウトテンプレート(layout.php):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <body>
    <h1>%{$title}</h1>
    <div id="maincontent">
<!-- テンプレートの内容 -->
<?php echo $_content; ?>
<!-- /テンプレートの内容 -->
    </div>
  </body>
</html>

テンプレート(template.php):

<?php // レイアウトテンプレート名をテンプレート中で指定する場合 ?>
<?php //$_context['_layout'] = 'mylayout.php'; ?>
<?php // レイアウトで使用する変数テンプレート中で指定する場合 ?>
<?php $_context['title'] = 'レイアウトのサンプル'; ?>
<table>
<?php foreach ($list as $i=>$item): ?>
  <tr bgcolor="#{$i % 2 ? '#FFCCCC' : '#CCCCFF'}">
    <td&gt;#{$i}</td&gt;
    <td&gt;%{$item}</td&gt;
  </tr>
<?php endforeach ?>
</table>

出力例:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <body>
    <h1>レイアウトのサンプル</h1>
    <div id="maincontent">
<!-- テンプレートの内容 -->
<table>
  <tr bgcolor="#CCCCFF">
    <td&gt;0</td&gt;
    <td&gt;10</td&gt;
  </tr>
  <tr bgcolor="#FFCCCC">
    <td&gt;1</td&gt;
    <td&gt;&lt;A&amp;B&gt;</td&gt;
  </tr>
  <tr bgcolor="#CCCCFF">
    <td&gt;2</td&gt;
    <td&gt;</td&gt;
  </tr>
</table>
<!-- /テンプレートの内容 -->
    </div>
  </body>
</html>

いくつか補足:

2007-11-02

Visual C# Express Editionのダウンロード時の質問項目がひどすぎる

バカすぎる。俺は学生なんだが、

こんな質問に答えられるわけがないだろ。「お客様の主な役割について最も適したものをお聞かせください。」という質問に「学生」って答え作ってるんだから、学生にしたら上の質問を無効にしろよ。「システムを導入するにあたっての、あなたの立場を教えてください。」は確実に答えが選択肢にないんですが。学生は不可なのかと思って対象ユーザーをしらべたけど、ちゃんと学生も対象に入っている。

Visual C# 2005 Express Edition は、学生や、プロフェッショナルではない開発者を対象ユーザーと想定して作成されています。Visual C# 2005 Express Edition には、Visual Studio 2005 Professional Edition と同じ機能が多数用意されていますが、アプリケーション開発を簡単に始めることができるようにシンプル化されてもいます。

http://www.microsoft.com/japan/msdn/vstudio/express/faq/default.aspx#vcsharp学生向けを意識してるなら、質問もそれ向けに作ってくれよ。あれか製品自体は学生向けだけど、無料ダウンロード学生禁止なのか?もうどうでもいいや。

あ、あと

どのプログラミング言語の話題に興味がありますか。
HTMLXMLが入ってるのもアレHTMLプログラミング言語って言うのは意外とマイクロソフトが広めてるのかもしれない。

http://anond.hatelabo.jp/20071102133439

この日記を上の検索機能から、興味がある単語(例.XMLオートマトン)で検索をかけてます。

http://anond.hatelabo.jp/20070907154801

このスレッド立てた増田です。

このサイトの型システムの解説が分かりやすかったです。

http://www.chimaira.org/docs/Problems200504.htm

XML的型システム(一種類である必要は全然ありません)が確立して、それがプログラミング言語の型システムとしっかりとした関係を結んでいる状況を期待しているわけです。

ここについてしっかり考えてみたいと思います。

プログラミング言語の型システムとしっかりした関係を結ぶにはどうすればいいか考えてみようと思います。

まず、プログラミング言語を絞って考えます。

日本Webプログラミングで主流な言語Rubyの型システムXML的型システムとの対応についてみんなで考えてみましょう。

ここでのリアクションがよかったら、この話題専用の日記を立ち上げましょう。

2007-10-31

生け垣オートマトン

ネーミングセンスが好きだ。

英語だと、hedge automataだ。

RELAX NGというXMLスキーマ数学的な基礎らしい。

通常のオートマトンが文字列を扱うのに対して、

生け垣オートマトンは生け垣を扱う。

ここで、生け垣は順序木の順序列のことだ。

すごい理論としておもしろいので勉強中だ。

これを勉強した後と前では、RSSSOAP等のXMLの応用に対する見方も変わるかもしれない。

みんなも、下記URIをぜひ読んでみよう。

参考URI

2007-10-30

[]55行で作るC#テンプレートエンジン

http://anond.hatelabo.jp/20071030034313二番煎じ

あまりのアホさに、作ってて気が狂いかけた

方針


using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Microsoft.CSharp;

delegate void ConvertTemplateDelegate(TextWriter tw, Dictionary<object, object> args);
static class TemplateGenerator {
    public static ConvertTemplateDelegate Generate(string code) {
        CompilerParameters param = new CompilerParameters();
        param.GenerateInMemory = true;
        param.ReferencedAssemblies.Add("System.Web.dll");
        CompilerResults rs = new CSharpCodeProvider().CompileAssemblyFromSource(param, ParseTemplate(code));
        if (0 < rs.Errors.Count) {
            StringWriter sw = new StringWriter();
            sw.WriteLine("Compile Error...");
            foreach (CompilerError err in rs.Errors)
                sw.WriteLine(err.ToString());
            throw new Exception(sw.ToString());
        }
        return (ConvertTemplateDelegate) Delegate.CreateDelegate(typeof(ConvertTemplateDelegate), rs.CompiledAssembly.GetType("Template", true).GetMethod("Convert"));
    }
    private static string ParseTemplate(string code) {
        using (StringWriter sw = new StringWriter()) {
            sw.WriteLine("using System; using System.Collections.Generic; using System.IO; using System.Web;");
            sw.WriteLine("public static class Template {");
            sw.WriteLine("public static void Convert(TextWriter tw, Dictionary<object, object> args) {");
            int index = 0;
            while (0 <= index &amp;&amp; index < code.Length) {
                int i = code.IndexOf("<%", index);
                sw.WriteLine("tw.Write(\"{0}\");", EscapeString(i < 0 ? code.Substring(index) : code.Substring(index, i - index)));
                if (0 <= i) {
                    i += 2;
                    int i2 = code.IndexOf("%>", i);
                    if (0 <= i2) {
                        string cc = code.Substring(i, i2 - i);
                        if (cc.StartsWith("="))
                            sw.WriteLine("tw.Write(HttpUtility.HtmlEncode(\"\"+({0})));", cc.Substring(1));
                        else
                            sw.WriteLine(cc);
                        i = i2 + 2;
                    }
                }
                index = i;
            }
            sw.WriteLine("}}");
            return sw.ToString();
        }
    }
    private static string EscapeString(string code) {
        return code.Replace("\\", "\\e").Replace("\"", "\\\"").Replace("\t", "\\t").Replace("\n", "\\n").Replace("\r", "\\r").Replace("\\e", "\\\\");
    }
}

サンプル C# コード。ためしにテンプレートから Xml 生成して、標準出力してみる。

class Program {
    static void Main(string[] args) {
        ConvertTemplateDelegate func = TemplateGenerator.Generate(TemplateEngine.Resource1.template);
        using (StringWriter sw = new StringWriter()) {
            Dictionary<object, object> arg = new Dictionary<object, object>();
            arg["title"] = "template sample";
            arg["data"] = new string[] { "foo", "fooo", "<strong>foooooooooo!</strong>" };
            func(sw, arg);
            Console.WriteLine(sw);
        }
    }
}

サンプルテンプレート

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title><%= args["title"] %></title>
  </head>
  <body>
    <h1><%= args["title"] %></h1>
    <table>
<% string[] data = (string[]) args["data"]; %>
<% for(int i = 0; i < data.Length; i++) { %>
      <tr bgcolor="<%= i % 2 == 0 ? "#FFCCCC" : "#CCCCFF" %>">
        <td><%= i %></td>
        <td><%= data[i] %></td>
      </tr>
<% } %>
    </table>
  </body>
</html>

出力例

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>template sample</title>
  </head>
  <body>
    <h1>template sample</h1>
    <table>


      <tr bgcolor="#FFCCCC">
        <td>0</td>
        <td>foo</td>
      </tr>

      <tr bgcolor="#CCCCFF">
        <td>1</td>
        <td>fooo</td>
      </tr>

      <tr bgcolor="#FFCCCC">
        <td>2</td>
        <td>&lt;strong&gt;foooooooooo!&lt;/strong&gt;</td>
      </tr>

    </table>
  </body>
</html>

CodeDom 使って動的コンパイル……って、このコードのままだとセキュリティ的に大問題な気がするな。

素直に ASP.NET 使ったほうが楽だと直感した。

あと EscapeString すっごく自信ない。たぶん修正が必要だと思うw

40行で作るPerlテンプレートエンジン

60行で作るPHP用テンプレートエンジン

やってしまった・・・。

方針:

  • PHPのように<?php・・・?>が無いのでそのまま表示と(foreach|if|unless)に対応。
  • [% $c{title} %]で普通に表示(TTっぽい?)
  • [# $c{title} #]でHTMLエスケープ表示

package SixtyLinesTemplate;

use strict;
use warnings;
our $VERSION = '0.01';

sub convert {
    return unless defined(my $str = shift);
    $str =~ s{&amp;}{&amp;}gso;
    $str =~ s{<}{&lt;}gso;
    $str =~ s{>}{&gt;}gso;
    $str =~ s{\"}{&quot;}gso;
    $str;
}

sub include_template {
    my $tmpl = shift;
    my %c = %{+shift};
    eval convert_template($tmpl);
    die $@ if $@;
}

sub convert_template {
    my $tmpl = shift;
    my $cache = $tmpl.'.cache';
    return scalar do { open my ($FH) , $cache; local $/; <$FH> }
        if ( -f $cache &amp;&amp; (stat($tmpl))[9] <= (stat($cache))[9] );
    my $out = do { open my ($FH) , $tmpl; local $/; <$FH> };
    $out =~ tr/()/\x28\x29/;
    $out =~ s/\[%\s*(foreach|if|unless|end)\s*(.+?)\s*{?\s*%\]/");".(lc($1) eq 'end' ? '} print q(' : "$1 $2 { print q(")/ige;
    $out =~ s/\[%(.+?)%\]/);print $1; print q(/g;
    $out =~ s/\[#(.+?)#\]/);print SixtyLinesTemplate::convert($1); print q(/g;
    $out = 'print q('.$out.');';
    open my ($FH) , '>' , $cache;
    print $FH $out;
    $out;
}

1;

サンプルコード


use SixtyLinesTemplate;

my $context = {
    'title' => 'Example',
    'list'  => [10,'<A&amp;B>']
};

SixtyLinesTemplate::include_template('template.tmpl',$context);

サンプルテンプレート


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head&gt;
    <title>[# $c{title} #]</title>
  </head&gt;
  <body>
    <h1>[# $c{title} #]</h1>
    <table>
[% foreach my $i (0..@{$c{list}}-1) %]
      <tr bgcolor="[% $i % 2 ? '#FFCCCC' : '#CCCCFF' %]">
        <td&gt;[% $i %]</td&gt;
        <td&gt;[# $c{list}[$i] #]</td&gt;
      </tr>
[% end %]
    </table>
  </body>
</html>

出力例:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>Example</title>
  </head>
  <body>
    <h1>Example</h1>
    <table>

      <tr bgcolor="#CCCCFF">
        <td>0</td>
        <td>10</td>
      </tr>

      <tr bgcolor="#FFCCCC">
        <td>1</td>
        <td>&lt;A&amp;amp;B&gt;</td>
      </tr>

    </table>
  </body>
</html>

foreachんところが汚く見えるかもしれませんが、あれは添え字を取ろうとするとああなるんでご勘弁を。

普通ループするだけならforeach my $item (@$c{title}) でいけますゆえ。

あと存在しない変数とか使うと死んだり警告でたりするのでevalの前にno strictとno warningsをやった方がいいかもねぇ。

って何まじめに検証してんだ俺・・・orz

追記:

SixtyじゃなくてFortyだね。恥ずかし!

追追記:

danさんに添削頂いたYO!

でも&amp;の奴はちゃんと書いてるんだけども投稿すると勝手エスケープされてしまってるんだよね。何でだろ?

ちなみにこのconvertの処理はCGI::Utilから拝借しました。

60行で作るPHPテンプレートエンジン

唐突に、PHP用のテンプレートエンジンを作ってみる。

方針:

  • ふつうのPHPファイルテンプレートとして使う。
  • <?php echo $var; ?> は面倒なので #{$var} と書けるようにする。
  • <?php echo htmlspecialchars($var); ?> はもっと面倒なので %{$var} と書けるようにする。
  • ついでにXML宣言も <<?php ?>?xml ... に自動置換する。

【追記】レイアウト機能を追加してみた

コード

<?php
/*
 *  SixtyLinesTemplate.php - 60行しかないけどSmartyより速いテンプレートエンジン
 *
 *  使い方:
 *     require_once('SixtyLinesTemplate.php');
 *     $TEMPLATE_DIR = 'templates'; // 省略可、パーミッションに注意
 *     $context = array('title'=>'Example',
 *                      'list'=>array(10,'<A&amp;B>',NULL));
 *     include_template('template.php', $context);
 *
 *  ライセンス: public domain (自由に改造してね)
 */

/*
 *  テンプレートを探すディレクトリ。
 */
$TEMPLATE_DIR = NULL;

/*
 *  テンプレートを読み込んで実行する。
 *  $_context は変数名をキー、値を要素とする連想配列。
 */
function include_template($_filename, $_context) {
    $_cachename = convert_template($_filename);
    extract($_context);
    include($_cachename);
}

/*
 *  filename を読み込み、convert_string() で置換してから
 *  filename.cache に書き込む。読み書きのロックは省略。
 *  (file_{get,put}_contents() はファイルロックできるようにすべきだ。)
 */
function convert_template($filename) {
    global $TEMPLATE_DIR;
    if (! file_exists($filename) &amp;&amp; $TEMPLATE_DIR)
        $filename = "$TEMPLATE_DIR/$filename";
    $cachename = $filename . '.cache';
    if (! file_exists($cachename) || filemtime($cachename) < filemtime($filename)) {
        $s = file_get_contents($filename);
        $s = convert_string($s);
        file_put_contents($cachename, $s);
    }
    return $cachename;
}

/*
 *  テンプレートの中身を置換する。
 *  - '#{...}' を 'echo ...;' に置換
 *  - '%{...}' を 'echo htmlspecialchars(...);' に置換
 *  - ついでにXML宣言も置換
 */
function convert_string($s) {
    $s = preg_replace('/^<\?xml/', '<<?php ?>?xml', $s);
    $s = preg_replace('/#\{(.*?)\}/', '<?php echo $1; ?>', $s);
    $s = preg_replace('/%\{(.*?)\}/', '<?php echo htmlspecialchars($1); ?>', $s);
    return $s;
}
?>

サンプルPHPコード

<?php
require_once('SixtyLinesTemplate.php');
$TEMPLATE_DIR = 'templates'; // optional
$context = array('title'=>'Example', 'list'=>array(10,'<A&amp;B>',NULL));
include_template('template.php', $context);
?>

サンプルテンプレート

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>%{$title}</title>
  </head>
  <body>
    <h1>%{$title}</h1>
    <table>
<?php foreach ($list as $i=>$item): ?>
      <tr bgcolor="#{$i % 2 ? '#FFCCCC' : '#CCCCFF'}">
        <td>#{$i}</td>
        <td>%{$item}</td>
      </tr>
<?php endforeach ?>
    </table>
  </body>
</html>

出力例:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>Example</title>
  </head>
  <body>
    <h1>Example</h1>
    <table>
      <tr bgcolor="#CCCCFF">
        <td>0</td>
        <td>10</td>
      </tr>
      <tr bgcolor="#FFCCCC">
        <td>1</td>
        <td>&lt;A&amp;B&gt;</td>
      </tr>
      <tr bgcolor="#CCCCFF">
        <td>2</td>
        <td></td>
      </tr>
    </table>
  </body>
</html>

2007-09-25

がんばるあなたを応援したい

上二つはガジェット自体の構造について。要はXMLを書けばよいらしい。

で3つ目が本題で、内容javascriptRSSJSONデータを取得して表示する方法。表示はこれを参考にすればよいと思う。後は、読んだ後、リストからはずす処理をどういったUIでやるかだよね。Javaやったんならオブジェクトの扱いは大体わかると思うから、後はDOMを理解すればOKだと思う。

がんばれ。

2007-09-24

スーツ族とかSIerとか言う人に対する愚痴

なんかまとまってないけど、書いたので乗せる。ほとんど愚痴だよ。

このへんからぼろぼろ出てきてるけど、まぁおおむね理解できる。

http://d.hatena.ne.jp/higayasuo/20070923

http://d.hatena.ne.jp/habuakihiro/20070922

http://d.hatena.ne.jp/jYoshiori/20070826/1188150596

 けどなんなだかなぁという気が最近している。

 スーツ族がつまらない連中代名詞であるのは良いとして、「スーツ族の煽りの結果、せっかくの良いものが台無しだぁ??」みたいな既定路線の論調はなんなんだろうという気になる。

 RoRでもStrutsでもなんでもいいんだけど「オープンソースの成果を世に普及させたい」とか、「俺の仕事場で楽しく使いたい」というのならば、道具としては工業製品としての品質を持っていないと駄目なんだけどって言いたい。

 で、また特有の色眼鏡で「あーまたサポートがどうのとか、枯れてないと駄目だとか言い出したよー」って言われそう。そういうファクターも大切だと言いたいけど、ここでいいたい品質って言うのは、フレームワークが持っているべき「誰が使ってもそれなりの物を作れる」っていう品質StrutsとかRoRが低い品質だって言いたい訳じゃない。素敵なフレームワークだと俺も思う。

けど、スーツ族とかSIer存在馬鹿すぎて駄目だとかそういうのはどうよと思う。

スーツ族とか頭の固いおじさん達の方がこのイット業界といえども圧倒的に多数なんだからそういう人たちでもうまく使えるようにするという進化を何度も繰り返すべきであり、その繰り返しは許容すべきモンなんじゃないだろうか。

 物理的な工業製品進化を見ても分かるように、「馬鹿でも使える」というキーワードはとても大切で、これは複雑さが人類史上maxソフトウェアといえども忘れてはいけないことの一つだと思う。「馬鹿でも使える」のを物理的な仕組み作りじゃ無理かもしれないということの解の一つとして「設定より規約」があるのかもしれないし、「いやいや、自動XML生成ツールで克服だよ」があるのかもしれない。

とにかく、そういった人たちの否定は、進化の否定、技術者としての自分の否定になるんじゃないだろうか。

あと、

スーツ族 == SIerコンサルタント

スーツ族 == ネット専業とかパッケージベンダーとかコミッタ

とかの文脈であって、たいていSIer中の人間は馬鹿にされがちだけど、SIerの中にもコミッタは当然いるし、理解が深いのも多いよって言いたい。 逆にSIerで、技術専門職である人間(業界専業のSEだとこの話の対象から外れるが・・・)の場合、千差万別のシステムを見てるので、尋常じゃない位の知識量と技術力が蓄積されている。

 そういう人たちが大規模なシステムを組むときに、普通プログラマ達がそれなり作ってそれなりの品質になるように苦心するわけ。上に挙げたようなエントリを書く人やそれにbookmark入れてコメントするような意識の高い人たちばかりだったら、理想郷になるんだろうけど。。。

2007-09-19

http://zapanet.info/blog/item/1089

キャッシュの話でないのであれば、複製を保存せず、透過的に変換する行為については著作権侵害には問えないだろう。

一時期流行った「赤ちゃん語変換」みたいなサイトならともかく、「半角」と「全角」の違いであればクライアント側のグリフでいかようにもなってしまう話である。 著作者本人がいくら「半角」での表示を期待していても、それを「全角」文字として表示してしまうコンピュータはたくさんあるのだ。

アスキーアートなんて、まともに絵として表示される環境の組み合わせは相当限定されているはずだが、絵として表示できなければ著作権侵害になってしまうのかってな話だ。

RSS は生の XML のまま表示させないといかんのかってな話だ。

だいたいにして著作権法の同一性保持権は「著作物の性質並びにその利用の目的及び態様に照らしやむを得ないと認められる改変」を認めている。

表示能力に劣る携帯端末での文書表示が目的ならこの改変は認められるのではないだろうかと思うがどうだろうか。

キャッシュの話であれば、もう fj.soc.copyright やらでさんざん議論されていたような気はするが。

ひろゆきが言うように複製を保持してそれを公衆送信可能にすることは、現行の著作権法では著作権の侵害になる。

しかし、現在ではインターネットの公正な利用の範疇として、キャッシュ機能は検索エンジン等で広く利用されている。 皆がそれを利用している。

その行為でだれかの利益が侵されているならともかく、だれの利益も侵さない行為は「侵害」と言わないと思う。

侵害されていると思うなら、裁判所に行ってくればいい。 もしかしたら Google から大金せしめられるかもしれない。

2007-09-07

不満に思っている事案

http://anond.hatelabo.jp/20070907153704

XML規格のデータ型と、サーバサイドのスクリプト言語Javascriptデータ型の対応がきれいになってない。

・セマンティックウェブが名前だけよく聞くがとっかかりが見えない。

2007-09-02

http://anond.hatelabo.jp/20070902125208

> どんな形式(PDF, ワード, 一太郎, HTML, Flash)にでも変換できるような、中間言語があるといいのかな。TeXとか。

実はこういう方向に思考が行くのは正当な流れで、その延長上に"XMLに対する期待"ってものがあったりする。XMLって、中身と見た目を完全に分けて、クライアント側で、そのクライアントに適したようにレンダリングしてよ、っていうのが目的のひとつだから、まさにここでいう中間コード

ただし、中間コードとして何でもできるXMLみたいな規格は複雑すぎて、簡単な用途に使うのには流行らなかった。まぁ、いくつか流行ったものもあるけどね。RSSとか。

そこでどうなったかというと、"中身と見た目の分離"というところでぴんと来た人もいるだろうけど、HTML+CSS適当に簡単で、しかも中身と見た目を分離できる。

というわけで、みんな、なんだか同じところをぐるぐる回ってるんじゃないかなぁ・・・という話でした。

2007-08-12

マークアップエンジニアって結局何やる人なの?

何か名前の響きからしてこんな感じの人を想像してたんだけど

でもいままでamachang発言((X)HTML+CSS しか出来ない人は真剣に第二の何かを探したほうがいいとか)の反応ざっと見てきたけどid:amachang(とその周辺)が「マークアップエンジニア = (X)HTML+CSS しか出来ない人」として話を進めてるのにも関わらずそれについて反論があんまりないんだよな。「趣味じゃなくて仕事として(X)HTML(とCSS)を作成するためにはこれこれこういう知識が必要なんだよ」とか「マークアップエンジニアには(X)HTMLCSSしかすることがないとでも思ってんのか馬鹿」とか言ったりするのかと思ったらほとんどそんなことなくて、むしろ同意ですとかそんなこと言われなくてもわかってるよとかJavaScriptだって同じじゃんとか見た感じそんなのばっかり。どうも俺の想像した職業とは違うらしい。

マークアップエンジニアって本当に(X)HTMLCSSの知識だけで(X)HTMLCSS書いてる人なの?反応見ててそもそも(X)HTMLCSSに理解があるのかってこと自体にまで疑問を感じるんだけど。

2007-07-19

/* Ten */
if (typeof(Ten) == 'undefined') {
    Ten = {};
}
Ten.NAME = 'Ten';
Ten.VERSION = 0.06;

/* Ten.Class */
Ten.Class = function(klass, prototype) {
    if (klass && klass.initialize) {
	var c = klass.initialize;
    } else if(klass && klass.base) {
        var c = function() { return klass.base[0].apply(this, arguments) };
    } else {
	var c = function() {};
    }
    c.prototype = prototype || {};
    c.prototype.constructor = c;
    Ten.Class.inherit(c, klass);
    if (klass && klass.base) {
        for (var i = 0;  i < klass.base.length; i++) {
	    var parent = klass.base[i];
            if (i == 0) {
                c.SUPER = parent;
                c.prototype.SUPER = parent.prototype;
            }
            Ten.Class.inherit(c, parent);
            Ten.Class.inherit(c.prototype, parent.prototype);
        }
    }
    return c;
}
Ten.Class.inherit = function(child,parent) {
    for (var prop in parent) {
        if (typeof(child[prop]) != 'undefined' || prop == 'initialize') continue;
        child[prop] = parent[prop];
    }
}

/*
// Basic Ten Classes
**/

/* Ten.JSONP */
Ten.JSONP = new Ten.Class({
    initialize: function(uri,obj,method) {
        if (Ten.JSONP.Callbacks.length) {
            setTimeout(function() {new Ten.JSONP(uri,obj,method)}, 500);
            return;
        }
        var del = uri.match(/\?/) ? '&' : '?';
        uri += del + 'callback=Ten.JSONP.callback';
        if (!uri.match(/timestamp=/)) {
            uri += '&' + encodeURI(new Date());
        }
        if (obj && method) Ten.JSONP.addCallback(obj,method);
        this.script = document.createElement('script');
        this.script.src = uri;
        this.script.type = 'text/javascript';
        document.getElementsByTagName('head')[0].appendChild(this.script);
    },
    addCallback: function(obj,method) {
        Ten.JSONP.Callbacks.push({object: obj, method: method});
    },
    callback: function(args) {
        // alert('callback called');
        var cbs = Ten.JSONP.Callbacks;
        for (var i = 0; i < cbs.length; i++) {
            var cb = cbs[i];
            cb.object[cb.method].call(cb.object, args);
        }
        Ten.JSONP.Callbacks = [];
    },
    MaxBytes: 8000,
    Callbacks: []
});

/* Ten.XHR */
Ten.XHR = new Ten.Class({
    initialize: function(uri,opts,obj,method) {
        if (!uri) return;
        this.request = Ten.XHR.getXMLHttpRequest();
        this.callback = {object: obj, method: method};
        var xhr = this;
        var prc = this.processReqChange;
        this.request.onreadystatechange = function() {
            prc.apply(xhr, arguments);
        }
        var method = opts.method || 'GET';
        this.request.open(method, uri, true);
        if (method == 'POST') {
            this.request.setRequestHeader('Content-Type',
                                          'application/x-www-form-urlencoded');
        }
        var data = opts.data ? Ten.XHR.makePostData(opts.data) : null;
        this.request.send(data);
    },
    getXMLHttpRequest: function() {
        var xhr;
        var tryThese = [
            function () { return new XMLHttpRequest(); },
            function () { return new ActiveXObject('Msxml2.XMLHTTP'); },
            function () { return new ActiveXObject('Microsoft.XMLHTTP'); },
            function () { return new ActiveXObject('Msxml2.XMLHTTP.4.0'); },
        ];
        for (var i = 0; i < tryThese.length; i++) {
            var func = tryThese[i];
            try {
                xhr = func;
                return func();
            } catch (e) {
                //alert(e);
            }
        }
        return xhr;
    },
    makePostData: function(data) {
        var pairs = [];
        var regexp = /%20/g;
        for (var k in data) {
            var v = data[k].toString();
            var pair = encodeURIComponent(k).replace(regexp,'+') + '=' +
                encodeURIComponent(v).replace(regexp,'+');
            pairs.push(pair);
        }
        return pairs.join('&');
    }
},{
    processReqChange: function() {
        var req = this.request;
        if (req.readyState == 4) {
            if (req.status == 200) {
                var cb = this.callback;
                cb.object[cb.method].call(cb.object, req);
            } else {
                alert("There was a problem retrieving the XML data:\n" +
                      req.statusText);
            }
        }
    }
});

/* Ten.Observer */
Ten.Observer = new Ten.Class({
    initialize: function(element,event,obj,method) {
        var func = obj;
        if (typeof(method) == 'string') {
            func = obj[method];
        }
        this.element = element;
        this.event = event;
        this.listener = function(event) {
            return func.call(obj, new Ten.Event(event || window.event));
        }
        if (this.element.addEventListener) {
            if (this.event.match(/^on(.+)$/)) {
                this.event = RegExp.$1;
            }
            this.element.addEventListener(this.event, this.listener, false);
        } else if (this.element.attachEvent) {
            this.element.attachEvent(this.event, this.listener);
        }
    }
},{
    stop: function() {
        if (this.element.removeEventListener) {
            this.element.removeEventListener(this.event,this.listener,false);
        } else if (this.element.detachEvent) {
            this.element.detachEvent(this.event,this.listener);
        }
    }
});

/* Ten.Event */
Ten.Event = new Ten.Class({
    initialize: function(event) {
        this.event = event;
    },
    keyMap: {
        8:"backspace", 9:"tab", 13:"enter", 19:"pause", 27:"escape", 32:"space",
        33:"pageup", 34:"pagedown", 35:"end", 36:"home", 37:"left", 38:"up",
        39:"right", 40:"down", 44:"printscreen", 45:"insert", 46:"delete",
        112:"f1", 113:"f2", 114:"f3", 115:"f4", 116:"f5", 117:"f6", 118:"f7",
        119:"f8", 120:"f9", 121:"f10", 122:"f11", 123:"f12",
        144:"numlock", 145:"scrolllock"
    }
},{
    mousePosition: function() {
        if (!this.event.clientX) return;
        return Ten.Geometry.getMousePosition(this.event);
    },
    isKey: function(name) {
        var ecode = this.event.keyCode;
        if (!ecode) return;
        var ename = Ten.Event.keyMap[ecode];
        if (!ename) return;
        return (ename == name);
    },
    targetIsFormElements: function() {
        var target = this.event.target;
        if (!target) return;
        var T = (target.tagName || '').toUpperCase();
        return (T == 'INPUT' || T == 'SELECT' || T == 'OPTION' ||
                T == 'BUTTON' || T == 'TEXTAREA');
    },
    stop: function() {
        var e = this.event;
        if (e.stopPropagation) {
            e.stopPropagation();
            e.preventDefault();
        } else {
            e.cancelBubble = true;
            e.returnValue = false;
        }
    }
});

/* Ten.DOM */
Ten.DOM = new Ten.Class({
    getElementsByTagAndClassName: function(tagName, className, parent) {
        if (typeof(parent) == 'undefined') {
            parent = document;
        }
        var children = parent.getElementsByTagName(tagName);
        if (className) { 
            var elements = [];
            for (var i = 0; i < children.length; i++) {
                var child = children[i];
                var cls = child.className;
                if (!cls) {
                    continue;
                }
                var classNames = cls.split(' ');
                for (var j = 0; j < classNames.length; j++) {
                    if (classNames[j] == className) {
                        elements.push(child);
                        break;
                    }
                }
            }
            return elements;
        } else {
            return children;
        }
    },
    removeEmptyTextNodes: function(element) {
        var nodes = element.childNodes;
        for (var i = 0; i < nodes.length; i++) {
            var node = nodes[i];
            if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) {
                node.parentNode.removeChild(node);
            }
        }
    },
    nextElement: function(elem) {
        do {
            elem = elem.nextSibling;
        } while (elem && elem.nodeType != 1);
        return elem;
    },
    prevElement: function(elem) {
        do {
            elem = elem.previousSibling;
        } while (elem && elem.nodeType != 1);
        return elem;
    },
    scrapeText: function(node) {
        var rval = [];
        (function (node) {
            var cn = node.childNodes;
            if (cn) {
                for (var i = 0; i < cn.length; i++) {
                    arguments.callee.call(this, cn[i]);
                }
            }
            var nodeValue = node.nodeValue;
            if (typeof(nodeValue) == 'string') {
                rval.push(nodeValue);
            }
        })(node);
        return rval.join('');
    },
    onLoadFunctions: [],
    loaded: false,
    timer: null,
    addEventListener: function(event,func) {
        if (event != 'load') return;
        Ten.DOM.onLoadFunctions.push(func);
        Ten.DOM.checkLoaded();
    },
    checkLoaded: function() {
        var c = Ten.DOM;
        if (c.loaded) return true;
        if (document && document.getElementsByTagName &&
            document.getElementById && document.body) {
            if (c.timer) {
                clearInterval(c.timer);
                c.timer = null;
            }
            for (var i = 0; i < c.onLoadFunctions.length; i++) {
                    c.onLoadFunctions[i]();
            }
            c.onLoadFunctions = [];
            c.loaded = true;
        } else {
            c.timer = setInterval(c.checkLoaded, 13);
        }
    }
});

/* Ten.Style */
Ten.Style = new Ten.Class({
    applyStyle: function(elem, style) {
        for (prop in style) {
            elem.style[prop] = style[prop];
        }
    }
});

/* Ten.Geometry */
Ten.Geometry = new Ten.Class({
    initialize: function() {
        if (Ten.Geometry._initialized) return;
        var func = Ten.Geometry._functions;
        var de = document.documentElement;
        if (window.innerWidth) {
            func.getWindowWidth = function() { return window.innerWidth; }
            func.getWindowHeight = function() { return window.innerHeight; }
            func.getXScroll = function() { return window.pageXOffset; }
            func.getYScroll = function() { return window.pageYOffset; }
        } else if (de && de.clientWidth) {
            func.getWindowWidth = function() { return de.clientWidth; }
            func.getWindowHeight = function() { return de.clientHeight; }
            func.getXScroll = function() { return de.scrollLeft; }
            func.getYScroll = function() { return de.scrollTop; }
        } else if (document.body.clientWidth) {
            func.getWindowWidth = function() { return document.body.clientWidth; }
            func.getWindowHeight = function() { return document.body.clientHeight; }
            func.getXScroll = function() { return document.body.scrollLeft; }
            func.getYScroll = function() { return document.body.scrollTop; }
        }
        Ten.Geometry._initialized = true;
    },
    _initialized: false,
    _functions: {},
    getScroll: function() {
        if (!Ten.Geometry._initialized) new Ten.Geometry;
        return {
            x: Ten.Geometry._functions.getXScroll(),
            y: Ten.Geometry._functions.getYScroll()
        };
    },
    getMousePosition: function(pos) {
        // pos should have clientX, clientY same as mouse event
        if ((navigator.userAgent.indexOf('Safari') > -1) &&
            (navigator.userAgent.indexOf('Version/') < 0)) {
            return {
                x: pos.clientX,
                y: pos.clientY
            };
        } else {
            var scroll = Ten.Geometry.getScroll();
            return {
                x: pos.clientX + scroll.x,
                y: pos.clientY + scroll.y
            };
        }
    },
    getElementPosition: function(e) {
        return {
            x: e.offsetLeft,
            y: e.offsetTop
        };
    },
    getWindowSize: function() {
        if (!Ten.Geometry._initialized) new Ten.Geometry;
        return {
            w: Ten.Geometry._functions.getWindowWidth(),
            h: Ten.Geometry._functions.getWindowHeight()
        };
    }
});

/* Ten.Position */
Ten.Position = new Ten.Class({
    initialize: function(x,y) {
        this.x = x;
        this.y = y;
    },
    subtract: function(a,b) {
        return new Ten.Position(a.x - b.x, a.y - b.y);
    }
});

/*
// require Ten.js
**/

/* Ten.SubWindow */
Ten.SubWindow = new Ten.Class({
    initialize: function() {
        var c = this.constructor;
        if (c.singleton && c._cache) {
            return c._cache;
        }
        var div = document.createElement('div');
        Ten.Style.applyStyle(div, Ten.SubWindow._baseStyle);
        Ten.Style.applyStyle(div, c.style);
        this.window = div;
        this.addContainerAndCloseButton();
        document.body.appendChild(div);
        if (c.draggable) {
            this._draggable = new Ten.Draggable(div, this.handle);
        }
        if (c.singleton) c._cache = this;
        return this;
    },
    _baseStyle: {
        color: '#000',
        position: 'absolute',
        display: 'none',
        zIndex: 2,
        left: 0,
        top: 0,
        backgroundColor: '#fff',
        border: '1px solid #bbb'
    },
    style: {
        padding: '2px',
        textAlign: 'center',
        borderRadius: '6px',
        MozBorderRadius: '6px',
        width: '100px',
        height: '100px'
    },
    handleStyle: {
        position: 'absolute',
        top: '0px',
        left: '0px',
        backgroundColor: '#f3f3f3',
        borderBottom: '1px solid #bbb',
        width: '100%',
        height: '30px'
    },
    containerStyle: {
        margin: '32px 0 0 0',
        padding: '0 10px'
    },
    // closeButton: 'close.gif',
    closeButton: 'http://s.hatena.com/images/close.gif',
    closeButtonStyle: {
        position: 'absolute',
        top: '8px',
        right: '10px',
        cursor: 'pointer'
    },
    _baseScreenStyle: {
        position: 'absolute',
        top: '0px',
        left: '0px',
        display: 'none',
        zIndex: 1,
        overflow: 'hidden',
        width: '100%',
        height: '100%'
    },
    screenStyle: {},
    showScreen: true,
    singleton: true,
    draggable: true,
    _cache: null
},{
    screen: null,
    windowObserver: null,
    visible: false,
    addContainerAndCloseButton: function() {
        var win = this.window;
        var c = this.constructor;
        var div = document.createElement('div');
        win.appendChild(div);
        Ten.Style.applyStyle(div, c.containerStyle);
        this.container = div;
        if (c.handleStyle) {
            var handle = document.createElement('div');
            Ten.Style.applyStyle(handle, c.handleStyle);
            win.appendChild(handle);
            this.handle = handle;
        }
        if (c.closeButton) {
	    var btn = document.createElement('img');
            btn.src = c.closeButton;
            btn.alt = 'close';
            Ten.Style.applyStyle(btn, c.closeButtonStyle);
            win.appendChild(btn);
            new Ten.Observer(btn, 'onclick', this, 'hide');
            this.closeButton = btn;
        }
        if (c.showScreen) {
            var screen = document.createElement('div');
            Ten.Style.applyStyle(screen, Ten.SubWindow._baseScreenStyle);
            Ten.Style.applyStyle(screen, c.screenStyle);
            document.body.appendChild(screen);
            this.screen = screen;
            new Ten.Observer(screen, 'onclick', this, 'hide');
        }
    },
    show: function(pos) {
        pos = (pos.x && pos.y) ? pos : {x:0, y:0};
        with (this.window.style) {
            display = 'block';
            left = pos.x + 'px';
            top = pos.y + 'px';
        }
        if (this.screen) {
            with (this.screen.style) {
                display = 'block';
                left = Ten.Geometry.getScroll().x + 'px';
                top = Ten.Geometry.getScroll().y + 'px';
            }
        }
        this.windowObserver = new Ten.Observer(document.body, 'onkeypress', this, 'handleEscape');
        this.visible = true;
    },
    handleEscape: function(e) {
        if (!e.isKey('escape')) return;
        this.hide();
    },
    hide: function() {
        if (this._draggable) this._draggable.endDrag();
        this.window.style.display = 'none';
        if (this.screen) this.screen.style.display = 'none';
        if (this.windowObserver) this.windowObserver.stop();
        this.visible = false;
    }
});

/* Ten.Draggable */
Ten.Draggable = new Ten.Class({
    initialize: function(element,handle) {
        this.element = element;
        this.handle = handle || element;
        this.startObserver = new Ten.Observer(this.handle, 'onmousedown', this, 'startDrag');
        this.handlers = [];
    }
},{
    startDrag: function(e) {
        if (e.targetIsFormElements()) return;
        this.delta = Ten.Position.subtract(
            e.mousePosition(),
            Ten.Geometry.getElementPosition(this.element)
        );
        this.handlers = [
            new Ten.Observer(document, 'onmousemove', this, 'drag'),
            new Ten.Observer(document, 'onmouseup', this, 'endDrag'),
            new Ten.Observer(this.element, 'onlosecapture', this, 'endDrag')
        ];
        e.stop();
    },
    drag: function(e) {
        var pos = Ten.Position.subtract(e.mousePosition(), this.delta);
        Ten.Style.applyStyle(this.element, {
            left: pos.x + 'px',
            top: pos.y + 'px'
        });
        e.stop();
    },
    endDrag: function(e) {
        for (var i = 0; i < this.handlers.length; i++) {
            this.handlers[i].stop();
        }
        if(e) e.stop();
    }
});

/* Hatena */
if (typeof(Hatena) == 'undefined') {
    Hatena = {};
}

/* Hatena.User */
Hatena.User = new Ten.Class({
    initialize: function(name) {
        this.name = name;
    },
    getProfileIcon: function(name) {
        if (!name) name = 'user';
        var pre = name.match(/^[\w-]{2}/)[0];
        var img = document.createElement('img');
        img.src = 'http://www.hatena.ne.jp/users/' + pre + '/' + name + '/profile_s.gif';
        img.alt = name;
        img.setAttribute('class', 'profile-icon');
        img.setAttribute('width','16px');
        img.setAttribute('height','16px');
        with (img.style) {
            margin = '0 3px';
            border = 'none';
            verticalAlign = 'middle';
        }
        return img;
    }
}, {
    profileIcon: function() {
        return Hatena.User.getProfileIcon(this.name);
    }
});

/* Hatena.Star */
if (typeof(Hatena.Star) == 'undefined') {
    Hatena.Star = {};
}

/*
// Hatena.Star.* classes //
**/
if (window.location && window.location.host.match(/hatena\.com/)) {
    Hatena.Star.BaseURL = 'http://s.hatena.com/';
} else {
    Hatena.Star.BaseURL = 'http://s.hatena.ne.jp/';
}
Hatena.Star.Token = null;

/* Hatena.Star.User */
Hatena.Star.User = new Ten.Class({
    base: [Hatena.User],
    initialize: function(name) {
        if (Hatena.Star.User._cache[name]) {
            return Hatena.Star.User._cache[name];
        } else {
            this.name = name;
            Hatena.Star.User._cache[name] = this;
            return this;
        }
    },
    _cache: {}
},{
    userPage: function() {
        return Hatena.Star.BaseURL + this.name + '/';
    }
});

/* Hatena.Star.Entry */
Hatena.Star.Entry = new Ten.Class({
    initialize: function(e) {
        this.entry = e;
        this.uri = e.uri;
        this.title = e.title;
        this.star_container = e.star_container;
        this.comment_container = e.comment_container;
        this.stars = [];
        this.comments = [];
    },
    maxStarCount: 11
},{
    flushStars: function() {
        this.stars = [];
        this.star_container.innerHTML = '';
    },
    bindStarEntry: function(se) {
        this.starEntry = se;
        for (var i = 0; i < se.stars.length; i++) {
            if (typeof(se.stars[i]) == 'number') {
                this.stars.push(new Hatena.Star.InnerCount(se.stars[i],this));
            } else {
                this.stars.push(new Hatena.Star.Star(se.stars[i]));
            }
        }
        if (se.comments && !this.comments.length) {
            for (var i = 0; i < se.comments.length; i++) {
                this.comments.push(new Hatena.Star.Comment(se.comments[i]));
            }
        }
        this.can_comment = se.can_comment;
    },
    setCanComment: function(v) {
        this.can_comment = v;
    },
    showButtons: function() {
        this.addAddButton();
        this.addCommentButton();
    },
    addAddButton: function() {
        if (this.star_container) {
            this.addButton = new Hatena.Star.AddButton(this);
            this.star_container.appendChild(this.addButton);
        }
    },
    addCommentButton: function() {
        if (this.comment_container) {
            this.commentButton = new Hatena.Star.CommentButton(this);
            this.comment_container.appendChild(this.commentButton.img);
        }
    },
    showStars: function() {
        var klass = this.constructor;
        // if (this.stars.length > klass.maxStarCount) {
        //     var ic = new Hatena.Star.InnerCount(this.stars.slice(1,this.stars.length));
        //     this.star_container.appendChild(this.stars[0]);
        //     this.star_container.appendChild(ic);
        //     this.star_container.appendChild(this.stars[this.stars.length - 1]);
        // } else {
        for (var i = 0; i < this.stars.length; i++) {
            this.star_container.appendChild(this.stars[i]);
        }
    },
    showCommentButton: function() {
        if (this.can_comment) {
            this.commentButton.show();
            if (this.comments.length) this.commentButton.activate();
        } else {
            // this.commentButton.hide();
        }
    },
    addStar: function(star) {
        this.stars.push(star);
        this.star_container.appendChild(star);
    },
    addComment: function(com) {
        if (!this.comments) this.comments = [];
        if (this.comments.length == 0) {
            this.commentButton.activate();
        }
        this.comments.push(com);
    },
    showCommentCount: function() {
        this.comment_container.innerHTML += this.comments.length;
    }
});

/* Hatena.Star.Button */
Hatena.Star.Button = new Ten.Class({
    createButton: function(args) {
        var img = document.createElement('img');
        img.src = args.src;
        img.alt = img.title = args.alt;
        with (img.style) {
	    cursor = 'pointer';
	    margin = '0 3px';
            padding = '0';
            border = 'none';
            verticalAlign = 'middle';
        }
        return img;
    }
});

/* Hatena.Star.AddButton */
Hatena.Star.AddButton = new Ten.Class({
    base: ['Hatena.Star.Button'],
    initialize: function(entry) {
        this.entry = entry;
        this.lastPosition = null;
        var img = Hatena.Star.Button.createButton({
            src: Hatena.Star.AddButton.ImgSrc,
            alt: 'Add Star'
        });
        this.observer = new Ten.Observer(img,'onclick',this,'addStar');
        this.img = img;
        return img;
    },
    ImgSrc: Hatena.Star.BaseURL + 'images/add.gif'
},{
    addStar: function(e) {
        this.lastPosition = e.mousePosition();
        var uri = Hatena.Star.BaseURL + 'star.add.json?uri=' + encodeURIComponent(this.entry.uri) +
            '&title=' + encodeURIComponent(this.entry.title);
        if (Hatena.Star.Token) {
            uri += '&token=' + Hatena.Star.Token;
        }
        new Ten.JSONP(uri, this, 'receiveResult');
    },
    receiveResult: function(args) {
        var name = args ? args.name : null;
        if (name) {
            this.entry.addStar(new Hatena.Star.Star({name: name}));
            //alert('Succeeded in Adding Star ' + args);
        } else if (args.errors) {
            var pos = this.lastPosition;
            pos.x -= 10;
            pos.y += 25;
            var scroll = Ten.Geometry.getScroll();
            var scr = new Hatena.Star.AlertScreen();
            var alert = args.errors[0];
            scr.showAlert(alert, pos);
        }
    }
});

/* Hatena.Star.CommentButton */
Hatena.Star.CommentButton = new Ten.Class({
    base: ['Hatena.Star.Button'],
    initialize: function(entry) {
        this.entry = entry;
        this.lastPosition = null;
        var img = Hatena.Star.Button.createButton({
            src: Hatena.Star.CommentButton.ImgSrc,
            alt: 'Comments'
        });
        img.style.display = 'none';
        this.observer = new Ten.Observer(img,'onclick',this,'showComments');
        this.img = img;
    },
    ImgSrc: Hatena.Star.BaseURL + 'images/comment.gif',
    ImgSrcActive: Hatena.Star.BaseURL + 'images/comment_active.gif'
},{
    showComments: function(e) {
        if (!this.screen) this.screen = new Hatena.Star.CommentScreen();
        this.screen.bindEntry(this.entry);
        var pos = e.mousePosition();
        pos.y += 25;
        this.screen.showComments(this.entry, pos);
    },
    hide: function() {
        this.img.style.display = 'none';
    },
    show: function() {
        this.img.style.display = 'inline';
    },
    activate: function() {
        this.show();
        this.img.src = Hatena.Star.CommentButton.ImgSrcActive;
    }
});

/* Hatena.Star.Star */
Hatena.Star.Star = new Ten.Class({
    initialize: function(args) {
        if (args.img) {
            this.img = args.img;
            this.name = this.img.getAttribute('alt');
        } else {
            this.name = args.name;
            var img = document.createElement('img');
            img.src = Hatena.Star.Star.ImgSrc;
            img.alt = this.name;
            with (img.style) {
                padding = '0';
                border = 'none';
            }
            this.img = img;
        }
	new Ten.Observer(this.img,'onmouseover',this,'showName');
	new Ten.Observer(this.img,'onmouseout',this,'hideName');
	if (this.name) {
            this.user = new Hatena.Star.User(this.name);
            this.img.style.cursor = 'pointer';
            new Ten.Observer(this.img,'onclick',this,'goToUserPage');
        }
        if (args.count && args.count > 1) {
            var c = document.createElement('span');
            c.setAttribute('class', 'hatena-star-inner-count');
            Ten.Style.applyStyle(c, Hatena.Star.InnerCount.style);
            c.innerHTML = args.count;
            var s = document.createElement('span');
            s.appendChild(img);
            s.appendChild(c);
            return s;
        } else {
            return this.img;
        }
    },
    ImgSrc: Hatena.Star.BaseURL + 'images/star.gif'
},{
    showName: function(e) {
        if (!this.screen) this.screen = new Hatena.Star.NameScreen();
        var pos = e.mousePosition();
        pos.x += 10;
        pos.y += 25;
        this.screen.showName(this.name, pos);
    },
    hideName: function() {
        if (!this.screen) return;
        this.screen.hide();
    },
    goToUserPage: function() {
        window.location = this.user.userPage();
    }
});

/* Hatena.Star.InnerCount */
Hatena.Star.InnerCount = new Ten.Class({
    initialize: function(count, e) {
        this.count = count;
        this.entry = e;
        var c = document.createElement('span');
        c.setAttribute('class', 'hatena-star-inner-count');
        Ten.Style.applyStyle(c, Hatena.Star.InnerCount.style);
        c.style.cursor = 'pointer';
        c.innerHTML = count;
        new Ten.Observer(c,'onclick',this,'showInnerStars');
        this.container = c;
        return c;
    },
    style: {
        color: '#f4b128',
        fontWeight: 'bold',
        fontSize: '80%',
        fontFamily: '"arial", sans-serif',
        margin: '0 2px'
    }
},{
    showInnerStars: function() {
        var url = Hatena.Star.BaseURL + 'entry.json?uri=' +
        encodeURIComponent(this.entry.uri);
        new Ten.JSONP(url, this, 'receiveStarEntry');
    },
    receiveStarEntry: function(res) {
        var se = res.entries[0];
        var e = this.entry;
        if (encodeURIComponent(se.uri) != encodeURIComponent(e.uri)) return;
        e.flushStars();
        e.bindStarEntry(se);
        e.addAddButton();
        e.showStars();
    }
});

/* Hatena.Star.Comment */
Hatena.Star.Comment = new Ten.Class({
    initialize: function(args) {
        this.name = args.name;
        this.body = args.body;
    }
},{
    asElement: function() {
        var div = document.createElement('div');
        with (div.style) {
            margin = '0px 0';
            padding = '5px 0';
            borderBottom = '1px solid #ddd';
        }
        var ico = Hatena.User.getProfileIcon(this.name);
        div.appendChild(ico);
        var span = document.createElement('span');
        with(span.style) {
            fontSize = '90%';
        }
        span.innerHTML = this.body;
        div.appendChild(span);
        return div;
    }
});

/* Hatena.Star.NameScreen */
Hatena.Star.NameScreen = new Ten.Class({
    base: [Ten.SubWindow],
    style: {
        padding: '2px',
        textAlign: 'center'
    },
    containerStyle: {
        margin: 0,
        padding: 0
    },
    handleStyle: null,
    showScreen: false,
    closeButton: null,
    draggable: false
},{
    showName: function(name, pos) {
        this.container.innerHTML = '';
        this.container.appendChild(Hatena.User.getProfileIcon(name));
        this.container.appendChild(document.createTextNode(name));
        this.show(pos);
    }
});

/* Hatena.Star.AlertScreen */
Hatena.Star.AlertScreen = new Ten.Class({
    base: [Ten.SubWindow],
    style: {
        padding: '2px',
        textAlign: 'center',
        borderRadius: '6px',
        MozBorderRadius: '6px',
        width: '240px',
        height: '120px'
    },
    handleStyle: {
        position: 'absolute',
        top: '0px',
        left: '0px',
        backgroundColor: '#f3f3f3',
        borderBottom: '1px solid #bbb',
        width: '100%',
        height: '30px',
        borderRadius: '6px 6px 0 0',
        MozBorderRadius: '6px 6px 0 0'
    }
},{
    showAlert: function(msg, pos) {
        this.container.innerHTML = msg;
        var win = Ten.Geometry.getWindowSize();
        var scr = Ten.Geometry.getScroll();
        var w = parseInt(this.constructor.style.width) + 20;
        if (pos.x + w > scr.x + win.w) pos.x = win.w + scr.x - w;
        this.show(pos);
    }
});

/* Hatena.Star.CommentScreen */
Hatena.Star.CommentScreen = new Ten.Class({
    base: [Ten.SubWindow],
    initialize: function() {
        var self = this.constructor.SUPER.call(this);
        if (!self.commentsContainer) self.addCommentsContainer();
        return self;
    },
    style: {
        width: '280px',
        height: '280px',
        overflowY: 'auto',
        padding: '2px',
        textAlign: 'center',
        borderRadius: '6px',
        MozBorderRadius: '6px'
    },
    handleStyle: {
        position: 'absolute',
        top: '0px',
        left: '0px',
        backgroundColor: '#f3f3f3',
        borderBottom: '1px solid #bbb',
        width: '100%',
        height: '30px',
        borderRadius: '6px 6px 0 0',
        MozBorderRadius: '6px 6px 0 0'
    },
    containerStyle: {
        margin: '32px 0 0 0',
        textAlign: 'left',
        padding: '0 10px'
    },
    getLoadImage: function() {
        var img = document.createElement('img');
        img.src = Hatena.Star.BaseURL + 'images/load.gif';
        img.setAttribute('alt', 'Loading');
        with (img.style) {
            verticalAlign = 'middle';
            margin = '0 2px';
        }
        return img;
    }
},{
    addCommentsContainer: function() {
        var div = document.createElement('div');
        with (div.style) {
            marginTop = '-3px';
        }
        this.container.appendChild(div);
        this.commentsContainer = div;
    },
    showComments: function(e, pos) {
        var comments = e.comments;
        if (!comments) comments = [];
        this.commentsContainer.innerHTML = '';
        for (var i=0; i<comments.length; i++) {
            this.commentsContainer.appendChild(comments[i].asElement());
        }
        if (e.starEntry && !e.can_comment) {
            this.hideCommentForm();
        } else {
            this.addCommentForm();
        }
        var win = Ten.Geometry.getWindowSize();
        var scr = Ten.Geometry.getScroll();
        var w = parseInt(this.constructor.style.width) + 20;
        if (pos.x + w > scr.x + win.w) pos.x = win.w + scr.x - w;
        this.show(pos);
    },
    bindEntry: function(e) {
        this.entry = e;
    },
    sendComment: function(e) {
        if (!e.isKey('enter')) return;
        var body = this.commentInput.value;
        if (!body) return;
        this.commentInput.disabled = 'true';
        this.showLoadImage();
        var url = Hatena.Star.BaseURL + 'comment.add.json?body=' + encodeURIComponent(body) +
            '&uri=' + encodeURIComponent(this.entry.uri) +
            '&title=' + encodeURIComponent(this.entry.title);
        new Ten.JSONP(url, this, 'receiveResult');
    },
    receiveResult: function(args) {
        if (!args.name || !args.body) return;
        this.commentInput.value = ''; 
        this.commentInput.disabled = '';
        this.hideLoadImage();
        var com = new Hatena.Star.Comment(args);
        this.entry.addComment(com);
        this.commentsContainer.appendChild(com.asElement());
    },
    showLoadImage: function() {
        if (!this.loadImage) return; 
        this.loadImage.style.display = 'inline';
    },
    hideLoadImage: function() {
        if (!this.loadImage) return; 
        this.loadImage.style.display = 'none';
    },
    hideCommentForm: function() {
        if (!this.commentForm) return;
        this.commentForm.style.display = 'none';
    },
    addCommentForm: function() {
        if (this.commentForm) {
            this.commentForm.style.display = 'block';
            return;
        }
        var form = document.createElement('div');
        this.container.appendChild(form);
        this.commentForm = form;
        with (form.style) {
            margin = '0px 0';
            padding = '5px 0';
            // borderTop = '1px solid #ddd';
        }
        //if (Hatena.Visitor) {
        //    form.appendChild(Hatena.Visitor.profileIcon());
        //} else {
        //    form.appendChild(Hatena.User.getProfileIcon());
        //}
        var input = document.createElement('input');
        input.type = 'text';
        with (input.style) {
            width = '215px';
	    border = '1px solid #bbb';
            padding = '3px';
        }
        form.appendChild(input);
        this.commentInput = input;
        var img = this.constructor.getLoadImage();
        this.loadImage = img;
        this.hideLoadImage();
        form.appendChild(img);
        new Ten.Observer(input,'onkeypress',this,'sendComment');
    }
});

/* Hatena.Star.EntryLoader */
Hatena.Star.EntryLoader = new Ten.Class({
    initialize: function() {
        var entries = Hatena.Star.EntryLoader.loadEntries();
        this.entries = [];
        for (var i = 0; i < entries.length; i++) {
            var e = new Hatena.Star.Entry(entries[i]);
            e.showButtons();
            this.entries.push(e);
        }
        this.getStarEntries();
    },
    createStarContainer: function() {
        var sc = document.createElement('span');
        sc.setAttribute('class', 'hatena-star-star-container');
        sc.style.marginLeft = '1px';
        return sc;
    },
    createCommentContainer: function() {
        var cc = document.createElement('span');
        cc.setAttribute('class', 'hatena-star-comment-container');
        cc.style.marginLeft = '1px';
        return cc;
    },
    scrapeTitle: function(node) {
        var rval = [];
        (function (node) {
            if (node.tagName == 'SPAN' &&
                (node.className == 'sanchor' ||
                 node.className == 'timestamp')) {
                     return;
            } else if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) {
                return;
            }
            var cn = node.childNodes;
            if (cn) {
                for (var i = 0; i < cn.length; i++) {
                    arguments.callee.call(this, cn[i]);
                }
            }
            var nodeValue = node.nodeValue;
            if (typeof(nodeValue) == 'string') {
                rval.push(nodeValue);
            }
        })(node);
        return rval.join('');
    },
    headerTagAndClassName: ['h3',null],
    getHeaders: function() {
        var t = Hatena.Star.EntryLoader.headerTagAndClassName;
        return Ten.DOM.getElementsByTagAndClassName(t[0],t[1],document);
    },
    loadEntries: function() {
        var entries = [];
        //var headers = document.getElementsByTagName('h3');
        var c = Hatena.Star.EntryLoader;
        var headers = c.getHeaders();
        for (var i = 0; i < headers.length; i++) {
            var header = headers[i];
            var a = header.getElementsByTagName('a')[0];
            if (!a) continue;
            var uri = a.href;
            var title = '';
            // Ten.DOM.removeEmptyTextNodes(header);
            var cns = header.childNodes;
            title = c.scrapeTitle(header);
            var cc = c.createCommentContainer();
            header.appendChild(cc);
            var sc = c.createStarContainer();
            header.appendChild(sc);
            entries.push({
                uri: uri,
                title: title,
                star_container: sc,
                comment_container: cc
            });
        }
        return entries;
    }
},{
    getStarEntries: function() {
        var url = Hatena.Star.BaseURL + 'entries.json?';
        for (var i = 0; i < this.entries.length; i++) {
            if (url.length > Ten.JSONP.MaxBytes) {
                new Ten.JSONP(url, this, 'receiveStarEntries');
                url = Hatena.Star.BaseURL + 'entries.json?';
            }
            url += 'uri=' + encodeURIComponent(this.entries[i].uri) + '&';
        }
        new Ten.JSONP(url, this, 'receiveStarEntries');
    },
    receiveStarEntries: function(res) {
        var entries = res.entries;
        if (!entries) entries = [];
        for (var i = 0; i < this.entries.length; i++) {
            var e = this.entries[i];
            for (var j = 0; j < entries.length; j++) {
                var se = entries[j];
                if (!se.uri) continue;
                if (encodeURIComponent(se.uri) == encodeURIComponent(e.uri)) {
                    e.bindStarEntry(se);
                    entries.splice(j,1);
                    break;
                }
            }
            if (typeof(e.can_comment) == 'undefined') {
                e.setCanComment(res.can_comment);
            }
            e.showStars();
            e.showCommentButton();
        }
    }
});

/* Hatena.Star.WindowObserver */
Hatena.Star.WindowObserver = new Ten.Class({
    initialize: funct


  

2007-06-27

http://anond.hatelabo.jp/20070627152101

br /が文法違反になるのはxmlじゃなくhtmlで書いてるからなんじゃないの?

ちゃんとdtd宣言に則った書式で書かないと減点されるよ。

ログイン ユーザー登録
ようこそ ゲスト さん