OmniAICreator/Qiita-1.07M huggingface dataset:
Amazon S3 bucketをセットアップし、アクセスユーザーを作成する

ROSAクラスターで稼働する IBM Cloud Pak for Data 4.7 の Watson Discovery サービスが、Multi Cloud Gateway 経由でアクセスするバックエンドのオブジェクトストレージ用途でAmazon S3 bucketをセットアップする手順例です。

:::note info
テスト環境のため、セキュリティ観点からは最適の設定でない場合があります。ご注意ください。
:::

参考：[Amazon S3 の開始方法](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/GetStartedWithS3.html?icmpid=docs_amazons3_console)

## S3 バケットを作成する
AWSマネージドコンソールで、Amazon S3サービスにアクセスします。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/573d4840-df0c-377b-bd9e-e8654a1977cc.png)
`バケットを作成`をクリックします。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/ce80785d-3ea3-4164-b330-1ab8f6603aae.png)

バケット名を入力、AWSリージョンを選択し、残りの項目はデフォルトのままで、`バケットを作成`をクリックします。
![create_bucket1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/ca8cc04d-7660-1179-92be-69142db1bfba.png)

バケットが作成されたことを確認します。
![create_bucket4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/f4aded47-e523-6237-2fda-e9bd4b59e781.png)



## IAM ユーザーを使って Amazon S3 バケットにアクセスするために必要な AWS の設定をする
参考：[IAMユーザーでAmazon S3にアクセスするために必要な設定](https://www.jpcyber.com/support/create-iam-user-and-iam-policy)

AWSマネージドコンソールで、IAMサービスにアクセスします。
![iam1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/ad5a30b5-52bf-30b4-5a5e-a294f4b41a7d.png)

アクセス管理 →　ユーザーを開き、`ユーザーの作成`をクリックします。![iam2-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/cde48154-8644-3316-ecbb-a9a17d9ff37e.png)
ユーザー名を入力し、`次へ`をクリックします。
![iam3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/f953182f-341d-6549-31cd-6aae278cc993.png)
「許可のオプション」で `ポリシーを直接アタッチする` を選択し、「許可ポリシー」で `AmazonS3FullAccess` にチェックを入れ `次へ` をクリックします。
![iam4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/3d10b2cc-8c1f-b0a0-857d-8eebf09feb66.png)
必要に応じてタグを追加し、`ユーザーの作成` をクリックします。
![iam5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/84148c20-e110-8e4a-c817-47db23f91a74.png)
ユーザーが作成されました。
![iam6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/6c96f830-3128-a411-5c1d-b35e0f145e9e.png)
ユーザー名をクリックし、概要セクション内の `アクセスキーを作成` をクリックします。
![iam7-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/89e30696-33f9-58bc-cd1c-3072f72e8332.png)
`aws コンピューティングサービスで実行されるアプリケーション` を選択し、`上記のレコメンデーションを理解し、アクセスキーを作成します` にチェックを入れ、 `次へ` をクリックします。
![iam8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/cc5684d4-d3a2-e8b6-960c-13c6334e091b.png)
必要に応じてタグを追加し、`アクセスキーを作成` をクリックします。
![iam9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/b1d917f0-8f61-a459-cc02-af330b29e890.png)
`.csv ファイルをダウンロード` をクリックし、ユーザーのアクセスキーとシークレットアクセスキーを含む .csv ファイルを保存します。
![iam10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2164968/3f758a18-65c4-d7c6-e2a5-1b1a49c9027e.png)
MarpでMermaidを利用している場合のVS Codeでプレビューする方法・marp-cliで変換する方法

## はじめに

プレゼン資料などを作成するときに[Marp](https://marp.app/)を利用することがあると思う。Marp自体はマークダウンで記述するので、図やグラフなどは画像などにして張り付けることが必要になるが、[Mermaid](https://mermaid.js.org/)を利用すると、Marpの資料に図を簡単に入れ込むことができる。

 今回は、MarpでMermaidを利用している場合に、VS Codeでプレビューする方法をみていきたい思う。また、VS CodeからMarpをPDFやPPTXにエクスポートするのではなく、[marp-cli](https://github.com/marp-team/marp-cli)を利用して、エディターに依存せずMarpからPDFやPPTXを作成する方法も見ていく。

## VS CodeでMermaidを利用したMarpのプレビューをする方法

- VS Code の`.vscode/settings.json`に以下を追記
```json
{
    ...
   "markdown.marp.enableHtml": true
}
```
- [Marp for VS Code](https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode)を追加する

- Ctrl + Shift + P で `Markdown: Change Preview Security Settings` を検索し、`Disabled`を設定する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/9c20d241-e7c7-da44-8e93-5e910ce4a4ab.png)

以上で完了になる。後は、以下のようなマークダウンを作成して、VS Codeでプレビューして図が描かれればOK。
```markdown
---
marp: true
style: div.mermaid { all: unset; }
---
<div class="mermaid">
gantt    
    title A Gantt Diagram
    dateFormat  YYYY-MM-DD
    section Section
    A task           :a1, 2014-01-01, 30d
    Another task     :after a1  , 20d
    section Another
    Task in sec      :2015-01-12  , 12d
    another task      : 24d
</div>

<script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10.0.0/dist/mermaid.esm.min.mjs';
mermaid.initialize({ startOnLoad: true });
window.addEventListener('vscode.markdown.updateContent', function() { mermaid.init() });
</script>
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/629eef24-c201-2f26-73f3-8bbf8c9b5d12.png)

- 参考：https://github.com/marp-team/marp-core/issues/139
- 参考：[Enable HTML in Marp Markdown](https://github.com/marp-team/marp-vscode#enable-html-in-marp-markdown-%EF%B8%8F)
- 参考：[Markdown preview security](https://code.visualstudio.com/docs/languages/markdown#_markdown-preview-security)
 
## [marp-cli](https://github.com/marp-team/marp-cli)でMermaidを利用したMarpからPDFやPPTXを生成する方法

[marp-cli](https://github.com/marp-team/marp-cli)を利用する事で、VS Codeなどを利用せずともコマンドラインでMarpからPDFやPPTXなどを作成できるようになる。ただ、Mermaidを利用している場合、以下のようなコマンドでMarp→PPTXを作成しても、scriptやHTMLのタグがそのままになってしまい期待通りの出力ならない。
```console
$ docker run --rm -v $PWD:/home/marp/app/ -e LANG=$LANG -e MARP_USER="$(id -u):$(id -g)" marpteam/marp-cli --pptx report.md --allow-local-files
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/09335472-28ff-1fa3-8915-af5158746e25.png)

これを解決するには、`--html`オプションも一緒に利用する必要がある。つまり、以下のようなコマンドにすると、HTMLに変換してそれをPPTXとして出力してくれるので、期待通りの出力結果になる。
```console
$ docker run --rm -v $PWD:/home/marp/app/ -e LANG=$LANG -e MARP_USER="$(id -u):$(id -g)" marpteam/marp-cli --pptx report.md --html --allow-local-files
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/0236b8da-d719-5c24-f5ae-37260b7cedd8.png)
【Rails Rspec 備忘録】Failure/Error: 〇〇　expected: 1 got: 2

### はじめに
※rails初心者向けです。<br /><br />
Rspecでテストコードを書いていた時に、　Failure/Error: 〇〇　expected: 1 got: 2　に直面しました。
備忘録として解決法を残しておこうと思います。

### やりたかったこと
レコードが存在しない場合に新しくid=1のレコードを作成して保存するようなテストを書こうと思いました。

### 間違ったコード
createを2回しているため、エラーが起きた。
expect(テーブル名).exists?(1).to be(false)でレコードの中身をnilにして新しくcreateできると思ったが　、id = 2のレコードが作られてしまった。

```ruby:hoge_spec.rb
describe `PUT /hoge/fuga` do
  before do
    @hoge = create(:hoge, 1)
  end

  context 〇〇 do
　　　　　　it 'レコードが存在しない場合新しくid=1のレコードを作成する' do
    expect(テーブル名).exists?(1).to be(false)
    @hoge = create(:hoge, id: 1)
    put ...........
    json = Json.parse(response.body)
    #レコードが作成されたことの確認
    expect (テーブル名).to eq(1)
    #保存の確認
    hozon = テーブル名.to eq テーブル名.first
　　　　　　end
  end
end
```

### 解決法
before doで書いていた
```ruby
 @hoge = create(:hoge, id: 1)
```
を、before　doから消し、各テスト項目に書くことで2回作成されることを防いだ。
```ruby:hoge_spec.rb
describe `PUT /hoge/fuga` do
  before do
  　　# 省略(@hoge = create(:hoge, id: 1)は消す)
  end

  context 〇〇 do
　　　　　　it 'レコードが存在しない場合新しくid=1のレコードを作成する' do
    expect(テーブル名).exists?(1).to be(false)
    put ...........# 省略
    @hoge = create(:hoge, id: 1)
    json = Json.parse(response.body)
    #レコードが作成されたことの確認
    expect (テーブル名).to eq(1)
    #保存の確認
    hozon = テーブル名.to eq テーブル名.first
  end
end
```

### 最後に
いけた。
Gitでrebase前の状態を確認する

# はじめに

Gitでrebaseやamendなどを使用して歴史改変を行うと、改変前のコミットはどこからも参照されないコミット(dangling commit)となり、logに表示されなくなります。  
(元々複数のブランチから参照されていた場合や、タグを付けていた場合などを除く)

改変前の状態を後から確認したくなった場合などに、そのようなコミットをlogに表示する方法を紹介します。

# 方法

初めにこのような状態があり、

```shell-session
$ git log --graph --oneline --decorate --all
* d670ab8 (master) F
* 3919af1 E
* be56851 D
| * 00ed0c4 (HEAD -> hoge) I
| * 47f1706 H
| * e3af59b G
|/
* 30d63a9 C
* fa7b8c4 B
* 06d8040 A
* b4826a9 Initial commit
```

`hoge`ブランチを`master`ブランチにrebaseしました。

```shell-session
$ git rebase master
Successfully rebased and updated refs/heads/hoge.
```

この時、普通にグラフを表示すると以下のようになり、rebase前の状態は見えなくなっています。[^remote]

```shell-session
$ git log --graph --oneline --decorate --all
* a5a6587 (HEAD -> hoge) I
* f7db3f4 H
* ef48479 G
* d670ab8 (master) F
* 3919af1 E
* be56851 D
* 30d63a9 C
* fa7b8c4 B
* 06d8040 A
* b4826a9 Initial commit
```

しかし、「rebase時のコンフリクト解消で何かミスったかも…？」など、後から元の状態を見たい場合もあるかと思います。

そのような場合、以下のようにすると、見えなくなった元のコミットも表示されます。  
Bashの記法(`` ` ``)を使用するため、Windowsの場合はGit Bash上で実行する必要があります。

