OmniAICreator/Qiita-1.07M huggingface dataset:
Pythonプログラムを追跡する

# やったこと
Pythonでメソッドの流れや実行の順番などを確かめた
Python文の実行のトレースと追跡

呼び出し元/呼び出し先　の関係の出力などができた
# コマンド
関数の呼び出しの関係性だけなら
`python -m trace -T {Program}.py`


```shell:
python -m trace {OPTION} {PROGRAM}.py
````

# 補足
色々なオプションがあり、今後使いそうなものだけピックアップ

|a|a|a|
|---|---|---|
|-c|--count|各文が何回実行されたのかをファイルを作成|
|-C|--coverdir|レポートファイルを保存するディレクトリを指定|
|-t|--trace|実行された通りに行を表示|
|-l|--listfuncs|実行された関数の表示|
|-T|--trackcalls|呼び出しの関係性の表示|

まだまだ他にもオプションはあるので、より詳しく確認する場合は
参考ページへ



# 参考ページ
https://docs.python.org/ja/3/library/trace.html#module-trace
CakePHPインストール時に「the requested PHP extension intl is missing from your system.」が発生

composerを使ってcakephp3をインストールしようとしたら、表題の様なエラーが発生したため、対処方法をメモ。

# 原因
「phpの拡張の｢intl｣がインストールされていないよ」的な感じ。

# 対処方法
下記のコマンドを実行して必要な拡張機能をインストール

```
$ sudo yum --enablerepo=remi,remi-php7.2 update
$ sudo yum --enablerepo=remi,remi-php7.2 install php72-php-intl
```

上記のコマンドを実行後、改めてCakePHPをインストール

# CakePHPインストール

```
$ composer create-project --prefer-dist cakephp/app samplecake
```

# 結果

やっとCakePHPのインストールが成功しました。

Laravelのインストールが正常にできても、CakePHPのインストール時には上記のようなエラーが発生する時があるようです。
Jupyterからスクリプトを実行して加工する

[前回](https://qiita.com/driller/items/8c8a0b52a369edfd80a8)の記事でコメントをいただいたので、Jupyterからスクリプトを実行する方法を紹介します。
あなたのシェル芸がJupyterを使うことで、さらに輝きます。 :star2:

セルマジック `%%script` を用いると、引数に渡したスクリプトを実行します。例えば、 `%%script python3.7` であれば、Python3.7を実行し、 `%%script bash` であればbashを実行します。スクリプトの内容はセルに直接記入します。

試しにbashを実行してみます。

```bash
%%script bash

for i in 1 2 3 ; do
  echo $i
done
```

```
1
2
3
```

Jupyterのセルに書いたbashが実行できました。Jupyterで実行する利点として、結果を加工したり可視化できる点が挙げられます。

例として、プロセス数を取得するスクリプトを実行して、結果をpandasで可視化してみます。

```bash
%%script bash --out bash_out

echo "date,procs"
for i in `seq 10` ; do
  echo "`date +%Y-%m-%d-%H:%M:%S`,`ps -ef | grep -cv grep`"
  sleep 5
done
```

`--out` オプションに渡した名前で、Pythonのオブジェクトに格納できます。

```python
print(bash_out)
```

```
date,procs
2019-12-06-10:49:21,337
2019-12-06-10:49:26,340
2019-12-06-10:49:31,340
2019-12-06-10:49:36,342
2019-12-06-10:49:41,340
2019-12-06-10:49:46,341
2019-12-06-10:49:51,344
2019-12-06-10:49:56,343
2019-12-06-10:50:01,342
2019-12-06-10:50:06,341
```

これをpandasのDataFrameに読み込んでみます。

```python
from io import StringIO
import pandas as pd

df = pd.read_csv(StringIO(bash_out), index_col=["date"], parse_dates=["date"])
print(df)
```

```
                     procs
date                      
2019-12-06 10:49:21    337
2019-12-06 10:49:26    340
2019-12-06 10:49:31    340
2019-12-06 10:49:36    342
2019-12-06 10:49:41    340
2019-12-06 10:49:46    341
2019-12-06 10:49:51    344
2019-12-06 10:49:56    343
2019-12-06 10:50:01    342
2019-12-06 10:50:06    341
```

`plot`メソッドでさくっと可視化します。

```python
%matplotlib inline
df.plot()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22023/415b595b-c95e-1d63-14f2-fb578ba4193e.png)

このように、Jupyterでは任意のスクリプトを実行でき、結果をPythonのオブジェクトで処理できます。よいJupyterライフを！
北海道でRPAを盛り上げたい！

## ご挨拶

地方IT勉強会 Advent Calendar2019に参加しています。

