OmniAICreator/Qiita-1.07M huggingface dataset:
ABC046 ARC062 の問題を解いてみました

## A問題
https://atcoder.jp/contests/abc046/tasks/abc046_a

$a$ と $b$ と $c$ が同じペンキなら 1 を
$a , b , c$ の 2つが同じペンキなら 2 を
3つの色がすべて異なるなら 3 を 出力します。

~~~C++
#include <bits/stdc++.h>
using namespace std;
//Created by karaju.

int main(void){
  int a, b, c;
  cin >> a >> b >> c;
  
  if(a == b && b == c) cout << 1 << endl;
  else if(a == b || b == c || c == a) cout << 2 << endl;
  else cout << 3 << endl;
  
}
~~~
~~~C++:setを使った別解
#include <bits/stdc++.h>
using namespace std;
//Created by karaju.

int main(void){
  set<int> paint;
  for(int i = 0; i < 3; i++){
    int a;
    cin >> a;
    paint.insert(a);
  }
  cout << paint.size() << endl;
}
~~~

## B問題
https://atcoder.jp/contests/abc046/tasks/abc046_b

一番左のボールは $K$ 通り、 それ以外は左のボールの色を除いて、 $K - 1$ 通りの塗り方があります。
合計で何通りかを繰り返しで計算しましょう。（オーバーフローに注意）

~~~C++
#include <bits/stdc++.h>
using namespace std;
//Created by karaju.

int main(void){
  int n, k;
  cin >> n >> k;
  long long ans = k; 
  for(int i = 1; i < n; i++){
    ans *= k - 1;
  }
  cout << ans << endl;
}
~~~

## C問題
https://atcoder.jp/contests/abc046/tasks/arc062_a


全探索では、 [この提出](https://atcoder.jp/contests/abc046/submissions/48679139) のように、TLEになってしまいます。
なので、全探索ではない解き方を考える必要があります。

まず、前回確認したときよりも得票数が減ることはありえません。
そして、高橋くんの得票数が$T_i$の倍数であり、青木くんの得票数が$A_i$の倍数である必要があります。

なので、
$前回の高橋くんの得票数 \leq n \times T_i, 前回の青木くんの得票数 \leq n \times A_i$
を満たす最小の自然数$n$を求められれば、今回確認したときの2人の得票数を求めることができます。
この$n$は以下の式で求められます。
$n = max(\lceil \frac{前回の高橋くんの得票数}{T_i}\rceil,\lceil \frac{前回の青木くんの得票数}{A_i}\rceil) $


$n$の値が求められたので、2人の得票数も求められます。
この処理を繰り返せば、この問題は解くことができます。


~~~C++
#include <bits/stdc++.h>
using namespace std;
//Created by karaju.

int main(void){
  int n;
  cin >> n;
  long long t_now = 1, a_now = 1, t, a;
  // t_now, a_now は 両者の得票数
  for(int i = 0; i < n; i++){
    cin >> t >> a;
    
    long long mag = max( (t_now + t - 1) / t, (a_now + a - 1) / a );
    // a / b の切り上げは、 (a + b - 1) / b で 計算できる
    
    t_now = t * mag;
    a_now = a * mag;
  }
  cout << a_now + t_now << endl;
}
~~~

## D問題
https://atcoder.jp/contests/abc046/tasks/arc062_b

問題を読んで考えてみると、できるだけパーの回数が多いほうが良いということがわかります。そして、勝つ方法は、 __相手がグーを出したときに自分がパーを出す__ という方法のみです。
なので、相手がパーを出したらパーで対応して、相手がグーを出したらできるだけパーで対応するというのが最善手です。

このことから、答えは $自分が出せるパーの回数 - 相手のパーの回数$ で求められます。

~~~C++
#include <bits/stdc++.h>
using namespace std;
//Created by karaju.

int main(void){
  string s;
  cin >> s;
  int g = 0, p = 0;
  //グー・パーの数をカウントする変数
  for(int i = 0; i < s.size(); i++){
    if(s[i] == 'g') g++;
    else p++; //パーの回数を数える
  }
  int times = s.size() / 2;
  //自分の出せるパーの回数を求める
  
  cout << times - p << endl;
}
~~~
AppServiceでカスタムバックアップ

# やったこと
Azure App Serviceでバックアップを設定してみた。



Azure App Service でアプリをバックアップおよび復元する
https://learn.microsoft.com/ja-jp/azure/app-service/manage-backup?tabs=portal

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661284/3f794933-136a-094a-b77e-c6fac92364c8.png)
自動バックアップは勝手に実行される。カスタマイズはできないけど30GBまで保存される。
カスタムバックアップは手動で設定すれば、除外ファイルなど設定できる。ただ、10GBまで。

# メモ
バックアップサイズは、/home 以下のコンテンツそのままのサイズなのか、圧縮後のサイズなのかが気になって試してみた。
コンテンツサイズが10GBを超えていても、zipで圧縮されて10GB以下になればOKらしい。

自動バックアップは成功時にどれくらいのバックアップ サイズになったかが分からない。ファイルもダウンロードできないので、ポータルのクオータの画面でファイル使用量からなんとなくの値しか分からない。
カスタムバックアップは成功時にどれくらいのバックアップ サイズになったかが表示されるので10GBを超えてるか同課の確認に使える。

バックアップサイズが大きすぎる場合は
> The website + database size exceeds the {0} GB limit for backups. Your content size is {1} GB.

というようなエラーが出るらしい。

My Backups are failing, Let’s open a support ticket
https://azure.github.io/AppService/2018/01/02/My-Backups-are-failing,-Let's-open-a-support-ticket.html
ALB と ECS on Fargate を利用する際の疎通設定

## 背景
AWSを基盤に**ECS on Fargate**で稼働するWebアプリケーションを開発することになった。
アプリケーションには前段に**ALB**を置いて、インターネット経由のHTTPSアクセスをALBで受け付けて、ALBからトラフィックがルーティングされるような構成をとることになった。
以上のようなシステムを構築する際に、「エンドユーザー（クライアント） - ALB - ECSタスク」のネットワーク疎通のためにどのリソースでどの設定項目でどのような設定が必要になるかが分かりづらかったので整理してみた。

システム構成図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271327/0a1fca02-58e4-f6e5-e5ad-aef89476e7bf.png)


なお、以下を前提とする。
- Public Subnetに紐づく**ルートテーブル**にて**Internet Gateway**経由でインターネットと疎通する設定は済んでいる
- **ネットワークACL**はデフォルトのままとする

## 整理した内容

### 通信の経路
今回の構成の場合、エンドユーザー（クライアント）からECSタスクまでの通信の経路は以下の通りになる。
1. エンドユーザー（クライアント） → ALB
2. ALB → ECS on Fargateのホスト
3. ECS on Fargateのホスト → ECSタスク

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271327/012e203e-a156-e199-5f83-262ad81455e6.png)

ただし `3.`については、ECS on Fargateの場合はネットワークモードで「awsvpc」というネットワークモードのみが指定可能で、 「awsvpc」ではhostportとcontainerportが同一になるという仕様がある（ECSタスクのポートマッピングのcontainerportの設定で指定したのと同じポート番号がホスト側で予約されるという仕様）。
そのため、`3.` に関しては `2.` と区別して意識する必要がない（ECS on EC2の場合は区別する必要あり）。

`1.` と `2.` の各経路に関して、ALBやECSで通信に用いるプロトコルとポートを設定したうえで、ALBとECSのセキュリティグループで該当のプロトコルとポートによる疎通を許可してやれば問題なく疎通できる。
プロトコルとポートの設定箇所やセキュリティグループの設定については以下の通り。

### プロトコルとポートの設定
- `1.` の経路については、**ALBのリスナー** にて、ALBがリクエストを受け付けるプロトコルとポートを設定する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271327/bc5565f4-f3d9-adda-8b40-a40c0563d4c0.png)


- `2.` の経路については、（1）ALBがターゲットに対して **トラフィックをルーティング** する際のプロトコルとポートと、（2）ALBが **ターゲットヘルスチェック** を行うためのプロトコルとポートの2種類を設定する。それぞれの設定箇所は以下の通り。
    - （1）の設定箇所
        -　**ALBのターゲットグループ** でプロトコルとポートを指定
        -　**ECSサービス定義** のproductionlistenerportにてポートを指定
        -　**ECSタスク定義** のポートマッピングのcontainerportにてポートを指定  
    - （2）の設定箇所
        - **ALBのターゲットグループのヘルスチェック**の設定項目にてプロトコルとポートを指定（（1）のルーティング用のプロトコルとポートと同じでもよい）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271327/8d7505bf-02b0-a399-3456-c049d35d790c.png)


### セキュリティグループの設定
**ALB**と**ECSサービス**に対してアタッチすることになる。
**ALB**のセキュリティグループではインバウンドルールで `1.`、アウトバウンドルールで`2.` のトラフィックの疎通の許可が必要。
**ECSサービス**のセキュリティグループではインバウンドルールで`2.` のトラフィックの疎通の許可が必要。
「material-design-icons/svg」をNext.jsとViteでビルドしているプロジェクトで使いたい場合の対応方法

`@material-design-icons/svg`をインポートして使うぞ！
と張り切って導入したらめっちゃ怒られたので鎮める方法を残します。

## どんなエラーだったのか？
まず`@material-design-icons/svg`をinstallします。

