OmniAICreator/Qiita-1.07M huggingface dataset:
rex0220 計算式プラグイン チェックボックスの自動セットと手動選択

[計算式プラグイン](https://qiita.com/rex0220/items/ae83c6d5ce50ff7a9a73)で、チェックボックスの自動セットと手動選択を行ってみます。

# 概要

単純に計算式でチェックボックスに値を自動セットすると、手動選択が出来なくなります。
自動セットする条件と手動選択をする計算式を記述してみます。

- チェックボックス1：　数値>10 の場合、"A"をセット。"B","C"は、選択
- チェックボックス2：　ラジオボタンの値をセット。それ以外は選択
- チェックボックス3：　数値3>10 に変更時、"A"をセット

計算式の考え方としては、「自動セットする選択肢」と「手動セットする選択肢」を合わせて配列にすることです。

- チェックボックス1、チェックボックス2

![2025-01-19_20h18_33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/2643845a-3b2f-3433-0753-224983a81b7b.png)


- チェックボックス3：　数値3>10 に変更時、"A"をセット

![2025-01-19_21h36_23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/947e33b9-f2cb-ef53-b460-17827dc81dc2.png)


# 操作例

![2025-01-19_20h30_53.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/381b5a5a-a675-1715-c10f-0cc93b928af7.gif)

- チェックボックス3

![2025-01-19_21h42_02.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/99230fa9-6c92-808b-ed09-40dec6e923f7.gif)


# 計算式プラグイン設定

「循環参照を許可」をチェックします。

![2025-01-19_21h37_14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/30044569-c51d-e6c4-9b6f-fb1098866369.png)


- チェックボックス1：　
    - 数値>10 の場合、"A"をセット。"B","C"は、選択
        - DISTINCT で、"A"と選択肢から重複値を排除
    - 数値<=10 の場合、
        - ARRAY_DEL で、"A" を選択肢から削除
</br>

- チェックボックス2：　ラジオボタンの値をセット。それ以外は選択
    - DISTINCT で、ラジオボタンとチェックボックス2の重複値を削除

</br>

- チェックボックス3：　
    - 数値3>10 に変更時、"A"をセット
        - EV_INFO("fcode")="数値3"　は、数値3変更イベント
        - DISTINCT で、"A"と選択肢から重複値を排除

```.js
計算式プラグイン
OPTION: 循環参照を許可

// チェックボックス1 CHECK_BOX (editable)
IF(数値>10,
  DISTINCT("A",ARRAY(チェックボックス1)),
  ARRAY_DEL(チェックボックス1,"A")
)

// チェックボックス2 CHECK_BOX (editable)
DISTINCT(ラジオボタン,チェックボックス2)

// チェックボックス3 CHECK_BOX (editable)
IF(AND(EV_INFO("fcode")="数値3",数値3>10),
  DISTINCT("A",ARRAY(チェックボックス3)),
  ARRAY(チェックボックス3)
)
```
人の切り崩し方

どうも、のどかはです


これは数分もかかんない文章量なので、読みやすいかもです

## 人って完璧じゃない話

人は当たり前ですが情報を伝えられた時に疑うよりも飲み込みたい者です。

評価したり確かめたり確認すること、考え込むことが嫌いです。

ですので立て続けに発言できる人の前では、人間というのは盲信しやすくなります。

この文章も事実が並んだように見せた結果、そうであるかのように感じます。

## 完璧って話
逆にいうなら完璧に見せることが簡単だという話です。

そして完璧度合いを大きく見せれば見せるほど、有能に見えます。

実態は？という話です。

そう

完璧に見せようとしてる人は弱いんです。

擬態と同じように、何かを身に纏おうとしている人は弱いです。

## 文章という呪縛
人は文章を見た時に作者の意図より先に自らの主観ベースで捉えます。

あなたは今回の文章を読んで落ち込んだか、己との共通点を勝手に探し始めたはずです。

そして謎の思考のループに陥るか、自らの特徴を元に自身を評価してしまったでしょう。

そうじゃない人はこんな文章に多分興味持たないです。

## 知識や勉強って何って話
国語で一番嫌な問題、大人にいっつも言われてうざったい話、いっつも指摘されるような常識とかいうやつ。

大事だって言われて言われてうるさい話。

恐らく作者の意図を考えることは無駄だ。

新しい革命を個性を発揮していけば大物になれると信じ込んできたはずです。

僕たちはいっつもそういうのを追い求めてきたでしょう。

これも盲信させるための文章ですが、まあ少なくとも正しさはあるでしょう。

けれどという話です。

頭を疲れさせてしまうような

人のことを考えてみるという行為は、実は遠回りなようで実力をつける近道です。

それができないんだと言い始める前に冒頭を思い出してください。

人って完璧じゃないんです。

みんな完璧じゃない中で人のことを考えて見てるんです。

主観的に、わがままに

身勝手に

じゃあきっとおんなじことを考えてるんだってことに気づくと思います。

## おわり

今回は以上です。

お読みいただきありがとうございます。
【テスト自動化】Playwrightで異なるロールのアカウントで同時にテストを行う

## 前書き
自動テストで、例えばアドミン権限を持つ`アカウントA`でユーザーアカウント相当の`アカウントB`のロールの変更を行い、ロール変更に伴ってメニューの出し分けや実行できるアクションが適切に変わっているかを確認するシナリオを作成したくなるシチュエーションがあるかと思います。
ここでは2つのブラウザを用意し、それぞれのブラウザに`アカウントA`と`アカウントB`でログインを行い、`アカウントA`でロール変更を行なった際に即座に（ログインし直すことなく）`アカウントB`で確認するような自動テストをPlaywrightで実装する方法を記載いたします。

## 認証
（以下Playwrightの基本的なセットアップはできている前提で記載させていただきます）
まず認証情報を保存するためのjsonファイルを作成します。
認証情報を保存しておくことで、後続のテストで再利用することができます。（テストシナリオのたびにログインし直す必要がない。）
アドミンアカウントとユーザーアカウント用にそれぞれ`admin.json`と`user.json`を作成します。
またこれらのjsonファイルはgit管理する必要がないのでgitignoreに追加しておきます。

```
mkdir -p playwright/.auth
touch playwright/.auth/admin.json
touch playwright/.auth/user.json
echo $'\nplaywright/.auth' >> .gitignore
```
以下のセットアップファイルでアドミンアカウントとユーザーアカウントそれぞれでログインを行い、それぞれの認証情報を作成したjsonファイルに保存します。
``` tests/auth.setup.ts
import { test as setup, expect } from '@playwright/test';

const adminFile = 'playwright/.auth/admin.json';

setup('アドミンアカウントでログイン', async ({ page }) => {
  // ログインステップ
  await page.goto('https://github.com/login');
  await page.getByLabel('Username or email address').fill('admin');
  await page.getByLabel('Password').fill('password');
  await page.getByRole('button', { name: 'Sign in' }).click();
  // ログイン後に遷移するURLを待つ（クッキーがセットされるのを待つ）
  await page.waitForURL('https://github.com/');

  // admin.jsonに認証情報を保存する
  await page.context().storageState({ path: adminFile });
});

const userFile = 'playwright/.auth/user.json';

setup('ユーザーアカウントでログイン', async ({ page }) => {
  // ログインステップ
  await page.goto('https://github.com/login');
  await page.getByLabel('Username or email address').fill('user');
  await page.getByLabel('Password').fill('password');
  await page.getByRole('button', { name: 'Sign in' }).click();
  // ログイン後に遷移するURLを待つ（クッキーがセットされるのを待つ）
  await page.waitForURL('https://github.com/');

  // user.jsonに認証情報を保存する
  await page.context().storageState({ path: userFile });
});
```
## テスト
アドミンアカウント・ユーザーアカウント用それぞれの`BlowserContexts`を作成します。
`storageState`で認証用に作成したjsonファイルを指定することでログインした状態でテストを開始することができます。
それぞれのブラウザでログインを行った後に、各アカウントでの具体的なテストを記載します。

```tests/example.spec.ts
import { test } from '@playwright/test';

test('admin and user', async ({ browser }) => {
  // アドミンアカウント用のBlowerContextsを作成する
  const adminContext = await browser.newContext({ storageState: 'playwright/.auth/admin.json' });
  const adminPage = await adminContext.newPage();

  // ユーザーアカウント用のBlowerContextsを作成する
  const userContext = await browser.newContext({ storageState: 'playwright/.auth/user.json' });
  const userPage = await userContext.newPage();

  await adminPage.goto(url);
  await adminPage.sideMenuButton.click();
  // 以下に例えばユーザーアカウントのロール変更を行うアクションを記載する

  await userPage.goto(url);
  await userPage.sideMenuButton.click();
  // 以下に例えばユーザーアカウントのロール変更を確認するアクションを記載する

  await adminContext.close();
  await userContext.close();
});
```
## 最後に
今回はロール変更の際の挙動を確認するテストを例にご紹介しましたが、例えばチャット機能などを有するプロダクトのテスト自動化では送信側と受信側でそれぞれ別々のアカウントでログインを行いテストを行うなどのシナリオでも応用できるかもしれません。

https://herp.careers/v1/justincase/JWF43Evxcuut
【Discord】メッセージの転送機能について解説

こんにちは、りょうです
今回は一月くらい前に正式に実装されたメッセージの転送機能について解説します

# メッセージの転送
もともとβ版で一部ユーザーに先行で提供されていました。
メッセージを他のサーバーやDMにそのまんま送る機能になります。
転送されたメッセージにはこのように**転送済み**という表示がついています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818367/6564142e-a5fd-9b15-66ee-c0d3d6bb8ae3.png)

