OmniAICreator/Qiita-1.07M huggingface dataset:
paizaの答えをAIに頼んで別言語に書き換えさせる2【3Dプリンタ問題】


前にプログラミング問題の解答をAIに頼んで別言語に書き換えさせる記事を書きました。
あんまり上手くいかなかったので再チャレンジします。

https://qiita.com/wagreagrw/items/5f2236db2b08e71e1578

この記事はpaizaの問題の答えを
AIに頼んで別言語に書き換えさせようという試みです。
Pythonの解答をPowerShellに書き換えさせてみます。


## paizaとは
ブラウザ上でコードを書いて実行できる、無料プログラミング練習問題集です。

- 難易度別に問題を選ぶ
- 問題文を読んで、解答コードを書く
- 提出するとテストケースが実行されて結果をわかる
- 正解・不正解だけではなく、解答コード例や解説も見ることができるので、プログラミングの習得から復習まで活用できます
### こんな人におすすめ
- プログラミングスキルの腕試しをしたい方
- プログラミングのスキルアップしたい方
- 新しい言語にチャレンジをしたい方

## 問題
3Dプリンタ (Bランク相当)

https://paiza.jp/works/mondai/b_rank_skillcheck_archive/3d_printer


### Pythonで書いた解答
~~~
X, Y, Z = map(int, input().split())
grid = [[0] * Y for _ in range(Z)]

for z in range(Z):
	for x in range(X):
		s = input().strip()
		for y in range(Y):
			if s[y] == '#':
				grid[z][y] = 1

	bar = input()

for z in range(Z - 1, -1, -1):
	for y in range(Y):
		if grid[z][y] == 1:
			print("#", end="")
		else:
			print(".", end="")
	print()
~~~

↑これを元にAIへ質問を投げます。

「
PythonプログラムをPowerShell Ver5.1プログラムに書き換えてください。
プログラムを書き換えるときに次のポイントに注意してください
・変数は全て半角小文字とする
・標準入力をスプリットするときは(read-host).split()と書く
」

### AIの解答：
~~~
# 入力を取得
$x, $y, $z = (read-host).split() | ForEach-Object { [int]$_ }
# グリッドを初期化
$grid = @()
for ($i = 0; $i -lt $z; $i++) {
    $grid += ,(@(0) * $y)
}

# グリッドにデータを入力
for ($i = 0; $i -lt $z; $i++) {
    for ($j = 0; $j -lt $x; $j++) {
        $s = read-host "Enter row for Z=$i, X=$j"
        for ($k = 0; $k -lt $y; $k++) {
            if ($s[$k] -eq '#') {
                $grid[$i][$k] = 1
            }
        }
    }
    # バーの入力 (この変数は使用しないが、指定された仕様に従う)
    $bar = read-host
}

# グリッドを逆順で出力
for ($i = $z - 1; $i -ge 0; $i--) {
    for ($j = 0; $j -lt $y; $j++) {
        if ($grid[$i][$j] -eq 1) {
            write-host -NoNewline "#"
        } else {
            write-host -NoNewline "."
        }
    }
    write-host
}
~~~

### まとめと解説：
　前回記事ではPythonのプログラムをPowerShellに書き換えるように指示しただけでしたので失敗してしまいましたが、今回は注意点も合わせて伝えてみました。
 
- 変数は全て半角小文字とする
　PowerShellでは変数の大文字・小文字の区別がないので変数Aも変数aも同じ扱いになります、AIはこれを学習していないみたいなので変数名を小文字限定に指示しました。
<br>
 
- 標準入力をスプリットするときは(read-host).split()と書く
　標準入力の書き方も学習していないようなので指示しました。この指示がないと「read-host -split " "」と書かれてしまいます。

 <br>
　このように<INS>使いこなすのにプログラミング知識が必要</INS>で、細かい指示をいちいちしないと答えが出せないのでは、まだまだAIは発展中のツールなのだと思います。
 
「プログラミング知識が無くてもプログラムが書ける」という謳い文句のツールは昔からあって30年以上前の汎用機時代からあります。COBOLをJAVAに書き換えるとか、フローチャートをプログラムに置き換えるとか、文章をプログラムに置き換えるとか、いろいろありましたけど、どれもイマイチでした。

どうしてメディア(マーケッター)の人たちが絶賛しまくっているのか？
投資家からお金を集めたいとか、労働者の単価を下げたいとか？
統計学のサンプルサイズ、標準誤差、標準偏差、母集団の標準偏差について



## サンプルサイズ、標準誤差、標準偏差、母集団の標準偏差について

統計学において、母集団全体の特性を理解するためにサンプルを抽出し、そこから得られる情報を元に推定を行います。このプロセスで重要な概念が、サンプルサイズ、標準誤差、標準偏差、そして母集団の標準偏差です。

### サンプルサイズ
サンプルサイズとは、母集団から取り出されたデータの数を指します。サンプルサイズが大きくなるほど、サンプル平均は母集団平均に近づきやすくなります。これは、大きなサンプルがより多くの情報を含んでおり、母集団全体をより正確に反映する可能性が高くなるためです。

### 標準誤差
標準誤差（Standard Error, SE）は、サンプル平均がどの程度母集団平均から離れているかを示す不確実性の指標です。標準誤差は次の式で計算されます：

1. 標準誤差 (Standard Error, SE) の式:
```math
   SE = \frac{\sigma}{\sqrt{n}}
```
ここで、
σ は母集団の標準偏差、n はサンプルサイズです。
この式からわかるように、サンプルサイズが大きくなると、標準誤差は小さくなります。つまり、サンプル平均が母集団平均により近づくことを意味します。逆に、サンプルサイズが小さいと標準誤差は大きくなり、サンプル平均のばらつきが増えるため、推定の信頼性が低下します。

### 標準偏差
標準偏差（Standard Deviation, SD）は、サンプル内のデータポイントがサンプル平均からどれだけ離れているかを示す指標です。標準偏差は、データのばらつきそのものを表し、次の式で計算されます：
2. 標本標準偏差 の式:
```math
   s = \sqrt{\frac{1}{n-1} \sum_{i=1}^{n} (x_i - \bar{x})^2}
```

### 母集団の標準偏差
σは、母集団全体におけるデータのばらつきを表します。母集団全体のデータが利用できる場合、この値は計算できますが、実際には母集団全体のデータが得られないことが多いため、通常はサンプルから推定されます。

### まとめ
サンプルサイズが増加すると、標準誤差は小さくなり、サンプル平均が母集団平均に近づくことが期待されます。標準偏差は、サンプル内のデータのばらつきを示し、母集団の標準偏差が未知の場合は標本標準偏差を用いて推定されます。これらの概念は、統計的推定の精度や信頼性を理解するために非常に重要です。

## 具体例
![output.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36629/f707ed58-5016-5506-82ea-edb3d717a5cd.png)

上記のプロットは、サンプルサイズと標準誤差の関係を示しています。サンプルサイズが増えると、標準誤差が小さくなることが視覚的に確認できます。

具体的な標準誤差の値は以下の通りです：

サンプルサイズ 10: 標準誤差 ≈ 3.98
サンプルサイズ 50: 標準誤差 ≈ 1.44
サンプルサイズ 100: 標準誤差 ≈ 0.90
サンプルサイズ 500: 標準誤差 ≈ 0.44
サンプルサイズ 1000: 標準誤差 ≈ 0.32
サンプルサイズ 5000: 標準誤差 ≈ 0.14
サンプルサイズ 10000: 標準誤差 ≈ 0.10
この例では、母集団の平均身長が 170cm、標準偏差が 10cm である仮想の人口を考えました。サンプルサイズが大きくなるほど、標準誤差が小さくなり、サンプル平均が母集団平均に近づくことがわかります。これにより、サンプルサイズを大きくすることで推定の精度が向上することが確認できます。

## Pythonのコード全文
```Python
import numpy as np
import matplotlib.pyplot as plt

# Define parameters
population_mean = 170  # cm
population_std_dev = 10  # cm
population_size = 1000000

# Generate a population with a normal distribution
np.random.seed(42)
population = np.random.normal(population_mean, population_std_dev, population_size)

# Sample sizes to consider
sample_sizes = [10, 50, 100, 500, 1000, 5000, 10000]

# Store the standard errors for different sample sizes
standard_errors = []

for size in sample_sizes:
    samples = np.random.choice(population, size, replace=False)
    sample_mean = np.mean(samples)
    sample_std_dev = np.std(samples, ddof=1)  # ddof=1 for sample standard deviation
    standard_error = sample_std_dev / np.sqrt(size)
    standard_errors.append(standard_error)

# Plotting the standard error against sample size
plt.figure(figsize=(10, 6))
plt.plot(sample_sizes, standard_errors, marker='o')
plt.title('Standard Error vs. Sample Size')
plt.xlabel('Sample Size')
plt.ylabel('Standard Error')
plt.grid(True)
plt.xscale('log')  # Log scale for better visualization
plt.show()

standard_errors, sample_sizes
```
ロジカルシンキングを考える

# 最初に

最近、仕事で自分の意見が相手にうまく伝わらないことが多いと感じたため、以下の本を読んでみました。

