OmniAICreator/Qiita-1.07M huggingface dataset:
Node-RED MCU Edition用のTTS(Text to Speech)ノードを作ってみた

# はじめに

Node-RED MCU Edition版の<A HREF="https://protopedia.net/prototype/2345">スタックチャン (Stack-chan)</A>を制作しています。
スタックチャンはサーボモーター x 2個 (Pan, Tilt)とM5Stackデバイス(写真はM5Stack Core2)から構成されます。

![GSC917WbYAAL6gG.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/4837efb0-beb4-d401-bf60-7757bd166908.jpeg)

サーボモーターノードは @background さんが作成しています。

https://flows.nodered.org/node/@background404/node-red-contrib-mcu-servo

Faceノードは @mshioji さんが作成しています。

https://flows.nodered.org/node/@mshioji/node-red-contrib-mcu-draw-face

今回はスタックチャンをしゃべらすノード(TTS=Text to Speech)を作ってみました。

## カスタムノードの作成

画像表示系のカスタムノードを作成した際の記事はこちらです。

https://qiita.com/kitazaki/items/34d8d4a2750259977a84

https://qiita.com/kitazaki/items/5d1324c055828f1acda9

# Moddable SDKのサンプルプログラム

Moddable SDKのサンプルプログラムの中に
examples/pins/audioout/elevenlabs-stream
と
examples/pins/audioout/openai-stream
というプログラムがあります。

# Node-RED MCU Editionのノードへ移植する

画像表示系のカスタムノードを作成したファイルをコピーして、elevenlabs-streamとopenai-streamのサンプルプログラムを移植していきます。

elevenlabs-streamは問題がありませんでしたが、openai-streamはエラーが発生しました。
エラーはModdable SDK 4.9.0で解消しました。
https://github.com/Moddable-OpenSource/moddable/issues/1368

![palette.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/28d05b74-7892-1a54-872d-d231f25ace4b.png)

![palette-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/1163ee2f-9dbd-fea8-6372-85212716a1d9.png)

![flow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/16741d31-a3cd-d918-7fb1-a2997897cdc5.png)

![sample_1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/79f0104a-54b4-02e1-9f57-5ceeb3fac96f.gif)

## npmとNode-REDノードライブラリに登録しましたので、ぜひご利用ください！

### Elevenlabs版

https://flows.nodered.org/node/@kitazaki/node-red-contrib-mcu-elevenlabs

https://npmjs.org/package/@kitazaki/node-red-contrib-mcu-elevenlabs

https://github.com/kitazaki/node-red-contrib-mcu-elevenlabs

### OpenAI Stream版

https://flows.nodered.org/node/@kitazaki/node-red-contrib-mcu-openaistream

https://npmjs.org/package/@kitazaki/node-red-contrib-mcu-openaistream

https://github.com/kitazaki/node-red-contrib-mcu-openaistream

# mp3再生ノード (2024年8月11日追記)

Moddable SDKのサンプルプログラムの
examples/pins/audioout/mp3-resource-stream
を参考にして、mp3ファイルを再生するカスタムノードを作成しました。

![](https://raw.githubusercontent.com/kitazaki/node-red-contrib-mcu-mp3/main/image/palette.jpg)

![](https://raw.githubusercontent.com/kitazaki/node-red-contrib-mcu-mp3/main/image/flow.jpg)

https://flows.nodered.org/node/@kitazaki/node-red-contrib-mcu-mp3

https://www.npmjs.com/package/@kitazaki/node-red-contrib-mcu-mp3

https://github.com/kitazaki/node-red-contrib-mcu-mp3
Stable Diffusionの元開発者が公開した画像生成モデル："FLUX.1"を試しました

昨日Stable Diffusionの元開発者が公開された画像生成モデル"FLUX.1"を使ってみました。非常に性能良かったので、共有したいと思います。

今回公開されたこの"FLUX.1"モデルには3つのバージョン：pro、dev、schnellがあります。前者2つは商用利用不可で、主に高品質な画像制作に使用されます。schnellは商用利用可能で、かつ処理速度が速いのでこれを試しました。（Hugging Faceで使用申請を出して、しばらく待つと利用可能になります。）

schnellが特に興味深かったのは、わずか4ステップで画像を生成できる点です。約半年前に別の4ステップモデルを試した時は、生成された画像の品質がかなり低かったのですが、FLUX.1 schnellの結果には本当に驚かされました。
テストには、Stable Diffusionでもよく使われるデモプロンプト「A cat holding a sign that says hello world（"hello world"と書かれた看板を持つ猫）」を使用しました。以下がschnellで生成された画像です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/ea163530-f635-957f-3da1-3ecadceea505.png)

半年前なら同じクオリティの画像を生成するのに約30秒かかっていたものが、今ではたった5秒程度で生成できるようになりました。

あとはStable Diffusionと比較したいため、Stable Diffusion 3 mediumでも同じプロンプトで生成してみました。⇩

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/4577fc59-4c19-627e-267f-186c11e3bc99.png)

個人的には、schnellの方がより良い仕上がりに感じます。なお、この画像は28ステップで生成したものです。同じく4ステップだけなら生成できませんでした⇩

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/5bbc012b-20b0-8bfc-7fa9-6595df2cbdfc.png)

FLUX.1の開発チームはテキストから動画を生成するモデルも開発しているようです。こちらもかなり期待できそうですね。

興味ある方：

https://huggingface.co/black-forest-labs/FLUX.1-dev
[paiza]コレがSランクだと？（文字列収集 (paizaランク S 相当)

# なんか急に簡単じゃね？
処理自体4行で書けたんだけど、これホントにSランクなの？

https://paiza.jp/works/mondai/real_event/word_collection

