パッチを書こう

動いてしかるべき物が別のOSだと動かなかったりしたときにはちゃんと調べてパッチを書こう。

パッチを書こう

パッチを書こうパッチを書こうパッチを書こうパッチを書こう

パッチを書こうパッチを書こうパッチを書こうパッチを書こう

パッチを書こう

参考文献

https://github.com/mirrors/perl/compare/mirrors:19bfff0f437aaac271c0658c51d56954ab685688...mirrors:efddccb56d48c54934eb6a832cb5c3f06b994f82

http://d.hatena.ne.jp/punitan/20110510/1305049279


Ubuntu 11.04 (Natty) で perl がインストール出来ない場合の理由と対策

追記

perlbrew 最新版では修正済みです。patchperl にパッチ投げておきました。

perlbrewも最新のpatchperl を使うようになったので、失敗する場合はもう一度perlbrew の最新版を再インストールしてください(perlbrew のバージョン番号は変わってないので注意)

追記終わり

http://d.hatena.ne.jp/Itisango/20110504/1304487042 の原因。

原因 - Ubuntu の math ライブラリ諸々がディレクトリごと移動した

Configure はデフォルトで

/usr/local/lib
/lib
/usr/lib
/usr/lib64

を読みに行くところ、Ubuntu Natty からは libm などのライブラリが

/lib/i386-linux-gnu
/usr/lib/i386-linux-gnu

などに移動しているためリンクできずにリンカがエラーを吐く。

対策

Configure の plibpth にこれらのディレクトリを加えてやれば解決できる。

ライブラリのパスは環境に依存してるので

$ gcc -print-search-dirs | grep libraries | cut -f2 - -d= | tr ':' '\n'

などして確認できる。

おまけ

make test の時に

../lib/User/pwent.t ............................................... ok
../lib/feature/unicode_strings.t .................................. ok
x2p/s2p.t ......................................................... ok

Test Summary Report
-------------------
op/stash.t                                                      (Wstat: 0 Tests: 31 Failed: 0)
  TODO passed:   26
../cpan/Memoize/t/errors.t                                      (Wstat: 11 Tests: 6 Failed: 0)
  Non-zero wait status: 11
  Parse errors: Bad plan.  You planned 11 tests but ran 6.
../ext/ODBM_File/t/odbm.t                                       (Wstat: 32512 Tests: 0 Failed: 0)
  Non-zero exit status: 127
  Parse errors: No plan found in TAP output
../lib/DBM_Filter/t/01error.t                                   (Wstat: 32512 Tests: 3 Failed: 0)
  Non-zero exit status: 127
  Parse errors: Bad plan.  You planned 21 tests but ran 3.
Files=1808, Tests=349977, 930 wallclock secs (73.67 usr 14.43 sys + 511.11 cusr 72.13 csys = 671.34 CPU)
Result: FAIL
make: *** [test_harness] Error 3

のようなエラーが出た場合は libgdbm のリンクに失敗しているため、

$ perlbrew install perl-5.12.3 # もしここで失敗したら
$ cd ~/perl5/perlbrew/build/perl-5.12.3/
$ locate libgdbm | grep o$
/usr/lib/i386-linux-gnu/libgdbm.so
/usr/lib/i386-linux-gnu/libgdbm_compat.so
$ vim ext/ODBM_File/hints/linux.pl

として ext/ODBM_File/hints/linux.pl の条件式をlocate で確認したパスに合わせて次のように書き換える

