OmniAICreator/Qiita-1.07M huggingface dataset:
querySelectorAllについて

### const choices = Array.from(document.querySelectorAll('.form-check [name="answer[choices][]"]')).map(element => element.value);

chatgptにコード依頼を頼んだ際に記述されたコードが全くわからなかったので。

`querySelectorAll`
指定されたセレクターに一致する全ての要素を取得

`('.form-check [name="answer[choices][]"]'))`
formcheckクラス内に存在する[name="answer[choices][]"]'からとってくるイメージ

`Array.from`
取得したオブジェクトを配列に変換するメソッド。
querySelectorAllでは配列で返さないらしい。

`.map(element => element.value)`
valueで取得したものを新しい配列として返している。

したがって、const choices = Array.from(document.querySelectorAll('.form-check [name="answer[choices][]"]')).map(element => element.value); のコードは、指定されたセレクタに一致する要素を取得し、それぞれの要素の value プロパティを含む配列 choices を作成している
初めてのRspec

### Rspecについて

ここ最近悩みに悩んでいたrspec
少し進んだので。

まず何で悩んでいたのか。

### 正しい情報でユーザーを登録できることのテスト。
一番の初手で詰まるという大凡ミス。
というのもuser#createが少し複雑で

```
１userが作成される(@user.save)

２質問機能を表示させるための質問文、選択肢を取得
(@question = Question.find_by(question_text: 'どのようにUSJを楽しみたいですか。')
      @choice = Choice.find_by(question_id: @question.id))

３answer#newアクションにredierctする
(redirect_to new_answer_path(question_id: @question.id, choice_id: @choice.id)


```

という形。

```
def create
    @user = User.new(user_params)
    if @user.save
      session[:user_id] = @user.id
      @question = Question.find_by(question_text: 'どのようにUSJを楽しみたいですか。')
      @choice = Choice.find_by(question_id: @question.id)
      redirect_to new_answer_path(question_id: @question.id, choice_id: @choice.id)
    else
      flash.now[:danger] = '失敗しました'
      render :new
    end
  end
```

なのでuserが作成された後はよくあるindexアクションに飛ぶわけではない。

まず勘違いしていたこと。
### テスト環境では別のdbになる。
一番気づかないといけないところ。 (もう少し基礎を勉強しないとね。)
何ならこれに気づかなかったのでいつまで経ってもテストが成功しなかったのよね。

```
NoMethodError:
            undefined method `id' for nil:NilClass
          
                  @choice = Choice.find_by(question_id: @question.id)
```
そこで気づいた。
### テスト内でデータを作成しやんと。

何かないかなと昔使っていた書籍をペラペラ見ていると

### FactoryBotの説明を見つけた。

これだ！！

頭の中で
```
@question
@choice
を作成。
その後にuserを作成すれば成功できるのでは？
```

chatgptに聞きながらコードを編集していく。

```
 it '正しい情報でユーザーを登録できること' do
    @user = FactoryBot.create(:user)
    @question = FactoryBot.create(:question)
    @choice = FactoryBot.create(:choice)
    visit new_user_path

    fill_in 'user[name]' , with: 'test'
    fill_in 'user[email]', with: 'test@example.com'
    fill_in 'user[password]', with: 'password'
    fill_in 'user[password_confirmation]', with: 'password'
    click_button '登録'
    
    expect(page).to have_current_path(new_answer_path(question_id: @question.id, choice_id: @choice.id))
  end

```
最終のコードがこちら。
できた！！

ただ一つ疑問点が。
` expect(page).to have_current_path(new_answer_path(question_id: @question.id, choice_id: @choice.id))`
このコードなんだけど

元々は

` expect(current_path).to eq new_answer_path(question_id: @question.id, choice_id: @choice.id)`
このように書いていた。

だがこの場合

```
expected: "/answers/new?choice_id=1&question_id=1"
            got: "/answers/new"
```
このようなエラーが発生する。

エラーが出るのはわかったけど

どう違うのかがまだ少し腑に落ちていない感じがする。

どうやらcapybaraが関わってきてそうだけど

ここはもう少し勉強が必要そうだね。
src.rpmのビルドやデバッグのあれこれ

1. RHELサイトにログインして src.rpm をダウンロードする
nfs-utils-1.3.0-0.68.el7.src.rpm など

2. ビルドに必要なパッケージをインストールする
yum grouplist
yum groupinstall "Development Tools"


3. src.rpmを解凍する(1)
rpm2cpio <***.src.rpm> | cpio -idv

4. tar Jxvf <***.tar.xz>

5. Makefile.in から Makefile を生成する
./configure

#ここで依存ライブラリが環境に存在しない場合にエラーがでるので解決しながら、無事configurationコマンドを実行できるまで頑張る
#CLFAGSを変更したい場合はここで指定する
./configure CFLAGS=" -g -O0"

デバッグした時に行がとびとびになる場合はコード最適化のせい。-O0（大文字オー・ゼロ）をつける。

6. デバッグする
    1. コンソール
gdb mount.nfs
(gdb)> run 127.0.0.1:/nfs-shared /mnt
(gdb)> break main
(gdb)> next or n
  
    2. VSCode
デバッグで C/C++ のlanuch.json を設定してデバッグを実行する。
"program": "${workspaceFolder}/mount.nfs4",　デバッグするコマンドライン
"args": ["127.0.0.1:/nfs-shared", "/mnt"], コマンド実行の引数を設定する場合は配列に設定
"stopAtEntry": true, main関数で自動breakする場合true
プログラミングテストを効率化する方法～sqlファイルの保存～

目的：テストデータをすぐ作成できるようにする

a5m2でsqlファイルを保存する
sqlはsqlログから取得、パラメーター情報はソースでデバックをとり取得する
その方法が一番分かりやすい形で情報が取れる
sqlファイルの上部にはコメントで、
「使用する画面名」
「パラメータ情報」
「sql」
名を記載する

sqlファイルはローカルに画面単位ごとに保管し、検証などで使用したい際に随時使う
mecab-ipadic-neologdが見つからないと怒られる

つくりながら学ぶ! PyTorchによる発展ディープラーニングの第7章を実行中に`mecab-ipadic-neologd`が見つからないというエラーに遭遇したので，その解決法です．


本はこれです．

https://github.com/YutaroOgawa/pytorch_advanced



# エラー
発展Pytorchディープラーニングの実行に際して，`mecab-ipadic-neologd`が見つからないというエラーに遭遇．
解決の道のりを備忘録的に残します．

```
Traceback (most recent call last):
  File "/home/user_hoge/pytorch_advance/7_nlp_sentiment_transformer/7-1_Tokenizer.py", line 126, in <module>
    m_t = MeCab.Tagger('-Ochasen -d /usr/lib/mecab/dic/mecab-ipadic-neologd')
  File "/home/user_hoge/anaconda3/envs/MeCab/lib/python3.10/site-packages/MeCab.py", line 355, in __init__
    _MeCab.Tagger_swiginit(self, _MeCab.new_Tagger(*args))
RuntimeError
```

# 環境の準備
## Mecabの利用方法

ルート環境を汚染しないように仮想環境を構築

```
conda create -n MeCab python=3.10
conda activate MeCab
```

## 各種パッケージのインストール

必要なパッケージをインストール．MeCabだけは何故か`conda`でうまく入らないので，`pip`で入れましたが，原因は不明…

```
cd pytorch_advance/
conda install -y -c conda-forge mecab-python3
conda install -c conda-forge janome
pip install MeCab
```

# 解決法:プログラムの書き換え
7-1プログラムの125行目付近の`/usr/lib/mecab/dic/mecab-ipadic-neologd`がそれぞれの状況に合わせて変えなきゃいけない！

要するに，`mecab-ipadic-neologd`の場所がそれぞれの環境によって違うので，その場所を探して，正しい場所を探さないといけない．
そこで，今回は，`mecab-ipadic-neologd`が`/usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd`にあったので，下記のように7-1プログラムを書き換えることで動いた！
変更箇所が2箇所あり，面倒なので，変数`neodic_path`を宣言してます．

### 変更箇所

```diff_python:7-1_Tokenizer.py
# In[4]:
import MeCab

- m_t = MeCab.Tagger('-Ochasen -d /usr/lib/mecab/dic/mecab-ipadic-neologd')
+ neodic_path = '/usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd'
+ m_t = MeCab.Tagger("-Ochasen -d {} ".format(neodic_path))

text = '機械学習が好きです。'
print(m_t.parse(text))


# In[5]:
# 単語分割する関数を定義
- m_t = MeCab.Tagger('-Owakati -d /usr/lib/mecab/dic/mecab-ipadic-neologd')
+ m_t = MeCab.Tagger("-Owakati -d {} ".format(neodic_path))

