OmniAICreator/Qiita-1.07M huggingface dataset:
EDBの外部接続設定

# 記事の概要
edbを外部接続できる様に設定してみた。

## 前提
IAサーバー
edbは、v14
RHEL 8.6

# 本編
### edbのデフォルトユーザーに切り替え
```php
su - enterprisedb
# Last login: Thu Mar  9 23:32:21 CST 2023 on pts/0
# [enterprisedb@itz-661001tnp6-38d1 ~]$
```
#### edbを起動する
```php
systemctl start edb-as-14
# ==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ====
# Authentication is required to start 'edb-as-14.service'.
# Authenticating as: root
# Password: 
# polkit-agent-helper-1: pam_authenticate failed: Authentication failure
# ==== AUTHENTICATION FAILED ====
# Failed to start edb-as-14.service: Access denied
# See system logs and 'systemctl status edb-as-14.service' for details.
```
どうやら、edb-as-14.serviceにアクセスができていないみたいだ。

### confファイルを変更
変更するconfファイルは、**postgresql.conf**と**pg_hba.conf**である。

#### **postgresql.conf**の編集
まずは、postgresql.confの場所を確認する。
```php
find / -name postgresql.conf
# /var/lib/edb/as14/data/postgresql.conf
```
postgresql.conf内で、**「listen_addresses = '*'」** になるように編集する。
```php
vi /var/lib/edb/as14/data/postgresql.conf

# 以下postgresql.confの設定
# - Connection Settings -
listen_addresses = '*'		# what IP address(es) to listen on;
```
#### **pg_hba.conf**の編集
同様に、pg_hba.confの場所を確認する。
```php
find / -name pg_hba.conf
# /var/lib/edb/as14/data/pg_hba.conf
```
pg_hba.confで受け付けるIPアドレスを指定する。今回は全てのIPアドレスからのアクセスをパスワード認証で受け付けるように、以下の様に設定する。
```php
vi /var/lib/edb/as14/data/pg_hba.conf

# 以下pg_hba.confの設定
# IPv4 local connections:
host    all             all             0.0.0.0/0               md5
```
また、認証方式は、以下の様に、**peer** や**trust** などあるが、今回は**md5** で統一する。
```
trust          任意のロール名でパスワードなしで接続可能
reject         接続をすべて拒否
scram-sha-256  パスワード認証、最も安全だが一部クライアントで未サポート
md5            パスワード認証
password       パスワード認証、パスワードを平文で送信
gss            GSSAPI を利用したシングルサインオン
sspi           SSPI を利用したシングルサインオン
ident          Ident認証
peer           Peer認証
ldap           LDAP認証
radius         RADIUS認証
cert           SSLクライアント証明書を使った認証
pam            PAM認証
bsd            BSD認証
```

### edbを起動して、状態を確認
```php
systemctl start edb-as-14
systemctl status edb-as-14
#● edb-as-14.service - EDB Postgres Advanced Server 14
#   Loaded: loaded (/usr/lib/systemd/system/edb-as-14.service; enabled; vendor preset: disabled)
#   Active: active (running) since Sat 2023-03-11 00:45:39 CST; 15s ago
#  Process: 74633 ExecStartPre=/usr/edb/as14/bin/edb-as-14-check-db-dir ${PGDATA} (code=exited, status=0/SUCCESS)
# Main PID: 74639 (edb-postmaster)
#    Tasks: 9 (limit: 50188)
#   Memory: 69.6M
#   CGroup: /system.slice/edb-as-14.service
#           ├─74639 /usr/edb/as14/bin/edb-postmaster -D #/var/lib/edb/as14/data
#           ├─74641 postgres: logger 
#           ├─74643 postgres: checkpointer 
#           ├─74644 postgres: background writer 
#           ├─74645 postgres: walwriter 
#           ├─74646 postgres: autovacuum launcher 
#           ├─74647 postgres: stats collector 
#           ├─74648 postgres: dbms_aq launcher 
#           └─74649 postgres: logical replication launcher 
```
### edbを触ってみる
```php
edb-psql edb
#edb-psql (14.4.0, server 14.4.0)
#Type "help" for help.
#edb=# 
```
### ユーザーにパスワードを設定する
```php
alter user enterprisedb password 'XXXXXX';
#ALTER ROLE
```

以上
DeepLink対応備忘録

お仕事でDeepLink対応をおこなったので、自分なり備忘録を残します。

今回は、既存のandroid・iOS 両方のアプリで、
「LINE上のURLをタップすると、アプリの特定の画面に遷移させたい」という要件がありました。

今回は実現するための手法を1から検討し、実現性の検証を行いました。

LINE上のURLはすでにバックエンドサーバが稼働していたため、
バックエンド側の修正工数も考慮する必要がありました。
（ただし、修正不可ではなく、運用コストも含めて総合的に判断という温度感でした）

また、バックエンドサーバの仕様として、
画面遷移のためにユーザIDのようなものをパラメータに含め、
アプリはそれを読み取らなければいけないという設計上の制約がありました。
例) ``https://example.com/transition/detail?userId=xxx``

## 調べたもの

- カスタムスキーマ
- Universal Link & Android App Link
- Firebase Dynamic Link

解説はこの記事がわかりやすかったです。あとは公式を...
https://qiita.com/y-some/items/e0e0f5cb4d7d5559b09c

カスタムスキーマについてはLINEでサポートをしておらず（セキュリティ事件もあったので、一応方法はありそう）、対象外。
Firebase Dynamic LinkはuserIdを毎回パラメータに付与するという要件に適用せず、除外。
（1日に発行できる回数に引っかかる恐れがある、そもそもuserIdのような可変のパラメータは向かなそう）

Universal Link & Android App Link を使用することにしました。

Universal Link は サーバ上のファイルでURLの定義と挙動を決める。
Android App Link は アプリのintent-filterでURLの定義と挙動を決める。

iOSとandroidの実装差分では、この部分が大きな差かな、と思います。
あとはAndroid App Link の方が制約が厳しいので、寄せるならAndroid App Linkから寄せる方が良い。

## まとめ

今回は、Universal Link & Android App Link を採用しました。
よりモダンで簡単そうなのがFirebase Dynamic Link だったのですが、
今回のアーキテクチャの最適解は選んだ方だと思ったので、良い判断ができたと思いました。

Firebaseになじみがあったので、Firebaseから選定しましたが、
他にも選択肢はあったかもしれません。
今回は時間的に選択肢を広げても調査・検証しきれないな...と思いましたが、
最適を見つけるために常にアンテナを張るべきだな..とも思いました。
【解決方法まとめ】Railsサーバー起動時の「A server is already running.」エラーに遭遇した時の対処法

# はじめに
2021/9~エンジニアしている高橋と申します。
業務でぶち当たったエラーの対処法をまとめていきます。

※あと最近見た映画「ブルージャイアント(BLUE GIANT)」の感動シーンを最後に載せます

# エラー内容
```ruby:error_log
=> Booting Puma
=> Rails 6.0.4.4 application starting in development 
=> Run `rails server --help` for more startup options
A server is already running. Check /home/XXXXXXXXXX/tmp/pids/server.pid.
Exiting
```

パッと見た瞬間のワイ

### 「なんじゃらほい・・・」(´-ω-`)

# エラーメッセージの意味を理解する

Railsサーバーを起動しようとした際に**既にサーバーが起動しているため**に発生するエラーです。
このエラーは、以下のような意味があります。

* `「A server is already running.」` : サーバーは既に実行中です。
* `「Check /home/XXXXXXXXXX/tmp/pids/server.pid.」` : サーバーのプロセスIDが記録されたserver.pidファイルを確認してください。
つまり、サーバーが既に起動しており、**server.pidファイルにはそのプロセスIDが記録されているため**、再度サーバーを起動することができないというエラーです。

このエラーを解決するには、以下の手順を実行する必要があります。

```
1. server.pidファイルを確認する
2. 既に起動しているサーバーのプロセスIDを終了する
3. server.pidファイルを削除する
4. サーバーを再起動する
5. 上記の手順を実行することで、サーバーを再起動することができます。
```

# server.pidファイルを確認する
エラーメッセージにあるように、まずはサーバーのプロセスIDを記録したserver.pidファイルを確認しましょう。
server.pidファイルは、Railsアプリケーションのtmp/pidsディレクトリにあります。
次のコマンドでserver.pidファイルを確認できます。

```ruby:
$ cat tmp/pids/server.pid
```


# 既に起動しているサーバーのプロセスIDを終了する
server.pidファイルに記録されているプロセスIDをkillコマンドで終了しましょう。
次のコマンドで、ポート番号3000を使用しているプロセスを調べることができます。
```ruby
$ lsof -i:3000
```
上記コマンドを実行すると、プロセスIDとプロセス名が表示されます。
プロセスIDを確認したら、次のコマンドでプロセスを終了しましょう。
```ruby
$ kill <プロセスID>

# それでもキルされなかったら以下を実行して強制的にキルする
$ kill -9 <プロセスID>
```

