OmniAICreator/Qiita-1.07M huggingface dataset:
モデル参照ブロック内の信号ログ取得

モデル参照ブロックのシミュレーションモードを「アクセラレータ」にして、親モデルからシミュレーションをしてみると、参照ブロック内に設置した Scopeブロックに信号が表示されないようです。

![scope1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482981/4c9fd454-4c5f-2f0f-616a-28bf08972517.png)

ここでは、どうしてもモデル参照ブロック内部の信号を確認したい場合の方法を紹介します。
手順は以下の通りです。至って簡単です。

1: 観測したい信号線上で右マウスクリックをするとコンテキストメニューが現れます。
  [プロパティ]をクリックして、"信号プロパティ" 画面を表示させます。

2: 信号プロパティ画面より、信号名を適当に決めて、[信号データのログ]にチェックを入れ、[OK]をクリックします。設定後は以下の様な画面になります。


![c_model1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482981/eda05dd0-7017-e891-de24-ac6aad66200f.png)


3: 参照モデルを保存して、親モデルから実行します。

4: ワークスペース上に、"out" という名前の変数が保存されます。
 これは、コンフィギュレーションパラメータ > データのインポート/エクスポート の [単一のシミュレーション出力：] に定義される変数名に紐づけされます。


`whosコマンド実行結果`
![ws1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482981/12e1a75c-8619-3386-0be7-1476df3b2fcf.png)



5: オブジェクト変数の階層が深いですが、次のコマンドで、時間の情報と信号の情報より、プロットすることができます。

`plotコマンド実行結果`
![ws2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482981/e6cbde86-dc9c-29e8-2641-d6c1faaaa125.png)

![plot1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482981/f5dbd271-42e6-842f-a411-55458c738a1d.png)
RSpecでchromedriverとChromeのバージョンが合わない

#はじめに
RSpecでsystem specを書いている時にエラーが出て解決までに２時間ぐらいかかりました。
普段から使っているgemを把握していたり、ログを見ていれば、すぐ解決出来たのはずなのに...
いい勉強になりました。


#エラー

rspecを実行すると...

```
 1.2) Failure/Error: e = error
          
          Selenium::WebDriver::Error::SessionNotCreatedError:
            session not created: Chrome version must be between 71 and 75
              (Driver info: chromedriver=2.46.628411 (3324f4c8be9ff2f70a05a30ebc72ffb013e1a71e),platform=Mac OS X 10.14.6 x86_64)

```
このようなエラーが出ます。

Chromeとchromedriverのバージョンが合っていないみたいです。
とりあえず、chromedriverのバージョンを上げてみたり、homebrewで新たにインストールして見ましたが解決しませんでした。

インストール時の参考記事↓
[MacにChromeDriverを入れる](https://blog.naichilab.com/entry/mac-chromedriver)
[How to Install Chrome Driver on Mac (2019 Update)](https://www.swtestacademy.com/install-chrome-driver-on-mac/)

#解決策
次にgemで関係するものないかなと思い、`gem list`でgemを覗いてみるとchromedriver-helperというそれぽいのがあったのでググってみるとお目当ての記事にたどり着きました。


以下記事参照↓
[サポートが終了したchromedriver-helperからwebdrivers gemに移行する手順-Qiita](https://qiita.com/jnchito/items/f9c3be449fd164176efa)

そもそもデフォルトでchromedriver-helperが入っているみたいです。gemの存在すら知りませんでした。
chromedriver-helperのサポートが終了しいるため、chromedriverとChromeのバージョンが合わないというエラーが出たみたいです。
また、chromedriver-helperのインストール時にちゃんと警告も出ているみたいです。ちゃんと見ていなかったので気づきませんでした😅

警告通りgemをgem 'webdrivers'に入れ替えたらあっさり解決しました。
Windows環境 Goのrealizeでハマった話

いきなりDocker化すると、動きがわからず、
ハマる可能性大なので一回ローカルで試すのが吉と思う

コンパイルの出力先ファイル名になんでもいいから拡張子つけないとダメ。
windowsなので、exeをつけた。

``` yaml
  commands:
    install:
      status: true
      method: go build -o app.exe
    run:
      status: true
      method: ./app.exe
```

そうしないと。このエラー

``` bash
$ realize start
[15:10:53][GO_DEMO2] : Watching 2 file/s 0 folder/s
[15:10:53][GO_DEMO2] : Install started
[15:10:57][GO_DEMO2] : Install completed in 3.978 s
[15:10:57][GO_DEMO2] : Running..
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x8 pc=0x4d006d]

goroutine 52 [running]:
os.(*Process).signal(0x0, 0xa58520, 0xd9a4c0, 0xc000214020, 0xc00007af70)
        c:/go/src/os/exec_windows.go:59 +0x2d
os.(*Process).Signal(...)
        c:/go/src/os/exec.go:131
github.com/oxequa/realize/realize.(*Project).run.func1(0xc00007b6a8)
        C:/Users/N10W78/go/src/github.com/oxequa/realize/realize/projects.go:581 +0x64
github.com/oxequa/realize/realize.(*Project).run(0xc00005e300, 0xc000019650, 0x5, 0xc00020a180, 0xc000058420, 0xa53d40, 0xc0002020c0)
        C:/Users/N10W78/go/src/github.com/oxequa/realize/realize/projects.go:646 +0xc62
github.com/oxequa/realize/realize.(*Project).Reload.func3(0xc00005e300, 0xc00020a180, 0xc000058420)
        C:/Users/N10W78/go/src/github.com/oxequa/realize/realize/projects.go:262 +0x14e
created by github.com/oxequa/realize/realize.(*Project).Reload
        C:/Users/N10W78/go/src/github.com/oxequa/realize/realize/projects.go:260 +0x29e
```

また、Goでwebサーバしている場合、プロセスを殺してやらないと、実行ファイルが上書きされず
ホットリロードされなかった。
macやlinuxならいけるのだろうか。。。今後調査 ・・・追記Linux上なら何事もない

``` yaml
    scripts:
      - type: before
        command: taskkill /F /im app.exe
```

realize.yml サンプル

``` yaml
settings:
  legacy:
    force: true
    interval: 0s
schema:
- name: realize
  path: .
  args:
  - main.go
  commands:
    install:
      status: true
      method: go build -o app.exe
    run:
      status: true
      method: ./app.exe
  watcher:
    extensions:
    - go
    paths:
    - /
    scripts:
      - type: before
        command: taskkill /F /im app.exe
    ignored_paths:
    - .git
    - .realize
    - vendor
```
ubuntuのCUIで日本語入力することがないような人生を過ごしたい

###日本語のubuntuを入れた
母国語が日本語なのでそうしました。
ところが問題が発生しました。
ホームディレクトリ配下のディレクトリがカタカナで表記されています。
GUIだからかと思ったんですがCUIでもダウンロードと書いていて、

```
cd ダウンロード
```
と書かなければダウンロードディレクトリに移動できないという自体が発生しました。
「cd 」と打って日本語入力に切り替えて「ダ」と打ってtabを叩いてまたローマ字入力に戻すことに辛い気持ちでした。

###英語にする。
結論だけ述べれば
[ubuntuでホームディレクトリの中身を英語にする](https://qiita.com/taiko19xx/items/d1a001bfc25245b91354)
上記を参考に、以下で実現します。

```
LANG=C xdg-user-dirs-gtk-update
```

これで英語化しました。

```
cd Downloads
```
が出来ます。

###もうちょっと設定したほうがいいかもしれない
スクリーンショットを取るとhome配下に配置されるようになってると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443834/9a52d858-5b73-07eb-2b37-6b8efa3aa7f4.png)
何が問題かっていうとディレクトリの変更自体はうまく言ってるんですがボタンの設定が反映されてないみたいなんです。
settingを開いてこんなふうに設定しちゃいましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443834/b8faf5d8-cbaa-b873-8b2b-292d533f6c9a.png)

他の操作もhomeに落ちるのかと思い調べましたが、
特に問題はなかったです。
ダウンロードとかきちんとDownloadsに入ってました。
問題があればそれの対処を追記していきたいと思います。
keepalive_requests in upstream context

先日、某所のnginxを1.14系から1.16系に更新したところ、レスポンスタイムが悪化する現象に遭遇したので、その時の対処記録。以下は99percentileと95percentileでのレイテンシのグラフ。

### 99percentile latency

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1608/535527a4-b5d7-96a3-f6d1-45329013b960.png)

### 95percentile latency

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1608/2dc7c18e-e75b-fdcd-5882-987948a9250c.png)

nginxのバージョンアップでレスポンスタイムが悪化するのを経験したのは初めてのことだったのですが、いろいろ調べてみるとアップストリームサーバとのキープアライブに関する挙動が大きく変わったのが原因で、そのへんのディレクティブの値をちょいと調整することで元のレスポンスタイムを維持できるようになりました。

## keepalive_requests in upstream context

nginxの1.16系と1.14系の大きな違いの一つとしてkeepalive_requestsディレクティブが従来のhttp, server, locationコンテキストに加えてupstreamコンテキストでも利用できるようになったことが挙げられます。（実際に導入されたのは1.15.3）

https://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive_requests

また、同じタイミングでkeepalive_timeoutについてもupstreamコンテキストで利用可能になっています。

https://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive_timeout

