OmniAICreator/Qiita-1.07M huggingface dataset:
気温を計る

IoTで一番身近な対象が気温の測定ではないだろうか。

気温の測定は季節のうつろいによる変化を知り健康管理にも有効かもしれない。

気温の観測はまずは気候による変化を知ることが重要で、生活環境の確認は二次的なものではないかと思う。

自宅内でロギングすればIoTする必要はないが、ロギングのために大きなサーバーを24時間稼働させると多く電気を使ってしまい、IoTの方がエコになるケースもあるだろう。またデータのバックアップなど考えるとIoTの方が有利だったりする。

気象庁が提供しているデータを利用する方法もあるが、観測地から離れている場合など、自分で測定してみたいと思うこともあるかもしれない。また気象庁が提供しているデータは使い勝手が悪かった記憶もあります。

業務用の観測機器は高額なものが多く個人で利用するのは難しく自作することを考えてみる。業務用の観測機器が高額なのは、気温といえども場合によっては人の生命に関わることもあり、信頼性を担保する為だと思われる。

~~[観測データの一般公開は違法](https://qiita.com/rukihena/items/85b5d719949316b83442)になるようなので注意が必要です。~~

「気象観測の手引き」という資料が気象庁から提供されているが、およそIoTとは掛け離れた資料となっている。

この資料によると気象観測は屋外の百葉箱などで行うのが正しいらしい。しかしながら気象庁でもすでに百葉箱は使っておらず、強制通風筒というセンサーの入った測定機器を使っているようです。

IoTの場合、屋外での測定は問題が2つある。一つは電源の問題で、もう一つは通信の問題である。

![TempIoT.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/82c16c06-6e0e-78f1-23d9-e3f4133d27ed.png)

電源はAC電源を引き延ばして供給する方法と、バッテリーを使う方法がある。屋外にAC電源を引き出すは難しいケースも多く、またバッテリーは切れてしまった時のダウンタイムが発生する可能性がある。

[NETTOMO](https://www.netatmo.com/)という商品の屋外モジュールは単三が2本のようだが、持ちが悪いという報告がネットで散見される。

ウェザーステーションはLa Crosse社のWS-2308やOregon Scientific社のWMR100などもあるようです。

太陽電池でキャパシタなどに充電を行いパッテリー交換が必要ないモジュールが理想だが、通信が電気をくうので、実現はかなりハードルが高い。太陽電池はいつも充電できるわけではなく、ワーストケースでの設計が必要になる。

通信は有線で接続するパターンと無線で接続するパターンが考えられる。これも有線を屋外に引き出すのは難しいケースがあり、無線の場合sakura.ioなどのパブリックな通信回線を使うとコストがかかり、プライベートな通信回線だと親機が必要になる。プライベートな接続はBluetoothやWiFiが考えられる。

センサーだけを室外に伸ばす方法はアナログ出力やI2Cのままでは能力的に現実的ではない。マイコンを使いセンサーの値をRS485で送るような製品があるようだ。

屋外の設置は防滴や暴風で飛ばされないような固定などの課題もある。また高温により機械の寿命が短くなったり、氷点下の温度になり動作しないなどの問題もあるかもしれない。

![TempIoTINT.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/7f47dd2b-c8e1-e2a1-b07c-93ee1c24bb3b.png)

室内での測定を考えてみると、冷暖房を使う部屋やキッチンなどはあまり適さないと思う。また玄関や窓を開け閉めするような部屋も適さない。

温度を計測するセンサーはLM61のようなアナログ出力のものとBMP180のようなI2Cインターフェースのものがある。arduinoのようなマイコンにはアナログ入力があるが、32BitのSOCはアナログ入力がないものがほとんどでそのままは使えない。I2CのインターフェースはSOCがI2CをサポートしていなくてもGPIOのBitbangで利用することができる。[アナログ出力をマイコンでシリアルに変換するモジュール](https://qiita.com/yamori813/items/d9230337bff090556111)を作ったことがありました。

I2Cの温度センサーはLANG-SHIPさんのページでいろいろ調べられていました。

https://lang-ship.com/blog/?p=502

センサーをデバイスの中に入れてしまうと、デバイスの発熱に影響されるのでよくない。

気象庁の観測は毎時0分の値になるが、IoTの場合時間内に複数の計測を行うことができる。通常は平均値を使うことになるがその影響を考える必要があるかもしれない。

台風以来[BMP180を南向きのリビングに置き蟹さんのmruby](https://qiita.com/yamori813/items/c2cb30fb48b216ab89e9)から気温と気圧をThingSpeakに投げているのだが、いつの頃からか12時に奇妙なピークが見られるようになった。ピークが出ない日もある。ThingSpeakからデータをダウンロードしてみて確認してみたが、12時台に異常に高い値がある。気圧にはこれほど大きな変化は出てない。

![スクリーンショット 2019-12-15 17.58.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/a16a4eb6-43f9-d47e-af85-a0f194d744b3.png)

この日は昼の間外出していたので、昼食の準備などの影響はないはずである。

いろいろ考えてみたところ、日光の直射が当たっていることを思いつき、今日確認したら当たりでした。

![IMGP0016.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/ee2f4220-2ad5-77b0-1050-885ac045f56f.jpeg)

冬至に近づき、室内に直射が入る部分が増えたことが原因です。以前は日が高かったので、この位置は直射は入らなかったと思います。ピークが出てない日は曇りや雨の日だったのだと思います。

![TempIoTGESHI.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/92332cd6-89ac-48b3-2055-168ae1432dfa.png)

近年温暖化で、とんでもない高温の夏の日がある。温泉卵は60度のお湯で作る。温泉卵を冷やしても生卵にもどらないので、温泉卵にならないように注意してください。

気象観測はいろいろ楽しいので、ぜひ皆さんも試してみてください。

参考

[気温に関する用語](http://www.jma.go.jp/jma/kishou/know/yougo_hp/kion.html)
Linux

Linuxについての基礎知識を中心にまとめていきます。


##Linuxとは

linuxは無償で使用可能なオープンソースのOSです。またwindowsやmacなどのOSとは異なり、最小限の機能しかないため軽量であったり、OS自体の中身を書き換えられたりするのが特徴としてあげられます。このような背景もあり、PC分野だけでなく、サーバーの分野でも大きなシェアを占めているのがLinuxです。あの有名な「android」もLinuxをベースに作られたOSみたいですね。偉大。

##Unix
Unixは現存する中で最も古いOSであり、現在もlinuxと同様に多くの場面で使われています。Linuxを知る人なら、一度はUnixを聞いたことがあるのではないでしょうか。それもそのはずでLinuxは無償で誰でも使えるようにUnixを参考にして作られているUnix系OSなんです。「ios」はUnixをベースに作られているみたいですよ。

##CUI操作

私たちがWindowsやOS Xで慣れ親しんでいるような、ウィンドウを表示してマウスで操作するスタイルが「GUI（Graphical User Interface）」です。GUIに対して、キーボードでコマンド（command：命令）を入力し、その結果を文字で受け取るスタイルが「CUI（Character User Interface）」になります。※CUIは、「CLI（Command Line Interface）」と呼ばれることもあります。
LinuxはGUIでもCUIでも操作が可能です。

**CUIに関する記事**

CUIを中心にコマンドなどをまとめている２記事を下記に貼ります。

・Linuxコマンド入門　
　https://26gram.com/linux-command
・Linuxショートカット総まとめ
　https://eng-entrance.com/linux_shortcut


基礎的な知識と操作に関しては上記の２記事含めた内容である程度カバーできると思います。
idman のソースコードを doxygen で見る

今年はアドベントカレンダーで BitVisor のID管理（以下、idman）を活用する記事を書きたいと思ってますが、そのまえに idman のソースコードを読む（見る）方法をご紹介したいと思います。すでに知っている方はごめんなさい。

# はじめに

BitVisor の idman/ 以下のソースコードは doxygen 形式でコメントが書かれています。簡単にいうとプログラムのコメント欄にタグ付で引数の目的なんかを書いておくと html に整形して自動的に実装仕様書みたいなものを生成してくれる便利ツールです。目的は JavaDoc と同じですが多言語に対応しています。Doxygen の詳細は [このへん](http://www.doxygen.nl) を参照してください。

# idman とは

BitVisor には idman/ と呼ばれるディレクトリがあり、そこにはハイパーバイザからカードリーダ経由でICカードにアクセスするライブラリが入っています。国家公務員身分証ICカードに BitVisor 専用AP（アプリまたはアプレット）を書き込んでおき、それを使って BitVisor 起動時のユーザ認証や IPsec VPN モジュールの鍵交換でのユーザ認証（リモートアクセスVPNの認証的なもの）をするのに使っていたようです。いわゆる公開鍵認証基盤（Public Key Infrastructure, PKI）アプリをつくるためのライブラリといえると思います。

# Doxygen をつかう
まず doxygen をインストールします。graphviz は関数の呼び出しグラフを作るのに使います。

```
$ sudo yum -y install doxygen
$ sudo yum -y install graphviz graphviz-gd
```

最初に bitvisor/Doxyfile の以下の部分を修正してください。PROJECT_NAME のところに Secure VM って書いてあるのが懐かしいですが、html ページに表示されますから現在の名前に変えておきましょう。

``` 
PROJECT_NAME           = BitVisor
INPUT                  = idman
RECURSIVE              = YES
CREATE_SUBDIRS         = YES

以下の３つは Graphhviz の呼び出しグラフ作成用
HAVE_DOT               = YES
CALL_GRAPH             = YES
CALLER_GRAPH           = YES

```

bitvisor/Doxyfile のあるディレクトリで doxygen を実行します。グラフなしだと一瞬で html が作られるのですが、グラフがあると数分間待たないといけません。
 
```
$ doxygen
Generating namespace index...
Generating graph info page...
Generating directory documentation...
Generating index page...
Generating page index...
Generating module index...
Generating namespace index...
Generating namespace member index...
Generating annotated compound index...
Generating alphabetical compound index...
Generating hierarchical class index...
Generating member index...
Generating file index...
Generating file member index...
Generating example index...
finalizing index lists...
lookup cache used 1540/65536 hits=14109 misses=1613
finished...
```

html が出力されたのでウェブブラウザで documents/html/index.html を開きます。

![Doxygen.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550398/80f9073e-035d-4ee0-a61c-19add5df3c5d.png)

ファイル名をクリックして関数のコメントなんかを眺めていきましょう。以下のようにコメントは短いですが十分にわかりやすく書けている感じがします（尊敬の遠い眼差し）。

![Comment.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550398/921af51d-86f5-eb3e-ed21-ae72710139a9.png)

以下のように関数ごとに CALL GRAPH と CALLER GRAPH が表示されます。

![Graphviz.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550398/6c06a3bb-a521-6760-a386-652cbda2730e.png)

BitVisor の idman はもともと Linux のオープンソースのライブラリ pcsc-lite, pcsc-lite-ccid, libusb を参照して実装されています。ですから、BitVisor の pcsc, ccid, pkcs11 なども同じようにライブラリごとに独立していて、再利用しやすいように実装されているんじゃないかなと思います。どちらにしてもこのようなグラフは全体を理解するのに役立つと思います。

# おわりに
ソースコードだけで読むのも味わい深いですが、BitVisor では ID管理（idman）だけちょっとビジネスっぽい雰囲気を醸し出していますから Doxygen でコメントを書いておいてもらってよかったですね。次の記事で idman 以下のライブラリの目的とか使い方を紹介できたらと思ってます。
SalesforceでBtoBtoCサービスのSales-CRM及びCSオペレーションシステムを構築する

CBcloud Advent Calender 8日目の記事です。

今回はSalesforceというCRMツールを利用して、BtoBtoCサービスのデータ可視化やオペレーション構築、CRM構築周りのお話をします。
SalesforceはあくまでもCRMツールですが、ご利用各社で様々なカスタマイズがなされ、結果、様々な役割を担っていることかと思います。
そこで、私は、CRMツールの側面とCSオペレーションツールの側面を併せ持った、データ集約基盤としてのSalesforceを作った話し、そして、やって見たところの反省点を書いていきたいと思います。

# 前提となる用語整理
- BtoBtoC: 自社が企業顧客と一般顧客に対してサービスを提供している状態
- データ集約基盤: 単純にRDBでもよく、サービスだけでなく、営業で生まれる情報、オペレーションで生まれる情報を、なんらかの方法で繋がった方法で利活用できるシステム
- オペレーションツール: 主に今回はCSの対応を支えるツールとする。応対に必要な情報が見やすく、かつ何人もの対応を連続して対応できるUIを持ったツール。

# 構築したシステムについて
企業顧客をSalesforceの取引先と取引先責任者に登録し、一般顧客データは全てカスタムオブジェクトで作成した。
電話応対はコールシステムをsalesforce上に表示して対応したが、
この時コールシステムが、salesforceの取引先責任者とリードにしか活動を作成できなかったため、カスタムオブジェクトの一般顧客データと同等のリードを作成し、電話番号で繋ぐことでカスタムオブジェクトから活動を辿れるようにした。
ほかにもサービス起因の情報があるが、顧客情報に紐づける形で複数作成している。

# システム設計の背景
Salesforceには顧客の情報をとろくする場所として取引先責任者とリードがある。
一般にsalesforceを利用する場合は顧客の情報を取引先責任者に入れる。
しかし、BtoBtoCのようなサービスの場合は顧客属性が複数あるため、単純に取引先責任者を利用できない。
切り出すか、属性情報を持たせ、取引先責任者に入れるパターンを考えたが
情報を一気に入れた場合、分ける方が辛く、マージする方が楽そうであるため今回は初めから切り出して作成した。
また、コールシステムなどの外部サービスを用いる時、標準のオブジェクトを採用しておけば
外部サービスを最大限生かすことができるため、できるだけ標準オブジェクトを利用しておいた方が良い。

# よかった点
今回の構築は２人でsales側とcs側を構築し
運用開始まで、sales側が2週間、cs側が３週間ほどかかった。
速度的にはシンプルに作り、だいぶ早く回すことができたと思っている。
また、シンプルな分、標準的な使い方しかしておらず、運用について悩むことが比較的少なかった。

# 反省点
シンプルに作ろうとしたため、一般顧客側は切り出してカスタムオブジェクトとして作った。
しかし、コールシステム連携やMAツール連携を考えた時、どうしてもリードを介さなければならない
など、後々に、リードを経由すればいいと思っていたものが管理コストを上昇さているのを感じている。

# 改善案
salesforceは２方向の顧客に対応していない。そのため、上記のような対応を取る必要がある。
今回は、工数をかけないようにトリッキーなことはしなかったが、もう１つの選択肢として
salesforceを2インスタンスにするのが、なかなか良いのではと考えている。

salesforceを２インスタンスにし、それぞれの顧客データは、それぞれの取引先責任者に入れる。
そして、両方が利用するデータはどちらかに寄せて、お互い外部オブジェクトで必要なデータを参照し合う。
これにより、各インスタンスが応対する顧客それぞれに特化できるためシンプルになる。
外部ツールについても取引先責任者を利用できるため、最大限の利活用が可能となる。

また、料金面でもsalesforceはインスタンス課金ではなくアカウント課金のため
DB費用など多少の料金増は考えられるが、基本的に料金が変わらない。

その他の外部ツールについても
コールシステムはコールシステム側のアカウント数や電話料金
また、MAツールについてはリード数による課金となることが想定される。
そのため、こちらも基本的に料金が変わらない。

# おわりに
salesforceはプログラムをかけば、本当に何にでも利用できてしまう。
そのため、どうやって使うのかを考えるのが一番難しい。

今回は、BtoBtoCというSalesforceにとって想定をオーバーするシーンでどのように利用できるか考えた。
まだ、実際に構築したわけではないため可能性でしかないが
私にとって、開発速度、シンプルさ、料金を加味し、業務に必要な情報を集める上で一番美しい設計だと考えている。

ぜひ、皆様の意見を聞かせてください。
Mysqlのチューニングまとめ

Mysqlのチューニングのよく使う手段をまとめる

## 環境
AWS RDS
mysql: 5.7.23
パフォーマンスインサイト有効にしてる

# SlowQuery
## 設定

| slow_query_log | ON | 説明 |
|:--|:--|:--|
| slow_query_log_file | /var/lib/mysql/slow.log | logファイルのパス |
| log_output | TABLE | mysql.slow_logテーブルへ出力する |
| long_query_time         | 5 | 5秒超えると、slow_queryと判定する |

## 本番DBで何回SQL何回実行しても遅い
index追加、アプリの改善が効きそう

## 本番DBでの実行は一時的遅い
### lock waitを監視する
パフォーマンスインサイトでlocks周りのメトリクスでlock発生してかどうかを確認

lock発生した場合は、どのQueryかを特定する

```sql
SELECT r.trx_id waiting_trx_id,  
       r.trx_mysql_thread_id waiting_thread,
       r.trx_started waiting_started,
       r.trx_tables_in_use waiting_tables_in_use,
       r.trx_query waiting_query,
       b.trx_id blocking_trx_id, 
       b.trx_mysql_thread_id blocking_thread,
       b.trx_started blocking_started,
       b.trx_tables_in_use blocking_tables_in_use,
       b.trx_query blocking_query
   FROM       information_schema.innodb_lock_waits w
   INNER JOIN information_schema.innodb_trx b  ON  
    b.trx_id = w.blocking_trx_id
  INNER JOIN information_schema.innodb_trx r  ON  
    r.trx_id = w.requesting_trx_id;
```
https://dev.mysql.com/doc/refman/5.6/ja/innodb-information-schema-examples.html
こちらを参考に、jenkinsかlamdaで上のSQLの結果をCSVで溜め込んで調査する

blocking_query見つかったら、そちらを改善する

### buffer pool
パフォーマンスインサイトでこの二つ見る

| メトリクス名 | 説明 |
|:--|:--|
| innodb_buffer_pool_hit_rate | buffer poolへのヒット率、基本は99%以上ある、低い場合はbuffer poolサイズをあげた方が良い |
| innodb_buffer_pool_usage | buffer pool利用率、高くなると、余裕を持って、buffer poolサイズをあげた方が良い || innodb_buffer_pool_hit_rate | buffer poolへのヒット率、基本は99%以上ある、低い場合はbuffer poolサイズをあげた方が良い |
Ubuntu の xkb のキーボード設定を直したい

# 概要
キーバインドを色々いじろうと xkb の設定ファイルをいじっていたら設定が破損してしまい、

- 立ち上げるときにUbuntuロゴからログイン画面が表示されるまでの間に何やらメッセージが表示される
- 日本語 JIS キーボードのレイアウトが認識されない(USキーボードになってしまう)

という状況になってしまったので、試行錯誤の末修復した話。
メモ書きとして残しておきます。

# 環境
```bash

$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04.3 LTS"
```

# 対処
結論から言うと、`xkb-data` パッケージをインストールし直したら直りました。

```bash
$ sudo apt-get install --reinstall xkb-data
$ reboot
```

# なにをしたら破損したか
`/usr/share/X11/xorg.conf.d` 以下に下手な設定ファイルを作成したら、冒頭に書いたような症状になってしまいました。  
作成したのは次のようなファイルです。

```
Section "InputClass"
    Identifier "keyboard defaults"
    MatchIsKeyboard "on"

    Option "XkbRules" "evdev"
    Option "XKbModel" "pc105"
    Option "XkbLayout" "jp, us"
    Option "XkbVariant" ","
    Option "XkbOptions" "caps:hyper,hjkl:direction"
    # 自分で作成した"hjkl:direction"というオプションを読み込ませようとした
EndSection
```
Laravel で ORバリデーション

バリデーションを記載していると、orのバリデーションが欲しくなる時がたまにある。
だがLaravelにOrのバリデーションが存在しない。
正規表現で対応できることも多いが、今回は既存バリデーションをそのまま使用したかったのでor判定する新しいバリデーションを作成してみた

# ORバリデーション
メッセージはもうちょっと改良の余地あり。
エラーになったバリデーションメッセージを連結するほうがいいかも。

```php:OrRule.php
namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;
use Illuminate\Support\Facades\Validator;


class OrRules implements Rule
{
    private $rules = [];

    function __construct(Array $rules)
    {
        $this->rules = $rules;
    }

    /**
     * バリデーションの成功を判定
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        foreach ($this->rules as $rule) {
            $validator = Validator::make([$attribute => $value], [
                $attribute => $rule
            ]);

            if (!$validator->fails()) {
                // エラーなしなら終了
                return true;
            }
        }
        return false;
    }

    /**
     * バリデーションエラーメッセージの取得
     *
     * @return string
     */
    public function message()
    {
        return ':attribute は正しい形で入力してください';
    }
}
```

```php:使い方
// 画像ファイルまたはURLまたはbooleanなら通す ルール定義
[
    'image' => [new OrRules(['mimes:jpeg,bmp,png', 'url', 'boolean'])]
]
```

# 開発経緯
開発経緯を少しだけ。

ちょっと仕事で複数画像を順番を保持しつつ登録処理を書かなければならないことがあった。
登録するときはすべて新規登録のため、画像のルールもmimesだけで問題なかったが・・・

**問題は更新するときだった**

# 画像の更新対象がわからない問題
更新するときは以下の３つの状態をLaravel側で認識しないといけなかったため、単純にmimesだけ通すルールだと判断ができなかった。

- 「どの画像が更新されたか」
    - これはmimesで問題ない
        - input に画像がセットされるため
- 「どの画像が更新されていないか」
    - これはどうやって？
- 「どの画像が削除されたか」
    - これはどうやって？

色々考えた結果、以下の考えのもと処理を作成。

- 「どの画像が更新されたか」
    - これはmimesで問題ない
        - input に画像をセット
- 「どの画像が更新されていないか」
    - **登録画像パスのままなら更新されていない**
        - input に登録画像URLをセット
- 「どの画像が削除されたか」
    - **falseなら削除されている**
        - 画像の設定が削除されたらinput にfalseをセット

このため、「mimesまたはurlまたはboolean」のバリデーションルールが必要になり、
上記に示したORバリデーションを作成することになった。

正直、このやり方がベストなのかどうかまではわからん。。。
PostgreSQLでオートインクリメントの初期値を変更する

## 概要
システム移行後にデータ登録した際にエラーを吐いたので原因を調べてみたら、idの衝突を起こしていた。
解決方法としてはシーケンスの位置を調整してあげればよい。

## バージョン等
PostgreSQL:11.x

## 解決方法
下記SQLを実行する

```sql
-- 名前は各テーブルのシーケンス名に変更してください
SELECT setval('users_id_seq', 50000)
```
FuelPHPでのMySQL接続時にThe server requested authentication method unknown to the client [caching_sha2_password] となった場合に対処してみた

## 概要
FuelPHPでMySQLに接続時、掲題のエラーが発生した場合の対応法です。

## 環境
- MySQL v8.0
- PHP 7.3.12

## エラー事由
MySQL8.0でのデフォルトの認証方式は「caching_sha2_password」であるが、PHP側では対応がされていない。
そのため、認証方式が異なるためにエラーが発生する。

## 対応方法
MySQLに接続するユーザーの認証方式を「mysql_native_password」に変更します。

### 1.ユーザー単位での認証方式の変更
先ず現状の認証方式を確認します。

```mysql
mysql> SELECT user, host, plugin FROM mysql.user;
+------------------+-----------+-----------------------+
| user             | host     | plugin                |
+------------------+-----------+-----------------------+
| admin            | %     &nbp;   | caching_sha2_password |
| mysql.infoschema | localhost | mysql_native_password |
| mysql.session    | localhost | mysql_native_password |
| mysql.sys        | localhost | mysql_native_password |
| root             | localhost | caching_sha2_password |
+------------------+-----------+-----------------------+
5 rows in set (0.00 sec)
```

現状を確認後、指定したユーザーの認証方式を変更します。

```mysql
mysql> ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'password';
Query OK, 0 rows affected (0.19 sec)
```


### 2.デフォルトの認証方式の変更
MySQLへのデフォルトの認証方式を変更します。

```/etc/mysql/conf.d/my.conf
[mysqld]
# デフォルトの認証方式を変更(デフォルトは「caching_sha2_password 」)
default-authentication-plugin=mysql_native_password
```
日本のスマホのOSシェアAndroidが57.2%、iOSが42.8％について思うこと

MMD研究所調べで
[日本でのスマホのOSシェア、Androidが57.2%、iOSが42.8％に](https://iphone-mania.jp/news-269382/)
が発表されました。

iPhoneのシェアは3.9ポイント減少で一見Appleの下火にも見えるが、
驚異的なのはメーカーとしてはappleの圧倒的独壇場ということです。
世界的にAndroidのシェアNo1のSamsungでさえも日本では10%弱です。

肝となるのは「メインで使っている」というところも気になるところです。
メインで使っているということはサブでもiPhoneを持っている人も少なからずいると思います。

そしてこの数字の驚くべき点はAndroid端末よりiPhoneの方が高価格帯にも関わらずです。

性別・年代別のグラフも面白いです。
10代女子のiphone率は圧倒的、インスタ・tiktokなどのSNSの影響はあるでしょう。
10代男子もiphone率高いです。
また他人と同じ端末を利用したいという人も多いはず。

「次も利用するか」は実質満足度を表すと思っています。
iPhone利用者の方がポイントが高いです。

結果Apple強し。

かなという印象です。

来年2020年に噂されているiPhone12も5Gの対応端末予想やiPhoneSE2など
最近はiPhon8からX,Xs,11とラインナップをエントリーモデルからプロ仕様まで幅広く用意している
Appleなので今後5年ほどはまだまだ安定でしょう。

GAFA強し。
強化学習３７　Atariのwrapperで自動スタートを作る

中学生から大学生までのAI初学者を対象にしています。

OpenAIのATARIを使おうとすると、ゲームの特殊性をカバーするためのwrapperが欲しくなります。
　例えば、ブロック崩しでは、ライフポイントが５に初期設定されていますが、最初とライフポイントが減った時点（失敗したとき）にfireボタンを押さないとゲームが動きません。
　これを超えないと、機械学習が全く進まないというアホみたいなことになります。個人的には時間の無駄です。
　そもそもは、FireResetEnvというwrapperが準備されていますが、ブロック崩しでは、ライフが減るごとには動かないので、１度失敗すると、ずっとそのままになります。
　そこで、下のようなラッパーを書いてみました。

```python
class FireResetEnvAuto(gym.Wrapper):
    def __init__(self, env):
        """Take action on reset for envs that are fixed until firing."""
        gym.Wrapper.__init__(self, env)
        assert env.unwrapped.get_action_meanings()[1] == 'FIRE'
        assert len(env.unwrapped.get_action_meanings()) >= 3
        self.lives = 0

    def reset(self, **kwargs):
        self.env.reset(**kwargs)
        self.lives = self.env.unwrapped.ale.lives()
        obs, _, done, info = self.env.step(1)
        if done or info.get('needs_reset', False):
            self.env.reset(**kwargs)
        obs, _, done, info = self.env.step(2)
        if done or info.get('needs_reset', False):
            self.env.reset(**kwargs)
        return obs

    def step(self, ac):
        lives = self.env.unwrapped.ale.lives()
        if lives<self.lives:
            self.lives=lives
            return self.env.step(1)
        return self.env.step(ac)
```
殆どは、chainerrl/wrapper/atari_wrapper.py
でちょっとだけ付け足しただけです。
これが、chokozainerrlです。
Eyebrow Headline (WIP)

原文： https://uxmovement.com/content/how-you-can-aid-user-scanning-by-using-eyebrow-headlines/
日文： https://uxmilk.jp/75005

其他參考：

https://twitter.com/steveschoger/status/956229542288543744
https://jsfiddle.net/tiffhockin/t4svvroq/
https://www.w3.org/TR/html50/common-idioms.html

(WIP)
年末まで毎日webサイトを作り続ける大学生 〜59日目 オブジェクト(プロトタイプベース)の復習〜

##はじめに
こんにちは！@70days_jsです。

昨日覚えたオブジェクト（プロトタイプベース）の復習をしました。

59日目。(2019/12/16)
よろしくお願いします。

##サイトURL
https://sin2cos21.github.io/day59.html

##やったこと
オブジェクト（プロトタイプベース）の復習です。
男性用の名前、女性用の名前のデータを用意しておくと、ランダムでオブジェクトを生成してくれます。
（リロードごとにランダムに表示されている）

![test3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/516248/2d05a912-7989-dea8-a30c-ba6785a715ca.gif)

html↓

```html
 <body></body>
```

css↓

```css
.page {
  display: inline-block;
  width: 200px;
  height: 200px;
  background-color: red;
  margin: 30px 10px 10px 10px;
}
```

JavaScript（72行あります）↓

```javascript
let canvas = document.getElementById("canvas"),
  order = 0,
  humanName = [["men1", "men2", "men3"], ["women1", "women2", "women3"]],
  men = humanName[0].length,
  woman = humanName[1].length,
  num = men + woman,
  hairetu = [],
  menOrwoman = ["men", "woman"];

function Human(id, sex, name) {
  this.initialize(id, sex, name);
}

Human.prototype.greet = function() {
  let idDiv = document.getElementById(this.id);
  idDiv.innerHTML =
    "Hello, I'm " +
    this.name +
    "<br>My sex is " +
    this.sex +
    "<br>id is " +
    this.id;
  if (this.sex === "men") {
    idDiv.style.backgroundColor = "blue";
  }
};

function render() {
  hairetu.forEach(function(object) {
    object.greet();
  });
}

Human.prototype.initialize = function(id, sex, name) {
  this.sex = menOrwoman[sex];
  this.id = id;
  this.name = name;
};

function createHuman() {
  let id = order;
  let sex;
  if (men <= 0) {
    sex = 1;
    woman--;
  } else if (woman <= 0) {
    sex = 0;
    men--;
  } else {
    sex = Math.round(Math.random());
    if (sex === 0) men--;
    if (sex === 1) woman--;
  }
  let number;
  if (menOrwoman[sex] === "men") number = Math.floor(Math.random() * men);
  if (menOrwoman[sex] === "woman") number = Math.floor(Math.random() * woman);
  let name = humanName[sex][number];
  humanName[sex].splice(number, 1);
  let human = new Human(id, sex, name);
  hairetu.push(human);
  let div = document.createElement("div");
  div.setAttribute("class", "page");
  div.setAttribute("id", order);
  order++;
  document.body.appendChild(div);
}

for (var i = 0; i < num; i++) {
  createHuman();
}

render();
```

ポイントはコンストラクターを用意して、initializeで初期値を入れて、好きなメソッドをprototypeを通して入れるということです。

コンストラクター↓

>function Human(id, sex, name) {
  this.initialize(id, sex, name);
}

initialize↓

>Human.prototype.initialize = function(id, sex, name) {
  this.sex = menOrwoman[sex];
  this.id = id;
  this.name = name;
};

メソッド↓

>Human.prototype.greet = function() {
...
}

今回男女の名前は、多次元配列に入れています。↓

> humanName = [["men1", "men2", "men3"], ["women1", "women2", "women3"]]

humanName[0]が男で、humanName[1]が女です。
ここに好きな名前を入れていくと、リロード時にランダムでそれぞれの名前のオブジェクトを生成してくれます。

##感想
年末までにインベーダーゲームとオセロを仕上げたいですね。
オブジェクト指向が習得できればできるような気がする...かも。

最後まで読んでいただきありがとうございます。明日も投稿しますのでよろしくお願いします。
JPAAWG 2nd General Meeting 参加レポート

2019.11.14-15 開催された [JPAAWG 2nd General Meeting](https://meetings.jpaawg.org) で@qualitia_cdevが注目した内容を簡単にまとめます。


#### JPAAWG 2nd General Meeting まとめ
##### 1. DMARCの普及
   - 昨年米国で政府政策発表の後、普及がどんどん進んでいる
   - 欧米中心に普及されているが日本ではまだの様子。その理由についてJPAAWGのOpen Round Tableでも議論された

##### 2. ARCのRFCリリース
   - 2019.7月 RFC8617がリリース
   - リンク [https://tools.ietf.org/html/rfc8617](https://tools.ietf.org/html/rfc8617)

##### 3. BIMIの台頭
   - Yahoo!USが試験運用中
   - Googleが2020年導入予定
   - RFC化が進んでいる

##### 4. パスワード付きZIPファイル排他の動き
   - 世界から見ると日本独特の文化
   - ISP中心にやめたがっているが、企業側のニーズは減らない
   - 代替案についてJPAAWGのOpen Round Tableで議論された

##### 5. パスワードレス・生体認証への興味
   - Yahoo! JAPANでパスワードレスが進んでいる
   - SMTPのMF認証方法の1つに生体認証のアイデアもあり

##### 6. DNSへの関心
   - ドメインのブランドを守るために、DNSレベルの信頼性について議論が進んでいる


##### 7. 発表資料リンク : [https://meetings.jpaawg.org/program](https://meetings.jpaawg.org/program/)
AcronisBackupをv9からv12.5にアップデートした話

# AcronisBackupをv9からv12.5にアップデートした話
はい皆さんこんにちは

結論から言うとこの記事は
・AcronisBackup for VMware (v9)　を使っている
・v12.5の最新版にしたいから検証してみた
・無償版のESXiだとバックアップは動かないよ
・エラーはThe specified file does not exist
という話です。

# 前提条件
v9の環境は以下の通りです。
- AcronisBackup for VMware (v9)
- ESXi6.0

こちらが検証環境
- AcronisBackup 12.5
- ESXi6.5（無償版）

# 問題の詳細
アップデート方法はこちらを参照
https://kb.acronis.com/ja/content/58695

**~~アップデートというか移行な気がする~~**

やってみたものの、肝心のv12.5でバックアップがエラーになる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532987/a3492ce5-8748-c757-a71a-dc0f2c643c6d.png)

The specified file does not exist

## ここでハマってしまう

- エラーを調べてもよく分からない

https://kb.acronis.com/content/62640

- ただv9ではバックアップもリストアもできる

**ここでふと思い出す。そういえば検証機は無償版のESXiだったな・・・**

そこでESXi6.0（有償版）のマシンをバックアップ対象にしてみると・・・


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532987/bb2d566d-7476-27a4-f00d-6e1d585e8957.png)

**やったね！できたね！~~アンパンマン~~**

##詳細は以下のナレッジから分かります。

https://kb.acronis.com/ja/content/23511

~~正直エラーからはたどり着かない~~

**ありがとうございました。**
Androidアプリの初回起動判定

パーソンリンクアドベントカレンダー、17日目の投稿です:clap:
本日は、Androidアプリのバージョン周りについて書きます。よろしくお願い致します。


#はじめに
Java, Android Studio 共に初心者ですので間違い等ありましたら、わかる方コメント頂けますと幸いです。
現在使っているバージョンはこちらになります。
Android Studio : 3.4.2

#Version NameとVersion Code
アプリやソフトウェアで"1.3.2"といったバージョン情報を目にすることがあるかと思います。
Android Studio ではこれをVersion Nameと言い、製作者が編集できるようになっています。
一般的に
1桁目:メジャーバージョン
2桁目:マイナーバージョン
3桁目:マイナーマイナーバージョン
と呼ばれます。

それに対してVersion Codeは更新した回数をインクリメントしていきます。
シンプルに更新回数を見るために必要なものとなります。

Version Nameはあくまで名前ですので、推奨はされていないと思いますがアップデートしても変更しない事も可能です。

これらの情報はbuild.gradleに記述します。
build.gradleのVersion Codeを書き換えると、その他書き換え処理等が必要な場所を自動で更新してくれます。助かりますねぇ

#初回起動判定
アプリをダウンロードして初めて開いたという初回起動の判定を行います。
SharedPreferencesはそのアプリのバージョンなどの設定情報を管理するものになります。
データの書き込みにはeditorで編集、applyやcommitで保存します。
データの取得にはgetを使います。(この辺りはSharedPreferencesについて検索してみてください）

```first.java
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;

//設定関連クラス
public class PreferencesUtil {

    // 設定値の識別子
    private enum Key {
        IS_FIRST
    }
    
    //初回起動かどうかの判定
    public static boolean isFirstJudgment(Context context) {
        return getSharedPreferences(context).getBoolean(Key.IS_FIRST.name(), true);
    }

   //初回起動フラグの設定
    public static void setFirstFlag(Context context, boolean isFirst) {
        Editor edit = getSharedPreferences(context).edit();
        edit.putBoolean(Key.IS_FIRST.name(), isFirst);
        edit.apply();
    }
}
```
初回起動か判定をしたい時にはisFirstJudgmentメソッドを呼び出します。
この場合ではtrueの場合初回起動であるとしています。

初回起動された後にはtrue->falseにする事で次回起動時は初回起動ではないと判断されます。
その際は下記のようにしてfalseにしてあげます。

```.java
PreferencesUtil.setApplicationFirst(getApplicationContext(), false);
```

#アップデート後の初回起動判定
Version Codeがインクリメントされた事をトリガーにして、アップデート後の初回起動の判定を行います。

```update.java
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;

//設定関連クラス
public class PreferencesUtil {

    public static boolean isLastVersion(Context context) {
        //現在のバージョンを取得する
        int currentCode = getSharedPreferences(context).getInt("VersionCode", 1);
        //最新のバージョンを取得する
        int latestCode = ApplicationUtil.getVersionCode(context);

        //現在と最新のバージョンを比較
        if (latestCode > currentCode) {
            return true;
        } else {
            return false;
        }
    }
}
```
currentCodeが最後に保存された端末内のVersion Codeになります。
latestCodeがダウンロードされた最新のVersion Codeを取得しています。
この二つの変数を比較する事で最新版かどうかの判定をしています。

この場合、trueであればアップデート後、初回起動ということになりますね。
その後、currentCodeにlatestCodeの値を導入してあげることでこれ以降はfalseが帰ってくるようになります。

#まとめ
これらの処理は一度だけ、プッシュ通知の設定、プライバシーポリシー同意のポップアップを出したり、アップデートした点をお知らせするといった事をする為に用いることができます！

ということで本日の記事はこれで以上になります。
明日は@kuwakuwakuwaさんです。よろしくお願い致します！
JDK 14 の新機能 JEP 358: Helpful NullPointerExceptions を試した

`-XX:+ShowCodeDetailsInExceptionMessages` を追加する必要がある。

```java
import static org.assertj.core.api.Assertions.assertThat;

import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;

import org.junit.Test;

public class NPETest {
    public String maybeNull = null;

    @Test
    public void testNpe() {
        // Preconditions
        final RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
        assertThat(runtimeMXBean.getSpecVersion()).isEqualTo("14");
        assertThat(runtimeMXBean.getInputArguments()).contains("-XX:+ShowCodeDetailsInExceptionMessages");

        // Do
        final String subst = maybeNull.substring(0, 1);
    }
}
```

これで

```
java.lang.NullPointerException: Cannot invoke "String.substring(int, int)" because "this.maybeNull" is null
```

時代は変わるなぁ。。。
#API のドキュメントの項目が時にアルファベット順に並んでいるのに気づいていたか？

Stripe APIの例

これに気づいただけで、これから探すのがうまくなると思う

APIリファレンスを作る時もカテゴリ分けとか大変なので、アルファベット順で良いのかもしれない

![image](https://user-images.githubusercontent.com/13635059/70856745-acb4c300-1f25-11ea-960d-871a9425827f.png)


# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/2849








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
社内におけるSalesforceの浸透について

#想定読者
Salesforceの管理者

#自己紹介
現在勤めているランスタッドには入社して8年目になります。
IT部門へは2018年の冬に異動してきましたので、約1年が経過しました。
その前は人材派遣部門のコンサルタントとして7年程営業をしておりました。
その中でITとして過ごしたこの1年を少し振り返ってみようかと思います。

#Salesforceのユーザとして

私が初めてSalesforceに触れたのは営業時代の時で、Salesforceを使うユーザー側としてでした。
社内でSalesforceが導入される前に、私がいた営業所がパイロット支店として試験的にスタートさせていただけることになったからです。
当時はSalesforceのことを知らなかったため、Salesforceのことを細かく調べました。SFA、CRM、MA等聞いたことがない言葉がたくさんあったことを覚えています。
元々新しいシステムを覚えたり、データを扱うのは好きだったので、マニュアルを見るのも特に苦ではなく、使い方を覚えて新しいシステムを使うのが楽しかったかなと思います。

Salesforceを使い始めて、そもそも顧客管理というものは既に体系化されていて、
</font><font color="blue">顧客管理ではなく、顧客「関係」管理</font>として「関係」を管理する方法が確立されていることに驚いた記憶があります。


更にSalesforceはこの行位階ではTOPシェアをもっているCRMのため、これは本気で覚えなくては、今までとは全く違った営業方法を覚えてSalesforceを使っていかないとクビになるな、と本当に焦りを感じました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536690/5ba281df-1dc0-e369-f7c3-483e1c049012.png)


##ユーザとして感じた違和感

その一方で、パイロット拠点としての役目を終えていざSalesforceが導入されると、少し違和感を覚えることがありました。まわりが感じているSalesforceを使うことへの温度感がそこまでではないなと思うことがあったんですね。

Salesforceというような、いわゆるCRMは営業やマネージャーにとってはなくても業務はまわります。
</font><font color="red">むしろ今までの仕事のやり方を変えてまで何で入力をしなくちゃいけないんだとか、使うメリットがわからないと感じるのはむしろ当然のことなんだなと、いろいろ調べて気づくことがありました。</font>

もちろんどちらが正しいということではなくて、
それから漠然とですが私自身はユーザとしてではなく、Salesforceの管理者として、社内の業務を改善していきたいと思いました。

##転機

程なくして、タイミングよくIT部門で「Salesforce」の浸透を目的としたポジションが社内公募であがりました。
営業時代に、ほとんどの人はシステムで分からないことがあった時、誰にも聞かずそのままにするか、自己流で使っていくことが多いため、わからないことがあった時にそのままにせず、気軽に聞ける存在が必要であると感じていました。
その想いもあり、真っ先に応募してそこから私はITで働く側になったという形です。

ITで働くにあたり、大きく決めていることがありました。
それは社内でSaleforceで分からないことがあった時、
<font color="blue">一番最初に問合せ頂ける存在になりたかった</font><font color="blue"></font>ということです。


#そしてSalesforceのシステム管理者へ
こうして、私はSalesforceのシステム管理者になりました。
その中で行った活動を1つご紹介できればと思います。

##支店での研修
弊社は全国各地に支店があります。
ITで働く前に私が感じていた、この課題をなんとか解決するために全国各地に足を運び、Salesforce研修を実施いたしました。
>むしろ今までの仕事のやり方を変えてまで何で入力をしなくちゃいけないんだとか、使うメリットがわからないと感じるのはむしろ当然のこと


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536690/065c547f-0a92-fc55-7fae-86e8eac6855e.png)


###■実施する上でのポイント
資料は私側で用意いたしましたが、当日のファシリテーションは現場(各支店の担当者)の方にやっていただきました。

本部側がファシリしてしまうと、
「また本部がなんかいってる」くらいに留まってしまうので、現場(各支店の担当者)の方にやっていただきました。
実際に円滑に研修が進行いたしました。

###■実施後の効果
いざ研修を実施してみると、実施前と実施後で数字に変化がありました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536690/7cfc2496-79f6-62db-c5ff-6b50ee2a55af.png)


####・日々の情報入力に対しての件数

####・問合せ件数

####・開発要望

####・ユーザ間でのchatterでのコミュニケーション

このような研修を実施することにより、Salesforceを使うメリットをより伝えることができ、少しづつですが社内に浸透できている気がします。

#最後に

この1年を振り返ると、Salesforceに情報を入力することはある程度浸透してきているのかなと思っています。
ただ課題はたくさんあって、その中でも入力された情報をいかに活用するか、今の業務プロセスに浸透させていくかはまだまだ道半ばです。
来年はその情報の活用を大きなテーマにしたいと思っています。
python bs4 requestによる抽出の備忘録

pythonでwebスクライビング時の備忘録です。

```python
from bs4 import BeautifulSoup
import reuest
import os
"""プロキシ対応"""
os.environ["https_proxy"] = "http://xxx.xx.xx.xx:8080"
url = "https://www.python.org/"
html = requests.get(url)
soup = BeautifulSoup(html.text, "lxml")
print(soup)
print("----------------------------------------------")
# python.org内の文字列のみを取得したい場合
name = soup.find_all("div", class_="introduction")
# name = soup.find_all("div", {"class": "introduction"}と記載しても良い。
name = name[0].text
print(name)
title = soup.find_all("title")
title = title[0].text
print(title)
```
結果

```python
Python is a programming language that lets you work quickly and integrate systems more effectively. Learn More

Welcome to Python.org
```
SlackをTogetter風にまとめるアプリ「Togelack」を使ってみた

#概要
Slackの無料プランだと過去ログが10000件までしか遡れないので
Togelackというツールを試してみた。
（個人用ならEverNoteとかでいいかも）

#参考サイト
[GitHub](https://github.com/rutan/togelack)
[Togetter的な社内Slackまとめサイトをつくった話](https://qiita.com/ru_shalm/items/32160b23df535ed78967)
[SlackのTogetter風アプリ「Togelack」をHerokuにデプロイする](https://qiita.com/ru_shalm/items/35100b527877cfe09b5e#_reference-c1aa5a6f960321384793)
[逆引きマニュアル: Slack: APIトークンを発行する方法](https://www.ikemo3.com/inverted/slack/create-api-token/)

#事前準備
1：Herokuのアカウントを用意する
無料プランでもクレジットカード必須です。（課金されないけど）
ある意味ここが一番時間がかかります。

2：アプリ名を決めておく
何でもいいけどHerokuですでにあるものは使えないので注意。
ここで決めたものがRedisになる（後述）

3：SlackアプリのCLIENT_IDとCLIENT_SECRETを取得する
[アプリ管理ページ](https://api.slack.com/apps)から「Create New App」を選択。
アプリ名とWorkspaceを選択。
App CredentialsにあるClient IDとClient Secretをメモ帳か何かにコピペする。

4：APIキー取得とRedirect URLの発行
（2の画面のまま）
左側メニューに「OAuth & Permissions」というのがあるので選択。
「OAuth Tokens & Redirect URLs」という項目に「OAuth Access Token」というのがあるのでコピペする。
無ければ「Install App to Workspace」を押して追加。

その下の「Redirect URLs」に追加。
「https://（2で決めたアプリ名）.herokuapp.com/auth/slack/callback」
きちんとSave URLsを押しましょう。

#Herokuにデプロイ
[このサイト](https://github.com/rutan/togelack)に「Deploy to Heroku」という紫のボタンがあるので押します。
上から順に入力・変更箇所記載します。

「App name」
2で決めたアプリ名を入力

「PRIVATE_MODE」
社内Slackとかの場合はtrue推奨

REDIS_URL
「**redis**://（2で決めたアプリ名）.herokuapp.com/auth/slack/callback」

SLACK_CHANNEL
設定しておくと「まとめが作成されました」が自動で流れます。

SLACK_CLIENT_ID
SLACK_CLIENT_SECRET
3でコピペしておいたものを入れましょう

SLACK_TEAM_ID
SLACK_TEAM_NAME
[ここ](https://api.slack.com/methods/team.info/test)で確認できるので、
"team"の"id"と"domain"を入れましょう。

SLACK_TOKEN Required
4でコピペしたTokenを入れましょう。

「Deploy app」を押して成功すると「View」というボタンが表示されます。

#追記
これを使ったら10000件超過して遡れなくなった投稿も参照できました。
windows10にpythonをインストール

#【puthon】環境設定


1,python公式サイトにアクセス
https://www.python.org/downloads/windows/


2,Downloads＞Windows　をクリック
![スクリーンショット (267).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551834/7a91e3d6-869b-ec83-6792-e9dda71ddab8.png)


3,Letest Python 3 Release ~をクリック
![スクリーンショット (268).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551834/b16b4f96-04ee-1765-3649-189d09a7fd3e.png)


4,ページの下のほうまでスクロールし、Windows x86-64 execrtable installer　をクリック
![スクリーンショット (269).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551834/55389e08-9519-1143-7cfe-af4bcad3ae38.png)
iOSのUIKitで覗き穴のようなビューを実現する

iOS の UIView で下のスクリーンショットのような覗き穴のようなビューを作る方法です。画像の Cropper ビューなんかを作るときにも必要になりますね。

<img width=375 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16508/e7fa3e22-79d8-18a9-d52a-7f6b37015cb8.png" />

この完成形のスクリーンショットのビュー構造は

- スクリーンいっぱいの `UIImageView`
- その上に同じサイズの `HoleView` (今回作るビュー）

というようになっています。

### コード

タッチした場所を中心に覗き穴ができるようなコードの例です。
覗き穴の部分の実装は UIView の `drawRect(_:CGRect)` メソッドをオーバライドしている部分で、やっていることは次のとおりです。簡単ですね。

- まずビューの全体を塗りつぶす（＝穴の外側となる）
- ブレンドモード `.clear` を指定して穴の部分を塗りつぶす

```swift:HoleView.swift
import UIKit

class HoleView: UIView {
    
    private var holeCenter: CGPoint = .zero
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        
        guard let context = UIGraphicsGetCurrentContext() else { return }
        
        // 全体を塗りつぶす
        UIColor.black.withAlphaComponent(0.75).setFill()
        context.fill(bounds)

        // 穴はブレンドモードで .clear を指定して塗りつぶす
        let holeRect = CGRect(x: holeCenter.x - 100, y: holeCenter.y - 100, width: 200, height: 200)
        context.setBlendMode(.clear)
        context.fillEllipse(in: holeRect)
    }
    
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else { return }
        // タッチした場所を穴の中心とする
        holeCenter = touch.location(in: self)
        setNeedsDisplay()
    }

}
```

### 実行結果

いい感じに覗き穴っぽくなりました :+1:

![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16508/4fbeb049-ec9c-8d0e-6153-3c6567815563.gif)
リージョンについて勘違いをしていてradiko録音スクリプトをGCPで動かすのに失敗した話

## サマリ

[Radiko録音スクリプトを作った](https://qiita.com/1021ky@github/items/0fc49fec62c6ab213e32)ので聞きたい番組をGCPで定期的に録音しようとしました。
GCPは東京リージョンがあるから、東京のラジオが聞けると思っていましたができませんでした。
原因はリージョンについて勘違いをしていて、そもそもできないことをしようとしていたからでした。

## 前提の話

### 試した環境

* [GCP Cloud Run](https://cloud.google.com/run/?hl=ja): (2019/12/14)

## Cloud Runでの録音実施とその結果

[Radiko録音スクリプトを作った](https://qiita.com/1021ky@github/items/0fc49fec62c6ab213e32)で作ったスクリプトをDockerで動くようにして、Cloud Runで実行しました。

ラジコから音声ファイルを取得するには前処理として、WebAPIをコールして音声ファイル取得に必要なパーシャルキーという文字列をHTTPヘッダーから取り出します。このとき、HTTPレスポンスボディにラジコがどのエリアで判定したかをWebAPIが返してくれます。
以下はローカルで実行して判定されたエリアをログで出したものです。エリアID：JP13と日本の東京と判定されています。

```bash
DEBUG:root:res.content:b'JP13,\xe6\x9d\xb1\xe4\xba\xac\xe9\x83\xbd,tokyo Japan\r\n'
```

Cloud Runでもasia-northeast1（東京リージョン）で実行すれば同様の動きをすると思っていました。（※ここが勘違いしていた部分）

実行すると以下のようになりました。

```bash
DEBUG:root:res.content:b'OUT'
```

## 原因をさぐる

OUTというのはローカルで実行したときに返ってきたことがなかったので、もしかして日本からアクセスしたことになっていないのでは？
と仮設を立ててみました。Radikoは日本専用のサービスなので。

> 『ラジコ』『ラジコプレミアム（エリアフリー聴取）』は日本国内限定のサービスです。
> 海外からの聴取はできません。

引用元：[radikoヘルプ　海外から聴取できますか？], http://faq.radiko.jp/faq/show/19?category_id=4&page=1&sort=sort_access&sort_order=desc ,（検索年月日：2019年12月16日）

実際にどこの国からアクセスしているか調べるために[ipinfo.io](http://ipinfo.io/)というIPアドレスやその他の情報を取得できるサービスを使ってみました。

詳細は[こちらのサイト](http://kumonchu.com/linux/ipinfo/)で紹介されています。

以下のコードを入れて、どこの国からアクセスしているかログに出力させました。（python3.7.5です。）

入れたコード。

```python3
import requests
import logging

res = requests.get('http://ipinfo.io')
loggin.debug(f'ipinfo.io content:{res.content}')
```

ローカルで実行した結果。

```bash
ipinfo.io content:b'{\n  "ip": "**********",\n  "hostname": "*****",\n  "city": "*******",\n  "region": "******",\n  "country": "JP",\n  "loc": "******",\n  "org": "******",\n  "postal": "******",\n  "timezone": "Asia/Tokyo",\n  "readme": "https://ipinfo.io/missingauth"\n}'
```

東京ですね。

Croud Runで実行した結果。

```bash
2019-12-09 12:15:54.747 JSTDEBUG:root:ipinfo.io content:b'{\n "ip": "**********",\n "hostname": "******.gae.googleusercontent.com",\n "city": "New York City",\n "region": "New York",\n "country": "US",\n "loc": "40.7143,-74.0060",\n "org": "AS15169 Google LLC",\n "postal": "10004",\n "timezone": "America/New_York",\n "readme": "https://ipinfo.io/missingauth"\n}'
```

**"New York"!!!!**

国外からのアクセスになっている。それは無理だわ・・・。
ここでリージョンをasia-northeast1にしてもアクセス元が日本になるわけではないことがわかりました。

## まとめ

* Cloud Runではリージョンをasia-northeast1にしていてもアクセス元となる。
* アクセス元の国や地域を考慮するWebAPIをCloud Runからコールするときは気をつけないといけない。

じゃあこれはどうやったら解消できるのか？というのを調べてみましたが、わかりませんでした。
ネットワークの問題っぽいなのでGCPの[ネットワーキングサービス](https://cloud.google.com/products/networking/?hl=ja)を使えばできるかもしれません。ただ私はネットワークの知識不足でどのプロダクトなら解消できるかドキュメントを読んでもわかりませんでした。
こうすればいいよってわかる方がいたらぜひ教えていただきたいです。
flexbox 基本


## 参考記事

https://webdesign-trends.net/entry/8148#_align-items

## flexboxゲーム

https://flexboxfroggy.com/#ja


## htmlの格子


```html
    <div class="container">
      <div class="box box-1">
      </div>
      <div class="box box-2">
      </div>
      <div class="box box-3">
      </div>
    </div>

```
## 基本概念

- flexの使い方とを理解
  - flex-grow（伸び率）
  - flex-shrink（縮み率）
  - flex-basis（基本幅を指定できる）


- flex-grow

![スクリーンショット 2019-12-16 11.14.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286971/42433d49-c71a-6475-a4f7-6df3ba6d8dc2.png)


- flex-shrink

![スクリーンショット 2019-12-16 11.15.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286971/d4171050-58c9-ad30-a433-92fc672866e9.png)


- flex-basis

![スクリーンショット 2019-12-16 11.15.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286971/2bb5f553-3226-1113-e44d-e6703908ca7d.png)


- 一括設定

![スクリーンショット 2019-12-16 11.17.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286971/eafc7647-4fc4-2b63-65dc-8bce89e5ff0e.png)


## よく使うプロパティ

- display: flex;
- justify-content: center;
- align-items: center;
- order: 1,2,3; 順番変更
Nuxtで超簡単にスタンドアロンアプリを作る(デスクトップPWA)

PWA Advent Calendar 2019 17日目です。

## やりたかったこと
デスクトップアプリを作りたかった。
Electronを最初は考えていたけど、デスクトップPWAがアツいよって聞いたのでやってみることにした。

## デスクトップPWAのメリット
* Webアプリとデスクトップアプリが同時に作れる
* Nuxtなら何も考えず作れる

## デスクトップPWAのデメリット
* 導線がすごくとても分かりづらい
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154239/b518d138-7ab9-a67b-f5b0-e3a517e5c3cc.png)
アドレスバーの右側にちょこっと出るだけ！こんなの知ってないと絶対に気づかない...

## 作ってみる

npxをインストール

```bash
npm i -g npx @vue/cli
```

create nuxt appをする

```bash
npx create-nuxt-app desktoppwa
```

適当に選んでいく



UI FrameworkはVuetifyがおすすめ

```bash
Choose UI framework
  None
  Ant Design Vue
  Bootstrap Vue
  Buefy
  Bulma
  Element
  Framevuerk
  iView
  Tachyons
  Tailwind CSS
> Vuetify.js   
```

PWAモジュールを入れるのを忘れずに。

```
Choose Nuxt.js modules
 ( ) Axios
>(*) Progressive Web App (PWA) Support
 ( ) DotEnv 
```

おわり

## 動かしてみる

```
cd desktoppwa
npm run build
npm start
```

`http://localhost:3000/` で動いていることが確認できるはず。

## インストールする
このまま使えばWeb版だが、デスクトップPWAなので(当たり前だけど)インストールできる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154239/457962f7-80dc-b3e5-1ffc-b610c07659c5.png)

アドレスバーの右の＋ボタンを押す。

デスクトップにショートカットが追加され
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154239/062c447d-b020-d802-6fc1-159a5edb5f1d.png)

見た目もアプリっぽくなる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154239/27ff41fc-30b7-0baf-142d-278662ed38a3.png)

ローカルのサーバを落としてもつながるため、オフラインでも動くことが確認できる。

## 最後に

実際にやるときにはもうちょっと考えなきゃいけないことは多いハズ(キャッシュの持ち方とか)
モバイルのPWAが注目を集めてるけど、デスクトップPWAも面白いことができると思うので色々と試せたらなあと
導線をうまくあれするいい方法があればよいのだけども...
BGPでハマった話

# はじめに

この記事は、[MicroAd Advent Calendar 2019](https://qiita.com/advent-calendar/2019/microad)の18日目の記事です。

現在データセンターの移設を行っていますが、その作業に関連してハマった内容を書いておきたいと思います。
この記事には具体的な機器のメーカー名、機種の情報は記述してません。
また、参考になるようなコンフィグ等も含んでいません。

# 背景

データセンターの移設に向けて、データセンター間の接続を行うべく、
様々な準備を進めていました。
DC間は、以下のようにBGPで接続しようとしていました。

<img width="894" alt="bgp-nw01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20794/9a097e39-ad76-3250-bbd9-bf1429d96c4e.png">

左側の既存データセンターと、右側の新規データセンター間を、
BGPで接続しルーティングを回そうと計画していました。

※上記の図では実際のAS番号ではなくプライベートAS番号で書いています。

# 何をしたのか
通常であれば問題にあるようなことはなく、ただBGPを設定して接続するだけのはずでした。

### 割り振られた4byteのAS番号...
新規データセンター側の機器には今回AS番号を取得して割り振っていた
グローバルなAS番号（4byte）が設定してあります。
この機器は、上流のISPともすでにBGP接続しており4byte AS番号による
不具合などは特に起きていませんでした。

### 異なるメーカの対向装置...
既存データセンター側は、費用をできるだけ抑えるため既存で使ってるメーカーの機器で
BGPを設定することにしました。
一つだけ注意したことはできるだけ新しいOSを入れておくことでした。
しかし、この機器が厄介な問題を引き起こすことに。

### そしてハマった...
新規データセンター側も既存データセンター側も機器の準備が整い、
専用線も開通したのでケーブルを接続。

本来なら、BGPのPeeringが確立して無事終了となるところ、
なぜかステータスが「**Established**」にならず:scream::scream:

# 原因調査
Peerが上がらない原因の調査を開始。
まずはL2での接続ができているのか、対向の装置にPingを飛ばしてみることに。
**→どうやらPingは飛ぶらしい**

次に、BGPのネイバーの状態を確認。
一方が、「Open Message Error」となっていることは判明。
**→どうやらPeerの確立時にエラーが起きているらしい**:disappointed_relieved:

メッセージを調べるも何が原因でそうなっているのか分からず。
とりあえず、双方のコンフィグを確認したが複雑な設定は入れておらず、
むしろシンプルすぎて原因となりそうなところが見当たらず。

## 途方に暮れる
過去に書いた記事の通り、Cumulus LinuxでBGPを使っている程度の知識しか持ち合わせておらず、
BGPに詳しくないがゆえに原因が何なのかさっぱりわからない。

とりあえず、困ったときはtcpdumpでも採ってみようとtcpdumpで状況が見えるか試してみることに。

## 希望の光
tcpdumpを採ってみると、ちゃんとOpenメッセージのやり取りはしているように見えた。
ただ、直後に既存データセンター側の機器から「Open Message Error subcode unknown」が送られていて、
Peerが確立しないという状況であることは分かりました。

さて、何が原因なのか。
tcpdumpをぼーっと眺めていて、「もしかしてcapabilityの一部が未サポートなのかな？？」

試しに新規データセンター側の機器に、「dont-capability-negotiate」のオプションコマンドを使って
既存データセンター側の機器にcapabilityのネゴシエーションをしないように設定してみることにしました。

## 二つ目のハマリポイント
普通なら、capabilityを無効にすることで**万事解決！**となるはずがPeerが確立しない。
**「うーん？？？」**
またしても途方に暮れることに…

このままだとセンター移設にも影響してしまうのではないかという焦り、
ちゃんと接続検証してなかった自身を猛省しつつ、もう一度tcpdumpを取得して状況を見ることに。

## 今度こそ
ぼーっとtcpdumpを見ていて、ようやく気づいたことが。
それは新規データセンター側から送られてくるAS番号がおかしいということ。

BGPに詳しい人なら常識なのかもしれないが、
BGPの4byteASは、BGPメッセージのオプションcapabilityとして埋め込まれており、
先にAS番号を「23456」として相手に送信しているのです。

そのため、既存データセンター側のneighborで設定しているremote-asが合わず、
エラーになっていたのです。

# 解決方法
通常なら新規データセンターで使用している機器を2byteAS番号に変えてしまえば解決なのですが、
今回の4byteASはグローバルAS番号であることと、NW構成的に変更できず。
やむを得ず、新規データセンター側の機器でneighborのオプション設定にある「local-as」コマンドを使って
2byteのローカルAS番号であるかのように設定することにしました。

図で書くとこんな感じに。
<img width="932" alt="bgp-nw02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20794/0d8d3376-cf88-e064-513a-04497ee4c34d.png">

データセンター間のBGP接続設定で、新規データセンター側のASを2byteのプライベートAS(64512)のに設定しました。

これで無事にPeerが確立しました:raised_hands:

# おわりに
今回の件で、BGPについて少し詳しくなれた気がしました。
特に4byteのAS番号を使う機会がほとんどないので詳しく調べられてよかったと思います。
そして何より学んだことは、事前の接続検証はちゃんとやらなきゃダメだよねってこと…。
（質問）bundle installを実行するとLibrary not loaded: というエラーが発生する

知識が不十分で数日かけて解決に至りませんでした、迷走してトラブルが悪化していると感じたため質問させていただきます。
質問が初めてのため、回答以外にも不備あればご教示いただけると幸いです。

```console:エラー内容

Ken@MacBook-Pro (アプリ名) % bundle install
Ignoring bcrypt-3.1.13 because its extensions are not built. Try: gem pristine bcrypt --version 3.1.13
（中略　※大量に同様のIgnoring~）
Ignoring zlib-1.1.0 because its extensions are not built. Try: gem pristine zlib --version 1.1.0
Traceback (most recent call last):
        33: from /Users/Ken/.rbenv/versions/2.5.1/bin/bundle:23:in `<main>'
        32: from /Users/Ken/.rbenv/versions/2.5.1/bin/bundle:23:in `load'
        31: from /Users/Ken/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/bundler-
（中略）
         3: from /Users/Ken/.rbenv/versions/2.5.1/lib/ruby/site_ruby/2.5.0/rubygems/core_ext/kernel_require.rb:54:in `require'
         2: from /Users/Ken/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/openssl-2.1.2/lib/openssl.rb:13:in `<top (required)>'
         1: from /Users/Ken/.rbenv/versions/2.5.1/lib/ruby/site_ruby/2.5.0/rubygems/core_ext/kernel_require.rb:54:in `require'
/Users/Ken/.rbenv/versions/2.5.1/lib/ruby/site_ruby/2.5.0/rubygems/core_ext/kernel_require.rb:54:in `require': dlopen(/Users/Ken/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/openssl-2.1.2/lib/openssl.bundle, 9): Library not loaded: /usr/local/opt/openssl/lib/libssl.1.0.0.dylib (LoadError)
  Referenced from: /Users/Ken/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/openssl-2.1.2/lib/openssl.bundle
  Reason: image not found - /Users/Ken/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/openssl-2.1.2/lib/openssl.bundle
```

```console:vim
vim ~/.zshrc        
eval "$(rbenv init -)"
export PATH="/usr/local/opt/mysql@5.6/bin:$PATH"
export PATH="/usr/local/opt/openssl@1.1/bin:$PATH"
export PATH="/usr/local/opt/gettext/bin:$PATH"
export PATH="$HOME/.rbenv/bin:$PATH"
export PATH="/usr/local/opt/curl/bin:$PATH"
```                                     

```console:brew
Ken@MacBook-Pro ~ % brew deps --installed --tree
autoconf

openssl@1.1

pkg-config

rbenv
└── ruby-build
    ├── autoconf
    ├── pkg-config
    └── readline

readline

ruby-build
├── autoconf
├── pkg-config
└── readline
```

##調べた内容
###brew update && brew upgradeを実行
こちらの記事を参照
https://qiita.com/kota-es/items/98ae6ee84fc59aaae2ea
###brew doctorを実行
いくつかbrew linkするよう指示が出ましたので実行
###Homebrewの再インストール
コマンドを検索して実行
###その他
エラー文でググって、出た記事の内容をいろいろと実行

上記いずれも、解決には至りませんでした。

##原因と思われること
OSのアップデートをしてcatalinaに変更したこと、rails6でwebpackerを使用するためにいろいろと検索した内容を入力してしまったこと
その際にlibresslからopensslに変更してしまい、パスが通っていない・brewの設定がおかしい

##知りたいこと
今回の問題の解決策と、もし可能であれば今回のエラーに関してこんな知識を習得した方が良い、こんな書籍がおすすめ、などのご意見をいただけると非常に助かります。
PythonからLINEBotにメッセージを送りたい

久しぶりにPythonをしたくなり
このページを参考にLINEBotを作っています。

https://blue-black.ink/?p=3935

私がやったこと
1､ターミナルに　

pip install requests

を送りました。

2,PythonでLINEにメッセージを送る準備
”””
token = "私のを入力"
payload = {"massage": "Hello World"}
url = "http://notify-api.line.me/api/notify"
headers = {"Authorizatino": "Bearer" + token}
res = requests.post(url, data=payload, headers=headers)
print(res)
”””

これをすると

Process finished with exit code 0

このように表示されて、ラインにはメッセージは来ませんでした。
（この文章は正常に送信したっていう意味らしい）

３．コマンドに

python　test.py

を入力して

Response[200]

が帰ってきたら成功とありますが

python: can't open file 'test.py': [Errno 2] No such file or directory

と表示されています。

まだラインにメッセージは来ません。
なんでか…今日一日で調べれるかな…
何も知らないまま雑にNuxtで開発したら死んだ話

# はじめに
本投稿は [TECOTEC Advent Calendar 2019](https://qiita.com/advent-calendar/2019/tecotec) の16日目の記事です。  
以前、手探りでやった結果大惨事になったプロジェクトの状況を、主犯の一人として反省を込めてメモがてら書き記していきたいと思います。

## 使ってた技術
- Nuxtjs
- vuex
- Pug
- Firebase(Authentication/Functions/Firestore/Hosting)

## 状況

**俺たちは雰囲気でこのプロジェクトをやっている。**

新規のサービス開発。チームとしては10名くらい。Nuxt触ったことある人なし。JSのスキルレベルもそこそこという感じでした。(ヤバ1) まあNuxtならそんなに難易度高くない（らしい）しへーきへーき！！みたいな楽観もあった気がしないでもない。(ヤバ2）
なお、Firebaseも同様にほぼ触ったことないメンバーでした。collection定義なにもわからない。（ヤバ3）  
一体何がダメだったんでしょうかねぇ

## 何が起きたか。
- 無秩序に乱立した用途のよくわからないComponent
- 各Componentで似たようなオレオレObjectの大量発生
- テスト書いてない
- 途中で主要なFirestore collectionの定義し直し
- 一部導入したフレームワークの影響もありSCSSの肥大化/制御不能

特に検索系のComponentがヤバく、ほぼ同じPlateが18種類のComponentで爆誕しました。Slotでええやないか。
また、途中でもともと権限で出し分けていた管理系機能を別アプリとして切り出すような事態も起きてて、もはや何がなんだかという感じでした。使ってないComponentいっぱいあった気がする……。  

いわゆるStore系の扱いもよくわからず、こちらも同様にスパゲッティ化しました。基本collection単位で切ってたんですけどね……。オレオレObjectを扱う謎Actionが乱立したのが悪かったかな………。  
タスクはbacklogでチケット切ってチケット駆動開発のような感じで行っていて、これ自体が悪いわけじゃないんですが、いわゆる画面単位でタスクを切った結果、各々が作ったVueファイルのなかにBusinessLogicが押し込まれるという事態になりました。どうして？  
collection定義し直しは雑に作った結果検索がクソ遅くて速度改善のために実施しました。なお、結果別のところ直したらぼちぼち改善したのであれが何だったのかは忘れることにしました。

## どうすればよかったのか
##### Component作成のルールを決める
Nuxtで指定されているもの以外、フォルダの切り方が不明。ぱっと見でどのComponentが何なのかわからない。そんな状況を打破するにはやはりルールを整備する必要があります。なんで気づかなかったんですかね？
そこで、このPJの反省を活かし以降のプロジェクトではAtomicDesignを導入。最低限のフォルダ分けと作成ルールを整備しました。これによってSCSS側もScopedで書きやすくなり、圧倒的にマシになりました。
なんで気づかなかったんですかね？

##### Typescriptの導入
オレオレObjectが無限に発生するならそうならないように型で縛ればいい。型は偉大である。共通の型を使えば処理の共通化もしやすい。素晴らしい。書く手間は増えるが些細なことだ。型のルールをちゃんと決めてなくてこっちも乱立しかけたりしたけどそれも些細なことだ。
もともとこのPJでも導入の検討はしてたんですけど何もかも新規だしハードル上がりそうだからやめたんですよね確か。結果としてはどうせ何もわからないしあったほうがマシだった説は濃厚なんですが。

##### ElasticSearchの導入
検索を自前でやるなんて自殺行為でございますわ！！なんで入れてなかったのかは忘れました。

##### テスト書く
いや最初から書けよ。テスト書いてないとかお前それ（ｒｙとライオンのスタンドが現れて怒られてしまいます。

## 振り返ってみて
こうして振り返るとだめなことするとだめになるというお手本のような感じでございますね。当時は何もわからなかったんですよ。多分。実はそんなに昔じゃないとかそういうのは置いといて。

VueやReactにTypescript入れちゃったらそれはもうAngularじゃんみたいなのは一昔前には言われてましたけど最近はもうTypescriptは導入必須みたいな空気感ありますよね。個人的にはJavaが長かったのもあって型がある方が落ち着くんですが、JSで雑に書いてもいい感じに動いてくれるのも嫌いじゃないんですよね。だからと言って調子に乗ると大変なことになるというのも多大な犠牲ともにわかりました。
それと、導入してイキってますがAtomicDesignは未だによくわかっていません。そんなに知見が転がってないのと、あくまで考え方でしかないのでPJごとにいい感じに調整するしかないような感じですし。どこかの勉強会で聞いたまずAtomsから始めよ的なやつはまあそのとおりだなあと思いました（てきとう）。

# 総括
**人間は愚かなのでルールを整備しましょう。ルールを整備したら強制する仕組みも導入しましょう。**
<br>

## 4/10追記
その後のAtomicDesign
https://tec.tecotec.co.jp/entry/2020/03/27/090000