アクトインディ技術部隊報告書 http://tech.actindi.net アクトインディ技術部隊報告書 Sat, 04 Sep 2010 13:35:59 +0900 ja 空白一つにこだわりたい(2) http://tech.actindi.net/3492489572 完全にネタ切れなのですが、毎週1つのエントリーペースは守って行きたいので連投です。
質より量でまいります。
以前、空白一つにこだわりたいというエントリーを書きましたが、割と日々便利に使っています。
最近はちょっと違ったところで、空白を一つにしたい状況に遭遇しています。
- [ ]  こんにちは   あいうえお    かきくけこ
- [ ]   こんばんは  あいうえお   かきくけこ
- [ ]  おはよう  あいうえお   かきくけこ
という感じなのですが、何かから行をコピペしてくると発生することが多いです。
これをちまちま直しているのが非常に手間ということで、適当に、elispを書いてみました。
(defun just-one-space-each ()
  (interactive)
  (save-excursion
    (let* ((begin (progn (beginning-of-line) (point)))
           (end (progn (end-of-line) (point)))
           (begin (min begin end))
           (end (max begin end)))
      (goto-char begin)
      (while (and (re-search-forward " +" nil t) (<= (point) end))
        (replace-match " ")))))
各行で実行すると
- [ ] こんにちは あいうえお かきくけこ
- [ ] こんばんは あいうえお かきくけこ
- [ ] おはよう あいうえお かきくけこ
という風に空白1つに統一できます。快適!
ちなみに、Twitterのつぶやきで最近 delete-indentation (M-^)というのを教えてもらいました。
行の連結に使えるのですが、just-one-spaceの使いどころと似ています。 ■ ]]>
Fri, 03 Sep 2010 16:59:32 +0900
マニュアル/ソースを良く読もう! http://tech.actindi.net/3492486546 完全にネタ切れなので、中途半端に失敗談を書きます。
skype.elは非常に便利なのですが、自分のEmacsの操作が鈍い所為かチャットの切り換えにいつも、もたもたしておりました。
このままではいけないと思った私は、便利elispを書いて対応することに。
社内のSkypeの利用形態としては、グループチャットが主で使われる部屋も2つ位と少ないので、このチャットをキー一発で開ければOKであろうと思われました。
ということで、skype.elをちらちら見つつ、
(require 'cl)

(defun *skype-find-ai-chat (name)
  (let ((chat (find-if (lambda (x) 
                         (search name
                                 (aref x 2)))
                       (skype--chat-get-recent-objects))))
    (when chat
      (switch-to-buffer
       (skype--open-chat-buffer chat)))))

(defun skype-open-konnichiwa-chat ()
  (interactive)
  (*skype-find-ai-chat "こんにちは"))

(defun skype-open-kombanwa-chat ()
  (interactive)
  (*skype-find-ai-chat "こんばんは"))

(defun skype-open-oyasuminasai-chat ()
  (interactive)
  (*skype-find-ai-chat "おやすみなさい"))

(define-key global-map [(super ?1)] 'skype-open-konnichiwa-chat)
(define-key global-map [(super ?2)] 'skype-open-kombanwa-chat)
(define-key global-map [(super ?3)] 'skype-open-oyasuminasai-chat)
のような物を書いてみました。
これで、Super-1〜2で目的の部屋を一発で開くことができます。
これは割と便利だなーと思いつつ、改めて、skype.elを眺めたところ、
(global-set-key (kbd "M-9") 'skype--anything-command)
とするとanything.elと連携できて良いよ!との解説が。
試してみたところ、断然こっちの方が便利でした。
やはりREADME的なものはちゃんと読もう、と思った次第です。
■ ]]>
Fri, 03 Sep 2010 16:09:06 +0900
低価格レンタルサーバーの共有SSLとWordPress (2) http://tech.actindi.net/3491875086 完全にネタ切れなので、中途半端にWordPressのことを書きます。
続きものだった筈の低価格レンタルサーバーの共有SSLとWordPress (1)を書いてから半年程放置してしまいましたが、WordPressも3系が出たということでこのテーマについて少しまとめてゆくことにしてみました。
前回は1つのWordPress+低価格レンタルサーバーでSSLサイトと通常のサイトをどう切り盛りするかというのがテーマでしたが、色々試してみた結果、1つのWordPressでがんばらずにフォーム専用のWordPressを別個にインストールして使うことにするのが一番手間がかからないようです。
ちょっとした問題としては、SSL専用でWordPressを利用する場合、WordPress2系ではどういう訳かSSLの状態では管理画面にまともにログインできませんでした。
大抵のところでは、URLがhttpでもhttpsでも使えるので管理画面のログインはhttpでサイトの利用はhttpsという謎な運用をすることにより回避できていましたが、WordPress3系では解決しているようです。これは嬉しいところですね。
非常に中途半端ですが、次回に続きます…
■ ]]>
Fri, 27 Aug 2010 14:18:06 +0900
隙があればlispを詰め込んで行きたい (9) http://tech.actindi.net/3491523364 隙があればlispを詰め込んで行く日々ですが、古めのウェブページの累計カウンター的な物を月に一回更新するという作業が発生しました。
sedで一発かなと思いましたが、sedで一発と思ったらCLで書くことにしているので、CLで書いてみます。
具体的な内容ですが、index.htmlの中に、カウンター的なものがあり、数字はそれぞれ1枚のGIF画像になっているのを、毎月集計された数字に更新というところです。
サーバーとは、SSHで通信できます。
折角なので、リモートのファイルをローカルのファイルと同じ感覚で編集できるようなマクロを作成してみました。
といってもリモートからscpしてきて編集するだけのものです。
これと、以前に定義したオレオレsedを組み合わせて任務は完了です。
(exec:define-executable scp)

(defmacro with-output-to-remote-file ((stream path) &body body)
  (let ((temp-file-name (string (gensym "/tmp/with-output-to-remote-file-"))))
    `(unwind-protect (progn
                       (with-open-file (,stream ,temp-file-name :direction :output)
                         ,@body)
                       (scp ,temp-file-name ,path)
                       nil)
       (when (cl-fad:file-exists-p ,temp-file-name)
         (delete-file ,temp-file-name)))))

(defmacro with-input-from-remote-file ((stream path) &body body)
  (let ((temp-file-name (string (gensym "/tmp/with-input-from-remote-file-"))))
    `(unwind-protect (progn
                       (scp ,path ,temp-file-name)
                       (with-open-file (,stream ,temp-file-name)
                         ,@body)
                       nil)
       (when (cl-fad:file-exists-p ,temp-file-name)
         (delete-file ,temp-file-name)))))

(defun カウンター (num)
  (fare-utils:join-strings
   (list
    "<!-- カウンター -->" 
    "<div id=\"count\">" 
    "<table id=\"counter\">" 
    "<tr>" 
    "<td>" 
    (format nil
            "~{<img src=\"./images/count_~a.gif\" alt=\"\" />~%~}"
            (map 'list #'values (write-to-string num)))
    "</td>" 
    "<td> <img src=\"./images/count_ken.gif\" alt=\"\" width=\"18\" height=\"17\" /></td>" 
    "</tr>" 
    "</table>" 
    "</div>"
    "<!-- /カウンター -->")
   :separator #\Newline))
;; 実行例
(with-output-to-remote-file (out "example:public_html/index.html")
  (with-input-from-remote-file (in "example:public_html/index.html")
    (sed "<!-- カウンター -->"
         "<!-- /カウンター -->" 
         (カウンター 12345)
         :IN IN
         :OUT OUT)))

]]>
Mon, 23 Aug 2010 12:36:04 +0900
隙があればlispを詰め込んで行きたい (8) http://tech.actindi.net/3490064003 隙があればlispを詰め込んで行く毎日を連投です。
このシリーズの6回目で本日が祝日であるかどうかを判定したい、というネタを投稿しましたが、そもそも何がしたかったかというと、業務時間かどうかによってFirefoxや、Skypeのプロファイルを切り替えられるようにしてみたら便利かな、というのが動機でした。
ということで、この前のHOLIDAY-Pを拡張して、IN-WORKING-HOURS-Pというのを作成し、就業時間中は、仕事用のプロファイルでアプリを起動することにしてみました。
そういえば今迄説明なしで来てしまいましたが、もちろんウィンドウマネージャーはStumpWMです!
(DEFUN IN-WORKING-HOURS-P ()
  (AND (NOT (HOLIDAY-P))
       (< 6
          (NTH-VALUE 2 (DECODE-UNIVERSAL-TIME (GET-UNIVERSAL-TIME)))
          17)))

;; firefox
(DEFCOMMAND FIREFOX () ()
  "Run or switch to firefox."
  (IF (IN-WORKING-HOURS-P)
      (run-or-raise "/usr/bin/firefox -P \"work\" " '(:class "Firefox"))
      (run-or-raise "/usr/bin/firefox -P \"home\"" '(:class "Firefox"))))
これで、会社で同僚にFirefoxを使って説明をしているときに、アッー!なURLの履歴などが出てきてしまいアッー!っとなることを防げますね。 ■ ]]>
Fri, 06 Aug 2010 15:13:23 +0900
隙があればlispを詰め込んで行きたい (7) http://tech.actindi.net/3490053352 隙があればlispを詰め込んで行く毎日ですが、今日の課題は、
  "8/24(火)、
8/25(水)、
8/26(木)、
8/27(金)
8/31(火)、
9/1(水) 、
9/2(木) 、
9/3(金)
9/7(火) 、
9/8(水) 、
9/9(木) 、
9/10(金)
9/14(火)、
9/15(水)、
9/16(木)、
9/17(日)"
のような、曜日付き日付の文字列が与えられた場合に、日付に対応している曜日が正しいかの判定です。
日付はそれほどでもないですが、曜日は結構間違ってたりすることも多いですよね。
(SET' FOO
  "8/24(火)、
8/25(水)、
8/26(木)、
8/27(金)
8/31(火)、
9/1(水) 、
9/2(木) 、
9/3(金)
9/7(火) 、
9/8(水) 、
9/9(木) 、
9/10(金)
9/14(火)、
9/15(水)、
9/16(木)、
9/17(日)")

(PPCRE:DO-REGISTER-GROUPS ((#'PARSE-INTEGER MON) (#'PARSE-INTEGER DATE) DOW)
    ("(\\d+)/(\\d+)\\((.+)\\).*" FOO)
  (LET* ((CDOW (NTH-VALUE 6 (DECODE-UNIVERSAL-TIME (ENCODE-UNIVERSAL-TIME 0 0 0 DATE MON 2010))))
         (X (FORMAT NIL "~D/~D (~A)" MON DATE (ELT "月火水木金土日" CDOW)))
         (Y (FORMAT NIL "~D/~D (~A)" MON DATE DOW)))
    (FORMAT T "~A => ~A~%" X Y)
    (UNLESS (STRING= X Y)
      (ERROR "曜日が間違っています! (正)~A => (誤)~A~%" X Y))))
動作:
8/24 (火) => 8/24 (火)
8/25 (水) => 8/25 (水)
8/26 (木) => 8/26 (木)
8/27 (金) => 8/27 (金)
8/31 (火) => 8/31 (火)
9/1 (水) => 9/1 (水)
9/2 (木) => 9/2 (木)
9/3 (金) => 9/3 (金)
9/7 (火) => 9/7 (火)
9/8 (水) => 9/8 (水)
9/9 (木) => 9/9 (木)
9/10 (金) => 9/10 (金)
9/14 (火) => 9/14 (火)
9/15 (水) => 9/15 (水)
9/16 (木) => 9/16 (木)
9/17 (金) => 9/17 (日)
;>>> 曜日が間違っています! (正)9/17 (金) => (誤)9/17 (日)
こんな感じのものを書いてしのいでみました。
大体の内容ですが、単純に正規表現で切り出してシステムから割り出したものと一致するかを見ているだけです。
Common Lispで適当に書き捨てましたが、どちらかというとelispで書いた方が役立つ機会は多いかもしれません。 ■ ]]>
Fri, 06 Aug 2010 12:15:52 +0900
Emacsで複数のバッファのファイル名を控えておきたいとき http://tech.actindi.net/3489465278 Emacsで色々な場所にちらばっている複数のバッファを編集しつつ、編集したファイルだけ名前を控えておきたいとき、皆さんはどのように対処されてますでしょうか。
多分、本当にたまにしか必要に迫られることはないと思うのですが、
自分の考えた解決法は、
M-:して
Eval: (push (buffer-file-name) foo)
してfooにファイル名を蓄積して、*scratch*などで、fooを評価して一覧を得るというものです。
foo ;; C-u C-x C-eなど
("/home/mc/tmp/g13237.del" "/home/mc/work/log/log-2010-07-30.org" ...)
とりあえず、これでしのげましたが、なんとなくEmacs標準の方法がありそうですねー。
■ ]]>
Fri, 30 Jul 2010 16:54:38 +0900
ERBでのコメントアウトについて http://tech.actindi.net/3489112542 RailsのViewでは、ERBが使われていますが、#や、=begin、=endの範囲コメントは入れ子になった場合に使い勝手が悪いことが多いですよね。
皆さんざっくりコメントアウトするときには、どういう方法を使っているのでしょうか。
自分は、とりあえず、
<%- if false -%>
コメントアウトしたいこと
<%- end -%>
と書いたり、
def comment(&body)
end
というのを定義して、
<%- comment { -%>
コメントアウトしたいこと
<%- } -%>
などとしてみたりでしのいでいますが、もっと楽な方法はある気がしてなりません。
■ ]]>
Mon, 26 Jul 2010 14:55:42 +0900
隙があればlispを詰め込んで行きたい (6) http://tech.actindi.net/3488673731 休日の判定は思ったより色々面倒そうですが、動機がどうでも良いことだけに簡単に済ませたいところ。
ということで、休日情報のAPIが公開されていないか調べたところ、いくつかみつかったのですが、Google Calendarからjsonで手軽に情報を取得できるようなので、これを使ってみることにしました。
(DEFUN GET-CALENDAR-JSON (UT)
  (LET ((REQUEST-URL 
         (KMRCL:MAKE-URL 
          "full"
          :BASE-DIR "http://www.google.com/calendar/feeds/japanese@holiday.calendar.google.com/public/"
          :VARS `(("start-min" . ,(XYZZY:FORMAT-DATE-STRING "%Y-%m-%d" UT))
                  ("start-max" . ,(XYZZY:FORMAT-DATE-STRING 
                                   "%Y-%m-%d"
                                   (+ UT (* 24 60 60))))
                  ("max-results" . "1")
                  ("alt" . "json-in-script")
                  ("callback" . "handleJson")))))
    (STRING-TRIM "handleJson();"
                 (SB-EXT:OCTETS-TO-STRING
                  (DRAKMA:HTTP-REQUEST REQUEST-URL :FORCE-BINARY 'T)))))

(DEFUN -> (LIST &REST KEYS)
  (IF (ENDP KEYS)
      LIST
      (KMRCL:AWHEN (FIND (CAR KEYS) LIST :KEY #'ZL:CAR-SAFE)
        (APPLY #'-> KMRCL:IT (CDR KEYS)))))

(DEFUN HOLIDAY-P (&OPTIONAL (UT (GET-UNIVERSAL-TIME)))
  (LET ((DAY (NTH-VALUE 6 (DECODE-UNIVERSAL-TIME UT))))
    (OR (<= 5 DAY)
        (< 0
           (CDR
            (-> (JSON:DECODE-JSON-FROM-STRING (GET-CALENDAR-JSON UT))
                :FEED
                :OPEN-SEARCH$TOTAL-RESULTS
                :$T))))))
(HOLIDAY-P)
;⇒ 今日が休日ならT

(HOLIDAY-P (ENCODE-UNIVERSAL-TIME 0 0 0 21 7 2010))
;⇒ NIL

(HOLIDAY-P (ENCODE-UNIVERSAL-TIME 0 0 0 19 7 2010))
;⇒ T
どうやらGoogle Calendarだと今年分しか情報が取得できない様子なのですが、当日が休日なのかどうかを判定できさえすれば良いのでこれでOKとします。
■ ]]>
Wed, 21 Jul 2010 13:02:11 +0900
WordPressとActiveRecord http://tech.actindi.net/3488082520 しかし、これは既に試してみている人が絶対いそうだなと思ったので軽くググってみたところ、やはり、そのものズバリがありました。
github: jystewart / wp_ar
こんな感じで使えます。
irb(main):254:0> WpUser.count
12
150行弱のコードですが、機械的に変換する作業には割と使えるかもしれないなと思いました。
自分も、CLSQLなどで同じようなものを組んでみたいです。 ■ ]]>
Wed, 14 Jul 2010 16:48:40 +0900
Ruby で Google Analytics API http://tech.actindi.net/3487632078 こんにちは!! tahara です。 Ruby で Google Analytics API をたたいてみました。

といっても Garb を使えば簡単です。 ユーザID(email)とパスワードでも認証ができるのですが、今回は OAuth を使います。

インストール

gem install garb oauth

まずは Google Analytics, OAuth and Ruby. Oh, my. | everburning を参考に OAuth します。 あらかじめ https://www.google.com/accounts/ManageDomains から CONSUMER_KEY と CONSUMER_SECRET を取得しておく必要があります。

# -*- coding: utf-8 -*-

require 'oauth'

CONSUMER_KEY = "xxxxxx"
CONSUMER_SECRET ="xxxxxxxxx"

consumer = OAuth::Consumer.new CONSUMER_KEY, CONSUMER_SECRET, {
      :signature_method   => 'HMAC-SHA1',
      :site               => 'https://www.google.com',
      :request_token_path => '/accounts/OAuthGetRequestToken',
      :authorize_path     => '/accounts/OAuthAuthorizeToken',
      :access_token_path  => '/accounts/OAuthGetAccessToken',
    }

request_token = consumer.
  get_request_token({}, :scope => "https://www.google.com/analytics/feeds/")

# 次の URL をブラウザでアクセスし、確認コードを取得する。
p request_token.authorize_url

# 取得した確認コード
ACCESS_CODE = "xxxxxxxxx"

# 確認コードからアクセストークンを取得
access_token = request_token.get_access_token(:oauth_verifier => ACCESS_CODE)

# access_token.token と access_token.secret を取得する。
p access_token.token
p access_token.secret
ACCESS_TOKEN = access_token.token
ACCESS_SECRET = access_token.secret

# 次回からは次のようにしてアクセストークンを生成する。
access_token = OAuth::AccessToken.new(consumer, ACCESS_TOKEN, ACCESS_SECRET)

CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_SECRET がそろったので準備完了です。 Garb を使ってみます。 次は正規表現 ^/facilities/[0-9]+$ にマッチするページのページビューを取得するコードです。

# -*- coding: utf-8 -*-
=begin
http://github.com/vigetlabs/garb
=end

require "garb"
require "oauth"

CONSUMER_KEY = "xxxxx"
CONSUMER_SECRET ="xxxxxx"
ACCESS_TOKEN = "xxxxx"
ACCESS_SECRET = "xxxxx"

consumer = OAuth::Consumer.new CONSUMER_KEY, CONSUMER_SECRET, {
      :signature_method   => 'HMAC-SHA1',
      :site               => 'https://www.google.com',
      :request_token_path => '/accounts/OAuthGetRequestToken',
      :authorize_path     => '/accounts/OAuthAuthorizeToken',
      :access_token_path  => '/accounts/OAuthGetAccessToken',
    }
access_token = OAuth::AccessToken.new(consumer, ACCESS_TOKEN, ACCESS_SECRET)

Garb::Session.access_token = access_token

# プロファイル を指定
profile = Garb::Profile.first('UA-xxxxxxx-x')

class PageView
  extend Garb::Resource

  # 横に並ぶ項目。複数指定可能
  metrics :pageviews
  # 縦に並ぶ項目。複数指定可能
  dimensions :page_path
  # 並び順。複数指定可能。降順は後に .desc をつける。
  sort :pageviews.desc

  # フィルタ
  filters do
    # 正規表現で指定可能
    # http://code.google.com/intl/ja/apis/analytics/docs/gdata/gdataReferenceDataFeed.html#filters
    # http://www.google.com/support/analytics/bin/answer.py?answer=55582
    contains(:page_path, '^/facilities/[0-9]+$')
  end
end

# OpenStruct の配列で結果を取得。最大 10000 件取得できる。:offset で取得開始位置も指定可能。
res = PageView.results(profile, :start_date => '2010-07-01'.to_date, :end_date => '2010-07-07'.to_date, :limit => 10000)
# => [#<OpenStruct page_path="/facilities/159", pageviews="1237">, #<OpenStruct page_path="/facilities/164", pageviews="1061">, ...]

Data Feed Query Explorer - Google Analytics - Google Code ではブラウザから Analytics Data Export API をたたけるようになっていますので、 このページを参考にしながら、 metrics や dimensions の設定をいろいろかえると面白いことができるかもしれません。

]]>
Fri, 09 Jul 2010 11:41:18 +0900
隙があればlispを詰め込んで行きたい (5) http://tech.actindi.net/3487564229 こういうのはやっぱりsed/awkの仕事だろう、と思うのですが、一つLISPでがんばりたいところ
具体的な仕事内容ですが、
  1. 複数のエントリーがまとめられた、複数の長いテキストファイルを入力とする
  2. エントリーの区切り文字は^_
  3. エントリーごとに1ファイルにして出力
というところです。
書き捨てな感じですが、
(dolist (file (directory "/var/tmp/foo/bar/big-*.txt"))
  (dolist (mail (cl-utilities:partition-if 
                 (mycl-util:curry #'string= "^_")
                 (kmrcl:read-file-to-strings file)))
    (alexandria:with-output-to-file 
        (out (format nil "/var/tmp/result/~A" (gensym "foo-")))
      (print out)
      (dolist (line mail)
        (write-line line out)))))
のように書いてみました。
軽く解説すると、
  1. ファイル読み込み1行を要素とするリストにする
  2. PARTITION-IFでリストの中身をデリミタで1ファイル1リストとして分割する
  3. 分割した要素1リストを1ファイルとして出力。名前が被らないようにGENSYMで名前をつける
という風にしてみました。
想像していたより短く書けたので満足です。
■ ]]>
Thu, 08 Jul 2010 16:50:29 +0900
隙があればlispを詰め込んで行きたい (4) http://tech.actindi.net/3486766146 仕事の内容ですが、WordPressにはカスタムフィールドという便利機能があり、ここに入力したデータが便利にページに表示されます。
このカスタムフィールド内のHTMLを大量に変更することになりました。
具体的には、
select * from wp_postmeta where meta_key = 'こんにちは画像';
で目的の内容が取得できるので、このテキストの内容を置換して同じ場所に戻してやる、ということになります。
SQL文を書いて色々すれば良いのですが、CLSQLを使ってみることにしました。
(asdf:oos 'asdf:load-op :clsql)
(in-package :clsql-user)

(connect '("localhost" "db" "wp" "")
         :database-type :mysql)
  
(execute-command "set character_set_client='utf8'")
(execute-command "set character_set_connection='utf8'")
(execute-command "set character_set_results='utf8'"))

;; DBから読み出してSQLを出力
;; <a href=...>を<a target="_blank" href=...>に変更

(let ((ahref (ppcre:create-scanner "(<a)(\\s+)(href=.*)"))
      (window.open (ppcre:create-scanner "window.open")))
  (alexandria:with-output-to-file (out "/tmp/foo.txt")
    (do-query ((meta_id post_id meta_key meta_value)
               "select * from wp_postmeta where meta_key = 'こんにちは画像';")
      (cond ((ppcre:scan "window.open" meta_value)
             ;; 既にwindow.openで開くような指定があるばあいはスルー
             :nop)
            ('T (let ((new-val
                       (ppcre:regex-replace 
                        ahref
                        meta_value
                        (lambda (match &rest registers)
                          (declare (ignore match))
                          (destructuring-bind (a b c) registers
                            (format nil
                                    "~a target=\"_blank\"~a~a"
                                    a
                                    b
                                    c)))
                        :simple-calls 'T)))
                  (format out
                          "update wp_postmeta set meta_value = '~A' where meta_key = 'こんにちは画像' and post_id = ~A;~%" 
                          new-val
                          post_id))))))) 
内容としては、
  • CLSQLを準備
  • MySQLに接続
  • 文字コードをUTF-8に設定(任意)
  • select文を発行して結果をリストで受けとる
  • リストの内容から、目的の文を取り出しPPCRE(Common LispのPerl正規表現互換パッケージ)で処理
  • ファイルにSQL文を書き出し
今回は目的のSQLサーバーに直接接続するのが面倒だったので、ファイルにSQL文を書き出しましたが、CLSQLで接続して変更ということも勿論できます。
また、"select〜"みたいなことになっていますが、(select [...])のようにも書けるようです。
色々適当ですが、とりあえず目的は達成できました
■ ]]>
Tue, 29 Jun 2010 11:09:06 +0900
隙があればlispを詰め込んで行きたい (3) http://tech.actindi.net/3486158018 具体的には、h1、title、meta keywords、meta descriptionが記述されたCSV形式のファイルがあり、これの内容どおりになっているかをチェックする、という内容。
とりあえず、HTMLのタグの抜き出しには、Drakmaと、closure-htmlを使って、欲しいタグの内容を抜き出す関数を作成してみました。
|((:h1 ...) (:keywords ...) (:description ...) (:title ...))|という変な名前ですが、title keywords description h1を抜き出して返す関数名が思い付かなかったので返す結果の形をそのまま名前にしています。Common Lispは名前に記号も使えるので思考が停止したときに便利ですね。
(defun |((:h1 ...) (:keywords ...) (:description ...) (:title ...))| (url)
  (let* ((page (drakma:http-request url))
         (doc (chtml:parse page (cxml-stp:make-builder)))
         (ans () ))
    (stp:do-recursively (a doc)
      (when (and (typep a 'stp:element)
                 (or (string-equal (stp:local-name a) "title")
                     (string-equal (stp:local-name a) "meta")
                     (string-equal (stp:local-name a) "h1")))
        (let* ((kwd-or-dsc (cond ((string-equal (stp:attribute-value a "name")
                                                "description")
                                  `(:description
                                    ,(stp:attribute-value a "content")))
                                 ((string-equal (stp:attribute-value a "name")
                                                "keywords")
                                  `(:keywords
                                    ,(stp:attribute-value a "content")))))
               (tag (intern (string-upcase (stp:local-name a)) :keyword))
               (svalue (stp:string-value a))
               (tem () ))
          (cond ((and (string= "" svalue)
                      (eq :meta tag))
                 :nop)
                ('T (push svalue tem)
                    (push tag tem)))
          (when kwd-or-dsc
            (push (cadr kwd-or-dsc) tem)
            (push (car kwd-or-dsc) tem))
          (and tem (push tem ans))
          )))
    ans))
この|((:h1 ...) (:keywords ...) (:description ...) (:title ...))|を使って
(progn
  (print '////////////////////////////////////////////////////////////////)
  (dolist (x (fare-csv:read-csv-file "foo.csv"))
    (destructuring-bind (url title kwd dsc h1) x
      (let* ((url (ppcre:regex-replace "://www.example.com" ;CSVファイルのURL
                                       url
                                       "://www.example.net")) ;実際のサーバーのURL
             (q (|((:h1 ...) (:keywords ...) (:description ...) (:title ...))| url)))
        (flet ((*check (var key)
                 (string= var (second (assoc key q)))))
          (cond ((and (*check h1 :h1)
                      (*check kwd :keywords)
                      (*check dsc :description)
                      (*check title :title))
                 :nop)
                ('t
                 (flet ((frob (var key)
                          (list key
                                (if (*check var key)
                                    :ok
                                    (list :ng var (second (assoc key q)))))))
                   (print '*******************************************)
                   (print url)
                   (print (frob h1 :h1))
                   (print (frob kwd :keywords))
                   (print (frob dsc :description))
                   (print (frob title :title))))))))))
のように殴り書きしてみました。キーワードが一致していないと
////////////////////////////////////////////////////////////////
*******************************************
"http://www.example.com/foo/bar" 
(:H1 (:NG "こんにちは" "Routing Error")) 
(:KEYWORDS (:NG "なるほど" NIL)) 
(:DESCRIPTION (:NG "なんのことですか?" NIL)) 
(:TITLE (:NG "mjd!" "Action Controller: Exception caught")) 
...
のような結果がREPLに出てきます。
なんだか長いですけど、Common Lispで書いても実行を確認しながら書けるので、そんなに大変でもありません。
■ ]]>
Tue, 22 Jun 2010 10:13:38 +0900
Google Data APIs Objective-C Client LibraryをiOS SDKで使用するための準備 http://tech.actindi.net/3485836586 こんにちは。masudaです。

今回はGoogle Data APIs Objective-C Client LibraryをiOS SDKで使用するための準備について書きたいと思います。

Google Data APIs Objective-C Client LibraryはGoogleの様々なサービスをObjective-Cから使うことができるライブラリです。
Google Data APIs Objective-C Client Library

あらかじめGData.xcodeprojを、ライブラリを使用したいプロジェクトの「ファイルとグループ」欄に追加しておきましょう。

ライブラリをコンパイルする

コンパイルオプションを指定してコンパイルします。
今回はPicasaサービスとそれに付随してOAuthを使用したので、以下のオプションを指定しました。

-DGDATA_INCLUDE_PHOTOS_SERVICE=1
-DGDATA_INCLUDE_OAUTH=1

iPhone Simulator版とiPhone OS版をReleaseでコンパイルします。

lipoでFat Binaryにする

cd build
lipo -create Release-iphoneos/libGDataTouchStaticLib.a Release-iphonesimulator/libGDataTouchStaticLib.a -output libGDataTouchStaticLib.a

コンパイルしたライブラリをXcodeに追加する

  • Xcodeの「ターゲット」でアプリを指定し右クリックし「情報を見る」を選択。
  • 「一般」 – 「リンク済みライブラリ」の下の「+」をクリック。
  • 「その他を追加…」をクリックし、さきほどコンパイルしたlibGDataTouchStaticLib.aを選択。

コンパイルするための設定を追加する

  • プロジェクトを右クリックし、「情報を見る」を選択。
  • 「ビルド」を選ぶ。
  • 「ヘッダ検索パス」に/usr/include/libxml2を追加。
  • 「ユーザヘッダ検索パス」にライブラリのフォルダを追加(このとき「再帰的」にチェックを入れる)。
  • 「常にユーザパスを検索」にチェックを入れる。
  • 「他のリンカフラグ」に -all_load -ObjC -lxml2 を指定。

参考文献

]]>
Fri, 18 Jun 2010 16:56:26 +0900
隙があればlispを詰め込んで行きたい (2) http://tech.actindi.net/3485257703 今回もネタがないのでLISPネタです。
日常の作業では、テキストファイルを加工することが割とあったりすると思いますが、そういう時には、sedや、awkって便利ですよね。
ちょっとした一行野郎が大活躍、ということは結構あると思います。
自分もそういう一行野郎が好きではあるのですが、いやしかし、隙があればlispを詰め込んで行きたい。
最近もsedを使いたくなるようなHTMLの編集作業に遭遇しました。
「指定したディレクトリ以下に含まれるすべてのHTMLファイルの<div class="foo"から、</div>の間を、用意したテキストファイルの内容と置き換える。」
という仕事です。
sedで一発だろうと思いましたが、とりあえず、Common Lispで書いてみました。
(LOOP :FOR FILE :IN
   (DIRECTORY "/tmp/foo/**/*.html")
   :DO
   (WITH-OPEN-FILE (IN FILE)
     (WITH-OPEN-FILE (OUT (FORMAT NIL "~A.new.html" (PATHNAME FILE))
                          :DIRECTION :OUTPUT
                          :IF-EXISTS :SUPERSEDE
                          :IF-DOES-NOT-EXIST :CREATE)
       (LOOP :WITH OPEN 
          :FOR LINE := (READ-LINE IN NIL NIL) :WHILE LINE
          :DO (PROGN
                (WHEN (SEARCH "
" LINE) (SETQ OPEN 'T)) (COND ((AND OPEN (SEARCH "
" LINE)) (SETQ OPEN NIL) (WITH-OPEN-FILE (IN2 "g000001/foo.html") (LOOP :FOR LINE := (READ-LINE IN2 NIL NIL) :WHILE LINE :DO (WRITE-LINE LINE OUT)))) ((NOT OPEN) (WRITE-LINE LINE OUT))) )))))
気分は一行野郎なのでコードもいきあたりばったりで汚ないです。
これで仕事は片付いたのですが、率直な感想として、sedに比べると書くのがかなりめんどくさいです。(一切ライブラリを使ってないということもありますが…)
こんなにめんどうでは、やっぱりCommon Lispよりsedを使ってしまいます。
いやしかし、こういう道具を沢山書き溜めておいて、必要なときにさっと出せるようになれば、そのうちsedやawkではなく、自然にCommon Lispを使うようになるかもしれません。
ということで、若干無理はあるものの、コードを纒めて次の機会に備えておくことにしました。
(DEFUN SED (START-PAT END-PAT NEW 
            &KEY (IN *STANDARD-INPUT*) (OUT *STANDARD-OUTPUT*))
  (LOOP :WITH OPEN 
        :FOR LINE := (READ-LINE IN NIL NIL) :WHILE LINE
        :DO (PROGN
              (WHEN (SEARCH START-PAT LINE)
                (SETQ OPEN 'T))
              (COND ((AND OPEN (SEARCH END-PAT LINE))
                     (SETQ OPEN NIL)
                     (WRITE-LINE NEW OUT))
                    ((NOT OPEN)
                     (WRITE-LINE LINE OUT))))))

(DEFUN MAP-FILE-INTO (FILES FUNCTION)
  (LET ((TEMPNAME-SUFFIX (GENSYM "TEMP-FILE-")))
    (DOLIST (FILE FILES)
      (LET ((TEMPFILE-NAME (FORMAT NIL "~A_~A" FILE TEMPNAME-SUFFIX)))
        (WITH-OPEN-FILE (IN FILE)
          (WITH-OPEN-FILE (OUT TEMPFILE-NAME
                           :DIRECTION :OUTPUT
                           :IF-EXISTS :SUPERSEDE
                           :IF-DOES-NOT-EXIST :CREATE)
            (FUNCALL FUNCTION IN OUT)))
        (RENAME-FILE TEMPFILE-NAME FILE)))))
この2つを使えば、今回の仕事は、
(MAP-FILE-INTO (DIRECTORY "**/*.html")
               (LAMBDA (IN OUT)
                 (SED "<div class='foo'>"
                      "</div>"
                      (KL:READ-FILE-TO-STRING "foo.txt")
                      :IN IN
                      :OUT OUT)))
のように書けます。
いまのところぱっとしませんが、そのうちCommon Lispだけでテキスト仕事は片付けられるようになることを目指します!
■ ]]>
Sat, 12 Jun 2010 00:08:23 +0900
Lisp on Rails 第9回 〜 ビュー http://tech.actindi.net/3484714545 こんにちは!! tahara です。 Objective-C づけになり、すっかりこぶさたしておりましたが Lisp on Rails 第9回です!

今回はビューです。 Common Lisp で ERB 相当を実装します。 Common Lisp で実装するからにはリードテーブルを使い、 HTML ファイルを関数にコンパイルしたいと思います。

HTML ファイルを関数にコンパイルソースは http://github.com/quek/lisp-on-rails/blob/master/action-pack/ecl.lisp です。

ところどころ説明させていただきます。 html-defun-readtable ではビューファイルの最初の1文字をマクロキャラクタにして、 先頭に (in-package :xxxx) を追加し、全体を (defun xxxx () ...) でくるむようにしています。 動的にリーダをカスタマイズしているのです。 これでビューファイルを1つの関数として読み込むことができるようになります。

(defun html-defun-readtable (fname pathspec)
  (let ((*readtable* (basic-readtable)))
    (set-macro-character
     (first-char pathspec)
     (let ((in-package t))
       (lambda (stream char)
         (unread-char char stream)
         (print
          (if in-package
              (progn
                (setf in-package nil)
                `(in-package ,(package-name action-controller:*app-package*)))
              `(defun ,fname ()
                 ,(body-code stream char)))))))
    *readtable*))

Rails ではコントローラからビューへの値の受け渡しは @foo のようなインスタンス変数が使われます。 それに対応するためビューファイルの中に @ で始まるシンボルがあれば、 コントローラのスロット値へのアクセスに変換するシンボルマクロを定義します。

(defun body-code (stream char)
  (walk-body-code (read-body-code stream char)))

(defun read-body-code (stream char)
  (let ((*readtable* (make-html-readtable char)))
    (loop for x = (read stream nil stream t)
          until (eq x stream)
          collect x)))

(defun walk-body-code (code)
  `(symbol-macrolet
       ,(series:collect
            (series:mapping
             ((x (series:choose-if (q:^ q:symbol-head-p _ "@")
                                   (series:scan-lists-of-lists-fringe code))))
             `(,x (slot-value action-controller:*controller*
                              ',(intern (subseq (symbol-name x) 1)
                                        action-controller:*app-package*)))))
     ,@code))

そんなこんなで、なんとかモデル、コントローラ、ビューが繋がりました。

モデル

(in-package :blog)

(def-record post
  (:has-many comments))

(def-record comment
  (:belongs-to post))

コントローラ。生の defclass です。

(in-package :blog)

(defclass top-controller (application-controller)
  ((message)
   (posts)))

(defmethod index ((self top-controller))
  (with-slots (message posts) self
    (setf message "まみむめも♪"
          posts (all post))))

ビュー。HTML タグと loop が混在するのもまた一興ですね。

<!doctype html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>ブログ</title>
  </head>
  <body>
    <h1><%= @message %></h1>
    <h2>投稿を loop で表示する</h2>
    <ul><% (loop for post in @posts for comments = (comments-of post) do %>
      <li><%= (content-of post) %> -- <%= (name-of post) %></li>
      <% if comments do %>
      <ul><% (loop for comment in comments do %>
        <li><%= (body-of comment) %> -- <%= (commenter-of comment) %></li><% ) %>
      </ul><% ) %>
    </ul>
  </body>
</html>

コントローラは次のように書けるようにすると、それっぽい気もしますが、いまはまだ書けません。

(def-controller top (application)
  (def-action index
      (setf @message "まみむめも♪"
            @posts (all post)))
  (def-action foo
      (setf @essage "foo")))

以上、まとめますと 「リーダをいじれる言語は素敵ですね!」 でした。

ソースはこちらから http://github.com/quek/lisp-on-rails

第10回につづきます。

]]>
Sat, 05 Jun 2010 17:15:45 +0900
macroexpandでHTMLを書く http://tech.actindi.net/3484452177 今回もネタがないのでEmacsネタです。
Dylanのマクロについての文献:
http://people.csail.mit.edu/jrb/Projects/dexprs.pdf を読んでいて、XMLや、LISPは、Skeleton Syntax Tree Representationsに分類されるというのを読んで、そうか、HTMLも簡単にマクロ書けたりするのかもと思ったのでEmacs Lispでちょっと試してみました。
(defun split-id-or-class (string)
  (let ((elts (split-string string "[\\.#]")))
    (if (cdr elts)
        elts
        string)))

(defmacro defhtmltag (tag)
  (let* ((tag-str (symbol-name tag))
         (tags (split-string tag-str "[\\.#]"))
         (tag-name (car tags))
         (attr (cadr tags)))
    `(defmacro ,tag (&rest body)
       `(list ,(concat
                "<"
                ,tag-name 
                (apply #'concat 
                       (cond ((find ?. ,tag-str)
                              (list " class=\"" ,attr "\""))
                             ((find ?# ,tag-str)
                              (list " id=\"" ,attr "\""))
                             ('T (list ""))))
                ">")
              ,@body
              ,(concat "</" ,tag-name ">")))))

(defun flatten (lis)
  (cond ((atom lis) lis)
        ((listp (car lis))
         (append (flatten (car lis)) (flatten (cdr lis))))
        (t (append (list (car lis)) (flatten (cdr lis))))))

(defmacro with-html-output-to-string (&rest body)
  `(reduce (lambda (x y) (format "%s%s" x y))
           (flatten (list ,@body))))
使い方としては、
(defhtmltag li.foo)
のようにすると、
(list "<li>" "こんにちは" "</li>")
のようなものにマクロが展開されるので、リストの入れ子を平坦にして一つの文字列に繋げれば完成です。
ちょっと込み入ったところだと
(defhtmltag table)
(defhtmltag tbody)
(defhtmltag td)
(defhtmltag tr)

(defun list-to-table (list)
  (table 
   (tbody
    (mapcar (lambda (x)
              (tr
               (mapcar (lambda (y) (td y))
                       x)))
            list))))

(insert
 (with-html-output-to-string
  (list-to-table '((foo bar baz quux)
                   (1 2 3 4)
                   (z z z z)))))
;=> <li class="foo"><li class="foo"><li class="foo"><li class="foo">foo</li><li class="foo">bar</li><li class="foo">baz</li><li class="foo">quux</li></li><li class="foo"><li class="foo">1</li><li class="foo">2</li><li class="foo">3</li><li class="foo">4</li></li><li class="foo"><li class="foo">z</li><li class="foo">z</li><li class="foo">z</li><li class="foo">z</li></li></li></li>
ということもできます。
ちなみに、マクロ展開でHTML書くって新しいかも!と思いましたが、別にマクロにしなくても関数でも書けることに今気付きました…
とりあえず、もし、HTMLにマクロがあったとしたらLISPと似た感じになるのかなあという印象は持ちました。
■ ]]>
Wed, 02 Jun 2010 16:22:57 +0900
隙があればlispを詰め込んで行きたい http://tech.actindi.net/3483760148 今回もネタがないのでEmacsネタです。 日常のちょっとしたテキストの編集作業なのですが、
app/views/top/foo.html.erb
app/views/shared/_foo.html.erb
app/views/shared/foo.html.erb
app/views/top/_foo.html.erb
app/views/shared/foo.html.erb
app/views/layouts/application.html.erb
config/links/foo.html.erb
public/images/shared/foo.jpg
のようなテキストをスペース区切りの一行にまとめる必要に迫られました。
ここはEmacsで、改行をスペースに置換してやれば良いんじゃないかと思いますが、いや、ここは踏ん張ってlispを書いてゆきたいと思い、
(mapconcat (lambda (x) (format "%s" x))
'(
app/views/top/foo.html.erb
app/views/shared/_foo.html.erb
app/views/shared/foo.html.erb
app/views/top/_foo.html.erb
app/views/shared/foo.html.erb
app/views/layouts/application.html.erb
config/links/foo.html.erb
public/images/shared/foo.jpg
)
" ") 
のようなものを書いて、式のにカーソルを持っていって、C-u C-x C-eです。
そうすると、式の後ろに
=> "app/views/top/foo.html.erb app/views/shared/_foo.html.erb app/views/shared/foo.html.erb app/views/top/_foo.html.erb app/views/shared/foo.html.erb app/views/layouts/application.html.erb config/links/foo.html.erb public/images/shared/foo.jpg"
のようなものが挿入されます。lambdaって書けて良かったですよね。
次に、
A    app/views/top/foo.html.erb
M    app/views/shared/_foo.html.erb
M    app/views/shared/foo.html.erb
M    app/views/top/_foo.html.erb
?    app/views/shared/foo.html.erb
M    app/views/layouts/application.html.erb
A    config/links/foo.html.erb
M    public/images/shared/foo.jpg
のようなテキストでファイル名の部分だけ、一行にスペース区切りでつなげる必要に迫られました。
ここは、Emacsで、kill-rectangleでしょうか。いや、ここは踏ん張ってlispを書いてゆきたいと思い、
(apply #'concat
(loop for (x y) on 
'(
A    app/views/top/foo.html.erb
M    app/views/shared/_foo.html.erb
M    app/views/shared/foo.html.erb
M    app/views/top/_foo.html.erb
?    app/views/shared/foo.html.erb
M    app/views/layouts/application.html.erb
A    config/links/foo.html.erb
M    public/images/shared/foo.jpg
)
by #'cddr
collect (format "%s " y))
)
のようなものを書き、上と同じく、eval-last-sexp すると
"app/views/top/foo.html.erb app/views/shared/_foo.html.erb app/views/shared/foo.html.erb app/views/top/_foo.html.erb app/views/shared/foo.html.erb app/views/layouts/application.html.erb config/links/foo.html.erb public/images/shared/foo.jpg "
という文字列が得られます。
なるほど、これは、shell-command-on-regionで、awk '{if($1=="M"){printf("%s ", $2);}}'とかしている場合ではないですね。
Emacs便利です。
■ ]]>
Tue, 25 May 2010 16:09:08 +0900
EmacsでGoogle Chart http://tech.actindi.net/3483310778 今回もネタがないのでEmacsで遊んでいたネタを。
Googleは、便利にグラフを書けるAPIであるGoogle Chart APIというのを提供しています。
URLを指定するだけで、グラフが書けたり、QRコードが書けたり色々便利なものですが、数値のリストからスタックされた棒グラフを書いてみようと思ったので、ちょっと遊んでみました。
(defun* gchart-stack-bar-chart-url (data &key (style :horizontal))
  (let ((len (length data)))
    (concat
     "http://chart.apis.google.com/chart?"
     "cht=b" (case style
               (:horizontal "hs")
               (otherwise "vs")) 
     "&chd=t:"
     (let* ((totals (mapcar (lambda (x)
                              (apply #'+ x))
                            data))
            (max (apply #'max totals))
            (to-string (lambda (x) (format "%s" x))))
       (mapconcat 
        to-string
        (mapcar 
         (lambda (x)
           (mapconcat
            to-string x ","))
         (apply #'mapcar*
                #'list
                (mapcar
                 (lambda (x) 
                   (mapcar
                    (lambda (y)
                      (format "%.1f"
                              (* (/ 100 max) y)))
                    x))
                 data)))
        "|"))
     "&chco=ff0000,00ff00,0000ff"
     "&chs=350x"
     (int-to-string (* len 28)))))
(let ((data '((10 20 30)
              (3 50 1)
              (1 2 3)
              (33 33 33)
              (5 6 7)
              (33 33 33)
              (3 3 9))))
  (browse-url (gchart-stack-bar-chart-url data)))
これで、

のようなグラフが書けます。
タイトルも付けられるようですが、飽きてしまいました
Emacs便利です。
■ ]]>
Thu, 20 May 2010 11:19:38 +0900
確認恐怖症をEmacsが救う http://tech.actindi.net/3482813168 ネタがないので今回もEmacsの小ネタです。
Emacsには、LISPが搭載されているので、ちょっとしたLISPを書くことでも色々便利に使えます。
代表的なところとしては、ちょっとした計算でしょうか
(+ 1500
  200
 3000
 4500
)
;⇒ 9200
S式の前置記法がこういう場合には便利です。
最近、SSLの申請で、更新するCSRを確認することがあったのですが、こういう確認の為の文字列比較にも使えることに気付きました。
(equal
"-----BEGIN CERTIFICATE REQUEST-----
MIICijCCAXICAQAwRTELMAkGA1UEBhMCSlAxEzARBgNVBAgTClNvbWUtU3RhdGUx
ITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAM7k/tno3FquqOOrhkFxCiAVx/0qPjjcOhcD0PXx
ZCgSd6vHK0oSjDrWl+KFRMISd+EECBIrWR0I/u3RywKmlj1Q29wgt+UzFFJSK5+k
wsiQTnxs//uAqWoLBUUU3Y0/67P+cJSqflAcGgt8imhXEh2GzfPPKfB9nK3P4MZ7
WcrKvTwUEewASdaBWU+8+4ic8JzIwiCLge6tQvf/xeqkBhp7Othsf9vmwGARjDaI
DPSswlaKqkaXEog9fhhJmO2QUzEQ9R92MNmxu+wXHKxx3LuC4dvnoNNFz1l+cPq9
3wVoLBIaEBw8U06+BEPtlAf8ZRGYVG7LpxvhyS0EdDirN0MCAwEAAaAAMA0GCSqG
SIb3DQEBBQUAA4IBAQAF/Stfy58MQFRCmXZxaiKK1Ez9CBdyBtbCM+xquYzfRTMg
EEmGRXoZ1FomV2B2avkUU0frOnb3cktfuttBs1olwKvf3lzktdRoQBPrzDy7iAej
p4MwQHEmFgVXe3ZstjoYIQ2PudSPUlCQRUAi9oiNjVt0iAY7w1xnlCMqYTzGBW4y
8MpnVDKtTmmMPM0wxtiKDkOmT3S8L/mR1wNDnpavv5hOIn8z7No+qHzkLcuHEHYF
IVn9suw6L2GvPgxdw4XarWoFjeuADhszwwVpI87oGMH3H5Z6kniW22bQX1l402dO
YqSaxgasSPwJi+3njg0upYERIV7i9fR74/tufNv7
-----END CERTIFICATE REQUEST-----"

"-----BEGIN CERTIFICATE REQUEST-----
MIICijCCAXICAQAwRTELMAkGA1UEBhMCSlAxEzARBgNVBAgTClNvbWUtU3RhdGUx
ITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBAM7k/tno3FquqOOrhkFxCiAVx/0qPjjcOhcD0PXx
ZCgSd6vHK0oSjDrWl+KFRMISd+EECBIrWR0I/u3RywKmlj1Q29wgt+UzFFJSK5+k
wsiQTnxs//uAqWoLBUUU3Y0/67P+cJSqflAcGgt8imhXEh2GzfPPKfB9nK3P4MZ7
WcrKvTwUEewASdaBWU+8+4ic8JzIwiCLge6tQvf/xeqkBhp7Othsf9vmwGARjDaI
DPSswlaKqkaXEog9fhhJmO2QUzEQ9R92MNmxu+wXHKxx3LuC4dvnoNNFz1l+cPq9
3wVoLBIaEBw8U06+BEPtlAf8ZRGYVG7LpxvhyS0EdDirN0MCAwEAAaAAMA0GCSqG
SIb3DQEBBQUAA4IBAQAF/Stfy58MQFRCmXZxaiKK1Ez9CBdyBtbCM+xquYzfRTMg
EEmGRXoZ1FomV2B2avkUU0frOnb3cktfuttBs1olwKvf3lzktdRoQBPrzDy7iAej
p4MwQHEmFgVXe3ZstjoYIQ2PudSPUlCQRUAi9oiNjVt0iAY7w1xnlCMqYTzGBW4y
8MpnVDKtTmmMPM0wxtiKDkOmT3S8L/mR1wNDnpavv5hOIn8z7No+qHzkLcuHEHYF
IVn9suw6L2GvPgxdw4XarWoFjeuADhszwwVpI87oGMH3H5Z6kniW22bQX1l402dO
YqSaxgasSPwJi+3njg0upYERIV7i9fR74/tufNv7
-----END CERTIFICATE REQUEST----"
)
;⇒ nil
Emacs便利です。
■ ]]>
Fri, 14 May 2010 17:06:08 +0900
Apache で特定の User-Agent だけ BASIC 認証をバイパスする方法 http://tech.actindi.net/3482790616 こんにちは!! tahara です。 iPhone アプリからのアクセス以外はベーシック認証でブロックしたい、というときのお話です。 この設定で User-Agent に CFNetwork が含まれていない場合だけベーシック認証が必要になります。