```shell-session
$ git log --graph --oneline --decorate `git rev-list --reflog`
* a5a6587 (HEAD -> hoge) I
* f7db3f4 H
* ef48479 G
* d670ab8 (master) F
* 3919af1 E
* be56851 D
| * 00ed0c4 I
| * 47f1706 H
| * e3af59b G
|/
* 30d63a9 C
* fa7b8c4 B
* 06d8040 A
* b4826a9 Initial commit
```

元の`hoge`ブランチの先頭コミットである`00ed0c4`をcheckoutすれば、rebase前の状態を復元できます。

```shell-session
$ git checkout 00ed0c4
```

[^remote]: 元の状態をremoteにpush済みであれば表示されますが、rebase後にforce pushするとやはり表示されなくなります。

# おまけ

上記のコマンドはまれによく使うため、エイリアスを設定しておくと便利です。  
`.gitconfig`に以下の内容を記載しておくと、普段は`git logg`で通常のグラフを表示、  
必要に応じて`git loga`でrebase前の状態も表示、と使い分けることが可能です。

```:.gitconfig
[alias]
    logg = log --graph --oneline --decorate --all
    loga = "!f() { git logg $(git rev-list --reflog) $@; }; f"
```
【Tableau】データソースの更新日時について



## 概要
データソースのパターン別で最終更新日時を確認しました。

## 背景
「更新する予定のないCSV」と「月次更新予定のAWS Athena上のテーブル」を結合したデータソースの最終更新日時をダッシュボード上に表示しようとしたところ、最終更新日時がCSVの最終更新日時になってしまった。

そこで「月次更新予定のAWS Athena上のテーブル」のみで構成された別のデータソースを作成して最終更新日時を表示していたが、Tableau searver上での月次抽出の際に最終更新日時が更新されていなかった。

どの状態が正常なのかよくわからなくなったため、Tableau社に検証してもらった。

## パターン
##### 1.「更新する予定のないCSV」と「月次更新予定のAWS Athena上のテーブル」を結合したデータソース

![スクリーンショット 2023-07-21 10.44.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728184/67bd792a-7a14-4234-a480-8158169fb225.png)





##### 2.定期更新されるAWS athena上のテーブルを参照してカスタムSQLクエリで抽出した場合(limit 10)
![スクリーンショット 2023-07-21 10.45.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728184/0f3370c9-3311-742e-0415-b662e9bbd12d.png)



##### 3.定期更新されるAWS athena上のテーブルのみをそのままデータソースとした場合

![スクリーンショット 2023-07-21 10.45.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728184/f3a3c999-5e83-de57-c186-a0a8b5301655.png)


## 想定される候補
・ワークブックをpublishした日時
・tableau serverで定期抽出を実行した日時
・AWS athena上のテーブルが定期更新された日時
・カスタムSQLクエリが最後に編集された日時
・カスタムSQLクエリが最後に実行された日時
・ワークブックをpublishした日時


## 検証結果
3パターンとも以下の内容が正しいそうです。
```
- ライブ接続の場合
最初はワークブックをした日時、その後は、ビュー内の「更新」ボタンをクリックして、データを更新した日時

- 抽出接続の場合
tableau serverで抽出を実行した日時
```




最終更新日時が更新されていなかった問題についてはキャッシュの影響の可能性があるので、以下のURLを参考にとのことです。
https://kb.tableau.com/articles/issue/view-out-of-date?lang=ja-jp

現状問題は起きていないので、再度問題が起きたら上記を試す予定...
【Tableau】フィルターのタイトルをパラメータによって切り替える



## やりたいこと
フィルターのタイトルをパラメータで可変にしたい

## 背景
シートやダッシュボードのタイトルにはパラメータ等を挿入ができるが、フィルターのタイトルはパラメータ等の挿入ができず、タイトルをパラメータによって切り替える方法がわかリませんでした。
そこで代替方法を試したので手順をまとめようと思います。

シートのタイトル
![スクリーンショット 2023-07-21 2.36.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728184/cc2af8b6-eb89-dfdb-245f-70c5d9b3568e.png)

フィルターのタイトル
![スクリーンショット 2023-07-21 2.36.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728184/d4252ad5-eb75-d8df-fdd0-5c2098cb900d.png)






## 手順
##### 1. パラメータを用いたダッシュボードを作成
こちらの記事を参照
https://qiita.com/takowasa298/items/ebb88837ac8ac0d52075






##### 2. 計算フィールドを2つ作成する
フィルターのタイトルを非表示にします。
![スクリーンショット 2023-07-21 2.38.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728184/01b10d1b-a17f-4024-46d2-2565b4bdb548.png)


![スクリーンショット 2023-07-21 2.48.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728184/4e385fbd-b820-f099-8324-7d93850275cc.png)






##### 3.テキストオブジェクトをフィルターの上部に配置する。

![スクリーンショット 2023-07-21 2.50.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728184/72df2391-e2d4-0b3e-7978-86af03fb634a.png)


##### 4. テキストオブジェクトにパラメータを挿入する。

![スクリーンショット 2023-07-21 2.38.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728184/dec9c754-3825-01b4-6ed2-1f84c228091e.png)

##### 5. 動作確認
パラメータ1を変更するとフィルターのタイトルも変わっていることがわかります。
レイアウトはお好きなように調整してください。
![スクリーンショット 2023-07-21 2.39.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728184/5137f2fe-52cb-12a3-037d-2ff8472df2fc.png)

![スクリーンショット 2023-07-21 2.39.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728184/1631afbf-ae39-1f12-92e4-1c7fbba9b0f2.png)

![スクリーンショット 2023-07-21 2.40.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728184/11cd9636-c1c2-f466-73c8-c1926dc59b63.png)

フィルターのタイトルを切り替える方法がありましたら教えていただけると助かります...
プリザンターのパフォーマンスが悪いと思った時の調査方法

# はじめに
プリザンターは動作スピードがとても早く、タイムラグによるストレスがないという点においても、とても魅力的な製品です。しかし、そんなプリザンターですが、動作が重い(パフォーマンスが悪い)時があります。そんな時の原因の調査方法をご紹介します。

# 前提
本記事ではプリザンターの処理速度が遅いと思った際の調査方法をご紹介しますが、原因の特定を目的としたものではありません。本記事では、あくまで「原因と考えられる」事象を推測するための方法です。