ただ、keepalive_requestsはデフォルト値が100になっているため、同時に大量のリクエストを捌くような環境ではアップストリームとの接続をキープアライブにする設定にしていても、頻繁にアップストリームとの接続が切れてしまいます。なので、そういった環境下ではかなり大きめの値にしておくのがよいでしょう。（nginxでアップストリームとのキープアライブを有効にする設定については[こちら](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive)を参照）

```nginx
upstream backend {
    # upstream servers
    # ...
    keepalive 100;
    keepalive_requests 10000;
}
```

実際に、keepalive_requestsを大きい値に設定することで元のレスポンスタイムに戻りました。

### 99percentile latency（再掲）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1608/535527a4-b5d7-96a3-f6d1-45329013b960.png)

## まとめ

- nginx-1.16系ではupstreamコンテキストでkeepalive_requestsが利用できる
  - 実際に導入されたのは1.15.3
- keepalive_requestsのデフォルト値（100）は同時に大量のリクエストを捌くような環境下では小さく、アップストリームとの再接続が頻繁に発生してレイテンシが悪化しやすいので、大きめの値を設定しよう

## おまけ

ちなみに、上記のグラフは[kazeburo/mackerel-plugin-axslog](https://github.com/kazeburo/mackerel-plugin-axslog)を使って出力しています。

[秒間数千件以上のアクセスログでも高速に集計し、可視化できる mackerel-plugin-axslog の紹介](https://kazeburo.hatenablog.com/entry/2019/04/05/093000)
QualityForwardとRedmineを連携する

[QualityForward](https://bit.ly/2MwQ68v)はテスト管理クラウドサービスです。ExcelやGoogleスプレッドシートような一覧形式でテストを一括作成したり、テストケースを更新できます。テストはプロジェクト管理システムと相性がよく、QualityForwardもJIRAやRedmineと連携できるようになっています。

今回はRedmineとの連携方法について紹介します。

## Redmineについて

今回はRedmineをクラウドで提供している[Planio（プラニオ）](https://plan.io/ja/)を使っています。APIキーは個人設定で確認できます。もし表示されない場合は管理 > 設定画面のAPIタブで `RESTによるWebサービスを有効にする` が有効になっているか確認してください。

<img width="2582" alt="Screenshot_ 2019-08-16 14.57.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/7987f87d-ae02-4602-f10c-b767522b734d.png">

そして、QualityForwardで情報として使えるのは下記の情報です。

- バグ曲線、グラフデータ取得用URL
- 最近のインシデント取得用URL

この二つをどう定義するかはプロジェクトによって異なるでしょう。そこで、チケット一覧の検索条件を指定して、保存するのがお勧めです。

クエリを保存すると、 `query_id=2` といったIDが生成されるので、これを指定します。例えば以下のようになります。

- **バグ曲線、グラフデータ取得用URL**  
https://qualityforward.planio.jp/projects/aaa/issues.json?key=9fac...539&query_id=2
- **最近のインシデント取得用URL**  
https://qualityforward.planio.jp/projects/aaa/issues.json?key=9fac...539&query_id=3

`https://qualityforward.planio.jp/projects/aaa/` はRedmineプロジェクトのURLになります。

## QualityForwardの設定

QualityForwardではテストフェーズの設定を使います。

<img width="3074" alt="Screenshot_ 2019-08-16 14.47.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/627a6754-4799-13ad-a070-25e4a7d1f5c8.png">

設定の中に `連携するBTS` という項目があるので、ここでRedmineを選択します。設定するのは下記の3つです。

| 項目 | 値 |
|------|----|
| ベースURL | https://qualityforward.planio.jp/?key=9fac...539 |
| バグ曲線、グラフデータ取得用URL | https://qualityforward.planio.jp/projects/aaa/issues.json?key=9fac...539&query_id=2 |
| 最近のインシデント取得用URL | https://qualityforward.planio.jp/projects/aaa/issues.json?key=9fac...539&query_id=3 |

ベースURLにはプロジェクトのパスは入らないので注意してください。グラフデータURLなどは、query_id以外のパラメータも指定可能です。詳しくは[Rest Issues - Redmine](https://www.redmine.org/projects/redmine/wiki/Rest_Issues)にて確認してください。

<img width="1537" alt="Screenshot_ 2019-08-16 15.00.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/9459451f-35b1-a549-fa52-901ffa638111.png">

## 連携後

連携するとバグ曲線やグラフデータを描くデータとして使われたり、最近のインシデント一覧にRedmineのデータが表示されるようになります。

<img width="1229" alt="Screenshot_ 2019-08-16 12.34.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/97285ca6-fa92-be99-2d4b-60bfd47b8652.png">

<img width="1229" alt="Screenshot_ 2019-08-16 12.36.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/f6050e43-033b-b830-195c-6b1f17420f62.png">


## まとめ

プロジェクト管理とテスト管理について異なるシステムを導入しているケースも多いでしょう。連携することで開発生産性が大きく向上しますので、ぜひAPI連携をしてみてください。

[QualityForward](https://bit.ly/2MwQ68v)
Fujitsu PRIMERGY RX200S7にCentOS7をインストール〜RAIDの設定編

富士通のサーバPrimergyシリーズのラックマウントサーバにCentOS7をインストールする。
2019年現在RX100,RX200,RX300のS7世代の中古品がお手軽価格で入手できるのでこれらを使用する。
ただしストレージの構成によってインストール方法が異なってくるので注意が必要。インストールメディアはisoイメージをDVD−Rに焼き付けたものを使用する。そのため、DVD-ROMドライブが必要。本体に光学ドライブが内蔵されていない場合USB接続のドライブを利用できる。biosでUSBから起動できるように設定しておく（デフォルトで起動可能）。

###SASアレイコントローラカードが装着されていない場合
使用できるHDDはSATAインターフェースの物に限られる。また、software RAIDを介してインストールする必要があり、software RAIDドライバをインストールする必要がある。
http://azby.fmworld.net/app/customer/driversearch/ia/drviadownload?driverNumber=F1019699
ここでダウンロードできる「ソフトウェアRAID Embedded MegaRAID RHDUP driver package for RHEL7」megasrが必要。ダウンロードリンクは消滅する可能性があるので注意。
またRX1330M3など最近の機種の場合
http://azby.fmworld.net/app/customer/driversearch/ia/drviadownload?driverNumber=F1027982
こちらのmegasr2ドライバが必要となる。

（追記）
MegaRAIDを使わないでただのSATAインターフェイス*4としてインストールする方法もある。その場合OSの方でSoftware RAIDを設定することも可能。

+ LCI MegaRAIDの設定を行う。

電源スイッチを入れると、しばらくしてMegaRAIDがHDDを認識する画面が出るのでctl+Mで設定に入る。
VirtualDiskの設定をマニュアルに従って実施する。
http://jp.fujitsu.com/platform/server/primergy/manual/peripdf/b7fy-2551-01.pdf

+ megasrドライバをインストールする

USBメモリにドライバを予め書くこんでおく必要がある。USBメモリは64MB等小さなもので十分だが、
ドライバをddで書き込むため、フォーマットしておく。ddが使えるPC/Mac等が必要。

    $ dd if=megasr-16.01.2014.0318.4fts-16.el7.5-000.x86_64.iso of=/dev/diskxx

CentOS7のインストール

+ インストールDVDをドライブに入れて起動する。
+ インストールを選択する画面ですかさずescキーを押す。
+ プロンプトに以下のように入力
 
``` 
>linux dd modprobe blacklist=ahci
```
+ USBメモリを装着し、USBメディアを読み込むためｒを押す。
+ USBメディアの番号を入力。
+ ドライバファイルの番号を入力。
+ 読み込むためｃを押す。
+ 一つ前のメディア選択に戻るのでｃを押す。
+ インストーラが起動する。


###SASアレイコントローラカードが装着されている場合

使用するコントローラごとに設定方法が異なるため、まずはマニュアルを参照する。
基本的にはシステム起動時にコントローラカードのromが読み込まれるのでctrl+H等でsettingユーティリティに入る必要がある。
RAID 0/1 SAS based on LSI MegaRAID (D2507)
https://jp.fujitsu.com/platform/server/primergy/manual/peripdf/b7fy-2541-01.pdf

RAID Ctrl SAS 6G 0/1 (D2607)
https://jp.fujitsu.com/platform/server/primergy/products/note/svsdvd/dvd/pdf/b7fy-2751-01.pdf

このあたりを参照してRAIDを構成する。
以降のインストールは同じ。
VSCodeでimport文の自動ソート

## やりたいこと

import文をセーブ時に自動ソートしたいけどprettierではできない。
VSCodeのソースアクションでimportの整理ができるがいちいち手動でやるのはめんどくさいのでセーブしたときに自動で実行するようにしたい。

## 方法

settings.jsonに以下を追加。

```json
  "editor.codeActionsOnSave": {
    "source.organizeImports": true
  }
```

---

formatOnSaveとの実行順序とかちゃんと分かっていないけど、手元ではとりあえず動いてるからまあ良し！

---

## 追記 (2019/8/18)

formatOnSaveとの実行順序でやっぱり不具合が起きたので、organizeImportsをonSave実行するのはやめて別コマンドで手動実行することにした。

「キーボードショートカット」で "organizeImports" で検索すると出てくるので、これを好きなキーバインドに変更して使用。

multiCommandという拡張も試したが、organizeImportsが非同期実行されているせいか、 organizeImports -> format -> save の順に実行されず、うまく動かないケースが多発したので使用をやめた。
Ubuntu 18.04にFilebeat 7.3を導入する(aptコマンドでインストール)

以下、rootユーザーで実行しています。

# 1. Filebeatのインストール
下記のコマンドを実行します。
ElasticsearchやKibanaを事前にインストールしている環境であればリポジトリの登録は不要です。

```
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | apt-key add -
echo "deb https://artifacts.elastic.co/packages/7.x/apt stable main" | tee -a /etc/apt/sources.list.d/elastic-7.x.list
apt update
apt install filebeat
```

# 2. filebeat.ymlの編集
filebeat.ymlに以下のパラメーターを追加します。

```/etc/filebeat/filebeat.yml
setup.dashboards.enabled: true

setup.kibana:
  host: "XX.XX.XX.XX:5601" # KibanaサーバーのIPアドレス

output.elasticsearch:
  hosts: ["XX.XX.XX.XX:9200"] # ElasticsearchサーバーのIPアドレス
```

# 3. Syslog関連のモジュールの有効化
下記のコマンドを実行します。

```
filebeat modules enable system
```


# 4. 起動
下記のコマンドを実行します。

```
systemctl start filebeat
```

# 4. 動作確認
下記のコマンドを実行して検索クエリを送って検索結果としてシスログが何かしら返ってくれば、正常にシスログを取得出来ています。

```
curl -XGET "http://XX.XX.XX.XX(ElasticsearchサーバーのIPアドレス):9200/filebeat-7.3.0/_search" -H 'Content-Type: application/json' -d'{  "query": {    "match_all": {}  }}'
```

もしくは、KibanaコンソールでManagement->Index Managementを開いて、Filebeatのインデックスが表示されるか確認します。
![Screenshot_2019-08-16 Kibana.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478819/79d83f4c-3783-62f4-7fe0-f2e5ae2d98a7.png)
BigQuery使いのためのMac環境設定

# このドキュメントはなにか?

* 私のPC環境を再セットアップするときに読むためのドキュメント。
* 主にVSCodeでBigQuery用のクエリを書くための環境。

# 手順

# 基本

* Home Brew https://brew.sh/index_ja.html

# 日本語入力

* https://www.google.co.jp/ime/
* https://pqrs.org/osx/karabiner/

# 開発環境

* VSCode https://code.visualstudio.com

# shell

* fish shell
    * `brew install fish`
* oh-my-fish
    * https://github.com/oh-my-fish/oh-my-fish
    * `curl -L https://get.oh-my.fish | fish`
* ログインシェルをfishにする。


# GCP

* Cloud SDK
    * https://cloud.google.com/sdk/docs/?hl=ja
* fishの場合は追加の設定が必要。
    * https://qiita.com/dora56/items/5daa67e6dcf676474934

# こまごま

* `ssh-keygen`
    * SSOを使ってる場合は、Githubにkeyを登録したあと、SSO有効化が必要。
* `tig`
    * `brew install tig`
SQLを使ったデータ分析のチップス、ノウハウ

テラバイト級、ペタバイト級の大規模データの分析では、JOIN句やWindow関数などを使った複雑なSQLを書けることが必須条件だと思います。そのような大規模データはGCPのBigQueryやAWSのRedshiftにデータが格納されている事が多く、SQLを自由に書けないと必要なデータを抽出することができないからです。そして、SQLの構文や文法に関する書籍やサイトは数多く存在しますが、SQLでデータ分析する際のチップスやノウハウを紹介したものはほとんど見当たらなかったので記事にしてみました。

# まずはスモールデータで試す
いくらBigQueryやRedshiftが高速だと言っても、1年分のログデータとマスタデータ（例：ユーザ情報、アイテム情報）をJOIN句で結合させて…などすれば、クエリの結果が返ってくるまで数十分、最悪数時間掛かる場合があります。返ってきたデータが意図した通りのものであれば良いのですが、関数の使い方が間違っていたり、そもそもデータに不備があったりして意図した結果ではないという事はしばしばあります。その場合、クエリが返ってくるまで待っていた時間が無駄になります。そのような事態が防ぐために、まずはスモールデータで試して結果を確認するようにしましょう。先ほどの例で説明すれば、

1. まず、1日分（1時間分などでもOK）のログデータを対象にクエリを実行し、結果を確認する。意図した結果でない場合、その原因を探す。SQLに問題があるのか、データに不備があるのかのどちらかの場合が多い。
2. 1で結果が問題ないことを確認できれば、1年分のログデータを対象に再度クエリを実行する。

という流れになります。

# テンポラリーテーブルを活用
アドホックな分析をしていると、下図のように途中までは同じ処理だけど、後半の処理だけを換えて分析したいという事がよくあります。この場合、毎回最初から最後まで処理を流すのは無駄です。

<img width="300" alt="スクリーンショット 2019-08-08 19.07.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127582/8630cccb-548c-30ea-43db-521f5da91c3d.png">

このような場合は下図のようにテンポラリテーブル（一時テーブル）を作りましょう。前半の共通処理部分は一度だけ実行すれば結果を使い回せるようになったので、全体としてのクエリの実行時間が短くなり作業効率が上がります。もしこのテンポラリテーブルが他の人の分析でも使用される可能性が高い場合、データエンジニアにお願いして誰でもアクセス可能な共通テーブルにすると良いでしょう。

<img width="420" alt="スクリーンショット 2019-08-08 19.26.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127582/d9ce8f07-7ba3-06d1-95ca-510f7c26c923.png">


# JOIN句には要注意
異なるテーブルを結合させるJOIN句は分析には欠かせません。ログデータにユーザやアイテムの属性情報が入ったマスタデータを結合させるというのは、データ分析では必ず通る道です。ただ、この便利なJOIN句、気を付けておいた方が良いです。というのも、意図せずにデータが増殖（？）することがあるからです。
例えば、アイテムの履歴情報を持たせるために、アイテムIDとレコード数が1対1ではなくて1対Nの関係になっている分析用のマスタテーブルがあったとします。この場合、何も条件を指定せずにログデータにこのテーブルをOUTER JOIN句で結合させると、複数レコードを持つアイテムID（分析用のマスタテーブルの中でアイテムIDとレコード数が1対Nの関係にある）ではログがN件まで増えます。これを防ぐためには、マスターテーブルの各アイテムIDに対して、最新のタイムスタンプのレコードだけをOUTER JOIN句で結合させるというような処理が必要です。ただ、この例に限らず、JOIN句で意図せずにデータが増殖していたという事例は時々起きるので、JOIN句を使う場合は結合後のデータ件数を都度確認するようにしましょう。`count`を使って全体件数を確認する、また、特定のユーザIDやクッキーIDのログだけを抽出して確認するのがお薦めです。

# テーブル名、カラム名に騙されない
例えば、性別や生年月日などのユーザの属性情報を分析に使いたいという場合があったとします。そして、これらの属性情報が格納されていそうなテーブルを探したところ、`users`というテーブルに`sex`、`birthday`というカラムを発見。早速、この`users`というテーブルからユーザ毎の性別や生年月日を抽出したものの、一部のユーザ情報しか入っていなかった。よくよく調べると`users`というテーブルは現在は使われておらず、最新のユーザ情報は`users2`というテーブルに格納されていたという笑うに笑えない事例に遭遇することがあります。
他にも、商品名を分析に利用したく、`items`というテーブルの`name`というカラムのデータを抽出してきたものの何かがおかしい。詳しい人に訊くと、`name`は商品の説明文が入ったカラムで、商品名は`title`というカラムに入っていることが分かったというような事例もあります。
このような事例は時々見聞きするので、テーブル名やカラム名ですぐに飛びつかないようにして、念の為データの中身を確認するようにしましょう。例えば、

- 最近登録されたユーザやアイテムのデータがちゃんと格納されているのか確認する。
- 詳しそうな人、知っていそうな人に訊く。
    - Slackで専用チャネルを作って、そこで情報交換するのもあり
- 自分が知っているメタデータに関する情報は社内Wikiなどに積極的に書き残す。

などの対策を取ると良いと思います。
【手抜き】STM32の使い方まとめ 0.STM32のご説明

#前書き
自分で全てをまともに書く意味はないと察したので、
・１ブログ１テーマ
・相互リンクを作る
・素晴らしい他人の引用を張りつつ(ひどい)補足説明する
ことにしました。。。
よりよいプログラミングをサポートできれば…いいんだけど

#テーマ概要
ArduinoやRaspiの方々多いですけど、STMというやつもあるんだよー。
以上です。
ロボカッパーやNHKロボコンの方々も使ってる人まあまあいると思うので。
このマイコンの問題点はリファレンスがあまりよくないこと。。リファレンスあるんですけど多分それ見てもプログラムできないという。。
まあ、様々な方がブログ書いてるのでわからないことはあさってください。ねむいさんとか…

#今日の引用
@usashirouさんのQiitaです。

- [STM32 Nucleoって何？](https://qiita.com/usashirou/items/e66c77a02477f579cee7)

しばらくこの方の記事を引用しますね…

#引用の補足
個人的に、AVR(初期Arduinoに載っていたチップ)やPIC、H8よりは性能が良い（アバウトすぎ）と思っています。
最近はArduinoでもつよつよが載るらしいですね。。
###チップの型番
STMは非常に種類が多く混乱する人が多いのです。
たとえば、あるチップでは型番が**STM32F407VGT6**となります。
まず"**STM32**"のあと英数字二桁で大まかな分類があり、
**L0,L1,F0,F1,G1,F3,F2,F4,F7,H7**（後ろに来るほど高性能--主観）というグループ分けの中に、
さらに数字二桁(**07**)で型番分けされています。数字の大きさと性能は関係しているかもしれません（）
そして英字二桁(**VG**)はパッケージ（チップの形とピン数）を表し、最後の**T6**は動作温度ですね。気にしたことないですけど。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481835/84e8770b-e4d0-48d9-fab8-ad0caee3b7bb.png)
https://www.st.com/ja/microcontrollers-microprocessors/stm32-32-bit-arm-cortex-mcus.html

###Nucleoの種類
基板の形で３種類**Nucleo32,Nucleo64,Nucleo144**（この数字はマイコンチップのピン数なのですが）に大別されます。
実際の商品名としては載っているチップの型番ごとについてますね。
引用記事の画像を参考にしてください。
>初めて使うという人は、CortexM4のF4やL4のものを選びましょう。

ですね。あとUSBA-MiniBのケーブルも必要です。
パッケージの型紙はピン配置が読みやすいので*捨てないで*…
次の記事までPCにつながないでください。。ドライバが必要なので一応。

###stのサイトについて
読み込みが異常に遅いです。どうでもいいですけど。

#相互リンク(随時更新@2020/03/09)
**【手抜き】STM32の使い方まとめ**
（まだない記事は今後変更の可能性があります）

- [0.STM32のご説明](https://qiita.com/nabeya11/items/9ee076933983ed7ae3b6)
- [1.STM32CubeIDEの導入とLチカ](https://qiita.com/nabeya11/items/0859271c1307d88d6891)
- 2.GPIOでデジタル入力
- [3.STM32CubeIDEの日本語化](https://qiita.com/nabeya11/items/fb6e0c4fe3156e307f6a)
- 4.STM32CubeIDEでGit
- 5.標準タイマを使う
- 6.タイマ割り込みで等時間制御
- 7.PWM波形の出力
- 8.I2CのMemWrite/Read()
- 8.Encoderモードの使い方
- 9.UART~送信:DMAとprintf少数表示まで~
- 10.MCSDKでブラシレスモータを回す
- 11.RS485
- 12.CAN
- 13.STM32CubeIDEでデバッグ
- [番外. 「私、マクロを使えって言ったよね！？」](https://qiita.com/nabeya11/items/c901c5c0ccd61f9cc01a)
- [番外.STM32CubeIDEと日本語の文字化け](https://qiita.com/nabeya11/items/beac1586510d357bf911)
フリーWebSocketサーバーをAchexからWebsocket.inへ変更

[手元にサーバー不要でWebSocket Client間で通信できるフリーサーバー Achex, Websocket.in が便利そう - Qiita](https://qiita.com/khsk/items/113a2781881ac2e480c0)
を調査後、Achexを利用していたが、しらばくしてからしばしば接続がcloseされるようになった。

[デモページ](https://achex.ca/dev/general_testing.html)
でも動作が怪しいため、自動再接続を組むよりは乗り換えることにした。
今確認すると好調のようで一時的な不調だったとも思われるが、まる一日は不調だっため書き直してしまった。

というわけで
[WebSocket.in - The open and free WebSocket server for all.](https://www.websocket.in/)
との乗り換えというか比較になりますが、
WebSocket.inはかなり機能が貧弱。
基本的には立てたインスタンス全体へのstringエコーしか存在しません。
せめてもの機能としてAchexでのHubのようなルームがGETパラメーターとして付加できます。
`wss://connect.websocket.in/YOUR_CHANNEL_ID?room_id=YOUR_ROOM_ID`

* 単機能でAchexより柔軟性がなく
* Achexよりさらに盗聴されやすく
* 指定ユーザーにWhisperできないため接続全体に受信負荷がかかる

と、Achexにくらべ優位性はあまりありませんでした。
Achexが以後も安定を保つならばこちらのほうがよさそうです。

なお、Websocket.in単純なstringの送信しかできませんが、
JSONStringを送信すれば一応、指定ユーザーにだけ受信処理をさせるようなこともできます。
(当然その他のユーザーも受信はするので自分でなければ処理しない、という手間が必要になってきますが)

```js
const commentJson = {
  'to' : 'receiver',
  'msg': []
}

socket.send(JSON.stringify(commentJson));

// 受信側
socket.addEventListener('message', function (event) {
  console.log('message',event)
  const json = JSON.parse(event.data)
  console.log(json)
  if (json.to == 'receiver') {
    // 自分宛なので処理
  }
}
```

この処理はAchex時点で書いているはずなので、
Achexからの乗り換えではもともとのto指定の値を受信側で見る処理を加えることと、
Auth処理を外すだけで簡単なWS機能なら乗り換えることができました。
時間のかかるPythonスクリプトを定期実行させる

#環境
macOS version 10.14.6
Ubuntu 16.04 in AWS
Python 3.5.2
#前提
AWSのEC2インスタンスを使って、自動的にスクリプトを起動するcron jobを作りました。
本来は、
・AWS Lambda
・ECS Scheduled Tasks
等を使うのが得策だとは思いますが、

①今回実行するスクリプトが丸一日くらいかかる（Lambdaは１５分が限界との噂）
②手っ取り早く、安く済ませたい

との考えがあり、少しレガシーかもしれないですが、シンプルなcrontabを使用することにしました。
本当はDocker環境とかを構築したかったのですが、初心者で且つ時間の都合上、EC2に収まってしまいました。
より良い方法等あれば、ぜひ教えて頂ければと思っております。
cronの選定に関しては、下記などを参考にしました。
https://medium.com/better-programming/cron-job-patterns-in-aws-126fbf54a276

##1, EC2インスタンスに接続
インスタンスは作成済みとの前提で進めていきます。今回は上記の環境で動かしていきます。
ターミナルで、

```
$ ssh -i ~/directory/directory/sample.pem ubuntu@IPv4 パブリックIP
```

ssh接続でサーバーにログインします。
ubuntuの部分は、AMI（サーバーの種類？）によって変わるので、気をつけてください。
余談ですが、ファイル・フォルダのパスがわからない場合は、そのファイル・フォルダをターミナルにドラッグ＆ドロップするとフルパスが表示されるみたいです。当たり前すぎるかもしれないですが、初心者の私は割と重宝しています・・・

##2, Pythonをインストール
サーバーにPythonをインストールしていきます。Ubuntu環境なので、aptコマンドを使っていきます。
念の為、

```
$ sudo apt update
$ sudo apt upgrade
```

を実行しておきます。
<br>
以下でPythonをインストールしていきます。

```
$ sudo apt install python3 python3-pip python3-dev
```
最低限ここまではどの人も共通してインストールするのかなと思っております。
あとは、使うモジュール等によって必要なものがあると思うので、その都度インストールすればいいかと思いました。
今回私は後述するモジュールを使うために、以下のものもインストールしました。

```
$ sudo apt install libmysqlclient-dev libffi-dev libssl-dev build-essential
```
もしかしたら、いらないものも含まれてるかもしれません。

##3, モジュールをインストール
今回のスクリプトで使ったのは以下のモジュールだったので、サーバーで使えるようにインストールします。

```
$ pip3 install requests sqlalchemy selenium lxml paramiko eventlet mysqlclient
```

##4,crontabを編集する
EC2にはcron jobのための機能がもともと入ってるみたいなので、以下のコマンドを入力すると、cronに関する記述ができる編集画面に移行します。

```
$ crontab -e
```
気をつけないといけないのが、`$ crontab -r`とすると、全てのcrontabのデータが消えるみたいなので、設定してからは、気をつけないと苦労が水の泡になるそうです。私は毎回指差し確認しながら実行しています・・・。

余談ですが、初心者の私がビビったのは、編集画面をVimにしてしまったこと。泣きそうになりました。
nanoがなんだかんだわかりやすかったので、怖い方はnanoを使ったほうがいいとは思います。
editorは以下で後からでも変えれます。

```
$ select-editor
```
<br>
それではcrontabに記述していきますが、書き方はいろいろあるので、要件にあった内容を調べたほうがいいと思います。今回私は以下のようにしました。
`0 20 * * * python3 /insert-fullpath/sample.py >> /insert-fullpath/cron_log.txt 2>&1`
上記は「毎日20時にsample.pyを起動する。出力されたもの、さらにエラーが出た場合は予め作っておいたcron_log.txtに書き込んでください」という指示です。
とにかく、起動しているかわからず怖かったので実行結果がわかるように上記のようにしました。
ちなみに、保存した上記crontabのファイルは、ターミナルの指示に従って、何も操作せずに保存すると`/var/spool/cron/crontabs/bitnami/`に存在していました。

##5, タイムゾーンの設定
デフォルトだとサーバーはロンドン時間になってると思うので、タイムゾーンも確認しておきます。

```
$ timedatectl
```
上記で現行のタイムゾーンを確認

```
$ sudo timedatectl set-timezone America/Vancouver
```
これで、バンクーバー時間になると思います。

##おわりに
社内でブラウザテストのスクリプトを起動させるために、今回初心者ながらいろいろ試してみました。本当はLambdaやDockerなどの技術を使いたかったのですが、力及ばず。
よりよい方法やお気づきの点がありましたら、お声がけ頂けると大変嬉しいです。

今働かしていただいている会社のサービスも、ぜひ御覧ください！
[サッカー順位表 FootyStats](https://footystats.org/jp/)
ニフクラにCLIでSSH公開鍵をインポートする

毎度、ググっても出てこない小ネタを取り扱っております。
本記事は個人的な見解であり、筆者の所属するいかなる団体にも関係ございません。

ニフクラといえば、日本の国産クラウドとして頑張っている会社さんです。
今回は、CLIから(本当はGitLabパイプラインから)ニフクラサーバーのインスタンスを
起動するというスクリプトを書いていて、めっちゃはまった(恨み)のでそれを解消するために
記事を書いておこうと思います。

## 0. 発端

ニフクラさんの環境を使ってハンズオンセミナーをさせていただいております。
Kubernetes 実践入門ハンズオン - connpass
https://k8s-introduction.connpass.com/
当然、ハンズオンなので仮想マシンインスタンスを必要とするわけです。
1回目、2回目ぐらいまでは参加者30人分のインスタンスをえっこらえっこら立てていたわけですが、
さすがにもうしんどくなってきましたので自動化しようと重い腰を上げたわけです。

Ansibleで、とかとも考えたのですが、問題がありましてシェルスクリプトで実装しようと
しているのが事の発端でございます。これ以上迷える子羊が増えないように書いておきます。

## 1. 結論

コマンドは実行できる環境になっているとする
公開鍵をid_rsa.pubとする

```bash
$ nifty-import-keypair <任意6文字以上の鍵名> --request-method POST --public-key-material "$(base64 id_rsa.pub | tr -d '\n')"
KEYPAIR  <任意6文字以上の鍵名>  7d:52:14:86:7e:77:eb:74:19:85:55:0e:b9:87:00:35
```

で登録できました...。

## 2. 注意点
### 2-1. --request-method POST を指定

これはコマンドのエラーメッセージが出るとおりにPOSTにしてください。

### 2-2. --public-key-material の指定方法

クラウド CLI（nifty-import-keypair） | ニフクラ
https://pfs.nifcloud.com/api/cli/nifty-import-keypair.htm
には、`base64エンコードされた公開鍵の文字列を指定します。`と書いてあります。

これを見て
`「はあ、SSHの公開鍵の形式にはいくつかあるものな、BASE64形式にする必要があるのか」`
と思ってしまったのが迷走の始まりでした。

しかし、そんなことは**全くなく**通常のssh-keygenで出力されるOpenSSH形式をbase64でエンコード
するだけで良かったのです。

1の結論では、id_rsa.pubをbase64して改行コードを削除しています。

```
base64 id_rsa.pub | tr -d '\n'
```

### 2-3. 鍵名は6文字以上にする

6文字以上にしてください。

## 3. 泣き言

ただbase64にすればいいなんて、そんなこと思わないじゃないですか、
PEM形式にしたりいろいろやっちゃいましたよ(涙)
#Mysql2::Error: Can't connect to MySQL server onについて

#起こったこと

備忘録です。低レベルですが、同じエラーを起こしてしまった人のために。
MacOSのアプデを自動でしているため、再起動に入ってしまった。
アプデ後、bundle startをしてもうまく起動しない。
いつもならターミナルがbashからrubyに変わるのに跳ねられてしまう。
色々調べていると、次のエラー文がみられた。

#Mysql2::Error: Can't connect to MySQL server on なんちゃら

あんまり英語が得意ではないが、MysqlがCan't connectなので接続で来てないらしい。
さてここで重要なのは、僕が初心者すぎてMysqlなんぞやってレベルであること。

##とりあえずググってみた
<img width="1324" alt="スクリーンショット 2019-08-16 13.37.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453260/4bcbc3c8-9a4f-920e-4289-9b58a171460b.png">

#解決策は[ $mysql.server start ]

スクリーンショットの検索結果は、残念ながら解決策よりも高等な解決策を示されていた。
以下のURLを参考にしていただきたいです。
https://qiita.com/itooww/items/13055c8bb1d226ee5844

#原因は再起動によるMySQLの活動停止

当たり前だが、再起動とか電源切るとアプリケーションは止まる。
ただ、エンジニアになって自分がどういう物を使っているかをイメージできないことも多い。
バグだとか、壊れたわけではないが原因がわからないと解決の仕様が無い。。。

#こうならないための対策

MySQLの自動起動です。これでいちいち立ち上げなくてもよくなります！
https://qiita.com/rinkun/items/c1649bcbe9a79bf2b07e
bat_ショートカット先の実体コピー

#1.概要
実行ディレクトリ内に存在する.lnkのリンク先の実体を
実行ディレクトリにコピーするバッチ。
・リンク先がディレクトリならディレクトリごとコピーする。
・リンク先は実行ディレクトリはCドライブとしている(変更可能)。

#2.ソースコード

```
@echo off

rem ショートカットの実体をコピーするバッチ
::実行ディレクトリ内のリンクファイルの実体を
::実行ディレクトリにコピーします。

::lnkファイルの実体パスをtemp.txtに出力
type *.lnk|find "C:\"|find /v "/">temp.txt

::temp.txtのパスを読み出し、実行ディレクトリにコピー
:: ※フォルダの場合…フォルダごとコピーする
for /f "delims=" %%A in (temp.txt) do (
   if exist %%A\ (
      echo D | xcopy "%%A" "%~dp0\%%~nxA" /Y
   ) else (
      copy "%%A" "%~dp0" /Y
   )
)
::不要になったtemp.txtを削除
if exist "temp.txt" del temp.txt
pause

```

#3.出力結果
（略）
適当にショートカットを作って実行してみてください。

#4.出典
https://okwave.jp/qa/q4890627.html
[Python]実質二次元の三次元ndarrayから二次元要素を抽出

OpenCVのHoughLinesP( )関数の戻り値が三次元配列である事に気付いてから列を抽出するまでけっこうかなりすごく悩んだので覚え書きしておきます。

```Python:ハフ変換の戻り値　X（抜粋）
[[[249 138 400 138]]
 [[405 139 400  60]]
 [[404 230 404  61]]
 [[418 137 486 137]]]
```

目的は、ここからy軸の値（1, 3列目）だけ抽出すること。

```Python:抽出したい値
[[138 138]
 [139  60]
 [230  61]
 [137 137]]
```

【参考にさせてもらったURL】
[[Python]Numpyの参照、抽出、結合](https://qiita.com/supersaiakujin/items/d63c73bb7b5aac43898a)

…を参照して、X[:, [1, 3]]としてみた。

```
print X[:, [1, 3]]

#結果
index 1 is out of bounds for axis 1 with size 1
```

「**要素 1 は範囲外でござい**」エラー。
…までは理解できた。

```
print X[0][:, [1, 3]]

#結果
[[138 138]]
```

ここから混乱。
リストと配列の違いを飲み込めていなかったのが原因。

```Python:解決
X[:, 0][:, 1, 3]

#または
X[0, :][:, 1, 3]

#結果
[[138 138]
 [139  60]
 [230  61]
 [137 137]]
```

こう、まとめてみると何のことはないのだが、妙に行き詰まったのでした。
空階層（空次元？）でもあくまで配列として扱わないといけなかった、という話。
GCEでCloud NATを経由させるとSocketTimeoutException

##本記事の概要
下記記事にて構築したアプリケーションの運用中に発生した障害とその対応について記述します。
https://qiita.com/issei_0403/items/a69f42c85fb81e1efc62

##構成
外部API接続時にIP制限がかかっているため、CloudNATで出口IPを固定しつつ外部APIに接続しています。
外部APIは秒間リクエスト数に制限があります。
![Untitled Diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262530/c7a56c0e-2885-e325-59ee-de4c228f3568.png)

##障害の内容
- アプリケーションがリクエストを投げている行でconnect time outが発生し外部APIに届いていない🤔
- Stackdriver LoggingでCloud NATのログを見てみると、アプリケーション側で失敗したリクエストに紐付いていそうなCloud NATのログについて
allocation_statusが"dropped"になっている🤔

(つーか１週間前まで何事もなくうごいてたのになんで急に動かなくなったんだ😡)

##試したこと
####１．アプリケーションで使用しているOkHttpのタイムアウト時間を長めにとってみる
※下記記事参照
https://qiita.com/issei_0403/items/716fc73afb86142d4933

####１．の結果
Cloud NATのallocation_statusが"dropped"になる問題は解消。
しかし、外部APIへのリクエスト数が多すぎて怒られる😅

####2.リクエストを投げる前にsleepしてみる

```java
//　もろもろ省略
import java.util.concurrent.TimeUnit;
TimeUnit.MILLISECONDS.sleep(200);
```

####2.の結果
リクエスト制限以下にしたので、無事解消。


##続き(2019/08/22)
40リクエスト程度さばいたところで、突如2分以上待たされる事象が発生し再度Timeoutが発生しました。
自動でスケーリングするとのことでしたが、GCE上のアプリケーション(今回はバッチ処理)をCloud NATを経由させると極端に長い待ちが突然発生してうまく動かないことがあるみたいです。
GCEに固定IPを割り当て、Cloud NATを経由させないことにしました。
結果Cloud NATを経由させた時と比較にならないレベルで爆速で動きました・・・。
【Kotlin】Enumに複数のパラメータを持たせる

# コード
## enum classの定義
```kotlin
enum class Family(val firstName: String, val birthplace: String, val age: Int) {
    TARO("Taro", "tokyo", 30),
    HANAKO("Hanako", "hokkaido", 25)
}
```

* `val`としてパラメータを定義する
* `name`というパラメータ名は使えない（スーパークラスであるEnumのメンバーとして定義されているため）

## 呼び出し
```kotlin
val name = Family.TARO.firstName // "Taro"
val age = Family.HANAKO.age // 25
val birthplace = Family.HANAKO.birthplace // "hokkaido"
```

# 参考
[Kotlin enum with multiple “parameter” - Stack Overflow](https://stackoverflow.com/questions/53160024/kotlin-enum-with-multiple-parameter)
音が鳴るタイマーをつくってみた

思ったより時間かかりました。

[https://soundtimer.herokuapp.com/](https://soundtimer.herokuapp.com/)

```index.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <link rel="stylesheet" href="css/styles.css">
  <title>Sound Timer</title>
</head>
<body>
    <audio id="music">
      <source src="js/alarm.mp3" type="audio/mp3">
    </audio>
    <div id="timer">
        00:00
    </div>

  <form name="minForm" id="minForm">
    <input type="text" name="work_minutes" placeholder="minute">
    <!-- <input type="text" name="break_minutes" placeholder="Break"> -->
  </form>

  <button id="start">start</button>
  <!-- <button id="stop">stop</button>
  <button id="reset">reset</button> -->



  <script src="js/main.js"></script>
</body>
</html>

```

```main.js
{
  const displayTimer = document.getElementById('timer');
  const minForm = document.getElementById('minForm');
  const start = document.getElementById('start');
  const stop = document.getElementById('stop');
  const reset = document.getElementById('reset');
  const music = document.getElementById('music');

  let countdown;
  let state = "work";

  var audio = document.createElement('audio');
  console.log(audio);
  audio.id = 'sound';
  audio.src = 'js/alarm.mp3';
  

  function timer(seconds) {
    let s = seconds;
    const now = Date.now();
    const then = now + seconds * 1000;
    displayTimeLeft(seconds);

    countdown = setInterval(() => {
      const secondsLeft = Math.round((then - Date.now()) / 1000);
      // check it we should stop it!
      if(secondsLeft <= 0) {
        clearInterval(countdown);
        audio.play();
      }

      //display it
      displayTimeLeft(secondsLeft);
    }, 1000);

  }

  function displayTimeLeft(seconds) {
    const m = Math.floor(seconds / 60);
    const remainderSeconds = seconds % 60;
    const display = `${String(m).padStart(2, '0')}:${String(remainderSeconds).padStart(2, '0')}`;
    displayTimer.textContent = display;
  }
  

  start.addEventListener('click', () => {
    const mins = minForm.work_minutes.value;
    timer(mins * 60);
    minForm.reset();
  });

}
```
Macでpythonのarucoライブラリを動かす

# 目的
Macでpythonのaruroライブラリを動かした際の備忘録です。

# 準備

関連ライブラリのインストール

```
$ pip install opencv-python
$ pip install opencv-contrib-python
$ pip install pyzbar
$ pip install pillow
$ brew install zbar
(windowsの場合はyum install zbar)
```

# コード

下記記事のコードを使わせて頂きます。

> [【Pythonでプログラミング】arucoライブラリを使ってARマーカを認識してみた](http://okatenari.com/2017/11/28/python-ar/)
> [ArUco マーカーの検出](https://qiita.com/sugman_a/items/1af4664521decebace8b)

# テスト

▪️ARマーカー

```
python sample.py
```

![33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/344880/c5812c3e-8e5a-0cab-a1fe-bfe337ad3326.png)

<img width="240" alt="スクリーンショット 2019-07-13 18.01.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/344880/f6bf2122-8533-8810-3ead-4262c235f0c8.png">

▪️QRコード

```
python qr.py
b'http://icon-qr.quel.jp/00000071298450'
```

<img width="240" alt="スクリーンショット 2019-07-13 18.20.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/344880/228083e8-3641-9830-bb0f-1aa036aeb449.png">

ARマーカ/QRコード共に読み取れました。

# CodingError対策

```
$ python sample2.py 
Traceback (most recent call last):
  File "sample2.py", line 2, in <module>
    aruco = cv2.aruco
AttributeError: module 'cv2.cv2' has no attribute 'aruco'
```

arucoライブラリインストールが必要

```
$ pip install opencv-contrib-python
```

--

```
$ python sample.py Reader
Traceback (most recent call last):
  File "sample.py", line 51, in <module>
    arReader()
  File "sample.py", line 32, in arReader
    imghalf = cv2.resize(frame,(halfWidth,halfHeight))
TypeError: integer argument expected, got float
```

resizeの引数はintegerである必要がある。round()関数で四捨五入する。

```b:sample.py
halfWidth = round( halfWidth )
halfHeight = round( halfHeight )
```

--

```
$ python qr.py 
Traceback (most recent call last):
  File "qr.py", line 3, in <module>
    from pyzbar.pyzbar import decode
ModuleNotFoundError: No module named 'pyzbar'
```

pyzbarをインストールする必要があります

```
pip install pyzbar
pip install pillow
brew install zbar
(windowsの場合はyum install zbar)
```

# 参考
[【Pythonでプログラミング】arucoライブラリを使ってARマーカを認識してみた](http://okatenari.com/2017/11/28/python-ar/)
[ArUco マーカーの検出](https://qiita.com/sugman_a/items/1af4664521decebace8b)
[Pythonで画像ファイルからQRコードを読み込む (MacOS)](https://qiita.com/kiyota-yoji/items/7fe134a64177ed708fdd)
[Pythonでバーコードを読み込む](https://qiita.com/orengepy/items/1d405762813846765ec1)
[Python3でQRコードを読み込みたかった](http://uryoya.hatenablog.com/entry/2017/06/17/155503)
DirectX::SpriteBatchで画像を簡単に表示してみる(DirectX11)

DirectXには画像を簡単に表示することが出来るSpriteBatchというクラスがあります。このクラスを使えば、面倒な頂点シェーダーやピクセルシェーダーを用意する必要が無くなるのです！
# 下準備
まず、表示したい画像をVisualStudioに追加します。
![g.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368850/0527ddc0-5e0c-8b45-4026-044f65dd8b5d.png)
右クリック→プロパティで項目の種類をImage Content Pipelineに設定します。
![pro.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368850/eeca5e21-a36d-ba44-dbf6-09d862073413.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368850/7fe7f44a-937f-d750-3119-e29d24bc123e.png)
これでビルドした時に、画像ファイルから.ddsというファイルが出来るようになります。この.ddsファイルを読み込んで画像を表示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368850/6f4df26e-2206-8284-ed3e-a43476bb8f6b.png)
プロパティページから.ddsファイルの出力先を変更することが出来ます。画像に関してはこれでOKです。
# 描画
まずは初期化や画像の読み込みをします。

```C++
//変数
ID3D11Device* device     //構築済みとする
ID3D11DeviceContext* deviceContext     //構築済みとする
std::unique_ptr<DirectX::SpriteBatch> spriteBatch;     //これが肝
ID3D11ShaderResourceView* shaderResourceView     //読み込んだ画像ファイルの保存先

//spriteBatchの初期化
{
    spriteBatch = std::make_unique<DirectX::SpriteBatch>(deviceContext);
}

//画像の読み込み
{
    DirectX::CreateDDSTextureFromFile(
    device,           //デバイス
    L"Assets/title.dds",    //読み込む画像ファイルの場所と名前
    nullptr,                 //nullptrでいい 
    &shaderResourceView);     //ここに読み込んだファイルの情報が格納されます
}
//
```
描画していきます。

```C++
//以下ループ
{
    //Drawの前に呼び出す
    spriteBatch.get()->Begin();

    //Draw     
    spriteBatch.get()->Draw(
    shaderResourceView,     //読み込んだ画像ファイル
    DirectX::XMFLOAT2(0.0f,0.0f)     //画像の座標
    );

    //Drawの後に呼び出す
    spriteBatch.get()->End();
}
```
これで描画出来る...はずです。
実際に画像が描画されるのは、SpriteBatchのEnd関数が呼ばれたタイミングになります。

尚、こんな感じでBegin()とEndの間に何度もDraw関数を呼び出すことが出来ます。

```C++
{
    spriteBatch.get()->Begin();

    spriteBatch.get()->Draw(...);
    spriteBatch.get()->Draw(...);
    spriteBatch.get()->Draw(...);

    spriteBatch.get()->End();
}
```
Vue.js の style アトリビュートにコメントが書けない、、、いや、書けるのだけど構文がちょっと謎。

# Vue.js の styleアトリビュートにコメントが書けない、、、いや書けるのだけど、構文がちょっと謎。

はじめに。[Vue.js]には大変お世話になっております。仕事でも、プライペートでも、ガリガリ使わせていただいております。目からウロコが落ち、生産性も上がり、たいへん感謝しております。

## 誰のための記事ですか？

[Vue.js]をガリガリ使いはじめてからしばらくたって、「あれ？この動き、なんか変？」って思った人向け。しかも、ピンポイントで [style]アトリビュートにコメントを書いた時の話。

なので、[Vue.js]を使っていない人には無関係な話。さらに、[style]アトリビュートを使わない！もしくは[CSS]に書くべきだろ！ってひとにも無関係な話。

[Vue.js]:https://jp.vuejs.org/index.html

[CSS]:https://ja.wikipedia.org/wiki/Cascading_Style_Sheets

[style]:https://www.w3schools.com/tags/att_global_style.asp

## [style]アトリビュートにコメントを書いちゃう

まぁ、「[style] に書かなくても [CSS] に記述すれば、いいじゃん」って言い分も理解できます。そういう考えもある程度理解はできるので、そういうひとはここでは対象にしていないです。

ここでは、「なぜ[CSS]に分けて書くの？？遠いでしょ。情報はなるべく近くにあるべきじゃない？[style]アトリビュートに書こうよ」ってなひとが対象です。

、、、で、話をすすめると。
style には `/* ... */` 記法でコメントが記述できると知られています。

参考：CSS でのコメントの書き方はこんな感じ↓
https://developer.mozilla.org/ja/docs/Web/CSS/Comments

参考：CSSのドラフト↓
https://drafts.csswg.org/css-style-attr/

でも、[Vue.js] を使っていると、ときどきコメントがうまく効いていないことがある。

[Vue.js] でも [style]内でのコメントはサポートされているようだが、構文の解釈が若干異なるもよう。

## [Vue.js] の style のコメントの解釈が謎なコメントはこちら


```html
<div style='padding: 10px; background-color: hsl(0, 20%, 75%); /* comment */'>{{ message }}</div>
<div style='padding: 10px; /* comment */ background-color: hsl(0, 20%, 70%);'>{{ message }}</div>
<div style='padding: 10px /* comment */; background-color: hsl(0, 20%, 65%);'>{{ message }}</div>
```
style アトリビュート内のコメントの位置がちょっと違うだけなのですが。


## CodePen で実行してみると

<p class="codepen" data-height="512" data-theme-id="0" data-default-tab="html,result" data-user="yamazaki3104" data-slug-hash="wvwGNRq" style="height: 512px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Vue.js style test">
  <span>See the Pen <a href="https://codepen.io/yamazaki3104/pen/wvwGNRq/">
  Vue.js style test</a> by yamazaki.3104 (<a href="https://codepen.io/yamazaki3104">@yamazaki3104</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

コメントの記述があっても 8行目の background-color は効いているが、[Vue.js] を通した 15行目の background-color の記述は無視されてしまっている。

![スクリーンショット 2019-08-18 15.43.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107592/c16e31b9-4c51-f39a-8096-a031e3da8427.png)
（👆こんな感じに背景色が効かず白くなってしまう。）


/* */ の後ろに ; を書けば希望する動作になるが、、、「コメントってどこでも書けるんじゃないの？？」って思っているひとは多いと思う。

## 教えてプロなひと

コメントの正しい書き方をご存知なかた。おられましたら、このエントリにコメントをいただけますと幸いです。迷える子羊（おっさん）に愛の手を。
ROSを始めよう　その９

# 前回の内容
[その８](https://qiita.com/hagi-suke/items/5067420f747852be77a3)

# 今回の内容
今回はArduinoなどによる自作ロボットの動かし方を見ていきましょう。

# マイコンをROSを動かすrosserial
## Arduinoとrosserialの準備
`$ sudo apt-get install ros-kinetic-rosserial ros-kinetic-rosserial-arduino`でインストールします。
また、`$ sudo apt-get install arduino`でArduinoをインストールして`$ arduino`で立ち上げます。
そして、以下のようにインストールをしたら準備完了です。

```
$ cd ~/sketchbook/libraries
$ rosrun rosserial_arduino make_libraries.py .
```

## プログラムでLチカさせる
まずは以下のプログラムをArduinoに書き込みます。

```arduino_blink.ino
#include <ros.h>
#include <std_msgs/Bool.h>
#include <std_msgs/String.h>

ros::NodeHandle node;
std_msgs::String chat;
ros::Publisher pub("arduino", &chat);

void ledCallback(const std_msgs::Bool &is_led_on){
  if (is_led_on.data) {
    digitalWrite(13, HIGH);
    chat.data = "led on!";
  } else {
    digitalWrite(13, LOW);
    chat.data = "led off!";
  }
  pub.publish(&chat);
}

ros::Subscriber<std_msgs::Bool> sub("led", &ledCallback);

void setup()
{
  pinMode(13, OUTPUT);
  node.initNode();
  node.subscribe(sub);
  node.advertise(pub);
}

void loop()
{
  node.spinOnce();
  delay(1);
}
```
次に`$ roscore`を立ち上げ、`$ rosrun rosserial_python serial_node.py _port:=/dev/ttyUSB0`と実行します。(Arduinoが認識されているのが、/dev/ttyACM0ならそのように書きましょう。)

もし書き込み権限がなければ、`$ sudo chmod 777 /dev/ttyUSB0`と権限を与えましょう。

`$ rostopic echo /arduino`でArduinoから送られてくるMessageを確認できます。
`$ rostopic pub /led std_msgs/Bool true`や`$ rostopic pub /led std_msgs/Bool false`でTopic /ledを発行して、LED変化とMessageを確認できます。

# サーボモーターの利用
`$ sudo apt-get install ros-kinetic-dynamixel-motor`でDynamixelというサーボモーターをROSで制御できるようになります。

# まとめ
今回はArduinoなどによる自作ロボットの動かし方を見ていきました。
これにてROSの勉強はひとまず終わりです。あとは実践あるのみ！色々作っていきましょう。
ROSを始めよう　その８

# 前回の内容
[その７](https://qiita.com/hagi-suke/items/8f94235d85af8d4dc6b8)

# 今回の内容
今回は座標変換ツールtfなどを見ていきましょう。
参考：http://wiki.ros.org/ja/tf/Tutorials
　　　http://wiki.ros.org/ja/urdf/Tutorials/Create%20your%20own%20urdf%20file
　　　http://wiki.ros.org/ja/pcl/Tutorials

# 座標変換ツールtf
ロボットアームなどを動かす時には、関節角度から手先の位置を求める順運動学の問題などを解く必要があります。tfはこれを手助けしてくれるツールです。
## PR2を動かしてみる
`$roslaunch pr2_gazebo pr2_empty_world.launch`でシミュレーターを立ち上げる。
次に動かす際に便利なライブラリを取ってきます。(まだリリースされていないソフトです。)

```
$ cd ~/catkin_ws/src
$ git clone https://github.com/OTL/ez_utils.git
$ cd ~/catkin_ws
$ catkin_make
```
そして`$ rosrun rviz rviz`とrvizを立ち上げて、Robot Modelを表示します。(表示されない場合、画面左のGlobal Optionsをbase_linkにセットしましょう。)
さらに、TFをAddして表示しましょう。(画面左のTFのFramesのAll Enabledをクリックして表示を外して見やすくしましょう。)
TFのhead_plate_frameとl_gripper_led_frameにチェックを入れると、PR2の頭と左手先のフレームが表示されます。

`$ rosrun tf tf_echo /head_plate_frame /l_gripper_led_frame`と打つと、/head_plate_frameから見た/l_gripper_led_frameの座標系、すなわち相対位置を得られます。

## 常に頭が左手先を見続けるプログラムを作ってみる

```look_hand.py
#!/usr/bin/env python
import rospy
import tf2_ros
from ez_utils.ez_joints import JointsServer

if __name__ == '__main__':
    rospy.init_node('pr2_look_left_hand')
    # TFのデータを蓄えるバッファを作成
    tf_buffer = tf2_ros.Buffer()
    # TransformListenerを作成
    tf_listener = tf2_ros.TransformListener(tf_buffer)
    # 頭と左腕をTopicで動かせる状態にする
    head = JointsServer('/head_traj_controller')
    left_arm = JointsServer('/l_arm_controller')
    # 首の角度の初期化
    yaw_angle = 0.0
    pitch_angle = 0.0
    rate = rospy.Rate(10.0)
    while not rospy.is_shutdown():
        try:
            # frame間の相対関係を取得
            trans = tf_buffer.lookup_transform('head_plate_frame',
                                               'l_gripper_led_frame',
                                               rospy.Time())
            # 首の角度を決定
            yaw_angle = trans.transform.translation.y / 1.0
            pitch_angle = -trans.transform.translation.z / 1.0
            print trans.transform.translation
            # 角度をロボットに送信
            head.set_positions([yaw_angle, pitch_angle])
        except (tf2_ros.LookupException, tf2_ros.ConnectivityException, 
                tf2_ros.ExtrapolationException):
            rospy.logwarn('tf not found')
        rate.sleep()
```
chmodで実行可能にし、`$ rosrun ros_beginner look_hand.py`で実行しましょう。

`rosrun rqt_ez_publisher rqt_ez_publisher`でrqt_ez_publisherを立ち上げ、左手先を動かしてみましょう。
Topicとして/l_arm_controller/follow_positionを選択して追加し、スライダーで動かすことができます。

# その他の基本的なライブラリ
## ロボット定義フォーマットURDF
ROSで自作ロボットを使う場合などに、ロボットの見た目やモーターの配置、センサーの配置を定義するファイルが必要になります。これがURDFです。
参考：[http://wiki.ros.org/urdf](http://wiki.ros.org/urdf)

## 3次元点群処理PointCloud Library
3次元点群を扱った認識プログラムを書く際に縁なライブラリとしてpcl_rosがあります。
参考：[http://wiki.ros.org/pcl_ros](http://wiki.ros.org/pcl_ros)

## InteractiveMarkers
rvizを使って入力をするためのツールです。
参考：[http://wiki.ros.org/interactive_markers](http://wiki.ros.org/interactive_markers)

# まとめ
今回は座標変換ツールtfなどを見ていきました。
次回は、Arduinoなどによる自作ロボットの動かし方を見ていきましょう。

[その９](https://qiita.com/hagi-suke/items/ea88dc7eaac48fd90d09)
[Laravel 5.8] トランザクションのネストとカウント

# コミット

ネストされたDB::commit()は無視され、最も浅いDB::commit()でコミットされます。

以下の例では、DBにユーザー2人が作成されるのは、`t1()`のDB::commit()実行時です。
`t２()`内のDB::commit()では、DBにユーザーは誰も作成されていません。

```php
function t1()
{
    DB::beginTransaction();
    User::create(['id' => 1]);
    t2();
    sleep(10);
    DB::commit(); // ここでコミットされる
}

function t2()
{
    DB::beginTransaction();
    User::create(['id' => 2]);
    DB::commit(); // ここではコミットされない
}

t1();
```

sleep(10)実行中に、DBで`select * from users;`することで、コミットされていないことを確認できます。

## Laravelはトランザクションのカウントを取っている

トランザクションのカウント(`$this->transactions`)を取り、そのカウントが1の時のみコミットを実行しているようです。
カウントはトランザクション開始するごとに増え、コミットするごとに減っています。

```php:vendor/laravel/framework/src/Illuminate/Database/Concerns/ManagesTransactions.php
public function beginTransaction()
{
    $this->createTransaction();

    $this->transactions++;

    $this->fireConnectionEvent('beganTransaction');
}

public function commit()
{
    if ($this->transactions == 1) {
        $this->getPdo()->commit();
    }

    $this->transactions = max(0, $this->transactions - 1);

    $this->fireConnectionEvent('committed');
}
```

ちなみに2回目以降のトランザクション開始はセーブポイント作成になるようです。
参考：https://github.com/laravel/framework/blob/5.8/src/Illuminate/Database/Concerns/ManagesTransactions.php

## DB::commit()し忘れると

トランザクションのカウントは`DB::beginTransaction()`するごとに増えていきますので、１つ忘れると全てのトランザクションがコミットされません。
シンプルな例ですが、以下はDBにユーザーは誰も作成されません。

```php
DB::beginTransaction();
User::create(['id' => 1]);
// DB::commit(); // コミット忘れた

DB::beginTransaction();
User::create(['id' => 2]);
DB::commit();
```

# ロールバック

`DB::rollBack()`した時もトランザクションのカウントが1つ減ります。また2回目以降の`DB::beginTransaction()`はセーブポイント作成になります。
よって以下の例は、id１のユーザーのみ作成されます。

```php
DB::beginTransaction();
User::create(['id' => 1]);

DB::beginTransaction();
User::create(['id' => 2]);

DB::rollBack();
DB::commit();
```

以下の例では、id1のユーザーのみDBに作成されます。
`t2()`で例外がスローされていますが握りつぶしているため、`t2()`はロールバック、`t1()`はコミットという結果になっています。

```php
function t1()
{
    try {
        DB::beginTransaction();
        User::create(['id' => 1]);
        t2();
        DB::commit();
    } catch (Exception $e) {
        DB::rollBack();
    }
}

function t2()
{
    try {
        DB::beginTransaction();
        User::create(['id' => 2]);
        throw new Exception; // 例外発生
        DB::commit();
    } catch (Exception $e) {
        DB::rollBack();
        // ここでthrow $eせず、例外を握りつぶしている
    }
}

t1();
```

例外を握り潰さないようにすると、全てロールバックされます。

```php
// id1もid2も作成されない
\DB::transaction(function () {
    User::create(['id' => 1]);
    \DB::transaction(function () {
        User::create(['id' => 2]);
        throw new Exception;
    });
});
```
【備忘録】Rails5でモデル名を変更する方法

##前提条件
OS:Mac OS X
Rails:5.2.3
groupモデルをroomモデルに変更します。

##モデル名の変更方法
最初に結論から。
そのあとそれぞれのコマンドの解説をしています。
※置換で一気に変更する際は、migrationファイルなど変更したくないファイルには気をつけてください。

####1. 変更するモデルに対応するDBのテーブル名を変更

```ruby:20190815230119_rename_groups.rb
  def change
    # :groupsが変更前
    rename_table :groups, :rooms
  end
```
変更内容をDBに反映

```ruby:ターミナル
   $ rails db:migrate
```

####2.モデルに関連するファイル名を全て変更
```ruby:ターミナル
   # find 対象ディレクトリ | xargs rename -s 変更前のファイル名 変更後のファイル名
   $ find ./ | xargs rename -s group room
   $ find ./ | xargs rename -s Group Room
```
■ 実行結果の例 ■
groups_controller.rb
　　　　↓
rooms_controller.rb

####3.モデルが使用されてるファイルの中身を全て変更
```ruby:ターミナル
   # find 対象ディレクトリ -name "検索する文字列" | LC_ALL=C xargs sed -i -e "s/変換前/変換後/g"
   $ find ./ -name "*room*" | LC_ALL=C xargs sed -i -e "s/group/room/g"
   $ find ./ -name "*room*" | LC_ALL=C xargs sed -i -e "s/Group/Room/g"
```
■ 実行結果の例 ■
class Admin::GroupsController < ApplicationController
　　　　　　　　　　　↓
class Admin::RoomsController < ApplicationController

####4.バックアップとしてできたファイルを削除
なぜかファイル名の末尾に-eとつくバックアップのファイルが生成されたため削除する。

```ruby:ターミナル
   # find 対象ディレクトリ -name "検索する文字列" | xargs rm
   $ find ./ -name "*.*-e" | xargs rm
```
■ 実行結果 ■
下記のようなファイル名の末尾に-eとつくファイルが削除された。
groups_controller.rb-e

##使用したコマンドの解説

####findコマンド
ファイルやディレクトリを検索できる。

| オプション        |コマンドの説明                    |
|:--------------:|:-------------------------:|
| -name          |  ファイル名を指定して検索できる  | 

####xargsコマンド
前に実行したコマンドの結果を引き継げる。

```ruby:ターミナル
   # find 対象ディレクトリ | xargs rename -s 変更前のファイル名 変更後のファイル名
   $ find ./ | xargs rename -s group room
```

上記の例だと、「find ./」で自分がいる階層のファイルとディレクトリを検索している。
xargsを使ってその検索結果を引き継ぎ、引き継いだ検索結果の中からファイル名がgroupの
ものをroomに変更している。

####sedコマンド
ファイルの中身のテキストを置換できる。

| オプション        |コマンドの説明                    |
|:--------------:|:-------------------------:|
| -i          |  ファイルを上書きする  | 
| s          |  正規表現で置換処理をする  | 
| g          |  マッチした全ての文字列を置換する  | 
-eコマンドはちょっとよくわかんない。
ご存知の方、ご教授いただけると助かります。


####LC_ALL=C
出力する言語や時刻などのフォーマットを設定する。
LC_ALL=Cはデフォルトの言語(英語)で出力される。

デフォルトの言語を日本語にしているせいかこれつけないと**illegal byte sequence**
っていうエラーがでるからつけてます。

##終わりに
モデル名の変更に時間がかかったので自分用のメモとしてこの記事を書きました。
皆様のモデル名の変更するときの参考になれば幸いです。

なぜバックアップのファイルが出力されたのか謎。
GKEのインスタンスにログインするときのコマンドメモ

すぐ忘れるのでメモ
例ではcloud composerのworkerインスタンスにログインしています

# ログインするクラスターを設定
## 現在のコンテキストを確認
kubectlの現在のコンテキストがログインしようとしているインスタンスが属するクラスターか確認する
→合っていれば「podの確認」へ

```
kubectl config current-context
```

## GKEに作られているクラスターを一覧表示
```
gcloud container clusters list
```

## クラスターの登録(コンテキストも自動で切り替わる)
gcloudコマンドなので認証されているgcloudユーザの権限でアクセスされる

```
gcloud container clusters get-credentials 上記で確認したクラスター名 --zone アベイラビリティゾーン
```
アベイラビリティゾーンの例：us-central1-f

# podの確認
defaultネームスペース以外のpodも表示する

```
kubectl get pods --all-namespaces --sort-by=.metadata.creationTimestamp
```


# podに入る
```
kubectl exec -it -n ネームスペース pod名 bash
```
ネームスペースの例：composer-1-7-2-airflow-1-10-1-94fd936d
pod名の例：airflow-worker-84f76c4b96-dl9c4