OmniAICreator/Qiita-1.07M huggingface dataset:
AWS勉強備忘録23 - Amazon S3のセキュリティ対策（パブリック or Not）

Amazon Simple Storage Service（Amazon S3）は、AWSが提供する耐久性とスケーラビリティに優れたオブジェクトストレージサービスです。データのバックアップ、アーカイブ、ウェブサイトのコンテンツなど、さまざまな用途で利用されています。

## S3バケットのパブリックアクセス

S3バケットをパブリックに設定することで、ウェブサイトのホスティングやファイル共有などに利用することができます。しかし、機密情報を含むバケットを誤ってパブリックに設定すると、データ漏洩のリスクがあります。

### パブリックアクセスの制御

- **パブリックアクセスブロック**: S3ダッシュボードからパブリックアクセスブロック設定を有効にすることで、バケットのパブリックアクセスを防ぐことができます。
- **バケットポリシー**: バケットポリシーを使用して、特定のIPアドレスやAWSアカウントからのアクセスのみを許可するように設定することができます。

## IAMとアクセスポリシーによるセキュリティ強化

AWSのIAM（Identity and Access Management）を利用することで、S3バケットへのアクセスを細かく制御することが可能です。

### アプリケーションレベルのアクセス制御

アプリケーションは、ログインシステムやセッション管理など、自身の認証・認可システムを備えています。ユーザーがログインすると、アプリケーションはそのユーザーの権限に基づいて、どのデータにアクセスできるかを決定します。たとえば、自分の投稿や友達の投稿の表示、写真のアップロードなどです。

### サービス側でのアクセス管理

アプリケーションサーバー側では、IAMロールやアクセスポリシーを使用して、サーバーシステムがAWSリソース（S3バケットやデータベースなど）にアクセスする権限を管理します。これにより、アプリケーションのバックエンドが必要なリソースに安全にアクセスできるようになりますが、このプロセスは透過的で、エンドユーザーには直接関係ありません。

### 例：写真のアップロードと共有

一般ユーザーが写真をアップロードする場合、アプリケーションはユーザーの認証情報を確認し、写真をS3バケットに保存するためのリクエストをサーバーに送信します。このプロセスで、サーバーがAWSリソースにアクセスする際にIAMロールが利用されますが、ユーザー個々にIAMロールが割り当てられるわけではありません。代わりに、サービス自体が操作を代行し、ユーザーのアクセス権限はアプリケーションのロジックで管理されます。


### 署名付きURLの利用

- 公開が必要なコンテンツに対しては、署名付きURLを生成して、一時的にアクセスを許可する方法があります。これにより、限られた時間内でのみコンテンツへのアクセスを許可することができます。

## まとめ

Amazon S3は非常に強力なストレージサービスですが、セキュリティ設定には注意が必要です。適切なアクセス制御を行い、機密情報の漏洩を防ぐために、パブリックアクセスブロック設定やIAMポリシーの利用を推奨します。
AWS SysOpe対策 コスト管理ツール

# はじめに
AWS試験の中の一つであるSysOpsアドミニストレーター アソシエイトには様々な
コスト管理ツールが出てきます。
- AWS Budgets
- AWS Cost and Usage Report
- AWS Cost Explorer

これらのサービスの主な特徴についてまとめました。

# AWS Budgets
AWS Budgets は、AWS のリソース使用量とコストを管理するためのツールです。

- カスタム予算設定
  月や年単位特定の時間枠で予算を設定可能です。また、タグを使用して特定のプロジェクトやチームごとの予算作成もできます。
- アラート通知
  予算の設定に対して、特定の閾値を超えるとアラート通知を受け取ることが可能です。さらに閾値を超えた時、アラート通知以外にもIAMポリシーの適用や特定のEC2インスタンスの停止といったアクションなども実行できます。

# AWS Cost and Usage Report
AWS Cost and Usage Report は、AWS アカウントのコストと使用状況に関する詳細な情報を提供するレポートです。

- カスタマイズ可能なレポート
  ユーザーは、特定の期間やリソースに関するカスタマイズ可能なレポートを作成できます。これにより、特定のリソースのコストや使用状況を詳細に分析できます。

- CSV 形式のダウンロード
 レポートは CSV 形式でダウンロードでき、他のツールやソフトウェアでの分析や処理が容易になります。

- リアルタイム更新
 レポートはリアルタイムで更新されるため、常に最新のデータを確認できます。

# AWS Cost Explorer
AWS Cost Explorer は、AWS のコストと使用状況を可視化するためのツールです。

- コストの視覚化
 グラフやチャートを使用して、コストと使用状況を視覚化できます。これにより、コストのトレンドやパターンを把握しやすくなります。

- フィルタリングとグループ化
 Cost Explorerを使用して、データをフィルタリングやグループ化して分析することができます。リージョン、サービス、タグなどの要因に基づいてデータを表示できます。

- 予測と比較
 将来のコストの予測や、過去のコストとの比較を行うことができます。これにより、コストの予測と効果的なコスト管理が可能になります。

# まとめ
AWSのコスト管理ツールについてまとめました。
各サービスの特徴を抑えてSysOps試験に挑みます。
Docker で Selenium を動かす

# はじめに
ブラウザの自動操作を試してみたかったので、コンテナで環境を構築しました。
使用ブラウザは Chrome で Python の Selenium を採用しています。

### フォルダ構成
```
.
├── app.py
├── docker-compose.yml
├── Dockerfile
└── requirements.txt
```


### Dockerfile
```
FROM python:3

RUN sh -c 'echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' && \
    wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
    apt update && \
    apt install google-chrome-stable -y

COPY app.py .
COPY requirements.txt .

RUN pip install --upgrade -r requirements.txt

CMD ["python", "app.py"]
```

Chrome を apt コマンドでインストールします。
Python パッケージは requirements.txt を参照して pip 経由でインストールします。



### requirements.txt

```
selenium-wire
chromedriver-binary-auto
```
pip でインストールする python パッケージは管理しやすいように requirements.txt に記述しておきます。

今回は HAR ファイルも取得するようにしたかったため、selenium を拡張するパッケージである selenium-wire ライブラリを使用します。
HAR ファイルはブラウザのネットワークアクティビティを記録したものとなります。

ChromeDriver はインストールしている Chrome のバージョンに合わせる必要があります。
chromedriver-binary-auto パッケージを入れれば自動でインストールされている Chrome のバージョンに合わせたものをインストールしてくれるので便利です。

https://pypi.org/project/chromedriver-binary-auto/


### docker-compose.yml
HAR ファイルの保存場所として、ローカル端末の harfile ディレクトリをマウントしておきます。

```
version: '3'
services:
  chrome-selenium:
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
      - ./harfile:/home/harfile
```


### app.py

今回はサンプルなので、阿部寛の HP にアクセスしておきます。
```
from seleniumwire import webdriver
from selenium.webdriver import ChromeOptions
import chromedriver_binary

options = ChromeOptions()
options.add_argument("--headless")
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")

sw_options = {
    'enable_har': True
}

url = "http://abehiroshi.la.coocan.jp/"

driver = webdriver.Chrome(options=options, seleniumwire_options=sw_options)
driver.get(url)

print(driver.title)
print(driver.current_url)

with open('/home/harfile/test.har', mode='w') as f:
    f.write(driver.har)

driver.quit()
```


## 動作確認
docker compose build でビルドしたあとに、起動してみます。
指定した URL にアクセスして、タイトルが取得できています。
```
$ docker compose up
[+] Running 1/0
 ✔ Container test-chrome-selenium-1  Created                           
Attaching to test-chrome-selenium-1
test-chrome-selenium-1  | 阿部寛のホームページ
test-chrome-selenium-1  | http://abehiroshi.la.coocan.jp/
```

ローカル端末の harfile ディレクトリに test.har が作成されています。
HAR ファイルはブラウザの開発者ツールに読み込ませると内容が簡単に確認できます。
ブラウザからどのような通信が行われているのか確認できます。
指定した URL に GET リクエストを行って、関連したファイルも取得していることを確認できました。

![スクリーンショット 2024-03-25 170250.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3115963/08c06897-5150-c24b-92a0-ca26d383373a.png)

# おわりに
今回は環境構築を行ったので、次回は何かしらのサイトの UI 自動化を試してみたいと思います。
ログインが必要なサイトの認証の突破とかを試したいなと考えています。
Golangのパッケージレベル変数と関数レベル変数の違い

Golangでは、パッケージレベル変数と関数レベル変数は異なるスコープと目的を持ちます。

### パッケージレベル変数:

- スコープ:

パッケージレベル変数は関数の外、つまり関数の中ではなく、通常はGoソースファイルの一番上に宣言されます。
同じパッケージ内のすべての関数からアクセスできます。
パッケージがインポートされるときに初期化されます。

- 初期化:

パッケージがロードされるときに初期化され、パッケージ内の関数が呼び出される前に初期化されます。
明示的な初期化が必要です。初期化されていない場合、ゼロ値が割り当てられます。

- 使用法:

パッケージ全体で共有されるデータや設定などの値を保持するために使用されます。
同じパッケージ内の異なる関数間でデータを共有するのに役立ちます。

### 関数レベル変数:

- スコープ:

関数レベル変数は関数内で宣言され、その関数内でのみアクセス可能です。
他の関数からはアクセスできません。
- 初期化:

関数が呼び出されるたびに初期化されます。
初期化はオプションですが、初期化されていない場合、ゼロ値が割り当てられます。
- 使用法:

関数内でのみ必要な一時的なデータを保持するために使用されます。
特定の関数のローカルスコープでのみアクセス可能であり、他の関数に影響を与えません。

### 変数定義の種類

- var キーワードを使用した変数定義:

var キーワードを使用して変数を定義します。この方法では、変数の型を指定することができますが、初期値は与えられません。

```go

var age int
var name string
var isStudent bool
```

- 短い変数宣言（Short Variable Declaration） `:=` :

短い変数宣言 := を使用して変数を定義および初期化します。この方法では、変数の型は右辺の値から推論されます。

```go
age := 30
name := "John"
isStudent := true
```
ただし、この方法は関数内でのみ使用できます。

- 明示的な型指定付きの変数定義:

変数の型を明示的に指定して変数を定義し、必要に応じて初期化します。

```go
var temperature float64 = 25.5
var country string = "USA"
var (
	a, b int    = 5, 3
	c    string = "Hello"
)
```
この方法は、変数の型を明示的に指定する場合や、パッケージレベルの変数を定義する場合に使用されます。

- ゼロ値（Zero Value）:

変数が初期化されない場合、その変数には型に応じたゼロ値が割り当てられます。数値型のゼロ値は 0、文字列型のゼロ値は空の文字列 ""、ブール型のゼロ値は false です。

```go
var num int    // num には 0 が割り当てられる
var text string  // text には空の文字列が割り当てられる
var flag bool   // flag には false が割り当てられる
```

### 例:

```go
package main

import "fmt"

// パッケージレベル変数
var packageVar int = 100

func main() {
    // 関数レベル変数
    var localVar int = 50
    fmt.Println("Package-level variable:", packageVar)
    fmt.Println("Function-level variable:", localVar)
}
```
このコードでは、`packageVar` はパッケージレベルの変数であり、`localVar` は関数レベルの変数です。`packageVar` は `main` 関数の外で宣言されており、`main` 関数の内部である `localVar` とは異なるスコープを持っています。


https://go.dev/play/p/jTRWnIkTzWs
AWS Lambda でカスタムレイヤーを追加する方法

# 概要
- Lambdaで何かしらの処理を行いたい時、デフォルトだとインストールされていないパッケージを使う場合は、レイヤーをアタッチする必要がある
- Lambdaを使うとき、基本的に必要になる作業なので、自分のやり方を備忘として残す

# 手順
## 1. ローカルで必要なパッケージをまとめる
- レイヤーに含めたいパッケージを仮想環境にインストール
```shell-session
python3 -m venv venv
source venv/bin/activate
pip install package-name
```

- 「__pythonという名前__」のディレクトリにパッケージを詰めてzipファイルにする
    - __pythonという名前である必要がある__（任意ではないことに注意）
    - 仮想環境の具体的なpathはそのときのローカルの状況次第
```shell-session
mkdir -p layer/python
cp -r venv/lib/python3.10/site-packages/* layer/python/
cd layer
zip -r my_layer.zip python
```

※ 原因をきちんと調べていないが、カスタムレイヤーにboto3を含めてしまうとlambda側で呼び出した時に`Error: Runtime exited with error: signal: segmentation fault"`が起きて失敗する場合があるのでboto3を抜いたバージョンのレイヤーを作った方が良い（lambdaではデフォルトでboto3を使うことができる）

## 2. S3にzipファイルを送る
- 個人内で再利用する際に、色々と便利なので、S3を使う方法が気に入っている
- S3への送信方法は手動、AWS CLI等々、色々とあり得るが、下記のようなboto3を使ったpythonスクリプトで送れる
    - 環境変数にAWS認証情報等が含まれている前提

```python
# send_file_to_s3.py

import argparse
import boto3
import os


def upload_file_to_s3(local_file_path: str, object_name: str) -> None:
    """Upload file to S3"""
    s3_client = boto3.client(
        "s3",
        aws_access_key_id=os.getenv("AWS_ACCESS_KEY_ID"),
        aws_secret_access_key=os.getenv("AWS_SECRET_ACCESS_KEY"),
    )
    s3_client.upload_file(local_file_path, os.getenv("BUCKET_NAME"), object_name)


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("local_file_path")
    parser.add_argument("object_name")
    args = parser.parse_args()
    upload_file_to_s3(args.local_file_path, args.object_name)

```

- 下記の要領で実行し、指定したバケットにzipを送る
```shell-session
python send_file_to_s3.py your-local-path/my_layer.zip my_layer.zip
```


## 3. カスタムレイヤーを作る
- S3に送ったzipファイルを用いてカスタムレイヤーを作る
- マネジメントコンソールにおいて、簡単に作成できる（Lambda > Layers > Create layer）
![スクリーンショット 2024-03-30 22.42.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3554168/bdcb5853-5cd5-bd87-66e9-f65bd5abacfa.png)
- 入力項目
    - Name: 適当に
    - Description: 適当に
    - 「Upload a file from Amazon S3」を選択
    - Amazon S3 link URL: アップロードしたS3バケットのzipファイルを見にいくとObject URLを見つけることができる（S3 URIではないことに注意）
    - Compatible architectures: アタッチしたいLambda関数を作成する際に選んだものと同じものである必要がある
    - Compatible runtimes: アタッチしたいLambda関数を作成する際に選んだものと同じものである必要がある


## 4. レイヤーをアタッチする
- そのレイヤーをアタッチしたいLambda関数のページにて、レイヤーを追加する（Lambda > Functions > your-function-name > Layer > Add a layer）
![スクリーンショット 2024-03-30 22.51.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3554168/cff95a05-257f-d566-bf74-a5ffaf82b62a.png)

- 先ほど追加したレイヤーを選ぶ

![スクリーンショット 2024-03-30 22.51.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3554168/c567a49a-d1fa-21ba-55b7-2fd49bd89007.png)

- 入力項目
    - Layer source: Custom layersを選ぶ
    - Custom layers: 正しくCompatibleなRuntimeとArchitectureでレイヤーを作成できていれば、ドロップダウンのリストで自分の作成したレイヤーを選べる
    - Addする
AtCoder初心者振り返りメモ ABC347

# ABC347の回
https://atcoder.jp/contests/abc347
# A-問題
https://atcoder.jp/contests/abc347/tasks/abc347_a

[問題文]
正整数 N,K 及び長さ N の数列A=(A1,A2,…,AN) が与えられます。
A に含まれる要素のうち、K の倍数であるもののみを全て取り出し、それらをK で割って出力してください。


[考察や感想]
リストの値 A[i] % K ==  0 で判定し、Kの倍数の場合は
Kで割った商を出力しました。


````Python:A.py
N,K = map(int,input().split())
A = list(map(int, input().split()))

ans = []
for i in A:
    # Kで割り切れる場合は、Kで割った商を ans へ格納する
    if i % K == 0:
        ans.append(i//K)

print(*ans)

````
# B-問題
https://atcoder.jp/contests/abc347/tasks/abc347_a

[問題文]
英小文字からなる文字列 S が与えられます。S の空でない部分文字列は何種類ありますか？

ただし、部分文字列とは連続する部分列のことを指します。例えば、xxx は yxxxy の部分文字列ですが、xxyxx の部分文字列ではありません。

[考察や感想]
先頭から 文字数（1,2,・・・,L）で順に部分文字列を切り取って格納しますが、空（null)を除くというヒントを記述するのと重複を除去するためにsetを使いました。

````Python:B.py
S = input()

L = len(S)

# set に格納して重複をなくす
ST = set()

# 先頭から 文字数（1,2,・・・,L）で順に部分文字列を切り取って格納する
# null の場合は、除外する
for i in range(1,L+1):
    for j in range(0,L+1):
        c = S[j:i]
        if c != "":
            ST.add(c)

print(len(ST))
````
ABC347をPythonで（A～E）

AtCoder Beginner Contest 347の解答等のまとめです

https://atcoder.jp/contests/abc347

# A問題
問題文のことをそのままする。
なおAtcoderでは、空白区切りは改行区切りで提出しても正解になる
```python:A
n, k = map(int, input().split())

for a_i in map(int, input().split()):
    if a_i % k == 0:
        print(a_i // k)
```
# B問題
全通り試す
```python:B
s = input()

a = set()

for j in range(len(s) + 1):
    for i in range(j):
        a.add(s[i:j])

print(len(a))
```
# C問題
どれかが休日初日のときに全部休みか調べる
1. 全部を$a+b$で割ったあまりにしてソートする
1. 一番大きいのと小さいのとの差が$a$未満ならOK
1. 一番小さいのに$a+b$を足して一番大きくする

コードは少しややこしいことをしているが$i-1$を見ればいい
```python:C
n, a, b = map(int, input().split())
d = list(map(int, input().split()))

x = [d_i % (a + b) for d_i in d]
x.sort()

ans = "No"
for i in range(n):
    j = (i + n - 1) % n
    if x[j] - x[i] < a:
        ans = "Yes"
    x[i] += a + b

print(ans)
```
# D問題
$C$で立っているビットは片方でしか立たない
→$C$で立っていないところは$X,Y$両方立つか立たない
上の条件で成立する数があるか調べる
```python:D
a, b, C = map(int, input().split())
c = C
z = [0] * 60
for i in range(59, -1, -1):
    z[i] = c % 2
    c //= 2

count = z.count(1)
if (a + b - count) % 2 == 1:
    exit(print(-1))

d = (a + b - count) // 2
x_count = a - d
y_count = b - d

if x_count < 0 or y_count < 0:
    exit(print(-1))

w = [0] * 60
for i in range(60):
    if z[i] == 0 and d > 0:
        w[i] = 1
        d -= 1

x, y = ["0"] * 60, ["0"] * 60
for i in range(60):
    if w[i] == 1:
        x[i] = "1"
        y[i] = "1"
    elif z[i] == 1:
        if x_count > 0:
            x[i] = "1"
            x_count -= 1
        else:
            y[i] = "1"

X, Y = int("".join(x), 2), int("".join(y), 2)

if X ^ Y == C and x.count("1") == a and y.count("1") == b:
    print(X, Y)
else:
    print(-1)
```
# E問題

