OmniAICreator/Qiita-1.07M huggingface dataset:
🤖 UnslothによるLLM-JPモデルの高速推論実装ガイド(Google Colab📒ノートブック付)

## デモ動画

<blockquote class="twitter-tweet" data-media-max-width="800"><p lang="ja" dir="ltr">LLama3.2 3Bファインチューニング実験 | 25<br>Unslothの推論の実験！取り敢えずはLLM-JPでやってみた！ <a href="https://t.co/DoTVzHatyx">https://t.co/DoTVzHatyx</a> <a href="https://t.co/N8ZdE06M1a">pic.twitter.com/N8ZdE06M1a</a></p>&mdash; Maki@Sunwood AI Labs. (@hAru_mAki_ch) <a href="https://twitter.com/hAru_mAki_ch/status/1861232229072199745?ref_src=twsrc%5Etfw">November 26, 2024</a></blockquote>

## 📦 必要なライブラリのインストール

```python
%%capture
!pip install unsloth
# 最新のUnslothナイトリービルドを取得
!pip uninstall unsloth -y && pip install --upgrade --no-cache-dir "unsloth[colab-new] @ git+https://github.com/unslothai/unsloth.git"
```

**解説**:
このセルではUnslothライブラリをインストールしています。Unslothは大規模言語モデル（LLM）の推論を高速化するためのライブラリです。`%%capture`を使用することで、インストール時の出力を非表示にしています。

## 🔧 必要なライブラリのインポートと基本設定

```python
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
from unsloth import FastLanguageModel
import torch

# モデルの基本設定
max_seq_length = 512
dtype = None
load_in_4bit = True
model_id = "llm-jp/llm-jp-3-13b"  # または自分でファインチューニングしたモデルID
```

**解説**:
- `transformers`: Hugging Faceの変換器ライブラリ
- `unsloth`: 高速化ライブラリ
- `torch`: PyTorchフレームワーク
- モデルの設定では：
  - 最大シーケンス長: 512トークン
  - 4ビット量子化を有効化
  - LLM-JP 13Bモデルを使用

## 🚀 モデルとトークナイザーの初期化

```python
# モデルとトークナイザーのロード
model, tokenizer = FastLanguageModel.from_pretrained(
    model_name=model_id,
    dtype=dtype,
    load_in_4bit=load_in_4bit,
    trust_remote_code=True,
)

# 推論モードに設定
FastLanguageModel.for_inference(model)
```

**解説**:
このセルでは：
1. モデルとトークナイザーを同時にロード
2. 4ビット量子化を適用し、メモリ使用量を削減
3. モデルを推論モードに設定して最適化

## 💬 応答生成関数の実装

```python
def generate_response(input_text):
    """
    入力テキストに対して応答を生成する関数
    """
    # プロンプトの作成
    prompt = f"""### 指示\n{input_text}\n### 回答\n"""
    
    # 入力のトークナイズ
    inputs = tokenizer([prompt], return_tensors="pt").to(model.device)
    
    # 応答の生成
    outputs = model.generate(
        **inputs,
        max_new_tokens=512,
        use_cache=True,
        do_sample=False,
        repetition_penalty=1.2
    )
    
    # デコードして回答部分を抽出
    prediction = tokenizer.decode(outputs[0], skip_special_tokens=True).split('\n### 回答')[-1]
    
    return prediction
```

**解説**:
この関数は以下の処理を行います：
1. 入力テキストを指示形式のプロンプトに変換
2. トークナイズしてモデルに入力可能な形式に変換
3. 以下のパラメータで応答を生成：
   - `max_new_tokens`: 最大512トークンまで生成
   - `use_cache`: キャッシュを使用して高速化
   - `do_sample`: 決定的な出力を生成
   - `repetition_penalty`: 繰り返しを抑制（1.2）
4. 生成された出力から回答部分のみを抽出

## ✅ 使用例

```python
if __name__ == "__main__":
    # 入力例
    sample_input = "今日の天気について教えてください。"
    
    # 応答の生成
    response = generate_response(sample_input)
    
    print("入力:", sample_input)
    print("応答:", response)
```

**解説**:
このセルは実際の使用例を示しています：
- サンプル入力を設定
- `generate_response`関数を呼び出して応答を生成
- 入力と応答を表示

このコードを実行することで、LLM-JPモデルを使用して日本語の質問に対する応答を生成できます。Unslothによる最適化により、標準的な実装と比較して高速な推論が可能です。


 <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
Tips #023 続・キャンバスアプリでマスタから値をLookUpしたいゾ

https://qiita.com/Novskiiiiiiiiii/items/b06ab0f33667f0e7e1f9

この時は

    LookUp(マスタ名, マスタの照合項目 = フォーム上の入力フィールド.Text, 表示させたいマスタの項目)

こんな感じで、「テキスト入力フィールドに入力した値」をもとにマスタの項目をひっぱってきたんですが、

今回は「ドロップボックスで選択した結果」をもとにマスタの項目をひっぱってくるやり方を残しておきます。

というのも同じ要領で

    LookUp(科目コード一覧,科目コード=dc_kamoku_code_value.text,科目名)

こんな感じで設定したのですが、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3891071/4955f0be-0f27-592c-5d87-4ea32a6bd154.png)

こんな感じで怒られちゃいまして。.textがダメだから.SearchTextでやってみようと思い、

    LookUp(科目コード一覧,科目コード=dc_kamoku_code_value.SearchText,科目名)

と入れてみたら今度は

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3891071/f8372675-3430-15a4-8b94-26be64419248.png)

型の互換性でエラーになってしまいました。

なので、じゃあ文字列肩を数値型にすりゃええんだろ、と思って

    LookUp(科目コード一覧,科目コード=Value(dc_kamoku_code_value.SearchText),科目名)

こう入れてみました。ふむ、上手くいきそうだぞ。


コンボボックスに値を入力してみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3891071/c2c6d132-e185-e705-c6c6-a33205ff65da.png)

うむ、科目名が表示されました。

今度は値を入力せず、コンボボックスの値を選択してみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3891071/cd653e53-a5f9-1708-1650-12a4f8341ae6.png)

な…ん…だと？

チャドの霊圧が消えた…

調べてみると.SearchTextは文字列を入力して検索した結果を出すものらしいので、
コンボボックスの値を選択するのだと発動しない様子。

最終的に上手く動作したのはこんな感じ。

    LookUp(科目コード一覧,科目コード=Value(dc_kamoku_code_value.Selected.Value),科目名)

コンボボックスのDataCardに「dc_kamoku_code_value」とつけているからわかりにくいけど、

dc_kamoku_code_valueでSelectedしたアイテムのValueをValue関数で数値型にすれば解決。

ベジータ「…まるでValueのバーゲンセールだな…」

それではまた！

https://qiita.com/Novskiiiiiiiiii/items/8505305f289f545bebe5
Spring bootの@NotNull, @NotBlank, @NotEmptyの違い

備忘メモ

https://qiita.com/NagaokaKenichi/items/67a63c91a7db8717fc7d

・追記メモ
実装で確認した所、boolean型, あとInteger等の数値型に@NotBlankを付けると500エラーになる。空文字や空白の概念が無いからでしょうね。なるほど。
【LaTeX】図のサブキャプションをつける方法

LaTeXで複数枚の図を挿入する際、ひとつの図番号の中に(a), (b)と入れたいときはsubcaptionパッケージを使用する。以下をプリアンブル中に記述することでサブキャプションを使用できるようになる。

```
\usepackage{subcaption}
```

# 実装例

<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3574030/b55d5fde-09ae-138d-dfe4-93bed08f5c5e.png">

```latex:コード
\begin{figure}[h]
  \centering
  \begin{minipage}{0.43\columnwidth}
    \centering
    \includegraphics[width=\columnwidth]{サンプルa.pdf}
    \subcaption{サンプルa}
    \label{fig:サンプルa}
  \end{minipage}
  \hspace{5mm}
  \begin{minipage}{0.43\columnwidth}
    \centering
    \includegraphics[width=\columnwidth]{サンプルb.pdf}
    \subcaption{サンプルb}
    \label{fig:サンプルb}
  \end{minipage}
  \caption{サンプル}
  \label{fig:サンプル}
\end{figure}
```

ちなみにサブキャプションをつけない場合は以下のようになる。

<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3574030/29fe1c5f-8f99-b6bf-e7b4-790a3083aecd.png">

```latex:コード
\begin{figure}[h]
  \centering
  \begin{minipage}{0.43\columnwidth}
    \centering
    \includegraphics[width=\columnwidth]{サンプルA.pdf}
    \caption{サンプルA}
    \label{fig:サンプルA}
  \end{minipage}
  \hspace{5mm}
  \begin{minipage}{0.43\columnwidth}
    \centering
    \includegraphics[width=\columnwidth]{サンプルB.pdf}
    \caption{サンプルB}
    \label{fig:サンプルB}
  \end{minipage}
\end{figure}
```
【合格体験記】AWS Certified Security - Specialty(SSC)

## はじめに
AWS Certified Security - Specialty に合格しました！

