OmniAICreator/Qiita-1.07M huggingface dataset:
Autogen入門ハンズオン＋学習が楽しくなる方法と振る舞いの考察


## 本日のイベント・勉強会
https://hannari-python.connpass.com/event/331175/

ハンズオンパートでも自分の意見を言いたい参加者が複数名いて収拾がつかなかったので、ハンズオン資料を読みながらやりながら、私が感じた話だけを書き連ねていきます。

なお、資料は公開されています。

https://github.com/hideyuki-ogawa/autogen-hands-on/blob/main/autogen_pt2.ipynb

OpenAI APIキーは事前に取得しておきましょう。

### アンケートがなかったので、勝手にアンケート
:::note
AutoGenに触れてみよう、と思ったのは本セミナーのおかげなので感謝しています
:::

:::note warn
コミュニティに興味を持った場合、常連の方？のクセが強く、ハンズオンパートは説明を聞けないものと思った方がいいかもしれません。が、せっかくAIの勉強会なので、AIに解説してもらってある程度予習というか、インプットを入れてから本イベントに参加するべきなのかもしれません。
:::

### Gensparkの検索じゃない版？
私の認識というか理解の仕方が合っているか微妙なところですが、複数のエージェントを立てて一つの目標に向かっていく、ということがやりたいことなんだろうなぁ、という印象を持ちました。
検索チックな使い方を想定するとGensparkが分かりやすいので例示したんですが、おそらく似たようなイメージで生成AIに何か生成結果を出させるという事なんだろうという理解です。

### TRPGをやらせる
本格的なシステムを使うと学習がきついので、死亡フラグTRPGをやらせてみました。

- コード：プレイヤーエージェントを3人以上作る
- システムメッセージ：全パターンの死亡フラグのセリフを覚える
- システムメッセージ：（長いので後述）
- ユーザーインプット：演目を決める

ルール説明がえぐい！
雑に「死亡フラグTRPGをやろう」ではルールもへったくれもないのでシステムメッセージで全部書き出したが、これでも精度がびみょい。

参考例

https://www.perplexity.ai/search/si-wang-hurakutrpgtohananika-r-ZpETbn.ASMSFpBtgnI_5NA

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122800/46100f65-a9b7-6adc-96d2-fe3885d24c80.png)

こんなんじゃ何をすればいいかわかるはずもないので、頑張って言語化する

```
死亡フラグにセリフについて各自学習してもらう（期待としては、異なる題材から死亡フラグを学んで、それぞれの見解が異なっていて欲しい。シード値を変える？）

- システムメッセージ：（読みやすいように改行しているが、実際は一行）

これからあなたの死亡フラグとなるセリフを渡す。
その後与えられたトークテーマに沿って議論をする。
あなたの目的は渡された死亡フラグのセリフを会話に組み込んで、他のプレイヤーからの死亡判定の賛同を得る事である。
死亡判定とは、物理的に命を落とす事を指すが、逮捕されるなど社会的に死ぬなど生存する上で致命的な障害が伴う事も含むことができる。各プレイヤーの倫理観が絶対であり、抗議は認めない。
このとき、自分を除く過半数の合意が得られればあなたは勝利する。
ただし、他のプレイヤーからの賛同が得られない場合、今使った死亡フラグのセリフを破棄し、新たに死亡フラグのセリフを決定する。
その後同様に与えられたトークテーマに沿って議論をしていく。
これを繰り返し、誰かが勝利となった時点でゲームを終了する。
ここまでを１セットと呼ぶ。

１セットが終了したら、人間の評価により死亡フラグの判定が正しかったかを判定し、承認されればあなたにゲームポイントが１点付与される。承認されなければ、今回のようなケースでは死亡フラグと判定されない事を学習する。
人間がゲームを終了するまで繰り返し、最終的に多くのゲームポイントを持っているプレイヤーが勝者となる。
```

説明だけではよくわからないと思うので、分かりやすいところだけを置いておきます。（私のお気に入りとも）

https://youtu.be/8O233kpTxDE?si=4tmNGkuVTc54Wybp&t=1000

こういうことをやってほしい。

### 結論からいうと、うまくいかない
反省点を書くと、そもそも死亡フラグTRPGがマイナーすぎたのかも
将棋や囲碁ではお互いに最善手を指し（打ち）続けた場合、先手必勝の手筋が割と研究され尽くしているので、ある程度ランダムの要素を入れて麻雀にする。
プレイヤー４人とゲームマスター１人を立て、ゲームマスターは各プレイヤーの持ち点や河や山、曲目などプレイヤーが操作する以外の全てを管理し、ゲームを進行させる。

このようにした上で、たとえば特定のプレイヤーは安手早上がりを狙ったり、大きな手作りを好んだりと特色を与える方法がよさそう
今日はもう心が折れたのでやらないが、こういったシミュレーションをさせるとAutogenの面白さに気付きやすいかもしれない、という提案だけ残しておきます。
ただし、ゲームの終了条件などに人間が介在する余地を残しておかないとどのタイミングで評価すればいいか、我々も分からないため「麻雀のルールやアガリ、待ち読みも符計算は知っているけどこの卓のレギュレーションは知らない一見の客か友人」を想定してメッセージを細かくルール説明的に書くのがよさそう。
payload

# 1. ペイロードとは何か？
ペイロードは、アクションオブジェクトに含まれる追加のデータで、状態を更新するためにリデューサーに渡されます。アクションは通常、以下のような構造を持ちます：

**type：アクションの種類を示す文字列。**
**payload：アクションに関連する追加のデータ。**
例：

```javascript
const addItemAction = {
  type: 'ADD_ITEM',
  payload: {
    id: 1,
    name: '商品A',
    price: 1000
  }
};
```

# 2. なぜペイロードが必要なのか？
**データの伝達：payloadを使用して、リデューサーに必要なデータを渡すことができます。**
**状態の更新：リデューサーはpayloadのデータを使用して、現在の状態を新しい状態に変換します。
アクションの汎用性：同じtypeでも、payloadの内容を変えることで多様な状態変更が可能になります。**

# 3. リデューサーでのペイロードの使用
**リデューサーはアクションのtypeとpayloadを受け取り、状態を更新します。**

例：

```javascript
function cartReducer(state = [], action) {
  switch (action.type) {
    case 'ADD_ITEM':
      return [...state, action.payload];
    default:
      return state;
  }
}
```
この例では、ADD_ITEMアクションがディスパッチされると、payload内のアイテムがカートの状態に追加されます。

# 4. ペイロードのベストプラクティス
**明確なデータ構造：payloadのデータは、できるだけシンプルで明確に保ちます。**
**不変性の維持：状態を直接変更せず、新しいオブジェクトを返すようにします。**
**エラー処理：エラーが発生した場合、payloadにエラーメッセージやステータスを含めることもあります。**
例：エラーを含むアクション

```javascript
const fetchErrorAction = {
  type: 'FETCH_ERROR',
  payload: {
    message: 'データの取得に失敗しました',
    code: 500
  },
  error: true
};
```

# 5. ペイロードと他のプロパティ
meta：アクションに関する追加情報を含める場合、metaプロパティを使用することがあります。
error：エラーを示す場合、errorプロパティをtrueに設定します。

# 6. まとめ
ペイロードは、アクションを通じてリデューサーに必要なデータを提供する重要な役割を持っています。適切に設計されたペイロードは、状態管理をより効率的で予測可能なものにします。

参考ポイント：

アクションは純粋なオブジェクトであり、typeとpayloadを含みます。
リデューサーはアクションのtypeを評価し、payloadのデータを使用して新しい状態を返します。
例：コンプリートなフロー
**アクションの作成**：

```javascript
function addItem(item) {
  return {
    type: 'ADD_ITEM',
    payload: item
  };
}
```
**ディスパッチの実行**：

```javascript
dispatch(addItem({ id: 1, name: '商品A', price: 1000 }));
```

**リデューサーでの処理**：

```javascript
function cartReducer(state = [], action) {
  switch (action.type) {
    case 'ADD_ITEM':
      return [...state, action.payload];
    default:
      return state;
  }
}
```

**この流れにより、payloadを介して状態を一貫して管理できます。**

**最後までよんでいただきありがとうございます。
@y-t0910をフォロー,いいねしていただけると嬉しいです！**
Linuxのグループ

<h1>Linuxのグループ復習</h1>

意外に自信がない部分。基本だけど、あんまりやることがない。

<h2>グループの追加 その１</h2>

この場合だと、プライマリグループに影響を与えず追加できる
```
[root@kubemgr ~]# useradd test999
[root@kubemgr ~]#
[root@kubemgr ~]#
[root@kubemgr ~]# id test999
uid=1002(test999) gid=1004(test999) groups=1004(test999)
[root@kubemgr ~]#
[root@kubemgr ~]#
[root@kubemgr ~]# usermod -aG was,ihs test999
[root@kubemgr ~]# id test999
uid=1002(test999) gid=1004(test999) groups=1004(test999),1001(was),1002(ihs)
[root@kubemgr ~]#
```

<h2>グループの追加　その２</h2>

