ホーム > アーカイブ > 投稿者のアーカイブ

投稿者のアーカイブ

JRuby から Datomic を使う

Clojure の作者 Rich Hickey が作ったデータベースサービス Datomic がおもしろそうなので、JRuby から使ってみました。

といっても、jar を JRuby で読んで debugger 起動してるだけですが。

Datomic って?

こちらの紹介記事が分かりやすいです。

大きな特徴は下記の 2 つ。

  • クエリの処理とキャッシュをクライアント側 (Peer) で行うことにより、スケールしやすい
  • データ (fact) を削除・更新しても過去のデータが残り、さらに任意の時点のデータベースにクエリを投げられる

かなり魅力的ですよね。

JRuby から使う

現在のところ Datomic のピアライブラリは JVM 用しかない (たぶんしばらくこのまま) ので、rubyist としては JRuby から使いたい。

ここでは Datomic Shell とほぼ同様の挙動を JRuby で実現します。

まず、JRuby の準備。rvm / rbenv 使ってるなら簡単。

rvm install jruby rvm jruby
gem install ruby-debug

ピアライブラリのダウンロード、展開。

# datomic.com の "Get Datomic" から datomic-0.1.2753.zip をダウンロード unzip datomic-0.1.2753 cd datomic-0.1.2753

このディレクトリに下記の内容で datomic.rb をつくる。

require "java" # datomic ピアライブラリの jar をクラスパスに追加 require "./datomic-0.1.2753.jar" # 依存ライブラリの jar をクラスパスに追加 Dir.glob("./lib/*.jar") do |jar| require jar end require "rubygems" require "ruby-debug" Debugger.settings[:autoeval] = true include_class "datomic.Entity" include_class "datomic.Connection" include_class "datomic.Database" include_class "datomic.Peer" include_class "datomic.TxReport" include_class "datomic.Util" include_class "java.io.FileReader" # デフォルトでは inspect が <#…> みたいなそっけないものなので # Java オブジェクトでは to_s (toString) を使う Java::JavaLang::Object.class_eval do def inspect; to_s; end end debugger puts "" # debugger 直後に終了しないように

あとは –debug オプションつきで起動する。

ruby --debug datomic.rb

これで、Getting StartedTutorial を試してみましょう。

実際に使うとなると、クエリや結果のクラスを拡張すると使いやすそうですね。

GitHub のネコ耳タコ足の生物 (Octocat) について

この子について調べた。

名前は Octocat

https://github.com/about をみると、上記の画像のキャプションに「Octocat」とある。明らかに Octopus + Cat ですね。

原案は映像作家の David O’reilly

site:en.wikipedia.org octcat で検索すると、David O’Reilly という人物の記事にヒットし、ここに Octocat Adventure という項がある。要訳すると・・・

  • 2008年3月13日に YouTube にシカゴにすむ 9 才の少年から OCTOCAT ADVENTURE 1 という、「ペイント」で描かれたアニメーションが投稿される。
  • その後、続編も投稿され、9月7日に最後のエピソードが公開される。
  • 最後のエピソードは開始 20 秒で突如 3DCG に変わりやたら高いクオリティに。
  • David O’reilly 氏が自らのサイトで、すべて自分の作であると明かす。

とのこと。

ちなみに最後のエピソードで流れる、日本語の歌は森田童子 (「ぼくたちの失敗」で有名) の「哀悼夜曲」という曲。なんで?

GitHub で使用しているイラストは iStockPhoto から

実際に、GitHub で使用している Octocat のイラストについては、Quora で GitHub の PJ Hyett 氏が回答している。こちらも要訳。

  • GitHub の Tom Preston-Werner 氏が 404 ページ用のおもしろい画像を探してた。
  • iStockphoto で Octocat のイラストを発見し、$50 くらいで購入。
  • その後、排他的使用権を取得。
  • Git は octopus merge が使え (man git-merge)、Tom は猫好きだが、これがどれだけこの画像の選択に影響を及ぼしていたかは本人にきいてみないとわからん。

とのこと。へー。

Rails, RSpec, Spork(, Guard) で適切にクラスをリロード

Rails アプリケーションの開発時、spork と guard を使うと非常に効率がいいです。

この記事では spork 使用時にクラスを適切にリロードするための方法を紹介します (guard 関係ないけど、快適にテストできるとこまでのメモとして書いておきます)。spork と guard については、ググるか README みてください。