このどこから転送されたかという表示はこうなってます。
ここを押すと転送元のメッセージに飛びます。
ただし、所属していてもアクセス権のないチャンネルだと表示はありません。

| 場合 | 表示 |
|:-:|:-:|
| サーバー内から|  転送先のチャンネル名 |
|サーバー外(所属鯖or公開鯖)|サーバーアイコン+サーバー名|
|サーバー外(未所属鯖)|表示なし|
|DM|表示なし|

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818367/b6c1e7e3-c5db-8d84-6081-73cf186beddd.png)

テキストメッセージだけでなく、画像や動画等もそのまま転送が可能です。

# 転送の手順
まず転送したいメッセージを右クリして**転送**を押します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818367/18166cf4-3f1a-460f-6de1-1746d239bdb4.png)

次に転送先のサーバーを選択します。
チャンネル名で検索も可能です。ユーザー名で検索すればDMにも送れます。
選択ができたら送信を押して完了です。

:::note info
最大5箇所にメッセージを転送できます
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818367/e7b427fc-346f-9c91-d8fe-d654f1fcb9e7.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818367/6da8c55c-760c-afdc-4bd2-ca18329522de.png)

## メッセージを追加
この入力欄にメッセージをいれて追加でメッセージを送信できます。
これで追加されたものは転送のメッセージとは別枠で送信されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818367/48d72b95-8a5c-bc77-7010-3006452fb301.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818367/d8533b3f-bd16-db73-a3f0-70a135f09539.png)

# 荒らしに使われるのか？
結論として使われるかもしれませんが、今までの対策の方法で**充分防げます**。
メンションは転送された場合はすべて自動でオフになります。
また、転送メッセージも通常のものと同じようにAutomodやWickなどのBOTで防げることを確認しました
扱いは一緒みたいですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818367/13b6e623-115a-4ba1-3d36-4ce7082811d7.png)

# その他
元メッセージが編集されたとしても、転送メッセージは更新されません。
今後実装されるかもしれませんが今のところは転送されないようにする機能などはありません。
アナウンスチャンネルへの転送はできませんでした。
年齢制限をかけている場所からかかっていない場所への転送もできません。

# まとめ
今回はメッセージの転送機能について解説をしました。
個人的には同じサーバー内であれば今までのBOTのメッセージリンク自動展開機能のほうが便利だなあとか思ってしまいました。
慣れれば便利な機能だとは思うのでしばらく使ってみようと思います。
今後また何かあれば追記します

わからないことがあれば書いてくれれば答えます！

**Discord荒らしの情報や対策方法の共有をしている自鯖です**
ぜひ参加お願いします↓↓↓↓

https://discord.com/invite/ESRGwGQhxc
[VirtualBox][Mac] Mac環境で仮想マシンファイルからVirtualBoxを起動する

# 環境
MacBook Pro (2.3 GHz 8コアIntel Core i9)
macOS 14.0（23A344）
Homebrew 4.3.8
gh 2.52.0

# 目次
- [ディレクトリ構成](#ディレクトリ構成)
- [手順](#手順)

# ディレクトリ構成
~~~:directory_structure
drive/ ←ルートディレクトリ
├── Applications/
├── Syetem/
└── Usr/
│   ├── shared/
│   └── personnel(ex. Jochun)/　←ホームディレクトリ
│       ├── MyVagrant/
│       │   ├── MyTest001/
│       │   └── MyTest002/
│       │   └── MyTestLPIC002/
│       │       ├── Vagrantfile (ubuntu/trusty64) ←今回インストールしたVagrantboxによって作成されたVagrantfile
│       │       └── .vagrant (仮想マシン)
│       ├── Desktop/
│       ├── Downloads/
│       │   └── CentOS7LPIC1/ ←今回インストールした仮想マシンファイル
│       ├── Documents/
│       ├── .config/
│       ├── .ssh/
│       ├── .zshrc/
│       └── .local/
│           ├── .bin
│           └── 
~~~

# 手順
1. 仮想マシンファイルをダウンロードする（プロジェクトや研修で配布されたもの、サイトからダウンロードしたもの）
1. `新規`を押下する
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/c8e13864-f563-9162-7d07-5c2fc344ae65.png)
1. `名前`を記載する
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/ff61b6a8-80cd-931e-7cf4-a053744786fb.png)
1. 保存先のディレクトリを選ぶ（今回は`MyVagrant`）
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/1ce4df1e-af21-babe-8cfc-3afbaa78b7ea.png)
1. `次へ`を押下する
1. `1024MB`にする
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/1adfbe42-92be-f09d-0926-141102756dc6.png)
1. `すでにある仮想ハードディスクを使用する`のチェックマークを有効にする
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/54d08257-2672-3361-dba2-f0eae4b435c0.png)
1. 右端のフォルダのアイコンを押下する
1. `追加`を押下する
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/ed1e7eb0-5a12-3992-06f1-66d6f71be73a.png)
1. ダウンロードした仮想マシンファイルの`.vdi`を選択する
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/abcd4091-e37d-a98d-bb7b-cfd020d6363d.png)
1. `次へ`を押下する
1. `完了`を押下する
1. 作成した`MyTestLPIC002`というVirtualBox`が新たに作成された
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/1399e6c8-18da-ab76-b407-9f81a6693f0a.png)


# 参考リンク
JavaScript でスクロールバーの幅を取得し、CSS でレイアウトを最適化する方法

OSやブラウザのスクロールバーによって、レイアウトが崩れたり、意図しない余白が生じたりするなど、コンテンツの表示が影響を受けることはよくあります。例えば、テキストの改行位置が変わり、デザインとのずれが生じるなどです。
通常は特に気にする必要はありませんが、特定のコンテンツ内でのみスクロールを制御する必要があったため、スクロールバーの影響を受けずにコンテンツを表示する方法を探したところ、以下の方法を見つけました。

<p class="codepen" data-height="300" data-default-tab="js,result" data-slug-hash="XJrBBBq" data-pen-title="Calculate Scrollbar Size" data-user="HManiwa" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/HManiwa/pen/XJrBBBq">
  Calculate Scrollbar Size</a> by H. Maniwa (<a href="https://codepen.io/HManiwa">@HManiwa</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://public.codepenassets.com/embed/index.js"></script>

~~※ なぜかCodepenが表示されません~~

## CSS
`scrollbar-gutter`プロパティでスクロールバーの表示領域を確保し、CSSカスタム変数で設定したスクロールバーの幅をコンテンツの余白から差し引きます。
[scrollbar-gutter - MDN](https://developer.mozilla.org/ja/docs/Web/CSS/scrollbar-gutter "scrollbar-gutter")

```css
:root {
  --box-padding: 24px;
  --scrollbar-size: 0px;
}

.box {
  inline-size: 400px;
  block-size: 400px;
  overflow: hidden;
}

.inner {
  padding: var(--box-padding);
  block-size: 100%;
  overflow: auto;
}

#box-2 > .inner {
  padding-inline-end: calc( var(--box-padding) - var(--scrollbar-size) );
  scrollbar-gutter: stable;
}
```

## JavaScript
`getScrollbarSize()`関数は、スクロールバーのサイズを取得し、取得した値をCSSカスタムプロパティ`--scrollbar-size`に`setProperty()`メソッドを使って設定します。

この関数は、一時的な`div`要素を生成して`body`に追加し、その要素のオフセット幅/高さとクライアント幅/高さの差分を調べることで、スクロールバーのサイズを算出しています。

要素にスクロールバーが表示されている場合、オフセット幅/高さにはスクロールバーの幅/高さが含まれますが、クライアント幅/高さには含まれません。この差を利用することで、スクロールバーのサイズを算出できます。
この差分がスクロールバーのサイズとなり、その値が返されます。[^1]

```javascript
function getScrollbarSize() {
  const div = document.createElement("div");
  div.style.overflow = "scroll";
  div.style.width = "100px";
  div.style.height = "100px";
  div.style.position = "absolute";
  div.style.visibility = "hidden";

  document.body.appendChild(div);

  const scrollbarWidth = div.offsetWidth - div.clientWidth;
  const scrollbarHeight = div.offsetHeight - div.clientHeight;

  document.body.removeChild(div);

  return { width: scrollbarWidth, height: scrollbarHeight };
}

