OmniAICreator/Qiita-1.07M huggingface dataset:
初めてAnsibleを使ってみた④ ロール

前回の記事

https://qiita.com/starroadkoichi1128/items/a02712df95bdb7e351e5

# Ansibleロールとは
今回はAnsibleのロールを試してみます。
私の中でロールというとAWSのIAMロールやVMwareのロールをイメージしてしまい
権限をセットしてアカウントに付与するものみたいなイメージがありますが
Ansibleでのロールはプレイブック内のタスク細分化みたいな感じです。
例えば前回作成した以下のプレイブックの場合で見てみます。

    - hosts: all
      vars:
        sname: httpd
      tasks:
        - name: httpインストール
          yum:
            name={{sname}}
            state=present
        - name: serviceスタート
          service:
            name=httpd
            state=started
        - name: FW無効化
          service:
            name=firewalld
            state=stopped

このプレイブックではタスクとして以下の３個があります。
* httpdのインストール
* httpdサービスのスタート
* FWの無効化

これをロールで細かく分けて作成することができます。
イメージとしてはこんな感じですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3857934/c1a55e6b-85cd-4c5a-acc9-756fe3d72a76.png)

まぁぶっちゃけこのサンプルテストブックでは大したことやっていないので
分けるメリットが無いのですが実際に業務等で使用する場合は使えそうですね。
例えば
1. 責任分界点が明確になる
1. 関連する動作やアクションだけでまとめることにより記述ミスが減る(インストールだけのロール等)
1. 2できれいにまとめていればレビューもやりやすい
1. メインプレイブック側で呼び出すロールを選ぶことで用途に合わせたプレイブックを作成できる

上手くロール側の設計をしておけば柔軟に使えそうですね。

# ロールを使って動作を試してみる

前回試したhttpdインストール、サービス起動、FW停止の
プレイブックをロールを使った形にして動作を試してみます。
/home/workのディレクトリを作業ディレクトリとして作成しています。



* コマンドで実行するプレイブック

/home/work/main.yml

    - hosts: all
      roles:
        - install
        - service
        - fw

* httpdインストールするロール

/home/work/roles/install/tasks/main.yml

    ---
    - name: httpインストール
      yum:
        name: httpd
        state: present





* httpdサービスを起動するロール


/home/work/roles/service/tasks/main.yml

    ---
    - name: serviceスタート
      service:
        name: httpd
        state: started


* FWを停止するロール

/home/work/roles/fw/tasks/main.yml

    ---
    - name: FW無効化
      service:
        name=firewalld
        state=stopped

↓の二つの書き方はどちらでもよいみたい
name: firewalld
name=firewalld

ツリーコマンドで表示するとこのようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3857934/6690e66e-7759-4c9c-a7ae-10c0935d79eb.png)

デフォルト設定ではロールの名前はmain.ymlとする必要があり
フォルダもロール名/tasks/main.ymlにする必要があるようです。

# 実行
上手くいきました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3857934/cedfde87-5f57-461e-8fef-a27f004580fd.png)

２回目

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3857934/46e0555d-6898-49ac-8079-0c02708e8ef9.png)
empApi PushTopic LWC

## topicの登録は [empApi PushTopic](Aurahttps://qiita.com/hohopeter/items/0ae8901426064547b78c) を参考

## LWCを作成

```xml
<template>
    <lightning-button label="Subscribe PushTopic" onclick={handleSubscribe}></lightning-button>
    <lightning-button label="Unsubscribe PushTopic" onclick={handleUnsubscribe}></lightning-button>

    <template for:each={messages} for:item="msg">
        <p key={msg} class="slds-box slds-box_xx-small slds-m-vertical_xx-small">
            {msg}
        </p>
    </template>
</template>
```

```apex
import { LightningElement } from 'lwc';
import { subscribe, unsubscribe, onError } from 'lightning/empApi';

export default class MyPushTopicListener extends LightningElement {
    subscription = null;
    messages = [];

    // 初期化（LWCにおけるcomponentDidMountのような役割）
    connectedCallback() {
        // イベントエラー時の処理
        onError((error) => {
            console.error("Error in EmpApi: ", error);
        });
    }

    // PushTopicの購読
    handleSubscribe() {
        const channel = '/topic/AccountUpdatePushTopic';  // 使用するPushTopic名を指定
        const replayId = -1;  // 最新のメッセージから購読

        // 購読して、メッセージを受け取る
        subscribe(channel, replayId, (message) => {
            console.log('Received message: ', JSON.stringify(message));
            // 受信したメッセージをmessagesリストに追加
            this.messages = [JSON.stringify(message.data.sobject), ...this.messages];
        }).then((response) => {
            console.log('Successfully subscribed to channel: ', channel);
            this.subscription = response;
        });
    }

    // PushTopicの購読解除
    handleUnsubscribe() {
        if (this.subscription) {
            unsubscribe(this.subscription, (response) => {
                console.log('Unsubscribed from channel: ', response);
            });
        }
    }
}
```

```xml
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>63.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__RecordPage</target>
        <target>lightning__AppPage</target>
        <target>lightning__RecordAction</target>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>
```

## LWCコンポーネントを画面に追加、今回はホーム画面に追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3894299/7320bd34-4cc8-436f-a34b-85fd3e5810fd.png)

## 新規でAccountを追加、または、Faxを変更するとMsgが↑↑↑ように表示される
WEBページをPDF化してBedrockのベクトルDBに自動同期する

 # 内容
Amazon Bedrockのナレッジベースを使用したRAGシステムを構築します。
EC2サーバ上に`get_pdf.py`というスクリプトを用意します。このスクリプトはPlaywrightを使用して、WEBページのデータをPDFとしてEC2サーバ内のディレクトリに保存後、S3バケットにアップロードを行います。また`sync_pdf.py`というスクリプトを用意します。このスクリプトはS3に取得したPDFの情報をAuroraで構成したベクトルDBに同期します。なお2つのスクリプトはcronを使用して定期的に実行を行います。

![rag60.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/aad66fd2-91c3-4a57-8a31-b27999be0a0c.png)

# 前提条件
* EC2サーバはPrivarteLinkやNATゲートウェイを使用して、S3やBedrockのAPIにアクセス出来ること
* EC2サーバはイントラネット内またはインターネット上のWEBサーバにアクセス出来ること
* EC2サーバはS3やBedrockにアクセスするためのIAMロールの設定が完了していること
* Playwrightがインストール済みであること

# PDFデータの取得
`s3_bucket_name`にPDF保存先のS3バケット名を指定します。また`local_dir`にはPDFを保存するサーバ上のディレクトリを指定します。サーバ内のディレクトリにPDFファイル取得した後、S3にアップロードするといった動作を行います。

```python:get_pdf.py
import asyncio
from playwright.async_api import async_playwright
import boto3

s3_client = boto3.client('s3')
s3_bucket_name = "********"
local_dir = "/***/***/doc"
```

PlaywrightはChromiumブラウザをバックグラウンドで起動して、該当のWEBページに移動した後、PDFファイルとして保存します。その後、`s3_client.upload_file`を使用してS3にファイルをアップロードしています。


```python
async def save_as_pdf(url, output_filename):
    output_path = f"{local_dir}/{output_filename}"
    async with async_playwright() as p:
        browser = await p.chromium.launch()
        page = await browser.new_page()
        await page.goto(url)
        await page.pdf(path=output_path, format="A4")
        await browser.close()
        s3_client.upload_file(output_path, s3_bucket_name, output_filename)
```

情報を取得するWEBサイトのリストです。URLと保存するPDF名を指定します。
```python
pdf_tasks = [
    ("https://xxx.xxx.co.jp/xxx01", "pdf01.pdf"),
    ("https://xxx.xxx.co.jp/xxx02", "pdf02.pdf"),
]
```

上記リストを使用して`save_as_pdf`を呼び出します。処理完了後、S3バケットにPDFファイルが取得されます。
```python
for url, output_filename in pdf_tasks:
    asyncio.run(save_as_pdf(url, output_filename))
```

# ベクトルDBへの同期

上記S3に取得したPDFのデータをベクトルDBに同期します。実行結果のログ保存ディレクトリを`log_dir`に指定します。`knowledgeBaseId`と`dataSourceId`に対象のナレッジベースIDおよびデータソースIDを指定します。これらの設定内容を元にBedrockのAPIにアクセスして同期処理を行います。

```python:sync_pdf.py
import boto3
import json
from datetime import datetime

log_dir = "/***/***/log"

timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
log_file = f"{log_dir}/ingestion_response_{timestamp}.log"

client = boto3.client('bedrock-agent', region_name="ap-northeast-1")
response = client.start_ingestion_job(
    knowledgeBaseId='******',
    dataSourceId='******'
)

```

下記は実行結果を受け取ってログを出力する処理の例です。

```python
def convert_datetime(obj):
    if isinstance(obj, datetime):
        return obj.isoformat()
    raise TypeError("Type not serializable")

with open(log_file, 'w') as f:
    json.dump(response, f, indent=2, default=convert_datetime)

```

