Rで認証プロキシを乗り越える

Rではパッケージのインストールなどはネットワーク経由(CRAN)で行われます。認証プロキシが必要なネットワークの内部でRのパッケージをインストールする必要がある場合、それを乗り越えるためのいくつかの方法についてメモ。

–internet2 を使う

Rの実行時に –internet2 というオプションを指定する方法。この指定をすると windows の場合はOSのネットワークプロキシの設定を参照する。これはR+プロキシで検索するとよく出てくる方法だけど、認証プロキシには対応していないのでなにか方法を考えないといけない。

以前紹介したRubyのlocalproxyを使って、OSのプロキシの設定をlocalhostにしてしまえば –internet2 でもプロキシを通過可能。

この方法は非常に汎用性が高く、rubyのgemとか、その他ネットワーク越しのパッケージインストールでは威力を発揮する方法ですが、rubyを導入したり、OS起動時にスクリプトを起動するなど、初期設定はめんどくさいので、とりあえずRだけ認証プロキシを通過すればよい場合は次の方法がおすすめです。

http_proxy, http_proxy_user を指定

Rの実行時に http_proxy=http://proxy.hogehoge.com:PORT http_proxy_user=ask を指定すれば(指定の方法は –internet2 と同じ方法)パッケージインストールなどの際にプロキシユーザーとパスワードを入力するダイアログが出現します。これに入力するだけ。特に難しいことはないはずです。

[ruby] open-uri でプロキシ認証

認証プロキシ下のコンピュータから ruby の open-uri を使うためのメモです。

ネットで検索したら open-uri.rb にパッチをあてる、みたいなハックが何件かヒットしましたが、ソースコードを読んでみたところ、少なくともバージョン 1.9.2 ではライブラリを書き換えることなく、以下のように対処可能です。

require "open-uri"

pxy = "http://my.proxy.com:8080"
usr = "proxyuser"
pss = "proxypass"

options = { :proxy_http_basic_authentication => [pxy,usr,pss] }
uri = "http://www.google.com/"

open(uri,options){ |io|
  # do something with io
}

proxy_http_basic_authentication というオプションに3つの要素(プロキシサーバーアドレス+ポート、ユーザ名、パスワード)を与えれば認証プロキシを乗り越えることができます。

おまけ

スクリプトにパスワードを直接書くことに抵抗ある人は例えば以下のようにすれば、スクリプトの実行毎にプロンプトに入力することができます。

require 'highline'  # なければ gem でインストールしましょう。

usr = HighLine.new.ask('Proxy ID: ')
pss = HighLine.new.ask('Proxy Password: ') { |q| q.echo = '*' }

highline を使うとパスワードをターミナルから入力する際に、画面に表示させずに * (アスタリスク)を表示させることができます。gem でインストール可能です。

ウィンドウリサイズ時に canvas 要素の幅を自動調整するための tips

canvas 要素の幅は、通常、width 属性で指定しますが、これをウィンドウのリサイズに合わせて自動的に幅を調節するための Tips です。
“ウィンドウリサイズ時に canvas 要素の幅を自動調整するための tips”の続きを読む

Ruby のバージョンマネージャー rvm を Ubuntu で使う

Ubuntu 11.04 を導入しました。いままでは windows から Redhat にログインするという形で使っていたのですが、yum はパッケージの依存関係とかに時間を取られてしまって Ubuntu ならそのへん楽になるんじゃないかと。

実際非常に楽でした。いいですね、Ubuntu。

ただ認証プロキシ下での rvm (Ruby version manager) の設定ですこしハマったのでメモを残しておきます。
“Ruby のバージョンマネージャー rvm を Ubuntu で使う”の続きを読む

【C++】 基本型・クラス間の型変換を定義するには?

c++ では static_cast<double>(int) とかやると型を変換できますが、それを自分で定義したクラスに対して行う方法について書いてみます。
コンストラクタを使ってやる方法もありますが、この方法だと int, double などの基本型(組み込み型)には使えません。たとえばあるクラス X を int 型にキャストしたい場合などですね。

X::operator int() を定義する

こういうときは次のような方法が有効です。

struct X {
  operator int(){ /* 変換のためのコード */}
};

このような operator T を定義しておくと、

X x;
int y=x;
int z=static_cast<int>(x);

