進・日進月歩

IT, Jazz, study, engineering, すべての真実とクリエイティビティのために

git diff を VimDiff で見よう

  • Filed under: 雑記
Wednesday
Feb 24,2010

git-vim

最近、自分ががしがしコミットしていたソースツリーを他人と共有する必要があり、人がどういう変更をしていたのかを確認する必要が出てきました。
コンフリクトを避けるのはもちろんですが、互いの空気をソースから読み取るというのは重要です。

要は git diff を見ればいいんですが、git diff はぱっとみよくわかりませんね・・・・

git-diff

世の中にはスーパーハカーがいたりするのでこれでいいのかもしれませんが、超一般ピープルである私にはちょっときついです。そこでGitVimDiffです。

motemen さんの git.vim をベースにさせていただきました。これはmoteます・・・・!

スクリプトを.vim/pluginsにコピーしてvimを起動します。
そこでいきなり:GitVimDiffと入れてみます。するとHEADからの差分が表示されます。

さて、今回の目的は他人のコミットとの差分を表示することです。git logでハッシュ値を確認してそれとworking ソースの差分を表示してみましょう。
例えば、 :GitVimDiff cb110a2a9c1532b8737ed37953aeaaa48436351c とか入れてみます。すると、このコミットの時のソースコードとの差分が出ます。これが冒頭のスクリーンショットです。

git diffよりも大分見やすくなりましたね!すばらしい。

vimscript歴2時間で作成したコードなのでまだまだ改善の余地はあるのではないかと思いますが、突っ込み改善歓迎です。

Friday
Feb 12,2010

最近コンセプトとかビジョンとか言ってる人がたくさんいます。
正直、何を言っているのかがさっぱりわからない人が多かったため、今まで完全にスルー対象でした。
しかし、最近のcookpadやpixiv,mixi,gree,DeNAを見たり戦略コンサルに就活するにあたり色々勉強している流れで、ほんのり理解できた気がしたので書き散らかしてみようかと思いました。

コンセプトの代表格と言えば自分の中では高須賀さんです。
詳細な理屈はあまり腑に落ちていないので覚えていないのですが、常々コンセプトの重要性について説いて回っており、新しいコンセプトに出会いたいと真剣に思っているようです。

一方でビジョンの代表格はMITメディアラボで石井教授のNIIでの講演の言葉を今でも覚えています。

technologyは一年で古くなる。
needsは10年で古くなる。
しかしビジョンは100年続かせることができる。

すごく抽象的で概念的な言い方をすれば、よく学生が言うような「本質」だとか「軸」だとかそういうものであるような気がします。(これに関してまた色々と言いたい事は無いことも無いのですが、また暇な時に・・・・)

自分もwebサービス作りに絡んで4,5年経つのでぼんやりとその重要性に関しては認識していました。
実に色んな種類のサイトやらシステムやらを作りましたが、明確に流行るものと流行らないものには差があった様に思います。
簡単に言えば、見ればすぐに誰が使うかわかるものと、一体誰が使うのかが謎なものです。
もちろん謎だけど流行ってるものというのもありますが(自分は絵をかかないのでなぜpixivが流行ってるかは理解しがたい)、ユーザ的には何らかの共通点を見いだすことができそうだなと漠然と感じています。
きっとこれがコンセプトやビジョンに当たるのではないだろうかと思います。

さて、コンセプトやビジョンというものはwebサービスにおいて重要なんでしょうか?おそらく答えはyesです。

webサービスとは読んで字のごとく「webを通じてなんらかのサービスを提供」するものです。
pixivならイラストを見たり描いたり。mixiなら友達との交流。ECサイトなら買物。そいういう感じです。
色々なサービスについて色んなことが言えるのですが、今回は議論をわかりやすくするために特にSNSについて取り上げたいと思います。

SNSは、少なくとも日本に関して言えばmixi・gree(前期)に始まり、OpenPNE系などのSNS乱立時代を経て、メジャーなところではモバゲー・gree(後期)・pixiv等にいたっています。
モバゲーもgree(後期)もpixivもSNSなのかと疑問を持たれる方もいると思いますが、それはもっともですし、しかもそこがキーポイントです。

SNSは、先発組と後発組で明確に戦略が変わっています。
皆様ご存知の通り先発組の代表格はmixiとgree(前期)です。
この両者の争いに関しては他に譲りますが、基本的にはどちらがデファクトになるかという争いでした。
機能やデザイン面での多少の差異はありますが、どちらも日記・コミュニティ・足跡など非常に似た機能を持ち合わせており利用目的も非常に似ていました。
どちらが先にデファクトになるのか。デファクトになりインフラとして機能するようになるか。これがとにかく重要でした。

一方で後発組をみてみると、pixiv, gree(後期),モバゲーなどがあります。
これらはSNSという体裁がある一方で、ゲームやイラストといった特定のコンセプトを明確に打ち出しその地位を不動のものとしつつあります。
pixivといえばイラスト、gree・モバゲーといえばゲームという形です。
(携帯ゲームは携帯固有の大人の事情があるためgreeとモバゲーはデファクト争い以外の色々な要素がありそうです)
非モテSNSやゲイSNSなどOpenPNEをベースとしたSNSのうちある程度流行ったものもコンセプトを明確にしているものと言えます。
個々でのポイントは、後発組はコンセプトを明確にしているという点です。

これらの事例からわかる通り、先発組は汎用的な用途でマスをとりデファクトをとる戦略、後発組はコンセプトを打ち出し特定の用途に特化する戦略が有効であることがわかると思います。