プライマリーグループをきちんと入れて再度実行
```
[root@kubemgr ~]# useradd test998
[root@kubemgr ~]#
[root@kubemgr ~]# id test998
uid=1003(test998) gid=1005(test998) groups=1005(test998)
[root@kubemgr ~]# usermod -g test998 -G ihs,was test998
[root@kubemgr ~]#
[root@kubemgr ~]#
[root@kubemgr ~]# id test998
uid=1003(test998) gid=1005(test998) groups=1005(test998),1001(was),1002(ihs)
[root@kubemgr ~]#
[root@kubemgr ~]#
[root@kubemgr ~]# cat /etc/passwd | grep 998
cockpit-wsinstance:x:998:998:User for cockpit-ws instances:/nonexisting:/sbin/nologin
test998:x:1003:1005::/home/test998:/bin/bash
[root@kubemgr ~]#
[root@kubemgr ~]# cat /etc/group | grep test998
was:x:1001:kenken,test001,test999,test998
ihs:x:1002:kenken,test001,test999,test998
test998:x:1005:

```
<h2>プライマリーグループの確認方法</h2>

```
cat /etc/passwd
```

<h2>ユーザがどのグループに所属しているか確認</h2>

```

[root@kubemgr ~]# groups test001
test001 : test001 wheel was ihs
```
無料枠において Render.com でデプロイした Web アプリのスリープ対策について調査

※本内容は 2024/11/15 時点での調査となっております

# 放置すると Render.com でデプロイした Web アプリはスリープ(停止)する
## まずは Render の無料枠について調査
:::note info
* [そもそも Render の無料枠には制限が幾つかある](https://zenn.dev/tatehito/scraps/f7929e4a980d1c)
    * 周知されているところだと「DB は ~~90~~ **30** 日しか使えない」という制限がある
:::

:::note alert
2024 年夏頃から **DB の無料枠での使用期間が 90 日間から 30 日間に変更** されたようです
:::

> [『Render は、15 分間受信トラフィックを受信しない無料 Web サービスを停止します。Render は、次に処理する要求を受信するたびに、サービスを再び起動します。』](https://docs.render.com/free?_gl=1%2Aum7r58%2A_gcl_au%2ANzg0NTYxMjI4LjE3MjY4OTU1ODM.%2A_ga%2ANDk3NzA4MTQwLjE3MjY4OTU1ODQ.%2A_ga_QK9L9QJC5N%2AMTczMTU4MjIzNy40OC4xLjE3MzE1ODI5MTEuNjAuMC4w#spinning-down-on-idle)
> (原文翻訳引用)
  * **「15 分間 1 件もリクエストが来ないようなら停止 (スリープ) するよ」** と言っている
    * これが「Web アプリの画面が読み込み中でなんか遅い」という原因として考えられる

## （対策）定期的にリクエストを送る
:::note info
リクエストを送れば良いので定期的にリクエストを送る仕組みを利用すれば対処可能
:::
:::note warn
* 現実問題「15 分おきに手動で Web アプリにアクセスする」というのは無理なので自動化を図る必要がある
    * 余程認知されている Web アプリ出ないと厳しい
:::
### 具体的な手段についての一例
  * [こちらの記事](https://qiita.com/ppputtyo/items/2ab44303dcfabeb7b23e)ではリクエストを送って返答があるかを確かめてくれるツールを紹介している
    * 定期的に自動でリクエストを送ることでスリープ対策を取っている

他にも定期的に`ping`コマンドを実行してくれるツールも散見されたので手段には困らないと思われる

## 余談）GAS でいける
:::note info
* [この記事](https://zenn.dev/sdb_blog/articles/002-render-okosu)のようにどうやら GAS でもいけるらしい
  * ただ利用にあたっては Render.com だけでなく GAS 側の制限も考慮しないとならない 
:::

---
### 参考資料
https://zenn.dev/tatehito/scraps/f7929e4a980d1c

https://qiita.com/ppputtyo/items/2ab44303dcfabeb7b23e

https://docs.render.com/free?_gl=1%2Aum7r58%2A_gcl_au%2ANzg0NTYxMjI4LjE3MjY4OTU1ODM.%2A_ga%2ANDk3NzA4MTQwLjE3MjY4OTU1ODQ.%2A_ga_QK9L9QJC5N%2AMTczMTU4MjIzNy40OC4xLjE3MzE1ODI5MTEuNjAuMC4w#spinning-down-on-idle

https://zenn.dev/sdb_blog/articles/002-render-okosu
Next.jsのApp Routerにおけるredirectとrouterについて

こんばんは。

今日は「Next.jsのApp Routerにおけるredirectとrouterについて」について説明いたします。

Next.jsのApp Routerにおけるredirectとrouterは、どちらもページ遷移に関連する機能ですが、使用する状況や動作方法に違いがあります。それぞれの違いについて具体例を挙げながら説明します。

# redirect（リダイレクト）

## 概念:

- redirectは、サーバーまたはクライアント側でURLを別のURLに変更する仕組みです。
- 主にSEO対策、認証管理、URL変更などに使用されます。
- ユーザーが特定のURLにアクセスした際、自動的に別のURLにリダイレクトされます。
- ステータスコード（例: 301, 302）を伴う場合があり、SEOやユーザー体験に影響します。

## 特徴:

- ページ遷移前にURLが変更されます。
- 元のURLではなく、新しいURLにアクセスします。
- サーバーサイドで行われる場合、ページがリロードされることがあります。
- クライアントサイドでも実装可能ですが、主に事前処理に使用されます。

## 例:

```javascript
// app/page.js
import { redirect } from 'next/navigation';

export default function Page() {
  const isLoggedIn = false;

  if (!isLoggedIn) {
    redirect('/login'); // ログインしていないユーザーをログインページにリダイレクト
  }

  return <h1>Welcome!</h1>;
}
```

- ユーザーが/にアクセスした場合、redirectによって/loginに自動遷移。
- ブラウザ上には元のURL/ではなく、/loginが表示されます。

# router（ルーター）

## 概念:

- routerは、クライアントサイドのナビゲーションを行うための機能です。
- ページ遷移を実現しますが、URLが即座に更新され、サーバーリクエストを伴いません。
- 主にボタンクリックやユーザー操作に基づいて動作します。
- ページのリロードが発生せず、SPA（シングルページアプリケーション）として動作します。

## 特徴:

- ユーザー操作（ボタンクリックやリンククリック）によってトリガーされます。
- 現在のURLを保持しながら、別のURLに遷移します。
- URLは変更されますが、ページの再読み込みは行われません。

## 例:

```javascript
// app/page.js
'use client';

import { useRouter } from 'next/navigation';

export default function Page() {
  const router = useRouter();

  const handleNavigation = () => {
    router.push('/dashboard'); // ダッシュボードに遷移
  };

  return (
    <div>
      <h1>Welcome!</h1>
      <button onClick={handleNavigation}>Go to Dashboard</button>
    </div>
  );
}
```

- ユーザーがボタンをクリックすると、router.pushによって/dashboardに移動。
- ページはリロードされず、瞬時に切り替わります。

# 主な違い

| **項目**          | **redirect（リダイレクト）**                     | **router（ルーター）**                    |
|------------------|-----------------------------------------------|-----------------------------------------|
| **動作場所**       | サーバー/クライアント両方で可能                   | クライアント専用                        |
| **用途**          | 条件に基づくURLの変更（認証チェック、SEOなど）       | ユーザー操作に基づくナビゲーション       |
| **ページリロード** | 場合によっては発生                               | 発生しない（SPA方式で動作）             |
| **ステータスコード** | 301, 302などが使用可能                            | ステータスコードなしでURL遷移            |
| **使用例**         | 初期ロード時の認証チェックによるリダイレクト        | ボタンクリックによるページ遷移           |

この2つの機能は目的とページ遷移の方式に違いがあるため、適切な状況で使い分けることが重要です。

今日は以上です。

ありがとうございました。
よろしくお願いいたします。
Dify(ローカル)とOllama(ローカル)でllmアプリを構築してみた

# Dify(ローカル)と Ollama(ローカル)をつないでみた

## 概要

流行りの Dify をローカルで管理し、Ollama を利用してローカルで llm を動かし完全ローカルで llm アプリを構築してみた。

## 事前準備

下記はインストール済みなのを前提にしています。

- Docker
- Docker-compose
- Git

## 手順

### Dify をローカルで動かす手順

dify リポジトリをクローンします。

```bash
git clone https://github.com/langgenius/dify.git
```

作業ディレクトリを移動します。

```bash
cd dify
```

環境設定ファイルを準備

```bash
cp .env.example .env
```

コンテナを立ち上げる

```bash
cd docker
docker compose up -d --build
```

ローカル Dify にアクセスする<br>
http://localhost:3000

### 2. Ollama をローカルで動かす

docker で用意されてる Ollama イメージを pull する

```bash
docker pull ollama/ollama
```

docker-compose.yml ファイルを作成する

```bash
touch docker-compose.yml
```

使用する Ollama イメージを指定して docker-compose.yml を編集する

```yml
version: "3"

services:
  ollama:
    image: ollama/ollama
    container_name: ollama
    environment:
      - OLLAMA_HOST=0.0.0.0
    ports:
      - "11434:11434"
    volumes:
      - ollama:/root/.ollama

volumes:
  ollama:
```

コンテナを立ち上げる

```bash
docker compose up -d --build
```

ローカル Ollama にアクセスする<br>
http://localhost:11434

下記のように出ると問題なく起動してます。<br>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3648303/bcab408f-1840-5ef4-2e85-64a2048681e8.png)


### Dify でのモデル設定

Dify の設定　 → 　モデルプロバイダー　 → 　 Ollama を選択<br>
すると下記の設定画面が出てきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3648303/110bab33-d4ec-e715-2fe1-88254cbb0ba7.png)

ここに下記のように入力する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3648303/9f155eeb-1f88-ac48-8786-103dcefa5e00.png)


そして保存を押すと登録完了

すると llm 選択の際に
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3648303/52d18279-cd49-a0fe-26c4-ff7f56ae22dd.png)


