OmniAICreator/Qiita-1.07M huggingface dataset:
万が一、microk8sを壊してしまったら

### まずは状況確認

```sh
microk8s kubectl get nodes -o wide
```

### 間違ってadd-nodeした場合など (全データー吹っ飛んだと思ったら)

/var/snap/microk8s/current/var/kubernetes/backend.backup/
    
に過去のログが残っているので

```sh
cp -r /var/snap/microk8s/current/var/kubernetes/backend.backup ~/backup-xxx
mv /var/snap/microk8s/current/var/kubernetes/backend/ ~/backup-yyy
mv /var/snap/microk8s/current/var/kubernetes/backend.backup /var/snap/microk8s/current/var/kubernetes/backend
```

で治る

### 正しくadd-node / leave しよう

drainで実行しているタスクを移す
それからnodeを外す
leave, joinはマスターではなくクライアント側で実行すること
以下交互に実行する
(必要ならmicrok8s addonもdisable, enableしてもよい)

```sh
# If corrupted
microk8s kubectl drain targetpc --ignore-daemonsets
```

```sh
microk8s leave
```

```sh
microk8s remove-node targetpc --force

microk8s add-node
```

```sh
#On *clinet* For example
microk8s join 192.168.0.1:25000/xxxxxx/1234 --worker
```

参考
[Kubernetes道場 21日目 - Cordon / Drain / PodDisruptionBudgetについて](https://cstoku.dev/posts/2018/k8sdojo-21/)
    
[How to drain a node and restart it?](https://discuss.kubernetes.io/t/how-to-drain-a-node-and-restart-it/16331)

[microk8sクラスターのノードを再起動する](https://blog.ouvill.net/blog/2023-01-16-reboot-microk8s-node/microk8s%E3%81%AE%E3%83%8E%E3%83%BC%E3%83%89%E3%82%92%E5%86%8D%E8%B5%B7%E5%8B%95%E3%81%99%E3%82%8B/)
【Qiita使い方メモ】`**太字**`以外で文字を太字にする方法

Qiitaのフェスに間に合うようにアカウントを登録しようと思ったらもう投稿期間は終わっていた。やってしまった。

---

Qiitaを学習メモにしようと思っていて、チートシートや書き方の検索していたらとても興味深いコメントを見つけた。

https://qiita.com/TETSURO1999/items/fe3675f11ae05f412520#comment-7c05efaa02e9bc8142bb

```
$\pmb{\textsf{\\pmb なら日本語のゴシック体でも一応太字っぽくできます。}} $
```

$\pmb{\textsf{本当に太字っぽくなった…なんだこれ。}} $

お行儀は確かに悪いが自分が使う分にはありだと思った。こういう情報を残してくれる方を見ると、自分の書いたメモもいつかこういう風に誰かの役に立つかもしれないのでモチベーションが上がる。
【Python】turtleで図形描いてみた

# 本日のブログ内容
今日はPythonでいろんな図形を描いてみたのでコードと描いてみた図形を記録として残そうと思います。

## 三角形
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2759758/467cdf26-ea7a-6a41-4be3-963766d1e8b5.png)

### 実際のコード
```python
turtle.color('red', 'yellow')
turtle.begin_fill() # 線の色
for i in range(3):
    turtle.forward(100)
    turtle.left(360 / 3) # 左に3回曲がる
turtle.done()
```
## 四角形
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2759758/966c6fa9-67df-9f28-fe61-dc6223cfa2c4.png)

### 実際のコード
```python
turtle.color('red', 'yellow')
turtle.begin_fill() # 線の色
for i in range(4):
    turtle.forward(100)
    turtle.left(360 / 4) # 左に四回曲がる。
turtle.done()
```

## 星
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2759758/fdfe34fb-0d48-0495-baae-842758d9975e.png)

### 実際のコード
```python
turtle.color('black', 'yellow')
turtle.begin_fill() # 線の色
for _ in range(5):
    turtle.forward(200)
    turtle.right(360 / 5 * 2)
turtle.end_fill() # 囲まれ中の色
turtle.done()
```

