systemd上でxrandrが動かないのを解決した回

目的

systemd上でXアプリケーションを動作させる。

理由

Manjaro Linuxではモニターを繋いだだけでは自動でマルチモニタにならないため。マルチモニタを使う場合は xrandr を用いて

xrandr --output LVDS1 --auto --primary --output VGA1 --auto --above LVDS1

といったコマンドをいちいち打つ必要がある。面倒なのでコマンドをシェルスクリプトにしてモニターを繋ぐたびに手動でシェルスクリプトを実行していたが、ぶっちゃけめんどくさくなってきたので自動化しようと考えた。

提案手法

同じようなことを考えることはいるもので、下記のようにタイマー機能で1秒ごとにスクリプトを実行して切り替えを自動化している人がいることがわかった。

ArchLinuxで自動でdisplayの接続を認識し調整する

上記のページはウィンドウマネージャーとして awesome 環境を用いているが、自分は Xfce なので cron か systemd を検討した。自分の環境に cron はインストールしていないので環境を汚したくないなと思って systemd で自動化することに決めた。
systemd での自動実行には systemd.timer を用いればできることがわかったので、これについて調べた。

systemd.timer について

参考 systemd/タイマー - ArchWiki

ざっくりと言えば、<サービス名>.service と同じディレクトリに <サービス名>.timer を置いてやればいい。
systemctl daemon-reload も念の為忘れずに。

.service と .timer を書いた

autodualmonitor.service

[Unit]
Description = Automatic dual-single monitor switcher

[Service]
Type = oneshot
ExecStart = /home/<ユーザー名>/MyShellScript/auto_dualmonitor.sh
Requires=lightdm.service

autodualmonitor.timer

[Unit]
Description=Automatic dual-single monitor switcher : timer

[Timer]
OnBootSec=1min
OnUnitActiveSec=1sec

[Install]
WantedBy=timers.target

両方とも /etc/systemd/system ディレクトリに配置した。スクリプトは上記の ExecStart に書かれている通りの場所に配置した。

トラブルシューティング

systemctl daemon-reload

してから動くか試すために

sudo systemctl start autodualmonitor.service

を実行したがエラーが出て動作しなかった。 .timer もenableにしてみたが Active: failed (Result: exit-code) になっており、正常に動作していないことがわかった。

systemctl status autodualmonitor.service

でログを見てみたところ、 Can't open screen というログが見られた。どうやら xrandr が動いていないようだ。
調べてみたところ、Archlinux wiki の次のページに答えがあった。

systemd/ユーザー - ArchWiki

DISPLAY は X アプリケーションがどのディスプレイを使えばいいのか知るために使用されます。XAUTHORITY はユーザーの .Xauthority ファイルのパスと、X サーバーにアクセスするのに必要な cookie を指定します。systemd ユニットから X アプリケーションを起動する場合、これらの変数を設定する必要があります。バージョン 219 から、セッションが開始したときに DISPLAY と XAUTHORITY を systemd --user デーモンの環境にアップロードする X11 セッションアプレット /etc/X11/xinit/xinitrc.d/50-systemd-user.sh が systemd に付属するようになりました。これによって、X を標準の方法で起動しているかぎり、ユーザーサービスは DISPLAY や XAUTHORITY を使用することができるようになっています。<<

要約するに、DISPLAYとXAUTHORITYの環境変数が設定されていないとxrandrのようなXアプリケーションは動作しないということらしい。で、ターミナルから実行して動作するのに systemd では何故動作しないのかといえば、

systemd のユーザーインスタンスは .bashrc などに設定された環境変数を全く継承しません。<<

ということだった。つまりはシェルスクリプト内でDISPLAYとXAUTHORITYを設定してやれば動作すると見ていいだろう。そこで autodualmonitor.sh(モニター切り替え用のスクリプト) を次のように書き換えた。

autodualmonitor.sh

#!/bin/bash

IN="LVDS1"
EXT="VGA1"

export DISPLAY=:0.0
export XAUTHORITY="/home/<ユーザー名>/.Xauthority"

if (xrandr | grep "$EXT disconnected"); then
    xrandr --output $IN --auto $EXT --off
else
    xrandr --output $IN --auto --primary --output $EXT --auto --above $IN
fi

大抵の場合、DISPLAYは:0.0なので特に考えずにそのまま書いた。XAUTHORITYは echo $XAUTHORITY を実行して調べてきたものをそのまま書いた。

