このブログの中を検索する

2012/09/23

Googleが予想するあなたの年齢、性別、興味が意外と当たる

title: Googleが予想するあなたの年齢、性別、興味が意外と当たる
url: http://toomva.blog60.fc2.com/blog-entry-390.html
https://www.google.com/settings/ads/onweb/?hl=ja

snippet:
-----引用-----

自分が閲覧したサイトから、Googleが興味/関心のあるカテゴリ、年齢、性別、言語などを推定して、Googleのwebページからこれらの推定結果を知ることができます。

以下のアドレス
https://www.google.com/settings/ads/onweb/?hl=ja
にアクセスするだけ。

-----引用-----

Word2007の数式ツールはTeX形式の入力ができる (例: 積分は¥int^[上]_[下][スペース]で簡単に作れる)

title: Word2007の数式ツールはTeX形式の入力ができる (例: 積分は¥int^[上]_[下][スペース]で簡単に作れる)
url: http://www.sunmattu.net/?p=84

snippet:
-----引用-----

Microsoft Office Wordには、Word2003までは数式を書くための数式エディタというツールが、不便ながらもついていました。2003までの標準添付ツールはMathtypeの機能限定版でした。しかし、Word 2007からは、数式を扱う新しい機能が標準装備されました。

Word2007の数式ツールは、記号などはTeX形式の入力ができたりもするので(たとえば、¥times[スペース]と打つと(¥は半角)、×(かけ算)に自動的に変換してくれたり、 ¥alpha[スペース]でαが出てきたり…Σ記号や積分記号も¥int^[上]_[下][スペース]で簡単に作れたりします)、TeXにちょこっと慣れてる人はすぐ使いこなせます。

-----引用-----

Microsoft Word 2010のMathアドイン : 数学を解いたり、グラフを描画して、Word内に結果を張り付けるツール

title: Microsoft Word 2010のMathアドイン : 数学を解いたり、グラフを描画して、Word内に結果を張り付けるツール
url: http://www.sunmattu.net/?p=84
http://www.microsoft.com/japan/athome/umall/math/features.aspx
http://www.microsoft.com/downloads/en/details.aspx?displaylang=en&FamilyID=ca620c50-1a56-49d2-90bd-b2e505b3bf09

snippet:
-----引用-----

Word 2007 の Microsoft Math アドインを使用すると、次の操作が可能です。
  • 関数や数式 (等式および不等式) を 2-D または 3-D でプロットする
  • 数式 (等式および不等式) を解く
  • 数値結果を計算する
  • 代数式を簡約する

-----引用-----

チケット駆動開発入門 (ツール: Redmine、Trac)

title: チケット駆動開発入門 (ツール: Redmine、Trac)
url: http://www.slideshare.net/rrrkitamura/13-1647261

snippet:
-----引用-----

  • 「はじめにチケットありき。」 
  • 「チケットなしの作業禁止。」 
  • チケットがない作業は闇作業。
  • 「チケットなしのコミット禁止。」 
  • チケットがないコミットは闇コミット。
  • チケットにより作業のインプット・原因・「なぜ」を明確にする。
  • 作業説明のお供にチケットを。
  • 作業メモもチケットに記録していく。

-----引用-----

RedmineやTracを上手に活用する6つのポイント

title: RedmineやTracを上手に活用する6つのポイント
url: http://htakeuchi.offtheball.jp/archives/2590

snippet:
-----引用-----

ポイント1
「どの情報をどのように見てマネジメントするか」から逆算してチケット項目を決定しましょう。できる限りシンプルに

ポイント2
  • 誰がチケットを起票しどのように担当者をアサインするか
  • チケットのクローズ条件
  • チケットの各項目(優先度、マイルストーンなど)へどのような情報を入力するか
などのチケット運用ルールを事前に定義、メンバーへ周知

ポイント3
  • 終了しているはずのチケットが閉じられていない
  • 誰にもアサインされていないチケットが放置されている
このような状況は非常に危険です。
メンバーがチケットの運用に慣れるまでは週次でチケットの棚卸を行う。

ポイント4
期限切れのチケットを放置厳禁

ポイント5
メールでやりとりされた内容、口頭で交わした内容などもチケットへ記入する習慣を
代わりに、メンバはチケットだけを入力すれば良いルールにして。

ポイント6
チケットの担当者が能動的にチケットを処理し、クローズまで責任を持って担当する土壌を作る。

-----引用-----

Eclipse Xtext : DSLの開発を容易にするためのフレームワーク、オリジナルのプログラミングを簡単に作成できる

title: Eclipse Xtext : DSLの開発を容易にするためのフレームワーク、オリジナルのプログラミングを簡単に作成できる
url: http://legacy-style.blogspot.jp/2011/08/xtext.html
http://www.openarchitectureware.org/pub/documentation/4.3/html/contents/xtext_tutorial.html
http://www.youtube.com/watch?v=oN74qLb66xs

snippet:
-----引用-----

Eclipse Foundationによって開発されているEclipseプラグインのひとつに「Eclipse Xtext」というものがある。Eclipse XtextはDSLの開発を容易にするためのフレームワーク/ツールキットであり、これを利用すればオリジナルのプログラミングを簡単に作成することができる。

-----引用-----

2012/06/20

AvalonEdit : SharpDevelop 4.0で使用されているWPFで作られたText Editorコンポーネント

title: AvalonEdit : SharpDevelop 4.0で使用されているWPFで作られたText Editorコンポーネント
url: http://www.codeproject.com/Articles/42490/Using-AvalonEdit-WPF-Text-Editor

snippet:
-----引用-----

ICSharpCode.AvalonEdit is the WPF-based text editor that I've written for SharpDevelop 4.0. It is meant as a replacement for ICSharpCode.TextEditor, but should be:

Extensible
Easy to use
Better at handling large files

-----引用-----

Haxe : JavaScript、C++などへソースコードを変換できる上位の汎用プログラミング言語

title: Haxe : JavaScript、C++などへソースコードを変換できる上位の汎用プログラミング言語
url: http://d.hatena.ne.jp/mzp/20120604/jsx
http://ja.wikipedia.org/wiki/Haxe

snippet:
-----引用-----

Haxe(ヘックス、発音記号は /heks/[1][2])は汎用プログラミング言語の一つである。静的型付けのオブジェクト指向言語であり、構文はActionScriptおよび標準化が中止されたECMAScript 4に類似している。Adobe Flashおよび独自のVM(Neko)で実行可能なバイトコードにコンパイルされるほか、JavaScript、ActionScript、C++、PHPへのソースコードの変換が可能であるため、主にクロスプラットフォーム開発を目的として使用される。また、FlashからHTML5への移行にも使用される。

-----引用-----

CPUで、L1キャッシュでのアクセスミスは数十クロックのペナルティー、L2キャッシュは100クロックぐらいのペナルティー

