OmniAICreator/Qiita-1.07M huggingface dataset:
備忘録(Python)

# Entry内の文字をクリックされたら消す

~~~
import tkinter

def focus(ev):
    e.delete(0, tkinter.END)

root = tkinter.Tk()
e = tkinter.Entry(root)
e.insert(tkinter.END,"注文数を入力")
e.pack()
e.bind("<Button-1>", focus)
#e.bind("KeyPress-F10")
root.mainloop()
~~~

insertした文字列をマウスで左クリックされたら消す。

![tkinter_bind_sample.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3724119/f3349e87-e4c4-88ea-ff2c-222a86484d18.gif)


参考にしました↓
https://teratail.com/questions/323007

GIFうるさくてごめん;;
【書評】エンジニア力を上昇させるために

チェックの抜けが多い。
質問の意図が理解できない。
言葉では理解したつもりでも自分の中に落とし込めない。

プログラミングの構文だとかフレームワークだとかのエンジニアとして以前に社会人としてビジネススキルが足りずに日々苦労している人は多いと思う。私は現在進行形で毎日苦しんでいる。質問されても言葉が全く出てこずにつまってしまったり、自分ではOKと思っていたが抜けが発生していて修正を繰り返す等今一つ仕事をしていく中で成長しているという実感はない。同じミスを繰り返してしまうたびにいつクビを切られてしまうかとおびえながら「またやってしまった」と自己嫌悪に陥ってしまう。

そのなかで職場の先輩たちからのアドバイスとして「本を読む」「メモをとる」など言っていただき、実際に本を読み、その書いてあったことを実践しているのがこの書評になる。

Qiitaというプラットフォームがふさわしいかどうかについては自分がエンジニアとして成長するためのアウトプットなのでそこはご容赦いただきたい

読んだ本　「読書脳」樺沢紫苑

この本でかかれていることは大きく３つ
1,なぜ読書をするとよいのか
2,記憶に残る読書の方法
3,どんな本を選べばよいか

この本の中で書かれていることとして一番共感したのは
「自己成長につながらない読書は意味がない」
という部分。
読んでそれで終わってしまってはただ読んだだけ、次の日には忘れるでしょうし結局時間がもったいないなというのは確かにそうだと、ではそこからどうやって自己成長につなげる読書をするのかというのが本題です。

正直読書をはじめてかなり序盤にこの本と出会えたことはラッキーだと思ういい一冊でした。

「自己成長につながる読書」＝「記憶に残る読書」これを実現させるにはアウトプットをすることが記憶に残るとのことです。
（今のところ読んだビジネス書３冊中３冊アウトプットをして記憶に定着させようと書いてあった。）

アウトプットの方法も書かれており
本にマーカー等でメモ
人に話す、説明する
本の感想や気づき、明言をXでシェアする
Xやブログで書評やレビューをする

このうち１週間で３つやるのがよいとのことでそれが今回の記事になります。

そもそもアウトプットをやった経験が少ない自分にはこの記事の書き出しで２時間くらい悩んだりと、アウトプットをするという訓練にもなるし記憶に残る読書をするためでもあるし一石二鳥になるのではと思っています。

読書をすることでいきなりスキルがぐんと伸びるような甘い現実は無いと思いますので今後も自己研鑽を続けていきたいと思います。
Forms→承認→添付ファイル保存のPower Automateフロー

# 目的
タイトルの通りです。承認、添付ファイル保存のポイント備忘録。
Forms投稿をトリガーとするフローについて。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670355/c64c3ee6-1768-ff79-9e8c-800151618f3d.png)


# 承認のポイント
`Approval`で複数承認者を指定している場合は複数応答が返ってくるので結果の条件分岐は下図のように指定。
![2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670355/8d3266ae-f592-7953-3bee-469add99c240.jpeg)
2行目の条件式は、下記の通り。
```empty(outputs('Wait_for_an_approval')?['body/outcome'])```

1行目だけだとキャンセルされた時もYesに進んでしまうので2行目必須。
承認者が単数、複数どちらでも有効。

# 添付ファイル保存のポイント
[先人の教え](https://hanakuso365.hatenablog.com/entry/2022/01/04/143006)通り、Formsトリガーからの添付ファイル出力を`json`関数で成型していったん見やすくして、その出力を`Perse JSON`にいれてSchemaを抽出。
![4.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670355/a2b5a740-2d24-597a-b279-ca151306cb68.jpeg)

添付ファイルが無い時は↑がエラーになるので、エラー発生時は意味も無く現在時刻を取得。現在時刻が取得されなかったら（すなわち`Perse JSON`が成功したら）次の処理(`Apply to each`）へ進むように細工。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670355/9dfa5680-2c3a-6879-eda4-c7f340530460.png)

`Apply to each` の中で添付ファイルの中身をパスで取得して任意の場所に作成。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670355/8f019f8c-5118-9ad1-d082-a89aaa096fbd.png)
<font color=red>赤</font>は添付ファイルが保存されているSharepointサイト、<font color=blue>青</font>はFormsタイトル、<font color=green>緑</font>は質問タイトル。`name`は`Perse JSON`から抽出したファイル名。
C++教材まとめ

# C++教材一覧

独学に利用している教材と参考になりそうなサイトを後で振り返る用にまとめておきます。

## オンラインフリーコンテンツ

https://isocpp.org/

https://www.w3schools.com/cpp/default.asp

https://www.learncpp.com/

https://qiita.com/rinatz/items/05492be4eea28f6598da

https://cpp-lang.sevendays-study.com/

https://qiita.com/arta-crypt/items/75cbb052ec492f8d5a97

## 参照渡し、ポインタ渡し、値渡し参考

https://qiita.com/agate-pris/items/05948b7d33f3e88b8967

## 書籍
非常に簡単で躓くことはほぼありませんでした。
![711K7jC7B6L._SY466_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670541/baccde18-387b-41a1-a30a-3003728275f8.jpeg)

説明足らずな箇所はあるもののGPT先生に質問しながらであれば十分読める程度です。図でイメージできるようにイラストが満載なのでイメージから頭に入れるタイプの人にはやりやすいと思います。
![81R9BU+gx4L._SY466_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670541/b75fe7f4-a03c-3769-3da9-5aeaabe68cd4.jpeg)

C++の開発者本人が書いた本を柴田先生が訳したもので、C++に関してわからないことがあればこの本で探せば必ず見つかると思って最終手段として準備しました。分厚いし高額です。
![71krxBESNzL._SY466_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670541/79a3e8e3-eebb-e0e7-7f53-5dab0e3b416e.jpeg)
iOSのオートメーションを使ってネットスーパーの配達日時を自動でカレンダーに登録する

