OmniAICreator/Qiita-1.07M huggingface dataset:
OpenAI APIでdavinciをファインチューニングしてみた。

OpenAI APIには簡単にファインチューニング出来る機能があるので、ファインチューニングしてみることにしました。
※この記事は連作の2/2です。※[前回はこちら](https://qiita.com/katsuki_ono/items/b5fcd458a70a24e73eee)

[前回](https://qiita.com/katsuki_ono/items/b5fcd458a70a24e73eee)作成したツールを用いて100程のデータを用意したので、こちらを用いてdavinciをファインチューニングします。(現在、ファインチューニング出来るモデルでdavinciが一番使いやすいため、davinciを使用しました。)

OpenAIのAPIのファインチューニングはOpenAIのサーバーで行われ、長期的に実行中にする必要はないので、今回はGoogle colabを使用します。

手順は、davinciをファインチューニングするだけです。

# davinciをファインチューニングする
まずdavinciをファインチューニングするデータをGoogle colabで使用するGoogleアカウントのドライブに保存します。

次にGoogle colabで新規ノートブックを開き、Google colabからGoogle ドライブにアクセスして、ファインチューニングするデータを読み込めるように以下の操作を行います。

ファイルを開く
写真の赤枠のマークを押す。
![ECEC3A64-9001-4920-BBB8-BB2D6042E2F0.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3287642/621e164a-9581-d55e-b1f2-700416311558.jpeg)

Googleドライブをマウントする
写真の赤枠のマークを押す。メニューが開いたら、ドライブに接続を押す。
![75EE7CC2-6328-4BFC-99DB-EE8025D72621.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3287642/0bf7e31c-6f23-1b30-b897-72924a71809b.jpeg)

次に、以下をインストールします。
```
!pip install --upgrade pip
!pip install setuptools wheel
!pip install openai
```

以下を実行してファインチューニングを行います。
実行前にコードに以下を入れてください。
openai_api_keyには、openaiのキー
ft_datasetには、ファインチューニングするデータのパスかID
ft_modelには、ファインチューニングするベースのモデル(2023年6月1日時点だと、ada, babbage, curie, davinci)
ft_filenameには、ファインチューニング後のモデル名の一部
```
# 入力事項
openai_api_key = "" # openaiのキー
ft_dataset = "" # ファインチューニングするデータのパスかID
ft_model = "" # ファインチューニングするベースのモデル(2023年6月1日時点だと、ada, babbage, curie, davinci)
ft_filename = "" # ファインチューニング後のモデル名の一部

# ファインチューニングを申し込む
!OPENAI_API_KEY={openai_api_key} openai api fine_tunes.create -t {ft_dataset} -m {ft_model} --suffix ft_filename
```

fine_tuned_modelが生成されるまで待ちます。生成までに数時間かかる場合があるようです。
以下のコードのyour-fine-tune-job-idに、先程の実行後に生成されたID(openai api fine_tunes.follow -iの後のft-からの部分)を入れて実行するとファインチューニング状況を確認出来ます。
```python
import openai

# openai_api_key = "" # openaiのキー

openai.api_key = openai_api_key

# ファインチューニング状況の確認
fine_tune = openai.FineTune.retrieve('your-fine-tune-job-id')
print(fine_tune)
```

以下を実行するとファインチューニングしたモデルのリストを確認出来ます。
```
# openai_api_key = "" # openaiのキー
!OPENAI_API_KEY={openai_api_key} openai api fine_tunes.list
```

fine_tuned_modelが生成されたらファインチューニングしたモデルを試してみます。
以下のコードに、fine_tuned_modelにはファインチューニングしたモデルと、textには任意のプロンプトを入れて実行します。
```python
import openai

# openai_api_key = "" # openaiのキー

fine_tuned_model = ""
text = ""

response = openai.Completion.create(
    model=fine_tuned_model,
    prompt=text,
    max_tokens=100
)

print(response.choices[0].text.strip())
```

元のモデルと違った返答が返ってきたら成功です！

※[以前、私が作成したトトというキャラクター](https://note.com/katsuki_ono/n/nb9362f4f10af)を学習したdavinciに、「トトとは？」と聞いたら、以下のような返答をしました。かなりイマイチですね。
![IMG_8289.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3287642/8340c0cd-e8be-cbdc-eb72-cc576a8009c0.jpeg)


# 最後に
davinciだとやっぱり微妙ですね。
ファインチューニングはそこそこコストもかかるので、GPT系のモデルで出来るようになったらまた試してみます。
また何か作ってみます。
フォームのトリガーで初心者が落ちた穴(Google Forms x GAS)

# 前置き

・とにかくForms回答で送られてくるデータをGASで捕まえたい！という方のための内容です。
・「GoogleFormsとSpreadSheet」で調べると諸先輩方の丁寧な解説が沢山出てきますので割愛し、その先をご説明します。
・変数と定型句を見分けやすいよう「わざとらしく」書きました
・作業環境は以下の通り※GoogleのUIは2023年5月末時点
# コンテナバインドの分岐点

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/803674/100fd7cd-a670-ddcf-8781-0fca83c601a1.png)
見た目がそっくりな2つの作業場所が存在します
・フォームのApps Script
・スプシのApps Script <-正解
こちらでコーディング&トリガー設定
フォームの回答なのに...
# テスト難しい...
普段は頼もしい2つのボタンが役に立ちませんでした。。。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/803674/2150a084-66af-6237-66d3-157d1486a79a.png)
毎回フォーム回答を送信しないとテストできない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/803674/041f745e-0c79-f4b8-8aa7-e6d33a3115b5.png)
# どれ使う？
    function myFunction(KOTAE) {
        //二次元配列なら
        const KAITOU_twoD = KOTAE.values
        //回答のみで設問は手に入らない
        
        //連想配列なら
        const KAITOU_dict = KOTAE.namedValues
        //設問：回答のセットで手に入る
        //namedvaluesはダメ <-Vは大文字！
        //なぜかオートコンプが効きません

        //テスト
        browser.msgbox()
        console.log() //<-コレ推奨です
        logger.log()
    }
要素の順番制御が難しい(後述)ため、設問とセットになっていない二次元配列は集計・処理ミスにつながりかねない

# Forms回答の怪
一方、連想配列(KAITOU_dict)の中身を見てみると

    {'タイムスタンプ': [ '2023/06/01 22:31:27' ],
     '質問１': [ 'オプション 1' ]}

キー：[値]が更に配列の入れ子状態なので扱いにくい...

      //連想配列を二次元配列に変換
      let KAITOU_twoD = [];
      for (var KOBETU in KAITOU_dict) {
        KAITOU_twoD.push([KOBETU, KAITOU_dict[key][0]]);
      }
      //設問＆回答セットの二次元配列を入手

# 不思議のダンジョンかよ
現場の要望に応えて設問を増やしてみました
   
    //連想配列(namedValues)の結果
    { '質問１': [ 'オプション 1' ],
      'タイムスタンプ': [ '2023/06/01 22:31:27' ],
      '質問3': [ 'オプション 1' ],
      '質問2': [ 'オプション 1' ] }
（どの設問をコピーして作ったかによって順番が変動）
＝増設の手間とコーディングの手間はトレードオフ関係
やりたい内容によって最適な対処方法は分岐しそうです


以上、初投稿の拙い文章で大変恐縮ですが最後までお読みいただきありがとうございました！
【python】 whisperライブラリのインストールからテストまで【自分用まとめ】

# 注意事項
この記事は自分用メモに公開していますが、書きかけもいいところです。
導入までてこずっているのもあって、無茶苦茶を書いてしまっていると思います。
追記するまで暖かい目で見守っていてください
導入を急いでいる人は、他の記事を参考にするか、ChatGPTに聞いてください......本当に申し訳ない

# はじめに
openAIが提供するライブラリでwhisperというものがあるらしい。
音声ファイルをテキストに文字起こししてくれるようで、使えるならばうれしい。
しかもMITライセンスで無料。試してみるしかない。

# 導入手順

## ffmpegのインストール

1. 以下のサイトから使用環境に合わせてインストールファイルをダウンロード
https://ffmpeg.org/download.html


1. ダウンロードファイルを解凍し、任意のフォルダに移動させる
（例：C:\Users\ **hogefoo**\AppData\Local\Programs）


1. 環境変数の設定
Windowsキー　＋　pause breakキー　で設定を開く
システムの詳細設定＞環境変数＞**hogefoo**のユーザー環境変数＞新規(N)を開く
Pathにffmpegファイルのbinファイルのパスを新規追加
(例：C:\Users\ **hogegoo**\AppData\Local\Programs\ffmpeg-N-110972-gbaa9fccf8d-win64-gpl-shared\bin)

参考：ffmpegのインストール手順詳細
https://jp.videoproc.com/edit-convert/how-to-download-and-install-ffmpeg.htm


## python側　パッケージのインストール
　pip で以下のパッケージをインストールする。
Whisperが対応しているのはPython 3.8～3.10らしいので注意してほしい。
加えて、既存環境にあるライブラリとの依存関係の問題があると動作しない可能性が高いし、
venvで新しい仮想環境を作成してからインストールすることをお勧めする。（自分は後悔した）

~~~powershell
pip install - U openai-whisper
pip install ffmpeg
~~~