https://github.com/pd4d10/vite-plugin-svgr

```bash
npm install --save-dev @material-design-icons/svg
yarn add -D @material-design-icons/svg
pnpm add -D @material-design-icons/svg
```

インストールされたらコンポーネントで下記のように記述し読み込みました。

```javascript
import ChevronRight from '@material-design-icons/svg/filled/chevron_right.svg?react'
```

そして下記のエラーが発生しました。
```javascript
InvalidCharacterError: Failed to execute 'createElement' on 'Document': The tag name provided ('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTkgM0g1Yy0xLjEgMC0yIC45LTIgMnYxNGMwIDEuMS45IDIgMiAyaDE0YzEuMSAwIDItLjkgMi0yVjVjMC0xLjEtLjktMi0yLTJ6bS05IDkuNUg4djFoM1YxNUg2LjV2LTIuNWMwLS41NS40NS0xIDEtMWgydi0xaC0zVjlIMTBjLjU1IDAgMSAuNDUgMSAxdjEuNWMwIC41NS0uNDUgMS0xIDF6bTggMi41aC0xLjc1bC0xLjc1LTIuMjVWMTVIMTNWOWgxLjV2Mi4yNUwxNi4yNSA5SDE4bC0yLjI1IDNMMTggMTV6Ii8+PC9zdmc+') is not a valid name.
```
:::note alert
無効なタグ名を使って要素を作成しようとしたときに発生するようです…
:::

## 解決方法
認識されるように設定してあげます。
viteでbuildされている場合は、`vite-plugin-svgr`を利用することで修正できました。

:::note info
ツールによってインストールするものが異なります。
使っているbuildツールと共に`svgr`をキーワードに含めて検索すると良いと思います！
:::

```bash
npm install --save-dev vite-plugin-svgr
yarn add -D vite-plugin-svgr
pnpm add -D vite-plugin-svgr
```

npmのサイトを確認しながら設定していきます。

https://www.npmjs.com/package/vite-plugin-svgr

```typescript:vite.config.ts
import svgr from "vite-plugin-svgr";

export default defineConfig({
  plugins: [svgrPlugin()],
  .
  .
  .
})
```

おおよそ完了ですが、TypeScriptの環境だとSVGの読み込み位置で下記のようなエラーが出ると思います。

```typescript
モジュール '@material-design-icons/svg/filled/chevron_right.svg?react' またはそれに対応する型宣言が見つかりません。
```

これだけではエラーを解消することができません。
`ts.config`の設定ファイルを編集する必要があります。

:::note warn
`vite-plugin-svgr`のプラグインにはsvgの型定義が書かれていますが、うまく読み込めていないことが発生していました…
:::

`vite-plugin-svgr`のプラグインには下記のようにsvgの型定義がされています。

```typescript
declare module "*.svg?react" {
  import * as React from "react";

  const ReactComponent: React.FunctionComponent<
    React.ComponentProps<"svg"> & { title?: string }
  >;

  export default ReactComponent;
}
```

https://github.com/pd4d10/vite-plugin-svgr

プラグインに定義してある型定義を利用できるように`ts.config`に設定を追記します。

```typescript:ts.config
 "compilerOptions": {
    "types": ["vite-plugin-svgr/client"]
 },
```


コンポーネントとして呼び出して確認してみてください！
```typescript
<ChevronRight>
```

画像の名称は下記のサイトから確認できます。

https://marella.me/material-design-icons/demo/svg/


## まとめ
知識が足りず間違ったものをインストールしたり、誤った書き方をしてしまったりで解消に時間がかかってしまいました…。

終わってみればなんのこともないのですが、この解決方法が良いのかはまだわかっておりません。
Reactを利用しているプロジェクトでSVGアイコンを扱いたい時には注意してください！


## 参考URL

https://blog.devgenius.io/react-vite-tailwind-css-twin-macro-storybook-svg-imports-as-react-component-6b44d5e2641

https://zenn.dev/longbridge/articles/36ece55292f9da
ABC042 ARC058 の問題を解いてみました


## A問題
https://atcoder.jp/contests/abc042/tasks/abc042_a

整数$A,B,C$ を並べ替えて五七五にできるというのは、整数$A,B,C$ のうち2つが<code>5</code> で,1つが <code>7</code> ということなので、その条件を満たしているかを判定すればよいです。
~~~C++
#include <bits/stdc++.h>
using namespace std;
//Created by karaju

int main() {
	int A, B, C;
	cin >> A >> B >> C;
	int five = 0, seven = 0;
	if (A == 5) five++;
	if (A == 7) seven++;
	if (B == 5) five++;
	if (B == 7) seven++;
	if (C == 5) five++;
	if (C == 7) seven++;
	
	if (five == 2 && seven == 1) {
		printf("YES");
	}
	else {
		printf("NO");
	}
	
	return 0;
}
~~~
~~~C++:他の解答例
#include <bits/stdc++.h>
using namespace std;
//Created by karaju

int main() {
	int ABC[3];
	cin >> ABC[0] >> ABC[1] >> ABC[2];
	sort(ABC, ABC + 3);
	if (ABC[0] == 5 && ABC[1] == 5 && ABC[2] == 7) printf("YES");
	else printf("NO");
}
~~~

## B問題
https://atcoder.jp/contests/abc042/tasks/abc042_b

長さ$L$の文字列が$N$個与えられるので、それらを辞書順に並び替えて結合してください。 という問題です。
文字列を辞書順に並び替えるには、ソートを使えば良いです。
文字列を$N$個含んだ配列を作成して、その配列をソートしましょう。
~~~C++
#include <bits/stdc++.h>
using namespace std;
//Created by Karaju

int main() {
	int N, L;
	cin >> N >> L;
	string words[N];
	for (int i = 0; i < N; i++)  cin >> words[i];
	sort(words, words + N);
	for (int i = 0; i < N; i++) cout << words[i];
	
	return 0;
}
~~~
## C問題
https://atcoder.jp/contests/abc042/tasks/arc058_a

$N$円の品物を購入する __嫌いな数字が含まれない__ 最小金額を求める問題です。
嫌いな数字は$K (0 \leq K < 10$)個あり、$D_1,D_2,...,D_K$ です。

嫌いな数字が含まれていたら、その金額に1円足した金額について確かめるという方法で $N$ から嫌いな数字を取り除くことができます。

~~~C++
#include <bits/stdc++.h>
using namespace std;
//Created by karaju

int main() {
	int n, k;
	cin >> n >> k;
	int li[10];
	for (int i = 0; i < k; i++) {
		int d;
		cin >> d;
		li[d]++;
		//配列の嫌いな数字番目を1にする
	}
	int x; //xの値を1ずつ増やしていく
    bool ok;
	
	for (int i = n; true; i++) {
		x = i;
		ok = true;
		while (x) { //xが0になるまで
			//一桁ずつ嫌いな数字かどうか確かめる
			if (li[x % 10] == 1) {
				ok = false;
				break;
			}
			x /= 10;
			//一の位を削ぎ落としていく
		}
		if (ok) { //嫌いな数字が含まれていないなら
			cout << i << endl;
			return 0;
		}
	}
	
	return 0;
}
~~~

## D
https://atcoder.jp/contests/abc042/tasks/arc058_b

あとで
Git commitをテンプレート化する

## はじめに

Gitのコミットメッセージを毎回書き方が統一できていないので、統一したいなと思ってcommit templateの設定をしたので記録として残します。

# 開発環境
- Mac

# 導入

## 配置場所

```
project
├── .github
│   └── commit_message.txt
```

## commit_template.txtを作成する

- 参考記事のテンプレートが使いやすそうと思ったので、使用してます。

```
# ==== Commit Messages ====

# ==== Commit Messages(Template) ====
# :emoji: #Issue番号 変更内容
# 例) :+1: #438 コメント追加
#       👍 #438 コメント追加
# ==== Prefix ====
# :fix: バグ修正
# :hotfix: クリティカルなバグ修正
# :add: 新規機能・新規ファイル追加
# :feat: feature
# :update: バグではない機能修正
# :change: 仕様変更による機能修正
# :docs: ドキュメントのみ修正
# :disable: 無効化
# :remove(delete): ファイル削除、コードの一部を取り除く
# :rename: ファイル名の変更
# :upgrade: バージョンアップ
# :revert: 修正取り消し
# :style: 空白、セミコロン、行、コーディングフォーマットなどの修正
# :refactor(clean,improve): リファクタリング
# :test: テスト追加や間違っていたテストの修正
# :chore: ビルドツールやライブラリで自動生成されたものをコミットするとき

# ==== Emojis ====
# 🐛  :bug: バグ修正
# 👍  :+1: 機能改善
# ✨  :sparkles: 部分的な機能追加
# 🎨  :art: デザイン変更のみ
# 💢  :anger: コンフリクト
# 🚧  :construction: WIP
# 📝  :memo: 文言修正
# ♻️  :recycle: リファクタリング
# 🔥  :fire: 不要な機能・使われなくなった機能の削除
# 💚  :green_heart: テストやCIの修正・改善
# 👕  :shirt: Lintエラーの修正やコードスタイルの修正
# 🚀  :rocket: パフォーマンス改善
# 🆙  :up: 依存パッケージなどのアップデート
# 👮  :cop: セキュリティ関連の改善
# ⚙   :gear: config変更
# 📚  :books: ドキュメント

```

### git configに設定する

- 上記のテンプレートを使用できるように、設定します。