iOSのオートメーションを使って[イトーヨーカドーのネットスーパー](https://www.iy-net.jp/)の配達予定日時を自動でカレンダーに登録するようにしてみたのでやり方をメモ。

## 前提整理

まず、イトーヨーカドーのネットスーパーでの買物の手順を整理しておく（厳密にすると登場人物はもっと細かく分類できそうだが、簡単のためにここでは「ユーザー」と「ネットスーパー」という単純化した整理にしておく）。

1. ユーザーがネットスーパーで買物をする。このときに受取時間帯（2時間幅）を合わせて指定する。
2. ネットスーパーからユーザーに「注文完了のお知らせ」メールが届く。このとき、配達予定日時はまだ確定していない。
3. 受取時間帯の数時間前になると、ネットスーパーからユーザーに「配達予定日時のお知らせ」メールが届く。このメールには最新のお届け予定日時（30分程度の幅）が確認できるURLが記載されており、ユーザーはこのURLにアクセスすることで配達予定日時の更新を知ることができる。配達予定日時は時々刻々更新される。
4. 受取時間帯が近付き配達が開始されると、ネットスーパーからユーザーに「配達開始のお知らせ」メールが届く。このメールも「配達予定日時のお知らせ」とほぼ同じ内容で、最新のお届け予定日時が確認できるURLが記載されている。
5. ユーザーは自宅でネットスーパーの商品を受け取る。
6. ネットスーパーからユーザーに「配達完了のお知らせ」メールが届く。

図にするとこんな感じ。

```mermaid
sequenceDiagram
ユーザー ->> ネットスーパー: 1. 注文内容、受取時間帯確定
ネットスーパー ->> ユーザー: 2. 注文完了のお知らせ
ネットスーパー ->> ユーザー: 3. 配達予定日時のお知らせ
ネットスーパー ->> ユーザー: 4. 配達開始のお知らせ
rect rgb(64, 64, 64)
Note right of ユーザー: 受取時間帯
rect rgb(32, 32, 32)
Note right of ユーザー: 配達予定日時
ネットスーパー ->  ユーザー: 5. 配達・受取
end
end
ネットスーパー ->> ユーザー: 6. 配達完了のお知らせ
```

上記手順の3, 4でメールを見逃したり、ついうっかり5の受取時間に外出してしまうといったことを防ぐために、配達予定日時を自動でカレンダーに登録し、通知が来るようにしておきたい。

## やったこと

iOSのショートカットアプリでオートメーションを作成する。以下iOS 17.4.1での場合。

1. `ショートカットアプリ`を開く
2. `オートメーション`を選択する
3. 右上の`+`からオートメーションを作成する。`個人用オートメーション` > `メール`を選択する。
4. `差出人`をお知らせメールの送信メールアドレスにする。
5. `件名が次を含む`にお知らせメールの件名をコピペする。今回は「配達予定日時のお知らせ」をトリガーにしたので、「配達予定日時のお知らせ」メールの件名をコピペする。
6. `すぐに実行`を選択する。
7. オートメーションの本体を記述する。

オートメーションの本体は下記の通り。

1. メールを入力として受け取る
1. 変数`本文`を`コンテンツ`に設定
1. `本文`で`https://www\.logistics\.iy-net\.jp/notice/[0-9a-f]+`に一致
1. 変数`url`を`一致`に設定
1. `url`の内容を取得
1. `URLの内容`で`お届け予定時間\s*:\s*[0-9/: ]+〜[0-9/: ]+`に一致
1. 変数`お届け予定`を`一致`に設定
1. `お届け予定`で`[0-9/: ]+〜`に一致
1. `一致`から日付を取得
1. 変数`開始`を`日付`に設定
1. `お届け予定`で`〜[0-9/: ]+`に一致
1. `一致`から日付を取得
1. 変数`終了`を`日付`に設定
1. `開始`から`終了`までの`ネットスーパー受け取り`という名前の予定を追加
1. `新規予定`の`URL`を`url`に設定

こうしておくことで、「配達予定日時のお知らせ」メールを受信すると自動でオートメーションが実行され、カレンダーに配達予定日時が登録される。

メール本文もお届け予定日時のWebページも機械可読性は特に考えられていないので、とにかく正規表現でどうにかする。URLは末尾がIDのようなので先頭部分でひっかける。日時の取得は正規表現でおおざっぱにひっかけて、細部は「日付を取得」にお任せする。Webページに改行が含まれることがあるため、正規表現で半角空白ではなく`\s`を使わなければいけなかったりといったところはハマリどころだろうか。

## 改善できそうなところ

上記では「配達開始のお知らせ」ではなく「配達予定日時のお知らせ」をトリガーにしているため、カレンダーに作成される予定の日時は最終的な配達予定日時とはズレることがある。これは、できるだけ早くカレンダーに予定を作成し、配達予定に気づくチャンスを少しでも多くするためである。カレンダーの日時をより正確にするためには、「配達開始のお知らせ」をトリガーに配達予定日時を再度取得し更新するといったことも考えられるだろう。

とはいうものの、現在はそこまではせず、カレンダーのURL欄にお届け予定日時のWebページのURLを設定しておき（オートメーションの「`新規予定`の`URL`を`url`に設定」の部分）、必要に応じて人手で簡単に予定を確認・更新できるようにするに止めている。
令和5年になってvSphere Client6.0をWineで動かすメモ

時は令和5年。VMWareがBroadcomに買収されて界隈は大騒ぎの今日この頃である。
それはさておき、会社の化石と化した仮想環境がいまだにvCenter6.0で動作している。
データセンターに置くWindowsライセンスがもったいないのでWineで動かすことを考える。

環境はUbuntu 22.04 LTS

# Wineで動かす方法
WineHQの動作確認サイトに情報がある。
https://appdb.winehq.org/objectManager.php?sClass=version&iId=32171

基本的には、この情報で全く問題ないが、はまったポイントがある。

# インストール
まず

```
sudo dpkg –add-architecture i386
```
を実行しておくこと。

Wineのインストール自体は
https://wiki.winehq.org/Ubuntu
stableの最新版で問題ない。

# Winetricks
Winetricksは、**Githubから入れる** 。ここが結構大事。aptから入れると古いバージョンが入ってしまうことがあり、いろいろとうまくいかない。

```
cd "${HOME}/Downloads"
wget  https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks
chmod +x winetricks
```

適当にpathの通っているところに置くとよい。

# インストーラ実行
公式の手順が若干適当なので訂正

```
WINEPREFIX="$HOME/.vsphere" WINEARCH=win32 wine wineboot

WINEPREFIX="$HOME/.vsphere" WINEARCH=win32 winetricks -q dotnet35sp1 msxml3 vcrun2005 vcrun2008 vcrun2010 cjkfonts

WINEPREFIX="$HOME/.vsphere" WINEARCH=win32 ~/Downloads/VMware-viclient-all-${version}.exe

WINEARCH=win32 WINEPREFIX="$HOME/.vsphere" wine ~/.vsphere/drive_c/Program Files/VMware/Infrastructure/Virtual Infrastructure Client/Launcher/VpxClient.exe
```

日本語フォントがおかしくなることがあるので、いろいろ頑張って修正するとよい。
【備忘録】SupabaseAuth を @supabase/supabase-js と @supabase/ssr で比較する

# はじめに
**SupabaseAuth** を **@supabase/supabase-js** と **@supabase/ssr** 
を使った時の違いについてまとめた **備忘録** です。

今回は **GitHubOAuth認証** を使用して **ログイン処理** を行った時についてまとめます。

## @supabase/supabase-js を使った時
・**ローカルストレージ側**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348923/24008787-4d75-b9eb-2b31-62a01ec36d40.png)

**oauth_provider_token** に GitHubAPIを叩く **アクセストークン** が
**sb-\<projectURL>-auth-token** に **provider_token** や **Supabase側のアクセストークン** 
等を持つオブジェクトが代入されています。

・**cookie側**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348923/fe033d39-9f7c-3c2e-7351-267663a8eda0.png)

**sb-access-token** に **Supabase側のアクセストークン** が
**sb-refresh-token** に **Supabase側のリフレッシュトークン** が代入されています。

それぞれ **ローカルストレージ側のsb-\<projectURL>-auth-token** にも代入されています。

## @supabase/ssr を使った時
・**ローカルストレージ側**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348923/884ddf69-0753-f091-3404-2d6e3f529f56.png)

**oauth_provider_token** に GitHubAPIを叩く **アクセストークン** が代入されています。

・**cookie側**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348923/282121b5-52ec-2d4b-7e8a-73e683e90dcc.png)

**sb-\<projectURL>-auth-token.0** に **Supabase側のアクセストークン** 等を持つオブジェクトが代入されています。(**provider_token** は入ってないです。)

**sb-\<projectURL>-auth-token.1** に **日時** が代入されています。
おそらく **セッション更新日時** だと思われます。

## @supabase/supabase-js と @supabase/ssr は併用出来るのか？
・**@supabase/ssr** でログイン -> **@supabase/supabase-js** でユーザ情報を取得 -> できない

・**@supabase/supabase-js** でログイン -> **@supabase/ssr** でユーザ情報を取得 -> できない

認証において **互換性がない** ので併用できません。
sentence-transformesでのcallback関数の書き方

Sentence-TransformersでEmbedding Modelをトレーニングする際に、どのようにCallback関数を書いたらいいかの日本語の記事がなかったので、備忘録を兼ねて残しておきます。