<Location />
  Satisfy Any
  BrowserMatchNoCase CFNetwork is_iPhone=1
  Order Deny,Allow
  Deny from all
  Allow from env=is_iPhone

  AuthUserFile /var/www/htpasswd
  AuthGroupFile /dev/null
  AuthName "Please enter username and password"
  AuthType Basic
  require valid-user
</Location>

これでステージング環境が Google に補足されることもなくなるはずです。

]]>
Fri, 14 May 2010 10:50:16 +0900
letの束縛部分を便利に編集したい http://tech.actindi.net/3482117931 (let ((str "foo bar baz")) .... (setq len (length str))) という風に書いていて、後でlenが欲しくなるような
つまり
(let ((str "foo bar baz")
      (len 0))
  ....

  (setq len (length str)))
こういう風に前に戻って(len 0)を追加したいわけですね。
思い立ったが吉日なのでそういうelispを書いてみることにしました。
(progn
  (defun edit-let-bind ()
    (interactive)
    (let ((foundp nil))
      (save-excursion
        (catch 'loop
          (while (not (c-at-toplevel-p))
            (backward-up-list)
            (down-list)
            (let ((thing (thing-at-point 'symbol)))
              (cond ((or (string= "let" thing)
                         (string= "do" thing))
                   (down-list)
                   (setq foundp t)
                   (throw 'loop nil))
                  ('T (backward-up-list))))))
        (when foundp
          (recursive-edit)))))
  ;; keybind
  (define-key global-map [(control meta shift ?c)] 'edit-let-bind))
非常に適当な作りですが、letや、doの束縛部を編集するために、再帰編集モードに入り、束縛部分にカーソルを飛し、編集が終わったら、再帰編集モードから抜ける、という風にしてみました。
再帰編集モードから抜けるのが、C-M-cだったので、C-M-sh-cで、束縛部の編集へ。
一応それなりに便利に使えますが、どなたかもっとちゃんとした、elispの流儀に則ったものを作成して頂けると嬉しいです! ■ ]]>
Thu, 06 May 2010 15:58:51 +0900
空白一つにこだわりたい http://tech.actindi.net/3481435886 ネタがないので今回もEmacs lispの小ネタです。
文字列やS式をだらだら編集し、最後に空白一つ区切りで整形しようとしたときなのですが、間に改行が挟まっていると、just-one-spaceがきかないので、kill-lineしたりして調整することになります。
"foo
   bar
      baz"
=>
"foo bar baz"
自分はこれが非常にもどかしかったので、just-one-spaceを拡張したものを作成してみました。
といっても、just-one-spaceのソースが空白とタブしか飛していなかったので改行も加えただけです。
(defun just-one-space-to-next-sexp (&optional n)
  (interactive "*p")
  (let ((orig-pos (point)))
    (skip-chars-backward " \t\n")
    (constrain-to-field nil orig-pos)
    (dotimes (i (or n 1))
      (if (or (= (following-char) ?\s))
	  (forward-char 1)
	(insert ?\s)))
    (delete-region
     (point)
     (progn
       (skip-chars-forward " \t\n")
       (constrain-to-field nil orig-pos t)))))
;; キーバインド例
(define-key  global-map [(meta shift ?\s)] 'just-one-space-to-next-sexp)
これで、すぱっと隣りに揃えられるので気持良いです。
リージョンやリストの中身を処理してくれる関数もあったら便利かもしれません。
■ ]]>
Wed, 28 Apr 2010 18:31:26 +0900
Objective-Cでメンバ変数に動的にアクセスする方法 http://tech.actindi.net/3481147128 こんにちは。masudaです。

今回、複数回使い回したいViewがあったのですが、一方で様々なところで使われるものではありませんでした。
こんなときにわざわざクラスを作るのはどうも重い感じがしてしまいます。
そこでUIViewのサブクラスを作らずに、メソッドで作ることにしました。

  • UIViewController
    • 今回作成したいView
    • 今回作成したいView

というように複数個必要です。
このViewの中身はUILabelが2つだけ。

さらに出来ることなら、作成するViewの中身であるUILabelを、このViewを持っているViewControllerのメンバ変数からアクセスしたい。
以前はTagを割り当ててアクセスしていたのですが、以外と面倒だったのでそれ以外の方法がないかどうか調べてみました。

実際には以下のようなコードを使用することで出来ました。

#include <objc/runtime.h>
 
@implementation HogeViewController
 
- (UIView *)generateView:(NSString *)titleLabelName contentLabelName:(NSString *)contentLabelName
{
    UIView   *resultView;
    UILabel  *titleLabel, *contentLabel;
 
    // 便宜上CGRectZeroを使います。
    resultView = [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
 
    titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
    [resultView addSubview:titleLabel];
    [titleLabel release];
 
    object_setInstanceVariable(self, [titleLabelName UTF8String], titleLabel);
 
    contentLabel = [[UILabel alloc] initWithFrame:CGRectZero];
    [resultView addSubview:contentLabel];
    [contentLabel release];
 
    object_setInstanceVariable(self, [contentLabelName UTF8String], contentLabel);
 
    return resultView;
}
 
@end

titleLabelName, contentLabelNameにはそれぞれに割り当てたいメンバ変数の名称を指定します。
こんな感じにobject_setInstanceVariable関数を使用してあげれば、割り当てたいメンバ変数に割り当てることが出来ます。

P.S.
といいつつも、実は様々なところで使われる必要がわかり、まじめにUIViewのサブクラスを作成したため、上記のコードはお蔵入りになりました。

参考文献

]]>
Sun, 25 Apr 2010 10:18:48 +0900
関連する単語 http://tech.actindi.net/3481090705 こんにちは!! tahara です。

少々事情があってある単語に関連する単語を自動的に取得したくなりました。 『集合知イン・アクション』 を参考に Common Lisp で書いてみました。

Yahoo の Web API を利用させていただきます。

  • ウェブ検索とブログ検索で単語に関連するテキストを収集
  • 日本語形態素解析で単語に分解
  • 単語からタームベクトルを作成
(eval-when (:compile-toplevel :load-toplevel :execute)
  (require :drakma)
  (require :cxml)
  (require :cl-ppcre))

(defparameter *words*
  '("アナウンサー" "お医者さん" "イラストレーター" "宇宙飛行士"
    "タクシー運転手" "電車運転士" "バス運転士" "映画監督" "絵本作家"
    "演奏家" "歌手" "カメラマン" "看護師" "外交官" "画家" "高校の先生"
    "小学校の先生" "中学校の先生" "気象予報士" "キャビンアテンダント"
    "救急救命士" "銀行員" "警察官" "裁判官" "作詞家" "サッカー監督"
    "サッカー選手" "作曲家" "シェフ" "指揮者" "社長" "小説家" "消防士"
    "新聞記者" "動物のお医者さん" "政治家" "声優" "船長" "大工" "図書館司書"
    "俳優" "花火師" "花屋" "パイロット" "パン屋さん" "美容師"
    "ピアノニスト" "プロ野球選手" "弁護士" "幼稚園の先生")
  "これらの単語に関連する単語が欲しいのです。")

(defparameter *yahoo-appid*
  "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  "Yahoo Web API の アプリケーションID")
(defparameter *yahoo-ma-url* "http://jlp.yahooapis.jp/MAService/V1/parse"
  "日本語形態素解析")
(defparameter *yahoo-web-search-url*
  "http://search.yahooapis.jp/WebSearchService/V1/webSearch"
  "ウェブ検索")
(defparameter *yahoo-blog-search-url*
  "http://search.yahooapis.jp/BlogSearchService/V1/blogSearch"
  "ブログ検索")

(defparameter *occurrence-threshold* 5
  "これより少ない出現頻度の単語は無視します。")
(defparameter *stop-words*
  '("あれ" "いい" "こんな" "こちら" "こと" "これ" "それ" "ため" "とき" "ない"
    "もの" "よく"
    "以上" "一覧" "最新"
    "amp" "at" "by" "com" "gt" "http" "https" "jp" "lt")
  "これらの単語は無視します。")
(defparameter *stop-words-regexps*
  (mapcar #'ppcre:create-scanner
          '("^[0-90-9]+$" "^.$"))
  "これらの正規表現に一致する単語ま無視します。")

;; Drakma の設定
(setf drakma:*drakma-default-external-format* :utf-8)
(pushnew '("application" . "xml") drakma:*text-content-types* :test #'equal)

(defun stop-word-p (word)
  (or (find word *stop-words* :test #'string=)
      (some (lambda (x) (ppcre:scan x word)) *stop-words-regexps*)))

(defun yahoo-ma-request (text)
  (drakma:http-request
   *yahoo-ma-url*
   :method :post
   :parameters `(("appid" . ,*yahoo-appid*)
                 ("filter" . "1|9") ; 形容詞 名詞
                 ("sentence" . ,text))))

(defun text-to-words (text)
  (destructuring-bind (result-set
                       schema-location
                       (ma-result
                        _
                        total-count
                        filtered-count
                        word-list))
      (cxml:parse (yahoo-ma-request text) (cxml-xmls:make-xmls-builder))
    (declare (ignorable result-set schema-location ma-result _
                        total-count filtered-count))
    (loop for (_a _b (_c _d word)) in (cddr word-list)
         collect word)))

(defun yahoo-web-search-request (query)
  (drakma:http-request
   *yahoo-web-search-url*
   :method :get
   :parameters `(("appid" . ,*yahoo-appid*)
                 ("query" . ,query)
                 ("results" . "50")
                 ("format" . "html"))))

(defun web-search (query)
  (destructuring-bind (result-set
                       pgr . results)
      (cxml:parse (remove #\lf (yahoo-web-search-request query))
                  (cxml-xmls:make-xmls-builder))
    (declare (ignorable result-set pgr))
    (loop for (result _a (_title _b title) (_summary _c summary)) in results
         collect (list title summary))))

(defun yahoo-blog-search-request (query)
  (drakma:http-request
   *yahoo-blog-search-url*
   :method :get
   :parameters `(("appid" . ,*yahoo-appid*)
                 ("query" . ,query)
                 ("results" . "50"))))

(defun blog-search (query)
  (destructuring-bind (result-set first-result-position . results)
      (cxml:parse (remove #\lf (yahoo-blog-search-request query))
                  (cxml-xmls:make-xmls-builder))
    (declare (ignorable result-set first-result-position))
    (loop for (result _a id rss-url (_title _b title)
                      (_description _c description)) in results
         collect (list title description))))

(defun word-to-word-list (word)
  (remove-if #'stop-word-p
             (loop for i in '(web-search blog-search)
                append (text-to-words
                        (format nil "~{~{~a ~a ~}~}" (funcall i word))))))

(defun word-count-alist (word)
  (let (alist)
    (loop for i in (word-to-word-list word)
       if (assoc i alist :test #'string=)
       do (incf (cdr (assoc i alist :test #'string=)))
       else
       do (setf alist (acons i 1 alist)))
    (setf alist (sort alist #'(lambda (x y)
                                (>= (cdr x) (cdr y)))))
    (remove-if (lambda (x) (< (cdr x) *occurrence-threshold*)) alist)))

(defun normalize (alist)
  "重みづけを、その平方和が 1 とらるように正規化する。"
  (loop with factor = (sqrt (loop for i in alist sum (expt (cdr i) 2)))
       for (word . magnitude) in alist
       collect (cons word (/ magnitude factor))))

(defun all-word-alist ()
  (loop for word in *words*
     collect (print (cons word (normalize (word-count-alist word))))))

出力は次のとおりです。

("宇宙飛行士" ("宇宙" . 0.7740145) ("飛行士" . 0.5890963) ("山崎" . 0.09774244)
 ("若田" . 0.06604219) ("野口" . 0.05547544) ("地球" . 0.05547544)
 ("訓練" . 0.050192066) ("ステーション" . 0.047550377) ("毎日新聞" . 0.044908687)
 ("日本人" . 0.042267002) ("国際" . 0.042267002) ("日本" . 0.039625313)
 ("直子" . 0.039625313) ("スペースシャトル" . 0.03434194) ("ニュース" . 0.03434194)
 ("シャトル" . 0.03170025) ("帰還" . 0.03170025) ("家族" . 0.03170025)
 ("写真" . 0.029058563) ("ISS" . 0.029058563) ("情報" . 0.026416875)
 ("光一" . 0.026416875) ("聡一" . 0.026416875) ("JAXA" . 0.023775188)
 ("活動" . 0.023775188) ("飛行" . 0.023775188) ("紹介" . 0.023775188)
 ("産経新聞" . 0.023775188) ("映像" . 0.021133501) ("ミッション" . 0.021133501)
 ("NASA" . 0.021133501) ("交信" . 0.021133501) ("職業" . 0.018491814)
 ("毛利" . 0.018491814) ("滞在" . 0.018491814) ("撮影" . 0.018491814)
 ("研究" . 0.018491814) ("女性" . 0.018491814) ("サイト" . 0.018491814)
 ("搭乗" . 0.015850125) ("ページ" . 0.015850125) ("選抜" . 0.015850125)
 ("イベント" . 0.015850125) ("実現" . 0.015850125) ("アポロ" . 0.015850125)
 ("きぼう" . 0.013208438) ("航空" . 0.013208438) ("開発" . 0.013208438)
 ("機構" . 0.013208438) ("参加" . 0.013208438) ("さいたま市" . 0.013208438)
 ("試験" . 0.013208438) ("仕事" . 0.013208438) ("最後" . 0.013208438)
 ("月面" . 0.013208438) ("着陸" . 0.013208438) ("特集" . 0.013208438)
 ("時事通信" . 0.013208438) ("契約" . 0.013208438) ("サム" . 0.013208438))

さて、この出力を利用することができるかどうかがまた問題です。

]]>
Sat, 24 Apr 2010 18:38:25 +0900
次の日のファイルも作りたい http://tech.actindi.net/3480889215 Emacsでスクラッチファイルを日付順にして管理するライフハック」で紹介したように日付を元にファイル名を付けて、スクラッチファイルやブログの下書きなどを書いているのですが、たまに、次の日付のファイルが欲しくなることがあります。
これはブログのネタになりそうだということで、そういうファイルを作成するEmacs Lispを適当に書いてみました。
自分は、Emacs Lispを書くときは、なんとなく(require 'cl)したくないのですが、欲しい関数を調べるのが億劫だったのでべたべたに(require 'cl)になってしまいました。
(require 'cl)

(defun buffer-name-prefix ()
  (let ((buffer-name (buffer-name (current-buffer))))
    (substring buffer-name 0 (position-if #'digit-char-p buffer-name)) ))

(defun prefix-Y-m-d.suffix-to-list (string)
  (destructuring-bind 
      (prefix Y m &optional d)
      (split-string string "-")
    (when (and (null d)
               (every #'digit-char-p prefix) )
      (shiftf d m Y prefix ""))
    (destructuring-bind
        (d &optional suffix)
        (split-string d "\\.")
      (list prefix Y m d (or suffix "")) )))

(defun next-file-name (name)
  (destructuring-bind 
      (prefix Y m d suffix)
      (prefix-Y-m-d.suffix-to-list name)
    (let ((time (encode-time 0
                             0
                             0
                             (parse-integer d)
                             (parse-integer m)
                             (parse-integer Y)
                             nil
                             0) ))
      (concat (if (string= "" prefix) "" (concat prefix "-"))
              (format-time-string "%Y-%m-%d" (progn (incf (first time)) time))
              (if (string= "" suffix) "" (concat "." suffix)) ))))

(defun make-next-file ()
  (interactive)
  (find-file (next-file-name (buffer-name))) )
使い方ですが、foo-2000-02-28.txtのようなファイル名のバッファで作業している時に(make-next-file)すると、foo-2000-02-29.txtのようなファイルをfind-fileします。
バッファの名前は、{prefix-}yyyy-mm-dd{.suffix}のようなものを想定していて、これ以外では上手く動きませんが、それなりに便利に使えています。Emacs便利です。 ■ ]]>
Thu, 22 Apr 2010 10:40:15 +0900
Redmine_Importer便利です http://tech.actindi.net/3480393573 社内では、タスク管理にRedmineを導入していて、システムの人から、全然システムじゃない人まで利用しています。
Redmineは便利なのですが、定期的なチケットや、まとめての登録が面倒になってきました。
以前、Redmine勉強会のUstreamを眺めていて、csvから一括で登録できるというプラグインを紹介していたことを思いだしたので早速導入してみることにしました。 junoさんの発表で色々一括登録する方法が紹介されていますが、junoさんが日本語化されているRedmine_Importerというものを導入してみることにしました。
インストールすると、プロジェクトの設定画面のモジュールのところから有効にできるモジュールとしてImporterが現われますので、これをオンにすると利用できます。
これで大量のチケットも楽に登録できます。ありがたや! ■ ]]>
Fri, 16 Apr 2010 16:59:33 +0900
UITableViewにcellを動的に追加/削除する2つの方法。 http://tech.actindi.net/3480206140 こんにちはmasudaです。

今回はUITableViewにcellを動的に追加/削除するということについて書こうと思います。

特にこれまでUITableViewのbeginUpdatesとendUpdatesという二つのメソッドを、いったいどんな場合に使用したらいいのか明確になっていませんでした。
ここら辺を重点的に書きたいと思います。

以下のAppleの公式ドキュメントにかなり詳しく書かれています。
Table View Programming Guide for iPhone OS: Inserting and Deleting Rows and Sections

cellを一つずつ追加/削除していく場合

cellを一つずつ追加/削除していく場合には、beginUpdates/endUpdatesの出番はありません。
追加/削除したいcellのindexPathを作成してinsert(or delete)RowsAtIndexPaths:withRowAnimation:メソッドを呼ぶだけ。
単純です。

ただし注意点はinsertRowsAtIndexPaths:withRowAnimation:メソッドを呼ぶと、UITableViewDataSourceのtableView:cellForRowAtIndexPath:メソッドが呼ばれるということ。
すなわち、cellの中身をNSArray等で管理している場合にはあらかじめNSArrayの内容を変更しておかなければなりません。

cocoa*life – UITableViewCellを削除ボタンを使って削除する

複数のcellをいっぺんに追加/削除する場合

ここまではbeginUpdatesやendUpdatesを使用する必要はありません。
では、どういうときに使用するべきなのか?

ポイントはbeginUpdates/endUpdatesに関することが書かれているセクションのタイトルがBatch Insertion and Deletion of Rows and Sectionsであるということ。
batchというのは英語で束という意味なので、「いっぺん」に複数のcellを処理したいときに使うということになります。

つまり、このメソッドを使用するかしないかの選択基準の違いは、一つずつかいっぺんかということになります。
もちろん複数のcellを追加/削除したい場合であっても、一つずつ追加/削除することができます。

beginUpdatesとendUpdatesで追加/削除のメソッド群を挟みます。
endUpdatesを呼び出したあと、tableView:cellForRowAtIndexPath:メソッドが呼ばれ、追加と削除の結果が表示されます。

beginUpdatesとendUpdatesで挟まれた追加/削除の挙動は、公式ドキュメントに以下のように書かれています。

The code calls the deleteRowsAtIndexPaths:withRowAnimation: method after it calls insertRowsAtIndexPaths:withRowAnimation:. However, this is not the order in which UITableView completes the operations. It defers any insertions of rows or sections until after it has handled the deletions of rows or sections. This happens regardless of ordering of the insertion and deletion method calls.

Deletions within an animation block specify which rows and sections in the original table should be removed; insertions specify which rows and sections should be added to the resulting table.

引用元: Table View Programming Guide for iPhone OS: Inserting and Deleting Rows and Sections(強調は引用者による)

この文章をまとめてみました。
(前提条件としてbeginUpdates/endUpdatesで囲まれている中では)

  • deleteRowsAtIndexPaths:withRowAnimation:メソッドをinsertRowsAtIndexPaths:withRowAnimation:メソッドの前に呼ぶことは必須ではない(not the order)。
  • 実際のcellの追加は削除のあとに行われる。上記メソッドの呼び出し順序は影響を及ぼさない(regardless of ordering of the insertion and deletion)。
  • 削除時のindexPathにはbeginUpdates呼び出し前、元々の(original)テーブルに対するものを指定し、追加時は削除後の結果となる(resulting)テーブルに対するものを指定する。

このような仕組みにすることで、以下のページに書かれているように1つのcellを削除するごとにindexPathを調整することが必要なく、削除を直感的に行うことが出来ます。
テーブルのセルの削除や追加にbeginUpdates/endUpdatesは必要か(2) – iPhoneアプリ開発まっしぐら★ – iPhoneアプリ開発グループ

ということで、beginUpdates/endUpdatesメソッドはcellをいっぺんに追加/削除したい場合に使えばよい!ということになります。

参考文献

]]>
Wed, 14 Apr 2010 12:55:40 +0900
Lisp on Rails 第8回 〜 before_* http://tech.actindi.net/3479881378 こんにちは!! tahara です。 Lisp on Rails 第8回です!

今回は ActiveRecord::Base の save, create, update, destroy 等々のメソッドには beforo_* や after_* というフックメソッドを定義することができます。 ActiveRecord::Callbacks でそのあたりの実装がされています。

これを Common Lisp でやろうとした場合、

(defmethod save :before ((self post)) ...)
で OK と思ったらそうはいきません。 before_* メソッドが false を返した場合はメソッドを呼び出しを中断する必要があります。 Common Lisp の before メソッドは返り値は無視してしまうので、そのまま使うことはできないのです。

仕方ないので自分で新しいメソッドコンビネーションを実装します。

(define-method-combination active-record ()
  ((around (:around))
   (before (:before))
   (primary () :required t)
   (after (:after)))
  "before メソッドが nil を返した場合メソッドの実行を中断する。"
  (flet ((call-methods (methods)
           (mapcar #'(lambda (method)
                       `(call-method ,method))
                   methods))
         (call-methods-and (methods)
           `(and ,@(mapcar #'(lambda (method)
                               `(call-method ,method))
                           methods))))
    (let ((form (if (or before after (rest primary))
                    `(when ,(call-methods-and before)
                       (multiple-value-prog1
                           (call-method ,(first primary)
                                        ,(rest primary))
                         ,@(call-methods (reverse after))))
                    `(call-method ,(first primary)))))
      (if around
          `(call-method ,(first around)
                        (,@(rest around)
                           (make-method ,form)))
          form))))

あとは defgeneric するときにこのメソッドコンビネーションを指定すれば OK です。

(defgeneric save (record)
  (:method-combination active-record)
  ...)

簡単にメソッドの呼び出し方法を定義できてしまうなんて Common Lisp はいい言語ですね。

ソースはこちらから http://github.com/quek/lisp-on-rails

第9回につづきます。

]]>
Sat, 10 Apr 2010 18:42:58 +0900
It's all textとCodaの連携 http://tech.actindi.net/3479687420 WordPressで作業していると、フォーム内のHTMLを編集する必要が出てくることが割と多いのですが、フォーム内の貧弱な編集機能であれこれするのはとても面倒です。
こういう時に自分が愛用しているのは、FireFoxのアドオンのIt's All Text!です。
結構便利なので、フォームの中身はことごとく呼び出したEmacsから編集しているのですが、便利なのでシステム系の人以外のデザイナーさん達にもお薦めしたいです。
そんな感じで、社内でも布教していたのですが、Codaとの組み合わせで上手く動かなかったので、メモ。
Codaには、コマンドラインから起動できる便利なCommand-Line Codaという便利スクリプトがあるのですが、これとの組み合わせで上手く動かない現象に遭遇
原因を探ってみたところ、どうやら、ファイルのパス名にスペースが入ってしまっているのが原因ではないかということで、
#!/bin/sh

/usr/local/bin/coda `echo $*|sed 's/ /\\ /g'`
のような適当なスクリプトを作成して、/usr/local/bin/its-all-codaのような名前で保存し、これをIt's All Text!から呼ぶことにしてみたところ解決。
sed便利です。
■ ]]>
Thu, 08 Apr 2010 12:50:20 +0900
任意のイベントを受付け、発火できるオブジェクト http://tech.actindi.net/3478908901 komagataです。

canvasでウロウロするシリーズも少しコードが汚くなって来たのでリファクタリングしました。

iPhone シミュレータ

canvasでウロウロする4

コンストラクタの継承が出来なかったのをJavaScript: The Good Partsに載っていた関数型の継承を使って書き直しました。

また、同じく同書に載っている、任意のオブジェクトに任意のイベントを受付け、発火できる機能を追加する、とても便利なeventuality関数を使うように書き換えました。

var eventuality = function(that) {
  var registry = {}

  that.fire = function(event) {
    var array, func, handler,
        type = typeof event === 'string' ? event : event.type

    if (registry.hasOwnProperty(type)) {
      array = registry[type]
      for (var i = 0; i < array.length; i++) {
        handler = array[i]
        func = handler.method
        if (typeof func === 'string') {
          func = this[func]
        }
        func.apply(this, handler.parameters || [event])
      }
    }
    return this
  }

  that.on = function(type, method, parameters) {
    var handler = {method: method, parameters: parameters}
    if (registry,hasOwnProperty(type)) {
      registry[type].push(handler)
    } else {
      registry[type] = [handler]
    }
    return this
  }

  return that
}

eventuality関数はonとfireの二つのメソッドを持ちます。onで任意の名前のイベントを登録し、fireで発火します。

eventuality関数を継承したオブジェクトは全て同機能を持つのでenterframeイベントを持ったspriteオブジェクトなどがとても簡単につくれるようになりました。

var sprite = function(img_src, x, y, width, height) {
  var that = eventuality()
  that.img = new Image
  that.img.src = img_src
 
  that.on('enterframe', function(){
    that.game.context.drawImage(
      that.img,
      that.x,
      that.y,
      that.width,
      that.height
    )
  })
 
  return that
}

こんな感じで好き勝手なイベントが作れるのが便利です。

コード:4 at master from komagata's canvas-prowler - GitHub

JavaScript: The Good Parts ―「良いパーツ」によるベストプラクティス
]]>
Tue, 30 Mar 2010 12:35:01 +0900
Lisp on Rails 第7回 〜 ActiveRecord::Base の find メソッド http://tech.actindi.net/3478630834 遅くなりました!! tahara です。 Lisp on Rails 第7回です!

今回は ActiveRecord::Base の find メソッドの機能を多少実装してみたいと思います。

ActiveRecord::Base の find メソッドは次の4つの使い方があります。

  1. id で検索。 引数は (id, *args), (id1, id2, ..., *args), ([id1, id2, ..., *args]) の3パターン。 該当するレコードがない場合は RecordNotFound が発生する。
  2. 最初の1件を検索。 引数は (:first, *args) で、該当がない場合は nil を返す。 Model.first(*args) というショートカットがある。
  3. 最後の1件を検索。 引数は (:last, *args) で、該当がない場合は nil を返す。 Model.last(*args) というショートカットがある。
  4. 該当する全件を検索。 引数は (:all, &args) で、該当がない場合は nil を返す。 Model.all(*args) というショートカットがある。

上記の4つの使い方全てで次のハッシュオプションが使えます。

  • :conditions - いわゆる検索条件。文字列またはリストで指定。
  • :order - SQL の ORDEY BY
  • :group - SQL の GROUP BY
  • :having - SQL の HAVING
  • :limit - 最大取得件数。
  • :offset - 取得開始位置。
  • :joins - SQL の JOIN だけど、普通次の :include を使う。
  • :include - 検索時に一緒にとってくるテーブルをアソシエーション名(has_many :xxxs)で指定する。
  • :select - 取得カラム。デフォルトは "*"。
  • :from - SQL の FROM。ビューから検索するとき等に使える。
  • :readonly - 取得結果をリードオンリー指定する。
  • :lock - SQL でのロック。"FOR UPDATE" とか。

このような場合 Common Lisp ではマルチディスパッチとキーワード引数を使えばうまくいくはずです。

;; find は CL にあるので select にする
(defgeneric select (class id-or-keyword
                          &key
                          conditions
                          order
                          group
                          having
                          limit
                          offset
                          joins
                          include
                          select
                          from
                          readonly
                          lock
                          &allow-other-keys))

(defmethod select ((class symbol) id-or-keyword &rest args)
  (apply #'select (find-class class) id-or-keyword args))

(defmethod select ((class active-record-class) (id integer)
                   &rest args
                   &key conditions)
  (setf conditions (append (list :id id) conditions))
  ...)

(defmethod select ((class active-record-class) (ids list)
                   &rest args
                   &key conditions)
  (setf conditions (append (list :id ids) conditions))
  ...)

(defmethod select ((class active-record-class) (keyword (eql :all))
                   &rest args)
  ...)

(defmethod select ((class active-record-class) (keyword (eql :first))
                   &rest args
                   &key (order "id"))
  ...)

(defmethod select ((class active-record-class) (keyword (eql :last))
                   &rest args
                   &key (order "id"))
  ...)

(defun all (&rest args)
  (apply #'select (car args) :all (cdr args)))
;; first と last は CL パッケージとかぶる。

といった感じで実装してみました。 joins, include, readonly 等はまだ未実装です。

しかし Common Lisp パッケージとシンボル名(find, first, last)がかぶるのが悩ましいところです。shadowing しようかしらん。

ソースはこちらから http://github.com/quek/lisp-on-rails

第8回につづきます。

]]>
Sat, 27 Mar 2010 07:20:34 +0900
WordPressのプラグイン Contact Form 7 が便利だった件 http://tech.actindi.net/3478497183 現在、WordPressを通してPHPの文化を勉強中です。
アンケートや申込みのフォームを作成することは度々あるかと思うのですが、WordPressでそれを実現する定番プラグインにContact Form 7というのがあることを知りました。 今回、Contact Form 7を利用するにあたり、利用したい機能をどうやって設定するかを調べてみたのでメモ。

自動返信のサンクスメールを飛したい

Contact Form 7では、通知用とその他の予備で、2通の通知メールを出すことができます。
このメール(2)の設定で、申込者のメールアドレスを送り先に指定すれば、自動返信のサンクスメールを設定することが可能でした。便利ですね。

サンクスページを設置したい

WordPress管理画面から お問い合わせ > その他の設定 の欄に、
on_sent_ok: "location.replace('サンクスページのURL');"
と記述することによって、で正常に送信できた後のリダイレクトを設定することができます。便利ですね。

UTF-8ではなく、JIS(iso-2022)のメールを送信したい

これは、Contact Form 7の設定ではないのですが、大体組み合せで発生する問題だと思うので、ここに書いておきたいと思います。
WordPressではデフォルトの設定では、UTF-8のメールが飛ぶようです。最近のメーラーだとUTF-8のメールも普通に読めますが、対応してない環境も多数あるかと思います。
ということで、UTF-8ではなく、JISにしたいのですが、変更するには、 WP Multibyte Patch というプラグインで設定するのが定番のようです。
設定ファイルのサンプルが-sample.phpとして付属してきますので、これをリネームして利用します。
wp-content/plugins/wp-multibyte-patch/wpmp-config-sample.php
=>
wp-content/plugins/wp-multibyte-patch/wpmp-config.php
wp-content/plugins/wp-multibyte-patch/ext/ja/config-sample.php
=>
wp-content/plugins/wp-multibyte-patch/ext/ja/config.php
という感じにリネーム。
wp-content/plugins/wp-multibyte-patch/ext/ja/config.php の内容は、
<?php
/* WP Multibyte Patch extension config file */

// Set mail mode.
// "auto" picks  "jis" or "UTF-8" automatically.
// "jis" or "UTF-8" fix the encoding method to its name.
$wpmp_conf['mail_mode'] = 'jis';   // auto, jis, UTF-8

?>
ですが、ここでjisを指定することになるようです。リネームしたら、プラグインを有効化し、テストしてJISでメールが届いているかを確認します。
色々な人が様々な便利/拡張機能を提供していてWordPress/PHP素晴らしいですね。 ■ ]]>
Thu, 25 Mar 2010 18:13:03 +0900
Core Animationで遊んでみる (2) http://tech.actindi.net/3478391136 英文のタイプは日本語のタイプと違うものなので、頭の変なところを使って意外と難しいということを最近知ったmasudaです。

今回も前回に引き続き、Core Animationで少し遊んでみたいと思います。
これも簡単にできるフェード処理です。

前回と同様、QuartzCore.frameworkをincludeし、

#import <QuartzCore/QuartzCore.h>

とimportすることが必要です。

さて実際にフェード処理を記述してみましょう。
たとえば、hogeViewというViewをフェードアウトしてみます。

CATransition    *transition;
transition = [CATransition animation];

// トランジション時間の設定(これだと1秒)。
[transition setDuration:1.0f];

// トランジションの種類の設定、今回はフェード。
[transition setType:kCATransitionFade];

// トランジション中に起こす処理を記述。
[hogeView setHidden:YES];

// トランジションを実行。
[[[self view] layer] addAnimation:transition forKey:@"layerAnimation"];

フェードインの時はsetHiddenをNoですね。

この方法を用いて、もう一つサンプルを書いてみます。
UINavigationItemのright/leftButtonItemを設定する際にはanimated:YESとすることでフェードイン/アウトしてくれますが、TitleViewはそのような項目はないのでこの方法を使えないかと思いやってみたらできました。

TitleViewにはUISegmentedControlを設定することにします。

CATransition    *transition;
transition = [CATransition animation];

[transition setDuration:1.0f];
[transition setType:kCATransitionFade];
[[self navigationItem] setTitleView:segmentedControl];
[[[[self navigationController] navigationBar] layer] addAnimation:transition forKey:@"layerAnimation"];
]]>
Wed, 24 Mar 2010 12:45:36 +0900
プレゼンハムで直線を書く関数 http://tech.actindi.net/3478295613 komagataです。

以前のプログラムで使った、javascriptでプレゼンハムアルゴリズムを使って2点間を結ぶ直線の座標を求める関数を単体で使えるように切り出してみました。

#!/usr/bin/env js

/**
 * Build line's path by Bresenham algorithm
 *
 * @arguments Array src - line source coordinate. (Ex: [12, 32])
 * @arguments Array dest - line destination coordinate. (Ex: [41, 55])
 * @return Array - builded path array. (Ex: [[12, 32], ... [41, 55]])
 */
var build_path = function(src, dest) {
  var next_x = src[0],
      next_y = src[1],
      delta_x = dest[0] - src[0],
      delta_y = dest[1] - src[1],
      step_x,
      step_y,
      step = 0,
      fraction = 0,
      path = []

  if (delta_x < 0) {
    step_x = -1
  } else {
    step_x = 1
  }
  if (delta_y < 0) {
    step_y = -1
  } else {
    step_y = 1
  }

  delta_x = Math.abs(delta_x * 2)
  delta_y = Math.abs(delta_y * 2)

  path[step] = [next_x, next_y]
  step++

  if (delta_x > delta_y) {
    fraction = delta_y - delta_x / 2
    while (next_x != dest[0]) {
      if (fraction >= 0) {
        next_y += step_y
        fraction -= delta_x
      }
      next_x += step_x
      fraction += delta_y
      path[step] = [next_x, next_y]
      step++
    }
  } else {
    fraction = delta_x - delta_y / 2
    while (next_y != dest[1]) {
      if (fraction >= 0) {
        next_x += step_x
        fraction -= delta_y
      }
      next_y += step_y
      fraction += delta_x
      path[step] = [next_x, next_y]
      step++
    }
  }
  return path
}

// print path
var way = build_path([152, 152], [162, 136])
for (var i = 0; i < way.length; i++) {
  print(way[i])
}
152,152
153,151
153,150
154,149
155,148
155,147
156,146
156,145
157,144
158,143
158,142
159,141
160,140
160,139
161,138
161,137
162,136

座標には配列を使っています。この辺の基本的な機能はWebGLとかでまとまって実装されればいいなと思います。

]]>
Tue, 23 Mar 2010 10:13:33 +0900
Lisp on Rails 第6回 〜 ここらでリファクタリング http://tech.actindi.net/3477957044 こんにちは!! tahara です。 Lisp on Rails 第6回です!

has-one を has-many のコピペで書いてしまったので、 ここらでリファクタリングしたいと思います。

has-one のスロット定義

(defclass ar-has-one-slot-mixin ()
  ((has-one :initarg :has-one
            :initform nil
            :accessor has-one)
   (class-symbol :initarg :class-symbol
                 :initform nil
                 :accessor class-symbol)))

(defmethod initialize-instance :after ((self ar-has-one-slot-mixin) &rest args)
  (declare (ignore args))
  (unless (class-symbol self)
    (setf (class-symbol self) (has-one self))))

(defclass ar-has-one-direct-slot-definition (ar-direct-slot-definition
                                             ar-has-one-slot-mixin)
  ())

(defclass ar-has-one-effective-slot-definition (ar-effective-slot-definition
                                                ar-has-one-slot-mixin)
  ())

has-many のスロット定義

(defclass ar-has-many-slot-mixin ()
  ((has-many :initarg :has-many
             :initform nil
             :accessor has-many)
   (class-symbol :initarg :class-symbol
                 :initform nil
                 :accessor class-symbol)))

(defmethod initialize-instance :after ((self ar-has-many-slot-mixin) &rest args)
  (declare (ignore args))
  (unless (class-symbol self)
    (setf (class-symbol self)
          (sym (singularize (has-many self))))))

(defclass ar-has-many-direct-slot-definition (ar-direct-slot-definition
                                              ar-has-many-slot-mixin)
  ())

(defclass ar-has-many-effective-slot-definition (ar-effective-slot-definition
                                                 ar-has-many-slot-mixin)
  ())

いやー、ひどいですね。 ほとんど one と many の違いだけです。

さて、これをリファクタリングするのに Common Lisp にはマクロという手抜きプログラマには必須の機能があります。

普通リファクタリングするとなると、関数、メソッド、スーパークラス等々の 切り出しが必要になりますよね? でも、マクロなら何ら設計を変更することなくリファクタリングが可能になります。

では、実際にマクロを使ってリファクタリングしてみましょう。

(defmacro def-has-xxx-slot-definition (xxx
                                       default-class-symbol-form)
  `(progn
     (defclass ,(sym "ar-has-" xxx "-slot-mixin") ()
       ((,(sym "has-" xxx) :initarg ,(key-sym "has-" xxx)
                 :initform nil
                 :accessor ,(sym "has-" xxx))
        (class-symbol :initarg :class-symbol
                      :initform nil
                      :accessor class-symbol)))

     (defmethod initialize-instance :after ((self ,(sym "ar-has-" xxx "-slot-mixin")) &rest args)
        (declare (ignore args))
        (unless (class-symbol self)
          (setf (class-symbol self) ,default-class-symbol-form)))

     (defclass ,(sym "ar-has-" xxx "-direct-slot-definition") (ar-direct-slot-definition
                                                  ,(sym "ar-has-" xxx "-slot-mixin"))
       ())

     (defclass ,(sym "ar-has-" xxx "-effective-slot-definition") (ar-effective-slot-definition
                                                     ,(sym "ar-has-" xxx "-slot-mixin"))
       ())
     ))

(def-has-xxx-slot-definition one (has-one self))
(def-has-xxx-slot-definition many (sym (singularize (has-many self))))

すばらい。 最初のひどい設計を何ら変えることなくリファクタリングできました。

手抜き設計のベタ書きコードそのままで、リファクタリングを可能とするマクロは、 未熟なプログラマにとって、なくてはならない存在です。

ソースはこちらから http://github.com/quek/lisp-on-rails

第7回につづきます。

]]>
Fri, 19 Mar 2010 12:10:44 +0900
Core Animationで遊んでみる (1) http://tech.actindi.net/3477781577 こんにちは。masudaです。
三寒四温な日々が続いていますが、いかがお過ごしでしょうか?

Leopardの目玉機能の一つはCore Animationでした。
Appleの触れ込みによると、Core Animationを利用すると簡単にアニメーション処理を追加することができるそうです。

なんですが、アニメーションではないところでも、便利に使うことができます。
今回はiPhone SDKを用いて、そのちょっと便利な使い方を書こうと思います。

以下のサンプルでは全部
QuartzCore.frameworkをincludeし

#import <QuartzCore/QuartzCore.h>
とimportをすることが必要です。

UIViewを角丸にする

UIViewを角丸にするのはとても簡単です。

[[view layer] setCornerRadius:10.0];
[view setClipsToBounds:YES];

UIViewに枠線を追加する

[[view layer] setBorderColor:[[UIColor lightGrayColor] CGColor]];
[[view layer] setBorderWidth:1.0];

setBorderColorメッセージの引数はCGColorなので、上記のようにUIColorからCGColorに変更してあげる必要があります。

]]>
Wed, 17 Mar 2010 11:26:17 +0900
glpngをmacで使う http://tech.actindi.net/3477747671 飲み屋での一杯目は「水」。komagataです。

canvas上の何も無いも同然なグラフィックAPI上でアプリを書いてきましたが、WebGLというOpenGL ESベースのAPIの実装が始まってるそうなのでまずはOpenGLの勉強を始めました。

デスクトップアプリケーションのGUIツールキット部分はWebとは関係無い(=canvasみたいな感じになるはずな)ので、GLUT(The OpenGL Utility Toolkit)を使って行きます。

とりあえずpngを簡単に読み込みたかったのでglpngというライブラリを使おうとしたのですが、各地でリンク切れ。前世紀にメンテが終わってるっぽい雰囲気ですが、下記(OpenBSDのリポジトリ)に有りました。

ftp://ftp.usa.openbsd.org/pub/OpenBSD/distfiles/glpng-1.45/glpng.zip

どうせWebのためにやるのでOS依存部分で苦労したくないんですが、Macでコンパイルするのに少し修正する必要がありました。

% diff glpng.c glpng.c.org
28,29c28,29
< #include <GLUT/glut.h>
< #include "GL/glpng.h"
---
> #include <GL/glpng.h>
> #include <GL/gl.h>

付属のMakefile.LINUXでmakeすれば静的ライブラリ(libglpng.a)が出来ます。(Makefile.SGIってファイルも付いてるのが古さを感じます)

pngInfoとpngBind関数が使えるようになるので簡単にpngファイルが簡単にテクスチャとして貼れました。

#include <stdio.h>
#include <GLUT/glut.h>
#include "glpng.h"

GLuint texture;

void display()
{
    glClear(GL_COLOR_BUFFER_BIT);
    glPushMatrix();
        glTranslatef(0, 0, 0);
        glBindTexture(GL_TEXTURE_2D, texture);
    glPopMatrix();
  
    glBegin(GL_QUADS);
        glTexCoord2d(0.0, 1.0);
        glVertex2d(-1, -1);
        glTexCoord2d(1.0, 1.0);
        glVertex2d(1, -1);
        glTexCoord2d(1.0, 0.0);
        glVertex2d(1, 1);
        glTexCoord2d(0.0, 0.0);
        glVertex2d(-1, 1);
    glEnd();
    glFlush();
} 

void init()
{ 
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glColor3d(1.0, 1.0, 1.0);
    glEnable(GL_TEXTURE_2D);
  
    pngInfo info;
    texture = pngBind("tree.png", PNG_NOMIPMAP, PNG_ALPHA, &info, GL_CLAMP, GL_NEAREST, GL_NEAREST);
} 
  
int main(int argc, char** argv)
{ 
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
    glutInitWindowSize(100, 100);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("hunter");
    glutDisplayFunc(display);
    init();
    glutMainLoop();
} 
Macのframeworkという仕組みがイマイチわかってないんですが、下記でコンパイルできました。

% cc -framework GLUT -framework OpenGL -o game game.c libglpng.a

tree

ソース:10 at master from komagata's glut - GitHub

]]>
Wed, 17 Mar 2010 02:01:11 +0900
Lisp on Rails 第5回 〜 has-one http://tech.actindi.net/3477394606 こんにちは!! tahara です。 Lisp on Rails 第5回です!

