OmniAICreator/Qiita-1.07M huggingface dataset:
gsutil で firebase storage へのCORS設定

## 概要

FEなどからStorageへのURLへGETリクエストを許可するためのCORS設定です。

## コマンド

#### 適宜どのoriginを許可するか設定
```cors.json
[
  {
    "origin": ["*"],
    "method": ["GET"],
    "maxAgeSeconds": 3600
  }
]
```


#### gsutil コマンドでstorage bucket にcorsを設定

```bash
gsutil cors set cors.json gs://<your-cloud-storage-bucket>
```

#### gsutil update がリジェクトされたら

```
does not have storage.buckets.update access to the Google Cloud Storage bucket. Permission 'storage.buckets.update' denied on resource
```

と出たら、firebase のサービスアカウント(xxx.jsonで吐き出されるクレデンシャル）をダウンロードして、

```
gcloud auth activate-service-account --key-file=xxx.json
```

としてからもう一度`gsutil update`


以上です。
Gmailの送信者規約の変更で年明け大変そうだなぁってなっている話

# はじめに
割と前にGmailの規約変更で1日あたり5000件以上のメールをGmailに対して送信してる場合に、
特定の対応を行わないといけないという規約が発表されました。

今担当しているシステムでは1日に2度のメール送信、特定の操作により追加でのメール送信を行っており、
1日少なくても2件以上のメール送信が行われています。

# 何が必要？
[Gmailの規約](https://support.google.com/mail/answer/81126?hl=ja) によると
1. 送信メールを認証すること
1. 未承諾のメールまたは迷惑メールを送信しないようにすること
1. 受信者がメールの配信登録を容易に解除できるようにすること

の3点が必要になってくるようです。

# 対応について
１の認証についてはDKIMの認証等を行っているので問題はないはず（はず・・・きっとおそらくたぶん）
２についてはアカウントの登録、認証を行っていない限りメールも送信されないので問題ないはず

ということで一番の問題は３の対応についてです。

公式の情報によるとメールの送信ヘッダに
```
List-Unsubscribe-Post: List-Unsubscribe=One-Click
List-Unsubscribe: <https://solarmora.com/unsubscribe/example>
```
のようなものを埋め込むことで対応しよう！といった旨のことが書かれているので、
システムにすでに実装してある受信拒否の設定を少しいじったAPI（ヘッダのuncsbscribeに渡すURLをユーザ、送信メールの種類毎に一意にしてAPI側でユーザを探れるようにしないといけないはず）にして渡す対応が必要になりそう・・・

# 実際のところ
まずは現在システムに登録されているGmailのアカウント数の計測から実施する必要がありそうです。
本番環境のデータ調査をかなり実施しているのですが、体感ではGmailの登録数は実はあまりないので、
2月までの対応期限にはなっているものの、まだGmail宛に1日5000通の送信は行っていないんじゃないかなと思ってます。（SESのログとかから確認必要ではありますが・・・）

# 最後に
俺たちの戦いはこれからだ！みたいな感じで今後もユーザ数は増加していく想定ではいるので、
年明けの早いうちに対応のほうを進めたいと思います

# 参考
https://support.google.com/mail/answer/81126?hl=ja
Elixir様、日本の未来を切り拓いてください。

アドベントカレンダー初参戦の[こーへー](https://twitter.com/suuuusan0815)です。
31歳からIT業界に入り、現在丸2年経ちました。

最近リリースされた[Bright](https://bright-fun.org/)というエンジニアスキルを測るサービスで、自分自身のElixirレベルを計測しました。
基礎的な部分では、ベテラン👑の域に達してます。目標は開発できるレベルに達する事です。
![スクリーンショット 2023-12-24 11.38.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2670710/78fc9b9b-cb23-8d1b-996b-d239a60a6326.png)

そんな僕がブロックチェーンについてお話させていただきます。
先日Web3.0のハッカソンやセミナーに参加して、研究しつつ自分でWeb3.0のイベントを開いてみました。

結果、無名イベントにも関わらず12人の方にご参加をいただきました。

![スクリーンショット 2023-12-24 11.54.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2670710/083f7cf5-233b-6a62-4e62-d0e9ae7ff1a9.png)

改めて、旬な話題なんだなと実感したので、アドベントカレンダーにもElixirと掛け合わせた内容をオリジナルで書いていきたいと思います。

まずは、時代背景から。

## Web1.0（1991年頃 - 2000年代初頭）
**特徴**
Web1.0はインターネットの初期段階を指し、「読み取り専用」のウェブとも呼ばれます。

この時代のウェブは、主に静的なページで構成され、ユーザーは情報を閲覧するだけで、内容に対して積極的に貢献することはほとんどありませんでした。

**代表的なサービス**
Yahoo! Directory（ヤフーのディレクトリサービス）: インターネット上のウェブサイトをカテゴリ別に分類した。
Altavista（アルタビスタ）: 初期の強力な検索エンジンの一つ。
GeoCities（ジオシティーズ）: 個人が簡単にウェブページを作成できるサービス。


## Web2.0（2000年代初頭 - 現在）
**特徴**　*中央集権型*
Web2.0は「読み書き可能な」ウェブを指し、よりインタラクティブでユーザー参加型の特徴があります。

この時代のウェブは、ソーシャルメディア、ブログ、ウィキなど、ユーザーがコンテンツを生成し、共有し、互いにコミュニケーションを取れるプラットフォームを提供します。

**代表的なサービス**
Facebook（フェイスブック）: ソーシャルネットワーキングサイトで、ユーザーがプロフィールを作成し、友人と交流できる。
YouTube（ユーチューブ）: ユーザーがビデオをアップロードし、共有するプラットフォーム。
Wikipedia（ウィキペディア）: ユーザーが自由に編集可能なオンライン百科事典。


## Web3.0 
**特徴**　*非中央集権型*
Web3.0の技術はブロックチェンをベースとし、Web2.0の中央集権型とは対照的に、非中央集権型で構築されるシステムです。

Web3.0の特徴としては、2.0時代とは真逆で個人がプラットフォームとなれる仕組みがあり、これまでのメガテック企業独占時代を覆します。

目新しい技術に思いますが、実はブロックチェーンやWeb3.0という言葉の提唱や技術の確立はGavin Wood氏に2014年4月に発表されています。
そこから仮想通貨バブルやNFTに注目が集まった時代はありましたが、結局のところここ9年で大きな変化はありません。

## 世間一般的な考察
まず、Web3.0に変革すべきポイントとしては以下が挙げられます。
- メガテック企業の富と情報の独占化
- いつ、情報が流出するかわからないリスクorすでに既得者によって操られてる説
- コンテンツの垢Ban

### つまりWeb3.0というムーブメントはGAFAに代表される巨大プラットフォームに対するアンチテーゼとして生まれた概念なんです。

## アンチテーゼとして生まれたサービス
### [Brave](https://brave.com/ja/) Chromeの代替
広告配信の仲介者が存在しない。YouTube広告やWebサイト広告などをブロック可能。
### [Odysee](https://odysee.com/)　YouTubeの代替
ブロックチェーンをベースに作られたシステム。分散型の動画配信プラットフォーム。
### [Damus](https://damus.io/)　Xの代替
分散型SNSのプロトコルでテキスト送信に特化したシンプルなSNS。

### Elixirとブロックチェーンの相性
先にも挙げたように、Web3.0は非中央集権型なので、つまりは一箇所に情報を集約する事なくそれぞれが固有のデータとして分散独立しています。

この分散という点に着目すると、これだけで非常に「Elixirと相性がいいのでは？」と、思ってしまいます。
ElixirはErlangVM上で動作しますが、これが並行処理能力と耐障害性に非常に優れているからです。

ちなみに、公表はされていないので名前は出しませんが、ブロックチェーン技術を搭載した有名なゲームがElixirで作られているのでは。とも言われています。

### まとめ
技術的なエビデンスは追求する必要がありますが、Web3.0やElixir言語が日本で浸透していないのには、色々な理由があります。

ただ、一つ確かに言えることは、これら概念をサービス化し、その技術をElixirが支える日がそう遠くない未来に訪れるでしょう。
認証トークンの仕組みについて

認証で具体的にどんなアルゴリズムでやっているかご存じですか？
私は全然知りませんでした。😐

Railsのdeviseを使ったら勝手にやってくれるから特に気にも留めていませんでした。
しかし、プライベート開発中に仕組みを勉強する機会がありましたので、
学習した内容を記事にさせて頂きます。

>記事がいいなと思ったらtwitterのフォローもお待ちしております‼
https://twitter.com/takeshi_program

## はじめに
本記事は以下の読者様が対象です。
- プログラミング初心者

## 本記事のゴール
- トークンによるセキュリティ向上 +αデータベースリソースの負荷軽減ができる理由を把握できる。

## トークンとは？
トークンは暗号文字列です。
そのため、復号化の方法知らなければ、意味のない文字列です。

## 認証トークンの使い方について
認証トークンはログインが成功した際にサーバーから発行されクライアントに付与されます。
そして、クライアント側は付与されたトークンを毎回のリクエスト時に本体データと一緒に送付します。
サーバー側はそのトークンを見て有効期限内の有効なトークンであれば
正常なレスポンスを送り、異常であれば再度ログインを求めるためのページを返すのが一般的です。

## トークンの有無による認証方法の違い
- #### トークンなし(`emailとpassword`だけ)の場合
トークンを使わない場合はトークンの代わりに毎回リクエストに`emailとpassword`を付与して送ります。
その都度サーバー側はDBへリクエストを行い、`password`を取得し、passwordが同じものかを照合します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534058/52772fb0-e8e0-de36-4201-1e23b0361c36.png)

照合結果がOKであれば、適切なデータをレスポンスします。

単純なため仕組みですが、このプロトコルのデメリットは
仮に第三者に`emailとpassword`を盗聴された場合に、ユーザーが盗まれた事に気づき`password`を変更する必要があります。
それまで、第三者にデータを盗まれ続けます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534058/c5e60611-236b-d688-1565-b90784d7352f.png)

- #### トークンありの場合
トークンの場合、ユーザーが盗聴に気づかなくても一定時間が経過したらトークンが無効になるため、トークンを使った方が仮に情報を盗まれても被害を小さくできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534058/cd739a9e-6d9d-11d3-ba7d-e96b0da316f4.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534058/83e7fbac-e297-da61-e5de-071bb6c4614a.png)

(もし期限のないトークンの場合はユーザーが盗聴に気づくまで盗まれ続けます)

## トークン詳細について
トークンへの期限の実装方法ですが、
そもそも暗号化というのはある文字を意味のない文字列に変換する処理です。
暗号化する前の文字の中に期限を入れていれば期限の情報を内包した文字を暗号化できます。
それを復号すれば期限情報を取得できるため、現在時刻と比較すればよいという事です。

以下が`Ruby`で暗号化、復号化するコードです。

```ruby
require 'openssl'
require 'securerandom'

def encrypt(data, key, iv)
  cipher = OpenSSL::Cipher.new('AES-256-CBC')
  cipher.encrypt
  cipher.key = key
  cipher.iv = iv
  encrypted = cipher.update(data) + cipher.final
  return encrypted
end

def decrypt(encrypted_data, key, iv)
  cipher = OpenSSL::Cipher.new('AES-256-CBC')
  cipher.decrypt
  cipher.key = key
  cipher.iv = iv
  decrypted = cipher.update(encrypted_data) + cipher.final
  return decrypted
end

# 32バイトのランダムな鍵を生成
encryption_key = SecureRandom.bytes(32)
iv = OpenSSL::Random.random_bytes(16) # Initialization Vector (IV)

# 暗号化
data_to_encrypt = '{email: "test_user", limit: "2023/12/24"}' #トークンの生成
encrypted_data = encrypt(data_to_encrypt, encryption_key, iv)
puts encrypted_data

# 復号化
decrypted_data = decrypt(encrypted_data, encryption_key, iv) #トークンの生成
puts decrypted_data

```


### データベースリソースの負荷軽減
トークンがあればサーバー側はトークンの有効期限をチェックするだけよく、DBからユーザー情報を取得する必要がなくなるため、データーベースへのリクエストの回数が減り、DBリソース負荷を軽減できるメリットもあります。

## おわりに
今回のサンプルコードは`emailとlimit`のプロパティしか渡していませんが、ここに`[create, update, delete, read]`などを入れることで認証だけでなく、認可の情報もトークンに載せて送ることができます。
すごい技術ですよね～
おそらく`AWSのAMIやcognito`、`Ruby on Railsのdevise`もそのような仕組みなのでしょうね。

また発見があれば記事にしたいと思います。
ありがとうございました。👍
投稿機能アプリの削除機能

備忘録としてあげさせていただきました。


## 目的
- CRUDのD(DELETE)を体験
- データの操作で基本的な処理となる「削除」を理解
- destroyアクションを理解
- Prefix

## 削除機能
7つのアクションのうち、削除機能はdestroyが該当

## 実装の流れ
1. ツイートを削除するためのルーティングを設定　
1. 削除ボタンをビューに追加 
1. destroyアクションをコントローラーに定義する 

## destroyアクションのルーティング設定
config/routes.rb
```ruby
 resources :tweets, only: [:index, :new, :create, :destroy]
```

 ## 削除ボタンを投稿一覧に追加
 `linl_to`mメソッドを使い、削除ボタンを追加
 削除ボタンのパスには **_ツイートのid_**を　パラメーターとして持たせる
 /tweets/《tweetのid》というパスにすると、パラメーターとして受け取ることができる

 HTTP： **_DELETE_** メソッド
 「data:{turbo_method::delete
app/views/tweets/index.html.erb
`<span><%= image_tag 'arrow_top.png' %></span>`
`<%= link_to '削除', "/tweets/#{tweet.id}", data: { turbo_method: :delete } %>`

### image＿tag
imgタグを生成するためのRailsのヘルパーメソッド.。第一引数にapp/assets/images配下、もしくは、public配下の画像を指定
```ruby
<span><%= image_tag 'arrow_top.png' %></span>
=> <span><img src="assets/arrow_top.png" /></span>
```

## link_tおの遷移先をPrefixで指定
 ### Prefixとは？
 ルーティングの`URI Pattern`に名前をつけて変化させたもの
 ターミナルの`rails routes`コマンドを実行したら見れる

このPrefix名に続けて`_path`と記述を付け加えることによって、`URI Pattern`のパス値して認識される
 
 `'/'` =>  `root_path`

Preixを用いて遷移先を設定
app/views/tweets/index.html.erb

 `<%= link_to '削除', tweet_path(tweet.id), data: { turbo_method: :delete } %>`
 ## destroyアクションをコントローラに定義
 ツイートを削除する際にはモデルのdestroyメソッド使用
`params[:id]`を使用し、削除したいツイートの情報を取得
この時の`params[:id]`は先ほどPrefixで指定したパスである`tweet_path(tweet.id)`の
`tweet/id`に当たる数字が入ります


```ruby
  def destroy
    tweet = Tweet.find(params[:id])
    tweet.destroy
    redirect_to root_path
  end
```
ビューにツイート情報を受け渡さないので、インスタンス変数ではなくただの変数として置く

#### 処理の流れ
パラメータとして受け取った`params[:id]`を元に、削除したいツイートを`find`メソッドを用いて取得します
そして、そのツイートを`destroy`メソッドで削除する。
削除した後はトップ画面を表示するために`redirect_to`メソッドを使用している
Database操作#INSERT編

# INSERT文
`INSERT`は`CRUD`における`Create`にあたるもの
### 基本
#### 使用方法
```sql
INSERT INTO table_name (column1, column2, column3,...) VALUES (value1, value2, value3,...);
```
#### 解説
column1に入れる値をvalue1に記述する
column2に入れる値をvalue2に記述する
column3に入れる値をvalue3に記述する
## user表
|name|age|gender|address|
|:---:|:---:|:---:|:---:|
|varchar|int|varchar|varchar|
```sql
INSERT INTO user (name, age, gende) VALUES ('john', 23, 'male');
```
文字列として扱う(varchar型に代入する)場合シングルクォーテーションで囲む
```sql
INSERT INTO user VALUES ('john', 23, 'male', 'Tokyo');
```
テーブル内にあるすべてのカラムに入れる場合はテーブルのカラム名を省略できる
横スクロール可能な要素にヒントを表示するjsライブラリ

## はじめに
スカラパートナーズAdventcalendar24日目担当です。
今回はスマホなどでスクロール可能な要素を視覚的に示すためのJavaScriptライブラリ「ScrollHint」の使い方について解説します。

## ScrollHintとは？
ScrollHintは、スクロール可能な要素をユーザーに知らせるためのJavaScriptライブラリです。

https://appleple.github.io/scroll-hint/

例えばスマホやタブレットで閲覧時に、横に長いテーブル表示などは横にスクロールしなければ全ての情報を見ることができません。このようなコンテンツをスクロールする必要がある場合に、下記のようなアイコンを表示してくれるものとなります。

![スクリーンショット 2023-12-24 12.26.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480255/f74bdde9-1bc5-2982-92ed-6534a75a9e42.png)

## 実装方法

### 1. HTML,CSSコードを準備する
```HTML
<div class="js-scrollable entry-container">
    <h2>動物について</h2>
    <table class="dataframe animal-table">
        <thead>
            <tr style="text-align: right;">
                <th>動物</th>
                <th>生息地</th>
                <th>食性</th>
                <th>寿命（年）</th>
                <th>保全状況</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>ライオン</td>
                <td>サバンナ</td>
                <td>肉食</td>
                <td>14</td>
                <td>脆弱</td>
            </tr>
            <tr>
                <td>ゾウ</td>
                <td>森林</td>
                <td>草食</td>
                <td>60</td>
                <td>絶滅危惧</td>
            </tr>
            <tr>
                <td>パンダ</td>
                <td>竹林</td>
                <td>草食</td>
                <td>20</td>
                <td>脆弱</td>
            </tr>
            <tr>
                <td>カンガルー</td>
                <td>アウトバック</td>
                <td>草食</td>
                <td>23</td>
                <td>脅威なし</td>
            </tr>
            <tr>
                <td>ペンギン</td>
                <td>南極</td>
                <td>肉食</td>
                <td>15</td>
                <td>危険に近い</td>
            </tr>
        </tbody>
    </table>
</div>
```

```CSS
.animal-table {
    width: 100%;
    border-collapse: collapse;
}

.animal-table, .animal-table th, .animal-table td {
    border: 1px solid black;
}

.animal-table th, .animal-table td {
    padding: 8px;
    text-align: left;
}

.animal-table th {
    background-color: #f2f2f2;
}
.js-scrollable td,
.js-scrollable th {
    white-space: nowrap;
    background-color: transparent;
}
.js-scrollable table {
    margin-bottom: 0;
}
.js-scrollable {
    margin-bottom: 30px;
}
```

### 2. ScrollHint 読み込み（CDN）
```HTML
<!-- CDNでの読み込み -->
<link rel="stylesheet" href="https://unpkg.com/scroll-hint@latest/css/scroll-hint.css">
<script src="https://unpkg.com/scroll-hint@latest/js/scroll-hint.min.js"></script>
```

### 3.JavaScriptの記述
```JavaScript
window.addEventListener('DOMContentLoaded', function(){
  new ScrollHint('.js-scrollable');
});
```

### 4.チェックしてみる
検証ツールでスマホサイズなどにするとアイコンが表示されるようになりました。
ScrollHintでは、画面幅に合わせてアイコンの表示・非表示を切り替えてくれるため、開発側でレスポンシブ対応を行う必要はありません。

![スクリーンショット 2023-12-24 12.31.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3480255/13d84c87-8650-36c2-3e26-27db79793376.png)


## おわりに
ScrollHintは手軽に実装でき、ユーザビリティを向上させることができるツールです。
ぜひ手元でお試しいただければと思います。

また、今回の記事では紹介しませんがScrollHintにはさまざまなオプションがありますので、気になる方は下記公式サイトからチェックしていただければと思います。

https://appleple.github.io/scroll-hint/
【Rails】enum 使う時はprefixを使いましょう

# はじめに
`enum`を使う時は`prefix`を使いましょう、という提案です。

# なぜprefixを使うと良いのか

**1.可読性が上がる**、**2.拡張性が高くなる**からです。

## 可読性が上がる
```ruby
class Article < ApplicationRecord
  belongs_to :user
  enum :status, { unsaved: 10, draft: 20, published: 30 }, _prefix: status
end
```
`_prefix`がない場合も一見わかりやすいですが、個人的には`_prefix`を付与することで、`モデル`の`このカラム`の`このステータスの状況`が一目でわかりやすくなります。
```ruby:_prefixがない場合
[3] pry(main)> article.published?
=> true
[4] pry(main)> article.draft?
=> false
[5] pry(main)> article.unsaved?
=> false
```

```ruby
class Article < ApplicationRecord
  belongs_to :user
  enum :status, { unsaved: 10, draft: 20, published: 30 }, prefix: status
end
```

```ruby:_prefixがある場合
[3] pry(main)> article.status_published?
=> true
[4] pry(main)> article.status_draft?
=> false
[5] pry(main)> article.status_unsaved?
=> false
```

## 拡張性が高くなる

例えば、同じようなステータスがある場合、重複によりエラーが出てしまいます。

```ruby
class Conversation < ActiveRecord::Base
  enum status: { active: 0, archived: 10 }
  enum comments_status: { active: 0  inactive: 10 }
end
```
```ruby
irb(main):004:0> c = Conversation.find(1)
ArgumentError (You tried to define an enum named "comments_status" on the model "Conversa
```
このような時も、あらかじめ`prefix`を設定しておけば重複せずに管理することができます。

```ruby
class Conversation < ActiveRecord::Base
  enum status: [:active, :archived], prefix: true
  enum comments_status: [:active, :inactive], prefix: true
end
```

```ruby
[3] pry(main)> conversation.status_active? 
=> true

[5] pry(main)> conversation.comments_status_active? 
=> true
```
refのやってはいけない使い方をして痛い目を見た話

## はじめに
refを使っていますか？
私はReactを触り始めて、1ヶ月ぐらいでrefを教えていただきました。
知識としては知っていましたが、実務で実際に書いてみてrefとstateの違いと、refを使ってはいけない具体例を経験することができたので、共有します。

プログラミング初心者やReactの初学者の方の参考になれば嬉しいです。

### 自己紹介
私は2023年9月1日にフロントエンドエンジニアとして自社開発のSaaS企業に入社しました。
未経験独学で、薬剤師からの転職です。
詳しくはこちらをご覧ください。

https://qiita.com/odendayoko/items/f616b2f1952897a9af5d

## 具体例で説明
### 背景
WEBのサービスサイトの問い合わせフォームを実装しています。
form要素を使って、問い合わせ送信ボタンを実装しました。
追加要件として、送信中は何度もリクエストを送れないようにするために、一度送信ボタンを押したらボタンを非活性にするという実装をすることになりました。

### 設計
- 送信ボタンを一度押したら非活性にする
    - button要素のdisabled属性をtrueにする
- 判定する条件に`isSending`を使う

### 実装
追加要件を先輩から伝えられた時に、「すでに`isSending`を使った同じような実装があるからそれを参考にしてみて」と言われました。
ソースコードを見てみると、 `const isSending = useRef(false);`と定義されていました。
なるほど！これを使えばいいんですね👍と何も考えずに実装してみました。
```react
import React, { useRef, FC } from 'react';

const FormComponent: FC = () => {
    const isSending = useRef(false);
    
    const handleSubmit = () => {
        isSending.current = true;
        // ここでfetchする
    };
    
    return(
        <form onSubmit={handleSubmit}>
             {/* {問い合わせフォームの内容は省略} */}
            <button disabled={isSending.current}>送信</button>
        </form>
    );
};
export default FormComponent;
 
```
まずは、参考にする実装と同じように`isSending`を`useRef`を使って宣言します。初期値は`false`です。
送信ボタンを押した時に実行される`handleSubmit関数`の中で、`isSending`の値を`true`に更新します。
そして、button要素のdisabledプロパティで`isSending.current`を読み取リます。`isSending.current`が`true`ならbutton要素は非活性になります。

それではどのような動きになるのかを確認します。
ん？？？何かがおかしい…
一度送信ボタンを押してもボタンは非活性になっていません。
もう一度送信ボタンを押すと非活性になります。
これは一体何が起きているのでしょうか？

これがReact公式ドキュメントにも落とし穴として書かれている、**レンダー中に ref.current の値を読み取ったり書き込んだりしないでください。**　にまんまとはまってしまった結果です。

### refとstateの違い
こちらのReact公式ドキュメントでとても分かりやすく解説されています。

https://ja.react.dev/learn/referencing-values-with-refs#differences-between-refs-and-state

refとstateの大きな違いは、**変更した時にコンポーネントが再レンダリングされるかどうか**です。
refの場合は、値が変更されてもコンポーネントは再レンダリングされません。再レンダリングされないということは、値を変更したとても画面に反映されないということです。
そのため、**レンダー中にcurrentの値を読み取る（または書き込む）べきではない**　とされています。

私が書いた例で何が起こっていたのかを考えてみます。
- 送信ボタンを押した時、currentの値はtrueに変更される
- しかし、refの値が変更されてもコンポーネントは再レンダリングされないため、ボタンが非活性になるという画面の変化は起こらない
- 再度押した時に非活性になったのは、おそらく他の要因でコンポーネントが再レンダリングされてrefの変更が画面に反映されたから

refの値を使って画面を変更しようとすると、こういうことになるんですね😭
stateを使って書き直しましょう。

### 修正
```react
import React, { useState, FC } from 'react';

const FormComponent: FC = () => {
    const [isSending, setIsSending] = useState(false);
    
    const handleSubmit = () => {
        setIsSending(true);
        // ここでfetchする
    };
    
    return(
        <form onSubmit={handleSubmit}>
             {/* {問い合わせフォームの内容は省略} */}
            <button disabled={isSending}>送信</button>
        </form>
    );
};
export default FormComponent;
```
これで送信ボタンを押した時に`isSending`のstateが更新され、ボタンが非活性になる変更が画面に反映されるようになりました。

## refの注意点
最後にrefを使う注意点を自分の言葉でまとめます。

:::note alert
- refをレンダー中に使うな！！
- refはstateと違って値が更新されても再レンダリングされない
    - UIの変更に反映されない可能性がある
- return文の中にrefを使った判定を入れるのは危険だからstate使う！！
:::

## 終わりに
refについて何にも分かっていなかったと痛感しました…
知識をつけても、痛い目をみないと身につきませんね😭
ガンガン失敗して使いこなせるようにしていきたいです。
gRPCでGoのボイラーテンプレートが生成されるディレクトリについて

下記の公式ドキュメントを参考にprotoファイルからボイラーテンプレートを自動生成しようとしましたが、オプションの意味が分かりづらく思ったようなディレクトリに作成されませんでした。
https://grpc.io/docs/languages/go/basics/#generating-client-and-server-code

結論から言うと以下です。

| オプション | 意味 |
| ---- | ---- |
| --go_out= | `*.pb.go`ファイルが作成される起点となるディレクトリ |
| --go_opt=paths= | `source_relative`を指定すると`--go_out`で指定した`直下に`*.pb.go`ファイルがさ生成される |
| --go-grpc_out= | `*_grpc.pb.go`ファイルが作成される起点となるディレクトリ |
| --go-grpc_opt=paths= | `source_relative`を指定すると`--go-grpc_out`で指定した`直下に`*_grpc.pb.go`ファイルがさ生成される |

#### --go_out

`.`を指定するとprotoファイルと同ディレクトリをコードを生成する起点とします。
`.`を指定せず,`gen/api`などを指定すれば、コマンドを実行したパスから相対パスのディクレトリにすることも可能です。

#### --go_opt=paths
goの場合、protoファイルで`option go_package = "github.com/xxx/yyy";`のような指定をすると思いますが、その場合、それに対応したディクトリにコードが表示されてしまいます。
例えば、`--go_out=gen/api`を指定した場合、自動生成されるコードのパスは`gen/api/github.com/xxx/yyy`となってしまいます。
`--go_opt=paths=source_relative`を指定すると、`gen/api`のパスにコードが自動生成されるようにすることができます。

`--go-grpc_out`、`--go-grpc_opt=paths`についても同様です。
Pulumi を試す

pulumi を試してみた

# 準備

```compose.yml
version: '3'
services:
  pulumi:
    image: pulumi/pulumi:3.99.0
    env_file: .env
    volumes:
      - .:/app
      - .pulumi:/root/.pulumi
      - .aws:/root/.aws
```

```
$ cat .gitignore
*
!/.env.sample
!/compose.yml
!/.dockerignore
$ cat .dockerignore
*
```

```shell-session
$ docker compose run --rm pulumi version
$ docker compose run --rm --entrypoint bash pulumi
> pulumi version
( 起動時間が気になるならコンテナ上げた方がいい
```

### NOTE

- `~/.pulumi` を Linux 以外(Mac など) と共有するには，`~/.pulumi/plugin/` などの binary format が違うディレクトリを共有できない．

## おまけ

### Refs

```shell-session
$ cat compose.yml
version: '3'
services:
  aws:
    image: amazon/aws-cli:2.15.4
    volumes:
      - .aws:/root/.aws
$ docker compose run --rm aws configure sso
```

https://hub.docker.com/r/amazon/aws-cli

https://zenn.dev/yaasita/articles/aa48bfa06b9a53


```plantuml
class PulumiCloud
class LocalMachine
package AWS {
  class S3
}

LocalMachine -up-> PulumiCloud : pulumi up
PulumiCloud -right-> S3 : API
```


## Refs

https://www.pulumi.com/docs/clouds/aws/get-started/begin/

https://qiita.com/mziyut/items/069c21328bbeb25d5aab

https://docs.docker.jp/v1.12/compose/compose-file.html

https://hub.docker.com/r/pulumi/pulumi
レシーバ付き関数リテラルを使用した関数についてやっと理解できた(はず)

# はじめに
業務でKotlinを使用していますが、[Kotlin Koans](https://play.kotlinlang.org/koans)でレシーバ付き関数リテラルの記述を見て「？」となったので理解できるまで調べました。
未来の自分が見ても振り返れるようにまとめます。

# ？となったコード
以下のコードです。
```kotlin:関数定義
fun buildString(build: StringBuilder.() -> Unit): String {
    val stringBuilder = StringBuilder()
    stringBuilder.build()
    return stringBuilder.toString()
}
```
引数でレシーバ付き関数リテラルを使用しています(`build: StringBuilder.() -> Unit`の部分)。
上記関数を使用する場合、以下のように使用します。
```kotlin:使用例
val s = buildString {
    this.append("Numbers: ")
    for (i in 1..3) {
        // 'this' can be omitted
        append(i)
    }
}
```
最初はこのコードを見た時点で何が起こっているか理解できませんでした。

# 理解できなかった点
## `buildString`の定義内でなぜ`build()`とできるのか？
理由は以下の通りです。

- `build`の型が`StringBuilder.() -> Unit`であり、関数なので`build()`と呼び出しができる
- `() -> Unit`の部分は、引数なし、戻り値なしの関数
- `StringBuilder.()`の部分は、**`StringBuilder`の引数なしの拡張関数**

上記の理解ができたことでこの疑問は解決しました。

## 使用時の記述が理解できない
`buildString {}`の中身の処理は理解できますが、なぜ`buildString {}`の記載のみでいいのかが理解できませんでした。

これは、`StringBuilder`の引数なしの拡張関数の実装だったことがわかったことで納得できました。
つまり、`buildString`使用時に実装を記述しているということでした。
なので`buildString {}`の`{}`内の実装が`buildString`の関数定義内で使用され、結果が`s`に代入されていることになります。

上記から、共通処理はレシーバ付き関数リテラルを引数に持つ関数で記載し、固有の処理は呼び出し時に記載する、といった使用方法ができると理解しました。

# 終わりに

今回記載したことが理解できたことで、レシーバ付き関数リテラルの使い所も理解できたと思っています。。。

# 参考資料
 - [Kotlinのレシーバ付き関数リテラルとは - ツレヅレナルママニ](https://tkhs0604.hatenablog.com/entry/function-literals-with-receiver)
 - [Kotlinのスコープ関数の定義をちゃんと読む - 縁側プログラミング](https://engawapg.net/kotlin/76/understand-kotlin-scope-function-definitions/)
Vonage API冒険記：初めての挑戦が知識を広げる扉を開く

今日は初心者の私がVonageのコミュニケーションAPIに挑戦してみた結果を報告します

まず初めに、APIのセットアップに挑戦。初めての経験でしたが、VonageのコミュニケーションAPIは使いやすく、セットアップもスムーズに進みました。挑戦することで、APIの基本的な機能を理解できました。

挑戦の過程で、APIの多彩な機能に触れることができました。これらの機能を組み合わせて独自のコミュニケーション体験を作り出すことができるんですね。

そして、挑戦の成果としてAPIの設定が完了し、新たな知識を得ることができました。これからはこの知識を基に、何か新しいものを作ってみたいと考えています。具体的なプロジェクトやアイディアがまだ明確ではないけれど、挑戦を通して学ぶことができたことが非常に充実感をもたらしています。
テスト自動化初心者の冒険：継続性がもたらす成功の秘訣

テスト自動化初心者の私が、成功への一歩を見つけたお話です！
自動化って何かと難しそうだと思っていたけれど、あるプロジェクトでの成功を経て、継続性の大切さを実感しました。

まず最初に気づいたのは、「継続性」の重要性。最初は戸惑うこともあるし、失敗も絶対に避けられない。でも、毎日少しずつでも進めることが、成功への近道なんです。

さらに、プロジェクト進行中に変更があった時、柔軟に対応できるように心がけることもキーポイント。
継続的にプロジェクトに取り組む中で、柔軟性も自然と身についていきました。変更に対応できることで、プロジェクトの進行がスムーズになります。

最後に、サポートが成功に繋がるかもしれないポイント。
初心者の頃、分からないことだらけでしたが、サポートがあれば心強い。
ツールの使い方やトラブルシューティングについて、遠慮せずに質問できると安心です。私もおかげで成功に導かれました。

まとめると、テスト自動化の成功には「継続性」が不可欠。毎日少しずつでも進め、柔軟に変化に対応し、サポートを受けることで初心者でも成功に近づけると思いました。
一等無人航空機操縦者の夜間限定解除試験について(教習所経由)

# はじめに
### この記事について
* この記事は一等無人航空操縦者の夜間限定解除を行った際の備忘録となります。試験の詳細については触れられませんが、当日の試験の流れについて記載するのでお役に立てればと思います。
### 講習日程
* 日帰り
* 15:00~20:00
### 費用
* 4万程度
# 試験の流れ
### 点数配分
* 100点満点中80点以上で合格。減点性
### 机上試験
* 模擬的な飛行計画書に沿って、留意点について答えていくもの
* パターン化されているので、当日暗記すればOK
### 口述試験
* 当日の飛行空域や飛行形態に応じて、注意点等を答えていくもの
* 出題例としては以下の通り
  * 飛行空域及びその周辺の状況に問題はないか。
  * 航空法等の違反はないか。
  * 必要な許可証、承認証、技能証明証等を携帯しているか。
  * 操縦者の体調等に問題はないか。
  * 気象状況に問題はないか。
### 作動前点検
* 飛行を行う前に機体やプロポの確認を実施する
* 出題例は以下の通り。正直、問題文からではわからないポイントが多すぎるので当日教えてもらいましょう
  * 各機器が確実に取り付けられているか。（ネジ、コネクター等の脱落やゆるみ等）
  * 機体(ローター/プロペラ、フレーム、機体識別票等）及び操縦装置に外観の異常、損傷又はゆがみ等がないか。
### 作動点検
* 実際に機体を作動して確認を実施する
* 出題例は以下の通り。
  * 電源系統（機体及び操縦装置の電源を投入した際の状態等）は正常か。
  * 通信系統（機体と操縦装置の通信、GNSS の通信等）は正常か。
  * 燃料の搭載量又はバッテリーの残量は十分か。
  * リモートID機能の作動が正常であるか（リモートID非搭載機の場合は、リモートIDが正常に作動していると仮定し、リモートIDが正常に作動している旨の点呼を行う。）。
  * 推進系統（発動機又はモーター等）は正常か。
  * 自動制御系統及び操縦系統は正常か。機体を離陸地点直上でホバリングさせた状態で、各操縦系統の操作を行い、機体及び操縦装置が意図通りに作動するか。

### 実技試験
* スクエアと八の字を実施します。それぞれの実施方法はこの[動画](https://www.youtube.com/watch?v=3rxUsn1sUQ0)を見ればわかります。
### 飛行後点検
* 出題例は以下の通り
  * 各機器が確実に取り付けられているか。（ネジ、コネクター等の脱落やゆるみ等）
  * 機体（ローター/プロペラ、フレーム、機体識別票等）の外観、損傷、ゆがみ等がないか。
  * 各機器の異常な発熱はないか。
  * 機体へのゴミ等の付着はないか。
### 飛行日誌
* 飛行時間に沿って飛行日誌を埋めていきます。様式は大体こんな感じ
* ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2584877/6770c5b7-a9a7-27b8-6b97-649c8838a8fc.png)

# さいごに
* 夜は冷えるので防寒対策を行いましょう
* 夜は視力が落ちるのでいい眼鏡をかけていきましょう
# 参考文献
* [一等無⼈航空機操縦士実地試験実施細則回転翼航空機（マルチローター）](https://www.mlit.go.jp/common/001516516.pdf)
テスト自動化ツールT-DASHを試してみた感想



今日は、私がテスト自動化ツールT-DASHを試用した際の実体験を共有したいと思います。

テスト自動化についてあまり詳しくなかったのですが、その使い勝手を確かめてみることにしました。

T-DASHのセットアップは非常にスムーズで、使いやすい機能が提供されていました。テストケースの作成から実行までが直感的で、カスタマイズオプションも多彩で、プロジェクトに合わせて調整できる点が魅力的でした。

専門知識が不足しているユーザーにとって、T-DASHのサポートチームとコミュニティが頼りになりました。質問や問題が生じた場合、迅速にサポートを提供してもらえる環境もあるそうで、とても安心感がありました。

新人の私でも使いやすいT-DASHは、簡単に導入できるので、知識がない人でも始めやすいツールだと思いました。
なぜ全部div要素じゃダメなのか

# div要素があれば何でもできる？

HTMLに慣れ始めたころに、Webサイトの大部分はdiv要素だけで実装できると気付きました。

例えば、
- リストを作る際にわざわざul要素の中でli要素を並べなくても、div要素を縦並びにすれば同じことを実現できます。

- テキストの一部を強調する場合も、strong要素を使わなくても、div要素で囲んだ上で「インライン要素にする」「中のテキストを太字にする」スタイルを充てれば同じことを実現できます。

要するに、表現が異なる箇所ごとにdiv要素で囲い、特別なスタイル充てを施せば、目標の見た目の大体は実現できます。

（機能をdiv要素だけで実現するのは難しいです。それでも、リンクのためのa要素とか、動画のためのvideo要素くらいで十分そうです。）

多くのユーザーはWebサイトの表面部分（UI）にしか関心がありません。したがって、HTML文書がどう記述されていようが関係ないように思えます。

なぜul要素やstrong要素は存在するのでしょうか。

# なぜ全部div要素じゃダメなのか

これを理解するために、開発者以外にHTML文書に関心を持つ存在がある、ということを把握する必要があります。

例えば、**スクリーンリーダー**（視覚障がい者などのためにコンテンツ読み上げをするソフト）です。

スクリーンリーダーは、要素に込められた意味を抽出し、特別扱いする機能を持ちます。その例を2つ挙げてみます。

> Case1: テキストを強調して読み上げる
　
開発者がstrong要素で囲んだ個所を、強調して読み上げてくれるかもしれません。
しかしdiv要素で囲んでclass属性で太字スタイルを充てていたとしたら、そこに込められた「強調している」という意味を解釈してもらえなくなります。

> Case2: リンク集の読み上げを回避する
　
nav要素で囲まれたリンク集は、意味的に強くないので読み上げを回避するように取り計らってくれるかもしれません。
しかしdiv要素で囲んでリスト化しているだけだとしたら、そこに込められた「ナビゲーション用でメインコンテンツではない」という意味を解釈してもらえなくなります。

div要素は特別な意味を持たない要素です（強いて言えば、「1つのまとまりである」という意味）。スクリーンリーダーが特別な解釈をする可能性は低いでしょう。

###### 開発者が特別な意味を持つ要素を積極的に活用することで、コンテンツがスクリーンリーダーからの恩恵を受けやすくなります。

スクリーンリーダー以外の例としては、**SEO**（検索エンジン）があります。

SEOは、HTML文書から「Webサイトが最も提供したいこと」を汲み取ることで、ユーザーの求めているコンテンツを検索上位に出せるようにしています。

そのため、Web開発者は特別な意味を持つ要素の中に「Webサイトが最も提供したいこと」を込めることで、多くのユーザーにアクセスしてもらおうと試みます。

# セマンティクス

コードの中に適切な意味を含ませて文書構造・構成要素の意味を明確にすることを**セマンティクス**と言います。

HTML文書の中で特別な意味を持つ要素を使用することは、ちょうどセマンティクスに当たります。

# 結論

div要素だけで実装してしまうと、HTML文書に込められた意味を外部のツールが汲み取りにくくなります。

セマンティクスを意識して、多くの人が有効にコンテンツを利用できるようにしましょう！
KDDI AU光のレンタルルーターを飛ばして、モデムと自分のWi-Fiルーターと直接に接続できる？

AU光を使い始めました。

工事の方より、モデムとWi-Fiルーター両方を使わないとダメだってこと。インタネットだけを契約してWi-Fi機能を使わなくても、そのWi-Fiルーターが必要だって。

それ、おかしくないかと思います。だってモデムと自分のWi-Fiルーターを繋いて、WAN側で設定をして同じ効果じゃないか？

でも、KDDIのレンタルルーターはモデムとどのようなProtocolで繋がるかわからないので、工事の方に聞いてみましたが、「工事の人なんてその辺にはわかりません」と言われました。まあ、おそらくわかっても教えてくれないと思って諦めました。

つまり、AU Modem -> AU Router -> My Routerとなっている。

これ、どう考えても納得できません。そのレンタルルーターは電力消費が少ないけど、ゼロじゃない。スペースとコードの整理も面倒ですし、なりより、ネットワークにもう一つのレイヤーが増えて不愉快です。（Bridgeモードであればアドレス転換がないため、スピードには多分影響がないですが、やっぱり不快）

ネットで色々調べてみましたが、関連情報がなさそうです。日本の方々、本当にこれでいいの？
Windowsナレータープログラム

# Windowsの読上げをpythonで使ったナレータープログラム
Windows用のナレータープログラムをpythonで作ってみました。

## 工夫点
読みと表示に分けて読み間違える部分をひらがなやカタカナで指定できるようにした点。

## 必要なもの
PySimpleGUI と Win32com　ライブラリを使っているので
pip list で確認して入っていなければ
pip install PySimpleGUI
pip install win32com
でインストールしてください。

## ソース（自由に改修してください）
~~~
#
import PySimpleGUI as psg
import win32com.client as wc

spk = wc.Dispatch('SAPI.SpVoice')

#　ここにナレーションを入れます。（’よみ’,'表示'）の順で書きます
mess = [
    ('読みには読めない漢字の部分を平仮名で入れます。','読みには読めない漢字の部分を平仮名で入れます。'),
    ('読みと表示に分けることで正確に発音できます。','読みと表示に分けることで正確に発音できます。')
]
dispnum=0

wlay = [[psg.Multiline(default_text=mess[0][1],size=(40,10),border_width=2,font=("",15),key='MText',disabled=True)],
        [psg.Button('Next',key='Next'),psg.Button('Top',key='Top'),psg.Button('終了',key='END')]]

win = psg.Window('ナレーター',wlay)
while True:
    ev,val = win.read()
    if ev in ('END',None):
        break
    if ev == 'Next':
        dispnum+=1
        if dispnum >= len(mess):
            dispnum=len(mess)-1
    if ev == 'Top':
        dispnum=0
    win['MText'].Update(mess[dispnum][1])
    spk.Speak(mess[dispnum][0])

win.close()
~~~
【kaminari】Rails APIで全体のページ数をレスポンスで返したい

# はじめに
`Rails API`と`kaminari`使用時に**全体のページ数**を取得してレスポンスしたかったので、その方法についてまとめます。

# 手順
再利用できるよう、consernsにモジュールとして切り出しておきます。
`kaminari`では、`Article.page(1).total_pages`のように`total_pages`を使うことで全体のページ数を取得することができます。

```ruby:app/controllers/concerns/pagination.rb
module Pagination
  extend ActiveSupport::Concern

  def pagination(records)
    {
      total_pages: records.total_pages # 全体のページ数
    }
  end
end
```

`meta: pagination(articles)`で`pagination`を呼び出し、`meta`キーを配下として値を時データを参照ができ、最終的に`adapter: :json`で`articles`と一緒にレスポンスできるようにします。

```ruby
class Api::V1::ArticlesController < Api::V1::BaseController
  include Pagination
  def index
    articles = Article.published.order(created_at: :desc).page(params[:page] || 1).per(10).includes(:user)
    render json: articles, meta: pagination(articles), adapter: :json
  end
end
```

```json:レスポンス
{
  "articles": [
    {
      "id": 30,
      "title": "タイトル",
      "content": "本文",
    }
  ],
  "meta": {
    "total_pages": 3
  }
}
```
【ABC334】コンテストメモ【AtCoder】

## はじめに
毎週取り組んでいる「AtCoder Beginner Contest」の感想・まとめをこちらの記事に散文的にまとめていきます。

:::note warn
使用言語はC++
:::

:::note warn
「未着手」は手を付けていない問題。
「未提出」は手を付けたけれど提出はしていない問題。
:::

## 結果
- 順位: 8412th / 11231
- 点数: 100 (1)
- 時間: 7:29
- pef: 132相当
- R: 169 → 165 (-4)
- 完問数:1完 A

## 問題別評価

### A問題
- AC(1) 2:29
- [実行結果](https://atcoder.jp/contests/abc334/editorial/8985)

[A - Christmas Present](https://atcoder.jp/contests/abc334/tasks/abc334_a)
[公式解説 by yuto1115](https://atcoder.jp/contests/abc334/editorial/8984)
簡単な条件分岐。個人的にAtCoderのA問題のなかで一番簡単だった。


### B問題
- 未提出

[B - Christmas Trees](https://atcoder.jp/contests/abc334/tasks/abc334_b)
[公式解説 by yuto1115](https://atcoder.jp/contests/abc334/editorial/8984)
B問題にしては難しすぎる気がする。発想自体は合っていたけれどうまく処理できなかった。
数学に落とし込むことまでは理解できたがそのあと脳内が散らかってしまった。演習量が足りない。

### C問題
- TLE(1)
- [実行結果](https://atcoder.jp/contests/abc334/submissions/48790047)

[C - Socks 2](https://atcoder.jp/contests/abc334/tasks/abc334_c)
[公式解説 by yuto1115](https://atcoder.jp/contests/abc334/editorial/8983)
TLEくやしすぎる。偶数のときは隣同士をペアにしたほうがよいのは直観的に理解した。
上記にその証明がかかれているため確認してほしい。
問題は奇数のときにどのように整理するか。累積和を使用することで簡単に処理することが可能だった。思いつけただけで悔しかった。

### D問題
- 未着手

[D - Reindeer and Sleigh](https://atcoder.jp/contests/abc334/tasks/abc334_d)
[公式解説 by cn449](https://atcoder.jp/contests/abc334/editorial/8986)
D問題まで見れなかった。BCよりもDの方が解けそうだったなと反省。難易度順に並んでいないことがあるので詰まってしまった場合は先の問題を解く癖をつけた方が良い。受験数学のときと一緒。

### E問題
- 未着手

[E - Christmas Color Grid 1](https://atcoder.jp/contests/abc334/tasks/abc334_e)
[公式解説 by cn449](https://atcoder.jp/contests/abc334/editorial/8987)
競プロおなじみのグラフ問題。競プロをやる以上、避けては通れない。でもいまではない。

### F問題
- 未着手

[F - Christmas Present 2](https://atcoder.jp/contests/abc334/tasks/abc334_f)
[公式解説 by yuto1115](https://atcoder.jp/contests/abc334/editorial/8982)
グラフ問題。分かりません。

### G問題
- 未着手

[問題文](https://atcoder.jp/contests/abc334/tasks/abc334_g)
[公式解説 by cn449](https://atcoder.jp/contests/abc334/editorial/8980)
E問題と似ている問題。グラフ問題。分かりません。

## 総評・まとめ
BCの難易度が予想より高く、苦戦してしまった。
E問題以降はグラフ問題が多くなる傾向があるのかもしれない。直近の目標は緑pefなのでABCDを解きたい。グラフの問題はいったん後回しにしてまずは目の前の全探索や簡単なアルゴリズムを勉強していこうと恩う。
【Unity初歩】Asset Storeを使って🎄を感じるゲームにする

# はじめに
本日はクリスマスイブということで、これまで作ってきた🦀と🦐によるマ◯オみたいなゲームにクリスマスっぽい装飾をつけてみました。

前回の記事

https://qiita.com/usomaru/items/00fe664286afcd905c12

# Asset Storeの使い方

Window > Asset Storeを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201826/dc20ab9e-741a-033f-97d8-d3e4b3f756eb.png)

「Search online」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201826/14f07a4b-ed72-40cc-05f8-92201187ae16.png)

すると、Asset Storeがブラウザで立ち上がります。(New Year Saleやってた)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201826/c0b31069-acdb-b7ba-9636-adb30ef9153e.png)

2D Christmasで検索して良さげなのがないか見てみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201826/fe8928ef-865a-ec6b-c9e7-cf4aecfccffa.png)

無料のものを試してみたかったので、こちらをとりあえず入れてみました。
「Add to My Assets」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201826/85270b14-328c-2d80-8098-e36a1eca0705.png)

追加が終わったら「Open in Unity」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201826/be88f398-d9e4-3105-e5ba-a7e4f947c1f0.png)

この画面が立ち上がるので、「Download」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201826/f19e7d7b-9d47-8341-af8c-1d2ee0945c67.png)

右上の「Import」をクリックすると、「Import Unity Package」というウィンドウが立ち上がるので、その画面の「Import」をさらにクリック。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201826/8e756536-d558-5f34-19db-e2d20072fb74.png)

Assetsに追加されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201826/06534737-a8bb-f08f-98b1-7b28447cad40.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201826/b650fc8c-bfef-e4a5-df74-0900b0eb9f7f.png)

あとの使い方はこれまでの背景やオブジェクトを追加してきた時と同じです。

ついでに音楽も追加してみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201826/7c1aa25c-602a-186d-f2f3-b9ae91135f75.png)

今回は効果音ではなく、BGMとして流したいため、Hierarchyで右クリック > Audio > Audio Sourceを選択して追加しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201826/f1742a6d-fe16-d084-47f1-f536bbe3c228.png)

効果音のときと同じく、ここに流したい音楽を設定してあげればおーけー👌

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201826/256b76e9-449b-9eeb-7f9e-352cc6307307.png)

# できたもの
※音が鳴るので注意
クリア後の画面にも音楽を鳴らしてあげればよかった。。。🎅

https://twitter.com/usomaru26/status/1738755278714380553

# おわりに
無料のAssetでもいい感じのものが多くあるので、簡単に気持ちリッチなゲームができました🎄
TI-Python と micro:bit の連携について

# はじめに 

TI の電卓のちょっとユニークなところとして、[TI-Innovator™ Hub](https://education.ti.com/en-ph/products/micro-controller/ti-innovator)や[TI-Innovator™ Rover](https://education.ti.com/en-ph/products/micro-controller/ti-innovator-rover)などで電子工作っぽいことやロボット制御ができます。

その中でも、比較的安価に取り組みやすい micro:bit との連携機能を試してみます。micro:bitと連携できれば、TI-84 Plus CE Python から micro:bit をリモートコントロールしたり、micro:bit に繋いだセンサーの値を TI-84 Plus CE Python に取り込んでグラフ表示できたりします。

# micro:bit ファームウェアの更新

[こちら](https://education.ti.com/en/product-resources/microbit)のサイトで `BBC microbit files and documents_CE_Python.zip` をダウンロードして展開します。micro:bit のバージョンにより、次の展開後のファイルを micro:bit にインストールします。インストール方法は、いつもどおり、micro:bitをUSBケーブルでPCに繋いでマウントされるストレージにファイルをコピーするだけです。

* micro;bit V1: `Use on Version 1 microbit Card/TI_Runtime/ti_runtime_1.0.0.hex`
* micro:bit V2: `Use on Version 2 microbit Card/TI_Runtime/ti_runtime_3.2.0.hex`

インストールが終わると、micro:bit のマトリックス LED が TI のロゴっぽく点灯します。

![IMG_7230.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/05231e3e-c990-b769-9298-c9b83ed9635f.jpeg)

# mico:bit用アドオンのインストール

micro:bit のバージョンにより、次のファイルを TI-84 Plus CE Python にインストールします。インストールは TI Connect CE のファイル一覧画面にドラッグ＆ドロップするだけです。

* micro;bit V1: `Use on Version 1 microbit Card/Modules-version 1.0.0/*.8xv`
* micro:bit V2: `Use on Version 2 microbit Card/Modules 2.1.0/*.8xv`


# TI-84 Plus CE Pythonとの接続

micro:bit との接続には Micro USB-B to USB mini-B の USB OTG ケーブルが必要とのことですが、TI-84 Plus CE Python には付属していません。なので、Amazon で探して[こちら](https://www.amazon.co.jp/gp/product/B06XHHFNRX)を購入しました。

今回、micro:bit V2 に Grave のアダプターを用いて、Grave の Ultrasonic Ranger を繋いでみました。

![IMG_7231.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/11486323-9ddf-91b8-f4cd-0dad322279d9.jpeg)

# スクリプト

次のスクリプトは、micro:bit から Ultrasonic Ranger の値を取り込んで、ti_plotlib でグラフ表示するスクリプトです。

```python
import ti_plotlib as plt
from ti_system import *
from microbit import *
from mb_grove import *
from mb_pins import *

plt.cls()
plt.window(-1,10,-10,100)
plt.grid(1,10,"dash")
plt.axes("on")
plt.labels("sec","cm",11,3)
plt.title("X vs Time Motion Graph")
plt.color(255,0,0)

for i in range(40):
  d=grove.read_ranger_cm(pin0)
  t=i*.25
  sleep(250)
  plt.plot(t,d,"o")
plt.show_plot()
```

実行結果です。きちんと Ultrasonic Ranger の値が取り込めてます。

![Capture1-1703386203283.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/fda9e1e2-1d03-1dd5-6f9d-d2f2b05ab807.png)
Rubyのクラスとインスタンスについて

## 概要
自分自身が初めてクラスとインスタンスを学習した際に苦労したため、その際にメモしたものをアウトプットの練習を兼ねて記事にしました。
自分自身まだまだ知識が浅く間違いがあるかもしれませんが、その際は優しくご指摘・アドバイス頂けると幸いです。
よろしくお願いします。

### クラスとインスタンスの概要
クラスとインスタンスの関係は設計図とその設計図から作られた実物体というような説明がよくされます。
これは後々でてくる`new`メソッドを使ったインスタンスの作成方法の部分で上記の説明がわかると思います。
クラスから作られたインスタンスは共通の性質を持ちながらも、そのインスタンスごとに特有の性質を持たせることができるようになります。

### クラスの定義方法
クラスの定義には`class`というキーワードを使います。
例えば`Human`クラスというクラスを作るとします。
```ruby
class Human
    # このなかにクラスのメソッドや持たせたいデータを書いていく
end
```

### インスタンスの作成方法
インスタンスは先ほどのクラスに対して`new`メソッドを呼び出すことで作成できます。
`Human.new`とするだけです。
これによりクラスからインスタンスを作成することができます。
また、インスタンスの作成時に使えるメソッドとして`initialize`メソッドがあります。
このメソッドはインスタンスの作成時に自動で呼び出すことができるメソッドです。
```ruby
class Human
    # このなかにクラスのメソッドや持たせたいデータを書いていく
    def initialize
        #インスタンス生成時に実行したい処理を書く
    end
end
```

### インスタンス変数とインスタンスメソッド
インスタンス変数はインスタンスごとに保持できる値を変えられる変数になります。
また、インスタンスメソッドはクラスのインスタンスに対して呼び出せるメソッドです。
```ruby
class Human
    # このなかにクラスのメソッドや持たせたいデータを書いていく
    def initialize(name)
        # インスタンス生成時に実行したい処理を書く
        # インスタンス変数
        @name = name
    end
    # インスタンスメソッド
    def show_name
        puts @name
    end
end
```
インスタンス変数とインスタンスメソッドを定義すると上記のようなコードになります。

### アクセサメソッド
Rubyでゲッターとセッターを定義する際に便利な`attr_accessor`メソッドというものがあります。
```ruby
def クラス名
  attr_accessor :age 
end
```
上記のように変数を書くことによりゲッターとセッターを自動で定義してくれます。
【ChatGPT有＋DALL-E3】作品です。プロンプト共有。


　どうも、カーブミラーです。
　ちょっと早いですけど、メリークリスマス。
![DALL·E 2023-12-22 22.53.39 - Santa Claus holding a cue card that reads “Merry Christmas”. The setting is a cozy, festive room with Christmas decorations like a tree, lights, and s.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/6f43fa0d-3828-4cbb-c889-0ac0ba92fe3e.png)

　自作の作品です。プロンプト共有しましょう。今回は、だまし絵です。

:::note info
本記事は、ChatGPT＋DALL-E3で、
作品を作っています。あしからず。
:::

　まずは、
　　作品をどうぞ。
![DALL·E 2023-12-24 11.36.32 - A highly detailed anamorphic drawing of a dragon on a flat sheet of paper, placed on a wooden table. This optical illusion drawing is designed to make.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/3e7514f1-39ee-3609-bcea-26f5dadee661.png)

　これは、だまし絵です。

　だまし絵とは、何か。
***
***GoogleSGE***
だまし絵とは、実物と見まがうほど写実的な絵画のことです。また、トロンプルイユ（仏：Trompe-l'œil）とも呼ばれています。
﻿
だまし絵は、視覚的な錯覚を利用した隠し絵で、本来描かれているものが、見方によって別のものに見える絵です。
﻿
だまし絵は、古代ギリシャ絵画にみられ、ルネサンス期では建築物の壁面に大理石の模様や彫刻作品を描き込むなどの表現も行われていました。
﻿
芸術の形態の一つであるシュルレアリスム（超現実主義）でよく使われた手法や技法で、マウリッツ・エッシャー「Maurits Cornelis Escher」などがいる。
﻿
最近では解りやすく「トリックアート」と呼ばれる事も多くあります。﻿﻿
***
　だまし絵について知りたければ。
　　ウィキペディアを参照することを
　　　おすすめします。

　ちなみに、
　　今回のだまし絵は、
　　　シンプルなものです。
***
　さて、プロンプトです。

　なお、ここでは、みなさんへの
　　プロンプトのシェアを
　　　目的にしますので、
　　　　ドラゴンに限らず描画できる
　　　　　形にしておきました。

　ターゲットを
　　ドラゴンにすれば、
　　　上記画像のようになります。
```Text:
下記プロンプトに従って、描画。
[keyword: ターゲット] 
The realistic anamorphic drawing of [keyword] on a flat sheet of paper placed on a wooden table creates an optical illusion in which [keyword] appears to emerge from the paper in three dimensions. The drawings are extremely detailed and capture [keyword]'s unique characteristics, texture, and form. The use of shadow and light emphasizes the three-dimensionality and makes [keyword] look like the real thing. To allow the viewer to concentrate on the anamorphic work, the background noise is kept to a minimum and the drawing is flat on a wooden table.
```
***
***日本語***
[キーワード：ターゲット］ 
木のテーブルの上に置かれた平らな紙に描かれた[keyword]のリアルなアナモフィック・ドローイングは、[keyword]が紙から立体的に浮かび上がって見える目の錯覚を引き起こす。 ドローイングは非常に細かく、[keyword]のユニークな特徴、質感、形をとらえている。 影と光を使うことで立体感を強調し、[keyword]を本物のように見せている。 見る人がアナモフィックな作品に集中できるように、背景のノイズは最小限に抑えられ、ドローイングは木製のテーブルの上に平らに置かれている。
***

　色鉛筆での彩色を頼むと、
　　こんな感じになります。
![DALL·E 2023-12-24 11.36.40 - A highly detailed anamorphic drawing of a dragon, colored with colored pencils on a flat sheet of paper, placed on a wooden table. The drawing creates.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/6bd792e0-3909-e4eb-28a8-1148c3723786.png)

　みなさんも
　　いい作品を
　　　生み出してください。

　今回は、ここまで。
初心者がGASを触ってみた

GASはどういうことができるかも知っているし社内でも活用されていることは知っている。
ただ、自分はJavaも分からないしまずJavaをちゃんと勉強しないと使えないだろう…と思っていました。
先日、既に社内の他の方が作ってくださったGASをベースに少し修正して新たなGASを作る機会がありました！
そのため、コード面での実装は別にせよ、GASをいじったりすることでどう動かせるのかについては学びました。
今日は初心者がGASを触ってみた記録です。

# ざっくりGASとは
GAS＝Google Apps Script（[Apps Script](https://workspace.google.co.jp/intl/ja/products/apps-script/)）
Googleが開発し、提供しているプログラミング言語。
GASはJava Scriptをベースに作られている。
Googleサービスとの連携が可能なので、業務でGoogleを使っている場合は業務効率化ができるようになる。

ちなみに私自身はJava Scriptを学んだことがなく、知識がないという状態です…。

# 今回やりたいこと
*  通常は閲覧権限を絞っているPDFがあり、Googleフォームでの申請してきた人のみに閲覧権限を付与する
*  また、その閲覧権限は一日ではく奪したい
*  Googleフォームでの申請内容はslackに連携する

# 実際にGASを触ってみる
GASのスクリプトエディタの編集画面へ飛ぶには、
今回だったらトリガーにしたいGoogleフォームの編集画面の画像赤枠のところに「<>スクリプトエディタ」とあるのでここをクリックすることで飛べます。

![GASの開き方.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654142/7d357f57-77fa-1824-2588-e53786ca7bb6.png)
*  エディタのタブでファイルを作って実装するコードを記載する
*  トリガーの設定
今回、Googleフォームで送信されたことをトリガーにしたいので、フォーム送信時に関数を動かすようトリガーを設定。（画像2行目）
ここの関数ではslack通知/ドライブにあるPDFを呼び出して権限付与等を行っている。
![トリガー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654142/c2a7785b-2008-deac-d28e-93ebf10d78d5.png)
*  閲覧権限を日次で削除
上記トリガーの画像1行目の詳細が以下。
日次ベースで時刻を設定したイベントを設定することで、hidePDFの関数が毎日午後11時～午前0時に実行される。
これでhidePDFの中で記載している、日次での閲覧権限削除が実行される。
![日次.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654142/9c5be6c8-53b3-d129-9221-b4af5a71a6a3.png)
*  実行数のタブでは処理が完了したか失敗したか、失敗した際にはエラーメッセージが出る

# エラーでつまずいたときは…
ベースとなるGASは既にあるのでそれを真似して作るも、コードに馴染みがない私にとってはエラーが出るとつまずきます。
「わー何で；；」とここで少し投げ出したくなったりします。
そんな時にこれって何がどう間違っているの？というのはChatGPTに聞いたりしました。
コードについて知識が浅いので、このエラーってどういう意味だ？と思った時には、今までだと一個一個をいろんなサイトで調べたりして「こういうことか！」とまで腹落ちするには時間がかかります。
そんな時に、今回初めてChatGPTを使いましたが、エラーの内容とかをパッと答えてくれてめちゃくちゃ便利…！


# 最後に
GASを使えば様々な面で業務効率化ができるなと改めて実感しました。
コードの面ではまだまだ勉強が必要で、今回はあまり触れなかったですが、今後勉強して実装できるようになりたい。
オブジェクト指向について

# オブジェクト指向の３つの概念

### 1\. オブジェクト指向とは
いかに効率良く開発を行うかを突き詰めた考え方

### 2\. オブジェクト指向に必要な3つの概念
以下の３つはオブジェクト指向における設計に必要な３つの概念です。
『カプセル化』
『継承』
『ポリモーフィズム』

### 3\. カプセル化

**他のプログラムに干渉しない（されない）** という概念です。

 例えば、自動車クラスのプログラムに変更を加えたら自転車クラスのプログラムに影響が出てしまうことが無いように、自動車と自転車それぞれのクラスを隔離するという考え方です。


 ### 4\. 継承

**同じようなプログラムはまとめる**　という概念です。

例えば、バス、トラック、スポーツカーの共通点は車であるという点です。
従って、それぞれに共通しているもの（タイヤやエンジン等）は1つにまとめましょうという考え方です。

### 5\. ポリモーフィズム

**汎用的な形にできるようにする** という概念です。
日本語では多様性や、多態性と表現されます。

継承という概念では車という共通の部分に着目しましたが、ポリモーフィズムでは同じ車でもバス、トラック、スポーツカーそれぞれの異なる機能に対応できるよう汎用的な形にしましょうという考え方です。

### まとめ
今回オブジェクト指向を初めて学習しましたが、プログラムを設計する段階で実装した後のことも考えることが重要だと知りました。
自身で設計する際には迷うことも多いですが、今後プログラムを設計する際にはオブジェクト指向を意識しながら理解を深めていきたいです。


#### 参照資料
https://www.youtube.com/watch?v=SjwbqGK-H1o
TerraformでAWS LambdaをNode.js 20へアップグレードする方法

先日AWSから **『[アクションが必要です] AWS Lambda での Node.js 16 のサポート終了について』** というタイトルのメールを受け取ったので、早速アップグレードを試みたのですが、Terraform初心者としてハマるところが多かったので、備忘録としての投稿です。


# 前提
今回の例は、以前Terraformで構築したNode.js 16のAWS Lambdaを、Node.js 20に更新するものです。
またTerraformは当初、1.4.4を使用していました。


# LambdaのNode.js Runtimeが更新できない！
AWSからのメールにあった`2024 年 6 月 12 日までに、既存の Node.js 16 の関数を Node.js 20 にアップグレードすることをお勧めします。`の指示に従い、aws_lambda_functionのruntimeを`nodejs16.x`から`nodejs20.x`に変更し、terraformのコマンドを実行したところ…

![Upgradeエラー1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92580/3c34446c-8bd9-7604-3736-411dcb2dc968.png)

nodejs20.xがサポートされていないように見える？


# Terraformのupdate情報を確認する
本稿執筆時点で、Terraformの最新版が1.6.6とのことだったので、1.4.4から1.6.6にアップグレードして再度トライしてみましたが、エラーメッセージは変わらず。

terraform-provider-awsのchangelogを確認すると、2023/11/16リリースの5.26.0でnodejs20.xが追加されたことを確認。
https://github.com/hashicorp/terraform-provider-aws/blob/5deca6413355b80d737a33f646223798dc0af2cc/CHANGELOG.md?plain=1#L233

一方でTerraformの1.6.6は2023/12/13リリースなので、Terraformのミスとは考えづらい。
https://github.com/hashicorp/terraform/releases/tag/v1.6.6

terraform-provider-awsを別途指定する方法があると考えるのが自然かも？


# 灯台下暗し
terraform-provider-awsを指定できないか？と思いながら改めてterraformのバージョンを確認していたところ、

![Upgradeエラー2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92580/54ad518a-fb92-5a98-9e9b-6c75c89a8413.png)

**provider_registry.terraform.io/hashicorp/aws v4.63.0**

君だったのか！と気付き、Terraformの設定に以下を追加。（上述のterraform-provider-awsの情報に合わせ、5.26.0以上としました。）

```HCL
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.26.0"
    }
  }
}
```

早速Terraformコマンドを実行したところ、

![Upgradeエラー3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92580/5caeee44-e8e3-ad2d-b5f6-de1dd4474044.png)

指示された通り`terraform init -upgrade`を実行したところ、aws_lambda_functionのruntimeにnodejs20.xを指定できるようになりました。


# 所感
今回のトラブルシューティングを含め、昨今Google検索だけでは必要な情報を見つけられない印象が自分の中にあります。昨今は、以下のように情報収集して問題解決することが増えてきています。

1. 当該ツール・アプリのGitHubリポジトリを確認する。
	- Issue・changelog・テストコードに、欲しい情報が見つかることが多いです。
2. エラーメッセージを詳細に確認する。
	- 単純なバージョン情報や、隅の方に表示されているメッセージが、案外キーになっていることが昨今多いかも。
＜R2＞リテイク観点、Org・オブジェクト（ライセンスは要確認）・レポート


## :zipper_mouth: リテイク２観点 :zipper_mouth:
・時間はかりながら90分のシナリオを解く
・時間かかりそうなものはスキップしてQAでリカバリ
・どう解釈したからこう回答したというプレゼン
・データモデルと移行要件、ガバナンスは飛ばし、アクセス要件は少し読む。（たまにトランスレーションワークベンチなどあるため）:zipper_mouth:
・Orgをどう決めたか、ざっくりER、俯瞰図、ソリューションに回答を書く :zipper_mouth:
・「どう解釈したから、こう回答したよ」と話すこと。


## Org戦略の観点
### Chatterの利用
・組織が分かれるとChatterでやり取りできない。
・代替はSlack、Teamsなど
### 標準レポートの利用
・その組織のデータを参照する。マルチだとレポートに含められない。
### 規制要件
・国ごとの権限が厳しく１Orgにできない、セキュリティ上Orgを分ける必要があるケース
### データ件数（顧客も数十万件程度）
・データ件数が多すぎるとマルチオルグも検討（そうするとガバナに抵触しづらくなる）
### データ連携や認証
・マルチオルグだとマスタの持ち方やSSO、ルーティングなど、複雑なポイントが増える
### ガバナンス
・1Orgのほうが移送難易度が高い（ほかのアプリへの影響を考慮）、マルチのほうがシンプル。
### その他
・トランスレーションワークベンチやマルチ通貨を使い、他言語・他通貨対応する。（1Orgの理由に利用）
　※マルチ通貨は商談の完了予定日でその時点の価格が決まる。

 ## オブジェクト（簡易）※最終試験ではもっと細かく理解必要　
### SalesCloud/ServiceCloud/FieldService
・1→N
・赤：主従関係
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/450298/3ff485e8-355b-2590-944e-ae631737b8ef.png)



 ## 分析要件のPros／Cons：要有識者確認
しっかり、XXだからCRM Analyticsにしました、という説明をすること。
 
 |# | 実装方針 | 適応要件 |
|:-----------:|:------------:|:------------|
| 1       | 標準レポート       | 組織内のデータを分析する場合。サマリレポート、リストなど。|
| 2     | 分析スナップショット  | 定期的に別テーブルに断面を保持するので、トレンドレポートを見たいケース。※2,000件までしか1度にスナップショットできないなどの制限あり。  |
| 3       | CRM Analytics      | 標準レポートではタイムアウトしかねないLDVデータの分析、外部システムのデータソース含めた分析、アドホックな分析など高度なユーザビリティを求めているケース、断面の明細をドリルダウンしたいケース、すべての（大量）データの傾向分析をしたい、BIツールのユースケース    |
| 4       | Einsteinディスカバリー      |  ビジネスデータに関するインサイトを識別し、表面化して視覚化するための統計モデリングと機械学習により、ビジネスインテリジェンスを増強するものです  |
Enumチートシートからマップリストの値の操作を学ぶ④ - side-effects

こんにちは！
プログラミング未経験文系出身、Elixirの国に迷い込んだ？！見習いアルケミストのaliceと申します。
今回はマップリストのデータの操作についてEnumチートシートを写経して学んだことをまとめます。
本記事side-effects(副作用が無い関数群)についてです。

https://hexdocs.pm/elixir/main/enum-cheat.html#side-effects

# 目的
マップリストの値の操作ができるように様々な関数を知りたい。

## 実行環境
Windows 11 ＋ WSL2 ＋ Ubuntu 22.04
Elixir v1.14.3
Erlang v26.0.2

# 前提
本シリーズは下記でscaffold生成されたPhoenix+LiveViewのプロジェクトを使用しています。
```bash:bash
mix phx.new dec23
cd dec23
mix ecto.create
mix phx.gen.live Users User users name:string age:integer
# 生成されたroutingをrouter.exに記載
mix ecto.migrate
```

# 元データ
```diff_elixir:iex
iex(1)> users = Dec23.Users.list_users
[debug] QUERY OK source="users" db=1.7ms idle=1572.5ms
SELECT u0."id", u0."name", u0."age", u0."inserted_at", u0."updated_at" FROM "users" AS u0 []
↳ :erl_eval.do_apply/7, at: erl_eval.erl:746
[
  %Dec23.Users.User{
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    id: 1,
    name: "santa",
    age: 100,
    inserted_at: ~U[2023-12-23 09:06:44Z],
    updated_at: ~U[2023-12-23 09:06:44Z]
  },
  %Dec23.Users.User{
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    id: 2,
    name: "reindeer",
    age: 55,
    inserted_at: ~U[2023-12-23 09:07:18Z],
    updated_at: ~U[2023-12-23 09:07:18Z]
  },
  %Dec23.Users.User{
    __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
    id: 3,
    name: "dwarf",
    age: 39,
    inserted_at: ~U[2023-12-23 09:07:44Z],
    updated_at: ~U[2023-12-23 09:07:44Z]
  }
]
```


# Enumチートシートとは？
Enumチートシートというものがあります。

https://hexdocs.pm/elixir/main/enum-cheat.html

下記のマップリストを例にしたチートシートです。
幸運なことに元データと同じデータ構造をしています！
```diff_elixir
cart = [
  %{fruit: "apple", count: 3},
  %{fruit: "banana", count: 1},
  %{fruit: "orange", count: 6}
]
```
というわけでこれを写経してみました。

# Enum.each
第一引数の要素を順番に取り出す。
取り出した各要素に第二引数の関数処理をするが`:ok`が出力される。
つまり、元データに対して副作用が無い。

https://hexdocs.pm/elixir/main/Enum.html#each/2

## お手本の写経
```diff_elixir:iex
Enum.each(cart, &IO.puts(&1.fruit))

apple #IO.putsにより出力されたもの
banana #IO.putsにより出力されたもの
orange #IO.putsにより出力されたもの
:ok
```

## 自分のケースでの演習
```diff_elixir:iex
users |> Enum.each(& IO.puts(&1.name))
santa #IO.putsにより出力されたもの
reindeer #IO.putsにより出力されたもの
dwarf #IO.putsにより出力されたもの
:ok
```

# ～Elixirの国のご案内～
↓Elixirって何ぞや？と思ったらこちらもどぞ。Elixirは先端のアレコレをだいたい全部できちゃいます:laughing::sparkles::sparkles:

https://qiita.com/piacerex/items/09876caa1e17169ec5e1

↓ゼロからElixirを始めるなら「エリクサーチ」がおすすめ！私もエンジニア未経験から学習中です。

https://elixir-lang.info/topics/entry_column


↓[We Are The Alchemists, my friends!:bouquet:](https://qiita.com/torifukukaiou/items/6bcd5bbb80df9e594e9e "Awesome-san's Awesome article")[^10]
Elixirコミュニティは本当に優しくて温かい人たちばかり！
私が挫折せずにいられるのもこの恵まれた環境のおかげです。
まずは気軽にコミュニティを訪れてみてください。[^11]


https://speakerdeck.com/elijo/elixirkomiyunitei-falsebu-kifang-guo-nei-onrainbian


[^10]: @torifukukaiouさんのAwesomeな名言をお借りしました。Elixirコミュニティを一言で表すと、これに尽きます。


[^11]: @kn339264さんの素敵なスライドをお借りしました。Elixirコミュニティはいろんな形で活動中！