Sentence-TransformersでEmbedding Modelをトレーニングするコード自体はこちらを参考にしてください。[LlamaIndexによる埋め込みモデルのファインチューニングを試す](https://note.com/npaka/n/nd69fbfbdfa74)
また、こちらは公式のDocumentです。[SentenceTransformer](https://www.sbert.net/docs/package_reference/SentenceTransformer.html) 

今回はEvaluatorから提供されるスコアが最高値になった際にモデルを保存するCallback関数を例に書きます。
best_model自体は既にfitのオプションとして実装されているのでご注意。

### Callback関数
```Python
best_score = -999999
def custom_callback(score, epoch, steps):
    global best_score
    print(f"score : {score}, epoch : {epoch + 1}, steps :{steps}  ")
    if best_score <= score:
        model.save("/output/")
```



### model.fit()
```Python
model.fit(
    train_objectives=[(loader, loss)],
    epochs=EPOCHS,
    warmup_steps=warmup_steps,
    output_path="results",
    show_progress_bar=True,
    evaluator=InformationRetrievalEvaluator, 
    evaluation_steps=1,
    callback=callback,
)
```

このコードでは、InformationRetrievalEvaluatorをEvaluatorとして採用しています。
Evaluatorを使った際は、validation datasetに対するEvaluatorのスコア(lossではないので注意), 現在のEpoch数, 現在のstep数が引数として、callback関数に渡されます。

現状のsentence-transformersだとlossの数値をcallback関数に直接渡せないので、callbackをクラスから定義する必要があるのですが、それはまた別の機会とします。
SQLのDMLについて2

## データ操作言語（DML)について記載。
※参考 兼 自身のメモ用
※随時追記

`副問合せ`
2回のSELECT文を1回にまとめて検索すること

`単一行副問合せ`
1回目のSELECT文が1つのレコードのみを返す
```sql:①
-- JAMESの部門コードを調べるとする（値は10とする）
SELECT 
    dept_code
FROM
    t_user
WHERE
    user_name = 'JAMES'
;
```

```sql:②
-- ➀の結果を使用して、JAMESと同じ部門のユーザを調べるとする
SELECT 
    *
FROM
    t_user
WHERE
    dept_code = 10
;
```

```sql:③：単一行副問合せ
-- ➀と➁を一度にまとめて検索する
SELECT 
    *
FROM
    t_user
WHERE
    SELECT dept_code FROM t_user WHERE user_name = 'JAMES'
;
```

`複数行副問合せ`
1回目のSELECT文が複数のレコードを返す
```sql:④：複数行副問合せ
-- 複数行副問合せで検索されるため、＝ではなくINを使用する
SELECT 
    列名
FROM
    テーブル名
WHERE
    条件式
IN
    (任意のSQL文)
;
```
Let's EncryptからCentOS（CentOS 9）、NginxをHTTPS化（Cerbot）

## 前提
もうすでにNginxのインストールやサーバへのドメインの紐づけが終わっている前提です。

## 本題

以下の手順では、CentOS上のNginxをhttps化する方法について説明します。

まず、以下のコマンドを実行してEPELリポジトリをインストールします。このリポジトリは、CentOSにはデフォルトで含まれていないが、追加のパッケージを提供します。

```bash
sudo su
dnf install <https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm> -y
```

次に、以下のコマンドを実行して`snapd`をインストールします。これはSnapパッケージの実行環境で、この後のcertbotのインストールに必要です。

```bash
dnf --enablerepo=epel -y install snapd
ln -s /var/lib/snapd/snap /snap
echo 'export PATH=$PATH:/var/lib/snapd/snap/bin' > /etc/profile.d/snap.sh
systemctl enable --now snapd.service snapd.socket
```

次に、以下のコマンドを実行して`certbot`をインストールします。Certbotは、Let's EncryptからSSL証明書を取得するためのツールです。

```bash
snap install certbot --classic
```

`certbot`を使いやすくするために、以下のコマンドを実行してシンボリックリンクを作成します。

```bash
ln -s /snap/bin/certbot /usr/bin/certbot
```

次に、以下のコマンドを実行して`core`をインストールします。これは、snapdの基本的な機能を拡張するためのものです。

```bash
sudo snap install core
```

以下のコマンドを実行して、Nginxの設定を自動的に調整し、SSL証明書を取得します。

```bash
sudo certbot --nginx
```

最後に、表示される指示に従ってメールアドレスを入力し、利用規約に同意し、メルマガの受け取りを選択します。その後、SSL証明書を取得するドメインを選択します。

- メールアドレス: [your.mail.addres@email.com](your.mail.addres@email.com)
- 利用規約: Y
- メルマガ: N
- 対象のドメイン: 1（複数の場合、スペース区切り）

一度エラーが出た場合でも、再度同じコマンドを実行することで成功することがあります。
Flutter 〜Dartのジェネリクスについて〜

# ジェネリクスについて
ジェネリクスを使用すると、異なるデータ型で動作する単一のメソッドやクラスを定義することが可能。

# ジェネリクスの基本
型パラメータを使用して抽象的にクラスや関数を定義する方法。
コンパイル時に型の安全性を保ちつつ、様々な型で再利用可能なコンポーネントを作成することが可能。

```dart
// Tを型パラメータとして持つジェネリッククラスBoxを定義
class Box<T> {
  // T型のオブジェクトを保持するfinal変数object。
  // finalなので、この変数が初期化後に変更不可能
  final T object;
  // Boxクラスのコンストラクタ。
  // このコンストラクタは引数としてT型のオブジェクトを受け取り、
  // メンバ変数objectにそれを格納
  Box(this.object);
}

void main() {
  // Boxクラスのインスタンスを生成。
  // ジェネリクスの型パラメータ<T>にintを指定して、
  // 整数123をオブジェクトとしてBoxに格納する。
  var box = Box<int>(123);
  
  // Boxインスタンスのobjectメンバにアクセスし、その値をコンソールに出力する。
  // 出力されるのは "123"
  print(box.object); // 123
}
```

クラスや関数では通常 <T> のように角括弧を使用して指定され、T は任意の型を表すプレースホルダーとして機能する。

```dart
Box(this.object);
```
この部分は以下と同義。
引数として受け取ったオブジェクトをクラスのフィールド object に直接割り当てる。

```dart
  Box(T obj) : this.object = obj {
  }
```

# 結論
Box(this.object); のようなコンストラクタの記法は、Dart において型の安全性を保ちつつ、コードの簡潔さを保つための効率的な方法であり、特にジェネリクスを使用して多様な型に対応するクラスを定義する場合に有効。
２回目のチーム開発！【アプレンティス】

#  はじめに
私は、現在アプレンティス（若手エンジニアの育成・マッチングサービス）に参加しているエンジニア未経験の24歳です。
今回は、２回目のチーム開発についてまとめていきます。
今回のテーマは、**『ワクワクするものを開発せよ』**　ということで前回とは違ったテーマのアプリになっています！

##  アイデア決め
まずはチームメンバーで各自アイデアを出しました。
私は過去に調理師をしていた経験から、「みんなでキロクごはん」という作った料理を共有するアプリなどを考えましたが、わくわくにはかけており・・・
他のチームメンバーが考案した、「ハッピーバーふぅデイ」という、誕生日ケーキのスタンプみたいなものが表示されて、画面に向かって「ふぅーっ」と息を吹きかけるとろうそくの火が消えるアプリは、とてもワクワクして面白かったのですが、現実的に厳しく断念。
そんな中、今回作るアプリが決まりました！
それは・・・**「ジョジョ立ち倶楽部」** です！

##  アプリの概要
- ジョジョ立ち倶楽部は、有名な漫画およびアニメシリーズ「ジョジョの奇妙な冒険」に登場するキャラクターたちのポーズである「ジョジョ立ち」を撮影し、共有するためのアプリケーションです。
- ユーザーは自分の好きなキャラクターのポーズをカメラで撮影して、写真として投稿することができます。また、撮影したコンテンツをシェアして、コメントのやり取りをすることも可能です

  【 **チームメンバーが作成してくれたアプリの紹介動画が [こちら](https://youtu.be/gNwxkVXvyjg)**】


##  使用技術
### フロントエンド
- Next.js 14.1.3

### バックエンド
- Ruby 3.2.3
- Rails 7.1.3.2

### データベース
- MySQL

また、要件定義や設計、タスク出しの作成、共有するために【canva】や【figma】も使用しました。

## 開発の流れ
まずは、プロジェクトマネージャーを毎週一人任命します。毎週プロジェクトマネージャーを変えることで、リーダーシップが苦手な人も、チームの目標に対して自分が今どのような貢献をしているのかといったことが明確になり、貢献意識が向上する力がつきます。

1. アイデア決め
2. 要件定義
3. 設計、タスク出し、環境構築
4. 実装、スライド作成

プログラミング学習と並行し、約１ヶ月半の期間が設けられました。
環境構築では、macユーザーとwindowsユーザーで異なる部分を調整しました。


# おわりに
アプレンティス通じて、今回貴重な経験をさせていただきました。
独学での学習では知り得なかった技術や、ちょっとした豆知識などもチームメンバーから沢山教わりました。

このチーム開発での反省点は、明らかに技術不足だったことです。
チーム会の話し合いでも分からない用語がかなりあり、そこから調べて、理解して・・・という流れが多かったので、かなりチーム開発の足を引っ張ってしまいました。
また、毎週変わるはずのプロジェクトマネージャーも結局一人に任せっきりになっていたことも反省点のひとつです。
そんな中でも、可能な範囲のタスクを分配してくれて、重荷になった分のタスクも実装してくれたチームメンバーに感謝しています。

２回目のチーム開発、不完全燃焼ではありますが少しは成長できたのかなと思います。
とても良い経験でした。
また、他にチームも実際に使いたいと思うような素晴らしいアプリを実装しており、感激しました。
これからオリジナルプロダクトに入りますが、くじけず頑張って学習を進めていきたいと思います。
デスクトップLinuxのおすすめアプリ-2024版-

デスクトップ用途でLinuxを使うときに、インストールしておきたいアプリケーション。

- crazydiskinfo: disk情報参照ツール。CUIだが "WindowsのCrystalDiskInfo" の代替
- vscode: 定番テキストエディタ
- avast antivirus: アンチウィルスソフト。設定によりリアルタイムスキャンも可能（らしい）
- chrome: Webブラウザ
- sl: まったりしたい人におすすめ
Dockerコマンドチートシート

### Docker hub ログイン
```
$ docker login
```
### Dockerイメージ一覧確認(起動してるか確認)
```
$ docker images
```
Cannot connect ... と出てればログアウト中

### Dockerコンテナ一覧確認
```
$ docker ps -a
```
STATUSがExitedなら停止状態、Upなら起動中

### Dockerコンテナのログ確認
```
$ docker logs {コンテナID}
```

### ログを出力し続ける
```
$ docker logs -f {コンテナID}
```

### Dockerコンテナ削除
```
$ docker rm <コンテナ名(NAMES)>　
$ docker rm <CONTAINER ID>
```

### 使用していない全ての コンテナ の削除
```
$ docker system prune
```

### Dockerイメージ削除
```
$ docker rmi <Dockerイメージ名(REPOSITORY)>
または
$ docker rmi <IMAGE ID>
```

### 使用していない全ての image の削除
```
$ docker image prune
```

### Dockerの容量利用状況を確認
```
$ docker system df
```
### Build Cacheの消去
```
$ docker builder prune
```
### キャッシュを使わずビルドする方法
```
$ docker-compose build--no-cache
```

### Dockerfile作成
```
$ nano Dockerfile
```
```dockerfile:Dockerfile ※一例
FROM python:3.8

RUN mkdir /code　
WORKDIR /code

RUN apt-get update
RUN pip install --upgrade pip

RUN pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118

COPY . /code/

#エラーが出たので追記
RUN apt-get update && apt-get upgrade -y
RUN apt-get install -y libgl1-mesa-dev
```

### Dockerfileからイメージ構築
```
$ docker build . --tag {任意のイメージ名}
```

### Docker環境でプログラム実行
```
$docker run -d -it --gpus all -v $(pwd):/code -e "CUDA_VISIBLE_DEVICES=0" {イメージ名} {コンテナで起動するコマンド}
```

### docker-compose起動
```
$ docker-compose up -d
```

### コンテナ確認
```
$ docker-compose ps
```

### コンテナに入る
```
$ docker-compose exec container} ${command}
```

### docker-compose停止
```
$docker-compose down
```

**参考**
* ゼロから始めるDocker入門
https://qiita.com/suzu12/items/315fba934de11af826bd
自己参照ループを含むネットワークの検出


# はじめに

巨大なネットワークをサンプリングしながら、「自己参照ループ」を強く持つ部分ネットワークを検出したい。

## 実装

スノーボールサンプリングという手法を用いてサブグラフを探索します。
そのサブグラフの中で、自己ループが最も多いものを視覚的に描画し、評価しています。

```python
import networkx as nx
import numpy as np
import matplotlib.pyplot as plt
import random


# ランダムジオメトリックグラフの生成
G = nx.random_geometric_graph(300, 0.1)

# テストデータに自己参照ループの追加
for node in G.nodes():
   if random.random() < 0.1:  # 10%の確率で自己ループを追加
       G.add_edge(node, node)


# 初期ノードの選択とスノーボールサンプリングの実行
def snowball_sampling(start_node, target_size=30):
   queue = [start_node]
   sampled_nodes = set()
   while len(sampled_nodes) < target_size and queue:
       current = queue.pop(0)
       if current not in sampled_nodes:
           sampled_nodes.add(current)
           neighbors = list(G.neighbors(current))
           random.shuffle(neighbors)
           queue.extend(neighbors)
   return sampled_nodes


# 複数回のスノーボールサンプリングを実行
best_sample = set()
best_loop_count = 0
trial_results = []
for i in range(20):  # 20回の試行
   initial_node = random.choice(list(G.nodes()))
   sample = snowball_sampling(initial_node)
   subgraph = G.subgraph(sample)
   loop_count = sum(1 for n in subgraph.nodes() if subgraph.has_edge(n, n))
   trial_results.append((sample, loop_count))
   # 各試行の結果を表示
   print(f"試行 {i+1}: 初期ノード {initial_node}, 自己ループ数 {loop_count}")
   if loop_count > best_loop_count:
       best_loop_count = loop_count
       best_sample = sample

# 最適なサブグラフの描画
best_subgraph = G.subgraph(best_sample)
plt.figure(figsize=(8, 8))
nx.draw(best_subgraph, with_labels=True, node_color='orange', edge_color='red')
plt.title(f'Best Sample with {best_loop_count} self-loops')
plt.show()

# 最終判定結果の表示
print(f"最終判定結果: 選択された最適なサンプリングは自己ループを {best_loop_count} 個含みます。")
```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348593/0f137a5e-7720-30c5-93a8-b7834e3bc8fd.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348593/7d66ed81-e451-406e-957d-36e50a815042.png)
ラズパイCNC = RPi + CODESYS CNC Motion / EtherCAT


CAD/CAMが産業用のACサーボで動くCNCを作ってます。

本来は制御メーカーのPLCで、ノイズや温度、IOに信頼性のあるものをと思うのですが、お金も納期もかかるみたいなので、ラズパイで作っています。

いまのところこんな感じ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408008/259b2a3b-2cd9-c53d-15d3-384b6458eb44.png)

シミュレーターモードで動きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408008/7a8c57cc-be22-1bba-ab09-3444f0867a4e.png)
（手動画面）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408008/28f1e4b3-1284-3d1c-e1e9-509c32c033a7.png)