def tokenizer_mecab(text):
    text = m_t.parse(text)  # これでスペースで単語が区切られる
    ret = text.strip().split()  # スペース部分で区切ったリストに変換
    return ret

text = '機械学習が好きです。'
print(tokenizer_mecab(text))
```


# 問題の特定方法

解決の道のりを備忘録的に残します．

そもそも，それ以前のMeCabはちゃんと動いていたので，MeCabには問題がないと判断
→`mecab-ipadic-neologd`（辞書）がないんじゃないかということで，辞書を探しに行きます．


`mecab-ipadic-neologd`ちゃんが入るところが間違っちゃったのかなと思って`find`コマンドで探すとその通りで無事見つけることができました．
流石に，辞書で`/usr/lib`以外にいっちゃうことはないと思うので，その中で探してまーす．


```
cd /
find ./usr/lib/ -path '*/mecab-ipadic-neologd'
```

すると，

```
./x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd
```

にあるとのことなので，プログラムを`/usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd`に合うように書き換えて無事解決！パチパチ

linuxの各ディレクトリの構成に関しては下記を参考にしてください．

https://qiita.com/usizou/items/be52822007d3c7ff639f

https://www.linuxmaster.jp/linux_skill/2010/02/06linux.html
EclipseでPG開発を効率化する方法～アウトラインとリファクタリング～

アウトライン：
ファイル内のfunctionに飛べるようになる
特に量が多いソースを触っているときに使える
リファクタリング：
項目名の一括変換ができる
今までは一ファイルずつ全置換で変更していたが、リファクタは全て変更できるので効率が上がった
AnimationMontage再生中に中断されたときに呼び出されるデリゲート【UnrealC++】

## 概要
AnimationMontage再生中に中断されたときに呼び出されるデリゲートの実装方法についての忘備録
(※エンジンのソースコードを読むことにまだ慣れていないので記事の内容が適切じゃない可能性があります。)

:::note info
実装するにあたって以下の3つを使用します。
・FOnMontageEnded
・CompleteDelegate.BindWeakLambda()
・Montage_SetEndDelegate()
:::

## サンプルコード

```c++:.cpp
	UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
	FOnMontageEnded CompleteDelegate; // デリゲート
	if (AnimInstance && ReloadMontage)
	{
		AnimInstance->Montage_Play(ReloadMontage);
		FName SectionName = FName("Reload");;
		AnimInstance->Montage_JumpToSection(SectionName);

		/*
        * AnimationMontageが中断した場合の処理
        * (例えばリロードアニメーション中に攻撃を受けたときリロードアニメーションを中断する実装をしている場合、
        * AnimationMontageで設定していたAnimNotifyが呼ばれなくなる問題に対応できる)
        */
		CompleteDelegate.BindWeakLambda(this, [this](UAnimMontage* animMontage, bool bInterrupted)->void
			{
				if (bInterrupted)
				{
					// アニメーションが中断した時
				}
				else
				{
					// アニメーションが問題なく終了した時
				}
			});
	}
    /*
    * ブロードキャストする
    * (BindWeakLambda内のanimMontageとbInterruptedはFAnimMontageInstance::Stopの中のInst->QueueMontageBlendingOutEventで設定されている)
    * (Broadcast自体はUAnimInstance::TriggerMontageEndedEvent()の中で行っている)
    */
	AnimInstance->Montage_SetEndDelegate(CompleteDelegate, ReloadMontage);
```
<br>
GPT-3.5とGPT-4の能力の違いについて、これなら納得できますか？

これまで、多くの人がGPT-3.5とGPT-4の違いについて言及されています。
納得できるような、納得できないような、場合によっては、GPT-3.5の方が自分にとって理解しやすいケースもありました。
でもやっぱりすっきりしません。
そこで私は以下のような実験をしてみました。
結果は、私にとっては答えが出たような気がします。
感じ方は人それぞれだと思いますので、各自ご判断ください。

### 共通の質問
```text
以下の文章を部下からメールでもらいました。
丁寧な口調で部下をなだめながら、やる気を起こさせる文章に修正してください。
***
これはあなたの仕事だし、あなたの責任で進めてきたことですよね。
どうして、今更、蔑ろにしてきた私に対して、のほほんと「やってくれ」なって言えるのですか？
```

### 結果

#### GPT3.5の場合
```text
件名: 重要な業務についてのお願い

拝啓、〇〇さん

ご連絡いただき、ありがとうございます。
お手紙を読ませていただきましたが、今回の件については、私の説明不足やお手本の提供不足があったかもしれません。
お気持ちをお伝えしにくくさせてしまい、申し訳ありません。

私はあなたの仕事への取り組みと責任感を高く評価しています。
これまでの成果を考えると、今回のミスは例外的なものだと思います。
私たちは、一緒に問題を解決し、今後のステップに向けて前進していく必要があります。

これからの業務については、改めて明確な指示とサポートを提供いたします。
私たちのチームは協力し合い、成功への道を共に歩んでいきます。
あなたの能力と貢献は、私たちの重要な要素ですし、私はあなたの力を信じています。

もし何か質問や懸念事項があれば、いつでも私にお知らせください。
私たちは共に働くことで、より良い結果を達成できることを信じています。

再度、お手紙をいただきありがとうございました。
私たちのチームと共に、前向きな姿勢で進んでまいりましょう。

よろしくお願いいたします。

心より、〇〇より
```
#### GPT4の場合
```text
拝啡 [部下の名前] 様、

メールをいただき、誠にありがとうございます。
貴重なご意見をお聞かせいただき、感謝申し上げます。

おっしゃる通り、これは私が担当し、責任を持って進めているプロジェクトでございます。
私のコミュニケーションが不十分であったことにより、誤解や不快な思いをさせてしまったこと、深くお詫び申し上げます。

[部下の名前] 様の専門的なスキルと経験は、このプロジェクトにとって大変貴重であり、チーム全体が成功に向かうための力となっています。
私があなたにお願いした理由は、あなたが頼りになる仲間であると確信しているからです。

ただし、私の言葉が不適切であったかもしれません。
私自身も学びながら成長していきたいと思っておりますので、お気づきの点やアドバイスを教えていただけると幸いです。

引き続き、[部下の名前] 様のご協力とサポートを賜りながら、共にこのプロジェクトを成功に導けるよう、ベストを尽くして参ります。何卒、よろしくお願い申し上げます。

敬具、

[あなたの名前]
```

### 以上です
シワの描き方

# はじめに
<!-- 発端や概要を記載 -->
シワの描き方・種類について有用な情報をまとめたもの。
プログラミングに関係ないけど、自分用のメモとなります。


# 目次
<!-- タイトルとアンカー名を編集 -->
1. [シワの種類](#Types_of_shiwa)
1. [Chapter2](#Chapter2)
1. [参考文献](#reference)

<!-- 各チャプター -->
<a id="Types_of_shiwa"></a>
# シワの種類
Youtubeの動画で参考になったので、記録しておく。
動画は以下。
<iframe width="560" height="315" src="https://www.youtube.com/embed/kV7VLV0o_yA" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

シワの種類には以下の5種類がある。
1. 引っ張りシワ
引っ張られたところを頂点として発生する。

1. 折り曲げシワ
折り曲げると、余った衣服が出っ張ることでできるシワ。

1. 回転シワ
一種の引っ張りシワ。
回転すると回転の向きに引っ張られてシワができる。
発生するのは腕のところくらい。

1. たるみシワ
下に布が貯まることで発生するシワ。
腕とか足のさきっぽに発生する。

1. ひねりシワ
雑巾とか、ひねることで発生するシワ。
人間だと上半身と下半身の向きが違ったりすると発生するシワ。




<a id="reference"></a>
# 参考文献
- [Youtube動画](https://www.youtube.com/watch?v=kV7VLV0o_yA)
変数の中で複数行に分けて書く場合でも改行をしない方法

変数の中で複数行を改行せず宣言する方法に詰まったので書き残します。
* 見やすく書きたかった
* PEP8の1行79文字以内の規約に引っ掛からないようにするため


```python
>>> a = "あいうえお"\
... "かきくけこ"
>>> 
>>> print(a)
あいうえおかきくけこ


# インデントは揃えたほうがいいかも

>>> b = "リンゴ"\
...     "ミカン"
>>> 
>>> print(b)
リンゴミカン
>>>
【Android】Androidアプリで緯度経度から住所を取得する【Kotlin】