# 原因と考えられる事象を発見する方法
## 前提
まずは、「Syslog」が見られる環境である必要があります。そして、「Syslog」に設定されている列ごとの意味を理解する必要があります。こちらに関しては下記のユーザマニュアルをご参照ください。  
[FAQ：操作ログ(SysLogsテーブル)の内容について](https://pleasanter.org/manual/faq-contents-of-syslogs)  
なお、本記事で理解する必要がある項目は「Elapsed」です。
## 結論
上記でご紹介した「Elapsed」にはサーバサイドで1リクエスト当たりに必要とした時間（ミリ秒）が記録されます。つまり、「Elapsed」列の値が大きい処理が原因と考えられます。ただこちらは上記にもあるように「原因と考えられる」だけであり、原因の特定をすることはできません。
## 方法
1. まずは「Syslog」テーブルのデータをコピーします(この時、カラム名も含めてコピーしてください)。
   * スプレッドの左上を右クリックします。
   * キャプチャのように「ヘッダー付きでコピー」をクリックします。  
# はじめに
プリザンターは動作スピードがとても早く、タイムラグによるストレスがないという点においても、とても魅力的な製品です。しかし、そんなプリザンターですが、動作が重い(パフォーマンスが悪い)時があります。そんな時の原因の調査方法をご紹介します。

# 前提
本記事ではプリザンターの処理速度が遅いと思った際の調査方法をご紹介しますが、原因の特定を目的としたものではありません。本記事では、あくまで「原因と考えられる」事象を推測するための方法です。

# 原因と考えられる事象を発見する方法
## 前提
まずは、「Syslog」が見られる環境である必要があります。そして、「Syslog」に設定されている列ごとの意味を理解する必要があります。こちらに関しては下記のユーザマニュアルをご参照ください。  
[FAQ：操作ログ(SysLogsテーブル)の内容について](https://pleasanter.org/manual/faq-contents-of-syslogs)  
なお、本記事で理解する必要がある項目は「Elapsed」です。
## 結論
上記でご紹介した「Elapsed」にはサーバサイドで1リクエスト当たりに必要とした時間（ミリ秒）が記録されます。つまり、「Elapsed」列の値が大きい処理が原因と考えられます。ただこちらは上記にもあるように「原因と考えられる」だけであり、原因の特定をすることはできません。
## 方法
1. 「Syslog」テーブルのデータをコピーします(この時、カラム名も含めてコピーしてください)。
   * スプレッドの左上を右クリックします。
   * キャプチャのように「ヘッダー付きでコピー」をクリックします。  
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659914/d27c46fc-a722-f2ed-43b3-42959bb56843.png)
2. Excel(A1)に上記コピーした内容を貼り付けます。
3. A列(CreatedTime)の書式を「YYYY/MM/DD HH:MM:SS」に変更します。
   * A列を選択し、右クリックします。
   * 「セルの書式設定」をクリックします。
   * 「分類」の「時刻」を選択し、「YYYY/MM/DD HH:MM」を選択します。
   * 「分類」の「ユーザー定義」を選択し、「yyyy/m/d h:mm;@」を「yyyy/m/d h:mm:ss;@」に変更します。
   * 「OK」をクリックします。
4. 「ホーム」タブの「編集」にある「並べ替えとフィルター」をクリックします。
5. 「フィルター」をクリックします。
6. 「Elapsed」の右下「▼」をクリックし、「数値フィルター > トップテン」をクリックします。
7. 数値を「10」から任意の数値に変更します。
8. 「Elapsed」の右下「▼」をクリックし、「降順」を選択します。
9. P列(Elapsed)を選択し、「ホーム」タブの「スタイル」にある「条件付き書式」をクリックします。
10. 「データバー」をクリックし、好みのスタイルを選択します。

## 表の見方
表は「Elapsed」の降順になっているため、先頭行には処理のもっとも時間のかかっているリクエストが表示されています。そのため、先頭行はとくにパフォーマンスを悪化させている要因だと考えられます。
Rails + MySQL – NULLをORDERで最後/最初に並べる例

```rb
# ASCで並び替え NULL は最後に並べる
User.order(Arel.sql('name IS NULL ASC, name ASC'))

# DESCで並び替え NULL は最後に並べる
User.order(Arel.sql('name IS NULL ASC, name DESC'))

# ASCで並び替え NULL は最初に並べる
User.order(Arel.sql('name IS NULL DESC, name ASC'))

# DESC で並び替えNULLは最後に並べる
User.order(Arel.sql('name IS NULL DESC, name DESC'))
```


# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ
NixOSでhostsファイルを書きかえられない問題

# 発生した問題

`coc.nvim`をインストールし、`:CocInstall coc-json`コマンドを実行する段階で、IPv6で接続できないというエラーが発生しました。

`host`コマンドでIPアドレスを調べ、`/etc/hosts`ファイルを編集しようとしました。

```bash
sudo vim /etc/hosts

E166: リンクされたファイルに書込めません
```

`ls -l`コマンドで確認してみると、`/etc/static/hosts`ファイルからのシンボリックリンクが張られていました。
こちらに書き込むのが正しいのかなと考え、`/etc/static/hosts`ファイルを編集しようとしました。

```bash
sudo vim /etc/static/hosts

E166: リンクされたファイルに書込めません
```

こちらのファイルも`ls -l`コマンドで確認してみると、`/nix/store/<ハッシュ値>-hosts`ファイルからのシンボリックリンクが張られていました。

# 問題の原因

今まで`configuration.nix`ファイルなどを編集して設定を変更していたにも関わらず、今回の例ではhostsファイルを直接弄っていたことが問題の原因でした。

# 解決策

`networking.extraHosts`に対してホスト名とIPアドレスの対応を記述することでhostsファイルに追記されます。

```nixos:configuration.nix
# 省略
{
 # ...
 networking.extraHosts = 
  ''
   IPアドレス ホスト名
  ''
 # ...
}
```

ビルド後、`/etc/hosts`ファイルや`/etc/static/hosts`ファイルを確認してみると、ファイルの末尾に今回追記した内容が追加されています。

```
# ...
IPアドレス ホスト名
```

# まとめ

水曜日からNixOSを触り始めたということもあり、わたしの理解が浅いせいで発生したエラーだと思います。

戒めとしてこの記事は残しておきたいと思います。
管理者側　顧客情報詳細ページ

 **はじめに**
bootstrap導入済　
namespases使用
devaice導入済
顧客一覧ページ作成済
Admin::CustomersController作成済
__________
完成イメージ
### ルーティング
costomersに**show**、
編集ページのための**edit**
注文履歴一覧を表示するために**resources :orders, only: [:index]** を追加
```diff_ruby
 namespace :admin do
  resources :customers, only: [:show, :edit, :update] do
+   resources :, only: [:index] # ここを追加
  end
```
### モデル

顧客が多数の注文を持っているようにします
顧客の注文履歴一覧を見るためです
```costomer.rb
class Customer < ApplicationRecord
   has_many :orders
end
```
```order.rb
class Order < ApplicationRecord
   belongs_to :customer
end
```

### :shamrock:コントローラー
特定の顧客の情報を一つ取得して、@customerに格納します。
```admin/costomers_contoroller.rb
def show
  @customer = Customer.find(params[:id])
end
```

```admin/orders_controller.rb
class Admin::OrdersController < ApplicationController
  def index
      @customer = Customer.find(params[:customer_id])
      @orders = @customer.orders
   end
end
```
**@customer = Customer.find(params[:customer_id])**
URLから送られてきた顧客ID（customer_id）を使って、その顧客の情報をデータベースから取得しています。この顧客情報は、後でビューで表示するために @customer 変数に格納されます。

**@orders = @customer.orders**
取得した顧客が過去に行ったすべての注文情報をデータベースから取得しています。これらの注文情報は、後でビューで表示するために @orders 変数に格納されます。

つまり、このコントローラーは、指定された顧客が過去に行ったすべての注文の一覧を取得し、それをビューに表示するための情報を提供する役割を果たしています。
### views 顧客情報詳細ページ
```erb:admin/costomers/show.html.erb
<div class="container mt-5">
  <h2 class="mb-4 text-center"><%= @customer.last_name %> <%= @customer.first_name %>さんの会員詳細</h2>

  <div class="pl-5">
    <p class="my-3"><strong>会員ID </strong><span style="margin-left:150px;"><%= @customer.id %></span></p>
    <p class="my-3"><strong>氏名 </strong><span style="margin-left:160px;"><%= @customer.last_name %> <%= @customer.first_name %></span></p>
    <p class="my-3"><strong>フリガナ </strong><span style="margin-left:130px;"><%= @customer.kana_last_name %> <%= @customer.kana_first_name %></span></p>
    <p class="my-3"><strong>郵便番号 </strong><span style="margin-left:130px;"><%= @customer.post_code %></span></p>
    <p class="my-3"><strong>住所 </strong><span style="margin-left:160px;"><%= @customer.address %></span></p>
    <p class="my-3"><strong>電話番号 </strong><span style="margin-left:125px;"><%= @customer.phone_number %></span></p>
    <p class="my-3"><strong>メールアドレス </strong><span style="margin-left:80px;"><%= @customer.email %></span></p>
    <p class="my-3"><strong>会員ステータス </strong><span style="margin-left:90px; color:<%= @customer.is_deleted ? 'gray' : 'green' %>;"><%= @customer.is_deleted ? '退会済み' : '有効' %></span></p>

   <%= link_to '編集する', edit_admin_customer_path(@customer), class: 'btn btn-success btn-space' %>
   <%= link_to '注文履歴一覧へ', admin_customer_orders_path(@customer), class: 'btn btn-info' %>


  </div>
</div>
```
Google Colaboratory に SSH接続して VSCode上から環境を利用する方法

# はじめに
Google Colaboratory は非常に便利で、簡単にGPUコンピューティングを利用できるようになってますが、Jupyter Notebook　形式 + α しか利用できないため、可読性が下がったり、ファイル分けが難しいため、これを簡単に利用したい。
そのため、Visual Studio Codeを利用して、あたかも自分のPC上で作業しているかのように扱うことが可能だとわかったので今回はその備忘録。

# 注意点

Google Colaboratoryの規約違反の可能性があるので、GPUコンピューティングを利用する際はProに入ることをお勧めします。

# 概要

`cloudflared` を利用してトンネリングから接続リンクまでを自動で作業してもらうという非常に優秀なツールがあったのでそれを使う。
作業の手順としては以下の通り。

1. Google Colaboratory ファイルを　Google Driveから作り、コードを貼り付けて実行
1. 自分のPC上に`cloudflared` をインストール
1. SSHの設定
1. 接続！

非常に簡単である。

# 手順 (Mac)

後にWindowsも追記する予定

## 1. Notebook の作成

まずはホストするサーバーの起動をするために、Drive上に、Jupter Notebookを作成する。

1. Google Drive の好きな場所に Google Colaboratory ファイルを作成して開く。
1. `ランタイム`->`ランタイムのタイプを変更`から`ハードウェア　アクセラレータ`を`GPU`を選択する。
1. 以下のプログラムをコードセルに貼り付け、任意のパスワードを指定して実行する。
    ```python
    import os
    from google.colab import drive
    drive.mount('/content/drive')
    
    !pip install colab_ssh --upgrade
    from colab_ssh import launch_ssh_cloudflared, init_git_cloudflared
    launch_ssh_cloudflared(password="任意のパスワードを指定する")
    ```

## 2. PC に　`cloudflared` をインストール

今回は`Homebrew`を利用してインストールするため、インストールしていない人は、`Homebrew`をインストールしてください。

```sh
brew install cloudflare/cloudflare/cloudflared
```

## 3. SSH設定を作成する

ssh コマンドで特定のホストについてどんなプロキシを利用するかを設定します。
~/.ssh/config　というファイルに追記、または作成して記述します。
sshで自動でそのファイルを参照するので、特に同期などという作業は必要ないみたいです。

また、インストールした`cloudflared`の絶対パスを指定する必要があるので、以下のコマンドで取得して記述し直してください。<>はいりません。

```sh
which cloudflared
```

```ssh
Host *.trycloudflare.com
	HostName %h
	User root
	Port 22
	ProxyCommand <cloudflaredの絶対パス> access ssh --hostname %h
```

<details><summary>パスが出なかった場合</summary><div>

---
パスが出なかった場合はパスが通っていないので以下のコマンドで存在を確認し、パスを作成します。

```sh
# これを実行し、cloudflaredが表示されていればインストールされています。
brew_path=`brew --prefix`; cd $brew_path/bin; ls | grep "cloudflared"

# これを実行して出力されるパスがcloudflaredの絶対パスです。
brew_path=`brew --prefix`; echo $brew_path/bin/cloudflared
```
---
</div></details>

## 接続！

作成した Jupter Notebook にコマンドが記述されているため、そちらで基本的に実行できます。
以下はそのコマンドのコピーです。

### SSH

```sh
ssh little-representations-establish-audit.trycloudflare.com
```

### Visual Studio Code

1. 左下の`< >` マークをクリックし、 上に出てくるパレットからSSHを選択します。
2. 以下のコマンド（リンク）を入力します。

```sh
little-representations-establish-audit.trycloudflare.com
```

入力画面は、左下の `< >`　アイコン　→ ホストに接続する、で表示させることができます。

# データの保存するパスについて

リモート環境はランタイムを削除するとリセットされてしまうので、Google Drive上に保存することをお勧めします。

リモート環境の接続時にパスを設定しますが、以下のパスで保存場所をGoogle Driveにすることができます。

```
/content/drive/MyDrive/これ以降のパスは個人的に設定することができます。
```

# 参考

https://qiita.com/kujirahand/items/9796023a563c19eaf944
webdriver_managerのエラー対策

webdriver_managerを使用していたところ、エラーが発生するようになりました。
driverをダウンロードするためのパスが変わってしまった？ようです。
以下の方法でソースコードを書き換えずに処理できました（応急処置になります）。

```
pip uninstall webdriver-manager
pip install https://github.com/david-engelmann/webdriver_manager.git
```

<h2>追記</h2>
Version3.9で修正されたため、webdriver_managerをアップデートすればOKです。

<h3>参考資料</h3>
<a href='https://github.com/SergeyPirogov/webdriver_manager/pull/537'>
github issue
</a>
さくらのVPSの512MBプランでもクローンする方法

## あらすじ
以前、ReaRを使ってさくらのVPSのクローンを作成する記事 [さくらのVPSをReaRでクローンする](https://qiita.com/Kaz_Macintosh/items/fc77c413ff741f0ac6ef) を書きましたが、メモリが2GB程度ないと実行できないようでした。また同様なツールのMondo Rescueもメモリが少ないと起動すらしません。そこで今回は、コピー先でLive CDを起動して、ddでコピーする方法を試してみました。

以下の内容はMIRACLE LINUX 8での結果です。

## Live CDの用意
今回は軽量な[KNOPPIX](https://www.knopper.net/knoppix/index-en.html)を使用しました。KNOPPIX懐かしいですね。ダウンロードページよりCDバージョンのISOファイルをダウンロードします。CDなら700MBで済みます。

## コピー先の準備
さくらのVPSのコントロールパネルにログインし、コピー先のVPSの画面を開いて「OS再インストール」を選択します。ISOイメージ→アップロードするを選択するとアップロード先の情報が表示されるので、指示された内容に従ってSFTPでKNOPPIXのISOファイルをアップロードします。アップロードが完了したらVPSを起動します。

KNOPPIXが起動したら以下の設定を行います。
1. ネットワークの設定
1. rootパスワードの設定
1. sshサーバーの起動

### 1. ネットワークの設定
さくらのVPSは自動的にネットワークが設定されないので、手動で設定してあげる必要があります。nmtuiコマンドとかを使うと楽です。
![knoppixnet.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129769/f3fc4c79-7fb9-3de0-ca76-81cf7a171466.png)

### 2. rootパスワードの設定
passwd
（VPSのパケットフィルタでアクセス制限しておくことをおすすめします）

### 3. sshサーバーの起動
/etc/init.d/ssh start

## コピー元から転送開始
続いてコピー元にログインして、ディスクイメージを転送します。

```
# dd if=/dev/vda bs=32k status=progress | ssh -C 192.168.0.1 dd of=/dev/vda bs=32k
```
コマンド解説
dd if=/dev/vda if=はコピー元のディスク。
bs=32k　は転送時のブロックサイズ。（値によって転送効率が変わる）
status=progress　進行状況の表示。

ここまでがコピー元のサーバーに関係する部分です。of=が付いてないので標準出力に出力されますが、パイプによりsshコマンドに渡されます。sshのポートフォワーディング機能を利用して、ddコマンドに入力しています。

コピー先の部分
| ssh -C 192.168.0.1　接続先のサーバー(KNOPPIX) -Cは圧縮オプション。
dd of=/dev/vda of=はコピー先のディスク

転送が完了したらKNOPPIXは shutdown -h now コマンドなどで終了します。

## コピー後の設定
### 1. ネットワークの設定
コピー先のVPSを起動すると、コピー元と同じように起動すると思います。ただしネットワークの設定が必要なため、nmtuiなどお好きな方法でネットワークの設定をします。

### 2. gptの修正
たとえばさくらのクラウド(20GB)からコピーした場合など、ディスクのサイズが違うため修正が必要です。
```
# gdisk /dev/vda
```
x、e、m、p、w で修正。

## 最後に
これでたくさん作りたいサーバーを簡単にクローンしたり、VPSへの移行、VPSからの移行が簡単にできますね。さくらのVPSは値段が安い反面、さくらのクラウドにある機能が削られてるので、このへんを使い分けていくとなかなかコストパフォーマンスがよいです。


以下、2023.8.18追記
## 追記：ローカルネットワークでクローンする
今まで説明してきた方法には一つ問題があります。それはグローバルIPアドレス同士でクローンを行った場合、インターネット越しに大量のトラフィックが発生する場合があります（実際はさくらのネットワーク内ですが）。さすがに数GBのデータを何度も送信していると、帯域制限を行われてしまう恐れがあります。さくらは割と緩い印象がありますが、ConoHaで同じことをやったら一発でポートをブロックされてしまいました。事前の通告もなくいきなり。

[スイッチ](https://manual.sakura.ad.jp/vps/network/switch.html) を作成して、eth1とスイッチを接続すれば、ローカルネットワーク経由で転送ができます。

## 追記：異なるリージョン間をローカル接続する
さくらのVPSのスイッチは同じリージョン間でしか接続できません。リージョンを跨いだクローンを行いたい場合は、さくらのクラウドのブリッジ機能を使って、VPSのそれぞれのリージョンのスイッチを接続するという方法があります。詳しくは [こちら](https://manual.sakura.ad.jp/vps/support/technical/tkik-local.html) に説明があるので参考にしてみてください。

実際にどのくらいのトラフィックが発生しているのか、ディスク容量20GB、ディスクの使用量3.7GBほどのディスクイメージを転送してみたところ、6.78GB 程でした。（転送元はVPSではなくクラウドのディスクです）
![cloud to vps local-net.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129769/467aacea-eaab-831a-acda-86bee2567901.png)
sshの-Cオプションで圧縮しているので、20GBのディスクでもそのまま20GBのトラフィックが発生するわけではありませんが、実際の使用量の倍もあるのは意外でした。
振り返りでは「労う・感謝する」ことを大事にしよう

## この記事は何
どの会社でもある程度のスパンでチームの振り返りをやっていることは多いと思います。
スクラムなどを導入しているのであれば各スプリントで振り返りを行っているのではないでしょうか。

この振り返りがあまり活発にならない、あまり議論が生まれない、という悩みをちらほら聞くので、いきいきとした振り返りを作るために僕が特に意識している「労い・感謝」の重要性について記事にしました。

## 労う・感謝することの意味
振り返りを始めるときに、すぐに問題だった箇所から入ることはないでしょうか？
逆にKPTなどでKeepを集めても何も出てこない、そんな組織もあると思います。

僕は、まずは自分たちが行ってきたことそれ自体を認める、労う、称賛することを必ずメンバーにやってもらうようにしています。

僕はチームとしてお互いを労い、感謝しあうことはとても重要なプロセスだと思っています。
この理由は「それ自体が自分たちが努力するインセンティブになるから」です。
仕事のインセンティブはもちろん給与など金銭的なものが一番わかりやすいですが、お金が必要になるのも生きていくため、さらにいうと豊かな生活を送るためだと思います。
豊かな生活はお金だけではなく、人同士の繋がりや感謝などからも得られることは今までの経験から誰でも知っているはずです。

振り返りではまずはお互いのやってきたことを労い、感謝し、認め合い、次のスプリント、プロジェクトからも頑張っていこうと思えるような前向きな雰囲気を作っていくことで、問題にも正面から向き合うことができるようになっていきます。

## 具体的に取り組んでいること

ちなみにこの「労う・感謝する」ことの重要性については[ゾンビスクラムサバイバルガイド: 健全なスクラムへの道](https://www.amazon.co.jp/%E3%82%BE%E3%83%B3%E3%83%93%E3%82%B9%E3%82%AF%E3%83%A9%E3%83%A0%E3%82%B5%E3%83%90%E3%82%A4%E3%83%90%E3%83%AB%E3%82%AC%E3%82%A4%E3%83%89-%E5%81%A5%E5%85%A8%E3%81%AA%E3%82%B9%E3%82%AF%E3%83%A9%E3%83%A0%E3%81%B8%E3%81%AE%E9%81%93-%E6%9C%A8%E6%9D%91-%E5%8D%93%E5%A4%AE/dp/4621307398)という本でも紹介されています。

本の中では「Kudobox」という感謝をお互いに伝え合うツールの紹介がされています。これは以下のような流れで感謝を伝えていきます。

- 各スプリントなどの期間で、「〇〇が助かった」「〇〇が良かった」と感じたタイミングで、箱にメッセージカードをポストしていく（プレゼントなどもメッセージにつけられるようにするのもGood）
- スプリントレトロスペクティブのタイミングなどで箱を開け、それぞれのメンバーへメッセージカードを贈る

https://kudobox.co/

僕のチームではKudoboxまではやっていませんが、スプリントレビューやレトロスペクティブのタイミングで、自分たちがこのスプリントで何をリリースできたのかを振り返り、それぞれのメンバーからそれぞれのメンバーへ良かったところ、助かったところを伝えあうということをしています。

そこまでで一旦自分たちが取り組んできたことをお互いに認め合い、Probremに向き合っています。

## 起こった変化
この取り組みを続けることで、メンバー同士の関係性がよくなったと感じています。
振り返りだけではなく、日々のコミュニケーションや朝会での議論も活発になり、「息をしているスクラム」を作ることができました。

チームとしての動きに何か課題を感じていたら、まずはお互いを認め合う、感謝することから始めてみるのはいかがでしょうか？
SQL問題　初級編

# はじめに
みなさまこんにちは、
本日はみなさまに向けてSQLの問題を出題させていただきます。
４択なので、答えを一つ選んでください。

# 前提環境
postgres:13
https://hub.docker.com/layers/library/postgres/13/images/sha256-f146d3f56382d538abf128322bbe060784fdc0586c369c6e70a0c40838b00f94?context=explore

# 問題
以下、4つのクエリの中から、関数hoge()が**呼び出されないもの**を選んでください。
hoge()は以下、内容とする。



```SQL:hoge.sql
-- 呼び出されたらtrueを返すだけ
CREATE OR REPLACE Function hoge() RETURNS boolean
AS $$
DECLARE
  flag boolean;
BEGIN
  flag := TRUE;
  RETURN flag; 
END;
$$
LANGUAGE plpgsql;
```

## 選択肢

A\. `select hoge();`
B\. `select TRUE OR hoge();`
C\. `select FALSE OR hoge();`
D\. `select TRUE AND hoge();`

## 答え
**B**

## 解説
これはPostgreSQLの評価規則によるもので、具体的には式の一部を評価しただけで式の結果を決定できる場合には、他の副式がまったく評価されないことがあります。

選択肢Bのクエリでは、`TRUE OR hoge();`という式があります。この式では、`TRUE OR`の部分が既に`TRUE`を返すため、その後の`hoge()`関数は評価されない可能性があります。これは、一部のプログラミング言語に見られる「短絡評価」の一種とも言えますが、PostgreSQLでは必ずしも左から右に評価されるわけではないです。

したがって、この問題の条件「関数hoge()が呼び出されないものを選ぶ」に適合するのは選択肢Bとなります。

詳細は[こちら](https://www.postgresql.jp/document/13/html/sql-expressions.html#:~:text=%E3%82%82%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82-,4.2.14.%20%E5%BC%8F%E3%81%AE%E8%A9%95%E4%BE%A1%E8%A6%8F%E5%89%87,-%E5%89%AF%E5%BC%8F%E3%81%AE)のPostgreSQL公式ドキュメントをご覧ください！

## 終わりに
また、時間があったらこれ系の問題作ります。
BizRobo!の環境をAWSで簡単に構築してみた

## はじめに
弊社のチームではBizRobo!の検証をするための環境構築を依頼されることが度々あります。
そのたびにインスタンスを新規作成しているのですが、依頼される頻度が多くなってきたので効率化したいなと思いAWSのCloudFormationを使って構築してみました。
タグ管理も統一できるようになるので効率的な運用ができそうです。
どのように実現したのかまとめてみました。

## 構築イメージ
### インフラ構成図
ゴールとするインフラ構成図は以下のようになります。
![AWS環境構築（社内依頼確認用） - Qiita用CloudFormation構成図.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124412/2ee0a7f7-ed84-4dd5-4b03-dd2edf081257.jpeg)

### 事前準備
CloudFormationを構築する前に準備しておく事
* BizRobo!の環境構築済みのAMI
* VPC
    * IGWの設定
* サブネット
    * ルートテーブルの設定
* セキュリティグループ


## やってみる
実際に構築したコードは以下に記します。
``` yaml
AWSTemplateFormatVersion: 2010-09-09
Description: BizRobo!v11.3 test instance

Parameters:
  ExistingVpcId:
    Type: AWS::EC2::VPC::Id
    Description: 利用するvpcID
    
  ExistingSubnetId:
    Type: AWS::EC2::Subnet::Id
    Description: 利用するsubnetID

  ExistingSecurityGroupId:
    Type: AWS::EC2::SecurityGroup::Id
    Description: 利用するsgID

Resources:
  MyEIP:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc

  MyNetworkInterface:
    Type: AWS::EC2::NetworkInterface
    Properties:
      SubnetId: !Ref ExistingSubnetId
      GroupSet:
        - !Ref ExistingSecurityGroupId
      Tags:
        - Key: Name
          Value: v11.3_testserver_network_interface

  MyInstance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: 利用するamiID
      InstanceType: r5a.large(タイプは用途に応じて)
      NetworkInterfaces:
        - NetworkInterfaceId: !Ref MyNetworkInterface
          DeviceIndex: 0
      Tags:
        - Key: Name
          Value: v11.3_testserver
        - Key: Used
          Value: unknown
        - Key: Product
          Value: test
        - Key: EndDate
          Value: unknown
        - Key: Team
          Value: unknown
```


~余談~
プログラミング経験が浅いのでChatGPTに問いかけて大枠の構成を作成してもらい、細かい修正を筆者が行いました。
ざっくりした問いかけである程度作成してもらえるので、プログラミングの勉強時間が削減できていいですね！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124412/186d2e12-83be-cdbe-541c-6bf0ecb914bb.png)



## 振り返り
VPC・サブネット・セキュリティグループを固定に設定したかったのですが、既存のものはパラメーターからしか設定できないようです。
運用オペレーションでカバーできますが、本当は固定にしたいなと思います。

AMIは固定値にしていますが、パラメータで選択するようにして事前に複数バージョン用意しておけば対応の幅が広がる気がします。
また、特定のサブネットにあるインスタンスを自動停止する設定をしておけば不要なコストがかかりっぱなしになるリスクも下げれられると思います。([こちらの記事](https://qiita.com/CatOnTheLegs/items/907266d4d08a759411c0)で記述します)

## おわりに
ある程度要件が似たような環境構築をする際はCloudFormationを利用すると便利だと感じました。
環境構築がシンプルで容易になるように模索していきたいと思います。
Datadogで案外大事なケースを踏んで少し監視の改善ができた話し

ジャーニーマン( @beajourneyman )です。

Datadogで案外大事なケースを踏んで、大事故にはならずに対処した経験から、監視文字列の基本的なルールについて備忘録を残します。

# 結論、文字列はセグメント化されて認識されているので文字列のまとまりを意識する必要がある

監視したい文字列と監視文字列の塊として認知されている文字列の差異。

```
Sabroismale
```
[Sabro]で検索したくてもできない。[Sabroismale]で設定する。

```
Sabro_is_male
```
[Sabro]で検索したくてもできない。[Sabro_is_male]で設定する。

```
Sabro:is_male
```

こちらはどうだろう。こちらも [Sabro]で検索したくてもできない。[Sabro:is_male]で設定する。

セグメント化の詳細は以下に詳しいので紹介します。[Sabro.com]も同じく[Sabro]では検索できません。

http://unicode.org/reports/tr29/

# 経緯と対応

## もしかして検知されていない？

今回3つ目のパターンの[is_male]に相当する監視文字列を設定していましたが、検知されませんでした。たまたま、利用サービスのレコード生成ルール刷新という大型アップデートが順次ローンチされたタイミングで不測の事態に構えていたため、早期検知できました。

```
Sabro:is_male
```

社内の監視チームに即エスカレーションして、調査をしてもらいました。

> 確認したところ、文字列の設定はされているものの想定通りの動作をしていない状態でした。文字列を[Sabro:is_male]に変更した場合、今回のログが想定通り検知されることを確認しました。

## 根本原因の究明

一旦の暫定対応ができたので、恒久対応に向けてサポートへの問合せをしてもらいました。

>うまく機能しなかった原因は、Datadogの仕様として文字を特定の条件で単語としてグループ化(セグメント化)しいるためです。今回の例ですと[Sabro:is_male]でグループ化されており、こちらが文字列として最小単位となっているため[Sabro:is_male]では検索ヒットしますが[is_male]では検索ヒットしないとのことでした。

その時に提示されたのが、前述の「[UNICODE TEXT SEGMENTATION](#retrogstudy)」のドキュメントでした。

## 今後に向けて

監視チームと協議して、ヒアリングシートのひな型に今回の件で明らかになった仕様を例示つきで記載いただくコトになりました。以下趣旨の内容です。

>＜文字の区切り単位について＞
検索文字列を検索する際、ログメッセージを一定の区切りによって分割し、その中から検索文字列に一致するものがあるかを検索します。
可能な限りスペースなどで区切られた文字列で検索文字列を指定することを推奨いたします。
例)
・英字+記号の集合は1区切りとして扱う
例) ログメッセージ"Sabro.com"は検索文字列"Sabro"で検索不可


# まとめ

* Datadogの検索文字列は一定の区切り(セグメント)によって分割されて1単位として認識されている。
* 英字+記号の集合は1区切りとして扱われるるので、記号の前後の文字列では検索できない。
* 暫定対応で対処できてもそのままにせず、原因を突き止めると全体の改善につながる。

みなさん、日々の運用おつかれさまです。適切な監視で事故ない運用をしましょう！！

以上です。
【個人事業】スタートアップする時に選定した事をまとめてみた

# はじめに

個人事業主になった妻からの相談があり2年前に作成した内容になります
どこにもまとめておらずどうやってつくったのかもわからなくなっていたため、記憶を頼りにまとめていこうと思います。

## まとめる内容

- ドメイン取得・管理
- 人が多くなったときの組織管理、共有方法
- サイトを公開するまで
    - お問い合わせフォーム
- メールの受信・送信

今回は、どういう要件があって、何を選定したかをまとめてみようと思います

# 要件

- スタートアップ段階のため費用は、できればかけたくない
- 事業を説明するサイトがほしい
- お問い合わせを受け取れるフォームがほしい
- ドメインは、独自ドメインがいい

固定費用をなるべく抑えたい気持ちは理解できるので、費用を抑えながら今後の展開も視野にいれて作りました

## ドメインの取得と管理

ドメイン管理は、『ムームードメイン』にしました
この時にGoogleもドメイン管理しているのを知っていたら`Google Domains`を利用してたと思います。
※別会社に譲渡したので、利用しなくてよかったかも

固定費用として年額かかる事を **承認** してもらいました

## 組織管理、共有方法

クラウドサービスは使ったほうがいいと思ったので、元々会社でよく利用しているAWSにするかGoogleにするかで悩みました

- 組織っぽくアカウント管理する
    - AWS: Organization
    - Google: Cloud Identity
- 共有する
    - AWS: S3? ぱっと思いつきませんでした
    - Google: Google Workspace（ドライブ、Meetなど）
- サイトを公開したい
    - AWS: EC2, S3, CloudFront
    - Google: GAE, GCE, GCS

今は1人でやっている事業ですが従業員が増えた場合に、情報共有が簡単にできたりとかしたいだろうなと思い **Google** にすることにしました。
（※すでにGoogleサービスのドライブ、スプレッドシート、Meetに慣れていたというのはあります）

### Google Workspace

https://workspace.google.co.jp/intl/ja/features/

**費用 ¥680 JPY / 月**
いきなり年間定期コストがかかるのは大変だということで一旦諦めました。
人が増えた時に再検討しようと思います

### Google Cloud Identity

https://cloud.google.com/identity?hl=ja

> Cloud Identity は IDaaS（Identity as a Service）ソリューションであり、企業向けモバイル管理（EMM）サービスです。
> Google Workspace で利用できる ID サービスとエンドポイント管理をスタンドアロン型のサービスとして提供します。
> Cloud Identity を利用することで、管理者は Google 管理コンソールからユーザー、アプリ、デバイスを一元管理できます。
> https://support.google.com/cloudidentity/answer/7319251?hl=ja

組織のように独自ドメインで、アカウント管理ができるのと無料だったので採用しました。
（※サイトの公開場所をGoogleCloudPlatformにしようと思っていたのも採用した一つです）

## サイト公開

動的な部分はない事を確認して、静的ファイルとCDNの組み合わせでいこうと思いました
`Cloudflare`と`GCS`の組み合わせで作成

固定費用としてアクセス数によって変動することを **承認** してもらいました

## お問い合わせフォーム

当初、サイトに埋め込みたいと言われて・・・心の中で「動的やん」って思いながら何か解決方法がないか探しました

その時に見つけたのが以下のサービスで無料でつかえます

https://getform.io/

ただ運用して現在は、Googleフォームに落ち着いています
理由として、フォーム内容を自由に変更できるのと、集計が取れるからのようです

## メールの受信・送信

メールについてはGメールが利用したかったのですが、受信方法がわからずに諦めました
で、格安のサービスないかなとおもって探してさくらインターネットを見つけました

https://rs.sakura.ad.jp/mail/

12ヶ月一括： 1,048円で利用できます

固定費用として年額かかる事を **承認** してもらいました


# おわりに

今回は、現状の構成の洗い出しと選定について思い出してかきました

現在費用としては、年額を除けば、20円/月くらいで運用できています

サイト公開まわりのことを次回まとめようと思います
複数のカタログの共通項を高速探索

list_A, list_B の共通する部分のインデックスを探すのは、for 文を使うより、以下の方が早い。

```python
both = set(list_A).intersection(list_B)

indices_A = [list_A.index(x) for x in both]
indices_B = [list_B.index(x) for x in both]
```
https://stackoverflow.com/questions/51171314/find-indexes-of-common-items-in-two-python-lists


これをもとに、２つのtableから共通項を高速に取り出すことができる。

```python 
# list_sid_APOGEE  -- データA
# list_sid_table_i -- データB

table_i = Table.read(finelame_i)
    
list_sid_table_i = list(table_i['sid'].data)

both = set(list_sid_table_i).intersection(list_sid_APOGEE)

indices_table_i      = [list_sid_table_i.index(x) for x in both]
#indices_table_APOGEE = [list_sid_APOGEE. index(x) for x in both]

table_i = table_i[indices_table_i]

```

次は、動くけれど遅いやり方：
```python
# list_sid_APOGEE  -- データA
# list_sid_table_i -- データB

table_i = Table.read(finelame_i)
    
list_sid_table_i = list(table_i['sid'].data)

filter_sid = [ sid in list_sid_APOGEE for sid in (table_i['sid']) ]
table_i = table_i[filter_sid]

```
チーム開発未経験の大学3年生がハッカソンに参加した感想

# 初ハッカソンで初開発
今回初めてハッカソンに参加しました。記事は初心者ですが、初心者がハッカソンに参加した感想を書こうと思います。

## ハッカソン
今回、サポーターズが主催している技育Campのマンスリーハッカソンに参加しました。先に感想をいうと、大学１年の頃に参加しとけばよかったと思うほど、充実しているものでした。


## 概要
期間は土日の二日間でオンラインで行われました。事前開発は１週間前からありました。テーマは自由でした。僕は即席チームで参加しました。３０チームある中で即席チームは４チームでした。
僕のチームは三人でした。

### チームメンバーの概要
・自分（学部3年）
php:udemy1年独学
python；3か月ほど長期インターン

・大学4年生
python:研究で使用
HTML：使える

・大学院1年
python:研究で使用
HTML：できる

３人とも開発経験は初めてでした。即席チームということもあり事前開発は行わず、１日目の午前中に作るものを決めました。
### 何故作ろうとおもったか
私たちのチームは社会を笑顔にするものを作ると決めました。
そこで、今はやっているchatbotと今大人気のちいかわを使い、開発を進めることにしました。そして誰もが使いやすいように、LINEに実装しました。

### 実際に作ったもの

作ったものはちいかわ構文を使った、chatbotです。
これは、感情分析を用いた、ネガティブポジティブ判定を行うchatbot。
#### 感情分析

```mermaid
graph TB
    形態素解析 --> 単語の取りだし --> 日本語評価極性辞書==> ネガティブポジティブ判定
```

まずメッセージが送られると、形態素解析を実行し名詞、副詞に分けて単語を取り出す。そして、日本語極性辞書の読み込み、
単語をネガティブポジティブ判定をし、それに合わせた返答をしてくれるChatbotです。

![_MXK3q5hl0a14EgfwzEO9Y5BjyTIpGXWrQJ_n_FA9OoqWd2IVfzIQhSDVpCcPPa1rkqckyWZ7YXNVIeD1F6FWxu95-lJTYUcoh36KyXIy6B_MAtt9GWKc2T2ZP4RkEeIf5GQEQh7yulECQgiwy2egxtk5A=nw.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3087507/879ff3db-e323-c1c1-239c-2a4d6bb285a6.png)



### 感情分析とは

顔の表情、声のトーン、文書など情報から、どのような感情が含まれているのかを分析するものです。ちいかわbotでは、文書を使った感情分析のみです。今回は東北大学の乾・鈴木研究室の「日本語評価極性辞書」を使いました。
具体的には、取り出された単語に対してネガティブなのか、ポジティブなのか判定する仕組みです。


## 開発過程
まず１日目の午前になにを開発するのか決めました。全員がpythonの開発経験がないので、ちゃんと実装まで行くことができるのか心配でした。まずフロントエンド側とバックエンド側で別れて開発を行いました。僕は主にフロントエンドを担当しました。LINEに実装する際はバグが出たりと実装するのが、いちばん時間がかかりました。苦労しました。即席チームということもあって徹夜で開発を行いました。初めてのチーム開発でしたがすごく楽しかったです。


## 発表
賞の受賞もあったので、重要な発表でした。プレゼンの時間は２分だったので、いかに伝えたいことを２分で伝えきるか話し合いました。googleスライドで作成しました。

### 他のチームの発表
他のチームの発表はレベルがすごく高くてびっくりしました。スライドもみんな凝っていました。発表にも慣れていたので、もっと参加してレベルをあげたいと思わされました。
 
### 感想
正直チーム開発が不安でしかなかったです。でも、いざチーム開発をしてみるとすごく楽しかったです。
そして、すごく成長できたと思います。大学一年から参加していれば、今とてつもないスキルが身についていたのではと、もっと早く参加していればよかったと思わされるくらい有意義な時間でした！
React NativeでキーボードのReturn Keyタイプを制御する


開発環境:
- React Native
- Expo


React NativeとExpoを使用してモバイルアプリを開発する際に、キーボードのリターンキー（またはエンターキー）の見た目と動作を制御する方法について紹介します。具体的には、キーボードの「改行」を「完了」に表示を置き換える方法と、リターンキーが押されたときの動作を設定する方法を解説します。

## リターンキーの表示を制御する

React Nativeの`TextInput`コンポーネントでは、`returnKeyType`プロパティを使ってリターンキーの見た目を変更することが可能です。以下に具体的なコードを示します。

```jsx
import React from 'react';
import { TextInput } from 'react-native';

const App = () => {
  return (
    <TextInput
      returnKeyType="done"
    />
  );
};

export default App;
```

このコードでは、`returnKeyType`に`done`を指定しています。この結果、キーボードのリターンキーの表示が「改行」から「完了」に変わります。

## `returnKeyType`の他の値

`returnKeyType`プロパティには、他にも以下のような値を指定することが可能です。

- `default`: プラットフォームのデフォルトの見た目。日本語環境では通常「リターン」と表示されます。
- `go`: 日本語環境では「次へ」と表示されます。フォームを次に進めるために使用します。
- `next`: 日本語環境では「次へ」と表示されます。次の入力フィールドに移動するために使用します。
- `search`: 日本語環境では「検索」と表示されます。検索フォームを送信するために使用します。
- `send`: 日本語環境では「送信」と表示されます。メッセージなどを送信するために使用します。
- `done`: 日本語環境では「完了」と表示されます。全ての入力が終わったことを示すために使用します。

## リターンキーが押されたときの動作を制御する

`returnKeyType`でリターンキーの見た目を制御した上で、リターンキーが押されたときの動作を制御するには`onSubmitEditing`イベントハンドラを使用します。

```jsx
import React from 'react';
import { TextInput, Alert } from 'react-native';

const App = () => {
  return (
    <TextInput
      returnKeyType="done"
      onSubmitEditing={() => Alert.alert('Submit Button Pressed')}
    />
  );
};

export default App;
```

上記の例では、リターンキーが押されたときに`Alert.alert('Submit Button Pressed')`が実行され、アラートダイアログが表示されます。

## まとめ

React Nativeでは、`returnKeyType`プロパティと`onSubmitEditing`イベントハンドラを使用して、キーボードのリターンキーの見た目と動作を簡単に制御することができます。これにより、アプリケーションのユーザビリティを向上させることができます。特定の言語環境、この場合は日本語環境に応じた表示と動作を行いたい場合にも役立ちます。
Azure App Service で WordPress を構築する

ウェブサイトを作る必要が出たので App Service で構築しました。

[すでに持っている(がびっくりするほど何も書いていない)ブログ](https://olivia.jp/wordpress/ "びあろぐ")も Azure 上で動く WordPress ですが、こちらは VM (Ubuntu) に WordPress を普通にインストールしたものです。
元 Linux 系エンジニアなので Linux のお勉強も兼ねています。~~というのは建前で、当時 Azure なんもわからなすぎて VM につっこみました。~~

今回は App Service で構築してみます。過去に Qiita で書いている方もいますが、記事が古くなっているようなので需要はあると信じています。

# Marketplace からリソースを作成

まずは [WordPress] で検索しました。WordPress だけで 120 もあるようです。
今回は App Service を使いたいのでこちらをクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335429/68cbd6e9-5b21-3efe-2890-ed869d13a460.png)

普段通り、サブスクリプション・リソースグループ・リージョンを指定します。
[ホスティングの詳細] の [名前] には、一意の文字列を入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335429/6609f37a-9c0e-155f-85b8-c552a8f6b998.png)

今回本番環境ですが、ほとんどアクセスされないことが想定されるため Basic を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335429/8a0ff32b-8504-29cc-4ded-b645dda61264.png)

WordPress に必要な情報を入力。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335429/c40861f7-eec4-2dfa-e838-85bb4fd57660.png)

今回は Blob Storage を使用します。
Virtual Network は事前に作成したものを選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335429/e5a291ee-10b7-0a81-f744-4b552a00ff3a.png)

内容を確認して作成。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335429/4a0cc696-0dd7-2c7c-febe-9f4afc25ec3d.png)

デプロイ完了！
作成後放置していましたが、7 分程度かかったようです。
ポチって押したらバッて作ってくれて超便利～(語彙力）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335429/bd69bd6d-f781-4b6f-da0f-4e930c36fe83.png)

# カスタムドメインを設定

できたリソースがこちら。
[既定のドメイン] から URL をクリックするともう WordPress ができている。
便利かよ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335429/ebe92f4e-a222-a203-9ebe-cfeed49ef979.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335429/8eadfdf7-51a6-4fbd-6158-a2bc994f586e.png)

今回はカスタムドメインを使いたいので [カスタム ドメイン] > [カスタム ドメインの追加] をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335429/645545aa-ba8c-5492-0146-1308688e82f2.png)

