Jamwiki使ってみた

自分専用のwikiあったら便利だなーってずっと思ってたんだけど
wikiって種類が多すぎてどれを選べばよいのかわからなくて踏み出してませんでした。

  • PHPのやつはいやだった。(まだPHPになれていない。慣れていたらPukiwikiにしてたかも)
  • それからCommercial Baseなやつもだめ。(あたりまえだ)
  • 記法が特殊なやつもいやだった。例えばTracみたいな記法すっごいいやだ。
  • MySQLPostgreSQLを使うやつはいやだった。大げさすぎる。


そんなこといろいろ考えて
Jamwiki
http://jamwiki.org/wiki/en/StartingPoints
にしました。


特徴

  • Javaベース
  • MediaWikiクローン。MediaWikiの記法がそのまま使える(MediaWiki使ったことないけど!)
  • 内部DB(hsqldb)使用。外部DBも使用可能
  • インストールが楽だった。


インストール方法

warをtomcatとかにデプロイする。以上


記法どうこういっといてまだ<pre>しか使ってないwすみません。

OAuth認証+JavaからTwitterにポスト その5

しばらく前に書いてたこのシリーズですが、
「これじゃ動かない」という指摘を受けました。
動かない理由は自作したユーティリティクラスを載せていなかったためです。


なのでちょっと手直しをしつつ、テスト用のクラス(TestPost.java)も加えて
githubにまるごとpushしました。


↓こちら
http://github.com/tototoshi/OAuthSample


変更点はBase64エンコードのライブラリを変更したり
設定をプロパティファイルに分離させた程度で、本質的ではありません。


ビルド用のbuild.xmlはそのままでは使えませんが、
使っているライブラリなど、参考になるかなと思ったので上げました。
どうぞよろしく

(goto-line LINE &optional Buffer)

Lispプログラムの中ではgoto-lineを使うのには注意が必要。
goto-lineは移動先にジャンプする前に現在行にマークをするようだ。
そういえば今までちょくちょくminibufferにMark Setって出てた。
原因はこれだったのか。

This function is usually the wrong thing to use in a Lisp program.
What you probably want instead is something like:


代わりにこうするとよい。

(goto-char (point-min))
(forward-line (1- N))


できれば行番号での移動ではなく、文字数を使って移動するのが望ましい
とHelpには書いてあるけれど、文字数でどうやって行移動するんだろう?

ラベル付きbreak

プログラミング言語Ruby 5.5.6 throwとcatch」より

JavaJavaScriptなどの言語では、任意のプレフィックスで繰り返しに名前、ラベルを付けることができ、「ラベル付きbreak」と呼ばれる制御構造によって、名前付き繰り返しを抜け出すことができる。


知らなかった...

↓こんな感じ

public class Label {

	public static void main(String[] args) {

		for (int i = 0; i < 2; i++) {
			label: for (int j = 0; j < 2; j++) {
				for (int k = 0; k < 2; k++) {
					int product = j * k;
					if (product > 3) {
						break label;
					}
					System.out.println(product);
				}
			}
			System.out.println("Break!");
		}
	}
}


出力

0
0
0
1
Break!
0
0
0
1
Break!

実際に使われてるところは見たことないなあ。
一種のgoto文のように見えるし、使う場面はそんなにないように思う。

mixi足あとツール(だめ、ぜったい)

昨日飲んでるとき
mixiの自動巡回ツールを3000円で買った奴がいる」
という話を聞いて、なんてこった、と思ったので
↓自分もちょっと書いてみた。


使い方
インスタンス作ってpatrolProfilePage()にidを渡すと、そのid人のページに足跡がつきます。


forループでかたっぱしからつけるもよし。
ランダムに踏むもよし。。。


いやいや
多分規約に触れるのでやらないようにw

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;

public class MixiPatrol {
	private static final String HOST = "http://mixi.jp";
	private static final String LOGIN = "/login.pl";
	private static HttpClient httpClient = new DefaultHttpClient();

	public MixiPatrol(String email, String password) {
		login(email, password);
	}