......実はここでつまずいた。
内容は以下に類似していて、テストコード実行時にFileNotFoundError と怒られた
エラーメッセージをみるとmel = log_mel_spectrogram(audio)で怒られているみたい......
https://teratail.com/questions/b36fxex20hc3nx

いやでも、ffmpegインストールしたしなと思って、PCを再起動させたら普通に起動した。
~~（そんなことある？）~~
途中でいろいろとネットにある問題解決方法を試しまくっていたので、再起動が解決策かは要検証事項。
後で新しい仮想環境を作成してしっかり調べるつもり。

# 文字起こしのテストコード
以下はtest.mp3をtext.txtに文字起こしするコード
これだけのコードで文字起しができちゃうなんで、すげえ！
しかもタダ。OpenAI万歳！

~~~python

import whisper

# モデルの読み出し（今回はsmallモデルを利用）
model = whisper.load_model("small")

# inputfile,outputfileの定義
input_file = r"C:\Users\*hogefoo*\Documents\test.mp3"
output_file = r"C:\Users\*hogefoo*\Documents\text.txt"

# print result
result = model.transcribe(input_file,verbose=True, language='ja')
print(result["text"])

# write txt file
with open(output_file, "w",encoding="utf_8") as f:
    f.write(result["text"])

~~~

# アウトプット例
今回読ませた音声ファイルは以下のサイトから拝借しております。
https://self-development.info/%E3%81%BB%E3%81%BC%E5%AE%8C%E7%92%A7%E3%81%AA%E6%96%87%E5%AD%97%E8%B5%B7%E3%81%93%E3%81%97%E3%81%8C%E3%81%A7%E3%81%8D%E3%82%8Bai%E9%9F%B3%E5%A3%B0%E8%AA%8D%E8%AD%98whisper%E3%81%AE%E3%82%A4%E3%83%B3/

音声の内容はこんな感じ

~~~
過去最強クラスの台風14号が近づいてきています。
九州南部、そして北部の皆さんを中心に防風、高波、高潮や大雨などに最大級の警戒をしてください
~~~


これを文字起こしした結果が以下の通り。
~~~
過去最強クラスの台風14号が近づいてきています九州南部、そして北部の皆さんを中心に防風、高並、高潮や大雨などに最大級の警戒をしてください
~~~
漢字が一部違うけど、全然読める！！！
自分のタイプミスより全然いいじゃんよ！！！

# 今後の展開
めんどうな議事録とか、whisperで文字に起こして、ChatGPTなりに要約させてみようと思っている。
というか、Pythonである程度文節ごとくらいに区切る処理はできるのでは？やれるならチャレンジする。
導入時のつまずきの原因も確認する。
EC2にローカルからファイルを転送する方法とEC2からダウンロードする方法も

ローカルからテスト用のファイルをEC2に転送したい時ってたびたびありますよね。

その方法を備忘録がてら残しておきたいと思います。

# 自己紹介
都内のDevOps系の企業でエンジニアをやっています。
主にAWSとTerraformを扱っております。
フルリモートで勤務しております。
大阪在住、年齢は27歳、趣味は古着屋巡りと映画鑑賞です。

# 本記事の内容
- SCPコマンドを使用してローカルからEC2に対してファイルをアップロードする方法
- SCPコマンドを使用してEC2からローカルにファイルをダウンロードする方法
- 初心者向けの内容です

# VPCの作成
VPCはこちら以下キャプチャの内容で作成します。
※設定内容は以下参照

![スクリーンショット 2023-06-01 23.28.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626370/1b739298-ef0a-f122-ae26-954752343ae4.png)

インターネットゲートウェイを作成してアタッチするのを忘れずに。

ルートテーブルも更新しておきます。

    
![スクリーンショット 2023-06-01 23.58.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626370/1d518297-c44f-4812-fd9b-766d37cdab9b.png)


# サブネットの作成
今回はパブリックサブネットのみ作成していきます。
※設定内容は以下参照

![スクリーンショット 2023-06-01 23.31.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626370/751b962b-7145-66e7-1fa0-8f3aac7abfd6.png)

# セキュリティグループの作成
セキュリティグループはSSHとHTTPSを許可しておきます。
※ポート22はマイIPにしているので隠してします
※アウトバンドルールはデフォルトにしています

![スクリーンショット 2023-06-01 23.44.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626370/add952ed-9cd8-d71a-70eb-58e19b37f698.png)

# EC2の作成
設定に関してはキャプチャ参照

※ネットワーク設定以外はデフォルト設定です

![スクリーンショット 2023-06-01 23.46.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626370/54d2272b-e795-097e-31ff-b6fc37dc6917.png)

![スクリーンショット 2023-06-01 23.47.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626370/d1dcef3f-1019-4c7b-4a9b-4a4ed84302e2.png)

![スクリーンショット 2023-06-01 23.48.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626370/65f42454-2c18-17d3-dc74-46720e00395b.png)


# EC2インスタンスへの接続確認

![スクリーンショット 2023-06-02 0.00.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626370/60a38958-3007-09aa-632b-050baa0dedcf.png)


無事接続できました。

# SCPコマンドを使用してファイル転送

デスクトップ上のテストファイルをSCPコマンドを使ってEC2へ転送

```
$desktop
 scp -i ~/.ssh/KeyPair.cer test.txt ec2-user@3.112.210.144:/home/ec2-user/
```


確認してみます。

![スクリーンショット 2023-06-02 0.12.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626370/548a390c-dd21-92ca-68c2-61be8b3e1ec4.png)


無事ファイル転送できていました。


ではEC2からローカルにダウンロードする場合はどうでしょう。

さきほどのコマンドの順序を逆にすればOKです。

```
scp -i .ssh/KeyPair.cer ec2-user@3.112.210.144:/home/ec2-user/test2.txt ~/Desktop
```

こちらのコマンドでできます。

# まとめ

### ローカル→EC2
```
scp -i [秘密鍵のパス] [アップするファイルのパス] [ユーザー名]@[パブリックIP]:[アップロード先のディレクトリパス]
```


### EC2→ローカル
```
scp -i [秘密鍵のパス] [ユーザー名]@[パブリックIP]:[アップロード元のファイルパス] [アップロード先のディレクトリパス] 
```

Qitaの記事にするまでもないと思いましたが何でも残しておくと後で備忘録として見返せるかなと思い記事にしました。

今後も引き続きアウトプット頑張っていきます。
Nutanix NGTのRHEL 9・Alma Linux 9・Rocky Linux 9へのインストール方法

# TL;DR
RHEL9はchkconfigパッケージをdnfでインストールすればインストールできるようになる
AlmaLinuxとRockyLinuxについては上記と共にISOをどこかにコピーし、『installer/linux/src/installer_factory.py』の34行目に、
『"almalinux" in distribution or』または
『"rocky linux" in distribution or』と書き足せばインストールできるようになる。

# 詳細
以下root権限で実行することを前提とする
RHEL9では標準でSysVinitがインストールされないようになったので、
まずこれをインストールしてあげる必要がある。
```
dnf install chkconfig 
```
RHELについては上記だけでインストーラーが正しく動作するので完了となる。

しかし、AlmaLinuxとRockeyLinuxについてはインストーラー自体に項目が存在しない。
とはいえRHEL9のクローンなので、項目さえ追加してあげれば正しく動作するので追加する。
任意の場所にISOの内容を丸ごとコピーし、
コピーしたディレクトリへ移動してから
```
vi installer/linux/src/installer_factory.py
```
を実行し、
34行目あたり(CentOSやRHELの部分)に、
```
"almalinux" in distribution or
```
```
"rocky linux" in distribution or
```
どちらかを追加で記入するとインストーラーが正しく動くようになる。

# 状況に応じて
今回当方で実施した際は使わなかった(以前に作成していた)が、
pythonコマンドが存在しないとエラーが表示された場合はpython3をwhichコマンドで検索し、
同ディレクトリにpython3にリンクしたシンボリックリンクをpythonとして作成してあげれば問題ない。

また、RHEL9の場合ISOからそのままインストーラーを実行すると思われるが、
umountできなくなってしまったことが1度だけ発生した。
その場合は
```
lsof <マウントディレクトリ>
kill <lsofで表示されたPID>
```
でプロセスをkillしてあげてlsof <マウントディレクトリ>で結果が何も表示されなくなればumountできる。

# 最後に
インストーラーが正常終了できた出力が表示されても心配になるかもしれない。
その場合は下記コマンドを実行してNGTがCVMと疎通できているか確認すると良い。

```
ncli vm list name="<(Prism上を参照)サーバー名>"
『id』欄の『::』の後の文字列を控える(マシンID)。

ncli ngt get vm-id=<マシンID>
『Communication Link Active : true』であればOK
```

以上、誰かの役に立てば幸いです。
Dockerコンテナを用いてSVNサーバを起動し、Windowsフォルダをマウント、ユーザーIDとパスワードも設定

# Dockerコンテナを用いてSVNサーバを起動し、WindowsフォルダをマウントしてユーザーIDとパスワードを設定する方法

CI/CDの環境構築などを試す際、手軽にリポジトリを立ち上げたくなります。
Windows WSL環境上のDockerで、Docker Hubからコンテナを入手して立ち上げると「立ち上げて遊んでポイ」が容易なのでいつもやっています、、、が、たまにしかやらないので、手順忘れがち。
ChatGPTさんに作文してもらった内容を備忘のため記載しておきます。