今回は ActiveRecord の has_one アソシエーションもどきを実装したいと思います。 前回の has_many に瓜二つです。 ar-has-one-direct-slot-definition と ar-has-one-effective-slot-definition を定義します。

(defclass ar-has-one-slot-mixin ()
  ((has-one :initarg :has-one
            :initform nil
            :accessor has-one)
   (class-symbol :initarg :class-symbol
                 :initform nil
                 :accessor class-symbol)))

(defmethod initialize-instance :after ((self ar-has-one-slot-mixin) &rest args)
  (declare (ignore args))
  (unless (class-symbol self)
    (setf (class-symbol self) (has-one self))))

(defclass ar-has-one-direct-slot-definition (ar-direct-slot-definition
                                             ar-has-one-slot-mixin)
  ())

(defclass ar-has-one-effective-slot-definition (ar-effective-slot-definition
                                                ar-has-one-slot-mixin)
  ())

direct-slot-definition-class と effective-slot-definition-class と compute-effective-slot-definition でゴニョゴニョすると上記の slot-definition が使えるようになります。

slot-value-using-class と (setf slot-value-using-class) で関連テーブルの 取得と設定を行います。

(defmethod c2mop:slot-value-using-class
  ((class active-record-class)
   instance
   (slot-def ar-has-one-effective-slot-definition))
  (aif (call-next-method)
       it
       (setf (slot-value instance (has-one slot-def))
             (car (all (find-class (class-symbol slot-def))
                       :conditons (list (key-sym (class-name class) '-id)
                                        (%value-of instance :id)))))))

(defmethod (setf c2mop:slot-value-using-class) :after
           (new-value
            (class active-record-class)
            instance
            (slot-def ar-has-one-effective-slot-definition))
   (when new-value
     (setf (%value-of new-value (str (class-name class) "-id"))
           (%value-of instance :id))))

で、だいたいこんな感じで使えるようになります。

(def-record post
  (:has-many comments)
  (:has-one post-info))
(def-record post-info
  (:belongs-to post))
(let* ((post (car (all post)))
       (post-info (post-info-of post)))
  (describe post-info))

以上、なんとなく has-one できました。 ソースはこちらから http://github.com/quek/lisp-on-rails

第6回につづきます。

すみません。 次回はコピペじゃないように頑張ります。

]]>
Fri, 12 Mar 2010 23:56:46 +0900
思い込み、こわいです http://tech.actindi.net/3477312231 いきなりWordPressの話なのですが、私はこれまで、WordPressとは、HTML内のリンクというリンクにhttp〜というURLをベタベタと詰め込めるだけ詰め込む生き物だと思っておりました。
これが故に、作成したサイトを別のURLを持つテストサイト等にコピーする際にも、SQLで色々するはめになるものだと思っておりました。
「せめてURLじゃなくて"/"から始まってくれれば良いのに…」と思いながらDBをいじっておりましたが、ふと、SQLでsiteurlに"/"を入れてみたところ普通に"/"からという記述で動くことが分かりました。
おやおや?ということで、この状態で、
設定 > 一般設定 > WordPress のアドレス (URL)
を眺めたところ、内容は空になっておりました。ものは試しに"/"を入力してみましたが、どうも末尾の"/"は消されて空になる様子
なんだWordPress内でURL指定じゃなくて、絶対パスでの指定ができるんじゃないかと!
WordPress のアドレス (URL)
の(URL)という表現が紛らわしいですよね。
※ちなみに最初の設定時ではなく、稼働中のものを途中で変更すると色々壊れてしまい、SQLで色々するハメになる場合がありますのでご注意下さい■ ]]>
Fri, 12 Mar 2010 01:03:51 +0900
UITableViewCellの高さを内容に合わせて変化させる http://tech.actindi.net/3477191382 こんにちは。