# server.pidファイルを削除する
プロセスが終了したら、server.pidファイルを削除します。
次のコマンドで削除できます。

```ruby
$ rm tmp/pids/server.pid
```

# サーバーを再起動する
これで、サーバーを起動することができます。
以下のコマンドでサーバーを起動してください。
```ruby
$ rails server
```

これでいけるはず…‼
できなかったらコメントなどください～！

# おわりに

最後に感動シーンを…

3人バンドのドラマーの玉田が2人のレベルについていけず打ちひしがれている場面。
観客の老人が声をかけてくれる…

![スクリーンショット 2023-03-13 005825.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1884151/e7281dab-69d1-a8ef-2131-ee77179d15b2.png)

見てくれる人はその人の見てくれてるんですね。
グッとくる個人的名シーンです！

最後まで読んでいただきありがとうございます！
Twitterやてます～
https://twitter.com/takazu_engineer
非同期処理の覚書

# 00. 同期処理のコード

```Python
import time


def sync_func():
    for i in range(10):
        time.sleep(0.5)
        print(i)

start = time.time()
sync_func()
end=time.time()

print(end-start)

```

# 01. 非同期処理のコード

```Python
import asyncio
import time



async def sync_func():
    for i in range(10):
        await asyncio.sleep(0.5) #eventloop not blocked
        print(i)

start = time.time()
loop = asyncio.get_event_loop()
loop.run_until_complete(sync_func())
loop.close()

end=time.time()

print(end-start)


```

# 02. 同期処理コード vs. 非同期処理コード

```Python
import time

def sync_func():
    for i in range(10):
        time.sleep(0.5)
        print(i)


start = time.time()
sync_func()
sync_func()
sync_func()
end=time.time()

print(end-start)


```

```Python:result
0
1
2
3
...
0
1
2
...
0
...
9

15.031020402908325

```

```Python
import time
import asyncio

async def sync_func():
    for i in range(10):
        await asyncio.sleep(0.5) #eventloop not blocked
        print(i)

start = time.time()
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(sync_func(),sync_func(),sync_func(),))
loop.close()
end=time.time()

print(end-start)

```

```Python:result

0
0
0
1
1
1
...
9
9
9
5.013215065002441

```
関数の実行時間を計測するコードを短くする。

## 0. 既存の方法

```Python
import time


def sync_func():
    for i in range(10):
        time.sleep(0.5)
        print(i)

start = time.time()
sync_func()
end=time.time()

print(end-start)
```


```Python: result
0
1
2
3
4
5
6
7
8
9
5.009452819824219

```
## 1. 提案の方法

Pythonには、デコレータという機能があり、関数の前後に特定の処理を追加できます。これを使用して、関数の実行時間を計測するデコレータを定義することができます。

```Python
import time


def timer(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print("Elapsed time: ", end_time - start_time, "seconds")
        return result
    return wrapper

@timer
def sync_func():
    for i in range(10):
        time.sleep(0.5)
        print(i)


sync_func()

```

```Python: result
0
1
2
3
4
5
6
7
8
9
Elapsed time:  5.0100860595703125 seconds

```
この例では、timerデコレータを定義し、my_function()関数に適用しています。timerデコレータは、wrapper関数を返します。wrapper関数は、my_function()関数を実行する前に開始時間を取得し、関数の実行が完了した後に終了時間を取得し、経過時間を表示します。最後に、wrapper関数はmy_function()関数の戻り値を返します。

デコレータを使用することで、関数を実行するたびに計測するコードを書く必要がなくなり、コードも短くなります。ただし、デコレータを理解していない人にとっては、読みやすさが低下する可能性があります。
自社の教育環境にDiscourseを導入してみた

構築までは大先輩にお任せして
設定をいろいろいじってみたので簡単に備忘録（伝える気ゼロですいません）

※設定変えるたびに追記予定

①　管理者権限の付与
②　カテゴリの追加、削除
③　記事投稿時のテンプレ作成
④　表示カテゴリのデフォルト設定
⑤　設定内の変更した設定のみを表示
⑥　ユーザーレベルの設定（セキュリティ設定）
⑦　チャットの使用制限

①管理者権限の付与
１　左ペイン上部の管理者クリック
２　ユーザーをクリック
３　対象者をクリック　
４　権限にある「管理者権限を付与」をクリックし管理者として登録しているメールアドレスにメール送信　
５　メールきたらよしなにクリック　

②　カテゴリの追加、削除
追加
１　すべてのカテゴリをクリック
２　スパナマークをクリック
３　新規カテゴリを追加をクリック
４　名前を入力
５　必要があればセキュリティの追加
※スタッフカテゴリに追加する場合は管理者権限ないと見れない

削除　
１　削除したいカテゴリをクリック　
２　スパナマークをクリック
３　右下にある「カテゴリを削除」をクリック

③　記事投稿時のテンプレ作成
１　テンプレはカテゴリごとに設定できるため設定したいカテゴリをクリック　
２　スパナマークをクリック
３　Templateをクリックしテンプレ内容を記載　
４　テンプレ設定したカテゴリで新規投稿して内容確認　

④　表示カテゴリの初期設定
左ペインに表示されるカテゴリは個人設定でどのカテゴリを表示するかしないかを設定できるが
初期設定として表示したいカテゴリを変更する場合の設定方法のことを指す　
１　左ペイン上部の管理者クリック
２　設定をクリック
３　設定内左ペインのナビゲーションをクリック　
４　default sidebar categoriesで設定可能（あとはよしなに）

⑤　設定内の変更した設定のみを表示
１　左ペイン上部の管理者クリック
２　設定をクリック
３　設定内右上の「上書き部分のみ表示」
４　よしなに

⑥ ユーザーレベルの設定
※しっかり設計したほうがいい
１　左ペイン上部の管理者クリック
２　設定をクリック
３　信頼レベルをクリック
４　●●が出来る人をどのユーザーレベルにするかが選択可能
５　ユーザーレベルを上げるための条件も設定可能（投稿を何回したら●レベル等）
　　※条件を一つでも満たせばレベルが上がる

⑦　チャットの使用制限
１　左ペイン上部の管理者クリック
２　設定をクリック
３　チャットをクリック
４　使わないならプラグインを有効チェックマークをなしにする
５　チャットが投稿出来るユーザーレベルの設定やチャット履歴保存期間の設定が可能
[NestJS]レスポンスの返却値に特定プロパティを除外する方法

# はじめに
セキュリティ上、どうしてもDB上から取得したデータに特定プロパティが含まれないようにしたいときがあるかと思います。
そのときの対応方法をまとめています。

# 方法
Entityクラスに`@Exclude({ toPlainOnly: true })`を該当プロパティ上に記載する

```
import { Exclude } from '@nestjs/class-transformer';

export class User {
  id: number;

  email: string;

  @Exclude({ toPlainOnly: true })
  password: string;
}

```

適用したいcontrollerに
```
@UseInterceptors(ClassSerializerInterceptor)
```
もしくはグローバル上で適用したい場合は
```
app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector)));
```
こうすることでUserデータを取得したときにパスワードが含まれないようになります。

# おまけ
GraphQL（コードファースト）上でも返却値に特定プロパティをを除外する方法があったので記載しておきます。
その方法は該当プロパティ上に`@HideField()`を付与する。
```
@ObjectType()
export class User {
    @Filed(() => Int)
    id: number

    @Field()
    email: string

    @HideField()
    password: string
}

```
nginx.confの主なディレクティブ

●nginxの設定ファイルは、設定の有効な範囲を示す「コンテキスト」内に個別の設定を意味する「ディレクティブ」を記述して構成される。

nginx.confの主なディレクティブ

・http{}　httpサーバとしての設定
・server{}　バーチャルホストの設定
・location　プレフィックス　URLのパスの条件{}　条件にマッチするリクエストURLに対する設定
・listen　IPアドレス:ポート;　リクエストを受け付けるIPアドレスとポート番号(デフォルト80)の指定
・server_name　...名前;　バーチャルホストの名前の指定
・index　ファイル名...;　インデックスとして返すファイル名の指定
・root　パス;　webで公開するHTMLを保存する最上位のディレクトリ(ドキュメントルート)の指定
・proxy_pass　URL;　プロキシ先の指定
・proxy_http_version　1.0|1.1;　プロキシでのHTTPプロトコルバージョンの指定
・proxy_set_header　フィールド　値;　プロキシ先に送られるリクエストへッダーフィールドの再定義または追加
・proxy_pass_header　フィールド;　プロキシ先からクライアントへの通過を許可するヘッダフィールドの指定
・fastcgi_pass　IPアドレス:ポート;　FastCGIサーバの指定
・fastcgi_param　パラメータ　値;　FastCGIサーバに渡すパラメータの指定
・return　値　<値の書式>　特定のステータスコードを返す、またはリダイレクトする