（自動画面・・今のところ物寂しい感じですが・・）


Gコードのエディタあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408008/8511bde8-512c-affc-7fe2-dbf5fdaeafbc.png)

アラーム履歴もCODESYSのアラームシステムに則っています。自社開発などがしやすいよう、アラームやログはコード内にちらかさず、専用のPOUを作成しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408008/a4d02dd4-97f0-fc41-709f-6e6222f094c7.png)

機械とGコード制御連携をとるためのMコードの実装方法もサンプルとして書いてあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408008/3c3ea752-09e4-ffc5-6f6f-f9ef7f01b0cd.png)



プロジェクトは自分用にGitHubにあげて管理しているのですが、GitHubのアカウントをいろんな方と協業できるように分けようと思っていて、まだ公開してないです。

CODESYS V3.5 SP19 Patch5で制作しています。
開発に必要なのは、CODESYSが高速に動かせるPCだけなので、とても楽ちんです。

CODESYSの仮想サーボと画面などのシミュレーターのおかげで、動作に特定の機械は必要ありません。

ただ、EtherCATのサーボアンプ＋モーター＋機械がそろそろほしいところです。
CAD-CAM-シミュレーターと連携するサーボモータや制御機器、機械のデモなどを展示会でしてみたいメーカー様、興味があったらお気軽にお問合せください。笑

興味がある個人の方もお気軽に。

よろしかったら、みんなでワイワイ創りましょう。

ではまた！


=== 自己紹介 ===

えーっと長くなったので次回かな
最低限の知識でChrome拡張機能をつくってみる（HTML/CSS/JS）

## はじめに
Chromeの拡張機能をつくるのは難しそう、という勝手なイメージがあったのですが、ごくシンプルなものであればタイトルに記したスキル程度でも作成できたので記事にすることにしました。
とくに個人的に使用するものであれば案外敷居は高くないので、これを機に何か作成してみてはいかがでしょうか。

## 今回作る拡張機能
今回は「拡張機能の作り方」に焦点を当てたいので、機能は「**Qiitaサイトの背景色を変更する**」というシンプルなものにしようかと思います。
ちなみに、本記事ではストアへの登録は行いません。

## 作成方法
### 1. 作業ディレクトリの作成
ディレクトリ名はなんでも構いません。今回は「change-qiita-bg」というディレクトリに作成しようと思います。
### 2. manifest.json の作成
いきなりよくわからないものがでてきましたがまったく問題ありません。以下のようなファイルを作成してchange-qiita-bgディレクトリ直下に保存しましょう。manifest.jsonの詳しい内容については他記事に任せることとします。

```change-qiita-bg / manifest.json
{
  "name": "Change Qiita Background",
  "version": "1.0",
  "manifest_version": 3,
  "content_scripts": [
    {
      "matches": ["https://qiita.com/*"],
      "js": ["content.js"]
    }
  ]
}
```
今回書いたもののうち、「name」「version」「manifest_version」は必須ですので必ず含めましょう。
残った"content_scripts"をざっくり説明すると、「`mathes`にマッチするページで`js`で指定したファイルをよみこむ」といったものになります。
今回では「 https://qiita.com/ 〜」のページでcontent.jsを読み込む といった記述になります。

### 3. 読み込ませたいjsファイルを作成
今回は背景色を変更するだけですので、以下のようなファイルを作成すればOKです。
```change-qiita-bg / content.js
document.body.style.backgroundColor = 'red';
```

### 4. Chrome拡張機能ページで作成した拡張機能を読み込む
chrome://extensions/ にアクセスすると拡張機能ページを開くことができます。
「パッケージ化されていない拡張機能を読み込む」をクリックし、今作成したchange-qiita-bgディレクトリを指定すると拡張機能が追加されます。

<hr>

以上が全工程になります。manifest.jsonというあまりみかけないものはでてきましたが、それ以外は案外あっさり、といった感じだったのではなかったでしょうか。

もちろんQiitaのページにアクセスするとしっかり背景色が真っ赤になってくれます。

![スクリーンショット 2024-04-22 20.39.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704882/c00d3e05-0093-a7e1-1025-5480f9739303.png)


## おわりに
いかがだったでしょうか？
今回のようなごく簡単なものであれば、10分足らずでオリジナルの拡張機能を作成できてしまいます。
これを機に「痒い所に手が届く」ような拡張機能を作成してみてもいいかもしれません。
UI状態をdata classで管理する時の大体のお決まりっぽいもの

# 概要

AndroidでUI状態を管理するときにいろいろやり方があると思いますが、UiState状態をdata classで定義しておいて使用する方法があると思います。
使用する際に「これどうすれば良いんだっけ？」と思うことがあるのである程度のお決まりみたいなものをまとめておきます。

## 定義するとき

```SampleViewModel.kt
// ViewModelの外に定義しておく
// プロパティ多いようだったら別ファイルにした方が良いかも
data class SampleUiState(
    val message: String = "",
    val loading: Boolean = false,
    val user: User? = null
)

@HiltViewModel
class SampleViewModel @Inject constructor() {
    ....
}
```

## ViewModel内で使うとき

updateとcopyを使っていきます。ただコードが長くなりがちなので、拡張関数を何かしら作っておくと良いかもしれません。
なぜupdateを使うのかというと、スレッドセーフかつアトミック（完全に行われるか全く行われないかのいずれか）な方法だからです。

```SampleViewModel.kt
@HiltViewModel
class SampleViewModel @Inject constructor() {

    private val _uiState = MutableStateFlow(SampleUiState())
    val uiState: StateFlow = _uiState.asStateFlow()

    fun getUser() {
        _uiState.update { state ->
            state.copy(
                loading = true
            )
        }
        viewModelScope.launch {
            try {
                val user = userRepository.getUser()
                _uiState.update { state ->
                    state.copy(
                        user = user
                    )
                }
            } catch (e: Exception) {
                _uiState.update { state ->
                    state.copy(
                        message = "error"
                    )
                }
            } finally {
                _uiState.update { state ->
                    state.copy(
                        loading = false
                    )
                }
            }
        }
    }
}
```

## Compose Viewで使うとき

単純にViewModelで個別に値を持っているよりuiStateで持っている方がviewModel.hoge.valueみたいに書かなくて済むのでちょっと楽です。

```SampleComposable.kt
@Composable
fun SampleComposable(
    viewModel: SampleViewModel
) {
    // ライフサイクルを考慮する場合はcollectAsStateWithLifecycle()を使った方が良い
    val uiState by viewModel.uiState.collectAsState()

    Text(text = uiState.message)
}
```

## Activityで使うとき

