プロメモグラム

誰が見てもわかるような文章を目指す

Linux上のFirefoxでタイトルバーを隠す

LinuxFirefoxを使う上で、タイトルバーが無駄に伸びているのが気になる。 Chromeでは、タブとタイトルバーが一緒になっているので、それが決めてでChromeを使っていた。

環境

Firefoxのバージョンによって、方法が違うかもしれない。

操作

  1. アドレスバーにabout:configと入力し、設定画面に遷移。
  2. browser.tabs.drawInTitlebarと検索する。
  3. falseになっているので、trueにする。

結果

もともとの画面。タイトルバーが無駄にある f:id:zia_glass:20180602151557p:plain

タイトルバーがなくなりスッキリした。 f:id:zia_glass:20180602151604p:plain

Railsデプロイで困ったことメモ

調べながら解決していったので、自分の詰まったところとそのリンクのまとめに近い。

やっていること

  1. 規模が小さい趣味プログラムをサブディレクトリによって、複数のWebサービスを同一のサーバで起動させる。
  2. HTTPSの設定と、HTTPへのリクエストをHTTPSにリダイレクト。

環境

Rails側設定

/config/environments/production.rb

SSLの強制、/publicの公開、サイトのトップページをサブディレクトリに。

config.force_ssl = true
config.public_file_server.enabled = true
ENV["RAILS_RELATIVE_URL_ROOT"] = "/siteA"
Rails.application.config.relative_url_root = "/siteA"

/config.ru

サブディレクトリで起動するように変更。

require_relative 'config/environment'

map ActionController::Base.config.relative_url_root || "/" do
        run Rails.application
end

/config/puma.rb

ここで、nginxで振り分けるsockを生成する設定。 ポート番号もアプリごとに分ける。

_app_path = "#{File.expand_path("../..", __FILE__)}"
_app_name = File.basename(_app_path)
_home = ENV.fetch("HOME") { "/home/アプリケーションのディレクトリ" }
pidfile "#{_home}/run/#{_app_name}.pid"
bind "unix://#{_home}/run/#{_app_name}.sock"
daemonize true
directory _app_path
port        ENV.fetch("PORT") { ポート番号をアプリごとに設定 }

nginx側設定

設定ファイルをいじり、サブディレクトリをRailsのアプリケーションのポートに振り分ける。 Rails側のタイムアウトの時間設定はproxyのタイムアウトで設定するのが注意どころ。

upstream siteA {
  server unix:///home/~/run/~.sock fail_timeout=0;
}
upstream siteB {
  server unix:///home/~/run/~.sock fail_timeout=0;
}
server {
        listen 80;
        server_name www.example.com;
        return 301 https://$host$request_uri;
}
server {
        server_name www.example.com;
        listen 443 default ssl;
        ssl on;
        ssl_certificate     /etc/letsencrypt/live/www.example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem;
        location /pll {
                proxy_pass http://siteA;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $http_host;
                proxy_set_header X-Forwarded-Proto https;
                proxy_redirect off;
        }
        location /hateconcat {
                proxy_pass http://siteB;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $http_host;
                proxy_set_header X-Forwarded-Proto https;
                proxy_redirect off;
        }

        location / {
                root /var/www/html;
                index index.html;
        }

        error_page 500 502 503 504 /500.html;
        client_max_body_size 4G;
        proxy_connect_timeout       605;
        proxy_send_timeout          605;
        proxy_read_timeout          605;
        send_timeout                605;
        keepalive_timeout           605;
}

問題と解決のリンク

サブディレクトリへの展開

An unhandled lowlevel error occurred.

このようなエラーはSECRET_KEY_BASEが無いときに出ることが多いらしい。 起動時に環境変数を渡してあげる。

puma_error.logで確認できるのでわかりやすい。

Assetsをプリコンパイルしても、404エラーが出る。

プロダクション環境ではデフォルトでは、public/を公開しない。おそらくnginxなどに委ねることもできるからだと思う。

個人的に分かる範囲での正規表現

正規表現についての基本の基本を自分用にまとめる。
できるだけシンプルにまとめたかった。

他にもいろいろできるみたいだが、とりあえずはこれだけでもいろいろできそう。
ところどころ「・・・」とあるが、これは何か文字が入るという意味。

1文字の表し方