[地方IT勉強会 Advent Calendar](https://adventar.org/calendars/4605)

はじめまして。
Λ（らむだ）です。
北海道の製造業の会社でRPA推進をしています。
今回は北海道でRPAを盛り上げたいという内容で書きます。

## 私がRPAをはじめた当時

私がRPAと初めて出会ったのは2018年10月でした。
当時はRPAに関する情報が全然入手できない状況でした。
（本もないし、インターネットで検索してもほとんど情報が出てこない）
さらに追い打ちをかけるように、北海道では以下がありませんでした。

1.　セミナー（有料・無料問わず）
2.　勉強会
3.　RPAについて話せる場所（コミュニティ）

とはいえ、RPAを勉強して習得しなければ会社は待ってくれません。
そこで以下を実行しました。

1.　Twitterで情報収集
2.　本州のセミナー・勉強会の動画を観る
3.　出張（上長に頼みこんで）で本州のイベントに参加

とても苦労しましたし、勉強したくてもできないもどかしさで日々悩んで
いました。

## RPACommunityとの出会い

Twitterと、情報収集で観ていた動画でRPACommunityを知りました。

[RPACommunity](https://rpacommunity.connpass.com/)

RPACommunityは日本で唯一、最大のRPAユーザーコミュニティです。
当時、北海道には支部は無かったので、「これは北海道に支部を立ち上げる
しかない」と意を決していたところ、2019年5月にRPACommunityファウンダー
のチャラ電Mitzさんと出張で参加した本州のイベント会場でお会いする機会が
あり、北海道では本州と比較しRPAの情報が入手しにくいこと、北海道には
私と同じように困っている人がいるはずだとの想いを伝えました。
その後立上げ準備を開始しvol.01を9月10日に開催することができました。

[RPA勉強＆LT会！RPALT札幌 vol.01](https://rpacommunity.connpass.com/event/142706/)

定員30名のところ一時キャンセル待ちが出るほどの申し込みがあり大好評で終えることができました。
この度vol.02を12/6にさっぽろテレビ塔で行います。

[RPA勉強＆LT会！RPALT札幌 vol.02](https://rpacommunity.connpass.com/event/156158/)

さらに、熱い開催要望を受けまして地元である苫小牧・千歳でも新しい支部を立ち上げました。

[RPA勉強＆LT会！RPALT苫小牧・千歳 vol.01](https://rpacommunity.connpass.com/event/156533/)

さらにさらに、**北見支部**も立上げが決まりました。

道内各地にRPAの潮流を起こしていきたいと思います。

## 最後に

RPAは大企業での普及が進んでいますが、中小企業にも必ず必要となる技術です。
1人でも多くの方にRPAを知ってもらい、北海道にもRPAによる業務効率化の波を広げていきたい、
そして働き方改革につなげていきたいと考えています。
[BluePrism]Collectionの重複行を削除するにはどうしたらいいか（まだ悩み中なので誰か教えてください）

#これを書いた理由

レコードの重複を除く処理って普通に必要なので。
そして、これを今のかしこい子がやるようにシンプルにきれいにやりたいのです。

#初心者レベルの私（文系の元コボラー）が安直に思いつく方法

1．チェック列を作成
2．Collectionをソート
3．行の内容を退避
4．次の行と、退避した前の内容が一致していたらチェック列にマーク
5．マークした列を削除

できるんですけど、実際いまそうやって作られてるやつがいっぱいあるのですけど、
ダサい……。

#単純に重複行を削除するだけのオブジェクトを作ります。
たとえばこういうCollectionがあったとして
![重複A.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142092/55879691-cb80-294f-bb3d-a56b28459adf.png)
2行目と6行目に佐伯真彩が重複しているので、6行目が削除したい行になります。

##重複行を削除するためのオブジェクト

###必要っぽいのは
[DataView.ToTable メソッド](https://docs.microsoft.com/ja-jp/dotnet/api/system.data.dataview.totable?view=netframework-4.8)

>**distinct** Boolean
true の場合、返された DataTable にはすべての列に対して重複しない値を持つ行が含まれています。 既定値は false です。

つまり「ToTable(true)」って書けば重複行を削除してくれるらしい。
で、Collectionをこの「DataView」にするためには
[DataTable.DefaultView プロパティ](https://docs.microsoft.com/ja-jp/dotnet/api/system.data.datatable.defaultview?view=netframework-4.8)

どっちも名前空間はSystem.Data（デフォルトであるやつ）なので、Initialiseに新たに名前空間とかを設定する必要はありません。

###これを踏まえてコードステージに1行書きます。
入力引数は処理したいCollection、出力引数はカラのCollectionです。

```c#
outCollection=inCollection.DefaultView.ToTable(true)
```
オブジェクトに書くのはこれだけ
![フロー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142092/67a3ed41-339f-eac8-9288-16ad755c693e.png)

これで重複行を削除するオブジェクトができます。

#単純じゃない場合（重複列を指定したい）※未解決
たとえばデータに連番がついていたら、行全体が重複ってことにはなりません。
「連番を除く列で重複だったら」ということにしないといけないのですけど……。
![重複B.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142092/f74819ec-ba26-16ab-c4ea-a2067a6805f5.png)

###さっきの「DataView.ToTable メソッド」のパラメータにもうひとつ書いてあるのを使う

>**columnNames**  String[]
返された DataTable に含まれる列名の一覧を格納する文字列の配列。 DataTable には、この配列内に表示される順序で、指定された列が含まれています。

そしたらフィルタしたい列名を後ろにつけたらいいのかなーって

```c#
outCollection=inCollection.DefaultView.ToTable(true,"氏")
```

これだと出力がこうなってしまいます。指定した列しか出ない。
![重複失敗1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142092/5b54ab5d-4c1a-f9b8-f603-0cf84726630c.png)

###複数列をフィルタ対象にするのは

できます。「String[]」って書いてあるからこれは配列です。なので複数書けます。引数を後ろへつなげるだけです。

```c#
outCollection=inCollection.DefaultView.ToTable(true,"氏","名","氏カナ","名カナ")
```

でもこれだとやっぱり上のと同じように、フィルタ対象ではない列（例だと「SEQ」）が出力に出てこないです。
![フィルタ後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142092/f4fc9ac1-7e4e-bee0-9e51-271d55451928.png)


#いま詰まっていること

- 出力するときには、入力したCollectionと同じ全部の列で出力されたい

つまり上の例で言うと、こうなることです。
![重複ゴール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142092/f096b7c1-e553-42c2-ddbe-74374fd174ca.png)


#まだ終わりではないです

Qiitaで質問するって、使い方としてどうかと思いましたが、誰か教えてください。
あと、皆様のとこの御社では、Blue Prismで重複削除の処理を実装するときには、どういう書き方をされているのでしょうか。教えてください。
カルネージハートから学ぶシステムテストの重要性

カルネージハート Advent Calendar 2019 4日目の記事です。

今回はカルネージハートから学ぶシステムのテストの重要性についてです。

# はじめに

- 前提条件としてカルネージハートEXAについて想定しています
- カルネージハートではTDD(テストコードの記述)などはできない想定です(これ超絶辛いっす)

## テストの重要性

結論ありきですが、カルネージハートの世界ではテストは非常に重要です。
なぜテストが重要か?

- 実装だけでは正常動作(異常系ももちろんのこと)の保証が全くない

ためです。

正常動作の保証がないとどうなるか?

- いわゆるバグが発生して、ほぼゲームに負けます

これを現実世界に置き換えるとどうなるか？

- 個人情報を扱うシステムだと重大なインシデント発生
- 重機関連のシステムだと最悪人の命を死に至らしめます
- 等など

社会的地位が危ぶまれます。
システム的にテストは重要な仕事と言えます。

## 話はそれますが

一部のWebシステム界隈ではテスターはペーペーの仕事。。
等と言われるようなこともあるそうです。

とんでもないですね。

システム的にテストは重要な仕事です。
~~Excelスクショペタペタ3年間ずっととかはちょっと思うところはありますが~~

## 最後に

事実上の最新作EXAが2010年に発売以降続編の情報が皆無ですが、一部の熱狂的ファンは大会を開催してゲームを続けています。ゲームを盛り上げることで続編も出るかもしれません。カルネジスト、ネジらーの皆様のご協力をお願いします！

カルネージハートファンのプログラミング知識を共有しましょう！

ミサイル回避でお茶を濁します

![ezgif-2-26865a7fb846.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133718/1e968499-e3f1-4b41-01d9-61ae865f1b56.gif)
staticメソッドの使いみちがイマイチわからないのでまとめてみた

※ __本記事は未完成__ です。
まだ自分の中に落とし込めていないのですが、他の人の役に立つこともあるかと思い、投稿します。
誤っている箇所がありましたら、遠慮なくマサカリを投げてください。

## 「staticメソッド」とは？

直訳すると「静的メソッド」です。「クラスメソッド」ともいいます。
対義語は「インスタンスメソッド」です。

## staticメソッドのメリット

### ①インスタンスを生成せずに呼び出せる

インスタンスを生成せずに呼び出せるのが一番のメリットです。インスタンス生成にかかるオーバーヘッドがなくなるので、 __インスタンス生成に時間がかかるクラスに有効__ です。
そのため、頻繁に呼び出されるユーティリティメソッドはよくstaticメソッドとして実装されます。

また、自クラスのファクトリメソッドのように、 __インスタンスの生成前に実行すべきメソッド__ はstaticにするしかありません。

### ②インスタンスごとに動作が変わらないことを保証できる

インスタンスを複数生成しても、そのインスタンスが持つstaticメソッドの処理はどのインスタンスも同じ動作になります。

### ③状態に依存しないことを保証できる

基本的にはインスタンス化しないと状態を持てないので、状態に依存しないことを保証できます。
具体的には、 __与えられた引数のみでメソッドの挙動が決まる__ ことが保証できます。

その逆も然りで、状態を変更しない、いわゆる __副作用が起きない__ ことも保証されます。

ただし、これは「基本的には」です。
グローバル変数という __インスタンス化しなくても状態を持てる変数がある場合は話が変わる__ ので注意です。

## staticメソッドのデメリット

### DIしにくい

言語にもよりますが、staticメソッドを持つクラスはDIしにくいです。
つまりモック化して単体テストしにくいということです。

## staticメソッドの使い分け

### ①インスタンスごとに持つ意味があるかどうか

メソッドの意味を考え、インスタンスごとに持つ意味がなければstaticメソッドにし、あればインスタンスメソッドにすべきです。
たとえオーバーライドされる予定がなく、状態に依存していなくても、インスタンスごとに持つべきであればstaticメソッドにしてはいけません。

例: `犬` クラスの `吠える` メソッドにはstaticを付けない。吠えるのは個々の犬だから
→わかりづらいかも、、

### ②オーバーライドされる予定がない

言語によるかもしれませんが、例えばC#はstaticメソッドをオーバーライドできません。
オーバーライドを前提としたメソッドは、インスタンスメソッドとして定義する必要があります。

### ③状態に依存しない

属性の参照・変更がなく、引数と戻り値のみで完結する場合のみ使うべきです。
staticな属性は参照・変更できますが、望ましくありません。

## 使いみち

私はファクトリメソッドとユーティリティメソッドしかstaticにしません。（今思いつく限りでは）
他に有用な使いみちがありましたら、教えていただけると嬉しいです。

### ①ファクトリメソッド

TBD

```cs
static void create {
}
```

### ②ユーティリティメソッド

TBD

```cs
static string {
}
```

## おまけ: privateメソッドをstaticにするかどうか

状態に依存しないprivateメソッドをstaticにするか迷ったことはありませんか？
privateメソッドの呼び出し元がstaticの場合はstaticにしなければいけませんが、インスタンスメソッドから呼び出す場合はstaticにしなくても言語仕様上は問題ありません。

状態に依存しないことを保証するため、privateメソッドをstaticにするのは有用です。
しかしstaticメソッドは同一クラスから呼び出す場合でもクラス名を省略できない言語が多いです。

私はスッキリ書くことを優先し、 __必要でない限りはprivateメソッドをstaticにしません__ 。

## まとめ

TBD

## 参考リンク
- [staticメソッドの使いどころについて - staticメソッドについて質問です。st... - Yahoo!知恵袋](https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1220329577)
- [Java - staticなmethodのメリットとは(13203)｜teratail](https://teratail.com/questions/13203)
BEMについて学んだことまとめ

## 目次
1. BEMとは
2. BEMの使い方

## 今回の学習のゴール
- BEMとは何か、何ができるかを知る
- 実際の使い方について知る

## 1. BEMとは
- Block, Element, Modifierの略語
- 命名規則の１つで、有名なCSS設計思想である
- モジュラーでメンテナンス可能なコードを書くことができるため、再利用性を容易にする
    - 規格化された部品（モジュール）を組み合わせて機能を連結させたものをモジュラーという
- CSSセレクタをBlock, Element, Modifierの3つに分けて定義する
    - block
        - UIパーツの塊で再利用できるもの（コンポーネント）
        - Blockの名前はユニークにしパーツごとの独立性を保つようにする
        - ex. card
    - Element
        - Blockの中にのみ存在できる構成要素
        - blockとelementは2つのアンダーバーで繋ぐ
        - ex. card__title
    - Modifier
        - BlockやElementを修飾したい場合に使用し、バージョンの違いや一時的な状態などを示す
        - 違いが少ないBlockやElementを再利用するために用いる
        - card__title--primary
- block__element–modifierがクラス名の基本構造

```html
<div class="block block--modifier">    <!-- modifierはblockにもelementにもつけることができる -->
  <span class="block__element block__element--modifier"></span>
</div>
```

## 2. BEMの使い方

```html:html
<div class="posts">
  <ul>
    <li class="posts__item"> 投稿1 </li>
    <li class="posts__item posts__item--active"> 投稿2 </li>    <!-- modifierがあるクラス名とないクラス名を両方記述する -->
    <li class="posts__item"> 投稿3 </li>
  <ul>
<div>
```
```css:scss
.posts {
  /* postsのCSSを記述 */
  &__item {
    /* posts__itemのCSSを記述 */
    &--active {
      /* posts__item--activeのCSSを記述 */
    }
  }
}
```


## 参照
- [BEM — Block Element Modifier](http://getbem.com/naming/)
- [BEM を使うべき5つの理由](https://frasco.io/5-reasons-to-use-bem-f5ca38f748a1)
- [【CSS設計】今さら聞けないBEMの基本](https://nycreation.jp/blog/archives/289)
- [BEMの基本ルール](https://morizyun.github.io/web/css-bem-basic-rule.html)
ChatWork:特定のグループチャットの未読を一括で既読にできるようになった

2019年11月のリリースノートで
特定の指定したグループチャットの未読を一括で既読にできるようになりました。

いつの間に！

でもなんか今更感ありますね。
今まではブックマークレット作って対応してました。たしかに昔この機能ないんだと思った記憶があります。

ただ、公式の機能として一括で既読にできるのは便利ですね！

![chatwork_allread.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452135/8500c164-909c-6fab-f49c-a508466d05b4.png)

参照：[2019年11月　リリースノート](https://blog-ja.chatwork.com/2019/11/201911_11.html)
Googleスプレッドシートにカウントアップボタンがなかったので作った

# Googleスプレッドシートにはスピンボタンがない。
### スピンボタンって何や？
Excelの画面で説明すると、三角形のこれです。↓
![スピンボタン.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/359997/7510a7cf-f254-e099-de80-9739049675c4.gif)

数字をクリックで管理できて非常に便利。

### スプレッドシートにはない。
この便利なボタン、実はGoogleスプレッドシートにはなく、数値は逐一入力しないといけない。
せっかくクラウドで共有してみんなで使えるんだから、それぞれがクリックして数えることができれば非常に便利だと思うんだけど。

# こういうのを作ります。
動画の通りです。↓
![カウントアップ.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/359997/56d1206d-f3f9-cdf0-7008-2f693922513f.gif)

gif作るのって難しいですね。下手でごめんなさい。

### 機能
・選択したセルの数値を1増やすボタン
・選択したセルの数値を1減らすボタン
の二つ。

### 流れ
・スクリプトを実行
・選択中のセルを取得
・そのセル内の数値を増やす/減らす

これだけですね。
あと注意として、対象のセルには数値しか入力できないようにしておけば、立派なカウントアップ・ダウンボタンであると言えると思います！


# というわけで早速作る。
### スプレッドシートを作成
とりあえず空のものを用意しましょうか。

### スクリプトエディタを開く
先にスクリプトを用意してから、図形に紐づける必要があるので、作っておきましょう。
<img width="664" alt="スクリーンショット 2019-12-06 10.27.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/359997/c2158e83-b64b-7a7f-aab9-3fda4733f329.png">


### スクリプトを書く
今回のスクリプトはこの2種類。アップとダウンで別々に書きました。 ~~図形2つを区別する方法がわからなかったので。~~

```javascript:buttonUp.gs
var sheet=SpreadsheetApp.getActiveSheet();
function onClickUp(){
  var cell = sheet.getActiveCell();
  buttonUp(cell);
}

function buttonUp(cell) {
  var value=cell.getValue();
  cell.setValue(value+1);
}
```

```javascript:buttonDown.gs
var sheet=SpreadsheetApp.getActiveSheet();
function onClickDown(){
  var cell = sheet.getActiveCell();
  buttonDown(cell);
}

function buttonDown(cell) {
  var value=cell.getValue();
  cell.setValue(value-1);
}
```

説明すると、どちらも
シートを取得
→選択されているセルを取得
→数値を変更する関数呼び出し
→セルの値を取得
→セルの値を1変更してセット

という流れで動いています。多少でもコードを書いたことのある方なら見ればわかる程度のものだと思います。
わからなくてもコピペで大丈夫ですよー。


### 図形を描画し、配置する
ボタンとなる図形を書きます。
<img width="516" alt="スクリーンショット 2019-12-06 10.44.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/359997/739abbef-4040-de4a-2851-3c51946230e8.png">


### 図形にスクリプトを割り当て
先ほどの図形を右クリックして、関数名を割り当てます。
<img width="205" alt="スクリーンショット 2019-12-06 10.46.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/359997/dd66ab9c-5518-e88d-9442-bf68cfec0f44.png">

アップにはonClickUp、ダウンにはonClickDownを割り当てましょう。


### スクリプトを認証させる
1回目の実行では許可されていないと怒られます。許可しましょう。
[この方の説明がわかりやすいかと。](https://www.virment.com/step-allow-google-apps-script/)

# おわりに。
今回のカウントアップボタンはあくまで個人作業のために製作したネタです。
業務上で使用される場合などは十分チェックした上でご利用ください！
私は一切の責任を負いません！w
Cloudwatchアラーム通知をメールに来るようにする

# Cloudwatchアラーム通知をメールに来るようにする
株式会社パーソンリンクにエンジニア未経験で入社して3週目の高島です。今後実務でRDSを扱っていくにあたり、RDSに何か問題があった時や、CPUの使用率がメトリクスの閾値を超えた時にslackに通知が来るように設定したいと思いました。その前段階として、まずはcloudwatchとメールとの連携をすることにしました。
> 参考にさせていただいた記事：[CloudWatchアラーム通知をSlackにする](https://qiita.com/hf7777hi/items/e0f43f0fb7e2effa0af8)

## RDSとは
**Amazon Relational Database Service**の略。Amazonの提供するリレーショナルデータベースの構築サービス。セットアップを簡単に行うことができる。



## 用語
・**cloudwatch**とは、AWSで、リアルタイムに実行されるアプリケーションを監視するリソース。メトリクスを収集し、それをアラームにすることができる。
・**メトリクス**とは、システムのパフォーマンスに関するデータ。
・**閾値（しきい値）**とは、条件分岐の境目となる値。

##やり方
- AWSコンソールから、Cloudwatchを検索。
- **アラーム**タブ→画面右のほうにある、**アラーム作成**
- 監視したいメトリクスを選択する。メトリクスの名称は、公式ドキュメントに掲載<br>
https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/viewing_metrics_with_cloudwatch.html
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/499375/a4caa055-05ab-6e75-4baa-7c2161fadfee.png)
今回は、CPUtilization（CPU使用率）が０以上の時にアラームを鳴らす。
テスト的にやるので、必ず引っかかる条件でとりあえずやってみる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/499375/7da4c2bc-f998-e551-c798-a84d38d5b18c.png)
**SNSトピックの選択**においての選択次第で、**通知を受け取る E メールエンドポイント**と表示されるので、そこにアラームを飛ばしたいメールアドレスを入力する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/499375/78bb71da-9675-eb1e-9b1c-56f14ad6552a.png)
Gmailにてメッセージを確認することができました。

ここで勘違いしていたのですが、アラームは常に来るわけではなく、正常→警告レベルになった時に１回だけ来ます。

メールで通知するようにすれば、何か異常が起きた時にすぐ気づくことができますね。
次は、@shinoyuさんです。最後まで読んでいただき、ありがとうございました。
Laravel基本知識&操作

久しぶりにLaravel(5系)を触っているので、忘れないように基本操作メモ

# MVCフォルダ構成
- コントローラ
  - `app/Http/Controllers`
- モデル
  - `app`
- テンプレート
  - `resources/views`

# バッチ
## 格納場所
app\Console\Commands

## コマンド
- コマンド名をバッチファイル内の `$signature` に定義しておく
- `app\Console\Kernel.php` の `$commands` に追加
- バッチ実行
  - php artisan コマンド名

# バリデーション
## 参考
https://readouble.com/laravel/5.4/ja/validation.html

## コントローラ/モデル側
```php
$data = $_POST['id']; // チェックしたいデータ
$rule = ['id' => required|integer]; // チェックしたいキーとそのルール
$messages =[ // ルールに引っかかった際のエラーメッセージ
    id.required => 'IDが入力されていません',
    id.integer => 'IDが数字ではありません'
];

Validator::make($data, $rules, $messages)->validate();
```

## テンプレート側
`$errors` に格納される

```php
@if ($errors->any())
    @foreach ($errors->all() as $error)
        <div>{{$error}}</div>
    @endforeach
@endif
```

# DB操作
## 参考
https://readouble.com/laravel/5.4/ja/queries.html

## SELECT
### 基本
```php
$result = DB::table('テーブルA')
// 取得するフィールド
    ->select(
        'フィールド1',
        'フィールド2',
    )
// 結合
    // シンプルな結合
    ->join('テーブルB', 'フィールドB1', '=', 'フィールドA1')
    // 複数条件の場合
    ->join('テーブルC', function($join) {
        $join->on('フィールドC1', '=', 'フィールドA1');
        $join->on('フィールドC2', '=', 'フィールドA2');
    })
// 条件
    // シンプルな条件
    ->where('フィールド1', '>', 1)
    // バインドしない場合
    ->whereRaw('フィールド3 IS NULL')
    // 入れ子
    ->where(function($sql) {
    $sql->where('フィールドA5', '!=', 9) 
        ->orWhere('フィールドA6', '!=', 9);
    }
// 並べ替え
    ->orderBy('フィールド1', 'ASC');
// 取得
    // 全件
    ->get();
    // 1行
//  ->first();

foreach ($result as $val) {
    echo $val->フィールド名;
}
```

### 特定のフィールド取得
```php
$field = DB::table('テーブルA')
    ->where('id', '=', '1')
    ->value('フィールド名');
```

### 取得した値のemptyチェック
```php
if ($result->isEmpty()) {
}
```

## INSERT
### 基本
```php
DB::table('テーブルA')
    ->insert([
        'フィールド1' => 1,
        'フィールド2' => 'テスト'
    ]);
```

## UPDATE
### 基本
```php
DB::table('テーブルA')
    ->where('フィールド1', '1')
    ->update(['フィールド2' => 'test']);
```

# ログ系
## ログ出力
### 出力先
- `storage/logs/`

```php
Log::info('1111');
```
【Mac】bundle installでmysql2が入らないときの対策コマンド

## ◆現象
bundle installをすると次のようなエラーが出てmysql2が上手く入らない。

```
〜省略〜
current directory: /Users/hogehoge/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/mysql2-0.5.2/ext/mysql2
make "DESTDIR="
compiling client.c
compiling infile.c
compiling mysql2_ext.c
compiling result.c
compiling statement.c
linking shared-object mysql2/mysql2.bundle
ld: library not found for -lssl
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [mysql2.bundle] Error 1

make failed, exit code 2

Gem files will remain installed in /Users/hogehoge/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/mysql2-0.5.2 for inspection.
Results logged to /Users/hogehoge/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-18/2.5.0/mysql2-0.5.2/gem_make.out

An error occurred while installing mysql2 (0.5.2), and Bundler cannot continue.
Make sure that `gem install mysql2 -v '0.5.2' --source 'https://rubygems.org/'` succeeds before bundling.
```

### ●エラーで言われていること

```
ld: library not found for -lssl
```
ライブラリ（mysql2を入れるのに必要なもの）が見つからないと言われている。ライブラリが見つかるよう指定してあげると解決できる。

## ◆対策コマンド

ターミナルで次のコマンドを実行してから再度bundle installをする。

```
bundle config --global build.mysql2 --with-opt-dir="$(brew --prefix openssl)"
```

これでbundlerを使ってmysql2を入れる際、以下のような場所にあるライブラリを使ってくれるようになる。

```
brew --prefix openssl
=> /usr/local/opt/openssl@1.1
```
mac に metasploit をインストール

ちょっと mac で使いたかったのでインストール手順のメモ。

```shell
% curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templates/metasploit-framework-wrappers/msfupdate.erb > msfinstall && chmod 755 msfinstall && ./msfinstall
```
これでインストールできるので、あとは path を通すだけ。


```shell
% echo 'export PATH="/opt/metasploit-framework/bin:$PATH"' >> ~/.zshrc
% exec $SHELL
```
path を通したら起動してみる。

```shell
% msfconsole
```
めでたし。
ベイズ深層学習 5章 ニューラルネットワークのベイズ推論 説明資料

#資料リンク
[スライドはこちら](https://www.slideshare.net/ssuserca2822/5bayesian-deep-learning)
#書籍
機械学習プロフェッショナルシリーズ　ベイズ深層学習
[書籍リンクはこちら](https://www.kspub.co.jp/book/detail/5168707.html)
#内容
基本的には書籍の内容に沿って説明していますが、理解の確認のために途中式や説明を適宜追加しています。スライド内の数式では誤植も修正しています。
質問・コメント等は大歓迎ですので、twitter(@_oshiritantei)か記事コメント欄までお願いいたします。すべての式展開を追っていますので、途中式の説明等依頼をいただければ追記していきます。
ローカルでデバッグ＆テスト可能なLINEチャットボット開発環境（Node.js Express  LINESimulator ）を作成する

#ローカルでデバッグ＆テスト可能なLINEチャットボット開発環境（Node.js Express  LINESimulator ）を作成する

　
※本記事は最終的にQ&Aチャットボットを構築するための一部分となります。
[本編はこちら](https://qiita.com/abemaki/items/8c611cc63ec109ab3835)

※前段の記事で作成したオウム返しチャットボットベースとなります。
[まだ未作成の方はこちら](https://qiita.com/abemaki/items/44d2015561c31ea9628e)






###DEBUG環境を作成する

####１．DEBUG環境を作成します

構成の追加からlaunch.jsonを生成します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524081/060d9888-c146-2b7a-ea9f-d90c8764bb14.png)

DEBUG用の設定情報を追加します。DEBUG時はシュミレータに接続するように設定します。
"Channel_endpoint"の設定はDEBUG用の設定（"http://localhost:8080/v2/bot/message/reply/" 固定）にしましょう。　

```console
{
    // IntelliSense を使用して利用可能な属性を学べます。
    // 既存の属性の説明をホバーして表示します。
    // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "launch",
            "name": "プログラムの起動",
            "program": "${workspaceFolder}\\index.js",
             "env": {
                "Channel_endpoint":"http://localhost:8080/v2/bot/message/reply/"
              }
        }
    ]
}
```
　
　
　

####２．LINEシュミレーターを準備します

LINEシミュレーターの導入はとても簡単

```console
git clone https://github.com/kenakamu/LINESimulator ../LINESimulator
cd ..\LINESimulator\
npm install
```
　　

　
LINEシミュレーターの起動はいつものコマンドで

```console
npm start
```
　　
　
　

BOTをDEBUGで起動しておきます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524081/e9d5bd3a-3d6e-34db-a453-6968b3e9cd89.png)

　
　

起動するとLINE設定情報を求めらるので、.envからコピーして設定を貼り付けます
設定を入力したらConnectします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524081/7dcb2553-1e7b-a64d-989d-0b4286f37a22.png)

　
　

接続がうまくいくとシュミレーターを使ってBOTとのやり取りが可能になります
これで開発効率が大幅に向上するはず
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524081/24dffe85-d76d-d530-3772-b6da4b32f25c.png)
MacOS クリーンインストールの方法

MacBook Pro 13inch 2016 
Sierra->High Sierra->Mojave->Catalinaと順にUpgradeしてきました

windowsと同じでUpgradeをずっとやってると、レインボーマークやレスポンスが悪くなってきます

やっとの思いでクリーンインストールを決意。

とりあえずバックアップは、TimeMachineと必要なファイルをGoogleDriveに移動。
アプリとかはHomebrewで、パスワード系は1passwordだしOK

###クリーンインストール方法
alt+command+RでUtillitiesを起動してディスクをフォーマット。
（CatalinaをインスコするとMacintosh HDとMacintosh HD-Dataができる。
　両方フォーマットしないとイケナイそう）

###注意点
朝とか時間がない中クリーンインストールしてたけど、ヤメたほうがいいです
AppleのサーバからOSをDLしているとき、スタンバイ状態にならないよう、
マウスのカーソルを動かしてたほうがいいです
※結構時間がかかります。。。
grubでkernel起動 その3

#概要

grubが入ったフロッピーイメージでkernelの様なものを起動する。
xv6をgrubから起動してみた。

#閃きのイメージ

xv6もmultiboot_header持ってるから、起動できるんじゃね。

#開発環境

debian 6.0.7 sqeeze
grub 0.96

#フロッピーイメージにコピーする。

```
$ mount -t vfat -o loop fd.img /mnt
$ cp kernelmamfs /mnt/boot/xv6.elf
$ umount /mnt
```

#qemuで実行。


```
$ qemu -fda fd.img -smp 2 -m 256 -serial mon:stdio 
```

#grubでブート。


```
$ root (fd0)
$ kernel /boot/xv6.elf
$ boot
```

#結果

![Screenshot3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/bb15e910-60f3-268a-c37c-c1781cb7e9aa.png)


以上。
【AngularJS】画面ロードさせずにURLのみ変更したい

#経緯
URL変更時、画面をローディングさせたくないが、ローディング先がapp.jsのルーティング先として登録されているため、ロードされてしまう状態に。

###やってみたこと
・$locationによる操作
・window.locationによる操作
・Historyオブジェクトでの操作

ちょっと前に色々試行錯誤したので記憶が曖昧なのですが、試せるだけ試した記憶です。

#実装
~~~controller.js
$scope.changeParam = function(){
    // URLパラメータの変更を条件とする
    if ($location.search()["word"] != $scope.word){
       // 元のパスを取得
       var path = $location.path();
       // URL変更の関数を呼び出す
       changeUrl(path);
    }
}

// URL変更時、ロードさせない
var changeUrl = function(path) {
    var lastRoute = $route.current;
    // URL変更時に発火
    var deregistrationFn = $rootScope.$on('$locationChangeSuccess', function () {
	    // URL変更前の情報をURL変更後に代入する
	    $route.current = lastRoute;
	    deregistrationFn();
    });
    $location.url(path);
};

~~~

#補足
・URL変更前→URL変更後に代入、という形で実現できるようですが、詳しい原理は不明…
・app.jsに登録しているルーティング構成次第では回避できる気がしますが、既に構築済みなルーティング構成をいじる方がしんどい場面などで使えると思います。
・色々調べていたところ、結構特殊な状況らしく、本来なら$locationやHistoryオブジェクトによる履歴の操作などで実装するのがスマートっぽいです。

#参考記事
・[Angularで画面遷移やロードをさせずにURLのみを変更する方法](http://deepblue-will.hatenablog.com/entry/2015/09/03/Angular%E3%81%A7%E7%94%BB%E9%9D%A2%E9%81%B7%E7%A7%BB%E3%82%84%E3%83%AD%E3%83%BC%E3%83%89%E3%82%92%E3%81%95%E3%81%9B%E3%81%9A%E3%81%ABURL%E3%81%AE%E3%81%BF%E3%82%92%E5%A4%89%E6%9B%B4%E3%81%99)
Gemfileインストール時のエラー(An error occurred while installing pg (0.20.0), and Bundler cannot continue.)

Railsチュートリアル3.1のbundle installで発生したエラーへの初心者なりの対処法です。

- 発生したエラーと対処
- 後書き

の順に書いていきます。

##発生したエラーと対処
Railsチュートリアル3.1の手順に沿ってGemfileを上書き後"bundle install --without production"したところ、エラーになり"bundle update"するようにとのメッセージが出ました。
言われた通りにupdateすると次のようなエラーが出ました。

```ruby:qiita.rb
An error occurred while installing pg (0.20.0), and Bundler cannot continue.
Make sure that `gem install pg -v '0.20.0' --source 'https://rubygems.org/'` succeeds
before bundling.
```

ソースを確認しろと言われてもRubyGemsのページに行ったところで何もできず、検索してもそれらしい解決法を見つけられず、とりあえずもう一度インストール

```ruby:qiita.rb
You have requested:
  spring = 2.0.2

The bundle currently has spring locked at 2.1.0.
Try running `bundle update spring`

If you are updating multiple gems in your Gemfile at once,
try passing them all to `bundle update`
```

エラーメッセージが変わっていたので次は"bundle update spring"を実行

```ruby:qiita.rb
You have requested:
  minitest = 5.10.3

The bundle currently has minitest locked at 5.13.0.
Try running `bundle update minitest`

If you are updating multiple gems in your Gemfile at once,
try passing them all to `bundle update`
```
さらにメッセージが変わったので次は"bundle update minitest"を実行

```ruby:qiita.rb
You have requested:
  spring = 2.0.2

The bundle currently has spring locked at 2.1.0.
Try running `bundle update spring`

If you are updating multiple gems in your Gemfile at once,
try passing them all to `bundle update`
```

またエラーメッセージですがそれはさっきしたよってことで"bundle update --without production"をしてみると無事インストールに成功しました。

##後書き
まだ学び始めで技術的なことは何も言えないのですが初心者は取り敢えずエラーメッセージと向き合うことから始めるべきだなという気づきがあったため投稿しておきました。
自分はエラーが出てとりあえずGoogleで検索をしたのですが、”brewを試す””検索パスは通っているか？”のようなよく分からないものばかりで混乱してしまいました。
下手にイジっても復旧させる技術がないので躊躇し、もう一度エラーメッセージを読み直してみようと思った結果、無事に解決した次第です。

初心者の落ち入るエラーなんて大したものじゃないことがほとんどだと思います。
英語とエラーから逃げずに頑張ろう！！
STM32 HALの勉強方法

# HALの勉強方法
STのHPに
https://www.stmcu.jp/design/document/users_manual/53059/
などはあるのですが、まあこれはわかりにくいです。
おすすめはSTM32CubeF4などのターゲットデバイスのHALをダウンロードした後、Projectsフォルダの中にある、STM32CubeProjectsList.htmlをブラウザで開いて下さい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263486/28a9fd98-0582-d94f-200f-cb411ef126ba.png)
こんな感じの画面になります。
これは各ペリフェラルのサンプルコードがどこにあるかの一覧です。これで、使いたいHALのサンプルがすぐに見つかります。
注意点は縦だけでなく、横にも長いので、見落としのないようにしてください。
コントローラとアクションでビューページの分岐をする時

ありがちなコントローラーαがAまたはBみたいな分岐を書かなきゃいけない時

```悪い例.rb

 if コントローラーα == 'A' || コントローラーα == 'B'
```

と書いていたんだけど


```いい例.rb
 if controller_name.in?(%w(A B))
```

と短く書くことができる！

これからは`controller_name.in?`を使おう
アクションの判断も`action_name.in?`で判断することができる！



##例文
```ruby

 return render('try/steps') if controller_name.in?(%w(try orders)) && action_name.in?(%w(apply confirm))
```
【TOP】herokuの無料枠で動くLINE向けQ&Aチャットボットを作る（elasticlunr.js + Express ）

#はじめに
herokuの無料枠で動くLINE向けQ&Aチャットボットを作ります。
長くなるのでいくつかに記事を分けて書いていきたいと思います。

最終的には『コミュニケーション型チャットボットを作りたい』という目的があるんですが
まずはその切り口になればと思い、まずはQ&Aチャットボットを作成します。

本記事は分割して作成する記事をリンク集且つTOPページとして活用する想定です。


#さっそく作る


###①Heroku + LINE + node.js (Express.js)でオウム返しボットを作成する

下記記事ではQ&Aチャットボットの土台となるアプリケーションを作成します
オウム返しを作成することで、heroku + Line + node.jsで動作するチャットボット作成に必要な技術を理解しつつ土台の作成が可能です。
https://qiita.com/abemaki/items/44d2015561c31ea9628e


　
　
###②ローカルでデバッグ＆テスト可能なLINEチャットボット開発環境（Node.js ＋ Express.js ＋  LINESimulator ）を作成する

下記記事では本格的にBOT開発を始めると
動作確認＆デバッグが手軽にできる環境が必要になるのでこのタイミングで作成しておきましょう
https://qiita.com/abemaki/items/ba61555277ad89737fc4


　
　
###③前々回の記事で作成したオウム返しチャットボットにQ&Aエンジンを実装する

いよいよQ&Aエンジンの作成です
①②でしっかりとした開発基盤を作っておけば実装は簡単です
https://qiita.com/abemaki/items/2f1d5ec7e09ce7371431




　
　
###④以降・・・

要望ニーズがあれば以下のいずれかの記事を作成します！！

・BOTが明確な回答を確信できない場合に、可能性のある候補をユーザーに選択方式で提示する実装

・管理画面の実装
　ナレッジベースの軸となるエクセルをアップロードする機能
　BOTのテスト、トレーニング、チューニングする機能

・LINE以外のUIに対応する実装

・フロー、シナリオ回答する実装

・本格利用するためのセキュリティ対策実装

・コミュニケーション機能の実装

・発話を理解して、「インテント（意図）」と「エンティティ（重要な単語）」を得る実装
TensorflowLiteによるKerasモデルの圧縮


本記事は，[DSL Advent Calendar](https://qiita.com/advent-calendar/2019/muroran-it-dsl)の6日目の記事です．
研究テーマの引き継ぎがてら，Tensorflow Liteの使い方についてまとめます．

# TensorflowLiteとは
TensorFlow Liteは，TensorFlowやKerasで学習したモデルを，モバイル・組み込み端末上で動かすために，圧縮を行うフレームワークです．
float32形式で保存されているモデルの重みを，int8やfloat16形式に圧縮することができます．

リアルタイムで予測を行いたい，小型デバイスのStand-aloneで予測を行いたい場合は，ぜひ利用してみてください．

# 実行環境
Ubuntu16.04
Python 3.7.4
- TensorFlow 1.15.0
- Keras 2.3.1

# モデルの圧縮
圧縮するモデルは，ImageNetで学習済みのInceptionV3を使用します．
一度，InceptionV3モデルをh5ファイルに保存し，その後tfliteファイルに圧縮を行います．

```python
from keras.applications.inception_v3 import InceptionV3

# InceptionV3モデルをロード
model = InceptionV3(include_top = True, weights = "imagenet")
# モデルの保存
model.save("hoge.h5")
```

###h5ファイルからtfliteファイルを作成

```python

import tensorflow as tf

converter = tf.lite.TFLiteConverter.from_keras_model_file("hoge.h5")
converter.optimizations = [tf.lite.Optimize.OPTION1]
converter.target_spec.supported_types = [tf.OPTION2]
tflite_model = converter.convert()

with open("model.tflite", "wb") as f:
    f.write(tflite_model)
```

OPTION1
- DEFAULT : モデルの重み，予測時の計算共に量子化
- OPTIMIZE_FOR_SIZE : モデルの重みを量子化，予測時の計算は浮動小数点演算
- OPTIMIZE_FOR_LATENCY : 調査中...

OPTION2
- int8
- float16　etc...

OPTION1では量子化を行う箇所，OPTION2では量子化の大きさを設定できます．
Tensorflow1.14.0以前のバージョンでは，OPTION2の設定は出来ないので注意が必要です．

結果，hoge.h5ファイルの容量は96.3MBでしたが，int8のファイルの容量は23.9MB，float16は47.7MBとなりました．
それぞれ，1/4, 1/2にモデルサイズを圧縮できました！




# Pythonでの予測
お試しで，option1 = DEFAULT, option2 = int8の量子化を行ったモデルで，猫の画像を予測してみます．
![neko.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161164/1eb0629e-f599-963c-021d-db548bc7da2b.jpeg)



```python
import numpy as np
from keras.applications.inception_v3 import preprocess_input
from keras.preprocessing.image import array_to_img, img_to_array, load_img

# 画像のロード & 正規化
img = img_to_array(load_img("cat.jpeg", target_size=(299, 299)))
input_img = preprocess_input(img)

# TFliteモデルのロード
interpreter = tf.lite.Interpreter(model_path = "hoge.tflite")
interpreter.allocate_tensors()

# モデルの入出力情報の取得
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()

# 入力画像のshapeを整形
input_data = np.expand_dims(img_input, axis = 0)

# 予測
interpreter.set_tensor(input_details[0]['index'], input_data)
interpreter.invoke()
output_data = interpreter.get_tensor(output_details[0]['index'])

# 予測結果の出力
print(output_data.argmax(axis = 1))
```

```:output
[281]
```
ImageNetのラベル番号！281番はtabby cat(ぶち猫，トラ猫)なので，ちゃんと正解できています！

また，予測を行う際，デフォルトでは，バッチサイズが1となっています．
モデルを変換する際にinput_shapeを指定することでバッチ予測ができます．


```python
converter = tf.lite.TFLiteConverter.from_keras_model_file("hoge.h5", 
                                   input_shapes={'input_1': (10, 299, 299,  3)})
```


## 応用例
公式サイトに複数のサンプルコードが挙がっています．
https://www.tensorflow.org/lite/examples

モデルを差し替えることで，手軽に自分で作成したモデルを試すことができます．

# まとめ
TensorflowLiteのモデルの変換，Pythonでの予測の流れをまとめました．
今回はしていませんが，実際に運用する場合は圧縮率・各パラメータごとの精度の検証等も比較する必要があります．


# 参考文献
- https://nextremer-nbo.blogspot.com/2019/10/tf20keraspost-training-quantization.html
- https://www.tensorflow.org/lite
- https://blog.imind.jp/entry/2019/08/11/182853
SwiftUIで画像をページングする

# はじめに
今作っているアプリで、Instagramのように写真をページングで表示したいと思い、SwiftUIのCustomViewを作ってみました。

SwiftUIのScrollViewのscrollイベントを検知する方法や、ScrollViewをprogrammaticallyにscrollする方法を見つけるのに苦戦したので、同じことをしたい人にとって きっと役に立つと思います。

# 完成イメージ

![ImagePagerDemo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94278/1d1833ff-9685-61e8-eeff-deefee214e07.gif)

E7系、かっこいい

# ソース

画像、"e7_square","e5_square","doctor_yellow_square"は、お手持ちの画像に置き換えてください。

```ImagePager.swift
import SwiftUI

struct ImagePager: View {

    var imageNames: [String]
    
    @State private var index: Int = 0
    @State private var offset: CGFloat = 0
    
    var body: some View {
        GeometryReader { geometry in // 1. offset(scroll位置)を操作するため、GeometryReaderを利用
            ScrollView(.horizontal, showsIndicators: false) {
                HStack(spacing: 0) {
                    ForEach(0..<self.imageNames.count) {
                        Image(self.imageNames[$0])
                            .resizable()
                            .aspectRatio(contentMode: .fit)
                            .frame(width: geometry.size.width, height: geometry.size.width)
                    }
                }
            }
            .content.offset(x: self.offset) // 2. self.offsetとscrollViewのoffsetをバインディング
            .frame(width: geometry.size.width, height: nil, alignment: .leading)
            .gesture(DragGesture()
                .onChanged({ value in  // 3. Dragを監視。Dragに合わせて、スクロールする。
                    self.offset = value.translation.width - geometry.size.width * CGFloat(self.index)
                })
                .onEnded({ value in // 4. Dragが完了したら、Drag量に応じて、indexを更新
                    let scrollThreshold = geometry.size.width / 2
                    if value.predictedEndTranslation.width < -scrollThreshold {
                        self.index = min(self.index + 1, self.imageNames.endIndex - 1)
                    } else if value.predictedEndTranslation.width > scrollThreshold {
                        self.index = max(self.index - 1, 0)
                    }
                    
                    withAnimation { // 5. 更新したindexの画像をアニメーションしながら表示する。
                        self.offset = -geometry.size.width * CGFloat(self.index)
                    }
                })
            )
        }
    }
}

struct Carousel_Previews: PreviewProvider {
    static var previews: some View {
        ImagePager(imageNames: [
            "e7_square",
            "e5_square",
            "doctor_yellow_square"
        ])
    }
}
```

# 解説

1. offset(scroll位置)を操作するため、GeometryReaderを利用
2. self.offsetとscrollViewのoffsetをバインディング
3. Dragを監視。Dragに合わせて、スクロールする。
4. Dragが完了したら、Drag量に応じて、indexを更新
5. 更新したindexの画像をアニメーションしながら表示する。



# 参考
https://stackoverflow.com/a/58302447/8834586

以上です。
SMBの検出・有効化・無効化　Windows

# 概要

>この資料では、SMB クライアントおよびサーバー コンポーネントでサーバー メッセージ ブロック (SMB) バージョン 1 (SMBv1)、SMB バージョン 2 (SMBv2)、SMB バージョン 3 (SMBv3) を有効または無効にする方法について説明します。

よく使う[Powershell](https://docs.microsoft.com/ja-jp/powershell/scripting/overview)のコマンドレットだけ表記し、あとは情報ソースの[URL](https://ja.wikipedia.org/wiki/Uniform_Resource_Locator)を貼ります。

## SMBとは

>[Windows Server の SMB 3 プロトコルを使用したファイル共有の概要](https://docs.microsoft.com/ja-jp/windows-server/storage/file-server/file-server-smb-overview#feature-description)より引用

>サーバー メッセージ ブロック (SMB) プロトコルはネットワーク ファイル共有プロトコルの一種で、コンピューターのアプリケーションがコンピューター ネットワーク上のサーバー プログラムに対してファイルの読み込みや書き込みを実行したり、サービスを要求したりする際に使用されます。 SMB プロトコルは、TCP/IP プロトコルをはじめとするネットワーク プロトコルの上位で使用できます。 SMB プロトコルを使えば、アプリケーション (またはアプリケーションのユーザー) がリモート サーバーにあるファイルなどのリソースにアクセスできます。 これにより、リモート サーバー上でアプリケーションがファイルを読み込み、作成、および更新できるようになります。 また、SMB クライアント リクエストを受け取ることができるように設定された任意のサーバー プログラムと通信できます。 Windows Server 2012 では、SMB プロトコルの新しい3.0 バージョンが導入されています。

ファイル共有の仕組みの一つです。

## 警告

>SMBv2 または SMBv3 は無効にしないことをお勧めします。 あくまでも "一時的な" トラブルシューティング手段として、SMBv2 または SMBv3 を無効にしてください。 SMBv2 または SMBv3 を無効なままにしないでください。
>[Windows 10 Fall Creators Update と Windows Server バージョン 1709 以降のバージョンの既定では SMBv1 はインストールされません](https://support.microsoft.com/ja-jp/help/4034314/smbv1-is-not-installed-by-default-in-windows)

「新しい仕組みのほうが安全ですよ」ということですね。
[ソフトウェアの脆弱性を狙う攻撃の通信の観測について、
警察庁が公表](https://xn--dckta5b5b2j4a3878bqnb245b20icpn0jz.com/%e3%82%bd%e3%83%95%e3%83%88%e3%82%a6%e3%82%a7%e3%82%a2%e3%81%ae%e8%84%86%e5%bc%b1%e6%80%a7%e3%82%92%e7%8b%99%e3%81%86%e6%94%bb%e6%92%83%e3%81%ae%e9%80%9a%e4%bf%a1%e3%81%ae%e8%a6%b3%e6%b8%ac%e3%81%ab/)している記事からも危険度を推し量ることが出来ます。


## Windows Server 2012 R2 および 2016

#### SMBv1

|||
|:-:|:-:|
|検出|Get-WindowsFeature FS-SMB1
|無効化|Disable-WindowsOptionalFeature -Online -FeatureName smb1protocol
|有効化|Enable-WindowsOptionalFeature -Online -FeatureName smb1protocol

#### SMBv2/v3

|||
|:-:|:-:|
検出|Get-SmbServerConfiguration &#124; Select EnableSMB2Protocol

無効化|Set-SmbServerConfiguration -EnableSMB2Protocol $false
有効化|Set-SmbServerConfiguration -EnableSMB2Protocol $true

## Windows 8.1 および Windows 10

#### SMBv1

|||
|:-:|:-:|
検出|Get-WindowsOptionalFeature –Online –FeatureName SMB1Protocol
無効化|Disable-WindowsOptionalFeature -Online -FeatureName SMB1Protocol
有効化|Enable-WindowsOptionalFeature -Online -FeatureName SMB1Protocol

#### SMBv2/v3

|||
|:-:|:-:|
検出|Get-SmbServerConfiguration &#124; Select EnableSMB2Protocol

無効化|Set-SmbServerConfiguration –EnableSMB2Protocol $false
有効化|Set-SmbServerConfiguration –EnableSMB2Protocol $true

# 情報ソース

「プログラムの追加と削除」・「サーバーマネージャー」・「PowserShell」・「レジストリ」・「グループポリシー」それぞれの方法とその比較が見られます。やはりソースが一番見やすい！そして濃い！
[Windows と Windows Server で SMBv1、SMBv2、SMBv3 を検出する方法と有効または無効にする方法](https://support.microsoft.com/ja-jp/help/2696547/detect-enable-disable-smbv1-smbv2-smbv3-in-windows-and-windows-server)

# まとめ

未だにsmbv1しか対応していないNASが現役だったり、
smbv1が不要なのに設定を放置しているところは早く何とかしましょう！
smbv1はランサムウェアの温床です。
Emotetも流行っているし、皆さんお気を付けくださいね！
COUNTでの条件NULLの話


システム改修の効果測定や新事業の展開拡大の効果予測など、KPI確認のために最近叩く回数も増えてきているので今更感を感じながらもメモがてら書いていきます。

---

### 一定条件のレコードのみをCOUNTしようとしてうまく行かなかった話

このような`sales`テーブルが存在すると仮定する。

| dates | number | res | mvp |
| --- | --- | --- | --- |
| 2017-01-01 00:00:00 | 2562 | false | NULL |
| 2017-02-01 00:00:00 | 2250 | false | NULL |
| 2017-03-01 00:00:00 | 2768 | false | NULL |
| 2017-04-01 00:00:00 | 2468 | false | NULL |
| 2017-05-01 00:00:00 | 1637 | false | NULL |
| 2017-06-01 00:00:00 | 1672 | false | NULL |
| 2017-07-01 00:00:00 | 2339 | false | NULL |
| 2017-08-01 00:00:00 | 2585 | false | NULL |
| 2017-09-01 00:00:00 | 2200 | false | NULL |
| 2017-10-01 00:00:00 | 2600 | false | NULL |
| 2017-11-01 00:00:00 | 3020 | true | A |
| 2017-12-01 00:00:00 | 2869 | true | B |

`res`カラムの値を利用し、目標を達成した数を`COUNT`するため、
以下のようなSQLを叩く。


```sql
SELECT COUNT(res='true') AS "success",
       COUNT(res='false') AS "failed"
  FROM sales
```

**結果**

| success | failed |
| --- | --- |
| 12 | 12 |

条件問わず全部カウントされている...

公式ページ
https://www.postgresql.jp/document/7.4/html/functions-aggregate.html

> expressionが非NULL値を持つ入力値の個数

null以外全てを数える模様。
ならば、条件を通す時に指定した値以外は`NULL`で`COUNT`に渡すようにすれば良い。

```sql
SELECT COUNT(
         (CASE
            WHEN res='true' THEN res
            ELSE NULL
         END)
       ) AS "success",
       COUNT(
         (CASE
            WHEN res='false' THEN res
            ELSE NULL
         END)
       ) AS "failed"
  FROM sales
```

| success | failed |
| --- | --- |
| 2 | 10 |

ok


では、今度は逆にNULLの数をカウントしてみる。
ということで、今度は以下SQLを実行

```sql
SELECT COUNT(
        (CASE
            WHEN mvp=NULL THEN mvp
            ELSE 'true'
        END)
      ) AS "NOT NULL",
      COUNT(
        (CASE
            WHEN mvp!=NULL THEN mvp
            ELSE 'true'
        END)
      ) AS "IS NULL"
  FROM sales;
```

**結果**

| NOT NULL | IS NULL |
| --- | --- |
| 12 | 12 |

ん？ やはり何かおかしい...?

ググってみると、SQLでは3値論理を採用し、`NULL`を第3の真理値として扱っているらしい。
よって、条件などで利用する際には`IS NULL`を利用する必要があるとのこと。

ということで条件式を一部変更

```sql
SELECT COUNT(
        (CASE
            WHEN mvp IS NULL THEN mvp
            ELSE 'true'
        END)
      ) AS "NOT NULL",
      COUNT(
        (CASE
            WHEN mvp IS NOT NULL THEN NULL
            ELSE 'true'
        END)
      ) AS "IS NULL"
  FROM sales;
```

**結果**

| NOT NULL | IS NULL |
| --- | --- |
| 2 | 10 |

ok

---

### まとめ

月並みですがNULLの扱いに気をつけましょう
攻めだるまサポート。アクティブサポート

###ア​クティブサポートとは
twitterでお客さまが何気なくつぶやいた内容に対し、CSから積極的にアクションを起こしサポートをおこないます。
具体的には、「ご意見」や「ポジティブなご報告」等に対し、CSからお礼/お祝い の言葉をリプライしたり、twitter上で仕様が分からない、アカウントを無くしてしまった等で困っているお客さまにCS自らアプロー​チし、解決に向けた攻めのサポートをおこなっています。


###目的
実は困っていてもお問い合わせをしない　というお客さまはたくさんいらっしゃり、一部のタイトルではDAUの0.1%以下という調査結果も出ています。
もちろん、お問い合わせにてお寄せいただくお困りごとやご意見に対して、真摯にお返事をすることがCSの使命でありつつ、それだけでは救えない、向き合えないお客さまもたくさんいるということに目を向けて始めたのがアクティブサポートです！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541100/678fdd7f-34d2-7b4b-d836-aef804b2585c.png)

twitterの特性上、思ったことや感じたことを気軽に投稿しやすいので、ゲームに対しての熱い想いが多く見受けられる　かつ　1人に対しての回答が複数人に届きやすい環境にあります。

より多くのお客さまを救い、そしてより多くのお客さまの気持ちに寄り添っていくため、twitterでサポートに取り組んでいます！


###実際にやっていること
以下のようなツイートを検知すると対象のお客様に対してリプライをおこないます。
・不具合の発生が疑われるツイート
・データ消失など、復旧対応が必要な内容のツイート
・ポジティブ、積極的なご意見ご要望

逆に以下のような内容のツイートへのリプライは炎上リスクにもつながるため控えております。
・ガチャやマッチング結果への不満ツイート
・RMT仲介やまとめサイト等の個人利用ではないアカウントのツイート

あと注意している点は、
・公式twitterアカウントとのすみわけを行う事
同じ情報がお客様のタイムラインに流れる状況はユーザーライクではないので、前もってマーケティング担当者やプロダクトのメンバーと認識合わせをおこなっております。

・IPタイトルの協業先との連携
当たり前ですが、画像や情報は協業先の確認を取ってから発信しております。


###成果
こうしたサポートを1年ほど続けており、ほんの少しずつではありますが、認知されはじめてきました。
そして、嬉しい言葉やたくさんの「いいね」をいただけるようになってきています！
最近では、twitter上でサポートを行ったお客さまを対象に満足度アンケートを実施しており、その結果、満足度約90%と高い評価をいただいてます！

###さいごに
事業として業務を行っている以上、継続判断の数値を追う事、KPIを達成する事は必要です。
私たちは、twitterのインプレッション、エンゲージメントをメインにKPIを設定しているのですが、全然思った通りいかないのです！

その要因は大きく2つ考えられ、
1つ目はアクティブサポートがお客さまのツイートを検知してリプライで応対していくサービスのため、発端となるツイートがなければリプライもできず、インプレッションもエンゲージメントも上がらないことです。
2つ目は、タイトルの周年、大規模な不具合が発生すると、ツイート数も増加するため、結果としてインプレッション、エンゲージメントが上がる、という外的要因の影響が大きいことです。

以上により、定量的な成果を判断しづらいことは引き続き課題ではありますが、
定性面では、応対したお客さまからの声が本当にポジティブなご意見が多く、「サポートからメッセージが来てうれしい！」などのリプライをいただいております。

目標達成の為の数値も大事ですが、お客様を満足させる***パッション***も大事です。
いかにこのパッションをうまく見せれるか、今後も考えていきたいと思います。
カルネージハートから学ぶプログラミング簡易化のススメ

カルネージハート Advent Calendar 2019 3日目の記事です。

今回はカルネージハートから学ぶプログラミングの簡易化のススメについてです。

# はじめに

- 前提条件としてカルネージハートEXAについて想定しています
- カルネージハートではTDD(テストコードの記述)などはできない想定です
- カルネージハートでは処理は1/30秒（1フレーム）単位以上の処理速度のカスタマイズはできません(WebサーバーやDBのチューニングと言った話は例外とします)

## 結論

- 基本的に処理(コードを)を記述すればするほど、処理が重くなり、反応速度が落ちる
- 処理が重くなるだけでなく、潜在的なバグが増えてデバッグが大変になる

## 簡易化のススメ

結論ありきですが、カルネージハートの世界ではプログラムは可能な限りシンプルである方が良いと言われています。
それはなぜか。例えばの例です。

- 1/30秒（1フレーム）単位で行動を制御するため、コンマ数秒の処理の遅れが命取りになりえます
- 例えば秒速1000mで進む弾丸への反応が0.1秒でも遅れると、その間に100m弾丸は進みます
- その結果弾丸が直撃します

対策としては

- 処理を遅くしないため、余計な処理は極力実行しない

また複雑な処理はもう1つのデメリットがあります。

- 潜在的なバグが増えてデバッグが大変になる

です。処理が複雑になればなるほど、分岐条件が増えて、テストしなければならない条件・状況が増えていきます。
その分デバッグが大変です。

## 簡易化デメリット

もちろん簡易化のデメリットもあります

- 分岐処理が減るため、汎用性が落ちる

こればっかりはトレードオフです。どこまで汎用性を持たせるかによります。

## システム開発に置き換えると

- プログラミングを簡易化すると処理速度が上がり、ユーザーフレンドリーな作りになる
- 開発者もプログラミングを簡易化することでデバッグの口数が減る

汎用性が落ちるデメリットに対しては...

- 要件定義次第でなんとか...

## 要件定義なんとかならない場合

- できないことはできない。すっぱり諦める。

これ大事です。

## 諦められない要件が出た場合

- 大炎上です...辛い

## 最後に

事実上の最新作EXAが2010年に発売以降続編の情報が皆無ですが、一部の熱狂的ファンは大会を開催してゲームを続けています。ゲームを盛り上げることで続編も出るかもしれません。カルネジスト、ネジらーの皆様のご協力をお願いします！

カルネージハートファンのプログラミング知識を共有しましょう！

トライポッドでお茶を濁します。

![ezgif-2-a2d6ecc38560.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133718/55516894-d933-0e22-7f9a-92ab268abf2c.gif)
備忘録

@kitagawa_takuji さんによる
NIST SP800-63B 和訳かつ要約がありがたかった。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">PDF版だと69ページあるNIST SP800-63Bの内、パスワードの定期変更についての記述は2行程度だけなのに、まるで定期変更すべきでないがすべてみたいなことになっとるな。</p>&mdash; 北河拓士🔰 (@kitagawa_takuji) <a href="https://twitter.com/kitagawa_takuji/status/983976635274858499?ref_src=twsrc%5Etfw">April 11, 2018</a></blockquote>

![Twitter.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347488/88acc610-2a10-b677-f29f-fe7ca0c7bbd3.png)
「adb shell am kill」を使って「アクティビティを保持しない」設定から卒業する

`adb shell am kill` が便利だったのでご紹介したいと思います。

# 「アクティビティを保持しない」設定 
開発者オプションにある「アクティビティを保持しない」設定、Androidエンジニアなら使ったことがあるかと思います。

この設定を有効にすることで、Activityがバックグラウンドに行ったタイミングで破棄されるようになり、Activityの破棄に起因するバグなどを確認するのに役立つ便利な設定です。:relaxed:

## ちょっと不満なところ :worried:
そんな便利な設定なのですが、

1. いちいち開発者オプションを開いてON/OFFを切り替えないといけない
2. 設定をONにすると端末全体でその設定が有効になってしまう

といった、ちょっとだけ不満に感じる点も個人的には感じています。

# `adb shell am kill`

そこで今回ご紹介するのが `adb shell am kill` です。
まぁ雑に説明するなら、好きなタイミングで特定のアプリをkillすることができる、というadbコマンドになります。

## 使い方
使い方はすごく簡単で、対象としたいアプリのパッケージ名（下記サンプルコードの `your.package.name` の部分）を指定してコマンドを叩くだけです。👇

```bash
$ adb shell am kill your.package.name
```

1つ注意点として、アプリがフォアグラウンドにある場合は効果がないので、画面切替（マルチタスク）画面などにして、アプリがフォアグラウンドにいない状態でコマンドを叩く必要があります。

# おわりに
以上、簡単ではありますが、 `adb shell am kill` に関してご紹介しました。

コマンドを叩くだけで簡単にアプリがkillされた時の挙動を確認できるので、「アクティビティを保持しない」設定を使うよりかは便利ではないでしょうか。気になった方はぜひ使ってみてください。:relaxed:
ワイ「ファイアウォール...?#後編」


[ワイ「ファイアウォール...?#前編」](https://qiita.com/ECOHOHOHOO/items/5f9b762cd1193e7d7cb0)
の続きです。

前回は、ファイアウォールについてザックリと学んだ。
IPアドレスとポート番号について通信を制限できることが分かった。

本記事では、実際にはどんな時に設定するのか？と言うところを考えていく。
特に、実際に業務上必要になったところを触れていきたい。

なお、ファイアウォールと言う単語を初めて聞いた時のワイは、何かとてつもなくカッコイイものだと思っていたのは内緒。


# Case1 ping（疎通確認）
言わずと知れた疎通確認に使うコマンドping。
クライアントからサーバに、接続しようとした時に（SSHやHTTPSなんでもいいけど）、なぜか繋がらない！と言う時に使うことが多い。

ネットワーク的にそもそも到達可能か？的な観点で使うけれども、WindowsOSではファイアウォール機能のデフォルトで破棄されるはず。

なので、ping応答しないんだけど。。。。となったらまずは相手のサーバのファイアウォール設定を確認した方が良い。

なお、試しに”qiita.com”のWEBサーバにpingを打つと、何も帰ってこない。
”www.google.com”とかに向けてping打つと帰ってくる。

```
$ ping www.google.com
PING www.google.com (216.58.197.132): 56 data bytes
64 bytes from 216.58.197.132: icmp_seq=0 ttl=51 time=47.465 ms
64 bytes from 216.58.197.132: icmp_seq=1 ttl=51 time=64.642 ms
・・・
$ ping qiita.com
PING qiita.com (13.114.166.234): 56 data bytes
Request timeout for icmp_seq 0
Request timeout for icmp_seq 1
・・・
```

ちなみに、ping応答を無条件に許可すると言うのはセキュリティ上の論争があるようで、組織のセキュリティポリシーに準じたほうがよさそう。

# Case２ HTTPS,SSH,DB接続（よく使うやつら）
ここら辺んは頻出するので、大体見落とされることはやや少なめだと感じています。
なお、ポート番号はデフォルトの値を書いてます。

■HTTP/HTTPS：80/443port 
WEBサービスを動かそうと思ったら、該当ポートを解放する必要があります。
そういえば、先日もできたばかりのWEBサービスを導入したけど接続できないと言う問い合わせを受けた。（若手メンバーから）
普通にWindows Firewallで443port空いてなかったよ！

■SSH：22port
SSH接続しようと思ったら、該当ポートを解放する必要があります。

■DB接続:1521/5432/3306port
DBへ接続しようと思ったら、該当ポートを解放する必要があります。
なお、ポート番号は製品によって違います。
Oracle DB（1521）
PostgreSQL（5432）
MariaDB/MySQL（3306）

# Case３ FTP、SMB接続（珍しいやつら？）
業務上では時々しか扱うことがなかった、プロトコル達。
■FTP
ファイル転送とかしたい時に、該当ポートを解放する必要があります。
FTPでは２つの接続モードがあって、以下のサイトがとてもわかりやすいです。
http://naoberry.com/tech/ftp-active-pasv/

まとめると、サーバ側はこんな感じです。
・Active
　21port
　*ただしクライアント側の任意のポートへ接続しに行く

・Passive
　２１port + 1024以上の任意のポート

とてもややこしいので要注意です。

■SMB：４４５port
Windowsファイル共有したい場合、該当ポートを解放する必要があります。
プロトコルのバージョンが低いと、UDPの137、138、TCPの139portも解放する必要があるみたいです。


#話を戻してクラウドサービスの場合
前の記事では記載したが、仮想マシンを作成するにあたり、主要なクラウドサービスを利用する場合、OSレベルでのファイアウォールだけでなく、サブネットやインスタンス毎にもファイアウォールが存在する。

要はファイアウォールの設定は２回必要だよと言うことになる。

じゃあ、２回作業すればイイじゃん！と言う話ではあるが、手順が増えたりした場合、都度整理しておかないと作業ミス・作業漏れが発生することが多いです。

また、ファイアウォールの設定に限らないが、`自動化できるものは自動化して、人の手がいるものは手順書の作成`などに注力しましょう。


#終わりに
今の時代はファイアウォールの設定１つだけやればいいというのはあまりないと思うので、読んだ人が混乱しないようになることを祈ります。

ワイは混乱したんや・・・。

以上。
オリジナルキーボード作成中（未完成）

この記事は[キーボード #1 Advent Calendar 2019](https://adventar.org/calendars/4117)の6日目の記事です。
普段仕事ではレツプリを使っています。
新しくキーボード作りたいなー、せっかくだからオリジナルのセカンドキーボードを作ろうという感じで作り始めました。
![IMG_0400.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356727/21ff91f8-6037-87f3-3ec5-44ac9b4d4cea.jpeg)
# どんなのを作るか
やりたいことを一通り詰め込んでみたら以下のような感じになりました。

* 一体型
* 空中配線
* バックライト
* 無線
* OLED
* 格子配列
* 凸型配置のアローキー
* 左下スッキリ
* 薄型

で、これらを盛り込めるように考えたキーボードが下の図です。
![my_handwired_keyboard.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356727/6c2335f5-8b82-2023-4b5a-c822d6490c46.jpeg)
左上にBLE-micro-pro、上部分に電池、左下にOLEDを置く予定です。
余白が寂しいのでてきとうにハニカム模様の刻印も入れてみました。
本体はアクリル一枚で配線はむき出し、空間はゴム足でなんとかすることで薄さを実現します。

また、今回BLEかつ光らせたりOLEDを付けたくてどうしようと悩んだ（ボタン電池では光らない）結果、小型のモバイルバッテリーで電源供給するようにしました。
無骨だけどしょうがない。
![IMG_0401.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356727/eba1dbb6-c229-7257-33c0-7e120b823f87.jpeg)
# 制作過程
まずはレーザーカッターでアクリル板を切断。
今回は5mm厚のガラスカラーを使用しました。色がかっこいい！！
![IMG_0298.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356727/d66d7d45-da94-8fcb-2e88-791c9fdc9a1b.jpeg)
出来上がり。シールを剥がしてから彫刻したらすごい汚れた…
![IMG_0300.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356727/cce786a9-ee03-34e9-9e8c-26cbbd2b251f.jpeg)

次は空中配線をしていきます。
空中配線の仕方は[ここ](http://www.masterzen.fr/2018/12/16/handwired-keyboard-build-log-part-1/)を参考にしました。

まずはキースイッチ分ダイオードをこんな感じにする苦行をします。
![IMG_0347.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356727/20d54488-a7e7-177a-f57c-5f045441fdf4.jpeg)
これらをキースイッチの足にはんだ付け。はんだが溶ける煙でアクリルが汚れる…
![IMG_0350.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356727/63e7ec50-9df5-2415-137c-4ffe0584e0ab.jpeg)
次に横を繋いでいきます。ワイヤストリッパーはすごい便利だなと思いました。
![IMG_0399.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356727/50d869b9-2253-e2db-6c12-5f9d93dd1199.jpeg)
# 残り作業
残念ながら今回の記事はここまでです。
年内に完成させたい。
LEDの配線は[ここ](https://geekhack.org/index.php?topic=94258.0)を参考に進めていこうと思っています。
空中配線が重なりあって果たしてゴム足の高さが足りるんだろうか:thinking:
# ここまでの感想
空中配線は大変なので次は基板を作りたい。


この記事はMacBook Air (13-inch, Mid 2013)で書きました。
bashのプロンプトを見やすくシンプルカラーに変更


# 参考

[こちらが参考になりました！](https://amzn.to/2ZRrTRr)

# 方法

.bashrcに追記します。数字の37はカラーコードで30~37の中から選べます。ターミナルに合った好みのものを選んでください。

```terminal
export PS1='\n \[\e[1;37m\]\w \n \[\e[1;37m\]> \[\e[m\]
'

[変更後(homeディレクトリ)]
 ~
 >