OmniAICreator/Qiita-1.07M huggingface dataset:
【C#備忘録】string型はNULLを持てるが、NULLが入った値にTostring()メソッドは使用できない

※この備忘録は初学者の私が学習、もしくは業務で体験した内容を忘れないために書き起こしたものとなります。

#目的
画面Aのint?型のResultData.noの値を、画面Bの行数が可変(ここでは、1,2行目は必ず存在し、3,4行目は可変行とする)のグリッド(GridDataクラスのnumberプロパティ)に代入したい
※画面Bの各行について、代入用に変数を割り当てる
　1行目…data_1,
　2行目…data_2,
　3行目…data_3(変数自体存在していない可能性あり),
　4行目…data_4(変数自体存在していない可能性あり)
※data_1,data_2,data_3,data_4はGridDataクラスのインスタントで、GridDataクラスには、string型のnumberプロパティが存在するものとする。
##誤答
~~~C#
// data_1,data_2は必ず存在するので、そのまま代入
data_1.number = data_2.number = ResultData.no.Tostring();

// data_3,data_4は存在しない可能性があるため、nullでない場合に代入
if (data_3 != null)
{
    data_3.number = ResultData.no.Tostring();
}
if (data_4 != null)
{
    data_4.number = ResultData.no.Tostring();
}
~~~
上記の場合、ResultData.noがNULLのとき、Tostring()メソッドでNULLを変換できないためエラーとなってしまう。

##正常に動作したコード
~~~C#
data_1.number = data_2.number = ResultData.no.HasValue ? ResultData.no.Tostring() : "";

if (data_3 != null)
{
    data_3.number = ResultData.no.HasValue ? ResultData.no.Tostring() : "";
}
if (data_4 != null)
{
    data_4.number = ResultData.no.HasValue ? ResultData.no.Tostring() : "";
}
~~~
上記のように、
「int?型のResultData.noに値が存在しているかどうか？⇒存在しているならResultData.noをTostring()メソッドで文字列変換し、data_1等に代入」
をすることで対処できる。
矩形選択（くけいせんたく）のショートカット【VSCode・サクラエディタ】

## VSCodeのショートカット
### Windows
・矩形範囲選択モード： Ctrl + Shift + Alt + [矢印キー] 
・矩形範囲選択モード解除：Esc 

### Mac
・矩形範囲選択モード： command + option + [矢印キー] 
・矩形範囲選択モード解除：Esc 

## サクラエディタのショートカット
・矩形範囲選択モード： Alt + [矢印キー] または Shift + [F6] 
・矩形範囲選択モード解除：Esc
Azure IoT Central アプリケーションをデプロイする手順メモ

## はじめに