## 星（ver2.0）
![Untitled (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2759758/0dfb0229-4743-2bdf-36f9-19e12700a30d.png)

### 実際のコード
```python
turtle.color('black', 'yellow')
turtle.begin_fill() # 線の色
for _ in range(7):
    turtle.forward(200)
    turtle.right(360 / 5 * 2 + 10)
turtle.end_fill() # 囲まれ中の色
turtle.done()
```

## 六角形
![Untitled (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2759758/daab7cf1-f540-5fe6-a1bf-7cbf6b4bbcbf.png)

### 実際のコード
```python
turtle.color('red', 'yellow')
turtle.begin_fill() # 線の色
for i in range(6 * 10):
    turtle.forward(100)
    turtle.fd(i)
    turtle.right(360 / 6)
turtle.done()
```

## 薔薇？
![Untitled (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2759758/85526148-aa4e-d324-9781-6cdd7c0dc9f5.png)

### 実際のコード
```python
turtle.color('black', 'red')
turtle.begin_fill()
for i in range(200):
    turtle.fd(i)
    turtle.left(360 / 4 + 10)
turtle.end_fill()
turtle.done()
```
アンリーダブルコード

## はじめに

アンリーダブルコード。
人には読めないけどコンピューターには読める奇跡のコード。
しばしば技術的負債と呼ばれ、リファクタリングすべきかどうかの議論がXなどを騒がせる。

人が書いているのに人には読めないコード。
なぜそのようなコードが生まれるのでしょう。

## 長くてまとまりがない話ってどうですか？

長くてまとまりがない話、どう思いますか？
その話を何度も聞かされることになったら、どう思いますか？

『長くてまとまりのない関数。』
『粒度の異なる脈絡のない処理がバラバラと書かれた関数。』
『あちこちからコピペしてきたのかチグハグなコメントや処理。』
『実際の処理と名称が全く異なる関数。』

コンピューター相手なら、平気で書けちゃいますね。
人間相手なら、途中で分からなそうな顔をしたり次回から話を聞いてくれなくなったりもしますが、コンピューター相手だと、それがないです。

もっと人間にとっては分かりやすいコードが存在していても、コンピューターは文法的にエラーが無い限りは黙って動きます。

構造的に『「人間が理解しやすいコード」ではないとコンピューターも動かない』、という状況にならない限りはアンリーダブルなコードが生まれてしまいそうです。

## 構成力・整理力・文章力

「人間が理解しやすいコード」は、分かりやすい日本語をプログラムに翻訳したものです。
分かりやすいプログラムを書くには構成力・整理力・文章力が必要ということになります。

理路整然と要点をまとめて、主語や述語を省略せずに話をトピック事に区切って伝える。
これができるだけで大分分かりやすいプログラムが書ける様になるのではないかと思います。

プログラミングは日本語で書かれた設計を、コンピューターの分かる言語に翻訳する仕事ですので。

わたし達は、日本語なら自由自在に使いこなせると思いがちですが、実はそうではないです。
Line等で短文のやり取りをするぐらいで、まとまった文章を書く機会がほとんどないので、構成力・整理力・文章力がないことは普通のことかと思います。不便なことに、人間は使わない能力が衰える様にできているので。

本屋に構成力・整理力・文章力をカイゼンするための書籍がたくさん並んでいることからも『できるようになりたい人』が一定数いると分かります。

それらの本を読めば翌日にはカイゼンしているかというとそんなことはないです。
**ダイエット本を読んでも翌日に痩せてはいない**のと同じです。
抽象化された法則やルールはシンプルですが、具体化して使いこなすには実践の反復が必要なのです。
本を読んで、法則やルールを覚えて、何らかのアウトプットをすることで実践の反復を行わないとカイゼンしません。

## リーダブルコード

文章力がついてきたら、コードをリーダブルにする訓練をしたいところです。
こちらも当然、読んだ**だけ**では効果がなく、年単位での実践の反復が必要かと思います。

以下に、ありがたい要約がありましたので添付しておきます。

https://qiita.com/AKB428/items/20e81ccc8d9998b5535d

## おわりに

今回は構造的にアンリーダブルなコードが書かれるケースについて考察をしました。[^1]
リーダブルなコードを書くには、今自分が書いているコードが「**どのようなものか**」の把握、カイゼンに向けての法則やルールの学習、および学習したことを定着させるための反復が必要かと思いました。

## おまけ

- [kaku3 - Qiita記事一覧](https://kaku3.github.io/workbooks/Qiita/)
ポエム多め。PM、メンター、未経験エンジニアや新卒向け記事など。

- [エンジニアのためのお仕事問題集](https://github.com/kaku3/workbooks)
2030年にIT人材が最大79万人不足するとのことで、学習用の資料をgitで無料公開してます(不定期更新)。

よろしければどうぞ。

[^1]: リリース優先、プロト、フィジビリなどのコードは考察外
文字列収集 (paizaランク S 相当)　Python解説

# 自己紹介
大阪大学2回生で競技プログラミング部rainbou副部長、Atcoder緑
X:https://x.com/e4h99rhQ7I24670

# 問題文　文字列収集 (paizaランク S 相当)　URL
https://paiza.jp/works/mondai/real_event/word_collection

# 所感
初見問題として解くのはかなり難しいと思う。
AtcoderだとC問題くらいでdiff600程度だと予想（ざる予想）

# 解法
文字列ソート、累積和、二分探索を使う。
まず、文字列と数字のペアを文字列でソートする。順番は文字列が最初に与えられるのできにせずにいつものようにソートすればよい。
次にそのリストの累積和を作っておく。itertoolsでも累積和を作れるという話を聞いたことがあるが、僕は知らないので手作業で作っていく。
あとは、M個のクエリが飛んでくるたびに二分探索を２回して買う必要のある範囲を絞っていく。
ここがボトルネックとなり計算量はO（MNlogN）
必要な範囲が求められれば、あとは先ほど作っておいた累積和をてきとうに出力しておしまい。
```python
import bisect

N, M = map(int, input().split())
A = [list(map(str, input().split())) for _ in range(N)]
S = [0]
A.sort()

for i in range(N):
    A[i][1] = int(A[i][1])
    S.append(S[-1]+A[i][1])


for i in range(M):
    q = input()
    l = bisect.bisect_left(A, [q, -1])
    r = bisect.bisect_right(A, [q+'{', 0])

    print(S[r]-S[l])
```

# 以下雑談
paizaではbisectは使えるらしい。
はやいとこsortedcountainersも使えるようにしてほしい。現在は200行くらいコードべたばりしなければ使えない。悲しい。
rails console -e test

# テスト環境のコンソールを使えるようにする
```
rails console -e test
```
テスト環境のデータベースにレコードを生成したりすることができた。

# 出典
https://teratail.com/questions/289185#:~:text=1-,rails%20c%20%2De%20test,-%E3%81%A7%E8%A9%A6%E3%81%97%E3%81%A6

https://railsdoc.com/page/rails_console

# 感想
railsのドキュメントに書いてあったけどできなかった。
バージョンが違うからなのかはわからないができてよかった。
Qiita Cli コマンド備忘録

# 事前準備

node.jsのインストール

バージョン管理がめんどくさい人は最新をダウンロード

https://nodejs.org/en/download/package-manager


セットアップ関係、コマンド関係は以下のgithubを参照

https://github.com/increments/qiita-cli?tab=readme-ov-file#%E8%A8%98%E4%BA%8B%E3%81%AE%E4%BD%9C%E6%88%90

# 記事の作成

npx qiita new 記事のファイルのベース名

# 記事の投稿・更新

npx qiita publish 記事のファイルのベース名

# 全ての記事を投稿・更新

npx qiita publish --all

# github actionsが動くはず

上記のコマンド以外でも cliがきちんと機能していれば

/.github/workflows/publish.yml

上記のファイルができているはずなのでgithub actionsが動くはずです


元々githubで管理していましたが毎回投稿作業がめんどくさかったので導入できてとても楽でした
Kaggle Masterに学ぶ機械学習実践アプローチ 写経 01

```python 
# %%
print("hello")

# %%
import matplotlib.pyplot as plt 
import numpy as np
import pandas as pd
import seaborn as sns
from sklearn import datasets 
from sklearn import manifold 


# %%
data = datasets.fetch_openml(
    'mnist_784',
    version=1,
    return_X_y=True
)

pixel_values, targets = data 
targets = targets.astype(int)

# %%
pixel_values

# %%
single_image = pixel_values[0:1].to_numpy().reshape(28, 28)

# %%
plt.imshow(single_image, cmap='gray')

# %%
tsne = manifold.TSNE(n_components=2, random_state=42)
transformed_data = tsne.fit_transform(pixel_values.to_numpy()[:3000, : ])

# %%
tsne_df = pd.DataFrame(
    np.column_stack((transformed_data, targets[:3000])),
    columns=["x", "y", "targets"]
)
tsne_df.loc[:, "targets"] = tsne_df.targets.astype(int)

# %%
tsne_df

# %%
grid=sns.FacetGrid(tsne_df, hue="targets")
grid.map(plt.scatter, "x", "y").add_legend()

# %%



```
PowershellでExcelを操作する（RPAもどき）

ExcelをPowershellで自動化してみたくて調べてみました。なお検証はExcel2016のみですので、その点はご了承ください。

# Excelの起動

* Excelファイル`test.xlsx`を開く場合

```powershell:
$excel = New-Object -ComObject Excel.Application
$excel.visible = $true
$file = $excel.Workbooks.Open("test.xlsx")
```

* 新規にExcelファイルを作成する場合

```powershell:
$excel = New-Object -ComObject Excel.Application
$excel.visible = $true
$file = $excel.Workbooks.Add()
```

* 既に起動されているExcelファイルを利用する場合

```Powershell:
$excel = [System.Runtime.InteropServices.Marshal]::GetActiveObject("Excel.Application")
$file = $excel.Workbooks.item(1)
```

# セルの操作

* セルにデータや式を入れる場合

下のプログラムは、シート`計算`を選択し、セル`A1`にデータ`10`を入れ、セル`B1`に式`=A1*2`を入れるものです。

```Powershell:
$sheet = $file.Worksheets.Item("計算")
$sheet.Cells(1,1) = 10
$sheet.Cells(1,2) = "=A1*2"
```

* セルのデータや式を標準出力に出す場合

下のプログラムは、シート`計算`を選択し、セル`B2`の値と式を標準出力に出しています。

```Powershell:
$sheet = $file.Worksheets.Item("計算")
Write-Host $sheet.Cells(1,2).Value()
Write-Host $sheet.Cells(1,2).Formula()
```

* セルのコピー＆ペーストを実行する場合

下のプログラムは、シート`計算`を選択し、セル`A1:B1`のデータをセル`A2:B2`に貼り付けます。

```Powershell:
$sheet = $file.Worksheets.Item("計算")
$sheet.Range("A1:B1").Copy($sheet.Range("A2:B2"))
```

# その他の機能

* マクロを実行する

マクロ`Macro1`を実行します。

```Powershell:
$excel.run("Macro1")
```

* メッセージボックスを表示する

```Powershell:
Add-Type -Assembly System.Windows.Forms
[System.Windows.Forms.MessageBox]::Show("内容","タイトル")
```

# ファイルの保存と、Excelの修了

* 保存して終了する場合

```Powershell:
$file.Save()
$file.close()
$file = $null
$excel.quit()
$excel = $null
[GC]::Collect()
```

* 名前を付けて保存して終了する場合

```Powershell:
$file.SaveAs("test2.xlsx")
$file.close()
$file = $null
$excel.quit()
$excel = $null
[GC]::Collect()
```

* 保存をしないで終了する場合

```Powershell:
$file.close()
$file = $null
$excel.quit()
$excel = $null
[GC]::Collect()
```

* ダイアログを出さない設定

上記の場合で、ダイアログが出て終了できない場合は、ダイアログを出さない設定をします。

```Powershell:
$excel.DisplayAlerts = $False
```
同一コンテナ内で２つのサーバーを起動[supervisor,nginx]

### 初めに
今回はフロントエンドとバックエンドのサービスを同一コンテナ内で２つポートを空けて作成する手順を紹介します。
それぞれの細かいコードは省きます。
大雑把な手順はフロントとバックのコードをビルドした後、
supervisodで起動してnginxでフロントをサーブする手順となっています。
[supervisordとは](http://supervisord.org/index.html)
※今回はバックエンドサーバーがGO言語で`backend`ディレクトリ、
フロントエンドがVite x Reactで`frontend`ディレクトリとなっています。

### 1.docker-compose.yaml,Dockerfileを作成
```docker-compose.yaml
version: "3"
 
services:
  your-service-name:
    build:
      context: .
      dockerfile: Dockerfile
    restart: always
    ports:
      - 8080:8080 # Goサーバーのポート
      - 5173:5173 # VitexReactのポート
```
次にDockerfileです
```Dockerfile
# Goビルド
FROM golang:1.22.5 AS backend_service
 
WORKDIR /workdir
 
COPY backend .
 
RUN CGO_ENABLED=0 go build -o app.exe .
 
# フロントビルド
FROM oven/bun:latest as frontend_service
 
WORKDIR /workdir
 
COPY frontend .
 
RUN bun install && \
    bun run build
 
# nginx導入
FROM nginx:alpine as nginx
 
COPY --from=frontend_service /workdir/dist /usr/share/nginx/html
COPY nginx/default.conf /etc/nginx/conf.d/default.conf
 
FROM ubuntu:20.04
WORKDIR /workdir
 
RUN apt-get update && \
    DEBIAN_FRONTEND=noninteractive \
    apt-get install -y \
    tzdata \
    ca-certificates \
    curl \
    supervisor \
    nginx \
    && rm -rf /var/lib/apt/lists/* \
    && cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
    && rm -rf /var/lib/apt/lists/*
 
COPY --from=frontend_service /workdir/dist /usr/share/nginx/html
COPY --from=backend_service /workdir/app.exe /workdir/app.exe
COPY --from=nginx   /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf
 
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]

```

### supervisord.confを作成
ビルドした成果物を起動させるために`supervisord.conf`を同階層に作成します。
```supervisord.conf
[supervisord]
nodaemon=true
user=root
 
[program:backend_service]
command=/workdir/app.exe
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
 
[program:frontend_service]
command=/usr/sbin/nginx -g 'daemon off;'
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
```
今回はログを標準出力にしていますが、状況に合わせてログファイルにすることもできます。
[supervisordのログについて](https://qiita.com/sugiki/items/86515393664cb5ce16ff)

### nginxを作成
最後にビルドしたファイルを配信するためにnginxの設定ファイルを作成します。
同階層にnginxディレクトリを作成後`default.conf`を作成してください
```default.conf
server {
    listen 5173;
    server_name localhost;
 
    location / {
        root /usr/share/nginx/html;
        try_files $uri $uri/ /index.html;
    }
 
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
    }
}
```

### 起動
以上の手順が終了したら、docker-compose.yamlのある階層で
`docker-compose up --build`
を入力してコンテナをビルドしてください
正常にビルドが完了したら
http://localhost:5173/
にアクセスするとフロントのindex.htmlがサーブされているはずです!
The Arch Way v2.0 和訳

:::note
本記事は次の記事の和訳です: 
https://wiki.archlinux.org/index.php?title=User:Misfit138/The_Arch_Way_v2.0&oldid=77351

Arch Linuxの原則についてまとめた非公式記事です。公式Wiki上で2009年ごろ作られましたが、最終的に [非公式扱い](https://wiki.archlinux.org/title/User_talk:Misfit138/The_Arch_Way_v2.0#Deletion/merge_request) となり放棄されました。現在は原著者のユーザページにアーカイブされています。最近改めて見直してみて、なかなか良い内容だなと思ったため和訳することにしました。

正式なArchの原則は [The Arch Linux Principles](https://wiki.archlinux.org/title/Arch_Linux#Principles) にまとめられています。
:::

# The Arch Way v2.0

## 1. シンプル

**不要な追加、変更、複雑化をしない** 

シンプルさは最も重要な原則です。デザインのシンプルさを優先し、他の原則はすべて犠牲にする必要があります。実装に関するシンプルさは、インターフェースに関するシンプルさよりも重要です。

## 2. エレガント

**シンプルさ、強さ、効率の良さ、小奇麗さ、独創的なデザインを兼ね備える**

フランスの飛行家で冒険家、作家であるサン＝テグジュペリは、エンジニアリングにおけるエレガンスを定義するのに最適な言葉を残しています:
> 「デザイナーが完璧に仕上げたことを知るのは、付け加えるものがなくなった時ではなく、取り除くものがなくなったときである。」

エレガントであることよりも、シンプルであることのほうが少し重要です。

## 3. 汎用 (Versatile)

**多くのことを十分にこなし、多様な用途や機能を持つ**

シンプルかつエレガントなシステムは大抵、汎用性も持ち合わせています。しかし、何よりもシンプルさを優先してデザインされる必要があり、そのためには汎用性も犠牲になります。
汎用性はエレガントであることほど重要ではなく、簡便さよりは重要になります。

## 4. 簡便 (Expedient)

**簡単、あるいは素早く、便利**

シンプルでエレガントかつ汎用的なシステムは、実用に際して簡便でなければなりません。しかし、他の原則を優先するためであれば犠牲にできます。実装のシンプルさが損なわれる場合は、簡便さを犠牲にします。
複雑なユーザーインターフェースによって簡便さが損なわれる場合は、余計な複雑化をせずに、その複雑さを表現する必要があります。

----

## 補足: ライセンスについて  
Arch Wikiの記事はすべて [GFDL v1.3 というライセンスに従う](https://wiki.archlinux.org/title/ArchWiki:General_disclaimer) ため、一応原著者名を含めたライセンステキストを貼っておきます。

```text:GNU Free Documentation License
Copyright (C)  2009  Misfit138
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled "GNU
Free Documentation License".
```

GFDLライセンス全文はこちらです。

https://www.gnu.org/licenses/fdl-1.3.html
GitHub Actionsチートシート

# はじめに
RubyやTypeScript,Goを学んできましたが、言語ばかりを勉強してきたためCI/CDやインフラ周りの知識・技術が欠けているなと感じました。
その取り掛かりとしてGitHub Actionsについて勉強したので、その単語集を作りました。(随時更新・修正予定)

# GitHub Actionsとは
そもそもGitHub Actionsとは何なのでしょうか。GitHub ActionsとはGitHubが提供しているワークフロー自動化サービスです。
仕組みとしては以下のようになっております。
- Workflow(ワークフロー)はJob(ジョブ)単位で分けられている
- JobはRunner(ランナー)という仮想マシンのインスタンス上で実行される
- JobはさらにStep単位で分けられており、Step内にコマンドなどの処理が実行される

# サンプルコード
```.github/workflow/workflow.yml
name: First Workflow
on: [push]

jobs:
    run-shell-commands:
        runs-on: ubuntu-latest
        steps:
            - name: echo a string
              run: echo "Hello World"
            - name: Multiline Command
              run: |
                node -v
                npm -v
```
## 説明
- ``name: First Workflow`` : ここではワークフローの名前を定義しています。今回は``First Workflow``という名前をつけています
- ``on: [push]`` : ここではどのタイミングでワークフローを走らせるのか定義しています。今回は``push``を指定しており、pushしたら実行するように定義しています。他にもpull_requestやissueなども指定することができます。
また、次のようにしてbranchを指定することもできます。
```
on:
   push:
    branches: [ "main" ] 
```
- ``jobs``: ここではワークフローにの中に含まれる一連の処理を定義します。
- ``run-shell-commands`` : こちらはジョブの名前になります。任意でつけることができます。
- ``runs-on: ubuntu-latest`` : ここではどのような仮想環境でジョブの処理を実行するのか指定します。今回はUbuntuの最新版を指定しています。
- ``steps``: ワークフローの具体的な処理を書いています。
    - ``name`` : ステップの名前を指定しています。
    - ``run`` : 具体的な処理を記載しています。
LocalStack で AWS CLI コマンドを使う

## このエントリについて

- [こちらのエントリ](https://qiita.com/outerlet/items/8199c2f4eb7cbc678f16) と同じく、以前残したメモを供養する目的で書きました
- LocalStack はv3がリリース済みですが、ここに書いたのはv2の使用時に確認した設定やコマンドです。v3のコンテナで動くことを確認したうえで書いていますが、v3に最適化した訳でない点はご承知おきください

## コンテナの LocalStack に対しAWS CLIコマンドを発行する方法

1. コンテナの外から `aws` コマンドを使う
2. `awslocal` コマンドを使う

## （事前準備） LocalStack 用のプロファイルを定義

- `aws` コマンドの `--profile` に与える LocalStack 用のプロファイルを用意しておく
- 中身は適当でよいが、存在するAWS環境に有効なプロファイルを使うと LocalStack の方でエラーにしてしまうはず

#### （例） ~/.aws/config

```plaintext
[profile localstack]
region = ap-northeast-1  # この値は AWS_DEFAULT_REGION 環境変数と合わせるのが無難
output = json
```

#### （例） ~/.aws/credentials

```plaintext
[localstack]
aws_access_key_id = Dummy
aws_secret_access_key = Dummy
```

## コンテナの外から `aws` コマンドを使う

- `--endpoint-url` と `--profile` を与えて `aws` コマンドを発行する
- `--profile` には、予め用意しておいた LocalStack 用のプロファイルを指定する

#### （例） `s3` コマンドを発行

下記は `s3` コマンドだが `lambda` や `dynamodb` なども同じやり方

- localstack/localstack イメージを使用
- "localstack" というプロファイルを使用し、ポート番号には 4566 を指定

```terminal
% aws s3 --endpoint-url http://localhost:4566 --profile localstack mb s3://localstack-sample-bucket
make_bucket: localstack-sample-bucket
% aws s3 --endpoint-url http://localhost:4566 --profile localstack ls
2023-06-08 05:01:55 localstack-sample-bucket
```

## `awslocal` コマンドを使う

- ⁠`awslocal` は `--endpoint-url` や `--profile` を指定することなく、ローカルの LocalStack に対して `aws` コマンドを発行するもの
- Docker で localstack/localstack イメージから起動した場合、コンテナに入れば `awslocal`が使える状態になっている（コンテナ内でのインストールは不要）
- `--endpoint-url` や `--profile` の以外は `aws` が `awslocal` になるだけで、コマンドの体系は同じ
    - `aws s3 ls` は、そのまま `awslocal s3 ls` になる
- Docker にセットアップした LocalStack がデフォルトの設定なら、コンテナの外からでも [`awslocal` によるコマンドが可能](https://github.com/localstack/awscli-local?tab=readme-ov-file#example)
    - デフォルトの 4566 ポート以外でセットアップするなどした場合は `AWS_ENDPOINT_URL` 環境変数を設定して対応

#### （例） s3 コマンドを実行

```terminal
% docker container exec -it localstack-container /bin/bash
# awslocal s3 mb s3://localstack-sample-bucket
make_bucket: localstack-sample-bucket
# awslocal s3 ls
2023-06-08 05:47:43 localstack-sample-bucket
```

### （補足） awslocal のインストール

- Mac なら pip で [awscli-local パッケージ](https://github.com/localstack/awscli-local "https://github.com/localstack/awscli-local") でインストールする
- Docker での起動も含めローカルに LocalStack をセットアップするなら、 `awslocal` もローカルにインストールしておいた方が便利
    - ~~LocalStack コンテナに対してローカルから `awslocal` を発行する方法もあると思いますが、　`aws` コマンドで足りるので調査しておらず、ここでは割愛します~~

```terminal
pip install awscli-local
```
島探し (paizaランク S 相当)　Python解説

# 自己紹介
大阪大学2回生で競技プログラミング部rainbou副部長、Atcoder緑
X:https://x.com/e4h99rhQ7I24670


# 問題文 島探し (paizaランク S 相当)　URL
https://paiza.jp/works/mondai/s_rank_skillcheck_sample/search-island

# 解説
この問題はSランク問題のなかでは基礎的な問題だと思います。特に、初めてSランク問題に挑戦さあれる方には特におすすめです。
Atcoderで出題されればおそらくdiff400くらいだろうと思われます。

解法自体は非常にシンプルでUnionFindや幅優先探索などなんでも解けると思います。ここでは、一番簡単で分かりやすいであろう幅優先探索を使った解説をしていきます。

グリッド上を全探索し１が出てきたらansを+=1してそこに隣接している１のマスを０に変えていけばいいです。その後、変更されたマスをqueに入れてを繰り返しやっていく感じになります。
計算量はO(HW)です。

※ここでは入力例にあったN, Mを用いずにH, Wとしています。これは多くのグリッド問題がH, Wを用いるため、それにのっとって、ほかの問題に応用の聞きやすいようにしています。
# 実装例

```python
from queue import Queue
W, H = map(int, input().split())
A = [list(map(int, input().split())) for _ in range(H)]
ans = 0
DIJ = [(1, 0), (-1, 0), (0, 1), (0, -1)]

def in_board(x, y):
    if 0 <= x < H and 0 <= y < W:
        return True
    return False

def bfs(i, j):
    que = Queue()
    que.put((i, j))
    A[i][j] = 0
    while not que.empty():
        i, j = que.get()
        for di, dj in DIJ:
            x, y = i+di, j+dj
            if not in_board(x, y):
                continue
            if A[x][y] == 0:
                continue
            A[x][y] = 0
            que.put((x, y))

for i in range(H):
    for j in range(W):
        if A[i][j] == 0:
            continue
        ans += 1
        bfs(i, j)

print(ans)

```
mod7占い (paizaランク S 相当)

# 自己紹介
大阪大学2回生で競技プログラミング部rainbou副部長、Atcoder緑
X:https://x.com/e4h99rhQ7I24670

# 問題文URL
https://paiza.jp/works/mondai/s_rank_skillcheck_sample/mod7

# 解説
この問題はぱっとみ、かなり難しい問題のように見えます。
この問題ではDPという考え方を使うのですが、慣れていないとおそらく解けなかったと思います。
さすがはSランク問題といった感じです。（笑）
Atcoderで出題されればおそらくdiff800程度でしょう。

先ほども触れましたようにこの問題はDPを使います。
N<=10^5である点からもDPとぱっと思いつくことは難しくないと思います。（DP解きなれてくればなんとなく問題文から雰囲気を察すれるようになれます。）

今回はDP[i][j][k]<-i番目の数のみでj枚使ってKmod７を作れる個数でDPします。
遷移としては
```python
DP[i+1][j][k] += dp[i][j][k]
DP[i+1][j+1][(k+a)%7] += dp[i][j][k](if j != 2)
ans += DP[i][j][k](if j == 2 and (k+a) % 7 == 0)
```
です

あとはこれを実装に落とし込むだけです。
```python
N = int(input())
dp = [[[0]*7 for _ in range(3)] for _ in range(N+1)]
dp[0][0][0] = 1

ans = 0
for i in range(N):
    a = int(input()) % 7
    for j in range(3):
        for k in range(7):
            dp[i+1][j][k] += dp[i][j][k]
            if j != 2:
                dp[i+1][j+1][(k+a) % 7] += dp[i][j][k]
            elif j == 2 and (k+a)%7 == 0:
                ans += dp[i][j][k]

print(ans)

```

modをとらなくてもいいというのはどこか気持ち悪いですね。ｗ
Phoenix Playground をWSL環境から使えるようにする

# 解決した問題

Phoenix PlaygroundをWSL環境で動作させてるLivebookから実行すると、起動できませんでした。

https://hexdocs.pm/phoenix_playground/readme.html

# 原因

Phoenix Playgroundがxgd-openを使って、localhost:4000をブラウザーで開こうとするのですが、xdg-openが実行できずエラーとなる。

# 解決策

xgd-openを実行した時に、Windows側のブラウザを起動するように設定する。

次の記事の設定を行って、起動できました。

https://zenn.dev/ciffelia/articles/wsl-xdg-open

# 結果

Phoenix Playgroundのサンプル開けました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532235/2e241bee-990c-6670-d9f9-55437069b021.png)
Guest Additionsのアップグレードが失敗する場合の対処方法

VirtualBox7でGuest Additionsをアップグレードしたところ、エラーメッセージが出た。
dkmsパッケージをインストールすると、アップグレードに成功した。

## 環境
- VirtualBox
バージョン 7.0.18
- ホストOS
Windows 11 Home
- ゲストOS
Ubuntu 22.04 LTS (Jammy Jellyfish)

## 現象
Guest Additionsインストール後、アップグレードを実行するとエラーメッセージを出してアップグレードに失敗する。

![スクリーンショット 2024-07-20 094828.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490928/c7cbcd40-0b11-1ce1-0a09-710d0bf6e43c.png)
*Guest Additions インストール直後（Guest Additionsのバージョンが古い）*

![スクリーンショット 2024-07-20 094843.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490928/1545da55-1c9a-6081-97f2-be8e6ed738ac.png)
*アップグレードの実行*

![スクリーンショット 2024-07-20 095006.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490928/1b11f4c0-a0b6-fbd4-9033-1a22c89e6e52.png)
*アップグレード失敗*

＜エラーメッセージ＞
```
Automatic update of Guest Additions has failed: files were installed, but kernel modules were not reloaded automatically. Please consider rebooting the guest.
終了コード :
VBOX_E_GSTCTL_GUEST_ERROR (0X80BB000F)
コンポーネント:
GuestSessionWrap
インターフェース:
IGuestSession {234f0627-866d-48c2-91a5-4c9d50f04928}
```
（再起動を促されているようだが、再起動しても解決しない。）

## 対処方法
dkmsパッケージをインストールする
```
sudo apt install dkms
```
![スクリーンショット 2024-07-20 095457.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490928/721e4d9a-95f4-fe3d-b081-a0a6056d3589.png)
*再度アップグレードを実行し、バージョンを確認*


## 参考サイト
[LinuxにVirtualBox Guest Additionsを入れる方法まとめ【Ubuntu・Mint・Debian・CentOS・Fedora】](https://linuxfan.info/virtualbox-guest-additions#toc2)
for文でcontinueの理解。使用例も合わせて

## 実装

```go
	for i := 1; i <= 100; i++ {
		if i%3 == 0 {
			fmt.Println(i, "3で割り切れる数")
			if i%5 == 0 {
				fmt.Println(i, "3でも5でも割り切れる数")
			}
		} else if i%5 == 0 {
			fmt.Println(i, "5で割り切れる数")
		} else {
			fmt.Println(i)
		}
	}
```

上記のようにfor文の中身をif文で出し分けしてもいいのですが、可読性が悪くなるので下記のように書き換えることができます。

```go
	for i := 1; i <= 100; i++ {
		if i%3 == 0 && i%5 == 0 {
			fmt.Println(i, "3でも5でも割り切れる数字")
			continue
		}

		if 1%3 == 0 {
			fmt.Println(i, "3で割り切れる数字")
			continue
		}

		if i%5 == 0 {
			fmt.Println(i, "5で割り切れる数字")
			continue
		}

		fmt.Println(i)
	}
```

`continue`で見た目もすっきりとした記述に変更すことができる。`continue`は条件を満たしたら、今のループを終了して次のループ開始します。

## 実践してみる

ユーザーリストをループして、例えば18歳以下のユーザーを除外する場合に、年齢を見て、18歳未満は`continue`でスキップします。そして、18歳以上のユーザーのみに処理を書く場合などに使えます。

```go
for _, user := range users {
	if user.Age < 18 {
		continue
	}
	// 18歳以上のユーザーのみを処理
}

```
【SQL】VIEWの基礎

## VIEWの基礎

### VIEWとは
ビュー（VIEW）は、基となるテーブルからデータを取得する仮想テーブルです。
ビューは、実際のデータを持たず、基となるテーブルのクエリ結果を提供します。
ビューを使用することで、データの抽象化、セキュリティ、簡潔なクエリ作成が可能になります。

### VIEWの利点
1. **データの抽象化**: ユーザーに対してデータの特定の部分だけを見せることができ、データベースの複雑さを隠すことができます。
2. **セキュリティ**: 特定のユーザーに対してビューを通じてアクセス権を制御することで、機密データを保護できます。
3. **簡潔なクエリ作成**: 複雑なクエリをビューとして保存し、簡単に再利用することができます。
4. **データの一貫性**: ビューを使用することで、一貫性のあるデータ表現を提供できます。

### VIEWの作成
ビューを作成するためには、`CREATE VIEW`文を使用します。

**例: 単純なビューの作成**

```sql
-- employeesテーブルから特定の列を選択するビューを作成
CREATE VIEW employee_names AS
SELECT employee_id, first_name, last_name
FROM employees;
```

### VIEWの使用
ビューを使用することで、基となるテーブルからデータを取得するクエリを簡素化できます。

**例: ビューの使用**
```sql
-- employee_namesビューを使用してデータを取得
SELECT * FROM employee_names;
```

### 更新可能なVIEW
ビューを通じてデータを更新することも可能です。ただし、ビューが特定の条件を満たしている必要があります（例：単一のテーブルに基づいている、集計関数を含まないなど）。

**例: 更新可能なビュー**
```sql
-- 単一のテーブルに基づくビューの作成
CREATE VIEW employee_salaries AS
SELECT employee_id, salary
FROM employees;

-- ビューを通じてデータを更新
UPDATE employee_salaries
SET salary = salary * 1.10
WHERE employee_id = 101;
```
### 非更新可能なVIEW
ビューが複数のテーブルを結合している場合や、集計関数を含む場合、そのビューは更新できません。

**例: 非更新可能なビュー**
```sql
-- 集計関数を含むビューの作成
CREATE VIEW department_salaries AS
SELECT department_id, AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id;

-- 非更新可能なビューを通じての更新はエラーになります
-- UPDATE department_salaries
-- SET avg_salary = 50000
-- WHERE department_id = 10;
```
### VIEWの管理
既存のビューを変更するためには、CREATE OR REPLACE VIEW文を使用します。また、ビューを削除するためには、DROP VIEW文を使用します。

#### VIEWの変更
```sql
-- 既存のビューを変更
CREATE OR REPLACE VIEW employee_names AS
SELECT employee_id, first_name, last_name, email
FROM employees;
```
#### VIEWの削除
```sql
-- ビューを削除
DROP VIEW employee_names;
```

### ビューのセキュリティ
ビューを使用することで、ユーザーが直接テーブルにアクセスすることなく、必要なデータだけを提供できます。これにより、機密データを保護しつつ、必要なデータへのアクセスを制御できます。
**例: ビューを使用したアクセス制御**
```sql
-- 従業員の給与情報を含まないビューを作成
CREATE VIEW public_employee_info AS
SELECT employee_id, first_name, last_name, department_id
FROM employees;

-- 特定のユーザーにビューへのアクセス権を付与
GRANT SELECT ON public_employee_info TO public_user;
```
【SQL】トランザクション

## トランザクション管理

PL/SQLでのトランザクション管理は、データの一貫性と整合性を確保するために重要です。トランザクション管理には、`COMMIT`、`ROLLBACK`、`SAVEPOINT`の3つの主要なコマンドがあります。

### トランザクションの基本概念
トランザクションは、一連のデータベース操作を単一の論理単位として扱うものです。トランザクションの主な特性は以下の通りです。

- **原子性 (Atomicity)**: トランザクション内のすべての操作は一つの単位として扱われ、すべて成功するか、すべて失敗する。
- **一貫性 (Consistency)**: トランザクションが終了すると、データベースの状態が一貫したものになる。
- **独立性 (Isolation)**: トランザクションは互いに独立して実行され、同時に実行される場合でも結果は個々のトランザクションが順番に実行された場合と同じになる。
- **耐久性 (Durability)**: トランザクションが完了すると、その結果は永続的に保存される。

### COMMIT
`COMMIT`コマンドは、トランザクションを終了し、すべての変更をデータベースに確定させます。これにより、他のユーザーが変更内容を確認できるようになります。

**例: COMMITの使用**

```sql
BEGIN
    UPDATE employees
    SET salary = salary * 1.10
    WHERE department_id = 10;

    COMMIT; -- 変更を確定
END;
```
### ROLLBACK
`ROLLBACK`コマンドは、トランザクションを終了し、トランザクション内のすべての変更を取り消します。これにより、データベースはトランザクション開始前の状態に戻ります。

**例: ROLLBACKの使用**
```sql
BEGIN
    UPDATE employees
    SET salary = salary * 1.10
    WHERE department_id = 10;

    ROLLBACK; -- 変更を取り消し
END;
```

### SAVEPOINT
`SAVEPOINT`コマンドは、トランザクション内の特定のポイントを設定します。ROLLBACK TO SAVEPOINTコマンドを使用することで、トランザクション全体を取り消すのではなく、指定したセーブポイントまでの変更を取り消すことができます。

**例: SAVEPOINTとROLLBACK TO SAVEPOINTの使用**
```sql
BEGIN
    UPDATE employees
    SET salary = salary * 1.10
    WHERE department_id = 10;

    SAVEPOINT before_bonus; -- セーブポイントを設定

    UPDATE employees
    SET salary = salary + 1000
    WHERE department_id = 10;

    -- エラーが発生した場合、セーブポイントまでロールバック
    IF SQL%ROWCOUNT = 0 THEN
        ROLLBACK TO before_bonus;
    ELSE
        COMMIT; -- 変更を確定
    END IF;
END;
```
【SQL】トリガー

## トリガー

### トリガーの基本概念
トリガーは、特定のイベント（INSERT、UPDATE、DELETE）がテーブルに対して実行されたときに、自動的に実行されるストアドプログラムです。トリガーを使用することで、データベースの一貫性と整合性を保つための自動処理を実装できます。

### トリガーの種類
- **行レベルトリガー**: 各行の変更に対して実行されるトリガー。
- **文レベルトリガー**: SQL文の実行全体に対して実行されるトリガー。

### トリガーの作成と使用

**例: 行レベルトリガーの作成**
従業員の給与が変更されたときに、変更履歴をログに記録するトリガーを作成します。
```sql
CREATE OR REPLACE TRIGGER trg_employee_salary_change
AFTER UPDATE OF salary ON employees -- employeesテーブルのsalary列が更新された後にトリガーを実行
FOR EACH ROW -- 更新された各行に対してトリガーを実行
BEGIN
    -- salary_historyテーブルに更新前と更新後の給与情報を挿入
    INSERT INTO salary_history (employee_id, old_salary, new_salary, change_date)
    VALUES (:OLD.employee_id, :OLD.salary, :NEW.salary, SYSDATE); -- :OLDと:NEWで更新前と更新後の値にアクセス
END;
```

**例: 文レベルトリガーの作成**
employeesテーブルに対するINSERT文が実行された後に、挿入操作の概要をログに記録する文レベルトリガーの例です。
```sql
CREATE OR REPLACE TRIGGER trg_employee_insert_log
AFTER INSERT ON employees -- employeesテーブルへのINSERT文実行後にトリガーを実行
DECLARE
    v_row_count NUMBER; -- 挿入された行数を格納する変数
BEGIN
    -- 挿入された行数をカウント
    SELECT COUNT(*) INTO v_row_count FROM employees;
    
    -- トリガーログテーブルに挿入操作の概要を記録
    INSERT INTO trigger_log (event_type, table_name, log_date, row_count)
    VALUES ('INSERT', 'employees', SYSDATE, v_row_count);
END;

```

### トリガーの利点
- **自動化**: データの変更に対する自動処理を実装できる。
- **データ整合性の維持**: データの変更に対して、追加の検証や処理を自動的に実行できる。
- **監査とログ**: データの変更履歴を自動的に記録できる。

### トリガーの注意点
- **トリガー内の処理が複雑になると、パフォーマンスに影響を与える可能性がある。
- **トリガーはデバッグが難しい場合があるため、ロジックをシンプルに保つことが重要。
ソフトウェア開発の現場から：進捗管理の理想と現実

## はじめに

「進捗どうですか？」
この質問、開発者なら誰もが耳にタコができるほど聞いたことがあるでしょう。
本記事では、ソフトウェア開発現場での進捗管理の現実と、チームで試行錯誤できる改善策をお伝えします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/4953fd7a-7eac-d115-4712-02fb4506ead5.png)

## 現場あるある：進捗管理の難しさ

### 1. 見積もりの難しさ

実際にありそうな会話：

PM：「このタスク、どのくらいで終わりそう？」
開発者：「うーん、3日くらいかな」
PM：「じゃあ4日で見積もっておこう」
1週間後...
PM：「あれ？まだ終わってないの？」
開発者：「すみません、想定外の問題が...」

教訓：未知の要素が多いタスクの見積もりは本当に難しい。

### 2. 「順調です」の落とし穴

朝会での会話：

リーダー：「進捗はどう？」
開発者：「はい、順調です」
（内心：あー、でもこの部分どうしよう...でも今は言いづらいな...）

結果：問題が大きくなってから発覚し、対応が後手に回る。

### 3. モチベーション維持の現実

ある日の開発者：
「今日はどうしてもコードが書けない...」
「このライブラリのドキュメントを読むふりをして、Qiitaをだらだら見てしまった...」

現実：誰しもモチベーションが上がらない日はある。それをどう乗り越えるかが重要。

## 実践してみたい：現実的な進捗管理アプローチ

### 1. 「ストーリーポイント」の導入

具体例：
タスクA: 3ポイント（1日程度）
タスクB: 8ポイント（3-4日程度、不確定要素あり）

期待される効果：時間ではなく、相対的な難易度で見積もることで、より現実的な計画が立てやすくなる。

https://asana.com/ja/resources/story-points

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/e4366ebe-5e26-01f6-4631-b4843fe040dd.png)

### 2. 「確信度」を報告に含める

進捗報告の例：
「タスクAは80%完了。確信度は60%です。APIの仕様が曖昧な部分があるので、確認が必要かもしれません。」

期待される効果：早期に潜在的な問題を共有できるようになり、チームの対応が素早くなる。

https://agility-at-scale.com/safe/confidence-vote/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/b28d1332-6917-8ce3-1620-e8e45eef05d8.png)


### 3. 「今日はダメな日」の共有

チームでの約束事：
「今日はコードが書けない日」を宣言できる（月に1-2回まで）

実際の使用例：
「今日は集中できないので、ドキュメント整理と簡単なバグ修正に専念します。」

期待される効果：無理に生産性を装わなくて済み、精神的な負担が減る。翌日以降の生産性向上につながる可能性がある。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/4a3f0af5-2525-a732-5171-bafcf5be7dd0.png)


### 4. 「もくもく会」の導入

毎週水曜日の午後2時間を「もくもく会」として設定。
- 各自がその時間にやりたいことを宣言
- 集中して作業
- 終了後に簡単な成果報告

期待される効果：普段手が付けられない技術的負債の返済や、新技術の学習時間が確保できる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/eeafbce7-39e8-2412-94cf-058c21988c4a.png)

### 5. 「リファクタリングスプリント」の実施

3-4スプリントに1回、1週間のリファクタリング期間を設ける。

実際の取り組み：
- 技術的負債の棚卸し
- チーム全体でのコードレビュー
- パフォーマンス改善

期待される効果：コードの品質が向上し、長期的な保守性が高まる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/09fa0670-f0f8-7d5e-df94-2585582ab7bb.png)

## まとめ：進捗管理の改善に向けて

完璧な進捗管理は存在しません。しかし、チームの現状に合わせて少しずつ改善を重ねることで、着実に成果を上げることができるはずです。

上記で紹介したアプローチは、一つのチームですべてを一度に導入するのは難しいかもしれません。しかし、以下のような段階的な導入を検討してみるのはいかがでしょうか：

1. まずは「確信度」を報告に含める取り組みから始める
2. チーム内で話し合い、最も必要性を感じるアプローチを1つ選んで試験的に導入する
3. 1-2ヶ月ほど試行した後、効果を振り返り、継続するか別のアプローチを試すか決める
4. 効果が見られたアプローチは正式に採用し、次のアプローチの試行に移る

このような段階的な改善プロセスを通じて、チームに最適な進捗管理の方法を見つけていくことができるでしょう。

理想的には、こうした取り組みを通じて：

- チーム内のコミュニケーションが活発になる
- 予期せぬ問題への対応力が向上する
- 個々のメンバーの成長スピードが上がる

といった効果が期待できます。

皆さんのチームでは、どのような進捗管理の課題や工夫がありますか？ また、この記事で紹介したアプローチの中で、試してみたいものはありますか？ 
開発現場の生産性向上と、開発者一人一人のウェルビーイング。この2つを両立させる進捗管理の形を、一緒に探っていけたら嬉しいです。
Cloudflare デプロイ中のRemixアプリのドメインと同様のドメインでR2のスタイルが別ファイルになっているHTMLオブジェクトにアクセスする

## 概要

下記の記事の対応でHTMLのファイルを1階層下げたり、CSSのスタイルシートを別のフォルダに設置したりした。

https://qiita.com/miriwo/items/e3c8239f408ccdef48cb

上記の記事よりも前に下記の記事でリダイレクトを用いた別ドメインでの提供がうまく動かなくなった。

https://qiita.com/miriwo/items/cc46a70fb1d1716c6103

これをうまく動くように修正してみる。

## 方法

1. リダイレクトを管轄しているworkersの「redirect-static-file」のコードを下記の様に修正

    ```js
    export default {
      async fetch(request, env) {
        const url = new URL(request.url);

        // /detail/パスへのリクエストをR2バケットにリダイレクト
        if (url.pathname.startsWith('/detail/')) {
          const key = url.pathname.replace('/detail/', '');
          const r2Url = `https://public.www.miriwo.work/pages/${key}`;
          const r2Response = await fetch(r2Url);

          if (!r2Response.ok) {
            return new Response('Not Found', { status: 404 });
          }

          const headers = new Headers(r2Response.headers);
          return new Response(r2Response.body, {
            headers,
          });
        }

        // その他のリクエストはRemixアプリケーションにフォワード
        return env.ASSETS.fetch(request);
      },
    };
    ```

1. 保存してデプロイをしておく

ここまで設定すれば [https://miriwo.work/detail/index.html](https://miriwo.work/detail/index.html)にアクセスすることでファイルを開くことはできるようになる。

![CleanShot 2024-07-20 at 13.52.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/8460d075-3868-8d57-a71e-976e0125d6f5.png)

しかしよく見るとスタイルが当たっておらず、これをなんとかしたい。

1. 下記のようにindex.htmlのlink要素を変更（要は直接R2の中のCSSを指定）

    ```static/pages/index.html
    <!DOCTYPE html>
    <html lang="ja">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <!-- <link rel="stylesheet" href="../assets/css/index.css"> -->
        <!-- <link rel="stylesheet" href="https://R2のパブリックバケットのドメイン/assets/css/index.css"> -->
        <link rel="stylesheet" href="https://public.www.miriwo.work/assets/css/index.css">
        <title>Document</title>
    </head>
    <body>
      <h1>Hello Cloudflare R2(Other directory style)</h1>
    </body>
    </html>
    ```

これで[https://miriwo.work/detail/index.html](https://miriwo.work/detail/index.html)にアクセスしたところ下記のようにスタイルが当たった。

![CleanShot 2024-07-20 at 14.21.20@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/05ad2455-d8e3-7851-afd1-a4577dcf776b.png)
【SQL】パッケージ

## パッケージ

### パッケージとは
パッケージは、関連するPL/SQLオブジェクト（プロシージャ、ファンクション、変数、カーソルなど）を一つにまとめたコンテナです。パッケージを使用することで、コードのモジュール化、再利用性、保守性が向上します。

### パッケージの構成
パッケージは、パッケージ仕様（宣言部）とパッケージ本体（実装部）の2つの部分から構成されます。

1. **パッケージ仕様（宣言部）**: パッケージ内の公開メンバー（プロシージャ、ファンクション、変数など）を宣言します。
2. **パッケージ本体（実装部）**: パッケージ仕様で宣言されたメンバーの実装を定義します。

### パッケージの作成

**例: パッケージ仕様の作成**

```sql
CREATE OR REPLACE PACKAGE employee_pkg IS
    PROCEDURE update_salary(p_emp_id IN NUMBER, p_new_salary IN NUMBER);
    FUNCTION get_salary(p_emp_id IN NUMBER) RETURN NUMBER;
END employee_pkg;
```
**例: パッケージ本体の作成**
```sql
CREATE OR REPLACE PACKAGE BODY employee_pkg IS

    -- プロシージャの実装
    PROCEDURE update_salary(p_emp_id IN NUMBER, p_new_salary IN NUMBER) IS
    BEGIN
        UPDATE employees
        SET salary = p_new_salary
        WHERE employee_id = p_emp_id;
    END update_salary;

    -- ファンクションの実装
    FUNCTION get_salary(p_emp_id IN NUMBER) RETURN NUMBER IS
        v_salary employees.salary%TYPE;
    BEGIN
        SELECT salary INTO v_salary
        FROM employees
        WHERE employee_id = p_emp_id;
        RETURN v_salary;
    END get_salary;

END employee_pkg;
```
**例: パッケージの使用**
```sql
DECLARE
    v_salary NUMBER;
BEGIN
    -- パッケージのプロシージャを呼び出し
    employee_pkg.update_salary(101, 5000);

    -- パッケージのファンクションを呼び出し
    v_salary := employee_pkg.get_salary(101);
    DBMS_OUTPUT.PUT_LINE('Updated Salary: ' || v_salary);
END;
```

### パッケージの利点
- **モジュール化**: 関連するプロシージャやファンクションを一つにまとめ、管理しやすくする。
- **再利用性**: 一度作成したパッケージを他のプログラムから簡単に呼び出せる。
- **保守性**: パッケージ本体を変更しても、パッケージ仕様に変更がなければ依存するプログラムを再コンパイルする必要がない。
- **効率性**: パッケージ内のコードは一度メモリにロードされると、以降の呼び出しは高速になる。
【SQL】ストアドプロシージャとファンクション

## ストアドプロシージャとファンクション

PL/SQLでは、ストアドプロシージャとファンクションを使用して、再利用可能なコードブロックをデータベース内に保存し、必要に応じて呼び出すことができます。これにより、コードの再利用性と保守性が向上します。

### ストアドプロシージャ
ストアドプロシージャは、特定のタスクを実行するための一連のSQLステートメントを含むプログラムユニットです。ストアドプロシージャは、呼び出されたときに一度に実行され、複雑なビジネスロジックをデータベース内で効率的に処理します。

#### ストアドプロシージャの作成と呼び出し
**例: ストアドプロシージャの作成**

```sql
-- ストアドプロシージャの作成
CREATE OR REPLACE PROCEDURE greet_user (p_name IN VARCHAR2) IS
BEGIN
    DBMS_OUTPUT.PUT_LINE('Hello, ' || p_name || '!');
END;
```
**例: ストアドプロシージャの呼び出し**
```sql
-- ストアドプロシージャの呼び出し
BEGIN
    greet_user('Alice');
END;
```

### ファンクション
ファンクションは、特定の値を計算して返すためのプログラムユニットです。ファンクションは、呼び出されると値を返す点がストアドプロシージャと異なります。ファンクションは、SELECT文の中やPL/SQLブロック内で使用できます。

### ファンクションの作成と呼び出し
**例: ファンクションの作成**
```sql
-- ファンクションの作成
CREATE OR REPLACE FUNCTION get_double (p_number IN NUMBER) RETURN NUMBER IS
BEGIN
    RETURN p_number * 2;
END;
```
**例: ファンクションの呼び出し**
```sql
-- ファンクションの呼び出し
DECLARE
    v_result NUMBER;
BEGIN
    v_result := get_double(5);
    DBMS_OUTPUT.PUT_LINE('Double of 5 is ' || v_result);
END;
```

### IN、OUT、IN OUTパラメータ
ストアドプロシージャとファンクションは、パラメータを使用してデータを受け渡すことができます。パラメータには、IN、OUT、IN OUTの3種類があります。
- **INパラメータ**: 呼び出し元からプロシージャやファンクションに値を渡すためのパラメータ。呼び出し元で変更しても影響を受けません。
- **OUTパラメータ**: プロシージャやファンクションから呼び出し元に値を返すためのパラメータ。呼び出し元で使用される前に、プロシージャやファンクション内で初期化される必要があります。
- **IN OUTパラメータ**: 呼び出し元から値を受け取り、プロシージャやファンクション内でその値を変更し、変更後の値を呼び出し元に返すためのパラメータ。

**例: IN、OUT、IN OUTパラメータの使用**
```sql
-- ストアドプロシージャの例（IN、OUTパラメータ）
CREATE OR REPLACE PROCEDURE calculate_area (
    p_radius IN NUMBER,
    p_area OUT NUMBER
) IS
BEGIN
    p_area := 3.14 * p_radius * p_radius;
END;
```

```sql
-- 呼び出し例
DECLARE
    v_radius NUMBER := 5;
    v_area NUMBER;
BEGIN
    calculate_area(v_radius, v_area);
    DBMS_OUTPUT.PUT_LINE('Area of circle: ' || v_area);
END;
```

### ストアドプロシージャとファンクションの違い
- ストアドプロシージャ: 特定のタスクを実行するためのプログラムユニットで、値を返す必要はありません。
- ファンクション: 特定の値を計算して返すプログラムユニットで、必ず値を返す必要があります。
村人の友好関係 (paizaランク S 相当) Python解説

初めてqiitaで記事を書きます。読みにくい点などもあるかと思いますが優しい目でお願いします。質問等は随時受け付けています。
# 自己紹介
大阪大学2回生で競技プログラミング部rainbou副部長、Atcoder緑
X:https://x.com/e4h99rhQ7I24670

# 問題文（村人の友好関係 (paizaランク S 相当)）
https://paiza.jp/works/mondai/s_rank_skillcheck_archive/group_popularity
#  解説

まず、この問題はpaizaのなかでもかなり難しい問題だと思います。体感はAtcoderで1200diff程度だと思っています。

以下具体的な解法に触れていこうと思います。
制約等から愚直解ではrun time errorすることは自明です。
なぜなら計算量がO(QN^2)である。
そのため、なにか高速化できるかどうかを検討します。

ここで、頂点Ａと頂点Ｂの属性が違った時、その頂点間のパス（最短でなくてもよい）のうち最小の重みが最大であるパスのみを考えればいいことが分かります。
これは最初に辺の情報を入力として受け取った後に辺の重みでソートして、最大辺から考慮し頂点をUnionしていき、両端とも同じ属性に属している場合はその辺が使われる（答えになる）ことはないので無視します。
```python
A.sort(key=lambda x: (x[1]), reverse=True)
```
Aを二重リストで受け取った後にこの行を書くと、要素の２番目の降順にソートしてくれます。


ACコード
```python


class UnionFind:

    # インデックスは0-start
    # 初期化
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n
        self.group = n

    # private function
    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            vertices = []
            while self.parents[x] >= 0:
                vertices.append(x)
                x = self.parents[x]
            for i in vertices:
                self.parents[i] = x
            return x

    # x,yが属するグループの結合
    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)

        if x == y:
            return
        '''
        以下消すかどうかその都度考える
        '''
        if self.parents[x] > self.parents[y]:
            x, y = y, x

        self.parents[x] += self.parents[y]
        self.parents[y] = x
        self.group -= 1

    # x,yが同グループか判定
    def same(self, x, y):
        return self.find(x) == self.find(y)

    # xと同じグループの要素数を取得
    def size(self, x):
        return -self.parents[self.find(x)]

    # xが親かを判定
    def isparent(self, x):
        return self.parents[x] < 0



'''
同じ群にいるかどうかの判定はsame(x, y)でおこなう
26, 27行目のunion-by-sizeは行ってはいけないときがある。
そのグループの中で親が変わってはいけないとき
'''

N, M, Q = map(int, input().split())

doukoukai = [False]*N

AB = [list(map(int, input().split())) for _ in range(M)]
AB.sort(key=lambda x: (x[2]), reverse=True)
UF = UnionFind(N)
edge = []

for i in range(M):
    a, b, f = AB[i]
    a -= 1
    b -= 1
    if UF.same(a, b):
        continue
    UF.union(a, b)
    edge.append((a, b, f))

for i in range(Q):
    op, q = map(str, input().split())
    q = int(q)-1
    ans = 0
    if op == '+':
        doukoukai[q] = True
    else:
        doukoukai[q] = False
    for a, b, f in edge:
        if doukoukai[a] != doukoukai[b]:
            ans = max(ans, f)
    print(ans)


```

なにか質問等ございましたら、X等で言ってください。
【SQL】例外処理

## 例外処理

### 例外の種類
- **事前定義例外**: ORACLEが事前に定義している一般的なエラー（例: ZERO_DIVIDE, NO_DATA_FOUND）
- **ユーザー定義例外**: 開発者が独自に定義するエラー

### 例外ハンドラ
```sql
DECLARE
    v_number NUMBER;
BEGIN
    v_number := 1 / 0; -- ここで例外が発生
EXCEPTION
    WHEN ZERO_DIVIDE THEN
        DBMS_OUTPUT.PUT_LINE('Division by zero error!');
    WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('An unexpected error occurred: ' || SQLERRM);
END;
```

### RAISE文
RAISE文は、PL/SQLのプログラム内で明示的に例外を発生させるために使用されます。RAISE文を使用することで、カスタム例外を発生させたり、事前定義された例外を再度発生させたりすることができます。

#### RAISE文の使い方
1. **カスタム例外の発生**
    - カスタム例外を宣言し、特定の条件が満たされたときにその例外を発生させます。

2. **事前定義された例外の再発生**
    - 例外処理ブロック内で捕捉された例外を再度発生させることができます。
#### カスタム例外の発生

以下の例では、負の値が入力された場合にカスタム例外を発生させます。

```sql
DECLARE
    v_number NUMBER := -1; -- 負の値を初期化
    e_negative_number EXCEPTION; -- カスタム例外を宣言
BEGIN
    -- 負の値が入力された場合にカスタム例外を発生させる
    IF v_number < 0 THEN
        RAISE e_negative_number;
    END IF;
EXCEPTION
    -- カスタム例外を処理する
    WHEN e_negative_number THEN
        DBMS_OUTPUT.PUT_LINE('Error: Negative number is not allowed.');
END;
```

#### 事前定義された例外の再発生

以下の例では、事前定義された例外を捕捉し、再度発生させます。

```sql
DECLARE
    v_number NUMBER := 10;
    v_result NUMBER;
BEGIN
    BEGIN
        -- 0による除算を試みる
        v_result := v_number / 0;
    EXCEPTION
        WHEN ZERO_DIVIDE THEN
            DBMS_OUTPUT.PUT_LINE('Caught an exception: Division by zero.');
            RAISE; -- 例外を再度発生させる
    END;
EXCEPTION
    -- 再度発生した例外を処理する
    WHEN ZERO_DIVIDE THEN
        DBMS_OUTPUT.PUT_LINE('Re-raised exception: Division by zero.');
END;
```

#### RAISE_APPLICATION_ERRORプロシージャ
RAISE_APPLICATION_ERRORプロシージャは、ユーザー定義のエラーメッセージを生成するために使用されます。このプロシージャを使用すると、特定のエラー番号とメッセージを指定して例外を発生させることができます。

例: RAISE_APPLICATION_ERRORの使用

```sql
DECLARE
    v_number NUMBER := -1;
BEGIN
    -- 負の値が入力された場合にユーザー定義の例外を発生させる
    IF v_number < 0 THEN
        RAISE_APPLICATION_ERROR(-20001, 'Negative number is not allowed.');
    END IF;
EXCEPTION
    -- ユーザー定義の例外を処理する
    WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);
END;

```

### ベストプラクティス
- 例外処理は簡潔に、エラーの特定と対応を明確に行う。
- 不要な例外処理を避け、必要な部分にのみ例外ハンドラを設ける。
【SQL】条件分岐、ループ、CASE文

## 制御構造

### 条件分岐（IF THEN ELSE）
```sql
DECLARE
    v_score NUMBER := 85;
BEGIN
    -- 条件分岐の開始
    IF v_score >= 90 THEN
        -- v_score が 90 以上の場合の処理
        DBMS_OUTPUT.PUT_LINE('Grade: A');
    ELSIF v_score >= 80 THEN
        -- v_score が 80 以上 90 未満の場合の処理
        DBMS_OUTPUT.PUT_LINE('Grade: B');
    ELSE
        -- 上記以外の場合の処理
        DBMS_OUTPUT.PUT_LINE('Grade: C');
    END IF; -- IF ブロックの終了
END;

```

### ループ（LOOP, WHILE LOOP, FOR LOOP）
#### LOOP
LOOP文は、条件が満たされるまで繰り返し処理を行うための構造です。LOOPは明示的にEXIT文で終了条件を指定するまで実行され続けます。

```sql
-- LOOP
DECLARE
    v_counter NUMBER := 1; -- ループカウンタを1に初期化
BEGIN
    LOOP
        -- v_counterが5を超えたらループを終了
        EXIT WHEN v_counter > 5;
        
        -- 現在のカウンタの値を出力
        DBMS_OUTPUT.PUT_LINE('Counter: ' || v_counter);
        
        -- カウンタを1増やす
        v_counter := v_counter + 1;
    END LOOP; -- ループの終了
END;

```
#### WHILE LOOP
WHILE LOOPは、指定された条件が真の間、繰り返し処理を行います。条件が最初に評価され、条件が満たされる限りループ内の処理が実行されます。

```sql
-- WHILE LOOP
DECLARE
    v_counter NUMBER := 1; -- ループカウンタを1に初期化
BEGIN
    -- v_counterが5以下である限り、ループを実行
    WHILE v_counter <= 5 LOOP
        -- 現在のカウンタの値を出力
        DBMS_OUTPUT.PUT_LINE('Counter: ' || v_counter);
        
        -- カウンタを1増やす
        v_counter := v_counter + 1;
    END LOOP; -- ループの終了
END;
```
#### FOR LOOP
FOR LOOPは、指定された範囲内の値に対して繰り返し処理を行います。カウンタ変数は自動的に初期化され、範囲内の各値に対してループが実行されます。
```sql
-- FOR LOOP
BEGIN
    -- iが1から5までの値を取りながらループを実行
    FOR i IN 1..5 LOOP
        -- 現在のカウンタの値を出力
        DBMS_OUTPUT.PUT_LINE('Counter: ' || i);
    END LOOP; -- ループの終了
END;

```

### CASE文
CASE文は、条件分岐の一種で、指定された式の値に基づいて異なる処理を行います。各条件が評価され、最初に真と評価された条件に対応する処理が実行されます。
```sql
-- CASE文
DECLARE
    v_grade CHAR(1) := 'B'; -- グレードを'B'に初期化
BEGIN
    -- グレードに基づいて処理を分岐
    CASE v_grade
        WHEN 'A' THEN 
            DBMS_OUTPUT.PUT_LINE('Excellent'); -- グレードが'A'の場合の処理
        WHEN 'B' THEN 
            DBMS_OUTPUT.PUT_LINE('Good'); -- グレードが'B'の場合の処理
        WHEN 'C' THEN 
            DBMS_OUTPUT.PUT_LINE('Average'); -- グレードが'C'の場合の処理
        ELSE 
            DBMS_OUTPUT.PUT_LINE('Poor'); -- それ以外の場合の処理
    END CASE; -- CASE文の終了
END;

```

### ベストプラクティス
- 条件分岐やループは必要最低限に。
- 複雑な条件やループのネストを避ける。
ファイルのunlink C言語

Cプログラム内でのファイル削除はどうやってやるか。
unlinkを使います。unlinkはunistd.hというヘッダをincludeする。

```unlink.c
#include    <stdio.h>
#include    <stdlib.h>
#include    <unistd.h>
void main(int argc,char *argv[]) {
    int r;
    if (argc!=2) {
        fprintf(stderr,"Invalid argument.\n");
        exit(-1);
    }
    r=unlink(argv[1]);
    if (r==0) {
        printf("file successfully unlinked.\n");
    }
    if (r==-1) {
        printf("file unlink failed.\n");
    }
    exit(0);
}

```

./unlink filenameとして使います。
削除成功の場合、file successfully unlinked.
失敗の場合、file unlink failed.というメッセージが出て終了します。
レンタルバ予測予測

import pandas as pd
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.metrics import mean_squared_error, r2_score
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt

# データの読み込み
train_data = pd.read_csv('hour_train.csv')
test_data = pd.read_csv('hour_test.csv')

# 'season'と'weathersit'をダミー変数に変換
train_data = pd.get_dummies(train_data, columns=['season', 'weathersit'], drop_first=True)
test_data = pd.get_dummies(test_data, columns=['season', 'weathersit'], drop_first=True)

# トレーニングデータとテストデータでのダミー変数の列を一致させる
train_columns = set(train_data.columns)
test_columns = set(test_data.columns)
missing_in_test = train_columns - test_columns
missing_in_train = test_columns - train_columns

for col in missing_in_test:
    test_data[col] = 0
for col in missing_in_train:
    train_data[col] = 0

# 列を揃えるために並べ替え
train_data = train_data.sort_index(axis=1)
test_data = test_data.sort_index(axis=1)

# 特徴量とターゲット変数の設定
features = ['temp', 'atemp', 'hum', 'yr', 'mnth', 'hr', 'holiday', 'workingday'] + \
           [col for col in train_data.columns if col.startswith('season_') or col.startswith('weathersit_')]
target = 'cnt'

X_train = train_data[features]
y_train = train_data[target]

# データの標準化
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)

# GBDTモデルの作成
model = GradientBoostingRegressor(random_state=42)

# クロスバリデーションによるモデルの評価
cv_scores = cross_val_score(model, X_train_scaled, y_train, cv=5, scoring='neg_mean_squared_error')
mean_cv_mse = -cv_scores.mean()
mean_cv_r2 = cross_val_score(model, X_train_scaled, y_train, cv=5, scoring='r2').mean()

print(f'Cross-Validation Mean Squared Error: {mean_cv_mse:.2f}')
print(f'Cross-Validation R^2 Score: {mean_cv_r2:.2f}')

# データの分割（トレーニングとバリデーション用）
X_train_split, X_val_split, y_train_split, y_val_split = train_test_split(X_train_scaled, y_train, test_size=0.2, random_state=42)

# モデルのトレーニング
model.fit(X_train_split, y_train_split)

# バリデーションデータでの予測
y_val_pred = model.predict(X_val_split)

# バリデーションデータでの評価
print(f'Validation Mean Squared Error: {mean_squared_error(y_val_split, y_val_pred):.2f}')
print(f'Validation R^2 Score: {r2_score(y_val_split, y_val_pred):.2f}')

# テストデータでの予測
X_test = test_data[features]
X_test_scaled = scaler.transform(X_test)
y_test_pred = model.predict(X_test_scaled)

# テストデータの実際の値
y_test_actual = test_data[target]

# テストデータの評価
test_mse = mean_squared_error(y_test_actual, y_test_pred)
test_r2 = r2_score(y_test_actual, y_test_pred)

print(f'Test Mean Squared Error: {test_mse:.2f}')
print(f'Test R^2 Score: {test_r2:.2f}')

# 予測値と実際の値の散布図を作成
plt.figure(figsize=(10, 6))
plt.scatter(y_test_actual, y_test_pred, alpha=0.5)
plt.xlabel('Actual Count')
plt.ylabel('Predicted Count')
plt.title('Actual vs Predicted Count')
plt.plot([y_test_actual.min(), y_test_actual.max()], [y_test_actual.min(), y_test_actual.max()], 'k--', lw=2)
plt.grid(True)
plt.show()