というような書き方ができるようになります。

サンプル

上で書いてあることとほとんど同じですが、コンパイルできるコードを一通り書いておきます。
さまざまな型から Hoge クラスにキャストしたり、また、Hoge クラスから別の型へのキャストをするようなサンプルになっています。

#include &lt;iostream&gt;
#define castmsg(from, to) std::cout << "Cast from "#from" to "#to << std::endl;
struct Fuga {
  int fuga;
};
struct Hoge {
  int hoge;
  operator int(){   // Hoge -> int へのキャスト
    castmsg(Hoge,int);
    return hoge;
  }
  operator Fuga(){  // Hoge -> Fuga へのキャスト
    castmsg(Hoge,Fuga);
    Fuga f;
    f.fuga = hoge;
    return f;
  }
  Hoge(int h){      //  int -> Hoge へのキャスト
    castmsg(int,Hoge);
    hoge=h;
  }
  Hoge() : hoge(0) { }  // デフォルトコンストラクタ
};

int main(){
  Hoge hoge;
  hoge.hoge = 1;
  std::cout << "=== Type cast test (by static_cast) ===" << std::endl;
  /* Hoge -> int */
  int h = static_cast<int>(hoge);
  /* Hoge -> Fuga */
  Fuga fuga = static_cast<Fuga>(hoge);
  /* int -> Hoge */
  Hoge hogera = static_cast<Hoge>(4);
  std::cout << "Hoge->int  : " << h << std::endl;
  std::cout << "Hoge->Fuga : " << fuga.fuga << std::endl;
  std::cout << "int->Hoge  : " << hogera.hoge << std::endl;
  std::cout << "=== Type cast test (implicit) ===" << std::endl;
  /* Hoge -> Fuga */
  fuga = hoge;
  /* int -> Hoge */
  hogera = 6;
  std::cout << "hogera: " << hogera << std::endl;    // ここでも暗黙の Hoge->int が使われる
  //std::cout << fuga << std::endl;    // これはエラー!(Fuga->int は存在しない)
  std::cout << "fuga.fuga: " << fuga.fuga << std::endl;
}

/* 出力 */
/*
=== Type cast test (by static_cast) ===
Cast from Hoge to int
Cast from Hoge to Fuga
Cast from int to Hoge
Hoge->int  : 1
Hoge->Fuga : 1
int->Hoge  : 4
=== Type cast test (implicit) ===
Cast from Hoge to Fuga
Cast from int to Hoge
hogera: Cast from Hoge to int
6
fuga.fuga: 1
*/

暗黙の型変換を抑制する

上の例で言うと、ユーザー定義クラスの Hoge に int が = 演算子を使って代入できるようになっていますが、場合によってはこの挙動は危険だ、という場合もあるでしょう。そんなときはコンストラクタ Hoge(int) の前に explict 修飾子をつけましょう。
これをつけることで

Hoge x=1;

のようなコードをコンパイル時エラーにすることができるようになります。

[R] RSQLite の使い方 (2)

前回は R で SQLite を利用するための基本中の基本を示しました。
今回は高速化の方法など少しだけ踏み込んだ内容について記します。

トランザクションの利用

トランザクションを使って大量のクエリを高速に処理します。トランザクションって何?って人はググってみてください。前回も書きましたが、dbWriteTable などはトランザクションを利用しないので、場合によってはこちらを使ったほうが速い、のかもしれません(未確認)。

library(RSQLite)
driver=dbDriver("SQLite")
dbname="test.db"
con=dbConnect(driver,dbname)

# 準備
test.tbl=as.data.frame(matrix(rnorm(100),nc=2))
colnames(test.tbl)=c("random1","random2")
rs=dbWriteTable(con,"random",test.tbl,row.names=F)

# トランザクション開始
dbBeginTransaction(con)
rs=dbSendQuery("DELETE FROM random WHERE random1>0 AND random2>0;")

# DELETE される行が 10 行より多ければロールバックする(DELETEしない)
if(dbGetInfo(rs)$rowsAffected > 10){
  cat("Rollback!")
  dbRollback(con)
} else { # そうでなければコミットする(DELETE が反映される)
  cat("Commit!")
  dbCommit(con)
}

