[DRE-commits] [tdiary] 01/03: Imported Upstream version 4.1.2

Youhei SASAKI uwabami-guest at moszumanska.debian.org
Tue Aug 18 02:01:50 UTC 2015


This is an automated email from the git hooks/post-receive script.

uwabami-guest pushed a commit to branch master
in repository tdiary.

commit ddf4ad3b396e8d92dccc97b3c1295d48f07fb802
Author: Youhei SASAKI <uwabami at gfd-dennou.org>
Date:   Fri Jun 5 02:51:52 2015 +0900

    Imported Upstream version 4.1.2
---
 .travis.yml                                    |   2 +-
 ChangeLog                                      |  42 +++++++++
 Gemfile                                        |  13 +--
 Gemfile.lock                                   | 125 +++++++++++++------------
 README.md                                      |   6 +-
 doc/HOWTO-authenticate-in-rack.md              | 104 ++++++++++++++++++--
 doc/HOWTO-testing-tDiary.md                    |   2 +-
 doc/INSTALL-paas.md                            |  73 ++++-----------
 doc/README.en.md                               |   2 +-
 doc/README.md                                  |   2 +-
 js/comment_ajax.js                             |   2 +-
 lib/tdiary.rb                                  |   1 +
 lib/tdiary/application.rb                      |  95 ++++++++++++-------
 lib/tdiary/application/configuration.rb        |  14 +--
 lib/tdiary/application/extensions/omniauth.rb  |  22 -----
 lib/tdiary/cli.rb                              |  12 ++-
 lib/tdiary/core_ext.rb                         |   2 +-
 lib/tdiary/diary_container.rb                  |  55 +++++++++++
 lib/tdiary/environment.rb                      |   3 +
 lib/tdiary/plugin.rb                           |  15 ++-
 lib/tdiary/plugin/00default.rb                 |   7 +-
 lib/tdiary/plugin/05referer.rb                 |  16 ++--
 lib/tdiary/rack.rb                             |   7 +-
 lib/tdiary/rack/auth.rb                        |  20 ++++
 lib/tdiary/rack/auth/basic.rb                  |   2 +-
 lib/tdiary/rack/auth/omniauth.rb               | 124 +++++++++++++++---------
 lib/tdiary/rack/auth/omniauth/authorization.rb |  64 +++++++++++++
 lib/tdiary/rack/session.rb                     |  35 +++++++
 lib/tdiary/style.rb                            |   3 +-
 lib/tdiary/tasks/assets.rake                   |   2 +-
 lib/tdiary/tasks/release.rake                  |  25 +++--
 lib/tdiary/version.rb                          |   2 +-
 misc/paas/heroku/Gemfile                       |  20 ----
 misc/paas/heroku/Gemfile.local                 |   8 ++
 misc/paas/heroku/Gemfile.lock                  |  74 ---------------
 misc/paas/heroku/app.json                      |  19 ++++
 misc/paas/heroku/config.ru                     |   6 ++
 misc/paas/heroku/tasks/mongodb.rake            |  12 +++
 misc/paas/heroku/tdiary.conf                   |  28 +++---
 misc/plugin/amazon.rb                          |  10 +-
 misc/plugin/category.rb                        |  20 +---
 misc/plugin/category_autocomplete.rb           |   4 +-
 misc/plugin/comment_ajax.rb                    |   2 +
 misc/plugin/comment_emoji_autocomplete.rb      |   4 +-
 misc/plugin/comment_mail-smtp.rb               |  31 ++++--
 misc/plugin/makerss.rb                         |   6 +-
 misc/plugin/recent_comment3.rb                 |   6 +-
 misc/plugin/recent_list.rb                     |   6 +-
 misc/plugin/theme_online.rb                    |  10 +-
 spec/acceptance/save_conf_plugin_spec.rb       |   4 +-
 spec/core/application_spec.rb                  |  65 +++++++++++++
 spec/core/diary_container_spec.rb              |  71 ++++++++++++++
 spec/core/plugin_spec.rb                       |  13 +++
 spec/fixtures/tdiary.conf.gem                  |   4 +-
 spec/fixtures/tdiary.conf.rack                 |   4 +-
 spec/fixtures/tdiary.conf.secure               |   4 +-
 spec/fixtures/tdiary.conf.webrick              |   4 +-
 spec/spec_helper.rb                            |   9 +-
 58 files changed, 890 insertions(+), 453 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index b0aa377..53b61fb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,9 +5,9 @@ sudo: false
 services: memcache
 
 rvm:
-  - 1.9.3
   - 2.0.0
   - 2.1
+  - 2.2
   - ruby-head
 
 cache:
diff --git a/ChangeLog b/ChangeLog
index b97a21a..0cd1426 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,45 @@
+2015-03-15  MATSUOKA Kohei <kohei at machu.jp>
+    * use omniauth automatically if omniauth gem loaded
+    * support some auth providers (twitter, facebook, google, github)
+
+2015-02-25  MATSUOKA Kohei <kohei at machu.jp>
+	* support ruby-2.2 and unsupport ruby-1.9.3
+
+2015-02-19  TADA Tadashi <t at tdtds.jp>
+	* enable to specify multiple twitter user in OmniAuth
+
+2015-02-02  TADA Tadashi <t at tdtds.jp>
+	* Gemfile: work around about rack 1.6 not separate params with ';'. see #485
+
+2015-01-28  TADA Tadashi <t at tdtds.jp>
+	* use Rack::Session::Dalli automatically if dalli gem loaded
+
+2015-01-27  TADA Tadashi <t at tdtds.jp>
+	* plugin/00default.rb: fix #482 by another code: bad url of og:image
+
+2015-01-26  TADA Tadashi <t at tdtds.jp>
+	* accept external JavaScript or CSS URL without scheme
+	* plugin/theme_online.rb: support another theme site by options
+
+2015-01-24  TADA Tadashi <t at tdtds.jp>
+	* plugin/comment_mail-smtp.rb: use Mail gem instead of Net::SMTP
+	* plugin/comment_ajax.rb: set theme_url into js
+
+2015-01-21  MATSUOKA Kohei <kohei at machu.jp>
+	* add add_startup_proc plugin interface
+	* plugin/makerss.rb: create rdf on startup
+
+2015-01-19  TADA Tadashi <t at tdtds.jp>
+	* plugin/amazon.rb: retry by returning error from rpaproxy
+
+2015-01-10  MATSUOKA Kohei <kohei at machu.jp>
+	* diary_container.rb: add the model to get diary directoly without using CGI
+	* Gemfile: use webrick server as default (to use other server, write in Gemfile.local)
+	* cli.rb: add --log option to tdiary server command
+
+2014-12-29  MATSUOKA Kohei <kohei at machu.jp>
+	* release 4.1.1
+
 2014-12-27  MATSUOKA Kohei <kohei at machu.jp>
 	* lib/tdiary/application.rb: fix #442: call extensions setup before the core setup
 	* lib/tdiary/application/extensions/omniauth.rb: fix error with base_dir 
diff --git a/Gemfile b/Gemfile
index 85a9104..5e71cb9 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,26 +1,17 @@
 source 'https://rubygems.org'
 
-gem 'rack'
+gem 'rack', '~> 1.5.0'
 gem 'sprockets'
 gem 'hikidoc'
 gem 'fastimage'
 gem 'gemoji'
+gem 'mail'
 
 group :coffee do
   gem 'coffee-script'
   gem 'therubyracer'
 end
 
-group :server do
-  platforms :mri do
-    gem 'thin'
-  end
-
-  platforms :jruby do
-    gem 'trinidad'
-  end
-end
-
 group :development do
   gem 'pit', require: false
   gem 'racksh', require: false
diff --git a/Gemfile.lock b/Gemfile.lock
index 2268513..ef7824c 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,11 +1,9 @@
 GEM
   remote: https://rubygems.org/
   specs:
-    addressable (2.3.6)
-    byebug (3.5.1)
-      columnize (~> 0.8)
-      debugger-linecache (~> 1.2)
-      slop (~> 3.6)
+    addressable (2.3.8)
+    byebug (4.0.4)
+      columnize (= 0.9.0)
     capybara (2.4.4)
       mime-types (>= 1.16)
       nokogiri (>= 1.3.3)
@@ -18,53 +16,57 @@ GEM
     coffee-script (2.3.0)
       coffee-script-source
       execjs
-    coffee-script-source (1.8.0)
+    coffee-script-source (1.9.1)
     columnize (0.9.0)
-    coveralls (0.7.2)
-      multi_json (~> 1.3)
-      rest-client (= 1.6.7)
-      simplecov (>= 0.7)
-      term-ansicolor (= 1.2.2)
-      thor (= 0.18.1)
-    daemons (1.1.9)
-    debugger-linecache (1.2.0)
+    coveralls (0.7.12)
+      multi_json (~> 1.10)
+      rest-client (>= 1.6.8, < 2)
+      simplecov (~> 0.9.1)
+      term-ansicolor (~> 1.3)
+      thor (~> 0.19.1)
     diff-lcs (1.2.5)
     docile (1.1.5)
-    eventmachine (1.0.4)
-    execjs (2.2.2)
-    fastimage (1.6.6)
+    domain_name (0.5.23)
+      unf (>= 0.0.5, < 1.0.0)
+    execjs (2.4.0)
+    fastimage (1.6.8)
       addressable (~> 2.3, >= 2.3.5)
-    ffi (1.9.6)
+    ffi (1.9.8)
     gemoji (2.1.0)
     hike (1.2.3)
     hikidoc (0.1.0)
-    jasmine (2.1.0)
-      jasmine-core (~> 2.1.0)
+    http-cookie (1.0.2)
+      domain_name (~> 0.5)
+    jasmine (2.2.0)
+      jasmine-core (~> 2.2)
       phantomjs
       rack (>= 1.2.1)
       rake
-    jasmine-core (2.1.3)
+    jasmine-core (2.2.0)
     launchy (2.4.3)
       addressable (~> 2.3)
     libv8 (3.16.14.7)
+    mail (2.6.3)
+      mime-types (>= 1.16, < 3)
     method_source (0.8.2)
     mime-types (2.4.3)
-    mini_portile (0.6.1)
-    multi_json (1.10.1)
-    nokogiri (1.6.5)
+    mini_portile (0.6.2)
+    multi_json (1.11.0)
+    netrc (0.10.3)
+    nokogiri (1.6.6.2)
       mini_portile (~> 0.6.0)
-    phantomjs (1.9.7.1)
+    phantomjs (1.9.8.0)
     pit (0.0.7)
-    power_assert (0.2.2)
+    power_assert (0.2.3)
     pry (0.10.1)
       coderay (~> 1.1.0)
       method_source (~> 0.8.1)
       slop (~> 3.4)
-    pry-byebug (2.0.0)
-      byebug (~> 3.4)
+    pry-byebug (3.1.0)
+      byebug (~> 4.0)
       pry (~> 0.10)
-    rack (1.6.0)
-    rack-test (0.6.2)
+    rack (1.5.2)
+    rack-test (0.6.3)
       rack (>= 1.0)
     racksh (1.0.0)
       rack (>= 1.0)
@@ -72,32 +74,35 @@ GEM
     rake (10.4.2)
     redcarpet (3.2.2)
     ref (1.0.5)