今回はお名前ドットコムで取得したドメインを使用するので、[その他すべてのドメイン サービス] を選択。
カスタムドメインを入力すると、[ドメインの検証] が表示される。
このホスト名をお名前ドットコムに登録し、[検証] をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335429/8b7e4a01-15cc-1be4-e688-3260fb0c1715.png)

[検証に合格しました。] と表示されれば OK
[追加] をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335429/df717239-f2cf-5a1d-c4dc-fb49766a0704.png)

登録できた。上段がカスタムドメイン。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335429/b100da43-7298-b499-73e5-9e2167b30abc.png)

# WordPress を使う

アクセスしてみた。ひょ～～～～簡単！！
普段は会社様の社内インフラとかやってるのでこういうの感動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335429/df7fadf2-829d-5b34-8558-dd5585df0d82.png)

# さいごに
思ったより 100 倍くらい簡単でした。
WordPress のいい感じのテーマあったら教えてください。クレジット消せるやつがいいです。
完全理解とかのレベルにすらなってないです。
【CSS Tips】保守性のために、なるべく子孫セレクターなどの結合子を用いたセレクター使わない

## これは何

CSSでなるべく子孫セレクターなどの結合子を用いたセレクター使わない方が良い理由を整理しました。

## 結合子とは

` `や`>`でセレクターを繋ぐことで、特定のタグやクラスの子要素や後にくる要素にスタイルを当てることができます。