今回はUITableViewにおいてcellの高さをcellの内容に合わせて変化させるということをやってみます。

Natsuliphoneのソースを参考にさせていただきました。

UITableViewでcellの高さを設定するには、UITableViewDelegateのtableView:heightForRowAtIndexPath:メソッドを実装して高さを返してあげます。
ただ、ここに問題があってこのメソッドが呼び出される時点ではcellができていないのです。
ですので、cellForRowAtIndexPath:メソッドなどでcellを取得してそのcellの高さを返すというような方法をとることができません。

そこで対象となるcellに高さを計算するためのクラスメソッドを実装し、そこで得られた値をtableView:heightForRowAtIndexPath:に返します。

+ (CGFloat)heightWithContents:(NSString *)contents
{
    CGFloat result;
    CGSize  labelSize;

    result = 0.0;
    labelSize = [contents sizeWithFont:[UIFont systemFontOfSize:16.0]
                     constrainedToSize:CGSizeMake(300.0, 10000)
                         lineBreakMode:UILineBreakModeWordWrap];
    result += labelSize.height;

    return result;
}

複数行にわたるtextの高さを求めるにはsizeWithFont:constrainedToSize:lineBreakMode:メソッドを使用します。
sizeWithFont:forWidth:lineBreakMode:メソッドは1行だけのサイズを返しますので、名前にだまされないようにしてください。

