ひまつぶし雑記帖

ActivityPubでoutboxの実装

2023/7/18 [10:11:56] (火) 天気

ActivityPubを通じて、Fediverse連合空間にユーザーアカウントとして認識してもらえるようになった。

次はウチのつぶやきというか投稿を拾ってもらえる、たとえばMastodonでtokorotenのコンテンツを表示してもらえるのが目標。

そのためには適切なoutboxを用意する必要がある。
よくわかってないけど、outboxてのは、これまでの行動、投稿のログ、という理解で大丈夫かな。outboxのtypeはOrderedCollectionがMUSTとされていて、たぶん順番も見られるんだろう。

あ。今さらだけど、わたしはど素人なので、見様見真似。間違った情報を垂れ流すことが多くてすみません。先に謝っておきます。

/actor/outbox
へのアクセスに対してこれまで投稿履歴を返す。
create(投稿)したnote(発言)とそれらを取得するためのurlなどの情報が羅列されたjson。
image 
こんな感じだろうと思われる(大雑把)
「投稿」を「投稿しました」で包んで、そいつを順番に並べたものがoutboxという箱になる。

実際に配置したのが以下のoutbox。
といっても、お約束、決まり事通りに並べて作ってるだけなので、手数はともかく、それほど難しいものではない。

{"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://tokoroten.doncha.net/t2aki/outbox",
"summary": "outbox of t2aki@tokoroten.doncha.net",
"type": "OrderedCollection",
"totalItems": 2,
"orderedItems": [{
  "type": "Create",
  "id": "https://tokoroten.doncha.net/t2aki/activity/00054-20230717",
  "url": "https://tokoroten.doncha.net/t2aki/activity/00054-20230717",
  "published": "2023-07-17T12:45:08Z",
  "actor": "https://tokoroten.doncha.net/t2aki",
  "to": ["https://www.w3.org/ns/activitystreams#Public", "https://tokoroten.doncha.net/t2aki/followers"],
  "object": {
    "type": "Note",
    "id": "https://tokoroten.doncha.net/t2aki/items/00054-20230717",
    "url": "https://tokoroten.doncha.net/t2aki/items/00054-20230717",
    "published": "2023-07-17T12:45:08Z",
    "to": ["https://www.w3.org/ns/activitystreams#Public", "htps://tokoroten.doncha.net/t2aki/followers"],
    "attributedTo": "https://tokoroten.doncha.net/t2aki",
    "content": "[2023/07/17 12:45]\u003cbr /\u003elog取得のサブルーチンはpostとgetでちょっといじらないとダメやな。帰ったら仕込む"
    }
  }, {
  "type": "Create",
  "id": "https://tokoroten.doncha.net/t2aki/activity/00053-20230717",
  "url": "https://tokoroten.doncha.net/t2aki/activity/00053-20230717",
  "published": "2023-07-17T11:37:47Z",
  "actor": "https://tokoroten.doncha.net/t2aki",
  "to": ["https://www.w3.org/ns/activitystreams#Public", "https://tokoroten.doncha.net/t2aki/followers"],
  "object": {
    "type": "Note",
    "id": "https://tokoroten.doncha.net/t2aki/items/00053-20230717",
    "url": "https://tokoroten.doncha.net/t2aki/items/00053-20230717",
    "published": "2023-07-17T11:37:47Z",
    "to": ["https://www.w3.org/ns/activitystreams#Public", "https://tokoroten.doncha.net/t2aki/followers"],
    "attributedTo": "https://tokoroten.doncha.net/t2aki",
    "content": "[2023/07/17 11:37]\u003cbr /\u003e他のアカウントのoutboxをみて、そこにあるnoteのURLを叩くとHTMLページが開くんだけど、なんでや。jsonが返ってくるんじゃなかったっけ。HTTPのヘッダを覗いてもjsonじゃなくてフツーのHTMLを返してるぞ。こちらのリクエストに応じてjsonをHTMLに変換してたりするのかな。謎だらけ。"
    }
}]}


typeがNoteとなっているブロックが投稿内容で、このNoteが基本となっている。
idとurlは投稿内容へのリンク。このNoteのjsonを返す。
publishedは日付。JSTだから+9とか必要かもしれないけど、とりあえず。
attributedToは投稿者。
toはお約束事。