title: CPUで、L1キャッシュでのアクセスミスは数十クロックのペナルティー、L2キャッシュは100クロックぐらいのペナルティー
url: http://research.preferred.jp/2012/06/centroid-path-decomposition/
http://download.intel.com/jp/developer/jpdoc/248966-024JA.pdf
http://jp.xlsoft.com/documents/intel/seminar/2_Sofrware%20Optimize.pdf

snippet:
-----引用-----

インテルのマニュアルには「分岐予測ミスには、約 20 サイクルのペナルティーが課せられる。」とあります。
L1キャッシュでのアクセスミスは数十クロックのペナルティーが生じる」「L2キャッシュでのアクセスミスは数十バスクロックのペナルティーが生じる」とあります。バスクロックということはCPUクロックに直すと3倍とか5倍とかの数字になりますから、L2キャッシュミスが発生すると、CPUからみると100クロックぐらいは待たされることになります。

-----引用-----

perf : CPUの分岐予測の失敗、キャッシュミスをカウントするプロファイラ、Linux用

title: perf : CPUの分岐予測の失敗、キャッシュミスをカウントするプロファイラLinux用
url: http://research.preferred.jp/2012/06/centroid-path-decomposition/

snippet:
-----引用-----

perfは最近のCPUの機能がいろいろ使えるようになっているすごいプロファイラです。ビルドしなおしたりせずに使えるので、お手軽簡単でもあります。Linuxを使っているのであれば一度試しておく価値があるでしょう。Debian/Ubuntuであればapt-get install linux-toolsでインストールできます。

例:
   1,006,797,327 cache-references
       672,031,146 cache-misses              #   66.749 % of all cache refs
    15,364,571,222 branch-instructions
       389,161,442 branch-misses             #    2.53% of all branches
    67,849,694,976 instructions              #    0.59  insns per cycle
   114,053,128,530 cycles                    #    0.000 GHz
 
IPC(1クロックあたりの実行命令数、insns per cycleのところの数値です)

IPCの向上を阻害する要因は(おそらく)たくさんありますが、分岐予測の失敗、メモリもしくはIOなど遅いデバイスへのアクセス、の2つが大きな原因となり得るでしょう。上記の例では分岐予測の失敗は2.5%程度、キャッシュミスの割合は67%程度です。

-----引用-----

NUnitで複数ケースを実装する方法

title: NUnit複数ケースを実装する方法
url: http://codezine.jp/article/detail/6590?p=2

snippet:
-----引用-----

using NUnit.Framework;
using CsTdd04.FizzBuzz;

namespace CsTdd04.FizzBuzzTest {
  [TestFixture]
  public class FizzBuzzerTest {
    [TestCase(1, "1")]
    [TestCase(3, "Fizz")]
    [TestCase(5, "Buzz")]
    [TestCase(6, "Fizz")]
    [TestCase(9, "Fizz")]
    [TestCase(10, "Buzz")]
    [TestCase(12, "Buzz")]
    [TestCase(15, "FizzBuzz")]
    public void SayTest(int n, string expected) {
      Assert.That((new FizzBuzzer()).Say(n), Is.EqualTo(expected));
    }
  }
}

-----引用-----

「Initializr」でHTML5サイトのテンプレートを作成

title: 「Initializr」でHTML5サイトのテンプレートを作成
url: http://news.mynavi.jp/column/ide/130/index.html

snippet:
-----引用-----

Initializerデモの作成に利用してもよいし、本格的なWebサイトやWebアプリケーションを構築するためのベースにすることもできるだろう。うまく活用することで、HTML5を使用したサイトを構築するための手間を大きく削減できるはずだ。また、HTML5の利用にあたり、先人達のノウハウを利用できるという点も大きなメリットといえるだろう。

-----引用-----

Google Data APIを.NETで使用するための開発者ガイド、コードサンプル

title: Google Data APIを.NETで使用するための開発者ガイド、コードサンプル
url: https://sites.google.com/site/copypesouko/--manyuaru/netclientlibra2

snippet:
-----引用-----

.NETクライアントライブラリ開発者ガイド

このドキュメントはGoogle Data API("GData")質問を送って、返された応答を解釈するのに.NETクライアントライブラリを使用する方法を説明します。

チュートリアルと例

以下の例は、C#クライアントライブラリを使用することでどのように様々なGData要求を送るかを示しています。
それらをより具体的にするように、これらの例は、どのように特定のサービス:Googleカレンダー と対話するかを示しています。 私たちはCalendarがあなたが他のサービスで使用のためのこれらの例を適合させるのを助けるために他のGoogleサービスと異なっている場所を指摘するつもりです。Calendarに関する詳しい情報に関しては、Google Calendar Data APIドキュメントを見てください。
あなたのクライアントを構築して、走らせます。
このドキュメントの例をコンパイルするには、次のusingステートメントを使用する必要があります:

using Google.GData.Client;

フィードを要求

Google Calendar Data APIドキュメントで説明されるように、あなたは以下のHTTP要求をCalendarに送ることによって、Calendarフィードを要求できます:
GET http://www.google.com/calendar/feeds/userID/private/full
もちろん、あなたは userID をユーザのEメールアドレスに取り替えなければなりません。 詳細のためのCalendarドキュメントを見てください。あなたは、Calendarと対話するのに代わりに特別なデフォルトURLを使用できますが(Calendarドキュメントで説明されるように)、本書では私たちは private full feed URL を使用するつもりです。(それは、ユーザIDを含みます)。
また、あなたは適切な認証を提供しなければなりません。ウェブアプリケーションにおける、使用ではなく、デスクトップクライアントなどのインストールされたクライアントアプリケーションにおける使用だけに、私たちがここ(「インストールされたアプリケーションのためのGoogle認証」として、知られている)で使用している認証システムが適切であることに注意してください。認証に関する詳しい情報に関しては、 Google Account Authentication ドキュメンテーションを見てください。

ユーザにEメールアドレス" jo@gmail.com "とパスワード"mypassword"でC#クライアントライブラリを使用することでCalendarフィードを要求するには、以下のコードを使用してください:

// クエリーとサービスオブジェクトを作成してください:

FeedQuery query = new FeedQuery();
Service service = new Service("cl", "exampleCo-exampleApp-1"));
// あなたの証明書を設定します:
service.setUserCredentials("jo@gmail.com", "mypassword");

// クエリーオブジェクトを作成してください:
query.Uri = new Uri("http://www.google.com/calendar/feeds/jo@gmail.com/private/full");

// 以下についてクエリーするようにサービスに命令します。
AtomFeed calFeed = service.Query(query);

 Service のクラスはクライアント接続(認証がある)のGDataサービスに代理をします。クライアントライブラリを使用することで質問をサービスに送るための基本手順は以下のステップから成ります:
適切なURLを得るか、または構成してください。
データをサービスに送るなら(あなたが例えば新しいエントリーを挿入しているなら)、クライアントライブラリのクラスを使用することで生データをオブジェクトに変えてください。(あなたがただフィードを要求しているなら、私たちがこの例でしているように、このステップは適用されません。)
サービス名(Calendarのための「Cl」などの)とあなたのアプリケーションの名前を設定して、新しいServiceインスタンスを作成してください。(このフォームで。companyName-applicationName-versionID).
適切な証明書を設定してください。
リクエストを送信し、任意の結果を受け取るメソッドを呼び出します。
 service.setUserCredentials メソッドは標準の.NET Network資格証明書オブジェクトで service.Credentials の特性の用意をします。 資格証明書はあなたのクライアントがだれの代理にクエリーを送るかときのユーザのIDとパスワードへのセットです。 例は本書では「Authentication for Installed Applications」認証システムを使用します。 他の認証システムに関する詳しい情報に関しては、Google Account Authentication ドキュメンテーションを見てください。
全体のフィードを要求するために、あなたは service.Query メソッドを呼びます。(それは、 FeedQuery オブジェクトを取って、そのURLで見つけられた全体の給送を返します)。私たちは、後でどのように本書ではより特定のクエリーを送るかを示すつもりです。
 Service のクラスの他のメソッドのように、 Query は認証を扱って、必要に応じて向け直します。

新しい項目を挿入する

カレンダーフィードにアイテムを挿入するには、次のコードを使用する場合があります:

AtomEntry entry = new AtomEntry();
AtomPerson author = new AtomPerson(AtomPersonType.Author);
author.Name = "Jo March";
author.Email = "jo@gmail.com";
entry.Authors.Add(author);
entry.Title.Text = "Tennis with Beth";
entry.Content.Content = "Meet for a quick lesson.";

Uri postUri = new Uri("http://www.google.com/calendar/feeds/jo@gmail.com/private/full");

// 要求を送ってください、そして、応答を受けてください:
AtomEntry insertedEntry = service.Insert(postUri, entry);

URLを設定した後に、私たちは、 AtomEntry オブジェクトを組み立てます。
エントリータイトルは、 AtomTextConstruct、様々なフォーム(プレーンテキスト、HTML、またはXHTML)でテキストをつかむクラスです。エントリー内容は AtomContentオブジェクトによって表されます、プレーンテキストかフォームのどちらかの、他の中身を保持できるクラス、XMLとバイナリ・データを含んでいます。
各作者は名前、URI、およびEメールアドレスとして代理をされます。 (この例では、私たちはURIを省いています。)  あなたは、エントリーの Authors 収集に AtomAuthor オブジェクトを追加することによって、エントリーに作者を加えます。
私たちは私たちが前の例で作成したのと同じ Service オブジェクトを使用しています。この場合、呼ぶためのメソッドは Insertです。(そのInsertは指定された挿入URLにアイテム を送ります)。
サービスは新たに作成されたエントリーを返します、エントリーへの編集URLのように。(エントリーは追加サーバで発生している要素を含むかもしれません)。
上のコードは POST http://www.google.com/calendar/feeds/jo@gmail.com/private/full (適切な認証がある)を送って、エントリーを提供するのに同等です。

特定のエントリーを要求します。

以下のコードで、あなたは前の例に挿入した特定のエントリーを要求できます。
このシリーズの例の文脈では、そのエントリーを検索するのは本当に必要ではありません、Calendarが既に挿入されたエントリーを返したので。 しかし、あなたがURLをエントリーに知っているときはいつも、同じテクニックを適用できます。

FeedQuery singleQuery = new FeedQuery();
singleQuery.Uri = new Uri(newEntry.SelfUri.ToString());
AtomFeed newFeed = service.Query(singleQuery);
AtomEntry retrievedEntry = newFeed.Entries[0];

挿入されたエントリーには、特性、 ToString() メソッドを使用して、新しいURIオブジェクトを作成するのに使用できる AtomUri オブジェクトを返す SelfUri があります。
次に、私たちはただ新しいAtomFeedオブジェクトを手に入れるためのサービスの Query メソッドを呼ばなければなりません、Entries収集におけるちょうど1つのエントリーで。
上のコードは適切な認証と共に GET http://www.google.com/calendar/feeds/jo@gmail.com/private/full/entryID  をCalendarに送るのに同等です。

エントリの検索

フルテキスト検索で最初に一致したものを取得するには、次のコードを使用します:

FeedQuery myQuery = new Query(feedUrl);
myQuery.Query = "Tennis";
AtomFeed myResultsFeed = myService.Query(myQuery);
if (myResultsFeed.Entries.Count > 0) {
  AtomEntry firstMatchEntry = myResultsFeed.Entries[0];
  String myEntryTitle = firstMatchEntry.Title.Text;
}

この例は、 FeedQuery オブジェクトを組み立てることによって、始まります。(オブジェクトはほとんどURLと関連質問パラメータから成ります)。それぞれの標準のGData クエリーパラメータに、特性があります。
 FeedQuery を組み立てた後に、私たちは、サービスの Query 方法にそれを通過します。(それは、クエリー結果を含むフィードを返します)。 代替的アプローチが自分でURLを構成して(フィードURLにクエリーパラメータを追加することによって)、次に、 Query 方法を呼ぶだろうことですが、 FeedQuery 方法が役に立つ層の抽象化を提供するので、あなたは自分でURLを構成する必要はありません。
フィードの Entries 収集は給送におけるエントリーのリストを返します。 Entries.Count はフィードにおける、エントリーの数を返します。
この場合、クエリーが何か結果を返したなら、私たちは、最初の合う結果を AtomEntry オブジェクトに割り当てます。そして、私たちは、エントリーのタイトルを検索するのに AtomEntry のクラスの Title プロパティを使用します。
上のコードは GET http://www.google.com/calendar/feeds/jo@gmail.com/private/full?q=Tennis をCalendarに送るのに同等です。

カテゴリ別の照会

Note: Google Calendarがラベルをイベントに関連づけないので、この例はCalendarで動作しません。
以前の全文検索に合って、特定のカテゴリにあるすべてのエントリーから成るフィードを検索するか、または特定のラベルを持つには、以下のコードを使用してください:

AtomCategory myCategory = new AtomCategory("by_jo");
QueryCategory myCategoryFilter = new QueryCategory(myCategory);
myQuery.Categories.Add(myCategoryFilter);
AtomFeed myCategoryResultsFeed = myService.Query(myQuery);

 AtomCategory のクラスは、カテゴリフィルタで使用されるためにもちろんカテゴリを表します。 QueryCategory のクラスは複数のカテゴリを含むことができますが、この場合、私たちは、1つのカテゴリだけがあるフィルタを組み立てています。
そして、私たちは既存のクエリーにそのフィルタを加えます。(まだ、それは、前の例からの全文クエリーストリングを含んでいます)。
私たちは再び質問をサービスに送るためのQueryメソッドを使用します。
Calendarがカテゴリ検索を許すなら、上のコードは GET http://www.google.com/calendar/feeds/jo@gmail.com/private/full/-/by_jo?q=Tennis をCalendarに送るのに同等でしょう。