実は、この傾向は動画サイトにもある程度言えます。代表的な例としてyoutubeとニコニコ動画を考えてみましょう。
youtubeは動画配信サイトとして不動の地位を築いている先発組です。youtube動画の埋め込み機能を使い(違法動画ではありますが)PVのまとめサイトやネタ動画サイトのインフラとして使われるようになっています。
一方で後発組であるニコニコ動画は、ご存知の通り初期段階ではyoutubeをインフラとして利用しており、その上にコメントでのコミュニケーションというコンセプトを上乗せして成功しました。

他にもフリーメールにおけるgmail(大容量化)、検索におけるgoogle(膨大な対象ページ)など多くがこうした後発組は「あるコンセプト」に従っているという例に当てはまります。

コンセプトはwebサービスにおいてなぜこうまでに重要なのでしょうか?
それはユーザがそのwebサービスにたどり着くためにはコンセプトが必要だからです。

例えばレシピを探そうと思ったとしましょう。図書館に行く、googleで探す、NHKを見るなど色んな方法が考えられます。
こうした様々な方法の中からあえてcookpadにアクセスする理由とは何でしょうか?
検索エンジンからたどり着くということもあるでしょうが、そうでなければ、「cookpadはレシピサイト」というコンセプトのサービスであるからです。
webサービスにたどり着くためには、現実の行為に対応されたコンセプトが必要なのです。

そしてそのコンセプトの中でナンバーワンであることがさらに重要です。

レシピと聞いてどのwebサービスを思い出すでしょうか?居酒屋なら?クーポンなら?多くの人が同じようなwebサービスを思い浮かべることでしょう。
しかしそれ以外のサイトについていくつあげることができますか?ググっちゃダメですよ。
たいていどんなサイトに関してもググってみれば似たようなサイトを見つけることができますが、最初に思い浮かぶサイトは大抵の人が同じモノです。
この立ち位置を築くことがwebサービスにはとても重要です。

これらを一言でまとめてしまうと、「適当な大きさのニッチでナンバーワンになればおk」なんですが、このことは本当に多くのwebサービスに当てはまっているということがわかります。

さて、コンセプトとビジョンの重要性についてはある程度ご納得いただけたでしょうか。
当たり前すぎることを連ねた感じはありますが、webサービスで起業したいという人でもこの「コンセプト」や「ニッチNo1」の重要性をあまり感じていないように思います。

長文となりましたが、webサービスにおいてビジョンやコンセプトというものがいかに重要であるかということが少しでも感じ取れていただけたら幸いです。

ここからは蛇足。