const scrollbarSize = getScrollbarSize();
document.documentElement.style.setProperty(
  "--scrollbar-size",
  `${scrollbarSize.width}px`
);
```

[^1]:ここでは縦スクロールバーのサイズのみを取得しているため、`scrollbarSize`オブジェクトの`width`プロパティを使用しています。縦横両方のスクロールバーの値を設定する場合は、コードを適宜修正してください。
【Blender To Unity】BlenderからUnityに移行する際の注意点の記事リンク

　BlenderからUnityに移行する際に気を付けるべきポイントをまとめた記事のリンク集です。
　BlenderToUnity関連の記事を投稿するたびに順次更新していきます。

# 「BlenderからUnityにモデルをエクスポートする方法」
　BlenderからUnityにモデルをエクスポートする際の実践的な手順についてまとめた記事です。

https://qiita.com/fuji_kyoto_kc/items/57697feac48ad83fd706

# 「FBXファイルエクスポート時のコレクション構造について」

 Blenderで作成したFBXファイルをエクスポートする際のコレクション構造に関する記事です。

https://qiita.com/fuji_kyoto_kc/items/685e1dbded19bb43916c

# 「Blenderで作成したマテリアルをBakeしてUnityにインポートする方法」

　Unityにモデルをインポートした際に、テクスチャを抽出しても反映されないテクスチャが存在する場合のトラブルシューティング記事です。

https://qiita.com/fuji_kyoto_kc/items/5beee314d239ae59b811

# 「オブジェクトのTransform値を適用時や結合時などに面が裏返ってしまう」
　エクスポートする前にオブジェクトのTransform値を適用したり、結合した際に、面が裏返ってしまうことがあります。その原因と開発の際に心がけるべきことをまとめた記事です。

https://qiita.com/fuji_kyoto_kc/items/759a6e676f7ae0b93250
#0019（2024/01/19）Kinesis Data Firehose と Amazon Kinesis Data Streams の違い

# モチベーション
- Kinesis Data Firehose と Amazon Kinesis Data Streams をAWS SAAの模擬試験中によく読み違えたりしたので、違いを整理してみた。

# Kinesis Data Firehose と Kinesis Data Streams の違い

AWSでデータストリームを扱う際、**Amazon Kinesis Data Firehose** と **Amazon Kinesis Data Streams** は混同しやすいサービスですが、それぞれ異なる用途と特徴を持ちます。この違いを明確に整理します。


## **1. 概要の比較**

| **項目**                        | **Kinesis Data Firehose**                              | **Kinesis Data Streams**                           |
|---------------------------------|-----------------------------------------------------|-------------------------------------------------|
| **主な用途**                     | データのストリーミング収集とターゲットへの配信         | リアルタイムでのデータストリーミング処理          |
| **処理のタイミング**             | ほぼリアルタイム（バッチ形式で配信）                  | 完全なリアルタイム処理                             |
| **データの保存期間**             | 一時的（S3や他のターゲットにデータを送信後消える）      | 最大 365 日間（デフォルトは 24 時間）             |
| **管理の必要性**                 | サーバーレスで自動管理                                 | サーバー管理が必要（シャード数を手動で設定）       |
| **サポートされるターゲット**      | S3、Redshift、Elasticsearch、Splunk など               | アプリケーション（Lambda、EC2、カスタムコンシューマ） |
| **スケーリング**                 | 自動スケーリング                                      | シャード数を手動で設定                           |
| **コスト管理**                   | シンプルな料金体系                                    | シャード数によって料金が変動                     |
| **データ変換**                   | サポート（Lambdaによる変換）                          | コンシューマ側で独自変換を実装                   |


## **2. 特徴の違い**

### **Kinesis Data Firehose** : データを収集して保存
- **完全マネージド型サービス**:
  - サーバーレスでスケーラブル、自動的にデータ収集からターゲットへの配信を管理。
- **データの変換と圧縮**:
  - Lambdaを利用してデータを変換可能（例: JSONをParquet形式に変換）。
  - データを圧縮（例: GZIP）して送信することでストレージコスト削減。
- **ターゲットへの配信**:
  - データを S3、Redshift、Elasticsearch、Splunk などのターゲットにバッチ形式で送信。
- **ユースケース**:
  - ログデータの収集と保存（例: サーバーログをS3に保存）。
  - データウェアハウス（Redshift）へのデータ投入。

### **Kinesis Data Streams** : リアルタイムデータ処理
- **リアルタイム処理向け**:
  - データを取得後、すぐにアプリケーションで処理可能。
- **カスタマイズ可能なシャード構成**:
  - データのスループットに応じてシャードを増減可能（1シャードは1秒間に最大1MB書き込み、2MB読み取り）。
- **データのリテンション**:
  - デフォルトでは24時間、最大365日まで保存可能。
- **コンシューマライブラリ**:
  - Kinesis Client Library (KCL) を使ってカスタムアプリケーションを構築可能。
- **ユースケース**:
  - IoTデバイスのリアルタイムデータ処理。
  - 動画やクリックストリームデータの分析。



## **3. まとめ**
- **Kinesis Data Firehose** は「データを収集して保存」するシンプルなサービスに最適。
- **Kinesis Data Streams** は「リアルタイムデータ処理」を求めるアプリケーションに適している。
(DAY26) 俺と学ぶRust言語~フォルダサイズ表示ツール~

# 今日の内容
- 指定したフォルダのサイズを返すツールを作る

# はじめに
[前回](https://qiita.com/FUKAch/items/8a29453a8c1fc62e16f9)はwriteとwrite_allの違いについて学びました。今回は、指定したフォルダのサイズを返すツールを作成します。（しました）。

今日から二週間ほど、記事を書く時間が無くなるためほとんどの投稿が事後報告になります。100DaysOfCode本来の姿と捉えてください。

時間ができたら、プログラムの詳細やポイントなどの説明文をついかします。

# 作成したツール
### 指定したフォルダのサイズを返すツール

**コード**
```rust
fn main() {
    let args: Vec<String> = std::env::args().collect();
    //もし開始するディレクトリが指定されなければ、今の位置の構造を表示する
    let path = args.get(1).unwrap_or(&".".to_string()).clone();
    match search_dir(path) {
        Err(e) => eprintln!("Error: {}", e),
        Ok(size) => println!("size: {} bytes", size)
    }
}

