僕とコードとブルーハワイ

omega (@equal_001) の日記

Rust で 言語処理100本ノック 第1章 前半

2016/12/16 追記:この記事のコメントで私の煩雑コードにアドバイスしてくださった方々、本当にありとうございました!多くの学びを得られましたことをここで御礼申し上げます(稚拙ながらコメントの返信をしました)。



これは Rust Advent Calendar 2016 の 14日目の記事です。

初心者枠なので、濃密でためになる情報はありません。ごめんなさい。


今年の秋頃から趣味でのろのろとRustについて調べ始め、最近勉強がてらあの有名な言語処理100本ノック をやってみています。

言語処理100本ノックはPythonを想定して問題作成されている事もあってか、Rustで書こうとした時に色々苦労したので、
今回はそのことについてつらつら書いていきます。


長くなるので、今回は第一章の前半だけ。


00. 文字列"stressed"の文字を逆に(末尾から先頭に向かって)並べた文字列を得よ

    let text = "stressed";
    println!("{}",
        text.chars()  // ["s", "t", .. "d"]
        .rev()  // iterableをreverseする
        .collect::<String>()  // iterable to String
    );
    // https://doc.rust-lang.org/std/iter/trait.Iterator.html#examples-17

    // rsplitを使った方法も出来た
    let text_2: Vec<&str> = "stressed".rsplit("").collect();
    println!("{}", text_2.join(""));

ふわっとした感じで言うと、Pythonで言うところの.split("")がchars() にあたるらしいです(細かいことをいうとリスト型ではなく、charのイテレータ)。
まずchars()でiterableにして、rev()でreverse、Stringに変換みたいな感じでやっています。

してるのは、これを入れないとコンパイラが型アノテーションできずにエラー吐くからです。

このあたり最初わからずにだいぶ苦労しました。

ちなみに rsplit() というsplitした上で逆順にリストに格納するメソッドがあったのでそちらでも書いてみました。どっちの書き方が早いのかな...。

01.「パタトクカシーー」という文字列の1,3,5,7文字目を取り出して連結した文字列を得よ.

    let text: Vec<_> =  "パタトクカシーー".split("").collect();
    // .split("")すると0番目と-1番目は""(空文字)
    // mapでもいけそう
    let mut result = "".to_string();
    for (idx, x) in text.iter().enumerate() {
        if idx % 2 == 0 {
            result.push_str(x);
        }
    }
    println!("{}", result);
    // 文字列を先にlistにできたら text.split(|x| x%2 == 0); みたいにできそう
    // https://doc.rust-lang.org/beta/std/vec/struct.Vec.html#examples-50

to_string() で&str->Stringに変換したあと偶数配列だけcharを取得してます。pushは破壊的なのでmutな変数にpush_str()する、という流れです。
そういえば同じようなことが出来るメソッドで to_owned() というのがあるんですが、いまいち違いがわかってません。


02. 「パトカー」+「タクシー」の文字を先頭から交互に連結して文字列「パタトクカシーー」を得よ.

    // 01と同じ方法で
    let text_1: Vec<_> = "パトカー".split("").collect();
    let text_2: Vec<_> = "タクシー".split("").collect();

    let mut result = "".to_string();
    // https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.zip
    let iter = text_1.iter().zip(text_2.iter());
    for x in iter {
        result.push_str(x.0);
        result.push_str(x.1);
        // println!("{}{}", x.0, x.1);  // tupleのaccessはdot
    }
    println!("{}", result);

01と方法はほぼ同じです。
違う点はzip()を使って2つループさせてるところくらいです。Pythonにも同様のものがあります。一旦変数に入れないと行けないところがPythonと違ってちょっと面倒ですが。
zipで回した中身がtupleになっていて、tupleの要素へのアクセスは x.0, x.1という書き方でやるようです。

03. "Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."という文を単語に分解し,各単語の(アルファベットの)文字数を先頭から出現順に並べたリストを作成せよ.

    let text: Vec<_> = "Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics.".split(" ").collect();
    let mut result = "".to_string();
    for x in text {
        result.push_str(x.len().to_string().as_str());
    }
    println!("{}", result);

01, 02と方法変わってない。
そういえばlistの中身を確認するときってドキュメントだとassert使って証明の流れが多いですね。
log的な感じで標準出力してくれたりしないのかな。

04. 元素記号

use std::collections::HashMap;

     :

    let text: Vec<_> = "Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can.".split(" ").collect();
    let mut result = HashMap::<String, usize>::new();

    // 2文字を結合したものを一時的に入れる
    let mut two_chars = "".to_string();
    for (idx, x) in text.iter().enumerate() {
        let word: Vec<_> = x.split("").collect();
        // matchは使えないので愚直にif
        if idx == 0 || idx == 4 || idx == 5 || idx == 6 || idx == 7 || idx == 8 || idx == 14 || idx == 15 || idx == 18 {
            result.insert(word[1].to_string(), idx);  // idx => usize で usizeをstrにcastする方法を見つけられない
        } else {
            two_chars.push_str(word[1]);
            two_chars.push_str(word[2]);
            //result.insert(tmp.to_string().as_str(), idx.to_string().as_str());  // error: expected a literal
            result.insert(two_chars.to_string(), idx);
        }
        // Char_atはunstable https://doc.rust-lang.org/1.1.0/syntax/str/fn.char_at.html
    }