# cronの設定
`crontab`を編集して、上記スクリプトの自動実行設定を追加します。下記は毎日20:00に`getpdf.py`を実行し、毎日20:10に`syncpdf.py`を実行する例です。

```shell
00 20 * * * python3 /root/getpdf.py
10 20 * * * python3 /root/syncpdf.py
```
VSCodeでの3段以上のソースを移動させるテクニック (移動先の空フォルダを用意しておく)

# Windows の VSCode ファイルをまとめて移動

Next.jsでApp routerなどを使っていると、
VSCodeは importのLinkを自動で追跡してくれます。
2段だと問題なく移動できますが
3段以上だと移動に長く時間がかかったり失敗したりします。

例えば、
Next.jsのプロジェクトで`src`フォルダの無いリポジトリだったり、i18nの機能を追加したい場合の時など[locale]フォルダを間に入れたい場合

深い階層をまとめて移動させたい場合に以前はエクスプローラーを立ち上げて、そこでファイルを移動させてから、VSCodeに戻り手動でリンクを張り直していました。

* 移動テクニック
このテクニックは**移動先の空フォルダを用意**しておき、
その後末端のフォルダやファイルを2段ごとに「少しづつ」移動させるとVSCodeはリンクを自動で張り直してくれます。
1つづつファイルだけ移動させても大丈夫です。

## 例

👇️元のフォルダ構造

```
src
├── app
│   ├── (auth)
│   │   └── (admin)

```

👇️[locale]フォルダを間に入れたい
その下に空のフォルダを用意しておく

```
src
├── app
│   ├── [locale]
│   │   ├── (auth)
│   │   │   └── (admin)

```


```
src
├── app
│   ├── (auth)
│   │   ├── (admin)
│   │   │   ├── analytics  (移動前)
│   │   │   ├── dashboard  (移動前)
│   │   │   ├── settings  (移動前)
│   │   │   └── users  (移動前)
│   │   └── protected
│   │       └── page.tsx
│   ├── [locale]
│   │   ├── (auth)
│   │   │   └── (admin)
│   │   │       ├── analytics  (移動後)
│   │   │       ├── dashboard  (移動後)
│   │   │       ├── settings  (移動後)
│   │   │       └── users  (移動後)

```

👆️ (admin)フォルダ をまとめて一気に移動させても大丈夫です。
importのLinkも自動で貼り直してくれます。


### 空フォルダ構造の(強引な)作り方

特定フォルダ以下を別の場所にコピーして、ファイルだけを削除すると出来ます。

具体的には、
「Everyting」などのファイル操作ツールを使ってフォルダを指定します。
そうするとその下のフォルダとファイルの一覧が表示されるのでファイルだけ消します。

CLIのコマンドでフォルダだけコピーXCOPYとかありそうですが調べてません。

# 感想

国際化はできるだけ早くやるべきでした。

AIのMCP(ファイル操作系のMCP等)を使うことで「AIによるファイル操作」が可能になりましたので、これからはチャットで指示するだけで出来るようになります。
SortedContainersの計算量まとめ

# はじめに
SortedContainersのデータ構造たちは内部に`_load`という値を持っており、この値に計算量が依存します。この記事ではその値を$M$、要素数を$N$として話を進めます。
また、挿入する要素同士の比較は$O(1)$で可能なものとします。

# SortedList
常にソートされた配列です。
他言語ではmultisetと呼ばれるかもしれません。
|操作  |償却計算量|$ M = \sqrt[3]{N}$の場合[^4]|
|---|---|---|
|add  | $O(\log(N) + M + \frac{N}{M^2}  )$ | $O(\sqrt[3]{N})$|
|discard| $O(\log(N) + M + \frac{N}{M^2}  )$ |$O(\sqrt[3]{N})$|
|pop|$O(\log(N)) + M + \frac{N}{M^2}  )$ |$O(\sqrt[3]{N})$|
|getitem(一般)|$O(\log(\frac{N}{M}))$ [^1]|$O(\log{N})$|
|getitem(先頭、末尾のバケット)|$O(1)$|$O(1)$|
|contains|$O(\log(N))$|$O(\log(N))$|
|bisect_left|$O(\log(N))$|$O(\log(N))$|
|bisect_right|$O(\log(N))$|$O(\log(N))$|
|count|$O(\log(N))$|$O(\log(N))$|
|index|$O(\log(N))$|$O(\log(N))$|
|remove|$O(\log(N) + M + \frac{N}{M^2}  )$ |$O(\sqrt[3]{N})$|
|del  |$O(\log(N) + M + \frac{N}{M^2}  )$ |$O(\sqrt[3]{N})$|
|clear|$O(1)$[^2]|$O(1)$|
|update$(4K \geq N)$|$O(K\log(K))$|$O(K\log(K))$|
|update$(4K \lt N)$|$O(K(\log(N) + M + \frac{N}{M^2})  )$ | $O(K\sqrt[3]{N})$|

[^1]: 実際には最悪で$O(\frac{N}{M})$かかりますが、addやpop時の計算量で償却可能。
[^2]: 実際には$O(N)$かかりますが、追加の際の計算量で償却可能。

# SortedSet
重複しない版のSortedListです。
内部にpythonのsetを持っているため、ハッシュ化できないオブジェクトの挿入やハッシュの衝突回避目的には利用できません。

|操作  |平均計算量|$ M = \sqrt[3]{N}$の場合[^4]|最悪計算量|
|---|---|---|---|
|add(存在しない要素) | $O(\log(N) + M + \frac{N}{M^2}  )$ | $O(\sqrt[3]{N})$|$O(N)$[^5]|
|add(存在する要素) | $O(1)$ | $O(1)$|$O(N)$[^5]|
|discard(存在しない要素)| $O(1)$ |$O(1)$|$O(N)$[^5]|
|discard(存在する要素)| $O(\log(N) + M + \frac{N}{M^2}  )$ |$O(\sqrt[3]{N})$|$O(N)$[^5]|
|pop|$O(\log(N)) + M + \frac{N}{M^2}  )$ |$O(\sqrt[3]{N})$|$O(N)$[^5]|
|getitem(一般)|$O(\log(\frac{N}{M}))$|$O(\log{N})$|$O(\frac{N}{M})$ [^3] |
|getitem(先頭、末尾のバケット)|$O(1)$|$O(1)$|$O(1)$|
|contains|$O(1)$|$O(1)$|$O(N)$[^5]|
|bisect_left|$O(\log(N))$|$O(\log(N))$|$O(\log(N))$|
|bisect_right|$O(\log(N))$|$O(\log(N))$|$O(\log(N))$|
|count|$O(\log(N))$|$O(\log(N))$|$O(\log(N))$|
|index|$O(\log(N))$|$O(\log(N))$|$O(\log(N))$|
|remove|$O(\log(N) + M + \frac{N}{M^2}  )$ |$O(\sqrt[3]{N})$|$O(N)$[^5]|
|del  |$O(\log(N) + M + \frac{N}{M^2}  )$ |$O(\sqrt[3]{N})$|$O(N)$[^5]|
|clear|$O(N)$|$O(N)$|$O(N)$|　
|update$(4K \geq N)$|$O(K\log(K))$|$O(K\log(K))$|$O(KN)$[^5] |
|update$(4K \lt N)$|$O(K(\log(N) + M + \frac{N}{M^2})  )$ | $O(K\sqrt[3]{N})$|$O(KN)$[^5]|





[^3]: 実際にはaddやpopなどの計算量で償却されるのでボトルネックにはならない。

[^4]: _loadの値を実際に$ \sqrt[3]{N} $と設定するのが、実行時間的に最速とは限りません。

[^5]: pythonのsetについて、ハッシュの衝突時ｎ各操作の最悪計算量が$O(N)$となることが原因でこの計算量となっています。

# リンク(参考文献)
Sorted Containers ( GitHub )
https://github.com/grantjenks/python-sortedcontainers/tree/master

Performance at Scale
https://grantjenks.com/docs/sortedcontainers/performance-scale.html
アーキテクトやコンサルタントの視点においてセキュリティ(DevOpsSec)に関する口出しや選定について悩ましい話

# なにこれ
ワイの悩み
最近いろんなところでシニアとして、またはそういう役割として助言を求められるから考え方を書いておく。

# 私の考え方の前提として
何かを使うという観点において、
一般的な商用車しか必要としてないところにF1カーを押し付けても、
コスト・使い勝手等から見合わなかったりそもそも運用できるのかレベルで無理筋なことになる。

走行前にタイヤだのオイルだの温めたりする必要がある車で営業にいくとか、５００ｋｍ走るごとに高い消耗品の交換が待っているとか。（もうちょっと距離は長いけれどそういう市販車は存在する）

そういうのはそりゃお客さんのもとに最速でたどり着けるという目的だけは達成しているけど、ほかがすべてアカン。

トータルで見れば損していることになるので、身の丈にあった技術やサービスをチョイスしていく必要があると考えます。

# 具体の話

ここのところDev(開発)とOps(運用)については、必須レベルのところは対してコストの差はなくなってきたと思います、が、Sec(セキュリティ)についてはまだ未知で青天井のところがあって、たとえば下記。