fn search_dir(path: String) -> Result<u64, Box<dyn std::error::Error>> {
    let mut total_size: u64 = 0;
    for entry in std::fs::read_dir(path)? {
        let entry = entry?;
        let metadata = entry.metadata()?;
        if metadata.is_file() {
            total_size += metadata.len();
        } else if metadata.is_dir() {
            if let Some(entry_path) = entry.path().to_str() {
                total_size += search_dir(entry_path.to_string())?;
            }
        }
    }
    Ok(total_size)
}
```
コマンドライン引数からディレクトリのパスを受け取り、隅々までファイルを探してファイルサイズを合算します。
もしパスが指定されなければ、実行したディレクトリのフォルダサイズを表示します。

# おわりに
二週間ほど事後報告になっていまうことをお許しください。
ご精読ありがとうございました。
UbuntuのDNS名前解決エラー(Temporary failure in name resolution)解消手順

# この記事について
VM上にインストールしたUbuntuでDNS名前解決エラーが発生したので解決の記録を残します。

# 環境
PC: MacBook Air M2
OS: macOS Ventura Ver. 13.2.1
Virtual Box: VirtualBox-7.1.4-165100-macOSArm64
Ubuntu image: ubuntu-24.04.1-live-server-arm64

# 参考
[Ubuntu 20.04 temporary failure in name resolution for wired](https://askubuntu.com/questions/1358221/ubuntu-20-04-temporary-failure-in-name-resolution-for-wired)

# 事象
Ubuntuで`ping www.google.com`コマンドを実行すると名前解決エラーが発生します。
```
Ping: www.google.com: Temporary failure in name resolution
```

# エラー原因
`/etc/resolv.conf`で指定されているデフォルトのDNSサーバーがDNSクエリを解決できておらずエラーが発生しているため、パブリックDNSサーバーに変更します。

# 解消手順
1. 既存の設定ファイルを削除します
    ```
    sudo rm /etc/resolv.conf
    ```
1. 設定ファイルを作成します
    ```
    sudo touch /etc/resolv.conf
    ```
1. 作成した設定ファイルを編集します
    ```
    sudo nano /etc/resolv.conf
    ```
1. `nameserver 1.1.1.1` を追記し、Ctrl+Sで保存しCtrl+Xでエディタを閉じます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219028/25d30bc1-7852-88af-02a2-6e7891d5d190.png)

1. DNSサービスを再起動します
    ```
    sudo systemctl restart systemd-resolved.service
    ```
1. pingが通るようになりました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219028/b51fa6b2-7366-9622-26ed-de4a6ce2286b.png)
Git Clone から編集まで（VSCode環境）

# Github & VSCodeのインストール
### Gitを使うまで
1, [GitHub](https://github.com/)のアカウントを作成

2, [GitHub](https://git-scm.com/)のインストール
ダウンロードから任意のOSを選択し、64-bit Git for Windows Setupを選択（基本的には）
![スクリーンショット 2025-01-19 191623.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989912/105a67be-d0db-6041-67f3-3106f18aa72d.png)

3, インストール後、Git Bashというアプリが使えるようになる
以下のようにして初期設定を行う
```
git config --global user.name "あなたの名前"
git config --global user.email "あなたのメールアドレス"
```
### VSCodeを使うまで
1, [VSCode](https://code.visualstudio.com/)をインストール
Windowsの場合[Windows」のボタンをクリック

2, ダウンロードしたインストーラー（VSCodeUserSetup-x64-xxx.exe）をダブルクリックして起動

#### Git関連の拡張機能をインストールしておこう
VSCodeを起動し、左の「拡張機能」アイコンをクリック
検索バーに「Git」と入力し、「GitLens」などの拡張機能をインストール
拡張機能がインストールされると、VSCode内でGitの履歴管理やコミット操作が簡単にできる

# VSCodeのターミナルからgit cloneを行う
VSCodeのターミナルを開く
![スクリーンショット 2025-01-19 193459.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989912/67bbe302-5437-e28f-8a69-235c0f2f7776.png)

git clone コマンドを使ってGitのURLをクローン

![スクリーンショット 2025-01-19 193626.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989912/05ed50ff-16c7-8ac8-5558-bba85a7fbc7e.png)
```
git clone https://github.com/username/repository.git
```

# Gitの任意のブランチを選択して作業を進める
ソース管理を選択
![スクリーンショット 2025-01-20 124748.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989912/5f2eac87-0e93-aac0-d1c7-cc9239843a84.png)

左下にあるmain(今回はdevになっている)を選択し、編集したいブランチ、リモートブランチに移動
リモートブランチはPC上に保存されていないGitのクラウド上のもの
![スクリーンショット 2025-01-19 194132.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989912/c5b24e4b-3320-847f-c2dd-eb6982a4e05e.png)
![スクリーンショット 2025-01-19 194145.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989912/63cba852-eff7-ae2f-9d1e-4b314707136a.png)

#### gitブランチとは
Gitにおけるブランチは、プロジェクトの独立した開発ラインを管理するための機能である
ブランチを使うことで、メインのコード（通常はmainまたはmasterブランチ）の内容を変更することなく、新しい機能の開発や修正を行うことができる

「コミット（セーブポイント）の分岐を作る」機能で、その分岐を「ブランチ」と呼んでいる

この図ではmasterをもとにしたdevelopブランチを作成している
![gitflow-768x372.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989912/ccd58640-ef39-b355-c363-8a4e2f0288f2.png)
[Gitで始めるバージョン管理](https://kapibara-sos.net/archives/218)
初心者による　「Command Line」勉強記録

まず、Command Lineとは何か
　→文章のみでコンピュータを操作すること

☆操作するのにそれぞれのコマンドに役割がある

ディクトリ...フォルダ(のみ)の名称
カレントディクトリ...自分が今いるディクトリ
/「スラ」... 一番初期のディクトリ(始祖)  



コマンドの種類と役割
・touch... ファイル作成
・mkdir... フォルダ作成
・cat...   ファイルの内容表示

・cd...    移動
・ls...    内容を確認
・ped...   現在地の確認

・mv 〇〇(を)〇〇...　　　ファイル移動
・mv 〇〇(を)〇〇...　　　名前変更 

・cp 〇〇(を)〇〇...　　　コピー
・cp -r 〇〇(を)〇〇...　　ディクトリのコピー

・cd..  ・・・　　　　　　ひとつ前(親)に戻る
・cd(空欄)...　　　　　　ホームディクトリ

・rm...　　　削除
・rm -r ... 　ディクトリの削除

以上、プロゲート１時間少々程度の基礎勉強記録
Mac同士の「高パフォーマンス画面共有」、結構すごくてオラたまげたぞ！

# 概要
- Macへのリモート接続（画面共有）はVNCプロトコルを使うのが一般的です。
- そのため、WindowsのRDPプロトコルより比較的しょぼい（失礼）印象がありました。
- しかし、M1以降のMacでのみつかえる、[高速な画面共有](https://support.apple.com/ja-jp/guide/remote-desktop/apdf8e09f5a9/mac)機能というものがあるらしく、試してみました。

# 環境
::: note warn
- M1以降のMac　2台
- 最新のMacOS（14以上とのこと）
:::

# 接続
- M1 Mac Miniで同一サブネットでのローカル接続。（WIFI5）
- SpotLightでScreenなどと検索すると接続画面が出ます。
- 2個の仮想ディスプレイが使えるようです。

![スクリーンショット 2025-01-19 18.10.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/eae512bd-c973-d11e-9b6c-1f2f88627b76.png)

# Apple「待たせたな……… こいつがお望みのフルパワーだ」
![スクリーンショット 2025-01-19 18.23.52.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/0ffa1b3b-d84a-500d-517f-bb9113721f4b.jpeg)

- 結論からいうと、4K60FPSで遅延もほとんど感じませんでした。
- 4Kで動画を再生すると、おおむね40Mbpsが最大値として使われているようでした。
- 有線ならさらに安定しそうですが、無線でも遅延は感じず、まったく違和感がありませんでした。
- この帯域ではリモートワークの常用はきびしいかもしれませんが、社内利用では問題ないと思います。（フルHDならいける？）

# ユーザエクスペリエンス
- 上のほうにコントロールセンターがあり、動的解像度に対応。これは良い。ただし4Kだとちょっとにじんだ感じになりました。
- 5ボタンマウスの進む・戻るは使えませんでした。
- タッチペンなどのハードウェアの転送は難しい可能性がありますね。
- 一般的な事務用途しかしない企業ユースとしては、管理性やセキュリティが高まるメリットがあるともいえます。
- 技術的にはUDPを使っているとのことでAzure AVD ShortPath的なものなのでしょうか？

# Mac Mini M1のサポート期間
- きのこ先生（ChatGPT）に聞いてみました。
::: note
M1 Macのセキュリティアップデートの期間については、以下のように予測できます：
- M1 Macは2020年11月に発売されました。
- ***Appleの一般的なサポート期間は約5-7年です。***
- 現在の日付（2025年1月19日）から考えると、M1 Macはまだサポート期間内にあります。
- Intel Macの平均的なOSアップデートサポート期間は約7年で、その後2年間のセキュリティアップデートが提供されています。
- M1 MacはApple Silicon搭載モデルであり、Intel Macよりも長期間サポートされる可能性が高いです。
- これらの要因を考慮すると、***M1 Macは少なくとも2027年末まで最新のmacOSでサポートされ、その後2029年末頃までセキュリティアップデートが提供される可能性が高い***と予測できます。
:::

# オラわくわくすっぞ！
- Mac Mini M1はM4の登場で値下がりが激しいです。2025年1月現在、40000円台から。
- なので***企業内シンクライアント的に使ってもいいかも***しれません。
- 「どひゃー！Mac Proってこんなに高いのか！オラたまげたぞ！」みたいなモンスターマシンはサーバールームに置いておくみたいな使い方も？
- 情シス・ヘルプデスクおじさんとしては、現地に赴かなくてすむメリットをまず思い浮かべました。
- Miniならキーボードマウスが切り離されているので故障もしにくいですし。
- 以上、現場からポエムでした。（なんでドラゴンボール？）
危険！！GitのリポジトリをiCloudにクローンしないで

## はじめに

Gitはコードのバージョン管理に不可欠なツールであり、多くの開発者が日常的に利用しています。一方で、ファイルのバックアップや共有のためにiCloudなどのクラウドストレージサービスを活用している方も多いでしょう。しかし、**GitのリポジトリをiCloud上にクローンすることは非常に危険**であり、避けるべき行為です。本記事では、その理由と安全なリポジトリ管理方法について解説します。

## iCloudにGitリポジトリをクローンしてはいけない理由

### 1. データの損失やリポジトリの破損のリスク
iCloudはファイルベースの同期を行いますが、Gitリポジトリは多数の小さなファイルと特殊なディレクトリ構造（例：`.git`ディレクトリ)で構成されています。iCloudがこれらのファイルを同期する過程で、同期のタイミングや順序の不整合が発生し、**リポジトリが破損**する可能性があります。

### 2. ファイルの競合と同期エラー

複数のデバイスで同じリポジトリを操作している場合、iCloudの同期機能が原因でファイルの競合が発生します。これにより、**最新の変更が失われたり、意図しない形でファイルが上書き**されることがあります。また、同じファイルが生成されることもあります。

### 3. パフォーマンスの低下

iCloudはバックグラウンドでファイルのアップロードとダウンロードを行います。Gitの操作（クローン、プル、プッシュなど）とiCloudの同期が同時に行われると、**処理速度が低下**し、開発効率が大幅に落ちる可能性があります。

### 4. セキュリティの懸念

Gitリポジトリには機密情報やAPIキーなど、外部に漏れてはならない情報が含まれている場合があります。iCloudにこれらの情報をアップロードすることで、**セキュリティリスク**が高まります。

## まとめ

iCloudは便利なクラウドストレージサービスですが、Gitリポジトリとの相性は良くありません。**予期せぬデータ損失やリポジトリの破損を防ぐためにも、GitのリポジトリをiCloud上にクローンすることは避けましょう。** 安全な開発環境を維持するために、適切なリポジトリ管理方法を選択することが重要です。
【Google認証失敗】条件付きバリデーション

# １ はじめに
以下の画像のようにGoogle認証を取り入れており、以下の画像までは実行できるのですが、アカウントを選択して実行してもうまくログインできなくなるという現象が起こりました。これを解決するのに少し時間がかかったので、備忘録として投稿します。

![2025-01-19 17.42の画像.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3952789/4c9dbac5-2d8f-2aa9-1818-f174f762191f.jpeg)

# ２ 解決のための流れ
+ Google Cloud Consoleでのプロジェクト及びリダイレクトURLの確認
+ OAuth レート上限の確認
+ Rails側でデバッグ

上記の流れで確認していきました。

#### Google Cloud Consoleでのプロジェクト及びリダイレクトURLの確認
まずは、[Google Cloud Console](https://console.cloud.google.com/)にログインをして自分が作成したプロジェクトを間違えて消していないか。次にリダイレクトURLが間違えていないか確認しました。
ここでの発見はリダイレクトURLでは`http://localhost:3000`のように設定しているので、自分でアプリ作成のために作成したルーティングの`http://localhost:3000/users`なども必要に応じて追加する必要があるなと感じました。毎回ログインするときにトップ画面に戻るのは手間なので。