<details><summary>結合子の解説</summary><div>

### 子孫結合子

1つ目の要素の子孫要素に2つ目の要素があるとき

```css
.container .button {
  background: #55c500;
}
```

### 子結合子

1つ目の要素の直接の子要素に2つ目の要素があるとき

```css
.container > .button {
  background: #55c500;
}
```

### 隣接兄弟結合子

1つ目の要素のすぐ後に2つ目の要素があるとき

```css
.container + .button {
  background: #55c500;
}
```

### 一般兄弟結合子

1つ目の要素の後に2つ目の要素があるとき

```css
.container ~ .button {
  background: #55c500;
}
```

</div></details>

## 結合子を用いたセレクターを使わない方が良い理由

### 保守性が下がるため

結合子を用いたセレクターは、HTMLの構造に大きく影響されます。

タグを追加したり一部を削除したり並べ替えをしたりした際に、意図しないスタイルの崩れを引き起こしてしまいます。

特に子結合子を用いている場合、親とこの間に一つ別のタグを挟むだけでスタイルが効かなくなってしまいます。

特に複数人で開発している場合や開発の規模が大きい場合、HTMLの変更によってスタイル崩れを起こしてしまう可能性が上がります。

このため、なるべく結合子を使わないことや、使う場合も子結合子よりも子孫結合子を使う・HTML側にコメントを残す影響が出にくい形で使う必要があります。