```SampleActivity.kt
@AndroidEntryPoint
class SampleActivity : AppCompatActivity() {

    val viewModel: SampleViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ..
        lifecycleScope.launch {
            // repeatOnLifecycleはライフサイクルに応じてJobを操作してくれる
            repeatOnLifecycle(Lifecycle.State.STARTED) { 
                viewModel.uiState.collect { uiState ->
                    ..
                }
            }
        }
    }
}
```

# まとめ

場合によってベストプラクティスは変わってくるかと思いますが、大体のやり方は似てくるかと思います。
もっと良いやり方があったら適宜追記します。

# 参考

https://developer.android.com/topic/architecture/ui-layer/stateholders?hl=ja

https://star-zero.medium.com/uistate%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9F%E7%8A%B6%E6%85%8B%E7%AE%A1%E7%90%86-4d88c6d575f0

https://techblog.zozo.com/entry/zozotown-android-viewmodel

https://proandroiddev.com/mastering-android-viewmodels-essential-dos-and-donts-part-2-%EF%B8%8F-2b49281f0029
【Flyway代替】DBマイグレーションツール「sqldef」を使用して、Windows（Ubuntu in WSL） + PostgreSQL環境でDBマイグレーションを行う方法

## はじめに
- きっかけは以前参画したプロジェクトにて、プロダクトごとにsqldefとFlywayを使い分けてマイグレーションを行っていたが、個人的にはsqldefの方が使いやすかったので、現在参画していのプロジェクトにも導入したいと思ったから。
- 制約：Linux版のバイナリファイルを使いまわす。
  - 現在参画しているプロジェクトの開発端末はWindows、CI/CD環境はLinux
  - どちらの環境でもLinux版の同じ実行ファイルを使ってマイグレーションを行いたい。

## 実施環境
- OS Windows11
- WSL Ubuntu-22.04
- DB YugabyteDB v.2.21.0.0-b545 ※ Postgresqlとの互換性あり

## 使用方法

### 事前準備
- WSLが使用できる状態にする
- Postgresqlが使用できる状態にする

