「ADD」を含む日記 RSS

はてなキーワード: ADDとは

2009-05-31

はてなハイク問題点(とその改善案等)のまとめ

はてなアイデアを眺めつつ、主観で分類してまとめてみます。

比較的問題の全体に対する影響度が低い「改善案」だと私が思ったものは、省いている場合があります。

細かい改善提案などについても、いつかまとめようと思います。(参考:http://i.hatena.ne.jp/t/UI%E6%94%B9%E5%96%84

 

1.動作不具合と見込まれるもの

 1.1.半角スペースが含まれるキーワードページが正常に表示されない

    「iPod touch」というキーワードアクセスしようとすると、「iPod」に飛びます。

    発生するものと、発生しないものがあるようです。アイデアにて検討中ステータスです。

    関連アイデアhttp://i.hatena.ne.jp/idea/24207

 

 1.2.URLキーワードに関するもの

  1.2.1.URLキーワードは、キーワード表示が文字化けすることがある

      主題の通りです。

      関連アイデアhttp://i.hatena.ne.jp/idea/24215

 

  1.2.2.URLキーワードが、タイトル名で検索したときヒットしない

      主題の通りです。

      関連アイデアhttp://i.hatena.ne.jp/idea/24509

               http://i.hatena.ne.jp/idea/18718

 

 1.3.お絵かきモード時、キャンパスリサイズが制御不能になることがある

    「ウィンドウうにょーん現象」として、多くのお絵かきハイクユーザを苦しめている不具合です。

    「絵を描く」→「狭くなってきたので下に枠を広げる」→「絵の続きを描こうとする」

    →「下の枠が上に引きずられてウィンドウが小さくなる」→「絵の下半分が削られる」

    関連アイデアhttp://i.hatena.ne.jp/idea/18837

             http://i.hatena.ne.jp/idea/20483

 

2.不具合ではないが、解決されるべきと考えられるもの

 2.1.はてなmobile経由ではエントリ削除できない

    mobileからアクセスしているユーザの「誤エントリを消せない」という戸惑いの声がたまに見られます。

    アイデアにて検討中ステータスです。

    関連アイデアhttp://i.hatena.ne.jp/idea/18629

             http://i.hatena.ne.jp/idea/21943

 

 2.2.過去エントリを遡って閲覧することが困難、検索もできない

    エントリ時系列どおりに閲覧することが現在GUIでは簡単にできません。

    関連アイデアhttp://i.hatena.ne.jp/idea/18807

             http://i.hatena.ne.jp/idea/18469

             http://i.hatena.ne.jp/idea/20578

 

 2.3.はてな記法の大半が使用できない

    主題の通りです。

    関連アイデアhttp://i.hatena.ne.jp/idea/21587

             http://i.hatena.ne.jp/idea/18644

             http://i.hatena.ne.jp/idea/23919

             http://i.hatena.ne.jp/idea/21089

 

 2.4.PC版とモバイル版で各種タブの表示位置、リンク先が不統一

    主題の通りです。他にも、タブの表示位置などは不統一な点が多くあります。

    関連アイデアhttp://i.hatena.ne.jp/idea/22471

             http://i.hatena.ne.jp/idea/20671

             http://i.hatena.ne.jp/idea/19119

 

 2.5.Fanが大量にいるユーザの、Fans表示の量が多すぎる

    省略表示されないので、Fanが大量にいるユーザのEntriesページが、

    各ユーザアイコン読み込みで非常に重くなることがあります。

    関連アイデアhttp://i.hatena.ne.jp/idea/21356

 

 2.6.エントリ欄の使い方がわかり難い

    入力欄に説明も何もないため、初めてハイクを閲覧するユーザがRecent Entriesを見たときに、

    キーワード指定の意味が判らないことがあります。

    入力欄に説明を書き、フォームをフォーカスすると文字列が消えるなどのサポートが必要と見込まれます。

    参考ページ:http://h.hatena.ne.jp/invite

    関連アイデアhttp://i.hatena.ne.jp/idea/24335

 

3.不具合ではないが、検討してみるべきと考えられるもの

 3.1.閲覧環境の整理に関するもの

  3.1.1.見たくないキーワードがある

      興味のないキーワードや、見たくないキーワード等を非表示にしたいという要望です。

      Fx+GreaseMonkeyで実現されていますが、mobileや他ブラウザでは適用されませんし、

      基本機能としての実装検討が期待されます。

      関連アイデアhttp://i.hatena.ne.jp/idea/21160

 

  3.1.2.見たくないユーザエントリがある

      詳細は「3.1.1.見たくないキーワードがある」と同様です。

      関連アイデアhttp://i.hatena.ne.jp/idea/24495

 

 3.2.ユーザ間のコミュニケーションに関するもの

  3.2.1.お気に入り登録を制御したい

      自分に対するお気に入り登録を「ストーキング」されていると感じる場合があるようです。

      登録された際に拒否できるようにするなどの対応が考えられます。

      関連アイデアhttp://i.hatena.ne.jp/idea/21300

               http://i.hatena.ne.jp/idea/21391

               http://i.hatena.ne.jp/idea/23918

               http://i.hatena.ne.jp/idea/21179

               http://i.hatena.ne.jp/idea/18295

 

  3.2.2.Replyを制御したい

      「3.2.1.お気に入り登録を制御したい」と方向性は同じです。

      執拗Replyされるなどの行為が「ストーキング」されていると感じる場合があるようです。

      特定ユーザからのReplyを拒否できるようにするなどの対応が考えられます。

      関連アイデアhttp://i.hatena.ne.jp/idea/23762

               http://i.hatena.ne.jp/idea/19451

 

 3.3.ユーザお気に入り指定した際、対象ユーザのAboutがお気に入りキーワード扱いになる。

    仕様不具合か不明です。少々、不自然な動作であると考えられます。

    関連アイデアhttp://i.hatena.ne.jp/idea/20725

 

 3.4.Favoriteページに自分エントリが表示される

    仕様不具合か不明です。少々、不自然な動作であると考えられます。

    関連アイデアhttp://i.hatena.ne.jp/idea/23776

 

 3.4.関連キーワード文字列長制限がない

    本来キーワードとして指定できる文字列は「255バイトまで」となっていて、

    エントリ時にキーワードを指定する場合は、超過分はカットされます。

    しかし、関連キーワードキーワードを追加する際は、この制限が適用されません。

    結果、「関連キーワードに長大なキーワードAddする」→「そのリンククリック」→

    「長大なキーワードページでエントリ」とすることで、長大なキーワードを指定してエントリすることができます。

    迷惑行為に利用することができる点で問題視されます。

    関連アイデアhttp://i.hatena.ne.jp/idea/20722

             http://i.hatena.ne.jp/idea/20545

 

 3.5.エントリに含められる動画の数に制限がない

    画像過去にある昆虫画像が大量に張られる事態に際し、1エントリには3枚までとなっています。

    しかし、動画の数には制限がなく、迷惑行為に利用することができる点で問題視されます。

    関連アイデアhttp://i.hatena.ne.jp/idea/20981

 

4.現在の利用状況に関連するもの

 4.1.RecentEntriesページに関するもの

  4.1.1.過度長文・動画画像の連投によってRecentEntriesが使い辛くなる

      RecentEntriesを中心に閲覧しているユーザはかなり多いようです。

      このため、一部のユーザ(&BOT)が大量にエントリをすると、そういったユーザにとって

      ハイクの閲覧が困難・視界に入るうものの多様性の喪失となり、不満を抱く原因になるようです。

      非表示機能の充実、RecentEntriesをTOPページにしない、などの対応が考えられます。

      関連アイデアhttp://i.hatena.ne.jp/idea/21136

               http://i.hatena.ne.jp/idea/19817

 

 

疲れたので一旦ここまで……気が向いたら思いつき次第追記します。

2009-05-15

http://anond.hatelabo.jp/20090515175109

Bed bed = new Bed();

bed.add(taro);

bed.add(hanako);

room.setLightSwitch(SWITCH_STATUS_OFF);

return !taro.isCherry();

2009-05-14

IIS+ASP.NET+SQLite

自分のための覚え書き。知ってる人からすれば全然当たり前のことかも…

IIS上で、Visual Studio 2008で開発したASP.NETWebサイトを動かす時に、SQLiteを使う方法

IISの動作しているマシンに「SQLite for ADO.NET 2.0」をインストール

それだけで良いと思ったけれど、以下のエラーが発生。

ArgumentException: 要求された .Net Framework データ プロバイダが見つかりません。これは、インストールされていない可能性があります。

いろいろ調べたら、手動でmachine.configを書き換える必要があるみたい。

そこで、machine.configに以下の行を追加。

	<system.data&gt;
		<DbProviderFactories&gt;
			<add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".Net Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite, Version=1.0.61.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139" /&gt;
		</DbProviderFactories&gt;
	</system.data&gt;

無事に動くようになりました。

2009-03-24

http://anond.hatelabo.jp/20090324005857

img_passがimg_pathの間違いなんじゃないか、と思う以外は別にそんなに分かりにくいと思わないけどなぁ。

俺も同じようにすると思う。

Thumbnail, thumbnail, thumbnailsが紛らわしいと思うなら、

thumb_array = array.new();
while(img_path = gets())
  thumb = Thumbnail.new(img_path)
  thumb_array.add(thumb)
end

とすればよろし。

名付け方

ギークではないし、どちらかといえば下手なのですが。

http://anond.hatelabo.jp/20090324005857

  1. インスタンス名をどうするか
  2. 生成したインスタンスを格納する配列名前をどうするか
    • その集合を現す名前があるはず。

例えば、サムネイルを作る makeThumbnails という関数なら、

result = array.new()
while(src = gets())
    result.add(Thumbnail.new(src))
end
return result

かもしれないし、例えばサムネイルを一覧表示時のアイコンに使うなら、index_iconsとか、gif化してアニメーションするならframesとかつけるかも。

ちなみに、perlなら $frame = shift @frame だ。

whileの内側だけで使う一時変数なら名前は短く一文字とか、他にも処理があるならtmbとか、thumbとかにするかも。

2009-03-11

[][][][][][]

Deploy Merb, Sinatra, or any Rack App to Heroku

http://blog.heroku.com/archives/2009/3/5/32_deploy_merb_sinatra_or_any_rack_app_to_heroku/

http://heroku.com/pages/quickstart

http://heroku.com/docs

http://heroku.com/

HerokuをGit経由で使ってみる

http://d.hatena.ne.jp/aki-s-119/20081110/1226335713

http://github.com/guides/using-git-and-github-for-the-windows-for-newbies

Windows から Git を使う方法

http://d.hatena.ne.jp/kusakari/20080715/1216091060

msysgit - Google Code

http://code.google.com/p/msysgit/

PuTTYssh2プロトコルを使ってssh接続

http://net-newbie.com/putty.html

&gt;heroku help
=== General Commands

 help                         # show this usage

 list                         # list your apps
 create [<name&gt;]              # create a new app

 keys                         # show your user's public keys
 keys:add [<path to keyfile&gt;] # add a public key
 keys:remove <keyname&gt;        # remove a key by name (user@host)
 keys:clear                   # remove all keys

=== App Commands (execute inside a checkout directory)

 info                         # show app info, like web url and git repo
 open                         # open the app in a web browser
 rename <newname&gt;             # rename the app

 sharing:add <email&gt;          # add a collaborator
 sharing:remove <email&gt;       # remove a collaborator

 domains:add <domain&gt;         # add a custom domain name
 domains:remove <domain&gt;      # remove a custom domain name
 domains:clear                # remove all custom domains

 rake <command&gt;               # remotely execute a rake command
 console <command&gt;            # remotely execute a single console command
 console                      # start an interactive console to the remote

 restart                      # restart app servers
 logs                         # fetch recent log output for debugging
 logs:cron                    # fetch cron log output

 bundles                      # list bundles for the app
 bundles:capture [<bundle&gt;]   # capture a bundle of the app's code and dat
 bundles:download             # download most recent app bundle as a tarba
 bundles:download <bundle&gt;    # download the named bundle
 bundles:animate <bundle&gt;     # animate a bundle into a new app
 bundles:destroy <bundle&gt;     # destroy the named bundle

 destroy                      # destroy the app permanently

=== Example story:

 rails myapp
 cd myapp
 (...make edits...)
 git init
 git add .
 git commit -m "my new app"
 heroku create myapp
 git remote add heroku git@heroku.com:myapp.git
 git push heroku master

2009-03-03

portupgrade -f '&lt;2011-06-22' 古いのを新しく
portupgrade -f '&gt;2011-08-08' 新しいのをもう一度
portupgrade -x editors/openoffice-3
vi /usr/local/libdata/pkgconfig/libpanelapplet-2.0.pc
Requires: add libgnomeui-2.0
portupgrade -x japanese/im-ja
portupgrade -x java/diablo-jdk16

2009-01-28

ソースコードバージョン管理されてて、誰がどこを変更したかなんヒストリー見ればわかるんだからコメント行に「add by」とか書くな邪魔だから

って主張は、まだ現代IT業界では受け入れてくれませんよねぇ。

2009-01-20

そういえばinheritなんてものがあるのを忘れてた。

// ==UserScript==
// @name           add style
// @namespace      http://anond.hatelabo.jp/
// @include        http://anond.hatelabo.jp/*
// ==/UserScript==
GM_addStyle(
	"font{color:inherit;font-size:inherit}"+
	"u, s, strike{text-decoration:inherit}"+
	"b{font-weight:inherit}"+
	".section{max-height:80em;overflow-y:auto}"
);

firefoxオンリーだそうで http://anond.hatelabo.jp/20090120114819 ユーザースタイルシート的には

font{color:inherit;font-size:inherit}
u, s, strike{text-decoration:inherit}
b{font-weight:inherit}
.section{max-height:80em;overflow-y:auto}

かな?

その他は http://anond.hatelabo.jp/20090120094216 の辺で。

それでストーカーするには Web::Scraperでその辺のタグの有無をチェックして DBIx::Simple で記録すればよいかな?

ついでに WWW::Mechanize::Plugin::Web::Scraper で封じ込めという手もありそう。

http://anond.hatelabo.jp/20090120114819

追加でこんなかんじにした

// ==UserScript==
// @name           add style
// @namespace      http://anond.hatelabo.jp/
// @include        http://anond.hatelabo.jp/*
// ==/UserScript==
GM_addStyle(
	"font{color:black;font-size: 100%}"+
	"s, strike{text-decoration:none}"+
	".section{max-height:80em;overflow-y:auto}"
);

あ、GM_addStyle使ってるから動かないのかな。

http://d.hatena.ne.jp/os0x/20080109/1199867276 が参考になるかも。

それともスタイルシート解釈の違いなのか。なんにせよIEはイジリ概がない。

strike{

text-decoration:none;

}

s{

text-decoration:none;

}

font{

color:black;font-size:100%;

}

これだけあればわりと快適。

// ==UserScript==

// @name add style

// @namespace http://anond.hatelabo.jp/

// @include http://anond.hatelabo.jp/*

// ==/UserScript==

GM_addStyle(

"font{color:black;font-size:100%}"+

"s, strike{text-decoration:none}"

);

これは自分環境だと使えなかったorz

そろそろ前回記録更新か?

前回は何日くらい活動してたっけ?

タグ遊びの人、さしずめタグキディさん、寝てますか?

ここまでひつこいとストーキングしたくなる。

まずは張っとく


あと、自分のぐりもん

// ==UserScript==
// @name           add style
// @namespace      http://anond.hatelabo.jp/
// @include        http://anond.hatelabo.jp/*
// ==/UserScript==
GM_addStyle(
	"font{color:black;font-size:100%}"+
	"s, strike{text-decoration:none}"
);

IEは「ユーザースタイルシートのススメ - Personnel」を参考に、

#hatena-anond font{color:black;font-size:100%}
#hatena-anond s, strike{text-decoration:none}
#hatena-anond center{text-align:left}

ってユーザースタイルシートに書いておけばよいのかな。

って思ったけど、センタリングフォントサイズが効かない。なんでだろ。

2008-10-19

ADDかも…と最近気づいた

教えてくれた方、ありがとうございました

小学校の頃、自分の「忘れ物カード」と他の人のとを比較して、なぜわたしはこんなにいっぱい忘れ物しちゃうんだろうと思ったり、恥ずかしくて悲しい思いをした。

きっと他の人に、私は「できない人・ダメな人」と(今も)おもわれていたにちがいない。

でも、今その理由がわかったって、どうにもならない。わたしは努力しなきゃいけない

それにしてもわたしの性格のほとんどがADDのと合致してるなんて、なんだかこわい。よくあたるうらないみたい。

とりあえず病院へ行って、ほんとうにADDなのか診てもらわなきゃ。

わたしは、自分の好きなように生きたい。(他人に迷惑をかけないように)

2008-10-18

http://anond.hatelabo.jp/20081018072817 の続きだよ

これでおしまいだよ

elisp

sangels.el
(require 'cl)				; for cl-seq

(defvar sangels-movies-dir nil)
(defvar sangels-player "c:/Program Files/GRETECH/GomPlayer/GOM.exe")
(defvar sangels-sort-by 'sangels-sort-by-rate)
(defvar sangels-rate-file "~/.emacs.d/.sangels/rate")
(defvar sangels-buffer "*sangels*")
(defvar sangels-thumbnail "00_thumbnail.jpg")
(defvar sangels-m3u "00_movies.m3u")
(defface sangels-name '((t (:family "fixed" :weight bold :height 3.0)))
  "")
(defface sangels-rate '((t (:family "fixed" :weight bold :height 1.5)))
  "")
(defvar sangels-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map "n" 'next-line)
    (define-key map "p" 'previous-line)
    (define-key map (kbd "RET") 'sangels-select)
    (define-key map (kbd "SPC") 'sangels-select)
    (define-key map "q" 'sangels-quit)
    (define-key map "+" 'sangels-rate-plus)
    (define-key map "-" 'sangels-rate-minus)
    map))
(defvar sangels-mode-hook nil)
(defvar sangels-highlight-overlay nil)
(defvar sangels-rate-alist nil)

(defconst sangels-rate-max 6)

(defun sangels-insert-movies ()
  (save-excursion
    (let* ((inhibit-read-only t)
           (files (remove-if-not
                   (lambda (x)
                     (and (not (member (file-name-nondirectory x) '("." "..")))
                          (file-directory-p x)
                          (member sangels-thumbnail (directory-files x))))
                   (directory-files sangels-movies-dir t)))
           (ids (mapcar 'file-name-nondirectory files)))
      (erase-buffer)
      (setq ids (sangels-sort-ids ids))
      (dolist (id ids)
        (let ((file (expand-file-name id sangels-movies-dir))
              (pos (point)))
          (insert-image-file (expand-file-name sangels-thumbnail file))
          (end-of-line)
          (insert (propertize (format "%-15s " id)
                              'face 'sangels-name))
          (sangels-insert-rate id)
          (insert "\n")
          (put-text-property pos (point) 'sangels-id id))))))

(defun sangels-sort-by-name (a b)
  (string< a b))

(defun sangels-sort-by-rate (a b)
  (or (> (sangels-rate a) (sangels-rate b))
      (sangels-sort-by-name a b)))

(defun sangels-sort-ids (ids)
  (sort ids
        (or sangels-sort-by
            'sangels-sort-by-name)))
(defun sangels-insert-rate (id)
  (let ((rate (sangels-rate id)))
    (insert (propertize (concat
                         (make-string rate ?★)
                         (make-string (- sangels-rate-max rate) ?☆))
                        'sangels-rate t
                        'face 'sangels-rate))))

(defun sangels-current-id ()
  (get-text-property (point) 'sangels-id))

(defun sangels-play-movie (movie)
  (let ((explicit-shell-file-name "cmdproxy")
        (shell-file-name "cmdproxy"))
    (apply
     'call-process-shell-command
     "start" nil "*tmp*" nil
     (mapcar (lambda (x) (concat "\"" x "\""))
             (list sangels-player
                   (unix-to-dos-filename movie))))))

(defun sangels-select ()
  (interactive)
  (let ((id (sangels-current-id)))
    (when id
      (sangels-play-movie (expand-file-name
                           sangels-m3u
                           (expand-file-name id sangels-movies-dir))))))

(defun sangels-quit ()
  (interactive)
  (kill-buffer sangels-buffer))

(defun sangels-rate (id)
  (or (cdr (assoc id sangels-rate-alist)) (/ sangels-rate-max 2)))

(defun sangels-rate-save ()
  (interactive)
  (let ((dir (file-name-directory sangels-rate-file)))
    (unless (file-exists-p dir)
      (make-directory dir t)))
  (with-temp-file sangels-rate-file
    (insert (pp-to-string sangels-rate-alist))))

(defun sangels-rate-load ()
  (interactive)
  (when (file-exists-p sangels-rate-file)
    (with-temp-buffer
      (insert-file-contents sangels-rate-file)
      (goto-char (point-min))
      (setq sangels-rate-alist (read (current-buffer))))))

(defun sangels-rate-plus (&amp;optional n)
  (interactive "p")
  (setq n (or n 1))
  (let* ((id (sangels-current-id))
         (cell (assoc id sangels-rate-alist)))
    (unless cell
      (setq cell (cons id (sangels-rate id)))
      (setq sangels-rate-alist (cons cell sangels-rate-alist)))
    (setcdr cell (+ (cdr cell) n))
    (save-excursion
      (let ((inhibit-read-only t))
        (beginning-of-line)
        (goto-char (next-single-property-change (point) 'sangels-rate))
        (delete-region (point)
                       (next-single-property-change (point) 'sangels-rate))
        (sangels-insert-rate id)))
    (sangels-rate-save)))

(defun sangels-rate-minus (&amp;optional n)
  (interactive "p")
  (setq n (or n -1))
  (sangels-rate-plus (- n)))

(defun sangels-post-command-hook ()
  (save-excursion
    (move-overlay
     sangels-highlight-overlay
     (progn
       (move-beginning-of-line 1)
       (point))
     (progn
       (move-end-of-line 1)
       (forward-line)
       (point))
     (current-buffer))))

(defun sangels-mode ()
  (interactive)
  (kill-all-local-variables)
  (use-local-map sangels-mode-map)
  (setq sangels-highlight-overlay (make-overlay 0 0))
  (overlay-put sangels-highlight-overlay 'face 'highlight)
  (overlay-put sangels-highlight-overlay 'evaporate t)
  (make-local-variable 'post-command-hook)
  (add-hook 'post-command-hook 'sangels-post-command-hook nil t)
  (setq major-mode 'sangels-mode)
  (setq mode-name "Sangels")
  (run-mode-hooks 'sangels-mode-hook)
  (set-buffer-modified-p nil)
  (setq buffer-read-only t))

(defun sangels (&amp;optional arg)
  (interactive "P")
  (when (or arg (not sangels-movies-dir))
    (setq sangels-movies-dir (read-directory-name "movies dir: ")))
  (sangels-rate-load)
  (switch-to-buffer (get-buffer-create sangels-buffer))
  (sangels-insert-movies)
  (sangels-mode))

(provide 'sangels)

real street angels から mechanize を使って動画を取ってきてEmacsで見てみるよ

せっかく書いたから匿名でのせてみるよ

使い方は

  • 動画を取ってきたいよ
    • config.yamlユーザとかを設定するよ
    • ids.txt に取ってきたいIDを書くよ
    • sangels.bat を実行するよ
  • Emacs動画を見たいよ
    • sangels.el を load するよ
    • M-x sangels だよ

必要なものを gem で取ってくるにはこうすればいいよ

  • gem install -r log4r
  • gem install -r -v 0.6 hpricot
  • gem install -r mechanize

長すぎてelispが消えたから続きがあるよ

sangels.bat - 起動用バッチファイル

@echo off
setlocal
set WD=%~dp0
cd /d %WD%

ruby get_movies.rb
ruby get_images.rb
ruby create_m3u.rb

ruby

config.yaml - 設定ファイル
user: ユーザID
password: パスワード
ids_file: ids.txt
done_file: ids_done.txt
movies_dir: movies

log4r_config:
  pre_config:
    global: INFO
  loggers:
    - name: app
      type: Log4r::Logger
      level: INFO
      outputters:
        - STDOUT
        - FILE
  outputters:
    - name: STDOUT
      type: Log4r::StdoutOutputter
      formatter:
        type: Log4r::PatternFormatter
        pattern: "%d [%l] %C - %M"
        date_pattern: "%H:%M:%S"
    - name: FILE
      type: Log4r::FileOutputter 
      filename: "#{LOGDIR}/sangels.log"
      formatter:
        type: Log4r::PatternFormatter
        pattern: "%d [%l] %C - %M"
        date_pattern: "%Y-%m-%d %H:%M:%S"
get_movies.rb
require 'fileutils'
require 'logger'
require 'mechanize'

BASEDIR = File.dirname($0)
require "#{BASEDIR}/util"
require "#{BASEDIR}/sangels"

$config = load_config(BASEDIR)
prepare_logger(BASEDIR)
$log = new_logger("get_movies")
WWW::Mechanize.log = new_logger("mechanize")
WGet.log = $log

class IDFile
  def initialize(file)
    @file = file
    unless File.exist?(@file)
      Fileutils.touch(@file)
    end
  end

  def ids(contains_comment = nil)
    File.open(@file) {|io|
      io.to_a.map {|x|
        x.chomp
      }.select {|x|
        if x.empty?
          nil
        elsif contains_comment
          true
        else
          not /^\s*\#/ =~ x
        end
      }
    }
  end

  def add(id)
    ids = ids(true)
    unless ids.any? {|x| x == id}
      write(ids + [id])
    end
  end

  def delete(id)
    ids = ids(true)
    if ids.any? {|x| x == id}
      write(ids - [id])
    end
  end

  def write(ids)
    File.open(@file, "w") {|io|
      ids.each {|x| io.puts x}
    }
  end
end


$log.info("BEGIN #{$0} ================")
exit_code = 0
begin
  ids_file = IDFile.new($config.ids_file)
  done_file = IDFile.new($config.done_file)
  movies_dir = $config.movies_dir
  wget = WGet.new

  sangels = SAngels.new
  sangels.login($config.user, $config.password)
  ids_file.ids.each {|id|
    begin
      movies = sangels.movies(id)
    rescue SAngels::Movies::InvalidMoviesError
      $log.warn("invalid movie id: #{id}")
      next
    end
    dir = File.expand_path(id, movies_dir)
    movies.each {|link|
      wget.retrieve(link.href, dir)
    }
    expected = movies.movie_links.map{|x| File.basename(x.href)}
    actual = Dir.glob("#{dir}/*").map {|x| File.basename(x)}
    if (expected - actual).empty?
      done_file.add(id)
      ids_file.delete(id)
    end
  }
rescue => e
  $log.error(e)
  exit_code = 1
end

$log.info("END #{$0} (#{exit_code}) ================")
exit exit_code
get_images.rb
require 'fileutils'
require 'logger'
require 'mechanize'
require 'ostruct'

BASEDIR = File.dirname($0)
require "#{BASEDIR}/util"
require "#{BASEDIR}/sangels"

$config = load_config(BASEDIR)
prepare_logger(BASEDIR)
$log = new_logger("get_images")
WWW::Mechanize.log = new_logger("mechanize")
WGet.log = $log

$log.info("BEGIN #{$0} ================")
exit_code = 0
begin
  movies_dir = $config.movies_dir
  sangels = SAngels.new
  sangels.login($config.user, $config.password)
  thumbnails = sangels.thumbnails

  Dir.glob("#{movies_dir}/*").each {|dir|
    next unless File.directory? dir
    id = File.basename(dir)

    url = thumbnails.url(id)
    unless url
      $log.warn("#{id} is not found")
      next
    end
    path = File.expand_path("00_thumbnail#{File.extname(url)}", dir)
    next if File.exist? path

    $log.info("retrieving #{url}")
    thumbnail = thumbnails.get_file(id)
    File.open(path, "wb") {|io| io.write(thumbnail)}
  }
rescue => e
  $log.error(e)
  exit_code = 1
end

$log.info("END #{$0} (#{exit_code}) ================")
exit exit_code
create_m3u.rb
BASEDIR = File.dirname($0)
require "#{BASEDIR}/util"

$config = load_config(BASEDIR)
movies_dir = $config.movies_dir
Dir.glob("#{movies_dir}/*") {|dir|
  next unless File.directory? dir
  name = File.basename(dir)
  files = Dir.glob("#{dir}/*.wmv").sort

  File.open("#{movies_dir}/#{name}.m3u", "w") {|io|
    files.each {|file|
      io.puts "#{name}/#{File.basename(file)}"
    }
  }

  File.open("#{dir}/00_movies.m3u", "w") {|io|
    files.each {|file|
      io.puts "#{File.basename(file)}"
    }
  }
}
sangels.rb
require 'mechanize'
require 'hpricot'

BASEDIR = File.dirname($0)
require "#{BASEDIR}/util"

class SAngels
  HOST = "real2.s-angels.com"
  LOGIN_URL = "http://#{HOST}/member/"
  INFO_URL = "http://#{HOST}/teigaku/item.php"
  THUMBNAILS_URL = "http://#{HOST}/teigaku/"
  THUMBNAIL_URL = "http://#{HOST}/images/default/thumb/"

  def initialize()
    @agent = WWW::Mechanize.new
  end

  def login(user, password)
    login_form = @agent.get(LOGIN_URL).forms.find {|form|
      form.fields.any? {|field| field.name == "frmLoginid"}
    }
    login_form.frmLoginid = user
    login_form.frmPw = password
    @agent.submit(login_form)
  end

  def movies(id, no_validate = nil)
    Movies.new(@agent, id, !no_validate)
  end

  def thumbnails
    Thumbnails.new(@agent)
  end

  class Thumbnails
    def initialize(agent)
      @agent = agent
      doc = Hpricot(@agent.get_file(THUMBNAILS_URL))
      elems = doc.search("div[@class=realthum]/a")
      @links = Hash(
        elems.map {|elem|
          href = elem["href"]
          id = $1 if /ID=(.+)/ =~ href
          url = elem.search("img")[0]["src"]
          [id, url]
        })
    end

    def get_file(id)
      @agent.get_file(url(id))
    end

    def url(id)
      @links[id]
    end

    def exist?(id)
      url(id)
    end
  end

  class Movies
    class InvalidMoviesError < StandardError
    end

    def initialize(agent, id, no_validate)
      @agent = agent
      @id = id
      if !no_validate &amp;&amp; !valid?
        raise InvalidMoviesError
      end
    end

    def info_page_url
      "#{INFO_URL}?ID=#{@id}"
    end

    def info_page
      @agent.get(info_page_url)
    end

    def movies_page
      @agent.click(info_page.links.find {|link| /P=10/ =~ link.href})
    end

    def movie_links
      movies_page.links.select {|link|
        /wmv$/ =~ link.href
      }.sort {|a, b|
        File.basename(a.href) <=> File.basename(b.href)
      }
    end

    def valid?
      info_page.uri.to_s == info_page_url
    end

    def each(&amp;block)
      orig_links = movie_links
      orig_links.each {|orig_link|
        link = movie_links.find {|l| File.basename(l.href) == File.basename(orig_link.href)}
        block.call(link)
      }
    end
  end
end
util.rb
require 'log4r'
require 'log4r/yamlconfigurator'
require 'singleton'
require 'fileutils'
require 'ostruct'

def Hash(a)
  Hash[*a.flatten]
end

def load_config(basedir)
  OpenStruct.new(File.open("#{basedir}/config.yaml") {|io| YAML.load(io)})
end

def new_logger(name)
  Log4r::Logger.new("app::#{name}")
end

def prepare_logger(basedir, logdir = nil)
  logdir ||= basedir
  Log4r::YamlConfigurator["LOGDIR"] = logdir
  Log4r::YamlConfigurator.load_yaml_file("#{basedir}/config.yaml")
end

class NullObject
  include Singleton
  def method_missing(message, *arg)
    NullObject.singleton
  end
end

class WGet
  class << self
    attr_accessor :log
    def initialize
      super
      @log = NullObject.singleton
    end
  end
  
  def log
    self.class.log
  end

  def retrieve(url, dir)
    FileUtils.mkdir_p(dir)
    file = File.expand_path(File.basename(url), dir)
    if File.exist?(file)
      log.info("already retrieved #{url}")
      return true
    end

    tmp = "#{file}.part"
    log.info("retrieving #{url}")
    ret = system("wget", "-c", "-O", tmp, url)
    if ret
      log.info("retrieving succeeded #{url}")
      File.rename(tmp, file)
    else
      if $? == 0x020000 # Ctrl-C
        exit($?)
      else
        log.error("retrieving failure #{url} (#{$?})")
      end
    end
    return ret
  end
end

2008-09-28

みんないじめてるけど、はてなキーワードはすごいんだよ!

例えば「 はてなキーワードが嫌いになった理由 - 将来が不安」とか、最近はてなキーワードがだめとか何とか、そういう話題がかまびすしかったわけですが、いやいや、今更言うのもなんですが、はてなキーワードはすごいんですよ?

キーワードページからそのキーワード含む日記が解る。こういう機能、なかなか無いです。

でも、そのキーワードを使っているはてな以外の日記も見たい時があるかもしれません。

テクノラティなら、はてなに限らず、色々なブログサービスの、そのキーワードを含む記事を探すことができます。

でも、日記キーワードリンクからダイレクトに飛べないと、いちいち見る気になりません。なので、そういうGreasemonkeyスクリプトを書いてみました。はてダの記事中のキーワードリンクの、リンク先をテクノラティにします。

// ==UserScript==
// @name           Keyword to Technorati
// @namespace      http://anond.hatelabo.jp/
// @include        http://d.hatena.ne.jp/*
// ==/UserScript==
var keywords = document.getElementsByClassName("keyword");
for(var i=0; i<keywords.length; i++){
    keywords.item(i).href = "http://www.technorati.jp/search/" + keywords.item(i).textContent;
}

これではてダ以外の記事も見れて、ちょっと世界が広がるかも!

でも、これもちょっと不便です。キーワードリンクで、そのキーワード意味を知りたい時もあるからです。

はてなキーワードの素晴らしいところは、キーワード含む日記キーワード意味、どちらも一つのページで確認できる事です!まぁキーワードの説明とWikipedia、どっちか片方でも良いような気もしますがf(^ ^;)

そこで、テクノラティキーワード検索結果ページにも、そのキーワード意味が表示されれば便利です。

(余談ですけど、Wikipediaの記事があるなら、Wikipediaの記事だけ表示すれば十分かなぁとか思っちゃったり?概してWikipedia記述の方が優れてるし…)

というわけで、これもユーザースクリプトで実現してみます。

// ==UserScript==
// @name           Technorati with Wikipedia or ?keyword
// @namespace      http://anond.hatelabo.jp/
// @description    Add Wikipedia in Technorati search page
// @include        http://www.technorati.jp/search/*
// ==/UserScript==

var keyword = (decodeURIComponent(document.URL).split("?")[0]+" ").slice("http://www.technorati.jp/search/".length, -1);

function appendKeyword(title,body,url){
    var div = document.createElement("div");
    div.style.border = "inset gray thin";
    div.style.padding = "5px 14px";
    
    var h2 = document.createElement("h2");
    h2.innerHTML = title.link(url);
    h2.style.fontSize = "2em";
    div.appendChild(h2);
    
    var content = document.createElement("div");
    content.innerHTML = body;
    div.appendChild(content);
    
    div.appendChild(document.createElement("hr"));
    
    var foot = document.createElement("div");
    foot.innerHTML = "["+decodeURIComponent(url).link(url)+"]";
    foot.style.textAlign = "right";
    div.appendChild(foot);
    
    //document.getElementById("main").insertBefore(div, document.getElementById("main").firstChild);
    document.getElementById("extra").insertBefore(div, document.getElementById("extra").firstChild);
}

GM_xmlhttpRequest({
    method: "GET",
    url: "http://wikipedia.simpleapi.net/api?output=json&amp;keyword="+keyword,
    onload: function(response){
        var wp = eval(response.responseText);
        if(wp){
            appendKeyword(wp[0].title, wp[0].body, "http://ja.wikipedia.org/wiki/"+encodeURIComponent(wp[0].title));
        }else{
            GM_xmlhttpRequest({
                method: "GET",
                url: "http://d.hatena.ne.jp/keyword?mode=rss&amp;ie=utf8&amp;word="+encodeURIComponent(keyword),
                onload: function(response){
                    var hk = (new DOMParser).parseFromString(response.responseText, "text/xml");
                    appendKeyword(keyword,
                        hk.getElementsByTagName("description").item(1).textContent,
                        "http://d.hatena.ne.jp/keyword/"+keyword
                    );
                }
            });
        }
    }
});

これで、はてダキーワードリンクで飛んだ先に、その単語の説明とはてな以外も含めたブログ記事が表示されます。やったね\(^o^)/

追記

用語の説明は、検索結果の上に表示するより、サイドバー広告が表示されてる)にあった方が便利かなーとか思ったので、コードをちょぴっと変更しました。既にインスコしちゃってた人、ごめんね!

ところでテクノラティ検索結果のAutopagerize、なんか1頁目ばっかり継ぎ足される気がするけど、ボクだけかな?

2008-09-25

[]

http://www.ubuntulinux.jp/products/JA-Localized http://www.ubuntulinux.jp/

http://jody.sci.hokudai.ac.jp/~ike/colum/ubuntu_feisty_amd64.html

wget -q http://www.ubuntulinux.jp/ubuntu-ja-archive-keyring.gpg -O- | sudo apt-key add -

sudo wget http://www.ubuntulinux.jp/sources.list.d/hardy.list -O /etc/apt/sources.list.d/ubuntu-ja.list

sudo apt-get update

sudo apt-get install ubuntu-desktop-ja

sudo apt-get install ubuntu-ja-keyring

sudo apt-get upgrade

sudo apt-get install language-pack-gnome-ja language-pack-ja

sudo apt-get install ipafont ipamonafont lha-sjis

sudo apt-get install scim-anthy

sudo apt-get install scim-bridge im-switch

sudo apt-get install openoffice.org-l10n-ja openoffice.org-help-ja mozilla-firefox-locale-ja-jp

im-switch -l

2008-08-03

ニコニコ動画を快適化するvimperator設定まとめ

.

8/27追記

本記事末尾のローカルkey mappingを実現するコードを改良してプラグインにしました。

Vimperatorローカルkey mappingを実現するプラグイン local_mappings.js を書いた。

http://anond.hatelabo.jp/20080826124641


まずnicontroller.jsを入れる。

2008-07-14 - やぬすさんとこの日記

http://d.hatena.ne.jp/janus_wel/20080714

→n秒後/前に移動するkey mappingも忘れずに!

vimperatorrcにこれを書く。

Re: autocmd が分からない - hogehoge

http://d.hatena.ne.jp/teramako/20080731/p1

コードをいじった。

" --- autocmd ---

" nicovideo
" cでコメント入力、Cでコマンド入力、sでシーク、lでボリューム調整、
" pで停止/再生、mでミュートのon/off、vでコメの表示トグル、zでズームjavascript <<EOM
liberator.plugins.nicomap = function(){
  // no args
  var list=[
    ["p","nicopause"],
    ["m","nicomute"],
    ["v","nicomementvisible"],
    ["z","nicosize"],
    ["s","nicoseek"],
  ];
  // has args
  var list2=[
    ["c","nicomment"],
    ["C","nicommand"],
    ["l","nicovolume"],
    ["s","nicoseek"],
  ];
  if(buffer.URL.indexOf("http://www.nicovideo.jp/watch") == 0){
    for (var j=0; j<list.length; j++){
      let i = j;
      liberator.mappings.addUserMap([1],[list[i][0]],list[i][1],
        function(){
          liberator.execute(list[i][1]);
        },{
          rhs:":"+list[i][1]+"<CR>"
        }
      );
    }
    for (var j=0; j<list2.length; j++){
      let i = j;
      liberator.mappings.addUserMap([1],[list2[i][0]],list2[i][1],
        function(){
	  liberator.execute('normal :'+list2[i][1]+'<Space>');
	},{
	  rhs:":"+list2[i][1]+"<Space>"
	}
      );
    }
  } else {
    for (var i=0; i<list.length; i++){
      liberator.mappings.remove(1,list[i][0]);
    }
    for (var i=0; i<list2.length; i++){
      liberator.mappings.remove(1,list2[i][0]);
    }
  }
};
liberator.autocommands.add('LocationChange','.*','js liberator.plugins.nicomap()');
EOM

フォーカスプレーヤーに奪われないようにするグリモン

2008-08-02 - 地獄の猫日記

http://d.hatena.ne.jp/nokturnalmortum/20080802#1217633913

→→これで超快適すぎるニコライフの幕開け!

.

補足

現在マウスカーソル位置でクリックイベント発生するkey mappingを設定できればより快適なんだが・・・。

(「コメントする」ボタンDOMノードが取得できれば、dispatchEventでいけそうだけど)

追記: ちょっと改良してみた。
" ************* local key mappings ****************
javascript <<EOM
 (function(){
function setlocalmap(obj){
    var list = obj.list;
    var list2 = obj.list2;
    var exp = obj.exp;
    if(list.constructor != Array || list2.constructor != Array){
      echr("invalid argument: array argument required");return;
    }
    if(exp.constructor != RegExp){
      echr("invalid argument: regex argument required");return;
    }
    if(exp.test(liberator.buffer.URL)){
      for (var j=0; j<list.length; j++){
        let i = j;
        liberator.mappings.addUserMap([1],[list[i][0]],list[i][1],
          function(){
            liberator.execute(list[i][1]);
          },{
            rhs:":"+list[i][1]+"<CR>"
          }
        );
      }
      for (var j=0; j<list2.length; j++){
        let i = j;
        liberator.mappings.addUserMap([1],[list2[i][0]],list2[i][1],
          function(){
  	  liberator.execute('normal :'+list2[i][1]+'<Space>');
  	},{
  	  rhs:":"+list2[i][1]+"<Space>"
  	}
        );
      }
    } else {
      for (var i=0; i<list.length; i++){
        liberator.mappings.remove(1,list[i][0]);
      }
      for (var i=0; i<list2.length; i++){
        liberator.mappings.remove(1,list2[i][0]);
      }
    }
}
/** 
 * Add Key Mappings to Specific Web Pages
 * @param obj : has following properties
 *  list : commands that take no args
 *  list2 : commands that take args
 *  exp : target page's URL (regex)
 * @see Re: autocmd が分からない - hogehoge
 * http://d.hatena.ne.jp/teramako/20080731/p1
 */
liberator.plugins.addLocalUserMap = function(obj){
  liberator.plugins[obj.name + "MapSetter"] = function(){
    setlocalmap(obj);
  }
  liberator.autocommands.add(
  	'LocationChange', '.*', 'js liberator.plugins.' + obj.name + 'MapSetter()'
  );
};

// nicovideo
// cでコメント入力、Cでコマンド入力、sでシーク、lでボリューム調整、
// pで停止/再生、mでミュートのon/off、vでコメの表示トグル、zでズーム。
var nicovideo = {
	name : 'nico',
	exp : /^http:\/\/www.nicovideo.jp\/watch/,
	list : [
	    ["p","nicopause"],
	    ["m","nicomute"],
	    ["v","nicomementvisible"],
	    ["z","nicosize"],
	    ["s","nicoseek"],

	],
	list2 : [
	    ["c","nicomment"],
	    ["C","nicommand"],
	    ["l","nicovolume"],
	    ["s","nicoseek"],
	],
};
liberator.plugins.addLocalUserMap(nicovideo);
})();
EOM

2008-07-07

もん毛スター for firefox

動作未確認。すんげー冗談半分。

// Hatena Monge Star user script
// 2008-07-07
// by masda. (http://anond.hatelabo.jp/20080707043247)

// ==UserScript==
// @name           Hatena Monge Star
// @namespace      http://anond.hatelabo.jp/20080707043247
// @description    Hatena Monge Star
// @include        http://b.hatena.ne.jp/entry/*
// @version        0.3.1
// ==/UserScript==

// deriving from [http://d.hatena.ne.jp/Hamachiya2/20080707/HatenaBlackStar2] ver Firefox
//               [http://f.hatena.ne.jp/hatenacinnamon/20070109001332]
// Thx! and CUTE!


location.href = 'javascript:(' + function() { (function (w) {

	if (typeof(w.Ten) == 'undefined') {
		return;
	}

	HatenaBookmarkMongeStar = new Ten.Class({
		initialize: function(li, entryTitle) {
			var comment = '';
			var tags    = '';
			var commentSpans = Ten.DOM.getElementsByTagAndClassName('span', 'comment', li);
			if (commentSpans.length > 0) {
				comment = Ten.DOM.scrapeText(commentSpans[0]);
			}

	        var tagsSpans = Ten.DOM.getElementsByTagAndClassName('span', 'user-tag', li);
			if (tagsSpans.length > 0) {
				$A(tagsSpans[0].getElementsByTagName('a')).each(function(a) {
					tags += '[' + Ten.DOM.scrapeText(a)+ ']';
				});
			}

			var title = tags + comment;
			if (title.length == 0) {
				var name = Ten.DOM.scrapeText(li.getElementsByTagName('a')[1]);
				title = name + 'のブックマーク';
	        }

			// this.uri   = 'http://b.hatena.ne.jp/keyword/' + li.getElementsByTagName('a')[1].href;
			var u = li.getElementsByTagName('a')[1].href;

			if (u.indexOf('#') == -1) {
				this.uri = u + '#_HatenaMongeStar';
			} else {
				this.uri = u + '_HatenaMongeStar';
			}

			this.title = title + ' - ' + entryTitle;

			this.comment_container = Hatena.Star.EntryLoader.createCommentContainer();
			var target = commentSpans[0] || li;
			target.appendChild(this.comment_container);

			this.star_container = Hatena.Star.EntryLoader.createStarContainer();
			this.star_container.className = 'hatena-star-star-container MongeStarContainer';
			target.appendChild(this.star_container);
		}
	});


	var tryCount = 0;
	var tryMax = 300;
	function waitForHatenaStar() {
//		if (Hatena.Star.EntryLoader.loaded) {
//			Hatena.Star.EntryLoader.loaded = false;
		var s = document.getElementsByClassName('hatena-star-add-button');
		if (s.length) {

			Hatena.Star.EntryLoader.loaded = false;

			Hatena.Star.EntryLoader.loadEntries = function() {
				var entries = [];
				var title = Ten.DOM.scrapeText(Ten.DOM.getElementsByTagAndClassName('span', 'title', document.body)[0]);
				var ul = document.getElementById('bookmarked_user');
				if (ul) {
					$A(ul.getElementsByTagName('li')).each(function(li) {
						if (li.className != 'more') {
							entries.push(new HatenaBookmarkMongeStar(li, title));
						}
					});
				}
				return entries;
			}
			new Hatena.Star.EntryLoader();

		} else {
			if (++tryCount > tryMax) {
				setTimeout(waitForHatenaStar, 400);
			}
		}
	}

	setTimeout(waitForHatenaStar, 500);

})(window); }.toString() + ')()';



GM_addStyle(<><![CDATA[

	.MongeStarContainer {
		margin-left: 4px;
	}

	.MongeStarContainer .hatena-star-add-button {
		background-color: #fc6 ! important;
	}

	.MongeStarContainer a {
		text-decoration: none ! important;
		color: #f80 ! important;
		font-size: 10px;
		position: relative;
	}

	.MongeStarContainer a:before {
		content: '毛';
		font-size:small;
	}

	.MongeStarContainer a .hatena-star-star {
		filter: alpha(opacity=00);
		-moz-opacity:0.00;
		opacity:0.00;

		position: absolute;
		top: 0;
		left: 0;
	}

	.MongeStarContainer .hatena-star-inner-count {
		color: #f90 ! important;
	}

]]></>);

動いたらいいな-

2008-07-01

本日情報の授業:アセンブリ言語の処理あれこれ

プログラムを学ぶ上での一番根源的なものとしてアセンブリ言語が扱われることってわりと多いように思う。

便利なプログラムコンピューター内ではこう処理されてます、とか。

だけど、その説明ってあんまり意味が無いよなとか思ったり。

add D1 D2 D3(アセンブリの命令でD1D2の値を足してD3へ代入を意味)なんてもはや単なるプログラミング言語に過ぎない訳で、それCでも出来るよ、としか思わない。

はいはいアセンブリ不便ですね、ってなって結局主軸は別の言語に移す。

プログラミングの楽しさや便利さはその別の言語を通じて学ぶことになるのだし、じゃあアセンブリ言語を学ぶ意義ってなによ。

c=a+bって書けばコンピューターが計算してくれますっていうのと、add D1 D2 D3ってやればCPUが計算してくれますっていうのは感覚としては同じ。

本当に根源的なものまで突き詰めるのなら電気信号をどう解釈してどういう仕組みで演算して数を格納してっていうことをやってほしい。

アセンブリを根源扱いして崇めることにはなにか抵抗を感じる。

2008-06-20

JavaScript楽しい

Event.add=function(_element,_name,_func){
 if(_name=="load") { Event.onload.add(_func); return; }
 if(ua.name.indexOf("IE")>0 &amp;&amp; _name=="keypress") _name="keydown";
 if(window.addEventListener) _element.addEventListener(_name, _func, false);
 else if (window.attachEvent) {
  if(_element==window) _element=document;
  _element.attachEvent("on"+_name,function(){
   var e=arguments[0];
   e.target=e.srcElement;
   e.pageX=document.body.scrollLeft+e.clientX;
   e.pageY=document.body.scrollTop+e.clientY;
   _func.apply(_element,arguments);
  });
 }
};

はじめてのラッパー

2008-05-30

http://anond.hatelabo.jp/20080530031237

これだけの文章が書けるなら馬鹿ではないかと。

ADHD(どちらかというとADDのほう)では?

あてはまるなら、それなりの対応方法があるかと。

2008-04-06

[]新年度なので、これからよくわかりたいOpenIDについて

##はじめに

 →OpenIDが仮に広まった未来には、サービス事業者がユーザ個人情報をどれだけ持つのが適正なのかを考えられるようになりたいよ

  • 今回整理している内容が事実と違ってることがあったら、速効おしえてちゃん!!

##OpenIDを利用したサービスは、将来オープンOpenIDプロバイダを受け入れることができる?

OpenIDを受け入れる、ということは「特定ではないIDプロバイダによって認証」されたユーザサービス事業者は受け入れるということになるよ。

※以下サービス事業者の例を、わかりやすくするために京都発のWebサービス提供会社はてなさん(以下はてな)にするよ

ここでいう「特定ではないIDプロバイダによって認証」というカッコ書きについて整理しておくね。

これ、逆に言うとこれまでのサービスって、はてなも勿論そうだけど「特定されるIDプロバイダによって認証」が行われていたんだということになるよね。

例えば、はてなというサービスにエンドユーザ増田が、はてなIDパスワードでもってログインを行う場合は、

増田はてなサービスはてな会員管理システム(これもはてなの一部だけど)の3者関係で考えると、

増田はてなサービスを利用するためにログインすると、はてなサービスは、はてなの会員管理システムに僕が僕であるためのIDパスワードを問い合わせして

はてな側に僕だよ、っていうことを認証、そしてサービス利用の許可(認可)していたわけだよね。

これまでの

はてなサービスはてなの会員管理システムで認証する、というお決まりのやり方を

はてなサービス→「特定ではないIDプロバイダによって認証」もOKにしちゃう!

っていうのがOpenIDの基本的な考えだと思ってるよ。

つまり、はてなに対してみんな大好きなmixi渋谷区)のゆるふわIDパスワードOpenID認証しちゃえ!ていう感じ。

OpenIDと呼ばれるもののコアなところって、この自分じゃない余所様でログインをさせるにあたっての

通信の決まり・振る舞い方についての仕組みとかのことなんだね。

認証機能の委譲、なんて難しい言葉で言われてもバカな僕にはわかんなかったから、とりあえずこんな感じで整理してみたよ。

でもね。増田自身がはてなの立場になって考えてみるとこう思うよきっと。

他所のプロバイダさんに認証をお願いしたら、、、

「コノ人確カニ○○○君!ザッツヒム!イッツOK!!」ていう怪しげな応答があったとしてもさ

「うちは京都サービスさかいに、妙ちくりんな英語まじりのプロバイダさんの言うことなんか信用できまへんなー」

自然と思ってしまうよきっと。これがひいてはOpenIDプロバイダの評判問題ってやつにつながる話だね。

あと、じゃあOpenIDプロバイダの認証結果は信じることにしたとしてでも今度は

「まーmixiさんところが認証OKてゆなら確実でっしゃろう?遠いところからよくきはりました。

どれ、アンタうちでもサービス使わせてやるさかい...あれれ?君、うちでいうところのid:誰くんでしたっけ?」

なっちゃうねーやっぱり。。これが認証と認可(属性情報交換)に関わる問題てやつだよ。

うーん、ちょっと自分自身にとってもムツカシくなってきたなぁ。もう少しわかりやすく書くね。

上の話ははてな子ちゃんが自分の会員管理システムログインさせない(外の会員管理システムログインする)ことにより、

自社のサービス提供では当たり前にできていたことができない、という問題が2つ出てきたねーということだよね。

1. 「あなた(Openプロバイダ)の認証、あ、あたし。信じていいの?ゴクリ・・・」

という信頼関係について。

2. 「あなた(エンドユーザ)は彼(OpenIDプロバイダ)に認められた人だから、アタシも、が、がんばって信じる!…けど、○○○君(エンドユーザ)のことをもっと知る必要があるの。。。」

という(エンドユーザの)認可・(OpenIDプロバイダからの)属性情報の受入(交換)について。

うー、あれ?

はてなスターではこの2つの問題をどうしているの?って思う人は多いよね。

たぶんはてなスターOpenID対応しているっていうのを聞いたことがあっても、実際にやったことある人は少数派じゃないかなまだ。。

じゃあこっからははてなスターを例にとって説明するよ!

詳しくは下のリンクの説明通りなんだけど、

http://www.hatena.ne.jp/info/openid

今回増田が問題としている2つについてはてなスターの機能はどーなってるの?ていうのを整理すると

1.「OpenIDプロバイダとの信頼関係について」=「フレンドプロバイダのみ認証OK!」(いわゆるホワイトリスト

2.「(エンドユーザ)認可・(OPとの)属性情報交換」=OpenIDユーザ名でスターがつく

という対応をしているみたい。

※ちなみにこの記事書くにあたって増田ははじめてOpenID経由ででスターつけてみたよ!!

つまり、

1.の信頼関係については、Livedoorなど数社のOpenIDプロバイダのみを受入OKにしているし、

2.の属性情報については、OpenID認証を行う際に必要なOpenIDプロバイダ側の「ユーザ名@OP名」でスターがつくだけ

  →なので属性情報交換などはほぼゼロだよね、って感じだったよ。

1.は、

「なーんだ。Open何とか言っておきながら内輪でのID連携かよ。うちも一応OpenIDプロバイダたててんだよ?え?無理?うちみたいなチンケなプロバイダは無視ですかそーですか」

みたいな中小企業のボヤキが聞こえてくるくらい全然Openじゃなくすることで一方での

はてな子ちゃんにとっての問題=「あなた(Openプロバイダ)の認証、あ、あたし。信じていいの?ゴクリ・・・」問題を回避しているということになるよね。

2.についてははてなスターはほぼガン無視を決め込んでいるのが今回よくわかりました!

今回増田がためしにOpenID認証経由でスターをつけてみたんだけど、

あのー、、増田も一応こうして増田をやっているので一応はてな市民であって、「あいでぃー:xxx」みたいな立場ではあるじゃないですか。

なのに、LivedoorIDでスターつけちゃったら「あいでぃー:xxx」でスターつけたことにならない><!(※)ので、

うーん、、ちょっとこれは深刻な機能不足だなーと思った次第ですー。いや?いいのかこれでOpenIDとしては。微妙だなぁ・・

(※)

だって、増田idhttp://s.hatena.ne.jp/xxx/starsでスターが反映されない

あと<増田のLivedooeのアカウント名>@livedoor のスターのカウント(上のhatena/user/starsに相当するページね)はどこにいったのだろう??

でもさぁ、

はてな子ちゃんの立場はそれはそれでよくわかるのよね。

いまいまのOpenIDセキュリティレベルでは、どこの馬の骨ともわからん奴にあなたのことについて

情報の連携を行ったりとか危険すぎるしね。しょうがないよね?

※ほんとは、はてなの「あいでぃー:xxx」とLivedooridがSocialに結びついてくれて、

自動的にhatenaidでスターをAddしたことになればいいんだけどねー。でもそれじゃあはてなIDログインしろってことと変わらんかー。

とも思うし難しいなぁこの辺。

こういう問題があるOpenID界隈では、でもこれらの問題について色々知恵を出し合って解決しようとしている

人もいるみたい。サイボウズのzigorouさんとか、他にもいっぱいいらっしゃるけど、皆さんすごいがんばってるみたい!すごい!

増田個人は、

1.については各OpenIDプロバイダIDを利用するサービス(Ryling Party)それぞれのホワイトリスト

Socialに連携/公開されてグラフになってエンドユーザが利用できる・できないの仕組みになるのがいいのかなー、

と思っていたりするよ。DNSみたいな公開されて相互利用できるよな仕組みがあればいいのかなー。

2.については属性情報の仕組みとしてはAXとかsregとかあるけど、要は使い方でリバティ・アライアンスの頃からしきりと言われているらしい

「串刺しにした」サービスの連携のためにどう属性情報流通させるのか?SSO連携が肝だよねー。とか。

また属性情報流通させるにあたってのその情報粒度は?っていう話を詰めなきゃいけないんだろうなー、というレベルぼんやり中です。

もう少し↑について知識・考えついてきたら、またまとめてみたいです。じゃあまたね!!

2008-03-14

public class Main {
    public static void main( String[] args ) {
        // ( 5 - 3 ) + 1
        Exp exp = new Add(new Sub(new Num(5), new Num(3)), new Num(1));
        System.out.println(exp.eval());
    }
}


/**
 * 抽象クラス
 */
abstract class Exp {
    public abstract int eval();
}


/**
 * 足し算
 */
class Sub extends Exp {

    /** 左辺 */
    private Exp hidari;
    /** 右辺 */
    private Exp migi;

    /**
     * コンストラクタ
     */
    public Sub(Exp hidari, Exp migi){
        this.hidari = hidari;
        this.migi = migi;
    }

    /**
     * 評価
     */
    @Override
    public int eval() {
        return hidari.eval() - migi.eval();
    }

}


/**
 * 引き算
 */
class Add extends Exp {

    /** 左辺 */
    private Exp hidari;
    /** 右辺 */
    private Exp migi;

    /**
     * コンストラクタ
     */
    public Add(Exp hidari, Exp migi){
        this.hidari = hidari;
        this.migi = migi;
    }

    /**
     * 評価
     */
    @Override
    public int eval() {
        return hidari.eval() + migi.eval();
    }
}


/**
 *
 */
class Num extends Exp {

    /**
     *
     */
    private int self;

    /**
     * コンストラクタ
     */
    public Num(int self) {
        this.self = self;
    }

    /**
     * 評価
     */
    @Override
    public int eval() {
        return self;
    }

}

2008-03-03

大分昔の話を書こう

技術系の日記をつけてる人が居た。

正直な所、ファンだった。

僕はその人の書いた、気に入ったエントリにはスターを沢山つけた。

すごいと思ったところをドラッグし、とにかくadd starした。

自分ではその行為はまともなつもりだったかもしれないけれど、今思い出すとかなりしつこい行為だと思う。

その人は日記プライベートモードにした。「もうやめます」という旨のメッセージを残して。

要するに、僕が気持ち悪かったのでその人は逃げた。

虚しい。虚しすぎる。

反省はしている。でももうどうしようもない。笑うしかない。

ログイン ユーザー登録
ようこそ ゲスト さん