-    rest-client (1.6.7)
-      mime-types (>= 1.16)
-    rspec (3.1.0)
-      rspec-core (~> 3.1.0)
-      rspec-expectations (~> 3.1.0)
-      rspec-mocks (~> 3.1.0)
-    rspec-core (3.1.7)
-      rspec-support (~> 3.1.0)
-    rspec-expectations (3.1.2)
+    rest-client (1.8.0)
+      http-cookie (>= 1.0.2, < 2.0)
+      mime-types (>= 1.16, < 3.0)
+      netrc (~> 0.7)
+    rspec (3.2.0)
+      rspec-core (~> 3.2.0)
+      rspec-expectations (~> 3.2.0)
+      rspec-mocks (~> 3.2.0)
+    rspec-core (3.2.2)
+      rspec-support (~> 3.2.0)
+    rspec-expectations (3.2.0)
+      diff-lcs (>= 1.2.0, < 2.0)
+      rspec-support (~> 3.2.0)
+    rspec-mocks (3.2.1)
       diff-lcs (>= 1.2.0, < 2.0)
-      rspec-support (~> 3.1.0)
-    rspec-mocks (3.1.3)
-      rspec-support (~> 3.1.0)
-    rspec-support (3.1.2)
-    rubyzip (1.1.6)
-    selenium-webdriver (2.44.0)
+      rspec-support (~> 3.2.0)
+    rspec-support (3.2.2)
+    rubyzip (1.1.7)
+    selenium-webdriver (2.45.0)
       childprocess (~> 0.5)
       multi_json (~> 1.0)
       rubyzip (~> 1.0)
       websocket (~> 1.0)
-    sequel (4.17.0)
-    simplecov (0.9.1)
+    sequel (4.20.0)
+    simplecov (0.9.2)
       docile (~> 1.1.0)
       multi_json (~> 1.0)
-      simplecov-html (~> 0.8.0)
-    simplecov-html (0.8.0)
+      simplecov-html (~> 0.9.0)
+    simplecov-html (0.9.0)
     slop (3.6.0)
     sprockets (2.12.3)
       hike (~> 1.2)
@@ -105,20 +110,19 @@ GEM
       rack (~> 1.0)
       tilt (~> 1.1, != 1.3.0)
     sqlite3 (1.3.10)
-    term-ansicolor (1.2.2)
-      tins (~> 0.8)
-    test-unit (3.0.8)
+    term-ansicolor (1.3.0)
+      tins (~> 1.0)
+    test-unit (3.0.9)
       power_assert
     therubyracer (0.12.1)
       libv8 (~> 3.16.14.0)
       ref
-    thin (1.6.3)
-      daemons (~> 1.0, >= 1.0.9)
-      eventmachine (~> 1.0)
-      rack (~> 1.0)
-    thor (0.18.1)
+    thor (0.19.1)
     tilt (1.4.1)
-    tins (0.13.2)
+    tins (1.3.5)
+    unf (0.1.4)
+      unf_ext
+    unf_ext (0.0.6)
     websocket (1.2.1)
     xpath (2.0.0)
       nokogiri (~> 1.3)
@@ -135,9 +139,10 @@ DEPENDENCIES
   hikidoc
   jasmine
   launchy
+  mail
   pit
   pry-byebug
-  rack
+  rack (~> 1.5.0)
   racksh
   rake
   redcarpet
@@ -149,5 +154,3 @@ DEPENDENCIES
   sqlite3
   test-unit
   therubyracer
-  thin
-  trinidad
diff --git a/README.md b/README.md
index 658fc5f..256c2a6 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
 # tDiary
 