なお、ここではこの方法を確立した時点での最新リリースだった Rails 3.0.7 を想定してます。Rails 3.2 ではクラスリロードの方法が変わっているらしいのでそのままでは動かないかも。

spork / guard 使えるとこまで

ここはさらっと。

$ rails new blog --skip-test-unit $ cd blog # Gemfile group :development, :test do gem "rspec-rails" gem "spork" gem "guard-rspec" gem "guard-spork" # gem "growl" # spork で spec の実行完了時に growl で通知してくれる。好みで。 end $ bundle install $ rails g rspec:install $ spork --bootstrap # spec/spec_helper.rb # ENV["RAILS_ENV"] ||= 'test' 以下のコードを Spork.prefork do … end のブロック内に移動 $ guard init spork $ guard init rspec # Guardfile # spork で実行するよう :cli => "--drb" 追加 guard 'rspec', :version => 2, :cli => "--drb do

これで準備完了。

$ guard

で guard が起動するので、spec 下に適当な spec を書き、自動的に実行されることを確認する。

クラスのリロード

上記の手順を終えた状態では、クラスを書き換えても変更が反映されない。

クラスをリロードさせる方法は検索するといくつか見つかるが、うまくリロードできないケースがあったり、複数回クラスを load して、コールバック (before 何とかみたいなの) が重複して定義されるケースがあった。

いろいろ試した結果次の方法がよさそう。

# config/environment/test.rb Blog::Application.configure do # Spork 使用時はクラスをキャッシュしない # これは development のデフォルト設定と同じ if defined?(Spork) && Spork.using_spork? config.cache_classes = false else config.cache_classes = true end end # spec/spec_helper.rb Spork.each_run do if Spork.using_spork? # これがないと Spork 非使用時に失敗する # routes のリロード Blog::Application.reload_routes! # railties-3.0.7/lib/rails/application/bootstrap.rb よりコピペ # もともとは config.cache_classes が true のとき、リクエストごとに呼ばれる部分 # ここでは spec が実行されるごとに呼んでいる ActiveSupport::DescendantsTracker.clear ActiveSupport::Dependencies.clear # オブザーバが動いてないので、有効にする ActiveRecord::Base.instantiate_observers # machinist gem を利用してる場合、blueprints を再度読み直す # load "#{File.dirname(__FILE__)}/support/blueprints.rb" end end

基本的には development 環境でリクエストごとにクラスリロードしてるのと同じ方法なので、まともに動いてるようです。ただ、この方法だと controller のテストをする際にリクエストごとにクラスリロードしてしまって、遅くなるかも (未確認です)。

なお、上記の方法が本当に問題ないか不明なので、デプロイ前には spork も guard も使わない状態で全部テストすることをおすすめします。

おまけ

実際の開発時には Guardfile も一部オプションを変えてるので、一応紹介。

# Guardfile # 起動に時間がかかるとあきらめちゃうことがあるので 30 秒までは待つよう wait: 30 追加 guard 'spork', rspec_env: { 'RAILS_ENV' => 'test' }, wait: 30 do … # 上でも書いた cli: "--drb" のほか... # all_on_start: false - 起動時の spec 全部実行を無効に。時間かかるので。回帰テストは Jenkins さんにまかせます。 # all_after_pass: false - 実行した spec が全部パスした時の spec 全部実行を無効に。これも時間かかるので。 guard 'rspec', all_on_start: false, all_after_pass: false, version: 2, cli: "--drb" do …

それではみなさま良き Rails ライフを。

新年のごあいさつ (おそい)

  • 投稿者: labocho
  • 2012年1月26日 9:51 PM
  • 未分類

もう来週は 2 月ですが、あけましておめでとうございます。

昨年は転職したのが一番おおきなイベントでした。人並みに働くのは体力的にしんどいですが、まあ、好きなことを仕事にできてるので、幸せなほうでしょう。

さて、昨年に掲げた目標をみてみましょう。

  • Web サービス作る
    夏くらいには 8 割方できてたんだけどほったらかし・・・。仕事がプログラミングだと、個人的なプログラミングはなかなか進まない。
  • 身体を動かす趣味をつくる
  • なにか習い事始める
    この 2 つについては、4 月からフェンシングを始めたので、目標達成。と思ってたんだけど、ここのところ全然行けてないので、今後はどうだろ。