typeがCreateのブロックがNoteのブロックをobjectに包んでいる。
idとurlのリンクはこのCreateのjsonを返す。今日時点、返すのがこのブロックでいいのか謎。とりあえず。
各要素はNoteと同じなので以下略。

そのCreateブロックを順番に並べてoutboxの完成。

前回設定したwebfingerとactor.jsonで、マストドンで「t2aki@tokoroten.doncha.net」を検索するとユーザーアカウントとして認識される。
image
「他のサーバーの以前の投稿は表示されません」と記載されている状態。

今回outboxを設定したので、個々のNoteのリンクをマストドンで検索するとtokorotenの投稿がマストドンで表示される。
image

検索して一度表示されると、ユーザーアカウント表示の下にも表示されるようになった。
image
たぶん、検索して結果が返ってきたことで、このマストドンサーバーにキャッシュされたのかな。

ただ、やはり謎は深くて。

謎その1)
ユーザーアカウント画面の下の「リモートで表示」というリンクを開くと、わたしのactor.jsonが表示される。ほかのひとの「リモートで表示」を開くとマストドンで開いたり、やっぱりactor.jsonが返ってきたりいろいろ。
リモートで表示とは、マストドンの別サーバーだったら意図通りに開くけど、マストドンじゃないサーバーだったらjsonをそのまま開くということになってるんだろか。

謎その2)
mastodonやmisskeyのoutboxはNoteを包んだCreateブロックを持たずにfirstやlastといったリンクを返すだけだったりするんだけど、これはありなのか。

ActivityPub w3c.org
↑ここがActivityPubの本家本元(?)
頑張って読むしかないんだろうけど、爺さんにはつらいぞ、英語。

そして、やはりRSAで署名したPOSTをどこかに投げないことには始まらない。
これについてはレンタルサーバーにモジュールがないのでほぼ諦め。ローカルで作ってスクリプトで投げる、ぐらいしか思いつかないしなあ。

とはいえ、ごそごそスクリプトを考えるのは爺さんのボケ防止にちょうどいいパズルゲームでもあるなあ。

ちなみに。元ネタの「 ところてんx10 」はほぼ毎日たわごと並べてるので、RSSリーダーにでも登録していただけると更新をお届けできます。


すげー今さらのRSSとか!

[07/19 11:17:32]
謎その1は解決。
HTTP_ACCEPTを見て判別。jsonを要求されてたらjson、そうじゃなければHTMLを返してた。さっそくウチも導入。やっぱ生のjsonが返ってくるとびっくりするからなあ。

https://gihyo.jp/dev/serial/01/perl-hackers-hub/005902

AS2以外の形式の情報を返すこと(コンテントネゴシエーション)も認められています。これを利用して、同じURLでも、ActivityPubの情報を要求された場合はAS2形式の情報を、それ以外の場合はHTML形式での情報を返すようにしています。



[08/04 10:40:12]
publishedの日付問題。
飛んでくるPOSTというかjsonを見ると、JSTだけど+900やJSTという表記がなくて標準時になってる。
localtimeじゃなくてgmtimeを使えば良かった

»電子書籍制作代行についてはこちら

古代メキシコ展

2023/7/14 [00:20:28] (金) 天気

トーハクこと東京国立博物館で開催中の古代メキシコ展に行ってきた。
テオティワカン、アステカ、マヤ文明の出土品の展示で、目玉は赤の女王というミイラ。
image image image image image 
相変わらずトーハクの展示は迫力だったなあ。見ていてまったく飽きないし、時間が足りない。

神々の犠牲があって成り立っている、という世界観?
なので生贄を捧げることになってたらしい。

にしても、神さまってのは人間につきものなんだなあ。

科学博物館でもペルー展(インカ)をやってるということで行ってみたけど、こちらは小さなコーナーで正直拍子抜け。
だけど、こっちは常設がスゲー。今さらながらびっくりした。
江戸時代あたりの日本は時間が一定じゃなく、季節ごと夜日中ごとで違ってたなんて、この歳になって初めて知った。
昼と夜、春夏秋冬で時間の流れかたが違うというのは、感覚的にはこっちが正しい時間のような気もする。
で、それをはかるための時計作りに心血を注いでいたという胸熱な展開もあったらしい。