### 詳細度が上がるため

結合子を用いるとセレクターの詳細度が上がります。

セレクターの詳細度があがると、予期せず他の指定を上書きしたり逆に他の指定で上書きすることが難しくなったりします。

このため、コードを書きやすくするためになるべく詳細度は低くする方がよく、結合子を用いる必要のない場合は使用しない方が良いです。

### パフォーマンスが低下するため

セレクターが複雑になると、セレクターを解析する時間が増加します。
また、ブラウザはCSSセレクターを右から左に読み取るため、`.list > a`などのようにすると、ページ全体の`aタグ`を確認しそれらの子孫セレクタを解析します。

これらの理由から、できるだけ結合子を使わずにクラスセレクターなどの単純なセレクターを選ぶことで、保守性やパフォーマンス向上に貢献することができます。
windowsでiverilog その137

# 概要　
windowsでiverilogやってみた。
練習問題やってみた。

# 練習問題
ナップザック問題を解け。

# サンプルコード

```


module nap(input clk, input rst, output [7:0] out);
	reg [7:0] dp[0:10];
	reg [7:0] va[0:6];
	reg [7:0] wt[0:6];
	assign out = dp[8];
	integer i,
		j;
	always @(posedge clk or negedge rst)
	begin
		if (!rst)
		begin
			va[0] <= 3; wt[0] <= 2;
			va[1] <= 2; wt[1] <= 1;
			va[2] <= 6; wt[2] <= 3;
			va[3] <= 1; wt[3] <= 2;
			va[4] <= 3; wt[4] <= 1;
			va[5] <= 85; wt[5] <= 5;
			dp[0] <= 0;
			dp[1] <= 0;
			dp[2] <= 0;
			dp[3] <= 0;
			dp[4] <= 0;
			dp[5] <= 0;
			dp[6] <= 0;
			dp[7] <= 0;
			dp[8] <= 0;
			dp[9] <= 0;
		end
		else
		begin
			for (i = 0; i < 6; i = i + 1)
			begin
				for (j = 0; j <= 8; j = j + 1)
				begin
					if (j >= wt[i])
					begin
						if (dp[j] < (dp[j - wt[i]] + va[i]))
						begin
							dp[j] = dp[j - wt[i]] + va[i];
						end
					end
				end
			end
		end
	end
endmodule

module test();
	reg clk;
	reg rst;
	wire [7:0] out;
	nap u(.clk(clk), .rst(rst), .out(out));
	initial
	begin
		$monitor("%d", out);
		clk = 0;
		rst = 1;
		#1
			rst = 0;
		#1
			rst = 1;
		#10
			$finish;
	end
	always
	begin
		#5
			clk = 1;
		#5
			clk = 0;
	end
endmodule

```

