OmniAICreator/Qiita-1.07M huggingface dataset:
UiPathで株価CSVを取得する

# はじめに
保有する株式の資産推移を見たいと思い、株価データを口座がある証券会社から手動で取得していたが、大変なのでUiPathを使って自動化してみた。
# UiPathについて
Webであれば**スクレイピング**が主流だが、昨今は制限が厳しくなっている。
今回使用したのは、SBI証券が提供しているアプリケーション「[HYPER SBI 2](https://go.sbisec.co.jp/lp/lp_hyper_sbi2_211112.html)」である。
[UiPath](https://www.uipath.com/ja) は昔少し触った事があった程度で久しぶりにインストールして使ってみた。
自動化ツール(RPA)にはいろいろな製品があるが、無償で使えるバージョン(コミュニティ)があるのはUiPath位じゃないだろうか。
アカウントを作成して、マイページに入ると、ダウンロードができる。(サイズが1GB位ある)
# 手動での手順
SBI証券が提供する「HYPER SBI 2」を使って、保有する銘柄の株価情報を CSV で取得する手順。
個人が保有する銘柄はそれほど多くないので１回だけなら苦にならない。
ただ、頻繁に更新するとなればだんだん面倒になってくる。

**日経平均株価**を取得する例では、
左隅のドロップダウンで「主要指標」を選択し、「日経平均」を選択
[照会]->[CSVエクスポート]ボタンを順に押していく
![日経平均.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3834038/6872293e-aac7-b87d-4929-951fa948633e.jpeg)

**個別銘柄**の場合も、同じ画面で左隅のドロップダウンで「個別銘柄」を選択し、銘柄コードを入力して
[照会]->[CSVエクスポート]の手順。

# 自動化方法
ともかく、あまり時間を掛けたくなかったので、簡単な方法にした。
あるフォルダにファイル名を銘柄コード４桁にしたファイルを置いておき上書き更新する方法とした。
日経平均株価は便宜的に、「0000.csv」といった感じ。

UiPath では１つの操作を**アクティビティ**(activity)と言う単位で行い、繋げていくことで処理を行っていく。
繰り返し(Loop)や分岐(If)も１つのアクティビティとなる。
実は、どこに必要な**アクティビティ**があるのか探すのが初心者にとっては一番わかり難い。
ここでは下の様にフォルダー内ファイルの繰り返しアクティビティを使った。

![uipath2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3834038/cb08a822-0dc7-198e-f761-59a35b3b3dc9.jpeg)

「CurrentFile」というのが**ファイルオブジェクト**で「CurrentFile.Name」のように**ファイル名**がプロパティの一つの要素として取得できる。

１銘柄の操作は、**レコーダー** を使って簡単に生成できる。
ただし、今回キーボード入力が必要なところでうまく出来なかった。
この部分は後で、手動で「**テキストを設定**」アクティビティを挿入している。
下記は、「**ファイルの保存**」ダイアログでのファイル名の入力の部分。

![UiPath3.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3834038/265edc25-2970-d3df-ef44-e57131d7781b.jpeg)
ここで「code」は自分で定義した変数、ファイル名の４文字を代入している。
まさに、単純な繰り返しなのでこれだけである。
というところで、約半日で一通り動くようになった。

まだ、UiPath 自体の細かい操作は良く理解していない。
それでも動くのがRPAの真髄といったところか。

# CSVの後の処理
本題とは外れるが、落としたCSVはデータベースである **PostgreSQL** にバッチコマンドでロードして差分登録を行っている。なので株価の抽出期間はいじる必要が無い。

:::note warn
株式分割があると過去に遡って株価を修正する必要があるので、過去から再登録が必要になる。
:::

# 最後に
**レコーダー**で自動作成されたボタンの認識率が良いのには少々驚きだった。
UiPathは便利だと再認識した。
Docker Imageに脆弱性のあるライブラリが含まれていたときの対応方法

# 概要
docker imageに脆弱性のあるライブラリが含まれていたときの対応方法。

# 対処法1
個別にライブラリを脆弱性のないバージョンまでアップデートする。
例えばDockerfileに以下の処理を追加する。

ただしこれは表層的な対処法なので、可能であれば対処法2を行う。

```dockerfile
RUN set -ex \ 
	&& apt-get update -qq \ &
	& apt-get install -y \
	 # fix CVE-2024-47685 linux-libc-dev 次回image更新時に削除
	linux-libc-dev 
 ```

# 対処法2
イメージを、脆弱性のないライブラリを含むバージョンまでアップデートする。
その際に、マイナーバージョンを上げるだけで済みそうなのであれば、マイナーバージョンをMaxまであげるとよりいい。

例えば、6.1.99-1のlinux-libc-devが使われており、それはCVE-2024-47685に引っかかっているとする。
その場合まず、どのイメージでこのライブラリが使われているかを明確にする。

例えばDockerfileが以下のようであった場合、nodeとrubyでlinux-libc-devが使われている可能性がある。

```dockerfile
FROM node:22.10.0-slim
FROM ruby:3.3.4-slim
```

それぞれのイメージをDockerHubで検索し、使用しているバージョンのページに行き、Packagesの箇所にライブラリの名前をいれて検索 or VulnerabilitiesにCVEの番号を入力して検索(CVEで検索してもでない場合があるので、今回の場合はライブラリ名で検索するのが安全)。
以下のようにruby:3.3.4-slimで使用していることがわかった。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/965739/a5e5bcd2-a236-98a4-3546-68a7bd7a9eb1.png)

https://hub.docker.com/layers/library/ruby/3.3.4-slim/images/sha256-581fc2162515aac9be327b4b7c8220d2187adfaf4455d76cf10e0d6b7163b166?context=explore 

パッチバージョンを上げるだけで済むのであれば、基本的にパッチバージョンを最大まで上げる & 既存の機能に影響がでないことを確認 & 軽く動作確認してリリースすればいい。
メジャー、マイナーバージョンを上げる必要がある場合は、必要に応じた分だけバージョンをあげて、適切に影響範囲等に対して対応すればいい。

今回の場合は、3.3.5以上にすれば問題は解消するが、ruby3.3系で最新のバージョンは3.3.6なので、3.3.6まであげる。

```dockerfile
FROM node:22.10.0-slim
FROM ruby:3.3.6-slim
```
WindowsでAlacritty+WSL環境を作る

## はじめに
ここでは， Windows で Alacritty+WSL 環境を作ります．既に WSL 環境が構築されていることを前提とします．Windows ターミナル等で WSL が開ければ問題ないです．

## Alacuritty のインストール
好きな方法で入れたら良いです．私は[公式サイト](https://alacritty.org/)からインストーラをダウンロードしてインストールしました．

## Alacuritty の設定

### WSL のバージョン確認

Windows PowerShell を開いて，インストールされている WSL のバージョンを確認します．
コマンドは `wsl -l`です．
```PowerShell
PS C:\Users\USERNAME> wsl -l
Linux 用 Windows サブシステム ディストリビューション:
Ubuntu-22.04 (既定)
docker-desktop
docker-desktop-data
Ubuntu
```
今回は`Ubuntu-22.04`でした．

### 設定ファイルでWSLを起動するようにする

Alacuritty は以下のパスの設定ファイルを読み込みます．
```txt
%APPDATA%\alacritty\alacritty.toml
```
検索して見つけても良いですがおそらくこんな場所のはず．USERNAME は適宜読み替えてください．
```txt
C:\Users\USERNAME\AppData\Roaming\alacritty\alacritty.toml
```
最初は`alacritty`ディレクトリが存在しない可能性があります．その場合はRoaming フォルダ内に`alacritty`ディレクトリと`alacritty.toml`を作成します．

`alacritty.toml`には以下のようにして起動するシェルを選択します．Ubuntuのバージョンは自分で確認したものに合わせます．
```toml
[terminal.shell]
program = "/Windows/System32/wsl.exe ~ -d Ubuntu-22.04"
```

`alacritty.toml` を保存し，Alacritty を起動したら WSL に接続することができます．

## おまけ zellij の自動起動
後ろに `bash -ic zellij` を付けることで自動起動できます．`i` オプションはインタラクティブシェルとして起動，`c`オプションは続く文字列をコマンドとして実行することを意味します．
同様の手法でtmuxも自動起動できます．
```toml
[terminal.shell]
program = "/Windows/System32/wsl.exe ~ -d Ubuntu-22.04 bash -ic zellij"
```
paizaラーニング問題集「座標系での向きの変わる移動」を解き、感じたこと

▼問題文のURL

https://paiza.jp/works/mondai/a_rank_level_up_problems/a_rank_snake_move_boss

▼考え方

現在の座標(x,y)と現在の向きをリストlで管理します。入力(=移動の向きL,R)と現在の向きに基づき、次の座標と次の向きを計算し出力します。向きは、0:北,1:東,2:南,3:西とします。

▼コード
```py
X,Y,N = map(int,input().split())

# l: 現在の座標(x,y)と向きを表すリスト
l = [X,Y,0]

for _ in range(N):

    # d: 入力
    d = input()
    
    if d == "L":
        
        if l[2] == 0:
            # 次の座標の計算
            l[0] -= 1
        elif l[2] == 1:
            l[1] -= 1
        elif l[2] == 2:
            l[0] += 1
        elif l[2] == 3:
            l[1] += 1

        # 次の向きの計算
        l[2] -= 1

    else:
        
        if l[2] == 0:
            l[0] += 1
        elif l[2] == 1:
            l[1] += 1
        elif l[2] == 2:
            l[0] -= 1
        elif l[2] == 3:
            l[1] -= 1

        l[2] += 1

    print(l[0],l[1])

    if l[2] < 0:
        l[2] = 3
    elif l[2] > 3:
        l[2] = 0
```

▼感じたこと

私はコードを書く際に、いろいろなやり方が思いつけるようになりたいです。そもそも教科書的な良いやり方とは何なのかをまず身に着け、そのうえで、解答コード例の方針の内容や、その他の良いやり方に触れるべきだなと思いました。

求められることや制約条件が何なのか、ということが大事なのかなと思います。それらをまず踏まえて、最適なやり方がいろいろと思いつくようになりたいです。

参考までに、解答コードに比べて、私のコードは行数が11行多く(空行除く)、変数は1つ少なく、リストは同数でした。
kubectlのコマンドがkube-apiserverのどのエンドポイントを叩いてるか知る方法

`-v` オプションを使う
```
$ kubectl get po -v6
I1113 11:59:07.112554    4529 loader.go:395] Config loaded from file:  /Users/<User>/.kube/config
I1113 11:59:07.131680    4529 round_trippers.go:553] GET https://127.0.0.1:57471/api/v1/namespaces/default/pods?limit=500 200 OK in 15 milliseconds
No resources found in default namespace.
```

参考

https://kubernetes.io/ja/docs/reference/kubectl/cheatsheet/#kubectl%E3%81%AE%E3%83%AD%E3%82%B0%E3%83%AC%E3%83%99%E3%83%AB%E3%81%A8%E3%83%87%E3%83%90%E3%83%83%E3%82%B0
【ChatGPT】の機能をまとめておきます。ChatGPTの著名人ですら、古い情報のままなので。


　どうも、カーブミラーです。

　今回は、ChatGPTの機能をまとめておきます。ChatGPT関連の著名人が間違った発信をしていたためです。

:::note info
本記事は、ChatGPT（有料版）
で行なっております。画像は
ありません。　あしからず。
:::
　ChatGPT等の動作状況を知らせる
　　OpenAIのステータスページ。
　　　[OpenAIステータス](https://status.openai.com/)

***
　まずは、ニュース。

　OpenAI創業者兼社長、
　　Greg Brokman氏が
　　　長期休暇から、OpenAIに復帰。
　　　　[Greg Brockmanさんポスト](https://x.com/gdb/status/1856441156281753908?t=rD3jbYzujoKq_0RzhTQBVA&s=19)
　DeepL翻訳
>人生最長の休暇が終わり、@OpenAIの構築に戻る。

　お帰り、グレッグ。
***
　さて、本題です。

　今回は、
　　ChatGPTの機能を
　　　まとめておきます。

　ChatGPT関連の著名人が
　　間違った発信をしていたため、
　　　指摘したのが、きっかけ。

　最新刊の書籍でも
　　o1などの最新情報に
　　　触れているのに
　　　　古い情報を出していることに
　　　　　前々から気になって
　　　　　　いましたので。
***
　とはいえ、
　　ここでは
　　　機能に絞って書きます。
　　　　もちろん、わかる範囲ですが😅

　ChatGPT Plus
　・選択可能なモデル
　　・GPT-4 レガシー
　　・GPT-4o
　　・GPT-4o mini
　　・GPT-4o with Canvas
　　・o1-preview
　　・o1-mini
　・付随機能
　　・DALL-E3
　　・Advanced Data Analysis
　　　（旧Code Interpreter）
　　・ファイルアップロード
　　・音声入力・出力
　　・音声会話（アプリのみ）
　　・ウェブ検索
　　・GPTs作成・利用

　ChatGPT Plusでの制限
　　ChatGPTとの応答は、
　　　３時間40回。
　　GPTsは
　　　３時間25回。
***
　ChatGPT 無料版
　・モデル選択不可
　　・GPT-4oかGPT-4o miniが
　　　　内部的に切り替わる。
　　　　　GPT-3系はすでにない。
　・付随機能
　　・DALL-E3
　　・Advanced Data Analysis（ADA）
　　・ファイルアップロード
　　・音声出力（入力はアプリのみ）
　　・音声会話（アプリのみ）
　　・ウェブ検索
　　・GPTs利用（作成できない）

　無料版での制限
　　ChatGPTとの応答は、約10回。
　　　そのあと、モデルが切り替わるが
　　　　各種機能は使用不可に。
　　GPTsは
　　　ChatGPT応答と同じ。
　　DALL-E3は、公式２回、実際３回。
　　　またアプリでの編集・選択はなし。
　　ADAも制限がある、らしい。
***
　なお、ChatGPTは
　　予告なく変更されますので
　　　ご注意ください。

　私も気づき次第、
　　書いていきたいと思っています。

　みなさんの
　　作品制作の糧に
　　　なれば、幸いです。

　今回は、ここまで。
WebpackとNode.jsのバージョンの確認の仕方

Webpackのバージョンを確認するコマンド
```powershell
npx webpack -v
```

Node.jsのバージョンを確認するコマンド
```powershell
node -v
```
```powershell
PS C:\Users\xxx\xxx> node -v
v18.20.5
PS C:\Users\xxx\xxx> npx webpack -v
4.46.0
```
上記の場合、Node.jsNode.jsとWebpackの間で互換性の問題が発生するため
下記を入力する。

```powershell
nvm install 18
nvm use 18
```
まずはここから！VIエディタの操作をシンプル解説

`vi`エディタは、UNIX系システムで広く利用される効率的なテキストエディタです。以下に、`vi`の基本的な使用方法と操作手順を説明します。

## **`vi`の起動方法**
ターミナルで以下のコマンドを入力して、`vi`エディタを起動します。

```bash
vi ファイル名
```

※権限周りの関係で、sudo付きのパターンもある
```bash
sudo vi ファイル名
```

---

`vi`（または`vim`）エディタの基本操作について、以下にまとめました。

### モードの切り替え
`vi`エディタには4つのモードがあります。これらを理解することで、効率よく編集が行えます。

1. **ノーマルモード**（コマンドモード）：起動直後のモードで、カーソル移動や削除、保存などのコマンド入力ができます。
2. **インサートモード**：テキストの編集ができるモードで、`i`キーを押すと切り替わります。編集を終えるときは `Esc` キーを押してノーマルモードに戻ります。
3. **ビジュアルモード**：テキストの選択が可能なモードで、`v` キーを押して有効にします。
4. **コマンドラインモード**：保存や終了などの操作を行うモードで、`:` キーを押すと切り替わります。

### よく使うコマンド
以下は、基本的な編集やカーソル移動に役立つコマンドの一覧です。

#### 編集操作
- `i`：カーソル位置から挿入（インサートモードに切り替え）
- `a`：カーソルの次の位置から挿入
- `o`：カーソルの下に新しい行を挿入
- `x`：カーソル位置の文字を削除
- `u`：直前の操作を元に戻す（Undo）
- `Ctrl + r`：元に戻した操作を再実行（Redo）

#### カーソル移動
- `h`：左へ移動
- `j`：下へ移動
- `k`：上へ移動
- `l`：右へ移動
- `0`：行の先頭に移動
- `$`：行の末尾に移動
- `gg`：ファイルの先頭に移動
- `G`：ファイルの末尾に移動

#### テキストのコピー・貼り付け
- `yy`：現在の行をコピー
- `p`：コピーまたは削除したテキストを貼り付け
- `dd`：現在の行を削除（カット）

#### 保存と終了
- `:w`：ファイルを保存
- `:q`：終了
- `:wq`：保存して終了
- `:q!`：変更を保存せずに終了

### その他の便利なコマンド
#### 検索
- `/キーワード`：下方向にキーワードを検索
- `?キーワード`：上方向にキーワードを検索
- `n`：次の検索結果に移動
- `N`：前の検索結果に移動

#### 置換
- `:%s/旧テキスト/新テキスト/g`：ファイル全体で旧テキストを新テキストに置換

---

`vi`エディタの多彩なコマンドを使いこなすことで、より効率的に編集作業を行うことができます。慣れてくると、ショートカットを活用してスピーディに作業ができるようになります。
SpiringBootでThymeleafが動かないエラーの解消方法

## はじめに
SpringBootでの画面描画のためThymeleafを使い始めたのですが、早速動かず詰まったので解消方法を記述しておきます。

### 環境
- OS: Windows11
- IDE: IntelliJ IDEA 2024.2.4 (Community Edition)
- Java: "21.0.5" 2024-10-15 LTS
- SpringBoot: "3.3.5"
- Thymeleaf: "3.3.5"

## 問題
Thymeleafが動かない。
具体的には以下のような状態でした。
- HTMLタグの以下の記述に対して、エラーが出る
  - `xmlns:th="http://www.thymeleaf.org"`
  - エラー文：URI が未登録です (設定 | 言語 & フレームワーク | スキーマと DTD)
- 保存時のアクション：コードの整形を有効にしているが、保存時に`xmlns:th="http://www.thymeleaf.org"`が自動で削除される
- `th:text`などの補完が効かない

## 解決方法
### IntelliJ Community版の仕様
> - HTMLタグの以下の記述に対して、エラーが出る
>   - `xmlns:th="http://www.thymeleaf.org"`
>   - エラー文：URI が未登録です (設定 | 言語 & フレームワーク | スキーマと DTD)
> - `th:text`などの補完が効かない

上記については、IntelliJ Community版がThymeleafのサポートをしていないため起きているようです。有料版の場合、プラグインの利用が可能で、それを使うと補完が効いたり、URIの検出をしてくれるようです。

以下の記事に大変助けられました。
[URI is not registered：Community Edition の IntelliJ で表示される警告への対応方法](https://poco-tech.com/posts/troubleshoot/thymeleaf-xmlns-warning/)

### 自動削除への対処法
> - 保存時のアクション：コードの整形を有効にしているが、保存時に`xmlns:th="http://www.thymeleaf.org"`が自動で削除される

上記については正直原因がわかりきっていませんが、解決した方法を列挙します
- ブランチをThymeleaf導入前に戻し、再度インストール
- なぜか`src/main/java/resources/templates`ディレクトリがなくなっていたため、手動で作成
- `src/main/java/resources/templates`内にHTMLファイルを作成
- HTMLタグ内の記述を以下のように修正
    ```html
    // lang属性を記述
    <html lang="ja" xmlns:th="http://www.thymeleaf.org">
    ```

個人的にはlang属性の追記か、Thymeleafの再インストールに効果があったのではないかと考えています。

## 備考
上記の問題以外にもいくつかハマった点があったので残しておきます。
エラーというよりも、単純に認識不足のため備考として記述します。

### ソースコード
```Java
　// 修正後の動くようになったコードです
  @GetMapping("/studentList")
  public String getStudentList(Model model) {
    List<Student> allStudentList = service.searchForAllStudentList();
    List<StudentCourse> allStudentCourseList = service.searchForAllStudentCourseList();
    model.addAttribute("studentList",
        converter.getStudentDetailsList(allStudentList, allStudentCourseList));

    return "studentList";
  }
```
### 問題
- modelの補完に`addAttribute`がない
- 画面を確認すると、studentListという文字列のみ描画される

### 解決方法
#### Modelを`org.springframework.ui`で選択する
Modelには`ch.qos.logback.core.model`もあり、そちらを選択すると`addAttribute`が選べないようです

#### `@RestController`ではなく`@Controller`を使用する
凡ミスですが、これに気づきませんでした。。
これを修正しないと、studentListが文字列で返ってきてしまいます。


## おわりに
所属しているコミュニティで同様の問題で詰まっていた方が過去にもいたようですが、最終的にIntelliJを再インストールすることで解消したようです。
上記で直らなければ再インストールを検討してみても良いかもしれません。

## 参考
- [URI is not registered：Community Edition の IntelliJ で表示される警告への対応方法](https://poco-tech.com/posts/troubleshoot/thymeleaf-xmlns-warning/)
[VBA]特殊記号や禁則文字を入力したい！

## 特殊記号や禁則文字を入力するには

1.UNICODE関数を使ってコードポイントを取得
2.ChrW関数でコードポイントを文字化する
という方法が一番簡単そう…

主要な特殊記号/禁則文字のコードポイントもまとめてあります◎
https://indoor-nekura.work/unicode_chrw/
2024年9-10月の学習記録

9-10月は、職務内容が充実していた。
以前からの継続案件であるが、Docker + Webpackを用いてフロントエンドの作業環境を構築したり、WYSIWYGプラグイン「TinyMCE」を用いたウェブサイトを開発したりと、未知のことが多く勉強することが多くあった。
その代わりといっては何であるが、自学に割いた時間は少ない2ヶ月だった。

## ChatGPT の活用法

あるライブラリについて調べるとき、公式ドキュメントのURLを ChatGPT に与えた上で「⚫︎⚫︎を実現するにはどうすればよいか。このドキュメントを参考にして答えよ。回答する際は参考にしたページを示せ。」と聞くとよいことに気がついた。

無限の学習時間があれば、1ページ目から自分でドキュメントを読むべきであるが、有限の職務時間のなかでタスクを遂行するにはそうもいかない。
かといって、ChatGPTの回答を鵜呑みにするとハルシネーションで無駄な時間を使われることもある。
そこで「**ChatGPTに質問する → ドキュメントの特定のページを示してもらう → そのページを自分で読む**」という手順を踏むと、いい具合に調査時間を減らした上で、ハルシネーションに騙される可能性を減らすことができる。
つまり「**自分の代わりに速読して見当をつけてくれる係**」として、ChatGPTを活用するということである。

## レスポンシブ対応はどこまですべきか？

特に JavaScript の開発をしているときに思うのだが、「一度PCビューで開いたあと、SPビューに縮めたら動作がおかしくなった」、あるいは逆に「SPビューで開いたあと、PCビューまで広げたら動作がおかしくなった」というケースは、一体どこまで対応すべきなのだろうか。

JavaScript の場合、完璧に対応しようと思えば、様々な関数にいちいち resize のイベントリスナーを付けなければいけないことにある。しかし、その設定を付けすぎると今度は動作が重くなるのではないか、という不安がある。

デバッガーはPC/SPビューを切り替える特殊な見方をするが、一般的なウェブ利用者が頻繁にブラウザ幅を変更しながら見ているとは思えない。
しかし最近気づいたのだが「**スマホにおいて、縦持ち←→横持ちを切り替えながら見る**」ことは十分ありえる話である。少なくとも、このぐらいは最初から対応範囲に入れて開発するほうが、あとあと修正する手間を減らせそうである。
Spring BootでのDBアクセス効率化とパフォーマンス改善の話

## はじめに
今回は、収支の内訳を分析して、お金の使われ方をCSVにまとめるバッチ処理をSpring Bootで作成したお話。最初は30分くらいで終わっていた処理が、気づけば1時間半もかかるように…。これはおかしい、ということで原因を探ることにしました。

## 問題の原因
調べてみると、原因はDBへのアクセス方法でした。DBからデータを取ってくる際に、一気に取得するのではなく、1件ずつ個別に取り出していました。

どうしてこんな設計にしてしまったのかというと、数万件あるデータの中から必要なものだけを効率的に取得しようと考えたからでした。大量データを全部持ってきてアプリ側で処理するよりも、必要なデータだけをその都度DBから引っ張ってくる方が速いかなと。

### 実際にやってしまった実装
例えば、こんなふうに1件ずつデータを取得するコードを書いていました。

```
for (String id : targetIds) {
    Data data = dataRepository.findById(id);
    // データを集計・計算
}
```

でもこの方法だと、targetIdsの件数分だけDBにアクセスすることになります。数万件のデータを1件ずつ取ってきては処理…となるため、時間がかかってしまっていたみたいです。

## 解決策：一括取得とMap・Setの活用
処理時間を短縮するために、以下の方法を試してみました。

### DBから一括取得する
必要なデータを最初にまとめてDBから取得しておけば、DBアクセスの回数を大幅に減らせます。たとえば、findAllByIdを使って、まとめてデータを取得しました。

```
List<Data> dataList = dataRepository.findAllById(targetIds);
for (Data data : dataList) {
    // データを集計・計算
}
```
こうするとDBへのアクセスは1回で済むため、処理時間が一気に短くなりました！

MapやSetを使ってさらに効率化
一括で取得したデータをループ内で効率よく処理するため、MapやSetを使いました。これにより、特定のIDでの検索や重複チェックを高速に行えるので、処理速度が多少はアップしました。

```
// 取得したデータをMapに変換
Map<String, Data> dataMap = dataList.stream()
    .collect(Collectors.toMap(Data::getId, Function.identity()));

for (String targetId : targetIds) {
    Data data = dataMap.get(targetId);
    if (data != null) {
        // データを集計・計算
    }
}
```
こうすることで、IDでの検索が高速化され、リストを1件ずつループして探すよりも効率的です。

## 結果
この改善により、処理時間は元の30分程度に戻りました。DBアクセスの回数が減ったことで、パフォーマンスが向上しました。

## 感想
時と場合にもよるとは思いますが、DBアクセス回数を減らすことの重要さを知りました。

実際は先輩から改善できないのかを聞かれるまでは、時間がかかってもしょうがないのかなと思っていたので、これでいいのかと常に疑問を持てるよに訓練していきたいです。
Cursor: 利用できるようになったo1-miniおよびo1-previewについて

## **o1-miniとo1-previewの解説**

- **o1-mini**:
    - [OpenAI o1-mini | OpenAI](https://openai.com/index/openai-o1-mini-advancing-cost-efficient-reasoning/)
- **o1-preview**:
    - [Introducing OpenAI o1 | OpenAI](https://openai.com/index/introducing-openai-o1-preview/)

## **利用するのに適切なシーン**

- **o1は明確に定義された推論集約型の問題に優れている**:
    - o1モデルは、具体的な条件や要件がある問題に対して、論理的な推論を行う能力が高いことを示しています。
- **ほとんどのタスクにはsonnet/4oを推奨**:
    - 一般的なタスクには、sonnetまたはgpt-4oモデルを使用することを推奨しています。これは、o1モデルが特定の問題に特化しているため、汎用性の高いタスクには他のモデルが適しているという意味です。

https://x.com/cursor_ai/status/1834665828308205661

## **コスト**

公式には記述がなく、開発者フォーラムで共有されてたPrice Tableを参照してます。管理画面に利用数が表示されてないので、間違ってる可能性があります。参考までにどうぞ。

> Chat, Cmd-K, Terminal Cmd-K, and Context Chat with o1-preview: 40 cents per request.
Chat, Cmd-K, Terminal Cmd-K, and Context Chat with o1-mini: 10 requests per day included in Pro/Business, 10 cents per request after that.
> 

1. **o1-preview**:

- 各リクエストに対して40セントの料金が発生します。
- つまり、o1-previewを使用する際は、リクエストごとにコストがかかるということです。
- **o1-mini**:
    - ProまたはBusinessプランでは、1日に10回のリクエストが無料で含まれています。
    - その後は、追加のリクエストごとに10セントの料金がかかります。
    - つまり、最初の10回は無料で、それ以降は有料になるということです。

## **o1-miniの利用手順**

- **Cursorアカウントの作成**
    - Cursorの公式ウェブサイトでアカウントを作成します。
- **Proプランへのアップグレード**
    - o1-miniを利用するためにはProプランへの加入が必要です。
- **リクエストの送信**
    - o1-miniまたはo1-previewをチャットで選択してリクエストを送信します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4019/af3c3ca7-ce04-8ae3-c1ec-71cbc58b2b5a.png)
Cursor: AI レビューの使い方

### **AI レビュー (ベータ版)**

AI レビューは、コードベースの最近の変更をレビューして潜在的なバグを検出できる機能です。

### [**](https://docs.cursor.com/advanced/ai-review#custom-review-instructions)カスタムレビューの手順**

- Cursor Settings → Beta → AI Reviewで機能が利用できるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4019/f6e15992-71f4-27e5-0703-4d539bf10177.png)

### カスタムインストラクション

AIレビューを効果的に活用するためには、AIに焦点を当ててほしいポイントをカスタムインストラクションとして提供できます。たとえば、コードのパフォーマンスに関する問題を重点的に確認してほしい場合、次のように指示します：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4019/5326f371-271e-11c6-20f2-5f5fae316d89.png)

このように指示することで、AIはコードの変更点を確認する際にパフォーマンスに関連する問題を優先的に検出・改善しようとします。

### [**](https://docs.cursor.com/advanced/ai-review#review-options)オプションの確認**

レビューはいくつかのオプションから選択できます。

- **`Review Working State`**
    - これにより、コミットされていない変更が確認されます。
- **`Review Diff with Main Branch`**
    - これにより、現在の作業状態とメイン ブランチ間の差分が確認されます。
- **`Review Last Commit`**
    - これにより、最後に行ったコミットが確認されます。

### 注意点

- 日本語で返すように書いても、現状は英語でレビュー結果が返ってくるようです。日本語で結果を返す方法を見つけたら教えてください。

## 参考

[Cursor - Build Software Faster](https://docs.cursor.com/advanced/ai-review)
Cursor: Chatでの効率的な複数ファイル・フォルダ選択テクニック

## 概要

Cursorは、アプリケーション開発を効率化するための強力なツールであり、その中核機能の一つがAIチャットです。複雑な開発作業において、AIチャットに複数のファイルやフォルダを同時に提供する必要性が頻繁に生じます。

そこでCursorは、この課題に対応するため、AIチャットに複数のファイルを効率的に渡すための多様な選択方法を提供しています。本記事では、ファイル数やシチュエーションに応じた最適な選択テクニックを紹介し、Cursor内のAIチャット機能をより効果的に活用する方法を解説します。

## 主要機能の説明

1. **@Files**: 個別のファイルを素早く選択するためのコマンド
2. **@Folders**: フォルダ単位で効率的に選択するためのコマンド
3. **Add context**: 多数のファイルを連続して選択するための機能

## シチュエーション別の選択テクニック

### 1. 少数ファイルの迅速選択：@Filesの活用

2〜3個程度のファイルを選択する場合、@Filesコマンドが効果的です。

使用方法：

1. @キーを入力し、コマンド一覧から「Files」を選択します。
2. 表示されたファイル一覧から必要なファイルを選びます。

便利な機能：

- @の後にファイル名を入力すると、予測変換でファイルを絞り込めます。
- これにより、目的のファイルをより迅速に特定できます。

### 2. フォルダ単位の効率的選択：@Foldersの利用

関連ファイルがまとまったフォルダを選択する場合、@Foldersコマンドが最適です。

使用方法：

1. @キーを入力し、コマンド一覧から「Folders」を選択します。
2. 表示されたフォルダ一覧から必要なフォルダを選びます。

メリット：

- フォルダ内の全ファイルを一括で選択できます。
- プロジェクトの構造に基づいた効率的な選択が可能です。

### 3. 多数ファイルの連続選択：Add contextの活用

約10個程度のファイルを個別に選択する場合、Add context機能が効率的です。

特徴：

- 複数のファイルを連続して選択できます。
- 選択操作ごとに画面が閉じないため、スムーズな作業が可能です。

使用方法：

1. Add context機能を起動します。
2. ファイル一覧から必要なファイルを次々と選択します。
3. 選択したファイルは自動的にAIチャットに読み込まれます。

## 選択方法の比較表

| 機能 | 最適な使用シーン | 選択可能数 | 特徴 |
| --- | --- | --- | --- |
| @Files | 少数の特定ファイル選択 | 1〜数個 | 予測変換による素早い絞り込み |
| @Folders | フォルダ単位の一括選択 | フォルダ内全て | プロジェクト構造に基づく効率的選択 |
| Add context | 多数のファイル個別選択 | 〜10個程度 | 連続選択によるスムーズな操作 |

## まとめ

Cursorの多様なファイル・フォルダ選択機能を適切に活用することで、内蔵されたAIチャット機能を用いた開発作業の効率を大幅に向上させることができます。シチュエーションに応じて@Files、@Folders、Add context機能を使い分けることで、AIチャットに最適なコンテキストを提供し、より的確な支援を受けることが可能になります。

これらのテクニックを駆使することで、複雑なアプリケーション開発においても、Cursorのインテリジェントな機能を最大限に活用し、効率的なファイル管理と編集が実現できるでしょう。Cursorの高度な機能を使いこなし、AIとの協働による生産性の高い開発環境を構築しましょう。
CursorとChatGPT 4o with canvasの違い

### 概要

AI技術を活用したプログラミング支援ツールとして「ChatGPT 4o with canvas」と「Cursor」が注目されています。どちらも開発者のワークフローをサポートしますが、それぞれ異なる強みがあります。本記事では、この2つのツールの特徴を比較します。

### ChatGPT 4o with canvasとは？

ChatGPTの"Canvas"機能は、10/4に追加されました。チャットベースのインターフェースに加え、特定のコンテンツやコードを別のエリアに表示することで、チャットの流れを維持しつつ集中して作業を進められます。

**特徴：**

- **集中した作業環境**：コードや文章を「キャンバス」に表示することで、チャットから独立した作業が可能。
- **コンテキスト保持**：生成したコンテンツをキャンバスに分離し、対話を崩さず複数のタスクを同時に処理できる。
- **マルチドキュメントサポート**：複数のキャンバスを管理できるため、異なるプロジェクトやアイデアを同時に扱いやすい。

### CanvasとCursorの違い

| 比較項目 | ChatGPT 4o with canvas | Cursor |
| --- | --- | --- |
| **動作環境** | Webブラウザ。現状はモバイルアプリでは利用できない | VSCodeクローンの専用エディタアプリ |

### Cursorの代表的な機能とCanvasの実装状況

Canvasの機能は間違いがあるかもしれません。機能を見つけたら、補足をお願いします。

| 比較項目 | ChatGPT 4o with canvas | Cursor |
| --- | --- | --- |
| **チャット機能** | あり | あり（コードベース全体を参照可能） |
| **インラインチャット機能** | あり | あり |
| **自動補完** | なし | 高度なコード補完 |
| **コード生成** | なし | あり |
| **マルチライン編集** | なし | あり |
| **スマートリライト** | なし | あり |
| **カーソル予測** | なし | あり |
| **コードベース検索** | なし | あり |
| **コード参照（@記号）** | なし | あり |
| **画像利用** | なし | あり |
| **ウェブ検索** | なし | あり |
| **インスタント適用** | なし | あり |
| **ドキュメント参照** | なし | あり |
| **⌘ Kによる編集** | なし | あり |
| **クイック質問** | なし | あり |
| **ライティングに特化したショートカット機能** | あり | なし |

### Canvasのショートカット機能について

右下から選択可能して、以下のショートカットを選択可能です。

- 絵文字を追加する
- 最終仕上げを追加する
- 読解レベルの変更
- 長さの調節
- 編集を提案する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4019/3d623369-6f1b-8fd2-a050-e646b3b17fbd.png)

### Canvasを試す手順

1. **ChatGPTにアクセス**：ChatGPT 4.0にアクセスし、プロプランにサインアップ。
2. **ChatGPT 4o with canvasの起動**：左上のメニューからChatGPT 4o with canvasを選択する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4019/a74e0988-ef47-ed7a-cfb8-700fb2b9659c.png)

    
3. **ChatGPT 4o with canvasのチャット欄にトリガーワードを記述**: 「記事」「書いて」「コード」等のトリガーワードをチャット欄に記述すると反応してCanvasが起動します。

### どちらを選ぶべきか？

- 文章の編集を手軽に試したいならCanvasが最適。
- 本格的にプログラミング効率を上げたいならCursorが有力です。

### まとめ

ChatGPT 4o with canvasとCursorは、それぞれ異なる目的に特化した強力なツールです。目的に応じて使い分けることで、作業効率が向上します。
ウェブ開発の未来：AIの台頭と開発者のキャリア展望

昨今のウェブ開発業界は大きな転換期を迎えています。

Vercelがアイデアを説明するだけでウェブサイトを作成できるツール(v0)をローンチし、QuickJSの開発者たちはFigmaのデザインを数分でコードに変換できると約束しています。さらに、開発者向けの新しい生成AIモデルが次々と登場しているのが現状です。

## 激変する開発環境

15年のキャリアを持つウェブ開発者として、私たちは重要な岐路に立っています。確かにテクノロジーは常に急速な進化を遂げてきましたが、今回の変化は異質です。新しいAIツールは単なる作業効率の改善にとどまらず、熟練の開発者が担ってきた業務を自動化しているのです。

- レスポンシブレイアウトの構築
- デザインのコード化
- 複雑なロジックのデバッグ

これらの作業が次々とAIに委ねられつつあります。

## 楽観論への疑問

「AIによる自動化で、開発者はより高次な戦略立案や創造的な問題解決に集中できる」という意見をよく耳にします。しかし、この主張には懐疑的にならざるを得ません。歴史的に見ても、自動化は以下のような結果をもたらすことが多いのです：

- より短いデッドライン
- より高い期待値
- より速いペースでの成果物の要求

## 生き残りのための戦略

### 1. 参入障壁の上昇を認識する

基本的な開発タスクがAIで処理可能になった今、エントリーレベルの機会は減少しています。シニア開発者1人でジュニア開発者数人分の仕事をこなせるようになりつつあります。

### 2. 「なぜ」を理解する

AIが「どのように」を処理できる時代には、「なぜ」の理解が不可欠です：

- ビジネスニーズの把握
- ユーザー体験の理解
- 戦略的判断の重要性

### 3. より優れた開発者になる

- アルゴリズムとデータ構造の習得
- ハードウェアやネットワークレイヤーとの相互作用の理解
- システム言語や組み込みプログラミングの学習
- ゲーム開発やDevOpsなど、異分野への探求

### 4. ジェネラリストとしての価値

AIは特定の分野で深い知識を持つことができますが、人間の強みは：

- 異なる文脈間の切り替え
- 生成された出力の適切な組み合わせ
- 開発環境全体の包括的な理解

### 5. フレームワークへの依存度低下

2024年、ウェブ開発のフレームワーク戦争は終わりに近づいています：

- 開発者体験とパフォーマンスの標準化
- フレームワーク間の移行の容易さ
- ツールの相互運用性の向上

## 結論

ウェブ開発は確かに変化していますが、それは必ずしも職業の消滅を意味するものではありません。
むしろ、適応力と学習能力を持つ開発者にとって、新たな機会の時代が始まろうとしています。
重要なのは、この変化を受け入れ、自身のスキルを継続的に進化させていく姿勢です。
Cursor: Notepad機能の使い方

## 1. Notepad機能の概要

CursorのNotepad機能は、アイデアのブレインストーミングやファイルの参照に便利な機能です。保存した情報を簡単に参照でき、文脈に沿った具体的な質問や効率的な情報交換を可能にし、問題解決や学習プロセスを効果的に支援するツールです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4019/f1b5a8be-fa9f-dad8-02e3-78869ad85504.png)

## 2. ComposerからNotepadの呼び出し方

1. Cursorアプリケーションを開きます。
2. CursorでComposerを立ち上げて、右上からControl Panelを立ち上げます。Composer が有効になっていると Cmd + i ショートカットを実行するとエディターの下部に Composer のパネルが表示されます。
    
    [Cursor エディターの Composerが進化！ Control Panelで開発がもっと楽しく](https://zenn.dev/chachamame/articles/d8d65e4418db17)
    

直接Notepadを呼び出す方法がわからないので、わかる方いたらコメントください！

## 3. Notepadの設定方法

1. 新しいノートを作成:
    - 「新規ノート」ボタンをクリックします。
    - ノートにタイトルを付けます。
2. テキストの入力:
    - ノート本文にテキストを自由に入力します。

## 4. Notepadの呼び出し方（Chat）

- チャット機能で、@Notepadシンボルを使用して以前に作成したNotepadを呼び出すことができます。これにより、保存された情報を参照しながら、より具体的で文脈に沿った質問をすることが可能になります。このNotepadの内容を基に、より詳細で的確な質問を投げかけることができ、効率的な情報交換や問題解決につながります。

## 5. 便利な利用シーン

- プロジェクトのアイデア出し
- 重要なファイルパスの記録
- タスクリストの作成と管理
- 頻繁に使用するコードスニペットの保存
- システムプロンプトをNotepadに保存しておいて、状況に応じて切り替える

## 6. 公式ドキュメント

- まだなさそうです。
CursorのComposerとChatの使い分け

## はじめに

Cursorエディタには、AIを活用した2つの主要な機能があります：ComposerとChatです。これらの機能の特徴と使い分けについて解説していきます。

## 機能比較表

| 機能 | Composer | Chat |
| --- | --- | --- |
| コンテキスト理解 | 自動的に現在のファイルを紐づける。関連ファイルを自動提案する。 | 初期状態では無し（手動で共有が必要） |
| 主な用途 | コード生成・編集 | 一般的な質問・説明 |
| 履歴管理 | コントロールパネルに自動保存 | チャット履歴を選択可能 |
| UI | インラインメニューで利用可能。サイドメニューでも表示可能 | サイドメニューのみ |
| コードブロックの実行 | できない | 可能 |

## Composer機能の特徴

### 長所

- コードの生成と編集に特化
- ファイルを開いた時点で、現在のファイルと関連ファイルのコンテキストを自動的に理解。関連ファイルを自動提案する。
- プロジェクト構造やインポート関係を考慮した提案が可能
- コントロールパネルに履歴が保存され、後から参照可能
- インラインでのコード編集が容易

### 短所

- 履歴の簡易選択ができない

## Chat機能の特徴

### 長所

- 一般的な質問や説明の取得に最適
- 以前のチャットにすぐ切り替えられる
- コマンドをコードブロックで回答させると、「Run」ボタンのクリックでCLIコマンドを実行させることができる。

### 短所

- 初期状態ではコンテキスト情報を持っていない
- 必要なコードやファイルは手動でチャットに共有する必要がある

## 使い分けのポイント

### Composerを使うべき場面

- コンテキストがシンプルなコードの修正

### Chatを使うべき場面

- コンテキストが大きめのコードの修正
- コードの概念や使い方の質問
- エラーメッセージの解析
- 一般的なプログラミングの質問
- 長期間コンテキストを維持して作業する場合

## まとめ

ComposerとChatは、それぞれ異なる用途に最適化された機能です。開発のシーンに応じて適切に使い分けることで、より効率的な開発が可能になります。Composerはコンテキストが短めのコード開発に、Chatはコンテキストが長めの作業に、というように場面に応じた使い分けがおすすめです。
atcoder練習(2024.11.13)

# キーワード

# 問題
https://atcoder.jp/contests/abc378/tasks/abc378_c

長さ N の正数列 A=(A_1, A_2, …, A_N) が与えられます。以下で定義される長さ N の数列 B=(B_1, B_2, …, B_N) を求めてください。

i=1,2,…,N について、  
B_i を次のように定義する：  
A_i と等しい要素が i の直前に出現した位置を B_i とする。そのような位置が存在しなければ B_i =−1 とする。  
より正確には、正整数 j であって，  
A_i = A_j となる j<i が存在するならば、そのうち最大の j を B_i とする。そのような j が存在しなければ B_i =−1 とする。  
制約  
1≤N≤2×10^5  
1≤A_i ≤10^9  

入力はすべて整数  
**入力**  
入力は以下の形式で標準入力から与えられる。
N  
A_1  
A_2  
…  
A_N
**出力**  
B の要素を空白区切りで1行に出力せよ。

**入力例 1**  
5  
1 2 1 1 3  
**出力例 1**  
-1 -1 1 3 -1  
i=1:  
A_1 =1 より前に 1 は現れないので、  
B_1 =−1 です。  
i=2:  
A_2 =2 より前に 2 は現れないので、  
B_2 =−1 です。  
i=3:  
A_3 =1 の直前に現れた 1 は A_1 なので、  
B_3 =1 です。  
i=4:  
A_4 =1 の直前に現れた 1 は A_3 なので、  
B_4 =3 です。  
i=5:  
A_5 =3 より前に 3 は現れないので、  
B_5 =−1 です。  
**入力例 2**  
4  
1 1000000000 1000000000 1  
**出力例 2**  
-1 -1 2 1  

# 回答
```
N = int(input())
A = list(map(int, input().split()))

last = {}
B = []

for i in range(N):
  if A[i] in last:
    B.append(last[A[i]] + 1)
  else:
    B.append(-1)
  last[A[i]] = i
    
print(" ".join(map(str, B)))
```

# 参考

# 備考
- 提出形式大事、提出形式が違うだけで結構悩まされていた。
- forをできるだけ減らすかの勝負感がある。アルゴリズムを考えるの大事、いっつも頭の中ではゴリ押しの解法しか思いつかない。もうちょい数学をちゃんと深く勉強していればよかった。
- ゴリ押しの解放しか思いつかないのは手数が少ないからなようか気がする。Pythonの文法をしっかりと理解するのはもちろん、ライブラリ的な発想でまとまった処理についても理解しておくと手数が増えるかも（例えばインプットがそう、なんとなく覚えてきた。）。
Cursor: AI開発アシスタント Clineを導入する手順

# Cline - AI開発アシスタント

Clineは、VSCodeやCursor上で動作する革新的なAIアシスタント拡張機能です。コーディングからプロジェクト管理まで、開発者の作業を包括的にサポートします。

## 主な特徴

- 最新のClaude 3.5 Sonnetのエージェントコーディング機能を使用して、様々なタスクを実行できます
- ファイルの作成・編集
- 複雑なプロジェクトの探索
- ブラウザの使用
- ターミナルコマンドの実行（ユーザーの許可が必要）

### 🔌 対応API一覧

- 利用する場合は、それぞれAPIプロバイダーの設定が必要。Cursorの場合は、APIプロバイダーの設定が不要なので、それと比べると設定が面倒です。

**API**

- [OpenRouter](https://openrouter.ai/)
- [Anthropic](https://www.anthropic.com/)
- [OpenAI](https://openai.com/)
- [Google Gemini](https://deepmind.google/technologies/gemini/)
- [AWS Bedrock](https://aws.amazon.com/bedrock/)
- [Azure OpenAI](https://azure.microsoft.com/products/ai-services/openai-service)
- [GCP Vertex AI](https://cloud.google.com/vertex-ai)
- [Ollama](https://ollama.com/)（ローカルモデル）

### Cursorと同様の機能

- チャットUIによる対話的なコーディング支援
- 各種コンテキストの追加

### 特徴的な機能

- **Computer Useを利用したブラウザ操作機能**
    - Claude 3.5 Sonnet の新しいComputer Use機能により、Cline はブラウザを起動し、要素をクリック、テキストを入力し、スクロールして、各ステップでスクリーンショットとコンソール ログをキャプチャできます。
    - インタラクティブなデバッグ、エンドツーエンドのテスト、さらには一般的な Web の使用が可能になります。
    - これにより、エラー ログを自分で操作してコピー アンド ペーストする必要なく、視覚的なバグやランタイムの問題を Cline が自主的に修正できるようになります。
    - [Introducing computer use, a new Claude 3.5 Sonnet, and Claude 3.5 Haiku \ Anthropic](https://www.anthropic.com/news/3-5-models-and-computer-use)

https://x.com/sdrzn/status/1850880547825823989

## 導入方法

1. Cursorを起動して、左側の「拡張機能」アイコンをクリック
2. 検索バーに「Cline」を入力し、Cline拡張機能をインストール

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4019/2916f914-27f2-3c66-4fb1-cb83190c729e.png)

3. インストール完了後、Clineのアイコンが左サイドバーに追加されます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4019/f94805cf-0f67-5a3b-933b-d3e545705c4d.png)

4. アイコンをクリックし、設定ガイドに従ってAPIプロバイダーとモデルを選択。デフォルトではOpenRouterが選択されている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4019/9b1a06d7-211c-2c2f-7b0f-31862a77eead.png)

※APIキーはローカルに保存され、この拡張機能からのAPIリクエストにのみ使用


5. 設定完了後、プロジェクトでClineを活用開始！

## 参考リンク

- https://github.com/cline/cline
CodeProjectが、多くの記事を閉鎖しています。課題と対応策を検討

プログラミングに関するサイトの、[CodeProject](https://www.codeproject.com/)が、ユーザーから投稿された記事を閉鎖しています。
私もかなり利用していました。以前、利用したコードを確認しようとしたところ、記事を閲覧できないことがわかりました。

次によると、アーカイブとして再公開される可能性があるようです。そうなるといいのですが。
[CodeProject.com is changing](https://www.codeproject.com/info/Changes.aspx)


redditで少し話題になっています。
[codeproject,com is no more :(](https://www.reddit.com/r/cpp/comments/1g6y1l5/codeprojectcom_is_no_more/)


### 課題と対応策

今回の件を踏まえると、大手サイトといえども、突然、情報にアクセスできなくなる可能性があります。
それに備えて、参考にした情報・コードを、手元のPCに保存しておくしか対応策はない感です。ただし、そうするかどうか、悩みます。

例えば、次のようにフォルダに分けて、参考情報を保存していますが、全部の情報ではありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132059/0b496784-d156-a5ff-0b73-ff66f99fa76f.png)

また、URLのショートカットのみを保存しているのも多く、そのページがなくなれば、参照できません。

従って、

- プロジェクトのサンプルは、フォルダに保存
- ウェブサイトのテキストは、OneNoteに保存

が良い感がします。
Git：フェッチとプルの使い分け方は？

Gitにおけるfetchとpullの使い分けは、リモートリポジトリからの情報取得に関する重要なポイントです。

* **git fetch**: このコマンドは、リモートリポジトリから最新の変更を取得しますが、ローカルの作業ブランチには影響を与えません。具体的には、リモートの変更をローカルのリモートトラッキングブランチ（例: origin/master）に保存します。これにより、ローカルの作業を中断することなく、リモートの状態を確認できます。取得した変更をローカルブランチに適用するには、別途git mergeやgit rebaseを実行する必要があります。（上級者向け）

* **git pull**: このコマンドは、fetchとmerge（またはrebase）を一度に実行します。つまり、リモートリポジトリから最新の変更を取得し、それを現在の作業ブランチに自動的に統合します。このため、手軽に最新の状態を反映させることができますが、自動的なマージが行われるため、コンフリクトが発生する可能性もあります。
※使用ソフトによっては、マージON/OFF切り替えあり

### 使い分けのポイント

* **状況による選択**: fetchは、特に複数人で作業している場合や、変更内容を確認したい場合に適しています。一方で、すぐに最新の変更を反映させたい場合はpullが便利です。

* **コンフリクト管理**: pullを使用する際は、コンフリクトが発生する可能性があるため注意が必要です。特に、他の開発者と同時に作業している場合は、まずfetchで変更内容を確認し、その後手動でマージする方が安全です。

このように、fetchとpullはそれぞれ異なる目的と利点がありますので、状況に応じて使い分けることが重要です。
【BizRobo!】Classicブラウザ画面のスクリーンショットを撮りたい！

## はじめに

今回は、 **「Classicブラウザ画面のスクリーンショットを撮る方法」** をご紹介します！

Classicロボットには「スクリーンショット抽出(Extract Screenshot)」機能がありません。
そこで、Classicロボットでスナップショットを取得し、その後BERロボットを使用してスナップショットを画像に変換し、疑似的にスクリーンショットを取得します。

あくまで一例ですので、参考程度にご覧ください！

:::note warn
記事内のロボットは v10.4.0.4 で作成しています。
:::

## 設定方法
前述のとおり、①Snapshotを取得するロボット、②Snapshotをpngに変換するロボットを準備します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3685566/62634e0f-f98c-edb5-bdf5-5e3f2da2fae2.png)

### ①Snapshotを取得するロボット
今回はテストで、https://www.google.com/ を取得しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3685566/32f39afb-f11b-7f4f-8b81-92350a96995f.png)

### ②Snapshotをpngに変換するロボット
複数のSnapshotを変換する作りにしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3685566/d554b78e-71d4-2ece-9c5c-8241ccfee458.png)

[Assign Png ファイル名]では、Snapshotのファイルパスからpngの保存先ファイルパスに割り当てをしています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3685566/98669d22-b9f7-8c6b-e685-f78cc9bdc636.png" width=70%>

上記の処理で、Snapshotで取得したページのスクリーンショットを取得することができます！

## さいごに
ご覧いただきありがとうございました！
ぜひ参考にしていただければ幸いです。
引数の型に演算子または関数を適用できませんでした(SPSS Modeler データ加工逆引き12-4)

# フィールド作成：引数の型に演算子または関数を適用できませんでした　AEQMJ0348E

![スクリーンショット 2024-11-08 10.21.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/542355db-1f5d-f089-e1ae-00d0e9d247ce.png)

## 1.想定されるトラブル

・[フィールド作成]ノードで日付の計算時にエラーが発生する

## 2.サンプルストリームのダウンロード

https://github.com/yoichiro0903n/blue/raw/refs/heads/main/date_difference_ng.str

## 3.サンプルストリームの説明

![スクリーンショット 2024-11-08 10.25.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/995d2b4b-eaad-5f99-816e-a5fcd871f611.png)

a.入力は以下の通りです。

![スクリーンショット 2024-11-08 10.26.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/446f4e51-bf48-c367-1ced-a151595dcc71.png)

[データ型]タブで確認すると[日付]は連続型に定義されています。

![スクリーンショット 2024-11-08 10.27.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/eee14853-78ea-8bd4-e679-5bfc8096a5dc.png)


b.[フィールド作成]ノードを編集します。date_days_difference（A,B）でAとBの日数の差を求めます。Aには列方向に参照するオフセット関数を利用します。[@&#xFFF0;OFFSET(フィールド,1)]でフィールドの値の1行上を参照します。

![スクリーンショット 2024-11-08 10.27.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/ab9f41c1-b3b5-f0d9-4a67-dff2d57a8526.png)

#### エラーの現象を確認する

[テーブル]を実行すると以下のエラーメッセージが表示されます。

![スクリーンショット 2024-11-08 10.28.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/e0d6413b-fcbd-ccf0-17d8-84ef55170c25.png)

#### 連続型を日付型に変更して問題を解決する

c.[置換]ノードを編集します。連続型の[日付]を日付型に置換します。

![スクリーンショット 2024-11-08 10.28.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/98bcc70a-9982-fc0b-fadd-0d63615cc5bc.png)

[テーブル]を実行します。

![スクリーンショット 2024-11-08 10.31.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/2c923bd4-c72a-bd80-9ce7-9d900d059f39.png)


#### 注意事項

cではto_date(日付)としてしまいがちですが、to_date(to_string(日付))のように連続型＞文字列型＞日付型と2段階の変更が必要です。

https://qiita.com/416nishimaki/items/8db8af125916ed8dc811

## 4.参考情報

#### SPSS ModelerのCLEM式でよく使う「日付と時刻」関数

https://qiita.com/Makimaki2020/items/72e3b774039327fa4ac4

#### SPSS Modeler ノードリファレンス目次

https://qiita.com/416nishimaki/private/503037195081d3323eee

#### SPSS Modeler 逆引きストリーム集（データ加工）

https://qiita.com/416nishimaki/items/4bf813e6cba84b2a1008
任意のExcelの指定した列をインポートする方法

```vba

Sub ImportExcelMultipleColumns()
    ' 変数の定義
    Dim fDialog As FileDialog
    Dim filePath As String
    Dim xlApp As Object
    Dim xlBook As Object
    Dim xlSheet As Object
    Dim lastRow As Long
    Dim i As Long
    Dim j As Integer
    Dim targetSheetName As String
    Dim columnList As Variant
    Dim db As DAO.Database
    Dim rs As DAO.Recordset

    ' ファイルダイアログを表示してExcelファイルを選択
    Set fDialog = Application.FileDialog(msoFileDialogFilePicker)
    fDialog.AllowMultiSelect = False
    fDialog.Title = "インポートするExcelファイルを選択してください"
    fDialog.Filters.Add "Excelファイル", "*.xlsx; *.xls", 1

    If fDialog.Show = -1 Then
        filePath = fDialog.SelectedItems(1)
    Else
        MsgBox "ファイルが選択されていません。"
        Exit Sub
    End If

    ' Excelアプリケーションを開く
    Set xlApp = CreateObject("Excel.Application")
    Set xlBook = xlApp.Workbooks.Open(filePath)

    ' インポートしたいシート名と列を指定
    targetSheetName = "Sheet1" ' シート名を指定
    columnList = Array("B", "D", "F") ' 任意の列を指定（例："B", "D", "F" 列）

    ' 指定したシートをセット
    On Error Resume Next
    Set xlSheet = xlBook.Worksheets(targetSheetName)
    On Error GoTo 0

    If xlSheet Is Nothing Then
        MsgBox "指定したシートが見つかりません。"
        xlBook.Close False
        xlApp.Quit
        Set xlApp = Nothing
        Exit Sub
    End If

    ' 最終行を取得（最も長い列の最終行を見つける）
    lastRow = xlSheet.Cells(xlSheet.Rows.Count, columnList(0)).End(-4162).Row ' -4162はxlUp

    ' Accessのテーブルにデータをインポート
    Set db = CurrentDb
    Set rs = db.OpenRecordset("YourTableName") ' 取り込み先のテーブル名を指定

    ' 各列のデータをループしてインポート
    For i = 1 To lastRow
        rs.AddNew
        For j = LBound(columnList) To UBound(columnList)
            rs.Fields("Field" & (j + 1)) = xlSheet.Cells(i, columnList(j)).Value ' 各フィールド名を"Field1", "Field2", "Field3"のように指定
        Next j
        rs.Update
    Next i

    ' 終了処理
    rs.Close
    Set rs = Nothing
    xlBook.Close False
    xlApp.Quit
    Set xlApp = Nothing
    MsgBox "インポートが完了しました。"
End Sub

```
Connection refusedのまとめ

[まとめページに戻る](https://qiita.com/Keiji_otsubo/items/60afc2a8d211b6f7d89f)
[まとめA～M](https://qiita.com/Keiji_otsubo/items/f3ddedee6793bf1576f8)


+ [NET::ERR_CERT_COMMON_NAME_INVALIDのエラー](https://qiita.com/Keiji_otsubo/items/847d3a3b3c8391c9818c)
+ [Data SpiderとSalesforce連携の通信断(Connection refused)](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX000000mure)

Connection refusedを調べてみると一般的には接続自体ができない状態になっている事例が多いです。SSHの問題、ポートが動的に変動してファイヤーウォールで遮断されたような...

+ [tcpdumpで理解するTCPのコネクション拒否 (connection refused)](https://qiita.com/keikmobile/items/407e2f51f23e50839983)

「Connection refused」は、接続しようとしているポートが listen されていないことを示す TCP/IP メッセージです。

https://www.ibm.com/docs/ja/developer-for-zos/15.0?topic=client-rseg1242

# 接続アプリケーション

もう一度設定をみたら、本番環境には接続アプリケーションは作成してませんでした。Sandboxだけに接続アプリケーションを設定しています。考えたら始めはSandboxで接続テストをやっていてうまくできなくて、色々触ってましたが、何故か本番環境は全く問題なかったので接続アプリケーションを作らなかったですね。

 

使っている連携ツールがSandboxに対する機能が今一つだからかもしれません。（本番環境と使えるコマンドが違う）

 

上記から考えると接続アプリケーションの有無はあんまり関係ないかもしれませんね。

確かにPostmanを使う時もプレイグランドでは指示に従って接続アプリケーションを作ったような気がしますが、同じPostmanのIdを使って本番環境にも問題なくアクセスできました（接続アプリケーションは作ってません）

# 気になる設定など

+ [組織にインストールされていないSalesforceの接続アプリケーションを使うときの注意点](https://note.com/kobaryo/n/n516b6e7f942a)

+ 組織の信頼済み IP 範囲の設定

信頼済み IP 範囲で、携帯電話に送信されるコードなど、ID を確認するためのログインの問題が発生することなくユーザーがログインできる、IP アドレスのリストが定義されます。

https://help.salesforce.com/s/articleView?id=sf.security_networkaccess.htm&type=5

+ プロファイルでのログイン IP アドレスの制限

ユーザーのプロファイルで許可される IP アドレス範囲を指定することによって、ユーザーレベルでログインアクセスを制御します。プロファイルに IP アドレス制限を定義すると、その他のすべての IP アドレスからのログインは拒否されます。


+ 信頼できる外部 URL に限定したリダイレクトの許可

信頼できる外部 URL へのリダイレクトのみを許可して、悪意のあるリンクからユーザを保護します。以前は、リンクで Salesforce 外にリダイレクトすることに関してユーザに警告することしかできませんでした。この変更は、最初に Summer '22 で導入されました。Winter '23 では、明確化のためにこのセッション設定の表示ラベルが更新されました。設定の表示ラベルが「Allow redirections to untrusted external URLs (信頼できない外部 URL へのリダイレクトを許可)」になり、オプションは [常に]、[With user’s permission (ユーザの権限がある場合)]、[ブロック] になりました。以前は、この設定の表示ラベルは「次へのリダイレクトを許可」であり、オプションは [すべての外部 URL]、[ユーザの権限があるすべての外部 URL]、[Only trusted URLs (信頼できる URL のみ)] でした。

https://help.salesforce.com/s/articleView?id=release-notes.rn_security_other_block_redirects.htm&release=240&type=5

+ 信頼済み URL の管理

ユーザーやネットワークとのやりとりを信頼する URL を指定します。コンテンツセキュリティポリシー (CSP) ディレクティブを使用して、Lightning コンポーネント、サードパーティ API、WebSocket 接続で各信頼済み URL から読み込むことができるリソースの種別を制御します。[セッションの設定] で Permissions-Policy HTTP ヘッダーを有効にしている場合は、Salesforce からブラウザー機能にアクセスできる URL も制御できます。

https://help.salesforce.com/s/articleView?id=release-notes.rn_security_other_block_redirects.htm&release=240&type=5

+ [Connection refused」は、接続しようとしているポートが listen されていないことを示す TCP/IP メッセージです。](https://www.ibm.com/docs/ja/developer-for-zos/15.0?topic=client-rseg1242)
RSpecで共通のテストを再利用！shared_examplesとinclude_examplesの使い方

# 1. はじめに
RSpecでテストを書いていると、似たようなテストケースが何度も出てきて「コードが重複してしまう…」と感じたことはありませんか？そんなときに便利なのが shared_examples と include_examples です。この2つを使うと、共通のテストケースを1か所にまとめて複数のテストで再利用できるようになります。
今回は、shared_examplesとinclude_examplesの使い方を紹介します！

# 2. shared_examplesとinclude_examplesとは？
shared_examples : 共通のテストケース（例）を定義するための機能。
include_examples : 定義した共通のテストケースをテストで呼び出すための機能。
この2つを使うことで、同じようなテストをいちいち書き直さずに、再利用できるようになります！
###### 基本の使い方
例えば、あるAPIが200のステータスコードでJSON形式のレスポンスを返すかを確認するテストを書いたとします。
```
describe SomeController, type: :controller do
  before { get :index }
  it "returns a 200 status code" do
    expect(response.status).to eq(200)
  end
  it "returns the correct content type" do
    expect(response.content_type).to eq("application/json")
  end
end
```
ここでは、2つのテスト (it "returns a 200 status code" と it "returns the correct content type") を書いていますが、他のエンドポイントでも同じようなテストが必要な場合、毎回同じコードを書くことになり面倒です。
そこで、shared_examplesを使って、共通のテストケースを定義してみましょう！

# 3. shared_examplesを使った共通テストの定義
まずは、共通のテストケースをshared_examplesで定義します。
```
shared_examples "a successful response" do
  it "returns a 200 status code" do
    expect(response.status).to eq(200)
  end
  it "returns the correct content type" do
    expect(response.content_type).to eq("application/json")
  end
end
```
shared_examplesを使って "a successful response" という名前で共通のテストケースを定義しました。この中に「ステータスコードが200であること」と「レスポンスの形式がJSONであること」を確認するテストが含まれています。

# 4. include_examplesで共通テストを使う
次に、テスト内でinclude_examplesを使って、この共通テストケースを呼び出してみましょう。
```
describe SomeController, type: :controller do
  before { get :index }
  # 共通テストケースを呼び出し
  include_examples "a successful response"
end
```
include_examples "a successful response"と書くだけで、先ほど定義した共通のテストケースが実行されます。これで、重複したテストコードを書く必要がなくなり、テストがすっきりします！

# まとめ
shared_examplesとinclude_examplesを使えば、同じようなテストを何度も書く必要がなくなり、テストコードがシンプルになります。特に、異なる条件で同じチェックを行う場合や、共通のレスポンスを確認するテストを書くときに便利です。
RSpecのテストが増えてきてコードが重複しているなと感じたら、ぜひこの方法を試してみてください。テストがすっきりするだけでなく、メンテナンスも楽になると思います。！
Conta規格byスイッチサイエンス(マルチシリアル共有バス)(紹介)(Groveも)


参考

![o_coq634.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/a707f0c5-06a5-6fd2-25aa-9d41f365af1e.jpeg)


https://trac.switch-science.com/wiki/Conta_format


https://www.switch-science.com/pages/conta%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA

https://www.switch-science.com/products/9958

目的
なぜか、ちらちら、広告や誘導で出る用になったので
それほど、わるい規格では、ないので紹介
Grove系で関連付けられている
どうも、24-11-12に発売されたみたい(新商品が優先される?)
(まつたく、利害関係は、ありません)

簡単な紹介

固定式のシリアルマルチバスだと一般の人は、わからないので
まず、共有、共通型の非同期または、同期の順送りの
I2C,SPI,TxRxとGPIOのバス(共通線方式)
をヘッダーとソケットで固定する。
スロット、ソケットは、平面型
類似は、PICに多いmikro BUS

たぶん、スイッチサイエンスは、こども教室をやっているので
そのへんから発想は、出ているのか?
半田なしでぽん付けで学習が行える

今、caa45040的には、M5Stackで採用されている
「Grove」で遊んでいるのでAI等が勝手に紹介か?
I2Cのバスの規格は、いろいろあるが、今の所、
Conta規格で遊ぶ予定は、ない(値段が高い)
LeetCodeを1日1題解いてみる (day14)

14日目に取り組んだ問題はこちら！

# 83. Remove Duplicates from Sorted List

https://leetcode.com/problems/remove-duplicates-from-sorted-list/description/

## 問題文
Given the head of a sorted linked list, delete all duplicates such that each element appears only once. Return the linked list sorted as well.

## 僕の回答 (失敗作)

```py
class Solution:
    def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
        curr = head.next
        prev = head

        while curr:
            if prev.val == curr.val:
                prev.next = curr.next
                if curr.next:
                    curr = curr.next.next
                else:
                    curr = None
            else:
                curr = curr.next
                prev = curr
        
        return head    
```

## 僕の回答 (GPTのヒントあり)
```py
class Solution:
    def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
        if not head:
            return head
        
        curr = head

        while curr and curr.next:
            if curr.val == curr.next.val:
                    curr.next = curr.next.next
            else:
                curr = curr.next
        return head
```
## より効率の良い回答例

```py
class Solution:
    def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
        current = head
        while current and current.next:
            if current.val == current.next.val:
                current.next = current.next.next
            else:
                current = current.next
        return head
```

### コメント
初めは`prev`を使用して管理していたが、試行錯誤してもうまくいかなかったので、GPTにヒントをもらって`curr`のみの実装に変更しました。
ポインターの問題が苦手です...。練習します。

### 次の問題はこちら!
https://qiita.com/h_y_s_d/items/c41910f98f92e2110c0b
OpenMANIPULATOR-X の teleop_keyboard をちょこっと改造

# 初めに
ROS2 foxy 上で、OpenManipulator-x の teleop_keyboard を改造して、指定した動作を連続的にできるようにします。

# 基本操作
ROBOTIS OpenMANIPULATOR-X e-manual で説明されているセットアップが完了している前提です。

e-manual 通りにセットアップされていると、以下のフォルダの中に teleop_keyboard.py があるので、エディタで開いて下さい。
~/colcon_ws/src/open_manipulator/open_manipulator_x_teleop/open_manipulator_x_teleop  

以下の操作を行い、最後の om_teleop.py に上記の teleop_keyboard.py の内容をコピーします。
1行目：すでに存在しているディレクトリに移動します。
2行目：新たにパッケージ open_manipulator_x_teleop1 を作成し、ノード名を om_teleop で設定します。
3行目:om_teleop.pyがあるフォルダに移動します。
4行目:om_teleop.py をエディタで開きます。
``` : 準備操作
cd ~/colcon_ws/src/open_manipulator
ros2 pkg create --build-type ament_python --node-name om_teleop open_manipulator_x_teleop1
cd open_manipulator_x_teleop1/open_manipulator_x_teleop1
gedit om_teleop
```

最初の方の from ... import ...が並んでいる所の最下行に以下を追加します。
```
from time import sleep
```
最後の方の　def main の try: while(rclpy.ok()): の 1 行前に　i=0 を以下のように追加します。さらに、
rclpy.spin_once(om_teleop)の次の行以降を以下のように書き換えます。
if 文の中の命令は、元の teleop_keyboard.py の内容を参考にして、自分の好きな動作に設定します。
```
    i = 0
    try:
        while(rclpy.ok()):
            rclpy.spin_once(om_teleop)
            i = i + 1
            print (i)
            if i == 2:
                goal_joint_angle[0] = 0.0
                goal_joint_angle[1] = 0.1
                goal_joint_angle[2] = 0.1
                goal_joint_angle[3] = 0.2
                pathtime = 5.0
                om_teleop.send_goal_joint_space(pathtime)
                sleep(pathtime)

            if i == 3:
                goal_joint_angle[0] = 0.0
                goal_joint_angle[1] = 0.0
                goal_joint_angle[2] = 0.0
                goal_joint_angle[3] = 0.0
                pathtime = 5.0
                om_teleop.send_goal_joint_space(pathtime)
                sleep(pathtime)

            if i == 4:
                goal_joint_angle[0] = 0.0
                goal_joint_angle[1] = -1.05
                goal_joint_angle[2] = 0.35
                goal_joint_angle[3] = 0.70
                pathtime = 5.0
                om_teleop.send_goal_joint_space(pathtime)
                sleep(pathtime)

            if i > 5:
                break

            for index in range(0, 7):
                prev_goal_kinematics_pose[index] = goal_kinematics_pose[index]
            for index in range(0, 5):
                prev_goal_joint_angle[index] = goal_joint_angle[index]
```
om_teleop.pyがあるフォルダの一つ上のフォルダにあるsetup.py の中の entry_points の部分を以下のように修正します。
```
 entry_points={
        'console_scripts': [
            'om_teleop = open_manipulator_x_teleop1.om_teleop:main'
        ],
    },
```

# 実行方法
以下を順番に別々の端末から実行します。最後の rviz は実行すると、PC画面で実機の動きが確認できます（rvizは実行しなくても可）。
``` : 1,3 行目は e-manual の記載の通り
ros2 launch open_manipulator_x_controller open_manipulator_x_controller.launch.py
ros2 run open_manipulator_x_teleop1 om_teleop
ros2 launch open_manipulator_x_description open_manipulator_x_rviz.launch.py
```

## 参考文献
1) <a href=https://emanual.robotis.com/docs/en/platform/openmanipulator_x/overview/> ROBOTIS OpenMANIPULATOR-X e-manual</a>
Ruby の TCPSocket クラスで memcached のメモリに関する情報を取得する

# やりたいこと

memcached のメモリに関する情報を取得するには stats コマンドを使用する。例えばターミナルでは以下のように行う。

```shell-session
$ echo stats | nc -w 1 localhost 11211 | awk '$2 ~ /bytes/ { print $2": "$3 }'
bytes_read: 17492988
bytes_written: 370282118
limit_maxbytes: 3212836864
hash_bytes: 524288
bytes: 523087
```

- memcached がデフォルトで使用するポート番号は 11211
- `bytes: 523087` が使用しているメモリのサイズ

Ruby でも同様のことを行いたい。

# 方法

[TCPSocket](https://docs.ruby-lang.org/ja/latest/class/TCPSocket.html) クラスを使用する。

```rb
require 'socket'

HOST = 'localhost'
PORT = 11_211

socket = TCPSocket.open(HOST, PORT)
stats = {}

begin
  socket.puts('stats')

  loop do
    line = socket.gets.chomp
    break if line == 'END'

    key, value = line.match(/STAT (?<key>\w+) (?<value>\d+)/).values_at(:key, :value)
    next unless key.include?('bytes')

    stats[key.to_sym] = value.to_i
  end
ensure
  socket.close
end

stats
#=>
# {:response_obj_bytes=>32768,
#  :read_buf_bytes=>81920,
#  :read_buf_bytes_free=>32768,
#  :bytes_read=>17492988,
#  :bytes_written=>370282118,
#  :limit_maxbytes=>3212836864,
#  :launch_time_maxbytes=>3212836864,
#  :hash_bytes=>524288,
#  :bytes=>523087}
```

なお [Active Support コア拡張機能](https://railsguides.jp/active_support_core_extensions.html)の [String#to_fs](https://api.rubyonrails.org/classes/ActiveSupport/NumericWithFormat.html) を使うとサイズの数値が読みやすくなる。第 1 引数に `:human_size` を指定する。

```rb
require 'active_support'
require 'active_support/core_ext/numeric/conversions'

stats.transform_values { _1.to_fs(:human_size, locale: :en) }
#=>
# {:response_obj_bytes=>"32 KB",
#  :read_buf_bytes=>"80 KB",
#  :read_buf_bytes_free=>"32 KB",
#  :bytes_read=>"16.7 MB",
#  :bytes_written=>"353 MB",
#  :limit_maxbytes=>"2.99 GB",
#  :launch_time_maxbytes=>"2.99 GB",
#  :hash_bytes=>"512 KB",
#  :bytes=>"511 KB"}
```

# バージョン情報

```shell-session
$ ruby --version
ruby 3.3.6 (2024-11-05 revision 75015d4c1f) [arm64-darwin24]

$ echo version | nc -w 1 localhost 11211 # memcached
VERSION 1.6.17

$ gem list | grep activesupport
activesupport (8.0.0)
```

# 参考

- [Memcached Documentation](https://docs.memcached.org/)
- [Metrics for Memcached - Amazon ElastiCache](https://docs.aws.amazon.com/AmazonElastiCache/latest/dg/CacheMetrics.Memcached.html)
- [Memcached memory usage - Server Fault](https://serverfault.com/questions/201814/memcached-memory-usage)
WindowsのZscaler環境下でuvを実行する場合

# 発生する問題
uv をZscaler環境下で実行すると以下のようなエラーを出力することがあります。
（ネットワーク（所内・在宅）で変わることもありますが）


```
> uv python pin 3.8.7
> uv sync
error: Failed to download https://github.com/indygreg/python-build-standalone/releases/download/20210103/cpython-3.8.7-x86_64-pc-windows-msvc-shared-pgo-20210103T1125.tar.zst
  Caused by: Request failed after 3 retries
  Caused by: error sending request for url (https://github.com/indygreg/python-build-standalone/releases/download/20210103/cpython-3.8.7-x86_64-pc-windows-msvc-shared-pgo-20210103T1125.tar.zst)
  Caused by: client error (Connect)
  Caused by: invalid peer certificate: UnknownIssuer
```

原因は、ZscalerがSSL検査を行っている場合は通信の中間に割り込み、
uvがMozillaの証明書を使用するため、検証できずエラーになります。

> By default, uv loads certificates from the bundled webpki-roots crate. The webpki-roots are a reliable set of trust roots from Mozilla, and including them in uv improves portability and performance (especially on macOS).

# 対応方法
```
uv sync --native-tls
```

OSが管理する証明書を使えば問題解消できます。
環境変数もあるみたいです。
あと、下記でも対応できましたが、エラーを無視しますし、ホスト毎に設定が必要なので微妙かと。オレオレ証明書の場合は仕方ないかもですが。
[python: uv で trusted-host は、allow-insecure-host](https://qiita.com/baku2san/items/87d6eb38b2d07c473748)

# 蛇足
```
uv add pip pip_system_certs --native-tls
```
とするとちょっと幸せになるかも