書き換えてから念の為 sudo systemctl daemon-reload し、systemctl start autodualmonitor.service がエラーを出さないことを確認してからPCを再起動した。

再起動後に systemctl status autodualmonitor.timer を実行して見てみると Active: active (waiting) となっており、モニターを抜き差ししてみると、少し時間を置いてモニターが接続されることが確認できた。

まとめ

  • Xアプリケーションを用いる際には DISPLAY と XAUTHORITY の環境変数が使われているので留意する。
  • systemd には .bashrc などで設定した環境変数を一切継承しないので留意する。
  • systemd 関係で詰まったときは systemctl status とシェルスクリプト上で echo を組み合わせてデバッグする。
  • やっぱりLinuxって面倒くさい

ThinkPadX230を買ったのでManjaro Linuxをインストールしたらとんでもなく起動に時間がかかるので解決した話

はじめに

Think Pad X230を中古で買いました。22,800円。

メモリを増設して8GBにしておきました。低電力メモリで動くんだねこれ。

Windows10との別れ

Windows10がインストール済みでしたが、WindowsはSteam専用機で事足りているので、Linuxを入れました。

今回選んだのはManjaro Linuxです。


参考
メインページ (日本語) - Manjaro Linux

Think PadへのManjaro Linuxのインストール手順

1. Stable Releaseからxfce版の18.0.4のisoをダウンロード

Downloading File / - Manjaro Linux - OSDN

2. Image WriterでUSBにisoイメージを書き込み

3. Think PadのBIOSを開いてブートの優先度を変えておく。

BIOSThinkPadのロゴが出ている状態でF1
shiftキー押しながら^キーで起動優先度を上に移動できる。USBの優先度を最上位にする。

4. 起動したらインストール

自分はパーティション消してインストールしました。

5. 終わるまで待つ

6. 再起動

インストール完了したが・・・

起動が遅い

起動が遅い!(重要)

なぜか起動に2分近くかかる始末。これを解決した。

はじめにやったこと

原因を探るために、

systemd-analyze

で起動時間を見てみた。5秒。

そんなわけないだろ・・・

次にブート時のログを見るために、

dmesg

でログを表示した。

明らかに時間がかかっているログがあり、メッセージをみると”crng init done”とあった。

ググってみると乱数生成器が乱数生成しきるまで時間がかかっているらしいことがわかった(というかもしかしてタイムアウトまで待ってる?)

対策を調べてみるとrng-toolsとかhavegedで乱数生成を手伝わせるのがいいらしいことがわかった。
今回は色々とあって縁のあるrng-toolsをインストールした。
Rng-tools - ArchWiki

rng-toolsのインストールと有効化

1. pacmanのパッケージリストをアップデートする
インストールしたてほやほやなのでパッケージリストをアップデートしないと何もインストールできないので、

sudo pacman -Syy

してやる。

2. rng-toolsのインストール

sudo pacman -S rng-tools

でrng-toolsをインストールする。

3. 確認

rngd -f

これで乱数生成器が起動(どんどん/dev/randomにぶち込まれていく状態)

dd if=/dev/random of=/dev/null bs=1024 count=1 iflag=fullblock

これをrngd -fが起動していない状態でやるとバチクソ時間がかかる。rngd -fを起動すると一瞬で終了する。サラマンダーよりはやい

4. rng-toolsのサービスを有効化
あとは起動時にrngdが起動するように設定する。

systemctl enable —now rngd.service

でOK。確認は

systemctl status rngd.service

でenabledになっているかを見ればよい。

結果

Manjaro Linuxの起動が速くなった!

具体的には2分かかっていたところが14秒で終わるようになった。


ちなみにcrng initが動いている理由をよくわかってないままやったので、その辺は後々調べておこうと思う。

GASとOutgoing WebhookでSlackのbotを作った時に引っかかった部分

GAS(Google Apps Script)とSlackのOutgoing WebhookでSlackのbotを作ってみました。

はじめに

もともとはRustで書いたものを動かすつもりでしたが、どこにデプロイするかという問題にぶち当たりました。

お金も出したくないので無料でSlack botを作れないかと思って調べたところ、GASに行き当たりました。

参考にしたのは
Slack BotをGASでいい感じで書くためのライブラリを作った - Qiita
です。

どんなものができたか

内容

「突然のほにゃらら」に反応して、吹き出し化するbot。以上。

動作

f:id:sorenuts:20190612110249p:plain
できたもの

ソース

ぶち当たったところ