```
$ git config [--global or --local] commit.template .github/commit_template.txt
```

### git commitを打つ

- 下記のように表示されます。

![スクリーンショット 2023-12-29 19.13.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/923146/0b8ddf79-442b-5a60-b8f8-8fc9fbea8b31.png)


## コミットを確認
- 下記のようになっています。

![スクリーンショット 2023-12-29 19.14.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/923146/441422c9-3f69-4fc2-c2a7-99db9a70c504.png)


# まとめ
- テンプレートを作成することで、統一したコミットメッセージを残すことができるので非常に便利！


# 参考
- [8.1 Git のカスタマイズ - Git の設定](https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA-Git-%E3%81%AE%E8%A8%AD%E5%AE%9A)
- [初心者必見！Gitのコミットメッセージのテンプレートの作成方法について](https://qiita.com/shun198/items/72511bd95e13cf0be88c)
Alexa-hostedで lambdaからS3にファイルアップロードをする方法

# 目次
* きっかけ
* 事前準備
* コード


# 1. きっかけ
Alexa-hostedは独自のAWS環境を用意することなく、スキル開発を進めることが可能です。
また、テンプレートやVScodeの拡張機能も用意されているみたいです。
エンドポイント等も設定せずとも使えるため、複雑なスキル作成には向いていませんが、
簡単なスキル作成にはもってこいですね！！！

lambdaだけでなく、S3,Dynamodbも利用できるみたいです。

AlexaSkillsKitで用意されたS3環境にlambdaがアップロードするやり方が全然乗っていなかったので、
**lambdaからS3に対してアップロードする** 方法、コードを提供します。

今回は、Alexaと会話終了と共にS3に会話内容を保存するコードを共有します。


# 2. 事前準備
以下のS3 Storageを押します。

![スクリーンショット 2023-12-29 午後7.09.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936739/324f6772-e9ce-9220-9729-ef9b33cdf545.png)

そうすると、用意されているバケットがありますので、コピーしておきます。

# 3. コード

いろいろなやり方があると思いますが、私は以下の方法で実現できました。
boto3を使っています。
requirements.txtにはboto3を記載しておきましょう。

また、インテントにEndSessionIntentを追加しています。

※以下はプログラムの一部です。
```python
import boto3
import ask_sdk_core.utils as ask_utils
from ask_sdk_core.handler_input import HandlerInput

# Alexa-hosted skillのためのS3クライアント初期化
s3_client = boto3.client('s3')

# Alexa-hosted skillのバケット名を環境変数から取得
bucket_name = "YOUR_BUCKET_NAME"

class EndSessionHandler(AbstractRequestHandler):
    def can_handle(self, handler_input):
        return ask_utils.is_intent_name("EndSessionIntent")(handler_input)

    def handle(self, handler_input):
        # セッション属性から会話履歴を取得
        session_attr = handler_input.attributes_manager.session_attributes
        conversations = session_attr.get("conversations", [])

        # 現在の日付と時間をファイル名にする
        now = datetime.now()
        file_name = f"Media/トーク履歴/{now.strftime('%Y-%m-%d_%H-%M-%S')}.txt"
        
        # 会話履歴を整形して保存
        formatted_conversations = "\n".join([f"{c['role']}: {c['content']}" for c in conversations])

        # S3に会話履歴を保存
        try:
            s3_client.put_object(
                Bucket=bucket_name,
                Key=file_name,
                Body=formatted_conversations.encode("utf-8")
            )
            speak_output = "スキルを終了します。さようなら。会話履歴は保存されました。"
        except Exception as e:
            speak_output = f"保存に失敗しました: {e}"

        # 会話終了の応答
        return (
            handler_input.response_builder
                .speak(speak_output)
                .response
        )

```


うん、ちゃんとAlexaとの会話内容がS3にアップロードされていますね！^^

![スクリーンショット 2023-12-29 午後7.13.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1936739/e13880f6-8b38-3201-521a-798717f03519.png)


ご参考までに！！
お読みいただき、ありがとうございました！
Node.jsの導入方法

# はじめに
ようやくWebへの重い腰が上がり、少しずつ着手しています。
Webは昔に少し触れたくらいで技術力はもはや無いに等しいので、改めてしっかり触れていこうと思います。
ただお気持ち表明だけだと忙しさに負けてしまうので、、、。
記事にすることで自身のモチベーションを維持していこうと思います！

まずは簡単にNode.jsの導入手順を備忘録も兼ねて記事として残しておこうと思います。

# Node.js導入手順
まず前提として環境はMacになります。
なのでMacに導入する前提で進めていきます。

まず、Homebrewを使用してnodebrewをインストールします。

```
$ brew install nodebrew
```

Homebrewを導入していない場合は以下ページより導入しておきます。

https://brew.sh/ja/

インストールが無事完了したら、次はnodebrewのパスを通すために調整します。

```
$ nodebrew setup
```

上記を実行すると通すべきパスの情報が出力されますので、そのパス情報を.zshrc (bashを使用している場合は、.bash_profile）に追記して、変更を反映させます。

```
$ echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.zshrc
$ source ~/.zshrc
```
次に、node.jsの導入を行います。

```
$ nodebrew install stable
```
上記を実行し、安定版をインストールします。
ちなみにバージョンを指定してインストールを行なったり、最新版を指定してインストールすることも可能です。

上記インストールが完了したら、以下を実行し正常にインストールされているか確認します。

```
$ nodebrew list
```

上記にインストールしたバージョンが表示されていれば問題ありません。
ですが、現状ではインストールされているだけの状態なので、今度は有効化する必要があります。
有効化は以下を実行することで可能です。

```
$ nodebrew use v20.10.0
```

上記で有効化の設定は以上です。
useコマンドを叩くと、listを実行した際にcurrent欄に設定したバージョンが表示されるので、不安な方は再度listを実行してみると良いと思います。

最後に、正しく設定されているか確認するため、以下を実行します。

```
$ node -v
$ npm -v
```

それぞれバージョンが表示されていれば導入は完了です。

# さいごに
今年最後の記事になります、どうぞ良いお年をお迎えください！
手軽に実現！OpenCVとWebカメラでQRコードの位置を特定する方法

本記事では、OpenCVを使用してWebカメラからQRコードの位置を特定します。
![スクリーンショット 2023-12-30 134537.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632959/e0c8664d-8434-8aaa-ee2d-142ece09e411.png)

QRコードの生成に関しては以下の記事を参照してください。
[QRコードの生成](https://qiita.com/kakuteki/items/3b24bd240da50553dc94 "")

必要なもの
Python: プログラミング言語として使用。
OpenCV: 画像処理を行うためのオープンソースライブラリ。

## 1: 環境設定
まず、Pythonがインストールされていることを確認してください。次に、OpenCVをインストールします。コマンドラインまたはターミナルで以下のコマンドを実行します。

```
pip install opencv-python
```

## 2: カメラからの映像取得
Webカメラから映像を取得するためのコードを書きます。OpenCVを使ってカメラにアクセスし、映像を取得し表示します。
```
import cv2

# カメラのキャプチャを開始
cap = cv2.VideoCapture(0)

while True:
    # フレームをキャプチャする
    ret, frame = cap.read()
    if not ret:
        break

    # フレームを表示する
    cv2.imshow('QR Code Scanner', frame)

    # 'q'を押して終了
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# キャプチャを解放
cap.release()
cv2.destroyAllWindows()
```

## 3: QRコードの検出と位置の特定
OpenCVには、QRコードを検出し、その位置を特定する機能が備わっています。以下のコードは、カメラのフレームごとにQRコードを検出し、その位置を四角で囲む方法を示しています。また、コマンドラインには検出したQRコードの座標を出力します。
```
import cv2

# QRコード検出器を初期化
qrCodeDetector = cv2.QRCodeDetector()

cap = cv2.VideoCapture(0)

while True:
    ret, frame = cap.read()
    if not ret:
        break

    # QRコードを検出し、その位置を取得
    decodedText, points, _ = qrCodeDetector.detectAndDecode(frame)

    if points is not None:
        points = points[0]

        # Debugging: Print the points to check their structure.
        print(f"Points: {points}")

        # Validate and draw lines around QR code
        if len(points) == 4 and all(len(point) == 2 for point in points):
            for i in range(len(points)):
                start_point = tuple(map(int, points[i]))
                end_point = tuple(map(int, points[(i + 1) % len(points)]))

                cv2.line(frame, start_point, end_point, (0, 255, 0), 3)
        else:
            print("Invalid points structure.")

        # デコードされたテキストを表示
        print(decodedText)

    cv2.imshow('QR Code Scanner', frame)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

```
このコードは、Webカメラからの映像に対してリアルタイムでQRコードを検出し、その位置を四角で囲み、デコードされたテキストをコンソールに表示します。プログラムを終了するには、'q'キーを押してください。
日付を操作するDateオブジェクト

<br>
良く使う、Dateオブジェクトについて、まとめてみました。

(個人的にはどんどん追記していきたい)

# 目次
<details>

1. Dateオブジェクトとは

2. 呼び出し方

3. 日時を読み取るメソッド

4. 日時を変更するメソッド

5. 使い方

6. Reactライブラリ


</details>

# 1. Dateオブジェクトとは

カレンダー作成や日付取得に用いるオブジェクトです。

# 2. 呼び出し方

Date型としてDateオブジェクトを呼び出します。

```
const now :Date = new Date();
```

# 3. 日時を読み取るメソッド

| メソッド名 | 説明 |
|:-:|:-:|
| getFullYear()|  年を4桁で返す(例: 2022) |
|getMonth()   | 月(0-11)を返す|
|getDate()   | 日(1-31を返す)  |
|getDay()   | 曜日(0-6)を返す　※0は日曜日  |
|getHours()   |時間(0-23)を返す   |
|getMinutes()   |分(0-59)を返す   |
|getSeconds()   |秒(0-59)を返す   |
|getMilliseconds()   | ミリ秒(0-999)を返す  |
|getTime()   |1970年1月1日00:00:00からの経過時間をミリ秒単位の数値で返す|
|toLocaleString()   |言語に合わせた日時の文字列を返す(2022/12/25 9:15:00など)   |

# 4. 日時を変更するメソッド

カレンダーで予定を設定するのに使用したりします。

| メソッド名 | 説明 |
|:-:|:-:|
| setFullYear(x)|  引数で設定した年を設定する |
|setMonth(x)   | 引数で設定した月を設定する(0-11)|
|setDate(x)   | 引数で設定した日(1-31)を設定する  |
|setHours(x)   |引数で設定した時間(0-23)を設定する   |
|setMinutes(x)   |引数で指定した分(0-59)を設定する   |
|setSeconds(x)   |引数で指定した秒(0-59)を設定する   |
|setMilliseconds(x)   | 引数で指定したミリ秒(0-999)を設定する  |

:::note info
指定した値が月末の日付を超える値を渡すと,
超えた日数は予定から繰り上がり、
月も同じように超えた場合は次の年に自動で置き換えられます。
:::

# 5. 使い方

①日付を取得する方法
```
const now :Date = new Date(); //現在の日時を表すオブジェクト

let year:number = now.getFullYear(); // 2022

let date:number = now.getDate();

date.setDate(now.getDate() +10);  //今日から10日後に日時を設定する
```


②今月の初日は何曜日かを取得する方法
```
//今日の日付を取得
const date : Date = new Date(); -> 2023/12/29

//今月の初日に変更
date.setDate(1); -> 2023/12/1

//初日の曜日を取得
const day:number = date.getDay(); -> 5(つまり金曜日)
```

③今月の末尾を取得する方法

```
//わざと1か月進める
date.setMonth(date.getMonth() +1); -> 1(12月から1か月進めたので)

// 日付を0に設定する(Dateの範囲が1-31なため、はみ出した分は前月へ繰り越される)
day = date.setDate(0); -> 2023/12/31

//dayの中の日付部分のみ取り出す
days:number = day.getDate(); -> 31
```



# 6. Reactライブラリ

同じような機能を持ったライブラリがReactにあったので紹介します。

この説明もしていきたいなあ。

https://zenn.dev/morit4ryo/articles/934d67dcf8ab59
クラウドサービスモデルの理解：IaaS、PaaS、SaaS

# はじめに

「IaaS」、「PaaS」、「SaaS」という3つのサービスモデルについて、改めてまとめてみた。

## IaaS (Infrastructure as a Service) 【イアース】
- **概要**: IaaSは、基本的なコンピューティングインフラストラクチャ（サーバー、ストレージ、ネットワーキング）を提供するサービスモデル。ユーザーはインフラの管理、設定、拡張を自由に行える。これにより、物理的なインフラストラクチャの購入とメンテナンスのコストを削減可能。
- **代表的なサービス**: Amazon Web Services (AWS) の EC2、Google Cloud Platform の Compute Engine。
- **利点**: ハードウェアの購入コスト削減、高い拡張性、カスタマイズ性。

## PaaS (Platform as a Service) 【パース】
- **概要**: PaaSは、アプリケーションの開発に必要なプラットフォーム（開発ツール、データベース管理システムなど）を提供する。これにより、開発者はアプリケーションのコーディングとデータ管理に集中でき、インフラストラクチャの管理から解放される。
- **代表的なサービス**: Microsoft Azure、Google App Engine。
- **利点**: 開発の迅速化、効率的なアプリケーション管理、コスト削減。

## SaaS (Software as a Service) 【サース】　
- **概要**: SaaSは、ソフトウェアアプリケーションをインターネット経由で提供するモデル。ユーザーはインストールやメンテナンスを気にすることなく、ブラウザからアプリケーションにアクセスできる。
- **代表的なサービス**: Google Workspace、Salesforce、Dropbox。
- **利点**: 初期投資不要、簡単な導入と管理、自動更新。

## まとめ
エンジニアとして、これらのクラウドサービスモデルを理解し活用することは、現代のインフラ管理において極めて重要だと思います。IaaSは、細かいカスタマイズとコントロールが求められる場合に最適です。PaaSは、アプリケーション開発とデプロイメントのプロセスを効率化したい場合に適している。SaaSは、インフラの管理とメンテナンスの手間を最小限に抑えたい場合に有効です。これらのモデルを適切に選択し活用することで、エンジニアはより効率的で柔軟なインフラ環境を実現できると思います

https://cloudfit.co.jp/article/3
CSVファイルをFileAPIで読み込む

言わずと知れたCSVファイルを、EXCEL等で出力されるシフトJIS形式の状態で読み込めるJavaScriptコードを書いてみます。
# 実行条件
- 入力対象となるCSVはソフトJIS形式である。例えば郵便局の[郵便番号データ](https://www.post.japanpost.jp/zipcode/download.html)を加工無しで読めるようにする。
- フレームワークは用いずVanillaJSで書く。
- なるべくシンプルなコードとし装飾も最低限にする。
# 対象コード
シフトJIS形式によるテキストファイルを読み込む場合、問題になるのは **実際のHTML上で使用されているキャラクターコードとの相違をどうするか？** ということです。下記コードにおいては、[encoding.js](https://github.com/polygonplanet/encoding.js/blob/master/README_ja.md)により解決しています。
```
<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<script src="https://cdnjs.cloudflare.com/ajax/libs/encoding-japanese/2.0.0/encoding.min.js"></script>
</head>
<body>
	<style>
		table{
			border-left:1px solid #000000;
			border-top:1px solid #000000;
			border-spacing:0;
		}

		table td{
			border-right:1px solid #000000;
			border-bottom:1px solid #000000;
		}
	</style>

	<input type="file" id="csvfile"><br>	<!-- ファイル選択 -->
	<table id="output"></table>				<!-- 出力先 -->

	<script>
		"use strict";

		// ファイルが選択された時
		document.getElementById('csvfile').onchange = e=>{
			const reader = new FileReader();

			// 読込後の処理
			reader.onload = file=>{
				// Shift-JISで読まれたテキストをUNICODE文字列に変換
				const arr = new Uint8Array(file.target.result);
				const text = Encoding.convert(arr,{
					to:"UNICODE",
					from:Encoding.detect(arr),
					type:"string"
				});

				// table要素を取得
				const output = document.getElementById('output');

				// 文字列を1行ずつ処理
				const rows = text.split('\n');
				for(let i = 0;i < rows.length;i++){
					// tr要素作成
					const element = document.createElement("tr");

					// 1行をカンマ分割して1個ずつtd要素で追加
					const cells = rows[i].split(',');
					cells.forEach(cell=>{
						const td = document.createElement("td");
						td.textContent = cell.replaceAll('"','');	// "を除去して設定(手抜き)
						element.appendChild(td);
					});

					// tr要素をtableへ追加
					output.appendChild(element);
				}
			}

			// 選択されたファイルを読む
			reader.readAsArrayBuffer(e.target.files[0]);
		}
	</script>
</body>
</html>
```
【不合格】統計検定準1級を落ちた話

# はじめに

先日、統計検定準1級をCBTで受験したのですが、残念ながら不合格でした。

「合格しました！」の記事を投稿してQiitaを始めたかったのですが、
最初の記事として、不合格報告と振り返りを行きたいと思います。


# 成績

下記の通りあと１点足らず不合格でした。
しかし受験中に解けない問題も多かったため、不合格は妥当な結果と感じました。
ただ、、、とても悔しい！！！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3328060/6e205c5d-e1f8-fd8c-a924-6ef1a0961e74.png)

# 振り返り
詳しくは合格体験記で書きたいのですが、受験までに300時間ほど勉強しました。
ワークブックと過去問に関しては、大半の問題が解けるようになっていました。
ただ実際にCBTの試験を受けてみると、出題形式が異なる問題や初見の問題が多く、
解き方が考えつかなかったり、計算した結果が選択肢に無いような状態になりました。

具体的には、下記の問題で詰まりました。
・条件付き独立
・プロビットモデル
・平均値と中央値の分散
・時系列データの自由度
など

# 今後の対策
まずは点が取れていない「多変量解析」において、再度基礎的な内容から復習する予定です。
また比較的容易な「確率と確率分布」についても、未知の問題へ対応できるように力をつけます！

# おわりに
統計的に考えると今回の59点という数字が、試験に対する私の力をどのように示しているのかは、現時点で不明です。

たまたま今回低い数値が出たのかもしれないですし、
59点でも実力(平均値付近?)よりずっと上なのかもしれません。

今後何回も受けることがあれば統計的に観測できるかもしれませんが、
そんなにたくさん試験を受けたくありません。(笑)

次で受かるようにがんばります！

読んでくださり、ありがとうございました。
RasberryPi 4BでGPIOのシリアル通信を有効にするメモ

# はじめに

RasberryPi 4BのGPIOでシリアル通信をするメモです。
センサの情報をシリアル通信で取得したかったのですが、同梱されているはずのUSB変換がなくなっていたので、ラズパイのGPIOポートを使いたいと考えました。

# 環境

- RasberryPi 4B(Ubuntu 20.04.4 LTS)

| 項目 | バージョン |
|-- | -- | 
| Ubuntu|20.04|
|ROS|Noetic|

# 参考
- [Raspberry Piのシリアルポート設定（UART）を理解する - Toki Blog（トキブログ） (toki-blog.com)](https://toki-blog.com/pi-serial/)

- [RaspberryPi(ラズパイ)でシリアル通信を有効化する方法 シリアル関連の設定方法【UART・stty・echo・cat】 (tech-and-investment.com)](https://tech-and-investment.com/raspberrypi2-5-uart-setting/#uart%e3%81%ae%e6%9c%89%e5%8a%b9%e5%8c%96%e3%81%a8%e7%a2%ba%e8%aa%8d%e6%96%b9%e6%b3%95)

- [Raspberry PiのTTLシリアルポートをアクティブにし、機能していることを確認します。 (raspberrypi-japan.com)](
https://raspberrypi-japan.com/enable-port-serial-raspberry-pi-3/)

# やったこと

## RasberryPiのシリアルポート設定
シリアルポートはデフォルトでは無効になっています。そのため、設定で有効にする必要があります。
raspi-configで設定します。

```bash
$ sudo raspi-config
```
raspi-configが起動したら、以下のような画面になるので、

Interfacing options
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599506/ff2496bb-5e7c-61cc-e0bb-e1cce18b2b82.png)

Serial Port
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599506/fa238f5d-f853-a1c3-3813-c5b231da5dc0.png)

「いいえ」 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599506/280d9a79-b1bd-2ed3-312d-2e940518d360.png)

ハードウェアポートをアクティブ化するかどうかの質問に「はい」

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599506/69ba13c5-4844-217f-e5a3-7505f1a29e6c.png)

「了解」

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599506/3fd876a9-ad61-424f-82d3-779ae1e2ffa7.png)

## デバイスの確認

```
$ dmesg | grep PL011
[    0.038572] Serial: AMBA PL011 UART driver
[    1.431030] fe201000.serial: ttyAMA0 at MMIO 0xfe201000 (irq = 14, base_baud = 0) is a PL011 rev2

$ ls -al /dev/ttyAMA0
crw--w---- 1 root tty 204, 64 12月 28 19:44 /dev/ttyAMA0
```
表示結果の2行目に「ttyAMA0… is a PL011」と表記されているため、デバイス名は「ttyAMA0らしい」ということが分かります。

ボーレート確認しようと思ったら、許可がないとのことなので、権限を付与します。
```
$ stty -F /dev/ttyAMA0
stty: /dev/ttyAMA0: 許可がありません
```

```
$ sudo chmod a+rw /dev/ttyAMA0
ubuntu@TB3:~$ ls -al /dev/ttyAMA0
crw-rw-rw- 1 root tty 204, 64 12月 28 19:44 /dev/ttyAMA0
```

ボーレートを確認すると、115200であることがわかりました。
```
$ stty -F /dev/ttyAMA0
speed 115200 baud; line = 0;
min = 1; time = 0;
-brkint -icrnl -imaxbel iutf8
-isig -icanon -iexten -echo -echoe -echok -echoctl -echoke
```

## データ送受信テスト

シリアル通信には、GPIO14(TXD)、GPIO15(TXD)を使います。ブレッドボードを使って、シリアル通信を対向させます（自分と通信）。抵抗は適当なものを使いました。(手元にあった27Ω)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599506/ff6032d8-87fb-fed7-50e6-a21b9e6cbbfd.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599506/567d8240-22c8-6333-a1ba-e204fb19c70a.png)

参考：[Raspberry PiのTTLシリアルポートをアクティブにし、機能していることを確認します。 (raspberrypi-japan.com)](
https://raspberrypi-japan.com/enable-port-serial-raspberry-pi-3/)


ターミナルで受信します。待ち構えている状態です。
（先ほど権限付与したので、sudo必要なかったかも）

```bash
$ sudo cat /dev/ttyAMA0
```

別のターミナルで送信します。
```
$ echo "Hello" > /dev/ttyAMA0
```

受信側のターミナル
```
$ sudo cat /dev/ttyAMA0
ello
H
```

なにか通信できている…模様。

# まとめ

本記事ではRasberryPi 4Bのシリアル通信を有効にしたメモを記載しました。
[備忘録]保護ビューでのBook操作

# 保護ビューのBookに対し操作したい
ダウンロードしてきたエクセルを開くと保護ビューで開かれて、ActiveWorkbookなどを利用しているマクロが利用できなかった。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559813/f42c2e27-bb17-6a8d-dab6-9b5106f41345.png)

保護ビューで開かなければ良いだけなのだけど、それを変えるのも面倒なのでActiveWorkbook部分などのマクロを修正した備忘録になります。

# エラーになった箇所

## ActiveWorkbook
↓だとActiveWorkbookが取得できずエラーに
``` 修正前.vb
For Each targetSheet In ActiveWorkbook.Sheets
	' なんらかの処理
Next targetSheet
```

↓ProtectedViewWindowsを利用して、保護ビューでもActiveWorkbookと同じようにする。
``` 修正後1.vb
For Each targetSheet In Application.ProtectedViewWindows(1).Workbook.Sheets
	' なんらかの処理
Next targetSheet
```

↓保護ビューでないBookのとき用に条件を入れておく
``` 修正後2.vb
Dim targetSheet As Worksheet

If ActiveWorkbook Is Nothing Then
    ' ActiveWorkbook がNothingの場合、保護ビューで開かれていると仮定して、Bookを取得
    Set targetBook = Application.ProtectedViewWindows(1).Workbook

Else
    Set targetBook = ActiveWorkbook
End If

For Each targetSheet In targetBook.Sheets
　　' なんらかの処理
Next targetSheet
```
（保護ビュー以外で、ActiveWorkbook がNothingの場合は検討してません。。）


# Workbooks(TARGET_BOOK_NAME).Activate Sheets(resultListBox.Value).Select
↓の様な箇所があってシートを選択しようとした部分でエラー
``` 修正前.vb
TARGET_BOOK_NAME = "something"
TARGET_SHEET_NAME = "something"

 ’ {中略}
Workbooks(TARGET_BOOK_NAME).Activate
Sheets(TARGET_SHEET_NAME).Select

```

ProtectedViewWindowsを利用
``` 修正後1.vb
Application.ProtectedViewWindows(TARGET_BOOK_NAME).Workbook.Activate
Application.ProtectedViewWindows(TARGET_BOOK_NAME).Workbook.Sheets(TARGET_SHEET_NAME).Select

```
VS Codeでショートカット"行を下に挿入（Ctrl+Enter）"が使えなくなった

## 行を下に挿入

HTMLを書いてると、

<タグ>こんな感じで< /タグ>

最後にもタグがあるため、"行を下に挿入"というショートカットを多用する。

これがVS CodeなどのエディタではCtrl+Enterに割り当てられているのだが、いつの間にかこのショートカットが利かなくなっていた。

## キーボードショートカットの設定

このような状態になった時は、キーボードショートカットが他と被っていることが多いのだが、Ctrl+Enterを使うショートカットが多すぎてどれか分からない... 

仕方なく虱潰しにショートカットを変更していくと、Solution ExplorerのOpen Fileのショートカットを変更したときに、エディタの行を下に挿入が使えるようになった。

もしソリューションエクスプローラーを入れていて、同様の症状が出た場合は、ここをチェック！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638306/0558b808-fe45-8e54-12be-b1993db057c4.png)
Dev Containerを使って、Rubyに触れてみる