と追加したモデルが表示されます。

## まとめ

このようにすべてローカルで Dify と Ollama を起動させ、llm アプリを構築することができました。
Ollama には様々なモデルがあるので色々試してみるのも面白いと思います。

## 注意

ローカルで動かす場合、かなり遅いので実用性は皆無です。
Next.js App RouterでアドベントカレンダーUIを作ってみた

## はじめに

Next.jsを使用して、インタラクティブなアドベントカレンダーUIを実装してみました。
3Dアニメーションや雪のエフェクトを取り入れつつ、TypeScriptの型安全性も確保しています。

## 完成イメージ

- 24個のドアが7日ごとにグリッド表示
- ドアをクリックすると3Dアニメーションで開く
- 雪が降るエフェクト
- 中にランダムな絵文字とメッセージ
https://adbent-yusukekoides-projects.vercel.app/

## 実装で工夫した点

### 1. ハイドレーションエラーの解決

App Routerでの最大の課題は、サーバーサイドレンダリング（SSR）とクライアントサイドレンダリング（CSR）の整合性でした。

```typescript
// クライアントサイドのみの処理を制御
const [isClient, setIsClient] = useState(false);

useEffect(() => {
  setIsClient(true);
}, []);

// ランダムな要素はクライアントサイドでのみ実行
const [currentSurprises] = useState(() => {
  const initialSurprises: SurpriseMap = {};
  if (typeof window !== 'undefined') {
    const shuffled = [...surprises].sort(() => Math.random() - 0.5);
    // ...
  }
  return initialSurprises;
});
```

### 2. TypeScriptの型安全性確保

オブジェクトのインデックスアクセスに関する型エラーに悩まされました。
インターフェースを定義することで解決しました：

```typescript
interface Surprise {
  emoji: string;
  message: string;
}

interface SurpriseMap {
  [key: number]: Surprise;
}

const [currentSurprises] = useState<SurpriseMap>(() => {
  // ...
});
```

### 3. 3Dアニメーションの実装

CSSの3D変換を使用して、本物のドアのような開閉アニメーションを実現：

```css
.door {
  transform-style: preserve-3d;
  transition: transform 0.5s;
}

.door.open {
  transform: rotateY(-105deg);
}
```

### 4. カレンダーグリッドの実装

7日ごとの改行を実現するために、配列を週単位で分割：

```typescript
const renderCalendarGrid = () => {
  const weeks = [];
  let currentWeek = [];
  
  for (let i = 1; i <= 24; i++) {
    currentWeek.push(<Door key={i} number={i} />);
    
    if (currentWeek.length === 7 || i === 24) {
      weeks.push(
        <div key={weeks.length} className="flex justify-center w-full">
          {currentWeek}
        </div>
      );
      currentWeek = [];
    }
  }
  
  return weeks;
};
```

### 5. 雪のエフェクト

複数の雪の結晶文字を使い、ランダムな動きを実現：

```typescript
const snowflakes = ["❄", "❅", "❆", "✻", "✺", "*"];

const getSnowflakes = () => {
  return Array.from({ length: 8 }).map((_, i) => ({
    flake: snowflakes[Math.floor(Math.random() * snowflakes.length)],
    delay: Math.random() * 5,
    duration: 2 + Math.random() * 3,
    position: Math.random() * 100
  }));
};
```

## 困った点と解決策

### 1. SSRとCSRの不一致

**問題**：
- `Math.random()`を使用した要素の生成
- クライアントサイドでのみ必要なアニメーション

**解決策**：
- `isClient`フラグでレンダリングを制御
- `useEffect`でクライアントサイド処理を分離

### 2. TypeScriptのエラー

**問題**：
- インデックスシグネチャの欠落
- 暗黙的なany型

**解決策**：
- 適切なインターフェースの定義
- 型アノテーションの追加

### 3. モバイル対応

**問題**：
- 小さい画面でのグリッドのはみ出し
- タッチデバイスでの3Dエフェクト

**解決策**：
- レスポンシブなグリッドレイアウト
- `hover`状態の適切な処理

```typescript
<div className="max-w-7xl mx-auto p-4 sm:p-6">
  <div className="flex flex-col gap-4">
    {/* グリッドコンテンツ */}
  </div>
</div>
```

## デプロイ方法

Vercelを使用して簡単にデプロイできます：

1. GitHubにプッシュ
2. Vercelでプロジェクトをインポート
3. 自動デプロイの設定

```bash
# デプロイコマンド
vercel
```

## まとめ

Next.js を使用したインタラクティブUIの実装は、
いくつかの課題がありましたが、適切な設計と型定義により解決できました。

特に以下の点が重要でした：
- SSR/CSRの適切な使い分け
- TypeScriptの型安全性確保
- パフォーマンスとアニメーションの両立
【UE5】info.plistの設定方法

# はじめに
iOSでユーザーに対してカメラやマイクのアクセスや通知の許可をとる場合、info.plistに正しい記述をしないとアプリがクラッシュしてしまいます。

通常はXcodeでinfo.plistの記述をしますが、Unreal Engineの場合はプロジェクト設定から追加することができます。

本記事では、UEのプロジェクト設定からinfo.plistに追加する方法を紹介します。

# 開発環境
- Windows11
- iMac（Sonoma 14.5）
- UE5.3.2

Windowsのリモートビルドでパッケージ化している場合も、MacのXcodeからパッケージ化している場合も、やり方は同じです。

# 設定方法
Project Settings > Platforms > iOSを開きます。
Buildカテゴリに`Additional Plist Data`という項目があり、ここに記述することで設定にないプロパティを自由に追加することができます。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2987446/5f8b8fc5-3086-7623-930c-c0699617c93a.png)


プロパティの一覧はこちらを見てください。

https://developer.apple.com/documentation/bundleresources/information-property-list

info.plistのプロパティを見ていると、そのプロパティに対する値の型で多いのが`string`と`boolean`だったので、この2つを説明します。

### stringの設定方法

例えば、特に設定をせずApp Storeにアプリを提出すると、アプリのリージョンがENになってしまいます。

<img width=300 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2987446/88cd6e8b-8938-d000-ef66-32800889757e.png">

これを修正するには、info.plistに次の記述をします。
```
<key>CFBundleDevelopmentRegion</key>\n<string>ja_JP</string>\n
```

このように設定したいプロパティをkeyで囲み、値をstringで囲みます。

### booleanの設定方法
プロパティはstringと同じで、keyで囲みます。
```
<key>UIRequiresPersistentWiFi</key>\n<true />\n
```
上記のプロパティはアプリにWifi接続が必要かどうかを示すものです。

リージョンの設定、Wifi接続のプロパティを設定した場合は次のようになります。

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2987446/fd8a55d0-1126-6465-3d39-87535cc98dfc.png)

### 確認方法
info.plistに追加した状態でiOSでパッケージ化します。
パッケージ化が終わったら、`~/{Your Projetct}/Saved/StagedBuilds/IOS/Info.plist`を開いて、追加したプロパティが記述してあれば無事設定されています。

# まとめ
Androidはクラッシュしないけど、iOSではクラッシュするという状況に陥った場合、ほとんどの場合はinfo.plistの設定忘れなので、マイクやカメラなど端末の機能を利用する場合は忘れないようにしましょう。

# 参考記事

https://qiita.com/WisteriaWave/items/e72eab4b167a63d911ee

https://historia.co.jp/archives/6518/#:~:text=%E2%97%8BUE4%E3%81%8CInfo.plist%E3%82%92%E7%94%9F%E6%88%90%E3%81%97%E3%81%A6%E3%82%8B%E3%82%B3%E3%83%BC%E3%83%89&text=%E3%81%AB%E3%81%82%E3%82%8BUEDeployIOS%E3%82%AF%E3%83%A9%E3%82%B9%E5%86%85%E3%81%AEGenerateIOSPList%E3%81%A7%E7%A2%BA%E8%AA%8D%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82

https://developer.apple.com/documentation/bundleresources/information-property-list
Mirror vs Netcode(MLAPI), どっちを使うほうがいいか

以下のMLAPIではなく、Mirrorの方がいいのかも、という記事、まだ本当にそうかわかってないですが、自分的にもありえるのかもと思い始めたので、

https://soysoftware.sakura.ne.jp/archives/2140


MirrorのDiscordでのUnityのMLAPIのチームっぽい人（証明はできない）の発言を一応メモとして残しておきます。

![mirror_mlapi.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1771055/38e352ad-4091-3f2f-b694-52e2862d5b70.png)