環境：
・Windows 10（WSL設定済み）
・Docker (WSL上で動作）

以下の手順で、Dockerコンテナを用いてSVNサーバを起動し、ユーザーIDとパスワードを設定します。また、WindowsのフォルダをDockerコンテナにマウントします。
※ここではサーバ―名を「suna-svn-server」、リポジトリ名を「new-repo」としています。

## 1. Dockerコンテナを起動する

Dockerコンテナ`garethflowers/svn-server`を起動します。また、Windowsのフォルダ（ここでは`C:\svn-server`）をコンテナの`/var/opt/svn`ディレクトリにマウントします。

```shell
docker run -d --name suna-svn-server -v /mnt/c/svn-server:/var/opt/svn -p 3690:3690 garethflowers/svn-server
```

## 2. 新しいリポジトリを作成する
新しいリポジトリnew-repoを作成します。
```
docker exec -it suna-svn-server svnadmin create /var/opt/svn/new-repo
```

## 3. Dockerコンテナのシェルを開く
```
docker exec -it suna-svn-server sh
```
これでDockerコンテナのシェルが開きます。

### 4. passwdファイルを作成（または編集）する
リポジトリのconfディレクトリに移動します。
```
cd /var/opt/svn/new-repo/conf
```
viを使ってpasswdファイルを作成（または編集）します。
```
vi passwd
```
iを押して挿入モードに入ります。これでファイルに入力できるようになります。
以下の内容をファイルに入力します：
```
[users]
username = password
```
usernameとpasswordは使用したいユーザー名とパスワードに置き換えてください。

ESCを押して挿入モードを終了します。
:wqを入力しEnterを押してファイルを保存してviを終了します。

## 5. svnserve.confファイルを編集する
同様に、svnserve.confファイルを編集します。
```
vi svnserve.conf
```
再度viのコマンドを使用して、以下の行をコメントアウト解除（または存在しない場合は追加）します：
```
password-db = passwd
```
これも保存してviを終了します。
※匿名アクセス用に「anon-access = read」「auth-access = write」を追加してもよいですが、あまりお勧めしません。

## 6. Dockerコンテナのシェルを終了する
exitを入力してEnterを押すと、Dockerコンテナのシェルを終了できます。

これで、new-repoという新しいリポジトリが作成され、ユーザーが設定されました。
Dockerコンテナ「suna-svn-server」を起動すれば、TortoiseSVNからはsvn://localhost:3690/new-repoのURLでこのリポジトリにアクセスできます。
yarn：一生インストールできない

# 事象
yarnを`npm install -g yarn`でインストールし、`yarn --version`で確認すると、下記エラーが出る。
```shell
-bash: yarn: command not found
// or
-zsh: yarn: command not found
```

以下を試したが、一向に治る気配がない。
- この記事の内容（https://bobbyhadz.com/blog/npm-command-not-found-yarn）
- この記事の内容（https://qiita.com/kana-e/items/1124f0da268eae8aac5b）



##  救世主現る
下記記事を見つける事ができて本当に救われました。。。
感謝しかないです、ありがとうございます。

原因は、**Node**だったようです。


https://yularis.com/nvm-permission-error/
【Java】新規SpringスタータープロジェクトおよびMavenの「SunCertPathBuilderException」エラー対応

# はじめに
前記事を会社で試そうとしたら、新規SpringスタータープロジェクトおよびMavenの「SunCertPathBuilderException: unable to find valid certification path to requested target」エラーにより四苦八苦したので対処法を書いておく。
証明書の設定をしたにも関わらずMavenのエラーを解消するまでに1日がかりだった。でも別のPCで試したら証明書だけであっさりエラーが解消された。
たぶん、最初にeclipseがJava 17を使用しているのに、Java 11で証明書を設定していたからかも。

https://qiita.com/yaju/items/8ddc1a9416c1ee84c37b

# 環境
* Windows 10 Pro
* Eclipse 2023
* Java 17
* Spring Boot 3.1.0
* Maven

## 環境変数JAVA_HOMEの設定
eclipse.iniを開きます。

```ini:eclipse.ini
-vm
C:/pleiades/2023-03/java/17/bin
```

環境変数画面の新規ボタンをクリックします。
「変数名」に「JAVA_HOME」を、「変数値」にeclipse.iniのvm値のbinを除いた「C:\pleiades\2023-03\java\17」を入力して下さい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/c1b6afe9-1d81-e9ac-a9ce-db3e1c476524.png)

# 新規Springスタータープロジェクトの場合
「利用可能なコンテンツがありません。」となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/90d86b8d-d442-4e6f-d12e-2a834a35fe40.png)

## 証明書のダウンロード
ブラウザで https://start.spring.io/ にアクセス

下記記事の証明書のダウンロードを参考にする。

1.URL左のロックアイコンをクリックする
2.「接続がセキュリティで保護されています」の証明書アイコン「証明書は有効です」をクリックする
3.詳細タブでエクスポートをクリック、ローカルの適当な場所にダウンロードする

https://qiita.com/sasaki_hir/items/72d309681a8215523cca

自分はダウンロードした証明書「_.spring.io.cer」を「C:¥temp」フォルダに保存した。

## キーストアに証明書を追加
コマンドプロンプトを起動し以下を実行

```bat
%JAVA_HOME%\bin\keytool -importcert -keystore "%JAVA_HOME%\lib\security\cacerts" -storepass changeit -file "C:¥temp¥_.spring.io.cer"
```

:::note
`alias`オプションを付けなかった場合、エイリアス名は`mykey`となります。
:::

「この証明書を信頼しますか。 [いいえ]: 」が表示されたら、「はい」と入力し実行

```
この証明書を信頼しますか。 [いいえ]:  はい
証明書がキーストアに追加されました
```

## 動作確認
新規Springスタータープロジェクトの作成を実行し、エラーが解消されてることを確認する。

# Mavenの場合
新規Springスタータープロジェクトの作成時のエラーを突破して、やれやれとホッとしたのも束の間、Mavenでも同様のエラーが発生した。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/258b3b19-b7ba-65cd-04ac-ec62b1c93ec1.png)

## 証明書のダウンロード
ブラウザで https://repo1.maven.org/maven2/ にアクセス

証明書のダウンロードは、新規Springスタータープロジェクトで証明書のダウンロードした同様の方法になります。

1.URL左のロックアイコンをクリックする
2.「接続がセキュリティで保護されています」の証明書アイコン「証明書は有効です」をクリックする
3.詳細タブでエクスポートをクリック、ローカルの適当な場所にダウンロードする

自分はダウンロードした証明書「repo1.maven.org.cer」を「C:¥temp」フォルダに保存した。

## キーストアに証明書を追加
コマンドプロンプトを起動し以下を実行

```bat
%JAVA_HOME%\bin\keytool -alias repo -importcert -keystore "%JAVA_HOME%\lib\security\cacerts" -storepass changeit -file "C:¥temp¥repo1.maven.org.cer"
```

「この証明書を信頼しますか。 [いいえ]: 」が表示されたら、「はい」と入力し実行

```
この証明書を信頼しますか。 [いいえ]:  はい
証明書がキーストアに追加されました
```

## 動作確認
pom.xmlの依存関係をダウンロード出来るようになっていることを確認する。

# その他設定
上記で解決するまでに下記2点の設定を追加したものの、別PCではやり直してみたところ設定しなくても動作した。
証明書の読み込みタイミングとかあるので、eclipseの再起動やPC再起動だけでも解決するかも知れない。

それでも解決しない場合、無駄とはいえないが下記の設定してみるといいかも。

## eclipse.iniの末尾に追加
```ini:eclipse.ini
-Djavax.net.ssl.trustStore=C:\pleiades\2023-03\java\17\bin\lib\security\cacerts
-Djava.net.ssl.trustStorePassword=changeit
```

## Mavenのワークスペースのデフォルト使用
eclipseの設定画面のMaven -> Java コンフィギュレーター -> JRE　システム・ライブラリー・バージョンにて「ワークスペースのデフォルト使用」に切り替える。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/830a3855-8083-e9e9-f1f3-273b1127c3a5.png)

# 最後に
ようやく会社でも前記事のプロジェクトを動かすことが出来た。
RxSwiftを学ぶ②Subjectの種類

## はじめに
RxSwiftを学習中の初学者です。
RxSwiftを学ぶ上で詰まった点や理解が難しかった点について備忘録と理解の整理のために記事を書いています。

## 今回の内容
前回は、SubjectとObjectの違いについて書きましたが、今回はSubjectについて深掘りしていきたいと思います。というのも、Subjectにも色々種類があって、どれがどんな機能を持つか訳わからなくなっていたからです。整理のために書いていきます。