ディレクティブの書式には以下の2種類。
・ディレクティブ名 値;
・ディレクティブ名 値 {}
-1- 簡単なゲームを沢山作ることにした。

自分の納得いくゲームを作りたい・・・

人生でやってきたゲームから、自分なりのゲームを妄想するが、どうしても難易度が上がり初心者の私にとって難しい内容になってしまう。

妄想と技術レベルのギャップで心が折れそうだ！！！

よし、簡単なゲームを沢山作るぞ！

下記リンクのyoutubeの動画を拝見し、
とりあえずここにあるゲーム+α数種を作っていこう！！！
と思いました。（とても参考になる方なのでみんなもチャンネル登録しよう！）

ステップというのは、一段ずつ着実に上がっていくもの。いきなり、オープンワールドなゲームなんて作れないんだから！と、自分の尻を叩いて燃え上がらせます。どうぞ、この記事をご覧になった方は応援をよろしくお願いいたします。

Miroで作成ロードマップを管理し、Qiitaで記事の投稿も行い、自分の行っていることを形として残していくことにしました。
私と同じような思いを持っている方と交友したいので、連絡是非待っています！
Twitter　→　https://twitter.com/oHixDio

youtubeリンク
↓↓↓

https://www.youtube.com/watch?v=fSTa05CTB3w&t=118s
frame・boundsを簡単にまとめてみました

## frameとbounds
- frame
    - 親View(SuperView)からみて、現在のView（子Viewなど）のサイズと位置を保持するプロパティ
- bounds
    - 現在のView（子Viewなど）からみて、現在のViewのサイズと位置を保持するプロパティ
    - Viewにimageなどコードでサイズを定義する際、基本的にはboundsを使う方が良い
        - boundsは要素（自分）自身を基準としたサイズや位置を持っているから
- 両者の違い
    - 親Viewと子View、つまり、どこを基準としてサイズや位置を決めるのかに両者の違いがある

## コード
- Viewを表示させてみる
```swift:Swift
//boundsを基準にWidthとheightを定義
redView.frame = CGRect(x: 100, y: 200, width: view.bounds.width/3, height: view.bounds.width/3)
print(redView.frame) //(100, 200, 143, 143)

// viewにUIImageViewを追加
self.view.addSubview(imageView)
```
![Simulator Screen Shot - iPhone 14 Pro Max - 2023-03-12 at 23.51.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2915639/5cff1055-8c3d-0e9c-2f0a-9bfc587f60b6.png)

- おまけ：iPhone14 pro を使用しているデバイスとしてソースコードを記載する
```swift:Swift
//画面のサイズを取得する
//横幅
let deviceWidth = UIScreen.main.bounds.width
print(deviceWidth) //393.0

//高さ
let deviceHeight = UIScreen.main.bounds.height
print(deviceHeight) //852.0

//一気にサイズ（width,height）を取得する
let deviceSize = UIScreen.main.bounds.size
print(deviceSize) //(393.0, 852.0)

//画面のピクセル（解像度）を取得する
//横幅
let deviceResolutionWidth = UIScreen.main.nativeBounds.width
print(deviceResolutionWidth) //1179.0

//高さ
let deviceResolutionHeight = UIScreen.main.nativeBounds.height
print(deviceResolutionHeight) //2556.0

//一気に解像度（width,height）を取得する
let deviceResolutonSize = UIScreen.main.nativeBounds.size
print(deviceResolutonSize) //(1179.0, 2556.0)
```
## おわりに
間違い等ありましたらコメント欄でご指摘ください。

