OmniAICreator/Qiita-1.07M huggingface dataset:
AI Programmerの作法 その6

# 概要
AI Programmerの作法、調べてみた。
atcoderやってみた。

# 投入したソースコード
- C++
- N枚の整数値が与えられ、それらの重複しない要素の数を数える問題です。

# 実行結果

```
N枚の整数値が与えられ、それらの重複しない要素の数を数える問題です。

#include <iostream>
using namespace std;

int main() {
    int N;
    cin >> N;
    int a[N];
    for(int i = 0; i < N; i++)
    {
        cin >> a[i];
    }
    int count = 0;
    for(int i = 0; i < N; i++)
    {
        bool flag = true;
        for(int j = 0; j < count; j++)
        {
            if(a[i] == a[j])
            {
                flag = false;
            }
        }
        if(flag)
        {
            a[count] = a[i];
            count++;
        }
    }
    cout << count << endl;
    return 0;
}



```

# paiza.io
# 入力

```
3
12
10
10
```


# 実行結果

```
2
```

# 成果物

https://paiza.io/projects/IdOrCPFZcqzI3454fdkSeA

以上。
TypeScript(恐らくJavaScriptでも)で読み込むモジュールを切り替えたかった話

# そもそも何しようとしてたか

`.env`ファイルや環境変数等の情報を元に、使うモジュールが切り替わる場合、使われないモジュールを読み込まなければ、CPUやメモリのリソースを削減できそうだと思い、色々試してみていました。
結論としては、どうしても使われる可能性のあるモジュールは全部読み込ませないといけないようだ、ということに至りました。

# 何をしたか

## `import`文に可変な文字列を仕込む

```javascript
const param = 'hoge_1';
import hoge from `./util/${param}.js`;
```

これに関しては、`error: The module's source code could not be parsed: Unexpected token ```. Expected a string literal`と出ました。

同じように、
```javascript
const param = 'hoge_1';
import hoge from './util/' + param + '.js';
```
も、`The module's source code could not be parsed: Expected ';', got '+'`と、`import`に渡すパラメータ絡みと思われるエラーが出ました。

## `import`文を分岐させる

`import`に渡すパラメータを変化させられないのであれば、`import`文周りを変化させれば良いではないか、と次善の策に出ました。

```javascript
const param = 'hoge_1';
switch (param) {
  case 'hoge_1':
    import hoge from './util/hoge_1.js';
    break;
  default:
    import hoge from './util/hoge.js'
}
```

このようにしてみましたが、`The module's source code could not be parsed: 'import', and 'export' cannot be used outside of module code`と出ました。どうも`import`を`if`や`switch`で分岐させることはできないようでした。

# 最終的に何したか

`import`させるモジュールの切り替えには失敗しましたが、辛うじてコード内で使用するモジュールの切り替えは行えたので、それを紹介します。

```javascript
import hoge_1 from './util/hoge_1.js';
import hoge_default from './util/hoge.js';

let hoge = /* なんかそれっぽい仮置きオブジェクト */;
const param = 'hoge_1';
switch (param) {
  case 'hoge_1':
    hoge = hoge_1;
    break;
  default:
    hoge = hoge_default;
}

```

# 最後に

今回に関しては、実際にこれをやりたかったコードでは、切り替えるモジュール群が大したことない大きさだったので別に大丈夫だったのですが、私が思うに、この世にはクソデカモジュール群があると思うのです……。そういった場合にはモジュールを本当に切り替える必要が出てくるのではないかと思います。
もし、モジュールを切り替える方法が実はあるということがあれば、コメント等よろしくお願いします！
【SSH】GitHubへSSHアクセスをチェックする

## 概要
「このSSH鍵で、ちゃんとGitHubにSSHで繋るのかな？」というのが気になった時の確認コマンド

GitLabや他の通信先も同様なので、確認したいサービスに合わせて読み換えてください

## コマンド

### 基本
デフォルトの秘密鍵（`id_rsa`）で実行

```bash
ssh -T git@github.com
```
※ SSH v1： `~/.ssh/identity` がデフォルト
※ SSH v2： `~/.ssh/id_rsa` と `~/.ssh/id_dsa` がデフォルト
※ `-T` オプション： 仮想端末の割り当てを禁止（GitHubがPTYの割当を許可していないため、警告メッセージが出ることを防ぐ）

### 秘密鍵を指定して実行
デフォルト以外の秘密鍵（SSH鍵）で実行

```bash
ssh -T -i another_key git@github.com
```

### ユーザ名を指定して実行
別のユーザ名で実行（GitHubで使うことは多分ない）

```bash
ssh -T -l user github.com
```
もしくは
```bash
ssh -T user@github.com
```
VBA try catch 代用

エラーが発生した際に、catchラベルに飛び、エラー内容とエラーラベルをメッセージに表示する
```
Option Explicit

Sub ErrFunctionSample()
      On Error GoTo catch
try:
100:
101:      Dim ErrMsg As String
102:      Debug.Print (Range("A1").test)
103:
104:
105:
106:      Exit Sub
catch:
      ErrMsg = err.Description & " Label：" & Erl
      MsgBox ErrMsg

End Sub
```

## ラベル付与
1,コードをシートにペースト
2,選択したセルからendLabelStrで指定したセルまで必要に応じてラベルを付与する
```
Option Explicit

Private startLabelNo As Long '開始No
Private endLabelStr As String
Private rgScope As Range
Private btmR As Long
Private rg As Range
Private labelNoTmp As Long

Private Sub setLabelNo()
'■コードにlabelNoを付ける
'Noを付けたいコードをシートに貼り付け、セルを選択し実行。

  startLabelNo = 100 '開始No
  endLabelStr = "catch:"

  '処理範囲
  btmR = Range("A" & Rows.Count).End(xlUp).Row
  'アクティブセルから最下行まで
  Set rgScope = ActiveSheet.Range("A" & ActiveCell.Row & ":" & "A" & btmR)
  rgScope.Select

  'endLabelStrが無ければ処理を中断する
  Set rg = rgScope.Find(what:=endLabelStr, LookIn:=xlValues, LookAt:=xlWhole, MatchCase:=True, MatchByte:=True)
  If rg Is Nothing Then
    MsgBox (endLabelStr & "が有りません。")
    Exit Sub
  End If
  
  labelNoTmp = startLabelNo
  For Each rg In rgScope
    '処理内容は必要に応じて変更してください
    Select Case True
      Case rg.Value Like "Sub*"
      Case rg.Value Like "Function*"
      Case IsNumeric(Mid(rg, 1, 3))
        rg = labelNoTmp & ":" & Mid(rg, 5)
      Case rg.Value Like "* _"
        rg = "    " & rg
      Case rg.Value Like "*Case*"
        rg = "    " & rg
      Case rg = endLabelStr
        Exit For
      Case Else
        rg = labelNoTmp & ":" & rg
    End Select
      
      labelNoTmp = labelNoTmp + 1
  Next
End Sub
```
【SSH】ssh-keygenでファイル名を指定して作成（などアレコレ）

## 概要
SSH鍵を生成する `ssh-keygen` コマンド
その際、ファイル名を指定してSSH鍵を生成する方法と、その他関連コマンド

## コマンド
生成されるファイルの出力先は、もちろん `~/.ssh/`

### 名前を指定して作成
`-f` オプションでファイル名（厳密には保存先）が決められる

```bash
ssh-keygen -f id_rsa_file_name
```

### 標準出力なしで作成
`-q` 標準出力を無効にする（キーマップが出ない）

```bash
ssh-keygen -q -f id_rsa_file_name
```

### コメントの指定
`-C` オプション
「`ユーザ名@ホスト名`（デフォルト）」以外にする場合に使用
別のメールアドレスとかを使用する（xxx@example.com）

```bash
ssh-keygen -C comment -f id_rsa_file_name
```

### 暗号化形式の指定
`-t` オプション
暗号化形式を「rsa（デフォルト）」以外にする場合、「dsa」「ecdsa」「ed25519」から指定

```bash
ssh-keygen -t ed25519 -f id_rsa_file_name
```

### fingerprint の指定
`-E` オプション
鍵のfingerprintを「sha256（デフォルト）」以外にする場合、「md5」指定

```bash
ssh-keygen -E md5 -f id_rsa_file_name
```

## エラー： SSH鍵の権限がオープン過ぎて怒られた場合
何かしら SSH 通信を利用したときに、以下の場合は、SSH キーの権限を変更する必要があります。

発生するエラー: Permissions 0644 for 'id_rsa_xxxxx' are too open.

```zsh
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for '/Users/xxxxx/.ssh/id_rsa_xxxxx' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "/Users/xxxxx/.ssh/id_rsa_xxxxx": bad permissions
git@github.com: Permission denied (publickey).
```
👉 `秘密鍵のパーミッションが "644" なので、他のユーザーからアクセスできるような権限では使えないよ ！`

### 権限を変更する
`chmod` コマンドで、書き込み・読み取り・実行権限を変更する（詳しい説明は割愛）

```zsh
# 対象のキーを指定（600 もしくは 400）
chmod 600 id_rsa_xxxxx
```

## おまけ

生成したSSH鍵の公開鍵をコピーするときは、以下でも可能

macOSの場合

```bash
pbcopy < ~/.ssh/ファイル名.pub
```