本記事では、私のAWS Certified Security - Specialty資格取得までの道のりを詳しく紹介します。学習方法、使用した教材、苦労した点とその克服方法、そして試験当日の体験まで、包括的に共有させていただきます。これから同じ挑戦をしようと考えている方々にとって、この体験記が少しでも参考になれば幸いです。

## AWS Certified Security - Specialty とは

公式に記載ある通り、セキュリティに特化した試験です。
>AWS Certified Security - Specialty では、AWS クラウドにおけるセキュリティソリューションの作成と実装に関する知識を検証します。この認定では、専門的なデータ分類と AWS のデータ保護メカニズム、データ暗号化方法とそれらを実装するための AWS メカニズム、および安全なインターネットプロトコルとそれらを実装するための AWS メカニズムについての理解も検証されます。

|  | |
|:-:|:-:|
| カテゴリ  | 専門知識  |
|  試験時間 |  170 分 |
| 試験の形態  | 65 個の問題 (複数選択または複数応答のいずれか)  |
| 料金  | 300 USD  |

## 学習期間
約1か月半くらい試験準備期間として時間を設けました。
私の場合は受験を決めた日に試験を予約してしまって、そこから学習を進めています。

## 学習方法
**1. 公式の練習問題を解いてみる**

[AWS Certified Security - Specialty Official Practice Question Set (SCS-C02 - Japanese)](https://explore.skillbuilder.aws/learn/course/15232/aws-certified-security-specialty-official-practice-question-set-scs-c02-japanese)

まずは、現時点で試験問題がどのくらい解けるかの感覚を掴みます。
見たことないサービスや何となく名前は分かるけど、具体的に何ができるかあまり把握していないようなサービスが問題に出てくると思うので、解説を熟読した後に[BlackBelt](https://aws.amazon.com/jp/events/aws-event-resource/archive/?cards.sort-by=item.additionalFields.SortDate&cards.sort-order=desc&awsf.tech-category=*all)で対象のサービスについて理解を深めました。

**2. 試験対策の動画を視聴する**
Udemyに有料の講座はいくつもありますが、今回は無料で視聴できるYouTubeの動画を探しました。

株式会社サーバーワークスさんの公式チャンネルにAWS認定試験の講座が各試験毎にアップされており、
こちらを活用させていただきました。
旧バージョンの対策講座ではありましたが、現バージョンの試験でも十分活用できる内容です。


https://www.youtube.com/c/ServerworksJp/featured

**3. Udemyの演習問題をひたすら解く**
やはり問題の数をこなして、頭に入れるのが合格への一番の近道です。
AWS公式の演習問題だけですと数が少ないので、Udemyで提供されている演習問題を解き、正答率を100%に近づけます。私の場合は90%~95%くらいまで安定して正答できるよう繰り返し実施しました。
Udemyの演習問題で出てきたサービスも理解を深めたい場合は、BlackBeltを適宜利用しました。

## 試験当日
かなりの問題数をこなしたつもりでしたが、見たことない問題が殆どで最初は戸惑いました。
体感的にUdemyで出題された問題と似た問題は5問も無かったと思います。
ただ、出題されるサービスは演習問題で出ていたサービスが多かったので
落ち着いて問題文を読む事である程度自身を持って回答を選択できました。

どの問題も2択までは簡単に絞れて、そこから問題文と回答を照らし合わせて最終的に選択しました。

## 受験結果
点数：783点/1000点
結果：合格

無事に合格できましたが、結構ギリギリでした。
もっと演習問題を多く解くか、出題されるサービスの理解をより深める事で点数は上がると思います。

## 最後に
AWS Certified Security - Specialty資格の取得は、私にとって単なる試験合格以上の意味がありました。受験を通じて、クラウドセキュリティに関する深い知識と実践的なスキルを獲得し、プロフェッショナルとしての自信を大きく高めることができました。

最後に、この記事を読んでくださった皆様、特にAWS Certified Security - Specialty資格の取得を目指している方々にエールを送りたいと思います。
「好きな技術はありますか？」と聞かれたら

## はじめに
皆さんは「好きな技術はありますか？」と聞かれたらちゃんと答えることができますか？
**私は上手く答えられませんでした。**

この記事では「好きな技術」を持つことについて私なりの考えを書いてみようと思います。

## この記事の対象者
- 好きな技術は今のところないけど、好きな技術を持つことに憧れている方


## 実際に転職活動時に私が答えたチグハグな回答
面接官：「好きな技術はありますか？」
私：「れ、Railsですかね・・・（一応一番歴も長いし）」
面接官：「なるほど、Railsのどんなところが好きですか？」
私：「よ、読みやすいところとか、ど、ドキュメントも国内に豊富にあって、こ、コミュニティとかも盛り上がっているところですかね？（嘘ではない）」
面接官「ふむふむ、他の言語と比べてどう読みやすいとかありますか？」
私「えと、、、なんか、、、直感的に読める・・・ような気がしています！」

本当にこんな感じでした


## 実際Ruby on Rails好きなの？
いえ、別に好きでもなければ嫌いでもないです。
そもそも好きな技術がないです。それでも業務に必要な技術を学ぶ意欲はありますし、新しい技術は積極的に試していきたいという気持ちはあります。
その技術に詳しい＝好きというのも違う気がしています。
「技術が好き」ってどういう状態を指すのか、どうすればその状態になるのか分からなくなっている迷える子羊になってます。

## なんで好きな技術が欲しいの？
「好きな技術は？」と聞かれて答えられないのが恥ずかしい…というのもありますが、
好きな技術を持っているエンジニアさんはキラキラして見える、自分もそうなりたい！と漠然と思っています。
実際好きな技術を持つことで、エンジニアライフがより楽しくなるんだろうなぁと思っています。

## 「技術が好き」ってどういう状態なのか？
こちらの記事にヒントがありました。

https://qiita.com/karamage/items/771b633c3243989418a2#%E8%87%AA%E5%88%86%E3%81%AE%E5%BC%B7%E3%81%BF%E3%81%8C%E4%BD%95%E3%81%AA%E3%81%AE%E3%81%8B%E3%82%8F%E3%81%8B%E3%82%89%E3%81%AA%E3%81%84

一部抜粋すると
> いま、現在「自分の強みが何なのかわからない」という方も大勢いらっしゃると思います。
> その答えは、簡単です。
> 「何をやっているときが楽しいですか？」
> その**「楽しいもの」が答え**です。

ここから思うに、「技術が好き」というのも
**その技術を使っていると楽しい**状態が続くと好きになるもの、と考えられます。
個人的にもそれは納得です。

## どうすれば技術を好きなれるのか？楽しさを見出せるのか？
を考える前に、エンジニアリング以外の例で「楽しい」について考えてみます。
私はフットサルが趣味なのですが、楽しいです。この「楽しい」をもう少し分解してみると
- ゲームに勝つという目的があり、勝った時は「やった！」と達成感がある
- 難しいパスを成功させたり、ゴールを決めることができると気持ち良い
- 良いプレーを他者に褒められると脳汁が溢れる
- まだまだ上達の余地がある

↑の要素だけであれば他のスポーツでも良いのでは？となるのですが、
フットサルは他のスポーツと比べて**得意**であるという違いがあります。

さて、技術の話に戻ると、「技術が好き」「技術を使ったり学んだりすると楽しい」というのは下記のような状態を指すのではないかと思います。
- その技術を使う目的がある
- その技術を使って目的を達成すると、達成感を感じることができる
- 他者に技術力の高さを褒められると脳汁が溢れる
- まだまだ上達の余地がある
- 他の技術と比べて得意である

## 好きな技術がない私に足りないもの
前述の中で見ると、
- その技術を使う目的がある

が私に足りないと感じました。

私が技術を使う目的は「業務を進めること」です。
しかし、「業務を進めること」は私にとって外発的動機に分類されます。
つまり「業務を進める上で必要だから仕方なく技術を学んでいる」という状態です。

ああ自分は意識低いんだなぁ、と思ってしまいますが、この状態は別に悪だとは思っていません。
こちらの記事の通り技術に興味がなくても、エンジニアとして生きていくことはできますし、社会貢献をすることもできます。

https://qiita.com/indigonightism/items/c1bf747bed15e2840936

でも好きな技術を持つことに憧れを捨てきれないので下記の行動をとりあえず何も考えずにやってみようかなと思っています
- 業務以外に技術を使う目的を持つ
  - 個人開発する
  - エンジニアコミュニティに参加してみる
  - 学習内容や気づきを記事やLTなどアウトプットする
  - 業務命令以外のところでその技術を使い、課題解決に取り組む

　この辺を試してみてそれでも好きな技術が見つからないのであればもう割り切って「業務を進める上で最低限必要な技術を学び、業務を遂行するエンジニア」を貫きます。


 ## 最後に
 読んでいただきありがとうございました。
 こんなこと書いている時点でエンジニアに向いてないだろ！って思う方いらっしゃるかもしれませんが、向いてる向いてないに関わらず「エンジニアとして好きな技術を持ってみたい」という欲求は少なからずあると思っています。
 皆様は好きな技術はありますか？好きになったきっかけがあればぜひ教えて欲しいです！！
Power AutomateでTeamsのアーカイブされたチームを取得する

［Microsoft Teams］コネクタの［チームの取得］アクションで、アーカイブされたチームを取得してもエラーになりません。

［チームの取得］で、boolean型の「アーカイブ済みであるか(isArchived)」をレスポンス結果として返すので、isArchivedの値を参照してアーカイブ状態を判定できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3640497/0fd9e3a0-43c7-bf28-9c36-36d1283941a2.png)

https://learn.microsoft.com/ja-jp/connectors/teams/#getteamresponse
Gspread の使い方 (シートのRead)

こちらのページを参考にしました。
[[Python] Googleスプレッドシートのデータをpandas DataFrameで読み込み、書き込みを行う](https://note.com/kohaku935/n/ne048969e4617)

Ubuntu 24.04 を使いました。
gspread は、標準のパッケージに含まれていないので、pipx を使いました。

## 環境設定

```bash
sudo apt install python3-oauth2client
sudo apt install pipx
```

pipx でパッケージのインストール

```bash
pipx install gspread --include-deps
pipx install gspread-dataframe --include-deps
```

## service_account.json の用意

[Google Cloud Console](https://console.cloud.google.com) にアクセスし、
IAM & Admin --> Service Accounts とすすみます。

次のような JSON ファイルをダウンロードします。

```json:project-***.json
{
  "type": "service_account",
  "project_id": "project-***",
  "private_key_id": "7ed369f775573954a88bff7cd2****",
  "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEv****",
  "client_email": "project-*****@appspot.gserviceaccount.com",
  "client_id": "1099015721238****",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/project-nov15-2024%40appspot.gserviceaccount.com",
  "universe_domain": "googleapis.com"
}
```

service_account.json にリネームします。

## プログラム

```py:from_spread.py
#! /usr/bin/python
#
import sys
import os

# pipx でインストールされたパッケージのパスを取得

package_path = os.path.expanduser('~/.local/share/pipx/venvs/gspread/lib/python3.12/site-packages')

sys.path.append(package_path)

package_path = os.path.expanduser('~/.local/share/pipx/venvs/gspread-dataframe/lib/python3.12/site-packages')

sys.path.append(package_path)


import gspread
from oauth2client.service_account import ServiceAccountCredentials
import pandas as pd
from gspread_dataframe import get_as_dataframe, set_with_dataframe

SS_ID = '1D1hk5LH6O3BlFehaBgnzfGtbcra***'

credentials = ServiceAccountCredentials.from_json_keyfile_name(
    './service_account.json')
    
gc = gspread.authorize(credentials)
workbook = gc.open_by_key(SS_ID)
worksheet = workbook.sheet1

df_read = get_as_dataframe(worksheet)

print(df_read)
#
```

## 実行結果

```text
$ ./from_spread.py 
   t1301  小山    39561  False  2014-3-12
0  t1302  下野  72843.0    0.0  2014-6-22
1  t1303  栃木  59218.0    0.0   2014-9-9
2  t1304  佐野  37129.0    0.0  2014-10-5
```

元ファイルは、次のものです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/b17bbece-ab8f-c5ee-fcb8-c015da0e6643.png)

## 確認したバージョン

```text
$ python --version
Python 3.12.7

$ pipx --version
1.6.0
```
SORACOM Flux と LINE Messaging API で画像メッセージを配信する方法

この記事では、SORACOM Flux で LINE Messaging API で画像メッセージを送信する方法を解説します。


前回の記事では、SORACOM Flux から LINE Messaging API を使って LINE公式アカウント でメッセージを送る方法を解説しました。

https://qiita.com/yukima77/items/68b133628a00b1e2a654

<br>
今回は、画像メッセージを送る方法を解説して、ソラカメで取得して、SORACOM Harvest Files に保存された画像データを LINE の画像メッセージで送信する方法を解説します。


# LINE Messaging API の画像メッセージ

LINE Messaging API を使って、画像メッセージを送る場合のオブジェクトは以下のような形式となります。

```json
{
  "type": "image",
  "originalContentUrl": "https://example.com/original.jpg",
  "previewImageUrl": "https://example.com/preview.jpg"
}
```

<br>
画像メッセージに関するAPIリファレンスはこちらになるので、詳しくはこちらをご覧ください。

https://developers.line.biz/ja/reference/messaging-api/#image-message


# SORACOM Harvest Filesの画像を送る方法
次に、SORACOM Harvest Files にある画像データを LINE Messaging API で送信する方法を解説します。
ソラカメなどを使った場合には、SORACOM API を使って、ソラカメの画像を SORACOM Harvest Files に保存する方法が簡単なので、Harvest Files Event Channel を使って、SORACOM Harvest Files にファイルが作成されたイベントをトリガーに、LINE Messaging API を呼び出すことを想定しています。

SORACOM Flux の Webhookアクションで指定するHTTPボディは以下のように指定することが出来ます。LINE Messaging API で画像メッセージを送信するは、上記のようにURLを指定しますが、Harvest Files Event Channel をトリガーとした場合は、以下のように設定することで、SORACOM Harvest Files に格納された画像のURLを取得できます。


```json
{
  "messages": [
    {
      "type": "image",
      "originalContentUrl": "${event.payload.presignedUrls.get}",
      "previewImageUrl": "${event.payload.presignedUrls.get}"
    }
  ]
}
```

# まとめ
上記の手順で、SORACOM Flux を使って、SORACOM Harvest Files に格納された画像をLINE公式アカウントで配信することが出来ました！
これらのフローを全て SORACOM Flux のみで完結できるのが、便利なところだと思いますので、さくっと試してみたい方は是非ぜひ！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21408/255e9d8d-b33c-c0bd-6d0a-2a5beca88c36.png)

# その他の参考リンク

https://qiita.com/yukima77/items/68b133628a00b1e2a654

https://qiita.com/yukima77/items/7b65d0695f06ec074343

https://qiita.com/yukima77/items/cb6032987d60ee35a2bd
固定ヘッダーの高さ分スクロールをずらすjs、他ページからアンカーリンクに飛ばすのも対応

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Anchor Adjustment</title>
    <style>
      body {
        margin: 0;
      }
      header {
        position: fixed;
        top: 0;
        width: 100%;
        height: 60px; /* ヘッダーの高さ */
        background: #333;
        color: white;
        display: flex;
        align-items: center;
        justify-content: center;
        z-index: 1000;
      }
      main {
        padding-top: 60px; /* ヘッダー高さ分の余白 */
      }
      section {
        padding: 20px;
        margin: 50px 0;
        border: 1px solid #ccc;
      }
    </style>
  </head>
  <body>
    <header>Fixed Header</header>
    <main>
      <nav>
        <a href="./jsscrollpadding.html#section1">Go to Section 1</a> |
        <a href="#section2">Go to Section 2</a> |
        <a href="./jsscrollpadding.html#section3">Go to Section 3</a>
      </nav>

      <section id="section1">
        <h2>Section 1</h2>
        <p>Content for Section 1</p>
      </section>

      <section id="section2">
        <h2>Section 2</h2>
        <p>Content for Section 2</p>
      </section>

      <section id="section3">
        <h2>Section 3</h2>
        <p>Content for Section 3</p>
      </section>
    </main>

    <script>
      document.addEventListener("DOMContentLoaded", () => {
        // ヘッダーの要素を取得
        const header = document.querySelector("header");

        // ヘッダーの高さを取得
        const getHeaderHeight = () => (header ? header.offsetHeight : 0);

        // アンカーリンクのスクロール位置を調整
        const scrollToAnchor = (hash) => {
          if (hash) {
            const targetElement = document.querySelector(hash);
            if (targetElement) {
              const offset = getHeaderHeight(); // ヘッダーの高さ分をずらす
              const topPosition =
                targetElement.getBoundingClientRect().top +
                window.pageYOffset -
                offset;
              window.scrollTo({ top: topPosition, behavior: "smooth" });
            }
          }
        };

        // ページロード時のURLにアンカーがある場合
        if (location.hash) {
          scrollToAnchor(location.hash);
        }

        // アンカーリンククリック時のスクロール制御
        document.querySelectorAll('a[href^="#"]').forEach((anchor) => {
          anchor.addEventListener("click", (event) => {
            event.preventDefault(); // デフォルト動作をキャンセル
            const targetId = anchor.getAttribute("href");
            scrollToAnchor(targetId); // スクロール位置を調整
          });
        });
      });
    </script>
  </body>
</html>


```
毎年決まっている特別な日（整理 ver1.0 / 2024年11月26日最終更新）

以下に、毎年決まっている特別な日を整理してわかりやすくまとめました：

---

### **美術・文化関連**
- **11月3日「文化の日」**  
  美術館・博物館の常設展などが観覧無料。  
- **5月18日「国際博物館の日」**  
  美術館・博物館の常設展などが観覧無料。  
- **5月5日「こどもの日」**  
  子ども（中学生以下）が美術館・動物園などを無料で利用できることが多い。  
- **9月第3月曜日「敬老の日」**  
  高齢者（65歳以上）が博物館や美術館を無料または割引で利用可能な場合あり。  

---

### **映画関連**
- **12月1日「映画の日」**  
  映画料金が1,000円になる特別日。  
- **毎月1日「映画の日」**  
  映画館の料金が割引（例: 1,000～1,200円）。  
- **毎年3回「映画サービスデー」**（3月・6月・12月の第1土曜日）  
  映画館の料金が割引。  

---

### **書籍・図書館関連**
- **4月23日「子ども読書の日」**  
  図書館で子ども向けの特別イベントが開催されることが多い。  
- **10月27日～11月9日「読書週間」**  
  図書館や書店でキャンペーンや展示会が行われる。  

---

### **商業関連**
- **11月11日「ポッキー＆プリッツの日」**  
  メーカー主導でキャンペーンやイベントが行われる。  
- **7月7日「七夕」**  
  ショッピングモールや商店街で短冊イベントや特別セールが実施される。  
- **11月第4金曜日「Black Friday」**  
  ショッピングモールやオンラインストアで大規模なセールが行われ、特別割引が適用される日。  

---

### **スポーツ関連**
- **10月第2月曜日「スポーツの日」**（旧「体育の日」）  
  地域のスポーツ施設が無料または割引開放される。  
- **8月8日「山の日」**  
  自然公園や登山施設で特別イベントや無料入場が企画される。  

---

### **その他の特別な日**
- **9月20日「空の日」**  
  空港や航空博物館で特別イベントが行われる。  
- **10月10日「目の愛護デー」**  
  眼科や関連施設で無料検診やイベントが開催される。  

---

必要に応じて、随時詳細を更新してまいりますので、気になる日がございましたらぜひお知らせください！
また、内容に誤りがありましたら、ご指摘いただけると幸いです。
Databricksアシスタントのインパクト分析

こちらで紹介されている機能です。

https://docs.databricks.com/ja/databricksiq/databricks-assistant-impact.html

ダッシュボード定義のJSONファイルがこちらに公開されています。こちらをダウンロードしておきます。

https://github.com/databricks/tmm/blob/main/System-Tables-Demo/Assistant-Events/databricks-assistant-metrics.lvdash.json

ダッシュボード一覧で、**ファイルからダッシュボードをインポート**をクリックします。

![Screenshot 2024-11-26 at 10.44.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/7d035113-0795-5f3d-ec44-fe9f93c55f22.png)

ダウンロードしたJSONファイルを選択してインポートします。

![Screenshot 2024-11-26 at 10.45.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/a9c42666-3dd7-319e-e265-6949fc7a2b9d.png)
![Screenshot 2024-11-26 at 10.45.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/44a25b19-ee3d-3819-9c8d-2f74147a1959.png)

アシスタントの利用状況を概観できるダッシュボードが作成されます。

![Screenshot 2024-11-26 at 10.46.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/598db91c-6cc2-919c-0918-bca4a07434f9.png)
![Screenshot 2024-11-26 at 10.46.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/e2cbc154-c925-39a1-1fe5-ccb6be92a8f6.png)

Genieスペースを作成することで、深掘り分析も可能です。

![Screenshot 2024-11-26 at 10.49.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/b5ee7c07-f157-cc3f-8f1c-a2d365c826bc.png)

なお、こちらのダッシュボードでわかるのは利用状況の概要であり、どのようなプロンプトが送信されているのかまではわかりません。マニュアルにあるように、[ユーザーへのアンケート](https://docs.databricks.com/ja/databricksiq/databricks-assistant-impact.html#recommended-survey-questions)を実施いただく必要があります。

### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
ESP32-WROOM32を単体で使おうとしたらリセットを繰り返しまくった件

# 原因

結論を先に書くと、ENをプルアップし忘れてただけでした。
もし忘れてた人いたらちゃんとプルアップしましょう。

# 起こった事象
DEVKITCなどの開発ボードではなく、単体のESP32-WROOM32を自分で設計したPCBに載せて使っていたところ、突然リセットを繰り返すように。
ググるとブートストラップピンのうちフラッシュの供給電圧を決めるGPIO12が起動時にHiになっているとフラッシュへの供給電圧が1.8Vとなり、通常フラッシュは3.3Vで動作するため電圧が足りず起動失敗になるらしい。
そのため起動時にGPIO12はローに落とすか、下の記事のようにefuse書き換えでGPIO12の状態にかかわらずフラッシュの電圧を3.3に固定することで解決している情報をぼちぼち見かけました。
    
https://qiita.com/nichicon/items/43cc870701383fd14d53
    
確かデフォでIO12はプルダウン設定だったよな..？と思いつつIO12をGNDに落とす配線を繋げてテストするも状況は変わらず再起動ループ。

別の事例としてフラッシュ消去すると治るというのもありましたが、そもそも再起動ループで書き込みすらできない状況...

そこでいろいろ試しているうちに気づきました。

**リセット用のENボタンを触ってると再起動の嵐が止む時があるぞ...？と。**

そこからはすぐDEVKITCの回路図を見に行き...するとなんということでしょう。ENピンが10kΩでしっかりプルアップ結線されているではありませんか。

# 結論

...というわけで、ただの初歩的な配線忘れでした。おばか。
ENをプルアップしたら嘘のように安定動作しました。


# さいごに
初めてのQiita記事ですが、こうして覚書的に当たった問題の解決法を記していくのってなんかいいですね。こういうのに助けられてきた身としては、書いた記事で誰か助けられたら嬉しいな...とは思いますが、さすがに今回のは初歩的過ぎて誰もやらかさなさそう...
無人航空機操縦者技能証明：二等

## DIPS2.0での申請
その前にClass NK で試験合格証明書申請が必要。無料。

最大7営業日待てとある。私は４日でメールが届いた。
11月19日(火) 14:52 申請
11月22日(火) 14:53 完了メール到着　#ん？申請と1分違い。自動送信？なわけないか

Class NKから届いたメール抜粋：
>以下の試験合格証明書の発行が完了いたしました。
>
>発行内容：試験合格証明書発行申込み
>
>＜技能証明取得の流れ＞
①試験申込システムより試験合格証明書をダウンロードしてご確認ください。
以下のURLより試験申込システムにログイン後、試験合格証明書発行申込みを選択して「申込内容の確認」ボタンをクリックすると試験合格証明書がご確認いただけます。
>
>②国土交通省が運営管理するドローン情報基盤システム（DIPS）にアクセスし、無人航空機操縦者技能証明の取得申請を行ってください。

DIPS2.0で下までスクロールして、「技能証明の新規交付」。
STEP 02の技能証明情報で「技能証明合格証明書」の添付が必須。
講習修了証明書１はスクールからもらったものを添付（システム上必須ではないようだが。。。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3916302/99755cac-6520-0be6-b397-868c2a5777b0.png)

↑の技能証明合格証明書はClassNK↓（下のほうまでめくる）からダウンロードして添付。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3916302/d782631f-07b6-8153-fec7-1ffc6e7eb761.png)

:::note info
最後にメール送信中・・・みたいなお待ちください画面になって、ちゃんと読んでなくてぼーっと待ち続けても画面変わらずちょっとあせった。
届いたメールのリンクをクリックしないと進まない！
:::

無事完了。。。というか最終結果待ち。

最終結果追記：
11/27 写真がアップすぎると再申請させられた。スマホで撮ったからね。。。
ちなみに、左のがOKで右のがNG。上の余白が3mmほど無いといけないらしい。

<img width="100" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3916302/c0cf9b8b-7fcb-51b4-700b-90d9019a8e3e.jpeg>
<img width="100" src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3916302/73ec63e0-6f71-df74-8c33-77526d964a63.jpeg>

11/28 手数料￥3000納めた
12/05 DIPSからの新規申請完了のお知らせメール到着。完了

## まとめ
申請の全体の流れはスクールで教えてもらったYouTube動画などで手順を調べて進めたが、手順がちょっと違っていた。

https://www.youtube.com/watch?v=FvIi-hkU4B4

もっと初期の手順からまとめるとこんな流れ。※この記事はDとＥ

A学科試験（class NK）
↓
B身体検査（class NK）
↓
C実地試験免除申込（class NK）
↓
D試験合格証明書の発行申込（class NK）
↓
E技能証明書の新規交付（DIPS2.0）

BまではOKで、Cをしようとしたら、どこにもClass NK試験申込システムにメニュー的なものが無い。
そのかわりDがいきなりできるようになっていたので、B→D→Eという流れで申請実施できた。

お世話になったさくらドローンスクールからは、ドローン界隈の制度や申請の仕方は結構頻繁に変更があることは聞いていたのでそこまでびっくりせずにすんでよかった。

https://drone.wisteria-school.jp/okayama.html
AWS + Rails ( ActionMailer のエラー ) のメール送信時のエラー ( Invalid delivery method :ses ) ( aws-sdk-rails 5.0.0 )

# 原因

`aws-sdk-rails 5.0.0` からいくつかのモジュールへの依存関係が削除され、独立したgemになったようだ
 
https://newreleases.io/project/gems/aws-sdk-rails/release/5.0.0

>Feature - [Major Version] Remove dependencies on modular feature gems: aws-actiondispatch-dynamodb, aws-actionmailer-ses, aws-actionmailbox-ses, aws-activejob-sqs, and aws-record-rails.

- aws-actiondispatch-dynamodb
- aws-actionmailer-ses
- aws-actionmailbox-ses
- aws-activejob-sqs
- aws-record-rails
 
# 解決

Gemfile に `aws-actionmailer-ses` を追加する

```rb
gem 'aws-actionmailer-ses'
```

https://rubygems.org/gems/aws-actionmailer-ses


# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ


# プロフィール・経歴

https://github.com/YumaInaura/YumaInaura
Raspberry Pi 3 B +　ＯＳを最新にする。　のだが。。。

以下でＯＳをバージョンアップ
１台目　VNCから実行

1.バージョン確認
```
uname -a
```

2.パッケージ管理リスト更新
```
sudo apt update
```

3.ソフトを最新にする。　時間かかります。５年間も放置していたので（汗）。
```
sudo apt -y upgrade
```

4.OSのディストリビューションを最新に更新
```
sudo apt dist-upgrade -y
```

5.ファームウエアとOSのカーネルをバージョンアップ
Raspberry PiのファームウェアとOSのカーネルをバージョンアップ
```
 sudo rpi-update
```
cp: '//root/.rpi-firmware/vc/hardfp/*' を stat できません: そのようなファイルやディレクトリはありません
で　失敗。
/root/.rpi-firmware/ の配下に vc/hardfp のディレクトリを作成し、再度実行。

https://note.com/enqueue/n/n0bc02bc07015
の延久さん。　ありがとうございます。　うまくいきました。

6.不要なファイルを削除
```
sudo apt autoremove -y
```

7.不要となったパッケージのアーカイブファイルを削除
```
sudo apt autoclean
```

8.更新を有効化するために再起動
```
sudo reboot
```
2台目　VNC接続できない。
あれれ？？？
直接つないでみると　VNCServerで警告が。。。　最新にしてとか言っている。
だめだ。　再インストールしよ。

1台目も思った設定が出てこないので、再インストールしよ。
stylyでvr

# 概要
stylyでvrやってみた。
styly始めてみた。

# 手順

- styly studioを開く。
- 新規シーンを押す。
- シーンタイトルをtest0にする。
- VRシーンにチェックを入れる。
- シーンを作成を押す。
- インサートボタンを押す。
- 3d object >> officeal modelを押す。
- VKO_Motion013をaddする。
- パブリックボタンを押して、公開する。


# 成果物


https://gallery.styly.cc/scene/3eb99167-cceb-494b-a3bd-23f2ebffda04


以上。
【簡単】GPT CrawlerでURLからGPTsを作成する方法

![gpt_crawler_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240240/be12ed8e-86f8-902d-6ea0-ed380dd7a856.png)

AIチャットボットの開発でデータ作成に悩んでいませんか？
今回は、Builder.ioがオープンソース化した「GPT Crawler」を使って、指定したURLから簡単にGPTsを作成する方法をご紹介します。
![gpt_crawler_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240240/910d7910-8a9a-f7c7-b758-a37111919d3a.png)


GPTsを作る時に困るのがデータの作成ですが、このGPT Crawlerを使うとなんとURLを指定するだけでサイトをクローリングしてGPTsに最適なJSONデータを生成してくれます。

# GPT Crawlerとは？

GPT Crawlerは、指定したURLをクローリングし、GPTsに最適なJSONデータを自動生成してくれるツールです。
これにより、データ作成の手間を大幅に削減できます。

# 実践：弊社コーポレートサイトで試してみた

今回は、弊社 MAKE A CHANGE のコーポレートサイトを学習したGPTsを作成しました。
https://makeachange.co.jp/

👉 AIチャットボットを体験する
https://chatgpt.com/g/g-67447768304481918ccc24098610f436-zhu-shi-hui-she-make-a-change

![gpt_crawler_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240240/9ecb3a5b-9dd8-d79f-bc3f-d57ec5624d21.png)

このチャットボットに質問すると、株式会社MAKE A CHANGEに関する情報を即座に提供してくれます。

# 作成手順

手順は以下3ステップです。

①GPT Crawlerをローカル環境に構築
②パラメーターをセットしてGPT Crawlerを実行
③生成されたファイルをGPTsに設定

順番に解説していきます。

## ①GPT Crawlerをローカル環境に構築

まずGitからオープンソース化されたGPT CrawlerをCloneします。

```
git clone https://github.com/builderio/gpt-crawler
```

次にパッケージをインストールします。
```
cd gpt-crawler
npm install
```
つづけてPlaywrightをインストールします。
```
npx playwright install
```
ここまでで環境構築は完了です。

## ②パラメーターをセットしてGPT Crawlerを実行

「config.ts」に読み込みたいURLなどのパラメーターを設定します。
```
export const defaultConfig: Config = {
  url: "https://makeachange.co.jp/corporate/", // 読み込みたいURL
  match: "https://makeachange.co.jp/corporate/**",　// 読み込みたいファイルを指定
  maxPagesToCrawl: 50,
  outputFileName: "output.json",
  maxTokens: 2000000,
};
```
いよいよ実行します
```
npm start
```
実行するとURLからデータを読み込んでいることがわかります。
![gpt_crawler_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240240/dde68eaf-a947-f129-c5a3-55f52c2bf972.png)


完了後、ルートフォルダ内に「output-1.json」というファイルが生成されていました。
![gpt_crawler_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240240/fe2c3829-d71e-a07a-970c-4abfff2d5d09.png)


## ③生成されたファイルをGPTsに設定

あとは生成されたJSONファイルをGPTsに設定して完了です。

「知識」に生成したJSONを設定して完了です。

これで指定したURLの情報を学習したGPTsが作成されました。

## まとめ

GPT Crawlerを使えば、手間のかかるデータ作成が驚くほど簡単になります。GPTsやDifyなどのツールと組み合わせることで、より高度なAIチャットボットを手軽に構築できます。

ぜひ、この便利なツールを活用してみてください。

## おまけ

株式会社MAKE A CHANGEはAIシステム・アプリ開発とソリューションを提供する専門企業です。

お気軽にご相談ください。

また、生成AIに関わる仕事がしたい仲間（AIエンジニア、PM、UIUXデザイナーなど）も募集中です。

https://makeachange.co.jp
【競技プログラミング】AtCoder Beginner Contest 337_D問題

# 問題
https://atcoder.jp/contests/abc337/tasks/abc337_d

# 解法手順
1. 入力を受け取る
   - H, W, K を入力から取得
   - H行のグリッド情報を文字列のリストとして取得

2. 変数の初期化
   - 答えを格納する変数 ans を非常に大きな値（INF）で初期化
   - 累積和を記録するための配列 X と D を用意（サイズは max(H, W) + 1）

3. 横方向の探索
   - 各行について以下の処理を行う：
     a. X と D の累積和を計算
     b. 連続する K 個のマスについて、'x' がないかチェック
     c. 'x' がない場合、その区間の '.' の数を数え、ans を更新

4. 縦方向の探索
   - 各列について以下の処理を行う：
     a. X と D の累積和を計算
     b. 連続する K 個のマスについて、'x' がないかチェック
     c. 'x' がない場合、その区間の '.' の数を数え、ans を更新

5. 結果の出力
   - ans が更新されていれば（INFでなければ）その値を出力
   - ans が更新されていなければ（INFのままなら）-1 を出力



# ACコード

```python:ac.py
# 1. 入力を受け取る
H, W, K = map(int, input().split())
grid = [input() for _ in range(H)]

# 2. 変数の初期化
INF = float('inf')
ans = INF
X = [0] * (max(H, W) + 1)
D = [0] * (max(H, W) + 1)

# 3. 横方向の探索
for row in grid:
    # a. X と D の累積和を計算
    for i in range(W):
        X[i+1] = X[i] + (row[i] == 'x')
        D[i+1] = D[i] + (row[i] == '.')
    
    # b. 連続する K 個のマスについて、'x' がないかチェック
    # c. 'x' がない場合、その区間の '.' の数を数え、ans を更新
    for i in range(W - K + 1):
        if X[i+K] - X[i] == 0:
            ans = min(ans, D[i+K] - D[i])

# 4. 縦方向の探索
for col in range(W):
    # a. X と D の累積和を計算
    for i in range(H):
        X[i+1] = X[i] + (grid[i][col] == 'x')
        D[i+1] = D[i] + (grid[i][col] == '.')
    
    # b. 連続する K 個のマスについて、'x' がないかチェック
    # c. 'x' がない場合、その区間の '.' の数を数え、ans を更新
    for i in range(H - K + 1):
        if X[i+K] - X[i] == 0:
            ans = min(ans, D[i+K] - D[i])

# 5. 結果の出力
print(ans if ans != INF else -1)

```
【chatGPT 対話備忘録】JavaとPLC機器

# 私：
JavaとPLC機器の送受信に関する情報について教えて

# ChatGPT:
Javaを使用してPLC機器との送受信を実現するためには、PLC機器の通信プロトコルや仕様を理解する必要があります。以下に一般的な方法とポイントを説明します。

### 1.PLCとの通信方法
PLCとの通信は、通常以下のいずれかの方法で行われます：

Ethernet/TCP/IP通信

通信プロトコル：MODBUS TCP、MCプロトコル（三菱）、EtherNet/IPなど。
通信設定：IPアドレス、ポート番号を設定してソケット通信を行います。
シリアル通信 (RS-232/RS-485)

通信プロトコル：MODBUS RTUなど。
Javaではシリアル通信ライブラリ（例：JavaComm、RxTxライブラリ）を利用します。
メーカー専用ドライバ

各メーカーが提供するSDKやドライバを使用します（三菱のMELSOFT Libraryなど）。


### 2.必要な準備
PLCの仕様確認

使用するPLCの通信プロトコル（MODBUS、MCプロトコルなど）を確認します。
読み取り・書き込み対象のデバイスアドレスを把握します（例：D0、M100）。
Java環境の整備

Java開発環境（JDK、IDEなど）。
必要に応じて通信ライブラリ（RxTx、Apache MINAなど）。
ネットワーク設定

PLCのIPアドレスやポート番号を確認します。


### 3.ソケット通信の基本コード
以下は、PLCとTCP/IP通信を行う基本的なサンプルコードです。

```java:java
import java.io.*;
import java.net.*;

public class PLCCommunicator {
    private String plcIp = "192.168.0.10"; // PLCのIPアドレス
    private int port = 502; // ポート番号（例: MODBUS TCPのデフォルトは502）

    public void sendCommand(String command) throws IOException {
        try (Socket socket = new Socket(plcIp, port)) {
            OutputStream outputStream = socket.getOutputStream();
            InputStream inputStream = socket.getInputStream();

            // コマンドを送信
            outputStream.write(command.getBytes());
            outputStream.flush();

            // 応答を受信
            byte[] response = new byte[1024];
            int bytesRead = inputStream.read(response);

            // 応答を表示
            System.out.println("Response: " + new String(response, 0, bytesRead));
        }
    }

    public static void main(String[] args) {
        PLCCommunicator communicator = new PLCCommunicator();
        try {
            String command = "02FF00025920000000100600"; // サンプルコマンド
            communicator.sendCommand(command);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
```
ポイント:
plcIp と port は使用するPLCに合わせて変更してください。
command はPLCのプロトコル仕様に従って作成します（例：MCプロトコルコマンド）。
応答データを適切に解析する必要があります。


### 4.注意点
リアルタイム性の考慮

通信のタイミングがシステム要件に合うように、スレッドや非同期処理を適切に使用します。
エラーハンドリング

タイムアウトや通信エラーの処理を実装する。
データの解析

PLCからのデータは通常、バイナリ形式や特定のプロトコルに基づいているため、適切なデコード処理が必要です。
テストとデバッグ

PLCのシミュレータを利用してテストすることをお勧めします（メーカーが提供している場合があります）。


### 5.リソース
MODBUSプロトコル: MODBUS公式サイト
三菱MCプロトコル仕様書: 三菱公式サイトまたはサポートから入手可能。
Javaシリアル通信ライブラリ: RxTx
カスタム化の提案
ご使用のPLCの詳細（メーカー名、モデル名、通信プロトコル）を教えていただければ、より具体的な実装例をご提供できます！
React / GitHub Actions を使用した自動テストの設定手順


このガイドでは、GitHub Actions を使って特定のブランチ（例: `feature/new-feature-test-ci`）に変更がマージされた際に自動でテストを実行する方法を説明します。

---

## **1. GitHub Actions とは**
GitHub Actions は、GitHub リポジトリでコードのビルド、テスト、自動化を行う CI/CD ツールです。リポジトリ内に設定ファイルを追加するだけで、自動テストやデプロイを行うワークフローを構築できます。

---

## **2. プロジェクトの準備**

### **必要なツール**
- Node.js プロジェクトが既に設定されていること。
- テストコマンド（例: `npm run test`）が正常に動作すること。

---

## **3. ワークフローの設定**

### **ファイル作成**
1. リポジトリのルートディレクトリに `.github/workflows` フォルダを作成します。
2. `test.yml` ファイルを作成します。

### **ファイル内容**
以下の内容を `test.yml` に記述します。

```yaml
name: Run Tests on Push

on:
  push:
    branches:
      - feature/new-feature-test-ci # このブランチへのプッシュまたはマージ時に実行

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      # ソースコードをチェックアウト
      - name: Checkout repository
        uses: actions/checkout@v3

      # Node.js のセットアップ
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 18 # 必要なNode.jsのバージョン

      # 必要な依存関係をインストール
      - name: Install dependencies
        run: npm install

      # テストを実行
      - name: Run tests
        run: npm run test
```

---

## **4. 設定ファイルの説明**

- **`on.push.branches`**:
  - `feature/new-feature-test-ci` ブランチへのプッシュまたは他のブランチからのマージをトリガーにします。
- **`runs-on`**:
  - テストを実行する仮想マシン環境を指定します（ここでは最新の Ubuntu）。
- **`actions/checkout`**:
  - リポジトリのコードを CI 環境にクローンします。
- **`actions/setup-node`**:
  - Node.js のバージョンを指定してインストールします。
- **`npm install`**:
  - `package.json` に記載された依存関係をインストールします。
- **`npm run test`**:
  - テストを実行します。

---

## **5. テストの確認方法**

### **ワークフローの動作確認**
1. **プッシュまたはマージを行う**
   - `feature/new-feature-test-ci` ブランチに変更をプッシュするか、プルリクエストをマージします。
2. **GitHub Actions を確認**
   - リポジトリの「Actions」タブに移動し、`Run Tests on Push` ワークフローが実行されていることを確認します。

### **成功例**
テストが正常に実行されると以下のようなステータスが表示されます：
- **Actions タブ**: 実行されたワークフローが `✓` マークで表示されます。
- **プルリクエスト**: 成功ステータスが確認できます。


![スクリーンショット 2024-11-26 9.50.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2294049/e9f4a629-5ab2-ba63-83a3-623c4b53a813.png)

---

## **6. 問題が発生した場合のトラブルシューティング**

### **エラー例と対策**
1. **依存関係のインストールエラー**
   - エラーログで必要なパッケージが見つからない場合、`package.json` を確認し、必要な依存関係をインストールして再度コミットします。

2. **テストスクリプトが実行されない**
   - `package.json` の `scripts` に `test` が正しく定義されているか確認してください。

   ```json
   {
     "scripts": {
       "test": "vitest"
     }
   }
   ```

3. **Node.js バージョンの不一致**
   - プロジェクトで使用している Node.js のバージョンと `setup-node` の設定が一致しているか確認してください。

---

## **7. 補足情報**

- **プルリクエストのみに適用する場合**
  以下のように `on.push` を `on.pull_request` に変更します。

  ```yaml
  on:
    pull_request:
      branches:
        - feature/new-feature-test-ci
  ```

- **他のブランチでも同じ設定を使用する場合**
  `branches` にブランチ名を追加するか、`branches-ignore` を使用して除外するブランチを指定します。

---

これで GitHub Actions を使った自動テストの設定が完了しました。これにより、コードの変更が `feature/new-feature-test-ci` ブランチにプッシュまたはマージされると、テストが自動的に実行されます。
OACのビジュアライゼーションの凡例を自由な位置に

# はじめに
OAC（**Oracle Analytics Cloud**）でビジュアライゼーションを作成すると、選択したビジュアライゼーション・タイプにより凡例が自動的に表示されます。
最近追加された、「凡例」ビジュアライゼーションを使えば、これまでよりもさらに自由な位置に凡例を配置できます。

# 凡例
サンプルを作ってみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/927a48a1-deb5-33e3-2531-2e682539c440.png)

それぞれのビジュアライゼーションごとに凡例が表示されています。
「受注優先度に基づいたデータ分析」をテーマにしたこのキャンバスでは、どのビジュアライゼーションでも「Order Priority」が凡例として表示されています。

# 凡例の表示場所
凡例の位置は、ビジュアライゼーションごとに設定できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/4992659e-4684-7cb9-812c-f90852e942aa.png)

デフォルトでは、「自動」となっています。

# 凡例ビジュアライゼーション
「Order Priority」を右クリックして、「ビジュアライゼーションの選択」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/397f2848-7b2c-21d5-58e3-393d286cb530.png)

「凡例」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/5b38e049-4838-2fac-1abc-80fd5e851f19.png)

キャンバスに「凡例」ビジュアライゼーションが追加されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/f14c536c-d4a8-13f5-7b10-87a3c34d8762.png)

大きさや位置を変更してみましょう。

横長にして、右下に配置しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/1a220967-ea6c-5460-2833-8bf94ffb9c52.png)

他のビジュアライゼーションで凡例を表示する意味がなくなったので、「なし」にしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/f37c256e-799b-d580-638a-5bac3299a2ef.png)

凡例を「なし」にしたので、各チャートがより大きく表示できるようになりました。

# その他の利用例
自由書式にしたキャンバスで、積上げ棒ビジュアライゼーションに凡例ビジュアライゼーションを重ね合わせてみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342206/8b51b551-90e4-a03b-6f1e-58a26877d710.png)
【chatGPT 対話備忘録】JDBCとは

私：
JDBCとは

ChatGPT:
JDBC（Java Database Connectivity） は、Javaでデータベースに接続し、SQLを使ってデータの操作（取得、挿入、更新、削除）を行うためのAPI（Application Programming Interface）です。JDBCを使用すると、Javaアプリケーションからリレーショナルデータベース（RDBMS）にアクセスできます。

JDBCの特徴
標準化されたAPI:

JDBCはJavaで標準化されており、異なるデータベースでも同じ方法で操作可能です。
各データベースベンダーは、自社のデータベースに対応するJDBCドライバを提供しています。
柔軟なデータベース操作:

SQLクエリを送信してデータベースを操作できます。
結果の取得やデータベースとのトランザクション管理が可能です。
トランザクション管理:

commitやrollbackを使用してトランザクションを制御できます。
JDBCの構成
JDBCは以下の主要な要素で構成されています：

JDBCドライバ:

データベースとJavaアプリケーションを接続するためのブリッジです。
例: MySQLのJDBCドライバ（mysql-connector-java）、MariaDBのJDBCドライバなど。
JDBC API:

Java標準ライブラリとして提供されるクラスやインターフェイスの集合。
主なインターフェイス：
DriverManager：接続を管理
Connection：データベース接続
Statement：SQL文の実行
ResultSet：SQLクエリの結果の処理
基本的なJDBC操作の流れ
JDBCドライバのロード:

```java:java
Class.forName("com.mysql.cj.jdbc.Driver"); // MySQL用
```
データベースに接続:

```java:java
Connection conn = DriverManager.getConnection(
    "jdbc:mysql://localhost:3306/your_database", "username", "password");
```
SQL文の作成と実行:

```java:java
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM your_table");
```
結果の処理:

```java:java
while (rs.next()) {
    System.out.println(rs.getString("column_name"));
}
```
リソースの解放:

```java:java
rs.close();
stmt.close();
conn.close();
```
JDBCのメリット
データベース独立性:

JDBCはJava標準APIなので、異なるデータベースを操作する際もコードをほぼ変更する必要がありません（ドライバを切り替えるだけ）。
広範なサポート:

多くのデータベース（MySQL, PostgreSQL, Oracle, SQL Serverなど）で使用できます。
トランザクション制御:

複雑な操作にも対応。
JDBCの使用例
以下は、MySQLデータベースに接続してデータを取得する簡単な例です：

```java:java

import java.sql.*;

public class JDBCExample {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/testdb";
        String user = "root";
        String password = "password";

        try (Connection conn = DriverManager.getConnection(url, user, password);
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery("SELECT * FROM users")) {

            while (rs.next()) {
                System.out.println("ID: " + rs.getInt("id") + 
                                   ", Name: " + rs.getString("name"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
```
これにより、JDBCを使用してデータベースに接続し、データを操作する基本的な流れを理解できます。
Nutanixバイブルのメモ①

# はじめに
Nutanixバイブルを読み始めたので自分自身の備忘録としてメモしてみます。
参考にしたサイトは https://www.nutanixbible.jp/ です。

# 今日のトピック
「第1章：The Basics」-「Where We Started」をメモしてみる。
私の個人的な理解やメモはcode記法で記載します。

# 概要
- NutanixのHCIは「WebスケールIT」の原則を活用している。
`⇒「WebスケールIT」とは？
    ・大規模なクラウドサービスプロバイダーが採用するITインフラストラクチャーのこと。
    ・システムの拡張性・効率性・柔軟性を高めることが可能。`
    
- Webスケールなインフラストラクチャーの重要な要素は以下。
    - ハイパーコンバージェンス
    - ソフトウェアデファインドインテリジェンス
    - 自律分散システム
    - インクリメンタルかつリニアな拡張性

- その他の要素は以下。
    - APIベースの自動化と豊富な分析機能
    - セキュリティをコアに据えている
    - 自己修復機能

# Where We Started
- Nutanixは、ある1つの目標に焦点を当てて考案された。それは ***あらゆる場所のインフラストラクチャーコンピューティングを、存在を意識しなくていいくらい簡単（インビジブル）にする。*** ということ。
`⇒ ITインフラ管理が「インビジブル＝利用者が意識する必要がない・気づかないほど、シンプルに利用可能にするということと理解。`

- このシンプルさは、次の3つのコア領域に焦点を当てることで達成された。
    - 選択とポータビリティを可能にする。（HCI/Cloud/Hypervisor）
    - コンバージェンス、抽象化、インテリジェントソフトウェア（AOS）による「スタック」のシンプル化。
    - ユーザーエクスペリエンス（UX）とデザイン（Prism）を重視した、直感的なユーザーインターフェイス（UI）の提供。

- HCI/Cloud/Hypervisor
    - 特定の1つのHypervisorやプラットオームもしくはクラウドがすべての顧客のニーズに適合するわけではないため、同じプラットフォーム上で複数のHypervisorをサポートすることにした。
    - これにより顧客に選択と自由を提供。加えて異なるプラットフォーム間で移動できるようにすることで柔軟性を提供。
    - 12種類以上のHWプラットフォームと複数のハイパーバイザー（AHV/ESXi/Hyper-Vなど）をサポートし、主要なクラウドベンダー（AWS/Azure/GCP）とのインテグレーションを拡充している。
`⇒ この記載の後に「ワンオフ製品（オーダーメイド品）を作ろうとしているわけではなく、プラットフォームを構築している」との表現もあった。そのため、Nutanixは"仮想基盤"を提供するのではなく"選択の自由を持ったクラウド基盤"を提供している。と理解。`

- AOS+AHV/ハイパーバイザー：「ランタイム」
    - 分散ストレージファブリック（DSF）と呼ばれる機能でストレージのシンプル化をはかっている。
`⇒ DSFとはデータを複数ノードに分散配置する仕組み。各ノードのローカルにデータを配置し、各ノードでストレージI/Oをさばいている。`
    - シンプル化をはかるために以下の2つのコア領域に分割されている。
        1. コアサービス・・・基礎的なサービス群
        2. プラットフォームサービス・・・コアサービスをもとにしたサービス群であり、付加的な機能およびサービスを提供する
`⇒ AOSとは？
    ・CVM内で稼働するOSのこと。
    ・Nutanixのコア機能を提供するOS。（実体はCentOSらしい）
    ・Prism等の画面サービスやHypervisorへのストレージサービス等の機能を提供。`

- Prism：「インターフェイス」
    - シンプルさ、一貫性、直感性にフォーカスしたデザイン原則を適用することを意識して、「フロントエンド（UI/UX）」に多大な時間と労力を費やした。
    - プラットフォームに単一インターフェイスを提供し、その中で一貫した操作体験を維持することを重点としている。
`⇒ いろいろなサービスや複数のHypervisorをPrismで提供される単一画面で管理できることを目的としている。と理解。`

- Nutanix：「プラットフォーム」
    - Nutanixのビジョンはシンプルであり、 ***「単一のプラットフォームでアプリとデータの場所を問わず実行可能にする」*** である。
    - 2014年頃に作成されたNutanixプラットフォームアーキテクチャーを説明するためのイメージ図があるが、現在までに多くは変わっていない。ただ拡大を続けている。

# おわりに
まずは「第1章：The Basics」-「Where We Started」のメモを書いてみました。
次回は「第1章：The Basics」-「製品とプラットフォーム」について書こうと思います。
（NCPですが、6.5を受験するか、6.10まで待つか悩み中です・・・。）
自動分類ノードで2値の判別予測の確信度が0.5を下回る理由(SPSS Modeler データ加工逆引き12-6)

# 自動分類ノードで2値の判別予測の確信度が0.5を下回る理由

![スクリーンショット 2024-11-18 9.52.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/62d7ab1f-0d98-bc24-5063-0ba1c40ce1ad.png)

## 1.想定されるトラブル

・2値の判別予測時に自動分類ノードを用いると不自然な確信度が表示される

　→シングルモデルによる2値分類では確信度0.5を分岐点に真偽を判別するため、
 　確信度は0.5以上ですが、　アンサンブル学習のロジック上、起こり得る現象です。
   
## 2.ストリームのダウンロード

https://github.com/yoichiro0903n/blue/raw/refs/heads/main/conf_low.str

## 3.サンプルストリームの説明

![スクリーンショット 2024-11-18 9.54.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/3f5a9bde-7674-8cc9-f429-7a80dcf2a183.png)

a.入力は以下の通りです。スマートフォンの利用状況から事後の解約を予測するためのデータです。

![スクリーンショット 2024-11-18 9.59.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/c48fd198-a0e0-690f-59f1-94288b5baf96.png)

#### 不自然な確信度の確認

b.[データ型]ノードを編集します。

![スクリーンショット 2024-11-18 10.00.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/7a126f51-a00a-e536-cd1c-3dee361ad91b.png)

c.[自動分類]ノードを編集します。[使用モデル数]を説明しやすいように3つにしています。

![スクリーンショット 2024-11-18 10.00.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/5b3c08b3-a91e-6d06-c893-ea5704f25411.png)

d.[自動分類]ナゲットを編集します。[C5.0][XGBoostツリー][CHAID]の３つのモデルが選択されました。

![スクリーンショット 2024-11-18 10.00.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/e17d775b-9969-f57f-86a4-f5d6ed6c3047.png)

e.[ソート]ノードを編集します。確信度を[昇順]で並び替えます。

![スクリーンショット 2024-11-18 10.01.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/9b2b727c-e504-f35d-fce0-8a73851f319b.png)

f.[テーブル]ノードを実行します。３つのモデルを統合した確信度[$XFC-解約フラグ]には本来存在しない0.5以下のスコアが表示されています。

![スクリーンショット 2024-11-18 10.01.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/1b8d5acf-1e63-e538-50b9-a829cd2b5ed8.png)

#### 確信度算出のロジックを確認

g.[自動分類]ノードを編集します。[アンサンブル　モデルにより生成された...]のチェックを外します。

![スクリーンショット 2024-11-18 10.02.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/257afb0d-de05-2fae-40c3-e072e02dc675.png)

h.[テーブル]ノードを実行します。

![スクリーンショット 2024-11-18 10.04.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/31dd8219-1e06-3c91-371c-91f290b8668b.png)

先頭レコードの確信度が0.452になる理由は

C5.0 はTrue と予測して確信度が0.800
XGBoost はTure と予測して確信度が0.555
CHAID　は False　と予測して確信度が0.818

Tureの確信度のみ合計し、モデル数で按分　(0.8+0.55)/3 = 0.452になります。

アンサンブルの記事でも取り上げています。

https://qiita.com/416nishimaki/items/b88e9b353adb863f8a47

#### 注意事項

SPSS Modeler (Ver18.5) では確信度=0.5丁度の場合にはFalse
SPSS Statistics (Ver30) では確信度=0.5丁度の場合にはTure
で判定されます。Statisticsにはアンサンブルや自動分類がないためこの記事の主旨とは
異なりますが参考まで。

## 4.参考情報

#### 自動分類ノード

https://qiita.com/416nishimaki/items/3861d67b960a91fa4137

#### SPSS Modeler ノードリファレンス目次

https://qiita.com/416nishimaki/private/503037195081d3323eee

#### SPSS Modeler 逆引きストリーム集（データ加工）

https://qiita.com/416nishimaki/items/4bf813e6cba84b2a1008
【MUI】【CSS】自作コンポーネントに固定のCSSを与えつつ、場合によって＋αのCSSを当てたい時の書き方。

## シチュエーション
「MUIを利用した自作のコンポーネント、backgroundColorを青色にするCSSだけで基本的には良いんだけど、場所によっては青以外の別の色に変更したり、他のCSSも当てたいんだよな〜」って時のやり方です。

```tsx:SampleComponent.tsx
import React from 'react';
import { Box, Typography } from '@mui/material';

const SampleComponent = ({ sx = {}, ...props }) => {
  // デフォルトのスタイル
  const defaultStyles = {
    backgroundColor: 'blue',
  };

  return (
    <Box sx={{ ...defaultStyles, ...sx }} {...props}>
      <Typography variant="h6">This is a sample component</Typography>
    </Box>
  );
};

export default SampleComponent;
```

### ポイント
1.プロップスでsxを受け取る
※ちなみに型を定義する際は「?」でオプショナルにする。
```tsx
const SampleComponent = ({ sx = {}, ...props }) => {}
```

2.デフォルトのスタイルを用意
コンポーネントを使う側は、sxプロップスを指定しなければ`defaultStyles`に定義したCSSだけが適用されます。
```tsx
  // デフォルトのスタイル
  const defaultStyles = {
    backgroundColor: 'blue',
  };
```



3.スプレッド構文でオブジェクトマージ
```tsx
<Box sx={{ ...defaultStyles, ...sx }}
```
一番のポイントです。
オブジェクトマージによって最終的に一つのオブジェクトをsx属性に当てます。
ちなみにプロップスのsxにbackgroundColorを赤色で指定すれば、最終的に赤色になります。
オブジェクトマージは同一のプロパティが存在する場合は右側のプロパティの値で上書きされる為です。

## さいごに
今回のやり方はMUIのsxでなくても、divのような純粋なHTMLのstyle属性にも同じことが出来ます。
常にCSSをプロップスを受け取るだけではなく、共通化できそうなCSSがあればデフォルトのCSSを当ててコードの重複を減らすことを意識していきましょう！
結合テストの歴史と進化 第2回：モジュール化時代の到来

## はじめに

前回は、IBMメインフレーム時代の結合テストについて見てきました。メインフレーム時代の「結合テスト」は巨大なパズルを組み立てるような作業であり、失敗すれば膨大な手戻りが発生しました。この状況を打破する鍵として生まれたのが、構造化プログラミングの手法です。
## 構造化プログラミングの台頭

### スパゲッティコードの時代
1970年代初頭、多くのプログラムは「スパゲッティコード」と呼ばれる非構造的な形態をとっていました。GOTO文が乱用され、コードは複雑な相互参照の迷宮と化し、バグの発見や修正が極めて困難でした。エラーを1つ修正すれば、別の箇所で新たな問題が発生することもしばしば。
```fortran
! GOTO文
GOTO 100 ! ラベル「100」へジャンプ
      ...
100   IF (X .GT. 0) GOTO 200 ! ラベル「100」で、変数Xが0より大きいかどうかを判定し、大きければ、ラベル「200」へジャンプ
      Y = -1 ! Xが0以下の場合、Y = -1
      GOTO 300
200   Y = 1
300   CONTINUE
```
あるNASAのプロジェクトで、わずか数行のコード修正が原因でロケット打ち上げ計画が数週間遅れたことがありました。この事件を契機に、開発効率を劇的に向上させる方法が求められるようになります。

### 構造化プログラミングの誕生
1968年、エドガー・ダイクストラが「GOTO文を排除すべきだ」と提唱する論文を発表しました。この理論に基づき、ソフトウェアを**「順次」「選択」「繰り返し」**の3つの構造に基づいて設計する手法が生まれました。これが「構造化プログラミング」です。
```pascal
{ 構造化プログラミング }
if x > 0 then
  y := 1
else
  y := -1
end if
```

構造化プログラミングの特徴：
1. コードの可読性向上
2. プログラムの論理的構造の明確化
3. デバッグと保守の容易さ
## Design by Contractの誕生

### 契約による設計の背景
Bertrand Meyerは、1970年代後半にモジュール間の関係を「契約」として捉える考え方を提唱しました。
契約による設計とはモジュール間のインターフェースを「契約」として定義し、各モジュールが以下を保証します。
1. 事前条件
モジュールが正常に動作するために必要な条件
2. 事後条件
モジュールが処理後に保証する結果
3. 不変条件
プロセス中に維持されるべき状態

この契約により、以下の利点が生まれました。
1. モジュール間の依存関係が明確化。
2. テストケース設計がシステマチックに。
3. 早期に設計の不備を発見可能。
## 初期の結合テスト手法

### トップダウンテスト vs ボトムアップテスト

1970年代、大規模システムの開発では、システム全体を小さなモジュールに分解し、段階的にテストする手法が発展しました。
また、テスト中の未完成モジュールを模倣するための「スタブ」と、テストを実行する「ドライバ」の概念が生まれました。
トップダウンテストの例：
```pascal
procedure MainModule;
  procedure SubModule1;  // スタブモジュール
    begin
      result := test_data;  // テスト用のダミーデータ
    end;
  begin
    SubModule1;  // サブモジュールの呼び出し
    ProcessData;  // メインロジックの実行
  end;
```

ボトムアップテストの例：
```pascal
procedure TestDriver;  // テスト実行用のモジュール
  begin
    SubModule1.Input := test_data;  // テスト入力の設定
    SubModule1.Execute;  // サブモジュールの実行
    AssertEquals(expected, SubModule1.Output);  // 結果の検証
  end;
```

## モジュール化時代の教訓

### 1. インターフェースの重要性
1.  インターフェースの安定性が重要
2. 依存関係の明確化
3. カプセル化の価値

### 2. テスト容易性の設計

設計原則の確立：
1. 単一責任の原則
2. 依存関係の最小化
3. インターフェースの単純化

### 3. テストプロセスの標準化
1. ユニットテスト
2. モジュール結合テスト
3. サブシステムテスト
4. システム結合テスト
5. 受入テスト

## 現代への影響

### 1. モジュール設計の原則
構造化プログラミング時代に確立された設計原則は、現代のソフトウェア開発の基盤となっています：

- 単一責任の原則
- 明確なインターフェース定義
- 依存関係の最小化

### 2. テスト戦略の進化
当時確立されたテスト手法は、現代のソフトウェア開発プロセスに直接つながっています：

```yaml
# 現代のCI/CDパイプライン
stages:
  - unit          # ユニットテスト
  - integration   # モジュール結合テスト
  - system        # システムテスト
  - acceptance    # 受入テスト
```

### 3. 契約による設計の現代的展開
Design by Contractの概念は、現代のプログラミング言語や静的型付けシステムに深く組み込まれています：

```typescript
// TypeScriptでの型による契約の実現
interface UserService {
  // 入力の型制約 = 事前条件
  getUser(id: PositiveInteger): Promise<User>;
  
  // 戻り値の型制約 = 事後条件
  updateUser(user: User): Promise<UpdateResult>;
}
```

### 4. テストの重要性の認識
この時代に確立された重要な教訓：
- コードの品質は設計段階で決まる
- テスト可能性を最初から考慮する
- モジュール間の明確な境界線の重要性