OmniAICreator/Qiita-1.07M huggingface dataset:
【React】hoge.map is not a functionの解決方法

# はじめに
本記事では、Reactでmapを使用した際に発生する「***hoge.map is not a function***」というエラーの原因とその解決方法について解説します。特に`state`の初期値に関する誤りが原因で、このエラーが発生する場合の対処法を紹介します。
 
:::note warn
***この記事は<font color="Red">個人的なアウトプット</font>を目的として作成したものです。そのため、誤った情報や不足している内容が含まれている可能性があります。もし間違いや気になる点がございましたら、ぜひご指摘いただけますと幸いです***。
:::

# 事象
ボタンをクリックすると、以下のように`div`要素が追加されていく機能を実装しました。しかし、このコードを実行すると次のエラーが発生しました。

```
hoge.map is not a function
```
***実際のコード***
```react
function App() {
  const [box, setBox] = useState(1);

  const onClickAddBox = () => {
    if (box.length < 5) {
      setBox((box) => [...box, box.length + 1]);
    }
    console.log("ボックスが増えました");
  };
  return (
    <>
      <button onClick={onClickAddBox}>ボックスを追加</button>
      {box.map((item, index) => (
        <div key={index}>
          <p>ボックスが増えます</p>
          {item}
        </div>
      ))}
    </>
  );
}
```

# 原因
`state`の初期値が配列の形になっていなかったためのこのエラーが発生しました。
***<font color="Red">エラーの原因は、stateの初期値が配列ではなく数値として設定されていたことです。</font>*** mapは配列メソッドであるため、配列以外のデータ型に対して使用するとエラーが発生します。

このコードでは、boxを配列として扱いたいにもかかわらず、初期値が数値(1)になっていました。その結果、box.mapを呼び出そうとした際にエラーが発生しました。

***修正コード***
修正後のコードでは、`box`の初期値を数値から配列([1])に変更しました。これにより、`box`に対して`map`メソッドを正しく使用できるようになりました。

```react
function App() {
  const [box, setBox] = useState([1]); //配列の形に変更

  const onClickAddBox = () => {
    if (box.length < 5) {
      setBox((box) => [...box, box.length + 1]);
    }
    console.log("ボックスが増えました");
  };
  return (
    <>
      <button onClick={onClickAddBox}>ボックスを追加</button>
      {box.map((item, index) => (
        <div key={index}>
          <p>ボックスが増えます</p>
          {item}
        </div>
      ))}
    </>
  );
}
```

# 終わりに
本記事では、stateの初期値が適切でない場合に発生する「hoge.map is not a function」エラーの原因と解決方法を紹介しました。stateのデータ型や初期値に注意していきたいと思います。

# 参考

【JavaScript入門】配列処理をするmap()の使い方とMapオブジェクトの解説！

https://www.sejuku.net/blog/21812

『【js】x.map is not a functionの解決方法とそれから理解したこと』　Qitta

https://qiita.com/mk-tool/items/cdf80eeef761e8219711
RustでReversiを高速化したい

# はじめに

ReversiをRustでビットボードを使って実装することにより、高速な処理を実現しつつ、PyO3でPythonバインディングを提供することで使いやすいインターフェースを実現しました。

機械学習で効率的にReversiを実行することを目標としています。

# インストール

```bash
pip install rust-reversi
```

# 実装のポイント

## ビットボード

64マスのボードを64ビットの整数で表現することで、ビット演算による高速な状態管理を実現しています

```rust
struct Board {
    player_board: u64,
    opponent_board: u64,
    turn: Turn,
}
```

## 合法手生成

ビット演算を活用して効率的に合法手を生成しています

```rust
fn get_legal_moves(&self) -> u64 {
    let horizontal_watch = 0x7E_7E_7E_7E_7E_7E_7E_7E & self.opponent_board;
    let vertical_watch = 0x00_FF_FF_FF_FF_FF_FF_00 & self.opponent_board;
    let all_watch = 0x_00_7E_7E_7E_7E_7E_7E_7E_00 & self.opponent_board;
    // ...
}
```

## Pythonインターフェース

PyO3により、Pythonから直感的に操作できます：

```python
from rust_reversi import Board, Turn, Color

board = Board()
legal_moves = board.get_legal_moves_vec()
move = board.get_random_move()
board.do_move(move)
```

# 機能一覧

- ボード状態の管理
- 合法手の生成と検証
- ゲームの進行管理
- 駒数の計算
- テスト用のランダム手生成

# テスト

Perftテストによって実装の正確性を確認しています

```python
def perft(board: Board, depth: int) -> int:
    if depth == 0:
        return 1
    if board.is_game_over():
        return 1
    if board.is_pass():
        new_board = board.clone()
        new_board.do_pass()
        return perft(new_board, depth - 1)
    count = 0
    for mv in board.get_legal_moves_vec():
        new_board = board.clone()
        new_board.do_move(mv)
        count += perft(new_board, depth - 1)
    return count
```

# あとがき

山岡忠夫先生のcreversiが最適化されすぎている(SIMD命令)、古い(numpyのバージョンが古い)ということがあり、自分でreversiを実装してみました。

個人的にはReversiは単純すぎず、難しすぎず教師あり学習や強化学習の題材としてとても優れていると思っています。

学習や推論はPythonで行いたいけどPythonは速度が遅くてつらい...というときに使ってみてください。
~~探索、学習もRustで書けばよいのではないですか？~~

今後は対戦機能や機械学習によるAIの実装をしてみたいです。


# 謝辞
本記事の執筆にあたり、Anthropic社のAIアシスタントClaudeには記事の構成、内容の整理、および表現の改善において多大なる支援をいただきました。ここに感謝の意を表します。

# 参考

- rust_reversi: https://github.com/neodymium6/rust_reversi
- PyPI rust-reversi: https://pypi.org/project/rust-reversi/
- Perftの活用: https://www.egaroucid.nyanyan.dev/ja/technology/explanation/
- creversi: https://github.com/TadaoYamaoka/creversi
- ビットボード: https://qiita.com/sensuikan1973/items/459b3e11d91f3cb37e43
全部知ってる？VSCodeの拡張機能たち

はじめに
---
皆さん、VSCode使ってますか？使ってますよね？

VSCode（Visual Studio Code）は、多機能かつ軽量なエディタで、多くのエンジニアが愛用しています。でも、標準のまま使っているとなんだか味気ない…そんなあなたに朗報です！VSCodeには "拡張機能" という名の魔法のアイテムがあるんです！今回はおすすめの拡張機能を紹介します。

拡張機能たち
---

## Git Graph - ビジュアルでGitの歴史を追え！
「ブランチ構造が複雑で混乱する…」そんなとき助けになるのが **Git Graph** です！

### ✨ 特徴
- リポジトリの履歴を視覚的に確認可能
- ブランチやマージの状況が一目でわかる
- コミットの詳細情報も簡単に閲覧

### :speech_balloon: コメント
「うわ、私のコミット汚すぎ:persevere:」
視覚化すると綺麗にしようと心掛ける習慣作りになりますね

### 🖼️ リンク

https://marketplace.visualstudio.com/items?itemName=mhutchie.git-graph

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3553959/5ea7748f-3b20-0bdd-0d27-ac13c52f07e6.png)

## Auto Rename Tag - タグ編集のひと手間ケア！

HTMLを書いているときに、開閉タグを両方直すのが面倒に感じたことはありませんか？ **Auto Rename Tag** がその悩みを解決！

### ✨ 特徴
- HTMLやXMLのタグを編集するとき、ペアとなるタグも自動で更新
- 作業時間が短縮！
- コードのミスを減らせる

### :speech_balloon: コメント
「痒い所に手が届く:relaxed:」
慣れちゃうと無しでは生きてけない体になるやつ

### 🖼️ リンク

https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-rename-tag

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3553959/4acc2362-7581-0711-fa05-334ed705d191.png)

## vscode-pet - 仕事場にかわいいペットを！

「プログラミング疲れたよ…癒しが欲しい…」 **vscode-pet** があなたを癒します！

### ✨ 特徴
- ターミナルにかわいいペットが登場
- あんなキャラがペットに！？
- 作業の合間にちょっと一息

### :speech_balloon: コメント
「あなたはだあれ？〇〇〇って言うのね！:cat2:」
ぜひ、インストールして確認してみてください

### 🖼️ リンク

https://marketplace.visualstudio.com/items?itemName=tonybaloney.vscode-pets

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3553959/b67d7538-b028-5c0e-72b9-371a7be29c42.png)

## Rouge Theme - かわいいテーマで目に優しい環境を

カラフルすぎるエディタ画面に疲れていませんか？ **Rouge Theme** なら、目に優しい配色で快適なコーディング環境を提供します。

### ✨ 特徴
- かわいい‼
- 落ち着いた配色で集中力アップ
- 長時間の作業でも疲れにくい

### :speech_balloon: コメント
「Kawiiはつくれる:lipstick:」
白系でPC周り揃えてるインフルエンサーの画面テーマ

### 🖼️ リンク

https://marketplace.visualstudio.com/items?itemName=josef.rouge-theme

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3553959/a5e06259-1320-431f-565d-ec6f5822dd6c.png)

## Material Icon Theme - アイコンで一目瞭然！

「ファイル名だけじゃどのファイルかわからない…」そんな悩みを解決するのが **Material Icon Theme**

### ✨ 特徴
- ファイルタイプごとにアイコンを割り当て
- 見た目が分かりやすく、整理整頓にも最適
- プロジェクト全体が直感的に把握可能