# コミットされたかどうかチェック
#(この場合コミットされていないのでデータベースの内容はそのまま)
dbGetQuery(con,"select count(*) from random;")
#=>   count(*)
#=> 1       50

C/C++-API でいうところの sqlite3_prepare & sqlite3_bind_XX の利用

これも高速化のテクニックのひとつです。あらかじめパラメータつきのクエリを準備しておいてパラメータに値を次々に代入して SQL 文を実行するための方法です。

library(RSQLite)
driver=dbDriver("SQLite")
dbname="test.db"
con=dbConnect(driver,dbname)

# 準備(上で作った random テーブルがすでにあれば必要なし)
test.tbl=as.data.frame(matrix(rnorm(100),nc=2))
colnames(test.tbl)=c("random1","random2")
rs=dbWriteTable(con,"random",test.tbl,row.names=F)

# Prepare された SQL ステートメントを使ってデータ挿入
dbBeginTransaction(con)
keys=data.frame(r1=runif(10), r2=runif(10)) # 適当なデータ

# セミコロンに続いてデータフレームのカラム名で指定
pquery="INSERT INTO random (random1, random2) VALUES (:r1,:r2);"
rs=dbSendPreparedQuery(con, pquery, keys)
dbCommit(con)

拡張関数の利用

RSQLite.extfuns パッケージを使うと sin, exp, floor のような数学関数,trim のような文字列関数,stdev, mode, median のような統計関数が使えるようになります。
これらの関数を使うことでより複雑なクエリを生成することが可能になり、結果として処理速度の向上が見込めるかもしれません。

下の例では有名なアヤメデータ(iris)に対して、

  • 種(Species)ごとにグループ分けして がく片の長さ(Sepal.Length)の標準偏差の小さい順にデータフレームを作成

という処理をしています(注:plyr パッケージの ddply 関数を使えばほぼ同じことができます)。

library(RSQLite)
library(RSQLite.extfuns)   # 拡張関数用のパッケージ
driver=dbDriver("SQLite")
dbname="test.db"
con=dbConnect(driver,dbname)
init_extensions(con)       # 拡張関数が使えるようにするためのおまじない

# 準備(iris データを使う)
data(iris)
rs=dbWriteTable(con,"iris",iris,row.names=F)

# Species ごとにグループ分けして Sepal.Length の標準偏差の小さい順にデータフレームを作成
dbGetQuery(con,"select Species, stdev(Sepal_Length) as slstdev from iris group by Species order by slstdev;")

[R] RSQLite の使い方 (1)

RSQLite(+RSQLite.extfuns)パッケージを使うことで R から SQLite3 へ非常に簡単にアクセス可能になる。SQLite 本体もどうやらパッケージに含まれているようで、事前にインストールする必要がないため、パッケージをインストールするだけで非常に簡単に使い始めることができます(パッケージ自体も 1MB もないくらいのサイズです。如何に SQLite が小さいかがよくわかります)。

クエリーを投げる、トランザクション、などの基本的機能は完備されています。さらにデータフレームを一気に INSERT するための dbWriteTable などのおかげで便利に使えます。以下に使い方を示していきます。

一番シンプルな使い方

# (0) 準備:ドライバに SQLite を指定し,データベースをオープン.
#           コネクション・オブジェクト (S4) が帰ってくるので
#           保持しておく.
dbname="test.db"
library(RSQLite)
driver=dbDriver("SQLite")
con=dbConnect(driver,dbname)

# (1) dbGetQuery : すでに存在するデータベースを open してテーブルを取得
# (hoge というテーブルを持っていると仮定)
tbl=dbGetQuery(con,"SELECT * from hoge;")

# (2) dbSendQuery : テーブルが帰ってこない(SELECT 以外の?)クエリーは
#     dbSendQuery を使うべき → エラー処理が可能に
#     (dbGetQuery でも NULL が返るだけでエラーにはならない)
rs=dbSendQuery(con,"CREATE TABLE new_tbl(id INTEGER, hoge TEXT);")
dbinfo=dbGetInfo(rs)
print(dbinfo)

# dbinfo の中身
#=> $statement
#=> [1] "CREATE TABLE new_tbl(id INTEGER, hoge TEXT);"
#=> $isSelect
#=> [1] 0
#=> $rowsAffected
#=> [1] 0
#=> $rowCount
#=> [1] 0
#=> $completed # 正常に終了したか?
#=> [1] 1
#=> $fieldDescription
#=> $fieldDescription[[1]]
#=> NULL