```
Raydie — 2021年4月2日 19:11
「なぜUnityはオンラインライブラリにMirrorではなくMLAPIを選んだんだ？ Mirrorは多くの作業が完了しているのに、MLAPIはまだプロトタイプだ。MLAPIがMirrorと同じレベルに達するのは…数年かかるかも？」
「UnityはMirrorの開発者たちと話し合ったのか？」

Luke [Unity] — 2021年4月2日 19:14
「私たちは多くの人と話をし、理由があってのことです🙂」

Raydie — 2021年4月2日 19:15
「そうだね、確かにMLAPIは自分のライブラリを構築するための選択肢が多いと思う。
Mirrorは既に多くの作業が終わっているから、それを進化させるのは難しいかもしれない。でもね。きっとその理由には意味があるんだろうね。
今はMLAPIとMirrorの両方を使ってプロトタイプゲームを作ってみてるけど、現時点ではMirrorの方が機能が多く、安定している目的に合っているよ。
将来的にはMLAPIがより強力で、Unityでのパフォーマンスも良くなるかもしれないね。
ただ、単純にその決定について気になっただけさ🙂」

Luke [Unity] — 2021年4月2日 19:19
「私たちの目的は必ずしも安定していて、すぐに本番環境で使えるライブラリを採用することではありませんでした。
MLAPIはまだ実験段階であり、これから多くの変更を加える予定です。その変更はMirrorに対しては実装が難しかったでしょう。
もし今すぐ安定していて機能豊富なライブラリが必要であれば、私の意見ではMirrorの方が良い選択だと思います。」
```


上記にあるように

「目標は安定したネットワークライブラリをUnityに取り込むことではなく、実験的なもの。安定していて機能豊富なライブラリが必要なら、Mirrorの方がいい」


のかもしれません。Mirrorへ移行してみて様子を見てみます。
TypeScriptでcdktf用のcustom providerパッケージを作る

CDKTF in TypeScriptでインフラの定義を部分的にラップした関数を提供したい。

## セットアップ

tsupでビルドしたいので入れておく。ここではpnpmを使う。

```bash
pnpm init
pnpm install -D tsup @types/node typescript
```

あとはcdktf自体もhomebrewかなんかでインストールしておく必要あり。

cdktfとconstructはcustom providerを利用する側でも使うので `peerDependencies` に入れておくのが良さそうだが、正しいかは不明。

## TypeScriptコードの生成

ここまで準備できたら、ベースにしたいproviderを `terraformProviders` で指定した `cdktf.json` を作る

```json
{
  "language": "typescript",
  "app": "exit 0",
  "terraformProviders": [
    "tailor-platform/tailor@~> 0.0"
  ]
}
```

TypeScriptのproviderをgenerateする

```bash
cdktf get
```

すると同ディレクトリに `.gen` が生える。

あとは生成されたproviderを使って、公開したい関数を `index.ts` らへんに準備しておく。

```src/index.ts
export * as Tailor from "../.gen/providers/tailor";

export const addSomeUsefulResources = () => {
  /**
   * いろいろいい感じにリソースを追加してくれる何かしらのコード...
   */
}

```

## ビルド

tsupの設定ファイルはこんな感じ。

```ts
/// <reference types="node" />
import { defineConfig } from "tsup";

export default defineConfig({
  format: ["cjs"],
  entry: ["src/index.ts"],
  clean: true,
  minify: true,
  dts: true,
});
```

cdktfはesmに対応していないので `format` はCommonJS決め打ち。

最終的にはnpmで公開したいので `exports` と `types` を追加。

```json
{
  "name": "my-cdktf-custom-provider"
  "version": "0.1.0",
  "exports": {
    ".": "./dist/index.js",
  },
  "types": "./dist/index.d.ts"
}
```

こういうコマンドも用意しておくと便利

```json
  "scripts": {
    "cdktf:fetch": "cdktf get",
    "build": "pnpm cdktf:fetch && pnpm type-check && tsup",
    "package:publish": "pnpm build && pnpm publish --access public",
  }
```

これで `pnpm package:publish` を実行するだけでパッケージをビルドして公開できる

## 使う側

TypeScriptのcdktfプロジェクトをprovider指定せず初期化

```bash
cdktf init --template=typescript --local
```

先ほど作ったnpmパッケージをインストール

```
npm install --save my-cdktf-custom-provider
```

あとは `main.ts` の中で呼び出すだけ

```main.ts
import { Construct } from "constructs";
import { App, TerraformStack } from "cdktf";
import { addSomeUsefulResources } from "my-cdktf-custom-provider";

class MyStack extends TerraformStack {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    addSomeUsefulResources();
  }
}
```

最後にデプロイする

```bash
cdktf deploy
```

おわり

## 参考実装

https://github.com/IzumiSy/tailor-barebone-cdktf-sdk
なんでもボックス検出できるowlvit

# すぐ使えてなんでも検出
またすごいの出てきたよ。
物の名前を入れたらなんでも検出してくれる。

https://huggingface.co/docs/transformers/model_doc/owlvit

たとえば、「サーフボード（青ボックス）」と「波（赤ボックス）」を検出してみる。

![output (9).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/a0285a67-6825-666f-7e8d-bf677fb0df3c.jpeg)

あるいは、「横笛」を検出してみる。

![output (12).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/d73f8daf-123a-73c8-08d7-06f31ebbb00a.jpeg)

まあたいしたものである。

お気づきかもしれないが、COCO datasetにないクラスも余裕で探せる。

しかもCPUでも２、３秒。
GPUで実行すれば0.5秒以下である（T4）。
クラス数が多くなるとだんだん処理も長くなるけど。

# 使い方

モデルの初期化

```python
from PIL import Image, ImageDraw, ImageFont
import torch
from transformers import OwlViTProcessor, OwlViTForObjectDetection

# モデルとプロセッサの読み込み
processor = OwlViTProcessor.from_pretrained("google/owlvit-base-patch32")
model = OwlViTForObjectDetection.from_pretrained("google/owlvit-base-patch32")
processor.cuda()
model.cuda()
```

実行

```python
import time
import torch
from PIL import Image, ImageDraw, ImageFont
from transformers import OwlViTProcessor, OwlViTForObjectDetection

# 画像の読み込み
image = Image.open("animal.jpg")
texts = [["a photo of a dog",
          "a photo of a cat"]]

# モデル処理
start = time.time()
inputs = processor(text=texts, images=image, return_tensors="pt")
inputs = {k: v.to("cuda") if isinstance(v, torch.Tensor) else v for k, v in inputs.items()}
outputs = model(**inputs)
print(f"Inference time: {time.time() - start} seconds")

# ボックスのスケーリング設定
target_sizes = torch.Tensor([image.size[::-1]])
results = processor.post_process_object_detection(outputs=outputs, target_sizes=target_sizes, threshold=0.1)

# ラベルごとの色設定
label_colors = {
    "a photo of a dog": "red",
    "a photo of a cat": "blue"
}

# 描画設定
draw = ImageDraw.Draw(image)
font = ImageFont.load_default()  # デフォルトフォントを使用

# 各検出結果にボックスとラベルを描画
i = 0  # 1枚目の画像
text = texts[i]
boxes, scores, labels = results[i]["boxes"], results[i]["scores"], results[i]["labels"]

for box, score, label in zip(boxes, scores, labels):
    if score >= 0.2:  # 信頼度0.2以上のみ描画
        box = [round(i, 2) for i in box.tolist()]
        label_text = text[label]
        color = label_colors.get(label_text, "red")  # デフォルト色を赤に設定

        # ボックスとラベルの描画
        draw.rectangle(box, outline=color, width=3)  # ボックスの描画
        draw.text((box[0], box[1] - 10), f"{label_text}: {round(score.item(), 2)}", fill=color, font=font)  # ラベルの描画

# 結果の保存
image.save("output.jpg")  # 画像を保存
```

みんな仕事いそがしいと思うけど、
てきとうに仕事以外のこともやって、
人生がんばっていこうね。

🐣
****
フリーランスエンジニアです。
お仕事のご相談こちらまで
rockyshikoku@gmail.com

Core MLを使ったアプリを作っています。
機械学習関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)
ubuntuにgitとGitHub CLIを入れる

gitを入れます！ubuntuに！

## 環境
- ubuntu22.04

## gitのインストール

```shell:shell
sudo apt install git
```
でインストールできる。
```shell:shell
git --version
```
で```git version 2.34.1```みたいな感じのが出力されたらOK

## 初期設定
```shell:shell
git config --global user.name ユーザー名
git config --global user.email メールアドレス
```
で初期設定を行う。

## GitHub CLI
コマンドライン上でGitHubの操作を行えるCLIツールです。にわかなのでログインにしか使ってません。

### インストール
```shell:shell
sudo apt install gh
```
でインストール。

### ログイン
なんかgithubって定期的にパスワード入れなさいみたいなこと言われるんですけどアカウントのパスワードとはまた違うやつで、ちょっとよくわかんないですよね
それをどうにかしたい！そのためのgithub cliですよみなさん

```shell:shell
gh auth login
```
を実行して、選択肢をなんやかんやで選んでいって、ブラウザでログインしてコマンドライン上に出てたパスワード入れると完了。これでもう未来永劫謎ログインすることなく生きていけます。めでたしめでたし:v:
初めてiOSのゲームを作ってAppStoreに配信できたので感想