今なんどきだい?という問いかけが実はかなり意味深だったんだなあ(え?

上野公園って、そこにある全部の展示と動物園まで見て回ると3泊でも足りないんじゃないかな。
で、ホテル代を払ってでも全部回る価値はありそう。

»電子書籍制作代行についてはこちら

ActivityPubを使ってFediverseにたどり着く

2023/7/12 [02:17:04] (水) 天気

いや、なんのこっちゃだけど。
2023年、ツイッター亡き後の世界となった。ネット空間には祖国を奪われた難民たちで溢れかえり…というB級サイバーパンクSFの設定。

そこで再評価されることになった、実は古より存在するFediverseというネットの連合空間。ActivityPubという共通の言語で繋がるネット世界、ということになった。

てことで、「いっちょかみ」できるかなあ、とここ数日あれこれ検索しまくって試して、とりあえずmastdonで検索して仲間として検索結果に出るところまではたどり着いた。
image 
最小限のActivityPub、いわゆるお一人様で、もちろん喋ることもフォローなどアクションをすることもできない。ただ、連合空間に顔を出した、だけなんだけど。

「mastodonなどに認識してもらえる」のがまずはゴールだったんで、ここまでやったことをメモ。
(すべてはネットで検索して得られたもので、先人たちに大感謝)

ActivityPubに参加するため用意するもの
サーバーやドメインをもっていることが前提。わたしはいつものlolipopサーバー。

どうやら以下の4つがあればActivityPubに顔を出すことはできる、っぽい。

nodeinfo(json)
サーバーの情報、でいいのかな。ここにGETでアクセスされて、ウチはactivitypubやってますよ、ユーザーは1人ですけどね、というのを返す。

{                                                                                                                                                            
  "openRegistrations": false,
  "protocols": [
    "activitypub"
  ],
  "software": {
    "name": "tokoroten",
    "version": "0.1.0"
  },
  "usage": {
    "users": {
      "total": 1
    }
  },
  "version": "2.1"
}



host-meta(xml)
webfingerのURLを返す。uriは検索対象のユーザー名の文字列に置換される。

<?xml version="1.0"?>                                                                                                                                        
<XRD xmlns="https://docs.oasis-open.org/ns/xri/xrd-1.0">
<Link rel="lrdd" type="application/xrd+xml" template="https://tokoroten.doncaha.net/.well-known/webfinger?resource={uri}" />
</XRD>



webfinger(json)
host-metaで得られたwebfingerのURLにGETでアクセスされるのでユーザー情報のエンドポイントを返す。

{                                                                                                                                                            
  "subject": "acct:t2aki@tokoroten.doncha.net",
  "links": [
    {
      "rel": "self",
      "type": "application/activity+json",
      "href": "https://tokoroten.doncha.net/t2aki"
    }
  ]
}



actor(json)
webfingerで取得したユーザーのURLにアクセスするとこの情報を返す。

{                                                                                                                                                            
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    "https://w3id.org/security/v1"
  ],
  "id": "https://tokoroten.doncha.net/t2aki",
  "type": "Person",
  "url": "https://tokoroten.doncha.net/t2aki",
  "inbox": "https://tokoroten.doncha.net/t2aki/inbox",
  "outbox": "https://tokoroten.doncha.net/t2aki/outbox",
  "followers": "https://tokoroten.doncha.net/t2aki/followers",
  "following": "https://tokoroten.doncha.net/t2aki/following",
  "name": "t2aki",
  "preferredUsername": "t2aki",
  "summary": "@t2aki@tokoroten.doncha.net",
  "icon": {
      "type": "Image",
      "mediaType": "image/jpeg",
      "url": "https://tokoroten.doncha.net/images/prof-image.jpg"
  },
  "pubKicKey": {
      "id": "https://tokoroten.doncha.net/t2aki#main-key",
      "owner": "https://tokoroten.doncha.net/t2aki",
      "publicKeyPem": "-----BEGIN PUBLIC KEY-----\n略==\n-----END PUBLIC KEY-----",
      "type": "Key"
  }
}



nodeinfoやhost-metaはわかってないまま設置。
たぶん、webfingerでユーザー情報のURLを返して、そのURLにアクセスするとユーザー情報を得ることができますよ、というやりとりがあればまずは第一関門突破だと思われる。

HTTPでリクエストの投げ合いをして相互理解を深める。WEBの基本。