### 実行ファイルを入手
- [https://github.com/sqldef/sqldef/releases](https://github.com/sqldef/sqldef/releases)からお好みのリリースバージョンのpsqldef_linux_amd64.tar.gzをダウンロード
  - 今回はv0.17.5のものを入手
- WSLを起動し、ダウンロードしたファイルの階層に移動
- 以下のコマンドで圧縮ファイルを解凍
`tar xf psqldef_linux_amd64.tar.gz`

### SQLファイルを作成
- 以下のSQLファイルを作成
```sql:01_create_table.sql
CREATE TABLE employee (
  emp_no     CHAR(5)     PRIMARY KEY,
  first_name VARCHAR(15) NOT NULL,
  last_name  VARCHAR(15) NOT NULL,
  age        SMALLINT    NOT NULL
);
```
- 上記ファイルを解凍したpsqldefの実行ファイルと同じ階層に配置
### sqldefを実行
- 以下のコマンドを実行し、現状のDBとの差分を確認
`PGPASSWORD={password} ./psqldef -h 127.0.0.1 -p 5433 -U {user_name} {database_name} < 01_create_table.sql --dry-run`
```bash:出力結果
$ PGPASSWORD=postgres ./psqldef -h 127.0.0.1 -p 5433 -U postgres postgres < 01_create_table.sql --dry-run
-- dry run --
CREATE TABLE employee (
  emp_no     CHAR(5)     PRIMARY KEY,
  first_name VARCHAR(15) NOT NULL,
  last_name  VARCHAR(15) NOT NULL,
  age        SMALLINT    NOT NULL
);
```
- 以下のコマンドを実行し、DDLを実行
`PGPASSWORD={password} ./psqldef -h 127.0.0.1 -p 5433 -U {user_name} {database_name} < 01_create_table.sql`
```bash:出力結果
$ PGPASSWORD=postgres ./psqldef -h 127.0.0.1 -p 5433 -U postgres postgres < 01_create_table.sql
-- Apply --
CREATE TABLE employee (
  emp_no     CHAR(5)     PRIMARY KEY,
  first_name VARCHAR(15) NOT NULL,
  last_name  VARCHAR(15) NOT NULL,
  age        SMALLINT    NOT NULL
);
```
- 再度現状のDBとの差分を確認
`PGPASSWORD={password} ./psqldef -h 127.0.0.1 -p 5433 -U {user_name} {database_name} < 01_create_table.sql --dry-run`
```bash:出力結果
$ PGPASSWORD=postgres ./psqldef -h 127.0.0.1 -p 5433 -U postgres postgres < 01_create_table.sql
-- Nothing is modified --
```


## 参考サイト
- [sqldefとpgrollを利用したPostgreSQLでのスキーマブルーグリーンデプロイメント](https://zenn.dev/nnaka2992/articles/blue_grean_on_postgres_with_sqldeff_and_pgroll)
【VSCode】ショートカットキーを使ってタスクを自動化しよう

開発をしている時、何度も同じ操作をしなくてはいけないケースがあります。
例えば、ビルドしてテスト環境にFTPでアップロードする、といった操作は開発中には何度も実行される操作だと思います。

操作自体は慣れてしまえばビルドコマンドを叩いて、FTPクライアントを起動して、該当ファイルを選択、アップロードして、といったところなので数十秒で済みますが、これが何度も発生すると生産性に悪影響があると思います。

そこで今回はvscodeのタスク登録とショートカットキーを使ってキー操作だけで一連の作業を実行できるようにする方法について解説をします。

# まずはシェルを作る
```bash
#!/usr/bin/bash

# カレントディレクトリをスクリプトのあるディレクトリに変更
cd $(dirname $0)

# ビルド
npm run dev

# SFTPでファイル名を変更してアップロード
sftp -i /Users/xxxxx/.ssh/xxxxx.pem xxxx@hostname <<EOF
put public/script.js /var/www/html/js/script-test.js
put public/script.js.map /var/www/html/js/script-test.js.map
EOF
```
一連の作業を実行するシェルを作成します。
今回はnpmでビルド後にsftpコマンドでリモートサーバーにファイルをアップロードしています。
また、アップロード先でファイル名の変更もしています。

作成したファイルはプロジェクトのルートにbuild.shという名前で保存しておきました。
このシェルは自身の環境に依存した情報（キーファイルのパスなど）が含まれるのでGitなどパブリックな場所にはアップしないように注意してください。

シェルの作成に慣れていない方はここだけ難しいと思いますが、ご辛抱を！

# タスクを登録する
```json
{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "run build.sh",
      "type": "shell",
      "command": "sh ./build.sh",
      "problemMatcher": [],
      "group": {
        "kind": "build",
        "isDefault": true
      }
    }
  ]
}
```
次にvscodeに作成したシェルの実行をしてくれるタスクを登録します。
タスクとは、vscodeの機能の１つで、コマンドの実行やvscode上での操作を自動化するための仕組みです。

プロジェクトルート下に.vscodeフォルダを作成し、その中にtasks.jsonという名前で上記のjsonを記述してください。

labelは、このタスクの名前です。
commandに実行する処理を記述します。
groupはショートカットキーに登録する記述で、Macの場合だとCMD+Shift+Bに割り当てられます。

これで、「run build.sh」という名前でタスクが登録され、ショートカットキーにも紐付けができました。

# タスクを実行してみる
では、さっそくタスクを実行してみます。
vscodeのメニューバーでターミナル > タスクの実行 > run build.sh を実行します。

実行するとターミナルが表示されて、一連の処理が実行されるはずです。
実際にサーバーに意図通りアップロードされていることも確認しましょう。

![スクリーンショット 2024-04-22 19.55.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476743/6808fe23-4176-cdbc-6ec6-c7be28c0c8cd.png)
![スクリーンショット 2024-04-22 19.56.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476743/e9f33409-dcec-053f-9f26-91cd12855422.png)

# ショートカットキーで実行してみる
CMD+Shift+Bを押して、ショートカットキーでも同じように実行されることを確認しましょう。
Windowsの場合は、Ctrl+Shift+Bです。

## 他のショートカットキーに紐づける
任意のショートカットキーを使いたい場合は、vscodeのメニューバーからcode > 基本設定 > キーボードショートカット と進むとキーボードショートカットの設定画面になるので、そちらから登録をすることができます。

# まとめ
今回はvscodeのタスク機能とショートカットキー機能について解説をしました。
みなさんもvscodeの機能を使って繰り返しの作業をショートカットキーで実行できるようにすることで生産性アップに繋げてください！
Git-3 コミットについての詳細

# 概要
コミットを実行した時、gitリポジトリにはblobオブジェクト、treeオブジェクト、commitオブジェクトが記録される。

# コミットを時系列順に積み上げていく
![b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985939/8c2e7688-e3d3-0fcc-3207-fff50e954ba4.png)

# blobオブジェクト
ステージング領域で指定されたファイル1つ1つはそれぞれblobオブジェクトというファイルとしてgitリポジトリに保存される。これが各ファイルの実質的なフルバックアップとなる。また、それぞれのblobオブジェクトの識別子はファイルの内容からSHA-1で算出したハッシュ値となる。

# treeオブジェクト
gitで管理しているプロジェクト内の全てのディレクトリの内容（ファイル一覧）と、各ファイルに対応するblobオブジェクトを紐づけて、コミットを実行した時点におけるプロジェクト全体の状態を作成する。

各ファイルに対応するblobオブジェクトは、
- ステージングで指定されたファイルは新規のblobオブジェクト（今回のコミットで記録される）
- 上記以外のファイルのblobオブジェクトは直前のコミットにおけるtreeオブジェクトから引き継ぎ

となる。

一度もステージングされたことがないファイルは、treeオブジェクトにも入らないし、gitの管理対象にならない。

treeオブジェクトはコミットを実行する度に新規追加されてコミットと紐づけられる。そのため、あるコミット時点でのプロジェクト全体の状態（スナップショット）を表し、どこでも復元することを可能にしているのが、treeオブジェクトである。

# commitオブジェクト
コミットに付随する情報とtreeオブジェクトへの参照などの情報を含むオブジェクト。
- コミットを実行した人
- コミット日時
- 今回のコミットで新規作成されたtreeオブジェクトへの参照
- 直前のコミットへの参照（"親コミット"という）

※gitリポジトリの最初のコミットには親コミットは存在しない。

これらの情報を持っていることにより、commitオブジェクトから、
- コミットした時点のtreeオブジェクト（プロジェクトのスナップショット）の内容を見て、そこに紐づけされたblobオブジェクトからプロジェクト全体のファイル・ディレクトリの状態を復元することができる
- 親コミットを辿っていってgitリポジトリ全体の歴史（コミット履歴）を知ることができる
ライトスクラムの進め

皆さんの開発現場はウォーターフォールですか？
アジャイルですか？
それともどっちつかずのなんちゃってアジャイルですか？

私の経験上、完全にアジャイル、特にスクラムをするには人が足りなかったり導入コストがかかるので中途半端なアジャイルやスクラムで運用しているチームが多いのではないかと思います。
そこで、この際ライトスクラムという名前を授けようと思います。
大体アジャイルって言ってるのはスクラムでしょ？

# 登場人物
### プロダクトオーナー
リリースの判断や企画など行います。
ドメインに詳しい開発の人（マーケとか？）がいいかと思います。

### スクラムマスター
不要です。
スクラムマスターはスクラムが回るようにするのが目的ですが、そもそも完全なスクラムは求めてません。
緩くていいんです。

### PM・チームリーダー
開発スケジュールや要件定義などを行います。
プロジェクトを継続的に回すことがこの役割です。
大事なのは無茶なスケジュールを言ってくる人たちを言葉でねじ伏せ、蹴散らすことです。

### メンバー
エンジニアやデザイナーなどです。
メンバーは自分の与えられたチケット・タスクに対して期限までにリリースする責任を持ちます。
その範囲は言われたものを作るだけでなく、設計なども行います。
場合によってはタスクの不要性で説き伏せて、タスクを捻り潰しても問題ありません。

# スプリント
### バックログ => チケット
バックログなんて名前はおしゃれなのでチケットで十分です。

### ベロシティ
開発の速度は開発案件にポイントをつけて、消費できるポイントを指数で計測します。
しかし、ライトスクラムでは不要です。
なぜなら、使い慣れた人月を使うからです。
我らは神話を信じる信徒です。

### イテレーション
スクラムにおいて、イテレーションは決まっています。
それは短くて1週間から長くて1ヶ月が大半でしょう。
正直、1週間は短すぎる気がしますが。
しかし、ライトスクラムでは厳密である必要はありません。
毎回変わっても問題ありません。
なぜなら、ライトスクラムではベロシティは使われないからです。

### バーンダウンチャート => WBS
ポイントないんだから何をバーンダウンさせるんです？
重要なのはタスクの進捗状態です。

# イベント
### スプリントプランニング => 定例MTG
イテレーションの期間は決まってませんし、なんなら案件によって異なります。
なので、定例MTGでプランニングをすることもあれば、進捗確認だけのこともあります。
場合によってはそこでプランニングの臨時MTGを決めることもあるかと思います。

### デイリーMTG
私は合った方がいい派ですが、これは思想によります。
ただし、期待した成果物が出てこない場合はコミュニケーションロスの場合があるので、やった方がいいです。
些細な疑問をその日のうちに解決できるので。

### スプリントレビュー
場合によります。
リリースする成果物の確認はプロダクトオーナーがするので、時間と場所をとってやるのが適切だとは思います。
しかし、現実としてプロダクトオーナーは忙しいことが多く、大抵捕まりません。
プロダクトオーナーがスプリントレビューの時間を取れない・取らないのは完全なスクラムを導入できない一つの大きな理由だと思います。
その場合はリモートや別の時間で個別で確認してもらいましょう。
リリースしてから「要求と違う」なんて言われたらそれはプロダクトオーナーの責任です。

### スプリントレトロスペクティヴ
毎回やる必要はありません。
スクラムは会議が多いので、スプリントプランニング、プロダクトレビューに加えスプリントレトロスペクティヴまでやると開発する以上に疲れます。
年一回とかでいいんです。
チームの余裕に合わせていきましょう。

# 最後に
これらは料理で言う基本的なレシピです。
現場によって色々工夫することでよって初めて完成します。
皆さん、闇鍋を楽しみましょう。
Github Actions + reg suit で snapshot key が検知できない場合

# Error

```
[reg-suit] warn Failed to detect the previous snapshot key
[reg-suit] info Skipped to fetch the expected data because expected key is null.
```

# 対応

checkout でfetch-depth を指定して、全てのヒストリーとコミットを参照できるようにしておけば良かったようだ
もしくは適当に大きな数字を指定しても成り立つかもしれない

> Number of commits to fetch.
> 0 indicates all history for all branches and tags.

https://github.com/actions/checkout



```yml
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
```

# 参考

reg suit 公式
https://github.com/reg-viz/reg-suit#getting-started



# チャットメンバー募集


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

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ


# プロフィール・経歴

https://github.com/YumaInaura/YumaInaura
【初心者】Cursorとは

開発環境でCursorというエディタを使っているので、それについて備忘録。

### Cursorとは
Visual Studio Code（VSCode）をベースに開発されたAI搭載のコードエディタです。

このツールのメイン機能は、AIによるコードの自動生成、質問応答、エラーの自動修正で、これにより開発者は効率的に作業を進めることができます。

AI使って開発できるんだ、ｽｹﾞｰ

### コード自動生成する
GItHub Copilotのようにコードを”補完”するのではなく、自然言語に基づいて”生成”してくれる。

また、既存のコードを選択して自然言語で依頼すれば、そのコードへのリファクタリングや修正などもその場でサクッと行ってくれます。

リファクタリングもしてくれるのか!?ｽｹﾞｰ


### シームレスなチャット
Cursorのエディタでは、GPTへの質問ができるチャットウィンドウが右側に表示されます。
チャットでは、コードを選択した状態で開くと、そのコードが引用され、直接質問することが可能です。

さらに、ファイル全体を参照することもでき、バグチェックやリファクタリングなどの依頼も可能です。

ﾋｪｰ。なんか常にプロを横におきながら作業できるような感じね。

参考
https://generativeinfo365.com/?p=2082#:~:text=Cursor%E3%81%AF%E3%80%81Visual%20Studio%20Code,%E9%80%B2%E3%82%81%E3%82%8B%E3%81%93%E3%81%A8%E3%81%8C%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82
【GitHub】リポジトリ名／【GitLab】プロジェクト名をURLも併せて変更する

## ざっくりやること
1. GitHub／GitLab上で、リポジトリ名／プロジェクト名を変更する
2. ローカルリポジトリの参照先URLを変更する
`git remote set-url origin [新URL]`

## 詳細手順
### GitHub
#### 0.変更前
![0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257421/ffd2fff5-3277-69de-2189-89b21c46159e.png)

![1_ぼかし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257421/98fdc505-674f-4fdf-aef3-1a19633030e1.png)

#### 1.リポジトリ名変更
GitHub > 対象のリポジトリ > Settings
![2_赤枠.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257421/62028f91-3804-e8d2-95ae-29220b3e1700.png)

#### 2.参照先URL変更
`git remote set-url origin [新URL]`
![3_ぼかし_赤枠.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257421/cf00046a-fcac-c144-5267-3cec89c10ab8.png)

#### 3.疎通確認
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257421/9574a528-9534-3643-be33-bdbb938c6ef1.png)

![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257421/aba294de-5c7a-0dfb-98e9-b8f8ee8f692f.png)

### GitLab
#### 0.変更前
![0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257421/6bde3327-bd08-b1ff-ee14-c4f2ee87d059.png)

![1_ぼかし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257421/7efd1ffb-3fc0-325e-d34e-e96720ba1e52.png)

#### 1.プロジェクト名変更
GitLab > 対象のプロジェクト > 一般設定 > 命名、トピック、アバター
![2_赤枠.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257421/d89bb0b1-b17b-3bb6-4a80-e0c8c48d4c18.png)

GitLab > 対象のプロジェクト > 一般設定 > 高度な設定 > パスを変更
![2_2_赤枠.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257421/1e5915d7-2469-c977-0f6b-e1e0f352802e.png)

#### 2.参照先URL変更
`git remote set-url origin [新URL]`
![3_ぼかし_赤枠.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257421/a4dfe522-f88c-8e39-79c4-bed75bbf638f.png)

#### 3.疎通確認
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257421/b385f589-0a53-15f6-8653-affe13f07bf3.png)

![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257421/35f2cbb2-0d0b-ac67-7c60-840e5aa67e6b.png)

## 補足
リモートリポジトリへのアクセス名が「origin」でない方は、適宜読み替えてください。
IPA試験「午後問題」が解けなかったのは基礎力が足りないせいだった

## はじめに

◆この記事は何？
午後問題の勉強方法について共有する記事です。

◆対象は？
情報処理技術者試験の高度区分を受験する方（特に情報処理安全確保支援士）

◆この記事のねらい
**午後問題対策**の戦略立案の参考になれば幸いです。

## 先に結論
- 午後問題(過去問)が解けなかったのは、**基礎力が足りない**せい
- 基礎力を上げると合格基準に到達、効率も上がりました
    - 解くスピードの向上
    - 復習の効率向上
    - 精神的な負荷軽減