今回はこちらには何の問題もありませんでした。

#### OAuth レート上限の確認
一応問題ないとは思いますが、まさかと思い確認しました（私の場合はYoutube apiも使用しているため）。今の私のアプリの内容的に、上限にいくはずもなく問題ありませんでした。
正直ここで詰まってしまい、次に何を確認すれば良いのかわからなくなり、ChatGptに解決する手段を聞いてみました。それが次の手段です。

#### Rails側でデバッグ
```php:users/omniauth_callbacks_controller.rb
Rails.logger.debug "OmniAuth response: #{request.env['omniauth.auth'].inspect}"
```
上記のコードを追記してあげることで、OmniAuthレスポンスの内容を確認できることがわかったので、実施してみました。簡単にこのコードの説明をすると`request.env['omniauth.auth']`の中にGoogle認証した時のデータが入っているのでその中身について確認するためのコードです。

上記のコードを追加して、Google認証を実施した結果として、しっかりとデータが取得できていることがわかりました。つまりデータは取得できているが、最後にテーブルにデータを保存することができていないことが、ここで発見されました。

これをみた時に、まさかと思い出したのですが、Google認証をした後に、users/editにパスが飛ぶようにしており、そこではユーザーの他のデータを追加させようとしていたことを思い出しました。そして追加のデータにバリデーションをつけていたので、バリデーションをしていない、Google認証のデータは取得できなかったのです。