+[![Deploy](https://www.herokucdn.com/deploy/button.png)](https://www.heroku.com/deploy?template=https://github.com/tdiary/tdiary-core/tree/heroku)
+
 [![Gem Version](https://badge.fury.io/rb/tdiary.png)](https://rubygems.org/gems/tdiary) [![Build Status](https://secure.travis-ci.org/tdiary/tdiary-core.png)](https://travis-ci.org/tdiary/tdiary-core) [![Coverage Status](https://coveralls.io/repos/tdiary/tdiary-core/badge.png?branch=master)](https://coveralls.io/r/tdiary/tdiary-core) [![Dependency Status](https://gemnasium.com/tdiary/tdiary-core.png)](https://gemnasium.com/tdiary/tdiary-core) [![Code Climate](https://codeclimate.com/gith [...]
 
 ## tDiary, The TSUKKOMI-able Weblog.
@@ -18,7 +20,7 @@ tDiaryには以下のような特徴があります。
 
 ### レンタルサーバーユーザにやさしい
 
-必要なのはRuby(1.9.2ないしは2.0.0以降に対応)だけ。単独でCGIとして動作し、基本機能はデータベースや追加のライブラリを必要としません。
+必要なのはRuby(2.0.0以降に対応)だけ。単独でCGIとして動作し、基本機能はデータベースや追加のライブラリを必要としません。
 
 ### プラグインで拡張できます
 
@@ -30,4 +32,4 @@ tDiaryには以下のような特徴があります。
 
 ### その他
 
-インストールにはドキュメント(doc/INSTALL.html)を参照して下さい。動作にはruby(1.9.2以降または2.0.0以降)と、CGIをサポートするWebサーバが必要です。
+インストールにはドキュメント(doc/INSTALL.html)を参照して下さい。動作にはruby(2.0.0以降)と、CGIもしくはRackをサポートするWebサーバが必要です。
diff --git a/doc/HOWTO-authenticate-in-rack.md b/doc/HOWTO-authenticate-in-rack.md
index e083b07..f668156 100644
--- a/doc/HOWTO-authenticate-in-rack.md
+++ b/doc/HOWTO-authenticate-in-rack.md
@@ -39,24 +39,27 @@ htpasswd -cd .htpasswd username
 
 ### ライブラリを有効にする
 
-まず、利用する外部サービスに対応したライブラリを有効にします。Twitter認証では `omniauth-twitter` ライブラリを使用します。Gemfile.localにて以下の行が有効になっていることを確認してください。無ければ追加してください。
+利用する外部サービスに対応したライブラリを有効にします。Twitter認証では `omniauth-twitter` ライブラリを使用します。Gemfile.localにて以下の行が有効になっていることを確認してください。無ければ追加してください。
 
 ```
 gem 'omniauth'
 gem 'omniauth-twitter'
 ```
 
-次に設定ファイル `config.ru` を編集します。 ```run TDiary::Applicationn.new( base_dir )``` の前に以下の行を追加します。無ければ追加してください。
+### Twitter Appsへのアプリケーションの登録
 
-```
-require 'tdiary/application/extensions/omniauth'
-```
+Twitter 認証を使うためには、Twitter のサイトにてアプリケーションを登録する必要があります。[Twitter Apps](https://dev.twitter.com/apps/new)にアクセスし、以下の情報を入力して新しいアプリケーションを登録してください。
 
-### 鍵とパスワードの取得と環境変数への設定
+  - Name: アプリケーションの名前です。設置する日記のタイトルを設定すると分かりやすいでしょう。
+  - Description: アプリケーションの説明です。迷ったら「日記へログインするためのTwitter認証」などとすると良いでしょう。
+  - Website: アプリケーションのURLです。設置する日記のトップページを設定すると分かりやすいでしょう。
+  - Callback URL: 認証後に移動するURLです。Websiteと同じURLを設定してください。
 
-Twitter 認証を使うためには、Twitter認証を利用するための鍵 (Consumer key) とパスワード (Consumer secret) としてTWITTER_KEYとTWITTER_SECRETを環境変数として設定する必要があります。これらは[Twitterのサイト](https://dev.twitter.com/apps/new)から取得できます。
+Name, Description, Websiteに設定した値は、Twitterのアプリ連携画面(認証画面)に表示されます。また、Callback URLを空欄にするとTwitter認証が動作しなくなります。任意のURLで良いので設定してください。
 
-鍵とパスワードを取得したら環境変数に設定します。
+### 鍵とパスワードの取得と環境変数への設定
+
+Twitterのサイトから鍵とパスワードを取得したら、鍵 (Consumer key) とパスワード (Consumer secret) をそれぞれ環境変数として設定します。
 
 ```
 export TWITTER_KEY="your_consumer_key"
@@ -74,3 +77,88 @@ export TWITTER_NAME='your_twitter_screen_name'
 ```
 
 日記の編集画面にアクセスすると、Twitterのログイン画面が表示されるようになります。編集画面へは `your_twitter_screen_name` で指定したアカウントのみがアクセスできます。
+
+サポートしている外部サービス認証の一覧
+----
+
+### Twitter
+
+Gemfile.localの記述
+
+```
+gem 'omniauth'
+gem 'omniauth-twitter'
+```
+
+環境変数の設定
+
+```
+export TWITTER_KEY="your_consumer_key"        # Consumer Key (API Key)
+export TWITTER_SECRET="your_consumer_secret"  # Consumer Secret (API Secret)
+export TWITTER_NAME="your_screen_name"        # アクセスを許可するアカウント名
+```
+
+KeyとSecretは [Twitter Application Management](https://apps.twitter.com/) にて取得できます。
+
+### Facebook
+
+Gemfile.localの記述
+
+```
+gem 'omniauth'
+gem 'omniauth-facebook'
+```
+
+環境変数の設定
+
+```
+export FACEBOOK_KEY="your_app_id"               # App ID
+export FACEBOOK_SECRET="your_app_secret"        # App Secret
+export FACEBOOK_EMAIL="your_email at example.com"  # アクセスを許可するアカウントのメールアドレス
+```
+
+IDとSecretは [Facebook Developers](https://developers.facebook.com/) にて取得できます。
+設定画面にてWebsiteの「Site URL」と「Mobile Site URL」には、設置する日記のアドレスを指定してください。
+
+### Google
+
+Gemfile.localの記述
+
+```
+gem 'omniauth'
+gem 'omniauth-google-oauth2'
+```
+
+環境変数の設定
+
+```
+export GOOGLE_CLIENT_ID="your_client_id"          # クライアント ID
+export GOOGLE_CLIENT_SECRET="your_client_secret"  # クライアント シークレット	
+export GOOGLE_EMAIL="your_email at gmail.com"        # アクセスを許可するアカウントのメールアドレス
+```
+
+IDとシークレットは [Google Developers Console](https://code.google.com/apis/console/) にて取得できます。
+設定画面にて「リダイレクトURL」には、設定する日記のアドレスの末尾に `update.rb/auth/google_oauth2/callback` を加えたものを指定してください。
+日記のアドレスが `http://diary.example.com/` の場合、リダイレクトURLは `http://diary.example.com/update.rb/auth/google_oauth2/callback` となります。
+
+また、Google Developers Consoleの「APIと認証」にて、Google+ APIのステータスをonにしてください。
+
+### GitHub
+
+Gemfile.localの記述
+
+```
+gem 'omniauth'
+gem 'omniauth-github'
+```
+
+環境変数の設定
+
+```
+export GITHUB_KEY="your_client_id"          # Cliend ID
+export GITHUB_SECRET="your_client_secret"   # Cliend Secret
+export GITHUB_NAME="your_github_nickname"   # アクセスを許可するアカウント名
+```
+
+Cliend ID と Cliend Secret は、 [New OAuth Application](https://github.com/settings/applications/new) にて取得できます。
+設定画面にて「Authorization callback URL」には、設置する日記のアドレスを指定してください。
diff --git a/doc/HOWTO-testing-tDiary.md b/doc/HOWTO-testing-tDiary.md
index 668db0b..376b5f5 100644
--- a/doc/HOWTO-testing-tDiary.md
+++ b/doc/HOWTO-testing-tDiary.md
@@ -18,7 +18,7 @@ tDiary-3.0.1.20101011 以降のバージョンでは tDiary を test するた
 
 tDiary でテストを実行するためには以下の環境を用意する必要があります。
 
-  - Ruby 1.9.3 または Ruby 2.0.0
+  - Ruby 2.0.0 以降
   - Bundler 1.3.5 以降
 
 動かし方
diff --git a/doc/INSTALL-paas.md b/doc/INSTALL-paas.md
index 60f2915..e3a2172 100644
--- a/doc/INSTALL-paas.md
+++ b/doc/INSTALL-paas.md
@@ -6,74 +6,39 @@ Install to PaaS
 
 tDiary-3.1.3 以降のバージョンでは tDiary を [Heroku](http://www.heroku.com) や [sqale](http://sqale.jp) のような PasS で動かすことが可能です。PaaS を利用することで、3.1.3 以前のバージョンで必要とされていた Apache のような http サーバーの用意や CGI として動作させるための環境設定を行う事なく、 tDiary を動かして日記を書くことが可能となります。
 
-必要なもの
------
-
-tDiary を PaaS で動作させるためには以下のツールが必要となります。
-
-  - [git](http://git-scm.com)
-  - Ruby 1.9.2 以降
-  - RubyGems 1.3.7 以降
-  - Bundler 1.0.0 以降
-
-また、よくわからない場合は Heroku が配布している [heroku toolbelt](https://toolbelt.heroku.com) を用いると簡単に上記のツールをインストールすることができます。
-
 動かし方 - Heroku の場合
 ----
 
-tDiary の最新版を取得します。
-
-```
-git clone git://github.com/tdiary/tdiary-core.git
-```
-
-続いて、依存するライブラリをインストールするために bundle install コマンドを実行します。
+Webブラウザだけあれば動作させることが可能です。
 
-```
-% cd tdiary-core
-% bundle install
-```
+日記の更新時にTwitterのOAuthを使って認証するようになっています。あらかじめ[Twitter Application Management](https://apps.twitter.com/)にてアプリケーションを作成し、Consumer Key (API Key) と Consumer Secret (API Secret) を取得しておきます。
 
-heroku コマンドを用いて Heroku でアプリケーションを作成します。なお、Heroku のアカウント作成方法は本ドキュメントでは省略します。tDiary のルートディレクトリ(Gemfile が存在する箇所) で以下のコマンドを実行します。
+続いて GitHub 上にある[tDiaryのリポジトリ](https://github.com/tdiary/tdiary-core)から、Herokuボタンを使ってデプロイしてください(トップページ下部のREADMEにあります)。
 
-```
-% heroku apps:create [アプリケーション名]
-```
+Heroku の New App ページになったら、下記の情報を入力して、Deploy for Free ボタンを押します。
 
-アプリケーション名には mydiary など任意の名前を英数字で入力します。続いて、Heroku 専用の作業ブランチを作成します。
+* App Name (任意)
+* TWITTER_KEY: Twitter の Consumer Key (API Key)
+* TWITTER_SECRET: Twitter の Consumer Secret (API Secret)
+* TWITTER_NAME: 認証に使う Twitter のユーザ名
 
-```
-% git checkout -b deploy
-```
+「Deployed to Heroku」まで進めば利用可能です。「View it」のリンクから日記に飛んで下さい。
 
-作業ブランチで Heroku で動かすために必要な設定ファイルをコピーします。
+【注意】View itから飛んだ先のURLは https://~ になっています。いったん http://~ にしないと認証が通らないので注意してください。なお、設定画面で「日記のURL」を https://~ に変更することで https での利用が可能です。
 
-```
-% cp misc/paas/heroku/* .
-```
-
-続いて .gitignore の 2 行目の .htpasswd と 9 行目の tdiary.conf を削除します。
-
-日記更新時に必要となるユーザー名とパスワードを保存する .htpasswd ファイルを作成します。この情報は重要なので、外部には公開しないでください。
-
-```
-% bundle exec bin/tdiary htpasswd
-```
+動かし方 - sqale の場合
+----
 
-ここまでの変更内容を deploy ブランチにコミットし、Heroku にアプリケーションを転送します。
+tDiary を sqale で動作させるためには以下のツールが必要となります。
 
-```
-git add .
-git commit -m "deploy"
-git push heroku deploy:master
-```
-
-これで http://mydiary.herokuapp.com にアクセスして日記を書くことができます。
+  - [git](http://git-scm.com)
+  - Ruby 2.0.0 以降
+  - RubyGems 1.3.7 以降
+  - Bundler 1.0.0 以降
 
-動かし方 - sqale の場合
-----
+また、よくわからない場合は Heroku が配布している [heroku toolbelt](https://toolbelt.heroku.com) を用いると簡単に上記のツールをインストールすることができます。
 
-tDiary の最新版を取得します。
+git を使って tDiary の最新版を取得します。
 
 ```
 git clone git://github.com/tdiary/tdiary-core.git
diff --git a/doc/README.en.md b/doc/README.en.md
index 9296896..b316c69 100644
--- a/doc/README.en.md
+++ b/doc/README.en.md
@@ -36,7 +36,7 @@ You can choice a grammar of writing your diary by 'Style' feature. Some style fi
 
 ### Written in Ruby
 
-Important :-). tDiary requires Ruby-1.9.2 or later.
+Important :-). tDiary requires Ruby-2.0.0 or later.
 
 ### Others
 
diff --git a/doc/README.md b/doc/README.md
index e1ccbe4..6972aaf 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -36,7 +36,7 @@ iモードに限らず、ほとんどの携帯電話やPalm・ザウルスなど
 
 ### Rubyで書かれている
 
-重要なポイントでしょう:-)??実行にはruby 1.9.2またはruby 2.0.0以上が必要です。
+重要なポイントでしょう:-)??ruby 2.0.0以上が必要です。
 
 セクション(段落)アンカーや過去の日記の参照など、一般的なWeb日記システムの持つ機能は基本的にサポートしています。
 
diff --git a/js/comment_ajax.js b/js/comment_ajax.js
index a5c9b41..fa8eb58 100644
--- a/js/comment_ajax.js
+++ b/js/comment_ajax.js
@@ -12,7 +12,7 @@ $(function() {
 		$('<input type="hidden">').attr('name', 'comment').appendTo(form);
 		$(':submit', form).attr('disabled', 'disabled');
 		$('div.button input', form).hide();
-		$('div.button', form).append('<div id="loading-button"><img src="theme/loading.gif">')
+		$('div.button', form).append('<div id="loading-button"><img src="' + $tDiary.plugin.comment_ajax.theme + '/loading.gif">')
 		$.post(form.attr('action'), form.serialize(), function(data) {
 			$('#loading-button').remove();
 			$('div.button input', form).show();
diff --git a/lib/tdiary.rb b/lib/tdiary.rb
index e243602..afe4bcc 100644
--- a/lib/tdiary.rb
+++ b/lib/tdiary.rb
@@ -50,6 +50,7 @@ module TDiary
 	# Diary model class
 	autoload :Style,                    'tdiary/style'
 	autoload :Comment,                  'tdiary/comment'
+	autoload :DiaryContainer,           'tdiary/diary_container'
 
 	# Routing and Dispatch
 	autoload :Dispatcher,               'tdiary/dispatcher'
diff --git a/lib/tdiary/application.rb b/lib/tdiary/application.rb
index 9a948ed..01bbb01 100644
--- a/lib/tdiary/application.rb
+++ b/lib/tdiary/application.rb
@@ -7,7 +7,7 @@ require 'tdiary/rack'
 # FIXME too dirty hack :-<
 class CGI
 	def env_table_rack
-		$RACK_ENV
+		$RACK_ENV || ENV
 	end
 
 	alias :env_table_orig :env_table
@@ -27,53 +27,76 @@ module TDiary
 		end
 
 		def initialize( base_dir = '/' )
-			@app = ::Rack::Builder.app {
+			@app = ::Rack::Builder.app do
 				map base_dir do
-					# call extensions setup before the core setup (fixed #442)
-					Application.config.builder_procs.reverse.each do |builder_proc|
-						instance_eval &builder_proc
+					map Application.config.path[:index] do
+						use TDiary::Rack::HtmlAnchor
+						use TDiary::Rack::Static, "public"
+						use TDiary::Rack::ValidRequestPath
+						run TDiary::Dispatcher.index
 					end
+
+					map Application.config.path[:update] do
+						use TDiary::Rack::Auth
+						run TDiary::Dispatcher.update
+					end
+
+					map Application.config.path[:assets] do
+						environment = Sprockets::Environment.new
+						TDiary::Application.config.assets_paths.each {|assets_path|
+							environment.append_path assets_path
+						}
+
+						if Application.config.assets_precompile
+							require 'tdiary/rack/assets/precompile'
+							use TDiary::Rack::Assets::Precompile, environment
+						end
+
+						run environment
+					end	
 				end
-			}
+			end
+			run_plugin_startup_procs
 		end
 
 		def call( env )
-			@app.call( env )
-		end
-	end
-
-	Application.configure do
-		config.builder do
-			map Application.config.path[:index] do
-				use TDiary::Rack::HtmlAnchor
-				use TDiary::Rack::Static, "public"
-				use TDiary::Rack::ValidRequestPath
-				run TDiary::Dispatcher.index
+			begin
+				@app.call( env )
+			rescue Exception => e
+				body = ["#{e.class}: #{e}\n"]
+				body << e.backtrace.join("\n")
+				[500, {'Content-Type' => 'text/plain'}, body]
 			end
+		end
 
-			map Application.config.path[:update] do
-				instance_eval &Application.config.authenticate_proc
-				run TDiary::Dispatcher.update
-			end
+	private
+		def run_plugin_startup_procs
+			# avoid offline mode at CGI.new
+			ARGV.replace([""])
+			cgi = RackCGI.new
 
-			map Application.config.path[:assets] do
-				environment = Sprockets::Environment.new
-				TDiary::Extensions::constants.map {|extension|
-					TDiary::Extensions::const_get( extension ).assets_path
-				}.flatten.uniq.each {|assets_path|
-					environment.append_path assets_path
-				}
+			request = TDiary::Request.new(ENV, cgi)
+			conf = TDiary::Configuration.new(cgi, request)
+			tdiary = TDiary::TDiaryBase.new(cgi, '', conf)
+			io = conf.io_class.new(tdiary)
 
-				if Application.config.assets_precompile
-					require 'tdiary/rack/assets/precompile'
-					use TDiary::Rack::Assets::Precompile, environment
-				end
+			plugin = TDiary::Plugin.new(
+				'conf' => conf,
+				'mode' => 'startup',
+				'diaries' => tdiary.diaries,
+				'cgi' => cgi,
+				'years' => nil,
+				'cache_path' => io.cache_path,
+				'date' => Time.now,
+				'comment' => nil,
+				'last_modified' => Time.now,  # FIXME
+				'logger' => TDiary.logger,
+				# 'debug' => true
+			)
 
-				run environment
-			end
+			# run startup plugin
+			plugin.__send__(:startup_proc, self)
 		end
-
-		config.authenticate TDiary::Rack::Auth::Basic, '.htpasswd'
 	end
 end
 
diff --git a/lib/tdiary/application/configuration.rb b/lib/tdiary/application/configuration.rb
index 87e73b5..abd8e6a 100644
--- a/lib/tdiary/application/configuration.rb
+++ b/lib/tdiary/application/configuration.rb
@@ -1,7 +1,7 @@
 module TDiary
 	class Application
 		class Configuration
-			attr_accessor :assets_paths, :assets_precompile, :plugin_paths, :path, :builder_procs, :authenticate_proc
+			attr_accessor :assets_precompile, :plugin_paths, :path
 
 			def initialize
 				# if you need to auto compilation for CoffeeScript
@@ -12,16 +12,12 @@ module TDiary
 					update: '/update.rb',
 					assets: '/assets'
 				}
-				@builder_procs = []
-				@authenticate_proc = proc { }
 			end
 
-			def builder(&block)
-				@builder_procs << block
-			end
-
-			def authenticate(middleware, *params, &block)
-				@authenticate_proc = proc { use middleware, *params, &block }
+			def assets_paths
+				TDiary::Extensions::constants.map {|extension|
+					TDiary::Extensions::const_get( extension ).assets_path
+				}.flatten.uniq
 			end
 		end
 	end
diff --git a/lib/tdiary/application/extensions/omniauth.rb b/lib/tdiary/application/extensions/omniauth.rb
deleted file mode 100644
index b929451..0000000
--- a/lib/tdiary/application/extensions/omniauth.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# -*- coding: utf-8 -*-
-require 'tdiary/application'
-require 'tdiary/rack/auth/omniauth'
-
-TDiary::Application.configure do
-	config.builder do
-		use ::Rack::Session::Pool, expire_after: 2592000
-		use OmniAuth::Builder do
-			configure {|conf| conf.path_prefix = "/auth" }
-			provider :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET']
-		end
-
-		map('/auth') do
-			run TDiary::Rack::Auth::OmniAuth::CallbackHandler.new
-		end
-	end
-
-	config.authenticate TDiary::Rack::Auth::OmniAuth, :twitter do |auth|
-		# TODO: an user can setting
-		auth.info.nickname == ENV['TWITTER_NAME']
-	end
-end
diff --git a/lib/tdiary/cli.rb b/lib/tdiary/cli.rb
index 0e2a6f1..25589ed 100644
--- a/lib/tdiary/cli.rb
+++ b/lib/tdiary/cli.rb
@@ -58,7 +58,7 @@ module TDiary
 
 		desc "assets_copy", "copy assets files"
 		def assets_copy
-			require 'tdiary/environment'
+			require 'tdiary'
 			assets_path = File.join(TDiary.server_root, 'public/assets')
 			TDiary::Application.config.assets_paths.each do |path|
 				Dir.glob(File.join(path, '*')).each do |entity|
@@ -96,7 +96,10 @@ module TDiary
 			"bind to the IP"
 		method_option "port", aliases: "p", type: :numeric, default: 19292, banner:
 			"use PORT"
+		method_option "log", aliases: "l", type: :string, banner:
+			"File to redirect output"
 		def server
+			require 'tdiary'
 			require 'tdiary/environment'
 
 			if options[:cgi]
@@ -105,12 +108,13 @@ module TDiary
 					:bind   => options[:bind],
 					:port   => options[:port],
 					:logger => $stderr,
-					:access_log => $stderr,
+					:access_log => options[:log] ? File.open(options[:log], 'a') : $stderr
 				}
 				TDiary::Server.run( opts )
 			elsif
 				# --rack option
 				# Rack::Server reads ARGV as :config, so delete it
+				require 'webrick'
 				ARGV.shift
 				opts = {
 					:environment => ENV['RACK_ENV'] || "development",
@@ -118,9 +122,11 @@ module TDiary
 					:Host        => options[:bind],
 					:Port        => options[:port],
 					:pid         => File.expand_path("tdiary.pid"),
-					:AccessLog   => $stderr,
 					:config      => File.expand_path("config.ru")
 				}
+				if options[:log]
+					opts[:AccessLog] = [[File.open(options[:log], 'a'), WEBrick::AccessLog::CLF]]
+				end
 				::Rack::Server.start( opts )
 			end
 		end
diff --git a/lib/tdiary/core_ext.rb b/lib/tdiary/core_ext.rb
index 30b9210..b207fab 100644
--- a/lib/tdiary/core_ext.rb
+++ b/lib/tdiary/core_ext.rb
@@ -37,7 +37,7 @@ class String
 	end
 
 	def emojify
-		self.gsub(/:([a-zA-Z0-9_+-]+):/) do |match|
+		self.to_str.gsub(/:([a-zA-Z0-9_+-]+):/) do |match|
 			emoji_alias = $1.downcase
 			emoji_url = %Q[<img src='http://www.emoji-cheat-sheet.com/graphics/emojis/%s.png' width='20' height='20' title='%s' alt='%s' class='emoji' />]
 			if emoji_alias == 'plus1' or emoji_alias == '+1'
diff --git a/lib/tdiary/diary_container.rb b/lib/tdiary/diary_container.rb
new file mode 100644
index 0000000..71489d2
--- /dev/null
+++ b/lib/tdiary/diary_container.rb
@@ -0,0 +1,55 @@
+module TDiary
+	class DiaryContainer
+		# YYYYMMDD
+		def self.find_by_day(conf, date)
+			# date: YYYYMMDD
+			m = date.match(/^(?<year>\d{4})(?<month>\d{2})(?<day>\d{2})$/)
+			raise ArgumentError.new("date must be YYYYMMDD format") unless m
+			new(conf, m[:year], m[:month], m[:day])
+		end
+
+		def self.find_by_month(conf, date)
+			# date: YYYYMM
+			m = date.match(/^(?<year>\d{4})(?<month>\d{2})$/)
+			raise ArgumentError.new("date must be YYYYMM format") unless m
+			new(conf, m[:year], m[:month])
+		end
+
+		def initialize(conf, year, month, day = nil)
+			cgi = FakeCGI.new
+			if year && month && day
+				cgi.params['date'] = ["#{year}#{month}#{day}"]
+				@controller = TDiaryDayWithoutFilter::new(cgi, '', conf)
+			elsif year && month
+				cgi.params['date'] = ["#{year}#{month}"]
+				@controller = TDiaryMonthWithoutFilter::new(cgi, '', conf)
+			else
+				raise StandardError.new
+			end
+		end
+
+		def conf
+			@controller.conf
+		end
+
+		def diaries
+			# Hash of 'YYYYMMDD' => TDiary::Style::WikiDiary
+			@controller.diaries
+		end
+
+		class FakeCGI < CGI
+			def refeter; nil end
+			def user_agent; nil; end
+			def mobile_agent?; nil; end
+			def request_method; 'GET'; end
+		end
+	end
+end
+
+# Local Variables:
+# mode: ruby
+# indent-tabs-mode: t
+# tab-width: 3
+# ruby-indent-level: 3
+# End:
+# vim: ts=3
\ No newline at end of file
diff --git a/lib/tdiary/environment.rb b/lib/tdiary/environment.rb
index b078974..406225c 100644
--- a/lib/tdiary/environment.rb
+++ b/lib/tdiary/environment.rb
@@ -9,6 +9,9 @@ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __FILE__)
 
 require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
 
+# FIXME: workaround fix for tainted path from Gemfile.local
+$LOAD_PATH.each{|lp| $LOAD_PATH << $LOAD_PATH.shift.dup.untaint}
+
 if defined?(Bundler)
   env = [:default]
   env << :development if ENV['RACK_ENV'].nil? || ENV['RACK_ENV'].empty?
diff --git a/lib/tdiary/plugin.rb b/lib/tdiary/plugin.rb
index 5087a23..91e4b07 100644
--- a/lib/tdiary/plugin.rb
+++ b/lib/tdiary/plugin.rb
@@ -31,6 +31,7 @@ module TDiary
 			@conf_procs = {}
 			@conf_genre_label = {}
 			@content_procs = {}
+			@startup_procs = []
 			@cookies = []
 			@javascripts = []
 			@javascript_setting = []
@@ -337,6 +338,16 @@ module TDiary
 			@content_procs[key].call( date )
 		end
 
+		def add_startup_proc( block = Proc::new )
+			@startup_procs << block
+		end
+
+		def startup_proc( app )
+			@startup_procs.each do |proc|
+				proc.call( app )
+			end
+		end
+
 		def remove_tag( str )
 			str.gsub( /<[^"'<>]*(?:"[^"]*"[^"'<>]*|'[^']*'[^"'<>]*)*(?:>|(?=<)|$)/, '' )
 		end
@@ -344,8 +355,8 @@ module TDiary
 		def apply_plugin( str, remove_tag = false )
 			return '' unless str
 			r = str.dup
-			if @conf.options['apply_plugin'] and str.index( '<%' ) then
-				r = str.untaint if $SAFE < 3
+			if @conf.options['apply_plugin'] and r.index( '<%' ) then
+				r = r.untaint if $SAFE < 3
 				Safe::safe( @conf.secure ? 4 : 1 ) do
 					begin
 						r = ERB::new( r ).result( binding )
diff --git a/lib/tdiary/plugin/00default.rb b/lib/tdiary/plugin/00default.rb
index 260744e..089799d 100644
--- a/lib/tdiary/plugin/00default.rb
+++ b/lib/tdiary/plugin/00default.rb
@@ -342,12 +342,13 @@ def default_ogp
 		uri = @conf.index.dup
 		uri[0, 0] = base_url if %r|^https?://|i !~ @conf.index
 		uri.gsub!( %r|/\./|, '/' )
+		image = File.join(uri, "#{theme_url}/ogimage.png")
 		if @mode == 'day' then
 			uri += anchor( @date.strftime( '%Y%m%d' ) )
 		end
 		%Q[<meta content="#{title_tag.gsub(/<[^>]*>/, "")}" property="og:title">
 		<meta content="#{(@mode == 'day') ? 'article' : 'website'}" property="og:type">
-		<meta content="#{h uri}#{h theme_url}/ogimage.png" property="og:image">
+		<meta content="#{h image}" property="og:image">
 		<meta content="#{h uri}" property="og:url">]
 	end
 end
@@ -383,7 +384,7 @@ def script_tag
 	require 'uri'
 	query = script_tag_query_string
 	html = @javascripts.sort.map {|script|
-		if URI(script).scheme
+		if URI(script).scheme or script =~ %r|\A//|
 			%Q|<script src="#{script}" type="text/javascript"></script>|
 		else
 			%Q|<script src="#{js_url}/#{script}#{query}" type="text/javascript"></script>|
@@ -1001,7 +1002,7 @@ end
 # old ruby alert
 #
 def old_ruby_alert
-	if RUBY_VERSION < '1.9' and !@conf['old_ruby_alert.hide']
+	if RUBY_VERSION < '2.0.0' and !@conf['old_ruby_alert.hide']
 		%Q|<div class="alert-warn">
 			<a href="#" class="action-button" id="alert-old-ruby">×</a>
 			#{old_ruby_alert_message}
diff --git a/lib/tdiary/plugin/05referer.rb b/lib/tdiary/plugin/05referer.rb
index 1fd6e81..eebe895 100644
--- a/lib/tdiary/plugin/05referer.rb
+++ b/lib/tdiary/plugin/05referer.rb
@@ -117,13 +117,15 @@ def referer_update( diary )
 		end
 
 	when 'day'
-		referer_load_current( diary )
-		referer_save_current( diary, @cgi.referer )
-		if latest_day?( diary ) then
-			referer_load_volatile( @referer_volatile )
-		elsif @cgi.referer
-			referer_load_volatile( @referer_volatile )
-			referer_save_volatile( @referer_volatile, @cgi.referer )
+		if diary
+			referer_load_current( diary )
+			referer_save_current( diary, @cgi.referer )
+			if latest_day?( diary ) then
+				referer_load_volatile( @referer_volatile )
+			elsif @cgi.referer
+				referer_load_volatile( @referer_volatile )
+				referer_save_volatile( @referer_volatile, @cgi.referer )
+			end
 		end
 
 	when "edit"
diff --git a/lib/tdiary/rack.rb b/lib/tdiary/rack.rb
index 82175cf..449f551 100644
--- a/lib/tdiary/rack.rb
+++ b/lib/tdiary/rack.rb
@@ -4,16 +4,13 @@ module TDiary
 	module Rack
 		autoload :HtmlAnchor,       'tdiary/rack/html_anchor'
 		autoload :ValidRequestPath, 'tdiary/rack/valid_request_path'
+		autoload :Session,          'tdiary/rack/session'
 		autoload :Static,           'tdiary/rack/static'
+		autoload :Auth,             'tdiary/rack/auth'
 
 		module Assets
 			autoload :Precompile,    'tdiary/rack/assets/precompile'
 		end
-
-		module Auth
-			autoload :Basic,         'tdiary/rack/auth/basic'
-			autoload :OmniAuth,      'tdiary/rack/auth/omniauth'
-		end
 	end
 end
 
diff --git a/lib/tdiary/rack/auth.rb b/lib/tdiary/rack/auth.rb
new file mode 100644
index 0000000..8047f16
--- /dev/null
+++ b/lib/tdiary/rack/auth.rb
@@ -0,0 +1,20 @@
+module TDiary
+	module Rack
+		class Auth
+			autoload :Basic,         'tdiary/rack/auth/basic'
+			autoload :OmniAuth,      'tdiary/rack/auth/omniauth'
+
+			def initialize(app)
+				if defined? ::OmniAuth
+					@app = TDiary::Rack::Auth::OmniAuth.new(app)
+				else
+					@app = TDiary::Rack::Auth::Basic.new(app, '.htpasswd')
+				end
+			end
+
+			def call(env)
+				@app.call(env)
+			end
+		end
+	end
+end
diff --git a/lib/tdiary/rack/auth/basic.rb b/lib/tdiary/rack/auth/basic.rb
index cbb919f..ca209b7 100644
--- a/lib/tdiary/rack/auth/basic.rb
+++ b/lib/tdiary/rack/auth/basic.rb
@@ -3,7 +3,7 @@ require 'webrick/httpauth/htpasswd'
 
 module TDiary
 	module Rack
-		module Auth
+		class Auth
 			class PasswordFileNotFound < StandardError; end
 
 			class Basic
diff --git a/lib/tdiary/rack/auth/omniauth.rb b/lib/tdiary/rack/auth/omniauth.rb
index 9319de4..a139753 100644
--- a/lib/tdiary/rack/auth/omniauth.rb
+++ b/lib/tdiary/rack/auth/omniauth.rb
@@ -1,51 +1,83 @@
 require 'omniauth'
+require 'tdiary/rack/auth/omniauth/authorization'
 
-module TDiary
-	module Rack
-		module Auth
-			class OmniAuth
-				def initialize(app, provider, &block)
-					@app = app
-					@provider = provider
-					@authz = block
-				end
-
-				def call(env)
-					auth = env['rack.session']['auth']
-					return login(env) unless auth
-					env['REMOTE_USER'] = "#{auth.uid}@#{auth.provider}"
-					return forbidden unless @authz.call(auth)
-					@app.call(env)
-				end
-
-				def login(env)
-					env['rack.session']['tdiary.auth.redirect'] =
-						"#{env['REQUEST_PATH']}?#{env['QUERY_STRING']}"
-					redirect = File.join(File.dirname(env['REQUEST_PATH']), "#{::OmniAuth.config.path_prefix}/#{@provider}")
-					[302, {'Content-Type' => 'text/plain', 'Location' => redirect}, []]
-				end
-
-				def logout(env)
-					env['rack.session']['user_id'] = nil
-				end
-
-				def forbidden
-					[403, {'Content-Type' => 'text/plain'}, ['forbidden']]
-				end
-
-				class CallbackHandler
-					def call(env)
-						# reset sesstion to prevend session fixation attack
-						# see: http://www.ipa.go.jp/security/vuln/documents/website_security.pdf (section 1.4)
-						env['rack.session.options'][:renew] = true
-						auth = env['omniauth.auth']
-						env['rack.session']['auth'] = auth
-						env['REMOTE_USER'] = "#{auth.uid}@#{auth.provider}"
-						redirect = env['rack.session']['tdiary.auth.redirect'] || '/'
-						[302, {'Content-Type' => 'text/plain', 'Location' => redirect}, []]
-					end
-				end
-			end
+class TDiary::Rack::Auth::OmniAuth
+	class NoStrategyFoundError < StandardError; end
+	@provider_procs = {}
+
+	class << self
+		attr_reader :provider_procs
+	end
+
+	def self.add_provider(name, &block)
+		@provider_procs[name] = block
+	end
+
+	def initialize(app)
+		provider = enabled_providers.first
+		unless provider
+			raise NoStrategyFoundError.new("Not found any strategies. Write the omniauth strategy in your Gemfile.local.")
+		end
+
+		@builder = ::Rack::Builder.new(app) {
+			use TDiary::Rack::Session
+		}
+		@builder.instance_eval(&self.class.provider_procs[provider])
+	end
+
+	def call(env)
+		@builder.call(env)
+	end
+
+	add_provider(:Twitter) do
+		# https://apps.twitter.com/
+		# https://github.com/arunagw/omniauth-twitter
+		use ::OmniAuth::Builder do
+			provider :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET']
+		end
+		use TDiary::Rack::Auth::OmniAuth::Authorization, :twitter do |auth|
+			ENV['TWITTER_NAME'].split(/,/).include?(auth.info.nickname)
+		end
+	end
+
+	add_provider(:Facebook) do
+		# https://developers.facebook.com/apps/
+		# https://github.com/mkdynamic/omniauth-facebook
+		use ::OmniAuth::Builder do
+			provider :facebook, ENV['FACEBOOK_KEY'], ENV['FACEBOOK_SECRET']
+		end
+		use TDiary::Rack::Auth::OmniAuth::Authorization, :facebook do |auth|
+			ENV['FACEBOOK_EMAIL'].split(/,/).include?(auth.info.email)
+		end
+	end
+
+	add_provider(:GitHub) do
+		# https://github.com/settings/applications
+		# https://github.com/intridea/omniauth-github
+		use ::OmniAuth::Builder do
+			provider :github, ENV['GITHUB_KEY'], ENV['GITHUB_SECRET']
+		end
+		use TDiary::Rack::Auth::OmniAuth::Authorization, :github do |auth|
+			ENV['GITHUB_NAME'].split(/,/).include?(auth.info.nickname)
+		end
+	end
+
+	add_provider(:GoogleOauth2) do
+		# https://code.google.com/apis/console/
+		# https://github.com/zquestz/omniauth-google-oauth2
+		use ::OmniAuth::Builder do
+			provider :google_oauth2, ENV["GOOGLE_CLIENT_ID"], ENV["GOOGLE_CLIENT_SECRET"]
+		end
+		use TDiary::Rack::Auth::OmniAuth::Authorization, :google_oauth2 do |auth|
+			ENV['GOOGLE_EMAIL'].split(/,/).include?(auth.info.email)
+		end
+	end
+
+private
+
+	def enabled_providers
+		::OmniAuth::Strategies.constants.select do |name|
+			self.class.provider_procs.has_key?(name)
 		end
 	end
 end
diff --git a/lib/tdiary/rack/auth/omniauth/authorization.rb b/lib/tdiary/rack/auth/omniauth/authorization.rb
new file mode 100644
index 0000000..ca80fb3
--- /dev/null
+++ b/lib/tdiary/rack/auth/omniauth/authorization.rb
@@ -0,0 +1,64 @@
+require 'omniauth'
+
+module TDiary
+	module Rack
+		class Auth
+			class OmniAuth
+				class Authorization
+					def initialize(app, provider, &block)
+						@app = app
+						@provider = provider
+						@authz = block
+					end
+
+					def call(env)
+						if not authenticate?(env)
+							# phase 1: request phase
+							login(env)
+						elsif env['REQUEST_PATH'].match(%r|auth/#{@provider}/callback|)
+							# phase 2: callback phase
+							callback(env)
+						else
+							# phase 3: authorization phase
+							auth = env['rack.session']['auth']
+							env['REMOTE_USER'] = "#{auth.uid}@#{auth.provider}"
+							return forbidden unless @authz.call(auth)
+							@app.call(env)
+						end
+					end
+
+					def login(env)
+						STDERR.puts "use #{@provider} authentication strategy"
+						req = ::Rack::Request.new(env)
+						env['rack.session']['tdiary.auth.redirect'] = "#{req.base_url}#{req.fullpath}"
+						redirect = File.join("#{req.base_url}#{req.path}", "#{::OmniAuth.config.path_prefix}/#{@provider}")
+						[302, {'Content-Type' => 'text/plain', 'Location' => redirect}, []]
+					end
+
+					def logout(env)
+						env['rack.session']['user_id'] = nil
+					end
+
+					def forbidden
+						[403, {'Content-Type' => 'text/plain'}, ['forbidden']]
+					end
+
+					def callback(env)
+						# reset sesstion to prevend session fixation attack
+						# see: http://www.ipa.go.jp/security/vuln/documents/website_security.pdf (section 1.4)
+						env['rack.session.options'][:renew] = true
+						auth = env['omniauth.auth']
+						env['rack.session']['auth'] = auth
+						env['REMOTE_USER'] = "#{auth.uid}@#{auth.provider}"
+						redirect = env['rack.session']['tdiary.auth.redirect'] || '/'
+						[302, {'Content-Type' => 'text/plain', 'Location' => redirect}, []]
+					end
+
+					def authenticate?(env)
+						env['omniauth.auth'] || env['rack.session']['auth']
+					end
+				end
+			end
+		end
+	end
+end
diff --git a/lib/tdiary/rack/session.rb b/lib/tdiary/rack/session.rb
new file mode 100644
index 0000000..eadcf15
--- /dev/null
+++ b/lib/tdiary/rack/session.rb
@@ -0,0 +1,35 @@
+begin
+	require 'rack/session/dalli'
+rescue LoadError
+end
+
+module TDiary
+	module Rack
+		class Session
+			def initialize(app)
+				@app = session_middleware(app)
+			end
+
+			def call(env)
+				@app.call(env)
+			end
+
+		private
+
+			def session_middleware(app)
+				if ::Rack::Session.const_defined? :Dalli
+					::Rack::Session::Dalli.new(
+						app,
+						cache: Dalli::Client.new,
+						expire_after: 2592000
+					)
+				else
+					::Rack::Session::Pool.new(
+						app,
+						expire_after: 2592000
+					)
+				end
+			end
+		end
+	end
+end
diff --git a/lib/tdiary/style.rb b/lib/tdiary/style.rb
index 4601804..9b76ca1 100644
--- a/lib/tdiary/style.rb
+++ b/lib/tdiary/style.rb
@@ -2,6 +2,7 @@
 
 require 'tdiary/comment_manager'
 require 'tdiary/referer_manager'
+require 'erb'
 
 module TDiary
 	module Style
@@ -46,7 +47,7 @@ module TDiary
 		end
 
 		module BaseDiary
-			include ERB::Util
+			include ::ERB::Util
 			include CommentManager
 			include RefererManager
 
diff --git a/lib/tdiary/tasks/assets.rake b/lib/tdiary/tasks/assets.rake
index 7049ee2..005487d 100644
--- a/lib/tdiary/tasks/assets.rake
+++ b/lib/tdiary/tasks/assets.rake
@@ -13,7 +13,7 @@ namespace :assets do
 	desc "copy assets files"
 	task :copy do
 		require 'fileutils'
-		assets_path = File.dirname(__FILE__) + '/../../public/assets'
+		assets_path = File.dirname(__FILE__) + '/../../../public/assets'
 
 		FileUtils.mkdir_p assets_path
 		FileList['{js,theme}/*'].each do |file|
diff --git a/lib/tdiary/tasks/release.rake b/lib/tdiary/tasks/release.rake
index 1070de7..dd187a9 100644
--- a/lib/tdiary/tasks/release.rake
+++ b/lib/tdiary/tasks/release.rake
@@ -34,24 +34,35 @@ def make_tarball( repo, version = nil )
 			sh "chmod +x index.rb index.fcgi update.rb update.fcgi"
 			sh 'rake doc'
 			Bundler.with_clean_env do
-					sh "bundle --path .bundle --without coffee:server:development:test"
+					sh "bundle --path .bundle --without coffee:development:test"
 			end
+
+			# reduce filesize
+			Dir.glob('.bundle/ruby/*/cache/*').each do |file|
+				# cached gem file
+				rm_rf file
+			end
+			Dir.glob('.bundle/ruby/*/gems/*/*/').each do |dir|
+				# spec, fixtures etc..
+				rm_rf dir unless File.basename(dir).match(/lib|data/)
+			end
+
 			Dir.chdir '.bundle/ruby' do
 				v = `ls`.chomp
 				case v
+				when '2.2.0'
+					FileUtils.cp_r '2.2.0', '2.0.0'
+					FileUtils.cp_r '2.2.0', '2.1.0'
 				when '2.1.0'
-					FileUtils.cp_r '2.1.0', '1.9.1'
 					FileUtils.cp_r '2.1.0', '2.0.0'
+					FileUtils.cp_r '2.1.0', '2.2.0'
 				when '2.0.0'
-					FileUtils.cp_r '2.0.0', '1.9.1'
 					FileUtils.cp_r '2.0.0', '2.1.0'
-				when '1.9.1'
-					FileUtils.cp_r '1.9.1', '2.0.0'
-					FileUtils.cp_r '1.9.1', '2.1.0'
+					FileUtils.cp_r '2.0.0', '2.2.0'
 				else
+					FileUtils.cp_r v, '2.2.0'
 					FileUtils.cp_r v, '2.1.0'
 					FileUtils.cp_r v, '2.0.0'
-					FileUtils.cp_r v, '1.9.1'
 					FileUtils.rm_rf v
 				end
 			end
diff --git a/lib/tdiary/version.rb b/lib/tdiary/version.rb
index 5672e8e..e95a99c 100644
--- a/lib/tdiary/version.rb
+++ b/lib/tdiary/version.rb
@@ -1,3 +1,3 @@
 module TDiary
-	VERSION = '4.1.1'
+	VERSION = '4.1.2'
 end
diff --git a/misc/paas/heroku/Gemfile b/misc/paas/heroku/Gemfile
deleted file mode 100644
index 78be0bf..0000000
--- a/misc/paas/heroku/Gemfile
+++ /dev/null
@@ -1,20 +0,0 @@
-source 'https://rubygems.org'
-
-gem 'rake'
-
-gem 'rack'
-gem 'sprockets'
-gem 'hikidoc'
-gem 'fastimage'
-
-gem 'omniauth'
-gem 'omniauth-twitter'
-gem 'omniauth-github'
-
-gem 'thin', require: false
-gem 'tdiary-io-rdb'
-gem 'pg'
-gem 'thor'
-
-# To use memcached for Cache
-# gem 'tdiary-cache-memcached'
diff --git a/misc/paas/heroku/Gemfile.local b/misc/paas/heroku/Gemfile.local
new file mode 100644
index 0000000..1bbfecd
--- /dev/null
+++ b/misc/paas/heroku/Gemfile.local
@@ -0,0 +1,8 @@
+ruby '2.2.0'
+gem 'thin', require: false
+gem 'tdiary-io-mongodb', github: 'tdiary/tdiary-io-mongodb'
+gem 'tdiary-contrib', github: 'tdiary/tdiary-contrib'
+gem 'omniauth'
+gem 'omniauth-twitter'
+gem 'dalli'
+gem 'memcachier'
diff --git a/misc/paas/heroku/Gemfile.lock b/misc/paas/heroku/Gemfile.lock
deleted file mode 100644
index 1c74965..0000000
--- a/misc/paas/heroku/Gemfile.lock
+++ /dev/null
@@ -1,74 +0,0 @@
-GEM
-  remote: https://rubygems.org/
-  specs:
-    addressable (2.3.5)
-    daemons (1.1.9)
-    eventmachine (1.0.3)
-    faraday (0.9.0)
-      multipart-post (>= 1.2, < 3)
-    fastimage (1.6.0)
-      addressable (~> 2.3, >= 2.3.5)
-    hashie (2.0.5)
-    hike (1.2.3)
-    hikidoc (0.0.6)
-    jwt (0.1.11)
-      multi_json (>= 1.5)
-    multi_json (1.8.4)
-    multi_xml (0.5.5)
-    multipart-post (2.0.0)
-    oauth (0.4.7)
-    oauth2 (0.9.3)
-      faraday (>= 0.8, < 0.10)
-      jwt (~> 0.1.8)
-      multi_json (~> 1.3)
-      multi_xml (~> 0.5)
-      rack (~> 1.2)
-    omniauth (1.2.1)
-      hashie (>= 1.2, < 3)
-      rack (~> 1.0)
-    omniauth-github (1.1.1)
-      omniauth (~> 1.0)
-      omniauth-oauth2 (~> 1.1)
-    omniauth-oauth (1.0.1)
-      oauth
-      omniauth (~> 1.0)
-    omniauth-oauth2 (1.1.2)
-      faraday (>= 0.8, < 0.10)
-      multi_json (~> 1.3)
-      oauth2 (~> 0.9.3)
-      omniauth (~> 1.2)
-    omniauth-twitter (1.0.1)
-      multi_json (~> 1.3)
-      omniauth-oauth (~> 1.0)
-    pg (0.17.1)
-    rack (1.5.2)
-    rake (10.1.1)
-    sequel (4.7.0)
-    sprockets (2.11.0)
-      hike (~> 1.2)
-      multi_json (~> 1.0)
-      rack (~> 1.0)
-      tilt (~> 1.1, != 1.3.0)
-    tdiary-io-rdb (0.0.1)
-      sequel
-    thin (1.6.1)
-      daemons (>= 1.0.9)
-      eventmachine (>= 1.0.0)
-      rack (>= 1.0.0)
-    tilt (1.4.1)
-
-PLATFORMS
-  ruby
-
-DEPENDENCIES
-  fastimage
-  hikidoc
-  omniauth
-  omniauth-github
-  omniauth-twitter
-  pg
-  rack
-  rake
-  sprockets
-  tdiary-io-rdb
-  thin
diff --git a/misc/paas/heroku/app.json b/misc/paas/heroku/app.json
new file mode 100644
index 0000000..f75ea81
--- /dev/null
+++ b/misc/paas/heroku/app.json
@@ -0,0 +1,19 @@
+{
+  "name": "tDiary",
+  "website": "http://www.tdiary.org/",
+  "repository": "https://github.com/tdiary/tdiary-core/tree/heroku",
+  "addons": [
+    "sendgrid",
+    "memcachier",
+    "mongolab"
+  ],
+  "scripts": {
+    "postdeploy": "bundle exec rake mongodb:index"
+  },
+  "env": {
+    "TWITTER_KEY": "",
+    "TWITTER_SECRET": "",
+	 "TWITTER_NAME": "",
+    "RACK_ENV": "production"
+  }
+}
diff --git a/misc/paas/heroku/config.ru b/misc/paas/heroku/config.ru
new file mode 100644
index 0000000..52de4de
--- /dev/null
+++ b/misc/paas/heroku/config.ru
@@ -0,0 +1,6 @@
+$:.unshift( File.join(File::dirname( __FILE__ ), 'lib' ).untaint )
+require 'tdiary/application'
+
+use ::Rack::Reloader unless ENV['RACK_ENV'] == 'production'
+base_dir = '/'
+run TDiary::Application.new( base_dir )
diff --git a/misc/paas/heroku/tasks/mongodb.rake b/misc/paas/heroku/tasks/mongodb.rake
new file mode 100644
index 0000000..5e03c60
--- /dev/null
+++ b/misc/paas/heroku/tasks/mongodb.rake
@@ -0,0 +1,12 @@
+namespace :mongodb do
+	desc "make index into mongoDB"
+	task :index do
+		require 'erb'
+		require 'tdiary'
+		conf = TDiary::Config.new
+		TDiary::DiaryContainer.new(conf, '2015', '01')
+		TDiary::IO::MongoDB::Diary.create_indexes
+		TDiary::IO::MongoDB::Comment.create_indexes
+		TDiary::IO::MongoDB::Plugin.create_indexes
+	end
+end
diff --git a/misc/paas/heroku/tdiary.conf b/misc/paas/heroku/tdiary.conf
index 97b8500..552936b 100644
--- a/misc/paas/heroku/tdiary.conf
+++ b/misc/paas/heroku/tdiary.conf
@@ -1,9 +1,13 @@
+#
+# tdiary.conf for Heroku
+#
 require 'tempfile'
 @data_path = Dir.tmpdir
 
 @style = 'Wiki'
 
- at io_class = TDiary::IO::Rdb
+ at io_class = TDiary::IO::MongoDB
+ at database_url = ENV['MONGOLAB_URI']
 
 @index = './'
 @update = 'update.rb'
@@ -21,21 +25,17 @@ require 'tempfile'
 
 @options['apply_plugin'] = true
 @options['sp.path'] = ['misc/plugin']
- at options['style.path'] = ['misc/style/gfm', 'tdiary/style']
- at options['sp.selected'] =
-"amazon.rb
-append-css.rb
-calendar2.rb
-dropdown_calendar.rb
-footnote.rb
-highlight.rb
-image.rb
-jdate.rb
-kw.rb
-my-ex.rb
-"
+ at options['sp.selected'] = %w(amazon.rb append-css.rb calendar2.rb comment_ajax.rb comment_mail-smtp.rb dropdown_calendar.rb footnote.rb highlight.rb html_anchor.rb jdate.rb makerss.rb kw.rb my-ex.rb theme_online.rb ).join("\n")
 
 @options['dropdown_calendar.label'] = ''
+
+ at options['comment_mail.smtp_host'] = 'smtp.sendgrid.net'
+ at options['comment_mail.smtp_port'] = 587
+ at options['comment_mail.user_name'] = ENV['SENDGRID_USERNAME']
+ at options['comment_mail.password'] = ENV['SENDGRID_PASSWORD']
+ at options['comment_mail.authentication'] = :plain
+ at options['comment_mail.starttls'] = true
+
 @options['spamfilter.bad_comment_patts'] = "(href=|casino|gambling|betting|fastsearch\\.eu\\.com|ganzao|poker|holdem|hold.em|roulette|drug|tramadol|viagra|fioricet|oxycontin|biaxin|aldara|business cards|home depot|slot.?machine|insurance|getblog2|video-game|Good site|internet-all\\.com|deai|tdfms|comu2|omaha)\r\n"
 @options['spamfilter.bad_ip_addrs'] = ""
 @options['spamfilter.bad_mail_patts'] = "(mu at alloha\\.info|mumu2004 at mail\\.com|zhongleibo|dfd at 12\\.com|anonimous|aol\\.|yahoo\\.|google\\.|hotmail\\.|msn\\.|leroy\\.|ablare\\.|gmx\\.|lorazepam|\\.co$)"
diff --git a/misc/plugin/amazon.rb b/misc/plugin/amazon.rb
index de0ede5..a1f365d 100644
--- a/misc/plugin/amazon.rb
+++ b/misc/plugin/amazon.rb
@@ -46,6 +46,8 @@ if @conf['amazon.bitly'] and @conf['bitly.login'] and @conf['bitly.key'] then
 	add_js_setting( '$tDiary.plugin.bitly.apiKey', "'#{@conf['bitly.key']}'" )
 end
 
+class AmazonRedirectError < StandardError; end
+
 def amazon_fetch( url, limit = 10 )
 	raise ArgumentError, 'HTTP redirect too deep' if limit == 0
 
@@ -57,6 +59,8 @@ def amazon_fetch( url, limit = 10 )
 		res.body
 	when Net::HTTPRedirection
 		amazon_fetch( res['location'].untaint, limit - 1 )
+	when Net::HTTPForbidden, Net::HTTPServiceUnavailable
+		raise AmazonRedirectError.new( limit.to_s )
 	else
 		raise ArgumentError, res.error!
 	end
@@ -78,10 +82,14 @@ def amazon_call_ecs( asin, id_type, country )
 	url << "&ResponseGroup=Medium"
 	url << "&Version=#{@amazon_require_version}"
 
+	limit = 10
 	begin
-		Timeout.timeout( 10 ) do
+		Timeout.timeout( limit ) do
 			amazon_fetch( url )
 		end
+	rescue AmazonRedirectError
+		limit = $!.message.to_i
+		retry
 	rescue ArgumentError
 	end
 end
diff --git a/misc/plugin/category.rb b/misc/plugin/category.rb
index b57b47b..5cb4ea5 100644
--- a/misc/plugin/category.rb
+++ b/misc/plugin/category.rb
@@ -209,20 +209,6 @@ end
 module Category
 
 #
-# CGI (mock-up CGI class for Cache::recreate)
-#
-class CGI
-	attr_reader :params
-	def initialize
-		@params = Hash.new([])
-	end
-	def referer; nil; end
-	def user_agent; nil; end
-	def mobile_agent?; nil; end
-	def request_method; 'GET'; end
-end
-
-#
 # Info
 #
 class Info
@@ -487,17 +473,13 @@ class Cache
 	# (re)create category cache
 	#
 	def recreate(years)
-		cgi = Category::CGI::new
-
 		list = []
 		@plugin.__send__(:transaction, 'category') do |db|
 			db.keys.each {|key|db.delete(key)}
 
 			years.each do |y, ms|
 				ms.each do |m|
-					ym = "#{y}#{m}"
-					cgi.params['date'] = [ym]
-					m = TDiaryMonthWithoutFilter.new(cgi, '', @conf)
+					m = DiaryContainer::find_by_month(@conf, "#{y}#{m}")
 					m.diaries.each do |ymd, diary|
 						next if !diary.visible? or !diary.categorizable?
 						categorized = categorize_diary(diary)
diff --git a/misc/plugin/category_autocomplete.rb b/misc/plugin/category_autocomplete.rb
index ed30cb7..c30f7ea 100644
--- a/misc/plugin/category_autocomplete.rb
+++ b/misc/plugin/category_autocomplete.rb
@@ -9,10 +9,10 @@
 
 if !@cgi.mobile_agent? && /\A(?:form|preview|append|edit|update)\z/ =~ @mode
 	add_header_proc do
-		%Q|<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css"/>|
+		%Q|<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css"/>|
 	end
 
-	enable_js('http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js')
+	enable_js('//ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js')
 	enable_js('caretposition.js')
 	enable_js('category_autocomplete.js')
 
diff --git a/misc/plugin/comment_ajax.rb b/misc/plugin/comment_ajax.rb
index 8d5920c..12aa239 100644
--- a/misc/plugin/comment_ajax.rb
+++ b/misc/plugin/comment_ajax.rb
@@ -1,5 +1,7 @@
 if @mode == 'day' and not bot? then
 	enable_js('comment_ajax.js')
+	add_js_setting('$tDiary.plugin.comment_ajax')
+	add_js_setting('$tDiary.plugin.comment_ajax.theme', %Q["#{theme_url}"])
 end
 
 # Local Variables:
diff --git a/misc/plugin/comment_emoji_autocomplete.rb b/misc/plugin/comment_emoji_autocomplete.rb
index 5c9be9d..010a7eb 100644
--- a/misc/plugin/comment_emoji_autocomplete.rb
+++ b/misc/plugin/comment_emoji_autocomplete.rb
@@ -9,10 +9,10 @@
 
 if !@cgi.mobile_agent? && /\A(?:day)\z/ =~ @mode
 	add_header_proc do
-		%Q|<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css"/>|
+		%Q|<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css"/>|
 	end
 
-	enable_js('http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js')
+	enable_js('//ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js')
 	enable_js('caretposition.js')
 	enable_js('comment_emoji_autocomplete.js')
 
diff --git a/misc/plugin/comment_mail-smtp.rb b/misc/plugin/comment_mail-smtp.rb
index 97d837f..c9571b5 100644
--- a/misc/plugin/comment_mail-smtp.rb
+++ b/misc/plugin/comment_mail-smtp.rb
@@ -2,7 +2,7 @@
 # comment_mail-smtp.rb
 #
 # SMTPプロトコルを使ってツッコミをメールで知らせる
-#   入れるだけで動作する
+#   同一ホスト内にSMTPサーバがある場合は有効にするだけで動作する
 #
 # Options:
 #   設定画面から指定できるもの(ツッコミメール系プラグイン共通):
@@ -25,18 +25,33 @@
 #     @options['comment_mail.smtp_port']
 #          それぞれ、メール送信に使うSMTPサーバのホスト名とポート番号。
 #          無指定時はそれぞれ「'localhost'」と「25」。
+#   以下は通常は不要。必要に応じて指定する:
+#     @options['comment_mail.user_name']
+#     @options['comment_mail.password']
+#          SMTP認証が必要な場合のユーザ名とパスワード
+#     @options['comment_mail.authentication']
+#          SMTP認証の方式。:plainや:loginなど(Mail gemに指定できるもの)
+#     @options['comment_mail.starttls']
+#          TLSに自動接続する(true/false) (Mail gem)
 #
-# Copyright (c) 2003 TADA Tadashi <sho at spc.gr.jp>
+# Copyright (c) 2015 TADA Tadashi <t at tdtds.jp>
 # You can distribute this file under the GPL2 or any later version.
 #
 def comment_mail( text, to )
 	begin
-		require 'net/smtp'
-		host = @conf['comment_mail.smtp_host'] || 'localhost'
-		port = @conf['comment_mail.smtp_port'] || 25
-		Net::SMTP.start( host, port ) do |smtp|
-			smtp.send_mail( text.force_encoding( 'US-ASCII' ), @conf.author_mail.untaint, to )
-		end
+		require 'mail'
+
+		mail = Mail.new( text )
+		delivery_opts = {
+			address: @conf['comment_mail.smtp_host'] || 'localhost',
+			port: @conf['comment_mail.smtp_port'] || 25,
+			authentication: @conf['comment_mail.authentication'],
+			user_name: @conf['comment_mail.user_name'],
+			password: @conf['comment_mail.password'],
+			enable_starttls_auto: @conf['comment_mail.starttls']
+		}.delete_if{|k,v| v == nil}
+		mail.delivery_method( :smtp, delivery_opts )
+		mail.deliver
 	rescue
 		$stderr.puts $!
 	end
diff --git a/misc/plugin/makerss.rb b/misc/plugin/makerss.rb
index 9733bde..07b54f7 100644
--- a/misc/plugin/makerss.rb
+++ b/misc/plugin/makerss.rb
@@ -28,7 +28,7 @@
 # Distributed under the GPL2 or any later version.
 #
 
-if /^append|replace|comment|showcomment$/ =~ @mode then
+if /^append|replace|comment|showcomment|startup$/ =~ @mode then
 	unless @conf.description
 		@conf.description = @conf['whatsnew_list.rdf.description']
 	end
@@ -486,6 +486,10 @@ add_edit_proc do
 	HTML
 end
 
+add_startup_proc do
+	makerss_update
+end
+
 def replace_entities( text )
 	unless @xml_entity_table then
 		@xml_entity_table = {
diff --git a/misc/plugin/recent_comment3.rb b/misc/plugin/recent_comment3.rb
index a9311fa..e81eb9b 100644
--- a/misc/plugin/recent_comment3.rb
+++ b/misc/plugin/recent_comment3.rb
@@ -95,13 +95,9 @@ def recent_comment3(ob_max = 'OBSOLUTE' ,sep = 'OBSOLUTE',ob_date_format = 'OBSO
 		if entries.size == 0
 			notfound_msg
 		else
-			cgi = CGI::new
-			def cgi.referer; nil; end
-
 			tree_order.each do |entry_date|
 				a_entry = @index + anchor(entry_date)
-				cgi.params['date'] = [entry_date]
-				diary = TDiaryDayWithoutFilter::new(cgi, '', @conf)
+				diary = DiaryContainer::find_by_day(@conf, entry_date)
 				title = diary.diaries[entry_date].title.gsub( /<[^>]*>/, '' ) if diary
 
 				if title.nil? || title.length == 0 || title.strip.delete(' ').delete(' ').length == 0 then
diff --git a/misc/plugin/recent_list.rb b/misc/plugin/recent_list.rb
index 58bdda8..d142886 100644
--- a/misc/plugin/recent_list.rb
+++ b/misc/plugin/recent_list.rb
@@ -28,14 +28,10 @@ def recent_list( days = 30, date_format = nil, title_with_body = nil, show_size
 
 	result = %Q|<ul class="recent-list">\n|
 
-	cgi = CGI::new
-	def cgi.referer; nil; end
-
 	catch(:exit) {
 		@years.keys.sort.reverse_each do |year|
 			@years[year].sort.reverse_each do |month|
-				cgi.params['date'] = ["#{year}#{month}"]
-				m = TDiaryMonthWithoutFilter::new(cgi, '', @conf)
+				m = DiaryContainer::find_by_month(@conf, "#{year}#{month}")
 				m.diaries.keys.sort.reverse_each do |date|
 					next unless m.diaries[date].visible?
 					result << %Q|<li><a href="#{@index}#{anchor date}">#{m.diaries[date].date.strftime(date_format)}</a>\n|
diff --git a/misc/plugin/theme_online.rb b/misc/plugin/theme_online.rb
index fbb3cc1..3525b43 100644
--- a/misc/plugin/theme_online.rb
+++ b/misc/plugin/theme_online.rb
@@ -1,5 +1,8 @@
 # theme_online.rb: choice theme from online repository on tDiary.org
 #
+# options:
+#    @options['theme_online.url']: top level URL of another theme site
+#
 # Copyright (C) 2014 by TADA Tadashi <t at tdtds.jp>
 # You can distribute and/or modify it under GPL2 or any later version.
 #
@@ -7,8 +10,10 @@ require 'json'
 require 'open-uri'
 
 def theme_list_online(list)
+	url = @options['theme_online.url'] || 'http://theme.tdiary.org/'
+	url = "http:#{url}" if url =~ %r|\A//|
 	begin
-		online_list = JSON.load(open('http://theme.tdiary.org/themes.json', &:read))['themes']
+		online_list = JSON.load(open(File.join(url, 'themes.json'), &:read))['themes']
 		list + online_list.keys.map do |t|
 			title = online_list[t]['title']
 			label = t == title ? '' : " (#{title})"
@@ -21,5 +26,6 @@ def theme_list_online(list)
 end
 
 def theme_url_online(theme)
-	"http://theme.tdiary.org/#{h theme}/#{h theme}.css"
+	url = @options['theme_online.url'] || 'http://theme.tdiary.org/'
+	File.join(url, "#{h theme}/#{h theme}.css")
 end
diff --git a/spec/acceptance/save_conf_plugin_spec.rb b/spec/acceptance/save_conf_plugin_spec.rb
index ed15f75..b079159 100644
--- a/spec/acceptance/save_conf_plugin_spec.rb
+++ b/spec/acceptance/save_conf_plugin_spec.rb
@@ -56,8 +56,8 @@ feature 'プラグイン選択設定の利用' do
 
 		expect(page.body).to be_include('caretposition.js')
 		expect(page.body).to be_include('category_autocomplete.js')
-		expect(page.body).to be_include('http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js')
-		expect(page.body).not_to be_include('http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js?')
+		expect(page.body).to be_include('//ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js')
+		expect(page.body).not_to be_include('//ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js?')
 	end
 end
 # Local Variables:
diff --git a/spec/core/application_spec.rb b/spec/core/application_spec.rb
new file mode 100644
index 0000000..3206cfe
--- /dev/null
+++ b/spec/core/application_spec.rb
@@ -0,0 +1,65 @@
+# -*- coding: utf-8 -*-
+require 'spec_helper'
+require 'rack/test'
+require 'tdiary/application'
+
+describe TDiary::Application do
+	include Rack::Test::Methods
+
+	before do
+	end
+
+	describe '#call' do
+		let(:app) { TDiary::Application.new }
+
+		context "when is accessed to index"
+		it do
+			get '/'
+			expect(last_response.status).to eq 200
+		end
+
+		context "when is accessed to update" do
+			it do
+				get '/update.rb'
+				expect(last_response.status).to eq 401
+			end
+		end
+
+		context "with base_dir" do
+			let(:app) { TDiary::Application.new('/diary') }
+
+			it do
+				get '/diary/'
+				expect(last_response.status).to eq 200
+			end
+
+			context "when access to root directory" do
+				it do
+					get '/'
+					expect(last_response.status).to eq 404
+				end
+			end
+		end
+
+		context "when the application raises exception" do
+			before do
+				allow(TDiary::Dispatcher).to receive_message_chain(:index).and_return(
+					lambda {|env| raise StandardError.new }
+				)
+			end
+
+			it do
+				get '/'
+				expect(last_response.status).to eq 500
+				expect(last_response.body).to match(/^StandardError/)
+			end
+		end
+	end
+end
+
+# Local Variables:
+# mode: ruby
+# indent-tabs-mode: t
+# tab-width: 3
+# ruby-indent-level: 3
+# End:
diff --git a/spec/core/diary_container_spec.rb b/spec/core/diary_container_spec.rb
new file mode 100644
index 0000000..63ad0ae
--- /dev/null
+++ b/spec/core/diary_container_spec.rb
@@ -0,0 +1,71 @@
+require 'spec_helper'
+
+require 'tdiary'
+require 'tdiary/cache/file'
+require 'tdiary/io/default'
+require 'tdiary/diary_container'
+
+describe TDiary::DiaryContainer do
+	let(:conf) { TDiary::Configuration.new }
+	let(:today) { Time.local(2005, 1, 20, 12, 0, 0) }
+
+  let(:tdiary_conf_org) { File.join(TDiary::root, "spec/fixtures/tdiary.conf.webrick") }
+  let(:tdiary_conf) { File.join(TDiary::root, "tdiary.conf") }
+
+  before do
+  	# create sample confing
+		FileUtils.cp_r tdiary_conf_org, tdiary_conf, verbose: false
+
+		# create sample diary
+		tdiary = DummyTDiary.new
+		tdiary.conf = conf
+		io = TDiary::IO::Default.new(tdiary)
+		io.transaction(today) do |diaries|
+			date = today.strftime('%Y%m%d')
+			diary = io.diary_factory(date, "foo", "", "wiki")
+			diaries[date] = diary.append("bar")
+			TDiary::TDiaryBase::DIRTY_DIARY
+		end
+  end
+
+  after do
+    FileUtils.rm_f tdiary_conf
+		["/tmp/data/#{today.year}"].each do |dir|
+			FileUtils.rm_rf File.join(TDiary.root, dir)
+		end
+  end
+
+	context "with find_by_month" do
+		let(:diary) { TDiary::DiaryContainer.find_by_month(conf, "200501") }
+		it { expect(diary).to be_a_kind_of TDiary::DiaryContainer }
+
+		describe "#conf" do
+			subject { diary.conf }
+			it { expect(subject).to be_a_kind_of TDiary::Configuration	}
+		end
+
+		describe "#diaries" do
+			subject { diary.diaries }
+			it { expect(subject).to be_a_kind_of Hash }
+			it { expect(subject.keys).to include('20050120') }
+			it { expect(subject.values).to include(be_a_kind_of TDiary::Style::WikiDiary) }
+		end
+	end
+
+	context "with find_by_day" do
+		let(:diary) { TDiary::DiaryContainer.find_by_day(conf, "20050120") }
+		it { expect(diary).to be_a_kind_of TDiary::DiaryContainer }
+
+		describe "#conf" do
+			subject { diary.conf }
+			it { expect(subject).to be_a_kind_of TDiary::Configuration	}
+		end
+
+		describe "#diaries" do
+			subject { diary.diaries }
+			it { expect(subject).to be_a_kind_of Hash }
+			it { expect(subject.keys).to include('20050120') }
+			it { expect(subject.values).to include(be_a_kind_of TDiary::Style::WikiDiary) }
+		end
+	end
+end
diff --git a/spec/core/plugin_spec.rb b/spec/core/plugin_spec.rb
index 848d222..efa97ea 100644
--- a/spec/core/plugin_spec.rb
+++ b/spec/core/plugin_spec.rb
@@ -379,6 +379,19 @@ describe TDiary::Plugin do
 			it { expect { subject }.to raise_error }
 		end
 	end
+
+	describe '#startup_proc' do
+		let (:proc) { lambda { "some plugin" } }
+		let (:app) { lambda { "tdiary application" } }
+		before do
+			@plugin.__send__(:add_startup_proc, &proc)
+		end
+
+		it 'add_startup_procで登録したブロックが実行されること' do
+			expect(proc).to receive(:call).with(app)
+			@plugin.__send__(:startup_proc, app)
+		end
+	end
 end
 
 # Local Variables:
diff --git a/spec/fixtures/tdiary.conf.gem b/spec/fixtures/tdiary.conf.gem
index 2ae4263..059c7bf 100644
--- a/spec/fixtures/tdiary.conf.gem
+++ b/spec/fixtures/tdiary.conf.gem
@@ -38,8 +38,8 @@ recent_list.rb
 "
 
 @options['dropdown_calendar.label'] = ''
- at options['makerss.file'] = 'public/index.rdf'
- at options['makerss.no_comments.file'] = 'public/no_comments.rdf'
+ at options['makerss.file'] = 'index.rdf'
+ at options['makerss.no_comments.file'] = 'no_comments.rdf'
 
 @options['spamfilter.bad_comment_patts'] = "(href=|casino|gambling|betting|fastsearch\\.eu\\.com|ganzao|poker|holdem|hold.em|roulette|drug|tramadol|viagra|fioricet|oxycontin|biaxin|aldara|business cards|home depot|slot.?machine|insurance|getblog2|video-game|Good site|internet-all\\.com|deai|tdfms|comu2|omaha)\r\n"
 @options['spamfilter.bad_ip_addrs'] = ""
diff --git a/spec/fixtures/tdiary.conf.rack b/spec/fixtures/tdiary.conf.rack
index 2ae4263..059c7bf 100644
--- a/spec/fixtures/tdiary.conf.rack
+++ b/spec/fixtures/tdiary.conf.rack
@@ -38,8 +38,8 @@ recent_list.rb
 "
 
 @options['dropdown_calendar.label'] = ''
- at options['makerss.file'] = 'public/index.rdf'
- at options['makerss.no_comments.file'] = 'public/no_comments.rdf'
+ at options['makerss.file'] = 'index.rdf'
+ at options['makerss.no_comments.file'] = 'no_comments.rdf'
 
 @options['spamfilter.bad_comment_patts'] = "(href=|casino|gambling|betting|fastsearch\\.eu\\.com|ganzao|poker|holdem|hold.em|roulette|drug|tramadol|viagra|fioricet|oxycontin|biaxin|aldara|business cards|home depot|slot.?machine|insurance|getblog2|video-game|Good site|internet-all\\.com|deai|tdfms|comu2|omaha)\r\n"
 @options['spamfilter.bad_ip_addrs'] = ""
diff --git a/spec/fixtures/tdiary.conf.secure b/spec/fixtures/tdiary.conf.secure
index 045f5ac..0dc4d90 100644
--- a/spec/fixtures/tdiary.conf.secure
+++ b/spec/fixtures/tdiary.conf.secure
@@ -37,8 +37,8 @@ my-ex.rb
 "
 
 @options['dropdown_calendar.label'] = ''
- at options['makerss.file'] = 'public/index.rdf'
- at options['makerss.no_comments.file'] = 'public/no_comments.rdf'
+ at options['makerss.file'] = 'index.rdf'
+ at options['makerss.no_comments.file'] = 'no_comments.rdf'
 
 @options['spamfilter.bad_comment_patts'] = "(href=|casino|gambling|betting|fastsearch\\.eu\\.com|ganzao|poker|holdem|hold.em|roulette|drug|tramadol|viagra|fioricet|oxycontin|biaxin|aldara|business cards|home depot|slot.?machine|insurance|getblog2|video-game|Good site|internet-all\\.com|deai|tdfms|comu2|omaha)\r\n"
 @options['spamfilter.bad_ip_addrs'] = ""
diff --git a/spec/fixtures/tdiary.conf.webrick b/spec/fixtures/tdiary.conf.webrick
index 8f17260..987ba19 100644
--- a/spec/fixtures/tdiary.conf.webrick
+++ b/spec/fixtures/tdiary.conf.webrick
@@ -39,8 +39,8 @@ recent_list.rb
 "
 
 @options['dropdown_calendar.label'] = ''
- at options['makerss.file'] = 'public/index.rdf'
- at options['makerss.no_comments.file'] = 'public/no_comments.rdf'
+ at options['makerss.file'] = 'index.rdf'
+ at options['makerss.no_comments.file'] = 'no_comments.rdf'
 
 @options['spamfilter.bad_comment_patts'] = "(href=|casino|gambling|betting|fastsearch\\.eu\\.com|ganzao|poker|holdem|hold.em|roulette|drug|tramadol|viagra|fioricet|oxycontin|biaxin|aldara|business cards|home depot|slot.?machine|insurance|getblog2|video-game|Good site|internet-all\\.com|deai|tdfms|comu2|omaha)\r\n"
 @options['spamfilter.bad_ip_addrs'] = ""
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 659e1c3..b877a33 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -26,10 +26,11 @@ RSpec.configure do |config|
 end
 
 class DummyTDiary
-	def conf
-		conf = DummyConf.new
-      conf.data_path = TDiary.root + "/tmp/"
-      conf
+	attr_accessor :conf
+
+	def initialize
+		@conf = DummyConf.new
+		@conf.data_path = TDiary.root + "/tmp/"
 	end
 
 	def ignore_parser_cache

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/tdiary.git



More information about the Pkg-ruby-extras-commits mailing list