環境変数の扱い方

参考サイトを見てみると、

var prop = PropertiesService.getScriptProperties().getProperties();
prop.token

APIキーを環境変数から取り出しているみたいなのだけど、上手く動作しない。
なので

 var token = PropertiesService.getScriptProperties().getProperty('SLACK_ACCESS_TOKEN');

で直接取り出した。

Slackのスタンプの扱い

Slackのスタンプは

:hoge:

といった感じにコロンでくくられているのだが、そのままこれを受け取って文字列の長さをlength()で出してしまうと、スタンプで1文字なのに、コロン2つと中の文字を合わせて6文字扱いになってしまう。

こんな感じで吹き出しのサイズがおかしくなる。

f:id:sorenuts:20190612203723p:plain
変更前はこうだった

そこで文字列の長さを測る関数を別に用意した。
コロンからコロンまでを無視し、対応するコロンがない場合については巻き戻して文字列を数える関数である。

2バイト文字を2文字として数える関数にこの機能を盛り込んでおいた。半角と全角だと文字幅が違うからね。

URLエンコード

上と関連した話として、GASに飛んでくる文字はURLエンコードで飛んでくるみたいで、ASCII文字の記号は%xx形式になっている。

だから、コロンをそのまま判定しようとして

if ( text.charAt(i) == ':'){hogehoge}

としようとしても無駄である。

コロンの場合は"%3A"になるので、切り出すか、%に当たった場合に記号として判別するかした方がよい。

GASの更新

書いたスクリプトが反映されたりされなかったりして悩んだ。
「公開→ウェブアプリケーションとして導入」の後に、プロジェクトバージョンを最新にして更新しておかないとダメみたい。要検証。

おわりに

GASとかいう便利なものがあるとは知らなかった。思わぬ収穫。

botについては吹き出しの下側もサイズをきちんとしておきたい。そのうち。

Serenityを使ってDiscordをRustから遊ぶ

はじまり

ちょっと作りたいものがあったのでDiscordのAPIを調べてました。

ぶっちゃけた話、Pythonでdiscord.pyを使った方が楽なんだと思うんですけど、Pythonをみたら発狂して転げ回る病気にかかったということにしているので今回はRustで。


RustでDiscordAPIを叩くライブラリを探してみるとSorenityというライブラリが見つかりました。

github.com

日本語で説明しているページが見当たらなかったので、しばらくあちこちにらめっこしながら、とりあえずサンプルが動いたのでそこまで書いておきます。

下準備

まずはDiscord向けのbotを作る準備をしないといけません。Discord向けのアプリを作るためにまずデベロッパーポータルへ行きましょう。

discordapp.com

Discordにログインした状態でアクセスすると、下のようなページが出ると思います。

f:id:sorenuts:20190604213214p:plain
アプリケーションを作る

右上の"New Application"をクリックし、作成するアプリケーションの名前を入力して作成します。

日本語でも大丈夫みたいですね。

作成すると下のようなページが出るはずです。

f:id:sorenuts:20190604214002p:plain
アプリケーションを作った

そうしたら上図の赤丸のBOTをクリックします。

f:id:sorenuts:20190604214209p:plain
BOTページ

右のADDBOTをクリックすると、

"ADD A BOT TO THIS APP? "
"Adding a bot user gives your app visible life in Discord. However, this action is irrevocable! Choose wisely."

と、「bot追加したらもう戻れねえぜ!賢い選択を。」的なことを聞かれるので"Yes, do it !"を力強くクリックしましょう。


余談ですが、"Choose wisely"は『インディー・ジョーンズ/最後の聖戦』を元ネタとするミームみたいですね

それはさておき、クリックすると、

f:id:sorenuts:20190604215502p:plain
BOTが生まれた

上図のようなページに移動します。

"A wild bot has appeared!"
「あ!やせいの BOTが とびだしてきた!」ですかね。
Discordは本当にゲーム関連の洒落が多くて素敵ですね。

それもさておき、上図の赤丸部分がプログラムで使用することになるトークンです。後で使います。覚えておいてください。

訪れるたびに毎回少しずつ変化しますが、いつ作ったものを使っても問題ないです。


次に、左カラムのOAuth2をクリックします。

移動先のページをスクロールすると、下図のようなチェックボックスが大量に出てくるかと思います。

f:id:sorenuts:20190604220335p:plain
OAuth2のURLジェネレータ

ここではbotにチェックを入れます。するとさらに下に下図のようなチェックボックス群が出てきます。