参考: Natsuliphoneのソース

]]>
Wed, 10 Mar 2010 15:29:42 +0900
衝突判定でウロウロする http://tech.actindi.net/3477066280 身に覚えの無い商品がAmazonから送られてくる。komagataです。

canvasでウロウロするものに衝突判定を追加してみました。

(今回はAndroidエミュレーターで機種はNexus Oneで動作させてみましたが、webkitなのでiPhone用から何の変更も無しに動いたのは楽でした。)

5554:nexus_one

http://komagata.org/canvas-prowler/3/

(iPhoneやAndroidでアクセスしてみて下さい)

自分で作る前に、文系プログラマー的にはゲームプログラムはどういう実装をすればいいのかを言葉で知りたかったので実装のイメージ的なところを以前のモノと合わせて言葉で説明したいと思います。

移動方法の実装イメージ:

まず、キャラクターの描画はフレーム毎に定期的に(30fpsとかで)描画します。描画はキャラクタの現在持っている座標に単に描画するだけです。

それとは別にクリックイベントをトリガーとしてプレイヤーキャラクターとクリック地点をプレゼンハムアルゴリズムで直線を引き(実際には描画しない)、その直線の座標を配列としてプレイヤーキャラクターの移動のためのバッファ(キュー)に格納します。

キャラクターはクリックイベントには感知せず、1フレーム毎に自分の移動バッファに座標があれば一つづつ消費しながら自分の座標を変更していき、バッファに無ければ何もしません。

クリックイベント時には移動バッファが残っていても空にした上で新しい経路を設定するのでクリックした瞬間に進路を変更します。

衝突判定:

何かが有る度に、それぞれのオブジェクト(プレイヤー、背景、障害物など)を全て走査、それぞれのオブジェクトが持つプレイヤーフラグ、障害物フラグを見て処理します。(これは関係無いオブジェクトも毎回走査することになるのでとてもヘボイやり方でした。イベント毎にイベントリスナーを登録するように次は変更したいです。)

プレイヤーキャラクターの移動バッファの次の移動場所が障害物フラグを持つオブジェクトと衝突している場合に移動を中止して以降の移動バッファもクリアします。

シンプルなドット絵を対象にしているので四角形と四角形の衝突を判定するのはとても楽です。

少しハマったのは、衝突した時点で移動バッファをクリアするのではなく、衝突する一歩前で次の移動地点を見てバッファをクリアしなければならないというところです。

衝突した時点でバッファをクリアすると、見た目上は分かり辛いですが、一歩分障害物にめり込んでいるので障害物に接触した瞬間動けなくなります。

この変な動きも面白かったですが、プログラムを見直して、なるほどなあと思いました。

次回もこれに新しい要素を付け加えたいと思います。

]]>
Tue, 09 Mar 2010 04:44:40 +0900
多段 ssh で vnc http://tech.actindi.net/3476755810 こんにちは!! tahara です。

例えば host1 を経由して host2 に vnc したい場合どうすればいいか調べてみました。 結果 ↓ のページに書かれてあるとおりすれば可能でした。ありがとうございます。

ssh を多段に使ってずっと遠くにあるマシンに port forward する|裏表(Phinloda のもう裏だか表だか分からないページ)

蛇足になりますが、次の手順で host2 に vnc できました。

]]>
Fri, 05 Mar 2010 14:30:10 +0900
MacOSX上でMacPortsを使わずにRails開発環境を作る http://tech.actindi.net/3476702991 MacOSX上などにRails開発環境を複数作らなくてはいけなくて色々試行錯誤しています。
環境は、
  • デザイナーさん制作ツール: Coda
  • Ruby on Rails
  • Apache2
  • MacOSXだったり
  • Linuxだったり
  • 貧乏
という感じで、OS環境を2〜3種跨ぎ、かつ、MacOSXとWindowsは主にデザイナーさんが利用するプラットフォームです。
  1. Linuxなら直にRoR環境を構築してしまえば良いし、デザイナーさん達がLinuxは使うことはない
  2. MacOSXも直にMacPortsなどを利用してRoR環境を構築すれば良いけれど、デザイナーさん達はMacOSXをメインに使うらしいので、勝手に各自RoR環境を構築してみて下さいとも言いがたい
  3. 何か問題が起きた場合に、各自で環境を構築してもらうと、何がどうなってエラーになっているのか探るのが面倒臭い
という状況でした。
適当に考えた末、VirturlBox上にRoRの環境を構築し、そのVMイメージを皆で共有すれば楽チンで良いに違いない!ということで試しに、MacOSXの上にVirturlBoxを導入してみました。
ホスト<=>VM間のファイル共有はNFS。
本当は、VirturlBoxの共有ファイル機能を利用したかったのですが、なんだか上手く動かせなかったのでNFSに。
ローカルのファイルをCodaで編集して、Apache/VirturlBoxがホストするページをローカルのブラウザで眺める、という感じで作業してもらうことになりました。
MacOSXは、NFSなどの上で作業すると、._unkoや、.DS〜というファイルを大量にばらまきますが、この構成の場合、作業ディレクトリはホスト側なのでそういうこともありません。
とりあえず、LinuxとMacOSXをホストにして実際に使ってみていますが、可もなく不可もないような、微妙な環境ができあがりました。
もっと他にナイスな組み合わせを教えてください…。■ ]]>
Thu, 04 Mar 2010 23:49:51 +0900
canvasでウロウロする(2) http://tech.actindi.net/3476597468 火曜日担当なのに間に合わずに水曜日にアップしている2010生まれてこなかった方が良かった男オブザイヤー候補、komagataです。

canvasでウロウロするのをiPhoneにフィットするように修正しました。

canvas prowler2

http://komagata.org/canvas-prowler/2/

解像度がファミコンは224x256に対してiphoneは320x480なので細かいですね。

ソース:2 at master from komagata's canvas-prowler - GitHub

]]>
Wed, 03 Mar 2010 18:31:08 +0900
UITextFieldに入力されている文字数を動的に、非同期に数える。 http://tech.actindi.net/3476570782 2週間連続で原稿を落としたmasudaです。
こんにちは。

あまりググればわかるということは書きたくはないなと思っているので、なかなかネタを見つけるのは難しいです。

今回はiPhoneアプリを書いているときにはまったところで、ググってもなかなか答えが見つからないことを書きたいと思います。

2つあるので2週間はこれで持つ!

とあるUITextFieldによる入力フォームと、UIBarButtonItemによる「完了」ボタンがある画面を考えます。

今回のエントリの目的はUITextFieldに文字が入力されていない、つまり空であるときは、「完了」ボタンを表示しない画面を作成するということです。

ポイントはUIControlEventEditingChangedイベントを使うこと。
最初はUITextFieldDelegateのtextField:shouldChangeCharactersInRange:replacementString:とかを使用することを考えましたが、文字を消去したときにボタンが消えない等々うまくいきませんでした。

サンプルコードを書いてみます。

- (void)setupUserInterface
{
    UIView      *contentView;
    UITextField *textField;

    contentView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    [self setView:contentView];
    [contentView release];

    doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
                                                               target:self
                                                               action:@selector(respondsToDoneButtonTouchDown:)];

    textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 100, 20)];
    [contentView addSubview:textField];
    [textField release];
    [textField addTarget:self
                  action:@selector(respondsToEditingChanged:)
        forControlEvents:UIControlEventEditingChanged];
}


- (void)respondsToEditingChanged:(id)sender
{
    if ([sender isKindOfClass:[UITextField class]])
    {
        // 本当はsenderを用いずにメンバ変数とかにしておけばいいのだけれど、今回はあえて型変換をしてみる。
        if ([[(UITextField *)sender text] length])
        {
            [[self navigationItem] setRightBarButtonItem:doneButton animated:YES];
        }
        else
        {
            [[self navigationItem] setRightBarButtonItem:nil animated:YES];
        }
    }
}

参考
Disable button if textField is empty - iPhone SDK Development

]]>
Wed, 03 Mar 2010 11:06:22 +0900
iPhone アプリケーションの開発 http://tech.actindi.net/3476158930 こんにちは!! tahara です。

突然ではありますが、とりあえず読むべきは iPhone Dev Center にある以下のドキュメントでしょうか。

まずは iPhone ヒューマンイン ターフェイス ガイドライン を読んでみました。

iPhone が他と違うところ

  • 小さい画面サイズ。 480x320
  • メモリ少ない。OS が警告をくれたらすぐにメモリ開放すべすし。didReceiveMemoryWarning
  • 1画面。ある意味 Stumpwm!
  • さらに、同時に1アプリケーション。
  • 標準に準拠してヘルプコンテンツを最小限にすべし。

3つのアプリケーションの形態

  • iPhone アプリケーション
  • Web 専用contents
  • ハイブリッドアプリケーション(上の2つの組み合わせ)

3つのアプリケーションスタイル

  • 生産性型アプリケーション(例 Mail)
  • ユーティリティ型アプリケーション(例 Weather)
  • 没入型アプリケーション(例 ゲームアプリ)

デスクトップアプリを移植する場合はよく使われる 20% の機能のみに絞る。

ヒューマンインターフェイスの原則

  • 自然なメタファで
  • 具体的なものを直接いじる感覚
  • テキスト入力を最小限に、選択肢を提示
  • ユーザの操作に対するフィードバック、効果的なやりとり
  • ユーザが開始でき、それを停止できる動きであること
  • インターフェイスの一貫性

製品定義ステートメントを作りましょう。

  • 対象ユーザを明確化
  • 実装機能の限定

簡潔さと使いやすさ

  • 使い方を明白に
  • 頻繁に使用される情報を画面上部に集中
  • テキスト入力を最小限
  • 重要な情報を簡潔に
  • タップ可能な要素の領域は指先サイズに

製品ステートメントにふさわしい主たる機能に焦点を当て、 簡潔かつ入力を最小限にする。

ジェスチャを適切にサポートする。

  • 単純かつ簡単な方法は必須
  • 新しいジェスチャを定義しない

ブランドはささやかで控え目に。 ただしアプリケーションアイコンにはブランドももりこむ。

一般的なタスク

  • 開始
    • ステータスバーに適切なスタイルを設定する
    • 最初の画面に似た起動画面を用意して感覚的起動時間を短縮する
    • 余計なスプラッシュ画面は不要
    • 基本縦で起動
    • 最後に実行したときの状態を復元する
  • 停止
    • いつでも停止できるように
    • 停止時は次の起動のために可能なかぎり詳細の情報を保存しておく
  • 設定(Settings)と設定オプション
    • 設定は一度設定したら変更しないもの
    • 設定オプションは頻繁に変更する可能性があるもの
    • 理想はユーザに設定を要求しないこと
  • その他いろいろ ... ちょっと省略してしまいました。

ユーザインターフェイスの設計

  • ステータスバーはあまりいじらない
  • ToolBar は 44x44 で5つ以下が妥当
  • Tab Bar はモードの切り替え。 5つまでは横に並んで、それをこえたものは More に。 バッジを表示できる。
  • モーダルビューは煩わしいので乱用しない。
  • Action Sheet はユーザの選択肢でり複数のボタンを備える。 害のあるものは赤で一番上に。
  • モーダルビューは主たる機能が関連する自己簡潔型のタスクで(例 Mail のメッセージ作成)
  • アクティビティインジケータ
    • ステータスバーのは1〜2秒ネットワークにアクセスする場合
    • もっと時間がかかる場合はツールバーに表示
  • 進捗がわかるものは Progress View
  • Text Field は左端に使用目的、右端に追加機能
  • システムが用意しているボタン、アイコンを意図されたとおり使う
    • ユーザにやさしい
    • 工数削減

アイコン、画像の作り方の説明でおしまい。

このようなドキュメントがしっかり用意されているのは素晴しいですね。

]]>
Fri, 26 Feb 2010 16:42:10 +0900
C-s/C-rを使おう http://tech.actindi.net/3476099961 WordPressのことを調べようと思って前フリしてましたが、これまた全然進んでません。

ということなので、最近知ったEmacsの知ってる人には、当たり前な機能を紹介したいと思います。
Emacs使いの方は、C-sはもちろん良く利用すると思いますが、C-sで検索モードに入ってからの、C-w、M-yが便利であることを最近知りました。
C-wで単語単位で検索ワードを漸増しつつ検索できたりしますし、M-yは最新のキルリングの内容で検索できます。

また、C-sの応用として、カーソル移動に積極的にC-s/C-rを利用するのも非常に便利であることを再認識しています。
viだとf〜などが便利なのでfを良く使うのですが、EmacsでもC-sで似たようなことはできるんだなあと。
10年位使っていますが、この10年間だいぶ損をしていたなあと思った次第です。
■ ]]>
Fri, 26 Feb 2010 00:19:21 +0900
プレゼンハムでウロウロする http://tech.actindi.net/3475914255 komagataです。

前回は矢印キーでウロウロしたのでマウスクリックでウロウロするものを作りました。

canvas

http://komagata.org/canvas-prowler/1/

直線や曲線を整数で高速に描画するプレゼンハムアルゴリズムでクリック地点までの経路を計算して近付きます。

グラフィックのプログラミングは間違えても変な動きをしたりして面白いですね!

]]>
Tue, 23 Feb 2010 20:44:15 +0900
Lisp on Rails 第4回 〜 has-many http://tech.actindi.net/3475577346 こんにちは!! tahara です。 Lisp on Rails 第4回です!

今回は ActiveRecord の has_many アソシエーションもどきを実装したいと思います。 前回の belongs_to とほとんど同じです。 ar-has-many-direct-slot-definition と ar-has-many-effective-slot-definition を定義します。

(defclass ar-has-many-slot-mixin ()
  ((has-many :initarg :has-many
             :initform nil
             :accessor has-many)
   (class-symbol :initarg :class-symbol
                 :initform nil
                 :accessor class-symbol)))

(defmethod initialize-instance :after ((self ar-has-many-slot-mixin) &rest args)
  (declare (ignore args))
  (unless (class-symbol self)
    (setf (class-symbol self)
          (sym (singularize (has-many self))))))

(defclass ar-has-many-direct-slot-definition (ar-direct-slot-definition
                                              ar-has-many-slot-mixin)
  ())

(defclass ar-has-many-effective-slot-definition (ar-effective-slot-definition
                                                 ar-has-many-slot-mixin)
  ())

direct-slot-definition-class と effective-slot-definition-class と compute-effective-slot-definition でゴニョゴニョすると上記の slot-definition が使えるようになります。

slot-value-using-class と (setf slot-value-using-class) で関連テーブルの 取得と設定を行います。

(defmethod c2mop:slot-value-using-class
  ((class active-record-class)
   instance
   (slot-def ar-has-many-effective-slot-definition))
  (aif (call-next-method)
       it
       (setf (slot-value instance (has-many slot-def))
             (all (find-class (class-symbol slot-def))
                  :conditons (list (key-sym (class-name class) '-id)
                                   (%value-of instance :id))))))

(defmethod (setf c2mop:slot-value-using-class) :after
           (new-value
            (class active-record-class)
            instance
            (slot-def ar-has-many-effective-slot-definition))
  (loop with id = (%value-of instance :id)
        with column = (str (class-name class) "-id")
        for x in new-value
        do (setf (%value-of x column) id)))

で、だいたいこんな感じで使えるようになります。

(def-record comment
    (:belongs-to post))
(def-record post
    (:has-many comments))
(let* ((post (car (all post)))
       (comments (comments-of post)))
  (mapc #'describe comments))

以上、なんとなく has-many できました。 ソースはこちらから http://github.com/quek/lisp-on-rails

第5回につづきます

]]>
Fri, 19 Feb 2010 23:09:06 +0900
真の豊かさとは何か http://tech.actindi.net/3475492156 今回は、WordPressのフォームネタの続きの筈なのですが、準備が全く間に合ってないので全然関係ない話を。
当社は、社内のコミュニケーションにskypeが活用されているのですが、Emacs派の私とtaharaさんは、もちろんskype.elを愛用しています。
複数人で会話しているので会話が埋もれがちになるのですが、これまでみんなに見ておいて欲しい作業の報告等には、目立つように絵文字をちりばめて派手にしていました。
しかし、それもだんだんスルーされるようになって来たことに危機感を抱いた私は、報告メッセージをAA化し出力することにし、それのためのelispをやっつけで書いてみました。
(defun omatase (arg title name mesg)
  (interactive "p\nstitle: \nsname: \nsmesg: ")
  (let* ((title-chars (append title nil))
         (last-1~3 (last title-chars 3))
         (butlast3 (butlast title-chars 3))
         (last3 (first last-1~3))
         (last2 (second last-1~3))
         (last1 (or (third last-1~3) 12288)))
    (insert (format "
.
┌○┐%s
│%c|ハハ  お待たせしました、%sさん
│%c|゚ω゚)
│%c| //
└○┘ (⌒)
  し⌒ 

%s

  ハハ  以上、よろしくお願いします
 (゚ω゚)
_(_つ/ ̄ ̄ ̄/_
  \/___/
"
                    (if (null butlast3)
                        ""
                      (apply 
                       #'concat 
                       (mapcar (lambda (c) 
                                 (format "\n│%c|" c))
                               butlast3)))
                    last3
                    name
                    last2
                    last1
                    mesg))))
M-x omataseで
title: 死んでもいやです
name: 名無し
mesg: そんなことできません
と入力すると、
.
┌○┐
│死|
│ん|
│で|
│も|
│い|
│や|ハハ  お待たせしました、名無しさん
│で|゚ω゚)
│す| //
└○┘ (⌒)
  し⌒ 

そんなことできません

  ハハ  以上、よろしくお願いします
 (゚ω゚)
_(_つ/ ̄ ̄ ̄/_
  \/___/
という風に出力されます。ただバッファにAAが出力されるだけですが、Emacsって良いですね。
メッセージは依然適当にスルーされています。 ■ ]]>
Thu, 18 Feb 2010 23:29:16 +0900
犯罪的なコミットエンドランを簡単に防ぐ http://tech.actindi.net/3475242539 komagataです。