	private void login(String email, String password) {
		HttpPost httpPost = new HttpPost(HOST + LOGIN);

		try {
			ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
			params.add(new BasicNameValuePair("next_url", "/home.pl"));
			params.add(new BasicNameValuePair("email", email));
			params.add(new BasicNameValuePair("password", password));
			httpPost.setEntity(new UrlEncodedFormEntity(params, "EUC-JP"));

			HttpResponse response = httpClient.execute(httpPost);
			HttpEntity entity = response.getEntity();
			InputStream in = entity.getContent();
			BufferedReader br = new BufferedReader(new InputStreamReader(in,
					"EUC-JP"));
			String line;
			while ((line = br.readLine()) != null) {
				System.out.println(line);
			}
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void patrolProfilePage(int id) {
		try {
			HttpGet httpGet = new HttpGet(HOST + "/show_friend.pl?id="
					+ String.valueOf(id));
			HttpResponse response = httpClient.execute(httpGet);
			HttpEntity entity = response.getEntity();
			InputStream in = entity.getContent();
			BufferedReader br = new BufferedReader(new InputStreamReader(in,
					"EUC-JP"));
			String line;
			while ((line = br.readLine()) != null) {
				System.out.println(line);
			}
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}
}

OAuth認証+JavaからTwitterにポスト その4

週1のペースでまったりと続くこの企画。

前回はrequest_tokenを取得しました。

今日やるのは↓の2と3のところ

Desktop Clients

The traditional OAuth flow for desktop clients can be cumbersome. We've created a PIN-based experience for destkop clients that use the following flow:

1. The application uses oauth/request_token to obtain a request token from twitter.com.
2. The application directs the user to oauth/authorize on twitter.com.
3. After obtaining approval from the user, a prompt on twitter.com will display a 7 digit PIN.
4. The user is instructed to copy this PIN and return to the appliction.
5. The application will prompt the user to enter the PIN from step 4.
6. The application uses the PIN as the value for the oauth_verifier parameter in a call to oauth/access_token which will verify the PIN and exchange a request_token for an access_token.
7. Twitter will return an access_token for the application to generate subsequent OAuth signatures.


request_tokenではまだAPIにアクセスすることはできません。
APIにアクセスするにはaccess_tokenが必要です。
そのaccess_tokenの取得の際に必要な7 digit PINを今回は取得します。



実はあっさり終わります。
まず2番。

http://twitter.com/oauth/authorize?oauth_token=REQUEST_TOKEN
# REQUEST_TOKENはこの前取得したやつに置き換えて下さい。


こういうページに飛びます。

許可します。

で、次、3番

7桁の番号が表示されます。

You've successfully granted access to tvvitter(クライアントの名前)
って表示されてますね。つまりconsumerがuserの代わりにService Providerにアクセスするのを今のクリックで承認したわけです。


以上。ちょっとテキトーすぎるかもしれないけどw

OAuth認証+JavaからTwitterにポスト その3

サンプルソースはまとめてgithubにあります
http://github.com/tototoshi/OAuthSample


とりあえず、request tokenを取得するJavaプログラム
https://github.com/tototoshi/OAuthSample/blob/master/java/src/main/java/com/github/tototoshi/oauth/twitter/RequestToken.java
https://github.com/tototoshi/OAuthSample/blob/master/java/src/main/java/com/github/tototoshi/oauth/twitter/OAuthUtil.java

RequestToken.javaの説明

getRequestParameter()

private String getRequestParameters() {
		return
			"oauth_consumer_key=" + CONSUMER_KEY + "&" +
			"oauth_nonce=" + URLEncode(getNonce()) + "&" +
			"oauth_signature_method=" + SIGNATURE_METHOD + "&" +
			"oauth_timestamp=" + getTimeStamp() + "&" +
			"oauth_version=" + OAUTH_VERSION ;
	}

必要とされてるパラメータつなげてるだけです。
nonceはgetNonce()で取得し、それをエンコードしています。timestampとかconsumer keyとかも必要に応じてしてください。多分する必要はないけど。
getNonce()の中身ですが、commonsで便利そうなライブラリがあったのでそれ使いました。
getTimeStamp()もまあ適当に。


oauth_signature_methodですが、twitterで対応してるのはHmacSHA1らしいのでそれを指定します。
oauth_versionは1.0


request parameterが得られたので、これをもとにgetSignatureBaseString()メソッドでsignature(署名)の元になる文字列を作っています。

	private String getSignatureBaseString(String requestParameters) {
		return "GET&" + OAuthUtil.URLEncode(REQUEST_TOKEN_URL) + "&" + OAuthUtil.URLEncode(requestParameters);
	}

HTTPメソッド + request token URL をエンコードしたもの + request parameterをエンコードしたもの。
HTTPメソッドですが、OAuthの仕様にはPOST推奨と買いてありましたが、TwitterはGETを指定しているのでGETで。


これでsignature base stringが出来上がりました。
これでやっとsignatureが作れる。
とその前に(まだあんのかよ。。。)


keyを作らなきゃいけません。

	private String getKeyString(){	
		if(oauthToken == null){
			return CONSUMER_SECRET + "&";
		}else{
			return CONSUMER_SECRET + "&" + oauthToken;
		}
	}

consumer secret(Twitterにアプリ登録したときもらったやつ)とoauth tokenを「&」でつなぎます。
といってもoauth tokenは今まさに取得しようとしてるわけで、まだありません。
だから必要ありませんが、ここで注意。「&」は必要です。


これでsignatureを作る準備完了
getSignature()はbase stringとkeyからsignatureを作るメソッドです。

	private String getSignature(String signatureBaseString, String keyString){
		String signature = null;
		String algorithm = "HmacSHA1";
		try {
			Mac mac = Mac.getInstance(algorithm);
			Key key= new SecretKeySpec(keyString.getBytes(), algorithm);
			
			mac.init(key);
			byte[] digest = mac.doFinal(signatureBaseString.getBytes());
			signature = URLEncode(Base64.encode(digest));
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		}
		return signature;
	}

HmacSHA1アルゴリズムでハッシュ→Base64→URLエンコードが手順です。


これでsignatureが得られました。やっとだ。。。
このsignatureをくっつけてリクエスト送ります。
↓こんな感じ。あ、commons-httpclient使ってます。

		String req = REQUEST_TOKEN_URL + "?" + requestParameters + "&oauth_signature=" + signature;
		HttpGet httpGet = new HttpGet(req);


うまく行けば、

oauth_token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&oauth_token_secret=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&oauth_callback_confirmed=true

こんな感じのresponseが返ってきます。
oauth_tokenがrequest tokenで、oauth_token_secretはそれと対になるパスワードです。
これをもとに次回はaccess tokenを取得、するわけですが、疲れたので次回。


2011/09/09 修正しました。コードの部分をgithubへのリンクにしました。