f:id:sorenuts:20190604220521p:plain
BOTの権限設定

このチェックボックスbotに与える権限を設定できます。これはbotを招待する際に権限オフにもできます。

とりあえず試すために管理者にチェックを入れます。

その後2つ上の図の赤丸でリンクをコピーし、それにアクセスすると下図のような画面が出ます。

f:id:sorenuts:20190604220823p:plain
BOTをサーバーに追加する

そこから追加するサーバーを選んで認証を押してやると

f:id:sorenuts:20190604221006p:plain
BOTがスポーンした

BOTがサーバーに参加します。
が、当然このままでは何もできません。
プログラムで動かしてやる必要があります。

SerenityでDiscord BOTを動かす

とりあえずSerenityをcloneしてきましょう。

git clone https://github.com/serenity-rs/serenity.git

そうしたらexampleディレクトリ内の01_basic_ping_botに移動しましょう。

cd serenity/examples/01_basic_ping_bot/

それでもってcargo run・・・といきたいところですが、このままだと「トークンの環境変数がないぞ」と怒られて動きません。
トークンをプログラム内か環境変数に書いてやる必要があります。

コードをいじらないで動かす場合は、

export DISCORD_TOKEN=<ここにトークン>

とでもしておけばいいと思います。

コードをいじって動かす場合は45,46行目の

    let token = env::var("DISCORD_TOKEN")
        .expect("Expected a token in the environment");

    let token = "ここにトークン"

としておきましょう。

そうしたらcargo runします。


無事起動し、サーバーに接続できると、コンソールに

<BOTの名前> is connected!

が出ますので、そうしたらDiscord上で"!ping"と書き込んでやると・・・

f:id:sorenuts:20190604222931p:plain
こいつ・・・動くぞ・・・!
動きましたね。

まとめ

というわけで、SerenityでRustからDiscord BOTを動かしてみました。
学校から動かしたらプロキシに引っかかって動かなかったり、cargo run自体が通らなかったり、そもそもサンプルコードを真剣に読んでなかったりと手こずりましたが、無事動いたのでよしとします。

今後はこれを使って、前からやりたかったことをやってみようと思います。

最後まで読んでいただき、ありがとうございました。


PS:どこかインターンに行きたい・・・

バーニラバニラで練習題

ことの始まり

サークルの先輩方との飲み会にてズンドコキヨシプログラムを知った。
→パイセン「バニラの求人のやつもありやな」
→詳細な仕様がサークルのSlackに上がってきた(!?)
Golangの練習がてら書いてみるか〜
→書 き ま し た

バニラの歌詞

こんな感じだったような

※
V A N I L LA バニラ!
V A N I L LA バニラ!

※※
バーニラ バニラ バーニラ 求人
バーニラ バニラ 高収入
バーニラ バニラ バーニラ 求人
バーニラ バニラでアルバイト

※※繰り返し

※繰り返し

バニラの求人見たーいー 見たーいー 見たーいー
バニラの求人見たーいー ニャニャニャーニャーニャニャーニャー

仕様

下記のSTEP1からSTEP6までを実行。「見たーいー見たーいー・・・」の部分については考えないことにした(「にゃにゃにゃーにゃーにゃにゃーにゃー」は含めてもよさそう?)

  • STEP1

V!, a!, n!, i!, l!, la!の中からランダムに出力
V!, a!, n!, i!, l!, la!の順番で出てきたら”バニラ!”を出力。

  • STEP2

STEP1をもう一回

  • STEP3

“バーニラ”, “バニラ”, “バニラで” の中からランダムに出力
バーニラ, バニラ, バーニラ の順番で出てきたら”求人!”を出力

  • STEP4

“バーニラ”, “バニラ”, “バニラで” の中からランダムに出力
バーニラ, バニラ の順番で出てきたら”高〜収〜入〜!”を出力

  • STEP5

STEP3をもう一回

  • STEP6

“バーニラ”, “バニラ”, “バニラで” の中からランダムに出力
バーニラ, バニラで の順番で出てきたら”高~収~入~!”を出力しておわり。

コード

gitに投げた。
github.com

感想

Golangのいい練習になった。

ズンドコ節を知らない世代が増えてきた頃にはもしかすると需要があるのではないだろうか(本当に?)
頭の中に残る繰り返しを含む歌は練習用の題材としていいのかもしれない。多分。

.pcapファイルについてちょっと調べた