* WAFに年数百万円から一千万円かけられますか？
* ソースコードのチェックツール、構成管理ツールに年５００万以上かかるけどいいですか？
* 運用監視にセキュリティ系のログチェックツールかますけどすっごいお金かかりますいいですか？

**そのお金出せるサービスってECの大手か金融とかしかないよね・・。**

だいたいはクラウドが用意するWAFを適切に運用することで事足りるし、ソースコードのチェック等は人依存のところもあるけど、サービスイン時に脆弱性検査にお金をかけることでエビデンスとしているところがほとんどで、リアルタイムのセキュリティ監視とかなかなかえぐいもん使ってるところないわけではないけどないわーです。

また、取り組みとしてのSecは支持するものの、専門家に話を聞くだけでもめんどくさいお金発生するし、シャープな助言するところにはあまり遭遇したことはない。

ざっくり今やべーなと思う点についてひとつだけ。

アプリケーションエンジニアについてAPIやバックエンドの設計、実装、テストを適切に行う教育は最初にやっといていいと思いますけどね・・一度地雷踏んで学んだエンジニアは自然とできるようになるけど、一般教養としてはなかなかやってないですよね・・

# 現時点のスタンス

Sec関連の施策は費用対効果重視＆観点として持つくらいでええんちゃうかなと思います。

私はセキュリティの専門家ではなくて・・
それなりに場数は踏んでいて知見を共有することはできるけど、専門家を雇ったほうがいいよという助言をすることにします。
【読書メモ】できるリーダーは「これ」しかやらない_1章のまとめ

# はじめに
　私は、4月から管理職として働くことになりました。
　高校・大学時代に部活動の主将としてチームを率いた経験はありましたが、
　リーダーシップについて改めて体系的に学ぶ必要性を感じました。
　そこで、[「できるリーダーは「これ」しかやらない」（伊庭正康著）](https://www.amazon.co.jp/%E3%81%A7%E3%81%8D%E3%82%8B%E3%83%AA%E3%83%BC%E3%83%80%E3%83%BC%E3%81%AF%E3%80%81%E3%80%8C%E3%81%93%E3%82%8C%E3%80%8D%E3%81%97%E3%81%8B%E3%82%84%E3%82%89%E3%81%AA%E3%81%84-%E3%83%A1%E3%83%B3%E3%83%90%E3%83%BC%E3%81%8C%E8%87%AA%E3%82%89%E5%8B%95%E3%81%8D%E5%87%BA%E3%81%99%E3%80%8C%E4%BB%BB%E3%81%9B%E6%96%B9%E3%80%8D%E3%81%AE%E3%82%B3%E3%83%84-%E4%BC%8A%E5%BA%AD%E6%AD%A3%E5%BA%B7/dp/4569842372/ref=asc_df_4569842372?mcid=bd8b3523904c37c297f9422ef2892a5c&tag=jpgo-22&linkCode=df0&hvadid=707442440616&hvpos=&hvnetw=g&hvrand=7694447405697479056&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1009540&hvtargid=pla-635986291142&psc=1&gad_source=1)という書籍を
　手に取り、学習を進めています。
　
　本書はリーダーとして成果を出すために必要な考え方や具体的な行動について
　豊富な事例とともに解説しています。
　特に、メンバーの主体性を引き出し、チーム全体のパフォーマンスを最大化するための
　リーダーの役割に焦点を当てている点が印象的でした。
　
　本記事では、本書で紹介されている内容の中から、私が実際に業務で活用できそうだと
　思った部分や、共感した考え方についてまとめます。
　リーダーシップについて学び始めたばかりの私にとって、本書は多くの示唆を与えてくれました。
　読者の皆様にとっても、日々の業務やチーム運営の参考になれば幸いです。

# 「厳しく伝える」のではなく、「丁寧に伝える」
　近年、本人のためを思って叱ったことや、指導したことがパワハラになりうる時代です。 
　ただ気を付けないこといけないことは、その時代の風潮に過剰反応してしまい、
　部下の言動に対してなにも言えなくなることです。
　
　本書では部下へのアプローチを変える必要があると記載されていました。
　「厳しく伝える」のではなく「丁寧に伝える」というアプローチです。
　
　具体的な方法は以下です。
　・なぜ、その業務をするのかを伝える
　・具体的に、どうやればよいのか手順を伝える
　・その指示を聞いて、どう思ったかを確認する
　・不安な点、不明な点がないか確認する
　・その後も定期的に確認の場を設ける
　
　丁寧に教えるだけでなく、確認をするという部分は読んでいて勉強になりました。
　実際に部下の仕事を教える際は上記を意識しようと思います。

# 部下を成長させるには
　部下が成長するには**自己決定感**が重要になります。
　自己決定感とは「自分がそれを決めた」という感覚のことです。
　
　自己決定感が高いと失敗をしても次に活かすことができます。
　この自己決定感を誘導するセリフが「で、どうしますか？」というセリフです。
　このセリフにより次にする行動を自分で決めることで、責任感を持ち、
　積極的に行動できると思いました。
　
　たとえば部下がミスした場合でも、成長の機会ととらえ、
　「ミスは次に活かせばいいです。で、どうしますか？」と次の行動をどうするかを
　考えさせるようにしたいと思います。

# 新人に教えておくべきこと
　新人は学生気分が抜けず、社会人としてのマインドセットができていないまま
　社会にデビューする人もいると思います。私自身もそうでした。
　
　本書では新人に教えておくべきたった一つのこととして
　**すべてのことを相手軸で想像してみてほしい**と記載されていました。
　上記を明確に伝えて、都度、フィードバックすることも大事とも記載されていました。
 
　確かに、相手のことを考えて行動することはとても重要で
　私もお客様に資料で説明する際に、使用する言葉をお客様が普段使う
　業務用語に置き換えて説明したり、専門用語に関しては注釈を挿入したりすることで
　お客様との会話がスムーズになり「私たちにわかりやすく説明してくれている」との
　お言葉を頂いたこともあったので、相手軸ですべてのことを考えるようにすることは
　新人や部下に伝えていきたいと感じました。

# 最後に
　今回は1章についてまとめさせていただきました。
　引き続き2章について、業務で活用できそうだと思った部分や、共感した考え方について
　まとめたいと思います。
　私と同じように管理職になったばかりの方や、管理職で悩んでいる方の
　お役に立つことができれば幸いです。
【Rails初学者】RailsでPostgreSQLにTablePlus接続する方法をやってみました

# RailsでPostgreSQLにTablePlus接続する

こんにちは。
rails初学者です。
この記事では、**Rails**アプリケーションで使用している**PostgreSQL**データベースに、黒い画面にコマンドを打たずに、画面のボタンやフォームで操作できるツールの**TablePlus**を使って接続する手順を忘れないようにまとめたものになります。

---

## TablePlusとは？【Rails開発におすすめのツールらしい】

TablePlusは、**PostgreSQL**や**MySQL**、**SQLite**などに対応した、**高速・軽量なGUIデータベースクライアント**だそうです。

ターミナル操作なしでデータベースを確認・編集できるため、  
**Railsアプリ開発**でも非常に重宝されるようです。

---

## RailsでTablePlusからPostgreSQLに接続する方法

### ① TablePlusをインストールする

公式サイト（[https://tableplus.com/](https://tableplus.com/)）からダウンロードしてインストールします。  
無料プランでも基本的な機能は十分使えます。

---

### ② PostgreSQL接続情報を入力して新しいコネクションを作成する

TablePlusを起動後、「Create a new connection」→「PostgreSQL」を選択します。

以下の情報を入力します。

| 項目       | 入力内容                        |
|------------|---------------------------------|
| Name       | 任意（例：`MyApp DB`など）    |
| Host       | `localhost`                    |
| Port       | `5432`（デフォルト）            |
| User       | ログインするPostgreSQLユーザー名（例：`user_name`） |
| Password   | 設定していない場合は空白のまま |
| Database   | Railsプロジェクトのdevelopment用DB名（例：`myapp_development`） |

設定が完了したら、「Connect」をクリックして接続します。

---

## よくあるエラーとその対処法【Rails×TablePlus】

- **User名・Database名のミスに気をつける**  
  `config/database.yml` の `development`セクションに記載された名前と一致させます。

- **PostgreSQLサーバーが起動しているか確認します**  
  macOSなら以下のコマンドで確認できます。

  ```bash
  brew services list
  ```

  `postgresql` のステータスが `started` になっていればOKです。

- **パスワード設定がある場合は、忘れずTablePlus側にも入力します**

---

## まとめ
TablePlusを使えば、Railsアプリのデータベース操作が快適に行える。
特に、SQLに不慣れな私のような初学者でも、視覚的にテーブルやデータを操作できるのが大きなメリットだそうです。

---

初学者のため、間違えていたらすいません。
引き続き、学習を進めていきまs
[初心者]Git GitHubについて・環境構築

学校のチーム開発授業でメンバーに使うことを想定した記事です。
Git GitHubに全く触れたことのない人向けに概要と環境構築の方法をまとめました。

# リポジトリ（repository）とは
簡単に言うと「**プロジェクトのデータを保存しておく場所**」です。

- ソースコード
- 画像や設定ファイル
- 更新履歴（どこを、誰が、いつ変更したか）

これらをまとめて管理できるものがリポジトリです。
リポジトリには、自分のパソコンの中に作る「**ローカルリポジトリ**」と、
GitHubなどのクラウド上に置く「**リモートリポジトリ**」があります。

# Git
Gitはリポジトリを管理するための「**バージョン管理ツール**」です。

- ファイルの変更履歴を記録できる
- 必要な場合、昔の状態に戻せる（バージョンダウン）
- チームで開発するときに、誰が何を変えたかわかる

というように、バージョン管理する上で超便利なツールです。

# GitHub
GitHubはGitのリモートリポジトリ（インターネット上のリポジトリ）を管理できるサービス。

- 自分のパソコンだけじゃなく、ネット上にリポジトリを置ける
- それを使って違うパソコンから開発したり、チームで共有して開発ができる。

というもの、さらに…

- コードレビューの依頼（プルリクエスト）
- やることリストの管理（issue）
- CI・CDの実装（Actions）
<br>
など、開発をスムーズにする機能がいっぱいあります。

# Git・GitHubの環境構築をしよう
1.  **Gitをインストール**<br>
    →パソコンにGitを入れる<br>
     **WIndowsの場合** <br>
    公式サイトからインストーラーをダウンロードして実行

     **Macの場合**
    - ターミナルを開いて、以下コマンドを打つ
    ```bash:bash
    git --version
    ```
    - 入ってなければ、Xcodeのコマンドラインツールのインストール案内が出るので、それに従ってインストールする
    
2. **GitHubのアカウント作成**
    →GitHubにアクセスしてアカウントを作る
    <br>
3. **Gitの初期設定**
    →名前とメールアドレスを設定（GitHubのアカウントと合わせるのがおすすめ）
    ```bash:bash
    git config --global user.name "あなたの名前"
    git config --global user.email "あなたのメールアドレス"
    ```
    **設定の確認**
    ```bash:bash
    git config --global --list
    ```

    ここまでの設定ができたら、一通りの動作はできるようになります。
<br>

4. **SSH接続の設定**
    セキュリティなどの面から設定することをおすすめしますが、やらなくてもGit・GitHubは使えます。
    1. SSHキーを作成
        ```bash:bash
            ssh-keygen -t rsa
        ```
        →何か聞かれても基本Enter連打でOK
        <br>
    2. 公開鍵をGitHubに登録する
        GitHubにアクセスし、自身のアカウントでログインし設定画面を開いてください。
        ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4073103/8879fe23-4ba7-4080-9e6c-7d6e52774497.png)
        SSH and GPG keysをクリックし、
        ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4073103/0aa20fe1-8c7f-4aa5-8092-021edb3ce604.png)
        New SSH keyをクリック
        ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4073103/83c5ba45-dad6-42a5-ba73-fea244ca7caa.png)
        「Title」に鍵の名前、「Key」に公開鍵を入力します。
        <br>
        **接続の確認**
        ```bash:bash
        ssh -T git@github.com
        ```
        「Hi 〇〇! You've successfully authenticated」と出れば成功です！