# 実践

        val textView = findViewById<TextView>(R.id.text_view)
        val addresses: List<Address>? =
            Geocoder(this, Locale.getDefault()).getFromLocation(
                        35.710057714926265,
                        139.81071829999996,
                        1
                    )
        addresses?.first()?.adminArea?.let {
            textView.text  = it
        }

Geocoderの引数には　第一引数にcontext,第二引数にLocaleを渡します
第二引数にLocaleを渡すことで　好きな言語で表示することができます。

**Locale.getDefault()**　は　端末の言語設定をもとに言語を指定できます。

getFromLocationの引数には
スカイツリーの緯度35.710057714926265,　経度139.81071829999996
第三引数には　maxResults　が必要なので　適当に１を

これで　住所を取得できるので　それを **.adminArea**すると
住所を都道府県で取得することができます。
都道府県以外にも　国や郵便番号、市区町村や番地など詳しいところまで指定できるみたいです。
詳しくは　参考資料の所にある他の方の記事を見てください。



# 参考

https://qiita.com/kikuchy/items/c79241b0488cb40c1da6


https://qiita.com/kiyo1219/items/a7a4441b4857a24ff6cf
windows 11 上で Ubuntu 22.04.2 LTS を動かす

windows 11 上で Ubuntu 22.04.2 LTS を動かす方法です。
Windows Subsystem for Linux(WSL)を使います。

# 設定方法
## 1. windowsの機能の有効化
  1.  [設定] を起動する
  2.  [アプリ] → [オプション機能] を選択する
  3. [Windows のその他の機] をクリックする
  3. [Windows の機能の有効化または無効化]の画面が立ち上がるので、その中から[Linux用Windowsサブシステム]と[仮想マシンプラットフォーム]にチェックをつける
  3. [OK] をクリックする
  3. 再起動が要求されるので、PCを再起動する

## 2. Microsoft Storeでアプリを入手
  1.  [Windows Subsystem for Linux] を入手（ペンギンのアイコン）
  1.  [Ubuntu 22.04.2 LTS] を入手

## 3. Ubuntuのセットアップ
  1.  [Ubuntu 22.04.2 LTS] を開く
  1.  初期セットアップが開始されるので、しばらく待つ
  1.  ユーザー名とパスワードを設定する
  1.  最新の状態に更新
``` shell
sudo apt-get update
sudo apt-get upgrade -y
sudo apt autoremove -y
sudo apt autoclean
```

完成！
windows上でLinuxコマンドが使えるようになりました。

# 参考
- 図解！　Linuxコマンドのツボとコツがゼッタイにわかる本
「threadingを使用して開始したスレッド」を強制終了する

# 結論
`threading.Thread`を継承したカスタムスレッドクラスを用意し、強制終了する関数を用意させておきます。これによって強制終了が可能になります。ただし、Threadingにはそもそも直接強制終了させる手段がないという点を知った上での自己責任で実装したほうが良さそうです。

# サンプルコード
```.py
import threading

import ctypes
import time

# カスタムスレッドクラス
class twe(threading.Thread):
    def __init__(self, group=None, target=None, name=None, args=(), kwargs={}):
        threading.Thread.__init__(self, group=group, target=target, name=name)
        self.args = args
        self.kwargs = kwargs
        return
    
    def run(self):
        self._target(*self.args, **self.kwargs)

    def get_id(self):
        if hasattr(self, '_thread_id'):
            return self._thread_id
        for id, thread in threading._active.items():
            if thread is self:
                return id
    
    # 強制終了させる関数
    def raise_exception(self):
        thread_id = self.get_id()
        resu = ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(thread_id), ctypes.py_object(SystemExit))
        if resu > 1:
            ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(thread_id), 0)
            print('Failure in raising exception')

# 開始するスレッドで実行する関数
def sample_func(a, b, c, hoge1 = None, hoge2 = None, hoge3 = None):
    try:
        while True:
            print((a, b, c, hoge1, hoge2, hoge3))
            time.sleep(1)
    finally:
          print('ended')

def main():
    # 開始するスレッドを定義
    # targetに実行する関数
    # args, kwargsには関数に渡す引数
    x = twe(name = 'Thread A', target=sample_func, args=(1, 2, 3), kwargs={'hoge1': 'hogehoge1', 'hoge2': 'hogehoge2', 'hoge3': 'hogehoge3'})
    # スレッド開始
    x.start()
    # 10秒間、開始したスレッドが処理し続ける
    time.sleep(10)
    # raise_exceptionを呼び出すことでスレッドが終了
    x.raise_exception()
    # 既に終了しているので処理を待機しないはず
    x.join()

if __name__ == '__main__':
    main() 
```

```
(1, 2, 3, 'hogehoge1', 'hogehoge2', 'hogehoge3')
(1, 2, 3, 'hogehoge1', 'hogehoge2', 'hogehoge3')
(1, 2, 3, 'hogehoge1', 'hogehoge2', 'hogehoge3')
(1, 2, 3, 'hogehoge1', 'hogehoge2', 'hogehoge3')
(1, 2, 3, 'hogehoge1', 'hogehoge2', 'hogehoge3')
(1, 2, 3, 'hogehoge1', 'hogehoge2', 'hogehoge3')
(1, 2, 3, 'hogehoge1', 'hogehoge2', 'hogehoge3')
(1, 2, 3, 'hogehoge1', 'hogehoge2', 'hogehoge3')
(1, 2, 3, 'hogehoge1', 'hogehoge2', 'hogehoge3')
(1, 2, 3, 'hogehoge1', 'hogehoge2', 'hogehoge3')
ended
```

# 注意事項
`threading`はそもそも直接強制終了する手段を提供していないようです。だからこそ、カスタムクラスを用意して実装させているわけです。おそらく、`threading`を使用するときは安全にスレッドを終了させてほしいという意味もあると思います。このことを知った上で自己責任で実装したほうが良さそうです。

以上です。

# 参考

https://www.delftstack.com/ja/howto/python/python-kill-thread/

https://ja.pymotw.com/2/threading/
ローカルで新しく作ったプロジェクトをGitGUIクライアントForkからGitHubにプッシュする

# ローカルで新しく作ったプロジェクトをForkからGitHubにプッシュする
# はじめに
自分用のメモです。
適当にテキストファイルをいれたディレクトリを用意します。

#### ローカルで新しいGitリポジトリを作成する
Forkを開き、「File」メニューから「Create New Local Repository」を選択します。ローカルリポジトリにしたい先ほど用意したディレクトリを選択します。

#### リポジトリをコミット
新しいリポジトリが作成されると、そのリポジトリのディレクトリの中のファイルがLocal Changesで確認できます。Forkを使って、ファイルをステージングエリアに追加し、コミットします。

#### GitHubで新しいリポジトリを作成する
WebブラウザでGitHubを開き、新しいリポジトリを作成します。
#### ローカルリポジトリをGitHubのリモートリポジトリにリンクする
GitHubの新しいリポジトリページからリポジトリのURLをコピーします。それから、Forkのローカルリポジトリを開き、「Repository」メニューから「Push」を選択するか上にあるPushアイコンをクリックします。
add remoteをクリックするとリモートリポジトリのURLのコピーをもった状態だと自動で入力されてます。間違いないことを確認しプッシュします。
【bitbucket】リモート側のhost keyが変わってエラーになった際の対処法

# はじめに
今回リモートへプッシュやプルをしようとした際、【REMOTE HOST IDENTIFICATION HAS CHANGED!】とエラーが表示されました。
これはリモート側のキーが変わることで起こるエラーですが、Githubやその他クライアントでも同じことが起こりえます。
どのクライアントでも基本的に同じ対応でいけると思いますが、今回は上記エラーの対処法を備忘録的にまとめておこうと思います。

# エラーの対処法
まず、表示されるエラーは以下のような構文です。
```
Pushing to bitbucket.org:XXXX.git
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
SHA256:XXXXXXXXX.
Please contact your system administrator.
Add correct host key in XXXX.ssh/known_hosts to get rid of this message.
Offending RSA key in XXXX.ssh/known_hosts:3
Host key for bitbucket.org has changed and you have requested strict checking.
Host key verification failed.
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
```
翻訳すると半ば脅しのようなエラーになっていますが、、、
原因はシンプルで冒頭でご説明した通り、リモート側のhost keyが変わったことによるエラーのようです。

上記が原因なので、対処法としては現状のKeyを新しいものに置き換える必要があります。
キーの置き換えは以下を実行することで対応可能です。

```
ssh-keygen -R bitbucket.org && curl https://bitbucket.org/site/ssh >> ~/.ssh/known_hosts
```
対応としては以上になります。

# さいごに
対応方法がわかっていたとしてもこの手のエラーは一瞬ドキっとしますよね、、、
JSとPHPの類似機能比較 ~その1~