- ここでの「基礎力」とは、シラバスの用語を全て説明できるようになること

## 背景
2024年春の情報処理技術者試験を受験しました。

先日受験したばかりでまだ結果は返ってきていませんが、午後問題の対策で良かったことを共有したいと思います。

## 午後問題の対策でよく言われていること

午後問題の対策として次のような内容をよく聞きます。
- 「記述に慣れましょう」
- 「文量に慣れましょう」
- 「過去問をやっておきましょう」

間違いではないと思います。私も過去問を解きました。

## 午後問題を解いたときに思ったこと

午後問題(過去問)を解いて思ったのは「**なんとなくわかるけど、解けない**」でした。

応用情報の勉強で覚えたはずの内容や、新たに学んだはずの内容が曖昧で、解けるまでには至りませんでした。

問題文中で使われている用語も、知らない単語が多かったです。

## 基礎力を上げた

そのまま過去問を解く、という選択肢もあり得たのですが、過去問に慣れることよりも基礎を優先しました。

やったこと/意識したことは次のとおりです。

- 午後問題の過去問演習は一旦やめました
- シラバスに掲載されている用語を理解して説明できるようにしました
- 時間をかけました
- 基礎力チェックのために、午前2を解きました

## 基礎力を上げて解いてみた

基礎力を上げて、午後問題を解いた結果、次のような変化がありました。

- スラスラと解けました
- 合格基準である正答率6割以上が連発しました
- 問題のやり直し/復習も楽にできました
- 解く時間が短くなったので、回数をこなせるようになりました
- 自信もつき、精神的にも楽になりました

午後問題が解けない要因はいくつかあったと思うのですが、その中で一番効いたのが**基礎**でした。

## おわりに

午後問題が解けない要因は、不慣れではなく、基礎が足りないせいでした。

基礎を重視したことで、「試験のための勉強」「受験テクニック」というよりも「しっかりと身につく勉強」ができました。

試験区分は決めていませんが、私は再びIPA高度試験を受験すると思います。
そのときも基礎重視で勉強するつもりです。

本記事が試験勉強の戦略立案に少しでもお役に立てれば幸いです。

それでは。
git fetchとは何か

## Git Fetchの概要
Git fetchは、リモートリポジトリから最新の情報をローカルリポジトリに取得するGitコマンドです。このコマンドは、リモートリポジトリにあるコミット、ファイル、ブランチの情報をローカルにダウンロードするために使用されますが、ローカルの作業ディレクトリのファイルを変更することはありません。つまり、fetchはリモートの状態を確認するための安全な方法であり、ローカルの作業には影響を与えません