文字 概要
[・・・] 括弧内の文字の集合から1つ
[^・・・] 括弧内の文字以外の集合から1つ
[a-z] 小文字、大文字、数値など範囲した集合から1つ
. 任意の1文字
^ 行頭
$ 行末

バックスラッシュによる特殊な1文字

文字 概要
\d 数字(digit?)。[0-9]と等価。
\w 英数字(word?)
\s スペースまたはタブ
\t タブ
\n 改行
 [メタ文字] メタ文字そのものを文字として利用したいときに\でエスケープ

繰り返し系

文字 概要
{n} n回繰り返す
{m,n} mからn回繰り返す
+ 1回以上繰り返す
* 0回以上繰り返す
? 0回or1回。言い換えると省略可能な文字
+?, *? 最小マッチ。マッチする中で+や*の繰り返しが最小限のもの。

文字をまとめる括弧

文字 概要
(・・・) 文字をまとめる。言い換えると文字列。 キャプチャしたい時にまとまりとして使用。 キャプチャは後述。
(?:・・・) ()でまとめたいが、キャプチャしなくていいものを記録しない。
| 〜または〜。(abc|def)など。

キャプチャ

一致するものの中の一部を取り出すことができる。()を使って実現する。

# 言語100本ノックの22問目より。
import sys
import re

lines = ["[[Category:イギリス|*]]",
"[[Category:英連邦王国|*]]",
"[[Category:G8加盟国]]",
"[[Category:欧州連合加盟国]]",
"[[Category:海洋国家]]",
"[[Category:君主国]]",
"[[Category:島国|くれいとふりてん]]",
"[[Category:1801年に設立された州・地域]]"]


pattern = r'\[\[Category:(.*?)(\|.*)?\]\]'
for line in lines:
    for match in re.finditer(pattern, line):
        print(match.group(1))

()を2回使っているが、1つ目の括弧の中身がほしいので、group(1)で取り出している。
取り出し方は言語によって異なると思うが、大体は、1つ目、2つ目という感じで取れそう。

メモ化とline_profilerによる計測

アルゴリズムの勉強などをあまりしていなかったので,メモ化という言葉は就活なんかでの技術試験で知るのが初めてだった.
メモ化自体はそこまで難しいことではなく,何度も同じ計算をしないで,一度計算したものをうまく保存することで計算結果を再利用するというものである.

例として,フィボナッチ数列がよく使われる.
フィボナッチ数列は,fib(n) = fib(n-1) + fib(n-2)で定義されるため,fib(k)が何度も呼び出されることになる.
ここで,メモ化を用いることで,一度計算したfib(k)を保存し,再利用する.

これを,時間計測ツールであるline_profilerを用いて,計測した.

# 通常のフィボナッチ数列
def normal_fib(n):
    if n == 0 or n == 1 :
        return n
    else:
        return normal_fib(n-1) + normal_fib(n-2)

# メモするフィボナッチ数列
memo = [0 for x in range(100)]
def memo_fib(n):
    if n < 2 :
        return n
    elif memo[n] != 0:
        return memo[n]
    else:
        memo[n] = memo_fib(n-1) + memo_fib(n-2)
        return memo[n]

@profile
def main():
    print(memo_fib(20))
    print(normal_fib(20))

if __name__ == '__main__':
    print("Memoization!!!")
    main()
    print(memo)

fib(20)で比較した出力結果は以下のよう.