if (-e '/usr/lib/libgdbm_compat.so' or -e '/usr/lib64/libgdbm_compat.so'
    or -e '/usr/lib/i386-linux-gnu/libgdbm.so' or -e '/usr/lib/i386-linux-gnu/libgdbm_compat.so'
) {

パーミッションが -r--r--r-- なので強制的に上書き。その後、

$ make clean && make && make test
$ make install

すればあら不思議インストールされています。

$ perlbrew list
* perl-5.12.1
  perl-5.12.3
  /usr/bin/perl (5.10.1)

ということでライブラリのパスが変わってしまったために起きた問題でした。

参考文献

http://rt.perl.org/rt3//Public/Bug/Display.html?id=86854

http://rt.perl.org/rt3/Public/Bug/Display.html?id=90106


dotcloud雑感

みんながhello worldばかりやっているのでちょっとしたアプリつくってみようということで作ったもの。http://middleware.punytan.dotcloud.com/

Plack::Middleware::* なnamespaceを列挙して、モジュール名クリックでPODを読み込んでくれる超便利な仕上がりとなっております。適当な頻度で更新されるはず。(うまく動いていれば)

ソースはここにおいてあります https://github.com/punytan/middleware.punytan.dotcloud.com

dotcloudは簡単すぎでhello worldの解説は日本語でも大量にあるのでそれを読むとすぐに使えるようになってしまうのでそのあとの+αを。

ssh

ssh 使うときは info でポートがわかるけれども、

dotcloud ssh foo.bar

みたいにも入れるのでこっちのほうが楽ですね。

モジュール

はじめからperlの環境とcpanmが入ってるのでdot-filesを管理している人はモジュールを一気に入れたほうがモジュール不足でイラッとしなくて済むと思う。(とくにモジュール周りやテスト周り)

必要なものをいちいち選んでインストールするのが面倒なので富豪的に普段使っているものをどんどん入れた。

https://github.com/punytan/dot-files/blob/master/build-env/06_perl-modules.list

この中で入らなかったのは

  • Text::MeCab
  • MP3::Tag

の二つだけなのでXML関連をはじめ、諸々ライブラリはOSにインストール済みな雰囲気。これは大変便利。

extlib

これは多分個人の趣味よるかもしれないけれども、CPANに上げてないモジュールはextlib使わずにインストールしてみた。手元の環境と全く同じという訳でもなさそうなのでPP以外に依存してる場合は、同梱するとあとでやや面倒になりそうな気がする。

gitが入ってるぽいので富豪的にモジュールを入れたあとは github などから git clone して make dist 後(あるいは$HOME/shipit-distから持ってきて)、cpanmに渡すだけで楽々インストールできます。

VPSと比べて

VPSだとXMLライブラリのインストールやsshの設定やら諸々手間なことが待っているわけですが、ここまでデプロイするのが楽だと丸投げしたくなってしまいますね!

個人的にはmemcachedが使えるといいなぁという所。


Tatsumaki + AnyEvent::Twitter::Stream を一枚のスクリプトで完結させる方法

これができると嬉しいこと

サーバとクライアントがひとつのプロセスにまとまってクローラー的なプロセスが必要なくなり、監視せずに済むので地味に嬉しい

概要

言われてみれば何だ、という程度ではあるけれども、app.psgiで Twiggy::Server を使い、コネクションを AE::timer で監視し、AE::cv->recv; するという方法をつかえば Tatsumaki::MessageQueue も使えて万々歳。これがなかなか思いつかなかった…

思いつかなかった言い訳

Twitter の userstream は時々切れるので再接続の処理をする必要があった。今までずっとクローラーで while ループ回したりしてたけれども、 while を使って接続が切れるごとに ->recv してるとサーバと一緒に動かすことができなくて悶々とした日々を過ごすこと数ヶ月。

サーバでは builder {} を return していたので、当然 while なんて挟めなかった。

ソース

必要な部分だけ切り取り

use strict;

package PollHandler;
use parent 'Tatsumaki::Handler';
__PACKAGE__->asynchronous(1);
use Tatsumaki::MessageQueue;

sub get {
    my $self = shift;

    my $mq = Tatsumaki::MessageQueue->instance('tweet');
    my $client_id = $self->request->param('client_id')
        or Tatsumaki::Error::HTTP->throw(500, 'client_id is required');
    $mq->poll_once($client_id, sub { $self->on_new_event(@_) });
}

sub on_new_event {
    my $self = shift;
    $self->write(\@_);
    $self->finish;
}

package main;
use AE;
use Plack::Builder;
use Tatsumaki::Application;
use Twiggy::Server;
use AnyEvent::Twitter::Stream;

my $app = Tatsumaki::Application->new([ '/poll' => 'PollHandler' ]);

my $mapp = builder {
    # enable etc...
    $app;
};

my $server = Twiggy::Server->new(
    host => 'example.com',
    port => 5000,
)->register_service($mapp);

my $STREAM_CONN; # we need $STREAM_CONN to keep the availability of stream connection
my $LISTENER;    # we have to declare $LISTENER here, because variables in the timer callback scope are not visible from here

my $w; $w = AE::timer 1, 10, sub {
    return if $STREAM_CONN;

    my $oauth = { ... };

    say "ALERT: wake up";
    $LISTENER = AnyEvent::Twitter::Stream->new(
        %$oauth,
        method     => 'userstream',
        on_error   => sub { $STREAM_CONN = 0; },
        on_eof     => sub { $STREAM_CONN = 0; },
        on_connect => sub { $STREAM_CONN = 1; },
        on_tweet   => sub {
            my $tweet = shift;

            my $mq = Tatsumaki::MessageQueue->instance('tweet');
            $mq->publish({ type => 'tweet', tweet => $tweet });
            $STREAM_CONN = 1;
        }
    );
};

AE::cv->recv;

補足

AnyEvent::HTTP の変更によって AE::T::Stream 0.20 は動かないが、 AE::T::Stream の DEVELOPER RELEASE (0.20_1) だと chunked encoding 周りが fix されているので上げるべし


git submodule を使わないで vim プラグインを管理する

dot-files を git で管理してるとついつい vim プラグインも submodule 使って管理してしまいたくなるんですが、 submodule を使わないほうが楽なんじゃないかなと思って dot-files の整理と一緒にこんなシェルスクリプトを書いてみた。

整理した dot-files はこちら https://github.com/punytan/dot-files

使い方など

  • .gitignore に vim/buldle/* を追加して、bundle以下は管理しないようにする
  • 追加したいプラグインのリポジトリを install 部分に追加する
  • bundleディレクトリは各自の環境に合わせて書き換えて
  • プラグインのアップデートは upgrade を引数に実行するとまとめて git pull してくれる
  • pathogen.vim 使ってください(って書けって言われた。常識ですけど!)
build-env/05_vimbundle.sh
#!/usr/bin/env bash

if [ ! -d "$HOME/dot-files/vim/bundle" ]; then
    mkdir -p "$HOME/dot-files/vim/bundle";
fi

cd "$HOME/dot-files/vim/bundle";

case $1 in
    'install')
        git clone git://github.com/thinca/vim-guicolorscheme.git;
        git clone git://github.com/Shougo/neocomplcache.git;
        git clone git://github.com/thinca/vim-quickrun.git;
        git clone git://github.com/Shougo/unite.vim.git;
        git clone git://github.com/thinca/vim-ref.git;
        ;;
    'upgrade')
        dirlista=`find . -maxdepth 1 -type d -print`;
        for d in $dirlista; do
            if [ "$d" != "." ]; then
                cd "$d";
                echo $d;
                git pull;
                cd '..';
            fi
        done;
        ;;
    *)
        cat << EOM
Usage:
    $0 install

    $0 upgrade

EOM
        ;;
esac

daemontools メモ

daemontools はめったに設定しないので毎回忘れる!とくにmultilogとか編集中にはダウンさせておくとか。一連の流れをまとめたメモ。

インストール

$ sudo apt-get install daemontools-run
$ cd
$ mkdir daemontools

foo ディレクトリをつくり、スティッキービットをたてる

$ cd ~/daemontools
$ mkdir foo
$ mkdir foo/log
$ chmod +t foo

シンボリックリンクを /etc/service 以下につくる

自動で supervise が起動するのでダウンさせておく

$ cd /etc/service
$ sudo ln -s /home/hoge/daemontools/foo foo
$ sudo svc -d /etc/service/foo
$ sudo svc -d /etc/service/foo/log

runを作成

$ cd ~/daemontools/foo
$ vim run
export PATH=/path/to/library
cd /home/hoge/app/foo && exec setuidgid hoge executable-file

log/runを作成

$ vim log/run
exec setuidgid hoge multilog t ./main

作成したrunファイルに実行パーミッションを付与

ログを書き込むためにlogディレクトリの所有ユーザを指定する

$ chmod +x run log/run
$ chown hoge log

先ほどダウンさせたサービスを開始する

$ sudo svc -u /etc/service/foo/log
$ sudo svc -u /etc/service/foo
$ sudo svstat /etc/service/foo
$ sudo svstat /etc/service/foo/log

を実行して up の秒数が増えていれば正常に起動している。10 seconds 以上にならないときは異常終了しているので環境変数やパスが間違っていないか確認する。


SSHだけでリモートサーバからローカルMacにGrowl通知したい!

Growlしたい!というときは次のようにやってます。

概要

  • リモートで growl 専用のログファイルを準備する。
  • ローカルからリモートに ssh で接続し、tail -f でログファイルの監視する。
  • リモート側では、そのログファイルに対して Growl させたい内容をリダイレクトを使って追記する
  • 追記された内容が出力されるので、その出力をローカルのLLで行ごとに読み込む。
  • 読み込んだ行を growlnotify を起動して通知する

これだけ。growlnotify が必要なので Growl のディスクイメージの Extras フォルダから事前にインストールしておく。

手順

ステップ1 - リモートで

$ echo 'foo' > $HOME/growler.log 

このように、ログファイル(通知させたい内容を追記するファイル)を作成しておく。

ステップ2 - ローカルで

$ ssh example@example.com tail -n 1 -f '$HOME/growler.log' | perl -e 'system "growlnotify", "-m",  $_ while (<STDIN>);'

この例では example.com に ssh でログインし、ログファイルを tail -f で監視する。標準出力が pipe によって perl に流れるので、それを受信して growlnotify を起動する。これによってファイルの最終行が growl され、接続できているか確認できる。

ステップ3 - リモートで

$ echo 'hoge' >> $HOME/growler.log
$ ls >> $HOME/growler.log

このように標準出力をログファイルに追記するだけでgrowl通知ができる!

応用

とても時間のかかる処理をさせている間に別の処理をしたい場合

cpan-outdated -p | cpanm; echo 'upgraded' >> $HOME/growler.log

としておくと、処理が終わったときに通知してくれます。

ログファイルを吐き出すIRCクライアント(この場合は weechat )をリモートの screen 上で実行している場合

ssh example@example.com tail -n 1 -f '$HOME/.weechat/logs/*/*/*.weechatlog' | perl irc_growl.pl &

としてサーバにつなげて irc_growl.pl で処理を加えた上で growl させることもできる。irc_growl.pl では、--appIcon に LimeChat を指定することで Growl 時のアイコンを変更している。

ssh のコマンドが長いと感じたら、.bashrc に alias を設定しておくと良い。参考に irc_growl.pl を貼りつけておく。

irc_growl.pl

while (<STDIN>) {
    chomp;
    next unless $_;
    next if /^==>/; # ignore tail's output

    my $attr = parse($_);
    if ($attr->{type} =~ /(:?NOTICE|PRIVMSG)/) {
        system("growlnotify", "-m", $attr->{content}, "-t", $attr->{user}, "--appIcon", "LimeChat");
    }
}

sub parse {
    my ($line) = @_;

    my ($time, $cmd, @contents) = split /\t/, $line;
    my $content = join "\t", @contents;

    my $user;
    if (not $cmd) {           # critical error
        $cmd = 'ERROR';
    } elsif ($cmd eq '-->') { # join
        $cmd = 'JOIN';
    } elsif ($cmd eq '<--') { # part
        $cmd = 'PART';
    } elsif ($cmd eq '--') {  # messages from server
        $cmd = 'SERVER';
    } elsif ($cmd eq '*') {   # notice
        $user = $cmd;
        $cmd = 'NOTICE';
    } else {                  # privmsg
        $user = $cmd;
        $cmd = 'PRIVMSG';
    }

    return +{
        type    => $cmd,
        time    => $time,
        content => $content,
        user    => $user,
    };
}

やっぱりTCPでネットワーク通知したい場合

これで困ってないので調べていない。

sugyanさんが週末を犠牲にしてまで調べているのでしばしお待ちを!!


pjax こそが pushState + Ajax の本命

pjaxの前にpushStateとは

AjaxとjQueryの説明は不要として、pushStateとはなんぞや。

pushStateを使ってブラウザの履歴に対する操作をし、HTMLの一部のみを書き換える動作でもブラウザの戻る/進む機能を実現できる方法のひとつ。Ajaxなページを再現し、かつURLを見慣れた方法で自然にpermalinkを表現できる。有名なところではGitHubで使われてるアレ。

hash fragment (/#!/)

ブラウザの履歴を機能させるため、URL の fragment (#) を使ってAjaxなページを実現する方法。一時期もてはやされた感があるが、 http://d.hatena.ne.jp/karasuyamatengu/20110212/1297465199 など合理的な反論があり、これから導入するのはためらわれるところ。

有名なところではTwitterで使われているあの厄介者。

pjaxとは

pjax とは pushState + ajax を合わせた語で、その名のとおり pushState を使いつつ Ajax な処理を行う為の jQuery ライブラリ。 GitHub の defunkt が開発していることもあり、今後 pushState を使ったものでは導入が進んでいく可能性がかなり高いのではないかと読んでいる。

また、最近ではページの見た目の面では非クロスブラウザを許容する風潮があるように見受けられ、この流れともpjaxは親和性が高い。

「高機能なWebブラウザでは見栄えよく、そうでないWebブラウザで“も”それなりに」

http://itpro.nikkeibp.co.jp/article/Watcher/20110329/358885/

pjax の振る舞いは、 Chrome のようなブラウザでは pushState を使い、 IE のようなブラウザでは通常のアクセスと同じように、全く同じ permalink でアクセスできるようにしてくれる。

「コンテンツがcurlでロードできなければそのサイトは壊れている勢力」の救世主

私もこの勢力のうちのひとりだと内心思っているのでやや傾倒している感はある。

しかし hash fragment を使用したページは curl では取得できない。これはサーバ側に fragment 以降は送信されないためであるが、 public なものに curl や LWP::UserAgent や Google のクローラーといったクライアントでアクセスさせるために URL に細工することは解せない。かと言って自分でゴリゴリと pushState の実装を書くのも骨が折れる。そういった問題を解決してくれるものになると思われる。

使い方

ここではざっくりとした使い方を書いておく。

細かい使い方はいろいろあるようなので、GitHubにあるREADMEを参照すると良い。https://github.com/defunkt/jquery-pjax

クライアントサイド

"js-pjax" クラスのアンカーに対してのみ機能させる場合はこのようにセレクタを書く。

<script src="/jquery.min.js"></script>
<script src="/jquery.pjax.js"></script>
<script type="text/javascript">
  $(function () {
    $('a.js-pjax').pjax('#main');
  })
</script>
サーバサイド

pjax を使ったリクエストの場合に、 HTTP ヘッダに X-PJAX: true が付くのでサーバサイドではヘッダを見て返すbodyを変更する。

もし、 X-PJAX がない場合はすべてをレンダリングした HTML を返し、X-PJAX が true の場合には対象のコンテナにロードさせるのに適切な response body を返すよう処理を書く。X-PJAX のリクエストの場合でタイトルを変更したい場合は、<title>タグも含めて応答する。

実装

サーバをPerlで実装したので

$ cd /tmp
$ curl https://gist.github.com/raw/901139/c13279a29cfcca8cc75e63fb9eeb65b3ca2785c7/app.psgi -LO 
$ plackup

で起動し、リクエスト/レスポンスをチェックできる。

app.psgi
use strict;
use warnings;
use feature qw/say switch/;
use Data::Section::Simple;
use Text::Xslate;
use Plack::Request;

my $tx = Text::Xslate->new(
    path => [ Data::Section::Simple->new->get_data_section ],
);

my $app = sub {
    my $req = Plack::Request->new(shift);
    my %data = ( %ENV,
        TIME => scalar localtime,
        PJAX => ($req->header('X-PJAX') ? 1 : 0)
    );

    say "----- X-PJAX is " . ($data{PJAX} ? 'TRUE' : 'FALSE');
    my $type =  $data{PJAX} ? 'pjax' : 'default';

    my $res = $req->new_response(200);
    $res->content_type('text/html; charset=utf-8');

    given ($req->path_info) {
        when ('/') {
            $data{title} = "root";
            $res->body( $tx->render("root-$type.tx", {data => \%data}) );
        }
        when ('/home') {
            $data{title} = "/home";
            $res->body( $tx->render("home-$type.tx", {data => \%data}) );
        }
        when ('/help') {
            $data{title} = "/help";
            $res->body( $tx->render("help-$type.tx", {data => \%data}) );
        }
        when ('/favicon.ico') {
            $res->redirect("http://www.google.com/favicon.ico", 301);
        }

        default {
            $res->status(404);
            $res->body('Not Found');
        }
    }

    return $res->finalize;
};

$app;

__DATA__

@@ home-pjax.tx
    <: if $data.PJAX { :> <title><: $data.title :></title> <: } :>
    <p> Hello, <: $data.USER :> </p>
@@ home-default.tx
    : cascade base;
    : override main -> { include "home-pjax.tx" }
    : override title -> { "/home" }

@@ help-pjax.tx
    <: if $data.PJAX { :> <title><: $data.title :></title> <: } :>
    <pre> <: $data | dump :> </pre>
@@ help-default.tx
    : cascade base;
    : override main -> { include "help-pjax.tx" }
    : override title -> { "/help" }

@@ root-pjax.tx
    <: if $data.PJAX { :> <title><: $data.title :></title> <: } :>
    <p> pjax!! pjax!! pjax!!</p>
@@ root-default.tx
    : cascade base;
    : override main -> { include "root-pjax.tx" }
    : override title -> { "root" }

@@ base.tx
    <!DOCTYPE html>
    <html>
        <head>
            <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
            <script src="http://pjax.heroku.com/jquery.pjax.js"></script>
            <meta charset='utf-8'> 
            <title> <: block title -> { :> hello pjax <: } :> </title>
            <script type="text/javascript">
                $(function () {
                    $('a.js-pjax').pjax('#main');
                })
            </script>
        </head>
        <body>
            : include "nav.tx"
            <div>
            : $data.TIME
            </div>
            <div id="main">
                : block main -> { }
            </div>
        </body>
    </html>

@@ nav.tx
    <ul id="nav">
        <li><a href="/" class="js-pjax">Index</a></li>
        <li><a href="/home" class="js-pjax">Home</a></li>
        <li><a href="/help" class="js-pjax">Help</a></li>
    </ul>
サンプルについて

pjax リクエストを飛ばす方法、レスポンスをどう返せば意図したとおりに動くか、レスポンスを受けてタイトルを変更する方法など、手っ取り早く知りたいであろう事柄を埋めこんであるので、多少は参考になると思う。

curl で gist から取ってくる方法が一番楽だと思う。

結論

簡単に pushState による履歴操作と hash fragment (裏側のURLは汚い)に勝る綺麗な URL を実現できるので流行るといいな。


Perl CPANモジュールガイド

CPAN本の出版おめでとうございます&献本頂きありがとうございます。拙作 (AnyEvent::Twitter 0.52 と AnyEvent::Twitter::Strem のパッチ紹介) も収録されています。

Perl CPANモジュールガイド

紹介と感想

CPANモジュールを32のジャンル(ユーティリティ/データ/クラス/日付/アルゴリズム等々)に分け、目的のモジュールと使い方を説明する形式で、まさに書名の通り「CPAN モジュールガイド」と呼ぶにふさわしい本といえるのではないでしょうか。また、400ページ超のこの分量を書くのは相当な苦労だったのだろうと想像できるほどの力作となっています。

多くのPerl入門書ではCPANの記述は最終章近くで存在に触れている程度でしかなく、どれを使えば良いのかわからない状態で先に進めない人が多いのではないかと思いますが、本書はそういった問題を解決するひとつの手段になりうるのではないかと思います。

また、自分の知らないモジュールがたくさんあることを思い知らされました。さらに、モジュール紹介の中にあるtips (例えば、use constant した定数にコンパイルタイムで最適化が入ること等々) はPerlを使う上で知っておいたほうが良いものが多いです。

モジュールガイドなのにAcme::のnamespaceがないのはうわなにをするやめくぁwせdrftgyふじkl;

ということで、Perl CPANモジュールガイド おすすめです。


TEPCO 電気需要 JSON API 作った

http://linknode.net/tepco.html

Access-Control-Allow-Origin: * 

をヘッダーに含めているので、Same Origin Policyを気にせず、サイトをまたがってリクエストを飛ばしてJSONを取ってくることができます。

使用例

次のようなもので簡単に表を出力することができます。

    <script> 
        $(function () {
            $.ajax({
                url : 'http://api.linknode.net/tepco/v2/demand.json',
                dataType : 'json',
                success  : function (data) {
                    //console.log(data.raw);
                    //console.log(data);
                    $('#raw').append(data.raw);
 
                    $('#last_updated').append(data.last_updated.date + ' ' + data.last_updated.time);
 
                    for (var i in data.demand) {
                        $('#target > tbody').append(
                            $('<tr>').append(
                                $('<td>').append(data.demand[i].date + ' ' + data.demand[i].time),
                                $('<td>').append(data.demand[i].today),
                                $('<td>').append(data.demand[i].yesterday)));
                    }
                }
            });
        });
    </script> 

掲載等

こちらで紹介していただきました。

http://itpro.nikkeibp.co.jp/article/NEWS/20110325/358756/

http://togetter.com/li/115564

利用例

http://blog.livedoor.jp/petykin/archives/1411749.html

http://jsdo.it/sugyan/TEPCO


« 5 »