# まとめ
今回は初心者向けにGitとGitHubについてと環境構築についてまとめました。一度きちんと設定しておけば、今後の開発がとてもスムーズになります。最初は少し面倒に感じるかもしれませんが、開発効率が上がるだけでなく、導入している企業もたくさんあると思いますので仕事にも役立ちます。ぜひこの機会に登録と設定をしてみましょう！
<br>
次回はGitとGitHubを使っていくために基本的なコマンドについてまとめようと思います。
GitHub ActionsでOIDCを使うときは、id_tokenの書き込み権限をつけましょう

# やりたいこと
GitHub Actionsのワークフロー内でOIDCを利用し、AWS側で作成したIAMロールをAssumeする

# 現象
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3679074/3e1c637f-e604-4be9-9bed-d8cdc92b0c12.png)

`It looks like...`のメッセージと共にクレデンシャルをの取得に失敗した旨のエラーが表示される。

## 確認したこと
- あらかじめ登録している`Secrets`や`Variables`の値は間違い無い
- AWS側でのOIDCプロバイダも作成済
- GitHub ActionsがAssumeするロールの信頼ポリシーで対象リポジトリを信頼している

# 修正前のコード

```yaml
name: AWS OIDC

on:
  push:

jobs:
  job1:
    runs-on: ubuntu-latest
    steps:
      - name: Set Environment Values
        run: |
            echo "AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID }}" >> $GITHUB_ENV
            echo "AWS_CICD_ROLE_NAME=${{ secrets.AWS_CICD_ROLE_NAME }}" >> $GITHUB_ENV
            echo "AWS_REGION=${{ secrets.AWS_REGION }}" >> $GITHUB_ENV
      - name: Get AWS Temporary Credential
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-region: '${{ env.AWS_REGION }}'
          role-to-assume: 'arn:aws:iam::${{ env.AWS_ACCOUNT_ID }}:role/${{ env.AWS_CICD_ROLE_NAME }}'

```
※regionもsecretsで登録しているのは気にしないでください

# 原因

```
It looks like you might be trying to authenticate with OIDC. Did you mean to set the `id-token` permission? If you are not trying to authenticate with OIDC and the action is working successfully, you can ignore this message.
```
というメッセージの通り、`id-token`のパーミッションが設定されていないのが原因。
以下の通り、GitHub Actionsのデフォルト設定だと、`id-token`の書き込み権限が**無効**になっている。

> If you don't specify permissions, the GITHUB_TOKEN only has read access to the contents and metadata of the repository.
Other scopes, such as id-token, are not granted unless explicitly requested.

https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions

そのため、`aws-actions/configure-aws-credentials`の実行の中で必要な**GitHubから発行されるOIDCトークン**が発行できずエラーになった。


# 修正後のコード

```diff_yaml
name: AWS OIDC

on:
  push:

+ permissions:
+   id-token: write

jobs:
  job1:
    runs-on: ubuntu-latest
    steps:
      - name: Set Environment Values
        run: |
            echo "AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID }}" >> $GITHUB_ENV
            echo "AWS_CICD_ROLE_NAME=${{ secrets.AWS_CICD_ROLE_NAME }}" >> $GITHUB_ENV
            echo "AWS_REGION=${{ secrets.AWS_REGION }}" >> $GITHUB_ENV
      - name: Get AWS Temporary Credential
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-region: '${{ env.AWS_REGION }}'
          role-to-assume: 'arn:aws:iam::${{ env.AWS_ACCOUNT_ID }}:role/${{ env.AWS_CICD_ROLE_NAME }}'

```


# まとめ
GitHub ActionsでOIDCを使うときは、id_tokenの書き込み権限をつけよう
static class でコルーチンを実行する邪悪なコード

一種の**ネタコード**として、  
`static class` でコルーチンを実行する方法を紹介してみたいと思います。

***

## 紹介するコード

```csharp:static class でコルーチンを実行する邪悪なコード
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;

public static class CommonScript
{
    private static CommonScriptBootstrapper coroutineRunner;

    public class CommonScriptBootstrapper : MonoBehaviour
    {
        void Awake()
        {
            CommonScript.SetRunner(this);

            // シーンアンロードイベント登録
            SceneManager.sceneUnloaded += OnSceneUnloaded;
        }

        void OnDestroy()
        {
            // イベント解除（メモリリーク防止）
            SceneManager.sceneUnloaded -= OnSceneUnloaded;
        }

        private void OnSceneUnloaded(Scene scene)
        {
            // シーンがアンロードされたら、実行中のコルーチンを停止
            StopAllCoroutines();
        }
    }

    static CommonScript()
    {
        SceneManager.sceneLoaded += (scene, mode) =>
        {
            SetupBootstrapper();
        };
        SetupBootstrapper();
    }

    private static void SetupBootstrapper()
    {
        GameObject go = GameObject.Find("CommonScriptBootstrapper");
        if (go == null)
        {
            go = new GameObject("CommonScriptBootstrapper");
            go.AddComponent<CommonScriptBootstrapper>();
            GameObject.DontDestroyOnLoad(go);
        }
    }

    public static void SetRunner(CommonScriptBootstrapper runner)
    {
        coroutineRunner = runner;
    }

    //以下に static メソッドを記述
    //coroutineRunner?.StartCoroutine でコルーチンを実行可能

    public static void ExecCoroutine()
    {
        coroutineRunner?.StartCoroutine(CoroutineMethod());
    }

    private static IEnumerator CoroutineMethod()
    {
        Debug.Log("time: " + 1);
        yield return new WaitForSeconds(5);
        Debug.Log("time: " + 2);
        yield return new WaitForSeconds(5);
        Debug.Log("time: " + 3);
        yield return new WaitForSeconds(5);
        Debug.Log("time: " + 4);
    }

    //実行元が MonoBehaviour で
    //実行元と一蓮托生の場合はこの方法でコルーチンを生成するべきである。
    public static void ExecCoroutineDefailt(MonoBehaviour rootMono)
    {
        rootMono.StartCoroutine(CoroutineMethod());
    }
}
```

***

## コードの解説

