pax_global_header00006660000000000000000000000064132571176350014524gustar00rootroot0000000000000052 comment=462a84ede31b214879ee042aabb5ccd909ab1672 tdiary-contrib-5.0.8/000077500000000000000000000000001325711763500144705ustar00rootroot00000000000000tdiary-contrib-5.0.8/.gitignore000066400000000000000000000000151325711763500164540ustar00rootroot00000000000000coverage pkg tdiary-contrib-5.0.8/.travis.yml000066400000000000000000000004321325711763500166000ustar00rootroot00000000000000language: ruby cache: bundler rvm: - 2.2.9 - 2.3.6 - 2.4.3 - 2.5.0 - ruby-head before_install: - gem update --system - gem update bundler script: bundle exec rake spec notifications: irc: "irc.freenode.org#tdiary" matrix: allow_failures: - rvm: ruby-head tdiary-contrib-5.0.8/Gemfile000066400000000000000000000000461325711763500157630ustar00rootroot00000000000000source 'https://rubygems.org' gemspec tdiary-contrib-5.0.8/Gemfile.lock000066400000000000000000000035441325711763500167200ustar00rootroot00000000000000PATH remote: . specs: tdiary-contrib (5.0.7) pushbullet_ruby tdiary GEM remote: https://rubygems.org/ specs: addressable (2.5.2) public_suffix (>= 2.0.2, < 4.0) coderay (1.1.2) concurrent-ruby (1.0.5) crack (0.4.3) safe_yaml (~> 1.0.0) diff-lcs (1.3) docile (1.1.5) emot (0.0.4) thor faraday (0.13.1) multipart-post (>= 1.2, < 3) fastimage (2.1.1) hashdiff (0.3.6) hikidoc (0.1.0) json (2.1.0) mail (2.7.0) mini_mime (>= 0.1.1) method_source (0.9.0) mime-types (3.1) mime-types-data (~> 3.2015) mime-types-data (3.2016.0521) mini_mime (1.0.0) multipart-post (2.0.0) pry (0.11.1) coderay (~> 1.1.0) method_source (~> 0.9.0) public_suffix (3.0.0) pushbullet_ruby (1.1.2) faraday (~> 0.13.0) mime-types rack (2.0.3) rake (12.1.0) rspec (3.6.0) rspec-core (~> 3.6.0) rspec-expectations (~> 3.6.0) rspec-mocks (~> 3.6.0) rspec-core (3.6.0) rspec-support (~> 3.6.0) rspec-expectations (3.6.0) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.6.0) rspec-mocks (3.6.0) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.6.0) rspec-support (3.6.0) safe_yaml (1.0.4) simplecov (0.15.1) docile (~> 1.1.0) json (>= 1.8, < 3) simplecov-html (~> 0.10.0) simplecov-html (0.10.2) sprockets (3.7.1) concurrent-ruby (~> 1.0) rack (> 1, < 3) tdiary (5.0.7) bundler (~> 1.3) emot fastimage hikidoc mail rack rake sprockets thor thor (0.20.0) webmock (3.0.1) addressable (>= 2.3.6) crack (>= 0.3.2) hashdiff PLATFORMS ruby DEPENDENCIES bundler (~> 1.3) pry rake rspec simplecov tdiary-contrib! webmock BUNDLED WITH 1.16.1 tdiary-contrib-5.0.8/README.en.md000066400000000000000000000006751325711763500163600ustar00rootroot00000000000000# tDiary contrib package This package include some utilities and plugins for tDiary. See documents in each directories. To use with tDiary, make "Gemfile.local" file on top of tDiary, and write a line like below: ``` gem 'tdiary-contrib' ``` ---- See licenses and copyrights in each theme files. If no license or copyright, it can be distoributed by GPL2, and it has a copyright below: ``` Copyright (c) 2005 TADA Tadashi ``` tdiary-contrib-5.0.8/README.md000066400000000000000000000013211325711763500157440ustar00rootroot00000000000000# tDiary contrib パッケージ このパッケージには、tDiaryに関係したいくつかのユーティリティやプラグ インが収録されています。ドキュメントはそれぞれのツールのディレクトリ に含まれています。 tDiaryで使う場合は、tDiaryのトップディレクトリに Gemfile.local という ファイルを作成し、以下のように記述します: ``` gem 'tdiary-contrib' ``` ---- 著作権およびライセンスは各テーマのファイルに記述してあるものに従いま すが、特に明記されていない場合、配布条件はGPL2、著作権は以下になりま す。 ``` Copyright (c) 2005 TADA Tadashi ``` tdiary-contrib-5.0.8/Rakefile000066400000000000000000000014721325711763500161410ustar00rootroot00000000000000require 'rubygems' require 'rake' require 'rake/clean' require 'rspec/core/rake_task' require 'bundler/gem_tasks' CLOBBER.include( "coverage" ) task :default => [:spec] desc 'Run the code in specs' RSpec::Core::RakeTask.new(:spec) do |t| t.pattern = "spec/**/*_spec.rb" end namespace :spec do if defined?(RCov) desc 'Run the code in specs with RCov' RSpec::Core::RakeTask.new(:report) do |t| t.pattern = "spec/**/*_spec.rb" t.rcov = true t.rcov_opts = IO.readlines(File.join('spec', 'rcov.opts')).map {|line| line.chomp.split(" ") }.flatten end else desc 'Run the code in specs with SimpleCov' task :report do ENV['COVERAGE'] = 'simplecov' Rake::Task["spec"].invoke end end end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/doc/000077500000000000000000000000001325711763500152355ustar00rootroot00000000000000tdiary-contrib-5.0.8/doc/en/000077500000000000000000000000001325711763500156375ustar00rootroot00000000000000tdiary-contrib-5.0.8/doc/en/filter/000077500000000000000000000000001325711763500171245ustar00rootroot00000000000000tdiary-contrib-5.0.8/doc/en/filter/spambayes.txt000066400000000000000000000001571325711763500216540ustar00rootroot00000000000000For detail English : http://www.hinet.mydns.jp/en/?SpamBayes Japanese : http://www.hinet.mydns.jp/?SpamBayes tdiary-contrib-5.0.8/doc/en/plugin.txt000066400000000000000000000000341325711763500176730ustar00rootroot00000000000000== tDiary contrib/plugin == tdiary-contrib-5.0.8/doc/en/style/000077500000000000000000000000001325711763500167775ustar00rootroot00000000000000tdiary-contrib-5.0.8/doc/en/style/hatena.txt000066400000000000000000000005431325711763500210020ustar00rootroot00000000000000== tDiary contrib/sytle/hatena_style == Hatena::Diary compatible style * How to install Copy hatena_style.rb into core/tdiary/ directory, where other styles are. After that, edit tdiary.conf and specify style as 'Hatena'. * TextFormattingRules Refer . All but expression are supported.tdiary-contrib-5.0.8/doc/en/style/markdown.txt000077500000000000000000000010461325711763500213660ustar00rootroot00000000000000== tDiary contrib/sytle/markdown_style == Markdown style * How to install require 'BlueCloth'. get & install from Copy markdown_style.rb into core/tdiary/ directory, where other styles are. After that, edit tdiary.conf and specify style as 'Markdown'. * TextFormattingRules Refer . ** tDiary original feature # =>

& section ## =>

### =>

{{my '20041004p01','test'}} => tDiary's plugin tdiary-contrib-5.0.8/doc/en/util.txt000066400000000000000000000000321325711763500173500ustar00rootroot00000000000000== tDiary contrib/util == tdiary-contrib-5.0.8/doc/ja/000077500000000000000000000000001325711763500156275ustar00rootroot00000000000000tdiary-contrib-5.0.8/doc/ja/filter/000077500000000000000000000000001325711763500171145ustar00rootroot00000000000000tdiary-contrib-5.0.8/doc/ja/filter/antirefspam.history.txt000066400000000000000000000054711325711763500236750ustar00rootroot00000000000000=begin ver 1.0 2005/06/26 ・更新履歴を別ファイルにした ・リンク元のチェックの有無を設定できるようにした (thanks to Kazuhiro NISHIYAMA) ・ブロックしたツッコミをログ(spamcomments)に残すようにした ・一度も設定を行っていない場合にエラーが起きていた不具合を修正 (thanks to Kazuhiro NISHIYAMA) ・"トップページURL" が相対指定になっているときに、チェックをすり抜けてしまうことがあった  不具合を修正 (thanks to Kazuhiro NISHIYAMA) ・"トップページURL" と同様に base_url でもチェックするようにした (thanks to Kazuhiro NISHIYAMA) ・"「リンク元置換リスト」にマッチするリンク元を信頼する" を有効にしており、かつリンク元の  URLの長さが50文字以上だった場合に、チェックをすり抜けてしまっていた不具合を修正   (thanks to Hiroshi Koyasu) ver 0.9 2004/11/24 ・リンク元置換リストにマッチするリンク元を信頼する機能を追加 (thanks to Shun-ichi TAHARA) ・コメントの制限に正規表現を使えるようにした ・HTTP.version_1_2 系を使えなかった場合に動作がおかしかった不具合を修正 ・spamips に出力される時刻の分/秒部分がおかしかったのを修正 ・その他エラーが起きにくいように処理を変更 ver 0.8 2004/11/15 ・プロキシーサーバーを指定する機能を追加 ・ver 0.6m〜0.71 で、Ruby 1.6 系でエラーが出ることがあった不具合を修正 ver 0.71 2004/11/12 ・ver 0.6m と ver 0.7 で、"信頼するリンク元" の指定が適用されなくなっていた不具合を修正 ver 0.7 2004/11/11 ・一部のアンテナで、設定によって更新日時が取れないことがあった問題に対処 ・コメントスパムに対処するため、コメントに制限をかける機能を追加 ver 0.6m 2004/11/07 (MoonWolf) ・ソースのインデント変更 ・if not→unlessへの書き換え等 ver 0.6 2004/11/07 ・トップページURL以外の許容するリンク先を指定できるようにした。 ・設定画面の言語リソースを分割した。 ver 0.5 2004/10/31 ・信頼できるURL に正規表現を使えるようにした ・safeurls, spaurls に、同一の URL が2つ連続で記録される問題に対処した(つもり) ver 0.4 2004/10/20 ・Ruby 1.8.2 (preview2) で動作しなかった不具合を修正 ・接続するポートを80からuri.portに変更 (thanks to MoonWolf) ver 0.3 2004/09/30 ・負荷を下げるための修正をちょっとだけ入れた ver 0.2 2004/09/27 ・信頼できるURLの一覧を設定画面から変更できるようにした ver 0.1 2004/09/15 ・最初のバージョン =end tdiary-contrib-5.0.8/doc/ja/filter/antirefspam.txt000066400000000000000000000075451325711763500222010ustar00rootroot00000000000000# # AntiRefererSpam Plugin # # version 1.0.0G (2005/08/01) # # Copyright (c) 2004-2005 T.Shimomura # You can redistribute it and/or modify it under GPL2. # Please use version 1.0.0 (not 1.0.0G) if GPL doesn't want to be forced on me. # ・これはなにをするもの? tDiary の「本日のリンク元」に、主に海外のアダルトサイトからの大量の アクセス履歴(リファラスパム)が残ってしまうのを防ぐためのプラグイン (厳密にはフィルター)です。 リンク元URLが指すページのHTMLに、日記のアドレスが含まれていなければ 不正なリンク元であるとみなします。 (今のところはこれだけの対処で99%近くをブロックできているみたいです) また、コメントスパムに対処するために、コメントに対して制限をかける 機能もついています。 ・インストール tDiary はバージョン 2.0.0 以降が必要です。2.1 系での動作は未確認。 tDiary をインストールしたディレクトリを $(tdiary_home) としたとき、 plugin/antirefspam.rb を $(tdiary_home)/plugin に、 plugin/ja/antirefspam.rb を $(tdiary_home)/plugin/ja に、 tdiary/filter/antirefspam.rb を $(tdiary_home)/tdiary/filter に、 それぞれコピーしてください。 本プラグインの古いバージョンがある場合は上書きしてかまいません。 古いバージョンで問題なく動作していた場合は、設定を変更する必要も ありません。 ・最低限必要な設定 tDiary の設定画面で、"Anti Referer Spam" の "許容するリンク先の指定" を確認してください。 設定画面に、"トップページURL" と "日記のURL" がカッコつきで書かれて いるはずです。これら以外にリンク先のURLとして許容したいものがあれば、 それを http〜で始まる絶対パス指定で書いてください。 また、tDiary をインストールしてあるサーバーが外部の HTTP サーバーに アクセスする際に HTTP プロキシを経由する必要がある場合は、その設定 も行ってください。 ・さらに細かい設定 [最低限必要な設定]のみでも効果があるはずですが、tDiary の設定画面で "Anti Referer Spam" の「信頼するリンク元の指定」を設定することで、 負荷が軽くなるはずです。 信頼するリンク元には、いくつかのサーチエンジンやアンテナを書いておく とよいでしょう。 詳細な書式については、設定画面に表示されるヒントを参照してください。 ・プラグインが生成するファイル このプラグインは、日記データが存在するディレクトリにAntiRefSpamFilter というディレクトリを作って、その下にいくつかのファイルを作成します。 safeurls 問題ないリンク元とみなした URL の一覧 spamurls 不正なリンク元とみなした URL の一覧 spamips 不正なリンク元とみなした IP の一覧 spamcomments 不正なコメントとみなしたコメントの一覧 safeurls に入るべき URL が、spamurls に登録されてしまった場合は、 その URL を、「信頼するリンク元の指定」で設定してください。 spamurls に入るべき URL が、safeurls に登録されてしまった場合は、 このプラグインを強化する必要があります。 ・このプラグインのバージョン ・日記の URL ・誤判定されてしまった URL を作者に教えてもらえれば対応するかもしれません。 ・FAQ 以下のページにある FAQ を適宜更新します。 http://www.netlife.gr.jp/redbug/diary/?date=20041018#p02 ・連絡先 T.Shimomura tdiary-contrib-5.0.8/doc/ja/filter/comment_key.ja.html000066400000000000000000000250351325711763500227120ustar00rootroot00000000000000 Comment-key Filter & Plugin

コメントキーフィルタ&プラグイン

はじめに

最近、所有者以外が書き込みできるタイプのページ(掲示板やコメント、トラックバックなど)に宣伝目的で大量のデータを書き込む、いわゆるスパム攻撃が激しくなっています。

特に流行のblogなどで被害が顕著ですが、同じように受信出来てしまうtDiaryでも同様のことが起こっています(対抗策が十分でない分、被害を受けやすくなっています)

そこで、tDiaryの持つフィルタ機能とプラグイン機能を利用して、これらのスパムのうちコメントスパムに対して対策を行うのが「コメントキーフィルタ&プラグイン」です。自動的にスパム送信を行うプログラムに対し効果を発揮します。

尚、本フィルタ&プラグインはsheepman発案のコメントスパム対策をフィルタとプラグインのみで実現したものです。

動作環境

動作に必要な条件は以下の通りです。

  • tDiary 2.0.0以上のシステム
  • 自前でプラグイン及びフィルタがインストール出来る

インストール・アンインストール

  • key.rb を tdiary/filter 下に配置します。
  • comment_key.rb を misc/plugin 下に、 ja/cooment_key.rb を misc/plugin/ja 下に配置します。
  • tDiary の設定ページにアクセスし、「プラグイン選択」にて comment_key.rb を有効にしてください。

これでインストールは完了です。フィルタとプラグインの両方をインストールしないと動作しませんので注意してください。

使い方

インストールが完了した時点で、設定ページのプラグインメニューに「コメントキーフィルタ」が表示されます。このページにまずは移動してください。

このページの「コメントキーフィルタを有効にする」のチェックを有効にすることで、とりあえずフィルタが有効になります。

その下にはキーの値を生成する際に使用する文字列を指定します。この文字列がキーの値の元になる文字列の一部となりますので、お好きな文字列を設定してください。この文字列が他の人の日記のものと同一だと、生成されるキーはやはり同一になってしまうのでご注意を。

その下にある「常に同一の鍵文字列を生成する」は通常は必要ありませんのでそのままにしておいてください。

以上が設定し終わると、このフィルタが機能します。

動作原理

本フィルタはsheepmanさんのコメントスパム対策を移植したものなので原理は同じですが、一応説明しておきます。

本プラグイン&フィルタはコメントフォームに対し、値として日付ごとに一意な文字列を持つキー "comment_key" を追加し*1、コメント書き込み時にこのキーとフィルタ内で生成した文字列を比較することで「日記表示時にそのページにあったコメントフォームから書き込んだのか?」を判定します。

判定がNGとなった場合はコメントの保存を行いません。

キーに設定された文字列は、元となるキー文字列のMD5チェックサムになっていて、元となるキー文字列を容易に推測されないようになっています。

*1 日付に関係なく同一の文字列を生成することも出来ますが突破されやすくなります。詳しくはFAQを参照

FAQ

Q1. 最新表示でコメントできない

もしかして、speed_comment.rbプラグインを使っていませんか?その場合、この本プラグイン&フィルタではコメント対象の日付が特定できません。その時は設定ページにある「常に同一の鍵文字列を生成する」のチェックを入れれば一応コメントできるようになります。

ただし、最新表示のみならず日付別表示でも常に同じ鍵文字列を生成するので多少コメントスパムの突破率は上がると思います。

おことわり

このフィルタ&プラグインはコメントスパムを防止する目的で作成されていますが、これを完全に防ぐことはできませんのでご了承ください。

例: 表示された日記のコメントフォームを解析したうえでスパム送信を行うようなプログラムなど

ライセンスなど

「コメントキーフィルタ&プラグイン」はGPLライセンスに従い公開・配布されるものです。

謝辞

このフィルタ&プラグインは、コメントスパムに困っていた時に見つけたsheepmanさんのコメントスパム対策を使いたいんだけど、本体に手を入れたくない。なんとかならないか…と考えて出来たものです。重要な部分はほぼそのまま使わせてもらっています。ありがとうございます。

これでなんとかコメントスパムが減ればいいな…。

履歴

2005/08/31 (Ver.0.5.0)
設定ページのカテゴリに対応(tDiary-2.1.2.20050826以降)
2005/04/17 (Ver.0.4.0)
常に同一の鍵文字列を生成するオプションを追加
2005/03/21 (Ver.0.3.0)
携帯からコメントが出来なくなっていたのを修正
2005/01/25 (Ver.0.2.0)
TrackBack及びPingbackの投稿にも適用されてしまっていたのを修正
2005/01/15 (Ver.0.1.0)
初版公開
Copyright © ハハハハ 2001-2005 All Right Reserved.
E-Mail: rin_ne-at-big.or.jp
tdiary-contrib-5.0.8/doc/ja/filter/spambayes.txt000066400000000000000000000001571325711763500216440ustar00rootroot00000000000000For detail Japanese : http://www.hinet.mydns.jp/?SpamBayes English : http://www.hinet.mydns.jp/en/?SpamBayes tdiary-contrib-5.0.8/doc/ja/plugin.txt000066400000000000000000000010631325711763500176660ustar00rootroot00000000000000== tDiary contrib/plugin == ここに収録されたプラグインは、 * 汎用性が低い * 国際化対応されていない(する意味がない) * tDiaryのバージョンに合わせたアップデートがされていない * tDiary本体または標準プラグインの動作環境から外れている 等の理由でプラグイン集への収録が見送られているものですが、 それぞれはとても有用なプラグインです。 個々の説明は、それぞれのプラグインのディレクトリに入っています。 tdiary-contrib-5.0.8/doc/ja/plugin/000077500000000000000000000000001325711763500171255ustar00rootroot00000000000000tdiary-contrib-5.0.8/doc/ja/plugin/add_bookmark.txt000066400000000000000000000026711325711763500223110ustar00rootroot00000000000000!概要 subtitleの右にソーシャルブックマークへのリンクを埋め込みます。 !使い方 プラグインフォルダに配置するだけで使用可能です。 プラグイン選択画面で有効に変更後、設定画面で埋め込みたいブックマークを選択します。 !ライセンス GPL2 !更新履歴 !!20070215 * サービスから MM/Memo を削除 * サービスに livedoor クリップ と Buzzurl を追加 !!20070109 * サニタイズキャンペーンに伴う修正 !!20050906 * HTML4.01 Strictに準拠 * セクションのURLをエスケープするように変更 !!20050901 * はてなブックマークのURLを修正 !!20050828 * add_subtitle_procに対応 * webshots,LiVEMARK,fc2ブックマークを削除 * 強制的にアイコンを使用するように設定 !!20050602 * はてなブックマークのアイコンの修正 * del.icio.usのURLの修正 !!20050601 * LiVEMARKに対応 * はてなブックマーク、del.icio.us、MM/Memoをアイコンで表示できるようにした。 !!20050528 * @confの値とdayモードの判定方法を変更 * 処理でイテレータを使うように変更 * 英語リソースの追加 * webshotsに対応 * fc2ブックマークに対応 !!20050525 * 初版公開 !参考情報 add_conf_procのチェックボックス処理についてはsearch_control.rb、body_enter_procについてはrandom_google.rbを参考にしました。 tdiary-contrib-5.0.8/doc/ja/plugin/category_to_tag.txt000066400000000000000000000016621325711763500230450ustar00rootroot00000000000000category_to_tag.rb - カテゴリをタグ風に表示します。 ※tDiary 2.1.3.20051012以降でのみ動作します。 ■使い方 インストールするだけで使えるようになります。日記モードのcategory.rbか、 BlogKitのblog-category.rbのいずれかと併用して使います。 なお、これらの併用プラグインよりもあとに読み込まれなければいけません。 プラグイン選択を使う場合には@options['sp.path']で指定したパスの最後の ディレクトリに入れるか、いっそプラグイン選択を使わずに、tDiary本体の pluginディレクトリに入れてしまうのがよいでしょう。 なお、タグの一覧はスタイルシートで「div.tags」を指定することで見栄え を変更できます。append-css.rbを使うといいでしょう。 例: div.day div.tags { text-align: right; font-size: 80%; } tdiary-contrib-5.0.8/doc/ja/plugin/cocoment.txt000066400000000000000000000013221325711763500214730ustar00rootroot00000000000000! 名前 coCommentプラグイン ! 概要 tDiaryをcoComment(http://www.cocomment.com/)に対応させるプラグイン !使い方 プラグインフォルダに入れるだけで動作します。 !ライセンス GPL2 !更新履歴 !!20070309 * mobile_agent? の使用方法を修正 !!20070213 * ケータイ端末からのアクセスは無視するようにした !!20070212 * IE7でのスクリプトエラーに対処(埋め込む Javascript を微調整) !!20070118 * postURLとpostTitleを取得するときにjavascriptを使わないようにした。 !!20070117 * tDiary-contrib 追加に伴って name 属性 comment-form を core に追加 * cocomment-fetchlet を追加 !!20060527 * 初版公開 tdiary-contrib-5.0.8/doc/ja/plugin/google_adsense.txt000066400000000000000000000020431325711763500226430ustar00rootroot00000000000000google_adsense.rb - Googe AdSenseのバナー広告を挿入するプラグイン プラグイン選択で選択し、日記のヘッダやフッタなど、任意の場所に以下の ように指定するだけで使えます。 <%= google_adsense %> バナーのサイズや色は、設定画面から変更可能です。 なお、配布されているgoogle_adsense.rbには、tDiary.Net 用のAdSense IDが書かれているので、このまま使うとtDiary.Netの広告収入 になってしまいます。自分のAdSense IDを使いたい場合には、ファイルの最 初の方にある以下の部分を、自分のIDに合わせて書き換えてください。 google_ad_client = "pub-3317603667498586" ~~~~~~~~~~~~~~~~~~~~この部分がID 2005-10-12追記 セクションターゲット(※)に対応しました。タグは日記の各日付の最初と最後に挿入 されます。 ※https://www.google.com/support/adsense/bin/answer.py?answer=23168&topic=371 tdiary-contrib-5.0.8/doc/ja/plugin/google_analytics.txt000066400000000000000000000005351325711763500232140ustar00rootroot00000000000000google_analytics.rb - Googe Analyticsの解析用コードを挿入する プラグイン選択で選択し、設定画面でProfile IDを指定すれば使えます。 Profile IDは、Analyticsのページでサイトを登録すると表示されるJavaScript中にある、 「UA-xxxxx-x」のうち、「xxxxx-x」の部分のことです。 tdiary-contrib-5.0.8/doc/ja/plugin/image_gps.txt000066400000000000000000000054421325711763500216260ustar00rootroot00000000000000image_gps.rb 機能 JPEGファイルに含まれるExif情報を解析し、各種撮影条件を表示します。 また、位置情報が含まれる場合、周辺地図ををポップアップ表示し、 Googleマップへのリンクを生成します。 前提条件 このPluginはimage.rbが導入されていることを前提としています。 image.rbを有効にしてください。また、image_ex.rbと共存することはできません。 ・ExifParserの導入 image_gps.rbはExifのパーサとして、ExifParserを使用しています。 以下のコマンドで導入できます。 #gem install exifparser ・Pluginのインストール image_gps.rbを適切な場所に配置してください。多言語用リソースは存在しません。 ・Google Maps API Keyの取得 ポップアップでの地図表示を行う場合は、 Google API console( https://code.google.com/apis/console ) にてStatic Maps APIのAPIキーを生成し、[設定]-[その他]-[image_gpsの設定]の Google Static Maps API Keyに生成されたAPIキーを設定してください。 地図のポップアップ表示機能を使用しない場合は、設定する必要はありません。 API Keyに関する詳細は、 https://developers.google.com/maps/documentation/staticmaps/?hl=ja も参照してください。 ・Exif情報の表示 [設定]-[その他]-[image_gpsの設定]のShow Exif Infoに値を設定することにより、 任意のExif情報を表示することができます。 Exifのタグ名をスペース区切りで記述してください 例) Model FocalLength FNumber ExposureTime ExposureBiasValue で、モデル名、焦点距離、F値、露出時間、露出補正が表示されます。 ・地図サイトへのリンクURLの設定 [設定]-[その他]-[image_gpsの設定]のMap Link URLにURLを記述することにより 任意の地図サービスサイトへのリンクを設定することができます。 主要なサービスについては、セレクタから選択することによりデフォルト値が設定されます。 未設定の場合はGoogleマップへのリンクが設定されます。 ・CSSの追加 写真と撮影条件をそれっぽく表示するために、CSSを設定する必要があります。 apend_css.rbを使用すると簡単にCSSを追加することができます。 参考に、作者が設定しているCSSを示します。 --ここから img.photo{ float:left; clear:both; } div.photo_detail{ clear:both; display:block; margin:0.5em; padding:0.5em; } img.map { outline:solid 5px gray; } --ここまで 使用方法 プラグインの書式は、image.rbと同じです。 制限事項 secureモードには対応していません。 image_ex.rbと同時に使用することはできません。 tdiary-contrib-5.0.8/doc/ja/plugin/livedoor_weather.txt000066400000000000000000000074701325711763500232400ustar00rootroot00000000000000! 概要 [[Weather Hacks - livedoor 天気情報|http://weather.livedoor.com/weather_hacks/]]を利用して日記に天気情報を埋め込むプラグイン !使い方 インストールしたら、設定画面で天気情報を取得する都市IDを設定してください。日記更新時に天気情報を取得します。 デフォルトでは日記の一日単位上部に天気情報を埋め込みます。 !!CSS div.lwws { text-align: right; font-size: 0.8em; } 上記のように設定すると見やすくなります。 !!キャッシュファイル 天気情報はxml形式で @cache_path/lwws/YYYYMMDD.xml というファイルに保存しています。 !!プラグイン呼び出し !!!lwws_today 今日の天気を表示します。 !!!lwws_tomorrow 明日の天気を表示します。 !!!lwws_dayaftertomorrow 明後日の天気を表示します。 !!!使い方 例えば(Wikiスタイルの例) ||今日||明日||明後日 ||{{lwws_today}}||{{lwws_tomorrow}}||{{lwws_dayaftertomorrow}} と書くと三日分の天気が表で表示されます。 サイドバーなどに使うとかっこいいかもしれません。 !ToDo *セキュア対応 *キャッシュの削除機能 *(他にあれば募集します) !ライセンス GPL2 !更新履歴 !!20070329 * open-uri の proxy を tdiary.conf から読み込むようにした !!20070214 * feed 生成時の出力を抑制 !!20070206 * NKFを使うのをやめて @conf.to_native を使うようにした * proxy の削除(trunk に追従) * to_native の第二引数として utf-8 を指定 !!20070109 * サニタイズキャンペーンに伴う修正 !!20060712 * lwws_getのバグ修正 !!20060709 * 設定更新時には強制的にキャッシュを再取得するように変更 !!20060702 * lwws_getの処理を変更 !!20060310 * 設定が保存されない不具合の修正 !!20060309 * キャッシュの自動更新を設定可能にする * 自動更新間隔を任意で設定可能にする ** 自動更新間隔を0にするとアクセスするたびにLWWSをたたくようになるので、適当に6-12くらいの数字を入れるのを推奨。 !!20060219 * 携帯閲覧時には画像を非表示 * 画像にtitle要素としてtelopエレメントを追加 !!20060213 * キャッシュファイルを6時間で更新するようにした。 * 任意の日付の天気を表示するlwwsメソッドを追加 !!20060212 * 新規メソッドとしてlwws_today,lwws_tomorrow,lwws_dayaftertomorrowを追加。プラグイン呼び出しとして、任意の場所に天気を表示します。 * 表示項目を変更機能の追加(設定画面)。 * アイコン表示機能の追加(設定画面)。 * 詳細へのリンクは天候に作成するようにした。(アイコンの場合はアイコンに設定) * convert_dateメソッドを追加。date_statusからYYYYMMDD形式の文字列を返します。 * 英語リソースをでっちあげた。(中国語は英語リソースの焼きまわし) * 「℃」を言語リソースに移動 * lwws_to_thmlメソッドで任意の日付を指定可能にした。 !!20060211 * lwws_getメソッドの引数をdateからdate_status(today,tomorrow,dayaftertomorrow)へと変更 * 設定画面の不要なエスケープを修正 * lwws_getメソッドでxmlを保存する時にYYYYMMDD形式になっていないバグを修正 !!20060210 * 最初のリリース * Uconvではなく、NKFを使ってUTF-8を扱うようにした。 * typo(というか、コピペ修正ミス)を直した。 * 最高気温、最低気温が存在する場合には表示するようにした。 * livedoor天気情報へのリンクを作るようにした。 * proxyの情報はamazon.proxyに統合した。tdiary-contrib-5.0.8/doc/ja/plugin/opensearch_ad.txt000066400000000000000000000006451325711763500224660ustar00rootroot00000000000000! 名前 OpenSearch Auto-Discovery プラグイン ! 概要 tDiaryをOpenSearch Auto-Discoveryに対応させるプラグイン !使い方 利用するには OpenSearch description XML をあらかじめ作成する必要があります。 サンプルファイルは http://www.opensearch.org/Specifications/OpenSearch/1.1 にあります。 !ライセンス GPL2 !更新履歴 !!20070117 * tDiary-contrib に追加 tdiary-contrib-5.0.8/doc/ja/plugin/playstore.txt000066400000000000000000000022311325711763500217060ustar00rootroot00000000000000playstore.rb 機能 GooglePlayのアプリ情報の表示及びリンクの生成を行います。 ・market_botの導入 GooglePlayのパーサとして、market_botを使用しています。 通常は以下のコマンドで導入できます。 #gem install market_bot -v 1.0.4 Rack環境の場合、Gemfile.localに以下を記述し、bundle installを実行してください。 gem 'market_bot','=1.0.4' ・Pluginのインストール playstore.rbを適切な場所に配置してください。多言語用リソースは存在しません。 ・使用方法 アプリIDを引数にしてプラグインを呼び出します。 アプリIDはアンドロイドアプリ一つ一つに設定されており、GoogleMapの場合は、 com.google.android.apps.maps です。 例) tDiary記法 <%= playstore 'com.google.android.apps.maps' %> wiki記法 {{playstore 'com.google.android.apps.maps'}} また、playstoreのかわりにplaystore_txtを呼び出すことにより テキストのみのリンクを生成することもできます。 ・制限事項 現状は英語版のGooglePlayの内容が表示され、リンク先も英語版になります。 tdiary-contrib-5.0.8/doc/ja/plugin/section_footer.txt000066400000000000000000000057341325711763500227210ustar00rootroot00000000000000! 概要 セクションの後ろにナビゲーションを追加するプラグイン。 以下の項目が追加されます。 * タグ(カテゴリ) * このエントリを含むはてなブックマーク * はてなブックマークコメント表示 * このエントリを含む del.icio.us * このエントリを含む livedoor クリップ * このエントリを含む Buzzurl * Permalink !注意事項 * blogkitでは動きません * セキュアな環境では動きません * category_to_tag.rb と同時に使うことはできません * Permalinkやアイコンは用途に合わせてadd_section_leave_procから適当に削ってください * 利用するには [[JSON library for Ruby|http://rubyforge.org/projects/json/]] が必要(lib 以下に配置済み) ! 動作事例 http://www.hsbt.org/diary/ !ライセンス GPL2 ! Changelog !!20070323 * del.icio.us Image API 使用時に ?aggregate を追加 !!20070322 * 画像取得API に対応 !!20070321 * JSON library for Ruby を追加 !!20070215 * アイコンを本家から持ってくるようにした !!20070212 * Buzzurl(http://buzzurl.jp) に対応した !!20070210 * Permalink 生成時の余計なエスケープをしないようにした !!20070206 * NKFを使うのをやめて @conf.to_native を使うようにした * to_native の第二引数として utf-8 を指定 !!20070205 * delicious JSON のキャッシュデータは @cache/delicious/YYYYMM に作成するようにした !!20070204 * 全面的に見直し、追加関係のリンクは生成しないようにした * del.icio.us の JSON API に対応、ブックマーク数を表示できるようにした * はてなブックマーク、livedoor クリップのブックマーク数画像表示APIに対応させた * 上記のAPIを使うようにしたため、まちゅさんのブックマークカウントキャッシュは使わないようにした !!20060107 * リンク追加処理をメソッドとして分離 !!20051229 * [[人気の日記プラグイン (はてなブックマーク + MM/Memo) - まちゅダイアリー (2005-12-27)|http://www.machu.jp/diary/20051227.html#p03]]の改造の取り込み !!20051227 * [[人気の日記プラグイン (はてなブックマーク) - まちゅダイアリー (2005-12-27)|http://www.machu.jp/diary/20051227.html#p02]]の改造の取り込み !!20051207 * 「このエントリを含むdel.icio.us」のリンクを追加 !!20051129 * 「このエントリを含むMM/Memo」のリンクを追加 !!20051124 * 「このエントリをdel.icio.usに追加」のリンクを追加 !!20051121 * 携帯からのアクセスの時には表示しないようにした。 !!20051114 * 最初のリリース ! 謝辞 このプラグインはたださんが作ったcategory_to_tag.rbとえろぺおさんによる[[tDiary の指定したセクションの permalink を求める|http://bigfield.ddo.jp/diary/20051026.html#p01]]をインスパイヤしました。ありがとうございました! tdiary-contrib-5.0.8/doc/ja/plugin/select_theme.txt000066400000000000000000000000511325711763500223230ustar00rootroot00000000000000See: http://arika.org/diary/20050421#p01 tdiary-contrib-5.0.8/doc/ja/style/000077500000000000000000000000001325711763500167675ustar00rootroot00000000000000tdiary-contrib-5.0.8/doc/ja/style/hatena.txt000066400000000000000000000010601325711763500207650ustar00rootroot00000000000000== tDiary contrib/sytle/hatena_style == はてなダイアリー互換スタイルです。 * インストール方法 添付の hatena_style.rb を他のスタイルと同様 core/tdiary/ に投入してください。 その後、 tdiary.conf でスタイルを 'Hatena' と指定すると有効になります * 記法 記法に関してははてなダイアリーのヘルプを参照してください。ここに記載されていることのうち、以外には対応しています。tdiary-contrib-5.0.8/doc/ja/style/markdown.txt000077500000000000000000000015121325711763500213540ustar00rootroot00000000000000== tDiary contrib/sytle/markdown_style == Markdownスタイルです。 * インストール方法 BlueClothが必要です。から入手してインストールしてください。 添付の markdown_style.rb を他のスタイルと同様 core/tdiary/ に投入してください。 その後、 tdiary.conf でスタイルを 'Markdown' と指定すると有効になります * 記法 記法に関してはMarkdown文法紹介を参照してください。 tDiaryでの拡張として#が

に##が

になります。セクションの区切りは#で行います。 tDiaryのプラグインを呼び出すには{{〜}}で囲みます。(例: {{my '20041004p01','test'}} ) tdiary-contrib-5.0.8/doc/ja/util.txt000066400000000000000000000007001325711763500173420ustar00rootroot00000000000000== tDiary contrib/util == ここに収録されたツールは、 * 汎用性が低い * 国際化対応されていない(する意味がない) * tDiaryのバージョンに合わせたアップデートがされていない 等の理由でcoreへの収録が見送られているものですが、 それぞれはとても有用なユーティリティです。 個々の説明は、それぞれのディレクトリに入っています。 tdiary-contrib-5.0.8/filter/000077500000000000000000000000001325711763500157555ustar00rootroot00000000000000tdiary-contrib-5.0.8/filter/antirefspam.rb000066400000000000000000000230051325711763500206130ustar00rootroot00000000000000# # antirefspam.rb # # Copyright (c) 2004-2005 T.Shimomura # You can redistribute it and/or modify it under GPL2. # Please use version 1.0.0 (not 1.0.0G) if GPL doesn't want to be forced on me. # require 'net/http' require 'uri' module TDiary module Filter class AntirefspamFilter < Filter # 有効にすると指定したファイルにデバッグ情報文字列を追記する def debug_out(filename, str) if $debug filename = File.join(@conf.data_path,"AntiRefSpamFilter",filename) File::open(filename, "a+") {|f| f.puts str } end end # str に指定された文字列が適切なリンク先を含んでいるかをチェック def isIncludeMyUrl(str) # str に日記のURLが含まれているかどうか base_url = @conf.base_url unless base_url.empty? if str.include? base_url return true end end # str にトップページURLが含まれているかどうか unless @conf.index_page.empty? if @conf.index_page.index(URI.regexp(%w[http https])) == 0 if str.include? @conf.index_page return true end end end # str に許容するリンク先が含まれているかどうか if (myurl = @conf['antirefspam.myurl']) && !myurl.empty? if str.include? myurl return true end #url = myurl.gsub("/", "\\/").gsub(":", "\\:") #exp = Regexp.new(url) exp = Regexp.union(myurl) if exp =~ str return true end end return false end def referer_filter(referer) conf_disable = @conf['antirefspam.disable'] != nil ? @conf['antirefspam.disable'].to_s : '' conf_checkreftable = @conf['antirefspam.checkreftable'] != nil ? @conf['antirefspam.checkreftable'].to_s : '' conf_trustedurl = @conf['antirefspam.trustedurl'] != nil ? @conf['antirefspam.trustedurl'].to_s : '' conf_proxy_server = @conf['antirefspam.proxy_server'] != nil && @conf['antirefspam.proxy_server'].size > 0 ? @conf['antirefspam.proxy_server'].to_s : nil conf_proxy_port = @conf['antirefspam.proxy_port'] != nil && @conf['antirefspam.proxy_port'].size > 0 ? @conf['antirefspam.proxy_port'].to_s : nil if conf_disable == 'true' or # リンク元チェックが有効ではない場合はスルーする referer == nil or # リンク元が無い referer.size <= 1 or # 一部のアンテナで更新時刻が取れなくなる問題に対応するため、リンク元が1文字以内の場合は許容 isIncludeMyUrl(referer) # 自分の日記内からのリンクは信頼する then return true end # "信頼できるURL" を1つずつ取り出してrefererと合致するかチェックする conf_trustedurl.each_line do |trusted| trusted.sub!(/\r?\n|\r/,'') next if trusted =~ /\A(\#|\s*)\z/ # #または空白で始まる行は読み飛ばす # まずは "信頼できる URL" が referer に含まれるかどうか if referer.include? trusted debug_out("trusted", trusted+" (include?) "+referer) return true end # 含まれなかった場合は "信頼できる URL" を正規表現とみなして再チェック begin #if referer =~ Regexp.new( trusted.gsub("/", "\\/").gsub(":", "\\:") ) if referer =~ Regexp.union( trusted ) debug_out("trusted", trusted+" (=~) "+referer) return true end rescue debug_out("error_config", "trustedurl: "+trusted) end end # URL置換リストを見る if conf_checkreftable == 'true' # "URL置換リスト" を1つずつ取り出してrefererと合致するかチェックする @conf.referer_table.each do |url, name| begin if /#{url}/i =~ referer && url != '^(.{50}).*$' debug_out("trusted", url+" (=~referer_table) "+referer) return true end rescue debug_out("error_config", "referer_table: "+url) end end end @work_path = File.join(@conf.data_path,"AntiRefSpamFilter") @spamurl_list = File.join(@work_path,"spamurls") # referer spam のリンク元一覧 @spamip_list = File.join(@work_path,"spamips") # referer spam のIP一覧 @safeurl_list = File.join(@work_path,"safeurls") # おそらくは問題のないリンク元一覧 # ディレクトリ/ファイルが存在しなければ作る unless File.exist? @work_path Dir::mkdir(@work_path) end unless File.exist? @spamurl_list File::open(@spamurl_list, "a").close end unless File.exist? @safeurl_list File::open(@safeurl_list, "a").close end uri = URI.parse(referer) temp_filename = File.join(@work_path,uri.host) # チェック時には対象のドメイン名を持った一時ファイルを作る begin File::open(temp_filename, File::RDONLY | File::CREAT | File::EXCL).close # 一度 SPAM URL とみなしたら以後は以後は拒否 spamurls = IO::readlines(@spamurl_list).map {|url| url.chomp } if spamurls.include? referer return false end # 一度 SPAM URL でないと判断したら以後は許可 safeurls = IO::readlines(@safeurl_list).map {|url| url.chomp } if safeurls.include? referer return true end # リンク元 URL の HTML を引っ張ってくる Net::HTTP.version_1_2 # おまじないらしい body = "" begin Net::HTTP::Proxy(conf_proxy_server, conf_proxy_port).start(uri.host, uri.port) do |http| if uri.path == "" response, = http.get("/") else response, = http.get(uri.request_uri) end body = response.body end # body に日記の URL が含まれていなければ SPAM とみなす unless isIncludeMyUrl(body) File::open(@spamurl_list, "a+") {|f| f.puts referer } File::open(@spamip_list, "a+") {|f| f.puts [@cgi.remote_addr, Time.now.utc.strftime("%Y/%m/%d %H:%M:%S UTC")].join("\t") } return false else File::open(@safeurl_list, "a+") {|f| f.puts referer } end rescue # エラーが出た場合は @spamurl_list に入れない&リンク元にも入れない return false end rescue StandardError, TimeoutError # 現在チェック中なら、今回はリンク元に勘定しない return false ensure begin File::delete(temp_filename) rescue end end return true end def log_spamcomment( diary, comment ) @work_path = File.join(@conf.data_path,"AntiRefSpamFilter") @spamcomment_list = File.join(@work_path,"spamcomments") # comment spam の一覧 # ディレクトリ/ファイルが存在しなければ作る unless File.exist? @work_path Dir::mkdir(@work_path) end unless File.exist? @spamcomment_list File::open(@spamcomment_list, "a").close end File::open(@spamcomment_list, "a+") {|f| f.puts "From: "+comment.name+" <"+comment.mail+">" f.puts "To: "+diary.date.to_s f.puts "Date: "+comment.date.to_s f.puts comment.body f.puts ".\n\n" } end def comment_filter( diary, comment ) # ツッコミに日本語(ひらがな/カタカナ)が含まれていなければ不許可 if @conf['antirefspam.comment_kanaonly'] != nil if @conf['antirefspam.comment_kanaonly'].to_s == 'true' unless comment.body =~ /[ぁ-んァ-ヴー]/ log_spamcomment( diary, comment ) return false end end end # ツッコミの文字数が指定した上限以内でないなら不許可 maxsize = @conf['antirefspam.comment_maxsize'].to_i if maxsize > 0 unless comment.body.size <= maxsize log_spamcomment( comment ) return false end end # NGワードが1つでも含まれていたら不許可 if @conf['antirefspam.comment_ngwords'] != nil ngwords = @conf['antirefspam.comment_ngwords'] ngwords.to_s.each_line do |ngword| ngword.sub!(/\r?\n|\r/,'') if comment.body.downcase.include? ngword.downcase log_spamcomment( comment ) return false end # 含まれなかった場合は "NGワード" を正規表現とみなして再チェック begin if comment.body =~ Regexp.new( ngword, Regexp::MULTILINE ) log_spamcomment( comment ) return false end rescue debug_out("error_config", "comment_ngwords: "+ngword) end end end return true end end end end tdiary-contrib-5.0.8/filter/commentkey.rb000066400000000000000000000014461325711763500204620ustar00rootroot00000000000000# # comment_key.rb: Comment-key filter Ver.0.5.0 # included TDiary::Filter::CommentKeyFilter class # # caution: # * This filter must use together plugin 'comment_key.rb'. # # see: # http://www20.big.or.jp/~rin_ne/soft/tdiary/commentkey.htm # # Copyright (c) 2005 Hahahaha # Distributed under the GPL # module TDiary module Filter class CommentkeyFilter < Filter def comment_filter( diary, comment ) return true unless @conf['comment_key.enable'] return true if /^(?:TrackBack|Pingback)$/ =~ comment.name require 'digest/md5' keyprefix = @conf['comment_key.prefix'] || 'tdiary' vkey = Digest::MD5.hexdigest(keyprefix + (@conf['comment_key.nodate'] == 'true' ? "" : @cgi.params['date'][0])) vkey == @cgi.params['comment_key'][0] end end end end tdiary-contrib-5.0.8/filter/commentsize.rb000066400000000000000000000005741325711763500206450ustar00rootroot00000000000000# # comment_size.rb: included TDiary::Filter::CommentSizeFilter class # module TDiary module Filter class CommentsizeFilter < Filter def comment_filter( diary, comment ) return false if comment.body.size > @conf['comment.size'] true end def referer_filter( referer ) true end end end end tdiary-contrib-5.0.8/filter/hidecomment.rb000066400000000000000000000004561325711763500206030ustar00rootroot00000000000000# # ref. http://www.cozmixng.org/retro/projects/tdiary/ticket/60 # module TDiary::Filter class HidecommentFilter < Filter def comment_filter( diary, comment ) comment.show = false # ツッコミを非表示にするが true # spam扱いにはしない end end end tdiary-contrib-5.0.8/filter/iplookup.rb000066400000000000000000000030751325711763500201510ustar00rootroot00000000000000# # iplookup.rb: included TDiary::Filter::IplookupFilter class # # # Copyright (c) 2008 SHIBATA Hiroshi # Distributed under the GPL2 # require 'resolv' module TDiary module Filter class IplookupFilter < Filter def iplookup_init if @conf.options.include?('iplookup.ip.list') @iplookup_ip_list = @conf.options['iplookup.ip.list'] else @iplookup_ip_list = "bsb.spamlookup.net\nopm.blitzed.org\n" + "niku.2ch.net\ndnsbl.spam-champuru.livedoor.com" end end def black_ip?( address ) chance = 2 ip = address.gsub(/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/, '\4.\3.\2.\1') @iplookup_ip_list.split(/\n+/).each do |dnsbl| begin address = Resolv.getaddress( "#{ip}.#{dnsbl}" ) return true rescue Resolv::ResolvTimeout if chance > 0 chance -= 1 retry end rescue Resolv::ResolvError rescue Exception end end return false end def comment_filter( diary, comment ) iplookup_init return false if black_ip?( @cgi.remote_addr ) return true end def referer_filter( referer ) iplookup_init return false if black_ip?( @cgi.remote_addr ) return true end end end end tdiary-contrib-5.0.8/filter/plugin/000077500000000000000000000000001325711763500172535ustar00rootroot00000000000000tdiary-contrib-5.0.8/filter/plugin/antirefspam.rb000066400000000000000000000052671325711763500221230ustar00rootroot00000000000000# # antirefspam.rb # # Copyright (c) 2004-2005 T.Shimomura # You can redistribute it and/or modify it under GPL2. # Please use version 1.0.0 (not 1.0.0G) if GPL doesn't want to be forced on me. # add_conf_proc( 'antirefspam', 'Anti Referer Spam', 'security') do if @mode == 'saveconf' @conf['antirefspam.disable'] = @cgi.params['antirefspam.disable'][0] @conf['antirefspam.trustedurl'] = @cgi.params['antirefspam.trustedurl'][0] @conf['antirefspam.checkreftable'] = @cgi.params['antirefspam.checkreftable'][0] @conf['antirefspam.myurl'] = @cgi.params['antirefspam.myurl'][0] @conf['antirefspam.proxy_server'] = @cgi.params['antirefspam.proxy_server'][0] @conf['antirefspam.proxy_port'] = @cgi.params['antirefspam.proxy_port'][0] @conf['antirefspam.comment_kanaonly'] = @cgi.params['antirefspam.comment_kanaonly'][0] @conf['antirefspam.comment_maxsize'] = @cgi.params['antirefspam.comment_maxsize'][0] @conf['antirefspam.comment_ngwords'] = @cgi.params['antirefspam.comment_ngwords'][0] end <<-HTML #{@antispamref_html_antispamref}

#{@antispamref_html_myurl}

#{@antispamref_html_proxy}

server : port :

#{@antispamref_html_trustedurl}

#{@antispamref_html_comment}

#{@antispamref_html_comment_maxsize}

#{@antispamref_html_comment_ngwords}

#{@antispamref_html_faq} HTML end tdiary-contrib-5.0.8/filter/plugin/commentkey.rb000066400000000000000000000030601325711763500217520ustar00rootroot00000000000000# # comment_key.rb: Comment-key plugin Ver.0.5.0 # # functions: # * add "comment_key" key in comment form. # # caution: # * This plugin must use together filter 'comment_key.rb'. # # see: # http://www20.big.or.jp/~rin_ne/soft/tdiary/commentkey.htm # # Copyright (c) 2005 Hahahaha # Distributed under the GPL # alias :orig_comment_name_label :comment_name_label alias :orig_comment_name_label_short :comment_name_label_short def comment_name_label comment_key( orig_comment_name_label ) end def comment_name_label_short comment_key( orig_comment_name_label_short ) end def comment_key( label ) return label unless @conf['comment_key.enable'] require 'digest/md5' keyprefix = @conf['comment_key.prefix'] || 'tdiary' vkey = Digest::MD5.hexdigest(keyprefix + (@conf['comment_key.nodate'] == 'true' ? "" : @date.strftime( '%Y%m%d' ))) %Q!\n#{label}! end # configuration if TDIARY_VERSION >= '2.1.2.20050826' then add_conf_proc( 'comment_key', @comment_key_label_conf, 'security' ) do comment_key_conf end else add_conf_proc( 'comment_key', @comment_key_label_conf ) do comment_key_conf end end def comment_key_conf if @mode == 'saveconf' then @conf['comment_key.enable'] = 'true' == @cgi.params['comment_key_enable'][0] ? true : false @conf['comment_key.prefix'] = @cgi.params['comment_key_prefix'][0] @conf['comment_key.nodate'] = @cgi.params['comment_key_nodate'][0] end @conf['comment_key.prefix'] = 'tdiary' unless @conf['comment_key.prefix'] comment_key_conf_html end tdiary-contrib-5.0.8/filter/plugin/commentsize.rb000066400000000000000000000005661325711763500221440ustar00rootroot00000000000000add_conf_proc( 'comment_size' , @comment_size_conf, 'security') do if @mode == 'saveconf' then @conf['comment.size'] = @cgi.params['comment.size'][0] end @conf['comment.size'] = 0 unless @conf['comment.size'] result = <<-HTML

#{@comment_size}

#{@comment_size_desc}

Bytes

HTML end tdiary-contrib-5.0.8/filter/plugin/en/000077500000000000000000000000001325711763500176555ustar00rootroot00000000000000tdiary-contrib-5.0.8/filter/plugin/en/iplookup.rb000066400000000000000000000003601325711763500220430ustar00rootroot00000000000000# en/iplookup.rb # # Copyright (c) 2005 SHIBATA Hiroshi # Distributed under the GPL @iplookup_label = 'IP Blacklist' @iplookup_ip_label = 'IP Blacklist Services' @iplookup_ip_label_desc = 'List of IP Blacklist Services' tdiary-contrib-5.0.8/filter/plugin/en/spambayes.rb000066400000000000000000000032401325711763500221650ustar00rootroot00000000000000# Copyright (C) 2007, KURODA Hiraku # You can redistribute it and/or modify it under GPL2. class SpambayesConfig module Res module_function def title "Bayes filter" end def check_comment "Check comments" end def check_referer "Check referers" end def token_list(type) "#{type}-token list" end def rebuild_db "Rebuild database" end def use_bayes_filter "Use Bayes-filter" end def use_filter_to_referer "Use Bayes-filter to referer" end def save_error_log "Save error-log at cache-directory" end def threshold "Threshold" end def receiver_addr "Mail TO" end def register_ham "Register as HAM" end def register_spam "Register as spam" end def comment_processed "Comments processed" end def token "token" end def probability(type) "#{type}-probability" end def score_in_db(type) "score in #{type}-database" end def execute_after_click_OK "Execute if you click OK" end def registered_as(type) "registered as #{type}" end def rebuild_db_after_click_OK "Rebuild database from corpus if you click OK" end def processed_referer "Referer processed" end def token_of_referer "token of referer" end def mail "Mail address" end def posted_host_addr "Host-IP from which comment posted" end def name "Name" end def referer "Referer" end def url_in_comment "URL in comment" end def comment_body_and_keyword "Text in comment and Keyword in search-engine's referer" end def no_token_exist "(No token exists)" end def spam_rate "Rate of spam" end end end tdiary-contrib-5.0.8/filter/plugin/iplookup.rb000066400000000000000000000022641325711763500214460ustar00rootroot00000000000000# iplookup.rb # # Copyright (c) 2005 SHIBATA Hiroshi # Distributed under the GPL # if TDIARY_VERSION >= '2.1.2.20050825' then add_conf_proc( 'iplookup', @iplookup_label, 'security' ) do iplookup_conf_proc end else add_conf_proc( 'iplookup', @iplookup_label ) do iplookup_conf_proc end end def iplookup_conf_proc if @mode == 'saveconf' then if @cgi.params['iplookup.ip.list'] && @cgi.params['iplookup.ip.list'][0] @conf['iplookup.ip.list'] = @cgi.params['iplookup.ip.list'][0] else @conf['iplookup.ip.list'] = nil end if @cgi.params['iplookup.safe_ip.list'] && @cgi.params['iplookup.safe_ip.list'][0] @conf['iplookup.safe_ip.list'] = @cgi.params['iplookup.safe_ip.list'][0] else @conf['iplookup.safe_ip.list'] = nil end end # initialize DNSBL list @conf['iplookup.ip.list'] = "bsb.spamlookup.net\nopm.blitzed.org\nniku.2ch.net" unless @conf['iplookup.ip.list'] result = <<-HTML

#{@iplookup_ip_label}

#{@iplookup_ip_label_desc}

HTML end tdiary-contrib-5.0.8/filter/plugin/ja/000077500000000000000000000000001325711763500176455ustar00rootroot00000000000000tdiary-contrib-5.0.8/filter/plugin/ja/antirefspam.rb000066400000000000000000000071401325711763500225050ustar00rootroot00000000000000# # antirefspam.rb # # Copyright (c) 2004-2005 T.Shimomura # You can redistribute it and/or modify it under GPL2. # Please use version 1.0.0 (not 1.0.0G) if GPL doesn't want to be forced on me. # @antispamref_html_antispamref = <<-TEXT

リンク元に制限をかける

リファラスパムを防ぐために、refererに対して制限をかけることができます。

TEXT @antispamref_html_disable = <<-TEXT refererに対して制限をかけない TEXT @antispamref_html_myurl = <<-TEXT

許容するリンク先の指定

トップページURL(#{h(if @conf.index_page.empty? then "未設定" else @conf.index_page end)})と日記のURL(#{h(if @conf.base_url.empty? then "不明" else @conf.base_url end)})以外にリンク先として許容するURLを指定します。 正規表現も利用可能です。

TEXT @antispamref_html_proxy = <<-TEXT

HTTPプロキシーサーバーの指定

このプラグインは、リンク元に指定された HTTP サーバーにアクセスして、リンク元のHTML を取得します。 このアクセスに HTTP プロキシを経由する必要がある場合は以下で設定してください。
例 : server : proxy.foo.com port : 8080

TEXT @antispamref_html_trustedurl = <<-TEXT

信頼するリンク元の指定

ヒント:

  • 1行に1つの URL を書いてください。
  • \#で始まる行、空行は無視されます。
  • "信頼するリンク元" は2段階に分けてチェックされます。
    • 1回目は、正規表現を使っていないものとしてチェックします。書かれた URL がリンク元に 含まれてさえいれば、信頼するリンク元とみなします。
      例 : リンク元が http://www.foo.com/bar/ や http://www.foo.com/baz/ の場合、 URL には http://www.foo.com/ と書けばよい。
    • 2回目は、正規表現を使っているものとしてチェックします。この場合、URL中 の : (コロン) と / (スラッシュ) は 内部でエスケープされます。正規表現を使う場合、リンク元の全体にマッチする必要がある点に注意してください。
      例 : リンク元が http://aaa.foo.com/bar/ や http://bbb.foo.com/baz/ の場合、 URL には http://\\w+\.foo\.com/.* と書けばよい。

TEXT @antispamref_html_checkreftable = <<-TEXT 「リンク元置換リスト」にマッチするリンク元を信頼する。 TEXT @antispamref_html_comment = <<-TEXT

ツッコミに制限をかける

コメントスパムを防ぐために、コメントに対して様々な制限をかけることができます。

TEXT @antispamref_html_comment_kanaonly = <<-TEXT ツッコミにひらがな/カタカナが含まれていない場合は拒否する。 TEXT @antispamref_html_comment_maxsize = <<-TEXT ツッコミ文字列の長さの上限を指定(文字数) TEXT @antispamref_html_comment_ngwords = <<-TEXT 以下の単語がツッコミに含まれていた場合は拒否する
(正規表現も利用可能です。正規表現は複数行モードで動作します。 正規表現の先頭と末尾に \/ はつけないでください)
TEXT @antispamref_html_faq = <<-TEXT

FAQ

その他、最新のFAQは http://www.netlife.gr.jp/redbug/diary/?date=20041018\#p02 を参照してください。

TEXT tdiary-contrib-5.0.8/filter/plugin/ja/commentkey.rb000066400000000000000000000016731325711763500223540ustar00rootroot00000000000000# Japanese resource of comment_key.rb # # Copyright (c) 2005 Hahahaha # Distributed under the GPL # @comment_key_label_conf = 'コメントキーフィルタ' def comment_key_conf_html <<-"HTML"

#{@comment_key_label_conf}

コメントキーフィルタを有効にする

コメントキーフィルタのために使用される鍵の先頭文字列を指定します。なお、この文字列はMD5にてエンコードされるため、出力HTML内に直接表現されることはありません。

常に同一の鍵文字列を生成する

HTML end tdiary-contrib-5.0.8/filter/plugin/ja/commentsize.rb000066400000000000000000000004221325711763500225250ustar00rootroot00000000000000if /conf/ =~ @mode then @comment_size_conf = 'コメントサイズ制限' @comment_size_desc = 'ツッコミの最大サイズをByteで指定してください。日本語は一文字で約3Bytesとなります。' @comment_size = 'コメントサイズ制限' end tdiary-contrib-5.0.8/filter/plugin/ja/iplookup.rb000066400000000000000000000004501325711763500220330ustar00rootroot00000000000000# ja/iplookup.rb # # Copyright (c) 2008 SHIBATA Hiroshi # Distributed under the GPL2 @iplookup_label = 'IPブラックリスト' @iplookup_ip_label = 'IPブラックリストサービス' @iplookup_ip_label_desc = 'IPブラックリストサービスの一覧' tdiary-contrib-5.0.8/filter/plugin/ja/spambayes.rb000066400000000000000000000036501325711763500221620ustar00rootroot00000000000000# Copyright (C) 2007, KURODA Hiraku # You can redistribute it and/or modify it under GPL2. class SpambayesConfig module Res module_function def title "Bayesフィルタ" end def check_comment "ツッコミを確認する" end def check_referer "リンク元を確認する" end def token_list(type) "#{type}トークン一覧" end def rebuild_db "データベースの再構築" end def use_bayes_filter "Bayesフィルタを使う" end def use_filter_to_referer "リンク元にBayesフィルタを使う" end def save_error_log "エラーログをキャッシュディレクトリに保存" end def threshold "閾値" end def receiver_addr "宛先メールアドレス" end def register_ham "ハムとして登録" end def register_spam "スパムとして登録" end def comment_processed "ツッコミを処理しました" end def token "トークン" end def probability(type) "#{type}率" end def score_in_db(type) "#{type}データベースでのスコア" end def execute_after_click_OK "OKを押すと実行します" end def registered_as(type) "#{type}として登録しました" end def rebuild_db_after_click_OK "OKを押すとコーパスからデータベースを再作成します" end def processed_referer "リンク元を処理しました" end def token_of_referer "リンク元のトークン" end def mail "メールアドレス" end def posted_host_addr "投稿ホストのIP" end def name "名前" end def referer "リンク元" end def url_in_comment "コメント中のURL" end def comment_body_and_keyword "コメント本文と検索リンク元のキーワード" end def no_token_exist "(トークンがありません)" end def spam_rate "スパム率" end end end tdiary-contrib-5.0.8/filter/plugin/spambayes.rb000066400000000000000000000326351325711763500215750ustar00rootroot00000000000000# Copyright (C) 2007, KURODA Hiraku # You can redistribute it and/or modify it under GPL2. require "bayes" add_conf_proc("spambayes", SpambayesConfig::Res.title, "security") do spambayes_conf_proc end def spambayes_conf_proc SpambayesConfig.new(@mode, @cgi, @conf).show end module ::TDiary module Filter class Filter; end class SpambayesFilter < Filter class Comment; end class Referer; end end end end class SpambayesConfig Comment = ::TDiary::Filter::SpambayesFilter::Comment Referer = ::TDiary::Filter::SpambayesFilter::Referer RE_FILENAME_BODY = /\d+[a-z0-9]+/ RE_SPAM_FILE = /^S#{RE_FILENAME_BODY}$/o RE_HAM_FILE = /^H#{RE_FILENAME_BODY}$/o RE_DOUBT_FILE = /^D#{RE_FILENAME_BODY}$/o RE_FILENAME = /^[SHD]#{RE_FILENAME_BODY}$/o def initialize(mode, cgi, conf) @mode = mode @cgi = cgi @conf = conf filter_path = conf.filter_path || "#{PATH}/tdiary/filter" require "#{filter_path}/spambayes" unless ::TDiary::Filter::SpambayesFilter.const_defined?(:Misc) extend ::TDiary::Filter::SpambayesFilter::Misc ::TDiary::Filter::SpambayesFilter::Misc.conf = conf bayes_filter end def save_mode? @mode=="saveconf" end def add_spam(data) t = data.token return if t.empty? bayes_filter.spam << t if t.any?{|i| !bayes_filter.spam.include?(i)} bayes_filter.spam << t while (bayes_filter.estimate(t)||0.0) <= threshold @db_updated = true end def add_ham(data, with_add_comment=false) t = data.token return if t.empty? bayes_filter.ham << t if t.any?{|i| !bayes_filter.ham.include?(i)} bayes_filter.ham << t while (bayes_filter.estimate(t)||1.0) > threshold @db_updated = true add_comment(data) if data.is_a?(Comment) && with_add_comment end def save_db bayes_filter.save if @db_updated @db_updated = false end def show case @cgi.params["sb_mode"][0] when "show_comment" show_all_comment when "process_comment" process_comment + show_config when "show_ham_tokens" show_db_token_list(:ham) when "show_spam_tokens" show_db_token_list(:spam) when "confirm_ham" confirm(:ham) when "confirm_spam" confirm(:spam) when "register_ham" register(:ham) + show_config when "register_spam" register(:spam) + show_config when "confirm_rebuild_db" confirm_rebuild_db when "rebuild_db" rebuild_db + show_config when "show_all_referer" show_all_referer when "process_referer" process_referer + show_config when "show_comment_token" show_comment_token when "show_referer_token" show_referer_token when "save_config" save_config + show_config else show_config end end def save_config return "" unless save_mode? r = "" @conf[conf_use] = @cgi.params[conf_use][0] || nil @conf[conf_for_referer] = @cgi.params[conf_for_referer][0] || nil @conf[conf_log] = @cgi.params[conf_log][0] || nil @conf[conf_mail] = @cgi.params[conf_mail][0] || nil cpt_ham = (@cgi.params[conf_threshold_ham][0]||threshold_ham).to_f cpt_spam = (@cgi.params[conf_threshold][0]||threshold).to_f if 0
  • #{Res.check_comment}
  • #{Res.check_referer}
  • #{Res.token_list("Spam")}
  • #{Res.token_list("Ham")}
  • #{Res.rebuild_db}

    • #{Res.use_bayes_filter} :
    • #{Res.use_filter_to_referer} :
    • #{Res.save_error_log} :
    • #{Res.threshold}: 0 <= Ham < <= Doubt <= < Spam <= 1.0
    • #{Res.receiver_addr} :
    EOT end def show_comment(data, name=nil) r = < #{data.name}(#{data.mail}) / #{data.date}
    #{CGI.escapeHTML(data.body)}
    EOT rate = bayes_filter.estimate(data.token) r << "#{Res.spam_rate} : #{rate}" if rate if name r << <


    token EOT end r end def show_all_comment r = "" spam_list = Dir["#{bayes_cache}/S*"].map{|i| File.basename(i)}.sort ham_list = Dir["#{bayes_cache}/H*"].map{|i| File.basename(i)}.sort doubt_list = Dir["#{bayes_cache}/D*"].map{|i| File.basename(i)}.sort r << "

    Ham

      " ham_list.each do |f| data = Comment.load(data_file(f)) r << "
    • \n#{show_comment(data, f)}\n
    • \n" end r << "

    Doubt

      " doubt_list.each do |f| data = Comment.load(data_file(f)) r << "
    • \n#{show_comment(data, f)}\n
    • \n" end r << "

    Spam

      " spam_list.each do |f| data = Comment.load(data_file(f)) r << "
    • \n#{show_comment(data, f)}\n
    • \n" end r << "
    " r << "" r << "" r end def data_file(f) raise "InvalidData: #{CGI.escapeHTML(f)}" unless /^O?[SHD]\d+[a-z0-9]+$/ =~ f "#{bayes_cache}/#{f}" end def register_data(f, type) require "fileutils" case type when :ham prefix = "H" when :spam prefix = "S" else prefix = "D" end if RE_FILENAME =~ f new_name = "#{corpus_path}/#{prefix}#{f[/^[SHD](#{RE_FILENAME_BODY})$/o, 1]}" FileUtils.mv(data_file(f), new_name) end end def process_comment return "" unless save_mode? @cgi.params.each do |k, v| next unless k=~/^[SHD]\d+[a-z0-9]+$/ v = v[0] data = Comment.load(data_file(k)) case v when "spam" add_spam(data) when "ham" add_ham(data, k !~ RE_HAM_FILE) else raise "INVALID VALUE:#{k}" end register_data(k, v=="spam" ? :spam : :ham) end @cgi.params.keys.select{|k| k=~/\Aprocess_[SHD]\d+[a-z0-9]+\z/}.each do |k| FileUtils.rm_f(data_file(k[/^process_(.*)$/, 1])) end save_db "

    #{Res.comment_processed}


    " end def comment_date(data) data.diary_date.strftime("%Y%m%d") end def add_comment(data) comment = ::TDiary::Comment.new(data.name, data.mail, data.body, data.date) cgi = Struct.new(:params, :referer, :request_method, :remote_addr, :script_name).new("", "", "", "", "") cgi.params = Hash.new{[]}.update("name"=>[data.name], "mail"=>[data.mail], "body"=>[data.body], "date"=>[comment_date(data)]) cgi.remote_addr = data.remote_addr io = force_filtering do @conf.io_class.new(::TDiary::TDiaryComment.new(cgi, "day.rhtml", @conf)) end io.transaction(data.diary_date) do |diaries| diary = diaries[comment_date(data)] if diary without_filtering do diary.add_comment(comment) end ::TDiary::TDiaryBase::DIRTY_COMMENT else ::TDiary::TDiaryBase::DIRTY_NONE end end end def token_table(label, tokens, prefix) return "" if tokens.empty? r = "

    #{label}

    \n" r << "" bf = bayes_filter tokens = tokens.sort do |a, b| a=prefix+a b=prefix+b sa = bf.score(a) || 1.1 sb = bf.score(b) || 1.1 sa==sb ? a<=>b : sb<=>sa end tokens.each do |t| pt = prefix+t r << "\n" end r << "
    #{Res.token}#{Res.probability("Spam")}
    #{t}#{bf[pt] ? format("%10.4f", bf[pt]) : "Doubt"}
    " end def show_token_list(token_list) tl = {} token_list.uniq.each do |t| k = case t when /^A (.*)/ :addr when /^M (.*)/ :mail when /^N (.*)/ :name when /^R (.*)/ :referer when /^U (.*)/ :url else :body end tl[k] ||= [] tl[k] << ($1 ? $1 : t) end r = "" [[:body, Res.comment_body_and_keyword, ""], [:referer, Res.referer, "R "], [:url, Res.url_in_comment, "U "], [:name, Res.name, "N "], [:mail, Res.mail, "M "], [:addr, Res.posted_host_addr, "A "]].each do |i| key, label, prefix = i r << token_table(label, tl[key]||[], prefix) end if r.strip.empty? Res.no_token_exist else r end end def show_db_token_list(type) r = "

    #{Res.token_list(type.to_s.upcase)}

    " r << "

    #{bayes_filter.class.name}

    " show_token_list(bayes_filter.send(type).keys) end def confirm(type) r = "

    " id = @cgi.params["comment_id"][0] case type when :ham r << Res.register_ham when :spam r << Res.register_spam end r << "

    " r << "" r << "" r << "

    #{Res.execute_after_click_OK}

    " r << "
    " << show_comment(Comment.load(data_file(id))) end def register(type) return "" unless save_mode? id = @cgi.params["comment_id"][0] data = Comment.load(data_file(id)) r = "" case type when :ham add_ham(data, true) when :spam add_spam(data) end r << Res.registered_as(type) save_db register_data(id, type) r << show_comment(data) << "
    " end def confirm_rebuild_db <#{Res.rebuild_db_after_click_OK}

    EOT end def rebuild_db return "NotSave" unless save_mode? bayes_filter(true).save r = "" spams = Dir["#{corpus_path}/S*"] hams = Dir["#{corpus_path}/H*"] all = [] while spams.size>0 and hams.size>0 all << spams.shift all << hams.shift end all.concat(spams) all.concat(hams) all.each do |f| n = f[/^#{Regexp.escape("#{corpus_path}/")}(.*)$/, 1] next unless RE_FILENAME =~ n data = Comment.load(f) case n[/^./] when "S" add_spam(data) when "H" add_ham(data) end end PStore.new(referer_corpus).transaction(true) do |db| (db["spam"]||[]).each do |ref| add_spam(ref) end (db["ham"]||[]).each do |ref| add_ham(ref) end end bayes_filter.save "" end def show_referer_list(referer_list, type) h = "r"+type[0, 1] r = "

    #{type.upcase}

    \n" r << "
      \n" referer_list.uniq.sort.each do |l| r << "
    • #{l.viewable_html}
      \n" r << "from #{l.remote_addr}
      \n" rate = bayes_filter.estimate(l.token) r << "#{Res.spam_rate} : #{rate}
      \n" if rate r << "
      \n" r << "
      \n" r << "token" r << "
    • " end r << "
    \n" r << "\n" end def show_all_referer r = "" spams = Referer.load_list(referer_cache("spam")) hams = Referer.load_list(referer_cache("ham")) doubts = Referer.load_list(referer_cache("doubt")) r << show_referer_list(hams, "ham") r << show_referer_list(spams, "spam") r << show_referer_list(doubts, "doubt") r << "\n" end def process_referer return "" unless save_mode? spams = [] hams = [] @cgi.params.each do |k, v| next unless k=~/^r([shd])(.*)$/ type = $1 referer = Referer.from_html($2) v = v[0] case v when "spam" add_spam(referer) if type=~/^[dh]/ spams << referer when "ham" add_ham(referer) if type=~/^[ds]/ hams << referer end end bayes_filter.save ["ham", "spam", "doubt"].each do |k| size = (@cgi.params[k[0, 1]+"size"][0]||"0").to_i Referer.truncate_list(referer_cache(k), size) end PStore.new(referer_corpus).transaction do |db| spams.concat(db['spam']||[]) hams.concat(db['ham']||[]) db["spam"] = spams.uniq db["ham"] = hams.uniq end "

    #{Res.processed_referer}


    " end def show_comment_token c = Comment.load(data_file(@cgi.params["comment_id"][0])) show_token_list(c.token) end def show_referer_token ref = Referer.from_html(@cgi.params["referer"][0]||"") url = CGI.escapeHTML(ref.referer) "#{url}"+show_token_list(ref.token) end end tdiary-contrib-5.0.8/filter/plugin/zh/000077500000000000000000000000001325711763500176745ustar00rootroot00000000000000tdiary-contrib-5.0.8/filter/plugin/zh/iplookup.rb000066400000000000000000000003601325711763500220620ustar00rootroot00000000000000# zh/iplookup.rb # # Copyright (c) 2005 SHIBATA Hiroshi # Distributed under the GPL @iplookup_label = 'IP Blacklist' @iplookup_ip_label = 'IP Blacklist Services' @iplookup_ip_label_desc = 'List of IP Blacklist Services' tdiary-contrib-5.0.8/filter/rblcheck.rb000066400000000000000000000014311325711763500200560ustar00rootroot00000000000000# rblcheck.rb # Copyright (c) 2004 MoonWolf # Distributed under the GPL # # options: # @options['rblcheck.list'] = [ # 'bl.moonwollf.com', # RBL list # ] require 'socket' module TDiary module Filter class RblcheckFilter < Filter alias :_filter :referer_filter alias :_filter :comment_filter private def _filter( *args ) rev_addr = @cgi.remote_addr.split(".").reverse.join(".") @conf['rblcheck.list'].each {|rbl| addr = "#{rev_addr}.#{rbl}" begin host = Socket.getaddrinfo(addr, "http")[0][3] case host when "127.0.0.2" return false end rescue SocketError end } true end end end end tdiary-contrib-5.0.8/filter/spambayes.rb000066400000000000000000000305411325711763500202710ustar00rootroot00000000000000# Copyright (C) 2007, KURODA Hiraku # You can redistribute it and/or modify it under GPL2. require "bayes" module TDiary::Filter class SpambayesFilter < Filter class TokenList < Bayes::TokenList def initialize super(Bayes::CHARSET::UTF8) end end module Misc @@without_filtering = nil @@force_filtering = nil def without_filtering? @@without_filtering || (@conf[conf_use]||"").size==0 end def without_filtering orig = @@without_filtering @@without_filtering = true yield ensure @@without_filtering = orig end def force_filtering?; @@force_filtering; end def force_filtering orig = @@force_filtering @@force_filtering = true yield ensure @@force_filtering = orig end @@conf = nil def self.conf=(conf) @@conf ||= conf end def self.conf; @@conf; end def self.to_native(s) s ? @@conf.to_native(CGI.unescape(s)).gsub(/[\x00-\x20]/, " ") : "" end PREFIX = "spambayes" def conf_filter; "#{PREFIX}.filter"; end def conf_mail; "#{PREFIX}.mail"; end def conf_threshold; "#{PREFIX}.threshold"; end def conf_threshold_ham; "#{PREFIX}.threshold_ham"; end def conf_use; "#{PREFIX}.use"; end def conf_log; "#{PREFIX}.log"; end def conf_for_referer; "#{PREFIX}.for_referer"; end def cache_path @conf.cache_path || "#{@conf.data_path}cache" end def bayes_cache Dir.mkdir(cache_path) unless File.exist?(cache_path) r = "#{cache_path}/bayes" Dir.mkdir(r) unless File.exist?(r) r end def referer_cache(key) "#{bayes_cache}/referer_#{key}.log" end def referer_corpus "#{corpus_path}/referer.db" end def unescape_referer(referer) @conf.to_native(CGI.unescape(referer)).gsub(/[\x00-\x20]+/, " ") end def debug_log "#{bayes_cache}/debug.log" end def debug(*args) open(debug_log, "a") do |f| f.puts(*args) end end def corpus_path r = "#{bayes_cache}/corpus" Dir.mkdir(r) unless File.exist?(r) r end def bayes_db "#{@conf.data_path}/bayes.db" end def bayes_filter(reset=false) if reset @bayes_filter = nil File.delete(bayes_db) if File.exist?(bayes_db) end case @conf[conf_filter] when /graham/i @bayes_filter ||= Bayes::PaulGraham.new(bayes_db, Bayes::CHARSET::UTF8) else @bayes_filter ||= Bayes::PlainBayes.new(bayes_db, Bayes::CHARSET::UTF8) end convert_to_utf8 unless @bayes_filter.charset==Bayes::CHARSET::UTF8 @bayes_filter end def convert_to_utf8 require "bayes/convert" require "kconv" @bayes_filter.convert(Bayes::CHARSET::UTF8, Bayes::CHARSET::EUC) @bayes_filter.save comments = [] ["S", "H", "D"].each do |c| comments.concat(Dir["#{bayes_cache}/#{c}*"]) end ["S", "H"].each do |c| comments.concat(Dir["#{corpus_path}/#{c}*"]) end comments.each do |f| Comment.load(f).convert_to_utf8.save(f) end end def threshold (@conf[conf_threshold]||"0.95").to_f end def threshold_ham (@conf[conf_threshold_ham]||"0.05").to_f end def url(path=nil) if /^https?:\/\// =~ (path||"") path else File.join(@conf.base_url, (path||"")) end end def index_url url(@conf.index) end def update_url url(@conf.update) end end class Comment attr_reader :name, :date, :mail, :body, :remote_addr, :diary_date def self.load(file_name) r = nil open(file_name) do |f| f.flock(File::LOCK_SH) r = Marshal.load(f) end raise "NoData" unless r.is_a?(self) r end def initialize(comment, cgi) @name = comment.name || "" @date = comment.date || Time.now @mail = comment.mail || "" @body = comment.body || "" @remote_addr = cgi.remote_addr || "" d = cgi.params['date'][0] || Time.now.strftime("%Y%m%d") @diary_date = Time::local(*d.scan(/^(\d{4})(\d\d)(\d\d)$/)[0]) + 12*60*60 end def convert_to_utf8 @name = @name.kconv(Kconv::UTF8, Kconv::EUC) @body = @body.kconv(Kconv::UTF8, Kconv::EUC) self end def save(filename) open(filename, "w") do |f| f.flock(File::LOCK_SH) f.rewind Marshal.dump(self, f) end end def digest Digest::MD5.hexdigest([@name, @date, @mail, @body, @remote_addr, @diary_date].join) end RE_URL = %r[(?:https?|ftp)://[a-zA-Z0-9;/?:@&=+$,\-_.!~*\'()%]+] def token r = TokenList.new if @name.empty? r.push("", "N") else r.add_message(@name, "N") end r.add_mail_addr(@mail, "M") b = @body.dup b.gsub!(RE_URL) do |m| r.add_url(m, "U") "" end r.add_message(b) r.add_host(@remote_addr, "A") r end def cache_name @date.strftime("%Y%m%d%H%M%S")+digest end end class Referer @@specials = {} def self.load_list(f) r = [] open(f) do |f| f.flock(File::LOCK_SH) r << Marshal.load(f) until f.eof? end r rescue [] end def self.truncate_list(fn, size) return unless File.exist?(fn) open(fn, "a+") do |f| f.flock(File::LOCK_EX) buff = [] buff << Marshal.load(f) until f.eof? buff.slice!(0, size) f.truncate(0) buff.each do |i| Marshal.dump(i, f) end end end def self.from_link(link) if /^(.*?)_(.*)$/=~link addr = $1 url = $2 new(CGI.unescape(url), addr ? CGI.unescape(addr) : nil) end end def self.from_html(html) if /^(.*?)_(.*)$/=~html addr = $1 url = $2 new(CGI.unescapeHTML(url), addr ? CGI.unescapeHTML(addr) : nil) end end attr_reader :referer, :remote_addr def initialize(referer, remote_addr = nil) @referer = referer @remote_addr = remote_addr end def hash @referer.hash end def eql?(dst) (self.class == dst.class) and (@referer == dst.referer) end def to_s Misc.to_native(@referer) end def to_html CGI.escapeHTML(@remote_addr||"") + "_" + CGI.escapeHTML(@referer) end def to_link CGI.escape(@remote_addr||"") + "_" + CGI.escape(@referer) end def <=>(o) to_s <=> o.to_s end def split_url base, request, anchor = @referer.scan(/^(.*?)(?:\?(.*?)(?:\#(.*))?)?$/)[0] end def token if l=special? m = l+"_token" if respond_to?(m) r = send(m) else r = special_token(@@specials[l]) end else r = TokenList.new base, request, anchor = split_url r.add_url(base, "R") r.add_message(Misc.to_native(request)) if request r.add_message(Misc.to_native(anchor)) if anchor end r.add_host(@remote_addr, "A") if @remote_addr r end def viewable_html if l=special? m = l+"_html" if respond_to?(m) r = send(m) else r = special_html(@@specials[l]) end else r = to_s end CGI.escapeHTML(r||"") end def special? r = @@specials.find do |n, a| a[0] =~ @referer end r ? r[0] : false end def self.special(name, regexp, label = nil) name = name.to_s label ||= name.capitalize @@specials[name.to_s] = [regexp, label] end def special_html(special) re, label = special "#{label}: " + Misc.to_native(@referer[re, 1]) end def special_token(special) re = special[0] r = TokenList.new r.add_message(Misc.to_native(@referer[re, 1])) r end RE_QUERY_SEP = /[&;]|$/ RE_QUERY_HEAD = /\?(?:.*#{RE_QUERY_SEP})?/o RE_GOOGLE_HOSTS = /.*\.google\.(?:(?:co\.)?[a-z]{2}|com(?:\.[a-z]{2})?)/o RE_GOOGLE = %r[^https?://#{RE_GOOGLE_HOSTS}/.*#{RE_QUERY_HEAD}(?:as_)?q=(.*?)#{RE_QUERY_SEP}]o special :google, RE_GOOGLE RE_GOOGLE_IP = /209\.85\.\d{3}\.\d{1,3}|72\.14\.\d{3}\.\d{1,3}/ RE_GOOGLE_CACHE = %r[^https?://#{RE_GOOGLE_IP}/search#{RE_QUERY_HEAD}q=cache:[^:]+:(.*?)(?:(?:\+|\s+)(.*?))?#{RE_QUERY_SEP}]o special :google_cache, RE_GOOGLE_CACHE def google_cache_token r = TokenList.new RE_GOOGLE_CACHE =~ @referer ref = "http://#{CGI.unescape($1)}" words = $2 r.add_url(ref, "R") r.add_message(Misc.to_native(words)) end def google_cache_html RE_GOOGLE_CACHE =~ @referer ref = "http://#{CGI.unescape($1)}" words = $2 "Google(Cache): #{ref} #{Misc.to_native(words)}" end RE_EZ_GOOGLE = %r[^https?://ezsch\.ezweb\.ne\.jp/search/ezGoogleMain\.php#{RE_QUERY_HEAD}query=(.*?)#{RE_QUERY_SEP}]o special :ez_google, RE_EZ_GOOGLE, "Google(ezweb)" RE_EZWEB = %r[^https?://ezsch\.ezweb\.ne\.jp/.*?#{RE_QUERY_HEAD}query=(.*?)#{RE_QUERY_SEP}] special :ezweb, RE_EZWEB, "EZweb" RE_GOO = %r[^http://search\.goo\.ne\.jp/.*?#{RE_QUERY_HEAD}MT=(.*?)#{RE_QUERY_SEP}]o special :goo, RE_GOO RE_NIFTY = %r[^https?://search\.nifty\.com/.*?#{RE_QUERY_HEAD}Text=(.*?)#{RE_QUERY_SEP}]o special :nifty, RE_NIFTY RE_LIVESEARCH = %r[^https?://search\.live\.com/.*?#{RE_QUERY_HEAD}q=(.*?)#{RE_QUERY_SEP}]o special :livesearch, RE_LIVESEARCH, "Live Search" RE_BIGLOBE = %r[^https?://.*search\.biglobe\.ne\.jp/.*?#{RE_QUERY_HEAD}q=(.*?)#{RE_QUERY_SEP}]o special :biglobe, RE_BIGLOBE RE_MSN = %r[^https?://search\.msn\.co\.jp/.*?#{RE_QUERY_HEAD}q=(.*?)#{RE_QUERY_SEP}]o special :msn, RE_MSN, "MSN" RE_INFOSEEK = %r[^https?://search\.www\.infoseek\.co\.jp/.*?#{RE_QUERY_HEAD}qt=(.*?)#{RE_QUERY_SEP}]o special :infoseek, RE_INFOSEEK RE_HATENA_B = %r[^https?://b\.hatena\.ne\.jp/[^/]+/(.*?)(?:\?.*)?$]o special :hatena_b, RE_HATENA_B, "Hatena::Bookmark" RE_YAHOO = %r[^https?://.*\.yahoo\.co(?:m|\.[a-z]{2})/.*?#{RE_QUERY_HEAD}p=(.*?)#{RE_QUERY_SEP}]o special :yahoo, RE_YAHOO RE_BAIDU = %r[^https?://.*\.baidu\.jp/.*?#{RE_QUERY_HEAD}wd=(.*?)#{RE_QUERY_SEP}]o special :baidu, RE_BAIDU end include Misc def initialize( cgi, conf ) super Misc.conf = conf end def ham?(tokens) e = bayes_filter.estimate(tokens) || (threshold_ham+threshold)/2 case when ethreshold false else nil end end def comment_filter(diary, comment) return false if force_filtering? return true if without_filtering? r = true data = Comment.new(comment, @cgi) base_url = "#{update_url}?conf=spambayes;mode=conf;sb_mode=" spam_url = "Register as spam : #{base_url}confirm_spam" ham_url = "Register as ham : #{base_url}confirm_ham" case ham?(data.token) when true r = true tag = "HAM" url = spam_url when false r = false tag = "SPAM" url = ham_url else r = false tag = "DOUBT" url = "#{spam_url}\n#{ham_url}" end cn = tag[0,1]+data.cache_name data.save("#{bayes_cache}/#{cn}") url.gsub!(/(\n|\z)/){";comment_id=#{cn}#$1"} require "socket" require "time" subject = "#{tag}:#{data.body.gsub(/\n/, " ")}".scan(/.{1,8}/e).map{|b| @conf.to_mail(b)} subject = subject.map{|i| "=?ISO-2022-JP?B?"+[i].pack("m").chomp+"?="}.join("\n ") addr = @conf[conf_mail] body = < To: #{addr} Date: #{Time.now.rfc2822} Message-Id: Subject: #{subject} MIME-Version: 1.0 Content-Type: text/plain; charset="iso-2022-jp" Content-Transfer-Encoding: 7bit Errors-To: #{addr} X-Mailer: tDiary #{TDIARY_VERSION} X-URL: http://www.tdiary.org/ Filter treated comment as #{tag}. #{url} ---- Target: #{index_url}/?date=#{data.diary_date.strftime("%Y%m%d")} Name: #{data.name} Mail: #{data.mail} IP : #{data.remote_addr} Body:------ #{data.body.scan(/.{1,40}/).map{|l| @conf.to_mail(l)}.join("\n")} EOT begin plugin = TDiary::Plugin.new("conf"=>@conf, "mode"=>"comment", "diaries"=>nil, "cgi"=>@cgi, "years"=>nil, "cache_path"=>cache_path, "date"=>data.diary_date, "comment"=>comment, "last_modified"=>nil) plugin.comment_mail(body, addr) if /^.*@.*/ =~ addr rescue ArgumentError end r rescue Exception => e debug "---- comment_filter ----", Time.now, e.message, e.class.name, e.backtrace.join("\n") r end def referer_filter(referer) return true if without_filtering? || !(@conf[conf_for_referer]) r = true referer = Referer.new(referer, ENV["REMOTE_ADDR"]) token = referer.token case ham?(token) when true key = "ham" when false r = false key = "spam" else r = false key = "doubt" end open(referer_cache(key), "a") do |f| f.flock(File::LOCK_SH) Marshal.dump(referer, f) end r rescue Exception => e debug "---- referer_filter ----", Time.now, e.message, e.class.name, e.backtrace.join("\n") raise end end end tdiary-contrib-5.0.8/filter/spamlookup.rb000066400000000000000000000013631325711763500204770ustar00rootroot00000000000000# # spamlookup.rb: included TDiary::Filter::SpamlookupFilter class # require 'resolv' require 'uri' module TDiary module Filter class SpamlookupFilter < Filter def black_domain?( domain ) begin Resolv.getaddress( "#{domain}.rbl.bulkfeeds.jp" ) return true rescue end false end def black_url?( body ) URI.extract( body, %w[http] ) do |url| domain = URI.parse( url ).host.sub( /\.$/, '' ) return true if black_domain?( domain ) end false end def comment_filter( diary, comment ) !black_url?( comment.body ) end def referer_filter( referer ) !black_url?( referer ) end end end end tdiary-contrib-5.0.8/io/000077500000000000000000000000001325711763500150775ustar00rootroot00000000000000tdiary-contrib-5.0.8/io/dbi_io/000077500000000000000000000000001325711763500163245ustar00rootroot00000000000000tdiary-contrib-5.0.8/io/dbi_io/ChangeLog000066400000000000000000000013621325711763500201000ustar00rootroot000000000000002007-02-18 sasasin * dbi_io.rb: delete restore_referer and store_referer impl. * tdiary_table.sql: add referervolatile table definition. * plugin/refererDbiIO.rb: add new plugin for referer. 2005-12-27 Kazuhiko * dbi_io.rb (store_referer): ignore invalid referers. 2005-12-20 Kazuhiko * dbi_io.rb.fast (transaction): lock whole transaction exlusively. (store_referer): update different entries only. 2005-12-11 Kazuhiko * dbi_io.rb (store_comment): delete possible duplicate comments. (restore_referer): quote diary_id. (calendar): fix a bug in a multi-user environment. 2005-12-10 Kazuhiko * dbi_io.rb: code cleanup. tdiary-contrib-5.0.8/io/dbi_io/README.ja000077500000000000000000000025651325711763500176100ustar00rootroot00000000000000!dbi_io データベース名('tDiaryDB') データベースに接続するユーザ データベースに接続するパスワード 作者。今後、マルチユーザ対応するときに使います。 !!データベースの作成 !!! PostgreSQLの場合 $ createdb -h -U -E EUC-JP Password: $ psql -h -U -f tdiary_table.sql Password: CREATE DATABASE !!tdiary.confの編集 #require 'tdiary/pstoreio' #@io_class = TDiary::PStoreIO require 'tdiary/dbi_io' @io_class = TDiary::DbiIO #-- dbi_ioの場合の設定 -- @dbi_driver_url = 'dbi:Pg:' # URLを設定します。 @dbi_user = '' # DBのアカウント @dbi_passwd = ' # DBのパスワード @dbi_author = '' # author !! プラグインのインストール リンク元の保存・表示のために、プラグインを以下のいずれかの 方法でインストールする必要があります (1) tdiary.confの@option['sp.path']に、このディレクトリに あるpluginのパスを追加し、設定画面からrefererDbiIO.rb を有効にする。 (2) tDiaryのインストール先にあるpluginディレクトリに、 plugin/refererDbiIO.rbをコピーする。 tdiary-contrib-5.0.8/io/dbi_io/dbi_io.rb000077500000000000000000000137701325711763500201110ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # dbi_io.rb: DBI IO for tDiary 2.x. # # NAME dbi_io # # DESCRIPTION tDiary向けDBI用IOクラス # 詳細は、README.jaを参照してください # # Copyright (C) 2003 ma2tak # (C) 2004 moonwolf # (C) 2005 Kazuhiko # (C) 2012 hsbt # # You can distribute this under GPL. require 'tdiary/io/base' require 'tempfile' require 'dbi' module TDiary module CommentIO def restore_comment(diaries) begin diaries.each do |date, diary_object| @dbh.select_all("SELECT diary_id, name, mail, last_modified, visible, no, author, comment FROM commentdata WHERE author=? AND diary_id=? ORDER BY no;", @dbi_author, date) do |diary_id, name, mail, last_modified, visible, no, author, comment| comment = Comment.new(name, mail, comment, Time.at(last_modified.to_i)) comment.show = visible diary_object.add_comment(comment) end end rescue Errno::ENOENT end end def store_comment(diaries) begin diaries.each do |date, diary| no = 0 diary.each_comment(diary.count_comments(true)) do |com| no += 1 param = [com.name, com.mail, com.date.to_i, com.visible?, com.body, @dbi_author, date, no] sth = @dbh.execute("UPDATE commentdata SET name=?, mail=?, last_modified=?, visible=?, comment=? WHERE author=? AND diary_id=? AND no=?;", *param) if sth.rows == 0 @dbh.execute("INSERT INTO commentdata (name, mail, last_modified, visible, comment, author, diary_id, no) VALUES (?,?,?,?,?,?,?,?);", *param) end end @dbh.execute("DELETE FROM commentdata where author=? AND diary_id=? AND no>?", @dbi_author, date, no) end rescue Errno::ENOENT end end end module RefererIO def restore_referer(diaries) return end def store_referer(diaries) return end end class DbiIO < BaseIO include CommentIO include RefererIO def initialize(tdiary) @tdiary = tdiary @dbi_url = tdiary.conf.dbi_driver_url @dbi_user = tdiary.conf.dbi_user @dbi_passwd = tdiary.conf.dbi_passwd @dbi_author = tdiary.conf.dbi_author || 'default' @dbh = DBI.connect(@dbi_url, @dbi_user, @dbi_passwd) load_styles end class << self def load_cgi_conf(conf) end def save_cgi_conf(conf, result) end end # # block must be return boolean which dirty diaries. # def transaction(date) File.open("#{Dir.tmpdir}/dbi_io.lock", 'w') do |file| file.flock(File::LOCK_EX) @dbh.transaction do date_string = date.strftime("%Y%m%d") diaries = {} cache = @tdiary.restore_parser_cache(date, 'defaultio') if cache diaries.update(cache) else restore(date_string, diaries) restore_comment(diaries) restore_referer(diaries) end @old_referers = {} diaries.each_pair{|k,v| @old_referers[k] = v.instance_variable_get('@referers').dup} dirty = yield(diaries) if iterator? store(diaries) if dirty & TDiary::TDiaryBase::DIRTY_DIARY != 0 store_comment(diaries) if dirty & TDiary::TDiaryBase::DIRTY_COMMENT != 0 store_referer(diaries) if dirty & TDiary::TDiaryBase::DIRTY_REFERER != 0 if dirty or not cache @tdiary.store_parser_cache(date, 'defaultio', diaries) end end end end def calendar calendar = Hash.new{|hash, key| hash[key] = []} sql = "SELECT year, month FROM diarydata WHERE author=? GROUP BY year, month ORDER BY year, month;" @dbh.select_all(sql, @dbi_author) do |year, month| calendar[year] << month end calendar end def diary_factory(date, title, body, style = 'tDiary') styled_diary_factory(date, title, body, style) end # HNF移行ツールのため、作成 def restore_diary(date) diaries = {} restore(date, diaries, false) diaries end private def restore(date, diaries, month=true) sql = "SELECT diary_id, title, last_modified, visible, body, style FROM DiaryData WHERE author='#{@dbi_author}' and diary_id='#{date}';" if month == true if /(\d\d\d\d)(\d\d)(\d\d)/ =~ date sql = "SELECT diary_id, title, last_modified, visible, body, style FROM DiaryData WHERE author='#{@dbi_author}' AND year='#{$1}' AND month='#{$2}';" end end @dbh.select_all(sql) do |diary_id, title, last_modified, visible, body, style| style = 'tdiary' if style.nil? || style.empty? style = style.downcase diary = eval("#{style(style)}::new(diary_id, title, body, Time::at(last_modified.to_i))") diary.show(visible) diaries[diary_id] = diary end end def store(diaries) diaries.each do |date, diary| # save diaries if /(\d\d\d\d)(\d\d)(\d\d)/ =~ date year = $1 month = $2 day = $3 end visible = (diary.visible? ? "true" : "false") param = [year, month, day, diary.title, diary.last_modified.to_i, visible, diary.to_src, diary.style, @dbi_author, date] sth = @dbh.execute("UPDATE diarydata SET year=?, month=?, day=?, title=?, last_modified=?, visible=?, body=?, style=? WHERE author=? AND diary_id=?", *param) if sth.rows == 0 @dbh.execute("INSERT INTO diarydata (year, month, day, title, last_modified, visible, body, style, author, diary_id) VALUES (?,?,?,?,?,?,?,?,?,?);", *param) end end end # 追加メソッド for test def delete(diaries) diaries.each do |date, diary| sql = "DELETE FROM diarydata WHERE author=#{@dbi_author} AND diary_id=#{date};" @dbh.execute(sql) end end end end tdiary-contrib-5.0.8/io/dbi_io/plugin/000077500000000000000000000000001325711763500176225ustar00rootroot00000000000000tdiary-contrib-5.0.8/io/dbi_io/plugin/refererDbiIO.rb000066400000000000000000000045461325711763500224610ustar00rootroot00000000000000# # refererDbiIO.rb: load/save and show today's referer for DBI IO # $Revision: 1.1 $ # # Copyright (C) 2003 ma2tak # (C) 2004 moonwolf # (C) 2005 Kazuhiko # (C) 2007 sasasin # # You can distribute this under GPL. # def referer_transaction( diary = nil, save = false ) return if @conf.io_class.to_s != 'TDiary::DbiIO' File.open("#{@conf.data_path}/dbi_io_ref.lock", 'w') {|file| file.flock(File::LOCK_EX) dbh = DBI.connect(@conf.dbi_driver_url, @conf.dbi_user, @conf.dbi_passwd) dbh.transaction{ if diary.respond_to?( :date ) then table = 'refererdata' ymd = diary.date.strftime('%Y%m%d') begin sql = "SELECT diary_id, count, ref FROM " + table + " WHERE author=? AND diary_id=?;" dbh.select_all(sql, @conf.dbi_author || 'default', ymd) {|diary_id, count, ref| yield(ref.chomp, count.to_i) } rescue Errno::ENOENT end else table = 'referervolatile' ymd = nil begin sql = "SELECT diary_id, count, ref FROM " + table + " WHERE author=?;" dbh.select_all(sql, @conf.dbi_author || 'default') {|diary_id, count, ref| yield(ref.chomp, count.to_i) ymd = diary_id } rescue Errno::ENOENT end end if @mode =~ /^(append|replace)$/ and !diary.respond_to?( :date ) then if !ymd or (@date.strftime( '%Y%m%d' ) > ymd) then ymd = nil diary.clear_referers begin dbh.execute("TRUNCATE TABLE " + table + ";") rescue Errno::ENOENT end save = false end end if save then unless ymd then ymd = (@date ? @date : Time::now).strftime( '%Y%m%d' ) end no = 0 diary.each_referer(diary.count_referers) {|count,ref| no += 1 param = [count, @conf.dbi_author, ymd, ref] begin sth = dbh.execute("UPDATE " + table + " SET count=? WHERE author=? AND diary_id=? AND ref=?;", *param) if sth.rows==0 no = dbh.select_one("SELECT MAX(no) FROM " + table + " WHERE author=? AND diary_id=?", @conf.dbi_author, ymd).first.to_i + 1 param << no dbh.execute("INSERT INTO " + table + " (count, author, diary_id, ref, no ) VALUES (?,?,?,?,?);", *param) end rescue DBI::ProgrammingError $stderr.puts "invalid referer:#{ref}" end } end } } end tdiary-contrib-5.0.8/io/dbi_io/tdiary_table.sql000077500000000000000000000025301325711763500215130ustar00rootroot00000000000000CREATE TABLE diarydata ( author TEXT NOT NULL, diary_id VARCHAR(8) NOT NULL, year VARCHAR(4) NOT NULL, month VARCHAR(2) NOT NULL, day VARCHAR(2) NOT NULL, title TEXT NULL, last_modified INTEGER NOT NULL, visible BOOLEAN NOT NULL, body TEXT NOT NULL, style TEXT NULL, CONSTRAINT diarydata_pkey PRIMARY KEY (author, diary_id) ); CREATE TABLE commentdata ( author TEXT NOT NULL, diary_id VARCHAR(8) NOT NULL, no INTEGER NOT NULL, name TEXT NULL, mail TEXT NULL, last_modified INTEGER NOT NULL, visible BOOLEAN NOT NULL, comment TEXT NULL, CONSTRAINT commentdata_pkey PRIMARY KEY (author, diary_id, no) ); CREATE TABLE refererdata ( author TEXT NOT NULL, diary_id VARCHAR(8) NOT NULL, no INTEGER NOT NULL, count INTEGER NOT NULL, ref TEXT NOT NULL, CONSTRAINT refererdata_pkey PRIMARY KEY (author, diary_id, no) ); CREATE TABLE referervolatile ( author TEXT NOT NULL, diary_id VARCHAR(8) NOT NULL, no INTEGER NOT NULL, count INTEGER NOT NULL, ref TEXT NOT NULL, CONSTRAINT referervolatile_pkey PRIMARY KEY (author, diary_id, no) ); tdiary-contrib-5.0.8/js/000077500000000000000000000000001325711763500151045ustar00rootroot00000000000000tdiary-contrib-5.0.8/js/appstore.js000066400000000000000000000056371325711763500173120ustar00rootroot00000000000000/* * appstore.js : embeded iTunes information * * Copyright (C) 2011 by tamoot * You can distribute it under GPL. */ $( function() { function appstore_desc(text) { return jQuery('').addClass("amazon-price").text(text).append("
    "); }; function appstore_detail(app_url, app_id, appstore_a) { var params = { output : 'json', id : app_id }; var price = "$"; if($('html').attr('lang') == 'ja-JP') { $.extend(params, { lang : 'ja_jp', country : 'JP' }); price = "\\" }; $.ajax({ type : 'GET', url : 'http://ax.itunes.apple.com/WebObjects/MZStoreServices.woa/wa/wsLookup?', data : params, dataType : 'jsonp', // // callback on error.. // error : function() { var itunes_a = jQuery('').attr({ target : "_blank", href : app_url }).addClass("amazon-detail"); $(appstore_a).prepend(itunes_a); }, // // append dom // success : function(data) { app = data["results"][0]; if(app == null) { appstore_a.text('Search Error: ' + app_url); return }; $(appstore_a).addClass("amazon-detail"); var appstore_spand = jQuery('').addClass("amazon-detail"); $(appstore_a).append(appstore_spand); appstore_spand.prepend(jQuery('').attr({ src : app["artworkUrl100"], width : 128, height : 128 }).addClass("amazon-detail").addClass("left")); var appstore_spandd = jQuery(''); appstore_spandd.addClass("amazon-detail-desc"); appstore_spand.append(appstore_spandd); appstore_spandd.append(jQuery('').addClass("amazon-title").text(app["trackCensoredName"] + " ")); appstore_spandd.append(appstore_desc(app["version"])); appstore_spandd.append(appstore_desc(app["releaseDate"])); appstore_spandd.append(appstore_desc(app["sellerName"])); appstore_spandd.append(appstore_desc(price + app["price"])); appstore_spandd.append(appstore_desc(app["supportedDevices"].join(', '))); appstore_spand.append('
    '); } }); }; function appstore(target) { $('.appstore', target).each( function() { var appstore_url = $(this).attr('href'); var appstore_id = $(this).attr('data-appstoreid') appstore_detail(appstore_url, appstore_id, this); }); }; // for AutoPagerize $(window).on('AutoPagerize_DOMNodeInserted', function(event) { appstore(event.target); }); // for AuthPatchWork // NOTE: jQuery.bind() cannot handle an event that include a dot charactor. // see http://todayspython.blogspot.com/2011/06/autopager-autopagerize.html if(window.addEventListener) { window.addEventListener('AutoPatchWork.DOMNodeInserted', function(event) { appstore(event.target); }, false); } else if(window.attachEvent) { window.attachEvent('onAutoPatchWork.DOMNodeInserted', function(event) { appstore(event.target); }); }; appstore(document); }); tdiary-contrib-5.0.8/js/datepicker.js000066400000000000000000000034361325711763500175630ustar00rootroot00000000000000/* * datepicker.js : datepicker using jQuery-UI * http://jqueryui.com/demos/datepicker/ * * Copyright (C) 2012 by tamoot * You can redistribute it and/or modify it under GPL. */ $( function() { function setDateText(date) { var dates = date.split("/"); $("#year" ).val(dates[0]); $("#month").val(dates[1]); $("#day" ).val(dates[2]); } function dateTextFromField() { var y = parseInt( $("#year" ).val() ); var m = parseInt( $("#month").val() ); var d = parseInt( $("#day" ).val() ); if( y > 0 && 13 > m && m > 0 && 32 > d && d > 0 ){ $("#datepicker-input").val(y + "/" + m + "/" + d); } } var datepicker_dom = $(""); var datepicker_trigger = $("") .addClass("ui-icon") .addClass("ui-icon-calendar") .addClass("datepicker-trigger"); var datepicker_input = $("", { id: "datepicker-input", name: "datepicker", style: "display: none;", type: "text" } ); datepicker_dom.append(datepicker_input); datepicker_dom.append(datepicker_trigger); datepicker_dom.insertAfter("span.day"); $("#datepicker-input").datepicker({ onSelect: function(dateText, inst){ setDateText(dateText); }, beforeShow: function(input ,inst){ dateTextFromField(); }, dateFormat: "yy/m/d" }); $(".datepicker-trigger").click(function() { $("#datepicker-input").datepicker("show"); }); var icon = $(".ui-icon-calendar"); icon.css({"display":"inline","position":"absolute","margin-top":"5px"}); icon.after($("").css({"margin-left":"16px"})); icon.hover(function(){ $(this).css({"cursor":"pointer"}); }); }); tdiary-contrib-5.0.8/js/editor.js000066400000000000000000000052271325711763500167360ustar00rootroot00000000000000/** * editor.js - support writing using wiki/gfm notation. * * Copyright (C) 2012 by MATSUOKA Kohei * You can distribute it under GPL. */ /* utility functions */ $.fn.extend({ insertAtCaret2: function(beforeText, afterText){ var elem = this.get(0); elem.focus(); if(jQuery.browser.msie){ this.insertAtCaret(beforeText + afterText); }else{ var orig = elem.value; var posStart = elem.selectionStart; var posEnd = posStart + beforeText.length; elem.value = orig.substr(0, posStart) + beforeText + afterText + orig.substr(posStart); elem.setSelectionRange(posEnd, posEnd); } } }); $(function() { var form = $("textarea"); var targetArea = $("div.update > div.form").first(); var notations = { wiki: { h3: function(){ form.insertAtCaret("! ") }, h4: function(){ form.insertAtCaret("!! ") }, a: function(){ form.insertAtCaret2("", "[[|]]") }, em: function(){ form.insertAtCaret2("''", "''") }, strong: function(){ form.insertAtCaret2("'''", "'''") }, del: function(){ form.insertAtCaret2("==", "=='") }, pre: function(){ form.insertAtCaret2("\n<<<\n", "\n>>>\n") }, bq: function(){ form.insertAtCaret("\"\" ") }, ul: function(){ form.insertAtCaret("* ") }, ol: function(){ form.insertAtCaret("# ") }, table: function(){ form.insertAtCaret( "\n||body1||body2\n||body3||body4\n") }, plugin: function(){ form.insertAtCaret2( "", $.makePluginTag("plugin_name")) } }, gfm: { h3: function(){ form.insertAtCaret("# ") }, h4: function(){ form.insertAtCaret("## ") }, a: function(){ form.insertAtCaret2("", "[]()") }, em: function(){ form.insertAtCaret2("*", "*") }, strong: function(){ form.insertAtCaret2("**", "**") }, pre: function(){ form.insertAtCaret2("\n```\n", "\n```\n") }, code: function(){ form.insertAtCaret2("`", "`") }, bq: function(){ form.insertAtCaret("> ") }, ul: function(){ form.insertAtCaret("* ") }, ol: function(){ form.insertAtCaret("1. ") }, table: function(){ form.insertAtCaret( "\nhead1|head2\n----|----\nbody1|body2\nbody3|body4\n") }, plugin: function(){ form.insertAtCaret2( "", $.makePluginTag("plugin_name")) } } }; var toolbox = $("
      "); $.each(notations[$tDiary.style], function(key, callback) { var button = $("
      ') .click(function() { saveCheckedDate(plugins[0].commit.date); notify.hide(); }) ); var notify = $('
      プラグインの更新が見つかりました。
      ') .append(close) .append(ul); return notify; } $.get(url, function(plugins) { var now = new Date(); var checkedDate = loadCheckedDate(); var updates = $.grep(plugins, function(plugin) { // TODO: 条件を追加する(使用中プラグイン) if (checkedDate) { return (checkedDate < plugin.commit.date); } else { var age = parseInt((now - new Date(plugin.commit.date)) / 1000 / 3600 / 24); return (age < 7); } }); if (updates.length > 0) { $('form.update').before(createNotify(updates)); } $tDiary.updates = updates; }); }); tdiary-contrib-5.0.8/js/referer.js000066400000000000000000000006461325711763500171020ustar00rootroot00000000000000/** * referer.js: fetch referer with ajax * * Copyright (C) 2013 by MATSUOKA Kohei * You can distribute it under GPL. */ $(function() { $('div.main').on('click', 'button.lazy_referer', function(e) { var button = $(this); button.attr("disabled", "disabled"); $.get(button.data('endpoint'), function (data) { button.after($(data)); button.hide(); }, 'html'); }); }); tdiary-contrib-5.0.8/js/show_and_hide.js000066400000000000000000000020621325711763500202350ustar00rootroot00000000000000/* * show_and_hide.js : javascript for show_and_hide.rb plugin of tDiary * * Copyright (C) 2011 by tamoot * You can distribute it under GPL. */ $( function() { function show_and_hide(target) { $('.show_and_hide_toggle', target).each( function() { $(this).click( function() { $('.show_and_hide#'+$(this).attr('data-showandhideid')).slideToggle(400); }); }); }; // for AutoPagerize $(window).on('AutoPagerize_DOMNodeInserted', function(event) { show_and_hide(event.target); }); // for AuthPatchWork // NOTE: jQuery.bind() cannot handle an event that include a dot charactor. // see http://todayspython.blogspot.com/2011/06/autopager-autopagerize.html if(window.addEventListener) { window.addEventListener('AutoPatchWork.DOMNodeInserted', function(event) { show_and_hide(event.target); }, false); } else if(window.attachEvent) { window.attachEvent('onAutoPatchWork.DOMNodeInserted', function(event) { show_and_hide(event.target); }); }; show_and_hide(document) $('.show_and_hide').hide(); }); tdiary-contrib-5.0.8/js/slideshow.js000066400000000000000000000061641325711763500174520ustar00rootroot00000000000000/* * slideshow.js : show slides * * Copyright (C) 2016 by TADA Tadashi * Distributed under the GPL2 or any later version. */ $(function(){ function isFullscreenEnabled(doc) { return( doc.fullscreenEnabled || doc.webkitFullscreenEnabled || doc.mozFullScreenEnabled || doc.msFullscreenEnabled || false ); }; function requestFullscreen(element) { var funcs = [ 'requestFullscreen', 'webkitRequestFullscreen', 'mozRequestFullScreen', 'msRequestFullscreen', ]; $.each(funcs, function(idx, func) { if (element[func]) { element[func](); return false; } }); }; function isFullscreen() { if (document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement ) { return true; } return false; }; function startSlideShow(content) { if (!isFullscreenEnabled(document)) { return false; } var slides = []; $.each(content.children(), function(i, elem) { var e = $(elem).clone(); if (e.prop('tagName') == 'H3') { // main title $('a', e).remove(); // section anchor $('span', e).remove(); // hatena start etc... $('button.slideshow', e).remove(); slides.push([$('
      ').append(e)]); } else if (e.prop('tagName') == 'H4') { // page title slides.push([e, $('
      ')]); } else { var last = slides[slides.length-1]; last[last.length-1].append(e); } }); var screen = window.screen; var slide = $('
      '). addClass('slide'). css('width', screen.width). css('height', screen.height); var current_page = 0; var firstClick = true; $('body').append(slide); slide.append(slides[current_page]); requestFullscreen(slide[current_page]); $(document).on({ 'keydown': function(e) { if (e.keyCode == 13 || e.keyCode == 34 || e.keyCode == 39) { // next page if (slides.length - 1 > current_page) { e.preventDefault(); slide.empty().append(slides[++current_page]); } } else if (e.keyCode == 37 || e.keyCode == 33) { // prev page if (current_page > 0) { e.preventDefault(); slide.empty().append(slides[--current_page]); } } else if (e.keyCode == 36) { // [Home] to top page e.preventDefault(); slide.empty().append(slides[current_page = 0]); } else if (e.keyCode == 35) { // [End] to bottom page e.preventDefault(); slide.empty().append(slides[current_page = slides.length-1]); } }, 'click': function() { if (!firstClick && slides.length - 1 > current_page) { slide.empty().append(slides[++current_page]); } firstClick = false; }, 'fullscreenchange webkitfullscreenchange mozfullscreenchange msfullscreenchange': function() { if (!isFullscreen()) { // fullscreen was closed $(document).off('keydown').off('click'); slide.remove(); } } }); return true; }; $('.slideshow').on('click', function(e){ var section = $(this).parent().parent(); e.preventDefault(); if (!startSlideShow(section)) { alert("couldn't start slideshow.") return; } }); }); tdiary-contrib-5.0.8/js/socialbutton.js000066400000000000000000000070501325711763500201520ustar00rootroot00000000000000/** * socialbutton.js - * * Copyright (C) 2011 by MATSUOKA Kohei * You can distribute it under GPL. */ /** * SYNOPSIS * * you can set options at socialbutton.rb * * $tDiary.plugin.socialbutton.enables = * ['twitter', 'hatena', 'facebook_like', 'evernote']; * * $tDiary.plugin.socialbutton.options = { * twitter: { via: 'machu' } * }; * */ $(function() { // load config from tDiary plugin (socialbutton.rb) var config = $tDiary.plugin.socialbutton; // set options for jQuery.socialbutton var callbacks = { twitter: function(url, title) { var link = url; var pos = 0; if ((pos = url.indexOf('#')) > 0) { link = url.substr(0, pos) } return { url: link, text: title, button: 'horizontal', lang: $('html').attr('lang').substr(0,2) }; }, hatena: function(url, title) { return { url: url, title: title, button: 'simple-balloon' }; }, facebook_like: function(url, title) { return { url: url, button: 'button_count', locale: $('html').attr('lang').replace('-', '_') }; }, evernote: function(url, title) { return { url: url, title: title, button: 'article-clipper-jp' }; }, google_plusone: function(url, title) { return { href: url, size: 'medium', lang: $('html').attr('lang') }; }, pinterest: function(url, title) { return { url: url, media: $('p img:first', $('div.section h3 a[name=' + url.substr(-3) + ']').parent().parent()).attr('src'), description: title, button: 'horizontal', }; }, }; function socialbutton(target) { $('.socialbuttons').css('height', '1em') var bottom = $(window).height() + $(window).scrollTop(); $($tDiary.blogkit ? '.day' : '.day .section') .filter(function() { return bottom > $(this).offset().top; }) .filter(function() { return $(this).find('.socialbutton').length == 0 }) .each(function() { var anchor = $(this).find('h3 a'); if ($tDiary.blogkit) { var link = $(this).children('h2').find('a:first').get(0); var url = link ? link.href : document.URL; var title = $(this).children('h2').find('.title').text(); } else if (anchor.length == 0) { // The section may not have an anchor on etdiary style. // https://github.com/tdiary/tdiary-contrib/issues/59 var url = ($(this).parents('.day').find('h2 a:first').get(0)||'').href; var title = $(this).parents('.day').find('h2 .title').text(); } else { var url = anchor.get(0).href; var title = anchor.attr('title'); } if (url && title) { // console.debug('loading socialbutton: ' + title); var socialbuttons = $(this).find('.socialbuttons'); append_button(url, title, socialbuttons); } }); } function append_button(url, title, socialbuttons) { $.each(config.enables, function(i, service) { var options = callbacks[service](url, title.replace(/"/g, '"')); $.extend(options, config.options[service]); $('') .css("float", "left") .css("margin-right", "0.5em") .appendTo(socialbuttons) .socialbutton(service, options); }); } $(window).on('scroll', function(event) { socialbutton(document); }); socialbutton(document); }); tdiary-contrib-5.0.8/js/twitter_anywhere.js000066400000000000000000000011611325711763500210450ustar00rootroot00000000000000/* * twitter_anywhere.js : use Twitter@Anywhere * * Copyright (C) 2012 by tamoot * You can distribute it under GPL. */ $( function() { // load config from tDiary plugin (twitter_anywhere.rb) var config = $tDiary.plugin.twitter_anywhere; // hovarcards var expand = config.hovercards.expand_default; $.each(config.selectors, function(i, css){ twttr.anywhere(function(twitter) { twitter(css).hovercards(expand); }); }); }); // tweet box function showTweetBox(option) { twttr.anywhere(function (T) { T("#tweetbox").tweetBox(option); }); } tdiary-contrib-5.0.8/js/yahoo_kousei.js000066400000000000000000000010661325711763500201430ustar00rootroot00000000000000$( function() { $( '.plugin_yahoo_search_result_raw' ).each( function( index ) { $(this).click( function() { var pos = $($('td', $(this)).get(3)).text().split(','); sp = parseInt(pos[0]); ep = parseInt(pos[1]); var o = $( 'textarea[name="body"]' ).get( 0 ); o.focus(); if ( jQuery.browser.msie ) { var range = document.selection.createRange(); range.collapse(); range.moveStart( 'character', sp ); range.moveEnd( 'character', ep ); range.select(); } else { o.setSelectionRange( sp , sp + ep ); } } ); } ); } ); tdiary-contrib-5.0.8/lib/000077500000000000000000000000001325711763500152365ustar00rootroot00000000000000tdiary-contrib-5.0.8/lib/bayes.rb000066400000000000000000000107511325711763500166720ustar00rootroot00000000000000# Copyright (C) 2007, KURODA Hiraku # You can redistribute it and/or modify it under GPL2. require "pstore" module Bayes module CHARSET def self.setup_re(m) o = $KCODE $KCODE = m::KCODE m.const_set(:RE_MESSAGE_TOKEN, Regexp.union(m::RE_KATAKANA, m::RE_KANJI, /[a-zA-Z]+/)) $KCODE=o end module EUC KCODE = "e" KATAKANA = "\xa5\xa2-\xa5\xf3" BAR = "\xa1\xbc" KANJI = "\xb0\xa1-\xfc\xfe" RE_KATAKANA = /[#{KATAKANA}#{BAR}]{2,}/eo RE_KANJI = /[#{KANJI}]{2,}/eo CHARSET.setup_re(self) end module UTF8 KCODE = "u" def self.c2u(c) [c].pack("U") end def self.utf_range(a, b) "#{c2u(a)}-#{c2u(b)}" end KATAKANA = utf_range(0x30a0, 0x30ff) BAR = c2u(0x30fc) KANJI = utf_range(0x4e00, 0x9faf) RE_KATAKANA = /[#{KATAKANA}#{BAR}]{2,}/uo RE_KANJI = /[#{KANJI}]{2,}/uo CHARSET.setup_re(self) end end class TokenList < Array attr_reader :charset def initialize(charset=nil) unless charset charset = case $KCODE when /^e/i CHARSET::EUC else CHARSET::UTF8 end end @charset = charset end alias _concat concat def concat(array, prefix=nil) if prefix _concat(array.map{|i| "#{prefix} #{i.to_s}"}) else _concat(array) end end alias _push push def push(item, prefix=nil) if prefix _push("#{prefix} #{item.to_s}") else _push(item) end end def add_host(host, prefix=nil) if /^(?:\d{1,3}\.){3}\d{1,3}$/ =~ host while host.size>0 push(host, prefix) host = host[/^(.*?)\.?\d+$/, 1] end else push(host, prefix) h = host while /^(.*?)[-_.](.*)$/=~h h = $2 push($1, prefix) push(h, prefix) end end self end def add_url(url, prefix=nil) if %r[^(?:https?|ftp)://(.*?)(?::\d+)?/(.*?)\/?(\?.*)?$] =~ url host, path = $1, $2 add_host(host, prefix) if path.size>0 push(path, prefix) p = path re = %r[^(.*)[-_./](.*?)$] while re=~p p = $1 push($2, prefix) push(p, prefix) end end end self end def add_message(message, prefix=nil) concat(message.scan(@charset::RE_MESSAGE_TOKEN), prefix) self end def add_mail_addr(addr, prefix=nil) push(addr, prefix) name, host = addr.split(/@/) return self if (name||"").empty? host ||= "" push(name, prefix) add_host(host, prefix) self end end class FilterBase attr_reader :spam, :ham, :db_name, :charset def initialize(db_name=nil, charset=nil) @spam = self.class::Corpus.new @ham = self.class::Corpus.new @charset = charset @db_name = db_name if db_name && File.exist?(db_name) PStore.new(db_name).transaction(true) do |db| @spam = db["spam"] @ham = db["ham"] @charset = db["charset"] end end end def save(db_name=nil) db_name ||= @db_name @db_name ||= db_name return unless @db_name PStore.new(@db_name).transaction do |db| db["spam"] = @spam db["ham"] = @ham db["charset"] = @charset yield(db) if block_given? end end def [](token) score(token) end end class PlainBayes < FilterBase class Corpus < Hash def initialize super(0.0) end def <<(src) s = src.size.to_f src.each do |i| self[i] += 1/s end end end def score(token) return nil unless @spam.include?(token) || @ham.include?(token) s = @spam[token] h = @ham[token] s/(s+h) end def estimate(tokens, take=15) s = tokens.uniq.map{|i| score(i)}.compact.sort{|a, b| (0.5-a).abs <=> (0.5-b)}.reverse[0...take] return nil if s.empty? || s.include?(1.0) && s.include?(0.0) prod = s.inject(1.0){|r, i| r*i} return prod/(prod+s.inject(1.0){|r, i| r*(1-i)}) end end class PaulGraham < FilterBase class Corpus < Hash attr_reader :count def initialize super(0) @count = 0 end def <<(src) @count += 1 src.each do |i| self[i] += 1 end end end def score(token) return 0.4 unless @spam.include?(token) or @ham.include?(token) g = @ham.count==0 ? 0.0 : [1.0, 2*@ham[token]/@ham.count.to_f].min b = @spam.count==0 ? 0.0 : [1.0, @spam[token]/@spam.count.to_f].min r = [0.01, [0.99, b/(g+b)].min].max r end def estimate(tokens, take=15) s = tokens.uniq.map{|i| score(i)}.compact.sort{|a, b| (0.5-a).abs <=> (0.5-b)}.reverse[0...take] return nil if s.empty? || s.include?(1.0) && s.include?(0.0) prod = s.inject(1.0){|r, i| r*i} return prod/(prod+s.inject(1.0){|r, i| r*(1-i)}) end end end tdiary-contrib-5.0.8/lib/bayes/000077500000000000000000000000001325711763500163415ustar00rootroot00000000000000tdiary-contrib-5.0.8/lib/bayes/convert.rb000066400000000000000000000012301325711763500203420ustar00rootroot00000000000000# Copyright (C) 2008, KURODA Hiraku # You can redistribute it and/or modify it under GPL2. require "bayes" require "kconv" module Bayes module CHARSET module EUC KCONV = Kconv::EUC end module UTF8 KCONV = Kconv::UTF8 end end class FilterBase def convert_corpus(corpus, to_code, from_code) r = self.class::Corpus.new corpus.each do |k, v| r[k.kconv(to_code::KCONV, from_code::KCONV)] = v end r end private :convert_corpus def convert(to_code, from_code) @charset = to_code @ham = convert_corpus(@ham, to_code, from_code) @spam = convert_corpus(@spam, to_code, from_code) end end end tdiary-contrib-5.0.8/lib/exifparser/000077500000000000000000000000001325711763500174065ustar00rootroot00000000000000tdiary-contrib-5.0.8/lib/exifparser/README000066400000000000000000000004421325711763500202660ustar00rootroot00000000000000ExifParserは、tdiary-contribの管理から外れました。 通常は以下のコマンドによりインストールすることができます。 #gem install exifparser もしくは、 $git clone https://github.com/kp1/exifparser.git でソースコードを取得可能です。 tdiary-contrib-5.0.8/lib/extensions/000077500000000000000000000000001325711763500174355ustar00rootroot00000000000000tdiary-contrib-5.0.8/lib/extensions/contrib.rb000066400000000000000000000004101325711763500214150ustar00rootroot00000000000000# -*- coding: utf-8 -*- require 'tdiary/extensions' module TDiary module Extensions class Contrib def self.sp_path File.join(TDiary::Contrib.root, 'plugin') end def self.assets_path File.join(TDiary::Contrib.root, 'js') end end end end tdiary-contrib-5.0.8/lib/tdiary-contrib.rb000066400000000000000000000002311325711763500205110ustar00rootroot00000000000000# -*- coding: utf-8 -*- require 'extensions/contrib' module TDiary class Contrib def self.root File.expand_path('../..', __FILE__) end end end tdiary-contrib-5.0.8/lib/tdiary/000077500000000000000000000000001325711763500165325ustar00rootroot00000000000000tdiary-contrib-5.0.8/lib/tdiary/contrib/000077500000000000000000000000001325711763500201725ustar00rootroot00000000000000tdiary-contrib-5.0.8/lib/tdiary/contrib/version.rb000066400000000000000000000000761325711763500222070ustar00rootroot00000000000000module TDiary class Contrib VERSION = "5.0.8" end end tdiary-contrib-5.0.8/lib/wgs2tky.rb000066400000000000000000000030611325711763500171750ustar00rootroot00000000000000# # wgs2tky.rb # -- GPS data converter # # kp # Destributed under the GPL class Wgs2Tky Pi = Math::PI Rd = Pi/180 # WGS84 A = 6378137.0 # 赤道半径 F = 1/298.257223563 # 扁平率 E2 = F*2 - F*F # 第一離心率 # Tokyo A_ = 6378137.0 - 739.845 # 6377397.155 F_ = 1/298.257223563 - 0.000010037483 # 1 / 299.152813 E2_ = F_*2 - F_*F_ Dx = +128 Dy = -481 Dz = -664 def Wgs2Tky.conv!(lat,lon,h = 0) b = lat[0].to_f + lat[1].to_f/60 + lat[2].to_f/3600 l = lon[0].to_f + lon[1].to_f/60 + lon[2].to_f/3600 (x,y,z) = Wgs2Tky._llh2xyz(b,l,h,A,E2) x+=Dx y+=Dy z+=Dz (b,l,h) = Wgs2Tky._xyz2llh(x,y,z,A_,E2_) lat[0..2]=Wgs2Tky._deg2gdms(b) lon[0..2]=Wgs2Tky._deg2gdms(l) end private include Math extend Math def Wgs2Tky._llh2xyz(b,l,h,a,e2) b *= Rd l *= Rd sb = sin(b) cb = cos(b) rn = a / Math.sqrt(1-e2*sb*sb) x = (rn+h)*cb*cos(l) y = (rn+h)*cb*sin(l) z = (rn*(1-e2)+h) * sb return x,y,z end def Wgs2Tky._xyz2llh(x,y,z,a,e2) bda = sqrt(1-e2) po = sqrt(x*x+y*y) t = atan2(z,po*bda) st = sin(t) ct = cos(t) b = atan2(z+e2*a/bda*st*st*st,po-e2*a*ct*ct*ct) l = atan2(y,x) sb = sin(b) rn = a / sqrt(1-e2*sb*sb) h = po / cos(b) - rn return b/Rd,l/Rd,h end def Wgs2Tky._deg2gdms(deg) sf = deg*3600 s = sf.to_i%60 m = (sf/60).to_i%60 d = (sf/3600).to_i s += sf - sf.to_i return d,m,s end end tdiary-contrib-5.0.8/misc/000077500000000000000000000000001325711763500154235ustar00rootroot00000000000000tdiary-contrib-5.0.8/misc/section_footer2/000077500000000000000000000000001325711763500205275ustar00rootroot00000000000000tdiary-contrib-5.0.8/misc/section_footer2/buzzurl.yaml000066400000000000000000000003251325711763500231300ustar00rootroot00000000000000url: http://buzzurl.jp/entry/ src: http://buzzurl.jp/static/image/api/icon/add_icon_mini_10.gif title: ja: このエントリを含む Buzzurl =: this entry on Buzzurl counter: http://buzzurl.jp/api/counter/ tdiary-contrib-5.0.8/misc/section_footer2/fc2.yaml000066400000000000000000000003511325711763500220640ustar00rootroot00000000000000url: http://bookmark.fc2.com/search/detail?url= src: http://bookmark.fc2.com/img/add-16.gif title: ja: このエントリを含む FC2ブックマーク =: this entry on FC2 Bookmark counter: http://bookmark.fc2.com/image/users/ tdiary-contrib-5.0.8/misc/section_footer2/ldc.yaml000066400000000000000000000003611325711763500221550ustar00rootroot00000000000000url: http://clip.livedoor.com/page/ src: http://parts.blog.livedoor.jp/img/cmn/clip_16_16_w.gif title: ja: このエントリを含む livedoor クリップ =: this entry on livedoor clip counter: http://image.clip.livedoor.com/counter/ tdiary-contrib-5.0.8/misc/section_footer2/retweet.yaml000066400000000000000000000003521325711763500230720ustar00rootroot00000000000000url: 'http://twitter.com/home?status=RT @your-twitter-account: %s ' src: http://kayakaya.net/parts/tdiary/retweet.gif title: ja: このエントリをRetweetする =: Retweet for this entry counter: usesubtitle: !ruby/regexp /%s/ tdiary-contrib-5.0.8/misc/section_footer2/twitter.yaml000066400000000000000000000003301325711763500231110ustar00rootroot00000000000000url: 'http://twitter.com/home?status=Reading: %s ' src: http://twitter-badges.s3.amazonaws.com/t_mini-a.png title: ja: このエントリをTweetする =: Tweet this entry counter: usesubtitle: !ruby/regexp /%s/ tdiary-contrib-5.0.8/misc/section_footer2/yahoo.yaml000066400000000000000000000003741325711763500225360ustar00rootroot00000000000000url: http://bookmarks.yahoo.co.jp/url?url= src: http://i.yimg.jp/images/sicons/ybm16.gif title: ja: このエントリを含む Yahoo!ブックマーク =: this entry on Yahoo! JAPAN Bookmarks counter: http://num.bookmarks.yahoo.co.jp/image/small/ tdiary-contrib-5.0.8/plugin/000077500000000000000000000000001325711763500157665ustar00rootroot00000000000000tdiary-contrib-5.0.8/plugin/add_bookmark.rb000066400000000000000000000062671325711763500207430ustar00rootroot00000000000000# add_bookmark.rb $Revision 1.3 $ # # Copyright (c) 2005 SHIBATA Hiroshi # You can redistribute it and/or modify it under GPL2. require 'uri' def bookmark_init @conf['add.bookmark.delicious'] ||= '' @conf['add.bookmark.hatena'] ||= '' @conf['add.bookmark.livedoor'] ||= '' @conf['add.bookmark.buzzurl'] ||= '' end add_subtitle_proc do |date, index, subtitle| bookmark_init caption = %Q|#{subtitle} | section_url = @conf.base_url + anchor(date.strftime('%Y%m%d')) + '#p' + ('%02d' % index) if @conf['add.bookmark.delicious'] == 't' then escaped_url = URI.escape(section_url, /[^-.!~*'()\w]/n) caption += %Q|| caption += %Q|#{@caption_delicious}| caption += %Q| | end if @conf['add.bookmark.hatena'] == 't' then caption += %Q|| caption += %Q|#{@caption_hatena}| caption += %Q| | end if @conf['add.bookmark.livedoor'] == 't' then caption += %Q|| caption += %Q|#{@caption_livedoor}| caption += %Q| | end if @conf['add.bookmark.buzzurl'] == 't' then caption += %Q|| caption += %Q|#{@caption_buzzurl}| caption += %Q| | end <<-HTML #{caption} HTML end add_conf_proc( 'add_bookmark', @add_bookmark_label ) do add_bookmark_conf_proc end def add_bookmark_conf_proc bookmark_init saveconf_add_bookmark bookmark_categories = [ 'add.bookmark.delicious', 'add.bookmark.hatena', 'add.bookmark.livedoor', 'add.bookmark.buzzurl' ] r = '' r << %Q|

      #{@add_bookmark_label}

      #{@add_bookmark_desc}

        | bookmark_categories.each_with_index do |idx,view| checked = 't' == @conf[idx] ? ' checked' : '' label = @bookmark_label[view] r << %Q|
      • | end r << %Q|
      | end if @mode == 'saveconf' def saveconf_add_bookmark @conf['add.bookmark.delicious'] = @cgi.params['add.bookmark.delicious'][0] @conf['add.bookmark.hatena'] = @cgi.params['add.bookmark.hatena'][0] @conf['add.bookmark.livedoor'] = @cgi.params['add.bookmark.livedoor'][0] @conf['add.bookmark.buzzurl'] = @cgi.params['add.bookmark.buzzurl'][0] end end tdiary-contrib-5.0.8/plugin/apple_webclip.rb000066400000000000000000000013231325711763500211200ustar00rootroot00000000000000# # apple_webclip.rb - Add icon information for Apple WebClip. # # Copyright (C) 2008, TADA Tadashi # You can redistribute it and/or modify it under GPL. # add_header_proc do if @conf['apple_webclip.url'] and @conf['apple_webclip.url'].size > 0 %Q| \n| else '' end end add_conf_proc( 'apple_webclip', 'Apple WebClip' ) do if @mode == 'saveconf' then @conf['apple_webclip.url'] = @cgi.params['apple_webclip.url'][0] end <<-HTML

      Icon URL

      Create and cpecify PNG file 60x60 pixels.

      HTML end tdiary-contrib-5.0.8/plugin/appstore.rb000066400000000000000000000021211325711763500201440ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # appstore.rb - embeded AppStore data for tDiary, # use App Store Affliate Resources Search API. # http://www.apple.com/itunes/affiliates/resources/documentation/itunes-store-web-service-search-api.html # # Copyright (C) 2011, tamoot # You can redistribute it and/or modify it under GPL2. # require 'uri' if /\A(?:latest|day|month|nyear|preview)\z/ =~ @mode enable_js('appstore.js') end def appstore_detail(url) appstore_dom = '' begin appstore_dom = appstore_common(url, {:detail => true}) rescue appstore_dom = "Error. message=#{$!.message}." end end def appstore_common(url, params) return %Q|#{url}| if feed? appstore_uri = URI::parse(url) id = appstore_uri.path.split('/').last.gsub('id', '') raise StandardError.new("AppStore ID: not found from #{url}..") if id.nil? || id == '' return %Q|| end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/plugin/bigpresen.rb000066400000000000000000000054221325711763500202740ustar00rootroot00000000000000# bigpresen.rb $Revision: 1.03 $ # # bigpresen : クリックで進行する「高橋メソッド」風巨大文字プレゼンテーションを挿入 # # パラメタ : # str : 本文。"|"はスライドの区切り、"/"はスライド内の改行となる。 # "|"と"|"を表示する場合には、前に"\"をつけてエスケープ。 # width : スライドの幅。ピクセルで指定。(デフォルト : 480) # height : スライドの高さ。ピクセルで指定。(デフォルト : 320) # # 日記本文に、<%= bigpresen 'str','width','height' %> の形式で記述します。 # 文字のサイズは、表示テキストとスライドのサイズに合うよう自動的に調整されます。 # JavaScriptとDHTMLを用いて動かすので、閲覧環境によっては表示されないこともあります。 # # Copyright (c) 2006 Maripo Goda # mailto:madin@madin.jp # Document URL http://www.madin.jp/works/plugin.html # You can redistribute it and/or modify it under GPL2. @bigPresenID = 0; def bigpresen (str='', width='480',height='320') scriptID = 'bp' + @bigPresenID.to_s @bigPresenID += 1; presen_ary = str.gsub("\\/",'⁄').gsub("\\|","&\#65073").split(/\|/); presen_ary.collect!{|s| s = '"' + s.gsub('/','
      ') + '"' } presen_str = presen_ary.join(',') return <
      《START》
      HTML end tdiary-contrib-5.0.8/plugin/bitly.rb000066400000000000000000000021131325711763500174330ustar00rootroot00000000000000# # bitly.rb - shorten URL by bit.ly. # # usage: shorten_url_you_got = bitly( 'long_url' ) || long_url # (because bitly returns nil sometime.) # # required some options below: # @options['biyly.login'] : your login ID of bit.ly. # @options['biyly.key'] : your API key of biy.ly. # # Copyright (C) 2010, TADA Tadashi # You can redistribute it and/or modify it under GPL. # require 'json' require 'net/http' def bitly( long_url ) return nil if !long_url or long_url.empty? @bitly_cache ||= {} # cached only on memory return @bitly_cache[long_url] if @bitly_cache[long_url] login = @conf['bitly.login'] key = @conf['bitly.key'] # proxy px_host, px_port = (@conf['proxy'] || '').split( /:/ ) px_port = 80 if px_host and !px_port query = "/v3/shorten?longUrl=#{CGI::escape long_url}&login=#{login}&apiKey=#{key}&format=json" begin Net::HTTP.version_1_2 res = Net::HTTP::Proxy(px_host, px_port).get('api.bit.ly', "#{query}") @bitly_cache[long_url] = JSON::parse(res, &:read)['data']['url'] rescue TypeError => te# biy.ly returns an error. nil end end tdiary-contrib-5.0.8/plugin/bootstrap-navi.rb000066400000000000000000000025711325711763500212700ustar00rootroot00000000000000# Show navi for twitter-bootstrap theme # # Copyright (c) KAOD Masanori # You can redistribute it and/or modify it under GPL. def bootstrap_navi(options = {}) default_options = { :navbar_class => nil, :site_name? => true, :search_form? => true } options = default_options.merge(options) body = "" if options[:site_name?] body += <<-EOS #{h @conf.html_title} EOS end body += <<-EOS EOS if options[:search_form?] body += <<-EOS EOS end <<-EOS EOS end add_header_proc do %Q|| end tdiary-contrib-5.0.8/plugin/brow_si.rb000066400000000000000000000015101325711763500177540ustar00rootroot00000000000000# # brow_si.rb: insert brow.si code # # Copyright (C) 2012 by hb # add_conf_proc( "brow_si", "Brow.si" ) do if @mode == "saveconf" @conf["brow.si.site_id"] = @cgi.params["brow.si.site_id"][0] end <<-HTML

      Website Brow.si Site ID

      HTML end add_footer_proc do if @conf["brow.si.site_id"] and @conf.smartphone? <<-SCRIPT SCRIPT end end tdiary-contrib-5.0.8/plugin/canonical.rb000066400000000000000000000002121325711763500202350ustar00rootroot00000000000000# canonical.rb if /latest/ =~ @mode then add_header_proc do <<-HTML HTML end end tdiary-contrib-5.0.8/plugin/category_similar.rb000066400000000000000000000046211325711763500216530ustar00rootroot00000000000000# -*- coding: utf-8 -*- # category_similar.rb: # * shows similar posts under the diary # * depends on plugin/category.rb # You can redistribute it and/or modify it under the same license as tDiary. def category_similar(categories, max_item) info = Category::Info.new(@cgi, @years, @conf) months = [['01', '02', '03'], ['04', '05', '06'], ['07', '08', '09'], ['10', '11', '12']][@date.strftime("%m").to_i / (3 + 1)] # quarter years = { @date.strftime("%Y") => months } hash = @category_cache.categorize(info.category, years) items = [] hash.values_at(*categories).inject({}){|r, i| r.merge i if !r.nil? and !i.nil? }.to_a.each do |ymd_ary| ymd = ymd_ary[0] ary = ymd_ary[1] next if ymd == @date.strftime('%Y%m%d') t = Time.local(ymd[0,4], ymd[4,2], ymd[6,2]).strftime(@conf.date_format) ary.each do |idx, title, excerpt| items << %Q|#{t}#p#{'%02d' % idx} #{apply_plugin(title)}| end end unless items.empty? '
      ' + "

      #{category_similar_label}

      " + "
        " + items.sort.reverse[0, max_item].map{|i| "
      • #{i}" }.join("\n") + "
      " + "
      " end end add_conf_proc('category_similar', category_similar_label, 'basic') do if @mode == 'saveconf' @conf["category_similar.excludes"] = @cgi.params["category_similar.excludes"][0] @conf["category_similar.section_amounts"] = @cgi.params["category_similar.section_amounts"][0].to_i end <<-HTML

      #{category_similar_label}

      #{category_similar_excludes}

      #{category_similar_amounts}

      HTML end add_body_leave_proc do |date, idx| diary = @diaries[date.strftime('%Y%m%d')] if @mode =~ /day/ and diary.categorizable? categories = [] diary.each_section do |s| categories += s.categories unless s.categories.empty? end categories.delete_if do |i| @conf['category_similar.excludes'].split(/\r?\n/).include? i end category_similar(categories, @conf['category_similar.section_amounts']) end end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/plugin/category_to_tag.rb000066400000000000000000000030541325711763500214670ustar00rootroot00000000000000# # category_to_tag.rb - show categories list in end of each section # # Copyright (C) 2005, TADA Tadashi # You can redistribute it and/or modify it under GPL2. # if respond_to?( :categorized_title_of_day ) then # BlogKit def categorized_title_of_day( date, title ) @category_to_tag_list = {} cats, stripped = title.scan( /^((?:\[[^\]]+\])+)\s*(.*)/ )[0] if cats then cats.scan( /\[([^\]]+)\]+/ ).flatten.each do |tag| @category_to_tag_list[tag] = true # true when blog end else stripped = title end stripped end add_body_leave_proc do |date| feed? ? '' : category_to_tag_list end elsif respond_to?( :category_anchor ) # diary add_section_enter_proc do |date, index| @category_to_tag_list = {} '' end alias subtitle_link_original subtitle_link def subtitle_link( date, index, subtitle ) s = '' if subtitle then s = subtitle.sub( /^(\[([^\[]+?)\])+/ ) do $&.scan( /\[(.*?)\]/ ) do |tag| @category_to_tag_list[CGI::unescapeHTML(tag[0])] = false # false when diary end '' end end subtitle_link_original( date, index, s.strip ) end add_section_leave_proc do |date, index| feed? ? '' : category_to_tag_list end end def category_to_tag_list if @category_to_tag_list and not @category_to_tag_list.empty? then r = '
      Tags: ' @category_to_tag_list.each do |tag, blog| if blog r << %Q|#{tag} | else r << category_anchor( "#{tag}" ).sub( /^\[/, '' ).sub( /\]$/, '' ) << ' ' end end r << "
      \n" end end tdiary-contrib-5.0.8/plugin/category_to_tagcloud.rb000066400000000000000000000103541325711763500225170ustar00rootroot00000000000000# # category_to_tagcloud.rb # # Usage: # <% tag_list n %> # n: 表示最大数(default: nil) # # options configurable through settings: # @options['tagcloud.hidecss'] : cssの出力 default: false # # This plugin modifes and includes tagcloud-ruby. # http://yatsu.info/articles/2005/08/05/ruby%E3%81%A7tagcloud-tagcloud-ruby require 'pstore' def category_enable? !@plugin_files.grep(/\/category\-legacy\.rb$/).empty? end def add tag, url, count, elapsed_time @counts[tag] = count @urls[tag] = url @elapsed_times[tag] = elapsed_time end def print_html tags = @counts.sort_by {|a, b| b }.reverse.map {|a, b| a } return '' if tags.empty? tags = tags[0..@limit-1] if @limit if tags.size == 1 tag = tags[0] url = @urls[tag] elapsed_time = @elapsed_times[tag] return %{\n} end min = Math.sqrt(@counts[tags.last]) max = Math.sqrt(@counts[tags.first]) factor = 0 # special case all tags having the same count if max - min == 0 min = min - 24 factor = 1 else factor = 24 / (max - min) end html = %{
        } tags.sort{|a,b| a.downcase <=> b.downcase}.each do |tag| count = @counts[tag] level = ((Math.sqrt(count) - min) * factor).to_i html << %{
      • #{tag}
      • \n} end html << "
      " html end def init_category_to_tagcloud @counts = Hash.new @urls = Hash.new @elapsed_times = Hash.new @conf['category_to_tagcloud.cache'] ||= "#{@cache_path}/category2tagcloud.cache" @limit = nil end def tag_list limit = nil return '' if bot? return '' unless category_enable? begin init_category_to_tagcloud cache = @conf['category_to_tagcloud.cache'] @limit = limit PStore.new(cache).transaction(read_only=true) do |db| break unless db.root?('tagcloud') or db.root?('last_update') break if Time.now.strftime('%Y%m%d').to_i > db['last_update'] @counts = db['tagcloud'][0] @urls = db['tagcloud'][1] @elapsed_times = db['tagcloud'][2] end gen_tag_list if @urls.empty? print_html rescue TypeError '

      category plugin does not support category_to_tagcloud plugin. use category_legacy plugin instead of categoty plugin.

      ' end end def styleclass diff c = ' old' if diff > 30 c = " oldest" elsif diff > 14 c = " older" elsif diff < 7 c = " hot" end c end def gen_tag_list init_category_to_tagcloud if @mode == 'append' or @mode == 'replace' cache = @conf['category_to_tagcloud.cache'] info = Category::Tagcloud_Info.new(@cgi, @years, @conf) categorized = @category_cache.categorize(info.category, info.years) categorized.keys.each do |key| count = categorized[key].size ymd = categorized[key].keys.sort.reverse diff = (Time.now - Time.local(ymd[0][0,4], ymd[0][4,2], ymd[0][6,2])) / 86400 url = "#{@conf.index}?category=#{CGI.escape(key)}" add(key, url, count, "#{styleclass(diff.to_i)}") end PStore.new(cache).transaction do |db| db['last_update'] = Time.now.strftime('%Y%m%d').to_i db['tagcloud'] = [@counts, @urls, @elapsed_times] end end def tagcloud_css r = '' r = "\t\n" r end add_update_proc do gen_tag_list if @mode == 'append' or @mode == 'replace' end add_header_proc do tagcloud_css unless @conf['tagcloud.hidecss'] end if category_enable? module Category class Tagcloud_Info < Info def years now_year = Time.now.year now_month = Time.now.month r = Hash.new months = [ ['01'],['01','02'],['01','02','03'],['02','03','04'],['03','04','05'], ['04','05','06'],['05','06','07'],['06','07','08'],['07','08','09'], ['08','09','10'],['09','10','11'],['10','11','12'] ][now_month - 1] r[now_year.to_s] = months case now_month when 1 r["#{now_year - 1}"] = ['11','12'] when 2 r["#{now_year - 1}"] = ['12'] end r end end end end ## vim: ts=3 tdiary-contrib-5.0.8/plugin/cocomment.rb000066400000000000000000000017321325711763500203020ustar00rootroot00000000000000# cocomment.rb $Revision: 1.6 $ # # Copyright (C) 2006 by Hiroshi SHIBATA # You can redistribute it and/or modify it under GPL2. # if @mode == 'day' and not bot? add_body_enter_proc do |date| <<-SCRIPT SCRIPT end end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vi: ts=3 sw=3 tdiary-contrib-5.0.8/plugin/code-prettify.rb000066400000000000000000000005711325711763500210740ustar00rootroot00000000000000# Source code embedded plugin for tDiary. # Copyright (C) 2012 Koichiro Ohba # License under MIT. add_header_proc do <<-EOS EOS end def code(content, lang = nil) <<-EOS
      #{content}
      EOS end tdiary-contrib-5.0.8/plugin/coderay.rb000066400000000000000000000036271325711763500177510ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # coderay.rb - easy syntax highlighting for selected languages # refer to the URL below. # http://coderay.rubychan.de/ # # Copyright (C) 2013, tamoot # You can redistribute it and/or modify it under GPL2. # require 'cgi' require 'erb' require 'coderay' @coderay_default_css ||= ::CodeRay::Encoders[:html]::CSS.new(:default).stylesheet def coderay(lang, text, options = {}) html = ::CodeRay.scan(text, lang).html(:line_numbers => :inline, :bold_every => false, :line_number_anchors => false) %Q|
      #{html}
      | end add_header_proc do coderay_css = '' if @conf['coderay.css.url'] && @conf['coderay.css.url'].size > 0 coderay_css = %Q|| else coderay_css = <<-STYLE STYLE end coderay_css end add_conf_proc( 'coderay', 'CodeRay' ) do if @mode == 'saveconf' then @conf['coderay.css.url'] = @cgi.params['coderay.css.url'][0] end coderay_conf = <<-HTML

      custom style

      The stylesheet path is used instead of CodeRay default.

      Path:

         sample:
         #{CGI::escape_html('')}
         

      Print default stylesheet of CodeRay

      1. The coderay command installed along with the CodeRay gem can print out a stylesheet for you.

         bundle exec coderay stylesheet > /your/tdiary/path/coderay.css
         

      2. Edit your stylesheet and modify permissions.

      HTML coderay_conf end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/plugin/coderwall.rb000066400000000000000000000014631325711763500202730ustar00rootroot00000000000000require 'open-uri' require 'timeout' require 'json' def coderwall(name, size = [60, 60]) begin cache = "#{@cache_path}/coderwall.json" json = File.read(cache) File::delete(cache) if Time::now > File::mtime( cache ) + 60*60*24 rescue Errno::ENOENT begin Timeout.timeout(10) do json = open( "https://coderwall.com/#{name}.json" ) {|f| f.read } end open(cache, 'wb') {|f| f.write(json) } rescue Timeout::Error return "" end end html = '
      ' JSON.parse(json)['badges'].each do |badge| html << %Q|#{badge['name']}| end html << '
      ' end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/plugin/comment_pushbullet.rb000077500000000000000000000053511325711763500222330ustar00rootroot00000000000000# -*- coding: utf-8 -*- # comment_pushbullet.rb # # メールの代わりにPushbulletサービスを使ってツッコミを知らせる # プラグインを有効にした上で、Access Tokenを設定する # # Options: # 設定画面から指定できるもの # @options['comment_pushbullet.access_token'] # 自分のPushbulletアカウントのAccess Token https://www.pushbullet.com/account # 設定画面から指定できるもの(ツッコミメールと共通) # @options['comment_mail.enable'] # メールを送るかどうかを指定する。true(送る)かfalse(送らない)。 # 無指定時はfalse。 # @options['comment_mail.header'] # メールのSubjectに使う文字列。振り分け等に便利なように指定する。 # 実際のSubjectは「指定文字列:日付-1」のように、日付とコメント番号が # 付く。ただし指定文字列中に、%に続く英字があった場合、それを # 日付フォーマット指定を見なす。つまり「日付」の部分は # 自動的に付加されなくなる(コメント番号は付加される)。 # 無指定時には空文字。 # # tdiary.confでのみ指定できるもの: # # Copyright (c) 2015 TADA Tadashi # You can distribute this file under the GPL2 or any later version. # def comment_pushbullet require 'pushbullet_ruby' header = (@conf['comment_mail.header'] || '').dup header << ":#{@conf.date_format}" unless /%[a-zA-Z%]/ =~ header serial = @diaries[@date.strftime('%Y%m%d')].count_comments(true) title = %Q|#{@date.strftime(header)}-#{serial} #{@comment.name}| body = @comment.body.sub( /[\r\n]+\Z/, '' ) link = @conf.base_url + anchor(@date.strftime('%Y%m%d')) + '#c' + "%02d"%serial client = PushbulletRuby::Client.new(@conf['comment_pushbullet.access_token']) params = {title: title, url: link, body: body} client.push_link(id: client.me, params: params) end add_update_proc do comment_pushbullet if @mode == 'comment' end add_conf_proc( 'comment_mail', comment_mail_conf_label, 'tsukkomi' ) do comment_mail_basic_setting comment_mail_basic_html end add_conf_proc( 'comment_pushbullet', 'Pushbullet', 'tsukkomi' ) do if @mode == 'saveconf' then @conf['comment_pushbullet.access_token'], = @cgi.params['comment_pushbullet.access_token'] end <<-HTML

      Pushbullet Access Token

      Access Token (see https://www.pushbullet.com/account)

      HTML end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: tdiary-contrib-5.0.8/plugin/datepicker.rb000066400000000000000000000011651325711763500204310ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # datepickr.rb - show jQuery UI datepicker # # Copyright (C) 2012, tamoot # You can redistribute it and/or modify it under GPL. # # # not support # return if feed? if /\A(?:form|preview|append|edit|update)\z/ =~ @mode enable_js('//ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js') if @conf.lang == 'ja' enable_js('//ajax.googleapis.com/ajax/libs/jqueryui/1/i18n/jquery.ui.datepicker-ja.min.js') end enable_js('datepicker.js') end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/plugin/day2section.rb000066400000000000000000000006171325711763500205430ustar00rootroot00000000000000# # day2section.rb - tDiary plugin # # When a visitor accesses to day page without section anchor, navigate to first section. # # Copyright (c) MATSUOKA Kohei # Distributed under the GPL # add_footer_proc do if @mode == 'day' <<-SCRIPT SCRIPT end end tdiary-contrib-5.0.8/plugin/del_footer.rb000066400000000000000000000050021325711763500204320ustar00rootroot00000000000000=begin delicious.rb Delicious から その日付分のメモを取ってきて表示するプラグイン tdiary.conf で以下を設定します。tDiaryの設定画面からも設定可能です。 @options['delicious.id'] = 'YOUR DELICIOUS ID HERE' @options['delicious.pw'] = 'YOUR DELICIOUS PW HERE' proxy は以下に設定します。 @options['amazon.proxy'] = 'PROXY_HOST:PORT' reference: * mm_footer.rb by ishinao san * rss-show.rb (in Hiki) by TAKEUCHI Hitoshi san * fujisan.rb by Michitaka Ohno. =end require 'net/https' require 'rexml/document' require 'fileutils' def delicious_save_cache cache_file, file FileUtils.mkdir_p "#{@cache_path}/delicious" File.open("#{@cache_path}/delicious/#{cache_file}", 'w') do |f| f.flock(File::LOCK_EX) f.puts file f.flock(File::LOCK_UN) end end def delicious_parse_xml(xml) posts = [] REXML::Document.new(xml).elements.each("posts/post") do |post| post = <<-EOS
    • #{post.attribute("description").to_s}
    • EOS posts << post.delete("\r\n") end return posts end def delicious_get_html(date = Date.now) req = Net::HTTP::Get.new "/v1/posts/get?dt=#{date.strftime('%Y-%m-%d')}" req.basic_auth @options['delicious.id'], @options['delicious.pw'] https = Net::HTTP.new('api.del.icio.us', 443) https.use_ssl = true parsed = https.start {|w| response = w.request(req) delicious_parse_xml(response.body) } delicious_save_cache date.strftime("%Y-%m-%d"), parsed end add_edit_proc do |date| delicious_get_html date nil end add_body_leave_proc do |date| path = "#{@cache_path}/delicious/#{date.strftime('%Y-%m-%d')}" ret = '' if File.exist? path File.open(path) do |file| ret = <<-EOS

      Delicious

        #{file.read}
      EOS end end ret end def delicious_init @conf['delicious.id'] ||= "" @conf['delicious.pw'] ||= "" @conf['delicious.title'] ||= "Todey's URL Clip" end add_conf_proc( 'delicious', @delicious_label_conf ) do delicious_conf_proc end def delicious_conf_proc if @mode == 'saveconf' then @conf['delicious.id'] = @cgi.params['delicious.id'][0] @conf['delicious.pw'] = @cgi.params['delicious.pw'][0] end delicious_init <<-HTML

      #{@delicious_label_id}

      #{@delicious_label_pw}

      HTML end tdiary-contrib-5.0.8/plugin/description_from_body.rb000066400000000000000000000011131325711763500226720ustar00rootroot00000000000000# # description_from_body.rb - set meta description by first section's body in day mode # # Copyright (C) 2011, TADA Tadashi # You can redistribute it and/or modify it under GPL. # alias description_tag_dfb_orig description_tag def description_tag if @mode == 'day' then diary = @diaries[@date.strftime '%Y%m%d'] return '' unless diary body = '' diary.each_section do |sec| body = remove_tag( apply_plugin( sec.body_to_html ) ).strip break end %Q|| else description_tag_dfb_orig end end tdiary-contrib-5.0.8/plugin/development.rb000066400000000000000000000007011325711763500206330ustar00rootroot00000000000000# development.rb - utility methods for plugin developers # # Copyright (c) 2011 MATSUOKA Kohei # You can redistribute it and/or modify it under GPL2. # # load standard version jquery.js instead of jquery.min.js alias :jquery_tag_original :jquery_tag def jquery_tag jquery_tag_original.gsub(/\.min/, '') end # js cache clear by seconds. def script_tag_query_string "?#{TDIARY_VERSION}#{Time::now.strftime('%Y%m%d%H%M%S')}" end tdiary-contrib-5.0.8/plugin/editor.rb000066400000000000000000000003761325711763500176070ustar00rootroot00000000000000# # editor.rb - support writing using wiki/gfm notation. # # Copyright (c) 2012 MATSUOKA Kohei # You can distribute it under GPL. # # load javascript if /\A(form|edit|preview|showcomment)\z/ === @mode then enable_js('editor.js') end tdiary-contrib-5.0.8/plugin/en/000077500000000000000000000000001325711763500163705ustar00rootroot00000000000000tdiary-contrib-5.0.8/plugin/en/add_bookmark.rb000066400000000000000000000007751325711763500213430ustar00rootroot00000000000000# en/add_bookmark.rb $Revision 1.3 $ # # English resource of add_bookmark.rb # You can redistribute it and/or modify it under GPL2. # @add_bookmark_label = 'add to bookmark' @add_bookmark_desc = 'Please check the link that wants to be displayed.' @caption_delicious = 'add to del.icio.us' @caption_hatena = 'add to Hatena bookmark' @caption_livedoor = 'add to livedoor clip' @caption_buzzurl = 'add to Buzzurl' @bookmark_label = [ 'del.icio.us', 'Hatena bookmark', 'livedoor Clip', 'Buzzurl' ] tdiary-contrib-5.0.8/plugin/en/category-lite.rb000066400000000000000000000025271325711763500214730ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # en/category-lite.rb : tDiary plugin for show category pages (light edition) # # Copyright (C) 2015 TADA Tadashi # Distributed under the GPL2 or any later version. # @category_conf_label = 'Category' def category_conf_html r = <<-HTML

      Build category index

      To use the category feature, you should build category index. Check the box below and press OK to build category index.

      It takes several or several tens of second to create it. But your diaries are many or the server has low spec, it will be timeout. Rebuild index on off-line again.

      Edit Support

      Category names can be shown under the 'Article' form.

      HTML r end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/plugin/en/del_footer.rb000066400000000000000000000004241325711763500210370ustar00rootroot00000000000000# # English resource of delicious plugin $Revision: 1.0 $ # # Copyright (C) 2006 SHIBATA Hiroshi # You can redistribute it and/or modify it under GPL2. # @delicious_label_conf = 'del.icio.us' @delicious_label_id = 'User ID' @delicious_label_pw = 'Password' tdiary-contrib-5.0.8/plugin/en/git-register.rb000066400000000000000000000002541325711763500213230ustar00rootroot00000000000000@estraier_register_conf_label = 'Git' @estraier_register_conf_header = 'commit all' @estraier_register_conf_description = 'To commit all, check the box and submit \'OK\'.' tdiary-contrib-5.0.8/plugin/en/livedoor_weather.rb000066400000000000000000000017521325711763500222640ustar00rootroot00000000000000# # English resource of livedoor_weather plugin $Revision$ # # Copyright (C) 2006 SHIBATA Hiroshi # You can redistribute it and/or modify it under GPL2. # # # setting of tdiary.conf # @options['lwws.city_id'] : City ID where weather information is specified. # @lwws_plugin_name = 'livedoor weather' @lwws_label_city_id = 'City ID' @lwws_desc_city_id = 'City ID where weather information is specified. Please select City ID from among Point definition table(RSS)' @lwws_label_disp_item = 'View items' @lwws_desc_disp_item = 'Please select the item to want to display.' @lwws_icon_label = 'Icon' @lwws_icon_desc = 'Weather information is displayed in the icon. ' @lwws_max_temp_label = 'Max Tempreture' @lwws_min_temp_label = 'Min Tempreture' @celsius_label = 'C' @lwws_label_cache = 'Auto update of cache' @lwws_desc_cache = 'Enable auto update.' @lwws_desc_cache_time = 'Please set number of update time.' tdiary-contrib-5.0.8/plugin/en/microsummary.rb000066400000000000000000000010041325711763500214370ustar00rootroot00000000000000# ja/microsummary.rb # # Japanese resources for microsummary.rb # # Copyright (c) 2006 elytsllams # Distributed under the GPL # if @mode == 'conf' || @mode == 'saveconf' add_conf_proc( 'microsummary', 'Microsummary Generator' ) do saveconf_microsummary microsummary_init <<-HTML

      URI for microsummary generator XML

      HTML end end tdiary-contrib-5.0.8/plugin/en/nicovideo.rb000066400000000000000000000027421325711763500207010ustar00rootroot00000000000000# # ja/nicovideo.rb - Japanese resource # # Copyright (C) TADA Tadashi # Distributed under GPL. # def nicovideo_feed( i ) <<-HTML
      #{h i[:title]} #{h i[:title]} (#{i[:length]})
      HTML end def nicovideo_html( i ) <<-HTML
      #{h i[:title]}

      #{h i[:title]} (#{i[:length].split(/:/).map{|j|'%02d' % j.to_i}.join(':')})

      #{i[:date][0,10]} Posted
      #{i[:view].scan(/\d+?(?=\d{3}*$)/).join(",")} Views
      #{i[:comment_num].scan(/\d+?(?=\d{3}*$)/).join(",")} Comments
      #{i[:mylist].scan(/\d+?(?=\d{3}*$)/).join(",")} Mylists

      HTML end tdiary-contrib-5.0.8/plugin/en/openid.rb000066400000000000000000000004041325711763500201710ustar00rootroot00000000000000# openid.rb: English resource @openid_conf_label = 'OpenID' @openid_service_label = 'OpenID Service' @openid_service_desc = 'select your OpenID service name.' @openid_id_label = 'Your ID' @openid_id_desc = 'Specify your ID of OpenID service selected above.' tdiary-contrib-5.0.8/plugin/en/profile.rb000066400000000000000000000003661325711763500203620ustar00rootroot00000000000000# # profile.rb: english resource of profile plugin for tDiary # # Copyright (C) 2017 by Tada, Tadashi # Distributed under the GPL. # module ::Profile module Service class Gravatar < Base HOST = 'en.gravatar.com' end end end tdiary-contrib-5.0.8/plugin/en/section_footer.rb000066400000000000000000000005511325711763500217400ustar00rootroot00000000000000# section_footer.rb: English resource @section_footer_delicious_label = "del.icio.us history for this entry" @section_footer_hatenabm_label = "this entry on Hatena Bookmark" @section_footer_ldclip_label = "this entry on livedoor clip" @section_footer_buzzurl_label = "this entry on Buzzurl" @section_footer_yahoobm_label = "this entry on Yahoo! JAPAN Bookmark" tdiary-contrib-5.0.8/plugin/en/section_footer2.rb000066400000000000000000000002171325711763500220210ustar00rootroot00000000000000# section_footer2.rb: English resource @section_footer2_delicious_label = "Delicious history for this entry" @section_footer2_locale = 'en_US' tdiary-contrib-5.0.8/plugin/en/socialbutton.rb000066400000000000000000000003741325711763500214270ustar00rootroot00000000000000# -*- coding: utf-8 -*- # section_footer2.rb: English resource @socialbutton_label_conf = 'Social buttons' @socialbutton_label_enables = 'enable social button names' @socialbutton_label_twitter_via = 'screen name of the user to attribute the tweet to' tdiary-contrib-5.0.8/plugin/everytrail.rb000066400000000000000000000054601325711763500205060ustar00rootroot00000000000000# # everytrail.rb: plugin embedding trip map on everytrail.com. # # Copyright (C) 2010 TADA Tadashi # You can redistribute it and/or modify it under GPL2. # def everytrail_adjust_size( size ) s = size.collect {|i| i.to_i } s[0] = 400 if s[0] == 0 s[1] = 300 if s[1] == 0 s end def everytrail( trip_id, label = nil, size = [400, 300] ) size = everytrail_adjust_size( size ) r = %Q|
      | end def everytrail_flash( trip_id, label = nil, size = [400, 300] ) size = everytrail_adjust_size( size ) %Q|
      | end def everytrail_widget( trip_id, latitude = nil, longtitude = nil, label = nil, size = [400, 300] ) size = everytrail_adjust_size( size ) lat_param = latitude ? "&startLat=#{latitude}" : '' lon_param = longtitude ? "&startLon=#{longtitude}" : '' r = label ? %Q|

      #{h label}

      | : '' r << %Q|
      Map your trip with EveryTrail| end tdiary-contrib-5.0.8/plugin/facebook_comments.rb000066400000000000000000000040401325711763500217670ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2011, KADO Masanori # You can redistribute it and/or modify it under GPL. add_header_proc do <<-HTML HTML end def facebook_comments(href = '') <<-HTML
      HTML end add_body_leave_proc do |date| if @mode == 'day' href = @conf.base_url + anchor( @date.strftime('%Y%m%d') ) facebook_comments(href) end end add_conf_proc( 'Facebook Comments', 'Facebook Comments', 'etc' ) do if @mode == 'saveconf' then @conf['facebook_comments.YOUR_FACEBOOK_USER_ID'] = @cgi.params['facebook_comments.YOUR_FACEBOOK_USER_ID'][0] @conf['facebook_comments.YOUR_APPLICATION_ID'] = @cgi.params['facebook_comments.YOUR_APPLICATION_ID'][0] @conf['facebook_comments.num_posts'] = @cgi.params['facebook_comments.num_posts'][0] @conf['facebook_comments.width'] = @cgi.params['facebook_comments.width'][0] end <<-HTML

      YOUR_FACEBOOK_USER_ID

      YOUR_APPLICATION_ID

      num posts

      width

      HTML end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/plugin/flickr.rb000066400000000000000000000163541325711763500175760ustar00rootroot00000000000000# -*- coding: utf-8 -*- # show photo image on Flickr.com # # usage: # flickr(photo_id[, size[, place]]) # - photo_id: The id of the photo to show. # - size: Size of photo. (optional) # Choose from square, thumbnail, small, medium, or large. # - place: class name of img element. default is 'flickr'. # # flickr_left(photo_id[, size]) # # flickr_right(photo_id[, size]) # # options configurable through settings: # @conf['flickr.apikey'] : a key for access Flickr API # @conf['flickr.default_size'] : default image size # # Copyright (c) MATSUOKA Kohei # Distributed under the GPL # require 'net/https' require 'digest/md5' require 'rexml/document' @conf['flickr.apikey'] ||= 'f7e7fb8cc34e52db3e5af5e1727d0c0b' @conf['flickr.default_size'] ||= 'medium' if /\A(form|edit|preview|showcomment)\z/ === @mode then enable_js('flickr.js') add_js_setting('$tDiary.plugin.flickr') add_js_setting('$tDiary.plugin.flickr.apiKey', %Q|'#{@conf['flickr.apikey']}'|) add_js_setting('$tDiary.plugin.flickr.userId', %Q|'#{@conf['flickr.user_id']}'|) end def flickr(photo_id, size = nil, place = 'flickr') if @conf['flickr.apikey'] == nil || @conf['flickr.apikey'].empty? return '[ERROR] flickr.rb: API Key is not specified.' end size ||= @conf['flickr.default_size'] photo = flickr_photo_info(photo_id.to_s, size) unless photo return '[ERROR] flickr.rb: failed to get photo.' end %Q|#{photo[:title]}| end def flickr_left(photo_id, size = nil) flickr(photo_id, size, 'left') end def flickr_right(photo_id, size = nil) flickr(photo_id, size, 'right') end def flickr_photo_info(photo_id, size) photo = {} begin flickr_open('flickr.photos.getInfo', photo_id) {|f| if defined?(Oga) res = Oga.parse_xml(f) photo[:page] = res.xpath('/rsp/photo/urls/url').text photo[:title] = res.xpath('/rsp/photo/title').text else res = REXML::Document.new(f) photo[:page] = res.elements['//rsp/photo/urls/url'].text photo[:title] = res.elements['//rsp/photo/title'].text end } flickr_open('flickr.photos.getSizes', photo_id) {|f| if defined?(Oga) res = Oga.parse_xml(f) res.xpath('//rsp/sizes/size').each do |s| if s.get('label').downcase == size.downcase photo[:src] = s.get('source') photo[:width] = s.get('width') photo[:height] = s.get('height') end end else res = REXML::Document.new(f) res.elements.each('//rsp/sizes/size') do |s| if s.attributes['label'].downcase == size.downcase photo[:src] = s.attributes['source'] photo[:width] = s.attributes['width'] photo[:height] = s.attributes['height'] end end end } rescue Exception => e return nil end photo end def flickr_open(method, photo_id) cache_dir = "#{@cache_path}/flickr" Dir::mkdir(cache_dir) unless File::directory?(cache_dir) file = "#{cache_dir}/#{photo_id}.#{method}" if !File.exist?(file) || File.size(file) == 0 req = Flickr::Request.new(@conf['flickr.apikey']) req['method'] = method req['photo_id'] = photo_id begin Timeout.timeout(5) do open(file, 'w') {|fout| fout.puts req.open } end rescue TimeoutError, OpenSSL::OpenSSLError => e File.delete(file) raise e end end open(file) {|f| yield f } end # delete cache files def flickr_clear_cache cache_dir = "#{@cache_path}/flickr" Dir.glob("#{cache_dir}/*.flickr.photos.{getInfo,getSizes}") do |cache| # File.unlink(cache) File.rename(cache, "#{cache}.org") end end FLICKER_FORM_PID = 'plugin_flickr_pid' add_edit_proc do |date| <<-FORM
      Flickr:
      Photo size:
      FORM end def flickr_slideshow(tag, id = nil) id ||= @conf['flickr.id'] return unless id %Q|| end def flickr_slideshow_by_set(set_id) return unless set_id %Q|| end module Flickr class Request < Hash def initialize(api_key, secret = nil) self['api_key'] = api_key @secret = secret end def open Net::HTTP.version_1_2 https = Net::HTTP.new('www.flickr.com', 443) https.use_ssl = true https.start { response = https.get(query) response.body } end def query sign = @secret ? "&api_sig=#{signature}" : '' base_path + sort.map{|key, val| "#{key}=#{val}" }.join('&') + sign end def signature data = sort.map{|key, val| "#{key}#{val}" }.join Digest::MD5.hexdigest("#{@secret}#{data}") end def base_path '/services/rest/?' end end class RequestAuth < Request def base_path '/services/auth/?' end end end tdiary-contrib-5.0.8/plugin/gist.rb000066400000000000000000000010121325711763500172530ustar00rootroot00000000000000# show code snippet via gist.github.com # # usage: # gist(gist_id) # - gist_id: The id of the code snippet on gitst.github.com (e.g. 2056 for http://gist.github.com/2056) # # Copyright (c) KAKUTANI Shintaro # Distributed under the GPL def gist( gist_id ) gist_snippet_url = "http://gist.github.com/#{gist_id}" return (<<-EOS).chomp EOS end tdiary-contrib-5.0.8/plugin/git-register.rb000066400000000000000000000135261325711763500207270ustar00rootroot00000000000000#!/usr/bin/env ruby # -*- coding: utf-8 -*- # git-register.rb # # Copyright (C) 2011 hajime miyauchi # You can redistribute it and/or modify it under GPL2. # # tDiaryのデータを日別でGitに登録するプラグインです # # 1. プラグインディレクトリ(例: plugin)にgit-register.rbを設置。 # 2. プラグインディレクトリにja/git-register.rb、en/git-register.rbを設置。 # 3. tdiary.confにリポジトリを指定(リポジトリの場所を/var/git-respoと仮定) # @options["git.repository_dir"] = "/var/git-repos" # 4. リポジトリを作成(Apacheの起動ユーザをapacheと仮定) # $ mkdir /var/git-repos # $ cd /var/git-repos # $ git init # $ git config user.name "自分の名前" # $ git config user.email "メールアドレス" # $ chown apache.apache -R /var/git-repos # 5. リポジトリに一括commit(tDiaryのインストールディレクトリを/var/www/tdiaryと仮定) # $ cd /var/www/tdiary # $ ruby --encoding=UTF-8 git-register.rb # mode = "" if $0 == __FILE__ require 'cgi' ARGV << '' # dummy argument against cgi.rb offline mode. @cgi = CGI::new mode = "CMD" else mode = "PLUGIN" end if mode == "PLUGIN" add_body_leave_proc do |date| end end unless $tdiary_git_register_loaded $tdiary_git_register_loaded ||= true if mode == "CMD" tdiary_path = "." tdiary_conf = "." $stdout.sync = true def usage puts "git-register.rb" puts " register to git index files from tDiary's database." puts " usage: ruby --encoding=UTF-8 git-register.rb [-p ] [-c ]" exit end require 'getoptlong' parser = GetoptLong::new parser.set_options(['--path', '-p', GetoptLong::REQUIRED_ARGUMENT], ['--conf', '-c', GetoptLong::REQUIRED_ARGUMENT]) begin parser.each do |opt, arg| case opt when '--path' tdiary_path = arg when '--conf' tdiary_conf = arg end end rescue usage exit( 1 ) end tdiary_conf = tdiary_path unless tdiary_conf Dir::chdir( tdiary_conf ) begin $:.unshift tdiary_path require "#{tdiary_path}/tdiary" rescue LoadError $stderr.puts "git-register.rb: cannot load tdiary.rb. <#{tdiary_path}/tdiary>\n" $stderr.puts " usage: ruby --encoding=UTF-8 git-register.rb [-p ] [-c ]" exit( 1 ) end end module ::TDiary # # Register # class GitRegister < TDiaryBase def initialize(repository_dir, diary) @repository_dir = repository_dir @diary = diary @date = diary.date end def execute() dir = @date.strftime("#{@repository_dir}%Y%m/") Dir::mkdir( dir ) unless FileTest::directory?( dir ) td2_file = @date.strftime("#{dir}%Y%m%d.td2") fh = File::open(td2_file, 'w') fh.puts( "Date: #{@date}" ) fh.puts( "Title: #{@diary.title}" ) fh.puts( "Last-Modified: #{@diary.last_modified.to_i}" ) fh.puts( "Visible: #{@diary.visible? ? 'true' : 'false'}" ) fh.puts( "Format: #{@diary.style}" ) fh.puts fh.puts( @diary.to_src.gsub( /\r/, '' ).gsub( /\n\./, "\n.." ) ) fh.close # commit require 'shellwords' msg = "#{ENV['REMOTE_ADDR']} - #{ENV['REMOTE_HOST']}" Dir.chdir("#{@repository_dir}") do td2_file2 = @date.strftime("%Y%m/%Y%m%d.td2") system("git add -- #{Shellwords.shellescape(td2_file2)}".untaint) system("git commit -q -m \"#{msg}\" -- #{Shellwords.shellescape(td2_file2)}".untaint) end end protected def mode; 'day'; end def cookie_name; ''; end def cookie_mail; ''; end def convert(str) str end end # # Main # class GitRegisterMain < TDiaryBase def initialize(conf) super(CGI::new, 'day.rhtml', conf) end def execute(out = $stdout) require 'fileutils' repository_dir = @conf['git.repository_dir'] calendar @years.keys.sort.reverse_each do |year| out << "(#{year.to_s}/) " @years[year.to_s].sort.reverse_each do |month| @io.transaction(Time::local(year.to_i, month.to_i)) do |diaries| diaries.sort.reverse_each do |day, diary| out << diary.date.strftime('%m%d ') GitRegister.new(repository_dir, diary).execute end false end end end end end end if mode == "CMD" begin require 'cgi' if TDiary::Config.instance_method(:initialize).arity != 0 # for tDiary 2.1 or later cgi = CGI.new conf = TDiary::Config::new(cgi) else # for tDiary 2.0 or earlier conf = TDiary::Config::new end conf.header = '' conf.footer = '' conf.show_comment = true conf.hide_comment_form = true conf.show_nyear = false def conf.bot?; true; end TDiary::GitRegisterMain.new(conf).execute rescue print $!, "\n" $@.each do |v| print v, "\n" end exit( 1 ) end puts else add_update_proc do conf = @conf.clone conf.header = '' conf.footer = '' conf.show_comment = true conf.hide_comment_form = true conf.show_nyear = false def conf.bot?; true; end repository_dir = @conf['git.repository_dir'] diary = @diaries[@date.strftime('%Y%m%d')] TDiary::GitRegister.new(repository_dir, diary).execute end if !@conf['git.hideconf'] && (@mode == 'conf' || @mode == 'saveconf') args = ['git_register', @git_register_conf_label] args << 'update' if TDIARY_VERSION > '2.1.3' add_conf_proc(*args) do str = <<-HTML

      #{@git_register_conf_header}

      HTML if @mode == 'saveconf' if @cgi.valid?( 'git_register_rebuild' ) str << '

      The following diaries were registered.

      ' out = '' TDiary::GitRegisterMain.new(@conf).execute(out) str << "

      #{out}

      " end end str end end end end # $tdiary_git_register_loaded # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: tdiary-contrib-5.0.8/plugin/github_badge.rb000066400000000000000000000020231325711763500207140ustar00rootroot00000000000000# Github Badge, by drnic plugin. # http://drnicjavascript.rubyforge.org/github_badge/ # # usage: # github_badge(username, list_length, head, theme, title, show_all) # - username: user name on github.com # - list_length: project list length # - theme: specify theme for badge. "white" or "black". # - title: top text display on the badge. # - show_all: 'Show All' message. # # Copyright (c) 2008 KAKUTANI Shintaro # Distributed under the GPL def github_badge( username, list_length = 10, head = "div", theme = "white", title = "My Projects", show_all = "Show all" ) return (<<-EOS).chomp
      EOS end tdiary-contrib-5.0.8/plugin/github_link.rb000066400000000000000000000004061325711763500206120ustar00rootroot00000000000000def gh_link(gh_identifier, text=nil) text = gh_identifier.split('/').last if text.nil? id_and_name, number = gh_identifier.split('#') url = "https://github.com/#{id_and_name}" url = url + "/issues/#{number}" if number "#{h text}" end tdiary-contrib-5.0.8/plugin/goo_gl.rb000066400000000000000000000020631325711763500175620ustar00rootroot00000000000000# # goo_gl.rb - shorten URL by goo.gl # # usage: shorten_url_you_got = goo_gl( 'long_url' ) || long_url # # Copyright (C) 2011, tamoot # You can redistribute it and/or modify it under GPL. # require 'json' require 'net/https' def goo_gl( long_url ) return nil if !long_url or long_url.empty? # on memory @goo_gl_cache ||= {} # cached only on memory return @goo_gl_cache[long_url] if @goo_gl_cache[long_url] # proxy px_host, px_port = (@conf['proxy'] || '').split( /:/ ) px_port = 80 if px_host and !px_port # params params = {'longUrl' => long_url}.to_json https = nil begin https = Net::HTTP::Proxy(px_host, px_port).new('www.googleapis.com', 443) https.use_ssl = true res, body = https.post("/urlshortener/v1/url", params, {'Content-Type' => 'application/json'}) @goo_gl_cache[long_url] = JSON::parse(body)["id"] if res.code == '200' rescue Exception => e # do nothing.. ensure https.finish if https && https.started? end return @goo_gl_cache[long_url] end tdiary-contrib-5.0.8/plugin/google_adsense.rb000066400000000000000000000142701325711763500212750ustar00rootroot00000000000000# # Google AdSense plugin for tDiary # # Copyright (C) 2004 Kazuhiko # You can redistribute it and/or modify it under GPL2. # # modified by TADA Tadashi # def google_adsense( layout = nil, slot = nil ) google_adsense_init( layout ) google_ad_client = "pub-3317603667498586" google_ad_size = [ [468, 60], # 0 [120, 600], # 1 [728, 90], # 2 [300, 250], # 3 [125, 125], # 4 [160, 600], # 5 [120, 240], # 6 [180, 150], # 7 [250, 250], # 8 [336, 280], # 9 [200, 200], # 10 [234, 60] # 11 ] result = <<-EOF EOF result.gsub( /^\t+/, '' ) end def google_adsense_init( layout ) if layout != nil then @conf['google_adsense.layout'] = layout.to_i else @conf['google_adsense.layout'] = 0 unless @conf['google_adsense.layout'] end @conf['google_adsense.layout'] = @conf['google_adsense.layout'].to_i if @conf['google_adsense.layout'] < 0 or @conf['google_adsense.layout'] > 11 then @conf['google_adsense.layout'] = 0 end @conf['google_adsense.color.border'] = 'CCCCCC' unless @conf['google_adsense.color.border'] @conf['google_adsense.color.bg'] = 'FFFFFF' unless @conf['google_adsense.color.bg'] @conf['google_adsense.color.link'] = '000000' unless @conf['google_adsense.color.link'] @conf['google_adsense.color.url'] = '666666' unless @conf['google_adsense.color.url'] @conf['google_adsense.color.text'] = '333333' unless @conf['google_adsense.color.text'] end add_section_leave_proc do |date,index| if @mode == 'day' and index == 1 and @conf['google_adsense.slot'] then %Q|
      #{google_adsense( 0, @conf['google_adsense.slot'] )}
      | else '' end end # insert section target tags add_body_enter_proc do |date| "\n" end add_body_leave_proc do |date| "\n" end add_conf_proc( 'google_adsense', 'Google AdSense' ) do if @mode == 'saveconf' then @conf['google_adsense.layout'] = @cgi.params['google_adsense.layout'][0].to_i @conf['google_adsense.color.border'] = @cgi.params['google_adsense.color.border'][0] @conf['google_adsense.color.bg'] = @cgi.params['google_adsense.color.bg'][0] @conf['google_adsense.color.link'] = @cgi.params['google_adsense.color.link'][0] @conf['google_adsense.color.url'] = @cgi.params['google_adsense.color.url'][0] @conf['google_adsense.color.text'] = @cgi.params['google_adsense.color.text'][0] else google_adsense_init( nil ) end <<-HTML

      バナーのサイズ(#{@conf['google_adsense.layout']})

      広告バナーのサイズは全部で12種類あります。お好きなサイズを選んでください。

      バナーの色

      バナーの各パーツの色を指定できます。HTMLやCSSと同じ、6桁の16進数で指定します。

        
      背景  
      リンク  
      URL  
      テキスト  
      HTML end tdiary-contrib-5.0.8/plugin/google_analytics.rb000066400000000000000000000042001325711763500216320ustar00rootroot00000000000000# # Google Analytics plugin for tDiary # # Copyright (C) 2005 TADA Tadashi # You can redistribute it and/or modify it under GPL2. # if /^(?:latest|day|month|nyear|search)$/ =~ @mode then add_footer_proc do google_analytics_insert_code end end def google_analytics_insert_code return '' unless @conf['google_analytics.profile'] <<-HTML HTML end # UA-53836-1 add_conf_proc( 'google_analytics', 'Google Analytics' ) do if @mode == 'saveconf' then @conf['google_analytics.profile'] = @cgi.params['google_analytics.profile'][0] @conf['google_analytics.amp.profile'] = @cgi.params['google_analytics.amp.profile'][0] end r = <<-HTML

      Google Analytics Profile

      set your Profile ID (NNNNN-N)

      HTML if defined? AMP r << <<-HTML

      Google Analytics Profile for AMP page

      set your Profile ID (NNNNN-N) for AMP page

      HTML end r end if defined? AMP add_amp_header_proc do %Q|| end add_amp_body_enter_proc do profile_id = %w(google_analytics.amp.profile google_analytics.profile).map {|key| @conf[key] }.find {|profile| profile && !profile.empty? } <<-HTML HTML end end tdiary-contrib-5.0.8/plugin/google_map.rb000066400000000000000000000140131325711763500204230ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # google_map.rb - embeded Google Map for tDiary, use Google Maps JavaScript API V3. # http://code.google.com/intl/ja/apis/maps/documentation/v3/services.html # # Copyright (C) 2010, tamoot # You can redistribute it and/or modify it under GPL2. # def google_map(lat, lon, params = {}) params.merge!(:lat => lat, :lon => lon) google_map_common(params) end def google_geomap(address, params = {}) params.merge!(:address => address) google_map_common(params) end def google_map_common(params) params[:id] ||= '' params[:lat] ||= 0.0 params[:lon] ||= 0.0 params[:address] ||= nil params[:zoom] ||= 10 params[:html] ||= nil params[:title] ||= nil params[:width] ||= 320 params[:height] ||= 240 params[:type] ||= :ROADMAP params[:overview]||= false if feed? require 'cgi' url = nil if params[:lat].nonzero? && params[:lon].nonzero? query = "#{params[:lat]},#{params[:lon]}" url = %Q|http://maps.google.com/maps?q=#{CGI::escape(query)}| elsif params[:address] != nil query = params[:address] url = %Q|http://maps.google.com/maps?q=#{CGI::escape(query)}| end return %Q|#{url}| if url end dom_id = "#{@gmap_date.strftime("%Y%m%d")}_#{@gmap_count}" params.merge!(:id => dom_id) @gmap_data << params @gmap_count += 1 %Q|
      | end add_header_proc do if /\A(?:latest|day|month|nyear|preview)\z/ =~ @mode %Q|\n| end end add_body_enter_proc do |date| @gmap_data = [] @gmap_date = date @gmap_count = 0 '' end add_body_leave_proc do |date| gmap_scripts = '' if !feed? && @gmap_data.any? gmap_scripts = %Q|\n| end gmap_scripts end def google_map_script(hash) str = '' str << %Q|google.maps.event.addDomListener(window, 'load', function() {\n| str << %Q| var mapdiv = document.getElementById("#{hash[:id]}");\n| str << %Q| if(mapdiv){\n| str << %Q| var myOptions = {\n| str << %Q| zoom: #{hash[:zoom]},\n| str << %Q| overviewMapControl: #{hash[:overview]},\n| str << %Q| overviewMapControlOptions: {\n| str << %Q| opened: #{hash[:overview]}\n| str << %Q| },\n| str << %Q| center: new google.maps.LatLng(#{hash[:lat]}, #{hash[:lon]}),\n| str << %Q| mapTypeId: google.maps.MapTypeId.#{hash[:type]},\n| str << %Q| scaleControl: true\n| str << %Q| };\n| str << %Q| var gMap = new google.maps.Map(mapdiv, myOptions);\n| # set Marker if hash[:title] str << %Q| var marker = new google.maps.Marker({\n| str << %Q| position: new google.maps.LatLng(#{hash[:lat]}, #{hash[:lon]}),\n| str << %Q| map: gMap,\n| str << %Q| title: '#{hash[:title]}'\n| str << %Q| });\n| # set InfoWindow if hash[:html] str << %Q| var infowindow = new google.maps.InfoWindow({\n| str << %Q| content: '#{hash[:html]}',\n| str << %Q| size: new google.maps.Size(350, 200)\n| str << %Q| });\n| str << %Q| infowindow.open(gMap, marker);\n| end # :html end # :title str << %Q| };\n| str << %Q|});\n| str end def google_geomap_script(hash) str = '' str << %Q|google.maps.event.addDomListener(window, 'load', function() {\n| str << %Q| var mapdiv = document.getElementById("#{hash[:id]}");\n| str << %Q| if(mapdiv){\n| str << %Q| var geocoder = new google.maps.Geocoder();\n| str << %Q| if(geocoder) {\n| str << %Q| geocoder.geocode( { 'address': '#{hash[:address]}'}, function(results, status) {\n| str << %Q| if (status == google.maps.GeocoderStatus.OK) {\n| str << %Q| var geoLat = results[0].geometry.location;\n| str << %Q| var myOptions = {\n| str << %Q| zoom: #{hash[:zoom]},\n| str << %Q| overviewMapControl: #{hash[:overview]},\n| str << %Q| overviewMapControlOptions: {\n| str << %Q| opened: #{hash[:overview]}\n| str << %Q| },\n| str << %Q| center: geoLat,\n| str << %Q| mapTypeId: google.maps.MapTypeId.#{hash[:type]},\n| str << %Q| scaleControl: true\n| str << %Q| };\n| str << %Q| var gMap = new google.maps.Map(mapdiv, myOptions);\n| # set Marker if hash[:title] str << %Q| var marker = new google.maps.Marker({\n| str << %Q| position: geoLat,\n| str << %Q| map: gMap,\n| str << %Q| title: '#{hash[:title]}'\n| str << %Q| });\n| # set InfoWindow if hash[:html] str << %Q| var infowindow = new google.maps.InfoWindow({\n| str << %Q| content: '#{hash[:html]}',\n| str << %Q| size: new google.maps.Size(350, 200)\n| str << %Q| });\n| str << %Q| infowindow.open(gMap, marker);\n| end # :html end # :title str << %Q| }else{\n| str << %Q| alert("Geocode was not successful for the following reason: " + status)\n| str << %Q| }\n| str << %Q| });\n| str << %Q| }\n| str << %Q| }\n| str << %Q|});\n| str end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/plugin/google_photos.rb000066400000000000000000000064631325711763500211740ustar00rootroot00000000000000# -*- coding: utf-8 -*- # show Google Photos # # Copyright (c) MATSUOKA Kohei # Distributed under the GPL # def google_photos(src, width, height, alt="photo", place="photo", scale=nil) scale = scale || @conf['google_photos.scale'] || 100 width = width.to_i * (scale.to_f / 100) height = height.to_i * (scale.to_f / 100) %Q|#{alt}| end def google_photos_left(src, width, height, alt="photo", scale=nil) scale = scale || @conf['google_photos.scale'] || 100 width = width.to_i * (scale.to_f / 100) height = height.to_i * (scale.to_f / 100) google_photos(src, width, height, alt, 'left') end def google_photos_right(src, width, height, alt="photo", scale=nil) scale = scale || @conf['google_photos.scale'] || 100 width = width.to_i * (scale.to_f / 100) height = height.to_i * (scale.to_f / 100) google_photos(src, width, height, alt, 'right') end if /\A(form|edit|preview|showcomment)\z/ === @mode then enable_js('google_photos.js') add_js_setting('$tDiary.plugin.google_photos') add_js_setting('$tDiary.plugin.google_photos.api_key', @conf['google_photos.api_key'].to_json) add_js_setting('$tDiary.plugin.google_photos.client_id', @conf['google_photos.client_id'].to_json) add_footer_proc do '' end end add_edit_proc do |date| <<-FORM
      FORM end add_conf_proc('google_photos', 'Googleフォト') do if @mode == 'saveconf' @conf['google_photos.api_key'] = @cgi.params['google_photos.api_key'][0] @conf['google_photos.client_id'] = @cgi.params['google_photos.client_id'][0] @conf['google_photos.scale'] = @cgi.params['google_photos.scale'][0] @conf['google_photos.scale'] = 100 if @conf['google_photos.scale'].nil? || @conf['google_photos.scale'].empty? end r = <<-_HTML

      概要

      Googleフォトの写真を日記に表示します。

      機能

      • Googleフォトの写真を選択して日記に貼り付ける
      • PC上の写真をGoogleフォトへアップロードする

      制約事項

      • サムネイルを使用しているため、サイズが512pxまでしか表示できません

      使い方

      このプラグインを使うためには、Google Developers ConsoleからAPIキーと認証用クライアントIDを取得する必要があります。 手順はGoogleフォトプラグインを利用するためのAPIキーとクライアントIDの取得手順を参考にしてください。

      APIキー

      認証用クライアントID

      サムネイルからの縮小率 (単位%。数値1〜100)

      _HTML end tdiary-contrib-5.0.8/plugin/google_sitemaps.rb000066400000000000000000000034611325711763500215000ustar00rootroot00000000000000# google_sitemap.rb # Copyright (c) 2006 http://d.bulkitem.com/ # Distributed under the GPL add_update_proc do require 'time' headers = Array.new header = Hash.new Dir.glob(@conf.data_path + '/????/*.td2') { |data_file| File.open(data_file) { |buffer| buffer.each { |line| line.strip! if line == "." then if header['visible'] then headers.push(header.clone) end header.clear end if %r|^Date: ([0-9]+)$|i =~ line then header['loc'] = sprintf(@conf['google_sitemaps.uri_format'], $1) end if %r|^Last-Modified: ([0-9]+)$|i =~ line then header['lastmod'] = Time.at($1.to_i).iso8601 end if %r|^Visible: (.+)$|i =~ line then if $1.upcase == "TRUE" then header['visible'] = true else header['visible'] = false end end } } } headers.sort! { |a, b| b['loc'] <=> a['loc']} top_page_uri = File::dirname(@conf['google_sitemaps.uri_format']) + '/' now_datetime = Time.now.iso8601 File.open(@conf['google_sitemaps.output_file'], 'w') do |fp| fp.write %Q[\n] fp.write %Q[\n] fp.write %Q[ #{CGI::escapeHTML(top_page_uri)}#{now_datetime}\n] headers.each { |entry| fp.write %Q[ #{CGI::escapeHTML(entry['loc'])}#{entry['lastmod']}\n] } fp.write %Q[\n] end end def saveconf_google_sitemaps if @mode == 'saveconf' then @conf['google_sitemaps.uri_format'] = @cgi.params['google_sitemaps.uri_format'][0] @conf['google_sitemaps.output_file'] = @cgi.params['google_sitemaps.output_file'][0] end end tdiary-contrib-5.0.8/plugin/google_universal_analytics.rb000066400000000000000000000024751325711763500237360ustar00rootroot00000000000000# # Google Universal Analytics plugin for tDiary # # Copyright (C) 2014 TSUNEMATSU Shinya # You can redistribute it and/or modify it under GPL2. # if /^(?:latest|day|month|nyear|search)$/ =~ @mode then add_footer_proc do google_universal_analytics_insert_code end end def google_universal_analytics_insert_code return '' unless @conf['google_universal_analytics.profile'] <<-HTML HTML end # UA-53836-1 add_conf_proc( 'google_universal_analytics', 'Google Universal Analytics' ) do if @mode == 'saveconf' then @conf['google_universal_analytics.profile'] = @cgi.params['google_universal_analytics.profile'][0] end <<-HTML

      Google Universal Analytics Profile

      set your Profile ID (NNNNN-N)

      HTML end tdiary-contrib-5.0.8/plugin/google_webmaster.rb000066400000000000000000000014071325711763500216420ustar00rootroot00000000000000# encoding: utf-8 # google-webmaster.rb - embed a meta tag to let Google Webmaster tool know your verification code. # # Copyright (C) 2012, Tatsuya Sato # You can redistribute it and/or modify it under GPL2. # add_header_proc do "" end add_conf_proc('Google Webmaster', 'Google ウェブマスターツール', 'etc') do if @mode == 'saveconf' @conf['google_webmaster.verification'] = @cgi.params['google_webmaster.verification'][0] end <<-HTML

      Google ウェブマスターツールの検証コード

      HTML end tdiary-contrib-5.0.8/plugin/hatena_bookmark_nocomment.rb000066400000000000000000000003071325711763500235170ustar00rootroot00000000000000# hatena_bookmark_nocomment.rb # # Copyright (c) 2008 SHIBATA Hiroshi # Distributed under the GPL2 # add_header_proc do %Q|| end tdiary-contrib-5.0.8/plugin/hatena_star.rb000066400000000000000000000044151325711763500206100ustar00rootroot00000000000000# hatena_star.rb # Itoshi Nikaido # Distributed under the GPL @hatena_star_options = { 'token' => 'Token', 'star.image' => '.hatena-star-star-image', 'star.add' => '.hatena-star-add-button-image', 'comment.image' => '.hatena-star-comment-button-image' } add_header_proc do hatena_star = %Q|\t\n| hatena_star << %Q|\t\n| hatena_star << %Q|\t\n| end add_conf_proc( 'hatena_star', 'Hatena::Star' ) do if( @mode == 'saveconf' ) then @hatena_star_options.keys.each do |o| @conf["hatena_star.#{o}"] = @cgi.params["hatena_star.#{o}"][0].strip if @conf["hatena_star.#{o}"].length == 0 then @conf["hatena_star.#{o}"] = nil end end end <<-HTML

      Token

      Star Image (URL)

      Add Star Image (URL)

      Comment Image (URL)

      HTML end tdiary-contrib-5.0.8/plugin/hb_footer.rb000066400000000000000000000147011325711763500202650ustar00rootroot00000000000000# # hb_footer.rb # # はてなブックマーク (http://b.hatena.ne.jp/) のコメントを該当日付に貼り付けるtDiaryプラグイン # 改造版rss_recent Version 0.0.5i2と共に使用する # # Licence: GPL # Author: ishinao # add_body_leave_proc(Proc.new do |date| if @mode == 'day' or @mode == 'latest' diary = @diaries[date.strftime('%Y%m%d')] pnum = 1 hbsrc = '' diary.each_section do |para| td_url = "http://tdiary.ishinao.net/#{date.strftime('%Y%m%d')}.html%23p#{'%02d' % pnum}" hb_url = "http://b.hatena.ne.jp/entry/#{td_url}" rss_url = "http://b.hatena.ne.jp/entry/rss/#{td_url}" template_head = %Q[
      \n

      はてなブックマークの反応

      \n\n
      \n" cache_time = 3600; if date.strftime('%Y-%m-%d') != Time.now.strftime('%Y-%m-%d') cache_time = 3600 * 12; end hbsrc << hb_footer(rss_url, 50, cache_time, template_head, template_list, template_foot) pnum+=1 end hbsrc else '' end end) # rss-recent.rb: RSS recent plugin # # rss_recnet: show recnet list from RSS # parameters (default): # url: URL of RSS # max: max of list itmes(5) # cache_time: cache time(second) of RSS(60*60) # template_head: rendering header part # template_list: rendering RSS item part(with loop) # template_foot: rendering footer part # # Copyright (c) 2003-2004 Kouhei Sutou # Distributed under the GPL # # Modified using template string and content:encoded # Version 0.0.5i2 by ishinao # require "rss/rss" RSS_RECENT_FIELD_SEPARATOR = "\0" RSS_RECENT_ENTRY_SEPARATOR = "\1" RSS_RECENT_VERSION = "0.0.5i2" RSS_RECENT_HTTP_HEADER = { "User-Agent" => "tDiary RSS recent plugin version #{RSS_RECENT_VERSION}. " << "Using RSS parser version is #{::RSS::VERSION}.", } def hb_footer(url, max = 5, cache_time = 3600, \ template_head = "\n") url.untaint cache_file = "#{@cache_path}/rss-recent.#{CGI.escape(url)}" hb_footer_cache_rss(url, cache_file, cache_time.to_i) return '' unless test(?r, cache_file) rv = template_head i = 0 hb_footer_read_from_cache(cache_file).each do |title, url, time, content, description| break if i >= max next if (url.nil? or title.nil?) rv << eval('%Q[' + template_list + ']') i += 1 end rv << template_foot if i > 0 rv else '' end end class InvalidResourceError < StandardError; end def hb_footer_cache_rss(url, cache_file, cache_time) cached_time = nil cached_time = File.mtime(cache_file) if File.exist?(cache_file) if cached_time.nil? or Time.now > cached_time + cache_time require 'time' require 'open-uri' require 'net/http' require 'uri/generic' require 'rss/parser' require 'rss/1.0' require 'rss/2.0' require 'rss/dublincore' require 'rss/content' begin uri = URI.parse(url) raise URI::InvalidURIError if uri.scheme != "http" rss_source = hb_footer_fetch_rss(uri, cached_time) raise InvalidResourceError if rss_source.nil? # parse RSS rss = ::RSS::Parser.parse(rss_source, false) raise ::RSS::Error if rss.nil? # pre processing begin rss.output_encoding = @conf.charset || charset rescue ::RSS::UnknownConversionMethodError end rss_infos = rss.items.collect do |item| hb_footer_pubDate_to_dc_date(item) [item.title, item.link, item.dc_date, item.content_encoded, item.description] end hb_footer_write_to_cache(cache_file, rss_infos) rescue URI::InvalidURIError hb_footer_write_to_cache(cache_file, [['Invalid URI', url]]) rescue InvalidResourceError, ::RSS::Error # hb_footer_write_to_cache(cache_file, [['Invalid Resource', url]]) # when cannot get valid RSS, use old cache end end end def hb_footer_fetch_rss(uri, cache_time) rss = nil begin uri.open(hb_footer_http_header(cache_time)) do |f| case f.status.first when "200" rss = f.read # STDERR.puts "Got RSS of #{uri}" when "304" # not modified # STDERR.puts "#{uri} does not modified" else raise InvalidResourceError end end rescue TimeoutError, SocketError, StandardError, SecurityError # occured in redirect raise InvalidResourceError end rss end def hb_footer_http_header(cache_time) header = RSS_RECENT_HTTP_HEADER.dup if cache_time.respond_to?(:rfc2822) header["If-Modified-Since"] = cache_time.rfc2822 end header end def hb_footer_write_to_cache(cache_file, rss_infos) File.open(cache_file, 'w') do |f| f.flock(File::LOCK_EX) rss_infos.each do |info| f << info.join(RSS_RECENT_FIELD_SEPARATOR) f << RSS_RECENT_ENTRY_SEPARATOR end f.flock(File::LOCK_UN) end end def hb_footer_read_from_cache(cache_file) require 'time' infos = [] File.open(cache_file) do |f| while info = f.gets(RSS_RECENT_ENTRY_SEPARATOR) info = info.chomp(RSS_RECENT_ENTRY_SEPARATOR) infos << info.split(RSS_RECENT_FIELD_SEPARATOR) end end infos.collect do |title, url, time, content, description| [ hb_footer_convert(title), hb_footer_convert(url), hb_footer_convert(time) {|time| Time.parse(time)}, hb_footer_convert(content), hb_footer_convert(description), ] end end def hb_footer_convert(str) if str.nil? or str.empty? nil else if block_given? yield str else str end end end # from RWiki def hb_footer_modified(t) return '-' unless t dif = (Time.now - t).to_i dif = dif / 60 return "#{dif}m" if dif <= 60 dif = dif / 60 return "#{dif}h" if dif <= 24 dif = dif / 24 return "#{dif}d" end # from RWiki def hb_footer_modified_class(t) return 'dangling' unless t dif = (Time.now - t).to_i dif = dif / 60 return "modified-hour" if dif <= 60 dif = dif / 60 return "modified-today" if dif <= 24 dif = dif / 24 return "modified-month" if dif <= 30 return "modified-year" if dif <= 365 return "modified-old" end def hb_footer_pubDate_to_dc_date(target) if target.respond_to?(:pubDate) class << target alias_method(:dc_date, :pubDate) end end end tdiary-contrib-5.0.8/plugin/hb_footer4sec.rb000066400000000000000000000144701325711763500210470ustar00rootroot00000000000000# # hb_footer.rb # # はてなブックマーク (http://b.hatena.ne.jp/) のコメントを該当セクションに貼り付けるtDiaryプラグイン # 改造版rss_recent Version 0.0.5i2と共に使用する # # Licence: GPL # Author: ishinao # add_section_leave_proc do |date, index| td_url = "http://tdiary.ishinao.net/#{date.strftime('%Y%m%d')}.html%23p#{'%02d' % index}" hb_url = "http://b.hatena.ne.jp/entry/#{td_url}" rss_url = "http://b.hatena.ne.jp/entry/rss/#{td_url}" template_head = %Q[
      \n

      このセクションに対するはてブ

      \n\n
      \n" cache_time = 3600; if date.strftime('%Y-%m-%d') != Time.now.strftime('%Y-%m-%d') cache_time = 3600 * 12; end hb_footer4sec(rss_url, 50, cache_time, template_head, template_list, template_foot) end # rss-recent.rb: RSS recent plugin # # rss_recnet: show recnet list from RSS # parameters (default): # url: URL of RSS # max: max of list itmes(5) # cache_time: cache time(second) of RSS(60*60) # template_head: rendering header part # template_list: rendering RSS item part(with loop) # template_foot: rendering footer part # # Copyright (c) 2003-2004 Kouhei Sutou # Distributed under the GPL # # Modified using template string and content:encoded # Version 0.0.5i2 by ishinao # require "rss/rss" RSS_RECENT_FIELD_SEPARATOR = "\0" RSS_RECENT_ENTRY_SEPARATOR = "\1" RSS_RECENT_VERSION = "0.0.5i2" RSS_RECENT_HTTP_HEADER = { "User-Agent" => "tDiary RSS recent plugin version #{RSS_RECENT_VERSION}. " << "Using RSS parser version is #{::RSS::VERSION}.", } def hb_footer4sec(url, max = 5, cache_time = 3600, \ template_head = "\n") url.untaint cache_file = "#{@cache_path}/rss-recent.#{CGI.escape(url)}" hb_footer4sec_cache_rss(url, cache_file, cache_time.to_i) return '' unless test(?r, cache_file) rv = template_head i = 0 hb_footer4sec_read_from_cache(cache_file).each do |title, url, time, content, description| break if i >= max next if (url.nil? or title.nil?) rv << eval('%Q[' + template_list + ']') i += 1 end rv << template_foot if i > 0 rv else '' end end class InvalidResourceError < StandardError; end def hb_footer4sec_cache_rss(url, cache_file, cache_time) cached_time = nil cached_time = File.mtime(cache_file) if File.exist?(cache_file) if cached_time.nil? or Time.now > cached_time + cache_time require 'time' require 'open-uri' require 'net/http' require 'uri/generic' require 'rss/parser' require 'rss/1.0' require 'rss/2.0' require 'rss/dublincore' require 'rss/content' begin uri = URI.parse(url) raise URI::InvalidURIError if uri.scheme != "http" rss_source = hb_footer4sec_fetch_rss(uri, cached_time) raise InvalidResourceError if rss_source.nil? # parse RSS rss = ::RSS::Parser.parse(rss_source, false) raise ::RSS::Error if rss.nil? # pre processing begin rss.output_encoding = @conf.charset || charset rescue ::RSS::UnknownConversionMethodError end rss_infos = rss.items.collect do |item| hb_footer4sec_pubDate_to_dc_date(item) [item.title, item.link, item.dc_date, item.content_encoded, item.description] end hb_footer4sec_write_to_cache(cache_file, rss_infos) rescue URI::InvalidURIError hb_footer4sec_write_to_cache(cache_file, [['Invalid URI', url]]) rescue InvalidResourceError, ::RSS::Error # hb_footer4sec_write_to_cache(cache_file, [['Invalid Resource', url]]) # when cannot get valid RSS, use old cache end end end def hb_footer4sec_fetch_rss(uri, cache_time) rss = nil begin uri.open(hb_footer4sec_http_header(cache_time)) do |f| case f.status.first when "200" rss = f.read # STDERR.puts "Got RSS of #{uri}" when "304" # not modified # STDERR.puts "#{uri} does not modified" else raise InvalidResourceError end end rescue TimeoutError, SocketError, StandardError, SecurityError # occured in redirect raise InvalidResourceError end rss end def hb_footer4sec_http_header(cache_time) header = RSS_RECENT_HTTP_HEADER.dup if cache_time.respond_to?(:rfc2822) header["If-Modified-Since"] = cache_time.rfc2822 end header end def hb_footer4sec_write_to_cache(cache_file, rss_infos) File.open(cache_file, 'w') do |f| f.flock(File::LOCK_EX) rss_infos.each do |info| f << info.join(RSS_RECENT_FIELD_SEPARATOR) f << RSS_RECENT_ENTRY_SEPARATOR end f.flock(File::LOCK_UN) end end def hb_footer4sec_read_from_cache(cache_file) require 'time' infos = [] File.open(cache_file) do |f| while info = f.gets(RSS_RECENT_ENTRY_SEPARATOR) info = info.chomp(RSS_RECENT_ENTRY_SEPARATOR) infos << info.split(RSS_RECENT_FIELD_SEPARATOR) end end infos.collect do |title, url, time, content, description| [ hb_footer4sec_convert(title), hb_footer4sec_convert(url), hb_footer4sec_convert(time) {|time| Time.parse(time)}, hb_footer4sec_convert(content), hb_footer4sec_convert(description), ] end end def hb_footer4sec_convert(str) if str.nil? or str.empty? nil else if block_given? yield str else str end end end # from RWiki def hb_footer4sec_modified(t) return '-' unless t dif = (Time.now - t).to_i dif = dif / 60 return "#{dif}m" if dif <= 60 dif = dif / 60 return "#{dif}h" if dif <= 24 dif = dif / 24 return "#{dif}d" end # from RWiki def hb_footer4sec_modified_class(t) return 'dangling' unless t dif = (Time.now - t).to_i dif = dif / 60 return "modified-hour" if dif <= 60 dif = dif / 60 return "modified-today" if dif <= 24 dif = dif / 24 return "modified-month" if dif <= 30 return "modified-year" if dif <= 365 return "modified-old" end def hb_footer4sec_pubDate_to_dc_date(target) if target.respond_to?(:pubDate) class << target alias_method(:dc_date, :pubDate) end end end tdiary-contrib-5.0.8/plugin/hb_footer4sec_js.rb000066400000000000000000000016711325711763500215420ustar00rootroot00000000000000# hb_footer4sec_js.rb $Revision 1.0 $ # # Copyright (c) 2008 SHIBATA Hiroshi # You can redistribute it and/or modify it under GPL2. # def permalink( date, index, escape = true ) ymd = date.strftime( "%Y%m%d" ) uri = @conf.index.dup uri.sub!( %r|\A(?!https?://)|i, @conf.base_url ) uri.gsub!( %r|/\.(?=/)|, "" ) # /././ -> / link = uri + anchor( "#{ymd}p%02d" % index ) link.sub!( "#", "%23" ) if escape link end add_section_leave_proc do |date, index| if @mode == 'day' and not bot? <<-SCRIPT
      SCRIPT end end tdiary-contrib-5.0.8/plugin/hide_comment_form.rb000066400000000000000000000001051325711763500217650ustar00rootroot00000000000000def hide_comment_form @conf.hide_comment_form = true return '' end tdiary-contrib-5.0.8/plugin/hide_sidebar_smartphone.rb000066400000000000000000000002661325711763500231610ustar00rootroot00000000000000# hide_sidebar_smartphone.rb # # Copyright (C) 2011 by TADA Tadashi # You can distribute it under GPL2 or any later version. # enable_js( 'hide_sidebar_smartphone.js' ) tdiary-contrib-5.0.8/plugin/iddy.rb000066400000000000000000000045671325711763500172600ustar00rootroot00000000000000# # iddy.rb: iddy.jp plugin for tDiary # # Copyright (C) 2007 by TADA Tadashi # Distributed under GPL. # ###################################################################### # If you will modify or release another version of this code, # please get your own application key from iddy.jp and replace below. ###################################################################### @iddy_key = 'f93d2f38442fae3a1f08e82f84d335112cca0855' require 'open-uri' require 'timeout' require 'rexml/document' def iddy( id ) begin cache = "#{@cache_path}/iddy.xml" xml = open( cache ) {|f| f.read } if Time::now > File::mtime( cache ) + 60*60 then File::delete( cache ) # clear cache 1 hour later end rescue Errno::ENOENT begin xml = iddy_call_api( id, @iddy_key ) open( cache, 'wb' ) {|f| f.write( xml ) } rescue Timeout::Error return '
      No data.
      ' end end doc = REXML::Document::new( xml ) if doc.elements[1].attribute( 'status' ).to_s == 'fail' then return '
      iddy.jp returns fail.
      ' end user = doc.elements.to_a( '*/*/user' )[0].elements profileurl = user.to_a( 'profileurl' )[0] unless profileurl then return '
      No profile URL on iddy.jp.
      ' end imageurl = user.to_a( 'imageurl' )[0] name = user.to_a( 'name' )[0] nameroma = user.to_a( 'nameroma' )[0] mail = user.to_a( 'mail' )[0] submail = user.to_a( 'submail' )[0] html = '' @conf.to_native( html ) end def iddy_call_api( id, key ) request = "http://iddy.jp/api/user/?apikey=#{key}" request << "&accountname=#{id}" proxy = @conf['proxy'] proxy = 'http://' + proxy if proxy Timeout.timeout( 3 ) do open( request, :proxy => proxy ) {|f| f.read } end end tdiary-contrib-5.0.8/plugin/image_ex.rb000066400000000000000000000353441325711763500201020ustar00rootroot00000000000000# image_plugin_ex.rb # version 0.3 # -pv- # # 名称: # 絵日記Plugin機能追加版 # # 概要: # 日記更新画面からの画像アップロード、サムネイル作成、本文への表示 # # 使う場所: # 本文 # # 使い方: # image( number, 'altword', thumbnail ) - 画像を表示します。 # number - 画像の番号0、1、2等 # altword - imgタグの altに入れる文字列 # thumbnail - サムネイル(小さな画像)を指定する(省略可) # # image_left( number, 'altword', thumbnail ) - imageにclass=leftを追加します。 # image_right( number, 'altword', thumbnail ) - imageにclass=rightを追加します。 # # image_link( number, 'desc' ) - 画像へのリンクを生成します。 # number - 画像の番号0、1、2等 # desc - 画像の説明 # # その他: # tDiary version 1.5.4以降で動作します。 # tdiary.confで、 # 画像ファイルを保存するディレクトリ # @options['image.dir'] # 画像ファイルのURL # @options['image.url'] # 縮小画像の生成方法 # @options['image.url'] # 0 - 縮小画像を生成しない # 1 - ImageMagickのconvertで縮小画王を生成 # 2 - netpbm群で縮小画王を生成 # を設定してください。 # また、@secure = trueな環境では動作しません。 # # 詳しくは、 # http://shimoi.s26.xrea.com/hiki/hiki.xcg?TdiaryEnikkiEx # をご覧下さい。 # # ライセンスについて: # Copyright (c) 2002 Daisuke Kato # Copyright (c) 2002 Toshi Okada # Copyright (c) 2003 Yoshimi KURUMA # # You can redistribute it and/or modify it under GPL2. # =begin Changelog 2003-05-16 Yoshimi KURUMA * method 'image' is extended to show a thumbnail. * new method: 'image_link'. * version 0.3 2003-05-16 Yoshimi KURUMA * modify illegal option names. * version 0.2. 2003-05-16 Yoshimi KURUMA * support manual upload of thumbnail when useresize == 0 2003-04-27 Yoshimi KURUMA * link element is removed when no thumbnail. 2003-04-25 Yoshimi KURUMA * add JavaScript for insert plugin tag into diary. * upload/delete form style changed. 2003-04-24 Yoshimi KURUMA * upload/delete form style changed. 2003-04-22 Yoshimi KURUMA * version 0.1 first form_proc version. =end @image_dir = @options && @options['image.dir'] || './images/' @image_dir.chop! if /\/$/ =~ @image_dir @image_url = @options && @options['image.url'] || './images/' @image_url.chop! if /\/$/ =~ @image_url @imageex_thumbnailsize = @options && @options['image_ex.previewsize'] || 120 @imageex_yearlydir = @options && @options['image_ex.yearlydir'] || 0 enable_js("image_ex.js") add_body_enter_proc(Proc.new do |date| @image_date = date.strftime("%Y%m%d") @image_year = date.strftime("%Y") "" end) def image( id, alt = "image", id2 = nil, width = nil, place="none" ) @image_date ||= @date.strftime("%Y%m%d") @image_year ||= @date.strftime("%Y") if @imageex_yearlydir == 1 image_url = %Q[#{@image_url}/#{@image_year}/] image_dir = %Q[#{@image_dir}/#{@image_year}/] else image_url = %Q[#{@image_url}/] image_dir = %Q[#{@image_dir}/] end image_dir.untaint Dir.mkdir(image_dir) unless File.directory?(image_dir) list = imageList(@image_date, image_dir).untaint slist = imageList(@image_date, image_dir, "s").untaint if width width_tag = %Q[width="#{h width}"] else width_tag = "" end if id2 %Q[#{h alt}] else if slist[id.to_i] %Q[#{h alt}] else if list[id.to_i] # %Q[#{h alt}] %Q[#{h alt}] end end end end def image_left( id, alt = "image", id2 = nil, width=nil ) image( id, alt, id2, width, "left" ) end def image_right( id, alt = "image", id2 = nil, width=nil ) image( id, alt, id2, width, "right" ) end def image_link( id, str ) @image_date ||= @date.strftime("%Y%m%d") @image_year ||= @date.strftime("%Y") if @imageex_yearlydir == 1 image_url = %Q[#{@image_url}/#{@image_year}/] image_dir = %Q[#{@image_dir}/#{@image_year}/] else image_url = %Q[#{@image_url}/] image_dir = %Q[#{@image_dir}/] end list = imageList(@image_date, image_dir).untaint %Q[#{str}] end ### def imageList(date, image_dir='@image_dir', prefix="") date = "#{prefix}"+date image_path = [] Dir.foreach(image_dir){ |file| if file =~ /(.*)\_(.*)\.(.*)/ if $1 == date image_path[$2.to_i] = file end end } image_path end add_form_proc do |date| begin # ENV['PATH'] = nil imageex_useresize = @options && @options['image_ex.useresize'] || 0 imageex_converttype = @options && @options['image_ex.converttype'] || 0 imageex_thresholdsize = @options && @options['image_ex.thresholdsize'] || 160 imageex_convertedwidth = @options && @options['image_ex.convertedwidth'] || 160 imageex_convertedheight = @options && @options['image_ex.convertedheight'] || 120 if imageex_useresize == 1 || imageex_useresize ==2 begin require 'image_size.rb' rescue LoadError imageex_useresize = 0 end end if imageex_useresize == 1 def resize_image(orig, new, width, height, imageex_convertedwidth, imageex_convertedheight, orig_type, new_type) imageex_convertpath = @options && @options['image_ex.convertpath'] || "convert" imageex_convertpath if width > height imageex_convertedsize = %Q[#{imageex_convertedwidth}x#{imageex_convertedheight}] imageex_convertedsize else imageex_convertedsize = %Q[#{imageex_convertedheight}x#{imageex_convertedwidth}] imageex_convertedsize end system(imageex_convertpath , "-geometry", imageex_convertedsize , orig, new) if FileTest::size?( new ) == 0 File::delete( new ) end end elsif imageex_useresize == 2 def resize_image(orig, new, width, height, imageex_convertedwidth, imageex_convertedheight, orig_type, new_type) pnmscale = @options && @options['image_ex.pnmscalepath'] || "pnmscale" jpegtopnm = @options && @options['image_ex.jpegtopnmpath'] || "jpegtopnm" pnmtojpeg = @options && @options['image_ex.pnmtojpegpath'] || "pnmtojpeg" pngtopnm = @options && @options['image_ex.pngtopnmpath'] || "pngtopnm" pnmtopng = @options && @options['image_ex.pnmtopngpath'] || "pnmtopng" giftopnm = @options && @options['image_ex.giftopnmpath'] || "giftopnm" tifftopnm = @options && @options['image_ex.tifftopnmpath'] || "tifftopnm" bmptopnm = @options && @options['image_ex.bmptopnmpath'] || "bmptopnm" downtype = orig_type.downcase topnm = eval("#{downtype}topnm") if new_type == "jpg" pnmto = pnmtojpeg elsif new_type == "png" pnmto = pnmtopng end if width > height imageex_convertedsize ="#{imageex_convertedwidth}" else imageex_convertedsize ="#{imageex_convertedheight}" end com_line =%Q[#{topnm} #{orig} | #{pnmscale} --width #{imageex_convertedsize} | #{pnmto} > #{new}] system( com_line ) if FileTest::size?( new ) == 0 File::delete( new ) end end end def dayimagelist( image_dir, image_date, prefix="") image_path = [] image_dir.untaint Dir.foreach(image_dir){ |file| if file=~ /(.*)\_(.*)\.(.*)/ if $1 == "#{prefix}" + image_date.to_s image_path[$2.to_i] = file end end } return image_path end if @cgi.params['plugin_image_add'][0] && @cgi.params['plugin_image_file'][0].original_filename != '' image_dir = @cgi.params['plugin_image_dir'][0].read.untaint image_filename = '' image_extension = '' image_date = date.strftime("%Y%m%d") image_filename = @cgi.params['plugin_image_file'][0].original_filename if image_filename =~ /(\.jpg|\.jpeg|\.gif|\.png)\z/i image_extension = $1 image_name = dayimagelist(image_dir, image_date) image_file = image_dir+image_date+"_"+image_name.length.to_s+image_extension.downcase image_file.untaint File::umask( 022 ) File::open( image_file, "wb" ) {|f| f.print @cgi.params['plugin_image_file'][0].read } end if imageex_useresize == 1 or imageex_useresize == 2 open(image_file,"rb") do |fh| img = ImageSize.new(fh.read) begin # old image_size.rb width = img.get_width height = img.get_height orig_type = img.get_type rescue NoMethodError # image_size gem width = img.width height = img.height orig_type = (img.format || "OTHER").to_s.upcase end if imageex_converttype == 0 new_type = "jpg" elsif imageex_converttype == 1 new_type = "png" end if width if width > imageex_thresholdsize or height > imageex_thresholdsize small_image_file = %Q[#{image_dir}s#{image_date}_#{image_name.length.to_s}.#{new_type}] resize_image(image_file, small_image_file, width, height, imageex_convertedwidth, imageex_convertedheight, orig_type, new_type) end end end end elsif @cgi.params['plugin_image_thumbnail'][0] && @cgi.params['plugin_image_file'][0].original_filename != '' image_dir = @cgi.params['plugin_image_dir'][0].read.untaint image_filename = '' image_extension = '' image_date = date.strftime("%Y%m%d") image_filename = @cgi.params['plugin_image_file'][0].original_filename if image_filename =~ /(\.jpg|\.jpeg|\.gif|\.png)\z/i image_extension = $1 image_name = @cgi.params['plugin_image_name'][0].read.untaint image_file=image_dir+"s"+image_name+image_extension.downcase image_file.untaint File::umask( 022 ) File::open( image_file, "wb" ) {|f| f.print @cgi.params['plugin_image_file'][0].read } end elsif @cgi.params['plugin_image_del'][0] image_dir = @cgi.params['plugin_image_dir'][0] image_date = date.strftime("%Y%m%d") image_name = dayimagelist( image_dir, image_date) image_name2= dayimagelist( image_dir, image_date, "s") @cgi.params['plugin_image_id'].untaint.each do |id| if image_name[id.to_i] image_file=image_dir+image_name[id.to_i] image_file.untaint if File::exist?(image_file) File::delete(image_file) end end if image_name2[id.to_i] image_file2=image_dir+image_name2[id.to_i] image_file2.untaint if File::exist?(image_file2) File::delete(image_file2) end end end end rescue Exception puts "Content-Type: text/plain\n\n" puts "#$! (#{$!.type})" puts "" puts $@.join( "\n" ) end if @imageex_yearlydir == 1 image_dir = %Q[#{@image_dir}/#{@date.year}/] else image_dir = %Q[#{@image_dir}/] end if @imageex_yearlydir == 1 image_url = %Q[#{@image_url}/#{@date.year}/] else image_url = %Q[#{@image_url}/] end Dir.mkdir(image_dir) unless File.directory?(image_dir) n_image = imageList(@date.strftime("%Y%m%d"), image_dir).length list = imageList(@date.strftime("%Y%m%d"), image_dir) slist = imageList(@date.strftime("%Y%m%d"), image_dir, "s") pretable="" posttable="" if n_image > 0 pretable<< %Q[] posttable << %Q[
      ] end if @conf.respond_to?(:style) and @conf.style =~ /Wiki$/i image_plugin_tag1 = "{{" image_plugin_tag2 = "}}" elsif @conf.respond_to?(:style) and @conf.style =~ /RD$/i image_plugin_tag1 = "((%" image_plugin_tag2 = "%))" else image_plugin_tag1 = "<%=" image_plugin_tag2 = "%>" end r = '' r << %Q[ ] i = '' i << "" nt=0 id=0 while id < n_image do thumbnail_tag = '' if slist[id.to_i] src_tag = %Q[src="#{h image_url}#{h slist[id.to_i]}"] alt_tag = %Q[alt="#{h slist[id.to_i]}"] else src_tag = %Q[src="#{h image_url}#{h list[id.to_i]}"] alt_tag = %Q[alt="#{h list[id.to_i]}"] thumbnail_tag = %Q[
      #{csrf_protection}
      ] if imageex_useresize == 0 end ptag = "#{image_plugin_tag1}image #{id}, '画像の説明'#{image_plugin_tag2}" i<< %Q[
      #{image_plugin_tag1}image #{h id},'title#{h id}'#{image_plugin_tag2}
      #{thumbnail_tag}
      #{csrf_protection}
      ] if slist[id.to_i] || list[id.to_i] nt += 1 if slist[id.to_i] || list[id.to_i] if nt > 0 and nt%2 == 0 i<< %Q[(.*?)|m).to_a[1].gsub(/<.*?>/, '').strip result = <<-EOS #{h title} #{h title}
      #{h author}
      #{h price}

      EOS puboo_cache_set( id, result ) unless @conf.secure result rescue link end if __FILE__ == $0 require 'test/unit' class TestTatsuZine < Test::Unit::TestCase def setup @conf = Struct.new("Conf", :secure).new(true) def h(str); str; end end def test_puboo expect = <<-EOS 入門Puppet - Automate Your Infrastructure 入門Puppet - Automate Your Infrastructure
      栗林健太郎
      890円(税込)

      EOS assert_equal expect, puboo('70667') end end end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: tdiary-contrib-5.0.8/plugin/pygments_css.rb000066400000000000000000000103171325711763500210330ustar00rootroot00000000000000# # pygments.rb: insert CSS for html formatted code with Pygments. # # Copyright (C) 2012 SHIBATA Hiroshi # You can redistribute it and/or modify it under GPL2. # add_header_proc do <<-STYLE STYLE end tdiary-contrib-5.0.8/plugin/rating.rb000066400000000000000000000304521325711763500176030ustar00rootroot00000000000000# $Revision:0.1$ # rating.rb: 複数軸による記事評価とグラフ表示 # for tDiary # # 使い方 # そのまま plugin ディレクトリに置きます。 # '設定' -> 'rating.rb Configuration' で、評価軸や # 表示内容を設定。 # くわしくは # http://www.maripo.jp/diary/?date=20071019 # # Copyright (c) 2007 Mariko/Maripo GODA # http://www.maripo.jp/ # You can redistribute it and/or modify it under GPL. require 'pstore' require 'cgi' @dbase = "#{@cache_path}/rating.db" ######################################### # Config (Form) ######################################### add_conf_proc('rating', 'rating.rb Configuration') do rating_config = RatingConfig.new(@dbase) form_string = "" if @mode == 'saveconf' # save conf index = 0 # edit axes rating_config.each { |axis_config| #check values if (@cgi.params["label" + index.to_s][0] != "" && (@cgi.params["range" + index.to_s][0]).to_i > 0) axis_config.edit(@cgi.params["label" + index.to_s][0], @cgi.params["label_max" + index.to_s][0],@cgi.params["label_min" + index.to_s][0],@cgi.params["range" + index.to_s][0].to_i,@cgi.params["order" + index.to_s][0].to_i,@cgi.params["display" + index.to_s][0]!=nil) index += 1 end } if (@cgi.params["label_new"][0] != "" && @cgi.params["range_new"][0].to_i > 0) # add new axis rating_config.add_axis(@cgi.params["label_new"][0], @cgi.params["label_max_new"][0], @cgi.params["label_min_new"][0], @cgi.params["range_new"][0].to_i) end rating_config.save_to_db end # print conf form form_string += < フィードバックフォームの設定をします。軸はいくつでも作成することができます。

      作者blog に追加情報が書いてあるかもしれません。

      設定方法

      • 順 … 表示される順番です。小さいほうから順に並びます。番号が飛んでもOK。
      • 表示 … いらない軸はチェックを外してしまってください。
      • 軸の名前 … (例) "この記事は参考になりましたか"
      • 最低ラベル … 例 "まったく参考にならない"
      • 最高ラベル … 例 "とても参考になった"
      • 選択肢数 … 例 : 1~5の5段階なら "5"
      • 設定内容

      ] end id +=1 end if n_image > 0 r << %Q[
      絵日記(一覧・削除)
      #{pretable} #{i} #{posttable}
      ] end r << %Q[
      絵日記(追加)
      #{csrf_protection}
      ] end # vim: set ts=3 sw=3 noexpandtab : tdiary-contrib-5.0.8/plugin/image_gps.rb000066400000000000000000000137441325711763500202570ustar00rootroot00000000000000# -*- coding: utf-8 -*- # image_gps.rb $Revision: 1.1 $ # # 概要: # # # 使い方: # 絵日記Plugin(image.rb)とおなじ # # Copyright (c) 2009,2010 kp # Distributed under the GPL # =begin ChangeLog 2010-04-21 kp * スマートフォン対応 * Google Maps API Keyが設定されていない場合はStaticMAPを生成しない * リンク先をGoogle Mapsに統一 2009-06-03 kp * first version * fork from image_gps2.rb =end begin require 'exifparser' rescue retry if require 'rubygems' end def tky2wgs lat,lon lat_w = lat - lat*0.00010695 + lon*0.000017464 + 0.0046017 lon_w = lon - lat*0.000046038 - lon*0.000083043 + 0.010040 lat = lat_w lon = lon_w return lat,lon end def image( id, alt = 'image', thumbnail = nil, size = nil, place = 'photo' ) if @conf.secure then image = "#{@image_date}_#{id}.jpg" image_t = "#{@image_date}_#{thumbnail}.jpg" if thumbnail else image = image_list( @image_date )[id.to_i] image_t = image_list( @image_date )[thumbnail.to_i] if thumbnail end if size if size.kind_of?(Array) if size.length > 1 size = %Q| width="#{h size[0]}" height="#{h size[1]}"| elsif size.length > 0 size = %Q| width="#{h size[0]}"| end else size = %Q| width="#{size.to_i}"| end elsif @image_maxwidth and not @conf.secure then _, w, _ = image_info( "#{@image_dir}/#{image}".untaint ) if w > @image_maxwidth then size = %Q[ width="#{h @image_maxwidth}"] else size = "" end end show_exif_info = @conf['image_gps.show_exif_info'] show_exif_info = '' if show_exif_info.nil? google_maps_api_key = @conf['image_gps.google_maps_api_key'] google_maps_api_key = '' if google_maps_api_key.nil? if (@conf['image_gps.map_link_url'].nil? || @conf['image_gps.map_link_url'].empty?) map_link_url = '"//maps.google.co.jp/maps?q=#{lat},#{lon}"' else map_link_url = '"'+@conf['image_gps.map_link_url']+'"' end exif = ExifParser.new("#{@image_dir}/#{image}".untaint) rescue nil if exif #GPS Info begin raise if exif['GPSLatitudeRef'].value.length==0 raise if exif['GPSLongitudeRef'].value.length==0 lat = exif['GPSLatitude'].value lat = lat[0].to_f + lat[1].to_f/60 + lat[2].to_f/3600 lat = -lat if exif['GPSLatitudeRef'].value == 'S' lon = exif['GPSLongitude'].value lon = lon[0].to_f + lon[1].to_f/60 + lon[2].to_f/3600 lon = -lon if exif['GPSLongitudeRef'].value == 'W' datum = exif['GPSMapDatum'].value if exif.tag?('GPSMapDatum') lat,lon = tky2wgs(lat,lon) if datum == 'TOKYO' rescue lat = nil end # show exif info sep=' ' # ToDo: separator to config param. detail =%Q[

      ] show_exif_info.split(' ').each{|e| detail += "#{exif[e].to_s}"+sep if exif.tag?(e) } unless lat.nil? unless google_maps_api_key == '' map_img = %Q["//maps.googleapis.com/maps/api/staticmap?format=gif&] map_img += %Q[center=#{lat},#{lon}&zoom=14&size=200x200&markers=#{lat},#{lon}&] map_img += %Q[key=#{google_maps_api_key}&sensor=false"] end map_link = %Q[] map_link += %Q[MAP] map_link += %Q[] if map_img map_link += "" detail += map_link end detail += "

      " end img = %Q[#{alt}] img_t = %Q[#{alt}] url = '' url += %Q[
      ] url += %Q[] url += thumbnail ? img_t : img url += %Q[] url += %Q[#{detail}] if detail url += %Q[
      ] url end add_header_proc do if @mode !~ /conf$/ and not bot? then <<-HTML HTML else '' end end add_conf_proc('image_gps','image_gpsの設定','etc') do if @mode == 'saveconf' then @conf['mage_gps.google_maps_api_key'] = @cgi.params['image_gps.google_maps_api_key'][0] @conf['image_gps.show_exif_info'] = @cgi.params['image_gps.show_exif_info'][0] @conf['image_gps.map_link_url'] = @cgi.params['image_gps.map_link_url'][0] end <<-HTML

      Google Static Maps API Key

      Show Exif Info

      EXIFのタグ名をスペース区切りで設定します。

      exp.)Model FocalLength FNumber ExposureTime ExposureBiasValue

      Map Link URL

      地図サイトへのリンクURLを設定します。空欄の場合、Googleマップへリンクされます。

      パラメータとして\#{lat},\#{lon}が使用できます。それぞれ緯度、経度に展開されます。

      下のセレクタから選択すると各サービスのデフォルト値が設定されます。

      HTML end tdiary-contrib-5.0.8/plugin/inline_wiki.rb000066400000000000000000000001711325711763500206130ustar00rootroot00000000000000# Copyright (C) 2009 Hideki Sakamoto require 'hikidoc' def inline_wiki(buf) HikiDoc::to_html(buf) end tdiary-contrib-5.0.8/plugin/instagr.rb000066400000000000000000000015121325711763500177610ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # instagr.rb - plugin to insert images on instagr.am # !! integrated into the instagram.rb. # !! Please use the instagram.rb # # Copyright (C) 2011-2015, tamoot # You can redistribute it and/or modify it under GPL2. # # usage: # <%= instagr 'short URL instag.ram' => # <%= instagr 'short URL instag.ram', size} => # # available size option: # :small => 150x150 pixel # :medium => 306x306 pixel (default) # :large => 612x612 pixel def instagr( short_url, size = :medium) if respond_to?(:instagram) instagram( short_url, size ) else return %Q|instagr.rb was integrated into instagram.rb. Please use the instagram.rb| end end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/plugin/instagram.rb000066400000000000000000000040361325711763500203030ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # instagram.rb - embed your photo/videos in instagram to a diary # # Author: Tatsuya Sato # License: GPL require 'cgi' require 'json' require 'uri' require 'net/http' require 'open-uri' def instagram(*args) uri = URI::parse(args[0]) return instagram_iframe(*args) if uri.scheme.nil? return instagram_serverside(*args) end def instagram_iframe(code, width=612, height=700) return <<-BODY BODY end def instagram_serverside( short_url, size = :medium) return %Q|

      Argument is empty.. #{short_url}

      | if !short_url or short_url.empty? option = option.nil? ? {} : option # img size size = size.to_sym if size != :medium maxwidth_data = {:medium => 320, :large => 612} maxwidth = maxwidth_data[ size ] ? maxwidth_data[ size ] : maxwidth_data[:medium] # proxy px_host, px_port = (@conf['proxy'] || '').split( /:/ ) px_port = 80 if px_host and !px_port # query query = "?url=#{CGI::escape(short_url)}&maxwidth=#{maxwidth}" begin Net::HTTP.version_1_2 res = Net::HTTP::Proxy(px_host, px_port).get('api.instagram.com', "/oembed/#{query}") json_data = JSON::parse( res, &:read ) width = option[:width] ? option[:width] : json_data["width"] height = option[:height] ? option[:height] : json_data["height"] return <<-INSTAGR_DOM
      #{h @conf.to_native(json_data[

      #{h json_data["author_name"]}'s photo.

      INSTAGR_DOM rescue return %Q|

      Failed Open URL.. #{short_url}
      #{h $!}

      | end end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/plugin/ja/000077500000000000000000000000001325711763500163605ustar00rootroot00000000000000tdiary-contrib-5.0.8/plugin/ja/add_bookmark.rb000066400000000000000000000011221325711763500213160ustar00rootroot00000000000000# ja/add_bookmark.rb $Revision 1.3 $ # # Japanese resource of add_bookmark.rb # You can redistribute it and/or modify it under GPL2. # @add_bookmark_label = 'ブックマーク追加' @add_bookmark_desc = 'ページに埋め込みたいリンクをチェックしてください。' @caption_delicious = 'del.icio.usに追加' @caption_hatena = 'はてなブックマークに追加' @caption_livedoor = 'livedoor クリップに追加' @caption_buzzurl = 'Buzzurl に追加' @bookmark_label = [ 'del.icio.us', 'はてなブックマーク', 'livedoor クリップ', 'Buzzurl' ] tdiary-contrib-5.0.8/plugin/ja/category-lite.rb000066400000000000000000000035101325711763500214540ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # ja/category-lite.rb : tDiary plugin for show category pages (light edition) # # Copyright (C) 2015 TADA Tadashi # Distributed under the GPL2 or any later version. # @category_conf_label = 'カテゴリ' def category_conf_html r = <<-HTML

      カテゴリインデックスの作成

      カテゴリの機能を利用するにはカテゴリインデックスをあらかじめ作成しておく必要があります。 カテゴリインデックスを作成するには 以下のチェックを入れてからOKボタンを押してください。

      数秒から数十秒でインデックスの作成は終了しますが、日記の量が多い場合やサーバの性能が低い場合はタイムアウトしてしまう場合があります。この場合はオフラインで作成して下さい。

      日記編集サポート

      日記編集画面の「本文」の下にカテゴリ名を一覧表示することができます。 カテゴリ名をクリックすると「本文」にそのカテゴリ名が挿入されます(要JavaScript)。

      HTML r end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/plugin/ja/del_footer.rb000066400000000000000000000004761325711763500210360ustar00rootroot00000000000000# # English resource of delicious plugin $Revision: 1.0 $ # # Copyright (C) 2006 SHIBATA Hiroshi # You can redistribute it and/or modify it under GPL2. # @delicious_label_conf = 'del.icio.us' @delicious_label_id = 'del.icio.usのユーザーID' @delicious_label_pw = 'del.icio.usのパスワード' tdiary-contrib-5.0.8/plugin/ja/flickr.rb000066400000000000000000000066201325711763500201630ustar00rootroot00000000000000# flickr.rb Japanese resources add_conf_proc('flickr', 'Flickr プラグイン') do if @mode == 'saveconf' @conf['flickr.default_size'] = @cgi.params['flickr.default_size'][0] @conf['flickr.user_id'] = @cgi.params['flickr.user_id'][0] if @cgi.params['flickr.clear'][0] == "true" flickr_clear_cache end end flickr_bookmarklet = CGI.escapeHTML %Q{javascript:(function(){var w=window;w.page_photo_id||/^\/photos\/[^/]+\/(\d+)\//.test(w.location.pathname)?w.location.href="#{@conf.base_url}#{@update}?#{FLICKER_FORM_PID}="+w.page_photo_id||RegExp.$1:void(0);})()} r = <<-_HTML

      Flickr に登録した画像を日記に表示するプラグインです。日記の本文中で下記のように呼び出します。

      <%=flickr 画像ID, 画像サイズ%>
      画像ID
      それぞれの写真に一意に付けられる番号です。
      画像IDは Flickr で画像を表示したときの URL に含まれています。
      画像サイズ
      表示する画像の大きさを square, large square, thumbnail, small, small 320, medium, medium 640, medium 800, large から指定します。
      この値は省略できます。省略すると、画像は設定画面(この画面)で指定したサイズで表示されます。

      標準の画像サイズ

      画像サイズを省略してプラグインを呼び出した場合のサイズを指定します。

      FlickrのユーザID

      Flickr上でのあなたのユーザIDを入力してください。

      ※ Flickr ID は「19594487@N00」のような文字列です。分からないときは idgettr.com で調べることができます。

      Bookmarklet

      写真をかんたんに tDiary の日記へ載せるための Bookmarklet です。Bookmarklet を登録しなくても Flickr プラグインは使えますが、登録すればより便利になります。

      Flickr to tDiary (このリンクをブラウザのお気に入り・ブックマークに登録してください)

      使い方

      1. Flickr にアクセスし、日記に載せたい写真のページを開いて、この Bookmarklet を実行してください。
      2. 日記の編集フォームの下に先ほどの写真が表示されます。
      3. 「本文に追加」ボタンを押すと、日記中にこの写真を表示するための記述(プラグイン)が追記されます。

      キャッシュファイルの削除

      Flickrプラグインが使用しているキャッシュを削除します。

      _HTML end tdiary-contrib-5.0.8/plugin/ja/git-register.rb000066400000000000000000000002531325711763500213120ustar00rootroot00000000000000@git_register_conf_label = 'Git' @git_register_conf_header = 'Gitへ再登録' @git_register_conf_description = 'Gitへ再登録する場合はOKを押してください' tdiary-contrib-5.0.8/plugin/ja/google_sitemaps.rb000066400000000000000000000033231325711763500220670ustar00rootroot00000000000000# google_sitemap.rb # Copyright (c) 2006 http://d.bulkitem.com/ # Distributed under the GPL add_conf_proc('google_sitemaps', 'Google sitemap') do saveconf_google_sitemaps request_uri = File::dirname(@cgi.request_uri) if request_uri == "/" @conf['google_sitemaps.uri_format'] ||= 'http://' + @cgi.server_name + '/index.cgi?date=%s' else @conf['google_sitemaps.uri_format'] ||= 'http://' + @cgi.server_name + request_uri + '/index.cgi?date=%s' end @conf['google_sitemaps.output_file'] ||= File::dirname(ENV['SCRIPT_FILENAME']) + '/sitemap.xml' if File.writable_real?(@conf['google_sitemaps.output_file']) == false msg = "[NG] 指定されているファイルの書き込み権限がありません。" else msg = "[OK] 指定されているファイルの書き込み権限があります。" end <<-HTML

      Google ウェブマスターツール用のSitemap XMLを出力する設定を行います。

      アドレスフォーマット

      日付別表示時のURLフォーマットを指定します。日付文字列の部分は%sにしてください。

      eg.
      http://www.example.com/inex.cgi?date=%s
      http://www.example.com/%s.html

      XMLファイルの出力先

      出力するファイルを絶対パスで指定します。

      #{msg}

      HTML end tdiary-contrib-5.0.8/plugin/ja/livedoor_weather.rb000066400000000000000000000024241325711763500222510ustar00rootroot00000000000000# # Japanese resource of livedoor_weather plugin $Revision$ # # Copyright (C) 2006 SHIBATA Hiroshi # You can redistribute it and/or modify it under GPL2. # # # tdiary.confにおける設定: # @options['lwws.city_id'] : 天気情報を取得したい都市のIDを指定(設定画面から編集可能) # @lwws_plugin_name = 'livedoor 天気情報' @lwws_label_city_id = '都市IDの設定' @lwws_desc_city_id = '天気情報を取得する都市IDを指定します。全国の地点定義表(RSS)内の「1次細分区(cityタグ)」のidから選択してください。(初期設定は東京)' @lwws_label_disp_item = '表示項目の設定' @lwws_desc_disp_item = '表示させたい項目を選択してください。' @lwws_icon_label = 'アイコン表示の設定' @lwws_icon_desc = '天気情報をアイコン表示にする(詳細へのリンクは画像に設定)' @lwws_max_temp_label = '最高気温' @lwws_min_temp_label = '最低気温' @celsius_label = '℃' @lwws_label_cache = 'キャッシュの自動更新' @lwws_desc_cache = '自動更新を有効にする。' @lwws_desc_cache_time = 'キャッシュの更新間隔を時間で指定します。(初期設定は6時間)' tdiary-contrib-5.0.8/plugin/ja/microsummary.rb000066400000000000000000000010041325711763500214270ustar00rootroot00000000000000# ja/microsummary.rb # # Japanese resources for microsummary.rb # # Copyright (c) 2006 elytsllams # Distributed under the GPL # if @mode == 'conf' || @mode == 'saveconf' add_conf_proc( 'microsummary', 'Microsummary Generator' ) do saveconf_microsummary microsummary_init <<-HTML

      URI for microsummary generator XML

      HTML end end tdiary-contrib-5.0.8/plugin/ja/nicovideo.rb000066400000000000000000000032201325711763500206610ustar00rootroot00000000000000# # ja/nicovideo.rb - Japanese resource # # Copyright (C) TADA Tadashi # Distributed under GPL. # def nicovideo_feed( i ) <<-HTML
      #{h i[:title]} #{h i[:title]} (#{i[:length]})
      #{i[:desc]}
      HTML end def nicovideo_html( i ) <<-HTML
      #{h i[:title]}

      #{i[:date][0,10]}
      再生: #{i[:view].scan(/\d+?(?=\d{3}*$)/).join(",")}
      コメント: #{i[:comment_num].scan(/\d+?(?=\d{3}*$)/).join(",")}
      マイリスト: #{i[:mylist].scan(/\d+?(?=\d{3}*$)/).join(",")}

      #{h i[:title]} (#{i[:length].split(/:/).map{|j|'%02d' % j.to_i}.join(':')})
      #{i[:desc]}

      #{i[:comment]}

      HTML end tdiary-contrib-5.0.8/plugin/ja/openid.rb000066400000000000000000000005751325711763500201720ustar00rootroot00000000000000# openid.rb: Japanese resource @openid_conf_label = 'OpenID' @openid_service_label = 'OpenID認証サービス名' @openid_service_desc = 'あなたが使っているOpenIDの認証サービス名を選んでください' @openid_id_label = 'あなたのID' @openid_id_desc = '上で選択した認証サービスに登録してある、あなたのIDを入力してください' tdiary-contrib-5.0.8/plugin/ja/section_footer.rb000066400000000000000000000006771325711763500217410ustar00rootroot00000000000000# section_footer.rb: Japanese resource @section_footer_delicious_label = "このエントリの del.icio.us history" @section_footer_hatenabm_label = "このエントリを含むはてなブックマーク" @section_footer_ldclip_label = "このエントリを含む livedoor クリップ" @section_footer_buzzurl_label = "このエントリを含む Buzzurl" @section_footer_yahoobm_label = "このエントリを含む Yahoo!ブックマーク" tdiary-contrib-5.0.8/plugin/ja/section_footer2.rb000066400000000000000000000002571325711763500220150ustar00rootroot00000000000000# -*- coding: utf-8 -*- # section_footer2.rb: Japanese resource @section_footer2_delicious_label = "このエントリの Delicious history" @section_footer2_locale = 'ja_JP' tdiary-contrib-5.0.8/plugin/ja/socialbutton.rb000066400000000000000000000004661325711763500214210ustar00rootroot00000000000000# -*- coding: utf-8 -*- # section_footer2.rb: Japanese resource @socialbutton_label_conf = 'ソーシャルボタン' @socialbutton_label_enables = 'ボタンを表示するサービス' @socialbutton_label_twitter_via = 'ツイート時に表示するユーザ名(あなたのTwitterアカウント名)' tdiary-contrib-5.0.8/plugin/ja/yo_update.rb000066400000000000000000000040501325711763500206750ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # yo_update.rb - Japanese resource # # Copyright (C) 2014, zunda # # Permission is granted for use, copying, modification, # distribution, and distribution of modified versions of this # work under the terms of GPL version 2 or later. # def yo_update_conf_label '更新時にYoを送る' end def yo_update_test_result_label(username, result) "- #{h username} に Yo を送りました: #{h result}" end def yo_update_conf_html(conf, n_subscribers, test_result) action_label = { 'send_on_update' => '日記が追加された時', 'send_on_comment' => 'ツッコミされた時', } <<-HTML

      API key

      Username

      Yo を送るタイミング

        #{%w(send_on_update send_on_comment).map{|action| checked = conf["yo_update.#{action}"] ? ' checked' : '' %Q|
      • | }.join("\n\t")}

      Yo をにリンク(不要なら空白)をつけて送ってみる#{test_result}

      現在の受信者数

      #{h n_subscribers}

      Yoボタン

      ページのどこかに下記を追加してください

      <div id="yo-button"></div>

      やり方

      1. 個人用 Yo アカウントで http://dev.justyo.co/ にログインする
      2. ページ内の指示に従って APIアカウントを作成する。 Callback URL は空白のままにしてください
      3. API key と API username を上にコピーする
      HTML end tdiary-contrib-5.0.8/plugin/jdate.rb000066400000000000000000000012211325711763500173760ustar00rootroot00000000000000# jdate.rb $Revision: 1.1 $ # #「%J」で日本語の曜日名を出す # pluginに入れるだけで動作する。 # 日付フォーマットなどで「%J」を指定するとそこが日本語の曜日になる # # Copyright (c) 2003 TADA Tadashi # You can distribute this file under the GPL. # unless Time::new.respond_to?( :strftime_jdate_backup ) then eval( <<-MODIFY_CLASS, TOPLEVEL_BINDING ) class Time alias strftime_jdate_backup strftime JWDAY = %w(日 月 火 水 木 金 土) def strftime( format ) strftime_jdate_backup( format.gsub( /%J/, JWDAY[self.wday] ) ) end end MODIFY_CLASS end tdiary-contrib-5.0.8/plugin/jholiday.rb000066400000000000000000000006701325711763500201210ustar00rootroot00000000000000require 'Calendar.rb' require 'date' unless Time::new.respond_to?( :strftime_holiday_backup ) then eval( <<-MODIFY_CLASS, TOPLEVEL_BINDING ) class Time alias strftime_holiday_backup strftime def strftime( format ) holiday = "" day = Day.new(self.day,self.month,self.year,self.wday) holiday = day.holiday_name_jp if day.holiday? strftime_holiday_backup( format.gsub( /%K/, holiday ) ) end end MODIFY_CLASS end tdiary-contrib-5.0.8/plugin/jmonth.rb000066400000000000000000000013541325711763500176150ustar00rootroot00000000000000# jmonth.rb $Revision: 1.1 $ # #「%i」で日本語の陰暦月名を出す # pluginに入れるだけで動作する。 # 日付フォーマットなどで「%i」を指定するとそこが陰暦月名になる # # Copyright (c) 2005 sasasin/SuzukiShinnosuke # You can distribute this file under the GPL. # unless Time::new.respond_to?( :strftime_jmonth_backup ) then eval( <<-MODIFY_CLASS, TOPLEVEL_BINDING ) class Time alias strftime_jmonth_backup strftime JMONTH = %w(睦月 如月 弥生 卯月 皐月 水無月 文月 葉月 長月 神無月 霜月 師走) def strftime( format ) strftime_jmonth_backup( format.gsub( /%i/, JMONTH[self.month-1] ) ) end end MODIFY_CLASS end tdiary-contrib-5.0.8/plugin/jquery_ui_theme.rb000066400000000000000000000022331325711763500215110ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # jquery_ui.rb - use jQuery UI # # Copyright (C) 2012, tamoot # You can redistribute it and/or modify it under GPL. # # # not support # return if feed? add_header_proc do if /\A(?:form|preview|append|edit|update)\z/ =~ @mode themes = @conf['jquery_ui.theme'] if themes.nil? || theme == '' themes = 'base' end jquery_ui = '' jquery_ui << %Q|\n| jquery_ui else '' end end add_conf_proc( 'jquery_ui_theme', 'jQuery UI Theme' ) do if @mode == 'saveconf' then @conf['jquery_ui.theme'] = @cgi.params['jquery_ui.theme'][0] end <<-HTML

      Theme name

      sample) blitzer, flick .. See JQuery UI Theme.

      default is base.

      HTML end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/plugin/jroku.rb000066400000000000000000000016701325711763500174510ustar00rootroot00000000000000# jroku.rb $Revision: 1.1 $ # #「%R」で六曜を出す # 動かすためには # http://www.funaba.org/calendar.html#calendar # で配布されているClendarモジュールと付属しているcalclass.rbが必要 # 日付フォーマットなどで「%R」を指定するとそこが六曜になる # # Copyright (c) 2005 SHIBATA Hiroshi # You can distribute this file under the GPL. # require 'calclass.rb' unless Time::new.respond_to?( :strftime_jroku_backup ) then eval( <<-MODIFY_CLASS, TOPLEVEL_BINDING ) class Time alias strftime_jroku_backup strftime JROKU = %w(大安 赤口 先勝 友引 先負 仏滅) def strftime( format ) d=Gregorian.new(self.month, self.day, self.year) q_d = Calendar.kyureki_from_absolute(d.abs) index = (q_d[0] + q_d[2]) % 6 strftime_jroku_backup( format.gsub( /%R/, JROKU[index] ) ) end end MODIFY_CLASS end tdiary-contrib-5.0.8/plugin/jyear.rb000066400000000000000000000021331325711763500174240ustar00rootroot00000000000000# jyear.rb $Revision: 1.1 $ # # 西暦を和暦に変換するプラグイン。 # 日記やツッコミの日付フォーマットで使う。 # 「%Y」で「2005」のところを、「%K」で「平成17」と表示。 # pluginに入れるだけで動作する。 # # Copyright (c) 2005 sasasin/SuzukiShinnosuke # You can distribute this file under the GPL. # unless Time::new.respond_to?( :strftime_jyear_backup ) then eval( <<-MODIFY_CLASS, TOPLEVEL_BINDING ) class Time alias strftime_jyear_backup strftime def strftime( format ) case self.year when 0 .. 1926 gengo = "昔々" if self.year == 1926 && self.month == 12 && self.day >=25 then gengo = "昭和元年" end when 1927 .. 1989 jyear = self.year - 1925 gengo = "昭和" + jyear.to_s if self.year == 1989 && self.month == 1 && self.day >= 8 then gengo = "平成元年" end else jyear = self.year - 1988 gengo = "平成" + jyear.to_s end strftime_jyear_backup( format.gsub( /%K/, gengo ) ) end end MODIFY_CLASS end tdiary-contrib-5.0.8/plugin/latlonglab_route.rb000066400000000000000000000012311325711763500216450ustar00rootroot00000000000000# # latlonglab_route.rb - tDiary plugin for LatLongLab Route # # Copyright (C) 2009, Michitaka Ohno # Copyright (C) 2010, KAYA Satoshi # You can redistribute it and/or modify it under GPL2. # def route( id, w = 480, h = 480 ) if feed? return %Q|

      Link to LatLongLab Route

      | end if @conf.iphone? w = 240 h = 380 end <<-HTML
      HTML end tdiary-contrib-5.0.8/plugin/lazy_referer.rb000066400000000000000000000017621325711763500210120ustar00rootroot00000000000000# -*- coding: utf-8; -*- # # lazy_referer.rb: lazy loading referer # # Copyright (C) 2013 by MATSUOKA Kohei # You can distribute it under GPL. # if /^(day|form|edit)$/ =~ @mode and not bot? then enable_js('referer.js') # # overwrite method: draw only referer area (content will feach with ajax) # def referer_of_today_long( diary, limit ) return if limit == 0 return unless diary date = diary.date.strftime('%Y%m%d') # FIXME: endpoint is should created by TDiary::Plugin, because easy customize routing endpoint = "#{@conf.index}?plugin=referer&date=#{date}" %Q[\n] end end # # return referer of date as is (html) # add_content_proc('referer') do |date| diary = @diaries[date] referer_load_current( diary ) referer_of_today_long( diary, 100 ) end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: tdiary-contrib-5.0.8/plugin/livedoor_weather.rb000066400000000000000000000131571325711763500216640ustar00rootroot00000000000000# -*- coding: utf-8 -*- # livedoor_weather.rb # # insert weather information using livedoor weather web service. # # Copyright (C) 2007 SHIBATA Hiroshi # You can redistribute it and/or modify it under GPL2. # require 'open-uri' require 'timeout' require 'time' @lwws_rest_url = 'http://weather.livedoor.com/forecast/webservice/json/v1' def lwws_init @conf['lwws.city_id'] ||= 130010 @conf['lwws.icon.disp'] ||= "" @conf['lwws.max_temp.disp'] ||= "" @conf['lwws.min_temp.disp'] ||= "" @conf['lwws.cache'] ||= "" @conf['lwws.cache_time'] ||= 6 end def lwws_request( city_id ) url = @lwws_rest_url.dup url << "?city=#{city_id}" proxy = @conf['proxy'] proxy = 'http://' + proxy if proxy Timeout.timeout( 10 ) do open( url, :proxy => proxy ) {|f| f.read } end end def lwws_get lwws_init city_id = @conf['lwws.city_id'] cache_time = @conf['lwws.cache_time'] * 60 * 60 file_name = "#{@cache_path}/lwws/#{Time.now.strftime("%Y%m%d")}.json" begin Dir.mkdir("#{@cache_path}/lwws") unless File.directory?("#{@cache_path}/lwws") cached_time = if File.exist?( file_name ) File.mtime( file_name ) else nil end update = true if @conf['lwws.cache'] == "t" && cached_time && Time.now > cached_time + cache_time if cached_time.nil? || update json = lwws_request(city_id) File.open(file_name, 'wb') {|f| f.write(json)} end rescue => e @logger.error( e ) end end def lwws_to_html(date) lwws_init file_name = "#{@cache_path}/lwws/#{date.strftime("%Y%m%d")}.xml" begin # http://weather.livedoor.com/help/restapi_close if Time.parse('20130331') < date file_name.sub!(/xml/, 'json') require 'json' doc = JSON.parse(File.read(file_name)) telop = @conf.to_native( doc["forecasts"][0]["telop"], 'utf-8' ) # 「今日」のデータに気温は含まれない場合がある max_temp = doc["forecasts"][0]["temperature"]["max"]["celsius"] rescue nil min_temp = doc["forecasts"][0]["temperature"]["min"]["celsius"] rescue nil detail_url = doc["link"] title = @conf.to_native( doc["forecasts"][0]["image"]["title"], 'utf-8' ) url = doc["forecasts"][0]["image"]["url"] width = doc["forecasts"][0]["image"]["width"] height = doc["forecasts"][0]["image"]["height"] else require 'rexml/document' doc = REXML::Document.new(File.read(file_name)).root telop = @conf.to_native( doc.elements["telop"].text, 'utf-8' ) max_temp = doc.elements["temperature/max/celsius"].text min_temp = doc.elements["temperature/min/celsius"].text detail_url = doc.elements["link"].text title = @conf.to_native( doc.elements["image/title"].text, 'utf-8' ) url = doc.elements["image/url"].text width = doc.elements["image/width"].text height = doc.elements["image/height"].text end result = "" result << %Q|
      | if @conf['lwws.icon.disp'] != "t" then result << %Q|#{telop}| else result << %Q|#{title}| end if @conf['lwws.max_temp.disp'] == "t" and not max_temp.nil? then result << %Q| #{@lwws_max_temp_label}:#{h(max_temp)}#{@celsius_label}| end if @conf['lwws.min_temp.disp'] == "t" and not min_temp.nil? then result << %Q| #{@lwws_min_temp_label}:#{h(min_temp)}#{@celsius_label}| end result << %Q|
      | result rescue StandardError, Errno::ENOENT => e @logger.error( e ) '' end end def lwws_conf_proc lwws_init if @mode == 'saveconf' then @conf['lwws.city_id'] = @cgi.params['lwws.city_id'][0].to_i @conf['lwws.icon.disp'] = @cgi.params['lwws.icon.disp'][0] @conf['lwws.max_temp.disp'] = @cgi.params['lwws.max_temp.disp'][0] @conf['lwws.min_temp.disp'] = @cgi.params['lwws.min_temp.disp'][0] @conf['lwws.cache'] = @cgi.params['lwws.cache'][0] @conf['lwws.cache_time'] = @cgi.params['lwws.cache_time'][0].to_i end result = '' result << <<-HTML

      #{@lwws_label_city_id}

      #{@lwws_desc_city_id}

      HTML result << %Q|

      #{@lwws_icon_label}

      | checked = "t" == @conf['lwws.icon.disp'] ? ' checked' : '' result << %Q|

      | result << %Q|

      #{@lwws_label_disp_item}

      | result << %Q|

      #{@lwws_desc_disp_item}

      | result << %Q|
        | checked = "t" == @conf['lwws.max_temp.disp'] ? ' checked' : '' result << %Q|
      • | checked = "t" == @conf['lwws.min_temp.disp'] ? ' checked' : '' result << %Q|
      • | result << %Q|
      | result << %Q|

      #{@lwws_label_cache}

      | checked = "t" == @conf['lwws.cache'] ? ' checked' : '' result << %Q|

      | result << %Q|

      #{@lwws_desc_cache_time}

      | result << %Q|

      | result end add_body_enter_proc do |date| unless feed? or bot? lwws_to_html(date) end end add_update_proc do lwws_get end add_conf_proc( 'lwws', @lwws_plugin_name ) do lwws_conf_proc end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/plugin/make_link.rb000066400000000000000000000020431325711763500202440ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2011, KADO Masanori # You can redistribute it and/or modify it under GPL. # needs category.rb plugin add_edit_proc do <<-HTML HTML end tdiary-contrib-5.0.8/plugin/makerss_category.rb000066400000000000000000000016641325711763500216640ustar00rootroot00000000000000# # makerss_category.rb: extension for makerss plugin. # # Copyright (C) 2007 by SHIBATA Hiroshi # Distributed under GPL2. # # Usage: # @conf['makerss.category'] = ["mixi", "sns"] # class MakeRssCategory < MakeRssFull def title '(category only)' end def item( seq, body, rdfsec ) return unless rdfsec.section.respond_to?( :body_to_html ) return if rdfsec.section.categories.length == 0 rdfsec.section.categories.each do |category| if @conf['makerss.category'].include?(category) super end end end def file f = @conf['makerss.category.file'] || 'category.rdf' f = 'category.rdf' if f.length == 0 f =~ %r|^/| ? f : "#{document_root}/#{f}" end def write( encoder ) super( encoder ) end def url u = @conf['makerss.category.url'] || "#{@conf.base_url}category.rdf" u = "#{@conf.base_url}category.rdf" if u.length == 0 u end end @makerss_rsses << MakeRssCategory::new( @conf, @cgi ) tdiary-contrib-5.0.8/plugin/makerss_comment.rb000066400000000000000000000013261325711763500215040ustar00rootroot00000000000000# # makerss_comment.rb: extension for makerss plugin. # # Copyright (C) 2007 by SHIBATA Hiroshi # Distributed under GPL2. # class MakeRssComments < MakeRssFull def title '(comments only)' end def item( seq, body, rdfsec ) return if rdfsec.section.respond_to?( :body_to_html ) super end def file f = @conf['makerss.no_comments.file'] || 'comments.rdf' f = 'comments.rdf' if f.length == 0 f =~ %r|^/| ? f : "#{document_root}/#{f}" end def write( encoder ) super( encoder ) end def url u = @conf['makerss.no_comments.url'] || "#{@conf.base_url}comments.rdf" u = "#{@conf.base_url}comments.rdf" if u.length == 0 u end end @makerss_rsses << MakeRssComments::new( @conf, @cgi ) tdiary-contrib-5.0.8/plugin/mathjax.rb000066400000000000000000000014071325711763500177510ustar00rootroot00000000000000# -*- coding: utf-8 -*- # mathjax.rb $Revision: $ # # MathJaxを使った数式表示のためのプラグイン # # MathJaxでTeXやMathMLを使った数式を埋め込むことができます。 # # MathJaxについては、http://www.mathjax.org/ を参照のこと # # Copyright (C) 2014 by Yuh Ohmura # =begin ChangeLog 2017-06-05 Yuh Ohmura * Modity MathJax address. 2014-12-17 Yuh Ohmura * created. =end add_header_proc do ' ' end tdiary-contrib-5.0.8/plugin/microsummary.rb000066400000000000000000000033521325711763500210450ustar00rootroot00000000000000# microsummary.rb # # Copyright (c) 2006 elytsllams # Distributed under the GPL # add_header_proc do generator_xml = @conf['generator.xml'] if generator_xml != nil and @mode == 'latest' and !@cgi.valid?( 'date' ) %Q|\t\n| end end def create_xml file_name xml = <<-XML ^#{@conf.base_url.gsub(/\./, '\\.')}$ XML begin File::open( file_name, 'w' ) do |f| f.print to_utf8( xml ) end rescue end end def microsummary_init @conf['generator.xml'] ||= "" create_xml( @conf['generator.xml'] ) unless File::exists? @conf['generator.xml'] end if @mode == 'saveconf' def saveconf_microsummary @conf['generator.xml'] = @cgi.params['generator.xml'][0] end end tdiary-contrib-5.0.8/plugin/mm_footer.rb000066400000000000000000000124151325711763500203050ustar00rootroot00000000000000# # mm_footer.rb # # MM ( http://1470.net/mm/) のmylistを各日付に貼り付けるtDiaryプラグイン # # Licence: GPL # Author: ishinao # require 'nkf' add_body_leave_proc(Proc.new do |date| oldest_date = Time.local(2005, 1, 11) if date > oldest_date if @mode == 'day' or @mode == 'latest' if date < Time.local(2006, 7, 6) mm_user = 82 # your MM id url = "http://1470.net/mm/mylist.html/#{mm_user}?date=#{date.strftime('%Y-%m-%d')}" rssurl = "http://1470.net/mm/mylist.html/#{mm_user}?date=#{date.strftime('%Y-%m-%d')}&mode=rss" template_list = '
    • #{content}
    • ' else userName = 'hsbt' # your 1470.net id url = "http://1470.net/user/#{userName}/#{date.strftime('%Y/%m/%d')}" rssurl = "http://1470.net/user/#{userName}/#{date.strftime('%Y/%m/%d')}/feed" template_list = '
    • #{content.gsub(/href="\//, "href=\"http://1470.net\/")}
    • ' end template_head = %Q[\n" cache_time = 3600; if date.strftime('%Y-%m-%d') != Time.now.strftime('%Y-%m-%d') cache_time = 3600 * 12; end NKF.nkf('-e', mm_footer(rssurl, 50, cache_time, template_head, template_list, template_foot)) else '' end end end) require "rss/rss" MM_FOOTER_FIELD_SEPARATOR = "\0" MM_FOOTER_ENTRY_SEPARATOR = "\1" MM_FOOTER_VERSION = "0.0.5i" MM_FOOTER_HTTP_HEADER = { "User-Agent" => "tDiary RSS recent plugin version #{MM_FOOTER_VERSION}. " << "Using RSS parser version is #{::RSS::VERSION}.", } def mm_footer(url, max = 5, cache_time = 3600, \ template_head = "\n") url.untaint cache_file = "#{@cache_path}/rss-recent/rss-recent.#{CGI.escape(url)}" mm_footer_cache_rss(url, cache_file, cache_time.to_i) return '' unless test(?r, cache_file) rv = template_head i = 0 mm_footer_read_from_cache(cache_file).each do |title, url, time, content| break if i >= max next if (url.nil? or title.nil?) rv << eval('%Q[' + template_list + ']') i += 1 end rv << template_foot if i > 0 rv else '' end end class InvalidResourceError < StandardError; end def mm_footer_cache_rss(url, cache_file, cache_time) cached_time = nil cached_time = File.mtime(cache_file) if File.exist?(cache_file) if cached_time.nil? or Time.now > cached_time + cache_time require 'time' require 'open-uri' require 'net/http' require 'uri/generic' require 'rss/parser' require 'rss/1.0' require 'rss/2.0' require 'rss/dublincore' require 'rss/content' begin uri = URI.parse(url) raise URI::InvalidURIError if uri.scheme != "http" rss_source = mm_footer_fetch_rss(uri, cached_time) raise InvalidResourceError if rss_source.nil? # parse RSS rss = ::RSS::Parser.parse(rss_source, false) raise ::RSS::Error if rss.nil? # pre processing begin rss.output_encoding = @conf.charset || charset rescue ::RSS::UnknownConversionMethodError end rss_infos = rss.items.collect do |item| mm_footer_pubDate_to_dc_date(item) [item.title, item.link, item.dc_date, item.content_encoded] end mm_footer_write_to_cache(cache_file, rss_infos) rescue URI::InvalidURIError mm_footer_write_to_cache(cache_file, [['Invalid URI', url]]) rescue InvalidResourceError, ::RSS::Error # mm_footer_write_to_cache(cache_file, [['Invalid Resource', url]]) # when cannot get valid RSS, use old cache end end end def mm_footer_fetch_rss(uri, cache_time) rss = nil begin uri.open(mm_footer_http_header(cache_time)) do |f| case f.status.first when "200" rss = f.read # STDERR.puts "Got RSS of #{uri}" when "304" # not modified # STDERR.puts "#{uri} does not modified" else raise InvalidResourceError end end rescue TimeoutError, SocketError, StandardError, SecurityError # occured in redirect raise InvalidResourceError end rss end def mm_footer_http_header(cache_time) header = MM_FOOTER_HTTP_HEADER.dup if cache_time.respond_to?(:rfc2822) header["If-Modified-Since"] = cache_time.rfc2822 end header end def mm_footer_write_to_cache(cache_file, rss_infos) File.open(cache_file, 'w') do |f| f.flock(File::LOCK_EX) rss_infos.each do |info| f << info.join(MM_FOOTER_FIELD_SEPARATOR) f << MM_FOOTER_ENTRY_SEPARATOR end f.flock(File::LOCK_UN) end end def mm_footer_read_from_cache(cache_file) require 'time' infos = [] File.open(cache_file) do |f| while info = f.gets(MM_FOOTER_ENTRY_SEPARATOR) info = info.chomp(MM_FOOTER_ENTRY_SEPARATOR) infos << info.split(MM_FOOTER_FIELD_SEPARATOR) end end infos.collect do |title, url, time, content| [ mm_footer_convert(title), mm_footer_convert(url), mm_footer_convert(time) {|time| Time.parse(time)}, mm_footer_convert(content) ] end end def mm_footer_convert(str) if str.nil? or str.empty? nil else if block_given? yield str else str end end end def mm_footer_pubDate_to_dc_date(target) if target.respond_to?(:pubDate) class << target alias_method(:dc_date, :pubDate) end end end tdiary-contrib-5.0.8/plugin/monthly_autopagerize.rb000066400000000000000000000034151325711763500225670ustar00rootroot00000000000000# # monthly_autopagerize.rb - tDiary plugin # # add and tags for AutoPagerize at monthly mode # # Copyright (C) 2009 MATSUI Shinsuke # You can redistribute it and/or modify it under GPL2. # if @mode == 'month' then add_header_proc do stream = @conf['monthly_autopagerize.stream'] || 0 result = String.new ym = [] @years.keys.each do |y| ym += @years[y].collect {|m| y + m} end ym.sort! now = @date.strftime( '%Y%m' ) return '' unless ym.index( now ) prev_month = ym.index( now ) == 0 ? nil : ym[ym.index( now )-1] next_month = ym[ym.index( now )+1] case stream #when 0 # rel_prev_month = 'next' # rel_next_month = 'prev' when 1 rel_prev_month = 'prev' rel_next_month = 'next' else rel_prev_month = 'next' rel_next_month = 'prev' end if prev_month then result << %Q[\n\t] end if next_month then result << %Q[\n\t] end result.chop.chop end end add_conf_proc( 'monthly_autopagerize', 'Monthly AutoPagerize' ) do if @mode == 'saveconf' then @conf['monthly_autopagerize.stream'] = @cgi.params['monthly_autopagerize.stream'][0].to_i end <<-HTML

      Stream of Monthly AutoPagerize

      HTML end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vi: ts=3 sw=3 tdiary-contrib-5.0.8/plugin/my_hotentry.rb000066400000000000000000000077441325711763500207100ustar00rootroot00000000000000# show my hot-entry in Hatena::Bookmark # # usage: # <%= my_hotentry %> # # Copyright (c) MATSUOKA Kohei # Distributed under the GPL # require 'uri' require 'open-uri' require 'rexml/document' require 'pstore' require 'timeout' # 人気の日記のソート順(新着順: eid, 注目順: hot, 人気順: count) @conf ||= {} @conf['my_hotentry.sort'] ||= 'hot' class MyHotEntry def initialize(dbfile) @dbfile = dbfile end # 人気の日記の一覧を返す def entries r = nil PStore.new(@dbfile).transaction(true) do |db| r = db[:entries] end r || [] end # 人気の日記一覧を取得する def update(base_url, options = {}) options[:title] ||= '' options[:sort] ||= 'eid' options[:threshold] ||= 3 # RSSを取得 rss = nil rss_url = 'http://b.hatena.ne.jp/entrylist?mode=rss&url=' rss_url << URI.escape(base_url, /[^-.!~*'()\w]/n) rss_url << "&sort=#{options[:sort]}&threshold=#{options[:threshold]}" begin Timeout.timeout(5) do # convert Tempfile to String because REXML can't accept Tempfile open(rss_url) do |f| rss = REXML::Document.new(f.readlines.join("\n")) end end rescue TimeoutError => e return end # RDF/itemが空ならDBを更新しない (たまにitemが空のデータが返るため) return if rss.elements['rdf:RDF/item'].nil? # キャッシュに格納する PStore.new(@dbfile).transaction do |db| db[:entries] = [] rss.elements.each('rdf:RDF/item') do |item| url = item.elements['link'].text title = item.elements['title'].text # リンク先のタイトルからサイト名と日付を取り除く title.sub!(/(?: - )?#{options[:html_title]}(?: - )?/, '') title.sub!(/\(\d{4}-\d{2}-\d{2}\)/, '') db[:entries].push({ :url => url, :title => title }) end end end end # キャッシュファイルのパスを取得する def my_hotentry_dbfile cache_dir = "#{@cache_path}/hatena" Dir::mkdir(cache_dir) unless File::directory?(cache_dir) "#{cache_dir}/my_hotentry.dat" end # 人気の日記一覧を表示する def my_hotentry(count = 5) dbfile = my_hotentry_dbfile hotentry = MyHotEntry.new(dbfile) r = %Q|
        \n| hotentry.entries[0...count].each do |entry| entry_link = %Q|#{CGI::escapeHTML(entry[:title])}| escape_url = entry[:url].gsub(/#/, '%23') b_image = "http://b.hatena.ne.jp/entry/image/#{escape_url}" b_link = "http://b.hatena.ne.jp/entry/#{escape_url}" b_title = "このエントリを含むはてなブックマーク" bookmark_link = %Q|| r << "\t\t
      • #{entry_link} #{bookmark_link}
      • " end r << %Q|
      | r << %Q|
      \tPowered by Hatena Bookmark
      \n| end # 人気の日記一覧を更新する def my_hotentry_update dbfile = my_hotentry_dbfile hotentry = MyHotEntry.new(dbfile) hotentry.update(@conf.base_url, :html_title => @conf.html_title, :sort => @conf['my_hotentry.sort']) end if __FILE__ == $0 # コマンドラインから実行した場合 # tdiary.conf に base_url を設定しないと動作しない begin require 'tdiary' rescue LoadError STDERR.puts "tdiary.rb not found." STDERR.puts "please execute in tdiary base directory" exit 1 end cgi = CGI::new @conf = TDiary::Config::new(cgi) @cache_path = @conf.cache_path || "#{@conf.data_path}cache" my_hotentry_update puts my_hotentry else # 人気の日記一覧を取得する (日記更新時) add_update_proc do # ツッコミ時は実行しない if @mode == 'append' or @mode == 'replace' begin my_hotentry_update rescue end end end end tdiary-contrib-5.0.8/plugin/navi_day.rb000066400000000000000000000067631325711763500201210ustar00rootroot00000000000000# # navi_day.rb # # navi_day: 「前の日記」や「次の日記」を“月またぎ”に対応させる。 # # 日単位での表示の時の「前の日記」や「次の日記」のリンクが、 # 異なる月の日記を正しく指せない場合があるという tDiary の制限を # 解消するプラグインです。以前よりある navi_user.rb と機能的には # 同じですが、navi_user.rb よりは処理がずっと軽くなっています。 # また、日記の表示状態(非表示の日記)に対する考慮もなされています。 # # tDiary 2.0 以降で使えると思います。セキュアモードでも使えますが、 # セキュアモードの場合は、モバイル端末からのアクセスに対しては # このプラグインは効力を持ちません(tDiary セキュア環境の制限: # モバイル端末の場合は本文を出力するときに calc_links が呼ばれる # ため)。 # # navi_user.rb と併用すると navi_user.rb の方が優先されますので、 # このプラグインを使うときには必ず navi_user.rb を外してください。 # # Copyright (C) 2007, MIYASAKA Masaru # You can redistribute it and/or modify it under GPL2. # # Last Modified : May 27, 2007 # # for tDiary 2.0.X if not TDiaryMonth.method_defined?(:diaries) then eval( <<-MODIFY_CLASS, TOPLEVEL_BINDING ) module TDiary class TDiaryMonth attr_reader :diaries end end MODIFY_CLASS end class NaviDayCGI attr_reader :params def referer; nil; end def initialize @params = Hash.new([]) end end alias :calc_links_navi_day_backup :calc_links def calc_links if not @conf.secure and \ (/day|edit/ =~ @mode or \ /latest|month|nyear/ =~ @mode) then if /(latest|month|nyear)/ === @mode today = @diaries.keys.sort[-1] else today = @date.strftime('%Y%m%d') end days = @diaries.keys days |= [today] days.sort! days.unshift(nil).push(nil) today_index = days.index(today) days[0 .. today_index - 1].reverse_each do |prev_day| @prev_day = prev_day break unless @prev_day break if (@mode == 'edit') or @diaries[@prev_day].visible? end days[today_index + 1 .. -1].each do |next_day| @next_day = next_day break unless @next_day break if (@mode == 'edit') or @diaries[@next_day].visible? end if not @prev_day or not @next_day then cgi = NaviDayCGI.new years = [] @years.each do |k, v| v.each do |m| years << k + m end end this_month = @date.strftime('%Y%m') years |= [this_month] years.sort! years.unshift(nil).push(nil) this_month_index = years.index(this_month) years[0 .. this_month_index - 1].reverse_each do |prev_month| break unless not @prev_day and prev_month cgi.params['date'] = [prev_month] diaries = TDiaryMonth.new(cgi, '', @conf).diaries days = diaries.keys.sort days.unshift(nil) days.reverse_each do |prev_day| @prev_day = prev_day break unless @prev_day break if (@mode == 'edit') or diaries[@prev_day].visible? end end years[this_month_index + 1 .. -1].each do |next_month| break unless not @next_day and next_month cgi.params['date'] = [next_month] diaries = TDiaryMonth.new(cgi, '', @conf).diaries days = diaries.keys.sort days.push(nil) days.each do |next_day| @next_day = next_day break unless @next_day break if (@mode == 'edit') or diaries[@next_day].visible? end end end else calc_links_navi_day_backup end end tdiary-contrib-5.0.8/plugin/navi_this_month.rb000066400000000000000000000006301325711763500215030ustar00rootroot00000000000000# navi-this-month.rb # ref. http://www.tom.sfc.keio.ac.jp/~sakai/d/?date=20080628#p01 # alias navi_this_month__orig__navi_user_day navi_user_day def navi_user_day result = navi_this_month__orig__navi_user_day if @mode=='day' this_month = @date.strftime( '%Y%m' ) result << navi_item( "#{@index}#{anchor this_month}", "#{navi_this_month}" ) end result end def navi_this_month; "月表示"; end tdiary-contrib-5.0.8/plugin/nhk_program_info.rb000066400000000000000000000057041325711763500216430ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # nhk_program_info.rb - embedded NHK program information # refer to following URL. # http://api-portal.nhk.or.jp/ja # # Copyright (C) 2014, tamoot # You can redistribute it and/or modify it under GPL2. # require 'json' require 'date' require 'timeout' require 'open-uri' def nhk_program_info(id, service, area = nil) area = @conf['nhk_api.default.area'] if area.nil? || area == "" json = nil begin json = call_nhk_json(id, service, area) rescue return %Q|

      #{__FILE__}: error, #{$!}

      | end stime = DateTime::parse(json["start_time"]).strftime("%Y/%m/%d %H:%M:%S") etime = DateTime::parse(json["end_time"]).strftime("%Y/%m/%d %H:%M:%S") return <<-PROGRAM_HTML PROGRAM_HTML end def call_nhk_json(id, service, area) data = nil nhk_endpoint = "http://api.nhk.or.jp/v1/pg/info/#{area}/#{service}/#{id}.json?key=#{@conf['nhk_api.id']}" nhk_cache_path = "#{@cache_path}/nhk" Dir::mkdir(nhk_cache_path) unless File::directory?(nhk_cache_path) cache = "#{nhk_cache_path}/#{area}_#{service}_#{id}.json" begin data = File.read(cache) File::delete(cache) if Time::now > File::mtime( cache ) + 60*60*24*30 rescue open_param = [nhk_endpoint] open_param << {:proxy => "http://#{@conf['proxy']}"} if @conf['proxy'] status = nil data = nil Timeout.timeout(10) do open(*open_param){ |ff| data = ff.read; status = ff.status[0] } end raise "API Error" if status.to_s != '200' File::open(cache, 'wb') {|f| f.write(data) } end JSON::parse(data)['list'][service][0] end add_conf_proc( 'nhk', 'NHK API' ) do if @mode == 'saveconf' then @conf['nhk_api.id'] = @cgi.params['nhk_api.id'][0] @conf['nhk_api.default.area'] = @cgi.params['nhk_api.default.area'][0] end <<-HTML

      API key

      Register your tDiary and get API key.

      Go NHK API settings.

      Default Area

      Refer NHK API settings.

      HTML end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/plugin/nicovideo.rb000066400000000000000000000076151325711763500203030ustar00rootroot00000000000000# # nicovideo.rb - tDiary plugin for Nico Nico Video # # Copyright (C) 2012 TADA Tadashi # You can modify and/or distribute it under GPL. # # usage: # Link to the movie and show thumbnail, description...: # <%= nicovideo 'sm99999999' %> # # Link to the movie with original label: # <%= nicovideo 'sm99999999', 'movie title' %> # # Link to the movie with original label and link: # <%= nicovideo 'sm99999999', 'movie title', 'http://example.com/video' %> # # Show Inline player: # <%= nicovideo_player 'sm99999999' %> # # Show Inline player with size: # <%= nicovideo_player 'sm99999999', [400,300] %> # require 'net/http' require 'timeout' enable_js('nicovideo.js') unless base_url =~ /\Ahttps:/ def nicovideo_call_api( video_id ) uri = "http://ext.nicovideo.jp/api/getthumbinfo/#{video_id}" proxy = @conf['proxy'] proxy = 'http://' + proxy if proxy xml = Timeout.timeout( feed? ? 10 : 2 ) { px_host, px_port = (@conf['proxy'] || '').split( /:/ ) px_port = 80 if px_host and !px_port Net::HTTP::Proxy( px_host, px_port ).get_response( URI::parse( uri ) ).body } status = xml.scan(%r||).flatten.first if status == 'ok' then raw_api = xml.scan(%r|(.*)|m).flatten.first.scan(%r|<(.*?)>(.*)|) api = {} raw_api.each do |key, value| api[key] = @conf.to_native( value ) end api else raise ::Errno::ENOENT::new end end def nicovideo_inline( video_id, elem, label = nil, link = nil ) i = {} i[:id] = video_id i[:url] = link || elem['watch_url'] i[:thumb] = elem['thumbnail_url'] i[:title] = label || elem['title'] i[:desc] = elem['description'] i[:comment] = elem['last_res_body'] i[:date] = elem['first_retrieve'] i[:length] = elem['length'] i[:view] = elem['view_counter'] i[:comment_num] = elem['comment_num'] i[:mylist] = elem['mylist_counter'] if feed? then result = nicovideo_feed( i ) else result = nicovideo_html( i ) end result.gsub( /^\t+/, '' ) end def nicovideo_iframe( video_id ) %Q|\n| end def nicovideo_player(video_id, size = [640,360]) if feed? nicovideo(video_id) else q = size ? "?w=#{h size[0]}&h=#{h size[1]}" : '' %Q|| end end def nicovideo( video_id, label = nil, link = nil ) begin r = '' r << %Q|
      | api = nicovideo_call_api( video_id ) thumb = @conf.to_native( nicovideo_inline( video_id, api, label, link ), 'UTF-8' ) r << thumb r << '
      ' if feed? r.gsub!( /]*)?>/, '' ) r.gsub!( %r{}, '' ) else r << %Q|| end r rescue ::Errno::ENOENT "Sorry, #{video_id} was deleted." rescue Timeout::Error, NoMethodError, SecurityError, StandardError puts $! $@.each{|l| puts l} nicovideo_iframe( video_id ) end end tdiary-contrib-5.0.8/plugin/notify_miniblog.rb000066400000000000000000000072201325711763500215040ustar00rootroot00000000000000# # Copyright (C) 2007 peo # You can redistribute it and/or modify it under GPL2. # # modified hsbt. require 'net/http' @miniblog_config = (Struct.const_defined?("MiniBlogConfig") ? Struct::MiniBlogConfig : Struct.new("MiniBlogConfig", :host, :path)) @miniblog_list = { 'HatenaHaiku' => @miniblog_config.new('h.hatena.ne.jp', '/api/statuses/update.json'), } module Miniblog class Updater def initialize( user, pass, config ) @user = user @pass = pass @config = config end # this code is based on http://la.ma.la/blog/diary_200704111918.htm def update( status ) Net::HTTP.version_1_2 req = Net::HTTP::Post.new(@config.path) req.basic_auth(@user, @pass) req.body = status Net::HTTP.start( @config.host, 80 ) do |http| response = http.request(req) if response.body =~ /error/ raise 'update failed.' end end end end end def notify_miniblog notify_miniblog_init date = @date.strftime('%Y%m%d') diary = @diaries[date] sectitle = '' index = 0 diary.each_section do |sec| index += 1 sectitle = sec.subtitle end # strip category sectitle.gsub!(/\[[^\]]+\] */, '') url = URI.encode(@conf.base_url + anchor("#{date}p%02d" % index), /[^-.!~*'()\w]/n) prefix = @conf['miniblog.notify.prefix'] format = @conf['miniblog.notify.format'] source = 'tdiary/notify_miniblog.rb' status = 'status=' + format % [prefix, sectitle, url] + '&source=' + source if @conf['miniblog.service'] == "HatenaHaiku" then status += '&keyword=id:' + @conf['miniblog.user'] end config = @miniblog_list[@conf['miniblog.service']] begin miniblog_updater = Miniblog::Updater.new(@conf['miniblog.user'], @conf['miniblog.pass'], config) miniblog_updater.update( status ) rescue => e @logger.debug( e ) end end def notify_miniblog_init @conf['miniblog.notify.prefix'] ||= '[blog update]' @conf['miniblog.notify.format'] ||= '%s %s %s' @conf['miniblog.service'] ||= 'Twitter' end add_update_proc do if @mode == 'append' then notify_miniblog if @cgi.params['miniblog.notify'][0] == 'true' end end add_edit_proc do checked = '' if @mode == 'preview' then checked = @cgi.params['miniblog.notify'][0] == 'true' ? ' checked' : '' end <<-HTML
      HTML end add_conf_proc( 'notify_miniblog', 'MiniBlog' ) do notify_miniblog_init if @mode == 'saveconf' then @conf['miniblog.service'] = @cgi.params['miniblog.service'][0] @conf['miniblog.user'] = @cgi.params['miniblog.user'][0] @conf['miniblog.pass'] = @cgi.params['miniblog.pass'][0] @conf['miniblog.notify.prefix'] = @cgi.params['miniblog.notify.prefix'][0] @conf['miniblog.notify.format'] = @cgi.params['miniblog.notify.format'][0] end options = '' @miniblog_list.each_key do |key| options << %Q|\n| end <<-HTML

      MiniBlog Service

      Account Name

      Account Password

      Notify prefix

      Notify status format

      HTML end # vim:ts=3 tdiary-contrib-5.0.8/plugin/ogp.rb000066400000000000000000000036241325711763500171050ustar00rootroot00000000000000# ogp.rb - add Open Graph Protocol tags to header # # Copyright (c) 2011 MATSUOKA Kohei # You can redistribute it and/or modify it under GPL2. # # @conf['ogp.facebook.app_id'] - your facebook application ID. # @conf['ogp.facebook.admins'] - your facebook ID. def ogp_description(html) @conf.shorten(remove_tag(html), 200) end def ogp_image(html) images = html.scan(/ @conf['ogp.facebook.app_id'], 'fb:admins' => @conf['ogp.facebook.admins'] } if @mode == 'day' # remove original og:image generated at 00default.rb ogp.gsub!(/]+>\n/, '') diary = @diaries[@date.strftime('%Y%m%d')] if diary sections = diary.instance_variable_get(:@sections) section_index = @cgi.params['p'][0] || sections.size begin section = sections[section_index.to_i - 1].body_to_html section_html = apply_plugin(section) headers['og:description'] = ogp_description(section_html) headers['og:image'] = ogp_image(section_html) rescue end end end ogp + "\n" + headers.select {|key, val| val && !val.empty? }.map {|key, val| %Q|| }.join("\n") end add_conf_proc('Open Graph Protocol', 'Open Graph Protocol') do if @mode == 'saveconf' @conf['ogp.facebook.app_id'] = @cgi.params['ogp.facebook.app_id'][0] @conf['ogp.facebook.admins'] = @cgi.params['ogp.facebook.admins'][0] end <<-HTML

      Facebook Application ID

      Facebook User ID

      HTML end tdiary-contrib-5.0.8/plugin/ohmsha_estore.rb000066400000000000000000000006301325711763500211520ustar00rootroot00000000000000# -*- coding: utf-8 -*- # You can redistribute it and/or modify it under the same license as tDiary. # # display book info in https://estore.ohmsha.co.jp/ like amazon.rb # USAGE: {{ohmsha_estore '978427406694P'}} def ohmsha_estore( id, doc = nil ) "

      Ohmsha eBook Store is no longer available.

      \n" end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: tdiary-contrib-5.0.8/plugin/openid.rb000066400000000000000000000077121325711763500176000ustar00rootroot00000000000000# # openid.rb: Insert OpenID delegation information. $Revision: 1.10 $ # # Copyright (C) 2005, TADA Tadashi # You can redistribute it and/or modify it under GPL2. # @openid_config = (Struct.const_defined?("OpenIdConfig") ? Struct::OpenIdConfig : Struct.new("OpenIdConfig", :openid, :openid2, :x_xrds_location)) if /^(?:latest|conf|saveconf)$/ =~ @mode then @openid_list = { # service => @openid_config.new( # [openid.server, openid.delegate(replace as account name)], # openid # [openid2.provider, openid2.local_id(replace as account name)], # openid2 # 'X-XRDS-Location(replace as account name)'), 'Hatena' => @openid_config.new(['https://www.hatena.ne.jp/openid/server', 'http://www.hatena.ne.jp//']), 'livedoor' => @openid_config.new(['http://auth.livedoor.com/openid/server', 'http://profile.livedoor.com/']), 'LiveJournal' => @openid_config.new(['http://www.livejournal.com/openid/server.bml', 'http://.livejournal.com/']), 'OpenID.ne.jp' => @openid_config.new( ['http://www.openid.ne.jp/user/auth', 'http://.openid.ne.jp'], nil, 'http://.openid.ne.jp/user/xrds'), 'TypeKey' => @openid_config.new(['http://www.typekey.com/t/openid/', 'http://profile.typekey.com//']), 'Vox' => @openid_config.new(['http://www.vox.com/services/openid/server', 'http://.vox.com/']), 'myopenid.com' => @openid_config.new( ['http://www.myopenid.com/server', 'http://.myopenid.com'], # openid ['http://www.myopenid.com/server', 'http://.myopenid.com'], # openid2 "http://www.myopenid.com/xrds?username="), 'claimID.com' => @openid_config.new( ['http://openid.claimid.com/server', 'http://openid.claimid.com/'], nil, #['http://openid.claimid.com/server', 'http://openid.claimid.com/'], 'http://claimid.com//xrds'), 'Personal Identity Provider (PIP)' => @openid_config.new( ['http://pip.verisignlabs.com/server', 'http://.pip.verisignlabs.com/'], ['http://pip.verisignlabs.com/server', 'http://.pip.verisignlabs.com/'], 'http://pip.verisignlabs.com/user//yadisxrds'), 'Yahoo! Japan' => @openid_config.new( nil, ['https://open.login.yahooapis.jp/openid/op/auth', 'https://me.yahoo.co.jp/a/'], 'http://open.login.yahoo.co.jp/openid20/www.yahoo.co.jp/xrds'), 'Yahoo!' => @openid_config.new( nil, ['https://open.login.yahooapis.com/openid/op/auth', 'https://me.yahoo.com/a/'], 'http://open.login.yahooapis.com/openid20/www.yahoo.com/xrds'), } if @conf['openid.service'] and @conf['openid.id'] then openid_service = @openid_list[@conf['openid.service']] openid_id = @conf['openid.id'] result = '' add_header_proc do result = <<-HTML if openid_service.openid HTML result << <<-HTML if openid_service.openid2 HTML result << <<-HTML if openid_service.x_xrds_location HTML result.gsub( /^\t{2}/, '' ) end if openid_service end end add_conf_proc( 'openid', @openid_conf_label ) do if @mode == 'saveconf' then @conf['openid.service'] = @cgi.params['openid.service'][0] @conf['openid.id'] = @cgi.params['openid.id'][0] end options = '' @openid_list.each_key do |key| options << %Q|\n| end <<-HTML

      #{@openid_service_label}

      #{@openid_service_desc}

      #{@openid_id_label}

      #{@openid_id_desc}

      HTML end tdiary-contrib-5.0.8/plugin/opensearch_ad.rb000066400000000000000000000020501325711763500211030ustar00rootroot00000000000000# opensearch_ad.rb $Revision: 1.1 $ # # Copyright (c) 2008 SHIBATA Hiroshi # Distributed under the GPL # if /\A(?:latest|day)\z/ =~ @mode then if @conf['opensearch.xml'] and @conf['opensearch.title'] then opensearch_xml = @conf['opensearch.xml'] opensearch_title = @conf['opensearch.title'] add_header_proc do result = <<-HTML HTML result.gsub( /^\t\t/, '' ) end end end add_conf_proc( 'opensearch_ad', 'OpenSearch Auto-Discovery' ) do if @mode == 'saveconf' @conf['opensearch.xml'] = @cgi.params['opensearch.xml'][0] @conf['opensearch.title'] = @cgi.params['opensearch.title'][0] end <<-HTML

      Tilte for OpenSearch

      URI for OpenSearch description XML

      HTML end tdiary-contrib-5.0.8/plugin/picasa.rb000066400000000000000000000014351325711763500175560ustar00rootroot00000000000000# show photo image on Picasa Web Album # # usage: # picasa( src[, title[, place]] ) # - src: The url of the photo to show. # - title: title of photo. (optional) # - place: class name of img element. default is 'photo'. # # picasa_left( src[, title] ) # # picasa_right( src[, title] ) # # options configurable through settings: # @conf['picasa.user'] : picasa username # @conf['picasa.default_size'] : default image size # # Copyright (c) hb # Distributed under the GPL. # def picasa( src, alt = "photo", place = 'photo' ) %Q|#{alt}| end def picasa_left( src, alt = "photo" ) picasa( src, alt, 'left' ) end def picasa_right( src, alt = "photo" ) picasa( src, alt, 'right' ) end tdiary-contrib-5.0.8/plugin/plantuml.rb000066400000000000000000000033411325711763500201500ustar00rootroot00000000000000# -*- coding: utf-8 -*- # create image by PlantUML http://plantuml.com/ # # Copyright (c) tamoot # Distributed under the GPL # require 'uri' require 'zlib' require 'digest/md5' module ::PlantUML module Deflate CHARS ||= ('0'..'9').to_a + ('A'..'Z').to_a + ('a'..'z').to_a + ['-', '_'] def self.compress(text) compressed = Zlib::Deflate.deflate(text, Zlib::BEST_COMPRESSION) compressed.chars.each_slice(3).map do |chars| append3bytes(chars[0].ord, chars[1]&.ord.to_i, chars[2]&.ord.to_i) end.join end private def self.append3bytes(b1, b2, b3) [ b1 >> 2, ((b1 & 0x3) << 4) | (b2 >> 4), ((b2 & 0xF) << 2) | (b3 >> 6), b3 & 0x3F, ].map { |c| CHARS[c & 0x3F] || '?' }.join end end end def plantuml(text) html = %Q|
      | begin uri = URI::parse( @conf['plantuml.server'] ) uri.path.gsub!(/\/+$/, "") uri.path << '/png/' << PlantUML::Deflate::compress(text) html << %Q|| rescue html << %Q|Error: #{$!.message}| end html << %Q|
      | end add_conf_proc('plantuml_server', 'PlantUMLサーバ') do if @mode == 'saveconf' @conf['plantuml.server'] = @cgi.params['plantuml.server'][0] end r = <<-_HTML

      Summary

      The image is generated by using specified PlantUML server.

      URL

      Please specify the PlantUML server URL (official site or your own PlantUML server)

    • Official PlantUML server: http://www.plantuml.com/plantuml/
    • _HTML r end tdiary-contrib-5.0.8/plugin/playstore.rb000066400000000000000000000073131325711763500203410ustar00rootroot00000000000000# -*- coding: utf-8 -*- # playstore.rb # # 概要: # GooglePlay(play.google.com)へのリンクを生成します。 # # 使い方: # playstore'app_id' or playstore_txt'app_id' # # Copyright (c) 2014 kp # Distributed under the GPL # begin require 'market_bot' rescue retry if require 'rubygems' end require 'date' class PlayStore < MarketBot::Play::App def initialize(app_id,option={}) super(app_id,option) end def save(path) File.open(path,"wb"){ |f| Marshal.dump(self.html,f) } end def load(path) File.open(path,"rb"){ |f| begin html = Marshal.restore(f) rescue html = nil end } unless html.nil? result = PlayStore.parse(html) response_handler(html) end return html end def self.valid?(app_id) return app_id.downcase =~ /^([a-z_]{1}[a-z0-9_]*(\.[a-z_]{1}[a-z0-9_]*)*)$/ end end def playstore_load_cache(app) return nil path="#{@cache_path}/playstore/#{app.package}" begin stat = File::Stat.new(path) rescue Errno::ENOENT return nil end m = Date.parse(stat.mtime.to_s) return nil if Date.today - m > 7 # 1week before return app.load(path) end def playstore_save_cache(app) path="#{@cache_path}/playstore/#{app.package}" dir = File.dirname(path) Dir.mkdir(dir) unless File.directory?(dir) app.save(path) end def playstore_main(app_id) unless PlayStore.valid?(app_id) return :invalid end app = PlayStore.new(app_id,lang:'ja') if playstore_load_cache(app).nil? begin app.update rescue return :notfound end save = true else save = false end if app.nil? return :notfound else playstore_save_cache(app) if save return app end end def playstore(app_id) app = playstore_main(app_id) case app when :invalid <<-HTML
      package name is invalid(#{app_id}).
      HTML when :notfound <<-HTML
      #{app_id} was not found.
      HTML else <<-HTML
      HTML end end def playstore_text(app_id) app = playstore_main(app_id) case app when :invalid "package name is invalid(#{app_id})." when :notfound "#{app_id} was not found" else %Q[#{app.title}] end end add_header_proc do if @mode !~ /conf$/ and not bot? then <<-HTML HTML else '' end end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/plugin/plugin_checker.rb000066400000000000000000000027701325711763500213030ustar00rootroot00000000000000# plugin_checker.rb # # Copyright (c) 2012 MATSUOKA Kohei # You can redistribute it and/or modify it under GPL2. # def plugin_checker_js_settings enable_js('plugin_checker.js') add_js_setting('$tDiary.plugins', plugins.to_json) add_js_setting('$tDiary.mode', @mode.to_json) end if /\A(form|edit|preview|showcomment)\z/ === @mode add_header_proc do <<-STYLE STYLE end plugin_checker_js_settings end tdiary-contrib-5.0.8/plugin/popit.rb000066400000000000000000000016601325711763500174510ustar00rootroot00000000000000# popit.rb:plugin embedding POP on POPit(http://pop-it.jp) # # usage: # popit(pop_id) - pop_id: The id of the POP on POPit (e.g. 2000 http://pop-it.jp/item/amazon/1989/pop/2000 ) # # Copyright (c) KAYA Satoshi # You can redistributed it and/or modify if under GPL2. # def popit(pop_id, size = "large") return unless pop_id width_size = {"large" => "260", "small" => "180" } height_size = {"large" => "380", "small" => "220" } width_style = {"large" => "220px", "small" => "160px" } sizequery = size == "large" ? "?size=large" : '' r = "" r << %Q|| r << %Q|
      Powered by POPit
      | return r end tdiary-contrib-5.0.8/plugin/prettify.rb000066400000000000000000000014051325711763500201610ustar00rootroot00000000000000# prettify.rb if /\A(?:latest|day|month|nyear)\z/ =~ @mode then add_header_proc do <<-HTML HTML end end tdiary-contrib-5.0.8/plugin/prezi.rb000066400000000000000000000021551325711763500174470ustar00rootroot00000000000000# # prezi.rb: plugin embedding presentation on prezi.com # # Copyright (C) 2010 TADA Tadashi # You can redistribute it and/or modify it under GPL2. # def prezi( prezi_id, label = 'Link to presentation', size = [512,384] ) %Q|| end tdiary-contrib-5.0.8/plugin/profile.rb000066400000000000000000000121761325711763500177620ustar00rootroot00000000000000# # profile.rb: profile plugin for tDiary # # usage: # profile(id[, service = :gravatar]) # - id: user ID for profile service # - service: profile service (default is :gravatar) # Choose from :github, :gravatar, :hatena # # Copyright (C) 2009 by MATSUOKA Kohei < http://www.machu.jp/ > # Distributed under the GPL. # require 'timeout' require 'rexml/document' require 'open-uri' require 'digest/md5' require 'pstore' module ::Profile module Service # base class for profile services class Base # default attributes attr_reader :id attr_reader :image attr_reader :name attr_reader :mail attr_reader :description attr_reader :link # class instance variables class << self attr_reader :properties attr_reader :endpoint_proc end # set property and xpath pair for parse XML document def self.property(property, path) @properties ||= {} @properties[property] = path end # set endpoint proc (this proc is called by initialize method with id) def self.endpoint(&block) @endpoint_proc = block end def initialize(id, options = {}) @id = id @options = options if self.class.endpoint_proc endpoint = self.class.endpoint_proc.call(id) doc = fetch(endpoint) parse(doc) end end # get a XML document from endpoint and create REXML::Document instance def fetch(endpoint) Timeout.timeout(5) do open(endpoint) do |f| doc = REXML::Document.new(f) end end end # parse XML document with properties def parse(doc) self.class.properties.each do |property, path| if doc.elements[path] value = doc.elements[path].text instance_variable_set("@#{property}", value) end end end end # github.com class GitHub < Base property :name, 'name' property :mail, 'email' property :image, 'avatar_url' endpoint {|id| "https://api.github.com/users/#{id}" } def link "http://github.com/#{@id}" end def fetch(endpoint) require 'json' Timeout.timeout(5) do doc = open(endpoint) {|f| JSON.parse(f.read) } end end def parse(doc) self.class.properties.each do |property, key| instance_variable_set("@#{property}", doc[key]) if doc[key] end end end # twitter.com class Twitter < Base # dummy class end # iddy.jp, for backward compatibility class Iddy < Base # dummy class end # gravatar.com class Gravatar < Base HOST = 'ja.gravatar.com' unless const_defined?(:HOST) endpoint {|id| hash = Digest::MD5.hexdigest(id.downcase) "https://#{HOST}/#{hash}.json" } def image size = @options[:size] ? "?s=#{@options[:size]}" : "" "#{@image_base}#{size}" end def fetch(endpoint) require 'json' Timeout.timeout(5) do begin doc = open(endpoint) {|f| JSON.parse(f.read) } rescue RuntimeError => err if err.message =~ /^redirection forbidden: / endpoint.sub!(/www/, @options[:lang]) retry else raise end end end end def parse(doc) instance_variable_set("@name", doc['entry'][0]['displayName']) instance_variable_set("@mail", @id) instance_variable_set("@image_base", doc['entry'][0]['thumbnailUrl']) instance_variable_set("@link", doc['entry'][0]['profileUrl']) instance_variable_set("@description", doc['entry'][0]['aboutMe']) end end class Hatena < Base def image prefix = id[0..1] "http://www.hatena.ne.jp/users/#{prefix}/#{id}/profile.gif" end def link "http://www.hatena.ne.jp/#{id}/" end end end end PROFILE_VERSION = '20090909' def profile(id, service = :gravatar, options = {}) html = '' service_class = { :github => Profile::Service::GitHub, :gravatar => Profile::Service::Gravatar, :hatena => Profile::Service::Hatena, }[service.to_s.downcase.to_sym] || Profile::Service::Gravatar # TODO: create cache manager class # cache = "#{@cache_path}/profile.yaml" cache = "#{@cache_path}/profile.pstore" profile = nil # db = YAML::Store.new(cache) db = PStore.new(cache) db.transaction do key = service_class.name db[key] ||= {} # initialize db updated = db[key][:updated] if updated && (Time::now < updated + 60 * 60) && db[key][:version] == PROFILE_VERSION # use cache profile = db[key][:profile] else # get latest date and update cache begin profile = service_class.new(id, options.merge(lang: @conf.lang)) rescue Timeout::Error, StandardError return html << %Q{
      no profile
      } end db[key][:updated] = Time::now db[key][:profile] = profile db[key][:version] = PROFILE_VERSION end end html << %Q{
      } end tdiary-contrib-5.0.8/plugin/puboo.rb000066400000000000000000000050561325711763500174450ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2013, TADA Tadashi # Original code from tatsu_zine.rb by KADO Masanori # You can redistribute it and/or modify it under GPL. # # display book info in http://p.booklog.jp/ like amazon.rb # USAGE: {{puboo 9999}} require 'open-uri' def puboo_cache_dir cache = "#{@cache_path}/puboo" Dir.mkdir( cache ) unless File.directory?( cache ) cache end def puboo_cache_set( id, result ) File.open( "#{puboo_cache_dir}/#{id}", "w" ) do |f| f.write result end end def puboo_cache_get( id ) File.open( "#{puboo_cache_dir}/#{id}", "r" ) do |f| f.read end rescue nil end def puboo( id, doc = nil ) if !@conf.secure and !(result = puboo_cache_get(id)).nil? return result end link = "http://p.booklog.jp/book/#{id}" doc ||= open( link ).read.force_encoding('UTF-8') title = doc.match(%r|価格.*?(.*?).*?
      |m).to_a[1] author = doc.match(%r|
      作者
      HTML index = 0; rating_config.each { |axis_config| form_string += < HTML index += 1 } form_string += <
      順: 軸の名前:  最低ラベル:  最高ラベル:  選択肢数:  表示:
      追加 軸の名前: 最低ラベル: 最高ラベル: 選択肢数:
      HTML form_string += '' form_string #evaluate end ######################################### # Entry of the day ######################################### add_body_leave_proc do |date| graph_string = "" form_string = "" contentString = "" #initialize DateEval object todays_eval = DateEval.new(date.strftime('%Y%m%d'), @dbase) #initialize RatingConfig object @rating_config = RatingConfig.new(@dbase) graph_string += <
      [分布をみる]
      HTML form_string += '' + "\n" form_string += ('
      ') @rating_config.each{|axis_config| if !axis_config.display next end # add axis info form_string += ('
      ' + axis_config.label + '') # add radio buttons form_string += ('' + axis_config.label_min + '') # append graph string current_rank = 0 graph_string += '
      ' #begin "graphBox" graph_string += 'average : ' + sprintf("%10.2f", todays_eval.get_average(axis_config.id)) +'
      ' while current_rank < axis_config.range graph_string += ('
      ' + (current_rank + 1).to_s + '
      (' + todays_eval.get_value(axis_config.id, current_rank).to_s + '票)
      ') current_rank += 1 end graph_string += '
      ' #end "graphBox" for current_rank in 0..axis_config.range - 1 form_string += " " + '' + (current_rank + 1).to_s end form_string += ('' + axis_config.label_max + '
      ') form_string += '
      ' } graph_string += <
      HTML form_string += '' form_string += '
      '+"\n" (form_string + graph_string) end ######################################### # class RatingConfig ######################################### class RatingConfig @axes @max_axis_id= 0 @dbase def initialize (dbase) @dbase = dbase db = PStore.new(@dbase) db.transaction do #begin transaction if db.root?("config") @axes = Hash.new obj = db["config"] @max_axis_id = obj[0] obj.each{|ary| id = ary[4] @axes[id] = AxisConfig.new(ary[0],ary[1],ary[2],ary[3],ary[4],ary[5],ary[6]) } else @axes = Hash.new @max_axis_id = 0 end end #end transaction end #end initialize def save_to_db save_array = Array.new db = PStore.new(@dbase) save_array.push(@max_axis_id) each {|axis_config| save_array.push(axis_config.to_array) } db.transaction do #begin transaction db["config"] = save_array end #end transaction end #end save_to_db def add_axis (label, label_max, label_min, range) @max_axis_id += 1 new_axis = AxisConfig.new(label, label_max, label_min, range, @max_axis_id, 0, true) @axes[@max_axis_id] = new_axis end #end add_axis def edit_axis (axis_id, label, label_max, label_min, range, order,display) target_axis = @axes[axis_id] target_axis.edit(label, label_max, label_min, range, order,display) end def length return @axes.size end #end length def each @axes.to_a.sort {|a, b| a[1].order <=> b[1].order}.each {|key ,axis_conf| yield axis_conf } end #end each end ######################################### # class AxisConfig ######################################### class AxisConfig @label @label_max @label_min @range @id @order @display = true #accessors attr_reader :label, :label_max, :label_min, :range, :id, :order, :display def initialize (label, label_max, label_min, range, id,order,display) @label = label @label_max = label_max @label_min = label_min @range = range @id = id @order = order @display = display end #end initialize def edit (label, label_max, label_min, range, order, display) @label = label @label_max = label_max @label_min = label_min @range = range @order = order @display = display end #end initialize def to_array return [@label, @label_max, @label_min, @range, @id, @order,@display] end def disable @hidden = true end #end disable def enable @hidden = false end #end disable def check_label return @display? "checked":"" end #end check_label end ######################################### # class DateEval ######################################### class DateEval @axes #axes[id][rank] @date_string = "" @dbase @average #average[id] @total #total[id] GRAPH_PIXEL_LENGTH = 300 attr_reader :axes, :average, :total # constructor def initialize (date_string, dbase) @dbase = dbase @date_string = date_string db = PStore.new(@dbase) db.transaction do #begin transaction if db.root?(date_string) #read @axes = db[date_string] else #initialize @axes = Hash.new end end #end transaction end #end constructor def get_value(id, rank) if @axes.key?(id) && @axes[id][rank] != nil return @axes[id][rank] else return 0 end end def get_average(id) sum = 0 vote = 0 unless @axes.key?(id) return 0 end for index in 0..@axes[id].length - 1 if @axes.key?(id) && @axes[id][index] != nil vote += @axes[id][index] sum += @axes[id][index] * index end end if @axes[id].length == 0 return 0 else return sum.to_f/vote + 1 end end def vote(id, rank) unless @axes.key?(id) @axes[id] = Array.new end if @axes[id][rank] != nil @axes[id][rank] += 1 else @axes[id][rank] = 1 end end def save_to_db db = PStore.new(@dbase) db.transaction do #begin transaction #save db[@date_string] = @axes end #end transaction end #end save_to_db def get_graph_length (id, rank) unless @axes.key?(id) return 0 end if @axes[id][rank] != nil total = 0 @axes[id].each {|val| unless val == nil total += val end } return (@axes[id][rank] * GRAPH_PIXEL_LENGTH / total).to_i else return 0 end end #end end # class dateEval end ######################################### # Comment (vote) ######################################### if (@mode == 'comment') if @cgi.params["body"][0] != 'rating' return end @dbase = "#{@cache_path}/rating.db" #initialize RatingConfig object rating_config = RatingConfig.new(@dbase) #initialize DateEval object todays_eval = DateEval.new(@cgi.params['date'][0], @dbase) rating_config.each { |axis_config| if @cgi.params["axis" + axis_config.id.to_s][0]!= nil todays_eval.vote(axis_config.id, @cgi.params["axis" + axis_config.id.to_s][0].to_i) end } todays_eval.save_to_db end tdiary-contrib-5.0.8/plugin/recent_estraier.rb000066400000000000000000000025751325711763500215020ustar00rootroot00000000000000# recent_estraier.rb $Revision 1.1 $ # # recent_estraier: Estraier検索語新しい順 # estsearch.cgiが作成する検索キーワードログから # 最新xx件分の検索語を表示します。 # パラメタ: # file: 検索キーワードログファイル名(絶対パス表記) # estraier: estseach.cgiのパス # limit: 表示件数(未指定時:5) # make_link: を生成するか?(未指定時:生成する) # # # Copyright (c) 2005 SHIBATA Hiroshi # Distributed under the GPL2. # require 'nkf' def recent_estraier(file, estraier, limit = 5, make_link = true) begin lines = [] log = open(file) if log.stat.size > 300 * limit then log.seek(-300 * limit,IO::SEEK_END) end log.each_line do |line| lines << line end result = "
        " lines.reverse.each_with_index do |line,idx| break if idx >= limit word = NKF::nkf('-We -m0', line.split(/\t/)[2]) if word.empty? then limit += 1 else if make_link result << %Q|
      1. #{h word}
      2. | else result << %Q|#{h word}| end end end result << %Q[
      ] rescue %Q[

      #$! (#{$!.class})
      cannot read #{file}.

      ] end end tdiary-contrib-5.0.8/plugin/recent_tweet.rb000066400000000000000000000041261325711763500210060ustar00rootroot00000000000000# # recemt_tweet.rb: Twitter status plugin for tDiary # # Copyright (C) 2007 by Nishimoto Masaki # Distributed under GPL. # require 'open-uri' require 'timeout' require 'rexml/document' def recent_tweet( id, count ) begin cache = "#{@cache_path}/recent_tweet.xml" xml = open( cache ) {|f| f.read } if Time::now > File::mtime( cache ) + 10*60 then File::delete( cache ) # clear cache 10 minutes later end rescue Errno::ENOENT begin xml = recent_tweet_call_api( id ) open( cache, 'wb' ) {|f| f.write( xml ) } rescue Timeout::Error, StandardError return %Q|
      recent_tweet: #{$!}
      | end end begin doc = REXML::Document::new( xml ) if doc then html = '
      ' html << '

      ' html << 'What am I doing...' html << '

      ' html << '
        ' i = 0 doc.elements.each( 'statuses/status' ) do |status| created_at = Time.parse( status.elements.to_a( 'created_at' )[0].text ) text = status.elements.to_a( 'text' )[0].text if /^@/.match( text ) == nil and i < count then html << '
      • ' if Time.now > created_at + 60*60*23 then time = created_at.localtime.strftime( '%b %d %H:%M' ) else time = created_at.localtime.strftime( '%H:%M' ) end html << '' << %Q|#{text}| << ' ' html << '(' << %Q|#{time}| << ')' html << '
      • ' i += 1 end end html << '
      ' @conf.to_native( html ) else return '
      recent_tweet: Failed to open file
      ' end rescue REXML::ParseException return '
      recent_tweet: Failed to parse XML
      ' end end def recent_tweet_call_api( id ) request = "http://twitter.com/statuses/user_timeline/#{id}.xml" proxy = @conf['proxy'] proxy = 'http://' + proxy if proxy Timeout.timeout( 10 ) do open( request, :proxy => proxy ) {|f| f.read } end end tdiary-contrib-5.0.8/plugin/retweet.rb000066400000000000000000000052361325711763500200000ustar00rootroot00000000000000# # retweet.rb - show retweet count in each section # This plugin uses a Topsy Retweet Button for Web Sites powered by Topsy.com # # Copyright (C) 2010, MATSUOKA Kohei # You can redistribute it and/or modify it under GPL2. # # # settings for Topsy Retweet Button. # see: http://labs.topsy.com/button/retweet-button/#global_settings # # your Twitter username @topsy_nick = "your_twitter_account" # retweet button color #@topsy_theme = "blue" # retweet button text #@topsy_retweet_text = "retweet" unless defined?(permalink) def permalink( date, index, escape = true ) ymd = date.strftime( "%Y%m%d" ) uri = @conf.index.dup uri.sub!( %r|\A(?!https?://)|i, @conf.base_url ) uri.gsub!( %r|/\.(?=/)|, "" ) # /././ -> / link = uri + anchor( "#{ymd}p%02d" % index ) link.sub!( "#", "%23" ) if escape link end end unless defined?(subtitle) def subtitle( date, index, escape = true ) diary = @diaries[date.strftime( "%Y%m%d" )] return "" unless diary sn = 1 diary.each_section do |section| if sn == index old_apply_plugin = @options["apply_plugin"] @options["apply_plugin"] = true title = apply_plugin( section.subtitle_to_html, true ) @options["apply_plugin"] = old_apply_plugin title.gsub!( /(?=")/, "\\" ) if escape return title end sn += 1 end end end # load Tospy's script and initialize add_header_proc do r = "" r << %Q|\n| return r unless @topsy_theme or @topsy_nick or @topsy_retweet_text r << %Q|\n| end # show retweet button in top of section add_section_enter_proc do |date, index| <<-"EOS"
      EOS end # show retweet button in end of section add_section_leave_proc do |date, index| <<-"EOS"
      Twitter:
      EOS end tdiary-contrib-5.0.8/plugin/rubykaigi.rb000066400000000000000000000113611325711763500203030ustar00rootroot00000000000000# # rubykaigi.rb: make badges of RubyKaigi. # # usage: <%= rubykaigi 'role', 'size' %> # role: attendee (default), speaker, sponsor, staff, committer, individual sponsor, away # size: large(160x160), small(160x90) # # Copyright (C) TADA Tadashi # Distributed under GPL. # def rubykaigi2015( role = 'attendee', size = nil ) r = role.split(/[ _]+/).join('-') s = "-@#{h size}" unless size.nil? || size == "1x" %Q|RubyKaigi 2015 #{h r}| end def rubykaigi2014( role = 'attendee', size = nil ) r = role.split(/[ _]+/).join('-') s = "@#{h size}" unless size.nil? %Q|RubyKaigi 2014 #{h r}| end def rubykaigi2013( role = 'attendee', size = nil ) r = role.split(/[ _]+/).map{|s| s.capitalize}.join s = "@#{h size}" unless size.nil? %Q|RubyKaigi 2013 #{h r}| end def sappororubykaigi2012( role = 'attendee' ) r = role.split(/[ _]+/).map{|s| s.capitalize}.join %Q|SapporoRubyKaigi 2012 #{h r}| end def kansairubykaigi04( role = 'attendee' ) badges = { 'attendee' => "attendee_taiyou", 'speaker' => "speaker_shika", 'staff' => "staff_daibutsu" } %Q|KansaiRubyKaigi04 #{h role.capitalize}| end def rubykaigi2011( role = 'attendee', size = 'large' ) badges = Hash::new( 'attendee' ).update({ 'committer' => 'committer', 'individual sponsor' => 'individualSponsor', 'sponsor' => 'sponsor', 'staff' => 'staff', 'speaker' => 'speaker', 'attendee' => 'attendee', 'away' => 'attendeeAway' }) width, height = size == 'large' ? ['160','160'] : ['160', '90'] %Q|RubyKaigi2010 #{h role.capitalize}| end alias :rubykaigi :rubykaigi2015 #----- OLD EDITIONS -----# def sappororubykaigi03( role = 'attendee' ) %Q|badge_#{h role}.gif| end def rubykaigi2010( role = 'attendee' ) badges = Hash::new( 'attendee' ).update({ 'committer' => 'committer', 'individual sponsor' => 'individual_sponsor', 'sponsor' => 'sponsor', 'staff' => 'staff', 'speaker' => 'speaker', 'attendee' => 'attendee', 'away' => 'away' }) %Q|RubyKaigi2010 #{h role.capitalize}| end def rubykaigi2009( role = 'attendee' ) %Q|
      RubyKaigi2009#{h role.capitalize}
      | end def rubykaigi2008( role = 'attendee' ) img = case role when 'speaker' 1 when 'sponsor' 2 when 'staff' 3 else role = 'attendee' 0 end %Q|
      RubyKaigi2008#{h role.capitalize}
      | end def sappororubykaigi02( role = 'attendee' ) %Q|
      SapporoRubyKaigi02#{h role.capitalize}
      | end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/plugin/search-bing.rb000066400000000000000000000050501325711763500204750ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # search-bing.rb - site search plugin sample using Bing API. # # Copyright (C) 2011, TADA Tadashi # You can redistribute it and/or modify it under GPL. # # Needed these options below: # # @options['search-bing.appid'] : Your Bing AppId # @options['search.result_filter'] : your dialy's URL format of DAY mode into Regexp. # @options['search-bing.base'] : Base URI of your diary (for debugging) # require 'timeout' require 'json' require 'open-uri' def search_title '全文検索 by Bing' end def search_input_form( q ) r = <<-HTML
      検索キーワード:
      HTML end def search_bing_api( q, start = 0 ) appid = @conf['search-bing.appid'] u = 'https://api.datamarket.azure.com/Bing/SearchWeb/v1/Web' u << "?Query=%27#{q}%27&Options=%27EnableHighlighting%27&$top=50&$skip=#{start}&$format=Json" uri = URI( u ) begin open( uri, {:http_basic_authentication => [appid, appid]} ).read rescue SecurityError ### FIX ME: mysterious error at 1st access to the API open( uri, {:http_basic_authentication => [appid, appid]} ).read end ### FIX ME: this code failed on Timeout error, temporary using open-uri above. # px_host, px_port = (@conf['proxy'] || '').split( /:/ ) # px_port = 8080 if px_host and !px_port # res = Net::HTTP::Proxy( px_host, px_port ).start( uri.host, uri.port ) do |http| # req = Net::HTTP::Get.new( uri.request_uri ) # req.basic_auth( appid, appid ) # res = http.request( req ) # end # res.body end def search_to_html( str ) (str || '').gsub( /\uE000/, '' ).gsub( /\uE001/, '' ) end def search_result query = CGI::unescape( @cgi.params['q'][0] ) start = CGI::unescape( @cgi.params['start'][0] || '0' ).to_i begin uri = URI::parse( @conf['search-bing.base'] || @conf.base_url ) q = "#{query} site:#{uri.host}" q << %Q| inurl:"#{uri.path}"| unless uri.path == '/' json = JSON::parse(search_bing_api(u(q.untaint), start)) rescue Net::HTTPError return %Q|

      #$!

      | end r = search_input_form( query ) r << '
      ' json['d']['results'].each do |entry| url = entry['Url'] title = entry['Title'] desc = entry['Description'] r << %Q|
      #{search_to_html title}
      | r << %Q|
      #{search_to_html desc}
      | end r << '
      ' r << '
      ' # no search navi on Bing search because no total result not supported r << '
      ' r end tdiary-contrib-5.0.8/plugin/search-google-custom.rb000066400000000000000000000042741325711763500223510ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # search-google-custom.rb - site search plugin using Goole Custom Search. # # Copyright (C) 2011, hb # You can redistribute it and/or modify it under GPL. # # Needed these options below: # # @options["search-google-custom.id"] : Your Google Custome Search ID # @options["search-google-custom.cof"] : 広告の表示場所(9:右,10:一番上と右,11:一番上と下) # @options["search-google-custom.width"] : 検索結果のフレームの幅 # @options["search-google-custom.height"] : 検索結果のフレームの高さ # @options["search-google-custom.search_label"] : 検索テキストボックス左のラベル # @options["search-google-custom.button_text"] : 検索ボタンに書かれる文字列 # def search_title '全文検索 by Google カスタム検索' end add_footer_proc do %Q|| end def search_input_form(q='') cof = @conf["search-google-custom.cof"] || 9 search_label = @conf["search-google-custom.search_label"] || '検索キーワード:' button_text = @conf["search-google-custom.button_text"] || '検索' r = <<-HTML HTML end def search_result w = @conf["search-google-custom.width"] || 600 h = @conf["search-google-custom.height"] || 1300 r = <<-HTML
      HTML end tdiary-contrib-5.0.8/plugin/search-yahoo-websearch.rb000066400000000000000000000072271325711763500226460ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # search-yahoo-websearch.rb - Yahoo!デベロッパーネットワークのWeb検索APIを利用した検索プラグイン. # # Copyright (C) 2011, hb # You can redistribute it and/or modify it under GPL. # # オプション # # @options['search-yahoo-websearch.appid'] : アプリケーションID(必須) # @options['search-yahoo-websearch.premium'] : アップグレード版利用時はtrueを指定する(任意) # def search_title '全文検索 by Yahoo! ウェブ検索' end def search_input_form( q ) r = <<-HTML
      検索キーワード:
      HTML end def request_url if @conf['search-yahoo-websearch.premium'] 'http://search.yahooapis.jp/PremiumWebSearchService/V1/webSearch' else 'http://search.yahooapis.jp/WebSearchService/V2/webSearch' end end def search_to_html( str ) (str || '').gsub( /(?:]*)?>)+/, '' ).gsub( %r{<(/?)b[ \t\n\r]*>}, '<\\1strong>' ) end def yahoo_websearch_api( q, start = 1 ) url = request_url appid = @conf['search-yahoo-websearch.appid'] uri = URI::parse( @conf.base_url ) url << "?appid=#{appid}&query=#{q}&results=20&start=#{start}&format=html&site=#{uri.host}" proxy = @conf['proxy'] proxy = 'http://' + proxy if proxy proxy_host, proxy_port = nil if proxy proxy_host = proxy_uri.host proxy_port = proxy_uri.port end proxy_class = Net::HTTP::Proxy(proxy_host, proxy_port) query = URI.parse(url) req = Net::HTTP::Get.new(query.request_uri) http = proxy_class.new(query.host, query.port) http.open_timeout = 20 http.read_timeout = 20 res = http.start do http.request(req) end res.body end def yahoo_websearch_attribution <<-EOF Web Services by Yahoo! JAPAN EOF end def search_result query = CGI::unescape( @cgi.params['q'][0] ) start = CGI::unescape( @cgi.params['start'][0] || '1' ).to_i begin uri = URI::parse( @conf.base_url ) xml = yahoo_websearch_api( u( query.untaint ), start ) doc = REXML::Document::new( REXML::Source.new( xml ) ).root err = doc.elements.to_a( '/Error/Message' )[0] if err return %Q|

      ERROR - #{err.text}

      | end rescue OpenURI::HTTPError return %Q|

      #$!

      | end r = '
      ' doc.elements.to_a( 'Result' ).each do |elem| url = elem.elements.to_a( 'Url' )[0].text next unless url =~ @conf['search.result_filter'] title = elem.elements.to_a( 'Title' )[0].text summary = elem.elements.to_a( 'Summary' )[0].text r << %Q|
      #{search_to_html title}
      | r << %Q|
      #{search_to_html summary}
      | end r << '
      ' r << '
      ' pos = doc.elements["/ResultSet"].attributes["firstResultPosition"] unless pos == '1' r << %Q| | end total = doc.elements["/ResultSet"].attributes["totalResultsAvailable"] ret = doc.elements["/ResultSet"].attributes["totalResultsReturned"] if ret.to_i == 20 and pos.to_i + 19 < 1000 r << %Q|| end r << '
      ' r << yahoo_websearch_attribution r end tdiary-contrib-5.0.8/plugin/search-yahoo.rb000066400000000000000000000057541325711763500207100ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # search-yahoo.rb - site search plugin sample using Yahoo! Search BOSS API. # # Copyright (C) 2009, TADA Tadashi # You can redistribute it and/or modify it under GPL. # # Needed these options below: # # @options['search-yahoo.appid'] : Your BOSS APPID # @options['search-yahoo.result_filter'] : your dialy's URL format of DAY mode into Regexp. # require 'timeout' require 'rexml/document' require 'net/http' Net::HTTP.version_1_2 def search_title '全文検索 by Yahoo! Search BOSS' end def search_input_form( q ) r = <<-HTML
      検索キーワード:
      HTML end def search_boss_api( q, start = 0 ) url = 'http://boss.yahooapis.com/ysearch/web/v1/' appid = @conf['search-yahoo.appid'] url << "#{q}?appid=#{appid}&format=xml&count=20&start=#{start}" proxy = @conf['proxy'] proxy = 'http://' + proxy if proxy proxy_host, proxy_port = nil if proxy proxy_host = proxy_uri.host proxy_port = proxy_uri.port end proxy_class = Net::HTTP::Proxy(proxy_host, proxy_port) query = URI.parse(url) req = Net::HTTP::Get.new(query.request_uri) http = proxy_class.new(query.host, query.port) http.open_timeout = 20 http.read_timeout = 20 res = http.start do http.request(req) end res.body end def search_to_html( str ) (str || '').gsub( /(?:]*)?>)+/, '' ).gsub( %r{<(/?)b[ \t\n\r]*>}, '<\\1strong>' ) end def search_result query = CGI::unescape( @cgi.params['q'][0] ) start = CGI::unescape( @cgi.params['start'][0] || '0' ).to_i begin uri = URI::parse( @conf.base_url ) q = "#{query} site:#{uri.host}" q << %Q| inurl:"#{uri.path}"| unless uri.path == '/' xml = search_boss_api( u( q.untaint ), start ) doc = REXML::Document::new( REXML::Source.new( xml ) ).root res = doc.elements.to_a( '/ysearchresponse' )[0] unless res.attribute( 'responsecode' ).value == '200' then return '

      ERROR

      ' end rescue OpenURI::HTTPError return %Q|

      #$!

      | end r = search_input_form( query ) r << '
      ' doc.elements.to_a( '*/result' ).each do |elem| url = elem.elements.to_a( 'url' )[0].text next unless url =~ @conf['search-yahoo.result_filter'] title = elem.elements.to_a( 'title' )[0].text abstract = elem.elements.to_a( 'abstract' )[0].text r << %Q|
      #{search_to_html title}
      | r << %Q|
      #{search_to_html abstract}
      | end r << '
      ' r << '
      ' doc.elements.to_a( '/ysearchresponse/prevpage' ).each do |p| if /start=\d+/ =~ p.text then r << %Q| | end end doc.elements.to_a( '/ysearchresponse/nextpage' ).each do |n| if /start=\d+/ =~ n.text then r << %Q|| end end r << '
      ' r end tdiary-contrib-5.0.8/plugin/section_footer.rb000066400000000000000000000146351325711763500213460ustar00rootroot00000000000000# -*- coding: utf-8 -*- # section_footer.rb # # Copyright (c) 2005 SHIBATA Hiroshi # You can redistribute it and/or modify it under GPL2. # require 'digest/md5' require 'open-uri' require 'timeout' def permalink( date, index, escape = true ) ymd = date.strftime( "%Y%m%d" ) uri = @conf.index.dup uri.sub!( %r|\A(?!https?://)|i, @conf.base_url ) uri.gsub!( %r|/\.(?=/)|, "" ) # /././ -> / link = uri + anchor( "#{ymd}p%02d" % index ) link.sub!( "#", "%23" ) if escape link end add_header_proc do <<-SCRIPT SCRIPT end add_section_enter_proc do |date, index| @category_to_tag_list = {} end alias subtitle_link_original subtitle_link def subtitle_link( date, index, subtitle ) s = '' if subtitle then s = subtitle.sub( /^(\[([^\[]+?)\])+/ ) do $&.scan( /\[(.*?)\]/ ) do |tag| @category_to_tag_list[tag] = false # false when diary end '' end end subtitle_link_original( date, index, s.strip ) end add_section_leave_proc do |date, index| r = '
      ' # カテゴリタグの追加 if @category_to_tag_list and not @category_to_tag_list.empty? then r << "Tags: " @category_to_tag_list.each do |tag, blog| if blog r << %Q|#{tag} | else r << category_anchor( "#{tag}" ).sub( /^\[/, '' ).sub( /\]$/, '' ) << ' ' end end end # 「このエントリの Delicious history (JSON)」 r << add_delicious_json(date, index) # 「このエントリを含む Delicious (画像API)」 # r << add_delicious(date, index) # 「このエントリを含むはてなブックーク」 r << add_hatenabm(date, index) # 「このエントリを含む livedoor クリップ」 r << add_ldclip(date, index) # 「このエントリを含む Buzzurl」 r << add_buzzurl(date, index) # 「このエントリを含む Yahoo!ブックマーク」 r << add_yahoobm(date, index) # Permalinkの追加 r << add_permalink(date, index) r << "
      \n" end def add_permalink(date, index) r = " | " r << %Q|Permalink | return r end def add_hatenabm(date, index) r = " | " r << %Q|#{@section_footer_hatenabm_label} | return r end def add_ldclip(date, index) r = " | " r << %Q|#{@section_footer_ldclip_label} | return r end def add_buzzurl(date, index) r = " | " r << %Q|#{@section_footer_buzzurl_label} | return r end def add_delicious(date, index) url_md5 = Digest::MD5.hexdigest(permalink(date, index, false)) r = " | " r << %Q|#{@section_footer_delicious_label} | return r end def add_delicious_json(date, index) require 'fileutils' begin require 'json' rescue retry if require 'rubygems' end url_md5 = Digest::MD5.hexdigest(permalink(date, index, false)) cache_dir = "#{@cache_path}/delicious/#{date.strftime( "%Y%m" )}/" file_name = "#{cache_dir}/#{url_md5}.json" cache_time = 8 * 60 * 60 # 8 hour update = false count = 0 r = " | " r << %Q|#{@section_footer_delicious_label}| begin FileUtils.mkdir_p( cache_dir ) unless File::directory?( cache_dir ) cached_time = nil cached_time = File::mtime( file_name ) if File::exist?( file_name ) unless cached_time.nil? if Time.now > cached_time + cache_time update = true end end if cached_time.nil? or update begin Timeout.timeout(10) do open( "http://feeds.delicious.com/v2/json/urlinfo/#{url_md5}") do |file| File::open( file_name, 'wb' ) do |f| f.write( file.read ) end end end rescue => e @logger.debug( e ) end end rescue end begin File::open( file_name ) do |f| data = JSON.parse(@conf.to_native( f.read, 'utf-8' )) unless data[0].nil? count = data[0]["total_posts"].to_i end end rescue end if count > 0 r << %Q| #{count} users| else r << %Q|| end return r end def add_yahoobm(date, index) r = " | " r << %Q|#{@section_footer_yahoobm_label}| return r end tdiary-contrib-5.0.8/plugin/section_footer2.rb000066400000000000000000000167631325711763500214340ustar00rootroot00000000000000# section_footer2.rb # # Copyright (c) 2008 SHIBATA Hiroshi # You can redistribute it and/or modify it under GPL2. # require 'digest/md5' require 'timeout' require 'open-uri' require 'yaml' require 'pathname' begin require 'json' rescue LoadError retry if require 'rubygems' end def permalink( date, index, escape = true ) ymd = date.strftime( "%Y%m%d" ) uri = @conf.index.dup uri.sub!( %r|\A(?!https?://)|i, @conf.base_url ) uri.gsub!( %r|/\.(?=/)|, "" ) # /././ -> / link = uri + anchor( "#{ymd}p%02d" % index ) link.sub!( "#", "%23" ) if escape link end unless defined?(subtitle) def subtitle( date, index, escape = true ) diary = @diaries[date.strftime( "%Y%m%d" )] return "" unless diary sn = 1 diary.each_section do |section| if sn == index old_apply_plugin = @options["apply_plugin"] @options["apply_plugin"] = true title = apply_plugin( section.subtitle_to_html, true ) @options["apply_plugin"] = old_apply_plugin title.gsub!( /(?=")/, "\\" ) if escape return title end sn += 1 end '' end end def init_buttons_status @installed_buttons = ['yaml', 'delicious', 'hatena', 'facebook', 'twitter', 'plusone'] if @conf['section_footer2.isDisplay'].nil? @conf['section_footer2.isDisplay'] = '' end end add_header_proc do <<-"EOS" EOS end add_section_enter_proc do |date, index| @category_to_tag_list = {} init_buttons_status '' end alias section_footer2_subtitle_link_original subtitle_link unless defined?( section_footer2_subtitle_link_original ) def subtitle_link( date, index, subtitle ) s = '' @subtitle = subtitle if subtitle then s = subtitle.sub( /^(?:\[[^\[]+?\])+/ ) do $&.scan( /\[(.*?)\]/ ) do |tag| @category_to_tag_list[tag.shift] = false # false when diary end '' end end section_footer2_subtitle_link_original( date, index, s.strip ) end add_section_leave_proc do |date, index| unless feed? or bot? r = '
      ' # add category_tag if @category_to_tag_list and not @category_to_tag_list.empty? then r << "Tags: " @category_to_tag_list.each do |tag, blog| r << category_anchor( "#{tag}" ).sub( /^\[/, '' ).sub( /\]$/, '' ) << ' ' end r << ' | ' end # add button r << add_button_by_service(date, index) # add Permalink r << %Q|Permalink | r << "
      \n" end end def call_delicious_json( url_md5 ) json = nil begin Timeout.timeout(10) do open( "http://feeds.delicious.com/v2/json/urlinfo/#{url_md5}" ) do |f| json = JSON.parse( f.read ) end end rescue => e @logger.debug( e ) end return json end def add_delicious( date, index ) url_md5 = Digest::MD5.hexdigest(permalink(date, index, false)) db_file = "#{@cache_path}/delicious.cache" r = '' r << %Q|#{@section_footer2_delicious_label}| begin cache_time = 8 * 60 * 60 # 12 hour PStore.new(db_file).transaction do |db| entry = db[url_md5] entry = { :count => 0, :update=> Time.at(0) } if entry.nil? if Time.now > entry[:update] + cache_time json = call_delicious_json( url_md5 ) entry[:count] = json[0]["total_posts"].to_i unless json[0].nil? entry[:update] = Time.now db[url_md5] = entry end if entry[:count] > 0 r << %Q| #{entry[:count]} user| r << 's' if entry[:count] > 1 end end rescue => e @logger.debug( e ) end r << '' r << ' | ' return r end def add_hatena( date, index ) %Q! | ! end def add_facebook(date, index) # add Facebook Like! r = '' r << %Q! | ! end def add_twitter(date, index) r = <<-"EOS" | EOS end def add_plusone(date, index) %Q! | ! end def add_yaml(date, index) r = '' yaml_dir = "#{@cache_path}/yaml/" Dir.glob( yaml_dir + "*.yaml" ) do |file| r << parse_sbm_yaml(file, date, index) end return r end def add_button_by_service(date, index) r = '' @installed_buttons.each do |button| if @conf['section_footer2.isDisplay'].include?(button) then method = "add_" + button + "(date, index)" unless method.nil? then r << instance_eval(method) end end end return r end def parse_sbm_yaml(file, date, index) config = YAML.load( Pathname.new( file ).expand_path.read ) r = "" unless config.nil? url = config["url"] unless config['usesubtitle'].nil? sub = (@subtitle || '').sub( /\A(?:\[[^\]]*\])+ */, '' ) sub = apply_plugin( sub, true ).strip regexp = config["usesubtitle"] url.gsub!(regexp, sub) char_space = ' ' end title = config["title"][@conf.lang] r << %Q|| r << %Q|| r << %Q| | unless config["counter"].nil? r << '' r << ' | ' end return r end add_conf_proc('section_footer2', 'Section Footer Button') do if @mode == 'saveconf' then @conf['section_footer2.isDisplay'] = '' @cgi.params['section_footer2.isDisplay'].each do |item| @conf['section_footer2.isDisplay'] << item + '\n' end end r = '

      表示するボタンをチェックしてください(YAMLをチェックすると各自でインストールしたYAMLのボタンをすべて表示します)

      ' r << '

      ' init_buttons_status @installed_buttons.each do |button| if @conf['section_footer2.isDisplay'].include?(button) then item_checked = "checked" else item_checked = '' end r << %Q|#{button}| end r << '

      ' end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/plugin/section_permalink.rb000066400000000000000000000030341325711763500220210ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2011, KADO Masanori # You can redistribute it and/or modify it under GPL. # # section_permalink.rb # - enables section permalink and shows section title def section_mode? @mode == 'day' and @cgi.params['p'][0].to_s != "" end # Change permalink def anchor( s ) if /^([\-\d]+)#?([pct]\d*)?$/ =~ s then if $2 then s1 = $1 s2 = $2 if $2 =~ /^p/ "?date=#{s1}&p=#{s2.gsub(/p/, '')}" else "?date=#{s1}.html##{s2}" end else "?date=#$1" end else "" end end # Change HTML title to section name alias :_orig_title_tag :title_tag def title_tag if section_mode? and diary = @diaries[@date.strftime('%Y%m%d')] sections = diary.instance_variable_get(:@sections) title = "" section = sections[@cgi.params['p'][0].to_i - 1].stripped_subtitle_to_html title << apply_plugin(section, true).chomp title << " - #{h @html_title}" title << "(#{@date.strftime( '%Y-%m-%d' )})" if @date title << "" return title else _orig_title_tag end rescue _orig_title_tag end add_header_proc do if section_mode? and diary = @diaries[@date.strftime('%Y%m%d')] index = @cgi.params['p'][0] <<-EOS EOS end end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/plugin/section_permalink_anchor.rb000066400000000000000000000013261325711763500233550ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2011, KADO Masanori # You can redistribute it and/or modify it under GPL. # # section_permalink_anchor.rb # - enables section permalink with mod_rewrite # - depends on section_permalink.rb # # sample .htaccess: # # RewriteEngine on # RewriteRule ^([0-9\-]+)p?([0-9]*)\.html$ ?date=$1&p=$2 [L] # def anchor( s ) if /^([\-\d]+)#?([pct]\d*)?$/ =~ s then if $2 then s1 = $1 s2 = $2 if $2 =~ /^p/ "#{s1}#{s2}.html" else "#{s1}.html##{s2}" end else "#$1.html" end else "" end end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/plugin/select-style.rb000066400000000000000000000025211325711763500207300ustar00rootroot00000000000000# # select-style.rb: select a style from installed styles # # add a line below, after load_cgi_conf in tdiary.conf: # @style = @options2['style'] if @options2 && @options2['style'] # def saveconf_style if @mode == 'saveconf' then @conf['style'] = @cgi.params['style'][0] end end def enum_styles TDiary::Style.constants(false).grep(/Diary$/).delete_if{|s| s =~ /Base|Categorizable|Uncategorizable/ }.map{|s| s.to_s.sub(/Diary$/, '').downcase }.each{|s| yield s } end add_conf_proc( 'style', 'スタイル', 'update' ) do saveconf_style labels = { 'tdiary' => 'tDiary', 'wiki' => 'Wiki', 'gfm' => 'GFM', 'etdiary' => 'etDiary', 'emptdiary' => 'emptDiary', 'rd' => 'RD', } r = <<-HTML

      スタイルの指定

      スタイル (日記の文法) を指定します。

      スタイルについての詳細はスタイル - tDiary の記法をごらんください。

      HTML end tdiary-contrib-5.0.8/plugin/select_style.rb000066400000000000000000000023131325711763500210110ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # select_style.rb: a plugin for selecting styles # Distributed under the GPL # # [CAUTION] You need to insert a line to tdiary.conf after "load_cgi_conf" # @style = @options2['style'] if @options2['style'] # # styles def saveconf_style if @mode == 'saveconf' then @conf['style'] = @cgi.params['style'][0] end end if @mode =~ /^(conf|saveconf)$/ then @conf_style_list = [] Dir::glob( "#{::TDiary::PATH}/tdiary/{style/,}*_style.rb" ) do |style_file| style = File::basename( style_file ).sub( /_style\.rb$/, '' ) @conf_style_list << style end end add_conf_proc( 'style', 'スタイル' ) do saveconf_style r = <<-HTML

      スタイルの指定

      スタイル (日記の文法) を指定します。

      スタイルについての詳細はスタイル - tDiary の記法をごらんください。

      HTML end tdiary-contrib-5.0.8/plugin/select_theme.rb000066400000000000000000000043321325711763500207560ustar00rootroot00000000000000# Copyright (C) 2005 akira yamada # You can redistribute it and/or modify it under GPL2. THEME_BASE = File.join(::TDiary::PATH, 'theme') CACHE_FILE = File.join(@cache_path, 'theme_list') def get_theme_list if FileTest.exist?(CACHE_FILE) && File.mtime(CACHE_FILE) >= File.mtime(THEME_BASE) File.open(CACHE_FILE, 'r') do |i| i.flock(File::LOCK_EX) return Marshal.load(i.read) end end list = [] Dir.glob(File.join(THEME_BASE, '*')).sort.each do |dir| theme = dir.sub(%r[.*/theme/], '') next unless FileTest::file?("#{dir}/#{theme}.css".untaint) name = theme.split(/_/).collect{|s| s.capitalize}.join(' ') list << [theme, name] end File.open(CACHE_FILE, 'w') do |o| o.flock(File::LOCK_EX) o.puts Marshal.dump(list) end return list end def select_theme_form options = '' get_theme_list.each do |theme, name| options << %Q!\t\n! if theme == DEFAULT_THEME options = %Q!\t\n! + options end end < HTML end def label 'use' end def check_theme(name) return false if name.nil? || name.empty? FileTest.file?(File.join(THEME_BASE, name, name + '.css')) end with_cgiparam = false theme = nil if @cgi.params['select_theme'] && @cgi.params['select_theme'][0] tmp = @cgi.params['select_theme'][0].gsub(/[^-.\w]/, '') tmp.untaint if check_theme(tmp) theme = tmp with_cgiparam = true end end if theme.nil? && @cgi.cookies && @cgi.cookies.include?('tdiary_select_theme') tmp = @cgi.cookies['tdiary_select_theme'][0].gsub(/[^-.\w]/, '') tmp.untaint theme = tmp if check_theme(tmp) end if theme.nil? theme = @conf.theme end cookie_path = File::dirname( @cgi.script_name ) cookie_path += '/' if cookie_path !~ /\/$/ cookie = CGI::Cookie::new( 'name' => 'tdiary_select_theme', 'value' => theme, 'path' => cookie_path, 'expires' => Time::now.gmtime + 90*24*60*60) # 90days add_cookie(cookie) # XXX: OK? DEFAULT_THEME = @conf.theme @conf.theme = theme tdiary-contrib-5.0.8/plugin/show_and_hide.rb000066400000000000000000000032671325711763500211160ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # show_and_hide.rb - Show or hide the elements with a sliding motion using jQuery. # # Copyright (C) 2011, tamoot # You can redistribute it and/or modify it under GPL2. # require 'digest/md5' if /\A(?:latest|day|month|nyear|preview)\z/ =~ @mode enable_js('show_and_hide.js') end def show_and_hide(contents, title = 'Show contents', type = :link, rss_title = '(Hide contents on RSS. See my page...)') data_id = show_and_hide_id(contents) toggle_attr = {:class => 'show_and_hide_toggle', :"data-showandhideid" => data_id} dom_contents = '' if feed? # RSS dom_contents = h(rss_title) elsif type.to_s == 'button' toggle_attr.merge!(:value => title, :type => "button") dom_contents = %Q|| + show_and_hide_contents(contents, data_id) else toggle_attr.merge!(:href => 'javascript:void(0)') dom_contents = %Q|#{h(title)}| + show_and_hide_contents(contents, data_id) end dom_contents end def show_and_hide_id(contents) @@show_and_hide_counter ||= 0 @@show_and_hide_counter += 1 "#{Time::now.strftime("%s")}_#{@@show_and_hide_counter}_#{ Digest::MD5.hexdigest(contents)}" end def show_and_hide_contents(contents, id) %Q|
      #{h(contents)}
      | end def hash2attr(hash) attrs = [] hash.keys.each do |k| attrs << %Q|#{k}="#{hash[k]}"| end attrs.join(" ") end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/plugin/slideshare.rb000066400000000000000000000006051325711763500204370ustar00rootroot00000000000000# # slideshare.rb - insert some services of slideshare.net # # Copyright (C) 2011, Kiwamu Okabe . # You can redistribute it and/or modify it under GPL2. # def slideshare( embed_code ) %Q|| end tdiary-contrib-5.0.8/plugin/slideshow.rb000066400000000000000000000006561325711763500203230ustar00rootroot00000000000000# # slideshow.rb : tDiary plugin for show slides # # Copyright (C) 2016 TADA Tadashi # Distributed under the GPL2 or any later version. # # @options['slideshow.css'] = "URL of CSS" # enable_js('slideshow.js') def slideshow %Q|| end if @conf['slideshow.css'] add_header_proc do %Q[] end end tdiary-contrib-5.0.8/plugin/socialbutton.rb000066400000000000000000000040321325711763500210200ustar00rootroot00000000000000# socialbutton.rb # # Copyright (c) 2011 MATSUOKA Kohei # You can redistribute it and/or modify it under GPL2. # # enable social button names @conf['socialbutton.enables'] ||= 'twitter,hatena,facebook_like' # screen name of the user to attribute the tweet to @conf['socialbutton.twitter.via'] ||= '' def socialbutton_js_settings enable_js('jquery.socialbutton.js') enable_js('socialbutton.js') add_js_setting('$tDiary.plugin.socialbutton') # convert array to json add_js_setting('$tDiary.plugin.socialbutton.enables', %Q|["#{@conf['socialbutton.enables'].split(',').join('", "')}"]|) if @conf['socialbutton.twitter.via'] != '' options = "{ twitter: { via: '#{@conf['socialbutton.twitter.via']}' } }" else options = "{}" end add_js_setting('$tDiary.plugin.socialbutton.options', options) end add_conf_proc('socialbutton', @socialbutton_label_conf) do @conf['socialbutton.enables'] ||= [] if @mode == 'saveconf' @conf['socialbutton.enables'] = @cgi.params['socialbutton.enables'].join(",") @conf['socialbutton.twitter.via'] = @cgi.params['socialbutton.twitter.via'][0] end result = <<-HTML

      #{@socialbutton_label_enables}

        HTML ['twitter', 'hatena', 'evernote', 'facebook_like', 'google_plusone', 'pinterest'].each do |service| checked = @conf['socialbutton.enables'].index(service) ? 'checked' : '' id = "socialbutton.enables.#{service}" result << %Q|
      • | result << %Q|
      • | end result << <<-HTML

      #{@socialbutton_label_twitter_via}

      HTML end if @mode =~ /^(latest|day|month|nyear)$/ socialbutton_footer = Proc.new { %Q|| } if respond_to?(:blogkit?) && blogkit? add_body_leave_proc(socialbutton_footer) else add_section_leave_proc(socialbutton_footer) end # load javascript socialbutton_js_settings() end tdiary-contrib-5.0.8/plugin/squeeze.rb000077500000000000000000000156031325711763500200040ustar00rootroot00000000000000#!/usr/bin/env ruby # squeeze.rb # # Create daily HTML file from tDiary database. # # See URLs below for more details. # http://ponx.s5.xrea.com/hiki/squeeze.rb.html (English) # http://ponx.s5.xrea.com/hiki/ja/squeeze.rb.html (Japanese) # # Copyright (C) 2002 MUTOH Masao # You can redistribute it and/or modify it under GPL2 or any later version. # # The original version of this file was distributed with squeeze # TADA Tadashi with GPL2 or any later version. # unless $tdiary_squeeze_loaded $tdiary_squeeze_loaded ||= true mode = defined?(TDiary) ? "PLUGIN" : ENV["REQUEST_METHOD"]? "CGI" : "CMD" if mode == "CMD" || mode == "CGI" output_path = "./html/" tdiary_path = "." tdiary_conf = "." suffix = '' all_data = false overwrite = false compat = false $stdout.sync = true if mode == "CMD" def usage puts "squeeze $Revision: 1.25 $" puts " making html files from tDiary's database." puts " usage: ruby squeeze.rb [-p ] [-c ] [-a] [-s] [-x suffix] " exit end require 'getoptlong' parser = GetoptLong::new parser.set_options(['--path', '-p', GetoptLong::REQUIRED_ARGUMENT], ['--conf', '-c', GetoptLong::REQUIRED_ARGUMENT], ['--suffix', '-x', GetoptLong::REQUIRED_ARGUMENT], ['--all', '-a', GetoptLong::NO_ARGUMENT], ['--overwrite', '-o', GetoptLong::NO_ARGUMENT], ['--squeeze', '-s', GetoptLong::NO_ARGUMENT]) begin parser.each do |opt, arg| case opt when '--path' tdiary_path = arg.dup.untaint when '--conf' tdiary_conf = arg when '--suffix' suffix = arg when '--all' all_data = true when '--overwrite' overwrite = true when '--squeeze' compat = true end end rescue usage exit( 1 ) end output_path = ARGV.shift usage unless output_path output_path = File::expand_path(output_path) output_path += '/' if /\/$/ !~ output_path tdiary_conf = tdiary_path unless tdiary_conf Dir::chdir( tdiary_conf ) ARGV << '' # dummy argument against cgi.rb offline mode. $:.unshift tdiary_path else @options = Hash.new File::readlines("tdiary.conf").each {|item| if item =~ /@options/ begin eval(item) rescue SyntaxError end end } output_path = @options['squeeze.output_path'] || @options['yasqueeze.output_path'] suffix = @options['squeeze.suffix'] || '' all_data = @options['squeeze.all_data'] || @options['yasqueeze.all_data'] overwrite = @options['squeeze.overwrite'] compat = @options['squeeze.compat_path'] || @options['yasqueeze.compat_path'] if FileTest::symlink?( __FILE__ ) then org_path = File::dirname( File::readlink( __FILE__ ) ) else org_path = File::dirname( __FILE__ ) end $:.unshift( org_path.untaint ) end begin require "tdiary" rescue LoadError $stderr.print "squeeze.rb: cannot load tdiary.rb. <#{tdiary_path}/tdiary>\n" exit( 1 ) end end # # Dairy Squeeze # module ::TDiary class YATDiarySqueeze < TDiaryBase def initialize(diary, dest, all_data, overwrite, compat, conf, suffix) @ignore_parser_cache = true cgi = CGI::new def cgi.referer; nil; end def cgi.user_agent; 'bot'; end super( cgi, 'day.rhtml', conf ) @diary = diary @date = diary.date @diaries = {@date.strftime('%Y%m%d') => @diary} if @diaries.size == 0 @dest = dest @all_data = all_data @overwrite = overwrite @compat = compat @suffix = suffix end def execute if @compat dir = @dest name = @diary.date.strftime('%Y%m%d') else dir = @dest + "/" + @diary.date.strftime('%Y') name = @diary.date.strftime('%m%d') Dir.mkdir(dir, 0755) unless File.directory?(dir) end filename = dir + "/" + name + @suffix if FileTest.exist?( filename ) and @overwrite File::delete( filename ) end if @diary.visible? or @all_data if not FileTest::exist?(filename) or File::mtime(filename) != @diary.last_modified File::open(filename, 'w'){|f| f.write(eval_rhtml)} File::utime(@diary.last_modified, @diary.last_modified, filename) end else if FileTest.exist?(filename) and ! @all_data name = "remove #{name}" File::delete(filename) else name = "" end end name end protected def mode 'day' end def cookie_name; ''; end def cookie_mail; ''; end end end # # Main # module ::TDiary class YATDiarySqueezeMain < TDiaryBase def initialize(dest, all_data, overwrite, compat, conf, suffix) @ignore_parser_cache = true cgi = CGI::new def cgi.referer; nil; end super( cgi, 'day.rhtml', conf ) calendar @years.keys.sort.each do |year| print "(#{year.to_s}/) " @years[year.to_s].sort.each do |month| diaries2 = nil @io.transaction(Time::local(year.to_i, month.to_i)) do |diaries| diaries2 = diaries DIRTY_NONE end diaries2.sort.each do |day, diary| print YATDiarySqueeze.new(diary, dest, all_data, overwrite, compat, conf, suffix).execute + " " end end end end end end squeeze_navi_on_footer = '
      <%= navi_user %>
      ' if mode == "CGI" || mode == "CMD" if mode == "CGI" print %Q[Content-type:text/html\n\n Squeeze for tDiary

      Squeeze for tDiary

      $Revision: 1.25 $

      Copyright (C) 2002 MUTOH Masao<mutoh@highway.ne.jp>



      Start!


      ] end begin require 'cgi' cgi = CGI.new def cgi.user_agent; 'bot'; end conf = TDiary::Config::new(cgi) conf.header = '' conf.footer = squeeze_navi_on_footer conf.show_comment = true conf.hide_comment_form = true output_path = "#{conf.data_path}/cache/html" unless output_path Dir.mkdir(output_path, 0755) unless File.directory?(output_path) ::TDiary::YATDiarySqueezeMain.new(output_path, all_data, overwrite, compat, conf, suffix) rescue print $!, "\n" $@.each do |v| print v, "\n" end exit( 1 ) end if mode == "CGI" print "

      End!

      \n" else print "\n\n" end else add_update_proc do conf = @conf.clone conf.header = '' conf.footer = squeeze_navi_on_footer conf.show_comment = true conf.hide_comment_form = true diary = @diaries[@date.strftime('%Y%m%d')] dir = @options['squeeze.output_path'] || @options['yasqueeze.output_path'] dir = @cache_path + "/html" unless dir Dir.mkdir(dir, 0755) unless File.directory?(dir) ::TDiary::YATDiarySqueeze.new(diary, dir, @options['squeeze.all_data'] || @options['yasqueeze.all_data'], @options['squeeze.overwrite'], @options['squeeze.compat_path'] || @options['yasqueeze.compat_path'], conf, @options['squeeze.suffix'] || '' ).execute end end end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: tdiary-contrib-5.0.8/plugin/steam.rb000066400000000000000000000011041325711763500174200ustar00rootroot00000000000000# -*- coding: utf-8 -*- # steam.rb $Revision: 1.0 $ # # 概要: # steam(store.steampowered.com)のゲームのウィジェットを # 貼るプラグインです。 # # 使い方: # steamの任意のゲームのID(store.steampowered.com/app/{id}) # を指定することにより、ウィジェットが貼り付けられます。 # # Copyright (c) 2016 kp # Distributed under the GPL # =begin ChangeLog =end def steam( id ) %Q[] end tdiary-contrib-5.0.8/plugin/tatsu_zine.rb000066400000000000000000000050101325711763500204740ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2011, KADO Masanori # You can redistribute it and/or modify it under GPL. # # display book info in http://tatsu-zine.com/ like amazon.rb # USAGE: {{tatsu_zine 1}} require 'open-uri' def tatsu_zine_cache_dir cache = "#{@cache_path}/tatsu-zine" Dir.mkdir( cache ) unless File.directory?( cache ) cache end def tatsu_zine_cache_set( id, result ) File.open( "#{tatsu_zine_cache_dir}/#{id}", "w" ) do |f| f.write result end end def tatsu_zine_cache_get( id ) File.open( "#{tatsu_zine_cache_dir}/#{id}", "r" ) do |f| f.read end rescue nil end def tatsu_zine( id, doc = nil ) if !@conf.secure and !(result = tatsu_zine_cache_get(id)).nil? return result end link = "https://tatsu-zine.com/books/#{id}" doc ||= open(link, ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE).read title = doc.match(%r||).to_a[1] image = doc.match(%r||).to_a[1] price = doc.match(%r|span itemprop="price">(.*)|).to_a[1] author = doc.match(%r||).to_a[1] result = <<-EOS #{h title} #{h title}
      #{h author}
      #{h price}

      EOS tatsu_zine_cache_set( id, result ) unless @conf.secure result rescue => e @logger.error(e) link end if __FILE__ == $0 require 'test/unit' class TestTatsuZine < Test::Unit::TestCase def setup @conf = Struct.new("Conf", :secure).new(true) def h(str); str; end end def test_tatsu_zine expect = <<-EOS Ruby環境構築講座 Windows編 Ruby環境構築講座 Windows編
      arton
      1036

      EOS assert_equal expect, tatsu_zine('winrubybuild') end end end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: tdiary-contrib-5.0.8/plugin/tdiarytimes2.rb000066400000000000000000000265161325711763500207450ustar00rootroot00000000000000# tdiarytimes.rb $originalRevision: 1.1 $ # # Copyright (c) 2003 neuichi # Distributed under the GPL # # 2003-12-01 circle extention added by Minero Aoki # $Id: tdiarytimes2.rb,v 1.2 2007/01/11 02:55:26 tadatadashi Exp $ # # プラグイン配布ページ # http://i.loveruby.net/w/tdiarytimes.html # # 動作条件: # ruby-gdが使える環境が必要です。 # # 使い方: # このプラグインをプラグインディレクトリに入れ、 # index.rbと同じディレクトリに、tdiarytimes.pngという名前の # サーバが書き込み権限を持っているファイルを作ります。 # これで日記に書き込みするごとに、tdiarytimes.pngに # 画像を書き込みます。 # # 日記上からこのpngファイルを呼び出すには、 # tDiray上からプラグインとして # <%=tdiarytimes%> # として呼び出します。 # 引数としてimgタグのaltの文字列を指定することも出来ます。 # <%=tdiarytimes '文字列'%> # # また、tdiary.confに以下のオプションを書き込むことにより、 # カスタマイズをすることが出来ます。 # # @options['tdiarytimes.width'] = 400 # 四角の横幅。デフォルト値400。 # 実際に出力される画像サイズは、これに+10したサイズ。 # # @options['tdiarytimes.height'] = 20 # 四角の縦幅。デフォルト値20。 # 実際に出力される画像サイズは、これに+16したサイズ。 # # @options['tdiarytimes.file'] = 'tdiarytimes.png' # 出力する画像ファイル名。デフォルトは'tdiarytimes.png' # # @options['tdiarytimes.fillcolor'] = '#444444' # 四角の色。デフォルトは'#444444' # # @options['tdiarytimes.linecolor'] = '#ffffff' # 縦棒の色。デフォルトは'#ffffff' # # @options['tdiarytimes.textcolor'] = '#444444' # 文字色。デフォルトは'#444444' # # @options['tdiarytimes.fadeout'] = false # フェードアウトするか。デフォルトはfalse。 # フェードアウトしたいときには true にすればよい。 # # @options['tdiarytimes.fadeoutcolor'] = '#ffffff' # フェードアウトするとき、 # デフォルトではfillcolorへとフェードアウトしていく。 # ここで色を指定するとその色へとフェードアウトしていく。 # デフォルトは false # # @options['tdiarytimes.text'] = 'T D I A R Y T I M E S' # 出力する文字。デフォルトは'T D I A R Y T I M E S'。なお半角英数字のみ対応。 # # @options['tdiarytimes.day'] = 30 # ログを保存する最大日数。デフォルトは30。 # この場合、30日以上経ったデータは消去され、縦棒として描画されなくなる。 # require 'GD' ::GD::Image.module_eval { def tiny_string(text, x, y, color) string(GD::Font::TinyFont, x, y, text, color) end def small_string(text, x, y, color) string(GD::Font::SmallFont, x, y, text, color) end } # Ruby 1.6 missing File.read unless ::File.respond_to?(:read) def (::File).read(fname) File.open(fname) {|f| return f.read } end end # Ruby 1.6 missing MatchData#captures unless ::MatchData.method_defined?(:captures) ::MatchData.module_eval { def captures a = to_a() a.shift a end } end class TDiaryTimes class << TDiaryTimes alias newobj new end def TDiaryTimes.new(datadir, options) case options['tdiarytimes.shape'] when 'bar', nil c = TDiaryTimesBar when 'circle' c = TDiaryTimesCircle else raise ArgumentError, "unknown tdiarytimes.shape: #{options['tdiarytimes.shape']}" end c.newobj("#{datadir}/tdiarytimes", options) end def initialize(dbfile, options) @dbfile = dbfile @image_file = options['tdiarytimes.file'] || 'tdiarytimes.png' @day = options['tdiarytimes.day'] || 30 @keepdb = options['tdiarytimes.keepdb'] end attr_reader :image_file def update_image now = Time.now mtimes = (load_database() + [now]).reject {|tm| (now - tm) > (60 * 60 * 24 * @day) } image = create_image(mtimes) File.open(@image_file, 'w') {|png| image.png(png) } save_database(mtimes) unless @keepdb end private # # database # def load_database begin return Marshal.load(File.read(@dbfile)) rescue Errno::ENOENT return [] end end def save_database(content) File.open(@dbfile, 'w') {|f| Marshal.dump(content, f) } end # # common paint methods # def fadeout_color(srccolor, destcolor, time) par = (Time.now - time).to_f / (60 * 60 * 24 * @day) r, g, b = *zip(parse_rgb(srccolor), parse_rgb(destcolor))\ .map {|src, dest| src - (src - dest) * par }.map {|c| c.to_i } sprintf('#%02x%02x%02x', r, g, b) end def parse_rgb(str) hex = '[\da-f]' m = /\A\#(#{hex}{2})(#{hex}{2})(#{hex}{2})\z/io.match(str) or raise ArgumentError, "tdiarytimes: not color: #{str.inspect}" m.captures.map {|c| c.hex } end def zip(*lists) result = [] lists[0].each_index do |idx| result.push lists.map {|lst| lst[idx] } end result end end class TDiaryTimesBar < TDiaryTimes def initialize(dbfile, options) super @text = options['tdiarytimes.text'] || 'T D I A R Y T I M E S' @width = options['tdiarytimes.width'].to_i || 400 @height = options['tdiarytimes.height'].to_i || 20 @textcolor = options['tdiarytimes.textcolor'] || '#444444' @fillcolor = options['tdiarytimes.fillcolor'] || '#444444' @linecolor = options['tdiarytimes.linecolor'] || '#ffffff' @fadeoutcolor = options['tdiarytimes.fadeoutcolor'] || @fillcolor @fadeoutp = options['tdiarytimes.fadeout'] end def html(alt) %Q[#{h( alt || @text )}].gsub(/\s+/, ' ') end private GAP_W = 16 GAP_H = 16 def create_image(mtimes) image = GD::Image.new(@width + GAP_W, @height + GAP_H) image.transparent(image.colorAllocate('#fffffe')) image.interlace = true image.tiny_string @text, (GAP_W / 2), 0, image.colorAllocate(@textcolor) image.filledRectangle 0 + GAP_W / 2, 0 + GAP_H / 2, image.width - GAP_W / 2, image.height - GAP_H / 2, image.colorAllocate(@fillcolor) if @fadeoutp paint_lines_fadeout image, mtimes, @linecolor, @fadeoutcolor else paint_lines image, mtimes, @linecolor end paint_hours image, image.colorAllocate(@textcolor), (image.width - GAP_W > 160 ? 2 : 4) image end def paint_lines(image, mtimes, color) gdcolor = image.colorAllocate(color) mtimes.each do |time| line image, time, gdcolor end end def paint_lines_fadeout(image, mtimes, linecolor, destcolor) mtimes.each do |time| line image, time, image.colorAllocate(fadeout_color(linecolor, destcolor, time)) end end def line(image, time, color) x0 = (image.width - GAP_W).to_f * (time.hour * 60 + time.min) / (60 * 24) x = (x0 + (GAP_W / 1.25)).to_i image.line x, 0 + (GAP_H / 2), x, image.height - (GAP_H / 2), color end def paint_hours(image, color, stepping) 0.step(24, stepping) do |hour| image.tiny_string hour.to_s, (image.width - GAP_W) * (hour.to_f / 24) + (GAP_W / 2) - 4, image.height - (GAP_H / 2), color end end end class TDiaryTimesCircle < TDiaryTimes def initialize(dbfile, options) super #@text # cannot change now @width = options['tdiarytimes.width'].to_i || 80 @height = options['tdiarytimes.height'].to_i || 80 @textcolor = options['tdiarytimes.textcolor'] || '#444444' @fillcolor = options['tdiarytimes.fillcolor'] || '#444444' @linecolor = options['tdiarytimes.linecolor'] || '#ffffff' @fadeoutcolor = options['tdiarytimes.fadeoutcolor'] || @fillcolor @fadeoutp = options['tdiarytimes.fadeout'] end def html(alt) %Q[#{h( alt || '' )}].gsub(/\s+/, ' ') end private MIN_DEGREE = 0 MAX_DEGREE = 250 BAR_WIDTH = 24 TRANSCOLOR = '#ffffff' def create_image(mtimes) image = GD::Image.new(@width, @height) trans = image.colorAllocate(TRANSCOLOR) image.transparent trans image.interlace = true paint_outer_circle image, trans if @fadeoutp paint_lines_fadeout image, mtimes, @linecolor, @fadeoutcolor else paint_lines image, mtimes, @linecolor end paint_inner_circle image, trans textcolor = image.colorAllocate(@textcolor) image.small_string 'tdiary', @width / 2 + 1, 11, textcolor image.small_string 'times', @width / 2 + 4, 21, textcolor image end def paint_outer_circle(image, trans) image.filledArc @width / 2, @height / 2, @width, @height, MIN_DEGREE, MAX_DEGREE, if @fillcolor == TRANSCOLOR then trans else image.colorAllocate(@fillcolor) end, 0 end def paint_inner_circle(image, trans) image.filledArc @width / 2, @height / 2, @width - BAR_WIDTH * 2, (@width - BAR_WIDTH * 2) * (@height.to_f / @width), 0, 360, trans, 0 end def paint_lines(image, mtimes, color) gdcolor = image.colorAllocate(color) mtimes.each do |time| line image, time, gdcolor end end def paint_lines_fadeout(image, mtimes, linecolor, destcolor) mtimes.each do |time| line image, time, image.colorAllocate(fadeout_color(linecolor, destcolor, time)) end end def line(image, time, color) d0 = (time.hour * 60 + time.min).to_f / (60 * 24) d = MIN_DEGREE + (MAX_DEGREE - MIN_DEGREE) * d0 image.line @width / 2, @height / 2, @width / 2 + degcos(d) * (@width / 2) * 0.95, @height / 2 + degsin(d) * (@height / 2) * 0.95, color end include Math def degsin(d) sin(d / (180 / Math::PI)) end def degcos(d) cos(d / (180 / Math::PI)) end end def tdiarytimes(alt = nil) TDiaryTimes.new(@conf.data_path, @options).html(alt) end if $0 == __FILE__ # debugging tmp_options_bar = { 'tdiarytimes.shape' => 'bar', 'tdiarytimes.textcolor' => '#666666', 'tdiarytimes.linecolor' => '#df0000', 'tdiarytimes.fillcolor' => '#0f5f0f', 'tdiarytimes.fadeout' => true, 'tdiarytimes.keepdb' => false # for debug } tmp_options_circle = { 'tdiarytimes.shape' => 'circle', 'tdiarytimes.textcolor' => '#000000', 'tdiarytimes.linecolor' => '#bfbfbf', 'tdiarytimes.fillcolor' => '#2f2f7f', 'tdiarytimes.fadeout' => true, 'tdiarytimes.keepdb' => false # for debug } @mode = 'latest' @conf = Object.new def @conf.data_path '.' end case ARGV[0] when 'bar' @options = tmp_options_bar else @options = tmp_options_circle end TDiaryTimes.new(@conf.data_path, @options).update_image puts tdiarytimes() exit 0 end if /append|replace/ =~ @mode TDiaryTimes.new(@conf.data_path, @options).update_image end tdiary-contrib-5.0.8/plugin/tdiarytimes_flashstyle.rb000066400000000000000000000355361325711763500231230ustar00rootroot00000000000000# tdiarytimes_flashstyle.rb $Revision: 1.2 $ # # Copyright (c) 2004 phonondrive # Distributed under the GPL # # プラグイン配布ページ: # http://phonondrive.com/trd/ # -------------------------------------------------------------------- # # # # Abstract: # -------------------------------------------------------------------- # 日記を登録した時間帯をタイムライン上に記録します。記録されたエントリは # 日時の経過と共にフェードアウトしていきます。このような MTBlogTimes や # tdiarytimes.rb と同等の機能を Flash で実現します。 # ruby-gd のインストール作業も必要ないため、すぐに使用出来ます。 # # # Usage: # -------------------------------------------------------------------- # プラグインは、プラグインフォルダに入れて下さい。 # # プラグインは、プラグインフォルダに入れてください。 # tdiarytimes*.swf を tdiary.rb と同じフォルダにアップロードします。 # ヘッダ、フッタ部に記述した <%= tdiarytimes_flashstyle %> の部分に、 # Flash アプレットが表示されます。 # tdiarytimes.log は日記登録時に .swf と同じフォルダに作成されます。 # # ※ tdiarytimes_textstyle.rb との互換性はありません。 # # # Options: # -------------------------------------------------------------------- # タイムラインの色、透明度、サイズなどは、プリファレンス画面で設定できます。 # # # In secure mode: # -------------------------------------------------------------------- # たぶん動作しません。 # # =begin ChangeLog 2004.05.02 phonondrive * version 1.1.2 タイムラインが曜日別の Flash を追加 2004.05.02 phonondrive * version 1.1.1 タイムラインが円形で、時刻盤が曜日表示の Flash を追加 ログファイルが存在しない時にエラーが出る不具合を修正 2004.04.28 phonondrive * version 1.1.0 タイムラインが円形の Flash を追加 2004.04.27 phonondrive * version 1.0.1 時刻目盛テキストの色が変更されない不具合を修正 2004.04.25 phonondrive * version 1.0.0 =end # -------------------------------------------------------------------- # プラグインの動作 # -------------------------------------------------------------------- def tdiarytimes_flashstyle if @conf['tdiarytimes_f.templete'] == nil or @conf['tdiarytimes_f.templete'] == "" %Q|使用を開始するには、プリファレンス画面にて一度設定を完了して下さい。(tdiarytimes-flashstyle)| else logname = ((@conf['tdiarytimes_f.log_path'] != "" and @conf['tdiarytimes_f.log_path'] != nil) ? @conf['tdiarytimes_f.log_path'] : "tdiarytimes.log") @conf['tdiarygraph_f.templete'].sub(/&uid/, "\\&=#{File.mtime(logname.untaint).to_i}") end end # -------------------------------------------------------------------- # 日記登録時の処理 # -------------------------------------------------------------------- if /\A(?:append|replace)\z/ =~ @mode and @cgi.params['hide'][0] != 'true' then logname = ((@conf['tdiarytimes_f.log_path'] != "" and @conf['tdiarytimes_f.log_path'] != nil) ? @conf['tdiarytimes_f.log_path'] : "tdiarytimes.log") entr_lifetime = ((@conf['tdiarytimes_f.entr_lifetime'] != "" and @conf['tdiarytimes_f.entr_lifetime'] != nil) ? @conf['tdiarytimes_f.entr_lifetime'].to_i * 60 * 60 * 24 : 30 * 24 * 60 * 60) entr_interval = ((@conf['tdiarytimes_f.entr_interval'] != "" and @conf['tdiarytimes_f.entr_interval'] != nil) ? @conf['tdiarytimes_f.entr_interval'] : 2 * 60 * 60) begin logs = open(logname){|io| io.read }.chomp.split(',') rescue logs = "" end if (Time.now.to_i - logs.max.to_i) > entr_interval.to_i logs << "#{Time.now.to_i}" open(logname, "w"){|io| io.write(logs.find_all{|item| (Time.now.to_i - item.to_i) < entr_lifetime.to_i }.join(',')) } end end # -------------------------------------------------------------------- # プリファレンス画面での設定 # -------------------------------------------------------------------- add_conf_proc( 'tdiarytimes_f', 'tdiarytimes-flashstyle の設定' ) do if @mode == 'saveconf' then filename = "tdiarytimes234x30.swf" width = "234" height = "30" argvs = "" argv = Array.new @conf['tdiarytimes_f.uid'] = @cgi.params['uid'][0] argv << "#{Time.now.to_i}&uid" if @conf['tdiarytimes_f.uid'] == "1" @conf['tdiarytimes_f.type'] = @cgi.params['type'][0] @conf['tdiarytimes_f.filename'] = @cgi.params['filename'][0] @conf['tdiarytimes_f.width'] = @cgi.params['width'][0] @conf['tdiarytimes_f.height'] = @cgi.params['height'][0] @conf['tdiarytimes_f.log_path'] = @cgi.params['log_path'][0] argv << "log_path=#{@cgi.params['log_path'][0]}" if @cgi.params['log_path'][0] != "" @conf['tdiarytimes_f.text_visible'] = @cgi.params['text_visible'][0] argv << "text_visible=#{@cgi.params['text_visible'][0]}" if @cgi.params['text_visible'][0] == "0" @conf['tdiarytimes_f.text_text'] = @cgi.params['text_text'][0] argv << "text_text=#{CGI::escape @cgi.params['text_text'][0].upcase}" if @cgi.params['text_text'][0] != "" @conf['tdiarytimes_f.text_rgb'] = @cgi.params['text_rgb'][0] argv << "text_rgb=0x#{@cgi.params['text_rgb'][0]}" if @cgi.params['text_rgb'][0] != "" @conf['tdiarytimes_f.face_visible'] = @cgi.params['face_visible'][0] argv << "face_visible=#{@cgi.params['face_visible'][0]}" if @cgi.params['face_visible'][0] == "0" @conf['tdiarytimes_f.face_rgb'] = @cgi.params['face_rgb'][0] argv << "face_rgb=0x#{@cgi.params['face_rgb'][0]}" if @cgi.params['face_rgb'][0] != "" @conf['tdiarytimes_f.stage_rgb'] = @cgi.params['stage_rgb'][0] argv << "stage_rgb=0x#{@cgi.params['stage_rgb'][0]}" if @cgi.params['stage_rgb'][0] != "" @conf['tdiarytimes_f.stage_alpha'] = @cgi.params['stage_alpha'][0] argv << "stage_alpha=#{@cgi.params['stage_alpha'][0]}" if @cgi.params['stage_alpha'][0] != "" @conf['tdiarytimes_f.bg_rgb'] = @cgi.params['bg_rgb'][0] argv << "bg_rgb=0x#{@cgi.params['bg_rgb'][0]}" if @cgi.params['bg_rgb'][0] != "" @conf['tdiarytimes_f.bg_alpha'] = @cgi.params['bg_alpha'][0] argv << "bg_alpha=#{@cgi.params['bg_alpha'][0]}" if @cgi.params['bg_alpha'][0] != "" @conf['tdiarytimes_f.bar_rgb'] = @cgi.params['bar_rgb'][0] argv << "bar_rgb=0x#{@cgi.params['bar_rgb'][0]}" if @cgi.params['bar_rgb'][0] != "" @conf['tdiarytimes_f.bar_width'] = @cgi.params['bar_width'][0] argv << "bar_width=#{@cgi.params['bar_width'][0]}" if @cgi.params['bar_width'][0] != "" @conf['tdiarytimes_f.entr_interval'] = @cgi.params['entr_interval'][0] @conf['tdiarytimes_f.entr_lifetime'] = @cgi.params['entr_lifetime'][0] @conf['tdiarytimes_f.fade_time'] = @cgi.params['fade_time'][0] argv << "fade_time=#{@cgi.params['fade_time'][0]}" if @cgi.params['fade_time'][0] != "" @conf['tdiarytimes_f.preview'] = @cgi.params['preview'][0] if @cgi.params['type'][0] == "0" filename = @cgi.params['filename'][0] width = @cgi.params['width'][0] height = @cgi.params['height'][0] elsif @cgi.params['type'][0] filename = "tdiarytimes#{@cgi.params['type'][0].delete('-')}.swf" width = @cgi.params['type'][0].split('-').first.split('x')[0] height = @cgi.params['type'][0].split('-').first.split('x')[1] end if argv.size > 0 then argvs = "?#{argv.join('&')}" end @conf['tdiarytimes_f.templete'] = tdiarytimes_flashstyle_templete(filename, argvs, width, height) end <<-HTML

      設定の概要

      () 内は初期値です。初期値を使用する場合は、空欄のままで構いません。色は RRGGBB 形式で指定して下さい。不透明度は 0 (透明) 〜 100 (不透明) です。線幅はピクセルで指定します。


      プレビュー

      #{tdiarytimes_flashstyle_preview}

      表示する Flash アプレットの選択

      プリセットを使用しない場合は、以下で指定して下さい。

      Flash のファイル名

      Flash の表示幅

      Flash の表示高さ


      タイトルテキスト

      タイトルテキストの表示有無 (表示)

      タイトルテキスト (TDIARYTIMES-FLASHSTYLE)
      使用出来る文字は、英大文字 (A-Z) と数字 (0-9)、および記号のみです。

      タイトルテキストの色 (333333)

      時刻目盛テキスト

      時刻目盛テキストの表示有無 (表示)

      時刻目盛テキストの色 (333333)


      背景や棒グラフの色

      背景の色 (FFFFFF)

      背景の不透明度 (0)

      タイムラインの背景の色 (333333)

      タイムラインの背景の不透明度 (100)

      タイムラインに記録される棒グラフの色 (EEEEEE)

      タイムラインに記録される棒グラフの線幅 (1)

      タイムラインに記録される棒グラフの寿命日数 (30)


      ログ管理

      前回の日記登録から設定時間内はエントリを新規登録しない (2)

      設定日数後にログファイルからエントリを削除する (30)

      本プラグインが作成するログファイル名 (tdiarytimes.log)


      ユニークID を使用したファイル取得

      ファイル取得のリクエストにユニークID (例えば ?#{Time.now.to_i}) を含めることにより、古いファイルがブラウザにキャッシュされたままになるのを防ぎます。Flash のユニークID はプリファレンス設定時に、ログファイルのユニークID はエントリ登録時に更新されます。

      ユニークID の付加 (付加する)


      プレビュー

      表示したい SWF ファイル (.swf) が tdiary.rb と同じフォルダにアップロードされている必要があります。また、ログファイルが SWF ファイルと同じフォルダに作成されていない場合にはグラフが表示されません。

      プレビュー (非表示)

      HTML end def tdiarytimes_flashstyle_preview %Q|

      #{if @conf['tdiarytimes_f.preview'] == "1" then "#{tdiarytimes_flashstyle}" else "プレビュー表示を有効にすると、ここに Flash が表示されます。" end}

      | end def tdiarytimes_flashstyle_templete( filename="tdiarytimes234x30.swf", argvs="", width="234", height="30" ) <<-r r end tdiary-contrib-5.0.8/plugin/tdiarytimes_textstyle.rb000066400000000000000000000266261325711763500230120ustar00rootroot00000000000000# tdiarytimes_textstyle.rb $Revision: 1.3 $ # # Copyright (c) 2004 phonondrive # Distributed under the GPL # # プラグイン配布ページ: # http://phonondrive.com/trd/ # -------------------------------------------------------------------- # # # # Abstract: # -------------------------------------------------------------------- # 日記を登録した時間帯をタイムライン上に記録します。 # 記録されたエントリは日時の経過と共にフェードアウトしていきます。 # このような MTBlogTimes や tdiarytimes と同等の機能をテキストで実現します。 # また、テキストベースであることを生かした柔軟なサイトデザインが可能です。 # ruby-gd のインストール作業も必要ないため、すぐに使用出来ます。 # # # Usage: # -------------------------------------------------------------------- # プラグインは、プラグインフォルダに入れてください。 # ヘッダ、あるいはフッタ部に入力した <%= tdiarytimes_textstyle %> # の位置にタイムライン文字列が展開されます。 # 新しいエントリの記録や保持期間の過ぎた古いエントリの削除は、 # 日記の追加および登録時に行われます。 # ただし、エントリのフェードアウト効果はリアルタイムに計算されます。 # エントリの表示分解能は10分ごとです。 # # # Options: # -------------------------------------------------------------------- # # 現在、次の9つのオプションが用意されています。 # # init_text 日記の登録されていない時間帯の文字列 (任意の文字列) # entr_text 日記が登録された時間帯の文字列 (任意の文字列) # init_color 日記の登録されていない時間帯の文字列の色 (RRBBGG形式で指定) # entr_color 日記が登録された時間帯の文字列の色 (RRBBGG形式で指定) # fade_color 日記が登録された時間帯の文字列のフェードアウト先の色 (RRBBGG形式で指定) # init_css タイムライン文字列全体のCSS設定 (CSSの書式に準拠) # entr_css 日記が登録された時間帯の文字列のCSS設定 (CSSの書式に準拠) # title_text オブジェクト上にマウスをポイントした時のTIPS文字列 (任意の文字列) # fade_time ログとして保存しておく(フェードアウトに要する)日数 (任意の数値) # entr_interval 前回のエントリ登録から指定時間以内は新規登録しない (任意の数値) # # オプション値の設定方法には3つの方法があり、その優先順位は次の通りです。 # <%= tdiarytimes_textstyle %> 引数指定 > tdiary.conf設定値 > デフォルト値 # # entr_intervalを除いた全てのオプション値は <%= %> への引数指定により設定出来るため、 # ページにごとに意匠を変更するなど自由度の高いサイトデザインが可能です。 # 一方で、全てのオプションにデフォルト値が用意されているため、 # 全く設定を行わなくても動作します。 # デフォルト値の具体的な値については、tdiary.confへの記述方法の項を参照して下さい。 # # # <%= tdiarytimes_textstyle %>への引数指定によるオプション設定方法 # -------------------------------------------------------------------- #【書式】 # <%= tdiarytimes_textstyle init_text, entr_text, init_color, entr_color, fade_color, init_css, entr_css, title_text, fade_time %> # #【記述例】 # <%=tdiarytimes_textstyle "●","●","004400","66ff66","004400","background-color:#002200;font-size:9px",nil,"TEXTSTYLE!!",15 %> # # ※ tdiary.conf指定値、またはデフォルト値を使用したい場合は、引数に nil を指定してください。 # # # tdiary.confへの記述によるオプション設定方法 # -------------------------------------------------------------------- #【記述例】 (例として指定されている値は、プラグイン本体の持つデフォルト値です) # @options['tdiarytimes_textstyle.init_text'] = "|" # @options['tdiarytimes_textstyle.entr_text'] = "|" # @options['tdiarytimes_textstyle.init_color'] = "444444" # @options['tdiarytimes_textstyle.entr_color'] = "eeeeee" # @options['tdiarytimes_textstyle.fade_color'] = "444444" # @options['tdiarytimes_textstyle.init_css'] = "background-color:#444444;" # @options['tdiarytimes_textstyle.entr_css'] = "" # @options['tdiarytimes_textstyle.title_text'] = "TDIARYTIMES-TEXTSTYLE" # @options['tdiarytimes_textstyle.fade_time'] = 30 # @options['tdiarytimes_textstyle.entr_interval'] = 1 # # ※ fade_time の単位は日、entr_interval の単位は時間です。 # ※ ログとして保存しておく期間(フェードアウト期間)を過ぎたデータエントリは、 # 指定期間経過後の次回日記追加時にログファイルから削除されます。 # この期間を決定する fade_time 値は、<%= %> 引数からは指定出来ません。 # デフォルト値(30日)以外の値を用いたい場合は、必ず tdiary.conf にて指定して下さい。 # 同様に、entr_interval もデフォルト値(1時間)以外に設定したい場合は、 # tdiary.conf にて指定して下さい。ちなみに0.5だと30分間隔になります。 # # # In secure mode: # -------------------------------------------------------------------- # 現在のところ動作しません。(ログファイルを読み込めない為) # # # Acknowledgements: # -------------------------------------------------------------------- # This plugin is based on tdiarytimes.rb $Revision: 1.3 $ # Copyright (c) 2003 neuichi # Distributed under the GPL # http://nmnl.jp/hiki/software/?tDiary+%3A%3A+Plugin # # =begin ChangeLog 2004.03.04 phonondrive * version 1.0.4 非応答USER-AGENTリストを更新しました。 2004.02.05 phonondrive * version 1.0.3 フェードアウト効果の計算結果が正しく出力されない点を修正しました。 2004.01.30 phonondrive * version 1.0.2 最低登録間隔のオプション (entr_interval) を追加。 前回のエントリ登録から指定時間以内は新規登録しないようにしました。 2004.01.29 phonondrive * version 1.0.1 replace(登録)時もエントリを記録するようにしました。 次のUSER-AGENTからの呼び出しには結果を出力しないようにしました。 モバイル端末 (tDiary準拠) テキストブラウザ (w3m, Lynx, links) CSS非対応ブラウザ (Mosaic, Lite, iCab, JustView, WebExplorer) 検索ボット (bot, crawler, Spider, Slurp, inktomi, Sidewinder, naver) その他 (libwww, antenna) 2004.01.28 phonondrive * version 1.0.0 =end # tDiarytimes_textstyle の結果を出力しない USER-AGENT リスト # モバイル端末、テキストブラウザ、CSS非対応ブラウザ、検索ボット、アンテナなど # 大文字・小文字は区別しません。 def tdiarytimes_textstyle_ignore_user_agent; "w3m|Lynx|links|Mosaic|Lite|iCab|JustView|WebExplorer|bot|crawler|Spider|Slurp|inktomi|Sidewinder|naver|libwww|archiver|http|check|WDB|WWWC|WWWD|samidare|tamatebako|NATSU-MICAN|hina|antenna"; end # -------------------------------------------------------------------- # 日記登録時の処理 # -------------------------------------------------------------------- if /^(append|replace)$/ =~ @mode then # オプション値(エントリ保持期間)の読み込みと設定 fade_time = @options['tdiarytimes_textstyle.fade_time'] || 30 fade_time = 24 * 60 * 60 * fade_time.to_f entr_interval = @options['tdiarytimes_textstyle.entr_interval'] || 1 entr_interval = 60 * 60 * entr_interval.to_f # ログデータの読み込み cache = "#{@cache_path}/tdiarytimes_textstyle" Dir::mkdir( cache ) unless File::directory?( cache ) begin io = open("#{cache}/tdiarytimes_textstyle.dat","r") ary_data = Marshal.load(io) io.close # 1.0.1 >> 1.0.2 ログデータ移行用 if ary_data.size == 144 ary_data.push(Time.now.to_i - entr_interval - 1) end rescue # ログがない場合は仮データを用意 ary_data = Array.new(145) {|i| 0 } end # 不良データや寿命が来たエントリを削除する (0..143).each {|i| delta = (Time.now.to_i - ary_data[i])/fade_time.to_f if delta < 0 || delta > 1 ary_data[i] = 0 end } # 最低登録間隔を経過していたら、日記が登録された時間帯に新しいエントリをセットする if (Time.now.to_i - ary_data[144]) > entr_interval.to_f ary_data[(Time.now.strftime('%H').to_i*6 + Time.now.strftime('%M').to_f/10).to_i] = Time.now.to_i # 最終登録時間の記録 ary_data[144] = Time.now.to_i end # ログデータの書き込み io = open("#{cache}/tdiarytimes_textstyle.dat","w") Marshal.dump(ary_data,io) io.close end # -------------------------------------------------------------------- # プラグイン表示時の動作 # -------------------------------------------------------------------- def tdiarytimes_textstyle(init_text = nil, entr_text = nil, init_color = nil, entr_color = nil, fade_color = nil, init_css = nil, entr_css = nil, title_text = nil, fade_time = nil) r = "" # オプション値の読み込みと設定 init_text = @options['tdiarytimes_textstyle.init_text'] || "|" unless init_text entr_text = @options['tdiarytimes_textstyle.entr_text'] || "|" unless entr_text init_color = @options['tdiarytimes_textstyle.init_color'] || "444444" unless init_color entr_color = @options['tdiarytimes_textstyle.entr_color'] || "eeeeee" unless entr_color fade_color = @options['tdiarytimes_textstyle.fade_color'] || "444444" unless fade_color init_css = @options['tdiarytimes_textstyle.init_css'] || "background-color:#444444;" unless init_css entr_css = @options['tdiarytimes_textstyle.entr_css'] || "" unless entr_css title_text = @options['tdiarytimes_textstyle.title_text'] || "TDIARYTIMES-TEXTSTYLE" unless title_text fade_time = @options['tdiarytimes_textstyle.fade_time'] || 30 unless fade_time entr_color_rgb = entr_color.unpack("a2a2a2") fade_color_rgb = fade_color.unpack("a2a2a2") fade_time = 24 * 60 * 60 * fade_time.to_f # ログデータの読み込み cache = "#{@cache_path}/tdiarytimes_textstyle" begin io = open("#{cache}/tdiarytimes_textstyle.dat","r") ary_data = Marshal.load(io) io.close rescue # ログファイルが見つからない場合はエラーとダミーデータを表示 r << %Q|Error! cannot open log file.| ary_data = Array.new(145) {|i| 0 } end # htmlデータの出力 r << %Q|| (0..143).each {|i| data = ary_data[i] if data != 0 delta = (Time.now.to_i - data)/fade_time.to_f if delta < 0 # 不良エントリ対策 now_color = init_color elsif delta > 1 # フェードアウト期間超過エントリ対策 now_color = fade_color else # 正常なエントリの処理 now_color = "" (0..2).each{|i| now_color << format("%02x", entr_color_rgb[i].hex + ((fade_color_rgb[i].hex - entr_color_rgb[i].hex)*delta).to_i) } end r << %Q|#{entr_text}| else r << %Q|#{init_text}| end } r << %Q|| end end tdiary-contrib-5.0.8/plugin/title_anchor.rb000066400000000000000000000004441325711763500207700ustar00rootroot00000000000000# # title_anchor.rb: # # Copyright (C) 2007 by SHIBATA Hiroshi # Distributed under GPL2. # def title_anchor r = '' if /^latest$/ =~ @mode r << %Q|

      #{h @conf.html_title}

      | else r << %Q|

      #{h @conf.html_title}

      | end r end tdiary-contrib-5.0.8/plugin/tweet_quote.rb000066400000000000000000000154431325711763500206670ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # tweet_quote.rb - tDiary plugin to quote tweet on twitter.com, # formaly known as blackbird-pie.rb # # Copyright (C) 2010, hb # # usage: # <%= tweet_quote "id|url" %> # or # <%= twitter_quote "id|url" %> # or # <%= blackbird_pie "id|url" %> # or # <%= bbp "id|url" %> # require 'pstore' require 'open-uri' require 'timeout' require 'time' require 'uri' require 'openssl' require 'json' def twitter_quote_option_keys %w( oauth_consumer_key oauth_consumer_secret oauth_token oauth_token_secret render_method ).map{|k| "twitter_quote.#{k}" } end def twitter_statuses_show_api( tweet_id ) url = "https://api.twitter.com/1.1/statuses/show.json" unsafe = /[^a-zA-Z0-9\-\.\_\~]/ parameters = { :id => tweet_id } oauth_parameters = { :oauth_consumer_key => @conf["twitter_quote.oauth_consumer_key"], :oauth_nonce => OpenSSL::Digest.hexdigest( "MD5", "#{Time.now.to_f}#{rand}" ), :oauth_signature_method => "HMAC-SHA1", :oauth_timestamp => Time.now.to_i.to_s, :oauth_token => @conf["twitter_quote.oauth_token"], :oauth_version => "1.0" } data = "GET&#{URI.escape( url, unsafe )}&" data << URI.escape( oauth_parameters.merge( parameters ).sort.map{|k, v| "#{k}=#{v}" }.join( "&" ), unsafe ) oauth_parameters[:oauth_signature] = [OpenSSL::HMAC.digest( OpenSSL::Digest::SHA1.new, URI.escape( "#{@conf["twitter_quote.oauth_consumer_secret"]}&#{@conf["twitter_quote.oauth_token_secret"]}" ), data )].pack( "m" ).chomp proxy = @conf['proxy'] proxy = 'http://' + proxy if proxy headers = { "Authorization" => %Q[OAuth #{oauth_parameters.map{|k ,v| "#{URI.escape( k.to_s, unsafe )}=\"#{URI.escape( v, unsafe )}\""}.join( "," )}], :proxy => proxy } Timeout.timeout( 20 ) do open( "#{url}?#{parameters.map{|k,v| "#{k}=#{v}"}.join( "&" )}", headers ) {|f| f.read } end end def render_widget(tweet_id, screen_name, name, background_url, profile_backgound_color, avatar, source, timestamp, content) <<-HTML HTML end def render_bbp(tweet_id, screen_name, name, background_url, profile_backgound_color, avatar, source, timestamp, content) <<-HTML HTML end def twitter_status_json_to_html( json ) tweet_id = json['id_str'] screen_name = json['user']['screen_name'] name = json['user']['name'] background_url = json['user']['profile_background_image_url'] profile_background_color = "##{json['user']['profile_background_color']}" avatar = json['user']['profile_image_url'] source = json['source'] timestamp = Time.parse( json['created_at'] ) content = json['text'] content.gsub!( URI.regexp( %w|http https| ) ){ %Q|#{$&}| } content = content.split( /(<[^>]*>)/ ).map {|s| next s if s[/\A([a-zA-Z0-9_]{1,15}))(?![a-zA-Z0-9_])/ ){ %Q|#{$&}| } s.gsub( /#([a-zA-Z0-9]{1,16})/ ){ %Q|#{$&}| } }.join if @conf['twitter_quote.render_method'] == 'widget' render_widget(tweet_id, screen_name, name, background_url, profile_backgound_color, avatar, source, timestamp, content) else render_bbp(tweet_id, screen_name, name, background_url, profile_backgound_color, avatar, source, timestamp, content) end end def tweet_quote( src ) return unless twitter_quote_option_keys.all?{|v| @options.key? v } if %r|http(?:s)?://twitter.com/(?:#!/)?[^/]{1,15}/status(?:es)?/([0-9]+)| =~ src.to_s.downcase src = $1 end return unless /\A[0-9]+\z/ =~ src.to_s cache = "#{@cache_path}/tweet_quote.pstore" json = nil db = PStore.new( cache ) db.transaction do key = src db[key] ||= {} if db[key][:json] && /\A(?:latest|day|month|nyear)\z/ =~ @mode json = db[key][:json] else begin json = twitter_statuses_show_api( src ) rescue OpenURI::HTTPError return %Q|

      #$!

      | end db[key][:json] = json end end twitter_status_json_to_html( JSON.parse( json ) ) end add_conf_proc( 'twitter_quote', 'Embedded Tweets' ) do if @mode == 'saveconf' twitter_quote_option_keys.each do |k| @conf[k] = @cgi.params[k][0] end end <<-HTML

      Twitter OAuth settings

      Consumer key

      Consumer secret

      Your access token

      Access token

      Access token secret

      Render method

      HTML end alias :blackbird_pie :tweet_quote alias :bbp :tweet_quote alias :twitter_quote :tweet_quote tdiary-contrib-5.0.8/plugin/twitpic.rb000066400000000000000000000006741325711763500200050ustar00rootroot00000000000000# # twitpic.rb: plugin to insert images on twitpic.com. # # Copyright (C) 2010 TADA Tadashi # You can redistribute it and/or modify it under GPL2. # def twitpic( image_id, label = 'image on Twitpic', place = 'photo' ) %Q|#{h label}| end tdiary-contrib-5.0.8/plugin/twitter.rb000066400000000000000000000023261325711763500200200ustar00rootroot00000000000000# twitter.rb $Revision: 1.1 $ # Copyright (C) 2007 Michitaka Ohno # You can redistribute it and/or modify it under GPL2. require 'timeout' require 'time' require 'open-uri' require 'rexml/document' @twitter_statuses = [] if /^(latest|day)$/ =~ @mode then add_header_proc do xml = nil Timeout.timeout( 5 ) do begin xml = open( "http://twitter.com/statuses/user_timeline/#{@conf['twitter.user']}.xml" ){|f| f.read} rescue Exception end end doc = REXML::Document.new( xml ).root if xml if doc then doc.elements.each( 'status' ) do |e| @twitter_statuses << [@conf.to_native( e.elements['text'].text ), Time.parse( e.elements['created_at'].text ).localtime] end end '' end end add_body_leave_proc do |date| today_statuses = [] @twitter_statuses.each do |t, d| today_statuses << [t, d] if d.to_a[3,3] == date.to_a[3,3] end if !today_statuses.empty? r = %Q[
      ] r << %Q[

      Twitter statuses

      ] today_statuses.sort{|a, b| b.last<=>a.last}.each do |t, d| r << %Q[

      #{CGI::escapeHTML( t )} (#{d.strftime( '%H:%M:%S' )})

      ] end r << %Q[
      ] else '' end end tdiary-contrib-5.0.8/plugin/twitter_anywhere.rb000066400000000000000000000123071325711763500217220ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # twitter_anywhere.rb - bringing the Twitter communication platform to tDiary # refer to the URL below. # https://dev.twitter.com/docs/anywhere/welcome # # Copyright (C) 2010-2012, tamoot # You can redistribute it and/or modify it under GPL2. # def follow_button(account) return not_support_anywhere unless support_anywhere? return not_ready_anywhere unless ready_anywhere? if account.nil? || account == '' return anywhere_plugin_error("Account name is not specified.") end <<-FOLLOW_API FOLLOW_API end def tweet_box(label = nil, content = nil, option = {}) return not_support_anywhere unless support_anywhere? return not_ready_anywhere unless ready_anywhere? init_tweetbox @tweetbox_opt.merge!(option) @tweetbox_opt.merge!(:height => 120) unless option[:height].to_i > 0 @tweetbox_opt.merge!(:width => 480) unless option[:width].to_i > 0 @tweetbox_opt.merge!(:label => label) if label @tweetbox_opt.merge!(:defaultContent => content) if content %Q|| end def twitter_anywhere_settings enable_js('twitter_anywhere.js') add_js_setting('$tDiary.plugin.twitter_anywhere') selectors = @conf['twitter_anywhere.hovercards.selectors'].split(',').collect do |selector| %Q|"#{selector.strip}"| end add_js_setting('$tDiary.plugin.twitter_anywhere.selectors', "[#{selectors.join(',')}]" ) expanded = '{}' if @conf['twitter_anywhere.hovercards.expand_default'] == 'true' expanded = '{"expanded":true}' end add_js_setting('$tDiary.plugin.twitter_anywhere.hovercards') add_js_setting('$tDiary.plugin.twitter_anywhere.hovercards.expand_default', expanded) end add_header_proc do if /\A(?:latest|day|month|nyear|preview)\z/ =~ @mode if ready_anywhere? %Q|| else '' end end end def init_tweetbox @tweetbox_json_opt ||= [] @tweetbox_opt ||= {} end add_footer_proc do |date| if /\A(?:latest|day|month|nyear|preview)\z/ =~ @mode if ready_anywhere? init_tweetbox @tweetbox_opt.each_pair do |k, v| @tweetbox_json_opt << "\"#{k}\":\"#{v}\"" end tweet_box_call = %Q|\n| else '' end else '' end end add_conf_proc( 'twitter_anywhere', 'Twitter Anywhere' ) do if @mode == 'saveconf' then @conf['twitter_anywhere.id'] = @cgi.params['twitter_anywhere.id'][0] @conf['twitter_anywhere.hovercards.selectors'] = @cgi.params['twitter_anywhere.hovercards.selectors'][0] @conf['twitter_anywhere.hovercards.expand_default'] = @cgi.params['twitter_anywhere.hovercards.expand_default'][0] end expand_true = "" expand_false = "selected" if @conf['twitter_anywhere.hovercards.expand_default'] == "true" expand_true = "selected" expand_false = "" end <<-HTML

      Consumer key

      Register your tDiary and get Consumer key. Go Twitter OAuth settings.

      Rending Hovercards

      CSS Selector To limit the scope of where Hovercards appear

      example) div.section p, div.commentshort p, div.commentbody p

      Expanded by Default

      HTML end def support_anywhere? return !feed? end def ready_anywhere? if @conf['twitter_anywhere.id'] && @conf['twitter_anywhere.id'].size > 0 return true end return false end def not_support_anywhere '[Twitter@Anywhere] not support this environment.' end def not_ready_anywhere anywhere_plugin_error( "Twitter consumer Key not specified.", %Q|Go Twitter OAuth settings.|) end def anywhere_plugin_error(message, detail= '') <<-PLUGIN_ERROR

      [ERROR] twitter_anywhere.rb: #{message}


      #{detail}

      PLUGIN_ERROR end if /\A(?:latest|day|month|nyear|preview)\z/ =~ @mode twitter_anywhere_settings end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/plugin/twitter_badge.rb000066400000000000000000000021101325711763500211310ustar00rootroot00000000000000# # twitter_badge.rb: insert 'Follow me' badge of Twitter. # # Copyright (C) 2010 TADA Tadashi # You can redistribute it and/or modify it under GPL2. # def twitter_badge( account, opt = {} ) return '' unless account @twitter_badge_setting = { :account => account, :label => (opt[:label] || 'follow-me'), :color => (opt[:color] || '#35ccff'), :side => (opt[:side] || 'right')[0,1], :top => (opt[:top] || 136).to_i, :delay => (opt[:delay] || 5).to_i * 1000, } '' # do nothing in this method. end add_footer_proc do if @twitter_badge_setting then t = @twitter_badge_setting <<-TEXT TEXT else '' end end tdiary-contrib-5.0.8/plugin/twitter_js.rb000066400000000000000000000035601325711763500205150ustar00rootroot00000000000000# twitter_js.rb $Revision: 1.1 $ # Copyright (C) 2007 Michitaka Ohno # You can redistribute it and/or modify it under GPL2. if /\A(?:latest|day)\z/ =~ @mode then if @conf['twitter.user'] then twitter_user = @conf['twitter.user'] add_header_proc do result = <<-HTML HTML result.gsub( /^\t\t/, '' ) end add_body_leave_proc do |date| result = <<-HTML
      HTML result.gsub( /^\t\t/, '' ) end end end add_conf_proc( 'twitter_js', 'Twitter' ) do if @mode == 'saveconf' then @conf['twitter.user'] = @cgi.params['twitter.user'][0] end <<-HTML

      Account Name

      HTML end tdiary-contrib-5.0.8/plugin/twitter_summary_card.rb000066400000000000000000000035041325711763500225650ustar00rootroot00000000000000# Twitter Summary Card plugin # # # Copyright (c) 2013 Tatsuya Sato def twitter_summary_card_description section_index = @cgi.params['p'][0] if @mode == 'day' and section_index diary = @diaries[@date.strftime('%Y%m%d')] sections = diary.instance_variable_get(:@sections) section = sections[section_index.to_i - 1].body_to_html @conf.shorten(apply_plugin(section, true), 200) else @conf.description end end add_header_proc do headers = { 'twitter:card' => 'summary', 'twitter:site' => @conf['twitter_summary_card.site'] || @conf['twitter_summary_card.creator'], 'twitter:creator' => @conf['twitter_summary_card.creator'], 'twitter:title' => title_tag.match(/>([^<]+)/).to_a[1], 'twitter:description' => twitter_summary_card_description, 'twitter:image:src' => @conf.banner } headers = headers.select { |_, v| v && not(v.empty?) } headers = headers.map do |k, v| %Q|| end headers.join("\n") end add_conf_proc('Twitter Summary Card', 'Twitter Summary Card') do if @mode == 'saveconf' @conf['twitter_summary_card.site'] = @cgi.params['twitter_summary_card.site'][0] @conf['twitter_summary_card.creator'] = @cgi.params['twitter_summary_card.creator'][0] end <<-HTML

      Twitter Summary Card

      Please refer to the following documentation at first.

      Your tDiary's Twitte account

      Creator's Twitter account

      HTML end tdiary-contrib-5.0.8/plugin/ustream.rb000066400000000000000000000011111325711763500177650ustar00rootroot00000000000000# # ustream.rb - insert some services of Ustream.tv # # Copyright (C) 2010, TADA Tadashi . # You can redistribute it and/or modify it under GPL2. # def ustream( id, type = :recorded ) if type == :live then return '' end # insert recorded video if feed? then return %Q|Link to Ustream ##{id}

      | end %Q|| end tdiary-contrib-5.0.8/plugin/vimeo.rb000066400000000000000000000007221325711763500174330ustar00rootroot00000000000000# # vimeo.rb - insert some services of vimeo.com # # Copyright (C) 2011, Kiwamu Okabe . # You can redistribute it and/or modify it under GPL2. # def vimeo( id ) if feed? then return %Q|Link to vimeo ##{id}

      | end %Q|| end tdiary-contrib-5.0.8/plugin/volatile.rb000066400000000000000000000046471325711763500201450ustar00rootroot00000000000000# hide old diaries # # options configurable through settings: # @conf['volatile.limit'] : number of diaries to show # # Copyright (c) MATSUOKA Kohei # Distributed under the GPL # module ::TDiary # 複数の日記を一括して更新するためのクラス class TDiaryBulkUpdate < TDiaryUpdate def initialize( cgi, rhtm, conf ) super date = Time::local( *cgi.params['date'][0].scan( /^(\d{4})(\d\d)$/ )[0] ) @io.transaction( date ) do |diaries| yield(diaries) # DIRTY_DIARYは@ioへ日記を更新することを伝えるフラグ DIRTY_DIARY end end end end # 古い日記を非表示にするプラグイン class VolatileDiaryPlugin def initialize(conf) @conf = conf @limit = conf['volatile.limit'] || 10 end # all を true にすると全ての日記を対象とする def update(years, all = false) each_recent_diary(years) do |date, diary, count| diary.show(count <= @limit) all || count <= @limit end end def each_recent_diary(years) cgi = CGI.new count = 1 break_flag = false years.keys.sort.reverse_each do |year| years[year].sort.reverse_each do |month| cgi.params['date'] = ["#{year}#{month}"] cgi.params['year'] = [year] cgi.params['month'] = [month] cgi.params['day'] = ["1"] m = TDiaryBulkUpdate::new(cgi, '', @conf) {|diaries| # diaries.class is Hash (date => diary) diaries.sort.reverse_each do |date, diary| unless yield(date, diary, count) break_flag = true break end count += 1 end } break if break_flag end break if break_flag end end end add_update_proc do # 古い日記を非表示にする plugin = VolatileDiaryPlugin.new(@conf) plugin.update(@years) end add_conf_proc('volatile', "揮発性日記", 'update') do if @mode == 'saveconf' then @conf['volatile.limit'] = @cgi.params['volatile.limit'][0].to_i p = VolatileDiaryPlugin.new(@conf) p.update(@years, true) end r = <<-HTML

      日記の更新時に古い日記を非表示にします。

      公開する日記の件数

      公開したい日記の件数を入力してください。
      HTML r end tdiary-contrib-5.0.8/plugin/vote.rb000066400000000000000000000056051325711763500172760ustar00rootroot00000000000000# tdiary_vote.rb $Revision: 2 $ # Copyright (C) 2006 Michitaka Ohno # You can redistribute it and/or modify it under GPL2. # # ref. http://elpeo.jp/diary/20060622.html#p01 # # .tdiary-vote { # float: left; # background-color: aqua; # } require 'digest/md5' require 'pstore' @tdiary_vote_db = "#{@cache_path}/tdiary_vote" @tdiary_vote_label = "投票" @tdiary_vote_date = nil def vote( *items ) return '' unless @tdiary_vote_date h, voted = get_vote( @tdiary_vote_date, @cgi.cookies['tdiary_vote'][0] ) max = h.empty? ? 1 : h.values.max r = %Q[] items.sort{|a, b| h[b] <=> h[a]}.each do |item| num = h[item] r << %Q[] r << %Q[] r << %Q[] unless voted then r << %Q[] end r << %Q[] end r << %Q[
      #{CGI.escapeHTML( item )}#{num}] r << %Q[
      ] r << %Q[#{csrf_protection}] r << %Q[] r << %Q[] r << %Q[] r << %Q[] r << %Q[] r << %Q[
      ] r << %Q[
      ] end def get_vote( date, uid ) h = Hash.new(0) voted = false file = "#{@tdiary_vote_db}/#{date.strftime( "%Y%m%d" )}.db" if File.exist?( file ) then PStore.new( file ).transaction do |db| h.update( db['vote'] ) if db.root?( 'vote' ) voted = db['voter'].include?( uid ) if db.root?( 'voter' ) db.abort end end [h, voted] end def add_vote( date, item, uid ) Dir::mkdir( @tdiary_vote_db ) unless File::directory?( @tdiary_vote_db ) file = "#{@tdiary_vote_db}/#{date.strftime( "%Y%m%d" )}.db" PStore.new( file ).transaction do |db| db['voter'] = Hash.new unless db.root?( 'voter' ) db.abort if db['voter'].include?( uid ) db['voter'][uid] = @cgi.remote_addr db['vote'] = Hash.new(0) unless db.root?( 'vote' ) db['vote'][item] += 1 end end add_body_enter_proc do |date| @tdiary_vote_date = date '' end add_body_leave_proc do |date| @tdiary_vote_date = nil '' end unless bot? then if @mode == 'comment' && @cgi.valid?( 'vote' ) && @cgi.cookies['tdiary_vote'][0] then add_vote( @date, @cgi.params['vote'][0], @cgi.cookies['tdiary_vote'][0] ) end add_footer_proc do uid = @cgi.cookies['tdiary_vote'][0] || Digest::MD5.hexdigest( @cgi.remote_addr + Time.now.to_s + rand.to_s ) cookie_path = File::dirname( @cgi.script_name ) cookie_path += '/' if cookie_path !~ /\/$/ cookie = CGI::Cookie::new( 'name' => 'tdiary_vote', 'value' => uid, 'path' => cookie_path, 'expires' => Time.now.gmtime + 30*24*60*60 ) add_cookie( cookie ) '' end end tdiary-contrib-5.0.8/plugin/wikiloc.rb000066400000000000000000000017331325711763500177600ustar00rootroot00000000000000# # wikiloc.rb: plugin embedding trip map on wikiloc. # # Copyright (C) 2008 MUNEDA Takahiro # You can redistribute it and/or modify it under GPL2. # # derived from everytrail.rb, Copyright (C) 2008 TADA Tadashi # # Parameters: # @trip_id : your trip id # @measures : on/off # @maptype : M/S/H/T # @size : [width,height] # # Please see the following address about the details: # http://www.wikiloc.com/forum/posts/list/14.page # # ChangeLog: # 20080706: Initial release # 20080713: Change default parameters # def wikiloc( trip_id, measures = "off", maptype = "M", size = [500,400] ) size.collect! {|i| i.to_i } size[0] = 500 if size[0] == 0 size[1] = 400 if size[1] == 0 %Q|| end tdiary-contrib-5.0.8/plugin/windex.rb000066400000000000000000000327111325711763500176150ustar00rootroot00000000000000#!/usr/bin/env ruby # windex.rb $Revision: 1.2 $ # # windex: 索引を生成する # パラメタ: # str: キーワード文字列 # readname: 読み仮名 # # wikw: 索引からアンカーを生成する # パラメタ: # str: キーワード文字列 # # このファイルをtDiaryのトップディレクトリにも配置し、CGIとして # 実行することで索引ページを出力できます。 # # CGI動作時の引数 # http://(日記URL)/windex.rb?kw=(キーワード文字列) # とキーワードを指定してアクセスすることでそのキーワードに関係する日記の # 日付一覧を出力できます。一つだけの場合にはその日付の日記への # リダイレクトを出力します。 # # tdiary.confによる設定 # @options['windex.generate_all'] = true # 全ての日記から索引を生成します。これは時間がかかるので、索引の全生成を # 行いたいときだけtrueに設定して更新を行うような使い方を想定しています。 # # Copyright (c) 2003 Gony # Distributed under the GPL # mode = "" if $0 == __FILE__ mode = "CGI" if FileTest.symlink?(__FILE__) == true org_path = File.dirname(File.readlink(__FILE__)) else org_path = File.dirname(__FILE__) end $:.unshift(org_path) require "pstore" require "tdiary" tdiarybase = TDiary::TDiaryBase else tdiarybase = TDiaryBase end class WITDiary < tdiarybase def load_plugins super end def generate_wordindex(date,plugin,index) wordindex = WIWordIndex.new @io.transaction(date) do |diaries| wordindex.generate(diaries,plugin,index) end return wordindex end end class WIWordIndex def initialize @windex = {} @dates = [] end def generate(diaries,plugin,index) diaries.each_value do |diary| num_section = 1 diary.each_section do |section| anchor = index \ + plugin.anchor(diary.date.strftime("%Y%m%d")) \ + "#p%02d" % num_section if section.subtitle != nil scan(section.subtitle,anchor) end scan(section.body,anchor) num_section = num_section + 1 end end end def load(dir) @windex = {} Dir.mkdir(dir) unless File.directory?(dir) PStore.new(dir + "/windex").transaction do |pstore| @dates = pstore.roots @dates.each do |key| windex_tmp = pstore[key] windex_tmp.each_key do |key_windex| if @windex.has_key?(key_windex) == false @windex[key_windex] = {"readname" => nil, "anchor" => []} end if @windex[key_windex]["readname"] == nil \ && windex_tmp[key_windex].has_key?("readname") == true @windex[key_windex]["readname"] = windex_tmp[key_windex]["readname"] end @windex[key_windex]["anchor"].concat(windex_tmp[key_windex]["anchor"]) end end end end def save(dir,keyname) if File.directory?(dir) == false Dir.mkdir(dir,0755) end PStore.new(dir + "/windex").transaction do |pstore| pstore[keyname] = @windex end end def generate_html(page) return page.generate_html(@windex) end def has_key?(key) return @windex.has_key?(key) end def [](key) return @windex[key] end private def scan(body,anchor) to_delimiter_end = { "(" => ")","[" => "]","{" => "}","<" => ">", } wistrs = body.scan(%r[<%\s*=\s*windex\s*[^(<%)]*\s*%>]) wistrs.each do |wistr| # 引数抽出 argstr = wistr.gsub(%r[<%\s*=\s*windex\s*],"") argstr = argstr.gsub(%r[\s*%>],"") args = [] flag_done = false while flag_done == false pos_delimiter = argstr.index(%r['|"|%[Qq].]) #"' if pos_delimiter != nil # デリミタ文字取得 delimiter = argstr.scan(%r['|"|%[Qq].])[0] #"' if delimiter.length == 3 delimiter_end = delimiter[2].chr if to_delimiter_end.has_key?(delimiter_end) delimiter_end = to_delimiter_end[delimiter_end] end else delimiter_end = delimiter end # デリミタまでの文字列を削除 argstr = argstr[(pos_delimiter + delimiter.length)..-1] pos_delimiter = argstr.index(delimiter_end) if pos_delimiter != nil if pos_delimiter > 0 # 引数として取得 args << argstr[0..(pos_delimiter - 1)] else args << "" end # デリミタまでの文字列を削除 argstr = argstr[(pos_delimiter + delimiter_end.length)..-1] else flag_done = true end else flag_done = true end end if args.length > 0 if @windex.has_key?(args[0]) == false # ハッシュを生成 @windex[args[0]] = {"readname" => nil,"anchor" => []} end if args.length > 1 && @windex[args[0]]["readname"] == nil && args[1] != "" @windex[args[0]]["readname"] = args[1] end @windex[args[0]]["anchor"] << anchor end end end end class WIIndexPage def initialize(title,css) @title = title @css = css end def generate_html(windex) body = "" # 大項目名 => 名前の配列 のハッシュを生成 subindex_to_name = {} windex.keys.each do |key| subindex = "" if windex[key]["readname"] != nil subindex = get_subindex(windex[key]["readname"]) else subindex = get_subindex(key) end if subindex_to_name.has_key?(subindex) == false subindex_to_name[subindex] = [] end subindex_to_name[subindex] << key end # 大項目名ごとにHTMLを生成 if subindex_to_name.has_key?("記号") == true body << generate_html_subindex(windex,subindex_to_name,"記号") end subindex_to_name.keys.sort.each do |key| if key != "記号" body << generate_html_subindex(windex,subindex_to_name,key) end end body = <<-BODY #{h @title}(索引) #{@css}

      #{@title} [索引]

      #{body}
      BODY return body end private def generate_html_subindex(windex,subindex_to_name,key) readname_to_name = {} subindex_to_name[key].each do |name| key_new = "" if windex[name]["readname"] != nil key_new = windex[name]["readname"] else key_new = name end if readname_to_name.has_key?(key_new) == false readname_to_name[key_new] = [] end readname_to_name[key_new] << name end body = %Q[

      #{key}

      \n] # 読み仮名のソートでループ -> 名前のソートでループ keys = readname_to_name.keys if keys.empty? == false keys.sort.each do |readname| readname_to_name[readname].sort.each do |name| body << "

      #{name} ... " num_anchor = 1 windex[name]["anchor"].sort.each do |anchor| body = body + %Q[#{num_anchor}] if num_anchor < windex[name]["anchor"].length body = body + "," end num_anchor = num_anchor + 1 end body << "

      " end end end body << "\n
      \n" return body end def get_subindex(name) to_plainhiragana = { "ぁ" => "あ","ぃ" => "い","ぅ" => "う","ぇ" => "え","ぉ" => "お", "が" => "か","ぎ" => "き","ぐ" => "く","げ" => "け","ご" => "こ", "ざ" => "さ","じ" => "し","ず" => "す","ぜ" => "せ","ぞ" => "そ", "だ" => "た","ぢ" => "ち","っ" => "つ","づ" => "つ","で" => "て","ど" => "と", "ば" => "は","ぱ" => "は","び" => "ひ","ぴ" => "ひ","ぶ" => "ふ","ぷ" => "ふ","べ" => "へ","ぺ" => "へ","ぼ" => "ほ","ぽ" => "ほ", "ゃ" => "や","ゅ" => "ゆ","ょ" => "よ", "ゎ" => "わ","ヴ" => "う","ヵ" => "か","ヶ" => "け", } to_1byte = { "!" => "!",'”' => '"',"#" => "#","$" => "$","%" => "%","&" => "&","’" => "'","(" => "(",")" => ")","*" => "*","+" => "+","," => ",","−" => "-","." => ".","/" => "/", "0" => "0","1" => "1","2" => "2","3" => "3","4" => "4","5" => "5","6" => "6","7" => "7","8" => "8","9" => "9",":" => ":",";" => ";","<" => "<","=" => "=",">" => ">","?" => "?", "@" => "@","A" => "A","B" => "B","C" => "C","D" => "D","E" => "E","F" => "F","G" => "G","H" => "H","I" => "I","J" => "J","K" => "K","L" => "L","M" => "M","N" => "N","O" => "O", "P" => "P","Q" => "Q","R" => "R","S" => "S","T" => "T","U" => "U","V" => "V","W" => "W","X" => "X","Y" => "Y","Z" => "Z","[" => "[","¥" => "\\","]" => "]","^" => "^","_" => "_", "a" => "a","b" => "b","c" => "c","d" => "d","e" => "e","f" => "f","g" => "g","h" => "h","i" => "i","j" => "j","k" => "k","l" => "l","m" => "m","n" => "n","o" => "o", "p" => "p","q" => "q","r" => "r","s" => "s","t" => "t","u" => "u","v" => "v","w" => "w","x" => "x","y" => "y","z" => "z","{" => "{","|" => "|","}" => "}","‾" => "~", } topchr = name[0,1] if topchr.count("\xA1-\xFE") == 1 # マルチバイト文字 topchr = name[0,2] end if to_1byte.has_key?(topchr) == true topchr = to_1byte[topchr] end if topchr.length == 1 # シングルバイト文字の処理 topchr = topchr.upcase if (0x21 <= topchr[0] && topchr[0] <= 0x2F) \ || (0x3A <= topchr[0] && topchr[0] <= 0x40) \ || (0x5B <= topchr[0] && topchr[0] <= 0x60) \ || (0x7B <= topchr[0] && topchr[0] <= 0x7B) topchr = "記号" end else # マルチバイト文字の処理 # カタカナ->ひらがな変換 code = topchr[0] * 0x100 + topchr[1] if 0xA5A1 <= code && code <= 0xA5F3 topchr = 0xA4.chr + topchr[1].chr end # 濁点 / 半濁点 撥音など変換 if to_plainhiragana.has_key?(topchr) == true topchr = to_plainhiragana[topchr] end end return topchr end end class WIRedirectPage def initialize(key) @key = key end def generate_html(windex) anchor = windex[@key]["anchor"][0] body = <<-BODY moving... Wait or Click here! BODY return body end end class WISinglePage def initialize(title,date_format,css,key) @title = title @date_format = date_format @css = css @key = key end def generate_html(windex) anchors = windex[@key]["anchor"] body = %Q[

      #{@key}

      \n] anchors.sort.each do |anchor| str_date = anchor.scan(/\d{8}/)[0] date = Time.local(str_date[0..3].to_i,str_date[4..5].to_i,str_date[6..7].to_i) body << %Q[

      #{date.strftime(@date_format)}

      \n] end body << "\n
      \n" body = <<-BODY #{h @title}(索引) #{@css}

      #{@title} [索引]

      #{body}
      BODY return body end end class WIErrorPage def initialize(title,css,key) @title = title @css = css @key = key end def generate_html(windex) body = <<-BODY #{h @title}(索引) #{@css}

      #{@title} [索引]

      キーワード「#{h @key}」は登録されていません。
      BODY return body end end def windex(str,readname = "") return str end def wikw(str) if @wordindex.has_key?(str) == true anchors = @wordindex[str]["anchor"] if anchors.length == 1 return %Q[#{str}] else body = "#{str}(" num_anchor = 1 anchors.sort.each do |anchor| body << %Q[#{num_anchor}] if num_anchor < anchors.length body << "," end num_anchor = num_anchor + 1 end body << ")" return body end end return str end if mode != "CGI" @wordindex = WIWordIndex.new @wordindex.load(@cache_path + "/windex") add_update_proc do if @conf.options["windex.generate_all"] == true tdiary = WITDiary.new(@cgi,"day.rhtml",@conf) @years.each_key do |year| @years[year.to_s].each do |month| date = Time::local(year,month) wordindex = tdiary.generate_wordindex(date,self,@conf.index) wordindex.save(@cache_path + "/windex",date.strftime('%Y%m')) end end else wordindex = WIWordIndex.new wordindex.generate(@diaries,self,@conf.index) wordindex.save(@cache_path + "/windex",@date.strftime('%Y%m')) end end else cgi = CGI.new conf = TDiary::Config.new(cgi) cache_path = conf.data_path + "cache" plugin = WITDiary.new(cgi,"day.rhtml",conf).load_plugins wordindex = WIWordIndex.new wordindex.load(cache_path + "/windex") if cgi.valid?('kw') == true key = cgi.params['kw'][0] if wordindex.has_key?(key) == true num_anchor = wordindex[key]["anchor"].length if num_anchor == 0 page = WIErrorPage.new(conf.html_title,plugin.css_tag,key) elsif num_anchor == 1 page = WIRedirectPage.new(key) else page = WISinglePage.new(conf.html_title,conf.date_format,plugin.css_tag,key) end else page = WIErrorPage.new(conf.html_title,plugin.css_tag,key) end else page = WIIndexPage.new(conf.html_title,plugin.css_tag) end body = wordindex.generate_html(page) header = { "type" => "text/html", "charset" => "UTF-8", "Content-Length" => body.size.to_s, "Pragma" => "no-cache", "Cache-Control" => "no-cache", "Vary" => "User-Agent", } head = cgi.header(header) print head print body end tdiary-contrib-5.0.8/plugin/yahoo_kousei.rb000066400000000000000000000054341325711763500210170ustar00rootroot00000000000000# # yahoo_kousei.rb - # Yahoo!JAPANデベロッパーネットワークの校正支援APIを利用して、 # 日本語文の校正作業を支援します。文字の入力ミスや言葉の誤用がないか、 # わかりにくい表記や不適切な表現が使われていないかなどをチェックします。 # # Copyright (c) 2010, hb # You can redistribute it and/or modify it under GPL. # # 設定: # # @options['yahoo_kousei.appid'] : アプリケーションID(必須) # @options['yahoo_kousei.filter_group'] : # 指摘グループの番号をコンマで区切って指定します。 # @options['yahoo_kousei.no_filter'] : # filter_groupで指定した指摘グループから除外する指摘を指定します。 # # 設定値は http://developer.yahoo.co.jp/webapi/jlp/kousei/v1/kousei.html を参照 # require 'timeout' require 'rexml/document' require 'net/http' Net::HTTP.version_1_2 def kousei_api( sentence ) appid = @conf['yahoo_kousei.appid'] query = "appid=#{appid}&sentence=#{URI.encode( sentence.gsub( /\n/, '' ) )}" query << "&filter_group=" + @conf['yahoo_kousei.filter_group'] if @conf['yahoo_kousei.filter_group'] query << "&no_filter=" + @conf['yahoo_kousei.no_filter'] if @conf['yahoo_kousei.no_filter'] px_host, px_port = (@conf['proxy'] || '').split( /:/ ) px_port = 80 if px_host and !px_port xml = '' Net::HTTP::Proxy( px_host, px_port ).start( 'jlp.yahooapis.jp' ) do |http| xml = http.post( '/KouseiService/V1/kousei', query ).body end xml end def kousei_result( result_set ) html = <<-HTML

      文章校正結果

      HTML doc = REXML::Document::new( result_set ) results = REXML::XPath.match( doc, "//Result" ) if results.empty? html << "

      指摘項目は見つかりませんでした。

      " else html << '' html << '' doc.elements.each( '//ResultSet/Result' ) do |r| html << %Q|| end html << '
      対象表記候補文字詳細情報場所
      #{r.elements['Surface'].text}#{r.elements['ShitekiWord'].text}#{r.elements['ShitekiInfo'].text}#{r.elements['StartPos'].text},#{r.elements['Length'].text}
      ' end html end add_edit_proc do if @mode == 'preview' && @conf['yahoo_kousei.appid'] then xml = kousei_api( @cgi.params['body'][0] ) <<-HTML
      #{kousei_result( xml )} Webサービス by Yahoo! JAPAN
      HTML end end if /\A(form|edit|preview|showcomment)\z/ === @mode then enable_js( 'yahoo_kousei.js' ) end tdiary-contrib-5.0.8/plugin/yahoo_map.rb000066400000000000000000000067101325711763500202730ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # yahoo_map.rb - embeded Yahoo! JAPAN Map for tDiary # # Copyright (C) 2010, KAYA Satoshi # You can redistribute it and/or modify it under GPL2. # add_header_proc do init_ymap r = '' if @conf['yahoo_jp.appid'] and @conf['yahoo_jp.appid'].size > 0 r << %Q|| end end add_conf_proc( 'yahoo_jp_appid', 'Yahoo! JAPAN Application ID' ) do if @mode == 'saveconf' then @conf['yahoo_jp.appid'] = @cgi.params['yahoo_jp.appid'][0] end <<-HTML

      Yahoo! JAPAN Application ID

      Get Application id

      HTML end add_footer_proc do |date| insert_ymap_js end def init_ymap @ymap_container = Array.new end def generate_ymapid(lat, lon, layer, size) ymapid = 'ymapid' << lat.to_s << lon.to_s << layer.to_s << size ymapid.delete('.') end def yahoo_map(lat, lon, options = {}) options[:layer] ||= 17 options[:size] ||= 'medium' if feed? return %Q|

      Link to Yahoo! JAPAN Map

      | end # define map size height = {'small'=> '240px', 'medium' => '360px', 'large' => '480px'} width = {'small' => '320px', 'medium' => '480px', 'large' => '640px'} size = options[:size] ymapid = generate_ymapid(lat, lon, options[:layer], options[:size]) ymap_info = {:ymapid => ymapid, :lat => lat, :lon => lon, :layer => options[:layer]} @ymap_container << ymap_info %Q|
      | end def insert_ymap_js r = '' if @ymap_container.size > 0 and not feed? then r << %Q|| end end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/plugin/yo_update.rb000066400000000000000000000153521325711763500203120ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # yo_update.rb - Yo all when an entry or a comment is posted # # Copyright (C) 2014, zunda # # Permission is granted for use, copying, modification, # distribution, and distribution of modified versions of this # work under the terms of GPL version 2 or later. # require 'uri' require 'timeout' require 'net/http' require 'json' YO_UPDATE_TIMEOUT = 10 class YoUpdateError < StandardError; end def yo_update_url(date = nil, frag = nil) # date: Time frag: e.g. 'p01' url = @conf.index.dup url[0, 0] = base_url unless %r|^https?://|i =~ url url.gsub!( %r|/\./|, '/' ) if date ymd = date.strftime('%Y%m%d') anc = frag ? "#{ymd}##{frag}" : ymd url += anchor(anc) end url end def yo_update_api_key r = @conf['yo_update.api_key'] if not r or r.empty? return nil end return r end def yo_update_access_api(req) if @conf['proxy'] proxy_uri = URI("http://" + @conf['proxy']) proxy_addr = proxy_uri.host proxy_port = proxy_uri.port else proxy_addr = nil proxy_port = nil end begin Timeout.timeout(YO_UPDATE_TIMEOUT) do return Net::HTTP.start(req.uri.host, req.uri.port, proxy_addr, proxt_port){|http| http.request(req) } end rescue Timeout::Error raise YoUpdateError, "Timeout accessing Yo API" rescue SocketError => e raise YoUpdateError, e.message end end def yo_update_send_yo(username = nil, url = '') api_key = yo_update_api_key unless api_key raise YoUpdateError, "Yo API Key is not set" end data = {'api_token' => api_key} data['link'] = url unless url.empty? unless username req = Net::HTTP::Post.new(URI("http://api.justyo.co/yoall/")) req.set_form_data(data) expected = '{}' else req = Net::HTTP::Post.new(URI("http://api.justyo.co/yo/")) data['username'] = username req.set_form_data(data) expected = '{"result": "OK"}' end res = yo_update_access_api(req) data = res.body unless data == expected raise YoUpdateError, "error from Yo API: #{data}" end return data end def yo_update_send_yo_or_log(username = nil, url = '') return unless yo_update_api_key begin yo_update_send_yo(username, url) rescue YoUpdateError => e @logger.error "yo_update.rb: #{e.message}" end end def yo_update_subscribers_count api_key = yo_update_api_key unless api_key raise YoUpdateError, "Yo API Key is not set" end req = Net::HTTP::Get.new( URI("http://api.justyo.co/subscribers_count/?api_token=#{URI.escape(api_key)}") ) res = yo_update_access_api(req) data = res.body begin r = JSON::parse(data) if r.has_key?('result') return r['result'] else raise YoUpdateError, "Error from Yo API: #{data}" end rescue JSON::ParserError raise YoUpdateError, "Error from Yo API: #{data}" end end unless defined? yo_update_conf_label # maybe defined in a language resource def yo_update_conf_label 'Send Yo with updates' end end unless defined? yo_update_test_result_label # maybe defined in a language resource def yo_update_test_result_label(username, result) "- Sent to #{h username} and got #{h result}" end end unless defined? yo_update_conf_html # maybe defined in a language resource def yo_update_conf_html(conf, n_subscribers, test_result) action_label = { 'send_on_update' => 'when an entry is added', 'send_on_comment' => 'when a comment is posted', } <<-HTML

      API key

      Username

      Send Yo

        #{%w(send_on_update send_on_comment).map{|action| checked = conf["yo_update.#{action}"] ? ' checked' : '' %Q|
      • | }.join("\n\t")}

      Test sending Yo! to with optional link #{test_result}

      Current Subscribers

      #{h n_subscribers}

      Yo button

      Add the following to somewhere or your diary.

      <div id="yo-button"></div>

      Howto

      1. Sign in with your personal Yo account at http://dev.justyo.co/
      2. Follow the instructions to obtain new API account. Please leave the Callback URL blank.
      3. Copy the API key and API username above.
      HTML end end add_conf_proc('yo_update', yo_update_conf_label) do test_result = '' if @mode == 'saveconf' then @conf['yo_update.api_key'] = @cgi.params['yo_update.api_key'][0] @conf['yo_update.username'] = @cgi.params['yo_update.username'][0] @conf['yo_update.send_on_update'] = (@cgi.params['yo_update.send_on_update'][0] == 't') @conf['yo_update.send_on_comment'] = (@cgi.params['yo_update.send_on_comment'][0] == 't') test_username = @cgi.params['yo_update.test'][0] test_link = @cgi.params['yo_update.link'][0] if test_username and not test_username.empty? begin result = yo_update_send_yo(test_username, test_link) rescue YoUpdateError => e result = e.message end test_result = yo_update_test_result_label(test_username, result) end end unless @conf.has_key?('yo_update.send_on_update') @conf['yo_update.send_on_update'] = true end begin n_subscribers = yo_update_subscribers_count rescue YoUpdateError => e n_subscribers = e.message end yo_update_conf_html(@conf, n_subscribers, test_result) end add_update_proc do if @mode == 'append' and @conf['yo_update.send_on_update'] url = yo_update_url(@date) # link to the date yo_update_send_yo_or_log(nil, url) elsif @mode == 'comment' and @comment and @comment.visible? and @conf['yo_update.send_on_comment'] frag = "c%02d" % @diaries[@date.strftime("%Y%m%d")].count_comments(true) url = yo_update_url(@date, frag) yo_update_send_yo_or_log(nil, url) end end add_header_proc do if @conf['yo_update.api_key'] triggers = [] triggers << 'Entry' if @conf['yo_update.send_on_update'] triggers << 'Tsukkomi' if @conf['yo_update.send_on_comment'] trigger_str = "#{triggers.join(' or ')} is added" <<-HTML HTML end end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 sw=3 tdiary-contrib-5.0.8/plugin/youtube.rb000066400000000000000000000016221325711763500200100ustar00rootroot00000000000000# # youtube.rb: YouTube plugin for tDiary # # Copyright (C) 2010 by TADA Tadashi # # usage: <%= youtube 'VIDEO_ID' %> # def youtube( video_id, size = [425,350] ) if feed? %Q|| else <<-TAG
      TAG end end def youtube_custom( video_id, size = [416,337] ) <<-TAG
      TAG end tdiary-contrib-5.0.8/plugin/yshop.rb000066400000000000000000000140671325711763500174650ustar00rootroot00000000000000# yshop.rb $Revision: 3 $ # Copyright (C) 2008 Michitaka Ohno # You can redistribute it and/or modify it under GPL2. # ja/yshop.rb @yshop_label_conf ='Yahoo!ショッピング' @yshop_label_appid = 'アプリケーションID' @yshop_label_affiliate_type = 'アフィリエイトの種類' @yshop_label_yid = 'Yahoo! JAPANアフィリエイト' @yshop_label_vc = 'バリューコマースアフィリエイト' @yshop_label_affiliate_id = 'アフィリエイトID' @yshop_label_imgsize = '表示するイメージのサイズ' @yshop_label_medium = '普通' @yshop_label_small = '小さい' @yshop_label_clearcache = 'キャッシュの削除' @yshop_label_clearcache_desc = 'イメージ関連情報のキャッシュを削除する(Yahoo!ショッピング上の表示と矛盾がある場合に試して下さい)' require 'rexml/document' require 'open-uri' require 'kconv' eval( <<-TOPLEVEL_CLASS, TOPLEVEL_BINDING ) require 'erb' include ERB::Util TOPLEVEL_CLASS def yshop_get( param, store ) if Hash === param then param = param.dup elsif /^(\d{8}|\d{13})$/ === param then param = {:jan => $1} else param = {:query => param.to_s} end param[:store_id] = store if store cache = "#{@cache_path}/yshop" Dir::mkdir( cache ) unless File::directory?( cache ) file = "#{cache}/#{u( param.to_s )}.xml" begin xml = File::read( file ) rescue qs = [] qs << 'appid='+u( @conf['yshop.appid']||'YahooDemo' ) qs << 'affiliate_type='+u( @conf['yshop.affiliate_type'] ) if @conf['yshop.affiliate_type'] qs << 'affiliate_id='+u( @conf['yshop.affiliate_id'] ) if @conf['yshop.affiliate_id'] [:query, :jan, :isbn, :store_id].each do |item| qs << "#{item}="+u( param[item].toutf8 ) if param.include?( item ) end qs << 'hits=1' xml = open( 'http://shopping.yahooapis.jp/ShoppingWebService/V1/itemSearch?'+(qs*'&') ){|f| f.read} open( file, 'wb' ) {|f| f.write( xml )} if xml end REXML::Document.new( xml ).root if xml end def yshop_get_image( doc ) img = Struct.new( :size, :src, :width, :height ).new if @conf['yshop.imgsize'] == 1 then img.size = 'Small' img.width = img.height = 76 else img.size = 'Medium' img.width = img.height = 146 end begin img.src = doc.elements["Result/Hit/Image/#{img.size}"].text rescue img.src = "http://i.yimg.jp/images/sh/noimage/#{img.width}x#{img.height}.gif" end img end def yshop_get_brands( doc ) begin @conf.to_native( doc.elements['Result/Hit/Brands/Name'].text ) rescue '-' end end def yshop_get_price( doc ) begin r = doc.elements['Result/Hit/Price'].text nil while r.gsub!(/(.*\d)(\d\d\d)/, '\1,\2') "\\"+r rescue '(no price)' end end def yshop_get_shop( doc ) begin @conf.to_native( doc.elements['Result/Hit/Store/Name'].text ) rescue '-' end end def yshop_get_html( param, store, pos ) doc = yshop_get( param, store ) return unless doc && doc.attributes['totalResultsReturned'].to_i > 0 name = @conf.to_native( doc.elements["Result/Hit/Name"].text ) link = doc.elements["Result/Hit/Url"].text img = yshop_get_image( doc ) r = %Q[] r << %Q[#{h( name )}] if img.src r << h( name ) r << %Q[] end def yshop_image( param, store = nil ) yshop_get_html( param, store, 'amazon' ) end def yshop_image_left( param, store = nil ) yshop_get_html( param, store, 'left' ) end def yshop_image_right( param, store = nil ) yshop_get_html( param, store, 'right' ) end def yshop_detail( param, store = nil ) doc = yshop_get( param, store ) return unless doc && doc.attributes['totalResultsReturned'].to_i > 0 name = @conf.to_native( doc.elements["Result/Hit/Name"].text ) link = doc.elements["Result/Hit/Url"].text img = yshop_get_image( doc ) brands = yshop_get_brands( doc ) price = yshop_get_price( doc ) shop = yshop_get_shop( doc ) <<-HTML #{h( name )} #{h( name )}
      #{h( brands )}
      #{h( shop )}
      #{h( price )}
      HTML end add_conf_proc( 'yshop', @yshop_label_conf ) do yshop_conf_proc end def yshop_conf_proc if @mode == 'saveconf' then @conf['yshop.imgsize'] = @cgi.params['yshop.imgsize'][0].to_i if @cgi.params['yshop.clearcache'][0] == 'true' then Dir["#{@cache_path}/yshop/*"].each do |cache| File::delete( cache.untaint ) end end if @cgi.params['yshop.appid'][0].empty? then @conf['yshop.appid'] = nil else @conf['yshop.appid'] = @cgi.params['yshop.appid'][0] end if @cgi.params['yshop.affiliate_id'][0].empty? then @conf['yshop.affiliate_type'] = nil @conf['yshop.affiliate_id'] = nil else @conf['yshop.affiliate_type'] = @cgi.params['yshop.affiliate_type'][0] @conf['yshop.affiliate_id'] = @cgi.params['yshop.affiliate_id'][0] end end <<-HTML

      #{@yshop_label_appid}

      #{@yshop_label_affiliate_type}

      #{@yshop_label_affiliate_id}

      #{@yshop_label_imgsize}

      #{@yshop_label_clearcache}

      HTML end tdiary-contrib-5.0.8/plugin/zenback.rb000066400000000000000000000020421325711763500177260ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2011, KADO Masanori # You can redistribute it and/or modify it under GPL. def insert_zenback return if feed? @conf['zenback.script'] || '' end if @mode == 'day' and (respond_to?(:section_mode?) ? section_mode? : true) add_title_proc do |date, title| "#{title}" end add_body_enter_proc do "" end if defined? add_comment_leave_proc add_comment_leave_proc do "" + insert_zenback end else add_body_leave_proc do "" + insert_zenback end end end add_conf_proc( 'zenback', 'zenback', 'etc' ) do if @mode == 'saveconf' then @conf['zenback.script'] = @cgi.params['zenback.script'][0] end <<-HTML

      Script Code

      HTML end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/spec/000077500000000000000000000000001325711763500154225ustar00rootroot00000000000000tdiary-contrib-5.0.8/spec/apple_webclip_spec.rb000066400000000000000000000017571325711763500216010ustar00rootroot00000000000000$:.unshift(File.dirname(__FILE__)) require 'spec_helper' describe "apple_webclip plugin" do def setup_apple_webclip_plugin( url ) fake_plugin(:apple_webclip) { |plugin| plugin.conf['apple_webclip.url'] = url } end describe "url is enabled" do before do plugin = setup_apple_webclip_plugin('http://example.com/example.png') @header_snippet = plugin.header_proc end it "header include url" do expect(@header_snippet).to eq(%Q|\t|) end end describe "url is disabled" do describe "url is empty" do before do plugin = setup_apple_webclip_plugin('') @header_snippet = plugin.header_proc end it "header is empty" do expect(@header_snippet).to be_empty end end describe "url is nil" do before do plugin = setup_apple_webclip_plugin(nil) @header_snippet = plugin.header_proc end it "header is empty" do expect(@header_snippet).to be_empty end end end end tdiary-contrib-5.0.8/spec/fixtures/000077500000000000000000000000001325711763500172735ustar00rootroot00000000000000tdiary-contrib-5.0.8/spec/fixtures/flickr/000077500000000000000000000000001325711763500205455ustar00rootroot00000000000000tdiary-contrib-5.0.8/spec/fixtures/flickr/5950109223.flickr.photos.getInfo.xml000066400000000000000000000021231325711763500265260ustar00rootroot00000000000000 RubyKaigi 2011 0 rubykaigi https://www.flickr.com/photos/machu/5950109223/ tdiary-contrib-5.0.8/spec/fixtures/flickr/5950109223.flickr.photos.getSizes.xml000066400000000000000000000036071325711763500267400ustar00rootroot00000000000000 tdiary-contrib-5.0.8/spec/fixtures/github.json000066400000000000000000000007671325711763500214620ustar00rootroot00000000000000{"type":"User","login":"schacon","public_repos":150,"public_gists":80,"followers":5328,"html_url":"https://github.com/schacon","created_at":"2008-01-27T17:19:28Z","blog":"http://scottchacon.com","company":"GitHub","email":"schacon@gmail.com","avatar_url":"https://avatars.githubusercontent.com/u/70?v=3","hireable":false,"following":19,"name":"Scott Chacon","bio":null,"id":70,"location":"San Francisco, CA","url":"https://api.github.com/users/schacon","gravatar_id":"9375a9529679f1b42b567a640d775e7d"} tdiary-contrib-5.0.8/spec/fixtures/gravatar.json000066400000000000000000000014151325711763500217760ustar00rootroot00000000000000{"entry":[{"id":"7329339","hash":"3b3be63a4c2a439b013787725dfce802","requestHash":"3b3be63a4c2a439b013787725dfce802","profileUrl":"http:\/\/gravatar.com\/tdiary","preferredUsername":"tdiary","thumbnailUrl":"http:\/\/2.gravatar.com\/avatar\/3b3be63a4c2a439b013787725dfce802","photos":[{"value":"http:\/\/2.gravatar.com\/avatar\/3b3be63a4c2a439b013787725dfce802","type":"thumbnail"},{"value":"http:\/\/2.gravatar.com\/userimage\/7329339\/3b3be63a4c2a439b013787725dfce802"}],"profileBackground":{"color":"#e78736"},"name":{"givenName":"diary","familyName":"t","formatted":"tDiary"},"displayName":"tDiary","aboutMe":"The tDiary system","currentLocation":"JAPAN","emails":[{"primary":"true","value":"iHaveAn@email.com"}],"urls":[{"value":"http:\/\/www.tdiary.org","title":"tDiary"}]}]} tdiary-contrib-5.0.8/spec/fixtures/my_hotentry/000077500000000000000000000000001325711763500216545ustar00rootroot00000000000000tdiary-contrib-5.0.8/spec/fixtures/my_hotentry/entrylist-empty.xml000066400000000000000000000016731325711763500255760ustar00rootroot00000000000000 はてなブックマーク - 新着エントリー - empty-url.example.com http://b.hatena.ne.jp/entrylist?sort=eid&threshold=3&url=http%3A%2F%2Fempty-url.example.com empty-url.example.com の新着エントリー tdiary-contrib-5.0.8/spec/fixtures/my_hotentry/entrylist.xml000066400000000000000000003010421325711763500244330ustar00rootroot00000000000000 はてなブックマーク - 新着エントリー - 『ブログなら「はてなダイアリー」 - 写真・画像・動...』 http://b.hatena.ne.jp/entrylist?sort=eid&threshold=3&url=http%3A%2F%2Fd.hatena.ne.jp%2F 『ブログなら「はてなダイアリー」 - 写真・画像・動...』 の新着エントリー 【踊ってみた?】マジLOVE2000%【涼宮あつき】 100万再生達成 - An Empty Box >> pikayan’s Diary http://d.hatena.ne.jp/pikayan/20150103/p1 ニコニコ考察, ニコニコ紹介ニコニコ動画での現存するミリオン達成動画が合計2020作へ。削除込みで2182作。 【ニコニコ動画】【踊ってみた?】マジLOVE2000%【涼宮あつき】 31日13時1分頃、総合再生回数100万回突破。涼宮あつきさんによるブレイクダンス。“同一うp主さんで2作品ミリオン達成”270人目。同楽曲でのミリオン達成は、中毒になる動画(sm20526080)、Ver.クプラ(s... <blockquote cite="http://d.hatena.ne.jp/pikayan/20150103/p1" title="【踊ってみた?】マジLOVE2000%【涼宮あつき】 100万再生達成 - An Empty Box &gt;&gt; pikayan’s Diary"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Fpikayan%2F" alt="" /> <a href="http://d.hatena.ne.jp/pikayan/20150103/p1">【踊ってみた?】マジLOVE2000%【涼宮あつき】 100万再生達成 - An Empty Box &gt;&gt; pikayan’s Diary</a></cite><p>ニコニコ考察, ニコニコ紹介ニコニコ動画での現存するミリオン達成動画が合計2020作へ。削除込みで2182作。 【ニコニコ動画】【踊ってみた?】マジLOVE2000%【涼宮あつき】 31日13時1分頃、総合再生回数100万回突破。涼宮あつきさんによるブレイクダンス。“同一うp主さんで2作品ミリオン達成”270人目。同楽曲でのミリオン達成は、中毒になる動画(sm20526080)、Ver.クプラ(s...</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/pikayan/20150103/p1"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/pikayan/20150103/p1" alt="はてなブックマーク - 【踊ってみた?】マジLOVE2000%【涼宮あつき】 100万再生達成 - An Empty Box &gt;&gt; pikayan’s Diary" title="はてなブックマーク - 【踊ってみた?】マジLOVE2000%【涼宮あつき】 100万再生達成 - An Empty Box &gt;&gt; pikayan’s Diary" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/pikayan/20150103/p1"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T16:19:05+09:00 アニメとゲーム 1 成田山へ - がりぼんさんどこ行くの? http://d.hatena.ne.jp/garibon33/20150104/1420335640 10:40ども!読者のみなさんは、初詣とかって毎年行くところを決めてる?もしくは、何か所も行ったりする??がりぼんはさ、近くに大きな 成田山 というお寺があるの。もちろん近所の神社にも行くけど、成田さんにもわりと行くかな?今年は雪で階段が危ないからって、父さんとおっかさんは節分に行くって言ってたな。近くには国宝の 犬山城 もあって、近所の人だけじゃなく、わざわざ車で遠くから観光がてら来る人もいるみ... <blockquote cite="http://d.hatena.ne.jp/garibon33/20150104/1420335640" title="成田山へ - がりぼんさんどこ行くの?"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Fgaribon33%2F" alt="" /> <a href="http://d.hatena.ne.jp/garibon33/20150104/1420335640">成田山へ - がりぼんさんどこ行くの?</a></cite><p><a href="http://d.hatena.ne.jp/garibon33/20150104/1420335640"><img src="http://cdn-ak.b.st-hatena.com/entryimage/238072375-1420355148.jpg" alt="成田山へ - がりぼんさんどこ行くの?" title="成田山へ - がりぼんさんどこ行くの?" class="entry-image" /></a></p><p>10:40ども!読者のみなさんは、初詣とかって毎年行くところを決めてる?もしくは、何か所も行ったりする??がりぼんはさ、近くに大きな 成田山 というお寺があるの。もちろん近所の神社にも行くけど、成田さんにもわりと行くかな?今年は雪で階段が危ないからって、父さんとおっかさんは節分に行くって言ってたな。近くには国宝の 犬山城 もあって、近所の人だけじゃなく、わざわざ車で遠くから観光がてら来る人もいるみ...</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/garibon33/20150104/1420335640"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/garibon33/20150104/1420335640" alt="はてなブックマーク - 成田山へ - がりぼんさんどこ行くの?" title="はてなブックマーク - 成田山へ - がりぼんさんどこ行くの?" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/garibon33/20150104/1420335640"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T16:05:17+09:00 暮らし 1 慰安婦問題、ピンチをチャンスに変えよう! - ジェンダーとメディア・ブログ http://d.hatena.ne.jp/discour/20140922/p1 朝日新聞が8月5日「慰安婦問題を考える」特集で、過去の吉田清治証言に基づく記事を取消して以降のメディアの朝日新聞叩きは異常である。産経新聞は、ずっと慰安婦問題で論陣を張ってきているからまあそうだろうと思うが、これまで慰安婦問題にそう熱心でなかった新聞や週刊誌、月刊誌などあらゆるメディアが総出で朝日新聞の記事取消騒動に乗じて、朝日新聞が記事を取り消したゆえに、「慰安婦問題は捏造」だったという言説をま... <blockquote cite="http://d.hatena.ne.jp/discour/20140922/p1" title="慰安婦問題、ピンチをチャンスに変えよう! - ジェンダーとメディア・ブログ"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Fdiscour%2F" alt="" /> <a href="http://d.hatena.ne.jp/discour/20140922/p1">慰安婦問題、ピンチをチャンスに変えよう! - ジェンダーとメディア・ブログ</a></cite><p>朝日新聞が8月5日「慰安婦問題を考える」特集で、過去の吉田清治証言に基づく記事を取消して以降のメディアの朝日新聞叩きは異常である。産経新聞は、ずっと慰安婦問題で論陣を張ってきているからまあそうだろうと思うが、これまで慰安婦問題にそう熱心でなかった新聞や週刊誌、月刊誌などあらゆるメディアが総出で朝日新聞の記事取消騒動に乗じて、朝日新聞が記事を取り消したゆえに、「慰安婦問題は捏造」だったという言説をま...</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/discour/20140922/p1"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/discour/20140922/p1" alt="はてなブックマーク - 慰安婦問題、ピンチをチャンスに変えよう! - ジェンダーとメディア・ブログ" title="はてなブックマーク - 慰安婦問題、ピンチをチャンスに変えよう! - ジェンダーとメディア・ブログ" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/discour/20140922/p1"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T15:57:56+09:00 世の中 1 サザンオールスターズ「東京VICTORY」雑感 - TAKUYAONLINE http://d.hatena.ne.jp/takuya/20150104/1420352110 音楽サザンオールスターズの「東京VICTORY」っていう曲を最初に聴いたとき、すごく驚いて、いくらなんでも滅茶苦茶だろうって思った。時を駆けるよ Time goes round 変わりゆく My hometown 彗星(ほし)が流れるように 夢の未来へ Space goes round 友よ Forever young みんな頑張って それ行け Get the chance!!どこに驚いたかってい... <blockquote cite="http://d.hatena.ne.jp/takuya/20150104/1420352110" title="サザンオールスターズ「東京VICTORY」雑感 - TAKUYAONLINE"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Ftakuya%2F" alt="" /> <a href="http://d.hatena.ne.jp/takuya/20150104/1420352110">サザンオールスターズ「東京VICTORY」雑感 - TAKUYAONLINE</a></cite><p>音楽サザンオールスターズの「東京VICTORY」っていう曲を最初に聴いたとき、すごく驚いて、いくらなんでも滅茶苦茶だろうって思った。時を駆けるよ Time goes round 変わりゆく My hometown 彗星(ほし)が流れるように 夢の未来へ Space goes round 友よ Forever young みんな頑張って それ行け Get the chance!!どこに驚いたかってい...</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/takuya/20150104/1420352110"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/takuya/20150104/1420352110" alt="はてなブックマーク - サザンオールスターズ「東京VICTORY」雑感 - TAKUYAONLINE" title="はてなブックマーク - サザンオールスターズ「東京VICTORY」雑感 - TAKUYAONLINE" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/takuya/20150104/1420352110"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T15:20:21+09:00 エンタメ 2 2014年の映画 124本 - OnFire http://d.hatena.ne.jp/biwacovic/20150104/1420336076 (内訳)洋画新作 61洋画旧作 24邦画新作 18邦画旧作 21費用合計 134200円(平均1082.3円/1本)時間合計 13236分(平均106.7分/1本)幌馬車キートン・サイレント集フェイシズチャイニーズ・ブッキーを殺した男恋するミナミ危険な関係アイドル・イズ・デッド ノンちゃんのプロパガンダ大戦争ドラッグ・ウォー 毒戦・ふ・た・り・ぼ・っ・ち・ビフォア・ミッドナイトMUDポール・ヴァー... <blockquote cite="http://d.hatena.ne.jp/biwacovic/20150104/1420336076" title="2014年の映画 124本 - OnFire"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Fbiwacovic%2F" alt="" /> <a href="http://d.hatena.ne.jp/biwacovic/20150104/1420336076">2014年の映画 124本 - OnFire</a></cite><p>(内訳)洋画新作 61洋画旧作 24邦画新作 18邦画旧作 21費用合計 134200円(平均1082.3円/1本)時間合計 13236分(平均106.7分/1本)幌馬車キートン・サイレント集フェイシズチャイニーズ・ブッキーを殺した男恋するミナミ危険な関係アイドル・イズ・デッド ノンちゃんのプロパガンダ大戦争ドラッグ・ウォー 毒戦・ふ・た・り・ぼ・っ・ち・ビフォア・ミッドナイトMUDポール・ヴァー...</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/biwacovic/20150104/1420336076"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/biwacovic/20150104/1420336076" alt="はてなブックマーク - 2014年の映画 124本 - OnFire" title="はてなブックマーク - 2014年の映画 124本 - OnFire" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/biwacovic/20150104/1420336076"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T15:17:56+09:00 エンタメ 1 篠田魔孤と久保田創二 - mmpoloの日記 http://d.hatena.ne.jp/mmpolo/20150104/1420334496 昨年が没後50年だった無名の画家篠田魔孤については以前ここで紹介したことがある。・伝説の画家・篠田魔孤を誰も知らない(2007年1月7日) 上に掲載したような優れた絵を描いていながら無名のまま亡くなった。作品は散逸し、もうほとんど魔孤さんのことも絵のことも知る人がいなくなった。そういう私も生前の魔孤さんに会ったことはないし、作品も図版でしか見たことがない。その魔孤さんが亡くなったのが1964年11... <blockquote cite="http://d.hatena.ne.jp/mmpolo/20150104/1420334496" title="篠田魔孤と久保田創二 - mmpoloの日記"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Fmmpolo%2F" alt="" /> <a href="http://d.hatena.ne.jp/mmpolo/20150104/1420334496">篠田魔孤と久保田創二 - mmpoloの日記</a></cite><p><a href="http://d.hatena.ne.jp/mmpolo/20150104/1420334496"><img src="http://cdn-ak.b.st-hatena.com/entryimage/238068427-1420352225.jpg" alt="篠田魔孤と久保田創二 - mmpoloの日記" title="篠田魔孤と久保田創二 - mmpoloの日記" class="entry-image" /></a></p><p>昨年が没後50年だった無名の画家篠田魔孤については以前ここで紹介したことがある。・伝説の画家・篠田魔孤を誰も知らない(2007年1月7日) 上に掲載したような優れた絵を描いていながら無名のまま亡くなった。作品は散逸し、もうほとんど魔孤さんのことも絵のことも知る人がいなくなった。そういう私も生前の魔孤さんに会ったことはないし、作品も図版でしか見たことがない。その魔孤さんが亡くなったのが1964年11...</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/mmpolo/20150104/1420334496"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/mmpolo/20150104/1420334496" alt="はてなブックマーク - 篠田魔孤と久保田創二 - mmpoloの日記" title="はてなブックマーク - 篠田魔孤と久保田創二 - mmpoloの日記" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/mmpolo/20150104/1420334496"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T15:16:34+09:00 暮らし 1 ガンダムの神様現れる - 自閉症児 渡の宝箱 http://d.hatena.ne.jp/kuboyumi/20141228/1420026753 さて、今朝は前から子供達が楽しみにしていた東京スカイツリー。朝4時からおきて準備する子供達。我が家は朝が早いのです。朝からがっつり和食をいただきました。食べ放題って素敵。さて今日の目指すは東京スカイツリー。朝8時からだと待ち時間ゼロで登れました。東京の街を見て、楽しみました。これおかしいと思ったのは、全国のキティちゃん。なんで大阪が、たこ焼きで、松山が俳句なんだよ!大阪がたこ焼きだったら、松山はみ... <blockquote cite="http://d.hatena.ne.jp/kuboyumi/20141228/1420026753" title="ガンダムの神様現れる - 自閉症児 渡の宝箱"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Fkuboyumi%2F" alt="" /> <a href="http://d.hatena.ne.jp/kuboyumi/20141228/1420026753">ガンダムの神様現れる - 自閉症児 渡の宝箱</a></cite><p><a href="http://d.hatena.ne.jp/kuboyumi/20141228/1420026753"><img src="http://cdn-ak.b.st-hatena.com/entryimage/238067863-1420351238.jpg" alt="ガンダムの神様現れる - 自閉症児 渡の宝箱" title="ガンダムの神様現れる - 自閉症児 渡の宝箱" class="entry-image" /></a></p><p>さて、今朝は前から子供達が楽しみにしていた東京スカイツリー。朝4時からおきて準備する子供達。我が家は朝が早いのです。朝からがっつり和食をいただきました。食べ放題って素敵。さて今日の目指すは東京スカイツリー。朝8時からだと待ち時間ゼロで登れました。東京の街を見て、楽しみました。これおかしいと思ったのは、全国のキティちゃん。なんで大阪が、たこ焼きで、松山が俳句なんだよ!大阪がたこ焼きだったら、松山はみ...</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/kuboyumi/20141228/1420026753"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/kuboyumi/20141228/1420026753" alt="はてなブックマーク - ガンダムの神様現れる - 自閉症児 渡の宝箱" title="はてなブックマーク - ガンダムの神様現れる - 自閉症児 渡の宝箱" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/kuboyumi/20141228/1420026753"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T15:00:07+09:00 暮らし 1 Myo がやっと届きました!! - 強火で進め http://d.hatena.ne.jp/nakamura001/20141204/1417693695 Myo はこんな事や、こんな事ができます。Unity で作られた MyoとOculus Riftを使ったデモ - 強火で進めhttp://d.hatena.ne.jp/nakamura001/20140319/1395254765その Myo がやっと届きました。ちなみに注文した日付を確認した所、 2013/02/26 06:15 でした。最初は2013年の年末に届くって話だったんですけねorz1... <blockquote cite="http://d.hatena.ne.jp/nakamura001/20141204/1417693695" title="Myo がやっと届きました!! - 強火で進め"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Fnakamura001%2F" alt="" /> <a href="http://d.hatena.ne.jp/nakamura001/20141204/1417693695">Myo がやっと届きました!! - 強火で進め</a></cite><p><a href="http://d.hatena.ne.jp/nakamura001/20141204/1417693695"><img src="http://cdn-ak.b.st-hatena.com/entryimage/238067851-1420351211.jpg" alt="Myo がやっと届きました!! - 強火で進め" title="Myo がやっと届きました!! - 強火で進め" class="entry-image" /></a></p><p>Myo はこんな事や、こんな事ができます。Unity で作られた MyoとOculus Riftを使ったデモ - 強火で進めhttp://d.hatena.ne.jp/nakamura001/20140319/1395254765その Myo がやっと届きました。ちなみに注文した日付を確認した所、 2013/02/26 06:15 でした。最初は2013年の年末に届くって話だったんですけねorz1...</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/nakamura001/20141204/1417693695"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/nakamura001/20141204/1417693695" alt="はてなブックマーク - Myo がやっと届きました!! - 強火で進め" title="はてなブックマーク - Myo がやっと届きました!! - 強火で進め" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/nakamura001/20141204/1417693695"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T14:59:48+09:00 テクノロジー 1 まんだらけが千葉県佐原にとんでもないビルを作っている模様w - 東洋黒客は勇者である http://d.hatena.ne.jp/thk/20150103 年始年末はコミケの同人誌(中古)を漁りに秋葉原に繰り出している東洋黒客です、こんばんわ。年始年末は秋葉原の店舗も営業時間が不安定のため、各オタショップのサイトをチェックして営業時間を調べていたのですがまんだらけのページにとんでもない情報が載ってました。http://www.mandarake.co.jp/ え・・・なにこれ・・・ドン引き・・・。20世紀少年かよwww しかも、もうできあがりつつある... <blockquote cite="http://d.hatena.ne.jp/thk/20150103" title="まんだらけが千葉県佐原にとんでもないビルを作っている模様w - 東洋黒客は勇者である"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Fthk%2F" alt="" /> <a href="http://d.hatena.ne.jp/thk/20150103">まんだらけが千葉県佐原にとんでもないビルを作っている模様w - 東洋黒客は勇者である</a></cite><p><a href="http://d.hatena.ne.jp/thk/20150103"><img src="http://cdn-ak.b.st-hatena.com/entryimage/238067748-1420350733.jpg" alt="まんだらけが千葉県佐原にとんでもないビルを作っている模様w - 東洋黒客は勇者である" title="まんだらけが千葉県佐原にとんでもないビルを作っている模様w - 東洋黒客は勇者である" class="entry-image" /></a></p><p>年始年末はコミケの同人誌(中古)を漁りに秋葉原に繰り出している東洋黒客です、こんばんわ。年始年末は秋葉原の店舗も営業時間が不安定のため、各オタショップのサイトをチェックして営業時間を調べていたのですがまんだらけのページにとんでもない情報が載ってました。http://www.mandarake.co.jp/ え・・・なにこれ・・・ドン引き・・・。20世紀少年かよwww しかも、もうできあがりつつある...</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/thk/20150103"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/thk/20150103" alt="はてなブックマーク - まんだらけが千葉県佐原にとんでもないビルを作っている模様w - 東洋黒客は勇者である" title="はてなブックマーク - まんだらけが千葉県佐原にとんでもないビルを作っている模様w - 東洋黒客は勇者である" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/thk/20150103"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T14:51:48+09:00 世の中 1 ストライクウィッチーズ Operation Victory Arrow vol.1 サン・トロンの雷鳴 [DVD] - はてなキーワード http://d.hatena.ne.jp/asin/B00NNKBUF8 お得情報Amazonマーケットプレイス ¥ 3,446 よりKADOKAWA / 角川書店 - DVD - 2014/12/12 ¥ 3,676(定価 ¥ 4,968)26%OFF <blockquote cite="http://d.hatena.ne.jp/asin/B00NNKBUF8" title="ストライクウィッチーズ Operation Victory Arrow vol.1 サン・トロンの雷鳴 [DVD] - はてなキーワード"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2F" alt="" /> <a href="http://d.hatena.ne.jp/asin/B00NNKBUF8">ストライクウィッチーズ Operation Victory Arrow vol.1 サン・トロンの雷鳴 [DVD] - はてなキーワード</a></cite><p><a href="http://d.hatena.ne.jp/asin/B00NNKBUF8"><img onerror="Hatena.Bookmark.Video.rescueThumbnail(this);" src="http://ecx.images-amazon.com/images/I/41UFa79qZ8L._SL75_.jpg" alt="ストライクウィッチーズ Operation Victory Arrow vol.1 サン・トロンの雷鳴 [DVD]" title="ストライクウィッチーズ Operation Victory Arrow vol.1 サン・トロンの雷鳴 [DVD]" class="asin" /></a></p><p>お得情報Amazonマーケットプレイス ¥ 3,446 よりKADOKAWA / 角川書店 - DVD - 2014/12/12 ¥ 3,676(定価 ¥ 4,968)26%OFF</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/asin/B00NNKBUF8"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/asin/B00NNKBUF8" alt="はてなブックマーク - ストライクウィッチーズ Operation Victory Arrow vol.1 サン・トロンの雷鳴 [DVD] - はてなキーワード" title="はてなブックマーク - ストライクウィッチーズ Operation Victory Arrow vol.1 サン・トロンの雷鳴 [DVD] - はてなキーワード" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/asin/B00NNKBUF8"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T14:45:08+09:00 テクノロジー 1 撒き餌レンズの隠された機能大公開! - 亀猫のチャリカメ成長記! http://d.hatena.ne.jp/kame-neko/20111123/p1 -カメラ-GXR+A12 50mmF2.5一万円出せばおつりがくる純正レンズ、それがEF50mmF1.8II。びっくりするほど安いが、画質は(絞れば)凄い。通称は「撒き餌」。安いからといって手を出すと満足してしまい、より高いレンズを買ってしまうキヤノンの商法である。さてそんなレンズの弱点だが、質感が値段相応だと言うことだ。もちろん映りに関係することではないのだが、その安っぽさが尋常ではない。特にM... <blockquote cite="http://d.hatena.ne.jp/kame-neko/20111123/p1" title="撒き餌レンズの隠された機能大公開! - 亀猫のチャリカメ成長記!"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Fkame-neko%2F" alt="" /> <a href="http://d.hatena.ne.jp/kame-neko/20111123/p1">撒き餌レンズの隠された機能大公開! - 亀猫のチャリカメ成長記!</a></cite><p><a href="http://d.hatena.ne.jp/kame-neko/20111123/p1"><img src="http://cdn-ak.b.st-hatena.com/entryimage/238067566-1420349858.jpg" alt="撒き餌レンズの隠された機能大公開! - 亀猫のチャリカメ成長記!" title="撒き餌レンズの隠された機能大公開! - 亀猫のチャリカメ成長記!" class="entry-image" /></a></p><p>-カメラ-GXR+A12 50mmF2.5一万円出せばおつりがくる純正レンズ、それがEF50mmF1.8II。びっくりするほど安いが、画質は(絞れば)凄い。通称は「撒き餌」。安いからといって手を出すと満足してしまい、より高いレンズを買ってしまうキヤノンの商法である。さてそんなレンズの弱点だが、質感が値段相応だと言うことだ。もちろん映りに関係することではないのだが、その安っぽさが尋常ではない。特にM...</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/kame-neko/20111123/p1"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/kame-neko/20111123/p1" alt="はてなブックマーク - 撒き餌レンズの隠された機能大公開! - 亀猫のチャリカメ成長記!" title="はてなブックマーク - 撒き餌レンズの隠された機能大公開! - 亀猫のチャリカメ成長記!" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/kame-neko/20111123/p1"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T14:37:07+09:00 テクノロジー 1 フランソワーズ・アルディ - 不連続な読書日記 http://d.hatena.ne.jp/orion-n/20150103 今年の初買いは、篠綾子さんの『幻の神器』。定家が探偵役をつとめる平安京ミステリー、「藤原定家・謎合秘帖」シリーズの第一弾。胸が躍る。 その翌日、なんの脈絡もなくフランソワーズ・アルディの『私小説』と『夜のフランソワーズ』を購入した。 『私小説』は1973年の作品。二十歳をすぎた頃、毎日くりかえし聴きこんだ。『夜のフランソワーズ』はたぶん初聴だと思うが、とても懐かしい。 フランソワーズ・アルディが憧... <blockquote cite="http://d.hatena.ne.jp/orion-n/20150103" title="フランソワーズ・アルディ - 不連続な読書日記"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Forion-n%2F" alt="" /> <a href="http://d.hatena.ne.jp/orion-n/20150103">フランソワーズ・アルディ - 不連続な読書日記</a></cite><p>今年の初買いは、篠綾子さんの『幻の神器』。定家が探偵役をつとめる平安京ミステリー、「藤原定家・謎合秘帖」シリーズの第一弾。胸が躍る。 その翌日、なんの脈絡もなくフランソワーズ・アルディの『私小説』と『夜のフランソワーズ』を購入した。 『私小説』は1973年の作品。二十歳をすぎた頃、毎日くりかえし聴きこんだ。『夜のフランソワーズ』はたぶん初聴だと思うが、とても懐かしい。 フランソワーズ・アルディが憧...</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/orion-n/20150103"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/orion-n/20150103" alt="はてなブックマーク - フランソワーズ・アルディ - 不連続な読書日記" title="はてなブックマーク - フランソワーズ・アルディ - 不連続な読書日記" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/orion-n/20150103"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T14:10:19+09:00 エンタメ 1 2013-02-12 - 弁護士ラベンダー読書日記 http://d.hatena.ne.jp/la-law/20130212#p2 文体は好み。系統でいえば朝吹真理子だと思いました。そして中勘助(中勘助みたいというのが、私の最上の褒め言葉です)。文体が美しいのに、その美しい文体で表現する対象が美しいものばかりでなく人間の醜さもあるってところが、ますます中勘助っぽい(「銀の匙」じゃなくて「犬」や「でーぱだった」の路線の中勘助ね)。そして、文体が美しいのに、表現の対象は美しさそのものではなくて、美しいものが失われていくさま、失われ... <blockquote cite="http://d.hatena.ne.jp/la-law/20130212#p2" title="2013-02-12 - 弁護士ラベンダー読書日記"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Fla-law%2F" alt="" /> <a href="http://d.hatena.ne.jp/la-law/20130212#p2">2013-02-12 - 弁護士ラベンダー読書日記</a></cite><p>文体は好み。系統でいえば朝吹真理子だと思いました。そして中勘助(中勘助みたいというのが、私の最上の褒め言葉です)。文体が美しいのに、その美しい文体で表現する対象が美しいものばかりでなく人間の醜さもあるってところが、ますます中勘助っぽい(「銀の匙」じゃなくて「犬」や「でーぱだった」の路線の中勘助ね)。そして、文体が美しいのに、表現の対象は美しさそのものではなくて、美しいものが失われていくさま、失われ...</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/la-law/20130212%23p2"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/la-law/20130212%23p2" alt="はてなブックマーク - 2013-02-12 - 弁護士ラベンダー読書日記" title="はてなブックマーク - 2013-02-12 - 弁護士ラベンダー読書日記" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/la-law/20130212%23p2"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T14:09:33+09:00 暮らし 1 筑波大学附属図書館貴重書コレクション - LABYRINTHUS IMAGINATIONIS http://d.hatena.ne.jp/theseus/20141209/p1 国内でも、西洋の数学や哲学の貴重書が電子化されているものがありますが、筑波大学はなかなか充実していると思われたので紹介。筑波大学附属図書館から、次のところに入ります。貴重書コレクション(電子化リスト)下の方までスクロールすると、分野別に貴重書が分かれています。たとえば、ステヴィンの著作がありました。ほかにも、スホーテン版デカルト『幾何学』(1659)や、ヨハン・ベルヌーイ全集(1742)などがあり... <blockquote cite="http://d.hatena.ne.jp/theseus/20141209/p1" title="筑波大学附属図書館貴重書コレクション - LABYRINTHUS IMAGINATIONIS"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Ftheseus%2F" alt="" /> <a href="http://d.hatena.ne.jp/theseus/20141209/p1">筑波大学附属図書館貴重書コレクション - LABYRINTHUS IMAGINATIONIS</a></cite><p>国内でも、西洋の数学や哲学の貴重書が電子化されているものがありますが、筑波大学はなかなか充実していると思われたので紹介。筑波大学附属図書館から、次のところに入ります。貴重書コレクション(電子化リスト)下の方までスクロールすると、分野別に貴重書が分かれています。たとえば、ステヴィンの著作がありました。ほかにも、スホーテン版デカルト『幾何学』(1659)や、ヨハン・ベルヌーイ全集(1742)などがあり...</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/theseus/20141209/p1"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/theseus/20141209/p1" alt="はてなブックマーク - 筑波大学附属図書館貴重書コレクション - LABYRINTHUS IMAGINATIONIS" title="はてなブックマーク - 筑波大学附属図書館貴重書コレクション - LABYRINTHUS IMAGINATIONIS" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/theseus/20141209/p1"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T14:07:49+09:00 学び 1 【読書感想】abさんご - 琥珀色の戯言 http://d.hatena.ne.jp/fujipon/20130218 abさんご作者: 黒田夏子出版社/メーカー: 文藝春秋発売日: 2013/01メディア: ハードカバー購入: 9人 クリック: 912回この商品を含むブログ (36件) を見るabさんご作者: 黒田夏子出版社/メーカー: 文藝春秋発売日: 2013/02/09メディア: Kindle版購入: 4人 クリック: 171回この商品を含むブログ (3件) を見る内容紹介史上最高齢・75歳で芥川賞を受賞し... <blockquote cite="http://d.hatena.ne.jp/fujipon/20130218" title="【読書感想】abさんご - 琥珀色の戯言"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Ffujipon%2F" alt="" /> <a href="http://d.hatena.ne.jp/fujipon/20130218">【読書感想】abさんご - 琥珀色の戯言</a></cite><p>abさんご作者: 黒田夏子出版社/メーカー: 文藝春秋発売日: 2013/01メディア: ハードカバー購入: 9人 クリック: 912回この商品を含むブログ (36件) を見るabさんご作者: 黒田夏子出版社/メーカー: 文藝春秋発売日: 2013/02/09メディア: Kindle版購入: 4人 クリック: 171回この商品を含むブログ (3件) を見る内容紹介史上最高齢・75歳で芥川賞を受賞し...</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/fujipon/20130218"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/fujipon/20130218" alt="はてなブックマーク - 【読書感想】abさんご - 琥珀色の戯言" title="はてなブックマーク - 【読書感想】abさんご - 琥珀色の戯言" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/fujipon/20130218"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T14:05:15+09:00 暮らし 1 ふしぎなせかい「abさんご」 - 静寂(しじま)を待ちながら http://d.hatena.ne.jp/CultureNight/20130327/1364459444 日記, art149回芥川賞受賞作品「abさんご」がえらい問題作だった。 abさんご作者: 黒田夏子出版社/メーカー: 文藝春秋発売日: 2013/01メディア: ハードカバー購入: 9人 クリック: 912回この商品を含むブログ (36件) を見る ミーハー魂全開で読み始めたが、こんなに読中と読後で印象が違う小説は過去にない。 特徴は何といっても独特の文体だ。 横書きだし、固有名詞がほとんどない... <blockquote cite="http://d.hatena.ne.jp/CultureNight/20130327/1364459444" title="ふしぎなせかい「abさんご」 - 静寂(しじま)を待ちながら"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2FCultureNight%2F" alt="" /> <a href="http://d.hatena.ne.jp/CultureNight/20130327/1364459444">ふしぎなせかい「abさんご」 - 静寂(しじま)を待ちながら</a></cite><p><a href="http://d.hatena.ne.jp/CultureNight/20130327/1364459444"><img src="http://cdn-ak.b.st-hatena.com/entryimage/238063648-1420347866.jpg" alt="ふしぎなせかい「abさんご」 - 静寂(しじま)を待ちながら" title="ふしぎなせかい「abさんご」 - 静寂(しじま)を待ちながら" class="entry-image" /></a></p><p>日記, art149回芥川賞受賞作品「abさんご」がえらい問題作だった。 abさんご作者: 黒田夏子出版社/メーカー: 文藝春秋発売日: 2013/01メディア: ハードカバー購入: 9人 クリック: 912回この商品を含むブログ (36件) を見る ミーハー魂全開で読み始めたが、こんなに読中と読後で印象が違う小説は過去にない。 特徴は何といっても独特の文体だ。 横書きだし、固有名詞がほとんどない...</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/CultureNight/20130327/1364459444"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/CultureNight/20130327/1364459444" alt="はてなブックマーク - ふしぎなせかい「abさんご」 - 静寂(しじま)を待ちながら" title="はてなブックマーク - ふしぎなせかい「abさんご」 - 静寂(しじま)を待ちながら" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/CultureNight/20130327/1364459444"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T14:04:17+09:00 暮らし 1 『a b さんご』 - firecats & dogs http://d.hatena.ne.jp/firecat/20130407 abさんご作者: 黒田夏子出版社/メーカー: 文藝春秋発売日: 2013/01メディア: ハードカバー購入: 9人 クリック: 912回この商品を含むブログ (36件) を見る話題作を読んでみた。以下、感想。ひらがなの多用は読み違いを誘うところがあり、てにをはもちょっと変わっている。昨今はあまり用いられないのではと思われる言葉も使用されるし、造語ではないかと考えさせられる言葉もある。受身形が多用さ... <blockquote cite="http://d.hatena.ne.jp/firecat/20130407" title="『a b さんご』 - firecats &amp; dogs"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Ffirecat%2F" alt="" /> <a href="http://d.hatena.ne.jp/firecat/20130407">『a b さんご』 - firecats &amp; dogs</a></cite><p>abさんご作者: 黒田夏子出版社/メーカー: 文藝春秋発売日: 2013/01メディア: ハードカバー購入: 9人 クリック: 912回この商品を含むブログ (36件) を見る話題作を読んでみた。以下、感想。ひらがなの多用は読み違いを誘うところがあり、てにをはもちょっと変わっている。昨今はあまり用いられないのではと思われる言葉も使用されるし、造語ではないかと考えさせられる言葉もある。受身形が多用さ...</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/firecat/20130407"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/firecat/20130407" alt="はてなブックマーク - 『a b さんご』 - firecats &amp; dogs" title="はてなブックマーク - 『a b さんご』 - firecats &amp; dogs" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/firecat/20130407"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T14:01:23+09:00 暮らし 1 『abさんご』──後半「楽屋」が見えてくるのが惜しい(笑) - 山下晴代の「積ん読亭日常」 http://d.hatena.ne.jp/palaceatene/20130529/1369761390 『abさんご』(黒田夏子著、2013年1月、文藝春秋刊) 私は本作を読んで、すぐは、「紫式部日記」のような日本語の清逸な世界を感じさせて、なかなかよいと思った。まず、導入部など、唐突なはじまりがよいし、a地点からb地点という、説明のない抽象性は、言葉そのものの手触りを感じさせて、さすが、蓮實重彦の選んだ作だと思った。まず、蓮實氏は、「日本語を私に教えてくれる作品、どきどきさせてくれるものを望む」と... <blockquote cite="http://d.hatena.ne.jp/palaceatene/20130529/1369761390" title="『abさんご』──後半「楽屋」が見えてくるのが惜しい(笑) - 山下晴代の「積ん読亭日常」"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Fpalaceatene%2F" alt="" /> <a href="http://d.hatena.ne.jp/palaceatene/20130529/1369761390">『abさんご』──後半「楽屋」が見えてくるのが惜しい(笑) - 山下晴代の「積ん読亭日常」</a></cite><p><a href="http://d.hatena.ne.jp/palaceatene/20130529/1369761390"><img src="http://cdn-ak.b.st-hatena.com/entryimage/238063574-1420347487.jpg" alt="『abさんご』──後半「楽屋」が見えてくるのが惜しい(笑) - 山下晴代の「積ん読亭日常」" title="『abさんご』──後半「楽屋」が見えてくるのが惜しい(笑) - 山下晴代の「積ん読亭日常」" class="entry-image" /></a></p><p>『abさんご』(黒田夏子著、2013年1月、文藝春秋刊) 私は本作を読んで、すぐは、「紫式部日記」のような日本語の清逸な世界を感じさせて、なかなかよいと思った。まず、導入部など、唐突なはじまりがよいし、a地点からb地点という、説明のない抽象性は、言葉そのものの手触りを感じさせて、さすが、蓮實重彦の選んだ作だと思った。まず、蓮實氏は、「日本語を私に教えてくれる作品、どきどきさせてくれるものを望む」と...</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/palaceatene/20130529/1369761390"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/palaceatene/20130529/1369761390" alt="はてなブックマーク - 『abさんご』──後半「楽屋」が見えてくるのが惜しい(笑) - 山下晴代の「積ん読亭日常」" title="はてなブックマーク - 『abさんご』──後半「楽屋」が見えてくるのが惜しい(笑) - 山下晴代の「積ん読亭日常」" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/palaceatene/20130529/1369761390"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T13:57:52+09:00 エンタメ 1 「炊き出しに公園が使えないなら私有地を使えばいいじゃない」 - 法華狼の日記 http://d.hatena.ne.jp/hokke-ookami/20150103/1420344848 年末から年始にかけて渋谷区の公園が閉鎖され、ホームレスへの炊き出し活動がおこななくなったという報道があった。東京・渋谷区:宮下公園など3日まで閉鎖 ホームレス締め出し - 毎日新聞 それに対するid:kyoumoe氏のブログエントリを見ていて、よくわからなくなった。まず12月30日づけのエントリ。ホームレスを利用して政治的主張をしたがる人々 - 今日も得る物なしZそれはそれとして俺が疑問に思ってい... <blockquote cite="http://d.hatena.ne.jp/hokke-ookami/20150103/1420344848" title="「炊き出しに公園が使えないなら私有地を使えばいいじゃない」 - 法華狼の日記"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Fhokke-ookami%2F" alt="" /> <a href="http://d.hatena.ne.jp/hokke-ookami/20150103/1420344848">「炊き出しに公園が使えないなら私有地を使えばいいじゃない」 - 法華狼の日記</a></cite><p>年末から年始にかけて渋谷区の公園が閉鎖され、ホームレスへの炊き出し活動がおこななくなったという報道があった。東京・渋谷区:宮下公園など3日まで閉鎖 ホームレス締め出し - 毎日新聞 それに対するid:kyoumoe氏のブログエントリを見ていて、よくわからなくなった。まず12月30日づけのエントリ。ホームレスを利用して政治的主張をしたがる人々 - 今日も得る物なしZそれはそれとして俺が疑問に思ってい...</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/hokke-ookami/20150103/1420344848"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/hokke-ookami/20150103/1420344848" alt="はてなブックマーク - 「炊き出しに公園が使えないなら私有地を使えばいいじゃない」 - 法華狼の日記" title="はてなブックマーク - 「炊き出しに公園が使えないなら私有地を使えばいいじゃない」 - 法華狼の日記" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/hokke-ookami/20150103/1420344848"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T13:50:12+09:00 世の中 2 [design] - I Get Around The Media 楠見清のメディア回游 http://d.hatena.ne.jp/donburaco/searchdiary?word=*%5Bdesign%5D book, designこれからのデザインに必要なことは何だろうと考えていたら「共用品」という言葉に行き当たった。子どもも大人も高齢者も障害者も身体的な特性にかかわりなく、多くの人がともに利用しやすいもの。英語ではアクセシブル・デザイン(使いやすい設計)と呼ばれバリア・フリーやユニバーサル・デザインを包括する考え方として広まってきている。デザイン・プロダクトのアクセシビリティーについて考えるための... <blockquote cite="http://d.hatena.ne.jp/donburaco/searchdiary?word=*%5Bdesign%5D" title="[design] - I Get Around The Media 楠見清のメディア回游"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Fdonburaco%2F" alt="" /> <a href="http://d.hatena.ne.jp/donburaco/searchdiary?word=*%5Bdesign%5D">[design] - I Get Around The Media 楠見清のメディア回游</a></cite><p><a href="http://d.hatena.ne.jp/donburaco/searchdiary?word=*%5Bdesign%5D"><img src="http://cdn-ak.b.st-hatena.com/entryimage/238063171-1420346942.jpg" alt="[design] - I Get Around The Media 楠見清のメディア回游" title="[design] - I Get Around The Media 楠見清のメディア回游" class="entry-image" /></a></p><p>book, designこれからのデザインに必要なことは何だろうと考えていたら「共用品」という言葉に行き当たった。子どもも大人も高齢者も障害者も身体的な特性にかかわりなく、多くの人がともに利用しやすいもの。英語ではアクセシブル・デザイン(使いやすい設計)と呼ばれバリア・フリーやユニバーサル・デザインを包括する考え方として広まってきている。デザイン・プロダクトのアクセシビリティーについて考えるための...</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/donburaco/searchdiary?word=*%5Bdesign%5D"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/donburaco/searchdiary?word=*%5Bdesign%5D" alt="はてなブックマーク - [design] - I Get Around The Media 楠見清のメディア回游" title="はてなブックマーク - [design] - I Get Around The Media 楠見清のメディア回游" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/donburaco/searchdiary?word=*%5Bdesign%5D"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T13:46:55+09:00 暮らし 1 プロジェクション・ネックレス - Campaign_Otaku http://d.hatena.ne.jp/y_sequi/20150101/1420056207 Technology女性へのプレゼントとしてアクセサリーは定番だけど、近い将来、それは"モノ"ではなく"プロジェクション"になるかも知れない。panGeneratorが開発中の"Neclumi"は女性の首元にネックレスをプロジェクションするという趣向。現在は"picoprojector"でプロジェクションし、iPhone Appでネックレスの形状や動きを選択する形式。単なるプロジェクションなら人の... <blockquote cite="http://d.hatena.ne.jp/y_sequi/20150101/1420056207" title="プロジェクション・ネックレス - Campaign_Otaku"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Fy_sequi%2F" alt="" /> <a href="http://d.hatena.ne.jp/y_sequi/20150101/1420056207">プロジェクション・ネックレス - Campaign_Otaku</a></cite><p><a href="http://d.hatena.ne.jp/y_sequi/20150101/1420056207"><img src="http://cdn-ak.b.st-hatena.com/entryimage/238062817-1420346253.jpg" alt="プロジェクション・ネックレス - Campaign_Otaku" title="プロジェクション・ネックレス - Campaign_Otaku" class="entry-image" /></a></p><p>Technology女性へのプレゼントとしてアクセサリーは定番だけど、近い将来、それは&quot;モノ&quot;ではなく&quot;プロジェクション&quot;になるかも知れない。panGeneratorが開発中の&quot;Neclumi&quot;は女性の首元にネックレスをプロジェクションするという趣向。現在は&quot;picoprojector&quot;でプロジェクションし、iPhone Appでネックレスの形状や動きを選択する形式。単なるプロジェクションなら人の...</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/y_sequi/20150101/1420056207"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/y_sequi/20150101/1420056207" alt="はてなブックマーク - プロジェクション・ネックレス - Campaign_Otaku" title="はてなブックマーク - プロジェクション・ネックレス - Campaign_Otaku" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/y_sequi/20150101/1420056207"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T13:37:13+09:00 学び 1 赤い星、青い星、暗い星 - カガクのじかん http://d.hatena.ne.jp/inyoko/20150101/stars_red_blue_and_dark 【管理人より】私が勤務する塾の高3生向けの記事です。もちろん他の方にも理解していただけるように書きますが、ある程度は「物理」の知識が必要かもしれません。 受験生の皆さん、受験前の忙しい時期にアクセスありがとうございます。日頃からあまりしゃべるのが上手でなく、伝え切れていないことがあるように思っているので、このような記事を書こうと思いました。  最新の「コムタス通信*1」は見てくれましたか?センター... <blockquote cite="http://d.hatena.ne.jp/inyoko/20150101/stars_red_blue_and_dark" title="赤い星、青い星、暗い星 - カガクのじかん"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Finyoko%2F" alt="" /> <a href="http://d.hatena.ne.jp/inyoko/20150101/stars_red_blue_and_dark">赤い星、青い星、暗い星 - カガクのじかん</a></cite><p><a href="http://d.hatena.ne.jp/inyoko/20150101/stars_red_blue_and_dark"><img src="http://cdn-ak.b.st-hatena.com/entryimage/238059242-1420345147.jpg" alt="赤い星、青い星、暗い星 - カガクのじかん" title="赤い星、青い星、暗い星 - カガクのじかん" class="entry-image" /></a></p><p>【管理人より】私が勤務する塾の高3生向けの記事です。もちろん他の方にも理解していただけるように書きますが、ある程度は「物理」の知識が必要かもしれません。 受験生の皆さん、受験前の忙しい時期にアクセスありがとうございます。日頃からあまりしゃべるのが上手でなく、伝え切れていないことがあるように思っているので、このような記事を書こうと思いました。  最新の「コムタス通信*1」は見てくれましたか?センター...</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/inyoko/20150101/stars_red_blue_and_dark"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/inyoko/20150101/stars_red_blue_and_dark" alt="はてなブックマーク - 赤い星、青い星、暗い星 - カガクのじかん" title="はてなブックマーク - 赤い星、青い星、暗い星 - カガクのじかん" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/inyoko/20150101/stars_red_blue_and_dark"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T13:18:42+09:00 学び 1 福岡空港に第2滑走路が増設される件について - ” Wer Y sagt, muss auch Z sagen. ”で行こう http://d.hatena.ne.jp/kagura-may/20150104/p1 かつての啓徳空港@香港・九龍もかくやと言うくらい、住宅街の真ん中に鎮座する福岡空港。一時は海側に全く新規の空港を新設という話があったけど、結局、現滑走路とターミナルの間の空間に新滑走路を押し込むことに正式決定。ユーザーからすると使い勝手が変わらないんでありがたいけど、住民からすると、騒音も危険性も現状の2倍になるんだよな。少し複雑気分。  それはそれとして、今回の記事で気になったのは次の下り。 空... <blockquote cite="http://d.hatena.ne.jp/kagura-may/20150104/p1" title="福岡空港に第2滑走路が増設される件について - ” Wer Y sagt, muss auch Z sagen. ”で行こう"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Fkagura-may%2F" alt="" /> <a href="http://d.hatena.ne.jp/kagura-may/20150104/p1">福岡空港に第2滑走路が増設される件について - ” Wer Y sagt, muss auch Z sagen. ”で行こう</a></cite><p><a href="http://d.hatena.ne.jp/kagura-may/20150104/p1"><img src="http://cdn-ak.b.st-hatena.com/entryimage/238059078-1420344573.jpg" alt="福岡空港に第2滑走路が増設される件について - ” Wer Y sagt, muss auch Z sagen. ”で行こう" title="福岡空港に第2滑走路が増設される件について - ” Wer Y sagt, muss auch Z sagen. ”で行こう" class="entry-image" /></a></p><p>かつての啓徳空港@香港・九龍もかくやと言うくらい、住宅街の真ん中に鎮座する福岡空港。一時は海側に全く新規の空港を新設という話があったけど、結局、現滑走路とターミナルの間の空間に新滑走路を押し込むことに正式決定。ユーザーからすると使い勝手が変わらないんでありがたいけど、住民からすると、騒音も危険性も現状の2倍になるんだよな。少し複雑気分。  それはそれとして、今回の記事で気になったのは次の下り。 空...</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/kagura-may/20150104/p1"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/kagura-may/20150104/p1" alt="はてなブックマーク - 福岡空港に第2滑走路が増設される件について - ” Wer Y sagt, muss auch Z sagen. ”で行こう" title="はてなブックマーク - 福岡空港に第2滑走路が増設される件について - ” Wer Y sagt, muss auch Z sagen. ”で行こう" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/kagura-may/20150104/p1"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T13:09:17+09:00 世の中 1 2015-01-04 - お気に入り商品の紹介 http://d.hatena.ne.jp/neme_asuka/20150104#1420344031 13:00 | @titagun: ダイエット・健康等、の商品を割引価格、特別価格で取り扱っています。 URL こちらのサイトも運営していますので、どうぞ。 URL URL2015-01-04 08:16:48 via twittbot.net@titagun: 今までの常識をくつがえすスイングで 「飛んで曲がらない」ボールを実現します。 URL2015-01-03 23:06:20 via tw... <blockquote cite="http://d.hatena.ne.jp/neme_asuka/20150104#1420344031" title="2015-01-04 - お気に入り商品の紹介"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Fneme_asuka%2F" alt="" /> <a href="http://d.hatena.ne.jp/neme_asuka/20150104#1420344031">2015-01-04 - お気に入り商品の紹介</a></cite><p>13:00 | @titagun: ダイエット・健康等、の商品を割引価格、特別価格で取り扱っています。 URL こちらのサイトも運営していますので、どうぞ。 URL URL2015-01-04 08:16:48 via twittbot.net@titagun: 今までの常識をくつがえすスイングで 「飛んで曲がらない」ボールを実現します。 URL2015-01-03 23:06:20 via tw...</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/neme_asuka/20150104%231420344031"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/neme_asuka/20150104%231420344031" alt="はてなブックマーク - 2015-01-04 - お気に入り商品の紹介" title="はてなブックマーク - 2015-01-04 - お気に入り商品の紹介" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/neme_asuka/20150104%231420344031"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T13:04:17+09:00 テクノロジー 1 もうこれからずっとこの国はこの一言でいいんじゃないかな、というフレーズを思いついた。 - こころ世代のテンノーゲーム http://d.hatena.ne.jp/umeten/20141227/p1 「要は、お金がないんでしょ?貧乏人は非国民。」 非国民奥崎謙三は訴える!!!―「ゆきゆきて神軍」の凱歌posted with amazlet at 14.12.27奥崎 謙三 新泉社 売り上げランキング: 657,764 Amazon.co.jpで詳細を見るツイートする <blockquote cite="http://d.hatena.ne.jp/umeten/20141227/p1" title="もうこれからずっとこの国はこの一言でいいんじゃないかな、というフレーズを思いついた。 - こころ世代のテンノーゲーム"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Fumeten%2F" alt="" /> <a href="http://d.hatena.ne.jp/umeten/20141227/p1">もうこれからずっとこの国はこの一言でいいんじゃないかな、というフレーズを思いついた。 - こころ世代のテンノーゲーム</a></cite><p>「要は、お金がないんでしょ?貧乏人は非国民。」 非国民奥崎謙三は訴える!!!―「ゆきゆきて神軍」の凱歌posted with amazlet at 14.12.27奥崎 謙三 新泉社 売り上げランキング: 657,764 Amazon.co.jpで詳細を見るツイートする</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/umeten/20141227/p1"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/umeten/20141227/p1" alt="はてなブックマーク - もうこれからずっとこの国はこの一言でいいんじゃないかな、というフレーズを思いついた。 - こころ世代のテンノーゲーム" title="はてなブックマーク - もうこれからずっとこの国はこの一言でいいんじゃないかな、というフレーズを思いついた。 - こころ世代のテンノーゲーム" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/umeten/20141227/p1"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T12:54:56+09:00 世の中 1 「Web業界からEC業界に行ってブチ当たった、皆が教えてくれない「EC業界の見えない壁」の正体を、もやっと掴めました!」を読んで(次回ミーティングのために)整理してみました - リア http://d.hatena.ne.jp/ryuka01/20150104/1420341384 年明けで様々な記事を読んでいたところ、以下の記事を発見しました。Web業界からEC業界に行ってブチ当たった、皆が教えてくれない「EC業界の見えない壁」の正体を、もやっと掴めました!ECサイトの運営に携わっている方にはぜひ読んでいただきたい内容です。 記事を書かれている永上さんは、以前の会社が一緒だったこと、そして過去にブログで取り上げていただいたこと(参考:「えがちゃん」に取材をしていただきました... <blockquote cite="http://d.hatena.ne.jp/ryuka01/20150104/1420341384" title="「Web業界からEC業界に行ってブチ当たった、皆が教えてくれない「EC業界の見えない壁」の正体を、もやっと掴めました!」を読んで(次回ミーティングのために)整理してみました - リア"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Fryuka01%2F" alt="" /> <a href="http://d.hatena.ne.jp/ryuka01/20150104/1420341384">「Web業界からEC業界に行ってブチ当たった、皆が教えてくれない「EC業界の見えない壁」の正体を、もやっと掴めました!」を読んで(次回ミーティングのために)整理してみました - リア</a></cite><p><a href="http://d.hatena.ne.jp/ryuka01/20150104/1420341384"><img src="http://cdn-ak.b.st-hatena.com/entryimage/238058800-1420343719.jpg" alt="「Web業界からEC業界に行ってブチ当たった、皆が教えてくれない「EC業界の見えない壁」の正体を、もやっと掴めました!」を読んで(次回ミーティングのために)整理してみました - リア" title="「Web業界からEC業界に行ってブチ当たった、皆が教えてくれない「EC業界の見えない壁」の正体を、もやっと掴めました!」を読んで(次回ミーティングのために)整理してみました - リア" class="entry-image" /></a></p><p>年明けで様々な記事を読んでいたところ、以下の記事を発見しました。Web業界からEC業界に行ってブチ当たった、皆が教えてくれない「EC業界の見えない壁」の正体を、もやっと掴めました!ECサイトの運営に携わっている方にはぜひ読んでいただきたい内容です。 記事を書かれている永上さんは、以前の会社が一緒だったこと、そして過去にブログで取り上げていただいたこと(参考:「えがちゃん」に取材をしていただきました...</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/ryuka01/20150104/1420341384"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/ryuka01/20150104/1420341384" alt="はてなブックマーク - 「Web業界からEC業界に行ってブチ当たった、皆が教えてくれない「EC業界の見えない壁」の正体を、もやっと掴めました!」を読んで(次回ミーティングのために)整理してみました - リア" title="はてなブックマーク - 「Web業界からEC業界に行ってブチ当たった、皆が教えてくれない「EC業界の見えない壁」の正体を、もやっと掴めました!」を読んで(次回ミーティングのために)整理してみました - リア" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/ryuka01/20150104/1420341384"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T12:54:56+09:00 テクノロジー 38 2014-12-15 - 空中キャンプ http://d.hatena.ne.jp/zoot32/20141215#p1 これが最終の回答です。どの方もユニークな内容で、とてもおもしろいです。ランキングがすべてじゃないなと、あらためて思います。参加いただいた方ありがとうございました。TMC 男性@tmc_stmFORMA サッドティー 円卓 こっこ、ひと夏のイマジンブラッド・ピット.繰り返し見たい/誰かと見たい作品でまとめました。tomtom 男性@ss_wasshoiレゴ・ムービー ゴジラ イコライザーイコライザー... <blockquote cite="http://d.hatena.ne.jp/zoot32/20141215#p1" title="2014-12-15 - 空中キャンプ"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Fzoot32%2F" alt="" /> <a href="http://d.hatena.ne.jp/zoot32/20141215#p1">2014-12-15 - 空中キャンプ</a></cite><p><a href="http://d.hatena.ne.jp/zoot32/20141215#p1"><img src="http://cdn-ak.b.st-hatena.com/entryimage/238058776-1420343560.jpg" alt="2014-12-15 - 空中キャンプ" title="2014-12-15 - 空中キャンプ" class="entry-image" /></a></p><p>これが最終の回答です。どの方もユニークな内容で、とてもおもしろいです。ランキングがすべてじゃないなと、あらためて思います。参加いただいた方ありがとうございました。TMC 男性@tmc_stmFORMA サッドティー 円卓 こっこ、ひと夏のイマジンブラッド・ピット.繰り返し見たい/誰かと見たい作品でまとめました。tomtom 男性@ss_wasshoiレゴ・ムービー ゴジラ イコライザーイコライザー...</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/zoot32/20141215%23p1"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/zoot32/20141215%23p1" alt="はてなブックマーク - 2014-12-15 - 空中キャンプ" title="はてなブックマーク - 2014-12-15 - 空中キャンプ" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/zoot32/20141215%23p1"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T12:52:20+09:00 エンタメ 1 POCO C++ライブラリがスゴイ. - なぜか数学者にはワイン好きが多い http://d.hatena.ne.jp/tullio/20090430 非常にシンプルま味ですが,黒胡椒がピリッときて良い感じです.ホントにシンプルで,原材料名は「ブラックペッパー」「食塩」「糖類(砂糖,オリゴ糖)」「チキンエキスパウダー(乳を含む)」「オニオンパウダー」「ガーリックパウダー」等です.確かに表面に,ブラックペッパーらしき黒い香辛料が見えます. <blockquote cite="http://d.hatena.ne.jp/tullio/20090430" title="POCO C++ライブラリがスゴイ. - なぜか数学者にはワイン好きが多い"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Ftullio%2F" alt="" /> <a href="http://d.hatena.ne.jp/tullio/20090430">POCO C++ライブラリがスゴイ. - なぜか数学者にはワイン好きが多い</a></cite><p><a href="http://d.hatena.ne.jp/tullio/20090430"><img src="http://cdn-ak.b.st-hatena.com/entryimage/238058657-1420343026.jpg" alt="POCO C++ライブラリがスゴイ. - なぜか数学者にはワイン好きが多い" title="POCO C++ライブラリがスゴイ. - なぜか数学者にはワイン好きが多い" class="entry-image" /></a></p><p>非常にシンプルま味ですが,黒胡椒がピリッときて良い感じです.ホントにシンプルで,原材料名は「ブラックペッパー」「食塩」「糖類(砂糖,オリゴ糖)」「チキンエキスパウダー(乳を含む)」「オニオンパウダー」「ガーリックパウダー」等です.確かに表面に,ブラックペッパーらしき黒い香辛料が見えます.</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/tullio/20090430"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/tullio/20090430" alt="はてなブックマーク - POCO C++ライブラリがスゴイ. - なぜか数学者にはワイン好きが多い" title="はてなブックマーク - POCO C++ライブラリがスゴイ. - なぜか数学者にはワイン好きが多い" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/tullio/20090430"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T12:43:31+09:00 暮らし 1 5アンペア生活への挑戦 - hatehei666の日記 http://d.hatena.ne.jp/hatehei666/20141219/1418955637 11:20 「快楽を愛する者は貧しい人となり、ぶどう酒や油を愛する者は富むことがない」(箴言21:17)。 『5アンペア生活をやってみた』(斉藤健一郎著)を読みました。著者斉藤氏は現在40歳、朝日新聞の記者をやっており、以前そうした題のコラムを新聞に載せた事があります(*私も過去ログで触れました)。今度岩波ジュニア新書で項を新たにして出しました。 斉藤氏は2011年3月11日東日本大震災の時は郡山... <blockquote cite="http://d.hatena.ne.jp/hatehei666/20141219/1418955637" title="5アンペア生活への挑戦 - hatehei666の日記"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Fhatehei666%2F" alt="" /> <a href="http://d.hatena.ne.jp/hatehei666/20141219/1418955637">5アンペア生活への挑戦 - hatehei666の日記</a></cite><p><a href="http://d.hatena.ne.jp/hatehei666/20141219/1418955637"><img src="http://cdn-ak.b.st-hatena.com/entryimage/238058580-1420342732.jpg" alt="5アンペア生活への挑戦 - hatehei666の日記" title="5アンペア生活への挑戦 - hatehei666の日記" class="entry-image" /></a></p><p>11:20 「快楽を愛する者は貧しい人となり、ぶどう酒や油を愛する者は富むことがない」(箴言21:17)。 『5アンペア生活をやってみた』(斉藤健一郎著)を読みました。著者斉藤氏は現在40歳、朝日新聞の記者をやっており、以前そうした題のコラムを新聞に載せた事があります(*私も過去ログで触れました)。今度岩波ジュニア新書で項を新たにして出しました。 斉藤氏は2011年3月11日東日本大震災の時は郡山...</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/hatehei666/20141219/1418955637"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/hatehei666/20141219/1418955637" alt="はてなブックマーク - 5アンペア生活への挑戦 - hatehei666の日記" title="はてなブックマーク - 5アンペア生活への挑戦 - hatehei666の日記" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/hatehei666/20141219/1418955637"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T12:38:42+09:00 暮らし 1 国が年間被ばく線量設定基準20ミリシーベルト以下にした経緯等 - hatehei666の日記 http://d.hatena.ne.jp/hatehei666/20141223/1419300068 11:01 「しかし、あなたがたは偽りをでっちあげる者、あなたがたはみな、能なしの医者だ」(ヨブ13:4)。 日野行介著『福島原発事故 県民健康管理調査の闇』を読みました。福島県「県民健康管理調査」検討委員会が議論を秘密扱いし、事実を隠ぺいした経緯を、毎日新聞社所属の日野氏は徹底的に追及しています。これまで断片的な報道が幾つかありましたが、1冊の本に収まってみると、これまで目に見えなかったものが、... <blockquote cite="http://d.hatena.ne.jp/hatehei666/20141223/1419300068" title="国が年間被ばく線量設定基準20ミリシーベルト以下にした経緯等 - hatehei666の日記"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fd.hatena.ne.jp%2Fhatehei666%2F" alt="" /> <a href="http://d.hatena.ne.jp/hatehei666/20141223/1419300068">国が年間被ばく線量設定基準20ミリシーベルト以下にした経緯等 - hatehei666の日記</a></cite><p><a href="http://d.hatena.ne.jp/hatehei666/20141223/1419300068"><img src="http://cdn-ak.b.st-hatena.com/entryimage/238058362-1420342549.jpg" alt="国が年間被ばく線量設定基準20ミリシーベルト以下にした経緯等 - hatehei666の日記" title="国が年間被ばく線量設定基準20ミリシーベルト以下にした経緯等 - hatehei666の日記" class="entry-image" /></a></p><p>11:01 「しかし、あなたがたは偽りをでっちあげる者、あなたがたはみな、能なしの医者だ」(ヨブ13:4)。 日野行介著『福島原発事故 県民健康管理調査の闇』を読みました。福島県「県民健康管理調査」検討委員会が議論を秘密扱いし、事実を隠ぺいした経緯を、毎日新聞社所属の日野氏は徹底的に追及しています。これまで断片的な報道が幾つかありましたが、1冊の本に収まってみると、これまで目に見えなかったものが、...</p><p><a href="http://b.hatena.ne.jp/entry/http://d.hatena.ne.jp/hatehei666/20141223/1419300068"><img src="http://b.hatena.ne.jp/entry/image/http://d.hatena.ne.jp/hatehei666/20141223/1419300068" alt="はてなブックマーク - 国が年間被ばく線量設定基準20ミリシーベルト以下にした経緯等 - hatehei666の日記" title="はてなブックマーク - 国が年間被ばく線量設定基準20ミリシーベルト以下にした経緯等 - hatehei666の日記" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://d.hatena.ne.jp/hatehei666/20141223/1419300068"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote> 2015-01-04T12:35:37+09:00 世の中 1 tdiary-contrib-5.0.8/spec/fixtures/twitter.xml000066400000000000000000000065671325711763500215350ustar00rootroot00000000000000 65589541 tDiary.org tDiary tDiaryオフィシャルアカウント http://a0.twimg.com/profile_images/379668735/square_logo_normal.png https://si0.twimg.com/profile_images/379668735/square_logo_normal.png http://www.tdiary.org/ false 286 FFFFFF 333333 0084B4 D0FFD0 D0FFD0 261 Fri Aug 14 07:50:23 +0000 2009 3 32400 Tokyo http://a0.twimg.com/images/themes/theme1/bg.png https://si0.twimg.com/images/themes/theme1/bg.png false false false false 313 ja false 31 false false false Mon Sep 17 00:04:52 +0000 2012 247486242491604992 RT @hsbt: DefaultIO から RdbIO へのインポータできた #tdiary <a href="http://www.crowy.net/" rel="nofollow">Crowy</a> false false 2 false Mon Sep 17 00:01:16 +0000 2012 247485333179101185 DefaultIO から RdbIO へのインポータできた #tdiary <a href="http://mzp.github.com/atig/" rel="nofollow">atig.rb</a> false false 2 false tdiary-contrib-5.0.8/spec/flicker_spec.rb000066400000000000000000000020341325711763500203770ustar00rootroot00000000000000$:.unshift(File.dirname(__FILE__)) require 'spec_helper' describe "flickr plugin" do let(:plugin) { fake_plugin(:flickr) } before(:all) do stub_request(:get, "https://www.flickr.com/services/rest/?api_key=f7e7fb8cc34e52db3e5af5e1727d0c0b&method=flickr.photos.getInfo&photo_id=5950109223") .to_return(status: 200, body: File.new('spec/fixtures/flickr/5950109223.flickr.photos.getInfo.xml')) stub_request(:get, "https://www.flickr.com/services/rest/?api_key=f7e7fb8cc34e52db3e5af5e1727d0c0b&method=flickr.photos.getSizes&photo_id=5950109223") .to_return(status: 200, body: File.new('spec/fixtures/flickr/5950109223.flickr.photos.getSizes.xml')) end describe '#flickr' do subject { plugin.flickr('5950109223', size = nil) } it do expect(subject).to eq %Q|\"RubyKaigi| end end end tdiary-contrib-5.0.8/spec/gist_spec.rb000066400000000000000000000007611325711763500177330ustar00rootroot00000000000000$:.unshift(File.dirname(__FILE__)) require 'spec_helper' describe "gist plugin" do DUMMY_GIST_ID = 1234567890 it 'should render javascript tag with specified gist-id' do plugin = fake_plugin(:gist) snippet = plugin.gist(DUMMY_GIST_ID) expected = (<<-EOS).chomp EOS expect(snippet).to eq(expected) end end tdiary-contrib-5.0.8/spec/github_link_spec.rb000066400000000000000000000023451325711763500212640ustar00rootroot00000000000000$:.unshift(File.dirname(__FILE__)) require 'spec_helper' describe "github link plugin" do let(:plugin) { fake_plugin(:github_link) } subject { plugin.gh_link(*args) } describe 'repository page' do let(:args) { ['tdiary/tdiary-contrib'] } it 'should render repository a tag' do is_expected.to eq(%(tdiary-contrib)) end end describe 'issues page' do let(:args) { ['tdiary/tdiary-contrib#100'] } it 'should render issues a tag' do is_expected.to eq(%(tdiary-contrib#100)) end end context "When given altenative text" do let(:text) { 'This project' } let(:github_identifier) { 'tdiary/tdiary-contrib' } let(:args) { [github_identifier, text] } it 'should render repository a tag with the specified text' do is_expected.to eq(%(#{text})) end context "but the text is including ' } it 'should render a link text after sanitizing.' do is_expected.not_to eq(%(#{text})) end end end end tdiary-contrib-5.0.8/spec/google_analytics_spec.rb000066400000000000000000000027421325711763500223110ustar00rootroot00000000000000$:.unshift(File.dirname(__FILE__)) require 'spec_helper' describe "google_analytics plugin" do def setup_google_analytics_plugin(profile_id, mode) fake_plugin(:google_analytics) { |plugin| plugin.mode = mode plugin.conf['google_analytics.profile'] = profile_id } end describe "should render javascript" do before do @plugin = setup_google_analytics_plugin('53836-1', 'latest') end it "for footer" do snippet = @plugin.footer_proc expect(snippet).to eq(expected_html_footer_snippet) end end describe "should render javascript" do before do @plugin = setup_google_analytics_plugin('53836-1', 'conf') end it "for footer" do snippet = @plugin.footer_proc expect(snippet).to be_empty end end describe "should not render when profile_id is empty" do before do @plugin = setup_google_analytics_plugin(nil, 'latest') end it "for footer" do snippet = @plugin.footer_proc expect(snippet).to be_empty end end def expected_html_footer_snippet expected = <<-SCRIPT SCRIPT expected.gsub( /^\t/, '' ).chomp end end tdiary-contrib-5.0.8/spec/google_universal_analytics_spec.rb000066400000000000000000000030741325711763500244000ustar00rootroot00000000000000$:.unshift(File.dirname(__FILE__)) require 'spec_helper' describe "google_universal_analytics plugin" do def setup_google_universal_analytics_plugin(profile_id, mode) fake_plugin(:google_universal_analytics) { |plugin| plugin.mode = mode plugin.conf['google_universal_analytics.profile'] = profile_id } end describe "should render javascript" do before do @plugin = setup_google_universal_analytics_plugin('53836-1', 'latest') end it "for footer" do snippet = @plugin.footer_proc expect(snippet).to eq(expected_html_footer_snippet) end end describe "should render javascript" do before do @plugin = setup_google_universal_analytics_plugin('53836-1', 'conf') end it "for footer" do snippet = @plugin.footer_proc expect(snippet).to be_empty end end describe "should not render when profile_id is empty" do before do @plugin = setup_google_universal_analytics_plugin(nil, 'latest') end it "for footer" do snippet = @plugin.footer_proc expect(snippet).to be_empty end end def expected_html_footer_snippet expected = <<-SCRIPT SCRIPT expected.gsub( /^\t/, '' ).chomp end end tdiary-contrib-5.0.8/spec/jdate_spec.rb000066400000000000000000000007721325711763500200560ustar00rootroot00000000000000# -*- coding: utf-8 -*- $:.unshift(File.dirname(__FILE__)) require 'spec_helper' require 'time' describe "jdate plugin" do { '20080121' => '月', '20080122' => '火', '20080123' => '水', '20080124' => '木', '20080125' => '金', '20080126' => '土', '20080127' => '日', }.each do |k,v| it { expect(setup_jdate_plugin(Time.parse(k)).date.strftime('%J')).to eq(v) } end def setup_jdate_plugin(date) fake_plugin(:jdate) {|plugin| plugin.date = date} end end tdiary-contrib-5.0.8/spec/jmonth_spec.rb000066400000000000000000000012761325711763500202660ustar00rootroot00000000000000# -*- coding: utf-8 -*- $:.unshift(File.dirname(__FILE__)) require 'spec_helper' require 'time' describe "jmonth plugin" do { '2007/01/01' => '睦月', '2007/02/01' => '如月', '2007/03/01' => '弥生', '2007/04/01' => '卯月', '2007/05/01' => '皐月', '2007/06/01' => '水無月', '2007/07/01' => '文月', '2007/08/01' => '葉月', '2007/09/01' => '長月', '2007/10/01' => '神無月', '2007/11/01' => '霜月', '2007/12/01' => '師走' }.each do |k,v| it { expect(setup_jmonth_plugin(Time.parse(k)).date.strftime('%i')).to eq(v) } end def setup_jmonth_plugin(date) fake_plugin(:jmonth) { |plugin| plugin.date = date } end end tdiary-contrib-5.0.8/spec/jyear_spec.rb000066400000000000000000000007611325711763500200770ustar00rootroot00000000000000# -*- coding: utf-8 -*- $:.unshift(File.dirname(__FILE__)) require 'spec_helper' require 'time' describe "jyear plugin" do { '1925/01/01' => '昔々', '1926/12/25' => '昭和元年', '1927/01/01' => '昭和2', '1989/01/08' => '平成元年', '1990/01/01' => '平成2', }.each do |k,v| it { expect(setup_jyear_plugin(Time.parse(k)).date.strftime('%K')).to eq(v) } end def setup_jyear_plugin(date) fake_plugin(:jyear) { |plugin| plugin.date = date } end end tdiary-contrib-5.0.8/spec/my_hotentry_spec.rb000066400000000000000000000044151325711763500213460ustar00rootroot00000000000000# -*- coding: utf-8 -*- $:.unshift(File.dirname(__FILE__)) require 'spec_helper' require 'tmpdir' require 'fileutils' describe "MyHotEntry" do def cache_filename "#{File.basename(__FILE__, ".rb")}-#{$$}" end before(:each) do stub_request(:get, "http://b.hatena.ne.jp/entrylist?mode=rss&url=http%3A%2F%2Fd.hatena.ne.jp%2F&sort=eid&threshold=3") .to_return(status: 200, body: File.new('spec/fixtures/my_hotentry/entrylist.xml')) stub_request(:get, "http://b.hatena.ne.jp/entrylist?mode=rss&sort=eid&threshold=3&url=http://empty-url.example.com/") .to_return(status: 200, body: File.new('spec/fixtures/my_hotentry/entrylist-empty.xml')) fake_plugin(:my_hotentry) @cache_path = File.join(Dir.tmpdir, cache_filename) Dir.mkdir(@cache_path) @dbfile = "#{@cache_path}/my_hotentry.dat" @base_url = 'http://d.hatena.ne.jp/' @hotentry = MyHotEntry.new(@dbfile) end after(:each) do FileUtils.rmtree(@cache_path) end describe "#update" do before do @hotentry.update(@base_url) @entries = @hotentry.entries end it "キャッシュファイルが生成されていること" do expect(File).to be_file(@dbfile) end it "人気の日記が取得できていること" do expect(@entries.size).to be > 0 end it "取得したエントリにbase_urlとタイトルが含まれていること" do @entries.each do |entry| expect(entry[:url]).to be_include(@base_url) expect(entry[:title].size).to be > 0 end end end describe "何度もupdateした場合" do before do @hotentry.update(@base_url) @original_entry_size = @hotentry.entries.size @hotentry.update(@base_url) @entry_size = @hotentry.entries.size end it "キャッシュサイズが大きくならないこと" do expect(@entry_size).to eq(@original_entry_size) end end describe "取得結果が空の場合" do before do @exist_url = 'http://d.hatena.ne.jp/' @empty_url = 'http://empty-url.example.com/' end it "キャッシュをクリアしないこと" do @hotentry.update(@empty_url) expect(@hotentry.entries.size).to eq(0) @hotentry.update(@exist_url) expect(@hotentry.entries.size).to be > 0 exist_size = @hotentry.entries.size @hotentry.update(@empty_url) expect(@hotentry.entries.size).to eq(exist_size) end end end tdiary-contrib-5.0.8/spec/openid_spec.rb000066400000000000000000000155721325711763500202510ustar00rootroot00000000000000$:.unshift(File.dirname(__FILE__)) require 'spec_helper' describe "openid plugin w/" do def setup_open_id_plugin(service, userid) fake_plugin(:openid) { |plugin| plugin.mode = 'latest' plugin.conf['openid.service'] = service plugin.conf['openid.id'] = userid } end describe "Hatena" do before do plugin = setup_open_id_plugin('Hatena', 'tdtds') @header_snippet = plugin.header_proc end it { expect(@header_snippet).to include_link_tag_with( :rel => 'openid.server', :href => 'https://www.hatena.ne.jp/openid/server')} it { expect(@header_snippet).to include_link_tag_with( :rel => 'openid.delegate', :href => 'http://www.hatena.ne.jp/tdtds/')} end describe "livedoor" do before do plugin = setup_open_id_plugin('livedoor', 'tdtds') @header_snippet = plugin.header_proc end it { expect(@header_snippet).to include_link_tag_with( :rel => 'openid.server', :href => 'http://auth.livedoor.com/openid/server')} it { expect(@header_snippet).to include_link_tag_with( :rel => 'openid.delegate', :href => 'http://profile.livedoor.com/tdtds')} end describe "LiveJournal" do before do plugin = setup_open_id_plugin('LiveJournal', 'tdtds') @header_snippet = plugin.header_proc end it { expect(@header_snippet).to include_link_tag_with( :rel => 'openid.server', :href => 'http://www.livejournal.com/openid/server.bml')} it { expect(@header_snippet).to include_link_tag_with( :rel => 'openid.delegate', :href => 'http://tdtds.livejournal.com/')} end describe "OpenID.ne.jp" do before do plugin = setup_open_id_plugin('OpenID.ne.jp', 'tdtds') @header_snippet = plugin.header_proc end it { expect(@header_snippet).to include_link_tag_with( :rel => 'openid.server', :href => 'http://www.openid.ne.jp/user/auth')} it { expect(@header_snippet).to include_link_tag_with( :rel => 'openid.delegate', :href => 'http://tdtds.openid.ne.jp')} it { expect(@header_snippet).to include_xrds_meta_tag_with( :content => 'http://tdtds.openid.ne.jp/user/xrds')} end describe "TypeKey" do before do plugin = setup_open_id_plugin('TypeKey', 'tdtds') @header_snippet = plugin.header_proc end it { expect(@header_snippet).to include_link_tag_with( :rel => 'openid.server', :href => 'http://www.typekey.com/t/openid/')} it { expect(@header_snippet).to include_link_tag_with( :rel => 'openid.delegate', :href => 'http://profile.typekey.com/tdtds/')} end describe "Vox" do before do plugin = setup_open_id_plugin('Vox', 'tdtds') @header_snippet = plugin.header_proc end it { expect(@header_snippet).to include_link_tag_with( :rel => 'openid.server', :href => 'http://www.vox.com/services/openid/server')} it { expect(@header_snippet).to include_link_tag_with( :rel => 'openid.delegate', :href => 'http://tdtds.vox.com/')} end describe "myopenid.com" do before do @plugin = setup_open_id_plugin('myopenid.com', 'tdtds') @header_snippet = @plugin.header_proc end it { expect(@header_snippet).to include_xrds_meta_tag_with( :content => "http://www.myopenid.com/xrds?username=tdtds")} it { expect(@header_snippet).to include_link_tag_with( :rel => "openid.server", :href => "http://www.myopenid.com/server")} it { expect(@header_snippet).to include_link_tag_with( :rel => "openid.delegate", :href => "http://tdtds.myopenid.com")} it { expect(@header_snippet).to include_link_tag_with( :rel => "openid2.provider", :href => "http://www.myopenid.com/server")} it { expect(@header_snippet).to include_link_tag_with( :rel => "openid2.local_id", :href => "http://tdtds.myopenid.com")} end describe "claimID.com" do before do @plugin = setup_open_id_plugin('claimID.com', 'tdtds') @header_snippet = @plugin.header_proc end it { expect(@header_snippet).to include_xrds_meta_tag_with( :content => "http://claimid.com/tdtds/xrds")} it { expect(@header_snippet).to include_link_tag_with( :rel => "openid.server", :href => "http://openid.claimid.com/server")} it { expect(@header_snippet).to include_link_tag_with( :rel => "openid.delegate", :href => "http://openid.claimid.com/tdtds")} end describe "Personal Identity Provider (PIP)" do before do @plugin = setup_open_id_plugin('Personal Identity Provider (PIP)', 'tdtds') @header_snippet = @plugin.header_proc end it { expect(@header_snippet).to include_xrds_meta_tag_with( :content => "http://pip.verisignlabs.com/user/tdtds/yadisxrds")} it { expect(@header_snippet).to include_link_tag_with( :rel => "openid.server", :href => "http://pip.verisignlabs.com/server")} it { expect(@header_snippet).to include_link_tag_with( :rel => "openid.delegate", :href => "http://tdtds.pip.verisignlabs.com/")} it { expect(@header_snippet).to include_link_tag_with( :rel => "openid2.provider", :href => "http://pip.verisignlabs.com/server")} it { expect(@header_snippet).to include_link_tag_with( :rel => "openid2.local_id", :href => "http://tdtds.pip.verisignlabs.com/")} end describe "Yahoo! Japan" do before do plugin = setup_open_id_plugin('Yahoo! Japan', 'tdtds') @header_snippet = plugin.header_proc end it { expect(@header_snippet).to include_link_tag_with( :rel => 'openid2.provider', :href => 'https://open.login.yahooapis.jp/openid/op/auth')} it { expect(@header_snippet).to include_link_tag_with( :rel => 'openid2.local_id', :href => 'https://me.yahoo.co.jp/a/tdtds')} it { expect(@header_snippet).not_to include_link_tag_with( :rel => "openid.server")} it { expect(@header_snippet).not_to include_link_tag_with( :rel => "openid.delegate")} end describe "Yahoo!" do before do plugin = setup_open_id_plugin('Yahoo!', 'tdtds') @header_snippet = plugin.header_proc end it { expect(@header_snippet).to include_link_tag_with( :rel => 'openid2.provider', :href => 'https://open.login.yahooapis.com/openid/op/auth')} it { expect(@header_snippet).to include_link_tag_with( :rel => 'openid2.local_id', :href => 'https://me.yahoo.com/a/tdtds')} it { expect(@header_snippet).not_to include_link_tag_with( :rel => "openid.server")} it { expect(@header_snippet).not_to include_link_tag_with( :rel => "openid.delegate")} end RSpec::Matchers.define :include_link_tag_with do |options| description do "include #{options[:rel]} link tag" end match do |actual| expected = %|| if options[:href] actual.include?( expected ) end end RSpec::Matchers.define :include_xrds_meta_tag_with do |options| description do "include XRDS meta tag" end match do |actual| expected = (<<-"EOS").chomp EOS actual.include?( expected ) end end end tdiary-contrib-5.0.8/spec/opensearch_ad_spec.rb000066400000000000000000000026221325711763500215560ustar00rootroot00000000000000$:.unshift(File.dirname(__FILE__)) require 'spec_helper' describe "opensearch_ad plugin w/" do def setup_opensearch_ad_plugin(title, xml, mode) fake_plugin(:opensearch_ad) { |plugin| plugin.mode = mode plugin.conf['opensearch.title'] = title plugin.conf['opensearch.xml'] = xml } end describe "in day mode" do before do plugin = setup_opensearch_ad_plugin('OpenSearch', 'http://example.com/opensearch.xml', 'day') @header_snippet = plugin.header_proc end it { expect(@header_snippet).to eq(expected_link_tag_with( :title => 'OpenSearch', :xml => 'http://example.com/opensearch.xml'))} end describe "in latest mode" do before do plugin = setup_opensearch_ad_plugin('OpenSearch', 'http://example.com/opensearch.xml', 'latest') @header_snippet = plugin.header_proc end it { expect(@header_snippet).to eq(expected_link_tag_with( :title => 'OpenSearch', :xml => 'http://example.com/opensearch.xml'))} end describe "in edit mode" do before do plugin = setup_opensearch_ad_plugin('OpenSearch', 'http://example.com/opensearch.xml', 'edit') @header_snippet = plugin.header_proc end it { expect(@header_snippet).to be_empty } end def expected_link_tag_with(options) result = <<-HTML HTML result.gsub( /^\t/, '' ).chomp end end tdiary-contrib-5.0.8/spec/profile_spec.rb000066400000000000000000000036601325711763500204260ustar00rootroot00000000000000# -*- coding: utf-8 -*- require 'spec_helper' require 'profile' describe "Profile::Service" do describe "GitHub" do before do require 'json' allow_any_instance_of(Profile::Service::GitHub).to receive(:fetch).and_return(JSON.parse(File.read("spec/fixtures/github.json"))) # workaround for run spec on various environment. require 'openssl' OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE # http://develop.github.com/p/general.html @profile = Profile::Service::GitHub.new("schacon") end it "should include name, mail, image properties" do expect(@profile.name).to eq("Scott Chacon") expect(@profile.mail).to eq("schacon@gmail.com") expect(@profile.image).to eq("https://avatars.githubusercontent.com/u/70?v=3") end end describe "Gravatar" do # http://ja.gravatar.com/site/implement/hash/ before do require 'json' allow_any_instance_of(Profile::Service::Gravatar).to receive(:fetch).and_return(JSON.parse(File.read("spec/fixtures/gravatar.json"))) @profile = Profile::Service::Gravatar.new("iHaveAn@email.com") end it "should include name, mail, image properties" do expect(@profile.name).to eq("tDiary") expect(@profile.mail).to eq("iHaveAn@email.com") expect(@profile.image).to eq("http://2.gravatar.com/avatar/3b3be63a4c2a439b013787725dfce802") end context 'with options' do before do @profile = Profile::Service::Gravatar.new("iHaveAn@email.com", :size => 40) end it "should specify size option" do expect(@profile.image).to eq("http://2.gravatar.com/avatar/3b3be63a4c2a439b013787725dfce802?s=40") end end end describe "Hatena" do before do @profile = Profile::Service::Hatena.new("kmachu") end it "should include image property" do expect(@profile.image).to eq("http://www.hatena.ne.jp/users/km/kmachu/profile.gif") end end end tdiary-contrib-5.0.8/spec/rcov.opts000066400000000000000000000000471325711763500173030ustar00rootroot00000000000000-x /var/lib/gem -x spec/spec_helper.rb tdiary-contrib-5.0.8/spec/spec_helper.rb000066400000000000000000000074641325711763500202530ustar00rootroot00000000000000# -*- coding: utf-8 -*- $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), "..", "plugin"))) if ENV['COVERAGE'] == 'simplecov' require 'simplecov' SimpleCov.start do add_filter '/spec/' add_filter '/vendor/' end end require 'erb' require 'webmock/rspec' require 'tmpdir' RSpec.configure do |c| # create a temporary directory used by the plugin for cache c.before(:all) do @cache_path = Dir.mktmpdir end c.after(:all) do FileUtils.rmtree(@cache_path) end end # FIXME PluginFake in under construction. class PluginFake include ERB::Util attr_reader :conf attr_accessor :mode, :date def initialize @conf = Config.new @cache_path = "" @mode = "" @date = nil @header_procs = [] @footer_procs = [] @update_procs = [] @conf_procs = [] @edit_procs = [] @body_enter_procs = [] @body_leave_procs = [] end def add_conf_proc( key, label, genre=nil, &block ) @conf_procs << block end def add_edit_proc( block = Proc::new ) @edit_procs << block end def add_header_proc( block = Proc::new ) @header_procs << block end def add_footer_proc( block = Proc::new ) @footer_procs << block end def add_update_proc( block = Proc::new ) @update_procs << block end def conf_proc r = [] @conf_procs.each do |proc| r << proc.call end r.join.chomp end def header_proc r = [] @header_procs.each do |proc| r << proc.call end r.join.chomp end def footer_proc r = [] @footer_procs.each do |proc| r << proc.call end r.join.chomp end def add_body_enter_proc( block = Proc::new ) @body_enter_procs << block end def body_enter_proc( date ) r = [] @body_enter_procs.each do |proc| r << proc.call( date ) end r.join.chomp end def add_body_leave_proc( block = Proc::new ) @body_leave_procs << block end def body_leave_proc( date ) r = [] @body_leave_procs.each do |proc| r << proc.call( date ) end r.join.chomp end class Config attr_accessor :index, :html_title, :cgi def initialize @cgi = CGIFake.new @options = {} @options2 = {} @index = './' @html_title = '' bot = ["bot", "spider", "antenna", "crawler", "moget", "slurp"] bot += @options['bot'] || [] @bot = Regexp::new( "(#{bot.uniq.join( '|' )})", true ) end def []( key ) @options[key] end def []=( key, val ) @options2[key] = @options[key] = val end def delete( key ) @options.delete( key ) @options2.delete( key ) end def base_url begin if @options['base_url'].length > 0 then return @options['base_url'] end rescue end end def mobile_agent? false end def smartphone? false end def bot? @bot =~ @cgi.user_agent end end def feed? false end def iphone? false end alias ipod? iphone? end class CGIFake attr_accessor :user_agent def initialize @user_agent = "" end def mobile_agent? false end def iphone? false end end def fake_plugin( name_sym, cgi=nil, base=nil, &block ) plugin = PluginFake.new yield plugin if block_given? file_path = plugin_path( name_sym, base ) plugin_name = File.basename( file_path, ".rb" ) plugin.instance_variable_set(:@cache_path, @cache_path) plugin.instance_eval do eval( File.read( file_path ), binding, "(#{File.basename(file_path)})", 1 ) end plugin_sym = plugin_name.to_sym if plugin.class.private_method_defined?( plugin_sym ) plugin.__send__( :public, plugin_sym ) end plugin end def plugin_path( plugin_sym, base=nil ) paths = [] paths << ( base ? base : "plugin" ) paths << "#{plugin_sym.to_s}.rb" File.expand_path( File.join( paths )) end def anchor( s ) if /^([\-\d]+)#?([pct]\d*)?$/ =~ s then if $2 then "?date=#$1##$2" else "?date=#$1" end else "" end end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/spec/title_anchor_spec.rb000066400000000000000000000016431325711763500214400ustar00rootroot00000000000000$:.unshift(File.dirname(__FILE__)) require 'spec_helper' describe "title_anchor plugin" do def setup_title_anchor_plugin(mode) fake_plugin(:title_anchor) { |plugin| plugin.mode = mode plugin.conf.index = '' plugin.conf.html_title = "HsbtDiary" } end describe "in day mode" do before do @plugin = setup_title_anchor_plugin('day') end it { expect(@plugin.title_anchor).to eq(expected_html_title_in_day( :index => '', :html_title => 'HsbtDiary'))} end describe "in latest mode" do before do @plugin = setup_title_anchor_plugin('latest') end it { expect(@plugin.title_anchor).to eq(expected_html_title_in_latest( :html_title => 'HsbtDiary'))} end def expected_html_title_in_day(options) expected = %{

      #{options[:html_title]}

      } end def expected_html_title_in_latest(options) expected = %{

      #{options[:html_title]}

      } end end tdiary-contrib-5.0.8/spec/twitter_js_spec.rb000066400000000000000000000061351325711763500211640ustar00rootroot00000000000000$:.unshift(File.dirname(__FILE__)) require 'spec_helper' require 'time' describe "twitter_js plugin" do def setup_twitter_js_plugin(mode, user_id) fake_plugin(:twitter_js) { |plugin| plugin.mode = mode plugin.conf['twitter.user'] = user_id plugin.date = Time.parse("20080124") } end describe "should render javascript and div tag in day" do before do @plugin = setup_twitter_js_plugin("day", "123456789") end it "for header" do snippet = @plugin.header_proc expect(snippet).to eq(expected_html_header_snippet("123456789")) end it "for body leave" do snippet = @plugin.body_leave_proc(Time.parse("20080124")) expect(snippet).to eq(expected_html_body_snippet) end end describe "should render javascript and div tag in latest" do before do @plugin = setup_twitter_js_plugin("latest", "123456789") end it "for header" do snippet = @plugin.header_proc expect(snippet).to eq(expected_html_header_snippet("123456789")) end it "for body leave" do snippet = @plugin.body_leave_proc(Time.parse("20080124")) expect(snippet).to eq(expected_html_body_snippet) end end describe "should not render in edit" do before do @plugin = setup_twitter_js_plugin("edit", "123456789") end it "for header" do snippet = @plugin.header_proc expect(snippet).to be_empty end it "for body leave" do snippet = @plugin.body_leave_proc(Time.parse("20080124")) expect(snippet).to be_empty end end describe "should not render when user_id is empty" do before do @plugin = setup_twitter_js_plugin("edit", "") end it "for header" do snippet = @plugin.header_proc expect(snippet).to be_empty end it "for body leave" do snippet = @plugin.body_leave_proc(Time.parse("20080124")) expect(snippet).to be_empty end end def expected_html_header_snippet(user_id) expected = <<-EXPECTED EXPECTED expected.gsub(/^\t/, '').chomp end def expected_html_body_snippet expected = <<-HTML
      HTML expected.gsub( /^\t/, '' ).chomp end end tdiary-contrib-5.0.8/spec/youtube_spec.rb000066400000000000000000000011721325711763500204560ustar00rootroot00000000000000$:.unshift(File.dirname(__FILE__)) require 'spec_helper' describe "youtube plugin" do DUMMY_YOUTUBE_VIDEO_ID = 1234567890 { 'Mozilla' => %|\t\t
      \n\t\t\n\t\t
      \n| }.each do |k,v| it 'should render object tag in :user_agent' do plugin = fake_plugin(:youtube) cgi = CGIFake.new cgi.user_agent = k plugin.conf.cgi = cgi expect(plugin.youtube(DUMMY_YOUTUBE_VIDEO_ID)).to eq(v) end end end tdiary-contrib-5.0.8/style/000077500000000000000000000000001325711763500156305ustar00rootroot00000000000000tdiary-contrib-5.0.8/style/hatena_style.rb000077500000000000000000000623631325711763500206520ustar00rootroot00000000000000#!/usr/bin/env ruby -Ke # Copyright(c) 2004 URABE, Shyouhei. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this code, to deal in the code without restriction, including without # limitation the rights to use, copy, modify, merge, publish, distribute, # sublicense, and/or sell copies of the code, and to permit persons to whom the # code is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the code. # # THE CODE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHOR OR COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE CODE OR THE USE OR OTHER DEALINGS IN THE # CODE. # $Id: hatena_style.rb,v 1.12 2007-02-27 06:57:14 kazuhiko Exp $ # Hatena::Diary compatible style # Works only under ruby 1.8.1 or later [ 'uri', 'net/http', 'cgi', 'pstore', 'time', ].each {|f| require f } class TDiary::HatenaDiary include TDiary::DiaryBase, TDiary::CategorizableDiary def initialize(date, title, body, modified=Time.now) init_diary @sections = [] replace date, title, body @last_modified = modified end def style 'Hatena' end def replace(date, title, body) set_date date set_title title @sections.clear append body end def append(body, author=nil) @sections.concat Hatena::Diary.parse(body, author) self end def each_section(&block) @sections.each(&block) end def to_src @sections.inject('') {|r, i| r << i.to_src } end def to_html(opt, mode=:HTML) j = 0 @sections.inject('') {|r, i| j += 1 r << '
      ' if mode != :CHTML r << i.convert(mode, date, j, opt) r << '
      ' if mode != :CHTML r } end def to_s sprintf('date=%s, title=%s, body=%s', date.strftime('%Y%m%d'), title, @sections.map {|i| '[%s]' % i}.join) end end # This is the namespace module module Hatena def Hatena.conf ObjectSpace.each_object do |diary| next unless diary.kind_of?(TDiary::TDiaryBase) return diary.instance_eval { @conf } end end Diary = Object.new API = Object.new # get a text of hatena-style, and convert it into parse tree. def Diary.parse(str, author) str.gsub(/\r(?!\n)/,"\n")\ .delete("\r")\ .gsub(/^\*/,'**')\ .split(/^\*/)\ .inject([]) {|r, i| i.empty? ? r : r << Hatena::Section.new(i, author) } end # find the cache_path from entore ruby world # could someone please tell me more eficient way to do this... def API.cache_path ret = Hatena.conf.cache_path || Hatena.conf.data_path + '/cache' unless FileTest.directory?(ret) begin Dir.mkdir(ret) rescue Errno::EEXIST ; # OK end end ret end def API.update_kw(kw) return false if File.exist?(kw) && Time.now - File.mtime(kw) < 86400 File.open(kw, IO::WRONLY|IO::CREAT) do |fp| break unless fp.flock(IO::LOCK_EX|IO::LOCK_NB) uri = ::URI.parse('http://d.hatena.ne.jp/images/keyword/keywordlist') Timeout.timeout(60) do Net::HTTP.version_1_1 Net::HTTP.new(uri.host, uri.port).start do |http| res, body = http.get(uri.request_uri, {'User-Agent' => "tDiary/#{TDIARY_VERSION}"}) fp.seek(0, IO::SEEK_SET) fp.write(body) end end end true end def API.update_db(kw, db) raise if API.update_kw kw raise unless FileTest.exist? db.path false rescue str = File.open(kw, IO::RDONLY) do |fp| fp.flock(IO::LOCK_SH) fp.read end a = str.gsub(/\\s/,' ') \ .gsub(/\\(?!\|)/,'') \ .scan(/(?:[^|]|\\\|)*[^\\](?=\||\z)/) db.transaction do db['trie'] = Trie.new(a) end true end # The trie of keywords # Keywords are chached, chache expires every day (24h) def API.keywords path = API.cache_path kw = path + '/keywordlist' db = PStore.new(path + '/keywords.pstore') if API.update_db(kw, db) || @ret.nil? db.transaction(IO::RDONLY) do @ret = db['trie'] end end return @ret end end # Deterministic finate automata class Hatena::Trie private def add(kw) h = @hash1 kw.split(//e).each do |c| unless h.has_key? c tmp = Hash.new @ary << tmp h[c] = tmp end h = h[c] end @hash2[h] = kw end def initialize(a) @ary = Array.new @hash1 = Hash.new @hash2 = Hash.new a.each {|kw| add kw } end public def match(str) ret = nil h = @hash1 a = str.split(//e) i = 0 j = 0 while c = a[i + j] if h[c] h = h[c] if @hash2[h] ret = @hash2[h] end f = false j += 1 else return ret if ret h = @hash1 # reset i += 1 j = 0 end end return ret end end # -------- # Parser Tree Nodes class Hatena::Section def initialize(str, author) t = Time.now @author = author.freeze @src = str.gsub(/^\*t\*/, '*%d*' % t.to_i)\ .gsub(/<(ins|del)>/, '<\1 datetime="%s">' % t.xmlschema) @tree = Hatena::Block.new(@src) end def convert(mode, date, i, opt) @tree.convert(mode, date, i, opt, author) end def to_src @src end def categories @tree.title.categories end def author @author end def body @tree.body.to_s end def subtitle @tree.title.to_s end def stripped_subtitle @tree.title.strip.to_s end def body_to_html @tree.body.convert(:HTML) end def subtitle_to_html @tree.title.convert(:HTML) end def stripped_subtitle_to_html @tree.title.strip.convert(:HTML) end end # Block level elements class Hatena::Block attr_reader :to_s, :title, :body def initialize(str) # Too long. Needs refactoring. if str.nil? @title = Hatena::Title.new('') # dummy @body = Hatena::Inline.new('') # dummy @to_s = '' elsif str[0] == ?* t,b = *str.split(/\n/,2) @title = Hatena::Title.new(t) @body = Hatena::BlockAndorInline.new(b, false) @to_s = t + "\n" + (b||'') else @to_s = str @title = Hatena::Title.new('') # dummy @body = Hatena::BlockAndorInline.new(str, false) end end def convert(mode, date=nil, i=nil, opt=nil, author=nil) if title_is_dummy? @body.convert(mode) else @title.convert(mode, date, i, opt, author) + "\n" + @body.convert(mode) end end def title_is_dummy? @to_s[0] == ?* end end # Section subtitle class Hatena::Title attr_reader :to_s, :categories, :strip def initialize(str) if m = /\A\*([0-9]+)\*/.match(str) @time = Time.at(Integer(m[1])) @to_s = m.post_match.freeze elsif m = /\A\*([a-zA-Z0-9_]+)\*/.match(str) @name = m[1] @to_s = m.post_match.freeze else @to_s = (str[1..-1]||'').freeze end @categories = to_s.scan(/\[(.*?)\]/).map{|a| a[0] } @strip = Hatena::Inline.new(Regexp.last_match ? Regexp.last_match.post_match : to_s) end def convert(mode, date=nil, i=nil, opt=nil, author=nil) id = ('p%02d' % (i || 0)) h = '%0.32b' % rand(0x100000000) case when date.nil? categories.map {|i| "<%=category_anchor <<'#{h}'.chomp\n#{i}\n#{h}\n%>" }.join + strip.convert(mode) when mode == :CHTML sprintf('*%s%s
      ', @name ? %Q{ ID"=#@name"} : '', id, (opt['multi_user'] && author) ? "[#{author}]" : '', strip.convert(mode)) else sprintf('#%s">%s%s%s%s %s', @name ? %Q{ id="#@name"} : '', opt['anchor'] ? 'name="%s" ' % id : '', opt['index'], date.strftime('%Y%m%d'), @name || id, opt['section_anchor'], categories.map {|cat| "<%=category_anchor <<'#{h}'.chomp\n#{cat}\n#{h}\n%>" }.join, (opt['multi_user'] && author) ? "[#{author}]" : '', strip.convert(mode), @time ? %Q!#{@time.strftime('%H:%M')}! : '') end end end # Sequence of block level elements and/or inline level elements # or sequence of block level elements only. class Hatena::BlockAndorInline def initialize(str, allowinline = true) @elems = Array.new pbuffer = '' # paragraph buffer flush_pbuffer = lambda{ next if pbuffer.empty? if allowinline @elems.push Hatena::Inline.new(pbuffer) else @elems.push Hatena::Paragraph.new(pbuffer) end pbuffer.replace('') } lines = str.concat("\n").scan(/.*\n/) until lines.empty? case when lines[0][0] == ?- flush_pbuffer.call buffer = '' until lines.empty? break unless lines[0][0] == ?- buffer.concat lines.shift end @elems.push Hatena::Itemize.new(buffer) when lines[0][0] == ?+ flush_pbuffer.call buffer = '' until lines.empty? break unless lines[0][0] == ?+ buffer.concat lines.shift end @elems.push Hatena::Enumerate.new(buffer) when lines[0][0] == ?: flush_pbuffer.call buffer = '' until lines.empty? break unless lines[0][0] == ?: break unless lines[0].rindex(?:) != 0 buffer.concat lines.shift end @elems.push Hatena::Description.new(buffer) when lines[0] == ">>\n" flush_pbuffer.call buffer = '' nest = 0 until lines.empty? nest += 1 if lines[0] == ">>\n" nest -= 1 if lines[0] == "<<\n" buffer.concat lines.shift break if nest <= 0 end @elems.push Hatena::Quote.new(buffer) when lines[0] == ">|\n" flush_pbuffer.call buffer = '' until lines.empty? str1 = lines.shift buffer.concat str1 break if /\|<$/ =~ str1 end @elems.push Hatena::Verbatim.new(buffer) when lines[0] == ">||\n" flush_pbuffer.call buffer = '' until lines.empty? str1 = lines.shift buffer.concat str1 break if /\|\|<$/ =~ str1 end @elems.push Hatena::SuperVerbatim.new(buffer) when lines[0][0,5] == '><$/ =~ lines.shift end when lines[0][0,2] == '><' flush_pbuffer.call buffer = '' until lines.empty? str1 = lines.shift buffer.concat str1 break if /><$/ =~ str1 end @elems.push Hatena::UnParagraph.new(buffer) else pbuffer.concat lines.shift if pbuffer[-3..-1] == "\n\n\n" flush_pbuffer.call end end end flush_pbuffer.call end def convert(mode) @elems.inject('') {|r, i| r << i.convert(mode) << "\n" } end end # Itemize # extension to Hatena: nest can be more than 3 level. class Hatena::Itemize def initialize(str) @elems = Array.new lines = str.gsub(/^-/,'').scan(/.*\n/) buffer = '' until lines.empty? case when lines[0][0] == ?- until lines.empty? break unless lines[0][0] == ?- buffer.concat lines.shift end @elems.push Hatena::BlockAndorInline.new(buffer) buffer = '' when lines[0][0] == ?+ until lines.empty? break unless lines[0][0] == ?+ buffer.concat lines.shift end @elems.push Hatena::BlockAndorInline.new(buffer) buffer = '' when lines[0][0] == ?: until lines.empty? break unless lines[0][0] == ?: break unless lines[0].rindex(?:) != 0 buffer.concat lines.shift end @elems.push Hatena::BlcokAndorInline.new(buffer) buffer = '' else @elems.push Hatena::Inline.new(buffer) unless buffer.empty? buffer = lines.shift end end @elems.push Hatena::Inline.new(buffer) unless buffer.empty? end def convert(mode) template = nil if mode == :CHTML template = ["
        %s\n
      ", "\n
    • %s
    • "] else template = ["
        %s\n
      ", "\n
    • %s
    • "] end template[0] % @elems.inject('') {|r, i| r << template[1] % i.convert(mode) } end end # Enumerate # Extension to Hatena: nest can be more than 3 level class Hatena::Enumerate def initialize(str) @elems = Array.new lines = str.gsub(/^\+/,'').scan(/.*\n/) buffer = '' until lines.empty? case when lines[0][0] == ?- until lines.empty? break unless lines[0][0] == ?- buffer.concat lines.shift end @elems.push Hatena::BlockAndorInline.new(buffer) buffer = '' when lines[0][0] == ?+ until lines.empty? break unless lines[0][0] == ?+ buffer.concat lines.shift end @elems.push Hatena::BlockAndorInline.new(buffer) buffer = '' when lines[0][0] == ?: until lines.empty? break unless lines[0][0] == ?: break unless lines[0].rindex(?:) != 0 buffer.concat lines.shift end @elems.push Hatena::BlcokAndorInline.new(buffer) buffer = '' else @elems.push Hatena::Inline.new(buffer) unless buffer.empty? buffer = lines.shift end end @elems.push Hatena::Inline.new(buffer) unless buffer.empty? end def convert(mode) template = nil if mode == :CHTML template = ["
        %s\n
      ", "\n
    • %s
    • "] else template = ["
        %s\n
      ", "\n
    • %s
    • "] end template[0] % @elems.inject('') {|r, i| r << template[1] % i.convert(mode) } end end # Description list # Extension to hatena : term only and descriotion only are OK # :term: # ::desc # Extension to Hatena : can be combined with lists class Hatena::Description def initialize(str) @elems = Array.new str.each_line do |l| raise SyntaxError unless l[0] == ?: l = l[1..-1] buffer = '' # while l =~ /[^:]*#{URI.regexp}/o # buffer.concat Regexp.last_match.to_s # l = Regexp.last_match.post_match # end dt,dd = *l.split(/:/,2) buffer.concat dt @elems.push([ buffer.empty? ? nil : Hatena::Inline.new(buffer), (dd.nil? || dd.empty?) ? nil : Hatena::Inline.new(dd) ]) end end def convert(mode) template = nil if mode == :CHTML template = ["
      %s\n
      ", "\n
      %s
      ", "
      %s
      "] else template = ["
      %s\n
      ", "\n
      %s
      ", "
      %s
      "] end template[0] % @elems.inject('') {|r, i| r << template[1] % i[0].convert(mode) unless i[0].nil? r << template[2] % i[1].convert(mode) unless i[1].nil? r } end end # block level quote # Extension to hatena : nest can be more than 2 level. class Hatena::Quote def initialize(str) @elems = Hatena::Block.new(str[3..-4]) end def convert(mode) template = nil if mode == :CHTML template = "
      \n%s\n
      " else template = "
      \n%s\n
      " end sprintf(template,@elems.convert(mode)) end end # preformatted text class Hatena::Verbatim def initialize(str) @str = str[3..-4].freeze end def convert(mode) template = nil if mode == :CHTML template = "
      %s
      " else template = "
      %s
      " end sprintf(template,CGI.escapeHTML(@str)) end end # preformatted text class Hatena::SuperVerbatim def initialize(str) @str = str[3..-5].freeze end def convert(mode) template = nil if mode == :CHTML template = "
      %s
      " else template = "
      %s
      " end sprintf(template,CGI.escapeHTML(@str)) end end # non-paragraph blocklevel class Hatena::UnParagraph def initialize(str) @elems = Hatena::Inline.new(str[1..-3]) # 0123... # >
      # ... ... # ...
      <\n # ...-321 end def convert(mode) @elems.convert(mode) end end # paragraph # Extension to Hatena: not using
      but begins next paragraph class Hatena::Paragraph def initialize(str) @elems = Hatena::Inline.new(str.gsub(/\n\n\n/,'')) end def convert(mode) template = nil if mode == :CHTML template = "

      \n%s\n

      " else template = "

      \n%s\n

      " end sprintf(template, @elems.convert(mode)) end end # inline elements class Hatena::Inline def initialize(str) @elems = Array.new inside_a = false return if str == "\n" until str.empty? case str when /\A\[\](.*?)\[\]/m @elems.push Hatena::CDATA.new(Regexp.last_match[1]) when /\A\)\(\((.*?)\)\)\(/m, /\A\(\(\((.*?)\)\)\)/m @elems.push Hatena::CDATA.new('((') @elems.push Hatena::Inline.new(Regexp.last_match[1]) @elems.push Hatena::CDATA.new('))') when /\A\(\((.*?)\)\)/m @elems.push Hatena::Footnote.new(Regexp.last_match[1]) when /\A#{tag_regex}/o @elems.push Hatena::TAG.new(Regexp.last_match.to_s) if str.index("") == 0 inside_a = false end when /\A\[amazon:(.*?)\]/m @elems.push Hatena::AmazonSearch.new(Regexp.last_match[1], true) when /\A\[google:(.*?)\]/m @elems.push Hatena::Google.new(Regexp.last_match[1], true) when /\A\[(?:(#{gid_regex}):)?keyword:(.*?)\]/m, /\A\[\[(.*?)\]\]/m group, keyword = Regexp.last_match.captures @elems.push Hatena::Keyword.new(group, keyword, true) when /\A\[(?:(#{gid_regex}|[ad]):)?id:([a-zA-Z][-a-zA-Z0-9_]{1,30}[a-zA-Z0-9])\]/m, /\A(?:(#{gid_regex}|[ad]):)?id:([a-zA-Z][-a-zA-Z0-9_]{1,30}[a-zA-Z0-9](?::(?:[0-9]+|about))?)/ sid, id = Regexp.last_match.captures @elems.push Hatena::ID.new(sid, id, true) when /\A\[(?i:ISBN|ASIN):(.*?)(?::image(?::(?:small|large))?)?\]/m, /(?i:ISBN|ASIN):([-0-9A-Za-z]+)(?::image(?::(?:small|large))?)?/ @elems.push Hatena::Amazon.new(Regexp.last_match[1], true) when /\A\[tex:(.*?)\]/m @elems.push Hatena::TeX.new(Regexp.last_match[1]) when /\A#{gid_regex}/ @elems.push Hatena::Group.new(Regexp.last_match.to_s, true) when /\A\[((?i:https?|ftp|mailto):.+?)\]/m, /\A(#{URI.regexp})/o @elems.push Hatena::URI.new(Regexp.last_match[1]) else /.+?(?=[\[\]()<>]|(?i:https?|ftp|mailto|id|ISBN|ASIN)|[adg]:|$)/m =~ str if inside_a @elems.push Hatena::CDATA.new(Regexp.last_match.to_s) else @elems.push Hatena::Sentence.new(Regexp.last_match.to_s) end end str = Regexp.last_match.post_match end end def convert(mode) @elems.inject('') {|r, i| r << i.convert(mode) } end private # tag_regex was quoted from http://www.din.or.jp/~ohzaki/perl.htm#HTML_Tag def tag_regex /<[^"'<>]*(?:"[^"]*"[^"'<>]*|'[^']*'[^"'<>]*)*(?:>|(?=<)|$)/ end def gid_regex /g:[a-zA-Z][a-zA-Z0-9]{2,23}/ end end # String that surely doesn't contain any keywords # String that can contain keyword is a Sentence class Hatena::CDATA def initialize(str) @str = str.freeze end def convert(mode) @str end end # footnote # footnote.rb required class Hatena::Footnote def initialize(str) @str = str @heredoc = rand(0x100000000) end def convert(mode) sprintf("<%%=fn <<'%0.32b'.chomp\n%s\n%0.32b\n%%>", @heredoc, @str, @heredoc) end end # HTML tags # Disadvantanegs from hatena : is not supported # Extension to Hatena : ERB expression can be written class Hatena::TAG def initialize(str) @elems = Array.new return if /', @str, @str.delete('-')) # %= else sprintf('http://www.amazon.co.jp/exec/obidos/ASIN/%s/%s', @str, Hatena.conf['amazon.aid'] || '') end end end # Amazon search # http://d.hatena.ne.jp/hatenadiary/20040310#1078879113 class Hatena::AmazonSearch def initialize(str, tag_p) @str = str @tag_p = tag_p end def convert(mode) uri = 'http://www.amazon.co.jp/exec/obidos/external-search?mode=blended&tag=%s&encoding-string-jp=%%c6%%fc%%cb%%dc%%b8%%ec&keyword=%s' % [Hatena.conf['amazon.aid'] || '', URI.escape(@str, /[^-_.!~*'()a-zA-Z0-9]/)] return uri unless @tag_p template=nil if mode == :CHTML template = 'amazon:%s' else template = 'amazon:%s' end sprintf(template, uri, @str) end end # TeX expressoin # texdiary http://kumamushi.org/~k/texdiary/ required class Hatena::TeX def initialize(expr) @expr end def convert(mode) sprintf('<%%=eq "%s"%%>' % @expr) #%= end end # String that can contain keywords # String that cannot contain keywords is a CDATA class Hatena::Sentence def initialize(str) @elems = Array.new return if str.nil? || str.empty? if false # kw = Hatena::API.keywords.match(str) m = Regexp.new(Regexp.quote(kw)).match(str) @elems.push Hatena::CDATA.new(m.pre_match) @elems.push Hatena::Keyword.new(nil, kw, true) @elems.push Hatena::Sentence.new(m.post_match) else @elems.push Hatena::CDATA.new(str) end end def convert(mode) @elems.inject('') {|r, i| r << i.convert(mode) } end end # Local Variables: # mode: ruby # code: euc-jp-unix # End: tdiary-contrib-5.0.8/style/markdown_style.rb000066400000000000000000000125261325711763500212250ustar00rootroot00000000000000# # markdown_style.rb: Markdown style for tDiary 2.x format. $Revision: 1.10 $ # # if you want to use this style, add @style into tdiary.conf below: # # @style = 'Markdown' # # Copyright (C) 2003, TADA Tadashi # Copyright (C) 2004, MoonWolf # You can distribute this under GPL. # require 'bluecloth' module TDiary class MarkdownSection attr_reader :subtitle, :author attr_reader :categories, :stripped_subtitle attr_reader :subtitle_to_html, :stripped_subtitle_to_html, :body_to_html def initialize( fragment, author = nil ) @author = author @subtitle, @body = fragment.split( /\n/, 2 ) @subtitle.sub!(/^\#\s*/,'') @body ||= '' @categories = get_categories @stripped_subtitle = strip_subtitle @subtitle_to_html = @subtitle ? to_html('# ' + @subtitle).gsub(/\A|<\/h\d>\z/io, '') : nil @stripped_subtitle_to_html = @stripped_subtitle ? to_html('# ' + @stripped_subtitle).gsub(/\A|<\/h\d>\z/io, '') : nil @body_to_html = to_html(@body) end def subtitle=(subtitle) @categories = categories cat_str = "" categories.each {|cat| cat_str << "[#{cat}]" } @subtitle = (subtitle || '').sub(/^# /,"\##{cat_str} ") @strip_subtitle = strip_subtitle end def body @body.dup end def body=(str) @body = str end def categories=(categories) @categories = categories cat_str = "" categories.each {|cat| cat_str << "[#{cat}]" } @subtitle = "#{cat_str} " + (strip_subtitle || '') @strip_subtitle = strip_subtitle end def to_src r = '' r << "\##{@subtitle}\n" if @subtitle r << @body end def html4( date, idx, opt ) r = %Q[
      \n] r << do_html4( date, idx, opt ) r << "
      \n" end def do_html4( date, idx, opt ) r = '' subtitle = to_html('# ' + @subtitle) subtitle = subtitle.sub(/(\[([^\[]+?)\])+/) { $&.gsub(/\[(.*?)\]/) { $1.split(/,/).collect {|c| %Q|<%= category_anchor("#{c}") %>| }.join } } subtitle.sub!(/

      /,%Q[

      ">#{opt['section_anchor']} ]) if opt['anchor'] then subtitle.sub!(/

      /,%Q|[#{@author}]

      |) end r << subtitle r << @body_to_html r end def chtml( date, idx, opt ) r = '' r << to_html(@subtitle) r << @body_to_html r end def to_s to_src end private def to_html(string) r = BlueCloth.new( string ).to_html r.gsub!(/" } r end def get_categories return [] unless @subtitle cat = /(\\?\[([^\[]+?)\\?\])+/.match(@subtitle).to_a[0] return [] unless cat cat.scan(/\\?\[(.*?)\\?\]/).collect do |c| c[0].split(/,/) end.flatten end def strip_subtitle return nil unless @subtitle r = @subtitle.sub(/^((\\?\[[^\[]+?\]\\?)+\s+)?/, '') if r.empty? nil else r end end end class MarkdownDiary include DiaryBase include CategorizableDiary def initialize( date, title, body, modified = Time::now ) init_diary replace( date, title, body ) @last_modified = modified end def style 'Markdown' end def replace( date, title, body ) set_date( date ) set_title( title ) @sections = [] append( body ) end def append( body, author = nil ) section = nil body.each_line do |l| case l when /^\#[^\#]/ @sections << MarkdownSection::new( section, author ) if section section = l else section = '' unless section section << l end end if section section << "\n" unless section=~/\n\n\z/ @sections << MarkdownSection::new( section, author ) end @last_modified = Time::now self end def each_section @sections.each do |section| yield section end end def add_section(subtitle, body) sec = MarkdownSection::new("\n") sec.subtitle = subtitle sec.body = body @sections << sec @sections.size end def delete_section(index) @sections.delete_at(index - 1) end def to_src r = '' each_section do |section| r << section.to_src end r end def to_html( opt, mode = :HTML ) case mode when :CHTML to_chtml( opt ) else to_html4( opt ) end end def to_html4( opt ) r = '' idx = 1 each_section do |section| r << section.html4( date, idx, opt ) idx += 1 end r end def to_chtml( opt ) r = '' idx = 1 each_section do |section| r << section.chtml( date, idx, opt ) idx += 1 end r end def to_s "date=#{date.strftime('%Y%m%d')}, title=#{title}, body=[#{@sections.join('][')}]" end end end tdiary-contrib-5.0.8/style/wikiext_style.rb000066400000000000000000000006201325711763500210570ustar00rootroot00000000000000# wikiext_style.rb: when using wiki style, extends behavior. # # Just place this file into tdiary/style directory. # # Copyright (C) 2012, kdmsnr # You can distribute this under GPL. # module TDiary class WikiextDiary # dummy class end end require "hikidoc" class HikiDoc class HTMLOutput def paragraph(lines) @f.puts "

      #{lines.join("")}

      " end end end tdiary-contrib-5.0.8/tdiary-contrib.gemspec000066400000000000000000000026121325711763500207700ustar00rootroot00000000000000# coding: utf-8 lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'tdiary/contrib/version' Gem::Specification.new do |spec| spec.name = "tdiary-contrib" spec.version = TDiary::Contrib::VERSION spec.authors = ["tDiary contributors"] spec.email = ["support@tdiary.org"] spec.summary = %q{tDiary contributions package} spec.description = %q{tDiary contributions package that includes plugins, styles, utilities, libraries, filters, and extended io.} spec.homepage = "http://www.tdiary.org/" spec.license = "GPL-2 and/or others" spec.files = Dir[ 'README.md', 'README.en.md', 'Rakefile', 'doc/**/*', 'filter/**/*', 'io/**/*', 'js/**/*', 'lib/**/*', 'misc/**/*', 'plugin/**/*', 'spec/**/*', 'style/**/*', 'util/**/*' ] spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ["lib"] spec.add_dependency 'tdiary' spec.add_dependency 'pushbullet_ruby' spec.add_development_dependency "bundler", "~> 1.3" spec.add_development_dependency "rake" spec.add_development_dependency "rspec" spec.add_development_dependency "simplecov" spec.add_development_dependency "webmock" spec.add_development_dependency "pry" end tdiary-contrib-5.0.8/util/000077500000000000000000000000001325711763500154455ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/clean-spam/000077500000000000000000000000001325711763500174655ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/clean-spam/README.ja000066400000000000000000000000721325711763500207350ustar00rootroot00000000000000See http://www.namazu.org/~satoru/diary/20040923.html#p01 tdiary-contrib-5.0.8/util/clean-spam/tdiary-comment-clean000077500000000000000000000016651325711763500234370ustar00rootroot00000000000000#!/usr/bin/env ruby # # Copyright (C) 2004 Satoru Takabayashi # You can redistribute it and/or modify it under GPL2. # puts "Usage: tdiary-comment-clean PATTERN FILE..." if ARGV.length == 0 pattern = Regexp.new(ARGV.shift) file_names = ARGV deleted_comments = [] file_names.each {|file_name| i = File.open(file_name) first_line = i.gets comments = [] comment = "" while line = i.gets if line == ".\n" comments.push(comment) comment = "" else comment << line end end i.close tmp_name = "tmp.#{Process.pid}" File.open(tmp_name, "w") {|o| o.print first_line comments.each {|comment| if pattern.match(comment) deleted_comments.push(comment) else o.print comment o.puts "." end } } File.rename(file_name, file_name + ".bak") File.rename(tmp_name, file_name) } deleted_comments.each {|comment| print comment puts "." } tdiary-contrib-5.0.8/util/clean-spam/tdiary-comment-clean2000077500000000000000000000033321325711763500235120ustar00rootroot00000000000000#!/usr/bin/env ruby # # Copyright (C) 2004 Satoru Takabayashi # You can redistribute it and/or modify it under GPL2. # # Modified by machu ( http://www.machu.jp/diary/ ) # 2008-03-07: adding last-modified filter with -a and -b option # require 'optparse' after_date = Time.at(0) before_date = Time.now test = false opt = OptionParser.new opt.on('-a AFTER_HOUR') {|v| after_date = Time.at(Time.now - 60 * 60 * v.to_i) } opt.on('-b BEFORE_HOUR') {|v| before_date = Time.at(Time.now - 60 * 60 * v.to_i) } opt.on('-t') {|v| test = true } opt.parse!(ARGV) puts "Usage: tdiary-comment-clean [-a AFTER_HOUR] [-b BEFORE_HOUR] PATTERN FILE..." if ARGV.length == 0 pattern = Regexp.new(ARGV.shift) file_names = ARGV class Comment attr_accessor :body, :date def initialize @body = "" end def <<(body) if body.match(/^Last-Modified: (\d+)$/) @date = Time.at($1.to_i) end @body << body end end deleted_comments = [] file_names.each {|file_name| i = File.open(file_name) first_line = i.gets comments = [] comment = Comment.new while line = i.gets if line == ".\n" comments.push(comment) comment = Comment.new else comment << line end end i.close tmp_name = "tmp.#{Process.pid}" File.open(tmp_name, "w") {|o| o.print first_line comments.each {|comment| if pattern.match(comment.body) and (before_date > comment.date) and (after_date < comment.date) deleted_comments.push(comment) else o.print comment.body o.puts "." end } } File.rename(file_name, file_name + ".bak") unless test File.rename(tmp_name, file_name) unless test } deleted_comments.each {|comment| print comment.body puts "." } tdiary-contrib-5.0.8/util/clean-spam/tdiary-referer-clean000077500000000000000000000020041325711763500234130ustar00rootroot00000000000000#!/usr/bin/env ruby # # Copyright (C) 2004 Satoru Takabayashi # You can redistribute it and/or modify it under GPL2. # puts "Usage: tdiary-referer-clean PATTERN FILE..." if ARGV.length == 0 pattern = Regexp.new(ARGV.shift) file_names = ARGV deleted_referers = [] file_names.each {|file_name| tmp_name = "tmp.#{Process.pid}" i = File.open(file_name) o = File.open(tmp_name, "w") first_line = i.gets o.print first_line while true date_line = i.gets break if date_line.nil? raise unless /^Date: /.match(date_line) blank_line = i.gets raise unless blank_line == "\n" o.print date_line o.print blank_line while line = i.gets if line == ".\n" o.print line next end if pattern.match(line) deleted_referers.push(line) else o.print line end end end i.close o.close File.rename(file_name, file_name + ".bak") File.rename(tmp_name, file_name) } deleted_referers.each {|referer| print referer } tdiary-contrib-5.0.8/util/convert_pstore.rb000066400000000000000000000025121325711763500210460ustar00rootroot00000000000000# # convert utf-8 in pstore. # # usage: convert_pstore.rb file1 # $KCODE = 'u' require 'nkf' require "pstore" begin require "iconv" rescue LoadError end def convert_pstore( file ) db = PStore.new( file ) begin roots = db.transaction{ db.roots } rescue ArgumentError if /\Aundefined class\/module (.+?)(::)?\z/ =~ $!.message klass = $1 if /EmptdiaryString\z/ =~ klass eval( "class #{klass} < String; end" ) else eval( "class #{ klass}; end" ) end retry end end db.transaction do roots.each do |root| convert_element( db[root] ) end end end def convert_element( data ) case data when Hash, Array data.each_with_index do |e, i| if String === e data[i] = migrate_to_utf8( e ) else convert_element( e ) end end else data.instance_variables.each do |e| var = data.instance_variable_get( e ) if String === var data.instance_variable_set( e, migrate_to_utf8( var ) ) else convert_element( var ) end end end end def migrate_to_utf8( str ) to_native( str, 'EUC-JP' ) end def to_native( str, charset = nil ) begin Iconv.conv('utf-8', charset || 'utf-8', str) rescue from = case charset when /^utf-8$/i 'W' when /^shift_jis/i 'S' when /^EUC-JP/i 'E' else '' end NKF::nkf("-m0 -#{from}w", str) end end convert_pstore( ARGV[0] ) tdiary-contrib-5.0.8/util/estraier-search/000077500000000000000000000000001325711763500205265ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/estraier-search/ChangeLog000066400000000000000000000020161325711763500222770ustar00rootroot000000000000002007-02-23 SHIBATA Hiroshi * estraier-search.rb: add override whatsnew plugin. 2007-02-18 Kazuhiko * estraier-search.rb: add 'require "date"'. 2007-02-16 Kazuhiko * estraier-register.rb, estraier-search.rb: rename @last_modified attribute to @mdate. * estraier-register.rb: register all visible comments (ie. not limit to 100). 2007-02-15 Kazuhiko * estraier-search.rb, estraier.rhtml: support similarity search. * estraier-register.rb, estraier-search.rb: support "estraier.with_user_name" option. * estraier-search.rb, estraier.rhtml: support changing a phrase format. 2007-02-14 Kazuhiko * estraier.rxml: add guid elements and escape contents of description elements. * estraier-register.rb, estraier-search.rb: add the 'estraier.path' variable. * estraier.rhtml: revise for more tdiary-like outputs. 2007-02-13 Kazuhiko * initial release: ported from rast-search. tdiary-contrib-5.0.8/util/estraier-search/README.ja000066400000000000000000000104741325711763500220050ustar00rootroot00000000000000estraier-search README =================== Hyper Estraier を用いた tDiary 検索環境です。 特徴 ---------- 日記の更新と連動して自動的にインデックスを更新するので、いつでも最新の 情報で検索することができます。日記を HTML 化した後に必要な部分だけを取 り出してインデックスを作成するので、ヘッダやフッタなどによる検索ノイズ がなく、また、プラグインの出力が検索対象になるという特徴があります。 必要なもの ---------- * tDiary 1.5 以降 * Ruby 1.8.2 以降 * Hyper Estraier 1.4 以降 (ピュアRubyインターフェイス estraierpure.rb も必要です) セットアップ ------------ 1. estraier-register.rb を tDiary の プラグインディレクトリにコピーします。 2. estraier-search.rb を tDiary の index.rb があるディレクトリにコピー します。必要なら index.rb と同じようにシンボリックリンクを張ったり 名前を変えたりしてください。 3. CGI として実行可能にします。 $ chmod a+x estraier-search.rb 4. 必要なら #! のパスを変更します。 5. estraier.rhtml と estraier.rxml と i.estraier.rhtml を tDiary の skel/ ディレクトリにコピーします。 6. Hyper Estraier のノードマスタをセットアップします。その際、設定ファ イル(ノードマスタのrootdirの下の_conf)に、以下を追加してください。 attrindex: @uri{{!}}str この設定がないと、登録エントリが増えた際に、著しくパフォーマンスが 低下します。 7. ノードマスタから、tDiary用のノードサーバを作成し、その接続情報を tdiary.conf に記述します。デフォルトでは、以下のように記述したのと 同じ設定です。 @options["estraier.host"] = "localhost" @options["estraier.port"] = 1978 @options["estraier.path"] = "/node/" @options["estraier.node"] = "tdiary" @options["estraier.name"] = "admin" @options["estraier.password"] = "admin" 8. estraier-register.rb プラグインを有効にします。(tDiary の plugin/ ディレクトリにコピーするか、プラグイン選択のディレクトリにコピーし てブラウザから有効に設定します。言語リソースファイルの en/estraier-register.rb と ja/estraier-register.rb も、プラグインディ レクトリの en/ 以下およびja/ 以下にコピーしてください。) 9. 既存の日記コンテンツに対して検索インデックスを作成します。tDiary の 設定画面から「Estraier検索」を選び、「Estraier検索のインデックスを 再構築する場合は、チェックボックスをチェックしてOKを押してください」 というメッセージに従ってチェックしてOKを押すと、 インデックスの作成は、tDiary の CGI の実行権限で以下のように実行する ことでも可能です。 ruby estraier-register.rb [-p tdiary.rbのあるディレクトリ] [-c tdiary.confのあるディレクトリ] 10. 自分の tDiary の好きな場所 (例えばヘッダ) に以下のようなフォームを加 えてください。 search-form.rb プラグインを有効にしている場合は、以下のように書くこ ともできます。 <%= search_form("estraier-search.rb", "query") %> 以上です。 検索のしかた ------------ estraier-search の検索対象は、日記本文、ツッコミ、TrackBack です。 検索方法については、 http://hyperestraier.sourceforge.net/uguide-ja.html#searchcond をご覧 ください。検索条件の書式を指定していない場合は、「簡便書式」で検索を行 います。 連絡先 ------ かずひこ http://www.fdiary.net/ バグ報告は以下のどこかにお願いします。 * tdiary-devel ML * 直接メール tdiary-contrib-5.0.8/util/estraier-search/en/000077500000000000000000000000001325711763500211305ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/estraier-search/en/estraier-register.rb000066400000000000000000000003361325711763500251170ustar00rootroot00000000000000@estraier_register_conf_label = 'Estraier Search' @estraier_register_conf_header = 'Rebuild Estraier search index' @estraier_register_conf_description = 'To rebuild Estraier search index, check the box and submit \'OK\'.' tdiary-contrib-5.0.8/util/estraier-search/estraier-register.rb000077500000000000000000000164221325711763500245230ustar00rootroot00000000000000#!/usr/bin/env ruby # estraier-register.rb # # Copyright (C) 2007 Kazuhiko # You can redistribute it and/or modify it under GPL2. # require "estraierpure" unless $tdiary_estraier_register_loaded $tdiary_estraier_register_loaded ||= true mode = "" if $0 == __FILE__ require 'cgi' ARGV << '' # dummy argument against cgi.rb offline mode. @cgi = CGI::new mode = "CMD" else mode = "PLUGIN" end if mode == "CMD" tdiary_path = "." tdiary_conf = "." $stdout.sync = true def usage puts "hyper-estraier-register.rb $Revision: 1.1.2.13 $" puts " register to hyper-estraier index files from tDiary's database." puts " usage: ruby hyper-estraier-regiser.rb [-p ] [-c ]" exit end require 'getoptlong' parser = GetoptLong::new parser.set_options(['--path', '-p', GetoptLong::REQUIRED_ARGUMENT], ['--conf', '-c', GetoptLong::REQUIRED_ARGUMENT]) begin parser.each do |opt, arg| case opt when '--path' tdiary_path = arg when '--conf' tdiary_conf = arg end end rescue usage exit( 1 ) end tdiary_conf = tdiary_path unless tdiary_conf Dir::chdir( tdiary_conf ) begin $:.unshift tdiary_path require "#{tdiary_path}/tdiary" rescue LoadError $stderr.puts "hyper-estraier-register.rb: cannot load tdiary.rb. <#{tdiary_path}/tdiary>\n" $stderr.puts " usage: ruby hyper-estraier-regiser.rb [-p ] [-c ]" exit( 1 ) end end module ::TDiary # # Database # class EstraierDB attr_accessor :db attr_reader :conf def initialize(conf) @conf = conf @host = @conf["estraier.host"] || "localhost" @port = @conf["estraier.port"] || 1978 @path = @conf["estraier.path"] || "/node/" @node = @conf["estraier.node"] || "tdiary" @name = @conf["estraier.name"] || "admin" @password = @conf["estraier.password"] || "admin" end def transaction db = EstraierPure::Node.new db.set_url("http://#{@host}:#{@port}#{@path}#{@node}") db.set_auth(@name, @password) if db.doc_num < 0 raise "Database not found : http://#{@host}:#{@port}#{@path}#{@node}" end @db = db yield self end def cache_path @conf.cache_path || "#{@conf.data_path}cache" end end # # Register # class EstraierRegister < TDiaryBase def initialize(estraier_db, diary) @db = estraier_db.db super(CGI::new, 'day.rhtml', estraier_db.conf) @diary = diary @date = diary.date @diaries = {@date.strftime('%Y%m%d') => @diary} if @diaries.empty? @plugin = ::TDiary::Plugin::new( 'conf' => @conf, 'cgi' => @cgi, 'cache_path' => @io.cache_path, 'diaries' => @diaries ) def @plugin.apply_plugin_alt( str, remove_tag = false ) apply_plugin( str, remove_tag ) end end def execute(force = false) date = @date.strftime('%Y%m%d') cond = EstraierPure::Condition.new if @conf["estraier.with_user_name"] cond.add_attr("@uri STRBW #{@conf.user_name}:#{date}") else cond.add_attr("@uri STRBW #{date}") end result = @db.search(cond, 0) if result for i in 0...result.doc_num doc_id = result.get_doc(i).attr("@id") @db.out_doc(doc_id) end end return unless @diary.visible? # body index = 0 anchor = '' @diary.each_section do |section| index += 1 @conf['apply_plugin'] = true anchor = "#{date}p%02d" % index title = CGI.unescapeHTML( @plugin.apply_plugin_alt( section.subtitle_to_html, true ).strip ) if title.empty? title = @plugin.apply_plugin_alt( section.body_to_html, true ).strip title = @conf.shorten( CGI.unescapeHTML( title ), 20 ) end last_modified = @diary.last_modified.strftime("%FT%T") body = CGI.unescapeHTML( @plugin.apply_plugin_alt( section.body_to_html, true ).strip ) doc = EstraierPure::Document.new doc.add_attr("@title", title) if @conf["estraier.with_user_name"] doc.add_attr("@uri", "#{@conf.user_name}:#{anchor}") else doc.add_attr("@uri", anchor) end doc.add_attr("@mdate", last_modified) doc.add_hidden_text(title) doc.add_text(body) @db.put_doc(doc) end # comment @diary.each_visible_comment do |comment, index| if /^(TrackBack|Pingback)$/i =~ comment.name anchor = "#{date}t%02d" % index title = "TrackBack (#{comment.name})" else anchor = "#{date}c%02d" % index title = "#{@plugin.comment_description_short} (#{comment.name})" end body = comment.body doc = EstraierPure::Document.new doc.add_attr("@title", title) if @conf["estraier.with_user_name"] doc.add_attr("@uri", "#{@conf.user_name}:#{anchor}") else doc.add_attr("@uri", anchor) end doc.add_attr("@mdate", comment.date.strftime("%FT%T")) doc.add_hidden_text(title) doc.add_text(body) @db.put_doc(doc) end end protected def mode; 'day'; end def cookie_name; ''; end def cookie_mail; ''; end def convert(str) str end end # # Main # class EstraierRegisterMain < TDiaryBase def initialize(conf) super(CGI::new, 'day.rhtml', conf) end def execute(out = $stdout) require 'fileutils' calendar db = EstraierDB.new(conf) db.transaction do |estraier_db| @years.keys.sort.reverse_each do |year| out << "(#{year.to_s}/) " @years[year.to_s].sort.reverse_each do |month| @io.transaction(Time::local(year.to_i, month.to_i)) do |diaries| diaries.sort.reverse_each do |day, diary| EstraierRegister.new(estraier_db, diary).execute out << diary.date.strftime('%m%d ') end false end end end end end end end if mode == "CMD" begin require 'cgi' if TDiary::Config.instance_method(:initialize).arity != 0 # for tDiary 2.1 or later cgi = CGI.new request = TDiary::Request.new(ENV, cgi) conf = TDiary::Config::new(cgi, request) else # for tDiary 2.0 or earlier conf = TDiary::Config::new end conf.header = '' conf.footer = '' conf.show_comment = true conf.hide_comment_form = true conf.show_nyear = false def conf.bot?; true; end TDiary::EstraierRegisterMain.new(conf).execute rescue print $!, "\n" $@.each do |v| print v, "\n" end exit( 1 ) end puts else add_update_proc do conf = @conf.clone conf.header = '' conf.footer = '' conf.show_comment = true conf.hide_comment_form = true conf.show_nyear = false def conf.bot?; true; end diary = @diaries[@date.strftime('%Y%m%d')] TDiary::EstraierDB.new(conf).transaction do |estraier_db| TDiary::EstraierRegister.new(estraier_db, diary).execute(true) end end if !@conf['estraier.hideconf'] && (@mode == 'conf' || @mode == 'saveconf') args = ['estraier_register', @estraier_register_conf_label] args << 'update' if TDIARY_VERSION > '2.1.3' add_conf_proc(*args) do str = <<-HTML

      #{@estraier_register_conf_header}

      HTML if @mode == 'saveconf' if @cgi.valid?( 'estraier_register_rebuild' ) str << '

      The following diaries were registered.

      ' out = '' TDiary::EstraierRegisterMain.new(@conf).execute(out) str << "

      #{out}

      " end end str end end end end # $tdiary_estraier_register_loaded tdiary-contrib-5.0.8/util/estraier-search/estraier-search.rb000077500000000000000000000153271325711763500241470ustar00rootroot00000000000000#!/usr/bin/env ruby # -*- coding: utf-8; -*- # estraier-search.rb $Revision: 1.1.2.12 $ # # Copyright (C) 2007 Kazuhiko # You can redistribute it and/or modify it under GPL2. # BEGIN { $stdout.binmode } begin Encoding::default_external = 'UTF-8' rescue NameError $KCODE = 'n' end require "estraierpure" require "enumerator" require "date" if FileTest::symlink?( __FILE__ ) then org_path = File::dirname( File::readlink( __FILE__ ) ) else org_path = File::dirname( __FILE__ ) end $:.unshift( org_path.untaint ) require 'tdiary' # # class TDiaryEstraier # module TDiary class TDiaryEstraier < ::TDiary::TDiaryBase MAX_PAGES = 20 SORT_OPTIONS = [ ["score", "スコア順"], ["date", "日付順"], ] ORDER_OPTIONS = [ ["asc", "昇順"], ["desc", "降順"], ] FORM_OPTIONS = [ ["simple", "簡便書式"], ["normal", "通常書式"], ] NUM_OPTIONS = [10, 20, 30, 50, 100] def initialize( cgi, rhtml, conf ) super @host = @conf["estraier.host"] || "localhost" @port = @conf["estraier.port"] || 1978 @path = @conf["estraier.path"] || "/node/" @node = @conf["estraier.node"] || "tdiary" parse_args format_form if @query.empty? @msg = '検索条件を入力して、「検索」ボタンを押してください' else search end end def load_plugins super # add a opensearch rss link @plugin.instance_variable_get('@header_procs').unshift Proc.new { cgi_url = @conf.base_url.sub(%r|/[^/]*$|, '/') + (@cgi.script_name ? _(File.basename(@cgi.script_name)) : '') %Q|\t\n| } # override some plugins def @plugin.sn(number = nil); ''; end def @plugin.whats_new; ''; end end def eval_rxml require 'time' load_plugins ERB::new( File::open( "#{PATH}/skel/estraier.rxml" ){|f| f.read }.untaint ).result( binding ) end private def parse_args @query = @cgi["query"].strip @start = @cgi["start"].to_i @num = @cgi["num"].to_i if @num < 1 @num = 10 elsif @num > 100 @num = 100 end @sort = @cgi["sort"].empty? ? "score" : @cgi["sort"] @order = @cgi["order"].empty? ? "desc" : @cgi["order"] @form = @cgi["form"].empty? ? "simple" : @cgi["form"] end def search @db = EstraierPure::Node.new @db.set_url("http://#{@host}:#{@port}#{@path}#{@node}") begin t = Time.now cond = create_search_options cond.set_phrase(convert(@query)) @result = @db.search(cond, 0) @secs = Time.now - t rescue @msg = "エラー: #{_($!.to_s + $@.join)}

      " end end def format_result_item(item) @date = item.attr('@uri') if @conf["estraier.with_user_name"] @date.gsub!(/.*:/, "") end @date_str = Date.parse(@date).strftime(@conf.date_format) @last_modified = item.attr('@mdate') @title = _(item.attr('@title')) @summary = _(item.snippet).gsub(/\t.*/, "").gsub(/\n\n/, " ... ").delete("\n") for term in @query.split @title.gsub!(Regexp.new(Regexp.quote(CGI.escapeHTML(term)), true, @encoding), "\\&") @summary.gsub!(Regexp.new(Regexp.quote(CGI.escapeHTML(term)), true, @encoding), "\\&") end query = "[SIMILAR]" item.keywords.split(/\t/).each_slice(2).collect do |k, s| query << " WITH #{s} #{k}" end @similar = "%s?query=%s" % [_(@cgi.script_name || ""), CGI::escape(query)] end def format_links(result) page_count = (result.doc_num - 1) / @num + 1 current_page = @start / @num + 1 first_page = current_page - (MAX_PAGES / 2 - 1) if first_page < 1 first_page = 1 end last_page = first_page + MAX_PAGES - 1 if last_page > page_count last_page = page_count end buf = "

      \n" if current_page > 1 buf.concat(format_link("前へ", @start - @num, @num)) end if first_page > 1 buf.concat("... ") end for i in first_page..last_page if i == current_page buf.concat("#{i} ") else buf.concat(format_link(i.to_s, (i - 1) * @num, @num)) end end if last_page < page_count buf.concat("... ") end if current_page < page_count buf.concat(format_link("次へ", @start + @num, @num)) end buf.concat("

      \n") return buf end def format_anchor(start, num) return format('?query=%s;start=%d;num=%d;sort=%s;order=%s', CGI::escape(@query), start, num, _(@sort), _(@order)) end def format_link(label, start, num) return format('
      %s ', _(@cgi.script_name ? @cgi.script_name : ""), format_anchor(start, num), _(label)) end def create_search_options cond = EstraierPure::Condition.new if @conf["estraier.with_user_name"] cond.add_attr("@uri STRBW #{@conf.user_name}:") end if @sort == "date" order = "@uri" else order = "" end if @order == "asc" order = "[SCA]" if order.empty? else unless order.empty? order << " STRD" end end if @form == "simple" cond.set_options(EstraierPure::Condition::SIMPLE) end cond.set_order(order) return cond end def format_options(options, value) return options.collect { |val, label| if val == value "" else "" end }.join("\n") end def format_form @num_options = NUM_OPTIONS.collect { |n| if n == @num "" else "" end }.join("\n") @sort_options = format_options(SORT_OPTIONS, @sort) @order_options = format_options(ORDER_OPTIONS, @order) @form_options = format_options(FORM_OPTIONS, @form) end def _(str) CGI::escapeHTML(str) end def convert(str) @conf.to_native(str) end end end begin @cgi = CGI::new if ::TDiary::Config.instance_method(:initialize).arity != 0 # for tDiary 2.1 or later request = ::TDiary::Request.new(ENV, @cgi) conf = ::TDiary::Config::new(@cgi, request) else # for tDiary 2.0 or earlier conf = ::TDiary::Config::new end tdiary = TDiary::TDiaryEstraier::new( @cgi, 'estraier.rhtml', conf ) head = { 'type' => 'text/html', 'Vary' => 'User-Agent' } if @cgi['type'] == 'rss' head['type'] = "application/xml; charset=#{conf.encoding}" body = tdiary.eval_rxml else body = tdiary.eval_rhtml end head['charset'] = conf.encoding head['Content-Length'] = body.bytesize.to_s head['Pragma'] = 'no-cache' head['Cache-Control'] = 'no-cache' print @cgi.header( head ) print body rescue Exception if @cgi then print @cgi.header( 'type' => 'text/plain' ) else print "Content-Type: text/plain\n\n" end puts "#$! (#{$!.class})" puts "" puts $@.join( "\n" ) end tdiary-contrib-5.0.8/util/estraier-search/estraier.rhtml000066400000000000000000000036561325711763500234260ustar00rootroot00000000000000
      <%%=navi_user%>

      <%= _(@conf.html_title) %> [全文検索]

      検索方法

      並べ替え: 表示件数: 検索条件の書式:

      <% if @msg %>

      <%= @msg %>

      <% else %> <% @end = [@result.doc_num, @start + @num].min %>

      <%= _(@conf.to_native(@query)) %> の検索結果 <%= @result.doc_num %> 件中 <%= @start + 1 %> - <%= @end %> 件目 (<%= @secs %> 秒)

      <% if @result.doc_num > @num %> <%= format_links(@result) %> <% end %> <% for i in @start...@end %> <% item = @result.get_doc(i) || next %> <% format_result_item(item) %>

      <%= @date_str %> [類似検索]

      <%= @conf.section_anchor %><%= @conf.to_native(@title) %>

      <%= @conf.to_native(@summary) %>

      <%= @conf.comment_anchor %>  (スコア:<%= item.attr("#nodescore") %>)

      <% end %> <% if @result.doc_num > @num %> <%= format_links(@result) %> <% end %> <% end %> tdiary-contrib-5.0.8/util/estraier-search/estraier.rxml000066400000000000000000000024031325711763500232470ustar00rootroot00000000000000"?> <%= _( @conf.html_title ) %> [全文検索]: <%= _(@query) %> <%= @conf.base_url.sub(%r|/[^/]*$|, '/') %><%= _(@cgi.script_name ? File.basename(@cgi.script_name) : "") %><%= format_anchor(@start, @num) %> HyperEstraier 検索: <%= _(@query) %> ja-JP <%= @result.doc_num %> <%= @start + 1 %> <%= @num %> <% for i in @start...@start+@num %> <% item = @result.get_doc(i) || next %> <% format_result_item(item) %> <%= _(@date.sub(/^(\d{4})(\d{2})(\d{2}).*/, "\\1-\\2-\\3")) %> <%= _(@conf.to_native(@title)) %> <%= @conf.base_url %><%= @plugin.anchor(@date) %> <%= _(CGI.rfc1123_date(Time.parse(@last_modified))) %> <%= _(@conf.to_native(@summary)) %> <%= @conf.base_url %><%= @plugin.anchor(@date) %> <% end %> tdiary-contrib-5.0.8/util/estraier-search/i.estraier.rhtml000066400000000000000000000017041325711763500236450ustar00rootroot00000000000000

      <%= _(@conf.html_title) %> [全文検索]

      並べ替え: 表示件数:

      <% if @msg %>

      <%= @msg %>

      <% else %>

      <%= @result.doc_num %>件中<%= @start + 1 %>-<%= [@result.doc_num, @start + @num].min %>件目

      <% for i in @start...@start+@num %><% item = @result.get_doc(i) || next %><% format_result_item(item) %>

      <%= _(@date.sub(/^(\d{4})(\d{2})(\d{2}).*/, "\\1-\\2-\\3")) %><%= @conf.to_native(@title) %>(スコア:<%= item.attr("#nodescore") %>)

      <% end %> <% if @result.doc_num > @num %> <%= format_links(@result) %> <% end %> <% end %> tdiary-contrib-5.0.8/util/estraier-search/ja/000077500000000000000000000000001325711763500211205ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/estraier-search/ja/estraier-register.rb000066400000000000000000000004651325711763500251120ustar00rootroot00000000000000@estraier_register_conf_label = 'Estraier検索' @estraier_register_conf_header = 'Estraier検索インデックスの再構築' @estraier_register_conf_description = 'Estraier検索のインデックスを再構築する場合は、チェックボックスをチェックしてOKを押してください。' tdiary-contrib-5.0.8/util/image-gallery/000077500000000000000000000000001325711763500201645ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/image-gallery/README.ja000066400000000000000000000020411325711763500214320ustar00rootroot00000000000000tDiary Image Gallery Ver 2.1.0 -- README.ja -- Copyright (c) 2005-2014 N.KASHIJUKU You can redistribute it and/or modify it under GPL2. =================== ■概要 image or image_ex プラグインで日記に貼り付けた画像ファイルの一覧表示ページを生成する、  tDiaryの拡張機能(プラグイン & Ruby CGI)です。 ■使い方の詳細は…  以下のサイトをご覧下さい。 ・ドキュメント・サイト    http://exception.rash.jp/tdiary/image-gallery2.html ・作者の日記のサポート・ページ    http://exception.rash.jp/diary/?date=20010101 ■サンプルは…  ・作者の日記    http://exception.rash.jp/diary/  ・Image Gallery Listモード http://exception.rash.jp/diary/image-gallery.rb  ・Image Gallery SideShowモード http://exception.rash.jp/diary/image-gallery.rb?mode=slide  ・Image Gallery Viewerモード http://exception.rash.jp/diary/image-gallery.rb?mode=viewer;key=20090222_0 tdiary-contrib-5.0.8/util/image-gallery/image-gallery.rb000077500000000000000000000407101325711763500232350ustar00rootroot00000000000000#!/usr/bin/env ruby # -*- coding: utf-8 -*- # image-gallery.rb $Revision: 2.1.0 $ # # Copyright (c) 2005-2013 N.KASHIJUKU # You can redistribute it and/or modify it under GPL2. if RUBY_VERSION >= '1.9.0' Encoding::default_external = 'UTF-8' $LOAD_PATH.push('./') end if FileTest::symlink?( __FILE__ ) then org_path = File::dirname( File::readlink( __FILE__ ) ) else org_path = File::dirname( __FILE__ ) end $:.unshift( org_path.untaint ) $:.unshift( (org_path + '/lib').untaint ) unless $:.include?( org_path + '/lib' ) require 'tdiary' require 'pstore' require 'date' # class TDiaryGallery # module TDiary class ImageData attr_reader :file, :url, :title, :subtitle, :date, :width, :height, :type attr_writer :file, :url, :title, :subtitle, :date, :width, :height, :type end class TDiaryGallery < ::TDiary::TDiaryBase MAX_PAGES = 20 ORDER_OPTIONS = [ ["asc", "新しい順"], ["desc", "古い順"], ] MODE_OPTIONS = [ ["list", "リスト"], ["slide", "スライド"], ] def initialize( cgi, rhtml, conf ) super @img_version = "2.1.0" @image_hash = Hash[] @image_num = 0 @image_keys = [] @images = [] @exifstr = [] @t_page_title = "" get_conf(conf) parse_args(cgi) format_form read_cache make_image_data check_name_filter_dateformat make_page_title end private def get_conf(conf) @column = conf.options['image-gallery.column'].to_i @column = 3 if @column == 0 @line = conf.options['image-gallery.line'].to_i @line = 4 if @line == 0 @num = @line * @column @width = conf.options['image-gallery.width'] @width = "160" if @width == nil @vwidth = conf.options['image-gallery.vwidth'] @vwidth = "640" if @vwidth == nil @show_exif = conf.options['image-gallery.show_exif'] @show_exif = false if @show_exif == nil @use_mid_image = conf.options['image-gallery.use_mid_image'] @use_mid_image = false if @use_mid_image == nil end def parse_args(cgi) @start = cgi["start"].to_i @order = @cgi["order"].empty? ? "asc" : @cgi["order"] @name_filter = @cgi["name"].empty? ? "" : @cgi["name"].strip @title_filter = @cgi["title"].empty? ? "" : @cgi["title"].strip @subtitle_filter = @cgi["subtitle"].empty? ? "" : @cgi["subtitle"].strip @mode = @cgi["mode"].empty? ? "list" : @cgi["mode"].strip @mode = "list" if @mode != "viewer" and @mode != "slide" and @mode != "fslide" @key = cgi["key"].empty? ? "" : cgi["key"].strip @page_title = cgi["pagetitle"].empty? ? "" : @cgi["pagetitle"].strip @show_inputfield = true; show_inputfield = @cgi["showinputfield"].strip @show_inputfield = false if show_inputfield == "false" end def read_cache begin db = PStore.new("#{@io.cache_path}/gallery/image-gallery2.dat") # for tDiary 3.1.3 or later rescue db = PStore.new("#{cache_path}/gallery/image-gallery2.dat") # for tDiary 3.1.2 or faster end db.transaction do @image_hash = db["recent_image_hash"] @image_keys = db["recent_image_keys"] @image_url = db["recent_image_url"] @image_dir = db["recent_image_dir"] db.abort end end def make_image_data if @name_filter != "" or @title_filter != "" or @subtitle_filter != "" @image_keys.reject! { |key| image = @image_hash[key] (@name_filter != "" and image.file.match(@name_filter) == nil) or (@title_filter != "" and image.title.match(@title_filter) == nil) or (@subtitle_filter != "" and image.subtitle.match(@subtitle_filter) == nil) } end @image_num = @image_keys.length @image_keys = @image_keys.reverse if @order == "asc" if @mode == "list" or @mode == "slide" or @mode == "fslide" if @key != "" index = @image_keys.index(@key) if index != nil @start = (index / @num) * @num else return end end @num.times do |i| index = @start + i break if @image_keys[index] == nil @images.push(@image_hash[@image_keys[index]]) end elsif @mode == "viewer" if @key != "" index = @image_keys.index(@key) if index != nil @start = index else @start = 0 end end @images.push(@image_hash[@image_keys[@start]]) width, height = @images[0].width.to_i, @images[0].height.to_i size = ((width > height ? width : height) > @vwidth.to_i) ? @vwidth : width if width > height @sizestr = %Q[width="#{size}" height="#{(size.to_i*height/width).to_s}"] else @sizestr = %Q[width="#{(size.to_i*width/height).to_s}" height="#{size}"] end if @show_exif and @images[0].type == "jpg" begin require 'exifparser' @exifstr = read_exif_data("#{@image_dir}/#{@images[0].file}") rescue exp = [] exp.push(($!).to_s) ($!).backtrace.each do |btinfo| exp.push(btinfo) end @exifstr = exp end end end end def check_name_filter_dateformat @page_year = "" @page_month = "" @page_day = "" @page_date = nil return if @name_filter == "" t_name_filter = @name_filter.dup t_name_filter["^"] = "" if t_name_filter[0] == ?^ t_name_filter = t_name_filter[5,8] if t_name_filter[4] == ?/ begin if t_name_filter.index(/[\d]{8}/) != nil @page_year = t_name_filter[0,4] @page_month = t_name_filter[4,2] @page_day = t_name_filter[6,2] @page_date = Date.new(@page_year.to_i, @page_month.to_i, @page_day.to_i) elsif t_name_filter.index(/[\d]{6}/) != nil @page_year = t_name_filter[0,4] @page_month = t_name_filter[4,2] @page_date = Date.new(@page_year.to_i, @page_month.to_i, 1) elsif t_name_filter.index(/[\d]{4}/) != nil and t_name_filter[0,4].to_i >= 1970 @page_year = t_name_filter[0,4] @page_date = Date.new(@page_year.to_i, 1, 1) end rescue @page_year = "" @page_month = "" @page_day = "" @page_date = nil return end end def make_page_title return if @page_title == "" @t_page_title = String.new(@page_title) @t_page_title.gsub!("@year", @page_year) @t_page_title.gsub!("@month", @page_month) @t_page_title.gsub!("@day", @page_day) begin @t_page_title.gsub!("@subtitle", @images[0].subtitle) rescue end end def format_links(count) page_count = (count - 1) / @num + 1 current_page = @start / @num + 1 first_page = current_page - (MAX_PAGES / 2 - 1) if first_page < 1 first_page = 1 end last_page = first_page + MAX_PAGES - 1 if last_page > page_count last_page = page_count end buf = "

      \n" if current_page > 1 buf << format_link("«先頭へ ", 0, 0, @mode) buf << format_link("<前へ", @start - @num, @num, @mode) end if first_page > 1 buf << "... " end for i in first_page..last_page if i == current_page buf << "#{i} " else buf << format_link(i.to_s, (i - 1) * @num, @num, @mode) end end if last_page < page_count buf << "... " end if current_page < page_count buf << format_link("次へ>", @start + @num, @num, @mode) buf.concat(format_link(" 最後へ»", (page_count - 1) * @num, 0, @mode)) end buf << "

      \n" return buf end def format_link(label, start, num, mode) return format('%s ', _(@cgi.script_name ? @cgi.script_name : ''), mode, make_cgi_param, start, label) end def format_links_viewer buf = "

      \n" if @start == 0 buf << "«前へ" else buf << format_link_viewer("«前へ", @image_keys[@start - 1]) end buf << "  |  " buf << format_link("一覧へ", (@start / @num) * @num, 0, "list") buf << "  |  " if @start == @image_keys.length - 1 buf << "次へ»" else buf << format_link_viewer("次へ»", @image_keys[@start + 1]) end buf << "

      \n" return buf end def format_link_viewer(label, key) return format('%s', _(@cgi.script_name ? @cgi.script_name : ''), make_cgi_param, key, label) end def format_link_viewer_image(key) return format('%s?%smode=viewer;key=%s', _(@cgi.script_name ? @cgi.script_name : ''), make_cgi_param, key) end def format_links_date return "" unless @name_filter != "" and @title_filter == "" and @subtitle_filter == "" begin buf = "

      \n" if @page_day != "" yesterday = (@page_date - 1).strftime("%Y%m%d") tomorrow = (@page_date + 1).strftime("%Y%m%d") buf << format_link_date(%Q[«#{(@page_date - 1).to_s}], yesterday) buf << format('  |  %s  |  ', _(@cgi.script_name ? @cgi.script_name : ''), _(@mode), _(@order), '全画像') buf << format_link_date(%Q[#{(@page_date + 1).to_s}»], tomorrow) elsif @page_month != "" prevmonth = (@page_date << 1).strftime("%Y%m") nextmonth = (@page_date >> 1).strftime("%Y%m") if @name_filter[0] == ?^ and @name_filter[5] == ?/ prevmonth = %Q[^#{prevmonth[0,4]}/#{prevmonth}] nextmonth = %Q[^#{nextmonth[0,4]}/#{nextmonth}] elsif @name_filter[0] == ?^ prevmonth = %Q[^#{prevmonth[0,4]}] nextmonth = %Q[^#{nextmonth[0,4]}] end buf << format_link_date(%Q[«#{(@page_date << 1).to_s[0,7]}], prevmonth) buf << format('  |  %s  |  ', _(@cgi.script_name ? @cgi.script_name : ''), _(@mode), _(@order), '全画像') buf << format_link_date(%Q[#{(@page_date >> 1).to_s[0,7]}»], nextmonth) elsif @page_year != "" year = @page_year.to_i buf << format_link_date(%Q[«#{(year - 1).to_s}], "^"+(year - 1).to_s) buf << format('  |  %s  |  ', _(@cgi.script_name ? @cgi.script_name : ''), _(@mode), _(@order), '全画像') buf << format_link_date(%Q[#{(year + 1).to_s}»], "^"+(year + 1).to_s) end buf << "

      \n" return buf rescue return "" end end def format_link_date(label, name_filter) cgi_params = make_cgi_param if cgi_params.gsub!(/name=[^;]*;/, "name=#{CGI::escape(name_filter)};") == nil cgi_params = "name=" + CGI::escape(name_filter) + ";" + cgi_params end return format('%s', _(@cgi.script_name ? @cgi.script_name : ''), @mode, cgi_params, label) end def format_link_viewer_date(label, name_filter) return format('%s', _(@cgi.script_name ? @cgi.script_name : ''), CGI::escape(name_filter), label) end def format_link_viewer_category(subtitle) buf = "" subtitle.scan(/\[[^\]]*\]/).each do |category| tag = category[1..-2] next if tag[0] == ?[ buf << format('[%s]', _(@cgi.script_name ? @cgi.script_name : ''), CGI::escape("\\[" + tag + "\\]"), tag) end return buf end def format_link_list_category(images) categories = [] images.each do |image| categories |= image.subtitle.scan(/\[[^\]]*\]/) end buf = "" categories.each do |category| tag = category[1..-2] next if tag[0] == ?[ buf << format('[%s]', _(@cgi.script_name ? @cgi.script_name : ''), CGI::escape("\\[" + tag + "\\]"), tag) end return buf end def get_other_mode_link case @mode when "list" format_link("[SLIDESHOW]", @start, @num, "slide") + format_link("[SLIDESHOW(FullScreen)]", @start, @num, "fslide") when "slide" format_link("[LIST]", @start, @num, "list") + format_link("[SLIDESHOW(FullScreen)]", @start, @num, "fslide") when "fslide" format_link("[LIST]", @start, @num, "list") + format_link("[SLIDESHOW]", @start, @num, "slide") end end def make_cgi_param buf = "" buf << "name=#{CGI::escape(@name_filter)};" if @name_filter != "" buf << "title=#{CGI::escape(@title_filter)};" if @title_filter != "" buf << "subtitle=#{CGI::escape(@subtitle_filter)};" if @subtitle_filter != "" buf << "pagetitle=#{CGI::escape(@page_title)};" if @page_title != "" buf << "showinputfield=false;" if not @show_inputfield buf << "order=#{@order};" return buf end def format_options(options, value) return options.collect { |val, label| if val == value "" else "" end }.join("\n") end def format_form @order_options = format_options(ORDER_OPTIONS, @order) @mode_options = format_options(MODE_OPTIONS, @mode ) end def _(str) CGI::escapeHTML(str) end def read_exif_data(file) exifstr = [] str = "" exif = ExifParser.new(file) return exifstr if exif == nil exifstr.push("-- IFD0 (main image) --") exif.each(:IFD0) do |tag| next if tag.name == "Unknown" str = "#{tag.name} : #{tag.to_s}" exifstr.push(str) end exifstr.push("-- Exif SubIFD --") exif.each(:Exif) do |tag| next if tag.name == "Unknown" str = "#{tag.name} : #{tag.to_s}" exifstr.push(str) end exifstr.push("-- MakerNote --") exif.each(:MakerNote) do |tag| next if tag.name == "Unknown" or tag.name == "NikonCameraSerialNumber" str = "#{tag.name} : #{tag.to_s}" exifstr.push(str) end exifstr.push("-- GPS --") exif.each(:GPS) do |tag| next if tag.name == "Unknown" str = "#{tag.name} : #{tag.to_s}" exifstr.push(str) end return exifstr end def js_start_gallery if @mode == "fslide" <<-EOS EOS elsif @mode == "slide" <<-EOS2 EOS2 end end end end begin @cgi = CGI::new if TDiary::Config.instance_method(:initialize).arity == 0 # for tDiary 2.0 or earlier conf = TDiary::Config::new else # for tDiary 2.1 or later request = TDiary::Request.new( ENV, @cgi ) conf = TDiary::Config::new(@cgi, request) end tdiary = TDiary::TDiaryGallery::new( @cgi, 'gallery.rhtml', conf ) head = { 'type' => 'text/html', 'Vary' => 'User-Agent' } body = tdiary.eval_rhtml head['charset'] = conf.encoding head['Content-Length'] = body.bytesize.to_s head['Pragma'] = 'no-cache' head['Cache-Control'] = 'no-cache' print @cgi.header( head ) print body rescue Exception if @cgi then print @cgi.header( 'type' => 'text/plain' ) else print "Content-Type: text/plain\n\n" end puts "#$! (#{$!.class})" puts "" puts $@.join( "\n" ) end tdiary-contrib-5.0.8/util/image-gallery/js/000077500000000000000000000000001325711763500206005ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/000077500000000000000000000000001325711763500233715ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/Changelog000066400000000000000000000041231325711763500252030ustar00rootroot00000000000000v1.0: * Initial release v1.0.1: * Fixed bug in jd.gallery.js that prevented more than 10 images in carousel. * Fixed bug in resizer.php that prevented filenames with extensions in uppercase. v1.2: * Fixed thumbGenerator name * Fixed jumping thumbnails bug * In options: - Added useExternalCarousel (boolean, with carouselElement as an element) - Added populateFrom option (element) - Added showCarouselLabel option (boolean) - Added activateCarouselScroller (boolean) - Added slideInfoZoneSlide (boolean) * Switched to mootools 1.11 * Added plugin support for digitarald's history manager * Made a version compatible with name-spaced mootools (to be used with prototype, jquery or others) v2.0: * Code got cleaner, with some refactored functions. Should still be 80% backward-compatible. * Gallery Set (to select which gallery you want to see and switch between galleries) mode. > (replaces the buggy picture wall in earlier betas). * Changed populate functions (more modular) * Added Flush and recreate functions for slides and carousel * Added transitions engine * Real preloader for the slides. * Preloader for the carousel thanks to Tomocchino's preloader class. * In options: - Added options related to new features - Added thumbIdleOpacity (float) - Allowed carouselElement to be an ID of the element (string) - Added thumbCloseCarousel (boolean) - Added carouselHorizontal (boolean) to prevent spliting the carousel in multiple lines if it's horizontal (default: true) * Transitions (change the effect using defaultTransition option): - Old default is fade. - Real Cross-Fading for transparent PNGs: crossfade. - Fading to background: fadebg. - Some example of a neat fade&slide effect: fadeslideleft. - Continuous scrolling : + continuoushorizontal + continuousvertical v2.1beta1: * Compatible with mootools 1.2 * Fixed carouselHorizontal * Fixed external carousel bug * Update History manager from Digitarald * Added plugin support for digitarald's ReMooz (demozoom.html to see it)tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/css/000077500000000000000000000000001325711763500241615ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/css/ReMooz.css000066400000000000000000000056711325711763500261170ustar00rootroot00000000000000.remooz-element { cursor: -moz-zoom-in; } /** * Box layout */ .remooz-box { position: absolute; top: 0; left: 0; background: #000 no-repeat center; z-index: 100; } .remooz-loading { background-image: url(spinner.gif); } .remooz-body { width: 100%; height: 100%; } .remooz-box-focus.remooz-type-image .remooz-body { cursor: -moz-zoom-out; } .remooz-box-dragging .remooz-body { cursor: move; } /** * Close button */ .remooz-btn-close { position: absolute; left: -15px; top: -15px; width: 30px; height: 30px; text-decoration: none; border: 0; background: url(closebox.png) no-repeat center; visibility: hidden; cursor: pointer; } .remooz-engine-trident4 .remooz-btn-close { background-image: url(closebox.gif); } /** * Caption title */ .remooz-title { position: relative; left: 0; top: 15px; text-align: left; } .remooz-title-bg { position: absolute; left: 0; top: 0; width: 100%; height: 100%; background-color: #000; z-index: 99; -moz-border-radius: 5px; -webkit-border-radius: 5px; /* shadow opacity differs from box shadow because its default set to opacity 0.8 */ -webkit-box-shadow: 0 0 10px rgba(0, 0, 0, 0.9); } .remooz-title-content { position: relative; padding: 5px 15px; color: #fff; z-index: 101; font: 11px/1.5 Verdana, Geneva, Arial, Helvetica, sans-serif; } .remooz-engine-trident4 .remooz-title-bg { display: none; } .remooz-engine-trident4 .remooz-title-content { background-color: #333; } .remooz-title-content h6 { font-size: 1.2em; font-weight: bold; color: #eee; } .remooz-title-content p { color: #eee; } /** * Type specific */ .remooz-type-image img { display: block; border: 0; width: 100%; height: 100%; } /** * Shadow */ .remooz-bg { position: absolute; width: 33px; height: 40px; } .remooz-bg-n { left: 0; top: -40px; width: 100%; background: url(remo_bg_n.png) repeat-x; } .remooz-bg-ne { right: -33px; top: -40px; background: url(remo_bg_ne.png) no-repeat; } .remooz-bg-e { right: -33px; top: 0; height: 100%; background: url(remo_bg_e.png) repeat-y; } .remooz-bg-se { right: -33px; bottom: -40px; background: url(remo_bg_se.png) no-repeat; } .remooz-bg-s { left: 0; bottom: -40px; width: 100%; background: url(remo_bg_s.png) repeat-x; } .remooz-bg-sw { left: -33px; bottom: -40px; background: url(remo_bg_sw.png) no-repeat; } .remooz-bg-w { left: -33px; top: 0; height: 100%; background: url(remo_bg_w.png) repeat-y; } .remooz-bg-nw { left: -33px; top: -40px; background: url(remo_bg_nw.png) no-repeat; } tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/css/img/000077500000000000000000000000001325711763500247355ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/css/img/carrow1.gif000066400000000000000000000003631325711763500270040ustar00rootroot00000000000000GIF89a+++,,,222... 000111///  ***!!!###---  &&&333!,p'$Ag E[u0ϋ`B1*Bap$)!y&)#šT dC',D{kvg,ޑ9R~wOK)BE)@B>7 37$.!;tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/css/img/carrow2.gif000066400000000000000000000003611325711763500270030ustar00rootroot00000000000000GIF89a+++,,,222... 000111///  ***!!!###---  &&&333!,n'AhRGeK,]:'`+ !8y$H Qa5Gh>>DN;(E]HS(F{$N6AC>"@ D" "!;tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/css/img/closebox.gif000066400000000000000000000005371325711763500272470ustar00rootroot00000000000000GIF89a eee%%%===***000qqqRRR򠠠MMMBBB!,` "2B1p Bb ;t H$ :^!l$ǩ8TtH4+#  \&Md`%A$0A]B1z~ B&Ny`A(WyN'W{'NyB&]iAyB*AVBfp." aWd; MH$S^:ug`:7- t NPs ] xq0d5 "B)HPLLƍd_͜9󗛛7koo߿wHccc9` ̄ aBO]eժU@3~ ڹs`~A3g/(r!P1bWW04ϟ?0!}&d) ԶY>}@)))YP;@v1̷@#"""eݻ-0b)2e3q b P8@Algg`D_5J}ƈc11/?Y .ӧAf}-ހ7dˁ[7pEpB+//@1Pp(yxx XRRf֭X*@Yc?yCI߿T @( x߿,޽˗/(r?lLd)02C-f c|Ý;wX LڇwȆֲ `V3''' h把(Nг0}FJyNNXv`a"bB;ԟǏ TL7o9fd=˗W.]Z `>@MM-o\ %WTIz(:t >mg'ٽˀy<|I NHH-2D9Pd,;en`VHH(9%%e&,@j)X+H?a(Ķ@1#8I8>> ߌ׷yyyʹaaa999'''배||| )))<<<dddfffiiiXXX---ΞCCC+++(((@@@NNNէrrrBBB&&&uuukkkǜooo...RRRۊ!},&0|}yyzzy  y}| U) y{AVMQ@3 {(EB'10 ܹ|ߔ;_xd. ̼co %N2ppgY1H ", 1(ubFg" G f [$17Ad Oz@)M@GhYALqx@ :r FT`@+S];FZ*@!K"p.!O0DM%8Ac"&)22(Sz(LK #^$NϟBM 7DTA7AC`Ǿ$%HY@Zj˛?oylڶq!]tտ*Y1cǐ%SY3B=E]xŗ_ fKa\ɗ}%Yf[n5IEUnԱPE`AȋdbN1ˊ AK/bA1H.tG13hёё$Ikā A#؃Ó@FS9ܱN;SITsM6۴/ S1@C,g&"Jhϡ6ZJ\B^$;tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/css/img/fleche1.png000066400000000000000000000051021325711763500267500ustar00rootroot00000000000000PNG  IHDR&0}(gAMA7tEXtSoftwareAdobe ImageReadyqe< IDATxb? l@9lN(BCf԰#a6(f@ n1@0P!9LUq/?F @L4p N`dC?aM2@ 3 XmXJcҌЀ`? i] @,TB9(߿3 cffffFfeee ,,,4q)@usߙ|7V (ʙ 7Œ BH>:gQ %%Kxā /AA"""?GDD|p"V+ﰰ3zzzAr<"aK'OL#oÀ̠B[ ItrrpB6!G3a t_E/4Z@D; X3~!ڵkwHH~ G$..r(@=4p4(}ӧOLvvvI+!_ W__54ggPC*.A~ǏJ{i%!Gyzz|m VȂ*s:9 :ի'͛7 SEE Rp,V@9R&P=u@1@E<0WϟϔFB! LC^z%{a` JܠA`0(_r  ?P@:#@w1 -V[@s~ @3w11oRRR@MVVP &\( * A Zi oP@jqU; J{ 3>@G9@j.13h- \V)5ʡ?h5s@0gdĄG mŀ(9M 7AmR @ʱ3geeM,@\! ̙AMj` ̝7z!@.,Q^^^E޽'T+R5!&.fX3J B/R!+@UU;J֓ϟ?&T%C;+P ߒA9Z$Fh^%B9N }X;} %%.|jٝmΝׯ_O̠>%JYJOCTRp@ J'N 97ns͛݀wE0/u?|=/"=J\uy,.] 69TA6?՟HCo Z qZ9s& Xׯ_T ǁZ t 2*dpn߾}<<|`%A=/>76xTR0o6W‎csZ?m2MБm,qWֵk]_{Uy%!@>xHb0?0q xŊ;ck]rS*-v|!I.Mlxrd Lx#P|AtقeŌ d <1劑̌89ҧQ<ɔ-c]gω6X1'j6ܺw m XfѢ#$OEJj* E@3̚崔%#!U yT,bF&A/@T{sg @A>ss$L4(6܈#$0+- +" -0d$2 )JH`%89"eyf";tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/css/img/fleche2.png000066400000000000000000000055111325711763500267550ustar00rootroot00000000000000PNG  IHDR&0}(gAMA7tEXtSoftwareAdobe ImageReadyqe< IDATxb?@l @, D߁ߑ|3ĂELX PH'Â8!8,OmR810$aN@d?$߿H31fC(-2ifFFF&(`dcc8zpF) 0:& ed^ ySRVf6"љ<}`fU~@ @̇+Mr-r?2~3 PFPh2333pqq% IH-BOL6MϞ=|%8?t<\]]feeed:ׯ_ 1C(G!)﷬cǎ  h+0X!*f{ɽy柔`hr 訟h HarX ZAƿ¿>8p@Ǐ@KYO<:+`_ 7ȁ 9hai@+O\\]vIh!30@ zO?9聿?~T ~2q$arX=@ PW{-..Nײ`ؤ hW@X`u 5 h`޼yryyyIm6wC䨏4!uIr… esss9 alZ:+񉇇[jZ/] E%#!&/_.GQ^n33}DJ||&@_@GW !"cbbcݺu9997>CII70};5@ UpeCj۶mb&t ? ,Z˫Ϡv`k1!b48 \VV,ZZZ7AA/P9+0ҿ@81U@@+pةSjkkm">Gquu= o; @F-u-@r%'.]f )\Ƈ}||- DJ G:7бEI bVВ,ĀmwSj,2@=(fxx1` Z߁ACA.Bt:!tt0B9A0 w9A#:V (m` /@Gߐ[?&.N@(4@lPuW1aж(؀$+0DX@@4mTP] _@@';;_hQkb| W@z  t.E@VXa 1}b03]0`&.pƢ tfD ~r81AZPXa*3ZbźӪѨZrjW+XA-ZpSYK‚vpgɭ;n^św/_ E\8`q&Y]ʴӅYb̀-EB-,,Jk;u]Ǿ,ݻe |7y\䰏Ås_Wݛt Ө-mא`͟~~z݋/v_]xxpƊf1 voNZbHI!YX?8Yh Ao5USta)cs;h\8xTB*GciձƣLʋ& P ^ԗaW&~`JIbnզXo^Wh `4 F}>'Ngjg h+.٠H:أ*M*ꨤj*]ꪬ꫰*무j'! , dihlp,tmx|pHrl:ШtJZجv:( 6ap݃z݆|Jy㙗w=}Ko\?g<,! |_v0XV X[d]b^'ͅjZɵA!v !lsb+ZW/ 6Z^7\"rx v`X$5$#ʸ#*v!{.*a(8ar GfdNa}%B"&hܛ|b]p_m-tݢ2vz)y()fr G+)bBfvvP*{9Zxvu,Q!z^"+kik9gJ`k.Da>#|H卦99>2I8gH@ `.YLf4|҈Fs ,O% l' map2@,Y(fIi+*{r c2httM?4Ԁn7zEF1I،4g/ `,Gpjh-{5TbӭxyZۋHl砇.SEꬷ.~B! , dihlp,tmx|pHrl:ШtJZجv:ix6hpA!M_ x<@lx}ipo}{jon|nwli{km`^+]k  gt Аg hhet}ڈiV4 7P8(``A A.(p@ɓ| )AI `T$P@M2c\fN<\d1քpΞE=)է֠d ThX!A0+䄻wxfz 2ΛC7Fvy%868rLǔV3eH5m軪'oԬYxӮ!gw< 0OAss,HOu K>aA]k0|Λξ{зWw}<]uwY|] 2ũp\P`l]gAymLxȄ5l2 N@c'RL4g`"8/ʸc=V,B5NV$,fN7b)h8&X{)htezʼ' ȷfY烲!z墆ieIgR-_yv*hpy $Ph@ ݂݊;F1Y t2 d<#Zuׄvkoia&1?b+n&BChkna-[E{Er *+Y@$n).2 )&ty$x-yL2^Rd K%4Va_3VI8Fo5nL(7{0mX2l05$h`[y->sЧ} XKG9'*y[3P_ZXYʩ&-LQKvGhOX*wɫnfx2-E7K1 yxޥIo7ݎ8V8|/o<]7G/Wo'! , dihlp,tmx|pHrl:ШtJZجv:g0tqpچ1O yy}u~m{|~jxqov}jwn~poxzzpeg,]wo  h ih~ؒ juuNХG\A?T@0S0$yA L e'QBX`M2g>в2i\ %\,З&ss$Ԙ(d3̣<.Aȕ1hEH0n , `]x%o߿uƣY38V,ٚ*+1g~C fӊUho!]A !ூ $XFxǑU| 'P'jt{~SaL2#^r VWT̊^@>cCx׉Hbw<"w)VK!wvc is)ʓfyщ̜l0|2 ܉Y pb(gz'ꢡ%t)] 4i$ TO,hmg_' 0]lפ77ÜKXYCeq%(6maPD" kagw]Y }ܮ劽v-k%$o{?/q [;?o^ӻ-T=rtB $Pi &z-&_H=l@]gV|ebfe֘ovih3D8tp x኏xMy#:g"vmAbnuPf=f ^0 ~ Ȣ[xXNhԉt#Q%i22֗43&@]&֠eZt(%ߊȚQV7h1 &ommۗXג)(ڱb `v}A!^sܧSZ*Uu~ͅyyIz'AYٙio6'l^N) Տz4f [AuF6Z]8ڋ}뛆2[z oGȚ@lІG05&H, ɯ&g1P`pŌL|-KV؀Mis=h9s Y&\:ۇhrJ-jW]sud3l^HAʉv&ph-/&ܼ8K8\*,yx-<CXn=*|7 6[TtQo'7П! , dihlp,tmx|pHrl:ШtJZجv:);Oano#~x< 7 yye||g~vx o{fzhwy qrwpnGea^+yɂ  ѵۀlvɊmnA$߷ps` X0eB 0$Ǝ$ir#J `\˘%c:g#M-} JRP/ UN<dP ʧ7 Й,bXʝpNP[qu k  Ob72$38[rFYh3GN|z&sB fWAbtZ0܂v^q;[9l .tv<7V^^!j nYuvYd@ Te]Afuq=[f&Z&R&"{n.quAb̂ HY8̊!8׆!1ɣ`P` ^0Ф\ahYRh؍ȧ%`]F @'\rk2@'3>&z9܌o䵝fxʼn͡Ee'LVݕ@sJ&7N0~'ZN\ـ'c^#lڪ"쉭+z|ĩj]Ǟg' v]c/ڐ^&fE!H^ ݆6k9ʫ0Jp &c*kp@x[辙1]Eez&Zsv%~gRۀ\'8k@|z+i[W6^0cvcs3Is}zb3GUp/GW_\?Kp|wu~Wv'p*tzr_= 1cbD.n;]/o'! , dihlp,tmx|pHrl:ШtJZجv:ph4i7f9=x$ِ6=vx|jwzciu p~xfc~y{~yv{o ea^+ `Ô ºy”mٕm“nгCLۛz 0a@Qƒ2j\@/\ԸAE %H'+l1%Ŕ3IL gN |<3ˡ!BSҠ|Zfŕ-K@ 1EچҪpǚj`Ѯjε sӂT@Ykk \ u%e` WÁ&P0as뎶a1굪1T vI~kmC  $(.wʙWH+!za޲oWλq/x`엝b 'ͻ9rl)m* B)ßeA˜Fle}r e!ah!gtۃɇH3*px8`բXcjI` S%kY@o j j][ed%Y0fl)bg g'E&ϭYfqfpxB  G9|g,u\٘l-yU] Qzn)Z-* 暤[*쫦'†JZuW5͹(\}W'4)!ofnj#zغY5cKVl[,YNpYek\ 0]K"ž H ,UZWia:ہͥɌfJ䍎N2jL,'JlB]eZShj^YArcdrWffC+RʲP킧]دR dP̘Ʊs)'pjp lpo#yˍH`;⒫exٕf=7ޞ;]!o'7'! , dihlp,tmx|pHrl:ШtJZجv:P h)l#1O;~x{}~cvw ~|zx| gkk|kyqzd^+ oypo zB90a GE @qA\@#Ǎ rCɓ?-^=Hl/SE'7G/WB! , dihlp,tmx|pHrl:ШtJZجv:(8!6̮{~6x y}~ul lcp tkizzoye^+ {`фzͿ ьyq[ =k$0  (p@ŋ4\̶#ǏDxAI @b%ʕ f,i2ȟ [s$͡' ZNJFw3FScδ8hhh(@`@@Aʝ R5ΝA$jZl6̭`{뮭p_ niH yH +,ʋ1EzeEw{Y,0ٻ ,{8Z 7 '>aAlktqǵ޶q7UY:k=6m* @c%s}eV3GۂX!3!_ b kZff%B`{}^2&[bȕ|}HXF` "h1qS֠Vf{ӥiYMz7AYc&$tԵpnةxxꉀ2v)Emx.e5)W< i T@$|05"HΑZjt~ިx kE+t}'k[[IJV(+!+Apbی'&XmVq2'>;m"^8kay6tIb2&|- 0r$'d"E]\_Λr Xe-Y G]BޟHh.iYIGF4L\%6dɅVo `c +m;\ Hjt#wYH~0q*vk| .ANdBP\+!/`#ꬷNEEn/ !;tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/css/img/open.gif000066400000000000000000000007511325711763500263700ustar00rootroot00000000000000GIF89a*0fff !!!̊$$$xxxKKKZZZWWWNNNrrr---cccϫ```]]]333***ᓓ!0,*@p(tHRl6L-I:MYpJ_  F<q&<M@$@[ @a(5a_2O4IeӦMjϟ?|8H\RR򭼼k//EEE"q  @ p"wp[[Fw@uaaaSLYjlBYapp B#h %Z hf &hKuڵd&^HB`t5,߼y#@GJ LA__* YHBZH۱c Y Hƻy,B3K @x>|ࡖEhfȢ0jYf?Y}O-z @ x/e+$3YM-|}}ͺ@ d4x~bJ}-?%|y 666X<5G`H">>$=d @y)V }'nr,ٳH @LHb3&((,% 3\Â4py]YY9ǏXݻ3!*4 ĄURheeuT߀ Yf CHzT"##a3 q%$$޿G%^x1 )U1@>mmm>Z$*b &,zm2kk'Z]@,kpqqyIEoEa uuZ ] YZ,3/b|FW@L8>@x|\RcS@@ YLd̠m3H> c444,^~L0^d@kAq/~@jE"x[o۶m WH 6 &`@jE" l"GG 5"•@\g@@).00># a(2 |0 6q_ <]v֣˗!T3f@1jg f%gA%: >K@11~ & b,'. +R>-u|ςIENDB`tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/css/img/remo_bg_e.png000066400000000000000000000017361325711763500273700ustar00rootroot00000000000000PNG  IHDR!A pHYs  iCCPPhotoshop ICC profilexc``$PPTR~!11 !/?/020|pYɕ4\PTp(%8 CzyIA c HRvA cHvH3c OIjE s~AeQfzFcJ~RBpeqIjng^r~QA~QbIj ^<#U*( >1H.-*%CC"C= o]KW0cc btY9y!K[z,٦}cg͡3#nM4}2?~ 4]gAMA|Q cHRMz%u0`:o_F0IDATxTű 01Ky^J1=eĨ|RpIENDB`tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/css/img/remo_bg_n.png000066400000000000000000000017321325711763500273750ustar00rootroot00000000000000PNG  IHDR(X pHYs  iCCPPhotoshop ICC profilexc``$PPTR~!11 !/?/020|pYɕ4\PTp(%8 CzyIA c HRvA cHvH3c OIjE s~AeQfzFcJ~RBpeqIjng^r~QA~QbIj ^<#U*( >1H.-*%CC"C= o]KW0cc btY9y!K[z,٦}cg͡3#nM4}2?~ 4]gAMA|Q cHRMz%u0`:o_F,IDATxb``db`!F a0!qPpQE1H/`ZIENDB`tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/css/img/remo_bg_ne.png000066400000000000000000000025271325711763500275450ustar00rootroot00000000000000PNG  IHDR!([, pHYs  iCCPPhotoshop ICC profilexc``$PPTR~!11 !/?/020|pYɕ4\PTp(%8 CzyIA c HRvA cHvH3c OIjE s~AeQfzFcJ~RBpeqIjng^r~QA~QbIj ^<#U*( >1H.-*%CC"C= o]KW0cc btY9y!K[z,٦}cg͡3#nM4}2?~ 4]gAMA|Q cHRMz%u0`:o_FIDATxڬV0Ec{!B e}'C1L#B3d` e#LZ9 b<eU=Lìl dD Fs(Ď=[,Y0cH5(a%ٱeŒSe9*q́VF]du+oyenĖUx烳(čO89ԻW1/q̘*VB8*+U!_Qn3ܞ*|IENDB`tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/css/img/remo_bg_nw.png000066400000000000000000000023361325711763500275650ustar00rootroot00000000000000PNG  IHDR!([, pHYs  iCCPPhotoshop ICC profilexc``$PPTR~!11 !/?/020|pYɕ4\PTp(%8 CzyIA c HRvA cHvH3c OIjE s~AeQfzFcJ~RBpeqIjng^r~QA~QbIj ^<#U*( >1H.-*%CC"C= o]KW0cc btY9y!K[z,٦}cg͡3#nM4}2?~ 4]gAMA|Q cHRMz%u0`:o_F0IDATxڤ DKe8iu9lC7NxE?TXz@^hCglP p`~!ZȀYh)CXvER2;UG܋o,: H! B $A:tm'wCxBT_F_&*M\͍t_;6JIENDB`tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/css/img/remo_bg_s.png000066400000000000000000000017311325711763500274010ustar00rootroot00000000000000PNG  IHDR! 4 pHYs  iCCPPhotoshop ICC profilexc``$PPTR~!11 !/?/020|pYɕ4\PTp(%8 CzyIA c HRvA cHvH3c OIjE s~AeQfzFcJ~RBpeqIjng^r~QA~QbIj ^<#U*( >1H.-*%CC"C= o]KW0cc btY9y!K[z,٦}cg͡3#nM4}2?~ 4]gAMA|Q cHRMz%u0`:o_F+IDATxb`0fb`fb*cdž C-IENDB`tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/css/img/remo_bg_se.png000066400000000000000000000023541325711763500275500ustar00rootroot00000000000000PNG  IHDR!! pHYs  iCCPPhotoshop ICC profilexc``$PPTR~!11 !/?/020|pYɕ4\PTp(%8 CzyIA c HRvA cHvH3c OIjE s~AeQfzFcJ~RBpeqIjng^r~QA~QbIj ^<#U*( >1H.-*%CC"C= o]KW0cc btY9y!K[z,٦}cg͡3#nM4}2?~ 4]gAMA|Q cHRMz%u0`:o_F>IDATxڜk ?C$])k:XaFQJC&B{RzjjX?>UNy4[:I"xNP;h 99^&ɹdY<Z"'@epS=RN. !z1$2>LS9Po5fb!yC| V{4cPCvxB $,㠇p}!'dfĪ'NjZs\7]̶P/OŞd~vvxS7S 鶳?%IENDB`tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/css/img/remo_bg_sw.png000066400000000000000000000023071325711763500275700ustar00rootroot00000000000000PNG  IHDR!! pHYs  iCCPPhotoshop ICC profilexc``$PPTR~!11 !/?/020|pYɕ4\PTp(%8 CzyIA c HRvA cHvH3c OIjE s~AeQfzFcJ~RBpeqIjng^r~QA~QbIj ^<#U*( >1H.-*%CC"C= o]KW0cc btY9y!K[z,٦}cg͡3#nM4}2?~ 4]gAMA|Q cHRMz%u0`:o_FIDATxڌ Cvtil a@ zsF.{VT ]9˻s|tD1H.-*%CC"C= o]KW0cc btY9y!K[z,٦}cg͡3#nM4}2?~ 4]gAMA|Q cHRMz%u0`:o_F'IDATxbd`dF4D23010Aif$:K_IENDB`tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/css/img/spinner.gif000066400000000000000000000030411325711763500271000ustar00rootroot00000000000000GIF89a? %%%666DDDLLLTTT[[[dddlllttt{{{! NETSCAPE2.0!?,n RC~oY-1JeF$v1_oa SFr29?,  8:BS".J#EJ')C-W7"# ,W6C.&>K,C9!;K 6?>$'75-8)+b1)#/(?5)?:>!?!4W1/? >8K>?$:IBA!?, Xp$zD+!=3~/T))@BXr C Ȅ w6D(>IB$0B1D3,?:%A!?,QpXi Bc~6CY[@~g#lAPT:ȆE ~'FD2:C<7 >B.%HMC"31WBA!?, OLH,M?ܢU2? 4B0%Y*@~7jP/D~ JH).{?(<{?A!?,PoY _);^dOXʱ8"$ gr)12Db8 ?*=B1f.f6^A!?, OpňB,CwȅFU!2d21AHߢx$- @~-X=? ?(D0D =?NCA!?, VpH̸S ɼ>SHT.YB 8dDA6 )hB d+h ? ?,C"+?=2"C=a5 qG>7B OGA!?, N0 BEp ! CzZS+䞞_` ~ꩠ8VH( ?4G.M? ?6zG_?HA!?, U3ȟ!B_vѣu SV1 FY꓾M ݘ]>ZX*X "/I8??PG/ )??8i$>?A!?,SWW O\~AWP~(9Fñ6js|G ! 5!'7?&*?0)#C:?!C1/? A;tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/css/jd.gallery.css000066400000000000000000000133661325711763500267370ustar00rootroot00000000000000#myGallery, #myGallerySet, #flickrGallery { width: 720px; height: 720px; z-index:5; border: 0; margin: 0; } .jdGallery a { outline:0; } #flickrGallery { width: 500px; height: 334px; } #myGallery img.thumbnail, #myGallerySet img.thumbnail { display: none; } .jdGallery { overflow: hidden; position: relative; } .jdGallery img { border: 0; margin: 0; } .jdGallery .slideElement { width: 100%; height: 100%; background-color: #000; background-repeat: no-repeat; background-position: center center; background-image: url('img/loading-bar-black.gif'); } .jdGallery .loadingElement { width: 100%; height: 100%; position: absolute; left: 0; top: 0; background-color: #000; background-repeat: no-repeat; background-position: center center; background-image: url('img/loading-bar-black.gif'); } .jdGallery .slideInfoZone { position: absolute; z-index: 10; width: 100%; margin: 0px; left: 0; bottom: 0; height: 40px; background: #333; color: #fff; text-indent: 0; overflow: hidden; } * html .jdGallery .slideInfoZone { bottom: -1px; } .jdGallery .slideInfoZone h2 { padding: 0; font-size: 80%; margin: 0; margin: 2px 5px; font-weight: bold; color: inherit; } .jdGallery .slideInfoZone p { padding: 0; font-size: 60%; margin: 2px 5px; color: #eee; } .jdGallery div.carouselContainer { position: absolute; height: 135px; width: 100%; z-index: 10; margin: 0px; left: 0; top: 0; } .jdGallery a.carouselBtn { position: absolute; bottom: 0; right: 30px; height: 20px; /*width: 100px; background: url('img/carousel_btn.gif') no-repeat;*/ text-align: center; padding: 0 10px; font-size: 13px; background: #333; color: #fff; cursor: pointer; } .jdGallery .carousel { position: absolute; width: 100%; margin: 0px; left: 0; top: 0; height: 115px; background: #333; color: #fff; text-indent: 0; overflow: hidden; } .jdExtCarousel { overflow: hidden; position: relative; } .jdGallery .carousel .carouselWrapper, .jdExtCarousel .carouselWrapper { position: absolute; width: 100%; height: 78px; top: 10px; left: 0; overflow: hidden; } .jdGallery .carousel .carouselInner, .jdExtCarousel .carouselInner { position: relative; } .jdGallery .carousel .carouselInner .thumbnail, .jdExtCarousel .carouselInner .thumbnail { cursor: pointer; background: #000; background-position: center center; float: left; border: solid 1px #fff; } .jdGallery .wall .thumbnail, .jdExtCarousel .wall .thumbnail { margin-bottom: 10px; } .jdGallery .carousel .label, .jdExtCarousel .label { font-size: 13px; position: absolute; bottom: 5px; left: 10px; padding: 0; margin: 0; } .jdGallery .carousel .wallButton, .jdExtCarousel .wallButton { font-size: 10px; position: absolute; bottom: 5px; right: 10px; padding: 1px 2px; margin: 0; background: #222; border: 1px solid #888; cursor: pointer; } .jdGallery .carousel .label .number, .jdExtCarousel .label .number { color: #b5b5b5; } .jdGallery a { font-size: 100%; text-decoration: none; color: inherit; } .jdGallery a.right, .jdGallery a.left { position: absolute; height: 99%; width: 25%; cursor: pointer; z-index:10; filter:alpha(opacity=20); -moz-opacity:0.2; -khtml-opacity: 0.2; opacity: 0.2; } * html .jdGallery a.right, * html .jdGallery a.left { filter:alpha(opacity=50); } .jdGallery a.right:hover, .jdGallery a.left:hover { filter:alpha(opacity=80); -moz-opacity:0.8; -khtml-opacity: 0.8; opacity: 0.8; } .jdGallery a.left { left: 0; top: 0; background: url('img/fleche1.png') no-repeat center left; } * html .jdGallery a.left { background: url('img/fleche1.gif') no-repeat center left; } .jdGallery a.right { right: 0; top: 0; background: url('img/fleche2.png') no-repeat center right; } * html .jdGallery a.right { background: url('img/fleche2.gif') no-repeat center right; } .jdGallery a.open { left: 0; top: 0; width: 100%; height: 100%; } .withArrows a.open { position: absolute; top: 0; left: 25%; height: 99%; width: 50%; cursor: pointer; z-index: 10; background: none; -moz-opacity:0.8; -khtml-opacity: 0.8; opacity: 0.8; } .withArrows a.open:hover { background: url('img/open.png') no-repeat center center; } * html .withArrows a.open:hover { background: url('img/open.gif') no-repeat center center; filter:alpha(opacity=80); } /* Gallery Sets */ .jdGallery a.gallerySelectorBtn { z-index: 15; position: absolute; top: 0; left: 30px; height: 20px; /*width: 100px; background: url('img/carousel_btn.gif') no-repeat;*/ text-align: center; padding: 0 10px; font-size: 13px; background: #333; color: #fff; cursor: pointer; opacity: .4; -moz-opacity: .4; -khtml-opacity: 0.4; filter:alpha(opacity=40); } .jdGallery .gallerySelector { z-index: 20; width: 100%; height: 100%; position: absolute; top: 0; left: 0; background: #000; } .jdGallery .gallerySelector h2 { margin: 0; padding: 10px 20px 10px 20px; font-size: 20px; line-height: 30px; color: #fff; } .jdGallery .gallerySelector .gallerySelectorWrapper { overflow: hidden; } .jdGallery .gallerySelector .gallerySelectorInner div.galleryButton { margin-left: 10px; margin-top: 10px; border: 1px solid #888; padding: 5px; height: 40px; color: #fff; cursor: pointer; float: left; } .jdGallery .gallerySelector .gallerySelectorInner div.hover { background: #333; } .jdGallery .gallerySelector .gallerySelectorInner div.galleryButton div.preview { background: #000; background-position: center center; float: left; border: none; width: 40px; height: 40px; margin-right: 5px; } .jdGallery .gallerySelector .gallerySelectorInner div.galleryButton h3 { margin: 0; padding: 0; font-size: 12px; font-weight: normal; } .jdGallery .gallerySelector .gallerySelectorInner div.galleryButton p.info { margin: 0; padding: 0; font-size: 12px; font-weight: normal; color: #aaa; } tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/css/layout.css000066400000000000000000000020751325711763500262140ustar00rootroot00000000000000body { color: #ccc; font-family: "Trebuchet MS", "Lucida Grande", Arial, Helvetica, sans-serif; margin: 0 auto; padding: 0; font-size: 0.6em; background: #111 url('../images/bg/gradient1.gif') top left repeat-x; } h1 { color: #fff; font-size: 47px; font-weight: bolder; margin: 0 40px; padding: 0.08em 0; } h1 sup { color: #ddd; } h1 a { color: #fff; text-decoration: none; } h1 .company, h1 a .company { color: #d01a71; } h2 { color: #ddd; font-size: 2.5em; } h3 { color: #fff; font-size: 1.5em; } h4 { font-size: 1.3em; } .content { margin: 0 20px; } .content a { color: #fff; } .content p.linkage { margin-top: 2em; text-align: right; font-size: 1.7em; color: #ddd; } .content p.linkage a { color: #fff; } /*.content p.linkage a { color: #fff; background: url('../images/bg/biglink_off.gif') center right no-repeat; padding: 10px 20px; text-decoration: none; } .content p.linkage a:hover { background: url('../images/bg/biglink_on.gif') center right no-repeat; font-style: italic; }*/ #myGallery { text-align: left; margin: 0 auto; }tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/license.txt000066400000000000000000000773271325711763500255740ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONStdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/resizer.php000066400000000000000000000066051325711763500255740ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/scripts/000077500000000000000000000000001325711763500250605ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/scripts/Changelog000066400000000000000000000041231325711763500266720ustar00rootroot00000000000000v1.0: * Initial release v1.0.1: * Fixed bug in jd.gallery.js that prevented more than 10 images in carousel. * Fixed bug in resizer.php that prevented filenames with extensions in uppercase. v1.2: * Fixed thumbGenerator name * Fixed jumping thumbnails bug * In options: - Added useExternalCarousel (boolean, with carouselElement as an element) - Added populateFrom option (element) - Added showCarouselLabel option (boolean) - Added activateCarouselScroller (boolean) - Added slideInfoZoneSlide (boolean) * Switched to mootools 1.11 * Added plugin support for digitarald's history manager * Made a version compatible with name-spaced mootools (to be used with prototype, jquery or others) v2.0: * Code got cleaner, with some refactored functions. Should still be 80% backward-compatible. * Gallery Set (to select which gallery you want to see and switch between galleries) mode. > (replaces the buggy picture wall in earlier betas). * Changed populate functions (more modular) * Added Flush and recreate functions for slides and carousel * Added transitions engine * Real preloader for the slides. * Preloader for the carousel thanks to Tomocchino's preloader class. * In options: - Added options related to new features - Added thumbIdleOpacity (float) - Allowed carouselElement to be an ID of the element (string) - Added thumbCloseCarousel (boolean) - Added carouselHorizontal (boolean) to prevent spliting the carousel in multiple lines if it's horizontal (default: true) * Transitions (change the effect using defaultTransition option): - Old default is fade. - Real Cross-Fading for transparent PNGs: crossfade. - Fading to background: fadebg. - Some example of a neat fade&slide effect: fadeslideleft. - Continuous scrolling : + continuoushorizontal + continuousvertical v2.1beta1: * Compatible with mootools 1.2 * Fixed carouselHorizontal * Fixed external carousel bug * Update History manager from Digitarald * Added plugin support for digitarald's ReMooz (demozoom.html to see it)tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/scripts/History.Routing.js000066400000000000000000000062131325711763500305070ustar00rootroot00000000000000/** * History.Routing * * @version 2.0 * * @license MIT License * @author Harald Kirschner * @copyright 2008 Author */ History.implement(new Options()); History.implement({ options: { separator: ';' }, routes: [], register: function(route) { if (this.routes.push(route) == 1) this.addEvent('changed', this.match); }, unregister: function(route) { this.routes.remove(route); }, match: function(state, previous, manual) { if (!manual) this.routes.each(Function.methodize('match', this.state)); }, generate: function() { return this.routes.map(Function.methodize('generate')).clean().join(this.options.separator); }, update: function() { return this.setState(this.generate()); } }); History.Route = new Class({ Implements: [Events, Options], /** * pattern: Regular expression that matches the string updated from onGenerate * defaults: Default values array, initially empty. * flags: When regexp is a String, this is the second argument for new RegExp. * skipDefaults: default true; generate is not called when current values are similar to the default values. * generate: Should return the string for the state string, values are first argument * onMatch: Will be called when the regexp matches, with the new values as argument. */ options: { skipDefaults: true, defaults: [], pattern: null, flags: '', generate: function(values) { return values[0]; }, onMatch: $empty }, initialize: function(options){ this.setOptions(options); this.pattern = this.options.pattern || '(.*)'; if ($type(this.pattern) == 'string') this.pattern = new RegExp(this.pattern, this.options.flags); this.values = this.defaults = this.options.defaults.slice(); History.register(this); return this; }, setValues: function(values) { if (this.values.toString() == values.toString()) return this; this.values = values; History.update(); return this; }, setValue: function(index, value) { if (this.values[index] == value) return this; this.values[index] = value; History.update(); return this; }, build: function(values) { var tmp = this.values.slice(); this.values = values; var state = History.generate(); this.values = tmp; return state; }, destroy: function() { History.unregister(this); }, generate: function() { if (this.options.skipDefaultMatch && (String(this.values) == String(this.defaults))) return null; return this.options.generate.call(this, this.values); }, match: function(state) { var bits = state.match(this.pattern); var defaults = this.defaults; if (bits) { bits.splice(0, 1); for (var i = 0, j = bits.length; i < j; i++) bits[i] = $pick(bits[i], defaults[i] || null); if (String(bits) != String(defaults)) this.values = bits; } else { this.values = this.defaults.slice(); } this.fireEvent('onMatch', [this.values, this.defaults]); } }); Function.methodize = function(name) { var args = Array.slice(arguments, 1); return function(obj) { return obj[name].apply(obj, args); }; }; tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/scripts/History.js000066400000000000000000000051251325711763500270620ustar00rootroot00000000000000/** * History * * @version 1.0 * * @license MIT License * @author Harald Kirschner * @copyright 2008 Author */ var History = $extend(history, { implement: function(obj) { return $extend(this, obj); } }); History.implement(new Events($empty)); History.implement({ state: null, start: function() { if (this.started) return this; this.state = this.getHash(); if (Browser.Engine.trident) { var iframe = new Element('iframe', { 'src': "javascript:''", 'styles': { 'position': 'absolute', 'top': '-1000px' } }).inject(document.body).contentWindow; var writeState = function(state) { iframe.document.write('Moo!'); iframe.document.close(); }; $extend(this, { '$listener': function(state) { state = decodeURIComponent(state); if (this.state != state) this.setHash(state).changeState(state); }.bind(this), 'setState': function(state, force) { if (this.state != state || force) { if (!force) this.setHash(state).changeState(state, true); writeState(state); } return this; }, 'trace': function() { var state = this.getHash(); if (state != this.state) writeState(state); } }); var check = (function() { if (iframe.document && iframe.document.body) { check = $clear(check); if (!iframe.document.body.innerHTML) this.setState(this.state); } }).periodical(50, this); } else { if (Browser.Engine.presto915) { new Element('img', { 'src': "javascript:location.href='javascript:History.trace();';", 'styles': { 'position': 'absolute', 'top': '-1000px' } }).inject(document.body); } } this.trace.periodical(150, this); this.started = true; return this; }, changeState: function(state, manual) { var stateOld = this.state; this.state = state; this.fireEvent('changed', [state, stateOld, manual]); }, trace: function() { var state = this.getHash(); if (state != this.state) this.changeState(state); }, getHash: function() { var href = location.href, pos = href.indexOf('#') + 1; return (pos) ? href.substr(pos) : ''; }, setHash: function(state) { location.hash = '#' + state; return this; }, setState: function(state) { if (this.state !== state) this.setHash(state).changeState(state, true); return this; }, getState: function() { return this.state; } }); tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/scripts/ReMooz.js000066400000000000000000000256471325711763500266470ustar00rootroot00000000000000/** * ReMooz - Zoomer * * Inspired by so many boxes and zooms * * @version 1.0 * * @license MIT-style license * @author Harald Kirschner * @copyright Author */ var ReMooz = new Class({ Implements: [Events, Options, Chain], options: { link: null, type: 'image', container: null, className: null, centered: false, dragging: true, closeOnClick: true, shadow: (Browser.Engine.trident) ? 'onOpenEnd' : 'onOpen', // performance resize: true, margin: 20, resizeFactor: 0.95, resizeLimit: false, // {x: 640, y: 640} fixedSize: false, cutOut: true, addClick: true, opacityLoad: 0.6, opacityResize: 1, opacityTitle: 0.9, resizeOptions: {}, fxOptions: {}, closer: true, parse: false, // 'rel' parseSecure: false, temporary: false, onBuild: $empty, onLoad: $empty, onOpen: $empty, onOpenEnd: $empty, onClose: $empty, onCloseEnd: $empty, generateTitle: function(el) { var text = el.get('title'); if (!text) return false; var title = text.split(' :: '); var head = new Element('h6', {'html': title[0]}); return (title[1]) ? [head, new Element('p', {'html': title[1]})] : head; } }, initialize: function(element, options) { this.element = $(element); this.setOptions(options); if (this.options.parse) { var obj = this.element.getProperty(this.options.parse); if (obj && (obj = JSON.decode(obj, this.options.parseSecure))) this.setOptions(obj); } var origin = this.options.origin; this.origin = ((origin) ? $(origin) || this.element.getElement(origin) : null) || this.element; this.link = this.options.link || this.element.get('href') || this.element.get('src'); this.container = $(this.options.container) || this.element.getDocument(); this.bound = { 'click': function(e) { this.open.delay(1, this); return false; }.bind(this), 'close': this.close.bind(this), 'dragClose': function(e) { if (e.rightClick) return; this.close(); }.bind(this) }; if (this.options.addClick) this.bindToElement(); }, destroy: function() { if (this.box) this.box.destroy(); this.box = this.tweens = this.body = this.content = null; }, bindToElement: function(element) { ($(element) || this.element).addClass('remooz-element').addEvent('click', this.bound.click); return this; }, getOriginCoordinates: function() { var coords = this.origin.getCoordinates(); delete coords.right; delete coords.bottom; return coords; }, open: function(e) { if (this.opened) return (e) ? this.close() : this; this.opened = this.loading = true; if (!this.box) this.build(); this.coords = this.getOriginCoordinates(); this.coords.opacity = this.options.opacityLoad; this.coords.display = ''; this.tweens.box.set(this.coords); this.box.addClass('remooz-loading'); ReMooz.open(this.fireEvent('onLoad')); this['open' + this.options.type.capitalize()](); return this; }, finishOpen: function() { this.tweens.fade.start(0, 1); this.drag.attach(); this.fireEvent('onOpenEnd').callChain(); }, close: function() { if (!this.opened) return this; this.opened = false; ReMooz.close(this.fireEvent('onClose')); if (this.loading) { this.box.setStyle('display', 'none'); return this; } this.drag.detach(); this.tweens.fade.cancel().set(0).fireEvent('onComplete'); if (this.tweens.box.timer) this.tweens.box.clearChain(); var vars = this.getOriginCoordinates(); if (this.options.opacityResize != 1) vars.opacity = this.options.opacityResize; this.tweens.box.start(vars).chain(this.closeEnd.bind(this)); return this; }, closeEnd: function() { if (this.options.cutOut) this.element.setStyle('visibility', 'visible'); this.box.setStyle('display', 'none'); this.fireEvent('onCloseEnd').callChain(); if (this.options.temporary) this.destroy(); }, openImage: function() { var tmp = new Image(); tmp.onload = tmp.onabort = tmp.onerror = function(fast) { this.loading = tmp.onload = tmp.onabort = tmp.onerror = null; if (!tmp.width || !this.opened) { this.fireEvent('onError').close(); return; } var to = {x: tmp.width, y: tmp.height}; if (!this.content) this.content = $(tmp).inject(this.body); else tmp = null; this[(this.options.resize) ? 'zoomRelativeTo' : 'zoomTo'].create({ 'delay': (tmp && fast !== true) ? 1 : null, 'arguments': [to], 'bind': this })(); }.bind(this); tmp.src = this.link; if (tmp && tmp.complete && tmp.onload) tmp.onload(true); }, /** * @todo Test implementation */ openElement: function() { this.content = this.content || $(this.link) || $E(this.link); if (!this.content) { this.fireEvent('onError').close(); return; } this.content.inject(this.body); this.zoomTo({x: this.content.scrollWidth, y: this.content.scrollHeight}); }, zoomRelativeTo: function(to) { var scale = this.options.resizeLimit; if (!scale) { scale = this.container.getSize(); scale.x *= this.options.resizeFactor; scale.y *= this.options.resizeFactor; } for (var i = 2; i--;) { if (to.x > scale.x) { to.y *= scale.x / to.x; to.x = scale.x; } else if (to.y > scale.y) { to.x *= scale.y / to.y; to.y = scale.y; } } return this.zoomTo({x: to.x.toInt(), y: to.y.toInt()}); }, zoomTo: function(to) { to = this.options.fixedSize || to; var box = this.container.getSize(), scroll = this.container.getScroll(); var pos = (!this.options.centered) ? { x: (this.coords.left + (this.coords.width / 2) - to.x / 2).toInt() .limit(scroll.x + this.options.margin, scroll.x + box.x - this.options.margin - to.x), y: (this.coords.top + (this.coords.height / 2) - to.y / 2).toInt() .limit(scroll.y + this.options.margin, scroll.y + box.y - this.options.margin - to.y) } : { x: scroll.x + ((box.x - to.x) / 2).toInt(), y: scroll.y + ((box.y - to.y) / 2).toInt() }; if (this.options.cutOut) this.element.setStyle('visibility', 'hidden'); this.box.removeClass('remooz-loading'); var vars = {left: pos.x, top: pos.y, width: to.x, height: to.y}; if (this.options.opacityResize != 1) vars.opacity = [this.options.opacityResize, 1]; else this.box.set('opacity', 1); this.tweens.box.start(vars).chain(this.finishOpen.bind(this)); this.fireEvent('onOpen'); }, build: function() { this.addEvent('onBlur', function() { this.focused = false; this.box.removeClass('remooz-box-focus').setStyle('z-index', ReMooz.options.zIndex); }, true); this.addEvent('onFocus', function() { this.focused = true; this.box.addClass('remooz-box-focus').setStyle('z-index', ReMooz.options.zIndexFocus); }, true); var classes = ['remooz-box', 'remooz-type-' + this.options.type, 'remooz-engine-' + Browser.Engine.name + Browser.Engine.version]; if (this.options.className) classes.push(this.options.className); this.box = new Element('div', { 'class': classes.join(' '), 'styles': { 'display': 'none', 'top': 0, 'left': 0, 'zIndex': ReMooz.options.zIndex } }); this.tweens = { 'box': new Fx.Morph(this.box, $merge({ 'duration': 400, 'unit': 'px', 'transition': Fx.Transitions.Quart.easeOut, 'chain': 'cancel' }, this.options.resizeOptions) ), 'fade': new Fx.Tween(null, $merge({ 'property': 'opacity', 'duration': (Browser.Engine.trident) ? 0 : 300, 'chain': 'cancel' }, this.options.fxOptions)).addEvents({ 'onComplete': function() { if (!this.element.get('opacity')) this.element.setStyle('display', 'none'); }, 'onStart': function() { if (!this.element.get('opacity')) this.element.setStyle('display', ''); } } ) }; this.tweens.fade.element = $$(); if (this.options.shadow) { if (Browser.Engine.webkit420) { this.box.setStyle('-webkit-box-shadow', '0 0 10px rgba(0, 0, 0, 0.7)'); } else if (!Browser.Engine.trident4) { var shadow = new Element('div', {'class': 'remooz-bg-wrap'}).inject(this.box); ['n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'].each(function(dir) { new Element('div', {'class': 'remooz-bg remooz-bg-' + dir}).inject(shadow); }); this.tweens.bg = new Fx.Tween(shadow, { 'property': 'opacity', 'chain': 'cancel' }).set(0); this.addEvent(this.options.shadow, this.tweens.bg.set.bind(this.tweens.bg, 1), true); this.addEvent('onClose', this.tweens.bg.set.bind(this.tweens.bg, 0), true); } } if (this.options.closer) { var closer = new Element('a', { 'class': 'remooz-btn-close', 'events': {'click': this.bound.close} }).inject(this.box); this.tweens.fade.element.push(closer); } this.body = new Element('div', {'class': 'remooz-body'}).inject(this.box); var title = this.options.title || this.options.generateTitle.call(this, this.element); if (title) { // thx ie6 var title = new Element('div', {'class': 'remooz-title'}).adopt( new Element('div', {'class': 'remooz-title-bg', 'opacity': this.options.opacityTitle}), new Element('div', {'class': 'remooz-title-content'}).adopt(title) ).inject(this.box); this.tweens.fade.element.push(title); } this.tweens.fade.set(0).fireEvent('onComplete'); this.drag = new Drag.Move(this.box, { 'snap': 15, 'preventDefault': true, 'onBeforeStart': function() { if (!this.focused && !this.loading) ReMooz.focus(this); else if (this.loading || this.options.closeOnClick) this.box.addEvent('mouseup', this.bound.dragClose); }.bind(this), 'onSnap': function() { this.box.removeEvent('mouseup', this.bound.dragClose); if (!this.options.dragging) this.drag.stop(); else this.box.addClass('remooz-box-dragging'); }.bind(this), 'onComplete': function() { this.box.removeClass('remooz-box-dragging'); }.bind(this) }); this.drag.detach(); this.fireEvent('onBuild', this.box, this.element); this.box.inject(this.element.getDocument().body); } }); ReMooz.factory = function(extended) { return $extend(this, extended); }; ReMooz.factory(new Options).factory({ options: { zIndex: 41, zIndexFocus: 42, query: 'a.remooz', modal: false }, assign: function(elements, options) { return $$(elements).map(function(element) { return new ReMooz(element, options); }, this); }, stack: [], open: function(obj) { var last = this.stack.getLast(); this.focus(obj); if (last && this.options.modal) last.close(); }, close: function(obj) { var length = this.stack.length - 1; if (length > 1 && this.stack[length] == obj) this.focus(this.stack[length - 1]); this.stack.erase(obj); }, focus: function(obj) { var last = this.stack.getLast(); obj.fireEvent('onFocus', [obj]); if (last == obj) return; if (last) last.fireEvent('onBlur', [last]); this.stack.erase(obj).push(obj); } });tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/scripts/jd.gallery.js000066400000000000000000000712361325711763500274620ustar00rootroot00000000000000/* This file is part of JonDesign's SmoothGallery v2.1beta1. JonDesign's SmoothGallery is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. JonDesign's SmoothGallery is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with JonDesign's SmoothGallery; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Main Developer: Jonathan Schemoul (JonDesign: http://www.jondesign.net/) Contributed code by: - Christian Ehret (bugfix) - Nitrix (bugfix) - Valerio from Mad4Milk for his great help with the carousel scrolling and many other things. - Archie Cowan for helping me find a bugfix on carousel inner width problem. - Tomocchino from #mootools for the preloader class Many thanks to: - The mootools team for the great mootools lib, and it's help and support throughout the project. - Harald Kirschner (digitarald: http://digitarald.de/) for all his great libs. Some used here as plugins. */ /* some quirks to circumvent broken stuff in mt1.2 */ function isBody(element){ return (/^(?:body|html)$/i).test(element.tagName); }; Element.implement({ getPosition: function(relative){ if (isBody(this)) return {x: 0, y: 0}; var el = this, position = {x: 0, y: 0}; while (el){ position.x += el.offsetLeft; position.y += el.offsetTop; el = el.offsetParent; } var rpos = (relative) ? $(relative).getPosition() : {x: 0, y: 0}; return {x: position.x - rpos.x, y: position.y - rpos.y}; } }); // declaring the class var gallery = { Implements: [Events, Options], options: { showArrows: true, showCarousel: true, showInfopane: true, embedLinks: true, fadeDuration: 500, timed: false, delay: 9000, preloader: true, preloaderImage: true, preloaderErrorImage: true, fullScreen: false, /* Data retrieval */ manualData: [], populateFrom: false, populateData: true, destroyAfterPopulate: true, elementSelector: "div.imageElement", titleSelector: "h3", subtitleSelector: "p", linkSelector: "a.open", imageSelector: "img.full", thumbnailSelector: "img.thumbnail", defaultTransition: "fade", /* InfoPane options */ slideInfoZoneOpacity: 0.7, slideInfoZoneSlide: true, /* Carousel options */ carouselMinimizedOpacity: 0.4, carouselMinimizedHeight: 20, carouselMaximizedOpacity: 0.9, thumbHeight: 75, thumbWidth: 100, thumbSpacing: 10, thumbIdleOpacity: 0.2, textShowCarousel: 'Pictures', showCarouselLabel: true, thumbCloseCarousel: true, useThumbGenerator: false, thumbGenerator: 'resizer.php', useExternalCarousel: false, carouselElement: false, carouselHorizontal: true, activateCarouselScroller: true, carouselPreloader: true, textPreloadingCarousel: 'Loading...', /* CSS Classes */ baseClass: 'jdGallery', withArrowsClass: 'withArrows', /* Plugins: HistoryManager */ useHistoryManager: false, customHistoryKey: false, /* Plugins: ReMooz */ useReMooz: false, useMediaboxAdvanced: false }, initialize: function(element, options) { this.setOptions(options); this.fireEvent('onInit'); this.currentIter = 0; this.lastIter = 0; this.maxIter = 0; this.galleryElement = element; this.topElement = element; this.galleryData = this.options.manualData; this.galleryInit = 1; this.galleryElements = Array(); this.thumbnailElements = Array(); this.galleryElement.addClass(this.options.baseClass); if (this.options.useReMooz&&(this.options.defaultTransition=="fade")) this.options.defaultTransition="crossfade"; this.populateFrom = element; if (this.options.populateFrom) this.populateFrom = this.options.populateFrom; if (this.options.populateData) this.populateData(); element.style.display="block"; if(this.options.fullScreen) { var sizex = window.innerWidth; var sizey = window.innerHeight; element.setStyles({ 'position':'absolute', 'top':'0px', 'left':'0px', 'width':sizex, 'height':sizey }); window.addEvent('resize', function(event) { var sizex = window.innerWidth; var sizey = window.innerHeight; element.setStyles({ 'position':'absolute', 'top':'0px', 'left':'0px', 'width':sizex, 'height':sizey }); }); } if (this.options.useHistoryManager) this.initHistory(); if ((this.options.embedLinks)|(this.options.useReMooz)|(this.options.useMediaboxAdvanced)) { this.currentLink = new Element('a').addClass('open').setProperties({ href: '#', title: '', rel: 'lightbox' }).injectInside(element); if ((!this.options.showArrows) && (!this.options.showCarousel)) this.galleryElement = element = this.currentLink; else this.currentLink.setStyle('display', 'none'); } this.constructElements(); if ((this.galleryData.length>1)&&(this.options.showArrows)) { var leftArrow = new Element('a').addClass('left').addEvent( 'click', this.prevItem.bind(this) ).injectInside(element); var rightArrow = new Element('a').addClass('right').addEvent( 'click', this.nextItem.bind(this) ).injectInside(element); this.galleryElement.addClass(this.options.withArrowsClass); } this.loadingElement = new Element('div').addClass('loadingElement').injectInside(element); if (this.options.showInfopane) this.initInfoSlideshow(); if (this.options.showCarousel) this.initCarousel(); this.doSlideShow(1); }, populateData: function() { currentArrayPlace = this.galleryData.length; options = this.options; var data = $A(this.galleryData); data.extend(this.populateGallery(this.populateFrom, currentArrayPlace)); this.galleryData = data; this.fireEvent('onPopulated'); }, populateGallery: function(element, startNumber) { var data = []; options = this.options; currentArrayPlace = startNumber; element.getElements(options.elementSelector).each(function(el) { elementDict = $H({ image: el.getElement(options.imageSelector).getProperty('src'), number: currentArrayPlace, transition: this.options.defaultTransition }); if ((options.showInfopane) | (options.showCarousel)) elementDict.extend({ title: el.getElement(options.titleSelector).innerHTML, description: el.getElement(options.subtitleSelector).innerHTML }); if ((options.embedLinks) | (options.useReMooz)) elementDict.extend({ link: el.getElement(options.linkSelector).href||false, linkTitle: el.getElement(options.linkSelector).title||false, linkTarget: el.getElement(options.linkSelector).getProperty('target')||false }); if ((!options.useThumbGenerator) && (options.showCarousel)) elementDict.extend({ thumbnail: el.getElement(options.thumbnailSelector).getProperty('src') }); else if (options.useThumbGenerator) elementDict.extend({ thumbnail: options.thumbGenerator + '?imgfile=' + elementDict.image + '&max_width=' + options.thumbWidth + '&max_height=' + options.thumbHeight }); data.extend([elementDict]); currentArrayPlace++; if (this.options.destroyAfterPopulate) el.dispose(); }); return data; }, constructElements: function() { el = this.galleryElement; top_el = this.galleryElement; if (this.options.embedLinks && (!this.options.showArrows)) el = this.currentLink; this.maxIter = this.galleryData.length; var currentImg; for(i=0;i= img.width){ new_height = top_height; new_width = Math.round(top_height*img.width/img.height); } else if(top_width < img.width && img.height <= img.width) { new_width = top_width; new_height = Math.round(top_width*img.height/img.width); if(new_height > top_height) { new_height = top_height; new_width = Math.round(top_height*img.width/img.height); } margin_top = Math.round((top_height - new_height)/2); } else { margin_top = Math.round((top_height - img.height)/2); } img.element.appendChild(new Element('img').set('src',img.source).setStyles({ 'margin':'0 auto', 'display':'block', 'width':new_width+'px', 'height':new_height+'px', 'margin-top':margin_top+'px' })); }.pass([imageStyle, i], this) }); } }.pass([currentImg, i], this); } else { currentImg.element.appendChild(new Element('img').set('src',this.galleryData[i].image).setStyles({ 'margin':'0 auto', 'display':'block' })); } this.galleryElements[parseInt(i)] = currentImg; } }, destroySlideShow: function(element) { var myClassName = element.className; var newElement = new Element('div').addClass('myClassName'); element.parentNode.replaceChild(newElement, element); }, startSlideShow: function() { this.fireEvent('onStart'); this.loadingElement.style.display = "none"; this.lastIter = this.maxIter - 1; this.currentIter = 0; this.galleryInit = 0; this.galleryElements[parseInt(this.currentIter)].set({opacity: 1}); if (this.options.showInfopane) this.showInfoSlideShow.delay(1000, this); if (this.options.useReMooz) this.makeReMooz.delay(1000, this); var textShowCarousel = formatString(this.options.textShowCarousel, this.currentIter+1, this.maxIter); if (this.options.showCarousel&&(!this.options.carouselPreloader)&&(!this.options.useExternalCarousel)) this.carouselBtn.set('html', textShowCarousel).setProperty('title', textShowCarousel); this.prepareTimer(); if (this.options.embedLinks) this.makeLink(this.currentIter); }, nextItem: function() { this.fireEvent('onNextCalled'); this.nextIter = this.currentIter+1; if (this.nextIter >= this.maxIter) this.nextIter = 0; this.galleryInit = 0; this.goTo(this.nextIter); }, prevItem: function() { this.fireEvent('onPreviousCalled'); this.nextIter = this.currentIter-1; if (this.nextIter <= -1) this.nextIter = this.maxIter - 1; this.galleryInit = 0; this.goTo(this.nextIter); }, goTo: function(num) { this.clearTimer(); if(this.options.preloader) { this.galleryElements[num].load(); if (num==0) this.galleryElements[this.maxIter - 1].load(); else this.galleryElements[num - 1].load(); if (num==(this.maxIter - 1)) this.galleryElements[0].load(); else this.galleryElements[num + 1].load(); } if (this.options.embedLinks) this.clearLink(); if (this.options.showInfopane) { this.slideInfoZone.clearChain(); this.hideInfoSlideShow().chain(this.changeItem.pass(num, this)); } else this.currentChangeDelay = this.changeItem.delay(500, this, num); if (this.options.embedLinks) this.makeLink(num); this.prepareTimer(); /*if (this.options.showCarousel) this.clearThumbnailsHighlights();*/ }, changeItem: function(num) { this.fireEvent('onStartChanging'); this.galleryInit = 0; if (this.currentIter != num) { for(i=0;i' + (myself.relatedImage.number + 1) + "/" + this.maxIter + ": " + myself.relatedImage.title); }.pass(currentImg, this), 'mouseout': function (myself) { myself.cancel(); myself.start({'opacity': this.options.thumbIdleOpacity}); }.pass(currentImg, this), 'click': function (myself) { this.goTo(myself.relatedImage.number); if (this.options.thumbCloseCarousel&&(!this.options.useExternalCarousel)) this.hideCarousel(); }.pass(currentImg, this) }); currentImg.relatedImage = this.galleryData[i]; this.thumbnailElements[parseInt(i)] = currentImg; } }, log: function(value) { if(console.log) console.log(value); }, preloadThumbnails: function() { var thumbnails = []; for(i=0;i 8) && (this.rel == el.rel)); }); } else{ this.currentLink.setProperties({ href: this.galleryData[num].link, title: this.galleryData[num].linkTitle }) if (!((this.options.embedLinks) && (!this.options.showArrows) && (!this.options.showCarousel))) this.currentLink.setStyle('display', 'block'); } }, clearLink: function() { this.currentLink.setProperties({href: '', title: ''}); if (!((this.options.embedLinks) && (!this.options.showArrows) && (!this.options.showCarousel))) this.currentLink.setStyle('display', 'none'); }, makeReMooz: function() { this.currentLink.setProperties({ href: '#' }); this.currentLink.setStyles({ 'display': 'block' }); this.galleryElements[this.currentIter].element.set('title', this.galleryData[this.currentIter].title + ' :: ' + this.galleryData[this.currentIter].description); this.ReMooz = new ReMooz(this.galleryElements[this.currentIter].element, { link: this.galleryData[this.currentIter].link, shadow: false, dragging: false, addClick: false, resizeOpacity: 1 }); var img = this.galleryElements[this.currentIter]; var coords = img.element.getCoordinates(); delete coords.right; delete coords.bottom; widthDiff = coords.width - img.width; heightDiff = coords.height - img.height; coords.width = img.width; coords.height = img.height; coords.left += Math.ceil(widthDiff/2)+1; coords.top += Math.ceil(heightDiff/2)+1; this.ReMooz.getOriginCoordinates = function(coords) { return coords; }.bind(this, coords); this.currentLink.onclick = function () { this.ReMooz.open.bind(this.ReMooz)(); return false; }.bind(this); }, /* To change the gallery data, those two functions : */ flushGallery: function() { this.galleryElements.each(function(myFx) { myFx.element.dispose(); myFx = myFx.element = null; }); this.galleryElements = []; }, changeData: function(data) { this.galleryData = data; this.clearTimer(); this.flushGallery(); if (this.options.showCarousel) this.flushCarousel(); this.constructElements(); if (this.options.showCarousel) this.fillCarousel(); if (this.options.showInfopane) this.hideInfoSlideShow(); this.galleryInit=1; this.lastIter=0; this.currentIter=0; this.doSlideShow(1); }, /* Plugins: HistoryManager */ initHistory: function() { this.fireEvent('onHistoryInit'); this.historyKey = this.galleryElement.id + '-picture'; if (this.options.customHistoryKey) this.historyKey = this.options.customHistoryKey; this.history = new History.Route({ defaults: [1], pattern: this.historyKey + '\\((\\d+)\\)', generate: function(values) { return [this.historyKey, '(', values[0], ')'].join('') }.bind(this), onMatch: function(values, defaults) { if (parseInt(values[0])-1 < this.maxIter) this.goTo(parseInt(values[0])-1); }.bind(this) }); this.addEvent('onChanged', function(){ this.history.setValue(0, this.currentIter+1); this.history.defaults=[this.currentIter+1]; }.bind(this)); this.fireEvent('onHistoryInited'); } }; gallery = new Class(gallery); gallery.Transitions = new Hash ({ fade: function(oldFx, newFx, oldPos, newPos){ oldFx.options.transition = newFx.options.transition = Fx.Transitions.linear; oldFx.options.duration = newFx.options.duration = this.options.fadeDuration; if (newPos > oldPos) newFx.start({opacity: 1}); else { newFx.set({opacity: 1}); oldFx.start({opacity: 0}); } }, crossfade: function(oldFx, newFx, oldPos, newPos){ oldFx.options.transition = newFx.options.transition = Fx.Transitions.linear; oldFx.options.duration = newFx.options.duration = this.options.fadeDuration; newFx.start({opacity: 1}); oldFx.start({opacity: 0}); }, fadebg: function(oldFx, newFx, oldPos, newPos){ oldFx.options.transition = newFx.options.transition = Fx.Transitions.linear; oldFx.options.duration = newFx.options.duration = this.options.fadeDuration / 2; oldFx.start({opacity: 0}).chain(newFx.start.pass([{opacity: 1}], newFx)); } }); /* All code copyright 2007 Jonathan Schemoul */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Follows: Preloader (class) * Simple class for preloading images with support for progress reporting * Copyright 2007 Tomocchino. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ var Preloader = new Class({ Implements: [Events, Options], options: { root : '', period : 100 }, initialize: function(options){ this.setOptions(options); }, load: function(sources) { this.index = 0; this.images = []; this.sources = this.temps = sources; this.total = this. sources.length; this.fireEvent('onStart', [this.index, this.total]); this.timer = this.progress.periodical(this.options.period, this); this.sources.each(function(source, index){ this.images[index] = new Asset.image(this.options.root + source, { 'onload' : function(){ this.index++; if(this.images[index]) this.fireEvent('onLoad', [this.images[index], index, source]); }.bind(this), 'onerror' : function(){ this.index++; this.fireEvent('onError', [this.images.splice(index, 1), index, source]); }.bind(this), 'onabort' : function(){ this.index++; this.fireEvent('onError', [this.images.splice(index, 1), index, source]); }.bind(this) }); }, this); }, progress: function() { this.fireEvent('onProgress', [Math.min(this.index, this.total), this.total]); if(this.index >= this.total) this.complete(); }, complete: function(){ $clear(this.timer); this.fireEvent('onComplete', [this.images]); }, cancel: function(){ $clear(this.timer); } }); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Follows: formatString (function) * Original name: Yahoo.Tools.printf * Copyright Yahoo. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ function formatString() { var num = arguments.length; var oStr = arguments[0]; for (var i = 1; i < num; i++) { var pattern = "\\{" + (i-1) + "\\}"; var re = new RegExp(pattern, "g"); oStr = oStr.replace(re, arguments[i]); } return oStr; } tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/scripts/jd.gallery.set.js000066400000000000000000000155771325711763500302620ustar00rootroot00000000000000/* This file is part of JonDesign's SmoothGallery v2.1beta1. JonDesign's SmoothGallery is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. JonDesign's SmoothGallery is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with JonDesign's SmoothGallery; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Main Developer: Jonathan Schemoul (JonDesign: http://www.jondesign.net/) */ var gallerySet = new Class({ Extends: gallery, initialize: function(element, options) { this.setOptions({ manualSetData: [], gallerySelector: "div.galleryElement", galleryTitleSelector: "h2", textGallerySelector: 'Galleries', textShowGallerySelector: 'Other Galleries', textGalleryInfo: '{0} pictures', startWithSelector: true, /* Changing default options */ textShowCarousel: '{0}/{1} Pictures', carouselPreloader: false }); this.setOptions(options); this.gallerySet = this.options.manualSetData; this.addEvent('onPopulated', this.createGallerySelectorTab.bind(this)); this.addEvent('onPopulated', this.createGallerySelector.bind(this)); this.startWithSelectorFn = this.toggleGallerySelector.pass(true, this); if (this.options.startWithSelector) this.addEvent('onGallerySelectorCreated', this.startWithSelectorFn); this.parent(element, this.options); }, populateData: function() { options = this.options; var data = $A(this.gallerySet); this.populateFrom.getElements(options.gallerySelector).each(function (galEl) { currentGalArrayPlace = 0; galleryDict = { title: galEl.getElement(options.galleryTitleSelector).innerHTML, elements: [] } galleryDict.elements.extend(this.populateGallery(galEl, 0)); data.extend([galleryDict]); if (this.options.destroyAfterPopulate) galEl.dispose(); }, this); this.gallerySet = data; this.galleryData = data[0].elements; this.currentGallery = 0; this.fireEvent('onPopulated'); }, changeGallery: function(number) { if (number!=this.currentGallery) { this.changeData(this.gallerySet[number].elements); this.maxIter = this.gallerySet[number].elements.length; this.currentGallery = number; this.gallerySelectorBtn.set('html', this.gallerySet[number].title); this.fireEvent('onGalleryChanged'); } this.toggleGallerySelector(false); }, createGallerySelectorTab: function() { this.gallerySelectorBtn = new Element('a').addClass('gallerySelectorBtn').setProperties({ title: this.options.textShowGallerySelector }).set('html', this.options.textShowGallerySelector).addEvent( 'click', function(){ this.toggleGallerySelector(true); }.bind(this) ).injectInside(this.galleryElement); this.addEvent('onShowCarousel', function(){this.gallerySelectorBtn.setStyle('zIndex', 10)}.bind(this)); this.addEvent('onCarouselHidden', function(){this.gallerySelectorBtn.setStyle('zIndex', 15)}.bind(this)); }, createGallerySelector: function() { this.gallerySelector = new Fx.Morph( new Element('div').addClass( 'gallerySelector' ).injectInside( this.galleryElement ).setStyles({ 'display': 'none', 'opacity': '0' }) ); this.gallerySelectorTitle = new Element('h2').set('html', this.options.textGallerySelector ).injectInside(this.gallerySelector.element); var gallerySelectorHeight = this.galleryElement.offsetHeight - 50 - 10 - 2; this.gallerySelectorWrapper = new Fx.Morph( new Element('div').addClass( 'gallerySelectorWrapper' ).setStyle( 'height', gallerySelectorHeight + "px" ).injectInside(this.gallerySelector.element) ); this.gallerySelectorInner = new Element('div').addClass('gallerySelectorInner').injectInside(this.gallerySelectorWrapper.element); this.gallerySelectorWrapper.scroller = new Scroller(this.gallerySelectorWrapper.element, { area: 100, velocity: 0.3 }).start(); this.createGalleryButtons(); this.fireEvent('onGallerySelectorCreated'); }, createGalleryButtons: function () { var galleryButtonWidth = ((this.galleryElement.offsetWidth - 30) / 2) - 14; this.gallerySet.each(function(galleryItem, index){ var button = new Element('div').addClass('galleryButton').injectInside( this.gallerySelectorInner ).addEvents({ 'mouseover': function(myself){ myself.button.addClass('hover'); }.pass(galleryItem, this), 'mouseout': function(myself){ myself.button.removeClass('hover'); }.pass(galleryItem, this), 'click': function(myself, number){ this.changeGallery.pass(number,this)(); }.pass([galleryItem, index], this) }).setStyle('width', galleryButtonWidth); galleryItem.button = button; var thumbnail = ""; if (this.options.showCarousel) thumbnail = galleryItem.elements[0].thumbnail; else thumbnail = galleryItem.elements[0].image; new Element('div').addClass('preview').setStyle( 'backgroundImage', "url('" + thumbnail + "')" ).injectInside(button); new Element('h3').set('html', galleryItem.title).injectInside(button); new Element('p').addClass('info').set('html', formatString(this.options.textGalleryInfo, galleryItem.elements.length)).injectInside(button); }, this); new Element('br').injectInside(this.gallerySelectorInner).setStyle('clear','both'); }, toggleGallerySelector: function(state) { if (state) this.gallerySelector.start({'opacity' : 1}).element.setStyle('display','block'); else this.gallerySelector.start({'opacity' : 0}); }, initHistory: function() { this.fireEvent('onHistoryInit'); this.historyKey = this.galleryElement.id + '-gallery'; if (this.options.customHistoryKey) this.historyKey = this.options.customHistoryKey(); this.history = new History.Route({ defaults: [1,1], pattern: this.historyKey + '\\((\\d+)\\)-picture\\((\\d+)\\)', generate: function(values) { return [this.historyKey, '(', values[0], ')', '-picture','(', values[1], ')'].join(''); }.bind(this), onMatch: function(values, defaults) { this.changeGallery.pass(parseInt(values[0]) - 1, this).delay(10); if(this.gallerySelector) this.toggleGallerySelector.pass(false, this).delay(500); this.goTo.pass(parseInt(values[1]) - 1, this).delay(100); }.bind(this) }); updateHistory = function(){ this.history.setValues([this.currentGallery + 1, this.currentIter + 1]); this.history.defaults=[this.currentGallery + 1, this.currentIter + 1]; }.bind(this); this.addEvent('onChanged', updateHistory); this.addEvent('onGalleryChanged', updateHistory); this.fireEvent('onHistoryInited'); } });tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/scripts/jd.gallery.transitions.js000066400000000000000000000057731325711763500320410ustar00rootroot00000000000000/* This file is part of JonDesign's SmoothGallery v2.1beta1. JonDesign's SmoothGallery is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. JonDesign's SmoothGallery is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with JonDesign's SmoothGallery; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Main Developer: Jonathan Schemoul (JonDesign: http://www.jondesign.net/) */ gallery.Transitions.extend({ fadeslideleft: function(oldFx, newFx, oldPos, newPos){ oldFx.options.transition = newFx.options.transition = Fx.Transitions.Cubic.easeOut; oldFx.options.duration = newFx.options.duration = 1500; if (newPos > oldPos) { newFx.start({ left: [this.galleryElement.offsetWidth, 0], opacity: 1 }); oldFx.start({opacity: [1,0]}); } else { newFx.start({opacity: [0,1]}); oldFx.start({ left: [0, this.galleryElement.offsetWidth], opacity: 0 }).chain(function(fx){fx.set({left: 0});}.pass(oldFx)); } }, continuoushorizontal: function(oldFx, newFx, oldPos, newPos){ oldFx.options.transition = newFx.options.transition = Fx.Transitions.linear; if ( ((newPos > oldPos) || ((newPos==0) && (oldPos == (this.maxIter-1) ))) && (!((newPos == (this.maxIter-1 )) && (oldPos == 0))) ) { oldFx.set({opacity: 1}); oldFx.start({ left: [0, this.galleryElement.offsetWidth * -1] }); newFx.set({opacity: 1, left: this.galleryElement.offsetWidth}); newFx.start({ left: [this.galleryElement.offsetWidth, 0] }); } else { oldFx.set({opacity: 1}); oldFx.start({ left: [0, this.galleryElement.offsetWidth] }); newFx.set({opacity: 1, left: this.galleryElement.offsetWidth * -1}); newFx.start({ left: [this.galleryElement.offsetWidth * -1, 0] }); } }, continuousvertical: function(oldFx, newFx, oldPos, newPos){ oldFx.options.transition = newFx.options.transition = Fx.Transitions.linear; if ( ((newPos > oldPos) || ((newPos==0) && (oldPos == (this.maxIter-1) ))) && (!((newPos == (this.maxIter-1 )) && (oldPos == 0))) ) { oldFx.set({opacity: 1}); oldFx.start({ top: [0, this.galleryElement.offsetHeight * -1] }); newFx.set({opacity: 1, top: this.galleryElement.offsetHeight}); newFx.start({ top: [this.galleryElement.offsetHeight, 0] }); } else { oldFx.set({opacity: 1}); oldFx.start({ top: [0, this.galleryElement.offsetHeight] }); newFx.set({opacity: 1, top: this.galleryElement.offsetHeight * -1}); newFx.start({ top: [this.galleryElement.offsetHeight * -1, 0] }); } } });tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/scripts/jdgalleryresize.js000066400000000000000000000702641325711763500306260ustar00rootroot00000000000000/* This file is part of JonDesign's SmoothGallery v2.1beta1. JonDesign's SmoothGallery is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. JonDesign's SmoothGallery is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with JonDesign's SmoothGallery; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Main Developer: Jonathan Schemoul (JonDesign: http://www.jondesign.net/) Contributed code by: - Christian Ehret (bugfix) - Nitrix (bugfix) - Valerio from Mad4Milk for his great help with the carousel scrolling and many other things. - Archie Cowan for helping me find a bugfix on carousel inner width problem. - Tomocchino from #mootools for the preloader class Many thanks to: - The mootools team for the great mootools lib, and it's help and support throughout the project. - Harald Kirschner (digitarald: http://digitarald.de/) for all his great libs. Some used here as plugins. */ /* some quirks to circumvent broken stuff in mt1.2 */ function isBody(element){ return (/^(?:body|html)$/i).test(element.tagName); }; Element.implement({ getPosition: function(relative){ if (isBody(this)) return {x: 0, y: 0}; var el = this, position = {x: 0, y: 0}; while (el){ position.x += el.offsetLeft; position.y += el.offsetTop; el = el.offsetParent; } var rpos = (relative) ? $(relative).getPosition() : {x: 0, y: 0}; return {x: position.x - rpos.x, y: position.y - rpos.y}; } }); // declaring the class var gallery = { Implements: [Events, Options], options: { showArrows: true, showCarousel: true, showInfopane: true, embedLinks: true, fadeDuration: 500, timed: false, delay: 9000, preloader: true, preloaderImage: true, preloaderErrorImage: true, /* Data retrieval */ manualData: [], populateFrom: false, populateData: true, destroyAfterPopulate: true, elementSelector: "div.imageElement", titleSelector: "h3", subtitleSelector: "p", linkSelector: "a.open", imageSelector: "img.full", thumbnailSelector: "img.thumbnail", defaultTransition: "fade", /* InfoPane options */ slideInfoZoneOpacity: 0.7, slideInfoZoneSlide: true, /* Carousel options */ carouselMinimizedOpacity: 0.4, carouselMinimizedHeight: 20, carouselMaximizedOpacity: 0.9, thumbHeight: 75, thumbWidth: 100, thumbSpacing: 10, thumbIdleOpacity: 0.2, textShowCarousel: 'Pictures', showCarouselLabel: true, thumbCloseCarousel: true, useThumbGenerator: false, thumbGenerator: 'resizer.php', useExternalCarousel: false, carouselElement: false, carouselHorizontal: true, activateCarouselScroller: true, carouselPreloader: true, textPreloadingCarousel: 'Loading...', /* CSS Classes */ baseClass: 'jdGallery', withArrowsClass: 'withArrows', /* Plugins: HistoryManager */ useHistoryManager: false, customHistoryKey: false, /* Plugins: ReMooz */ useReMooz: false, useMediaboxAdvanced: false }, initialize: function(element, options) { this.setOptions(options); this.fireEvent('onInit'); this.currentIter = 0; this.lastIter = 0; this.maxIter = 0; this.galleryElement = element; this.topElement = element; this.galleryData = this.options.manualData; this.galleryInit = 1; this.galleryElements = Array(); this.thumbnailElements = Array(); this.galleryElement.addClass(this.options.baseClass); if (this.options.useReMooz&&(this.options.defaultTransition=="fade")) this.options.defaultTransition="crossfade"; this.populateFrom = element; if (this.options.populateFrom) this.populateFrom = this.options.populateFrom; if (this.options.populateData) this.populateData(); element.style.display="block"; if (this.options.useHistoryManager) this.initHistory(); if ((this.options.embedLinks)|(this.options.useReMooz)|(this.options.useMediaboxAdvanced)) { this.currentLink = new Element('a').addClass('open').setProperties({ href: '#', title: '', rel: 'lightbox' }).injectInside(element); if ((!this.options.showArrows) && (!this.options.showCarousel)) this.galleryElement = element = this.currentLink; else this.currentLink.setStyle('display', 'none'); } this.constructElements(); if ((this.galleryData.length>1)&&(this.options.showArrows)) { var leftArrow = new Element('a').addClass('left').addEvent( 'click', this.prevItem.bind(this) ).injectInside(element); var rightArrow = new Element('a').addClass('right').addEvent( 'click', this.nextItem.bind(this) ).injectInside(element); this.galleryElement.addClass(this.options.withArrowsClass); } this.loadingElement = new Element('div').addClass('loadingElement').injectInside(element); if (this.options.showInfopane) this.initInfoSlideshow(); if (this.options.showCarousel) this.initCarousel(); this.doSlideShow(1); }, populateData: function() { currentArrayPlace = this.galleryData.length; options = this.options; var data = $A(this.galleryData); data.extend(this.populateGallery(this.populateFrom, currentArrayPlace)); this.galleryData = data; this.fireEvent('onPopulated'); }, populateGallery: function(element, startNumber) { var data = []; options = this.options; currentArrayPlace = startNumber; element.getElements(options.elementSelector).each(function(el) { elementDict = $H({ image: el.getElement(options.imageSelector).getProperty('src'), number: currentArrayPlace, transition: this.options.defaultTransition }); if ((options.showInfopane) | (options.showCarousel)) elementDict.extend({ title: el.getElement(options.titleSelector).innerHTML, description: el.getElement(options.subtitleSelector).innerHTML }); if ((options.embedLinks) | (options.useReMooz)) elementDict.extend({ link: el.getElement(options.linkSelector).href||false, linkTitle: el.getElement(options.linkSelector).title||false, linkTarget: el.getElement(options.linkSelector).getProperty('target')||false }); if ((!options.useThumbGenerator) && (options.showCarousel)) elementDict.extend({ thumbnail: el.getElement(options.thumbnailSelector).getProperty('src') }); else if (options.useThumbGenerator) elementDict.extend({ thumbnail: options.thumbGenerator + '?imgfile=' + elementDict.image + '&max_width=' + options.thumbWidth + '&max_height=' + options.thumbHeight }); data.extend([elementDict]); currentArrayPlace++; if (this.options.destroyAfterPopulate) el.dispose(); }); return data; }, constructElements: function() { el = this.galleryElement; top_el = this.galleryElement; if (this.options.embedLinks && (!this.options.showArrows)) el = this.currentLink; this.maxIter = this.galleryData.length; var currentImg; for(i=0;i= img.width){ new_height = top_height; new_width = Math.round(top_height*img.width/img.height); } else if(top_width < img.width && img.height <= img.width) { new_width = top_width; new_height = Math.round(top_width*img.height/img.width); margin_top = Math.round((top_height - new_height)/2); } else { margin_top = Math.round((top_height - img.height)/2); } img.element.appendChild(new Element('img').set('src',img.source).setStyles({ 'margin':'0 auto', 'display':'block', 'width':new_width+'px', 'height':new_height+'px', 'margin-top':margin_top+'px' })); }.pass([imageStyle, i], this) }); } }.pass([currentImg, i], this); } else { currentImg.element.appendChild(new Element('img').set('src',this.galleryData[i].image).setStyles({ 'margin':'0 auto', 'display':'block' })); } this.galleryElements[parseInt(i)] = currentImg; } }, destroySlideShow: function(element) { var myClassName = element.className; var newElement = new Element('div').addClass('myClassName'); element.parentNode.replaceChild(newElement, element); }, startSlideShow: function() { this.fireEvent('onStart'); this.loadingElement.style.display = "none"; this.lastIter = this.maxIter - 1; this.currentIter = 0; this.galleryInit = 0; this.galleryElements[parseInt(this.currentIter)].set({opacity: 1}); if (this.options.showInfopane) this.showInfoSlideShow.delay(1000, this); if (this.options.useReMooz) this.makeReMooz.delay(1000, this); var textShowCarousel = formatString(this.options.textShowCarousel, this.currentIter+1, this.maxIter); if (this.options.showCarousel&&(!this.options.carouselPreloader)&&(!this.options.useExternalCarousel)) this.carouselBtn.set('html', textShowCarousel).setProperty('title', textShowCarousel); this.prepareTimer(); if (this.options.embedLinks) this.makeLink(this.currentIter); }, nextItem: function() { this.fireEvent('onNextCalled'); this.nextIter = this.currentIter+1; if (this.nextIter >= this.maxIter) this.nextIter = 0; this.galleryInit = 0; this.goTo(this.nextIter); }, prevItem: function() { this.fireEvent('onPreviousCalled'); this.nextIter = this.currentIter-1; if (this.nextIter <= -1) this.nextIter = this.maxIter - 1; this.galleryInit = 0; this.goTo(this.nextIter); }, goTo: function(num) { this.clearTimer(); if(this.options.preloader) { this.galleryElements[num].load(); if (num==0) this.galleryElements[this.maxIter - 1].load(); else this.galleryElements[num - 1].load(); if (num==(this.maxIter - 1)) this.galleryElements[0].load(); else this.galleryElements[num + 1].load(); } if (this.options.embedLinks) this.clearLink(); if (this.options.showInfopane) { this.slideInfoZone.clearChain(); this.hideInfoSlideShow().chain(this.changeItem.pass(num, this)); } else this.currentChangeDelay = this.changeItem.delay(500, this, num); if (this.options.embedLinks) this.makeLink(num); this.prepareTimer(); /*if (this.options.showCarousel) this.clearThumbnailsHighlights();*/ }, changeItem: function(num) { this.fireEvent('onStartChanging'); this.galleryInit = 0; if (this.currentIter != num) { for(i=0;i' + (myself.relatedImage.number + 1) + "/" + this.maxIter + ": " + myself.relatedImage.title); }.pass(currentImg, this), 'mouseout': function (myself) { myself.cancel(); myself.start({'opacity': this.options.thumbIdleOpacity}); }.pass(currentImg, this), 'click': function (myself) { this.goTo(myself.relatedImage.number); if (this.options.thumbCloseCarousel&&(!this.options.useExternalCarousel)) this.hideCarousel(); }.pass(currentImg, this) }); currentImg.relatedImage = this.galleryData[i]; this.thumbnailElements[parseInt(i)] = currentImg; } }, log: function(value) { if(console.log) console.log(value); }, preloadThumbnails: function() { var thumbnails = []; for(i=0;i 8) && (this.rel == el.rel)); }); } else{ this.currentLink.setProperties({ href: this.galleryData[num].link, title: this.galleryData[num].linkTitle }) if (!((this.options.embedLinks) && (!this.options.showArrows) && (!this.options.showCarousel))) this.currentLink.setStyle('display', 'block'); } }, clearLink: function() { this.currentLink.setProperties({href: '', title: ''}); if (!((this.options.embedLinks) && (!this.options.showArrows) && (!this.options.showCarousel))) this.currentLink.setStyle('display', 'none'); }, makeReMooz: function() { this.currentLink.setProperties({ href: '#' }); this.currentLink.setStyles({ 'display': 'block' }); this.galleryElements[this.currentIter].element.set('title', this.galleryData[this.currentIter].title + ' :: ' + this.galleryData[this.currentIter].description); this.ReMooz = new ReMooz(this.galleryElements[this.currentIter].element, { link: this.galleryData[this.currentIter].link, shadow: false, dragging: false, addClick: false, resizeOpacity: 1 }); var img = this.galleryElements[this.currentIter]; var coords = img.element.getCoordinates(); delete coords.right; delete coords.bottom; widthDiff = coords.width - img.width; heightDiff = coords.height - img.height; coords.width = img.width; coords.height = img.height; coords.left += Math.ceil(widthDiff/2)+1; coords.top += Math.ceil(heightDiff/2)+1; this.ReMooz.getOriginCoordinates = function(coords) { return coords; }.bind(this, coords); this.currentLink.onclick = function () { this.ReMooz.open.bind(this.ReMooz)(); return false; }.bind(this); }, /* To change the gallery data, those two functions : */ flushGallery: function() { this.galleryElements.each(function(myFx) { myFx.element.dispose(); myFx = myFx.element = null; }); this.galleryElements = []; }, changeData: function(data) { this.galleryData = data; this.clearTimer(); this.flushGallery(); if (this.options.showCarousel) this.flushCarousel(); this.constructElements(); if (this.options.showCarousel) this.fillCarousel(); if (this.options.showInfopane) this.hideInfoSlideShow(); this.galleryInit=1; this.lastIter=0; this.currentIter=0; this.doSlideShow(1); }, /* Plugins: HistoryManager */ initHistory: function() { this.fireEvent('onHistoryInit'); this.historyKey = this.galleryElement.id + '-picture'; if (this.options.customHistoryKey) this.historyKey = this.options.customHistoryKey; this.history = new History.Route({ defaults: [1], pattern: this.historyKey + '\\((\\d+)\\)', generate: function(values) { return [this.historyKey, '(', values[0], ')'].join('') }.bind(this), onMatch: function(values, defaults) { if (parseInt(values[0])-1 < this.maxIter) this.goTo(parseInt(values[0])-1); }.bind(this) }); this.addEvent('onChanged', function(){ this.history.setValue(0, this.currentIter+1); this.history.defaults=[this.currentIter+1]; }.bind(this)); this.fireEvent('onHistoryInited'); } }; gallery = new Class(gallery); gallery.Transitions = new Hash ({ fade: function(oldFx, newFx, oldPos, newPos){ oldFx.options.transition = newFx.options.transition = Fx.Transitions.linear; oldFx.options.duration = newFx.options.duration = this.options.fadeDuration; if (newPos > oldPos) newFx.start({opacity: 1}); else { newFx.set({opacity: 1}); oldFx.start({opacity: 0}); } }, crossfade: function(oldFx, newFx, oldPos, newPos){ oldFx.options.transition = newFx.options.transition = Fx.Transitions.linear; oldFx.options.duration = newFx.options.duration = this.options.fadeDuration; newFx.start({opacity: 1}); oldFx.start({opacity: 0}); }, fadebg: function(oldFx, newFx, oldPos, newPos){ oldFx.options.transition = newFx.options.transition = Fx.Transitions.linear; oldFx.options.duration = newFx.options.duration = this.options.fadeDuration / 2; oldFx.start({opacity: 0}).chain(newFx.start.pass([{opacity: 1}], newFx)); } }); /* All code copyright 2007 Jonathan Schemoul */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Follows: Preloader (class) * Simple class for preloading images with support for progress reporting * Copyright 2007 Tomocchino. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ var Preloader = new Class({ Implements: [Events, Options], options: { root : '', period : 100 }, initialize: function(options){ this.setOptions(options); }, load: function(sources) { this.index = 0; this.images = []; this.sources = this.temps = sources; this.total = this. sources.length; this.fireEvent('onStart', [this.index, this.total]); this.timer = this.progress.periodical(this.options.period, this); this.sources.each(function(source, index){ this.images[index] = new Asset.image(this.options.root + source, { 'onload' : function(){ this.index++; if(this.images[index]) this.fireEvent('onLoad', [this.images[index], index, source]); }.bind(this), 'onerror' : function(){ this.index++; this.fireEvent('onError', [this.images.splice(index, 1), index, source]); }.bind(this), 'onabort' : function(){ this.index++; this.fireEvent('onError', [this.images.splice(index, 1), index, source]); }.bind(this) }); }, this); }, progress: function() { this.fireEvent('onProgress', [Math.min(this.index, this.total), this.total]); if(this.index >= this.total) this.complete(); }, complete: function(){ $clear(this.timer); this.fireEvent('onComplete', [this.images]); }, cancel: function(){ $clear(this.timer); } }); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Follows: formatString (function) * Original name: Yahoo.Tools.printf * Copyright Yahoo. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ function formatString() { var num = arguments.length; var oStr = arguments[0]; for (var i = 1; i < num; i++) { var pattern = "\\{" + (i-1) + "\\}"; var re = new RegExp(pattern, "g"); oStr = oStr.replace(re, arguments[i]); } return oStr; } tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/scripts/license.txt000066400000000000000000000773271325711763500272630ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONStdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/scripts/mootools-1.2-more.js000066400000000000000000000446201325711763500305350ustar00rootroot00000000000000//MooTools More, . Copyright (c) 2006-2008 Valerio Proietti, , MIT Style License. Fx.Slide=new Class({Extends:Fx,options:{mode:"vertical"},initialize:function(B,A){this.addEvent("complete",function(){this.open=(this.wrapper["offset"+this.layout.capitalize()]!=0); if(this.open&&Browser.Engine.webkit419){this.element.dispose().inject(this.wrapper);}},true);this.element=this.subject=$(B);this.parent(A);var C=this.element.retrieve("wrapper"); this.wrapper=C||new Element("div",{styles:$extend(this.element.getStyles("margin","position"),{overflow:"hidden"})}).wraps(this.element);this.element.store("wrapper",this.wrapper).setStyle("margin",0); this.now=[];this.open=true;},vertical:function(){this.margin="margin-top";this.layout="height";this.offset=this.element.offsetHeight;},horizontal:function(){this.margin="margin-left"; this.layout="width";this.offset=this.element.offsetWidth;},set:function(A){this.element.setStyle(this.margin,A[0]);this.wrapper.setStyle(this.layout,A[1]); return this;},compute:function(E,D,C){var B=[];var A=2;A.times(function(F){B[F]=Fx.compute(E[F],D[F],C);});return B;},start:function(B,E){if(!this.check(arguments.callee,B,E)){return this; }this[E||this.options.mode]();var D=this.element.getStyle(this.margin).toInt();var C=this.wrapper.getStyle(this.layout).toInt();var A=[[D,C],[0,this.offset]]; var G=[[D,C],[-this.offset,0]];var F;switch(B){case"in":F=A;break;case"out":F=G;break;case"toggle":F=(this.wrapper["offset"+this.layout.capitalize()]==0)?A:G; }return this.parent(F[0],F[1]);},slideIn:function(A){return this.start("in",A);},slideOut:function(A){return this.start("out",A);},hide:function(A){this[A||this.options.mode](); this.open=false;return this.set([-this.offset,0]);},show:function(A){this[A||this.options.mode]();this.open=true;return this.set([0,this.offset]);},toggle:function(A){return this.start("toggle",A); }});Element.Properties.slide={set:function(B){var A=this.retrieve("slide");if(A){A.cancel();}return this.eliminate("slide").store("slide:options",$extend({link:"cancel"},B)); },get:function(A){if(A||!this.retrieve("slide")){if(A||!this.retrieve("slide:options")){this.set("slide",A);}this.store("slide",new Fx.Slide(this,this.retrieve("slide:options"))); }return this.retrieve("slide");}};Element.implement({slide:function(D,E){D=D||"toggle";var B=this.get("slide"),A;switch(D){case"hide":B.hide(E);break;case"show":B.show(E); break;case"toggle":var C=this.retrieve("slide:flag",B.open);B[(C)?"slideOut":"slideIn"](E);this.store("slide:flag",!C);A=true;break;default:B.start(D,E); }if(!A){this.eliminate("slide:flag");}return this;}});Fx.Scroll=new Class({Extends:Fx,options:{offset:{x:0,y:0},wheelStops:true},initialize:function(B,A){this.element=this.subject=$(B); this.parent(A);var D=this.cancel.bind(this,false);if($type(this.element)!="element"){this.element=$(this.element.getDocument().body);}var C=this.element; if(this.options.wheelStops){this.addEvent("start",function(){C.addEvent("mousewheel",D);},true);this.addEvent("complete",function(){C.removeEvent("mousewheel",D); },true);}},set:function(){var A=Array.flatten(arguments);this.element.scrollTo(A[0],A[1]);},compute:function(E,D,C){var B=[];var A=2;A.times(function(F){B.push(Fx.compute(E[F],D[F],C)); });return B;},start:function(C,H){if(!this.check(arguments.callee,C,H)){return this;}var E=this.element.getSize(),F=this.element.getScrollSize();var B=this.element.getScroll(),D={x:C,y:H}; for(var G in D){var A=F[G]-E[G];if($chk(D[G])){D[G]=($type(D[G])=="number")?D[G].limit(0,A):A;}else{D[G]=B[G];}D[G]+=this.options.offset[G];}return this.parent([B.x,B.y],[D.x,D.y]); },toTop:function(){return this.start(false,0);},toLeft:function(){return this.start(0,false);},toRight:function(){return this.start("right",false);},toBottom:function(){return this.start(false,"bottom"); },toElement:function(B){var A=$(B).getPosition(this.element);return this.start(A.x,A.y);}});Fx.Elements=new Class({Extends:Fx.CSS,initialize:function(B,A){this.elements=this.subject=$$(B); this.parent(A);},compute:function(G,H,I){var C={};for(var D in G){var A=G[D],E=H[D],F=C[D]={};for(var B in A){F[B]=this.parent(A[B],E[B],I);}}return C; },set:function(B){for(var C in B){var A=B[C];for(var D in A){this.render(this.elements[C],D,A[D],this.options.unit);}}return this;},start:function(C){if(!this.check(arguments.callee,C)){return this; }var H={},I={};for(var D in C){var F=C[D],A=H[D]={},G=I[D]={};for(var B in F){var E=this.prepare(this.elements[D],B,F[B]);A[B]=E.from;G[B]=E.to;}}return this.parent(H,I); }});var Drag=new Class({Implements:[Events,Options],options:{snap:6,unit:"px",grid:false,style:true,limit:false,handle:false,invert:false,preventDefault:false,modifiers:{x:"left",y:"top"}},initialize:function(){var B=Array.link(arguments,{options:Object.type,element:$defined}); this.element=$(B.element);this.document=this.element.getDocument();this.setOptions(B.options||{});var A=$type(this.options.handle);this.handles=(A=="array"||A=="collection")?$$(this.options.handle):$(this.options.handle)||this.element; this.mouse={now:{},pos:{}};this.value={start:{},now:{}};this.selection=(Browser.Engine.trident)?"selectstart":"mousedown";this.bound={start:this.start.bind(this),check:this.check.bind(this),drag:this.drag.bind(this),stop:this.stop.bind(this),cancel:this.cancel.bind(this),eventStop:$lambda(false)}; this.attach();},attach:function(){this.handles.addEvent("mousedown",this.bound.start);return this;},detach:function(){this.handles.removeEvent("mousedown",this.bound.start); return this;},start:function(C){if(this.options.preventDefault){C.preventDefault();}this.fireEvent("beforeStart",this.element);this.mouse.start=C.page; var A=this.options.limit;this.limit={x:[],y:[]};for(var D in this.options.modifiers){if(!this.options.modifiers[D]){continue;}if(this.options.style){this.value.now[D]=this.element.getStyle(this.options.modifiers[D]).toInt(); }else{this.value.now[D]=this.element[this.options.modifiers[D]];}if(this.options.invert){this.value.now[D]*=-1;}this.mouse.pos[D]=C.page[D]-this.value.now[D]; if(A&&A[D]){for(var B=2;B--;B){if($chk(A[D][B])){this.limit[D][B]=$lambda(A[D][B])();}}}}if($type(this.options.grid)=="number"){this.options.grid={x:this.options.grid,y:this.options.grid}; }this.document.addEvents({mousemove:this.bound.check,mouseup:this.bound.cancel});this.document.addEvent(this.selection,this.bound.eventStop);},check:function(A){if(this.options.preventDefault){A.preventDefault(); }var B=Math.round(Math.sqrt(Math.pow(A.page.x-this.mouse.start.x,2)+Math.pow(A.page.y-this.mouse.start.y,2)));if(B>this.options.snap){this.cancel();this.document.addEvents({mousemove:this.bound.drag,mouseup:this.bound.stop}); this.fireEvent("start",this.element).fireEvent("snap",this.element);}},drag:function(A){if(this.options.preventDefault){A.preventDefault();}this.mouse.now=A.page; for(var B in this.options.modifiers){if(!this.options.modifiers[B]){continue;}this.value.now[B]=this.mouse.now[B]-this.mouse.pos[B];if(this.options.invert){this.value.now[B]*=-1; }if(this.options.limit&&this.limit[B]){if($chk(this.limit[B][1])&&(this.value.now[B]>this.limit[B][1])){this.value.now[B]=this.limit[B][1];}else{if($chk(this.limit[B][0])&&(this.value.now[B]B.left&&A.xB.top);},checkDroppables:function(){var A=this.droppables.filter(this.checkAgainst,this).getLast(); if(this.overed!=A){if(this.overed){this.fireEvent("leave",[this.element,this.overed]);}if(A){this.overed=A;this.fireEvent("enter",[this.element,A]);}else{this.overed=null; }}},drag:function(A){this.parent(A);if(this.droppables.length){this.checkDroppables();}},stop:function(A){this.checkDroppables();this.fireEvent("drop",[this.element,this.overed]); this.overed=null;return this.parent(A);}});Element.implement({makeDraggable:function(A){return new Drag.Move(this,A);}});Hash.Cookie=new Class({Extends:Cookie,options:{autoSave:true},initialize:function(B,A){this.parent(B,A); this.load();},save:function(){var A=JSON.encode(this.hash);if(!A||A.length>4096){return false;}if(A=="{}"){this.dispose();}else{this.write(A);}return true; },load:function(){this.hash=new Hash(JSON.decode(this.read(),true));return this;}});Hash.Cookie.implement((function(){var A={};Hash.each(Hash.prototype,function(C,B){A[B]=function(){var D=C.apply(this.hash,arguments); if(this.options.autoSave){this.save();}return D;};});return A;})());var Color=new Native({initialize:function(B,C){if(arguments.length>=3){C="rgb";B=Array.slice(arguments,0,3); }else{if(typeof B=="string"){if(B.match(/rgb/)){B=B.rgbToHex().hexToRgb(true);}else{if(B.match(/hsb/)){B=B.hsbToRgb();}else{B=B.hexToRgb(true);}}}}C=C||"rgb"; switch(C){case"hsb":var A=B;B=B.hsbToRgb();B.hsb=A;break;case"hex":B=B.hexToRgb(true);break;}B.rgb=B.slice(0,3);B.hsb=B.hsb||B.rgbToHsb();B.hex=B.rgbToHex(); return $extend(B,this);}});Color.implement({mix:function(){var A=Array.slice(arguments);var C=($type(A.getLast())=="number")?A.pop():50;var B=this.slice(); A.each(function(D){D=new Color(D);for(var E=0;E<3;E++){B[E]=Math.round((B[E]/100*(100-C))+(D[E]/100*C));}});return new Color(B,"rgb");},invert:function(){return new Color(this.map(function(A){return 255-A; }));},setHue:function(A){return new Color([A,this.hsb[1],this.hsb[2]],"hsb");},setSaturation:function(A){return new Color([this.hsb[0],A,this.hsb[2]],"hsb"); },setBrightness:function(A){return new Color([this.hsb[0],this.hsb[1],A],"hsb");}});function $RGB(C,B,A){return new Color([C,B,A],"rgb");}function $HSB(C,B,A){return new Color([C,B,A],"hsb"); }function $HEX(A){return new Color(A,"hex");}Array.implement({rgbToHsb:function(){var B=this[0],C=this[1],J=this[2];var G,F,H;var I=Math.max(B,C,J),E=Math.min(B,C,J); var K=I-E;H=I/255;F=(I!=0)?K/I:0;if(F==0){G=0;}else{var D=(I-B)/K;var A=(I-C)/K;var L=(I-J)/K;if(B==I){G=L-A;}else{if(C==I){G=2+D-L;}else{G=4+A-D;}}G/=6; if(G<0){G++;}}return[Math.round(G*360),Math.round(F*100),Math.round(H*100)];},hsbToRgb:function(){var C=Math.round(this[2]/100*255);if(this[1]==0){return[C,C,C]; }else{var A=this[0]%360;var E=A%60;var F=Math.round((this[2]*(100-this[1]))/10000*255);var D=Math.round((this[2]*(6000-this[1]*E))/600000*255);var B=Math.round((this[2]*(6000-this[1]*(60-E)))/600000*255); switch(Math.floor(A/60)){case 0:return[C,B,F];case 1:return[D,C,F];case 2:return[F,C,B];case 3:return[F,D,C];case 4:return[B,F,C];case 5:return[C,F,D]; }}return false;}});String.implement({rgbToHsb:function(){var A=this.match(/\d{1,3}/g);return(A)?hsb.rgbToHsb():null;},hsbToRgb:function(){var A=this.match(/\d{1,3}/g); return(A)?A.hsbToRgb():null;}});var Group=new Class({initialize:function(){this.instances=Array.flatten(arguments);this.events={};this.checker={};},addEvent:function(B,A){this.checker[B]=this.checker[B]||{}; this.events[B]=this.events[B]||[];if(this.events[B].contains(A)){return false;}else{this.events[B].push(A);}this.instances.each(function(C,D){C.addEvent(B,this.check.bind(this,[B,C,D])); },this);return this;},check:function(C,A,B){this.checker[C][B]=true;var D=this.instances.every(function(F,E){return this.checker[C][E]||false;},this);if(!D){return ; }this.checker[C]={};this.events[C].each(function(E){E.call(this,this.instances,A);},this);}});var Asset=new Hash({javascript:function(F,D){D=$extend({onload:$empty,document:document,check:$lambda(true)},D); var B=new Element("script",{src:F,type:"text/javascript"});var E=D.onload.bind(B),A=D.check,G=D.document;delete D.onload;delete D.check;delete D.document; B.addEvents({load:E,readystatechange:function(){if(["loaded","complete"].contains(this.readyState)){E();}}}).setProperties(D);if(Browser.Engine.webkit419){var C=(function(){if(!$try(A)){return ; }$clear(C);E();}).periodical(50);}return B.inject(G.head);},css:function(B,A){return new Element("link",$merge({rel:"stylesheet",media:"screen",type:"text/css",href:B},A)).inject(document.head); },image:function(C,B){B=$merge({onload:$empty,onabort:$empty,onerror:$empty},B);var D=new Image();var A=$(D)||new Element("img");["load","abort","error"].each(function(E){var F="on"+E; var G=B[F];delete B[F];D[F]=function(){if(!D){return ;}if(!A.parentNode){A.width=D.width;A.height=D.height;}D=D.onload=D.onabort=D.onerror=null;G.delay(1,A,A); A.fireEvent(E,A,1);};});D.src=A.src=C;if(D&&D.complete){D.onload.delay(1);}return A.setProperties(B);},images:function(D,C){C=$merge({onComplete:$empty,onProgress:$empty},C); if(!D.push){D=[D];}var A=[];var B=0;D.each(function(F){var E=new Asset.image(F,{onload:function(){C.onProgress.call(this,B,D.indexOf(F));B++;if(B==D.length){C.onComplete(); }}});A.push(E);});return new Elements(A);}});var Slider=new Class({Implements:[Events,Options],options:{onTick:function(A){if(this.options.snap){A=this.toPosition(this.step); }this.knob.setStyle(this.property,A);},snap:false,offset:0,range:false,wheel:false,steps:100,mode:"horizontal"},initialize:function(E,A,D){this.setOptions(D); this.element=$(E);this.knob=$(A);this.previousChange=this.previousEnd=this.step=-1;this.element.addEvent("mousedown",this.clickedElement.bind(this));if(this.options.wheel){this.element.addEvent("mousewheel",this.scrolledElement.bindWithEvent(this)); }var F,B={},C={x:false,y:false};switch(this.options.mode){case"vertical":this.axis="y";this.property="top";F="offsetHeight";break;case"horizontal":this.axis="x"; this.property="left";F="offsetWidth";}this.half=this.knob[F]/2;this.full=this.element[F]-this.knob[F]+(this.options.offset*2);this.min=$chk(this.options.range[0])?this.options.range[0]:0; this.max=$chk(this.options.range[1])?this.options.range[1]:this.options.steps;this.range=this.max-this.min;this.steps=this.options.steps||this.full;this.stepSize=Math.abs(this.range)/this.steps; this.stepWidth=this.stepSize*this.full/Math.abs(this.range);this.knob.setStyle("position","relative").setStyle(this.property,-this.options.offset);C[this.axis]=this.property; B[this.axis]=[-this.options.offset,this.full-this.options.offset];this.drag=new Drag(this.knob,{snap:0,limit:B,modifiers:C,onDrag:this.draggedKnob.bind(this),onStart:this.draggedKnob.bind(this),onComplete:function(){this.draggedKnob(); this.end();}.bind(this)});if(this.options.snap){this.drag.options.grid=Math.ceil(this.stepWidth);this.drag.options.limit[this.axis][1]=this.full;}},set:function(A){if(!((this.range>0)^(A0)^(A>this.max))){A=this.max;}this.step=Math.round(A);this.checkStep();this.end();this.fireEvent("tick",this.toPosition(this.step));return this; },clickedElement:function(C){var B=this.range<0?-1:1;var A=C.page[this.axis]-this.element.getPosition()[this.axis]-this.half;A=A.limit(-this.options.offset,this.full-this.options.offset); this.step=Math.round(this.min+B*this.toStep(A));this.checkStep();this.end();this.fireEvent("tick",A);},scrolledElement:function(A){var B=(this.options.mode=="horizontal")?(A.wheel<0):(A.wheel>0); this.set(B?this.step-this.stepSize:this.step+this.stepSize);A.stop();},draggedKnob:function(){var B=this.range<0?-1:1;var A=this.drag.value.now[this.axis]; A=A.limit(-this.options.offset,this.full-this.options.offset);this.step=Math.round(this.min+B*this.toStep(A));this.checkStep();},checkStep:function(){if(this.previousChange!=this.step){this.previousChange=this.step; this.fireEvent("change",this.step);}},end:function(){if(this.previousEnd!==this.step){this.previousEnd=this.step;this.fireEvent("complete",this.step+""); }},toStep:function(A){var B=(A+this.options.offset)*this.stepSize/this.full*this.steps;return this.options.steps?Math.round(B-=B%this.stepSize):B;},toPosition:function(A){return(this.full*Math.abs(this.min-A))/(this.steps*this.stepSize)-this.options.offset; }});var Scroller=new Class({Implements:[Events,Options],options:{area:20,velocity:1,onChange:function(A,B){this.element.scrollTo(A,B);}},initialize:function(B,A){this.setOptions(A); this.element=$(B);this.listener=($type(this.element)!="element")?$(this.element.getDocument().body):this.element;this.timer=null;this.coord=this.getCoords.bind(this); },start:function(){this.listener.addEvent("mousemove",this.coord);},stop:function(){this.listener.removeEvent("mousemove",this.coord);this.timer=$clear(this.timer); },getCoords:function(A){this.page=(this.listener.get("tag")=="body")?A.client:A.page;if(!this.timer){this.timer=this.scroll.periodical(50,this);}},scroll:function(){var B=this.element.getSize(),A=this.element.getScroll(),E=this.element.getPosition(),D={x:0,y:0}; for(var C in this.page){if(this.page[C]<(this.options.area+E[C])&&A[C]!=0){D[C]=(this.page[C]-this.options.area-E[C])*this.options.velocity;}else{if(this.page[C]+this.options.area>(B[C]+E[C])&&B[C]+B[C]!=A[C]){D[C]=(this.page[C]-B[C]+this.options.area-E[C])*this.options.velocity; }}}if(D.y||D.x){this.fireEvent("change",[A.x+D.x,A.y+D.y]);}}});tdiary-contrib-5.0.8/util/image-gallery/js/SmoothGallery/scripts/mootools-1.2.1-core-yc.js000066400000000000000000001767131325711763500313040ustar00rootroot00000000000000//MooTools, , My Object Oriented (JavaScript) Tools. Copyright (c) 2006-2008 Valerio Proietti, , MIT Style License. var MooTools={version:"1.2.1",build:"0d4845aab3d9a4fdee2f0d4a6dd59210e4b697cf"};var Native=function(K){K=K||{};var A=K.name;var I=K.legacy;var B=K.protect; var C=K.implement;var H=K.generics;var F=K.initialize;var G=K.afterImplement||function(){};var D=F||I;H=H!==false;D.constructor=Native;D.$family={name:"native"}; if(I&&F){D.prototype=I.prototype;}D.prototype.constructor=D;if(A){var E=A.toLowerCase();D.prototype.$family={name:E};Native.typize(D,E);}var J=function(N,L,O,M){if(!B||M||!N.prototype[L]){N.prototype[L]=O; }if(H){Native.genericize(N,L,B);}G.call(N,L,O);return N;};D.alias=function(N,L,O){if(typeof N=="string"){if((N=this.prototype[N])){return J(this,L,N,O); }}for(var M in N){this.alias(M,N[M],L);}return this;};D.implement=function(M,L,O){if(typeof M=="string"){return J(this,M,L,O);}for(var N in M){J(this,N,M[N],L); }return this;};if(C){D.implement(C);}return D;};Native.genericize=function(B,C,A){if((!A||!B[C])&&typeof B.prototype[C]=="function"){B[C]=function(){var D=Array.prototype.slice.call(arguments); return B.prototype[C].apply(D.shift(),D);};}};Native.implement=function(D,C){for(var B=0,A=D.length;B-1:this.indexOf(A)>-1;},trim:function(){return this.replace(/^\s+|\s+$/g,"");},clean:function(){return this.replace(/\s+/g," ").trim(); },camelCase:function(){return this.replace(/-\D/g,function(A){return A.charAt(1).toUpperCase();});},hyphenate:function(){return this.replace(/[A-Z]/g,function(A){return("-"+A.charAt(0).toLowerCase()); });},capitalize:function(){return this.replace(/\b[a-z]/g,function(A){return A.toUpperCase();});},escapeRegExp:function(){return this.replace(/([-.*+?^${}()|[\]\/\\])/g,"\\$1"); },toInt:function(A){return parseInt(this,A||10);},toFloat:function(){return parseFloat(this);},hexToRgb:function(B){var A=this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); return(A)?A.slice(1).hexToRgb(B):null;},rgbToHex:function(B){var A=this.match(/\d{1,3}/g);return(A)?A.rgbToHex(B):null;},stripScripts:function(B){var A=""; var C=this.replace(/]*>([\s\S]*?)<\/script>/gi,function(){A+=arguments[1]+"\n";return"";});if(B===true){$exec(A);}else{if($type(B)=="function"){B(A,C); }}return C;},substitute:function(A,B){return this.replace(B||(/\\?\{([^{}]+)\}/g),function(D,C){if(D.charAt(0)=="\\"){return D.slice(1);}return(A[C]!=undefined)?A[C]:""; });}});Hash.implement({has:Object.prototype.hasOwnProperty,keyOf:function(B){for(var A in this){if(this.hasOwnProperty(A)&&this[A]===B){return A;}}return null; },hasValue:function(A){return(Hash.keyOf(this,A)!==null);},extend:function(A){Hash.each(A,function(C,B){Hash.set(this,B,C);},this);return this;},combine:function(A){Hash.each(A,function(C,B){Hash.include(this,B,C); },this);return this;},erase:function(A){if(this.hasOwnProperty(A)){delete this[A];}return this;},get:function(A){return(this.hasOwnProperty(A))?this[A]:null; },set:function(A,B){if(!this[A]||this.hasOwnProperty(A)){this[A]=B;}return this;},empty:function(){Hash.each(this,function(B,A){delete this[A];},this); return this;},include:function(B,C){var A=this[B];if(A==undefined){this[B]=C;}return this;},map:function(B,C){var A=new Hash;Hash.each(this,function(E,D){A.set(D,B.call(C,E,D,this)); },this);return A;},filter:function(B,C){var A=new Hash;Hash.each(this,function(E,D){if(B.call(C,E,D,this)){A.set(D,E);}},this);return A;},every:function(B,C){for(var A in this){if(this.hasOwnProperty(A)&&!B.call(C,this[A],A)){return false; }}return true;},some:function(B,C){for(var A in this){if(this.hasOwnProperty(A)&&B.call(C,this[A],A)){return true;}}return false;},getKeys:function(){var A=[]; Hash.each(this,function(C,B){A.push(B);});return A;},getValues:function(){var A=[];Hash.each(this,function(B){A.push(B);});return A;},toQueryString:function(A){var B=[]; Hash.each(this,function(F,E){if(A){E=A+"["+E+"]";}var D;switch($type(F)){case"object":D=Hash.toQueryString(F,E);break;case"array":var C={};F.each(function(H,G){C[G]=H; });D=Hash.toQueryString(C,E);break;default:D=E+"="+encodeURIComponent(F);}if(F!=undefined){B.push(D);}});return B.join("&");}});Hash.alias({keyOf:"indexOf",hasValue:"contains"}); var Event=new Native({name:"Event",initialize:function(A,F){F=F||window;var K=F.document;A=A||F.event;if(A.$extended){return A;}this.$extended=true;var J=A.type; var G=A.target||A.srcElement;while(G&&G.nodeType==3){G=G.parentNode;}if(J.test(/key/)){var B=A.which||A.keyCode;var M=Event.Keys.keyOf(B);if(J=="keydown"){var D=B-111; if(D>0&&D<13){M="f"+D;}}M=M||String.fromCharCode(B).toLowerCase();}else{if(J.match(/(click|mouse|menu)/i)){K=(!K.compatMode||K.compatMode=="CSS1Compat")?K.html:K.body; var I={x:A.pageX||A.clientX+K.scrollLeft,y:A.pageY||A.clientY+K.scrollTop};var C={x:(A.pageX)?A.pageX-F.pageXOffset:A.clientX,y:(A.pageY)?A.pageY-F.pageYOffset:A.clientY}; if(J.match(/DOMMouseScroll|mousewheel/)){var H=(A.wheelDelta)?A.wheelDelta/120:-(A.detail||0)/3;}var E=(A.which==3)||(A.button==2);var L=null;if(J.match(/over|out/)){switch(J){case"mouseover":L=A.relatedTarget||A.fromElement; break;case"mouseout":L=A.relatedTarget||A.toElement;}if(!(function(){while(L&&L.nodeType==3){L=L.parentNode;}return true;}).create({attempt:Browser.Engine.gecko})()){L=false; }}}}return $extend(this,{event:A,type:J,page:I,client:C,rightClick:E,wheel:H,relatedTarget:L,target:G,code:B,key:M,shift:A.shiftKey,control:A.ctrlKey,alt:A.altKey,meta:A.metaKey}); }});Event.Keys=new Hash({enter:13,up:38,down:40,left:37,right:39,esc:27,space:32,backspace:8,tab:9,"delete":46});Event.implement({stop:function(){return this.stopPropagation().preventDefault(); },stopPropagation:function(){if(this.event.stopPropagation){this.event.stopPropagation();}else{this.event.cancelBubble=true;}return this;},preventDefault:function(){if(this.event.preventDefault){this.event.preventDefault(); }else{this.event.returnValue=false;}return this;}});var Class=new Native({name:"Class",initialize:function(B){B=B||{};var A=function(){for(var E in this){if($type(this[E])!="function"){this[E]=$unlink(this[E]); }}this.constructor=A;if(Class.prototyping){return this;}var D=(this.initialize)?this.initialize.apply(this,arguments):this;if(this.options&&this.options.initialize){this.options.initialize.call(this); }return D;};for(var C in Class.Mutators){if(!B[C]){continue;}B=Class.Mutators[C](B,B[C]);delete B[C];}$extend(A,this);A.constructor=Class;A.prototype=B; return A;}});Class.Mutators={Extends:function(C,A){Class.prototyping=A.prototype;var B=new A;delete B.parent;B=Class.inherit(B,C);delete Class.prototyping; return B;},Implements:function(A,B){$splat(B).each(function(C){Class.prototying=C;$extend(A,($type(C)=="class")?new C:C);delete Class.prototyping;});return A; }};Class.extend({inherit:function(B,E){var A=arguments.callee.caller;for(var D in E){var C=E[D];var G=B[D];var F=$type(C);if(G&&F=="function"){if(C!=G){if(A){C.__parent=G; B[D]=C;}else{Class.override(B,D,C);}}}else{if(F=="object"){B[D]=$merge(G,C);}else{B[D]=C;}}}if(A){B.parent=function(){return arguments.callee.caller.__parent.apply(this,arguments); };}return B;},override:function(B,A,E){var D=Class.prototyping;if(D&&B[A]!=D[A]){D=null;}var C=function(){var F=this.parent;this.parent=D?D[A]:B[A];var G=E.apply(this,arguments); this.parent=F;return G;};B[A]=C;}});Class.implement({implement:function(){var A=this.prototype;$each(arguments,function(B){Class.inherit(A,B);});return this; }});var Chain=new Class({$chain:[],chain:function(){this.$chain.extend(Array.flatten(arguments));return this;},callChain:function(){return(this.$chain.length)?this.$chain.shift().apply(this,arguments):false; },clearChain:function(){this.$chain.empty();return this;}});var Events=new Class({$events:{},addEvent:function(C,B,A){C=Events.removeOn(C);if(B!=$empty){this.$events[C]=this.$events[C]||[]; this.$events[C].include(B);if(A){B.internal=true;}}return this;},addEvents:function(A){for(var B in A){this.addEvent(B,A[B]);}return this;},fireEvent:function(C,B,A){C=Events.removeOn(C); if(!this.$events||!this.$events[C]){return this;}this.$events[C].each(function(D){D.create({bind:this,delay:A,"arguments":B})();},this);return this;},removeEvent:function(B,A){B=Events.removeOn(B); if(!this.$events[B]){return this;}if(!A.internal){this.$events[B].erase(A);}return this;},removeEvents:function(C){if($type(C)=="object"){for(var D in C){this.removeEvent(D,C[D]); }return this;}if(C){C=Events.removeOn(C);}for(var D in this.$events){if(C&&C!=D){continue;}var B=this.$events[D];for(var A=B.length;A--;A){this.removeEvent(D,B[A]); }}return this;}});Events.removeOn=function(A){return A.replace(/^on([A-Z])/,function(B,C){return C.toLowerCase();});};var Options=new Class({setOptions:function(){this.options=$merge.run([this.options].extend(arguments)); if(!this.addEvent){return this;}for(var A in this.options){if($type(this.options[A])!="function"||!(/^on[A-Z]/).test(A)){continue;}this.addEvent(A,this.options[A]); delete this.options[A];}return this;}});var Element=new Native({name:"Element",legacy:window.Element,initialize:function(A,B){var C=Element.Constructors.get(A); if(C){return C(B);}if(typeof A=="string"){return document.newElement(A,B);}return $(A).set(B);},afterImplement:function(A,B){Element.Prototype[A]=B;if(Array[A]){return ; }Elements.implement(A,function(){var C=[],G=true;for(var E=0,D=this.length;E";}return $.element(this.createElement(A)).set(B);},newTextNode:function(A){return this.createTextNode(A); },getDocument:function(){return this;},getWindow:function(){return this.window;}});Window.implement({$:function(B,C){if(B&&B.$family&&B.uid){return B;}var A=$type(B); return($[A])?$[A](B,C,this.document):null;},$$:function(A){if(arguments.length==1&&typeof A=="string"){return this.document.getElements(A);}var F=[];var C=Array.flatten(arguments); for(var D=0,B=C.length;D1);A.each(function(E){var F=this.getElementsByTagName(E.trim());(B)?C.extend(F):C=F;},this);return new Elements(C,{ddup:B,cash:!D}); }});(function(){var H={},F={};var I={input:"checked",option:"selected",textarea:(Browser.Engine.webkit&&Browser.Engine.version<420)?"innerHTML":"value"}; var C=function(L){return(F[L]||(F[L]={}));};var G=function(N,L){if(!N){return ;}var M=N.uid;if(Browser.Engine.trident){if(N.clearAttributes){var P=L&&N.cloneNode(false); N.clearAttributes();if(P){N.mergeAttributes(P);}}else{if(N.removeEvents){N.removeEvents();}}if((/object/i).test(N.tagName)){for(var O in N){if(typeof N[O]=="function"){N[O]=$empty; }}Element.dispose(N);}}if(!M){return ;}H[M]=F[M]=null;};var D=function(){Hash.each(H,G);if(Browser.Engine.trident){$A(document.getElementsByTagName("object")).each(G); }if(window.CollectGarbage){CollectGarbage();}H=F=null;};var J=function(N,L,S,M,P,R){var O=N[S||L];var Q=[];while(O){if(O.nodeType==1&&(!M||Element.match(O,M))){if(!P){return $(O,R); }Q.push(O);}O=O[L];}return(P)?new Elements(Q,{ddup:false,cash:!R}):null;};var E={html:"innerHTML","class":"className","for":"htmlFor",text:(Browser.Engine.trident||(Browser.Engine.webkit&&Browser.Engine.version<420))?"innerText":"textContent"}; var B=["compact","nowrap","ismap","declare","noshade","checked","disabled","readonly","multiple","selected","noresize","defer"];var K=["value","accessKey","cellPadding","cellSpacing","colSpan","frameBorder","maxLength","readOnly","rowSpan","tabIndex","useMap"]; Hash.extend(E,B.associate(B));Hash.extend(E,K.associate(K.map(String.toLowerCase)));var A={before:function(M,L){if(L.parentNode){L.parentNode.insertBefore(M,L); }},after:function(M,L){if(!L.parentNode){return ;}var N=L.nextSibling;(N)?L.parentNode.insertBefore(M,N):L.parentNode.appendChild(M);},bottom:function(M,L){L.appendChild(M); },top:function(M,L){var N=L.firstChild;(N)?L.insertBefore(M,N):L.appendChild(M);}};A.inside=A.bottom;Hash.each(A,function(L,M){M=M.capitalize();Element.implement("inject"+M,function(N){L(this,$(N,true)); return this;});Element.implement("grab"+M,function(N){L($(N,true),this);return this;});});Element.implement({set:function(O,M){switch($type(O)){case"object":for(var N in O){this.set(N,O[N]); }break;case"string":var L=Element.Properties.get(O);(L&&L.set)?L.set.apply(this,Array.slice(arguments,1)):this.setProperty(O,M);}return this;},get:function(M){var L=Element.Properties.get(M); return(L&&L.get)?L.get.apply(this,Array.slice(arguments,1)):this.getProperty(M);},erase:function(M){var L=Element.Properties.get(M);(L&&L.erase)?L.erase.apply(this):this.removeProperty(M); return this;},setProperty:function(M,N){var L=E[M];if(N==undefined){return this.removeProperty(M);}if(L&&B[M]){N=!!N;}(L)?this[L]=N:this.setAttribute(M,""+N); return this;},setProperties:function(L){for(var M in L){this.setProperty(M,L[M]);}return this;},getProperty:function(M){var L=E[M];var N=(L)?this[L]:this.getAttribute(M,2); return(B[M])?!!N:(L)?N:N||null;},getProperties:function(){var L=$A(arguments);return L.map(this.getProperty,this).associate(L);},removeProperty:function(M){var L=E[M]; (L)?this[L]=(L&&B[M])?false:"":this.removeAttribute(M);return this;},removeProperties:function(){Array.each(arguments,this.removeProperty,this);return this; },hasClass:function(L){return this.className.contains(L," ");},addClass:function(L){if(!this.hasClass(L)){this.className=(this.className+" "+L).clean(); }return this;},removeClass:function(L){this.className=this.className.replace(new RegExp("(^|\\s)"+L+"(?:\\s|$)"),"$1");return this;},toggleClass:function(L){return this.hasClass(L)?this.removeClass(L):this.addClass(L); },adopt:function(){Array.flatten(arguments).each(function(L){L=$(L,true);if(L){this.appendChild(L);}},this);return this;},appendText:function(M,L){return this.grab(this.getDocument().newTextNode(M),L); },grab:function(M,L){A[L||"bottom"]($(M,true),this);return this;},inject:function(M,L){A[L||"bottom"](this,$(M,true));return this;},replaces:function(L){L=$(L,true); L.parentNode.replaceChild(this,L);return this;},wraps:function(M,L){M=$(M,true);return this.replaces(M).grab(M,L);},getPrevious:function(L,M){return J(this,"previousSibling",null,L,false,M); },getAllPrevious:function(L,M){return J(this,"previousSibling",null,L,true,M);},getNext:function(L,M){return J(this,"nextSibling",null,L,false,M);},getAllNext:function(L,M){return J(this,"nextSibling",null,L,true,M); },getFirst:function(L,M){return J(this,"nextSibling","firstChild",L,false,M);},getLast:function(L,M){return J(this,"previousSibling","lastChild",L,false,M); },getParent:function(L,M){return J(this,"parentNode",null,L,false,M);},getParents:function(L,M){return J(this,"parentNode",null,L,true,M);},getChildren:function(L,M){return J(this,"nextSibling","firstChild",L,true,M); },getWindow:function(){return this.ownerDocument.window;},getDocument:function(){return this.ownerDocument;},getElementById:function(O,N){var M=this.ownerDocument.getElementById(O); if(!M){return null;}for(var L=M.parentNode;L!=this;L=L.parentNode){if(!L){return null;}}return $.element(M,N);},getSelected:function(){return new Elements($A(this.options).filter(function(L){return L.selected; }));},getComputedStyle:function(M){if(this.currentStyle){return this.currentStyle[M.camelCase()];}var L=this.getDocument().defaultView.getComputedStyle(this,null); return(L)?L.getPropertyValue([M.hyphenate()]):null;},toQueryString:function(){var L=[];this.getElements("input, select, textarea",true).each(function(M){if(!M.name||M.disabled){return ; }var N=(M.tagName.toLowerCase()=="select")?Element.getSelected(M).map(function(O){return O.value;}):((M.type=="radio"||M.type=="checkbox")&&!M.checked)?null:M.value; $splat(N).each(function(O){if(typeof O!="undefined"){L.push(M.name+"="+encodeURIComponent(O));}});});return L.join("&");},clone:function(O,L){O=O!==false; var R=this.cloneNode(O);var N=function(V,U){if(!L){V.removeAttribute("id");}if(Browser.Engine.trident){V.clearAttributes();V.mergeAttributes(U);V.removeAttribute("uid"); if(V.options){var W=V.options,S=U.options;for(var T=W.length;T--;){W[T].selected=S[T].selected;}}}var X=I[U.tagName.toLowerCase()];if(X&&U[X]){V[X]=U[X]; }};if(O){var P=R.getElementsByTagName("*"),Q=this.getElementsByTagName("*");for(var M=P.length;M--;){N(P[M],Q[M]);}}N(R,this);return $(R);},destroy:function(){Element.empty(this); Element.dispose(this);G(this,true);return null;},empty:function(){$A(this.childNodes).each(function(L){Element.destroy(L);});return this;},dispose:function(){return(this.parentNode)?this.parentNode.removeChild(this):this; },hasChild:function(L){L=$(L,true);if(!L){return false;}if(Browser.Engine.webkit&&Browser.Engine.version<420){return $A(this.getElementsByTagName(L.tagName)).contains(L); }return(this.contains)?(this!=L&&this.contains(L)):!!(this.compareDocumentPosition(L)&16);},match:function(L){return(!L||(L==this)||(Element.get(this,"tag")==L)); }});Native.implement([Element,Window,Document],{addListener:function(O,N){if(O=="unload"){var L=N,M=this;N=function(){M.removeListener("unload",N);L(); };}else{H[this.uid]=this;}if(this.addEventListener){this.addEventListener(O,N,false);}else{this.attachEvent("on"+O,N);}return this;},removeListener:function(M,L){if(this.removeEventListener){this.removeEventListener(M,L,false); }else{this.detachEvent("on"+M,L);}return this;},retrieve:function(M,L){var O=C(this.uid),N=O[M];if(L!=undefined&&N==undefined){N=O[M]=L;}return $pick(N); },store:function(M,L){var N=C(this.uid);N[M]=L;return this;},eliminate:function(L){var M=C(this.uid);delete M[L];return this;}});window.addListener("unload",D); })();Element.Properties=new Hash;Element.Properties.style={set:function(A){this.style.cssText=A;},get:function(){return this.style.cssText;},erase:function(){this.style.cssText=""; }};Element.Properties.tag={get:function(){return this.tagName.toLowerCase();}};Element.Properties.html=(function(){var C=document.createElement("div"); var A={table:[1,"","
      "],select:[1,""],tbody:[2,"","
      "],tr:[3,"","
      "]}; A.thead=A.tfoot=A.tbody;var B={set:function(){var E=Array.flatten(arguments).join("");var F=Browser.Engine.trident&&A[this.get("tag")];if(F){var G=C;G.innerHTML=F[1]+E+F[2]; for(var D=F[0];D--;){G=G.firstChild;}this.empty().adopt(G.childNodes);}else{this.innerHTML=E;}}};B.erase=B.set;return B;})();if(Browser.Engine.webkit&&Browser.Engine.version<420){Element.Properties.text={get:function(){if(this.innerText){return this.innerText; }var A=this.ownerDocument.newElement("div",{html:this.innerHTML}).inject(this.ownerDocument.body);var B=A.innerText;A.destroy();return B;}};}Element.Properties.events={set:function(A){this.addEvents(A); }};Native.implement([Element,Window,Document],{addEvent:function(E,G){var H=this.retrieve("events",{});H[E]=H[E]||{keys:[],values:[]};if(H[E].keys.contains(G)){return this; }H[E].keys.push(G);var F=E,A=Element.Events.get(E),C=G,I=this;if(A){if(A.onAdd){A.onAdd.call(this,G);}if(A.condition){C=function(J){if(A.condition.call(this,J)){return G.call(this,J); }return true;};}F=A.base||F;}var D=function(){return G.call(I);};var B=Element.NativeEvents[F];if(B){if(B==2){D=function(J){J=new Event(J,I.getWindow()); if(C.call(I,J)===false){J.stop();}};}this.addListener(F,D);}H[E].values.push(D);return this;},removeEvent:function(C,B){var A=this.retrieve("events");if(!A||!A[C]){return this; }var F=A[C].keys.indexOf(B);if(F==-1){return this;}A[C].keys.splice(F,1);var E=A[C].values.splice(F,1)[0];var D=Element.Events.get(C);if(D){if(D.onRemove){D.onRemove.call(this,B); }C=D.base||C;}return(Element.NativeEvents[C])?this.removeListener(C,E):this;},addEvents:function(A){for(var B in A){this.addEvent(B,A[B]);}return this; },removeEvents:function(A){if($type(A)=="object"){for(var C in A){this.removeEvent(C,A[C]);}return this;}var B=this.retrieve("events");if(!B){return this; }if(!A){for(var C in B){this.removeEvents(C);}this.eliminate("events");}else{if(B[A]){while(B[A].keys[0]){this.removeEvent(A,B[A].keys[0]);}B[A]=null;}}return this; },fireEvent:function(D,B,A){var C=this.retrieve("events");if(!C||!C[D]){return this;}C[D].keys.each(function(E){E.create({bind:this,delay:A,"arguments":B})(); },this);return this;},cloneEvents:function(D,A){D=$(D);var C=D.retrieve("events");if(!C){return this;}if(!A){for(var B in C){this.cloneEvents(D,B);}}else{if(C[A]){C[A].keys.each(function(E){this.addEvent(A,E); },this);}}return this;}});Element.NativeEvents={click:2,dblclick:2,mouseup:2,mousedown:2,contextmenu:2,mousewheel:2,DOMMouseScroll:2,mouseover:2,mouseout:2,mousemove:2,selectstart:2,selectend:2,keydown:2,keypress:2,keyup:2,focus:2,blur:2,change:2,reset:2,select:2,submit:2,load:1,unload:1,beforeunload:2,resize:1,move:1,DOMContentLoaded:1,readystatechange:1,error:1,abort:1,scroll:1}; (function(){var A=function(B){var C=B.relatedTarget;if(C==undefined){return true;}if(C===false){return false;}return($type(this)!="document"&&C!=this&&C.prefix!="xul"&&!this.hasChild(C)); };Element.Events=new Hash({mouseenter:{base:"mouseover",condition:A},mouseleave:{base:"mouseout",condition:A},mousewheel:{base:(Browser.Engine.gecko)?"DOMMouseScroll":"mousewheel"}}); })();Element.Properties.styles={set:function(A){this.setStyles(A);}};Element.Properties.opacity={set:function(A,B){if(!B){if(A==0){if(this.style.visibility!="hidden"){this.style.visibility="hidden"; }}else{if(this.style.visibility!="visible"){this.style.visibility="visible";}}}if(!this.currentStyle||!this.currentStyle.hasLayout){this.style.zoom=1;}if(Browser.Engine.trident){this.style.filter=(A==1)?"":"alpha(opacity="+A*100+")"; }this.style.opacity=A;this.store("opacity",A);},get:function(){return this.retrieve("opacity",1);}};Element.implement({setOpacity:function(A){return this.set("opacity",A,true); },getOpacity:function(){return this.get("opacity");},setStyle:function(B,A){switch(B){case"opacity":return this.set("opacity",parseFloat(A));case"float":B=(Browser.Engine.trident)?"styleFloat":"cssFloat"; }B=B.camelCase();if($type(A)!="string"){var C=(Element.Styles.get(B)||"@").split(" ");A=$splat(A).map(function(E,D){if(!C[D]){return"";}return($type(E)=="number")?C[D].replace("@",Math.round(E)):E; }).join(" ");}else{if(A==String(Number(A))){A=Math.round(A);}}this.style[B]=A;return this;},getStyle:function(G){switch(G){case"opacity":return this.get("opacity"); case"float":G=(Browser.Engine.trident)?"styleFloat":"cssFloat";}G=G.camelCase();var A=this.style[G];if(!$chk(A)){A=[];for(var F in Element.ShortStyles){if(G!=F){continue; }for(var E in Element.ShortStyles[F]){A.push(this.getStyle(E));}return A.join(" ");}A=this.getComputedStyle(G);}if(A){A=String(A);var C=A.match(/rgba?\([\d\s,]+\)/); if(C){A=A.replace(C[0],C[0].rgbToHex());}}if(Browser.Engine.presto||(Browser.Engine.trident&&!$chk(parseInt(A)))){if(G.test(/^(height|width)$/)){var B=(G=="width")?["left","right"]:["top","bottom"],D=0; B.each(function(H){D+=this.getStyle("border-"+H+"-width").toInt()+this.getStyle("padding-"+H).toInt();},this);return this["offset"+G.capitalize()]-D+"px"; }if((Browser.Engine.presto)&&String(A).test("px")){return A;}if(G.test(/(border(.+)Width|margin|padding)/)){return"0px";}}return A;},setStyles:function(B){for(var A in B){this.setStyle(A,B[A]); }return this;},getStyles:function(){var A={};Array.each(arguments,function(B){A[B]=this.getStyle(B);},this);return A;}});Element.Styles=new Hash({left:"@px",top:"@px",bottom:"@px",right:"@px",width:"@px",height:"@px",maxWidth:"@px",maxHeight:"@px",minWidth:"@px",minHeight:"@px",backgroundColor:"rgb(@, @, @)",backgroundPosition:"@px @px",color:"rgb(@, @, @)",fontSize:"@px",letterSpacing:"@px",lineHeight:"@px",clip:"rect(@px @px @px @px)",margin:"@px @px @px @px",padding:"@px @px @px @px",border:"@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)",borderWidth:"@px @px @px @px",borderStyle:"@ @ @ @",borderColor:"rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)",zIndex:"@",zoom:"@",fontWeight:"@",textIndent:"@px",opacity:"@"}); Element.ShortStyles={margin:{},padding:{},border:{},borderWidth:{},borderStyle:{},borderColor:{}};["Top","Right","Bottom","Left"].each(function(G){var F=Element.ShortStyles; var B=Element.Styles;["margin","padding"].each(function(H){var I=H+G;F[H][I]=B[I]="@px";});var E="border"+G;F.border[E]=B[E]="@px @ rgb(@, @, @)";var D=E+"Width",A=E+"Style",C=E+"Color"; F[E]={};F.borderWidth[D]=F[E][D]=B[D]="@px";F.borderStyle[A]=F[E][A]=B[A]="@";F.borderColor[C]=F[E][C]=B[C]="rgb(@, @, @)";});(function(){Element.implement({scrollTo:function(H,I){if(B(this)){this.getWindow().scrollTo(H,I); }else{this.scrollLeft=H;this.scrollTop=I;}return this;},getSize:function(){if(B(this)){return this.getWindow().getSize();}return{x:this.offsetWidth,y:this.offsetHeight}; },getScrollSize:function(){if(B(this)){return this.getWindow().getScrollSize();}return{x:this.scrollWidth,y:this.scrollHeight};},getScroll:function(){if(B(this)){return this.getWindow().getScroll(); }return{x:this.scrollLeft,y:this.scrollTop};},getScrolls:function(){var I=this,H={x:0,y:0};while(I&&!B(I)){H.x+=I.scrollLeft;H.y+=I.scrollTop;I=I.parentNode; }return H;},getOffsetParent:function(){var H=this;if(B(H)){return null;}if(!Browser.Engine.trident){return H.offsetParent;}while((H=H.parentNode)&&!B(H)){if(D(H,"position")!="static"){return H; }}return null;},getOffsets:function(){if(Browser.Engine.trident){var L=this.getBoundingClientRect(),J=this.getDocument().documentElement;return{x:L.left+J.scrollLeft-J.clientLeft,y:L.top+J.scrollTop-J.clientTop}; }var I=this,H={x:0,y:0};if(B(this)){return H;}while(I&&!B(I)){H.x+=I.offsetLeft;H.y+=I.offsetTop;if(Browser.Engine.gecko){if(!F(I)){H.x+=C(I);H.y+=G(I); }var K=I.parentNode;if(K&&D(K,"overflow")!="visible"){H.x+=C(K);H.y+=G(K);}}else{if(I!=this&&Browser.Engine.webkit){H.x+=C(I);H.y+=G(I);}}I=I.offsetParent; }if(Browser.Engine.gecko&&!F(this)){H.x-=C(this);H.y-=G(this);}return H;},getPosition:function(K){if(B(this)){return{x:0,y:0};}var L=this.getOffsets(),I=this.getScrolls(); var H={x:L.x-I.x,y:L.y-I.y};var J=(K&&(K=$(K)))?K.getPosition():{x:0,y:0};return{x:H.x-J.x,y:H.y-J.y};},getCoordinates:function(J){if(B(this)){return this.getWindow().getCoordinates(); }var H=this.getPosition(J),I=this.getSize();var K={left:H.x,top:H.y,width:I.x,height:I.y};K.right=K.left+K.width;K.bottom=K.top+K.height;return K;},computePosition:function(H){return{left:H.x-E(this,"margin-left"),top:H.y-E(this,"margin-top")}; },position:function(H){return this.setStyles(this.computePosition(H));}});Native.implement([Document,Window],{getSize:function(){var I=this.getWindow(); if(Browser.Engine.presto||Browser.Engine.webkit){return{x:I.innerWidth,y:I.innerHeight};}var H=A(this);return{x:H.clientWidth,y:H.clientHeight};},getScroll:function(){var I=this.getWindow(); var H=A(this);return{x:I.pageXOffset||H.scrollLeft,y:I.pageYOffset||H.scrollTop};},getScrollSize:function(){var I=A(this);var H=this.getSize();return{x:Math.max(I.scrollWidth,H.x),y:Math.max(I.scrollHeight,H.y)}; },getPosition:function(){return{x:0,y:0};},getCoordinates:function(){var H=this.getSize();return{top:0,left:0,bottom:H.y,right:H.x,height:H.y,width:H.x}; }});var D=Element.getComputedStyle;function E(H,I){return D(H,I).toInt()||0;}function F(H){return D(H,"-moz-box-sizing")=="border-box";}function G(H){return E(H,"border-top-width"); }function C(H){return E(H,"border-left-width");}function B(H){return(/^(?:body|html)$/i).test(H.tagName);}function A(H){var I=H.getDocument();return(!I.compatMode||I.compatMode=="CSS1Compat")?I.html:I.body; }})();Native.implement([Window,Document,Element],{getHeight:function(){return this.getSize().y;},getWidth:function(){return this.getSize().x;},getScrollTop:function(){return this.getScroll().y; },getScrollLeft:function(){return this.getScroll().x;},getScrollHeight:function(){return this.getScrollSize().y;},getScrollWidth:function(){return this.getScrollSize().x; },getTop:function(){return this.getPosition().y;},getLeft:function(){return this.getPosition().x;}});Native.implement([Document,Element],{getElements:function(H,G){H=H.split(","); var C,E={};for(var D=0,B=H.length;D1),cash:!G});}});Element.implement({match:function(B){if(!B||(B==this)){return true;}var D=Selectors.Utils.parseTagAndID(B); var A=D[0],E=D[1];if(!Selectors.Filters.byID(this,E)||!Selectors.Filters.byTag(this,A)){return false;}var C=Selectors.Utils.parseSelector(B);return(C)?Selectors.Utils.filter(this,C,{}):true; }});var Selectors={Cache:{nth:{},parsed:{}}};Selectors.RegExps={id:(/#([\w-]+)/),tag:(/^(\w+|\*)/),quick:(/^(\w+|\*)$/),splitter:(/\s*([+>~\s])\s*([a-zA-Z#.*:\[])/g),combined:(/\.([\w-]+)|\[(\w+)(?:([!*^$~|]?=)(["']?)([^\4]*?)\4)?\]|:([\w-]+)(?:\(["']?(.*?)?["']?\)|$)/g)}; Selectors.Utils={chk:function(B,C){if(!C){return true;}var A=$uid(B);if(!C[A]){return C[A]=true;}return false;},parseNthArgument:function(F){if(Selectors.Cache.nth[F]){return Selectors.Cache.nth[F]; }var C=F.match(/^([+-]?\d*)?([a-z]+)?([+-]?\d*)?$/);if(!C){return false;}var E=parseInt(C[1]);var B=(E||E===0)?E:1;var D=C[2]||false;var A=parseInt(C[3])||0; if(B!=0){A--;while(A<1){A+=B;}while(A>=B){A-=B;}}else{B=A;D="index";}switch(D){case"n":C={a:B,b:A,special:"n"};break;case"odd":C={a:2,b:0,special:"n"}; break;case"even":C={a:2,b:1,special:"n"};break;case"first":C={a:0,special:"index"};break;case"last":C={special:"last-child"};break;case"only":C={special:"only-child"}; break;default:C={a:(B-1),special:"index"};}return Selectors.Cache.nth[F]=C;},parseSelector:function(E){if(Selectors.Cache.parsed[E]){return Selectors.Cache.parsed[E]; }var D,H={classes:[],pseudos:[],attributes:[]};while((D=Selectors.RegExps.combined.exec(E))){var I=D[1],G=D[2],F=D[3],B=D[5],C=D[6],J=D[7];if(I){H.classes.push(I); }else{if(C){var A=Selectors.Pseudo.get(C);if(A){H.pseudos.push({parser:A,argument:J});}else{H.attributes.push({name:C,operator:"=",value:J});}}else{if(G){H.attributes.push({name:G,operator:F,value:B}); }}}}if(!H.classes.length){delete H.classes;}if(!H.attributes.length){delete H.attributes;}if(!H.pseudos.length){delete H.pseudos;}if(!H.classes&&!H.attributes&&!H.pseudos){H=null; }return Selectors.Cache.parsed[E]=H;},parseTagAndID:function(B){var A=B.match(Selectors.RegExps.tag);var C=B.match(Selectors.RegExps.id);return[(A)?A[1]:"*",(C)?C[1]:false]; },filter:function(F,C,E){var D;if(C.classes){for(D=C.classes.length;D--;D){var G=C.classes[D];if(!Selectors.Filters.byClass(F,G)){return false;}}}if(C.attributes){for(D=C.attributes.length; D--;D){var B=C.attributes[D];if(!Selectors.Filters.byAttribute(F,B.name,B.operator,B.value)){return false;}}}if(C.pseudos){for(D=C.pseudos.length;D--;D){var A=C.pseudos[D]; if(!Selectors.Filters.byPseudo(F,A.parser,A.argument,E)){return false;}}}return true;},getByTagAndID:function(B,A,D){if(D){var C=(B.getElementById)?B.getElementById(D,true):Element.getElementById(B,D,true); return(C&&Selectors.Filters.byTag(C,A))?[C]:[];}else{return B.getElementsByTagName(A);}},search:function(I,H,N){var B=[];var C=H.trim().replace(Selectors.RegExps.splitter,function(Y,X,W){B.push(X); return":)"+W;}).split(":)");var J,E,U;for(var T=0,P=C.length;T":function(H,G,I,A,F){var C=Selectors.Utils.getByTagAndID(G,I,A);for(var E=0,D=C.length;EA){return false;}}return(C==A);},even:function(B,A){return Selectors.Pseudo["nth-child"].call(this,"2n+1",A); },odd:function(B,A){return Selectors.Pseudo["nth-child"].call(this,"2n",A);}});Element.Events.domready={onAdd:function(A){if(Browser.loaded){A.call(this); }}};(function(){var B=function(){if(Browser.loaded){return ;}Browser.loaded=true;window.fireEvent("domready");document.fireEvent("domready");};if(Browser.Engine.trident){var A=document.createElement("div"); (function(){($try(function(){A.doScroll("left");return $(A).inject(document.body).set("html","temp").dispose();}))?B():arguments.callee.delay(50);})(); }else{if(Browser.Engine.webkit&&Browser.Engine.version<525){(function(){(["loaded","complete"].contains(document.readyState))?B():arguments.callee.delay(50); })();}else{window.addEvent("load",B);document.addEvent("DOMContentLoaded",B);}}})();var JSON=new Hash({$specialChars:{"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},$replaceChars:function(A){return JSON.$specialChars[A]||"\\u00"+Math.floor(A.charCodeAt()/16).toString(16)+(A.charCodeAt()%16).toString(16); },encode:function(B){switch($type(B)){case"string":return'"'+B.replace(/[\x00-\x1f\\"]/g,JSON.$replaceChars)+'"';case"array":return"["+String(B.map(JSON.encode).filter($defined))+"]"; case"object":case"hash":var A=[];Hash.each(B,function(E,D){var C=JSON.encode(E);if(C){A.push(JSON.encode(D)+":"+C);}});return"{"+A+"}";case"number":case"boolean":return String(B); case false:return"null";}return null;},decode:function(string,secure){if($type(string)!="string"||!string.length){return null;}if(secure&&!(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(string.replace(/\\./g,"@").replace(/"[^"\\\n\r]*"/g,""))){return null; }return eval("("+string+")");}});Native.implement([Hash,Array,String,Number],{toJSON:function(){return JSON.encode(this);}});var Cookie=new Class({Implements:Options,options:{path:false,domain:false,duration:false,secure:false,document:document},initialize:function(B,A){this.key=B; this.setOptions(A);},write:function(B){B=encodeURIComponent(B);if(this.options.domain){B+="; domain="+this.options.domain;}if(this.options.path){B+="; path="+this.options.path; }if(this.options.duration){var A=new Date();A.setTime(A.getTime()+this.options.duration*24*60*60*1000);B+="; expires="+A.toGMTString();}if(this.options.secure){B+="; secure"; }this.options.document.cookie=this.key+"="+B;return this;},read:function(){var A=this.options.document.cookie.match("(?:^|;)\\s*"+this.key.escapeRegExp()+"=([^;]*)"); return(A)?decodeURIComponent(A[1]):null;},dispose:function(){new Cookie(this.key,$merge(this.options,{duration:-1})).write("");return this;}});Cookie.write=function(B,C,A){return new Cookie(B,A).write(C); };Cookie.read=function(A){return new Cookie(A).read();};Cookie.dispose=function(B,A){return new Cookie(B,A).dispose();};var Swiff=new Class({Implements:[Options],options:{id:null,height:1,width:1,container:null,properties:{},params:{quality:"high",allowScriptAccess:"always",wMode:"transparent",swLiveConnect:true},callBacks:{},vars:{}},toElement:function(){return this.object; },initialize:function(L,M){this.instance="Swiff_"+$time();this.setOptions(M);M=this.options;var B=this.id=M.id||this.instance;var A=$(M.container);Swiff.CallBacks[this.instance]={}; var E=M.params,G=M.vars,F=M.callBacks;var H=$extend({height:M.height,width:M.width},M.properties);var K=this;for(var D in F){Swiff.CallBacks[this.instance][D]=(function(N){return function(){return N.apply(K.object,arguments); };})(F[D]);G[D]="Swiff.CallBacks."+this.instance+"."+D;}E.flashVars=Hash.toQueryString(G);if(Browser.Engine.trident){H.classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"; E.movie=L;}else{H.type="application/x-shockwave-flash";H.data=L;}var J=''; }}J+="";this.object=((A)?A.empty():new Element("div")).set("html",J).firstChild;},replaces:function(A){A=$(A,true);A.parentNode.replaceChild(this.toElement(),A); return this;},inject:function(A){$(A,true).appendChild(this.toElement());return this;},remote:function(){return Swiff.remote.apply(Swiff,[this.toElement()].extend(arguments)); }});Swiff.CallBacks={};Swiff.remote=function(obj,fn){var rs=obj.CallFunction(''+__flash__argumentsToXML(arguments,2)+""); return eval(rs);};var Fx=new Class({Implements:[Chain,Events,Options],options:{fps:50,unit:false,duration:500,link:"ignore"},initialize:function(A){this.subject=this.subject||this; this.setOptions(A);this.options.duration=Fx.Durations[this.options.duration]||this.options.duration.toInt();var B=this.options.wait;if(B===false){this.options.link="cancel"; }},getTransition:function(){return function(A){return -(Math.cos(Math.PI*A)-1)/2;};},step:function(){var A=$time();if(A=(7-4*B)/11){C=A*A-Math.pow((11-6*B-11*D)/4,2); break;}}return C;},Elastic:function(B,A){return Math.pow(2,10*--B)*Math.cos(20*B*Math.PI*(A[0]||1)/3);}});["Quad","Cubic","Quart","Quint"].each(function(B,A){Fx.Transitions[B]=new Fx.Transition(function(C){return Math.pow(C,[A+2]); });});var Request=new Class({Implements:[Chain,Events,Options],options:{url:"",data:"",headers:{"X-Requested-With":"XMLHttpRequest",Accept:"text/javascript, text/html, application/xml, text/xml, */*"},async:true,format:false,method:"post",link:"ignore",isSuccess:null,emulation:true,urlEncoded:true,encoding:"utf-8",evalScripts:false,evalResponse:false},initialize:function(A){this.xhr=new Browser.Request(); this.setOptions(A);this.options.isSuccess=this.options.isSuccess||this.isSuccess;this.headers=new Hash(this.options.headers);},onStateChange:function(){if(this.xhr.readyState!=4||!this.running){return ; }this.running=false;this.status=0;$try(function(){this.status=this.xhr.status;}.bind(this));if(this.options.isSuccess.call(this,this.status)){this.response={text:this.xhr.responseText,xml:this.xhr.responseXML}; this.success(this.response.text,this.response.xml);}else{this.response={text:null,xml:null};this.failure();}this.xhr.onreadystatechange=$empty;},isSuccess:function(){return((this.status>=200)&&(this.status<300)); },processScripts:function(A){if(this.options.evalResponse||(/(ecma|java)script/).test(this.getHeader("Content-type"))){return $exec(A);}return A.stripScripts(this.options.evalScripts); },success:function(B,A){this.onSuccess(this.processScripts(B),A);},onSuccess:function(){this.fireEvent("complete",arguments).fireEvent("success",arguments).callChain(); },failure:function(){this.onFailure();},onFailure:function(){this.fireEvent("complete").fireEvent("failure",this.xhr);},setHeader:function(A,B){this.headers.set(A,B); return this;},getHeader:function(A){return $try(function(){return this.xhr.getResponseHeader(A);}.bind(this));},check:function(A){if(!this.running){return true; }switch(this.options.link){case"cancel":this.cancel();return true;case"chain":this.chain(A.bind(this,Array.slice(arguments,1)));return false;}return false; },send:function(I){if(!this.check(arguments.callee,I)){return this;}this.running=true;var G=$type(I);if(G=="string"||G=="element"){I={data:I};}var D=this.options; I=$extend({data:D.data,url:D.url,method:D.method},I);var E=I.data,B=I.url,A=I.method;switch($type(E)){case"element":E=$(E).toQueryString();break;case"object":case"hash":E=Hash.toQueryString(E); }if(this.options.format){var H="format="+this.options.format;E=(E)?H+"&"+E:H;}if(this.options.emulation&&["put","delete"].contains(A)){var F="_method="+A; E=(E)?F+"&"+E:F;A="post";}if(this.options.urlEncoded&&A=="post"){var C=(this.options.encoding)?"; charset="+this.options.encoding:"";this.headers.set("Content-type","application/x-www-form-urlencoded"+C); }if(E&&A=="get"){B=B+(B.contains("?")?"&":"?")+E;E=null;}this.xhr.open(A.toUpperCase(),B,this.options.async);this.xhr.onreadystatechange=this.onStateChange.bind(this); this.headers.each(function(K,J){try{this.xhr.setRequestHeader(J,K);}catch(L){this.fireEvent("exception",[J,K]);}},this);this.fireEvent("request");this.xhr.send(E); if(!this.options.async){this.onStateChange();}return this;},cancel:function(){if(!this.running){return this;}this.running=false;this.xhr.abort();this.xhr.onreadystatechange=$empty; this.xhr=new Browser.Request();this.fireEvent("cancel");return this;}});(function(){var A={};["get","post","put","delete","GET","POST","PUT","DELETE"].each(function(B){A[B]=function(){var C=Array.link(arguments,{url:String.type,data:$defined}); return this.send($extend(C,{method:B.toLowerCase()}));};});Request.implement(A);})();Element.Properties.send={set:function(A){var B=this.retrieve("send"); if(B){B.cancel();}return this.eliminate("send").store("send:options",$extend({data:this,link:"cancel",method:this.get("method")||"post",url:this.get("action")},A)); },get:function(A){if(A||!this.retrieve("send")){if(A||!this.retrieve("send:options")){this.set("send",A);}this.store("send",new Request(this.retrieve("send:options"))); }return this.retrieve("send");}};Element.implement({send:function(A){var B=this.get("send");B.send({data:this,url:A||B.options.url});return this;}});Request.HTML=new Class({Extends:Request,options:{update:false,evalScripts:true,filter:false},processHTML:function(C){var B=C.match(/]*>([\s\S]*?)<\/body>/i); C=(B)?B[1]:C;var A=new Element("div");return $try(function(){var D=""+C+"",G;if(Browser.Engine.trident){G=new ActiveXObject("Microsoft.XMLDOM"); G.async=false;G.loadXML(D);}else{G=new DOMParser().parseFromString(D,"text/xml");}D=G.getElementsByTagName("root")[0];for(var F=0,E=D.childNodes.length; Ftdiary-contrib-5.0.8/util/image-gallery/misc/000077500000000000000000000000001325711763500211175ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/image-gallery/misc/plugin/000077500000000000000000000000001325711763500224155ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/image-gallery/misc/plugin/recent_image.rb000066400000000000000000000243731325711763500253750ustar00rootroot00000000000000# recent_image.rb $Revision: 2.0.5 $ # # Copyright (c) 2005-2013 N.KASHIJUKU # You can redistribute it and/or modify it under GPL2. # # http://www1.whi.m-net.ne.jp/n-kashi/recent_image.htm # eval( <_" => ImageData Objects @recent_image_keys = [] # sorted keys of '@recent_image_hash' @recent_image_rkeys = [] # reverse sorted keys of '@recent_image_hash' @recent_image_use_cache = true @recent_image_show_exif = @options['image-gallery.show_exif'] @recent_image_show_exif = false if @recent_image_show_exif == nil @recent_image_cache = "#{@cache_path}/gallery/image-gallery2.dat" @recent_image_imgre = /[^_]image(?:_left|_right|_gps)?\s*\(?\s*([0-9]*)\s*\,?\s*[\"']([^'\"]*)[\"']/ # Local Functions # Search 'image' directory(s) and return a hash table. # "yyyymmdd_nn" => "File name" (or Thmbnail's File name) def get_filehash_rcimg(target) f_imghash = Hash[] f_list = Dir.glob(%Q[#{@recent_image_dir}/**/#{target}].untaint) f_list = f_list + Dir.glob(%Q[#{@recent_image_dir}/**/s#{target}].untaint) if target != "*" f_list.each do |f_name| b_name = File.basename(f_name) next unless b_name.match("^([0-9]{8}_[0-9]+)\..+") tmb_name = %Q[#{File.dirname(f_name)}/s#{b_name}] file = (f_list.include?(tmb_name) ? tmb_name : f_name) f_imghash[$1] = (@recent_imageex_yearlydir == 1 ? %Q[#{$1[0,4]}/#{File.basename(file)}] : File.basename(file)) end return f_imghash end def image_info_rcimg( f ) require 'fastimage' info = FastImage.new( f ) [info.type.to_s.sub( /jpeg/, 'jpg' ), info.size].flatten end # Make sorted keys of @recent_image_hash def keysort_rcimg sortproc = Proc.new {|a, b| a.gsub(/_(\d+)/) {"_%05d" % $1.to_i} <=> b.gsub(/_(\d+)/) {"_%05d" % $1.to_i} } @recent_image_keys = @recent_image_hash.keys.sort(&sortproc) @recent_image_rkeys = @recent_image_keys.reverse end def load_cache_rcimg db = PStore.new(@recent_image_cache) db.transaction(true) do @recent_image_hash = db["recent_image_hash"] @recent_image_keys = db["recent_image_keys"] @recent_image_rkeys= db["recent_image_rkeys"] db.abort end end def save_cache_rcimg return if @recent_image_hash.length == 0 cache_dir = File.dirname( @recent_image_cache ) Dir.mkdir(cache_dir) unless File.directory?(cache_dir) db = PStore.new(@recent_image_cache) db.transaction do db["recent_image_hash"] = @recent_image_hash db["recent_image_keys"] = @recent_image_keys db["recent_image_rkeys"] = @recent_image_rkeys db["recent_image_dir"] = @recent_image_dir db["recent_image_url"] = @recent_image_url db.commit db.abort end end def make_image_hash_rcimg f_imghash = Hash[] f_imghash = get_filehash_rcimg("*") cgi = CGI::new def cgi.referer; nil; end @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.diaries.keys.sort.reverse_each do |date| next unless m.diaries[date].visible? m.diaries[date].each_section do |section| subtitle = "" subtitle = section.subtitle.gsub(/[<{](.*?)[}>]/,'') if section.subtitle search_img_rcimg(date, section.subtitle, subtitle, f_imghash) search_img_rcimg(date, section.body, subtitle, f_imghash) end end end end end def search_img_rcimg(date, body, subtitle, f_imghash) body.to_s.scan(@recent_image_imgre).each do |num, title| # Search "image plugin" in all diaries f_name = f_imghash[%Q[#{date}_#{num}]] # and pick up params. -> image[0]=number, image[1]=title next if f_name == nil begin type, width, height = image_info_rcimg(%Q[#{@recent_image_dir}/#{f_name.delete("s")}].untaint) image = ImageData.new image.url = f_name image.file = f_name.delete("s") image.date = date image.title = title image.subtitle = subtitle image.type = type image.height = height image.width = width @recent_image_hash[%Q[#{date}_#{num}]] = image rescue end end end # Initial Function ... Make a hash table : "_" => ["Filename", "title"] def init_rcimg return if @recent_image_hash != nil and @recent_image_hash.length != 0 return unless @mode == 'day' or @mode == 'month' or @mode == 'latest' or @mode == 'preview' or @mode == 'nyear' if @recent_image_use_cache and File.exist?(@recent_image_cache) load_cache_rcimg else make_image_hash_rcimg keysort_rcimg if @recent_image_use_cache save_cache_rcimg end end end # PLUGIN body # recent_image() # def recent_image(items = 4, width = 80, link_mode = 1, name_filter = nil, title_filter = nil, reverse = false, random = false) items = items.to_i images = [] keys = [] init_rcimg return ("") if items == -1 keys = (random ? @recent_image_keys.randomize : (reverse ? @recent_image_keys : @recent_image_rkeys)) catch(:exit) { keys.each do |key| image = @recent_image_hash[key] next if name_filter != nil and image.file.match(name_filter) == nil next if title_filter != nil and image.title.match(title_filter) == nil images.push(image) if items != 0 throw :exit if items == images.length end end } result = %Q[
      \n] images.each do |image| if image.height.to_i > image.width.to_i sizestr = %Q[width="#{width*image.width.to_i/image.height.to_i}" height="#{width}"] else sizestr = %Q[width="#{width}" height="#{width*image.height.to_i/image.width.to_i}"] end case link_mode when 0 result << %Q[#{image.title}\n] when 1 result << %Q[#{image.title}\n] when 2 result << %Q[#{image.title}\n] when 3 result << %Q[#{image.title}\n] when Array result << %Q[#{image.title}\n] if link_mode[0] == 3 else end end result << "
      " end # PLUGIN body # count_image() # def count_image(name_filter = nil, title_filter = nil) count = 0 init_rcimg if name_filter == nil and title_filter == nil count = @recent_image_keys.length else @recent_image_keys.each do |key| image = @recent_image_hash[key] next if name_filter != nil and image.file.match(name_filter) == nil next if title_filter != nil and image.title.match(title_filter) == nil count = count + 1 end end count.to_s.reverse.gsub(/\d\d\d/, '\0,').reverse.sub(/^([-]{0,1}),/, '\1') end # Callback Functions # this is for view_exif(). add_body_enter_proc(Proc.new do |date| @image_date_exif = date.strftime("%Y%m%d") "" end) # Update Proc of the plugin add_update_proc do f_imghash = Hash[] if @recent_image_hash.length == 0 if @recent_image_use_cache load_cache_rcimg else make_image_hash_rcimg end end date = @date.strftime('%Y%m%d') @recent_image_hash.keys.each do |key| # Clear all data of the day in @recent_image_hash if key.include?(date) @recent_image_hash.delete(key) end end diary = @diaries[date] if diary.visible? f_imghash = get_filehash_rcimg(%Q|#{date}_*|) diary.each_section do |section| subtitle = "" subtitle = section.subtitle.gsub(/[<{](.*?)[}>]/,'') if section.subtitle search_img_rcimg(date, section.subtitle, subtitle, f_imghash) search_img_rcimg(date, section.body, subtitle, f_imghash) end end keysort_rcimg save_cache_rcimg if @recent_image_use_cache end # for SmoothGallery (SildeShow mode of 'tDiary Image Gallery') if /image-gallery\.(?:cgi|rb)$/ =~ $0 add_header_proc do < EOS end end tdiary-contrib-5.0.8/util/image-gallery/misc/plugin/view_exif.rb000066400000000000000000000033561325711763500247360ustar00rootroot00000000000000# view_exif.rb $Revision: 1.0.0 $ # # Copyright (c) 2013 N.KASHIJUKU # You can redistribute it and/or modify it under GPL2. # # http://www1.whi.m-net.ne.jp/n-kashi/recent_image.htm # # !caution! view_exif.rb needs recent_image.rb # require 'exifparser' # PLUGIN body # view_exif() ... input EXIF datas of images in your diary. # def view_exif(id = 0, exifparam ="") init_rcimg if @recent_image_hash == nil or @recent_image_hash.length == 0 begin @image_date_exif ||= @date.strftime("%Y%m%d") @exifparser = ExifParser.new(%Q[#{@image_dir}/#{@recent_image_hash[@image_date_exif+"_"+id.to_s].file}].untaint) if exifparam == "" # return a formatted string. model = @exifparser['Model'].to_s focallength = @exifparser['FocalLength'].to_s fnumber = @exifparser['FNumber'].to_s exposuretime = @exifparser['ExposureTime'].to_s isospeedratings = @exifparser['ISOSpeedRatings'].to_s exposurebiasvalue = @exifparser['ExposureBiasValue'].to_s if @exifparser.tag?('LensParameters') lensname = "("+ @exifparser['LensParameters'].to_s + ")" else lensname = "" end return %Q[

      #{model}, #{focallength}, #{fnumber}, #{exposuretime}, ISO#{isospeedratings}, #{exposurebiasvalue}EV #{lensname}

      ] else # return the requested value. return @exifparser[exifparam.untaint].to_s end rescue exp = ($!).to_s + "
      " ($!).backtrace.each do |btinfo| exp += btinfo exp += "
      " end return exp end end # Callback Functions add_body_enter_proc(Proc.new do |date| @image_date_exif = date.strftime("%Y%m%d") "" end) tdiary-contrib-5.0.8/util/image-gallery/tdiary.conf.igsample000066400000000000000000000002751325711763500241330ustar00rootroot00000000000000# # tDiary configuration file # @options['image-gallery.show_exif'] = true @options['image-gallery.column'] = 4 @options['image-gallery.line'] = 10 @options['image-gallery.width'] = "160" tdiary-contrib-5.0.8/util/image-gallery/theme/000077500000000000000000000000001325711763500212665ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/image-gallery/theme/image-gallery.css000066400000000000000000000020131325711763500245130ustar00rootroot00000000000000/* css for tDiary Image Gallery */ /* for List mode */ table.imagelist { margin: 0 auto; text-align: center; } table.imagelist p.imagetitle { margin-top: 0px; margin-bottom: 0px; } table.imagelist td { width: 33%; } table.imageview td { width: 50%; } table.imagelist p.imagedate { margin-top: 0px; } table.imageview { margin-left: auto; margin-right: auto; } table.imageview td { text-align: center; } p.exiftitle { text-align: left; } table.imageview li { text-align: left; } img.imagebody { border-style: solid; border-width: 1px; border-color: #fff; padding: 4px; margin: 0 auto; } p.infobar { text-align: center; } div.categorylink { font-size: small; text-align: right; margin-right: 0.3em; } /* for SlideShow mode */ .content { margin: 0 20px; } .content a { color: #fff; } .content p.linkage { margin-top: 2em; text-align: right; font-size: 1.7em; color: #ddd; } .content p.linkage a { color: #fff; } #myGallery { text-align: left; margin: 0 auto; } tdiary-contrib-5.0.8/util/image-gallery/views/000077500000000000000000000000001325711763500213215ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/image-gallery/views/gallery.rhtml000066400000000000000000000151251325711763500240340ustar00rootroot00000000000000<%# gallery.rhtml $Revision: 2.0.1 $ %> <%# Copyright (c) 2005-2012 N.KASHIJUKU %> <%# You can redistribute it and/or modify it under GPL2. %>
      <%%=navi_user%>

      <%= CGI::escapeHTML( @conf.html_title ) %> [Image Gallery]

      <% if @images.length == 0 %>

      該当するファイルはありません

      <%= format_links_date %> <% else %> <% if @mode == "list" or @mode == "slide" or @mode == "fslide" %> <%= format_links_date %>
      <% if @images.length != 0 %>

      <%= _(@conf.to_native(@t_page_title)) %>  Page <%=@start / @num + 1 %> [<%= @image_num %> 枚中 <%= @start + 1 %> - <%= @start + @images.length %> 枚目]  <%= get_other_mode_link %>

      <% end %>
      <% if @mode == "list" %> <% @line.times do |line|%> <% @column.times do |column| %> <% i = line * @column + column %> <% end %> <% break if @images[(line + 1) * @column] == nil %> <% end %>
      <% if @images[i] != nil %> <% if @images[i].width.to_i > @images[i].height.to_i %>

      <%= @images[i].file %>

      <% else %>

      <%= @images[i].file %>

      <% end %>

      <%= CGI::escapeHTML(@images[i].title) %>

      <%= @images[i].date.sub(/(\d{4})(\d{2})(\d{2})/, '\1-\2-\3') %>

      <% end %>
      <% elsif @mode == "slide" or @mode == "fslide" %> <%= js_start_gallery %>
      <% (@line * @column).times do |i| %>

      <%= CGI::escapeHTML(@images[i].title) %>[<%= @images[i].date.sub(/(\d{4})(\d{2})(\d{2})/, '\1-\2-\3') %>]

      <%= CGI::escapeHTML(@images[i].subtitle) %>

      <% image_file = @images[i].file.dup %> <% if @use_mid_image && @mode == "slide" %> <% if image_file[4] == ?/ %> <% image_file[4] = "/m" %> <% else %> <% image_file = "m" + image_file %> <% end %> <% end %>
      <% break if @images[i+1] == nil %> <% end %>
      <% end %>
      <% if @image_num > 0 %> <%= format_links(@image_num) %> <% end %>
      <% elsif @mode == "viewer" %> <%= format_links_viewer %>

       <%= @images[0].date.sub(/(\d{4})(\d{2})(\d{2})/, '\1-\2-\3') %>  <%= CGI::escapeHTML(@images[0].title) %>  [<%= @images[0].file %>:<%= @images[0].width %>(w)×<%= @images[0].height %>(h)]

      <% image_file = @images[0].file.dup %> <% month_filter = ((image_file[4] == ?/) ? %Q[^#{image_file[0,4]}/#{image_file[5,6]}] : %Q[^#{image_file[0,6]}]) %>
      <% end %>
      <% image_file = @images[0].file.dup %> <% if @use_mid_image %> <% if image_file[4] == ?/ %> <% image_file[4] = "/m" %> <% else %> <% image_file = "m" + image_file %> <% end %> <% end %> alt="<%= CGI::escapeHTML(@images[0].title) %>" title="<%= CGI::escapeHTML(@images[0].title) %>" class="imagebody">
      <% if @show_exif and @exifstr.length != 0 %>

      - EXIF Data -

      <%= @exifstr[0] %>

        <% i = 1 %> <% while i < @exifstr.length %> <% if @exifstr.length > 5 and i == @exifstr.length / 2 %>
        <% end %> <% if @exifstr[i][0,2] == "--" %>

      <%= @exifstr[i] %>

        <% else %>
      • <%= @exifstr[i] %>
      • <% end %> <% i = i + 1 %> <% end %>
      <% end %> <% end %> <% if @show_inputfield %>

      画像の選択: ファイル名:  日記のサブタイトル:  画像のタイトル:

      並べ替え:    表示形式:

      <% end %> tdiary-contrib-5.0.8/util/image2flickr.rb000077500000000000000000000227031325711763500203400ustar00rootroot00000000000000#!/usr/bin/env ruby # -*- coding: utf-8 -*- # = Image2Flickr # imageプラグインからflickrプラグインへのマイグレーションツール # # Author:: MATSUOKA Kohei # Copyright:: Copyright (c) MATSUOKA Kohei # License:: GPL # # USEGE: # imageプラグインからflickrプラグインへ移行するためのツールです。 # このツールの機能は、以下の2つです。 # (1) tDiaryのimageプラグインを利用して日記に載せた写真を、 # Flickrへアップロードします。 # (2) 日記データのimageプラグインの呼び出しを、 # flickrプラグインへと置き換えます。 # 古い日記データは .bak.YYYYmmddHHMMSS を付けてバックアップします。 # # == 注意 # # (1) tDiary2.3.1以降が対象です。 # 日記データがUTF-8に変換されている必要があります。 # (2) Wiki記法で記述された日記が対象です。 # # # == 移行手順 # # 1. Flickr APIキーの取得 # # flickr.comのAPIサイトにアクセスし、"Apply for a new API Key"にて # 新しいAPIキーを生成します。 # http://www.flickr.com/services/api/keys/ # # Authentication TypeはAuthentication Typeを選択してください。 # # # 2. tDiaryデータフォルダのバックアップ # # このマイグレーションツールはtDiaryの日記データを書き換えます。 # 古い日記データを残す仕様ですが、万が一に備えて # 事前にtDiaryのデータフォルダをバックアップしてください。 # # # 3. rflickrライブラリの取得 # # このマイグレーションツールはFlickrへの写真のアップロードに # rflickrライブラリを使用します。 # 以下のサイトからrflickrライブラリを取得して、インストールしてください。 # http://rubyforge.org/projects/rflickr/ # # RubyGemsが利用できる場合は、以下のコマンドでインストールできます。 # $ gem install rflickr # # # 4. マイグレーションツールの設定 # # image2flickr.rbをエディタで開き、以下の4つのパラメータを設定します。 # # # FlickrのAPIキー # @api_key = '123456789012345678901234567890' # # Flickr APIのシークレットキー # @secret = '1234567890' # # tDiaryのデータフォルダ # @data_path = '/var/tdiary' # # tDiaryのイメージフォルダ # @image_dir = '/var//www/tdiary/images' # # # 5. マイグレーションツールの実行 # # tDiaryのデータフォルダに書き込む権限を持つアカウントで、 # コマンドラインからimage2flickr.rbを実行してください。 # $ ./image2flickr # # すると、以下のメッセージが表示されます。 # ---- # Flickrへ写真をアップロードするためのトークンを取得します。 # Webブラウザで下記のURLへアクセスしたら、何かキーを押してください。 # http://www.flickr.com/services/auth/?api_sig=.... # ---- # # 指定されたURLへWebブラウザでアクセスし、トークンの発行を許可してください。 # コマンドラインへ戻り何かキーを押すと、マイグレーションが始まります。 # # なお、ツールを途中で中断し、2回目に実行するときはトークンを取得する # 必要はありません。 # # # 6. 実行結果の確認 # # ツールが終了したらtDiaryのデータフォルダを開き、 # imageプラグインの呼び出しがflickrプラグインの呼び出しへ # 置き換わっていることを確認してください。 # 古い日記データは .bak.20081024090000 などの拡張子がついて # バックアップされていますので、問題があれば元に戻してください。 # # ツールを実行すると、以下の2つのファイルが作成されます。 # (1) flickr.token # Flickrへ写真をアップロードするためのトークン。 # (2) image2flickr.yaml # tDiaryのイメージフォルダに存在するJPEGファイル (ex. 20081025_0.jpg) と # Flickrへアップロードしたphoto_idの対応付けを記録したファイル。 # # これらのファイルは、マイグレーションツールを途中で中断したときのために # 用意されています。 # マイグレーションが完了したら、少なくともflickr.tokenは削除してください。 # (トークンの不正利用を防ぐためです) # # $KCODE = 'utf8' begin require 'rubygems' gem 'rflickr' rescue end require 'flickr' require 'yaml/store' require 'tempfile' require 'fileutils' # FlickrのAPIキー @api_key = '123456789012345678901234567890' # Flickr APIのシークレットキー @secret = '1234567890' # tDiaryのデータフォルダ @data_path = '/var/tdiary' # tDiaryのイメージフォルダ @image_dir = '/var/www/tdiary/images' def main uploader = FlickrUploder.new('image2flickr.yaml', 'flickr.token', @api_key, @secret) parser = TDiaryParser.new(@data_path) i2f = Image2Flickr.new(parser, uploader, @image_dir) # tDiaryのimagesフォルダから対象日記を取得 files = Dir.glob("#{@image_dir}/*.{jp{,e}g,png,gif}").map{|file| File.basename(file).match(/^(\d{6})/) $1 }.compact.uniq # 対象日記を変換 files.each do |file| i2f.convert(file) end # cache のクリア Dir["#{@data_path}/cache/*.rb"].each{|f| FileUtils.rm_f( f )} Dir["#{@data_path}/cache/*.parser"].each{|f| FileUtils.rm_f( f )} end # Flickrへ写真をアップロードし、元ファイル名とphoto_idのペアをYAMLに記録する class FlickrUploder def initialize(yaml, token, api_key, secret) @flickr = Flickr.new(token, api_key, secret) # トークンが無ければ取得する unless @flickr.auth.token puts "Flickrへ写真をアップロードするためのトークンを取得します。" puts "Webブラウザで下記のURLへアクセスしたら、何かキーを押してください。" puts @flickr.auth.login_link # キー入力待ち gets @flickr.auth.getToken @flickr.auth.cache_token puts "トークンを取得し、#{token} へ保存しました。" puts end @db = YAML::Store.new(yaml) @db.transaction { @db['photos'] ||= {} } end # Flickrへ写真をアップロードする def upload(file, title) id = 0 @db.transaction { basename = File.basename(file) if @db['photos'][basename] # アップロード済みの場合はスキップ STDERR.puts "passed updating #{basename} (#{title}) ..." id = @db['photos'][basename] @db.abort else # 写真をアップロードする STDERR.puts "updating #{basename} (#{title}) ..." id = @flickr.photos.upload.upload_file(file, title) @db['photos'][basename] = id end } id end end class TDiaryParser include FileUtils def initialize(data_path) @data_path = data_path end # tDiaryの日記を置換する # 拡張子に ".bak.yyyymmddHHMMSS" を付けて日記データをバックアップする def each_diary(yearmonth) yearmonth.match(/(\d{4})(\d{2})/) year = $1 month = $2 file = "#{@data_path}/#{year}/#{yearmonth}.td2" # ファイルをバックアップ backup = "#{file}.bak.#{Time.now.strftime('%Y%m%d%H%M%S')}" cp(file, backup, :preserve => true) # 一時ファイルを生成 tmp = Tempfile.new('tmp') open(file) do |fin| fin.each('') do |headers| date = headers.grep(/^Date:\s*(\d{4}\d{2}\d{2})/){$1}[0] diary = fin.gets("\n.\n") diary = yield(date, diary) tmp.print headers tmp.print diary end end tmp.close cp(tmp.path, file) end end class Image2Flickr def initialize(parser, uploader, image_dir) @parser = parser @uploader = uploader @image_dir = image_dir end # imageプラグインをflickrプラグインへ置き換える def convert(yearmonth) @parser.each_diary(yearmonth) do |@date, diary| # 現在はWiki記法のみ対応 diary.gsub!(/\{\{(image[^}]+)\}\}/) {|match| begin STDERR.puts "found: #{match}" # image, image_left, image_right のいずれかに対応 replace = "{{#{eval($1)}}}" STDERR.puts "replace: #{replace}" STDERR.puts replace rescue => e # 例外が発生したら置換しない STDERR.puts "ERROR: #{e}" STDERR.puts match end } diary end end def image( index, title = nil, thumbnail = nil, size = nil, place = 'photo' ) replace("flickr", @date, index, title) end def image_center( index, title = nil, thumbnail = nil, size = nil, place = 'photo' ) replace("flickr", @date, index, title) end def image_left( index, title = nil, thumbnail = nil, size = nil, place = 'photo' ) replace("flickr_left", @date, index, title) end def image_right( index, title = nil, thumbnail = nil, size = nil, place = 'photo' ) replace("flickr_right", @date, index, title) end def replace(method, date, index, title) file = Dir.glob("#{@image_dir}/#{date}_#{index}.{jp{,e}g,png,gif}").shift # タイトルが未指定の場合はファイル名 title ||= File.basename(file) id = @uploader.upload(file, title) "#{method} #{id}" end end main tdiary-contrib-5.0.8/util/posttdiary/000077500000000000000000000000001325711763500176475ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/posttdiary/README.ja000066400000000000000000000004751325711763500211260ustar00rootroot00000000000000posttdiary.rb is a updater of diary via E-mail with images. see: http://tdiary-users.sourceforge.jp/cgi-bin/wiki.cgi?posttdiary%2Erb -- posttdiary-ex.rb is a more enhanced posttdiary.rb. see: http://ks.nwr.jp/wiki/wiki.cgi?posttdiary%2erb%b2%fe%c2%a4 (Japanese) http://ks.nwr.jp/prog/posttdiary.html (English) tdiary-contrib-5.0.8/util/posttdiary/posttdiary-ex.rb000077500000000000000000001113031325711763500230120ustar00rootroot00000000000000#!/usr/bin/env ruby # # posttdiary-ex: update tDiary via e-mail. $Revision: 1.2 $ # # Copyright (C) 2002, All right reserved by TADA Tadashi # You can redistribute it and/or modify it under GPL2. # # 2010.10.19: v.1.71: Modified by K.Sakurai (http://ks.nwr.jp) # Acknowledgements: # * Based on posttdiary.rb & tdiary.rb by TADA. # * Some codes partially imported from Enikki Plugin Ex. : # http://shimoi.s26.xrea.com/hiki/hiki.cgi?TdiaryEnikkiEx # * Thanks to taketori for image size detection method. # * Thanks to NOB for debugging. # * Thanks to tamo (http://tamo.tdiary.net) for image-POSTing codes & testing. # # language setup for tdiary.conf (for both @data_path & @tdiary_dirname) @tdencoding = 'UTF-8' # @tdencoding = 'US-ASCII' # @tdencoding = 'EUC-JP' # @tdencoding = 'Big5' #---------------------------------------------- def usage( detailed_help ) # (if "!" is at the head of the line, it is to be shown only when detailed_help == true (-h option) ) text = <<-TEXT #{File::basename __FILE__}: update tDiary via e-mail (v1.64). usage: ruby posttdiary-ex.rb [options (without -d)] ruby posttdiary-ex.rb [options (with -d)] arguments: url: update.rb's URL of your diary user: username for your tDiary system passwd: password for your tDiary system ! If the To: field is formatted as "user-passwd@example.com", ! you can omit user and passwd arguments. options: ! ============ for automatic configuration ========== --read-conffile, -a dirname: read settings from (dirname)/tdiary.conf ! Reads configuration parameters of image_ex plugin as well. ! (The default values of -i, -u, -t, -z, -o, -y, -C can be imported.) ! Specify the localtion (or fullpathname) of tDiary conf file. ! ex. -a /home/hoge/htdocs/diary/tdiary.conf ! ! ============ basic options ============== --image-path, -i dirname: directory to store the image(s) in. --image-url, -u URL: URL of the image directory. ! You must specify both -i and -u options ! (unless they are available from tdiary.conf + image_ex plugin) ! When using --remote-mode or --use-image-ex, -u is not required. --use-subject, -s: use mail subject as subtitle ! Also inserts attached image(s) between subtitle and body. --make-thumbnail, -t size: Create thumbnail with a link to the original image ! Works only when the original image is larger than the specified size ! (see --threshold-size also) ! ex. -t 80x80 --image-geometry, -g size: resize image(s). ! The original image would be overwritten. ! Does not change the image size when the original image is smaller. ! ex. -g 800x800 (change the image size to "fit in" to 800x800 pixels) --use-image-ex, -e: Recognize & auto-generate tags for image.rb (Enikki) or image_ex.rb (Enikki ex.) plugin ! Tag format: <%=image (serialno),"(alt text)"%> ! Serialno starts from 0. Will be automatically increased to match ! the real filename. ! Overrides -f option. --wiki-style, -w: output image tags in Wiki style ! Suppress adding a whitespace before each tag ! Adds "!" to subject when -s option is given ! Recognize Wiki style tags and rewrite ! Must be used with image.rb or image_ex.rb plugin. --blog-style, -B: do not specify date to append unless specified ! Suitable for use with blogkit --read-exif, -c: read "User Comment" tag from EXIF and use as ALT text ! If not specified, filename would be used as ALT text. ! Requires libexif and "exif" command. --hour-offset, -o offset: hour_offset of tDiary ! (ex. -o +4 (do not change date until 28:00)) --yearly-dir, -y: put images in yearly separated directories ! ( 2004/ , 2005/ , ...) --help, -h: show detailed help & advanced options ! ! ============ advanced options ============== ! --convert-path, -C fullpath_of_convert: location of "convert" command ! Use this option when ImageMagick's commands are not path-reachable. ! Assumes the same location for "identify" command as well. ! --exif-path, -E fullpath_of_exif: location of "exif" command ! Enables --read-exif command as well. ! Use this option when "exif" command is not path-reachable. ! --remote-mode, -R: upload images via update.rb using HTTP POST. ! Allows user to separate the mailserver and the webserver. ! Note: Thumbnails would not be posted. ! --remote-image-path,-D remote_dirname: ! Specify the image directory of the remote webserver. ! Required when using image_ex.rb with --remote-mode option. ! --remote-yearly-dir,-Y switch: ! Specify whether to put images in yearly separated directories ! at the remote webserver. ! Required when image_ex.rb with --remote-mode option. ! 0: do not separate, 1: separate ! --preserve-local-images, -P: ! Do not delete local image files. ! Effective only when --remote-mode is enabled. ! --upload-only, -U: ! Upload the attached images to server, but do not update the diary. ! Also possible by adding "_UPLONLY#" to mail body. ! --group-id, -G: specify the group name (or GID) of the image file. ! Also makes the file group writable (chmod 664). ! ex1. -G www ! ex2. -G 67 ! --class-name, -n class_name: ! Class name for each photo (default: photo) ! Invalid when --use-image-ex or --wiki-style option is enabled. ! --add-div, -v number_of_images: ! Encapsule all attached images with
      ...
      ! When specified number of (or more) images are attached. ! Set to 2 when not given. Specify 0 to disable. ! Automatically set to 0 when --wiki-style is enabled. ! ex. -v 3 (works only when 3 or more images are attached) ! --threshold-size, -z threshold_image_size: ! Make thumbnail if image size is larger. ! ex1. -z 120x140 ! ex2. -z 140 (same to 140x140) ! --image-format, -f format string: ! Specify the format string of the image tag ! These variables can be used in the format string: ! $0 : image serial number ! $1 : image url ! $2 : thumbnail image url (when -t is specified) ! $3 : class name ! $4 : ALT text (filename, or EXIF comment when -c is specified) ! ex. -f \\\"{{image \\\$0}}\\\" ! --use-original-name, -r: ! use original filename as ALT text when not specified ! --pass-filename, -p: ! Pass real filename (instead of serialno) to image_ex plugin ! (EXPERIMENTAL: Has no meanings so far) ! Effective only with -e option. ! --filter-mode, -d: print to stdout (does not call update.rb) ! --write-to-file, -b filename: writeout to file (does not call update.rb) ! --date-margin, -j date_margin: avoid writing diaries for future dates ! ex. -j 30 (default=7, 0=disabled) ! --rotate, -T LEFT or RIGHT: rotate images ! ex. -T RIGHT (rotate 90degrees clockwise) ! Also possible by adding "_ROT_LEFT#" or "_ROT_RIGHT#"to mail body. ! ! Output format: ! without -e/f, without -t: $4 ! without -e/f, with -t: $4 ! with -e: <%=image $0,'$4'%> ! with -w: {{image $0,'$4'}} (overrides -e) ! with -f: (specified format) (overrides -e, -w) ! ! Date specification format in mail body text: ! ex. when you want to append this mail to "2005 Feb 15" 's diary, ! add this line to mail body: ! ! _Date#2005-2-15 ! Examples: posttdiary-ex.rb -a /home/hoge/htdocs/diary/tdiary.conf http://yoursite.jp/~hoge/diary/update.rb (tDiary username) (passwd) posttdiary-ex.rb -w -i /home/hoge/htdocs/diary-images/ -y -t 120x120 -s -g 800x800 http://yoursite.jp/~hoge/diary/update.rb (tDiary username) (passwd) ! posttdiary-ex.rb -i /home/hoge/htdocs/diary-images/ -u http://yoursite.jp/~hoge/diary-images/ -t 120x120 -s -g 800x800 http://yoursite.jp/~hoge/diary/update.rb (tDiary username) (passwd) ! posttdiary-ex.rb -R -i /home/hoge/tmp -D /home/hoge/htdocs/diary-images -Y 1 -s -g 800x800 http://yoursite.jp/~hoge/diary/update.rb (tDiary username) (passwd) TEXT if( detailed_help ) text.gsub!( /\!/, '' ) else text.gsub!( /\![^\r\n]*[\r\n]+/, '' ) end text.delete("\t") end #--- override functions in the original tdiary.rb def base_url return '' end def TDiaryError( msg ) print msg + "\n" exit 0 end def load_cgi_conf raise TDiaryError, 'posttdiary-ex: No @data_path variable.' unless @data_path @data_path = add_delimiter( @data_path ) raise TDiaryError, 'posttdiary-ex: Do not set @data_path as same as tDiary system directory.' if @data_path == @tdiary_dirname def_vars1 = '' def_vars2 = '' variables = [:author_name, :author_mail, :index_page, :hour_offset] variables.each do |var| def_vars1 << "#{var} = nil\n" def_vars2 << "@#{var} = #{var} unless #{var} == nil\n" end begin cgi_conf = File::open( "#{@data_path}tdiary.conf" ){|f| f.read } cgi_conf.untaint unless @secure cgi_conf.force_encoding( @tdencoding ) b = binding.taint eval( cgi_conf, b, "(cgi_conf)", 1 ) eval( def_vars2, b ) rescue IOError, Errno::ENOENT end end #--- read tdiary.conf def read_tdiary_conf( dfname ) if test( ?d , dfname ) then @tdiary_dirname = dfname @tdiary_conf_file = 'tdiary.conf' elsif test( ?f , dfname ) then dfname =~ /(.*)[\/\\]([^\/\\]+)/ @tdiary_dirname = $1 @tdiary_conf_file = $2 end @tdiary_dirname = add_delimiter( @tdiary_dirname ) orgdir = Dir.pwd Dir.chdir( @tdiary_dirname ) @secure = false @options = {} # evaluate tdiary.conf (load_cgi_conf() would be called as well, via tdiary.conf) f = File::open( @tdiary_dirname + @tdiary_conf_file ){|f| f.read }.untaint.force_encoding(@tdencoding) eval( f, binding, "(tdiary.conf)", 1 ) Dir.chdir( orgdir ) true; rescue IOError, Errno::ENOENT raise 'posttdiary-ex: failed to read tdiary configuration file' end def check_local_images( date, path ) available_list = [] exist_list = [] maxnum = -1 Dir.foreach( path ) do |file| if file =~ /(\d{8,})_(\d+)\.([^\.]*)/ then if $1 == date then serial = $2.to_i maxnum = serial if serial > maxnum exist_list[serial]=true end end end num = 0 for i in 0 .. 200 if !exist_list[i] then available_list[num] = i num += 1 end end maxnum += 1 [maxnum, available_list] end def bmp_to_png( bmp ) png = bmp.sub( /\.bmp$/, '.png' ) stat = system( "#{@convertpath} #{bmp} #{png}" ) raise "posttdiary-ex: could not run convert command (#{@convertpath})" if !stat if FileTest::exist?( png ) File::delete( bmp ) png else bmp end end def check_command( cmdname ) raise 'posttdiary-ex: program bug found in check_command() (call the programmer!)' unless cmdname if @pt_exist_cmd then for priv in @pt_exist_cmd if priv == cmdname then return true end end end stat = false if ( test( ?x , cmdname ) ) then stat = true else require 'shell' sh = Shell.new searchdir = sh.system_path for dir in searchdir fullpath = add_delimiter( dir ) + cmdname if sh.executable?(fullpath) then stat = true break end end end if stat then @pt_exist_cmd = [] unless @pt_exist_cmd @pt_exist_cmd << cmdname else raise "posttdiary-ex: execution failed: #{cmdname} not found" end stat end def check_image_size( name, geo ) cmdstr = @magickpath + "identify" check_command( cmdstr ) return false if !FileTest::exist?( name ) begin imgsize = %x[#{cmdstr} '#{name}'].sub(/#{name}/, '').split[1][/\d+x\d+/] i = imgsize.split(/x/) j = geo.split(/x/) return false if !i[1] or !j[1] return false if i[0].to_i < j[0].to_i and i[1].to_i < j[1].to_i rescue return false end true end def change_image_size( org, geo ) check_command( @convertpath ) system( "#{@convertpath} -size #{geo}\\\> #{org} -geometry #{geo}\\\> #{org}" ) if FileTest::exist?( org ) org else "" end end def read_exif_comment( fullpath_imgname ) require 'nkf' v = "" check_command( @exifpath ) return "" if !FileTest::exist?( fullpath_imgname ) open( "| #{@exifpath} -t \"User Comment\" #{fullpath_imgname}", "r" ) do |f| s = f.readlines s.each do |t| t.gsub!( /.*Value:/, '' ) v = NKF::nkf( '-m0 -Xwd', t ).gsub!( /^\s+/, '' ).chomp! if $& end end v = '' if v =~ /^\(null\)$/i v end def read_exif_orientation( fullpath_imgname ) # returns orientaion value # top-left : 1 # right-top : 6 # left-bottom : 8 # bottom-right : 3 val = 1 v = '' check_command( @exifpath ) return 1 if !FileTest::exist?( fullpath_imgname ) open( "| #{@exifpath} -t \"Orientation\" #{fullpath_imgname}", "r" ) do |f| s = f.readlines s.each do |t| t.gsub!( /.*Value:/, '' ) if $& then v = t break end end end val = 6 if v =~ /right.+top/i val = 8 if v =~ /left.+bottom/i val = 3 if v =~ /bottom.+right/i val end def rotation_degree( ori ) deg = 0 deg = 90 if ori == 6 deg = -90 if ori == 8 deg = 180 if ori == 3 deg end def rotate_image( org, deg ) if FileTest::exist?( org ) then check_command( @convertpath ) system( "#{@convertpath} -rotate #{deg} #{org} #{org}" ) end if FileTest::exist?( org ) org else "" end end def make_thumbnail( idir, iname , newsize , gid ) org_full = idir + iname tb_name = "s" + iname tb_full = idir + tb_name begin check_command( @convertpath ) # only for imagemagick 6 and later!! system( "#{@convertpath} -thumbnail #{newsize}\\\> #{org_full} #{tb_full}" ) end if FileTest::exist?( tb_full ) if gid then require 'shell' sh = Shell.new sh.chown( nil , gid , tb_full ) sh.chmod( 00664 , tb_full ) end tb_name else iname end end def add_body_text( prev, sub_head , sub_body ) addtext = prev if prev.size > 0 and !(prev =~ /\n$/) then addtext += "\n" end if sub_head =~ %r[^Content-Transfer-Encoding:\s*base64]i then addtext += NKF::nkf( '-wXd -mB', sub_body ) elsif addtext += sub_body end addtext end def add_delimiter( orgpath ) if !orgpath or orgpath.size < 1 then newpath = "" else if !(orgpath =~ /[\/\\]$/) then if !(orgpath =~ /\//) and orgpath =~ /\\/ then newpath = orgpath + "\\" else newpath = orgpath + "/" end else newpath = orgpath.dup end end newpath end def make_image_body( imgdata , imgname , remotedir , now , image_boundary, protection_key ) fname = "" extension = "" image_body = "" if imgname =~ /^(.*)(\.jpg|\.jpeg|\.gif|\.png)\z/i extension = $2.downcase fname = $1 + extension else return nil end typestr = "image/jpeg" if extension =~ /jpe??g/i typestr = "image/bmp" if extension =~ /bmp/i typestr = "image/gif" if extension =~ /gif/i typestr = "image/png" if extension =~ /png/i if remotedir and remotedir.length > 0 then image_body.concat < 0 then image_body.concat < "Basic #{auth}", 'Content-Length' => image_body.length.to_s, 'Content-Type' => "multipart/form-data; boundary=#{image_boundary}", 'Referer' => refurl, } response, = http.post( cgi, image_body, image_header ) raise "posttdiary-ex: failed to upload image (#{imgname}) to remote server" if response.code.to_i < 200 or response.code.to_i > 202 end (image_body ? true : false) end def get_date_to_append( http, cgi, user, pass, now ) # call update.rb via HTTP and get the date to append str = cgi req = Net::HTTP::Get.new( str ) req.basic_auth user, pass response, = http.request(req) body = response.body year = now.strftime( "%Y" ) month = now.strftime( "%m" ) day = now.strftime( "%d" ) bodytmp = body.split(/$/); bodytmp.each do |oneline| if oneline =~ /\]*)\>/ then if $1 =~ /value=\"(\d\d\d\d)"/ then year = $1 end end if oneline =~ /\]*)\>/ then if $1 =~ /value=\"(\d+)\"/ then month = $1 end end if oneline =~ /\]*)\>/ then if $1 =~ /value=\"(\d+)\"/ then day = $1 end end end Time::local( year, month, day ) end def parse_mail( head, body , image_dir ) imglist = [] orglist = [] textbody = "" imgnum = -1 imgdir = add_delimiter( image_dir ) if head =~ /Content-Type:\s*Multipart\/Mixed.*boundary=\"*([^\"\r\n]*)\"*/im or head =~ /Content-Type:\s*Multipart\/Related.*boundary=\"*([^\"\r\n]*)\"*/im then bound = "--" + $1 body_sub = body.split( Regexp.compile( Regexp.escape( bound ) ) ) body_sub.each do |b| sub_head, sub_body = b.split( /(?:\r\n){2}|\r\r|\n\n/, 2 ) sub_body = "" unless sub_body next unless sub_head =~ /Content-Type/i if sub_head =~ %r[^Content-Type:\s*text/plain]i then textbody = add_body_text( textbody , sub_head, sub_body ) elsif sub_head =~ %r[^Content-Type:\s*(image\/|application\/octet-stream).*name=\"*(.*)(\.[^\"\r\n]*)\"*]im imgnum += 1 orgname = $2 orgname = "" if !orgname image_ext = $3.downcase image_name = "_tmp" + Process.pid.to_s + "_" + imgnum.to_s + image_ext File::umask( 022 ) open( imgdir + image_name, "wb" ) do |s| begin s.print Base64::decode64( sub_body.strip ) rescue NameError s.print decode64( sub_body.strip ) end end if /\.bmp$/i =~ image_name then bmp_to_png( imgdir + image_name ) image_name.sub!( /\.bmp$/, '.png' ) end imglist[imgnum] = imgdir + image_name orglist[imgnum] = orgname end end elsif head =~ /^Content-Type:\s*text\/plain/i textbody = add_body_text( textbody , head, body ) else raise "posttdiary-ex: can not read this mail (illegal format)" end addr = nil if /^To:(.*)$/ =~ head then to = $1.strip if /.*?\s*<(.*)>/ =~ to then addr = $1 elsif /(.*?)\s*\(.*\)/ =~ to addr = $1 else addr = to end end subject = '' nextline = false headlines = head.split( /[\r\n]+/ ) for n in 0 .. headlines.size-1 if nextline then if /^[ \t]/ =~ headlines[n] then s = headlines[n].sub( /^[ \t]/, '' ) subject += NKF::nkf( '-wXd', s ) else break end end if /^Subject:(.*)$/ =~ headlines[n] then s = $1.sub( /^\s+/, '' ) subject = NKF::nkf( '-wXd', s ) nextline = true end end [addr, subject, imglist, orglist, textbody] end begin raise usage(false) if ARGV.length < 1 require 'getoptlong' parser = GetoptLong::new conf_df_name = nil image_dir = nil image_url = nil use_subject = false thumbnail_size = nil image_geometry = nil use_image_ex = false hour_offset = nil @hour_offset = nil yearly_dir = false thumbnail_name = Hash.new("") exif_comment = Hash.new("") exif_orientation = Hash.new(1) image_orgname = Hash.new("") remote_mode = false remote_image_dir = nil remote_yearly_dir = false preserve_local_images = false upload_only = false class_name = 'photo' group_id = nil add_div_imgnum = 2 add_div_imgnum_specified = nil threshold_size = nil pass_filename = false filter_mode = false writeout_filename = nil read_exif = false image_format = ' $4' image_format_with_thumbnail = ' $4' image_format_specified = nil wiki_style = false blog_style = false use_original_name = false date_margin = 7 convertpath_specified = nil @convertpath = "convert" @magickpath = "" exifpath_specified = nil @exifpath = "exif" rotation_degree_specified = nil parser.set_options( ['--read-conffile', '-a', GetoptLong::REQUIRED_ARGUMENT], ['--image-path', '-i', GetoptLong::REQUIRED_ARGUMENT], ['--image-url', '-u', GetoptLong::REQUIRED_ARGUMENT], ['--use-subject', '-s', GetoptLong::NO_ARGUMENT], ['--make-thumbnail', '-t', GetoptLong::REQUIRED_ARGUMENT], ['--image-geometry', '-g', GetoptLong::REQUIRED_ARGUMENT], ['--use-image-ex', '-e', GetoptLong::NO_ARGUMENT], ['--hour-offset', '-o', GetoptLong::REQUIRED_ARGUMENT], ['--yearly-dir', '-y', GetoptLong::NO_ARGUMENT], ['--help', '-h', GetoptLong::NO_ARGUMENT], ['--convert-path', '-C', GetoptLong::REQUIRED_ARGUMENT], ['--exif-path', '-E', GetoptLong::REQUIRED_ARGUMENT], ['--remote-mode', '-R', GetoptLong::NO_ARGUMENT], ['--remote-image-path', '-D', GetoptLong::REQUIRED_ARGUMENT], ['--remote-yearly-dir', '-Y', GetoptLong::REQUIRED_ARGUMENT], ['--preserve-local-images', '-P', GetoptLong::NO_ARGUMENT], ['--upload-only', '-U', GetoptLong::NO_ARGUMENT], ['--group-id', '-G', GetoptLong::REQUIRED_ARGUMENT], ['--class-name', '-n', GetoptLong::REQUIRED_ARGUMENT], ['--add-div', '-v', GetoptLong::REQUIRED_ARGUMENT], ['--threshold-size', '-z', GetoptLong::REQUIRED_ARGUMENT], ['--image-format', '-f', GetoptLong::REQUIRED_ARGUMENT], ['--use-original-name', '-r', GetoptLong::NO_ARGUMENT], ['--wiki-style', '-w', GetoptLong::NO_ARGUMENT], ['--blog-style', '-B', GetoptLong::NO_ARGUMENT], ['--read-exif', '-c', GetoptLong::NO_ARGUMENT], ['--margin-time', '-m', GetoptLong::REQUIRED_ARGUMENT], ['--pass-filename', '-p', GetoptLong::NO_ARGUMENT], ['--filter-mode', '-d', GetoptLong::NO_ARGUMENT], ['--write-to-file', '-b', GetoptLong::REQUIRED_ARGUMENT], ['--date-margin', '-j', GetoptLong::REQUIRED_ARGUMENT], ['--rotate', '-T', GetoptLong::REQUIRED_ARGUMENT] ) begin parser.each do |opt, arg| case opt when '--read-conffile' conf_df_name = arg.dup when '--image-path' image_dir = arg.dup when '--image-url' image_url = arg.dup when '--use-subject' use_subject = true when '--make-thumbnail' thumbnail_size = arg.dup when '--image-geometry' image_geometry = arg.dup when '--use-image-ex' use_image_ex = true when '--hour-offset' hour_offset = arg.to_i when '--yearly-dir' yearly_dir = true when '--help' print usage(true) exit 0 when '--convert-path' convertpath_specified = arg.dup when '--exif-path' exifpath_specified = arg.dup read_exif = true when '--remote-mode' remote_mode = true when '--remote-image-path' remote_image_dir = add_delimiter(arg.dup) when '--remote-yearly-dir' remote_yearly_dir = (arg.dup =~ /[1yt]/i) when '--preserve-local-images' preserve_local_images = true when '--upload-only' upload_only = true filter_mode = true when '--group-id' if arg =~ /\D/ then require 'etc' group_id = Etc.getgrnam( arg.dup )['gid'] else group_id = arg.to_i end group_id = nil if group_id <= 0 or group_id > 65535 when '--add-div' add_div_imgnum_specified = arg.to_i when '--threshold-size' threshold_size = arg.dup when '--image-format' image_format_specified = arg.dup when '--use-original-name' use_original_name = true when '--wiki-style' wiki_style = true use_image_ex = true when '--blog-style' blog_style = true when '--read-exif' read_exif = true when '--pass-filename' pass_filename = true when '--filter-mode' filter_mode = true when '--write-to-file' filter_mode = true writeout_filename = arg.dup when '--date-margin' date_margin = arg.to_i when '--rotate' rotation_degree_specified = 0 rotation_degree_specified = 90 if arg =~ /right/i rotation_degree_specified = -90 if arg =~ /left/i end end rescue raise usage(false) end if conf_df_name then if read_tdiary_conf( conf_df_name ) then image_dir = @options['image.dir'] if @options['image.dir'] and !image_dir image_url = @options['image.url'] if @options['image.url'] and !image_url yearly_dir = true if @options['image_ex.yearlydir'] and @options['image_ex.yearlydir'] == 1 thumbnail_size = @options['image_ex.convertedwidth'].to_s + "x" + @options['image_ex.convertedheight'].to_s if @options['image_ex.convertedwidth'] and @options['image_ex.convertedheight'] and thumbnail_size == nil threshold_size = @options['image_ex.thresholdsize'].to_s if @options['image_ex.thresholdsize'] and !threshold_size @convertpath= @options['image_ex.convertpath'] if @options['image_ex.convertpath'] and !convertpath_specified @exifpath = @options['image_ex.exifpath'] if @options['image_ex.exifpath'] and !exifpath_specified else conf_df_name = '' end end image_url = "" if use_image_ex and !image_url raise 'posttdiary-ex: image-path (-i) or image-url (-u) missing...' if (!image_url and image_dir) or (!image_dir and image_url) if image_dir then image_dir = add_delimiter( image_dir ) end if image_url then image_url += '/' unless %r[/$] =~ image_url end if thumbnail_size then thumbnail_size.gsub!(/[\>\\\s]/, '') thumbnail_size = thumbnail_size + 'x' + thumbnail_size if !(thumbnail_size =~ /x/ ) raise usage if !(thumbnail_size =~ /^\d+x\d+/) end threshold_size = thumbnail_size if !threshold_size if threshold_size and threshold_size.size > 0 then threshold_size.gsub!(/[\>\\\s]/, '') threshold_size = threshold_size + 'x' + threshold_size if !(threshold_size =~ /x/ ) raise usage if !(threshold_size =~ /^\d+x\d+/) end if image_geometry then image_geometry.gsub!(/[\>\\\s]/, '') image_geometry = image_geometry + 'x' + image_geometry if !(image_geometry =~ /x/ ) raise usage if !(image_geometry =~ /^\d+x\d+/) end hour_offset = @hour_offset if !hour_offset hour_offset = 0 if !hour_offset if image_format_specified then image_format = image_format_specified image_format_with_thumbnail = image_format else if use_image_ex then image_format = '<%=image $0,\'$4\'%>' image_format_with_thumbnail = image_format end if wiki_style then image_format = '{{image $0,\'$4\'}}' image_format_with_thumbnail = image_format end end if wiki_style then add_div_imgnum = 0 else add_div_imgnum = add_div_imgnum_specified if add_div_imgnum_specified end @convertpath = convertpath_specified if convertpath_specified @convertpath = add_delimiter( @convertpath ) + "convert" if test( ?d , @convertpath ) @magickpath = $1 if @convertpath =~ /(.*[\/\\])[^\/\\]+$/ @exifpath = exifpath_specified if exifpath_specified @exifpath = add_delimiter( @exifpath ) + "exif" if test( ?d , @exifpath ) if filter_mode == false then url = ARGV.shift.dup if %r|http://([^:/]*):?(\d*)(/.*)| =~ url then host = $1 port = $2.to_i cgi = $3 raise 'posttdiary-ex: invalid url for update.rb.' if not host or not cgi port = 80 if port == 0 else raise 'posttdiary-ex: invalid url for update.rb.' end user = ARGV.shift.dup pass = ARGV.shift.dup end require 'base64' require 'nkf' require 'net/http' require 'shell' Net::HTTP.version_1_2 mail = NKF::nkf( '-m0 -Xwd', ARGF.read ) raise "posttdiary-ex: no mail text." if not mail or mail.length == 0 head, body = mail.split( /(?:\r\n){2}|\r\r|\n\n/, 2 ) body = "" unless body addr, subject, tmpimglist, orglist, @body = parse_mail( head, body, image_dir ) if /([^-]+)-(.*)@/ =~ addr then user = $1 unless user pass = $2 unless pass end raise "posttdiary-ex: please specify the username for your tdiary system." unless user or filter_mode if tmpimglist.length > 0 and ( !image_dir or !image_url ) then raise "posttdiary-ex: please specify image-path (-i) and/or image-url (-u)" end now = Time::now + hour_offset * 3600 tmp = Time::now + hour_offset * 3600 if @body.gsub!( /^\_date\#([\d\-\/\.]+)[^\r\n]*[\r\n]+/i , '' ) then t = $1 if /(\d\d\d\d)[^\d]*(\d\d)[^\d]*(\d\d)/ =~ t then tmp = Time::local( $1.to_i, $2.to_i, $3.to_i ); end if /(\d\d\d\d)[^\d]+(\d+)[^\d]+(\d+)/ =~ t then tmp = Time::local( $1.to_i, $2.to_i, $3.to_i ); end else if blog_style and !filter_mode then Net::HTTP.start( host, port ) do |http| tmp = get_date_to_append( http, cgi, user, pass, now ) end end end if @body.gsub!( /^\_up[ld]+only\#[ \t]*[\r\n]+/i , '' ) then upload_only = true end if @body.gsub!( /^\_rot[ate]*\_right\#[ \t]*[\r\n]+/i , '' ) then rotation_degree_specified = 90 end if @body.gsub!( /^\_rot[ate]*\_left\#[ \t]*[\r\n]+/i , '' ) then rotation_degree_specified = -90 end if @body.gsub!( /^\_rot[ate]*\_none\#[ \t]*[\r\n]+/i , '' ) then rotation_degree_specified = 0 end if date_margin != 0 and (tmp - now).abs >= date_margin * 24 * 3600 then # raise "posttdiary-ex: specified date is too far from today" # # use current date (now) instead of specified date(tmp).. else now = tmp end topic_year = now.strftime( "%Y" ) topic_month = now.strftime( "%m" ) topic_date = now.strftime( "%d" ) if image_dir then image_dir = add_delimiter( image_dir + now.strftime( "%Y" ) ) if yearly_dir Dir.mkdir( image_dir ) if !test( ?d , image_dir ) if remote_mode then image_url += topic_year + "/" if remote_yearly_dir else image_url += topic_year + "/" if yearly_dir end end nextnum = -1 av_list = [] if remote_mode then if !remote_image_dir or remote_image_dir.length < 1 then # needed when using image_ex.rb, but not when using image.rb... # raise 'posttdiary-ex: please specify --remote-image-path' remote_image_dir = "" else if remote_yearly_dir then remote_image_dir = add_delimiter( remote_image_dir + topic_year ) end end Net::HTTP.start( host, port ) do |http| nextnum,av_list = check_remote_images( http, cgi, user, pass, now) end else nextnum,av_list = check_local_images( now.strftime( "%Y%m%d" ), image_dir ) end @image_name = nil sh = Shell.new for i in 0 .. (tmpimglist.length-1) tmpimgname = tmpimglist[i] raise "posttdiary-ex: program bug found: no extension in tmpimgname" if !(tmpimgname =~ /(\.[^\.]*?)$/) image_ext = $1.downcase image_name = now.strftime( "%Y%m%d" ) + "_" + nextnum.to_s + image_ext nextnum += 1 sh.rename( tmpimgname , image_dir + image_name ) exif_comment[image_name] = (read_exif ? read_exif_comment(image_dir + image_name) : "" ) exif_orientation[image_name] = (read_exif ? read_exif_orientation(image_dir + image_name) : "" ) image_orgname[image_name] = orglist[i] change_image_size( image_dir + image_name , image_geometry ) if image_geometry if rotation_degree_specified then if rotation_degree_specified != 0 then rotate_image( image_dir + image_name , rotation_degree_specified ) end elsif read_exif and exif_orientation[image_name] != 1 then rotate_image( image_dir + image_name , rotation_degree( exif_orientation[image_name] ) ) end if group_id then sh.chown( nil , group_id , image_dir + image_name ) sh.chmod( 00664 , image_dir + image_name ) end thumbnail_name[image_name] = "" thumbnail_name[image_name] = make_thumbnail( image_dir, image_name , thumbnail_size , group_id ) if thumbnail_size and check_image_size( image_dir + image_name, threshold_size) @image_name = [] unless @image_name @image_name << image_name end if @image_name then img_src = "" marker = "_posttdiary_ex_temporary_marker_" img_in_div = 0 for j in 0 .. @image_name.size-1 i = @image_name[j] serial = i.sub( /^\d+_(\d+)\.[^\.]*?$/, '\1' ) serial = i if use_image_ex and pass_filename cm = "" cm = exif_comment[i] if read_exif and exif_comment[i] and exif_comment[i].size > 0 cm = image_orgname[i] if use_original_name and (!cm or cm.size == 0) cm = i.gsub(/\.[^\.]*?$/, '') if !cm or cm.size == 0 if use_image_ex then # modify <%=image (num),'comment'%> or <%=image (num)%> tags if @body =~ /\<\%\=image[^\s]*\s+#{j}\s*\,\s*[\"\'](.*)[\"\']\s*\%*\>/i then alttext = $1; alttext = cm if alttext.length < 1 @body.gsub!( /\<\%\=(image[^\s]*)\s+#{j}\s*\,\s*[\"\'].*[\"\']\s*\%*\>/i, '<%=\1 '+marker+serial.to_s+',\''+alttext+'\'%>' ) next elsif @body =~ /\<\%\=image[^\s]*\s+#{j}\s*\%*\>/i then alttext = cm @body.gsub!( /\<\%\=(image[^\s]*)\s+#{j}\s*\%*\>/i, '<%=\1 '+marker+serial.to_s+',\''+alttext+'\'%>' ) next end end if wiki_style then # modify {{image (num),"comment"}} or {{image (num)}} tags (also recognizes image_left, image_right) if @body =~ /\{\{image[^\s]*\s+#{j}\s*\,\s*[\"\'](.*)[\"\']\s*\}\}/i then alttext = $1; alttext = cm if alttext.length < 1 @body.gsub!( /\{\{(image[^\s]*)\s+#{j}\s*\,\s*[\"\'].*[\"\']\s*\}\}/i, '{{\1 '+marker+serial.to_s+',\''+alttext+'\'}}' ) next elsif @body =~ /\{\{image[^\s]*\s+#{j}\s*\}\}/i then alttext = cm @body.gsub!( /\{\{(image[^\s]*)\s+#{j}\s*\}\}/i, '{{\1 '+marker+serial.to_s+',\''+alttext+'\'}}' ) next end end img_in_div+=1 if thumbnail_size and thumbnail_name[i].size > 0 then t = thumbnail_name[i] img_src += image_format_with_thumbnail.gsub( /\$0/, serial ).gsub( /\$1/, image_url + i ).gsub( /\$2/, image_url + t ).gsub( /\$3/, class_name ).gsub( /\$4/, cm ) else img_src += image_format.gsub( /\$0/, serial ).gsub( /\$1/, image_url + i ).gsub( /\$3/, class_name ).gsub( /\$4/, cm ) end end @body.gsub!( /#{marker}/ , '' ) if img_src =~ /^\s+$/ then img_src = '' else if add_div_imgnum <= img_in_div and add_div_imgnum > 0 then img_src = "
      " + img_src + "
      " end end img_src.sub!( /^/ , ' ' ) if ! wiki_style if use_subject then img_src = img_src + "\n" if !(img_src =~ /^\s*$/) @body = "#{img_src}#{@body.sub( /\n+\z/, '' )}" else @body = "#{@body.sub( /\n+\z/, '' )}\n#{img_src}" end end if use_subject then title = '' @body = "#{subject}\n#{@body}" @body = "!" + @body if wiki_style else title = subject end if upload_only then exit 0 end require 'cgi' require 'nkf' if filter_mode then data = title + "\n"; data << @body + "\n"; if writeout_filename then open( writeout_filename, "wb" ) do |s| s.print data end else print data end else data = "title=#{CGI::escape title}" data << "&body=#{CGI::escape @body}" data << "&append=true" data << "&year=#{topic_year}" data << "&month=#{topic_month}" data << "&day=#{topic_date}" auth = ["#{user}:#{pass}"].pack( 'm' ).strip Net::HTTP.start( host, port ) do |http| protection_key = nil res = http.get( cgi, 'Authorization' => "Basic #{auth}", 'Referer' => url ) if %r|| =~ res.body then protection_key = $1 data << "&csrf_protection_key=#{CGI::escape( CGI::unescapeHTML( protection_key ) )}" end if remote_mode and @image_name then for i in 0 .. (@image_name.length - 1) imagename = @image_name[i] thumbnailname = thumbnail_name[imagename] post_image( http, cgi, user, pass, image_dir, imagename, remote_image_dir, now, protection_key, url ) File.delete( image_dir + imagename ) if !preserve_local_images File.delete( image_dir + thumbnailname ) if !preserve_local_images and test( ?f , image_dir + thumbnailname ) end end response = http.post( cgi, data, 'Authorization' => "Basic #{auth}", 'Referer' => url ) end end rescue $stderr.puts $! exit 1 end tdiary-contrib-5.0.8/util/posttdiary/posttdiary.rb000077500000000000000000000142411325711763500224030ustar00rootroot00000000000000#!/usr/bin/env ruby $KCODE= 'u' # # posttdiary: update tDiary via e-mail. $Revision: 1.5 $ # # Copyright (C) 2002, All right reserved by TADA Tadashi # You can redistribute it and/or modify it under GPL2. # def usage <<-TEXT.gsub( /^\t{2}/, '' ) #{File::basename __FILE__}: update tDiary via e-mail. usage: ruby #{File::basename __FILE__} [options] [user] [passwd] arguments: url: update.rb's URL of your diary. user: user ID of your diary updating. passwd: password of your diary updating. If To: field of the mail likes "user-passwd@example.com", you can omit user and passwd arguments. options: --image-path, -i: directory of image saving into. --image-url, -u: URL of image. You have to specify both options when using images. --image-format, -f: format of image tag specified image serial number as '$0' and image url as '$1'. default format is ' '. --use-subject, -s: use mail subject to subtitle. and insert image between subtitle and body. TEXT end def image_list( date, path ) image_path = [] Dir.foreach( path ) do |file| if file =~ /(\d{8,})_(\d+)\./ and $1 == date then image_path[$2.to_i] = file end end image_path end def bmp_to_png( bmp ) png = bmp.sub( /\.bmp$/, '.png' ) begin require 'magick' img = Magick::Image::new( bmp ) img.write( 'magick' => 'png', 'filename' => png ) rescue LoadError system( "convert #{bmp} #{png}" ) end if FileTest::exist?( png ) File::delete( bmp ) png else bmp end end begin raise usage if ARGV.length < 1 require 'getoptlong' parser = GetoptLong::new image_dir = nil image_url = nil image_format = ' ' use_subject = false parser.set_options( ['--image-path', '-i', GetoptLong::REQUIRED_ARGUMENT], ['--image-url', '-u', GetoptLong::REQUIRED_ARGUMENT], ['--image-format', '-f', GetoptLong::REQUIRED_ARGUMENT], ['--use-subject', '-s', GetoptLong::NO_ARGUMENT] ) begin parser.each do |opt, arg| case opt when '--image-path' image_dir = arg when '--image-url' image_url = arg when '--image-format' image_format = arg when '--use-subject' use_subject = true end end rescue raise usage end raise usage if (image_dir and not image_url) or (not image_dir and image_url) image_dir = image_dir.sub( %r[/*$], '/' ) if image_dir image_url = image_url.sub( %r[/*$], '/' ) if image_url url = ARGV.shift if %r|http://([^:/]+)(?::(\d+))?(/.*)| =~ url then host = $1 port = ($2 || 80).to_i cgi = $3 else raise 'bad url.' end user = ARGV.shift pass = ARGV.shift require 'base64' require 'nkf' image_name = nil mail = NKF::nkf( '-m0 -Xwd', ARGF.read ) raise "#{File::basename __FILE__}: no mail text." if not mail or mail.length == 0 head, body = mail.split( /(?:\r?\n){2}/, 2 ) if head =~ %r|Content-Type:\s*Multipart/Mixed.*boundary="?(.*?)"?[\r\n]|im then if not image_dir or not image_url then raise "no --image-path and --image-url options" end bound = "--" + $1 body_sub = body.split( Regexp.compile( Regexp.escape( bound ) ) ) body_sub.each do |b| sub_head, sub_body = b.split( /(?:\r?\n){2}/, 2 ) next unless sub_head =~ /Content-Type:/i if sub_head =~ %r[^Content-Type:\s*text/plain]i then @body = sub_body elsif sub_head =~ %r[ ^Content-Type:\s* (?:image/|application/octet-stream).+ name="?.+(\.\w{3})"? (?# 1: extension) ]imx image_ext = $1.downcase now = Time::now list = image_list( now.strftime( "%Y%m%d" ), image_dir ) image_name = now.strftime( "%Y%m%d" ) + "_" + list.length.to_s + image_ext File::umask( 022 ) open( image_dir + image_name, "wb" ) do |s| begin s.print Base64::decode64( sub_body.strip ) rescue NameError s.print decode64( sub_body.strip ) end end if /\.bmp$/i =~ image_name then bmp_to_png( image_dir + image_name ) image_name.sub!( /\.bmp$/i, '.png' ) end @image_name ||= [] @image_name << image_name end end elsif head =~ /^Content-Type:\s*text\/plain/i if head =~ /^Content-Transfer-Encoding:\squoted-printable/ @body = body.unpack("M").map {|str| NKF::nkf("-wJd", str) } else @body = body end else raise "cannot read this mail" end if @image_name then img_src = "" @image_name.each do |i| serial = i.sub( /^\d+_(\d+)\..*$/n, '\1' ) img_src += image_format.gsub( /\$0/, serial ).gsub( /\$1/, image_url + i ) end if use_subject then @body = "#{img_src}\n#{@body}".sub( /(?:\r?\n|\r)+\z/, "\n" ) else @body = "#{@body}".sub( /(?:\r?\n|\r)+\z/, "\n" ) << img_src end end addr = nil if /^To:(.*)$/ =~ head then addr = case to = $1.strip when /.*?\s*<(.+)>/, /(.+?)\s*\(.*\)/ $1 else to end end if /([^-]+)-(.*)@/ =~ addr then user ||= $1 pass ||= $2 end raise "no user." unless user raise "no passwd." unless pass subject = '' nextline = false headlines = head.split( /(?:\r?\n|\r)+/ ) for n in 0 .. headlines.size-1 if nextline then if /^[ \t]/ =~ headlines[n] then s = headlines[n].sub( /^[ \t]/, '' ) subject += NKF::nkf( '-wXd', s ) else break end end if /^Subject:\s*(.+)$/i =~ headlines[n] then subject = NKF::nkf( '-wXd', $1 ) nextline = true end end subject.strip! if use_subject then title = '' @body = "#{subject}\n#{@body}" else title = subject end require 'cgi' require 'nkf' data = "title=#{CGI::escape title}" data << "&body=#{CGI::escape @body}" data << "&append=true" require 'net/http' Net::HTTP.start( host, port ) do |http| auth = ["#{user}:#{pass}"].pack( 'm' ).strip res, = http.get( cgi, { 'Authorization' => "Basic #{auth}", 'Referer' => url }) if %r|| =~ res.body then data << "&csrf_protection_key=#{CGI::escape( CGI::unescapeHTML( $1 ) )}" end res, = http.post( cgi, data, { 'Authorization' => "Basic #{auth}", 'Referer' => url }) end rescue $stderr.puts $! $stderr.puts $@.join( "\n" ) File::delete( image_dir + image_name ) if image_dir and image_name and FileTest::exist?( image_dir + image_name ) exit 1 end tdiary-contrib-5.0.8/util/rast-search/000077500000000000000000000000001325711763500176615ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/rast-search/ChangeLog000066400000000000000000000035121325711763500214340ustar00rootroot000000000000002007-01-08 Kazuhiko * rast-register.rb, rast-search.rb: revise for UTF8. 2005-12-10 Kazuhiko * rast-register.rb: set 'diaries' for the 'my-ex' plugin. * rast-register.rb: revise attributes of the 'date' property. rebuilding indices is necessary. * rast-search.rb: revise for mod_ruby. 2005-12-06 Kazuhiko * rast.rhtml: remove a dummy link. 2005-12-05 Kazuhiko * rast-register.rb: revise attributes of the 'date' property. remove indices before rebuilding. 2005-12-04 Kazuhiko * rast-register.rb: support tDiary-2.0.x. * en/rast-register.rb, ja/rast-register.rb: add resources. 2005-11-24 Kazuhiko * rast-register.rb: fix a bug in command-line mode (reported by YAA). set 'cache_path' for the 'tlink' plugin (reported by YAA). * rast-register.rb: support rebuilding index by conf mode. abolish 'CGI' mode. 2005-11-23 Kazuhiko * rast-register.rb: use 'require' instead of 'autoload'. 2005-11-21 Kazuhiko * rast-register.rb: add a plugin file. * rast-search.rb, rast.rxml: support opensearch rss. * rast.rhtml: revise for more valid HTML output. 2005-05-11 Kazuhiko * rast.rhtml, i.rast.rhtml: use @num instead of 10. 2005-05-11 TADA Tadashi * rast.rhtml, i.rast.rhtml: set title to h2 element, and copy format_links plugin on top of results. 2005-05-10 TADA Tadashi * README.ja: fix typo. 2005-04-16 Kazuhiko * rast.rhtml: convert the encoding of @query. 2005-04-15 Kazuhiko * rast-search.rb: never use Rast::LocalDB. fix a bug in running from a shell. 2005-04-14 Kazuhiko * initial release of rast-search. tdiary-contrib-5.0.8/util/rast-search/README.ja000066400000000000000000000072261325711763500211410ustar00rootroot00000000000000rast-search README =================== Rast を用いた tDiary 検索環境です。 特徴 ---------- 日記の更新と連動して自動的にインデックスを更新するので、いつでも最新の 情報で検索することができます。日記を HTML 化した後に必要な部分だけを取 り出してインデックスを作成するので、ヘッダやフッタなどによる検索ノイズ がなく、また、プラグインの出力が検索対象になるという特徴があります。 必要なもの ---------- * tDiary 1.5 以降 * Ruby 1.8.2 以降 * Rast 0.3.1 以降 セットアップ ------------ 1. rast-register.rb を tDiary の プラグインディレクトリにコピーします。 2. rast-search.rb を tDiary の index.rb があるディレクトリにコピーしま す。必要なら index.rb と同じようにシンボリックリンクを張ったり名前を 変えたりしてください。 3. CGI として実行可能にします。 $ chmod a+x rast-search.rb 4. 必要なら #! のパスを変更します。 5. rast.rhtml と rast.rxml と i.rast.rhtml を tDiary の skel/ ディレク トリにコピーします。 6. rast-register.rb プラグインを有効にします。(tDiary の plugin/ ディレ クトリにコピーするか、プラグイン選択のディレクトリにコピーしてブラウ ザから有効に設定します。言語リソースファイルの en/rast-register.rb と ja/rast-register.rb も、プラグインディレクトリの en/ 以下および ja/ 以下にコピーしてください。) 7. (オプション) tdiary.conf で以下のように encoding の設定をできます。 Rast の encoding module の名前で設定してください。デフォルトは 'utf8' です。encoding の設定を変更する場合は、Rast のインデックス があるディレクトリ (cache ディレクトリの下の /rast) を消して、再度イ ンデックスを作りなおしてください。 @options['rast.index'] = 'utf8' 8. 既存の日記コンテンツに対して検索インデックスを作成します。tDiary の 設定画面から「Rast検索」を選び、「Rast検索のインデックスを再構築する 場合は、チェックボックスをチェックしてOKを押してください」というメッ セージに従ってチェックしてOKを押すと、 インデックスの作成は、tDiary の CGI の実行権限で以下のように実行する ことでも可能です。 ruby rast-register.rb [-p tdiary.rbのあるディレクトリ] [-c tdiary.confのあるディレクトリ] 9. 自分の tDiary の好きな場所 (例えばヘッダ) に以下のようなフォームを加 えてください。 search-form.rb プラグインを有効にしている場合は、以下のように書くこ ともできます。 <%= search_form('rast-search.rb', 'query') %> 以上です。 検索のしかた ------------ rast-search の検索対象は、日記本文、ツッコミ、TrackBack です。 検索方法については、 http://projects.netlab.jp/rast/query.html.ja をご覧くだ さい。 連絡先 ------ かずひこ http://www.fdiary.net/ バグ報告は以下のどこかにお願いします。 * tdiary-devel ML * 直接メール tdiary-contrib-5.0.8/util/rast-search/en/000077500000000000000000000000001325711763500202635ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/rast-search/en/rast-register.rb000066400000000000000000000003061325711763500234020ustar00rootroot00000000000000@rast_register_conf_label = 'Rast Search' @rast_register_conf_header = 'Rebuild Rast search index' @rast_register_conf_description = 'To rebuild Rast search index, check the box and submit \'OK\'.' tdiary-contrib-5.0.8/util/rast-search/i.rast.rhtml000066400000000000000000000017171325711763500221370ustar00rootroot00000000000000<%# i.rast.rhtml $Revision: 1.5.2.1 $ %>

      <%= CGI::escapeHTML( @conf.html_title ) %> [全文検索]

      検索方法

      並べ替え: 表示件数:

      <% if @msg %>

      <%= @msg %>

      <% else %>

      <%= @result.hit_count %>件中<%= @start + 1 %>-<%= @start + @result.items.length %>件目

      <% for item in @result.items %><% format_result_item(item) %>

      <%= _(@conf.to_native(@title)) %>(スコア:<%= item.score %>)

      <% end %> <% if @result.hit_count > @num %> <%= format_links(@result) %> <% end %> <% end %> tdiary-contrib-5.0.8/util/rast-search/ja/000077500000000000000000000000001325711763500202535ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/rast-search/ja/rast-register.rb000066400000000000000000000004351325711763500233750ustar00rootroot00000000000000@rast_register_conf_label = 'Rast検索' @rast_register_conf_header = 'Rast検索インデックスの再構築' @rast_register_conf_description = 'Rast検索のインデックスを再構築する場合は、チェックボックスをチェックしてOKを押してください。' tdiary-contrib-5.0.8/util/rast-search/rast-register.rb000077500000000000000000000171611325711763500230120ustar00rootroot00000000000000#!/usr/bin/env ruby # # Copyright (C) 2005 Kazuhiko # You can redistribute it and/or modify it under GPL2. # mode = "" if $0 == __FILE__ require 'cgi' ARGV << '' # dummy argument against cgi.rb offline mode. @cgi = CGI::new mode = "CMD" else mode = "PLUGIN" end if mode == "CMD" tdiary_path = "." tdiary_conf = "." $stdout.sync = true def usage puts "rast-register.rb $Revision: 1.10.2.2 $" puts " register to rast index files from tDiary's database." puts " usage: ruby rast-regiser.rb [-p ] [-c ]" exit end require 'getoptlong' parser = GetoptLong::new parser.set_options(['--path', '-p', GetoptLong::REQUIRED_ARGUMENT], ['--conf', '-c', GetoptLong::REQUIRED_ARGUMENT]) begin parser.each do |opt, arg| case opt when '--path' tdiary_path = arg when '--conf' tdiary_conf = arg end end rescue usage exit( 1 ) end tdiary_conf = tdiary_path unless tdiary_conf Dir::chdir( tdiary_conf ) begin $:.unshift tdiary_path require "#{tdiary_path}/tdiary" rescue LoadError $stderr.puts "rast-register.rb: cannot load tdiary.rb. <#{tdiary_path}/tdiary>\n" $stderr.puts " usage: ruby rast-regiser.rb [-p ] [-c ]" exit( 1 ) end end require 'rast' module ::TDiary # # Database # class RastDB DB_OPTIONS = { "preserve_text" => true, "properties" => [ { "name" => "title", "type" => Rast::PROPERTY_TYPE_STRING, "search" => false, "text_search" => true, "full_text_search" => true, "unique" => false, }, { "name" => "user", "type" => Rast::PROPERTY_TYPE_STRING, "search" => true, "text_search" => false, "full_text_search" => false, "unique" => false, }, { "name" => "date", "type" => Rast::PROPERTY_TYPE_STRING, "search" => true, "text_search" => true, "full_text_search" => false, "unique" => false, }, { "name" => "last_modified", "type" => Rast::PROPERTY_TYPE_DATE, "search" => true, "text_search" => false, "full_text_search" => false, "unique" => false, } ] } attr_accessor :db attr_reader :conf, :encoding def initialize(conf, encoding) @conf = conf @encoding = encoding @db_options = {'encoding' => @encoding}.update(DB_OPTIONS) @db_options['properties'].delete_if{|i| i['name'] == 'user'} unless @conf['rast.with_user_name'] end def transaction if !File.exist?(db_path) Rast::DB.create(db_path, @db_options) end Rast::DB.open(db_path, Rast::DB::RDWR, "sync_threshold_chars" => 500000) { |@db| yield self } end def cache_path @conf.cache_path || "#{@conf.data_path}cache" end def db_path @conf['rast.db_path'] || "#{cache_path}/rast".untaint end end # # Register # class RastRegister < TDiaryBase def initialize(rast_db, diary) @db = rast_db.db super(CGI::new, 'day.rhtml', rast_db.conf) @diary = diary @encoding = rast_db.encoding @date = diary.date @diaries = {@date.strftime('%Y%m%d') => @diary} if @diaries.empty? @plugin = ::TDiary::Plugin::new( 'conf' => @conf, 'cgi' => @cgi, 'cache_path' => @io.cache_path, 'diaries' => @diaries ) def @plugin.apply_plugin_alt( str, remove_tag = false ) apply_plugin( str, remove_tag ) end end def execute(force = false) date = @date.strftime('%Y%m%d') last_modified = @diary.last_modified.strftime("%FT%T") options = {"properties" => ['last_modified']} if @conf['rast.with_user_name'] result = @db.search("date : #{date} & user = #{@conf.user_name}", options) else result = @db.search("date : #{date}", options) end for item in result.items if force || item.properties[0] < last_modified @db.delete(item.doc_id) else return end end return unless @diary.visible? # body index = 0 anchor = '' @diary.each_section do |section| index += 1 @conf['apply_plugin'] = true anchor = "#{date}p%02d" % index title = CGI.unescapeHTML( @plugin.apply_plugin_alt( section.subtitle_to_html, true ).strip ) if title.empty? title = @plugin.apply_plugin_alt( section.body_to_html, true ).strip title = @conf.shorten( CGI.unescapeHTML( title ), 20 ) end body = CGI.unescapeHTML( @plugin.apply_plugin_alt( section.body_to_html, true ).strip ) properties = { "title" => title, "date" => anchor, "last_modified" => last_modified, } properties["user"] = @conf.user_name if @conf['rast.with_user_name'] @db.register(body, properties) end # comment @diary.each_visible_comment( 100 ) do |comment, index| if /^(TrackBack|Pingback)$/i =~ comment.name anchor = "#{date}t%02d" % index title = "TrackBack (#{comment.name})" else anchor = "#{date}c%02d" % index title = "#{@plugin.comment_description_short} (#{comment.name})" end body = comment.body properties = { "title" => title, "date" => anchor, "last_modified" => comment.date.strftime("%FT%T"), } properties["user"] = @conf.user_name if @conf['rast.with_user_name'] @db.register(body, properties) end end protected def mode; 'day'; end def cookie_name; ''; end def cookie_mail; ''; end def convert(str) str end end # # Main # class RastRegisterMain < TDiaryBase def initialize(conf) super(CGI::new, 'day.rhtml', conf) end def execute(encoding, out = $stdout) require 'fileutils' calendar db = RastDB.new(conf, encoding) FileUtils.rm_rf(db.db_path) db.transaction do |rast_db| @years.keys.sort.each do |year| out << "(#{year.to_s}/) " @years[year.to_s].sort.each do |month| @io.transaction(Time::local(year.to_i, month.to_i)) do |diaries| diaries.sort.each do |day, diary| RastRegister.new(rast_db, diary).execute out << diary.date.strftime('%m%d ') end false end end end end end end end if mode == "CMD" begin require 'cgi' if TDiary::Config.instance_method(:initialize).arity != 0 # for tDiary 2.1 or later cgi = CGI.new conf = TDiary::Config::new(cgi) else # for tDiary 2.0 or earlier conf = TDiary::Config::new end conf.header = '' conf.footer = '' conf.show_comment = true conf.hide_comment_form = true conf.show_nyear = false def conf.bot?; true; end encoding = 'utf8' TDiary::RastRegisterMain.new(conf).execute(encoding) rescue print $!, "\n" $@.each do |v| print v, "\n" end exit( 1 ) end puts else add_update_proc do conf = @conf.clone conf.header = '' conf.footer = '' conf.show_comment = true conf.hide_comment_form = true conf.show_nyear = false def conf.bot?; true; end diary = @diaries[@date.strftime('%Y%m%d')] encoding = 'utf8' TDiary::RastDB.new(conf, encoding).transaction do |rast_db| TDiary::RastRegister.new(rast_db, diary).execute(true) end end if !@conf['rast_register.hideconf'] && (@mode == 'conf' || @mode == 'saveconf') args = ['rast_register', @rast_register_conf_label] args << 'update' if TDIARY_VERSION > '2.1.3' add_conf_proc(*args) do str = <<-HTML

      #{@rast_register_conf_header}

      HTML if @mode == 'saveconf' if @cgi.valid?( 'rast_register_rebuild' ) encoding = 'utf8' str << '

      The following diaries were registered.

      ' out = '' TDiary::RastRegisterMain.new(@conf).execute(encoding, out) str << "

      #{out}

      " end end str end end end tdiary-contrib-5.0.8/util/rast-search/rast-search.rb000077500000000000000000000136461325711763500224370ustar00rootroot00000000000000#!/usr/bin/env ruby # -*- coding: utf-8 -*- # rast-search.rb $Revision: 1.6.2.2 $ # # Copyright (C) 2005 Kazuhiko # You can redistribute it and/or modify it under GPL2. # $KCODE= 'u' BEGIN { $stdout.binmode } if FileTest::symlink?( __FILE__ ) then org_path = File::dirname( File::readlink( __FILE__ ) ) else org_path = File::dirname( __FILE__ ) end $:.unshift( org_path.untaint ) require 'tdiary' require 'rast' # # class TDiaryRast # module TDiary class TDiaryRast < ::TDiary::TDiaryBase MAX_PAGES = 20 SORT_OPTIONS = [ ["score", "スコア順"], ["date", "日付順"], ] SORT_PROPERTIES = ["date"] ORDER_OPTIONS = [ ["asc", "昇順"], ["desc", "降順"], ] NUM_OPTIONS = [10, 20, 30, 50, 100] def initialize( cgi, rhtml, conf ) super @db_path = conf.options['rast.db_path'] || "#{cache_path}/rast" @encoding = 'utf8' # conf.options['sp.selected'] = '' parse_args format_form if @query.empty? @msg = '検索条件を入力して、「検索」ボタンを押してください' else search end end def load_plugins super # add a opensearch rss link @plugin.instance_variable_get('@header_procs').unshift Proc.new { cgi_url = @conf.base_url.sub(%r|/[^/]*$|, '/') + (@cgi.script_name ? _(File.basename(@cgi.script_name)) : '') %Q|\t\n| } # override some plugins def @plugin.sn(number = nil); ''; end end def eval_rxml require 'time' load_plugins ERB::new( File::open( "#{PATH}/skel/rast.rxml" ){|f| f.read }.untaint ).result( binding ) end private def parse_args @query = @cgi["query"].strip @start = @cgi["start"].to_i @num = @cgi["num"].to_i if @num < 1 @num = 10 elsif @num > 100 @num = 100 end @sort = @cgi["sort"].empty? ? "score" : @cgi["sort"] @order = @cgi["order"].empty? ? "desc" : @cgi["order"] end def search db = Rast::DB.open(@db_path, Rast::DB::RDONLY) begin options = create_search_options t = Time.now @result = db.search(convert(@query), options) @secs = Time.now - t rescue @msg = "エラー: #{_($!.to_s)}

      " ensure db.close end end def format_result_item(item) if @conf['rast.with_user_name'] @title, @user, @date, @last_modified = *item.properties else @title, @date, @last_modified = *item.properties end @summary = _(item.summary) || '' for term in @result.terms @summary.gsub!(Regexp.new(Regexp.quote(CGI.escapeHTML(term.term)), true, @encoding), "\\&") end end def format_links(result) page_count = (result.hit_count - 1) / @num + 1 current_page = @start / @num + 1 first_page = current_page - (MAX_PAGES / 2 - 1) if first_page < 1 first_page = 1 end last_page = first_page + MAX_PAGES - 1 if last_page > page_count last_page = page_count end buf = "

      \n" if current_page > 1 buf.concat(format_link("前へ", @start - @num, @num)) end if first_page > 1 buf.concat("... ") end for i in first_page..last_page if i == current_page buf.concat("#{i} ") else buf.concat(format_link(i.to_s, (i - 1) * @num, @num)) end end if last_page < page_count buf.concat("... ") end if current_page < page_count buf.concat(format_link("次へ", @start + @num, @num)) end buf.concat("

      \n") return buf end def format_anchor(start, num) return format('?query=%s;start=%d;num=%d;sort=%s;order=%s', CGI::escape(@query), start, num, _(@sort), _(@order)) end def format_link(label, start, num) return format('%s ', _(@cgi.script_name ? @cgi.script_name : ""), format_anchor(start, num), _(label)) end def create_search_options options = { "properties" => [ "title", "date", 'last_modified' ], "need_summary" => true, "summary_nchars" => 150, "start_no" => @start, "num_items" => @num } options['properties'] << 'user' if @conf['rast.with_user_name'] if SORT_PROPERTIES.include?(@sort) options["sort_method"] = Rast::SORT_METHOD_PROPERTY options["sort_property"] = @sort end if @order == "asc" options["sort_order"] = Rast::SORT_ORDER_ASCENDING else options["sort_order"] = Rast::SORT_ORDER_DESCENDING end return options end def format_options(options, value) return options.collect { |val, label| if val == value "" else "" end }.join("\n") end def format_form @num_options = NUM_OPTIONS.collect { |n| if n == @num "" else "" end }.join("\n") @sort_options = format_options(SORT_OPTIONS, @sort) @order_options = format_options(ORDER_OPTIONS, @order) end def _(str) CGI::escapeHTML(str) end def convert(str) @conf.to_native(str) end end end begin @cgi = CGI::new if ::TDiary::Config.instance_method(:initialize).arity != 0 # for tDiary 2.1 or later conf = ::TDiary::Config::new(@cgi) else # for tDiary 2.0 or earlier conf = ::TDiary::Config::new end tdiary = TDiary::TDiaryRast::new( @cgi, 'rast.rhtml', conf ) head = { 'type' => 'text/html', 'Vary' => 'User-Agent' } if @cgi['type'] == 'rss' head['type'] = "application/xml; charset=#{conf.encoding}" body = tdiary.eval_rxml else body = tdiary.eval_rhtml end head['charset'] = conf.encoding head['Content-Length'] = body.size.to_s head['Pragma'] = 'no-cache' head['Cache-Control'] = 'no-cache' print @cgi.header( head ) print body rescue Exception if @cgi then print @cgi.header( 'type' => 'text/plain' ) else print "Content-Type: text/plain\n\n" end puts "#$! (#{$!.class})" puts "" puts $@.join( "\n" ) end tdiary-contrib-5.0.8/util/rast-search/rast.rhtml000066400000000000000000000032501325711763500217020ustar00rootroot00000000000000<%# rast.rhtml $Revision: 1.7.2.1 $ %>
      <%%=navi_user%>

      <%= CGI::escapeHTML( @conf.html_title ) %> [全文検索]

      検索方法

      並べ替え: 表示件数:

      <% if @msg %>

      <%= @msg %>

      <% else %>

      <%= _(@conf.to_native(@query)) %> の検索結果 <%= @result.hit_count %> 件中 <%= @start + 1 %> - <%= @start + @result.items.length %> 件目 (<%= @secs %> 秒)

      <% if @result.hit_count > @num %> <%= format_links(@result) %> <% end %> <% for item in @result.items %> <% format_result_item(item) %>

      <%= _(@conf.to_native(@title)) %>

      <%= @conf.to_native(@summary) %>

      <%= @conf.comment_anchor %>  (スコア:<%= item.score %>)

      <% end %> <% if @result.hit_count > @num %> <%= format_links(@result) %> <% end %> <% end %> tdiary-contrib-5.0.8/util/rast-search/rast.rxml000066400000000000000000000021051325711763500215340ustar00rootroot00000000000000"?> <%= _( @conf.html_title ) %> [全文検索]: <%= _(@query) %> <%= @conf.base_url.sub(%r|/[^/]*$|, '/') %><%= _(@cgi.script_name ? File.basename(@cgi.script_name) : "") %><%= format_anchor(@start, @num) %> Rast 検索: <%= _(@query) %> ja-JP <%= @result.hit_count %> <%= @start + 1 %> <%= @num %> <% for item in @result.items %> <% format_result_item(item) %> <%= _(@conf.to_native(@title)) %> <%= @conf.base_url %><%= @plugin.anchor(@date) %> <%= _(CGI.rfc1123_date(Time.parse(@last_modified))) %> <%= @conf.to_native(@summary) %> <% end %> tdiary-contrib-5.0.8/util/section_link/000077500000000000000000000000001325711763500201265ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/section_link/README000066400000000000000000000013011325711763500210010ustar00rootroot00000000000000はてなダイアリーの「日記モード・見出し別ページ」のように、「1見出しが1ページになる日記形式、日付ごとにコメント・トラックバックを表示」になるようにします。 * tdiary以下のファイル3つ:tdiary以下に入れます(wikiとtdiary記法に対応しています) * misc/plugin/section_link.rb を設定画面から有効にします * mod_rewriteを使って拡張子を書き換えているひとは、misc/plugin/section_link_anchor.rbも有効にします ** mod_rewriteを書き換えます RewriteEngine on RewriteRule ^([0-9\-]+)p?([0-9]*)\.html$ ?date=$1§ion=$2 [L] tdiary-contrib-5.0.8/util/section_link/misc/000077500000000000000000000000001325711763500210615ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/section_link/misc/plugin/000077500000000000000000000000001325711763500223575ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/section_link/misc/plugin/section_link.rb000066400000000000000000000032131325711763500253640ustar00rootroot00000000000000# Copyright (C) 2011, KADO Masanori # You can redistribute it and/or modify it under GPL. # # section_link.rb # - enables section link and shows section title # - depends on: # - tdiary/tdiary_day_ext.rb # - tdiary/tdiaryext_style.rb # - tdiary/wikiext_style.rb alias :_orig_subtitle_link :subtitle_link def subtitle_link( date, index, subtitle ) if @cgi.params['section'].join('') != '' index = @cgi.params['section'][0] end r = _orig_subtitle_link( date, index, subtitle ) r.gsub(/#p(\d+)/){"§ion=#{$1}"} end alias :_orig_title_tag :title_tag def title_tag if @cgi.params['section'].join('') != '' and @mode == 'day' and diary = @diaries[@date.strftime('%Y%m%d')] sec = [] diary.each_section do |s| sec << s end site_title = " - #{_orig_title_tag.gsub( /<.*?>/, '')}" title = sec[@cgi.params['section'][0].to_i - 1].stripped_subtitle_to_html return "#{apply_plugin(title, true).gsub(/[\r\n]/, '')}#{h site_title }" else _orig_title_tag end end if @cgi.params["section"].join('') != "" add_section_leave_proc do diary = @diaries[@date.strftime("%Y%m%d")] i = 1 sections = [] diary.each_section do |s| unless i == @cgi.params["section"][0].to_i sections << [i, s] end i += 1 end unless sections.empty? "
      \n
        \n" + sections.map{|i, s| [i, my(@date.strftime("%Y%m%d") + "p" + sprintf("%02d", i), apply_plugin(s.stripped_subtitle_to_html, true))] }.map{|i, s| "
      1. #{s}
      2. " }.join("\n") + "\n
      \n" end end end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/util/section_link/misc/plugin/section_link_anchor.rb000066400000000000000000000013041325711763500267150ustar00rootroot00000000000000# Copyright (C) 2011, KADO Masanori # You can redistribute it and/or modify it under GPL. # # section_link_anchor.rb # - enables section link with mod_rewrite # - depends on section_link.rb # # sample .htaccess: # # RewriteEngine on # RewriteRule ^([0-9\-]+)p?([0-9]*)\.html$ ?date=$1§ion=$2 [L] # def anchor( s ) if /^([\-\d]+)#?([pct]\d*)?$/ =~ s then if $2 then s1 = $1 s2 = $2 if $2 =~ /^p/ "#{s1}p#{s2.gsub(/p/, '')}.html" else "#{s1}.html##{s2}" end else "#$1.html" end else "" end end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/util/section_link/tdiary/000077500000000000000000000000001325711763500214225ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/section_link/tdiary/tdiary_day_ext.rb000066400000000000000000000006731325711763500247660ustar00rootroot00000000000000# Copyright (C) 2011, KADO Masanori # You can redistribute it and/or modify it under GPL. module TDiary class TDiaryDay alias :_orig_eval_rhtml :eval_rhtml def eval_rhtml if @cgi.params['section'].join('') != "" @diary.section_no = @cgi.params['section'][0] end _orig_eval_rhtml end end end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/util/section_link/tdiary/tdiaryext_style.rb000066400000000000000000000012731325711763500252070ustar00rootroot00000000000000# Copyright (C) 2011, KADO Masanori # You can redistribute it and/or modify it under GPL. require 'tdiary/tdiary_day_ext' module TDiary class TdiaryextDiary; end class TdiaryDiary attr_accessor :section_no alias :_orig_to_html4 :to_html4 def to_html4( opt ) if @section_no idx = @section_no.to_i @sections = [@sections[idx - 1]] end _orig_to_html4 opt end alias :_orig_to_chtml :to_chtml def to_chtml( opt ) if @section_no idx = @section_no.to_i @sections = [@sections[idx - 1]] end _orig_to_chtml opt end end end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/util/section_link/tdiary/wikiext_style.rb000066400000000000000000000013311325711763500246510ustar00rootroot00000000000000# Copyright (C) 2011, KADO Masanori # You can redistribute it and/or modify it under GPL. require 'tdiary/tdiary_day_ext' module TDiary class WikiextDiary; end class WikiDiary attr_accessor :section_no alias :_orig_to_html4 :to_html4 def to_html4( opt ) if @section_no idx = @section_no.to_i return @sections[idx - 1].html4( date, idx, opt ) end _orig_to_html4 opt end alias :_orig_to_chtml :to_chtml def to_chtml( opt ) if @section_no idx = @section_no.to_i return @sections[idx - 1].html4( date, idx, opt ) end _orig_to_chtml opt end end end # Local Variables: # mode: ruby # indent-tabs-mode: t # tab-width: 3 # ruby-indent-level: 3 # End: # vim: ts=3 tdiary-contrib-5.0.8/util/tdiary-for-ruby1.9/000077500000000000000000000000001325711763500207345ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/tdiary-for-ruby1.9/compatible.rb000066400000000000000000000036331325711763500234050ustar00rootroot00000000000000# = for Ruby1.9.0 compatible = # # == 前提条件 == # # * Ruby1.9 の場合は --encoding=Binary オプションで動作させること # -------------------------------------------------------- # 汎用的な設定 # -------------------------------------------------------- # for Ruby1.9.0 unless "".respond_to?('to_a') class String def to_a [ self ] end end end unless "".respond_to?('each') class String alias each each_line end end # Ruby1.9では String が Enumerable ではなくなった class String def method_missing(name, *args, &block) each_line.__send__(name, *args, &block) end end # for Ruby1.8.X unless "".respond_to?('force_encoding') class String def force_encoding(encoding) self end end end unless "".respond_to?('bytesize') class String alias bytesize size end end unless "".respond_to?('ord') class String def ord self[0] end end class Integer def ord self end end end # -------------------------------------------------------- # tDiary 用の設定 # -------------------------------------------------------- # Ruby1.9でNKF::nkfを呼ぶと文字列のencodingが変わってしまう。 # そのため、encodingがBinaryの環境で動かすと # "character encodings differ" エラーとなる。 begin require 'nkf' module NKF alias :_nkf :nkf def nkf(option, src) r = _nkf(option, src) r.force_encoding('Binary') end module_function :nkf, :_nkf end rescue end # 日本語を含むツッコミを入れると diary.last_modified が String になる (原因不明) # (PStore 保存前は Time だが, 保存後に String となる) # 暫定的に String だったら Time へ変換する module TDiary class WikiDiary def last_modified if @last_modified.instance_of? String @last_modified = Time.at(0) end @last_modified end end end tdiary-contrib-5.0.8/util/tdiary-for-ruby1.9/tdiary-2.2.0.patch000066400000000000000000000075351325711763500237200ustar00rootroot00000000000000Index: update.rb =================================================================== --- update.rb (revision 97) +++ update.rb (working copy) @@ -5,7 +5,7 @@ # Copyright (C) 2001-2003, TADA Tadashi # You can redistribute it and/or modify it under GPL2. # -BEGIN { $defout.binmode } +BEGIN { $stdout.binmode } $KCODE = 'n' begin Index: misc/lib/hikidoc.rb =================================================================== --- misc/lib/hikidoc.rb (revision 97) +++ misc/lib/hikidoc.rb (working copy) @@ -476,7 +476,7 @@ def escape_meta_char( text ) text.gsub( META_CHAR_RE ) do |s| - '&#x%x;' % s[1] + '&#x%x;' % s[1].ord end end Index: misc/plugin/amazon.rb =================================================================== --- misc/plugin/amazon.rb (revision 97) +++ misc/plugin/amazon.rb (working copy) @@ -205,6 +205,7 @@ xml = amazon_call_ecs( asin, id_type ) File::open( "#{cache}/#{asin}.xml", 'wb' ) {|f| f.write( xml )} end + xml.force_encoding('UTF-8') doc = REXML::Document::new( xml ).root item = doc.elements.to_a( '*/Item' )[0] if pos == 'detail' then Index: tdiary.rb =================================================================== --- tdiary.rb (revision 97) +++ tdiary.rb (working copy) @@ -11,6 +11,7 @@ $:.insert( 1, File::dirname( __FILE__ ) + '/misc/lib' ) +require 'compatible' require 'cgi' require 'uri' begin @@ -466,6 +467,7 @@ load instance_variables.each do |v| + v = v.to_s v.sub!( /@/, '' ) instance_eval( <<-SRC def #{v} @@ -631,11 +633,10 @@ cgi_conf.untaint unless @secure def_vars = "" variables.each do |var| def_vars << "#{var} = nil\n" end - eval( def_vars ) + extend_vars = 'variables.each do |var| eval "@#{var} = #{var} if #{var} != nil" end' Safe::safe( @secure ? 4 : 1 ) do - eval( cgi_conf, binding, "(TDiary::Config#cgi_conf)", 1 ) + eval( def_vars + cgi_conf + extend_vars, binding, "(TDiary::Config#cgi_conf)", 1 ) end - variables.each do |var| eval "@#{var} = #{var} if #{var} != nil" end rescue IOError, Errno::ENOENT end end Index: plugin/ja/05referer.rb =================================================================== --- plugin/ja/05referer.rb (revision 97) +++ plugin/ja/05referer.rb (working copy) @@ -31,7 +31,7 @@

      既存設定はこちら

      #{label_referer_table}

      - #{"

      リンク元リストのURLを、特定の文字列に変換する対応表を指定できます。1件につき、URLと表示文字列を空白で区切って指定します。正規表現が使えるので、URL中に現れた「(~)」は、置換文字列中で「\\1」のような「\数字」で利用できます。

      " unless @conf.mobile_agent?} + #{"

      リンク元リストのURLを、特定の文字列に変換する対応表を指定できます。1件につき、URLと表示文字列を空白で区切って指定します。正規表現が使えるので、URL中に現れた「(~)」は、置換文字列中で「\\\\1」のような「\\数字」で利用できます。

      " unless @conf.mobile_agent?}

      既存設定はこちら

      HTML Index: index.rb =================================================================== --- index.rb (revision 97) +++ index.rb (working copy) @@ -5,7 +5,7 @@ # Copyright (C) 2001-2006, TADA Tadashi # You can redistribute it and/or modify it under GPL2. # -BEGIN { $defout.binmode } +BEGIN { $stdout.binmode } $KCODE = 'n' begin tdiary-contrib-5.0.8/util/tdiary-for-ruby1.9/tdiary-2.3.1.patch000066400000000000000000000173611325711763500237200ustar00rootroot00000000000000=== index.rb ================================================================== --- index.rb (revision 27329) +++ index.rb (local) @@ -1,11 +1,11 @@ #!/usr/bin/env ruby # -# index.rb $Revision: 1.35 $ +# index.rb # -# Copyright (C) 2001-2006, TADA Tadashi +# Copyright (C) 2001-2008, TADA Tadashi # You can redistribute it and/or modify it under GPL2. # -BEGIN { $defout.binmode } +BEGIN { $stdout.binmode } $KCODE = 'n' begin @@ -70,7 +70,7 @@ if @cgi.mobile_agent? then body = conf.to_mobile( tdiary.eval_rhtml( 'i.' ) ) head['charset'] = conf.mobile_encoding - head['Content-Length'] = body.size.to_s + head['Content-Length'] = body.bytesize.to_s else require 'digest/md5' body = tdiary.eval_rhtml @@ -80,7 +80,7 @@ body = '' else head['charset'] = conf.encoding - head['Content-Length'] = body.size.to_s + head['Content-Length'] = body.bytesize.to_s end head['Pragma'] = 'no-cache' head['Cache-Control'] = 'no-cache' === plugin/00default.rb ================================================================== --- plugin/00default.rb (revision 27329) +++ plugin/00default.rb (local) @@ -697,7 +697,7 @@ mail_header = (@conf['comment_mail.header'] || '').dup mail_header << ":#{@conf.date_format}" unless /%[a-zA-Z%]/ =~ mail_header mail_header = @date.strftime( mail_header ) - mail_header = comment_mail_mime( @conf.to_mail( mail_header ) ).join( "\n " ) if /[\x80-\xff]/ =~ mail_header + mail_header = comment_mail_mime( @conf.to_mail( mail_header ) ).join( "\n " ) rmail = '' begin === plugin/05referer.rb ================================================================== --- plugin/05referer.rb (revision 27329) +++ plugin/05referer.rb (local) @@ -159,7 +159,7 @@ def referer_add_to_diary( diary, body ) return unless body - body.each do |r| + body.each_line do |r| count, ref = r.chomp.split( / /, 2 ) next unless ref diary.add_referer( ref.chomp, count.to_i ) === plugin/ja/05referer.rb ================================================================== --- plugin/ja/05referer.rb (revision 27329) +++ plugin/ja/05referer.rb (local) @@ -31,7 +31,7 @@

      既存設定はこちら

      #{label_referer_table}

      - #{"

      リンク元リストのURLを、特定の文字列に変換する対応表を指定できます。1件につき、URLと表示文字列を空白で区切って指定します。正規表現が使えるので、URL中に現れた「(〜)」は、置換文字列中で「\\1」のような「\数字」で利用できます。

      " unless @conf.mobile_agent?} + #{"

      リンク元リストのURLを、特定の文字列に変換する対応表を指定できます。1件につき、URLと表示文字列を空白で区切って指定します。正規表現が使えるので、URL中に現れた「(〜)」は、置換文字列中で「\\\\1」のような「\\数字」で利用できます。

      " unless @conf.mobile_agent?}

      既存設定はこちら

      HTML === tdiary/defaultio.rb ================================================================== --- tdiary/defaultio.rb (revision 27329) +++ tdiary/defaultio.rb (local) @@ -13,7 +13,7 @@ header, body = data.split( /\r?\n\r?\n/, 2 ) headers = {} if header then - header.each do |l| + header.each_line do |l| l.chomp! key, val = l.scan( /([^:]*):\s*(.*)/ )[0] headers[key] = val ? val.chomp : nil === tdiary/tdiary_style.rb ================================================================== --- tdiary/tdiary_style.rb (revision 27329) +++ tdiary/tdiary_style.rb (local) @@ -22,7 +22,7 @@ if lines.size > 1 then if /^<#{section.body.collect{|l|l.chomp.sub( /^[  ]/u, '')}.join( "

      \n

      " )}

      \n] + r << %Q[

      #{section.body.collect{|l|l.chomp.sub( /^[ ]/u, '')}.join( "

      \n

      " )}

      \n] else r << %Q[

      <%= subtitle_proc( Time::at( #{date.to_i} ), nil ) %>] - r << %Q[#{section.body.collect{|l|l.chomp.sub( /^[  ]/u, '' )}.join( "

      \n

      " )}

      ] + r << %Q[#{section.body.collect{|l|l.chomp.sub( /^[ ]/u, '' )}.join( "

      \n

      " )}

      ] end r << %Q[<%= section_leave_proc( Time::at( #{date.to_i} ) ) %>\n] r << %Q[] @@ -211,10 +211,10 @@ if /^#{section.body.collect{|l|l.chomp.sub( /^[  ]/u, '' )}.join( "

      \n

      " )}

      \n] + r << %Q[

      #{section.body.collect{|l|l.chomp.sub( /^[ ]/u, '' )}.join( "

      \n

      " )}

      \n] else r << %Q[

      <%= subtitle_proc( Time::at( #{date.to_i} ), nil ) %>] - r << %Q[#{section.body.collect{|l|l.chomp.sub( /^[  ]/u, '' )}.join( "

      \n

      " )}

      \n] + r << %Q[#{section.body.collect{|l|l.chomp.sub( /^[ ]/u, '' )}.join( "

      \n

      " )}

      \n] end r << %Q[<%= section_leave_proc( Time::at( #{date.to_i} ) ) %>\n] end === tdiary.rb ================================================================== --- tdiary.rb (revision 27329) +++ tdiary.rb (local) @@ -6,10 +6,11 @@ You can redistribute it and/or modify it under GPL2. =end -TDIARY_VERSION = '2.3.1' +TDIARY_VERSION = '2.3.1.20081115' $:.insert( 1, File::dirname( __FILE__ ) + '/misc/lib' ) +require 'compatible' require 'cgi' require 'uri' begin @@ -460,6 +461,7 @@ load instance_variables.each do |v| + v = v.to_s v.sub!( /@/, '' ) instance_eval( <<-SRC def #{v} @@ -660,11 +662,10 @@ cgi_conf.untaint unless @secure def_vars = "" variables.each do |var| def_vars << "#{var} = nil\n" end - eval( def_vars ) + extend_vars = 'variables.each do |var| eval "@#{ var} = #{var} if #{var} != nil" end' Safe::safe( @secure ? 4 : 1 ) do - eval( cgi_conf, binding, "(TDiary::Config#cgi_conf)", 1 ) + eval( def_vars + cgi_conf + extend_vars, binding, "(TDiary::Config#cgi_conf)", 1 ) end - variables.each do |var| eval "@#{var} = #{var} if #{var} != nil" end rescue IOError, Errno::ENOENT end end @@ -776,6 +777,7 @@ @subtitle_procs.taint @section_leave_procs.taint return Safe::safe( secure ? 4 : 1 ) do + src.force_encoding('UTF-8') eval( src, binding, "(TDiary::Plugin#eval_src)", 1 ) end end === update.rb ================================================================== --- update.rb (revision 27329) +++ update.rb (local) @@ -1,11 +1,11 @@ #!/usr/bin/env ruby # -# update.rb $Revision: 1.22 $ +# update.rb # -# Copyright (C) 2001-2003, TADA Tadashi +# Copyright (C) 2001-2008, TADA Tadashi # You can redistribute it and/or modify it under GPL2. # -BEGIN { $defout.binmode } +BEGIN { $stdout.binmode } $KCODE = 'n' begin @@ -55,7 +55,7 @@ 'status' => '200 OK', 'type' => 'text/html', 'charset' => conf.mobile_encoding, - 'Content-Length' => body.size.to_s, + 'Content-Length' => body.bytesize.to_s, 'Vary' => 'User-Agent' ) else @@ -64,7 +64,7 @@ 'status' => '200 OK', 'type' => 'text/html', 'charset' => conf.encoding, - 'Content-Length' => body.size.to_s, + 'Content-Length' => body.bytesize.to_s, 'Vary' => 'User-Agent' ) end tdiary-contrib-5.0.8/util/tdiary-grep/000077500000000000000000000000001325711763500176745ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/tdiary-grep/README000066400000000000000000000004441325711763500205560ustar00rootroot00000000000000■■このツールは最新のtDiaryに追従していません。 ■■検索機能はプラグインとして実装されるようになったため、 ■■同等の機能はplugin/search-default.rbで実現しています。 ■■このツールは近々削除する予定です。 tdiary-contrib-5.0.8/util/tdiary-grep/grep.rb000066400000000000000000000227671325711763500211740ustar00rootroot00000000000000#!/usr/bin/env ruby # -*- coding: utf-8 -*- # # $Id$ # # Copyright (C) 2003,2004 Minero Aoki # # This program is free software. # You can distribute/modify this program under the terms of # the GNU LGPL, Lesser General Public License version 2.1. # TDIARY_DATA_PATH = nil CGI_URL = './' LOGGING = true DEBUG = $DEBUG # # HTML Templates # def unindent(str, n) str.gsub(/^ {0,#{n}}/, '') end HEADER = unindent(<<-'EOS', 2) tDiary Grep EOS FOOTER = unindent(<<'EOS', 2) EOS SEARCH_FORM = unindent(<<"EOS", 2)

      % fgrep -i '' */*.td2

      EOS SEARCH_RESULT = unindent(<<-'EOS', 2) + SEARCH_FORM
        % fgrep -i '<%= patterns.map {|re| escape(re.source) }.join(' ') %>' */*.td2
        <%
            toomanyhits = match_sections(patterns) {|section|
        %><%= format_date(section.date)
        %>: <%= escape(section.short_text) %>
        <%
            }
        %><%= toomanyhits ? 'too many hits.' : ''
        %>
      EOS SEARCH_ERROR = unindent(<<'EOS', 2) + SEARCH_FORM
        % fgrep -i '<%= escape(query) %>' */*.td2
        <%= escape(reason) %>.
        
      EOS HISTORY = unindent(<<"EOS", 2)
        <%
            cmd = ['ls', 'cd .', 'cvsdiffl', 'ps -ef', 'w', './configure --help',
                   'date', 'make', 'echo $?', 'vi log', 'jobs', 'cvs up', 'who']
            recent_queries.sort_by {|t,q| t }.each do |time, query|
              n = rand(100)
              if n < cmd.size
        %><%= time.to_i - 10 %>: <%= cmd[n] %>
        <%    end
        %><%= time.to_i %>: fgrep -i '<%= escape(query) %>' */*.td2
        <%
            end
        %>
      #{SEARCH_FORM} EOS # # Load Libraries # require 'cgi' class CGI def valid?(name) self.params[name] and self.params[name][0] end end require 'erb' require 'uri' # borrowed from tdiary require 'nkf' begin require 'uconv' def Uconv.unknown_unicode_handler(unicode) if unicode == 0xff5e "~" else raise Uconv::Error end end def to_euc(str) begin Uconv.u8toeuc(str) rescue Uconv::Error NKF::nkf('-w -m0', str) end end rescue LoadError def to_euc(str) NKF::nkf('-w -m0', str) end end # # Main # class TDiaryGrepError < StandardError; end class WrongQuery < TDiaryGrepError; end class InvalidTDiaryFormat < TDiaryGrepError; end class ConfigError < TDiaryGrepError; end Z_SPACE = " " # zen-kaku space BEGIN { $stdout.binmode } def main cgi = CGI.new html = '

      error

      ' begin html = generate_page(cgi) ensure send_html cgi, html end exit 0 end def generate_page(cgi) query = nil begin begin if LOGGING and File.file?(query_log()) and cgi.valid?('history') return history_page() elsif not cgi.valid?('q') return search_form_page() else query = [cgi.params['q']].compact.flatten.join(' ') html = search_result_page(setup_patterns(query)) save_query(query, query_log()) if LOGGING return html end rescue WrongQuery => err return search_error_page(query, err.message) end rescue Exception => err html = '' html << HEADER html << "
      \n"
          html << 'q=' << escape(query) << "\n" if query
          html << escape(err.class.name) << "\n" if DEBUG
          html << escape(err.message) << "\n"
          html << err.backtrace.map {|i| escape(i) }.join("\n") if DEBUG
          html << "
      \n" html << FOOTER return html end end def send_html(cgi, html) print cgi.header('status' => '200 OK', 'type' => 'text/html', 'charset' => 'UTF-8', 'Content-Length' => html.length.to_s, 'Cache-Control' => 'no-cache', 'Pragma' => 'no-cache') print html unless cgi.request_method == 'HEAD' end def setup_patterns(query) patterns = split_string(query).map {|pat| check_pattern pat /#{Regexp.quote(pat)}/iu } raise WrongQuery, 'no pattern' if patterns.empty? raise WrongQuery, 'too many sub patterns' if patterns.length > 8 patterns end def check_pattern(pat) raise WrongQuery, 'no pattern' unless pat raise WrongQuery, 'empty pattern' if pat.empty? raise WrongQuery, "pattern too short: #{pat}" if pat.length < 2 raise WrongQuery, 'pattern too long' if pat.length > 128 end def split_string(str) str.split(/[\s#{Z_SPACE}]+/ou).reject {|w| w.empty? } end def save_query(query, file) File.open(file, 'a') {|f| begin f.flock(File::LOCK_EX) f.puts "#{Time.now.to_i}: #{query.dump}" ensure f.flock(File::LOCK_UN) end } end def read_query_logs(file) File.open(file) {|f| begin f.flock(File::LOCK_SH) return f.readlines ensure f.flock(File::LOCK_UN) end } end def query_log "#{tdiary_data_path()}/grep.log" end # # eRuby Dispatchers and Helper Routines # def search_form_page patterns = [] ERB.new(HEADER + SEARCH_FORM + FOOTER).result(binding()) end def search_result_page(patterns) ERB.new(HEADER + SEARCH_RESULT + FOOTER).result(binding()) end def search_error_page(query, reason) ERB.new(HEADER + SEARCH_ERROR + FOOTER).result(binding()) end def history_page patterns = [] ERB.new(HEADER + HISTORY + FOOTER).result(binding()) end N_SHOW_QUERY_MAX = 20 def recent_queries return unless File.file?(query_log()) read_query_logs(query_log()).reverse[0, N_SHOW_QUERY_MAX].map {|line| time, q = *line.split(/:/, 2) [Time.at(time.to_i), eval(q)] } end def format_time(time) sprintf('%04d-%02d-%02d %02d:%02d:%02d', time.year, time.month, time.day, time.hour, time.min, time.sec) end def format_date(ymd) y, m, d = /\A(\d{4})(\d{2})(\d{2})/.match(ymd).captures "#{y}-#{m}-#{d}" end TOO_MANY_HITS = 50 def match_sections(patterns) hit = 0 match_sections0(patterns) do |section| yield section hit += 1 return true if hit > TOO_MANY_HITS end false end def match_sections0(patterns) foreach_data_file(tdiary_data_path()) do |path| read_diaries(path).sort_by {|diary| diary.date }.reverse_each do |diary| diary.each_section do |section| yield section if patterns.all? {|re| re =~ section.source } end end end end # # tDiary Implementation Dependent # def foreach_data_file(data_path, &block) Dir.glob("#{data_path}/[0-9]*/*.td2").sort.reverse_each(&block) end def read_diaries(path) diaries = [] File.open(path, :encoding => 'UTF-8') {|f| f.each('') do |header| diaries.push Diary.parse(header, f.gets("\n.\n").chomp(".\n")) end } diaries end class Diary def Diary.parse(header, body) ymd = header.slice(/^Date:\s*(\d{4}\d{2}\d{2})/, 1) or raise "unexpected tdiary format: Date=nil:\n#{header.strip}" format = header.slice(/^Format:\s*(\S+)/, 1) or raise "unexpected tdiary format: Format=nil:\n#{header.strip}" visible = case header.slice(/^Visible:\s*(\S+)/, 1) when 'true' then true when 'false' then false when nil then true else raise 'must not happen (parsing Visible:)' end new(ymd, visible, split_sections(body, format)) end SPLITTER = { 'tdiary' => /\n\n/, 'rd' => /^=(?!=)/, 'wiki' => /^!/, 'blog' => /\n\n/, 'blogrd' => /^=(?!=)/, 'blogwiki' => /^!/ } def Diary.split_sections(diary, format) re = SPLITTER[format.downcase] or raise ArgumentError, "unknown diary format: #{format}" diary.strip.split(re) end private_class_method :split_sections def initialize(ymd, visible, section_texts) @date = ymd @visible = visible @sections = [] section_texts.each_with_index do |src, idx| @sections.push DiarySection.new(self, idx + 1, src) end end attr_reader :date def each_section(&block) return unless @visible @sections.each(&block) end end class DiarySection def initialize(day, num, src) @day = day @number = num @source = src end def inspect "\#<#{self.class} #{@day.date}.#{@number}>" end def date @day.date end def format @day.format end attr_reader :source def url "#{CGI_URL}?date=#{@day.date}\#p#{sprintf('%02d', @number)}" end def short_text title, body = @source.split(/\n/, 2) sprintf('%-30s | %s', title.to_s.strip, remove_tags(body.to_s).gsub(/[\s#{Z_SPACE}]+/ou, ' ').slice(/\A.{0,60}/mu)) end private def remove_tags(str) str.gsub(/<.*?>|\(\([{|'<]|[>}|']\)\)|\(\(-(?m).*?(?-m)-\)\)/, '') end end @tdiary_data_path = nil def tdiary_data_path @tdiary_data_path ||= (TDIARY_DATA_PATH || data_path_config()) end def data_path_config tdiary_conf().slice(/^\s*@data_path\s*=\s*(['"])(.*?)\1/, 2) or raise ConfigError, 'cannot get tDiary @data_path' end @tdiary_conf = nil def tdiary_conf @tdiary_conf ||= File.read("#{File.dirname(__FILE__)}/tdiary.conf", :encoding => 'UTF-8') end # # Utils # ESC = { '&' => '&', '<' => '<', '>' => '>', '"' => '"' } def escape(str) str.gsub(/[&"<>]/) {|s| ESC[s] } end def escape_url(u) escape(URI.encode(u)) end main tdiary-contrib-5.0.8/util/tdiary-mode/000077500000000000000000000000001325711763500176635ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/tdiary-mode/http.el000066400000000000000000000114111325711763500211620ustar00rootroot00000000000000;;; http.el -- utils for HTTP ;; Copyright (C) 2002 Junichiro Kita ;; Author: Junichiro Kita ;; $Id: http.el,v 1.3 2005/07/20 08:39:56 tadatadashi Exp $ ;; ;; This program is free software; you can redistribute it and/or ;; modify it under the terms of the GNU General Public License as ;; published by the Free Software Foundation; either version 2, or (at ;; your option) any later version. ;; This program is distributed in the hope that it will be useful, but ;; WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;; General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; see the file COPYING. If not, write to the ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. ;;; Commentary: ;;; Code: (require 'pces) (defvar http-proxy-server nil "Proxy server for HTTP.") (defvar http-proxy-port nil "Proxy port for HTTP.") (defvar http-timeout 10 "Timeout for HTTP.") ;; derived from url.el (defconst http-url-unreserved-chars '( ?a ?b ?c ?d ?e ?f ?g ?h ?i ?j ?k ?l ?m ?n ?o ?p ?q ?r ?s ?t ?u ?v ?w ?x ?y ?z ?A ?B ?C ?D ?E ?F ?G ?H ?I ?J ?K ?L ?M ?N ?O ?P ?Q ?R ?S ?T ?U ?V ?W ?X ?Y ?Z ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9 ?$ ?- ?_ ?. ?! ?~ ?* ?' ?\( ?\) ?,) "A list of characters that are _NOT_ reserve in the URL spec. This is taken from draft-fielding-url-syntax-02.txt - check your local internet drafts directory for a copy.") ;; derived from url.el (defun http-url-hexify-string (str coding) "Escape characters in a string. At first, encode STR using CODING, then url-hexify." (mapconcat (function (lambda (char) (if (not (memq char http-url-unreserved-chars)) (if (< char 16) (upcase (format "%%0%x" char)) (upcase (format "%%%x" char))) (char-to-string char)))) (encode-coding-string str coding) "")) (defvar http-fetch-terminator "" "content body end mark.") (defun http-fetch (url method &optional user pass data) "Fetch via HTTP. URL is a url to be POSTed. METHOD is 'get or 'post. USER and PASS must be a valid username and password, if required. DATA is an alist, each element is in the form of (FIELD . DATA). If no error, return a buffer which contains output from the web server. If error, return a cons cell (ERRCODE . DESCRIPTION)." (let (connection server port path buf str len) (string-match "^http://\\([^/:]+\\)\\(:\\([0-9]+\\)\\)?\\(/.*$\\)" url) (setq server (match-string 1 url) port (string-to-int (or (match-string 3 url) "80")) path (if http-proxy-server url (match-string 4 url))) (setq str (mapconcat '(lambda (x) (concat (car x) "=" (cdr x))) data "&")) (setq len (length str)) (save-excursion (setq buf (get-buffer-create (concat "*result from " server "*"))) (set-buffer buf) (erase-buffer) (setq connection (as-binary-process (open-network-stream (concat "*request to " server "*") buf (or http-proxy-server server) (or http-proxy-port port)))) (process-send-string connection (concat (if (eq method 'post) (concat "POST " path) (concat "GET " path (if (> len 0) (concat "?" str)))) " HTTP/1.0\r\n" (concat "Host: " server "\r\n") "Connection: close\r\n" "Referer: " url "\r\n" "Content-type: application/x-www-form-urlencoded\r\n" (if (and user pass) (concat "Authorization: Basic " (base64-encode-string (concat user ":" pass)) "\r\n")) (if (eq method 'post) (concat "Content-length: " (int-to-string len) "\r\n" "\r\n" str)) "\r\n")) (goto-char (point-min)) (while (not (search-forward http-fetch-terminator nil t)) (unless (accept-process-output connection http-timeout) (error "HTTP fetch: Connection timeout!")) (goto-char (point-min))) (goto-char (point-min)) (save-excursion (if (re-search-forward "HTTP/1.[01] \\([0-9][0-9][0-9]\\) \\(.*\\)" nil t) (let ((code (match-string 1)) (desc (match-string 2))) (cond ((equal code "200") buf) (t (cons code desc))))))))) (provide 'http) ;;; http.el ends here tdiary-contrib-5.0.8/util/tdiary-mode/tdiary-mode.el000066400000000000000000000467041325711763500224360ustar00rootroot00000000000000;;; tdiary-mode.el -- Major mode for tDiary editing -*- coding: utf-8 -*- ;; Copyright (C) 2002 Junichiro Kita ;; Author: Junichiro Kita ;; $Id: tdiary-mode.el,v 1.4 2005/08/19 08:36:43 tadatadashi Exp $ ;; ;; This program is free software; you can redistribute it and/or ;; modify it under the terms of the GNU General Public License as ;; published by the Free Software Foundation; either version 2, or (at ;; your option) any later version. ;; This program is distributed in the hope that it will be useful, but ;; WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;; General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program; see the file COPYING. If not, write to the ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. ;;; Commentary: ;; usage: ;; ;; Put the following in your .emacs file: ;; ;; (setq tdiary-diary-list '(("my 1st diary" "http://example.com/tdiary/") ;; ("my 2nd diary" "http://example.com/tdiary2/"))) ;; (setq tdiary-text-directory (expand-file-name "~/path-to-saved-diary")) ;; (setq tdiary-browser-function 'browse-url) ;; (autoload 'tdiary-mode "tdiary-mode" nil t) ;; (autoload 'tdiary-new "tdiary-mode" nil t) ;; (autoload 'tdiary-new-diary "tdiary-mode" nil t) ;; (autoload 'tdiary-replace "tdiary-mode" nil t) ;; (add-to-list 'auto-mode-alist ;; '("\\.td$" . tdiary-mode)) ;; ;; You can use your own plugin completion, keybindings: ;; ;; (setq tdiary-plugin-definition ;; '( ;; ("STRONG" ("<%=STRONG %Q|" (p "str: ") "| %>")) ;; ("PRE" ("<%=PRE %Q|" (p "str: ") "| %>")) ;; ("CITE" ("<%=CITE %Q|" (p "str: ") "| %>")) ;; )) ;; ;; (add-hook 'tdiary-mode-hook ;; '(lambda () ;; (local-set-key "\C-i" 'tdiary-complete-plugin))) ;; ;; If you want to save username and password cache to file: ;; ;; (setq tdiary-passwd-file (expand-file-name "~/.tdiary-pass")) ;; ;; then, M-x tdiary-passwd-cache-save. !!DANGEROUS!! ;; ;; see http://kitaj.no-ip.com/rw-cgi.rb?cmd=view;name=tdiary-mode ;; ;; ToDo: ;; - find plugin definition automatically(needs modification for plugin) ;; - bug fix ;; ;;; Variable: (require 'http) (require 'poe) (require 'tempo) (defvar tdiary-diary-list nil "List of diary list. Each element looks like (NAME URL) or (NAME URL INDEX-RB UPDATE-RB).") (defvar tdiary-diary-name nil "Identifier for diary to be updated.") (defvar tdiary-diary-url nil "tDiary-mode updates this URL. URL should end with '/'.") (defvar tdiary-index-rb nil "Name of the 'index.rb'.") (defvar tdiary-update-rb "update.rb" "Name of the 'update.rb'.") (defvar tdiary-csrf-key nil "CSRF protection key.") (defvar tdiary-coding-system 'utf-8-dos) (defvar tdiary-title nil "Title of diary") (defvar tdiary-style-mode 'html-mode "Major mode to be used for tDiary editing.") (defvar tdiary-date nil "Date to be updated.") (defvar tdiary-edit-mode nil) (defvar tdiary-plugin-list nil "A List of pairs of a plugin name and its completing command. It is used in `tdiary-complete-plugin'.") (defvar tdiary-tempo-tags nil "Tempo tags for tDiary mode") (defvar tdiary-completion-finder "\\(\\(<\\|&\\|<%=\\).*\\)\\=" "Regexp used to find tags to complete.") (defvar tdiary-plugin-initial-definition '( ("my" ("<%=my %Q|" (p "a: ") "|, %Q|" (p "str: ") "| %>")) ("fn" ("<%=fn %Q|" (p "footnote: ") "| %>")) ) "Initial definition for tDiary tempo." ) (defvar tdiary-edit-mode-list '(("append") ("replace"))) (defvar tdiary-plugin-definition nil "A List of definitions for tDiary tempo. Each element looks like (NAME ELEMENTS). NAME is a string that contains the name of plugin, and ELEMENTS is a list of elements in the template. See tempo.info for details.") (defvar tdiary-complete-plugin-history nil "Minibuffer history list for `tdiary-complete-plugin'.") (defvar tdiary-passwd-file nil) (defvar tdiary-passwd-file-mode 384) ;; == 0600 (defvar tdiary-text-directory-mode 448) ;; == 0700 (defvar tdiary-passwd-cache nil "Cache for username and password.") (defvar tdiary-hour-offset 0 "Offset to current-time. `tdiary-today' returns (current-time + tdiary-hour-offset).") (defvar tdiary-text-suffix ".td") (defvar tdiary-text-directory nil "Directory where diary is stored.") (defvar tdiary-text-save-p nil "Flag for saving text. If non-nil, tdiary buffer is associated to a real file, named `tdiary-date' + `tdiary-text-suffix'.") (defvar tdiary-browser-function nil "Function to call browser. If non-nil, `tdiary-update' calls this function. The function is expected to accept only one argument(URL).") (defvar tdiary-mode-hook nil "Hook run when entering tDiary mode.") (defvar tdiary-init-file "~/.tdiary" "Init file for tDiary-mode.") ;(defvar tdiary-plugin-dir nil ; "Path to plugins. It must be a mounted file system.") ;(defvar tdiary-plugin-definition-regexp "^[ \t]*def[ \t]+\\(.+?\\)[ \t]*\\(?:$\\|;\\|([ \t]*\\(.*?\\)[ \t]*)\\)") ;;; Code: (defun tdiary-tempo-add-tag (def) (let* ((plugin (car def)) (element (cadr def)) (name (concat "tdiary-" plugin)) (completer (concat "<%=" plugin)) (doc (concat "Insert `" plugin "'")) (command (tempo-define-template name element completer doc 'tdiary-tempo-tags))) (add-to-list 'tdiary-plugin-list (list plugin command)))) (defun tdiary-tempo-define (l) (mapcar 'tdiary-tempo-add-tag l)) ;(defun tdiary-parse-plugin-args (args) ; (if (null args) ; nil ; (mapcar '(lambda (x) ; (let ((l (split-string x "[ \t]*=[ \t]*"))) ; (if (eq (length l) 1) ; (car l) ; l))) ; (split-string args "[ \t]*,[ \t]*")))) ;(defun tdiary-update-plugin-definition () ; (interactive) ; (let ((files (directory-files tdiary-plugin-dir t ".*\\.rb$" nil t)) ; (buf (generate-new-buffer "*update plugin*"))) ; (save-excursion ; (save-window-excursion ; (switch-to-buffer buf) ; (mapc 'insert-file-contents files) ; (setq tdiary-plugin-definition nil) ; (while (re-search-forward tdiary-plugin-definition-regexp nil t) ; (add-to-list 'tdiary-plugin-definition ; (list (match-string 1) ; (tdiary-parse-plugin-args (match-string 2))))) ; (kill-buffer buf))))) (defun tdiary-do-complete-plugin (&optional name) "Complete function for plugin." (let (command) (when (null name) (setq name (completing-read "plugin: " tdiary-plugin-list nil nil nil 'tdiary-complete-plugin-history))) (setq command (cadr (assoc name tdiary-plugin-list))) (when command (funcall command)))) ;; derived from tempo.el (defun tdiary-complete-plugin (&optional silent) "Look for a HTML tag or plugin and expand it. If there are no completable text, call `tdiary-do-complete-plugin'." (interactive "*") (let* ((collection (tempo-build-collection)) (match-info (tempo-find-match-string tempo-match-finder)) (match-string (car match-info)) (match-start (cdr match-info)) (exact (assoc match-string collection)) (compl (or (car exact) (and match-info (try-completion match-string collection))))) (if compl (delete-region match-start (point))) (cond ((or (null match-info) (null compl)) (tdiary-do-complete-plugin)) ((eq compl t) (tempo-insert-template (cdr (assoc match-string collection)) nil)) (t (if (setq exact (assoc compl collection)) (tempo-insert-template (cdr exact) nil) (insert compl) (or silent (ding)) (if tempo-show-completion-buffer (tempo-display-completions match-string collection))))))) (defun tdiary-today () (let* ((offset-second (* tdiary-hour-offset 60 60)) (now (current-time)) (high (nth 0 now)) (low (+ (nth 1 now) offset-second)) (micro (nth 2 now))) (setq high (+ high (/ low 65536)) low (% low 65536)) (when (< low 0) (setq high (1- high) low (+ low 65536))) (list high low micro))) (defun tdiary-read-username (url name) (let ((username (tdiary-passwd-cache-read-username url))) (or username (read-string (concat "User Name for '" name "': "))))) (defun tdiary-read-password (url name) (let ((password (tdiary-passwd-cache-read-password url))) (or password (read-passwd (concat "Password for '" name "': "))))) (defun tdiary-read-date (date) (while (not (string-match "[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]" (setq date (read-string "Date: " (or date (format-time-string "%Y%m%d" (tdiary-today))))))) nil) date) (defun tdiary-read-title (date) (read-string (concat "Title for " date ": ") tdiary-title)) (defun tdiary-read-mode (mode) (let ((default (caar tdiary-edit-mode-list))) (completing-read "Editing mode: " tdiary-edit-mode-list nil t (or mode default) nil default))) (defun tdiary-passwd-file-load () "Load password alist." (save-excursion (let ((buf (get-buffer-create "*tdiary-passwd-cache*"))) (when (and tdiary-passwd-file (file-readable-p tdiary-passwd-file)) (set-buffer buf) (insert-file-contents tdiary-passwd-file) (setq tdiary-passwd-cache (read buf))) (kill-buffer buf)))) (defun tdiary-passwd-file-save () "Save password alist. Dangerous!!!" (interactive) (save-excursion (let ((buf (get-buffer-create "*tdiary-passwd-cache*"))) (set-buffer buf) (erase-buffer) (prin1 tdiary-passwd-cache buf) (terpri buf) (when (and tdiary-passwd-file (file-writable-p tdiary-passwd-file)) (write-region (point-min) (point-max) tdiary-passwd-file) (set-file-modes tdiary-passwd-file tdiary-passwd-file-mode)) (kill-buffer buf)))) (defun tdiary-passwd-cache-clear (url) (setq tdiary-passwd-cache (remassoc url tdiary-passwd-cache))) (defun tdiary-passwd-cache-save (url user pass) (tdiary-passwd-cache-clear url) (add-to-list 'tdiary-passwd-cache (cons url (cons user (base64-encode-string pass))))) (defun tdiary-passwd-cache-read-username (url) (cadr (assoc url tdiary-passwd-cache))) (defun tdiary-passwd-cache-read-password (url) (let ((password (cddr (assoc url tdiary-passwd-cache)))) (and password (base64-decode-string password)))) (defun tdiary-post (mode date data) (let ((url (concat tdiary-diary-url tdiary-update-rb)) buf title user pass year month day post-data) (when (not (equal mode "edit")) (setq tdiary-edit-mode (setq mode (tdiary-read-mode mode))) (setq tdiary-date (setq date (tdiary-read-date date))) (setq tdiary-title (setq title (tdiary-read-title date)))) (setq user (tdiary-read-username url tdiary-diary-name)) (setq pass (tdiary-read-password url tdiary-diary-name)) (string-match "\\([0-9][0-9][0-9][0-9]\\)\\([0-9][0-9]\\)\\([0-9][0-9]\\)" date) (setq year (match-string 1 date) month (match-string 2 date) day (match-string 3 date)) (add-to-list 'post-data (cons "old" date)) (add-to-list 'post-data (cons "year" year)) (add-to-list 'post-data (cons "month" month)) (add-to-list 'post-data (cons "day" day)) (if tdiary-csrf-key (add-to-list 'post-data (cons "csrf_protection_key" tdiary-csrf-key))) (or (equal mode "edit") (add-to-list 'post-data (cons "title" (http-url-hexify-string title tdiary-coding-system)))) (add-to-list 'post-data (cons mode mode)) (and data (add-to-list 'post-data (cons "body" (http-url-hexify-string data tdiary-coding-system)))) (setq buf (http-fetch url 'post user pass post-data)) (if (bufferp buf) (save-excursion (tdiary-passwd-cache-save url user pass) (set-buffer buf) (decode-coding-region (point-min) (point-max) tdiary-coding-system) (goto-char (point-min)) buf) (tdiary-passwd-cache-clear url) (error "tDiary POST: %s - %s" (car buf) (cdr buf))))) (defun tdiary-post-text () (let* ((dirname (expand-file-name tdiary-diary-name (or tdiary-text-directory (expand-file-name "~/")))) (filename (expand-file-name (concat tdiary-date tdiary-text-suffix) dirname))) (unless (file-directory-p dirname) (make-directory dirname t) (set-file-modes dirname tdiary-text-directory-mode)) ;; If buffer-file-name is tdiary-text-directory/tdiary-diary-name/yyyymmdd.td ;; do nothing. (unless (equal filename buffer-file-name) (cond ((equal tdiary-edit-mode "replace") (write-region (point-min) (point-max) filename)) ((equal tdiary-edit-mode "append") (write-region (point-min) (point-max) filename t)))))) (defun tdiary-update () "Update diary." (interactive) (unless (and (eq (char-before (point-max)) ?\n) (eq (char-before (1- (point-max))) ?\n)) (save-excursion (goto-char (point-max)) (insert "\n"))) (tdiary-post tdiary-edit-mode tdiary-date (buffer-substring (point-min) (point-max))) (when tdiary-text-save-p (tdiary-post-text)) (if buffer-file-name (save-buffer) (set-buffer-modified-p nil)) (message "SUCCESS") (and (functionp tdiary-browser-function) (funcall tdiary-browser-function (concat tdiary-diary-url tdiary-index-rb "?date=" tdiary-date)))) (defun tdiary-do-replace-entity-ref (from to &optional str) (save-excursion (goto-char (point-min)) (if (stringp str) (progn (while (string-match from str) (setq str (replace-match to nil nil str))) str) (while (search-forward from nil t) (replace-match to nil nil))))) (defun tdiary-replace-entity-refs (&optional str) "Replace entity references. If STR is a string, replace entity references within the string. Otherwise replace all entity references within current buffer." (tdiary-do-replace-entity-ref "&" "&" (tdiary-do-replace-entity-ref "<" "<" (tdiary-do-replace-entity-ref ">" ">" (tdiary-do-replace-entity-ref """ "\"" str))))) ;(defun tdiary-read-mode (mode) ; (let ((default (caar tdiary-edit-mode-list))) ; (completing-read "Editing mode: " tdiary-edit-mode-list ; nil t (or mode default) nil default))) (defun tdiary-obsolete-check () ;; setting tdiary-diary-url in tdiary-init-file is obsolete. (when tdiary-diary-url (message "tdiary-diary-url is OBSOLETE. Use tdiary-diary-list instead of tdiary-diary-url.") (sit-for 5))) ;(defun tdiary-setup-diary-url (select-url) ; (interactive) ; (if (interactive-p) ; (setq select-url t)) (defun tdiary-setup-diary-url (select-url) ;; setting tdiary-diary-url in tdiary-init-file is obsolete. (tdiary-obsolete-check) (unless tdiary-diary-url (let* ((selected (car tdiary-diary-list)) (default (car selected))) (when select-url (setq selected (assoc (completing-read "Select SITE: " tdiary-diary-list nil t default nil default) tdiary-diary-list))) (setq tdiary-diary-name (nth 0 selected) tdiary-diary-url (nth 1 selected)) (and (eq (length selected) 4) (setq tdiary-index-rb (nth 2 selected) tdiary-update-rb (nth 3 selected)))))) (defun tdiary-new-or-replace (replacep select-url) (let (buf) (setq buf (generate-new-buffer "*tdiary tmp*")) (switch-to-buffer buf) (tdiary-mode) (setq tdiary-edit-mode "append") (let (start end body title csrf-key) (save-excursion (setq buf (tdiary-post "edit" tdiary-date nil)) (when (bufferp buf) (save-excursion (set-buffer buf) (if (re-search-forward "]+name=\"csrf_protection_key\" [^>]*value=\"\\([^>\"]*\\)\">" nil t nil) (setq csrf-key (match-string 1))) (re-search-forward "]+name=\"title\" [^>]+value=\"\\([^>\"]*\\)\">" nil t nil) (setq title (match-string 1)) (re-search-forward "" nil t nil) (setq end (match-beginning 0)) (setq body (buffer-substring start end)) ) (setq tdiary-csrf-key (and csrf-key (tdiary-replace-entity-refs csrf-key))) (when replacep (insert body) (setq tdiary-edit-mode "replace") (setq tdiary-title (tdiary-replace-entity-refs title)) (goto-char (point-min)) (tdiary-replace-entity-refs) (set-buffer-modified-p nil))))))) (defun tdiary-new (&optional select-url) (interactive "P") (tdiary-new-or-replace nil select-url)) (defun tdiary-replace (&optional select-url) (interactive "P") (tdiary-new-or-replace t select-url)) (defvar tdiary-mode-map (make-sparse-keymap) "Set up keymap for tdiary-mode. If you want to set up your own key bindings, use `tdiary-mode-hook'.") (define-key tdiary-mode-map [(control return)] 'tdiary-complete-plugin) (define-key tdiary-mode-map "\C-c\C-c" 'tdiary-update) (push (cons 'tdiary-date tdiary-mode-map) minor-mode-map-alist) (if (boundp 'minor-mode-list) (push 'tdiary-mode minor-mode-list)) (push '(tdiary-date " tDiary") minor-mode-alist) (defun tdiary-load-init-file () "Load init file." (let ((init-file (expand-file-name tdiary-init-file))) (when (file-readable-p init-file) (load init-file t t)))) (defun tdiary-make-temp-file-name () (let ((tmpdir (expand-file-name tdiary-diary-name (expand-file-name (user-login-name) temporary-file-directory)))) (unless (file-directory-p tmpdir) (make-directory tmpdir t) (set-file-modes tmpdir tdiary-text-directory-mode)) (expand-file-name tdiary-date tmpdir))) (defun tdiary-html-mode-init () "Initialize tDiary for default style" (tdiary-tempo-define (append tdiary-plugin-initial-definition tdiary-plugin-definition)) (tempo-use-tag-list 'tdiary-tempo-tags tdiary-completion-finder)) (defun tdiary-rd-mode-init () "Initialize tDiary for RD style" ) (defun tdiary-mode () "tDiary editing mode. The value of `tdiary-style-mode' will be used as actual major mode. \\{tdiary-mode-map}" (interactive) (funcall tdiary-style-mode) (and (featurep 'font-lock) (font-lock-set-defaults)) (tdiary-mode-setup)) (defun tdiary-mode-setup () "Set tDiary mode up." (interactive) (make-local-variable 'require-final-newline) (make-local-variable 'tdiary-date) (make-local-variable 'tdiary-title) (make-local-variable 'tdiary-edit-mode) (make-local-variable 'tdiary-diary-url) (make-local-variable 'tdiary-index-rb) (make-local-variable 'tdiary-update-rb) (make-local-variable 'tdiary-csrf-key) (setq require-final-newline t indent-tabs-mode nil tdiary-edit-mode "replace" tdiary-date (format-time-string "%Y%m%d" (tdiary-today))) (tdiary-load-init-file) (tdiary-setup-diary-url (if (boundp 'select-url) select-url t)) (set-buffer-file-coding-system tdiary-coding-system) (or tdiary-passwd-cache (tdiary-passwd-file-load)) (if buffer-file-name (let ((buf-name (file-name-nondirectory buffer-file-name))) (when (string-match "\\([0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]\\)" buf-name) (setq tdiary-date (match-string 1 buf-name)))) (setq tdiary-date (tdiary-read-date nil)) (if tdiary-text-save-p (set-visited-file-name (tdiary-make-temp-file-name)) (unless (string= (buffer-name) tdiary-date) (rename-buffer tdiary-date t)))) (let ((init (intern (concat "tdiary-" (symbol-name tdiary-style-mode) "-init")))) (if (fboundp init) (funcall init))) (run-hooks 'tdiary-mode-hook)) (defun tdiary-mode-toggle (&optional arg) (interactive "P") (let ((in-tdiary (and (boundp 'tdiary-date) tdiary-date))) (cond ((not arg) (setq arg (not in-tdiary))) ((or (eq arg '-) (and (numberp arg) (< arg 0))) (setq arg nil))) (cond (arg (tdiary-mode-setup)) (in-tdiary (setq tdiary-date nil))))) (provide 'tdiary-mode) ;;; tdiary-mode.el ends here tdiary-contrib-5.0.8/util/tdiary-vim/000077500000000000000000000000001325711763500175325ustar00rootroot00000000000000tdiary-contrib-5.0.8/util/tdiary-vim/ChangeLog000066400000000000000000000015171325711763500213100ustar00rootroot000000000000002005-07-29 Fri UECHI Yasumasa * echo site name and url when select a diary site. * allow to set update script each diary. * use CSRF protection key if exits. 2005-07-28 Thu UECHI Yasumasa * send referer when update a diary. 2004-11-08 Mon UECHI Yasumasa * change substitution order of character entity in TdiaryReplace(). thanx やえもん. 2004-02-25 Wed UECHI Yasumasa * support TrackBack 2004-02-19 Thu UECHI Yasumasa * quote argument of curl's -u option. 2004-02-17 Tue UECHI Yasumasa * use .netrc when g:tdiary_use_netrc = 1 2004-02-16 Mon UECHI Yasumasa * change editing mode, date, title in diary buffer. 2004-02-13 Fri UECHI Yasumasa * commit to CVS repository tdiary-contrib-5.0.8/util/tdiary-vim/README000066400000000000000000000055321325711763500204170ustar00rootroot00000000000000= tdiary.vim tdiary.vim は vim から日記を更新するための vimスクリプトです。 == 必要なもの tdiary.vim を使用するには以下のものが必要です。 * cURL - コマンドラインから http や ftp で通信するためのツール * iconv ライブラリ * vim (+iconv でコンパイルしたもの) cURL は (()) から入手できます。 == インストール tdiary.vim を $HOME/.vim/plugin ディレクトリにコピーするだけです。 == 設定 $HOME/.vimrc で次のように tDiary サイトの URL を設定します。 let tdiary_site1_url = "http://www.example.com/tdiary/" 最低限必要な設定はこれだけですが、複数の日記を更新するなら以下のような設定を追加してください。 let tdiary_site1_name = "ほげほげ日記" let tdiary_site2_url = "http://www.example.net/tdiary/" let tdiary_site2_name = "foobar日記" tDiary を設置するときに update.rb を update.cgi 等に変更している場合は以下も追加してください。 let tdiary_site1_updatescript = "update.cgi" let tdiary_site2_updatescript = "update.cgi" == パスワードの保存 cURL は $HOME/.netrc を読めるので、パスワードの保存にその機能を使います。ユーザ名とパスワードを .netrc に保存し、$HOME/.vimrc に let tdiary_use_netrc = 1 と設定すると有効になります。 == 使い方 tdiary.vim では次のコマンドが使えます。 * :TDiaryNew - 日記を書くための空のバッファを開きます * :TDiaryReplace - 指定した日付の日記を読み込んだバッファを開きます * :TDiaryUpdate - 日記を更新します * :TDiarySelect - 更新する tDiary サイトを選択するためのバッファを開きます * :TDiaryTrackback - TrackBack の excerpt を編修するためのバッファを開きます === 日記に追記 :TDiaryNew すると日付が YYYYMMDD 形式で表示されますので、適宜修正してリターンキーを押してください。日記を書いたら :TDiaryUpdate で更新してください。 === 日記を修正 :TDiaryReplace すると日付が YYYYMMDD 形式で表示されますので、修正したい日付に直してリターンキーを押してください。指定した日の日記が読み込まれます。修正後に :TDiaryUpdate で更新してください。 === tDiary サイトの選択 :TDiarySelect すると日記の一覧が表示されます。日記にカーソルを合わせてリターンキーを押すことで書き込み先が切り替わります。 === TrackBack 日記の編修バッファに表示されている TrackBackURL: に TrackBack 先の URL を記 入することで TrackBack が送られます。excerpt を編修する場合は :TDiaryTrackback することで編修用のバッファが開きます。 tdiary-contrib-5.0.8/util/tdiary-vim/tdiary.vim000066400000000000000000000174321325711763500215520ustar00rootroot00000000000000" Copyright (C) 2004 UECHI Yasumasa " Author: UECHI Yasumasa " $Revision: 1.8 $ " This program is free software; you can redistribute it and/or " modify it under the terms of the GNU General Public License as " published by the Free Software Foundation; either version 2, or (at " your option) any later version. " This program is distributed in the hope that it will be useful, but " WITHOUT ANY WARRANTY; without even the implied warranty of " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU " General Public License for more details. " You should have received a copy of the GNU General Public License " along with this program; see the file COPYING. If not, write to the " Free Software Foundation, Inc., 59 Temple Place - Suite 330, " Boston, MA 02111-1307, USA. if !exists("g:tdiary_site1_url") finish endif command! -nargs=0 TDiaryNew call TDiaryNew() command! -nargs=0 TDiaryReplace call TDiaryReplace() command! -nargs=0 TDiaryUpdate call TDiaryUpdate() command! -nargs=0 TDiarySelect call TDiarySelect() command! -nargs=0 TDiaryTrackback call EditTrackBackExcerpt() let s:curl_cmd = "curl" let s:user = '' function! s:TDiaryNew() call s:CreateBuffer("append") execute ":" . (s:body_start + 1) normal dG redraw! endfunction function! s:TDiaryReplace() call s:CreateBuffer("replace") let save_pat = @/ let @/ = 'input.\+name="title"[^>]\+>' normal ggn let title = substitute(getline("."), '.\+value="\(.*\)".\+', '\1', '') let @/ = 'textarea \+name="body"[^>]\+>' execute ":" . s:body_start normal dndf> let @/ = '/g silent! %s/</" normal G redraw! let @/ = save_pat endfunction function! s:TDiaryUpdate() " move to _tdiary_ buffer let n = bufwinnr(substitute(bufname("%"), "_.\\+_", "_tdiary_", "")) execute "normal " . n . "\w" " set parameters let data = s:SetParams() " set body & csrf protection key let data = data . "&body=" . s:MultiLineURLencode(s:body_start) let data = data . s:csrf_protection_key " debug mode if exists("g:tdiary_vim_debug") && g:tdiary_vim_debug call append("$", data) return endif " redirect data to tmpfile let tmpfile = tempname() execute "redir! > " . tmpfile silent echo data redir END " update diary let result = system(s:curl_cmd . s:user . " -d @" . tmpfile . " -e ". s:tdiary_update_url . " " . s:tdiary_update_url) call delete(tmpfile) redraw! if match(result, 'Wait or.\+Click here') != -1 echo "SUCCESS" else echo result endif endfunction function! s:TDiarySelect() split tDiary_select set buftype=nofile set nobuflisted set noswapfile let i = 1 while exists("g:tdiary_site{i}_url") let site_name = '' if exists("g:tdiary_site{i}_name") let site_name = g:tdiary_site{i}_name . " " endif call append(i - 1, site_name . g:tdiary_site{i}_url) let i = i + 1 endwhile normal gg nnoremap :call SetURL() endfunction function! s:EditTrackBackExcerpt() let save_line = line(".") normal gg call search("^TrackBackURL:") let tb_url = s:ParamValue(getline(".")) let tb_url = input("TrackBackURL: ", tb_url) delete call append(line(".") - 1, "TrackBackURL: " . tb_url) execute ":" . save_line let tb_bufname = substitute(bufname("%"), "_tdiary_", "_trackback_", "") split execute "normal \w" execute "edit " . tb_bufname set buftype=nofile set noswapfile set bufhidden=hide endfunction function! s:SetParams() let data = '' let i = 1 while i < s:body_start let l = getline(i) let r = s:ParamValue(l) if l =~ "^Editing mode" let mode = r let data = data . "&" . r . "=" . r elseif l =~ "^Date:" let data = data . s:Date2PostDate(r, mode) elseif l =~ "^Title:" let data = data . "&title=" . s:URLencode(r) elseif l =~ "^TrackBackURL:" if r != "" let data = data . "&plugin_tb_url=" . s:URLencode(r) let data = data . s:TrackBackExcerpt() endif endif let i = i + 1 endwhile return data endfunction function! s:ParamValue(str) let r = substitute(a:str, '^[^:]\+ *: *\(.*\)', '\1', '') let r = substitute(r, ' *$', '', '') return r endfunction function! s:TrackBackExcerpt() let data = "&plugin_tb_excerpt=" let n = bufwinnr(substitute(bufname("%"), "_.\\+_", "_trackback_", "")) if n > 0 execute "normal " . n . "\w" let data = data . s:MultiLineURLencode(1) execute "normal \p" endif return data endfunction function! s:MultiLineURLencode(start_line) let i = a:start_line let lastline = line("$") let data = "" while i <= lastline let data = data . s:URLencode(getline(i) . "\r\n") let i = i + 1 endwhile return data endfunction function! s:SetURL(...) if a:0 == 0 let i = line(".") else let i = a:1 endif let s:tdiary_url = substitute(g:tdiary_site{i}_url, "/\\+$", "", "") . "/" if exists("g:tdiary_site{i}_updatescript") let update_script = g:tdiary_site{i}_updatescript elseif exists("g:tdiary_update_script_name") let update_script = g:tdiary_update_script_name else let update_script = "update.rb" endif let s:tdiary_update_url = s:tdiary_url . update_script let s:user = "" call s:SetUser() "echo selected site let site_name = "" if exists("g:tdiary_site{i}_name") let site_name = g:tdiary_site{i}_name endif echo site_name s:tdiary_url if a:0 == 0 close endif endfunction function! s:SetUser() if exists("g:tdiary_use_netrc") && g:tdiary_use_netrc let s:user = " --netrc " elseif s:user == '' let s:user = input("User Name: ") let password = inputsecret("Password: ") if s:user != '' let s:user = " -u '" . s:user . ":" . password . "' " endif endif endfunction function! s:CreateBuffer(mode) if !exists("s:tdiary_update_url") call s:SetURL(1) endif let date = input("Date: ", strftime("%Y%m%d", localtime())) execute "edit _tdiary_" . date set buftype=nofile set noswapfile set bufhidden=hide "set fileformat=dos let s:body_start = 0 call append(s:body_start, "Editing mode (append or replace): " . a:mode) let s:body_start = s:body_start + 1 call append(s:body_start, "TrackBackURL: ") let s:body_start = s:body_start + 1 call append(s:body_start, "Date: " . date) let s:body_start = s:body_start + 1 call append(s:body_start, "Title: ") let s:body_start = s:body_start + 1 let s:body_start = s:body_start + 1 let data = "" if a:mode == "replace" let data = ' -d "' let data = data . s:Date2PostDate(date, a:mode) let data = data . '&edit=edit" ' endif execute 'r !' . s:curl_cmd . ' -s ' . s:user . data . s:tdiary_update_url normal gg let s:csrf_protection_key = "" if search('input.\+name="csrf_protection_key"') > 0 silent! s/"/\"/g silent! s/>/>/g silent! s/</