### :speech_balloon: コメント
「色んな管理系のアイコン これデフォルトにしてくれ :pray:」
Material Iconデザインした人たち センスありすぎる

### 🖼️ リンク

https://marketplace.visualstudio.com/items?itemName=PKief.material-icon-theme

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3553959/1ac5e207-394b-28d0-52e0-bc91adcba53d.png)

## Edit CSV - CSVファイルを簡単に操作！
「CSVを編集するのが地味に面倒…」そんなときに便利なのが **Edit CSV**

### ✨ 特徴
- CSVファイルを表形式で編集可能
- セルの編集がスムーズ
- データの確認や修正が簡単！

### :speech_balloon: コメント
「Excelくん、きみは卒業で :wave:」
Excelのために文字コード変えるの地味にめんどくさかったんですよね

### 🖼️ リンク

https://marketplace.visualstudio.com/items?itemName=janisdd.vscode-edit-csv

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3553959/bac7a00a-b8ca-18bc-02a8-0687e440e12e.png)



おわりに
---

今回は、VSCodeのおすすめ拡張機能を紹介しました。VSCodeはそのままでも優れたエディタですが、拡張機能を活用することでさらに便利で楽しい開発環境を作ることができます！
ぜひ、これらの拡張機能を試して、自分に合った開発環境を作り上げてください！
開発の効率アップとともに、コーディングがもっと楽しくなること間違いなしです✨
ReactNative でアプリをつくってみる（ToDoリスト編）

## React Nativeでアプリケーションをつくってみる

現在エンジニア歴４ヶ月の私ですが、勉強にきょうからコツコツアプリをつくっていきます。
その備忘録を残していきます。

最初はExpoの立ち上げから