# 問題の解決
Google認証した後に、バリデーションが機能するようにしようと思います。
そのために調べたところ、条件付きバリデーションがあったので、[こちら](https://railsguides.jp/active_record_validations.html#%E6%9D%A1%E4%BB%B6%E4%BB%98%E3%81%8D%E3%83%90%E3%83%AA%E3%83%87%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3)を参考にして以下の記述を追記をしました。
```php:user.rb
  with_options if: :google_auth? do |auth|
    auth.validates :name, presence: true, length: { maximum: 15 }
    auth.validates :profile, presence: true, length: { maximum: 100 }
    auth.validates :muscle_training_history, numericality: { only_integer: true, greater_than_or_equal_to: 0, message: "数字を入力してください" }
  end

  private

  def google_auth?
    provider == 'google_oauth2'
  end
```
`with_options if: :google_auth?`の部分で、もし`google_auth?`が正しければ実行するという記述になっており、`google_auth?`は下の方に作成しております。Google認証したときには、`providerカラム`は'google_oauth2'になるはずなので、この記述でうまくいきます。

# おわりに
今回は思わぬところでGoogle認証ができなくなりましたが、そのおかげで条件付きバリデーションを勉強できたのでよかったです。これからもポートフォリオ完成に向けて精進していきます。最後まで閲覧いただき誠にありがとうございました。
大規模言語モデルの基礎とtransformersライブラリの活用

## はじめに

大規模言語モデル（LLM）は、自然言語処理（NLP）タスクにおいて非常に強力なツールです。本記事では、GPT、BERT、T5といった代表的なモデルを紹介し、`transformers`ライブラリを使ってこれらのモデルを実際に動かす方法を解説します。

## 環境設定

まず、必要なライブラリをインストールします。以下のコマンドを実行してください。

```bash
!pip install transformers[ja,sentencepiece,torch] pandas
```

## GPT（デコーダ）

GPT（Generative Pre-trained Transformer）は、テキスト生成タスクに特化したデコーダ型のモデルです。ここでは、日本語に対応したGPT-2モデルを使って、テキスト生成を行います。

### transformersで使う

```python
from transformers import pipeline

# テキスト生成用のpipelineを作成
generator = pipeline(
    "text-generation", model="abeja/gpt2-large-japanese"
)

# "日本で一番高い山は"に続くテキストを生成
outputs = generator("日本で一番高い山は")
print(outputs[0]["generated_text"])
```

**Output：**

```
日本で一番高い山は比叡山に登った。しかし、一番高い山でさえも、やはり百人くらいの人が入る山だ。 私たちは、日本の山は、高い山が一番高いものと考え、それ
```

このコードは、「日本で一番高い山は」というテキストに続く文章を生成します。GPT-2は、与えられたテキストに基づいて自然な続きを生成する能力を持っています。

## BERT・RoBERTa（エンコーダ）

BERT（Bidirectional Encoder Representations from Transformers）やRoBERTaは、エンコーダ型のモデルで、主にテキストの分類やマスクされたトークンの予測に使用されます。

### transformersで使う

```python
import pandas as pd

# マスクされたトークンを予測するpipelineを作成
fill_mask = pipeline(
    "fill-mask", model="cl-tohoku/bert-base-japanese-v3"
)

# マスクされたテキストを用意
masked_text = "日本の首都は[MASK]である"

# [MASK]部分を予測
outputs = fill_mask(masked_text)

# 上位3件をテーブルで表示
display(pd.DataFrame(outputs[:3]))

# 別の例
masked_text = "今日の映画は刺激的で面白かった。この映画は[MASK]。"
outputs = fill_mask(masked_text)
display(pd.DataFrame(outputs[:3]))
```

**Output：**

|   | token | score | sequence |
|---|-------|-------|----------|
| 0 | 東京  | 0.95  | 日本の首都は東京である |
| 1 | 京都  | 0.03  | 日本の首都は京都である |
| 2 | 大阪  | 0.01  | 日本の首都は大阪である |

このコードは、マスクされた部分を予測し、その結果を表示します。BERTは、文脈を考慮して適切な単語を予測することができます。

## T5（エンコーダ・デコーダ）

T5（Text-To-Text Transfer Transformer）は、エンコーダ・デコーダ型のモデルで、様々なテキスト変換タスクに使用されます。

### transformersで使う

```python
# text-to-text生成用のpipelineを作成
t2t_generator = pipeline(
    "text2text-generation", model="retrieva-jp/t5-large-long"
)

# マスクされたスパンを予測
masked_text = "江戸幕府を開いたのは、<extra_id_0>である"
outputs = t2t_generator(masked_text, eos_token_id=32098)
print(outputs[0]["generated_text"])

# トークンのIDを確認
t2t_generator.tokenizer.convert_tokens_to_ids("<extra_id_1>")

# 別の例
masked_text = "日本で通貨を発行しているのは、<extra_id_0>である"
outputs = t2t_generator(masked_text, eos_token_id=32098)
print(outputs[0]["generated_text"])

# 特定の単語がボキャブラリに含まれているか確認
"日本銀行" in t2t_generator.tokenizer.vocab
```

**Output：**

```
徳川家康
日本銀行
False
```

T5は、テキストを入力として受け取り、別のテキストを出力するタスクに適しています。ここでは、マスクされた部分を予測し、その結果を表示しています。

## まとめ

本記事では、GPT、BERT、T5といった大規模言語モデルの基礎と、`transformers`ライブラリを使ってこれらのモデルを実際に動かす方法を紹介しました。これらのモデルは、自然言語処理タスクにおいて非常に強力なツールであり、様々な応用が可能です。ぜひ、実際にコードを動かして、その威力を体感してください。

## 参考リンク

- [transformersライブラリの公式ドキュメント](https://huggingface.co/docs/transformers/index)
- [GPT-2 Japanese Model](https://huggingface.co/abeja/gpt2-large-japanese)
- [BERT Japanese Model](https://huggingface.co/cl-tohoku/bert-base-japanese-v3)
- [T5 Japanese Model](https://huggingface.co/retrieva-jp/t5-large-long)

以上で、大規模言語モデルの基礎とその活用方法についての解説を終わります。

---

参考資料：
- [https://github.com/ghmagazine/llm-book](https://github.com/ghmagazine/llm-book)
Rustでcrateをbuildする際、"Library not loaded: @rpath/libclang.dylib" が出力されたことについて

## 目的

```
Library not loaded: @rpath/libclang.dylib"
```

を解決する。

## 環境

- M1 Macbook Sonoma14.7.1
- cargo 1.83.0
- opencv: stable 4.11.0

## エラー内容


```
cargo run
    Blocking waiting for file lock on build directory
   Compiling opencv v0.94.1
error: failed to run custom build command for `opencv v0.94.1`

Caused by:
  process didn't exit successfully: `/Users/user/tests/fourier/target/debug/build/opencv-99c31a0adba7676d/build-script-build` (signal: 6, SIGABRT: process abort signal)
  --- stderr
  dyld[31167]: Library not loaded: @rpath/libclang.dylib
    Referenced from: <804D229C-B191-3CCE-AB06-4C64F5AFBAC7> /Users/user/tests/fourier/target/debug/build/opencv-99c31a0adba7676d/build-script-build
    Reason: tried: '/Users/user/tests/fourier/target/debug/deps/libclang.dylib' (no such file), '/Users/user/tests/fourier/target/debug/libclang.dylib' (no such file), '/opt/homebrew/Cellar/rust/1.83.0_1/lib/rustlib/aarch64-apple-darwin/lib/libclang.dylib' (no such file), '/Applications/Xcode.app/Contents/Developer/usr/lib//libclang.dylib' (no such file)
```

どうやら、opencvのbuild時に必要な動的ライブラリである

```
libclang.dylib
```

が見つかっていないようです。

## 手順

次のpathに着目しました。

```
/opt/homebrew/Cellar/rust/1.83.0_1/lib/rustlib/aarch64-apple-darwin/lib/libclang.dylib
```

ここの中で、**libclang.dylib**が見つかっていないようなのです。

https://stackoverflow.com/questions/6000554/clang-complete-where-is-the-libclang-so-dylib-in-os-x

stack overflow を探しましたところ、libclang.dylibは

```
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/  
```

にあるようです。

```terminal
$ ls /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/              
AppIntentsMetadataExtractor.framework clang                                 libcodedirectory.dylib                swift
AppIntentsSupport.framework           libIndexStore.dylib                   libswiftDemangle.dylib                swift-5.0
LinkMetadataDT.framework              libLTO.dylib                          libtapi.dylib                         swift-5.5
SwiftSourceKitClientPlugin.framework  libSwiftDriver.dylib                  sourcekitd.framework                  swift_static
SwiftSourceKitPlugin.framework        libclang.dylib                        sourcekitdInProc.framework            tapi

$ ls /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/ | grep "clang"
clang
libclang.dylib
```

そこで、**libclang.dylib**のシンボリックリンクを作成しました。

```terminal
$ ln -s /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/libclang.dylib /opt/homebrew/Cellar/rust/1.83.0_1/lib/rustlib/aarch64-apple-darwin/lib/libclang.dylib
```

ここで、もう一回 **cargo run**を実行

```
$ cargo run
   Compiling opencv v0.94.1
   Compiling fourier v0.1.0 (/Users/user/tests/fourier)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 27s
     Running `target/debug/fourier`
Hello, world!
```

無事、buildされました。

## 参考

https://stackoverflow.com/questions/6000554/clang-complete-where-is-the-libclang-so-dylib-in-os-x
Transformerの位置符号（Positional Encoding）を可視化する

## はじめに
Transformerモデルにおいて、位置符号（Positional Encoding）は重要な役割を果たします。TransformerはRNNやCNNとは異なり、入力シーケンスの順序情報を直接的に扱うことができません。そのため、位置符号を用いて単語の位置情報をモデルに組み込みます。本記事では、位置符号の生成方法とその可視化について解説します。

## 位置符号の生成
以下のコマンドで必要なパッケージをインストールしましょう。

```bash
!pip install numpy matplotlib japanize-matplotlib
```

位置符号は、単語の位置情報をモデルに組み込むためのベクトルです。以下のコードは、位置符号を生成し、それを可視化するためのものです。

```python
import japanize_matplotlib
import matplotlib.pyplot as plt
import numpy as np

# パラメータ設定
K = 50  # 単語列の最大長
D = 64  # 埋め込みの次元

# 位置符号行列を初期化
pos_enc = np.empty((K, D))

# 位置符号を計算
for i in range(K):  # 単語位置iでループ
    for k in range(D // 2):  # kの値でループ
        theta = i / (10000 ** (2 * k / D))
        pos_enc[i, 2 * k] = np.sin(theta)
        pos_enc[i, 2 * k + 1] = np.cos(theta)

# 位置符号行列を画像で表示
im = plt.imshow(pos_enc)
plt.xlabel("次元")  # X軸のラベルを設定
plt.ylabel("位置")  # Y軸のラベルを設定
plt.colorbar(im)  # 値と色の対応を示すバーを付加
plt.show()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3932781/6d27cdd9-d78f-4225-8840-bb928f838e1b.png)


このコードでは、単語列の最大長 `K` と埋め込みの次元 `D` を設定し、位置符号行列 `pos_enc` を生成しています。位置符号は、単語の位置 `i` と次元 `k` に基づいて計算されます。具体的には、以下の式を使用します。

\[
\theta = \frac{i}{10000^{\frac{2k}{D}}}
\]

この計算により、位置符号行列が生成され、それをヒートマップとして可視化しています。

## 位置符号同士の内積を計算
次に、生成された位置符号同士の内積を計算し、その結果を可視化します。

```python
# 位置符号同士の内積を計算
dot_matrix = np.matmul(pos_enc, pos_enc.T)

# 行列を画像で表示
im = plt.imshow(dot_matrix, origin="lower")
plt.xlabel("位置")
plt.ylabel("位置")
plt.colorbar(im)
plt.show()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3932781/90ee8149-0dd9-6f6b-cfae-5463e61ff2e4.png)


このコードでは、位置符号行列 `pos_enc` とその転置行列 `pos_enc.T` の内積を計算し、その結果をヒートマップとして表示しています。この内積行列は、異なる位置間の類似度を示しており、位置符号がどのように位置情報をエンコードしているかを理解するのに役立ちます。

## まとめ
本記事では、Transformerモデルにおける位置符号の生成方法とその可視化について解説しました。位置符号は、単語の位置情報をモデルに組み込むための重要な要素であり、その生成過程と可視化を通じて、Transformerの動作原理をより深く理解することができます。

位置符号の可視化は、モデルの挙動を直感的に理解するための有用なツールです。ぜひ、実際にコードを実行して、位置符号の振る舞いを確認してみてください。

この記事が、Transformerの位置符号について理解を深める一助となれば幸いです。

---

参考資料：

- [https://github.com/ghmagazine/llm-book](https://github.com/ghmagazine/llm-book)
macOS Sequoia Wi-Fi接続できているのにネットに繋がらない件の解消方法

久しぶりにmacOSアプデしたらネットに繋がらなくなった件。
故障したかと思ったけど、調べてみたらセキュリティソフトのESETが原因でした。

# この記事で解決できること
ESETを入れていて、Wi-Fiは正常に繋がっているように見えるのにネット接続できない状態。
ESETを使用していない方は残念ながらこの記事の方法では解決できないので、別の方法を探してください。

# 解決方法
システム設定＞ネットワーク＞フィルタ で、ESETの名前が表示されているものを全て「−」ボタンで削除する。
これでネットに繋がるようになりました。
「状況」のプルダウンで「無効」も選べますが、無効にしただけでは直りませんでした。

# ネットに繋がったらESETをアプデしよう
下記手順で手動でインストールしました。
https://eset-info.canon-its.jp/support/versionup/mac.html

インストーラに従って進めていく中で、先ほど削除したフィルタも再設定されます。
太陽電池＋鉛蓄電池で無線カメラを稼働する

# はじめに
物騒な世の中、我が家を出先からでも見たいときに監視したい。そんな欲望に駆られて調べてみると、最近はソーラーパネルで駆動するカメラや、蓄電池で長時間動くと謳う無線カメラもある。が、しかし、これらは共通して、消費電力を抑えるため、いつでも画像を見られる訳ではない。そこで、通常のIPカメラをソーラーパネルで動かせないかと考えた。

# システム構成
ソーラーパネルで発電した電力を蓄電池に充電し、負荷に供給するのだが、過充電や過放電、過電流など検出して対策するのは結構面倒。しかしソーラーコントローラというものが、この辺のことをまとめてやってくれるらしい。
また、今回はバッテリー電圧が12V、カメラの電源電圧が5Vとなっているので、バッテリー電圧からシステム電圧を作るためのdcdcコンバータも必要になる。コントローラの中にはUSBの端子が付いているものもあり、こうしたものを買えば別に用意する必要がなかった。
![システム構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2822780/6aae5d38-c93f-34a7-a73d-ccee5fff6c24.png)

# 構成部品
主に必要なものは、amazonと秋月電子、近くのホームセンターでそろえた。
<dl>

### ・<a href="https://www.tp-link.com/jp/home-networking/cloud-camera/tapo-c120/#overview">IP カメラ（tplink製 tapo C120）</a>
  <dd>防水のipカメラ。スマホからは専用アプリで簡単に画像を確認できる。外部からopenCVを用いて画像を取ることもできる。正直値段が何倍もするipカメラよりずっと安定していて高画質な印象。
  </dd>

### ・<a href="https://akizukidenshi.com/catalog/g/g108233/">12W 太陽電池モジュール（SUNYOOO製 SY-M12W-12）</a>
  <dd>そもそもこの構成で動くのかを検証するため、あまり考えず、まぁこんなもんかと容量を選定。当然のことながら、これが後々厄介なことに。</dd>

### ・<a href="https://akizukidenshi.com/catalog/g/g100940/">12V 5Ah鉛蓄電池（LONG製 WP5-12）</a>
  <dd>太陽電池同様、5Ahあれば大丈夫！というより、とりあえず価格的にこの辺までなら遊びでやってみよう、という感覚で選定。容量足らなくても、ほかの用途にも使えるし・・・と自分に言い訳しながら。</dd>

### ・<a href="https://akizukidenshi.com/catalog/g/g118170/">太陽電池充放電コントローラー(12V5A) SUNYOOO製</a>
  <dd>60WまででLED以外のインジケータがないという凄い製品。</dd>
</dl>

### ・<a href="https://www.amazon.co.jp/dp/B0CF9GZ6V1?ref=ppx_yo2ov_dt_b_fed_asin_title&th=1">DCDCコンバータ（Renjzle製 USB電源アダプタ）</a>
バッテリーの電圧12Vからipカメラの動作電圧5Vを作るためのコンバータ。自動車で使うことを考えられているようで安いのに極めて高い変換効率。最大96%を謳っているので、念のため測ってみたところ、実際それくらいあった。

<dt>・その他</dt>
屋外に設置するため、コントローラ用プラボックス、カメラとプラボックスの固定金具、ケーブル、端子など。

# 容量計算
で、今更計算。こちらのカメラ、大体通常時の消費電力が350mA、24時間稼働するとすると大体8Ah。5Vなので40Wh。バッテリーは60Whなので、バッテリー容量としては1.5日分と言うことになる。

前にトラ技で悪天候に備えて5日分くらいのバッテリーが必要と言ってたので、全然足りていない（汗）。そもそもソーラーの能力が消費電力の約1/3というのも全くもって足りていないかもしれない。

# 実測
で、早速システムを構築し撮影を開始。意外と簡単にカメラ画像が確認できた。いける！と思った矢先、突然画像が途切れる。ほぼ計算通り、バッテリーが空になった。そして10時ごろに復活。日照時間や効率を考えると、太陽電池もソーラーパネルもアップグレードが必要そうだ。

# その後
夏場は南中高度が高く、日照時間が長いため、天気の悪い日や、天気の悪い日の翌朝繋がらない日があるな、といった程度だったが、冬場になって本格的に電流の収支が合わなくなってきた。M5atom S3とi2c接続の3チャンネル電流計を使って、どの程度の増強が必要か検討してみることとしたい。
Symfony CLIをつかったローカルWebサーバ + OrbStack時にコンテナが起動しない時の回避策

Symfony CLIを使ってローカルWebサーバを起動すると、プロジェクト内にある `compose.yaml` を判別し、Dockerコンテナを自動起動してくれます。起動すると、以下の様にプロファイラに `Docker Compose` , `Env Vars` が起動中な状態となります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9882/e1092c4b-d59f-3921-57ff-8c428f5cc7a2.png)

:::note
Symfony CLIでローカルWebサーバを起動すると、Dockerの内容を解釈して、DBの接続情報などを環境変数として追記してくれます。詳しくはこちら。

https://qiita.com/ippey_s/items/8919f618d13b3b6242e9
:::

ところが、OrbStackを利用してDocker環境を用意している場合、同じ様にしていてもコンテナが起動せず環境変数も追記されません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9882/c810ffb2-4231-e33e-e1ad-96e309bd437f.png)


これは、Symfony CLIが `DOCKER_HOST` の値を使って情報を取得しているからです。 `docker context ls` を起動すると、以下のようになっていると思います。


```shell
% docker context ls
NAME            DESCRIPTION                               DOCKER ENDPOINT                                        ERROR
default         Current DOCKER_HOST based configuration   unix:///var/run/docker.sock                            
desktop-linux   Docker Desktop                            unix:///Users/{ユーザ名}/.docker/run/docker.sock     
orbstack *      OrbStack                                  unix:///Users/{ユーザ名}/.orbstack/run/docker.sock   

```

OrbStackを使用するようになっていますが、 `DOCKER_HOST` には `default` が使われています。
なお、この `unix:///var/run/docker.sock` は、 orbstackのdocker.sockへのシンボリックリンクとなっていますが、どうもこれがうまく認識されていないようです。

そこで、 `.zshrc` に以下を追記します。

```zsh:~/.zshrc
export DOCKER_HOST=unix:///Users/{ユーザ名}/.orbstack/run/docker.sock
```

これにより、Symfony CLIが `DOCKER_HOST` を介して正しい情報を取得することができ、ローカルWebサーバ起動時に、コンテナも起動する様になります。

:::note warn
Symfony CLIやOrbStacknアップデートによって、上記対応は不要になる可能性があります。
:::
Conan2+VScodeでincludeパスを解決する方法

C++のパッケージ管理としてConanを使用してみました。

### 結論
`~/.conan2/p/**`を`c_cpp_properties.json`の`includePath`に設定する。

### 本文

[チュートリアル](https://docs.conan.io/2/tutorial/consuming_packages/build_simple_cmake_project.html)を一通り試してみてなかなかよさそうな感じがしたので、本腰を入れて使っていこうとしたらincludeパスが見つからないとの警告が出ていたので、これを解決する方法を探しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989875/bf23e394-f2cb-deaa-422b-661d93587051.png)

ドキュメントを眺めていたら、[デバッグのページ](https://docs.conan.io/2/examples/dev_flow/debug/step_into_dependencies.html)で`~/.conan2/p/`にソースがあるということが書かれていました。あくまでもキャッシュということなので、わかりやすいようにディレクトリが整理されているわけではないですが、これを使用することでヘッダを見つけます。ちょっと強引ですね。
```
user@DESKTOP-XXXXXXX:~/.conan2/p$ ls
b                   expat5694738970bf6  lz4b1bcde4b1a88a    poco31ea64622b791   zlib043557c4b0d5e
bzip22a75d000ecba1  expatc59ec503c3f1a  opens0d33bdaaab906  poco4df33fd2ff629   zlib812b4ea399739
bzip23c098e896e3ea  libmy60bc15376c5b1  opens354b7573984c7  pocofbe8104035a9a   zlibc14da49d1b22a
cache.sqlite3       libpq2aa305970b07c  opensd031988b37050  sqlit0c7da7bb92355  zlibd87f4658d264b
expat3ece0af824d2f  libpq8c3c64978c3b1  pcre2990e0d94ec2a4  sqlit5890f03075444  zstd78ed329de9a27
expat4162569998c9c  lz4562690604d161    pcre776b9bbf8e51c   sqlitb636e04a80b91  zstdc952ff066366b
```

このディレクトリのパスを再帰的に検索するように`c_cpp_properties.json`に設定すれば、OKです。
```
// c_cpp_properties.json
{
    "version": 4,
    "configurations": [
        {
            "name": "Linux",
            "includePath": [
                "~/.conan2/p/**"
            ],
            "defines": [],
            "compilerPath": "/usr/bin/g++",
            "cStandard": "c11",
            "cppStandard": "c++17"
        }
    ]
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3989875/cbef127a-97cb-24bf-c603-be1ba1d48d8e.png)

もっといい方法があればコメントいただけると嬉しいです
多腕バンディット問題のregretのグラフとその直感的な意味

強化学習、とりわけMulti-armed bandit（多腕バンディット問題）の設定で、regretを最小にしようとする状況がよくあります。regretのtステップごとの変化を実験的に観察する議論も見られます。それは、例えばMulti-armed bandit (以下、MABと呼ぶ。)の文脈などです。この記事はregretのいくつかの形(instantenous regret $r_t$, cumulative regret $R_t$, average regret $R_t/T$)に触れ、そこからグラフの形についてまとめます。

### Regretのおさらい

大ヒットをして現時点で2841回も引用されている論文（[ICMLの賞も受賞](https://www.amazon.science/latest-news/amazon-scientist-matthias-seeger-receives-icml-test-of-time-award)）[1] *Gaussian Process Optimization in the Bandit Setting: No Regret and Experimental Design*　を参考にします。

https://arxiv.org/abs/0912.3995

**Regretとは: (最適な選択を知らなかったことによる、最適な場合の報酬)-(実際の選択による報酬)　だと言えます。**


$f$を未知の関数として、ステップ$t$における選択は$\boldsymbol{x}_t$、また、$f$を最大化するような選択を$\boldsymbol{x}^*$としたときの場合を考える。ある時点での瞬間のregret($r_t$)は以下となる。

```math
r_t= f(\boldsymbol{x}^*)-f(\boldsymbol{x}_t)
```

この瞬間的なregret($r_t$)をステップ$t$について足し合わせたものがcumilative regret ($R_t$)である。

### Cumulative regretのグラフでの直感

今読んでいる論文は開示できないのですが、Cumulative regretのグラフはいろいろなところで見ます。例えば、次のバンディットアルゴリズムのまとめの記事では、Cumulative regretの可視化がたくさんあります。

https://qiita.com/birdwatcher/items/9560afeea61d14cff317

Cumulative regretのグラフから、アルゴリズムの挙動は直感的には以下のように解釈できるでしょう。

![スクリーンショット 2025-01-19 18.31.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614389/c8d815bf-e068-29cf-3549-eccda479bd15.png)



### Average regretのグラフでの直感

とある文献、[1] Gaussian Process Optimization in the Bandit Setting:
No Regret and Experimental DesignのFig. 5に注目してみましょう。

https://arxiv.org/abs/0912.3995


Fig. 5の縦軸は "mean average regret"であると示されています[1]。これは"cumulative regret"とは違います。"average regret" とは$R_t/T$としてcumulative regretを総ステップ数で平均を取ったものです[1]。論文中[1]では、MABの設定でアルゴリズムが満たすべき*望ましい*漸近的な特徴として、この"average regret" とは$T\rightarrow0$の時に$R_t/T\rightarrow0$となることだと述べられています。(注：Fig. 5のMean average regretというのは、average regretを多数観察して、それをMeanをとったことのようです。Meanとaverageが同時に出てきてややこしいですね。通常の理論的な文脈では"average regret"と書かれています。)

今までの流れをまとめると次のような望ましいアルゴリズムと、望ましくないアルゴリズムのaverage regretに関する挙動が想像できるでしょう。

![スクリーンショット 2025-01-19 17.56.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614389/2ef626a0-92a1-ada8-5d9a-b67ce90c4cd1.png)


つまり、もし論文中で"average regret"のステップごとの推移をグラフで示している場合は、上記の*望ましい*特徴を各アルゴリズムが示しているかを可視化する目的があるのでしょう。

### 次にわかりたいこと

以下は、個人的な学習の目標です。

#### Regret boundsについて大まかに理解したい。

強化学習でrewardを最大化することは、裏を返せばregretを最小化することです。この文脈で、Regret boundsという言葉がさまざまな論文で出てきます。([1]に限られない。)しかし、それは何のregretについてなのか、また、それはupper boundsなのか、lower boundsなのか曖昧です。regret自体に関しても、これまでの議論からでもいくつか可能性が出てきます。

- $R_t$ cumulative regret
- $R_t/T$ average regret
- $r_t$ instantenioues regret （上述の瞬間的なregret）

大ヒットをして現時点で2841回も引用されている[1]の論文（[ICMLの賞も受賞](https://www.amazon.science/latest-news/amazon-scientist-matthias-seeger-receives-icml-test-of-time-award)）でも、単に"4. Regret Bounds"とだけあります。それに後続する論文でも当たり前のようにregret boundsへの言及がたくさん出てきます。別の論文でもregret analysisとしてBig O, Big-θ notationでregretに関して分析があります。これらが何なのか、もしくは今の所詳しく知る必要があるのかも含めて読んでいきたいと思います。わかったら記事また書きます。


ここまで読んでくれてありがとうございました。間違いがありましたら、コメントでお知らせください。
(その4).構造体で遊ぶ。(分割(戻し))


x M5NanoC6での予定は、未定

目的
構造体の電文化と戻し
(たぶん、あっているはず。)
(浮動小数点も含む構造体も予定?)

オンラインコンパイラ


```c++

#include <iostream>
#include <string.h>  //memcpy
using namespace std;
int main(void){
    // Your code here!
    printf("START\n");
    
    unsigned char ac[256+1];
    
    struct {
        int sw1;
        int sw2;
    } SWs;
    
    SWs.sw1 = -1;
    SWs.sw2 = -2;
    
    char *c;
    c = (char *)(&SWs);

    memcpy(ac, c, 4 * 2); 

    printf("[%x][%x][%x][%x]\n",ac[0],ac[1],ac[2],ac[3]);
    printf("[%x][%x][%x][%x]\n",ac[4],ac[5],ac[6],ac[7]);


    char *p;
    p = (char *)(&SWs);
    
    memcpy(p, ac, 4 * 2); 

    printf("\n");
    printf("[%d],[%d]\n",SWs.sw1,SWs.sw2);
    
}//main



```


```

START
[ff][ff][ff][ff]
[fe][ff][ff][ff]

[-1],[-2]


```
ENV['RAILS_ENV']

```rails_helper.rb
ENV['RAILS_ENV'] ||= 'test'
```
### rspec内で実行すると
```rb
   it "サンプル" do
      p ENV['RAILS_ENV']
    end
```
```
"test"
...
Finished in 0.10224 seconds (files took 1.94 seconds to load)
4 examples, 0 failures
```

### コンソールの環境はdevelopmentになる
```rb
************ % rails c --sandbox                                           
Loading development environment in sandbox (Rails 7.2.0)

*******(dev)> ENV['RAILS_ENV']
=> "development"
````
### ENVオブジェクト
>環境変数を表すオブジェクト。Hash と同様のインターフェースを持ちます。ただし、Hash と異なり、ENV のキーと値には文字列しかとることができません。

>また、ENV で得られる文字列は Object#freeze されています。

例
```
irb(main):002> p ENV['TERM'].frozen?
true
=> true
```
https://docs.ruby-lang.org/ja/latest/class/ENV.html#:~:text=%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0%E3%82%92,frozen%3F%20%20%23%20%3D%3E%20true

### 感想
本当にRSpecはテスト環境なのか知りたかった。
実行環境がテスト環境であることを見ることができてよかった。
安心してtest用のデータベースを作成できる
どこでかは知らないが、ENV['TERM']はnilかfalseになるらしい

https://qiita.com/masatom86650860/items/424c45935529e965be84
【React】データ取得中ローディング画面が表示されない

# 事象
TODOアプリにおいて、supabaseからテストデータを取得させる間にローディング画面が表示されるよう実装したのですが、取得したデータは表示されるもののローディング画面は表示されない、という現象が発生しました。

## コード
(App.jsx及びsupabase関係のコンポーネントは省略）
```react:LogContent.jsx

import { useState, useEffect } from 'react';
import { getAllLogs } from '../utils/supabaseFunctions';

export const LogContent = () => {
  const [logs, setLogs] = useState([]);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    const getLogs = async () => {
      const logs = await getAllLogs();
      setLogs(logs);
    };
    getLogs();
    setIsLoading(false);
  }, []);


  return isLoading ? (
    <div>Loading...</div>
  ) : (
    <div>
      <h2>学習記録一覧</h2>
      {logs.map((log) => (
        <p key={log.id}>
          {log.title} {log.time}時間
        </p>
      ))}
    </div>
  );
};
```

# 原因
`useEffect`内での非同期処理の扱いをよく理解しておらず、`setIsLoading(false)`が不適切なタイミングで実行されてしまうことが原因でした。

`getLogs()`は`async`関数ですが、この関数は非同期処理`getAllLogs()`が呼び出されると、結果が帰ってくるまで制御を`async`の呼び出し元の関数に返します。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/async_function

この場合の呼び出し元は`useEffect`ですから、`await getAllLogs()`が完了するのを待つことなく次の行の`setIsLoading(false)`が実行されてしまうことになります。

```react
useEffect(() => {
    const getLogs = async () => {
        const logs = await getAllLogs();
        setLogs(logs);
    };
    getLogs(); //処理を開始
    // await getAllLogs()の結果が返ってくるまで制御がuseEffectに戻る
    setIsLoading(false); // 非同期処理の完了を待たずに実行
}, []);
```

ある処理を実行している間に他の処理を並行して実行するのが非同期処理ですから、これは当然の流れなのですが、非同期処理への理解が浅かったためすぐには原因がわからず、だいぶ悩みました。

# 対処
`try...catch...finally`を使用し、`setIsLoading(false)`の実行タイミングを制御することで解決しました。

```react
useEffect(() => {
    const getLogs = async () => {
        try {
            setIsLoading(true); // データ取得開始前にtrueに設定
            const fetchedLogs = await getAllLogs();
            setLogs(fetchedLogs);
        } catch (error) {
            console.error("読込エラーです：", error);
        } finally {
            setIsLoading(false); // データ取得完了後にfalseに設定
        }
    };

    getLogs();
}, []);
```

# JISOUのメンバー募集中！
プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか？
興味のある方は、ぜひホームページをのぞいてみてください！
▼▼▼

https://projisou.jp