# 実行結果

```
>vvp a.out
  x
  0
 94
nap1.v:74: $finish called at 12 (1s)

```

以上。
掲示板の検索機能

最近掲示板の検索機能の実装方法を学んだのでこちらにアウトプットしておきます。
# 検索機能の実装
検索バーを`ransack`というgemを使って実装していきます。
Ransackはデータベースから特定の条件に一致するレコードを探すための検索クエリを生成する機能を提供します。

#### 手順
①`ransack`のインストール
②コントローラーの編集
③viewの編集
④国際化(任意)

# ①`ransack`のインストール
Gemfileに以下のコードを記入
```ruby:Gemfile
gem 'ransack'
```
```
$ bundle install
```

# ②コントローラーの編集
```ruby:boards_controller.rb
#編集前
def index
@boards = Board.all.includes(:user).order(created_at: :desc).page(params[:page])
end
↓↓
def index
    @q = Board.ransack(params[:q])
    @boards = @q.result(distinct: true).includes(:user).order(created_at: :desc).page(params[:page])
  end
```
URLパラメータ`params[:q]`（これが検索条件）を使用してBoardモデルに対する検索クエリを生成しています。
検索クエリ`@q.result(distinct: true)`を実行し、その結果を取得しています。また、その結果から重複するレコードを除外するように指定（distinct: true）しています。
※掲示板Aに対して「rails1」というコメントと「rails2」というコメントがある場合、この`distinct: true`を入れないと、railsでコメントを検索した場合に、掲示板Aが2回取得されて検索結果が2件になってしまったり、エラーの原因にもなります。
# ④viewの編集
検索バーの実装はできている程で進めていきます。
パーシャルを作成します
```ruby :views/boards/_search.html.rb
<form>
  <%= search_form_for @q do |f| %>
    <div class="input-group mb-3">
      <%= f.search_field :title_or_body_cont, class: "form-control", placeholder: "検索ワード" %>
      <div class="input-group-append">
        <%= f.submit '検索', class: 'btn btn-primary' %>
      </div>
    <% end %>
  </div>
</form>
```
`search_form_for`というransackが提供するフォームヘルパーを使ってフォームを作成。
※検索クエリのように一貫性が保たれる変数はインスタンス変数@qとしてパーシャルに渡し、特定の状況に依存する変数はローカル変数qとしてパーシャルに渡すことで、パーシャルの再利用性を高めることができます。

