OmniAICreator/Qiita-1.07M huggingface dataset:
【swift4】UISwitchの画像サイズを可変にしたい

UISwitchのあの絵のサイズが固定だったので、可変にしたいなぁと思いました。いつも通り、あちこち引っかかったのでメモを残しておきます。

#前提
- swift4.2
- Xcode10.3
- iOS10〜
- InterfaceBuilderを使ってSwitchは配置
- 固定サイズじゃなくて可変サイズで使いたい。

参考にさせていただいたのはここの記事です。
[UISwitchを任意のサイズで使いたい!!](http://tokyo.supersoftware.co.jp/code/7936)

#いきなり答えに近いところまで
参考にさせてもらった記事で、UISwitchからクラスを派生して、InterfaceBuilderで置いたスイッチのクラスを差し替えてしまえばいい、と結論が出ていました。

#引っかかったところ
- InterfaceBuilderで設定したSwitchのサイズが取れない
（Constraintsで設定しているからかな）
- 参考記事では固定サイズで試されているので、機種で違う画面サイズに合うように比率にしたい
- Transformすると画像の位置がずれるのだけれど、その調整


#Switchのサイズが取れないこと
- Classでself.frame.size.widthや、self.bounds.size.widthではオリジナルのサイズしかとれず、IBで設定しているものが反映されていない。
- ConstraintsのHeightAnchorやWidthAnchorから簡単に値は取れない、と思う。

こうやったらとれるよ、ってあるなら教えてほしいです…。

**結論**

- 画面サイズから計算することにしました。

#比率での大きさの決定
- IBでConstraintsを整えているのだけれど、固定値では指定していない。

　Switch画像のサイズについては51,31。まずはこれは固定値なのは仕方ない。これが固定なのがそもそもの問題なので。
これがオリジナルのサイズということで、計算のベースになる。

- 普段も、Viewから比率で部品を積み上げていくという形にしているので、比率を活かせないか。

**結論**

- IBでSwitchを貼り付けるときに、最上位のView(画面サイズなので）からPropotional HeightやWidthで大きさを決めることにして、そのMultiplier（倍率）をメモしておきます。
- で、その倍率を画面サイズに掛けることで表示したいサイズを算出します。

値は@IBInspectableを利用してInterfaceBuilder上からその割合を入れるかたちにしました。

**ちなみにIBから入力すると、小数点以下が丸められて0.05とか入れても0.1の表記になりますが、実際にPrintするとちゃんと値が取れてるのがわかります**

　Propotional HeightとPropotional Widthから自動でMultiplier引っ張って来れたらその手間も無いんですが、そもそも値って取れるの？という部分でちょっと時間が足りなかったので諦めました。詳しい方、やれるよ！ということであったらこれまた教えてもらえないかなーと思ってます。

#Transformしたときの位置の補正

これまた引っかかりました。
正直、前にもpinchgestureを使って拡大縮小しようとか思って一週間くらい悩んで位置補正がうまく出来なかった時期があったんですが、このあたりの勘違いが原因な気もしています。

- Transformでサイズを変えると中心が同じままで拡大縮小する

難しく考えてしまったんですかね。
オリジナルサイズでのセンターと表示サイズでの差分とか色々考えて設定してみてなんで駄目なん？となってたんですが。

**結論**

- (オリジナルサイズ - 表示したいサイズ) ÷ 2 だけオリジナルサイズで表示した状態からずれる
- その分だけ引けばちゃんとセンターに収まる

という結果でした。


#出来上がったUISwitchの派生クラス
名前は可変の意味でVarをつけただけです。
オリジナルサイズは本当はOS単位で変わるらしいので、OSを判定してサイズを渡すようにするのがベストなんだとは思いますが、割愛。


- InterfaceBuilderでUISwitchをViewControllerに貼り付け
- 貼り付けたSwitchのクラスをUISwitchから下記のクラスに変更
- 画面サイズと同じサイズのViewから計算した比率でConstraintsを設定
- Attribute Inspecterの下記のクラスのfScaleに上で設定したのと同じ比率で横と縦の比率を設定する



```swift

class VarUISwitch: UISwitch {
    // iOS10 標準サイズが元になる
    let orgSize: CGSize = CGSize(width: 51.0, height: 31.0)
    // 倍率。IB上では丸められちゃうが、値は正しく入ってくる
    @IBInspectable var fScale: CGSize = CGSize(width: 1.0, height: 1.0)
    override func awakeFromNib() {
        // awakeFromNibはIBで設定したもののみイベント発生
        super.awakeFromNib()
        // 表示サイズ。
        let viewWidth = UIScreen.main.bounds.width * fScale.width
        let viewHeight = UIScreen.main.bounds.height * fScale.height
        // 拡大率 = 表示サイズ÷元のサイズ
        let scaleX: CGFloat = viewWidth / orgSize.width
        let scaleY: CGFloat = viewHeight / orgSize.height

        // Transformすると中心が同じままなので変化した分だけ戻す。
        // (元サイズ-表示サイズ)/2が足されるので、その分を引く。
        let offsetX = ((orgSize.width - viewWidth) / 2) * -1
        let offsetY = ((orgSize.height - viewHeight) / 2) * -1

        // transform
        let translateAff = CGAffineTransform(translationX: offsetX, y: offsetY)
        // 移動が先にしないと駄目らしいので、移動にスケールを足す
        self.transform = translateAff.concatenating(CGAffineTransform(scaleX: scaleX, y: scaleY))
    }
}

```

ご参考までに。
【メモ】VirtualBoxが言うことを聞かない

# VirtualBoxが言うことを聞かない

VitualBoxのインストール＆実行には Secure Boot を無効にしておく必要がある。忘れてエラーを吐かせると、その後以下のエラーでVboxがうまくVMを起動しなくなる。

```
VERR_VM_DRIVER_VERSION_MISMATCH (-1912)
```

以下で動作した。

```bash
sudo /sbin/rcvboxdrv setup
```
【メモ】Ubuntu 16.04 のシャットダウンが遅い時

# Ubuntu 16.04 のシャットダウンが遅い時

基本的には以下を参照
[Ubuntu 16.04でシャットダウンがクソみたいに遅いとき](http://qiita.com/o_nishy/items/2a3df17e95ad0ad7f734)

上リンクで設定方法が無いとあったが、以下に書いてある
[Slow shutdown on Ubuntu 16.04 LTS (Stopping thermal daemon/running fit make remote CUPS printers)](https://askubuntu.com/questions/760952/slow-shutdown-on-ubuntu-16-04-lts-stopping-thermal-daemon-running-fit-make-remo)

1. NTPが無い
2. CUPSの待ち時間が長い

###解決策
```
sudo apt install ntp
```

```
sudo systemctl edit cups-browsed.service 
```
とし、設定ファイルを下記のように記述

```
   [Service]
   TimeoutStopSec=10
```
その後、

```
sudo systemctl daemon-reload 
```
【メモ】Ubuntu 16.04 で DNS を設定する

# Ubuntu 16.04 で DNS を設定する
通常は /etc/network/interfaces に

```
nameserver 172.17.0.8 172.17.0.16

```
という行があれば設定されているはず。

何らかの理由で上記の設定がうまく動かない場合、以下の設定で無理矢理動作させることができる

/etc/resolvconf/resolv.conf.d/head

の最終行に

```
nameserver 172.17.0.8
```

などと書く。ただし、「このファイルは手で書き換えるな」とコメント行に書いてあるので動作保証外
【メモ】VNC server 立ち上げメモ

# VNC server 立ち上げメモ

```bash
apt-get -y install vnc4server

vncpasswd 
vncserver :1 
vncserver -kill :1

vi ~/.vnc/xstartup
  # 最終行に追記
  exec xfce4-session &

vncserver :1 -geometry 800x600 -depth 24
```

[Ubuntu 14.04 にVNCで入ったら灰色の画面(Grey Screen)になる時の対応](https://hack-le.com/ubuntu1404-vnc-grey/)<br>
[Ubuntu 16.04 LTS : VNCサーバーの設定 : Server World](https://www.server-world.info/query?os=Ubuntu_16.04&p=desktop&f=7)<br>
[VNCServerをUbuntu14.04で建てる。](https://qiita.com/ryunosinfx@github/items/b28e23f65c74a0f59d03)
Dockerでホストのssh鍵をゲストOSと共有する際の注意点

### まとめ
opensshのバージョン7.8以降で生成した鍵は後方互換性がない

#### 経緯
Dockerコンテナ上でgithubからcloneを実行したかった。
SSH鍵をコンテナ毎に生成するのは現実的ではないので、
ホストOSのSSH鍵(github登録済)を使おうと思った

#### 何が起きたか
docker-composeとDockerfileを記述して、
コンテナ上で鍵ファイルを閲覧できるところまでは確認。
任意のディレクトリでclone実行したところcloneに失敗

#### 生成されたキーがおかしい？
ゲストOS上で直接ssh-keygenで生成したキーは使用できるか確認したところ特に問題なくcloneに成功。
ホスト上で作成した鍵がおかしい？と思ったが、ホスト上でもcloneコマンドは成功している。
両者のid_rsaをlessで確認したところ、下記の違いが確認された。
##### ホスト

```
-----BEGIN OPENSSH PRIVATE KEY-----
```

##### ゲスト

```
-----BEGIN RSA PRIVATE KEY-----
```

ムムム、ヘッダの内容が若干違う？

#### OpenSSHの確認

opensshのバージョンは、、、
ホスト

```
OpenSSH_7.9p1, LibreSSL 2.7.3
```

ゲスト

```
OpenSSH_5.3p1, OpenSSL 1.0.1e-fips 11 Feb 2013
```

それっぽい違いがあるぞ、、、？！
調べたらすぐこんな記事が見つかりました。
https://dev.classmethod.jp/server-side/network/openssh78_potentially_incompatible_changes/
クラスメソッドさんありがとうございます！

openssh7.8以降を利用している際に後方互換性のあるキーを作成したい場合は`-m PEM`を付与する

```
ssh-keygen -m PEM
```

生成されたキーのヘッダを確認したところ旧バージョンの形式になってること確認
cloneも無事完了

ダイナミックな変更で驚いたが、オプションで解決できてよかったよかった。
【メモ】NFSがマウントできない場合

# NFSがマウントできない場合
## rpcbind 関係のエラーが出る
```bash
mount.nfs: rpc.statd is not running but is required for remote locking.
mount.nfs: Either use '-o nolock' to keep locks local, or start statd.
mount.nfs: an incorrect mount option was specified
```
rpcbindが起動しているのに上記のエラーが出る場合、以下をチェックしてみると良い。
/etc/hosts.deny に

```bash
ALL: ALL
```
を記載して、/etc/hosts.allow で個別に許可を出している場合、

```bash
ALL: localhost 127.0.0.1 : allow
```
を書き忘れないようにしないと、色々なものが動かない。もちろん、サービスを全て具体的に管理したい場合（大変なのであまりやらないが）

```bash
rpcbind : localhost
```
などと書く必要がある。
ローカルのPHPからsshトンネルを使ってサーバーへmysql接続

ちょっとしたクエリを試したいときなどローカルから直接アクセスできないDBサーバーへ接続したいときがあるかと思います。
mysqlクライアントツールなど使えば簡単にできるのですが、今回はphpの処理も絡めて行いたかったのでローカルのPHPプログラムからサーバのDBにアクセスできるようにしました。

## ポートフォワードさせる（sshトンネル）
ターミナルで以下のコマンドを実行させます。

```sh
ssh -N -L {任意のポート番号}:{DBエンドポイント} -i {鍵ファイル} -p {踏み台のsshポート番号} {ユーザ名}@{踏み台サーバのホスト}
```

上記コマンドの波括弧部分を変えます。任意のポート番号は使用されていないものならなんでも良いです。このポート番号にアクセスするとポートフォワードされるようになります。
オプションですが
N...リモートコマンドを実行しない
L...指定されたようにポートフォワードさせる
のようになっています。

## PDO

```PHP
$pdo = new PDO('mysql:host='. "127.0.0.1:{任意のポート番号}" .';dbname=' . "db_name" .';charset=utf8', "user_name", "password");
```

PDOはいつもの通りですが、hostがサーバーではなくローカルを指すようにします。その際、sshコマンドで入力したポートを利用します。

これでテスト的にプログラムを実行したいときに便利になりました。
NMFをscikit-learnとSPAMSで動かしてみる

# なにをしたいか
- NMFの使い方を確認する
- scikit-learnとSPAMSのそれぞれでのNMFを比較する

# NMF
Non-negative Matrix Factorizationです。[ここ](https://tips-memo.com/nmf)とか、その他いろいろな記事で非常に丁寧に説明されています。

# scikit-learnでの使い方
- [オフィシャル](https://scikit-learn.org/stable/modules/generated/sklearn.decomposition.NMF.html)のサンプルコードをなぞります。
- $ X \in {R}^{6\times2} $なので、$ W \in {R}^{6\times2} $で、$ H \in {R}^{2\times2} $です。
- n_componentsは、↑の2に当たります。

```python:NMF(scikit-learn)
>>> import numpy as np
>>> X = np.array([[1, 1], [2, 1], [3, 1.2], [4, 1], [5, 0.8], [6, 1]])
>>> from sklearn.decomposition import NMF
>>> model = NMF(n_components=2, init='random', random_state=0)
>>> W = model.fit_transform(X)
>>> H = model.components_
>>> # ここから結果の確認
>>> X_ = np.dot(W, H)
>>> print(X)  # 元のXの値
[[1.  1. ]
 [2.  1. ]
 [3.  1.2]
 [4.  1. ]
 [5.  0.8]
 [6.  1. ]]
>>> print(X_)  # NMFの結果得られたX
[[1.00063558 0.99936347]
 [1.99965977 1.00034074]
 [2.99965485 1.20034566]
 [3.9998681  1.0001321 ]
 [5.00009002 0.79990984]
 [6.00008587 0.999914  ]]
>>> print(model.inverse_transform(W))  # inverse_transformでもNMFの結果を見られる
[[1.00063558 0.99936347]
 [1.99965977 1.00034074]
 [2.99965485 1.20034566]
 [3.9998681  1.0001321 ]
 [5.00009002 0.79990984]
 [6.00008587 0.999914  ]]
```

# SPAMSでの使い方
- [公式](http://spams-devel.gforge.inria.fr/doc-python/html/doc_spams004.html)がサンプルコードを提供しています。
- ここでは、scikit-learnと同じXを使用します。
- [Source](https://github.com/jakirkham/spams-python/blob/master/spams.py#L2234)をみると、trainDLとlassoで同じことが出来るようです

```python:NMF(SPAMS)
>>> import numpy as np
>>> X = np.asfortranarray([[1, 1], [2, 1], [3, 1.2], [4, 1], [5, 0.8], [6, 1]])
>>> param = { 'K' : 2, 'numThreads' : 4,  "iter": 1000, "return_lasso": True}
>>> W, H = spams.nmf(X, **param)  # Xはfortranarrayである必要があります
>>> H = np.array(H.todense())  # Compressed Sparse Column formatで返ってきます
>>> print(np.dot(W, H))
[[1.  1. ]
 [2.  1. ]
 [3.  1.2]
 [4.  1. ]
 [5.  0.8]
 [6.  1. ]]
```

# 速度比較
```python:scikit-learn
%%timeit
model = NMF(n_components=2, init='random', random_state=0, max_iter=1000)
W = model.fit_transform(X)

729 µs ± 2.48 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

```

```python:spams
%%timeit
W, H = spams.nmf(X, **param)

5.47 ms ± 302 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
```

たぶんこれで比較になっていると思います
gpsbabel基本コマンド

## kml を gpx に変換

```bash
gpsbabel -t -i kml -f [input filename] -o gpx -F [output filename]
```

## kml を csv に変換

```bash
gpsbabel -t -i kml -f [input filename] -o unicsv -F [output filename]
```
他にテキストで使いやすい形式としては、"openoffice" 形式もある.

## 複数のgpxを統合する(タイムスタンプでソートされる)

```bash
gpsbabel -t -i gpx -f [input1] -i gpx -f [input2] -x track,merge,title="combined" -o gpx -F [output]
```

## 時間の無いgpxに時間を付与する（combine用）

```bash
#!/bin/bash
  
input=$1
output=$2

tmp1=`mktemp temp.XXXX`
tmp2=`mktemp temp.XXXX`
tmp3=`mktemp temp.XXXX`
tmp4=`mktemp temp.XXXX`
tmp5=`mktemp temp.XXXX`


gpsbabel -t -i gpx -f ${input} -o csv -F ${tmp1}
cat -n ${tmp1} | sed 's/,//g' | awk 'BEGIN{OFS=","}{print $1,$2,$3,"",""}' > ${tmp2}

count=0
cat ${tmp2} | while read line
do
   count=$(expr $count + 1)
# for mac(BSD)
   date -v+${count}S -j -f "%Y/%m/%d %T" "2013/09/21 12:00:00" "+,%Y/%m/%d, %T" >> ${tmp3}
done

paste ${tmp2} ${tmp3} | sed 's/ //g' > ${tmp4}

echo "No,Latitude,Longitude,Name,Altitude,Date,Time" > header
cat header ${tmp4} > ${tmp5}
gpsbabel -t -i unicsv -f ${tmp5} -o gpx -F ${output}
mv ${tmp5} ${output}.csv

rm temp.*
```
【メモ】gollum インストール

# gollum インストール
[本家](https://github.com/gollum/gollum/wiki/Installation)に従う。

###Ubuntu 16.04LTS の場合

```bash
sudo apt-get install ruby ruby-dev make cmake zlib1g-dev libicu-dev build-essential git libssl-dev
sudo gem install gollum
```
バイナリは /usr/local/bin/gollum に入る。

Markdown形式で書きたい場合は、

```
sudo gem install github-markdown
```
が必要（入れないと、表が組めないなどの問題が生じる）。
また、git の初期設定は済ませて置く方が良い。

Wiki を作成したいディレクトリ(/home/hoge/wiki/　と仮定)で、新しい git リポジトリを作成する。

```bash
cd /home/hoge/wiki/
git init
```
あとは gollum コマンドで起動するだけだが、サービスとして運用するのが現実的。
従って、次の設定を行う。

/etc/systemd/system/ に gollum.service という名前で以下の内容のファイルを作成する。

```
[Unit]
Description=Gollum wiki server
After=network.target

[Service]
Type=simple
User=%i
ExecStart=/usr/local/bin/gollum --show-all "home/hoge/wiki/"
Restart=on-abort

[Install]
WantedBy=multi-user.target
```

その後、コマンドラインで

```bash
sudo systemctl start gollum.service
```
とすれば、wikiがデーモンとして起動する。起動時に自動で立ち上げるには、

```bash
sudo systemctl enable gollum.service
```
とすればよい。

localhost:4567 にアクセスすれば、Home画面が立ち上がるはず。
(外部からは IP-address:4567)

デフォルトでポート番号が4567となっているが、gollum.service の "ExecStart=" のオプションに

```
--port
```
を付けると変更できるそうだ。
その他、数式を書きたい場合は

```
--mathjax
```
を加える。

2017/12/08 追記：
###パスワードをかける
下記参考ページをそのまま。auth.rb を作成。

```ruby
module Precious
  class App < Sinatra::Base
    use Rack::Auth::Basic, "Restricted Area" do |username, password|
      [username, password] == ["usr", "pswd"]
    end
  end
end
```
を作成し、起動オプションに

```
--config ~/(path)/auth.rb
```
を追加。

### MediaWiki への対応
[Enabling Mediawiki support in Gollum (GitHub)](https://github.com/gollum/gollum/wiki/Enabling-Mediawiki-support-in-Gollum)

### その他関連記事
[PukiWiki の代わりに Gollum を導入してみた](https://abicky.net/2014/09/15/121633/) <br>
[ぼっちWikiに最適なGollumについてのメモ](http://qiita.com/tatzyr/items/5ea6328719d72135c6c3)
【メモ】bashで任意のファイル名を連番に変換

# bashで任意のファイル名を連番に変換

jpegファイルからffmpegを用いてavi,mpg等を作成するためには、欠番のない 1 から始まる連番のファイル名である必要がある。


複数個ある

X\*.jpeg （\*は任意）

という一連のファイルを

X0001.jpeg
X0002.jpeg
...

という連番のファイル名に変更したい場合、以下のようなスクリプトで解決できる。

```bash

#!/bin/bash
a=0
for i in X*.jpeg; do
let a="${a}+1"
s=$(printf "X%04d.jpeg" $a)
echo $s
cp $i $s
done
```
【メモ】MarkdownをPDFに変換する

# MarkdownをPDFに変換する

方法はいくつかある。

##markdown-pdf
Node.js で動作する markdown-pdf を使う場合、

###インストール

```console
sudo apt-get install nodejs
sudo apt-get install npm
npm init
sudo npm install -g markdown-pdf
```

###使用方法

```console
markdown-pdf -o output.pdf input.md
```

##Pandoc
より多機能なpandocを使う場合
###インストール

```
sudo apt-get install -y texlive-full pandoc ruby rake
```

日本語を含むMarkdownを変換する場合、

```
pandoc input.md -o output.pdf -V documentclass=ltjarticle --latex-engine=lualatex
```

のように使う。PDF変換にはLaTeXを使うため、少し遅い。できあがりは綺麗。

## [追記]参考資料
[MarkdownをPDFに変換する「md-to-pdf」は痒いところに手が届く素敵ツール](https://dev.classmethod.jp/articles/md-to-pdf/)
【メモ】スリープの設定が反映されない時

## スリープの設定が反映されない時

ちゃんと電源管理でスリープ「無効」にしてあるのに、勝手にスリープしてしまう問題は、レジストリを書き換えないといけない。

下記に答え：
- [Windows の電源設定で無効にしても勝手にスリープになる現象を回避するには](https://mseeeen.msen.jp/avoid-unwelcome-auto-sleep-of-windows/)

下記キーのAttributesの値を "2" に変更すると、「システム無人タイムアウト」メニューが出現する。

```
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power\PowerSettings\238C9FA8-0AAD-41ED-83F4-97BE242C8F20\7bc4a2f9-d8fc-4469-b07b-33eb785aaca0
```
ffmpegでMacのスクリーンレコーディングしたmovファイルをmp4, gifに変換する

あまりソフトを増やしたりしたくないので手元のffmpegでできないかなと思ったらできたのでメモ

## スクリーンレコーディング（画面収録）する

`shift + command + 5` で適当に撮る

詳しくはこちら
https://support.apple.com/ja-jp/HT208721

注意点としては、キャプチャサイズを偶数倍ピクセルにすること。後述する mp4 変換の時に難儀する

## ffmpeg で変換する

### mp4

```bash
$ ffmpeg -i sample.mov -pix_fmt yuv420p out.mp4

# 整数倍ではないと言われてエラー出た時は以下のオプションをつける
# -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2"
```

### gif

```
$ ffmpeg -i sample.mov -r 24 out.gif
```
【メモ】Windows Subsystem for Linux 関連

# Windows Subsystem for Linux 関連
### インストールの前に
- [コントロールパネル] --> [プログラムと機能] --> [Windowsの機能の有効化または無効化]
- [□ Windows Subsystem for Linux] にチェック

### インストールしたら
```
sudo apt update
```

### 日本語表示
```
sudo apt install language-pack-ja
sudo update-locale LANG=ja_Jp.UTF8
```

### X window
xming等
【メモ】Windows 環境での便利ツール

# Windows 環境での便利ツール

## システム情報
- [AppReadWriteCounter v1.00](https://www.nirsoft.net/utils/app_read_write_counter.html)
- [FileActivityWatch v1.00](https://www.nirsoft.net/utils/file_activity_watch.html)
- [CPU-Z](https://www.cpuid.com/softwares/cpu-z.html)
- [HWMonitor](https://www.cpuid.com/softwares/hwmonitor.html)

## ファイル操作
- [Unlocker](https://unlocker.jp.uptodown.com/windows)
【メモ】PL2303チップ使用のUSB-シリアル変換の問題

# PL2303チップ使用のUSB-シリアル変換の問題

### ELECOM製 UC-SGT は 64bit 版ドライバが非対応

経緯と対策は["PL2303を載せたUSBシリアル変換ケーブルのドライバをwindows7/8（x64）に対応させる" ](http://blog.goo.ne.jp/nikonikopan/e/4e485fde2882228eca82e504a342273b) に書いてある。原因は中国製コピーへの対策。

Windows 10 での使用には EEPROM の書き換えが必要。その後、[秋月電子](http://akizukidenshi.com/catalog/faq/goodsfaq.aspx?goods=M-02746)のサイトから古いドライバ(動作確認済 v1.5.0 / 2011.10.24)をダウンロードしてインストール。「ドライバの更新」から "3.4.25.218" を選択すると動作する。 

#### 関連リンク

- [http://ehbtj.com/info/pl2303-windows10/](http://ehbtj.com/info/pl2303-windows10/)　<br>
- [http://edcv.net/network/prolific-pl-2303-drive/](http://edcv.net/network/prolific-pl-2303-drive/)　<br>
- [http://qiita.com/matobaa/items/c496ffc3b6635b2a82a3](http://qiita.com/matobaa/items/c496ffc3b6635b2a82a3) <- 3.4系ドライバが動作不良で3.3系を奨励している <br> 
- http://wiki.tomocha.net/Windows_Vista_USB-RS232C.html
pythonで2軸アームの順運動学

順運動学について興味を持ったので2軸ではありますが，先行して実装した方を参考にして実装をしてみました(パクったともいう)．

スライダーで腕の角度を変えたいなと思ったのでそこの部分を追加した感じとなります．今後は，以前に線分同士の交差判定を行ったので，これをもとに衝突検知もしたいと思います．

余談ですが，colabで上げてやりたかったのですがcolabは基本的にgui機能を封じているので上げませんでした．Foamの機能を使ってもよかったのかもしれませんが，matplotlibのアニメーションを動的に生成することができなさそうだと判断したので断念しました．(実装よりもcolab関連の方が時間使ったことは内緒)
以下実装です．

```arm.py
import math
import numpy
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider


fig, ax = plt.subplots(figsize=(8,8))
plt.subplots_adjust(left=0.25, bottom=0.25)
plt.xlim(-20,20)
plt.ylim(-20,20)
ax.axis('equal')
ax.set_xlim(-11,11)
ax.set_ylim(-11,11)

#Linkの長さ 
L1 = 5
L2 = 5

#各リンクの角度指定
deg1 = 30
deg2 = 50

theta1 = Slider(plt.axes([0.25,0.0,0.65,0.03]), 'theta1', -180, 180, valinit=deg1)
theta2 = Slider(plt.axes([0.25,0.05,0.65,0.03]), 'theta2', -180, 180, valinit=deg2)

#リンク１の座標算出
x1 = L1 * numpy.cos(math.radians(deg1))
y1 = L1 * numpy.sin(math.radians(deg1))

#リンク2の座標算出
x2 = x1 + L2 * numpy.cos(math.radians(deg1+deg2))
y2 = y1 + L2 * numpy.sin(math.radians(deg1+deg2))
 
#計算結果表示↓
print(x1)
print(x2)
print(y1)
print(y2)


#算出結果を格納
#リンクは[x,y]=[0,0]から表示するため最初の要素に0を代入
x = [0, x1, x2]
y = [0, y1, y2]

#表示
#線分表示↓
plots, = ax.plot(x,y,"r-")
ax.plot([0,3],[0,3])

def update(val):
    deg1 = theta1.val
    deg2 = theta2.val
    x1 = L1 * numpy.cos(math.radians(deg1))
    y1 = L1 * numpy.sin(math.radians(deg1))
    x2 = x1 + L2 * numpy.cos(math.radians(deg1+deg2))
    y2 = y1 + L2 * numpy.sin(math.radians(deg1+deg2))
    x = [0, x1, x2]
    y = [0, y1, y2]
    ax.axis('equal')
    ax.set_xlim(-11,11)
    ax.set_ylim(-11,11)
    plots.set_data(x,y)
    fig.canvas.draw_idle()

theta1.on_changed(update)
theta2.on_changed(update)


#表示実行
plt.show()
```
#参考
- [ロボット、電子工作、IoT、AIなどの開発記録](http://weekendproject9.hatenablog.com/entry/2017/11/17/005712)
- [widgets example code: slider_demo.py](https://matplotlib.org/examples/widgets/slider_demo.html)
- [コメント一行でUI生成。Form機能を使った一歩先のGoogle Colab活用術](https://qiita.com/stakemura/items/4b3a16c4f59590db067a)
GMTで特定の海域を塗り潰す

# GMTで特定の海域を塗り潰す

描き方を聞かれて少し迷ったのでメモ。
地球科学分野ではあまり使わないテクニックだが、海底地形を必要としない海域図では利用価値がある。

地図上で任意の領域を塗り潰すためには psxy の -G オプションを使えば良い。しかし沿岸部の場合、海岸線での塗り分けが必要になる。このような場合、psxy で領域を描画した後に pscoast で上書きすると良い。

以下に、大阪湾で例を示す。

例では 8 点のみで湾を囲む。海岸線の数値データが手元になく、領域の正確な範囲を作成するのが困難な場合でも簡易的に用いることができる方法となる。必要な緯度経度は Google Maps でポイントをクリックすると得られるもので十分。

湾内を塗りたい場合、以下のようなスクリプトで実現できる。
（※大阪湾の正確な定義に基づく描画ではない）

```paint_area.csh
#!/bin/csh -f

#gmtdefaults の設定
gmtset PAPER_MEDIA=A4
gmtset PAGE_ORIENTATION=portrait
gmtset LABEL_FONT_SIZE=18p
gmtset PLOT_DEGREE_FORMAT=ddd:mm:ssF

#出力ファイル
set psfile=osakabay.ps

#今回は、県境データが以下の名前で存在すると仮定
set prefecture=b_pref.txt

#描画オプションの指定
set Region=134.25/135.75/33.75/35.25
set Projection=M15
set Annotation=f.5a.5g.5WSne

#Basemap の描画（グリッドなし）　※グリッドを陸上にも描きたい場合は pscoast の後に記述するべし
psbasemap -R$Region -J$Projection -B$Annotation -K -V > $psfile

#塗りたい領域。簡易的に大阪湾より広いエリアを指定
psxy -R -J -G100/100/100 -m -L -: -K -V -O -f << END >> $psfile
34:36.555, 135: 0.183
34:38.280, 135:2.066
34:45.926, 135:24.653
34:39.187, 135:32.110
34:16.633, 135:19.462
34:17.840, 135:4.181
34:16.122, 134:56.474
34:16.973, 134:45.679
END

#海岸線の描画
pscoast -R -J -Df -W2 -G220 -P -K -V -O >> $psfile

#県境の描画
psxy $prefecture -R -J -W1/0/0/0 -m -O -V >> $psfile
```

上記のスクリプトを実行すると、次のような結果を得る。


![png](http://blog-imgs-46.fc2.com/p/i/r/pirokyoro/osakabay.png)
【メモ】地図座標変換(GMTとPROJ.4)

# 地図座標変換(GMTとPROJ.4)

ユニバーサル横メルカトル(UTM)図法のX-Y座標(m)を一般の緯度・経度に変換するために行ったことをメモしておく。

変換ツールは、世にいくつか出回っている。

GMT(Generic Mapping Tools)を用いた方法では、以下のように記述するのが最も簡単な方法だと思う。

```
mapproject [input.xy] -I -C -F -Ju[zone]/1:1 -R[region] -V > [output.latlon]
```
日本国内だと、[zone] = +53 or +54 で大体収まるのではないか。


今回は、GMTで変換した結果を検証するために別のツールを導入してみた。

[PROJ.4 - Cartographic Projections Library](http://trac.osgeo.org/proj/)

導入方法は[ここ](http://www.yaskey.cside.tv/mapserver/cygwin/#proj4)に比較的分かりやすく書いてある。

ソースコードを好きな場所にダウンロードし、展開する。

```
tar xvzf proj-4.x.x.tar.z
```
出来たディレクトリに移動して

```
./configure
make
make install
```
と打ち込めば完了する。Cygwinでは問題なくコンパイルできた。

上記のGMTと同様の動作は以下の記述で実現する。

```
invproj +proj=utm +ellps=WGS84 +datum=WGS84 +zone=+53 +units=m +no_defs -f "%4f" [input.xy] > [output.latlon]
```
楕円体の選択は多くの場合"WGS84"で問題ないと思う。古い測地系の場合は注意を要する。

他に [USGS National Mapping Division General Cartographic Transformation Package (GCTP)](http://gcmd.nasa.gov/records/USGS-GCTP.html) も検討したが、こちらはこれを利用したソースコードを書くときに使う方が利用しやすく、インストールのハードルもやや高いので、今回はやめた。ダウンロードは[ここ(FTP)](ftp://edcftp.cr.usgs.gov/pub/software/gctpc/)から
【メモ】簡易的なリアルタム収録

# 簡易的なリアルタム収録

```
recvtd 7004 11 10000 - /home/auto/log/recvt_192.log
#raw_shift 11 12 1000 0 osaka.ch &
raw_raw 11 12 1000 osaka.ch &  #(単に選別ならこちら)
orderd 12 15 10000 30
wdiskd 15 /dat/raw 259200 /home/auto/log/wdisk_tmp.log
```

### osaka.ch
```
0530
0531
0532
0533
0534
0535
0536
0537
0538
0539
053A
053B
```
bash_profileなどの設定ファイルを即時反映する方法


## .bash_profileや.bashrcなどの設定ファイルを使用している仮装環境などを再起動せずに設定を反映させる

結論だけ書くと**source**コマンドを使用する

### .bash_profileの設定を反映させる時
```bash
source ~/.bash_profile
```

### .bashrcの設定を反映させる時
```bash
source ~/.bashrc
```
【メモ】任意の期間の1分ファイルをコピーする

#任意の期間の1分ファイルをコピーする
たとえば収録用サーバのrawディレクトリのような1分ファイルのリポジトリから、期間とチャンネルを指定して1分ファイルたちをコピーしたい場合、以下のようなスクリプトがあると手間が省ける。

## 1. lsコマンドを利用する方法
ファイル名自動生成に比べ、存在しないファイルを見ない点では優位性がある。

```get_data_a.sh
#! /bin/bash

st="180111112800"
et="180124100000"

hpath="/home/tech01/hoge/120s"
dpath="/dat/raw1"

s=`date +%s -d "${st:0:2}-${st:2:2}-${st:4:2} ${st:6:2}:${st:8:2}:${st:10:2}"`
e=`date +%s -d "${et:0:2}-${et:2:2}-${et:4:2} ${et:6:2}:${et:8:2}:${et:10:2}"`

cd ${dpath}
echo "START["${st}"]" "END["${et}"]"

#for f in `ls ????????.??`; do
for f in `ls 1801????.??`; do
   df=${f:0:2}"-"${f:2:2}"-"${f:4:2}" "${f:6:2}":"${f:9:2}":00"
   dfs=`date +%s -d "${df}"`
   if [ ${dfs} -ge ${s} ] && [ ${dfs} -le ${e} ]; then
      echo -n ${f} " --> " ${hpath}/${f} " "
      wch ${hpath}/channel.ch < ${f} > ${hpath}/${f}
      last=${f}
   fi;
done
wck ${hpath}/${last}
```

## 2. ファイル名を自動生成する方法
ファイル数が多い場合、lsで探索するより速度面で優位性がある。
ただしdateコマンドの呼び出しがオーバーヘッド。

```get_data_b.sh
#! /bin/bash

st="180111112800"
et="180124100000"

hpath="/home/tech01/hoge/120s"
dpath="/dat/raw1"
tmpf=${hpath}/tmp_flist

s=`date +%s -d "${st:0:2}-${st:2:2}-${st:4:2} ${st:6:2}:${st:8:2}:${st:10:2}"`
e=`date +%s -d "${et:0:2}-${et:2:2}-${et:4:2} ${et:6:2}:${et:8:2}:${et:10:2}"`

cd ${dpath}
echo "START["${st}"]" "END["${et}"]"

echo "Making file list ..."
echo -n "" > ${tmpf}
declare -i i=${s}
while [[ ${i} -lt ${e} ]]
do
  i=$((i+60))
  fn=`date '+%y%m%d%H.%M' --date @${i}`
  echo ${fn} >> ${tmpf}
done

for f in `cat ${tmpf}`; do
   df=${f:0:2}"-"${f:2:2}"-"${f:4:2}" "${f:6:2}":"${f:9:2}":00"
   dfs=`date +%s -d "${df}"`
   if [ ${dfs} -ge ${s} ] && [ ${dfs} -le ${e} ]; then
      echo -n ${f} " --> " ${hpath}/${f} " "
      wch ${hpath}/channel.ch < ${f} > ${hpath}/${f}
      last=${f}
   fi;
done
wck ${hpath}/${last}

rm ${tmpf}
```

## 1. / 2. 共通 
```channel.ch
FF11
FF12
FF13
FF14
FF15
FF16
FF17
FF18
FF19
```
【メモ】簡単な使い方など (WIN System)

# 簡単な使い方など

- [簡易的なリアルタイム収録](https://qiita.com/rpscrw/items/d5c6b813f488aea0d9cb)

- パケットの受信から表示までの簡単な例

```
recvt -o akebono:8006 7000 11 10000 channels.tbl log.dat &
shmdump -tq 11 [CHIDs] | shmck [CHIDs]
```

- winファイルをshmdumpに送るとき

```
cat /dat/raw/18062023.5? | shmdump -tq - 0530
```

- sac形式に変換する

```
cat /dat/raw/18062023.5? | shmdump -tq - 0530 | wintosac -tchannles.tbl 0530
```
【メモ】リスト内のトリガを連続して検測する

# リスト内のトリガを連続して検測する
トリガファイルのリストを順番に読み込み、検測を行うためのスクリプトを作成した。
処理再開時に同じファイルを見ないために、以下の挙動をプログラムした。
- 処理が終わったトリガファイルは done/ に移動する。
- 一度見たが、処理が終わっていないファイルは pend/ に移動する。

pick.sh

```bash
#!/bin/bash

#PL=pick.list
PL=$1

# check list file
if [ -e $PL ]; then
   cat $PL > tmplist
else
   # make list when list does not exist
   echo $PL does not exist
   find trg/ -type f -print | egrep -v 'done|ch|BUSY|OLDEST|LATEST|COUNT|FREESPACE' | sort -k1n > tmplist
fi

function pick {
     FILE=$1
# read list file
   if [ -e $FILE ]; then
     echo 'start pick' $FILE
     win $FILE
# Ask done or not
     read -p'move '$FILE' to done/ ?[Y/n]' ANS
     case `echo $ANS | tr y Y` in
        "" | Y*)
        mv $FILE trg/done/
        echo "moved to done/";;
              *)
        mv $FILE trg/pend/
        echo "moved to pend/";;
     esac
     unset ANS
# Ask continue
     read -p'Continue?[Y/n]' ANS
     case `echo $ANS | tr y Y` in
        "" | Y*)
        echo "continue...";;
              *)
        echo "quit"
        break;;
     esac
   fi
}

for FILE in `cat tmplist`
do
   pick $FILE
done

# closing
rm tmplist
```
webarenaでubuntu その23

#概要

webarenaでubuntu18.04やってみた。
cheetanやってみた。

#使用したライブラリー

https://github.com/ohisama/cheetan

#create

```
<?php
	require_once 'config.php';
	require_once 'cheetan/cheetan.php';

	function action(&$c) {
	    if (count($_POST)) 
	    {
	        $c->test->insert($c->data['test']);
	    }
	}
?>
```

```
<form method="post" action="create.php">
	name<br />
	<input type="text" name="test/name" /><br />
	age<br />
	<input type="text" name="test/age" /><br />
	<input type="submit" value="new" />
</form>
```

#read

```
<?php
	require_once './config.php';
	require_once './cheetan/cheetan.php';

	function action(&$c) {
	    $c->set('datas', $c->test->find());
	}
?>
```

```
<h1>manager</h1>
<p>
<a href="./create.php">Write new</a>
</p>
<table border="1" width="98%">
	<tr>
	<td>id</td>
	<td>name</td>
	<td>age</td>
	<td>r_time</td>
	<td>edit/del</td>
  	</tr>
<?php 
	foreach ($data["datas"] as $data)
	{ 
?>
	<tr>
	<td><?php print $data["id"]; ?></td>
	<td><?php print $data["name"]; ?></td>
	<td><?php print $data["age"]; ?></td>
	<td><?php print $data["r_time"]; ?></td>
	<td>
		<a href="./update.php?id=<?php print $data["id"]; ?>">Edit</a>&nbsp;
		<a href="./delete.php?id=<?php print $data["id"]; ?>">Del</a>
	</td>
	</tr>
<?php
	}
?>
</table>
```

#update

```
<?php
	require_once 'config.php';
	require_once 'cheetan/cheetan.php';

	function action(&$c) {
	    if (count($_POST)) 
	    {
	        $c->test->update($c->data['test']);
	    }
	    $c->set('data', $c->test->findone('id=' . $_GET['id']));
	}
?>

```

```
<form method="post" action="update.php">
	name<br />
	<input type="text" name="test/name" value="<?php echo $data['data']['name']; ?>" /><br />
	age<br />
	<input type="text" name="test/age" value="<?php echo $data['data']['age']; ?>" /><br />
	<input type="hidden" name="test/id" value="<?php echo $data['data']['id']; ?>" />
	<input type="submit" value="update" />
</form>
```

#delete

```
<?php
	require_once 'config.php';
	require_once 'cheetan/cheetan.php';

	function action(&$c) {
	    if (count($_POST)) 
	    {
	        $c->test->del('id=' . $_POST['id']);
	    }
	    $c->set('data', $c->test->findone('id=' . $_GET['id']));
	}
?>
```

```
<form method="post" action="delete.php">
	name<br />
	<?php echo $data['data']['name'];?><br />
	age<br />
	<?php echo $data['data']['age'];?><br />
	<input type="hidden" name="id" value="<?php echo $data['data']['id']; ?>" />
	<input type="submit" value="del" />
</form>
```

以上。
express.jsのcors対応

#はじめに

APIサービスを構築する際に、Postmanなどのツールでは正常にアクセスできますが、
ブラウザからアクセスすると、エラーになる場合があります。

それはCORS(Cross-Origin Resource Sharing)対応をしていない可能性があります。
なぜなら、サイトのドメインとAPIサービスのドメインが違う場合は
先にoptionsメソッドで問い合わせをします。許可する場合のみ実際のAPIを通信します。

※同じドメインの場合はCORSの対応は要らないです。

#express.jsのcors対応
##方法1. optionsメソッドを実装
```javascript
const app = express()
const allowCrossDomain = function(req, res, next) {
  res.header('Access-Control-Allow-Origin', '*')
  res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE')
  res.header(
    'Access-Control-Allow-Headers',
    'Content-Type, Authorization, access_token'
  )

  // intercept OPTIONS method
  if ('OPTIONS' === req.method) {
    res.send(200)
  } else {
    next()
  }
}
app.use(allowCrossDomain)
```

##方法2. cors　middlewareを利用
### corsインストール
`npm install cors`

###すべてのAPIをCORS許可したい場合
```javascript
const express = require('express')
const cors = require('cors')
const app = express()

app.use(cors())

app.get('/user/:userId', function (req, res, next) {
  res.json({result: '任意のオリジンからすべてのAPIがアクセスOK'})
})
```

###個別のAPIをCORS許可したい場合
```javascript
const express = require('express')
const cors = require('cors')
const app = express()

app.get('/user/:userId', cors(), function (req, res, next) {
  res.json({result: '任意のオリジンからこのAPIのみアクセスOK'})
})
```

###CORSのオプション設定
設定可能なオプション：origin、methods、allowedHeaders、exposedHeaders、credentials、maxAge、preflightContinue、optionsSuccessStatus

設定例：

```javascript
const express = require('express')
const  cors = require('cors')
const app = express()

const corsOptions = {
  origin: 'http://example.com',
  optionsSuccessStatus: 200 
}

app.get('/user/:userId', cors(corsOptions), function (req, res, next) {
  res.json({msg: 'example.comからのアクセスのみ許可'})
})
```


#Vue.jsはproxy設定でCORSエラー回避
ローカル開発にてVue.jsとAPIサービスは違うポートで動作すると思います。

Apache,Nginxなどのサービスを経由していない場合は、
CORS問題がありますのでCORS対応が必要となります。
ただし、STG・本番はCORS対応は不要な場合が多いので、ローカルではCORSコードを追加するとよろしくないです。

Vue.jsはproxyの設定でCORS問題を回避できます。vue.config.jsに下記のように設定

```javascript
module.exports = {
    devServer:{
        proxy:{
            '^/api':{
                target: 'http://localhost:3001',
                ws: true,
                secure: false                
            }
        }
    }
}
```

#ヘッダーパラメータ名の注意点
ヘッダーのパラメータ名は小文字になる場合があります。
通信する際に{accessToken：'xxxxxx'}のヘッダーを設定して通信すると、
`req.headers.accessToken`では取得できず、`req.headers.accesstoken`なら取得できます。

ですので、ヘッダーのキー名はキャメルではなく、単語間を「_」で連結したほうがよいと思います。

参考記事：https://expressjs.com/en/resources/middleware/cors.html

以上
AWS CLI + JSONファイルでDynamoDBにデータを登録する

# 準備
DynamoDBに登録ためのJSONファイルを作成する。
・フォーマット
カラム・レコード毎にカンマでつなぐ。

```json:2レコード登録するフォーマット
{
    "【テーブル名】": [
        {
            "PutRequest": {
                "Item": {
                    "【カラム名】": {
                       "【データ型】" : "【データ】"
                    },
                    "【カラム名】": {
                       "【データ型】" : "【データ】"
                    }
                }
            }
        },
        {
            "PutRequest": {
                "Item": {
                    "【カラム名】": {
                       "【データ型】" : "【データ】"
                    },
                    "【カラム名】": {
                       "【データ型】" : "【データ】"
                    }
                }
            }
        }
    ]
}

```

・サンプル

```json:sample.json
{
    "sample-table": [
        {
            "PutRequest": {
                "Item": {
                    "id": {
                       "S" : "aaa"
                    },
                    "age": {
                       "N" : "29"
                    }
                }
            }
        },
        {
            "PutRequest": {
                "Item": {
                    "id": {
                       "S" : "bbb"
                    },
                    "age": {
                       "N" : "30"
                    }
                }
            }
        }
    ]
}
```

# AWS CLIで登録
準備したJSONファイルを使って登録。


```
aws dynamodb batch-write-item --request-items file://sample.json
```

※JSONファイルのパスは格納場所に合わせて変えること。
　サンプルは、カレントディレクトリにJSONファイルがある前提。

# 注意
JSONファイルには、24個のレコードが上限。
24個を超える場合は、エラーになるのでファイルを分けて複数回コマンドを実行する必要がある。

# 最後に
上限があったり、JSONファイルの作成がめんどいので、boto3使ってpythonで登録するプログラムを作った方が楽かも。
ちょっとしたデータを登録するときには有効だと思います。
送信専用channelと受信専用channel

# 宣言方法

goにおけるchannelとは何か、とかは今は省略。
日本語のchannelについての記事を見ていると、
`chan<- int`を「送信専用」、`<-chan int`を「受信専用」と書かれているものがいくつも見つかって、混乱したのでメモしておく
(例えば、https://qiita.com/yuki2006/items/3f90e53ce74c6cff1608)
(あるいは、https://qiita.com/marnie_ms4/items/cc2e49d4f11884e16611)

```go
// int型を扱う「送信専用？」チャネル
type s_ch chan<- int

// int型を扱う「受信専用？」チャネル
type r_ch <-chan int
```
個人的に、「送信専用」なのに矢印がchanへ向いている(受信？)し、「受信専用」なのに矢印がchanの外側に向かっている(送信？)のように見えるから、混乱した

結論から言うと、この違和感は正しいと思う。


# 英語のチュートリアルページの説明

http://golangtutorials.blogspot.com/2011/06/channels-in-go.html
かなり古い記事だが、これを読むと、上記の受信専用、送信専用の定義は逆転するし、とてもわかりやすくなる。上記のような混乱はまず起きない。

```go

// <-chan intは送信専用 dataを送信するだけのチャネル
ic_send_only := make (<-chan int) //a channel that can only send data - arrow going out is sending
// chan<- intは受信専用　dataを受信するだけのチャネル
ic_recv_only := make (chan<- int) //a channel that can only receive a data - arrow going in is receiving 
```

https://qiita.com/TsuyoshiUshio@github/items/d94a3d0f934bde6d6aed
この記事でも自分と似たようなモヤモヤが書かれています
Angularの開発環境を作る

こんにちは。
社内のデザイナーの人と話していて、jsを勉強している話を聞き、
じゃあついでにAngularとかどうよ？って軽率に勧めてみました。
責任は全くもって取れませんが、せめて0→1にする何かは必要な気がして、開発環境の構築メモです。

※対象読者はMac使っている方です。

## 今回書いてある内容
- パッケージマネージャーの導入
- Node.jsのインストール
- Angular CLIのインストール
- 初期アプリを作成する

## パッケージマネージャーの導入
[Homebrew](https://brew.sh/index_ja)を使いましょう。
以下のコマンドをターミナルに張り付けて実行します。

```shell
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```

インストールの確認でバージョンチェックを行います。

```shell
$ brew -v
```

上記コマンドを実行して、バージョンが出力されたら次のステップに行きましょう。

## Node.jsの導入
Homebrewを導入したのでそれを使って[Node.js](https://nodejs.org/ja/)をインストールしましょう。
以下のコマンドを入力して同じようにバージョンチェックまで行います。

```shell
$ brew install nodejs
$ node -v
```

バージョンまで出力出来たらまた次のステップに行きます

## Angular CLIのインストール
Angular CLIをnpmコマンドを使ってインストールします。

```shell
$ npm install -g @angular/cli
```

## 初期アプリを作成する
さて、開発準備が整ったので、アプリ開発を始めましょう。

```shell
$ ng new test-app
```

CSS何使う？的な選択とかいくつか出てきますが、好みで選んでいきましょう。
作成が終わったらテストサーバーを立ち上げてみましょう

```shell
$ cd test-app
$ ng serve
```

ローカルサーバーを立ち上げたら、[localhost:4200](http://localhost:4200)にアクセスして画面が表示されるか確認しましょう。
サーバーを落としたいときはCtrl+Cで落とします。

## まとめ
個人的なメモ的な意味もありますが、こういうのはたまにしかやらないので忘れますね。

## 参考
- [Angular Tutorial](https://angular.jp/guide/setup-local)
GASスクレイピングサンプル2(同じリンク同士を繰り返したどっていくパターン)

GASでのスクレイピングプログラムです
同じリンクでつながっているページ同士をたどって最後までURLを取得していくパターンです

<b>参考URL(テスト時に用いました)<b>
<a href="https://youpouch.com/2014/10/02/228902/">
【夜の4コマ部屋】ネコの恩返し / サチコと神ねこ様 第1回 / wako先生 | Pouch［ポーチ］
</a>


<b>PGM</b>
<pre>
<code class="JavaScript">
//最初に動かすメソッド
function scraping2(){
  const START_URL = 'https://youpouch.com/2014/10/02/228902/'//最初にスクレイピングするURL
  const START_COL = 2;
  const JUMP_LINK_STR = "次の話へ &raquo;" //ジャンプしていくリンクの内容
  
  var CrURL = START_URL;
  var sclaypingText = "";
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var rangeStr;
  var count = 0;
  
  while(CrURL != ''){
    count = count+1;
    rangeStr = "A"+count
    spreadsheet.getRange(rangeStr).setValue(CrURL);
    
    var response = UrlFetchApp.fetch(CrURL);
    var html = response.getContentText('UTF-8');
    var lines = html.split('\r\n');
    
    var rangeStr = ''
    var retURLList;
    var nextAllURLList = [];
    for(var j=0; j<lines.length; j++){
      retURLList = searchLink(JUMP_LINK_STR, lines[j])
      
      for(var k=0; k<retURLList.length; k++){
        nextAllURLList.push(retURLList[k]); 
      }
    }
    
    if(nextAllURLList.length >= 1){
      CrURL = nextAllURLList[0];
    }else{
      break
    }
  }
  
}

function searchLink(findLinkStr, srcStr){
  var resultURLList = [];
  
  var myRegExp1 = /<a href=.*?>.*?\<\/a>/g;
  var myRegExp2 = /<a href=.*?>/
  var myRegExp3 = /href=".*"/;
  var myRegExp4 = /<.*?>/g;
  
  var headTagStr;
  var str;
  var URLStr='';
  var tagStrs;
  var str2 = '"';
  
  var links = srcStr.match(myRegExp1);

  for(var i=0; i<links.length; i++){
    tagStrs = links[i].match(myRegExp4);
    headTagStr = links[i].match(myRegExp2)
    
    // リンク中に含まれている<a>,</a>, <span>, </span>等のタグを削除
    str = links[i];

    
    for(var j=0; j<tagStrs.length; j++){
        str = str.replace(tagStrs[j], '');
    }
    
    if(str == findLinkStr){
      URLStr = links[i].match(myRegExp3);
      URLStr = URLStr[0];
      
      URLStr = URLStr.replace('href=','')
      
      //前後の"を削除
      URLStr = URLStr.replace(str2,'')
      URLStr = URLStr.replace(str2,'')
      
      resultURLList.push(URLStr)
    }

  }
  
  return resultURLList

  

}
</code>
</pre>
Tensorflow install 備忘録

会社用PC内にJupyterをインストールしている人など、
微妙に権限設定がめんどくさい人向け(自分にも向けて)Tensorflowのインストール時の備忘録です。

#1.普通にインストールしようとすると→失敗！
```python

pip install tensorflow
↓
Cannot uninstall 'wrapt'. It is a distutils installed project and thus we cannot accurately determine which files belong to it which would lead to only a partial uninstall.
```
wraptが悪さをしているようです。 

#2.pip やcondaをアップデートしようとすると→失敗！
```python

conda update -all
conda update wrapt
conda remove wrapt
↓
PermissionError(13, 'アクセスが拒否されました。')
```
1.のwraptに関するエラー文をそのまま検索すると「wraptのアップデート」「wraptの削除」で対応する方法の2つが出ましたが上記のエラー結果が出てアクセス権の影響でうまくいきません。


#3.既にinstallしてあるものを無視すると→失敗!惜しい
```python
pip install tensorflow --ignore-installed
↓
Could not install packages due to an EnvironmentError: [WinError 5] アクセスが拒否されました。: 'C:\\ProgramData\\Anaconda3\\Lib\\site-packages\\easy_install.py'
Consider using the `--user` option or check the permissions.
```
既にインストールしてある ものを無視してTensorflowをインストールすると、似たようなエラーが出ましたが「--userを利用してみては？」というレコメンドを貰いました

#4.--userオプション付けると→成功！
```python

pip install tensorflow --ignore-installed --user
↓
#成功！
Successfully installed absl-py-0.7.1 astor-0.8.0 gast-0.2.2 google-pasta-0.1.7 grpcio-1.23.0 h5py-2.9.0 keras-applications-1.0.8 keras-preprocessing-1.1.0 markdown-3.1.1 numpy-1.17.0 protobuf-3.9.1 setuptools-41.1.0 six-1.12.0 tensorboard-1.14.0 tensorflow-1.14.0 tensorflow-estimator-1.14.0 termcolor-1.1.0 werkzeug-0.15.5 wheel-0.33.6 wrapt-1.11.2
```

結論、既にインストールしてあるライブラリを無視してかつ「--user」オプションをつけることでインストールが上手くいきました。

この他にも「pip自体のアップデート」もありましたがアクセス権の影響でうまくいきませんでした。
少ないと思いますが同様な事象で悩んでいる方はぜひお試しください。

#20201216追記
#module 'tensorflow.python.framework.ops' has no attribute '_TensorLike'エラー

tesorflow1系でプログラム作成した人がtensorflow2系にアップグレードした際にはまるエラーっぽい。
回避策はあまりネットにも載っていない。唯一下記が参考になり得そう。
importの書き方を工夫すればおそらく解消される。
https://medium.com/@softkaai/attributeerror-module-tensorflow-python-framework-ops-716cc0f574f

面倒くさい人は下記でtensorflowを戻してしまう

回避策
①tensorflowをuninstall

```python
conda uninstall tensorflow
```

②tensorflow1.14.0をinstall(おそらくtensorflow1系なら問題ない)

```python
conda install tensorflow==1.14.0
```

➂その後、kerasを再インストール
(keras入っていてもimportエラーが起こることがあるのでkeras利用する人は下記を実行)

```python
conda install keras
```

上記で解決
Laravel Blade の component を extends の代わりに使う

良いかどうかはともかく、そういう使い方もできるなと思ったネタ。なお 5.5 を使ってます。

普通に `@extends` を使えば次のようになりますが、

**layout.blade.php**

```php
<!doctype html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>Laravel - @yield('title')</title>
</head>
<body>
    <header>
        @section('header')
            <h1>Laravel</h1>
        @show
    </header>
    <main>
        @yield('content')
    </main>
</body>
</html>
```

**home.blade.php**

```php
@extends('layout')

@section('title', 'Home')

@section('header')
    @parent
    <h2>Home</h2>
@endsection

@section('content')
    <p>ここは Home のコンテンツです</p>
@endsection
```

これを `@component` を使って次のようにします。

**layout.blade.php**

```php
<!doctype html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>Laravel - {{ $title }}</title>
</head>
<body>
<header>
    {{ $header }}
</header>
<main>
    {{ $content }}
</main>
</body>
</html>
```

**home.blade.php**

```php
@component('layout', ['title' => 'Home'])

    @slot('header')
        {{-- @parent--}}
        <h1>Laravel</h1>
        <h2>Home</h2>
    @endslot

    @slot('content')
        <p>ここは Home のコンテンツです</p>
    @endslot

@endcomponent
```

ほぼ同じことが出来ますが、次のような違いがあります。

- `@extends` で使える `@parent` に相当するものが `@component` にはない
- `@extends` ではビューにアサインした変数がレイアウトテンプレートでも使用できる
    - `@component` だと明示的指定しないとレイアウトテンプレートに変数が渡されない

前者はあまり使う機会がない（Smarty や Twig にも同じような機能あるけどほとんど使った試しがない）のと、後者は個別のテンプレート用にアサインしたつもりの変数を、全体で共通に使われるレイアウトのテンプレートで使ってしまって、この変数どっから来たんや・・・みたいなのを避けることができてメリットにも感じます。

もし `@component` ですべての変数を渡したければ次のようにもできそうですし。

**home.blade.php**

```php
@component('layout', get_defined_vars())

    {{-- snip --}}

@endcomponent
```

## さいごに

たいていのテンプレートエンジンにある `include` や `extends` の機能、ビューにアサインされた変数が自動的にすべて引き渡されると `include` や `extends` の先のテンプレートでどこから来たのかわかりにくい変数が使われてしまうことがあります。

Blade の `@component` なら変数は明示的に渡す必要があって間違いが起きにくいので、`@include` や `@extends` をすべて置き換えてしまっても良いのでは、と思いましたが・・・

`@component` を `@extends` のように使うのは `@component` の本来の用途違うだろうので知らずに見ると混乱しそうで余計判りにくいかな。。。実際他の人が `@component` をこのような使い方をしていて何だこれはと思ったわけですけど（それでこの使い方を知った）
【SQL】結合したテーブルを基に、複数レコードをテーブルに挿入する(ROW_NUMBER))

###結合したテーブルの複数レコードを、別テーブルに挿入する方法



```SQL:売上表を時系列データを持つ売上明細表と結合させ、8月の売上表レコードを抽出して別テーブルに挿入
INSERT INTO August_SalesDetails(Id,SalesId,ProductId,Quantity,UnitPrice,Price,Note)

/*SELECTで抽出した表が挿入される*/
SELECT
ROW_NUMBER() over(order by D.id) +  (select max(Id) from SalesDetails)
,D.SalesId
,D.ProductId
,D.Quantity
,D.UnitPrice
,D.Price
,D.Note

/*以下で表を結合。8月の売上データ表を生成*/
FROM
SalesDetails D
join
Sales Sa
On D.SalesId = Sa.Id
Where MONTH(Sa.SalesAt) = 8 and YEAR(Sa.SalesAt) = 2019  
```

主要キーであるIdカラムには抽出したフィールドを挿入することができないので、ROWNUMBER()を使って、順番にIdを振り直す。
今夜はFastFCNの学習を回して寝よう

Semantic Segmentation の最近の動向をあまり追っていなかったのですが、
[つくりながら学ぶ！PyTorchによる発展ディープラーニング](https://www.amazon.co.jp/dp/B07VPDVNKW) という本を買い、
PSPNet というものがあることを知りました。
実装までしっかり書いてあってめちゃくちゃわかりやすいのでおすすめです。
自分は今までTensorFlow を主に使っていましたが、Pytorch の使い方を学びながら新しい技術についても学べます。

上述の本でPSPNetを実装している際に、FastFCNという最新のネットワークの存在を知ったので、
実際に動かしてみました。
論文の要点が以下の記事にまとまっています。
自分はまだ論文を読んでいないので、この記事を参考に読み進めていこうと思っています。
https://qiita.com/kamata1729/items/1b495658a63d76904ac3

その記事の中で、このレポジトリにリンクがはられていました。
https://github.com/wuhuikai/FastFCN 

今回の記事では、このレポジトリのコードを実際に動かす手順を書いていこうと思います。
ちょこちょこハマるところもあったので悲

# 環境
## host
メモリ 32GB
GPU GTX1080Ti

## docker
Dockerfile は、以下に置きました。
もしかしたら、ちょこちょこ追加したpackage があるかもしれません。
追って、検証していきたいと思います。
https://gist.github.com/gorogoroyasu/47d5ab6bd3b97b016ca1c8cca8435c6a

## git clone
レポジトリをcloneします。
README.md に色々書いてありますが、GPU1台で実行する場合下記のコード変更を先に行う必要があります。

## 環境に依存するコードの変更
今回一番言いたかったことはこれです。
https://github.com/wuhuikai/FastFCN/issues/12
何箇所かコードを変更する必要があります。

### encoding/models/encnet.py
https://github.com/wuhuikai/FastFCN/blob/097e7130f77a15eeca12f37a0afcf2f8f7f90439/encoding/models/encnet.py#L53
ここを、 `nn.BatchNorm1d(ncodes),` に変更します。

### experiments/segmentation/train.py
https://github.com/wuhuikai/FastFCN/blob/097e7130f77a15eeca12f37a0afcf2f8f7f90439/experiments/segmentation/train.py#L54
ここを `se_loss = args.se_loss, norm_layer = torch.nn.BatchNorm2d`に変更します。

https://github.com/wuhuikai/FastFCN/blob/097e7130f77a15eeca12f37a0afcf2f8f7f90439/experiments/segmentation/train.py#L111
ここを `loss = self.criterion(*outputs, target)
`に変更します。

https://github.com/wuhuikai/FastFCN/blob/097e7130f77a15eeca12f37a0afcf2f8f7f90439/experiments/segmentation/train.py#L132
この行を削除します。


## インストール
この変更を行ったあと、
```sh
PATH=.:$PATH
python setup.py install
```
を実行します。

## データのダウンロード
あとは README.mdに従ってデータをダウンロードして学習を実行すればよいです。
自分は、`ADE20K`をダウンロードしました。

```sh
python scripts/prepare_ade20k.py
```

結構時間がかかるので、寝る前にここまで完成させて、実行して寝ましょうｗ

データのダウンロードが完了したら、

```sh
cd experiments/segmentation
CUDA_VISIBLE_DEVICES=0 python train.py --dataset ade20k --model encnet --jpu --aux --se-loss --backbone resnet50 --checkname encnet_res50_ade20k_train
```

を実行すればトレーニングが開始されます。


ちなみに、自分のGPUでは、デフォルトのバッチサイズが大きすぎたので、

```
--batch-size 2
```

を追加しました。
たぶん、デフォルトは4だと思います。

とてつもなく時間がかかりそうで怖いですが、家に帰ってきた頃には数epoch 学習が進んでいると思うので、
その結果を見て一喜一憂しようと思います。

## 終わりに

SOTA だと信じて疑わなかったFastFCN ですが、
この記事を書いている途中にSOTA が更新されていることに気が付きました悲
https://paperswithcode.com/paper/high-resolution-representations-for-labeling

high-resolution-representations-for-labeling
についても調べていこうと思います。
1777 なディレクトリのログを logrotate したときのエラー

スティッキービットを付けたログディレクトリにいろいろな uid のプロセスからログを書き込みできるようにしたくて `mkdir -m 1777 /var/log/oreore` みたいなディレクトリのログを logrotate しよとしたところ、次のようなエラーになりました。

```
error: skipping "/var/log/oreore/ore.log" because parent directory has insecure permissions (It's world writable or writable by group which is not "root") Set "su" directive in config file to tell logrotate which user/group should be used for rotation.
```

root 以外のグループが書込み可能なディレクトリなディレクトリでは `su` を使用する必要があるとのことです。

logrotate のそれっぽいところを見てみると・・・

```c
  /* Check if parent directory of this log has safe permissions */
  if ((log->flags & LOG_FLAG_SU) == 0 && getuid() == 0) {
    char *ld = ourDirName(log->files[logNum]);
    if (stat(ld, &sb)) {
      /* If parent directory doesn't exist, it's not real error
        and rotation is not needed */
      if (errno != ENOENT) {
        message(MESS_ERROR, "stat of %s failed: %s\n", ld,
          strerror(errno));
        free(ld);
        return 1;
      }
      free(ld);
      return 0;
    }
    /* Don't rotate in directories writable by others or group which is not "root"  */
    if ((sb.st_gid != 0 && sb.st_mode & S_IWGRP) || sb.st_mode & S_IWOTH) {
      message(MESS_ERROR, "skipping \"%s\" because parent directory has insecure permissions"
                " (It's world writable or writable by group which is not \"root\")"
                " Set \"su\" directive in config file to tell logrotate which user/group"
                " should be used for rotation.\n"
                ,log->files[logNum]);
      free(ld);
      return 1;
    }
    free(ld);
  }
```

`log->flags & LOG_FLAG_SU` は `su` オプションが指定されているかどうか、つまり、

- `su` が未指定で
- logrotate が root で実行されていて
- ディレクトリが `gid != root && g+w` または `o+w`

だとエラーになります。

下記のように su しておけば黙らせられます。

```conf
/var/log/oreore/*.log {
  su root root
}
```
PHP のエラーログを root が作成してしまってアプリから書けなくなる問題

php のエラーログ、`php.ini` で次のように設定していると・・

```ini
error_log = /var/log/php/php.log
log_errors = On
```

なにかの拍子で root で php を実行してエラーが出力されると `/var/log/php/php.log` が root 所有の 0644 とかで作成されてしまい、アプリケーションの実行ユーザーからエラーログが書けなくなってしまいます。

この問題を解決するためのいくつかの案。

## 案：logrotate で 0666 でファイルを作成する

logrotate で次のように `create 0666 root root` を指定します。

```conf
/var/log/php/*.log {
  missingok
  notifempty
  create 0666 root root
}
```

こうしておけばローテーション時に 0666 でログファイルができるので、root でログに書き込んでしまっても Web アプリからのエラーログが書き込めなくなったりはしません。

と思ったら次のような問題があるらしいです。

> logrotateがrenameして新しいファイルを作るよりはやくPHPのloggerがファイルを作ってしまい、logrotateがfile existsで死んでしまう。どうしてPHPはファイルを開きっぱなしにできないのかしら
> https://twitter.com/kazeburo/status/960717004494684161

うーん・・・

## 案：php.ini ではエラーログを設定しない

php.ini ではエラーログのファイル名を空にして SAPI のデフォの出力先に出るようにします（CLI なら標準出力？か標準エラー？、mod\_php なら Apache の error\_log、php-fpm なら？？）。

**php.ini**

```
error_reporting = -1
display_errors = off
display_startup_errors = off
error_log =
log_errors = On
```

その上で httpd.conf とか php-fpm.conf とかの SAPI に固有の設定ファイルでエラーログの出力先を指定します。

**httpd.conf**

```
php_value error_log /var/log/php/apache.log
```

**php-fpm.conf**

```
php_value[error_log] = /var/log/php/apache.log
```

もしくは `php-<sapi>.ini` のような特定の SAPI でだけ読まれる php.ini でも良いかもしれません。

cron とかから CLI を実行するときはコマンドラインオプションで指定します。

**cron.d/app**

```
SHELL=/bin/bash
MAILTO=root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
* * * * * apache php -d error_log=/var/log/php/batch.log -d display_errors=stderr /path/to/batch.php | logger -i -t app
```

logrotate では nocreate を指定します。

```conf
/var/log/php/*.log {
  missingok
  notifempty
  nocreate
}
```

これで不意に root で `php -r xxx` とかしてしまってもログファイルは作成されません。

## さいごに

PHP を使い始めた最初のころから php.ini で↓みたいにするのは鉄板だと思ってたのですが、

```ini
error_log = /var/log/php/php.log
log_errors = On
```

実はそうでもなくて世間一般では SAPI 固有の設定ファイルで指定してたりする？ のだろうか。いや、syslog という手もあるか。。。

## 追記

Web アプリケーションを root で動かすことは一般的にはありえないですが、サーバのオペレーション用のスクリプトやちょっとしたワンライナーを PHP で作って root で実行とかすると、サーバグローバルな php.ini でログを吐く設定していると問題になることがあるということですね。ログ以外でも php.ini で出力先が設定できるものは同様です（なにかあったっけ？思いつかない）。アプリケーションのキャッシュとかは PHP のコアが吐くわけではないので問題ありません（それはアプリケションが吐くものなので）。

もっとも、PHP で Web アプリケーション以外を作ることはまあまずないですけど・・実際のところシステムの運用中にこの問題が起こったことはないと思います。

ただ、たまに PHP が一番得意だという理由で PHP でなんでも書く人はいますしそれをあまり止めたりもしないです。もちろん、Web アプリケーションと同じ言語で書いてしまうと Web アプリケーションの都合で言語のバージョンアップをするときに影響範囲がわかりにくくなるので、サーバオペレーション系のスクリプトはディストリから提供されているものをそのまま使うのが良いだろうと思います（Bash とか Python とか）。Web アプリケーション用の PHP とサーバオペレーション用の PHP を別々に入れる？ それはやめておいたほうが良いと思いますね、、、どっちの PHP で実行されるかわからなくて新規の人がとてつもなく混乱しそうです（勝手なイメージですが Ruby だと Web アプリケーションとサーバオペレーションをを同じ Ruby で実行してることが多そう？）。