## Subjectの種類
### PublishSubject
RxSwiftのPlaygroundには以下のように書いてありました。
Broadcasts new events to all observers as of their time of the subscription.(購読している時刻の新しいイベントをすべてのオブザーバーにブロードキャストします。)
Subjectには複数オブザーバーを設定できるため、その全てに新しいイベントを通知するということのようです。
```swift
 let disposeBag = DisposeBag()
    let subject = PublishSubject<String>()
    // 一つ目の観察者登録
    subject.subscribe { element in
        print(element)
    }
    subject.onNext("A")
    // 二つ目の観察者登録
    subject.subscribe { element in
        print(element)
    }
    subject.onNext("B")
```
```
    　実行結果
    next(A)
    next(B)
    next(B)
```
初めは１つのオブザーバーしか指定していないため、next(A)が一つのみ、
途中でもう一つオブザーバーを追加し、Bを通知するとそれぞれのオブザーバーにnext(B)が通知されます。



### BehaviorSubject
Broadcasts new events to all subscribers, and the most recent (or initial) value to new subscribers.(新しいイベントをすべてのサブスクライバーに、最新（または初期）の値を新しいサブスクライバーにブロードキャストします。)
新しいイベントが発生した時、全てのオブザーバーに通知するのはPublishSubjectと同じのようです。
ただし、初期値を設定できるのと、最新の値を新しいオブザーバーに通知する機能があるとのこと。

```swift
    let disposeBag = DisposeBag()
    let subject = BehaviorSubject(value: "A")
    subject.subscribe { element in
        print("Observar1:\(element)")
    }
    subject.onNext("B") // ①
    subject.subscribe { element in
        print("Observar2:\(element)")
    }
    subject.onNext("C") // ②
    subject.onNext("D") // ③
```
```
    実行結果
    Observar1:next(A)
    Observar1:next(B)　　
    Observar2:next(B)　　　
    Observar1:next(C)
    Observar2:next(C)
    Observar1:next(D)
    Observar2:next(D)
```
①が実行された時点では、Observar1にBが通知されますが初期値であるAも通知されています。
②が実行された時点では、Observar2には新しく発生したCしか通知されないはずなのに、Bが通知されています。このように新しく追加されたObservarに対しては、その前に発生したイベントも通知される機能のようです。③の時には新しく発生したイベントだけ通知されているので、オブザーバー追加直後のみですが、
来たばかりの新参者の観察者には一つ前に起こったことを一回だけ教えてあげる優しいやつのようです。

### ReplaySubject
Broadcasts new events to all subscribers, and the specified bufferSize number of previous events to new subscribers. (新しいイベントをすべての購読者に、指定されたbufferSize数の前のイベントを新しい購読者にブロードキャストします。)
挙動的には先ほどのBehaviorSubjectに似ていると個人的には思いました。ただBehaviorSubjectのように初期値はないのと、新規のオブザーバーに教える以前のイベントの数を指定できるといった点が違いますが。
```swift
 let disposeBag = DisposeBag()
    let subject = ReplaySubject<String>.create(bufferSize: 1)

    subject.subscribe { element in
        print("Observar1:\(element)")
    }
    subject.onNext("A")
    subject.subscribe { element in
        print("Observar2:\(element)")
    }
    subject.onNext("B")
```
```
実行結果
Observar1:next(A)
Observar2:next(A)
Observar1:next(B)
Observar2:next(B)
```
バッファ数を大きくすれば、新参者の観察者にもその数だけ以前の通知を送ることができるようです。

## 最後に
今回は、RxSwiftのSubject３種類について書きました。
間違い等あれば教えていただけたら幸いです。
またRxSwiftについて書いていけたらと思います。
最後まで読んでいただきありがとうございました！
DockerでLambdaのPython(3.10)レイヤー作成してみた！

psycopg2とかpillowとかを単にpip installするとLambdaでimport module errorが発生するので、それを解決するためにDockerでLambdaのランタイムを再現しつつ？レイヤーをzipで作成した。

## 0. 前提条件
- Dockerコマンドが使える状態になっている
- awsアカウントを作成済みになっている

## 1. Dockerイメージを作成する
```dockerfile:Dockerfile
FROM --platform=linux/x86_64 amazonlinux:2

ARG PYTHON_VERSION=3.10.5

RUN yum update -y && yum install -y tar gzip make gcc epel-release openssl11 openssl11-devel bzip2-devel libffi-devel \
  && curl https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz | tar xz \
  && export CFLAGS=$(pkg-config --cflags openssl11) && export LDFLAGS=$(pkg-config --libs openssl11) \
  && cd Python-${PYTHON_VERSION} && ./configure && make && make install \
  && cd - && rm -rf Python-${PYTHON_VERSION}

ADD entrypoint.sh /

RUN yum install -y zip \
  && mkdir /python \
  && chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]
```
m1 macとかだと--platform=linux/x86_64をしてしないと、勝手にlinux/amd64でインストールされてしまうので、一応指定しておく。(amd64でインストールしてしまうと、Lambdaでもamd64をしてしなくてはならないかも)
python3.10以降よりopenssl 1.1.1が必須になったため、epel-release,openssl11,openssl11-develもインストールしておく。
これをインストールしないと以下のエラーが出る。
```
pip is configured with locations that require TLS/SSL, however the ssl module in Python is not available.
```

## 2. シェルスクリプトを作成する
```bash:entrypoint.sh
#!/bin/bash -eu

SRC=/python
DIST=/dist/layer.zip

pip3 install -t ${SRC} $@
rm -f ${DIST}
zip -q -r ${DIST} ${SRC}
```

## 3. イメージをビルドする
```
docker build . -t bundle-pip-modules-for-aws-lambda-layers:python3.10
```
## 4. requirements.txtを作成する
```requirements.txt
psycopg2-binary
pillow
```
Lambdaで使用したいライブラリを書いておく。

## 5. Lambdaのレイヤーを作成する
Mac, linuxの場合
```
docker run --rm \
    -v $(pwd)/requirements.txt:/requirements.txt \
    -v $(pwd):/dist \
    bundle-pip-modules-for-aws-lambda-layers:python3.10 \
    -r requirements.txt
```
windowsの場合
```
docker run --rm \
    -v {カレントディレクトリ}/requirements.txt:/requirements.txt \
    -v {カレントディレクトリ}:/dist \
    bundle-pip-modules-for-aws-lambda-layers:python3.10 \
        -r requirements.txt
```
正常に終わればlayer.zipが作成される。

## 6. レイヤーを登録する
![スクリーンショット (44).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3468749/30b9e3ed-6f12-397d-84fb-9b86ea871a3b.png)

あとは使用するLambdaにレイヤーを追加して、試してみるだけです！