下記記事のイメージがわかりやすかったため、引用させていただきます。
引用元：[fetch｜サル先生のGit入門](https://backlog.com/ja/git-tutorial/stepup/15/)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2040900/7103f30f-1ea2-e253-d065-ba9b4c6de7a3.png)


## Git Fetchの動作
Git fetchを実行すると、リモートリポジトリの情報がローカルのリモート追跡ブランチに反映されます。リモート追跡ブランチとは、リモートリポジトリのブランチの状態を追跡するためのローカルのブランチです。例えば、リモートの`main`ブランチの最新状態はローカルの`origin/main`に反映されますが、ローカルの`main`ブランチ自体は変更されません

## Git Fetchの利点
Git fetchの主な利点は、リモートリポジトリの最新の変更を確認できることです。これにより、他の開発者が行った変更を確認したり、必要に応じてローカルブランチに統合する前に、変更内容をレビューすることができます。また、fetchはリモートの状態を取得するだけなので、ローカルの作業を誤って上書きするリスクがありません

## Git Fetchの使用方法
Git fetchを使用するには、ターミナルやコマンドプロンプトで以下のように入力します。
```bash
git fetch <リモート名>
```
ここで`<リモート名>`は通常`origin`ですが、リモートリポジトリの名前に置き換えてください。このコマンドを実行すると、リモートリポジトリの全てのブランチの情報がローカルに取得されます。特定のブランチの情報のみを取得したい場合は、ブランチ名を指定します。
```bash
git fetch <リモート名> <ブランチ名>
```
例えば、`origin`リモートの`main`ブランチから情報を取得したい場合は、以下のようになります。
```bash
git fetch origin main
```
fetchによって取得された情報は、`git log`コマンドを使用して確認することができます。例えば、リモートの`main`ブランチに追加されたコミットを確認するには、以下のようにします。
```bash
git log origin/main
```
## まとめ
Git fetchは、リモートリポジトリの最新情報を安全に確認するためのコマンドです。ローカルの作業に影響を与えることなく、リモートの変更をローカルに取得できるため、開発者がリモートの状態を確認し、必要に応じてローカルブランチに統合する際に役立ちます。
Salesforce 子リレーション検索画面つくってみた

# **子リレーション検索画面**
Workbenchを使用すれば、親オブジェクトに関連する子リレーションを確認することができますが、少し使いづらい点があったので作成してみました。  
良ければ、お使いください💁‍♂️  
(Lightning推奨)

## ソースコード(GitHub)
https://github.com/yutashio/sfdc_Childrelationshipview

## 検索条件
![image01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772806/23d02d20-6f82-a8d4-f7f9-c4a584f3cf49.png)
- 親オブジェクト名
- 親オブジェクトAPI参照名
- 作成者ID & 最終更新者IDを省く  

## 検索結果
![image02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772806/f57865f9-7b59-fdea-0b33-12446438204e.png)
- オブジェクト名
- オブジェクトAPI参照名
- Standard/Custom (オブジェクト)
- 項目名
- 項目API参照名
- Standard/Custom (項目)
- 子リレーション名
- カスケード削除
  
## 「オブジェクトマネージャ」へ遷移
オブジェクト名をリンク化しております。  
クリックすることで、新規タブで該当のオブジェクトマネージャーを開くことが可能です！！  

例）「取引先」を選択
![image05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772806/6cbfa6d9-963b-7e09-947c-43afe403a27a.png)
「取引先」設定画面へ遷移完了
![image06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772806/389adc29-e4b2-fad3-59b8-5c7751d80cdd.png)

## 検索時の作成者ID & 最終更新者IDを省く設定
ユーザオブジェクトなどは、子リレーションの件数が多くなってしまうため検索条件として、「作成者ID & 最終更新者IDを省く」チェックボックス✅を用意しております。  

チェックなし(1714件)
![image03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772806/138dd5e0-e8bb-bd5d-11be-dcaae8486e86.png)
チェックあり(507件)
![image04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3772806/3963e204-8028-198f-212c-09cb63381d34.png)
Unreal Enigne5.3のWebsocketsライブラリを使うとURL末尾に"/"が追加されて困った

## 解決方法
応急処置的だが、
`UnrealEngine\Engine\Source\Runtime\Online\WebSockets\Private\Lws\LwsWebSocket.cpp`
の`ConnectInternal`内の該当箇所（722行付近）を以下のように置き換えることで解決できる。

```cpp
	/*
	int32 UrlPathLength = FCStringAnsi::Strlen(TmpUrlPath) + 2;
	TArray<ANSICHAR> UrlPath;
	UrlPath.Reserve(UrlPathLength);
	UrlPath.Add('/');
	UrlPath.Append(TmpUrlPath, UrlPathLength - 2);
	UrlPath.Add('\0');
	*/

	TArray<ANSICHAR> UrlPath;

	// Check if TmpUrlPath starts with '/'
	if (TmpUrlPath[0] != '/') {
		int32 UrlPathLength = FCStringAnsi::Strlen(TmpUrlPath) + 2; // Extra space for adding '/' at the beginning
		UrlPath.Reserve(UrlPathLength);
		UrlPath.Add('/'); // Add '/' at the beginning if it doesn't start with '/'
		UrlPath.Append(TmpUrlPath, UrlPathLength - 2); // Append the existing path
		UrlPath.Add('\0'); // Null-terminate
	}
	else {
		// If TmpUrlPath already starts with '/', use it as is
		int32 UrlPathLength = FCStringAnsi::Strlen(TmpUrlPath) + 1;
		UrlPath.Reserve(UrlPathLength);
		UrlPath.Append(TmpUrlPath, UrlPathLength - 1); // Append the path
		UrlPath.Add('\0'); // Null-terminate
	}
```

## 困ったタイミング
ROS2のRosbridge_suiteを使ってUnreal EngineとROS2をWebsocket通信で接続しようとした際に、ROSBridgeが`[rosbridge_websocket-1] WARNING:tornado.access:404 GET //`と怒ってきて困ってしまった。

## 原因
`lws_parse_uri()`が、`ws://localhost`のようにエンドポイントを指定しないURIに、`/`を加え、`ws://localhost/`とするようになっているにも関わらず、`ConnectInternal`内で`/`が加えられており、URLが`ws://localhost//`のようになっている。
もう少し詳細には、エンドポイントを指定しない場合にエンドポイント名を`/`とする処理をしている。

## 解決法の解説
末尾がすでに`/`になっているときは、`/`を加えないようにすることで応急処置した。
sarコマンドでLinuxのパフォーマンスデータを取得してCSV化する

# はじめに
sarコマンドを使用してLinuxのパフォーマンスデータを取得しCSV化する。
後ほど別記事で、CSVファイルをPythonで読み込んでグラフ化する。

# 前提
* Linux
* sysstat（$ sudo apt install sysstat などでインストールしておく）

# パフォーマンスデータの取得
下のようにsarコマンドを実行し結果をファイルに保存する。
（この例では、全てのデータを1秒間隔で300回取得している。要は5分間。）
```
sudo sar -A -o test001.sar 1 300
```

# sarファイルのCSV化
sadfコマンドでsarファイルからCSVを出力する。
（本来の出力はタブで区切られているためカンマ区切りに変換している。）
```
sudo sadf -T -- -A test001.sar | tr "\t" , > test001.csv
```
下のようなCSVが出力できる。
![sar-csv001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662088/f6305ea8-31ca-c796-0220-6d7ff24fe386.png)
1列目がホスト名、2列目が取得間隔、3列目が取得時刻、4列目・5列目が取得カテゴリ、6列目が値となっている。
次回の記事で、このファイルをPythonで読み込んでグラフ化する。

# sadfによるグラフ化
sadfコマンドでもsarファイルからグラフを作成することはできる。
すべてのデータを指定すると縦に非常に長い画像となってしまうので、ここではCPUだけを対象としたグラフを作成してみる。
```
sudo sadf -T -g -- -P all test001.sar > test001-CPU.svg
```
下のようなグラフが出力される。
![sadf-graph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662088/00ad2088-125e-c996-430d-87dc9168634b.png)
JavaScriptで電力測定してみた



電力測定をする際に電流量測定のモジュールを使ってみようかと思ったところスイッチボットシリーズのスマートプラグで消費電力などを計測できることを知ったので試してみました。

obnizを使うことでJavaScriptで電力測定ができます。

## SwitchBotプラグミニ

スマートホーム的な何かをやれるコンセントです。

> [![スクリーンショット 2024-04-22 18.25.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/f272c21e-dc63-73ad-36e6-daa53560ea9b.png "スクリーンショット 2024-04-22 18.25.15.png")](https://amzn.to/3UpTzZC)
> https://amzn.to/3UpTzZC

結構安い。スマホからオンオフできて便利。

## obnizのパーツライブラリにもある

obnizからこのプラグにアクセスできるとのことで、BLEを使って情報にアクセスできる模様です。

https://docs.obniz.com/ja/sdk/parts/Switchbot_PlugMini/README.md


サンプル動かしただけでエラーなくいけました。

## コピペで動くコード

ライブラリのインストールから。ライブラリ(obniz JS v3.30.1)で試しています。

```bash
$ npm init -y
$ npm i obniz
```

IDだけ書き換え、以下のコードでファイルを作成して実行します。

```js
const Obniz = require("obniz");

const obniz = new Obniz("1234-5678"); //自身のIDに書き換え

obniz.onconnect = async function () {
    // Javascript
    const Switchbot_PlugMini = Obniz.getPartsClass("Switchbot_PlugMini");
    await obniz.ble.initWait();

    obniz.ble.scan.onfind = async (peripheral) => {
        if (Switchbot_PlugMini.isDevice(peripheral)) {
            console.log(Switchbot_PlugMini.getData(peripheral));
        }
    };
    await obniz.ble.scan.startWait(null, {duplicate: true, duration: null});
}

```

実行

```
$ node app.js
```

実行結果は以下のような感じです。

> ![スクリーンショット 2024-04-22 18.28.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/470fafbe-2f5e-7828-2655-6aa4c655d032.png "スクリーンショット 2024-04-22 18.28.44.png")

obnizのドキュメントを見ると以下のようなパラメータが取れそうでした。`sequenceNumber`と`alreadsySyncTime`がイマイチなんの値か現状分かってないです。調査不足。

- sequenceNumber: なんだろう...
- powerState: プラグがオンかオフか
- hasDelay: 遅延実行がオンになっているか
	- SwitchBotの機能でそういうのがあるぽい
- hasTimer: タイマーがセットされているか
	- SwitchBotの機能でそういうのがあるぽい
- alreadsySyncTime: なんだろう...
- wifiRssi: Wi-Fiの電波強度
- overload: オーバーロード、高負荷状態
- power: 消費電力

## ちゃんと取れてるかの確認

アプリでの表示とNode.jsのコンソール上での比較をすると

> ![スクリーンショット 2024-04-22 18.40.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/85461654-29fb-7173-05a5-5118259e1525.png "スクリーンショット 2024-04-22 18.40.13.png")

> ![スクリーンショット 2024-04-22 18.38.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/8d9a0f90-7907-1a1f-ad46-ce1c60847c1e.png "スクリーンショット 2024-04-22 18.38.54.png")

同じタイミングのスクショですが、アプリ上の電力って値が`12.5`WでNode.jsのターミナルでのpowerの値が`12.5`ということで一致していますね。

## コンセントの（デバイス）接続数でちゃんと数字変化

↑はプラグの先にMacBookとiPhoneを充電している状態で12.5Wという表示でした。

- MacBookだけだと6.8W

> ![スクリーンショット 2024-04-22 18.46.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/168dfe45-5bb5-e629-9ef0-484c05f3ae46.png "スクリーンショット 2024-04-22 18.46.19.png")

- 何も接続していないと0W

> ![スクリーンショット 2024-04-22 18.47.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/29fec27c-c7bf-c5ad-cf65-714d6be8a967.png "スクリーンショット 2024-04-22 18.47.32.png")

純正のAppleのアダプターを使っているからかもしれないですがちゃんと0Wになるのすごいですね。

## 現状obnizからOn/OFF制御はできないっぽい

SwitchBot側の(Bluetoothの)APIが開いてない可能性もありますが、現状obniz側からは電力などの情報取得しかできないみたいです。

getData()のメソッドだけで何ができるか検討してみたいと思います。
エディタ分割・解除ショートカットを設定する【VSCode】

# はじめに

VSCodeで「ちょっと比較したい！」ってなるとき、分割をショートカットでできると便利です。

※macOSを前提とした記事ですが、Win / 他の方も応用可能な内容です。

# ショートカット一覧の表示

この後の作業のために覚えましょう。

「`cmd + k` → `cmd + s`」です。
# エディタ分割

デフォルトで設定されています。最も簡単なものは`cmd + \`ですね。

確認したい方は、先程のショートカット一覧表示（`cmd + k` → `cmd + s`）から、`split`と検索しましょう。

![スクリーンショット 2024-04-11 15.59.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457770/40e0490b-7e7f-7096-e75e-211e0b2a81dd.png)

# エディタ分割の解除

これはデフォルトで設定されていません。

ショートカット一覧表示（`cmd + k` → `cmd + s`）から、`join`と検索しましょう。

![スクリーンショット 2024-04-11 16.01.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457770/73422dd1-6bf5-6e1b-c40a-8df4928eac56.png)

「表示：すべてのエディターグループを統合」にショートカットを追加します。

私は`cmd + shift + \`にしました（競合するものはすべて解除しました）。

# おわりに

以上、簡素ですがエディタ分割・解除方法でした。

ぱっと調べても出てこなかったので記事にしました。
どなたかの役に立てば幸いです。

さて、次は何を書こうかしら・・・
Vue.jsでフォームの値リセットと再描画を行う方法

Vue.jsで複雑なフォームを扱っている際に、フォームの値をプログラム的にリセットする必要がある場合があります。しかし、単にデータモデルをリセットするだけでは、UI上のフォーム要素に反映されないことがあります。この記事では、Vue.jsでフォームの値をリセットし、UIにもきちんと反映させる方法を解説します。

## 問題の説明
Vue.jsでv-modelを使用してフォームの入力値とデータを双方向バインディングしている場合、データオブジェクトの値を変更しても、DOMが即座に更新されないことがあります。これはVueのリアクティブシステムとDOMの更新サイクルが原因です。

## ソリューション

コンポーネントのキーを変更する
フォームやその他のコンポーネントを完全に再描画するために、コンポーネントのkeyを変更します。これにより、Vueはコンポーネントが新しいものと認識し、完全に再生成します。

```vue:vue
<template>
  <div :key="formKey">
    <my-form-component :form-data="formData"></my-form-component>
  </div>
</template>

<script>
export default {
  data() {
    return {
      formKey: 0,
      formData: {
        // 初期フォームデータ
      }
    };
  },
  methods: {
    resetForm() {
      this.formData = {
        // フォームデータをリセット
      };
      this.formKey++; // キーをインクリメントして再描画をトリガー
    }
  }
}
</script>
```

## まとめ
この記事では、Vue.jsを使用してフォームの値をプログラム的にリセットし、それをDOMに反映させる方法を紹介しました。
表領域の（過去からの）状態遷移を確認する

以下のSQLを実施する。
粒度は、snapshotが取られる間隔に依存する。

select v.name
 ,h.snap_id
 , h.tablespace_size * p.value/1024/1024 ts_mb
 , h.tablespace_usedsize * p.value/1024/1024 used_mb
 , h.rtime
 , to_char(s.begin_interval_time, 'YYYY-MM-DD HH24:MI:SS') begin_time
 , to_char(s.end_interval_time, 'YYYY-MM-DD HH24:MI:SS') end_time
  from dba_hist_tbspc_space_usage h
 , dba_hist_snapshot s
 , v$tablespace v
 , dba_tablespaces t
 , v$parameter p
  where h.tablespace_id = v.ts#
  and v.name = t.tablespace_name
  and t.contents not in ('UNDO','TEMPORARY')
  and p.name = 'db_block_size'
  and h.snap_id = s.snap_id
  and s.begin_interval_time 
-- Start time
  between to_date('2024-04-22 11:00:00','YYYY-MM-DD HH24:MI:SS') 
-- End time
  and to_date('2024-04-22 18:00:00','YYYY-MM-DD HH24:MI:SS')
-- specify tablespace
  and v.name in ('USERS')
 order by v.name, h.snap_id asc;



 以下のブログを参考にしました。
https://www.pythian.com/blog/technical-track/how-to-retrieve-growth-history-for-oracle-tablespaces