と、わかったようなことを書いたけど、ここにいたるまでハマりまくった。

サイトの構成をどうすればいいのか、そもそもそこから。
結論。考える必要はまったくなかった。
ActivitiyPubはディレクトリ構造とか拘束しないというか全然関係ない。全部jsonやxmlの設定ファイルでリクエストに返答できればいいだけだった。

アクセスされて、ActivityPubを構成するファイルを返す時のヘッダは以下がMUST

Content-Type: application/activity+json; charset=utf-8


てことは動的にヘッダをつけて返答する必要があるのか、ということで、スクリプトで対応。そのために.htaccessのrewriteruleで振り分けることにした。※1

.htaccess

RewriteEngine On                                                                                                                                             
RewriteCond %{QUERY_STRING} ^resource=(.*)$
RewriteRule webfinger.* script-finger%1 [L]
RewriteRule nodeinfo/2\.1$ script-nodeinfo [L]
RewriteRule host-meta$ script-hostmeta [L]
RewriteRule t2aki$ script-actor [L]


ここでのハマり。
apacheのrewriteruleはそのままだと「クエリを含まない」
fingerはresourceというクエリをつけてやってくる。そのクエリが分からないんじゃ何を求められてるのかわからない。それを解決するにはRewriteCondでクエリを判定させてやれば良い、てことにたどり着くのに2時間弱。

この先、フォローしたり投稿したりするには公開鍵秘密鍵で署名する必要があって、わたしの脳みそで理解できるレベルではない。そもそもlolipopではCrypt::OpenSSL::RSAのモジュールが使えないのでないものねだり。

手元、ローカルで作って手作業で鍵を作ってリクエストを投げる、ということを考えるしかなさそう。それもHTTPのヘッダ構成を調べる必要があって、高いハードルを見上げすぎて首を痛めるレベル。
とはいえ、せっかくだし、もう少し頑張ってみるかなあ。

※1
検索していてビックリしたのが静的ファイルだけでActivityPub実装してるかたいらっしゃった。
NetlifyとSupabaseでほぼ静的なActivityPubサーバ

今回まででとても参考になったサイト
Fediverse入門―非中央集権型SNSサーバを作ろう!
田舎の昼のサイレンbotをActivityPubで実装する(マストドンにアカウントを認識してもらう編)
ActivityPubの実装についてのメモ
本当に助かりました。多謝!!!

さっそく、ひとり言掲示板 「ところてんx10」 が役に立った、ぞ。

»電子書籍制作代行についてはこちら

ひとり言掲示板:ところてんx10

2023/7/6 [23:29:00] (木) 天気

ひとり言、メモ用掲示板を作ってみた。
・保存するのは100個まで。
・画像投稿はできない。
・検索機能はない。
・カテゴリづけもない。
・表示順は日付の新しいもの順だけ。
・一度書いたものを編集、削除することはできない。

投稿できるのはテキストだけ。
テキストの文字数制限はたしか80KBぐらいまでにしたのでけっこう長めのものも書き込める。

というなんかめちゃくちゃ手抜きのスクリプト。
一応RDFというかRSSは取得できるようにしてみたけど、これはおまけ。
image
スクリプト的には。公開はしてないけど、すでにメモ代わりのひとり言掲示板みたいなものは作って今も使っていて、ほぼそれの流用で、そこから検索機能やあれこれ機能を削っただけのシロモノ。

その、今すでに使ってるメモは、発注納品締切とか、スーパーでの買い物、ポケモンの対戦結果、医者、内科や歯医者、目医者の予約とかとか。
ほんとのメモ、めっちゃ個人的な備忘録。そんなものを公開の場に出すワケにもいかないし、そもそもそんなものわたし以外のひとには意味も価値もない。

ひとり言というなら、そのメモで勝手にやってりゃええやろ、というのはもっともな話。

とはいえ。
ツイッターにほとほと愛想が尽きて、みけさんもいないとなると、snsを利用することもない。
なので、この雑記帖に引きこもるぞー!てのは少し前に言ったけど、なかなか雑記帖に書くようなボリュームのネタもない。
なので、雑記帖の元ネタになりそうなことをメモする場所にしようかと。