アイテムを更新

既存の項目をアップデートするには、以下のコードを使用してください。 以下の例では、私たちは以前に検索されたエントリーのタイトルを古いテキスト(「ベスがいるテニス」)から「重要なミーティング」に変えています。

retrievedEntry.Title.Text = "Important meeting";
retrievedEntry.Update();

まず最初に、私たちは、私たちが、より早くとって来たエントリーのための新しいタイトルを設定します。 そして、私たちは、 Upate をただアップデートされたエントリーをサービスに送るためのメソッドと呼びます。
サービスはアップデートされたエントリーを返します、このエントリーの新しいバージョンのための新しいURLを含んでいます。(エントリーバージョンの詳しい情報に関して、protocol reference document の Optimistic concurrency 部を見てください)
上のコードはおよそ元のエントリーを取り替えるために新しいエントリー(Atomフォーマットにおける)と共に  PUT http://www.google.com/calendar/feeds/jo@gmail.com/private/full/entryID  をサービスに送るのに同等です。

アイテムを削除する

既存の項目を削除するには、以下のコードを使用してください:

updateEntry.Delete();

削除に使用するURLは編集URLと同じです、したがって、この例が前のものと非常に同様です、もちろんそれを除いて、私たちが Update の代わりに Delete メソッドを呼んでいます。
上のコードはおよそ DELETE http://www.google.com/calendar/feeds/jo@gmail.com/private/full/entryID をサービスに送るのに同等です。

-----引用-----

2012/06/19

F#では変数を導入する箇所では常にパターン・マッチとなる

title: F#では変数を導入する箇所では常にパターン・マッチとなる
url: http://www.atmarkit.co.jp/fdotnet/special/introfs_02/introfs_02_01.html

snippet:
-----引用-----

「『let』の位置でパターン・マッチができる」とか、「関数の位置でパターン・マッチができる」(つまり、パターン・マッチは特別なもの)と考えるよりも、「『let』も引数もパターン・マッチしているのだ」と考えた方が自然だ。つまり、

let n = 42  // この「n」は変数パターン
let f x = x // 引数の「x」も変数パターン
「let」も引数も変数パターン

ということだ。このように、F#では変数を導入する箇所では常にパターン・マッチとなる。

これまで見たように、パターン・マッチを使うと、値からデータを取り出すコードが素直に書ける。さらに注目してほしいのは、値を作るときと同じ書き方で値を取り出せるという点だ。このように構築と分解を統一した表記で扱えるのも、パターン・マッチの特長だ。

-----引用-----

F# option型は「値がないかもしれない」ということを型として明示する

title: F# option型は「値がないかもしれない」ということを型として明示する
url: http://www.atmarkit.co.jp/fdotnet/special/introfs_02/introfs_02_01.html

snippet:
-----引用-----

最も厄介なのは、nullというのは(null許容型を除くと)型に現れないことだ。nullは参照型であればどんな型の値にもなり得る。そのため、null参照によるエラーというのは実行してみるまで分からない。これは、nullが来るかどうかの判定をプログラマーが抜け・漏れなく正確に管理する必要があるということを意味する。

それに対してoption型は「値がないかもしれない」ということを型として明示できる。さらに、string option型と、単なるstring型は全く別の型であるため、そのままではstring型として使えない(オプションを要素が1つだけ入るリストと考えれば分かりやすいだろう)。そして、string option型の変数から、中に含まれている値を取り出す場合は、常に値がない可能性を考慮する必要がある。

これらの特徴により、F#ではnullよりも安全に「値がないかもしれない」という事象を扱うことができる。次のコードは、string option型の変数を、string型として扱おうとしているコード例だ。このコードはコンパイル・エラーになる。

let x = Some "hoge" // string option型の変数「x」
// これはコンパイル・エラー
//let ans = x.IndexOf("o")
↑string option型の変数を、string型として扱おうとしてエラーになるコード例

-----引用-----

F#の判別共用体は、ある種のクラス階層を表すために使える

title: F#の判別共用体は、ある種のクラス階層を表すために使える
url: http://www.atmarkit.co.jp/fdotnet/special/introfs_02/introfs_02_01.html

snippet:
-----引用-----

F#の判別共用体は、ある種のクラス階層を表すために使える。

例えば、ファイルとディレクトリを判別共用体で表してみよう。次のコードがその例だ。

// 簡単のため、ファイルはファイル名とサイズのみを持っているとする
type FileSystemEntry =
  | File of string * int
  | Dir of string * FileSystemEntry list
↑ファイルとディレクトリを判別共用体で表した例

※定義した「FileSystemEntry」型を、Dirケースの値の型としても定義しているところがポイント。
このコードでは、「File」と「Dir」という2つのケースを持つ判別共用体としてFileSystemEntry型が定義されている。File/Dirケースの値の型は、「of」以下に記載されている。このコード例では、Fileケースが保持する型はstring型とint型であり、Dirが保持する型はstring型とFileSystemEntry型リストである(タプルの型のように見えるが、実はタプルそのものではない。単に、複数の型を持つことを意味する)。値の型の中で「FileSystemEntry型リスト」が使われることで、再帰的に判別共用体を格納できるので、ファイル・システムのツリー構造を表現できるというわけだ。

-----引用-----

F#でジェネリック関数を簡単に定義する

title: F#でジェネリック関数を簡単に定義する
url: http://www.atmarkit.co.jp/fdotnet/special/introfs_01/introfs_01_01.html

snippet:
-----引用-----

F#はこの「状態を持たない」方向に傾けたプログラムを書くためのサポートが手厚く、逆に「状態を持った」方向に傾けたプログラムを書くのが面倒になるように文法が構築されている。


F#は、ジェネリック関数も簡単に定義できる。例えば、