パケットキャプチャではおなじみのpcapファイルについて、調べたのでまとめます。

動機

研究室で取り扱っているpcapファイルを管理するためにpcapパーサーを作ろうと思った。
そのためにpcapファイルの構造を調べたが、知りたい情報のある日本語の解説が見つからなかったので調べてまとめた。

pcapファイルの構造

HTTPパケットの入力の概要
上記ページはHitachiのuCosminexus Stream Data Platform - Application Framework システム構築・運用ガイドである。pcapファイルの構造についてはこちらに書かれてたので参考になった。
図を見た方が早いが、

  • Pcapファイル自体のファイルヘッダ(24バイト)
  • キャプチャしたパケット
    • キャプチャしたパケットのヘッダ(16バイト)
    • キャプチャしたパケットのデータ(可変長)

という構造になっているようだ。

Pcapファイル自体のファイルヘッダの構造

Development/LibpcapFileFormat - The Wireshark Wiki
上記のページによると、Pcapファイルのヘッダは下記のようになっているとのこと。

typedef struct pcap_hdr_s {
        guint32 magic_number;   /* magic number */
        guint16 version_major;  /* major version number */
        guint16 version_minor;  /* minor version number */
        gint32  thiszone;       /* GMT to local correction */
        guint32 sigfigs;        /* accuracy of timestamps */
        guint32 snaplen;        /* max length of captured packets, in octets */
        guint32 network;        /* data link type */
} pcap_hdr_t;

それぞれについての説明を見ていくと、

magic_number

ファイルの種類を識別する際に用いる。4バイト。

version_major

ファイルフォーマットのメジャーバージョン(ver:x.yのxの方)。2バイト。

version_minor

ファイルフォーマットのマイナーバージョン(ver:x.yのyの方)。2バイト。

thiszone

パケットヘッダのタイムゾーンGMTとどれだけずれているかの値。一時間のずれは3600になる。4バイト。

sigfigs

キャプチャしたパケットのタイムゾーンの精度?らしい。基本的に値は0になるとのこと。4バイト。

snaplen

"snapshot length"の略で、パケットのキャプチャサイズを制限するために用いるもの?らしい。通常は65535もしくはそれ以上とのこと。4バイト。

network

リンク層の種類。
www.tcpdump.org
上記のサイトに書かれている数値が入るらしい。Ethernetの場合、値は1になる。4バイト。

パケットのヘッダの構造

同じページを参照した。下記のような構造になっているとのこと。

typedef struct pcaprec_hdr_s {
        guint32 ts_sec; / *タイムスタンプ秒* /
        guint32 ts_usec; / *タイムスタンプマイクロ秒* /
        guint32 incl_len; / *ファイルに保存されたパケットのオクテット数* /
        guint32 orig_len; / *パケットの実際の長さ* /
} pcaprec_hdr_t;
ts_sec

パケットがキャプチャされた日時のUNIX時間。GMTに基づいたタイムスタンプではない場合にthiszoneを用いて調整する模様。4バイト。

ts_usec

パケットがキャプチャされた時間のマイクロ秒にあたる部分。4バイト。

incl_len

キャプチャした際に、実際に「保存された」パケットデータのバイト数

orig_len

キャプチャした際に、実際に「観測された」パケットデータのバイト数

パケットのデータの構造

incl_lenの長さで実際のパケットがそのまま現れる。

構造を確認してみる

SampleCaptures - The Wireshark Wiki
上記Wiresharkwikiから"http.pcap"をダウンロードし、Wiresharkバイナリエディタで開いて確認してみた。

f:id:sorenuts:20180607162829p:plain
WireShark上での表示

f:id:sorenuts:20180607162838p:plain
バイナリエディタ上での表示

pcap_hdr_s

magic_number

値は、
0xA1B2C3D4

D4 C3 B2 A1でググると、
File Signature Database:: D4C3B2A1 File Signatures
からwinpcapのキャプチャファイルだとわかります。

version_major,version_minor

それぞれ、
0x0002
0x0004
となっているので、バージョンは2.4だとわかる。
上記に挙げたWiresharkのページでも
"the commonly used format in its current version 2.4. This format version hasn't changed for quite a while (at least since libpcap 0.4 in 1998),"
と書いてあり、1998年からずっとバージョンは2.4の模様。

thiszone

0x0

sigfigs

0x0

snaplen

0xFFFF
10進数に直すと65535なので、通常の値だとわかる。

network

0x0001
Ethernetを示している模様

pcaprec_hdr_t

