OmniAICreator/Qiita-1.07M huggingface dataset:
SwiftUIでLottie Animationを適用する

## Lottie Animationとは 
[Lottie](https://airbnb.design/lottie/)Android、iOS、Web、Windows用アニメーションライブラリで、複雑なアニメーションを手軽に実装することができるようになります。さらに動画などのファイルに比べてファイル容量も軽量でSVGを用いているので拡大縮小もお手の物です。

## 環境
 - `OS`: `macOS Big Sur 11.0.1`
 - `Xcode`: `12.2`
 - `Swift`: `5.3.1`
 - `IOS` : `14.0`

## こんなものができます
#### *動作かなり重く見えますが実際はもっと軽く動きます。
![5o2ik-oq0mj.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376889/404f49b6-b081-8947-9a86-96c2b5f04b2e.gif)


## 準備
`Lottie`を開発中のアプリに適用します。

```console
$ pod init
```

```console
$ open Podfile
```
そして`Podfile`内に`pod 'lottie-ios'`を追記します。

```console
$ pod install 
```

次に、`.json`ファイルを用意します。
[LottieFiles](https://lottiefiles.com)から探すのが楽かと思います。

手元に`.json`ファイルが用意できたら、プロジェクトディレクトリの配下に格納します。

これで準備は以上です。

## コード例

```swift
struct AnimatedView: UIViewRepresentable {
    func makeUIView(context: Context) -> AnimationView {
        let view = AnimationView(name: "追加した.jsonファイルの名前(拡張子抜き)", bundle: Bundle.main)
        
        view.play { (status) in
            if status {
                withAnimation(.interactiveSpring(response: 0.6, dampingFraction: 0.8, blendDuration: 0.8)) {
                    isShow.toggle()
                }
            }
        }
        
        return view
    }
    
    func updateUIView(_ uiView: AnimationView, context: Context) {
    }
}
```
これだけのコードでgifアニメーションがアプリに適用できます。
ただ、今回は一定時間たつとバウンドするようにしているので、`withAnimation`メソッドを呼んでいますが、単純にgifアニメーションを表示したいだけとかだと更にコード行は減るかなと思います。

大きさは`frame`指定でいじってみるのが良いかなと思います。

```swift
struct ContentView: View {
    var body: some View {
        AnimatedView()
            .frame(width: 200, height 200)
            とか
            .frame(width: UIScreen.main.bounds.height / 2)
            など
    }
}
```

## まとめ
今回は`SwiftUI`で`Lottie Animation`を適用する方法を紹介しました。
すごく簡単で面白いのでぜひ試してみてください :hugging:
Springのlogでデフォルトのコンソール出力が消えない

# 起こった問題
相変わらずSpringBootでWebアプリを開発中。APIの実行ログをlog出力しようと思い、logging-spring.xmlを作成してコンソールに出力されるメッセージをカスタマイズしようとした。その際、自分で指定した形式とspringのデフォルト形式が両方同時に出力されてしまった。その解決法を備忘録として残す。

# 書いたコード、失敗してる出力
以下にlogging-spring.xmlのコードと出力されたログを示す。

```
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/base.xml"/>


    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <target>System.out</target>
        <encoder>
            <pattern>%message%n</pattern>
        </encoder>
    </appender>


    <root level="INFO">
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>
```
```
2020-12-10 19:28:28.557  INFO 4426 --- [  restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFERRED mode.
Bootstrapping Spring Data JPA repositories in DEFERRED mode.
・
・
・
2020-12-10 19:28:30.996  INFO 4426 --- [  restartedMain] DeferredRepositoryInitializationListener : Spring Data repositories initialized!
Spring Data repositories initialized!
2020-12-10 19:28:31.004  INFO 4426 --- [  restartedMain] c.t.s.restfulapi.RestfulApiApplication   : Started RestfulApiApplication in 4.35 seconds (JVM running for 4.752)
Started RestfulApiApplication in 4.35 seconds (JVM running for 4.752)
```
このように、僕が思い描いていた出力はメッセージのみであり実際そのログも出てるのだが、そのメッセージごとにspringのデフォルトのログ形式での出力もされてしまっている。
　
# 解決法
[このサイト](https://www.it-swarm-ja.tech/ja/java/spring-boot%E3%81%8C%E3%83%AD%E3%82%B0%E3%82%92%E3%82%B3%E3%83%B3%E3%82%BD%E3%83%BC%E3%83%AB%E3%81%AB%E5%87%BA%E5%8A%9B%E3%81%97%E3%81%AA%E3%81%84%E3%82%88%E3%81%86%E3%81%AB%E3%81%99%E3%82%8B/1054078911/)の一番下にこう書いてあった。
`最新の1.3.1リリースでテストされ、新しいリリースではbase.xmlがdefaults.xmlに名前が変更されました
`
ということで以下のように修正

```
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>


    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <target>System.out</target>
        <encoder>
            <pattern>%message%n</pattern>
        </encoder>
    </appender>


    <root level="INFO">
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>
```
すると、出力は以下のように

```
Tomcat initialized with port(s): 8080 (http)
Starting service [Tomcat]
Starting Servlet engine: [Apache Tomcat/9.0.37]
・
・
・
Initialized JPA EntityManagerFactory for persistence unit 'default'
Spring Data repositories initialized!
Started RestfulApiApplication in 3.822 seconds (JVM running for 4.209)
```

解決！！
[JavaScript] すごく初歩のJavaScript (配列,オブジェクト)

#JavaScript (配列,オブジェクト)

JavaScript 自分用の覚え書きです。

配列

```javascript:script.js
const name = ["yamada", "sasaki", "takada"];
```

オブジェクト

```javascript:script.js
const item = {name: "apple", price: 150};
```

オブジェクトと配列

```javascript:script.js
const characters = [
  {name: "山田", age: 20},
  {name: "佐々木", age: 25}
];
```
[PHP]SQLのIN節に配列をセットする

PHPでSQLのIN節で配列を指定したい時に詰まった事メモ。

## NG : IN節に配列でパラメータを渡す

```php
$id = 1;
$num = [1,2,3,4,5,...];

$param = array(
    "id" => $id,
    "num" => $num,
);

$pdo = new PDO();
$sql = "SELECT * FROM hoge_table WHERE id=:id AND num IN (:num)"; // :numでエラーが起きる
$stmt = $pdo->prepare($sql);
$stmt->execute($param);
```

これだとこういうエラーが出る。

```
Notice: Array to string conversion in 
```

プレースホルダーに配列は使えないらしい。

## OK : IN節にパラメータを一個一個指定する
一旦プレースホルダを一個一個指定して確認してみる。問題はなさそう。

```php
$param = array(
    "id" => $id,
    "num1" => $num1,
    "num2" => $num2,
    "num3" => $num3,
);

$pdo = new PDO();
$sql = "SELECT * FROM hoge_table WHERE id=:id AND num IN (:num1, :num2, :num3);"; //一個一個指定する
$stmt = $pdo->prepare($sql);
$stmt->execute($param);
```
でもこれだと配列の個数が可変の時に困る。

なので修正。

## NG : IN節にカンマ区切りの文字列のパラメータとして渡す

```php
$param = array(
    "id" => $id,
    "num" => implode(",",$num), // numをパラメータとして渡す
);

$pdo = new PDO();
$sql = "SELECT * FROM hoge_table WHERE id=:id AND num IN (:num)";
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
```

これだとなぜかINに当てはまる最初の行だけ取得する。

（天の声：(:num)のカンマ区切りが数値型にパースされちゃうとか、そうゆう感じじゃないかな・・・）
（ありえそう・・・）

なので修正。

## NG : カンマ区切りの文字列としてSQL文に入れ込む

```php
$param = array(
    "id" => $id,
);

$pdo = new PDO();
$sql = "SELECT * FROM hoge_table WHERE id=:id AND num IN (".implode(",",$num).");"; //numをSQL文に入れ込んでしまう
$stmt = $pdo->prepare($sql);
$stmt->execute($param);
```

結果的にはうまくいく。
だけどパラメータをSQLに直接入れてるので、ユーザが入力できる値だったりすると**SQLインジェクション**の恐れがある。

## OK : 疑問符のプレースホルダ使ってがんばる
以下のように解決できるみたい。詳しくは記事先へ。
[PDOのwhereでIN句を使う - Qiita](https://qiita.com/ritukiii/items/a0921a93a1c7b0c0642e)

## リファレンスを確認
PDOじゃないけどmysqliに気になる記述があった。
[PHP: mysqli_stmt::prepare - Manual](https://www.php.net/manual/ja/mysqli-stmt.prepare.php#108038)

> Turns out you can't directly use a prepared statement for a query that has a placeholder in an IN() clause.
> There are ways around that (such as constructing a string that consists of n question marks separated by commas, then using that set of placeholders in the IN() clause), but you can't just say IN (?).
> This is a MySQL restriction rather than a PHP restriction, but it's not really documented in the MySQL docs either, so I figured it was worth mentioning here.

「IN()節の中にプレースホルダを持つクエリに対して、準備された文を直接使用することはできないことがわかりました。
これを回避する方法はありますが (例えば、カンマで区切られた n 個のクエスチョンマークからなる文字列を作成し、そのプレースホルダのセットを IN() 節で使用するなど)、単に IN (?) と言うことはできません。
これはPHPの制限というよりはMySQLの制限ですが、MySQLのドキュメントにも書かれていないので、ここで言及する価値があると思いました。」

SQLの仕様らしい。

おしまい。
React NativeでAndroidのパフォーマンスが悪すぎて、四苦八苦した話

# はじめに
今年、仕事の案件で初めてReact Nativeでアプリ開発していたときの話。
開発中は比較的新しめのPixcel4または4,5年前のクソ端末という両極端な実機で動作確認をしていて、いざ受入で2,3年前ぐらいの準主力端末みたいなところで、顧客がテストしだしたら、クソ重いからどうにかしろと言われたときに、苦労した内容を少しまとめてみます

ちなみにアプリ名とかは出せないので、ざっくりどんなアプリかを説明させていただくと、とある情報の検索アプリです。リスト表示、詳細表示ができて、お気に入り保存なんかの機能があったりする感じです。
<div align="center">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18917/d34cc77e-eb66-1c3d-63a6-074f1b3604a2.png" alt="" title="">
</div>

# 環境
- react-native 0.61.4

# クソ重いというのがどういう状態だったか
- 起動に数秒かかる
- 画面遷移がいちいち遅い
- 画面描画が遅い
- ボタンタップからコンマ数秒～1秒程度遅れて、イベント発火する
- flatlistでのリスト表示のスクロールでカクつく
- スタックが溜まってくると画面によってはフリーズする(Google Mapの表示とかがひどかった記憶があります
- などなど。。。

とても世に出せる状態ではありませんでした。
確かテスト端末として利用してたのはHUAWEI p20 liteとかでした。
ちなみにAndroidでそんな状態でしたが、iOSではiPhone 6あたりでもテストしていましたが、ほぼぬるぬる動いている状態でした

# 試みたこと
上記のような状態でしたので、とにかく様々実践しました

- 画像ギャラリー
    - 表示で、画面表示時にすべての画像(MAX40枚とか)を一気に描画していたのを、表示画像の前後2枚分だけ裏で持っていく形に修正
    - これはなかなか効きました。ライブラリを選定しなおすみたいな選択肢もあったかなと思いますが
- 利用している画像ファイルの圧縮
    - それなりに画像ファイルを使っていたのと、昔iOSアプリをネイティブ(Objective-C)で開発していたころこういった対応をしていたなと思いだし
        - これはあまり効果はありませんでした。アプリ容量はかなり抑えられましたが(昔は容量に今よりシビアだったからだと後から思い出しました
- index.jsに**enableScreens();**の記述追加
    - これに関してはあまり理解できていないのですが、ボタンタップからのイベント発火や画面遷移がスムーズになりました
- Hermesの利用
    - 結果的にこれのおかげでどうにかなりました。すべてが爆速になりました。詳細は公式にわかりやすく記載されているので。。。
    - https://reactnative.dev/docs/hermes
    - 以下は公式の本文の翻訳。
    - ``Hermesは、AndroidでReactNativeアプリを実行するために最適化されたオープンソースのJavaScriptエンジンです。多くのアプリでは、Hermesを有効にすると、起動時間が改善され、メモリ使用量が減少し、アプリのサイズが小さくなります。``

# まとめ
最終的には、記述だけ見ると一行設定を入れただけで、解決したのですが、そこまでたどり着くのになかなか時間を要しました。同じようなことにハマったひとがいたとき解決のきっかけぐらいになれればと思い、投稿しました。

当時は対応しきれなかったのですが、デザインを再現するがためにその場しのぎで、ScrollViewの上にFlatlistのせるみたいな残念な作りになっていたので、他にもやれることは色々あったかなと思うので、次また新しくアプリを作るとなったときのために、また記事にしようかなと思います。
あまりまとまりがないまとめになってしまったんですが、最後まで読んでいただいてありがとうございました。
自前EDR その5

#概要

vistaにedrを構築する。
時系列で取得なsysmonを入れた。

#環境

windows vista 32bit

#写真

![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/ba78a12d-0a72-5ef3-5c04-e7fd1fa7ac6d.jpeg)

#インストール

sysmon -i

#電卓を起動、停止してみた。

#Sysmon Event ID

|Category|	ID|
|:--|:--|
|プロセスの作成 (Process Create)		|			1|
|作成日時の変更 (File creation time changed)	|			2|
|ネットワーク接続の検出 (Network Connection Detected)	|3|
|Sysmonサービス状態の変更 (Sysmon service state changed)	|4|
|プロセスの停止 (Process terminated)		|			5|
|ドライバの読み込み (Driver loaded)		|			6|
|イメージの読み込み (Image loaded)		|			7|
|スレッドイベントの作成 (CreatRemoteThread)	|			8|
|Disk/Volume Read イベント (RawAccessRead*)	|			9|

#MicrosoftはSysmon 11をリリースし、ユーザーが削除されたデータをバックアップするのを支援します。

マイクロソフトはSysmon 11をリリースしました。
これにより、ユーザーは監視対象デバイスで削除されたファイルを監視し、自動的にアーカイブできます。
参考までに、Sysmonは、システムの悪意のあるアクティビティを監視し、それらのイベントをWindowsイベントログに記録するように設計されたsysinternalsツールです。
これは可能ですが、ユーザーは違反後にネットワークで発生した悪意のあるアクティビティを削除したり、インシデントレスポンスやデジタルフォレンジックを実行したりして、攻撃がどのように行われたかを知ることができます。
Sysmon 11リリースでは、sysmonはファイルの削除を監視でき、削除されたファイルを自動的にアーカイブできます。
このツールは、デジタルフォレンジックまたはセキュリティ違反の軽減を実行する際のインシデント対応にも役立ちます。
ネットワークが侵害されると、攻撃者はさまざまなツールを使用してネットワーク全体に横方向に広がります。
アクセス権を取得すると、貴重なデータを収集し、ランサムウェアなどのマルウェアを配備します。
そのような場合、これらの言及されたツールは攻撃者によって自動的に削除されるため、インシデントレスポンダーと研究者は弱点を分析したり、ネットワークへの侵入方法を知ることができません。
Sysmonの新しいファイル削除監視およびアーカイブ機能が追加されたことにより、攻撃者が使用するツールやマルウェア実行可能ファイルへのアクセスが、インシデントレスポンダーにとってはるかに容易になります。
これらのファイルは、より良い防御を作成するために、研究者が攻撃者の戦術、技術、手順についてさらに学ぶのに役立ちます。
Sysmon 11は、Sysinternalのsysmonページまたはhttps://live.sysinternals.com/sysmon.exeからダウンロードできます。
ダウンロード後、適切に実行するには管理者権限が必要なため、管理者特権のコマンドプロンプトから実行する必要があります。
デフォルトでは、Sysmon 11はプロセスの作成やファイル時間の変更などの基本情報を監視できます。
ただし、他の多くのイベントをログに記録するように構成できます。
この機能を使用するには、Sysmon構成ファイルに新しいArchiveDirectoryおよびFileDeletion構成オプションを追加する必要があります。
次のコマンドを使用して構成ファイルをロードできます。

sysmon -i sysmon.xml

/ DeletedFilesは、基本構成ファイルによって有効化されたすべての削除済みファイルのファイル削除の監視とアーカイブを確認できるフォルダーの名前です。
このフォルダには、削除されたファイルのコピーも保存されます。
FIleDeletionオプションにはonmatch = “exclude”オプションを使用します。
この構成でSysmonを開始すると、イベントビューアのアプリケーションとサービスログ/ Microsoft / Windows / Sysmon / Operationalへのファイル削除イベントのロギングが開始されます。
ファイルがC; /ドライブから削除されると、Sha1-hash.extensionという名前のC：/ DeletedFilesにアーカイブされます。
たとえば、上記のファイルはC：\ DeletedFiles \ C24FEDB9B8A592722D5A9ADB34D276FC3B329D6F.exeとしてアーカイブされました。
このディレクトリはシステムACLで保護されており、それにアクセスするには、ユーザーはpsexec.exeプログラムをダウンロードし、次のコマンドを使用してcmdプロンプトを起動する必要があります。

psexec -sid cmd

ダウンロード後、削除されたファイルへのアクセスが簡単になります。
上記の例は、システムモニターが実行できることを示すためのサンプルにすぎません。
このツールの詳細については、Sysinternailsのサイトにあるドキュメントを参照してください。


以上。
FacebookグラフAPIの権限を付与する

# 概要

* グラフAPIであれこれしたい
* FacebookのAPIはすぐ仕様変更するので大変
* ネット記事を漁っても古くて今では使えないやり方を記載していたりする
* 2020年12月時点で有効な手順をメモしておく
* この記事もいつか古くなるので悪しからず


# 詳細

##### グラフAPIエクスプローラーにアクセス

* https://developers.facebook.com/tools/explorer/

##### 

<img width="70%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57350/b32c698b-855d-ea81-50ce-8f3a60adb22e.png">

##### 初期状態の権限を確認してみる

* "access_token"はユーザアクセストークンです
* Facebookはトークンの種類が多いので注意

```
$ curl https://graph.facebook.com/me/permissions?access_token=EAAKdUj6fD******************************************3N8ZCZAzLN

{"data":[{"permission":"public_profile","status":"granted"}]}
```

##### 権限を付与する

* ここでは"e-mail"の権限を試しに付与してみる
* 対象のアプリにプルダウンをあわせる

<img width="70%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57350/0aaf87f5-3305-ad0a-f41b-6073211c66d0.png">

* アクセス許可のプルダウンから"e-mail"を選択


<img width="70%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57350/040593cc-112e-12b2-88f4-184ac51f448b.png">

* "Generate Access Token"を押す。ここ少しわかりにくいかも。
* 新しいアクセストークンが生成される

<img width="70%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57350/bbfb11ef-3835-98d1-a090-68ad790114af.png">

##### 初期状態の権限を確認してみる

* コマンドラインで再び権限を確認してみる
* ”e-mail”権限が付与されていることがわかる

```
$ curl https://graph.facebook.com/me/permissions?access_token=EAAKdUj6fD*********************************************Fmw8ZBGUZD

{"data":[{"permission":"email","status":"granted"},{"permission":"public_profile","status":"granted"}]}
```

* 同様の手順で複数権限を付与してみる
* 問い合わせると権限が新たに付与されている事がわかる

<img width="70%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57350/5d4940b8-a8bb-e3f1-cfc9-99f77bd4bb26.png">

```
$ curl https://graph.facebook.com/me/permissions?access_token=EAAKdUj6fD*********************************************FEZAurPQZD

{"data":[{"permission":"email","status":"granted"},{"permission":"groups_show_list","status":"granted"},{"permission":"pages_messaging","status":"granted"},{"permission":"pages_messaging_phone_number","status":"granted"},{"permission":"pages_messaging_subscriptions","status":"granted"},{"permission":"public_profile","status":"granted"}]}
```

* FacebookのAPIって最初に権限付与しないと使えないってちゃんとわかりやすいところに書いておいてほしい
Firebaseの権限をエイリアスで管理したら失敗だった

## はじめに
本稿は [ディップ Advent Calendar 2020](https://qiita.com/advent-calendar/2020/dip-dev) の10日目の投稿です。
弊社メンバーが色々書いているのでぜひ見ていってください！

## Firebaseのユーザ管理について
アプリ開発のmBaaSとしてFirebaseがよく選択肢として挙がると思います。
運用していく中でユーザ管理をしていく必要があるわけですが、この管理がなかなかの難題です。

複数プロジェクト x 複数環境 x 入退場者といった感じで作業がかなり多くなります。
弊チームでは、メールエイリアスを作成して、そこにユーザを紐づけることで権限を簡単に変更することができるようにしました。

## メールエイリアスの落とし穴
メールエイリアスで簡単に管理できる！やったね！
と一瞬なったのですが、メールエイリアスには大きな落とし穴がありました。

それはメールエイリアスは社内の別の部門が管理しており、申請するためにはExcelでの申請書が必要だったのです。

Excelの申請書を提出する際にはいくつかマクロを実行する必要があります。
そのマクロがなんと...macでは動かない...。

仕方なく申請する時にはWindowsを起動することにしたのですが、
いくつか申請が溜まってからまとめて申請するようになってしまいました。
これでは「権限を簡単に変更する」ことができてませんね...。

## 落とし穴その2
運用をしておおよそ1年ほど経過した頃にあることに気付きました。
自分が想像しているレベルでの人の出入りおよび権限変更の必要がなかったのです！

FirebaseはAnalyticsやCloudMessageを使用しているのみで、多くのメンバーは閲覧権限すら必要がありませんでした...。
これは運用を考えている時には全く思いつかなかった問題です。

## 今後の対処法
「メールエイリアスでの権限変更を取りやめて、APIなどを使用して個別に設定する」
もしくは
「メールエイリアスの申請をmacでできるように管理部門と協議してプロセスを変更する」
線で検討していこうと思います。

## 反省
権限変更がしやすいように設計したつもりが、自分のリサーチ不足で苦しい選択肢となってしまっていました...(ﾄﾎﾎ...)
ユーザ管理は奥が深いので、実際に運用を始める前にしっかりとユースケースを定義して設計することが重要だなと再認識しました。
この失敗を2度と起こさないように気をつけていきたいですね。
iPadのSafariで音声を自動再生っぽく見せる方法

## はじめに

本記事は [DMMグループ Advent Calendar 2020](https://qiita.com/advent-calendar/2020/dmm) の10日目の記事です。

こんにちは、DMM.comの情報システム部で社内向けのサービスを開発しているmimicknです。
弊社では来客時の受付を専用のwebアプリを使用して受付さんが管理をしています。
そのアプリはiPadを使用して各来客用の会議室での時計&会議終了のアラートも兼ねているのですが、過去のiOSアップデートからSafariのポリシーに引っかかりアラートの音声が鳴らなくなってしまいました。
最近までは暫定回避策でiOSアプリでWebViewを使いWebViewからwebアプリを開くことで回避していましたが、アプリの管理コストの削減などによりブラウザで動くよう改修を加えました。

この記事はそのような場合で自動で音声を再生する方法(正確には自動再生っぽく見せる方法)を記載したいと思います。


## なぜ音声は鳴らなくなった？

まず今回の音声が鳴らなくなってしまった原因ですが、前述で記述の通りiOSでのSafariのポリシーの変更があったためです。
ポリシーの内容としては音声の再生には `ユーザのアクション` が必要というものです。
`ユーザのアクション` というのは、ボタンの押下などがあたりそれに紐付けての音声の再生なら可能となります。

PC版Safariであれば設定から変更し自動再生を許可することができるのですが、iOS版ではその設定がありません。
そのため自動再生するためには実装でうまいこと回避する必要が出てきます。


## 回避方法

いくつか回避方法はあるかと思いますが、今回弊社のアプリで回避に使用した方法は以下のとおりです。

1. 音声が再生されるページに訪れた際にダイアログを表示させる
2. そのダイアログを閉じさせ、その閉じる挙動に紐付けて音声ファイルをロードさせる
3. 2でロードした音声についてはユーザのアクションを必要とせず再生することができるようになる

になります。

より具体的に説明するために、Reactのコードを用いて説明します。
(少し古いシステムでのコードをベースにお話しているため書き方が古いですがご了承ください)
まず以下のような音声を再生するコンポーネントがあるとします。

``` Sound.jsx
import React from 'react';

const sound = new Audio('/sounds/sound.mp3');

export default class Sound extends Component {
  constructor(props) {
    super(props);
    sound.play();
  }

  render() {
    return (
      <div></div>
    );
  }
}
```

このコンポーネントではコンストラクタで対象の音声を再生といった動作をしています。
次にこのコンポーネントを呼ぶアプリを以下に記載します。

```App.jsx
import React from 'react';

import Sound from '../../components/Sound';

export default class App extends Component {
  render() {
    return (
      <Sound />
    );
  }
}

```

この状態では音声は自動再生されません。
このコードに実際に回避策を入れてみようと思います。

### 1. 音声が再生されるページに訪れた際にダイアログを表示させる

まず前述で述べた１に該当するダイアログです。
ダイアログの詳細のコードは省きますが、作りとしては `message` で表示させる文言を渡し、`onClose` でダイアログを閉じるときの関数を渡しています。
ダイアログの表示は訪れたときの一回のみの想定なので、initialDialogClose()ではisInitialの更新をさせる想定です。

```App.jsx
  render() {
    return (
      { // 音声有効化用のダイアログ
        isInitial ? (
          <Dialog
            message={'このページではサウンドが再生されます'}
            onClose={this.initialDialogClose}
          />
      ) : null}
      <Sound />
    );
  }
```

これで表示されるダイアログのイメージは以下です。

![dialog.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105900/566ed13e-2bb3-ca62-6f7e-688ad52c7358.png)

### 2. そのダイアログを閉じさせ、その閉じる挙動に紐付けて音声ファイルをロードさせる

次にそのダイアログの閉じる挙動に紐付けて音声ファイルをロードさせる実装です。
今回は以下のようにSound.jsxにロード用の関数を用意します。

``` Sound.jsx
export const enableSound = () => {
  sound.load();
};
```

あとはこの関数をApp.jsxで読み込み、先程のinitialDialogClose()で呼び出すように改修をします。

### 3. 2でロードした音声についてはユーザのアクションを必要とせず再生することができるようになる

これで先程ロードした音声ファイルについては、ユーザのアクションを使用せず再生(Audioクラスのplay())をすることができるようになります。

また今回は1ファイルのみのロードの説明でしたが、複数ファイルも同様に行うことができ、それぞれユーザのアクションを必要とせずに再生できるようになります。
(弊社のアプリでは複数の音声を鳴らせる実装となっています)


## おわりに

ダイアログのクローズをユーザに要求するため完全に自動再生とは行きませんでしたが、このような実装をすることでワンアクション後に任意のタイミングで音声を再生できるようになりました。

なかなか調査や回避方法に苦労したため、同じく困っている方の役に立てばと思います。

---

DMMグループ Advent Calendar 2020の記事でした。
明日の11日目は[juve_534](https://qiita.com/juve_534)さんです。よろしくお願いします！
【JavaScript】よくあるエラー内容

#プログラミング勉強日記
2020年12月10日
Windowsでは`F12`を押すと表示されるデベロッパーツールでJavaScriptのエラー内容を確認することができる。よくあるエラー内容をまとめる。

#Uncaught ReferenceError (変数名) is not defined
　変数が定義されていない場合に起こるエラーである。

　私の場合は、変数名もスペルミスやvar宣言が抜けていることが多い。

#Uncaught SyntaxError: Unexpected token
　読み込んでいるJavaScriptファイルに不正な文字がや`""`で囲っていない全角文字があるとエラーが出る。
　なので、JavaScriptファイルのコードを確認し、全角文字があったら半角文字にする。

#Uncaught ReferenceError: jQuery is not defined
　jQueryで定義されている関数を使っているが、jQueryが読み込まれていない状態であるエラー内容である。
　HTMLファイルといったブラウザで表示してほしいファイルがjQueryが先に読み込まれていない場合、jQueryを先に読み込むようにする。このようにJavaScriptの読み込み順番を変えるとエラーがなくなることがある。



#参考文献
[JavaScript エラーリファレンス](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Errors)
[JavaScriptエラー時にチェックするポイント](https://www.genius-web.co.jp/blog/web-programming/points-to-check-on-javascript-errors.html)
Android EmulatorのIPv6がグダグダです(泣)

#TL;DL
本日Android Emulatorでデバックをしながらコードを書いていたら盛大にハマりました。
次の犠牲者を出さないようにメモっておきます。

作っていたのはAndroidからIPv6で通信をするというアプリなのですが、Android EmulatorはすでにIPv6対応しているとのことで安心しておりました。
https://qiita.com/ip6/items/15f76aba059ebc969455

#起こったこと
あるライブラリを使いIPv6で通信をしようとしたところ、なぜだか通信エラーで落ちる。
IPv4を使えば問題なし。あれーバグ書いちゃったかな???

Android EmulatorでもSettingからIPv6が確認できるじゃない。
![Screenshot_1607592803.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253664/42cbc39d-6f59-1ccc-bf24-21c6824117f7.png)

なんで???

#原因
Android Emulatorはデフォルトでサイトローカルアドレスを使うようになっている模様。
サイトローカルアドレスは、fec0::で始まるアドレス。上記スクリーンショットでも、2つ当たっている。
ところがこのサイトローカルアドレスは2004年9月にRFC3879によって廃止されています。
https://www.wdic.org/w/WDIC/%E3%82%B5%E3%82%A4%E3%83%88%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%83%A6%E3%83%8B%E3%82%AD%E3%83%A3%E3%82%B9%E3%83%88%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9

なんで、EmulatorのホストからPINGを打とうが何しようが応答が帰ってこないことが判明。
Android EmulatorはSYNで接続しようとするが、サーバーがACKを返してもそのパケットはどこかで破棄されちゃっている模様。

なんで2004年に廃止されてしまった規格を、2020年に引きづっているんだよ。勘弁してくれよーーー。

ちなみに実機だとサイトローカルアドレスは当たらないので、実機で動かしたら無事動きました。
LSTMって何やねん

#12/14　今日学んだこと

　LSTMのよくある説明　→　チンプンカンプン
![PYGtu (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212914/16f7f69d-428d-d2f7-ec53-125cbd9b683b.png)

　学び　→　[H,X]というのは、ベクトルを横に並べることを意味している

　ここで注意することがあり、それが隠れユニット[H]の次元だということ
　[H]というのは、実は使う側に決定権がある。

　n_hidden: 隠れ層 -> 数が多い程，学習モデルの複雑さが増加

```python
LSTM(n_hidden, batch_input_shape=(None, length_of_sequence, in_out_neurons), return_sequences=False))
```

教えてくれた本　https://amzn.to/3qTVmFt
ディープラーニング構築テンプレート［AIプロジェクトの必須事項と技術的指針］
人物　：　https://roboteer-tokyo.com/archives/330


#12/12
　LSTMの件、やはり習うよりは慣れろという感じ・・・
　ボートの漕ぎ方を机上で学ぶより、まず浮かんでみてナンボやという感じ

　参考資料　https://math.uni.lu/eml/projects/reports/2020_Summer/DiasMoreira.pdf

#E資格に向けて


今日はLSTMの件をずっと調べている。

情報源
https://www.zhihu.com/question/41949741


自分と同じような疑問を持たれている、ややレベルの低めの
情報を探そうとすると、やはり中国にたどり着くことが多い。
（この点、日本のエンジニアは皆さん、相当に頭が良いというか、呑み込みが早いというか・・・）

この年になって、新しい概念をすんなり受け入れるには、
何かと苦労するものである・・・

#LSTM

そんな訳で、少しは分かりやすいイメージを得たので、
ここから勉強をすることにする。

#その他

zhifuのサイトは情報量が多くて、最近、よく見ている

https://www.zhihu.com/question/41949741
[Swift] reversed()に気を付けろ

## このメソッドには問題がある
```swift
extension Array {
    func reversedMap<T>(_ transform: (Element) -> T) -> [T] {
        map(transform).reversed()
    }
}
```

## じょ

一見普通に見えるメソッドですが、何が問題なのでしょう

## Array#reversed()

`Array`には要素の内容を逆順にする`reversed()`というメソッドがあります。
このメソッドはよくできていて、実際に要素が逆順になったArrayを生成せずにそのようにふるまう`ReversedCollection<Base>`という型のインスタンスを返します。
このメソッドは`Array`ではなく`BidirectionalCollection`プロトコル上にextensionとして実装されています。

```swift
func reversed() -> ReversedCollection<Self>
```

`BidirectionalCollection`は要素を逆順に走査することができるコレクションですので、この`reversed()`を実装するのにちょうどよいプロトコルといえるでしょう。


## Sequence#reversed()

感の良い方ならすでにお気づきだとは思いますが、初めに提示した`reversedMap`メソッドの戻り値は`Array`となっており、`BidirectionalCollection#reversed()`に適合していません。
ではこの`Array`を戻す`reversed()`メソッドはどこから来たのでしょう。
それは`Sequence`プロトコル上にextensionとして実装されています。

```swift
func reversed() -> Array<Element>
```

`Sequence`プロトコルは要素が順番に取り出せるということのみが規定されたプロトコルです。
`PartialRangeFrom`（5... のようなやつ）のように終端がない`Sequence`も実装可能です。

初めに提示した`reversedMap`メソッドはこちらの`reversed()`メソッドが使われているということです。

## ２つの相違

では`Sequence#reversed()`を使うことの何が問題なのでしょう。

`ReversedCollection<Base>`は`Base`が`BidirectionalCollection`であることを利用し、新たな`Collection`を生成することなく逆順に要素を取り出すことができます。
ところが`Sequence`から逆順の`Array`を生成するためには、**すべての要素を取り出し**た上で逆順になった`Array`を生成する必要があるのです。
計算量でいえば`BidirectionalCollection#reversed()`はO(1)で、`Sequence#reversed()`はO(N)です。
もちろんこの違いはとてつもなく大きいです。

## じゃあどうすればいいの？
方法は２通りあります。

まずメソッドの順番を変える方法。
こちらの方がわかりやすいです。

```swift
extension Array {
    func reversedMap<T>(_ transform: (Element) -> T) -> [T] {
        reversed().map(transform)
    }
}
```

`reversed()`メソッドを先に実行します。こうするとコンパイラはより適用範囲がより狭い`BidirectionalCollection#reversed()`を必ず選択します。

二つ目は戻り値の型を変える方法。

```swift
extension Array {
    func reversedMap<T>(_ transform: (Element) -> T) -> ReversedCollection<Self> {
        map(transform).reversed()
    }
}
```

こうすることで、`BidirectionalCollection#reversed()`に固定されます。
ただし、ちょっと見た目がうるさいです。

## まとめ？

手元でてきとーにテストしてみた結果、`BidirectionalCollection#reversed()`は`Sequence#reversed()`より１割程度高速になります。

戻された`Sequence`を使わないと意味がないのでテストは

```swift
measure {
  s = array.reversedMap { i in i * 2 }.reduce(0, +)
}
```
で行いました。
すごくてきとーにやってますので興味がある方はお手元でお確かめください。
[SlothLib] 日本語stopwordの準備

#stopwordのリスト作成

```stopword.py
import requests

url = "http://svn.sourceforge.jp/svnroot/slothlib/CSharp/Version1/SlothLib/NLP/Filter/StopWord/word/Japanese.txt"
r = requests.get(url)
tmp = r.text.split('\r\n')
stopwords = []
for i in range(len(tmp)):
    if len(tmp[i]) < 1:
        continue
    stopwords.append(tmp[i])
print(stopwords)

#####joblibで保存して使いたい時     
import joblib
joblib.dump(stopwords, 'stopwords.jb', compress = 3)
#####
```


#結果
joblibでload

```
>>> import joblib
>>> print(joblib.load('stopwords.jb'))
['あそこ', 'あたり', 'あちら', 'あっち', 'あと', 'あな', 'あなた', 'あれ', 'いくつ', 'いつ', 'いま', 'いや', 'いろいろ', 'うち', 'おおまか', 'おまえ', 'おれ', 'がい', 'かく', 'かたち', 'かやの', 'から', 'がら', 'きた', 'くせ', 'ここ', 'こっち', 'こと', 'ごと', 'こちら', 'ごっちゃ', 'これ', 'これら', 'ごろ', 'さまざま', 'さらい', 'さん', 'しかた', 'しよう', 'すか', 'ずつ', 'すね', 'すべて', 'ぜんぶ', 'そう', 'そこ', 'そちら', 'そっち', 'そで', 'それ', 'それぞれ', 'それなり', 'たくさん', 'たち', 'たび', 'ため', 'だめ', 'ちゃ', 'ちゃん', 'てん', 'とおり', 'とき', 'どこ', 'どこか', 'ところ', 'どちら', 'どっか', 'どっち', 'どれ', 'なか', 'なかば', 'なに', 'など', 'なん', 'はじめ', 'はず', 'はるか', 'ひと', 'ひとつ', 'ふく', 'ぶり', 'べつ', 'へん', 'ぺん', 'ほう', 'ほか', 'まさ', 'まし', 'まとも', 'まま', 'みたい', 'みつ', 'みなさん', 'みんな', 'もと', 'もの', 'もん', 'やつ', 'よう', 'よそ', 'わけ', 'わたし', 'ハイ', '上', '中', '下', '字', '年', '月', '日', '時', '分', '秒', '週', '火', '水', '木', '金', '土', '国', '都', '道', '府', '県', '市', '区', '町', '村', '各', '第', '方', '何', '的', '度', '文', '者', '性', '体', '人', '他', '今', '部', '課', '係', '外', '類', '達', '気', '室', '口', '誰', '用', '界', '会', '首', '男', '女', '別', '話', '私', '屋', '店', '家', '場', '等', '見', '際', '観', '段', '略', '例', '系', '論', '形', '間', '地', '員', '線', '点', '書', '品', '力', '法', '感', '作', '元', '手', '数', '彼', '彼女', '子', '内', '楽', '喜', '怒', '哀', '輪', '頃', '化', '境', '俺', '奴', '高', '校', '婦', '伸', '紀', '誌', 'レ', '行', '列', '事', '士', '台', '集', '様', '所', '歴', '器', '名', '情', '連', '毎', '式', '簿', '回', '匹', '個', '席', '束', '歳', '目', '通', '面', '円', '玉', '枚', '前', '後', '左', '右', '次', '先', '春', '夏', '秋', '冬', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '百', '千', '万', '億', '兆', '下記', '上記', '時間', '今回', '前回', '場合', '一つ', '年生', '自分', 'ヶ所', 'ヵ所', 'カ所', '箇所', 'ヶ月', 'ヵ月', 'カ月', '箇月', '名前', '本当', '確か', '時点', '全部', '関係', '近く', '方法', '我々', '違い', '多く', '扱い', '新た', 'その後', '半ば', '結局', '様々', '以前', '以後', '以降', '未満', '以上', '以下', '幾つ', '毎日', '自体', '向こう', '何人', '手段', '同じ', '感じ']
```
【MySQL】rootユーザのパスワードのリセット方法（windows）

##はじめに
PCの再起動をしたところMySQLにログインできなくなっていました
直接接続を試みてもERROR 1045 (28000): Access denied
rootのパスワードをリセットしたところ接続できたので、再起動によりパスワードが変えられてしまったようです（原因不明）
この記事ではrootパスワードのリセット方法を解説します

環境：
MySQL 5.6
Windows10

##MySQLを停止
スタートメニューで"サービス"と叩いて検索、サービスアプリを開きます
MySQL56を選び、サービスを停止
この時、プロパティを開き実行ファイルのパスをコピーしておきます

例）
"C:\Program Files\MySQL\MySQL Server 5.6\bin\mysqld.exe" --defaults-file="C:\ProgramData\MySQL\MySQL Server 5.6\my.ini" MySQL56

##MySQLの起動
コマンドプロンプトを管理者権限で開き、先ほどの実行ファイルパスの最後の"MySQL56"を削除し
"--skip-grant-table"を追加して

```
"C:\Program Files\MySQL\MySQL Server 5.6\bin\mysqld.exe" --defaults-file="C:\ProgramData\MySQL\MySQL Server 5.6\my.ini" --skip-grant-table
```
を実行

##MySQLに接続
別で新たにコマンドプロンプトを開いて

```
mysql -u root mysql
```
を実行
これでMySQLに接続できます

##パスワードの更新
```
UPDATE mysql.user SET Password=PASSWORD('新しいパスワード') WHERE User='root';
FLUSH PRIVILEGES;
```
を実行
UPDATE でroot アカウントのパスワードをリセット
FLUSH で付与テーブルをメモリーにリロードするようサーバーに通知して、パスワードの変更が認識されます

##確認
コマンドプロンプトをすべて閉じMySQLを停止
サービスアプリでMySQLを起動し、コマンドプロンプトで

```
mysql -u root -p
```
設定したパスワードで接続することができました
brewでaws-cliのv1をインストールする[Mac][Zsh]

aws-cliのv1とv2では利用できるコマンドが違うため、v1をインストールしたいということがあると思います！私はあります:sob:
しかし、brewでaws-cliをインストールすると最新のv2がインストールされてしまいます。これは困ります:sob:
なので、brewでaws-cliのv1をインストールする方法をご紹介します。

# brewでaws-cliのv1をインストールする方法

brewでaws-cliのv1をインストールするコマンドが以下です。
`@1`とバージョンを指定できます。

```zsh
% brew install awscli@1
```

バージョン指定をしてインストールした場合、パスが設定されていない状態でインストールされます。
そのため、パスを通す必要があります。
aws-cliのv1のパスを設定するコマンドが以下です。

```zsh
% echo 'export PATH="/usr/local/opt/awscli@1/bin:$PATH"' >> ~/.zshrc\n
```

最後にaws-cliのバージョンを確認するコマンドが以下です。

```zsh
% aws --version
aws-cli/1.18.190 Python/3.9.0 Darwin/19.6.0 botocore/1.19.30
```

# [補足] aws-cliのv1をインストールしてもバージョンが変わらない場合
`brew install awscli`で最新のaws-cliをインストールしていた場合、うまくパスを設定できないです。
その場合、以下のコマンドで最新のaws-cliをアンインストールしましょう。

```zsh
% brew uninstall awscli
```
【Java】Caffeineでお手軽にローカルキャッシュ

# Caffeineでお手軽にローカルキャッシュ
https://github.com/ben-manes/caffeine
・DBにクエリを投げた結果をキャッシュしたい
・TTL（Timeout） が設定できる
・ローカルキャッシュなのでサーバーの設定とか要らない
・Spring で @Cacheable とかやったけど上手く動かなかったというのはまた別の話・・・（ぇ

## 環境
・Windows10 64bit
・Spring MVC 4
・Caffeine 2.8.8
・DIで呼び出すサービスにキャッシュをセット

## Maven
```xml
		<!-- https://mvnrepository.com/artifact/com.github.ben-manes.caffeine/caffeine -->
		<dependency>
		    <groupId>com.github.ben-manes.caffeine</groupId>
		    <artifactId>caffeine</artifactId>
		    <version>2.8.8</version>
		</dependency>
```

## SampleService
・キャッシュのキー：ここではサンプルで固定ですが、パラメータがある場合はパラメータから一意なキーを作成します

```java
private static final String CACHE_KEY = "sampleCacheKey";
```

・キャッシュ本体

```java
private static @NonNull Cache<Object, Object> sampleCache = null;
```

・初期設定

```java
	@PostConstruct
	public void initSampleCache() {
		sampleCache =
				Caffeine.newBuilder()
				.maximumSize(1L)
				.expireAfterWrite(30, TimeUnit.MINUTES)
//				.recordStats()
				.build();
	}
```
・キャッシュを使うサービスメソッド

```java
	@SuppressWarnings("unchecked")
	public List<Sample> selectCachedSample(int limit, int offset) {
		List<Sample> result = null;
		try {
			result = (List<Sample>)sampleCache 
					.get(CACHE_KEY,
							key -> sampleMapper.selectSample(limit, offset));
		}
		catch (Exception e) {
			StringWriter sw = new StringWriter();
			e.printStackTrace(new PrintWriter(sw));
			logger.error(sw.toString());
			return null;
		}
//		logger.debug(String.format("Cache Stats:%s", sampleCache.stats()));
		return result;
	}
```
ログは初期設定の所と、上記のコメントを外すと出ます。
結構お手軽です。

以上、お疲れさまでした！
【Swift】関数の使い方〜その３〜


##戻り値
戻り値とは、関数の出力を表す値です。
戻り値の型は関数の宣言時に定義します。

**関数の呼び出し元は、定義された戻り値の型の値を出力として受け取ります。**

###戻り値の存在しない関数

関数を宣言する際に戻り値の定義は必須ではありません。
なので、戻り値が不要な場合は定義を省略できます。

message( )関数を作ってみました。

こちらは、print( )関数で文字を出力するだけの機能を持っていて
**戻り値を定義していないので関数の呼び出し元には何も値を返しません。**

```swift

func message(name: String) {
   print("\(name)さんこんにちは")
}

message(name: "Tanaka")

実行結果
Tanakaさんこんにちは
```

###戻り値のチェック

関数宣言で定義されている戻り値の型と実際の戻り値の方が一致するかは、
コンパイラによってチェックされています。

**定義された戻り値の型と戻り値の値が一致しない場合はコンパイルエラーになり、
戻り値が定義通りの値を返すことはコンパイル時に保証されます。**

当然ですが、Int型を戻り値としているにも関わらず、
戻り値の型をInt型以外にしているとコンパイルエラーになります。

```swift

func test() -> Int {
    let string = "眠いです。"
    return string   // コンパイルエラー
}

test()
```

エラー内容：`Cannot convert return expression of type 'String' to return type 'Int'`
和訳：タイプ 'String'の戻り値の型をリターンタイプ 'Int'に変換できません


**戻り値の型をInt型に指定している状態で、
戻り値をOptional\<Int>型にしている場合もコンパイルエラーになります。**

```swift

func test() -> Int {
    let string = "110"
    return Int(string)
}

test()
```

エラー内容：`Value of optional type 'Int?' must be unwrapped to a value of type 'Int'`
和訳：オプションタイプ「Int？」の値 タイプ「Int」の値にアンラップする必要があります

こちらの場合は、コンパイルエラーをなくすには、
**アンラップをするか戻り値の型をInt?型にすることで解決できます。**

###暗黙的なreturn

関数の実装が戻り値の返却のみで実装されている場合は、
returnキーワードを省略することができます。

この仕様のことを**暗黙的なreturn**と言います。

戻り値の返却のみで実装されている関数はこのような関数になります。

```swift

func test() -> Int {
    1 + 1
}

print(test())

実行結果
２
```

今回は、`1 + 1`の結果が返却できる型の値、かつ、別の処理が書かれていないので、
暗黙的なreturnが行われています。

`1 + 1`以外に別の処理を書いてしまうとreturnキーワードが必要になります。

以上、関数における戻り値の説明でした！

[【Swift】関数の使い方〜その１〜](https://qiita.com/onishiApp/items/8974493853e6564ff432)　と
[【Swift】関数の使い方〜その２〜](https://qiita.com/onishiApp/items/c5cda718694b4576ae75)　もございますので
ぜひそちらもご覧いただければと思います。
Gmailを利用したLaravelのメール送信設定

Laravelは認証機能をサクッと作れて便利ですよね。
5系だったら`php artisan make:auth`、最近の8系でも`php artisan jetstream:install`で簡単に作る(というか用意してもらう)ことができます。

ただ、認証周りでもパスワードリセットなどのメールが絡む機能の設定だけは自分でやる必要があります。

他の方の資料を参照しつつ、Gmailを利用したメール設定をしていきます!

ちなみに、以下の環境でお送りします。
> Laravel ver8
  デプロイ先heroku


#### 1.Gmailで２段階認証の設定
・Chromeでgoogleを見ると表示されるメニューから「アカウント」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420171/25ab1653-3bca-d6cf-1540-cb4f33434cc0.png)

・左メニュー「セキュリティ」から「２段階認証」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420171/94bd954c-3c93-b9c8-2263-c31a8b496ee0.png)

※ はじめての人は↑のアプリパスワードの欄がないかもしれませんが、一旦気にせず進めます。

・パスワードを入力する(パスワード忘れた場合はリセットして入力を進める)
↓
・パスワード入力を終えると２段階認証の方法を選択する画面に移ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420171/66d7be10-5495-c233-6c0d-79762b83109c.png)


この画面の認証設定はデフォルトの「音声」「テキストメッセージ」どちらでもOKです。
[次へ]に行くとスマホ等にパスワードが送られてくるので、それを画面に打つと↓のような画面が表示されたら次のステップへ行きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420171/e77615f0-b9e7-c511-6c53-4afe48a951ac.png)

#### 2. ログインできるアプリの登録

左メニューからデータとプライバシー > アプリとサービス > アカウントにアクセスできるサードパーティーアプリの登録 を選択!
＊最近設定したらカード全体ではなく、アイコン`>`しかクリックできないようになってたので注意。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420171/e9b4dcdb-28f2-3f32-e17d-3fc612887695.png)

#### 2.アプリパスワードの発行
・セキュリティ画面へ戻り「アプリパスワード」を選択、パスワード入力を求められるので、再度入力
アプリパスワードの画面にいったら、、、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420171/9879f999-4f59-09f4-1871-9f69ff0ce734.png)

・アプリを選択 > メール
・デバイスを選択 > その他 > アプリの名前を入力
して生成ボタンを押す。

・アプリパスワードが表示されるのでメモする。
※ メモを忘れたら再発行しましょう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420171/39cfcaa6-37ec-2175-eef2-7bf95e69568d.png)

これでGmail側でやることは終わりました。

#### 3.Laravel側の環境変数に設定する

Laravelの環境変数(`Mail_xxxx`)を設定していきます。

```.env
MAIL_DRIVER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=hoge@example.com // メールアドレス
MAIL_PASSWORD=hogehogehoge     // アプリパスワード
MAIL_FROM_ADDRESS=hoge@example.com  // MAIL_USERNAMEと同じ
MAIL_FROM_NAME=Laravel便り // メール送信元名
```

herokuにデプロイしている場合はアプリの管理ページ内`Settings > Config vars`から設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420171/a9a3dfe6-b94b-c0c2-c851-31dec43e4efb.png)

これでメール送信のための設定は終わりです。
パスワードリセット画面などからメールを送信してみましょう!

#### 補足
・開発環境と本番環境どっちもでメール送信する時はそれぞれに別のアプリパスワードを発行・設定する必要あり
・`.env`に書いた場合は`php artisan cache:clear`を実行してキャッシュ(編集前の環境変数情報)を消す
・デプロイしたアプリの`.env`に設定した場合は`cache:clear`の後に`php artisan config:cache`を実行する

#### 参考資料
[Laravelメール送信機能の実装でmailtrapやGmailのSMTPサーバーを使ってみる](https://qiita.com/KZ-taran/items/ffa60ac6353bc4dcc759#3-gmail%E3%81%AEsmtp%E3%82%92%E4%BD%BF%E3%81%86%E5%A0%B4%E5%90%88%E3%81%AE%E8%A8%AD%E5%AE%9A)
[Laravelでメール送信を送信したい](https://qiita.com/koru1893/items/e30d19ac97eac59b1e19)
[LaravelでGメールを送信する方法。アプリパスワードを取得すればOK。](https://loop-never-ends.com/laravel-gmail-app-password/)
[Failed to authenticate on SMTP server with username](https://qiita.com/mashshsh/items/665c14be44712c19c943)
CentOS6にワイルドカードの証明書(Let's Encrypt)導入と証明書発行でコケまくったけど何とかなった

# 前置き
こんばんは。@mashiです。
こんなご時世ですのでコストカットすることになり、無料の証明書であるLet's Encryptに変更することになりました。
もともとインフラは弱かったのですが、予想以上にコケまくって大変な思いをしたので、忘れないように備忘録として残しておきます。

# 導入と証明書発行
<pre>
cd /etc/
git clone https://github.com/letsencrypt/letsencrypt
chmod 755 ./certbot-auto
./certbot-auto certonly --manual -d [ワイルドカードのドメイン] --preferred-challenges dns
表示された値をDNSにTXT 300で登録後、Enterで進む
</pre>
これで/etc/letsencrypt/live/配下に[ワイルドカードのドメイン]の名前のディレクトリができているはず。(「*.」は抜けています)
そしてその中には、各pemファイルのリンクが存在します。

上記を確認した後に各ドキュメントルートのconfファイルを変更します。
<pre>
cd /etc/httpd/conf.d
cp [該当のドキュメントルート].conf [該当のドキュメントルート].conf.org
vi [該当のドキュメントルート].conf
</pre>

ファイルを開いたら3つのファイル指定の箇所を下記のように書き換えます。
<pre>
SSLCertificateFile /etc/letsencrypt/archive/[ワイルドカードのドメイン]/cert1.pem
SSLCertificateKeyFile /etc/letsencrypt/archive/[ワイルドカードのドメイン]/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/archive/[ワイルドカードのドメイン]/chain1.pem
</pre>

完了したらapache再起動
<pre>
service httpd restart
</pre>

これで完了のはず。

# 注意点
* 2020/11/30にてCentOS6のサポートが終了したことにより、以前のままではyumが利用できなくなりました。/etc/yum.repos.d/配下のファイル内のmirrorlistをコメントアウトし、baseurlを新たに追加し指定してあげることが必要かもしれません。
* certbotを利用する際にpythonが古いと怒られるケースがあります。アップデートして問題なければアップデートを、問題があるのであれば仮想環境にてpythonの新しいバージョンを動かすという方法もあるようです。めんどくさそう。
* 最初の git clone https://github.com/letsencrypt/letsencrypt を叩くとエラーを吐くケースがあるようです。「 https://github.com/certbot/certbot/info/ref が無いよ」と怒られるようです。なんで無いんだよ。この場合は「 wget https://dl.eff.org/certbot-auto 」を叩いて直接certbotを導入してゴニョゴニョすればいけるのかな。

# おまけ
ワイルドカードではなく普通に証明書を発行するのであればこれでいけました。confファイルの設定方法は同じです。
<pre>
./certbot-auto certonly -a standalone -d [ドメイン]
</pre>


更新の場合は下記のどちらか。
<pre>
通常の更新(有効期限が30日未満の場合のみ可能)
cd /etc/letsencrypt
./certbot-auto renew

有効期限までの残り日数に関係なくすぐに証明書を更新したい場合
cd /etc/letsencrypt
./certbot-auto renew --force-renew
</pre>

失効は下記です。
<pre>
cd /etc/letsencrypt
./certbot-auto revoke --cert-path /etc/letsencrypt/live/[ドメイン名]/cert.pem
</pre>

不明点が多いのでまた時間がある時にいろいろ調べていきます。証明書発行までが大変そう。

コメント等あればください。
collection_select要素のclass指定方法

こんにちわ！
現在車のレビューサイトをオリジナルアプリとして開発しており、
そこのレビュー検索機能ですこし悩んでしまった箇所がありましたのでアウトプットも兼ねて記事を書きたいと思います。

# 開発環境
Rails 6.0.0
BootStrap導入済み

# 今回の問題点
```html:views/review/index.html.erb
<div class="container">
  <div class="heading">
    <p class="heading-text">レビュー検索</p>
  </div>
  <%= search_form_for @p, url: search_reviews_path do |f| %>
      <div class="col-md">
        <div class="form-group">
          <label class="control-label">車種名</label>
          <%= f.collection_select(:model_of_car_eq, @review_model_of_car, :model_of_car, :model_of_car, include_blank: '指定なし', class:"form-control") %>
        </div>
        <div class="btn btn-default">
          <%= f.submit '検索', class:"btn btn-primary"%>
        </div>
      </div>
  <% end %>
</div>
```

今回は上記コードのような形でindexページに検索フォームを実装していました。
それで出来上がったのが下記です。

![スクリーンショット 2020-12-10 17.18.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/889492/b56deff4-4d98-55ec-f9fc-27ac33199716.png)

#### 検索ボックスちっさw 　なんでBootStrapのCSSが反映されていないんだ…



```html
<%= f.collection_select(:model_of_car_eq, @review_model_of_car, :model_of_car, :model_of_car, include_blank: '指定なし', class:"form-control") %>
```
このcollection_select要素の引数としてclass指定しているにも関わらず反映がされていませんでした。

検索で調べるもいまいちピンとくる記事がなく悩んでしまいました。


# 解決方法

実はめちゃめちゃ単純だったんです…
同じアプリの別のページでこんな記述をしていたのですが

```HTML
<%= f.collection_select(:automaker_id, Automaker.all, :id, :name, {}, class:"form-control") %>
```

#### {}が必要でした
{}にはselectedで選択済みにできるなどのオプションが入ります。
上記の｛｝は空欄の意味で記述されていると思っていましたが、実は違ったみたいですね。

下記のように修正したみたところ

```html
<%= f.collection_select(:model_of_car_eq, @review_model_of_car, :model_of_car, :model_of_car, {include_blank: '指定なし'}, class:"form-control") %>
```

![スクリーンショット 2020-12-10 18.10.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/889492/dce7ef93-3837-e25b-b0a1-3dcc6ddb361f.png)

**無事CSSを適用することができました！！**


流石にフォームが大きすぎるのであとは微調整していきたいと思います！
MySQL 5.7 でデータの先頭or末尾に文字を追加

何てことはなかった。。。
全データに対して文字連結 or INSERTする
全データの指定方法がわかってなかった。。。カラム名そのままでいいのね


```sql
UPDATE table SET content=CONCAT('先頭に追加する文字',  content, '末尾に追加する文字')　
```

```sql
UPDATE table SET content=INSERT(content,1,0,'先頭に追加する文字');
```
ESP32のセキュアなプロトタイピング環境を作成した(クライアント編)

#はじめに#
独学しているIoTセキュリティについて、集大成の意味合いを込めて現在理想と考えるセキュアなプロトタイピング環境を構築しました。
デバイス、サーバー、クライアントアプリの要素技術の勉強を含めて備忘録として分散して記していきます。
[前回](https://qiita.com/kmitsu76/items/831380bfd83bd0e7f8c6)、このプロジェクトにrainbowtypeと名前を付けました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387653/af2b0d90-7137-b10e-8066-1526cffce020.png)

構成は上記となり、今回はクライアント側の実装を検討してみます。


#rainbowtype clientの実装#

rainbowtype clientは開発者のWindowsPCに配置され、デバイスの操作、証明書の管理を行うためのアプリケーションとして作成した。
rainbowtype clientはrainbowtype serverと通信し、rainbowtype bootloaderが参照するデバイスステータス、アクションを設定する。
１，rainbowtype bootloaderが設定済みのデバイスに対して、以下を設定

* rainbowtype bootloaderで設定されたデバイス証明書の更新のための新しい公開鍵の提出要求
* 提出された新しい公開鍵に対する署名
* OTAするファームウェアの送信
* 個別に設定できるURLなどの情報

２，rainbowtype bootloaderが設定済みのデバイスが接続する先に対して、以下を設定

* rainbowtype bootloaderを認証できるサーバー証明書の発行
* AWS,Azureでrainbowtype bootloaderを認証するための確認証明書の作成

３，rainbowtype全体で使用する証明書の管理

* ルートCA証明書、秘密鍵の作成
* 署名者CA証明書、秘密鍵の作成

４，rainbowtype bootloaderのファームウェアに組み込む必要のある証明書定義の作成

５，製造された直後のデバイスに対して行うATECC608Aのプログラミング、証明書の保存を行うプロビジョニング

６，プロビジョニングが終わったデバイスに対してrainbowtype bootloaderを書き込むデプロイ

単一のWindowsアプリケーションとして作成し、ESP32とのシリアル通信、証明書作成など既存のPythonコードを使う必要がある。
そのため、Electronを使ってアプリケーションを作成し、そこからPython を呼び出す方法を考えた。
Reactフレームワークを利用できる[Electron React Boilerplate](https://electron-react-boilerplate.js.org/)を使用した。
ボタンなどのUIを利用するため、[Material-UI](https://material-ui.com/)を組み込んだ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387653/17ab3bb9-8999-6a60-be91-4e2e53b9a29a.png)

起動後の画面イメージは下記のようになった。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/387653/80b1bcc7-31fc-ce1d-23b4-96afdd0ed74d.png)


コードは[rainbowtype-client](https://github.com/kmwebnet/rainbowtype-client)へ公開した。
Vagrantを使う

#Vagrantとは
仮想環境の構築、共有をコマンドで簡単に行うためのツールです。

`VirtualBox` 　`VMWare` などの上に仮想マシンを構築します。
VirtualBox という土地に Vagrant を使って家( 建物 )を建てる感じでしょうか。



###①Vagrantインストール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/836751/daf8126c-64da-379b-2b43-fd60d6cf8964.png)
<b>[Vagrant](https://www.vagrantup.com　)</b>　←ここから自分の使っているOSを選んでインストール
　

###②Box の選択
Vagrantのインストールが終わりましたら、boxの選択をします。
このboxとは仮想マシンで使うOSのテンプレート（ひな型、元）になるファイルです。
いちいち仮想マシンごとにOSを１からインストールするのは面倒でしょ？ 使いなよってやつ。

https://app.vagrantup.com/boxes/search
http://www.vagrantbox.es/
↑
ここからboxを選んでインストールします。
方法は

```
~ % vagrant box add [boxの名前か URLを入れる]
```
実行すると使うプロバイダーを聞かれるので数字を押してenter

```
1)vmware
2)virtualbox
3)hyperv
```
インストールが開始します。終了しましたら 

```
~ % vagrant box list
``` 
コマンドでちゃんとインストールされているか確認しましょう。



###③Vagrantfile の作成
Vagrantfileとは仮想環境の構成情報が書かれている物です。
これがあれば開発環境の共有するのに大変便利となります。

```
~ % vagrant init [boxの名前]
```
仮想環境を初期化するためのコマンド。
実行するとVagrantfileが作成されています。
中を見てみると...

```
~ % vim Vagrantfile
　

Vagrant.configure("2") do |config|
    config.vm.box = "Boxの名前"
end
```

色々コメントが書いてありますが、このようになっているはずです。
　
###④Vagrant を使って仮想環境の起動
```
~ % vagrant up
```
とすると指定した仮想マシンが起動し始めます。
きちんと起動しているか確かめるためには

```
~ % vagrant status 
```
として 

```
Current machine states:

default                   running (virtualbox)
```
`running` になっていれば大丈夫です。


 　・ <b>停止</b>したいときは下記のコマンドを入力。


```
~ % vagrant halt
```
 

　・ <b>再起動</b>したい場合は

```
~ % vagrant reload
```
 
　・ <b>削除</b>は

```
~ % vagrant destroy
```
　

###⑤仮想環境に接続

```
~ % vagrant ssh
```
としてあげると、SSHで仮想マシンに接続できます。
SSHを終了したい場合は

```
vagrant@[BoxのOS名]:~$ exit
logout
Connection to 127.0.0.1 closed.
```
となります。



##参考
https://webbibouroku.com/Blog/Article/vagrant　
https://polidog.jp/2015/10/19/vagrant/　
https://learn.hashicorp.com/vagrant　
https://dev83.com/vagrant02/
チーム開発でSlackに通知してる外部サービスのRSS / Twitter


外部サービスの障害情報をSlackに通知してます。

# やりかた

RSS、Twitterの公式アプリで通知しています。

https://slack.com/apps/A0F81R7U7-rss

https://slack.com/apps/A0F7XDW93-twitter


# 外部サービス

## AWS 東京リージョン (Twitter)

https://twitter.com/awsstatusjp

## CircleCI (RSS)

https://status.circleci.com/history.rss

## Discord (RSS)

https://discordstatus.com/history.rss

## Firebase (RSS)

https://status.firebase.google.com/feed.atom

## GitHub (Twitter)

https://twitter.com/githubstatus

## pay.jp (RSS)

https://status.pay.jp/history.atom

## Slack (Twitter)

https://twitter.com/SlackStatus

# 参考

ありがとうございました🙏

https://qiita.com/qrusadorz/items/8b86d89233daffe3439c
MATLABでFigureを最前面にせず、描画対象にする。

Figureを2つ以上扱っていて、他の作業をしているときに図を前面に出さずに更新したいときがあります。
自分はよく忘れて検索するので、メモがてら残しておきます。


```matlab:example1.m
set(groot, 'CurrentFigure', FigNo);
```

をつかうとこれができます。


```matlab:最前面にする.m
while(true)
    % FTDTなどのコード
    % t:時間ベクトル
    % x:xの経時変化
    % y:yの経時変化
    figure(1);
    plot(t,x);
    figure(2);
    plot(x,y);
end
```
こういう風に書くと、1step毎にfigureが最前面に出るので、他の作業が進まなくて辛いです。

```matlab:最前面にしない.m
while(true)
    % FTDTなどのコード
    % t:時間ベクトル
    % x:xの経時変化
    % y:yの経時変化
    set(groot, 'CurrentFigure', 1);
    plot(t,x);
    set(groot, 'CurrentFigure', 2);
    plot(x,y);
end
```
こう書けば、裏で作業してても邪魔されずに快適です。
ドラムロールのタイムピッカー「pickerjs」を複数箇所で使用できるようにする

### デモ

https://codepen.io/qwe001/pen/LYRRvmL

### 実装

普通にjqueryのeachでぶん回すだけです

```
  var target = ".time";
  $(target).each(function(){
    var id = $(this).attr("id");
    new Picker(document.getElementById(id));
  });
```

### 注意

作者は複数箇所での使用はサポートしていないと言っています。
Gitのリポジトリがアーカイブにされてて追記できない状態だったので、
ここに書くことにしました。

https://github.com/fengyuanchen/pickerjs/issues/31

とりあえず、できましたよっていう報告だけ。

### おまけ

ドラムロールで選択した値を使って色々したいとか、あると思います。
pickイベントを使うことで、値を拾うことができます

このライブラリの情報が少ないのでソースコード全文掲載します
※動かすにはjQueryとmoment.jsが必要です

```javascript

function TimePicker()
{
  var target = '.time';

  var now = moment();
  var dateFormat = {
    zone   : 'Asia/Tokyo',
    year   : now.year(),
    month  : now.month(),
    day    : now.day(),
    hour   : now.hour(),
    minute : 0,
    second : 0
  };

  var date = moment().set(dateFormat);

  $(target).each(function(){
    var self = this;
    var id = $(self).attr('id');

    var picker = new Picker(document.getElementById(id), {
      format: 'HH:mm',
      controls: true,
      headers: true,
      date : new Date(date),
      increment: {
        minute : 15
      },
      text: {
        title: '<span>時間を選択してください</span>'
      },
      pick(event) { // OKボタンを押した時に発火
        var dt = picker.getDate();
        var momentInstance = moment(dt);
        var time = momentInstance.format("HH:mm");

        console.log(time);

        // なんかdiv要素書き替えるとかそういうの
        $(self).text(time);
      }
    });
  })
}

new TimePicker();
```

### さらにおまけ

ヘッダーに入るテキストには、HTMLタグが使用できます。
HTMLタグが使用できるということは、クリックイベントを仕込むことが出来るということです。
例えば、ヘッダーにボタン要素を設置して、クリックしたら任意のテキストを設定するといったことは、次のようなやり方で出来ます。
(もっと良い方法があったら誰か教えてください)

```javascript
    $(target).each(function(){
      var self = this;
      var id = $(self).attr('id');

      var picker = new Picker(document.getElementById(id), {
        // その他のオプション値は省略します。↑のソースコードを参考にしてください
        text: {
          title: '<span>時間を選択してください</span> <button type="button" class="btn-no-return">NR(直帰)</button>'
        },
        show(event){ // モーダルが開き始めた時に発火
          //
        },
        shown(event){ // モーダルが開き終わった時に発火
          $(self).addClass("active-cell"); // 直帰ボタンイベント用
        },
        hide(event){ // モーダルが閉じ始めた時に発火
          //
        },
        hidden(event){ // モーダルが閉じ終わった時に発火
          $(self).removeClass("active-cell"); // 直帰ボタンイベント用
        },
        pick(event){ // OKボタンを押した時に発火
          var dt = picker.getDate();
          var momentInstance = moment(dt);
          var time = momentInstance.format("HH:mm");
          console.log(time);

          // なんかdiv要素書き替えるとかそういうの
          $(self).text(time);
        }
      });

      // 直帰ボタンを押した時
      var btnNR = '.btn-no-return';
      $(btnNR).click(function(){
        $('.active-cell').text("NR");
        picker.hide();
      })
    })
```
テーブルのレコード分、ループする処理でコケると・・・？

##ロボ設計でつまずきがちなところ
Excelに記載された40人分のユーザーにそれぞれ専用のBOXフォルダを作成するロボを作成した、私。

BOXフォルダはアクセスするのにフォルダIDが必要なので、作成したら担当者マスタのExcelにIDを書き込んでいく予定。

フローは単純で
担当者マスタExcel読み込み　⇒　メールアドレスをKEYにBOXフォルダを作成　⇒　フォルダIDをマスタに書き込み
の流れです。
#### いよいよ、リリースとなり、初回、みんなが見守る中、処理実行開始！！
>【Start】
>1人目、作成OK
>2人目、作成OK
　：
>
>20人目でなんかコケちゃった:disappointed_relieved:　→　ロボ停止。エラーメール送信。
>【End】

BOX上には19人分のBOXフォルダと何も更新されていない担当者マスタが残る。

エラー原因を調査！！
どこまでいったか、担当者マスタのExcelを見ても分からないので、ログを追いかける→20人目でコケタのが分かる→原因を調査→分かった！解決

####さて、再実行（あ、BOXのフォルダ消さないと・・・19人分のフォルダ消す→再実行！今度こそ！）
>【Start】
1人目、作成OK
2人目、作成OK
　：
21人目でなんかコケちゃった:disappointed_relieved::disappointed_relieved:　→　ロボ停止。エラーメール送信。
>【End】

 BOX上には20人分のBOXフォルダと何も更新されていない担当者マスタが残る。

**心の声（くそーーーーー！ひとり分も終わらねぇ！！）**

ユーザー　「とりあえず、出来てる人だけでも使いたいんだけど」

私　　　　「あ、、BOXIDがかけてないから、使えないっっ。。。。まって、、、レコード絞って再実行します:sob:
　　　　　　も、、、もう少々お待ちください:tired_face:」

ユーザー　「じーーーーーーー。（早くして）」

※これが夜間バッチだった場合、翌朝から使えると思いこんでいた人達からのプレッシャーを受けまくるケースもあります

##ループ構成
お気づきの方もいらっしゃると思いますが、あるリストに対する一連の処理をする際には2パターンの設計があります。
####A
![A.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356722/e0f7aa6e-014c-2ea6-ab37-5737628684c0.png)

####B
![B.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356722/449dd3b9-88be-c76d-f538-e36b362bf0b0.png)

##まとめ
こういうループって絶対途中でコケるので、「やれるところまでやりましたロボ」にすることをオススメします。
（もしくは、ユーザーとの仕様決めのときに、ゼロイチロボかやれやりロボかの認識を合わせておく）

エラーはTry-Catchesで受けとめるんだけど、ロボ停止せずに、「コイツの作成失敗した」っていうのをメモって次の行の作業を進める。
ってすると、後から、ダメだった人だけフラグ立てて再実行すればよい。みたいな風にもできます。
エラーをキャッチしたら、ロボを停止しないといけないってことは無いのです。

RPA化するにあたって、「手作業をそのままRPAに再現させる」という方法を取ると、このループに陥る可能性が高いです。

人間のやり方では「纏めてやった方が効率がよい」ので、各処理ごとにまとめてやってしまう流れにしていることが多いと思いますが、RPAではまとめてやっても、1件ずつ全ての作業を流してもほとんど変わらないケースが多いので、そういう目線での設計が大切かなと思います。

以上、よくある事例紹介でした！