RubyでGoogleカレンダーの情報を引き抜いてみる
5,6年前に作ったGoogleカレンダーと会社のカレンダーを同期するシステムが
突然動かなくなったので修正しました。
理由は簡単で
Google Calendar Api V2がサポート切れになったから!
私は最近このプログラムを使ってなかったのでまったく困ってなかったのですが
他の人が結構ヘビーに使っていた人がいたので
重い腰をあげてGoogle Calendar API v3 に対応しました。
もともとこのコードはJavaで書いていたのですが、せっかくなのでRubyで書きなおしを
行いました。
そこそこ面倒だったので、手順を記載します。
基本は下記サイトの手順で行いました。
rubyにてgoogleカレンダーの情報を取得する - Qiita
しかしながら
下記のコマンドを実行を実行した際に問題が発生しました。
google-api oauth-2-login --client-id="<your client id>" --client-secret="<your client secret>" --scope="https://www.googleapis.com/auth/calendar"
サイト内ではこのコマンドを実行するとブラウザが立ち上がり
OAuthの認証の承認をすると ~/.google-api.yaml がダウンロードされるという旨が記載されているが
一向にダウンロードされません。
理由は簡単で、Google ChromeおよびFireFoxでは.google-api.yamlファイルがダウンロード
されるのですがなぜかIEだとされないというよくわからない不具合のせい。
なので、IEでも問題ないようにコードを書きました。
# coding: utf-8 require 'google/api_client' require 'google/api_client/client_secrets' require 'google/api_client/auth/installed_app' require 'json' require 'yaml' client = Google::APIClient.new( :application_name => 'Example Ruby application', :application_version => '1.0.0' ) plus = client.discovered_api('plus') flow = Google::APIClient::InstalledAppFlow.new( :client_id => 'クライアントID', :client_secret => 'クライアントシークレット', :scope => ['https://www.googleapis.com/auth/calendar'] ) client.authorization = flow.authorize File.open("./.google-api.yaml", "w"){|f| x = { "mechanism" => "oauth_2", "scope" => "https://www.googleapis.com/auth/calendar", "client_id" => client_secrets.client_id, "client_secret" => client_secrets.client_secret, "access_token" => client.authorization.access_token, "refresh_token" => client.authorization.refresh_token } f.puts(x.to_yaml) }
上記コードを実行すると.google-api.yamlファイルが実行ディレクトリに作成されます。
あとはgoogleカレンダーからデータを取得します。
oauth_yaml = YAML.load_file('./.google-api.yaml') client = Google::APIClient. client.authorization.client_id = oauth_yaml["client_id"] client.authorization.client_secret = oauth_yaml["client_secret"] client.authorization.scope = oauth_yaml["scope"] client.authorization.refresh_token = oauth_yaml["refresh_token"] client.authorization.access_token = oauth_yaml["access_token"] al = client.discovered_api('calendar', 'v3') # 時間を格納 向こう一か月分 today = Date.today time_min = Time.utc(today.year,today.month, today.day, 0).iso8601 time_max = Time.utc(onemonth.year, onemonth.month, onemonth.day, 0).iso8601 # イベントの取得 params = {'calendarId' => conf["calid"], 'orderBy' => 'startTime', 'timeMax' => time_max, 'timeMin' => time_min, 'singleEvents' => 'True'} result = client.execute(:api_method => cal.events.list, :parameters => params) # イベントの取得 params = {'calendarId' => conf["calid"], 'orderBy' => 'startTime', 'timeMax' => time_max, 'timeMin' => time_min, 'singleEvents' => 'True'} result.data.items.each do |event| p event.start.dateTime # 開始時間 p event.end,dateTime # 終了時間 p event.summary # タイトル p event.location # 場所 end
こんな感じになります。
人材募集企画 2011年版を解いてみた
ぷりんさんのプロフィール - はてなさんの記事を見て
自分ならどう書くかなと試してみました。
内容はこちら
↓
ぷよぷよの問題(人材募集企画 2011年版 問題2)をC++解いてみました。 - Gobble up pudding
試験内容はこちら
↓
人材募集企画 2011年版: 人生を書き換える者すらいた。
正直速度面ではループが多いため少し遅い気がします。
最適解とは言いがたいですが、まずまずと言ったところでしょうか。
追記:ちょっと修正しました。
N=0 G=1 Y=2 R=3 CHECKED=4 class PuyoPuyo def initialize list @list = list end def delete chain = 1 clone = Array.new @list.each{|line| clone << line.clone } points = get_del_points(clone) return if points.length == 0 points.each{|point| point[0].upto(@list.length - 1){|n| @list[n][point[1]] = @list[n + 1] ? @list[n + 1][point[1]] : N } } show chain delete chain + 1 end def get_del_points list del_points = Array.new 0.upto(list.length - 1){|n| 0.upto(5){|m| c = list[n][m] next if c == N || c == CHECKED list[n][m] = CHECKED points = check_all_side(c, n, m, list) next if(points.length < 4) del_points += points } } del_points.sort! {|a, b| b[0] <=> a[0] } return del_points end def check_all_side c, n, m, list points = Array.new points << [n,m] # 下 if n != 0 && list[n-1][m] == c list[n-1][m] = CHECKED points += check_all_side(c, n-1, m, list) end # 上 if n+1 < list.length && list[n+1][m] == c list[n+1][m] = CHECKED points += check_all_side(c, n+1, m, list) end # 左 if m != 0 && list[n][m-1] == c list[n][m-1] = CHECKED points += check_all_side(c, n, m-1, list) end # 右 if list[n][m+1] == c list[n][m+1] = CHECKED points += check_all_side(c, n, m+1, list) end return points end def show chain p '-------------------------' p "#{chain}連鎖" p '-------------------------' (@list.length - 1).downto(0){|n| 0.upto(5){|m| output = @list[n][m] == R ? 'R' : @list[n][m] == Y ? 'Y' : @list[n][m] == G ? 'G' : ' ' print(output) } print "\n" } p '-------------------------' end end puyo_list = Array.new puyo_list << [G,R,Y,G,Y,R] puyo_list << [G,R,Y,G,Y,R] puyo_list << [G,R,Y,G,Y,R] puyo_list << [R,Y,G,Y,G,G] puyo_list << [Y,R,R,G,R,G] puyo_list << [Y,G,Y,R,Y,R] puyo_list << [Y,G,Y,R,Y,R] puyo_list << [G,Y,R,Y,R,G] puyo_list << [Y,G,Y,R,Y,G] puyo_list << [R,Y,G,Y,R,G] puyo_list << [G,Y,G,Y,R,R] puyo_list << [R,Y,Y,G,Y,G] puyo_list << [N,N,G,Y,R,R] puyo = PuyoPuyo.new puyo_list puyo.delete
bashの脆弱性
かなり緊急度の高い障害ですね。
bashのコマンドが自由に実行できてしまうからかなり厄介です。
というわけで
MacとCentOSのbashのupdateをかけました。
とりあえず、自分のbashに脆弱性が存在するかどうかの確認から。
下記コマンドを実行。
$ env x='() { :;}; echo vulnerable' bash -c 'echo hello'
そうすると下記の様に表示されました。
vulnerable hello
というわけでばりばり脆弱性まっただ中なわけですが
とりあえずCentOSのほうは
$ yum update bash
でOK。一応サーバー再起動が吉。
Macのほうはportとかhomwbrewとか使って最新のbash入れるのが
よいです。そのうちAppleも出すだろうけど現状は出てないので。
$ sudo port install bash
上記コマンドでインストールされたbashを
/bin/bashと入れ替えるのもお忘れなく。
これで先ほどのコマンド
$ env x='() { :;}; echo vulnerable' bash -c 'echo hello'
を実行すると
bash: warning: x: ignoring function definition attempt bash: error importing function definition for `x' hello
と表示されます。
しかし、対応が速いですね。
備忘録(PostgreSQLで様々な一覧を取得)
今回の記事はPostgreSQLのよく使うわりにいつも調べているSQLの一覧について
備忘録として記載します。
テーブル一覧
select relname as TABLE_NAME from pg_stat_user_tables
テーブルとカラム一覧
select cl.* from information_schema.columns cl inner join pg_stat_user_tables ut on cl.table_name = ut.relname order by ordinal_position;
外部キーの一覧を取得するSQL
SELECT tc.constraint_name, tc.table_name, kcu.column_name, ccu.table_name AS foreign_table_name, ccu.column_name AS foreign_column_name FROM information_schema.table_constraints tc INNER JOIN information_schema.key_column_usage kcu ON tc.constraint_name = kcu.constraint_name INNER JOIN information_schesema.constraint_column_usage ccu ON ccu.constraint_name = tc.constraint_name WHERE tc.constraint_type = 'FOREIGN KEY'
ログインユーザーのテーブル、カラムの一覧および
主キー及び外部キーの情報一覧
SELECT cl.table_name, cl.column_name, fk.constraint_name, fk.foreign_table_name, fk.foreign_column_name, fk.constraint_type FROM information_schema.columns cl INNER JOIN pg_stat_user_tables ut ON ut.relname = cl.table_name LEFT OUTER JOIN (SELECT tc.constraint_name, tc.table_name, kcu.column_name, ccu.table_name AS foreign_table_name, ccu.column_name AS foreign_column_name, tc.constraint_type FROM information_schema.table_constraints tc INNER JOIN information_schema.key_column_usage kcu ON tc.constraint_name = kcu.constraint_name INNER JOIN information_schema.constraint_column_usage ccu ON ccu.constraint_name = tc.constraint_name WHERE tc.constraint_type IN ('FOREIGN KEY','PRIMARY KEY')) fk ON fk.table_name = cl.table_name AND fk.column_name = cl.column_name ORDER BY cl.table_name, cl.ordinal_position;
なにか間違いやもっといい書き方等あれば教えていただけると有り難いです。
Webスクレイピング(imgタグのURLの相対パスについて)
Webスクレイピングしている時に
imgタグのURLを取得したい場合というのはよくあります。
ただそういう際に困るのはimgタグのsrcが下記のように相対パスで書かれている場合です。
<img src="../img/hello.png">
今時のHTMLでは普通相対パスで書くことはあまりないのですが
レガシーなシステムではよくあることです。
このように相対パスから正確なURLを取得する際になかなか面倒です。
しかしRubyの場合は下記のように一行でいけます。
require 'uri' URI.join("http://hogepiyo.jp/path/to/index.html", "../../img/hello.png").to_s
とすると
http://hogepiyo.jp/img/hello.png
とURLを取得することが可能です。
今回は以上です。
printfは遅い
C言語でデバッグの時とかに使われるprintfはとてつもなく便利で
とりあえず、一番最初に使われる関数だと思います。
#include <stdio.h> int main(int argc, char **argv){ printf("Hello World!\n"); return 0; }
私個人としては、どんな言語を始めるにしても
とりあえず "Hello World!" を出力するプログラムを書くのがプログラミングの神様への
礼儀だと思っています。
というのはどうでもいい話なのですが、今回はprintfはとてつもなく遅いというお話です。
私もあまり気にしたことはないのですが
今回、WindowsのSQLServerをOLE DB経由で呼び出すプログラミングを作成している際に気がつきました。
printfがあるせいで大量データを取得する際に異常に遅くなるのです。
というわけでこんなサンプルを作成しました。
#include <stdio.h> #include <time.h> void method1(); void method2(); int main(){ FILE *fp = fopen("./time.txt", "w"); clock_t start, end; start = clock(); method1(); end = clock(); fprintf(fp, "時間:%.10f\n", (double)(end-start)/CLOCKS_PER_SEC); start = clock(); method2(); end = clock(); fprintf(fp, "時間:%.10f\n", (double)(end-start)/CLOCKS_PER_SEC); fclose(fp); return 0; } void method1(){ int i =0; int sum = 0; for(i = 0; i < 10000000; i++){ printf("%d\n", i); sum += i; } } void method2(){ int i = 0; int sum = 0; for(i = 0; i < 10000000; i++){ sum += i; } }
これの結果は一目瞭然で
method1は
時間:2.1418420000
method2は
時間:0.0278430000
printfがないと0.03秒以下なのに
printfがあると2秒以上かかるという結果に。。。
最適化を行わずにコンパイルしたので、ループ処理はどちらも行っています。
(余談ですが最近のコンパイラは異常に賢いので最適化するとmethod2ではコンパイル時に
勝手に計算して値を作成するため実行時にはループしません。)
というわけで実行速度を重視する場合に正規のモジュールを作成する際は
printfを削除していきましょう。