ts_sec

0x40A34B23
10進数に直すと1084443427である。下記のサイトでUnix時間からJSTに変換したところ、西暦2004年 3月 13日 19時 17分 7秒だとわかる。

f:id:sorenuts:20180607194351p:plain
Wireshark上での時刻の表示
UNIXタイムスタンプ変換ツール
Wiresharkで表示されている時刻と一致していることがわかる。

ts_usec

0x0004BFB8
10進数に直すと311224である。マイクロ秒と一致していることがわかる。

incl_len,orig_len

両方とも0x3Eで、10進数に直すと62
以降の62バイトとWiresharkで表示されているパケット本体が一致していることが確認できた。

結果

pcapの構造はpcap自体の情報を格納するヘッダ(Wiresharkwikiでは"global header"と記載されていた)、個々のパケットの情報を格納するヘッダ("Record(Packet) Header")、パケット本体("Packet Data")から成り立っているとわかった。

FEHの投票大戦からデータ取ってきてみた(Python)(スクレイピング)

事のはじめ

CTFで調べてみるとやっぱりPythonが有能
Python書くの練習すっぺ。スクレイピングでもやるか。
→ちょうどFEHの投票大戦が開催している
→いっちょやってみっか!(悟空)

とりあえず書いてみた

github.com

で、とりあえず書いてみました。
Twitterに投稿するまでを1セットという感じです。

最初に調べたこと

robots.txtを見てみる

スクレイピングする上ではやっぱり注意しないといけないのが「スクレイピング禁止」かどうかでしょうか
FEH投票大戦スコアページのrobots.txtをとりあえず見てきました。

f:id:sorenuts:20180601235734p:plain

よし(適当)多分大丈夫でしょう。

Pythonでのスクレイピング方法

ライブラリは前にBeautifulSoupというものがあるのを見たので、これについて使い方を調べてみました。

Python3 + urllib + BeautifulSoupでネット上の情報を取得する

HTMLのタグをもとに掘り下げていけば目的の部分を取り出せるようです。

スクレイピング対象の観察

今度はFEH投票大戦スコアページのソースを見に行きました。

f:id:sorenuts:20180602000619p:plain

ご存知、Chromeデベロッパーツール(うちはSRWareIronですが)でソースを見てみると、「n回戦」がarticleタグ単位で、「キャラVSキャラ」がliタグ単位で、「キャラ名とスコア」がpタグで表示されているとわかりました。
また、過去の大戦結果のページを見てみると、最新の対戦カードは上から二番目のarticleタグにくることがわかりました。
また、クラス名は'body-section-tournament'であることもわかりました。
articleタグのクラス名'body-section-tournament'に絞ってスクレイピングしてみると、一番上のarticleタグ、クラス名'body-section-tournament current'まで拾ってきてしまいました。調べてみた感じだと、どうやら同じ文字列が入ってることだけが原因みたいでした。

mankuro.hateblo.jp

仕方ないので常に上から二番目のarticle要素より、データを引っ張ってくることにしました。

実際にスクレイピング

articleタグ内のliタグ内のpタグの要素を引っ張ってきて出力してみると、取り出したかったデータが確認できました。

Twitterに投稿する

ついでなのでTwitterに取得したデータをPythonから投稿してみました。

Twitterへの投稿方法

いつも通りTwitter APIを使えるようにしました(書くの面倒)

pip install twitter

したら、あとはTwitter用のライブラリを導入して、キーやらなんやらを設定して投稿!だけなのですが、このままだと生のコンシューマキーとシークレットを晒すことになって危険です。
そこで、以前Rubyで作成したupdate_name*1でも環境変数をファイルに書いて外部に見えないようにしたのを思い出しました。Pythonでも同じことができると思い、環境変数からキーを読み込む方法を調べてみました。

【GitHub】に載せたくない環境変数の書き方 Python

こちらを参考に、.envにキーを書いて、コードをコピペして終わり!(書くの飽きてきた)

今後

とりあえず今の投票大戦期間で自動的に大戦経過をツイートできないかと考えている感じ。herokuだと止まっている時間が長いので、Red Hat Open Shiftに目をつけ始めている。
あとは劣勢時に通知が飛ばせればなぁとかそんな感じ。過去の傾向から予測して劣勢の予測とかもしてみたいなぁ(以前某所で見たことがあるけども)

*1:Twitterで特定の語尾のつぶやきを拾ってきて、自分のスクリーンネームにするお遊び