それでも、今のその非公開のメモとやらでやってりゃええんとちゃうんか、は変わりないんだけどね。
人通りのほとんどないここ、辺境とはいえ、公開する、ひと目につく可能性があると、それを意識することになる。
少しはマシなもの、誰かにとって有用なものが出てくる、かもしれない。

底辺とはいえ、いちおう出版社で編集なんてのをやってた昭和平成の頃、痛感したのが、ひと目に晒してナンボ、ということ。ひと目に晒すことで面白いものになるというのは事実で真実。

そんなひとり言掲示板、せっかくだからちょっと考えて名前もつけた。
「ところてんx10」
ところてん式に古いものから押し出されてなくなっていく。
保持するのは100だけ。てことで「ところTENx10」という寒いおやじギャグをドヤ顔。
「ところてんx10」

てのはともかく、みけさんがいなくなると、時間を持て余すんでスクリプトをいじる時間に当ててるだけっちゃだけのそれだけの話でもあるなあ。

»電子書籍制作代行についてはこちら

twitterが使えなくなった

2023/6/29 [01:44:56] (木) 天気

twitterのapiが昨日あたりから死んでる。認証で弾かれて使えない状態。
ていうか。APIの仕様が変わったらしくあちこち阿鼻叫喚の様相。呆れたというかツイッターにはうんざりげんなり。

twitterは、web本棚で本棚に本を登録した時に書名をツイートしたり、本棚アカウントにリプライして、自分の本棚を検索したり、といったことで利用している・していた。

ガラケーの時に、自分の本棚を開いても、検索したりする状況で、あのチマチマした画面が使いにくくてうっとーしーったらありゃしない。なもんで、ツイッターを利用することにした。

…という経緯でもあるんで、ガラケーが終了してスマホ前提なら画面、UI的なことは、それほど問題じゃない。web本棚のツイートについて確認してみるとほぼ利用実態もない。公開しているサービスの一部を取り止めにするのは、サービスレベルの低下だろ、と言われるとごめんなさい、だけど、この際、いろいろ不明、不透明なツイッター依存は取り止めにするしかない。

PC版
image
スマホ版
image
趣味は読書2 https://doncha.net/
このWEB本棚で、ツイッターを使う、ツイッターのAPIを使ってる部分をばっさり削除してまわった。
何度も言ってる、というか何度も自画自賛するんだけど。
このWEB本棚は実によくできていて、役割分担単位でのモジュール設計のおかげで、ツイッターが絡んでるところを排除するのもスグだった。これを作った17年前の自分を褒めてあげたい。

んで、身も蓋もないことをぶっちゃけると。
このWEB本棚は「あれ?これって読んだっけ?持ってなかったっけ?」
の確認をどこでもしたいという、かなりしょぼいところが始まり。
なので、元々は「既読・未読」の分類だけ。そのほかの機能はオマケ。

読んだことさえ忘れることがあるんで、買っただけで積んでる本はまったく覚えてない。本屋さんで書棚を眺めていて、を!これは面白そうじゃん!と思って、あれ?ひょっとしてもう読んでたり買ってたりしてないか?実際、部屋には同じ本が2冊あったりするわけで。
それにはネットでアクセスできる自分の本棚が重宝する。
という自分都合でやってるということもあるからこそ、20年近くも続いてる。

ツイッターは行政なんかの公的機関も通信インフラとして使ってる。
私企業に依存してるととんでもないことになる良い例というか悪い例というか。FacebookもLINEも同じ穴のなんちゃら。
ツイッターの今の状態はとても健全とは思えないんで、政府・行政は自前、内製で使いやすい通信インフラを構築する時じゃないかな。

[06/29 12:17:18]追記
とか、のんきなコトを書いてる場合じゃなかった。

2011年11月に公開した同人誌応援サイト「創作文芸見本誌会場HappyReading」の方は、サイトを閉鎖せざるを得なかった。
Twitterアカウントでログインして本を登録するサイトなんだけど、ログインできなくなってるよ、と嫁さんに聞かされてビックリ。OAuth認証は生きてると聞いてたのに、それもダメになったのか。てことは利用しようにも利用できない状態。ほんと困った、というか弱った。なんでまたそんな根本的な部分を使えなくするんだか。
しかたがないので、トップページにお知らせを上げて、サイトの閉鎖作業。