let gt x y = x < y
↑ジェネリック関数の定義例(F#)

とするだけで、C#での、

public static bool Gt<T>(T x, T y) where T : IComparable<T>
{
  return x.CompareTo(y) < 0;
}
↑ジェネリック関数の定義例(C#)

と同じようなものが定義できる。gt関数の型を推論するときに、比較演算子がジェネリックな演算子として定義されているため、gt関数の型も比較演算子同様、ジェネリックと判断されたのだ。

-----引用-----

Try F# : Webから利用可能なF#の対話的実行環境

title: Try F# : Webから利用可能なF#の対話的実行環境
url: http://tryfs.net/
http://www.atmarkit.co.jp/fdotnet/special/introfs_01/introfs_01_01.html

snippet:
-----引用-----

F#に標準搭載されている対話環境を使う。Visual Studio 2010がインストールされているものとして進める。インストールしていない場合は、「Try F#」を使うのが一番手っ取り早いだろう。

-----引用-----

MathJax : LaTeX方式で数式を書いてホームページに数式を表示するライブラリ

title: MathJax : LaTeX方式で数式を書いてホームページに数式を表示するライブラリ
url: http://genkuroki.web.fc2.com/

snippet:
-----引用-----

簡単な使い方:次を HTML ファイルの <head> と </head> のあいだに挿入する。それだけで LaTeX 方式で数式を書けるようになる。

<script type="text/x-mathjax-config">
  MathJax.Hub.Config({ tex2jax: { inlineMath: [['$','$'], ["\\(","\\)"]] } });
</script>
<script type="text/javascript"
  src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML">
</script>
<meta http-equiv="X-UA-Compatible" CONTENT="IE=EmulateIE7" />

最も簡単な使い方:次を HTML ファイル中の <head> と </head> のあいだに挿入する。それだけで LaTeX 方式で数式を書けるようになる。ただし $ $ は使えない。

<script type="text/javascript"
  src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML">
</script>

使用例:

HTMLの中に、LaTeX方式で数式を書くだけで、自動的に数式表示に変換される。

<p>\(\sum_{n=1}^\infty \frac{1}{n^2} = \frac{\pi^2}{6}\)</p>
<p>\[
  \sum_{n=1}^\infty \frac{1}{n^2} = \frac{\pi^2}{6}
  \tag{3}
\]</p>

-----引用-----

Rを高速化するコーディング方法

title: Rを高速化するコーディング方法
url: http://www.anlyznews.com/2012/02/r_12.html
http://www.sciviews.org/benchmark/

snippet:
-----引用-----

1. パッケージや内部関数を使う

2. 行列演算 < apply関数 < ループ演算

対数尤度関数の記述方法と処理時間
記述方法 経過時間 行列演算比
行列演算 0.03秒 1倍
apply関数 0.48秒 16倍
ループ演算 1.11秒 37倍

6. 高速な数値演算アルゴリズムを選択する

数値演算アルゴリズムと処理時間
アルゴリズム 関数名 経過時間
GLM glm() 0.02秒
Newton-Raphson nlm() 0.03秒
BFGS optim() 0.04秒
L-BFGS-B optim() 0.04秒
Nelder-Mead optim() 0.06秒
CG optim() 0.45秒
SANN optim() 4.70秒
MCMC(Metropolis-Hastings) MCMCmetrop1R 9.61秒

7. whileよりもfor

-----引用-----

RはCに比べて100倍遅い

title: RはCに比べて100倍遅い
url: http://www.anlyznews.com/2012/02/r_11.html

snippet:
-----引用-----

Rはループ速度が段違いに遅いと言われる。確かにループとメソッド呼び出しで構成したマイクロベンチマークを実行すると、Javaが6.32秒、C++で6.33秒で終わる処理が、87時間18分16.0秒(推定値)かかったりする。S-PLUSやMatlabなどの他の同種の言語よりは高速か同等と指摘されているが、汎用言語に比べると断然遅い(Benchmark 2)。
要素が32767あるベクターx、yを引数に取り最小公倍数を返す関数をRとCでそれぞれ記述し、経過時間を計測している。内部的にループ演算で最大公約数を計算するルーチンがあり、Rで実行するのは不利な演算だ。
実行結果はRが1.193秒、Cが0.005秒の経過時間がかかり、その速度差は238.6倍となった。R側のコードは行列化してapply関数を用いるなどで、さらに高速化は可能な見込みだが、その差は100倍を切る事は無いであろう。RはCに対して圧倒的に遅い

-----引用-----

2012/05/26

GoogleでのRの書き方スタイル

title: GoogleでのRの書き方スタイル
url: http://www13.atpages.jp/t6s5/docs/r-style-guide-j.html

snippet:
-----引用-----

TODOの書式 :

コード全体を通して TODO の書式を一貫させる.
TODO(ユーザ名): 予定の行動の明確な記述

常識を使うことと一貫性を持つこと :

もしコードを編集するなら, その周辺のコードを しばらく眺めてから, その書式を決めること. もし編集しているコードが if 節の前後に 空白を入れているなら, あなたもそれにならうこと. もし, 編集しているコードは注釈がアスタリスクの四角形で囲まれているなら, 新たに加える注釈もアスタリスクの四角形で囲うこと.

書き方のガイドラインを持つ意義は, コード書きの共通語彙を持つことで, どうやって書くかに悩まされることなく何を書きたいかに 集中できることにあります. 広く使われている書き方の規則をここに示したので, その共通語彙はわかるでしょう. しかし, 一部の グループで使われている書き方も重要です. もし, あるファイルに加えようとするコードが 既存のコードから極端に異なっているなら, その不連続性により, そのコードを読もうとするひとを コードの流れの外へと追い出してしまうでしょう. これを避けるよう努力すること.

-----引用-----

Rを使えるようになるための10のこと

title: Rを使えるようになるための10のこと
url: http://d.hatena.ne.jp/isseing333/20110917/1316231082

snippet:
-----引用-----

Rを使えるようになるための10のこと

Rは全く使ったことがない!JAVAとかC++とかガリガリ書けるけどRはよく分からない!という方々がすんなりRの世界に入れるよう、資料の探し場所や導入部分をまとめておきます。

-----引用-----

10分で分かるRパッケージの作り方

title: 10分で分かるRパッケージの作り方
url: http://www.slideshare.net/yokkuns/10r

snippet:
-----引用-----

10分で分かるRパッケージの作り方

パッケージのスケルトン作成の例 :
> package.skeleton(list=c("yahooWebSearch", "yahooBlogSearch"), name="RSearchYJ")

-----引用-----

scikits.learn : 機械学習の主な手法がほとんど入っているライブラリ

title: scikits.learn : 機械学習の主な手法がほとんど入っているライブラリ
url: http://d.hatena.ne.jp/isseing333/
http://scipy-lectures.github.com/_downloads/PythonScientific-simple.pdf

snippet:
-----引用-----

機械学習を実行するにあたって、今一番アツそうなのがscikits.learnというライブラリです。これはGoogle summer codeがきっかけで立ち上がったプロジェクトで、10人を超えるエンジニアが作っているようです。トップのUser Guideの中身をひと通り目を通しましたが、主な手法はほとんど入っています!欲を言えば、アンサンブル系がもっとあって欲しいですが。上記のパッケージでPythonをインストールしていれば、追加でパッケージを入れることなく、コンソール上でコードをコピペすれば結果を再現できます。Exampleにある画像も、ほとんどコピペで作成できます!(一部、改行やコメントの影響でエラーが出ました。)R使いな私としては、こういう手軽さがとても嬉しいですね。実際にRとどう住み分けるかは、引き続き考えなきゃいけないですが。

-----引用-----

Redmineでチケットを作成→gitでコミット→JenkinsによるCI実行

title: Redmineでチケットを作成→gitでコミット→JenkinsによるCI実行
url: http://d.hatena.ne.jp/mzp/20120506/dashbozu

snippet:
-----引用-----

一般的なソフトウェア開発現場では

  • Redmineチケットを作成する
  • gitコミットを繰り返し、中央レポジトリにpushする
  • JenkinsによるCIが実行される
  • 結果を確認し、Redmineのチケットを閉じる

という流れで作業が進んでいきます。これらの作業の中で、開発者は「適切な」タイミングでチェックとフィードバックをすることを求められます。適切なタイミングとは、例えば以下のようなものです。

  • Gitでpushしたタイミング ・・・ 開発者が仕様を勘違いしていないか
  • Jenkins のビルドが完了したタイミング・・・ビルドが壊れていないか
  • Redmineのチケットのステータスが変更になったタイミング ・・・ コードレビュー

-----引用-----

2012/05/23

長期的なビジョンを持つのは、金銭的に体力がないとできない

title: 長期的なビジョンを持つのは、金銭的に体力がないとできない
url: http://ufcpp.wordpress.com/2012/05/04/%E3%81%A9%E3%81%86%E3%81%97%E3%81%A6%E3%81%93%E3%81%86%E3%81%AA%E3%81%A3%E3%81%9F/
http://www.infoq.com/jp/articles/neal-gafter-on-java

snippet:
-----引用-----

以下の記事で、「Java に足りないのは長期的なビジョンと開発リソース」というような話も出ていたり。開発リソースを割くのはもちろん、こういうインフラに対して長期的なビジョンを持つっていうのも、金銭的に体力ないとできないんですよねぇ。

Javaの未来についてのNeal Gafter氏とのディスカッション

-----引用-----


2012/05/22

MASM, Easy Code Visual assembly IDE : アセンブラ言語のIDE

title: MASM, Easy Code Visual assembly IDE : アセンブラ言語のIDE
url: http://ja.wikipedia.org/wiki/Microsoft_Macro_Assembler
http://www.grc.com/smgassembly.htm
http://www.easycode.cat/English/index.htm

snippet:
-----引用-----

アセンブラ言語のIDE :
  • MASM : Microsoft Macro Assembler(マイクロソフト・マクロ・アセンブラ)

  • Easy Code Visual assembly IDE


-----引用-----

dapper-dot-net, DbExecutor : C#のMicro-ORM

title: dapper-dot-net, DbExecutor : C#のMicro-ORM
url: http://neue.cc/2012/01/17_363.html

snippet:
-----引用-----

C#のMicro-ORM :
  • dapper-dot-net
  • DbExecutor

-----引用-----

GCC-XML : C++の構文解析結果のメタデータをXML形式で出力するツール

title: GCC-XML : C++の構文解析結果のメタデータをXML形式で出力するツール
url: http://ufcpp.wordpress.com/2011/12/20/cxxi/

snippet:
-----引用-----

GCC-XML : C++構文解析結果のメタデータをXML形式で出力するツール

-----引用-----

銀の弾丸はない : 「AかBかどっちがいい?」みたいな質問の答えは、だいたい、「両方」もしくは「中間」になります = 中庸

title: 銀の弾丸はない : 「AかBかどっちがいい?」みたいな質問の答えは、だいたい、「両方」もしくは「中間」になります = 中庸
url: http://csharptan.wordpress.com/2011/12/25/net%e9%96%a2%e9%80%a3%e6%8a%80%e8%a1%93/

snippet:
-----引用-----

「AかBかどっちがいい?」みたいな質問の答えは、だいたい、「両方」もしくは「中間」になります。
  • GUICUIかと言われたら、両方。
  • 静的言語動的言語かと言われたら、両方。
  • ネイティブマネージかと言われたら、両方。
  • ウェブクライアントかと言われたら、両方。
  • オブジェクト指向型(OOP)関数型かと言われたら、両方。
それが現実です。
重要なのは、AとBそれぞれ、適切な利用場面がどこか、そして、選べるかどうかです。
「AもBも」といろいろ求められる昨今、AとB関係なく作れる部分と、そうでない部分をきっちりと分離しましょう。

-----引用-----

BDD とは? 振る舞いを決めた上で開発を進める手法(スペックファースト)

title: BDD とは? 振る舞いを決めた上で開発を進める手法(スペックファースト)
url: http://cs.gogo-asp.net/blogs/naoki/archive/2012/04/17/SpecFlow-_6830_-WatiN-_92302952287557305F30_-BDD-_6E30966E9950_.aspx

snippet:
-----引用-----

BDD は Behavior Driven Development の略で、振る舞いを決めた上で開発を進める手法(スペックファースト)の事です。

SpecFlow WatiN などがこの代表的なツールです。SpecFlow は Visual Studio 内での仕様の作成と実施をサポートし、WatiN はブラウザーを使用して、エンド ツー エンドの自動システム テストを実行できるようにします。

サンプルコード
using NSpec;

class describe_specifications : nspec
{
    void when_creating_specifications()
    {
        //some of these specifications are meant to fail so you can see what the output looks like
        it["true should be false"] = () => true.should_be_false();
        it["enumerable should be empty"] = () => new int[] { }.should_be_empty();
        it["enumerable should contain 1"] = () => new[] { 1 }.should_contain(1);
        it["enumerable should not contain 1"] = () => new[] { 1 }.should_not_contain(1);
        it["1 should be 2"] = () => 1.should_be(2);
        it["1 should be 1"] = () => 1.should_be(1);
        it["1 should not be 1"] = () => 1.should_not_be(1);
        it["1 should not be 2"] = () => 1.should_not_be(2);
        it["\"\" should not be null"] = () => "".should_not_be_null();
        it["some object should not be null"] = () => someObject.should_not_be_null();
        //EXPERIMENTAL - specify only takes a lambda and does
        //its best to make a sentence out of the code. YMMV.
        specify = ()=> "ninja".should_not_be("pirate");
    }
    object someObject = null;
}

サンプルスペック出力
describe specifications
  when creating specifications
    true should be false - FAILED - Expected: False, But was: True
    enumerable should be empty
    enumerable should contain 1
    enumerable should not contain 1 - FAILED - Expected: not collection containing 1, But was:...
    1 should be 2 - FAILED - Expected: 2, But was: 1
    1 should be 1
    1 should not be 1 - FAILED - Expected: not 1, But was: 1
    1 should not be 2
    "" should not be null
    some object should not be null - FAILED - Expected: not null, But was: null
    ninja should not be pirate

-----引用-----

The ICSI Netalyzr : 自分の回線にBuffer Bloat問題が有るかを調べられるツール

title: The ICSI Netalyzr : 自分の回線にBuffer Bloat問題が有るかを調べられるツール
url: http://netalyzr.icsi.berkeley.edu/

snippet:
-----引用-----

The ICSI Netalyzr
自分の回線にBuffer Bloat問題が有るかを調べられるツール
インターネット接続の情報取得サイト

-----引用-----

Domain Name Speed Benchmark : DNSのベンチマークを測定、最も高速なDNSサーバを探す

title: Domain Name Speed Benchmark : DNSのベンチマークを測定、最も高速なDNSサーバを探す
url: http://www.grc.com/dns/benchmark.htm
http://raven.air-nifty.com/night/2010/11/grcdns-benchmar.html

snippet:
-----引用-----

Domain Name Speed Benchmark
DNSのベンチマークを測定、最も高速なDNSサーバを探すツール
ポッドキャスト「Security Now!」のSteve GibsonによるDNS性能測定ツール

Google ChromeがDNSプリフェッチを取り入れたり、Google自身がDNSサーバを立ち上げたりして、DNS名前解決スピードがWebブラウジングの快適さにかなり関係しているということが徐々に認識されてきた。DNS Benchmarkは、公開されているDNSサーバに対してクエリを送信し、そのレスポンスを測定する。

測定している値は3種類ある。ひとつめはCached lookupsで、DNSサーバのキャッシュからの応答速度を測定する。まずクエリーを送信してレスポンスを待つ。この応答時間は無視する。次に同じクエリーを送信して、そのレスポンス時間を測定する。1回目のクエリーによって、その名前がキャッシュされたはずである。本当にキャッシュから返答しているかどうかを、レスポンス内のビットで確認する。DNSサーバは、さまざまなユーザから同じサーバ名のクエリーを受け取っている。実運用での名前解決は、キャッシュからの返答がほとんどであろう。この値にもっとも重きを置いて評価する。

ふたつめはUncached lookups。DNSサーバのキャッシュからではなく、相手ドメインのDNSサーバからの応答時間を測定する。たとえばeVNKhHzjoW.amazon.comのような、実際にはあり得ないサブドメイン名を生成し、DNSサーバにクエリーを送信する。他のユーザがこの名前を過去に問い合わせたことはあり得ないから、キャッシュに乗っていない。DNSサーバはDNSの階層をたどっていって、amazon.comのDNSサーバからの応答を得る。

三つめはDotcom lookupsで、測定対象のDNSサーバとインターネットの接続状態を確認する。eVNKhHzjoW.comのようなあり得ないドメイン名を生成し、.comのDNSサーバに問い合わせが行くようにして、応答時間を測定する。

-----引用-----

google-gdataを使ってBloggerブログを操作するサンプルコード

title: google-gdataを使ってBloggerブログを操作するサンプルコード
url: http://code.google.com/p/google-gdata/source/browse/trunk/clients/cs/samples/blogger/ConsoleSample.cs
http://code.google.com/p/google-gdata/

snippet:
-----引用-----

using System;
using System.Text;
using Google.GData.Client;
using System.Net;
using System.Xml;
using System.Text.RegularExpressions;

namespace BloggerDevSample
{
    class ConsoleSample
    {
        /** Lists the user's blogs. */
        static void ListUserBlogs(Service service)
        {
            Console.WriteLine("\nRetrieving a list of blogs");
            FeedQuery query = new FeedQuery();
            // Retrieving a list of blogs
            query.Uri = new Uri("http://www.blogger.com/feeds/default/blogs");
            AtomFeed feed = null;
            feed = service.Query(query);
            foreach (AtomEntry entry in feed.Entries)
            {
                Console.WriteLine("  Blog title: " + entry.Title.Text);
            }
        }

        /** Lists the user's blogs and returns the URI for posting new entries
         * to the blog which the user selected.
         */
        static Uri SelectUserBlog(Service service)
        {
            Console.WriteLine("\nPlease select a blog on which to post.");
            FeedQuery query = new FeedQuery();
            // Retrieving a list of blogs
            query.Uri = new Uri("http://www.blogger.com/feeds/default/blogs");
            AtomFeed feed = service.Query(query);

            // Publishing a blog post
            Uri blogPostUri = null;
            if (feed != null)
            {
                foreach (AtomEntry entry in feed.Entries)
                {
                    // Print out the title of the Blog
                    Console.WriteLine("  Blog name: " + entry.Title.Text);
                    Console.Write("  Post to this blog? (y/n): ");
                    if (Console.ReadLine().Equals("y"))
                    {
                        // find the href in the link with a rel pointing to the blog's feed
                        for (int i = 0; i < entry.Links.Count; i++)
                        {
                            if (entry.Links[i].Rel.Equals("http://schemas.google.com/g/2005#post"))
                            {
                                blogPostUri = new Uri(entry.Links[i].HRef.ToString());
                                Console.WriteLine("  Your new posts will be sent to " + blogPostUri.AbsoluteUri.ToString());
                            }
                        }
                        return blogPostUri;
                    }
                }
            }
            return blogPostUri;
        }

        /** Creates a new blog entry and sends it to the specified Uri */
        static AtomEntry PostNewEntry(Service service, Uri blogPostUri)
        {
            Console.WriteLine("\nPublishing a blog post");
            AtomEntry createdEntry = null;
            if (blogPostUri != null)
            {
                // construct the new entry
                AtomEntry newPost = new AtomEntry();
                newPost.Title.Text = "Marriage!";
                newPost.Content = new AtomContent();
                newPost.Content.Content = "<div xmlns='http://www.w3.org/1999/xhtml'>" +
                    "<p>Mr. Darcy has <em>proposed marriage</em> to me!</p>" +
                    "<p>He is the last man on earth I would ever desire to marry.</p>" +
                    "<p>Whatever shall I do?</p>" +
                    "</div>";
                newPost.Content.Type = "xhtml";
                newPost.Authors.Add(new AtomPerson());
                newPost.Authors[0].Name = "Elizabeth Bennet";
                newPost.Authors[0].Email = "liz@gmail.com";

                createdEntry = service.Insert(blogPostUri, newPost);
                if (createdEntry != null)
                {
                    Console.WriteLine("  New blog post created with title: " + createdEntry.Title.Text);
                }
            }
            return createdEntry;
        }

        /** Creates a new blog entry and sends it to the specified Uri */
        static void PostAndDeleteNewDraftEntry(Service service, Uri blogPostUri)
        {
            Console.WriteLine("\nCreating a draft blog post");
            AtomEntry draftEntry = null;
            if (blogPostUri != null)
            {
                // construct the new entry
                AtomEntry newPost = new AtomEntry();
                newPost.Title.Text = "Marriage! (Draft)";
                newPost.Content = new AtomContent();
                newPost.Content.Content = "<div xmlns='http://www.w3.org/1999/xhtml'>" +
                    "<p>Mr. Darcy has <em>proposed marriage</em> to me!</p>" +
                    "<p>He is the last man on earth I would ever desire to marry.</p>" +
                    "<p>Whatever shall I do?</p>" +
                    "</div>";
                newPost.Content.Type = "xhtml";
                newPost.Authors.Add(new AtomPerson());
                newPost.Authors[0].Name = "Elizabeth Bennet";
                newPost.Authors[0].Email = "liz@gmail.com";
                newPost.IsDraft = true;

                draftEntry = service.Insert(blogPostUri, newPost);
                if (draftEntry != null)
                {
                    Console.WriteLine("  New draft post created with title: " + draftEntry.Title.Text);
                    // Delete the newly created draft entry
                    Console.WriteLine("  Press enter to delete the draft blog post");
                    Console.ReadLine();
                    draftEntry.Delete();
                }
            }
        }

        /** Display the titles for all entries in the previously selected blog. */
        static void ListBlogEntries(Service service, Uri blogUri)
        {
            if (blogUri != null)
            {
                Console.WriteLine("\nRetrieving all blog posts");
                // Retrieve all posts in a blog
                FeedQuery query = new FeedQuery();
                Console.WriteLine("  Query URI: " + blogUri.ToString());
                query.Uri = blogUri;
                AtomFeed feed = service.Query(query);
                foreach (AtomEntry entry in feed.Entries)
                {
                    Console.WriteLine("  Entry Title: " + entry.Title.Text);
                }
            }
        }

        /** Display title for entries in the blog in the hard coded date range. */
        static void ListBlogEntriesInDateRange(Service service, Uri blogUri)
        {
            Console.WriteLine("\nRetrieving posts using query parameters");
            // Retrieve all posts in a blog between Jan 1, 2006 and Apr 12, 2007
            FeedQuery query = new FeedQuery();
            query.Uri = blogUri;
            query.MinPublication = new DateTime(2006, 1, 1);
            query.MaxPublication = new DateTime(2007, 4, 12);
            AtomFeed feed = service.Query(query);
            foreach (AtomEntry entry in feed.Entries)
            {
                Console.WriteLine("  Entry Title: " + entry.Title.Text);
            }
        }

        /** Change the contents of the newly created blog entry. */
        static AtomEntry EditEntry(AtomEntry toEdit)
        {
            Console.WriteLine("\nUpdating post");
            // Edit the new entry
            if (toEdit != null)
            {
                toEdit.Title.Text = "Marriage Woes!";
                Console.WriteLine("  Press enter to update");
                Console.ReadLine();
                toEdit = toEdit.Update();
            }
            return toEdit;
        }

        /** Delete the specified blog entry. */
        static void DeleteEntry(AtomEntry toDelete)
        {
            Console.WriteLine("\nDeleting post");
            // Delete the edited entry
            if (toDelete != null)
            {
                Console.WriteLine("  Press enter to delete the new blog post");
                Console.ReadLine();
                toDelete.Delete();
            }
        }

        /** Get the comments feed URI for the desired blog entry. */
        static Uri SelectBlogEntry(Service service, Uri blogPostUri)
        {
            Console.WriteLine("\nPlease select a blog entry on which to comment.");
            FeedQuery query = new FeedQuery();
            query.Uri = blogPostUri;
            AtomFeed feed = service.Query(query);
            Uri commentPostUri = null;

            if (feed != null)
            {
                foreach (AtomEntry entry in feed.Entries)
                {
                    // Print out the title of the Blog
                    Console.WriteLine("  Blog entry title: " + entry.Title.Text);
                    Console.Write("  Post a comment on this entry? (y/n): ");

                    if (Console.ReadLine().Equals("y"))
                    {
                        // Create the Post URL for adding a comment by finding this entry's id number.

                        // Find the href in the link with a rel pointing to the blog's feed.
                        for (int i = 0; i < entry.Links.Count; i++)
                        {
                           
                            if (entry.Links[i].Rel == "edit")
                            {
                                string commentUriStart = Regex.Replace(blogPostUri.ToString(), "/posts/default", "");
                                string selfLink = entry.Links[i].HRef.ToString();
                                string entryId = Regex.Replace(selfLink, blogPostUri.ToString() + "/", "");
                                // Build the comment URI from the blog id in and the entry id.
                                commentPostUri = new Uri(commentUriStart + "/" + entryId + "/comments/default");
                                Console.WriteLine("  Your new comments will be sent to " + commentPostUri.ToString());
                                return commentPostUri;
                            }
                        }
                    }
                }
            }

            return commentPostUri;
        }

        static AtomEntry PostNewComment(Service service, Uri commentPostUri)
        {
            Console.WriteLine("\nCommenting on a blog post");
            AtomEntry postedComment = null;
            if (commentPostUri != null)
            {
                // Add a comment.
                AtomEntry comment;
                comment = new AtomEntry();
                comment.Title.Text = "This is my first comment";
                comment.Content.Content = "This is my first comment";
                comment.Authors.Add(new AtomPerson());
                comment.Authors[0].Name = "Blog Author Name";
                postedComment = service.Insert(commentPostUri, comment);
                Console.WriteLine("  Result's title: " + postedComment.Title.Text);
            }
            return postedComment;
        }

        static void ListEntryComments(Service service, Uri commentUri)
        {
            if (commentUri != null)
            {
                Console.WriteLine("\nRetrieving all blog post comments");
                // Retrieve all comments on a blog entry
                FeedQuery query = new FeedQuery();
                Console.WriteLine("  Query URI: " + commentUri.ToString());
                query.Uri = commentUri;
                AtomFeed feed = service.Query(query);
                foreach (AtomEntry entry in feed.Entries)
                {
                    Console.WriteLine("  Comment Title: " + entry.Title.Text);
                }
            }
        }

        static void DeleteComment(AtomEntry commentEntry)
        {
            Console.WriteLine("\nDeleting the comment");
            if (commentEntry != null)
            {
                // Delete the comment.
                Console.WriteLine("  Press enter to delete the new comment post");
                Console.ReadLine();
                commentEntry.Delete();
            }
        }

        static void Main(string[] args)
        {
            Service service = new Service("blogger", "blogger-example");

            // ClientLogin using username/password authentication
            string username;
            string password;
            if (args.Length != 2)
            {
                Console.WriteLine("Usage: BloggerDevSample.exe <username> <password>");
                return;
            }
            else
            {
                username = args[0];
                password = args[1];
            }

            service.Credentials = new GDataCredentials(username, password);

            ListUserBlogs(service);
            Uri blogPostUri = SelectUserBlog(service);
            AtomEntry createdEntry = PostNewEntry(service, blogPostUri);
            PostAndDeleteNewDraftEntry(service, blogPostUri);
            ListBlogEntries(service, blogPostUri);
            ListBlogEntriesInDateRange(service, blogPostUri);
            AtomEntry editedEntry = EditEntry(createdEntry);
            DeleteEntry(editedEntry);
            Uri commentPostUri = SelectBlogEntry(service, blogPostUri);
            AtomEntry commentEntry = PostNewComment(service, commentPostUri);
            ListEntryComments(service, commentPostUri);
            DeleteComment(commentEntry);

            Console.WriteLine("Press enter to quit");
            Console.ReadLine();
        }
    }
}

-----引用-----