まず$i$番目の種類数を調べておく
種類数の累積和$S$を利用して
$S[i$が偶数回目に出たところ$] - S[i$が奇数回目に出たところ]
の総和を求めればいい
```python:E
n, q = map(int, input().split())
x = list(map(int, input().split()))

a = [0] * q
d = dict()
s = set()
for i, x_i in enumerate(x):
    if x_i not in d:
        d[x_i] = []
    d[x_i].append(i)

    if x_i in s:
        s.discard(x_i)
    else:
        s.add(x_i)
    a[i] = len(s)

b = [0]
for a_i in a:
    b.append(b[-1] + a_i)

ans = [0] * n
for key in d.keys():
    if len(d[key]) % 2 == 1:
        d[key].append(len(b) - 1)
    for i, j in zip(d[key][::2], d[key][1::2]):
        ans[key - 1] += b[j] - b[i]

print(*ans)
```
巨大テキストファイルを比較をする

## はじめに
データベースのデータを定期的にバックアップしている際、前回のバックアップファイルと今回のバックアップファイルに差分がないか確認したくなる機会があるのではないでしょうか。通常はそれほど大きなファイルではないので、テキストエディタで開いて目視で確認するのが一般的な方法です。しかし今回、各ファイルのサイズがおよそ10GBと非常に大きかったため、一般的なテキストエディタではファイルを開くことすらできませんでした。そこで、ターミナルで利用できるdiffコマンドを使って差分を確認することにしました。

## diffコマンド

``` bash
diff --side-by-side --width=[文字数] --suppress-common-lines  --speed-large-files a.txt b.txt | tee diff.log
```

`--side-by-side` 
    このオプションを付けると、diffは2つのファイルの差分を横に並べて表示します。変更のあった行では、ファイル1の内容が左側に、ファイル2の内容が右側に表示されます。このように横に並べて表示すると、変更箇所が一目でわかりやすくなります。
`--width=[文字数]`
この引数で表示する行の最大文字数を指定できます。デフォルトでは130文字ですが、今回は120文字に設定しています。使用するターミナルや画面サイズに合わせて見える最大の文字数を指定するのが良いかと思います。
`--suppress-common-lines` 
2つのファイルで共通の行が存在する場合、デフォルトではその共通の行も表示されます。しかし、差分を確認する際は共通の行は不要なので、このオプションを付けることでそれらの行を表示しないようにできます。
`--speed-large-files` 
通常、diffはファイル全体をメモリに読み込んでから処理を行います。しかし、大きなファイルの場合、メモリ不足でクラッシュする可能性があります。このオプションを付けると、diffはファイルの一部分ずつをメモリに読み込むようになり、大きなファイルでも安全に処理できるようになります。
`| tee diff.log`
この部分はパイプとteeコマンドを組み合わせたものです。diffコマンドの出力結果を標準出力に加えて、diff.logファイルにも書き出すことができます。これにより、結果を他のエディタで見やすい形にして確認することができます。

最初は `-u`オプションをつかって差分を確認するようにできないか試していましたが、1行の文字数がとても膨大なためターミナルの出力では確認が非常にやりにくく、`--side-by-side`オプションを使用して可能な限り見える範囲で差分を探すことにしてみました。差分があった行を詳しく確認したくなった際は、表示されている文字から検索をかけて特定しています。

## 余談：他に試した方法
### GUIベースの差分確認ツール
 - CompareMerge
 - FileMerge
 
どちらも10GBを超えるファイルを開くことができずにクラッシュしてしまいました。
### GitHubにファイルをアップロード
GitHubのアップロード上限があることが判明し、この方法も断念。

### ファイルを分割して差分を確認する
データベース全体ではなく、テーブル単位でバックアップを取ることで、ファイルサイズを小さくできるかもしれません。しかし、今回は実行せずに終わりました。
RTX830　pppoe接続/ipoe接続してみた

ipoe接続
https://network.yamaha.com/setting/router_firewall/flets/flets_other_service/ipv6_ipoe

ppoe接続
契約した回線の情報必須
https://network.yamaha.com/setting/router_firewall/flets/flets_other_service/internet

●結果
両方できた。2つ接続している状態になった。
l2tpipsecはpppoe接続。lan内の通信はipoe接続で分けたいけど、それは別記事で検証
SafariのTabキー操作が思うようにできなかったのでChromeと同じようにした話

## これはなに

先日Firefoxでの対応を記事にしました

https://qiita.com/gilly/items/83c80dcf4a2c8d04e84a

そういえばMacbookのSafariでも同じような設定をしたので、解消方法の覚書を記事に残しておこうと思います。

## デフォルトではTabキーでフォーカスが当たる場所が限られている

デフォルトの状態ではSafariでTabキー操作をした場合、フォーカスが当たる要素はChromeとは異なります。
Safariのデフォルトだと 文字に入力ができるinput要素だけにフォーカスが当たるようでした。

リンクやボタンにはフォーカスが当たってくれません。

## Tabキーでリンクにフォーカスが当たるようにする方法

Chromeと同じようにリンクにもフォーカスが当たるように設定を変更します。

1. Ssafariの「環境設定」を開く
    - ショートカット `⌘,` でも開けます
1. 「詳細タブ」の「アクセシビリティ」セクションの「Tabキーを押したときにWebページ上の各項目を強調表示」にチェックを入れる
![Safariの環境設定タブの詳細タブのスクリーンショット](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215239/fa5b0fff-9ec3-9d0d-423d-32e674ba3530.png)

以上で、リンクやボタンもフォーカス対象になり、Chromeと同じような挙動になります

---

ちなみにiPadでのTabキー操作のフォーカスについては下記の記事にまとめています。

https://qiita.com/gilly/items/18f4f5d26c1e26ca71c8

この記事が誰かのお役に立てれば幸いです。
[備忘録]GitHubに初期コミットをpushしようとしたらリポジトリが見つからないと言われた

# 背景
プログラマなんだし、いい加減 GitHub を使ってみようと思って初めてのリポジトリを作成したら少しハマった

# TL;DR
GitHubのリポジトリへ接続するにはアクセストークンが必要

2024/03/31 追記
アクセストークンが必要となるのはhttps接続しようとしていたためで、
ssh接続すればこんなことしなくても大丈夫でした。
ご助言いただいた @raki様 誠にありがとうございました。
* ssh接続参考

https://qiita.com/hollyhock0518/items/a3fee20951cd92c87ed9

# 動作環境
* Windows 10 Home
* Git for windows

# 前提
* GitHubアカウント作成済み
* プッシュ先のリポジトリ作成済み
* ローカルブランチ名は「main」

# 現象
GitHubにリモートリポジトリを作成し、pushしようとしたら、リポジトリが見つからないと言われた

```bash
$ git remote add origin https://github.com/{Account}/{Project}.git
$ git push -u origin main
remote: Repository not found.
fatal: repository 'https://github.com/{Account}/{Project}.git' not found
```
# 原因
GitHubのリポジトリへのアクセスにはアクセストークンが必要らしい

# 解決方法
アクセストークンを作成、アクセストークを使用してGitHubへアクセスする。
1\. アクセストークンを作成
* GitHubにログイン
* 画面右上のユーザアイコンをクリックし、[Settings]を選択
![画面上部メニュー](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2747533/1966e061-70ae-9e63-5dfd-a31168ddd927.png)
![GitHub_Settings.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2747533/c9fdd66f-89dc-94fa-a05e-b7f2d909b280.png)
* 左メニューの一番下、[Developer settings]を選択
![GitHub_DevelopersSetting.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2747533/fd6bce91-65ba-524c-54ab-f925da92bfe6.png)
* [Personal access tokens]-[Tokens(classic)]を選択
* [Generate new token]-[Generate new token(classic)]を選択
![Tokens.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2747533/87f55dad-946d-2fc9-889b-eccc76f0ea81.png)

:::note info
「Fine-grained personal access tokens」に比べて「Personal access tokens(classic)」は安全性が低くなるが一部機能は「Personal access tokens(classic)」でのみ動作する
:::
* トークンの設定を行う 
 Note:トークンの用途を記載
 Expiration:有効期限を設定、デフォルトは30日、今回はとりあえずデフォルト
 Select scopes:トークンのアクセス権限設定、リポジトリへのアクセス権限は最低限[repo]を選択すれば大丈夫
* [Generate token]をクリック
![TokenSetting.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2747533/a2a29c27-6ecc-12c8-0f60-69d9d461f003.png)

* トークン(ghp_xxxxxxxx)が表示されるのでコピペ
![token_copy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2747533/f08e4aa8-4ca5-8cc7-f9e6-a1f091e287c7.png)