WEB本棚の方はメールアドレスで登録、ログインすることにしてるんだけど、実はこれもあやしい、かな。メールアドレスは個人情報にあたるので本当ならPマークなんてのが必要となる、はず。ただ、このサイトを「業」としてやってない、個人の趣味の範囲だから大丈夫かなあ、と思ってるんだけど、ツッコミというか突っ込まれどころかもしれん、か。

いろいろ面倒な時代になったなあ。

»電子書籍制作代行についてはこちら

スパイダーマンとか古処誠二とか

2023/6/27 [17:57:36] (火) 天気

昨日はスパイダーマン・アクロス・ザ・スパイダーバース
いやもう評判以上で2時間半ほどもうバクバクうるうるしっぱなしだった。
大切なひとを守るために頑張っていて、大切なひとを守るために頑張ってるひとを全力で応援するひとたちがいて、という王道、ド直球。
昔っからわたしは家族の話に抵抗力がなくて、すぐに涙腺がイッてしまう。
そこにもってきて、週刊少年ジャンプだ。仲間が集結して応援するんだからもういかんかった。

マルチバースの均衡を保つためvs家族もマルチバースも守るため、という図式。
ツッコミどころとしては、え?それってミゲルが始めちゃったんじゃないの?というのがあって、グウェンのお父さんの仕事が?ピーターの子供にも?とかとかネタバレになるのであまり触れない。

キャラ的には今回の新キャラ、ドレッドヘアのホビーが美味しいところをもってく。もろ好みのタイプだった。

今日は古処誠二『敵前の森で』
やっぱ間違いないがないなあ。傑作。
最近の古処誠二は『ルール』や『七月七日』の頃のようなウエットなところがないんだけど、みんながみんな、その時その場での自分の最善を尽くしたその結果、という軸はブレず、本書もホント熱い。冒頭、佐々塚兵長のエピソードで始まるプロローグがめっちゃ効いてくる。というかみんなの行動原理がここに集約されてたんだということに最後まで読んで改めて気づかされて、じわ〜っと滾る。

良いフィクションの摂取ができた昨日今日だった。
て、2作ともわたし狙い撃ちされてた。

明日から週末にかけてはシフト仕事。
これがもうさすがに体力の限界なんだよなあ。朝シフトは4時起きだし、夜シフトは帰宅が0時を回る。還暦の体力でこんなシフトは無理。健康保険加入で人間ドックなんかがありがたいというか美味しいんだけど、そもそも健康を害するようなシフトなわけで、改めて見直すとこれって本末転倒。

てなことを今まではツイッターなどSNSでたらたら書き散らしてたんだけど。
みけさんもいなくなり、世界に向けて発信するぞ!みたいなこともないんで、昔に戻ってこっちに引きこもることにした。
SNS利用はこの雑記帖更新告知と、ゲームを進めるために作ったポケモンGOのツイッターアカウントだけにする。

ちょっと前にも書いたように、この雑記帖なら、書き散らかしたコンテンツの管理も自分でコントロールできるし、呆けてしまったり、死んでしまったりしたら、レンサバとの契約が切れてそれっきりで後腐れもないしねー

 

»電子書籍制作代行についてはこちら

profile

profile

 
doncha.net
contact:
»運営者
@t2aki@tokoroten.doncha.net

ところてんx5

2024/7/22 01:29

あと下ネタも気をつけないとマズい。底辺の頃のネタを21世紀のいま出したら危険過ぎる。シャレにならんだろう

2024/7/22 01:27

気持ちいいんだろうとは思う。けど不毛だなあ。おれも気をつけよう

2024/7/22 01:26

さらっとリアクション見ただけでも、拡散されたポストに対してマウントを取りたいだけのポストもチラホラ

検索
<<2024/7>>
 123456
78910111213
14151617181920
21222324252627
28293031

リンク

WINDOWS版サウンドノベル
おかえりください PC WINDOWS版サウンドノベル
『おかえりください』体験版

[498 Page]« »
1 2 3 4 5 6 7 8 9 10

TOTAL:2984