## 参考記事
[[iOS] frameとboundsの違いを理解する](https://qiita.com/tanaka-tt/items/0b2df30e1c79638580f7)

[【Xcode/Swift】端末の画面サイズ(ポイント)や解像度(ピクセル)、倍率(スケール)を取得する方法](https://ios-docs.dev/screensize/)

[[増補改訂第3版]Swift実践入門 ── 直感的な文法と安全性を兼ね備えた言語 (WEB+DB PRESS plusシリーズ)　](https://www.amazon.co.jp/%E5%A2%97%E8%A3%9C%E6%94%B9%E8%A8%82%E7%AC%AC3%E7%89%88-Swift%E5%AE%9F%E8%B7%B5%E5%85%A5%E9%96%80-%E7%9B%B4%E6%84%9F%E7%9A%84%E3%81%AA%E6%96%87%E6%B3%95%E3%81%A8%E5%AE%89%E5%85%A8%E6%80%A7%E3%82%92%E5%85%BC%E3%81%AD%E5%82%99%E3%81%88%E3%81%9F%E8%A8%80%E8%AA%9E-PRESS-plus%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA/dp/4297112132)
↑引用元
石川 洋資 (著), 西山 勇世 (著)
発行者：片岡 巌
出版社：技術評論社
印刷/製本：日経印刷株式会社

## 開発環境
- Xcode-13.4.1
- Swift version 5.7
APIGatewayでCloudwatchログを有効化した時の権限エラー解消方法

# 1. 概要
TerraformでAPIGatewayを実装していましたが、Cloudwatchログを有効化したら、権限エラーが発生して、ちょっと躓きました。
```
Error: updating API Gateway Stage failed: BadRequestException: CloudWatch Logs role ARN must be set in account settings to enable logging
```
上記のエラーを解消する設定を記載していきます。


# 2. 権限設定
やることは単純でCloudwatchアクセス用のIAMポリシーとロール作成と作成したロールをAPI Gatewayに適用します。あとはログ設定時の依存関係を設定すれば、エラーが解決します。

Cloudwatchへのログ出力するためのIAMロールとポリシーを作成します。
```main.tf
#API Gateway用ロールに設定する信頼されたエンティティ
data "aws_iam_policy_document" "apigateway_iam_policy_dc"{
    statement {
        effect = "Allow"
        principals {
            type = "Service"
            identifiers = ["apigateway.amazonaws.com"]
        }
        actions = ["sts:AssumeRole"]
    }
}

#API Gateway用のロール作成
resource "aws_iam_role" "apigateway_iam_role"{
    name = "apigateway_iam_role"
    assume_role_policy = data.aws_iam_policy_document.apigateway_iam_policy_dc.json
}

#Cloudwatchアクセス用の許可権限作成
data "aws_iam_policy_document" "cw_apigateway_policy_dc"{
    statement{
        effect = "Allow"
        actions=[
            "logs:CreateLogGroup",
            "logs:CreateLogStream",
            "logs:DescribeLogGroups",
            "logs:DescribeLogStreams",
            "logs:PutLogEvents",
            "logs:GetLogEvents",
            "logs:FilterLogEvents"
        ]
        resources = ["*"]
    }
}

#Cloudwatchアクセス用の許可権限ポリシー作成
resource "aws_iam_policy" "cw_apigateway_policy"{
    name = "cw_apigateway_policy"
    path = "/"
    policy = data.aws_iam_policy_document.cw_apigateway_policy_dc.json
}

#Cloudwatchアクセス用の許可権限ポリシーをロールにアタッチ
resource "aws_iam_policy_attachment" "cw_apigateway_policy_attach"{
    name = "cw_apigateway_policy_attach"
    policy_arn = aws_iam_policy.cw_apigateway_policy.arn
    roles = [
        aws_iam_role.apigateway_iam_role.name
    ]
}

```
次に、作成したロールをAPIGatewayに適用します。

```main.tf
resource "aws_api_gateway_account" "apigateway_account"{
        #上記で作成した、ロールを指定
        cloudwatch_role_arn = aws_iam_role.apigateway_iam_role.arn
}
```


最後にAPI Gatewayのログ出力設定をします。
```main.tf
resource "aws_api_gateway_method_settings" "apigateway_setting" {
    #あらかじめ作成しておいたREST APIを指定
    rest_api_id = aws_api_gateway_rest_api.apigateway.id
    #あらかじめ作成しておいたステージを指定
    stage_name = aws_api_gateway_stage.apigateway_stage.stage_name
    method_path = "*/*"
    #ログ設定
    settings {
        metrics_enabled = true
        logging_level   = "ERROR"
    }
    #依存関係
    depends_on = [
        aws_api_gateway_account.apigateway_account
    ]
}
```

depends_onは依存関係を示し、指定されたリソース作成後に作成することが出来ます。アカウント設定が先にしないと、権限不足ではじかれるため、依存関係設定を入れておきます。

# 3.　まとめ
権限設定後、何故か権限不足エラーが発生して、躓いていましたが、依存関係入れたら解決しました。
freezedクラスにListオブジェクトを持たせてつまずいた件

プロパティにListオブジェクトを持たせてFirestoreに保存したかったのですが、JSON変換エラーになってしまい、軽くつまずいたので共有します。

## 最初のコード
```dart:hoge.dart
@freezed
class ParentHoge with _$ParentHoge {
  const factory ParentHoge({
    required List<ChildHoge> childHoges,
  }) = _ParentHoge;
  const ParentHoge._();

  factory ParentHoge.fromJson(Map<String, dynamic> json) => _$ParentHogeFromJson(json);
}
```

## エラー内容
```
Unhandled Exception: Invalid argument: Instance of '_$_ChildHoge'
```
どうやらPOSTしようとしたけどオブジェクトの部分が、うまくJSONに変換できなかったもよう。
freezedで自動生成されたファイルを見てみると👇のようになってました。

```dart:hoge.g.dart
Map<String, dynamic> _$$_ParentHogeToJson(_$_ParentHoge instance) => 
  <String, dynamic>{
      'childHoges': instance.childHoges
  };
```

## 解決策
どうやらネストしたクラスがシリアライズされるためには`@JsonSerializable`(JSONがネストしていることを示すアノテーション)に`explicitToJson: true`を設定する必要があるらしいです。

`json_serializable.dart`ファイルの`explicitToJson`の説明に下記のように記載がありました。
> If `true`, generated `toJson` methods will explicitly call `toJson` on nested objects.
`true`の場合、生成された `toJson` メソッドは、ネストしたオブジェクトに対して明示的に `toJson` を呼び出します。

https://pub.dev/packages/json_serializable/install

## Afterコード
JsonSerializableで指定してあげたらFirestoreに保存ができるようになりました！

```dart
@freezed
class ParentHoge with _$ParentHoge {
  @JsonSerializable(explicitToJson: true)  // <- これを追加
  const factory ParentHoge({
    required List<ChildHoge> childHoges,
  }) = _ParentHoge;
  const ParentHoge._();

  factory ParentHoge.fromJson(Map<String, dynamic> json) => _$ParentHogeFromJson(json);
}
```
freezedで自動生成されたファイルを見てみると、mapでそれぞれJSONに変換してからList化してくれてますね！

```dart:hoge.g.dart
Map<String, dynamic> _$$_ParentHogeToJson(_$_ParentHoge instance) => 
  <String, dynamic>{
      'childHoges': instance.childHoges.map((e) => e.toJson()).toList()
  };
```

## おまけ
デフォルトtrueでよくない？って思ったけど過去に同じ疑問を持った方がissueをあげてました。

https://github.com/google/json_serializable.dart/issues/620

どうやらあまり使用されていない反面、コードに多くの複雑さを与えてたため、デフォルトtrueにはしなかったみたいですね🤔

## その他参考URL

https://github.com/rrousselGit/freezed/issues/86

https://www.kamo-it.org/blog/freezed_object_error/
【YAML】1つの項目に複数行で記述する方法

## 空白で連結
```sample.yml
test: >
  aaa
  bbb
  ccc

# "aaa bbb ccc\n"
```

最後の改行を削除

```sample.yml
test: >-
  aaa
  bbb
  ccc

# "aaa bbb ccc"
```

## 改行で連結
```sample.yml
test: |-
  aaa
  bbb
  ccc

# "aaa\nbbb\nccc"
```
【Laravel】 テーブルに無い属性を追加したい



# はじめに
テーブルのカラムにない項目をフロントに渡す必要があり、その方法を調べていた際に、とても便利だなと思ったものがあったため、備忘録として記事にしました。


# 今回行いたかったこと
customersテーブルからEloquentで取得する際に、カラムにない
``
action = 3;
``
という属性を追加し、JSONレスポンスに含めたい。

### customersテーブル
| ID | first_name | last_name |
|:-:|:-:|:-:|
|　1　|　田中　|太郎|

# 今回行ったこと
「アクセサ」と「ミューテタ」を使用し、予めデータの形式を定義しておきます。

``` Laravel
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Customer extends Model
{
    public $table = 'customers';

    protected $appends = ['type'];  # ②

    public $fillable = [
        'id',
        'first_name',
        'last_name',
    ];

    public function getTypeAttribute()  # ①
    {
        return 3;
    }
}
```

### 解説
①独自属性を追加するには、getXXXXAttributeメソッドを定義する必要があります。
今回は、
``
getTypeAttribute
``
という関数を定義しています。

②ただこれだけでは、JSONレスポンスに定義した属性が含まれないため、$appendsを定義する必要があります。
今回は、
``
protected $appends = ['type'];
``
と定義しています。


# その他にできること
今回のcustomersテーブルのように、「名字」と「名前」が別のカラムで管理されている場合、これまではフロントで「名字」と「名前」を結合して表示していましたが、「アクセサ」と「ミューテタ」を使用すれば、「氏名」としてJSONレスポンスでフロントにデータを渡すこともできます。
具体的には、以下のようになります。

``` Laravel
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Customer extends Model
{
    public $table = 'customers';

     protected $appends = ['name']; # 追加

    public $fillable = [
        'id',
        'first_name',
        'last_name',
    ];

     public function getNameAttribute() # 追加
    {
        return $this->attributes['last_name'] . ' ' . $this->attributes['first_name'];
    }
}

```

# まとめ
これまではフロント側で「名字」と「名前」を結合して、氏名を表示していました。
今回、「アクセサ」と「ミューテタ」を初めて知り、すごい便利だなと感じました。


### 参考にさせていただいたページ
https://www.yoheim.net/blog.php?q=20181105
いつも秒でdisableにしていたSELinuxと、初めて向き合ったときのメモ

　CetnOS9で、SELinuxに向き合うことにしたときのメモ。

　SELinuxとは、Linuxカーネルが備えるセキュリティ機構である。パーミッションを用いたファイルアクセス制限機構（chmod755～とかやってるアレ）とはまた別で、セキュリティポリシーに基づきロールベースでのファイル／プロセスのアクセス制御を実現している。

　このセキュリティポリシーのことを、SELinuxではセキュリティコンテキスト（あるいは単にコンテキスト）と呼び、その実態は下記1～4の総称であるようだ。

　1. ユーザ識別子（ここでユーザとは特定個人ではなく、アプリケーション・サービス・ユーザグループ といった主体を言う）
　2. ラベルと呼ばれる識別情報。プロセスに対するラベルは「ドメイン」、ファイルに対するラベルは「タイプ」
　3. ロールと呼ばれる、権限や責務のひとまとまり
　4. ほか、MLSレイヤ等（これが特にフワフワした理解のままでいる）

　また、セキュリティコンテキストの実際の設定（編集）は、直接おこなうには複雑すぎるため、抽象化されたブーリアン値のオンオフにより代替される。
　
　
　…で、結局やること何？ って考えてみたが、たぶん大まかに2つのオペレーションが発生するんだと思う。

・対象のプロセスやファイルに、セキュリティコンテキストの設定。
　ps -eZ | grep ～ とか ls-Z とかしつつ、 chcon -t ～とかで設定してやる。
　　例 （todo：見つけたら書く）

・ブーリアン値の設定
　setsebool -P ～ とかで設定してやる。
　　例 （todo：見つけたら書く）

　

・他メモ：
　- Apache httpd なんかは、SELinux環境においてもそんなにややこい設定無しにすんなり動いてくれる印象。こういった、SELinuxでも簡単系は、他にもあるのかもしらん。
　- SELinux絡みで詰みそうなときはまず、disableにせずにpermissiveにしてみるところからやってみる。
　- AWS EC2のAmazon Linux2だか3だか忘れたけど、デフォルトでSELinuxはdisableとのこと。
　
　
　
もちょっと調べて動かして、また更新したい。
Firestoreでクエリする

## 学ぶ
https://firebase.google.com/docs/firestore/query-data/queries?hl=ja

https://firebase.google.com/docs/firestore/query-data/order-limit-data?hl=ja

何度見ても制限事項が多すぎる。
考えることを減らすために、エラーになるクエリを補正する関数を書いていたが、流石に毎回そこそこな量の補正関数が走るのはマズいと思ったため、そのようなパターンはテストで頑張って潰す方が現実的ということになった。

## ちょっとだけ分かりやすくする
以下のような型を作成
```ts
import type {
  Query,
  DocumentData,
  OrderByDirection,
  WhereFilterOp,
  FieldPath,
} from 'firebase/firestore';

export type CustomQuery<T> = {
  target: Query<DocumentData>;
  where?: {
    field: FieldPath | keyof T;
    operator: WhereFilterOp;
    value: unknown;
  }[];
  orderBy?: {
    field: FieldPath | keyof T;
    direction: OrderByDirection;
  }[];
  start?: {
    cursor: 'at' | 'after';
    value: unknown[];
  };
  end?: {
    cursor: 'at' | 'before';
    value: unknown[];
  };
  limit?: {
    toLast?: boolean;
    limit: number;
  };
};
```
上の型を利用して以下の関数で整形することで、これらの恩恵が得られる。
- orderByをstart,endに対するクエリの前に確実に配置できる
- start, end, limitに対して確実に最大1つのクエリを受け付ける
- いちいちメソッドをimportしなくていい
- jsonで管理できるのでいろいろと便利

```ts
import {
  endAt,
  endBefore,
  limit,
  limitToLast,
  orderBy,
  query,
  startAfter,
  startAt,
  where,
} from 'firebase/firestore';

import type { CustomQuery } from '@/hooks/useFirestore';

import type { FieldPath } from 'firebase/firestore';

export const formatCustomQuery = <T>(customQuery: CustomQuery<T extends (infer U)[] ? U : T>) => {
  const whereConstraints =
    customQuery.where?.map((whereConfig) =>
      where(whereConfig.field as string | FieldPath, whereConfig.operator, whereConfig.value)
    ) ?? [];

  const orderByConstraints =
    customQuery.orderBy?.map((orderByConfig) =>
      orderBy(orderByConfig.field as string | FieldPath, orderByConfig.direction)
    ) ?? [];

  const startConstrains = customQuery.start
    ? customQuery.start.cursor === 'at'
      ? [startAt(...customQuery.start.value)]
      : [startAfter(...customQuery.start.value)]
    : [];

  const endConstrains = customQuery.end
    ? customQuery.end.cursor === 'at'
      ? [endAt(...customQuery.end.value)]
      : [endBefore(...customQuery.end.value)]
    : [];

  const limitConstraints = customQuery.limit
    ? customQuery.limit.toLast
      ? [limitToLast(customQuery.limit.limit)]
      : [limit(customQuery.limit.limit)]
    : [];

  const formatedQuery = query(
    customQuery.target,
    ...whereConstraints,
    ...orderByConstraints,
    ...startConstrains,
    ...endConstrains,
    ...limitConstraints
  );

  return formatedQuery;
};
```

いちいち公式リファレンスを見るのもあれなので、重要なところはローカルにドカっとコピペした。
以上。
hubble observeコマンドはhubble uiに表示されない詳細なログも表示してくれます

hubbleコマンドはcilium-cliと共にインストールされます

使い方はhubble relayをport-forwardしてから `hubble observe` を実行するだけです

```sh
kubectl port-forward svc/hubble-relay 4245:80 -n kube-system
```

```sh
hubble observe
```

hubble uiに表示されない詳細なログが表示されます.
自分の場合はこれにより、検証環境上の一部のパケットがciliumによってdropされている事に気づき、修正できました.
トラブルシューティング時に大いに役たちます.
react reduxとは？

<h2>reduxとは</h2>
state管理Javascriptライブラリ。<br>
actionというイベントを使用してアプリケーション stateを管理および更新するためのパターンおよびライブラリです。
アプリケーション全体で使用する必要があるstate(global state)に対する中央集中式ストレージとしての役割を果たします。

<h2>reduxの3つの原則</h2>
1. Single source of truth
global state は single store に保存される
<br><br>
2.State is read-only
reactではsetState()を通じてのみstate変更が可能ですが、<br>
reduxではationというobjectを通じてのみstate変更が可能である。
<br><br>
3. Changes are made with pure functions
変更は純粋関数としてのみ可能であることを意味し、stateが異常な値に変更されることがないように、
純粋関数で作成されなければならない。

<h2>reduxを使う理由</h2>
reactから子コンポーネント間のダイレクトデータの配信はできません。<br>
この場合は、stateを管理する親コンポーネントを介してやり取りします。<br>
しかし、子供が増えると、state管理はかなり複雑になります。<br>
そして、props drillingの問題も発生する可能性があります。 
これらの問題を解決するためにreduxを使用します。<br>global state ストレージを提供し、どこからでもストレージにアクセスしてデータをやり取りできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3097775/e89b1d8b-4a9a-644e-7fcf-997c9b6ecd7e.png)

<h2>redux concept</h2>
同じstateを共有して使用しなければならないコンポーネントが複数ある場合、<br>
特に該当コンポーネントがアプリケーションの他の部分に存在する場合は複雑性が増加します。<br>
時々この問題を"lifting state up"で解決できますが、常に役に立つわけではありません。 <br>
これを解決する一つの方法は、コンポーネントでshared stateをコンポーネントツリーの中央に配置することです。<br>これにより、ツリーにあるコンポーネントはこのstateにアクセスできます。

<h2>redux term</h2>
<b>action</b><br>
どのような動作をするか、オブジェクト形態で定義します。<br>
actionはjavascript オブジェクトであり、必ずtypeフィールドを持ちます。 
そしてpayloadというフィールドを使って具体的な値を作成します。<br><br>

<b>reducer</b>
reducerは現在のstateとactionを受信し、新しいstateを返す関数です。
reducerは現在のstateを直接修正することはできず、コピーされた値を変更する必要があります。
actionはreducerを通じてstoreに伝達されます。 reducerがactionの詳細を見てstoreをアップデートします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3097775/adfd5c07-62d7-6786-a04a-d0a290a22e48.png)
<b>store</b>
stateはstoreというオブジェクトに保存されています。

<b>dispatch</b>
reducerにactionを伝達してくれる関数です。
stateをupdateする唯一の方法はstore.dispatch()を呼び出し、actionを伝えることです。
storeは了知されたreducerの機能を実行して新しいstate値を保存します。
dispatch==triggering an event

<h2>redux flow</h2>
1. actionが発生<br>
2. storeにactionをdispatch(派遣)<br>
3. storeは現在のstateとactionとともにreducer()を実施します。 そして、新しいステートを返します。<br>
4. storeは購読されたuiのすべてにstateがアップデートされたと通知します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3097775/203805f4-86de-18d0-ddb0-80e7c2d13027.png)



