OmniAICreator/Qiita-1.07M huggingface dataset:
Python の ConfigParser を利用した設定管理クラスのテンプレート

## 概要

自分がよく使う Python の`ConfigParser`を使用して設定ファイルを読み込むための基本的なクラスの実装を共有します。
設定ファイルは `.ini` ファイルで、指定されたパスから読み込めます。

自分の過去記事ですが、それらを応用しています。

https://qiita.com/p-marry/items/266092a95eed54ff7f7a

https://qiita.com/p-marry/items/d0cca2baead0705ae947

## 前提条件

### ディレクトリ構造

以下のディレクトリ構造を想定しています。
`main.py`と`config`フォルダを同じフォルダに配置しています。

```bash
MyProject/
├── myproject/
│   ├── config/
│   │   └─── settings.ini
│   ├── main.py
│   └── core/
│       ├── __init__.py
│       └─── config_loader.py
```

### 設定ファイルの例 (settings.ini)

```ini
[DEFAULT]
setting1 = value1
setting2 = value2

[section1]
key1 = value1
key2 = value2
```

### Python コード

#### `main.py`

```py
import os
import sys

# フォルダの親ディレクトリをパスに追加する
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

from myproject.core.config_loader import ConfigLoader

# ConfigLoaderのインスタンスを作成
loader = ConfigLoader()
# 読み込んだ設定を格納する
settings = loader.settings

# 設定を利用する例
# DEFAULTセクションのsetting1の値を表示
print("Setting 1:", settings["DEFAULT"]["setting1"])
```

#### `core/config_loader.py`

```python
import os
import sys
from configparser import ConfigParser


class ConfigLoader:
    """
    設定ファイルを読み込むためのクラス。
    インスタンス化時にconfig_pathで指定した設定ファイルをロードする。
    デフォルトの設定ファイルは "config/settings.ini"。
    """

    def __init__(self, config_path: str = "config/settings.ini"):
        # 実行環境に基づく基準パスを取得する
        self.base_path = self.fetch_base_path()
        # 設定ファイルを読み込み、設定情報を保持する
        self.settings = self.load_settings(config_path)

    def fetch_base_path(self) -> str:
        """実行環境に応じた基準パスを取得する"""
        # アプリケーションがfrozen状態（PyInstallerなどでパッケージ化）かどうかを判定
        if getattr(sys, "frozen", False):
            # パッケージ化されている場合は実行ファイルのディレクトリを返す
            return os.path.dirname(sys.executable)
        else:
            # パッケージ化されていない場合は、スクリプトの親ディレクトリを返す
            return os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

    def load_settings(self, config_path: str) -> ConfigParser:
        """設定ファイルを読み込み、ConfigParserオブジェクトを返す"""
        # 設定ファイルのフルパスを作成
        full_config_path = os.path.join(self.base_path, config_path)
        # 設定ファイルが存在するか確認
        if os.path.exists(full_config_path):
            # 設定ファイルを読み込み、ConfigParserオブジェクトを返す
            parser = ConfigParser()
            parser.read(full_config_path, encoding="utf-8")
            return parser
        else:
            # 設定ファイルが存在しない場合、FileNotFoundErrorをスローする
            raise FileNotFoundError(f"設定ファイルが見つかりませんでした: {config_path}")
```

## 使用方法

1. `settings.ini` を作成し、必要な設定を記述します
2. `main.py` を実行し、`ConfigLoader`をインスタンス化します
3. `settings`変数を通じて設定値にアクセスできるようになります
    - 例: `settings["DEFAULT"]["setting1"]`のようにアクセスできます

## 注意点

-   設定ファイルのパスが正しいことを確認してください。デフォルトでは`config/settings.ini`が指定されています
-   設定ファイルの形式は`.ini`ファイルである必要があります
-   設定ファイルが存在しない場合、`FileNotFoundError`が発生します。状況によって適切なエラーハンドリングを行ってください
データベーススペシャリスト試験(DB)を受験した(追記:合格した)

## 1. はじめに

今月、データベーススペシャリスト試験を受験しました。この記事は、**試験合格のための勉強法を紹介するものではありません**ので、ご了承ください。

~~ 追記 ~~
無事に合格していました！

## 2. 対象読者

- データベーススペシャリスト試験に興味のある方
- IPAが主催する国家試験に興味のある方

## 3. 目次