Memoization!!!
6765
6765
[0, 0, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Wrote profile results to memo.py.lprof
Timer unit: 1e-06 s

Total time: 0.015669 s
File: memo.py
Function: main at line 19

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    19                                           @profile
    20                                           def main():
    21         1         51.0     51.0      0.3      print(memo_fib(20))
    22         1      15618.0  15618.0     99.7      print(normal_fib(20))

当確率ではないランダム

サイコロのように当確率で目がでるのではなく、おみくじのように出現確率が変化するようなプログラムが必要になったので作成した。

実際にうまく言っているかを確認するため、ヒストグラムを表示させた。

weighted_random関数

  • 入力:Numpyの配列に重み付けをした数値を入れる(合計が1である必要はない)
  • 出力:ランダムな値(0~配列長-1)を返す
import numpy as np
import matplotlib.pyplot as plt

# 入力データ(それぞれ、10%,30%,60%)
data = np.array([0.1, 0.3, 0.6])

# 関数
def weighted_random(data):
    # 累積
    culm = [0] * data.shape[0]
    total = np.sum(data)
    for i in range(data.shape[0]):
        cuml[i] = np.sum(data[:i+1]) / total
    # 乱数から選択
    s = np.random.rand()
    m = 0
    for i in cuml:
        if s < i:
            break
        m += 1
    return m

# 表示
x = np.array([weighted_random(data) for _ in range(1000)])
plt.hist(x, rwidth=1.0, bins=3)

f:id:zia_glass:20171125214942p:plain

1000個の結果から見て大体100個、300個、600個程度の出力を得ている。 なんかもっと綺麗に書けないんだろうか。

irisデータセットでOneClassSVM

One-Class SVMは1つのラベルでモデルを生成する。
RBFカーネルを用いることで、実行結果のように取り囲む識別面ができる。

実行結果

gamma = 0.1

f:id:zia_glass:20171008005341p:plain

gamma = 1.0

f:id:zia_glass:20171008005352p:plain

実行

import numpy as np
import scipy as sp
from sklearn import datasets
from sklearn import svm
import matplotlib.pyplot as plt 

def iris():
    iris = datasets.load_iris()
    X = np.hsplit(iris.data[0:100], [2])[0]
    y = iris.target[0:100]
    return(X, y)

X, y = iris()
colordic = ['red', 'green', 'g']
colors_map = map(lambda x: colordic[x] , y)
colors = [x for x in colors_map]


"""
gamma = 0.1
"""
#one-class svm
clf2 = svm.OneClassSVM(nu=0.1, kernel="rbf", gamma=0.1)
clf2.fit(X[:50, :])
#scatter
plt.scatter(X[:,0], X[:,1], color=colors)
#mesh
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.05),\
     np.arange(y_min, y_max, 0.05))
# contour
Z = clf2.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, cmap=plt.cm.Paired, alpha=0.5)
plt.show()


"""
gamma = 1.0
"""
# one-class svm
clf1 = svm.OneClassSVM(nu=0.1, kernel="rbf", gamma=1.0)
clf1.fit(X[:50, :])
#scatter
plt.scatter(X[:,0], X[:,1], color=colors)
#mesh
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.05),\
     np.arange(y_min, y_max, 0.05))
# contour
Z = clf1.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, cmap=plt.cm.Paired, alpha=0.5)
plt.show()
     

markdown-preview-enhancedのスタイル

Markdownを書くときはVSCodeとかKobitoでも書けるけどAtomが便利な気がする。

VSCodeはコード書くように行数表示やVimプラグイン入れているから文章入力には向かない。 Kobitoでもローカルで保存できるけど、もっとシンプルにDropbox上のディレクトリで管理したい。

AtomだとプラグインいれるとKobitoみたいにコードのシンタックスハイライトやプレビューとのスクロール位置の同期をしてくれたり、リストを作る時のハイフンも改行時に自動で入力してくれたりするから、総合的に考えてAtomに行き着いた。

パッケージ

  • markdown-preview-enhanced
    • プレビューを良くしてくれる。数式や図式実は対応しているみたい。
  • markdown-writer

日本語がスペルチェック機能によって赤い下線引かれてしまうのが目障りなので、Core-Packageからspell checkを無効にした。

スタイル

Ctrl+Shift+P入力後 "markdown-preview-enhanced: customize css" でmarkdown-preview-enhanced専用のcss設定ができる。

html body {
  @main_color: #303030;
  @inverce_color: #eeeeee;

  background: @inverce_color;

  h1,h2,h3,h4,h5,h6 {
    color: @main_color;
  }

  h1 {
    font-size: 2.0m;
    text-align: center;
  }

  h2 {
    font-size: 1.7em;
    border-bottom: 1px solid @main_color;
  }

  h3 {
    font-size: 1.5em;
    text-decoration: underline;
  }

  h4 {
    font-size: 1.3em;
  }

  p, li {
    color: @main_color;
    line-height: 2em;
  }

  table {
    tr {
      background-color: @inverce_color;
      th, td {
        color: @main_color;
        border: 1px solid @main_color + #888;
      }
      th {
        background: @inverce_color - #222;
      }
    }
  }
}

Link