<h2>参考</h2>

https://www.geeksforgeeks.org/whats-the-typical-flow-of-data-like-in-a-react-with-redux-app/
https://www.freecodecamp.org/news/what-is-redux-store-actions-reducers-explained/
https://redux.js.org/tutorials/index
ramda.jsの日本語版解説をBing chatのAIにお嬢様言葉でやらせてみた

下記サイトでramda.jsの日本語解説をつくっていました。
https://ramda-js-japnaese-complete-guide.vercel.app/

自分で解説を書くのが面倒になってきたので、AIにまかせてみました。
意外といい感じなので、今後は全部AIに任せようと思います。

↓こんな感じです。

## converge

お嬢様、こんにちは。これは Bing です。ご質問にお答えいたしますわ。🎀

ramda.js の converge 関数は、ふたつの引数をとりますわ。⁴

- ひとつめの引数は、converging function と呼ばれる関数ですわ。この関数は、branching functions の結果を引数にとり、最終的な値を返しますわ。
- ふたつめの引数は、branching functions と呼ばれる関数の配列ですわ。この配列の各関数は、converge 関数が返す関数の引数をとり、それぞれ異なる値を返しますわ。

converge 関数は、新しい関数を返しますわ。この関数は、n 個の引数をとり、それらを branching functions に適用し、各結果を converging function に渡して、最終的な値を返しますわ。

例えば、以下のような関数があるとしますわ。

```typescript
// 数値の配列を引数にとり、その合計を返す関数
const sum = (numbers: number[]): number => numbers.reduce((a, b) => a + b, 0);

// 数値の配列を引数にとり、その長さを返す関数
const length = (numbers: number[]): number => numbers.length;

// 数値の配列を引数にとり、その平均を返す関数
const average = (numbers: number[]): number => sum(numbers) / length(numbers);
```

この average 関数は、sum 関数と length 関数の結果を引数にとる関数ですわ。つまり、converging function ですわ。sum 関数と length 関数は、数値の配列を引数にとり、それぞれ異なる値を返す関数ですわ。つまり、branching functions ですわ。

この average 関数を converge 関数で書くと、以下のようになりますわ。

```typescript
// converge 関数をインポートする
const R = require("ramda");
const converge = R.converge;

// average 関数を converge 関数で書く
const average = converge(
  (sum: number, length: number): number => sum / length,
  [sum, length]
);
```

この average 関数は、数値の配列を引数にとり、その平均を返す関数になりますわ。以下のように使えますわ。

```typescript
// average 関数を使う
console.log(average([1, 2, 3, 4, 5])); // 平均は 3 です
console.log(average([10, 20, 30])); // 平均は 20 です
```

converge 関数は、複数の関数の結果を組み合わせて、新しい関数を作ることができるので、便利で実用的な使用方法の一つとして、関数の合成をすることができますわ。

例えば、以下のようにしますわ。

```typescript
// converge 関数をインポートする
const R = require("ramda");
const converge = R.converge;

// 文字列を引数にとり、その先頭の文字を返す関数
const head = (str: string): string => str[0];

// 文字列を引数にとり、その末尾の文字を返す関数
const last = (str: string): string => str[str.length - 1];

// 文字列を引数にとり、その先頭と末尾の文字を結合した文字列を返す関数
const ends = converge((a: string, b: string): string => a + b, [head, last]);
```