## はじめに

この記事の中でやりたいことは、以下のことです。
- Rubyの動作環境を構築する
- vscode拡張機能の「Dev Containers」を使う

## Dev Containersとは？

公式ドキュメント：https://code.visualstudio.com/docs/devcontainers/containers

Dev Containerはコンテナの内部で、簡単に開発環境を構築することができます。
この拡張機能を使用すると、ローカルにRubyをインストールする必要もありません。
（Dev Containerの構築時にGUIで選択するだけ）

また、Dev Containerの設定は[devcontainer.json](https://code.visualstudio.com/docs/devcontainers/containers#_create-a-devcontainerjson-file)の中に記載されます。
一度作成した設定を他でも使いまわせるのはありがたいですね。

↓公式のイメージ図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1450663/e46c93a2-9cc3-1432-aef1-18204c0389c7.png)


## 環境構築

### VSCodeのインストール

各環境に合わせて、インストーラーのダウンロードをしてください。
https://code.visualstudio.com/download

### Dev Containers拡張機能を入れる

VSCodeをインストールできたら左側の列にある以下のアイコンを押下する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1450663/2e1c9136-eb90-f353-196f-b14049b872d7.png)

拡張機能のアイコンを押下したら、表示された入力欄にで以下の拡張機能を検索する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1450663/f5d004f2-fa09-7172-c6e9-49be2acf46c8.png)