Windows で Git Bash など使っていた場合

```bash
clip < ~/.ssh/id_rsa.pub
```
findコマンドでファイル検索

## コピペ用

`/`：ルートディレクトリ
`~`：ホームディレクトリ

```terminal:検索
find / ファイル名 2>/dev/null
```

```terminal:ファイル検索
find ~ -type f -name ファイル名 2>/dev/null
```

```terminal:ディレクトリ検索
find ~ -type d -name ディレクトリ名 2>/dev/null
```

```terminal:例
$ find ~ -name sample.py 2>/dev/null
$ find ~/Desktop -type f -name "*開発キックオフ*" 2>/dev/null
```

:::note
`*`はワイルドカード。部分一致検索ができるので便利。
:::

:::note warn
**ルートディレクトリ**は、ファイルシステムのトップレベルに位置するディレクトリです。
上手くいかない場合は、権限があるかどうか確認してください。（例：`ls -lrt`）

わざわざルートディレクトリで検索する必要がない場合や、権限がない場合は、**ホームディレクトリ**での検索に変更したり、コマンドの先頭に`sudo`を付けて試してみるのも一つの手段です。

また、`Macのシステム環境設定>セキュリティとプライバシー>ファイルとフォルダ>iTermの設定`が有効であることもご確認ください。
:::


## `2>/dev/null`を付け足すことで余計な出力をなくしている

```terminal:Before
(base) sample@SampleMBP Selenium % find / -name "*自動*"
find: /usr/sbin/authserver: Permission denied
find: /Library/Application Support/Apple/ParentalControls/Users: Permission denied
find: /Library/Application Support/Apple/AssetCache/Data: Permission denied
find: /Library/Application Support/ApplePushService: Permission denied
find: /Library/Application Support/com.apple.TCC: Operation not permitted
find: /Library/Caches/com.google.SoftwareUpdate.0: Permission denied
find: /Library/Caches/com.apple.iconservices.store: Permission denied
find: /Library/Caches/com.apple.aned: Operation not permitted

省略
```

:::note warn
コマンドに`2>/dev/null`がない場合、Permission deniedなど欲しくない情報まで出力され、探すのが煩わしい
:::

---

```terminal:After
(base) sample@SampleMBP ~ % find / -name "*自動*" 2>/dev/null
/Users/username/Documents/Python/Webスクレイピング/JupyterLab/BeautifulSoup/全自動ランキングデータ抽出コード.ipynb
/Users/username/Documents/Python/Webスクレイピング/JupyterLab/BeautifulSoup/全自動画像取得&保存コード.ipynb
```

:::note
標準エラー出力を`/dev/null`という特別な場所に捨て去ってくれる
:::


## 参考

- [cronなどに記述する「2> /dev/null」の「2」ってなに？](https://www.itmedia.co.jp/help/tips/linux/l0388.html)
- [【Linux】/dev/nullをエンジニアが使う２つの目的](https://lanchesters.site/linux-dev-null/)
"Index name '~' on table '~' is too long; the limit is 64 characters"のエラーが出た際の対応法

はじめに
--
railsで実装の途中で新しくDBテーブルを作成した際に、下記の様にエラーが出て"rails db:migrate"が失敗してしまいました。
初めてのエラーだったので、原因と解決法を備忘録として残そうと思います。
~~~
~# bundle exec rails db:migrate
Running via Spring preloader in process 1026
== 20221005061523 ~: migrating =========================
-- create_table(:テーブル名)
   -> 0.1328s
== 20221005061523 ~: migrated (0.1333s) ================

== 20221005061746 ~: migrating ===================
-- create_table(:テーブル名)
   -> 0.0240s
== 20221005061746 ~: migrated (0.0241s) ==========

== 20221005062652 ~: migrating ==================
-- create_table(:テーブル名)
rake aborted!
StandardError: An error has occurred, all later migrations canceled:

"Index name '~' on table '~' is too long; the limit is 64 characters"
~~~

原因
--
原因は、エラー文読めばすぐわかりました。
index名が64文字の制限を超えちゃってるので修正してね、ということです。
~~~ruby
"Index name '~' on table '~' is too long; the limit is 64 characters"
#=> 翻訳 「テーブル '~' のインデックス名 '~' が長すぎます。制限は 64 文字です」
~~~

下記は例ですが、"very_so_very_long_string"というDBテーブルを作成し、"very_so_very_long_foreign_key"というDBテーブルと関連付けをするために"t.references"を用いて外部キーに設定しています。

~~~ruby
class CreateVerySoVerySoVeryLongString < ActiveRecord::Migration[6.1]
  def change
    create_table :very_so_very_so_very_long_string do |t|
      t.string :very_so_very_so_very_long_string_name
      t.references :very_so_very_so_very_long_foreign_key, null: false, foreign_key: true

      t.timestamps
    end
  end
end
~~~

ちなみにデフォルトのindex名は、"作成したDBテーブル名 on 関連付けするDBテーブル_id"の法則がある様なので、
今回の例だと下記になります。
76文字なのでエラーが発生してしまいますね。
~~~ruby
#デフォルトのindex名は、"作成したDBテーブル名 on 関連付けするDBテーブル_id"
#今回の場合 =>
"very_so_very_so_very_long_string_on_very_so_very_so_very_long_foreign_key_id"
~~~


解決法
--
そもそも長すぎるテーブル名も考えものかもしれませんが、無理やりテーブル名を短くしてわかりづらくなってしまったら本末転倒だと思います。
テーブル名は変更せずにこのエラーを回避するためには、"t.references"の箇所にindex名を設定するオプションを追加すれば問題なくrails db:migrateが成功します。

~~~ruby
#index: { name: '変更名' }を追加し、"change_short_string"に変更

class CreateVerySoVerySoVeryLongString < ActiveRecord::Migration[6.1]
  def change
    create_table :very_so_very_so_very_long_string do |t|
      t.string :very_so_very_so_very_long_string_name
      t.references :very_so_very_so_very_long_foreign_key, null: false, foreign_key: true, index: { name: 'change_short_string' }

      t.timestamps
    end
  end
end
~~~

参考
--
https://kemarii.com/blog/rails/index-name-too-long/
Mac Pythonバージョン切り替えができない、、、

- (注)自分のノートとして投稿しています。
- 解決まで色々いじってしまったので、再度試す時に同じ方法でできるか分かりません。

# 今回したこと
pythonのバージョンを3.8.12から3.10.4にアップデート

# 環境
- MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports)
OS : macOS 12.6
プロセッサ : 2 GHz クアッドコアIntel Core i5
メモリ : 32 GB 3733 MHz LPDDR4X
ストレージ : 1TB

# 参考にしたサイト
色々なサイトを確認してバージョンの切り替えを試みたが、
インストールはできるのに切り替えができない、、、

最終的には、このサイトが参考になりました！
[pyenvでpythonのバージョンが切り替わらない時にやったこと](https://it-syoya-engineer.com/pyenv-version-change-erorr/)


# 思ったこと
PATHの確認大事！
`echo $PATH`
↓ターミナルで実行してみて、、、
.pyenvを通過しているか確認したところ、通っていませんでした！

ターミナルで以下を実行すると、パスが通ってる！！！
`eval "$(pyenv init --path)"`


↓バージョンを確認をすると、しっかり切り替えができました！
`python -V`

# 参考にサイト
- [pyenvでpythonのバージョンが切り替わらない時にやったこと](https://it-syoya-engineer.com/pyenv-version-change-erorr/)
- [pyenvのパスが通らない](https://qiita.com/ms903-github/items/fbf53a42ad07aa7424e1)

この他にも解決するまで様々なサイトを参考にさせて頂きました。
Power BI で複数のテーブルのデータを分析する

ACCESS やリレーショナル データベースをかじったことのある人なら「リレーション」についてなんとなくでもご存じかと思いますが、そうでなければ？？？という感じだと思います。
Power BI はデータ ウェアハウスについての考え方、スタースキーマなどを知っていると高度に活用できるのですが、「まず今 Excel で苦労しているのを効率化したい！」という方にそこから勉強しろというのはちょっと酷かな、とも思います。とりあえず Power Query の「クエリのマージ」のやり方を知っていただくと、データをつなげることを手っ取り早く始めることができます。

# クエリのマージ
「クエリのマージ」は2つのテーブルを、キーとなる列 (共通であることを特定できる列) を使って1つのテーブルにすることを言います。Excel だと VLOOKUP なんかを使う操作です。
例：社員テーブルと部門テーブルは「部門ID」がキーとなります。
社員テーブル
| 社員番号 | 社員名 | 部門コード |
|--:|:-:|--:|
|1|赤井| 101 |
|2|青木| 101 |
|3|黒田| 201 |

部門テーブル
| 部門コード | 部門名 |
|--:|:-:|
|101|営業|
|201|人事|
|301|総務|

Power Query エディターで、社員テーブルのクエリで「クエリのマージ」を実行すると、このような画面が出てきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668909/14db893d-7f01-8cf3-ff16-c9102da8f294.png)

「部門コード」列がキーになるので、それぞれのテーブルで部門コードをクリックして選択しています。

::: note
この例ではシンプルに、キー列が1つの場合で説明していますが、**複数の列でキーとすることも可能です。**
その場合は、クリックした順に列名に数字が付くので、同じデータの列同士が同じ数字になるようにクリックします。
:::

「OK」ボタンを押すとこうなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668909/5bef574b-b975-18f6-f7be-8824da7efa02.png)

「社員テーブル」に「部門テーブル」という名前の列が追加されています。この「部門テーブル」という列名の右側の矢印のアイコン「↰↱」をクリックすると、部門テーブル内のどの列を追加するかを選択できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668909/78b1408d-5b6b-9173-45a0-e2f5bdc240ce.png)
「部門コード」は重複するのでチェックを外しています。また、[元の列名をプレフィックスとして使用します]のチェックも外しています。(チェックを入れておくと列を追加するときに「テーブル名.列名」の形式の列名が付きます。)
この状態で[OK]をクリックすると、下図のように社員テーブルに「部門名」が追加されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668909/df0ad066-c9f3-59e3-242e-57ec517f2565.png)