# 面倒くさいので画面パタメータをListでもらった後のFunctionだけ
ちなみに引数のListを作ってる箇所は[こっちの記事](https://qiita.com/AsilHatake/items/842548e48ae4a0eae119)に書いてあるYO!!

```javascript:wordCollection.js
// [問題文（原文）]
// あなたは文字列の愛好家で、文字列を収集することにとても熱心です。
// 
// 文字列は市場で高値で取引されています。今、市場には N 個の文字列が出まわっており、文字列 S_i (1 ≦ i ≦ N) の価格は P_i です。 あなたは数ある文字列の中でも、とくに先頭がある特定の文字列で始まる文字列に興味があり、そのような文字列をすべて買い占めたいです。例え、同じ文字列が複数売っていたとしてもそのすべてを買います。
// 
// そこで、市場に出回っている N 個の文字列 S_i とそれぞれの価格 P_i (i ≦ i ≦ N)、また、M 個のクエリ文字列 Q_i (1 ≦ i ≦ M) が与えられるので、それぞれのクエリ Q_i に対し、市場に出回っている文字列の中で先頭が Q_i で始まる文字列すべてを買い占めるのに必要な金額を出力するプログラムを作成してください。
function wordCollection(lines) {
  // 入力は以下のフォーマットで与えられます。
  // 
  // N M
  // S_1 P_1
  // S_2 P_2
  // ...
  // S_N P_N
  // Q_1
  // Q_2
  // ...
  // Q_M
  // 
  // ただし、文字列 S_i, Q_j (1 ≦ i ≦ N, 1 ≦ j ≦ M) は英小文字のみから構成されます。P_i は整数です。
  const [N, M] = lines[0].split(" ").map(v => Number(v));
  const words = lines.slice(1, N + 1).map(line => line.split(" ")).map(([word, price]) => ({ word, price: Number(price) }));
  // それぞれのクエリに対し、必要な金額を一行に出力してください。
  lines.slice(N + 1).forEach(word => console.log(words.filter(w => w.word.startsWith(word)).reduce((acc, cur) => acc + cur.price, 0)));
}

module.exports = {
  wordCollection
};
```

コレなんか引っ掛け有るんか？

# 追記
本記事が、@setowatson 様の方で紹介されまして、
mapやfilterやreduceやらが分かりにくい（繋げて書くとコードが複雑化してしまう）というご感想を頂いたので、
初心者向けに、無課金初期装備（forやifとかの基本構文のみ）で書き直してみたのも公開してみる試みです。
    
https://qiita.com/setowatson/items/d9c471e8d4c500e37414

```javascript:初心者向け
function wordCollection(lines) {
  const [N, M] = lines[0].split(" ").map(v => Number(v));
  
  // 超初心者っぽく書いてみた
  const words = [];
  // 販売されてるアイテムを検索しやすい形(JSONの配列)に変換
  for (let i = 1; i <= N; i++) {
    const item = lines[i].split(" ");
    words.push({
      word: item[0],
      price: Number(item[1])
    });
  }

  // 買い占めたい文字分ループ
  for (let i = N + 1; i <= N + M; i++) {
    // 購入金額合計
    let price = 0;
    for (let j = 0; j < N; j++) {
      // 頭始まりのチェック
      if (words[j].word.startsWith(lines[i])) {
        // 金額の加算
        price += words[j].price;
      }
    }
    console.log(price);
  }
}

module.exports = {
  wordCollection
};
```

コード量的にはだいぶ肥大化したけど、コレなら無課金ユーザでも簡単に読めるよね？（ﾆｯｺﾘ
【MongoDB】ObjectIDを構成するもの

## はじめに
開発環境ですがObjectIDを変更したがために発生した不具合を調査した経験からObjectIDを深堀ってみようと思いたちました。

## ObjectIDとは
MongoDBのObjectIDは、12バイトのデータから構成される識別子で、ドキュメントごとに一意のIDを生成します。ドキュメントを生成する際にObjectIDを指定しなければ自動で生成されます。

## ObjectIDを構成する要素
ただの文字列ではなく3つの要素から構成されていました。

https://www.mongodb.com/docs/manual/reference/method/ObjectId/

- タイムスタンプ（最初の4バイト）
    - Unixタイムスタンプ
- マシン識別子（3バイト）とプロセスID（2バイト）
    - 一意のマシンID。MongoDBインスタンスが稼働しているサーバーを識別するために使用される。プロセスID。同じマシン上で複数のプロセスが同時にObjectIDを生成しても、IDの衝突が防がれる
- カウンター（最後の3バイト）
    - 同じ秒内で生成されたObjectIDが重複しないようにするためのランダムカウンター

## 分解してみる
例：66b5b3d8735ba322ebdbd755

頭から下記の通りに分解できます。
タイムスタンプ: 66b5b3d8（2024-08-07 12:22:48 UTC）
マシンID+プロセスID: 735ba322eb
カウンター: dbd755

## 大小がある
ObjectIDには大小関係がありました。主にタイムスタンプ部分によって決定されます。これにより、ObjectIDを使ってドキュメントの生成時刻の順序を比較したり、ソートしたりすることができます。

## まとめ
MongoDBに限らず他のIDなどにはタイムスタンプや自動増分などの概念がありました。勉強になりました！

## 最後に
私の働いている会社で経験の有無を問わず採用を行っています。
興味のある方は是非カジュアル面談から応募してみてください！

https://jambo-support.com/recruit_engineer/
ReadMeのメモ

ReadMeのメモ

```
## 環境ごとの設定ファイル管理方針

本プロジェクトでは、環境ごとに異なる設定ファイルと全環境で共通する設定ファイルを以下のディレクトリ構造で管理します。この構造により、各環境に適した設定を明確に分離しつつ、共通の設定ファイルを一元管理します。

### ディレクトリ構造
- **環境ごとの設定ファイル**は、それぞれの環境名を持つディレクトリに配置します。
- **全環境共通の設定ファイル**は、`conf`ディレクトリ直下に配置します。

```bash
conf/
├── prod/
│   └── hogehoge.conf
├── stage/
│   └── hogehoge.conf
├── dr/
│   └── hogehoge.conf
├── 全環境共通A.conf
└── 全環境共通B.conf

### 管理方針
- `prod`ディレクトリ: 本番環境用の設定ファイルを配置します。このファイルは実際にプロダクション環境で使用される設定を反映しています。
- `stage`ディレクトリ: 準本番環境用の設定ファイルを配置します。このファイルはステージング環境で使用され、プロダクション環境にデプロイする前の最終テストに使用されます。
- `dr`ディレクトリ: 災害対策環境用の設定ファイルを配置します。このファイルは災害時にプロダクション環境を迅速に復旧するための設定を含んでいます。
- 全環境共通の設定ファイル: すべての環境で共通して使用される設定ファイルをconfディレクトリ直下に配置します。これにより、重複を避け、管理が容易になります。
```
独習C++ 2章

## 2.1 構造体、共用体、列挙体

### 2.1.1 構造体
```
#include <iostream>

struct product
{
   int id;
   int price;
   int stock;
};

int main()
{
   product pen;
   pen.id = 0;
   pen.price = 100;
   pen.stock = 200;
   product * ptr = &pen;

   std::cout << "商品ID: " << ptr->id << std::endl;
   std::cout << "単価: " << ptr->price << std::endl;
   std::cout << "在庫数: " << ptr->stock << std::endl;
}
```

```
#include <iostream>

struct product
{
   int id;
   int price;
   int stock;
};

int main()
{
   product pen = {0,100,200};
   product * ptr = &pen;

   std::cout << "商品ID: " << ptr->id << std::endl;
   std::cout << "単価: " << ptr->price << std::endl;
   std::cout << "在庫数: " << ptr->stock << std::endl;
}
```

We have to write initial values in the same order as they are written in the struct definition.

```
#include <iostream>

struct product
{
   int id;
   int price;
   int stock;
};

void show_product(struct product* ptr)
{
   std::cout << "商品ID: " << ptr->id << std::endl;
   std::cout << "単価: " << ptr->price << std::endl;
   std::cout << "在庫数: " << ptr->stock << std::endl;
}

int main()
{
   product pen = {0, 100, 200};
   product *ptr = &pen;
   show_product(ptr);
}
```

### 2.1.2 共用体
member variable are in the same address.
So, if we change any of them, other variables are changed.

```
#include <iostream>

union U
{
   int a;
   int b;
   int c;
};

int main()
{
   U u = {42};
   std::cout << "u.aのアドレスは " << &u.a << std::endl;
   std::cout << "u.bのアドレスは " << &u.b << std::endl;
   std::cout << "u.cのアドレスは " << &u.c << std::endl;
}
```

### 2.1.3 enum
```
#include <iostream>

enum class category {
   Value1,
   Value2,
   Value3 = 100,
   Value4
};

int main()
{
   category cat = category::Value4;
   std::cout << static_cast<int>(cat) << std::endl;
}
```

列挙体変数が何バイト使うのかを決めるには、underlying-typeを指定する
```
enum class category : char {
   Value1,
   Value2,
   Value3 = 100,
   Value4
};
```

char type is 1 byte. So, in this case, the value of each enum is 0 <= and < 127.
Spring　Framework

## Spring Framework
**そもそもフレームとは?**
枠組み、骨組みを意味する。再利用することで大まかな部分が出来上がっている状態でありよく利用する機能（設計や土台)がまとまっている。

**メリットとしては**
・効率よく開発できる
・品質・保守性が上がるなど
つまり　**Spring Frameworkとはjava言語で使えるフレームワーク**　のことである。
当たり前だがJava言語の知識が必要（まだまだ知識が浅いのでしっかりとつけていきたい:writing_hand:）
開発するうえで、部品化(大きなソフトウェアを独立した小さな機能の塊(コンポーネント))することが大切。

**部品化することにより上記のメリットに加え**
・チームでの開発
・柔軟性の高さ
・テストの容易さ
などがあげられる。変更・追加がしやすく、環境の変化も対応しやすいので柔軟性がある。
**またSpringの特徴として**
・DI(依存性の注入）
・AOP(アスペクト指向プログラミング）
(上2つはまた別でアウトプットする予定)
があげられる。
今さら聞けない sys.argvとは(Python)

今回は，よく登場する「sys.argv」とは何なのか，またその使用例も交えて紹介していきます．

## sys.argvとは
コマンドラインでPythonを実行する際にコマンドライン引数を扱えるようにするものです．
例えば，test.pyというファイルを実行する際，下記の様な引数を指定することを考えます．
```
python test.py -m arg1 arg2
```
ここで指定されたtest1.py，-m，arg1，arg2が**リスト形式**で，sys.argvに格納されます．ここで少し注意点があります．引数だけでなく，指定したpythonファイル名（ここではtest1.py）もリストに格納されるということです．
## sysのインポート
``` python:python
import sys
```
## コマンドライン引数を取得
コマンドライン引数は，sys.argvで，リスト形式で取得できます．
```pythonon:test1.py
import sys
print(sys.argv)
```
``` : コマンドラインからの実行
pyhon test1.py -m 12
```

``` :出力
['test1.py', '-m', '12']
```

ちなみに，sys.argv[0]でリストの1番目（ここではファイル名）等の指定ができます．

与えられた引数のよって処理を変えることもできます．

```python:pyhton
if len(sys.argv) == 1:
    # 引数がない場合（要素数が1、ファイル名のみ）の処理
elif len(sys.argv) == 2 and sys.argv[1] == "hoge":
    # 引数が1つかつその値が"hoge"だった場合の処理
else:
    # ...
    
```

こういう感じでライブラリやOSSは作られているのですね．
ぱっと思いついたのは物体検知のYoloです．
Yoloを実行する際，
```:コマンドライン引数
python detect.py [どの重みを使うか] [どの形式の入力なのか] ...
```
等，たくさんの引数があります．これもsysで指定しているのですね．
difyを自宅環境のdocker composeでデプロイする

# はじめに
difyを自宅で作ってみたかったので記念のメモ。
正直、公式サイトの指示に従ってつくっただけなので学びはゼロです。
超簡単でした


# Docker Desktopをインストールする

https://docs.docker.com/desktop/install/windows-install/

にあるので、DLして実行したらOK。

# dify をデプロイする

https://docs.dify.ai/v/ja-jp/getting-started/install-self-hosted/docker-compose

に従う。

ローカルPCからpowershell起動して
difyを保管しておきたい適当なフォルダへ移動させてからdiryをダウンロード。
自分の場合はC:\Users\user\Documents\github\へ移動してそこでgit cloneしました。

```
C:\Users\user\Documents\github\
git clone https://github.com/langgenius/dify.git
```

docker-composeを実行して起動を待つ

```
cd dify/docker
cp .env.example .env
docker compose up -d
```

数十分ほど待ったら完成

ちゃんと動いたらこんな画面でます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416263/a22568f2-9898-de93-e435-37a2b01042dc.png)

# 起動してるかどうか確認
別のpowershell立ち上げて、コンテナ動いてるか見てみる

```
cd C:\Users\user\Documents\github\dify/docker
docker compose ps
```

こんなの出たら成功
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416263/7d479f97-9957-492a-3003-f91a6e5bc4c5.png)

# difyにアクセスする
PC上でWebブラウザ起動して以下のURL実行

```
http://localhost
```

ログイン画面が出たら成功
アカウント登録してログインしたら、TOP画面が現れるので後は自由に作ってみたらOK。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416263/1cf43a6f-814b-4415-3140-6f5d8049d18f.png)

ただし、ローカルのDifyはあらかじめ使えるAIプロバイダは無いので
各自でAPI Keyを入手するなどして自分なりに設定をしてやる必要があるので注意。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416263/c7899158-d510-4db0-707d-30a7dc52b203.png)

そこ以外はただのDifyなんでご自由にどうぞ。

# 終わりに
AIアプリを作ろうと思ったら、別途でOpenAIからAPI Keyを取得したり何かと準備は必要だけども
自宅でAIアプリを作ることができたのが成果でした。

これができるってことはdocker-composeが動くところであれば
どこでも立ち上げられるから簡単ですね
wordpressの問い合わせフォームからメールが送られなくなった。（WPMailSMTP）

同じことが起こった時に忘れないようにするための備忘録メモ

状況
Gmailを使ってお問い合わせフォームからメールが届くように設定していた。
このサイトとか参照。
https://www.willstyle.co.jp/blog/4556/

症状
ーーー
アドレス不明
ドメイン example.com が見つからなかったため、メールは user@example.com に配信されませんでした。入力ミスや不要なスペースがないことを確認してから、もう一度送信してみてください。
ーーー

というメールが「WP Mail SMTP サマリー〜〜〜」という件名で届いた。
どうやら問い合わせフォームが機能していないようだ。
wordpressのダッシュボードからWPMailSMTPのテストメールもうまく送れていない。

原因？
・wordpressのバージョンを上げた。
・でもエラーはそれよりも前に来てたみたい。

やったこと　googlecloudのクライアントIDなど再度貼り付け直して、でもう一度google連携をした。
google連携は赤いボタンの「Remove OAuth Connection」を押した。
連携されましたとのアナウンスと共にメールが送信されるようになった。
POIで作成するExcelが発生した不具合の調査記録

## 現象
最近javaシステムが作成したExcelを開くとエラーが発生すると報告されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/2bd9420f-4bcc-af17-9528-5a2286ea5ae5.png)
「はい」で修復したらファイルが開けますが、修復ログ情報が出てきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/db9b5394-83ef-88f1-bd7a-7b13cef0a8a2.png)

```xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<recoveryLog xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><logFileName>error101160_01.xml</logFileName>
    <summary>
        ファイル 'C:\Users\mycount\Downloads\XXXXXXX.xlsm' にエラーが検出されました
    </summary>
    <removedRecords>
        <removedRecord>
            削除されたレコード: /xl/workbook.xml パーツ内の名前付き範囲 (ブック)
        </removedRecord>
    </removedRecords>
</recoveryLog>
```

この現象は、一部のファイルしか発生しません。POIバージョンは5.1.0です。

## 分析

### 名称付き範囲
エラー情報には、「名称付き範囲」の言葉は出てきました。その詳細情報は、数式タブの「名称の管理」アイコンで確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/c4b8c32e-9f28-16a3-bc70-521c4f39c2ef.png)

エラー発生するものとエラー発生しないものを比較して、エラー発生する場合、シートに印刷範囲設定と関わる名称付き範囲がなくなっているとわかりました。
- 正常の場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/a0fa8242-a927-7732-62a0-88051f74a10a.png)

- 異常の場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/ad2acdf2-d5a5-3355-fbbd-9d5224a0f1e1.png)

正常の場合のシート名は、「C999999」みたいで、頭文字「C」と数字の後続です。異常の場合のシート名は「C999<font color=red>S</font>99」みたいで、途中も英字があります。


プログラムには、印刷エリアを設定するPOI関数の呼び出しがあります。
```java
Sheet sheet = workbook.getSheet(sheetName);
workbook.setPrintArea(workbook.getSheetIndex(sheet), startCol, endCol, startRow, endRow);
```

### シングルコーテーション
Excelのシート名には、禁則文字があるとずっと以前から知っています。
```
「:」、「\」、「/」、「?」、「*」、「[」、「]」
```
でも「C999<font color=red>S</font>99」のシート名は別に問題なく設定されているので、禁則文字の問題ではないです。

印刷エリアの設定は、修復により削除されたけれど、手動で設定して正常パターンと比較してみて、シングルコーテーションありと気がつきました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/ce469b56-176e-71bf-6f25-a9d404f1a1b0.png)

もし無理やりシングルコーテーションを削除して保存する場合、数式エラーになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/6541d9c8-40ca-5598-ba01-73c4faf849c9.png)

もしかしてPOIはシングルコーテーションを付けていないからのバグでしょうか。

### 最新版テスト
POI最新版の5.3.0をダウンロードして試してみて、エラーが解消されます。

## 原因
新旧POIのソースを比較して以下の違いがあるとわかりました。
シート名にシングルコーテーションを付けるかどうかを判断する関数needsDelimitingに、POI5.3.0にnameStartsWithR1C1CellReferenceの呼び出しを追加されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/26667817-5a64-6dda-81ce-a1bbfc2b97b5.png)

つまりExcel数式に、シート名はもし行とセルの記載に誤認の可能性がある場合、シングルコーテーションを付ける必要です。POI 5.1.0の場合、A1（アルファベット、行番号）形式を対応したが、R1C1（行番号、列番号）形式を対応していません。C999S99の書き方には、「C」の文字はR1C1の識別子になるので、誤認に繋がりました。

## おわり
以上、問題解決＋原因明確、すっきりになりました！
AppleScriptでMacBookをスリープさせない方法

# はじめに
Macbookをスリープさせたくない・・・そう思った時はありませんか？
設定→ロック画面に移動し以下画像３つを全て「しない」に変更すればスリープされません。
しかし、会社貸与PC等はセキュリティソフトのプロファイルにより設定が変更できない場合が多々あります。
そのため、今回簡単に設定できるApple Scriptを活用してこの問題を解決します。
この記事のターゲットを考えて誰でもわかるように記載していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384409/27c22795-1522-d58e-5e14-a5a008df8706.png)

# AppleScriptの設定
Macの標準アプリとして「スクリプトエディタ」があります。
これを開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384409/4e623e10-0c4b-e2d1-6390-e077062aa492.png)


 　　　
スクリプトエディタを開いたら、以下をコピペし、コマンド＋Sで保存します。
```applescript:
tell application "System Events"
	repeat 1000 times
		key down {ASCII character 31}
		key up {ASCII character 31}
		delay 5
		key down {ASCII character 30}
		key up {ASCII character 30}
		delay 5
	end repeat
end tell
```

適当に名前を決めて保存をクリックします。
今回は「スリープさせないツール」という名称で保存します。
再度使いたくなった場合は今回保存したスクリプトファイルから起動すれば良いです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384409/9b394317-b6c4-2d6b-fbdc-0bec35096543.png)

使い方の説明です。
三角の再生ボタンで開始
四角のストップボタンで中止
この２つしか使用しません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384409/3c319bc1-305a-b39c-8202-45e27ecfbd75.png)

コードの中身を説明します。
カーソルキーを１つ下に移動させます→5秒待ちます→カーソルキーを１つ上に移動させます→5秒待ちます
上記操作をループします。
これをMAXで1000回繰り返します。時間で言うと2時間46分程はスリープされません。
無限にもできますが、ここでは敢えて無限にはしていません。
足りない場合は1000に0を加えるなどして保存してください。10倍の27時間47分程になります。
以上。
【paiza】残り物の量 (paizaランクC相当) 問題をPython4行で実行・解説

# 本投稿の趣旨

以下の問題をpythonでコーディングの解説を行います。

https://paiza.jp/works/mondai/c_rank_skillcheck_archive/leftover

:::note 
問題

あなたはスーパーマーケットを経営しています。
今、ある生鮮食品を m[kg] 仕入れました。
とても新鮮だったため、生のまま販売したところ、 
m[kg] のうち p[%] を売ることができました。
次にその売れ残りをすべてお惣菜にして販売したところ、
売れ残った量のうち q[%] が売れました
さて、m[kg] 仕入れたこの食品は最終的に何kg 売れ残ったでしょうか。
ただし、生鮮食品をお総菜にする際は、量を変えることなく調理できるものとします。

:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780099/146ec4e4-064a-52cb-f9ce-ff264a8b737c.png)


# コードの要点
1. 3つの整数m,p,qを受け取る　**←おそらくここが1番難点**
1. 生鮮食品をp%売った後の残りの量を計算
1. 売れ残りを惣菜にしてq%売った後の残りの量を計算
1. 最後に売れ残った量を表示

# コード全体 (4行しかないが…)


```ruby:
# 1.m,p,qを受け取る
m, p, q = map(int, input().split())

# 2.生鮮食品の売れ残りを計算
seisen_nokori = m * (1 - p / 100)

# 3.惣菜の売れ残りを計算
souzai_nokori = seisen_nokori * (1 - q / 100)

# 4.売れ残った量を出力
print(float(f'{souzai_nokori:.4f}'))
```

# コードの解説

###  1. m,p,qを受け取る
```ruby:
m, p, q = map(int, input().split())
```

このコードを実行すると入力欄が表示されます。
そこに任意の m,p,q を入力します。

- input() は操作ユーザーからの入力を受け取る関数です。
例: 「1 80 40」→ ["1 80 40"]

- split() は上記input関数で得た文字列をスペースで分解します。
例:["1 80 40"] → ["1", "80", "40"] 

- map(int, ...) は、このリストの各要素を整数 (int) に変換し、m, p, q の3つの変数に順番に割り当てます。

上記の結果として、m=100、p=20、q=30 という整数値を持ちます。

### 2. 生鮮食品の売れ残りを計算
```ruby:
seisen_nokori = m * (1 - p / 100)
```

p / 100 は「生鮮食品の売れた割合」、1 - p / 100 は「生鮮食品の売れ残った割合」、
m * (1 - p / 100) は「売れ残った惣菜量」を計算します。
例えば、m = 1 , p = 80 なら、1 * 0.8 で 0.2kg が売れ残ります。

### 3. 惣菜の売れ残りを計算
```ruby:
souzai_nokori = seisen_nokori * (1 - q / 100)
```
1 - q / 100 は「惣菜の売れ残った割合」
seisen_nokori * (1 - q / 100) は「惣菜の売れ残り量」を計算します。
例えば、seisen_nokori=0.2 , q = 40 の場合、0.12kg が売れ残ります。


### 4. 売れ残った量を出力
```ruby:
print(float(f'{souzai_nokori:.4f}'))
```

最後に結果の出力です。

ここでは Python のフォーマット文字列 (f-string) を使っています。
souzai_nokori の値を小数点以下4桁まで表示する形式でフォーマットします。
:.4f はフォーマット指定子で、: の後の .4f は「小数点以下4桁まで表示し、それ以上の桁は四捨五入する」という意味です。
例: souzai_nokori が 0.333333 の場合、f'{souzai_nokori:.4f}' は '0.3333' という文字列で表示します。

また、f'{souzai_nokori:.4f}' の結果は文字列 ('0.3333') ですが、それを float 関数を使って浮動小数点数に変換します。
この変換により、末尾の余分なゼロが削除されます。
例: '0.1200' という文字列が float('0.1200') によって 0.12 という浮動小数点数に変わります。
OSINTとは

お久しぶりです。

最近はコミュニティで知り合ったエンジニア仲間と交流したりしていました。

誰かアルゴリズムと離散数学教えてけれ。。。

その中で調べたOSINTについて書いていけたらと思います。
まだツールなどを使いこなせるような段階には至っていないのでとりあえず概念の説明だけします。

## OSINTとは？

OSINTとは(Open Sorce INTelligence)の頭文字をとったもので
簡単に言うとインターネット上で調べられる情報を基にして、セキュリティの抜け穴を洗い出す。
ことを言います。

攻撃者もOSINTを使って攻撃の手法を考えていますから、攻撃者視点に立った時、自分の会社がどのように見えるのかを知ることができます。



:::note alert
もし、実際に試すのであれば自社または自身のPCの情報を収集するだけにとどめてください。試したことでどんな問題が発生しても私は責任を負いません。
:::


## データ、情報、インテリジェンス

OSINTにおけるインテリジェンスとはAIなどで使われる『知能』といいう意味ではなく、軍事用語からきている一種の概念であります。

莫大なデータを収集し、情報を抽出して、そこから判断されるモノ・事がインテリジェンスとなります。

以下にバトルロイヤルゲームを例にとってそれぞれの例を挙げます。


データ
・部屋に落ちているアイテムの数
・銃声の数
・銃声が聞こえた方向
・地形


情報
・敵が持っている銃と敵の数
・自分の銃の発射レートとダメージは？
・位置関係から有利なのはどっち？
・今いる部屋はすでに敵にあさられている？


インテリジェンス
・あさられていて近くで銃声が聞こえるということは敵の物資は整っている可能性が高い。
・過去にこの状況だった時どういう行動したら助かった？
・自分が彼らを攻撃する目的はあるか？
・攻撃したとして予想される被害と利益は？
等になります。

これをIPアドレスなどサイバーセキュリティ用語に置き換えるだけなので概念としては理解しやすいと思います。


ここで得たインテリジェンスを基にして意思決定していきそれぞれの役割分担だったり
人数の割り当ての参考にします。


## フレームワーク
以下にOSINTを活用するうえで参考にできるデータソースを調べるために使えるソースを選定する際に使えるフレームワークのリンクを張っておきます。




https://osintframework.com/

ここでいい感じに使えるデータソースを確認して使っていく形になります。

例えば
ApacheのWebサーバーを使っているサーバがどれだけ公開されているのか？はツールを使えば一瞬でわかります。
そこからCVEとバージョンで絞り込んで攻撃対象を選定していきます。

攻撃対象が選定出来たらあとは目的に合わせてさらに情報収集をしていきます
もちろんここまで検索エンジンを使っているのでターゲットに負担をかけたりする心配もありません。
こうして様々な情報を組み合わせて攻撃の実行に至ります。


## まとめ
簡単に情報が集められてしまう怖さが知れたと思います。

会社に限らずネットに転がっている情報をつなぎ合わせれば個人も簡単に特定できますし
仲間と話していたのは特定厨とかストーカーがセキュリティエンジニアに成ったら最強なんじゃないかという話ですがどう思いますか？
RX631でCDC

ルネサスから提供されていたソースコードはいくつかあって、すでに公式では入手できないものもあるようです。

https://community-ja.renesas.com/cafe_rene/forums-groups/mcu-mpu/rx/f/forum5/4381/usb-pcdc

GR-CITRUSはusb_core.cなどのファイルを使ったRX62Nのサンプルソースを改修されたものが使われています。

オリジナルは公式サイトで見つからなかったのでwrbb-v2lib-firmから引っこ抜いてみました。

https://github.com/yamori813/rx-mrubyc/commit/066d362ec56edb6ce9d6fd49f2955888d6e6c311

結構苦戦して4日くらいかかりました。

usb_hal.cに

```c
#if GRSAKURA
    assignPinFunction(PIN_IO32, 0x11, 0, 0);
    assignPinFunction(PIN_IO34, 0x11, 0, 0);
#elif defined(GRCITRUS)
    assignPinFunction(PIN_IO41, 0x11, 0, 0);
    assignPinFunction(PIN_IO42, 0x11, 0, 0);
#else
#error "no target"
#endif
```

がなくて動かなくて苦労しました。たまたまArudinoのコードを眺めていて気が付きました。

この処理はRX62NにはなくてRX631で追加された機能のようです。

GR-CITRUSは各種サンプルソースを使いArduino互換のライブラリを用意して、その上にmrubyがのっかっているようです。

おそらくArudinoのライブラリはルネサスが作っていて、元になったRX631対応したusb_core.cなどは単体では公開されてなくて、社内のみで使われていた可能性もあります。

ルネサスのサンプルコードはオリジナルのCコンパラ用とgcc用があってgccではコンパイルできないこともしばしばあります。

xmodemを実装したところ、送り側で1バイト毎に1msのsleepを入れなと正しく動作しませんでした。oz_

GR-CITRUSではusb_hal.cのファンクションを入れ替えるHackが入っています。

PCからデータを送っているのにRX631側で読み込みをしないと不安定になるようです。
IBM Cloud Object Storage(ICOS)のバケットが削除できない場合の対処法について

# はじめに
自身が作成したICOSのバケットを削除する際、バケット内が空であるはずなのにバケット削除が出来ず困ったので、解決法をメモ書き程度ですがまとめておきました。

結論から述べるとバケット内に古いバージョンのオブジェクトおよび削除マーカーが残っていることが原因で削除が出来なくなっていました。一度でもバージョニングの設定をオンにしているとオブジェクトを全て削除しても過去に保存したオブジェクトの古いバージョンであったり削除マーカーが残ってしまうそうです。

ですのでこれらを削除してからバケットの削除を実施する必要があります。
削除方法として本記事でs3APIを使用した削除方法を記載します。

参考元としては以下の記事を使用しています。
[AWS CLI を使ってバージョニングが有効化された Amazon S3 バケットを空にしてみた](https://dev.classmethod.jp/articles/aws-cli-remove-files-versioning-s3-bucket/)


# 環境確認

今回使用する環境は以下の通りです。
IBM Cloud Object Storage(Standartプラン),  Smart Tierバケット(region : jp-osa)

バケット内が空のはずですが、バケットの削除に失敗する状態です。

![スクリーンショット 2024-08-09 15.18.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2625926/3ca7b328-cf95-ce40-dd13-027bfab22d21.png)

![スクリーンショット 2024-08-09 15.18.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2625926/e8d9a3dd-7a14-daaa-e9e7-6481e74ee5f9.png)

バージョニング設定をオンにして確認してみると過去のバージョンや削除マーカーが残っていることが確認できます。

![スクリーンショット 2024-08-09 15.19.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2625926/74b1af6c-f6e3-0ece-a244-a3013ad8d04b.png)


また、実施手順でaws CLIを使用するのであらかじめインストールする必要があります。

# 実施手順

## 1. aws　configの設定
はじめに対象となるICOSのサービス資格情報を登録します。
資格情報はポータルのICOSメニューから「サービス資格情報」→「新規資格情報」で作成できます。
S3互換性のある資格情報が必要なので作成時に「HMAC資格情報を含める」をオンにしてください。


作成後、「cos_hmac_keys」の二つの値をaws configureに入力します。
```
$ aws configure
AWS Access Key ID : $ACCESSKEYID
AWS Secret Access Key : $SECRETACCESSKEY
Default region name : $REGION
Default output format : json
```
regionは対象となるバケットのリージョンを入力します。（今回はjp-osa）

## 2. Version + DeleteMakersの削除

続いてs3apiを用いてVersionsとDeleteMarkersの削除を実施します。

```
$ aws --endpoint-url https://$ENDPOINT s3api delete-objects --bucket $BUCKETNAME --delete "$(aws --endpoint-url https://$ENDPOINT s3api list-object-versions --bucket $BUCKETNAME | jq '.Versions + .DeleteMarkers | {Objects: map({Key, VersionId})}')"
{
    "Deleted": [
        {
            "Key": "test1.png",
            "VersionId": "00000185-38b7-1295-06e3-7b14c1c37404"
        },
        {
            "Key": "test2.png",
            "VersionId": "0000018d-1706-10f5-06c2-5b9272eb7cd9",
            "DeleteMarker": true,
            "DeleteMarkerVersionId": "0000018d-1706-10f5-06c2-5b9272eb7cd9"
        },
        ...
    ]
}
```
deletedで削除しきれなかった過去versionやdeletemakerが削除されていることが確認できます。
実際にこの後にバケットの削除を実施すると削除することができました。
正確な 3D スキャンを取得するにはどうすればよいですか?

テクノロジーが進化し続けるにつれて、3D スキャンは複数の業界で重要なツールとなっています。エンジニアリングや建築からヘルスケアやエンターテイメントに至るまで、3D スキャンはオブジェクトの正確な詳細をキャプチャし、さらなる分析とアプリケーションの基礎を提供します。高精度の 3D スキャンを実現するには、機器の選択、スキャン設定、後処理などの複数の要素を総合的に考慮する必要があります。

1. 適切な機器を選択する
正確な 3D スキャンを取得するには、適切な機器を選択することが重要です。現在、市場にある 3D スキャン装置は、主にレーザー スキャナ、構造化光スキャナ、写真測量に分けられます。

![d470c3a44723ac5e38840439e32541ab.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824290/7017783e-59eb-8490-dd85-10204051f286.png)
レーザー スキャナ: レーザー ビームを使用して物体の表面を測定し、飛行時間または三角測量を通じて形状をキャプチャします。レーザー スキャナは幅広い屋外環境に適していますが、より高価です。
構造化光スキャナー: 格子パターンを物体表面に投影し、カメラを使用して変形したパターンをキャプチャすることで 3D 形状を再構成します。この方法は小型および中型のオブジェクトに適しており、高解像度と高速という利点があります。
https://www.revopoint3d.jp/
写真測量: 一連の 2 次元写真から 3 次元モデルを再構築します。このアプローチは安価ですが、データを処理するために高度なソフトウェアと大量のコンピューティング リソースが必要です。

2. スキャン設定と環境
環境条件とスキャンの設定は精度に直接影響します。いくつかの重要な要素を次に示します。
![4a05158e6ad158876099fefd41ff7884.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824290/e7b5f188-6f49-309c-8884-113f63a5419a.png)

照明条件: 強い光や影の影響を避けるために、均一に照明された環境でスキャンするようにしてください。構造化光スキャナは周囲光の影響を非常に受けやすいため、特別な注意が必要です。
スキャン角度と距離: スキャナーから対象物までの距離がデバイスの最適範囲内にあることを確認し、複数の角度からスキャンして完全な詳細をキャプチャします。
安定性: 振動や動きによるデータの歪みを避けるために、スキャン プロセス中にデバイスとオブジェクトを安定に保ちます。

3. データ処理と事後最適化
予備スキャン データを取得したら、後処理は精度を向上させるための重要なステップです。

データ クリーニング: ソフトウェア ツールを使用してノイズと冗長なデータ ポイントを除去し、モデルの純度を確保します。
位置合わせと結合: 複数の角度からスキャンする場合、さまざまなスキャン データを位置合わせして完全なモデルに結合する必要があります。これには通常、ICP (Iterative Closest Point) アルゴリズムなどの特定のアルゴリズムを使用する必要があります。
ディテールの強化とテクスチャ マッピング: 高解像度のテクスチャ マッピングによりモデルの詳細な表現が向上し、よりリアルになります。
エラー修正: ソフトウェア ツールを使用してエラー分析と修正を実行し、モデルの幾何学的精度を確保します。

4. 応用と実践
正確な 3D スキャンにはテクノロジーだけでなく、豊富な実務経験も必要です。アプリケーションのシナリオが異なれば、異なるスキャン戦略と後処理方法が必要になる場合があります。たとえば、医療分野では人体をスキャンする際に生体組織の微妙な違いを考慮する必要があり、建築分野では大規模な構造物の全体的な精度に重点を置く必要があります。
![332307ec18c9de4e2e7119e49131763a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824290/a7c21849-7b12-583c-75fe-24173c42b1dc.png)

継続的な実験と調整を高度な機器とソフトウェアツールと組み合わせることにより、ユーザーはさまざまな複雑な環境で高精度の 3D スキャン結果を得ることができます。今後、さらなる技術革新により、3Dスキャンはより便利かつ効率的になり、さまざまな業界でより幅広い応用の可能性がもたらされます。
Copilotに諭された

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394613/f57a1d4a-84ef-022e-80aa-3c8d50185e2d.png)
そうですよね。Pythonもすごく便利ですよね。
これからもよろしくねCopilot。
Selenium VBAでjavascriptやonclick絡みの処理に関する格闘と考察

# 目的、背景など
業務自動化の一環としてWebスクレイピングを独自に学習しています。
Selenium、VBAを使ったスクレイピングなんですが、htmlのパスを指定して行いたい処理をやりくりするだけに留まっていました。
ですが一部の処理でjavascriptの処理をキックしたい場面があったのですが、その際のVBAの記述の仕方に格闘しました。
なかなか自分好みの記事がなかったので、備忘録がてら投稿したいと思いました。

# 作業環境
* Selenium Basic 2.0.9.0
* Microsoft Visual Basic for Applications 7.1
* Google Chrome バージョン:126.0.6478.182（Official Build）（64 ビット）

# 伝えたいこと
DevToolsから覗いて以下のような ```onclick=``` でJavascriptが指定されているとき、

```ht
<a href="#hogeAction" onclick="hogescript()">
```

Selenium VBAでは以下の記述でJavascriptをキックすることができる。
（多分ほかにも書き方はある）

```vb
driver.ExecuteScript ("javascript:hogescript();")
または
driver.ExecuteScript ("document.querySelector(hogescript());")
```


# 末筆
何か色々書きたいことがあった気もしますが、忘れちゃったので一旦これで投稿します。
リスト名に_　とか- を使うと動きません


009_2Approvalという名前のリストがフローでエラーになったので名前を009-2Approvalとしてコピーしたのでけど...

もう一度作成しようとすると既にあるとのこと

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/8aa70aa0-5d9a-78bf-ebbd-3e7f9aa185bb.png)


しかし、URLをダイレクトに叩いても... 相変わらずの理解できないシステムですね。
これって本当に売り物なのかな？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/d037b2c3-f21d-3648-73ed-426dc2c8389d.png)


今まで散々泣かされてきたので、色々試そうと　0092Approval とURLに入力すると出てきた。
これっておかしくない？　信用できません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/41fc8c57-26f1-3e0b-ad8c-8b5f6681e268.png)


この件で問題になったのは以下ですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/03ce090b-902b-18c3-f619-0fb2a50fe82c.png)


:::note alert
{
  "status": 400,
  "message": "'SP.Data.009_2ApprovalListItem' という名前の型はモデルで解決できません。モデルが使用可能な場合、各型名は有効な型に解決される必要があります。\r\nclientRequestId: 621373a9-a9eb-4a57-a513-12ae699a49df\r\nserviceRequestId: a57f44a1-f0d4-3000-99dd-98f0cda6dfd8",
  "source": "https://xxxxxxx.com/sites/xxxxx/_api/web/lists/GetByTitle('009_2%E5%BC%94%E4%BA%8B%E9%80%A3%E7%B5%A1%E8%A1%A8%EF%BC%88%E7%A4%BE%E5%93%A1%E7%94%A8%EF%BC%89')/items(1)",
  "errors": [
    "-1",
    "Microsoft.SharePoint.Client.InvalidClientQueryException"
  ]
}
:::

最終的にはリストの名前を009_2Approvalから009bApprovalに変えたら問題なく処理できました。
toLocaleDateStringで日付けフォーマット

toLocaleDateStringいつも忘れるのでメモ。

```js
const date = Date.now();
// 1723185748505

const formatDate = new Date(date).toLocaleDateString("ja-JP");
// 2024/8/9
```

オプションも設定できるらしい。
```js
toLocaleDateString(locales, options)
```

時間の表示
```js
const formatDate = new Date(date).toLocaleDateString("ja-JP", {
  hour: "2-digit",
  minute: "2-digit"
});
// 2024/8/9 15:53
```


https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleDateString
DataStageでCSV形式のファイルで"aaaa""bbb"をaaaa"bbbと読み込む方法


# はじめに
DataStageのパラレルジョブのシーケンシャルファイルステージは、"aaaa""bbb"というデータをaaaa"bbbと読み込むことができないらしいので、何かいい方法はないかと探してみました。

 いろいろ探していたら、External Sourceステージというステージがあるらしい。そのステージは外部のコマンド・プログラムを実行して、その出力をステージが受信して、次のステージに流すことができるらしいことがわかりました。
また、pythonのcsvモジュールを使うと aaaa"bbb と読み込めることがわかりました。

この２つの組み合わせを使ったら、期待通りに読み込むことができたので、その方法をメモしておきます。

　
# 準備
(環境はRHEL8)
DataStageがインストールされているマシンにpythonがインストールされていなければインストールします。

　
 # 作業
１．csvモジュールを使用したpythonのコードを作成して/home/dsadm/python/rdcsv.pyとして保存します。
コードのサンプルは以下の通り。
```python:rdcsv.py
#
# https://docs.python.org/3/library/codecs.html#standard-encodings
# https://docs.python.org/3/library/csv.html
#
#
import csv
import pprint
import sys

args = sys.argv

# encode : utf_8, utf_8_sig (utf_8 with BOM), euc_jp, cp932, shift_jis
DEFAULT_ENCODE='utf_8'

# default delimiter
DELIM='\t'

# the number of args
cmdcols = len(args)

if (cmdcols != 2) and (cmdcols != 3):
    print("command line : python3 " + args[0] + " file.csv [encode]")

else:
    if (cmdcols == 2):
        encode=DEFAULT_ENCODE
    else:
        encode = args[2]

    with open(args[1], encoding = encode, newline='') as f:
        reader =  csv.reader(f)
        for row in reader:
            row=DELIM.join(row)
            print(row)
```
rdcsv.pyの先頭のコメントにあるcsv.htmlに記載されているサンプルコードをpython初心者の私が少し変更してみました(UTF-8のファイルを読み込んで、区切り文字はタブ(\t)で出力、ファイルのエンコードも指定できるようにしてみました)。

以下のsample.txt を
```txt:sample.txt
"1","aaaa""bbb"
"2","TokyoChiyoda"
"3","Kanagawa""Yokohama"
"4","Chiba"" Kashiwa """
```
rdcsv.pyで読み込ませて出力させるとこんな感じになります。
$ python3 rdcsv.py sample/sample.txt
1　　　　aaaa"bbb
2　　　　TokyoChiyoda
3　　　　Kanagawa"Yokohama
4　　　　Chiba" kashiwa "
$

２．rdcsv.pyを使用したパラレルジョブを作成します。
こんな感じのジョブ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3857190/7e0e3258-bdc8-05c0-1965-64731dc7ea67.png)
External Sourceステージの設定：
　・ソース・プログラムには、pythonのコマンドラインを記入
　・rdcsv.pyでは、区切り文字はタブ、引用符は無しで出力しているので、[フォーマット]内の指定もそれに合わせて設定

Peekステージからの出力：
Peek_2,0: c1:1 c2:aaaa"bbb
Peek_2,0: c1:2 c2:TokyoChiyoda
Peek_2,0: c1:3 c2:Kanagawa"Yokohama
Peek_2,0: c1:4 c2:Chiba" Kashiwa " 
　
期待する出力を得ることができました。
　
   
# その他
・rdcsv.pyは、入力ファイルの列数が変わっても変更する必要が無いので便利かもしれません。
・pythonのcsvモジュールを詳しく調べればもっといろいろな設定ができそうです。
・テストした環境は以下の通りです。
　　DataStage(InformationServer)：11.7.1.4 
　　python：3.6.8
Reactの状態管理ライブラリRecoilを勉強しようとしたら開発が停止していた話

# はじめに
Reactでちょっとしたシステムを作ってるのですが、状態管理とそれに伴う描画が混とんとしてきたので、もう一度改めて勉強しなおそうと思いました。

結果的に、タイトル通り、Recoilは開発が停止していたということに気づいて使用をやめたのですが、その経緯の個人的な記録、ブログです。

# 経緯
## 1. 状態管理を本で復習
まず以前買った、[React 実践入門](https://www.amazon.co.jp/dp/4815619484)をもう一度開いてみてました。2023年10月発売の本。

状態管理ライブラリは、ReduxとRecoilが有名だけど、本の中ではRecoilを使ったサンプル。

https://redux.js.org/

https://recoiljs.org/

## 2. どうしてもピンとこない
`get`プロパティに`get`関数を渡すRecoil、ネーミングルールどうなってんのとか文句を言いながら模索していましたが、どうしても`selector`での`set`の使い方がピンとこなくていろいろ探ってました。本を（TypeScriptに書き換えながら）写経すると、エラーになるんだけど、根本的にわかってないから、デバッグできない。

わからないのは、私の技術力不足なので仕方ないです。Recoilは何にも悪くない。ググって勉強するしかない。

## 3. ネット上の状況を調べてみた
それにしてもどうも、Recoilは日本語のブログが少ない。上っ面な`selector`の`get`まではあるんだけど、`set`の情報が少なすぎる。Udemyの講座も日本語はなさそうでした。Reduxはたくさんあります。

ということで、人気がないのかなぁと思ってGoogleトレンドを見てみると、Reduxのほうが人気だけど、そうは言ってもある程度はありそう。このグラフとネットの情報量の比率が、合ってない気がしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/722610/9f59b0a6-a50e-f523-715d-a39206bcc87b.png)

ちなみに上は日本。
もしやアメリカでは・・・？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/722610/6dd875b7-4949-e933-204e-ae2080521d6e.png)

なるほど！Recoilはfacebook(Meta)によって開発されているとのことなので、アメリカでは人気なのかー英語しか情報がないのかー。

## 4. 本家に行くしかない
ということで、日本語のブログはあきらめて、本家のチュートリアルとか英語圏のブログとか探ろうと思いました。

[公式ホームページ](https://recoiljs.org/)のチュートリアルをやってみたけど、私がピンとこなかった`selector`の`set`の話はまだ出てこないです。

気分転換に、ホームページgithubを除いてみたら・・・あれ？更新日が、year単位しかない。最終commitは、１年前だ！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/722610/e817ac1a-d599-28f9-10af-ced641793171.png)

何度か調べても同じ。

ちなみに数少ない日本語のブログの中で、ちょいちょい「facebookexperimentalだから注意ね」って書いてありました。facebookの実験用のアカウントということですね。まさに実験して途中でやめたか。


## 5. 私の中でもRecoil停止
ということで、私も、Recoilの使用はやめました。

機能がUpdateされなくてもちゃんと理解すれば動作はするんだろうけど、バグフィックスがされないことと、セキュリティ面の改善がされないということから、更新されないモジュールは使えないです。UIとか表面上のものならともかく、こういうデータのキモとなるようなライブラリは特に。

無念。


# まとめ・所感
ということで、2024年時点では、**Recoilは使わないほうがいい**ライブラリです。技術的にも改善されないし、日本語の情報が少ないから敷居がちょっと高い。
Googleトレンド(日本)で Redux:Recoil = 2:1 くらいだったけど、その1は、たぶん私のようにさまよっている初心者の足跡なんじゃないかと。本もあるくらいだし。

未知のライブラリを使ってみるときは、公式HPとかgithubとかの、**原典を当たることが大事**だなと改めて思いました。リファレンスは以前からそう思っていて公式HPを見ることが多いけど、今回のケースは初めてだったかも。
私は、Reactが出てきたころ(?)のJavaScript関連ライブラリの開発スピードがすさまじかった頃を知らないけど、そのころはこんな感じだったんだろうなぁ。

なお、Recoilにインスパイアされたライブラリとして、**[Jotai](https://jotai.org/)**（状態）というライブラリがあり、こちらは2024年8月現在、更新されています。ちらっとしか見れていませんが、かなり似ている感じがします。興味がある方はそちらも調べてみてください。
私はちょっと疲れたので、気力が回復したら見てみるかもしれません。

本の「**React実践入門**」については私はつまみ食いですが、TypeScriptも書いているし（React x TypeScriptの本は少ない）、丁寧で、わりと好きです。2023年10月発売だから、Recoilの開発停止とほぼ同時で不運だったかもしれません。技術本は、流行り以外にもこういうことがあるから難しいですね。

ではよきReactのライブラリ選択を。
Expressにおけるセキュリティ強化：Helmetについて👷

# はじめに
Webアプリケーション開発において、セキュリティは非常に重要な要素です。攻撃者が脆弱性を悪用するリスクを最小限に抑えるためには、適切なセキュリティ対策を講じる必要があります。
Express.jsを使用したWebアプリケーションの開発において、これらのセキュリティ対策をシンプルかつ効果的に実装できるライブラリがHelmetです。
この記事では、Helmetの基本機能、インストール方法、主なセキュリティ機能について紹介します。

https://helmetjs.github.io/

https://www.npmjs.com/package/helmet

# Helmetとは？
Helmetは、Node.jsのWebフレームワークであるExpress.jsアプリケーションにセキュリティ関連のHTTPヘッダーを設定するためのミドルウェアです。
これにより、アプリケーションの脆弱性を軽減し、さまざまな攻撃（クリックジャッキング、XSS、MIMEタイプのスニッフィングなど）から保護します。

Helmetのインストール
以下のコマンドでインストールできます。

```
npm install helmet
```

インストール後、アプリケーションにHelmetを追加するためのコードは非常に簡単です。Helmetをミドルウェアとして使用することで、デフォルトのセキュリティヘッダーが設定されます。


``` javascript
const express = require('express');
const helmet = require('helmet');

const app = express();

app.use(helmet()); // セキュリティヘッダーを設定
```

「app.use(helmet())」と指定すれば、デフォルトの設定がされます。
もし、それぞれのセキュリティに対して、細かい設定を行いたい場合は、別途、行うことができます。

# Helmetの主な機能
Helmetは複数のセキュリティ機能を提供しており、それぞれの機能は特定の脅威に対する保護を提供します。以下は、Helmetが提供する主な機能です。

## Content Security Policy（CSP）
CSPは、XSS（クロスサイトスクリプティング）攻撃を防ぐための機能です。スクリプトやスタイルシート、画像など、外部リソースのロードを制御します。

```javascript
app.use(helmet.contentSecurityPolicy({
  directives: {
    defaultSrc: ["'self'"],
    scriptSrc: ["'self'", "trusted-scripts.com"]
  }
}));
```

## X-Frame-Options（クリックジャッキング対策）
クリックジャッキングは、攻撃者が被害者を騙して意図しない操作を行わせる攻撃です。X-Frame-Optionsヘッダーは、Webページがiframeやframe内に表示されないように設定できます。

```javascript
app.use(helmet.frameguard({ action: 'deny' }));
```
## HSTS（HTTP Strict Transport Security）
HSTSは、ブラウザがHTTPを使用してWebサイトにアクセスするのを防ぎ、常にHTTPSを使用するように強制します。

```javascript
app.use(helmet.hsts({
  maxAge: 31536000, // 1年
  includeSubDomains: true, // サブドメインも含む
  preload: true
}));
```

## X-XSS-Protection
このヘッダーは、ブラウザにXSSフィルターを有効にするよう指示します。ほとんどの最新のブラウザでは既にデフォルトで有効になっていますが、Helmetを使ってさらに強化できます。

```javascript
app.use(helmet.xssFilter());
```
## MIMEタイプのスニッフィング対策
X-Content-Type-Optionsヘッダーは、ブラウザが宣言されたMIMEタイプに従うように指示し、MIMEタイプスニッフィングを防ぎます。

``` javascript
app.use(helmet.noSniff());
```

## Helmetのカスタマイズ
Helmetはデフォルトで上記のすべての機能を有効にしますが、個別の設定も可能です。特定の機能だけを有効にしたり、必要に応じて設定をカスタマイズしたりすることができます。

例えば、HSTSだけを有効にし、他の機能を無効にするには次のようにします：

```javascript
app.use(helmet.hsts({
  maxAge: 31536000,
  includeSubDomains: true
}));
```
# まとめ
Helmetは、Express.jsアプリケーションにおけるセキュリティを向上させるための強力なツールです。HTTPヘッダーを通じて、さまざまな攻撃からアプリケーションを保護し、開発者がセキュリティを強化するのを助けます。特に、HSTSやX-Frame-Options、CSPなどの機能を簡単に導入できる点が魅力です。
セキュリティはWebアプリケーション開発の重要な要素です。Helmetを導入することで、アプリケーションのセキュリティを一段と強化し、安心して利用できる環境を構築しましょう。

また、HelmetはExpressだけでなく、他のライブラリやFW専用のものもあるみたいです。

https://github.com/nfl/react-helmet

https://github.com/jnields/vue-helmet

# 最後に
他にも色々な記事を書いているので、よければ読んでいってください！

https://qiita.com/hukuryo/items/97797a91d7e2ee0bcabc

https://qiita.com/hukuryo/items/2c07c52ff3386d5d75b9

https://qiita.com/hukuryo/items/ebeb26823f944f143b11
k3sでアクセス元のIPアドレスを喪失しないクラスタを簡単に作る方法

k3sは簡単にkubernetesクラスタを構築できて便利ですが、デフォルトの構成では自前のロードバランサーであるservicelb（中身はklipper-lbという1ファイルのshellスクリプト）がアクセス元のIPアドレスを喪失してしまうので、バックエンドからこれを知るのが困難です。
これはきっと外部のCloud LBがフロントに立つ事を想定して、そちらがhttp/httpsなトラフィックに`X-Forwarded-For`や`X-Real-IP`を付加する事を期待しているからでしょう。

しかしせっかく簡単に作れるクラスタなので、外部LBに依存させず独立した構成にしたかったのでその方法をまとめました。

まず普通に デフォルト設定でk3sクラスタを構築します。`--disable=servicelb`オプションを指定しても良いですが、これは後から削除もできます。

次にserverを担当しているホストにログインして `/var/lib/rancher/k3s/server/manifests/traefik.yaml`の中身を以下のように書き換えます。ファイルを書き換えると自動的に helm-installer が設定を反映させようと動き出すので注意してください。

```yaml
---
apiVersion: helm.cattle.io/v1
kind: HelmChart
metadata:
  name: traefik-crd
  namespace: kube-system
spec:
  chart: https://%{KUBERNETES_API}%/static/charts/traefik-crd-25.0.3+up25.0.0.tgz
---
apiVersion: helm.cattle.io/v1
kind: HelmChart
metadata:
  name: traefik
  namespace: kube-system
spec:
  chart: https://%{KUBERNETES_API}%/static/charts/traefik-25.0.3+up25.0.0.tgz
  set:
    global.systemDefaultRegistry: ""
  valuesContent: |-
    additionalArguments:
    - "--log.level=INFO"
    - "--entrypoints.web.address=:80/tcp"
    - "--entrypoints.websecure.address=:443/tcp"
    deployment:
      podAnnotations:
        prometheus.io/port: "8082"
        prometheus.io/scrape: "true"
      kind: DaemonSet
    providers:
      kubernetesIngress:
        publishedService:
          enabled: true
    priorityClassName: "system-cluster-critical"
    image:
      repository: "rancher/mirrored-library-traefik"
      tag: "2.10.7"
    tolerations:
    - key: "CriticalAddonsOnly"
      operator: "Exists"
    - key: "node-role.kubernetes.io/control-plane"
      operator: "Exists"
      effect: "NoSchedule"
    - key: "node-role.kubernetes.io/master"
      operator: "Exists"
      effect: "NoSchedule"
    service:
      enable: false
    securityContext:
      capabilities:
        add:
        - NET_BIND_SERVICE
      runAsNonRoot: false
      runAsUser: 0
    hostNetwork: true
    updateStrategy:
      type: RollingUpdate
      rollingUpdate:
        maxUnavailable: 1
        maxSurge: 0
    ports:
      web:
        port: 80
        expose: true
        protocol: TCP
        exposePort: 80
      websecure:
        port: 443
        expose: true
        protocol: TCP
        exposePort: 443
        tls:
          enable: true
      metrics:
        port: 9100
        expose: true
        protocol: TCP
        exposePort: 9100
      traefik:
        port: 9000
        expose: true
        protocol: TCP
        exposePort: 9000
```

これによって helm-installer は `traefik` を DaemonSetとして配備しようとしますが、すでに servicelbが起動してポート80と443を使っているのでこの処理はPendingになります。

そこで kube-system名前空間にある先住DaemonSetを削除します
```sh
kubectl delete -n kube-system daemonset svclb-traefik-84aa502b
```

あとは勝手にtraefikのDaemonSetの配備が完了して外部からのアクセスを受け付け、独自に `X-Forwarded-For`や`X-Real-IP`をつけてくれます。
プロダクトコードに顔文字(*^-^)を導入した話

## はじめに

最初に書いておきますが、この記事からは何も知見は得られません。

フロントエンドエンジニア歴2年の新米です。これはプロダクトコードに半分はギャグで、半分は真面目に顔文字をコードの一部に導入したときの話です。2024年現在もこのコードは異常なく動いています。

## 経緯

ある日バグレポートがあがってきて、その原因はフロントエンドで定義して利用していたセパレータ(アンダースコア2つ`__`)とバックエンドから返してきているフィールドのセパレータ(アンダースコア2つ`__`)とのコンフリクトでした。

そこでシニアエンジニアに雑談がてら相談しました。すると「確かに `__` は簡単すぎるよね～、うーん、どうしよっか。。。？顔文字にでもしてみる？w」と言われました。

日々の業務に退屈していた私は「あー、いいですね！！コンフリクトも起きなさそうですしね！」と返事し、(この時点でQiitaに書けるぞ～と邪な考えもしながら)どの顔文字を採用するか検討を始めました。

*私もシニアの方もセパレータとして、もう少し複雑にすれば(例えば `__**__`)充分だと理解しています。

## 顔文字の条件

さっそくGoogleで顔文字を検索しました。すると非常にたくさんの顔文字が出てきます。ただ条件は主に以下です。

1. 半角のみで構成されている
2. ωや∀などコード内に入れて問題ないか微妙な文字を使っていない。
3. 複雑すぎない
4. かわいい(見ていてムカつかない)

これらの条件でしばらく探しており、疲れたころに見つけたのがタイトルにある(*^-^)です。
今見てもかわいいですね。

## 結論

変更自体は簡単でフロントエンドで定義しているセパレータを(*^-^)に置換するだけです。

バグも問題なく修正が確認されissueはクローズされました。

*Github issueにコミットのコメントが表示されて、PMとか偉い人が見れちゃうのでコミットコメントには “fix separator”とだけ書きました。

## 余談

PRには大真面目に「既存のセパレータはアンダースコアが2つ連続したものと定義されており、これがバックエンドからのレスポンスのフィールドとコンフリクトを起こすケースがある。このPRではフロントエンドで定義しているセパレータをよりロバスト( 堅牢)なものに修正する」と書きました。

あと裏では相談したシニアに「ホントに顔文字にしたんだ。。。」と若干引かれて、（お前がはじめた物語ちゃうんかい！？）と思ったりもしました。

以上です。
【備忘録】Jetson AGX Xavierの電源ボタンは一番左

2021年頃、まだGPUの価格が今ほど高騰していない時期に、10万円弱でJetson AGX Xavierを購入しました。しかし、しばらくの間、そのまま眠っていました。

最近、[Run Ollama on Nvidia Jetson devices — part 2](#https://medium.com/@balazskocsis/run-ollama-on-nvidia-jetson-devices-part-2-44576f515808)という記事を見つけ、Jetson AGX XavierにOllamaをセットアップしてみました。しかし、毎日使うわけではなく、たまにしか起動しません。それでも、ボタンが3つもあり、いつも操作に迷ってしまうため、備忘録としてここに記録しておきます。


![xavier_電源.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35883/a7ece40c-7ad7-504b-6b12-8f36d4b49db2.png)
LineageOSのFMラジオを日本対応にする

ASUS ZenFone 2 Laserのバッテリが妊娠して使い物にならなくなって久しく放置していたのですが、バッテリレスにしてUSB充電器から直接配線して復活したのでその時の対応メモです。

lineage-16.0の本体ソースのパッチ
```
sed -i "s/zd/ld/g" hardware/qcom/display-caf/msm8916/libhdmi/hdmi.cpp
sed -i "s/zd/ld/g" hardware/qcom/display-caf/msm8916/libqdutils/idle_invalidator.cpp
sed -i "s/zd/ld/g" hardware/qcom/audio-caf/msm8916/hal/audio_hw.c
```

Zenforne2 laser関連のダウンロード
```
git clone --single-branch -b 9.x           https://github.com/Asus-MSM8916/android_vendor_asus.git
git clone --single-branch -b 9.x-staging   https://github.com/Asus-MSM8916/android_kernel_asus_msm8916.git
git clone --single-branch -b lineage-16.0  https://github.com/Asus-MSM8916/android_device_asus_Z00xD.git
git clone --single-branch -b lineage-16.0  https://github.com/Asus-MSM8916/android_device_asus_msm8916-common.git
```

Patched app FMRadio to Japan band
packages/apps/FMRadio/src/com/android/fmradio/FmUtils.java
```
@@ -45,7 +45,8 @@
     // maximum station frequency
     private static final int HIGHEST_STATION = 1080;
     // minimum station frequency
-    private static final int LOWEST_STATION = 875;
+    //    private static final int LOWEST_STATION = 875;
+    private static final int LOWEST_STATION = 760;
     // station step
     private static final int STEP = 1;
     // convert rate
```
created file: device/asus/Z00xD/fm_srch_af_th.conf
```
[BANDCONFIG]
RadioBand=2
# 1:87.5-108 , 2:76-108 , 3:76-90
```
added to device/asus/Z00xD/device.mk
```
# FM Radio setting
PRODUCT_COPY_FILES += \
   device/asus/Z00xD/fm_srch_af_th.conf:system/etc/fm/fm_srch_af_th.conf
```
ワイドFMに対応しているので余生はFM Radioとして過ごします。
CORSを知ろう

## CORSとは
- オリジン間リソース共有（Cross-Origin Resource Sharing）のこと

----
## 事前知識：オリジンとは
- スキーム（プロトコル）、ホスト、ポートから構成されるもの
  https://example.com:443

----
## 大前提
- インターネットは危ない！

----
## 原則：同一オリジンポリシー
- ブラウザは、あるオリジンから配信されたリソースから他のオリジンに通信することを制限する
  例外：scriptタグのsrc属性／imgタグのsrc属性／formタグのaction属性　など
- この原則がないと、信用できないオリジンからのコンテンツを知らぬ間に受け入れてしまい大事な情報を盗まれる、などの危険性が増すことになる

----
## そうは言ってもクロスオリジンで通信したいことはある
- 自分で開発したWebアプリ同士で通信させたい
- 信用できるオリジンが提供しているAPIを自分のWebアプリから利用したい
　例）自治体が提供しているオープンデータなど

----
## そこでCORS
- 「このオリジンから配信されたリソースからの呼び出しは許可するよ」と設定する
- '*'と設定するとどこからの呼び出しでもOK！という意味になる（太っ腹だし、強心臓！）
- APIキーを払い出すときに「どのオリジンから利用するか」を設定させるサービスもある

----
## 落とし穴
- CORSはブラウザでない場所からの呼び出しには無力
  例）モバイルアプリ／デスクトップアプリ／APサーバ
- 認証が絡むと複雑
  オープンデータが一番使いやすい

----
## CORSの使いどころ
- Web APIの提供：CORSを検討してもいい

----
## 最後に
- 実は、CORSは使わなくて済むならそれが一番いい
- 他に方法がない場合にのみ採用するのが吉
paiza「mod7占い (paizaランク S 相当)」をHaskellで

[問題](https://paiza.jp/works/mondai/s_rank_skillcheck_sample/mod7)

# DP

ははーん、これはあれですね。
$cnt[0\leq k \leq 3][0 \leq r \leq 6]$ を、「カードを $k$ 枚選んでその和を7で割った余りが $r$ になる組み合わせの個数」としてDPして、最後に $cnt[3][0]$ を返せばいい感じですね？
カードを1枚も見ていない初期状態では $cnt[0][0] = 1, cnt[k][r] = 0$ として、カード $a_i$ に対して $cnt[k][r]$ を $cnt[k+1][(r + a_i) \bmod 7]$ に足し込めばできて、これは28要素の配列の21要素を更新するので、immutableな配列のままやってもオーバーヘッドは気にならないはず。

```haskell
import Data.Array

solve :: Int   -- N
      -> [Int] -- a_i
      -> Int   -- 答え
solve _n as = stN ! (3,0)
  where
    st0 = accumArray (+) 0 ((0,0),(3,6)) [((0,0),1)]
    stN = foldl step st0 as
    step st a = accum (+) st
                [ ((succ k, j), st ! (k, i))
                | (i, j) <- [(i, mod (a + i) 7) | i <- [0 .. 6]]
                , k <- [0 .. 2] ]
```

できました！

# 公式解説

「カードの内訳が、7で割って$r$余るようなカードはそれぞれ何枚なのかだけ数えて、それらから3枚選んで7で割り切れるようにする場合の数を数えるだけだよ」

DPいらんかった。

```haskell
solve :: Int -> [Int] -> Int
solve _n as = flip div 6 $ sum
  [ nI * nJ * nK
  | (i, nI) <- assocs cnt , nI > 0, let cntI = accum (+) cnt  [(i, -1)]
  , (j, nJ) <- assocs cntI, nJ > 0, let cntJ = accum (+) cntI [(j, -1)]
  , let ij = mod (i + j) 7, let k = if ij == 0 then 0 else 7 - ij
  , let nK = cntJ ! k, nK > 0
  ]
  where
    cnt = accumArray (+) 0 (0,6) [(mod a 7, 1) | a <- as]
```

調べる場合の数はたった $7^3$ 通りだし、カードの枚数配列は要素数たったの7なので、immutableな更新を平気で使う。
カードの選び方に順番は関係ないので、順番を気にせず数え上げた結果を $\_3 P_3 = 6$ で割っている。

公式解説だと、同じ枠から選んだ場合は、とかを $\_n C_r$ を駆使して数えていたり、事前計算したリストを使ったりしてるけど、単純にこれでいける。

# 力こそパワー解

こちらの記事に、どストレートな解が。

https://qiita.com/289CH4n/items/52b6fce9e1fc03b7a415

「何も考えずにカードリストから3枚選ぶやり方を全て試して、7で割り切れるものを数えるよ」

$\_{10^5} C_3 = 166,661,666,700,000$ 通りの数え上げは無理じゃね？と思いつつ、追試。
（元記事だと最初に mod 7 を計算しているけど、それは不要）

```haskell
solve :: Int -> [Int] -> Int
solve _n as = length $ filter (\x -> 0 == mod (sum x) 7) $ combinations 3 as

combinations :: Int -> [a] -> [[a]]
combinations 0 _  = [[]]
combinations _ [] = []
combinations n (x:xs) = [x:ys | ys <- combinations (pred n) xs] ++ combinations n xs
```

間に合っちゃいました。何が起きてるの？
問題文には $N \leq 100000$ と書いてあるけど、そんなテストケースはないとかそんな感じ？

# 終わりに

スキルチェックでHaskell使えるようにしてホスイ…