## 謎のゲーム
チョコプラの動画で見たネタをもとに作成
[しょうゆ取ってゲーム](https://apps.apple.com/jp/app/%E3%81%97%E3%82%87%E3%81%86%E3%82%86%E5%8F%96%E3%81%A3%E3%81%A6%E3%82%B1-%E3%83%BC%E3%83%A0/id6737563273)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760274/1d7efdae-1f8b-6fa9-2817-24ac4564bef9.png)

自分で作ったアプリが載っているとテンションが上がる

## 掛かった時間
作成期間１ヶ月、審査期間２週間くらい

## 使ったお金
Apple Developer Program　約12800円/年
アプリ申請に必要な開発者サイトのサーバー代　6500円/年
→今回はSwiftなので直接関係しないですが、Unityでアセット購入もしてるのでもっと掛かってます。趣味にお金掛けてる感覚😅

## やったこと
**Apple Developer Programに登録**
これだけで2週間くらい掛かった。
初回は反応なくて問い合わせたら証明書がNGとのことで、パスポートを再申請して登録完了

　
**アプリ作成**
とりあえず、シンプルな醤油取るだけのゲームを2週間くらいで作成しました。
Swiftは仕事で少し使ってましたが、SpriteKitなるものを調べて作成。
画面ごとにシーン作成、ボタン押下でシーン移動というのはUnityと同じで、すぐに慣れました。
StroyBoradのような、UIから画面を構築する方法がありましたが
コードで実装した方がメンテしやすくていいと思います。

　
**広告を入れた**
[GoogleAdMob](https://admob.google.com/intl/ja/home/)に登録して使いました。
[広告を入れる方法を書きました](https://qiita.com/ohigashi-tky/items/89213acbf012edb180ab)
こちらも色々と申請が必要で、個人サイトにAdMobが参照できるテキストファイルを置く必要があります。
FTPやSSHで接続してファイルを作成できるサイトを用意しないとダメです。
ドメイン取得してVPSに設定、WordPressでディベロッパーサイトを作成、ファイルを配置。
ここで用意したサイトURLは、後述のアプリ申請時のマーケットURLに登録する必要があります。
自分はこれ忘れて、申請許可されたあと再申請することになりました。

 　
**問い合わせ用のサイトとプライバシーポリシーを作成**
先ほどのサイトに自分のメールアドレスを記載
プライバシポリシーを[自動で作ってくれるサイト](https://app-privacy-policy-generator.firebaseapp.com/)で作成してコピペ
それぞれのURLをアプリ申請時のディベロッパーサイトURLとプライバシーポリシーURLに設定します。
サイト自体はシンプルでOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760274/f0cac7ef-9c51-973b-41e8-23ef62a28682.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760274/d7b0ed5c-2698-361e-7777-75d651eb7b8d.png)


　
**AppStoreConnectでアプリ申請**
これが一番きつかったです。
[ガイドライン](https://developer.apple.com/jp/app-store/review/guidelines/)違反で申請拒否されまくります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760274/e23535cc-a3bf-b147-ac66-3dbe37079ec0.png)

メタデータの注意なんかは文言など修正するだけでいいんですが、

4.2 最低限の機能　これに苦戦しました。
要するにアプリの機能が少ないよという意味です。
ボタンを追加して難易度を増やしたり、ランキング機能を付けてから
機能の説明を英文で丁寧に伝えました。レビューする人への感謝の一文を必ず入れてください笑

4.3 スパム
最初に２回くらいSKUという個別の識別文字列のようなものを変えてビルドしたせいで
同じアプリ名の申請情報が複製されていました。
なかなか消せなくてサポートに連絡して消すことで通りました。
[不要なアプリ削除方法も書きました](https://qiita.com/ohigashi-tky/items/3bd0229f3a8d0d4ed921)
　
修正してはビルド、TestFlight（試運転のようなもの）にアップを十数回繰り返しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760274/cbc1e39a-02ac-3dea-0495-595aec178167.png)

## 普通にしんどい
ゲーム作りは楽しいけど、審査が厳しすぎてしんどかったです。
厳しいおかげでAppStoreは治安がいいんだなと思いました。

少しでも参考になった・面白かったと思えたらいいね押してもらえると嬉しいです🙇‍♂️
LEGOブロックとM5Goを使った車のラジコンの試作（忘備録）

# はじめに
以前の記事

https://qiita.com/_Moony/items/9a85ce8c019a52960876

https://qiita.com/_Moony/items/9b2f3903329f4ef03ac5

のM5Goとサーボモータを使って、車のラジコンを試作しました。ラジコン本体はLEGOブロック（テクニック系のパーツを使用）で作成し、送信機はPS4コントローラを使用しました。WiFi環境がない場所でも動作するように、M5GoとPS4コントローラはBluetoothで接続しています。

# ラジコンについて

試作したラジコンです。
![20241113_080423.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1729073/c93064f4-b446-837e-7252-0c16d0ee8ebb.jpeg)

蓋になっているブロックを外した状態です。
![20241113_080503.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1729073/e55506c6-bbbd-8f19-bfe9-ec55f3fe86ea.jpeg)


機構の様子です（前輪）。
![20241113_080530.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1729073/e98d1648-4de0-d659-67a8-93c8e2a22d62.jpeg)

機構の様子です（後輪）。かじ取りの際にスムーズに旋回できるよう、ディファレンシャルギヤを介して後輪を駆動しています。
![20241113_080518.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1729073/432090c5-c391-bc6c-e2d9-567ff81b7c24.jpeg)

M5GoとPS4コントローラのBluetooth接続は以下の記事を参考にしました。

https://qiita.com/Geek493/items/8402ad875b88822e75ab

プログラムは以下のとおりArduinoで作成しました。
```
#include <M5Stack.h>
#include <PS4Controller.h>
#include "M5_UNIT_8SERVO.h"

M5_UNIT_8SERVO unit_8servo;

void setup() {
  Serial.begin(115200);
  PS4.begin("**:**:**:**:**:**"); //ここにmacアドレスを入れる
  Serial.println("Ready.");
  
  M5.begin();
  while (!unit_8servo.begin(&Wire, 21, 22, M5_UNIT_8SERVO_DEFAULT_ADDR)) {
    Serial.println("extio Connect Error");
    delay(100);
  }
  unit_8servo.setAllPinMode(SERVO_CTL_MODE);
}

void loop() {
  if (PS4.isConnected()) {
    //コントローラの右のジョイスティックで左右のかじ取り
    int angle = (PS4.RStickX() + 128) * 180/256;
    unit_8servo.setServoAngle(0, angle);
    Serial.printf("Angle at %d\n", angle);
    //コントローラの左のジョイスティックで前後移動
    int rotate = 3000 - (PS4.LStickY() + 128) * 3000/256;
    unit_8servo.setServoPulse(1, rotate);
    Serial.printf("rotate at %d\n", rotate);
  }
}
```

# 終わりに
車両の試作は、ディファレンシャルギヤの機構とかじ取り機構を設けつつ、短い全長にするように心がけました。360'ステップモータに取り付けた歯車とその相手の歯車のかみ合わせが少し緩いため、バックするときにギヤ鳴りすることが改良点です。
PythonでWord文書をMarkdown形式に変換する方法

Markdownは、簡潔な構文と幅広い互換性を持つ軽量マークアップ言語であり、ブログ、技術文書、バージョン管理システムでのコンテンツ管理に特に適しています。一方、Word文書はその強力なレイアウト機能から、文書作成の第一選択肢として広く利用されています。しかし、Word形式を直接使用すると、特定のプラットフォームでは複雑すぎたり、柔軟性に欠けたりする場合があります。**Pythonを使用してWord文書をMarkdown形式に一括変換する**ことで、文書構造を簡略化し、移植性とメンテナンス性を向上させることができます。本記事では、**Pythonを用いてWord文書をMarkdownファイルに変換する方法**を紹介します。

- **[PythonでWord文書をMarkdown形式に変換](#pythonでword文書をmarkdown形式に変換)**
- **[画像を削除してWord文書をMarkdown形式に変換](#画像を削除してword文書をmarkdown形式に変換)**

この記事で紹介する方法では、[Spire.Doc for Python](https://jp.e-iceblue.com/introduce/spire-doc-for-python.html)を使用します。PyPIでインストール可能です：`pip install spire.doc`。  

[無料ライセンスを申請する](https://www.e-iceblue.com/TemLicense.html)  

## PythonでWord文書をMarkdown形式に変換
`Document.LoadFromFile()`メソッドを使用して指定されたファイルパスからWord文書を読み込み、`Document.SaveToFile(fileName: str, FileFormat.Markdown)`メソッドを使用してMarkdown形式に変換し、保存します。以下は手順の例です：  
1. 必要なモジュール（`Document`と`FileFormat`）をインポートします。  
2. `Document`インスタンスを作成します。  
3. `Document.LoadFromFile()`メソッドを使用して指定されたファイルパスからWord文書を読み込みます。  
4. `Document.SaveToFile()`メソッドを使用してMarkdown形式に変換し、保存します。  
5. リソースを解放します。  

**コード例**  
```python
from spire.doc import Document, FileFormat

# Documentオブジェクトを作成
doc = Document()

# Word文書をロード
doc.LoadFromFile("Sample.docx")

# 文書をMarkdown形式に変換してファイルとして保存
doc.SaveToFile("output/WordToMarkdown.md", FileFormat.Markdown)
doc.Dispose()
```

元のWord文書  
![PythonでWord文書をMarkdown形式に変換](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278784/626d1cf6-ed8f-6750-2cdd-1d1b1a5cb74c.png)

変換結果  
![PythonでWord文書をMarkdown形式に変換](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278784/f9c86e22-465e-3b5e-5b8d-30a4ff50c735.png)

## 画像を削除してWord文書をMarkdown形式に変換
Word文書をMarkdown形式に直接変換すると、画像がBase64エンコードされた形式でMarkdownコード内に保存されるため、ファイルサイズが大きくなったり、一部のプラットフォームでBase64エンコードがサポートされない場合があります。そのため、変換前に画像を削除し、必要に応じてリンク形式でMarkdownコードに挿入することが推奨されます。以下は手順の例です：  
1. 必要なモジュール（`Document`と`FileFormat`）をインポートします。  
2. `Document`インスタンスを作成します。  
3. `Document.LoadFromFile()`メソッドを使用して指定されたファイルパスからWord文書を読み込みます。  
4. 文書内のセクション、セクション内の段落、段落内の子オブジェクトを順に走査し、子オブジェクトが`DocPicture`のインスタンスであるかを判定します。該当する場合は、`Paragraph.ChildObjects.Remove()`メソッドを使用して削除します。  
5. `Document.SaveToFile()`メソッドを使用してMarkdown形式に変換し、保存します。  
6. リソースを解放します。  

**コード例**  
```python
from spire.doc import Document, FileFormat, DocPicture

# Documentオブジェクトを作成
doc = Document()

# Word文書をロード
doc.LoadFromFile("Sample.docx")

# 文書中の全てのセクションを巡る
for i in range(doc.Sections.Count):
    section = doc.Sections.get_Item(i)
    # セクション内の全ての段落を巡る
    for j in range(section.Paragraphs.Count):
        para = section.Paragraphs.get_Item(j)
        # 段落内の全てのドキュメントオブジェクトを巡る
        for k in range(para.ChildObjects.Count):
            obj = para.ChildObjects.get_Item(k)
            # ドキュメントオブジェクトが画像の場合、画像を削除
            if isinstance(obj, DocPicture):
                para.ChildObjects.Remove(obj)

# 文書をMarkdown形式に変換してファイルとして保存
doc.SaveToFile("output/WordToMarkdownNoImage.md", FileFormat.Markdown)
doc.Dispose()
```

変換結果  
![画像を削除してWord文書をMarkdown形式に変換](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278784/ca434949-029b-851f-e65b-81a83355acec.png)

本記事では、Pythonを使用してWord文書をMarkdownファイルに変換する方法を紹介しました。
Snowflakeの権限で設定ミスったことメモ

9月にあったSnowflake World Tour TOKYOで学んだDATABASE ROLEを使うべく、ロール設計を見直しました。
（DATABASE ROLE、その時に初めて聞いた機能で、使わないとと思いつつ2か月経過してしまいました。）

![スクリーンショット 2024-11-15 181646.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3487310/3209cecd-0da0-f546-08ca-e854d8331ca3.png)

ユーザー：kumataroはアナリストとして、SELECTだけできればよいということで上記画像のようにロールを作りました。
他のいろいろ管理する人やタスクなどシステム操作で書き込んだりするのは別のファンクショナルロールを割り当てます。（この画像では省略）

図の下から。
- TEST_DB.TEST_SCHEMAのTABLEやVIEWに対するSELECT権限だけあるのがデータベースロールであるtest_db_r。
- データベースロールを継承したアクセスロールであるtest_user_role。
- そのアクセスロールを継承したファンクショナルロールであるanalyst_role。
- ファンクショナルロールであるanalyst_roleをユーザー：kumataroが持っている。

という感じになりました。

ベストプラクティスに沿った形になってるでしょうか？
⇒アドバイス求む

※追記Start

https://qiita.com/a-kamiya/items/22802fb715817b4878d2

新たな投稿でロール設計を修正しました。
※追記End

TEST_DB.TEST_SCHEMAにはテーブル1つとマテリアライズドビューが1つあります。
テーブル：TEST_TABLE
マテリアライズドビュー：TEST_MVIEW
TEST_TABLEをGROUP BY ALLで重複行削除したのがTEST_MVIEWです。

そしてTABLEとVIEWに対するSELECT権限を以下のクエリで付与しました。

```
--TEST_SCHEMAのTableとViewに対するSELECT権限付与
GRANT SELECT ON ALL TABLES IN SCHEMA TEST_SCHEMA TO DATABASE ROLE test_db_r
GRANT SELECT ON ALL VIEWS IN SCHEMA TEST_SCHEMA TO DATABASE ROLE test_db_r;
```

これでユーザー：kumataroはテーブルとViewが見えるでしょ？と思ったらSnowSight上にテーブルしか表示されないんです。
![スクリーンショット 2024-11-15 183103.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3487310/7cd8859e-eeb9-bb56-f463-4605dafbae8b.png)

なんで？？って30分くらい悩みました。
で、ふと気づきました。
VIEWに対するSELECT権限を付与したけど、実際見たいのはマテリアライズドビューじゃん！って。

```
GRANT SELECT ON ALL MATERIALIZED VIEWS IN SCHEMA TEST_SCHEMA TO DATABASE ROLE test_db_r;
```
このコマンド流したら見えました。

なんでこんなしょぼい間違いをしたのかというと、上記の画像で「テーブル」ってカタカナで出ている部分、マテリアライズドビューは「ビュー」の中に入るんですね。
「はいはい、ビューを見たいんでしょ」って思ってViewに権限付けてました。

自分の作業ミス記録として残します。
たぶんまた間違えるんだけど、次はこの記事を思い出したら5分で解決できるはず。
【備忘録】Firebase AuthのログインのためにSHA-1を用意する必要があったが出てくれなかった

# どういうことか

以下の状況でハマった。

* Flutterで開発している
* Android端末でGoogleログインしたかった
* そのためにFirebaseのコンソールにSHA-1を登録する必要がある
* ググって出てきたコマンドなどを試したがうまくいかなかった

## 解決策

この記事で救われた。

https://qiita.com/k-keita/items/ae6ccf9d3992fc7526bd

解決した理由はよくわかってないんですが。。

## 失敗例、またできなかったこと

### コマンドのパターン

ググったらよく出てくるコマンドを試した。
パスワードは入力しなくてもいいらしい。
結果出なかった。

`keytool -list -v -keystore ~/.android/debug.keystore`

```terminal
キーストアのパスワードを入力してください:  

*****************  WARNING WARNING WARNING  *****************
*キーストアに保存された情報の整合性は*
*検証されていません。整合性を検証するには*
*キーストアのパスワードを入力する必要があります。*
*****************  WARNING WARNING WARNING  *****************
```

### Android Studioのパターン

『Gradleから確認する』というもの。
「`/android` のディレクトリを右クリックしてFlutterの部分をクリックして〜」と書かれているが、Flutterの部分がグレーアウトされていて選択できなかった（一番下）。

![スクリーンショット 2024-11-15 18.29.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413699/88ba879f-66a4-df90-370e-edbf50072b5c.png)
Google maps APIの　development purposes only　の表示が消えない　（解決済み）

## はじめに
オリジナルアプリの中にGoogle Mapを実装したいと思い
1,Google cloud Platformにログインして
2,クレジットカード情報も登録して
3,使用するAPI(Maps JavaScript API,Geocoding API)の有効化もして
4,APIのキー取得、設定もして（APIごとのキーを取得すると書いてある記事もあったが今は1つでいいようですね）
```.gitignore
/.env
```
```.env
GOOGLE_MAPS_API_KEY = "取得したAPIキーを記載"
```
をそれぞれ記述して実行してもdevelopment purposes onlyの表示は消えない。
何で？と思ってたら、あっ!!!
```Gemfile
gem 'dotenv-rails'
```
の記述とインストールを忘れていた！
``$ bundle install ``もやって、ようやく表示されました。

## おわりに
新しい機能を使うときは難しい。でもどんどん色んな機能を実装して経験値を増やしていきたいです！
「Rails x AWS S3」で画像アップロードする手段を全く知らないため調べる

※本内容は 2024/11/15 時点での調査となっております

# "aws-sdk-s3" v.s. "fog-aws"
* 現状この 2 強と思われる
* 登場した時期が fog-aws の方が約 2 年先にリリースされている

## [aws-sdk-s3](https://github.com/aws/aws-sdk-ruby)
:::note info
* **AWS 公式の gem**
  * [aws-sdk-ruby](https://github.com/aws/aws-sdk-ruby) という gem に含まれている
      * `aws-sdk-s3` 単体でもインストール可能
* fog-aws と比較してもダウンロード数で約 5 倍の差をつけている
    * スター数など他数値においても圧倒している
:::
:::note warn
* ただ fog-aws と比較すると技術記事がなぜか少ない
:::

## [fog-aws](https://github.com/fog/fog-aws)
:::note info
* carrierwave ではこちらのジェムを用いた手順が提示されている
    * carrierwave が提示している Amazon S3 を使う場合の手順は「[carrierwave x fog-aws](https://github.com/carrierwaveuploader/carrierwave?tab=readme-ov-file#using-amazon-s3) 」で説明されている
  * この 2 つの組み合わせの相性が良い？
* aws-sdk-s3 より技術記事が多い
  * 2 年先にリリースされたから？
:::
:::note warn
* **AWS 公式ではない**
  * 他 gem に fog-google という Google Cloud Platform (Google Cloud Storage) 版の gem も提供しておりクラウドを扱う事に強みがある？
:::

### 他）[carrierwave-aws](https://github.com/carrierwaveuploader/carrierwave-aws)
* S3 利用特化の carrierwave
* 近年はアップデートされていない

# "aws-sdk-s3" v.s. "fog-aws"
* [ジェムの比較結果](https://www.ruby-toolbox.com/compare/aws-sdk-s3,fog-aws?display=table&order=score)は下の画像の通りになりました

(※2024/11/15時点)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3518714/67cd6c2f-aa54-2bf6-6c97-f4fd69079308.png)

---
### 所感
* この 2 点の gem の違いが全く分からない
  * そのせいか両方のジェムをインストールして実装している方もいらっしゃった
  * AmazonS3 の理解が乏しいからかどこが差異ポイントなのか理解できていない
* `[rails アプリ]  <-（fog-aws）-> [AWS S3]` という具合に AWS との連携を確立するだけなら公式の方が良い？
* carrierwave を個人的に使用したいので fog-aws を採用する予定

---
### 参考資料
https://github.com/orgs/aws/repositories?q=+lang%3Aruby&type=all

https://github.com/aws/aws-sdk-ruby

https://github.com/fog/fog-aws

https://github.com/carrierwaveuploader/carrierwave-aws

https://www.ruby-toolbox.com/compare/aws-sdk-s3,fog-aws?display=table&order=score
クラスとインスタンスについて自分なりのイメージで書き出してみる

# はじめに
自分なりのクラスとインスタンスについてのイメージを語ってみようと思います。私がよく使っているJavaを題材にします。
私は最初オブジェクト指向をたい焼き機とたい焼きの関係で理解したのでそれを例えとします。なぜこのような例えを用いるのかは、私的には専門的な言葉の定義をイメージなしで語るのはいまいち理解しにくいと思うからです。

## 自分なりの大まかな定義
- インスタンスは「モノ」
  → たい焼き
- クラスはモノをつくる「マシン」
  → たい焼き機
- 動的メソッドは「モノに対する操作」
  → たい焼きを焼く、食べるなどの動作
- 静的メソッドは「マシンの操作」
  → たい焼き機のボタン
- 動的変数は「モノの状態」
  → たい焼きの具材、大きさなど
- 静的変数は「マシンの共有」
  → たい焼きの個数など
- コンストラクタは「モノをつくる最初の工程」
  → たい焼きを作り始めるときの処理

## コードにしてみると
たい焼きのクラスをつくってみます。
具材、大きさを入れるための動的変数(インスタンスの変数)を用意します。

```java
public class Taiyaki {

    // たい焼きの具材
    public String ingredient;
    // たい焼きの大きさ
    private int size;

    // コンストラクタ (たい焼きを作る)
    public Taiyaki(int size) {
        this.size = size;
    }

    // たい焼きの具材をセットするメソッド
    public void setIngredient(String ingredient) {
        this.ingredient = ingredient;
    }

    // たい焼きの大きさを返すメソッド
    public int getSize() {
        return size;
    }
}

// メイン関数 (Java23以降から利用できる書き方)
void main() {
    // インスタンス化 → たい焼きを生成する
    var taiyaki = new Taiyaki(2);

    // インスタンスを操作する(動的メソッド呼び出し)
    taiyaki.setIngredient("あんこ");

    // 具材：あんこ, 大きさ： 2と出力される
    println("具材：" + taiyaki.ingredient + ", 大きさ：" + taiyaki.getSize());
}
```

## 静的メソッド、静的変数も使うと
上記のコードにたい焼き(インスタンス)の数を保存してみる。
```java
public class Taiyaki {

    // 作成したたい焼き(インスタンス)の個数
    private static int count;

    // 作成したたい焼き(インスタンス)の個数を返すメソッド

    public static int getCount() {
        return count;
    }

    public Taiyaki(int size) {
        this.size = size;
        count++;
    }

    (以下略...)
}
```

## 上記のものを絵で表現してみる
静的変数、静的メソッド、クラス、インスタンスを以下のように表現してみた。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1015774/9c3bf4e5-1c8d-02f1-69f6-a26fb67f19ad.png)


## さいごに
これらはクラス、インスタンスがいまいちよくわからない人のために書いた記事であくまでイメージです。
私も最初の頃はまったくの独学だったので静的(static付き)と動的の違いがわかりませんでした。やっているうちにわかってきたという感じです。
paiza.ioでelixir その325

# 概要
paiza.ioでelixirやってみた。
HashSet、やってみた。

# 参考にしたページ

https://qiita.com/tbpgr/items/6eeb56cf7c1771ac5ce0

# サンプルコード

```
set1 = Enum.into 2..6, HashSet.new
IO.inspect set1


IO.inspect "delete(set, term)"
IO.inspect Set.delete set1, 3


IO.inspect "difference(set1, set2)"
set2 = Enum.into 4..8, HashSet.new
IO.inspect Set.difference set1, set2


IO.inspect "disjoint?(set1, set2)"
IO.inspect Set.disjoint? set1, set2
set3 = Enum.into 7..10, HashSet.new
IO.inspect Set.disjoint? set1, set3


IO.inspect "equal?(set1, set2)"
set4 = Enum.into 7..10, HashSet.new
IO.inspect Set.equal? set1, set4
IO.inspect Set.equal? set3, set4


IO.inspect "intersection(set1, set2)"
IO.inspect Set.intersection set1, set2
IO.inspect Set.intersection set1, set3


IO.inspect "member?(hashset, term)"
IO.inspect Set.member? set1, 2
IO.inspect Set.member? set1, 7


IO.inspect "put(hashset, term)"
IO.inspect Set.put set1, 7
IO.inspect Set.put set1, 6


IO.inspect "size(hashset)"
IO.inspect Set.size set1
set5 = Enum.into 1..10, HashSet.new
IO.inspect Set.size set5


IO.inspect "subset?(set1, set2)"
IO.inspect Set.subset? Enum.into(2..4, HashSet.new), Enum.into(2..5, HashSet.new)
IO.inspect Set.subset? Enum.into(2..5, HashSet.new), Enum.into(2..4, HashSet.new)


IO.inspect "union(set1, set2)"
IO.inspect Set.union Enum.into(2..4, HashSet.new), Enum.into(4..8, HashSet.new)




```

# 実行結果

```
#HashSet<[2, 6, 3, 4, 5]>
"delete(set, term)"
#HashSet<[2, 6, 4, 5]>
"difference(set1, set2)"
#HashSet<[2, 3]>
"disjoint?(set1, set2)"
false
true
"equal?(set1, set2)"
false
true
"intersection(set1, set2)"
#HashSet<[6, 4, 5]>
#HashSet<[]>
"member?(hashset, term)"
true
false
"put(hashset, term)"
#HashSet<[7, 2, 6, 3, 4, 5]>
#HashSet<[2, 6, 3, 4, 5]>
"size(hashset)"
5
10
"subset?(set1, set2)"
true
false
"union(set1, set2)"
#HashSet<[7, 6, 2, 4, 3, 5, 8]>
```

# 成果物

https://paiza.io/projects/7y0hKYljxTfEITQLAkE_-A?language=elixir

以上
Trusted Advisorのチェックを非表示にする

# 内容

Trusted Advisorのチェック項目を非表示にしたい時があると思います。その際、AWSコンソールからだと「非表示&更新」という箇所がグレーアウトして非表示に出来ない項目がありますので、AWS CLIから表示にする方法を記載します。

![ts1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/88396fd7-5c48-7756-5111-d2c8f06c605e.png)

# 手順

右の矢印の箇所をクリックして、Excelファイルをダウンロードします。ダウンロードしたファイル名を確認します。

![ts2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/82106a09-222e-5e09-5dd5-ab627d605172.png)

`check/xxxxxx`の箇所を上記ファイル名に置き換えて下記コマンドを実行します。

```shell
aws trustedadvisor list-recommendations --region us-east-1 --query 'recommendationSummaries[?checkArn==`arn:aws:trustedadvisor:::check/AbcAdJ7NrP`]'
[
    {
        "arn": "arn:aws:trustedadvisor::xxxxxxxxxxx:recommendation/yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyy",
        "awsServices": [
```

`arn:aws:trustedadvisor::xxxxxxxxxxx:recommendation/yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyy`箇所の出力を確認します。

`arn:aws:trustedadvisor::xxxxxxxxxxx:recommendation/yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyy`箇所を上記で確認した結果に置き換えて下記コマンドを実行します。

```shell
aws trustedadvisor list-recommendation-resources --region us-east-1 --recommendation-identifier arn:aws:trustedadvisor::xxxxxxxxxxx:recommendation/yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyy
{
    "recommendationResourceSummaries": [
        {
            "arn": "arn:aws:trustedadvisor::xxxxxxxxxxx:recommendation-resource/zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzz/zzzzzzzzzzzzzzzzzzzzzzzzzzzz",
```

`"arn": "arn:aws:trustedadvisor::xxxxxxxxxxx:recommendation-resource/zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzz/zzzzzzzzzzzzzzzzzzzzzzzzzzzz"`箇所の出力を確認します。対象のリソースが複数ある場合（この項目の場合は対象のS3バケットが複数ある場合）、対象のリソース分出力されます。

`arn:aws:trustedadvisor::xxxxxxxxxxx:recommendation-resource/zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzz/zzzzzzzzzzzzzzzzzzzzzzzzzzzz`箇所を上記で確認した結果に置き換えて下記コマンドを実行します。対象リソースが複数の場合は全てのリソースに対して実行します。

```shell
aws trustedadvisor batch-update-recommendation-resource-exclusion --recommendation-resource-exclusions arn="arn:aws:trustedadvisor::xxxxxxxxxxx:recommendation-resource/zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzz/zzzzzzzzzzzzzzzzzzzzzzzzzzzz",isExcluded=true --region us-east-1

{
    "batchUpdateRecommendationResourceExclusionErrors": []
}

```

チェック項目から非表示となり、非表示の項目に表示されるようになります。

![ts3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/79e49f65-9f1c-eb62-b4be-75cead7b0df2.png)
PCの自動電源ON機能を活用するメリット

PCの自動電源ON機能を利用したことはありますか？  
この機能はBIOS設定で曜日と時間を指定すると、PCが自動で電源ONになるものです。私は職場の同僚に教えてもらって以来、使い始めました。これを使ってみると、いくつかのメリットがありましたので共有します。

### 1. 出社後すぐに作業を開始できる

勤務予定日の開始時間より少し早めに電源がONになるよう設定することで、出社後すぐにログイン可能な状態にしておけます。起動待ちの時間が短縮され、スムーズに作業を始められます。

### 2. 電力消費を抑えられる

電源を常時ONにする代わりに、自動電源ON機能を使えば必要な時だけPCをONにできます。電源をOFFにする時間が増えるため、待機電力の削減につながります。

### 3. セキュリティ対策に有効

PCをOFFにしている間は外部からアクセスされるリスクが減ります。電源がOFFになっていることで、物理的な侵入リスクも低減でき、不正アクセス防止に一役買います。

### 注意点

自動電源ON設定をしていても、指定した曜日が休日の場合はPCがONのままになる点に注意が必要です。しかし、設定・解除は簡単なので、一度試してみるのはいかがでしょうか？
Dockerとは

# <font color="green">Dockerとは</font>
#### Dockerは、一つのPC上に複数のコンテナ型仮想環境を作成できるツールです。
この「コンテナ」を活用することで、一台のPCで複数のアプリケーションを効率的に開発・実行できる様になります。

>コンテナ」とはパソコンやサーバー上で隔離され、干渉されない環境です。

# <font color="green">Dockerを使わない場合の問題点</font>
**１.複数のバージョン管理が難しい**
例えば、PCにLaravel 6で作った「アプリA」があり、これをPHPのバージョン7.2で動かしているとします。
その後、Laravel 8を使って「アプリB」をPHP 7.4で開発する必要が出てきたとします。
この場合、同じPCで複数のバージョンのPHPやライブラリを管理するのは煩雑で、手動で切り替えが必要になることがあります。

**２.環境の不一致**
チーム開発では、メンバー間での開発環境の違い（OSやソフトウェアバージョンの違い）が原因で、動作確認やデバッグが複雑になることがあります。

**３. 依存関係や設定の管理が複雑**
PCに複数のバージョンのライブラリやパッケージをインストールすると、依存関係が複雑化し、設定ミスや競合が発生しやすくなります。
たとえば、「アプリA」のためにインストールしたライブラリが「アプリB」に影響を与えることもあります。

#### <font color="gray"> 解決方法は？</fond>
この問題を避けるために、新しいPCを購入して別環境を構築するという選択肢もありますが、それはコストが高く、非効率です。**そこで役立つのがDockerです。**

# <font color="green">Dockerを活用する利点</font>
#### Dockerを使用することで、一つのPC上で複数の異なる環境を独立して構築できます。

### Dockerを使用する流れ
**１.** 自分のPCにDockerをインストールします。
**２.** 必要な環境を持つ**Dockerイメージ**を用意し、そのイメージを元に**コンテナ**を作成します。

>コンテナとは仮想環境そのものです。一台のPCで複数のコンテナを作成できます。

**３.** **コンテナAでアプリAを開発し、コンテナBでアプリBを開発する**、といったように独立した環境を使い分けられます。

**これらのコンテナは互いに干渉することなく動作します。**（必要であれば干渉させることも可能です）

### 具体例
一つのPCで、
- **コンテナA**では、Laravelバージョン６を使って**アプリA**を開発します。
- **コンテナB**では、Laravelバージョン８を使って**アプリB**を開発します。
このように、Dockerを使用すれば異なるバージョンのソフトウェアを簡単に共存させることができます。

# まとめ
Dockerとは、**開発者が効率良くプロジェクトを管理し、異なるアプリケーションをスムーズに開発するための強力なツール**です。
コンテナ型仮想環境を活用することで、従来の複雑な設定や環境の競合を避けられます。
**一台のPCでも、まるで複数の独立したマシンを使っているような柔軟な開発が可能になります。**
Pythonを使ってみよう（マクロでやっていた自動化を実現してみる）文字化けを直す


これは意外に素直におわった

>https://qiita.com/trhstrhsr/items/04d79cd4414e3d500347

```.py
import glob
import pandas as pd

root_path = r"\\172.17.2.1\user\PLANT\90_ｼｽﾃﾑ\400.アカウント\430.beat-box\432.ファイルの保存\*"
items = glob.glob(root_path)



df = pd.DataFrame(items)

# DataFrameをCSVに保存
df.to_csv(r"C:\Users\maedat\OneDrive - ●●●●株式会社\デスクトップ\output.csv", index=False,  encoding="shift_jis")
```

完成です
Pythonを使ってみよう（マクロでやっていた自動化を実現してみる）収集データ書き出し

### 6時間目突入

pandasを使うだけってあるので、」
```.py
import glob
import pandas as pd

root_path = r"\\●●●●\user\PLANT\90_ｼｽﾃﾑ\400.アカウント\430.beat-box\432.ファイルの保存\*"
items = glob.glob(root_path)

items.to_excel(root_path,sheet_name='ファイル名', index=True)
```
簡単に入れてコードするも

```.py（エラー）
C:\Users\maedat>Python "C:\Users\maedat\OneDrive - ●●●●株式会社\デスクトップ\import glob.py"
Traceback (most recent call last):
  File "C:\Users\maedat\OneDrive - ●●●●株式会社\デスクトップ\import glob.py", line 2, in <module>
    import pandas as pd
ModuleNotFoundError: No module named 'pandas'
```

いつも出るのはこのエラー

２行目が間違っているよだって

でも呼び出しなんでまちがってるっていっても

エラーコードで引いてみた
>https://qiita.com/udata/items/e164189028f4fa0fc50b
あった。

まずPandasのインストール

```.py
C:\Users\maedat>pip install pandas
Collecting pandas
  Downloading pandas-2.2.3-cp313-cp313-win_amd64.whl.metadata (19 kB)
Collecting numpy>=1.26.0 (from pandas)
  Downloading numpy-2.1.3-cp313-cp313-win_amd64.whl.metadata (60 kB)
Collecting python-dateutil>=2.8.2 (from pandas)
  Downloading python_dateutil-2.9.0.post0-py2.py3-none-any.whl.metadata (8.4 kB)
Collecting pytz>=2020.1 (from pandas)
  Downloading pytz-2024.2-py2.py3-none-any.whl.metadata (22 kB)
Collecting tzdata>=2022.7 (from pandas)
  Downloading tzdata-2024.2-py2.py3-none-any.whl.metadata (1.4 kB)
Collecting six>=1.5 (from python-dateutil>=2.8.2->pandas)
  Downloading six-1.16.0-py2.py3-none-any.whl.metadata (1.8 kB)
Downloading pandas-2.2.3-cp313-cp313-win_amd64.whl (11.5 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 11.5/11.5 MB 21.6 MB/s eta 0:00:00
Downloading numpy-2.1.3-cp313-cp313-win_amd64.whl (12.6 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 12.6/12.6 MB 23.6 MB/s eta 0:00:00
Downloading python_dateutil-2.9.0.post0-py2.py3-none-any.whl (229 kB)
Downloading pytz-2024.2-py2.py3-none-any.whl (508 kB)
Downloading tzdata-2024.2-py2.py3-none-any.whl (346 kB)
Downloading six-1.16.0-py2.py3-none-any.whl (11 kB)
Installing collected packages: pytz, tzdata, six, numpy, python-dateutil, pandas
Successfully installed numpy-2.1.3 pandas-2.2.3 python-dateutil-2.9.0.post0 pytz-2024.2 six-1.16.0 tzdata-2024.2

[notice] A new release of pip is available: 24.2 -> 24.3.1
[notice] To update, run: python.exe -m pip install --upgrade pip
```

### 次のエラー

```.py
C:\Users\maedat>Python "C:\Users\maedat\OneDrive - ●●●●株式会社\デスクトップ\import glob.py"
Traceback (most recent call last):
  File "C:\Users\maedat\OneDrive - ●●●●株式会社\デスクトップ\import glob.py", line 7, in <module>
    items.to_excel(root_path,sheet_name='売上', index=True)
    ^^^^^^^^^^^^^^
AttributeError: 'list' object has no attribute 'to_excel'
```


どうやら
>https://teratail.com/questions/p82w0odpsyi9vb
からすると

**まずリストをpandasのDataFrameに変換し、その後to_csvメソッドを使用します。**

とあるので、

このように変更しました。

```.py
import glob
import pandas as pd

root_path = r"\\●●●●\user\PLANT\90_ｼｽﾃﾑ\400.アカウント\430.beat-box\432.ファイルの保存\*"
items = glob.glob(root_path)



df = pd.DataFrame(items)

# DataFrameをCSVに保存
df.to_csv(r"C:\Users\maedat\OneDrive - ＤＯＷＡテクノエンジ株式会社\デスクトップ\output.xlsx", index=False)
```

きちんとファイルは出来上がりました。

でも文字化けする～～～～(´；ω；`)ｳｩｩ

旅路はながいのだ