- **GameObjectの生成**  
  `CommonScriptBootstrapper` という名前の GameObject を動的に生成し、  
  `MonoBehaviour` を継承した `CommonScriptBootstrapper` をアタッチしています。

- **コルーチン実行用ランナーの確保**  
  作成したオブジェクトによって、`static` なスコープでもコルーチン (`StartCoroutine`) の呼び出しが可能になります。

- **クラス分割について**  
  コメントで区切るだけでなく、`CommonScriptBootstrapper` を別ファイルに切り出すのも良いでしょう。  
  責任の分離が明確になります。

***

## 注意点

本来、コルーチンは `MonoBehaviour` を継承したインスタンスから実行するのが自然です。  
この手法はあくまで**邪悪な裏技**であり、  
**本番運用する際は十分注意が必要**です。

どうしても `static class` からコルーチンを実行したい場合に、  
参考程度にしていただければと思います。

***

## 最後に

この記事が皆さんにとって  
ちょっとしたネタやアイデアの種になれば幸いです。

ご覧いただき、ありがとうございました！

***

## 追記

文章を作成した後に
ChatGPT で文章を添削しています。

文章の添削に生成 AI を使用する事が
苦手な方は、申し訳ありませんがご容赦頂けるよう
よろしくお願いします。
新しい技術/ソフトも利用して行った方が良い理由

# 新しい技術/ソフトも利用して行った方が良い理由

移行 発展の三視点から行きます。

## 1.移行
もしサービスを運用している時 ハードが壊れて新しい機器にするときに元々動かしてたソフトが古すぎて新しい環境に対応できなかったら...? 修正はどんな期間になりますか?
更新は、大変でしょ？　

## 2.発展
運用しているサービスを引き継ぐときに発展させる時　あとから来た人たちが知らないような言語　作りしてたら....?

ry
初心者がIT学習を続けるためのモチベーション維持法💻📚✨


みなさん、こんにちは韓国在住のsanaです！

今週も一週間やってきましたね！　韓国は今週末連休なんですが日本もGWですね:sparkles:
もしかしたら、もう連休休み入っている方もいらっしゃいますよね！！


私自身IT初心者の状態でIT関連の企業に就職し、わからないことだらけで勉強の日々が続いています:droplet:

そんな私がIT学習を始めてからそして今現在もモチベーション維持するために心がけていたことをいくつか紹介したいと思います！


 :one: 小さな目標を設定する:star:
 
学習を始めたばかりの頃から、プログラミング習得してゲーム制作する！ のように大きな目標を掲げても挫折しやすいです。1日1章を勉強する、1つのプログラムを1時間で作る、など小さい目標を設定することで、少しずつ達成感を感じられ、また目標達成することで自信がつき、モチベーションが維持しやすくなります！:smiley:


:two: 学んだ内容を誰かに教える:writing_hand:

「教えることで学べる」という言葉があるように、自分が学んだことを誰かに説明してみることがモチベーション維持に繋がります。学んだことを人に伝えることは、自分の理解度を深めるだけでなく、やり遂げたという満足感も得られます！　進歩を目に見える形にすることも学習するうえで大事ですよね！ それこそQiitaに習得した知識を記事にすることも一つの手段だと思います:point_up_tone1:

:three: 他の初心者と交流する:sunglasses:

同じように学んでいる人たちとオンラインで繋がることで、お互いに励まし合いや情報共有ができ、モチベーションが維持しやすくなります。日本はどうなのかわかりませんが、韓国には学習者が集まるコミュニティーがたくさんあって私も参加したことがあるのですが、SNSやオンラインフォーラム、学習グループなどに参加することで、仲間ができ、孤独感を感じずに学べます:ok_woman_tone1:


:four: 自分のペースで学ぶことを大切にする:smiley_cat:

一番基本的ですが一番大切だと思っているので一番最後に紹介しました！

他の人と比較して焦ることなく、自分のペースで学習を続けることが重要です。IT学習は誰かと競争するものではなく自分のスキルアップのための学習だと思っているので、特に初心者の方は最初は時間がかかることもありますが、焦らず自分のペースで学んでいくことが長続きのコツです。:shamrock:



今日はモチベーション維持法について紹介しましたが新しくIT学習を始める方だけでなく、最近やる気が落ちてきたという方にも役に立てばいいなと思います:relaxed:

今週も一週間頑張りましょう!! ファイティン:v_tone1:
Reactの最新のActivityコンポーネントは便利すぎる！

Reactが初めて登場したとき、開発者はそのUIの状態管理のシンプルさに感動しました。しかしアプリケーションが複雑になるにつれ、コンポーネントの表示・非表示を管理しながら状態やパフォーマンスを維持するのは思ったより難しいことに気付きました。従来はCSSでの非表示切り替えや、コンポーネントを完全にアンマウントする方法に頼っていましたが、どちらにも欠点がありました。

そこでReactチームがこの課題に着目し、新たに実験的な超便利機能 `<Activity>` を発表しました！このコンポーネントは表示の切り替えを簡単にしつつ、状態やパフォーマンスも維持できる優れものです。`<Activity mode="hidden">`を使うと、Reactはコンポーネントをアンマウントしつつ状態を保存し、バックグラウンドで低い優先度でレンダリングを続けます。一方、`<Activity mode="visible">`は通常通りのレンダリングを行います。

よくあるシナリオを考えてみましょう。別のページに移動するとき、以前はユーザーが入力した情報や状態がすべて消えてしまいました。せっかくフォームに入力したのに、一度別ページに行くと戻ったときにはすべてがリセットされる…そんなイライラ、ありますよね？

これまでの典型的なコード例はこうでした：

```jsx
function App() {
  const { url } = useRouter();

  return (
    <>
      {url === '/' && <Home />}
      {url !== '/' && <SubPage />}
    </>
  );
}
```

残念ながら、この方法では`<Home />`から離れるとすぐに状態が失われます。ところが新しい`<Activity>`を使えば全てが解決します！

```jsx
function App() {
  const { url } = useRouter();

  return (
    <>
      <Activity mode={url === '/' ? 'visible' : 'hidden'}>
        <Home />
      </Activity>
      {url !== '/' && <SubPage />}
    </>
  );
}
```

この変更で、一度ページを離れても入力状態はそのまま保持され、スムーズで直感的なユーザー体験を提供します。

さらにすごいのは、Reactの新機能`<Activity>`がユーザーの次の行動を先読みして、事前にコンポーネントをレンダリングしておける点です。例えば、詳細ページに移動する際に通常はデータ取得のため待ち時間が発生しますが、`<Activity>`を使うとユーザーがクリックする前に裏でレンダリングし、データを準備しておくことができます。

```jsx
export default function App() {
  const { url } = useRouter();
  const pictureId = url.split('/').pop();

  const [pictures, setPictures] = useState([]);

  useEffect(() => {
    async function loadPictures() {
      const imgs = await getPictures();
      setPictures(imgs);
    }
    loadPictures();
  }, []);

  return (
    <ViewTransition>
    {pictures.map(({id}) => (
        <Activity key={id} mode={pictureId === id ? 'visible' : 'hidden'}>
        <PictureDetails id={id}/>
        </Activity>
    ))}
    <Activity mode={url === '/' ? 'visible' : 'hidden'}>
        <Home />
    </Activity>
    </ViewTransition>
  );
}

```

これにより、ユーザーが画像を選択するときに待ち時間がほぼなくなり、プロ並みの滑らかな体験が実現できます。

さらに将来的には、モーダル表示やバックグラウンドでの更新停止、メモリ管理まで幅広く対応するモードも計画中とのこと。これからのReact開発には欠かせない存在になりそうです。

Reactが提供する新たな`<Activity>`を使えば、UI開発はもっと楽しく簡単に、そしてユーザー体験も劇的に向上します。これからのReact開発者必見の機能、ぜひ試してみてください！

※この記事執筆時点では APIは実験的な機能であり、安定版のReactにはまだ含まれていません。試すにはReactパッケージを最新のexperimentalバージョンにアップグレードしてください。
MacOSでntfs formatドライブへの書き込み

# MacでのNTFSは読み込みのみ？
昔使用していたiMacでは、NTFSの読み込みに、ntfs-3gを利用していたのだが、現在のsequoiaでは動作しないらしい。

M1 MBPを使用していたときは、そもそもNTFSのディスク（USBやSSD）を使用した記憶がなかったので、気にしていなかった。（記憶ではntfs-3g＋Mounty）

M4 MBPに変えてからNTFSのSSDを利用しようとしたら、読み込めるものの書き込みができない…(泣)

ググっても、NTFS対応した製品を買って動作させたという記事、PR記事ばかり。
- iBoysoft NTFS for Mac
- EaseUS NTFS for Mac
- Tuxera NTFS for Mac
などなど

欲しいのは、そうじゃないんだ…。
製品であれば動くだろうけど、Macのアップグレードで動かなくなったり、買い直しするのもバカバカしいし…。

でもきっと方法はあるはず…。

そこで試行錯誤し、なんとか動作させることができたので、記録しておく。
## 必要なのはmacFuseとntfs-3g-mac