2024 (7)
1 (2)
2 (2)
3 (1)
5 (1)
7 (1)
2023 (53)
1 (1)
2 (5)
3 (1)
4 (1)
5 (3)
6 (9)
7 (9)
8 (6)
9 (5)
10 (3)
11 (2)
12 (8)
2022 (16)
1 (1)
3 (2)
6 (2)
7 (1)
8 (4)
9 (2)
10 (1)
11 (2)
12 (1)
2021 (12)
1 (3)
2 (1)
6 (1)
8 (2)
9 (1)
10 (1)
11 (2)
12 (1)
2020 (18)
1 (2)
2 (6)
4 (1)
6 (1)
7 (2)
8 (2)
12 (4)
2019 (17)
1 (3)
2 (4)
3 (2)
4 (2)
5 (1)
6 (1)
8 (1)
10 (1)
12 (2)
2018 (21)
1 (3)
2 (2)
3 (2)
4 (1)
5 (1)
6 (6)
8 (1)
9 (1)
10 (2)
12 (2)
2017 (32)
1 (2)
2 (1)
4 (2)
5 (1)
6 (6)
7 (3)
8 (5)
9 (3)
10 (2)
11 (2)
12 (5)
2016 (41)
1 (5)
2 (5)
3 (2)
4 (3)
5 (4)
6 (6)
7 (2)
8 (2)
9 (3)
10 (1)
11 (4)
12 (4)
2015 (99)
1 (11)
2 (12)
3 (9)
4 (6)
5 (8)
6 (8)
7 (3)
8 (5)
9 (16)
10 (6)
11 (1)
12 (14)
2014 (112)
1 (16)
2 (5)
3 (6)
4 (12)
5 (16)
6 (19)
7 (9)
8 (6)
9 (4)
10 (8)
11 (6)
12 (5)
2013 (145)
1 (24)
2 (15)
3 (18)
4 (23)
5 (14)
6 (11)
7 (7)
8 (11)
9 (5)
10 (4)
11 (6)
12 (7)
2012 (103)
1 (1)
2 (1)
3 (4)
4 (3)
5 (7)
6 (26)
7 (17)
8 (5)
9 (8)
10 (10)
11 (11)
12 (10)
2011 (54)
1 (4)
3 (7)
4 (4)
5 (14)
6 (6)
7 (3)
8 (3)
9 (1)
10 (4)
11 (2)
12 (6)
2010 (70)
1 (12)
2 (7)
3 (6)
4 (6)
5 (3)
6 (10)
7 (6)
8 (4)
9 (3)
10 (4)
11 (3)
12 (6)
2009 (144)
1 (15)
2 (12)
3 (12)
4 (6)
5 (15)
6 (6)
7 (10)
8 (9)
9 (17)
10 (12)
11 (14)
12 (16)
2008 (148)
1 (10)
2 (6)
3 (10)
4 (11)
5 (13)
6 (10)
7 (13)
8 (19)
9 (18)
10 (12)
11 (13)
12 (13)
2007 (106)
1 (7)
2 (5)
3 (3)
4 (7)
5 (5)
6 (9)
7 (8)
8 (13)
9 (18)
10 (11)
11 (8)
12 (12)
2006 (158)
1 (28)
2 (28)
3 (25)
4 (7)
5 (9)
6 (7)
7 (12)
8 (13)
9 (10)
10 (7)
11 (6)
12 (6)
2005 (350)
1 (31)
2 (26)
3 (26)
4 (27)
5 (29)
6 (30)
7 (32)
8 (30)
9 (30)
10 (32)
11 (29)
12 (28)
2004 (292)
1 (24)
2 (24)
3 (29)
4 (27)
5 (28)
6 (25)
7 (26)
8 (24)
9 (12)
10 (19)
11 (26)
12 (28)
2003 (318)
1 (22)
2 (25)
3 (21)
4 (28)
5 (28)
6 (28)
7 (28)
8 (29)
9 (26)
10 (29)
11 (28)
12 (26)
2002 (317)
1 (29)
2 (26)
3 (26)
4 (25)
5 (28)
6 (30)
7 (27)
8 (21)
9 (25)
10 (27)
11 (28)
12 (25)
2001 (277)
1 (17)
2 (21)
3 (23)
4 (20)
5 (31)
6 (18)
7 (26)
8 (25)
9 (29)
10 (19)
11 (24)
12 (24)
2000 (53)
6 (9)
7 (4)
8 (2)
9 (3)
10 (1)
11 (15)
12 (19)
1999 (3)
7 (1)
10 (2)
1998 (18)
9 (9)
10 (7)
11 (2)