データフレームの取得、挿入

R のデータフレームはリレーショナルデータベースと似た構造になっているので、write.table, read.table のようなノリで読み込み、書き込みを行うことができます。

library(RSQLite)
driver=dbDriver("SQLite")
dbname="test.db"
con=dbConnect(driver,dbname)
test.tbl=as.data.frame(matrix(rnorm(100),nc=2))
colnames(test.tbl)=c("random1","random2")

# データフレームをテーブルとして一括書き込み
rs=dbWriteTable(con,"random",test.tbl,row.names=F)

# 書き込めているかテスト
dbGetQuery(con,"SELECT * FROM random limit 5;")

#=>   row_names    random1    random2
#=> 1         1  0.2354093  1.7083581
#=> 2         2 -0.8101699 -0.6867071
#=> 3         3  0.4537572  1.8399874
#=> 4         4 -2.1129855  1.0211205
#=> 5         5  0.9778609 -0.9177596

# テーブルをデータフレームとして一括取得
dbReadTable(con,"random")

(注意) マニュアルによれば dbReadTable, dbWriteTable はトランザクションを利用しないようです。

続きを書きました。

firefox/google chrome でメイリオをアンチエイリアシング

windows xp で firefox を使っていると、さまざまなサイトでフォントがカクカクとして汚いページを見かけます。この原因はウェブページのフォントがメイリオ系に指定されていることが原因です。メイリオ系のフォントは Vista 以降に標準搭載されるようになったので、xp ではインストールが必要です(ただし windows update でインストールされるので入っている人も多いはず)。

最近はメイリオを標準フォントにしているウェブサイトも多いので(このサイトもそうです)汚いフォントはストレスになります。Internet Explorer な人々(IE7以降)はメイリオをインストールするだけできれいに表示されるらしいですが、firefox/chrome などの「非M$」なブラウザではインストールしただけではアンチエイリアシングがかからないため、設定が必要です。といっても設定は非常に簡単で

「画面のプロパティ(デスクトップの何もないところで右クリック→プロパティ)」 → デザインのタブ → 効果 → 「次の方法でスクリーンフォントの縁を滑らかにする」にチェック → Clear Type を選択

とするだけです。

また、google chrome には「強制メイリオちゃん」という拡張機能があって、これをいれると何でもかんでもメイリオフォントにしてくれます。

[Ruby] 認証プロキシを乗り越える

あるローカルなネットワークから外に出るときに、認証プロキシを通過しなければならないことはよくあります。

Web ブラウザーを経由するならば問題になりませんが、それ以外のアプリケーション経由の場合はプロキシの認証に対応していなかったりでめんどうなことも多いと思います。

そんなときはローカルにプロキシサーバを立てると便利です。

ローカルプロキシサーバのソフトウェアもありますが、ruby を使えばびっくりするほど簡単にプロキシサーバを作ることができるので、自作することにします。といっても、本当に簡単で、ほとんど定型的に以下のように書けます。ただし、エラー処理などはしてません。

# Simplest local proxy server
require 'rubygems'
require 'highline'  # gem でインストールできる
require 'webrick'
require 'webrick/httpproxy'
require 'uri'
# 親サーバーのプロキシ
puts 'Proxy authentication'
user = HighLine.new.ask('ID: ')
pass = HighLine.new.ask('Password: ') { |q| q.echo = '*' }
proxyuri="http://#{user}:#{pass}@YOUR_PROXY_SERVER:PORT"
# プロキシサーバオブジェクトを作る
s = WEBrick::HTTPProxyServer.new(
:BindAddress => '127.0.0.1',
:Port => 8028,
:ProxyVia => false,
:ProxyURI => URI.parse(proxyuri)
)
Signal.trap('INT') do
s.shutdown
end
s.start

このスクリプトをコマンドラインから起動して、親サーバのプロキシID、パスワードを入力したあと、(上の例の :BindAddress、:Port でプロキシサーバを構築した場合は)アプリケーションのプロキシ設定を

http://localhost:8028

とかすれば OK なはずです。

“[Ruby] 認証プロキシを乗り越える”の続きを読む