# はじめに
以下の違いは、基本的には記載しない。
- 言語環境
- メソッドと関数の違い

また私的メモのため、曖昧な部分もある。（アドバイスは歓迎）

# indexOfとstrpos
どちらも呼び出すStringの中から指定された値が最初に現れたインデックスを返す。
位置の計算は0から始まる。

:::note alert
違い
`indexOf`が値がなかったら-1を返すのに対し、`strpos`はfalseを返す。
:::

# toUpperCaseとstrtoupper
どちらも文字列を大文字にする。

# lengthとstrlen
文字列の長さを返す。

:::note alert
違い
`strlen`が返すのはバイト数であり、 文字数ではない。
:::

そのため、UTF-8でエンコードされた多バイト文字を扱うときに違いが出る。
以下は "こんにちは" がUTF-8でエンコードされていて、各日本語文字が3バイトで表現されている。

```php:php
$str = 'こんにちは';
echo strlen($str); // 15
```

```javascript:javascript
let str = 'こんにちは';
console.log(str.length); // 5
```
vue3 watcheffect

vue3で移動前、移動後のパスを取得したい。

# watchEffectを使う



```app.js

import router from './router.js'			
import {createApp, reactive, ref,watchEffect} from 'vue'

import App from './App.vue'
const app = createApp(App)
app.use(router)

const state = reactive({
    prevPath: '',
})
watchEffect(() => {
    const currentPath = router.currentRoute.value.fullPath
    console.log(`Navigated from ${state.prevPath} to ${currentPath}`)
    state.prevPath = currentPath
})

app.mount("#app")

```

以上
wikipediaのAPIを使ってゲーム作ってみた#1

# はじめに

初めまして！いっとんです。
プログラミングの勉強を兼ねて、投稿を始めてみました！
プログラミングの勉強を始めて1・2年のペーペーですがよろしくお願いします！

さて、今回は最近参加したハッカソンでAPIを触る機会があったので、APIを使って何か作れないかな？と考えた結果、wikipediaを使ったゲームを思いついたので、早速作ってみました。

# ゲームの概要
ゲームのルールはこんな感じです。

2つのワードを受け取る（例：日本と織田信長）
↓
一方をスタート、もう一方をゴールにする（※日本をスタート、織田信長をゴールとする）
↓
wikipediaの記事にはワードにそのワードのページに飛ぶことができるリンクが貼ってあるので、そのリンクをクリックしてゴールのワードのページを目指す（※「日本→歴史→戦国時代→織田信長」みたいな感じ）
↓
ゴールのページに到着すればクリア（※将来的に点数を付けたりしたいが、そこら辺のルール設定は未定）

# 開発環境
Djangoを使っていきます！
理由は最近使ってるからです！！（いつかUnityとか使って開発したいなあ）

## 作業開始
今回、pythonのインストールや基本的なdjangoの開発準備は割愛させていただきます。
プロジェクト名：wikiword
アプリ名：main
### 1.wikipediaから情報を取得
難しいのかなと思ったら結構簡単でした。

まずターミナルでwikipediaapiをインストールします。
```
pip install wikipediaapi
```
views.pyでインポートします
```python:views.py
import wikipediaapi
```
これで準備完了。

続いて、検索ワードを指定して文章を出力します。
```python:views.py
import wikipediaapi

# 取得する言語を日本語に設定
wiki_wiki = wikipediaapi.Wikipedia('ja')

# 検索ワードを指定してページを取得
page = wiki_wiki.page("検索ワード")

# ページの内容を出力
print(page.text)
```
これで"検索ワード"の所に自由なワードを入れれば、そのワードの記事が出力されます。

はい、終わり。
めちゃくちゃ簡単でした。

### 2.wikipediaみたいな見た目にする

しかし、このままでは章の名前とか段落とかがぐちゃぐちゃになっちゃいます。
調べた結果、どうやらこいつ↓を追加するとWikipediaのページをHTML形式で取得できるっぽいです。
```python
変数=wikipediaapi.ExtractFormat.HTML
```
助手のChatGPT君と一緒に作った結果、最終的に以下のようなコードになりました。
```python:views.py
# main
def main(request):
    import wikipediaapi
    # wikipediaapiのデータの形式を設定
    wiki_wiki = wikipediaapi.Wikipedia(
    # 日本語
    language='ja',
    # HTML形式
    extract_format=wikipediaapi.ExtractFormat.HTML,
    # ユーザーエージェントってやつ。詳しくは後程
    user_agent='CoolBot/0.0 (https://example.org/coolbot/; coolbot@example.org)'
    )

    # 検索ワード
    # 今回は仮として「みかん」と置いています。
    page_py = wiki_wiki.page("みかん")    

    # 検索ワードを発見した時
    if page_py.exists():
        #「みかん」のページのタイトルを入れる
        page_title = page_py.title
        #「みかん」のページの文章を入れる
        page_text = page_py.text

    # 検索ワードが見つからなかった場合
    else:
        page_text = 'ページが見つかりませんでした。'

    return render(request, 'main/main.html', {
        'page_text': page_text, 
        'page_title': page_title,
        })
```
```HAML:main.html
    <div class="main-text" id="main-text">
        <h1>{{ page_title }}</h1>
        <p>{{ page_title|safe }}</p>
        <!--safeを追記することで<h1>とかのhtmlタグを適用させることができる-->
    </div>
```

これで、本物のwikipediのページみたいにすることができました。

mainのユーザーエージェント(user_agent)は僕もあまり分かっていないのですが、ChatGPT君によると「HTTPリクエストを送信するクライアント（通常はWebブラウザやプログラム）が自身を識別するためにサーバーに送信する情報の一部」だそうです。

今回のような検索したワードの情報を出力するだけのコードを書いている時は必要なかったのですが、この先の工程で突然求められるようになったので、念のため記載しておきます。

https://meta.wikimedia.org/wiki/User-Agent_policy/ja

上のページに載ってあったコードをベタ張りしています。
詳しい方、教えていただけるとありがたいです・・・。

# おわりに
というわけで、今回はwikipediaの情報を入手するところまで紹介しました。
次回は、受け取った記事には、wikipediaみたいにワードにそのワードのページに遷移するリンクが貼られていないので、この部分をなんとかする回にしたいと思います。