- [https://www.amazon.co.jp/ロジカル・シンキング-Best-solution-照屋-華子-ebook/dp/B00978ZQOG/ref=zg_bs_g_1099156_d_sccl_27/355-7224766-1597644?psc=1](https://www.amazon.co.jp/%E3%83%AD%E3%82%B8%E3%82%AB%E3%83%AB%E3%83%BB%E3%82%B7%E3%83%B3%E3%82%AD%E3%83%B3%E3%82%B0-Best-solution-%E7%85%A7%E5%B1%8B-%E8%8F%AF%E5%AD%90-ebook/dp/B00978ZQOG/ref=zg_bs_g_1099156_d_sccl_27/355-7224766-1597644?psc=1)

読んだ内容を踏まえて自分なりの理解を記事としたいと思います。

(上記の本は例が随所にあり理解がしやすく、途中にトレーニングページがあり、自分のロジカルさがどれほどか確認しながら読み進めることができたので、読んでよかったです)

あくまでも、上記の本を読んだ上での自分の理解なので、考えが違う箇所や間違いがあればコメントいただけると幸いです。

ロジカルシンキングは様々な場面で必要とされる力ですが、今回はとある問題に対する結論を相手に伝えるようなケースを想定しています。

ただ、特定のケースに依存しないような表現を意識していますので、様々なケースに応用できればと思っています。

# 情報の全体図

この図が自分の中で一番イメージしやすかったため、最初に示します。

最終的には、この図のように情報がまとめられ、結論が示される形を目指します。

※図では階層は3段階になっていますが、ケースバイケースであり、階層は変動します。

![ロジカルシンキング体系図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2986704/33450448-720b-e1b8-194c-acc44a3996f5.png)


# ロジカルシンキングの流れ

ロジカルシンキングは、以下のような流れで考える必要があると思っています。

1. 必要な情報の収集
    1. 問題の明確化
    2. 必要な情報の明確化
    3. 必要な情報の収集
2. 結論の導出
    1. 横軸・縦軸で組み立てる
    2. 結論の決定

# 1. 必要な情報の収集

## 1-a. 問題の明確化

まず、問題に対してどのような情報を集める必要があるのかを確認するために理解を深めます。

その問題に対して、こちらがどんな結論を持っていかないといけないのか、元の目的は何かなど。

### ポイント

- 問題が発生した元の目的は必ず明確にする。

### 例

例えば、「工数を出して、社員にQiita記事投稿してもらう価値はあるか」という問題に対して、目的が「社名を拡げる」と「社員の知識向上」では判断基準となる情報が変わります。

このように、目的によって重点が置かれるポイントが変わるため、目的は必ず明確にしておいた方が良いと考えます。

## 1-b. 必要な情報の明確化

ここで、結論を導くためにどんな情報が必要かを明確にします。

### ポイント

- 問題に対して「MECE」でブレークダウンする。

### 例

例えば、先ほどの「工数を出して、社員にQiita記事投稿してもらう価値はあるか」に対して考えるとき、以下のように考えていくと良いと思います。

- 問題：工数を出して、社員にQiita記事投稿してもらう価値はあるか
    - メリット
        - 社内への影響
        - 社外への影響
    - デメリット
        - 社内への影響
        - 社外への影響

もし、最初のブレークダウンがメリットだけだと、聞き手は「あれ、デメリットはないんだっけ？隠してる？」のような疑いの目を持ち始めてしまいます。

MECEで情報を羅列していくことで相手の納得感が得られるのは、経験からも明らかかと思います。

ただ、このMECEの切り口は複数通りあり、目的に沿った切り口を探す必要があるため、クリエイティブな作業だなと感じます。

## 1-c. 必要な情報の収集

ここでは、先ほどのフェーズで明確にした情報を実際に収集します。

### ポイント

- 情報源は、事実か自分の判断か
- 情報は具体的か

### 例

例えば、先ほどの「工数を出して、社員にQiita記事投稿してもらう価値はあるか」を考える場合に、「自分は、社名を拡げるのに効果があると考えます」や「他の企業は社員の生産性が上がっています」だけ言われても聞き手は納得できません。

なので、自分の判断の場合は注意が必要ですし (2-aで追加の解説あり) 、抽象的な表現はあまり使用しない方が良いと考えます。

# 2. 結論の導出

## 2-a. 横軸・縦軸で組み立てる

収集した情報を論理的な接続を考えながら組み立てます。

### ポイント

- 横軸：MECEまたは「事実→判断基準→判断結果」で構成する

自分の判断の場合は後者で構成し、特に判断基準を明確にしておく必要があります。

- 縦軸：上から下は「なぜそうなるか」、下から上は「だから何か」で構成する

ここで上下の関係を構成するわけですが、ここで起きがちなのが、論理の飛躍です。

「なぜそうなるか」はわかるけれど「だから何か」がしっくりこないみたいなパターンはありがちです。

必ず双方向に問題がないか確認し、上下を論理的に構成しましょう。

## 2-b. 結論の決定

このフェーズ入る時には、結論を決定するための情報が揃っていると思います。

揃えた情報から結論を導きましょう！

## ポイント

- 問題に対する答えになっているか

ありがちなのが、検討を重ねるうちに問題から乖離していき、問題に対して結論が答えになっていないパターンです。

問題と結論だけをみて正しく答えになっているかは必ず確認しましょう。

ここまでくると最初に示した全体図のような構成に情報が整理されているかと思います。

# 最後に

ロジカルシンキングのような考え方は本などで勉強して終わりではなく、自分なりに試行錯誤を加えた上で体に覚えさせる必要があると思います。

今回の考えも今後アップデートしていき、相手に伝わりやすい表現力を磨いていきます。

ここまで読んでくださりありがとうございました。
Python3: Fizz Buzz (paizaランク C 相当)やってみた

分岐の問題なんですが、単純な繰り返しでもある。

https://paiza.jp/works/mondai/c_rank_skillcheck_sample/fizz-buzz


```py:
def fizzbuzz_gen():
    F = "Fizz"
    B = "Buzz"
    FB = "Fizz Buzz"
    i = 0
    while True:
        yield from (
            i+1, i+2, F, i+4, B
            , F, i+7, i+8, F, B
            , i+11, F, i+13, i+14, FB
            )
        i += 15

fb = fizzbuzz_gen()

N = int(input())

for _ in range(N):
    print(next(fb))
```
分岐なしでやってみました。無駄な演算をなるべく減らしてみます。

```py:
unbox = lambda *xs: xs[-1]

def count_gen(i):
    while True:
        yield i
        i += 1

def fizzbuzz_gen():
    F = "Fizz"
    B = "Buzz"
    FB = "Fizz Buzz"
    c = count_gen(1)
    while True:
        yield from (
            next(c), next(c), unbox(next(c), F)
            , next(c), unbox(next(c), B), unbox(next(c), F)
            , next(c), next(c), unbox(next(c), F)
            , unbox(next(c), B), next(c), unbox(next(c), F)
            , next(c), next(c), unbox(next(c), FB)
            )
        
fb = fizzbuzz_gen()

N = int(input())

for _ in range(N):
    print(next(fb))
```
あるいは：

```py:
def count_gen(i):
    while True:
        yield i
        i += 1

def fizz_gen():
    c = count_gen(1)
    while True:
        for _ in range(1, 3):
            yield next(c)
        next(c)
        yield "Fizz"

def fizzbuzz_gen():
    f = fizz_gen()
    
    while True:
        for _ in range(1, 3):
            for _ in range(1, 5):
                yield next(f)
                
            next(f)
            yield "Buzz"
            
        for _ in range(1, 5):
            yield next(f)
            
        next(f)
        yield "Fizz Buzz"


fb = fizzbuzz_gen()

N = int(input())

for _ in range(N):
    print(next(fb))
```
現物を並べただけだとおばかっぽく見えるので。
普段はFizzのジェネレーターの値を採用して、Buzz、FizzBuzzのときだけ "Buzz"、"Fizz Buzz" を返す、って感じです。
MVCモデルについて

# MVCモデルについて
WEBアプリについて独学や講義を受けるとMVCモデルについて学ぶと思います。
MVCモデルについてはそれぞれの役割についてまとめます。
* M(Model)：アプリケーションのビジネスロジックを担当。データの更新等を行う
* V(View)：ユーザに表示するビュー。モデルで取得したデータを利用してレンダリングする
* C(Controller)：ユーザの入力を処理し、入力データに基づきモデルを操作し、結果をビューに返却する

MVCモデルについては以下のようなイメージになるかと思います。
**MVCモデルイメージ**
```plantuml
(View) <-> (Controller)
(Controller) <-> (Model)
```

# MVCモデルの動作について
ユーザにはViewを返却することになりますが、コーディングとしていると、コントローラーで返却することになるため、モデルイメージと若干のギャップがあるかと感じると思いますので、具体的にどのような動作になるのか説明したいと思います。

```plantuml
autonumber
actor User
box "クライアント側"
participant  "Web" as H
end box

box "サーバ側"
participant  "View" as V
participant  "Controller" as C
participant  "Model" as M
end box

User --\ H : ボタン押下
activate H
H -> C : リクエスト
activate C
C -> M : リクエスト
activate M
M --> C : レスポンス
deactivate M
C -> C : Viewにセットする情報()
C --> V : レスポンス
deactivate C
activate V
V --> H : レスポンス
deactivate V
H --\ User : レスポンス
deactivate
```

* ユーザがボタン押下でControllerはリクエストを受領
* ControllerはModelにアクセスしてデータ取得を行い、Controllerに処理返却
* Contorllerは**Modelから取得したデータをViewにバインド**し、WEBにHTMLを返却

実際にコーティングを行うと、ViewがクライアントにHTMLを返却するわけではなく、ControllerがView(HTMLテンプレート）に記載されているバインドする変数を準備し、View(HTMLテンプレート)とバインドする変数を返却するフローとなります。

コードイメージについて記載します。
※以下コードについては処理イメージとなります。
```java:View
<!DOCTYPE html>
<html>
<head>
    <title>Form Submission Result</title>
</head>
<body>
    <h1>Submission Result</h1>
    <p>Name: <%= request.getAttribute("name") %></p>
    <p>Email: <%= request.getAttribute("email") %></p>
</body>
</html>
```

```java:Controller
public class SubmitFormServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        User user = UserDaoImpl.getUserDao();

        request.setAttribute("name", user.name);
        request.setAttribute("email", user.email);
        
        // 結果を表示するJSPにフォワード
        RequestDispatcher dispatcher = request.getRequestDispatcher("result.jsp");
        dispatcher.forward(request, response);
    }
}
```

```java:Model
public class UserDaoImpl Implemetns UserDao {
    @Override 
    public getUser( int index ) {
        // User情報を取得する
        // User user = get・・・
        return user
    }
}
```

# まとめ
MVCの開発について説明をしました。
コードを見てわかるように、ControllerがModelの取得し、取得結果をViewにバインドすることでHTMLを返却します。
Contollerはリクエストを受け取り、何かしらの処理を行い、Viewにバインドし返却することで、HTMLが表示されます。

記事が参考になれば幸いです。
Azure StaticWebAppsで簡単に認証を行う

# 対象とする読者
Azure SWAでWebアプリを作ったけど、特定の人にだけ見せたいという人

# 設定方法
- staticwebapp.config.json ファイルでルールを定義して、許可されているユーザーが制限されたルートにアクセスできるようにします

参考：
https://learn.microsoft.com/ja-jp/azure/static-web-apps/authentication-authorization

## ロール
デフォルトではユーザーは anonymous ロールと authenticated ロールに属します。

## staticwebapp.config.json
- allowedRoles: 任意の文字列

```json:staticwebapp.config.json
{
  "routes": [
    {
      "route": "/*",
      "allowedRoles": ["administrator", "reader"]
    }
  ],
  "responseOverrides": {
    "401": {
      "statusCode": 302,
      "redirect": "/.auth/login/aad"
    }
  }
}
```

# 招待 & ロール付与方法
- SWAのロール管理メニューを選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476893/f0fa9b6a-a3b5-afec-f08e-fb98d55bec74.png)

- 招待を押下

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476893/04b6adee-cf63-6994-47cb-da373301d80d.png)