[Expoドキュメント](https://docs.expo.dev/get-started/create-a-project/)


```
npx create-expo-app --template
```

````
create-expo-app@3.2.0
Ok to proceed? (y)  
````
 - yesを選択
<br><br>


 

````

 Choose a template: › - Use arrow-keys. Return to submit.
    Default
    includes tools recommended for most app developers
    Blank
  ❯ Blank (TypeScript)
    Navigation (TypeScript)
    Blank (Bare)
````
- Blank (TypeScript)を選択
<br><br>

````
What is your app named?
````
- 任意の名前　<br><br>

````
- cd my-app
- npm run android
- npm run ios
- npm run web
````
- 作成したディレクトリに移動して立ち上げたいコマンドを実行　<br><br>

または<br><br>


````
npx expo start
 ````
スマホにExpoアプリをダウンロードしておき
コマンド実行後、ExpoアプリからQRを読み取ると立ち上がります。

![Screenshot_20241213-230157.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704697/54e4c440-600f-aa8b-bf41-51d1a0321246.png)
ViperIDEを使ってみる②：パッケージマネージャーを使ってみる

# パッケージマネージャー

ViperIDE では [micropython-lib](https://github.com/micropython/micropython-lib) に集められているMicroPython のパッケージを簡単に扱える。

左ペイン下の箱が重ねられたようなアイコンをクリックするとパッケージマネージャーになります。

![スクリーンショット 2024-12-13 22.24.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/d5757861-fa17-f0dc-bd5c-8f643ed08837.png)

試しに usb-device-mouse にアクセスしてみる。パッケージマネージャーに一覧表示されている中から usb-device-mouse の右にある↓をクリックする。

![スクリーンショット 2024-12-13 22.33.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/b4202d1f-e464-75fa-b5da-635d8d70a28e.png)

左ペインの下にあるフォルダのアイコンをクリックしてファイルマネージャーに戻ると、MicroPython のファイルシステムの lib ディレクトリに usb-device-mouse の動作に必要なライブラリがインストールされている。

![スクリーンショット 2024-12-13 22.38.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/1a267ce0-bc12-9f02-338d-a45b95f712b0.png)

せっかくなので、[マウスのサンプルプログラム](https://github.com/micropython/micropython-lib/blob/master/micropython/usb/examples/device/mouse_example.py)を試してみる。

![スクリーンショット 2024-12-13 22.56.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/18b139be-3b40-2d48-c5e3-ed4c5e71687c.png)

REPL から以下を実行してみる。

```python
>>> from mouse_mnain import *
```

マウスカーソルが左右に動いて、コンテキストメニューが現れることを確認。

![スクリーンショット 2024-12-13 23.00.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/82cadd8c-6995-27ad-23e8-1fcfc25fa5e3.png)
YAMAHAルータでリモートアクセスVPN(IKEv2)に対応する

こちらは [ZYYX Advent Calendar 2024](https://qiita.com/advent-calendar/2024/zyyx) 12/12の記事です。

# 概要
所持しているYAMAHAルータ(RTX1210)のリモートアクセスVPN機能について、2024/07のファームウェアアップデートのタイミングでIKEv2を使ったリモートアクセスVPN接続が行えるようになったので試しました！（途中ハマってYAMAHAお客様相談センターに助けてもらいました！）という記事です。

# リモートアクセスVPN(IKEv2)を使いたかった理由
IKEv2を使いたかった一番の理由は、Android12以降のバージョンでIKEv2を用いたVPN接続設定がメインとなり、これまで利用していたL2TP/IPsecのVPN接続設定が新規作成できなくなったからです。

2022/09頃にYAMAHAお客様相談センターに、YAMAHAルータ側でIKEv2でのVPN接続に対応する予定があるか、と問い合わせた痕跡が手元に残っておりました。
当時のお返事としては、「L2TP/IPsec以外のリモートアクセスVPN方式に対応する予定はございません。」でした。
でも私は信じてる･･･！今は対応してなくてもYAMAHAさんはそのうち対応してくれるって･･･！
で、2024/07にちゃんと対応してくれたわけですよ。待ってて良かった。

# 設定の際に役立つページ
IKEv2を用いたリモートアクセスVPNの設定方法はYAMAHAの公式のページがわかりやすいです。


https://www.rtpro.yamaha.co.jp/RT/docs/ipsec/ikev2_ras/index.html

また、YAMAHA機器に特化したChatGPT、「YNGPT」も便利でした。（返される内容に少し翻弄されもしました）

https://cyber-telework.jp/archives/4423

あとは基本。YAMAHAルーターシリーズ コマンドリファレンスのページ。

https://www.rtpro.yamaha.co.jp/RT/manual/rt-common/

# 設定内容
実際に設定したトンネル設定は以下のようになりました。
トンネルインタフェース番号:10
ポリシーID:20
としています。

```
tunnel select 10
 tunnel encapsulation ipsec
 ipsec tunnel 20
  ipsec sa policy 20 10 esp
  ipsec ike version 10 2
  ipsec ike keepalive log 10 off
  ipsec ike keepalive use 10 on rfc4306 10 3
  ipsec ike local name 10 XXX.XXX.XXX.XXX ipv4-addr
  ipsec ike pre-shared-key 10 text himitsu
  ipsec ike remote name 10 xxx.example.com fqdn
  ipsec ike mode-cfg address 10 1
  ipsec auto refresh 10 off
 tunnel enable 10
```

## はまった点（2つ）
- ipsec ike local name で type を key-idにしてうまくいかなかったので最終的に type を ipv4-addr にしました。
- ipsec ike remote name も type を key-id にして、nameを「vpnclient」にしたんですがうまくいかなかったので type を fqdn に変えて、xxx.example.com のようなFQDN形式にしました。

上記はいずれもYAMAHAお客様相談センターにメールで問い合わせて、解決した内容となります！

# おわりに
一番いいたかったことは、
ヤマハネットワーク製品お客様相談センターは的確にサポートしてくれて助かる！
でした。
多分また今後もお世話になる事があるのでしょう･･･。
stormworksのLuaで二分法する話

### 始めに
ストームワークスでluaをやってるとたまに出てくる二分法のお話。
比較的プログラミング初級者向けの内容です。
そしてこの記事はこちらのアドベントカレンダーの記事です。

https://adventar.org/calendars/9924

### プログラムにおける二分法とは
二分法というのは、プログラムで数値解析を行う求根アルゴリズムのひとつです。
ひとつ例を挙げると、平方根があります。

luaなら _math.sqrt(x)_ で求まりますが、それを使わずに *√x* を求めてください。

というときに使われる手法の1つが二分法です。
一番簡単かつ安定している求根アルゴリズムです。
あと文字数が少ないというメリットがあります。（ストワでは大事）

### 二分法の簡単な考え方
たとえば *√2* なら二乗が2になる数値を二分しながら探します。
最初の範囲は1から2、中間は1.5です。
二乗が2になる数値（1.41421356）は1から1.5の間にあるので、次の範囲を1から1.5にします。
範囲1から1.5の中間は1.25になり、次の範囲は1.25から1.5になります。
その次は1.3625…と範囲の指定と中間の数値を繰り返して求めていけば行けばそのうち1.41421356に近づいて行きます。
これが二分法の原理です。
実装するうえで、 *f(x)=0* の方が都合かいいのでそれで実装します。

### 二分法のプログラム
```lua
--a,b範囲
--maxTime最大繰返し回数
--eps許容誤差
--f指定する関数

function bisection(a, b, eps, f,maxTime)
	local i, s = 0, 0
	while math.abs(a - b) > eps and i<maxTime do
		i = i + 1
		s = (a + b) / 2
		if (f(a) * f(s) < 0) then --f(a)*f(s)<0のとき、その間にf(x)=0となるxがある
			b = s
		else
			a = s
		end
	end
    if i>=maxTime then s=0 end --error
	return s
end
```
これが二分法の関数です。
実際簡単に実装可能で、for文で実装する方法もあります。

ただし使用する場合条件があります。
- 範囲内に確実に0となる *f(x)* が __ひとつだけ__ 存在すること
- *f(x)* は指定範囲内で __単調増加または単調減少である__ こと

根が二つ以上存在する場合は範囲を分割する必要があります。
許容誤差はepsです、ストワなら0.01くらいで充分だと思われます。
また間違った関数と範囲を指定すると無限ループになってしまうので最大繰り返し数(maxTime)を設けています。
luaは引数に関数を渡せるので、二分法を呼ぶときに *f(x)* を指定します

### ストワで活用
いわゆる弾道計算器に使います。
弾道計算に関してはふるにん氏のこちらの動画がわかりやすいです。

https://www.nicovideo.jp/watch/sm39987672

以下のようなコードを使うことで距離500mにLACを射撃したときの時間 *ballistitTime* が求まります。

```lua

ballisticData={}
targetData={}
gunData = {
    --{v0:Muzzle Velocity, k:Drag, lifetime }
	{ 800,  1.5,  5}, -- MG
	{ 1000, 1.2,  5}, -- LAC
	{ 1000, 0.6,  5}, -- RAC
	{ 900,  0.3,  10} -- HAC }
}

function gunf(t)
	local E=1-math.exp(-ballisticData.k*t)
    
   return targetData.w^2+(targetData.h+ballisticData.g*t/ballisticData.k-ballisticData.g/ballisticData.k^2*E)^2-(ballisticData.v0/ballisticData.k)^2*E^2
end

function bisection(a, b, eps, f,maxTime)
	local i, s = 0, 0
	while math.abs(a - b) > eps and i<maxTime do
		i = i + 1
		s = (a + b) / 2
		if (f(a) * f(s) < 0) then
			b = s
		else
			a = s
		end
	end
    if i>=maxTime then s=0 end --error
	return s
end

function onTick()
    gunIndex=1--LAC
    ballisticData={g=30,v0=gunData[gunIndex][1],k=gunData[gunIndex][2],lifeTime=gunData[gunIndex][3]}
    --g:gravitational acceleration　30m/s^2
    targetData={w=500,h=0}--w:目標までの水平距離,h：目標までの垂直距離
    ballisticTime=bisection(0,ballisticData.lifeTime,0.01,gunf,50)

    debug.log(ballisticTime)
end

```

同様のコードを使用してこちらのマイコンは製作しています

https://www.nicovideo.jp/watch/sm41938673

弾道計算機は命中までの時間が一番重要で、必ず繰り返し処理が必要となる部分です。
その式が *gunf(x)* 関数です。
これにより命中時間が求まり、命中時間が求まると仰角や方角も計算出来るようになります。

以上、ストワで二分法を使う話でした
git hooksを作ってみる。

# はじめに
多くの開発者が経験する共通の問題—間違ったブランチに不注意にコミットしてしまうこと。今回はそれの解決策の一つとして、Git Hooksを利用して、コミット前にブランチを明示的に確認させる方法を解説します。

# Git Hooksとは？

Git Hooksは、Gitのワークフロー中の特定のポイントで自動的に実行されるスクリプトです。コミット、プッシュ、マージなど、様々なGitイベントにフックできます。これにより、開発プロセスに追加の検証や自動化を導入できます。

# 実装手順
### 1. プロジェクトの準備
```bash
# 新しいプロジェクトディレクトリを作成
mkdir git-branch-confirmation
cd git-branch-confirmation

# Gitリポジトリを初期化
git init

# Gitのブランチmainを作成しコミットする
git switch -c main
echo "test" > test.txt
git add test.txt
git commit -m "test"
```

### 2. pre-commitフックの設定
```bash
# hooksディレクトリに移動
cd .git/hooks

# pre-commitスクリプトを作成
touch pre-commit

# スクリプトに実行権限を付与
chmod a+x pre-commit
```

### 3. pre-commitスクリプトの実装
以下のBashスクリプトを`pre-commit`ファイルに追加します：
```bash
# ブランチ確認プロンプト関数
prompt_confirmation() {
    local CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
    
    while true;
    do
        echo "===== ブランチ確認 ====="
        echo "現在のブランチ: $CURRENT_BRANCH"
        echo "本当にこのブランチ『$CURRENT_BRANCH』にコミットしますか？"
        echo "操作を続行するには「yes」、中止するには「no」と入力してください。"
        
        exec < /dev/tty
        read -r CONFIRM
        
        # 入力を小文字に変換
        CONFIRM_LOWER=$(echo "$CONFIRM" | tr '[:upper:]' '[:lower:]')
        
        # 確認応答の処理
        case "$CONFIRM_LOWER" in
            "y" | "yes")
                echo "コミットを続行します。"
                return 0
                ;;
            "n" | "no")
                echo "コミットをキャンセルしました。"
                return 1
                ;;
            *)
                echo "エラー: 「yes」または「no」で回答してください。"
                ;;
        esac
    done
}

# 確認関数を呼び出し
if ! prompt_confirmation; then
    exit 1
fi

# ユーザーが確認したら、コミットを許可
exit 0
```

**たったこれだけで完成です!!**

:::note info
- このスクリプトは、コミット前に現在のブランチを明示的に確認させます。
- 入力は大文字/小文字を区別しません。
- ユーザーに「yes」または「no」で明確な選択を求めます。
:::

# 動作確認
### 1. コミットするファイルの作成
```bash
echo "test" > test1.txt
git add test1.txt
```

### 2. コミットをして動作するのかを確認
```bash
git commit -m "test1"
===== ブランチ確認 =====
現在のブランチ: main
本当にこのブランチ『にコミットしますか？
操作を続行するには「yes」、中止するには「no」と入力してください。
y
コミットを続行します。
```

# おわりに
Gitでコミットするブランチを間違えるという事はよっぽどのことがないと、あり得ないと思いますが、上記のような形で`hooks`を使用すると簡単に防ぐことができます。他のGitのワークフローにも活用できるので、是非`hooks`を活用してみてはどうでしょうか？
プログラミングをすると英語ができるようになる？

# はじめ
先日「プログラミングをすると英語ができるようになるからいいよね！」と言われたことに対して、エンジニア全員が黙ってしまい、妙な空気が流れました。
プログラミングに興味を持ち始めた人や、周囲でプログラマーを見ている人からよく耳にするフレーズです。英語に抵抗感がある人にとっては、プログラミングを通じて英語力も鍛えられるというのは魅力的に聞こえるのかもしれません。

でも、実際にプログラミングをしていると、「そう簡単に英語ができるようになるわけじゃないよ」と感じる場面も多いはず。この記事では、この発言に対するモヤモヤ感の正体を考察し、プログラミングと英語の現実的な関係について考えてみます。

# 英語に触れる場面は多い
プログラミングをすると英語に触れる機会は確実に増えます。

- プログラミング言語自体が英語ベース
- ドキュメントは英語が多い

技術習得のために英語を読んだりする必要性がどうしても出てきます。英語に触れる時間が増えることで、英語の文法構造や単語に慣れることができたり、「How to…」質問形式といった特定の目的に直結した英語力は鍛えられそうです。また、問題解決への情報収集のため、英語を学習するというモチベーションアップにつながるかもしれません。

# でも、それだけで「英語ができる」とは言えない理由
英語に触れる機会は多いですが、プログラミングをしていると英語力が向上するとは言い切れません。
プログラミングで触れる英語は、技術的な用語やフレーズに限られますし、例え読むことができても書いたり話したりする能力が向上するわけではありません。プログラミングで学んだ英語は日常会話やビジネスにはあまり役に立たないことが多いでしょう。
例えば、英語ドキュメントを理解できても “Could you please help me with debugging this issue?” というような文をすらすら書けるようにはなりにくいと思います。

またGoogle翻訳やDeepLなどのツールが発達しており、英語を直接読まなくとも必要な情報は手に入ります。ChatGPTが翻訳して要約してくれるようになったことから、余計に英語力を伸ばす機会は少なくなるかもしれません。

# 「英語ができるようになる」は期待しすぎかも？
プログラミングをしていると英語に触れる機会が増えますし、技術英語には触れますが、日常英語や英語力全般が伸びるわけではありません。また技術英語も発音の仕方が国によって異なったりすることもあります。
ただ、プログラミングを通して言葉の意味を知るというおもしろさで英語学習のモチベーションは上がるかもしれません。

# 逆に英語ができるとプログラミングができる？かとも思うがそうでもない
英語ができるとプログラミングができるかと聞かれると、一概には言えないです。英語力はプログラミング学習を大いに助けますが、英語だけでプログラミングができるようになるとは限らないからです。
例えば、情報収集やエラー解決、学習教材の選択においては英語ができる方が選択肢はかなり広がります。
しかし、プログラミングの習得には論理的思考や知識、手を動かす経験から体に染み込ませることが必要です。
なので、英語力はプログラミング学習をスムーズに進める「アドバンテージ」にはなりますが、プログラミングそのものの能力を直接保証するものではありません。

# おわりに
プログラミングをすると英語学習を促進するとは思いますが、使っている英語の範囲が限定的なので「英語ができるようになる」わけではないと考えます。
「国語をすると英語ができるようになる」とは言われないのに、「プログラミングをすると英語ができるようになる」と言われるのは不思議ですね。
書かれているコードにはスペルミスもあったりするので、私はプログラミングで使っている言語が英語だという認識は薄くて、ただの記号に思えてます。

# 余談: 「プログラミングすると数学ができるようになる？」
抽象的な数学をプログラミングに落とし込むことで、数学的概念を実感として理解できる機会はあります。
またプログラミングには数学的思考(論理的思考、問題解決力、アルゴリズム)が必要なことも事実です。ですが、プログラミングで学べる数学は限定的で、しかも「自然」には学べず、自分で調べる必要があります。
またプログラミングの範囲にはWebサイト構築といった数学を直接使わない場合があったり、ライブラリといった自動化ツールに依存しすぎ数学の理論そのものを理解せずに使う場合もあります。
プログラミングをすることで数学的センスを磨ける可能性はありますが、数学の深い理解を得るには別途の努力が必要であり、また個人の興味や目的によって効果が異なるでしょう。
LINE BotにサクッとPush通知するだけのライブラリ「LINE Bot Notify」

# はじめに
2024年10月7日、界隈に衝撃的なニュースが駆け巡りました。
LINE Notifyサービス終了のお知らせです。

https://developers.line.biz/ja/news/2024/10/07/line-notify-will-be-discontinued/

私自身個人プロダクトで愛用させていただいており、また今年開催されたテックシーカーハッカソンでのLINE APIインプットイベントにて「IoTと親和性のあるLINE API」としていの一番に紹介していました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207109/36b9c417-1960-2153-a747-a1c27653a832.png)

https://speakerdeck.com/miso/line-x-iot-ru-men-hanzuon

この悲報に界隈は悲しみのポストに溢れていました。
私は一縷の望みを託しひとつのポストを投稿しました。

https://x.com/miso_develop/status/1843258233882038396

しかしこの悲痛な叫びはあまり響いていない気がしたので自分で作りました。



# LINE Bot Notify
LINE BotにサクッとPush通知するだけのライブラリです。

https://github.com/miso-develop/linebot-notify

チャネルアクセストークンもしくはチャネルID & シークレットのペアを指定しインスタンス生成します。
あとは通知したいメッセージを添えてpushメソッドを実行するだけです。

```js
import { LineBotNotify } from "linebot-notify"

const channelAccessToken = "<Channel Access Token>"
const notify = new LineBotNotify({ channelAccessToken })

const main = async () => {
	const remainingQuota = await notify.push("LINE Bot Notify!")
	console.log(remainingQuota)
}
main()
```

LINE Notifyはほぼ利用無制限でしたが、LINE Botの場合はフリープランだと月200通までの制限があります。
ですので残Push数を`push`メソッドの戻り値で返すようにしています。

Push通知はせず残Push数のみを返す`getRemainingQuota`メソッドも用意しているので、`push`メソッド実行前の残Push数をチェックし必要に応じてアラート文を加えて`push`メソッドを実行するなんて使い方がいいかもしれません。



## インストール

npmで公開しているので以下のコマンドで一発です。

```sh
npm install linebot-notify
```

## push(message, { to, notificationDisabled })メソッド

メッセージ以外に任意のオプションを指定できます。

|パラメーター|必須|型|既定値|内容|
|:--|:-:|:-:|:-:|:--|
|message|✔|string|-|送信するメッセージを指定します。|
|to||string \| string[] |`undefined`|送信先を指定します。<br>単一指定の場合はユーザーIDもしくはグループIDを、配列指定の場合はユーザーIDを指定します。|
|notificationDisabled||boolean|`false`|`true`を指定するとメッセージ送信時に通知を行いません。|

```js
// メッセージの送信（ブロードキャスト）
await notify.push("LINE Bot Notify!")

// ユーザーもしくはグループを指定してメッセージ送信
await notify.push("LINE Bot Notify!", { to: "<User ID or Group ID>" })

// 複数ユーザーを指定してメッセージ送信（マルチキャスト）
await notify.push("LINE Bot Notify!", { to: ["<User ID>", "<User ID>"] })

// ユーザーに通知されないようにメッセージ送信
await notify.push("LINE Bot Notify!", { notificationDisabled: true })
```



# こだわりポイント

## チャネルIDとシークレットがあれば使える
LINE Notifyの魅力のひとつはサクっと使い始められることだったのではないかと思っています。
Webコンソールにログインしてトークン発行してあとはWeb APIたたくだけ、という手軽さです。

このトークン発行までの手軽さを重要視し、チャネルアクセストークンを発行せずともチャネルIDとシークレットだけでも使えるようにしました。

現在LINE Botの新規作成は「[LINE Official Account Manager](https://manager.line.biz/)」から行いますが、チャネルアクセストークの発行にはさらに「[LINE Developersコンソール](https://developers.line.biz/console/)」で操作を行う必要があります。
しかしチャネルIDとシークレットの取得であれば「LINE Official Account Manager」のみで完結できます。

※商用プロダクトで使用する場合はちゃんとチャネルアクセストークンを使用することをおすすめします

## 依存ゼロ
最初は`line/bot-sdk`をラップしようかと思っていましたが、提供機能がシンプルすぎるので1から実装し依存もゼロにしました。
軽くてシンプルな作りになっています。



# おわりに
ここひと月ほどLINE Notifyを使用していた個人プロダクトをLINE Bot Notifyに切り替えて運用しておりまして、当たり前ですが特段問題なく使えています。
フリープランでは月200通までと制限はあるものの、私の個人プロダクト利用であれば問題ない範囲の良心的な制約です。
月200通制限を許容できる方はぜひ「LINE Bot Notify」をお試しいただけますと幸いです。
時間効率UP：「history」と「grep」で過去の忘れがちなコマンドを簡単に検索する方法について

## はじめに
普段、サーバーの運用や保守・設計などを行う中で、日常的にLinuxコマンドを使っています。

:::note warn
***LinuxやUnix系システムの管理においては、コマンドラインでの作業効率が非常に重要です。***
:::

今回は、その中でも特におすすめのコマンドの組み合わせである ```history``` と ```grep``` を使い、過去のコマンド履歴を効率よく検索する方法をご紹介します。

## まず、エンジニアは「時間」が命
エンジニアにとって、時間は最も重要なリソースです。多忙なスケジュールの中で、いかに効率を高められるかが求められます。

特に、**パソコンの操作感やコマンド検索のスピードは、あらゆる作業のベースとなるスキル**だと考えています。

:::note
以下の記事も、時間効率を上げるための内容を紹介しています。興味のある方はぜひ参考にしてみてください。
:::

https://qiita.com/free-honda/items/e58b6750dba27107889f

https://qiita.com/free-honda/items/7419e88404abafdcd624

https://qiita.com/free-honda/items/7acbde9386706fd6ce8b

## 前提：個人的に一番好きなコマンドの組み合わせ
皆さんも、こんな経験はありませんか？

:::note warn
- **「この前使ったあのコマンド、もう一度確認したいな」**
- **「どのコマンドを使ったんだっけ？成功したコマンドを忘れてしまった」**
:::

そんなときに役立つのが、```history``` と ```grep``` を組み合わせる方法です。

***この2つを使えば、過去に実行したコマンドの履歴から特定のキーワードを含むコマンドを簡単に検索できます。***

ここでは、この便利な方法を具体的に解説します。

## ```history```コマンドとは
```history``` コマンドは、現在のシェルセッションで実行したコマンド履歴を表示するためのコマンドです。

:::note
**シェルは通常、過去に入力したコマンドを履歴として保存しており、それを確認できます。**
:::

以下のコマンドを実行すると、過去に実行したコマンドの一覧が行番号付きで表示されます。

```bash
$ history
```

履歴は行番号付きで表示されるので、特定のコマンドを番号で再実行することも可能です。

## ```grep```コマンドとは

```grep``` は、指定した文字列（パターン）をファイルや標準入力から検索し、一致する行を表示するコマンドです。

例えば、以下のコマンドでは、テキストファイル ```logfile.txt``` 内に含まれる「```error```」という単語を検索できます。

```bash
$ grep "error" logfile.txt
```

このように、特定のキーワードを効率よく見つけ出すのに役立ちます。

## 実際に ```Git``` コマンドを探してみた
では、実際に ```history``` と ```grep``` を組み合わせて、過去に実行した ```Git``` コマンドを探してみます。

:::note warn
***この方法を使えば、どんな Git コマンドを実行したかを簡単に確認できます。***
:::

### ```history``` と ```grep``` を組み合わせて ```Git``` コマンドを探す

まず、```history``` コマンドで過去に実行したコマンドを表示し、その中から「```git```」を含むものだけを抽出するために ```grep``` を使います。

```bash
$ history | grep "git"
```

このコマンドを実行すると、過去に使った Git 関連のコマンドが表示されます。

```bash
1203  git clone https://github.com/example/repo.git
1204  git status
1205  git add .
1206  git commit -m "Fixed a bug"
1207  git push origin main
```

このように、```history | grep "git"``` を使えば、Git コマンドだけを効率よく検索できます。

さらに、特定のリポジトリ名や操作を絞り込む場合は、追加のキーワードで検索を絞ることが可能です。

```bash
$ history | grep "git pull"
```

この例では、「git pull」を含むコマンドだけを見つけられます。

![スクリーンショット 2024-12-13 22.56.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/b28009e2-2212-debc-ec63-04831494b4f3.png)

:::note warn
***必要に応じて他のキーワードを追加して試してみてください！***
:::

## まとめ

今回は、私が普段からよく使っている ```history``` と ```grep``` の組み合わせを活用したコマンド履歴の検索方法をご紹介しました。

:::note
***この方法を使えば、過去に実行したコマンドを素早く見つけられ、作業効率が大幅に向上します。***
:::

今後も基礎的なコマンドの知識を整理しながら発信していきますので、この記事が誰かの技術的な参考になれば嬉しいです！

## 関連記事

https://qiita.com/nokonoko_1203/items/35c4078bf72cffb16171

https://www.bold.ne.jp/engineer-club/linux-commands-getting-started
AWSプロモーション(販促)クレジットの仕様を理解して賢く活用する

AWSプロモーションクレジットはAWS Summit等のイベントやアンケートの回答等で配布されていることが多いかと思います。
個人レベルの検証用途でプロモーションクレジットの仕様を正しく理解せず意図しない課金が発生した例を何度か耳にしたので、ここだけは抑えておくべき点を備忘録として整理してみます。

まとめ
--------------
先に要点だけまとめます。

- 最新の規約を一読する
- クレジットで充当できない対象外サービスが存在する
- クレジット毎に充当可能な対象サービスを把握する
- 有効期限内に使用する
- クレジット残高を超過しない

以下、要点毎に解説します。


最新の規約を一読する
--------------
AWS利用料金に充当可能なクレジットです。
常に最新版の規約を確認するようにしましょう。
最新の規約は以下のURLから確認できます。

AWS プロモーションクレジット利用規約
https://aws.amazon.com/jp/awscredits/

クレジットで充当できない対象外サービスが存在する
--------------
利用規約にはクレジットで充当可能な「対象サービス」と充当不可の「対象外」サービスが定められています。
対象外サービスは以下の通りです(利用規約より抜粋)
- Amazon Mechanical Turk
- AWS マネージドサービス
- AWS マーケットプレイス
- AWS プロフェッショナルサービス
- AWS トレーニング
- AWS 認定
- Amazon Route 53 ドメイン名登録または譲渡
- 暗号通貨のマイニングのためのサービス
- AWS 契約主体によって指定されるその他のサービス
- Savings Plans やリザーブドインスタンスなどのサービスに対する前払い料金
- 対象外の AWS サポート
    - AWS エンタープライズサポート
    - AWS エンタープライズオンランプ
    - AWS 再販サポート (AWS エンタープライズサポートおよび AWS エンタープライズオンランプ)
    - AWS パートナー主導サポートである AWS サポート

 個人レベルの検証用途であれば注意すべきサービスはそう多くない印象ですが、強いてあげるのであればマーケットプレイスとRoute 53は要注意です。


クレジット毎に充当可能な対象サービスを把握する
 ---------------
利用規約で以下のように定められています。
>プロモーションクレジットは、AWS 契約主体によって指定された特定のサービス (総称して「対象サービス」) にのみ適用されます

確認にはプロモーションクレジットをAWSアカウントに適用する必要があります。
適用手順は[こちら](https://aws.amazon.com/jp/apply-coupon/)

実際にクレジットを適用した画面がこちらです。
「サービスの完全なリストを表示」をクリックすると対象サービスを確認することができます。
![スクリーンショット 2024-12-12 19.59.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193020/c14735d8-115b-b0b1-6c13-e6b029f20c11.png)

画面に収まっていませんが、下にスクロールすると全ての対象サービスを確認できます。
![スクリーンショット 2024-12-12 20.01.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193020/737ad41f-c01b-91ee-b24e-548c316571e4.png)

注意点として、プロモーションクレジット毎に対象サービスのリストが異なっていることがありました。
(発行元や発行時期によって対象のリストに違いがあるようです)
基本的にはリスト内のサービス利用であれば、意図しない課金が発生することはありません。
利用前に必ず対象サービスのリストを確認するようにしましょう。
特に、新サービスリリース直後のタイミングは要注意です。


有効期限内に使用する
--------------
クレジットには有効期限が存在しています。
>プロモーション クレジットは期間限定で有効であり、該当するプロモーション クレジット コードを受け取ったときに示された有効期限 (または当社または本規約で指定されたその他の日付) を過ぎると、引き換えることはできません。

有効期限を過ぎると登録しているクレジットカードに対して請求が発生します。
有効期限以降に課金サービスが残らないように気をつけましょう。


クレジット残高を超過しない
----------------
残高を大きく超えないように意識すればOKです。
クレジットの残高とBillingは定期的に確認しましょう。
使い終わったらすぐに削除する意識を徹底すれば課金額が大きく跳ねるリスクも減ります。
[請求アラーム](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/monitor_estimated_charges_with_cloudwatch.html)も活用すると安心です。





-----------------
以上です。
AWS Summit等のイベントアンケート等で定期的に配布されており、個人レベルで検証したい場合にとても重宝します。仕様を正しく理解して賢く使い倒しましょう。
【jest】ファイルごとのテストケース数を出力するcustom-reporters 作成してみた

## はじめに

jestのテストを行なっているときに、複数ファイル同時テストするとファイルごとのテストケース数がわからず、全てのファイルのテストケース数合計しか出力されません。
それが不便で、1ファイルごとのテストケース数をまとめて出力してくれるcustom-reportersを作成しました！

### 1. custom-reporters コード作成

```javascript:custom-reporters.js

const fs = require('fs');

class CustomReporter {
  constructor(globalConfig) {
    this._globalConfig = globalConfig;
  }

  onRunComplete(_, results) {
    const ROOT_DIR = this._globalConfig.rootDir;

    const testResults = results.testResults.map((testResult) => ({
      fileName: testResult.testFilePath.replace(ROOT_DIR, ''),
      numTotalTests: // テストケース合計
        testResult.numFailingTests +
        testResult.numFailingTests +
        testResult.numPassingTests +
        testResult.numPendingTests +
        testResult.numTodoTests,
      numFailingTests: testResult.numFailingTests, // 成功したテストケース数
      numPassingTests: testResult.numPassingTests, // 失敗したテストケース数
      numPendingTests: testResult.numPendingTests, // 保留中のテストケース数
      numTodoTests: testResult.numTodoTests, // todoのテストケース数
    }));

    // console.log(testResults) // ターミナルに表示したい場合
    const filePath = './results.json'; // 出力したいファイルパス
    fs.writeFile(filePath, JSON.stringify(testResults, null, 2), 'utf8', (error) => {
      if (error) {
        console.log('ファイルの書き出し中にエラーが発生しました:', error);
      }
    });
  }

  getLastError() {
    if (this._shouldFail) {
      return new Error('Custom error reported!');
    }
  }
}

module.exports = CustomReporter;
    
```

### 2. jestの設定

```javascript:jest.config.js

/** @type {import('jest').Config} */
const config = {
  reporters: ['default', '<rootDir>/custom-reporters.js'],
  // 他、必要な設定を追加
};

export default createJestConfig(config);
```


### 3. 出力されるデータ
```json:results.json

[
  {
    "fileName": "/src/__test__/example-test1.test.ts",
    "numTotalTests": 35,
    "numFailingTests": 4,
    "numPassingTests": 27,
    "numPendingTests": 0,
    "numTodoTests": 0
  },
  {
    "fileName": "/src/__test__/example-test2.test.ts",
    "numTotalTests": 11,
    "numFailingTests": 0,
    "numPassingTests": 11,
    "numPendingTests": 0,
    "numTodoTests": 0
  },
  {
    "fileName": "/src/__test__/example-test3.test.ts",
    "numTotalTests": 9,
    "numFailingTests": 3,
    "numPassingTests": 3,
    "numPendingTests": 0,
    "numTodoTests": 0
  }
]

```

## 参考資料
https://jestjs.io/docs/configuration#custom-reporters


## おわりに
これで1ファイルごとにテストコマンドを打たずとも、テストケース数がわかるようになりました！
同じ悩みを持った人の、お力になれば幸いです。
レターが「はよ出ます」

この記事は [株式会社TRAILBLAZER Advent Calendar 2024](https://qiita.com/advent-calendar/2024/trail-blazer) の19日目の記事です。
***
こんにちは、株式会社TRAILBLAZER経営企画部統括部長の
長谷川です。バックオフィス・ミドルオフィス全てを担当しています。統括部長などといういかめしい肩書ですが、肩書で仕事をやる会社ではないので、社内では娘がつけてくれたケーキ・トンカツ部長という愛称に、なるべく表記を統一しています（以下の画像は取締役が生成したケーキ・トンカツ部長のイメージ）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3932355/c04bfef5-ebb8-a367-ea8d-3277c8d8f67e.png)

私たちの会社のValueの一つに「はよやろう」があります。これは、「停滞を許容せずに、はやく始める」ことを重視する姿勢を表しています。このValueは、私たちの採用プロセスにも反映されています。

### 採用のプロセス

採用プロセス自体は一般的なものです。書類選考、２－３回の面接、オファーレターの発行、オファー面談の実施という流れですが、私たちはレターの発行を素早く行っています。

### オファーレターが「はよ出ます」

私たちはオファーレターをほとんどのポジションに対して、ほぼ即日～翌日出るオペレーションを組んでいます。これは、応募者に対する私たちの真剣さと迅速な対応を示すものです。多くの企業では、オファーレターの発行に数日から数週間かかることがありますが、私たちはこのプロセスを大幅に短縮しています。

### 成功事例: 「はよやろう」の力

象徴的な成功事例を紹介します。ある日、なるべく早く転職したい意向を持っているデータサイエンティストの最終面接を行いました。彼は翌日には第一志望の他社の最終面接がありましたが、私たちが面接後すぐにオファーレター発行したところ、彼は「熱意を感じる」「即日でレターが出るなんてすごい会社」と翌日の他社の面接をキャンセルして、TRAILBLAZERにジョインすることを決めてくれました。迅速な対応と決断力が、優れた人材を確保するための競争力となっています。

### まとめ

私たちの採用プロセスは、スピードと効率を重視しています。書類選考から面接、オファーレターの発行まで、すべてのステップで迅速な対応を心がけています。特に、オファーレターがほぼ即日出ることは、私たちのプロセスの大きな強みです。これにより、優れた人材を迅速に確保し、チームに迎え入れることができます。

私たちの会社で働くことに興味がある方は、ぜひご応募ください。そして、本当にオファーレターがすぐに出てくるか、確かめてみてください。ご応募、お待ちしています。

https://hrmos.co/pages/trail-blazer
BSODが発生した時

# はじめに

私は今年デスクトップパソコンを購入して、すでに２回も不具合を起こして修理に出しています💦
その中でBSOD（ブルースクリーン）になったので起こる原因など調べてみたので記事にしてみました✨

---

## 1.BSODの主な原因

BSODは、多くの場合、ハードウェアの故障、古いドライバーまたは破損したドライバー、問題のあるソフトウェア、ウイルス、システム ファイルの破損が原因で発生します。一般的な原因としては、メモリー(RAM)の不具合、ハード ドライブのパーツの損傷、古いドライバー、過熱などがあります。

私の場合、ハードウェアの問題では無く、ソフトウェアに問題があったそうです。

---

### 2.BSODが起こる時のエラーコード一覧

**windows10またはwindows11の主なエラーコード**

```bash
PAGE_FAULT_IN_NONPAGED_AREA停止コード：0x00000050
IRQL_NOT_LESS_OR_EQUAL停止コード：0x0000000A
SYSTEM_SERVICE_EXCEPTION停止コード：0x0000003B
KMODE_EXCEPTION_NOT_HANDLED停止コード：0x0000001E
CRITICAL_PROCESS_DIED停止コード：0x000000EF
MEMORY_MANAGEMENT停止コード：0x0000001A
DRIVER_IRQL_NOT_LESS_OR_EQUAL停止コード：0x000000D1
VIDEO_TDR_FAILURE停止コード：0x00000116
INACCESSIBLE_BOOT_DEVICE停止コード：0x0000007B
BAD_POOL_HEADER停止コード：0x00000019
SYSTEM_THREAD_EXCEPTION_NOT_HANDLED停止コード：0x0000007E
BAD_SYSTEM_CONFIG_INFO停止コード：0x00000074
WHEA_UNCORRECTABLE_ERROR停止コード：0x00000124
UNMOUNTABLE_BOOT_VOLUME停止コード：0x000000ED
MACHINE_CHECK_EXCEPTION停止コード：0x0000009C
DPC_WATCHDOG_VIOLATION停止コード：0x00000133
```

それぞれのエラーコードには意味があるようなので、BSODが出た際は調べてみると原因がわかるかもしれません。

---

## 3. **対処法**

### **ハードウェアの問題**

#### 確認ポイント:
- **接続不良**: 外部デバイス（USB、プリンタなど）が正しく接続されているか確認
- **過熱**: CPUやGPUの温度が高すぎるとエラーが発生することがあります
- **メモリの不具合**: RAMに問題がある場合、BSoDが発生することがあります

#### 対処法:
- デバイスを取り外し、再度接続
- エアダスターで内部を清掃し、冷却性能を向上
- Windowsの「メモリ診断ツール」を使用してRAMをテスト

### **ドライバの問題**

#### 確認ポイント:
- 最近インストールまたは更新したドライバが原因かもしれません

#### 対処法:
1. **セーフモードで起動**:
   - 再起動中にF8キーを押して「セーフモード」を選択
2. **ドライバのロールバック**:
   - デバイスマネージャーを開き、該当するドライバを右クリック → 「ドライバのロールバック」

### **ソフトウェアの問題**

#### 確認ポイント:
- 最近インストールしたアプリケーションが原因の可能性
- システムアップデートの不具合

#### 対処法:
- **システムの復元**:
  - Windowsの「システムの復元」を使用して、BSoDが発生する前の状態に戻します
- **Windows Updateの確認**:
  - 最新の更新プログラムを適用することで問題が解決する場合があります

---

## 4. **BSoDを未然に防ぐ方法**

### **定期的なメンテナンス**
- ハードウェアの清掃
- ソフトウェアのアップデート

### **バックアップを取る**
- システムイメージの作成
- 定期的なデータのバックアップ

### **信頼性モニタで監視**
Windowsの信頼性モニタを使用して、エラーの履歴を確認

### **リカバリーメディアの作成**
パソコンを使う前にOSをダウンロード


---

## おわりに

BSODが出た時の対処法として参考になればいいなと感じました。
ですが、修理の無償保証期間だったり、一定額の工賃免除など積極的に利用するのが一番だと思うので困った時は修理に出しましょう！！
LinerLayoutを拡張してマーカー付きタブレイアウトを実装する

AndroidではMaterialComponentsでTabLayoutが提供されています、ViewPagerと組み合わせてタブを提供するなどを簡単に実装することができます。
ただ、このTabLayout、そのまま素直につかうのなら簡単なのですが、少しデザインを凝ったり、タブに機能を追加しようとすると途端に難易度が上がります。カスタマイズ性は高いものの、内部実装の都合で多くの制約があるため、一定以上のカスタマイズが必要な場合は、いっそ一から自前で作ってしまった方が楽だったりします。
その場合、おそらくすぐに実装方法が思いつかなさそうなのが、マーカーかな？ということでシンプルな実装方法を紹介します。
実装したものが以下です。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155171/74aed1e3-82b4-5a72-504f-a70a6977d91b.gif)

# LinearLayoutを拡張

同一構造の要素が並んだViewなのでRecyclerViewが思い浮かぶ火らもしれませんが、RecyclerViewの場合、スクロールの制御を細かくやろうとしたり、表示される前の要素の位置や大きさを知る必要があると、難易度が高いです。たかだか数個程度のタブであれば、LienarLayout/HorizontalScrollViewあたりを利用するのが簡単です。

単純にフォーカスを当てる場所を指定すればそこにマーカーを表示し、変化があれば移動アニメーションをおこなうという実装が以下になります。

```kotlin
class TabView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0,
) : LinearLayout(
    context, attrs, defStyleAttr
) {
    init {
        orientation = HORIZONTAL
    }

    private val marker: Drawable = AppCompatResources.getDrawable(context, R.drawable.marker)!!
    private var animator: ValueAnimator? = null
    private var currentIndex = -1

    fun setSelected(index: Int) {
        val current = children.elementAtOrNull(currentIndex)
        val next = children.elementAtOrNull(index)
        currentIndex = index
        next ?: return
        animator?.cancel()
        animator = null
        if (current == null) {
            marker.setBounds(next.left, next.bottom - marker.intrinsicHeight, next.right, next.bottom)
            invalidate()
            return
        }
        animator = ValueAnimator.ofFloat(0f, 1f).also {
            it.addUpdateListener {
                val fraction = it.animatedValue as Float
                val left = (current.left + (next.left - current.left) * fraction).toInt()
                val right = (current.right + (next.right - current.right) * fraction).toInt()
                marker.setBounds(left, next.bottom - marker.intrinsicHeight, right, next.bottom)
                invalidate()
            }
            it.start()
        }
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        marker.draw(canvas)
    }
}
```

かなり割り切っているとはいえ、非常にシンプルに実装することができます。

なお、貼り付けたスクショの場合、markerに以下のようなGradientDrawableを使っています。
```xml
<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle"
    >
    <solid android:color="?attr/colorPrimary" />

    <corners
        android:bottomLeftRadius="0dp"
        android:bottomRightRadius="0dp"
        android:topLeftRadius="4dp"
        android:topRightRadius="4dp"
        />
    <size android:height="4dp" />
</shape>
```
S3単体よりCloudFront使って配信する方が安いかもよ

## はじめに
私の担当しているプロダクトの画像配信システムは「Akamai + CloudFront + S3」の構成で運用しています。そこで、Akamai + CloudFront + S3の構成からAkamai + S3で配信するよう切り替えた際に、思ったよりコストが下がらなかったので自戒として記事に残しておきます。

## S3の料金体系

S3のGETリクエストの料金 (S3標準)

|    | 1万GETリクエストあたりの料金 |
|:-------------|----:|
| S3 標準 | USD 0.004 |

インターネットからS3へのデータ転送料金 (IN)	
|    |  データ転送料金 |
|:-------------|----:|
| すべてのデータ受信 | USD 0.00/GB |

S3のインターネットへのデータ転送料金 (OUT)
＊CloudFront + S3構成の場合はこの料金かからない

|    |  データ転送料金 |
|:-------------|----:|
| 最初の10TB/月 | USD 0.09/GB |
| 次の40TB/月 |  USD 0.085/GB |
| 次の100TB/月 |  USD 0.07/GB |
| 150TB/月以上 |  USD 0.05/GB |

https://aws.amazon.com/jp/s3/pricing

## CloudFrontの料金体系

CloudFrontのHTTP(S)リクエストの料金

|    | 1万リクエストあたりの料金(日本) |
|:-------------|----:|
| 最初の1,000 万件のHTTP(S)リクエスト | 無料 |
| HTTPリクエスト | 0.0090 USD |
| HTTPSリクエスト | 0.0120 USD |

インターネットへのリージョンレベルのデータ転送 (OUT)

|    |  データ転送料金(日本) |
|:-------------|----:|
| 最初の1TB | 無料 |
| 次の9TB | USD 0.114/GB |
| 次の40TB | USD 0.089/GB |
| 次の100TB | USD 0.086/GB |
| 次の350TB | USD 0.084/GB |
| 次の524TB | USD 0.080/GB |
| 次の4PB | USD 0.070/GB |
| 5PB以上 | USD 0.060/GB |

オリジンへのリージョンレベルのデータ転送 (OUT)
＊CloudFront + S3構成の場合はこの料金かからない

|    |  データ転送料金(日本) |
|:-------------|----:|
| すべてのデータ転送 | 0.060 USD |

https://aws.amazon.com/jp/cloudfront/pricing/

## 結論

CloudFront + S3の場合
- S3へのリクエスト料金
- CloudFrontへのリクエスト料金
- CloudFrontからエンドユーザーへのデータ転送料金

S3の場合
- S3へのリクエスト料金
- S3からエンドユーザーへのデータ転送料金

の料金がかかってきます。

規模とアーキテクチャによって判断は異なりますが、私たちは前段のAkamaiでキャッシュを実施しているため、CloudFrontとS3へのリクエスト到達数は少ないです。そのため、主にデータ転送料金が費用差の要因となると考えられます。

S3のデータ転送料金

|    |  データ転送料金 |
|:-------------|----:|
| 最初の10TB/月 | USD 0.09/GB |
| 次の40TB/月 |  USD 0.085/GB |
| 次の100TB/月 |  USD 0.07/GB |
| 150TB/月以上 |  USD 0.05/GB |

CloudFrontのデータ転送料金

|    |  データ転送料金(日本) |
|:-------------|----:|
| 最初の1TB | 無料 |
| 次の9TB | USD 0.114/GB |
| 次の40TB | USD 0.089/GB |
| 次の100TB | USD 0.086/GB |
| 次の350TB | USD 0.084/GB |
| 次の524TB | USD 0.080/GB |
| 次の4PB | USD 0.070/GB |
| 5PB以上 | USD 0.060/GB |

料金表を見る限り、数100TB規模であればさほど差が出ない印象です。

## おわりに

クラウドのコスト体系って難しいですよね😓
事前に詳細なコストシミュレーションをしておきましょう
【合格体験記】OSS-DB Silverに合格した

OSS-DB Silverを取得したので、合格体験記兼備忘録として記事を残しておこうかなと思います。
これからこの資格を取る人の参考になれば幸いです！


## 取得動機

業務でPostgreSQLを扱う機会があり、学習を深めるとともに、自分の知識を試す良い機会だと思いOSS-DB Silverを受験しました。

## 学習方法と使用した教材
勉強期間は１週間で以下の学習教材を使って勉強をしました。

### 使用教材:

・[Ping-t](https://mondai.ping-t.com/g)
Ping-tを１週間で２周しました。Ping-tには非常に詳しい解説が載っており、これだけでも十分だと感じました。また、問題を解くだけでなく、使ったことのない機能については、実際にPostgreSQLの環境を構築して試してみました。


・[OSS教科書 OSS-DB Silver Ver.3.0対応](https://www.shoeisha.co.jp/book/detail/9784798180311)
試験前日に１周読みました。個人的に複数の教材を使うことで、「この問題ほかの教材で見た！」ってなってより覚えられる気がします。ただ、Ping-tのみでも問題なく合格できると思います。

## 試験当日

試験当日は30分くらい前に会場についてしまったので、少しカフェで勉強しながら時間をつぶしました。

### 試験の詳細:

- 試験時間：90分

- 問題数：50問

- 合格ライン：64点

解いている中で感じたのは、Pingtで見た問題が約8割、初見に見える問題が2割程度でした。ただ、初見の問題も多くがPing-tの解説に記載されていた内容に関連していたため、完全に見たことない機能が出てくるということはないのかなと思います。

## 振り返り

試験の結果は94点でした。

Pingtをしっかり取り組んでいれば十分に対応できる試験だと感じました。また、PostgreSQLに関する知識が深まり、試験を通してさらにDBに興味を持つきっかけにもなりました。

最近はデータベースの内部構造にも関心を持つようになり、[Database Design and Implementation](https://link.springer.com/book/10.1007/978-3-030-33836-7)を参考にしながら自作のRDBMSを作成しています。(とても難しい。。)

## まとめ

OSS-DB Silverを取得したことで、PostgreSQLに関する知識の引き出しを増やすことができたかなと思います。

次のステップとしては、データベーススペシャリストかOSS-DB Goldがあるらしいのでそれにも挑戦してみようと思います。


## 参考資料
- [OSS-DB 公式サイト](https://oss-db.jp/outline/silver)
- [Ping-t](https://mondai.ping-t.com/g)
- [OSS教科書 OSS-DB Silver Ver.3.0対応](https://www.shoeisha.co.jp/book/detail/9784798180311)
- [Database Design and Implementation](https://link.springer.com/book/10.1007/978-3-030-33836-7)
【Expo】getCurrentPositionAsyncのハングアップバグに対応する

# 永遠に終わらない位置情報...
Expo SDKの[expo-location](https://docs.expo.dev/versions/v52.0.0/sdk/location/)にあるgetCurrentPositionAsyncには位置情報の取得にハングアップするバグがあります。

これは[issues](https://github.com/expo/expo/issues/10756)にも挙げられていて、すぐに応答することもあれば、ハングアップすることもあります。
iOS or Androidの両方で起きており、しかも発生タイミングに規則性がなくランダムに起きる不思議なバグです。

## 解決方法
[ここのissues](https://github.com/expo/expo/issues/10756#issuecomment-1483254287)にもありますが、timeoutとretryロジックを組み合わせて暫定対応をすることができます。

### なぜtimeoutとretryをするのか？
上記にも触れた通り、このバグは発生タイミングに規則性がないので、何回か再実行をすると位置情報を取得することができます。
なので、timeoutする秒数とretryする回数を決めておき、そのretry回数内で位置情報を取得しようって方法です。

**例**
```text
位置情報の取得に許容できる合計時間が10秒の場合
timeout = 2000ms
retry   = 5回
```

## 実装
[issues](https://github.com/expo/expo/issues/10756#issuecomment-1483254287)のプログラムコードを参考に作ってみました。

:::note warn
注意
本コードはあくまでもサンプルです。
動作を保証するものではありません。
:::

### timeout関数

```ts
// 指定した時間内に処理が終わらなかった場合はタイムアウトエラーをthrowします。
export async function timeoutAsync<T = any>(onTry: () => Promise<T>, time: number): Promise<T> {
  return new Promise((resolve, reject) => {
    // タイムアウト処理
    const timeout = setTimeout(() => {
      reject(new Error('タイムアウト'));
    }, time);

    // 処理を実行
    void onTry()
      .then((result) => {
        clearTimeout(timeout);
        resolve(result);
      })
      .catch((err) => {
        throw new Error(err);
      });
  });
}

```

### retry関数
```ts

type Response<T> = {
  retryCount: number;
  result: T;
};

// 成功するまで指定した回数分だけ再実行します。
export async function retryAsync<T = any>(maxRetryCount: number, onTry: () => Promise<T>): Promise<Response<T | null>> {
  let count = 0;
  let result: T | null = null;

  while (count < maxRetryCount) {
    try {
      result = await onTry();
      break;
    } catch {
      result = null;
    } finally {
      count += 1;
    }
  }

  return { retryCount: count, result };
}
```

### getCurrentPositionAsyncをwrapする
```ts

import { getCurrentPositionAsync, LocationOptions } from 'expo-location';

type Args = {
 timeout?: number
 locationOptions?: LocationOptions
}

export async function getLocationCurrentPositionAsync(args?: Args) {
  const { timeout = 2000, locationOptions } = args ?? {}

  const { result, retryCount } = await retryAsync<LocationObject | null>(5, () =>
    timeoutAsync(() => getCurrentPositionAsync(locationOptions), timeout)
  );

  return { result, retryCount };
}
```

こうすることで、MAX10秒として位置情報を取得することが可能になります。
もし10秒待っても取得できなかった場合はresultがnullになるので、Alertを出すなりしてもう一度ユーザーに実行してもらうように誘導することも可能です。

ちなみにretryCountをreturnしてるのはログを残して調査に使用したりするためにあるだけなので、不要ならretrunする必要はないです。
Drawableを直接描画するための基礎知識

AndroidにおいてDrawableというと、ImageViewで表示したり、各ViewのBackground/Foregroundに指定して使うもの…ではありますが、カスタムViewなどで描画処理を実装する際は、Drawableを直接描画する必要も出てきます。

# Canvasへの描画

Drawableはdrawメソッドを持っており、引数にcanvasを渡すことで、そのcanvasへの描画を行うことができます

```kotlin
drawable.draw(canvas)
```

## サイズ、位置の指定

drawメソッドを使うだけだと、位置やサイズの指定ができません。
位置やサイズを指定したい場合はboundsを設定します

```kotlin
drawable.setBounds(left, top, right, bottom)
drawable.draw(canvas)
```

boundsはRectを使っても指定可能です、サイズを使い回したりする場合はこちらの方が便利ですね

```kotlin
val rect = Rect()
rect.set(left, top, right, bottom)
...
rect.offsetTo(left, top)
drawable.bounds = rect
drawable.draw(canvas)
```

## 9-patch

9-patch（NinePatchDrawable）の場合、このboundsはいわゆるコンテンツ領域に当たるため、9-patchで周囲にドロップシャドウなどを描いている場合、指定boundsの外側にドロップシャドウが描画されることになります。
コンテンツ領域の外側のサイズについてはgetPaddingで取得します。

```kotlin
(drawable as NinePatchDrawable).getPadding(rect)
```

# Drawable自身が持っているサイズ

Drawable自身が持つサイズは `intrinsicWidth` / `intrinsicHeight` で取得することができます。
Drawableは横幅について表示の都合に応じて指定するが、高さはDrawable自身のサイズを採用するといった変形を行うことがよくあります。その場合にこれらメソッドの戻り値を利用します。
[Rails] JSON キャメルケースとスネークケースの変換方法

# 概要

`Next`アプリケーションからリクエストを受け、`JSON`を返す `Rails API`を作成しています。

リクエスト、レスポンスデータのキャメルケース, スネークケース間の変換処理をテンプレ化しておきたく、本記事の執筆に至りました。

## キャメルケース → スネークケース
Nextリクエスト時にキャメルケースで構成されたJSONをスネークケースに変換します。
`deep_transform_keys` + `underscore` を利用します。

```ruby
params = {
  'hogeKey' => 'hoge',
  'fooKey' => 'foo'
}

transformed_params = params.deep_transform_keys(&:underscore)
p transformed_params
# {"hoge_key"=>"hoge", "foo_key"=>"foo"}
```

## スネークケース → キャメルケース
```ruby
params = {
  'hoge_key' => 'hoge',
  'foo_key' => 'foo'
}

camelized_hash = params.deep_transform_keys { _1.camelize(:lower) }
p camelized_hash
```

# まとめ
以上です。
ほぼ自分向けの記事ですが、どなたかの参考になったのであれば幸いです🙏
入力: IR通信

### 背景
メイン基板には赤外のLEDと受信モジュールが4組搭載されています。

![241215.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/f652aeca-4a1f-046f-53ce-460e7c9fcf99.jpeg)


今回はIRを使ったプログラミングを試してみます。
### Scratch
IR通信は通信とイベントのブロックにありました。

送信側
「メインLEDを点滅し、メッセージ1を送り1秒間待つ動作を続ける」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/6214c86d-6fc0-ff54-7bd5-59418b259920.png)

受信側
「LEDマトリクスにカウントダウン表示する。
　3回メッセージ0を受信したらマトリクスLEDを緑色一色を点灯する。」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/fb7dca0a-8d47-d699-1174-b6870440536b.png)

後述のspheroV2を見ると、メッセージは0-8があり、距離は0が近くて64が遠くまで届くということのようです。

### spheroV2
sphero_edu.pyのメソッドを参考に同様な動作をするスクリプトを作成してみましたが、実機で送受信できませんでした。
呼び出し先のスクリプトも探ったのですが、残念ながら、できませんでした。

#### メソッドのコメント

仕方ないので、記載されている内容をもとにコメントを翻訳しました。
- 指定した2つのチャンネル（0と1）で送信開始する。他のBOLTがこの信号を追従または回避できるようになる。  
1つ目は近距離IR信号（1メートル未満）、2つ目は遠距離IR信号（1～3メートル）のこと。
```
    def start_ir_broadcast(self, near: int, far: int):
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/3610bdfc-e37d-2b9e-1641-945d632140a3.png)

- 0と1を放送中のBOLTからメッセージを受信すると、放送元の進行方向と速度に合わせて調整（追いかける？）。見失ったらその場で回転
（Scratchで動作確認すると、受信者が発信者にガンガンぶつかっていたので両者の速度などの調整が難しそうです）
```
    def start_ir_follow(self, near: int, far: int):
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/fcaaed64-77e8-6bde-e937-57538acaa991.png)
- 0と1を放送中のBOLTからメッセージを受信すると、放送元から離れる方向に進む。見失ったらその場で回転
```
    def start_ir_evade(self, near: int, far: int):
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/b01663c2-0576-99ba-98de-620d4ffb6146.png)


### まとめ
IR通信を使ったScratchを実験しました。
spheroV2は残念ながら実機で動作確認できませんでした。2週間くらい頑張って追ってもできなかったので、今回は調査を保留しました。
要素を非表示にしたい時はどうしたらいいのか考える

[Ateam LifeDesign Advent Calendar 2024](https://qiita.com/advent-calendar/2024/ateam-life-design) 14日目を担当します、加能です :tulip: 
フロントエンド実装3年目、3年目とは思えないくらいまだまだへっぽこですが頑張っています。

## これは何？

HTMLの要素が削除されないWebサイト実装において、要素の非表示にしたい時はどうするべきか？の理解が浅かったので考えをまとめています。


## 要素を非表示にする方法は2つ

要素の非表示をする方法は2つの選択肢があるかと思います。

- style属性で`display:none`を付与する
    - jQueryで`hide()` / `show()`を使うのもこちらに当たります
- `display:none`が付いたクラスを用意して付与する
    - [Bootstrapの`d-none`](https://getbootstrap.jp/docs/5.3/utilities/display/)などもこちらに当たります

## どちらが良いのか

下記の観点から、「CSSのクラスを用意して付与する」方が良いのでは考えました。

### セマンティクスの分離

一番はこれかと思ってます。

HTMLは文書の構造であるべきなはずなのに、直接style属性でスタイルを当てて変更をするのは本来の意図と反しています。CSSにスタイルを書く方が意味的にあっています。

### 特異性

style属性で当てると、その状態で表示したい場合に詳細度を考慮する必要が出てきます。
クラスが当たっている状態よりも調整がしづらいです。

## クラス名をどうするか

以下のようなパターンがパッと思いつくかと思います。

- ①非表示の時だけクラスを付与する：`hidden`や`is-hidden`など
- ②表示の時にもクラスを付与する：`hide` / `show`など

下記の例からメリットデメリットを考え、①が最適かと考えています。

### ①非表示の時だけクラスを付与する

```HTML
## 表示

<p class="text">テキスト</p>

## 非表示

<p class="text hidden">テキスト</p>
```

- メリット
    - textが隠れていることは直感的にわかる
    - `display:block`じゃない時（flexやgridなど）の場合はこちらの方が扱いやすい
        - ↑これがいちばんのメリットだなと思ってます
- デメリット
    - textが動的に隠れる要素かは判断できない


### ②表示の時にもクラスを付与する

```HTML
## 表示

<p class="text show">テキスト</p>

## 非表示

<p class="text hide">テキスト</p>
```

- メリット
    - textの表示が切り替わることを想像しやすい
- デメリット
    - displayプロパティの重複（打ち消し）が起きやすい
    - 実際のロジックではクラス名の付け外しを同時にしなければいけないのでコードが冗長になる
    - `display:flex`のものには別のクラスを用意しないといけないのでコードが冗長になる
        - ↑これが一番のデメリットと思ってます

## まとめ

要素の非表示の切り替えは、
「`display: none`が付いたクラスを用意して、非表示の時に付与する」が良いのかな？と考えました。

`hidden` と `is-hidden` など細かいクラス名に悩みそうですが、
チームとしてよりわかりやすい方を選ぶで良いのではと思ってます。



Ateam LifeDesign Advent Calendar 2024では、その他にもたくさんの記事を投稿しています。
ぜひご覧ください。ではまた！ :wave_tone1:

[https://qiita.com/advent-calendar/2024/ateam-life-design](https://qiita.com/advent-calendar/2024/ateam-life-design)
[Python / shapely] NotImplementedError: Multi-part geometries do not provide a coordinate sequence が発生した原因と対処法

# エラー発生状況

以下のようなコードで、表題のエラーが発生した。

```python
instance.coords

# ... 途中略

  File "/usr/local/lib/python3.8/site-packages/shapely/geometry/base.py", line 960, in coords
    raise NotImplementedError(
NotImplementedError: Multi-part geometries do not provide a coordinate sequence
```

# 原因

`instance.geom_type` が `"LineString"` なら `instance.coords` を実行できるのですが、例えば `"MultiLineString"` だったりすると、 `.coords` を呼べないようです。


自分のコードからなぜ `MultiLineString` が作成されたのかはわかりませんでしたが、 `MultiLineString` は以下のように作成することができます。

```python
from shapely.geometry import MultiLineString


multi_line_string = MultiLineString([
    [(0.1, 0.2), (0.2, 0.2), (0.2, 0.1)],
    [(0.2, 0.3), (0.3, 0.3), (0.3, 0.2)],
])
print(multi_line_string)

# 実行結果
MULTILINESTRING ((0.1 0.2, 0.2 0.2, 0.2 0.1), (0.2 0.3, 0.3 0.3, 0.3 0.2))
```

これに対して `.coords` を呼び出そうとすると、同じエラーが発生します。

```python
multi_line_string.coords

# 実行結果
---------------------------------------------------------------------------
NotImplementedError                       Traceback (most recent call last)
Cell In[23], line 1
----> 1 multi_line_strg.coords

File /usr/local/lib/python3.8/site-packages/shapely/geometry/base.py:960, in BaseMultipartGeometry.coords(self)
    958 @property
    959 def coords(self):
--> 960     raise NotImplementedError(
    961         "Multi-part geometries do not provide a coordinate sequence")

NotImplementedError: Multi-part geometries do not provide a coordinate sequence
```

# 対処

このような場合には、以下のようにして中身をバラしてあげたら、 `.coords` を呼び出すことができました。

```python
line_instances = []
if instance.geom_type == "MultiLineString":
    for single_line in instance.geoms:
        line_instances.append(single_line)
   

# 一つずつ coords を実行してあげる
line_instances[0].coords
```