:::note warn
トークンは一度しか表示されないため、コピペを忘れないこと
:::
2\. アクセストークンを使用してGitHubへアクセス
```bash
# 作成済みのリモートリポジトリ削除
$ git rm origin
# トークン有でリモートリポジトリ追加
# {Token}に先程コピーしたトークンを入れる
# {Token}の後に「@」を入れるのを忘れないこと
$ git remote add origin https://{Token}@github.com/{Account}/{Project}.git/
# リモートリポジトリにpush
$ git push -u origin main
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 237 bytes | 237.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
To https://github.com/{Account}/{Project}.git
 * [new branch]      main -> main
branch 'main' set up to track 'origin/main'.
```
# あとがき
GitHubの案内通りにやってもハマるんだなぁ
# 参考元
https://www.tohoho-web.com/ex/github.html#make-access-token

https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#personal-access-tokens-classic
【2024年】Homebrew経由でGitをインストールする方法【Mac】


Udemyの「はじめてのGitとGitHub」講座を開始。
Gitのインストールから必要でしたが、講座内容が最新の情報ではないため、動画の通りにいかず苦戦しました。

自分なりに調べてインストールし、無事GitとGitHubの講座を継続できたので、振り返り含めアウトプットとして記録に残します。

## MacにGitがインストールされているか

まず、ターミナルを開いて自分のmacにgitが入っているか確認する。

