2008/05/30

はてな
全然難しくない話
filtered feed for coderepos
CodeReposフィードにはcategoryにshare配下のパスが埋め込まれている様なので、これをマッチングに使ってるだけです。
"Search Text"には"lang/javascript"とか"lang/python"とか入力します。
これで"lang/javascript"以下だけ欲しい人とか、"lang/perl"以下だけ欲しい人とか、"poem"だけ欲しい人とかがウォッチしやすくなるのかな? ちなみに正規表現でやるまでもなかいかな...と思って単純マッチングにしてあります。正規表現がお好み人はcloneして変更して下さい。
Pipes: Filtered Feed for CodeRepos

はてな
以前、MOONGIFTさん所で見付けた「Growl for Windows」を試してみた。
Growl for Windows
Features currently supported:
  • Fully compatible with original Growl for Mac
  • API for local and network applications
  • Notification forwarding
  • Experimental support for WebKit-based display styles
http://www.tripthevortex.com/growl/
まず、Growl本家からtarボールを持ってくる(SDKはdmgなので...)
Growl Developer Downloads

Information regarding the SVN repository and other areas of interest are addressed in the developer documentation. Growl requires Xcode 2.3 to compile, which is available for free from Apple.

Growl 1.1 Source
http://growl.info/downloads_developers.php
次に、"/Growl-1.1-source/Bindings/python"に移動し以下のパッチを当てる。
--- Growl.py.orig   Wed Jan 24 05:36:17 2007
+++ Growl.py    Fri May 30 11:22:18 2008
@@ -72,7 +72,7 @@
         if userInfo.has_key(GROWL_NOTIFICATION_STICKY):
             sticky = userInfo[GROWL_NOTIFICATION_STICKY]
         else:
-            priority = False
+            sticky = False
         data = self.encodeNotify(userInfo[GROWL_APP_NAME],
                                  userInfo[GROWL_NOTIFICATION_NAME],
                                  userInfo[GROWL_NOTIFICATION_TITLE],
おそらく開発者のtypoかと思う。
そして"python setup.py install"する。
気持ち悪い人は"python setup.py bdist_wininst"する

後はサンプルコード
Objective-Cのモジュールをインストールしていないので、netgrowl経由でしか送信出来ないです。
#!/usr/bin/python
import Growl
g = Growl.GrowlNotifier(
    applicationName='GrowlExample',
    notifications=["PyGrowl"],
    defaultNotifications=[0],
    hostname="localhost",
    password="My Really Secure Password")
g.register()
g.notify(
    noteType="PyGrowl",
    title='wanings',
    description='toilet spilled some xxx!',
    sticky=False)
まずGrowl for WindowsをインストールするとシステムトレイにGrowlというアイコンができ、「Settings」を選ぶと設定画面が表示されます。次にNetworkタブを開き
  • Listen for incoming notifications
  • Allow remote application registration
にチェックを入れます。そして"Server Password"に上記ソースにあるpassword、"My Really Secure Password"を入れます。(実際はソースも設定も変更して使用しましょう)
growl settings 1

後は上記サンプルプログラムを起動すると以下の様にGrowlが表示されます。
growl notify
なお、設定の"Applications"にて挙動を変えられますで色々試してみてもいいかもしれません。
growl settings 1
また、上記ではpythonの例を示しましたがperlで"Net::Growl"を使い
use strict;
use warnings;
use Net::Growl;
register(host => 'localhost',
         application=>"growl.pl",
         password=>'My Really Secure Password', );
notify(
       application=>"growl.pl",
       title=>'warning',
       description=>'toilet spilled some xxx more!',
       priority=>2,
       sticky=>False,
);
この様なサンプルでもGrowlは表示されます。
ちなみ、Growl for Windowsのせいなのか幾らかの日本語で文字化けが発生しました。
registerしたアプリケーションを消すには
%USERPFOFILE%¥Local Settings¥Application Data¥Vortex¥Vortex.Growl.WindowsClient
のディレクトリを一斉に消すと設定が消えてくれます。
個別で消す方法は見つかりませんでした。

色々な言語でBindingされている様なので皆さん試してみてはどうでしょうか

2008/05/29

はてな
これ、すごいっす。
The Memcache API - Google App Engine - Google Code

High performance scalable web applications often use a distributed in-memory data cache in front of or in place of robust persistent storage for some tasks. Google App Engine includes a memory cache service for this purpose.

http://code.google.com/appengine/docs/memcache/
何が凄いって仕様が凄い。
通常のset/getの他、dictとして格納出来るset_multi/get_multiもある。Tagtterの様にタグ毎にキャッシュしたい場合には持って来いなAPIです。
どうやらdangaをベースにしている様で、LiveJournalsourceforge、さらにはWikiPediaでも使われているライブラリらしいです。

さて、今日Tagtterにこのmemcache APIを使ってみました。
使い方としてはページをそのまま!Tagtterの場合、動的なコンテンツと言えばタグ、Vote、ユーザですが、これらが変更されない限りトップページタグページは変る事は無いのです。他の情報はjavascript(jQuery)で動的に取得しており、サーバには格納されていません。
どんなに大胆な使い方かと言うと
class TopPage(webapp.RequestHandler):
  def get(self):
    cache = memcache.get('tagtter_top_page')
    if cache:
      # キャッシュがあるならそのまま出力
      self.response.out.write(cache)
      return

    ・・・ 巨大なデータ処理 ・・・

    path = os.path.join(os.path.dirname(__file__), get_template(self))
    cache = template.render(path, template_values)
    # キャッシュに溜め込む
    memcache.set('tagtter_top_page', cache, cache_time)
    self.response.out.write(cache)

class AddTagsAPI(webapp.RequestHandler):
  def get(self, username):

    ・・・ タグの追加処理 ・・・

    # 結果を出力
    dump_json(self, { 'status': 'ok', 'message': 'done' })
    # キャッシュをクリアしてやる
    memcache.flush_all()
上記の様に、キャッシュがあればそのまま出力し、タグが追加されればキャッシュをクリアするという方法。
おかげでトップページタグページの表示速度が激変しました。
但し、ユーザ一覧ページ等は、pageというパラメータにより出力する内容が異なる為、このままでは対応出来ません。やっちゃうとどんどん同じページが表示されてしまいます。
今のところ、トップページとタグページにしか取り入れていませんが今後少しずつ取り入れて行きたいと思います。

ところで、公開されたAPIのもう一つImages APIも使ってみました。
使い方は簡単。
from google.appengine.api import images

...

image = images.Image(data) # input data
image.resize(100, 100)
image.rotate(90)
data = image.execute_transforms(output_encoding=images.JPEG)
現状、合成したり90度単位でない回転等は出来ませんが、コレ使えばなんでもありちゃんかいっと思った。いずれやる。

動いている物は以下
Image API Test

2008/05/28

はてな
「はてなスター」の置かれている位置によっては思いっきり誤爆してしまうhatenaStar.jsですが、皆さんのご不満を軽減すべく誤爆確認機能をつけました。これまで
:hatenastar 1
としていた場面で
:hatenastar 1?
とすると、つけようとしている「はてなスター」がブリンクします。
点灯している「はてなスター」を見て、「あぁ、あそこに付けるんだな」と思って頂ければと思います。
あとは安心して":↑<bs>"でコマンドヒストリを出してバックスペースで"?"を消し
:hatenastar 1
と実行して下さい。
hatenaStar.js

はてな
GoogleからjQueryやdojoがロード出来るAjaxライブラリが公開されました。

The AJAX Libraries API is a content distribution network and loading architecture for the most popular open source JavaScript libraries. By using the Google AJAX API Loader's google.load() method, your application has high speed, globaly available access to a growing list of the most popular JavaScript open source libraries including:

http://code.google.com/apis/ajaxlibs/
でも、リンク先に載ってるコード、良く見たら動かないよ><
googl ajax library typo
正しくは
<script src="http://www.google.com/jsapi"></script>
<script>
  var renderResults = function(results) {
      $.each(results, function(index, item) {
        $('#result')
          .append('<div id="result' + index + '"></div>');
        $('#result' + index)
          .append('<a href="' + item.url + '">' + item.title + '</a>')
          .append('<div>' + item.content + '</div>')
          .append('<span>' + item.visibleUrl + '</span>')
          .css('padding', '0.5em');
        $('#result' + index + ' div')
          .css('border', '1px dotted gray')
          .css('width', '500px')
          .css('padding', '1em')
          .append('<span>');
        $('#result' + index + ' span')
          .css('color', 'green')
          .css('margin-left', '1em');
      });
  }

  // Load jQuery
  google.load("jquery", "1");

  // on page load complete, fire off a jQuery json-p query
  // against Google web search
  google.setOnLoadCallback(function() {
    $.getJSON("http://ajax.googleapis.com/ajax/services/search/web?q=google&v=1.0&callback=?",

      // on search completion, process the results
      function (data) {
        if (data.responseData.results &&
            data.responseData.results.length>0) {
          renderResults(data.responseData.results);
        }
      });
    });

</script>
<div id="result"></div>
こんな感じになります。あと、visualization等の場合はgoogle.loadの第3引数が有効で"callback"の記述が出来たのですが、jQueryやdojo等サードパーティな物では動かなかった。残念。
ちなにみ上のコードを動かすと、こんな感じになります。

続きを読む...


2008/05/27

はてな
about: rel-bookmark戦争
『オレ、rel-bookmarkも嫌いなんだわー』とブツクサ言うsnj14 - otsune tumblr まとめサイト 画像保管庫Q
『オレ、rel-bookmarkも嫌いなんだわー』とブツクサ言うsnj14 - otsune tumblr まとめサイト 画像保管庫Q(追記)
3:14 - 『オレ、rel-bookmarkも嫌いなんだわー』とブツクサ言うsnj14
さて、私も少し考えてみた。
Basic HTML data types

Refers to a bookmark. A bookmark is a link to a key entry point within an extended document. The title attribute may be used, for example, to label the bookmark. Note that several bookmarks may be defined in each document.

http://www.w3.org/TR/REC-html40/types.html#h-6.12
mattn的に訳すと

Bookmarkについて。 bookmarkは広範囲に渡るドキュメント内の唯一のキーとなるエントリポイントへのリンクとなります。ブックマークをラベリングする際にはタイトル属性が使用され、ドキュメント内には幾らかのブックマークが定義され得る事に気をつけるべきでしょう。

そしてkuさんが言及している部分
Basic HTML data types

Authors may wish to define additional link types not described in this specification. If they do so, they should use a profile to cite the conventions used to define the link types. Please see the profile attribute of the HEAD element for more details.

http://www.w3.org/TR/REC-html40/types.html#h-6.12
訳すと
作者は本仕様では記述し得ないリンク型を別途定義したいと思うかもしれません。 であれば、リンク型を定義するのに一般的に用いられるprofileを使用すべきでしょう。 その他の詳細に関してはHEAD要素のprofile属性を参照して下さい。
そしてrel-bookmarkについて、microformats wikiでは
rel-design-pattern - Microformats

By convention (citation needed), this entry point also captures the notion of a "permalink".

http://microformats.org/wiki/rel-bookmark
訳すと

一般的には(言及が必要)、このエントリポイントとはpermalinkの概念で表現される物。

意訳過ぎたらごめんなさい
と言う事で
rel-bookmarkとは、それが含まれるドキュメントの内1点を指すべき物であり、rel-bookmarkがドキュメント内で実際のリンク先を指すべき、とまでは決めてない。あくまでpermalink扱い。
が私の考え。が上から読み取った私の解釈。
例えば末っ子の小学生が「姉ちゃん」と言えば「姉」を指し、60代サラリーマンが「姉ちゃん」と言えば「キャバクラの姉ちゃん」になる訳で...
つまりはそのテリトリ内で一意に現すことが出来る何か...がrel-bookmarkなのではないかと思った。

2008/05/26

はてな
Tagtterをリリースして、初期は「CPU Quota」連発してしまい見苦しい状態でした。ごめんなさい。
さて、一時はどうなるかと思いましたが現在は「CPU Quota」も表示される事無く動いています。
今日はこの状況を乗り切る際に行った「Google App Engine」のパフォーマンスチューニングtipsを3つほどご紹介。

webapp.WSGIApplicationのdebugフラグはFalseにすべし

いきなり当たり前で申し訳ないですが、実はこのフラグがTrueかFalseかというだけで「CPU Quota」が出る頻度が極度に異なります。
実際に同じ症状の方もいらっしゃる様なので、おそらく間違いありません。
また公開する様なシステムでは、パスワード等も管理される事になるかと思いますが、debug=Trueだとスタックトレースに変数の値が表示されてしまい無茶苦茶危険です。気を付けましょう。
なお、Tagtterではユーザのパスワードは一切保存していません。

時間の掛かる既知な処理はキャッシュする

これはGoogle App Engineだけに言える話ではないですが、Tagtterではユーザの存在確認の為にtwitter.comへアクセスしています。
但し、タグが追加される度、voteされる度にこれを行ってしまうとtwitter.comにも負荷を掛ける事になります。
そこでTagtterではTagtter内に存在するユーザに対してはtwitter.comへのアクセスを行わないようになっています。
確かにGoogle App Engineの処理能力は良いのですが、いかんせん制限が厳しかったりします。余談になりますが現状Tagtterのデータ全件をXMLエクスポートする処理は「CPU Quota」で動きません。現在はデータの種別毎にバックアップしています。

Templateにはクラスオブジェクトは渡さない

Django Templateには、db.Modelのインスタンスを渡せて非常に便利なのですが、このDBインスタンスをTemplateの中から扱うと非常に遅くなります。
またdb.Modelに持ったgeneratorをTemplateから使うと更にパフォーマンスが落ちます。
例えばTagtterではユーザに対して付けられたタグをManyToManyで管理しており、モデルの一部を抜粋すると
class TagtterTag(db.Model):
  name = db.StringProperty(required=True)

  ... snip ...

class TagtterMembership(db.Model):
  user = db.ReferenceProperty(TagtterUser)
  tag = db.ReferenceProperty(TagtterTag)

  ... ship ...

class TagtterUser(db.Model):
  name = db.StringProperty(required=True)

  ... snip ...

  def tags(self):
    return (x.tag for x in self.tagttermembership_set)

この様なコードになるのですが、user.tagsをTemplate側から呼び出すとかなりパフォーマンスダウンになります。また、Google App EngineではCPU占有度により「CPU Quota」させる仕組みがあるのですが、実はこれはTemplate内の呼び出しにも適応される為
application → template → model procedure
という処理を行うと、1処理(1値参照)あたりのCPU使用回数が増える事になります。
つまり上記Tagtterのtagsページでは全てのタグが表示されますがこれを
    template_values = {
      'tags' : TagtterTag.all(),
    }
この様にしてしまうとTemplate側からModelのメソッドを呼び出す事になり、現状のデータ件数だと100%エラーが発生してしまいます。
Google App EngineではCPU占有状態が5秒程続くとエラーになる様で、このブリッジ状態だけでもパフォーマンスダウンに繋がるって事になります。
これを回避する為には、applicationにてTemplateで使う値を全て保持してしまう事が最も効果的でした。
つまり全てdictとして渡してあげるのです。変にTemplate側で「タグの数が0でない物を表示」とするのではなく
    all_tags = []
    for tag in TagtterTag.all():
      if tag.size():
        size = tag.size()
        all_tags.append({
          'name' : tag.name,
          'title' : tag.title,
          'size' : size,
          'fontsize' : font_size(size),
        })
    ... ship ...

    template_values = {
      ... ship ...

      'tags' : all_tags,

      ... ship ...
    }
この様にTemplate側からdb.Modelメソッドを呼び出させないようにするのです。 これで、現状エラーも出なくなりました。要するに極力db.Modelインスタンスにアクセスしない様にするってのが味噌ですね。
こんな品祖なパフォーマンスチューニングですが、皆さんの何かしらのお役に立てば幸いです。

他にもパフォーマンスチューニングの方法は幾らでもあるかと思います。Tagtterで言えばクライアント側の処理は殆どパフォーマンスチューニングされていないのが現状です。
不定期ですが時間を見付けてやって行きたいと思います。

何かご要望などあれば、Feature Requestまで。

はてな
以前、「Big Sky :: 意外と知られていないvimのtips(calendar.vimの日記機能をGoogle Calendarと同期させる)」という記事を書いたのですが、どうやらこれを完成品にまで作り上げてくれた人が居るようです。
見たところ、私のソースを流用されてはいなさそうですが仕組みは似通っています。
diaryvgc - Google Code

Synchronism Python Script between VIM Calendar diary and Google Calendar .

DiaryVGC == Diary Vim Google Calendar

http://code.google.com/p/diaryvgc/
私の場合はファイルの存在や更新時刻で動作しますが、こちらはログファイルを使った全て。また私の様に「--- Google Calendar ---」という文字列で対象ファイルを絞ったり、イベント期間を設定出来たりはしません。
私の場合は「--- Google Calendar ---」という文言を見付けて、それだけを対象ファイルとしていますが、こちらはログファイルを使った全て。
ただ、中国の方のようでコード内にcp936やらgb2312といったエンコーディング名がちらほら。
適当にpatch当てて、動くまでは確認しました。
Index: diaryvgc.py
===================================================================
--- diaryvgc.py (revision 4)
+++ diaryvgc.py (working copy)
@@ -257,15 +257,15 @@
                             if sys.platform[:3] == 'win':
                                 try:
                                     diaryinfo = open(tfile).read()
-                                    info_done = unicode(diaryinfo,'cp936')
+                                    info_done = unicode(diaryinfo,'mbcs')
                                     #print "=============win===UTF8=============="+tfile
                                 except Exception,ex:
-                                    diaryinfo = codecs.open(tfile,'r','gb2312').read()
+                                    diaryinfo = codecs.open(tfile,'r','mbcs').read()
                                     info_done = diaryinfo.encode("utf-8")
                                     #print "============win====GB2312=============="+tfile
                             else:
                                 try:
-                                    diaryinfo = codecs.open(tfile,'r','gb2312').read()
+                                    diaryinfo = codecs.open(tfile,'r','mbcs').read()
                                     info_done = diaryinfo.encode("utf-8")
                                     #print "=============notwin===GB2312=============="+tfile
                                 except Exception,ex:

使い方は
diaryvgc.py --user your-gmail-id --pw your-pass-word --dir /path/to/vim/diary
で更新です。
追記
よくみたら場所で「China」がデフォルトになってますね。
使う人は適当に「Japan」とかに書き換えるのが良いかと...

自分が作った物が何かしらの形で流用されるってのは、うれしいですね。

2008/05/23

はてな
追記
検索順位が変ってしまったようです。

おそらくこれ、Technoratiがやりたかった事のはず。

- Yahoo! Search Results
http://www.yr-bcn.es/demos/microsearch/

microsearch [Wiki]

Using microformats

We support two kinds of microformats: hCard and hCalendar. hCard is used to add personal information to your webpage, hCalendar is used to add events. You can use the hCard creator and the hCalendar creator to create the code that you will need to insert into your webpage.

http://www.yr-bcn.es/dokuwiki/doku.php?id=microsearch#using_microformats
1段目の引用部にあるリンクで、「mattn」と検索してみて下さい。おそらく10秒から20秒程かかりますが検索結果が現れるかと思います。他の検索サービスと違う事に気付いた方、すばらしい。
そう、microformatsを使ってるのです。このサイト「Big Sky」に埋め込まれたmicroformatsの内、「hCard」と呼ばれる物(ここでは「Osaka, Japan」)を使用して地図上の大阪付近に「mattn」とプロットしているのです。
microsearch
2段目の引用部

Using microformats

hCardとhCalendarという、2種類のmicroformatsをサポートしています: hCardとは、貴方のウェブページに個人情報を加えるのに用いられ、hCalendarはイベントを加えるのに使用されます。 これらをウェブページに追加するには挿入するにはhCard CreatorFOAF-a-matic -- Describe yourself in RDFを使う事でコードを生成出来ます。

から、Yahooもmicroformatsに何かしらの期待を持っている事が伺えます。いずれ検索メタデータとして扱っていこうという事でしょうか。
リンク先には、今後GRDDLへの対応も予定されているので、ちょっとYahooが面白い事をやってくれそうな気がしてきました。

はてな
I wrote a plugin which moved the focus along the input fields.
When the web page has multiple <input> or <textarea> fields,
the focus walks the input fields by pressing A-i (or M-i).

http://www.pqrs.org/tekezo/tmp/vimperator/walk-input.js

It seems there was no similar function in the core code, would you merge this?

Regards,
Takayama Fumihiko.
http://www.mozdev.org/pipermail/vimperator/2008-May/001497.html
便利。<M-i>で順に入力フィールドへフォーカスが飛ぶ。
Dotan Cohenから「TABとどう違うの?」って返信への返信通り、"gi"だと届かないフィールドへフォーカスを飛ばすのはTABの押しすぎで指がつる。
使わせて頂く事にしよう。

tekezo++
Posted at 14:49 in