2008/07/11

はてな
卑怯と言われようが構いません。

let X = "ひだまり"
let _ = "スケッチ"

try
  X / _ / X < また見て下さいね
catch /^Vim\%((\a\+)\)\=:E488/
  echo eval(
    \  substitute(
    \    substitute(
    \      v:exception,
    \      '^.*E\(\d\+\).*:\s*\(\(.\) / \(.\).*\). <\(.*\)$',
    \      '\2"\3".(\1-123)."\5"', ''), '/', '.', 'g'))
endtry

2008/06/26

はてな
vimで自前でYAML読み込むとか面倒くさすぎる。
こう言う時はif_pythonとかif_perlとかを使わせてもらう。運良くvimスクリプトはjsonと相性が良いのでYAMLを読み込み、JSONに変換してvimに戻してあげる。
function! LoadYAML(file)
  perl << EOF
use YAML::Syck;
use JSON::Syck qw(Dump);
eval {
  VIM::DoCommand("let ret = " . Dump(LoadFile("".VIM::Eval('a:file'))));
};
VIM::DoCommand("let v:errmsg = substitute('$@', \"\\n\", '', 'g')") if $@;
EOF
  if !exists('ret')
    throw v:errmsg
  endif
  return ret
endfunction

echo LoadYAML("config.yaml")
戻り値はDictionary形式になります。
読み込めなかった場合はthrowしているのでvim7限定になりますがcatchしてやって下さい。

さて、if_perlですがperl510で動かなくなってました。今日パッチを作成してvim-devに送ったのですが、如何せん自信がありません(Shibuya.xsでvimmerな皆様、どうか私にお力をお貸し下さい)。
パッチは
vim72-perl510-fix.diff
にあります。不具合報告等あればご連絡下さい。

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まで。

2008/05/02

はてな
以前、「Big Sky :: 意外と知られていないvimのtips(vimでソースコードをHTML化するコツ)」という記事を書いて、なかなか好評だったのですが(前のサーバで公開した記事なので反響は見えませんが)、vimでHTMLを編集しておられる方って結構多いと感じました。
私もしかり、このブログにおいても全てvimで編集しています。
ソースコードは上記リンクに記した通り「:TOhtml」を使い、その他はほぼ全て打ち込んでいます。ただ別のサイトにある記事やリンクを引用する場合、少し手間が発生します。例えば
<a href="http://example.com">サンプル</a>
とタイプする場合、ブラウザのアドレスバーからURLを、さらにブックマーク画面を出してタイトルをコピーして上の様な記述に置き換えるとなるとキーボードだけで操作出来なかったりして少し煩わしい感じがしますね。オーサリングツールやmarkdown等で楽する事も出来ますがちょっとした更新で、しかもvimが使いたいなんて場合もありますよね。
また、ブラウザは起動していないけどURLならもう知ってるなんて場合、タイトル抜き出すのが大変なんて思っていませんか?
今日は私が使っているvimスクリプトを紹介してみます。
まずソース
let g:Anchorize_Format = '<a href="%s" class="external" target="_blank">%s</a>'
function! Anchorize_TITLE(url)
  silent! split _FETCHTITLE_
  silent! exec "0r!curl -s ".a:url
  if executable('nkf')
    if &enc == 'utf-8'
      silent! %!nkf -X8
    elseif &enc == 'cp932'
      silent! %!nkf -Xs
    endif
  endif
  silent! %join!
  silent! %g/^\s*$/d _
  silent! %s/^.\{-}<title[^>]*>\([^<]\+\)<\/title>.*/\1/i
  let ret = getline('.')
  silent! bw!
  if exists('Anchorize_Format')
    let format = Anchorize_Format
  else
    let format = '<a href="%s">%s</a>'
  endif
  return printf(format, a:url, ret)
endfunction
function! Anchorize_URL(v)
  let url = input('URL:')
  if len(url)
    if exists('Anchorize_Format')
      let format = Anchorize_Format
    else
      let format = '<a href="%s">%s</a>'
    endif
    if a:v
      silent! normal! gvs
      let word = getreg('"')
      exec "normal! a".printf(format, url, word)
    else
      let word = expand('<cword>')
      exec "normal! ciw".printf(format, url, word)
    endif
  endif
endfunction
nnoremap <leader>,u :call Anchorize_URL(0)<cr>
vnoremap <leader>,u :<c-w>call Anchorize_URL(1)<cr>
vnoremap <leader>,U s<c-r>=Anchorize_TITLE(getreg('"'))<cr><esc>
これをanchorize.vimとかでpluginディレクトリに放り込むとインストール完了。
使い方は、まず
今日もGoogleで検索
の「Google」という部分を「http://www.google.co.jp/」へのリンクにしたい場合には「Google」の部分までカーソルを移動して
<leader>,u
「<leader>」は何も設定していなければ「¥」になっているかと思います。
とタイプすると
URL:
というプロンプトが出るのでここに
URL:http://www.google.co.jp/
とタイプしてENTERを押すと
今日も<a href="http://www.google.co.jp/">Google</a>で検索
と変換されます。また空白を含んだ、例えば「Google Search」の様な場合「Google Search」をビジュアル選択して「<leader>,u」とすれば同じ動作になります。
さらに例えば
今日もhttp://b.hatena.ne.jp/でホットエントリ
というテキストのURL部分をビジュアル選択し、今度は
<leader>,U
「U」は大文字
とタイプすると
今日も<a href="http://b.hatena.ne.jp/">はてなブックマーク - ソーシャルブックマーク</a>でホットエントリ
と変換してくれます。
急いでネタ記事をアップしたいvimmerには重宝するのではないかと思います。なお、動作にはnkfというフィルタコマンドが必要です。Windowsであれば「nkf win32」あたりで検索すればヒットするかと思います。ちなみに、vimrc等でAnchorize_Formatという変数を
let g:Anchorize_Format = '<a href="%s" class="external" target="_blank">%s</a>'
等といった感じに編集する事も出来るので、class属性を常に付けたい人にも使えるかと思います。
元々公開するつもりも無かったスクリプトなので、拡張性ありませんがよろしければどうぞ。

2008/03/31

はてな
嘘。難読化っていうか、これバグだな...
Vim script line continuation? - vim_dev | Google グループ

Well, it seems the new line continuation can be placed weirdly, which will make the vim script syntax file even messy when considering the line continuation. Any comments?

検証コード
e
\c
\h
\o
\ "
\
\
\P
\l
\a
\!"

それPla!

2008/03/24

はてな
最近はオセロって言っちゃダメなんだっけ?
vim-reverse
コンピュータ対戦です。

続きを読む...


2008/03/17

はてな
vimではあまり使い道がないだろうけど...
スクリプトは
" DO NOT EDIT
scriptencoding utf-8
let s:self = expand("<sfile>")
com! UseDataToken exe join(map(remove(readfile(s:self),5,8),"strpart(v:val,1)"),"|")
"__DATA__
"silent! unlet datatoken
"let datatoken=readfile(expand("<sfile>"))
"cal remove(datatoken,0,search("^\"__DATA__$")-1)
"cal map(datatoken,"strpart(v:val,1)")
こんな感じで使う側はこんな感じ
"source datatoken.vim
UseDataToken

silent! unlet d
let d = eval(join(datatoken))
echo d.author
echo d.version
echo d.date

"__DATA__
"{
"'author': 'mattn <mattn.jp@gmail.com>',
"'version': '0.001',
"'date': 'Mon, 17 Mar 2008'
"}
perlの様にファイルハンドルでないのが気持ち悪いか。
追記
タイトル変だったので直した

新規投稿