学生しつつプログラミングを通して、ある程度の分析を加えつつ、時々気分でアドバイスしたりして来てるんですが、戦略コンサルを就職希望しているのはこういう話が好きだというのが一番です。
全体から傾向をつかむとか、なにかの本質的な原因を探るとか好きなんですね。好きだからこんな長文がかけます(ぉ

平均よりはITのことしってますしきっと経験もあるんだろうと思いますが、元はと言えば会社とか経営とか絡んでみたいと思って全て始まってますし、それだけのモチベーションで(学生でかわいがってもらってた可能性はあるにしても)個人名で仕事もらえる程度にはなりました。

戦略と技術のどちらの方が貢献できるのかと聞かれると非常に答えずらいのですが、世間の人から技術的な点を聞かれることが多い一方で、私は戦略的な穴の方が気になって気になってしょうがないと思っていたりもします。
技術的にgoogleにはいれるほどなのかと聞かれるとかなり微妙ですが、それなりになんとかしますしなぜかいつもそこの人員が足りていないので実務上そっちに回ることが多いのですが、ここらで1回技術屋さんやめて戦略を専業でやってみたいものだなぁというふうに思っています。

この文章はとりあえず過去の事例をいくつか上げてみた程度なので、あまり戦略的な分析ではないですが、なんか適当な目的を考えていつか書いてみたいなぁと思います。

蛇足でした。こういうのは就職活動始める前にやるべきだな。

※コンセプト重要ですが、トライアンドエラーを認めてないわけじゃないです

rubygemsのtwitterを拡張

  • Filed under: 雑記
Monday
Feb 8,2010

rubyからtwitterを便利に使うgemにtwitterというのがあります。
デフォルトだとand検索しか出来ないのですがor検索したいですね。
と、いうだけの簡単な拡張を書きました。

CODE:
  1. #extend_twitter.rb
  2.  
  3. module Twitter
  4.     class Search
  5.         def ors(query)
  6.             @query[:ors] = "#{query}"
  7.             self
  8.         end
  9.     end
  10. end

こうやってつかうと、twitterとついったーのor検索が出来ます。単純だけど便利。

CODE:
  1. root_dir = File.dirname(File.expand_path(__FILE__))
  2. require "rubygems"
  3. require "twitter"
  4. require "#{root_dir}/extend_twitter.rb"
  5.  
  6. tweets = Twitter::Search.new.ors("twitter ついったー").since(nil).per_page(100)
  7. tweets.each do |tweet|
  8.     puts "#{tweet["from_user"]}:\t#{tweet["id"]}\t#{tweet["text"]}"
  9. end

rubyの拡張性は異常。

twitterをキーワードを通してみる

  • Filed under: 雑記
Saturday
Jan 23,2010

twitter_streaming

twitter streaming apiというのをご存知ですか? twitterをリアルタイムに見るためのAPIです。
このAPIにはキーワードを使って、自分の好きな情報だけをリアルタイムに取得するためのfilterという機能があります。
これを使ってコードを出力し、表示したのが上の画像です。
「ruby」「pixiv」「pixpedia」「hrjn」「harajune」というキーワードでtwitterをリアルタイムに監視しています。

色々試したのですが、どうも日本語はうまくtokenizeできていないらしくうまく表示できません。
ただ、アルファベットの単語はうまくいくようで、ほぼ100%見つけ出すことができます。

この仕組のいいところはいくつかあります。

  • 本当に最先端の情報を得ることができる
  • followしてない人の発言でも見ることができる

「リアルタイム性」が協調されるtwitterですが、所詮自分がfollowしている範囲を監視していたところで、最新の結果なんか得られません。
本当に最新の情報を得たいと思うなら、twitter全体を監視すればいい!
簡単ですね(ぉ
なのでやってみました(ぉぉぉ

twitterは人物ベースの情報共有を行うものですが、このtwitter streaming apiを使えば話題ベースで情報を得ることができます。
どんな小さな、どこの誰が言ったものであろうと、twitter上で発言さえされていればそれを取得することができます。

もちろん欠点もあります。例えば「iPhone」で探すと情報が大量すぎてものすごいスピードで流れて行ってしまいます。
さすがにこれを人力で監視するのは無理なので、何らかの方法で話題を分類する必要があるでしょう。

仕組み

あまり詳細には書きませんが。

情報収集には、このブログのスクリプトをほぼそのまま流用させてもらいました。
これを、ターミナルで起動します。例えばこんな感じ。

ruby twitter_stream.rb >> twitter_stream.log

こうしてtwitterから特定のキーワードだけをリアルタイムに取得します。
そして表示部分はgeektoolを使います。
geektoolはコマンドの実行結果をデスクトップに表示するためのツールです。
geektoolをつかいこの検索結果をデスクトップに表示します。
例えばこんな感じ。

tail -n 5 twitter_stream.log

すると、この記事の冒頭のような感じになります。

簡単ですね。

geektoolの使い方等を覚えたりしたので多少時間がかかりましたが、全体で一時間少々でこれを作れました。
本当に簡単ですね!!素晴らしい時代だ。

では、みなさん。楽しいtwitterライフを!

Thursday
Dec 31,2009

今年はさりとて目立つことはしていないのですが、色々とITや技術に関しては思うことがありました。

2009年を総括すると「コンテンツ」の年であったように思います。
それの筆頭がmixiアプリやfacebookアプリを始めとしたソーシャルゲームであったように思います。
色々と細かいこと言えるんですが、正直私の興味の対象外なのであまり言及しません。
こういってしまうと、正直今年ほどIT的につまらなかった年はないなーと思ったりもします(ぉ

今年感じた感想意見を書いてみたいと思います。

  • だんだんと難しいITに注目が集まってきた(機械学習とか並列計算とか
  • テーマのはっきりしたサイトがウケル
  • 毎年いってるけど、やっぱりどんどんプログラムかける人は増えている

また、関連して、来年はこうなるだろうなということを書いてみます。

  • ソーシャルを超えた 1 to 1
  • プログラマはメタプログラマへ

だんだんと難しいITへ

難しいというと語弊がありますが、単純に言うと「その分野の知見やノウハウ」が試される時代へと変わってきました。
わかりやすく具体的に言うと「mapreduce(Hadoop)」や「機械学習」などがそれに当たるでしょうか。
ここ数年こういった事をテーマとした勉強会や読書会が多かったように思います。

今までも大規模サイトを扱う上でのノウハウなどは普通にあったわけですが、より数学やアルゴリズムに対して焦点が当たるようになったと思います。
こうした、map reduceや機械学習といったものは、教科書通りに実装すれば確かにうごくものです。
しかし、必ずしも望んだ結果がでるとは限りません。精度が悪かったり計算に時間がかかりすぎたりすることもあります。
このとき個別の事情に合わせてチューニングするテクニックがあります。
こうしたチューニングテクニックやノウハウを持ってる人材が今年求められ始めたような気がします。

テーマのはっきりしたサイトがウケル

具体的に言えば cookpad や pixiv などでしょうか。
「cookpadにいけばレシピが見つかる」「pixivにいけばイラストが見れる」こういうブランディングが大変効果的であることがはっきりと見えてきました。

これに気づいたのは、彼女にあげたPCの使い方を見ていたときです。
彼女は、「今日は餃子が食べたい」といってPCを開き食べログを見ます。「鍋にしよう」といってPCを開きcookpadを見ます。
彼女にとっては、PCは本や辞書と一緒なのです。使わないときは棚にしまっておいて、「鍋のレシピをみたいなー」と思ってPCを開くわけです。

携帯ゲームのメインターゲットであるような中高生は24時間携帯触っているかもしれないですし、私みたいなプログラミングばかりしてるような人種は24時間PCの前にいるでしょうが、ほとんど大多数の人はそんな状況にはありません。
想像に固くはないと思いますが、ずっとtwitterが垂れ流されてたりとか、skypeやメッセでガンガン連絡がくるような生活をしている人は大変稀です。
ほとんどのひとは、日中営業で外まわっていたり、買い物していたり、子供の送り迎えをしているわけです。
そんな人達がダラダラネットを見てるなんてことは基本的にはないでしょう。

結局そうした大多数の人達は、どうやってwebサイトを見るのか。
答えは至極当たり前で、「必要なときにPCを開き、必要なwebサイトを見る」です。
ネットニュースとかにも興味がない大多数の彼女ら / 彼らにとっては、テーマがはっきりしておりそれが必要とされることが重要なのです。

すごく当たり前なことなのですが、実際目の当たりにして目が覚めた気分でした。

毎年いってるけど、やっぱりどんどんプログラムかける人は増えている

某社でコードを書いているわけですが、インターン生が何組かきました。
PHPもSQLも書いたことがないという20歳にも満たない人たちが一週間でそれらを覚えて画像掲示板を作ったりしてました。
セキュリティとか、コードが汚いとか、細かいことはたくさん言えますが、立派に動いています。(それどころかハーディ君のセンスにはみんな驚愕

(別にプログラミングがそれほど難しいと感じたことはないのですが)正直プログラム書くだけならそんなものです。
正直いままでは、サーバが高いだとかPCが高いだとか本が高いだとかモテないだとか、そういう(中高生にはキツイ?)参入障壁が多少なりともあったわけですが、もうそんなのはありません。
やっぱりこれからは、どんどんプログラムかける人たちが増えていくんだなーと感じました。

今年のまとめ:

と、いう感じで、結局は毎年思ってることでもあるんですが、もう「プログラムが書ける」とかいう基準がすでにゴミ化してるんですよね。

むしろ、技術者としては「経験」「ノウハウ」が求められるようになっていっています。
またウェブのマーケティングとしては、いかにユーザの日常に入り込むかが求められています。じゃないとwebサイトなんて開いてもらえません。彼女ら / 彼らは、PCを開いてすらいないのですから。

というわけで、こっからはちょっとした予言?

ソーシャルを超えた 1 to 1

個人的な見解を言えば、webはもともとソーシャルでした。
パソコン通信なんてものも含めて考えれば、地域ごとのホストでオフ会するとかよくありましたし、掲示板作って身近なひとと連絡とるというのがデフォルトだったように思います。
(私も、KCLという茨城のパソコン通信のオフ会に小学校の頃いったり、高校の友達と掲示板とかやってました)
もともとあるコミュニティを前提としたソーシャルと言えるかもしれません。
時期的には前後しますが、mixiやgreeもどちらかというとこの種のサイトであるように思います。

yahoo / googleなどの検索エンジンの登場があって、はじめて1 to 1のつながりというものができました。
友達のウェブや紹介無しに、ダイレクトに必要な情報にアクセス出来るようになったのは、大変革命的なことでした。

それが、今またソーシャルに戻ってきました。
巨大掲示板を始めとして、OKWebや食べログやcookpadなど多くのサイトが生まれました。
これは、共通の話題やテーマを提供することで、知らない人同士でコミュニティを形成させるというソーシャルの形です。

そして、私は再び 1 to 1への革命が起きると考えています。
検索エンジンは、必要な情報へのダイレクトアクセスの方法を提供しました。CGM / UGMサイトはそのサイト内限定で知らない人へのダイレクトアクセスの方法を提供しました。
ひょっとしたら、特定のサイトに閉じずに、特定の知らない誰かにダイレクトでアクセスするような 1 to 1が次世代のあたらしいサービスになるのかもしれないと考えています。

プログラマはメタプログラマへ

すごく簡単に言うと、フレームワークを作るエンジニアという感じでしょうか。
先程「プログラミングなんて誰もでもできる」といったことへの答えのひとつがこれであるように思います。

Gaucheで有名な史郎さんがこの前講義で言っていた言葉でもあります。

プログラムは書くだけなら誰でもできますが、可読性や保守性を考えたコードを書くことはそれほど簡単ではありません。
これをLisperである史郎さんはマクロで拡張しまくってやるようですが、普通のphpやrubyでもこれは可能です。
適度な抽象化とカプセル化を行うことで、割と簡単にコードはすっきりします。

確かに、最初からすべての可能性を盛り込んで抽象化を行うことは困難です。が、ウェブサイトであればMVCの分離という程度の抽象化は誰でもやるべきだと思いますし、データアクセスの抽象化はどんなプログラミングであっても必須であるように思います。

よく、「綺麗なコードだからといっても意味がない」というはなしもよくききます。
綺麗であることに時間をかけるよりは、さっさと完成して動いた方が嬉しいという話ですね。
ただ、これは一人のスーパーエンジニアが全部どうにかするということを前提とした発想であり、早々に破綻します。

そのスーパーエンジニアがやめてしまったらどうするんですか?そのシステムの保守は?運用は?
そのエンジニアがインフルエンザにかかったら、サイトの更新を止めちゃうんでしょうか?
そういうわけにはいかないでしょう。

システムの規模が大きくなればなるほど、早々に他人にコードを見せたりいじったりしてもらわないといけない事態が発生します。
それにスーパーエンジニアには、スーパーなことをしていただかないとしょうがない(給料高いだろうし)ので、細かい修正はスーパーじゃない人にしてもらうというのが健全というものではないでしょうか。

これからのプログラマ / エンジニアは、コードを書くだけではなくプロジェクト全体を最適化することも考え、それをコードに反映することができる。
こういう能力が付加価値として必要なんではないでしょうかと思います。

まとめ:予言

人と人とをダイレクトに繋ぐ仕組みというのがあれば流行る気がする。

プログラマはメタプログラマになっていく

まとめ:全体

どうも今年は自分がボーッとしてたのもあるのでしょうが、あまりITサービスで面白いものはでなかったように思います。

sekai cameraやソーシャルゲームは大いに盛り上がってましたが、もともとジオタグ関連には否定的なのと、ゲームに興味がないのと、儲かってもなんかしれてそうというのでいまいちでした。
(yelpとかの話もされたことがあるのですが、yelpとその場に行かないとコメントが見れないseka cameraを単純に比較できるのはなぜなのか最期までよくわからなかった)

来年の目標というよりは、個人的な願望として、もっと全体のことを考えて最適化するようなことをしていきたいというのもありメタプログラマという話をしてみました。

また、ソーシャルは大いに結構だと思うのですが、インターネットの醍醐味は全く知らない何か/誰かを発掘出来ることであると思っている点から、知らない誰かへのダイレクトアクセスが今後なにか起こるのではないかなと言ってみました。

何はともあれ、来年は色々と面白そうな予感がいまちょっとしています。

駄文でしたが、読んでくれた人ありがとうございます m(_ _)m

Monday
Oct 12,2009

o(np)のdiffアルゴリズムを作りました。
元ネタはこの辺。
An O(NP) sequence comparison algorithm

なんで車輪の再発明したかというと、既存のライブラリだと挙動がわからない上に、使い勝手がいまいちだからです。
自分で全部書けば、自由自在(ぉ
とりあえずリファクタリングの余地は多々ある感じですが。

一般的な意味でのdiffと違うところと言えば、追加/削除のみしか考えておらず、「置換」がありません。
けど、アルゴリズム上「置換」に当たる場合は「追加→削除」または「削除→追加」のいずれかの順番でSESの中に現れるので、その場合を「置換」と処理すればよいかと思います。

使い方とかは暇があったら書く。

このあたりを参考にさせてもらいました。日本語の解説ではこれが一番わかりがよく正確だと思います。
diff(1)

CODE:
  1. <?php
  2. class DiffModel{
  3.     private $flip = false;
  4.     private $arr1 = null;
  5.     private $arr2 = null;
  6.     private $size1 = null;
  7.     private $size2 = null;
  8.     private $ses = null;
  9.  
  10.     private $patharr=null;
  11.     const SAME=0;
  12.     const ADD=1;
  13.     const DEL=2;
  14.  
  15.     public function __construct($article1="", $article2=""){
  16.         if(is_array($article1) and is_array($article2)){
  17.             $this->setArray($article1, $article2);
  18.         }else{
  19.             $this->setArticles($article1, $article2);
  20.         }
  21.     }
  22.  
  23.     public function setArticles($article1, $article2){
  24.         if(strlen($article1)> strlen($article2)){
  25.             $this->arr1 = empty($article1) ? array() : mb_str_split($article1);
  26.             $this->arr2 = empty($article2) ? array() : mb_str_split($article2);
  27.  
  28.             $this->size1 = count($this->arr1);
  29.             $this->size2 = count($this->arr2);
  30.             $this->flip = true;
  31.         }else{
  32.             $this->arr1 = empty($article2) ? array() : mb_str_split($article2);
  33.             $this->arr2 = empty($article1) ? array() : mb_str_split($article1);
  34.  
  35.             $this->size1 = count($this->arr1);
  36.             $this->size2 = count($this->arr2);
  37.             $this->flip = false;
  38.         }
  39.     }
  40.  
  41.     public function setArray($arr1, $arr2){
  42.         if(count($arr1)> count($arr2)){
  43.             $this->arr1 = $arr1;
  44.             $this->arr2 = $arr2;
  45.  
  46.             $this->size1 = count($this->arr1);
  47.             $this->size2 = count($this->arr2);
  48.             $this->flip = true;
  49.         }else{
  50.             $this->arr1 = $arr2;
  51.             $this->arr2 = $arr1;
  52.  
  53.             $this->size1 = count($this->arr1);
  54.             $this->size2 = count($this->arr2);
  55.             $this->flip = false;
  56.         }
  57.  
  58.     }
  59.  
  60.     public function diff(){
  61.  
  62.         $offset = $this->size2 + 1;
  63.  
  64.         $this->patharr = array();
  65.  
  66.         $fp = array_fill(0, $this->size1 + $this->size2 + 3, -1);
  67.         $delta = $this->size1 - $this->size2;
  68.  
  69.         $p=0;
  70.         for(; $fp[$delta + $offset] <$this->size1; $p++){
  71.             for($k = -$p; $k <$delta; $k++){
  72.                 $fp[$k + $offset] = $this->snake($k, $offset, $fp);
  73.             }
  74.  
  75.             for($k = $delta + $p; $k>= $delta; $k--){
  76.                 $fp[$k + $offset] = $this->snake($k, $offset, $fp);
  77.             }
  78.  
  79.         }
  80.  
  81.         return $delta + 2*($p - 1);
  82.     }
  83.  
  84.     public function getDiff(){
  85.         $ind = $this->size2 + $this->size1*($this->size2+1);
  86.         $item = array(-1, $this->size2, $this->size1);
  87.         $this->ses = array();
  88.         do{
  89.             switch($this->patharr[$ind][0]){
  90.             case (self::ADD):
  91.                 if($item[0] != $this->patharr[$ind][0]){
  92.                     $this->ses[] = array($this->flip ? self::ADD : self::DEL, $this->patharr[$ind][1], $item[1] - $this->patharr[$ind][1]);
  93.                 }else{
  94.                     $this->ses[count($this->ses)-1][1] = $this->patharr[$ind][1];
  95.                     $this->ses[count($this->ses)-1][2] += $item[1] - $this->patharr[$ind][1];
  96.                 }
  97.                 //echo sprintf("add %3d-%3d %s\n", $this->patharr[$ind][1], $item[1], mb_substr($this->article2, $this->patharr[$ind][1], $item[1] - $this->patharr[$ind][1], "utf-8"));
  98.                 break;
  99.             case (self::DEL):
  100.                 if($item[0] != $this->patharr[$ind][0]){
  101.                     $this->ses[] = array($this->flip ? self::DEL : self::ADD, $this->patharr[$ind][2], $item[2] - $this->patharr[$ind][2]);
  102.                 }else{
  103.                     $this->ses[count($this->ses)-1][1] = $this->patharr[$ind][2];
  104.                     $this->ses[count($this->ses)-1][2] += $item[2] - $this->patharr[$ind][2];
  105.                 }
  106.                 //echo sprintf("del %3d-%3d %s\n", $this->patharr[$ind][2], $item[2], mb_substr($this->article1, $this->patharr[$ind][2], $item[2] - $this->patharr[$ind][2], "utf-8"));
  107.                 break;
  108.             case (self::SAME):
  109.                 if($item[0] != $this->patharr[$ind][0]){
  110.                     $this->ses[] = array(self::SAME, $this->patharr[$ind][1], $item[1] - $this->patharr[$ind][1]);
  111.                 }else{
  112.                     $this->ses[count($this->ses)-1][1] = $this->patharr[$ind][1];
  113.                     $this->ses[count($this->ses)-1][2] += $item[1] - $this->patharr[$ind][1];
  114.                 }
  115.                 //echo sprintf("sam %3d-%3d %s\n", $this->patharr[$ind][1], $item[1], mb_substr($this->article2, $this->patharr[$ind][1], $item[1] - $this->patharr[$ind][1], "utf-8"));
  116.                 break;
  117.             }
  118.  
  119.             $item = $this->patharr[$ind];
  120.             $ind = $this->patharr[$ind][1] + $this->patharr[$ind][2]*($this->size2+1);
  121.  
  122.         }while($ind> 0);
  123.  
  124.         $this->ses = array_reverse($this->ses);
  125.         return $this->ses;
  126.  
  127.     }
  128.  
  129.     private function snake($k, $offset, &$fp){
  130.         $y=0;
  131.         if($fp[$k-1 + $offset] + 1> $fp[$k+1+$offset]){
  132.             $y = $fp[$k-1 + $offset] + 1;
  133.             //$this->patharr[($y-$k) + $y*($this->size2+1)] = array($y-$k,$y-1);
  134.             $this->patharr[($y-$k) + $y*($this->size2+1)] = array(self::DEL, $y-$k,$y-1);
  135.         }else{
  136.             $y = $fp[$k+1 + $offset];
  137.             $this->patharr[($y-$k) + $y*($this->size2+1)] = array(self::ADD, $y-$k-1, $y);
  138.         }
  139.  
  140.         $x = $y-$k;
  141.         $sx = $x;
  142.         $sy = $y;
  143.  
  144.         while($x <$this->size2 and $y <$this->size1 and $this->arr2[$x] == $this->arr1[$y]){
  145.             $x++;
  146.             $y++;
  147.         }
  148.  
  149.         if(!($x == $sx and $y == $sy) )$this->patharr[$x+$y*($this->size2+1)] = array(self::SAME, $sx,$sy);
  150.  
  151.         return $y;
  152.     }
  153.  
  154. }
  155. ?>

Wednesday
Oct 7,2009

JavaScriptで文字列型から整数型への変換速度比較
http://kur.jp/2009/10/06/stringtoint-by-javascript/
というのがあって、なんかコードを見てたらなんか思うところがあったので追試してみた。
結果から言うと、だいたい傾向は一緒だった。IE用の回避コードを入れてみて気づいたけど、実行順序によって速さが変わるかもしれない。(一度読み込んだ関数は二回目は若干速い?

CODE:
  1. <script type="text/javascript">
  2.     var randomnums = new Array(1000000);
  3.     for(i=0; i<1000000; i++){
  4.         randomnums[i] = String(Math.round(Math.random() * 100));
  5.     }
  6.  
  7. function warmup(){
  8.     for(i=0; i<1000000; i++){
  9.         randomnums[i];
  10.     }
  11. }
  12. function useSub(){
  13.     var startTime = new Date();
  14.     for(var i = 0; i <1000000;i++){
  15.         randomnums[i] - 0;
  16.     }
  17.     document.write(new Date() - startTime);
  18. }
  19. function useDiv(){
  20.     var startTime = new Date();
  21.  
  22.     for(var i = 0; i <1000000;i++){
  23.         randomnums[i] / 1;
  24.     }
  25.     document.write(new Date() - startTime);
  26. }
  27. function useparseInt(){
  28.     var startTime = new Date();
  29.  
  30.     for(var i = 0; i <1000000;i++){
  31.         parseInt(randomnums[i],10);
  32.     }
  33.     document.write(new Date() - startTime);
  34. }
  35. function useNumber(){
  36.     var startTime = new Date();
  37.  
  38.     for(var i = 0; i <1000000;i++){
  39.         Number(randomnums[i]);
  40.     }
  41.     document.write(new Date() - startTime);
  42. }
  43. //IEがおそすぎて変なalertを出すので1回分はダミー
  44. warmup();
  45. useSub();
  46. document.write("<br />");
  47. warmup();
  48. useSub();
  49. document.write("<br />");
  50. warmup();
  51. useDiv();
  52. document.write("<br />");
  53. warmup();
  54. useparseInt();
  55. document.write("<br />");
  56. warmup();
  57. useNumber();
  58. </script>

結果はこちら

firefox
6
6
6
119
274 

IE
801
781
851
2003
1553 

chrome
311
292
299
135
234
Friday
Sep 18,2009

screenには大変なじみがあるのではないかと思いますが、最近windowの縦分割(左右に分ける)をしたくなり、tscreenやscreenのパッチなど色々と考えた末に、tmuxにしてみました。

理由は特にない(^^;;んですが、使ってみた結果tmuxの方が若干見た目に奇麗であるように感じました。

現在最新版はバージョン0.9なのですが、ドキュメントがなくソースを読むしかない(?)ので、軽く使えるコマンドについて言及したいと思います。

とりあえずmacの人はmacportsにあるのでコマンド一発ではいります。

CODE:
  1. sudo port install tmux

そして、次は設定ファイルをおきましょう。screenでいうところの.screenrcは、.tmux.confというファイルになります。
私の設定ファイルはこちらをごらんください。
基本的にソースに付属しているscreen-keys.confをもとにしています。
このファイルを.tmux.confにリネームしてホームフォルダに置くだけで、screen風なキーバインドになります。

さて、screen-keys.confだけだとwindowを左右に分割することができないので、以下の設定を書き足してあります。
(他にも書いたんですが、ど忘れ・・・・)

CODE:
  1. #layout
  2. bind h select-layout even-horizontal
  3. bind v select-layout even-vertical
  4. bind f select-layout active-only

こうして、tmuxを立ち上げたあとC-a C-Sで画面を分割し、C-a C-hで分割を左右にすることができます。

さて問題はこの「select-layout even-horizontal」というコマンドをどこから見つけてくるかです。ドキュメントがないっぽいので、ソースを見ます。
ビビらなくても大丈夫。大変奇麗に作られてるのですぐに読めると思います。

ソースをここからダウンロードして展開してみてください。
そして、cmd-から始まるファイル名のファイルを探します。これが全部コマンドになっています。バージョン0.9だとこんな感じになっています。

CODE:
  1. % ls |grep "cmd-"
  2. cmd-attach-session.c
  3. cmd-bind-key.c
  4. cmd-break-pane.c
  5. cmd-choose-session.c
  6. cmd-choose-window.c
  7. cmd-clear-history.c
  8. cmd-clock-mode.c
  9. cmd-command-prompt.c
  10. cmd-confirm-before.c
  11. cmd-copy-buffer.c
  12. cmd-copy-mode.c
  13. cmd-delete-buffer.c
  14. cmd-detach-client.c
  15. cmd-down-pane.c
  16. cmd-find-window.c
  17. cmd-generic.c
  18. cmd-has-session.c
  19. cmd-kill-pane.c
  20. cmd-kill-server.c
  21. cmd-kill-session.c
  22. cmd-kill-window.c
  23. cmd-last-window.c
  24. cmd-link-window.c
  25. cmd-list-buffers.c
  26. cmd-list-clients.c
  27. cmd-list-commands.c
  28. cmd-list-keys.c
  29. cmd-list-sessions.c
  30. cmd-list-windows.c
  31. cmd-list.c
  32. cmd-load-buffer.c
  33. cmd-lock-server.c
  34. cmd-move-window.c
  35. cmd-new-session.c
  36. cmd-new-window.c
  37. cmd-next-layout.c
  38. cmd-next-window.c
  39. cmd-paste-buffer.c
  40. cmd-previous-layout.c
  41. cmd-previous-window.c
  42. cmd-refresh-client.c
  43. cmd-rename-session.c
  44. cmd-rename-window.c
  45. cmd-resize-pane.c
  46. cmd-respawn-window.c
  47. cmd-rotate-window.c
  48. cmd-save-buffer.c
  49. cmd-scroll-mode.c
  50. cmd-select-layout.c
  51. cmd-select-pane.c
  52. cmd-select-prompt.c
  53. cmd-select-window.c
  54. cmd-send-keys.c
  55. cmd-send-prefix.c
  56. cmd-server-info.c
  57. cmd-set-buffer.c
  58. cmd-set-option.c
  59. cmd-set-password.c
  60. cmd-set-window-option.c
  61. cmd-show-buffer.c
  62. cmd-show-options.c
  63. cmd-show-window-options.c
  64. cmd-source-file.c
  65. cmd-split-window.c
  66. cmd-start-server.c
  67. cmd-string.c
  68. cmd-suspend-client.c
  69. cmd-swap-pane.c
  70. cmd-swap-window.c
  71. cmd-switch-client.c
  72. cmd-unbind-key.c
  73. cmd-unlink-window.c
  74. cmd-up-pane.c

ここから「cmd-」を除いた部分がコマンド名です。機能はだいたいコマンド名見ればわかりますね。
各々のコマンドは引数を取ったりします。それを調べる時はソースを見ます。
たとえばさっきの「select-layout」であれば「cmd-select-layout.c」を見ます。すると、こんな感じのコードが見えるはずです。(一部抜粋)

CODE:
  1. const struct cmd_entry cmd_select_layout_entry = {
  2.     "select-layout", "selectl",
  3.     CMD_TARGET_WINDOW_USAGE " layout-name",
  4.     CMD_ARG1,
  5.     cmd_select_layout_init,
  6.     cmd_target_parse,
  7.     cmd_select_layout_exec,
  8.     cmd_target_send,
  9.     cmd_target_recv,
  10.     cmd_target_free,
  11.     cmd_target_print
  12. };

細かい説明ははしょりますが、というか理解してないのですが、ここからコマンド名が「select-layout」であり、エイリアスが「selectl」であることが読み取れます。
ちなみにこの書き方はxwindowの拡張であるglxの実装の一つであるcompizのプラグインもこういった書き方になっているので、見慣れておくといいような気もします。

次に、引数ですが次の部分に注目します。

CODE:
  1. void
  2. cmd_select_layout_init(struct cmd *self, int key)
  3. {
  4.     struct cmd_target_data  *data;
  5.  
  6.     cmd_target_init(self, key);
  7.     data = self->data;
  8.  
  9.     switch (key) {
  10.     case KEYC_ADDESC('0'):
  11.         data->arg = xstrdup("manual-vertical");
  12.         break;
  13.     case KEYC_ADDESC('1'):
  14.         data->arg = xstrdup("even-horizontal");
  15.         break;
  16.     case KEYC_ADDESC('2'):
  17.         data->arg = xstrdup("even-vertical");
  18.         break;
  19.     case KEYC_ADDESC('9'):
  20.         data->arg = xstrdup("active-only");
  21.         break;
  22.     }
  23. }

はい。ここで「even-vertical」とか出てきましたね。細かい説明はまたしてもはしょりますが、ここが引数でありそうな事はぱっと見でわかると思います。わかってください。
これをもとにさっきの設定を見てみましょう。

CODE:
  1. #layout
  2. bind h select-layout even-horizontal
  3. bind v select-layout even-vertical
  4. bind f select-layout active-only

今まで見てきた通りですね!

じつは、他のコマンドもだいたい似たような感じになっています。それぞれのコマンドは非常にコンパクトにわかりやすく書いてあるので山勘で何とかなるかと思います。

しかし、0.8系と0.9系でコマンドが変わったりしてるようなので、まだちょっと注意がいるかもしれません・・・・

というかんじで、みなさん楽しいtmuxライフをおくりましょう!

キーワード自動リンクの話

  • Filed under: 雑記
Tuesday
Sep 1,2009

キーワード自動リンクの話を某勉強会でしました。その資料を公開します。

自動リンクのためのデータ構造としてTrieを採用し、今回は有名な実装であるsenna, Tx, dartsの比較をしました。
それぞれのライブラリの背景は次の様なデータ構造です。

  • senna - パトリシア木
  • Tx - LOUDS
  • darts - Double Array

今回の実験はとりあえず実装しましたレベルなので、厳密な速度や容量にはなっていない可能生があります。
というのは、それぞれのライブラリを精査したわけではないからです。
またキーワード抽出した結果がそれぞれで若干異なっています。抽出できたキーワードの件数に大きなさや検索にかかる時間に相関が無さそうなので概ね正しいと考えることにしました。

というわけで、ご参考まで。

Monday
Aug 31,2009

Txでdartsのようなtraverseをする関数を作ってみました。

使い方はdartsのtraverseと同じだと思います。たまたま作ったのでパッチをそのまま貼っておきます。動作は未保証。dartsよりも爆速でふきました。

CODE:
  1. diff -cb tx-0.13/tx.cpp tx_original/tx.cpp
  2. *** tx-0.13/tx.cpp  2009-04-13 13:21:14.000000000 +0900
  3. --- tx_original/tx.cpp  2009-08-27 22:45:25.000000000 +0900
  4. ***************
  5. *** 195,200 ****
  6. --- 195,221 ----
  7.       return 0;
  8.     }
  9.    
  10. +   uint tx::traverse(const char* str, size_t& pos) const {
  11. +       uint curPos = 2;
  12. +       uint retId = NOTFOUND;
  13. +       size_t begin = pos;
  14. +       if (terminal.getSize() <= 2) return retId;
  15. +
  16. +       for (size_t i = 0 ; ; i++){
  17. +           const uint nodeId = loud.rank(curPos-1,1)-1;
  18. +           if (terminal.getBit(nodeId)){
  19. +               pos = begin + i;
  20. +               retId = terminal.rank(nodeId,1)-1;
  21. +           }
  22. +           uint nextPos = getChild(curPos,str[begin + i]);
  23. +           if (nextPos == UINT_MAX){
  24. +               break;
  25. +           }
  26. +           curPos = nextPos;
  27. +       }
  28. +       return retId;
  29. +   }
  30. +
  31.     uint tx::prefixSearch(const char* str, const size_t len, size_t& retLen) const {
  32.       uint curPos = 2;
  33.       uint retId = NOTFOUND;
  34. diff -cb tx-0.13/tx.hpp tx_original/tx.hpp
  35. *** tx-0.13/tx.hpp  2008-06-03 21:05:00.000000000 +0900
  36. --- tx_original/tx.hpp  2009-08-27 22:41:04.000000000 +0900
  37. ***************
  38. *** 26,31 ****
  39. --- 26,32 ----
  40.       int read(const char* fileName);
  41.  
  42.       uint prefixSearch(const char* str, const size_t len, size_t& retLen) const;
  43. +     uint traverse(const char* str, size_t& pos) const;
  44.       uint expandSearch(const char* str, const size_t len, std::vector<std::string>& ret, const uint limit = 0) const;
  45.       uint commonPrefixSearch(const char* str, const size_t len, std::vector<std::string>& ret, std::vector<uint>& retID,  const uint limit = TX_LIMIT_DEFAULT) const;
  46.       uint commonPrefixSearch(const char* str, const size_t len, std::vector<uint>& retLen, std::vector<uint>& retID,  const uint limit = TX_LIMIT_DEFAULT) const;
  47. ***************
  48. *** 42,48 ****
  49.      
  50.       static uint NOTFOUND;
  51.      
  52. !   private:
  53.       uint getChild(const uint pos, const char c) const;
  54.       uint getParent(const uint pos, char& c) const;
  55.       void enumerateAll(const uint pos, const std::string str, std::vector<std::pair<size_t, std::pair<std::string, uint>>>& ret) const;
  56. --- 43,49 ----
  57.      
  58.       static uint NOTFOUND;
  59.      
  60. ! //  private:
  61.       uint getChild(const uint pos, const char c) const;
  62.       uint getParent(const uint pos, char& c) const;
  63.       void enumerateAll(const uint pos, const std::string str, std::vector<std::pair<size_t, std::pair<std::string, uint>>>& ret) const;

about me

原田 惇

応用数学や統計、ITなどを利用していろんなことをしています。
自己紹介はこちら

adsense

amazonお勧め