## 参考文献
1. [Docker で AWS Lambda の Python 用 Layer を作成する](https://qiita.com/hoto17296/items/a374efc2d8159d75bc71#fn3)
2. [pipコマンドでモジュールインストール時にSSLエラー時の対処方法](https://rikei-danshi.work/entry/pip-ssl-error)
3. [Python 3.10の新機能(その8） OpenSSL 1.1.1が必須に](https://www.python.jp/news/wnpython310/require-openssl11.html)
4. [M1 Mac で Docker の x86_64 向けイメージを使う](https://qiita.com/kino-ma/items/a4e0b9da0375b33669d0)
5. [AWS Lambdaで発生する psycopg2._psycopg の ImportModuleError を解決する方法](https://memoribuka-lab.com/?p=3817)
証明書エラーを無視させることによる攻撃可能性を考えてみた

## きっかけ

とある公式Twitterアカウントにて、Web Shop のプライバシーエラーを無視するよう案内がされた。

- 証明書が期限切れとなっていたようである。
- 現在は該当ツイートは削除されています。

## 前提とする条件

（証明書エラーといえば中間者攻撃MITMということで、）

1. 公衆Wi-Fiに偽装したアクセスポイントに繋いだ場合を考える。（ARPスプーフィングが行われた場合も同様と思われる）  
2. DNSスプーフィングで、指定ドメインへの通信にのみproxyを設定できる。（ため、その他のサイトアクセスへの影響はなく、違和感少なく動かせる）
3. 証明書エラーを無視する（よう案内がされている）ため、TLS(https)へのMITMが成立する。（一応エラー内容など異なるが、証明書を確認しないような人をターゲットとすればよいため不問）  

## 影響

1. 通信が傍受される

    パスワードや決済情報などを含む通信内容を盗聴が可能。

2. 通信が改竄される

    リクエスト・レスポンス改竄による、任意のサイトへの誘導・スクリプト実行などが可能。

（アクセスポイントを用意し）

## 今回のサイトに適用されるか

このサイトは、対象ドメインでガワを提供し、ログインなど大事なとこは別ドメインで行っている。  
「から、まあいいんじゃないの」との意見を見かけた。

##### ダメであるパターンを二通り
- 利用者が別ドメインの証明書エラーも無視する。

    利用者からすると、この「サイト」を利用している際の証明書エラーを無視するよう案内されている。  
    そのため、ログインページへ遷移した際に再び証明書エラーが表示された場合も無視すると考えられる。  
    こうなればそのドメインへのMTIMも成立する。

- ログインページへの遷移を罠サイトに置き換える。  

    レスポンス改竄が容易なため、ログインページを模した別のページに遷移させることができる。利用者がログイン情報を送信すればそれを取得できる。

## 最後に

利用者としては、

- 公式からのものであっても、セキュリティ機能を無視させるような案内を容易に信頼しないようにしましょう。
- 信頼できるアクセスポイントに繋ぎましょう。

他のシナリオなど思いつく人教えてください。
徳丸本のDockerでの環境構築時、ADD failed: file not found in build context or excluded by .dockerignore: stat php-5.3.3.bin-.tar.gz: file does not existのエラー

[徳丸本サポートサイト](https://wasbook.org/)からDocker用の環境構築素材をダウンロード後、そのまま、```docker compose up -d```を実行したところ、以下エラーメッセージが出ました。。。

```
ADD failed: file not found in build context or excluded by .dockerignore: stat php-5.3.3.bin-.tar.gz: file does not exist
```

実行環境は、`MacBookAir M2`です。

# 結論
```TARGETARCH```というDocker側で自動的に設定される環境変数が設定されていなかったようです。。。
apachフォルダ内のDockerfileの2行目を下記ように変更しました。
```Dockerfile
ARG TARGETARCH=arm64
```
私はM2チップなので```arm64```です。
IntelのMacやwindows使っている方は```amd64```を設定すれば良いかと思います。


# 余談
なんで```TARGETARCH```に値が設定されてないか明確には分かりませんが、Docker Desktopでrosettaの設定をオンにしてたのが原因かもですね。。。
![Screenshot 2023-06-01 at 23.36.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599663/65289418-a556-d933-b89a-4d3f42e45d80.png)



# 参考文献
```TARGETARCH```以外にもDocker側で勝手に設定される環境変数が色々あるらしいです。
https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope
[java] int配列から順列を得る方法

# 序論
Javaの勉強中、int配列から順列を得る方法が必要であったので、そのメモ


# Code
```java:Permutation
import java.util.ArrayList;

public class Permutation {

	static public ArrayList<ArrayList<Integer>> resultList = new ArrayList<>();

	static ArrayList<ArrayList<Integer>> getPermutation(int[] arr, int[] output, boolean[] visited, int depth, int n, int r) {
		resultList.clear();
		permutation(arr, output, visited, 0, n, r);
		return resultList;
	}

	static void permutation(int[] arr, int[] output, boolean[] visited, int depth, int n, int r) {
		if (depth == r) {
			addToResult(output, r);
			return;
		}

		for (int i = 0; i < n; i++) {
			if (visited[i] != true) {
				visited[i] = true;
				output[depth] = arr[i];
				permutation(arr, output, visited, depth + 1, n, r);
				visited[i] = false;
			}
		}
	}

	static void swap(int[] arr, int depth, int i) {
		int temp = arr[depth];
		arr[depth] = arr[i];
		arr[i] = temp;
	}

	static void addToResult(int[] arr, int r) {

		ArrayList<Integer> temp = new ArrayList<>();

    // なぜかfor文ではないと、List内の順番がすべて一緒になってします。
		for (int i = 0; i < r; i++) {
			temp.add(arr[i]);
		}
		resultList.add(temp);
	}
}
```


```java:PermutationUse
import java.util.ArrayList;

public class PermutationUse {
	public static void main(String[] args) {
		int n = 3;
		int[] arr = { 1, 2, 3 };
		int[] output = new int[n];
		boolean[] visited = new boolean[n];

		ArrayList<ArrayList<Integer>> permu = new ArrayList<>();
		permu = Permutation.getPermutation(arr, output, visited, 0, n, n);
		System.out.println(permu);

    // [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
	}
}

```

# おわりに
javaの配列は長さの制限があるので、なるべく使用したくないのが正直な感想ではあるが、あまりにも基本的な部分なので、使用しないことも難しさを感じる。
今回はList型で出力をしたが、Array化は簡単であるので、List出力を基本で考えた方が、応用ができそう。
web技術の基本を学ぼう

# はじめに
今回はエンジニアになる上で土台となる基本的な技術をまとめました。
私なりに理解してわかりやすくした内容ではあるので
ぜひもう知っているよという方は復習に、
まだあまり理解していないよーという初学者の方はこれを機に理解していただけると思います。
（といっても私も初学者なので初学者なりにまとめた内容になります）

# Webの発展とは
WWW（World-Wide Web）とHTML（Hyper Text Markup Language）の公開と閲覧は
**・Webサーバー**
**・Webクライアント**
という2つのソフトウェアで実現されています。

また、**クライアント**と**サーバー**という言葉は
それぞれコンピュータやその上で動作するソフトウェアを指しています。
そしてクライアントからサーバーに対しての要求のことを**リクエスト**、
サーバーからクライアントに対する応答を**レスポンス**といいます。

私たちがWebページを閲覧できるのはこのようにクライアントとサーバー間で情報のやり取りをしているからなんですね。

しかし、どのように情報のやり取りをするのか取り決めをする必要があり、その取り決めのことを**通信プロトコル**と呼びます。その中でHTMLの転送に適したものが**HTTP**（Hyper Text Transfer Protocol）です。

# IPアドレス
例）**192.156.0.4**
上記のようにピリオドでくぎられた4組の数字で表されるのがIPアドレスです。
256×256×256×256通りあります。

そんなIPアドレスには2種類ある。
### グローバルIPとプライベートIP
**・グローバルIP**　
インターネットに接続されていてランダムに割り当てられているIPアドレス

**・プライベートIP**
インターネットなどほかのネットワークに接続されていないプライベート・ネットワークで自由に利用できるIPアドレス

# DNS
**DNS**（Domain Name Systems）とは、ドメイン名からIPアドレスに変換する際に用いられるシステム。ドメイン名とIPアドレスの対応表を持ったコンピュータ、DNSサーバーというものをインターネット上に配置している。

さらに私たちがよく目にする、jp,com,net,org といった最上位のドメインのことを
**トップドメイン**といいます。
**トップドメイン**はルートサーバと呼ばれる1つのDNSサーバで管理されており、インターネットを支えるルートサーバは世界中に配置されています。

# プロトコル
どのコンピュータとどのように情報をやりとりするかの取り決め・ルール
**TCP/IP**というものが代表的
**TCP/IP**は現実世界での郵便配達と同じようなもの

# ポート
TCP/IP通信によって送られてきた情報をどのようなアプリケーションで処理を行うべきかを判断する番号のことをいう。
コンピュータのなかでアプリケーションが情報を受け取るための港
URLにはポート番号が記述されておらず、省略されている。

| プロトコル | ポート番号 |
|:-----------|:------------:|
| FTP      | 20,21      | 
| SSH    | 22     |
| Telnet （リモートコンピュータとの汎用通信）      | 23        |
| SMTP （メール送信）      | 25         |
| DNS       | 53       |
| HTTP(WEBブラウジング）    | 80     | 
| POP3（メール受信）    | 110     | 
|HTTPS（暗号化されたHTTP)   | 443     | 

# ステートフル
サーバが前回のリクエスト結果を記憶していて、それを踏まえ次回のリクエストを実行している。
このようにサーバはリクエストに伴って状態が変わっていくプロトコルのことを
**ステートフル・プロトコル**
例）FTP

#ステートレス
サーバが前回のリクエスト結果を記憶しておらず、状態も保持できないプロトコルのことを
**ステートレス・プロトコル**
例）HTTP

# Cookie
HTTPの使用を拡張してWebアプリケーションとWebブラウザの間で情報をできるように交換できるようにしたもの。
Webブラウザに状態を持たせる仕組みのこと。
いわばWebサイトに訪れたユーザーの情報を一時的に保存してくれるのです。
ECサイトやSNSへのログイン時にお世話になっていますね。

# 終わりに
かなり表面的ですが初学者なりにまとめてみました。どうだったでしょうか。
ここが少し違うなどあればコメントにてお教えいただけると幸いです。
React コンポーネントのアンマウント時に最新のコールバック関数を実行する

useEffectフックを使って、コンポーネントがアンマウントされるときにクリーンアップ処理を実行することは一般的です。しかし、クリーンアップ処理がコンポーネントのライフタイム中に変更される場合、問題が生じる可能性があります。

以下のようなコードでは、コールバック関数がコンポーネントがマウントされたときのものしか呼び出されません。
変更された場合、変更後のコールバック関数は呼び出されません。

```js
const callback = console.log('Component is unmounting. Clean up:', props.cleanupTarget);
React.useEffect(() => {
  return () => {
    callback();
  }
},
// アンマウント時のみ実行するために空配列にする 
[]);
```


この問題を解決するために、useRefフックを使って最新のコールバック関数を記憶します。そして、useEffectのクリーンアップ関数でそのコールバック関数を呼び出します。

```js
const callbackRef = React.useRef<() => void>();

const callback = console.log('Component is unmounting. Clean up:', props.cleanupTarget);

React.useEffect(() => {
  callbackRef.current = callback;
}, [callback]);

React.useEffect(() => {
  return () => {
    if (callbackRef.current) {
      callbackRef.current();
      callbackRec.current = undefined;
    }
  };
}, []);
```

この例では、useRefフックを使って最新のコールバック関数を記憶しておき、useEffectのクリーンアップ関数でそのコールバック関数を呼び出しています。これにより、コールバック関数が変更された場合でも、常に最新のコールバック関数がコンポーネントのアンマウント時に呼び出されます。
rex0220 関連レコード集計プラグイン 組織選択で集計その２

関連レコード集計プラグインを使って、組織単位に集計する例その２です。
組織選択項目に、複数選択・選択なしを指定した場合の集計も行う例になります。

# 概要

アプリのレコード追加・更新時に、組織を組織コードの文字列に変換しそれを集計キーにしてレコード集計を行います。
※組織を組織コードの文字列に変換は、[計算式プラグイン](https://qiita.com/rex0220/items/ae83c6d5ce50ff7a9a73)を利用します。

![2023-06-01_22h51_27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/f15935cf-8b41-013a-9728-84e9af0b9a50.png)

# アプリ設定

集計キー用の組織コードを追加します。
※集計先アプリにも同様に組織コードを追加

![2023-06-01_22h53_34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/afc3f0bf-db08-e043-db47-337179bad44f.png)

# 計算式プラグインの設定

組織選択から組織コードに変換します。
計算式：SEL_CODE(組織選択,"array")

![2023-06-01_23h04_47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/408a391b-c748-07bb-7320-d5d736f0a2f2.png)

# 関連レコード集計プラグインの設定

集計先アプリを選択して、対象アプリ条件・集計条件・集計項目等を設定します。

![2023-06-01_22h57_21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/3935e401-e37f-52c0-64e5-5a8842e6d08a.png)

# 対象アプリ条件

集計キー用の組織コードを指定

![2023-06-01_22h58_26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/17c866ff-46cd-4855-c5e4-f9fd2edf91a0.png)


# 集計条件

集計キー用の組織コードを指定

![2023-06-01_22h59_41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/f849371a-d865-1e30-e6e9-97211d242792.png)

# 集計項目

集計キーになる組織コードの設定

組織選択の設定は、SET_CODE, SEL_CODE 関数を指定します。

組織選択の項目（計算式）：
```.js
// 組織コード
JOIN(
  SEL_CODE(組織選択,"array"),
  ","
)
// 組織選択
SET_CODE(
  SEL_CODE(組織選択,"array")
)
```

![2023-06-01_23h03_51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/b79fc009-cd41-0406-f663-d8311bf7ab85.png)
tarコマンドによるファイル解凍・圧縮

ファイル解凍・圧縮をする時に使用するtarコマンドについてまとめました。

## 解凍

オプションは、`x(extract)`、`v(verbose)`、`f(file)`です。
```bash
tar -xvf <解凍するファイル名>
```

## 圧縮

オプションは、`a(auto-compress)`、`c(create)`、`v(verbose)`、`f(file)`です。
`a(auto-compress)`を使うことで、圧縮後のファイル名の拡張子から自動で圧縮プログラムを決定してくれます。

```bash
tar -acvf <圧縮後のファイル名> <圧縮前のディレクトリ名>
```

`a`の代わりに、`-z(gzip)`や`-j(bzip2)`オプションを使うことも可能ですが、本記事では省略します。

例：tar.gzに(gzipで)圧縮する場合

```bash
tar -acvf xxx.tar.gz source/
```

例：tar.bz2に(bzip2で)圧縮する場合

```bash
tar -acvf xxx.tar.bz2 source/
```

例：tar.xzに(xzで)圧縮する場合

```bash
tar -acvf xxx.tar.xz source/
```
【SwiftUI】内側に影をつける

# はじめに
iOS16から影が内側に付けられるようになりました。

# 実装
```swift
import SwiftUI

struct ContentView: View {
    private let baseColor: Color = .init(red: 232/255, green: 232/255, blue: 232/255)
    
    private let shadowColor: Color = .init(red: 197/255, green: 197/255, blue: 197/255)
    
    var body: some View {
        RoundedRectangle(cornerRadius: 10)
            .fill(baseColor.gradient.shadow(.inner(color: shadowColor, radius: 8, x: 20, y: 20)))
            .frame(width: 300, height: 300)
    }
}
```

![Simulator Screenshot - iPhone 14 - 2023-06-01 at 22.58.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/8f8c8d4d-84ee-cf46-dd6a-d961cc63ede6.png)

ちょっと凹んでるように見えるかな？

# おわり
`drop`にするだけで外側の影になります
```swift
import SwiftUI

struct ContentView: View {
    private let baseColor: Color = .init(red: 232/255, green: 232/255, blue: 232/255)
    
    private let shadowColor: Color = .init(red: 197/255, green: 197/255, blue: 197/255)
    
    var body: some View {
        RoundedRectangle(cornerRadius: 10)
            .fill(baseColor.gradient.shadow(.drop(color: shadowColor, radius: 8, x: 20, y: 20)))
            .frame(width: 300, height: 300)
    }
}
```
![simulator_screenshot_2D9996DB-A146-4EE8-A5B2-EF4E818E674A.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/85e33eb2-5a2f-27d9-6cec-9c32a52056f3.png)
V3系symbol-sdkを速習Symbol風にブラウザコンソールから使用する

速習Symbolなどではsymbol-sdkをbroserifyしたものをブラウザコンソールから読み込み、コマンドプロンプトに対話形式でSymbolを素早く学べるコンテンツを提供していました。

しかし、symbol-sdkはv3になってからbrowserifyを利用したライブラリの生成ができなくなりました。残念に思っていたところ、オープニングラインさんのブログ記事でv3系sdkをブラウザで使う方法の解説がありました。

https://blog.opening-line.jp/%E8%A8%98%E4%BA%8B%E4%B8%80%E8%A6%A7/esmjavascript-module%E3%81%A8%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%81%A7symbol-sdk3%E3%82%92%E4%BD%BF%E3%81%86

> それで、じゃぁホスティングするときどうするんだっていう話になるんですが、
./node_modules/symbol-sdk/dist/ 配下の以下のファイルをあげておけばいいんじゃないかと思います。
bundle.web.js
bundle.web.js.map
5fcc69fd3573ae76acd8.module.wasm

なんと、npmでインストールした後にできるdistフォルダ配下のライブラリがそのまま使えるそうです。

なので、使ってみました。

使えました。

と言うわけで、今回はv3sdkをブラウザコンソールで使用する方法を解説します。

まずはインポートです。以下にbundle版が配置されているのでそれを読み込みます。

https://www.unpkg.com/symbol-sdk@3.0.7/dist/bundle.web.js

こちらにも置いていますのでご自由にどうぞ。

https://xembook.github.io/symbol-browserify/3.0.7/bundle.web.js


```js
module = await import("https://www.unpkg.com/symbol-sdk@3.0.7/dist/bundle.web.js");
```

コンソールでの呼び出し方はこの書き方一択です。await import(...)です。
この書き方、検索してもあまり見かけません。３回唱えましょう。
await import
await import
await import

ここさえ乗り越えたら後は楽勝です。

オープニングラインさんのブログの内容ほぼそのままですが、写経してみると

```js
symbolSdk = module.default;
facade = new symbolSdk.facade.SymbolFacade('testnet');

privateKey = new symbolSdk.PrivateKey("************");
keyPair = new facade.constructor.KeyPair(privateKey);

network = symbolSdk.symbol.Network.TESTNET;
deadline = network.fromDatetime(new Date(Date.now() + 7200000)).timestamp;

nodeUrl = localStorage.getItem('nodeUrl');
```

おっと、ここまで書きましたが、直接記事を読んでもらった方が早いですね。

https://blog.opening-line.jp/%E8%A8%98%E4%BA%8B%E4%B8%80%E8%A6%A7/esmjavascript-module%E3%81%A8%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%81%A7symbol-sdk3%E3%82%92%E4%BD%BF%E3%81%86

module importはv2系のbrowserifyとは違って、インポート時に実行を2回に分ける必要がなく一気に実行までいけるので便利ですね。ただ、v3系の読み込むライブラリは7.8MBと少しサイズ大きめなので注意が必要です。


それでは！
LINEAPI×CHATGPTAPI×DOCKER×CLOUDRUN×PYTHONで爆速でchatbotを作ってみる

完成したラインボット
どんな質問にも答えてくれる「解答キッド」
https://liff.line.me/1645278921-kWRPP32q/?accountId=524aznwp

#リポジトリー
https://github.com/Kobajun0219/Line-bot-chatgpt

#参考にした記事

https://zenn.dev/kenken82/articles/cloudrun-docker-tutorial

https://zenn.dev/kenken82/articles/ca5e36cf4d5ea1



#ソースコード

```Sample.py
from flask import Flask
from flask import request
import os
from linebot import (LineBotApi, WebhookHandler)
from linebot.exceptions import (InvalidSignatureError)
from linebot.models import (MessageEvent, TextMessage, TextSendMessage,)

import openai

# generate instance
app = Flask(__name__)

#key
CHANNEL_SECRET = os.environ["CHANNEL_SECRET"]
ACCESS_TOKEN = os.environ["ACCESS_TOKEN"]

# API_KEY
openai.api_key = os.environ["API_KEY"]

line_bot_api = LineBotApi(ACCESS_TOKEN)
handler = WebhookHandler(CHANNEL_SECRET)

# endpoint
@app.route("/")
def test():
    return "<h1>It Works!</h1>"

# endpoint from linebot
@app.route("/callback", methods=['POST'])
def callback():
    # get X-Line-Signature header value
		signature = request.headers['X-Line-Signature']

		# get request body as text
		body = request.get_data(as_text=True)
		app.logger.info("Request body: " + body)

		# handle webhook body
		try:
			handler.handle(body, signature)
		except InvalidSignatureError:
			print("Invalid signature. Please check your channel access token/channel secret.")
			abort(400)
		return 'OK'

# handle message from LINE
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
  response_text = generate_response(event.message.text)
  line_bot_api.reply_message(
			event.reply_token,
			TextSendMessage(text=response_text))


# OpenAIのAPIを使ってChat GPTに入力を渡し、応答を取得する
def generate_response(input_text):
    model_engine = "text-davinci-002"
    prompt = f"{input_text.strip()} \nAI:"
    completions = openai.Completion.create(
        engine=model_engine,
        prompt=prompt,
        max_tokens=1024,
        n=1,
        stop=None,
        temperature=0.7,
    )
    message = completions.choices[0].text.strip()
    return message


if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))

```
【JavaScript】innerHTMLを利用した言語切り替え機能

# はじめに
JavaScriptのinnerHTMLを使用したボタンによる「日⇔英」言語切り替え機能です。
言語に関しては、ブラウザから言語を取得したり、言語によってフォントを指定したりなど、なかなか奥深いのですが、本記事はあくまで、innerHTMLを使用した切り替えボタンに焦点を絞り書いていきます。
また、言語以外の表示切替にも利用できます。

# 目次
1. html
2. JavaScript

# 1. html
1. html内の切り替えたいテキストを含む要素（今回はp）にidを指定します。
2. 各言語ボタンに、クリック時にJavaScriptから呼び出す関数名をonclick属性で指定します。
3. JavaScriptファイルを読み込みます。
```index.html
<body>
	<p id="text1">ようこそ！</p><!-- 切り替え対象テキスト -->
	<button onclick="langJa()">日本語</button><!-- 日本語ボタン -->
	<button onclick="langEn()">English</button><!-- 英語ボタン -->
	<script src="lang.js"></script><!-- JavaScriptファイル読み込み -->
</body>
```
以下のような表示になるかと思います。
![Screenshot 2023-06-01 221000.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3072383/9eb082d2-790e-4b0f-943e-4a98a2b75c6b.png)

# 2. JavaScript
id="text1"に対して、innerHTMLでボタンクリック時にテキスト内容を書き換えます。
```lang.js
// 日本語に切り替え
function langJa(){
	text1.innerHTML = "ようこそ！";
}

// 英語に切り替え
function langEn(){
	text1.innerHTML = "Welcome！";
}
```
Englishボタンを押すと、以下のようになります。
![Screenshot 2023-06-01 221011.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3072383/342320c4-7cee-14b5-30f1-137c0d1c5dce.png)
日本語ボタンを押すと最初の状態に戻ります。
![Screenshot 2023-06-01 221000.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3072383/9eb082d2-790e-4b0f-943e-4a98a2b75c6b.png)

# おわりに
今回はinnerHTMLの使い方の一部をとても簡単にまとめました。
innerHTMLについてより深く知りたい方は、下の記事がとても参考になると思います。
### 【JavaScript】innerHTMLの使い方
https://qiita.com/mzmz__02/items/7bcbce347bc3c5d64b93
### 【JavaScript】innerHTM、textContentの違い
https://qiita.com/tomokichi_ruby/items/3640f0bc64ad6c676206
【Docker】ArgumentError: Missing `secret_key_base` for 'production' environment, set this string with `bin/rails credentials:edit`の解消法

### はじめに
Dockerfileをproduction環境でビルドする際に`webpacker:install`や`webpacker:compile`をする場合、config/secrets.ymlとconfig/master.keyの情報が必要になってきます。

私はmaster.keyファイルを.dockerignoreファイルに含めていた為エラーが発生しました。
master.keyの情報をイメージに含めずにビルドする方法に少し躓いたので、解決法を紹介します。

## 環境
Ruby 3.2.1
Rails 6.1.7.3
Docker version 23.0.5
MacOS 13.3.1

## Dockerfile
方法は複数あるそうですが、今回はdocker buildkitを使用します。buildkitはMacOSとwindowsに対しては、docker desktopをインストールしていればデフォルトで入っています。
以下のようにすることで、ビルド時にmaster.keyの値を使用しながら、最終的なイメージにはmaster.keyを含めないようにすることができます。
```Dockerfile:Dockerfile
RUN --mount=type=secret,id=master_key,target=config/master.key,required=true \
    bundle exec rails webpacker:install
```
```:コンソール
docker buildx build --secret id=master_key,src=./config/master.key .
```

+ コンソールでid=master_key,src=./config/master.keyとすることで、Dockerfile内のconfig/master.keyに、src=./config/master.keyが一時的に設定された状態でビルドすることができます。

## 参考
https://zenn.dev/hiro1111/articles/6113a7e347237f
Eclipse with Liberty

仕事で Eclipse を使っています。
4.28(2023-06)がリリースされました。
https://www.eclipse.org/projects/project-plan.php?planurl=https://www.eclipse.org/eclipse/development/plans/eclipse_project_plan_4_28.xml
Eclipse で、Liberty を使うには「IBM Liberty Developer Tools」をインストールすると良いのですが、依存関係とかうまく解決できないことがあります。
色々試した結果、以下をインストールするのが良いかと思っています。
```
・Eclipse-Platform
・MPC-1.10.1
・Eclipse Enterprise Java and Web Developer Tools 3.30 from the market
・libertyAdapter
http://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/wasdev/updates/libertyAdapter/2022-09/
```

eclipse-platform-4.28で試しました。
Open Liberty Tools for Eclipse/Version: 23.1/Build id: 2023-03-06_1555がインストールされました。
Server Runtime Environmentで「Liberty Runtime」が選択できるようになります。
単純な JAX-RS のアプリケーションを入れて起動すると以下のメッセージが出力され、問題なく動いています。
```
IBM J9 VM バージョン 8.0.8.0 - pwa6480sr8-20230314_01(SR8) (ja_JP) で、defaultServer (WebSphere Application Server 23.0.0.5/wlp-1.0.77.cl230520230514-1901) を起動しています
[AUDIT   ] CWWKE0001I: サーバー defaultServer が起動されました。
[AUDIT   ] CWWKE0100I: この製品は、開発使用向け、および限定的な実動使用向けにライセンスが交付されています。 全ライセンス条項は以下で表示可能です: https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/wasdev/license/base_ilan/ilan/23.0.0.5/lafiles/ja.html
[AUDIT   ] CWWKZ0058I: アプリケーションの dropins をモニター中です。
[AUDIT   ] CWPKI0820A: デフォルトの鍵ストアは'keystore_password' 環境変数を使用して作成されました。
[AUDIT   ] CWWKT0016I: Web アプリケーションが使用可能です (default_host): http://localhost:9080/aa/
[AUDIT   ] CWWKZ0001I: アプリケーション aa が 0.756 秒で開始しました。
[AUDIT   ] CWWKF0012I: サーバーは次のフィーチャーをインストールしました。[appSecurity-2.0, appSecurity-3.0, beanValidation-2.0, cdi-2.0, distributedMap-1.0, ejbLite-3.2, el-3.0, jaspic-1.1, jaxrs-2.1, jaxrsClient-2.1, jdbc-4.2, jndi-1.0, jpa-2.2, jpaContainer-2.2, jsf-2.3, jsonb-1.0, jsonp-1.1, jsp-2.3, localConnector-1.0, managedBeans-1.0, servlet-4.0, ssl-1.0, webProfile-8.0, websocket-1.1]。
[AUDIT   ] CWWKF0011I: defaultServer サーバーは、Smarter Planet に対応する準備ができました。defaultServer サーバーは 2.908 秒で始動しました。
```
確認出来たら、パッケージを更新し、Eclipse Pleiades pluginを導入すれば、日本語にも対応します。
LaTeXの記号を自分で定義する


TeX記法による数式の記述をする機会って結構ありますよね。Qiitaやはてなブログのような主要なブログでもサポートしてますし、TyporaやNotionのようなメモ帳アプリでも使えます。

そんなときに自分で記号を定義したいこともありますよね。$\newcommand{\argmin}{\mathop{\rm arg~min}\limits} \argmin_{\theta} L(\theta)$のarg minのようにデフォルトのTeXでは存在しない記号が欲しい状況があったり、あるいは複雑で書くのが面倒な記号（例えば$\hat{\boldsymbol{\beta}}_i^{(k)}$ `\hat{\boldsymbol{\beta}}_i^{(k)}`とか）により短いエイリアス（別名）を与えて書きやすくしたい場合もあります。

そのへんのやり方をメモしておきます。


# 定義の方法

新たな記号を定義するときは`\def`や`\newcommand`を使います。

## `\def`

```
\def\コマンド名#引数1#引数2...{ コマンドが呼び出されたとき実行される処理 }
```

### 例（引数なし）

TeXコード：

```tex
\def\t{ \top }
A^\t
```

実行結果：

$$
\def\t{ \top }
A^\t
$$


### 例（引数あり）

```tex
\def\d#1#2{ \frac{ \partial #1 }{ \partial #2 } }
\d{y}{x}
```

$$
\def\d#1#2{ \frac{ \partial #1 }{ \partial #2 } }
\d{y}{x}
$$



## `\newcommand`

```
\newcommand{ \コマンド名 }[ 引数の数（省略可） ]{ コマンドが呼び出されたとき実行される処理 }
```

### 例（引数なし）

```tex
\newcommand{ \g }{ \gamma }
\g
```

$$
\newcommand{ \g }{ \gamma }
\g
$$


### 例（引数あり）

```tex
\newcommand{\b}[1]{ \boldsymbol{#1} } % 定義
\b{a}^\top \b{x} % 文字を入れて呼び出してみる
```

$$
\newcommand{\b}[1]{ \boldsymbol{#1} }
\b{a}^\top \b{x}
$$


## `\DeclareMathOperator`

新たに演算子を定義するときには手軽でよい選択肢のように思います。
`amsmath`パッケージで定義されているコマンドですが、QiitaやJupyterなど多くの環境で使えるようです。

```tex
\DeclareMathOperator{新しいコマンド}{表示される演算子}
\DeclareMathOperator*{新しいコマンド}{表示される演算子}
```

`*`をつけると$\lim$のように下付き文字が真下に出るようになります。

### 例

```tex
\DeclareMathOperator*{\plim}{plim}
\plim_{n \to \infty} \beta
```

$$
\DeclareMathOperator*{\plim}{plim}
\plim_{n \to \infty} \beta
$$

## （参考）一時的に演算子を使いたい場合

一度しか使わない場合に向いていそうな方法もあるようなのでメモしておきます

### `\operatorname`

```tex
\operatorname{Cov}(X, Y)
```

$$
\operatorname{Cov}(X, Y)
$$

```tex
\operatorname*{arg min}_{\theta \in \Theta} f(\theta)
```

$$
\operatorname*{arg min}_{\theta \in \Theta} f(\theta)
$$


### `\mathop`

```tex
x^{(k+1)} := \alpha \mathop{ \text{sign} } f(x^{(k)})
```

$$
x^{(k+1)} := \alpha \mathop{ \text{sign} } f(x^{(k)})
$$



# 個人的によく使うユーザー定義コマンドの例

## argmin / argmax

```tex
% newcommandを使う場合
\newcommand{\argmin}{\mathop{\rm arg~min}\limits}

% DeclareMathOperatorを使う場合
\DeclareMathOperator*{\argmax}{arg max}
```

使用例：

$$
\newcommand{\argmin}{\mathop{\rm arg~min}\limits}
\argmin_{w} L(w)
$$

$$
\DeclareMathOperator*{\argmax}{arg max}
\argmax_{\theta} \ell(\theta)
$$


## 独立（確率論）

```tex
\newcommand{\indep}{\perp\!\!\!\perp} % 他サイトでは問題ないがQiitaだと崩れる（\!は負のスペース）
\newcommand{\indep}{\perp\hspace{-1em}\perp} % Qiitaでも崩れない方法
```

使用例：

$$
\newcommand{\indep}{\perp\hspace{-1em}\perp}
\displaystyle % これを明示しないと横スクロールバーが表示される
(Y^{(0)}, Y^{(1)}) \indep D
$$

## 確率極限

```tex
\DeclareMathOperator*{\plim}{plim}
```

使用例：

$$
\DeclareMathOperator*{\plim}{plim}
\plim_{n \to \infty} \sum_i X_i / n
$$



# 参考

- [【LaTeX】新しい演算子を定義するDeclareMathOperatorの使い方 | 数学の景色](https://mathlandscape.com/declaremathoperator/)
- [\newcommandを乱用するな、\DeclareMathOperatorを使え（LaTeXでの演算子の定義）](https://tottoto.net/how-to-use-declaremathoperator/)
【Unity】Unity Entities用のエディター拡張作ってみた。

# 自己紹介
Unity DOTSで何か作ってみたい大学生です。
そろそろガチで何か作りたい。
# 紹介
大したものでもなく、単純に私が使いたかっただけでエディター拡張作ったので適当に配布しておきます。
煮るなり焼くなりしてください。

https://github.com/AtsuAtsu0120/Editor-for-Entities
## 機能
機能については私がよく生成したいスクリプトを作れるようにしています。
つまり、自分が理解しているものしか生成できないので、上級者さんからすると不便かも。
ちなみに対応してるのは以下の通りです。
- Unmanaged Component(structのIComponentData)
- Managed Component(classのIComponentData)
- Buffer Data
- ISystem
- SystemBase
- Authoring

# 経緯
作った経緯ですが、デフォルトのUnity EntitiesではMonoBehaviourしかエディターから作れなかったので不便を感じたからです。
# 今後
私が使いたい機能が出てきたら随時更新していきます。
ちなみに、パッケージ作るの初めてで1.0.0はずっとスクリプトを作れないという致命的すぎるバグを抱えていました（）
Paiza Cランク獲得問題（Dランク相当）　標準出力メニュー①　C#

paizaのCランク獲得問題の解答がなかったので、備忘録として残します。
明らかに簡単な問題の場合は省略しますが、個人的に少しでも考えたコードを残していきたいと思います。
初心者ですので醜いコードを書きますが、温かい目で見守っていただけると嬉しいです。
また、より良い記述方法などありましたら、コメント等で教えていただけると嬉しいです。


# 目次
- 10 行の出力
- 【改行あり出力】1,000 行の出力
- 10 個の数値を出力 (末尾に半角スペース有) 
- 10個の数値を出力
- 【文字列の出力】入力された 10 個の文字列を出力






## 10 行の出力
[問題文](https://paiza.jp/works/mondai/stdout_primer/stdout_primer__newline_digit_step4/edit?language_uid=c-sharp)
```C#
using System;
class Program
{
    static void Main()
    { 
      int[] num = { 813, 1, 2, 923874, 23648, 782356, 3256, 2342, 24324, 112 };
        
        for(int i = 0; i < num.Length; i++)
        {
            Console.WriteLine(num[i]);
        }
    }
}
```

## 【改行あり出力】1,000 行の出力
[問題文](https://paiza.jp/works/mondai/stdout_primer/stdout_primer__newline_digit_boss/edit?language_uid=c-sharp)
```C#
using System;
class Program
{
    static void Main()
    {
      for(int i = 1; i <= 1000; i++)
        {
            Console.WriteLine(i);
        }
    }
}
```

## 10 個の数値を出力 
[問題文](https://paiza.jp/works/mondai/stdout_primer/stdout_primer__space_oneline_step4/edit?language_uid=c-sharp)
```C#
using System;
class Program
{
    static void Main()
    {
        for(int i = 1; i <= 10; i++)
        {
            if(i == 10)
            {
                Console.Write(i);
            }
            else
            {
                Console.Write(i + " ");
            }
        }
    }
}
```

## 入力された 10 個の文字列を出力
[問題文](https://paiza.jp/works/mondai/stdout_primer/stdout_primer__string_output_step4/edit?language_uid=c-sharp)
```C#
using System;
class Program
{
    static void Main()
    {
        for(int i = 0; i < 10; i++)
        {
            if (i == 9)
            {
                Console.Write(Console.ReadLine());
            }
            else
            {
                Console.Write(Console.ReadLine()+" ");
            }
            
        }
    }
}
```

## 【文字列の出力】入力された 10 個の文字列を出力
[問題文](https://paiza.jp/works/mondai/stdout_primer/stdout_primer__string_output_boss/edit?language_uid=c-sharp)
```C#
using System;
class Program
{
    static void Main()
    {
        string [] array = Console.ReadLine().Split();
        for (int i=0;i<array.Length;i++){
            Console.WriteLine(array[i]);
        }
    }
}
【開発者向けのAI検索エンジン】phindのAdvanced features


# phind
[Phind](https://www.phind.com/)は、開発者向けのAI検索エンジンです。
Phindは、大型の独自の生成型AI言語モデルによって駆動され、インターネットを検索することができます。
Phindは、複数のソースからの情報に基づいて回答を生成することができるほど賢いです。[1], [2]


# 知られざる設定方法

1. カスタムリンク
	検索ボックスに質問内容に加えて、取得したい特定のソース元を貼り付けて検索処理をすると特定のソースだけを参考に回答してくれる
	
	> 例
	```
	ライフサイクルフックって何ですか？
	
	https://qiita.com/styu214/items/e4375ff48ccd8b3c743f
	```
     
2. 追加のテキスト用検索ボックス
     高度にカスタムされたコードを生成・修正する場合に隠された検索ボックスにコード・テキストを追加できます。
     以下の画像の赤丸のトグルを押すと追加のテキスト用検索ボックスが表示され、質問文とは別にコードを書き込みます。
![Screen Shot 2023-06-01 at 21.15.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486680/853a28ba-8346-d6e1-610f-f860cae83a0c.png)
     
   
3. 検索フィルター(検索ドメイン指定)
	AIが回答時に参考にするサイトを指定して、検索結果をカスタマイズすることができます。

	- 設定方法
		1. 検索画面右上メニューバーをクリックして、`Customize Search`に移動する。


            ![Screen Shot 2023-06-01 at 21.25.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486680/ebadbd88-f9c5-64ef-9319-df4a61f7d68e.png)

		 2. `Paste in a url or enter a domain/keyword`に参考サイトのURLを入力する。
		 3. 参考サイト一覧の`RANK`で検索時の参考にするサイトの優先度を調節する。

			![Screen Shot 2023-06-01 at 21.23.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486680/549f6f89-1c80-e5d6-9d13-8879974554db.png)

# 参考
1. https://www.phind.com/
2. https://www.phind.com/tutorial