OmniAICreator/Qiita-1.07M huggingface dataset:
[JavaScript]2生物ライフゲーム/Two Camps Game of Life

[本記事は、自分サイトのこの記事と同一内容です。](https://hagiayato.github.io/my-site/jekyll/update/2021/02/23/GameOfLife.html)
# はじめに
以前なんとなく調べて出てきたのが、ライフゲームというものです。
その概要は下記"ライフゲームの説明"とwikipediaの[当該記事](https://ja.wikipedia.org/wiki/%E3%83%A9%E3%82%A4%E3%83%95%E3%82%B2%E3%83%BC%E3%83%A0)を参照していただくとして、webフロントの実装練習として作成してみました。
[実装したライフゲームの実行サイト](https://hagiayato.github.io/MyLifeGame/)

# ライフゲームの説明

## 概要
[ライフゲーム(wikipedia)](https://ja.wikipedia.org/wiki/%E3%83%A9%E3%82%A4%E3%83%95%E3%82%B2%E3%83%BC%E3%83%A0)
ライフゲームは、生命の誕生、生存、死亡をマス目でシミュレーションするゲームです。
ゲームと言ってもクリア、ゲームオーバー条件はなく、自由にマスに生命を配置し、その変化を楽しみむものです。
## セルの生死ルール
※上記wikipedia記事より引用

 - 誕生…死んでいるセルに隣接する生きたセルがちょうど3つあれば、次の世代が誕生する。
 - 生存…生きているセルに隣接する生きたセルが2つか3つならば、次の世代でも生存する。
 - 過疎…生きているセルに隣接する生きたセルが1つ以下ならば、過疎により死滅する。
 - 過密…生きているセルに隣接する生きたセルが4つ以上ならば、過密により死滅する。

### 独自機能　"2生物"
ここで実装しているライフゲームは、2色(=2生物)のライフゲームです。
セルの生死追加ルール

- 生存、過疎、過密…2種の生物それぞれで判定を行う。</li>
- 誕生…2種の生物それぞれで判定を行う。どちらの生物も誕生できるときは、ランダムにどちらかが誕生する。

※1色だけ使えば、普通のライフゲームとして遊べます。
なぜ2生物にしたのかは、単純な自分の興味と他の方がやっていないからです。
ライフゲームで2つの生物を戦わせてみたらどうなるのか、気になりますよね…
### 操作説明
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655112/9f046239-ef3a-daa8-2aec-719f9350f274.png)


- クリアボタン…全生物を消す
- 開始/停止ボタン…ライフゲーム開始/停止
- 入力色(ラジオボタン)…入力色(生物)の選択
- FPSレンジ操作…FPS・実行周期の変更　*※2021/2/26機能追加*
- グリッドのマスをクリック…入力色(ラジオボタン)で設定した色の生物を配置
  配置しているマスをクリックした場合は生物を消す。
- グリッド上でドラッグ…入力色(ラジオボタン)で設定した色の生物を一括配置

# リンク
### 実装の参考
- [canvasでドット絵用のキャンバスを作成する [1マス=1ドット]](https://www.petitmonte.com/javascript/canvas_dot_picture.html)  
  セル表示、色塗り機能はこちらのサイトのコードをもとに実装させていただいております。

### 製作者関係
- [このwebアプリの実行サイト](https://hagiayato.github.io/MyLifeGame/)
- [このwebアプリのソースコード(github)](https://github.com/HagiAyato/MyLifeGame)
Babel - .babelrc vs .babelrc.json vs babel.config.json vs babel.config.js

* Project-wide configuration
 > babel.config.json files, with the different extensions (.js, .cjs, .mjs)

* File-relative configuration
 > .babelrc.json files, with the different extensions (.babelrc, .js, .cjs, .mjs)
 > package.json files with a "babel" key
 > For compatibility reasons, .babelrc is an alias for .babelrc.json.


https://stackoverflow.com/questions/60288375/when-to-use-babel-config-js-and-babelrc
https://awdr74100.github.io/2020-03-16-webpack-babelloader/
https://babeljs.io/docs/en/config-files
Salesforceで子のオブジェクトのレコードページから親オブジェクトのレコード項目更新方法

Salesforceで子のオブジェクトのレコードページから親オブジェクトのレコード項目更新方法を記載します。
※前提としてLightning環境となります。Classic環境では対応できない方法です（Classic環境の場合、プロセスビルダーを使用すれば子オブジェクトで項目更新した際に項目内容を親オブジェクトの項目更新が可能です）

今回は例として「商談オブジェクト」レコードページから商談に紐づく「取引先オブジェクトの電話項目」を編集する設定方法をご紹介します。
（商談中に企業の電話番号が変更されたことが判明。その情報を商談ページから残したい　という状況を想定います）

１設定＞オブジェクトマネージャ＞取引先＞ボタン、リンク、およびアクション
をクリック。新規アクション作成ボタンをクリック
![アクション1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/22985cdb-3419-6c2d-5734-487a16f10f2a.png)


2添付画像のようにアクション種別を「レコードを更新」に設定し保存ボタンをクリック
![アクション2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/b59792b8-1c3e-2736-43ab-cdb9610d954d.png)

3レイアウトで[電話]のみ残し保存ボタンをクリック

![アクション保存.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/e3c733e0-90be-1da8-2ffc-cef1ee9eb604.png)

4次に商談のレコードページに移動し歯車マークから「編集ページ」をクリック
![編集ページ１.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/8e303b3c-438a-6de3-f165-05a55b3f6f8e.png)


5「関連レコード」を任意の場所に追加。
「参照項目」を取引先名、「更新アクション」を上記作成したアクション名に設定。
設定後に保存ボタンをクリックします。
![レコードページ保存.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/ca11321e-194c-e204-f83a-9b35fbf04c82.png)

設定完了後に商談ページを見ると紐づく取引先オブジェクトのレコード内容が確認できます。
鉛筆マークをクリックすると商談のページから取引先項目の編集が可能です。
![02231.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/33335963-14ff-bb63-62aa-0bff5bea38ff.png)




## 注意点

参照のみ（編集不可）のユーザがレコードを見た場合、コンパクトレイアウトの項目が表示されるのでご注意ください

詳細はこちら

https://qiita.com/Takaa/items/76b44376c79655c32055
RPAのID管理

想定課題の検討（RPA ID管理編）

**課題：
　RPA運用に係るID管理を最適化するには？**

**現状：
　概要：**
　　・デスクトップ型でRPAを運用している。
　　・RPAユーザは、RPA実行専用のアカウントとPCを発行し、使用・管理している。
　　・今回、あるRPAユーザから、複数人でRPAを運用したい、と申し入れを受けた。
　　
　**詳細：**
　　・RPA運用のAS-IS構成（RPAの利用部分）は以下イメージのとおり。
　　　![ASIS.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370717/fdd1dd01-6b27-a58a-3bc3-e5f7041e11f6.jpeg)
　　・申し入れの背景として、RPAユーザは、在宅勤務、打合せ、休暇などの業務都合を理由に、他の社員にRPAを実行してほしい機会が多くあるとのこと。

**検討：
　前提：**
　　・RPA運用に係るID管理は、セキュリティ、利便性、コストの3点を考慮する必要があると考える。
　　
　　**・セキュリティ：**
　　　　ルール上、RPA実行専用を含む、すべてのアカウントの共有は禁止されている。
　　**・利便性：**
　　　　RPAを実行できるユーザ数が増えると、RPAの利便性は基本的に高くなる。一方、RPA実行専用アカウントが増えると、管理負担は大きくなる。
　　**・コスト：**
　　　　PCおよびRPA利用アプリ（ライセンス費）に対してコストがかかる。基本的には、RPAを利用する社員が増えると、RPA利用アプリに対するコストは増加する。
　　
　　・判断の優先順位は、セキュリティ＞利便性＞コストとする。

　**検討：**
　　・シナリオを洗い出し、各シナリオを、セキュリティ、利便性、コストの3つの観点で評価する。

| シナリオ |セキュリティ  |利便性  |コスト  |
|:-:|:-:|:-:|:-:|
|①RPA実行専用アカウントを追加する|○  |△   |✖   |
|②社員アカウントを、通常作業とRPA実行で併用する   |○   |○   |○   |
|③RPA実行専用アカウントを複数社員で共用する   |✖   |○   |○   |
|④RPA運用サーバーを導入する   |○   |○   |✖   |

　　・シナリオ②：
　　　　概要：
　　　　　RPA実行専用アカウントを使用する代わりに、社員が既に持っているアカウントをRPA実行にも使用するという方法

　　　　詳細：
　　　　　・TO-BE構成（RPAの利用部分）は以下イメージのとおり。
　　　　　![TOBE.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370717/1a20ad7f-3f73-5816-2a95-2c9fc02d3728.jpeg)
　　　　　・セキュリティ：
　　　　　　　社員アカウントが共用されるリスクは低いため、ルールに準ずることが可能
　　　　　・利便性：
　　　　　　　RPAを利用できるユーザが増え、かつ、管理するアカウントは増加しないため、利便性が向上
　　　　　・コスト：
　　　　　　　RPAが利用するアプリの専用アカウントが不要となるため、ライセンス費が削減
　　　　
　　　　その他（残課題）：
　　　　　・利用アプリのアクセス権限は、社員とロボットが同一になる
　　　　　　　⇒おそらくOK
　　　　　・利用アプリのログには、社員がログインし、実行したログが出力される
　　　　　　　⇒要確認（セキュリティ担当）
　　　　　・利用アプリが二重ログイン制限（別PCかつ同一アカウント）を実装している場合、「RPA実行中は、ユーザは特定のシステムを利用することはできない」という制約が加わる
　　　　　　　⇒要確認（アプリ担当＋ユーザ）
　　　　　・RPAのメール送信は、ユーザ名義で送信される
　　　　　　　⇒要確認（ユーザ）

　　※シナリオ①③④については割愛する。

結論（一部残課題あり）
　本課題を解決するための方法は、**「社員アカウントを、通常作業とRPA実行で併用する」**という方法が最適と考える。
\uからはじまる謎の符号、Unicodeエスケープシーケンス

個人的メモのようなもの。

curlコマンドで叩くと謎の文字列が返ってくることがある。おぉ、読めない……

```
curl -sk "http://localhost/api/1/test"
{"message": "\u30ed\u30b0\u30a4\u30f3\u3057\u3066\u304f\u3060\u3055\u3044"}
```

実際には、 `jq` を通すことで読める。

```
curl -sk "http://localhost/api/1/test" | jq
{"message": "ログインしてください"}
```

この文字はなんなんだろうか、ということで。
調べてみると、正式名称は分からないものの、「**Unicodeエスケープシーケンス**」という言葉が出てきました。

「ロ」と「30ed」の対応は、何の対応なんだろうか……？

[JIS X 0208 (1990) to Unicode 漢字コード表](http://charset.7jp.net/jis0208.html) を参考にさせていただきました。

これを見ると、UTF-16での符号のようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90217/11743f39-b466-100f-1733-a3a7099681fb.png)

Webページでのサービスを見つけました。お手軽で良いかも。

[Unicodeエスケープシーケンス変換ツール](https://tech-unlimited.com/escape-unicode.html)
iPhone, iPadで別機器のライン出力から手軽に録音する方法

最近、子供の工作の手伝いとして、NintendoSwitchのヘッドフォン端子から、iPhone/iPadで音声取り込みを行う必要がありました。当初、Φ3.5mmオーディオケーブルでの接続を試しましたが、どうしてもiPhone/iPadが内蔵マイクによる取り込みから切り替わらず、苦戦しました。
最終的に解決しましたので、その知見を共有します。

## 必要となった物
試行錯誤の結果、下記のケーブル類があれば、音声取り込みができることがわかりました。逆に、これらのどちらかが無いと、iPhone/iPadは外部機器が接続されていると認識せず、内蔵マイクによる音声取り込みに切り替わってしまいます。

### 必要なもの１：ヘッドセット用 Φ3.5mm変換ケーブル

![100000001002598198_10204.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/956051/08585e4d-e01d-e20e-c080-9eda9d3ced50.jpeg)

iPhone/iPadのΦ3.5mmヘッドセット用端子は、4極の端子です。これを、マイク、スピーカの3極メスに分離する変換ケーブルが必要となります。私の場合は、[ELECOM AV-35AD02BK](https://www.elecom.co.jp/products/AV-35AD02BK.html)を利用しました。

### 必要なもの２：抵抗入りΦ3.5mmオーディオケーブル

![ac_001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/956051/8a77d2d5-8862-49c4-f56b-f8cabdbcaa45.jpeg)

ライン出力をマイク入力に変換するため、抵抗入りのケーブルが必要となります。一般的な「抵抗無し」のものを利用してしまうと、iPhone/iPadは別機器からの音声を取り込みません。私の場合は、[JVC CN-204A](https://www32.jvckenwood.com/jvc/avcord/index.asp?id_2=30)を利用しました。

## 接続方法
次の写真の通り、ヘッドセット用 Φ3.5mm変換ケーブルのマイク入力側に、抵抗入りΦ3.5mmオーディオケーブルを接続して利用します。一部の情報には、スピーカ側にも何か接続しないと認識しないとありましたが、私の場合はスピーカ側には何も接続しなくてもOKでした。

![IMG_0020.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/956051/0ba20172-6906-d9f2-40df-57dfd8386b41.png)

接続の順番によっては、うまく外部機器を認識しないこともありましたが、ヘッドセット用 Φ3.5mm変換ケーブルのiPhone/iPad接続部分を抜き差しすることで、認識するようになります。
Reactでログイン機能

## はじめに
Reactでとてもシンプルなログイン機能を見つけたのでメモです。localstrageにトークンを持たせる実装なので、XSSによる脆弱性が考えられます。あくまで一例として読んでいただければ幸いです。

## 実装
localStorageを用いてログイン情報を管理します。ログインしてない状態でURLにアクセスしたときにログイン画面にリダイレクトするために、PrivateRouteというコンポーネントを作成し、App.jsのRouteに設置します。


```js:Login.js
// 省略
if (パスワードが一致) {
  localStorage.setItem('user_id', トークン);
}
// 省略

```
api側でmailadressとpasswordが一致したら、localStrageにトークンを設置する。
ログアウトの際は、`localStorage.removeItem('user_id')`をする。



```js:PrivateRoute.js
  
import React from "react";
import { Route, Redirect } from "react-router-dom";

function PrivateRoute(props) {
    var isAuth = false;  
    var  user_id= localStorage.getItem("user_id");
    if(user_id!=null){        
        isAuth = true;
    }
    return isAuth ? <Route {...props} /> : <Redirect to="/login" />;
}

export default PrivateRoute;

```
localStrageにトークンが存在すれば遷移先のRouteを、存在しなければログインページへのリダイレクトをする。

```js:App.js
import React from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';

import Login from "./login/login";
import Home from "./home/home";
import PrivateRoute from "./components/PrivateRoute";

class App extends React.Component {
  render() {
    return (
      <BrowserRouter>
        <Switch>
          <PrivateRoute exact path="/home" component={Home} />
          <Route exact path="/login" component={Login} />
        </Switch>
      </BrowserRouter>
    );
  }
}

export default App;
```

\<Route>はログインしなくても見れるページ、\<PrivateRoute>はログインしないと見れないページに使用します。


## おわりに
結局、セキュリティの面も考慮した一番良い方法は何なのでしょうか。Cookieなどに持たせるべきなのでしょうか。
git@github.com: Permission denied (publickey). の解決方法



git pushしようとしたら以下のエラーが発生しました
## エラーメッセージ

```
$ git push
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

// ssh接続できるか試してみる
$ ssh -T git@github.com
git@github.com: Permission denied (publickey).
```

## 解決方法

`ssh-add`コマンドで状況を確認してみます

```
$ ssh-add -l
The agent has no identities.
```
エージェントにIDが登録されていないようです。
今回はこれが原因なのでIDを登録します。

```
$ ssh-add ~/.ssh/id_25519
Identity added: /Users/<username>/.ssh/id_25519 (47884591+yoritin@users.noreply.github.com)
```



## 再度確認

```
$ ssh -T git@github.com
Hi yoritin! You've successfully authenticated, but GitHub does not provide shell access.
```

ssh接続が確認できるようになりました。

~~ちなみに、再起動するたびに毎回エラーが発生する場合は
`ssh-add` するときに `-K` オプションを付けると再起動のたびに`ssh-add`する手間が省けます。~~
【Go】構造体（struct）の基本を簡単に理解する

## 構造体(struct)とは
Goにはクラスは存在しないらしく、その代わりに構造体を使用します。
名前（フィールド名）と型（int型やstring型など）を持つ**フィールドの集まり**です。
メソッドや埋め込み(embedded)などといった機能も存在します。これらを含めると長くなってしまうので別の記事で紹介します。

### なぜ使うのか
例えば、ユーザーのデータがあるとします。
この各ユーザーには共通して「名前」「性別」「年齢」のデータが必要です。
もしも構造体を使わなければ、以下の様に1つ1つ宣言する必要があります。

```go
var name string
var sex string
var age int
```
しかし、これだとそれぞれ共通したユーザーデータなのに関連性が分かりません。（まとまりがない）
なので1つの**関連性のあるデータ**なのだと分かりやすくする為に構造体を使用します。

```go:struct
type User struct {
  Name string
  Sex string
  Age int
}
```
上記の様に構造体を使うことによって、「名前」「性別」「年齢」というユーザーデータがまとまって分かりやすくなりました。
（コードの書き方についてはすぐ下で説明します。）

## 構造体の使い方
次にGoでの構造体の使い方についてです。
定義方法、初期化方法、操作方法(値の変更)の3つに分けて説明したいと思います。

### 定義方法
先ほど、「名前（フィールド名）と型（int型やstring型など）を持つフィールドの集まりです。」と言いましたが、それがどういった意味なのかを見てみましょう。
**構造体の定義には`type`と`struct`を使用**します。

```go
type 構造体型の名前 struct {
  フィールド名 型
}
```

```go
type User struct {
  Name string
  Sex string
  Age int
}

// 型が同じ場合、これでもOK
type User struct {
  Name, Sex string
  Age int
}
```
#### フィールド名の付け方には注意が必要
構造体を定義するときに注意して欲しいポイントとして、フィールド名の付け方があります。

上記の例ではフィールド名が`Name`や`Sex`、`Age`の頭文字は大文字になっています。
これには理由があります。

実は構造体のフィールド名の頭文字を小文字にしてしまうと**外部packageの外からアクセスできなくなる**のです。
逆に大文字にすればpackageの外側からでもアクセスできる様になるというわけです。

どういうことかというと、例えば以下のようなディレクトリ構成があるとします。

```:ディレクトリ構成
|-----dir/sub.go
|
|-----main.go
```
**小文字の場合**

```go:sub.go
package dir

type User struct {
  name, sex string
  age int
}
```

```go:main.go
package main

import (
  "fmt"
  "./mypkg"
)
func main() {
  akihiro := User{Name: "彰宏", Sex: "男", Age: 23}
  fmt.Println(akihiro)
}
```
実行結果はエラーが発生します。

**大文字の場合**

```go:sub.go
package dir

type User struct {
  Name, Sex string
  Age int
}
```

```go:main.go
package main

import (
  "fmt"
  "./mypkg"
)
func main() {
  akihiro := User{Name: "彰宏", Sex: "男", Age: 23}
  fmt.Println(akihiro) // => {彰宏 男 23}
}
```
実行結果は`{彰宏 男 23}`と正常に実行されます。

### 初期化方法
次に初期化方法です。
構造体については上記の`User`を使用します。

```go
変数名 := 構造体型の名前{フィールド名: 任意の値}
```

```go:方法１
// var akihiro User = User{Name: "彰宏", Sex: "男", Age: 23} と同じ
akihiro := User{Name: "彰宏", Sex: "男", Age: 23}
fmt.Println(akihiro) // => {彰宏 男 23}
```
他にもいくつかの宣言方法があるので紹介します。

```go:方法２
akihiro := User{"彰宏","男", 23}
fmt.Println(akihiro) // => {彰宏 男 23}
```

```go:方法３
var akihiro User
akihiro.Name = "彰宏"
akihiro.Sex = "男"
akihiro.Age = 23
fmt.Println(akihiro) // => {彰宏 男 23}
```

#### 宣言時に値を何も取らなかった場合
```go
var akihiro := User{}
fmt.Println(akihiro) // => {    0}
```
宣言時に値を何も取らなかった場合は、構造体のフィールドで定義した型の初期値が入ってきます。
つまり、`Name`や`Sex`はstring型なので`""`(空文字)、`Age`はint型なので`0`が入ってくるというわけです。

### 操作方法（値の変更）
初期化した構造体の値を変更するには、初期化した構造体を代入した`変数`に`.`で`フィールド名`を繋げてあげればOKです。

```go
akihiro := User{Name: "彰宏", Sex: "男", Age: 23}
fmt.Println(akihiro) // => {彰宏 男 23}

akihiro.Age = "18"
fmt.Println(akihiro) // => {彰宏 男 18}
```
python初心者が食べログをスクレイピングして駅からの距離と評価の関係を調べてみた

#目的
スクレイピングをしてみたくてなんとなく思い浮かんだ食べログをスクレイピングしてみます。
仮説として、駅からの距離が近い店は家賃が高いからそれだけ人気を維持しなければいけないから評価が高い店が多いのではないかと思いました。
駅からの距離と評価を抽出して関係を調べてみます。

#環境構築
windows8
anacondaをインストール
python3.7.5


#ソース
食べログの東京にある店でMAXの60ページ分をスクレイピングで取得しています。
1ページに20件の店なので1200件分のお店ですね。
すべての店には駅からの距離が記載されているのですが、1つだけ世田谷とだけしか書かれていない店があったため処理をスキップしています。

```python:tabeAnalysis.py
import requests
import csv
from bs4 import BeautifulSoup
import re
import matplotlib.pyplot as plt

root_url = 'https://tabelog.com/tokyo/' # 食べログURL
max_page = 60       # 最大表示ページ
url      = root_url # スクレイピングしていくURL
x        = []       # x軸 駅までの距離
y        = []       # y軸 評価

# 最大ページまで繰り返し
for page in range(2, max_page, 1):
    res      = requests.get(url)
    # HTMLパーサーでHTMLを扱いやすいようなデータに変換する
    soup     = BeautifulSoup(res.content, 'html.parser')
    # 駅からの距離を配列で取得
    distance = soup.find_all('div' , class_='list-rst__area-genre cpy-area-genre')
    rate     = soup.find_all('span', class_='c-rating__val c-rating__val--strong list-rst__rating-val')
    # スペースと"/"以降の文字を削除する（駅までの距離を取得）
    for (distance,rate) in zip(distance,rate):
        # 1つだけフォーマットが異なるデータがあったのでスキップする
        if '世田谷区' in re.sub('.*駅', '', re.sub('/[^/]*$', '', distance.text)).strip().replace('m', ''):
            continue
        # 距離の数字以外の文字を省いてx軸に加える
        x.append(int(re.sub('.*駅', '', re.sub('/[^/]*$', '', distance.text)).strip().replace('m', '')))
        # 評価をy軸に加える
        y.append(float(rate.text))
    # 次のページのURLを取得
    url = root_url + 'rstLst/RC/' + str(page) + '/'

# 散布図
plt.scatter(x, y)
# グラフの可視化
plt.show()
```
githubにも上げてみました
https://github.com/mimicman/tabeAnalysis

#実行結果
実行結果は下記のグラフになります。
横軸が駅からの距離で縦軸が評価です。


![Figure_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613127/57b17227-f635-a1d6-cbef-902bd0c6b5bf.png)

#評価
駅からの距離が近いと評価も高くなるんじゃないかとおも思いましたが、そうでもないようです。
むしろ予測とは逆に駅から遠いほうが評価の高い店があるようにも見えます。
これだけじゃわかりませんのでもっと統計時な処理が必要なのだと思います。
OpenBCI GUIで測定したデータをMATLABにインポート

# 概要
OpenBCIを動作させるための標準アプリケーションOpenBCI GUIで測定した脳波データをMATLABにインポートし、EEGLABで波形表示する方法を説明する。

# 実行環境
- OpenBCI GUI v5.0.1
- OpenBCI Cyton bord
- MATLAB R2020b
- EEGLAB v2020.0
- Windows10 pro 19041

# OpenBCI GUIについて
OpenBCI GUIは、OpenBCIボードからのデータを視覚化、記録、およびストリーミングするためのアプリケーションである。
詳細・セットアップ方法については下記ページを参照のこと。
https://docs.openbci.com/docs/06Software/01-OpenBCISoftware/GUIDocs

# OpenBCI GUIで取得されるデータについて
収録開始ボタンは特になく、測定したデータがすべてドキュメントフォルダに日付をファイル名にしたテキストファイルで保存される。
サンプリングレートはシリアル接続の場合、8chで250Hz,16chでは125Hzとなる。
また、データは未加工のRAWデータでμV単位である。

# MATLABへの取り込み
MATLABを起動しホームメニューからインポートボタンを押下し読み込みたいデータのテキストファイルを指定する。
出てきたインポート画面から取り込む範囲を指定し出力タイプを**[数値行列]**に変更後**[選択のインポート]**ボタンを押下することでMATLABに変数として読み込まれる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/877480/01e4be20-b43c-33ec-ef69-aaf64f238206.png)


読み込まれたデータはEEGLABのフォーマットと行と列が逆のため以下のように行列を転置させる必要がある。
また必要に応じて単位変換等を行う。

```matlab:取得データを転置
rawdata = OpenBCIRAW20210127172329'
```

# EEGLABで波形表示
続いてデータをEEGLABで読み込み表示を行う。
EEGLABを起動し、以下のメニューから読み込み画面を開く。
**[File] -> [Import data] -> [Using EEGLAB functions and plugins] -> [From ASCII/float file or Matlab array]**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/877480/f43c917a-afe8-7de4-d51e-5e4defdd5425.png)
先ほどMATLAB で読み込んだ配列の変数名と周波数を指定してOkで閉じることでインポートが完了する。
RAWデータを読み込んだままの状態ではOpenBCI GUIで見えていた波形とは大きく異なる。
OpenBCI GUIで行っている後処理と同様に電源ノイズの除去とフィルタリング処理を行う必要がある。
（例えば5-50Hz範囲外を除去するようにローパス・ハイパスフィルターをかける等）
【jquery,js】HTMLタグを除去する [replace,val] [js05_20210223]


####  <font color='orange'>処理の概要</font>
html表示されたコードからhtmlタグを除去する

##### 処理のフロー：
　(1)実行ボタンを押下する
　(2)html表示されたテキストからhtmlタグを除去する
　(3)除去したテキストをテキスト2へ表示する

####  <font color='orange'>画面イメージ</font>


#####画像１
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647299/e87fd8d4-08e3-17ba-571d-edf26d989892.png" width="500px">

#####画像２
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647299/e41b128f-5853-573d-6dd1-ae80ad77575b.png" width="500px">


####  <font color='orange'>ソースコード</font>
```html:index.html
<body>
    <font color="blue">テキスト１</font><br>
    <textarea style="height: 11em;width: 60em;" id="userText">
        <h1>
            <a href="https;//www.google.co.jp/">タイトル</a>
        </h1>
        <br>
        <div>
            本文本文本文本文本文本文本文本
            <span class="hoge">本文。</span>
            本文本文本文本文本文本文本文本
        </div>
    </textarea>
    <br>
    <input type="button" id="execButton" value="実行">
    <br>
    <font color="blue">テキスト２</font><br>
    <textarea style="height: 11em;width: 60em;" id="output"></textarea>
</body>
```

```javascript:main.js
$(function(){
    $("#execButton").click(function(){ 
        var text = $("#userText").val();

        text = text.replace(/<.+?>/g, "");

        $("#output").val(text);
    });
});
```

####  <font color='orange'>ポイント</font>
html：
なし
js：
(1)replace関数の第一引数に正規表現を渡す。これを空白文字に置換する
(2)置換後の文字は、コードのとおりに表示される

####  <font color='orange'>参考資料</font>
JavaScript(仕事の現場でサッと使える！デザイン教科書)　p90
OpenGLの勉強～GLFW、GLEW

- OpenGL
    - プラットフォーム（windows, macOS, linux)に依存しない「グラフィックスAPI」
- OpenGLを使えるようにするツールキット
    - GLUT（初期の頃に作られたもので、長い間メンテナンスされていない
    - FLTK
    - SDL
    - Qt（初学者にはちょっと規模が大きい？）
    - GLFW（マルチプラットフォームで扱いやすい）
- GLFWの特徴
    - ダブルバッファリング
    - ポーリング方式、コールバック方式の両方に対応
    - マルチウィンドウに対応
    - GLUTで使えるCubeやSphereなどは使えない
   
- GLEWはツールキットではない
    - グラフィックスハードウェアの拡張機能を使用可能にするためのもの
    - windowsの場合、元々サポートしているバージョンが1.1のため、いくらGPUがそれ以上のスペックを持っていても新しい機能を使えない
    - GLEWを使えば、GPUに対応するバージョンに拡張することが可能


### 参考文献
- 「グラフィックス・アプリ」制作のためのOpenGL入門　床井浩平
ROSの勉強　第13弾：Teleop-bot ~ key driver ~

# #プログラミング ROS< key driver>

## はじめに
1つの参考書に沿って，ROS(Robot Operating System)を難なく扱えるようになることが目的である．その第13弾として，key driverを扱う．


## 環境
##### 仮想環境
|||
|:-:|:--|
|ソフト|VMware Workstation 15|
|実装RAM|2 GB|
|OS|Ubuntu 64 ビット|
|isoファイル|ubuntu-mate-20.04.1-desktop-amd64.iso|

##### コンピュータ
|||
|:-:|:--|
|デバイス|MSI|
|プロセッサ|Intel(R) Core(TM) i5-7300HQ CPU @ 2.50GHz 2.50GHz|
|実装RAM|8.00 GB (7.89 GB 使用可能)|
|OS|Windows (Windows 10 Home, バージョン：1909)|

##### ROS
|||
|:-:|:--|
|Distribution|noetic|
|プログラミング言語|Python 3.8.5|


## ロボットの操作
遠隔操作や自律システムなどがあるが，遠隔操作のほうが簡単であるため遠隔操作の学習から始める．ここで扱う遠隔操作はキー入力を用いるTeleop-botというものである．

## Teleop-botの速度コマンド
ロボットを操作するにあたって，速度コマンドをロボットに伝えなければならない．そのために2つのプログラムにより構成する．
**<プログラム①>**
キー入力を受け取り，それをメッセージとして配信する

**<プログラム②>**
①のメッセージを受け取り，レスポンスとして``Twist``メッセージを出す



##### ★ROSでのヒント
**小さなROSノードの集まりを作る**
　　ソフトウェアテストの作成を簡単にしてくれる
　　⇒1つ1つのノードはなるべく小さくする


## 実装
今回はプログラム①，すなわちkey driverの実装を行う．以下にソースコードとそのときの実行の様子を示す．ここでいうkey driverとは，key入力のPublisher（配信者）である．
##### ソースコード
```python:key_publisher.py
#! /usr/bin/env python3

import sys, select, tty, termios	#ターミナルでの作業に必要なPythonのライブラリ
import rospy
from std_msgs.msg import String		#文字列を扱うメッセージ


if __name__ == '__main__':
	key_pub = rospy.Publisher('keys', String, queue_size = 1)	#トピック配信の準備
	rospy.init_node("keyboard_driver")	#ノードの初期化
	rate = rospy.Rate(100)	#100Hz(0.01s)

	old_attr = termios.tcgetattr(sys.stdin)	#現在のコンソール設定を保存
	tty.setcbreak(sys.stdin.fileno())		#この2行により，ユーザがキーを押したときにすぐに標準入力として受け取れるようになった

	print("Publishing keystrokes. Press Ctrl-C to exit ...")

	while not rospy.is_shutdown():
		"""selectはすぐにリターンする．また0秒でタイムアウトするように設定している"""
		if select.select([sys.stdin], [], [], 0)[0] == [sys.stdin]:
			key_pub.publish(sys.stdin.read(1))	#読み込んだものをStringとして配信
		rate.sleep()

	termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_attr)	#コンソールを標準モードに戻してからプログラムを抜ける必要がある
```

##### 実行様子
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/9dc7a3b8-41c1-212e-39db-706e766d0cff.png)

## 感想
今回はTeleop-botの導入として，キー入力を即座に配信してくれるものを作成した．これは基本的なもので1文字ずつしか取り出せず，矢印キーのような特殊文字については別々に配信してしまう．もしそのような特殊文字を使うときには少し工夫が必要になってくる．なお，Telop-botでは特殊文字のキーは用いないため今回のもので十分であると思われる．

(2022/12/29：追記)
1文字ずつしか取り出せないと書いていたが，改めて追記しておく．
```python:
sys.stdin.read(1)
```
このとき引数に1としているため，1文字しか取り出せない．
この引数が読み取る文字数を設定する．つまり，任意の文字数にすることも可能である．
ちなみに引数に何も渡さない場合，入力を全て1つの文字列として取得する．

＜参考＞

https://yu-nix.com/archives/python-std-in-out-err/#sys.stdin%E3%81%A7%E6%A8%99%E6%BA%96%E5%85%A5%E5%8A%9B%E3%82%92%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%82%80

## 参考文献
プログラミングROS Pythonによるロボットアプリケーション開発
　　　　　　　　Morgan Quigley, Brian Gerkey, William D.Smart 著
　　　　　　　　　　　　　　　　　　　　　　　河田　卓志　監訳
　　　　　　　　　　  　松田　晃一，福地　正樹，由谷　哲夫　訳
　　　　　　　　　　　　　　　　　　オイラリー・ジャパン　発行

https://yu-nix.com/archives/python-std-in-out-err/#sys.stdin%E3%81%A7%E6%A8%99%E6%BA%96%E5%85%A5%E5%8A%9B%E3%82%92%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%82%80
Pythonでiniファイルを読み込むライブラリ「configparser」


Pythonのライブラリ「configparser」について、備忘のために示す。

# 実行環境

Python 3.7.3
Mac OS 10.15.5

# 設定ファイル(iniファイル)

iniファイルとは設定ファイルのことで、設定値を "キー=値" の形式で書き記しておき、コードを実行するときに読み込ませて利用するファイルである。

設定ファイルの形式は以下の通り。

```
[セクション名1]
キー1=値1
キー2=値2
・・・

[セクション名2]
キー3=値3
・・・
・・・
```

セクション毎に区切り、その中にキーと値の組み合わせを書いていく。
セクションは何個書いても良い。

シェルスクリプトなどでは単純にこのiniファイルを実行すれば値を読み込めるが、Pythonでは専用のライブラリがあり、それが「configparser」である。

# configparserモジュール

この設定ファイルに対し、configparserを使って読み込みを行ってみる。

まずは、python内でconfigparserをインポートし、configparserオブジェクトを生成する。

その次に、この変数を使って設定ファイルを読み込む。

```python
import configparser

#ConfigParserオブジェクトを生成
config = configparser.ConfigParser()

#設定ファイル読み込み
config.read('iniファイルのパス')


```

設定ファイルを読み込むと、変数には設定ファイルの内容が入る。

例として、以下のような設定ファイル(test.ini)があったとする。

```test.ini
[KEY-VALUES]
KEY1=VALUE1
KEY2=VALUE2
KEY3=VALUE3

[TEST]
TEST_KEY1=TEST_VALUE1
TEST_KEY2=TEST_VALUE2
TEST_KEY3=TEST_VALUE3

```


このファイルをpythonで読込む。(test.iniと同じフォルダで実行)

```python
>>> import configparser
>>> config = configparser.ConfigParser()
>>> config.read('test.ini')
```


すると、設定ファイルの内容が変数に"ConfigParser"クラスのオブジェクトとして入る。

```python
>>> type(config)
#<class 'configparser.ConfigParser'>
```

このConfigparserオブジェクトから設定ファイルの具体的な内容を取り出す方法についてだが、
辞書と同じ様に

```
configparserオブジェクト[セクション名][キー名]
```

の形式で取り出せる。
また、関数**sections()**でセクションのリストを表示できる。使用例は以下の通り。

```python
>>> #セクション名のリスト
>>> config.sections()
['KEY-VALUES', 'TEST']
>>> 
>>> #値の取り出し
>>> config['KEY-VALUES']['KEY1']
'VALUE1'
>>> 
>>> config['TEST']['TEST_KEY1']
'TEST_VALUE1'
>>> 
```
Windows PowerShellでAWS CLIのコマンド短縮

Windowsで`aws cli`のDockerを使用するパターンのPowershellでのコマンド短縮方法を記載します。公式にはdoskey(コマンドプロンプト)を使用した方法が記載されています。

[Docker コマンドの短縮](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/install-cliv2-docker.html#cliv2-docker-aliases)

# Aliasに設定します

プロファイルファイルを開きます。
もしファイルがない場合、`New-Item -type file -force $profile`で新規作成します。

```powershell
PS C:\> notepad $profile
```

以下を記入します。作成する関数名は任意です。

```
function CustomAawsCli {docker run --rm -it -v $env:userprofile\.aws:/root/.aws -v ${PWD}:/aws amazon/aws-cli $args}
sal aws CustomAawsCli
```

`aws`でコマンドが使用できるようになります。

```powershell
PS C:\> aws --version
aws-cli/2.1.27 Python/3.7.3 Linux/4.19.121-linuxkit docker/x86_64.amzn.2 prompt/off
```

# 参考記事

[今すぐalias登録すべきPowerShellワンライナー](https://qiita.com/mu_sette/items/3954759daee8ae9ad26f)
みんなのiOS講座 ゼロからSwiftで学ぶiPhoneアプリ開発の基礎：作業メモ④

本日も[みんなのiOS講座 ゼロからSwiftで学ぶiPhoneアプリ開発の基礎](https://www.udemy.com/course/ios-apps/)の学んだことメモ。
Swiftの基礎の続き。


#クラスとインスタンス

- クラスを用いることで、変数や関数をひとまとめにすることができる。
- クラスの中に書かれた関数のことを**メソッド**という。

```
class Dog {
    var name = ""
    func bark() {
        let message = name + ": Bow-wow!"
        print(message)
    }
}
```

クラスを作る。


- 外部から変更可能な変数のことをプロパティという。

```
let pochi = Dog()
pochi.name = "Pochi"
pochi.bark()
```

この場合、nameを変更しメソッドが実行された結果、```Pochi: Bow-wow!```が出力される。
このようにクラスからインスタンスを生成し、プロパティやメソッドを使用することができる。
インスタンスは複数生成可能で、各インスタンスには異なるプロパティを持たせることができる。


#インスタンスプロパティと型プロパティ

- クラスに記述可能なプロパティは大きく分けて、インスタンスプロパティと型プロパティがある
- クラスの中に変数を書けばインスタンスプロパティとなる
- インスタンスプロパティにはインスタンスを生成してからアクセスする。

```
class Dog {
    var name = ""
}

let pochi = Dog()
pochi.name = "Pochi"
pochi.name
```


- 一方で型プロパティにはインスタンスを生成せずにアクセスすることができる。
- 型プロパティの場合には、 ```static```を先頭に記述する。
- インスタンスを生成しなくても、クラス名からプロパティにアクセスできる。

```
class Dog {
    var name = ""
    static var breeed = ""
}

Dog.breeed = "Akitaken"
Dog.breeed
```

この場合、インスタンスを生成しなくても```Akitaken```が出力される。
インスタンスプロパティ、型プロパティを使用するのは状況によって変わる。


#インスタンスメソッドと型メソッド

- インスタンスメソッドはインスタンスを生成してからアクセスできる。
- 型メソッドはクラスからメソッドにアクセスできる。

```
class Dog {
    func bark() {
        print("Bow-wow!")
    }
}

let pochi = Dog()
pochi.bark()
```

この場合```Bow-wow!```が出力される（インスタンスメソッド）。


```
class Dog {
    func bark() {
        print("Bow-wow!")
    }
    
    static func barkStatic() {
        print("Bow-wow-wow!")
    }
}

Dog.barkStatic()
```

この場合、```Bow-wow-wow!```が出力される（型メソッド）。



#メモ
クラスとインスタンスこういう風に使われるのか〜〜と感じた（具体的なイメージはいつも通り湧いていない）。
ERMaster 使用時に知っておきたい用語集

#【ERMaster 使用時に知っておきたい用語集】

##ERMaster

ER図を作成するためのEclipseのプラグイン。
直感的で分かりやすいUIであり、DBのテーブル項目や属性の設定、テーブル属性などが設定可能。
Excel形式出力、DDL出力、その他さまざまな機能を持っている。

　※ER図とは、テーブルとテーブル間の関連を線で結んで、DBを分かりやすく表現した図のこと。

##ERMaster使用時に出てくる基本的な用語

###・物理名

プログラムにおけるコンピューター向けの名称、DBがテーブルを特定する識別に使用される。

###・論理名

プログラムにおける人間向けの名称、ユーザが作成したアプリケーションのインターフェースなどで表示される。

###・スキーマ

オブジェクトに関する定義情報のこと。
どのオブジェクトがどの属性を使用しているかを関連付けて管理し、オブジェクトの作成時などにスキーマの情報が参照される。

###・パーティション

DB内の論理的な仕切りのこと。
HDD内部の領域を論理的に分割、また分割されている領域のこと。
分割管理することで問題が生じた際に被害を小さくする。また、使用効率の向上にもなる。

###・インデックス

DBのテーブルへの検索処理を高速化させるもの。
テーブルのデータを更新すると、インデックス側の索引用のデータの更新が必要になるため、データの追加・更新・削除時の処理速度が低下するデメリットがある。

###・主キー

テーブルに登録するレコードの全体のうち、ひとつのデータに特定することをDBが保証する列のこと。

主キーは、テーブル検索のスピードを格段に早くする。
テーブルデータの整合性を保証する。

<strong>主な制約の種類</strong>
・一意制約：データに重複がなく、必ず一意である必要がある。
・NOT NULL制約：NULLを許可しない。

###・複合主キー

DBのテーブルに設定される主キーを複数カラムを組み合わせとして定義すること。

1つのカラムではなく、複数カラムを主キーとして組み合わせ、レコードを一意にすることも可能。

###・外部キー

関連するテーブル間の整合性を保ちたい列に設定するDBの重要な機能のこと。
データの整合性をDBに保証させるために利用する。

外部キーを設定すると、親テーブルに存在しない値を登録した場合にはエラーになる。
子テーブルに値が存在する、親テーブルのレコードを削除しようとするとエラーとなるため削除できない。

<strong>データ削除、更新時のふるまい</strong>
・データ削除時のふるまい：ON DELETE
・データ更新時のふるまい：ON UPDATEで設定する。
固定メニュークリックでyoutubeポップアップ

```main.html
<head>
<!--youtubeポップアップ-->
<link rel="stylesheet" type="text/css" href="src/css/lightcase.css">
<script type="text/javascript" src="src/js/lightcase.js"></script>
</head>


<body>
		<div class="link_youtube">
			<a data-rel="lightcase" href="https://www.youtube.com/embed/Yx3C7hegG6M?rel=0">
				<img src="img/rabbit.png" alt="">
			</a>
		</div>


</div><!-- //#main -->
<script type="text/javascript">
	jQuery(document).ready(function($) {
		$('a[data-rel^=lightcase]').lightcase({
	transition: 'fade',
	showSequenceInfo: false,
	showCaption: false
}
		);
	});
</script>


</body>
```


ありがとうございます！
https://creative-rush.site/lightcase/

大元
https://cornel.bopp-art.com/lightcase/
1か月半の試験勉強で AWS 認定 SysOps アドミニストレーター(SOA) に合格した話

AWS SAA,DVAを取得できたエンジニアが
1か月の試験対策でAWS SOA(SysOPs)に合格できた話です。
個人的な経験ですが備忘録として投稿いたします。
ちょっとは、役に立てばうれしいです。

# 試験概要
AWS SOAについては、他の方が説明されていたり、AWS HPに記載されているので詳細までは省略させて頂きます。
概要として、下記確認されると良いかと思います。
AWS公式が示す試験ガイドです。
https://d1.awsstatic.com/ja_JP/training-and-certification/docs-sysops-associate/AWS-Certified-SysOps-Administrator-Associate_Exam-Guide.pdf

注)SysOpsについてはAWSより新しい試験がアナウンスされております。
https://aws.amazon.com/jp/certification/coming-soon/
新しい試験: AWS 認定 SysOps アドミニストレーター – アソシエイト (SOA-C02)
※本記事は、現行のSOA-C01に関する内容です。

# [参考]SAA,DVA取得時の記事
[AWS SAA取得時の話](https://qiita.com/pkopko-b8/items/3bfd8ccdbbc9baadbffe)
[AWS DVA取得時の話](https://qiita.com/pkopko-b8/items/ebd4965ce4160df1e28e)

# 試験結果
アソシエイト3種類の中で一番ギリギリな合格点となりました。
スコアにも表れているように、3種類の中で一番難しく感じました。
![スクリーンショット 2021-02-22 21.59.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513502/2cb64f0f-b35f-6917-d251-5f42d7de7c7d.png)

難しく感じたと思う理由：
・普段の業務でAWSの運用面経験が少ない
⇨AWSの運用面よりサービス実現に取り組む時間のほうが多く、結果、経験の差が出たと感じた。
⇨リージョンをまたぐバックアップなど、グローバルな運用方法についてイメージが沸いていなかった。

# 背景
## 経歴
　組込系（ARMアーキテクチャ）エンジニアとして働いています。
　IoT機器のアプリケーション開発、ネットワーク環境構築がメインの業務としてます。
　また、AWSを使用した、IoT機器の保守システム開発などをしてきました。

## 受験きっかけ
　このご時世、年末年始に時間があったので、AWS DVA取得をしようと思い、取得することができました。
CDF、SAA、DVA取得できたため、アソシエイト3種類レベルは取ってしまおうと思い受験いたしました。
前回、1/5にDVA取得後、SOAへの勉強を始めたので、1ヶ月半の期間で取得することができました。

# 取り組んだこと
今まで、SAA/DVAではUdemyによるオンライン学習を主として勉強をしておりました。
しかし、今回は、別な取り組みとして、単にSOAへの試験問題対策ではなく、AWSサービスの理解を進めるために、別な手段で試験勉強をすることにしました。
※単に試験に受かるだけなら、Udemyの問題を解くなど、試験対策をしたほうが良いように思えました。
　なので、SOAのスコアがアソシエイトで一番低かったのかもしれません・・・
　（AWSサービスへの理解のためと思えば、無駄ではなかったと思いたいです！）

##（１）本による"試験対象サービスの知識習得"
　SAA、DVA試験用にすでに購入していた本でした。
　そのため、SOAが対象としている章(サービス)を確認のために一読いたしました。
　対象サービスで使用のキーワードを理解することを目的としました。
　[AWS認定アソシエイト3資格対策～ソリューションアーキテクト、デベロッパー、SysOpsアドミニストレーター](https://www.amazon.co.jp/dp/B07TT1N73K/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)

## 以下、今までとは異なる取り組みを試みました。

##（２）AWS公式のトレーニングライブラリを使う
やはり、公式が出しているものを活用としようと思い、まずは、トレーニングライブラリで、
SOAがどういった試験なのかを確認しました。1.5時間の動画、日本語訳があるため、
気軽にInputでき、おすすめだと思います。
https://www.aws.training/Details/Video?id=41299
・Exam Readiness: AWS Certified SysOps Administrator - Associate (Japanese)

##（３）AWSが提供するサンプル問題集を確認
下記で、10問のサンプルがあり、一度解いてみました。
https://d1.awsstatic.com/ja_JP/training-and-certification/docs-sysops-associate/AWS-Certified-SysOps-Administrator-Associate_Sample-Questions.pdf
⇨本番の問題よりも易しく感じました。
（ここで、8問正解だったので、気が緩んでしまったかもしれません。）

##（4）AWS公式YouTubeで該当サービスのBlackBeltを見る
[Amazon Web Services Japan 公式](https://www.youtube.com/channel/UCnjKWUK2t5QJYfeqqilhJhQ)
SOAでは以下のサービスが特に問われていると感じました。
・AWS Auto scalling
⇨EC2だけではなくELBとの絡めた使い方を理解する
・Route53
⇨DNSサービスだけの理解ではなく、他サービスとの連携を理解する
・AWS Organizations
⇨アカウントをまたぐサービス参照やコスト管理について理解する
・CloudWatch/CloudTrail
⇨サービスのモニタリングや問題発生時、サービスを用いてどんな原因が考えられるかを理解する
・セキュリティ（特定のサービスではなく全般的に）
⇨外部ネットワークの危険に晒されることなく、セキュリティが確保された中での
　サービス連携の方法を理解する

# 感想
前述した内容と重複いたしますが、試験に受かることに重きを置くのであれば、Udemyや他の問題集をしたほうが試験慣れはすると感じました。今回は、問題対策よりもAWS公式提供のものを使用したため、試験中、問題の意図を理解するのに時間が掛かりました。

以上です。
【PHP】PHPでメソッドチェーンを実装する

# はじめに
Laravelとかクエリビルダを使っていると、以下ようなのコードをよく見かけると思います。

```php
$user = DB::table('users')
            ->where('name', 'John')
            ->first();
```


こちらのコード、大変読みやすくないですか？？
``users``テーブルの``name``が``John``のレコードの1つを所得するというのが、直感で理解できます。
「呼び出し元が見やすいことコードを書くように心がけたい。」そう感じている、Webエンジニア2年生なのです。


# メソッドチェーン
今日は、``->``を使ってメソッドチェーンを実装しようというお話です。

```php:Calculator.php
class Calculator {

    private $result;

    public static function create(int $int): Calculator {
        return new Calculator($int);
    }

    private function __construct(int $int) {
        $this->result = $int;
    }

    public function plus($int): Calculator {
        $this->result += $int;
        return $this;
    }

    public function minus($int): Calculator {
        $this->result -= $int;
        return $this;
    }

    public function getResult(): int {
        return $this->result;
    }
}
```

```php:main.php
$result= Calculator::create(10)
                    ->plus(5)
                    ->minus(7)
                    ->getResult();
var_dump($result); // int(8)
```

## ポイント
-  ``plus()``, ``minus()``関数内で``return $this``をしている。つまり自身のインスタンスを返却している。
-  ``getReasult()``関数で、プロパティを返却している。

## メリット
-  呼び出し元のコードが読みやすくなる。

## どんな時に使うのか
-  ある値に対して、同属の処理を行いたい時。今回でいうと、``plus()``, ``minus()``。

## 補足
-  ``create()``を``static``にし、その関数内で``new``をすることで、呼び出し元で``new``をしなくて良くなるため、可読性が上がる
-  ``__constructor``を``private``することで、呼び出し元で``new``できなくしている
絶対パスの取得には realpath を使おう

bash のスクリプトで絶対パスを取得するときはどうするんだっけ？
などと思って、Google検索などをすると、cd して pwd するスクリプトを紹介する古い記事が上位にヒットする。
以下は、実行した shell スクリプト（この場合は bash）が置かれているディレクトリを変数DIRにセットする例。

```bash:スクリプト例
DIR=$(cd $(dirname $0); pwd)
```

古いディストリビューションを使わざるをえない場合や、実行環境に依存しないスクリプトを書かなければいけない場合にはこの方法もいいだろうが、最近のディストリビューションには普通に realpath というコマンドがインストールされているはずなので、こちらを使いましょう。

```bash:realpathを使った例
DIR=$(realpath $(dirname $0))
```

[GNU coreutils](https://www.gnu.org/software/coreutils/) に含まれているものなので、RedHat系でも Ubuntu でも最小構成のインストールに含まれているはず。


```text:
Usage: realpath [OPTION]... FILE...
Print the resolved absolute file name;
all but the last component must exist

  -e, --canonicalize-existing  all components of the path must exist
  -m, --canonicalize-missing   no path components need exist or be a directory
  -L, --logical                resolve '..' components before symlinks
  -P, --physical               resolve symlinks as encountered (default)
  -q, --quiet                  suppress most error messages
      --relative-to=DIR        print the resolved path relative to DIR
      --relative-base=DIR      print absolute paths unless paths below DIR
  -s, --strip, --no-symlinks   don't expand symlinks
  -z, --zero                   end each output line with NUL, not newline

      --help     display this help and exit
      --version  output version information and exit

GNU coreutils online help: <https://www.gnu.org/software/coreutils/>
Full documentation at: <https://www.gnu.org/software/coreutils/realpath>
or available locally via: info '(coreutils) realpath invocation'
```

pwd を使うスクリプトの場合は、実在するディレクトリじゃないと駄目ですが、realpath ならオプションの指定で実在しないディレクトリも指定できます。デフォルトでは実在しないディレクトリではエラーを返します。
【Laravel初心者】投稿者かどうかによって表示を変える

Laravel初学者です。
オリジナルアプリを作成しているのでその過程を記事にしています。

理解が曖昧なところも多いため、ご指摘等ありましたらご連絡いただければ幸いです。

今回は詳細画面にて`投稿者のみ編集と削除のボタンが表示される`という実装について備忘録のため残します。



## 環境

|                | Version     |
|:---------------|------------:|
| PHP            | 7.4.14      |
| Laravel        | 8.24.0      |
| mysql          | 8.0.23      |
| docker         | 20.10.2     |
| docker-compose | 1.27.4      |


## コントローラー

```PHP:app/Http/Controllers/GameController.php

$user_id = Auth::id();

```

私の場合は`showアクション`で表示する画面で投稿者かどうかの条件分岐を入れたかったのでshowアクションに上記の記述をしました。


## ビュー

```PHP:
@if ($user_id == $game->user_id)
  <div class="mb-4 text-center" style="margin-top:10px">
    <a href="{{ route('game.edit', $game->id) }}" class="btn btn-primary">
      編集する
    </a>
    <form
      style="display: inline-block;"
      method="POST"
      action="{{ route('game.destroy', $game->id) }}"
     >
     @csrf
     @method('DELETE')
     <button class="btn btn-danger">削除する</button>
     </form>
   </div>
@endif
```

上記のように

```
@if ($user_id == $game->user_id)
```

で現在のログインユーザーのidと投稿($game)のuser_idが一致する場合は編集と削除の表示が出るように条件分岐しました。

以上です。
Rust sdl2 crate 自分用インストール備忘録（Windows）

# この記事は
WindowsでRustの`sdl2`クレートを使うために、[SDL](https://www.libsdl.org/download-2.0.php)からSDL2-devel-2.0.x-VC.zipをダウンロード（間違ってSDL2-2.0.x.zipを落として来るなよ（一敗））したものの、`sdl2`の[Readme.md](https://github.com/Rust-SDL2/rust-sdl2)で指示された場所にファイルを設置しても

```shell
LINK : fatal error LNK1181
```

を吐き続けた。
その後、色々試した結果うまくいく場所を見つけたので、備忘録として残しておく。

# 注意
この記事の内容は。「よくわかんないけど動きました」的なことなので、全く再現性はとれていない。しかし、私とあなたの環境でくらいなら上手くいくかもしれない。

# 環境
OS: Windows 10
rustc: 1.46.0
Rustのインストールフォルダ: C:\Rust

# 結論
Rustをインストールした場所の

```
\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib
```

に、SDL2.dll, SDL2.lib, SDL2main.lib, SDL2test.lib を置くべし。
つまり私の環境では

```
C:\Rust\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib
```

になるわけやね。
ActiveHashについて

オリジナルアプリ作成中に、ActiveHashを導入し実装したので
忘れないため記事にしたいと思います。

## ActiveHashとは?

まず、ActiveHashとは、変更されないデータをモデルファイル内に直接記述することで、データベースへ保存せずにデータを取り扱うことができるGemです。
例えば、都道府県などは変更されることはありませんよね。
そういったデータをデータベースではなくモデルで管理しようというものです。

私の開発したオリジナルアプリの部分ですと下記の画像の部分になります。
[![Image from Gyazo](https://i.gyazo.com/6b5067f8bacc5a7bafbcec7a6482cd93.gif)](https://gyazo.com/6b5067f8bacc5a7bafbcec7a6482cd93)

「文章問題」と「写真にタイトルをつけてください」の部分をActiveHashを使用しました。

## 導入の仕方

まずは、gemfileに下記を記述します

Gemfile

```
gem 'active_hash'
```

そして、ターミナルより

```
bundle install

```

サーバーを起動していたら、再起動させます。

これで、導入は完了です。

## モデルとデータベースを作成しよう。

先ほどの画像の情報は、postモデルを作成しデータベースに保存しています。
まず、postモデルを作成します。

```
% rails g model post

```

作成が済んだら、データベースに記述します。

```
class CreatePosts < ActiveRecord::Migration[6.0]
  def change
    create_table :posts do |t|
      t.string     :title
      t.string     :sentence,       null: false
      t.integer    :genre_id,       null: false
      t.references  :user,           foreign_key:true
      t.timestamps
    end
  end
end

```
注目するところは、下記の部分です。

```
t.integer    :genre_id,       null: false
```

カラム名にidをつけて、カラムの型はinteger型でを指定します。
記述を行ったら

```
% rails db:migrate
```

これで、データベースの設定は完了です。


## Genreモデルの作成

次にgenreモデルを作成し保存する内容を記述します。

```
% rails g model genre
```

そして、作成したモデルないに下記の記述を行います。

```
class Genre < ActiveHash::Base
  self.data =[
   { id: 1, name: '--' },
   { id: 2, name: '文章問題' },
   { id: 3, name: '写真にタイトルをつけてください' },
 ]
  
end
```
まずは、モデルの「Genreクラス」を定義し、ActiveHash::Baseクラスを継承します。
ActiveHash::Baseは、あるモデル内（クラス内）でActiveHashを用いる際に必要となるクラスです。ActiveHashのGemに定義されています。
また、ActiveHash::Baseを継承することで、ActiveRecordと同じようなメソッドを使用できるようになります。

そして、保存したいものに番号をつけてその番号をデータベースで管理します。

## アソシエーションの設定

postモデルに下記を記述します。

```
extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to :genre
```

投稿するものは、1つのジャンルに紐付いています。そのため、Articleモデルにはbelongs_toを設定します。
また、設定するには、extend ActiveHash::Associations::ActiveRecordExtensionsの記述も必要です。

## バリデーションの設定

次にバリデーションの設定を行います。

```
validates :genre_id, numericality: { other_than: 1, message: 'Select'}
```
これは、IDが「1」の時は保存できないよという意味です。
今回IDが1の時は、「--」が設定されているので、バリデーションの記述を行いました。

## ビューの記述

最後にビューでの記述です。

```
<%= f.collection_select(:genre_id, Genre.all, :id, :name, {}, {class:"select-box"}) %>
```
引数の内容は下記になります。

```
<%= form.collection_select(保存されるカラム名, 配列データを指定する, カラムに保存される項目, 選択肢に表示されるカラム名, オプション, htmlオプション) %>
```

第1〜第4引数の設定は必ず必要です。



以上が、ActiveHashの設定方法です。
まだまだ、初心者で間違いがあるかもしれません。
なにかございましたら、ご指摘いただければ幸いです。
VCVのPlugin Development Tutorialを試してみた。

[VCV](https://vcvrack.com) の [Plugin Development Tutorial](https://vcvrack.com/manual/PluginDevelopmentTutorial) をWindows10+MSYS2で試してみた。
　1. [VCV RACK ver1.1.6](https://vcvrack.com/)をインストール。
　2. MSYS2は、msys2-x86_64-20210105を使用した。適当な場所に置く。
　3. 開発環境をpacmanを使って構築
　　　pacman -Syu
　　　pacman -Su git wget make tar unzip zip mingw-w64-x86_64-gcc mingw-w64-x86_64-gdb  \
　　　mingw-w64-x86_64-cmake autoconf automake mingw-w64-x86_64-libtool mingw-w64-x86_64-jq python
             
　4. [Rack-SDK-1.16](https://vcvrack.com/downloads/Rack-SDK-1.1.6.zip)を落とし、MSYS2の /home/user_name/Rack-SDK に展開。
　5. RACK_DIR=/home/user_name/Rack-SDK を設定する。
　6. $RACK_DIR/helper.py createplugin MyPlugin　を実行し　フォルダ MyPlugin が作られる。
　7. 質問を適当に答えていくと、plugin.jsonが作られる。
　8. Makefileも作られるので、一旦、makeでエラーなく終了することを確認する。
　9. ~/Rack-SDK/MyPlugin/resの元に、[MyModule.svg](https://vcvrack.com/manual/_static/MyModule.svg)を置く。
　10. cd ~/Rack-SDK
　10. $RACK_DIR/helper.py createmodule MyModule res/MyModule.svg src/MyModule.cpp を実行する。
　11. cd ~/Rack-SDK/src にMyModule.cppが作られる。
　12. MyModule.cpp plugin.cpp plugin.hpp を下記のように編集する。
　13. make
　14. make dist
　15. make install
　16. VCVを立ち上げると、MyPluginが認識される。
　17. 認識されない場合は、Help->Open user folder で開いた場所のlogを見て。
　
        MyModule.cpp 

```c++


	MyModule() {
		config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
		configParam(PITCH_PARAM, 0.f, 1.f, 0.f, "");
	}

	float phase = 0.f;
	float blinkPhase = 0.f;

	void process(const ProcessArgs& args) override {
		// Compute the frequency from the pitch parameter and input
		float pitch = params[PITCH_PARAM].getValue();
		pitch += inputs[PITCH_INPUT].getVoltage();
		pitch = clamp(pitch, -4.f, 4.f);
		// The default pitch is C4 = 261.6256f
		float freq = dsp::FREQ_C4 * std::pow(2.f, pitch);

		// Accumulate the phase
		phase += freq * args.sampleTime;
		if (phase >= 0.5f)
			phase -= 1.f;

		// Compute the sine output
		float sine = std::sin(2.f * M_PI * phase);
		// Audio signals are typically +/-5V
		// https://vcvrack.com/manual/VoltageStandards.html
		outputs[SINE_OUTPUT].setVoltage(5.f * sine);

		// Blink light at 1Hz
		blinkPhase += args.sampleTime;
		if (blinkPhase >= 1.f)
			blinkPhase -= 1.f;
		lights[BLINK_LIGHT].setBrightness(blinkPhase < 0.5f ? 1.f : 0.f);
	}
 };

```

plugin.cpp 

```c++
#include "plugin.hpp"


Plugin* pluginInstance;


void init(Plugin* p) {
	pluginInstance = p;

	// Add modules here
	p->addModel(modelMyModule);

	// Any other plugin initialization may go here.
	// As an alternative, consider lazy-loading assets and lookup tables when your module is created to reduce startup times of Rack.
}     

```

plugin.hpp

```c++
#pragma once
#include <rack.hpp>


using namespace rack;

// Declare the Plugin, defined in plugin.cpp
extern Plugin* pluginInstance;

// Declare each Model, defined in each module source file
extern Model* modelMyModule;

```
PyTorch Lightningで予測時に"Missing key(s) in state_dict: ..." のエラーが出た時の対応メモ

#はじめに
PyTorch Lightningで保存されたモデルを使って予測をしようとした時に、```Missing key(s) in state_dict:...```のエラーが出てハマった話


# コードとエラー内容
## コード
```python
model = GraphConvModel.load_from_checkpoint(args.model)
```

## エラー
```
    model = GraphConvModel.load_from_checkpoint(args.model)
  File "C:\Users\kimisyo\.conda\envs\OpenChem\lib\site-packages\pytorch_lightning\core\saving.py", line 158, in load_from_checkpoint
    model = cls._load_model_state(checkpoint, strict=strict, **kwargs)
  File "C:\Users\kimisyo\.conda\envs\OpenChem\lib\sitepackages\pytorch_lightning\core\saving.py", line 204, in _load_model_state
    model.load_state_dict(checkpoint['state_dict'], strict=strict)
  File "C:\Users\kimisyo\.conda\envs\OpenChem\lib\site-packages\torch\nn\modules\module.py", line 1052, in load_state_dict
    self.__class__.__name__, "\n\t".join(error_msgs)))
RuntimeError: Error(s) in loading state_dict for GraphConvModel:
        Missing key(s) in state_dict: "graph_conv_layer_list.1.bias","graph_conv_layer_list.1.self_activation.weight", "graph_conv_layer_list.1.degree_liner_layer_list.0.weight","graph_conv_layer_list.1.degree_liner_layer_list.1.weight","graph_conv_layer_list.1.degree_liner_layer_list.2.weight", "graph_conv_layer_list.1.degree_l

(以下略)
```

#想定される原因
モデル(pl.LightningModuleを継承して作成したもの) 学習時に、隠れ層の数やサイズをコンストクタの引数で与えていたが、```load_from_checkpoint```では、**デフォルト引数でインスタンス化したモデルに対して重みがロードされる**ことが原因と考えられる。

#対策
当初は、モデルを構築時と同じ条件でインスタンス化し、そのインスタンス(例えばmodel)に対して以下のようにload_model_checkpointを呼び出せばよいかと思ったが、解消されず。


```python
model.GraphConvModel.load_from_checkpoint(args.model)
```


色々調べた結果、以下のようにload_from_checkpointの引数に、**Modelのインスタンスに与えたい引数を指定**したところ解決。

```python
model = GraphConvModel.load_from_checkpoint(args.model,
    atom_features_size=62,
    conv_layer_sizes=[20,20,20],
    fingerprints_size=50,
    mlp_layer_sizes=[100, 1]
)	
```

今回はPyTorch Lightningに特化して書いたが、PyTorch Lightningを使わないケースでも、load_from_checkpointを使ってモデルをロードする場合、注意が必要と思われる。

# 参考
https://pytorch-lightning.readthedocs.io/en/0.8.5/weights_loading.html
ポートフォリオ作成手順

テーマを決める
実装する機能と使用技術を決める(機能の実装は3段階程度に分ける想定で)
設計する
第1段階の開発
テストを書く
UI/UXをブラッシュアップする
第2段階の開発
第3段階の開発

注意点
第1段階として必須機能や簡単な機能から実装を開始して、
十分に開発に慣れてから、
次の段階で付加的な機能や難易度の高い機能を実装したり、AWS等のやや高度の技術な導入していく
「難しいことを同時にやらない」「変更は一度に一つまで」

「ポートフォリオのテーマと実装する機能一覧」が決定した後には「ポートフォリオの事前レビュー」
「設計作業」が終わった後には「メンターさんからのビデオチャットでのアドバイス」
「第一段階の機能をある程度実装した段階」で「コードレビュー」
dlibとOpenCVのそれぞれで顔検出した結果比較

## はじめに
google-image-downloadで取得した画像ファイルから、学習用の顔画像をファイルに保存するために、OpenCVのHaarCascadeとdlibのface Detetor(HOG)を試して、性能を比較してみました。

## 開発環境
Ubuntu 18.04.4 LTS
Python 3.6.9
opencv 4.5.1
dlib 19.21.1

## 比較結果
|  |入力画像ファイル数|正しく検出した顔の数|誤検出した数|処理時間|
|---|---|---|---|---|
|OpenCV HaarCascade|468  |278  |8|real	0m28.000s|
|dlib Face Detector(HOG)|468  |841| 9  |real	9m43.149s|
入力画像に含まれている顔の数は様々です。
誤検出したどうかは、切り出し後の画像を目視して確認しました。

- こちらが検出前のダウンロード画像の一部
![切り出し前.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1141413/e1a74ab4-fae8-ee6c-d099-163d3d54ef39.jpeg)

- こちらが検出後に保存した画像の一部
![切り出し後.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1141413/0d6f561b-77cd-921d-7e5f-9536110a67bb.jpeg)

## ソースコード
```python

#!/usr/bin/env python3

import cv2
import dlib
import sys
import os
import argparse
import logging

logger = logging.getLogger()

SAVED_IMAGE_SIZE = (200, 200)

class faceDetector:
	pass

class HaarDetector(faceDetector):
	def __init__(self):
		self.__detector = cv2.CascadeClassifier('./cascades/haarcascade_frontalface_default.xml')
	def run(self, img):
		return self.__detector.detectMultiScale(img, 1.08, 5, minSize=SAVED_IMAGE_SIZE)
	def getVertexes(self, face):
		(x, y, w, h) = face
		return (x, y, w, h)

class HogDetector(faceDetector):
	def __init__(self):
		self.__detector = dlib.get_frontal_face_detector()
	def run(self, img):
		return self.__detector(img, 1)
	def getVertexes(self, face):
		x0 = max(0, face.left())
		y0 = max(0, face.top())
		x1 = max(0, face.right())
		y1 = max(0, face.bottom())
		return (x0, y0, x1-x0+1, y1-y0+1)
```
OpenCV HaarCascadeとglib face detectorのインタフェース差異を吸収するためにfaceDetectorクラスを作成しました。
以下の関数で、入力画像ファイルから顔認識を行い、認識した領域をファイルに保存します。

```python

def detectAndSaveFace(input_dir, output_dir, useHaar):
	logging.basicConfig(level=logging.INFO, format='%(message)s')

	if useHaar:
		detector = HaarDetector()
	else:
		detector = HogDetector()

	files_processed = 0
	faces_detected = 0

	for filename in os.listdir(input_dir):
		orig_img = cv2.imread(os.path.join(input_dir, filename), cv2.IMREAD_GRAYSCALE)	
		if orig_img is None:
			logger.warning('ignoring {0}'.format(filename))
			continue

		faces = detector.run(orig_img)
		logger.debug('Detected({0}) in {1}'.format(len(faces), filename))
		files_processed += 1

		# Save the detected bounding boxes
		for face in faces:
			(x, y, w, h) = detector.getVertexes(face)
			face_img = cv2.resize(orig_img[y:y+h, x:x+w], SAVED_IMAGE_SIZE)
			face_filename = '{0}/{1}.pgm'.format(output_dir, faces_detected)
			cv2.imwrite(face_filename, face_img)
			faces_detected += 1

	logger.info('files processed = {0}, faces detected = {1}'.format(files_processed, faces_detected))
```

## 余談
正面を向いた顔画像を保存したかったので、dlibのCNNは試しませんでした。
dlibで検出した画像範囲の座標がマイナスになる場合がありました。

## 最後に
dlibのHOGによる検出精度が良いのは想定通りでしたが、私のPCでは予想以上に処理時間がかかりました。
HTMLとCSSのみでダイアログ表示

#できること
JavaScriptなしで、HTMLとCSSのみを使用してダイアログ表示を行います。

![ダイアログ機能.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1052793/95718714-a4ec-6db9-da24-d95f7bd41eee.gif)

動画のようにボタンをクリックすると、ダイアログが表示されます。
読んで欲しい文章を表示させることができます。

※ダイアログとは「ダイアログボックス」のことをいいます。何かを入力させたりメッセージを確認させるために、操作の過程で一時的に開かれる小さい画面のことです。

#HTML

```index.html
 <dialog id="dialog" class="dialog_style" >
                        「ダイアログの中身の文章（任意）」
 　 <button class="form__btn" onclick="document.getElementById('dialog').close();">
                       「ダイアログの中身にあるボタンの文章（任意）」
   </button>
 </dialog>
 
<button class="form__btn" onclick="document.getElementById('dialog').show();">
                    「クリックするとダイアログが表示されるボタンの文章（任意）」
                    </button>
```

#CSS

```styles.css

.dialog_style{ 
margin-left: 300px;
width: 1000px;
height: 500px;
border: 5px solid #b84c00;
border-radius: 10px;
}

.form__btn{
 〜省略〜
}

.form__btn:hover {
〜省略〜
}

```

CSSはお好みで記述してください。

以上です。
Railsでupdate_allとストロングパラメーターを併用した際のエラー対処

# 状況
railsの`update_all`メソッドとストロングパラメーターを併用して、SQLの発行回数を減らしてデータを一括更新したい。

# パラメーター
```
Parameters: {"update_ids"=>["1", "2", "3"], "group_id"=>"2"}
```
update_idsで取得した複数のアイテムの属するグループIDを一括で変更したい。

# 該当コード
```Ruby:items_controller.rb
def update
  ids = params[:update_ids]
  Items.where(id: ids).update_all(update_params)
end

private

def update_params
  params.permit(:group_id)
end
```

もちろん今回のような単純なケースだとストロングパラメーターを使用する必要はなく、

```Ruby:items_controller.rb
def update
  ids = params[:update_ids]
  Items.where(id: ids).update_all(group_id: params[:group_id])
end
```
と書けば目的は達成できますが、今後更新項目が増えていった際の想定の元にストロングパラメーターの使用を試みたという前提です。

# エラーメッセージ
```
TypeError (no implicit conversion of Hash into String)
```

# 検証：updateで書き直してみる
**`SQLの発行回数を減らしてデータを一括更新`**とは趣旨がずれてしまいますが、

```Ruby:items_controller.rb
def update
  ids = params[:update_ids]
  Items.where(id: ids).update(update_params)
end
```
とすると先程のエラーは解消されました。
ということはupdate_all独特のエラー・・・？

# エラー解決
```Ruby:items_controller.rb
def update
  ids = params[:update_ids]
  Items.where(id: ids).update(update_params.to_hash)
end
```
という具合に**`update_params.to_hash.to_hash`**と型指定をした所、処理が通り、SQLも一行で無事値を更新することが出来ました。
調べる限り同様の対処方法で解決しているケースも見受けられました。

`update_all`とストロングパラメーターを併用する場合、明示的に型変換をしないとエラーが出るような仕様になっているのでしょうか。
一先ず解決はしましたが、他にも良い方法等ありましたらご教示いただければ幸いです！

# 参考
https://teratail.com/questions/285505
https://takuya-1st.hatenablog.jp/entry/2016/08/25/041804
https://stackoverflow.com/questions/27372255/ruby-typeerror-no-implicit-conversion-of-hash-into-string