ちなみに、ゲーム自体は遊べる程度には完成しているので、興味がある方は是非Githubから遊んでみてください。(まだCSSとかは全くないです）

コードや記事の改善点や質問があればぜひ！！

Github:https://github.com/ITTON2001/WikiWord
AWS_PROFILEとAWS_DEFAULT_PROFILEの優先順位

# プロファイル設定の優先順位

## `AWS_PROFILE` > `AWS_DEFAULT_PROFILE` > `default`

| `AWS_PROFILE` | `AWS_DEFAULT_PROFILE` | 適用されるプロファイル |
|:-:|:-:|:-:|
| 未設定 | 未設定 | default |
| 未設定 | user1 | user1 |
| user0 | 未設定 | user0 |
| user0 | user1 | user0 |

- [AWS CLI](https://aws.amazon.com/cli/)
- [AWS SDK for Python (Boto3)](https://aws.amazon.com/jp/sdk-for-python/)

## `AWS_PROFILE` > `default`

| `AWS_PROFILE` | `AWS_DEFAULT_PROFILE` | 適用されるプロファイル |
|:-:|:-:|:-:|
| 未設定 | 未設定 | default |
| 未設定 | user1 | **default** |
| user0 | 未設定 | user0 |
| user0 | user1 | user0 |

- [AWS SDK for Java](https://aws.amazon.com/jp/sdk-for-java/)
- [AWS SDK for JavaScript](https://aws.amazon.com/jp/sdk-for-javascript/)
- [AWS SDK for .NET](https://aws.amazon.com/jp/sdk-for-net/)

## 結論

以下のことからも`AWS_DEFAULT_PROFILE`は使用しない方が無難

- Boto3以外のAWS SDKでは、`AWS_DEFAULT_PROFILE`は参照すらされていない
- ググると出てくるけど、AWSのドキュメントに`AWS_DEFAULT_PROFILE`の記載がない(昔はあった？)
- 優先順位を考えるのが手間。(`AWS_PROFILE`に設定しているか否か)
旧バージョンの Delphi に FireDAC をインストールするには？

# はじめに
FireDAC が使える後続のバージョンの Delphi を持っている場合、FireDAC を旧バージョンにインストールする事が可能かもしれません。

# FireDAC
FireDACは、エンタープライズデータベースへの接続性を提供するマルチデバイス対応の共通データアクセスライブラリです。InterBase、SQLite、MySQL、SQL Server、Oracle、PostreSQL、IBM DB2、Informix、SQL Anywhere、MongoDB などをサポートしています。

:::note
元々は DA-SOFT の『AnyDAC』という製品でした。
:::

 - [FireDAC (Embarcadero)](https://www.embarcadero.com/jp/products/rad-studio/firedac)
 - [FireDAC プレスリリース (Embarcadero)](https://www.embarcadero.com/jp/press-releases/firedac)

## FireDAC 8.0.5
XE4 の FireDAC C/S アドオンパックが利用可能な場合、Delphi 5 ～ XE4 の IDE にインストール可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/c381a109-0d24-9931-4a45-a849df8abe05.png)
SKU やモバイルアドオンパックの所持の有無によってダウンロードすべきファイルが異なります。

| FireDAC C/S アドオンパック | インストーラー名| 説明 |
|:---|:---|:---|
| [29458, FireDAC XE4 Update 2 for RAD Studio/Delphi/C++ Ent/Ult/Arch](https://cc.embarcadero.com/item/29458) | FireDAC_8.0.5.3365.exe | Enterprise 以上の SKU の RAD Studio / Delphi / C++Builder ユーザー向け |
| [29457: FireDAC Client/Server Add-On Pack Upd 2 for Delphi/C++/RAD XE4](https://cc.embarcadero.com/item/29457)  | FireDAC_8.0.5.3365.exe | モバイルアドオンを持っていない Delphi Professional ユーザーまたは RAD Studio / C++Builder Professional ユーザー向け |
| [29459: FireDAC XE4 Update 2 for RAD Studio Pro & Delphi Pro w/ Mobile](https://cc.embarcadero.com/item/29458) | FireDAC_8.0.5.3365_Mobile.exe | モバイルアドオンを持っている Delphi Professional ユーザー向け |

:::note
29457 と 29458 のインストーラは同じもののようです。
:::

### ダウンロード
上記ダウンロードリンクが有効でない場合、**Registered Products Portal**からダウンロードしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/8006ea54-b12f-6d97-6d65-dd84628287f2.png)

 - [Registered Products Portal (my.embarcadero.com)](https://my.embarcadero.com/)

### FireDAC のインストール
ダウンロードしたインストーラに `/SHOWIDE` を付けて起動すると、インストールする IDE を選択できます。

```
FireDAC_8.0.5.3365.exe /SHOWIDE
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/f7494af1-c4f0-ba86-68f0-d6e73131a394.png)

:::note warn
Delphi 自体のアップデータを事前に適用しておく必要があります。
:::

:::note warn
uADStanCipher.pas は輸出規制のため同梱されていません。コンパイル済ユニット (uADStanCipher.dcu) のみが同梱されています。
:::

## FireDAC 7.0.1

XE3 の FireDAC C/S アドオンパック (7.0.1) も 8.0.5 と同様のスイッチで旧バージョンへインストールできます。


## その他
海外製インストーラーには (よく) 罠があるので、問題があったら次の事を試してみてください。

 - インストーラは管理者権限で実行した方がいいかもしれません。
 - インストーラは `C:\WORK` のような日本語や空白が含まれないフォルダで実行した方がいいかもしれません。
 - アカウントに日本語が含まれている場合、`OWNER` のような管理者アカウントを作ってそこからインストールした方がいいかもしれません。
 - XP 環境ではインストールできないかもしれません。

# おわりに
8.0.5 は古いバージョンの FireDAC ですが、何かの時に役に立つかもしれません。

このバージョンの FireDAC はまだリファクタリングが進んでおらず、コンポーネント名が AnyDAC 準拠になっており、内部的にも AnyDAC の識別子が使われていたりと、現在の FireDAC とは互換性が取れない部分がある事には注意が必要です。

**See also:**

 - [XE3 以外の IDE のバージョンに FireDAC をインストールする (SupportKB)](https://support.embarcadero.com/jp/article/42975)
 - [AnyDAC および XE3 / XE4 FireDAC から XE5 FireDAC への移行について (SupportKB)](https://support.embarcadero.com/article/43590)
Public Domain のクラシック音楽を探す

定番のものもどんどん変わっていく感じなので、今後も整備していくつもりのメモ。

# 日本

「パブリックドメイン、public domainの名曲、名演名盤の音楽zipファイルをDL。楽譜、着メロ、着うた、BGM音源、インターネットラジオ、midiも近日配信。」
http://freeclassicmusicmp3.blog23.fc2.com/ 
以前よくお世話になっていたが、移転した模様
↓
「クラシック音楽mp3無料ダウンロード 著作権切れパブリックドメインの歴史的音源」
http://classicalmusicmp3freedownload.com/ja/index.php?title=%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8


「国立国会図書館デジタルコレクション」
https://rekion.dl.ndl.go.jp/ja/
国会図書館歴史的音源。日本の曲が多いです。


# 海外


「Royalty Free Music - Download over 100,000 mp3 files free | Musopen」
https://musopen.org/music/
楽譜が主ですが音源もあります。Wikipediaの音源によく使われています。


米空軍の儀礼用音楽
https://www.music.af.mil/Multimedia/Music/Public-Domain-Music/
Holiday Musicなんかもあって楽しい!

インターネット・アーカイブ
https://archive.org/
ジャンル分けとか無いので、ひたすら検索。
「主よ御許に近づかん」の合唱でいいのがないかなと探していて、これを使いました。
https://archive.org/details/78_nearer-my-god-to-thee_westminster-central-hall-choir-harris-arthur-l



youtube の publicdomainclassicalmusic3961 チャンネル
https://www.youtube.com/@publicdomainclassicalmusic3961

# 番外


国際楽譜ライブラリープロジェクト (International Music Score Library Project)
https://imslp.org/
楽譜ライブラリーですが音源がついている場合もあります

Open Music Archive
http://www.openmusicarchive.org/
クラシックは無さげ。

「Classical - Free Music Archive」
https://freemusicarchive.org/genre/Classical/
ジャンルとして「classical」クラシックがありますが、クラシック風音楽という感じです。


# Up to date

良さそうなものが見つかり次第追加していきます
基本情報技術者試験用語解説

# はじめに
基本情報技術者試験の勉強中にわからなかった用語を調べ、まとめた記事。
私的メモのため、随時更新していく。

# テクノロジ系
### 基礎理論
[待ち行列](https://wa3.i-3-i.info/word14718.html)

### ネットワーク
[CSMA/CD](https://wa3.i-3-i.info/word12183.html)
[DMZ](https://wa3.i-3-i.info/word12988.html)
[SNTP](https://wa3.i-3-i.info/word12623.html)
[OSI基本参照モデル](https://wa3.i-3-i.info/word1783.html)
[ブリッジ](https://wa3.i-3-i.info/word12031.html)
[OpenFlow](https://wa3.i-3-i.info/word12696.html)
[RARP](https://wa3.i-3-i.info/word175.html)

### データベース
[正規形](https://tech.012grp.co.jp/entry/db_normalization)
[ロールバック](https://wa3.i-3-i.info/word143.html)
[ロールバックとロールフォワードの違い](https://wa3.i-3-i.info/diff350db.html)

### セキュリティ
[チャレンジレスポンス方式](https://wa3.i-3-i.info/word12764.html)
[楕円曲線暗号](https://wa3.i-3-i.info/word17540.html)
[共通鍵暗号方式](https://wa3.i-3-i.info/word1837.html)
[公開鍵暗号方式](https://wa3.i-3-i.info/word1828.html)

### システム開発技術
[スタブ](https://wa3.i-3-i.info/word14933.html)
[UML](https://wa3.i-3-i.info/word17654.html)
[アクティビティ図](https://wa3.i-3-i.info/word110330.html)
[ユースケース図](https://wa3.i-3-i.info/word16098.html)
[状態遷移図](https://wa3.i-3-i.info/word16328.html)
[命令網羅(C1)](https://wa3.i-3-i.info/word15878.html)
[判定条件網羅(C2)](https://wa3.i-3-i.info/word15879.html)
[条件網羅(C3)](https://wa3.i-3-i.info/word15881.html)
[判定条件網羅と条件網羅](https://wa3.i-3-i.info/diff840test.html)

### アルゴリズムとプログラミング
[ガベージコレクション](https://wa3.i-3-i.info/word1176.html)
[クイックソート](https://wa3.i-3-i.info/word16752.html)
[基本選択法](https://wa3.i-3-i.info/word18247.html)
[基本挿入法](https://wa3.i-3-i.info/word18251.html)
[基本交換法](https://wa3.i-3-i.info/word14889.html)

### コンピュータ構成要素
[レジスタ](https://wa3.i-3-i.info/word1518.html)

# マネジメント系
### プロジェクトマネジメント
[EVM](https://wa3.i-3-i.info/word16508.html)
[アローダイアグラム](https://wa3.i-3-i.info/word15926.html)
[ガントチャート](https://wa3.i-3-i.info/word16111.html)
1514. Path with Maximum Probability

https://leetcode.com/problems/path-with-maximum-probability/description/

# アプローチ
- ダイクストラ

```java
class Solution {
   public double maxProbability(int n, int[][] edges, double[] succProb, int start, int end) {

        double[] calculatedCosts = new double[n];

        // この問題は、一般ダイクストラとは違い、コストが一番多いことを選択する必要がありますので、0を設定する必要がある
        Arrays.fill(calculatedCosts, 0.0);

        ArrayList<ArrayList<Node1514>> graph = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            graph.add(new ArrayList<>());
        }

        // 両方面移動できるので、各ノード別に移動するコストを保存する
        for (int i = 0; i < succProb.length; i++) {
            graph.get(edges[i][0]).add(new Node1514(edges[i][1], succProb[i]));
            graph.get(edges[i][1]).add(new Node1514(edges[i][0], succProb[i]));
        }

        PriorityQueue<Node1514> pq = new PriorityQueue<>();

        // スタートポイントコストは1で初期化
        // 掛け算を行うので
        pq.add(new Node1514(start, 1));
        calculatedCosts[start] = 1;

        while (!pq.isEmpty()) {

            Node1514 nowPoint = pq.poll();
            // 現在のノードと、コストを取得する
            int currentNode = nowPoint.node;
            double currentCost = nowPoint.cost;

            // 他の場所で計算されたコスト（costs[nodNode]）が、現在のコスト（cost）より大きい場合、処理する必要がないので、Continueする
            if (currentCost < calculatedCosts[currentNode]) {
                continue;
            }


            // グラフ内部の健在のノードから、連結されているノードを確認する
            for (Node1514 nextNode : graph.get(currentNode)) {
                int nextNodeNumber = nextNode.node;

                // 現在ノードから計算されているコストと、連結されているノードのコストを計算する（問題自体が掛け算するので、掛け算を行う）
                double nextCost = calculatedCosts[currentNode] * nextNode.cost;

                // 現在ノードの計算されているコストより、上の上で新しく計算されたコストが大きい場合、保存する
                if (calculatedCosts[nextNodeNumber] < nextCost) {
                    calculatedCosts[nextNodeNumber] = nextCost;
                    pq.add(new Node1514(nextNodeNumber, nextCost));
                }
            }
        }
        return calculatedCosts[end];
    }

    public class Node1514 implements Comparable<Node1514> {
        int node;
        double cost;

        Node1514(int node, double cost) {
            this.node = node;
            this.cost = cost;
        }

        @Override
        //コストを基準で降順整列する
        public int compareTo(Node1514 o) {
            if (this.cost < o.cost) {
                return 1;
            }
            return -1;
        }
    }
}

```

https://leetcode.com/problems/path-with-maximum-probability/solutions/3691148/java-easy-solution/

上記の解説を参考しました
Github Pages

# Github Pages 使い方
Github PagesでのWebページの公開方法です。


## 0. Githubアカウントの作成
Githubのアカウントがない場合は、[Github](https://github.com/)から登録する

## 1. リポジトリの作成
Githubでリポジトリを作成する。
リポジトリ名は基本的になんでもよいが、リポジトリ名によって公開するURLが変わるので注意。

- リポジトリ名を`アカウント名.github.io`とした場合
  - 公開URLは https://アカウント名.github.io 
- 上記以外の場合
  - 公開URLは https://アカウント名.github.io/リポジトリ名

## 2. リポジトリにファイルを更新
ローカルからプッシュなり、GitHub上で直接ファイル更新なりして、
必要なファイルをリポジトリに更新


## 3. サイト公開
1. Githubからリポジトリのページに移動

2. Settings を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2157731/78dabecb-0f12-9e77-aad0-1d8aee87fda3.png)

3. サイドバーの Pages を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2157731/430fdd03-3e8b-ad65-4c6e-9a39fc1d1933.png)

4. Branch を指定し、save をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2157731/cb874c36-ef61-1974-556a-c036c291196a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2157731/bc89bf09-70a9-d559-4620-822812b3e6fc.png)

これで公開完了。
公開URLにアクセスできるか確認する。
rex0220 計算式プラグイン テーブル行内で集計

kintone のテーブル行内で、値の集計を[計算式プラグイン](https://qiita.com/rex0220/items/ae83c6d5ce50ff7a9a73)で行います。

# 概要

テーブル行内の同じ科目を集計し、文字列項目に表示します。

![2023-07-02_18h41_55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/45ef5104-7f66-0d23-c53d-38555c860a8a.png)

# 操作例

![2023-07-02_18h53_34.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/e5866759-18b9-6e20-93f7-c34e626014bb.gif)


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

科目の値をいろいろ加工するため、LET 関数で変数を利用します。
![2023-07-02_18h44_27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/57f192e4-1768-5814-4deb-a03a1772f72f.png)

```.js
// まとめ
LET(a,ARRAY(_1時限目,_2時限目,_3時限目,_4時限目,_5時限目), // 科目を配列化
  b,ARRAY_SORT(DISTINCT(ARRAY_FIL(a,x,x))),  // ブランク・重複値を除外して、ソート
  c,ARRAY_MAP(b,x,x&"・"&ARRAY_COUNT(ARRAY_FIL(a,y,x=y))), // 科目に件数を追加した配列
  JOIN(c,", ")  // 配列を", "で連結
)
```
ちゃんと理解するJavaScriptの非同期処理とPromiseについて

この記事では、非同期処理とは何か、またそれをうまく扱うためのPromiseという仕組みについて解説します。

### 非同期処理とは？

同期処理とは、ソースコードが上から順に一つずつ処理されることを指します。つまり、ある行の処理が完了するまで、次の行には進みません。これに対して非同期処理とは、ある行の処理が完了するのを待たずに次の行に進むことができる処理方法です。この非同期処理は、時間がかかる処理（例えば、大量のデータをフェッチする、大規模な計算を行う等）がある場合に特に有用です。

### Promiseとは？

Promiseとは非同期処理の結果を扱うためのオブジェクトで、JavaScriptに組み込まれています。Promiseを利用すると、非同期処理が成功したときの処理と失敗したときの処理を簡潔に記述できます。

Promiseは`resolve`と`reject`という2つの関数を引数に取るコンストラクタで生成されます。`resolve`関数は非同期処理が成功した場合に呼び出され、Promiseを「満たされた（fulfilled）」状態にします。一方、`reject`関数は何らかの理由で非同期処理が失敗した場合に呼び出され、Promiseを「拒否された（rejected）」状態にします。それぞれの状態に応じて、後続の処理を`.then()`メソッドや`.catch()`メソッドで定義できます。

### 実際のコードを見てみよう

次の例は、非同期のAPIリクエストを模擬したコードです。

```javascript
function apiCall(url) {
  return new Promise( (resolve, reject) => {
    setTimeout( () => {
      if(url === 'https://api.example.com/data') {
        resolve({ data: '成功しました！' });
      } else {
        reject('エラー：無効なURL');
      }
    }, 2000);
  });
}

apiCall('https://api.example.com/data')
  .then(response => console.log(response.data))
  .catch(error => console.log(error));

apiCall('https://api.invalid.com')
  .then(response => console.log(response.data))
  .catch(error => console.log(error));
```


上記の`apiCall`関数は、非同期のAPIリクエストをシミュレートしています。この関数はPromiseを返し、そのPromiseは2秒後に解決または拒否されます。解決の場合、`resolve`関数が呼び出され、`.then()`メソッドで定義した処理が実行されます。一方、拒否の場合、`reject`関数が呼び出され、`.catch()`メソッドで定義したエラーハンドリングが実行されます。

具体的な例とその結果を以下に示します。

#### 成功した場合

上記のコードのうち、次の部分は有効なURLを`apiCall`関数に渡し、Promiseが解決される例を示しています。

```javascript
apiCall('https://api.example.com/data')
  .then(response => console.log(response.data))
  .catch(error => console.log(error));
```

このコードを実行すると、関数`apiCall`は有効なURL（`https://api.example.com/data`）を引数として受け取ります。その後、非同期処理が始まり、2秒後に`resolve`関数が呼び出されます。`resolve`関数は`{ data: '成功しました！' }`というオブジェクトを引数として取り、このオブジェクトが次の`.then()`メソッドに渡されます。`.then()`メソッドの中で定義されている関数が実行され、コンソールに"成功しました！"と表示されます。

#### 失敗した場合

次に、以下の部分は無効なURLを`apiCall`関数に渡し、Promiseが拒否される例を示しています。

```javascript
apiCall('https://api.invalid.com')
  .then(response => console.log(response.data))
  .catch(error => console.log(error));
```

このコードを実行すると、関数`apiCall`は無効なURL（`https://api.invalid.com`）を引数として受け取ります。その後、非同期処理が始まり、2秒後に`reject`関数が呼び出されます。`reject`関数は"エラー：無効なURL"という文字列を引数として取り、この文字列が次の`.catch()`メソッドに渡されます。`.catch()`メソッドの中で定義されている関数が実行され、コンソールに"エラー：無効なURL"と表示されます。

以上のように、Promiseの`resolve`と`reject`は、それぞれ非同期処理が成功したときと失敗したときの結果を次の処理に渡す役割を果たします。そして、`.then()`と`.catch()`メソッドを使用して、これらの結果をハンドリングします。
この例から、Promiseを使うと非同期処理が成功した場合と失敗した場合の両方に対応した処理を柔軟かつ簡潔に記述できることがわかります。

### まとめ

非同期処理はJavaScriptで頻繁に扱われ、特にデータを扱うウェブアプリケーションでは必須の知識です。しかし、非同期処理は複雑になりがちで、コードの流れを理解しにくくなることがあります。Promiseを用いることで、この非同期処理の結果をうまく扱い、流れを制御することができます。これにより、より綺麗で理解しやすいコードを書くことが可能となります。
platform.iniで#defineを定義する

今まで、
```main.ino
#define INI_ATOMS3
//#define INI_ATOM

#ifdef INI_ATOMS3
#define TRIG_PIN (5)
#define ECHO_PIN (6)
#define MOTOR_PIN (8)
#endif
#ifdef INI_ATOM
#define TRIG_PIN (25)
#define ECHO_PIN (21)
#define MOTOR_PIN (33)
#endif
:
```
こんな感じで先頭で#defineをきりかえつつ、platform.iniでも
```platform.ini
[env:m5stack-atoms3]
;[env:m5stack-atom]
platform = espressif32
board = m5stack-atoms3
;board = m5stack-atom
framework = arduino
build_flags = -D INI_ATOMS3
:
```
のように盛大に書き換えていましたが、

```platform.ini
[platformio]
;default_envs = m5stack-atoms3
default_envs = m5stack-atom

[env:m5stack-atoms3]
platform = espressif32
board = m5stack-atoms3
framework = arduino
build_flags = -D INI_ATOMS3

[env:m5stack-atom]
platform = espressif32
board = m5stack-atom
framework = arduino
build_flags = -D INI_ATOM
:
```
とすることでplatform.iniの先頭を変更するだけで済み、ソースコードで
```#define INI_ATOMS3```
のように定義したりコメントアウトしなくても済むようになりました。
今さらですが、便利。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/6fe834ee-5d73-362d-a8d7-27fbfb958da1.png)
Boardsのところにも列挙されます。便利！
supertest で Cloud Functions for Firebase のオフライン単体テストを書く

## 概要

Cloud Functions for Firebase (以下 functions) の関数をオフラインで単体テストします。

※ functions の関数のテストはどちらかというとシステムテストっぽくなりがちですが、公式に従って単体テストと呼称します。

https://firebase.google.com/docs/functions/unit-testing?hl=ja

↑公式ドキュメントによると、関数をテストするためにはオンラインモードとオフラインモードの2種類を選択することができます。
さらに、オンラインモードの場合はテスト用のプロジェクトを使って動かすか、Firebase Local Emulator Suite に接続して動かすかを選択することになります。

公式にはオンラインでのテストが推奨されています。

> Cloud Firestore または Realtime Database の関数を使用している場合は、テストコードが非常に複雑になるため、オフライン モードの使用は通常おすすめしません。

しかし、Firebase 以外の外部サービスと通信が関数内で発生する場合、それらのモックを作るのが難しくなるので、できれば関数単体でのテストも選択肢に入れられると良さそうです。

Express のテストフレームワークである [supertest](https://github.com/ladjs/supertest) を使ってテストを簡単に書くことができそうなので、書いてみます。

## テスト対象のコード

まずはモックが不要な、非常にシンプルな関数 `ok()` に対してテストを書いてみます。

```typescript:functions/ok.ts
import * as functions from "firebase-functions";

export const ok = functions
  .https
  .onRequest((request, response) => {
    response.sendStatus(200);
  });
```

### テストコード

Jest を想定して書いていますが、他のテストフレームワークでも assertion は大体同じように書けます。

```typescript:functions/__tests__/ok.test.ts
import * as express from "express"; // (1)
import * as supertest from "supertest"; // (1)
import {ok} from "../ok";

describe(storeSomething, () => {
  const app = express(); // (2)

  beforeAll(() => {
    app.use(ok); // (2)
  });

  it("returns 200 OK", async () => {
    await supertest(app) // (3)
      .get("/ok")
      .expect(200);
  });
});
```

まず `(1)` で `express` と `supertest` をインポートしておきます。

`(2)` で `express` を初期化し、関数 `ok()` を router に登録します。

あとは `supertest` で通常の Express app をテストするときのようにテストコードを書けば OK です。
<vscode>cvaでtailwindの補完が効かない

CVAでtailwindを書いたときに補完が出なかったのでその解決方法についてのまとめ。

```tsx
cva(
  'default class ...',
  {
    variants: 'bg-black text-sm ...' // <- tailwind intellisense 効かない
  },
  // ...
)
```

# settings.json
追加すればok
```settings.json
"tailwindCSS.experimental.classRegex": [
  ["cva\\(([\\s\\S]*?)\\)", "'([^']*)'"]
]
```

↑で動かなければより複雑なregexpを使う
```settings.json
 "tailwindCSS.experimental.classRegex": [
   [
     "cva\\(([^)(]*(?:\\([^)(]*(?:\\([^)(]*(?:\\([^)(]*\\)[^)(]*)*\\)[^)(]*)*\\)[^)(]*)*)\\)",
      "'([^']*)'"
   ]
]
```

# 参考
https://github.com/tailwindlabs/tailwindcss-intellisense/issues/719
build.gradleのKTS移行でsourceSetsの設定にハマった

Androidアプリケーションプロジェクトのビルド構成を**Groovy(build.gradle)** から**KTS(build.gradle.kts)** に移行することになりました。
ほとんどは[ビルド構成を Groovy から KTS に移行する](https://developer.android.com/studio/build/migrate-to-kts?hl=ja)の公式ドキュメントで移行することができました。
しかし、下記のbuild.gradleのsourceSetsの移行には時間がかかったため、記事として忘れないように残しておきます。

```groovy:build.gradle
android {
    flavorDimensions "situation", "type", "gender"
    productFlavors {
        pet {
            dimension "situation"
        }
        stray {
            dimension "situation"
        }
        dog {
            dimension "type"
        }
        cat {
            dimension "type"
        }
        male {
            dimension "gender"
        }
        female {
            dimension "gender"
        }
    }

    sourceSets {
        petDogMale.java.srcDirs += ["src/petDog/java"]
        petDogMale.res.srcDirs += ["src/petDog/res"]
        petDogFemale.java.srcDirs += ["src/petDog/java"]
        petDogFemale.res.srcDirs += ["src/petDog/res"]
        petCatMale.java.srcDirs += ["src/petCat/java"]
        petCatMale.res.srcDirs += ["src/petCat/res"]
        petCatFemale.java.srcDirs += ["src/petCat/java"]
        petCatFemale.res.srcDirs += ["src/petCat/res"]
        strayDogMale.java.srcDirs += ["src/strayDog/java"]
        strayDogMale.res.srcDirs += ["src/strayDog/res"]
        strayDogFemale.java.srcDirs += ["src/strayDog/java"]
        strayDogFemale.res.srcDirs += ["src/strayDog/res"]
        strayCatMale.java.srcDirs += ["src/strayCat/java"]
        strayCatMale.res.srcDirs += ["src/strayCat/res"]
        strayCatFemale.java.srcDirs += ["src/strayCat/java"]
        strayCatFemale.res.srcDirs += ["src/strayCat/res"]
    }
}
```

以下が移行後の内容です。

```kotlin:build.gradle.kts
android {
    flavorDimensions+= listOf("situation", "type", "gender")
    productFlavors {
        create("pet") {
            dimension = "situation"
        }
        create("stray") {
            dimension = "situation"
        }
        create("dog") {
            dimension = "type"
        }
        create("cat") {
            dimension = "type"
        }
        create("male") {
            dimension = "gender"
        }
        create("female") {
            dimension = "gender"
        }
    }

    applicationVariants.all {
        sourceSets {
            getByName(name) {
                when {
                    name.startsWith("petDog") -> {
                        java.srcDirs("src/petDog/java")
                        res.srcDirs("src/petDog/res")
                    }
                    name.startsWith("petCat") -> {
                        java.srcDirs("src/petCat/java")
                        res.srcDirs("src/petCat/res")
                    }
                    name.startsWith("strayDog") -> {
                        java.srcDirs("src/strayDog/java")
                        res.srcDirs("src/strayDog/res")
                    }
                    name.startsWith("strayCat") -> {
                        java.srcDirs("src/strayCat/java")
                        res.srcDirs("src/strayCat/res")
                    }
                }
            }
        }
    }
}
```
CentOS8（XFSのファイルシステム）でlsattrコマンド、chattrコマンドを実行

シェルのテストで、ファイルを削除するときにエラーを発生させたい、というのがあり、`lsattr`コマンドと`chattr`コマンドを使ってみました。

manでコマンドを調べてみると、

+ lsattr - Linux第2拡張ファイルシステム(ext2fs)上にあるファイルの属性(attribute)を表示する
+ chattr - Linux第2拡張ファイルシステム(ext2fs)上にあるファイルの属性(attribute)を変更する

とあったので、CentOS8のXFSのファイルシステムでも使用できるか試してみました。


# 環境
+ OS : CentOS Linux release 8.5.2111
+ ファイルシステム : XFS
```console
[root@centos85 ~]# cat /etc/redhat-release
CentOS Linux release 8.5.2111
[root@centos85 ~]#
```
```console
[root@centos85 ~]# df -T
ファイルシス        タイプ   1K-ブロック    使用   使用可 使用% マウント位置
devtmpfs            devtmpfs      993228       0   993228    0% /dev
tmpfs               tmpfs        1012180       0  1012180    0% /dev/shm
tmpfs               tmpfs        1012180    8608  1003572    1% /run
tmpfs               tmpfs        1012180       0  1012180    0% /sys/fs/cgroup
/dev/mapper/cl-root xfs         14034944 1905464 12129480   14% /
/dev/sda1           xfs          1038336  187364   850972   19% /boot
tmpfs               tmpfs         202436       0   202436    0% /run/user/0
[root@centos85 ~]#
```

# 試した内容
`touch`コマンドで空のファイルを作成します。
```console:実行結果
[root@centos85 ~]# touch sample.txt
[root@centos85 ~]# ls -l sample.txt
-rw-r--r--. 1 root root 0  7月  2 17:28 sample.txt
[root@centos85 ~]#
```

`lsattr`コマンドでファイルの属性を確認します。
```console:実行結果
[root@centos85 ~]# lsattr sample.txt
-------------------- sample.txt
[root@centos85 ~]#
```

`chattr`コマンドで`i`属性（変更不可の属性）を付与します。
```console:実行結果
[root@centos85 ~]# chattr +i sample.txt
[root@centos85 ~]# lsattr sample.txt
----i--------------- sample.txt
[root@centos85 ~]#
```

`i`属性（変更不可の属性）が付与された状態で`rm`コマンドで`sample.txt`を削除してみます。
```console:実行結果
[root@centos85 ~]# rm -f sample.txt
rm: 'sample.txt' を削除できません: 許可されていない操作です
[root@centos85 ~]# echo $?
1
[root@centos85 ~]#
```

しっかり削除できないようになりました。`rm`コマンドの戻り値も「0」ではなく「1」が返ってきます。

`chattr`コマンドで`i`属性（変更不可の属性）を外します。
```console:実行結果
[root@centos85 ~]# chattr -i sample.txt
[root@centos85 ~]# lsattr sample.txt
-------------------- sample.txt
[root@centos85 ~]#
```

`i`属性（変更不可の属性）を外した状態で`rm`コマンドで`sample.txt`を削除してみます。
```console:実行結果
[root@centos85 ~]# rm -f sample.txt
[root@centos85 ~]# echo $?
0
[root@centos85 ~]#
```

`i`属性（変更不可の属性）を外すと削除でき、`rm`コマンドの戻り値も「0」でが返ってきました。

ちょっと試したところ、XFSのファイルシステムでも、`lsattr`コマンド、`chattr`コマンドは使えそうです。

# 参考
[Linux コマンド 一覧表（manページ一覧）](https://kazmax.zpp.jp/cmd/ "Linux コマンド 一覧表（manページ一覧）")
Qiita x FastDocter HealthTechHackathon Hackasonに参加して

# Qiita x FastDocter HealthTechHackathon
前回に引き続き、Qiitaさんの主催するMedical Hackasonに参加してきましたワイワイ。

## 初めに
僕も医療者向けプログラミングスクール[ものづくり医療センター](URL "https://moicen-forest.studio.site/")通称『もいせん』を開講しており、Medical Hackathonの企画も行っています。
今回も武者修行&外の世界の空気を吸いに参加いたしました。

## 課題
テーマとしては身の回りのちょっとしたこと、でちりも積もれば山となり、通常の業務を圧迫することを解決するのが最もイノベーションなことだと考え、プロダクトの作成を行いました。
![スクリーンショット 2023-07-02 17.35.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581193/041e9536-d050-09e7-8349-44f16e554b3f.png)

そこで我々医療者が日々課題に感じていることは、患者さんからの質問に答えることです。
![スクリーンショット 2023-07-02 17.36.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581193/3f825c5d-cd2a-7c5d-3719-b9dd1c8c8aee.png)

## 解決案
そこで今回我々は次のような解決策を提案しました。
![スクリーンショット 2023-07-02 17.36.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581193/95e74b46-5fb3-f04d-d302-c59193eaf438.png)

### 概念図
概念図は下記のとおりです。
現場の医療者が自ら構築できるようにノーコードツールを使用しました。
![スクリーンショット 2023-07-02 17.36.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581193/e94fd671-b7b7-0bd7-aa00-459648646665.png)


### デモ
デモは下記になります。
ラインで友達になっていただくと、当院の詳細について知ることかできます。
![スクリーンショット 2023-07-02 17.36.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581193/4f9f5ad8-8506-ba49-b2de-6321573dbafe.png)


## 参加して
やはりHackasonに参加するのは非常に楽しかったです！
3回目も応募したいと考えております。
今後ともよろしきくお願いいたします。
CToolTipCtrl::UpdateTipText で Debug Assertion Failed

MFC の [CToolTipCtrl::UpdateTipText](https://learn.microsoft.com/ja-jp/cpp/mfc/reference/ctooltipctrl-class?view=msvc-160#updatetiptext)

制限については一切書かれていないのですが、第一引数 `LPCTSTR lpszText` として大きな文字列を渡すとアプリが落ちてしまいます。

アプリをデバッガで実行してみると、mfc140ud.dll で Debug Assertion Failed となっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1346257/fdb429a6-7703-583d-dd99-f3946d920a26.png)

自分の環境で実験したところ、`lpszText` が1024文字までなら大丈夫で、1025文字にするとこれが出ます。これが（明文化はされていないけど）上限なのでしょうか。それとも環境にもよるのでしょうか。

よくわかりませんが、とりあえず1024文字を超える長さの文字列を渡さないようにする対策をするしかないのかなと。
SSH接続（AWS Lightsail）

## 初めに
AWS Lightsailで作成したサーバーと
SSH接続できるように設定したので、備忘録として残します。

## 環境
| 開発環境   |バージョン    |
|-----------|------------|
| __Macbook Air__ | M1 |
| __AWS Lightsail__ | - |
| __terminal__ | - |

## 手順

__１、SSH keyを取得する__
![sshkey_lightsail_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984846/36ca7522-3550-74e4-48be-19c173ee4736.png)

__２、取得したkeyファイルを移動する（~/.ssh/配下に移動）__

```:terminal
$ cd ~/Downloads/

$ chmod 400 LightsailDefaultKey-ap-northeast-1.pem　// keyの権限変更

$ mv LightsailDefaultKey-ap-northeast-1.pem ~/.ssh/  // ファイルを指定した配下に移動する

```

__３、接続！！__
ユーザー名とパブリックIPアドレスを入れて下記のコマンドを打ちましょう。
```:terminal
$ ssh -i ~/.ssh/LightsailDefaultKey-ap-northeast-1.pem user_name@public_IP_address
```
サーバーに入ることができたら成功です。

## 最後に
最後まで閲覧いただきありがとうございました。
ご意見、ご指摘ありましたら、コメントお願いいたします。