IoT Central をデプロイする手順のメモです。
公式ドキュメントはこちら：[クイックスタート - Azure IoT Central アプリケーションを作成する](https://docs.microsoft.com/ja-jp/azure/iot-central/core/quick-deploy-iot-central)

## （任意）リソースグループを作成する

IoT Central アプリケーション作成時にもリソースグループを作成できるので、先にやっておく必要は特にない。

<a href="https://gyazo.com/c23e2cf4307e81abccc36694a4fe2905"><img src="https://i.gyazo.com/c23e2cf4307e81abccc36694a4fe2905.png" alt="Image from Gyazo" width="834"/></a>

<a href="https://gyazo.com/291b948efbb5190d9de5f205c9bca0b3"><img src="https://i.gyazo.com/291b948efbb5190d9de5f205c9bca0b3.png" alt="Image from Gyazo" width="827"/></a>

<a href="https://gyazo.com/78830efe0bc646c250b4ca9a0a6d0ad6"><img src="https://i.gyazo.com/78830efe0bc646c250b4ca9a0a6d0ad6.png" alt="Image from Gyazo" width="834"/></a>

<a href="https://gyazo.com/128f7300f2f9434a24186bb8e9307d45"><img src="https://i.gyazo.com/128f7300f2f9434a24186bb8e9307d45.png" alt="Image from Gyazo" width="834"/></a>

## IoT Central アプリケーションを作成する

<a href="https://gyazo.com/ce76b8a465d98c954ed5fa4bb12ff86d"><img src="https://i.gyazo.com/ce76b8a465d98c954ed5fa4bb12ff86d.png" alt="Image from Gyazo" width="817"/></a>

<a href="https://gyazo.com/ea378fd62b7603a39f49d325f97e2c6a"><img src="https://i.gyazo.com/ea378fd62b7603a39f49d325f97e2c6a.png" alt="Image from Gyazo" width="834"/></a>

<a href="https://gyazo.com/88014e10034cea833b28b7ba280987d0"><img src="https://i.gyazo.com/88014e10034cea833b28b7ba280987d0.png" alt="Image from Gyazo" width="834"/></a>

リソースグループはここでも作成できる。

価格：https://azure.microsoft.com/en-us/pricing/details/iot-central/?rtc=1
テンプレート：https://docs.microsoft.com/ja-jp/azure/iot-central/core/concepts-app-templates

<a href="https://gyazo.com/6386d40429febd109df9ac2169db6617"><img src="https://i.gyazo.com/6386d40429febd109df9ac2169db6617.png" alt="Image from Gyazo" width="834"/></a>

<a href="https://gyazo.com/4dc64da187bc22a596f71497fe465771"><img src="https://i.gyazo.com/4dc64da187bc22a596f71497fe465771.png" alt="Image from Gyazo" width="834"/></a>

<a href="https://gyazo.com/c9efd9c0b61cb1c7ee34aa27101f685b"><img src="https://i.gyazo.com/c9efd9c0b61cb1c7ee34aa27101f685b.png" alt="Image from Gyazo" width="1337"/></a>

ダッシュボードが見れたら完了。

## おわりに

特にデプロイではハマるところはなかったです。
次回は IoT デバイスを追加します。
Raspberry PiのrootFSをROM化してSD Cardの破損を防ぐメモ

Raspberry Piはデフォルトのまま運用すると電プチ操作やログ書き込みによるSD Card劣化によりSD Cardがわりとすぐに壊れてしまいます。
なのでサーバとして常時起動する運用を行うならSD CardのRead only化は必須です。
しかし、その方法をすぐ忘れて検索するのでメモとして残しておきます。

この記事はメモなので細かいこと書かずにコマンドだけ掲載しますが、Raspberry Piのrootfs ROM化については以下の記事に詳しく書かれているので興味ある人は以下記事を御覧ください。

> [Raspberry Pi OSのrootfs ROM 化 ― RAMディスク化しつつ、好きなパッケージを後から追加する方法](https://qiita.com/ma2shita/items/45818f0872472ecacac1)


# 前準備

毎回手で打つのが面倒くさいので[Overlay FS 操作用の関数`rsfsrom`を作りました](https://gist.github.com/tomtwinkle/d02d9c2c66457a97752032f778113a63)。
既に登録済みならこの作業は不要です。
`rsfsrom`を~/.bashrcに登録しておくのが嫌なら適当にshellscript化して `/usr/local/bin` にでも放り込んでおきましょう。

```bash:~/.bashrc
curl -L https://gist.github.com/tomtwinkle/d02d9c2c66457a97752032f778113a63/raw >> ~/.bashrc
source ~/.bashrc
```

# Overlay FS 有効化(SD Card ROM化)

```bash
rsfsrom enable
sudo systemctl reboot
```

# Overlay FS 無効化(SD Card ROM化解除)

```bash
rsfsrom disable
sudo systemctl reboot
```

# Overlay FS status確認

```bash
rsfsrom status
```
ESP-WROOM-02でスマートロックを作ろう②【物理鍵も使用できるように改修】

# はじめに

前回投稿した記事の続きです。
[ESP-WROOM-02でスマートロックを作ろう](https://qiita.com/souri-t/items/8d492599f83eca858b77)

## 前回の課題

サーボモーターの回転軸とサムターンを回す回転軸が完全に同期してしまっているので、通常の鍵（物理鍵）を使って開けることができない。
もしロックした状態で外出し、停電になってしまったら

**物理鍵で開けることができない！！！！**

こんな仕様になってしまったので電子的な方法以外にも解錠・施錠の方法を用意しようと思います。

# 検討 

「Qrio Lock」や「SESAME」などの市販のスマートロックは普通の物理鍵でも開けられる仕様になっているらしいが、どのような仕組みになっているかは詳細に公開されていない。
この仕組みを知るために新品を購入して分解するのは本末転倒なので、分解記事を探してみた。

「NinjaLock」を分解した勇者のレポートによるとこういう仕組みらしい。
[スマートロック、NinjaLockの分解レポート「なぜ手動でも機械でも鍵の開閉が可能なのか？」]
(https://dreamerdream.hateblo.jp/entry/2019/04/30/170000)

解説にある図解をFusion360で簡単に再現してみた。
<img width="300" alt="" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27488/ed44e919-7537-f5d0-a0bc-579d34fbfbb5.gif>

画像の内側の回転盤（黄色の部分）がサムターン（緑色の部分）を回した後に元の位置に戻ることによって、物理鍵による回転を妨げない構造になっていた。

これを前回のスマートロックに搭載すれば何とか解決できそうだ。

# 実装
というわけで新しい回転機構を作ります。

今までの木工では限界があったので、これを機に3Dプリンターを買ってしまいました。
この購入で３万円掛かっているので普通に市販のQrioLockが買えます...

ちなみに買ったのは「Ender3 Pro」というEngadgetでもベストバイに選ばれていた高コスパの3Dプリンターです。失敗もなく高い精度で作れました。
[3万円台3Dプリンター「Ender 3 Pro」が案外便利でした | ベストバイ2020](https://japanese.engadget.com/ender-3-pro-053041292.html)

<img width="300" alt="" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27488/afab16d6-a1b2-2af7-2e1b-7bbab296cdee.jpeg>

３次元CADで設計したものと実際にプリントされたもの。
バラバラですが、後で瞬間接着剤で接着します。
<img width="300" alt="" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27488/d9b59e7c-d62d-693d-7c20-31b537f49f6f.jpeg><img width="300" alt="" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27488/3336d525-ec7c-2f01-46f7-6c5c748ee086.jpeg>


ついでに以前木工で作ったサムターンを回す部分も3Dプリンターで作ってしまいました。
3Dプリンターが1台でもあると最強ですね。その他のパーツは全て前回の流用です。
<img width="350" alt="" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27488/c88f683b-7970-ecca-6ebd-c041fa8b0baf.jpeg>

また制御部である「ESP-WROOM-02」側も、サムターンを回転したら元に戻るようにソースコードを修正しておきます。


# 完成

無事に物理鍵で開けられるようになりました。
ようやく締め出しも発生しない健全な運用ができそうです。

<img width="350" alt="" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27488/65203156-a8b3-161a-7a6e-2a3a2b723114.gif>


[動画](https://youtu.be/TmvH0SXt0D0)

一応これで完成ですが、今後も改善は続けようと思います。
将来的にはWiFiの設定も基盤上のLCD画面で行えるところまで作り込むつもりです。
init?とは　失敗可能イニシャライザ

## 実行環境
Xcode 12.2
Swift 5.3.1

## 失敗可能イニシャライザ
失敗可能イニシャライザとは、初期化に失敗する可能性があるプロパティを初期化するときに使えるものです。
init?(引数)と記述し、失敗時にはnilを返します。

具体例を見ていきましょう。

### 記述例


```swift 
    
class TestFailInit {
    var num1: Any
    var num2: Any
    
    init?(_ num1: Any, _ num2: Any) {
        guard let num1 = num1 as? Int, let num2 = num2 as? Int else {return nil}
        
        self.num1 = num1
        self.num2 = num2
    }
```

こちらはnum1とnum2というAny型のプロパティを初期化時にInt型にダウンキャストするというものです。

しかし、引数によってはダウンキャストに失敗する可能性もあります。

このように初期化時に失敗する可能性があるときは失敗可能イニシャライザを使います。失敗時はreturn nilし、プロパティは未初期化状態となります。

```swift
if TestFailInit("テスト",5) != nil {
    // ダウンキャストに成功しているため
    print("初期化成功")
} else {
    // ダウンキャストに失敗しているため
    print("初期化失敗") // 初期化失敗
}
```

実際先ほどのものを初期化してみます。

こちらは引数にString型を取っているのでInt型にキャストできないですね。つまりreturn nilとなり、「初期化失敗」とプリントされます。

## 参考文献

石川洋資 / 西山勇世
［増補改訂第3版］Swift実践入門 ── 直感的な文法と安全性を兼ね備えた言語
32GB以上のSDカードをFAT32形式にフォーマット

## 目的
SDカード(32GB以上)をFAT32形式でフォーマットしたい．
しかし，Windows 10 の標準機能では32GB以上の記憶媒体はFAT32形式にフォーマットできない．
そこで，Raspberry Piで使用するためのツールを用いてSDカードをFAT32形式でフォーマットする．

## 準備
 - [Raspberry Pi Imager](https://www.raspberrypi.org/software/ "Raspberry Pi Imager") のインストール

## 手順

Raspberry Pi Imagerを起動
![raspberrypi_imager1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/995807/65bdff38-6b75-974d-23b8-6fddc43f6cd1.png)

"Operating System"の"CHOOSE OS"で"Erase"を選択
![raspberrypi_imager2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/995807/00d8ee64-93a4-6feb-93b9-667dbeff2784.png)

挿入したSDカードを選択し，"WRITE"を選択することで，SDカードがFAT32でフォーマットされる．
![raspberrypi_imager3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/995807/b175dcc0-0fe9-a01d-4a85-50ae8e0ded7f.png)
【AWS】 CloudWatch×AutoScallingで設定上限以上にインスタンスが作成されてしまった件

AWSのCloudWatchとAutoScallingを使用し、EC2インスタンスのCPU使用率が規定値を超過したらインスタンスを新しく立てるという検証をしていた際の失敗事例を記載します。

<h1>CloudWatchとAutoScallingの仕組み</h1>

それぞれの仕組みはこんな感じ。


[Amazon CloudWatch](https://aws.amazon.com/jp/cloudwatch/)
>CloudWatch は、AWS とオンプレミスで実行される AWS のリソース、アプリケーション、およびサービスを統括的に把握することができるように、ログ、メトリクス、およびイベントという形式でモニタリングデータと運用データを収集し、それらを自動化されたダッシュボードを使って可視化します。

>ユーザーが指定するメトリック値のしきい値に基づいたアラーム、または機械学習アルゴリズムに基づいて異常なメトリック動作を監視するアラームを作成することも可能です。


つまり、AWS上で動かすものを監視して、アラーム発砲ができるサービスみたいな感じです。

[AWS Auto Scaling](https://aws.amazon.com/jp/autoscaling/)
>AWS Auto Scaling は、安定した予測可能なパフォーマンスを可能な限り低コストで維持するためにアプリケーションをモニタリングし、容量を自動で調整します。AWS Auto Scaling を使用すると、複数のサービスにまたがる複数のリソースのためのアプリケーションスケーリングを数分で簡単に設定できます。

つまり、ユーザーが設定した範囲内でリソースを自動調整してくれるサービスみたいな感じです。

上記２つを組み合わせることで、リソースのある値が設定した閾値を超過した場合に、リソースを自動調整する仕組みを構築することができます。

<h1>発生した事象</h1>

今回の検証では、以下の２パターンの条件で実施していました。
【パターン①】
・EC2インスタンスのCPU使用率が７０％を超えたら新しくインスタンスを立てる
・その際のインスタンス上限数は４つ

【パターン②】
・EC2インスタンスのCPU使用率が３０％を下回ったらインスタンスを１つ削除する
・その際のインスタンス下限数は２つ

EC2インスタンスに以下のコマンドで負荷をかけました。

```
yes >> /dev/null &
```


その際、CPU使用率が７０％を超え、新しくインスタンスが起動してきたことを確認しました。
ずっと負荷をかけ続けていたので、４つまで自動でインスタンスが増えることを想定していました。

しかし、実際には以下の画像の通り、5個のインスタンスが起動してしまいました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316676/6646d7a4-be9a-6a4c-3012-544f75ca46f1.png)


上限の設定を間違えたかなと思い確認してみるも、きちんと４つに設定されていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316676/41f24ef2-55f9-f50e-efe8-42294dc2f9dd.png)

CloudWatchとの連携がおかしいのかと思い、とりあえず負荷をかける作業を中断。
すると、パターン②の方は問題なくクリアできていることが確認できました。

<h1>原因</h1>

この事象の原因は、AutoScallingのヘルスチェック機能の時間を短く設定してしまっていたことでした。

この機能は、EC2インスタンスが正常に起動しているか確認するためのものです。
AutoScalling設定の際に、猶予時間を設定する項目があるのですが、
こちらを短く設定してしまっていたためにこの事象が起きていたと考察しています。

猶予時間とは、インスタンスやサービスが起動し終わるまで、ヘルスチェックに失敗してもOKというものです。
デフォルトでは５分となっているのですが、検証でそんなに待ちたくない！という超絶短気な思考になってしまい、結果的にこんな事態を引き起こしてしまいました。

発生した経緯を推測すると、

・インスタンスのCPU使用率が７０％以上になった（この時のインスタンス数３）
・ヘルスチェックを実施し、起動しているor起動中のインスタンス数が４つ以下のため新たなインスタンスを起動（インスタンス④）
・インスタンス④起動中にヘルスチェックが実施される
・猶予時間を過ぎているため、起動完了していない状態がエラー状態となりトリガー発砲
・新たなインスタンスを起動（インスタンス⑤）

みたいな感じで上限を超えて増えていってしまったものと思われます。

ヘルスチェックの猶予時間はデフォルトのままいじらないのがよいというのが今回の学びでした。

<h1>参考</h1>
[AWS Auto Scaling](https://aws.amazon.com/jp/autoscaling/)

[Auto Scaling](https://qiita.com/leomaro7/items/60595987a308347d4d13)


<h2></h2>
この記事はAWS初学者を導く体系的な動画学習サービス
「AWS CloudTech」の課題カリキュラムで作成しました。
https://aws-cloud-tech.com
【Java 1.21 対応】Spigot Plugin のイベント一覧を作った

https://spigot-event-list.s7a.dev

# 紹介

[![sample](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628547/07493ec2-9b60-dc0d-23c3-3dab1545e51f.png)](https://spigot-event-list.s7a.dev)


こんな感じに名前と説明がまとまっています。バージョンは 1.21。

- Bukkit
- Spigot
- Paper
- Purpur
- BungeeCord
- Velocity

に対応しています。また、GitHub で管理されていますので、問題があれば Issue や PullRequest を出してくださればと思います。

https://github.com/sya-ri/spigot-event-list

# 余談

私自身、[Spigot V1.8.3のeventの一覧作ってみた](https://www.jias.jp/blog/?85) というブログに長いことお世話になっていました。しかし、最新バージョンに対応していないことやSpigot以外の環境（Paperなど)に対応していないことから代替のものを探していました。見つからなかったので作りました。
通信をするボットの開発

# 勉強の記録
通信をするボットの開発 2/7
## 勉強した内容
- crontab プログラムの自動実行をスケージュールの設定

## 何をベースに勉強してるか
- [N予備校 プログラミング入門](https://www.nnn.ed.nico/courses/668/chapters/9515)

## 内容の詳細
- HTTP　通信

### わかったことについて
- 数行書くだけで自動化BOTが作れるとは思わなかった
- これってもしかしてyoutubeの自動再生BOTも作れるのでは？？

### むずかしかったよ
```
mkdir -p $dirname
filename="${dirname}/hourly-ranking-`date +'%Y%m%d%H%M'`.xml"
```
この辺りは少し難しい

## 次回やる予定のこと
- GIThubを使うらしい…
Playwrightのメモ

# ブラウザをインストールしない

以下をつける。

```
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1
```

ほかのところだと忘れてうまくいかないので、
.npmrcにつけるとよい。
その後、必要なものを、以下のような感じで入れればOK

```sh:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=0 yarn add playwright-chromium
```

その他、もろもろのことをしたい場合には、[Playwright/Installation](https://playwright.dev/docs/installation/)を読むとよい。

# DockerImage

[mcr.microsoft.com/playwright](https://hub.docker.com/_/microsoft-playwright)を使う。
chromium-844399、firefox-1225、webkit-1423、node v14.15.4等がインストール済み。

```bash
FROM mcr.microsoft.com/playwright

# 日本語化
RUN apt-get update && \
    apt-get -y install locales fonts-ipafont fonts-ipaexfont && \
    echo "ja_JP UTF-8" > /etc/locale.gen && locale-gen

RUN mkdir /usr/src/app

WORKDIR /usr/src/app

# playwrightを入れる。でも、browserはすでに入っているので、普通にpackage.json経由でOK
RUN yarn add playwright

COPY . .

CMD ["node", "./index.js"]
```
GASの新しいエディタでタイムゾーンを変更する

# 前置き
昨年の12月7日に新しいエディタがリリースされ、GASでの開発効率が格段に上がりました！
何と言ってもインテリセンスが強力なのがいいですよね～
前のエディタではコメントアウトするのも`//`をタイプしないといけなかったですからね。
本当に便利になりました、ありがとうございます！

# いざ新しいエディタで開発
指定した時刻にSlackに通知する機能を作ろうと思いこんなコードを書いていました。
物は試しで17時にnotifyを実行するトリガーを作成しています。

```javascript
function myFunction() {
  var trigger = new Date();
  trigger.setHours(17);
  trigger.setMinutes(0);
  trigger.setSeconds(0);
  ScriptApp.newTrigger('notify').timeBased().at(trigger).create();
}

function notify(){
  // 通知処理!
}
```
トリガーの作成自体はうまくいっていますが、トリガーの起動時間がおかしいです。
プログラムを実行したのは`2021/02/7 13:58`です。
![trigger.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/843917/151b737d-5343-4dab-5ad9-4a7d9e7f8a9d.png)
なぜか`2021/02/06 23:59`にトリガーがセットされています。

# タイムゾーンを変更する
Dateがうまくいかない場合は大体タイムゾーンがおかしいです。
新しいエディタでタイムゾーンを変更するにはエディタの左側にある歯車のマークをクリックします。
![editor1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/843917/d45a2e77-e0e4-1fe3-b634-2a8ef56fb4c0.png)

一番下のチェックボックスにチェックを入れたら、左のメニューの`<>`をクリックしてコード編集画面に戻ります。
![editor2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/843917/49fdcef4-e91c-b989-d164-dcf2d8984ef6.png)

application.jsonをクリックして開きます。
![editor3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/843917/7cf584c7-3e73-34b1-8320-705475cc32c3.png)

`timeZone`の部分を`Asia/Tokyo`に修正して完成。
![editor4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/843917/6c900602-0f44-1ad8-83fc-a6aa9e351e1e.png)

# おわりに
新しいエディタになって基本的には使いやすくなったと感じていますが、メニュー画面がなくなったことによって、そのメニューが新しいエディタのどこにあるのかが分かりづらいのがふべんだなーと感じています。
ですが、概ね使いやすいのでそれほど気にならないです！
新しいエディタリリースに感謝！
【PDCAはもう古い】新事業チャレンジを成功させるPGPDCAについて 


現代のメーカーの開発現場では、既存のPDCAだけでは、上手くいかない事例が増えていると思います。

この記事では、PDCAの進化版である新方式「PGPDCA」について提案してみます。
「PGPDCA」は、既存のPDCAの頭に、「Practice(実践)」と「Gap Check(ギャップ確認)」を追加する手法です。

※「PGPDCA」は、一般的によく知られているPDCAの新方式「OODA」とも異なります。
　「PGPDCA」は、PDCAの純粋な進化版です。

#PDCAの問題点
現代で会社を成長させるためには、新事業や新技術へのチャレンジが必要不可欠となっています。

一方で、既存のPDCAは継続的な品質管理や改善の定番手法であるため、一定の効果はあります。しかしながら改善までに時間がかかるので、新事業には適用しにくい課題があります。

我々にとって重要なことは、もの凄く技術革新が速い現代において、タイムリーに新規事業を成功させ、さらに成長させることです。

#PGPDCAの提案
そのための解決策として「PGPDCA」を提案します。

「PGPDCA」はPDCAの進化版で、既存のPDCAの頭に「Practice(実践)」と「Gap Check(ギャップ確認)」を追加した手法になります。

#PGPDCAの流れ
##(1)Practice(実践)
まず、Practiceで実際にやってみます。

最近よく話題になる「PoC(実証実験)」や、ちょっとしたプログラムを作ってみる「試作」もこれに当たると思います。ここでは、最短期間で最大の結果が得られるようにやり方を工夫することが重要と思います。

##(2)Gap Check(ギャップ確認)
次にGap Checkで、現時点で我々は何ができていて、ありたい姿は何で、そのギャップは何かを明確にします。

特に、現時点で何ができているのかを事実ベースで確かなものにしておかないと、後の「Plan」で立てた計画が、その後の「Do」で崩壊します。したがって、しっかり確認することが必要です。

##(3)その後の流れ(PDCA)
既存のPDCAを実行します。

さらにその後は、また最初のPracticeに戻って、PGPDCAサイクルを回します。最後のActionが次のPracticeを兼ねられる場合は、１番目のPracticeを省略して2番目のGap Checkから始めても良いと思います。

#Gap Check時のありたい姿について
さらに、ありたい姿が我々の本質的な課題を解決するものか、吟味も必要です。

「犬の道はダメ！絶対！」
　
※犬の道とは・・・課題解決の入門書「イシューからはじめよ」の著者安宅和人さんが、同書において警鐘をならした「課題解決で陥りがちな罠」のことをいいます。


#まとめ
この記事では、PDCA進化版である「PGPDCA」についてまとめました。

本内容については、まだまだ議論の余地があると思うので、もしよろしければご意見頂けますと幸いです。少しでも新事業チャレンジの助けになれば幸いです。

以上
iTermからフォーカスが外れたときに自動で非表示にする（with BTT）

# はじめに
iTerm / iTerm2 を全画面フローティング表示で使っているマカーの皆さん

（全画面表示って何？って方は [iTerm2のおすすめ設定〜ターミナル作業を効率化する〜](https://qiita.com/ruwatana/items/8d9c174250061721ad11) を読んでみてください）

`$ open .`とか`$ mvim hoge.txt`とか、「別のアプリを開くよー」ってコマンド叩いたときにこんな感じになりません？？

![ezgif-3-b39ee3acf951.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275851/ef667557-3a11-720c-ecc9-5f88ed12af70.gif)

そう、iTermウィンドウの前にFinderが表示されてしまいます。

これめっちゃうざいんです。

そこで、「iTermからフォーカスが外れたら自動で非表示にしてほしい！！」 というニッチな層に向けて、BTTを使ったカスタマイズを紹介します。

# BetterTouchToolを使う

Macカスタマイズ界隈ではド定番のBetterTouchToolを使います。

知らない方はこちらより↓
[【Macユーザー必見】BetterTouchToolで極限まで作業効率をあげよう！！](https://qiita.com/ta1fukumoto/items/1d8199d53fed3be74996)

あまり紹介されていない「その他のトリガー」というトリッキーなメニューを使って設定します。

## 手順
1. 上部メニューから「その他のトリガー」を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275851/80fe81b7-3f92-36ae-6a7e-4f7bdcb57094.png)

2. トリガー > General > 「特定のアプリが非アクティブ化した」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275851/ead64829-ed2d-a975-5f4d-e8876f8a4d9e.png)

3. アクション > その他のアプリケーションの制御 > 「特定のアプリケーションを表示/非表示」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275851/21683472-2677-2b0a-cd7d-13f3ca717769.png)

4. アクション設定から「iTerm」を選択し、「Only Hide」にチェックを入れる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275851/94aa0608-ccd3-90bb-11c5-f272eeb916ab.png)

## 結果
open等のコマンドを叩き、フォーカスがFinderに移ると自動でiTermが隠れますね！！

快適。

![ダウンロード.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275851/bcf091cd-cbf1-4269-1551-be72fc3ef487.gif)


# おわりに
BTT便利っすね！
色々活用できそう！！

* スリープ復帰したとき
* 特定のアプリが起動したとき
* URLを踏んだとき

など、複雑なトリガーを使って色々できそうなので、遊んでみてください！！
何を学ぶかを決めるには from エンジニアの知的生産術(マイピックアップ)


「[エンジニアの知的生産術](https://www.amazon.co.jp/%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AE%E7%9F%A5%E7%9A%84%E7%94%9F%E7%94%A3%E8%A1%93-%E2%80%95%E5%8A%B9%E7%8E%87%E7%9A%84%E3%81%AB%E5%AD%A6%E3%81%B3%E3%80%81%E6%95%B4%E7%90%86%E3%81%97%E3%80%81%E3%82%A2%E3%82%A6%E3%83%88%E3%83%97%E3%83%83%E3%83%88%E3%81%99%E3%82%8B-WEB-PRESS-plus-ebook/dp/B07JFRF6MW/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=2GRDGUXMBTF82&dchild=1&keywords=%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AE%E7%9F%A5%E7%9A%84%E7%94%9F%E7%94%A3%E8%A1%93&qid=1608975046&sprefix=%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AE%E7%9F%A5%E7%9A%84%2Cstripbooks%2C272&sr=8-1)」を読み、今の自分にとって大切な考え方をピックアップ!

# 第7章. 何を学ぶかを決めるには

何を学ぶことが正解か事前に知ることは出来ない。
**時間、お金、やる気などのリソースを何に投資するかを意思決定すること!**
→ 経営戦略のアナロジーを知ることが大切

## 学びたい対象を探す探索戦略

何を学べばよいか悩んで1か月費やすよりも、何でもよいから何か一つを1か月学ぶ方がよい。**どうせ正解がわからないのならば、興味のある対象を学べばよい!**
→ **<font color='orange'>だんだんと学ぶ力が身につき、別の分野も効率良く学べるようになる。<font>**


## 知識を利用して拡大再生産戦略

### 社会人はまず「今やっている仕事の効率化」を学ぶべき!
→ **<font color='orange'>時間の余裕を作り、新たな学びに投資する。<font>**

- 知識を使って時間を得て、その時間を知識獲得に投資する
- 知識を使ってお金を得て、そのお金を知識獲得に投資する
- 知識を使って立場を得て、その立場を使って知識獲得をする

↓知識を使って立場を得て、その立場を使って知識獲得をする例

社内で「分野Aに詳しい人」になる。 →　分野Aに関する相談が自分に集中するようになる。 → 分野Aの知識の応用に関する情報が集まる。 → 知識を獲得できる。

**他の人より分野Aで詳しい人になれば、分野Aのうちのαタスクとβタスクが集まってきて、<font color='orange'>より費用対効果の良いαタスク(かかる時間が少ないが、知識や信頼、高給を得られるタスク)<font>を選択できる。**逆に知識が少ない人になれば、仕事を振られた時にはもう費用対効果の良いαタスクは選択肢にない。


### わからないことは15分で聞くべし!

わからないことに直面した場合、まず自分で15分解決を試みる。15分で解決しなかったら人に助けを求めるのが良い

→ **15分頑張っても解決できなかった場合、更に時間を費やしても解決できる可能性は低く、時間の無駄になる**
(経営視点からすると、人に相談すれば5分で解決する問題を、解決能力のない1人が1時間考え込んでも、時間と人件費の無駄。)

※15分が適切かどうかはチームによって変わる


## 掛け合わせによる差別化戦略

先輩が得意な分野で、先輩を打ち負かす必要はない。先輩が不得意な分野で、先輩よりも詳しくなれば良い。

### 複数の分野を掛け合わせることで一番になることは難易度が低い!

- 複数分野の知識を持つことにより人と共通知識が増え、スムーズなコミュニケーションが出来るようになる
- アイデアは新しい結合から生まれるため、複数分野の知識を持つことはアイデアを創り出す可能性を上げる

### 成長して卓越するのではなく、卓越することで成長の機会を得る

その知識分野に最も詳しい人になる状態を「卓越」と呼ぶ。
成長した結果卓越するのではなく、**まずは知識の掛け合わせによりニッチ分野で卓越し、その結果で掛け合わせたそれぞれの分野について成長の機会を得る。**
自分用　業務でよく使うGitコマンド

## はじめに
自分用なので時々更新されます。

## 新しいブランチを作成

`$ git checkout -b (ブランチ名) origin/master`
マスターをもとにブランチの作成

`$ git push -u origin (ブランチ名)`
リモートにブランチを登録

`$ git branch --set-upstream-to=origin/(ブランチ名)`
既に登録されているブランチを追跡ブランチに設定


## tagの作り方

`$ git tag タグ名`
コメント（注釈）なしでtagを切る。

`$ git push origin タグ名`
※tagを作成しただけではリモートに反映されないので必ずpushする。

`$ git co -b tag-タグ名 refs/tags/タグ名`
タグへの切り替え

## tagを削除する

`$ git tag -d TAGNAME`
ローカルのタグを削除

`$ git push origin :TAGNAME`

又は

`git push --delete origin TAGNAME`
削除したものをPUSHする
## add から push まで

`$ git add ファイル名`
ファイル名をステージング環境へaddする

`$ git commit`
エディターが開き保存するとコミットされる

`$ git push origin HEAD`
ローカルのカレントブランチがリモートの同名のブランチにpushされる。

## 削除
`$ git rm `
git管理下のファイルを削除する。

`$ git clean -f`
Untracked ファイルの削除 
※ディレクトリの場合は`dオプション`を付ける。

`$ git add -u`
削除されたファイルをaddする。

##取り込み
`$ git merge ブランチ名`
現在のブランチにブランチ名のブランチがマージされる。

### 変更を一時退避
 
`$ git stash`
一時退避

`$ git stash list`
保存状態一覧表示

``` 例.git
stash@{0}: ...
stash@{1}: ...
stash@{2}: ...
```

`$ git stash apply stash@{0}`
退避したファイルを戻す

### その他
#### .gitconfigの設定
```
[color]
branch = auto
diff = auto
status = auto
[alias]
st = status
ci = commit -a
br = branch
co = checkout
df = diff
[user]
name = hogehoge
email = hoge@hoge
```
【初心者でもわかる】-js不使用- 複数の画像を切り替える方法

# どうも7noteです。jsを使わずに画像の切り替えを実装する方法

複数の画像を一定時間で切替えたりするにはbxsliderなどの既存のjavascriptを読み込んで作成することが多いです。ですが、jsをつかわずに画像を切り替える方法を紹介。

![movie.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/73c050ae-0629-d03b-d4eb-ae078db41a12.gif)

## 複数の画像を自動で切り替える方法

```index.html
<div class="box"></div>
```

```style.css
.box {
  width: 200px;  /* 横幅を200pxに指定 */
  height: 200px; /* 高さを200pxに指定 */
  animation: image_anime 5s ease infinite; /* 5秒のアニメーションを繰り返す */
}
@keyframes image_anime {
  0% {
    background-image: url(photo01.jpg); /* 背景画像1を指定 */
  }
  50% {
    background-image: url(photo02.jpg); /* 背景画像2を指定 */
  }
  100% {
    background-image: url(photo01.jpg); /* 背景画像1を指定 */
  }
}
```

## まとめ

あまりこだわらず、ずっと背景を入れ替えるのを繰り返すだけならこのようなCSSだけでアニメーションを書くことができます。

jsを使う必要のないところは、使わずに済む方が簡単で良いですね。
でもこの方法だと画像ごとにaタグは設置できないので注意！

#### おそまつ！
~ Qiitaで毎日投稿中!! ~
[【初心者向け】WEB制作のちょいテク詰め合わせ](https://qiita.com/7note)
【Vue.js】オブジェクトのプロパティを追加してもリアクティブに動作しなかった時の備忘録


vue.jsでオブジェクトに新しくプロパティを追加してもリアクティブに動作しません。
未定義のプロパティをv-ifで参照させた時に、この事象に遭遇したため、調査してまとめました。

---

以下の3つのケースの変数を、v-ifに指定した場合の挙動について見ていきましょう。

- プリミティブな変数
- オブジェクトのプロパティ(定義済)
- オブジェクトのプロパティ(未定義)

## 例1：プリミティブな変数をv-ifに指定した場合

```vue
<template>
  <div>
    <button @click="show">表示する</button>
    <p v-if="isShow">クリックされました</p>
  </div>
</template>

<script>
export default {
  data () {
    return {
      isShow: false,
    }
  },
  methods: {
    show () {
      this.isShow = true
    }
  }
};
</script>
```

このケースの場合は、ボタンをクリックすると、期待通り`クリックされました`の文言が画面に表示されます。

![Kapture 2021-02-04 at 02.48.05.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397734/db538799-b355-a90b-f46d-f91fef766406.gif)


## 例２：オブジェクトのプロパティ(定義済)をv-ifに指定した場合

```vue
<template>
  <div>
    <button @click="show">表示する</button>
    <p v-if="hoge.isShow">表示</p>
  </div>
</template>

<script>
export default {
  data () {
    return {
      hoge: {
        isShow: false,
      }
    }
  },
  methods: {
    show () {
      this.hoge.isShow = true
    }
  }
};
</script>
```

この場合も、ボタンをクリックすると、期待通り`クリックされました`の文言が画面に表示されます。


## 例3：オブジェクトのプロパティ(未定義)をv-ifに指定した場合
```vue
<template>
  <div>
    <button @click="show">表示する</button>
    <p v-if="hoge.isShow">表示</p>
  </div>
</template>

<script>
export default {
  data () {
    return {
      hoge: {
        // isShow: false, コメントアウトで未定義にしています
      }
    }
  },
  methods: {
    show () {
      this.hoge.isShow = true
    }
  }
};
</script>
```

この場合、初期表示時点では期待通り、文言が表示されていません。(コンソールにもエラーは吐かれません。)

では、ボタンをクリックしてみます。
![Kapture 2021-02-04 at 02.56.36.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397734/74178b19-b584-6739-3bbe-c3b5f45db98c.gif)

この場合、`this.hoge.isShow = true`の処理が実行されるのですが、`クリックされました。`の文言は表示されません。解説・理由は以下の通りです。

## オブジェクトのプロパティを追加してもリアクティブに動作しない

Vueはコンポーネント生成時(onCreate時)のデータに対して変更検出を行うため、生成時に未定義のプロパティが後から追加されても、リアクティブなプロパティとして動作させることができません。

> https://vuejs.org/v2/guide/reactivity.html#For-Objects
\# For Objects
Vue cannot detect property addition or deletion. ...




## 解決策
例３のような、オブジェクトのプロパティ追加時でも`リアクティブ`に動作させるには、Vue.setを利用します。

- Vue.set(object, propertyName, value)の使用  
  - 第１引数： 追加したいオブジェクト
  - 第2引数： 追加したいプロパティ名
  - 第3引数： プロパティの値  

Vue.setのエイリアスの`this.$set`を利用して、例３の場合でもリアクティブに動作するよう実装してみる。

```vue
<template>
  <div>
    <button @click="show">表示する</button>
    <p v-if="hoge.isShow">表示</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      hoge: {
        // isShow: false, コメントアウトで未定義にしています
      }
    };
  },
  methods: {
    show() {
      this.$set(this.hoge, "isShow", true);
    }
  }
};
</script>

```
![Kapture 2021-02-04 at 02.48.05.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/397734/db538799-b355-a90b-f46d-f91fef766406.gif)

`this.hoge`に`isShow (true)`が追加されたことをVueが検知できるので、`クリックされました。`の文言が無事に表示されました。🙌

## 補足
Vue3では、オブジェクトのプロパティ追加時でも**リアクティブに動作する新仕様**になっているっぽいので、技術調査したら改めて記事にしようと思います。
Jenkinsの環境構築／利用時メモ

#####(1) JAVAのプログラムに対してテストプログラムを実行したが、実行エラーで発生
コンソールのメッセージで
”unable to locate a java runtime to invoke.”と出た。
⇨JAVAが正常にインストールされていないので、再インストール。

MacOS版ダウンロードはこちらから。
JRE
https://www.java.com/ja/download/mac_download.jsp

JDK
https://www.oracle.com/technetwork/java/javase/downloads/index.html

両方インストールすることで無事にテスト成功。


#####(2)ビルド間隔の設定
こちらを参考にしました。
https://qiita.com/koara-local/items/79cb9c08e77ac9d94b1d

「*****」ではなくて、「* * * * *」のように半角スペースで空けることが必要です。地味にハマってしまった。

#####(3)Slack通知
現時点(21.2.7）でオフィシャルでは正しい解説がないので、こちらを参考にした。
https://qiita.com/i_12121226/items/36dc0a9302e16ce29c11
セレクトボックスは値(value)でなくキー(key)で保存する

セレクトボックスでデータを保存する際、値でなくキーで保存する方法を紹介します。

### キーで保存するメリット
・セレクトボックスの表示を変えたい場合、データベースに登録しているレコードの値を変更する必要がありません。
・日本語のデータを保存する際に、keyを日本語にする必要がありません（コードの見た目の問題）

### やりかた
`invert`メソッドを使います。ハッシュの`key`と`value`が逆転します。

```ruby:selectbox.rb
<%= form_with url: users_path do |f| %>
  <%= f.select :fruit, { a: "りんご", b: "みかん" }.invert %>
  <%= f.submit "保存" %>
<% end %>
```

`invert`を使った上記コードの場合、
・ブラウザに表示されるのは、「りんご」「みかん」
・保存されるのは、「a」「b」です。

もし、セレクトボックスの表示を変えたくなったら

```ruby:selectbox.rb
<%= form_with url: users_path do |f| %>
  <%= f.select :fruit, { a: "ぶどう", b: "もも" }.invert %>
  <%= f.submit "保存" %>
<% end %>
```

上記のようにすればOKです。
既存のレコードの値を変える必要がなく管理が楽になります:relaxed:

以上です。

### 記事を書いた背景
キー(key)を日本語で書くのは、エンジニアの中には違和感を持つ方もおられるそうです。
そのため、下記のようなコードは控えたほうがいいそうです。

```ruby:selectbox.rb
<%= form_with url: users_path do |f| %>
  <%= f.select :fruit, { りんご: "りんご", みかん: "みかん" } %>
  <%= f.submit "保存" %>
<% end %>
```

もちろんこのままでも正常に動きますけどね:point_up:
ただ、そうなるとセレクトボックスの表示が英語になってしまうんですよね。

```ruby:selectbox.rb
<%= form_with url: users_path do |f| %>
  <%= f.select :fruit, { a: "りんご", b: "みかん" } %>
  <%= f.submit "保存" %>
<% end %>
```

これでは困るということで、`invert`メソッドを使ったわけです。

### 開発環境
Ruby: 2.7.1
Rails: 6.0.0.3
【Python】ABC191 D - Circle Lattice Points (誤差問題)【AtCoder】

[ABC191 D - Circle Lattice Points](https://atcoder.jp/contests/abc191/tasks/abc191_d)

ふりかえりをしていたが、
解説見て、解き方わかったのにどうしてもWAが消えない
10000倍して、整数でやってるつもりなのに、どうして！！！
ということでACの人たちのコードみたら、
10000倍してる人も**ルート計算で結局Decimal使ってるっぽい！**

#結論

**Decimal最強伝説！**
誤差問題はDecimalで提出しましょう。
※ちなみに、PyPyはDecimal計算遅いので、Pythonで提出しましょう。

#以下結論までの軌跡・・・
提出したコードたちはこちら

```python:WA1.py
import math,sys
def LS(): return list(sys.stdin.readline().rstrip().split())
#############################
from decimal import Decimal
n = 10000
X,Y,R = [int(Decimal(x)*n) for x in LS()]

ans = 0
for y in range(math.ceil((Y-R)/n),math.floor((Y+R)/n)+1):
    z = (R**2-(Y-y*n)**2)**0.5
    ans += math.floor((X+z)/n)-math.ceil((X-z)/n)+1

print(ans)
```
![スクリーンショット 2021-02-07 14.09.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/785975/b8e21bd8-491a-1f2b-5dc2-8e2d75511337.png)

ansの足し算のところで、整数+小数だから、そこで誤差発生してるのかな？
zを整数にしてみよう。

```python:WA２.py
import math,sys
def LS(): return list(sys.stdin.readline().rstrip().split())
#############################
from decimal import Decimal
n = 10000
X,Y,R = [int(Decimal(x)*n) for x in LS()]

ans = 0
for y in range(math.ceil((Y-R)/n),math.floor((Y+R)/n)+1):
    z = int((R**2-(Y-y*n)**2)**0.5)
    ans += math.floor((X+z)/n)-math.ceil((X-z)/n)+1

print(ans)
```
![スクリーンショット 2021-02-07 14.09.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/785975/b8e21bd8-491a-1f2b-5dc2-8e2d75511337.png)

なんでや・・・

#原因は「**0.5」
ルートを出すときに、**0.5っていうfloat型使ってるんじゃい！！！**
誤差がでるんじゃい！！！
無意識だった。。。

```python:AC1.py
import math,sys
def LS(): return list(sys.stdin.readline().rstrip().split())
#############################
from decimal import Decimal
n = 10000
X,Y,R = [int(Decimal(x)*n) for x in LS()]

ans = 0
for y in range(math.ceil((Y-R)/n),math.floor((Y+R)/n)+1):
    z = int(Decimal(R**2-(Y-y*n)**2).sqrt())
    ans += math.floor((X+z)/n)-math.ceil((X-z)/n)+1

print(ans)
```
![スクリーンショット 2021-02-07 14.24.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/785975/2e79ba5b-9b61-74f6-fe82-dd18b1be0a92.png)


というかそもそも誤差問題全部Decimalで計算すれば最強じゃね？
10000とかかける必要なくね？？？

```python:AC2.py
import math,sys
def LS(): return list(sys.stdin.readline().rstrip().split())
#############################
from decimal import Decimal
X,Y,R = [Decimal(x) for x in LS()]

ans = 0
for y in range(math.ceil(Y-R),math.floor(Y+R)+1):
    z = (R**2-(Y-y)**2).sqrt()
    ans += math.floor(X+z)-math.ceil(X-z)+1

print(ans)
```
![スクリーンショット 2021-02-07 14.24.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/785975/2e79ba5b-9b61-74f6-fe82-dd18b1be0a92.png)

#まとめ

**Decimal最強伝説！**
誤差問題はDecimalで提出しましょう!!!


おわり！！！
Go: JWT のペイロード部をデコード

こちらのプログラムを Go で書き換えました。
[Node.js: JWT のペイロード部をデコード](https://qiita.com/ekzemplaro/items/3e2c1e9cf9189a79b27c)
[Python3: JWT のペイロード部をデコード](https://qiita.com/ekzemplaro/items/e24d6af29ddc01683417)

```go:decode_jwt.go
// ---------------------------------------------------------------
//
//	decode_jwt.go
//
//				  Feb/07/2021
// ---------------------------------------------------------------
package main

import (
	"fmt"
	"os"
	"strings"
	"io/ioutil"
	b64 "encoding/base64"
)

// ---------------------------------------------------------------
func decode_jwt_proc(str_token string) string {
	aaa := strings.Split (str_token,".")
	str_bbb := strings.Replace(aaa[1],"-","+",-1)
	str_ccc := strings.Replace(str_bbb,"_","/",-1)

	llx := len(str_ccc)
	nnx := ((4 - llx % 4) % 4)
	ssx := strings.Repeat("=" , nnx)
	str_ddd := strings.Join([]string{str_ccc,ssx},"")
	ppp, err :=  b64.StdEncoding.DecodeString(str_ddd)
	if err != nil {
		fmt.Fprintf (os.Stderr,"*** error *** StdEncoding.DecodeString ***\n")
		fmt.Println("error:", err)
		return "error"
	}

	uEnc := b64.URLEncoding.EncodeToString([]byte(ppp))
	decode, _ := b64.URLEncoding.DecodeString(uEnc)

	return string(decode)
}

// ---------------------------------------------------------------
func main() {

	fmt.Fprintf (os.Stderr,"*** 開始 ***\n")
	file_token := os.Args[1]
	fmt.Fprintf (os.Stderr,"file_token = " + file_token + "\n")

	buff,_ := ioutil.ReadFile(file_token)
	fmt.Fprintf (os.Stderr,"len(buff) = %d\n" , len(buff))

	json_str := decode_jwt_proc(string(buff))
	fmt.Println (json_str)

	fmt.Fprintf (os.Stderr,"*** 終了 ***\n")
}

// ---------------------------------------------------------------
```

実行方法

```bash
go run decode_jwt.go token01.txt | jq .
```
テストコードについて調べてみた

# はじめに
テストコード書いてますか？
自分は書いていませんでした。実際テストコードも書いているという案件に出会ったことがなくあまり調べたりもしませんでした。。。
テストコードを業務上書いているという人の方が多そうだなと感覚的には思います。

ただ、「どうかこのコードが動きますように」と祈るのは精神的にきついと思いテストコードがそれを解決してくれるのではとググってみました。(もちろんテストはしている)
テストコードがどのような役割をしてくれるのかや、効果、そして、祈らず安心して開発ができるようになるのか、なぜテストコードを書かないことがあるのかを考えます。

テストコードの書き方例えば、xUnit系などの使い方は書きません。

# テストコードの役割
テストは以下が挙げられます。(その他にもシステム毎に種類があると思いますが、どの案件でも大抵これらは絶対にやっていることが多かと。)

- 単体テスト(機能単位のテスト)
- 結合テスト()
- システムテスト

テストコードは主に上記のテストよりもコードにより近く、粒度の小さい**メソッド** 単位のテストを担う

# テストコードのチェック内容
テストコードは基本的に**メソッドの戻り値**が期待通りかを確認する。
つまり、**戻り値がないメソッドはテストしづらい。**今まで、平気で戻り値がvoidのメソッド作ってきたので、voidは避けた方が良さそうです。
書きづらいというだけで、クラスのプロパティやDB、ファイルに何かしらアウトプットがあると思うので、そこを確認するようにすればテストはできます。

# メリット
どんなメリットがあるのか

- **リファクタリングしやすくなる**
- データのパターンをテストコード内で用意できるためテスト作業が楽
- データのパターン分画面でぽちぽち操作しながら検証せずに済む
- テストコードがない場合よりも早期にバグを発見できる
- 仕様をテストコードにわかりやすく書くことで他の人がそのメソッドの内容を理解しやすくなる
- 不具合を再現するのが楽
- 設計全体を理解する助けになることもあるらしい

リファクタリングをしやすくなるという点がテストコードにおいて最大のメリットかと思います。
何か既存のメソッドをリファクタリングした際にテストコードがあればコマンド1つでちゃんと動作したのかを確認でき安心してリファクタリング挑むことができる。
もちろんリファクタリング以外の機能改修のテストとしても使用できるかと思いますが、
他のテストフェーズでも正常に動くかを確認することができるため、テストコード特有のメリットではないと自分は調べた結果思いました。

# デメリット
どんなデメリットがあるか

- テストコードを学ぶ時間がかかる
- テストコードのコード規約を決める必要がある
- テストコードを書く時間が追加で必要となる
- テストコードのレビューが必要となる
- テストコードのメンテナンスが必要となる

デメリットは今までよりも追加時間がかかることだと思います。これは案件によって採用ができるかどうかに関わってきそうなデメリットですね。

# なぜテストコードを書かかないことがあるのか
- テストコードがなくてもシステムは動く
- 工数がかかることが問題となる
- リファクタリングの文化がない
- テストコードが書きやすいコードではない(保守フェーズ)

会社、案件、クライアントによっては時間が取れないことも多くあるため、テストコード書けないということは多そうです。
受託開発で、納品したら終わりという場合、リファクタリングの文化はなさそうですね。
すでに出来上がっているものに対して、テストコードを書こうとした場合に書きづらいということが起きる

# まとめ
テストコードの効果が一番はっきするのはリファクタリングの時だということがわかりました。
また、導入するかしないかは状況によって判断が変わるということですね。
テストコードはエンジニアの最強のツールという訳ではない。
品質の高いソフトウェアを作ることが目的で、単体テストで確認するのか、テストコードで確認するのかという手段が2つあり、どっちを選ぶのがいいかは状況を見て判断する。

テスト駆動開発の本とか読んで、もう少しインプットして絶対やるべきと考えが変わったら、記事更新します。

参考記事
- [【初心者向け】テストコードの方針を考える（何をテストすべきか？どんなテストを書くべきか？）](https://qiita.com/jnchito/items/2a5d3e15761fd413657a)
- https://mynavi-agent.jp/it/geekroid/2014/05/post-10.html
iCloud DriveをOn/Offした時の挙動に関して

##前提##
iCloud Driveを使うようにアプリを設計している。

##iCloud DriveをOffにする##
iOSの設定->アカウント->iCloud->iCloud Driveで一気に、または一覧からアプリ個別に
Offにすると、[[NSFileManager defaultManager] URLForUbiquityContainerIdentifier: <コンテナのID>];がnilを返す。Onならば適切なURLが返ってくる。
例: "file:///private/var/mobile/Library/Mobile%20Documents/iCloud~com~yourdomain~yourapp/"	0x0000000283860310）

アプリのファイルを保存する目的でiCloud Driveを使う場合、nilが返ってきたらfallbackとしてデバイス上に保存するようにしている(Documentsなど)。ややこしいのは、アプリの起動中でもこの設定は変えられてしまう可能性があることかな。適切な挙動としては、アクセスの必要があるたびにnilチェックを行って保存場所を変えるようにする必要があると思う。
new Proxy の get() の引数である receiver って何 ?

` new Proxy` のトラップ (trap)にある `get` メソッドの引数の `receiver` は何が渡ってきているのかを調べました。

```javascript
const target = {
  name: "k",
  get hello() {
    return this.name
  }
};

const handler = {
  get (target, key, receiver) {
    return Reflect.get(target, key, receiver)
  }
};

const proxyObj = new Proxy(target, handler);
console.log(proxyObj.name)
```

> receiver
proxy、または proxy から継承するオブジェクトのどちらか
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Proxy/Proxy/get

MDN での receiver の説明にあるように、receiver で渡される値は、**proxy、または proxy から継承するオブジェクトのどちらか**です。

上記のコード例だと、`proxyObj.name` によって `get()` が呼ばれ、そのときに `receiver` に渡ってくる値は、`proxyObj`です。

`proxyObj` は、`new Proxy(target, handler)` によって、`target` を継承しているため、 **proxy から継承するオブジェクト**(= `target`) であると、私は解釈しました。


間違いがあればご指摘下さい。
Can't connect to local MySQL server through socket '/tmp/mysql.sock' の解決方法【結論：MySQLの起動】

rails開発中にモデルを作成しようとしたらターミナルに以下の様なエラーが表示されました。昨日までは問題なく作成できていたのに...

```
Can't connect to local MySQL server through socket '/tmp/mysql.sock' 
```

今回はこのエラー解決までの過程を書いていきます。

# 開発環境
Mac OS Catalina: 10.15.7
ruby: 2.6.6
rails: ~> 6.1.0
mysql: 8.0.23

# 結論
MySQLを起動していなかった。

#　MySQLでDBを作成したい

```rails db:create```を実行してDBを作成しようとしたら以下の様なエラー文が表示された

```
Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
Couldn't create 'room_anatomy_development' database. Please check your configuration.
rails aborted!
ActiveRecord::ConnectionNotEstablished: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
/Users/cha-han/workspace/room-anatomy/bin/rails:5:in `<top (required)>'
/Users/cha-han/workspace/room-anatomy/bin/spring:10:in `block in <top (required)>'
/Users/cha-han/workspace/room-anatomy/bin/spring:7:in `tap'
/Users/cha-han/workspace/room-anatomy/bin/spring:7:in `<top (required)>'

Caused by:
Mysql2::Error::ConnectionError: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
/Users/cha-han/workspace/room-anatomy/bin/rails:5:in `<top (required)>'
/Users/cha-han/workspace/room-anatomy/bin/spring:10:in `block in <top (required)>'
/Users/cha-han/workspace/room-anatomy/bin/spring:7:in `tap'
/Users/cha-han/workspace/room-anatomy/bin/spring:7:in `<top (required)>'
Tasks: TOP => db:create
(See full trace by running task with --trace)
```

エラー文前半から、どうやら/tmp/mysql.sockを通してMySQLと繋がるつもりができなかった様だ。
そもそもsocketとは何だろうか？軽く調べてみた。

ソケットとは
MySQLのクライアントとサーバをつなげるための通信機構のこと

おそらく、ソケットの設定が書かれた/tmp/mysql.sockファイルが見つからないからMySQLに繋がることができない。
実際にファイルを探したが見つからなかった。

色々試行錯誤したが、そもそもMySQLが起動していたか試してみるとあっさり直った。
/tmp/mysql.sockファイルも作成されていた。

```
mysql.server start
```

#まとめ
ケアレスミスですが、自分への戒めのために残しておきます。
python単体テストでdatetimeをモック化する

`datetime.now()`が返す値を固定化するのにハマったので、事象と解決策を残しておきます。

# 前提
* 環境
    * python 3.8
    * ライブラリ
        * pytest
* 以下のコードをテストする

```python:sample.py
from datetime import datetime

def func():
    return datetime.now()
```


# 失敗例
一番初めに思いつくのが`datetime.now()`に対してモックを当てることですが、これは失敗します。

```python:test_sample.py
from datetime import datetime
from unittest import mock
from sample import func

@mock.patch('app.sample.datetime.now')
def test_func(m_now):
    m_now.return_value = datetime(2021, 2, 1)
    actual = func()
    assert actual == m_now()
```

```:テスト実行結果
...
E       TypeError: can't set attributes of built-in/extension type 'datetime.datetime'
...
```
「`datetime.datetime`の属性を勝手に変更しようとすんじゃねぇよ！！！！」と怒られました。

このようなエラーが発生する理由は、`datetime`がイミュータブルなオブジェクトだからです。
イミュータブルなオブジェクトなので、メソッドを新しい関数（mock）に差し替えることができません。(参考：[イミュータブルってなに？](https://python.ms/immutable/#_1-%E7%B0%A1%E5%8D%98%E3%81%AB%E8%A8%80%E3%81%88%E3%81%AF%E3%82%99))

# 成功例
では、どうやって`datetime.now()`の値を固定化すればいいのか。
これは`datetime`オブジェクトの中身を弄るのではなく、`datetime`オブジェクトごと差し替えてあげることで解決できます。

```python:test_sample.py
from datetime import datetime
from sample import func

@mock.patch('app.sample.datetime')
def test_func(m):
    m.now.return_value = datetime(2021, 2, 1)
    actual = func()
    assert actual == m.now()
```

```:テスト実行結果      
...
================== 1 passed in 1.23s ==================
```

# 最後に
モック化するときは、対象のオブジェクトがイミュータブルかどうかは注意しておきたいですね。
ちなみにpytestが一つも出てきてないですが、裏でテストを実行してくれてました。
また、pytestでmockを使うなら`pytest-mocker`などを調べてみるのも面白いです。
では。

# 参考
[まだmockで消耗してるの？mockを理解するための3つのポイント](https://note.crohaco.net/2015/python-mock/)
[Trying to mock datetime.date.today(), but not working｜stack overflow](https://stackoverflow.com/questions/4481954/trying-to-mock-datetime-date-today-but-not-working)
【流出解析】シリーズ　第10回　流出量・比流量・流出高の違い

# 移転のお知らせ

こちらの記事は下記のサイトに移転しました。

> [NNテックブログ](https://nnhiroba.xsrv.jp/nnTechBlog/Article/Article?ID=42)
Python3: JWT のペイロード部をデコード

こちらのプログラムを Python3 で書き換えました。
[Node.js: JWT のペイロード部をデコード](https://qiita.com/ekzemplaro/items/3e2c1e9cf9189a79b27c)

```py:decode_jwt.py
#! /usr/bin/python
# -*- coding: utf-8 -*-
#
#	decode_jwt.py
#
#					Feb/08/2021
#
# ------------------------------------------------------------------
import	sys
import	os
import	json
import	urllib
import	requests
import	base64
#
# ------------------------------------------------------------------
def decodeJWT(str_token):
	sys.stderr.write("len(str_token) = %d\n" % len(str_token))
	aaa = str_token.split(".")
#
	str_bbb = aaa[1].replace("-","+").replace("_","/")
	sys.stderr.write("len(str_bbb) = %d\n" % len(str_bbb))
	ppp = ""
	try:
		str_bbb += "=" * ((4 - len(str_bbb) % 4) % 4)
		ppp = base64.b64decode(str_bbb)
	except Exception as ee:
		sys.stderr.write("*** error *** in b64decode ***\n")
		sys.stderr.write(str(ee) + "\n")
	qqq = urllib.parse.quote(ppp)
	json_str = urllib.parse.unquote(qqq)
#
	return json_str
# ------------------------------------------------------------------
sys.stderr.write("*** 開始 ***\n")
file_token = sys.argv[1]
sys.stderr.write(file_token + "\n")
#
if os.path.exists(file_token):
	try:
		fp_in = open(file_token,encoding='utf-8')
		str_token = fp_in.read()
		fp_in.close()
#
		json_str = decodeJWT(str_token)
		unit_aa = json.loads(json_str)
		print(json_str)
	except Exception as ee:
		sys.stderr.write("*** error *** in jwt.decode ***\n")
		sys.stderr.write(str(ee) + "\n")
#
else:
	sys.stderr.write("*** error *** %s doesn't exist ***\n" % file_token)
#

sys.stderr.write("*** 終了 ***\n")
# ------------------------------------------------------------------
```

実行方法

```bash
./decode_jwt.py token01.txt | jq .
```

参考ページ
[‘Incorrect padding’ エラー対処方法.Pythonでbase64を用いてdecode](https://prglog.info/home/?p=135)
[2021年最新]小学生でも分かるAWSのデプロイ手順説明書 中編

# 説明書

[[2021年最新]小学生でも分かるAWSのデプロイ手順説明書 前編](https://qiita.com/ren0826jam/items/0d5583cb5b0d8c2a1ddd)

[[2021年最新]小学生でも分かるAWSのデプロイ手順説明書 後編](https://qiita.com/ren0826jam/items/2b7df26f7e02a12b2ff9)

## 注意点
- (EC2)...EC2内で行う。

- (ローカル)...EC2内で行う。

## デプロイ編

### 手順

#### 1.ライブラリのアップデートを行う(EC2)

```ruby

$ sudo yum update -y
```

#### 2.タイムゾーンとロケールの設定を行う(EC2)

```ruby

$ sudo timedatectl set-timezone Asia/Tokyo
$ sudo localectl set-locale LANG=ja_JP.UTF-8
```

#### 3.NTPの設定を行う(EC2)

```ruby

$ yum info chrony
$ chronyc sources -v
```

#### 4.標準パッケージのインストールを行う(EC2)

```ruby

$ sudo yum -y install gcc-c++ glibc-headers openssl-devel readline libyaml-devel readline-devel zlib zlib-devel libffi-devel libxml2 libxslt libxml2-devel libxslt-devel git
```

#### 5.データベースモジュールのインストールを行う(EC2)

- PostgreSQLの場合

```ruby

$ sudo yum -y install postgresql-devel
```

- MySQLの場合

```ruby

$ sudo yum -y install mysql-devel
```

#### 6.Rubyのインストールを行う(EC2)
※今回は2.7.2としてます。自分の環境に合わせて任意で変更お願いします。

- rbenvのインストール

```ruby

$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
$ source ~/.bash_profile
$ rbenv -v
```

- ruby-buildのインストール

```ruby

$ git clone git://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
$ cd ~/.rbenv/plugins/ruby-build
$ sudo ./install.sh
$ rbenv install -l
```

- Rubyのインストール

```ruby

$ rbenv install 2.7.2
$ rbenv global 2.7.2
```

#### 7.node.jsのインストールを行う(EC2)

```ruby

$ curl -sL https://rpm.nodesource.com/setup_14.x | sudo bash -
$ sudo yum install -y nodejs
$ sudo npm install -g n
$ sudo n stable
$ sudo ln -snf /usr/local/bin/node /usr/bin/node
```

#### 8.yarnのインストールを行う(EC2)

```ruby

$ curl --silent --location https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo
$ sudo yum install yarn -y
```

#### 9.Railsのインストールを行う(EC2)

```ruby

$ cd ~
$ mkdir rails
$ cd rails
$ bundle init
$ vim Gemfile 
# 「gem "rails", "〇〇"」部分を、"自分の環境のバージョン"に書き換え、コメントアウト解除

$ bundle install
$ bundle exec rails -v
# インストールされたことを確認

$ cd ..
$ rm -rf rails
```

#### 10.データベースの設定を行う(ローカル)

```ruby

$ EDITOR="vim" bin/rails credentials:edit
```

下記を追記する。

```credentials.yml.enc

db:
  username: (作成したDBのusername)
  password: (作成したDBのpassword)
  host: (作成したDBのdatabase endpoint)
```

続いて、config/database.ymlを編集。

```config/database.yml

production:
  <<: *default
  database: sample_app # 自分のアプリ名
  username: <%= Rails.application.credentials.db[:username] %>
  password: <%= Rails.application.credentials.db[:password] %>
  host:     <%= Rails.application.credentials.db[:host] %>
  port:     3306 # MySQLの場合
```


## 前編終了！
お疲れ様です。ここまでで、デプロイ作業の半分が完了しました。
次編からは、とうとうデプロイを行っていくので頑張りましょう！！！
[後編に続く...](https://qiita.com/ren0826jam/items/2b7df26f7e02a12b2ff9)
open(0)とすると標準入力に対応するファイルオブジェクトが取得できる

Python3で標準入力から入力を読む方法はいくつかありますが、組み込み関数の`open`を使って、`open(0)`とすると標準入力に対応するファイルオブジェクトを取得できます。

利用例としては以下のようになります。

```python
stdin = open(0)
for line in stdin:
    do_something(line)
```

`open`の引数を`0`にすると、なぜ標準入力になるのでしょうか? [ドキュメントを注意深く読むと以下のように記述されています。](https://docs.python.org/ja/3/library/functions.html#open)

> file は path-like object で、開くファイルの (絶対または現在のワーキングディレクトリに対する相対) パス名を与えるものか、または、ラップするファイルの整数のファイルディスクリプタです。

`open`の引数としてはファイルパスだけでなく、ファイルディスクリプタを示す整数を指定することもできます。標準入力のファイルディスクリプタは0ですから、`open(0)`とすると、標準入力に対応するファイルオブジェクトが取得できるわけです。

なお[`sys.stdin`](https://docs.python.org/ja/3/library/sys.html#sys.stdin)も標準入力のファイルオブジェクトです。つまり`open(0)`の戻り値と`sys.stdin`は実質的には同じものになるといえます。`sys.stdin`のほうが、標準入力を利用することが明確でわかりやすいのですが、`import sys`とする必要があって、タイプ数が増えます。コードゴルフや競技プログラミングなどでは`open(0)`のほうがお得かもしれません。
脱prettier

# prettierとは

Javascriptとかのフォーマットをして**きれい**に成型してくれるもの。
でも、本当に**きれい**なんか？？？
と思うことがままある。

## 例えば......

```js:prettier前
  const actions = useMemo(() => bindActionCreators({ toggleTodo }, dispatch), [dispatch])
```

```js:prettier後
  const actions = useMemo(() => bindActionCreators({ toggleTodo }, dispatch), [
    dispatch,
  ])
```

長いから、短くしたんだろうけど、かっこ悪くない？？？
ということで、頑張って、変えてみる。

```js:変更後
  const actions = useMemo(
    () => bindActionCreators({ toggleTodo }, dispatch),
    [dispatch],
  )
```

これで、短いから、大丈夫！
で、再度やってみると......

```js:再度prettier後
  const actions = useMemo(() => bindActionCreators({ toggleTodo }, dispatch), [
    dispatch,
  ])
```

......
辛い......
シンプルと言いつつ余計な事しすぎなんじゃない？？？

# 脱prettiersして、ESLintだけでやってみる

いっそのこと、[Javascript Standard Styleスタイルガイド](https://standardjs.com/readme-ja.html)だけをやってみる。
Typescriptに対応したのもあるようなので、以下のような感じで、組み込む。

```sh:
# dependenciesでOKな場合。
$ yarn add eslint-config-standard-with-typescript eslint-plugin-node eslint-plugin-promise
# devDependenciesに入れたい場合。
$ yarn add -D eslint-config-standard-with-typescript eslint-plugin-node eslint-plugin-promise
```

```js:eslintrc.js
module.exports = {
  extends: [
    'standard-with-typescript',
    'react-app',
    'react-app/jest'
  ],
  parserOptions: {
    project: './tsconfig.json'
  },
  rules: {
    'max-len': ['error']
  }
}
```

＃[max-len](https://eslint.org/docs/rules/max-len)はいろいろスルーしたいときもあるので、もう少し細かく調整が必要。
＃ignoreXxxは全部trueでもよさげ。

これでやると、ある程度フォーマットは効く。
が、発端のmax-lenはエラーのままなので、手作業でやる必要がある。
手作業で、直してあげておしまい。


```js:ESLint前
  const actions = useMemo(
    () => bindActionCreators({ toggleTodo }, dispatch),
    [dispatch],
  )
```

```js:ESLint後
  const actions = useMemo(
    () => bindActionCreators({ toggleTodo }, dispatch),
    [dispatch]
  )
```

trading-commaがルールの違いで、変わったけど、この辺は、これからはそっちに寄せるということで、いったんはここまで。
ESP-WROOM-02でスマートロックを作ろう①


# はじめに
スマートロックを自作する記事です。

スマートロックを自宅に取り付けたいなぁと思っていたが、実は市販製品は２万円を超えたりと結構値段が高く、ネットワークを介した活用プランだとサブスク料金もそれなりの費用が掛かることが判明。なので作ることにした。

開発に関して、当初は「RaspberryPi zero W」で作るつもりだったが、ESPr系で作る記事を当時見かけなかったので敢えてこちらで作ってみたかった。（野心？）
調べてみると「ESP-WROOM-02」というWi-Fi付きのマイコンがあるというのを知った。これなら起動が早く、シンプルに作れそうだと当時の直感で思った。
https://akizukidenshi.com/catalog/g/gM-09607/

# 使用物品

- 制御部
 - ESP-WROOM-02（[秋月電子の開発キット](https://akizukidenshi.com/catalog/g/gK-12236/)）
 - タクトスイッチ
 - ユニバーサル基板

- 可動部
 - 木材
 - サーボモーター


# 制御部の開発

どうやら「ESP-WROOM-02」はArduinoIDEで動かせるらしい。意外にも制御部の開発はあっさり終了。
最も驚いたのはこのマイコン、単なるWi-Fi接続のみならず、WebサーバーとしてHTTPリクエストを応答できる仕様だった。
参考：[ESP-WROOM-02をWebサーバーにする](https://www.petitmonte.com/robot/esp_wroom_02_webserver_ap.html)

そこで、スマートロックの解錠と施錠をブラウザ画面とWebAPIで実行できるように実装。
<img width="550" alt="" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27488/beac19a4-4af6-695f-a04f-0d259d709ef5.png>

出来上がった試作がこれ。良さそう。

<img width="350" alt="" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27488/a0c31719-f514-b24b-f330-04b20ea3618d.gif>

# 可動部の開発

実はここからが課題山積み。
まず、自宅のドアロックに適合した形状でなければならないのと、使用途中でドアから外れないように確実に取り付けないといけない。
とりあえず無理やり取り付けてみたのがこの写真。

ネジの位置を見てわかるように、このドアロックだけに最適化した形状...。汎用性は皆無。
<img width="300" alt="" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27488/798d71c2-c142-4c4d-5b2f-c488b6227fb6.jpeg>


作ったあとに一番悔しかったのはこれ。
![ezgif-2-b96020296aa1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27488/8882e701-b635-1036-ff14-78546cf7743a.gif)


...

...開かない！


取り急ぎ、設計を全面的に見直し、ここからはちゃんとAutoDeskのFusion360の力を借りて設計。

<img width="300" alt="" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27488/2e8cf4c3-82b8-b45c-03a1-320a2b31b552.jpeg> <img width="300" alt="" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27488/9a50fab3-33a3-f089-7947-3aa60758c09a.jpeg>

設計図どおりにボール盤で切削。これが半日掛かった...
<img width="300" alt="" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27488/f4ad4471-d502-269a-b8aa-63c53f8a8a06.jpeg>
<img width="300" alt="" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27488/7d3e7630-e665-17ff-82b6-2ceda2233278.jpeg>

その結果出来上がったのがこれ。
裏側にはマグネットを接着。いい感じ。
<img width="300" alt="" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27488/2ad01656-4c48-e74c-1670-83a2b44e35c9.jpeg>

<img width="300" alt="" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27488/113a47ef-1354-6ce2-d94a-b5319a60cf51.jpeg>


# 完成

こちらが最終的な完成品。
強力なネオジムマグネットが思った以上にドアと接着したので外れることはありませんでした。
![ezgif-3-8c1d8fd09333.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27488/7ed76733-4657-1636-ce58-722c5b89a8a5.gif)

一旦はこれで完成としましたが、１つ課題あり。
サーボモーターの回転軸とサムターンの回転軸が完全に同期しているので、通常の鍵による解錠・施錠が今の段階ではできません。(´；ω；｀)
次回はその課題を改修しようと思います。
[ESP-WROOM-02でスマートロックを作ろう②【物理鍵も使用できるように改修】](https://qiita.com/souri-t/items/f414bf741bf5dd511bb4)
<img width="300" alt="" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27488/76f4ca1a-8e2f-b668-8875-69701d2ad262.jpeg>