- 招待したい人のメールアドレスを指定して生成を押下
  - ロールの説明に閲覧者と日本語で出ているが、まどわされずに「reader」と英字で入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476893/0d5099aa-6e6a-537d-e5dd-f3f841130a9a.png)

- 招待リンクが発行される

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/476893/dd388192-9f57-a076-9d09-daf8e5544445.png)

※招待リンクのURL例
https://XXXXX.azurestaticapps.net/.auth/invitations/accept?provider=aad&userDetails=XXXXX&roles=YYYY&se=AAA&sig=BBB
シェルスクリプトで SIGPIPE を無視する方法

シェルスクリプトで SIGPIPE を無視する方法です。特に `set -o pipefail` を使用しているときに便利でしょう。ちなみに pipefail は POSIX.1-2024 で標準化されたので、もはや bash の拡張機能ではありません。以下のコードは POSIX 準拠の範囲で書いており、どの環境でも動作します。

```sh:SIGPIPE を無視するためのシェル関数
igpipe() {
  # set -e (errexit) が有効でも無効でも正しく動作するようにするため
  case $- in
    *e*) set +e; (set -e; "$@"); set -e -- $? ;;
    *) ("$@"); set -- $? ;;
  esac

  # 終了ステータスが 128 以上でない場合はシグナルではないので調べる必要はない
  [ "$1" -ge 128 ] || return "$1"

  # 「kill -l 終了ステータス」で対応するシグナル名を取得可能
  # 補足: POSIX では SIGPIPE が 141 (128 + 13) である保証はなく
  # 実際に ksh、yash では 141 ではない
  [ "$(kill -l "$1")" = PIPE ] || return "$1"
}
```

```sh
set -o pipefail

# SIGPIPE が発生する
seq 1000000 | head -n 10
echo "$? : ${PIPESTATUS[@]}" # => 141 : 141 0

# SIGPIPE を無視する
igpipe seq 1000000 | head -n 10
echo "$? : ${PIPESTATUS[@]}" # => 0 : 0 0
```

**補足** SIGPIPE はパイプラインを使ったコードで、データを出力しているコマンドよりも、出力先のコマンドが早く終了することで、データの書き込み先がなくなったことを知らせるシグナルです。

## バッドプラクティス（ダメな方法）

SIGPIPE を無視しようとして、以下のようなコードを書くのはよくありません。

:::note alert
SIGPIPE（？） を無視する良くない方法

```sh
seq 1000000 | head -n 10 || true
```

```sh
{ seq 1000000 || true; } | head -n 10
```
:::

たしかにこの方法で SIGPIPE を無視することができますが、**その他のエラーまで無視してしまいます**。その他の方法として一時的に pipefail を無効にする方法も考えられますが、当然 pipefail 本来の機能（途中のコマンドのエラーを検出する）まで機能しなくなってしまいます。

## 補足 pipefail とは？

pipefail はパイプラインのエラーを検出するときに便利な機能です。デフォルト（pipefail が無効）だと、パイプライン全体の終了ステータスは、パイプラインの最後のコマンドのものとなってしまい、途中のエラーを検出することができません。

```sh:set -o pipefail の典型的な使い方
set -o pipefail

# pipefail が無効だと cmd1 や cmd2 でエラーになっても、
# cmd3 が正常終了してしまうとパイプライン全体は正常終了扱いになる
if cmd1 | cmd2 | cmd3; then
  echo すべてのコマンドが正常終了しました
else
  echo いずれかのコマンドでエラーが発生しました
fi
```

上記のコードは POSIX 準拠 (POSIX.1-2024) のコードです。bash と mksh の `PIPESTATUS` 配列や zsh の `pipestatus` 配列を使って調べる方法もありますが、`PIPESTATUS` や `pipestatus` は POSIX 準拠ではないため非推奨とします。

:::note warn
PIEPSTATUS を使って調べる方法の例（POSIX 準拠ではないため非推奨）

```sh
cmd1 | cmd2 | cmd3
if (( (${PIPESTATUS[@]/#/+}) == 0 )); then
  echo すべてのコマンドが正常終了しました
else
  echo いずれかのコマンドでエラーが発生しました
fi
```

:::

なぜこのコード `(( (${PIPESTATUS[@]/#/+}) == 0 ))` で動くのかというと、`${var[@]/#pattern/str}` は配列の各要素の先頭から、パターンにマッチする文字列を置き換える変数展開で、ここではパターンを省略しているため各要素の先頭に + を追加するという意味になるからです。つまりこのコードは `PIPESTATUS` 配列のすべての要素を足しています。

```sh
(exit 1) | (exit 2) | (exit 3)
echo $(( ${PIPESTATUS[@]/#/+} )) # => 6
# ↑ echo $(( +1 +2 +3 )) を実行する
```
画像認識の環境構築とVSCodeの設定

# はじめに
<!-- 発端や概要を記載 -->
私は機械学習用にRTX3090のデスクトップPCを1台持っており、定期的にメンテナンスを行なっています。
今回、RTX3090環境へUbuntu24.04をインストールしたので、その作業内容をメモとして公開します。

本記事では、私がよく使う画像認識向け開発環境構築手順のメモを公開します。
機械学習環境はpytorchを前提とします。