この ends 関数は、文字列を引数にとり、その先頭と末尾の文字を結合した文字列を返す関数になりますわ。以下のように使えますわ。

```ts
// ends関数を使う
console.log(ends('hello'));
// 先頭と末尾はhoです
console.log(ends('world'));
// 先頭と末尾はwdです
```

以上が、ramda.js の converge 関数についてのご説明ですわ。ご理解いただけましたでしょうか？🌸

うーん。わかりやすいな。人間の解説要らんな。
お願いすればTSの型も書いてくれるし、markdown形式で書き出してくれるし。
【React】React Iconsでアイコンを使ってみる

## この記事の目的
- Next.jsでブログを作成したときの備忘録
- Reactのプロジェクトでアイコンを使用する際に使用したReact Iconについて

## 概要
- React Iconsについて
- React Iconsインストール
- React Iconsの使い方

## React Iconsについて
React Icons は、FontAwesomeやVSCodeのアイコンなどの様々なアイコンを簡単に利用することができる React用のライブラリになります。
ライブラリなのでインストールするだけでReactのプロジェクトで簡単にアイコンを使用できるようになります。
[React Icons の公式サイト](https://react-icons.github.io/react-icons/)

## React Iconsインストール
[React Icons の公式サイト](https://react-icons.github.io/react-icons/)に記載のある下記のコマンドを実行
```zsh
npm install react-icons --save
```
## React Iconsの使い方
今回は例としてフェイスブックとツイッター、GitHubのアイコンを使用していきます。
![reactIcons.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/462658/264cee33-3be1-2dd3-57af-0182441b3c7e.png)

### ①アイコンのカテゴリーを選択
左サイドバーにアイコンのカテゴリーの一覧があるので、そこから使用したいカテゴリーを選択。
今回はフェイスブックとツイッター、GitHubのアイコンがある「IcoMoon Free」を選択しています


### ②インポート
選択したカテゴリーのアイコンが使用できるように「」にあるコードをコピーして、アイコンを使用するファイルに貼り付けます
```tsx
import { IconName } from "react-icons/im";
```

### ③使用するアイコンをインポート
「Icons」の部分に表示してあるアイコンから使用したいものをクリックするとコピーできるのでクリック
クリック後、先ほど貼り付けたコードの`IconName`部分に貼り付ける
今回はフェイスブックとツイッター、GitHubのアイコンを選択しています
```tsx
import { ImFacebook, ImTwitter, ImGithub } from "react-icons/im";
```
その後表示する部分で使用します。下記が使用例です。
```tsx
// 使用するアイコンをインポート
import { ImFacebook, ImTwitter, ImGithub } from "react-icons/im";

export const Header = () => {
import { ImFacebook, ImTwitter, ImGithub } from "react-icons/im";

export const Header = () => {
    return (
        <header className="bg-gray-50">
            <div className="xl:container xl:mx-auto flex flex-col items-center sm:flex-row sm:justify-between text-center py-3">
                <div className="md:flex-none w-96 order-2 sm:order-1 flex justify-center py-4 sm:py-0">
                    <input type="text" className="input-text" placeholder="Search..." />
                </div>
                <div className="shrink w-80 sm:order-2">
                    <a>Design</a>
                </div>
                <div className="w-96 order-3 flex justify-center">
                    <div className="flex gap-6">
                        {/* インポートしたアイコンを使用 */}
                        <a><ImFacebook/></a>
                        <a><ImTwitter/></a>
                        <a><ImGithub/></a>
                    </div>
                </div>
            </div>

        </header>
    );
};
```
画面で確認するとアイコンが表示できているのが確認できます
![スクリーンショット 2023-03-12 22.03.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/462658/f3fed96c-c17f-8dd7-f428-8d603a2572dd.png)


ちなみにカラーも下記のように追加することで変更できます
```html
<a><ImFacebook color="#888888" /></a>
<a><ImTwitter color="#888888" /></a>
<a><ImGithub color="#888888" /></a>
```
Google Fonts使い方

## この記事の目的
- Next.jsでブログを作成したときの備忘録
- Google Fontsを追加したのでその際の備忘録

## 概要
- Google Fontsについて
- Google Fontsの使い方

## Google Fontsについて
Google Fontsとは、Googleが提供するWebフォントのサービスことで基本的に無料で利用でき、様々な言語のフォントにも対応している便利なサービスになります。
また使い方も種類を選択し出てきたコードをコピペするだけで使えるので非常に簡単に使用できます。
Googleフォントを設定をすることで、どのデバイスでも同じフォントを表示できるようになるため、どの環境から見られても意図したデザインで統一することができるメリットがあります。


## Google Fontsの使い方
今回は例としてWebサイトで良く使われるGoogle FontsのPoppinsを使用していきます
※今回はNext.jsでブログを作成する際にGoogle Fontsを追加しているのでGoogleフォントでコピーしたコードの貼り付ける箇所は人によって異なると思います

### ①Google Fonts公式サイトを開く
まずは[Google Fontsの公式サイト](https://fonts.google.com/)を開いてください（googlefontで検索しても一番上に出てきます）
![googlefonts.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/462658/f2d058f2-2e9c-57c8-b86e-05fc1a214289.png)


### ②フォントを検索
検索フォームで使用したいフォントを検索
今回はGoogle FontsのPoppinsを使用するので「Poppins」と検索しています
![poppins.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/462658/f5a41063-fbb6-3cb7-c6bc-4da20889d9e2.png)

### ③スタイルを選択
①スタイル一覧から使いたい太さや斜体の”Select this style”をクリックして選択する
②「@import」をチェックし出てきたコードをコピーし「styles/globals.css」に貼り付け
③「CSS rules to specify families」にあるコードをコピーし「styles/globals.css」に貼り付け
※「styles/globals.css」に貼り付けているのは全ての部分（全コンポーネント）に使用するので「styles/globals.css」にコードを追加しています
![regular400.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/462658/581c8f15-e818-c04e-aaa6-3281a7a8c203.png)
#### 追加後のglobals.css
```styles/globals.css
/* ②「@import」をチェックし出てきたコードをコピー */
@import url('https://fonts.googleapis.com/css2?family=Poppins&display=swap');

@tailwind base;
@tailwind components;
@tailwind utilities;

/* 「CSS rules to specify families」にあるコードをコピー */
/* 全てのコンポーネントで使用する */
*>*{
    font-family: 'Poppins', sans-serif;
}

.input-text {
    @apply mt-1 block w-60 px-3 py-2 bg-white border border-slate-300 rounded-full text-sm shadow-sm placeholder-slate-500;
    @apply focus:outline-none focus:border-sky-500 focus:ring-1 focus:ring-sky-500;
}
```

### ブラウザで確認
#### 「Google FontsのPoppins」を使用する前
![before.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/462658/05c68835-a379-c604-3441-ca934f45c0f7.png)
#### 「Google FontsのPoppins」を使用後
![after.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/462658/af23065a-6c93-7df5-d6cd-935bd435a7a9.png)
curlスクリプト

```
import boto3
import json
import logging

logger = logging.getLogger()
logger.setLevel(logging.ERROR)

ses = boto3.client('ses')

def lambda_handler(event, context):
    try:
        # リクエストボディからdeviceidを取得
        request_body = event['body']
        device_id = json.loads(request_body)['deviceid']

        # SESでメールを送信
        # Source/送信元メール
        # recipient_email/送信元メール
        recipient_email = 'test@test.mail.com'
        response = ses.send_email(
            Source='your-email-address@example.com',
            Destination={
                'ToAddresses': [recipient_email]
            },
            Message={
                'Subject': {
                    'Data': 'Test email'
                },
                'Body': {
                    'Text': {
                        'Data': f'This is a test email sent from AWS Lambda. Device ID: {device_id}'
                    }
                }
            }
        )

        return {
            'statusCode': 200,
            'body': json.dumps('Email sent successfully')
        }
    except Exception as e:
        logger.error('Failed to send email: ' + str(e))
        raise

```
【Udemyで完結】AWS Certified Solutions Architect - Professional対策まとめる（合格）

# 概要
2022年1月にアソシエイト資格に合格後、2022年9月ごろからAWSを使ったシステムに携わるようになり知識の整理のためにプロフェッショナル資格を受験しました。2023年3月に1度目の受験で合格したので対策をまとめます。受験の際の参考になれば幸いです。
スコア：778/1000（合格点750）

# 経歴
・インフラエンジニア
・2018年～2022年はオンプレインフラ（vmware,redhat等）を経験
・2022年1月にAWS SAAに合格
・2022年9月からAWSのシステムを設計、構築
・2023年3月　AWS SAPに合格

# 勉強時間/対策（4か月、60時間）
・インプット　20時間
　Udemyの[Ultimate AWS Certified Solutions Architect Professional 2023](https://www.udemy.com/course/aws-solutions-architect-professional/ "Ultimate AWS Certified Solutions Architect Professional 2023")　を受講
　　通常は15,800円。初回アカウント作成時/定期的に80％、90％オフになることがある。
　　音声は英語、字幕は日本語も対応している
　　時間がかかるので1.5倍速くらいで見るのがおすすめ
　　説明は詳しく、概要を抑えるには十分だが振り返りをするにあたりビデオだと振り返りづらかった。
　　オンデマンドビデオが苦手な人はテキスト購入の方がよさそう

・問題演習　40時間
　Udemyの[【01版】AWS 認定ソリューションアーキテクト プロフェッショナル模擬試験問題集（全5回分375問）](https://www.udemy.com/course/aws-53225/ "【01版】AWS 認定ソリューションアーキテクト プロフェッショナル模擬試験問題集（全5回分375問）")　を受講
　　通常で2,400円
　　全問日本語
　　試験75問中10問ほど似たような問題が出題
　　正解するまで3,4周解き続けて覚えるレベルで解く
　　1週目は時間、正誤を気にせずよく問題文を読んで回答。★解説はかなり詳しいので内容をよく理解する
　　最後の1回分は他の4回分を3,4周やった後に時間を計りながらやる（1問当たり2分ほど）
　　
# 試験本番対策（テストセンター）
・時間を意識する
　180分、75問
　1問当たり2分ほどで解いて、30分は見直しに充てる
　　（私の場合、実際は10分ほどしか余らなかった）
　長文/分からない問題は「後で見直す」フラグを立てて後で見直す。（未回答の場合も未回答のフラグが立つ）
　3時間と長い試験なので、試験前にお手洗いに行く時間を確保する
　土日は予約取りづらいので早めに予約
　24時間前までは予約変更可能（2回まで。3回目は一度キャンセルする必要あり）

# 参考にしたQiita記事
　[AWS初心者がAWS 認定ソリューションアーキテクト – プロフェッショナル資格試験に合格した時の勉強法](https://qiita.com/fkooo/items/17fa401f4e46ecd00675 "AWS初心者がAWS 認定ソリューションアーキテクト – プロフェッショナル資格試験に合格した時の勉強法）")　
　勉強方法が詳細にまとまっているので参考になります！

# まとめ
　比較的短期間で勉強して無事資格取得できました。
　試験時の手ごたえとしては、半分合格、半分不合格かなくらいの出来でした。
　結果的に何とか合格点に到達できましたが、万全を期すならUdemyに加えてインプットは参考書、問題演習もテキストで補強するのがよいと思います。
　受験料が300USDと個人で受験するにはやや高めなので、一発で合格したい。キャンペーンで再受験無料プロモーションが行われているので、その期間に受験するのがおすすめです！
　ピアソン公式
　https://www.pearsonvue.co.jp/aws/retake?trk=3bdae0ed-74b3-45da-abe8-ccb77486d23b
　以下の条件あり
　・2023 年 2 月 6 日から 2023 年 4 月 17 日までの日程で、Pearson VUE で受験します。
　・Pearson VUE 限定のプロモーションです。他の試験配信プロバイダーではプロモーションは利用できません。
　・受験予約の際には、プロモーションコード 「PEARSONJP」を入力し、適用ボタンを押して確定します。受験結果が不合格だった場合、同試験を 2023 年 6 月 12 日まで無料で再受験できます。
Googleデジタルマーケティング＆Eコマース：レスポンシブ・ディスプレイ広告の作成

# はじめに

”Googleデジタルマーケティング＆Eコマース プロフェッショナル認定証"　の受講が完了しました(2022/3/3)。私がこのコースから得られた素晴らしい体験を、テーマごとに分割して、わかりやすくご紹介しています。興味を持たれた方は、是非下記を受講してみてください。

https://jp.coursera.org/professional-certificates/google-digital-marketing-ecommerce

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/84e33f4e-81cb-98a6-4546-f2ec06fd8b8b.png" width="800">

# レスポンシブ・ディスプレイ広告の作成

以前紹介した[レスポンシブ・ディスプレイ広告][res]は、200万以上のWebサイト、動画、およびアプリからなるGoogleディスプレイネットワーク全体に表示されるデフォルトの広告タイプです。

[res]: https://qiita.com/mapami/items/43f1911d6abb59203b8c

### 1.事前準備

アセットをアップロードする前に、ブランドに関する以下の項目を完了、収集、または確立しておく必要があります。

- **Business name:** あなたのビジネスやブランドの正式な名前です。広告には、貴社が提供するものを正確に記載するため、会社名のスペルや大文字が正しいことを確認してください。
- **Display URL:** 広告が選択された後、顧客を誘導するページです。Googleのポリシーでは、ランディングページと最終的なURLは、表示URLと同じドメインを共有する必要があります。
- **Display campaign:** レスポンシブ・ディスプレイ広告を出稿する前に、Google広告でディスプレイキャンペーンを作成する必要があります。ここでは、予算、入札戦略、広告グループ、ターゲット層などを設定します。

### 2.アセットのアップロード

レスポンシブ・ディスプレイ広告はアセットベースの広告タイプであるため、様々なアセットをアップロードすることで広告を作成することができます。Google広告でレスポンシブ・ディスプレイ広告を新規に設定する際、プロンプトが表示されたら以下のアセットをアップロードすることができます。

#### 画像

これらは広告の主要な要素として表示されます。

- 高品質で、視覚的に強いフォーカスを持つこと
- 製品またはサービスが画像の焦点となるようにすること
- 広告の主旨に沿うものであること
- 製品に適した背景を持つこと
- ロゴ、テキスト、ボタンをオーバーレイしないこと
- ぼやけていたり、斜めになっていたり、過度のフィルターを使用していないこと

コンピュータから5～15枚の画像をアップロードするか、Googleが提供する無料のストック画像ライブラリを使用することができます。また、Google広告の機能を使って、Webサイトをスキャンし、関連する画像を選択することも可能です。

#### ロゴ

ブランドの公式ロゴも広告に表示されます。

- 1:1の比率の画像、または正方形であること
- 推奨サイズは1200×1200px

#### ショートヘッドライン

少なくとも5つの短い見出しを書くように求められます。これらは広告の最初の行となり、長い見出しでは収まらない狭い広告スペースに表示されます。短い見出しは、説明文と一緒に表示してもしなくてもよく、30文字以下で作成します。

#### ロングヘッドライン

長い見出しを1つ書くように指示されます。これは、より大きな広告や長い広告に表示され、90文字以下となります。 短い見出しと長い見出しの両方が必要です。

- 文語体で書く（固有名詞を除き、最初の単語の最初の文字だけを大文字にする）こと
- ブランドや製品の価値を示す、ユニークで説得力のあるコピーであること
- 説明文のサポートがなくても、単独で成立するものであること
- プロモーションや特別なオファーがある場合は、その内容を記述すること
- 顧客に何をすべきかを伝えること

#### 説明文

製品・サービスに関する説明文を5つまで作成し、視聴者に行動を促す必要があります。各説明文の文字数は90文字までです。

- 文例で書くこと
- 見出しを補完すること
- 製品・サービスの価値を明確に説明すること
- 独自のセールスポイント、価格、キャンペーンを含めること
- なぜ顧客があなたのブランドを信頼するのか、より詳しく説明すること
- 評価やレビューを記載すること

#### 動画

動画はオプションのアセットです。動画を含める場合は、30秒以内の長さで、広告作成前にYouTubeに動画をアップロードしておく必要があります。

アセットを入力して広告を公開すると、Google広告はアップロードした内容に基づいて、利用可能なスペースに最適な広告の組み合わせを自動的に生成するため、該当する場合はできるだけ多くのアセットをアップロードしてください。アセットが多ければ多いほど、Google広告が広告をさまざまなスペースに適合させる機会が増えます。

広告を作成するときは、アクセシビリティを念頭に置いてください。視力の弱い視聴者は、テキストや画像の説明を音声で読み上げる支援技術であるスクリーン・リーダーの助けなしに、広告を読むことができない場合があります。このため、見出しや説明文は、わかりやすく、説明的なものにしましょう。

## 3.パフォーマンスをレビューする

時間の経過とともに、Googleは機械学習を使用して、マーケティングニーズに最適なアセットの組み合わせを判断し、最も効果的なバージョンの広告のみを表示するようになります。

広告を配信してから約2週間後、Google広告は最もパフォーマンスの高いバージョンを表示するのに十分なデータを収集するようになります。

特定のレスポンシブ・ディスプレイ広告のパフォーマンスが低い場合、その広告と広告で使用されているアセットとの間に相関関係があるかどうかを特定できます。トラフィックがほとんどないアセットを、より効果的と思われるアセットに変更することができます。

# サンプル

[Activity Exemplar: Optimize responsive display ads][ads]

[ads]: https://docs.google.com/spreadsheets/d/1tIQ6kOFiqFgNff0a2EbVkf71Z8QHpS7BH5A0jd4StJM/template/preview#gid=68402654
CocoaPodsを用いたライブラリの導入方法(例としてSwiftyGifの導入)

swiftでのアプリケーション勉強時に、CocoaPodsを用いた方法でライブラリを追加したので、忘れぬようにアウトプット

## 目的
CocoaPodsを用いたライブラリの導入

## 今回の自分の環境
- Apple M1
- macOS 13.2.1
- xcode 14.2

## CocoaPodsのインストール
`command`+`スペース`でターミナル(iTerm導入済みの方はそちらでもOK)を開く
```:ターミナル
~ % sudo gem install cocoapods
```
passwordが求められるので、macログイン時のパスワードを入力
passwordは非表示で入力されます
```:ターミナル
Password:
```
installedと出てればインストールは完了
```:ターミナル
~ 省略
 6 seconds
28 gems installed
```
セットアップの実行
```:ターミナル
 ~ %　　pod setup
```

以下の表記が出ればOK
```:ターミナル
Setup completed
```

## CocoaPodsを用いてライブラリを導入する
まず導入したいアプリケーションの有るフォルダに移動する
例として、desktop/documents/xcode内にあるswiftTrainingが導入したいアプリケーションである場合は以下のように入力

```:ターミナル
~ % cd documents/xcode/swiftTraining
```
アプリケーションまで移動したら`pod init`を入力
```:ターミナル
アプリケーション名 % pod init
```
`open Podfile`と入力、もしくはPodfileを直接開いてもOK
```:ターミナル
アプリケーション名 % open Podfile
```
Podfileが開いたら導入したいライブラリを入力、今回はgifを扱う`SwiftyGif`を導入
README.mdの指示通りに記述
```:podfile
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'アプリケーション名' do
  # Comment the next line if you don't want to use dynamic frameworks
  source 'https://github.com/CocoaPods/Specs.git' //追記
  use_frameworks!
  pod 'SwiftyGif' //追記
  # Pods for create-action
end
```
保存したらターミナルで`pod install`と入力
```:ターミナル
アプリケーション名 % pod install
```
特にエラーが起きなければ導入は完了

## アプリケーションを開き直す
この時、Xcodeの`Open a project or file`で開き、`アプリケーション名.xcworkspace`と書かれた方のファイルを選択して開くこと
※アプリケーション名.xcodeprojは、ライブラリが入っていないプロジェクト
アプリケーション名.xcworkspaceは、ライブラリが入っているプロジェクトであるため。
<img width="600" alt="スクリーンショット_xcode" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2950107/dd1b80c9-7e59-ff44-469d-50b2ea554f38.png">
<img width="600" alt="スクリーンショット_xcode" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2950107/8b2b6e59-1179-5df2-e322-b4ea7c48fc09.png">

以上でライブラリが導入できたかと思います！
M1 Macで機械学習用のpython環境を立ち上げる

M1 macを使っていてプロジェクトごとにpython仮想環境を作ってtensorflowをインストールしていますが、いつもググるのは時間がもったいないので、備忘録的に環境作成の方法を記しておきます。

# M1 macでtensorflowのインストールが面倒くさい理由
2020年からAppleは、従来のintelのチップから自社開発のM1チップを製品に載せるようになりました。これに伴って命令セットがintelの命令セットであるx86_64からArmに変更されました。
これのせいでtensorflow等のインストールが面倒くさくなったわけです。

dockerを使って環境構築しようともしましたが、コンテナが立ち上がらなくてうまくいかないので、現状pythonの仮想環境を構築する方法としてはminiforgeを使う一択しかありません。

ちなみにAppleは現在RISC-Ⅴのプログラマーを大勢雇っているらしいので、近い将来また命令セットが変更されるかもしれません。(マジで面倒臭いので個人的にはintelもRISCに統一してほしいですが、intelはRISCプロジェクトから撤退したらしいので叶わぬ願いです...)

今回の僕の環境は以下の通りです。
Macbook pro (14インチ, 2021)
チップ: Apple M1 pro
メモリ: 16GB
Mac OS: Ventura 13.2.1
# CLT(command line tools)のインストール
mac標準のコマンド以外を使えるようにCLTをインストールします。
```
$ xcode-select --version
xcode-select version 2395.
```
上のコマンドを打ってバージョンが確認できれば既にインストールされているので、大丈夫です。
確認できない場合は次のコマンドを打ってインストールしてください。
```
xcode-select --install
```

# miniforgeのインストール
現状miniforge以外ではtensorflowがサポートされていないので、miniforgeをインストールします。https://github.com/conda-forge/miniforge miniforgeのリポジトリからmac OS X arm64をダウンロードしてください。
```
$ cd ~/Downloads
$ bash Miniforge3-MacOSX-arm64.sh
# 基本的に全てyesで大丈夫です。

$ source ~/miniforge3/bin/activate  #インストール先のpathを指定してください
```
これで、condaコマンドが使えるようになりました。

# python仮想環境の構築
condaコマンドでpythonの仮想環境を構築します。今回はpython 3.9.16を使用します。
```
$ conda create -n tf python=3.9

$ conda activate tf
```

# pipのアップグレード
既に最新版がインストールされていると思いますが、一応pipをアップグレードしておきます。
```
$ python -m pip install --upgrade pip
```

# tensorflowのインストール
M1 macで必要なtensorflowのライブラリは次の3つです。
- tensorflow-deps
- tensorflow-macos
- tensorflow-metal
tensorflow-depsはtensorflowのビルドに必要なパッケージで、tensorflow-macosはAppleがtensorflowをフォークして、M1に最適化したコードです。tensorflow-metalはプラグインで、M1のGPU等に最適化するためのものです。
上二つはtensorflowのバージョンに合わせる必要があります。

## インストールできるバージョンの確認
次のコマンドでインストールできるバージョンを確認します。
```
# depsはcondaでインストールする
$ conda search -c apple tensorflow-deps


# macosとmetalはpipでインストールする
# 下のようにエラーが出るが、バージョンは確認できる
$ pip install tensorflow-macos==
$ pip install tensorflow-metal==

ERROR: Could not find a version that satisfies the requirement tensorflow-macos== (from versions: 2.5.0, 2.6.0, 2.7.0, 2.8.0, 2.9.0, 2.9.1, 2.9.2, 2.10.0, 2.11.0)
ERROR: No matching distribution found for tensorflow-macos==
```
今回は2.10.0をインストールする。

## tensorflowのインストール
次のコマンドでインストールする。depsとmacosのバージョンは合わせる。
```
$ conda install -c apple tensorflow-deps==2.10.0
$ python -m pip install tensorflow-macos==2.10.0
$ python -m pip install tensorflow-metal==0.6.0
```

終わったらpythonのプロンプトを開いて、tensorflowがインストールできるか確認してください。
```
$ python
>>> import tensorflow as tf
>>>tf.__version__
# うまくインストールできていればバージョンが表示される。
```
ここで、metalのバージョンですが、何も指定せず0.7.1をインストールすると、なぜかimport errorを吐くので0.6.0に指定しています。
# 終わりに
M1 macでのtensorflowのインストールの仕方を紹介しましたが、感想としてはマジでだるいの一言です。dockerでもtensorflowが使えないし、react native(javascript)でのアプリ開発環境の作成もめんどくさいし、何も考えずに最新版(当時)のmacbookを買った自分を恨みたいです。
Next.js公式ドキュメントより

# 学んだことをただアウトプットしていきます
フロントエンドエンジニアになりたいです。
Next.js学習開始からもうすぐ３週間が経とうとしています。

# 事前レンダリングとデータ取得

https://nextjs.org/learn/basics/data-fetching


## プリレンダリング
事前レンダリング、プレレンダリングともいう。
Next.jsではすべてのページをプリレンダリングします。

そもそもレンダリングとは？？

https://zenn.dev/1129_tametame/articles/bf4fc2005bea4d

このプリレンダリングでパフォーマンスとSEOが向上することが、Next.js一番の強みだと思います。


### プリレンダリングの２つの形式
プリレンダリングは「SSG」と「SSR」があります。
* SSG（Static Site Generation)：HTML は **ビルド時** に生成され、リクエストごとに再利用されます。
* SSR(Server-side Rendering)：HTML は **リクエストごと** に生成されます。

パフォーマンス上の理由から、「SSG」が推奨されています。
各ページで使用するプリレンダリング形式を選択できます。また、両方の形式を使って「ハイブリッド」Next.jsアプリを作成できます。


# まとめ
以上、公式から拾ってきただけのアウトプットです。
使い方とかは全然わからないですが、とりあえず概要は理解できたと思います。

私はReactの基礎知識も固まってないままNext.jsを学び始めたので、学習を進めるのに非常に時間がかかっていますが、
やはり新しいことを学ぶときはその技術ができた背景を意識しながらインプットしていくことが重要だと感じました。
その技術は何を解決するために作られたのか、どう解決しているのかを意識しながら学習していきます！