犯罪的な戦術 - p0t

上記の様な戦術を簡単に防ぐ方法を考えてみました。

リポジトリがsubversionなのでpost-commitのhookを使ってテストを実行し、失敗していたら嫌なメールを送るという方法です。

対象のリポジトリ内のhookファイルに(大抵は/var/lib/svn/#{repost}/post-commit)を以下の様にします。

#!/usr/bin/env ruby

repos, rev = ARGV[0], ARGV[1]
author = `svnlook author #{repos}`
cmd = "cd /var/www/staging/ossuary/current && rake db:migrate:reset && script/spec spec -f progress"
unless system(cmd)
  `mail -s '[ossuary] #{author} made a commit-and-run in r#{rev}' error@actindi.net`
end

[ossuary] komagata made a commit-and-run in rev256 - komagata@gmail.com - Gmail

「komagataはリビジョン256でコミットエンドランを決めた。」

(´・ω・`)・・・。

]]>
Tue, 16 Feb 2010 02:08:59 +0900
Lisp on Rails 第3回 〜 belongs-to http://tech.actindi.net/3474928504 こんにちは!! tahara です。 Lisp on Rails 第3回です!

今回は ActiveRecord の belongs_to アソシエーションもどきを実装したいと思います。 実行時のイメージとしては次のようになります。

(def-record post)
(def-record comment
    (:belongs-to post)) ; comments テーブルは post_id 列を持っている。

(mapcar #'post-of (all comment))
;; => ポストのリストを取得

これを実装するのに Common Lisp の MOP を使ってみます。 インスタンス変数とそのインスタンス変数へのアクセスを拡張することになります。

まずインスタンス変数の拡張です。 ar-belongs-to-slot-mixin に belongs_to のアソシエーションテーブルと 外部キーを持たせ、それを継承した ar-belongs-to-effective-slot-definition を belongs_to のアソシエーションのインスタンス変数とします。

(defclass ar-belongs-to-slot-mixin ()
  ((belongs-to :initarg :belongs-to
               :initform nil
               :accessor belongs-to)
   (foreign-slotname :initarg :foreign-slotname
                     :initform nil
                     :accessor foreign-slotname)))

(defclass ar-belongs-to-effective-slot-definition (ar-effective-slot-definition
                                                   ar-belongs-to-slot-mixin)
  ())

slot-value-using-class を使い ar-belongs-to-effective-slot-definition にアクセスする際に、 foreign-slotname を外部キーとして belongs-to のテーブルから レコードを取得するようにします。

(defmethod c2mop:slot-value-using-class
  ((class active-record-class)
   instance
   (slot-def ar-belongs-to-effective-slot-definition))
  (aif (call-next-method)
       it
       (setf (slot-value instance (belongs-to slot-def))
             (select (find-class (belongs-to slot-def))
                     (slot-value instance (foreign-slotname slot-def))))))

以上、なんとなく belongs-to できました。 ソースはこちらから http://github.com/quek/lisp-on-rails

第4回につづきます

]]>
Fri, 12 Feb 2010 10:55:04 +0900
低価格レンタルサーバーの共有SSLとWordPress (1) http://tech.actindi.net/3474892431 完全にネタが切れてしまいましたので、普段に遭遇する困ったことを書いて行きたいと思います。
月額500円位からの低価格レンタルサーバーと、WordPressの組み合わせは、個人〜中小企業の強い味方なのではないかと思うのですが、SSLのフォームの設置で一癖あるらしい、と風の噂で聞きました。 具体的には、低価格レンタルサーバーでも共有SSLが追加オプションなしで無料で使えることが多いのですが、共有SSLなので、SSLでないURLとはだいぶ違ったURLになります。 例えば、さくらインターネットならば、
http://www.example.com
に対応する共有SSLのURLは、
https://securexxxx.sakura.ne.jp/example.com
になったり、Joe'sウェブホスティングならば、
https://serverxx.instantssl.co.jp/~example
であったり色々です。
どうやら、この辺りの事情とWordPressのデフォルトの挙動の相性が良くないらしいのですが、この辺りをだらだら探っていきたいと思います。
フォーム作成用のWordPressのプラグインは、Contact Form 7を利用することにし、
  • 1. 何が問題の原因なのかを理解する
  • 2. 先達の解決策を探る
  • 3. WordPressをいじれる位はPHPを勉強する
  • 4. WordPressが設置できる位の人なら簡単に設置/設定できるようなプラグインを作る
  • 位の流れで何回かに分けて書いてゆきたいと思います。
    果してPHPも知らない私にプラグインは作れるのでしょうか。■ ]]> Fri, 12 Feb 2010 00:53:51 +0900 Ruby + R http://tech.actindi.net/3474804152 こんにちは。
    masudaです。

    今回はRubyでRを使うというのをやってみようかなと思います。

    RはWikipediaのよると「オープンソースでフリーソフトウェアの統計解析向けプログラミング言語、及びその開発実行環境である。」そうです。

    RubyからRを呼び出すためのRSRubyというgemがあります。
    これがあるとお手軽にRubyからRの機能を呼び出すことが可能です。

    まずはR本体をインストールします。

    次にRubyGemでRSRubyをインストールします。
    オプションでRの場所を指定してあげます。

    Macだとこのようになります。

    sudo gem install rsruby -- --with-R-dir=/Library/Frameworks/R.framework/Resources

    使い方

    require 'rubygems'
    require 'rsruby'
    
    r = RSRuby::instance
    
    r.eval_R(<<-RCOMMAND)
      # 実行したいコマンド
    RCOMMANDS
    

    たったこれだけです。

    x = [1, 2, 3, 4, 5]
    y = [2, 4, 6, 8, 10]
    
    r.eval_R(<<-RCOMMANDS)
      pdf("~/foo.pdf")
    
      x <- matrix(c(#{x.map do |a| '"' + a + '"' end.join(',')}), 1, #{x.size})
      y <- matrix(c(#{y.map do |b| '"' + b + '"' end.join(',')}), 1, #{y.size})
    
      plot(x, y, xlim = c(1, 10), ylim = c(1, 10))
    
      dev.off()
    RCOMMANDS
    

    上記を実行することで、PDFでグラフが作成されます。
    PDFだと何かと便利なので、PDFにしています。

    RubyのArrayからRのArrayには自分はいつも上記のような書き方をしています。
    もっと良い書き方があるのかもしれません。

    私がRをきちんと学んでいないからR単体だけでできるのかもしれませんが、Rubyの強力な文字列処理とRの強力な統計処理、数値演算を手軽に融合できることが気に入っています。

    Rを使っていらっしゃる方は是非一度お試しください。

    ]]>
    Thu, 11 Feb 2010 00:22:32 +0900
    CanvasとWebSocketsでみんなでウロウロする http://tech.actindi.net/3474648989 火曜日担当のkomagataです。

    Metasploitは一回お休みさせていただいてJavascriptのお話しです。

    仕事は主にwebプログラミングなので身も蓋も無い言い方をすると「DBに入れたり出したり」しかしてません。

    「もう文字列処理はうんざりなんだよ!」

    というのは嘘ですが、たまには動きのある見栄えのするグラフィックとかアニメーションとかプログラムしてみたいと思い、HTML5で使えるようになるらしい、グラフィック機能のcanvasと双方向同期通信のWebSocketsを使ってキャラクターがウロウロするだけのプログラムを作ってみました。

    WebSocketsを実装しているのは現状Google Chrome 4以降だけなので、動作してる雰囲気を伝えるために動画にしてみました。

    最近のChromeには実装されているので下記のように簡単にサーバーに接続することができます。

    ws = new WebSocket("ws://localhost:8080/")
    ws.onopen = function() { console.log('open') }
    ws.onclose = function() { console.log('close') }
    ws.onmessage = function(evt) { ws.send('Hello!') }

    CometなどよりとてもシンプルでたちまちWebSocketsが好きになりました!

    Ajaxのように非同期に小さなメッセージをちょこちょこ飛ばすのではなく、1ユーザーに対して1本ガッシリしたラインを繋ぎ、双方向にドカドカ通信するイメージでしょうか。

    真っ先にネットゲーム的なものでの利用方法が思い付きますが、これが標準的なブラウザで使えるようになれば、他の新しい使い方で出てきて斬新なUIが生まれれば良いなと思います。

    とりあえず現状を下記のURLで動かしています。chromeやsafariのnightlyでは動くみたいです。(windows, mac, linuxどれでも動くことは確認しました。)

    http://verdana.komagata.org/prowler/

    ソースは下記です。

    komagata's prowler at master - GitHub

    ]]>
    Tue, 09 Feb 2010 05:16:29 +0900
    CMYK http://tech.actindi.net/3474323393 こんにちは!! tahara です。 今回は Lisp on Rails はお休みで、Ruby on Rails の Paperclip の話題です。

    IE で RGB の画像は表示できますが、CMYK の画像は表示できません。 CMYK から RGB に変換する手もありますが、変換時に結構色が変ってしまいます。 ということでアップロードする画像が CMYK の場合は、 バリデーションではじくようにします。

    まず CMYK の判定ですが、ImageMagic の identify コマンドで可能です。

    ~% identify -format '%[colorspace]' ~/archive/normal.jpg
    CMYK
    ~% identify -format '%[colorspace]' ~/archive/normal-rgb.jpg
    RGB
    

    ただし古い ImageMagic では -format '%[colorspace]' オプションが認識されないので -verbose オプションを使います。

    ~% identify -verbose ~/archive/normal.jpg
    Image: /home/ancient/archive/normal.jpg
      Format: JPEG (Joint Photographic Experts Group JFIF format)
      Class: DirectClass
      Geometry: 290x200+0+0
      Resolution: 72x72
      Print size: 4.02778x2.77778
      Units: PixelsPerInch
      Type: ColorSeparation
      Endianess: Undefined
      Colorspace: CMYK      <=== これ!!
      Depth: 8-bit
      ...
    

    この identify を呼び出して CMYK をチェックするバリデーションを config/initializers/paperclip.rb に組み込みます。

    module Paperclip
      module ClassMethods
        ...
    
        # CMYK は IE で表示できないため、検証でエラーとする。
        def validates_attachment_not_cmyk name, options = {}
          message = options[:message] || "CMYK フォーマットの画像はブラウザによって表示できないため使用できません。お手数ですが RGB フォーマットに変換してください。"
          attachment_definitions[name][:validations][:not_cmyk] = lambda do |attachment, instance|
            original_file = attachment.instance_variable_get(:@queued_for_write)[:original]
            colorspace =
              begin
                attachment.file? && original_file &&
                  Paperclip.run("identify", "-verbose #{original_file.path}")
              rescue
                nil
              end
            if colorspace && colorspace =~ /^\s*Colorspace: CMYK$/
              message
            end
          end
        end
        ....
    

    これでモデルから validates_attachment_not_cmyk というひどい名前のバリデーションが使えるようになります。

      validates_attachment_not_cmyk :picture_1
    

    まとめるとこうなります。

    (incf ImageMagic)
    (decf IE most-positive-fixnum)
    
    ]]>
    Fri, 05 Feb 2010 10:49:53 +0900
    括り出したい http://tech.actindi.net/3474287022 if pred method(100) else method(200) end のようなものを見ると
    method(if pred
             100
           else
             200
           end)
    
    と書きたくなってしまいます。ifは分岐が2つですが、Rubyのcase等の複数への分岐も同じくそうです。 LISPだと
    (method (if pred 100 200))
    
    という感じですが、このifの纏め方は、LISPではすんなり流れるものの、Rubyだとif〜endが重たくみえるので、なんとなく書いてはいけないようにさえ感じます。
    条件演算子なら
    method(pred ? 100 : 200)
    
    という風にすっきりなのですが、なんとなく読みづらいですね。 ]]>
    Fri, 05 Feb 2010 00:43:42 +0900
    Toll-free bridge http://tech.actindi.net/3474198831 こんにちは。
    masudaです。

    今日は節分でしたね。
    あの豆を食べるのが好きです。

    早くもネタが尽きてきました。
    自分がObjective-Cのポテンシャルがわかっていないので(別にObjective-Cである必要は全然ないのですが)、続き物を書くことができません。

    今回はToll-free bridgeについて書いてみようと思います。
    またもやどこにもあるようなネタです。

    Toll-free bridgeについてはHMDTさんなどで詳しく紹介がされています。
    ダイナミックObjective-C (38) Toll-free bridge(1) – 変換コスト0のブリッジ | エンタープライズ | マイコミジャーナル

    CocoaのオブジェクトとCoreFoundationのオブジェクトを相互にキャストするだけで変換することができます。
    たとえばCocoaのNSStringというクラスは、CoreFoundationではCFStringというものに対応します。

    具体例を示しましょう。
    変換の話の前に、CoreFoundationでは初期化はどうするか?

    NSStringであれば

    NSString *hoge = [[NSString alloc] initWithCString:"piyo"];
    

    のように書くところですが、CoreFoundationでは

     
    CFStringRef hoge = CFStringCreateWithCString(kCFAllocatorDefault, "piyo", kCFStringEncodingUTF8);
    

    となります。

    さて、本題のToll-free bridgeによる変換です。
    どのようなときに使うのか?
    具体例を挙げると、NSStringの遅いメソッドであるcharacterAtIndexを呼び出す代わりに、CoreFoundationにあるCFStringGetCharacterFromInlineBuffer関数を使用して高速に処理するなんて使い方をするとか。
    別にすべてCoreFoundationで書いてもかまいませんが、Cocoaを使うよりも幾分面倒なのでこういう適用が多いのではないかと思います。

    NSString                *hoge;
    CFIndex                 length, current;
    CFStringInlineBuffer    buffer;
    UniChar                 ch;
     
    *hoge = [[NSString alloc] initWithCString:"piyo"];
    length = CFStringGetLength((CFStringRef)hoge);
     
    CFStringInitInlineBuffer((CFStringRef)hoge, &buffer, CFRangeMake(0, length));
     
    current = 0;
    while (current < length)
    {
        ch = CFStringGetCharacterFromInlineBuffer(&buffer, current);
        NSLog(@"%c", ch);
     
        ++current;
    }
    

    こんな風にキャストするだけで渡すことができます。
    昔、NSDictionaryの生成をCFDictionaryの生成に変えたところ劇的に速度が向上したことがあったような気がします。

    ]]>
    Thu, 04 Feb 2010 00:13:51 +0900
    Metasploit3で脆弱性を検証する(1) http://tech.actindi.net/3474035399 Penetration Testing | The Metasploit Project

    火曜日担当のkomagataです。

    Gumblerウィルスが猛威を振るっているので流行に乗ってセキュリティネタです。

    脆弱性検証(というか実際に脆弱性を突くので悪用厳禁)ツールのMetasploit3をMacで使ってみました。

    Macportsのはrb-railsやrb-rackが普通のgemとぶつかって入りません。(port editで依存性を外せば入りましたが気持ち悪いです。)

    なので、svnのtrunkを持ってきました。

    % svn co https://www.metasploit.com/svn/framework3/trunk metasploit

    今回checkoutしたのはrevision8340でした。

    % cd metasploit
    % ./msfconsole
    /Users/komagata/code/metasploit/lib/msf/core/exploit/mixins.rb:46:in `require': /Users/komagata/code/metasploit/lib/msf/core/exploit/capture.rb:358: syntax error, unexpected ')', expecting kEND (SyntaxError)
    /Users/komagata/code/metasploit/lib/msf/core/exploit/capture.rb:375: syntax error, unexpected $end, expecting kEND
            from /Users/komagata/code/metasploit/lib/msf/core/exploit/mixins.rb:46
            from /Users/komagata/code/metasploit/lib/msf/core/exploit.rb:216:in `require'
            from /Users/komagata/code/metasploit/lib/msf/core/exploit.rb:216
            from /Users/komagata/code/metasploit/lib/msf/core.rb:52:in `require'
            from /Users/komagata/code/metasploit/lib/msf/core.rb:52
            from /Users/komagata/code/metasploit/lib/msf/ui/console/driver.rb:1:in `require'
            from /Users/komagata/code/metasploit/lib/msf/ui/console/driver.rb:1
            from /Users/komagata/code/metasploit/lib/msf/ui/console.rb:10:in `require'
            from /Users/komagata/code/metasploit/lib/msf/ui/console.rb:10
            from /Users/komagata/code/metasploit/lib/msf/ui.rb:10:in `require'
            from /Users/komagata/code/metasploit/lib/msf/ui.rb:10
            from ./msfconsole:16:in `require'
            from ./msfconsole:16

    ところがcoreで読み込んでるファイルがsyntax error。ほぼ全てのコマンドが動きません。

    「これは良いコミットエンドラン・・・(ゴクリ)」

    % svn diff
    Index: lib/msf/core/exploit/capture.rb
    ===================================================================
    --- lib/msf/core/exploit/capture.rb     (revision 8340)
    +++ lib/msf/core/exploit/capture.rb     (working copy)
    @@ -355,7 +355,7 @@
                    rescue RuntimeError => e
                            @pcaprub_error = e
                            print_status("Cannot stat device: #{@pcaprub_error}")
    -                       raise RuntimeError, "Pcaprub error: #{@pcaprub_error}")
    +                       raise RuntimeError, "Pcaprub error: #{@pcaprub_error}"
                    end
                    return my_net
            end

    取り敢えずこれで動きますのでお急ぎの方は是非。

    % ./msfconsole
    
                    |                    |      _) |   
     __ `__ \   _ \ __|  _` |  __| __ \  |  _ \  | __| 
     |   |   |  __/ |   (   |\__ \ |   | | (   | | |   
    _|  _|  _|\___|\__|\__,_|____/ .__/ _|\___/ _|\__| 
                                  _|                   
    
    
           =[ metasploit v3.3.4-dev [core:3.3 api:1.0]
    + -- --=[ 176 exploits - 30 auxiliary
    + -- --=[ 104 payloads - 17 encoders - 5 nops
           =[ svn r8340 updated today (2010.02.01)
    
    msf >

    metasploitはversion3からperlからrubyになったらしく、僕にとっては読みやすくて嬉しいです。でもWebインターフェースがRailsなのは少しアグレッシヴですね。

    次回は実際に脆弱性を突いてみようと思います。

    ]]>
    Tue, 02 Feb 2010 02:49:59 +0900
    Lisp on Rails 第2回 〜 メタクラス http://tech.actindi.net/3473716585 こんにちは!! tahara です。 Lisp on Rails 第2回です!

    ActiveRecord::Base ではクラスメソッドとして find や all の検索メソッドが定義されています。

    Common Lisp でそれらを実装するにあたり、メタクラスのメソッドとして実装してみます。 Common Lisp では自分でメタクラスを定義することができます。 次のようにメタクラスを定義します。 なんとなく、テーブル名とカラム情報を持たせています。

    (defclass active-record-class (standard-class)
      ((%table-name :initarg :%table-name :accessor %table-name-of)
       (%columns :initarg :%columns :accessor %columns-of)))
    
    各テーブル毎のクラスはこの active-record-class のインスタンスになり、 インスタンス変数としてテーブル名とカラム情報を持つイメージです。

    メタクラスに全レコードを取得する all メソッドを実装します。

    (defmethod all ((class active-record-class))
      (multiple-value-bind (rows columns)
          (clsql-sys:query (format nil "select * from ~a" (%table-name-of class)))
        (loop for i in rows
              collect (make-instance-from-row class i columns))))
    

    (def-record post) は次のように展開されて :METACLASS ACTIVE-RECORD::ACTIVE-RECORD-CLASS を指定します。

    (PROGN
      (DEFPARAMETER POST
        (DEFCLASS POST (BASE)
          ((ID :INITARG :ID :INITFORM NIL :ACCESSOR ID-OF)
           (NAME :INITARG :NAME :INITFORM NIL :ACCESSOR NAME-OF)
           (TITLE :INITARG :TITLE :INITFORM NIL :ACCESSOR TITLE-OF)
           (CONTENT :INITARG :CONTENT :INITFORM NIL :ACCESSOR CONTENT-OF)
           (CREATED-AT :INITARG :CREATED-AT :INITFORM NIL :ACCESSOR
                       CREATED-AT-OF)
           (UPDATED-AT :INITARG :UPDATED-AT :INITFORM NIL :ACCESSOR
                       UPDATED-AT-OF))
          (:METACLASS ACTIVE-RECORD::ACTIVE-RECORD-CLASS)))
          ...
    
    Ruby のクラス定義と違って Common Lisp のクラス定義ではクラス名に何も束縛しないため、 わざわざ defparameter しています。

    そんな感じでメタクラスによる

    (all post)
    
    ができました。

    ソースはこちらから http://github.com/quek/lisp-on-rails

    第3回につづきます

    ]]>
    Fri, 29 Jan 2010 10:16:25 +0900
    PerlとC++にしかできないような気がした十五の夜 http://tech.actindi.net/3473675040 今年の私のテーマは「挑戦」。 先日、そんな私にぴったりな、盗んだバイクで走り出したくなる挑戦をみつけました。
  • PerlとC++にしかできないような気がするアノ機能(挑戦者募集中)
  • #!/usr/bin/perl
    # PerlとC++は世界一。
    
    srand(time);
    
    my $a = 0;
    my $b = 0;
    for(my $i = 0; $i < 1000; $i++) {
        (rand(2)<1 ? $a : $b) += 1;
    }
    print "$a, $b\n"
    
    これをPerlや、C++以外の言語で書けるのか、と。
    私は、LISP野郎なのでLISPで回答するとして考えましたが「実行時に変数の名前によって任意の変数にアクセスし、その変数に値を代入できるか」という風にお題を解釈しました。 PerlやC++の場合は、?:にそういう機能があるのでしょう。 Common Lispだとどうなるかというと、「実行時に変数の名前によって任意の変数にアクセス」というのは、シンボル名による変数へのアクセスで可能なので、上をCommon Lispに訳すと
    (let ((a 0) (b 0))
      (declare (special a b))
      (dotimes (i 1000)
        (incf (symbol-value
               (if (< (random 2) 1) 'a 'b))))
      (format t "~A, ~A~%" a b))
    ;⇒ NIL
    ----------
    499, 501
    
    こんな感じに書くことになるのかなあと思いました。
    …というようなことをtaharaさんと昼食時に話していたのですが、taharaさん曰くifにsetfが付いてれば可能なんじゃないかとのこと。 なるほど、確かにそうです。
    setfというのは代入する構文のマクロなのですが、ユーザーが色々カスタマイズできます。 実行時に変数名でアクセス→代入というのではなく、そういう構文をマクロで定義するわけですね。
    ユーザーがifにsetfを書けば良いのですが、これが標準で付いている処理系をどっかでみたなーと思ったので調べてみるとCLISPがそうでした。 CLISPだと標準で
    (let ((a 0) (b 0))
      (dotimes (i 1000)
        (incf (if (< (random 2) 1) a b)))
      (format t "~A, ~A~%" a b))
    ;⇒ NIL
    ----------
    513, 487
    
    と書けます。自分はPerlは書けないのですが、+=をカスタマイズすることによって
    for(my $i = 0; $i < 1000; $i++) {
        if (rand(2) < 1) { 
          $a 
        } else {
          $b
        } += 1;
    }
    
    のようにも書けるようにユーザーが勝手に定義できる、という感じでしょうか。
    こんなことをしているとすぐカオスになりそうですが、LISPに構文は無いようなものなので特に混乱もなかったりします。LISPは単純で良いですね■ ]]>
    Thu, 28 Jan 2010 22:44:00 +0900
    iPhoneによる位置情報関係のまとめ http://tech.actindi.net/3473583175 こんにちは。
    先日komagataさんにgit svnの使い方を教えていただいたおかげで、少しは使えるようになってきたmasudaです。

    今回も前回のGeohashに引き続き、位置情報に関する内容です。
    ググれば出てくる内容なので、新しいことはなんにもないのが申し訳ないところです。

    位置情報に関するライブラリは

    • CoreLocation
    • MapKit
    などがあります。

    GPSで現在位置を取得するにはCoreLocationを使用し、地図を表示したり現在地の大まかな住所を取得するためにはMapKitを使用します。

    CoreLocationではCLLocationManagerDelegateを実装し

    CLLocationManager *locationManager = [[CLLocationManager alloc] init];
        if ([locationManager locationServicesEnabled])
        {
            [locationManager setDelegate:self];
            [locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
            [locationManager setDistanceFilter:kCLDistanceFilterNone];
        }
    
    - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
    {
        NSLog(@"%@", newLocation);
    }

    このようにすればLogに現在地の情報が取得できます。

    地図を表示するには

    CGRect screen = [[UIScreen mainScreen] bounds];
    MKMapView *mapView = [[MKMapView alloc] initWithFrame:screen];
    [[self view] addSubview:mapView];
    [mapView release];
    
    MKCoordinateRegion  region;
    region.center = [location coordinate];
    region.span.latitudeDelta = 0.005;
    region.span.longitudeDelta = 0.005;
    [mapView setRegion:region animated:YES];

    とすれば、locationで指定した座標に移動します。

    現在地を取得するにはMKReverseGeocoderDelegateを実装し

    MKReverseGeocoder *reverseGeocoder = [[MKReverseGeocoder alloc] initWithCoordinate:[location coordinate]];
    [reverseGeocoder setDelegate:self];
    [reverseGeocoder start];
    
    - (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark
    {
        NSLog(@"%@", [placemark title]);
    }

    とすることで取得することができます。
    すべてのAPIが非常にシンプルに作られているので、使用するのは非常に簡単です。

    ]]>
    Wed, 27 Jan 2010 21:12:55 +0900
    Lispに興味がない・・・だと・・・? http://tech.actindi.net/3473547098

    興味のある言語にLispと書いておいたら面接で爆笑された

    面接官「Lisp・・・ふははっ!Lisp!」

    面接官「Lispやってるんですか?wwwww」

    俺「(唖然)は、はい・・まだS式を理解したぐらいですが。。」

    面接官「Lisp・・・ニヤニヤ」

    Hunchentootで動いてるこのブログを見て弊社に面接に来た方がCommon Lispに興味なかったらメンバー全員がっかりしますね・・・。

    ]]>
    Wed, 27 Jan 2010 11:11:38 +0900
    Real (World) Git http://tech.actindi.net/3473481089 火曜日担当のkomagataです。

    gitよく分からないのでどういう風に使ってるのかデモってくれと言われたので実際に仕事のコードにコミットしてみました。

    実録!git!

    アクトインディでは「子供とのお出かけ先を探すサイト」いこーよhttp://iko-yo.net)というサイトを運営しています。 リポジトリはデザイナーさんがDreamweaverCodaのsvnクライアントを使うのでSubversionです。

    svnの最新リビジョンだけを持ってくる。(全部持ってくると死ぬほど時間がかかる。)

    % git svn clone -r HEAD https://svn.actindi.net/svn/oyaiku/trunk/outing outing --username=komagata

    Redmineのチケットを見る。 予め仕込んでおいた簡単そうなチケットを発見。(redmineではイシューというみたいです)

    いこーよ - 新機能 #3487: cityモデルのテストを書く - Redmine(タスク管理)

    チケットに対応したブランチを作る。

    % git branch issue3487

    作業ブランチを切り替える。

    % git checkout issue3487
    (git branch foo; git checkout fooはgit checkout -b fooと同じ)

    ブランチ確認。

    % git branch
      master
    * issue3487

    shouldaスタイルのマクロが使いたいのでremarkableを入れる。

    # config/environment.rb
    Rails::Initializer.run do |config|
      config.gem 'remarkable_rails', :lib => false
    end
    # spec/spec_helper.rb
    require 'spec/rails' # ここの下に書く
    require 'remarkable_rails'
    % sudo rake gems:install
    % rake gems:unpack
    % rake gems:refresh_spec

    一旦、コミット。

    % git add vendor vendor/gems/remarkable_rails-3.1.12
    % git commit -a -m'added remarkable'

    app/model/city.rbのテストを作る。

    # app/model/city.rb
    class City < ActiveRecord::Base
      belongs_to :prefecture
    
      validates_presence_of :name, :reading, :roman
      validates_length_of :name, :within => 1..40
      validates_length_of :reading, :within => 1..40
      validates_length_of :roman, :within => 1..40
      validates_uniqueness_of :roman
    end
    # spec/models/city_spec.rb
    require 'spec_helper'
    
    describe City do
      fixtures :cities
    
      should_belong_to :prefecture
      should_validate_presence_of :name
      should_validate_presence_of :reading
      should_validate_presence_of :roman
      should_validate_length_of :name, :within => 1..40
      should_validate_length_of :reading, :within => 1..40
      should_validate_length_of :roman, :within => 1..40
      should_validate_uniqueness_of :roman
    end

    テスト実行(ホントは全部のテストを実行する)

    % ./script/spec spec/models/city_spec.rb
    
    City
    - should belong to prefecture
    - should require name to be set
    - should require reading to be set
    - should require roman to be set
    - should ensure length of name is within 1..40 characters
    - should ensure length of reading is within 1..40 characters
    - should ensure length of roman is within 1..40 characters
    - should require unique values for roman
    
    Finished in 0.770165 seconds
    
    8 examples, 0 failures

    コミット

    % git add spec/models/city_spec.rb
    % git ci -a -m'added city_spec. fixed #3487'

    masterに移る。

    % git checkout master

    最新版を持ってくる

    % git svn rebase

    issue3487をマージする

    % git merge issue3487

    svnにコミット。

    % git svn dcommit

    完了。

    その他の便利機能

    いっこ前のコミットなかったことにする

    % git reset HEAD^

    昔のコミットを修正したい

    % git log --oneline
    c5524b2 * removed foo * removed remarkable
    460bfa1 [デザイン] TOPページ「外へおでかけ」の変更 (refs #3490) * 谷さん修正分
    9b819fd * add city_spec * add remarkable * add foo
    695b1eb [システム] [mobile] /facilities/:id のレイアウト変更。 (refs #2899) * いらないhrを削除。
    % git rebase -i 695b1eb

    エディタが立ち上がるので修正したいリビジョンのpickをeditに変更して終了する。

    pick 9b819fd * add city_spec * add remarkable * add foo
    pick 460bfa1 [デザイン] TOPページ「外へおでかけ」の変更 (refs #3490) * 谷さん修正分
    edit c5524b2 * removed foo * removed remarkable

    指定したリビジョンの状態に戻るので好きにaddしたり編集したりする。

    % git commit --amend
    % git rebase --continue

    修正完了

    複数の適当なコミットを一つにまとめたい

    % git log --oneline
    68fb234 add text2 in foo
    5cd81d6 add text in foo
    43fdcb7 add foo
    fb91711 removed old paperclip
    aa21e65 fixed
    % git rebase -i fb91711
    pick 43fdcb7 add foo
    pick 5cd81d6 add text in foo
    pick 68fb234 add text2 in foo

    次のリビジョンとまとめたいリビジョンの先頭をpickからsquashに変える。

    pick 43fdcb7 add foo
    squash 5cd81d6 add text in foo
    squash 68fb234 add text2 in foo

    コミットメッセージをいれて終了。

    みなさんおっしゃってますが、やはり、svnからgitにして嬉しいのはbranchの作成やcommitが気軽できるところですね。一つの作業をやってる途中に別の優先タスクが入った場合も、現在のbranchをほっぽってすぐにそちらのタスクに移れるのは精神的にもとても楽です。

    適当にfixed, fixedなどとコミットしていっても後で綺麗にまとめられるところもいいですね。

    gitは他にもいろいろ出来るみたいですが、今のところリアルにこんな感じで使っています。便利な使い方があれば教えて頂けると嬉しいです。

    ]]>
    Tue, 26 Jan 2010 16:51:29 +0900
    Lisp on Rails 第1回 http://tech.actindi.net/3473158189 こんばんは!! tahara です。

    いま仕事で Ruby on Rails を使っています。 正直 Active Record いいっすねー。 DB いじるには楽です。

    くやしいので Common Lisp でそれっぽいのを実装してみます。 Lisp on Rails ですね(何だか以前から聞く言葉のような気もします)。

    第1回目の今日は何となく Active Record っぽい雰囲気のような感じだけです。

    (eval-when (:compile-toplevel :load-toplevel :execute)
      (setf *connection-spec* '("localhost" "blog_test" "root" ""))
      (setq clsql-sys:*default-database-type* :mysql)
      (establish-connection))
    
    ;; レコードの定義
    (def-record post)
    ;; インサート
    (save (make-instance 'post :name "名前" :title "タイトル" :content "内容"))
    ;; 検索
    (all post)
    

    ソースはこちらから http://github.com/quek/lisp-on-rails

    第2回につづきます

    ]]>
    Fri, 22 Jan 2010 23:09:49 +0900
    Rubyの好きなところ http://tech.actindi.net/3473072867 x = 3 [0, *if x.even? [1, 2, 3] else [:a, :b, :c] end] ;⇒ [0, :a, :b, :c]
    def iota(n)
      if n.zero?
        0
      else
        [n, *iota(n - 1)]
      end
    end
    
    iota(10)
    ;⇒ [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
    
    Proc.new do |x, y| x * y;end [100,2]
    ;⇒ 200
    
    LISP/Schemeでも、書けるといえば書けるのですが、
    ;; Common LISP
    (let ((x 3))
      `#(0 ,@(if (evenp x)
                 '(1 2 3)
                 '(:a :b :c))))
    ;⇒ #(0 :A :B :C)
    
    (defun iota (n)
      (if (zerop n)
          (list 0)
          `(,n ,@(iota (1- n)))))
    
    ;⇒ (10 9 8 7 6 5 4 3 2 1 0)
    
    (multiple-value-call #'* (values-list '(100 2)))
    ;⇒ 200
    
    ;; もしくは
    (apply #'* '(100 2))
    ;⇒ 200
    
    Rubyの方が統一感があって良いですね。 ]]>
    Thu, 21 Jan 2010 23:27:47 +0900
    Objective-C的???Geohash http://tech.actindi.net/3472988345 こんにちは!
    はまっている時間はたいていRSpecに起因するものなのではないかと以前から感じているmasudaです。
    なんとか約束の火曜日に間に合ったでしょうか???

    先日chibaさんがGeohashをdecodeするものをCLで書いていらしたので、それを微妙に参考にしながらCocoaのCoreLocationのCLLocationにgeohashをencode/decodeするメソッド追加してみました。

    本当はビット演算がしたいのですが、文字列処理の方が自分には単純で簡単だったため、とりあえず今回は文字列処理にしてみました。

    我ながらひどいコードだと思いますので、これからリファクタリングをしていきたいところです。

    [CLLocation+Geohash.h]

    #import <CoreLocation/CoreLocation.h>
    #import <Foundation/Foundation.h>
    
    
    @interface CLLocation(Geohash)
    
    @property (nonatomic, readonly)   NSString    *geohash;
    
    + (CLLocation *)locationFromGeohash:(NSString *)aGeohash;
    
    @end
    

    [CLLocation+Geohash.m]

    #import "CLLocation+Geohash.h"
    
    #include <math.h>
    
    NSString *int_to_binary(NSUInteger input)
    {
        if (input == 1 || input == 0)
        {
            return [NSString stringWithFormat:@"%d", input];
        }
    
        return [NSString stringWithFormat:@"%@%d", int_to_binary(input / 2), input % 2];
    }
    
    
    double parse_binary(NSString *binary, double max, double min)
    {
        double mid = 0.0;
        
        for (NSUInteger i = 0; i < [binary length]; ++i)
        {
            if ([binary characterAtIndex:i] == '1')
            {
                min = mid;
            }
            else
            {
                max = mid;
            }
            
            mid = (max + min) / 2;
        }
        
        return mid;
    }
    
    
    NSUInteger binary_to_int(NSString *input)
    {
        NSUInteger result, length;
    
        result = 0;
        length = [input length];
    
        for (NSUInteger i = 0; i < length; ++i)
        {
            if ([input characterAtIndex:i] == '1')
            {
                result += pow(2, length - i - 1);
            }
        }
    
        return result;
    }
    
    
    NSString * generate_binary(double input, double max, double min, int cutoff)
    {
        NSMutableString     *result;
        double              mid;
    
        result = [NSMutableString string];
        for (int i = 0; i < cutoff; ++i)
        {
            mid = (max + min) / 2;
    
            if (input > mid)
            {
                [result appendString:@"1"];
                min = mid;
            }
            else
            {
                [result appendString:@"0"];
                max = mid;
            }
        }
    
        return [NSString stringWithString:result];
    }
    
    
    @implementation CLLocation(Geohash)
    
    - (NSString *)geohash
    {
        int cutoff = 15;
        NSString *base32_characters  = @"0123456789bcdefghjkmnpqrstuvwxyz";
    
        NSString            *bin_lat, *bin_lng;
        NSMutableString     *bin_packed, *result;
        
        bin_lat = generate_binary([self coordinate].latitude, 90.0, -90.0, cutoff);
        bin_lng = generate_binary([self coordinate].longitude, 180.0, -180.0, cutoff);
    
        bin_packed = [NSMutableString string];
    
        for (int i = 0; i < [bin_lat length]; ++i)
        {
            [bin_packed appendFormat:@"%c%c", [bin_lng characterAtIndex:i], [bin_lat characterAtIndex:i]];
        }
    
        result = [NSMutableString string];
    
        // extract by 5-bit.
        for (int i = 0; i < [bin_packed length] / 5; ++i)
        {
            NSUInteger index;
            index = binary_to_int([bin_packed substringWithRange:NSMakeRange(i * 5, 5)]);
            [result appendFormat:@"%c", [base32_characters characterAtIndex:index]];
        }
    
        return result;
    }
    
    
    + (CLLocation *)locationFromGeohash:(NSString *)aGeohash
    {
        NSString *base32_characters  = @"0123456789bcdefghjkmnpqrstuvwxyz";
    
        NSMutableString *bin_packed, *bin_lat, *bin_lng;
    
        bin_packed = [NSMutableString string];
    
        for (NSUInteger i = 0; i < [aGeohash length]; ++i)
        {
            NSString *character;
            character = [[NSMutableString stringWithFormat:@"%c", [aGeohash characterAtIndex:i]] lowercaseString];
    
            for (NSUInteger j = 0; j < [base32_characters length]; ++j)
            {
                if ([character isEqualToString:[NSString stringWithFormat:@"%c", [base32_characters characterAtIndex:j]]])
                {
                    NSMutableString *binary;
                    binary = [NSMutableString stringWithFormat:@"%@", int_to_binary(j)];
    
                    NSUInteger length = [binary length];
                    for (NSUInteger k = 0; k < 5 - length; ++k)
                    {
                        [binary insertString:@"0" atIndex:0];
                    }
    
                    [bin_packed appendString:binary];
                    break;
                }
            }
        }
    
        bin_lat = [NSMutableString string];
        bin_lng = [NSMutableString string];
    
        for (NSUInteger i = 0; i < [bin_packed length]; ++i)
        {
            if (i % 2)
            {
                // a latitude is composed of odd bits. 
                [bin_lat appendFormat:@"%c", [bin_packed characterAtIndex:i]];
            }
            else
            {
                // a longitude is composed of even bits.
                [bin_lng appendFormat:@"%c", [bin_packed characterAtIndex:i]];
            }
        }
    
        return [[CLLocation alloc] initWithLatitude:parse_binary(bin_lat, 90.0, -90.0)
                                          longitude:parse_binary(bin_lng, 180.0, -180.0)];
    }
    
    
    @end
    

    NSStringでかなり遅いcharacterAtIndexを使いまくっている。

    参考

    Geohash - Wikipedia, the free encyclopedia
    GeoHashのdecodeのアルゴリズムの解説します & ScalaのGeoHashライブラリを作ってみました(仮) - ゆろよろ日記

    ]]>
    Wed, 20 Jan 2010 23:59:05 +0900
    テストを通らないリリースを止めるライブラリ http://tech.actindi.net/3472868530 昼にキリンフリーを飲むと機嫌が良くなる火曜日担当のkomagataです。

    rspecのテストが通らないとデプロイを止めてしまうcapistranoのレシピのgemを作りました。

    showstopper 0.1.0

    ShowStopper is capistrano recipe that stop deploy when rspec is red.

    インストール

    $ sudo gem install showstopper -s http://gemcutter.org

    Capfileの中で読み込むだけで設定完了です。

    $ vi Capfile
    (...)
    require 'showstopper'

    これでrspecが通ってないのに誰かがデプロイしようとすると・・・

    % cap deploy
    (...)
      * == Currently executing `deploy'
        triggering before callbacks for `deploy'
      * == Currently executing `deploy:spec'
        rspec test failed

    showstopperがデプロイを中止してしまいます!

    これを投入していい加減なテストのあるプロジェクトを恐怖のどん底に陥れてやりましょう!

    ]]>
    Tue, 19 Jan 2010 14:42:10 +0900
    autotest-stumpwm http://tech.actindi.net/3472528762 こんにちは!! tahara です。

    script/autospec の結果を表示してくれる Growl がうらやましいのですが、私 の使っているのは Linux です。しかし、Linux には Stumpwm があります。 Stumpwm の stumpish を使えば echo でメッセージを表示することができます。

    そこで script/autospec の結果を Stumpwm で表示する gem を作ってみます。

    参考サイト

    gem を作るには Jeweler を使うのがよさそうです。 Jeweler は GitHub の API を使うようなので、まずその設定を行います。 user_name と api_token には自分の Username と API Token を指定します。

    git config --global github.user user_name
    git config --global github.token api_token
    

    Jeweler をインストールしてプロジェクトを作ってみます。

    gem install jeweler
    jeweler --rspec --create-repo autotest-stumpwm
    

    これで綺麗にプロジェクトが作成されます。 おまけに GitHub にリポジトリまでできています。

    次に Rakefile を編集します。TODO になっている次の二箇所を適当に編集すればよさそうです。 あと依存する gem も指定しておきます。

        gem.summary = %Q{TODO: one-line summary of your gem}
        gem.description = %Q{TODO: longer description of your gem}
        gem.add_dependency "autotest-growl", ">= 0.1.7"
    

    次に lib の下のファイルに Stumpwm を使って script/autospec の結果を表示するたコードを書きます。 コードが出きたら次のようにリリースします。

    rake version:write
    rake gemspec
    rake release
    

    これだけで Gemcutter にも自動的に公開されます。 Jeweler すばらしい!!

    修正したら git commit して、次のいずれかでバージョンをあげ rake release するだけ。

    rake version:bump:major              # Bump the gemspec by a major version.
    rake version:bump:minor              # Bump the gemspec by a minor version.
    rake version:bump:patch              # Bump the gemspec by a patch
    

    できあがった autotest-stumpwm を使うには gem install autotest-stumpwm して、 ~/.autotest に次の一行を書きます。これで autospec と Stumpwm の幸せな生活がおくれます。

    require 'autotest/stumpwm'
    

    さて、一番大切な Stumpwm で結果を表示するコードですが、

    # -*- coding: undecided -*-
    require 'rubygems'
    require 'autotest/growl'
    
    module Autotest::Growl
      def self.growl(title, message, icon, priority=0, stick="")
        priority = if priority > 0  # error or feailed
                     1              # red
                   elsif priority == -2 # passed
                     2                  # green
                   else
                     3              # yellow
                   end
        system "stumpish echo ^#{priority}* #{title} #{message}"
      end
    end
    
    ごめんなさい autotest-growl にモンキーパッチをあてただけです。 ]]>
    Fri, 15 Jan 2010 16:19:22 +0900
    Geohash http://tech.actindi.net/3472464385 Geohash - Wikipedia, the free encyclopedia そんな感じで、説明の順番のとおりに書いてできたコードが下記です。 なんとなく仕組みは分かったけど、そういえば、エンコード手順の説明は書いてないんだなあ…、と自分勝手なことを考えながら就寝しました。
    (defpackage :geohash
      (:use :cl)
      (:import-from :shibuya.lisp
                    :$ :$*))
    
    (in-package :geohash)
    
    (defun tr (from to string)
      (map 'string 
           (lambda (c)
             (or (some (lambda (x y) 
                         (and (char-equal x c) y))
                       from to)
                 (char-upcase c)))
           string))
    
    (defun 5bits (string)
      (map 'list
           ($ format nil "~5,'0,B" 
              $ read-from-string 
              $ format nil "#32R~A" 
              $ tr "0123456789BCDEFGHJKMNPQRSTUVWXYZ" 
                   "0123456789ABCDEFGHKJKLMNOPQRSTUV" 
              $ string $)
           string))
    
    (defun longitude-latitude (strings)
      (let ((bit-c-list ($* concatenate 'list strings)))
        (loop :for c :in bit-c-list
              :for i :from (if (char= #\0 (car bit-c-list)) 0 1)
              :if (evenp i) :collect c :into even
              :else :collect c :into odd
              :finally (return 
                         (list :longitude
                               (coerce even 'string) 
                               :latitude
                               (coerce odd 'string))))))
    
    (defun bitlist (string)
      (map 'list ($ parse-integer $ string $) 
           string))
    
    (defun decode (bits min mid max)
      (if (endp bits)
          mid
          ($* decode 
              (cdr bits)
              (if (zerop (car bits))
                  (list min (/ (+ mid min) 2) mid)
                  (list mid (/ (+ mid max) 2) max)))))
    
    (defun decode-geohash (string)
      (let* ((u ($ longitude-latitude $ 5bits string))
             (lon (getf u :longitude))
             (lat (getf u :latitude)))
        (list 
         :longitude 
         ($ float $ decode (bitlist lon) -90 0 90)
         :latitude
         ($ float $ decode (bitlist lat) -180 0 180))))
    
    (decode-geohash "u4pruydqqvj")
    ;⇒ (:LONGITUDE 57.64911 :LATITUDE 10.407439)
    
    ]]>
    Thu, 14 Jan 2010 22:26:25 +0900
    Delaunay Tessellation for iPhone http://tech.actindi.net/3472341020 こんにちは!!!
    今まで更新しろとせっつかれていたのにもかかわらず、全然更新しなかったmasudaです。

    とりあえず最初は今までやったのにアップロードしていなかったプログラムプレゼンテーションのネタを書こうかなと思います。

    過去の部分はこちらを参考にしてください。

    第1回 cocoa*life - Apple Push Notification Serviceを利用した、iPhone クライアントと、Rubyによるサーバの作成。

    第3回 cocoa*life - Grand Central Dispatchを試してみる。

    以下、同様にblogに載せようと思って途中でやめていたものを載せようと思います。

    プログラムプレゼンテーションの第2回は、iPhoneを用いてDelaunay分割をするというものにしてみました。

    本当は他のものをやるつもりだったのですが、前回のプログラムプレゼンテーションではkomagataさんがObjective-Cのキメラさ、カオスさをおもしろがっていたと勝手に仮定して、Objective-C++でさらなるカオスさを目指すことにしました。

    そんな折りに以前ドロネー分割をするためのプログラムをつくって、アップロードしようかなといっていたのを思い出しました。

    ということで、今回はそれを流用することにしました。
    単純に移植するだけだから簡単だろと思ったところ、意外と手直しに時間がかかってしまいました。

    ドロネー分割については計算幾何学で出てくるものですが、この余白はそれを書くのにはせますぎるということで、ググればきっとわかる!!!

    ソースコードはこちらです。
    ライブラリとしてBoost C++ Librariesを使用しています。

    実行すると、毎回ランダムな10点を作成し、下図のようにドロネー分割された図が表示されます。

    Delaunay tessellation   Delaunay tessellation with circumcircles

    右側の図は外接円も表示させた場合です。
    ドロネー分割では生成された三角形によって作られる外接円の中に、その三角形以外の点が含まれてはいけません。

    ランダムな点を生成する部分にはboost::randomを用い、ドロネー分割を計算する部分はC++で書かれています。

    Objective-CとC++のコードを混ぜる場合の注意点は、HMDTさんによくまとめられているのでこちらを参照していただくのがよいかと思います。
    HMDT – Objective-C++

    Objective-C++のソースを書かれるときは、.mとなっている拡張子を.mmにしてくださいね。
    自分はこれをしないでObjective-C++のファイルだと認識されずはまりまくりました。

    こんな風にC++のコードも簡単に使用することができるので、Objective-Cを使われている皆様もぜひ組み合わせてみてはいかがでしょうか???

    P.S.
    本当はNSOperationを使って、スレッドを新しく作ってバックグラウンドで処理をしたかったのですが、プログラムの構造上面倒なのでやめました。

    参考
    Objective-C プログラミング言語:C++ と Objective-C の併用
    HMDT – Objective-C++

    ]]>
    Wed, 13 Jan 2010 12:10:20 +0900
    Webプログラマーチュートリアル http://tech.actindi.net/3472257910 ニコ生はじめました。komagataです。

    新しくtaharaさんをメンバーに加えて、毎日持ち回りでこのブログを更新していくことになりました。

    火曜日:komagata
    水曜日:masudaさん
    木曜日:chibaさん
    金曜日:taharaさん

    このような曜日担当で更新してきます。忘れていたら罵倒してください・・・。

    ほとんどtaharaさんが書いてくれたのですが、Webプログラマーチュートリアルを作りました。

    web-programmer-tutorial - Project Hosting on Google Code

    何らかのプログラム経験さえあれば、これをみて自習するだけで業務するのに必要なスキルが習得できるように、ゴールと参考URL・書籍の一覧を用意しました。

    入社した最初の一ヶ月を研修期間としてこれをやることにしました。(やりながらメニュー自体も改善する)

    これならば自宅を警備しながらスキルを付けることが出来るのではないかと期待しております。

    OJTのみになってしまっているのを改善したいITベンチャーの方や自宅警備員の方でこれを使ってわからないところがあれば全力で支援いたします。

    ]]>
    Tue, 12 Jan 2010 13:05:10 +0900
    Hunchentoot になりました http://tech.actindi.net/3470616064 こんにちは。12月からメンバにくわわった tahara と申します。
    chiba さんの念願でした、このブログの AllegroServe から Hunchentoot への移行を行いました。
    既に chiba さんが Hunchentoot への移植はやってくれていたので Elephant の導入がメイン作業でした。 Elephant は Common Lisp のオブジェクトデータベースです。バックエンドは色々選べるのですが、今回は SQLite3 を使いました。

    現在このブログは次のような構成で動いています。

    それでは、今後ともよろしくお願いいたします。

    ]]>
    Thu, 24 Dec 2009 13:01:04 +0900
    StumpWMは便利です http://tech.actindi.net/3466487639 今回のプログラム・プレゼンテーションのネタはStumpWMです。 StumpWMはタイル型ウィンドウマネージャーなのですが、Common LISPで色々と拡張することができるのが特長です。

    今回は、このちょっとしたカスタマイズネタや使い方です。

    Actindi社内では現在全面的にRedmineで仕事を管理していて、仕事の確認/依頼もチケット番号ですることが非常に多いです。
    いつもチケットの番号でやりとりするのですが、伝えられた番号をぱっと開きたいことが多いので、これをStumpWMで便利にしてみようということで工夫してみました

      
    (DEFPARAMETER *LAST-TICKET* NIL)
    
    (DEFCOMMAND SHOW-TICKET (TICKET-NUMBER) ((:STRING "Ticket#: "))
      (WHEN (RUN-SHELL-COMMAND 
             (FORMAT NIL 
                    "/usr/bin/firefox "https://redmine.example.com/issues/show/~A\""
                     TICKET-NUMBER))
       (SETQ *LAST-TICKET* TICKET-NUMBER)))
    
    (DEFCOMMAND EDIT-IT () ()
      (RUN-SHELL-COMMAND
        (FORMAT NIL
                "/usr/bin/firefox "https://redmine.example.com/issues/edit/~A\""
                *LAST-TICKET*)))
    

    非常にでっちあげ感の漂う適当なコードですが、show-ticket 1234という風に実行すると、Redmineの1234番のチケットがfirefoxで表示されます。
    edit-itコマンドは保存していた直前のチケット番号を編集状態で開くという単純なものです。 ちょっとした工夫ですが、割と便利で愛用しています。
    といった具合で、その他、StumpWMの機能の説明をして1時間をしのぎました。
    みなさんもご興味あれば、StumpWMをお試しあれ。

    ]]>
    Fri, 06 Nov 2009 18:13:59 +0900
    さようならsed、こんにちはCommon Lisp http://tech.actindi.net/3463978702 chibaです。

    今回のプログラム・プレゼンテーションのネタは日常で使うちょっとしたスクリプトをCommon Lispでやってみようというものです。

    ネタ切れなので自分の ブログに書いたネタ を再演しつつ、ブログでは紹介してなかったwgetも併せて動かしてみました

  • 適当なwget
  • Software ToolsのごとくCommon Lisp上にユーティリティを作成して行けば、Common Lispだけでこういう細かい仕事はできるようになるやもしれません。

    ]]>
    Thu, 08 Oct 2009 17:18:22 +0900
    ブログもどき的、あまりにもブログもどき的 http://tech.actindi.net/3463977650 chibaです。

    今回のプログラム・プレゼンテーションのネタはこのブログもどきについてです。 そもそもは、ちょっと変ったことをしてみようということで、技術方面のブログはCLで作ってみようということになりました。

    構成は、

    • CL処理系: SBCL
    • AllegroServe(RubyでいうWEBrickのようなもの)
    という風になっています。

    SBCL処理系は、ライブラリをロードした状態の処理系のメモリイメージを実行可能ファイルとしてダンプできるのですが、適当に手元のノートPCでAllegroServe(CLのウェブサーバー)をロードした状態でダンプしたものを、さくらサーバーに置いたところ動いてしまったので、そのまま動かすことにしました。(x86の実行ファイルです)

    場当たり的に作っていく中で色々な問題に遭遇しました。

    • AllegroServeだとサーバーの処理系を大文字と小文字を区別するように設定することが前提になっているのでそうしないと色々困る。
    • AllegroServeをAllegro CL上で動かさない場合、日本語の扱いに難がある
    等々、割と根本的なところに問題があったりします。
    HUNCHENTOOT というサーバーもちょっと試てみたのですが、上記のような問題はないので、こちらに乗り換えたいところです

    ]]>
    Thu, 08 Oct 2009 17:00:50 +0900
    Emacsでスクラッチファイルを日付順にして管理するライフハック http://tech.actindi.net/3462883892 chibaです。

    自分は特にプログラムを書くのが趣味という訳でもないので、プログラムプレゼンテーションは割と苦手なのですが、今回は、過去に作った便利Emacs Lispをプレゼンして場をしのぎました。

    アイデアとしては、ファイルを

    file-2009-09-26.txt
    のように命名規則を設けて作成するようにし(これもElispで生成するようにする)、その規則を元に前の日のファイルを開いたり、次の日のファイルを編集したりするのをスムースにする、というものです。
    gist: 13417 - GitHub
    この例では、前のファイルに移動するキーとしてsuper+p次のファイルがsuper+nという風に割り当てみています。
    単純なアイデアの割には便利ですので、お使いの環境でもっと洗練/発展させてみて下さい

    ]]>
    Sat, 26 Sep 2009 01:11:32 +0900
    AquesTalk Rubyバインディング http://tech.actindi.net/3462879600

    komagataです。

    “プログラムプレゼンテーション”でAquesTalkのRubyバインディングを作りました。(Windowsのみ)

    win32-aques_talk - AquesTalk rubyバインディング - p0t

    AquesTalkのrubyバインディング作りました。

    komagata’s win32-aques_talk at master – GitHub

    AquesTalkはwindows版dllのみが組み込んで配布することもOKとなっているのでwindows版をRubyから手軽に使いたいと思って作りました。RubyバインディングといってもC言語拡張ではなく、ruby-ffi(Foreign Function Interface)を使っています。

    豊富なCのライブラリをRubyからサッと使いたいと思ってruby-ffiを使ってみました。ヘッダが必要で無く、動的ライブラリを直接実行するのが面白かったです。また、Windows上で、opensshやgitがいつも通り使えるのがちょっと意外でした。(rubyのgitバインディングはうまく動かないけど)

    ]]>
    Sat, 26 Sep 2009 00:00:00 +0900
    継続インテグレーションコマンド http://tech.actindi.net/3462861600

    komagataです。

    “プログラムプレゼンテーション”で継続的インテグレーションコマンドを作って発表しました。

    saimaa - 今すぐ始められる継続的インテグレーション - p0t

    継続的インテグレーションについては、CIサーバー(Continuous Integration Server)というやつが沢山あって非常に機能も豊富です。僕の仕事には少々大げさな気がしたのと、

    「cronでsvn up && rakeじゃ駄目なのかしら?」

    などと思ったのでそれをちょっとだけサポートするコマンドを作ってみました。

    komagata’s saimaa at master – GitHub

    アクトインディではcapistranoのデプロイコマンドにrspecとcucumberのフックが掛けてあるのでテストが通らなければデプロイはできません。ですが、コミットはできるのでテスト通らないコードがコミットされるとすぐにこの仕組みでメールが飛んでくるのでなかなか便利です。

    これを作って感じたのは、rubygemsとgithubはクロスプラットフォームのCUIプログラム(コマンド)を作る環境として素晴らしいなということです。(全開と似たようなこと言ってますが)

    rubygemsはインストールするとPATHが通ってるところに実行できる場所にコマンドをコピーしてくれるんですよね。jewelerでgithubへのアップも簡単です。

    ]]>
    Fri, 25 Sep 2009 19:00:00 +0900
    Talkedbun - 日本語テキストトゥースピーチサーバー http://tech.actindi.net/3462793200 komagataです。

    アクトインディでは週一回、エンジニアが持ち回りで、「動いて、ダウロードできるプログラム」を公開・発表するという“プログラムプレゼンテーション”(まあ単なるプレゼンです)をやることにしました。

    第一回はShu MASUDAさんでしたのでそちらはお任せするとして、僕は2回目にやりました。

    Talkedbun - 日本語テキストトゥースピーチサーバー - p0t

    URLにひらがなを指定すると、そのひらがなの音声がmp3で得られるwebサーバーを作りました。

    komagata’s talkedbun at master – GitHub

    日本語のURLからそのまま音声が取れたら面白いかなと思って作りました。作っていて一番勉強になったのは、RubyはRubygems, Rack, Sinatraなど、クロスプラットフォームでのマイクロウェイブアプリケーションを作る環境が素晴らしく整っているなということでした。RailsがWebrickをローカルに立ち上げて開発するというスタイルを作ったので自然とWebサーバーの実装、WAFの実装、周辺ツールなどの選択肢がたくさんあります。

    ついでにhaml, sassも使ってみましたが、HTMLのインデントやCSSの重複した記述が病的に気になる僕にはぴったりのアホなツールでとても気に入りました。

    (ジェバンニマチダさんが30分でやってくれました)

    ]]>
    Fri, 25 Sep 2009 00:00:00 +0900
    RSSは動いているか http://tech.actindi.net/3459056185 このエントリーがRSSリーダーに捕捉されれば、とりあえず良いのですが、されてない気がします… ]]> Wed, 12 Aug 2009 17:56:25 +0900 こわれたRSSを付けました http://tech.actindi.net/3459054071 どこかが壊れているようですが、Google Readerや、LDRではがんばって表示してくれるようです。 しかし、それも動きがちょっと変なようです。 ]]> Wed, 12 Aug 2009 17:21:11 +0900 社長にお披露目 http://tech.actindi.net/3458970860 公開できると良いですね!! ]]> Tue, 11 Aug 2009 11:31:03 +0900 このブログの更新はSLIMEでしている! http://tech.actindi.net/3458946663 SLIME使ってる人には非常に優しいブログですね
    具体的には、このサーバーが動いているサーバーのSwankの4005番ポートをローカルにポートフォワードして、EmacsからSlimeで接続し、エントリーの関数を定義しています。簡単ですね! ]]>
    Tue, 11 Aug 2009 11:31:03 +0900
    見た目だけはなんとか完成 http://tech.actindi.net/3458828432 デザインされたhtmlをlmlに直したりしているのですが、これが割と大変です。
    lmlとは、htmlをS式で表現したものなのですが、簡潔でS式の編集環境が整ってさえいれば素のhtmlより簡単に編集できます。
    とはいえ、その編集環境を整えるのが面倒なのですが…。 ]]>
    Mon, 10 Aug 2009 02:40:32 +0900
    急激に重くなった様子 http://tech.actindi.net/3458566436 Fri, 07 Aug 2009 01:53:56 +0900 URLを毎度決めている http://tech.actindi.net/3458279537 (get-universal-time) が使えることに気付きました。
    SLIME上で(get-universal-time)を評価してURLにすると良いかもと。 (get-universal-time)はUNIXタイムのように1970年からではなく、1900年からの秒数になります。 ]]>
    Mon, 03 Aug 2009 18:12:17 +0900
    CSSはウェブページの命 http://tech.actindi.net/3458279064 Mon, 03 Aug 2009 18:04:24 +0900 エントリーを後でどういう風に修正したら良いか http://tech.actindi.net/3457825200 エントリーを後でどういう風に修正したら良いか
    めんどくさそうです。

    ]]>
    Wed, 29 Jul 2009 12:00:00 +0900
    Hunchentootにしたい http://tech.actindi.net/3457821600 色々面倒臭そうなのでHunchentootにしたくなってきました。 とはいえ、Hunchentootも使ったことがないのでなんとも言えません。

    ]]>
    Wed, 29 Jul 2009 11:00:00 +0900
    テストエントリー http://tech.actindi.net/3457818000 SBCLだと日本語が通らないので、無理矢理にマクロを通したり、文字列をバイト列に変換したり涙ぐましいのですが、もっと簡単な方法はないんでしょうか。
    根本的に直さないと駄目な気がしてきました。 AllegroServeより良いのってどういうのがあるんでしょう。

    ]]>
    Wed, 29 Jul 2009 10:00:00 +0900
    掃除は大事 http://tech.actindi.net/3448278000 稼働中のPCを触ってみたところかなり高温になっているという報告を受けたので、4月から新しい仲間になったmasuda氏が機転を効かせてPC内部を掃除したところ、ばっちりPCの温度が下がり、調子も良くなりました。
    どうも熱暴走でPCが落ちてしまっていたようです。
    基本ですが掃除は大事だなとあらためて思った一件です。 ]]>
    Fri, 10 Apr 2009 00:00:00 +0900
    こんにちは、こんにちは http://tech.actindi.net/3445570800 どうぞよろしくお願いします!! ]]> Mon, 09 Mar 2009 16:00:00 +0900 非常に重要なアプリケーションの導入 http://tech.actindi.net/3445513200 先週末からchiba2009さんがエンジニアとして入ってくれました。
    chibaさんは一番得意な言語がCommon Lispという素敵な方です。
    ぜひ社内のシステムのそこここにCommon Lispを忍ばせてほしいです。
    そのchibaさんに今日、とても重要なアプリケーション教えてもらいました。
    それはvrmsです。
      % apt-cache search vrms
    vrms - virtual Richard M. Stallman
    
    早速インストールして実行してみました。
      % vrms
                    Non-free packages installed on dev
    
    gdb-doc                   The GNU Debugger Documentation
    
      1 non-free packages, 0.2% of 503 installed packages.
    
    まずい!
    というかなんでgdbのドキュメントがnon-freeなんでしょうか。
      % sudo apt-get remove --purge gdb-doc
    % vrms
    No non-free packages installed on dev!  rms would be proud.
    
    これで安心。rmsもお喜びのようです。 ]]>
    Mon, 09 Mar 2009 00:00:00 +0900
    sakuraba引退記念 http://tech.actindi.net/3445167600 最初から予定されていたことですが、2月末で、中米の荒くれ者ことsakurabaがアルバイトを完了しました。
    沖縄料理屋で送別会をやって、プレゼントを贈りました。
    sakurabaはMac信者なのでMighty Mouseでも送ればちょっとうれしいのは目に見えていたので、一人おでんセットをプレゼントしました。(しかもMighty Mouseより無意味に高い)
    sakurabaは僕とmachidaさんに向かってとびっきりの呪いの言葉を吐きました。
    sakurabaはアルバイトできてから、RailsもLinuxのサーバー構築も自分でどんどん覚えてしまって、一人でできるようになってしまいました。
    いまでは僕が、「もっとテスト書いたほうがいいですよ」と怒られる始末。
    ボリビアにでも旅立ってしまうのかもしれませんが、これからのsakurabaの活躍を陰ながら応援しています。 ]]>
    Thu, 05 Mar 2009 00:00:00 +0900
    ベンチャーでのおすすめアンチウィルスソフト http://tech.actindi.net/3444519600 以前、はじめてベンチャーのシステム管理を担当したときは、張り切っていて、サーバー集中管理型のアンチウィルスソフトの見積もりを取ったりしていたんですが、今回は、「フリーでいいの無いかな?」という、ゆるふわ系です。
    人数が10人程度なのでディレクトリサービスとか、そこまでやらなくてもいいかなと思っています。(以前は10人未満の会社でActive Directoryを使ってましたが、もう設定とか思い出せません)個人ではアンチウィルスソフトは AVG を使っていて、非常に気に入っていたんですが、商用利用は有料なのでGPLの ClamWin を試してみました。
    日本語化パッチも公開されていて、定義ファイルのダウンロードやスキャンのスケジュール設定も簡単にでき、予想以上に「使える!」といった感じでした。
    会社でも導入を進めて行きたいと思います。 ]]>
    Wed, 25 Feb 2009 12:00:00 +0900
    オフィスの引越し(プロバイダー編) http://tech.actindi.net/3444476400 五反田から五反田へオフィス引越しました。
    システム管理者にとっては何かと大変なオフィスの引越しですが、僕は担当することになったばかりなので全体を把握する丁度良い機会になりました。
    予告通り、プロバイダーはインターリンクの固定IP8個にしました。
    社内にクリティカルなサーバは無いんですが、IPも振り直しです。
    /etc/network/intarfaces を変更して安心してたら、Apacheの443番ポートのバーチャルホストの設定のところに固定IPを書いていたのを忘れてました・・・。
    それと、インターリンクはOP25Bしていることを忘れていて、
    (25番で大丈夫でした。)
    「そういやRedmineのチケット関連のメールが来てないな・・・」
    などと思っていました。
    慌ててPostfixをSubmissionポートを使う設定に変えました。
    会社で25番を絶対使いたい場合は別のプロバイダをお考えください。
    参照: Postfix – Submissionポートで通信 – p0t ]]>
    Wed, 25 Feb 2009 00:00:00 +0900
    1人体制での死活監視 http://tech.actindi.net/3444217200 一定規模以上のWebサイトを運営しているエンジニアの方、業務時間外の障害対応ってどういう風にやっていますか? ルールとか体制とかを中心に教えてほしいです。 ちなみに.. – 人力検索はてな
    ちなみにぼくの会社では、監視ツールや自作監視スクリプトでアラートをエンジニア社員全員に送って、誰かが対応することになっています。(たまに誰も対応やレスをしなくて上司に怒られます) これはぼくら社員にとって正直ストレスになるので、なにかよいルールや体制を上司に提案したいなと考えています。
    はてなでこういう質問がありました。たしかに大きいところではストレスになりますよね。 うちは「一定規模以上のWebサイトを運営してい」ないので特にストレスは感じないです。(アラート受ける人も2人しかいないし・・・)
    Montasticという無料でWebのステータスをチェックしてアラートを送ってくれるサービスを使っています。
    これだとHTTPしかチェックしてくれないのでライブドアのDATAHOTEL PATROLというやつも試してみたいところです。
    それとRailsのExceptionNotifierプラグインのみです。
    社内に監視システムを構築するとその監視システム自体の維持が大変なのでやってません。
    品質とのトレードオフだと思いますが、基本的に、
    「人員1人体制想定でどこまで品質を高められるか」
    という方向でがんばってみたいと思います。 ]]>
    Sun, 22 Feb 2009 00:00:00 +0900
    迫る引越し http://tech.actindi.net/3444174000 何で今急いでブログを作ったかというと、会社が明日引越しだからです。
    明日かよ!とお思いかもしれませんが、時は無常にも過ぎ去り、明日です。
    まずは、引越し先に電話回線(FAX)・Bフレッツ回線・プロバイダを用意しました。
    お客様のサービスのようなクリティカルなものは社内に無いので、自社サービスがひとつ乗っかっているサーバー1台だけを先に人力(チャリと人手)で運んで繋いできました。(昨日)
    それ以外は止めても大丈夫なので荷造りして引越し屋さんにまかせます。
    自分のブログで ITベンチャー勝ち組セット などというエントリーを書きましたが、その通りの INTERLINKの固定IP8個のやつ を契約しました。
    カードがあればその場で使えるようになるのは助かりますね。
    引越し先はBフレッツのマンションタイプが元々あったのでVDSLモデムが届きました。
    無線LANルータは COREGA CG-WLBARGPXW を買いました。
    おいおい、こんなので大丈夫か?と思うかもしれませんが、このルーター使ったことあるので大丈夫なんじゃないかなと楽観的に考えています。
    固定IPを使うにはルータにUnnumbered IPという機能が必須だそうで、買うときに気をつけたいポイントです。
    使ったことあるルータなので、特に問題無く、無線LANと固定IPでサーバ一個(Debian etch)設定できました。
    /etc/network/interfaces を新しいIPに変えて、DNSを変更しただけです。
    無線LANはWPA2, AESでパスワードかけましたが、アクセスポイント自体を隠す設定にするかどうかちょっと悩んで隠さないことにしました。(エンジニアでない人はクライアントの設定で混乱するかと思いまして・・・) これはどっちがいいでしょうか。みなさんどうしてますか?
    引越し後の通常社員初出社は明後日で、引越し屋さんが運び込むのは明日です。
    明日中に全クライアント向けの配線や設定を済ませてこようと思います。 ]]>
    Sat, 21 Feb 2009 12:00:00 +0900
    ブログはじめました http://tech.actindi.net/3444130800 先日、アクトインディ株式会社のシステムの担当になったのでこのブログを作ってみました。
    小さくてくだらない作業までこのブログに書いていこうと思うので、「ベンチャーのシステム担当あるある」
    みたいな感じで見ていただければ・・・なとと考えています。
    現状、僕とアルバイトのsakurabaの二人でネットワークと開発(要するにパソコン関係全部)を担当しています。
    僕自身、ネットワークの知識がイマイチなところもあり、「そこはこうすべきだろう、常識的に考えて・・・」
    などというところがあれば教えていただきたいな、という面もあります。
    なにはともあれ、よろしくお願いします。 ]]>
    Sat, 21 Feb 2009 00:00:00 +0900