ということで、いまいちな感じ。

では、今年の目標。

  • Web サービスつくる
  • もう少し文章書く
  • 無理しない

今年もよろしくお願いします。

 

Rails に XML をボディとするリクエストを JavaScript で送る

Rails における XML でのリクエスト

Rails に、Content-Type: application/xml で、ボディが XML のリクエストを送ると、コントローラ中では params に展開される。

# リクエスト # ヘッダはいろいろ省略してます POST /entries HTTP/1.1 Content-Type: application/xml <?xml version="1.0" encoding="UTF-8"?> <entry> <body>New blog entry</body> </entry> # EntriesController def create p params # => {"entry" => {"body" => "New blog entry"}, ... ...

これは主に ActiveResource のための仕様だろうが、XML によるレコードのエクスポートとインポートを行う目的で、同じインターフェイスを HTML から使いたいと考えた。

JavaScript によるリクエスト

HTML の form で Content-Type を application/xml にすることはできない (よね?) ので、jQuery を使って JavaScript で送る。

// url に URL 文字列、 // xml に XML 文字列が格納されているものとする。 $.ajax({ type: "POST", url: url, dataType: "xml", // Accept ヘッダをセットする。レスポンスを XML で受けとるなら必要。なくてもよい。 contentType: "application/xml", // Content-Type を XML にする data: xml, success: function(res, type) { alert(res); }, error: function(req, message, error){ alert(error); }, });

しかし、HTTP メソッドが GET 以外の場合、リクエストに含まれる authenticity_token をチェックし、無いか session[:authenticity_token] と一致しないと、session が空になってしまう (※)。

これは具合が悪いので authenticity_token を送信する方法を考える。

※ ApplicationController などで protect_from_forgery メソッドが呼ばれている場合。普通呼ばれてます。

CSRF プロテクショントークンを送る

form_for で作ったフォームには authenticity_token が hidden フィールドで格納されているので、そのまま submit すればよい。また、Ajax 通信でも、JSON で送るなら、送信するオブジェクトに authenticity_token プロパティを付与すればよい。この場合 authenticity_token は meta タグから取得する。

<!-- 最近の Rails (3 以降?) なら application.html.erb の head 要素にこんな記述があるはず --> <%= csrf_meta_tag %> <!-- これにより下記のような meta 要素が生成される --> <meta content="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" name="csrf-token"> // jQuery でこれを取得する var csrf_token = $("meta[name=csrf-token]").attr("content");

しかし、XML はルート要素が 1 つと決められているし、ルート要素は params の 1 要素に納められてしまうため、リクエストボディに authenticity_token を含めることはできない。

そこで、authenticity_token をチェックしているコードをみてみる。

# actionpack/lib/action_controller/metal/request_forgery_protection.rb def verified_request? !protect_against_forgery? || request.get? || form_authenticity_token == params[request_forgery_protection_token] || form_authenticity_token == request.headers['X-CSRF-Token'] end

どうやら X-CSRF-Token ヘッダにトークンを書いてもいいらしい。

jQuery.ajax は beforeSend オプションで、XMLHttpRequest オブジェクトを変更できるので、XMLHttpRequest.setRequestHeader() を使って X-CSRF-Token ヘッダを追加する。