>ターミナルとは「パソコンを文字で操作するリモコン」のようなもの。
>
>[【超初心者向け】ターミナルとは？Macの便利ツールを徹底解説](https://www.sejuku.net/blog/10977)

デスクトップにあるフォルダをダブルクリックで開いて中のファイルにアクセスするのが当たり前と思っていた身としては、命令文で操作できるなんてことに驚いた。

:::note
前者をGUI=グラフィカルユーザーインターフェース
後者をCUI=キャラクターユーザーインターフェースと言う。
:::

Macの場合、

`Finder ⇨ アプリケーション ⇨ ユーティリティ ⇨　ターミナル.app`

これで辿り着ける。

ターミナルを起動すると初期画面は下のように出る。

```
Last login: 日付
ユーザーネーム@haruharuQiis-MacBook ~ % 
```

Udemyの動画では入力最初の記号が「＄」だったので、$から入力していて全く進まなかった！笑

:::note
この記号(%や$)はプロンプトと言って入力操作できることを表す
:::

%の後からGit versionと入力すると、インストールされていないよとなる。

## Gitをダウンロードしに行く

[Git](https://git-scm.com/)からダウンロードをする。

![スクリーンショット 2024-03-23 20.22.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3690542/4497f885-06c1-ec00-8728-f7b60cd02d36.png)

ダウンロードをクリック、自分のOSをクリック

![スクリーンショット 2024-03-23 20.30.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3690542/0f2132ed-2ce0-bae8-8be1-292f8a572d4e.png)

この画面になる。
（ここでも動画と違い、なかなか簡単にはインストールさせてくれない...）

インストールする方法のオプションが多すぎる！！！

最も最新verがDLでき、パッケージ管理ができるHomebrew経由でインストールをする。

## Homebrewをインストールする

オプションの中から[Homebrew](https://brew.sh/)をクリックしてサイトへ飛ぶ。

![スクリーンショット 2024-03-23 20.33.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3690542/49332867-20d5-e925-45bc-0847ef007bf7.png)

どこかのバーのようなサイトに飛び、「Install Hoembrew」の下にあるコードをターミナルへコピペ

```

ユーザーネーム@haruharuQiis-MacBook ~ % /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
==> Checking for `sudo` access (which may request your password)...
Password:

```

passwordを要求されるため、パソコンのログイン時パスワードを入力。

enterでインストールが開始される。

途中で一旦止まるので再度enterキーを押す。

```
==> Installation successful!
```
これでインストール完了

```
==> Next steps:
- Run these two commands in your terminal to add Homebrew to your PATH: (echo; echo 'eval "$(/opt/homebrew/bin/brew shellenv)"') ›› /Users/ユーザー名/ zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"
- Run brew help to get started
- Further documentation:
https://docs.brew.sh

```

Next stepsが指示されるので従う。

PATHを通せと言われる。

>PATHを通すとはプログラムを簡単に名称だけで実行できるようにすること
>[【環境構築 入門】PATHの通し方 – Windows11, M1 Mac 対応 –](https://www.kikagaku.co.jp/kikagaku-blog/path/)

'eval $(/opt/homebrew/bin/brew shellenv)' >> /Users/ユーザー名/.zprofile
eval $(/opt/homebrew/bin/brew shellenv)

を貼り付ける。

私はここでecho以下を〜〜shellenv)"までを入力すればいいとわかったけど、'eval 〜〜〜 shellenv)"部分をそのままコピペしたら

```
zsh: parse error near `)'
```

エラーメッセージが出るし、'の後の)を外してもエラーが出るし、５回くらいやり直し、なんとか通った。

ユーザー名＠ユーザー名MacBook ~ %が表示されたら、

```
~ % brew help
```

と入力し、ヘルプの案内が表示されれば終了！

## やっとGitをインストール

ターミナルのユーザー名　~ %の後に

```
~ % brew install git
```

と入力するとインストールが開始する。

終了するとユーザー名 ~ % が表示され、入力可能状態となるので

```
~ % git version
```

これでバージョン情報が出力されれば終了！

## まとめ

年単位では大きく仕様が変更していることがあるため、講座選ぶときには新しい情報かどうかも重要なんだなという学びになった。

ただ、自分は調べることはそんなに苦痛ではなかった。

知らないことが多いため、１つの疑問から周辺知識も気になって調べ始めると終わらなくなるのは課題。
React typeScriptで勉強時間記録サイトを作成する初心者#2

こんにちは！！

私はエンジニア転職を目指して勉強しております。。

前回の記事で学習記録サイトを作成してポートフォリオ、プログラミング学習を進めることを宣言しています、

今回は学習記録サイトに必要な機能、技術をまとめます。
調べ、知識が不足しているもの、のちに必要となるものは随時更新していければと思いますので、暖かい目で見ていたでければと思います😭😭

_1. 作成サイト_
学習記録サイト、アプリ

_2. 使用技術_
・フロントエンド: React,typeScript
・バックエンド: pythonでやろうかなと:rolling_eyes:
・データベース: mySQL
・バージョン管理: Git,Github
他必要な技術あれば追加する。

_3. 主な機能_
・学習内容をフォームに入力しドロップダウンメニューに追加して選択できるようにする。
・学習時間を記録できる。
　:::note info
手入力又は、ストップウォッチ機能で測定した時間を記録。
:::
・メモ
・ユーザー登録、ログイン/ログアウト、コメント、いいね、タグ、フォロー

内容と時間を分野別に分けて月単位でグラフに表示する機能があると視覚的にどの程度学習したか分かりやすいと思うので、まずは突き詰めすぎずに簡単な機能を実装して行きたいと思います！！

最後に、私は仕事をしながらエンジニア転職の為にプログラミング学習をしています。このような境遇の方、全てのプログラミングに関わる方と共に頑張りたいと思うので少しでも良いかもなと思っていただけたら、いいなボタンを押していただけると励みになります。:writing_hand:気を引き締めて毎日頑張りたいと思います！！
[UnrealEngine5]ダッシュ機能

# 概要
Enhanced Input機能でShiftキーが押されている間プレイヤーがダッシュする機能を実装します。
合わせてTimeline機能を使って速度がなだらかに変化するようにします。

<blockquote class="twitter-tweet" data-media-max-width="560"><p lang="ja" dir="ltr">Qiita投稿しました🐓<br>[UnrealEngine5]ダッシュ機能<a href="https://t.co/nSbrXWlQSK">https://t.co/nSbrXWlQSK</a><a href="https://twitter.com/hashtag/Qiita?src=hash&amp;ref_src=twsrc%5Etfw">#Qiita</a> <a href="https://twitter.com/hashtag/UnrealEngine5?src=hash&amp;ref_src=twsrc%5Etfw">#UnrealEngine5</a> <a href="https://twitter.com/hashtag/UE5?src=hash&amp;ref_src=twsrc%5Etfw">#UE5</a> <a href="https://t.co/3XMU6lnXfL">pic.twitter.com/3XMU6lnXfL</a></p>&mdash; kazuma (@kazuma_f) <a href="https://twitter.com/kazuma_f/status/1774056311661187280?ref_src=twsrc%5Etfw">March 30, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 本文
今回はファーストパーソンテンプレートで新規作成してプレイヤーキャラにダッシュ機能を追加しました。
## Enhanced InputでShiftキーを設定
Input Mapping Context
![スクリーンショット 2024-03-30 211624.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/7e465d0e-955f-7131-fdfd-6f7f17ae58ab.png)

Input Action
![スクリーンショット 2024-03-30 211526.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/e8dd8137-75ed-a869-1e9a-55c6332ebe54.png)

## プレイヤーキャラのブループリント(今回はBP_FirstPersonCharacter)を変更
Event BeginPlayでプレイヤーの初期速度を設定
![スクリーンショット 2024-03-30 211402.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/e0654de0-d636-aa80-7c40-116fc0b85b62.png)
Shiftキーをトリガーにして速度を変更します。
![スクリーンショット 2024-03-30 211410.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/cbe99778-3361-b5f3-df46-35db981c83c9.png)
タイムラインを設定。時間0の値は0で最後の時間で1に設定します。
![スクリーンショット 2024-03-30 211428.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/00a3f5ec-0cd0-dcbf-7b6c-c9e6f6f20328.png)
色変えシステムの超便利なスクリプトをChatGPT君が作ってくれたお話

<h1>はじめに</h1>
みなさんこんにちは！
今回はChatGPT君が滅茶苦茶使えるスクリプトを作成してくれたので、その紹介をします！
Unityでゲームを開発している方は、是非活用してください！

<h1>経緯</h1>
ゲーム開発中のある日、テキストの色を変える方法を探していました。

(Unityの色指定について詳しく書かれている記事です)

https://qiita.com/Hal_mai/items/1469398078e81bc7ef27


Unityではオブジェクトの色を細かく変えたいとき、RGBAを指定して変えます。

```C#
new Color32(100, 100, 50, 1);
```

ただ、これだと4つも数値を指定しなくてはいけないのでめんどくさいです。
折角、Unity側が16進数のカラーコードを提供してくれているのに、16進数で色を指定することはできないようです・・・。

そこで、ChatGPTに「16進数で色を指定したい」と言ったところ以下のように回答してくれました。

<h1>ChatGPTの回答</h1>

「Unityでは、テキストの色を16進数で直接指定することはできませんが、RGB値を使用してカラーを指定することができます。RGB値は0から1の範囲で指定され、各色成分（赤、緑、青）はそれぞれの割合を示します。

しかし、16進数のカラーコードを使用することもできます。そのために、次のようなカスタム関数を使用して、16進数のカラーコードをUnityのColorオブジェクトに変換します。」

```C#
using UnityEngine;

public static class ColorExtensions
{
    public static Color FromHex(string hex)
    {
        hex = hex.Replace("#", "");
        byte r = byte.Parse(hex.Substring(0, 2), System.Globalization.NumberStyles.HexNumber);
        byte g = byte.Parse(hex.Substring(2, 2), System.Globalization.NumberStyles.HexNumber);
        byte b = byte.Parse(hex.Substring(4, 2), System.Globalization.NumberStyles.HexNumber);
        return new Color32(r, g, b, 255);
    }
}
```

「これで、16進数のカラーコードを ColorExtensions.FromHex("#RRGGBB") のように使用して、UnityのColorオブジェクトに変換することができます。

例えば、"#FF0000" は赤、"#00FF00" は緑、"#0000FF" は青です。これらの値を使用して、次のようにテキストの色を設定できます。」

```C#
using UnityEngine;
using UnityEngine.UI;

public class Example : MonoBehaviour
{
    public Text text;

    void Start()
    {
        text.color = ColorExtensions.FromHex("#FF0000"); // 赤色のテキスト
    }
}
```
「このようにして、16進数のカラーコードを使用してUnityのテキストの色を指定することができます。」

このスクリプトを見たときの感想は「天才か？」でした。
このスクリプトのお陰で、16進数のカラーコードだけで色を指定できるため、作業効率が格段に向上しました。
しかもColorExtensions関数はstatic変数で宣言されているので、プロジェクトのどこでも使用することが可能です。

<h1>おわりに</h1>

いかがでしょうか？
ChatGPT君がこんなに使える関数を作ってくれるとは正直思っていませんでした。
また、static変数を駆使すればさらに使える機能を作れると思ったので、もっと勉強したいと思います・・・。

是非、Unityでゲーム作りをしている方は使ってみてください！
副業をするまでの記録

# はじめに
私は会社員でシステムエンジニアとして働いています。普段はマネジメント側の業務が多いので物作りの経験をもっと積んで、マネジメントと別の強みを付けたいです。そこで副業でホームページ制作を始めたいと考えています。
HTML、CSS、JavaScriptの実務経験が乏しいので、まずはそれらの基礎的な知識の習得〜ポートフォリオ作成をしてから仕事の募集をする予定です。
この記事では私が副業を始めるまでの記録をしていきます。

2025/01/17
主にモチベーションが原因で手がつかず、完全に計画が破綻していました。再計画して最後までやり切りたいです。

# 目標
~~2024/09が終わるまでに副業収入が3万円/月となること。~~
2025/05末までに副業収入が3万円/月となること。

# 計画
2024/03　HTML/CSSのUdemy講座受講
[ウェブ開発入門完全攻略コース - HTML/CSS/JavaScript. プログラミングをはじめて学び創れる人へ！](https://www.udemy.com/share/101WGM3@5V_D-F8JD4gmDM_694zjecFvDdk1grEmfb7rW0m-1R2CN6h9VLx8gCGvPWRhlPwj/)
→完了
~2024/04中旬　JavaScriptのUdemy講座受講
[JavaScriptをとことんやってみよう【超初心者から脱初心者へレベルアップ】【わかりやすさ重視】](https://www.udemy.com/share/102QNO3@6QLwQnkj67e8uQ8WW9y9kfWW7n0hutMJS0wgZiKroG_YN1Rwq2UamJCUdygWA7s2/)
→完了
~2024/04　Webページの模写
→2024/04/24 計画を変更します。
    実際のwebページはudemyなどで見たものよりずっと複雑なことを実感しました。
    ページを作る流れを勉強したいので[無料コーディング練習所](https://webdesigner-go.com/coding-practice/)で練習します。完了予定は4月中予定。
→2024/05/07 計画を変更します。
    無料コーディング練習所が意外と手強く、4月中には完了しませんでした。
    5/17完了を目指します。
~~2024/05　ポートフォリオ作成~~
2025/02 ポートフォリオ作成
2025/04 初案件を獲得

下記動画を参考にさせていただき、計画をNotionのタイムラインビューを使って立てました。
[【テンプレ無料配布】Notion でガントチャート（WBS）を作る方法](https://youtu.be/Uk5QRqwgXHI?si=306Q9fE3520DJVYc)
![スクリーンショット 2025-01-19 10.05.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245072/3ae05844-e404-c93e-2993-c679567430f6.png)



# 今の気持ち
2024/03/30
ふわふわな計画な気がしていますが随時アップデートしていけばよいと思っています。
2024/04/01
仕事はクラウドワークスで探す予定です。応募者のポートフォリオを見ていると自分ができるようになるのか不安になりますがやってみようと思います。
2024/04/06
本業が立て込んできました。週末にリカバリします。
2024/04/14
ここまで予定通りにできています。
2024/10/09
予定から大きく遅れていて未だにポートフォリオ作りに着手できていないです。
ポートフォリオに載せるネタとなるアプリを作成しています。
2025/01/19
大日程〜小日程まで立て直して少し前進できました。継続していきます。
リストアップしたファイル以外を消すWindowsバッチ

# 経緯
最近では珍しいオートメイション化が全く進んでいない（あとなんかごちゃごちゃしてる）現場があったのですぐ使えるようにソースを記述しておく事にした。

# 使用用途</summary>
<p>１、なんか無駄に使わないファイルがごっそり入ったフォルダから対象を絞るの面倒！</p>
<p>２、運用フォルダから探してる時にうっかり開いたりしたらいやだ！</p>
<p>３、ローカルに丸ごとコピーしたけど見つからないし名前が間際しくて整理に時間が掛かる</p>
そんな限定的な時に使えるコード


```deleteFile.bat
@echo off
setlocal enabledelayedexpansion

rem リストファイルのパスを指定します。
set "list_file=list_file.txt"


rem リストファイルが存在するかどうかを確認します。
if not exist "%list_file%" (
    echo リストファイルが見つかりませんでした。
    pause
    exit /b
)

rem リストファイル内のファイル名を読み込みます。
set "found_files="
for /f "delims=" %%f in ('type "%list_file%"') do (
    set "found_files=!found_files! %%f"
)

rem カレントディレクトリ内のファイルをリストアップし、削除するかどうかを決定します。
for /f "delims=" %%i in ('dir /b /a-d') do (
    rem ファイル名がリストファイル内に存在するかどうかを確認します。
    echo !found_files! | findstr /i /r /c:"%%~ni" >nul
    if !errorlevel! equ 0 (
        echo Keeping "%%i"
    ) else (
        echo Deleting "%%i"
        del "%%i"
    )
)

endlocal
pause
```


```list_file.txt
deleteFile.bat
list_file.txt
↓に残しておきたいファイルを拡張子含めて記述しておく。
```
<br>
ほんとは前方一致とか検索に幅を持たせたり、batファイルとリストファイルを除外して他のファイルを消すようにしたかったけどこんな限定的な使い道なツールに時間かけたくなかったので妥協。
削除対象を消したいときとかもKeepingとDeleting部分のdelを移動させれば応用できるしちょっとしたツールとして使う分にはいいよね！

# 注意
・削除なので使う場合はテスト用フォルダを作ってその中で動かしてから使う事！
・誤って削除を行った場合、一切の責任を負いません。
AppRouter の server side で path query や search params を取得する方法

## 背景

App Router になってから、 server side での **pathQuery** や **searchParams** の取得方法が変わった.

client side なら 

```ts
import {useSearchParams} from "next/navigation
```

で済むのだが、 server 側がわからずちょっと詰まった

## 解決方法 と 実装例

Next.js は page から default で排出された module に対して props を渡している.
この props は Next.js が用意した型定義はなく, 実装者が自前で実装する

```tsx
// /app/[id]/page.tsx

interface Props {
  params: Record<"id", string>;
  searchParams: Record<string, string | string[] | undefined>
}

export default function Page(props: Props) {
  const {id} = props.params;

  return (
    <main>
       ...
    </main>
  );
}

```

> Next.js 公式 (これをなかなか見つけられなかった)
> https://nextjs.org/docs/app/api-reference/file-conventions/page#searchparams-optional

----

抽象度を高めて型定義するなら

```ts
interface NextPageProps<T extends string = never> {
  params: Record<T, string>;
  searchParams: Record<string, string | string[] | undefined>
}

// 利用例
type Props = NextPageProps<'id'>;

```
Rustの返り値について

# returnがなくてびっくりする
Rustでは以下のようなコードが成立する
```rust
fn add(a: u32, b: u32) -> u32{
	a+b
}
```
Rust初学者からするとこれはびっくりするし、なんだか気持ち悪く感じる
これが成立する理由は、**最後の式で評価された値が戻り値になる**という言語仕様のためである

# 式とは
Rustでは、ほとんどのコードが何らかの値を返す**式(Expression)で**あり、式は**値を生成する**ために評価される
式でないすべては、文(Statement)とされる
セミコロン`;`を付けることで、ExpressionをStatementにすることができる


## 勘違いポイント
たいていの言語で、例えば`if`は文である。しかし、Rustでは**式**となる
そのため、以下のようなコードも成り立つ
```rust
let a = if a < 0 { 0 } else { a };
```
ifの結果が値として評価されている、つまり式であるということになる

以下のようなスコープも式となる
```rust
{
	a+1;
	a*a
}
```
セミコロンのついている`a+1;`は文であり、スコープの最後で現れるの`a*a`が式である。スコープ全体としても式であり、最後の式の値を表す

# 関数の戻り値 
初めに触れたように、Rustでは**最後の式**が戻り値になる。そのため関数を以下のように書ける。他の言語と比較して、何が式であるかを意識する必要がある
```rust
fn abs(value: i32) -> i32 {
	if (value < 0) {
		-value	
	} else {
		value	
	}
}
```


# 参考
* [Introduction - The Rust Reference](https://doc.rust-lang.org/reference/introduction.html)
* [Rustにおいてbreakやreturnを含む式はどの型であっても良い](https://opaupafz2.hatenablog.com/entry/2022/07/31/152932)
	* breakやreturnなどが式としてどのように扱われるか書いてある
IT担当して災害支援（第二報）

# はじめに
先日書いた包括的なIT支援とは別の方面から、やはり能登の震災関連のオファーがあったのでやってみたお話です。


先日の第一報

https://qiita.com/yo16/items/d31485b73aa609a20bd6

# 概要
自宅でお風呂に入れない方向けのシャワー施設があり、そこの予約です。

## 現状
- 施設は、４つのシャワールームがある
    - ＝予約枠が同じ時刻で4枠ある
- １人30分の制限をつけて、30分ごとに予約している
    - 事情・例外がいろいろある
        - 家族で来て２つ同時に使いたいとか
        - １時間連続で使いたいとか
        - 小さな子がいて２人とか
- 営業時間は、9:00～21:00
    - 9:00～9:30、・・・、20:30～21:00で、12時間x2=24枠
    - 施設が４つなので、24x4=94枠/日
- 現状は、**電話**で受けて**紙**に書いている
    - これがかなり煩雑とのこと（確かに大変そう）

## 要件
### 必須
- 利用者
    - スマホ・PCで、予約する
    - 氏名と連絡先を入れる
    - 他の人の氏名は見えず、特定の時間に予約可否のみ知れる
    - ご年配の方が多い
- 管理者は
    - 予約者の氏名、連絡先を見られる
    - 変更、キャンセルができる
- システム
    - 無料で
    - 早く

### できれば
- 予約者
    - 自分の予約時間を見られる
    - 自分の予約時間をキャンセルできる

# 実現
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/722610/b61f6075-22d7-e9f5-6b22-46e9a0be5499.png)

ご年配の方も使われるので、なるべく大きめに、なるべく見やすくしています。
あまり詰め込んでいないので、スマホでも大体同じように見えます。
あ、上は管理者が見た画面で、管理者ログインしない場合は、名前のところに「×」と出るだけです。

ちなみに、リクルートが提供している、AirReserve（エアーリザーブ）というサービスがあります。こちらも、無料で利用できます。

ただ、予約する際にメールアドレス必須のユーザー登録が必要。ご高齢の方が、自宅のお風呂に入る代わりに使うような施設で、メールアドレスを入れるということ。最初だけ誰かが助けてあげないといけないかもしれないですね。いちおう今回はお見送りというか、選択肢として残してはありますが、とりあえず置いておきました。

https://airregi.jp/reserve/

いろいろな要望を盛り込んでるうちに、メンテナンス性とか保守性とか、継続して使い続けることを考えると、AirReserveを使う方がよい、となるかもしれない。

けど、ゆるくて乗っ取られたりいたずらされる可能性があるけど、ご高齢の方が楽なログインが、ちゃんとしたサービスでは難しい気がします。


# 技術
Apps Scriptで、GETメソッドでHTMLを返す仕組み（バックエンド）があり、そのHTML（フロントエンド）はReactで作ります。
データの保存先は、Apps ScriptからGoogle Spread Sheetへアクセスして、表形式で保存です。

Apps Scriptでは、GETでトップページ、その後のフロント→バックの通信は、フロントからバックの関数を呼べるというすばらしい仕組みのおかげで、すごく楽な関係です。（わかっていれば楽だと思えるけど、フロントとバックの区別がわからなくなる人、いるだろうなぁ。）

具体的な手法は、「GAS React」などでググると、開発環境の構築ブログがそこそこ出てきます。私は、ReactをViteでビルドして、index.htmlにして、GASへデプロイしました。
私が参考にさせてもらったサイトは下記。

https://engineer.retty.me/entry/2022/12/22/150035


# 感想
GASでのウェブアプリは初めての挑戦だったので、１歩進むごとにコケる感じでした。Reactの領域に持ってくればサクサクっと進むんだけど。
でも結果的に２日でできたので、コケた後に起き上がるのはそんなにつらくないです。

大きめに躓いた場所は、、、

## 躓き１：デバッグ環境が構築できない
Reactをローカルで動かすことはできるんですが、クライアントとサーバーのやり取りと、サーバーとGoogle Spread Sheetとのやり取りのコードは動かせないので、実質、クライアントでのデバッグはできないです。

また、TypeScriptをビルドしたコードをデプロイしてるので、本番環境のJavaScriptでコードが読めない。いい方法があったら教えてください。

方法は、`console.log`を打って状況を得るだけ。CGIの時代を思い出しましたｗ

## 躓き２：フロントとサーバのやり取り
フロントからバックの関数を呼ぶ際に、プリミティブ以外の型を渡すとエラーになり、プリミティブ以外を返すとしれっとnullになること。知ってれば、避けられることです。

## 躓き３：npmでモジュールをインストールすると重くなる
Reactとして、ダイアログの出し方、ハンバーガーメニューの出し方（管理者用）もちょっと躓きました。`npm install`でモジュールを使っていけばクリアはできるけど、どんどん容量が大きくなるのでちょっと心配でした。

結局気にしないことにしました。🙈

## 躓き４：GASのインデックスは１から
GASで、何かと要素の順番が1から始まるんですが、0で設定しても1として動く、という親切(?)仕様がちょいちょいあってかえって混乱すること。

一番悩んだのは、シートの移動。月ごとに１シート作ることにしたのですが、適当なところに作られるシートを、適切なところに挿入したくて躓きました。


# おわりに
GAS + Googleサービスの選択肢は、私にとってとても大きな一歩でした。

その理由の１点目が、小さくていいという話。世の中で、これくらいでいいのにっていうサービスは本当にたくさんあると思うので。社内ツールとか、個人の管理用とか。閉じた空間で利用するには本当に便利。

理由の２点目は、機能を広げる話。Spread SheetだけでなくGoogle Driveへ保存とかGoogle Mapとの連携もできそうです。

もし、うちの組織向けにこんなの作ってほしいなーとかご要望があれば、ご連絡ください！
Go言語でブロックチェーンのシステムを作成する（その１）

# はじめに
Go言語を使用して、ブロックチェーンのシステムを作成していきます。
今回は、ブロックチェーンについて簡単にまとめていきます。

# ブロックチェーンとは
ブロックチェーンは、デジタルデータの取引を記録する技術であり、特に暗号通貨の世界で注目を集めています。この技術は分散型台帳技術（DLT）とも呼ばれ、取引データを複数のコンピュータにまたがって保存し、管理する方法です。

## ブロックチェーンの主な構成要素
1. ブロック：データ（取引記録）、前のブロックへの参照（前のブロックのハッシュ値）、およびその他の情報（タイムスタンプ、自身のハッシュ値など）を含みます。
2. チェーン：各ブロックが前のブロックと連結して形成する、途切れることのない連続したリスト。
3. ノード：ブロックチェーンネットワークに参加する個々のコンピュータ。ノードは取引を検証し、ブロックを生成し、ブロックチェーンのコピーを保持します。

## ブロックチェーンの構造
ブロックチェーンは名前の通り、「ブロック」と呼ばれるデータの集合体が「チェーン」のように連なって構成されています。各ブロックには、複数の取引記録や前のブロックへの参照（ハッシュ値）が含まれています。

![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676504/8fb42e65-a558-5ea3-87f5-39c82aff647f.png)

## ブロックチェーンの特徴
- 分散化
  - ブロックチェーンは、中央集権型の管理者がいない分散型のシステムです。
  - データはネットワーク上の多数のコンピューター（ノード）に分散して保存されます。
- 不変性
  - 一度ブロックチェーンに記録されたデータは、後から変更することが非常に困難です。これは、前のブロックの内容を変更すると、そのブロックのハッシュ値も変わり、結果として以降の全てのブロックの正当性が失われるためです。
- 透明性
  - ブロックチェーン上のすべての取引は公開され、参加者によって検証されます。これにより、高いレベルの透明性が保証されます。

## ブロックチェーンの用途
- 暗号通貨
  - ビットコインやイーサリアムなどの暗号通貨の取引記録に使われています。
- スマートコントラクト
  - 取引の条件が満たされた時に自動的に実行される契約をデジタル化します。
- サプライチェーン管理
  - 商品の流通過程を透明に記録し、追跡しやすくします。
- データ管理
  - 個人データや企業データの安全な管理・共有に利用されます。

# おわりに
次回から実際にGo言語を使って実装していきます。

次の記事

https://qiita.com/jun_11/items/259f0a777e12b3fa1b32

# 参考

https://www.udemy.com/course/go-blockchain/?couponCode=ACCAGE0923
RDSのサブネットグループの変更時、「同一VPC内での変更は不可能」と言われる

# はじめに
こんにちは、ユーゴです。今回は、AWSで遊んでいたときに直面した課題を紹介します。
ネットを調べていると、似たような質問で「後からVPCの変更はできません」という回答が多く、そうすると「VPCが変更できず、同一VPCのサブネットグループを指定できないなら、サブネットグループも変更できないのでは...？作り直すのが面倒だ...」と半ば諦めていました。しかし、色々と試しているうちに、簡単にサブネットグループの変更ができたので、ご紹介します。

# やりたかったこと
最初にRDSでDBインスタンスを作成したとき、サブネットグループを指定し忘れました。defaultのサブネットグループが生成されてしまい、パブリックサブネットや違う用途のサブネットもアタッチされてしまいました。

# 課題
作成したRDSのDBインスタンスについて、以下のようなエラーが出る。

> You cannot move DB instance {インスタンス名} to subnet group {サブネットグループ名}. The specified DB subnet group and DB instance are in the same VPC. Choose a DB subnet group in different VPC than the specified DB instance and try again.

つまり、以下のような操作ができない
![RDS_DB_SubnetGroup_change_deny.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2607452/f0c0090d-2afd-2307-399e-32a1960d2949.png)


# 解決
一度違うVPCのサブネットグループを作成し、アタッチ。
次に、本当に設定したかったサブネットグループを指定する。
![RDS_DB_SubnetGroup_change.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2607452/d45bd2e4-0a67-2307-6541-e87880bf260c.png)


### 注意
サブネットグループの変更は、時間がかかります。(体感10〜20分くらい)

# まとめ
いかがだったでしょうか。今回は、RDSのサブネットグループが同一VPC内で変更できない問題について紹介しました。なぜ同一VPC内のサブネットを指定できないのか、AWS上のインフラを操作する仕様上の課題でしょうか？
ともあれ、違うVPCのサブネットグループを経由するだけで実現できることが分かったので、同じように困っている方の手助けになれば幸いです。
もしお役に立てましたら、いいね, LGTM, フォローなどよろしくお願いします！
エンジニアにとって大切な「ググり方」を身につける

## 最新の記事を取得
技術の世界では、新しい情報が常に生み出されています。特にプログラミングにおいては、最新の情報を得ることが重要です。

```
async/await after:2021
```

この検索方法を使用すると、指定した年以降に公開されたページのみが検索結果として表示されます。これにより、古い情報を除外して最新の情報のみを得ることができます。

## サイトを絞る
信頼できる特定のサイトから情報を得たい場合、サイトを絞って検索することが可能です。

```
promise site:developer.mozilla.org
```

上記の方法で、指定したサイト内でのみ検索を行います。この方法は、質の高い情報を求める場合に特に有効です。

## 特定のサイトを除外
逆に、特定のサイトからの情報を除外して検索したい場合は、以下のようにします。

```
async/await -site:w3schools.com
```

これは、あるサイトの情報が過剰に表示されることを避けたい時や、特定の観点からの情報を避けたい時に役立ちます。

## キーワードを含む記事を検索
検索したい具体的なキーワードがある場合は、そのキーワードを直接ダブルクォーテーションを用いて検索します。

```
"TypeScript generics"
```

ダブルクォーテーションで囲むことで、そのフレーズが正確に含まれるページのみを検索することができます。これにより、特定のトピックに関する情報を効率よく見つけることが可能になります。

## エラーメッセージで検索
プログラミング中に遭遇するエラーメッセージの解決策を探す場合、エラーメッセージをそのまま検索エンジンに入力するのが一番です。

1. エラーメッセージをそのまま貼り付ける

```
TypeScript error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
```

このエラーメッセージをそのまま検索すると、非常に具体的な状況に限定された結果しか得られない可能性があります。これは、特定のエラーコード（TS2345）に加えて、エラーの内容も非常に具体的であるためです。

このエラーメッセージから、変わる可能性のある部分を抽象化することで、より広範な解決策を見つけることができます。例えば、以下のように検索を改善できます。

2. エラーメッセージの中で変わる可能性のある部分にはワイルドカード（*）を使用

```
TypeScript error TS* type 'string' is not assignable to type 'number'
```

ここでは、エラーコードの具体的な数字（2345）をワイルドカード（*）に置き換えています。これにより、類似の型不一致に関するエラーであっても、検索結果に含まれるようになります。

また、「Argument of type」という部分を削除して、エラーの核心部分に絞ることで、より幅広い検索結果を得られるようにしています。
はじめてのOSSコントリビュートをしてみた

## この記事について

- 今回、はじめてOSSコントリビュートをしたので、実施事項と気づきを記載します
- OSSのコントリビュートを考えている方のご参考になれば幸いです
- 今回コントリビュートしたのは[こちら](https://github.com/aws-samples/bedrock-claude-chat)のリポジトリです

## なぜコントリビュートしようと思ったのか

私の場合は、2020年に現職でエンジニアになってから「社外の勉強会に登壇する」「OSSコントリビュートする」が密かに描いていた目標でした

私は普段AWS周りの情報収集をする事が多いのですが、たまたま見ていた[aws-samples](https://github.com/aws-samples)内のリポジトリで、記載を調整した方が良さそうな箇所があり、折角なのでコントリビュートに挑戦してみました

実際にMergeされたPRは[こちら](https://github.com/aws-samples/bedrock-claude-chat/pull/200)です

## コントリビュートの第一歩

PR内容を見ると「え、それだけ？」と思う方もいらっしゃるかもしれませんが、私は簡単なドキュメント変更がコントリビュートの第一歩としては丁度良かったです

というのも、コントリビュートの一連の流れをまず学べたからです

## コントリビュートの流れ

### コントリビュート方法の確認

- コントリビュートを受け付けているようなリポジトリの場合、`CONTRIBUTING.md`が用意されている場合が多いです
- 今回の対象リポジトリの場合は[こちら](https://github.com/aws-samples/bedrock-claude-chat/blob/main/CONTRIBUTING.md)の`CONTRIBUTING.md`を確認しながら、後の手順を進めていきます

### 修正内容の選定

- Issueが上がっている物を修正
- 自分でIssueを立てて修正
- Issueは立てずに修正

等、様々なパターンがあると思いますが、今回は軽微なドキュメント調整のためIssueは立てずに修正する事にしました

### リポジトリのforkからpushまで

- まずは対象のリポジトリを個人リポジトリにforkします
- その後forkしたリポジトリをcloneして、committしてpushします

:::note info
プロジェクトによっては、AWSの認証情報の流出防止としてcommit前に`git-secrets`等のチェックが設定されている場合もあります。
:::

https://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/patterns/scan-git-repositories-for-sensitive-information-and-security-issues-by-using-git-secrets.html

https://github.com/awslabs/git-secrets

### PR作成

- 既存のPRを参考にしながら作成していきます

:::note info
リポジトリによっては、GitHubActions内でPRのタイトルチェックが用いられている場合があります
タイトルチェックの実装例は[こちら](https://github.com/amannn/action-semantic-pull-request)です
:::

- 今回作成したPRは[こちら](https://github.com/aws-samples/bedrock-claude-chat/pull/200)です

### マージ

- Reviewerのチェック後にMergeされます

## コントリビュートすると

- PRを作成した時点で、contributionsの欄に[aws-samples](https://github.com/aws-samples)が表示されるようになりました

![GJumbk1bQAAHauE.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411902/b52fa890-f1b0-65f1-2503-195d2f94576f.jpeg)

- また、PR作成の履歴も残りました

![GJumblFbYAAE8_s.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411902/22255d35-f7f0-ed78-a610-b77090546020.jpeg)

## まとめ

- 以上が今回経験したOSSコントリビュートの流れでした
- 最初に`CONTRIBUTING.md`と`.github`配下のファイル、既存のIssueとPRを確認しておくと、円滑にコントリビュートが行えそうです
- 多くのコントリビューターがいるようなリポジトリの場合は、それだけ開発の為のツール（テストやPRのタイトルチェック等）が充実しており、自身で開発を行う際の参考になりそうです

## 参考文献

[Qiita - 2年間OSSにコントリビュートしてみての振り返り](https://qiita.com/Syuparn/items/ce27ddc9b2013c92a905)
[オープンソースにコントリビュートする方法](https://opensource.guide/ja/how-to-contribute/)  
[とほほのライセンス入門](https://www.tohoho-web.com/ex/license.html)
VSCode REST Client でREST APIを呼べる手順書を作成する

VSCodeの[REST Client](https://marketplace.visualstudio.com/items?itemName=humao.rest-client)というお手軽にHTTPリクエストを呼び出せる拡張機能があります。
基本的な使い方は、 拡張子が `.http` のファイルを作成するとVSCode上からリクエストを送ることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51316/75bf7cfa-9cb2-6d81-93b9-bc88e07e9f16.png)

一つのファイルに複数のリクエスト定義を記載し順番に呼び出すこともできます。
これはこれで便利なのですが、説明などを追加してドキュメントとしても管理できないかなぁと思っていたところ、実は Markdown ファイルにも対応してました。
コードブロックに `http` もしくは、`rest` をつけるとVSCodeからリクエストを送信できます（Markdownのプレビューからは呼べません。あくまで編集画面からです）。

これにより、API実行支援もついた可読性が高いドキュメントとして管理できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51316/cc26cdf7-9164-af99-705f-52bcb1e1a46d.png)


### サンプル

「`Send Request` 時に入力を要求する `@prompt` [^1]」や 「`.env` [^2]」を使ってより汎用性を高めてます。

<pre>
# ユーザー追加手順

以下を実行し、トークンを取得します。
取得したトークンは、`.env` ファイルの `TOKEN` に設定してください。

```http
# @prompt username
# @prompt password
POST http://example.com/api/get_token

{
    "username": "{{username}}",
    "password": "{{password}}"
}
```

以下のAPIで現在のユーザー一覧を取得します。

```http
GET http://example.com/api/users/
Authorization: {{$dotenv TOKEN}}
```

ユーザーを追加するAPIを実行します。

```http
POST http://example.com/users/
content-type: application/json
Authorization: {{$dotenv TOKEN}}

{
    "name": "Bob",
    "age": "{{$randomInt 1 50}}"
}
```

追加されたことを確認します。

```http
GET http://example.com/api/users/
Authorization: {{$dotenv TOKEN}}
```

以上
</pre>


[^1]:`Send Rquest` をクリックすると `username` を入力するプロンプトが上部に表示されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51316/3163950d-d28f-cd96-b911-1d709334042e.png)

[^2]:`.env` ファイルに設定した値を `{{$dotenv キー名}}` で参照できます。dotenv以外にもいろ色便利な[System変数](https://github.com/Huachao/vscode-restclient?tab=readme-ov-file#system-variables)があります( `guid` や `timestamp` も便利）。
Figma Tokensを使ってGithubにtokenをpushするまで

## 背景
デザインシステムの勉強中。
デザインtokenをgithubで管理したい。
パッケージ化してプロダクト側で使えるようにしたい。

## やること
1. Figma Tokensを使ってデザインtokenの作成
1. Figma TokensからGithubのリポジトリにtokenのJSONファイルをpushする

## 事前準備
- design-tokenを管理するリポジトリの作成
- 必要なものをインストール
  - Figma Tokens（Figmaのプラグイン）

## Figma Tokensを使ってデザインtokenの作成
Figma Tokensとはデザインシステムの最小単位のスタイルを定義するためのツール。
### できること
1. デザイントークンの管理
サービス内で利用しているcolorやfont、radiusなどのデザイントークンを一覧で確認、編集、デザインデータに反映することがでる
1. ドキュメント機能
Figma Tokensに登録したデザイントークンには、名前と値、その説明を記入することができ、これらの情報はFigmaのデザインに反映され、自動更新されるドキュメントとして使用することが可能
1. Githubとの連携
デザイントークン（JSON）を指定のGitHubリポジトリにpushし、Pull Requestまで作成することができる。


![スクリーンショット 2024-03-30 19.17.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689380/dc3c2e34-8b3a-c14c-a742-98b12c14ce85.png)

## Githubのリポジトリにtokenをpushする
### GithubでアクセスTokenを生成する

https://docs.github.com/ja/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-token

### Figma TokensとGithubを連携

#### Github credentialの登録

Figma Tokens > Settings > Add New > Github
以下の項目を入力

- 名前
- アクセスToken
- リポジトリ
- ブランチ
- pushするファイルパス（tokens.json）

![スクリーンショット 2024-03-30 19.26.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689380/3daa920a-68f9-a532-8fbd-9a331c8a9296.png)

#### Githubにpush
変更したら、Push to GitHubボタンをクリックする

![スクリーンショット 2024-03-30 19.30.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689380/e7c4050e-afb2-3389-a0ae-b0149446b193.png)

コミットメッセージを追加して、「Push Changes」ボタンをクリック
→ All done!が表示される


## 参考
- [【Figma Tokens × Style Dictionary】デザインシステムはじめの一歩](https://zenn.dev/kosukek/articles/c86b34b847a9f2)
- [Figma Tokens で小さくはじめるデザインシステム](https://zenn.dev/mi_/articles/453f7594120c9a)
- [Ubie Design Tokensを公開しました](https://zenn.dev/ubie_dev/articles/7a6413af237eae?redirected=1#style-dictionary)
深層学習を学び始めた

## はじめに
　この記事では、書籍やUdemyで深層学習について学んだことを書いていこうと思います。[①米国AI開発者がやさしく教える深層学習超入門第一弾【Pythonで実践】](https://www.udemy.com/course/deeplearning1/)は非常にわかりやすいので、深層学習を学ばれる方は、ぜひこの動画で学習することをお勧めします。

## 目次
- [深層学習が使われているもの](##深層学習が使われているもの)
- [深層学習とは](##深層学習とは)


## 深層学習が使われているもの
深層学習をつかった、サービスや製品は日常生活に深く浸透している
- DeepLやGoogle翻訳などの翻訳
- Alexa, Google homeなどの音声認識
- 医療用画像診断
- ChatGPT等の生成AI




## 深層学習とは
 深層学習は機械学習の１種で、3層以上の多層のニューラルネットワーク(NN)によって構成されている。
ニューラルネットとは、人間の脳の神経細胞を模倣したモデルである。このNNを用いて学習する。深層学種は、層を"深く"することでより精度の高いモデルを構築できる。層を深くするというのは、隠れ層の数を多くすることである。
下の画像は、隠れ層が２層のNNである。入力層にデータを渡して、自動で処理・学習して次の層に渡す。そして、出力層で学習した値を出力する。

![スクリーンショット 2024-03-30 18.59.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3750206/3dccb3e6-9656-e261-2ee4-220be070f26d.png)

## 機械学習と深層学習の違い
機械学習と深層学習のと大きな違いは、特徴量についてである。
- 機械学習
    - 特徴量は人が見つけたり、作る

- 深層学習
    - モデルが特徴量を作る

つまり、深層学習は、入力データを渡すだけで、自動でモデルが特徴量を作ってくれる。そのため、深層学習はいい"モデル"を作ることが重要である。
【Provisioned Concurrency】IoT CoreからのLambda実行でエラーが出たので解消してみた

## 経緯
IoT CoreからIoTルールアクションでLambdaを実行していたが、コールドスタートが気になりSAMテンプレートでProvisioned Concurrencyを適用。

## Provisioned Concurrency適用時の設定
### IoTルールのSQLステートメントとSAMテンプレート
```ruby:SQLステートメント
SELECT 
  aws_lambda("arn:aws:lambda:ap-northeast-1:111111111111:function:hoge-func:Live", {"payload": *})
FROM 
  'topic/subtopic'
```
```ruby:SAMテンプレート（Lambda部分）
  hogeFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub hoge-func
      CodeUri: src/handler
      Role: !GetAtt LambdaHogeRole.Arn
      AutoPublishAlias: Live
      ProvisionedConcurrencyConfig:
        ProvisionedConcurrentExecutions: 10
```
```ruby:SAMテンプレート（リソースベースポリシー部分）
  IoTRuleInvokePermission:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !Ref hogeFunction
      Principal: iot.amazonaws.com
      SourceArn: !Sub arn:aws:iot:ap-northeast-1:${AWS::AccountId}:rule/*
      SourceAccount: !Ref AWS::AccountId
      Action: lambda:InvokeFunction
```

## 問題
Provisioned Concurrency適用後から、IoTルールアクション経由でのLambda実行ができなくなった。

## エラー
IoTログを確認したところ、以下のエラーが出力されていた。
```ruby:エラー
Received an error while making a request to Lambda: ErrorType: Client, ErrorCode: AccessDeniedException, StatusCode: 403
```

## 原因
Provisioned Concurrencyの適用でLambdaのARNが変更されており、変更後のARNにリソースベースのポリシーステートメントがアタッチされていなかった。
```ruby:変更前のARN
arn:aws:lambda:ap-northeast-1:111111111111:function:hoge-func
```
```ruby:変更後のARN
arn:aws:lambda:ap-northeast-1:111111111111:function:hoge-func:Live
```

## 解決方法
DependsOnでLambdaのAliasLiveが作成されるのを待ってから、リソースベースのポリシーステートメントをLambdaにアタッチするように記載したらうまくいった。
```ruby:SAMテンプレート（リソースベースポリシー部分）
  IoTRuleInvokePermission:
    Type: AWS::Lambda::Permission
    DependsOn: hogeFunctionAliasLive
    Properties:
      FunctionName: !Join [ '', [ !GetAtt hogeFunction.Arn, ':Live' ] ]
      Principal: iot.amazonaws.com
      SourceArn: !Sub arn:aws:iot:ap-northeast-1:${AWS::AccountId}:rule/*
      SourceAccount: !Ref AWS::AccountId
      Action: lambda:InvokeFunction
```

## まとめ
リソース間の依存関係が問題だと早い段階で気づき、以下のように書いていたが、hogeFunctionのAliasに対して、リソースベースのポリシーをアタッチすることはできなかった。
```ruby:
DependsOn: hogeFunction
```
DependsOnで指定しているAliasLiveのリソースは、テンプレート上どこにも存在しないので、かなりの引っかかりポイントだと思われる。

## おわりに
同じような問題に突き当たった人の助けになれば幸いです。