なお、関連する記事は下記の通りです。
- [RTX3090環境へのUbuntu24.04セットアップ](https://qiita.com/genmai99/items/501ace251eaefbcb3649)
- [RTX3090/Ubuntu24.04でNVIDIA環境をセットアップ](https://qiita.com/genmai99/items/c0e6ffda4e23394bccd8)
- [Githubの初期設定](https://qiita.com/genmai99/items/ff700738bb87dfbbba14)
- (本記事) 画像認識の環境構築とVSCodeの設定
- [私のVSCodeのカスタマイズ](https://qiita.com/genmai99/items/5e4cc56420f51a80828a)

# 目次
<!-- タイトルとアンカー名を編集 -->
1. [venvで仮装環境構築](#venvで仮装環境構築)
1. [VSCodeの設定](#vscodeの設定)
1. [最後に](#最後に)
1. [参考文献](#参考文献)

<!-- 各チャプター -->
<a id="#venvで仮装環境構築"></a>
# venvで仮装環境構築

今回は環境名をpytorchとします。

- workディレクトリの中に環境名のディレクトリを作って移動

```
$ mkdir work/pytorch
$ cd work
```

- 仮装環境を作成

```　
$ python3 -m venv pytorch
```

- アクティベート

```
$ source pytorch/bin/activate
```

- [ここ](https://pytorch.org/)でpytorchのバージョンを確認し、仮装環境pytorchにインストール
- 今回pytorchはCUDA 12.4向けを入れます

```
$ pip3 install --upgrade pip
$ pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu124
$ pip3 install timm torchextractor yacs
```

- 続いてOpenCVとnumpyなど一通り必要なものを入れていきます

```
$ pip3 install opencv-python opencv-contrib-python
$ pip3 install imageio numpy pandas matplotlib scikit-image lxml pillow Cython contextlib2 jupyter scikit-learn seaborn tqdm
下記、サンプルで使っている案件があったため追加
$ pip3 install japanize_matplotlib torchviz
```

以上で基本環境はほぼ終わりです。
ちょっとした事ならこの環境で動かし、公開された論文の実装などはそれぞれ環境を構築して運用しています。

<a id="#vscodeの設定"></a>
# VSCodeの設定

VSCodeが非常に便利なので、VSCodeで動くように設定します。

### インタープリターで選択できるようにする

- VSCodeを起動しworkディレクトリを開く
- Ctrl(MacならCmd)+Shift+P
- Python: Select interpreterを選択
- ここから、作成した環境(pytorch)の表示有無で作業が変わります
 -　表示されている
　  -　pytorch環境を選択して完了
 -　表示されていない
　  -　Enter interpreter pathを選択
　  -　Findを選択
　  -　pytorch/bin/python3.12を選択
　  -　インタープリターに仮装環境を選択する
　  -　Ctrl(MacならCmd)+Shift+P
　  -　候補にpytorch環境が出てくるので選択
　  -　VSCodeを再起動

- 以上でインタープリターに作成した環境(pytorch)が表示されるようになります

### jupyter notebookを扱う時の注意
- VSCodeのアドオンでjupyterを入れている前提
- 実行時にkernelが自動起動するのでvenv環境を選択する
　-　もし自動起動しない場合は、右上のkernelをクリックすると同じ選択ができる

<a id="#最後に"></a>
# 最後に
以上、これまで４記事に渡って私がいつも最初に行うOSアップデート後の立ち上げ作業を書きました。
とはいえ、これで作業は終わりでなく...
この後にDockerやらAWS周りも設定しますし、
アカウントで同期がとれるとはいえ、VSCodeだって随時拡張しています。
そのあたり、ちょっとづつ自分用にメモを残していこうと思います。

<a id="#参考文献"></a>
# 参考文献
- [VS CodeでJupyterしてみよう](https://atmarkit.itmedia.co.jp/ait/articles/2108/06/news030.html)
scrollendイベントをiosでも処理したい

# 前提
Webアプリケーションにおいて、PC、Android、iPhoneで同じスクルール終了時のアクションを行いたい

# 課題
PC、Androidにはscrollendイベントが存在するが、safariには存在しない

https://developer.mozilla.org/ja/docs/Web/API/Element/scroll_event

https://developer.mozilla.org/ja/docs/Web/API/Element/scrollend_event

# 対処案
safariの場合のみ分岐させ、scrollイベントでなんとか（※）する
※setTimeoutで100ms後に動作させるイベント登録を行う。継続してscrollイベントが来る場合にはclearした上で、再度登録しなおす

```tsx
  useEffect(() => {
    const timeoutFn = () => {
      window.clearTimeout(timeoutId);
      timeoutId = window.setTimeout(handleScrollEnd, 100);
    };
    const notIos = 'onscrollend' in window;
    if (notIos) {
      // For PC,Android
      window.addEventListener('scrollend', handleScrollEnd);
    } else {
      // For IOS
      window.addEventListener('scroll', timeoutFn);
    }
    return () => {
      window.removeEventListener('scrollend', handleScrollEnd);
      window.removeEventListener('scroll', timeoutFn);
    };
  }, [handleScrollEnd]);
```

# 残課題
100ms後に処理しているため、遅延して処理していることが体感できるレベル

- もっとうまいやり方があれば教えてください
【初学者向け】.htmlの<script type="text/jsx">内をハイライトする方法

## はじめに
[Reactの公式チュートリアル(React Foundations)](https://nextjs.org/learn/react-foundations)を進めている際、HTML内のscript要素のtype属性にtext/jsxを指定したところ、コードがハイライトされず、視認性が低下していた。

## 結論
`text/jsx` を `text/babel` に置換することで、シンタックスハイライト問題が解決します。

![text/jsx](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3511329/5698a63c-5484-a393-68ac-d405d7b685c9.png)

![text/babel](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3511329/1e7aba6b-dbeb-f83f-9ead-d2ac2769c813.png)

## 調査結果
[Syntax for text/jsx inside HTML #119](https://github.com/textmate/html.tmbundle/issues/119)にて、既知の問題として報告されていましたが、解決されておらず。
代替案としてtext/babelに置き換える方法が提示されていました。
【備忘】gitの退避にはgit stash pushが良さそう


# はじめに

git で現在の作業を退避（stash）するとき、
今までは `$ git stash -u` や `git stash save {コメント}`を使っていました。

しかしながら、退避コメント付与したい時や特定ファイルのみ退避したいときに、
オプションを忘れてググったり、うまくできずに手間取ることがよくありました。

そんな中、`git stash push`というコマンドがあることを最近知り、
結構便利に感じたので自分用の備忘もかねて紹介します。

# 使い方

## 一番使う退避コマンド

個人的には、今後退避時はこのコマンドだけ使うことになりそうです。

```bash
# 退避対象ファイルをgitステージしておく
$ git stash push -m {コメントをここに} -S
```

## 少し詳しく

これだけだと寂しいので（自分もオプションの意味とか忘れそう）、
`git stash push`の使い方を少し説明します。

### 基本文法

```bash
# 追跡済みのファイル と ステージ済みのファイルを　退避
$ git stash push

# 追跡やステージ関わらず全ファイルを退避（.gitignoreされていないファイルも含む）
$ git stash push -a

# 追跡やステージ関わらず全ファイルを退避（.gitignoreされていないファイルは除く）
$ git stash push -u

#  特定のファイルのみ退避
$ git stash push -- {ファイルパス}
```

### コメント付与や特定ファイルのみ退避したいとき

ファイルパスの指定や変更分の一部ファイルだけを退避したい時に、上記だと面倒です。
そこで、退避したいファイルをステージした後、stash するのが一番楽だと思いました。

```bash
# 退避したいファイルをステージに追加 （自分はVSCodeでやる）
# cliでやるなら以下
$ git add file1 file2 file3

#  ステージしたファイルをすべて退避
$ git stash push -S

# コメントも残したい時
$ git stash push -m {コメントをここに} -S
```

ちなみに`-S`ではステージ済みであれば、`-u`（--include-untracked）をつけなくても未追跡ファイルも退避してくれます。

# まとめ

`$ git stash push -m {コメントをここに} -S`

stash はよく使うけど毎回オプションを忘れてしまうという方はこれがオススメです！

# 参考

https://git-scm.com/docs/git-stash#_commands

https://www.webdesignleaves.com/pr/plugins/git-stash.html
依存関係逆転の法則 どこが逆転しているか

# 依存関係逆転の法則

## 依存関係が逆転する前

通常、アプリケーションは使用するライブラリに依存する。ライブラリに変更があれば、アプリケーションの改修が必要となる。また、使用するライブラリを変更したい場合にも、アプリケーションの改修が必要になる。

![dependency_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/692cd4a0-d122-84b8-7242-234fe3ac4528.png)

## 依存関係が逆転した後

アプリケーションとライブラリの間にインターフェースを介入させることで、ライブラリはインターフェースに依存するようになる。（アプリケーションはインターフェースに依存する。）

ライブラリは依存されていたはずが、逆にインターフェースに依存しなくてはならなくなり、ここで依存関係が逆転している。

![dependency_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/331cfda1-8ab7-ab22-7b8f-8b69d4623fc5.png)

## 依存関係が逆転する利点

依存関係を逆転させると、アプリケーションコードの改修を行うことなくライブラリを別のライブラリに切り替えることが可能になる。

![dependency_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/5c272f07-26f2-6aee-a1cd-ddf800c7c819.png)

# 参考
- [徹底攻略Java SE 11 Gold問題集[1Z0-816]対応](https://amzn.asia/d/0eV9L1Wp)
違うブランチを参照して現在のブランチを使用したいときのgit操作

# 経緯
開発をしているときに別ブランチでlintやtsc,jestのテストを作成していましたが現在のブランチではそれが作成されていなかったためその別ブランチを使用して現在ブランチで開発している内容にもテストを通すようにします。

# git rebaseを使おう
git rebaseとは
簡単にいうとブランチの流れを簡潔にして見やすくする
分岐したブランチの上に現在のブランチを乗っけるようなイメージです。

こちらがとても参考になりました。
https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E6%A9%9F%E8%83%BD-%E3%83%AA%E3%83%99%E3%83%BC%E3%82%B9

# 実際の流れ
現状はmainブランチから切った現在のブランチと、テストを作成しているブランチがある状況でまだテストを作成しているブランチはmainにはマージしていない状況。

仮名で現在のブランチ名を`feature/task`ブランチとし、テストのブランチを`feature/test`ブランチとします。

とりあえず現在のブランチに移ります。
```
git checkout feature/task
```
そして現在ローカルにはテストのブランチがfetchされていないのでローカルに移します。
```
git fetch origin feature/test
```
そして現在ローカルにfeature/testブランチが作成されていないので作成します。
```
git checkout -b feature/test origin/feature/test

```
そしてrebaseしてfeature/taskブランチをfeature/testブランチの上に乗せて参照できるようにします。
```
git checkout feature/task
git rebase feature/test
```
これでテストを参照して開発することができるようになったので変更を加えたら強制的にpushしてPRの際に向き先をfeature/testに変更するようにします。
```
git push -f origin feature/task
```
PRの向き先はこの場合,`feature/test`に変更します。



忘れやすいですがこれから多用することになると思うので記事にしました。
『世界一流エンジニアの思考法』読書メモ

# 概要

この記事は、私が[『世界一流エンジニアの思考法』](https://books.bunshun.jp/ud/book/num/9784163917689)を読んで、私の理解をまとめたものです。
マイクロソフトのソフトエンジニアの著者がマイクロソフトで学んだ、一流エンジニアの思考法が述べられています。


# 第1章

- マイクロソフトのエンジニアはなぜ生産性が高いのか？
  - コードやシステムの理解に時間をかけている
    - コード修正で試行錯誤しない
    - 原因の仮説を立ててから行動するので速い
    - 理解に時間がかかるのは頭の良い人でも同じ
  - 頭の中にメンタルモデルを作るとスピードが上がる
    - メンタルモデルとは、考え方や行動の仕方の様式
    - 一流エンジニアのメンタルモデルを参考にする
    - まずシステム全体のイメージ図を作って理解する、分からなかったらすぐ人に聞く

# 第2章

- 『Be Lazy』(『より少ない時間で価値を最大化するという考え方』)を意識している
- やることを減らす、という考え方から来ている
- 具体例
  - 優先順位をつける(=1つだけピックアップして、それ以外はやらない)
  - 持ち帰りをやめて、その場で解決する
  - 納期を絶対としない。価値を最大化することを考える

# 第3章

- コードリーディングを速くするには？
  - レベル1『何も見ずに即座に実装できるもの』とレベル2『ググれば解決するもの』は違う。
  - レベル1を増やすと、開発が速くなるだけでなくコードリーディングも速くなる
- なぜ一流エンジニアは記憶力が高いのか？
  - 理解して、説明可能な状態にしているから
  - ミーティングで頭の中だけで整理することが訓練になる
    - 他人にどう説明するかを意識しながら人の話を聞くと良い

# 第4章

- 生産性の高いコミュニケーションのコツは？
  - 補足情報のような余分な情報を付けずに最小限だけ聞く
  - 相手(ドキュメントを読む人も含む)が欲しい情報は何かを意識する
  - クイックコールを活用

# 第5章

- 生産性の高いチームにするには？
  - サーバントリーダーシップ
  - 子供扱いしない(あれもだめ、これもだめ、としない)


# 第7章

- 新しいことは、原理的にAIにはできない
- インテグレーション(システム結合やテスト)はAIには難しい
- 技術が身についたり実現したりするには時間がかかる (ChatpGPTで7年)
【AWS RDS】インターネットから接続できるデータベースの作成手順

# 1. 概要
この記事では、<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3837534/b7ceb954-3c3c-bcd5-b3eb-6fa075cce89f.png" alt="RDS" width="14"> RDS(AWS)で外部から接続可能なデータベースを作成する手順を記載しています。

# 2. 目次
1. 概要
1. 目次
1. 手順
    1. マネジメントコンソールをひらく
    1. RDSサービスをひらく
    1. データベース一覧をひらく
    1. データベース作成をひらく
    1. データベースを作成する
    1. データベースのエンドポイントを確認する
    1. MySQLクライアントをつかって、データベースにログインする
1. 参考資料

# 3. 手順
### 3.1 マネジメントコンソールをひらく
※事前にAWSアカウントの作成が必要です。参考：[AWS アカウント作成の流れ](https://aws.amazon.com/jp/register-flow/ "AWS アカウント作成の流れ")
AWSマネジメントコンソールは以下の画面です。AWSの各種サービスを管理・操作できるWeb UIです。
![mgmt_console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3837534/c5c0632c-1443-f535-bd88-da47ad5646cc.png)
<br>
<br>

### 3.2　RDSサービスをひらく
左上の検索フォームに「RDS」と入力すると、サービス一覧に「RDS」が出てくるので、クリックします。
![rds_search.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3837534/e43853e4-5429-037c-457b-354b48aa2ccf.png)
<br>
<br>

### 3.3 データベース一覧をひらく
RDSサービス画面で左側の「データベース」をクリックします。
![rds_top.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3837534/d2a9c15e-56b5-f8fc-2ced-ca7db1b83581.png)
<br>
<br>
### 3.4 データベース作成をひらく
画面右上の「データベースの作成」をクリックします。
![rds_db_list.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3837534/ea5dd0ee-2c1d-2706-1c58-79b2926e4142.png)
<br>
<br>
### 3.5 データベースを作成する
※今回は検証用なので基本的にデフォルト値で作成します。下記の入力項目以外はデフォルト値を使用します。

#### 入力項目
- エンジンのオプション
    - エンジンのタイプ：「**MySQL**」
- テンプレート：「**無料利用枠**」
- 設定
    - マスターパスワード：「　**＜任意の文字列＞**　」
    - マスターパスワードの確認：「 **＜マスターパスワードと同じ文字列＞**　」
- 接続
    - パブリックアクセス：「**あり**」を選択


ここまで入力できたら画面一番下の「データベースの作成」をクリックします。

![create_db.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3837534/2c84c069-5129-e2e5-6885-8680f8c77eff.png)
<br>
<br>

### 3.6 データベースのエンドポイントを確認する
3.5で「データベースの作成」をクリックするとデータベースの一覧画面に移動します。
ステータスが「利用可能」になったことを確認、データベースを選択し、詳細画面に移動します。
※ステータスが「作成中」から「利用可能」になるまで数分かかります。
![rds_db_list_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3837534/4049b7ad-546c-d5d6-b04e-e0960be2a774.png)

詳細画面に移動すると「接続とセキュリティ」に「エンドポイントとポート」の記載があるので、メモします。
![db_info.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3837534/b09decc7-dd90-4923-2fe2-8bfb2325d019.png)
<br>
<br>
### 3.7 MySQLクライアントをつかって、データベースにログインする
※事前にMySQLコマンドやクライアントアプリのインストールが必要です。参考：[mysqlコマンドをインストールする方法](https://qiita.com/ponsuke0531/items/3ae69a9d477809c00917 "mysqlコマンドをインストールする方法") 
以下はターミナルからMySQLクライアントでログインする例です。ログインできれば完了です。
![login.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3837534/f3e6450f-57f5-4d45-3c6c-3bf15368a38f.png)

<br>
<br>
おわりです。
<br>
<br>

# 4. 参考資料

- [<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3837534/b7ceb954-3c3c-bcd5-b3eb-6fa075cce89f.png" alt="RDS" width="14"> AWS RDS ユーザーガイド](https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/Welcome.html)
- [AWS アカウント作成の流れ](https://aws.amazon.com/jp/register-flow/ "AWS アカウント作成の流れ")
- [mysqlコマンドをインストールする方法](https://qiita.com/ponsuke0531/items/3ae69a9d477809c00917 "mysqlコマンドをインストールする方法")
(ベンチマーク)STM8Sで素数を求める3...100まで(理系フリマ入手)


x 理系フリマ831にあるよ

x いちおう、c++じゃないけど、めんどくさいので

目的
素数を求めて時間を測って遊ぶ
2から開始しする
割るのは、2からn-1まで割る
ちゃんと割ってあまりを求める
z = x / y
a = x - ( z * y )

いろいろ
Arduino UNOより速い
ハードウェア、乗算器と除算器があるため


結果

![o_coq323.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/5f7be9ce-1c3a-5f62-61ea-04c7de9c416c.jpeg)

![o_coq324.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/2f7bd5d0-cd85-2f44-15f6-e6ac11402ef6.jpeg)

![o_coq325.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/6897029a-a113-28c6-13b2-9fc1485ce74a.jpeg)


![o_coq326.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/02d65e9c-7b45-69f3-894f-d1db070184a2.jpeg)



プログラム


```c++


//sosuu_STM8S_1

//インクルド
#include <Arduino.h>
#include "Serial.h"


void setup() {

  Serial_begin(9600);

}//setup

void loop() {

  int s[100];
  for (int ii = 0; ii < 100; ii++) {
    s[ii] = 0;
  }//for

  int time;

  int a=1;//work

  int pp = 0;
  //s[pp++] = 1;//debug
  //s[pp++] = 2;//debug
  Serial_println_s("START>>");
  time = millis();

  int ii;int jj;
  for (ii = 2; ii < (100 + 1); ii++) {

    //Serial.print('(');  //debug
    //Serial.print(ii);   //debug
    //Serial.print(')');  //debug
    //Serial.println();   //debug

    for (jj = 2; jj < (ii); jj++) {

      //Serial.print('['); //debug
      //Serial.print(jj);  //debug
      //Serial.print(']'); //debug

      a = ii / jj;
      a = ii - (a * jj);
      if ( a == 0) {
        //Serial.print('*');//debug
        break;
      }//if

    }//for
    if (a != 0) {
      //Serial.print('@');
      s[pp++] = ii;
    }
    //Serial.println();//debug
  }//for

  time = millis() - time;
  Serial_print_s("millis=");
  Serial_println_i(time);

  int yy = 0;
  while (s[yy] != 0) {
    Serial_print_i(s[yy]);
    Serial_print_c(',');
    yy++;
  }//while
  Serial_println_s("");

  Serial_println_s("<<END");
  delay(3000);
  //while (1) {} //debug
}//loop



```
【Python】transitionsで状態遷移実装

# 概要

Pythonのパッケージである `transitions`で状態遷移処理を実装する際のノウハウを、
サンプルソースを元に記載する。

# サンプルソース

```python
from transitions import Machine

# 状態の定義
states = ['A', 'B', 'C']

# 状態遷移の定義
transitions = {'trigger': 'fromAtoB', 'source': 'A', 'dest': 'B'}

# Modelインスタンスの生成
model = Model()

# Machineインスタンスの生成
machine = Machine(model=model, states=states, initial='A', auto_transisitons=False)

# Modelクラスの宣言
class Model(object):
	# 状態Bに遷移した時の処理
	def on_enter_B(self):
		print('State transition to B')
```

# サンプルソースに対する説明

## 状態の定義

```python
states = ['A', 'B', 'C']
```

A状態、B状態、C状態を定義している。

## 状態遷移の定義

```python
transitions = {'trigger': 'fromAtoB', 'source': 'A', 'dest': 'B'}
```

AからBへの状態遷移を定義している。

### フィールド: trigger

状態遷移のトリガーを命名する。
fromAtoB()をコールすることにより、AからBへの状態遷移をトリガーできる。

### フィールド: source

遷移前の状態を指定する。
ここではA状態が指定されているため、C状態にて `fromAtoB()`がコールされたとしても、
C状態からB状態への遷移は行われない。

### フィールド: dest

遷移後の状態を指定する。ここではB状態。

### フィールド: conditions

遷移が発生するための条件を指定する。
指定された変数、リスト、関数の戻り値がTrueの場合のみ遷移が行われる。

### フィールド: unless

遷移が発生しないための条件を指定する。
`conditions`フィールドと逆に、 `False`の場合のみの遷移が行われる。

### フィールド: before

遷移が発生する前に実行されるコールバック関数を指定する。

### フィールド: after

遷移が発生した後に実行されるコールバック関数を指定する。

## Modelインスタンスの生成

```python
model = Model()

class Model(object):
	def on_enter_B(self):
		print('State transition to B')	
```

`Machine`インスタンスの生成に使用するために、
`Model`クラスを宣言してインスタンスを生成している。

### on_enter_B()

状態Bへの遷移が発生した後に実行されるコールバック関数。
`on_enter_[状態名]()`という関数を宣言することで、同様にコールバック関数を追加できる。

## Machineインスタンスの生成

```python
machine = Machine(model=model, states=states, initial='A', auto_transisitons=False)
```

状態遷移を実装するため、Machineインスタンスを生成している。
ここでは、状態遷移実装対象に `model`, 状態に `states`, 初期状態にA状態, `auto_transitions` に `False` が指定されている。

### 引数: model

型は任意のオブジェクトまたはオブジェクトのリスト。
状態遷移を実装する対象のオブジェクトを指定する。

### 引数: states

型は状態のリストまたは辞書。
状態遷移で使用する状態を指定する。

### 引数: transitions

型は状態のリストまたは辞書。
状態遷移を指定する。

### 引数: initial

型は文字列または `state`オブジェクト。
初期状態を指定する。

### 引数: auto_transitions

型はブール値。
`True`を指定すると、 `to_[状態名]()`という形式のトリガーが追加される。
デフォルトでは `True`。

### 引数: ordered_transitions

型はブール値またはリスト。
`True` を指定すると、状態をリスト順に遷移させるための `next_state()` が追加される。

### 引数: before_state_change

型は関数または関数のリスト。
すべての状態遷移が実行される前に呼び出されるコールバック関数を指定する。

### 引数: after_state_change

型は関数または関数のリスト。
すべての状態遷移が実行された後に呼び出されるコールバック関数を指定する。

### 引数: **send_event**

型はブール値。
`True`に設定すると、トリガーが呼び出されたときに`EventData`オブジェクトが関数に渡される。
このオブジェクトには、トリガー名、ソース状態、遷移先状態、`model`などの情報が含まれる。

### 引数: prepare_event

型は関数または関数のリスト。
イベント処理の準備として、遷移が実行される前に呼び出されるコールバック関数を指定する。

### 引数: finalize_event

型は関数または関数のリスト。
イベント処理の完了として、遷移が実行された後に呼び出されるコールバック関数を指定する。

### 引数: ignore_invalid_triggers

無効なトリガーが呼び出された場合に、エラーを発生させずに無視するかどうかを指定する。
`True`に設定すると、無効なトリガーはエラーを発生させず、無視される。
サーバーサイドからのリクエストでCORSエラーを回避する方法

# はじめに
ウェブ開発において、異なるオリジン間でのデータのやり取りは一般的ですが、クロスオリジンリクエストに関連するCORS（クロスオリジンリソース共有）エラーに悩まされることがあります。この記事では、Next.jsを用いてサーバーサイドからリクエストを送ることでCORSエラーを回避する方法を紹介します。

# CORSとは
CORS（クロスオリジンリソース共有）は、ウェブブラウザが異なるオリジン（ドメイン、ポート、またはプロトコル）からのリクエストを制限するセキュリティ機能です。クライアントサイドからサーバーにリクエストを送信する際、Chromeなどのブラウザはサーバーからのレスポンスに`Access-Control-Allow-Origin`ヘッダーが含まれているかどうかをチェックします。もし、このヘッダーが存在しないか、リクエスト元のオリジンが許可されていない場合、CORSエラーが発生し、リクエストはブロックされます。

# 参考にしたもの
https://web.dev/articles/cross-origin-resource-sharing?utm_source=devtools&hl=ja#preflight-requests-for-complex-http-calls

## ブラウザからサーバーにアクセスすると
### ステップ 1: クライアント（ブラウザ）リクエスト
ブラウザがクロスオリジンリクエストを行うと、ブラウザは`Origin`ヘッダーを現在のオリジン（スキーム、ホスト、ポート）とともに追加します。

### ステップ 2: サーバーレスポンス
サーバーがこのヘッダーを確認し、アクセスを許可すると、リクエスト元のオリジンを指定する`Access-Control-Allow-Origin`ヘッダーをレスポンスに追加します（または、任意のオリジンを許可する場合は`*`）。

### ステップ 3: ブラウザがレスポンスを受信する
ブラウザは、適切な`Access-Control-Allow-Origin`ヘッダーを含むこのレスポンスを確認すると、レスポンスデータをクライアントサイトと共有します。

# 問題が発生した事例
今回は、環境省のウェブサイトからCSVデータを取得しようとした際に、クライアントサイドでCORSエラーが発生しました。おそらく、環境省のサーバーが`Access-Control-Allow-Origin`ヘッダーを含めていなかったため、ブラウザがリクエストを拒否したと思われます。



### 環境省 暑さ指数(WBGT)予測値等 電子情報提供サービス
https://www.wbgt.env.go.jp/data_service.php

# 対応方法
Next.jsのサーバーサイドから環境省のウェブサイトにリクエストすることにしました。Next.jsなどのサーバーサイド環境からリクエストを送る場合、ブラウザのCORSチェックが適用されません。これにより、環境省のサーバーが`Access-Control-Allow-Origin`ヘッダーを含んでいなくても、問題なくデータを取得できます。

# ファイル構成
```
my-next-app/
├── package.json
├── tsconfig.json
├── next.config.js
├── src/
│   ├── pages/
│   │   ├── index.tsx
│   │   └── api/
│   │       └── wbgt.ts //サーバーサイドからのリクエスト用ファイル
└── (その他の設定ファイルやディレクトリ)

```

# サーバーサイドからのリクエスト
```src/pages/api/wbgt.ts
import axios from 'axios'

export default async function handler(req: any, res: any) {
  const AREA_CODE = '44132' // 東京の地点コード

  try {
    const response = await axios.get(
      `https://www.wbgt.env.go.jp/prev15WG/dl/yohou_${AREA_CODE}.csv`,
    )
    const data = response.data

    res.status(200).json({ data })
  } catch (error) {
    console.error('CSVデータの取得に失敗しました', error)
    res.status(500).json({ error: 'CSVデータの取得に失敗しました' })
  }
}
```
## 参考　API Routeについて
https://nextjs.org/docs/pages/building-your-application/routing/api-routes

# クライアントサイドでの利用
```src/pages/index.tsx
import { useEffect, useState } from 'react'
import axios from 'axios'

const Index = () => {
  const [data, setData] = useState(null)

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await axios.get('/api/wbgt')
        setData(response.data)
        console.log(data)  //コンソール画面に取得したdataを表示
      } catch (error) {
        console.error('データの取得に失敗しました', error)
      }
    }

    fetchData()
  }, [])

  return (
    <div>
      <h1>WBGTインデックス</h1>
    </div>
  )
}

export default Index
```
クライアントサイドでは、このAPIルートに対してリクエストを送信し、取得したコンソール画面に表示しています。

# 結論
ブラウザのCORS制約は、クライアントサイドのセキュリティを強化するための重要な機能ですが、開発中にエラーを引き起こすことがあります。Next.jsなどのサーバーサイドでのリクエストを利用することで、これらの制約を回避し、安全にデータを取得する方法を紹介しました。
デバグと望遠鏡


画面に向かい続けても解けなかったバグが、ぶらぶらと歩いていると、ふとその原因が分かることがある。

これは、リラックスして全体を俯瞰的に考えることで、集中しているときに見えなかったバグの原因が見えてくるからだ。

画面と睨めっこするのは、望遠鏡を覗いているようなものだ。
望遠鏡は遠くのものを観察するには非常に便利だが、近くのものや周りを捉えることはできない。

探し物が見つからないときは、望遠鏡を一度置き、広がる景色を直接目で見渡してみると、案外すぐに見つかるかもしれない。
【Flutter】依存パッケージのエラーを自力で修正する

## 今回の背景
Flutterで自作したアプリの Android Gradle Plugin (AGP) を最新のバージョンに更新しようと思い、7.x.x から 8.x.x にアップデートしました。すると、使用しているパッケージの`sound_mode`にて以下のエラーが発生し、アプリのビルドが通らなくなりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/985195/cc6f993f-eff6-df71-0077-953a2db4884f.png)
```
Namespace not specified. Specify a namespace in the module's build file:
```

自分のアプリ内でビルドエラーが発生している場合、通常は build.gradle に namespace を追加することで解決できます。しかし、今回のケースではパッケージ側のソースコードまで遡って修正する必要がありました。
```groovy:android/build.gradle
android {
    namespace 'com.example.myapplication'
}
```

`sound_mode`パッケージは、pub.devで確認したところ8ヶ月以上更新がされておらず、こちらの対応が行われていません。代替できそうなライブラリが無かったこともあり、今回はパッケージ側のソースコードを自分で修正しました。
この記事では、他パッケージでも応用可能な知見として手順をご紹介します。

## パッケージ側のソースコードを修正する
まず、修正したいパッケージのGitHubリポジトリに移動し、forkします。[^1]

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/985195/139d9206-2331-ca2f-082c-70c3a2e6d81f.png)

次に、forkしたリポジトリをローカル環境にclone & 実行し、修正を行います。
（今回の場合は、`android/build.gradle`に`namespace`を追加しています）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/985195/19e14e94-20a1-0517-76d0-9b488a39ed77.png)

変更をcommit & pushします。また、forkしたリポジトリのURLをコピーしておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/985195/99a1e302-b7fe-91a7-f3bc-ec2999fe1dee.png)

最後に、`pubspec.yaml`を以下のように置き換えます。`url`には先ほどコピーしたGitHubのリポジトリのURLを貼り付けます。
```diff_yaml:(旧) pubspec.yaml
- sound_mode: ^3.0.0
```
```yaml:(新) pubspec.yaml
sound_mode:
  git:
    url: https://github.com/sakusaku3939/sound_mode.git
```

以上の手順により、自分でカスタマイズしたパッケージを使用することができるようになります。`url`の下に`ref`を置くことで、対象のブランチ名やコミットIDを指定することも可能です。

また、forkした後の変更点はそのままプルリクエストとして投げる事が可能なので、余裕があればOSSのコントリビューターとしてぜひ貢献してみましょう。もし開発が放置されていてmergeが行われない場合でも、他のユーザーがプルリクエストのfork先URLを`pubspec.yaml`に指定して利用できるようになります。

## あとがき
書きながら調べていたところ、今回のパッケージ側のnamespace問題は`build.gradle`に以下のコードを追加することで解決できたようです。。下調べが足りない
```groovy:android/build.gradle
subprojects {
    afterEvaluate { project ->
        if (project.hasProperty('android')) {
            project.android {
                if (namespace == null) {
                    namespace project.group
                }
            }
        }
    }
}
```

[^1]: `git clone`をした後に自分のリポジトリに上げることでも同様に可能
【AtCoder】幅優先探索（BFS）

## シンプルBFS

例題：[ABC007C - 幅優先探索](https://atcoder.jp/contests/abc007/tasks/abc007_3)

```C++
#include <bits/stdc++.h>
using namespace std;
using vi = vector<int>;
using vs = vector<string>;
using P = pair<int, int>;
#define rep(i, n) for (int i = 0; i < (n); i++)

const vi dy = { -1, 0, 1, 0 };
const vi dx = { 0, 1, 0, -1 };

int main() {
  int H, W; cin >> H >> W;
  int sy, sx, gy, gx;
  cin >> sy >> sx >> gy >> gx;
  sy--; sx--; gy--; gx--;
  vs C(H); rep(i, H) cin >> C[i];
  
  vector<vi> dist(H, vi(W, -1));
  queue<P> q;
  q.emplace(sy, sx); dist[sy][sx] = 0;
  while (!q.empty()) {
    auto [y, x] = q.front();
    q.pop();
    rep(k, 4) {
      int ny = y + dy[k], nx = x + dx[k];
      if (C[ny][nx] == '#') continue;
      if (dist[ny][nx] != -1) continue;
      
      q.emplace(ny, nx); dist[ny][nx] = dist[y][x] + 1;
    }
  }
  
  cout << dist[gy][gx] << endl;
}
```

## ダイクストラ法

例題１：[ABC340D - Super Takahashi Bros.](https://atcoder.jp/contests/abc340/tasks/abc340_d)

```C++
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using vi = vector<int>;
using P = pair<ll, int>;
#define rep(i, n) for (int i = 0; i < (n); i++)

int main() {
  int N; cin >> N;
  vi A(N-1), B(N-1), X(N-1);
  rep(i, N-1) {
    cin >> A[i] >> B[i] >> X[i];
    X[i]--;
  }
  
  vector<ll> cost(N, -1);
  priority_queue<P, vector<P>, greater<P>> pq;
  pq.emplace(0, 0);
  while (!pq.empty()) {
    auto [c, pos] = pq.top();
    pq.pop();
    if (cost[pos] != -1) continue;
    cost[pos] = c;
    if (pos == N - 1) break;
    int npos1 = pos + 1, npos2 = X[pos];
    if (cost[npos1] == -1) pq.emplace(c + A[pos], npos1);
    if (cost[npos2] == -1) pq.emplace(c + B[pos], npos2);
  }
  
  cout << cost[N-1] << endl;
}
```

類題：[ABC362D - Shortest Path 3](https://atcoder.jp/contests/abc362/tasks/abc362_d)


<br>

例題２：[典型90問043 - Maze Challenge with Lack of Sleep（★4）](https://atcoder.jp/contests/typical90/tasks/typical90_aq)

下記はdequeで実装しているが、構造体同士の比較演算を定義すればpriority_queueでも実装できる。

```C++
#include <bits/stdc++.h>
using namespace std;
using vi = vector<int>;
using vs = vector<string>;
#define rep(i, n) for (int i = 0; i < (n); ++i)

const int INF = 1001001001;
const vi dx = { -1, 0, 1, 0 };
const vi dy = { 0, 1, 0, -1 };

struct State { int x, y, dir; };

int main() {
  int H, W; cin >> H >> W;
  int sx, sy, gx, gy;
  cin >> sx >> sy >> gx >> gy;
  sx--; sy--; gx--; gy--;
  vs S(H); rep(i, H) cin >> S[i];
  
  vector<vector<vi>> cnt(H, vector<vi>(W, vi(4, INF)));
  deque<State> dq;
  rep(k, 4) { cnt[sx][sy][k] = 0; dq.push_back({ sx, sy, k }); }
  while (!dq.empty()) {
    State t = dq.front();
    dq.pop_front();
    rep(k, 4) {
      int nx = t.x + dx[k], ny = t.y + dy[k], cost = cnt[t.x][t.y][t.dir] + (t.dir == k ? 0 : 1);
      if (nx >= 0 && nx < H && ny >= 0 && ny < W && S[nx][ny] == '.' && cost < cnt[nx][ny][k]) {
        cnt[nx][ny][k] = cost;
        if (t.dir == k) dq.push_front({ nx, ny, k });
        else dq.push_back({ nx, ny, k });
      }
    }
  }
  
  int ans = INF;
  rep(k, 4) ans = min(ans, cnt[gx][gy][k]);
  cout << ans << endl;
}
```
週1　アウトプット宣言

はじめに

はじめまして『あさひ』とと言います。
先日、友人よりアウトプットすることの重要性とその薦めを受け、
私もチャレンジしてみようかと思った次第です。
差し当たって、1ヶ月、約5つの記事を、その週にインプットした勉強内容や私のプライベートで起こった事等、
皆様に共有できたらと考えています。

いままでのわたし

不動産営業として仕事をしていましたが体調を崩し、ながらく仕事をしていない期間がありました。
今は和歌山という国に出稼ぎに来ており、平日は工場で、週末は不動産の営業補佐として仕事をしており、
余った時間を勉強したり、本読んだりとのんびり生活しています。

保有している資格

・宅地建物取引士　
・管理業務主任者　試験合格
・マンション管理士　試験合格
・2級ボイラー技士　試験合格
・FP2級
・簿記3級　etc

基本的には不動産にまつわる資格の勉強をしてきまして、IT系の資格チャレンジは
今、勉強している『CCNA』が初めてです。今までは『受かるための勉強』で試験合格してきましたが
現在お世話になっている、youtubeコミュニティ『まさるの勉強部屋』を運営されているまさるさんから
実践を意識した勉強が大事と教えていただき、目下勉強スタイルの確立もめざしています。

https://www.youtube.com/watch?v=UFhpatADJ-s&list=PLfrpqyRFsglLIZ38E6ih11nEQZjNGgbVN&index=1&t=1s

おわりに

今回の週1アウトプット企画を通じて、
・自分の1週間に勉強した内容の可視化
・インプットした知識の整理・定着
・勉強した内容を他人にうまく説明できるようにすること

この3点を目標にしていきます。
皆様からの反応も私のモチベーションにつながりますので、ぜひよろしくお願いします

では、これから頑張っていきます～
AtCoder 勉強記録[C++] その51

AtCoderで入茶を目指して勉強しています。
勉強を継続するために投稿を始めました。
もともとアカウントを作成していましたが、今年の4月から本格的に勉強を始めました。
一応自分用に解法を書いていますが雑です、自分で読み返して困ったら修正します。
[私のアカウント](https://atcoder.jp/users/nanami_brother)
[解いた問題](https://kenkoooo.com/atcoder/#/table/nanami_brother)
# 本日解いた問題
## B - First Query Problem
[B - First Query Problem](https://atcoder.jp/contests/abc283/tasks/abc283_b)
解答
```c++

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using vec = vector<int>;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)

int main() {
  ll n;
  cin >> n;
  vec a(n);
  rep(i, n) cin >> a[i];
  ll q;
  cin >> q;
  for(int i = 0; i < q; i++){
    ll num, k, x;
    cin >> num;
    if(num == 1){
      cin >> k >> x;
      a[k-1] = x;
    } else {
      cin >> k;
      cout << a[k-1] << endl;
    }
  }
}
```
### 解法
クエリ1、2ごとに処理を分けて実行する。クエリ1の場合は`A[k]`の値を`x`に変更し、クエリ2の場合は`A[k]`を出力する。
## B - Multi Test Cases
[B - Multi Test Cases](https://atcoder.jp/contests/abc284/tasks/abc284_b)
解答
```c++
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using vec = vector<int>;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)

int main() {
  ll t;
  cin >> t;
  vec res(t);
  for(int i = 0; i < t; i++){
    ll a;
    ll n;
    cin >> n;
    for(int j = 0; j < n; j++){
      cin >> a;
      if(a%2!=0) res[i]++;
    }
    cout << res[i] << endl;
  }
}
```
### 解法
`T`個のテストごとに`N`回のループを回し、奇数の個数を数えることで結果が求まる。
GStreamerを使って映像や音声を送信するFPVアプリを作りたい

この記事からの続きです

https://qiita.com/hexaforce/items/3c59ae06c334e9dc326a

プログラムを書いているうちに、出来ることとやりたい事がいろいろとゴチャゴチャしてきて一応それなりのものが出来ました。

![Screenshot0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117164/a4dd3c28-2d97-c32b-31ad-8dce4998b2e9.png)


ソースコードはこちらにあります。
https://github.com/hexaforce/QStreamFPV
![Screenshot1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117164/a70db918-79af-c2c1-35be-1c2b260e8e47.png)

次の、課題としてBetaflightやiNavFlight、Ardupilotなどが搭載されたフライトコントローラからフライトログを受け取って画面に表示したいと思います。

理想的なものとしてBetaflight の Blackbox Explorerみたいなものを想定していますが出来るのか未知の領域です。
Mavlinkを使っていろいろパラメータは取得出来ますがGPSのデータを表示するところを目標にしています。
まずは調査から。。。
ダッシュカムをインストールするために必要なツール

ダッシュカムを車に取り付ける際、適切なツールと準備が不可欠です。この記事では、ダッシュカムの取り付けに必要な基本的なツールや、その使用方法について詳しく説明します。初めてダッシュカムをインストールする方でも、必要なツールを揃えておけばスムーズに作業を進めることができるでしょう。

インストール前の準備
ツールの選定
ダッシュカムをインストールする際に使用するツールは、作業の効率や仕上がりに大きく影響します。基本的には以下のツールが必要です。

ドライバーセット：ダッシュカムの取り付けには、車内のパネルやネジを外すためのドライバーが必要です。様々なサイズのドライバーを用意しておくと便利です。
ワイヤーストリッパー：電源ケーブルの皮をむくために使用します。適切にケーブルを処理することで、確実な接続が可能となります。
配線用のピンセット：細かい配線作業を行う際に便利なツールです。特に狭い場所での作業に役立ちます。
準備と計画
ツールを揃えたら、次に作業手順を確認します。ダッシュカムの取り付け位置や配線のルートを事前に決めておくことで、作業がスムーズに進みます。また、必要に応じて車両のマニュアルを確認し、どの部分を外す必要があるかを把握しておくと良いでしょう。

ダッシュカムの取り付け手順
ダッシュカムの位置決定
ダッシュカムを取り付ける位置を決めることは、撮影範囲や安全性に大きく影響します。フロントガラスの中央上部が一般的な取り付け場所ですが、車種によっては調整が必要です。取り付ける位置が決まったら、付属の吸盤や接着シールを使用してカメラを固定します。

詳しくはウェブサイト<a href="https://www.dashcaminstallation.com.au/">dashcaminstallation.com.au/</a>。

電源の確保
ダッシュカムは車の電源に接続する必要があります。多くの場合、シガーソケットに差し込む方法が簡単で一般的ですが、より専門的な設置ではヒューズボックスから直接電源を取る方法もあります。ワイヤーストリッパーを使用して電源ケーブルを適切に処理し、確実に接続します。

配線の整理
配線は車内にしっかりと隠して整理することが重要です。配線用のピンセットや結束バンドを使用して、配線が目立たないように処理します。また、配線が緩まないようにしっかりと固定することが必要です。

インストール後の確認
動作確認
取り付けが完了したら、ダッシュカムの動作確認を行います。電源が正常に供給されているか、カメラの角度が適切か、録画が正しく行われているかを確認します。また、GPSやWi-Fiなどの追加機能がある場合は、それらの動作も確認しましょう。

メンテナンスと調整
ダッシュカムは一度取り付けたら終わりではなく、定期的なメンテナンスと調整が必要です。特に季節の変わり目や長距離ドライブの前後には、カメラの取り付け状態や配線の緩みがないかをチェックしましょう。

オーストラリアでダッシュカムを使用する際の法的側面については、<a href=https://www.dashcaminstallation.com.au/dash-cam-installation-and-the-law-what-you-need-to-know-as-an-australian-driver/>Dash Cam Laws</a>（ダッシュカムに関する法律）をご覧ください。

まとめ
ダッシュカムをインストールする際には、適切なツールと事前の準備が重要です。基本的なツールを揃え、取り付け手順をしっかりと把握しておけば、初めての方でもスムーズに作業を進めることができます。定期的なメンテナンスを行うことで、ダッシュカムの機能を長く保つことができるでしょう。
cslを微修正する(引用文献のcitationに閉じ丸括弧をつける)

# 概要
cslを微修正したくなった。
具体的には、ほぼamerican-medical-association.cslのままで良いが、citationをただの上付き文字ではなくて、上付き文字＋")"(とじかっこ)にしたかった。

# 環境
Mac
pandoc (latex -> word)

# 内容
cslを以下のように編集した。
(citationの中のlayout)
```xml:修正前
    <layout delimiter="," vertical-align="sup">
      <text variable="citation-number"/>
      <group prefix="(" suffix=")">
        <label variable="locator" form="short" strip-periods="true"/>
        <text variable="locator"/>
      </group>
    </layout>
```

```xml:修正後
    <layout delimiter="," vertical-align="sup">
      <text variable="citation-number" suffix=")"/>
      <group prefix="(" suffix=")">
        <label variable="locator" form="short" strip-periods="true"/>
        <text variable="locator"/>
      </group>
    </layout>
```

# 感想
汎用性は微妙だが、ひとまず想定通りに修正された。
炎上プロジェクトの真の課題を捉える

### はじめに
この記事では、具体的な事例を交えながら、プロジェクト管理の難しさと対策について、私の学んだポイントを書きます。
ウォーターフォール開発であっても、アジャイル開発であっても中規模以上のプロジェクトであれば当てはまる内容だと考えています。私自身、SIer企業で10年以上にわたり、中規模から大規模（数億円規模、期間1〜3年）のプロジェクトを多く経験しており、その経験を基にしています。

### 炎上プロジェクトに出会ったことはありますか？
「炎上プロジェクト」とは、計画通りに進行せず、様々な問題が絡み合い、プロジェクト全体が危機的状況に陥ることを指します。よくある検知ポイントとしては、QCD（Quality, Cost, Delivery）における問題が表面化し、「このままではまずいのでは？」という声が上がるケースです。私はこのようなプロジェクトの炎上解消に途中参画することがいままで何度かありました。

- Quality：期待する品質（バグの少なさ、機能の正確性、使いやすさ、パフォーマンス）に達していない
- Cost：計画したコストより超過する見込み
- Delivery：計画した納期が達成できない見込み

これらの問題は、できるだけ早い段階で「何か手を打たなければ」という危機感を持つことが望ましいのですが、現場は日々の業務に追われ、課題が蓄積・複雑化していることに気づきにくいことが多いです。

### 炎上するにはたくさんの課題が
例えば、3日でリカバリできる1つの課題なら、対処はそれほど難しくありません。しかし、3日でリカバリできる課題が10個あり、それらが複雑に絡み合うと、対処には1ヶ月以上の時間が必要になります。さらに、それらの課題が放置され続けると、何が問題なのかさえも分からなくなり、メンバーが身動きできなくなる状況に陥ります。

顧客からのプレッシャーが増す中で、進捗を優先し、目の前のタスクをこなすことに集中してしまいがちです。しかし、こうした状況が続くと、リーダー層も状況を把握しにくくなり、メンバー間での情報共有が滞ることで、プロジェクト全体がさらに悪化する負のループに陥ってしまいます。
　
あなたは、このような状況の経験はありますか。

### 小さな課題は真の課題から派生する
炎上プロジェクトに直面した際には、現場をじっくりと観察し、考えられる課題をすべて書き出します。
実は、多くの小さな課題は、**根本的な課題から派生**していることが多いです。一つの課題を解決すると、他の課題も連鎖的に解決することがあります。
　
そして、その真の課題を捉えて、それが**どう変わるとプロジェクトにとって（もしくは自分にとって）最高の理想状態かを描いてみるというところも大事**です。
その課題は根深い課題なので、なかなか解決はしないかもしれませんが、回避したり、軽減したり、受容を促したり変化を起こす何かを実験を試すことができます。


### 幸せなシステム開発にするために
最後に、より幸せなシステム開発を実現するために私が大事だと思う3つのポイントを紹介します。

- **課題状況を可視化する**
プロジェクト外の人が状況をぱっと理解できる程度に、課題状況を可視化していることが重要と考えています。
何が課題かが整理され、理想の状態は何かを描けたら７割は解決しています。あとはその課題を全員で認識し、一つ一つやれることをやっていくだけです。
　
- **情報をフラットに全員がもつ**
みんながやれることをやっていくには、フラットに全員が同じ情報をもっている必要があります。リーダ層しか開示されていない情報は限りなく減らし、誰もが非同期で情報にアクセスできることが大切です。そのためには、適切なコミュニュケーションツールや仕組みの整備が求められます。
　
- **「助けて」と声を上げる力**
時にはスキルやパワーがプロジェクト内で足りない、アイディアもでてこないというときに、どうしようもないということではなく、助けて助けてと周りに騒ぐことも重要だと考えています。ヘルプを出すにもパワーがいるのでその体力も残した状態で騒ぐことが大事です。第三者のフラットな視点からみると、思っているよりとても簡単なことかもしれないし、新たな視点を得られるかもしれないです。「一人で抱え込まず、周りに助けを求める」スキルは常に意識していきたいです。


### おわりに
この記事で紹介した内容は、私自身もまだ全て実践できているわけではありません。一人でできることは限られており、システム開発は多くの人々が集まり、みんなの力が一つにまとまって作り上げていくシステム開発って本当にすごいことをやっているんだなと改めて思います。その現場が山あり谷ありありつつも、少しでも幸せな場所にしたいと、心から願っており、(綺麗事に聞こえると思いますが(笑)、一緒に働く仲間が、私自身が少しでも楽しくハッピーに仕事にできる場を作りたいです。)その場を作れる一人として邁進していきたいと思います。

読んでいただいた方に、この経験が少しでも役立てば幸いです。
他にもこのようなテーマで投稿予定です。またよかったらぜひ読んでください。
https://qiita.com/nanchan/items/232e1fe9015a4f6e0bf0