:::note warn
どちらかのテーブルのキー列はユニーク (一意：重複がない) であることが望ましいです。この例の場合、部門テーブル側にも部門コードの重複があると、その部門コードのデータが複数行作られてしまいます。
:::

社員テーブルに部門テーブルのデータを入れたので、部門テーブルは不要になりますが、削除してしまうと社員テーブルがエラーになってしまいます。そこでクエリの「部門テーブル」を右クリックし、[読み込みを有効にする]の左側のチェック ☑ を外します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668909/1d1d2eee-c792-7418-97a4-1a35935af8c3.png)
こうすることで、不要になった部門テーブルがレポート作成画面に表示されなくなり、更新時にデータのインポートも行われません。(社員テーブルには読み込まれるのでご安心ください。)

「クエリのマージ」については @yugoes1021 さんの [こちらのQiita](https://qiita.com/yugoes1021/items/6026532cb7ccdc11276d) に詳しく載っていますので、ここでは割愛します。
また、弊社メンバーの[こちらのブログ記事](https://marshal115.hatenablog.com/entry/2021/04/07/163531)では Excel の Power Query を使って、よりディープに解説しているので、本記事に物足りなさを感じる方はこちらもぜひご覧ください。

:::note
「クエリのマージ」のすぐ下にある「クエリの追加」は、同じ形の複数のテーブルのデータを足しこむ操作です。同じフォーマットの複数のテーブルを1つにまとめるような場合に使用します。SQL でいうところの UNION です。
:::

データ量が多くなるとクエリのマージはパフォーマンスに響くこともありますが、Excel 手作業から脱却するような場合においては有用です。Power Query エディターは、データベースやSQLになじみのない方、Excel 関数で頑張っている方にもとっつきやすい部分なので、ぜひ活用してみてください。
USDのWindows環境でのインストール

はまったのでログを残す。

https://github.com/PixarAnimationStudios/USD

```ERROR: 'cp932' codec can't decode byte 0xef in position 104: illegal multibyte sequence```

関連しそうなissue

https://github.com/PixarAnimationStudios/USD/issues/1806

時刻と言語＞言語と地域＞管理用の言語の設定＞システムロケールの変更＞ベータ：ワールドワイド言語サポートでUTF-8を使用

サンプルの

```python USD\build_scripts\build_usd.py "C:\Program Files\USD"```

のままだとうまくいかなかったので、インストール先に空白文字の無いパスを指定して解決。
【Git】error: remote origin already exists.エラーが出た時の対処法


タイトルのようなエラーが出た時の対処法です。

## 対処法

originを削除し、新たにoriginを登録し直します。

```
$ git remote rm origin
```

ちなみにリモートリポジトリ名をrenameしている場合は、以下のようにすれば良いです。

```
$ git remote rm <リモートリポジトリ名>
```

## 参考

https://docs.github.com/ja/get-started/getting-started-with-git/managing-remote-repositories
docker-composeで起動したpostgresqlの初回起動時スクリプト実行とDB永続化の方法

# docker-compose.yml
```yml
version: '3.1'

services:
  db:
    image: postgres
    restart: always
    ports:
      - 5432:5432
    volumes:
      - ./postgres/init:/docker-entrypoint-initdb.d #初回起動時用
      - ./postgres/data:/var/lib/postgresql/data #永続化用
    environment:
      POSTGRES_PASSWORD: #パスワード
      POSTGRES_DB: #DB名
```

`volumes`でマウントする。
`:`の左側がローカルマシン内のディレクトリ、右側がDockerコンテナ上でのディレクトリ。

## 初回起動時スクリプト`./postgres/init:/docker-entrypoint-initdb.d`
Dockerコンテナ上のpostgresqlの起動時にdataディレクトリ(`/var/lib/postgresql/data`)が空だった場合、`/docker-entrypoint-initdb.d`配下のファイル(*.sql, *.shなど)が実行される。

参考：https://hub.docker.com/_/postgres
> If you would like to do additional initialization in an image derived from this one, add one or more *.sql, *.sql.gz, or *.sh scripts under /docker-entrypoint-initdb.d (creating the directory if necessary). After the entrypoint calls initdb to create the default postgres user and database, it will run any *.sql files, run any executable *.sh scripts, and source any non-executable *.sh scripts found in that directory to do further initialization before starting the service.

> Warning: scripts in /docker-entrypoint-initdb.d are only run if you start the container with a data directory that is empty; any pre-existing database will be left untouched on container startup. One common problem is that if one of your /docker-entrypoint-initdb.d scripts fails (which will cause the entrypoint script to exit) and your orchestrator restarts the container with the already initialized data directory, it will not continue on with your scripts.

## 永続化`./postgres/data:/var/lib/postgresql/data`
Dockerコンテナ上の`/var/lib/postgresql/data`をローカルマシンでマウントしておくことで、万一コンテナ上のDBが吹き飛んでもローカルに生き残るので復旧できる。
csv文字化け 解決した件

# 調査のスタート
現在触っているシステムでrailsのサーバーからcsv作成する時、データー量が少ない時には
```
csv = "column1,column2\ndata1,data2\n..."
send_data csv, filename: 'result.csv', type: :csv
```
こんな感じでsend_dataでstringをすぐ送っているものにしました。
今まで特に問題ないと思いましたがEXCELでは文字化けが発生している連絡が来ました。
自分はexcel使っていないし自分が使っているエディタでは問題無かったので全然気づいていない状態でした。
エンコーディング確認するとちゃんとutf-8だったのでexcelでデーターインポートでファイル開けると問題ないことまで確認しました。

# もしかしてMIMEが問題だったか？
上に話した通りデーターが少ない時だけstringをsend_dataしていることでデーターが多い場合サーバーでcsvファイルを作って配信するパタンがあります。
ファイル作成しているパタンでは同じデーター書いている時にも文字化けが発生していないことが確認してもしかしてファイルが同じ状態ではないかとしてターミナルに
```
$ file -I result.csv
result.csv: text/plain; charset=utf-8

$ file -I big_result.csv #EXCELにも文字化け発生しないファイル
big_result.csv: text/csv; charset=utf-8
```

MIMEが違いました。もしEXCELだけ厳しいか？とかなぜtype: :csvしたのにtext/plainになっているか考えながら確認するとcsvというMIMEが存在しないこと確認しました。

https://developer.mozilla.org/ja/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types

text/csvでした。

railsのsend_dataもただcontent_typeに入れるだけだったので

https://github.com/rails/rails/blob/984c3ef2775781d47efa9f541ce570daa2434a80/actionpack/lib/action_controller/metal/data_streaming.rb#L109

```
send_data csv, filename: 'result.csv', type: 'text/csv'
```

それにするとダウンロードしたファイルも

```
$ file -I result.csv
result.csv: text/csv; charset=utf-8
```

type変更したので終わりだと思いましたがまだEXCELで文字化けが…

# BOM
もしかして特定の文字列が問題か？と思ってテキストエディタで問題あるファイルとないファイルを文言コピペしならが確認すると問題あるファイルのヘッダーを問題ないファイルの頭に貼りると問題無かったファイルも文字化けが発生したこと発見
問題が発生した後ではコピペした文言を削除しても文字化け発生する状態そのまま！

自分の作業がターミナルがメインだったので気づくことが遅かったんですがBOM有無の問題でした。

https://ja.wikipedia.org/wiki/%E3%83%90%E3%82%A4%E3%83%88%E9%A0%86%E3%83%9E%E3%83%BC%E3%82%AF

ファイルを作って配信する時にはBOMが存在しstringだけでは存在しなかっただけでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1683881/29dd12c4-7228-18bb-7ede-cd332012624e.png)
エディタでは文字列として見えないですが右のファイルはutf-8だと判断できる0xEF 0xBB 0xBFがちゃんと履いていることだけでした。見えないけどテキストエディタで修正するとBOMも削除されたので気づいた。
エディタによった保存する時確認したり開ける時に確認することがあることもあるけどEXCELが少し厳しかった、、、

# 解決
毎回ファイルの作ることは嫌だったので
```
def send_csv(csv_text, options = {})
    bom = "   "
    bom.setbyte(0, 0xEF)
    bom.setbyte(1, 0xBB)
    bom.setbyte(2, 0xBF)
    send_data bom + csv_text, options.merge(type: 'text/csv')
  end
```

BOMを勝手に追加するメソッドでcsvダウンロードすることにしました。

終わり
is only available in iOS 16.0 or newerの対応

# 環境
- Xcode 14.0.1 
- iOS16
- macOS Monterey 12.6

# iOS16の機能を利用しようとした時エラー
Textを太字にしたい
Fix候補は３つ
![スクリーンショット 2022-10-05 23.10.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/618527/f42e3569-6732-a718-1b31-1e6dde7a715d.png)

Fixはどれも選択せず
ググって上位表示記事を参考にした
["*** is only available in iOS 15.0 or newer"](https://developer.apple.com/forums/thread/681782)

# プロジェクトとターゲット両方を16.0に変更した
![スクリーンショット 2022-10-05 23.14.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/618527/158161c5-3934-d555-83d1-d7cc24116fd2.png)

![スクリーンショット 2022-10-05 23.19.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/618527/b481612b-9dec-4dfc-8f6d-5db8fc15eb8e.png)

![スクリーンショット 2022-10-05 23.16.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/618527/8c783ec8-65bd-4d3a-a6c4-28717b2c75b3.png)

![スクリーンショット 2022-10-05 23.43.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/618527/a3b63dea-7a2d-0bc9-3110-a6638f38a5ba.png)

TARGET>General>Minimum Target これは16.0じゃないとエラーでるが、

PROJECT>info>iOS Development Target これは16.0以下のままでもビルドできる

なにが違うんだろ。
Minimum Targetは最小Ver指定だからiOS 16.0未満は対象外ってことかな。

<b> Deployment Targetはプロジェクトとターゲットの両方に値を指定する

参考：[iOSのDeployment Targetはプロジェクトとターゲット両方に値を指定しないといけない](https://bamboo-hero.com/entry/ios-deployment-target)

まだ理解できないので今後の忘備録とします。
全シート検索して集計シートに集まる

大量のメールの中で重要なメールをエクセルの
シートに貼りつけて保存して、キーワードで
関連情報を抜き出す時に使ってました。

あるDir下の全ワード、エクセル、他ファイル
を全てオープンして、キーワードにヒットした
前後10行を一覧表示するのを作ってましたが
やり方忘れてしまいました(^^;;

vbaで試してないので、本当に適当なメモ書き
です、あとで一度整理して完成品をあげたいです

option explicit

dim sh as worksheet
dim i , j as long
dim keycode as string

keycode = "hoge"

for each sh in worksheets
  if sh.name <> "集計" then

     for i = 1 to 100
         for j = 1 to 100
            if instr(sh.range(i,j).value,keycode )  <> 0 then

               worksheets("集計").range(current,5) = sh.range(i,j).value

同上で、.font.size = 14
同上で、.interior.color= rgb(255,0,0)
                .colorindex = 20

前後5行を設定する


          current += 10
         next j
      next i
  endif
next
[Firebase] Functionsで本番・開発・Emulator環境を判別する

## はじめに
環境ごとに処理を変えたいんだけどFunctionsでどうやって判別できるの？
調べても直接的な回答記事が見つからなかったが、`process.env`に用意されてるんじゃないかと調べてみたら使えそうなものを見つけた。

## エミュレータであるかを判別する方法
```ts
process.env["FUNCTIONS_EMULATOR"] //  "true" or "false で返ってくる
```
予約済みの環境変数として最初から設定されているもよう。

## 本番環境 / デバッグ環境を判別する方法
```ts
process.env["FIREBASE_DEBUG_MODE"] //  "true" or "false で返ってくる
```
こちらも予約済みの環境変数として最初から設定されているもよう。

尚、設定によってはFIREBASE_DEBUG_MODEで判別できない場合もあるらしく、その場合はprojectIdで判別する必要がありそうです。
```ts
process.env["GCLOUD_PROJECT"] === "projectId";
```

https://firebase.google.com/docs/functions/config-env?hl=ja#reserved-names

## Sample: 本番・開発・Emulator環境を判別する
```ts
const isEmulator = process.env["FUNCTIONS_EMULATOR"] === "true";
const isDebug = process.env["FIREBASE_DEBUG_MODE"] === "true";

const environment = () => {
  switch (true) {
      case !isDebug:{
          return "本番環境";
      }
      case isEmulator: {
          return "Emulator";
      }  
      default: {
          return "開発環境";
      }  
  }
}

console.log(environment());
```


## 最後に
もっといい方法あれば教えてほしいですー！
Cookieの仕組みを理解する

# Cookieとは
簡単に言うとWebサーバとクライアント間でユーザーの状態などを維持・管理するための仕組みである

# Cookieの仕組みとは

- webサーバーへ接続してきたwebブラウザに対して、コンテンツ等と一緒にwebブラウザに保存してもらいたい情報をCookieとして送信する。*※接続してきたwebブラウザを識別する情報など*
- Cookieを受け取ったwebブラウザはそれを保存しておき、次にwebサーバへ接続する際に保存しておいたCookieを送信することで、webサーバー側で接続してきた相手を識別する事ができる。
- サーバ側で相手を識別することができるため、webブラウザからのリクエストに該当の識別情報が存在した場合は、
　ログイン情報を入力する必要はなくし、ネットショッピング等でページから離脱しても買い物カートの中の
　商品がそのままの状態で再開ができるようにすることができる。
- webサーバーはHTTPレスポンスに「set-cookie」ヘッダーを含めることでCookieを送信できる。
    - set-cookieヘッダーフィールドに記述する属性
        - name=value
            - Cookieにつける名前とその値(必須)
        - expires=date
            - Cookieの有効期限。この属性がない場合はwebブラウザを閉じるとCookieは削除される。
            - 有効期限が設定されておらず、webブラウザが閉じると削除されるCookieを「セッションCookie」と呼ぶ
        - max-age=seconds
            - Cookieの残存時間を秒数で指定
        - secure
            - HTTPSで通信している場合にのみCookieを送信
        - httponly
            - JavaScriptからのCookieへの参照制限
        - domain=DOMAIN_NAME
            - Cookieが利用されるドメイン名
        - path=PATH
            - Cookieが利用されるサーバー上のパス
```
サーバからのレスポンスヘッダー例
set-cookie: name=value; expires=date;domain=DOMAIN_NAME
```
- webブラウザでCookieを受け取った後は、CookieをHTTPリクエストのメッセージヘッダーに含めて送信できる。
    - HTTPリクエストに「Cookie」ヘッダーを含める事で送信できる
```
クライアントからのリクエストヘッダー例
Cookie: name=value
```
visudoをスクリプトで実行する

### 前置き

手順書を書いていて**visudoを実行後に手入力**してください。と書くのが格好悪い...
（sudoが要らないように作るのが基本だろうというのは重々承知しています）

他にも設定で手入力が必要なパターンがあるはずなので
何らかの解決方法があるという一例としてご覧いただければ幸いです。

##### 修正前

```bash
$ sudo visudo
エディタが起動するので
foobar ALL=(ALL:ALL) ALL
を追記する
```

##### 修正後

```bash
$ echo 'foobar ALL=(ALL:ALL) ALL' | sudo EDITOR='tee -a' visudo
```

##### 代替案

もちろん下記のように、直接 /etc/sudoers に追記するのでも良いのでしょうけど。
'>>' を '>' と打ち間違えると取り返しがつきませんので...

```
$ sudo bash -c "echo 'foobar ALL=(ALL:ALL) ALL' >> /etc/sudoers"
```




##### 参考

https://stackoverflow.com/questions/323957/how-do-i-edit-etc-sudoers-from-a-script
Raspberry PiでGStreamerを使用したRTSPサーバー

# 1. 概要
Raspberry Pi上でGStreamerを使用したRTSPサーバーを用意し、MJPEGをRTSP配信する。
MJPEGしか出せないUVCカメラでRTSP配信を試そうとしたところVLC Playerで再生できずに困っていると知人に言われ、調べてみた結果をまとめた。

# 2. 使用機器
* Raspberry Pi 3B
* OSはBuster(Debian 10)
* UVCカメラ: Buffalo BSW500M
* 再生アプリケーション: VLC Player

# 3. 準備
Gstreamerには、gst-rtsp-serverというRTSPサーバーアプリがあるのでそれを利用する。
Gstreamerのインストールは別の記事でまとめたので割愛する。

インストール済みGStreamerのバージョンを調べる。1.14.4だった。
```
$ gst-launch-1.0 --version
  gst-launch-1.0 version 1.14.4
  GStreamer 1.14.4
  http://packages.qa.debian.org/gstreamer1.0
```

autogen.shの実行で「You need gtk-doc to build this package」が出てエラーとなったので、「gtk-doc-tools」がインストールされていなければ予めインストールしておく方が良い。あとからでも問題はない。
```
$ sudo apt-get install gtk-doc-tools
```

gst-rtsp-serverをクローンする。バージョンごとにブランチが切られているので、取得したGStreamerのバージョンのブランチをチェックアウトする。
```
$ git clone git://anongit.freedesktop.org/gstreamer/gst-rtsp-server
$ cd gst-rtsp-server
$ git checkout 1.14.4
$ ./autogen.sh
$ make
$ sudo make install
```
# 4. 試す

gst-rtsp-server内のテストアプリのあるディレクトリに移動
```
$ cd examples/
```

カラーバーをH.264でRTSP出力
```
./test-launch '( videotestsrc ! x264enc ! rtph264pay name=pay0 pt=96 )'
```

VLC Playerのネットワークストリームを開くを選択、「rtsp://192.168.1.128:8554/test」と入力して、再生をクリックする。尚、「192.168.1.128」はRaspberry Pi 3BのIPアドレス。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865486/0349a18d-9469-7e4b-245c-8acc730f8400.png)

カラーバーが再生される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865486/7b1eb8dd-1d5d-f4ae-6a9f-d0ca4bddff7e.png)

## 4.1. YUVをH.264にソフトウェアエンコード
YUVをH.264に変換(ソフトウェアエンコード)してRTSPで配信した。
VLC Playerで再生できたが遅延は大きい。
```
./test-launch '( v4l2src device=/dev/video0 ! video/x-raw,width=640,height=480,framerate=30/1 ! videoconvert ! x264enc ! rtph264pay name=pay0 pt=96 )'
```
ただ、「x264 [error]: baseline profile doesn't support 4:2:2」とエラーが出ていた。

## 4.2. YUVをH.264にハードウェアエンコード
YUVをH.264に変換(ハードウェアエンコード)してRTSPで配信した。
VLC Playerで再生できた。遅延は少しマシになった。
```
./test-launch '( v4l2src device=/dev/video0 ! video/x-raw,width=640,height=480,framerate=30/1 ! videoconvert ! omxh264enc ! video/x-h264,profile=baseline ! h264parse ! rtph264pay name=pay0 pt=96 )'
```

## 4.3. MJPEGをH.264にハードウェアエンコード
MJPEGをH.264に変換(ハードウェアエンコード)してRTSPで配信した。
VLC Playerで再生できた。遅延はハードウェアエンコードのYUV->H.264と同じくらいか？

```
./test-launch '( v4l2src device=/dev/video0 ! image/jpeg,width=640,height=480,framerate=30/1 ! omxmjpegdec ! omxh264enc control-rate=1 target-bitrate=5120000 periodicty-idr=10 inline-header=FALSE ! h264parse config-interval=-1 ! video/x-h264,stream-format=byte-stream,alignment=au,profile=baseline ! rtph264pay name=pay0 pt=96 )'
```

# 5. まとめ
MJPEGのソースでもH.264にしてRTSP配信できます。
パラメータの組み合わせなどについて話題に上がったら調べて追記するつもり。

以上
AWSのアーキテクチャ図を書く

AWS上でサービスを構築初めて、大体終わってきたのでアーキテクチャ図を描きたくなりまとめてみました。
ほんとは実装する前にやるべきかなと思うのですが、今回は練習ということで書いてみました。

## ・前提
*　特になし。


## ・まず初めに
以下のリンクを読みます。こちらには書く前の心構えのようなものが書いてあります。

https://aws.amazon.com/jp/builders-flash/202204/way-to-draw-architecture/?awsf.filter-name=*all

## ・AWSサービスの位置関係を把握する。
自分が使っているサービスが
エッジロケーションで利用しているののか。
リージョンの内なのか外なのか。
AZの内なのか外なのか。

自分の場合は以下になるかなと

```
エッジロケーションで利用しているのか:Route 53, Cloud Front 
リージョンの内でAZの外:S3, Internet Gateway, NLB
AZの内:ECS
```


## ・どのツールで書くか
上記リンクないにPowerPointやSkwtchのツールキットが用意されてるので素直にそれを使うのが良いと思います。
自分はPowerPointを利用しています。
ちなみにテンプレファイルはページ数が多すぎて、自分の使いたいアイコンをコピペして使おうとすると大変なので、今後もアーキテクチャ図を書こうと思うのであれば、自分用にどこかによく使うアイコンをまとめとくと今後が楽そうです。

## ・あとは書いてみる
上記リンクでも記載されているように、アーキテクチャ図に正解はないです。
強いて言えば、伝えたいことが伝えられる図であればそれは正解だと思います。
「システムがでかいこと」「超絶シンプルなシステムであること」「A,B,Cが実はシステム連携していること」
など、そのアーキテクチャ図で何を伝えたいか、そしてそれが伝わるかが大事になります。

## ・自分の初作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2092476/552f8821-3dd6-1d1d-5622-cd04e7ecf6d9.png)

今見てみただけでも反省点はありますね。
・アイコンサイズのバランスが不自然(特に意図してあれが大きい、小さいではないです。)
・ECSとコンテナの書き方があっているか不明確
・AutoScaling groupでくくるのはコンテナだけでいいのか。(この辺はあとで調べようと思います。)

## ・最後に
なんとなくシステムとしては動いているけど、自分が理解しきれていない点が洗い出されたり実際軽くでもやってみてそれが見えただけでもよかったです。
なかなか書く機会ってない気がしますが、他のアーキ図とかみながらうまい見せ方を吸収していこうと思います。
C#用ライブラリの「Csv」を使ってみる

# はじめに
本記事はC#用ライブラリの「Csv」を使い方をサンプルを交えて述べる記事です。

# Csvとは
C#でCSVファイルを読み書きするためのライブラリです。かなり簡単に使えることが特徴です。
詳細は[こちら](https://github.com/stevehansen/csv/)を参照ください。

# CSVを使ってみる
「Csv」を使うサンプルとして、以下のようなCSVデータ(ウェブページの閲覧ログのイメージ)において、ページごとのユニークユーザー数を算出してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452292/43dfbfbf-e587-b14e-1643-160dd75d9789.png)
ユニークユーザー数とは重複を取り除いたユーザー数のことなので、例えば上記の製品紹介ページの場合は、ユニークユーザー数は2となります。(製品紹介ページのレコードは計5件ですが、内4件は同じユーザーID:5のユーザーなので、ユニークユーザー数としては2になります。)
では作り方を見ていきます。まずは「Csv」のインストールが必要です。VisualStudioでプロジェクトを作成し、プロジェクトを右クリックし、コンテキストメニューから「Nugetパッケージの管理」をクリックします。その後、「Csv」というNugetパッケージをインストールします。これでインストールは完了です。
![Csvパッケージインストールイメージ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452292/5ac9fdd1-ef7d-d7f1-c659-bd8ccaf009b0.png)
次にコードを書いていきます。実際のコードは以下です。
```csharp
using Csv;

// CSVファイルを文字列で取得
var csvText = File.ReadAllText("CSVファイルのパス");

// ページごとのユニークユーザーID一覧
var uniqueUserIdsPerPage = new Dictionary<string, HashSet<string>>();

// CSVファイルの各行ごとに処理をする
foreach (var line in CsvReader.ReadFromText(csvText))
{
    // [ページ名]列の値を取得
    var pageName = line["ページ名"];
    // [ユーザーID]列の値を取得
    var userId = line["ユーザーID"];
    
    if (!uniqueUserIdsPerPage.ContainsKey(pageName))
    {
        // 該当のページに対応するユーザーIDが一件も追加されていない場合はユーザーIDリストを初期化
        uniqueUserIdsPerPage.Add(pageName, new HashSet<string>() { userId });
    }
    else
    {
        // 該当のページに対応するユーザーIDを追加
        // HashSetへの追加なので重複追加はされない
        uniqueUserIdsPerPage[pageName].Add(userId);
    }
}

// ページごとのユニークユーザー数を出力
foreach (var (pageName, users) in uniqueUserIdsPerPage)
{
    Console.WriteLine($"{pageName}:{users.Count}");
}
```
コードの説明をしていきます。
CSVファイルの内容を文字列で取り出し、以下のforeach文でCSVの各行ごとに反復処理をします。
```csharp
// CSVファイルの各行ごとに処理をする
foreach (var line in CsvReader.ReadFromText(csvText))
{
    // 各行ごとにこの処理を実施
}
```
foreach内部ではまず、行ごとの[ページ名]列と[ユーザーID]列の値を取得します。
上記のコード内の変数`line`は「Csv」で提供するインターフェースを実装しているため、以下のように列名を使ってインデクサアクセスをすることで、その列名に対応する列の値が取得できます。
```csharp
// [ページ名]列の値を取得
var pageName = line["ページ名"];
// [ユーザーID]列の値を取得
var userId = line["ユーザーID"];
```
次に、取得したページ名ごとにユーザーIDの値をHashSetに詰めていきます。HashSetへの登録なので、重複したユーザーIDは登録されず、この方法でデータを登録していくことで、ページごとのユニークユーザーのIDリストが作成できます。
```csharp
if (!uniqueUserIdsPerPage.ContainsKey(pageName))
{
    // 該当のページに対応するユーザーIDが一件も追加されていない場合はユーザーIDリストを初期化
    uniqueUserIdsPerPage.Add(pageName, new HashSet<string>() { userId });
}
else
{
    // 該当のページに対応するユーザーIDを追加
    // HashSetへの追加なので重複追加はされない
    uniqueUserIdsPerPage[pageName].Add(userId);
}
```
foreachを抜けたのちに、登録した情報を使ってページ数ごとのユニークユーザーを出力します。
```csharp
// ページごとのユニークユーザー数を出力
foreach (var (pageName, users) in uniqueUserIdsPerPage)
{
    Console.WriteLine($"{pageName}:{users.Count}");
}
```
出力結果は以下のようになります。
![実行結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452292/8926a6a8-a3d7-bb33-1c8e-bdc11e60a649.png)
使ってみて感じた「Csv」の良さは、とにかく手軽に使えることだと思います。Csvのテキストから各行ごとの反復処理がすぐに書けますし、列名を指定して値を取得できるのもかなり便利だと思いました。手軽にCsvを操作したいときに役立つライブラリだと思いました。

# まとめ
本記事では、C#用ライブラリの「Csv」を使い方をサンプルを交えて述べました。
とにかく手軽に使えることが「Csv」の良さだと感じたので、サクッとCSVをC#で操作したいときには使ってみることをお勧めします。
スプレッドシートをWEBページに埋め込んだ際の挙動調査

## はじめに
業務外でWEBページに埋め込む形で使用しているスプレッドシートのカスタマイズについて相談され、
そもそも自身で埋め込んで使用したことが無かったため、
手始めに埋め込んだ際の挙動を調査したものを記事にしました。

## WEBページに埋め込む手順

スプレッドシート上部のタブ
「ファイル」＞「共有」＞「ウェブに公開」
を選択します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247154/ea6fc978-eb9d-a043-fd2b-1f8d3371b252.png" width="500" />

「埋め込む」タブを選択し、「公開」ボタンをクリックするとスプレッドシートが公開され、埋め込み用のタグが表示されます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247154/fba9f83b-fa2c-770f-54f9-08ad794ecc86.png" width="500" />

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247154/c89bf239-85f8-8a76-cc1e-847de2389215.png" width="500" />

埋め込み用のタグをWEBページに記載することで、スプレッドシートの内容を表示することができます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247154/2eecb3fa-4e5a-38ae-5914-ad11e86a00d7.png" width="500" />

## 公開時の詳細設定
### 公開するコンテンツの設定

埋め込みリンクを生成する際、ドキュメント内のシート全体を公開するか、特定のシートだけを公開するかを選択することができます。
特定のシートだけを公開する場合は、どれか一つのシートしか選べないようです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247154/ad1d4ea7-48ab-65d9-231c-a98e9bdc1582.png" width="500" />

### 埋め込みURLに設定できるパラメタ
埋め込み用のURLに対し、以下のパラメタを設定することができます。

| パラメタ | 内容 | 指定する値 | 
|:-:|:-:|:-:|
| gid | 初期表示したいシートのID  | 0 もしくは9桁のシートID 
| range  | 埋め込み時に表示する行と列の範囲 |  A1:B14 など
| widget | シートタブを下部に表示するかどうか  | true もしくは false
| headers | 行番号と列文字を表示するかどうか  | true もしくは false
| chrome | タイトルとフッターを表示するかどうか  | true もしくは false

- gid
    - 初期表示するシートを指定したい場合、このパラメタを設定します。
    - 一番左のシートの gid は 0 です。
    - それ以外のシートの gid は、それぞれのシート毎に設定された9桁の数字です。
        - gid はスプレッドシートで該当シートを表示した際のURLから確認できます。

- range
    - 公開時に表示する行と列の範囲を指定したい場合に、このパラメタを設定します。
    - 閲覧者はこのパラメタを除去してアクセスすることも可能なので、見られてはいけない情報が範囲外のセルにある場合見られてしまう可能性があるので注意しましょう。

- widget
    - シートタブを下部に表示するかどうかを設定できます。
    - 表示しない場合、代わりに以下の画像のようなフッターが表示されます。

    <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247154/fa6ad467-9da6-f9bf-b588-39b550e477d2.png" width="500" />


- headers
    - 行番号と列文字を表示するかどうかを設定できます。

- chrome
    - タイトルとフッターを表示するかどうかを設定できます


## その他の細かな挙動

### 自動更新

- 公開されたスプレッドシートは数分ごとに自動的に表示内容が更新されます。
- widget パラメタを true にしている場合に自動更新が行われる旨がフッターに表示されますが、false の場合でも自動更新は行われます。
- シート内で `Now()` 等の現在時刻を取得して表示内容を変える処理を記載している場合も、正しく動作します。

### 行と列の非表示
- 公開したシート内で行もしくは列を非表示にした場合、WEBページに埋め込まれたシートからも表示されなくなります。

### 他のシート・スプレッドシートからの参照
- 公開していない別のシートのセルから値を参照して表示することが可能です。
- また、公開していない別のスプレッドシートから `IMPORTRANGE` 等で値を参照する場合も正しく動作します。

### スタイルの調整
- 公開したスプレッドシートは、デフォルトだと縦横幅が短い状態で表示されます。
- 埋め込みタグの中に style タグを追加することで調整することができます。

### アクセス権限が設定されたスプレッドシートを公開した場合
- アクセス権限のあるGoogleアカウントでログインしている場合は閲覧することができます。
- そうでない場合、以下の画像のような表示となり閲覧することはできません。
   <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247154/c974af89-8c9e-6bfb-3e9c-5910483c8449.png" width="500" />
【PHPUnit】PHPUnit実行時、filter_input()からの戻り値がNullになるので組み込み関数でもMockを作ってテストする。

## な、なんだってー！？
PHP-CLIのSAPIだとfilter_input()を実行しても値がnullになりテストができない・・・

```php
$_GET['key'] = 'value'
var_dump($_GET['key']);
// string(5) "value"

var_dump(filter_input(INPUT_GET, 'key'));
// null
```

というわけで組み込み関数でもMockを作ってテストしてみます。
この方法は他の組み込み関数でも使えるはずなので、ぜひ使ってみてください。



サンプルのコードはこんな感じ。


```php:TargetService.php
<?php

namespace App\Service;

class TargetService
{
    public function __construct(){}

    /**
     * URLパラメータにkeyがあり値がvalueであることを
     * 確認するメソッド
     * @return bool
     */
    public function targetMethod()
    {
        return filter_input(INPUT_GET, 'key') === 'value';
    }
}
```


```php:TargetServiceTest.php
<?php

namespace App\Service;

require_once 'PHPUnit\Framework\TestCase.php';

class TargetServiceTest extends \PHPUnit_Framework_TestCase
{
 
    /**
     * Create test subject before test
     */
    protected function setUp()
    {
        parent::setUp();
        $this->target = new App\Service\TargetService();
    }

    /*
     * Test cases
     */
    public function testTargetMethod()
    {
        $this->assertTrue($this->target->targetMethod());
    }
}
```

このような場合に上記のようにtargetMethod()をテストしようと思いPHPUnitで単体テストを作成してもPHPUnitはSAPIがPHP-CLIのためfilter_input()を実行しても値がnullになりAssertが通リません。

そうした時はこのように単体テストを書くと組み込み関数のfilter_input()をオーバーライドできます。

```php:TargetControllerTest.php
<?php

namespace App\Service;

require_once 'PHPUnit\Framework\TestCase.php';

/**
 * filter_input()をオーバーライド
 */
function filter_input()
{
    return 'value';
}
 
class TargetServiceTest extends \PHPUnit_Framework_TestCase
{
 
    /**
     * Create test subject before test
     */
    protected function setUp()
    {
        parent::setUp();
        $this->target = new App\Service\TargetService();
    }

    /*
     * Test cases
     */
    public function testTargetMethod()
    {
        $this->assertTrue($this->target->targetMethod());
    }
}
```

ポイントは必ず組み込み関数と同じ名前を関数に名付けることです！

参考文献
[PHP: “Mocking” built-in functions like time() in Unit Tests](https://www.schmengler-se.de/en/2011/03/php-mocking-built-in-functions-like-time-in-unit-tests/)
マネジメントに必要とされる力

ソフトウェアに限らず、仕事でプロジェクトをマネジメントする際、私の経験上必要だと感じた力を３つ紹介します。

# 想像力
　プロジェクトマネジメントの本質は、「未知のリスク」に対応しつつ、「限られた時間内」に、「リソース」を上手く使ってプロジェクトをゴールに導くことだと考えています。プロジェクトマネージャは、基本的に誰も通ったことの無い道を自ら切り拓き、目的のアウトプットに到達することを期待されることから、常に、この先何が起こるかを想像しながらチームをマネジメントしなければなりません。
　　PMBOK（第６版）には、下記のような１０の知識エリアが定められています。
- 統合・マネジメント
- スコープ・マネジメント
- スケジュール・マネジメント
- コスト・マネジメント
- 品質・マネジメント
- 資源・マネジメント
- コミュニケーション・マネジメント
- リスク・マネジメント
- 調達・マネジメント
- ステークホルダ・マネジメント
　いずれの、知識エリアにおいても、ありったけの想像力を以て取り組むことは、プロジェクトの進行とともにあなたの大きな助けとなるでしょう。例えば、リスク・マネジメントでは、あらゆる観点からリスクを想像し、常に先手でリスク管理をしていかなければ、予期せぬリスクにプロジェクトが頓挫してしまうこともあるでしょう。コミュニケーション・マネジメントでは、相手が感情的にどう思うか、どのような利益相反が起きるか考えなければ、衝突・瓦解が起きることもあるでしょう。
　様々なケースを想像しながらマネジメントすることは、苦しくもありますが、プロジェクトマネージャの腕の見せ所でもあると思います。

# 企画力
　プロジェクトマネージャは、期待されるアウトプットを実現する必要があるので、どのような実現手段を採るかが重要になります。しかしながら、ここで肝に銘じておくべきことは、「手段に正解は無い」ということです。自分がマネージャとなり、あらゆる手段の中から自分の判断で手段を決定する際、「本当にこれで良いのだろうか？」と疑心暗鬼になることは少なくありません。しかしながら、往々にして実際のプロジェクトでは全ての手段を実行する余裕はありません。自分が信じる手段を元に実行手段を組み立てるしかないのです。この信じる手段を組み立てる行為こそ企画力だと思います。企画力は、自分の信じる手段、すなわち経験に基づいて養われる力であると思うので、日々いろんなアンテナを張りながら様々な情報を取り込むことが重要です。
　また、過去の失敗もまた経験です。「愚者は経験に学び、賢者は歴史に学ぶ」という言葉がありますが、誰もが賢者ではありません。過去の事例に学べる教訓は多々あるかもしれませんが、やはり最後に頼るべきは自身の経験です。自身の成功例を応用するのも良し、失敗例を避けるように工夫するも良しといったように、様々な経験をすることが新しいプロジェクトに対する企画力を高めることに繋がると考えています。

# 実行力
　プロジェクトマネジメントに必要な力として、想像力、企画力と述べてきましたが、プロジェクトマネージャは机上の空論に終わってはいけません。ありったけの想像力と過去の経験値に基づく企画力を以て、これを実行しなければプロジェクトは進みません。実行するということは勇気の要ることです。しかしながら、プロジェクトマネージャは実行する権限を与えられた立場でもあることも覚えておいてください。誰もがどう転ぶような分からないような状況であっても、あなたの判断が是として託されているのです。思い切って行動し、うまくいかない場合はしっかり反省して次へ活かしましょう。


# まとめ
いかがでしたでしょうか。本稿では、私の経験から、マネジメントに必要とされると思われる力を３つ紹介しました。この３つの力は、プロジェクトマネージャとして自分への戒めの意味も込めて、備忘録として書き記してきました。他のプロジェクトマネージャの方にも、それぞれ経験的に必要だと感じる力が幾つもあるはずです。PMBOKのような教科書的なお作法は誰でも勉強すれば身に付きますが、実際のプロジェクトに携わり自分が感じたこと、思ったことをテーラリングしていくことこそプロジェクトマネージャに求められる資質であるように感じます。
Qiitaの人気記事を検索できるサービス「Qiitank」を作りました

## 概要

私は Qiita で面白い記事を見つけることが日課です。
Qiita 標準では、トレンドしか確認できなくて困っていました。
過去 1 年の人気記事をまとめて読むことはできないものかと思っておりました。ストック数が多い記事は興味がない分野でも面白い記事が多く、新しい学びのきっかけとなります。
以前 Qiita の殿堂というサービスがありましたが、更新が止まってしまったため、類似のサービスを自作しました。

それが、qiita の人気記事を検索できるサービス [Qiitank](https://qiitank.r-nakaishi.com/) です！
Qiita の人気記事を貯めておくタンクのようなサービスを目指し、このような名前となりました。
自分が効率よく記事検索をおこなうために作成したものですが、せっかくなので同じような悩みを持つ方のために公開に踏み切りました。
Qiita サーフィン好きの方は是非使ってみてください。

## 使用技術

| 主な使用技術 | 用途                     |
| ------------ | ------------------------ |
| API Gateway  | API インターフェース     |
| Lambda       | バックエンド             |
| S3           | 画像などのコンテンツ格納 |
| DynamoDB     | 記事情報の格納           |

## 工夫点

ストック数 300 以上、400 以上、500 以上を人気記事として各月ごとに集計しました。
この閾値は適当です！
リクエストのたびに API を使用しては利用制限に引っかかるため、
毎週決まった時間に 1 年分の記事データを取得して DB を更新し、表示の際は DB を参照するようにしています。

## 苦労点

DB にデータを格納する部分の作成に時間がかかりました。どれくらいの間隔で記事を取得するかやストック数を取得する部分の実装がやや複雑になりました。

## 収穫

APIGateway と lambda 関数で Web ページを作成する方法を学ぶことができた。
OGP 画像の設定方法が分かった。
ひとまず、息切れせずに動くものを完成させて公開できた。

## 展望

ストック数以外でもフィルタリングできるようにしたいですね。
毎月 300 ストック以上の記事が出てこないと記事数が 0 件となり見栄えが悪い点も改善したいです。
CI/CD 周りを作っていきたい。

### まとめ

トータルで 20 時間ぐらいはかかったかと思いますが、フロントからバックエンドまで一通りの開発工程を体験できて良かったです。
改善のご要望などございましたらコメントによろしくお願いいたします。
ご覧いただきありがとうございました。
raspberry pi zero ツイ廃モニタ(wareshare 7.9inch Capacitive Touch Screen)設定

参考: https://www.waveshare.com/wiki/7.9inch_HDMI_LCD

/boot/config.txt
```
hdmi_group=2
hdmi_mode=87
hdmi_timings=400 0 100 10 140 1280 10 20 20 2 0 0 0 60 0 43000000 3
# 横長になるように回転
# X can be 1: 90°; 2: 180°C; 3: 270°
display_rotate=1
```
dockerでデバッグしようにもdocker attachでコンソールが出力されず、pumaのログも出力されない件

# 発生した問題
dockerの開発環境上でデバッグをするためにbinding.pryを置いて画面遷移したがpumaのログを吐かないため、binding.pryの所で処理が止まっているか確認出来ず、又docker attachでrailsが動いているコンテナにアタッチしてもコンソールが表示されない。

## 前提
貼りたいyoutubeの動画のurlをmovieモデルのmovie_urlカラムにform_withを用いて保存したい。
userモデルが親、movieモデルが子のリレーションをしている。
しかし、上手く保存出来ずこれが何故かを調べるためにデバッグしようとしたところ今回の問題が発生という流れ。

## 実際の問題コード

docker compose upでサーバーを起動は出来るが、それ以降サイトを読み込んでも以下のログから一向に変化なし。なぜ？

```
app_1  | => Booting Puma
app_1  | => Rails 7.0.4 application starting in development 
app_1  | => Run `bin/rails server --help` for more startup options
app_1  | Puma starting in single mode...
app_1  | * Puma version: 5.6.5 (ruby 3.1.1-p18) ("Birdie's Version")
app_1  | *  Min threads: 5
app_1  | *  Max threads: 5
app_1  | *  Environment: development
app_1  | *          PID: 1
app_1  | * Listening on http://0.0.0.0:3000
app_1  | Use Ctrl-C to stop
```

記述が間違っていると考えられるソースコードを以下に記す。

```docker compose.yml(一部抜粋)
version: '3'
services:
  app:
    build:
      context: .
# =========ローカルと本番切り替え===========
    #command: bundle exec puma -C config/puma.rb -e production
    command: bundle exec puma -C config/puma.rb
# ======================================
```

```puma.rb
threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i
threads threads_count, threads_count
port        ENV.fetch("PORT") { 3000 }
environment ENV.fetch("RAILS_ENV") { "development" }
plugin :tmp_restart

app_root = File.expand_path("../..", __FILE__)
bind "unix://#{app_root}/tmp/sockets/puma.sock"

stdout_redirect "#{app_root}/log/puma.stdout.log", "#{app_root}/log/puma.stderr.log", true
```

## 解決策
```docker compose.yml(一部抜粋)
version: '3'
services:
  app:
    　tty: true
    stdin_open: true
    build:
      context: .
# =========ローカルと本番切り替え===========
    #command: bundle exec puma -C config/puma.rb -e production
　　　　　　　　command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
# ======================================
```
###### 解説

::: note
tty: true
stdin_open: true
:::
docker attachでコンテナの外から命令するために必要とのことで追加しました。
続いて

:::note alert
command: bundle exec puma -C config/puma.rb
:::
:::note
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
:::
と変更することした。こちらリサーチ不足でなぜこれで上手くいったかわかっていないため分かり次第編集します。



```puma.rb
threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i
threads threads_count, threads_count
port        ENV.fetch("PORT") { 3000 }
environment ENV.fetch("RAILS_ENV") { "development" }
plugin :tmp_restart

app_root = File.expand_path("../..", __FILE__)
bind "unix://#{app_root}/tmp/sockets/puma.sock"
```

###### 解説

::: note alert
➖stdout_redirect "#{app_root}/log/puma.stdout.log", "#{app_root}/log/puma.stderr.log", true
:::

このコードにより、標準出力/標準エラーを出力するファイルが予期せぬところに出力され、ログが出力されないと仮定し削除したところpumaがログを吐くようになり、結果docker attachでコンソールを表示し、デバッグすることができました。めでたし、めでたし。
何か間違っている点ありましたら指摘のほどよろしくお願いします。
ExcelマクロVBAですぐに結果を出した学習方法

こんにちは。
先日、VBA始めて2週間で、4時間かかっていた業務を10分に縮めました。
「面倒な業務がこんな簡単に短縮できるのか!」と感動したので、私が今までやったことを記事にしたいと思います。
VBAを始める人が増えてくれたら超嬉しいです。

## マクロを学ぶ目的を考える
マクロは、**使う場面を思い浮かべないと書けません**。
普段の業務で、
・ひたすら繰り返す作業
・毎月発生する作業
など、「これ手でやらなくてもよくない?」という業務を思い出してください。

私の場合、「大量のデータから大量のグラフを作る業務」に焦点をあてました。
ターゲットを絞らないと、無限に学ぶことが出てきてしまいます。目標は決めておきましょう。

## まずこのサイトで基本を学ぶ
https://excel-ubara.com/excelvba1r/

ターゲットを絞ったとはいえ、基本構文すらわからないとさすがに書けません。
「**VBA再入門**」は、私が実際に学習したサイトです。VBAの基本的な書き方を学ぶにはうってつけだと思います。

### どのくらい勉強するか?
第1回から第8回までやれば、簡単なマクロは書けるようになります。(所要時間も3時間ほど。お手軽)
一応全30回ありますが、書くのに慣れさえすれば、最後までやりきらなくても問題ないです。
ただし、
>第11回．分からない事はエクセルに聞く（マクロの記録）
第12回．エクセルの言葉を理解する（オブジェクト、プロパティ、メソッド）
第17回．セルにブック・シートを指定する（Workbooks,Worksheets,With,Set）
第18回．シートをコピー・挿入・削除する（Worksheets,Copy,Add,Delete）

このあたりはやっておくべきと思います。

## いざマクロ作成!マクロの記録から始めよう
https://excel-ubara.com/excelvba1r/EXCELVBA511.html

先程紹介したサイトの、「第11回．分からない事はエクセルに聞く（マクロの記録）」です。
こちらを参考に、実際に業務を記録してみましょう。

### マクロを記録したら
マクロの記録で作られるVBAは、目も当てられないほどぐちゃぐちゃです。なので、必要な部分に絞ってコードを整えていくことになります。
単語単語で拾い上げつつ、たくさんググって乗り越えましょう。

マクロの添削方法についても、上記サイトが参考になると思います。

### とはいえ、とりあえず動けばヨシ
最初からうまく作るのは難しいので、とりあえず動いたらOK!としましょう。
調べつつ改修していけば、段々慣れてきれいに書けるようになります。とにかく実践して慣れるのが大事です。

## あとは学びつつ実践の繰り返し
コードのきれいな書き方やVBAの機能など、知識を増やすことで書けるマクロの幅が広がります。
「VBA再入門」のサイトは[学び方のロードマップ](https://excel-ubara.com/EXCELVBA0.html)もあるので、覗いてみてください。

以下では、記録したコードを整える例について挙げています。
これができるようになると強いです。

### コードの改修例

```vb:testシートでA1をB1にコピーするだけ
    Sheets("test").Select
    Range("A1").Select
    Selection.Copy
    Range("B1").Select
    ActiveSheet.Paste
```
SelectしてSelectしてCopyしてSelectしてPaste…
分かりづらすぎます。。さすがマクロの記録。

このコードを直すと↓
```vb:testシートでA1をB1にコピーするだけ
    Dim ws As Worksheet
    Set ws = Worksheets("test")
    
    ws.Range("A1").Copy Destination:=ws.Range("B1") 'この1行でコピーペースト終わり
```
すっきり書けました。
しかも、コピペ動作の記述は**たったの1行**です。
(最初の2行はオブジェクト変数定義)

### きれいなコードを書くためにやったこと
・オブジェクト変数を学ぶ
・Withステートメントを学ぶ
・とにかくググる

オブジェクト変数とWithステートメントは必修です。
あとのことはケースバイケースなので、**とにかくググって先人に頼りましょう**。
(先程の例はコピーペーストの書き方でしたが、グラフの作成やピボットテーブルの操作などなど、エクセルの機能分だけ無限にあります。それぞれの書き方覚えてられないので、いつも調べつつやってます)

## おわりに
VBAをちゃんと学ぼう!と思うと、敷居が高くて踏み出しにくいですが、
必要に迫られて「とにかく業務に活かす!」と思えば、ちょろっと勉強してちょろっと作る、くらいの感覚でできてしまいます。
そして作って動くとめちゃ楽しいのもいいところです。VBA大好き。

最後まで読んでいただき、ありがとうございました。
この記事がお役に立てたら幸いです。
PowerAutomate: chunk() で payload is too large を回避する

# 背景
Teams への通知をしようとすると、超えられない壁の一つとして立ちはだかるのが、これ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/397bbde9-1a6c-b86d-6a10-4c4fad13a093.png)

特定の条件下であれば、 [チャンク (chunk)](https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#chunk) で簡単に回避できるようになった、という紹介です

## 条件
表など、繰り返しデータで too large になっていて、card を分割可能

# 詳細

Adaptive Card で動的に表通知をしようとすると、結構簡単に超えてしまう

回避方法としては、サイズを減らすしかないので、以下などが考えられる
1. プロパティを減らす
    1. Default なら消す
1. プロパティを集約する
    1. 上位で定義して、継承させることで、定義数を減らす
1. 表示列を減らす
    1. 表示情報を削る
1. 表示内容を圧縮する
    1. 体言止めだったり、Summary表示だったり
1. 表示行数を一定数以下にとどめて分割

ここで、最後の、行数分割が最終手段になるわけだが、従来だと・・

1. 全体Loop
1. Loop変数で、.Skip(25).Take(25) みたいに一定行数取得
1. Post 

ってなって、かなり面倒な上に、Apply to Each だと [iterationIndexes()](https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#iterationIndexes) が使えないので、index も制御する必要がある

で、ここで救世主 [チャンク (chunk)](https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#chunk) の登場です

## 実装例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/09be015a-97f9-7e39-8992-78d2af3d799d.png)

1. 元となる行データを、適切な大きさで分割(Chunk)
1. Apply to each で分割したものを Loop
1. あとは、元の通知をほぼそのまま利用

```json: chunk 30 行で分割の例
@{chunk(variables('Rows'), 30)}
```

:::note warn
union() は、情報排除されるので、利用時は注意。
:::
https://qiita.com/baku2san/items/39e7a40c1a1fb327362a#%E5%BF%9C%E7%94%A8


## 動作例
一括の場合はエラーになるものも、適切なサイズで分割したものは、複数のCardで送信されて問題無し
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/27f3365a-2a51-537c-222b-b24e42b4b62d.png)
以下は送信例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/29be29f8-c031-d0b3-4d2a-ad90cb8eabca.png)

# あとがき
簡単になったとはいえ、365通知とか最近HTMLの肥大化が進んでるので、HTML系を転送すると簡単に超えてくるし、そもそもHTMLの縮小化手段が乏しくて困る・・

# keyword
how to avoid "payload is too large" by chunk
【Auth0】生成されたJWTにプロパティを追加したい場合のまとめ

# 概要

`Hasura`の`Permission`でテーブルへのアクセスや処理の可否を切り分けたかったが`Auth0`が用意してくれているDBだけでは切り分けが難しかったのでJWTにプロパティを追加した。

公式を見てみると`Auctions`を利用するといいよ！とのことでしたので利用した

RestAPIからデータを取得して必要なデータをJWTに詰め込む想定となっています。

https://auth0.com/docs/customize/actions/actions-overview


## ログイン時の処理にアクションを追加するのでクリック

![スクリーンショット 2022-10-05 21.29.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555632/bacc1f4a-9390-1c56-7edc-eec89faed868.png)

## Add Actionのプラスボタン > Build Customをクリック

必須項目を入力して作成する
![スクリーンショット 2022-10-05 21.31.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555632/bca4aabf-dbb1-ce41-397f-a6cb7aa166e2.png)

## アクションの定義

定義が完了したら「`Save Draft`」で期待する結果を得られることを確認し`Deploy`を行う

```js
const axios = require('axios');

exports.onExecutePostLogin = async (event, api) => {
  const {user_id} = event.user
  const namespace = "https://hasura.io/jwt/claims";
  
  // アクセストークンに必要な要素を追加していく
  api.accessToken.setCustomClaim(namespace, {
    'x-hasura-hogege': 'standard_user',
      'x-hasura-default-role': 'users',
      'x-hasura-allowed-roles': ['users'],
      'x-hasura-user-id': user_id
  })
};

/**
 * Handler that will be invoked when this action is resuming after an external redirect. If your
 * onExecutePostLogin function does not perform a redirect, this function can be safely ignored.
 *
 * @param {Event} event - Details about the user and the context in which they are logging in.
 * @param {PostLoginAPI} api - Interface whose methods can be used to change the behavior of the login.
 */
// exports.onContinuePostLogin = async (event, api) => {
// };
```

## アクションを適用する

![スクリーンショット 2022-10-05 21.34.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555632/9d3bff84-ae10-5cda-1a9b-d33055f83ee9.png)

# 最後に

ここまでの一連の流れが完了したらログイン時に発行されるJWTを複合すると追加したものが反映されています

https://jwt.io/
はじめまして

はじめまして！:ramen:


今までQiitaは他人のをみているだけでしたが、自分でもやってみようと決心し始めました！

Qiitaを始めた理由は、自分の行ってきた学習の復習、思ったことなどの備忘録、自分がどのようなことをやってきたか他の方に知ってもらうためです！



このQiitaでは、主に数か月前から行っているAWSの構築学習や資格勉強について発信していこうと思います、よろしくお願いします！
こういったブログのようなものは初めてで文才もないので見づらいと思いますが、そこの成長も含めてみて頂ければなと思います笑