```ruby :app/views/boards/index.html.erb
<%= render 'search_form', url: boards_path %>
```
これで掲示板一覧で検索機能を実装することができました。
React Hook FormとZodを活用した複数フィールドのバリデーションチェック

今回は、React Hook FormとZodを活用して、複数のフォームフィールドのバリデーションを効率的に行う方法について詳しく解説します。

# 開発環境
- react-hook-form: v7.15.4
- zod: v3.11.6

# はじめに
React Hook Formは、Reactでのフォームバリデーションを効率的に行うためのライブラリです。React Hook Formを使用することで、フォームフィールドの値の取得、バリデーション、エラーメッセージの表示などを簡単に実装できます。

一方、ZodはTypeScript向けのバリデーションライブラリで、簡単にバリデーションスキーマを定義でき、カスタムバリデーションもサポートしています。React Hook FormとZodを組み合わせることで、簡潔で理解しやすいコードで、複雑なバリデーションを含むフォームを実装することができます。

# Zodでの一つのフィールドのバリデーション
まず、一つのフィールドに対するバリデーションをZodを使ってどのように作成するか見てみましょう。ここでは、`firstName`というフィールドが空文字でないことを確認するバリデーションを設定しています。

```javascript
import { z } from 'zod';

export const profileSchema = z
    .object({
        firstName: z.string().nonempty('名は入力必須項目です'),
        // 他のフィールド...
    });
```

# Zodでの複数フィールドにまたがるバリデーション
一つのフィールドに対するバリデーションができたら、次は複数フィールドにまたがるバリデーションを設定してみましょう。以下の例では、同じく`lastName`にもバリデーションを設定し、さらに`firstName`と`lastName`のどちらかが空でないことを確認するバリデーションを追加します。

```javascript
export const profileSchema = z
    .object({
        lastName: z.string().nonempty('姓は入力必須項目です'),
        firstName: z.string().nonempty('名は入力必須項目です'),
        // 他のフィールド...
    })
    .refine((data) => data.lastName !== '' || data.firstName !== '', {
        path: ['lastName', 'firstName'],
        message: '姓と名のどちらか一つは入力してください'
    });
```

# React Hook Formでのエラーメッセージの表示
Zodで定義したバリデーションスキーマをReact Hook Formに組み込み、エラーメッセージを表示する方法を見てみましょう。

まず、`useForm`フックから得られる`register`と`errors`を利用します。`register`はフォームフィールドをReact Hook Formに登録するための関数で、`errors`は各フィールドのエラー情報を含むオブジェクトです。

次に、各フォームフィールドに`register`を割り当て、エラーがある場合は`errors`から対応するエラーメッセージを表示します。

```jsx
import { useForm } from "react-hook-form";
import { profileSchema } from "./validation";

const { register, handleSubmit, formState: { errors } } = useForm({
    resolver: zodResolver(profileSchema)
});

return (
    <form onSubmit={handleSubmit(onSubmit)}>
        <input {...register("firstName")} />
        {errors.firstName && <p>{errors.firstName.message}</p>}

        <input {...register("lastName")} />
        {errors.lastName && <p>{errors.lastName.message}</p>}
        
        {/* 他のフィールド... */}

        <input type="submit" />
    </form>
);
```

上記のコードにより、各フォームフィールドがバリデーションに失敗した場合、対応するエラーメッセージが表示されます。

以上が、React Hook FormとZodを用いて複数のフィールドのバリデーションチェックを行う方法になります。これらのライブラリを組み合わせることで、フォームのバリデーションを効率的に行うことが可能となります。ぜひお試しください。
git cryptをやめるときにハマったこと

## はじめに
git cryptで暗号化していたファイルを平文に戻し、GitHubの画面上でレビューできる状態にするまでに時間がかかってしまったので、経緯を共有します

## 経緯
- git cryptという技術を使って、秘匿化したい環境変数ファイルを暗号化し管理していたが、別の管理方法に移行することにした
- 一部の環境変数は秘匿化の必要がなかったので、git cryptで暗号化するのをやめ、平文の環境変数ファイルとして残す方針にした

## 作業環境
- VSCode
- GitHub

## 行った作業

1. `git crypt unlock` を実行し、ローカル上の環境変数ファイルを復号化
    - この時点で、ローカル(VSCode)では平文の状態になっている
2. 環境変数ファイルを更新後、 `git add / commit / push`
    - 秘匿化の必要がない情報だけ残した
    - この時点で、githubのプルリクの差分画面には、バイナリファイル(=暗号化された状態)が表示されている
3.  `.gitattributes` ファイルを `git add / commit / push`
    - `.gitattributes` ファイルでgit cryptの対象を管理している
    - 今回は環境変数ファイルをgit cryptの管理対象外にするため、記述を削除した

ここまで行って、プルリクの差分画面に平文の環境変数ファイルが表示されるかと思ったが、バイナリファイル(=暗号化された状態)のままだった

## 問題解決のためにやったこと
- 平文になったファイルをpushする
    - 作業3の後、VSCode上で環境変数ファイルに未保存のマークは出ていなかった
    - しかし、試しに `ctrl + s` してみると環境変数ファイルが変更扱いになった
    - → `git add / commit / push`

ただ、これでもGitHubのプルリクの差分画面はバイナリファイルのままだった

### GitHub上での確認の仕方
- 結局、プルリクの差分画面で確認する方法は分からず
- プルリクの差分画面 > 対象ファイルの3点リーダー > ` View File ` で中身を見ることによって、平文になっていることが確認できた

## 最後に
- 始めるときのドキュメントは多いけど、やめるときのドキュメントは意外と少ないですね
PCへのpytorch導入

python, pipの導入はすでに済。
今回はpytorchの導入をする必要があった。

https://pytorch.org/get-started/locally/

こちらのURLから、ターミナルにコマンドをコピペ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3517108/cfa181fd-72b8-0953-b448-a65df1dafbc8.png)


完了後、pycharmにて、pytorchが使用可能かどうかを確認。

```
import torch
```

エラーが出現しなくなったので、一旦こちらで導入終了。