var csrf_token = $("meta[name=csrf-token]").attr("content"); $.ajax({ type: "POST", url: url, dataType: "xml", // Accept contentType: "application/xml", beforeSend: function(xhr) { // X-CSRF-Token ヘッダのセット xhr.setRequestHeader("X-CSRF-Token", csrf_token) }, data: xml, success: function(res, type) { alert(res); }, error: function(req, message, error){ alert(error); }, });

これで OK。

Processing 環境の比較

このところ、花火シミュレートアプリ HANABICS (Chrome で見てね) というのを開発している (仕事じゃないよ)。

Processing というフレームワークで動かしてるんだけど、開発の過程でいろいろな環境を渡り歩いたので、それぞれの特徴についてまとめてみる。

続きを読む

RubyKaigi 2011 メモ (2 日目)

RubyKaigi 2011 のメモ、2 日目です。rubykaigi.org に録画があることに気づいたので、リンクをつけてます。

続きを読む

RubyKaigi 2011 メモ (1 日目)

7 月 16 日から 18 日まで開催された RubyKaigi 2011 に参加してきました。非常に楽しく、ためになる 3 日間でした。

セッションをきいている間、メモをとっていたので (多少整形して) 公開します。

理解できていない部分、誤って理解している部分、抜けている部分など多々あるので、備忘録としての役割が主です。これを読んで気になる部分があれば、他のレポート (RubyKaigi2011 スペシャルレポートとか) を読むなり、ust みるなり、登壇者が発信してる情報をさがすと良いと思います。

続きを読む

Mac の特殊キー記号の由来

Mac では、特殊キー (修飾キー) を記号で表現することがよくある。下記がその一覧。

記号キーコードポイントUnicode での文字名
commandU+2318PLACE OF INTEREST SIGN
controlU+2303UP ARROWHEAD
option / altU+2325OPTION KEY
shiftU+21E7UPWARDS WHITE ARROW
enterU+2324UP ARROWHEAD BETWEEN TWO HORIZONTAL BARS
escape / escU+238BBROKEN CIRCLE WITH NORTHWEST ARROW
homeU+2196NORTH WEST ARROW
endU+2198SOUTH EAST ARROW
returnU+21A9LEFTWARDS ARROW WITH HOOK
U+2191UPWARDS ARROW
U+2193DOWNWARDS ARROW
U+2190LEFTWARDS ARROW
U+2192RIGHTWARDS ARROW
deleteU+232BERASE TO THE LEFT
forward deleteU+2326ERASE TO THE RIGHT

command は使用頻度高いし、キーに印字してあるからすぐ覚えたんだけど、control や option は、印字してないし (MacBook Pro 2010-2011)、使用頻度同じくらいだしでよく間違える。

そこで、友達から、記号の意味がわかれば覚えるんじゃないか、といわれ、なるほどと思って調べてみた & 推測してみた。

資料はおもに日本語版および英語版の Wikipedia なので、悪しからず。

(command)

command キーを示す については、Wikipedia に詳しい記述がある

初代Mac開発メンバーであったスーザン・ケアが、北欧の史跡などを示す交通標識に使われる マークを記号辞典で見つけ、採用したといわれている。開発段階ではアップルマークが使われていたが、コマンドキー表示としてアップルマークが連なるメニューを見たスティーブ・ジョブズが自社ロゴを濫用していると感じ、別のマークにするよう指示した。

コマンドキー – Wikipedia

記号自体については Saint John’s Arms に詳しく、北欧で5-7世紀頃に使われていた記号だそうだ。Saint John’s Arms のほか Saint Hannes Cross などと呼ばれており (ただし、紀元前の木製スキーにも描かれているためキリスト教起源ではないとされる)、フィンランドでは、魔除けとして家の壁にペイントしたりするそうだ。

(control)

そもそも control キーは下記のような役割をもつ。

テレタイプ端末、及び初期のコンピューターキーボードでは、コントロールキーを押しながら他のキーを押すと、生成されるASCIIの下位5ビット以外がゼロとなった。これによりユーザーはASCIIの非表示文字である最初の32文字 (0×00 – 0x1f) を生成、入力できる。

コントロールキー – Wikipedia

たとえば、J (0x4A, 1001010b) を control とともに押下することで、改行 (0x0A, 0001010b) を得られる。制御文字 = Control character を入力するためのキーなので control キーというわけだ。

上記の例で、改行文字を ^J と書く記法があり (Caret notation, ASCII も参照)、この事で control を ^ で表すことになったらしい。そもそもなぜ ^ が使われたかはわからなかったが、この記法は Mac に限らない、一般的な記法らしい。

ただし、Mac では ASCII に含まれる ^ (U+005E, caret) のかわりに (U+2303, up arrowhead) で control キーを表している。

(option)

option キーを示す については、Wikipedia に記述がない。Google で調べてみたら、Quora にそのものずばりの質問があった。

Computer Keyboards: What is the origin of the Mac’s “option key” symbol ()? – Quora

その回答として、一番支持されてたものがこちら (抜粋)。

It was clearly inspired by the electrical symbol for an SPDT switch:

この回路図の左側から流れる電流を、スイッチによって、右上に流すか、左下に流すか選択できる。通常の動作を別のものに切り替えるという事で option や alternate (alt) を示すのだろう。

(shift)

まずはシフトキーの由来。

シフトキーの名称は、英文タイプライターが由来である。当初は刻印用の文字盤が水平に置かれて、下からの打鍵圧力により打刻される(アップストライク方式)構造だったが、その文字盤をシフトキーで「シフト(shift,ずらす)」という構造になっていた。

シフトキー – Wikipedia

shift は移す、替えるという意味で必ずしも上向きではない。上向きの矢印になったのは、下記の経緯によるのではないか。

のちにタイプライターは文字盤を手前側に置かれ、前からの打鍵圧力によって打刻される(フロントストライク方式)構造へと移り変わった。その文字盤は「ずらす」のではなく「リフト(lift,持ち上げる)」されるが、呼称は変わることなく「シフト」と呼ばれ続けた。

シフトキー – Wikipedia

(enter)

上の破線で部屋の入り口を、下の折れ線でその部屋に入る (enter) ことを示していると考えられる。

(escape)

○で示した領域から、逃げ出す (escape) 様を矢印で示していると考えられる。

(page down) / (page up)

省略を示す二本線をともなう矢印だろうか。

(home) / (end)

欧文の文書における、文の始め = 一番上の行の一番左、文の終わり = 一番下の行の一番右、を示していると考えられる。

(return) / ↑↓←→ / (delete) / (forward delete)

このあたりは明確ですよね。

ちなみに

上記の記号を使うときは、フォントは Lucida Grande にしとくといい感じですよ。

Picup を利用して Rails アプリに iPhone / iPad から画像をアップロードする

ご存じ iPhone / iPad のブラウザである Mobile Safari は、HTML5 の機能を多数実装してるわりに、<input type=”file” /> を使ったファイルのアップロードができない。

もちろん専用のネイティブアプリを作成すれば可能だけど、まあ、ほとんどの場合めんどくさいよね。

そこで、多少ユーザを選ぶけど、便利そうなのが William Lindmeier 氏制作の iOS アプリ Picup である。

ここでは、Picup の仕組みと、Rails アプリでの実装例を紹介する。

Picup の仕組み

iOS や MacOS (X?) では、URL スキームにアプリケーションを関連づけられる。Picup の場合 fileupload:// に続けて、アプリに渡したいパラメータをつけて Safari 等で開けば、Picup にパラメータが渡され起動する。

サーバ側では、Picup の Web サイトで配布しているスクリプト (picup.js) を利用して、<input type=”file” /> を、fileupload://… を開くボタンに書き換える (別にこのスクリプトを使わなくても fileupload://… へのリンクを自前で作ってもいい)。

このボタンがクリックされると、POST 先の URL (postURL)、フィールド名 (postImageParam) などのパラメータを渡して Picup が起動される。そして、Picup 上で、ユーザーが、カメラで撮影するか既存の写真を選択し、Done をタップすると、さきほど渡されたパラメータをもとに POST してくれる。

さらに、callbackURL を指定すると、POST 後に任意の URL を Safari で開くこともできる。その際に # 以降にいくつかパラメータが渡されるので、それを利用して、ユーザーを誘導することもできる。

Rails での作例

以下では、Ruby 1.9.2 + Rails 3.0.7 + carrierwave で Picup による写真のアップロードに対応した Rails アプリを作る。

とりあえず初期設定。

$ rails new picup_demo -d mysql -J # Gemfile - gem 'mysql2' + gem 'mysql2', '0.2.7' + gem 'carrierwave' + gem 'jquery-rails' $ bundle $ rails g jquery:install

jquery や後述の picup.js をロードするようにする。

# app/views/layouts/application.html.erb - <%= javascript_include_tag :defaults %> + <%= javascript_include_tag :all %>

写真のモデル・コントローラ・ビューを scaffold でつくる。

$ rails g scaffold photo file:string $ rake db:create $ rake db:migrate

アップローダをつくり、photos.file に設定する。

$ rails g uploader photo # app/models/photo.rb class Photo < ActiveRecord::Base + mount_uploader :file, PhotoUploader end

フォームのフィールドを、type=”file” にする。show で写真を表示する。

# app/views/photos/_form.html.erb - <%= form_for(@photo) do |f| %> + <%= form_for(@photo, html: {multipart: true}) do |f| %> - <%= f.text_field :file %> + <%= f.file_field :file %> # app/views/photos/show.html/erb - <%= @photo.file %> + <%= image_tag(@photo.file.url) %>

この時点で PC の Web ブラウザからアップロードできるか確認しておくとよい。

$ rails s # http://localhost:3000/photos/new へ Web ブラウザでアクセス

Picup のヘルパースクリプトを導入。http://picupapp.com/picup.js.zip をダウンロード、展開し、picup.js を public/javascripts 下に移動する。

type=”file” のフィールドを Picup を開くボタンに置き換える。

# app/views/photos/_form.html.erb <script type="text/javascript" charset="utf-8"> $(function(){ window.name = "Picup_demo_new_photo"; // アップロード後表示されるページから遷移するためにウィンドウ名をつけておく Picup.convertFileInput( "photo_file", // <input type="file" /> の ID { 'referrername': escape('Picup Demo'), // Picup に表示されるアプリケーション名 'purpose': escape('Upload A Photo'), //Picup に表示されるメッセージ 'postImageParam': 'photo_file', // フィールド名、この場合、rails では params[:photo_file] でアクセスできる。 'postURL': 'http://192.168.1.10:3000/photos.json', // post先 'callbackURL': 'http://192.168.1.10:3000/uploaded' // アップロード後に開く URL } ); }); </script> # app/controllers/photos_controller.rb def create - @photo = Photo.new(params[:photo]) + @photo = Photo.new(file: params[:photo_file])

IPアドレスは適当に書き換えて。 ここまででとりあえずアップロードはできる。 (アップロード後表示されるページは RoutingError になっちゃうけど、/photos を見ると、正しくアップロードできているのが確認できる)

アップロード後、アップロードされた写真のページへ遷移させたいので、create のレスポンスに、そのページの URL を含ませる。

# app/controllers/photos_controller.rb format.html { redirect_to(@photo, :notice => 'Photo was successfully created.') } format.xml { render :xml => @photo, :status => :created, :location => @photo } + format.json { + imgur_like_response = { + rsp: { + stat: "ok", + image: { + original_image: photo_url(@photo) + } + } + } + render :json => imgur_like_response + }

{rsp: …} となっているハッシュは、imgur に画像をアップロードした際のレスポンスを模したものである。いままで触れなかったが、Picup は postURL の指定がない場合、imgur.com に画像をアップロードする。その際、レスポンスに含まれる original_image の値は、アップロード後開かれる URL の # 以降に remoteImageURL=… の形で渡される (imgur.com からのレスポンスでは他にもいろいろな情報が付与されているが、無視されている)。

# public/uploaded.html <!DOCTYPE html> <html> <head> <title>Picup Demo</title> <script> <!-- var redirect = function() { var keys_values = window.location.hash.substring(1).split("&"); var params = {}; for(var i = 0; i < keys_values.length; i += 1){ var key_value = keys_values[i].split("="); params[key_value[0]] = key_value[1]; } if (params.remoteImageURL) { window.open(unescape(params.remoteImageURL), 'Picup_demo_new_photo'); window.close(); } }; redirect(); //--> </script> </head> <body> <h1>アップロード完了</h1> <a href="javascript:redirect();">自動的に移動しない場合はここをタップしてください。</a> </body> </html>

これが、アップロード後開かれるページである。URL の # 以降の remoteImageURL=… の値を読み出し、もともとフォームを表示していたタブ (Picup_demo_new_photo) で開き、このページ自身は閉じるようにしている。いちおうこれで、PC のブラウザからアップロードした際と似た挙動を実現できる。

なお、<input type=”file” /> の置き換えを、UA が Mobile Safari であることを確認した上で (Apple 公式の DetectingWebKit を使えば簡単) 行えば、PC のブラウザでも Mobile Safari でもほぼ同じように使える。

気になるところ

先述のとおり Picup.convertFileInput には postImageParam オプションで、送信されるファイルのフィールド名を指定できる。ここは、Rails の規約に従って photo[file] としたいところだが、実際に試してみると、Rails にはフィールド名が photo%5bfile%5d として渡されてしまい、params[:photo][:file] のようなかたちではアクセスできない。無用なエスケープがされちゃってるんですね。ちょっと残念。

あと、POST のレスポンスをもうすこし利用できるとうれしい。imgur のレスポンスに特化してるのがもったいない。

ホーム > アーカイブ > 投稿者のアーカイブ

検索
フィード
メタ情報

ページの上部に戻る