それぞれ、brewでinstallしておいてください。
この辺りが参考になるはずです。
> https://zenn.dev/at_yasu/articles/how-to-use-ntfs-at-mac

でもって、スクリプトを作成したので、ntfs_mount.shとでも名前をつけて保存し、実行できるようにパーミッションを変更します。
　僕は、scriptとかbinフォルダをホーム内に作成し、そこに置いてます。
（もちろんPATHも通してください）

```
% chmod +x ~/bin/ntfs_mount.sh
```

一旦、NTFSでフォーマットされたSSDなどを差し込みます。
もちろん、読み込みは可能ですが、書き込みができません。

そこで、スクリプトを実行します。

```
% sudo ntfs_mount.sh
Successfully mounted /dev/disk6s1 to /Volumes/ntfs.
```
のように出力すればOK完了。
これで、NTFSのディスクに読み書きが可能になります。


## 現時点での問題点

- 複数のNTFSディスクを使用するということがないので、考慮していません。
最初に見つけたntfsディスクを読み書き可能に再設定します。
　mount pointを/Volumes/ntfsに固定しているので、この辺りを細工すれば複数ディスクでも動くはずです。

```shell
#!/bin/bash

# This script mounts an NTFS device to a specified mount point on macOS.
# It first unmounts the device if it is already mounted, then creates the mount point
# if it does not exist, and finally mounts the device to the mount point.
# Usage: sudo ./ntfs_mount.sh

MOUNTPOINT="/Volumes/ntfs"

# Check if the script is run with root privileges
if [ "$EUID" -ne 0 ]; then
    echo "Please run as root"
    exit 1
fi

# Check ntfs usb device
DEVICE=$(mount | grep "(ntfs, local" | awk '{print $1}')
if [ -z "$DEVICE" ]; then
    echo "No NTFS device found."
    exit 1
fi

# umount
umount $DEVICE
if [ $? -ne 0 ]; then
    echo "Failed to unmount $DEVICE."
    exit 1
fi

# make mount point
mkdir $MOUNTPOINT
if [ $? -ne 0 ]; then
    echo "Failed to create $MOUNTPOINT."
    exit 1
fi

# mount
sudo mount_ntfs -o noappledouble $DEVICE $MOUNTPOINT
if [ $? -ne 0 ]; then
    echo "Failed to mount $DEVICE to $MOUNTPOINT."
    exit 1
fi

# output success message
echo "Successfully mounted $DEVICE to $MOUNTPOINT."
```

以上が、スクリプトの内容です。

苦労した甲斐があった！
containerInsightsDCGMExporterScraperやcontainerInsightsNeuronMonitorScraperの収集を停止する

EKSアドオンのAmazon CloudWatch 観測可能エージェント(amazon-cloudwatch-observability)を使い、強化されたオブザーバビリティを有効にしたCloudwatch Agentに以下のログがでてしまう。

```
2025-04-28T05:05:04Z W! {"caller":"internal/transaction.go:129","msg":"Failed to scrape Prometheus endpoint","kind":"receiver","name":"awscontainerinsightreceiver","data_type":"metrics","scrape_timestamp":1745816704540,"target_labels":"{__name__=\"up\", instance=\"dcgm-exporter-service.amazon-cloudwatch.svc:9400\", job=\"containerInsightsDCGMExporterScraper\"}"}
2025-04-28T05:05:43Z W! {"caller":"internal/transaction.go:129","msg":"Failed to scrape Prometheus endpoint","kind":"receiver","name":"awscontainerinsightreceiver","data_type":"metrics","scrape_timestamp":1745816743001,"target_labels":"{__name__=\"up\", instance=\"neuron-monitor-service.amazon-cloudwatch.svc:8000\", job=\"containerInsightsNeuronMonitorScraper\"}"}
```

これらのメトリクス収集を停止する方法が「[高速コンピューティングメトリクスの収集をオプトアウトする](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/install-CloudWatch-Observability-EKS-addon.html#CloudWatch-Observability-EKS-addon-OptOutAccelerated)」に書いてある。

アドオンの高度な設定で以下のようなJSONを設定すれば出なくなる。

``` json
{
  "agent": {
    "config": {
      "logs": {
        "metrics_collected": {
          "kubernetes": {
            "enhanced_container_insights": true,
            "accelerated_compute_metrics": false
          }
        }
      }
    }
  }
}
```
本番環境のS3をステージング環境にもコピーする

## やりたいこと

ステージング環境と本番環境でS3データの差異があり、表示ができないなどを解消したい。
主に画像です。

## 処理フロー

ステージング環境のEC2上でS3コピーのAWS CLIを実行します。
実行できればcronで毎日コピーするようにします。

```mermaid

flowchart LR
    subgraph Account_A [本番環境アカウント]
        S3A["S3 Bucket (Source)"]
    end
    subgraph Account_B [ステージング環境アカウント]
        EC2B["EC2 Instance (AWS CLI)"]
        S3B["S3 Bucket (Destination)"]
    end

    S3A -->|Download via aws s3 cp| EC2B
    EC2B -->|Upload via aws s3 cp| S3B

```

## 手順1 本番環境のバケットポリシーを変更

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowBAccountReadAccess",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::<ステージング環境アカウントID>:root"
      },
      "Action": ["s3:GetObject", "s3:ListBucket"],
      "Resource": [
        "arn:aws:s3:::本番環境バケット名",
        "arn:aws:s3:::本番環境バケット名/*"
      ]
    }
  ]
}
```

## 手順2 ステージング環境でロールを作成して、EC2にロール付与

```json

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::本番環境バケット名",
        "arn:aws:s3:::本番環境バケット名/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:PutObjectAcl"
      ],
      "Resource": [
        "arn:aws:s3:::ステージング環境バケット名/*"
      ]
    }
  ]
}

```

## 手順3 EC2でコマンド実行

### AWS CLIインストール手順は以下を参考

https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/getting-started-install.html

```bash
aws s3 sync s3://本番環境バケット s3://ステージング環境バケット
```

問題なく実行できればcronの設定を行います。

## 手順4 cronを設定する

```bash
crontab -e
```

```bash
0 10 * * * aws s3 sync s3://本番環境バケット s3://ステージング環境バケット
```

※上記例は朝10時に本番環境のS3内容をステージング環境にコピーします

## まとめ

定期的にコピーしておけばステージング環境の差異を埋めるだけではなく、本番環境のS3バックアップにもなりますので便利かなと思っています。
ただ、初回にコピー内容が多いと少し時間はかかります。
rex0220 計算式プラグイン テーブル指定行のコピー

[計算式プラグイン](https://qiita.com/rex0220/items/ae83c6d5ce50ff7a9a73)を使って、テーブル指定行のコピーを行ってみます。

# 概要

コピー開始行とコピー終了行で指定されたテーブル1の行をテーブル2 にコピーします。

![2025-04-28_14h10_38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/3a6bb15a-81d2-410a-bee9-ba2ad5a73bfd.png)

# 操作例

![2025-04-28_14h17_53.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/fa8756f0-a204-4f4d-b523-8c6b46c5f073.gif)

# 計算式プラグイン設定

TABLE_DATA 関数と TABLE_MAP 関数の組合せで、テーブルのコピーを行うことが出来ます。
TPFILTER で、テーブル行の指定範囲を抽出します。
TPDIC で、コピーする項目を指定します。

![2025-04-28_14h12_21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/703eb101-1daa-418c-827e-fbcfbbe86cec.png)

```javascript:
OPTION: 

// テーブル1.番号T1 NUMBER
ROWNO(テーブル1)+1

// テーブル2 SUBTABLE
TABLE_DATA(
  TABLE_MAP(テーブル1,
    TPFILTER(AND(
      (ROWNO(テーブル1)+1)>=コピー開始行, 
      (ROWNO(テーブル1)+1)<=コピー終了行
    )),
    TPDIC(
      "番号T2",番号T1,
      "日付T2",日付T1,
      "ドロップダウンT2",ドロップダウンT1,
      "数値T2",数値T1
    )
  )
)