### Rubyのインストール

早速Dev Containerを使ってRubyの環境を作っていきましょう。
手順は簡単です。

まずは、コマンドパレットを開いて、「新しい開発コンテナー...」と表示されているものを選択しましょう。

- コマンドパレットの開き方
    - Windows：「ctrl + shift + P」
    - Mac：「cmd + shift + P」

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1450663/e49aff52-9d77-45dc-f658-a76e659b31c4.png)

次の画面で、「Ruby」と入力して、以下のものを選択してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1450663/eec1a257-32ba-aec0-4443-65a264dc54d5.png)

あとは、ポチポチと進めていただければ完成です。
環境が構築できたら、試しにRubyのバージョン確認でもしてみましょう。
バージョンが表示されればOKです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1450663/0dd71245-b2f8-549c-1dfe-ae9e6da14736.png)


## Rubyに触れてみる

Ruby公式ドキュメント：https://www.ruby-lang.org/ja/documentation/

- 入門
    - [20分ではじめるRuby](https://www.ruby-lang.org/ja/documentation/quickstart/)
        - IRB（Interactive Ruby）を使って、コマンドライン上で実行していく。
        - 最後の方には、Rubyのファイルを作成して実行する箇所もある。
    - [他言語からのRuby入門](https://www.ruby-lang.org/ja/documentation/ruby-from-other-languages/)
        - Rubyと何が同じで何が違うのかがまとまっている。
        - 筆者は、[JavaからRubyへ](https://www.ruby-lang.org/ja/documentation/ruby-from-other-languages/to-ruby-from-java/)のページを読んだが、本当に簡単にまとまっていた。
        - 長々と書いていないので、さらっと把握したい人向け。

## 所感

今回は、RubyがかすむくらいにはDev Containerメインでしたね。
書き終わってから気が付きました。
でも、ちょっとは入門のリンクと感想を述べたからね。
決してタイトル詐欺とかでもないからね。
あくまで触れてみるだからね。

こんな感じでやってきましたが、次はRuby on RailsとかReactとかを使って何かを作っていきたいと思いました。
最後まで読んでいただきありがとうございました。
「現代数理統計学の基礎」演習問題解法メモ　第3章問16～21

今回で第3章は終わりです。問22は解いていません。他の方の解答も無く※印級かと。
実際、問16～21は何度やっても自力では解けず、繰り返してやっと解答が理解できて来たというものです。
問21は今でもよくわからず、また(2)の∞の入った積分範囲の変更も良くわかりません。
![第3章問16　P1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576811/b1d57ece-342a-d6bd-1dca-b63e06210381.jpeg)
![第3章問16　P2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576811/42482888-74b4-2f2c-f883-a1704a1626b4.jpeg)
![第3章問16　P3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576811/b4006c5a-17f5-6683-3074-64e83c007720.jpeg)
![第3章問17　P1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576811/32ae866a-fc1e-f5a0-ff5f-81907dc051d8.jpeg)
![第3章問17　P2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576811/43316b6a-b697-eda7-c430-ba87905df0e6.jpeg)
![第3章問18　P1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576811/475e267a-706d-2fad-885b-892031d2146c.jpeg)
![第3章問18　P2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576811/a6509144-e296-56f5-7c5e-b05954b2b453.jpeg)
![第3章問19 P1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576811/9f5a26fe-7dd2-7694-0743-efca24d2e698.jpeg)
![第3章問19　P2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576811/38868695-6f68-ff0e-2dd3-0c4c9fd2cd54.jpeg)
![第3章問20.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576811/5121c3bd-c9e8-bef4-3fbe-5338d85102c1.jpeg)
![第3章問21(1) P1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576811/df276a6d-d1c6-8cf0-dafd-a6cadf71ad00.jpeg)
![第3章問21(1) P2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576811/c790aea8-3da5-98d5-58e4-557f4880504b.jpeg)
![第3章問21(2) P1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576811/551265cf-5d1f-7978-a224-24de8c024525.jpeg)
![第3章問21(2) P2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576811/ac6d8b38-443c-5edb-56ee-ae56460bca62.jpeg)
無料の Web アイコンフォント【まとめ】

アプリには欠かすことのできない「**Web アイコン**」。今回は、シンプルで使いやすく、そして **無料で利用できる** Webアイコンフォントの配布サイトをまとめてみました。

## Heroicons

[![Heroicons](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106716/85fefc9d-32ee-11e2-be83-c73ece1f7486.jpeg)](https://heroicons.com/)
https://heroicons.com/

- MIT License
- アイコンを制作している方は Tailwind CSS の作成関係者
- ブラウザから SVG のコードを簡単にコピペ可
- npm 経由から React or Vue 用のアイコンパッケージをインストールできる

## Remix Icon

[![Remix Icon](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106716/3fd7ba77-d41d-d291-98f3-79a4be2c54a8.jpeg)](https://remixicon.com/)
https://remixicon.com/

- Apache License
- アイコンは SVG 若しくは PNG 形式を選択できる
- npm 経由のインストール可。React or Vue からアイコンインポート可
docker-composeのリソースを別コンテナとして起動したい


とりあえず`docker-compose up -d`してDockerコンテナを使っているけど、それ以外は良く分かっていない人向け。<br>
いつも使っているdockerコンテナは消さないまま別のコンテナで動作確認することが出来ます。
# 手順
1. `docker-compose stop`で今動いてるコンテナを停止する
2. リソースが入っているフォルダを丸ごと複製し、ルートフォルダ名を別名に変更する
3. docker-compose.yamlの`container_name`を別名に変更する
4. docker-compose.yamlのあるフォルダでpowershellを起動する
5. `docker-compose up -d`で起動する
# コマンドについて解説
コンテナ作成・起動
```powershell
docker-compose up -d
```
コンテナ停止・破棄<br>
永続化の設定をしていなければ、DBのデータも破棄します。
```powershell
docker-compose down
```
コンテナ停止、コンテナ起動コマンド<br>
コンテナ内のデータを破棄したいわけではないけれど一時的にコンテナ停止したい時は`stop`コマンドを使ってコンテナを停止することができます。<br>再度コンテナを動かしたい時は`start`コマンドを使います。
```powershell
docker-compose stop
docker-compose start
```
さくらレンタルサーバーで ruby 3.3.0 をビルド

# はじめに
さて，クリスマスといえばRubyのメジャーアップデートですね．早速 [去年と同じ方法](https://qiita.com/cycloawaodorin/items/0bec7bc01849ad7d4ba0) で ruby 3.3.0 をインストールしてみましょう．

```
==> Installing ruby-3.3.0...
-> ./configure "--prefix=$HOME/.rbenv/versions/3.3.0" --enable-shared --with-ext=openssl,psych,+ --disable-install-rdoc --with-openssl-dir=/usr/local "--with-libyaml-dir=$HOME/local"
-> make -j 8

BUILD FAILED (FreeBSD 13.0 on amd64 using ruby-build 20231225-2-g3b79c293)

You can inspect the build directory at /home/cycloawaodorin/tmp/ruby-build.20231229170435.10771.KdS07E
See the full build log at /home/cycloawaodorin/tmp/ruby-build.20231229170435.10771.log
```

おや，ビルドに失敗してしまいました．ログを見てみましょう．

```
(前略)
--- exts.mk ---
configuring digest
configuring digest/bubblebabble
configuring digest/md5
--- enc ---
--- enc/gb2312.o ---
compiling ./enc/gb2312.c
--- exts.mk ---
Killed
*** [ext/digest/exts.mk] Error code 137

make[1]: stopped in /home/cycloawaodorin/tmp/ruby-build.20231229170435.10771.KdS07E/ruby-3.3.0
--- trans ---
*** [trans] Error code 6

make: stopped in /home/cycloawaodorin/tmp/ruby-build.20231229170435.10771.KdS07E/ruby-3.3.0
--- enc ---
*** [enc] Error code 6

make: stopped in /home/cycloawaodorin/tmp/ruby-build.20231229170435.10771.KdS07E/ruby-3.3.0
--- exts.mk ---
1 error

make[1]: stopped in /home/cycloawaodorin/tmp/ruby-build.20231229170435.10771.KdS07E/ruby-3.3.0
*** [exts.mk] Error code 2

make: stopped in /home/cycloawaodorin/tmp/ruby-build.20231229170435.10771.KdS07E/ruby-3.3.0
3 errors

make: stopped in /home/cycloawaodorin/tmp/ruby-build.20231229170435.10771.KdS07E/ruby-3.3.0
external command failed with status 2
```

？？？
何が原因でしょうか．よくわかりません．

# 原因
新しいバージョンのGCCを試してみようとビルドを試みたものの，こちらのビルドも失敗．ググって見たところ，[あるフォーラム議論](https://forums.gentoo.org/viewtopic-p-8719091.html?sid=121c49f36a793f78466b4891eea2a62e) が見つかりました．

> xg++: fatal error: Killed signal terminated program cc1plus	
> In almost every cases, this means ran out of memory

ああ，これはありえそうです．さほどメモリが潤沢ではないのに，`make -j 8`は厳しいかもしれません．

# 解決法
次の環境変数を設定すればビルドできます．

```
MAKEOPTS="-j1"
```

他の環境変数と合わせると，実行すべきコマンドは
```
$ CC=gcc MAKEOPTS="-j1" RUBY_CONFIGURE_OPTS="--with-openssl-dir=/usr/local --with-libyaml-dir=$HOME/local" TMPDIR="$HOME/tmp" rbenv install 3.3.0
```
となります．libyaml-devは [前回の記事](https://qiita.com/cycloawaodorin/items/0bec7bc01849ad7d4ba0#libyaml-%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB) の方法でビルドしておきましょう．

```
==> Installing ruby-3.3.0...
-> ./configure "--prefix=$HOME/.rbenv/versions/3.3.0" --enable-shared --with-ext=openssl,psych,+ --disable-install-rdoc --with-openssl-dir=/usr/local "--with-libyaml-dir=$HOME/local"
-> make -j1
-> make install
==> Installed ruby-3.3.0 to /home/cycloawaodorin/.rbenv/versions/3.3.0
```
無事ビルドできました．

というわけで，makeを8並列実行してはメモリ不足でビルドに失敗するので，並列実行をやめましょうということでした．

ちなみに GCC 13.2 は `MAKEOPTS="-j1"` でもビルドに失敗したので，使いたい場合はローカルマシンでクロスコンパイルしてアップロードする必要がありそうです．

# 追記
```
Killed
*** [ext/digest/exts.mk] Error code 137
```
どうやら137というのがメモリ不足のしるしみたいですね．"Killed"というのもメモリー使い切りで発生させたことがあった気がします．
LivebookでDoctestが使えるよ

Livebookを久しぶりに起動して、トップページにある説明を眺めていたら、いろいろ知らない事が書いてありました。

Doctestが書けます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532235/11bf2251-245b-416d-bf03-e274d8468622.png)

ExUnitも使えます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532235/2a79cf62-ae49-4601-f1de-f89bb8b7f588.png)

使いやすくなってますね。

私と同じような、浦島太郎状態の方と、驚きを共有したいので記事にしておきます。
未経験営業がエンジニアに転職してみた

## この記事は
- 知識・経験ゼロでエンジニアになった人間が、転職した時の経験と考え方。
- 同じくIT業界に飛び込みたい！と思う方には役立つかもです。
- 結構脳筋の考え方なので合わない人は合わないかも。


## 筆者の転職前
- まだここにない出会いを提供する某広告会社で営業
- しばらくして「一生営業で食って行くのは無理」と感じる
- 市場価値を高めるには手に職をつけるべきと考え、エンジニアになることを決意

## 転職のstep
私観ですが下記に分かれると思っています。

1.決断をする
2.動機を「作る」
3.職種と会社を絞る
4.自己アピールする

本題に行くぞ

## 1.決断をする
#### あたり前ですが転職なんてめんどいです。
<br/>
まさか、

「わたし重度の転職フェチでこれまで19回転職してるの〜20回目はどこにしようかな！」

なんてイカれた思考の持ち主はいませんよね？
そう、転職はしんどいし面倒です。

業種を絞るのも面倒
会社を絞るのも面倒
履歴書も職務経歴書も書きたくない...もうChatGPTに書かせればいいか。

誰だってそう思います。

そんなめんどいことを成功させるんですから、必要になるのは強固な「意志」です。

ポジティブでもネガティブでも、決断の理由自体は真面目になんでもいいです。

「今より楽な暮らしがしたいだけだから、かっこ悪くて人に言えない...」

とかも別に思わなくていいです。面接なんてそれを着飾って話すだけなので。
むしろそういったプリミティブな感情の方がエネルギーになりやすいはず。
胸を張れ。



## 2.動機を「作る」
前段でなんでもいいと言いましたが、あくまでそれは決断する時の話です。

「週3回はお家でハナクソほじりながら仕事したいんです〜」

なんて面接で言ったらワンチャンはっ倒されます。
それでも素直に伝えたければ止めませんので、腹に鉄板でも仕込んでください。
<br/>
マインド的な話が続いて申し訳ないんですが、決断をした後は、人様に話せるように

決断の理由→動機

に加工する必要があります。この辺は言い換えってやつですね。

若干の脚色を加えるのも効果的ですし、綺麗な日本語を使うと更にいい感じに聞こえます。
例えば、
- 収入を上げたい → 転職市場での価値を高めて、活躍できる人材になりたい。
- 楽な生活がしたい → ワークライフバランスをとって、自己学習の時間を作りたい。
- 上司がクソ → 風通しの良い環境で、自らも会社を良くするための発信を行いたい。

このくらい言えれば上出来かと。
<br/>
そしてここが重要なんですが、今度はこの動機を本気で信じる必要があります。
なんの躊躇いもなくウソをつける人間って限られてるので、思い込みは必要なんですよね。
ここでつまづく人が多い印象なんですが、おすすめの対処法は
「とにかく話す」
これに尽きます。

言霊じゃないですが、口にし続けるといつか達成の意欲が湧いてくるものです。
(認知的不協和理論なんかがいい例かも)
友人や家族,誰でもいいので話しましょう。


## 3.職種と会社を絞る
自分の望む働き方が決まったら、今度は職種を絞りましょう。
一般的なフローだと業種から絞るかもしれませんが、個人的にはお勧めしないです。
例えば職種が「営業」であれば、普段やることって大体、

「目標の達成に向けて」
「お客さんに電話をかけて」
「営業をかけて」
「契約をとる」

これを毎月繰り返すのみ。
業種による違いって想像つかないんですよね〜。
知らないことに関して真実味のある話はできないので、業種で推すのはやめた方がいいと思います。普通に毎日やっても飽きないな、嫌じゃないな、と思うものから絞りましょう。
<br/>
会社に関しては素直に条件面と、やりたいことが叶うかで選んでしまって良いです。
前述しましたが面接でいいように話せれば問題ないです。

## 4.自己アピールする
一番大事なのはここ。忘れてはいけないのが、

「相手の企業に対するメリット提示」

この意識は忘れずにいましょう。やることは商談です。
で、商談するにあたって、自分の一番の武器以外は使わない方がいいです。

ポートフォリオが提示できるなら別ですが、
「ProGateでHTMLとCSS勉強してます〜」
とか言っても、経験者も何人も見てきた採用担当者やエンジニアからすると

「そうなんだ」

で終わります。
場合によっては

「あー効率悪いね」

とか言われます(経験談)。
そこでゴリ推しするよりは

「自分ができること」
「企業のやっていること」
「上記を掛け合わせると何ができるか」

で商談した方が効果的です。
何人も何人も「文系ですがものづくりが好きで〜」とか何人も何人も同じような話聞いてる担当者からすると、

「私が今、営業として関わっているお客さんと御社の商品を繋げてみたら面白いことができそうじゃないですか？」

みたいな話を聞いた方が興味は確実に引けます。
転職動機〜メリット提示まで、論旨が一貫するよう意識しましょう。


## 最後に
かなり経験談が混じりましたし、志望する会社によって、もちろん状況は変わります。
それでも、

「転職は意志力」「面接は商談」

この2つは割とどこでも当てはまると思っています。
皆さんの転職が良きものになるよう〜。
Raspberry Pi上で藍ちゃんを動かす

# 藍ちゃんとは
藍ちゃんはMisskeyの日本語用Botです。
しゅいろ([@syuilo@misskey.io](https://misskey.io/@syuilo))さんにより開発されており、リマインドや数取りゲームなどのゲームをしてくれたり、おしゃべりしてくれたりします。
Dockerfileが用意されているため、Dockerさえインストールされていれば環境構築不要で動かすことができます。
リポジトリはこちら

https://github.com/syuilo/ai

ぼくが運営しているMisskeyサーバーである[jiskey](https://jiskey.dev)でも藍ちゃんを動かしており、多くの方にフォローしていただいています。

https://jiskey.dev/@ai

# Raspberry Piで動かすことにした経緯
jiskeyでは藍ちゃんをもともとGCP(e2-micro)で動かしていました。
しかしながら月1400円ほどかかっており、割高に感じていました。
そのため、jiskeyを動かしているRaspberry Pi上で藍ちゃんも動かすことでクラウド費用を抑えることにしました。

![スクリーンショット 2023-12-29 16.40.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692201/47d678bb-9b2b-a3ab-d07e-9ecd439cb096.png)

# 前提
動作環境は以下のとおりです。
- ハード: Raspberry Pi 4B 4GB
- OS: Raspberry Pi OS Lite 10 (debian bullseye)
- Docker

今回藍ちゃんはDockerで動かします。
Raspberry Pi上で動作するようにした藍ちゃんはこちらにあるのでこちらも参考にしてください。

https://github.com/jj1guj/ai

# Raspberry Piで藍ちゃんを動かす

## `docker-compose.yml`を書き換える

以下のように`docker-compose.yml`のplatformを書き換えます。

```
      context: .
      args:
        - enable_mecab=1
    platform: linux/aarch64
    volumes:
      - './config.json:/ai/config.json:ro'
      - './font.ttf:/ai/font.ttf:ro'
```

## `Dockerfile`を書き換える

### ベースイメージを変更する
オリジナルはベースイメージにnode:lts-bullseyeを使用していますがこれをnode:18-bullseyeに変更します。これはNode.jsのバージョンが原因で動かなくなることを懸念して動くことが確認できているNode 18に変えたのですが、ltsにしても問題ないかもしれません。

```dockerfile
FROM node:18-bullseye
```

### 依存パッケージをインストールするようにする
aarch64向けのnode Dockerイメージにはcanvasモジュールの依存関係が入っていないようで、`npm install`時にcanvasモジュールがインストール出来ない旨のエラーが出ます。
また、makeもインストールされていないためビルド時にビルドできない旨のエラーが出ます。
そこで、これらの依存関係をインストールするようにします。

```dockerfile
RUN apt-get update && apt-get install -y tini libpango1.0-dev libcairo2-dev libjpeg-dev libgif-dev build-essential
```

[余談]ここでずっと詰まっていたのですがChat GPTに聞いたら一瞬で解決しました…

https://chat.openai.com/share/5114d691-fa36-4d27-8842-052686f27e17

### mecabの辞書のパスを書き換える
以下のようにmecabの辞書のパスを書き換えます。

```dockerfile
echo "dicdir = /usr/lib/aarch64-linux-gnu/mecab/dic/mecab-ipadic-neologd/" > /etc/mecabrc
```

### `npm install`を書き換える

@types/babel__traverseがバグっているらしく`npm install && npm build`だとビルドに失敗するためバージョンを下げてインストールするようにします([参考](https://github.com/syuilo/ai/issues/117))。

```dockerfile
RUN npm install --save @types/babel__traverse@7.18.3 && npm run build
```

# Raspberry Pi上で動かしてみた感想

当初Misskeyと藍ちゃんを同時に動かすことで多少負荷が上がると考えていましたが、実際に動かしてみるとそのようなことはありませんでした。
そのため、コスト削減のために同時に動かすのは選択肢としてありなのかもしれません。
しかしながらデータが吹っ飛ぶときはMisskeyと藍ちゃんの両方とも吹っ飛ぶので、データが飛んだときの対策が今後の課題です。
定期的にデータのバックアップを取ろうと思います。

# 今回の教訓
npmのエラーはChat GPTに任せよう
Jenkins PipelineでSSH接続するのに苦労した話

# やりたかったこと
JenkinsのジョブでLinuxサーバに接続し、Spring bootで作ったJavaアプリ（jar）を起動したかった。

# ハマったこと
1. Jenkinsに登録した認証情報を使ってSSH接続する。
1. SSH接続した後、起動用のシェルファイルを実行したがエラーが発生。

# なぜできなかった
1. 大人の事情でSSH Agent Pluginは使用できなかったため、愚直にSSH接続を行った。
ssh接続の認証はユーザ名＋パスワード。
SSH_ASKPASSを使用し、Jenkinsに登録した認証情報（Credentials）を使って接続を行う。
2. エラーはロケールが問題だった。SSHのデフォルト設定でロケール周りの環境変数を接続先に渡してしまっていた。

# 対処法
1. SSH_ASKPASSを利用してパスワードの入力を自動化した。
1. 空のconfigファイルを作成し、SSHコマンド実行時に指定した。

# コード
以下はサンプルのコード
```groovy:pipeline
pipeline {
    // agentやenvironmentは省略
    stages {
        stage('サンプルステージ') {
            steps {
                withCredentials([usernamePassword(credentialsId: 'logindata', usernameVariable : 'USERNAME', passwordVariable: 'PASSWORD')])

                    sh """
# インデントに注意
cat <<EOF > ask_pass
echo ${PASSWORD}
EOF
                    chmod +x ask_pass
                    
                    export SSH_ASKPASS=$0
                    export DISPLAY=dummy:0

                    # 空のconfigファイル作成
                    touch sshconfig

                    # 空のConfigファイルを指定して
                    # sshコマンドを実行
                    ssh -f -F sshconfig ${usernameVariable}@hostname.co.jp "sh remort.sh"
                    """
            }
        }
    }
}
```

# 感想
Linuxの知識が足りず苦労することが多かった。
数こなして知識を付けていきたい。
Python: tifffileを使って、画像をImageJで読み込める形の.tifファイルとして書き出す

作成日：20231229
言語：Python3

# tifffileとは
pythonで出力した画像をtif形式で保存したい時は、ライブラリ「tifffile」を使えば書き出しができます。tifffileは通常のtif以外にも、バイオ系でよく使われる画像ソフトや顕微鏡画像のフォーマットにも対応していて、メタデータも含めて読み書きすることができます。
（メタデータがない場合はscikit imageのio.imsaveなんかでも事足りそう。）

### 参考リンク:
元コード（作者のGitHub）はこちら。冒頭に一通り使い方の説明が書いてあります。

https://github.com/cgohlke/tifffile/blob/eb79f64e65fdd17fa5722dac9ce32ec6dd224f5d/tifffile/tifffile.py


# インストール

```
$ pip install tifffile
```

# サンプルコード

```python:create_img.py
 ### 画像作成
 import numpy as np
 
 img_stack=(np.random.rand(15,512,1024,3)*255).astype(np.uint8)
 print(img_stack.shape)
 
 ## 出力結果
 ## (15,512,1024,3)
```


今回はz-stackが15枚、大きさが 512×1024 のRGB画像を想定しています。蛍光顕微鏡で撮影した画像等を、.tif形式でImageJで簡単に開ける形で保存したいとします。
今回はRGB画像なので、データ型をnp.uint8（8-bitの非負の整数）にしておきます。

```sample_tifffile.py
 ### 画像の書き出し
 import tifffile
 
 with tifffile.TiffWriter('./img_tifffile.tif', imagej=True) as tif:
     tif.save(img_stack[np.newaxis, :, np.newaxis, :, :, :])     
     #ImageJ assumes TZCYXS order. Beware that a color channel is 'S', not 'C'.
```

tifは6次元の画像ですが、次元の順番はTZCYXSの順番にしておきます。TZCYXSはそれぞれTime, Z stack, Channel(撮影時のチャンネル数), Y(height), X(width), Sample(カラー)のチャネルを指します。
Cがカラーではなくchannel（GFPとRFPで2チャネルで撮影した時などに使う）であることに注意。Sがカラー。
RGB(S=3)やRGBA(S=4)等のカラー画像を保存する際は、忘れずに画像のデータ型を8-bitにしておきましょう。


### 参考リンク：
TZCYXSの意味については、作者のGitHubを参照しました。

https://github.com/cgohlke/tifffile/blob/eb79f64e65fdd17fa5722dac9ce32ec6dd224f5d/tifffile/tifffile.py#L16694-L16737

（https://forum.image.sc/t/what-is-s-in-tzcyxs/72225 ここに作者本人が回答していたのから遡りました）

scikit imageの古いdocumentationにも簡潔にまとまっています。

https://devdoc.net/python/scikit-image-doc-0.13.1/api/skimage.external.tifffile.html#skimage.external.tifffile.TiffWriter

（何故scikit imageのdocumentationに説明があるのか気になって軽く調べてみたのですが、tifffileは現在は独立のパッケージですが、以前はscikit imageの一部として実装されていたようです。私の手元のskimage 0.15.0では`import skimage.external.tifffile`ができましたが、最新バージョンではskimage.external.tifffileというモジュールはなくなっているようです。`import tifffile`するのが安全なように思います。）


# 補足 （tifffileのその他の機能）
tifffileを使うと、画像全体の読み込み・保存だけでなく、画像を直接開くことなく一部だけ確認したり読んだりすることもできます。最初の1スライスだけ読み込むとか、1成分だけにアクセスするとかの操作で大きな画像をいちいち開く必要がなくなるので、処理を高速化できます。

### 参考リンク：
Qiita記事

https://qiita.com/Hanjin_Liu/items/7a01c1c481161fe20a3e

（再掲）作者の元コードの冒頭にも一通り使い方が書いてあるので、こちらもご参照ください。

https://github.com/cgohlke/tifffile/blob/eb79f64e65fdd17fa5722dac9ce32ec6dd224f5d/tifffile/tifffile.py
OpenCVでwebカメラの映像を表示する

画像認識においてpythonでwebカメラの映像を使用することがよくあります。そこで今回は基本的なwebカメラの映像をOpenCVで取り込み表示するコードを書いてみたいと思います。


まず、PythonでOpenCVを使用するためには、OpenCVライブラリをインストールする必要があります。pip install opencv-pythonを実行することでインストールできます。

以下のコードはウェブカメラの映像を表示するための基本的なコードです。

```python3:app.py
import cv2

# ウェブカメラのキャプチャを開始
cap = cv2.VideoCapture(0)

# キャプチャがオープンしている間続ける
while(cap.isOpened()):
    # フレームを読み込む
    ret, frame = cap.read()
    if ret == True:
        # フレームを表示
        cv2.imshow('Webcam Live', frame)

        # 'q'キーが押されたらループから抜ける
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    else:
        break

# キャプチャをリリースし、ウィンドウを閉じる
cap.release()
cv2.destroyAllWindows()
```

このコードでは、
```
import cv2
```
でOpenCVをインポート。

```
cap = cv2.VideoCapture(0)
```
でウェブカメラのキャプチャを開始（0はデフォルトのウェブカメラを示します）。

```
while(cap.isOpened()):
    # フレームを読み込む
    ret, frame = cap.read()
    if ret == True:
```
でウェブカメラが開いている間、フレームを継続的に読み込みます。

```
cv2.imshow('Webcam Live', frame)
```
で各フレームをウィンドウに表示。

```
if cv2.waitKey(1) & 0xFF == ord('q'):
    break
```
でユーザーが「q」キーを押すと、ウィンドウを閉じてプログラムを終了。

ウェブカメラの番号（上記のコードでは0）は、使用するデバイスや設定によって異なる場合があります。複数のカメラがある場合は、1、2などに変更して試してみてください。また、このコードを実行するには、コンピュータにカメラが接続されていて、適切なドライバがインストールされている必要があります。