- [1. はじめに](#1-はじめに)
- [2. 対象読者](#2-対象読者)
- [3. 目次](#3-目次)
- [4. 自己紹介](#4-自己紹介)
- [5. データベーススペシャリスト試験について](#5-データベーススペシャリスト試験について)
- [6. 勉強期間](#6-勉強期間)
- [7. 受験のきっかけ](#7-受験のきっかけ)
- [8. 学んだこと](#8-学んだこと)
- [9. さいごに](#9-さいごに)

## 4. 自己紹介

以前受けた応用情報技術者試験の記事を自己紹介を兼ねて紹介します。こちらの記事に簡単な自己紹介も記載していますので、良ければご覧ください。

[応用情報技術者試験の経験談](https://qiita.com/aosan/items/85e4d43d07c05c7aeb4a)

## 5. データベーススペシャリスト試験について

データベーススペシャリスト試験について簡単にご紹介します。

**データベーススペシャリスト試験**は、IPA（独立行政法人情報処理推進機構）が主催する国家試験で、一度合格すれば、資格は**一生有効**です。

試験は、午前I・IIがマークシート、午後I・IIが記述式です。詳細は以下のリンクからご確認ください。

[データベーススペシャリスト試験概要](https://www.ipa.go.jp/shiken/kubun/ap.html)

また、データベーススペシャリスト試験を含む高度情報処理試験では午前Iの免除制度があり、私は昨年応用情報に合格していたため、この免除を利用しました。

[高度区分試験の免除制度](https://www.ipa.go.jp/shiken/about/koudo_menjo.html)

## 6. 勉強期間

試験勉強は**6月頃から始め、約4か月間、毎日1時間ほど**取り組みました。最初の1か月は参考書を読み、午前IIの問題を中心に勉強し、その後は過去問を中心に午後試験の対策を行いました。特に午後IIの試験は1問が2時間かかり、非常に大変でしたが、試験直前にはある程度解けるようになりました。

過去問は4年分を約2回ずつ解きました。以下に、使用した参考書やサイトを紹介します。

- **参考書**
  - [徹底攻略 データベーススペシャリスト教科書 令和6年度版](https://book.impress.co.jp/books/1123101134)
- **午前II対策**
  - [データベーススペシャリスト過去問道場](https://www.db-siken.com/dbkakomon.php)
- **午後I・II対策**
  - [過去問題・回答](https://www.ipa.go.jp/shiken/mondai-kaiotu/2024r06.html)
  - [過去問題答案用紙](https://www.itec.co.jp/learning_download#db02)
  - 参考書の特典で過去問の解説を利用

## 7. 受験のきっかけ

今回の試験を受けた理由は、業務でデータベース設計を行う際に、経験に頼った曖昧な知識に限界を感じたためです。例えば、以前担当したプロジェクトでは、設計の判断に迷い、確信が持てないまま進めた結果、後になって追加開発が難しい設計になっていることに気づきました。そうした課題を解消し、体系立てて論理的に学び直したいという思いが、受験の動機となりました。

## 8. 学んだこと

今回の試験勉強で特に勉強になったのは、データベース設計の基本的な概念です。正規化やインデックスなどの論理・物理設計について学びながら、業務にどう活かすかを考えました。

また、これまでは意識していなかったDBMSの詳細についても学ぶことができました。トランザクションの隔離レベルやログファイルの役割について理解が深まり、今後業務での活用を考えています。

午後試験では、仕様書から論理設計を行う問題が出題されますが、これは業務内容に近く、**短時間で多くの設計を体験する良い機会**となりました。過去の問題は多様なシステムを題材にしており、非常に勉強になりました。

例えば、令和5年度の午後II-2では「ドラッグストアチェーンの物流システム」、令和4年度の午後II-2では「フェリー会社の予約システム」のデータベース設計が題材となっていました。

## 9. さいごに

試験勉強は大変でしたが、学びたかったことを体系的に学べたことは非常に有益でした。実務で役立つ知識を得る一方、試験の枠組みから逸れないように注意する必要があり、そのバランスが難しかったです。
管理者権限がない場合のSSLエラー回避方法

## 自分の環境
- Fedora OS
- 自分には管理者権限がない
- venvで作成した仮想環境内において，pipを用いてライブラリをインストールしようとした際，下記のエラーが出た

## 発生した問題
SSL証明書の問題によりpipがHTTPSを通じてパッケージをダウンロードできない．

エラー内容
```　
Could not fetch URL https://pypi.org/simple/setuptools/: There was
a problem confirming the ssl certificate:HTTPSConnectionPool(host='pypi.org', port=443):
Max retries exceeded with url: /simple/setuptools/ (Caused by SSLError("Can't connect to HTTPS URL because the SSL module is not available.")) - skipping


```

## 解決方法
管理者権限がないため，OpenSSLをローカルユーザー環境にインストールし、PythonがSSLを使用できるように構成することでSSLエラーを回避する．

まず，OpenSSLのファイルをインストールしたい階層まで行きます．どこでも大丈夫です．

### ステップ1
OpenSSLのソースコードをダウンロード
``` bash:bash
wget https://www.openssl.org/source/openssl-1.1.1.tar.gz
```
最新版はこちら（https://openssl-library.org/source/ ）からご確認ください．

### ステップ2
ソースコードの解凍とディレクトリ移動
```bash:bash
tar -xf openssl-1.1.1.tar.gz
cd openssl-1.1.1
```
### ステップ3
インストール先を指定してコンパイル
```bash:bash
./config --prefix=$HOME/openssl --openssldir=$HOME/openssl
make
make install
```
これで$HOME/openssl以下にOpenSSLがインストールされます．

### ステップ4
PythonにSSLを認識させる
Pythonが新しいOpenSSLを認識するように環境変数を設定します．
```bash:bash
export LD_LIBRARY_PATH=$HOME/openssl/lib:$LD_LIBRARY_PATH
export PATH=$HOME/openssl/bin:$PATH
```

これで問題なく，pip install が使えるようになります．
Firebaseの環境を構築してデプロイしてみる

Firebaseの環境を構築し、Reactアプリケーションをデプロイした際の手順を記録しておく。

## Firebaseの環境構築
FirebaseのWebサイトからプロジェクトを予め作成しておく。
プロジェクト側にFirebase関連パッケージを導入し、初期設定を実施する。
下記の作業はプロジェクトルートで実施する。

```
# firebaseパッケージのインストール
❯ npm install firebase

# firebase-toolsのインストール
❯ sudo npm install -g firebase-tools

# firebaseへのログイン。質問は下記の通り回答した。
❯ firebase login
 
? Allow Firebase to collect CLI and Emulator Suite usage and error reporting
information? Yes

# 表示されるURLにアクセスして認証を実施する。
Visit this URL on this device to log in:
(省略)

# プロジェクトのルートディレクトリに移動してfirebaseの初期化を実施。
# 色々聞かれるので答えていく。
❯ firebase init

=== Project Setup

# 新規に作るか既存のプロジェクトを使うか聞かれるので、既存のプロジェクトを選択。
? Please select an option:
Use an existing project

# Firebaseで作成したプロジェクトを選択。
? Select a default Firebase project for this directory:
studytimeapp-339a8 (StudyTimeApp)

=== Hosting Setup
# デフォルトを選択。
? What do you want to use as your public directory?
public

# Reactを利用するのでYes
? Configure as a single-page app (rewrite all urls to /index.html)?
Yes

# GithubにPushした際に自動的にFirebaseにデプロイする場合はYes。
# Githubへの認証を表示されたURLから実施する。
? Set up automatic builds and deploys with GitHub?
Yes

Visit this URL on this device to log in:
(省略)

# プロジェクトのリポジトリを指定。
? For which GitHub repository would you like to set up a GitHub workflow?
(format: user/repository)
(省略)

# デプロイする前にビルドする場合はYes
? Set up the workflow to run a build script before every deploy?
Yes

# ビルド時の実行コマンドを指定。デフォルトのまま。
? What script should be run before every deploy?
npm ci && npm run build

# PullRequest時に本番サイトにマージするか。Noを選択。
? Set up automatic deployment to your site's live channel when a PR is merged?
No

✔  Firebase initialization complete!
```

デプロイできることを確認する。
下記コマンドでpublic以下の内容をデプロイする。
URLが表示されるので、アクセスしてfirebaseに正しくデプロイできていることを確認する。
```
❯ firebase deploy
```

続いて、自分で作成したアプリケーションをデプロイする。
まずは、アプリケーションのビルドを実施。
```
❯ npm run build
```
`dist`ディレクトリにビルド結果が格納される。
`firebase.json`を変更して、`dist`以下がデプロイされるようにする。

```json:firebase.json (抜粋)
{
  "hosting": {
    "public": "dist", // distへ修正
    (省略)
    }
}
```

以下のコマンドを実行して、ローカル環境で確認可能。
表示されたURLからブラウザで確認可能。
```
❯ firebase emulators:start
```

問題なければFirebaseにデプロイする。
表示されたURLにアクセスして問題ないことを確認する。
```
❯ firebase deploy
```

使用しない場合は無効化しておくと良い。
```
❯ firebase hosting:disable
```

Firebaseの初期化時に指定したGithubリポジトリにPushすると自動的にデプロイされる。

## 参考

https://zenn.dev/conecone/articles/058755b87fec41

https://zenn.dev/tentel/articles/488dd8765fb059
福岡出身システムエンジニア誕生記(フリーランスになるまで)

# はじめに

初めまして、自己紹介させていただきます。

1995年生まれ福岡出身フリーランスエンジニアです。
先日福岡に帰省して、いろいろ自分のこと振り返るの大切だなとおもい、
今回記事を書くことを決断しました。

普通の人間がフリーランスになって生活しているという一例をシェアできたらとおもいます。
誰かの参考になれば幸いです！

今回は就職してから1年目の自分のことについて書いてみようと思います。

# 目次
少し細かく振り返りながら記載するので複数記事書く予定です！
##### ・学生~就活編⇒https://qiita.com/Yutajino/items/bf074102e254457af934
##### ・1年目前半編⇒本記事
##### ・1年目後半編⇒https://qiita.com/Yutajino/items/a4f3ac0e4f6821a3b264
##### ・2年目前半編⇒https://qiita.com/Yutajino/items/fccb4ce3c38186d0eb3b
##### ・3年目編⇒完成次第リンク貼ります
##### ・フリーランス~失敗編⇒完成次第リンク貼ります
##### ・失敗~現在編⇒完成次第リンク貼ります


# 内定をもらってから就職までの間
内定をもらってから、会社から基本情報技術者試験の勉強をしておくように
連絡がありました。
入社して一ヶ月で強制的に基本情報技術者試験を受けることになっており、
それに向けて勉強を各々でやっておくように言われてました。

情報系のことを全く理解していなかった自分は、
一旦、内定先からお勧めされたやり方と、教材があったので、やる準備だけはしっかり整えました。

①「イメージ＆クレバー方式でよくわかる 栢木先生の基本情報技術者教室 (情報処理技術者試験)」
https://amzn.asia/d/cORZKsJ

②過去問道場
https://www.fe-siken.com/fekakomon.php

が、残り学生を楽しもうとしすぎて、
ほとんどやってませんでした笑

過去問道場の結果を添付するように言われていたのですが、
毎回6割切るくらいの成績を送っており、
ちゃんと勉強していないのがバレバレの新入社員だったと思います。

入社式3~4ヶ月前に内定者同士の交流会が開催されました。
どんな内定者がいるのかとワクワクもありましたが、
就活をまともにやっていないという負い目があり、
レベルの高い人たちが集まってるかもなと不安も大きかったです。

僕の同期はみんな個性的な方ばかりで、

データ大好き関西人
柔道日本全国レベル選手
音楽家
虫の研究をしていた人

他色々な人がいて面喰らったのを覚えてます。

一番インパクトあったのは、
まだ正式に入社していないのに、
同期同士で、いつ辞めるかを話していたことです笑
※社員さんに聞かれたら怒られるやつです

入社して、ほっとしていた自分に
将来的なことを考えた方がいいよと一石投じられた気分でした。

不安を抱えながら大学を卒業してそのまま入社式に向かってました。

# 就職一年目
個性的な方が多い印象をうけたので
最初の一年目、
自分は社会人としてスタートダッシュを決めてやろうと考えてました。

自分が未経験で今できることは何か考えた結果、
「真面目に研修受けること」
「基本情報技術者試験に合格すること」
「Oracle Bronzeを取得すること」
この三つはしっかりやろうと思いました。

入社して、1~2ヶ月間の研修の間、
エンジニアとしての基礎基本の話、Excelの使い方などまなびつつ
仕事終えてからは、参考書を毎日数ページでもいいから読むこと
過去問道場を電車の移動中に解くことを繰り返しました。

結果、基本情報技術者試験に無事合格して
研修期間を終えることができました。

Oracle Bronzeも緊張しまくってましたが、
無事に合格することができました！
Oracle Bronzeは、下記の本使ってました。
https://amzn.asia/d/35osGFB
https://amzn.asia/d/hdsnnpn

こちらも問題を何回も解くことと、本を5周くらい読み返すことをやってました。

# Let's go プロジェクト
研修期間を終えてからすぐにプロジェクトにアサインされました。

早速、資格取得のために勉強した知識が生かせるのかと思いワクワクしてましたが、
BIツールの改修メインの案件だったので、SQLの知識を少し使いながら案件進めていきました。

プロジェクトリーダーに守られながら最初の案件は無事完遂。

続く二つ目の案件は、SQLのコード改修の案件
資材の改修は無事に終えて、
現地に行ってテスト実施していたのですが
若干の不具合が発生してました。

SQLで取得したデータの項目と
データ投入先のテーブルの項目で
不一致が起こっていました。

本来なら上司に報告することが必須です。
が、自分の力を過信して、なんとかすることが大事だと考えてしまい、
無理やりデータを書き換えて、
データ投入できたということで進めてしまいました。

結果として、
現地作業を終えた後日に指摘があり
修正対応をして事なきを得ましたが、
上司にしっかり怒られました。

報連相の大事さを痛感させられたプロジェクトでした。
一年目の上期はエンジニアとしてのほろ苦デビューでした。

# あとがき
・基本情報技術者試験は、とにかく過去問道場を解く！
・研修期間に受けた基礎基本は、後から、学んで良かったと思うことが多い！
　しっかりやっておくとお得！
・エンジニアなりたての時は、失敗したら、まず上司に報連相！
　⇒失敗する前にやり始めで相談に行くのが一番いい！
【Rails】RAILS_DEFAULT_LOGGERを使用できない

## はじめに
Railsのアップデート中にRAILS_DEFAULT_LOGGERを使用している箇所でエラーが出たので、その対応をまとめます。

## 問題
コード
```ruby
RAILS_DEFAULT_LOGGER.info "xxx"
```

エラー文
```ruby
uninitialized constant RAILS_DEFAULT_LOGGER
```

## 解決方法
以下のように修正します。
```ruby
Rails.logger.info "xxx"
```

## 参考
https://stackoverflow.com/questions/11585296/uninitialized-constant-rails-default-logger
AtCoder ABC377 復習(緑コーダーがPythonでA〜C問題まで)

## ABC377 感想まとめ

[トヨタシステムズプログラミングコンテスト2024（AtCoder Beginner Contest 377) - AtCoder](https://atcoder.jp/contests/abc377)

このところ出かけていたり、心身が不調だったりで2週ほどサボっていました。今回もリアルタイム参加はできなかったのですが、一応復習はしておこうということで、問題を解いてみました。

## [A - Rearranging ABC](https://atcoder.jp/contests/abc377/tasks/abc377_a)

入力文字列 S の中に、A B C が各1個ずつあれば、Yesになります。

``` python
S = input()
if S.count("A") == 1 and S.count("B") == 1 and S.count("C") == 1:
    print("Yes")
else:
    print("No")
```

## [B - Avoid Rook Attack](https://atcoder.jp/contests/abc377/tasks/abc377_b)

ちょっと解き方で悩みました。マスのサイズが8x8と少なめなので、64個の全マス(i,j)について、

* i行に#があるか
* j列に#があるか

を、そのつど調べるようにしました。

``` python
N = 8
S = []
for i in range(N):
    S.append(list(input()))

count = 0
for i in range(N):
    # i行に#があるか
    if S[i].count("#") > 0:
        continue
    
    # j列に#があるか
    for j in range(N):
        exist = False

        for k in range(N):
            if S[k][j] == "#":
                exist = True

        if exist == False:
            count += 1

print(count)
```

:::note info
たぶん、"#"がある行/"#"がある列 を 配列とかsetとかで持っておいて、判定するほうが簡単にかけて処理回数も少ないと思います。。
:::

## [C - Avoid Knight Attack](https://atcoder.jp/contests/abc377/tasks/abc377_c)

Bにつづいて、チェスのような問題。今回はマスの数が最大 10^9 四方なので、計算速度に気をつける必要があります。

この問題は、以下のような方針で解答しました。
* コマの動ける方向を moves として定義
* 各コマが置いてある座標を false_set に記憶していく
* 各コマが動ける座標を false_set に記録していく
* 「全マスの数(N * N) - false_set の数」 で最終的な答えが求まる


``` python
N, M = map(int, input().split())

false_set = set() # 空でないマスの座標を記録

# コマが動ける座標
moves = [(-1, -2), (1, -2), (-2, -1), (2, -1), (-2, 1), (2, 1), (-1, 2), (1, 2)]

for i in range(M):
    a, b = map(int, input().split())
    # すでに置かれている
    false_set.add((a, b))

    # 8方向に移動できる。移動先はfalse_setに追加
    for move in moves:
        x = a + move[0]
        y = b + move[1]
        if 1 <= x <= N and 1 <= y <= N:
            false_set.add((x, y))

# 空のマスの数 = 全マスの数(N * N) - false_setの数
answer = N * N - len(false_set)
print(answer)
```

## [D - Many Segments 2](https://atcoder.jp/contests/abc377/tasks/abc377_d)

これは考えたのだけど、解答にはたどり着けず...。左端を固定すると良さそうだな、というのところまではわかったのですが...。

公式の解説動画を見て勉強しようと思います。

[トヨタシステムズプログラミングコンテスト2024（AtCoder Beginner Contest 377) - YouTube](https://www.youtube.com/watch?v=3QmnKGV0scU)
Scala で LeetCode を解いてみた感想

Scala を手に馴染ませるために 100問ほど解いた。
気がついたことを雑にメモる。

## 1. map / foreach 関数 と pattern matching の相性が良い

コードを綺麗にかける。

例: [1047. Remove All Adjacent Duplicates In String](https://leetcode.com/problems/remove-all-adjacent-duplicates-in-string/description/)

```scala
val stack = mutable.Stack[Char]()

s.foreach({
    // pattern matching anonymous function を使って
    // `c match {` が省略できた。
    
    case char if stack.isEmpty => stack.push(char)
    case char if stack.top == char => stack.pop
    case char  => stack.push(char)
  }
})
```


## 2. 関数型で処理を書く際には、foldLeftが活躍する

例: array の各要素を mapに追加する

```scala

array.foldLeft(Map())((map, keyValPair) => {
    val (key, value) = keyValPair
    map.updated(key, value)
})
```

## 3. `mutable.PriorityQueue` は max heap

Python の `heapq` は min heap だった。

## 4. バイナリサーチを自前実装しなければいけないケースが多い

`IndexedSeq#search` は要素が整列されている前提で、バイナリサーチを使って要素を探してくれる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534442/b0c131d9-b670-fa99-c107-607082d82af5.png)

しかし、これには柔軟性があまりない。
例えば、一見 Python の `bisect_left` に挙動が近いが、探している値が複数個存在する場合に、最初のインデックスが返ってくる保障はない。

細かいロジックを実現したい場合は、自前でバイナリサーチを実装する必要がある。

## 5. Ordering オブジェクトの自前実装

PriorityQueue, Sorting, Binary Search などで使用する要素に対して独自の順位付けをしたい時に実装する必要がある。

例えば以下。

```scala
implicit object ordering extends Ordering[(Int, Int)] {
    override def compare(x: (Int, Int), y: (Int, Int)): Int =
        if (x._1 != y._1) y._1 - x._1
        else x._2 - y._2
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534442/6315e8ae-c1dd-3404-7f01-658b9b28ae5e.png)


## 6. 冪乗の演算子は存在しない

2の5乗は、`2 ** 5`ではなく、`Math.pow(2, 5)`と書く。

## 7. 任意の数を底とする対数を求めるのにも一苦労。

log2 N は、 loge N / loge 2 であることを利用し、 `Math.log(10) / Math.log(2)`を使う。

## 8. 問題によっては答えを Long 型で返す必要がある

メソッドのシグニチャーで Long 型を返すように指定されているが、Int をリターンするコードを書いた場合、Int→Long の暗黙の型変換によりコンパイルは通ってしまうので注意が必要。

## 9. ループ内の continue が存在しない

flag や if文を使って制御しよう。

## 10. ループ内の break も存在しない

解決策(1). flagを使って制御する。

```scala
var finished = false

for (num <- nums if !finished) {
    ....
    finished = true
}
```

解決策(2). `breakable` を使う

```scala
import scala.util.control.Breaks._

breakable {
  for{num <- sortedNums} {
    if(max < num) break()
    println(num)
  }
}
```


## 11. for ループ内で early return できない

解決策の一つは、`boundary`を使うこと。

```scala
import scala.util.boundary, boundary.break

def hasTarget(nums: Array[Int], target: Int): Boolean = {
    boundary {
        for{num <- nums} {
            if(num == target) break(true)
        }
        false
    }
}
```

ちなみに、early return しようとすると以下のようなエラーが発される。
`non local returns` とのことなので、ラムダ関数の中から early return するのも不可能だという認識。

```scala
Line 13 Char 24: Warning (in solution.scala)
13 |      if (isInvalidRow) return false
   |                        ^^^^^^^^^^^^
   |Non local returns are no longer supported; use `boundary` and `boundary.break` in `scala.util` instead
```
【ポエム】新卒2年目のPoC案件挑戦記：生成AIとの向き合い方

# 新卒2年目のPoC案件挑戦記：生成AIとの向き合い方

**「エンジニアとしての成長と挑戦」–予想外のプロジェクトで感じた生成AIへの付き合い方**

大学で経営工学を学び、少しデータサイエンスにも触れていた私。データサイエンスは向いてないかもなぁ、と感じていた。
新卒でコンサル会社のSEとして就職し、PG、SE、PMOを経験し、ITの工程も要件定義~総合テストまでのある程度経験させてもらえていた。そんな中、突然、生成AIを使ったPoC案件に参画することになった。
<sub>（そんなに生成AIがすごく興味あるわけではなかった...。
むしろデータサイエンスをかじった経験から、軽く拒絶反応があった。
とはいえ、今はこの生成AIの動向を面白いと思って追っています。）</sub>


---

## 目次
- [案件の背景と開始](#案件の背景と開始)
- [生成AIとの向き合い方](#生成aiとの向き合い方)
- [3ヶ月で感じたエンジニアとしての成長](#3ヶ月で感じたエンジニアとしての成長)
- [まとめ](#まとめ)
- [この案件中に聴いてた曲](#この案件中に聴いてた曲)

---

## 案件の背景と開始
お客様からのご依頼は、「生成AIを使って何か面白いことをしてほしい」という、かなり抽象的なもの。最初は私自身、生成AIに感情を教えるくらいの意気込みで臨んだものの、実際にはシステムの方向性を模索するところから始まった。

何をしたかについては公開できませんが、生成AIを用いたETL-RAGを行った。  
特にETL処理プロセスの中で痛感したのは、生成AIの力を引き出すためには、こちらの意図や期待値を明確にすることが非常に大切だということ。

## 生成AIとの向き合い方

生成AIはただの高度な検索ツールとしても、あるいは「自分の思考を整理し、目的に向かって論理的に進むためのパートナー」としても活用できる。しかし、どちらの使い方であれ、結局は **「自分がどうしたいのか」の解像度を上げる** ことが必要だと感じた。

曖昧な指示を出すと、曖昧な答えしか返ってこないため、現状把握とゴールをしっかり明確にし、生成AIに対して何を期待するかを具体的に伝えることが求められる。プロンプトチューニングといったテクニックもあるが、それ以前に **「自分が本当に求めているものを整理し、明確にする」** 姿勢が、生成AIを使いこなすための鍵だと感じた。

そのため、細かいtipsなども参考にしつつ、何より **「自分が何を実現したいか」の解像度を上げること** が欠かせないと強く感じている。



## 3ヶ月で感じたエンジニアとしての成長
このPOC案件を通じて、振り返ると成長を実感する場面がいくつかあった。特に自分でも実感している成長ポイントを挙げていく。

1. ### 新しい技術に対する「免疫力」の向上
   最初は生成AIの話がきたときに「どうやるんだ？」って正直思ったが、やり始めると意外とイケると感じた。未知の技術に対する心理的な抵抗が薄れ、今は「とりあえず触ってみよう！」というスタンスになった。

2. ### ふわっとしたタスクを形にする力
   お客さんの要望が抽象的なまま進むことも多く、「結局何をすればいいの？」となることが多かったが、今はそれを何とか具体化して、形にするまでが早くなった気がする。

3. ### 成果が出にくい環境での粘り強さ
   PoC案件だからこその「成果が出にくい環境」もあり、長時間労働に対する耐性がついたのも成長ポイント。試行錯誤を何度も繰り返す場面が多く、集中力と粘り強さがこれまで以上に必要だった。今後のプロジェクトでも、この耐性は強みになりそう。

4. ### 問題解決の「型」が身についた
   現状を把握してゴールを設定して、それに向かっていくプロセスを整理するという流れが、かなりスムーズにできるようになってきたと感じる。いわば「考える型」みたいなものが自然に身についてきたので、複雑な問題に直面しても落ち着いて進められるようになったと思う。

---

## まとめ

今回のPoC案件を通して、生成AIとの向き合い方や自分自身の成長を感じた3ヶ月だった。生成AIをただのツールとしてではなく、プロジェクトを成功させるためのパートナーとして捉え、問題解決や目的に向かう力もついた。  
この挑戦記が、新しいフィールドで奮闘するエンジニアの皆さんの参考になれば幸いです。


<sub>※これはChatGPTに音声で私の思っていることや具体的な指示をして、この記事を書き上げました。</sub>

---
## この案件中に聴いてた曲
最後に私がこの生成AI案件の期間中によく聴いた曲紹介します。

生成AIに触れまくっている日々だからこそ芽生えた、私の中の生成AIに対するアンチテーゼが、この曲に乗って共感と反骨心が生まれ、そしてその感情を強くしたのだと思います。（長時間労働の反動かもしれませんがね笑）

布袋寅泰/HOTEI Andromeda (feat. アイナ・ジ・エンド）
https://youtu.be/LwORYn29ynw?si=RyrgoXF5QNY0eHTM
S3+Athena+TROCCOで爆速データ分析基盤立ち上げレシピ

データ分析したいけど、DWH(データウェアハウス)を導入するとなると大げさだなぁ、くらいのタイミングでライトに始められるデータ分析基盤を考えてみました。

# アーキテクチャ

![スクリーンショット 2024-10-29 19.20.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3511608/d49aca72-d353-fcdd-13ed-c94d63e05363.png)

Amazon AthenaはS3上のファイルに直接クエリできて、スキャン量のみのオンデマンド課金なのでランニングコストがかからず、今回の目的に合致していそうです。

本記事ではデータマート作成までを扱います。

# データレイク構築

S3へのデータ収集手段として、無料プランのあるTROCCO® を利用します。

https://trocco.io/lp/index.html

TROCCOのデータ転送先として「S3」とは別に「S3 parquet」という選択肢があります。
こちらは、ファイル形式をparquetに変換してくれるだけでなく、裏側でAWS GlueのジョブをキックしAthenaで参照できるカタログを自動生成してくれる便利機能が備わっています。

HTTP APIで取得できるオープンデータを使って、データ収集を試してみましょう。

https://spec.api.metro.tokyo.lg.jp/spec/t000002d0000000002-29f86c12fe08632ae141b9de48b558f5-0

![スクリーンショット 2024-10-29 19.32.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3511608/c99075a1-474d-db94-eec6-6391260cd7da.png)

公式ドキュメントに従って転送元/転送先の情報を入力していきます。

転送設定作成フォームのStep2 にて「出力オプション」のタブを選択すると、「データカタログの設定」という項目があります。こちらを有効化することで、Glueカタログジョブを自動実行することが可能になります。

![スクリーンショット 2024-10-29 19.55.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3511608/501f5de2-de20-7d98-b405-7dadbafc0f41.png)

データ転送を実行すると、Athena上でテーブルが作成されクエリ可能になります。

![スクリーンショット 2024-10-17 20.43.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3511608/dc31cf12-2f60-7766-4cd9-718700816cd7.png)

# データマート化

転送元: Athena を指定すると、Athenaに対してクエリした結果を転送先に送ることができます。

![スクリーンショット 2024-10-17 20.51.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3511608/86da9542-e088-c069-2eda-6e5730a9c146.png)

複数のテーブルを結合するなど、SQLを用いた柔軟なデータ加工が可能です。
クエリ結果は先ほどと同様に、再度S3に配置しGlueカタログ化します。

![スクリーンショット 2024-10-17 20.42.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3511608/e6c5b7c7-97ee-d77d-42e1-a285aa9cc775.png)

加工後のデータもAthena上でクエリできました。

# データパイプライン管理

Lake→Martの2つの処理を直列に配置します。

![スクリーンショット 2024-10-29 19.40.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3511608/3c746f26-fae8-3a08-cc41-ee9fb35b50ab.png)

データソースからのデータ取得が完了すると、後続の集計処理が自動で実行されます。
ワークフローにスケジュール設定を追加することで、毎日最新のデータをマートテーブルに反映することができます。

# まとめ
S3をベースに、クイックに一定のスケーラビリティを持ったデータ活用環境を立ち上げることができました。
parquetデータ形式は列志向で圧縮効率に優れ、大規模なデータセットにおける分析利用にも対応しやすいフォーマットです。

Icebergテーブルの実データ形式としても採用されているため、今回構築したS3上のデータをIceberg化して別サービスから参照するような形を取れば、スムーズに中〜大規模なアーキテクチャへも移行していけそうですね。
dbtのcustom generic testを実装してみた

# dbtのcustom generic testを実装してみた
## generic testとはなにか
dbtのテストは以下の３種類が存在しています。
1. generic test
1. singular test
1. unit test

## generic testの考え方

generic testは特定のmodel、columnに対して、データのテストを行います。
エラーデータを抽出するためのSELECT文を書き、実際にデータが抽出されたらエラーを検出します。

個人的な理解だと「テスト用の関数」です。

## SELECT文の書き方

例えば、特定のカラムが正の数であることを保証するテストは以下のように作成します。
SELECT文は、0以下の値を持つレコードが抽出されるように条件を追加します。
```sql
select * from {{model}}
where {{column_name}} <= 0  -- 0以下の値が抽出されるようにする
```

{{model}} {{column_name}} については現段階ではスルーしてください。

## generic testを定義するファイル作成
実際にはSELECT文だけではなく、以下のようにdbt用のおまじないを付け足します。

```sql
{% test myTest(model, column_name) %}
    select * from {{model}}
    where {{column}} <= 0  -- 0以下の値が抽出されるようにする
{% endtest %}
```

これを「.sql」の拡張子で指定したフォルダに配置します。

ここでは、myTest.sqlという名前にします。

## sqlファイルを置く場所
作成したmyTest.sqlを以下の場所に配置します。

> dbt/*tests*/generic

「tests」はデフォルトの位置です。
変更したい場合は、「dbt_project.yml」の以下のセクションで指定します。

> test-paths: ["tests"]

ここまで出来たらcustom generic testの定義は完成です。

## 実際にテストをする
次は、テストの適用方法です。
modelを定義するymlに以下のように記載をします。

```yaml
version: 2
models:
  - name: test_object
    columns:
      - name: TEST_ID
        description: ''
        data_type: INT
        tests: 
          - myTest
```

このように記載すると、「myTest」のgeneric testに、test_objectというモデルのTEST_IDというカラムがテスト対象として指定されることになります。

> {% test myTest(model, column_name) %}
ここのmodel、column_nameに渡されてテストが実行されることになります。

実際にテストを実行してみると、以下のようにテストが実施され成功していることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974516/2b12f5cc-4076-9c44-ed67-761d520b29ec.png)

わざと失敗をするSELECT文に修正をしてテストを実行すると、このようにエラーが検出されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974516/a7ba0ea5-8794-91fc-79f7-8335ca5d8a94.png)

## 参考
- https://docs.getdbt.com/best-practices/writing-custom-generic-tests
-
ルーティングとNATの仕組み

## はじめに
1日1項目1時間学ぼうの会

今回のテーマは**ルーティングとNATの仕組みについて**です。

## ルーティング
ルーティングは、ネットワーク間でパケットを最適な経路に沿って転送するプロセスです。これにより、異なるネットワークに所属するデバイス同士が通信できます。主に以下の要素で構成されます。

### ルータの役割
- 経路決定: 送信元と宛先のネットワークアドレスに基づいて、ルータがどの経路を使うか決定します
- ルーティングテーブル: 各ルータはネットワーク内の経路情報を保持しており、その情報をもとにパケットを次の適切なルータへ転送します

### スタティックルーティングとダイナミックルーティング
- スタティックルーティング: 管理者が手動でルーティング経路を設定する方法です。小規模なネットワークで使用されます
- ダイナミックルーティング: ルータが自動的に経路を学習・更新する方法で、規模が大きいネットワークに適しています
主なプロトコル:
- RIP (Routing Information Protocol)
- OSPF (Open Shortest Path First)
- BGP (Border Gateway Protocol)

## NAT
NATは、プライベートネットワークのIPアドレスをグローバルIPアドレスに変換する技術です。これにより、LAN内部の複数のデバイスがインターネットに接続する際に、1つのグローバルIPを共有できます。

### NATの目的
- IPアドレスの節約: プライベートIPを使い、限られたグローバルIPを効率よく使います
- セキュリティの向上: プライベートIPが外部から見えないため、外部からの直接攻撃を防ぎやすくなります

### NATの種類
1.静的NAT (Static NAT)
- 1つのプライベートIPを1つのグローバルIPに固定的に割り当てます

2.動的NAT (Dynamic NAT)
- ライベートIPに対し、グローバルIPをプールから動的に割り当てます

3.PAT (Port Address Translation)（NAPTとも呼ばれる）
- 1つのグローバルIPに対して、異なるポート番号を使って複数のプライベートIPをマッピングします
- 一般家庭のルータや企業のネットワークで広く使用されます

 ## ルーティングとNATの連携
 - NATテーブル: NAT機器は、内部アドレスと外部アドレスのマッピング情報を保持します。外部から返ってくるパケットが正しい内部デバイスに戻されるように、NATテーブルが参照されます
- ルーティング後のNAT変換: パケットは、ルーティングで宛先ネットワークが決定された後、NATで変換されてインターネットへ送信されます

### NATテーブルとは
NATテーブル (NAT Table) は、ルータやファイアウォールなどのネットワーク機器が保持する内部データ構造で、プライベートIPアドレスとポート番号を、グローバルIPアドレスとポート番号に対応づけるために使用する。このテーブルにより、NATを通過する通信パケットの変換が正確に行われ。

## ルーティングテーブルとNATテーブルの違い
<table>

<thead>
<tr><th style="text-align:center;">項目
    <th style="text-align:center;">ルーティングテーブル
    <th style="text-align:center;">NATテーブル
<tbody>
<tr><td>目的<td>パケットの転送経路を決定する<td>プライベートIPとグローバルIPの変換を管理する
<tr><td>管理する情報<td>宛先ネットワークの経路<td>IPアドレスとポート番号のマッピング
<tr><td>主な役割<td>どの経路でパケットを転送するか判断する<td>内部と外部のIPアドレスを変換して通信を成立させる
<tr><td>使用される場所<td>ルータやL3スイッチ<td>NAT機能を持つルータやファイアウォール
<tr><td>使用するプロトコル<td>OSPF, RIP, BGP など<td>NAT, PAT (NAPT)
<tr><td>通信単位<td>ネットワーク単位でのルーティング<td>パケット単位でのIP変換とポート管理
</table>

## 参照
https://www.freshvoice.net/knowledge/word/6881/

https://www.netvisionacademy.com/column/5340/

https://shinmeisha.co.jp/newsroom/2020/02/17/nat%E3%81%A8%E3%81%AF/#google_vignette
micro:bit での typescriptとC++

# micro:bitにおけるC++の呼び出し（型変換）

C++の実装時に、型につまづくので、( ..)φメモメモ。

**ヒントはここにあります**

https://github.com/microsoft/pxt-common-packages/blob/master/libs/base/pxtbase.h


## 数値(Numberとint)

Numberとintとは、そのまま相互運用が可能。

## 数値(Numberとdoubleやfloat)

typescriptのNumberはdoubleの精度を持つ。

Numberは、TNumberに対応しており、double toDouble(TNumber)やfloat toFloat(TNumber)でC++の型に変換し、
TNumber fromDouble(double)やTNumber fromFloat(float)でNumber型に変換する。

:::note info
**typescriptでのテクニック：値が整数であるかどうか**

`value === (value | 0)`

```ts: radio.ts での実装例

    export function sendValue(name: string, value: number) {
        let packet: RadioPacket;

        if (value === (value | 0)) {
            packet = RadioPacket.mkPacket(PACKET_TYPE_VALUE);
        }
        else {
            packet = RadioPacket.mkPacket(PACKET_TYPE_DOUBLE_VALUE);
        }

        packet.numberPayload = value;
        packet.stringPayload = name;
        sendPacket(packet);
    }

:::



## 文字列型の相互変換(StringとManagedString)
StringとManagedStringとを相互に変換するために、MSTR()やPSTR()が使われています。

MSTR() - StringからManagedStringへ変換
PSTR() - ManagedStringからStringへ変換

## 引数のかず

関数の引数が多すぎると、コンパイルエラーとなる。

:::note alert
**error TS9200: Assertion failed**
例えば、引数が6個の関数を呼び出すとエラー。
:::

```ts: test.ts
custom.buildErr(1, 2, 3, 4, 5, 6)
```

```ts: custom.ts

    //% block
    //% shim=custom::buildErr
    export function buildErr(p1: number, p2: number, p3: number, p4: number, p5: number, p6: number): void {
        // nop
    }
    
```

```cpp: custom.cpp

    //%
    void buildErr(TNumber p1, TNumber p2, TNumber p3, TNumber p4, TNumber p5, TNumber p6)
    {
        // nop
    }

```

# マクロの定義（ptx.json）

定数マクロをptx.jsonで定義できる。

**Setting C++ constants for DAL config - yotta**

https://makecode.com/extensions/pxt-json#setting-c-constants-for-dal-config-yotta

:::note warn
pxt.jsonを記述しただけでは、v2(codal)のビルド時にしか、`CUSTOM_DEFINE_VALUE`が定義されない。

```json
    "yotta": {
        "config": {
            "CUSTOM": 123
        }
    }
```

`YOTTA_CFG_` を接頭辞につける。

```cpp
#define DEFAULT_CUSTOM 9
#ifndef CUSTOM
#ifdef YOTTA_CFG_CUSTOM
#define CUSTOM YOTTA_CFG_CUSTOM
#else
#define CUSTOM DEFAULT_CUSTOM
#endif
```

:::
pythonでエクセルの書式を操作してテキストに差分がある部分だけ赤字にする(協力ChatGPT)


pythonでエクセル操作
二つのcellを比較してテキストに差分がある部分だけ赤色にする
最初はopenpyxlでやろうとしたのですが、それだと部分の書式設定ができないと判明したため
xlsxwriter で挑戦してみました
想定している結果が得られましたよ

当初単語設定を"[a-zA-Z0-9_]+"にしていたせいで原文を保持できず
ChatGPTも無理に原文を保持しようとして上手くいかないケースを返してきてたのですが。
私に電流が走り'([a-zA-Z0-9_]+|[^a-zA-Z0-9_]+)'にして全部とってくればいいじゃん！
ってChatGPTにいったらうまく動作するものが返ってきた。

ChatGPTに「ご指摘の通り」って言わせてやったぜ！(最初の聞き方が悪かっただけである）

```ChatGPT返信.txt
ご指摘の通り、元の文字列のすべての部分を保持しつつ、単語や記号を適切に抽出するために、
正規表現を見直す必要があります。以下の修正では、単語にマッチする部分だけでなく、
それ以外の部分も抽出し、元のテキストの構造を保持するようにします。
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3638856/8aac2ebd-443c-afbd-d7dc-5664bda64947.png)

```diff
import xlsxwriter
import difflib
import re

def extract_parts(text):
    # 単語とそれ以外の部分を抽出
    return re.findall(r'([a-zA-Z0-9_]+|[^a-zA-Z0-9_]+)', text)

def get_differences(parts1, parts2):
    # 差分を取得
    diff = difflib.ndiff(parts1, parts2)
    return diff

def create_rich_string(text1, text2, workbook):
    # リッチ文字列を生成するためのリスト
    rich_string = []
    
    # 赤色フォーマットの定義
    red_format = workbook.add_format({'color': 'red'})

    # テキストのパーツを抽出
    parts1 = extract_parts(text1)
    parts2 = extract_parts(text2)

    # 差分を取得
    differences = get_differences(parts1, parts2)

    # 現在のテキストを保持するための変数
    current_text = text2  # text2を基準にする

    # 差分を解析
    for part in differences:
        if part.startswith('+ '):
            # 新しく追加された部分
            rich_string.append(red_format)  # 赤色フォーマットを追加
            rich_string.append(part[2:])  # 新しい部分を追加
        elif part.startswith('- '):
            # 削除された部分は無視
            continue
        else:
            # 変更のない部分を追加
            rich_string.append(part[2:])  # 変更のない部分を追加

    return rich_string



# Excelファイルに書き込む関数
def main():

    # Excelファイルの作成
    workbook = xlsxwriter.Workbook('differences.xlsx')
    worksheet = workbook.add_worksheet()

    # 例
    text1 = "The quick brown fox jumps over the lazy dog"
    text2 = "The quick blue fox jumps over a lazy dog"
    # リッチ文字列を生成
    rich_string = create_rich_string(text1, text2, workbook)
    # 指定されたセルにテキストを追加
    worksheet.write("A1", text1)
    worksheet.write_rich_string("A2", *rich_string)


    # 例
    text1 = "ans = A1 + BB3 + CC"
    text2 = "ans = A1 + BB2 + CC * (DD_4 + 1)"
    # リッチ文字列を生成
    rich_string = create_rich_string(text1, text2, workbook)
    # 指定されたセルにテキストを追加
    worksheet.write("B1", text1)
    worksheet.write_rich_string("B2", *rich_string)

    # 例
    text1 = "ans = func(in(\"in1.txt\"),out(\"out1.txt\"))"
    text2 = "ans = func(in(\"in1.txt\"),out(\"outout.txt\"))"
    # リッチ文字列を生成
    rich_string = create_rich_string(text1, text2, workbook)
    # 指定されたセルにテキストを追加
    worksheet.write("C1", text1)
    worksheet.write_rich_string("C2", *rich_string)

    # ファイルを閉じる
    workbook.close()

main()
```
【イベントレポート】～～オープンソースカンファレンス2024 Tokyo/Fall～～

いつも記事を読んでいただきありがとうございます！
モブエンジニア（[@mob-engineer](https://qiita.com/mob_engineer))です！

10/26（土）に参加したオープンソースカンファレンス2024 Tokyo/Fallへ参加しましたので、イベントレポートとして**私が感じたこと**や**新たな発見**などを共有したいと思います。

:::note info
本記事は「オープンソースカンファレンス2024 Tokyo/Fall」の参加レポートとなります。なるべく、簡潔にまとめておりますので、読み物として気軽に読んでいただければ幸いです。
:::

# 目次
1. 参加したきっかけ
1. 訪問した展示ブース
    1. 株式会社NTTデータグループ
    1. 株式会社SRA OSS
    1. サイボウズ・ラボ株式会社
    1. Streamlitコミュニティ
    1. 小江戸らぐ
    1. モウフカブール
    1. 分散型SNSユーザー有志
    1. Project Sincromisor
1. 参加した所感

## 参加したきっかけ

### 訪問した展示ブース

### 株式会社NTTデータグループ
:::note info
サイトURL：https://www.nttdata.com/jp/ja/
:::
日本国内の発電所から出ているCO2量をAPIを用いてWeb画面に表示させるツールについて紹介いただきました。お話を聞いていく中で、上記機構をオープンソースとして共有しているとのことでしたので、誰でも利用できるそうです。

### 株式会社SRA OSS
:::note info
サイトURL：https://www.sraoss.co.jp/
:::
PostgreSQL教育にについて紹介いただきました。個人的にDBまわりのスキル向上を行いたかったので、有意義なお話を聞けたと感じております。

### サイボウズ・ラボ株式会社
:::note info
サイトURL：https://labs.cybozu.co.jp/
:::
マークアップ言語であるBrackについて紹介をいただきました。マークアップ言語を開発したねらいや使用した技術スタックについて様々なお話を聞くことができました。

### Streamlitコミュニティ
:::note info
サイトURL：https://discuss.streamlit.io/c/lang/japan/31
:::
Python製のWebアプリ用フレームワークであるStreamlitについて紹介していただきました。。私個人として、Streamlistの**書きやすさ**に対して将来性を感じているため、今後も使っていきたいと思いました。

### 小江戸らぐ
::: note info
:::note info
サイトURL：https://koedolug.dyndns.org/
:::
Pythonのライブラリを用いて、合成音声（初音ミク）を用いたドラムツールについて紹介していただきました。私個人もPythonを使ってWeb開発を行っているため、個人開発で遊んでみようかなぁと思いました！

### モウフカブール
:::note info
サイトURL：https://mofukabur.com/
:::
今まで執筆された書籍について紹介いただきました。また、私個人も書籍を執筆したいと考えているため、どのように書籍を書いていけばいいのかのヒントを見つけることができました。

## 参加した所感
期間が空いてしまい、記憶があいまいになっているところがいくつかありましたが、**技術者としての楽しさ**や**技術スタックへの興味**を改めて感じることができました。来年1月には、駒澤大学で開催されるようですので、次回も参加したいと思いました。

## 関連サイト
[Open Source Conference 2024 Tokyo/Fall](https://event.ospn.jp/osc2024-fall/)
[びぎねっとホームページ](https://begi.net/)
[特定非営利法人オープンソースソフトウェア協会](https://www.ossaj.org/)
関数とプロシージャ

## はじめに
PostgreSQLの関数に関してまとめてみました。
MySQLなど他のデータベースとは異なる箇所があるかもしれません。ご了承ください。

## 関数とプロシージャ
PostgreSQLでは、データベースに関数を定義することができます。
一般的にはストアドプロシージャと呼ばれます。
ストアドプロシージャでは、DBMSに備わっている便利な関数や機能を利用できるので、アプリケーション側での複雑な処理をDBMS側に任せることができます。
また、大量のデータをアプリケーション側へ渡さずにデータベースで処理できるので、ネットワークの負荷軽減なども期待できます。

## 関数とプロシージャの違い
PostgreSQLでは関数(FUNCTION)とプロシージャ(PROCEDURE)の2種類のストアドプロシージャを作成できます。
役割や定義はほぼ同じですが、以下のような違いがあります。

- 関数は戻り値を定義できるが、プロシージャはできない。
- 関数は`SELECT`で呼び出すが、プロシージャは`CALL`で呼び出す。
- 関数は定義内でトランザクションの`COMMIT`や`ROLLBACK`ができないが、プロシージャはできる。

## 関数定義
基本的な書式は以下です。
- 関数
```sql
CREATE FUNCTION 関数名(引数) RETURNS [SETOF] 戻り値 AS $$ 関数の記述
$$ LANGUAGE 使用言語;
```
関数の具体例

```sql
CREATE FUNCTION add_func(int, int) RETURNS bigint AS $$
SELECT ($1 + $2)::bigint /* 引数2つを足す */
$$ LANGUAGE SQL;
SELECT add_func(1,2); /* 関数呼び出し */
```


- プロシージャ
```sql
CREATE [ON REPLACE] PROCEDURE プロシージャ名(引数) AS $$ 関数の記述
$$ LANGUAGE 使用言語;
```

プロシージャの具体例
```sql
CREATE PROCEDURE insert_proc(int, text) AS $$
INSERT INTO tbl VALUES($1, $2) /* tblテーブルに引数の値をinsertする */
$$ LANGUAGE SQL;
CALL insert_proc(123, 'test'); /* プロシージャ呼び出し */
```

## PL/pgSQLで記述する関数について
### PL/pgSQLとは
PL/pgSQL（Procedural Language/PostgreSQL Structured Query Language）は、オープンソースのリレーショナルデータベースであるPostgreSQLのための手続き型言語です。この言語を使うことで、SQLのクエリに加え、より複雑な制御構造やエラーハンドリングなどを利用でき、PostgreSQLのデータベース内での高度なデータ処理が可能となります。

PL/pgSQLで記述する基本的な関数の構造は以下になります。
```sql
DECLARE
  変数の宣言
BEGIN
  関数の処理記述
END
```
上記の変数宣言についてもう少し詳しくみていきます。
変数宣言の基本的な書式は以下になります。
```sql
変数名 [CONSTANT] データ型 [NOT NULL] [{DEFAULT | := } 値など]
```
変数宣言の具体例
```sql
var_1 int DEFAULT 10; -- integer型でデフォルトを10とした変数var_1の宣言

var_2 CONSTANT text := 'Sample'; -- text型でSampleを固定値とした変数var_2の宣言
```

PL/pgSQLの関数の具体例
```sql
CREATE TABLE tbl (c1 int, c2 timestamp); tblテーブルを作成

CREATE OR REPLACE FUNCTION test_func(int, timestamp) RETURNS integer AS $$
DECLARE
  r timestamp;
  result int := 0;
BEGIN
  FOR r IN SELECT c2 FROM tbl WHERE c1 = $1 -- FOR文でc2の値を逐次rへ代入
  LOOP
    IF r < $2 -- 第2引数のtimestampの情報より古い日付かチェック
    THEN
      result := result + 1
    END IF; -- IFの終了
  END LOOP; -- LOOPの末端
  RETURN result; -- 戻り値を返却
END
$$
LANGUAGE plpgsql;
```
Readonly<T>とreadonly()に気をつけよう!!!

# はじめに
* Nuxt3 + TypeScriptを使用した実装でハマったこと
* コードを書く上でReadonly<T>とreadonly()の違いを認識できておらずハマってしまった
* そもそもreadonly()という関数は勝手にプロパティに対して'readonly' 修飾子を付与してくれるものだと勘違いしていた :rolling_eyes:

# `Readonly<T>` と `readonly()` は別物
そもそもではありますが、Readonly<T>とreadonly()は別物になります
まず、**`Readonly<T>`** はTypeScriptのユーティリティ型のひとつになります
そして、**`readonly()`** はVueが提供する関数のひとつになります

## それぞれ読み取り専用にしてくれるという機能だが...？
それぞれ「受け取ったオブジェクトに対して読み取り専用にする」という機能であるが、
そのプロパティに対して **「読み取り専用にする深さ」** が違います

## 深い・浅いとは？

* Readonly<T>に関しては受け取ったオブジェクトの直下プロパティしか読み取り専用にしてくれません
* ですが、readonly()はネストされたプロパティに対しても読み取り専用にしてくれます

https://typescriptbook.jp/reference/type-reuse/utility-types/readonly

https://ja.vuejs.org/api/reactivity-core#readonly

# 勘違いしてしまったコード

provide/inject を使用しつつ、injectの出しどころを制御したやつ

```typescript
import type { User } from '...'
import type { InjectionKey } from 'vue'

interface UserState {
  user: Readonly<Ref<User | null>>
  setUser: (_user: User) => void
}

export const UserSymbol: InjectionKey<UserState> = Symbol('UserSymbol')

export function provideUserState () {
  const user = ref<User | null>(null)

  const setUser = (_user: User): void => {
    user.value = _user
  }

  const userState = {
    user: readonly(user),
    setUser
  }

  provide(UserSymbol, userState) // ← userStateで型エラー

  return userState
}

export function injectUserState (): UserState {
  const userState = inject(UserSymbol)
  if (!userState) {
    console.log('userState', userState)
    throw new Error('userState is undefined')
  }
  return userState
}
```

UserStateインターフェースに対して、userStateを当て込めようとしたが型エラーで怒られる

# 気をつけたい
`readonly()` は返り値として、**`DeepReadonly`** を返すため `Readonly<T>`と混同しないようにしたい

```typescript
interface UserState {
  user: DeepReadonly<Ref<User | null>> // Readonly→DeepReadonly
  setUser: (_user: User) => void
}

export const UserSymbol: InjectionKey<UserState> = Symbol('UserSymbol')

export function provideUserState () {
  const user = ref<User | null>(null)
:
    const userState = {
        user: readonly(user), // DeepReadonlyが返ってくるよ！
        setUser
    }
}
provide(UserSymbol, userState)
```

# 宣伝

自分が所属している会社についても紹介させてください 🙇‍♂️
弊社では物流課題解決や荷物を配送するドライバーの価値を向上させるために
「ピックゴー」 というサービスを運用しています

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2641311/3bd56eb8-3f4e-7893-3823-7398ec5493ed.png)

## あと、那覇Baseが本店になりました
10月25日に自分のいる那覇Baseが本店になりました🎉

自社開発したい方やエンジニアとして成長したい方など少しでも興味ありましたらカジュアル面談や会社説明会も開催していますの気軽にお問い合わせください！

https://recruit-okinawa.cb-cloud.com/?utm_source=web_recruite_tokyo&utm_medium=pcheader&utm_campaign=okinawarecruitecm
RNN (Recurrent Neural Network)

RNN（Recurrent Neural Network, 再帰型ニューラルネットワーク）は、時系列データや自然言語など順序のあるデータを処理するために設計されたニューラルネットワーク。

## RNNの基本概念

1. 時系列データの処理：
   RNNは、テキスト、音声、時系列データなど、順序や時間的な依存関係のあるデータを扱うのに適する

2. 隠れ状態（hidden state）：
   過去の情報を記憶し、現在の予測に利用される

3. パラメータの共有：
   同じパラメータを時間ステップごとに再利用することで、モデルのサイズを抑えつつ、可変長の入力を処理できる

## RNNの構造

![recurrent-neural-network.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523626/745c57de-2926-823d-663b-6533ee33111c.png)


基本的なRNNは以下の要素で構成される：

1. 入力層（Input layer）
2. 隠れ層（Hidden layer）
3. 出力層（Output layer）

各時間ステップ $t$ において、RNNは以下の計算を行う：

1. 隠れ状態の計算：$$h_t = tanh(W_{hh} * h_{t-1} + W_{xh} * x_t + b_h)$$
1. 出力の計算：$$y_t = W_{hy} * h_t + b_y$$


ここで、
- $x_t$: 時間tでの入力
- $h_t$: 時間tでの隠れ状態
- $y_t$: 時間tでの出力
- $W_{hh}$, $W_{xh}$, $W_{hy}$: 重み行列
- $b_h$, $b_y$: バイアスベクトル

## RNNの問題点

1. 時間的な依存関係があるため、並列処理が難しく、学習に時間がかかる
2. 長い時間間隔の依存関係を学習するのが難しい（「長期依存性」）
    - 勾配爆発(Gradient Explosion)　→[勾配クリッピング](https://qiita.com/yunakam/items/3628c1f782087f43e560)
    - 勾配消失(Gradient Vanishing)　→[ゲート付きRNN](https://qiita.com/yunakam/items/32adbbb112922bb59369)

## 改良版・拡張版

#### ゲート付きRNN
ゲート機構を導入することで長期依存性の学習を改善し、勾配消失問題を軽減
- LSTM (Long Short-Term Memory)
- GRU (Gated Recurrent Unit)

#### 双方向RNN (Bidirectional RNN)
英→日翻訳など先の情報が助けとなるタスクにおいて、過去と未来の両方の文脈を考慮する

計算：
1. 前方向の隠れ状態計算 Forward Hidden State：
    $$h_t^{(f)} = \tanh(W_{hh}^{(f)}h_{t-1}^{(f)} + W_{xh}^{(f)}x_t + b_h^{(f)})$$

   <sub>$W_{hh}^{(f)}$ : 前の隠れ状態を新しい隠れ状態に変換するための前方向の重み行列
   $W_{xh}^{(f)}$ : 現在の入力を新しい隠れ状態に変換するための前方向の重み行列
   $b_h^{(f)} : $は前方向のバイアス項</sub>
   <br><br>
   
1. 後方向の隠れ状態計算 Backward Hidden State
   $$h_t^{(b)} = \tanh(W_{hh}^{(b)}h_{t+1}^{(b)} + W_{xh}^{(b)}x_t + b_h^{(b)})$$

   <sub>$W_{hh}^{(b)}$ : 次の隠れ状態を新しい隠れ状態に変換するための後方向の重み行列
   $W_{xh}^{(b)}$ : 現在の入力を新しい隠れ状態に変換するための後方向の重み行列
   $ b_h^{(b)}$ : 後方向のバイアス項</sub>
    <br><br>

1. 出力の計算
   $$y_t = W_{hy}^{(f)}h_t^{(f)} + W_{hy}^{(b)}h_t^{(b)} + b_y$$


    <sub>$W_{hy}^{(f)}$ : 前方向の隠れ状態を出力に変換するための重み行列
   $W_{hy}^{(b)}$ : 後方向の隠れ状態を出力に変換するための重み行列
   $b_y$ : バイアス項</sub>


## 補足

最近では、特に自然言語処理タスク分野では**Transformer**などの新しいアーキテクチャがRNNに取って代わりつつある。
具体的には、
- 機械翻訳
- テキスト生成（GPT)
- Q＆A
- 感情分析
- 音声認識
などの分野
One-Fund TheoremをChat GPTに聞いてみた

金融工学入門第2版の1-ファンド定理を勉強した上で、Chat GPTに聞いてみました。

### Chat GPTによる回答

1-ファンド定理(One-Fund Theorem)は、資産運用やポートフォリオ理論の概念の1つで、「効率的な市場において、すべてのリスク資産を保有する投資家は、同じリスク資産のポートフォリオに投資するべきである」という理論である。具体的には、投資家のリスク許容度が異なる場合でも、**「1つの効率的なリスク資産ポートフォリオ」**があれば、無リスク資産との組み合わせだけで投資家の好みに合ったポートフォリオが構築できることを示している。

### 1-ファンド定理の具体的な内容

1-ファンド定理では、次のようなことが示されている。
1. リスク資産の共通ポートフォリオ：
- すべての投資家は同じ「市場ポートフォリオ」などの効率的なリスク資産ポートフォリオを持つべきであるとされる。これは、すべてのリスク資産を組み合わせたもので、分散効果が最大化されるため、リスク調整後のリターンが最も効率的に得られるポートフォリオである。
1. 無リスク資産との組み合わせ：
- 投資家のリスク許容度に応じて、無リスク資産(例えば国債など)と効率的な市場ポートフォリオを適切な割合で組み合わせることで、各投資家にとって最適なリスク・リターンの組み合わせを実現できる。
- リスクを取りたくない投資家は無リスク資産を多く、リスク資産を少なく持つことで、好みのリスク水準に調整することができる。
1. 分散投資の効率化：
- すべての投資家が同じリスク資産ポートフォリオを共有するため、リスクの分散が効率的に行われ、市場全体の資源配分も合理的になる。

### 1-ファンド定理の例

例えば、ある市場に「市場ポートフォリオ(M)」と「無リスク資産(R)」があるとする。この場合、すべての投資家はMとRを自分のリスク許容度に応じて配分する。
- リスクを取りたくない投資家：市場ポートフォリオの割合を減らして、無リスク資産を多く持つ。
- リスクを取りたい投資家：無リスク資産を減らし、市場ポートフォリオの割合を多く持つ。また、場合によっては無リスク資産をショートし、リスクを増やすことで、リスク・リターンをさらに高めることも可能である。

### 1-ファンド定理の意義

1-ファンド定理は、市場の効率性と分散投資の合理性を示している。この定理に基けば、リスク資産を分散して保有する最も効率的な方法は、市場全体を反映するポートフォリオの投資することである。投資家が異なるリスク許容度を持っていても、無リスク資産との割合を調整するだけで、好みのリスク・リターンに対応できる。

### 1-ファンド理論と現代ポートフォリオ理論(MPT)
現代ポートフォリオ理論(MPT)において、この定理は、市場ポートフォリオの有効性と、分散投資がリスク低減に有効であるという概念の基盤を成している。
Google Chromeのファイルサイズが大きすぎる感じたら

## TL;DR

 - Chromeは過去バージョンを保管してるのでそれを消してあげることで容量を減らせる
 - `/Applications/Google Chrome.app/Contents/Frameworks/Google Chrome Framework.framework/Versions`の最新以外を消せばいい

## 注意

これでパソコンぶっ壊れても私は責任を取らない&取れないので自己責任でお願いします。

## 概要

Macのストレージがだいぶ減ってきたのでいらないファイルを消して容量を開けようとしてたら、Google Chromeが13GBも使用していることに気がついた。

サイトのキャッシュファイルだとしても多すぎる（普段あんまり使わないブラウザだし、Safariもそんなに多くない）ので、不審に思って調査したら、過去のアプリケーションのバージョンのバックアップ？を大量に保持していることに気がついた。

## 対処法

**過去のいらないバージョンを消す**

```bash
$ open '/Applications/Google Chrome.app/Contents/Frameworks/Google Chrome Framework.framework/Versions'
```

して、Currentエイリアスが指してる先以外（最新のもの以外）を全て消す。

![Ga6CJcaakAAWWP3.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628782/7149143b-ed91-e9f6-32f5-1c58786fa0c0.jpeg)

私の場合はこれで13.77GBから607MBに減らすことができました。

## 余談；なぜためてる？？

いらないと思う。なんでなんだろう？有識者の皆さん教えてください。
Linux (シェルとカーネルについて)

## ディストリビュージョンとOS
ディストリビュージョンとは、OSの中核となるLinuxカーネルに加えて、コマンド群やアプリケーションなどを含めてユーザーがそのまま利用できるようにパッケージングされたもの。
これを広義にLinuxとも呼び、Linuxディストリビュージョンとも呼ばれる

仮想化させて動作させているOSのことをホストOSと呼ばれ、仮想化ソフトウェアによって実行する仮想的なOSをゲストOSと呼ばれている

## シェル
シェルは、カーネルのインターフェイスプロセスの1つである。
シェル自体の役割はLinuxカーネルとユーザーとの橋渡しを主に行っている。

例として「date」というコマンドを実行した場合。
シェルは「date」というキーボードからの入力を受け取って、それをユーザーからの指示であると解釈する。
→ シェルはdateという文字列が指すコマンドを探し出し、カーネルに実行を依頼する。
→ カーネルがコマンド実行を終了するとシェルが結果を受け取ってユーザーの画面に出力する。


### カーネルとシェルが分かれている理由
この理由について主に3点挙げられる。
- カーネルは手に入れず、シェルだけを自分好みに変更させるため
- Linux以外のOSを利用する際もシェルが移植されていれば同様に行うことができるため
- シェルがエラーや高付加でクラッシュしたとしても、OS本体であるカーネルへの影響を最小限に抑えることができるため


## プロンプト
プロンプトは、シェルが「何かコマンドを入力してください」と意思表示している状態のことを指す。
プロンプトの表記方法について「一般ユーザーは`$`、スーパーユーザでは`#`」で例示される。


## シェルスクリプト
コマンドは直接操作するだけでなく、実行したいコマンド群を事前にファイルに記述し、そのファイルをシェルに指定することで一連のコマンドをまとめて実行することができる。
このような一連の操作の流れを記述したファイルのことをシェルスクリプトと呼ぶ。

## シェルの種類について
### sh
 シェルスクリプトを記述する際に一般的に使用される。
ただし、古いシェルのため機能が少なく対話型に使うには非常に不便であることからログインシェルとしては使用されない。

### csh
csh後継のtcshがあるため、ほとんど使用されることはない

### bash
 shを基本とし機能を拡張したシェル。
 対話型操作を行う上で十分な機能を持ち、多くのLinux環境でデフォルトのログインシェルとして使用されている。シェルスクリプトを記述するためにも向いている。

### tcsh
Cシェル系のシェルで、特に対話型操作で便利な機能を多く持つ。
しかし、シェルスクリプトの記述には向いておらず、一般ユーザのプロンプト記号は`%`が使われる。

### zsh
他のシェルの機能を取り込み、独自の拡張を加えたシェルである。
機能面では優れているが、使いこなすのは時間がかかるため初心者向けのシェルではない。

## シェルの選定
**bashを利用することを勧められている**。
理由としては以下のものが挙げられる
- Linuxのデフォルトログインシェルがbashであること
- 対話的に使用する場合やシェルスクリプトを利用する場合でも優れていること
- shとの後方互換性を持つこと
- Linux以外でもMac OSなど多くの環境に移植されていること

## シェルの一時的な切り替え
単に使いたいシェルを指定することで、使いたいシェルに切り替えることができる。
ex) `sh` `bash`など

非ログインシェルから抜けるためには`exit`と入力する。
また、ログインシェル自体を変更することもできるがコマンドを誤るとログインできなくなる可能性があるため、基本的にはbashのままで使用すること。

## ターミナルとシェル
ターミナルは、ユーザーがコンピューターへ入出力する際に利用する専用ハードウェアのことを指す。
しかし、Linuxを使用するにあたりハードウェアとしてのターミナルは使用されることなく代わりにターミナルエミュレーターが使用される。


#### 参考文献
> [新しいLinuxの教科書](https://www.sbcr.jp/product/4797380941/)
Pythonパッケージをシェルスクリプト／バッチファイルに埋め込む

Pythonの組み込みライブラリを眺めていたら面白そうなものを見つけました。zipファイルからモジュールを直接インポートできるそうです。

https://docs.python.org/3/library/zipimport.html

何かに使えないかと思い調べたところ、yt-dlpが配布に利用しているのを見つけました。パッケージを収めたzipファイルの先頭にshebangをつければ、同様にしたPythonファイルと同じようにシェルから直接実行できるということです。

https://github.com/yt-dlp/yt-dlp

Windowsのコマンドプロンプトにshebangはないですが、Pythonには1行目を無視するオプションが用意されており実質shebangを実現できます。Pythonはpyランチャー経由で起動するのが最も柔軟でしょうか。

```
> py --help | Select-String -CaseSensitive "^-x"

-x     : skip first line of source, allowing use of non-Unix forms of #!cmd
```

https://qiita.com/snipsnipsnip/items/50e4ca88e3ce3f8cffda

おおまかに理解したので少し汎用的に使えるようにして公開しました。pipxなどでインストールできます。このパッケージ自体がこのパッケージで固められるようになっているので、試してなんとなくなっとくしてください。

https://github.com/u1f992/lalian

1ファイルに固めるということで見た目は似ていますが、PyInstallerやNuitkaとは異なり、実行環境にもPythonをインストールする必要があります。またグローバルのPython環境（より正確にはshebangが指定するPythonインタプリタの環境）にインストールされているパッケージしか利用できません。たどってzipに含めれば可能でしょうが、ずっと難しくなります。

yt-dlpにはランタイムの依存パッケージがひとつもなく、かつLinux環境にはほぼ間違いなくPythonがインストールされているので、「recommended for Linux/BSD」とことわって配布に利用しているのですね。
Excelで手順書作成に関して

# 1,はじめに
お疲れ様です。
3回目の投稿になります。
現在は現場三年目になりましたが、時がたつのは早いと感じています....
最近エニプラアワードで、手順書を作成する機会があったので、
自分なりの作り方を共有させていただきたいと思います！

# 2,記事の経緯について
上記に最近作成した機会があった記載していますが、
現場配属一年目の時に監視システム管理の、
チーム内での調査方法や結果の割り出し方をExcelで手順書にしてほしいと頼まれ
インターネットで調べても参考になるものがあまりなく苦労したので、
今回記事にしようと考えました。

# 3,大枠の構成に関して
手順書の大枠の構成を、よくあるカレーの調理方法で、例を挙げたいと思います。
まず手順書の大枠として下記の5点あげられると思います。
<table>
 <thead>
    <tr>
      <th>大項目</th> <th>内容</th>
    </tr>
  </thead>
  <tr>
    <td> 表紙 </td> <td>作成日・作成者・構成更新日</td>
  </tr>
  <tr>
    <td> 目次 </td> <td>目的・各項目の説明・構成更新の内容</td>
  </tr>
    <tr>
    <td> 事前準備 </td> <td>事前準備手順</td>
  </tr>
    <tr>
    <td> 調理手順 </td> <td>調理手順(手順書本編)</td>
  </tr>
    <tr>
    <td> 結果 </td> <td>結果(盛り付け)</td>
  </tr>
</table>

 ![Image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2629111/90adacc4-267f-5e96-aa02-992a5d88ae4e.png)
 
 これらが、各Excelのシートごとになると思います。

 # 4,手順書の作り方
 ![Image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2629111/4fdd3dee-42f7-ac85-9427-e203c327d40f.png)

 上記の画像は「事前準備/調理/結果」シートで使用するフォーマットを自分なりに作成したものになります。
 イメージとしては画像の作成手順列に実行する前の状態の画像を挿入し、操作の説明を記載します。
  隣の結果列には期待値と実際に映し出される結果の画像を入れる形を想定してます。
 参考になればいいのですが....

 # 5,手順書作成の注意点/工夫点
 手順書作成で「自分が指摘された点」「工夫したほうがいい点」などなど
 ここで紹介させてください。
<dl>
  <dt>目次</dt>
  <dd>この手順書を作成するうえで目的を書くことを忘れていて上長に指摘されました。</dd>
  <dd>目的は自分がこれから作成する手順書は何かを明確にするものなので、</dd>
   <dd>大事なので書いておくほうがいいと思います...</dd>
  <dt>手順書に関して</dt>
  <dd>1,手順書は正確な情報を<strong>だれが見てもわかるような書き方</strong>をするのが大事です。</dd>
  <dd>2,大切な箇所/変更点(作業によって変更する箇所)は<strong>色付け</strong>する！！</dd>
  <dd>3,手順に<strong>画像</strong>を入れるほうがわかりやすい！(画像に赤枠など入れるとより分かりやすい)</dd>
  <dd>4,<strong>誤字脱字</strong>はよく指摘されたので注意!(作業していると見逃すので作業終わりにチェック)</dd>
</dl>

これ以外にもあったと思いますが、思い出せなかったです..
大切なのは、前もって上司や上長に細かくチェックしていただくほうがいいので、
参考程度にしていただけると幸いです。

# 6,おわりに
短めですが紹介としては以上になります。
こちらの記事に関して自分の手順書作成についてまとめたものなので、
こうしたほうがいい等あればコメントいただけると幸いです。
最後までご覧いただき、ありがとうございました。

# 記事作成参考URL

 https://qiita.com/Qiita/items/c686397e4a0f4f11683d
コールバック関数の使い方（初心者向け）

# はじめに
この記事はLaravelでコールバック関数を使用した際の備忘録です

修正および加筆が必要な場合は都度更新します

## コールバック関数とは
他の関数に引数として渡される関数のことです。
この関数は、特定の処理が完了した後や特定の条件が満たされたときに呼び出されます。コールバックを利用することで、コードをより柔軟にし、再利用性を高めることができます。

JavaScript、Java、C++、phpなどさまざまな多くの言語で利用されています

## コールバック関数の利用方法

```見本.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>数値の合計計算</title>
</head>
<body>
    <h1>数値の合計を計算する</h1>
    <form method="POST" action="/calculate-sum">
        @csrf <!-- CSRFトークンを含める -->
        <label for="numbers">数値をカンマで区切って入力してください:</label>
        <input type="text" id="numbers" name="numbers" placeholder="例: 1, 2, 3">
        <button type="submit">送信</button>
    </form>

    @if (session('sum'))
        <h2>合計: {{ session('sum') }}</h2>
    @endif
</body>
</html>

```
```ルーティング.php
use App\Http\Controllers\CalculationController;

Route::post('/calculate-sum', [CalculationController::class, 'calculateSum']);
```


```コントローラー.php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class CalculationController extends Controller
{
    public function calculateSum(Request $request)
    {
        // 入力された数値をカンマで分割
        $numbers = explode(',', $request->input('numbers', ''));
        //(キー:numbersがない場合、空文字を代入する
        
        // 合計を計算するコールバック関数
        $sum = $this->calculateTotal($numbers);

        // 合計をセッションに保存し、元のページにリダイレクト
        return redirect()->back()->with('sum', $sum);
    }

    // 合計を計算するコールバック関数
    protected function calculateTotal(array $numbers)
    {
        // 数値に変換して合計を計算
        return array_sum(array_map('floatval', $numbers));
    }
}
```


## まとめ
コールバック関数は、他の関数の引数として渡され、特定の条件や処理後に実行される柔軟な機能を持っています。本記事では、Laravelを使用してコールバック関数を活用し、数値の合計を計算する簡単なアプリケーションを提示しています