// テーブル2.番号T2 NUMBER
// テーブル2.日付T2 DATE
// テーブル2.ドロップダウンT2 DROP_DOWN
// テーブル2.数値T2 NUMBER
```
NeurIPS2024の量子化論文 (2)

# 概要

この記事では、[NeurIPS2024](https://neurips.cc/Conferences/2024)の量子化論文を紹介します。[^1]

[その1](https://qiita.com/kyad/items/ef9d7bf6a177e2d8758d)

[^1]: 画像や数式は論文から引用しています。


# Cherry on Top: Parameter Heterogeneity and Quantization in Large Language Models

https://arxiv.org/abs/2404.02837

- 概要：CherryQ. 一部のパラメータ(Cherry)が性能に大きな影響を持つことを用いた学習ベースの混合量子化
- キモ：Cherryは(2)式のHessianで決める。Algorithm 1のようにcherryとcherry以外を同時に調整(学習)する


# Efficient Multi-task LLM Quantization and Serving for Multiple LoRA Adapters

https://openreview.net/forum?id=HfpV6u0kbX

- 概要：LoRAによるマルチタスクで複数のLoRAアダプタがある場合に共通部分の量子化を共通化
- キモ：MLGPTQでは、(2)式のように、全タスクのうち最もHessianの寄与が大きいタスクでGPTQ処理する


# 2DQuant: Low-bit Post-Training Quantization for Image Super-Resolution

https://arxiv.org/abs/2406.06649

- 概要：超解像向け2bit量子化方法
- キモ：Fig. 2. Clippingの協会をDOBIで粗く、DQCで詳細に決める


# BitsFusion: 1.99 bits Weight Quantization of Diffusion Model

https://arxiv.org/abs/2406.04333

- 概要：Stable Diffusion v1.5のU-Netを1.99bitに量子化
- キモ：Fig. 3. 量子化前後の誤差から混合量子化して、量子化前からの蒸留でさらに最適化する


# Q-VLM: Post-training Quantization for Large Vision-Language Models

https://arxiv.org/abs/2410.08119

- 概要：VLMのPTQ
- キモ：エントロピーを量子化誤差の代理尺度として使う。レイヤのエントロピーが閾値内に収まるようにブロックに分け、ブロック内で最適に量子化する


# KVQuant: Towards 10 Million Context Length LLM Inference with KV Cache Quantization

https://arxiv.org/abs/2401.18079

- 概要：KVCacheの量子化
- キモ：Fig. 1 右の4つの工夫で制度改善した。Per-channel量子化など

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/18a7836e-7c5d-40f2-a6c1-a97da38dea11.png)


# MagR: Weight Magnitude Reduction for Enhancing Post-Training Quantization

https://arxiv.org/abs/2406.00800

- 概要：重みを非線形変換で調整して外れ値を抑制する方法
- キモ：量子化誤差に加え、重み行列の∞ノルムが最小になるように最適化する


# PTQ4DiT: Post-training Quantization for Diffusion Transformers

https://arxiv.org/abs/2405.16005

- 概要：Diffusion Transformer向け量子化
- キモ：CSBはレイヤ間で重みを対角行列で滑らかにする((4)~(7)式)。SSCは重みとの相関が少ない時系列ほど強く重み付ける((10)~(11)式）
【廃止】Sales Products and Quotes Superbadge Unit



https://trailhead.salesforce.com/content/learn/superbadges/superbadge_sales_prod_sbu

+ 価格表を選択して操作します。
+ さまざまな通貨を使用して取引を管理します。
+ 見積書を作成、複製、カスタマイズします。
+ 割引、税金、配送料を適用します。


UMS 販売プロセスに関する重要な注意事項は以下のとおりです。

+ すべての商談には関連付けられたアカウントが必要です。
+ すべての商談には少なくとも 1 つの関連連絡先が必要です。連絡先の役割が不明な場合は、「その他」と示します。
+ 新しい商談の名前は、 「取引先 - 金額」という形式で始まる必要があります。会社に複数の部門がある場合は、「取引先 部門 - 金額」という形式で、商談の名前に部門を含める必要があります。
+ 商談名には、整数のみを使用し、通貨記号 ($、¥、€) や小数点文字 (カンマ、ピリオド、スペース) などの数字以外の文字を追加しないでください。
+ 締め切り日は将来の日付にする必要があります。（任意の日付を使用できます。特定の日付はチェックされません。）
+ 商談は可能な限り、関連するマーケティング キャンペーンに関連付けるか、または参照する必要があります。
+ 取引が間違った段階にある場合、レコードを販売プロセスの前の段階に更新することが許可されます。
大きな取引に関する特別な注意: 100 万を超える案件の場合は、見積書を提出して承認を受ける必要があります。


# TerraGlobal 取引における製品と価格表の操作

TerraGlobalの各部門が関心を持つ製品とサービスを確認します。商談商品ライン項目を作成し、必要に応じてレコードを調整します。


:::note alert
We can't find the correct products associated with the TerraGlobal Renewables USA deal.

TerraGlobal Renewables USA 取引に関連する正しい製品が見つかりません
:::

:::note alert
We can't find the TerraGlobal Renewables USA deal.

:::

商談名は金額が必要とか言っていたくせいに...

太陽光パネルだけしか登録してなかったけどエラーメッセージは変わらず。１つ１つのチェックではエラーメッセージを変えてないみたいですね。かなり手抜きしている感じです。先が思いやられます。

:::note alert
We can't find the correct currency for the TerraGlobal SolarTech Europe deal.

:::

:::note alert
We can't find the correct currency for the TerraGlobal Canada deal.

:::


# 見積もりと割引の操作

TerraGlobalの各部門のニーズと関心に合わせて見積書を作成します。商談商品と見積書に関連する通貨と割引を扱います。


:::note alert
We can't find the correct currency for the TerraGlobal Solar Dynamics Australia deal.

TerraGlobal Solar Dynamics Australia の取引に適切な通貨が見つかりません。
:::

:::note alert
We can't find a quote with the correct values for tax and shipping.

税金と送料の正しい値が記載した見積りが見つかりません。
:::

これって、それぞれでなく、1000？
やっぱり意味が分からない

 Then add a flat fee of 1000 for shipping and handling. 


:::note alert
We can't find a second quote for the TerraGlobal Sunshine deal with the correct configuration.
:::

何をやってもダメですね。

これらも違います

https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007X9LpCSAV


作った見積りを消してもエラーは変わりません。何もチェックできてないのでは？相変わらずいいかげんなチェックロジックです。これでは廃止になっても仕方ない。

:::note alert
We can't find a second quote for the TerraGlobal Sunshine deal with the correct configuration.
:::

承認申請してから、勝手に承認していたから？再作成して申請だけだったら合格できた。
何だこれ　全然実用的には意味のないものでした... もう少ししっかりと作って欲しい。できないのだったら廃止でＯＫです。チェックロジックの抜け穴を探すハンズオンなんて意味がありません。
【Rails初学者】Fakerを使って簡単にシードデータを作成する

# Fakerを使って簡単にシードデータを作成してみました

こんにちは。
Railsを勉強している初学者です。  
今回は、アプリ開発の中で必要になる「ダミーデータ（シードデータ）」を、**Faker** という便利なGemを使って作成してみたので、忘れないようにまとめておきます。

## シードデータとは？
Railsでは、開発・テスト環境で使うためのデータを簡単に用意するために **シードデータ** を作ることがよくあります。
コマンド一発で、あらかじめ用意しておいたデータをDBに流し込むことができると知りました。

```bash
bin/rails db:seed
```

## Fakerとは？
**Faker** は、名前・住所・会社名・文章など、いろいろな「それっぽいデータ」をランダムに作り出してくれるGemです。  
テストデータ作成にとても便利なのです。

## 事前準備（Gemのインストール）
まず、`Gemfile`にFakerを追加します。

```ruby
# Gemfile
gem 'faker'
```

追加したら、ターミナルでインストールします。

```bash
bundle install
```

## シードデータ作成
今回は、`Article`モデル（記事モデル）に、タイトルと本文をランダムに生成して入れてみました。

```ruby
# db/seeds.rb

15.times do
  Article.create(
    title: Faker::Lorem.sentence(word_count: 6),
    content: Faker::Lorem.sentence(word_count: 200)
  )
end
```

### ポイント
- `15.times do` で15件データを作成
- `Faker::Lorem.sentence` を使ってランダムな文章を作成
  - `word_count: 6` → タイトル用（6単語）
  - `word_count: 200` → 本文用（200単語）

## シードデータを流し込む
ターミナルで以下を実行します

```bash
bin/rails db:seed
```

Articleテーブルに15件のランダムなデータが作成される

## 学んだこと
- 開発中はダミーデータがあるととても便利
- Fakerを使えば、簡単にリアルっぽいデータを作れます

## 参考リンク
- [Faker公式GitHub](https://github.com/faker-ruby/faker)
scratch初学者のための記事まとめ

# 技術的なうのっち記事

https://qiita.com/sanpeita/items/a02d6c5b50ff027da6e1

https://qiita.com/sanpeita/items/4a9266650c874d79b139

# scratch共有プロジェクト

## 色にぶつかったときの処理
### おにごっこゲームをつくったら迷路ゲームをつくろ
https://scratch.mit.edu/projects/216174297/

## みんなだいすきアンダーテール風
https://scratch.mit.edu/projects/237047089/
LILYGO T-Deck Plusを最新版でビルドする

以前遊んだLilygoのT-Deck Plusですが
espressif32のバージョンを
platform = espressif32@6.3.0
指定すると普通に動いたのでが（Lilygoのサンプルは@6.3.0）
6.9.0等の新しいを指定すると動きませんでした（本校執筆時の最新版6.10.0)

https://qiita.com/MetalOX/items/2bd305ad93f09e78ee09

別に古いバージョンを使っていれば良いのだけど、他のライブラリ等の整合も考えると
出来る限り最新版を使いたい所

# 原因は？

色々調べた結果、T-Deck PlusのMCUは **ESP32-S3** が原因のようで。

* ESP32（普通のESP32）の場合
* HSPI（SPI2）とVSPI（SPI3）が使える。
(通常、TFT_eSPIはVSPI（デフォルトのSPIバス、ピンは固定）を使う設計になってる。)
* 必要に応じて -DUSE_HSPI_PORT を指定すると、HSPI側（自由にピンを設定できる）に切り替えることができた。

ESP32-S3の場合
* ESP32-S3もSPI2/HSPI、SPI3/VSPIみたいな命名が一応あるけど、
* 実際には**"Flexible SPI" (FSPI)** という新しい仕組みになっていて、
ピンが完全に自由に割り当てできる仕様になった。

でも！ライブラリ（TFT_eSPI）の内部では依然として 「VSPIを使う」「HSPIを使う」みたいな昔ながらの記述が残っている。

ここで問題：
* TFT_eSPIが **"デフォルトでVSPIを使う"**  → でも、S3ではそれが正しく動作しないことがある。
* S3では、ピンを手動で設定したい＝自由なバスを使いたい → HSPI（SPI2）を選びたい。
(このとき、-DUSE_HSPI_PORT を指定することで、手動でピン設定できるバスに強制切り替えできる。)

VSPIだとS3で一部不安定になる場合があって、それを避けるためにも使う。

そのため、platformio.iniに記述が必要になります。
``` C:platformio.ini
build_flags = -DUSE_HSPI_PORT
```

後はUser_Setup.hに以下の内容を追加（インクルード）すれば最新版でも動作します。

``` C:tft_espi_setting.h
#define ST7789_DRIVER   /* ST7789を使うと指定 */