最初、1, 5, 6, 7, 8, 9, 15, 16, 19番目の単語だけ抜き出すというのをmatchでやったのですが、
matchの結果にinsert()は使えないようで、expected type `std::option::Option<&str>というエラーが出てしまったので愚直にfor-ifで判定してます。PythonのIN演算子を探したのですが参照周りの制約で難しいのでしょうか、見当たりませんでした。

ちなみに match ではこういう風に使いたかった。"|" で区切ると or条件になり、それ以外の場合を"_"に書く、という感じの構文で表現できるようです。

match {
    0 | 4 | 5 | 6 | 7 | 8 | 14 | 15 | 18 => result.insert( ... ,
    _  => result.insert(... ,
}

この問題のゴールは、条件に沿ってtextをスライスした結果を連想配列(辞書型もしくはマップ型)にすることなので、Rustにも連想配列がないか調べたところありました
mutな変数にinsert()で要素を追加していくという感じです。

> HashMap::::new();
usizeをstrにどうやってcastするのかイマイチ不明だったので、HashMap::::new()で逃げてます。
まぁ本来は後に文字列出力することも考えて<&str, &str>が良いのでしょうね。

> let mut two_chars = "".to_string();
文字列から先頭2つを抜きだすのは良いんですが、それを結合させる良い方法が思いつかず、一時的にtwo_chars(こういうのはやらないほうが良いんですが...)に突っ込んでます。
"A" + "B" まで簡素に書きたいとは言わないので、今より楽な方法はないかなーと模索してます。



こんな感じで、ドキュメントを読み漁りつつなんとなく動くものができたという感じです。慣れるまでなかなかつらいですね。
Pythonやっぱり楽だなぁというのと、型にこんなに気を使うと型のない言語が不安になりますね。

もっと良い書き方を覚えたら追記していきます。

おわり。

Pythonista+スクレイピング で Advent Calendar 管理

Python Advent Calendar 2016 その2 の7日目の記事です。
qiita.com

★ はじめに

Advent Calendarのサービスの有名所と言えば「Qiita Advent Calendar」と「Adventar」がありますね。
私は両サービスとも利用しているのですが、どちらのサービスに、いつ、どんなカレンダーに参加しているのかたまに忘れてしまうことがあるので、それらがひと目で分かるように、参加登録しているカレンダー情報を一箇所にまとめるiOSアプリをPythonistaで作成しました。

今日はどんな風に作ったのか?というのをつらつら書いていきます。
特に目新しい技術・トリッキーなアルゴリズム等は使ってないのであしからず。

「各サービスのカレンダーをこまめにチェックするなりGoogleカレンダーに登録しておけば良いのでは?」みたいな話はひとまず置いておいて下さい。
技術で無駄に遊びたいときってあるじゃないですか。アレですアレ。
(実はGoogleカレンダーにもいちいち登録するのも面倒くさかったというのが主な理由なんて言えない。)

* その前に、Pythonistaって何?

簡単に説明すると、PythoniOSアプリを開発することができるiOSアプリケーションです。
今回はPythonistaの詳細についてはここでは述べませんが、 私が今年のPyconJPで話したPythonistaについての発表資料があるのでよければ御覧ください。

* 開発環境

今回作ったアプリのコードは https://github.com/Omega014/AdventCalendarCollection に置いてあります。よければ参考までに。

* やりたいことのゴール

↓ 完成形の姿です。

f:id:equal_001:20161207033718j:plain

少ない...。
でもこんな感じでいっぺんに管理したい。


★ 実装方針

タイトルからお察しの通り、スクレイピングで自分が登録しているカレンダー情報を取得します。
流れとしては、

1. 「Qiita Advent Calendar」と「Adventar」のカレンダーのURLを取得
2. 取得したURLからカレンダーページを開き、Beautiful Soupを用いて自分が登録しているカレンダーのタイトルと日にちを抜き出す
3. 抜き出したカレンダーのタイトルと日にちをjsonに保存する(雑にDB代わりにjsonファイルを使う)
4. PythonistaのUIパーツを駆使して好みのカレンダーを作る
5. jsonからデータを読み出し、カレンダーの各日にちと紐づくUIパーツに、カレンダーのタイトルが表示されるようにする

みたいな感じです。
特に目新しい技術を使っているわけではないです。


ということで、各工程について書いていきます。

1. 「Qiita Advent Calendar」と「Adventar」のカレンダーのURLを取得

Adventar はユーザ毎の登録したカレンダー一覧のページがPublicになっているので、そのURLを使います。
(ちなみに私のユーザページのURLは http://www.adventar.org/users/7109
「?year=****」 を付けなくても今年のページに飛びますが、簡単に昔の年のデータも取得できるようにYEARで管理してます。

YEAR = "2016"
ADVENTAR_URL = "http://www.adventar.org/users/7109?year=[]".format(YEAR)

Qiita Advent Calendar もユーザ毎の参加中のカレンダーを見ることができるページがあるのですが、ログインしないと閲覧できないためQiita Advent Calendar 2016の全てのカレンダーのページを対象とし、その中から自分が登録しているものだけを抽出する方法を取ります。

全てのカレンダーはいずれかのカテゴリーに属しているらしく、各カテゴリーページを見るとカレンダーのリンク一覧が見れるので、これを利用してカレンダーページのURLを特定します。

QIITA_CATEGORIES = [
    "to_be_decided",
    "programming_languages",
    "libraries",
    "databases",
    "web_technologies",
    "mobile",
    "devops",
    "iot",
    "os",
    "editors",
    "academic",
    "services",
    "company",
    "miscellaneous"
]

def _scrape_qiita_advent_calendar():
    """ Qiita Advent Calendarから
        参加登録中のカレンダーのタイトルと年月日を取得して返す関数
    """
    # 公開されている全てのカレンダーのURLをリストに集約
    urls = []
    for category in QIITA_CATEGORIES:
        html = urllib.request.urlopen(
            "http://qiita.com/advent-calendar/{}/categories/{}".format(YEAR, category)
        ).read().decode('utf-8')
        soup = BeautifulSoup(html)

        # クラス名変更で動かなくなる可能性がある
        target_xml = soup.select("[class~=adventCalendarList_calendarTitle]")
        for target in target_xml:
            title = target.find_all("a")[-1].string
            url = "http://qiita.com{}".format(target.find_all("a")[-1]["href"])
            urls.append(url)

ちなみに何故全件を対象にしたのかというと、
Qiita Advent Calendar APIなるものがなく、かといってrequestsのpostを使ってログインを試みたのですが対策されてるのかログイン出来ず、Adventarのようにまとまったページに容易にアクセスできなかったので、
スクレイピング処理走らせるのせいぜい3回くらいやろ」ということで全件取得になりました。。

2. Beautiful Soupを用いて自分が登録しているカレンダーのタイトルと日にちを抜き出す

ちなみにbs4はPythonistaに組み込まれているので pip installしなくてもそのまま使えます。BeautifulSoup(html, "lxml") と書きたいなら pip install lxmlすればokです。

アドベントカレンダーでDOMツリーが異なるので、それぞれに合ったスクレイピング処理を実装しています。
デザインの変更などで動かなくなる可能性はありますが、それは仕方ないのでその時はちまちま直しましょうという空気感でやってます。

def _scrape_adventar():
    """ ADVENTARから
        参加登録中のカレンダーのタイトルと年月日を取得して返す関数
    """
    html = urllib.request.urlopen(ADVENTAR_URL).read().decode('utf-8')
    soup = BeautifulSoup(html)
    # クラス名変更で動かなくなる可能性がある
    registrations = []
    for data in soup.find_all("span"):
        date = data.parent.find("span").string[:10]  # '2016-12-05(月)'から曜日を削る
        title = data.parent.find("a").string
        registrations.append({"title": title, "date": date})
        
    return registrations


# TwitterとGithubとでどっちも登録しちゃった時用の為にリストにしておく  
QIITA_TARGET_USERS = ["OMEGA014"]

def _scrape_qiita_advent_calendar():
    """ Qiita Advent Calendarから
        参加登録中のカレンダーのタイトルと年月日を取得して返す関数
    """

             ~ (省略) ~ 

    registrations = []
    # 自分が登録してるカレンダーだけを探して日付とタイトルを辞書に格納
    for url in urls:
        html = urllib.request.urlopen(url).read()
        soup = BeautifulSoup(html)

        title = soup.title.string

        # 特定のユーザ名がauthorの日付を探す
        # クラス名変更で動かなくなる可能性がある
        target_xml = soup.select("[class~=adventCalendarCalendar_day]")
        for idx, target in enumerate(target_xml):
            # 参加登録されていない空き日は飛ばす
            if not target.img:  # imgのaltでユーザ名を取得...
                continue
            user_name = target.img["alt"]
            if user_name in QIITA_TARGET_USERS:
                date = "{}-12-{}".format(YEAR, idx+1)
                registrations.append({"title": title, "date": date})
        time.sleep(60)  # 1minだと短すぎるかな...
        
    return registrations

URL毎にurlopenしてはアクセスしてるので、アクセス先のサーバに負担がかからないようにtime.sleepしてます。
507カレンダーもあったので1分待つのも長く感じるのですが、データの取得を何度もやらないという前提でtime.sleepするくらいで置いてます(12月入ってからカレンダーの追加登録とかそうそうしないやろという)。
ちゃんとやるならaiohttpとかasyncioあたりを使って効率良くデータを取得したほうが良いですね。

3. 抜き出したカレンダーのタイトルと日にちをjsonに保存する

Pythonistaでデータを何処に持たせるかという問題がありまして、外部サーバにDBを作って通信することも可能ですが、そこまで大それたものを作るわけではないので、アプリのディレクトリにjsonファイルでデータを持たせておくというのをよくやります。
読み込むときも楽だし、簡単な実装で扱えるのでjsonでデータ管理はおすすめです。

    # 毎回読み込みすると重くて辛いのでjsonに最新のデータを持たせておく
    filepath = os.path.join(os.path.realpath('./'), 'registrations.json')
    os.remove(filepath)
    with open(filepath, 'a') as f:
        json.dump(registrations, f, indent=4)

ここまでは単なるスクレイピングのお話。

4. PythonistaのUIパーツを駆使して好みのカレンダーを作る

ここからPythonistaの話になります。

PythonistaにはUIパーツを指先一つでスイスイ組み立てれるUI Designerという機能があるので、これを使ってUIパーツを配置し、好みのカレンダーのデザインを作っていきます。(もちろんPythonコードでもUIを生成することも可能です)。

↓骨組み完成図。UI Designer上でみるとこんな感じ。
f:id:equal_001:20161207043844j:plain

使ったUIパーツは以下:

  • Label: 曜日・日付を表示させるだけ
  • TextView: カレンダーのタイトルを表示させる
  • Button: カレンダー情報の更新のアクション(self.refresh)を登録する

この時、LabelとTextViewの命名規則として label1, textview1のように日付と対応するように名前をつけてます。
こうすることで、たとえば12/7のTextViewを呼び出すときに以下のように記述することができるようになって便利です。

day = '7'
self.view['textview'+day]

ちなみに手でポチポチとUIパーツを配置しても良いですが、かなり疲れるのでUIパーツを一気に選択してコピペで書き換えれば楽に生成出来ます。
さらにちなむと、pyuiの実態はただのjsonで、UIパーツの座標や種類などの設定がずらーっと書いてあるだけなので、中身をコピペ&置換する方法でも短時間で生成出来ます。

5. 日付情報と紐づくUIパーツにカレンダーのタイトルが表示されるように設定する

やっていることは単純で、3で保存したjsonからカレンダーのタイトルと日付を読み込み、その日付に該当するTextViewにタイトルを入れる(self.view['textview'+day].text = title) というだけです。
これを登録しているカレンダー分実行しているという感じです。

self.refreshはButtonパーツと紐付けている(UI DesignerでButtonをタップするとActionという項目があるのでそこにself.refreshと入力するだけ)ので、refreshボタンを押したらスクレイピング処理->あたらしいjsonを再度読み込んで反映を自動でやってくれます。

import json
import os
from datetime import datetime

import ui  # Pythonistaのuiモジュール

import scraper  # 1~3で作ったスクレイピング処理をするモジュール


class AdventCalendarCollection (object):
    def __init__(self):
        self.view = ui.load_view('AdventCalendarCollection')
        self.view.background_color = "#ffebd5"
        self.view.present('fullscreen')
        self.view.name = 'AdventCalendarCollection'
        self.reload_data(None)
        self.change_today_bg_color()
        
    def refresh(self, sender):
        scraper.main()
        self.reload_data(None)

    def reload_data(self, sender):
        filepath = os.path.join(os.path.realpath('./'), 'registrations.json')
        with open(filepath, 'r') as f:
            registrations = json.load(f)
        # jsonに保存する時点でdayだけ保存しても良いかもなぁ...
        for data in registrations:
            day = data['date'].split('-')[-1]
            if day[0] == '0':
                day = day[1]
            title = data['title']
            self.view['textview'+day].text = title
    
    def change_today_bg_color(self):
        # 今日の日だけカレンダーの背景に色をつける
        today_datetime = datetime.now()
        if today_datetime.month == 12:
            today = str(today_datetime.day)
            self.view['textview'+today].background_color = '#ffd9d9'


AdventCalendarCollection()

ちなみに地味に self.change_today_bg_color() で今日の日付のTextViewの背景だけ色をつけてます。そんな処理も関数にちょいと書くだけで実現できるPythonistaとても便利!


以上で出来上がりです。簡単ですね!
これで幾つか登録したあとに心配になって何度も担当日をチェックしに行ったりせずにすむ...。

★ まとめ

  • 自分が登録したAdvent Calendarの情報をスクレイピング処理で取得して一つのカレンダーにまとめて見れるiOSアプリをPythonistaで作ってみた
  • Pythonistaを使うとちょっとのPythonコードを書くだけで自分が欲しいアプリを作れて楽しいよ
  • みんなもPythonista触ってみよう! <- これが言いたかった

今日のちょっとした良いこと Advent Calendar 2016 5日目

この記事は 今日のちょっとした良いこと Advent Calendar 2016 の 5日目 です。
www.adventar.org


仕事に勉強にプライベートのアレコレだったりと、なかなか精神的に余裕がない現代人が多いと言われる中で。
今日のちょっとした良いこと、何かあったかなぁと考えてみました。

★ 今日あった良いこと

  • 外国人のおねえさんと目があったときにお互いニコッっとした。笑顔を向けられるっていいね!
  • 12月にしては暖かく、過ごしやすい一日だった。さむいさむい〜っと身体を縮こまらせずにすむので肩こりしない!
  • 会社付近に植えてあるイチョウの葉っぱが黄色く輝いていて美しかった。癒された!
  • 珍しいバイクが走っているのを見かけた。ラッキー!
  • 午前中の頭痛は酷かったけど、前より症状が良くなってきている。よかった!
  • 知人の方から美味しいお魚の干物2種類を頂いた。お弁当の具材が充実するぞ!
  • 私の大好きな人達がそれぞれの嬉しいことがあって喜んでる。なんかこっちも嬉しくなった!

良いことって、ちょっと思い浮かべるだけでこんなにあるんですね。
明日はどんな良いことがあるかな。楽しみだ!╭(*・w・)و"

おわり。






★ とても長い余談という名の独り言

そうはいっても、良いことってイライラに埋もれて忘れがちになっちゃう。そんなときはどうしよう。

世の中には楽しいことしか考えない!という強者がいるけど、そうでない人は多分、日々のイライラに自分の頭の中を支配されてしまったり、ついつい嫌なことを思い出したりしてしまっているのかなーと思います。

私は大学4年~社会人1年目がイライラに支配されてたピークだったような気がします。
最近は(これでも)落ち着いてきて、色々対策をしてからは生きやすい人生になってきました。
そこで、どんなふうに対策してるっけなぁというのを自分の記録用にもまとめてみました。

1. ストレッサーとは距離を置く

(特に) 人間相手だと、ストレスを持ったまま他人と接すると相手を傷つけてしまい、次第に相手も意地を張ったり悪意をぶつけるようになったりと負のループに入るので、他者がストレッサーになってしまったと感じたら理由を述べて距離を置くようにしています。
そうすると大体の方は大人なので、傷つけたことに気づいてなかった、正直に話してくれてありがとうと真摯に受け止めてくれたり、今後のお互いの接し方の改善点などを話し合えたりもするようになります。
理由を述べて距離を置くという方法は仏のような人に教えてもらった対応策の一つですが、うまくいった事例が多いので自分のためにも相手のためにも距離を置く時間というのは大事だなぁと思う今日この頃です。

稀に、自分の過ちを指摘されたことを受け止められずに逆ギレして悪意ある言動をしてくる人がいるかもしれませんが、そんな人に遭遇したときのために

仏「まぁアレだよ、落ち着くまで放っておけばいいんじゃないかな。多分そのうち意地張るのに疲れて、そんなのくだらないことだって気付いて、やめちゃうよ(笑顔でおでんを頬張りながら)」

という言葉をここに置いておきます。

2. ストレッサーに対する見方の視点を変え、対象を観察した上で接する。

イライラしているときって、大体はストレッサーの悪い部分しか見れなくなっていることが多いです。つまり、視野がかなり狭くなってるんですよね。

別の視点から見てみることで自分の凝り固まった考えを一旦リセットし、冷静に対象を観察することで、ストレッサーとのうまい接し方や対応のしかたが見えてきたりします。
なんかイライラする!で放っておくのは精神的にも良くないし成長もしないので、ここはちょっと頑張って世界を広げてみましょう、という感じです。

3. 明るめの好きな音楽を聴く

明るい曲を聴くとなんだか前向きになれます。
傷心時は暗い曲も良いという話もありますが、ストレス溜まってるときに聴くと憎悪が倍増する薬になったりするので、大体は明るい曲を聴くようにします。

Coldplayが作るような世界中の人々に愛される曲を聴いて心を癒やすのも良いですね。
元気といえばアニソンも良いですね。あとアニメの主題歌になっている曲も結構元気になれる系のが多かったりします(銀魂のOP/EDはなんで毎回ああも最高なんですかね...!)。

ちなみに、はっぱ隊のYATTA!が個人的に一番威力がすごいです。
なんか色々な問題がどうでも良くなります。
「やんなるくらい健康だ」「丸腰だから最強だ」「お水飲んだら!うめー!」
とかいうフレーズを謎の快活さで堂々と歌っているのを聴くと本当にどうでも良くなります。いつの間にか手に持ってるジャスミン茶うまいな!って思ってる自分がいます。

4. ゆるいお笑い番組やコメディ映画を視聴する

雑に言うと「笑うという行為は大事」ということですね。
医療の分野でも笑いの効果について研究されてたりしますね。笑うと免疫力が高まるとか、副交感神経が優位になるとかとか。

とは言え、いきなり何も無しに笑え!と言われても特にストレスが溜まってる時はそうそう出来ないので、なんか笑っちゃうなぁとなるコンテンツを消費するという手段を取ります。
最近は Amazon Prime内村さまぁ〜ずが視聴できるようになっていたのでたまに見たりします。あとはジム・キャリーが主演の映画とかはコメディ系が多いのでよく見ます。「フィリップ、きみを愛してる!」とかね、笑いあり涙ありで楽しかった。

5. 絵を描く

個人的に油絵描いたりとかデッサンしたりとかしてるんですけど、これに没頭するとストレス発散になったりします。
絵を描くという行為は心理療法にも取り入られている手法の一つです。
自分の理想像や社会に対する不満等を絵で表現することで、本来はストレスとなるものを絵を描くという過程を経ることで消化する、という。

とは言いましたが、別にそういった効果を狙って始めたわけじゃないです。ただ、何かに没頭したあとはとてもスッキリするのです。私の場合は特に絵を描くこと。

他の人は彫刻だったり、曲を作ったりプログラムを書いたりすることがそれに当てはまるかも知れないですね。


なんかつらつら書きましたけど、その他にも友人達と遊ぶとか、自然散策、温泉に入るとか細かいことはありますが、上記のことをなんやかんややっているとストレスって案外なくなったりするものです。

まずは自分が楽しくやっていくのがいちばん。
良いこと・楽しいことをいっぱい集めよう。


★ 余談の余談

そういえば今日は 国際ボランティア・デー (International Volunteer Day) だそうです。小学生の頃にやったゴミ拾いに熱中したことをふと思い出し。

日本酒 Advent Calendar 2016 4日目

全世界の日本酒好きの皆様、こんにちは @equal_001です。
日本酒 Advent Calendar 2016 4日目を担当します。

www.adventar.org


今日は私のおすすめ日本酒銘柄を一本ご紹介します。

ちなみに日本酒は辛口が好きで、一番好きな日本酒は友人に紹介してもらった宮城のお酒「蔵王」です(これはどちらかと言えば甘めですが)。

では早速おすすめの一本を紹介します!

鍾乳洞で熟成させた日本酒「鍾乳洞熟成酒」

私事ですが、昨年の夏に友人達と岐阜へ旅行に行きまして。
その岐阜の美濃市にあります伝統的建築物群保存地区に、今廣酒販店 という100年以上続く酒屋さんへふらりと寄ったときに出会ったのが、「鍾乳洞熟成酒」でした。

この鍾乳洞熟成酒は、通年温度が一定の鍾乳洞に辛口の特別純米酒を一年置き、熟成させるという珍しいお酒であります。
今廣酒販店と大滝鍾乳洞でしか販売していないという希少な日本酒でして、私が寄った8月はまだ熟成中だったらしく、その場で予約をして出来上がる秋頃に自宅に郵送をしていただきました。

f:id:equal_001:20161201012637j:plain:w240,h360
(何故か別の銘柄の箱に入っていた。出してる本数が少ないので多分専用の箱は作ってないのだろう)

岐阜には名水長良川があり、美味しいお酒がたくさん作られている県で、例に漏れず鍾乳洞熟成酒も長良川の伏流水を使って熟成しているとのことでした。

さて塩梅のお話。
思っていたよりもけっこうな辛口、でも飲んだ少し後にお米の甘みといいますか、美味しいごはんをたくさん噛んだときの甘みがふわりと感じられるお味でした。
鍾乳洞熟成酒の誕生秘話 にも書かれているとおり、「まろやか」な美味しいお酒です。

料理との相性はどうかな、とこのお酒と様々なお量とで数回呑み合わせしたのですが、
おでんやお刺身はもちろん、ピザ、唐揚げ、ビーフシチュー(これはかなり意外だった!)とも合いました。
まろやかさがあるからかですかね、ビールに合うイメージの脂っこいものとも合うのはちょっと意外でした。

そしてなんと、今年も熟成酒ができましたというおハガキが届いておりまして、すぐに電話して取り寄せました。

f:id:equal_001:20161201010506j:plain:w240,h360
( 今年は二本買ってしまった!)

去年とはちょっと味が違い、辛味が強くアルコール感が表に出ていた気がしましたが、あのお米の甘みと「まろやか」さは健在でした。
来年の出来具合も楽しみです(買う気満々だ!)。

今年のものはまだ残っているかわかりませんが、今廣酒販店さんのHPから電話注文出来ますので、皆さんも一度試してはいかがでしょうか。
一般に日本酒と合うと言われているものとはちょっと違う料理と合うので、いろんな食べ物と合わせて楽しめる一品です。

余談

ちなみに岐阜旅行では4人(うち一人は酒飲めないので買ってないけど)でこれだけ買い込みました。。

f:id:equal_001:20161201015756j:plain

飛騨のどぶのどぶろく感はすごかった。どぶろく好きにはたまらない美味しさだった。また飲みたい。

あと、気になった一本。
ロックでうまい日本酒らしい。これを撮影した時点でだいぶ買い込んでいたので泣く泣く諦めたが、次見かけたときには購入したい。。
f:id:equal_001:20161201020249j:plain:w240,h360

こっそりまとめ

  • 「鍾乳洞熟成酒」は辛口でまろやか、そしてビールに合いそうな料理との相性も良い!
  • 岐阜の酒、うまい!

PyLadies Tokyoの二周年記念パーティでLTしてきた

PyLadies Tokyoの二周年記念パーティにLT枠で参加してきました。

さてさて、PyLadies Tokyo 二周年おめでとうございます :)
イベントに何度か参加させてもらいましたが、毎回イベント内容が充実していて楽しいですし、いつも沢山の人が集まっていて、とても良いコミュニティだと感じています。

これからも良き学びと出会いが続きますように!

次のイベントは競技プログラミングについてのイベントをやるそうです。楽しみです!


LT資料

github.com

PyConJP2016でiOS開発環境Pythonistaについて発表してきた

PyConJP2016でiOS開発環境Pythonistaについて発表してきました。

pycon.jp


日本の大きめのカンファレンスで発表するのは初めてだったのですが、80人強と向き合うとなかなか緊張しますね。
今回のPyConは5つの発表が平行して流れており、どのくらいの方が聞きに来てくれるかと不安だったのですが、Pythonistaに興味を持ってくださった方々が部屋の席が一杯に聴きに来てくださってとても嬉しかったです。
序盤から接続不良で画面が度々映らなかったり、動画が再生されなかったりして終始テンパってましたが、
私の発表を最後までずっと聴いてくださった皆様、本当にありがとうございました。m(_ _)m


今回発表した資料をリンクしておきます。
(スライド資料のメモ欄に色々解説書いてます)
当日は実際にコードを見ながら解説したのでその部分がまるっと抜けていますが、これからちょっとずつ画像と文章で解説を更新していきます。
そこが見たいゾッて思ってる方がいたらゴメンなさい。今月中に更新します。

docs.google.com


あと、実際に私が個人的な問題解決のために作ったiOSアプリを晒しておきます。参考になれば幸いです :)
⚠️コードの綺麗さは求めてはいけません!

アプリその1
忙しさにかまけて買った食材を賞味期限切れにしてしまう+冷蔵庫に食べ物があるのにそれを忘れて似たような食材を買ってしまう問題を解決するためのアプリ。これでだいぶ食材が無駄にならずに済んだ!
github.com

アプリその2
私の用途に特化したレシピサイトのブックマークアプリ。これを起動すると、私がよく使うレシピサイトとスーパーのチラシ情報サイトにボタン一つで飛べるようにしている。ブラウザにbookmarkでいいじゃんって思うかもしれないが、「自分専用」っていうのが結構楽しいのだ。デザインも自分で好きなように作れるし、自炊が楽しくなったよ。
ちなみにブックマーク機能を付けたいので実はまだ開発途中。
github.com


そうそう、発表後にハッシュタグ( #pycon_203 )を眺めていたら「Pythonistaを購入しました!」という方や「もう一度触ってみようと思った」という方を観測しました。日本人のPythonistaユーザが増えたぞ!とテンションが上がりました :))))
(英語のドキュメントしかないからか、まだまだ海外ユーザばかりなのです)

Pyhonistaに興味を持ってくださった方、もしかしたらこれから興味を持ってくれる方、ぜひぜひPythonistaでものづくりを楽しみましょう!!



ちなみに、発表風景の動画がuploadされているみたいなので、聴きに来れなかった方は是非いろいろな発表を見てみてください。
個人的には、

あたりが仕事でも使えそうで面白かったなーという印象でした。

www.youtube.com




そういえば、小話を一つ。

プロポーザルを出そうと思ったきっかけを聴かれたので、それについて。
実のところ最初は出すつもりはなく、「レベルの高い発表ばかりなんだろうなぁ、自分の発表ネタなんて誰も聞きたいと思わないだろうなぁ」ととてもネガティブ思考で過ごしてました。
でもある日、何気なーくPyConJPの公式ページを眺めてたら、今回のPyCon JP2016のテーマである Everyone's different, all are wonderful. が目に入りまして。
そのとき、「みんな違ってみんな良い、か。あぁ、もしかしたら人にウケるものとか考えなくて良いのかもしれない。というかそんなこと気にしなくても良いんだな。自分の好きなことや興味のある題材でやっていこう。きっと自分はその方が面白い物事を誰かに伝えられそうだな。」と思えて、その場のノリで2のプロポーザルを提出しました。
一つは査読で落ちちゃいましたが競馬の予測モデルの話。もう一つが、Pythonistaのお話でした。
おそらく、このきっかけがなかったら応募しなかっただろうな、と今思います。

PyConJP2015にも参加しましたが、昨年と違う点は、発表者になると自分のしてきたことに対し多くのフィードバックが得られますし、他人に情報を伝えるのである程度の水準まで技術を知らなければと必死になれることかな、と振り返って思いました。また、懇親会などで自分の発表ネタをきっかけに話しかけていただいたり、自分の知らない分野の話をたくさん聞けました。

スタッフの皆さま並びに参加者の方々、素晴らしいカンファレンスを本当にありがとうございました!

PyConJPは来年も開催されるようですね。技術が繋ぐ新たな出会いを思い描きつつ、その時を楽しみに待っています。

来年はどんなネタで応募しようかなぁ。。。

友人たちとisucon予習会をやってみた感想

isuconの予習会をした記録を書く。


pixivさんが社内isuconの資料を公開してくれたので、そちらの資料をもとに実際に予習会をやってみました。


友人が予習会の準備とかしてくれて、isucon概要や基本の戦略をwikiにまとめてくれたり、各チームのスコアをリアルタイムで見れる表とか作ってくれました。ありがとうございました m(_ _)m

資料:

僕はisucon初参加だったのですが、なんとなくisuconがどういうものかこのwikiのおかげで把握できました。
参加人数は10人で、1チーム2~3人にまとまるように当日にチームを4つ作ってスコアを競ってみました。
とりあえず何をやったか忘れないためにメモする。

今回学んだことをざっくりメモ

最初にやった方がいいこと
  • editorとかバージョン管理まわりとかの環境を早めに整える
    • チームの人が「/tmp/usernameをローカルと見立てて本番masterをクローン&コミットして、本番反映するときは本番masterがある場所でpullする」という素晴らしいバージョン管理方法を教えてくれて、今回はこの方法を実践してみました。メンバーがそばにいるので本番反映しますと一言声かけて実行してみて、だめならrevertするみたいにやってました。git remote add file:///tmp/username みたいなことをするという発想が自分にとっては新しくて、感動しました。
    • debianvimが入っていなくて、しかもapt-get updateしないとvimが入らないという状況だったので、最初に手に馴染んだエディタを入れるための方法を調べておいたほうがいいですね。ちなみに僕はvimを入れるためにカジュアルにupdateしてしまいましたが、updateすると今まで動いていたものが急に使えなくなるという状況になることがあるみたいなので、その辺りの知見があれば心強いですね..。
  • 頻繁に使うコマンドは何かでまとめて管理しておく (今回チームメンバーの人がMakefileをささっと作ってくれました)
    • 後半になるとコマンドのtypeミスが多くなるから、とチームの人が作ってくれました。これは初期にやってくれててとても助かりました。
  • コマンド補完を使えるようにする
    • 最初はtabで補完効かなくて不便だったので、apt-get install bash-completion して使えるようにしました。手馴れたもの以外のコマンドのオプションとかいちいち覚えていられないので..。
  • nginx, mysql, アプリケーションのログを出すようにする
    • slow_query とか便利でした
  • ログを解析するためのツールを導入して負荷が高いところを見てみる(みんなはkataribe, ALPとか使ってた)
  • index貼ってあるか確認してみる
    • 他のチームはindexを貼ってみて一気に2万とかスコア上がってました。相乗効果はアプリのチューニング次第だと思うんですが、早めに試しておくべきだった。
チームで試してみたこと

ぼくはあんまり改善できなかったけど、全体的にこんな感じだったらしい

  • socket通信にする
  • sqlの発行を抑えるためにメモリにのせれるものはのせる
  • workerの調整
  • css/jsあたりをminifyしてみる
  • imageのキャッシュ
  • 最後のベンチマークとるときはログ出力を止める
isucon参加する前に身に付けたいこと
  • isuconでちゃんと使える言語を身につけておく
    • 今回はrubyを選択したのですが、構文的な部分で時間を無駄に食ったので、そういう無駄をなくすためにもそれなりに使える言語を身につけておいたほうがいいですね。
    • あと選択した言語が得意な人がいると強いですね。自分がわかってることが一番ですけども。
  • どのファイルシステム/OSが来てもそれなりに使えるようになっておく
    • 今回はdebianだったのですが、環境構築まわりで疲弊したので、本番前にテストで環境構築してみたほうが本番の精神衛生が保てるとおもう。
  • webアプリケーションのパフォーマンスを改善するための定石を知っておく・事前に実践してみる・サクッとできるまで日頃から鍛錬しておく
    • 定石を知らないと最低限何をすべきかもわからない
    • 定石を知っていても実際どうやるかが頭に入っていなければググる時間が増え、大してパフォーマンス改善できずに試合終了する
    • ちょっとググるだけで問題解決できても素早くできないと他の作業にリソース振れないので日頃の鍛錬大事
チームでやる場合に気をつけたほうがいいなと思ったこと
  • バージョン管理をどうするか事前に決めておく
    • 多分それぞれの楽な方法を持っていると思うんですけど、当日試合がスタートしてからなんとなくで決めると、その決めた管理方法に慣れてる人とそうでない人で作業に差が出るので、可能なら先に打ち合わせして決めたほうがよいかなと感じた。
    • あと、まっさらな開発環境更の整備をどこまで時間をかけるかも事前に相談して決めておくといいですね。環境構築のためのshをdropboxに配置しておき、当日はそれを実行すれば環境が整うようにしておくと消耗しなくて済みそうです。
  • 参加意識とが同じレベルの人とやった方が良さそうな感じがあった
    • 今回、私は「とりあえずやってみるぞ」という気持ちで予習会に参加したのですが、おそらくチームの人はそうではなかった様子で、途中で足を引っ張ってしまったあたりから今後どうすれば相手の迷惑にならないのだろうと考えていて思うように作業できなかったので、まずは本番では同じ意識レベルの人と組んで、「いろいろダメなところがあったけどisuconに参加してみて楽しかったね」で終われる人と組むといいのかなと思いました。
  • 技術レベルが近い人と組むか、それなりにwebサービスのパフォーマンス改善の知識をつけてから参加したほうがいい感じがした
    • isucon初ということもあったのですが、僕が何をするとパフォーマンス改善するかを考えて試そうかなと思った時には経験者さんがガガーッと色々やっていて、その頃には下手にコード触ると逆に迷惑になるみたいな状況になり、相手のパフォーマンスとか精神的な部分にも負荷をかけてしまっていて、後半は僕はいないほうが良いのではという感じになったので、そうにならないためにも改善の知識を身につけてからやったほうがいいなと感じました。
全体的な感想
  • 第一に、体調万全でやる。体調が良くないとイライラしたり集中が続かないので、スムーズに問題解決ができなくなる...。
  • isucon予習会の前にしっかり事前調査しておけば少しは僕もマシな作業ができたかなと反省。
  • 試したいこといくつかあったけど今回できなかったのが悔しかったので、個人的にやってみる。なるべく足引っ張らないように最初に一人で似たようなことを試しておいたほうが良かったなと反省。後半、参加しないで後ろからみてた方が良かったかな、ってちょっと思った。
  • rubyを全く書けなくなっていて自分でも愕然としたのでredmineいじりの練習がてらruby触ろうと思います...本当にだめだめだった
  • プロファイラとかツール周りの知識を一通り自分の中で蓄えておきたいなと思った。そもそもrubyのプロファイラって何使えばいいの?みたいになって死んだ。
  • チームで苦しんだ点としてsinatraアプリの簡単なデバッグ方法がわからなかったんだけど、試合終了してから簡単にできることが判明して死んだ。ちゃんと添付資料読もう...。
  • 辛い気持ちになって嫌な体験にしないためにも本番は気楽にやりたいし、そういう空気になるようにしたい
  • 作業分担というか、二人でやるならインフラとアプリケーションで分けても良かったかもしれない。コンフリクトが発生しないような切り分けを最初に決めて、あとはひたすら担当の作業をするというほうが効率が良かったのかもしれないと今日やってみて思いました。
  • そんなに時間を気にしてやってなかったのでいつの間にか残り1hとかで焦ったので、タイマーとかで時間管理した方が良いですね..結構焦る。


雑にメモしたけど、まだまだ書いてない知見が結構あった(いっぺんに書くと疲れるし多すぎるので別のメモに書く)。
こういうの初めてで、楽しかったです。とても良い経験になりました。
予習会を主催してくれた人たちや参加者の皆、そしてチームメンバー、ありがとうございました!