#define TFT_WIDTH  240
#define TFT_HEIGHT 320

// ==== Pin Config for ESP32-S3 ====

#define TFT_MISO  38
#define TFT_MOSI  41
#define TFT_SCLK  40
#define TFT_CS    12
#define TFT_DC    11
#define TFT_RST   -1

// バックライト制御（必要なら）
#define TFT_BL     5
#define TFT_BACKLIGHT_ON HIGH

// ==== SPI Settings ====
#define TFT_SPI_FREQUENCY  40000000
```
[python-oracledb入門](第4回) リリース3.0 & 3.1新機能


# 連載目次
[連載：python-oracledb入門　目次](https://qiita.com/nakaie/items/c373cff694cb23a8568c)


# はじめに 
連載をサボっている間に新しいバージョンが2025年3月に新バージョンの3.0.0がリリースされ、4月3.1.0がリリースされました。今回は新バージョンで実装された主な機能についてThinモードを中心に解説します。修正された不具合を含む完全なリストは[こちら](https://python-oracledb.readthedocs.io/en/latest/release_notes.html)です。

# パイプライン処理の正式サポート
リリース2.4.0から試験的に導入されていましたが、3.0.0で正式機能となりました。この機能を利用すると、パイプラインに複数の処理(execute()やfetch系)を登録し、一度のデータベースのコールで複数の処理をまとめて非同期処理として投げることができます。データベースとのラウンドトリップの削減や非同期処理にすることでSQL処理中にほかの処理ができるようになるなど、全体的なパフォーマンスの向上に寄与します。もちろん更新系SQL文、SELECT文ともにそれぞれ複数の文を発行可能です。以下はマニュアルのままですがパイプライン処理のサンプルです。
```
import asyncio
import oracledb

async def main():
    # Create a pipeline and define the operations
    pipeline = oracledb.create_pipeline()
    pipeline.add_fetchone("select temperature from weather")
    pipeline.add_fetchall("select name from friends where active = true")
    pipeline.add_fetchmany("select story from news order by popularity", num_rows=5)

    connection = await oracle.connect_async(user="hr", password=userpwd,
                                            dsn="localhost/orclpdb")

    # Run the operations in the pipeline
    result_1, result_2, result_3 = await connection.run_pipeline(pipeline)

    # Print the database responses
    print("Current temperature:", result_1.rows)
    print("Active friends:", result_2.rows)
    print("Top news stories:", result_3.rows)

    await connection.close()

asyncio.run(main())
```
ただし、この機能は23aiに接続している場合のみ有効です。21c以前でも動きはしますが、パイプライン未使用時と同様SQLを1文ずつ投入します。


# プラグイン機能
プラグイン機能により、python-oracledbに対し独自の機能拡張が行えるようになりました。標準で数個のプラグインが提供されています。次で説明する集中型構成プロバイダもプラグインとして実装されています。


# 集中型構成プロバイダ
集中型構成プロバイダ (Centralized Configuration Providers) はデータベースの接続資格情報やコネクションプール関係やキャッシュ関係などの情報を一元的にアプリケーションコードの外で管理し、アプリケーションからは一元的に管理された情報にアクセスすることでこれらの情報を取得、利用できるようになる機能です。アプリケーション内に認証周りのセンシティブな情報を記述する必要がなくなりセキュリティも向上します。また構成情報の使い回しができるようになるのでコーディングの負荷の削減も可能です。
情報を管理する先としてはOCIのObject StorageやMicrosoft AzureのAzure App Configurationといったクラウドサービスの他に、ローカルファイルも選択可能なので、オンプレミスのアプリケーションでも本機能の利用が可能です。ただしローカルファイルが選択できるのはThinモードのみです。


# データフレーム対応
Apache Arrow PyCapsuleのインターフェースを利用して結果セットをデータフレームの形式で受け取ることができるようになりました。実際のデータフレームオブジェクトはOracleDataFrameという独自オブジェクトですが、当然ながら他のデータフレームに変換することが可能であり、PandasやPolarisのようなPandas互換のライブラリ、NumPy、PyTorch、Apache Parquetなどとの連携も可能になります。本機能はThickモードでも利用できますが、どちらのモードも3.1.0の段階ではプレリリース扱いの機能です。


# その他
- Python 3.8のサポートの廃止 (3.1.0より。両モードとも)
- スクロール可能なカーソルのサポート (3.1.0より)
- Oracle Advanced Queuingのサポート強化
- Oracle Application Continuityのサポート強化
- Oracle Transaction Guardへの対応
- コネクションプールのキャッシング対応
empApi PushTopic Aura

## PushTopicを登録
#### 開発者コンソールの匿名Windowで実行
#### 注意:Query中の項目に変更があった場合だけ、通知される。その他の項目を更新しても、通知されない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3894299/f4e6954b-cec9-4809-ac56-cef524200be0.png)

```Apex
PushTopic pushTopic = new PushTopic();
pushTopic.Name = 'AccountUpdatePushTopic';
pushTopic.Query = 'SELECT Id, Name, Fax FROM Account';
pushTopic.ApiVersion = 57.0;
pushTopic.NotifyForOperationCreate = true;
pushTopic.NotifyForOperationUpdate = true;
pushTopic.NotifyForOperationDelete = false;
pushTopic.NotifyForFields = 'Referenced';
insert pushTopic;
```

## Aura componentを作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3894299/39b6436a-6226-4e37-be45-9fd6d23ffd78.png)

cmp部分
※implements="flexipage:availableForAllPageTypes" 　1つで良い
```xml
<aura:component implements="flexipage:availableForAllPageTypes" access="global">
    <aura:attribute name="subscription" type="Object" />
    <aura:attribute name="messages" type="List" default="[]" />
    <lightning:empApi aura:id="empApi" />

    <div class="slds-m-around_medium">
        <lightning:button label="Subscribe PushTopic" onclick="{!c.handleSubscribe}" />
        <lightning:button label="Unsubscribe PushTopic" onclick="{!c.handleUnsubscribe}" />
    </div>

    <div class="slds-m-around_medium">
        <aura:iteration items="{!v.messages}" var="msg">
            <p class="slds-box slds-box_xx-small slds-m-vertical_xx-small">
                {!msg}
            </p>
        </aura:iteration>
    </div>
</aura:component>
```


Controller js部分
```j
({
    handleSubscribe : function(component, event, helper) {
        const empApi = component.find('empApi');
        const channel = '/topic/AccountUpdatePushTopic'; // ★PushTopic API名に合わせる
        const replayId = -1; // 最新から購読

        const callback = function (message) {
            console.log('Received PushTopic event:', JSON.stringify(message));
            // 受信したイベントをmessagesリストに追加
            let messages = component.get('v.messages') || [];
            messages.unshift(JSON.stringify(message.data.sobject)); 
            // ↑↑↑chatgptではmessage.payloadとなっているが、 ★★★★★message.data.sobjectが正しい
            component.set('v.messages', messages);
        };

        empApi.subscribe(channel, replayId, callback).then(function (newSubscription) {
            console.log('Subscribed to PushTopic channel:', channel);
            component.set('v.subscription', newSubscription);
        }).catch(function (error) {
            console.error('Error subscribing to PushTopic:', error);
        });
    },

    handleUnsubscribe : function(component, event, helper) {
        const empApi = component.find('empApi');
        const subscription = component.get('v.subscription');

        empApi.unsubscribe(subscription, function (message) {
            console.log('Unsubscribed from PushTopic channel');
        });
    }
})
```

## Auraコンポーネントを画面に追加、今回はホーム画面に追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3894299/b14683be-bc0c-4df8-9fc5-fcf71b0e0a4d.png)

## 新規でAccountを追加、または、Faxを変更するとMsgが↑↑↑ように表示される