OmniAICreator/Qiita-1.07M huggingface dataset:
特定のフォーマットの入力文字列からデータを解析し、そのデータを基にHTMLテーブルを生成する

特定のフォーマットの入力文字列からデータを解析し、そのデータを基にHTMLテーブルを生成するものです。具体的には、複数の「ブランチ」に関する情報が入力され、それぞれのブランチについてバージョンとキーに関連する値のペア（a,b,c,dなど）が含まれています。これらの情報を分析し、整理してHTMLテーブル形式で出力します。

```
# 入力文字列
input_string = "ブランチ1/V00.01/a:10:100,b:10:100,c:-----:-----,d:10:100 ブランチ2/V00.02/a:10:100,b:10:150,c:-----:-----,d:20:200"

# 入力文字列を処理してデータを抽出
branches_data = input_string.split()
branch_info = []
branch_names = []
data_keys_order = []

# データ項目の順序を保持するために最初のブランチから順序を取得
first_branch_data = branches_data[0].split('/', 2)[2]
data_keys_order = [item.split(':')[0] for item in first_branch_data.split(',')]

for branch in branches_data:
    parts = branch.split('/', 2)  # 最初の2つのスラッシュで分割
    name, version, data = parts
    branch_names.append(name)
    data_items = data.split(',')
    data_dict = {}
    for item in data_items:
        key, st_ver, st_size = item.split(':')
        data_dict[key] = [st_ver, st_size]
    branch_info.append({'name': name, 'version': version, 'data': data_dict})

# HTMLテーブルの作成を開始
html_output = '<table border="1">\n'
html_output += '  <tr>\n    <th colspan="2">ブランチ</th>\n'
for name in branch_names:
    html_output += '    <td colspan="2">{}</td>\n'.format(name)
html_output += '    <th rowspan="2">結果</th>\n'  # 結果列のヘッダーを追加
html_output += '  </tr>\n  <tr>\n    <th colspan="2">バージョン</th>\n'
for info in branch_info:
    html_output += '    <td colspan="2">{}</td>\n'.format(info['version'])
html_output += '  </tr>\n'

# データ行の処理
for key in data_keys_order:
    values = [info['data'][key] for info in branch_info if key in info['data']]
    numeric_values = [value for value in values[1] if value.isdigit()]
    row_style = ''
    result_cell = ''
    if len(set(numeric_values)) > 1 and numeric_values:  # 数値が一致しない場合（空リストを除外）
        row_style = ' style="background-color:pink;color:red;"'
        result_cell = '    <td{}>warning</td>\n'.format(row_style)
    else:
        result_cell = '    <td></td>\n'

    html_output += '  <tr>\n'
    if key == data_keys_order[0]:  # 最初のキーであればrowspanを設定
        html_output += '    <th rowspan="{}">機種</th>\n'.format(len(data_keys_order))
    html_output += '    <th{}>{}</th>\n'.format(row_style, key)
    for value in values:
        cell_style = row_style if row_style else ''
        html_output += '    <td{}>({})</td>\n'.format(cell_style, value[0])
        html_output += '    <td{}>{}</td>\n'.format(cell_style, value[1])
    html_output += result_cell  # 結果セルを追加
    html_output += '  </tr>\n'
html_output += '</table>'

print(html_output)
初投稿

# 自己紹介

・社会人二年目を迎えます。
・お酒が好きです。
# 保有資格
・基本情報技術者
・AWS Certified Cloud Practitioner
・Azure Fundamentals
・Azure Administrator
# 技術範囲
仕事ではAzureを主に使っています。
その他にはjava,Dartあたりを触ってアプリを作って遊んだりしています。
# 直近の目標
・応用情報技術者試験の合格を目指しています。
# Qiitaを始めた理由
社会人一年目がそろそろおわりに近づき、何もしていない自分に焦りを覚えました。
また、躓いた箇所を備忘録として残すことで、今後に役立てればと思い始めました。
# 最後に
同じ境遇の方と助け合いながら、日々乗り越えていければと思います
アクセス制御

publicは全てのクラスからのアクセスを許可します。
privateは同一クラスからのアクセスのみを許可します。

また、アクセス修飾子をクラス宣言に記載しない場合は、同一パッケージに属するクラスからのアクセスを許可(pakage private)します。
同窓会って「どう？」「そうかい？」

同窓会、高校で一つ、遠方の大学で二つでたことがある。

小学校、中学校と、地元の大学の同窓会はでたことがない。

今、はっと気がついた。

愛知県在住なのに、愛知県内にある卒業した大学の同窓会に誘われたことがない。

東京の大学と静岡県の大学は、仕事場の同窓会の案内が来て出たことがある。

地元の大学だけなぜ案内が来ないのだろう。

そこではっと思い出した。地元の大学だけ同窓会名簿を買ったことがある。
登録してある住所は間違いがない。

二人の学長から呼び出しがあって説明に行ったこともある。

卒業後もサークル活動に参加していた。

ある企業との共同研究で、アセンブラのプログラムも書きに行ってた。

経済産業省の事業で、自分の卒業大学と岐阜県の大学の連携した事業のプロジェクトマネージャもやった。

岐阜県の大学からは、非常勤講師の依頼があり、１０年間、修士課程の特別講義を担当した。

地元の大学からは講演依頼もない。

学会での招待講演の話はあった。当日、自分の組織主催の講演会があり、お断りした。

それがいけなかったのだろうか。

嫌われていたのだろうか。

なぞはなぞを呼ぶ。

私がアセンブラを書いた企業と大学の共同研究のアドバイザに４事業ほど呼ばれた。

嫌われてたら仕事は来ないはずだ。

あ、そうか。同窓会費を払っていない。

同窓会の招待状さえくれば、同窓会費をそのときに払うかもしれないのに。

社会事象は、原因と結果が逆転することはしばしばある。

結局、何が原因で何が結果かは特定できない。

同窓会って「どう？」「そうかい？」っていう話題でした。

<この項は書きかけです。順次追記します。>
This article is not completed. I will add some words in order.

# 参考資料

VZエディタ移植の方法と成果。註釈
https://qiita.com/kaizen_nagoya/items/5551be98dcbed8f41949

アセンブラへの道
https://qiita.com/kaizen_nagoya/items/46f2333c2647b0e692b2

成功体験は語っても、成功体験に頼らないために。清水吉男・田中伸明・柏原一雄・佐々木 眞一。仮説（153）
https://qiita.com/kaizen_nagoya/items/d32adfaf7b2568bfd9d2

参考文献駆動執筆(references driven writing)・デンソークリエイト編
https://qiita.com/kaizen_nagoya/items/b27b3f58b8bf265a5cd1

小川メソッド　覚え（30点を目指して）
https://qiita.com/kaizen_nagoya/items/3593d72eca551742df68


＜この記事は個人の過去の経験に基づく個人の感想です。現在所属する組織、業務とは関係がありません。＞
This article is an individual impression based on the individual's experience. It has nothing to do with the organization or business to which I currently belong.


# 文書履歴(document history)
ver. 0.01 初稿 　20240306
### 最後までおよみいただきありがとうございました。
いいね　💚、フォローをお願いします。
#### Thank you very much for reading to the last sentence.
Please press the like icon 💚　and follow me for your happy life.
AtCoder Beginner Contest 336 振り返り

# ABC336
## 概要
実力的には二年前に茶色になって放置して暫くぶりの参加なので詳しい解説などは期待しないでもらえると。
同じぐらいの初心者さんがこんな感じで解いたのかぁ的な見方か、上級者の方が愉悦として見ていただけると幸いです。

https://atcoder.jp/contests/abc336

## A - Long Loong
__考えてたこと__
特になし

__提出したもの__
```c++:a.cpp
int main() {
    int n;
    cin >> n;
    string ans;
    ans += "L";
    rep(i, 0, n) {
        ans += "o";
    }
    ans += "ng";
    cout << ans << endl;
    return 0;
}
```

__振り返り__
特になし

## B - CTZ
__考えてたこと__
10進数の数字をn進数に直すみたいなの、高校の時やった覚えがあります。
2で割っていってどこまで余りが出ないか数えるだけ。
__提出したもの__
```c++:b.cpp
int main() {
    int n;
    cin >> n;
    int ans = 0;
    while (true) {
        if (n % 2 == 0) {
            ans++;
            n /= 2;
        } else
            break;
    }
    cout << ans << endl;
    return 0;
}
```
__振り返り__
bitを用いるやり方や、`countr_zero`を用いるやり方など解説から勉強。

## C - Even Digits
__考えてたこと__
出力例の値がかなり大きかったから普通に解く問題じゃないだろうなぁと予想。
B問題でやったみたいにn進数の余りをうまく使ったら解けそうと判断。
先に良い整数を小さい順に配列で持っておいてn進数の余りをkeyとして持ってきてそれを1の位から並べていく、それだけ。

__提出したもの__
```c++:c.cpp
int main() {
    ll num;
    cin >> num;
    num--;
    ll ans = 0;
    int goodNum[] = {0, 2, 4, 6, 8};
    ll numTimes = 1;
    while (num > 0) {
        ll a = num % 5;
        ans += goodNum[a] * numTimes;

        num /= 5;
        numTimes *= 10;
    }
    cout << ans << endl;
    return 0;
}
```

__振り返り__
実際に掛け算をして値を求めてたけど、回答を見てそもそも計算する必要もないと気づきました。文字列として小さい桁から順に数字を持って最後に`reverse`するやり方の方が桁の値が大きくても良いし計算もしなくて安全。問題作成者の性格次第でLLでも回答範囲外に出来るから正直危なかったかも、反省。

## D - Pyramid
__考えてたこと__
全然わかりませんでした。
解答読んだらかなり純粋な算数？数学？でびっくりしました。
youtubeの公式解説の`dr[i]=min(dr[i+1]+1,vec)`みたいな解き方が好きで解説を聞いている途中で一回自分で書いてみたらACしました。

__提出したもの__
```c++:d.cpp
int main() {
    int n;
    cin >> n;
    vector<int> vec(n);
    rep(i, 0, n) cin >> vec[i];

    vector<int> max_left(n);
    vector<int> max_right(n);

    for (int i = 0; i < n; i++) {
        if (i == 0) {
            max_left[i] = 1;
        } else {
            max_left[i] = min(max_left[i - 1] + 1, vec[i]);
        }
    }

    for (int i = n - 1; 0 <= i; i--) {
        if (i == n - 1) {
            max_right[i] = 1;
        } else {
            max_right[i] = min(max_right[i + 1] + 1, vec[i]);
        }
    }

    int ans = 0;
    for (int i = 0; i < n; i++) {
        int now_ans = min(max_left[i], max_right[i]);
        ans = max(ans, now_ans);
    }
    cout << ans << endl;
    return 0;
}
```
__振り返り__
パワーで解くやり方なら気づけたかもだから反省、諦めずに。

## 感想
D問題でかなり詰まってたので、解説を見たら楽しくなってモチベがちょっと復活してきました。わくわくです。
APIとは

## :ledger:前置き
よく聞くようになったAPIですが、人にきちんと説明することできますか…？
私は恥ずかしながらぼんやりとしか理解していませんでした。
今回はそんなAPIについて初心者に分かりやすくまとめていきたいと思います。

## :ledger:APIってなに…？

一言で表すと
<b>`他社が提供しているサービス内の機能や情報を扱える仕組み`</b>です。

<b>A</B>pplication <b>P</B>rogramming <b>I</b>nterfaceの略称で
ソフトウェアやプログラム、Webサービスの間をつなぐインターフェースとも言われます。


使用するプロセスは
利用者が`リクエスト`を送信し、提供者が`レスポンス`を返すことで構成されています。

## WEB API
HTTP・HTTPS通信によってやりとりするAPIのことです。
GoogleやYahoo、Amazon、楽天、Facebook…など
ユーザーは各社のAPIを利用する事で、各サービスのデータを検索したりサイトで利用したり出来るようになります。

## REST API
「RESTの原則」に従って実装されるAPIのことです。
4つの原則を表にまとめてみました。

| 原を則 | 意味 |
|:-:|:-:|
|アドレス可能性   | 全てのリソースが一意なURI（識別子）を持っている<br>（提供するリソースは全てURIで表現できる）  |
|  ステートレス性 | 情報を保持せずやり取りは1回ごとに完結する  |
| 接続性  | やり取りされる情報に別のリンクを含めることができる  |
| 統一インターフェース性  | リソースの操作（取得、作成、更新、削除）は<br>HTTPメソッド（GET、POST、PUT、DELETE）を利用し<br>結果はXMLやHTML、JSON、CSV、プレーンテキスト<br>などで返される  |

## :ledger:APIを活用するメリット
<b>・開発の効率化やコストを削減することができる</b>
<b>・セキュリティや顧客満足度の向上
・システム変更時の影響が少ない</B>

## デメリット
<b>・提供事業者側が API の公開停止やサービス終了のリスク
・トラブルによる不具合
</B>


## APIエコノミー
APIを活用して広がる活動圏のこと。

具体的にはGoogle Maps APIなどです。
自社で地図を用意する必要がなく所在地や周辺情報を正確に表示することが可能です。

## さいごに…
APIを活用することで、利用者側では一から開発する手間がかからずに
高品質なものを実装することができます。
そして提供側もビジネス展開の拡大につながっていくメリットがあります。

しかし利用する上では様々なデメリットも加味しながらAPIを選択する必要があります。
トグルリスト（アコーディオン）に transition: height が効かない時の裏技

### 前置き（transition による遷移アニメーション）

アコーディオンにアニメーションをつけたいとき、
cssの`transition`を使えば簡単にアニメーションをつけられます。

```scss:scss
.toggle-block {
	overfllow: hidden;
	height: 0;
	transition: height 0.3s

	&.is-active {
		height: 300px;
	}
}
```
上記の`toggle-block`に`is-active`を着脱すれば、
0.3sかけて height が伸び縮みしてくれます。



### transition設定してもアニメーションにならないケース
```scss:scss
.toggle-block {
	overfllow: hidden;
	height: 0;
	transition: height 0.3s

	&.is-active {
		height: fit-content;
	}
}
```
これの場合はうまくいきません。
`transition`が効くのは「数値同士」の変化のみだからです。

- OK：　`0 ←→ 500px`　／　`0 ←→ 100vh`
- NG：　`fit-content ←→ 0`　／　`auto ←→ 100vh`

高さが不定のボックスには使えないのでしょうか？


### 高さ不定のトグルボックスに transition を効かせる

`height`ではなく`max-height`にすればうまくいきます。
```scss:scss
.toggle-block {
	overfllow: hidden;
	max-height: 0;
	transition: max-height 0.3s

	&.is-active {
		max-height: 100vh;
	}
}
```
これで数値同士の変化になったので、`transition`が効きます。
active時の`height`が不定でもこれで安心です。

※active時の`max-height`はわかってる範囲で最小にします。
　画面をはみ出る可能性がちょっとでもあれば 100vh にするしかないと思います。



### 【おまけ】アニメーションは jQuery でよくないか？
jQueryで書く方が色々できるし便利やと思います。
しかし、jsの使用は可能な限り最低限に抑えたいです。

クラスの付け替え(.is-activeなど）だけとかにしたい。

同じ見た目のサイトなら、より多くの人にコードが読めて、メンテナンスもしやすい方が良いと考えるからです。
WalletConnect V4 で許可していないネットワークで接続した際に表示されるネットワーク切り替えモーダルを非表示にする方法


# 概要
WalletConnect V4 を使ってウォレットに接続した際、許可していないネットワークで接続した場合に、自動で表示されるネットワーク切り替えモーダルを非表示にする方法を記載します。

例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/606623/1a69f2a7-bb60-4419-050e-13b12d989102.png)

# 手順
`createWeb3Modal`に、`allowUnsupportedChain`をtrueに設定することで、ネットワーク切り替えモーダルを非表示にすることができます。

``` ts
import { createWeb3Modal } from '@web3modal/wagmi/react';

createWeb3Modal({
    ...略
    // こちらの設定を有効にする
    allowUnsupportedChain: true,
})
```

# 補足
直近の修正で追加された機能のため、引数が、設定できない場合はバージョンを上げてください。

ネットワークの切り替えしxy

この記事を書いた時点では、ドキュメントに記載されていない内容でしたので、紹介させていただきました。
開発の役に立てば幸いです。

# 参考
https://github.com/WalletConnect/web3modal/issues/1891
https://github.com/WalletConnect/web3modal/pull/1982
Gemini 1.5 Proが待ち遠しい。TypeScriptでLangChainのChainsを試した

こんにちは、こんばんは。

Gemini 1.5 Proのウィッシュリストに登録してから、まだかまだかとAPI解放を心待ちにしています。
Gemini 1.5 Proがリリースされたら、100万トークンの入力に対応できるということで、夢が広がります。

Claude 3が出てきて、GPT-4の性能に陰りが見え始めているいま、Gemini Proで我慢して生成AIを使っています。

Next.jsで個人開発ウェブアプリを作成しており、その一環として、ある商品の説明テキストおよび、自分の感想を入れたら、ほどよくライティングしてくれるLangChainのChainsコードを作りました。

生成データをNext.jsで呼び出し、表示するようにしています。

TypeScriptでLangChainのChainsを実装したいという方の助けになれば幸いです。




```
import { PromptTemplate } from '@langchain/core/prompts'
import { StringOutputParser } from '@langchain/core/output_parsers'
import { ChatGoogleGenerativeAI } from '@langchain/google-genai'
import { HarmBlockThreshold, HarmCategory } from '@google/generative-ai'
require('dotenv').config()


const prompt1 = PromptTemplate.fromTemplate(`
あなたはプロのライターで、ライティングの天才です。次のテキスト元に、商品をおすすめする理由を具体例を用いて説明文以降にライティングしてください。
- 条件: 必ず約700文字の自然な日本語で文章を書いてください
- 条件: 必ずマークダウン形式で出力してください
- 条件: 気合い入れて、深呼吸して、一歩ずつ課題に取り組んでください
- 条件: あなたの回答にバイアスがかかっていないか、固定観念によるものではないかを確認してください
- 条件: ステップバイステップで考えてください
- 条件: 必ずその商品の専門家として答えてください
- 条件: 適度に改行を入れて人間が読みやすい文章にしてください。
- 条件: 自然な日本語の文章で作成してください。
- 条件: 主にテキストを元に、網羅的に文章を作成してください
- 条件: 文章の中にアスタリスク(*)は含めないでください
- 条件: 箇条書きは文章ではないので、100%箇条書きは使わないでください


テキスト: {texts}
説明文: 

1. 商品の概要を説明してください。

2. 消費者がその商品を使いたくなるメリットを説明してください。


`)

const prompt2 = PromptTemplate.fromTemplate(`
input内容を、記事タイトルのようにキャッチーに仕上げてください
- 条件1: 日本語の文字数で50文字まで
- 条件2: タイトルは必ず一つだけ作成してください
- 条件3: 文章にアスタリスク(*)は含めないでください

### タイトル作成 ###
{input}
### タイトル作成終了 ###
`)

const model = new ChatGoogleGenerativeAI({
	apiKey: process.env.GOOGLE_API_KEY,
	modelName: 'gemini-pro',
	maxOutputTokens: 2048,
	temperature: 0.9,
	safetySettings: [
		{
			category: HarmCategory.HARM_CATEGORY_HARASSMENT,
			threshold: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE
		}
	]
})

const temp1Chain = prompt1.pipe(model).pipe(new StringOutputParser())
const temp2Chain = prompt2.pipe(model).pipe(new StringOutputParser())

export async function LLMgeminiRun(product: string, texts: string) {
	try {
		console.log('API Call Start: temp1Chain')
		const temp1Result = await temp1Chain.invoke({ product, texts })
		console.log('API Response: temp1Chain', temp1Result)

		console.log('API Call Start: temp2Chain')
		const temp2Result = await temp2Chain.invoke({ input: temp1Result })
		console.log('API Response: temp2Chain', temp2Result)

		return { temp1Result, temp2Result }
	} catch (error) {
		console.error('API Call Error:', error)
		throw error
	}
}
```


参考
https://js.langchain.com/docs/integrations/chat/google_generativeai
Viewベースのプロジェクトにjetpack Composeを組み合わせる

## 目的
### ・基本的にはXMLでレイアウト作ってアプリを作成していきたい。
### ・一部分だけjetpackComposeでつくりたい
### ・元々あるプロジェクトの一部分だけjetpackComposeに変えたい
というときに、ViewにjetpackComposeのViewを組み込む。

## 環境とか

・Android Studio Hedehog 2023.1.1 Patch 2
・MacOS Ventura
・プロジェクトはEmpty Views Activityで作成
・ViewBindingを使用

## やり方

1.依存関係の追加

・EmptyViewsActivityで作成した場合、Compose関係の依存追加がされていないので追加

build.gladle(app)

```kotlin
buildFeatures{
        compose = true
    }
```

```kotlin
implementation("androidx.compose.material3:material3:1.2.0")
implementation("androidx.activity:activity-compose:1.8.2")
//↓プレビュー画面表示用
implementation("androidx.compose.ui:ui-tooling-preview:1.6.2")
debugImplementation("androidx.compose.ui:ui-tooling:1.6.2")
```

2.レイアウトにComposeViewを入れる
ButtonやTextViewなどと同じように入れればOK!
```xml

 <androidx.compose.ui.platform.ComposeView
        android:layout_marginTop="10dp"
        android:id="@+id/comp_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
```

3.アクティビティで呼び出し
```kotlin
class MainActivity : AppCompatActivity() {
    private lateinit var b: ActivityMainBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        b = ActivityMainBinding.inflate(layoutInflater)
        setContentView(b.root)
        b.compView.apply {
            setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
            setContent {
                //この中はjetpack Conposeのviewと同じ状態
                MaterialTheme {
                    homeList()//Composableなviewを呼びだし
                }
            }
        }
    }
    
}
```

これだけで、xmlでレイアウトしたViewにjetpackComposeを組み込むことができます
あとは、`@Composable`でViewを作って呼び出すことができます

## まとめ
・xmlレイアウトViewベースにjetpackComposeを組み込むのは簡単！
・UIや動作仕様に合わせて組み合わせて作るのもありでは？

## 参考サイト、詳細など

 https://developer.android.com/jetpack/compose/migrate/interoperability-apis/compose-in-views?hl=ja
 ・ComposeメインのプロジェクトにViewを追加することもできます
 https://developer.android.com/jetpack/compose/migrate/interoperability-apis/views-in-compose?hl=ja
PHPでフォルダ内にある画像ファイル一覧を取得

「product」というフォルダの中に複数の画像ファイルが入っていたとする。
その中の.jpgファイルだけ取得してimgタグにて書き出す方法。

```php
<?php
$dir = "product/";
$filelist = glob($dir . '*.jpg');
foreach ($filelist as $file) {
	if (is_file($file)) {
echo <<< eof
  <li><img src="{$file}"></li>
eof;
	}
}
?>
```
grobで特定の拡張子だけ選ぶ方法

```php
//.jpgだけ選ぶ
$filelist = glob($dir . '*.jpg');

//.pngだけ選ぶ
$filelist = glob($dir . '*.png');

//.txtだけ選ぶ
$filelist = glob($dir . '*.txt');

glob — パターンにマッチするパス名を探す
glob(string $pattern, int $flags = 0): array|false

Special characters:

* – ゼロ文字以上の文字にマッチします。
? – 正確に(任意の)一文字にだけマッチします。
[…] – グループ化された文字のうち、一文字にマッチします。
はじめの文字が ! だった場合、 グループにないあらゆる文字にマッチします。
\ – 次に来る文字をエスケープします。 但し、GLOB_NOESCAPE が使われている場合は除きます。
$patternの例
???.png⇒拡張子は.png、ファイル名は任意の３文字
a*.png⇒拡張子が.png、先頭の文字は必ずa、それ以降は0個～無限の任意の文字
```
Rails6.1でRubyを3.2にしたらスコープでキーワード引数が使えなくなった

# 背景
ruby on railsで開発しているのですが、rubyのバージョンを上げようと思ったら躓いてしまいました。日本語だとあまり情報がなかったので記事にしてみました。

railsとrubyのバージョンは下記の通り。
rails: 6.1.7.7
ruby: 3.0.6 -> 3.2.3

そもそもスコープってなに？というかたは、こちらの[リンク](https://pikawaka.com/rails/scope)とかが参考になるかもしれません。
私が開発しているアプリでは、モデルの中でよく使う条件式をわかりやすい名前のスコープとして定義したりしてます。

# 何が起きたのか？
例えば下記のようなスコープがあったとします。
(実際はキーワード引数を使う必要はないと思いますが、あくまで例なので悪しからず)
```
User < ApplicationRecord
    scope :younger_than,
          lambda { |age:|
            where(age: ...age)
          }
end
```
使うときは、こんな感じでクラスメソッドのように使えます。
```
User.younger_than(age: 10)
> SELECT `users`.* FROM `users` WHERE `users`.`age` < 10 # こんなSQLが発行される
> [#<User id: 1, age: 5, ...>,
>  #<User id: 3, age: 9, ...>] # ageが10未満のレコードを含むActiveRecord::Relationが返ってくる
```
railsのスコープは上記のようにキーワード引数が使えるのですが、rubyのバージョンを3.2にあげたところ下記のようなエラーが出るようになりました。
```
User.younger_than(age: 10)
> wrong number of arguments (given 1, expected 0; required keywords:age) (ArgumentError)
```
どうやらキーワード引数ではなく、ハッシュが位置引数として渡ってしまっているようです。

# 原因と対策
色々調べていると、railsのgithubで同様の問題を[issue](https://github.com/rails/rails/pull/46895)であげている人がいました。
issueの中を読んでみると、ruby 3.2からキーワード引数と扱い方が変わったらしく、それが影響してスコープでキーワード引数が使えなくなるとのこと。

しかも、残念ながらrails 6.1はセキュリティ対応のみ更新していく状態なので、今回のようなバグ対応はしないと、メンテナーから回答されていました。
一応対応した`rails:6-1-stable`というブランチがあり、railsがリリースされるたびにこちらのブランチも更新されているようですが、リリースされているわけではないです。

というわけで対策は下記のどれかとなります。
1. スコープのキーワード引数を位置引数の変える
1. スコープをクラスメソッドにする
1. ruby 3.1のままにする
1. rails7にあげる


rails7に早くあげたいところではありますが、大仕事なのは目に見えているので、一旦スコープのキーワード引数を位置引数に変えて、計画的にrails7へあげていくことにしました。
テストデータを一括大量生成するアプリ

※ただの開発日誌です

# 概要
テストデータを大量に作成したい機会があったのだが、いちからINSERT文を作成するのも面倒だなと思ったのがきっかけ。
その時はアカウント名をユニークにしたく、そうなるとコピペしても最終的にアカウント名の変更は手作業。
ネットになんかないかなーと探してみたけど、INSERT文を作成するようなアプリなかったので、ちょうどNext.jsを使ってみたいなーとも思っていたので、勉強がてらに造ってみることにしました。

# 技術
言語：JavaScript
フレームワーク：Next.js, TypeScript
CSSフレームワーク：Tailwindcss, MUI
サーバー：Vercel

# 成果物
https://test-data-generater.vercel.app/

# つまづいたこと
### 1.環境変数の設定がよくわからなかった。
`.env.local`に変数記載しても全然読み込まれなくて数時間ハマった。
`NEXT_PUBLIC_`を変数名の頭につける必要があるとのことだった。

以下参考としたページ

https://commte.net/nextjs-environment

### 2.スタイルがあたらない
最初MUIでスタイル当ててたが、細かいところが実装できなかったので、tailwindcssも入れて実装したら、競合しちゃったのか、tailwindcssのスタイルが当たらない事象が発生した。
やっぱりどっちかに絞るのがよかったかーと反省。

### 3.行の並び替え機能の実装が難易度高かった。
行の並び替えがドラック＆ドロップでできるようにしたくて、いろいろしらべながら実装したのだが、全然うまくできなくて数週間はまってたと思う。
結局`dnd-kit`ライブラリを導入で実装することができた。

以下参考としたページ

https://zenn.dev/kodaishoituki/articles/0e1c6109ae838e

https://zenn.dev/aldagram_tech/articles/c2cf248bd016fc

https://codesandbox.io/p/sandbox/react-table-drag-and-drop-sort-rows-with-dnd-kit-btpy9

https://docs.dndkit.com/introduction/installation

# おわりに
もっとこうしたほうがよいよなーって思うところいっぱいあるけど、いったんこれで終わりにしようと思います。
気が向いたらいろいろ修正していこうかなぁ
[no.007]EC2ボリューム拡張　（T2.micro Amazon Linux2 8G→12Gの例）

※追加ボリュームのマウント手順ではありませんので、ご注意を。

# 参考サイト
　https://qiita.com/murakami77/items/32b2f214e0a85ffdfe49


# 1. 念の為 EC2のスナップショットを作成する場合は以下の手順
- EC2画面を開く
- イメージとテンプレートをクリック　
- イメージを作成
- イメージ名を入力
- 　「再起動しない」にチェックを入れる（終了時に削除、は有効化にチェックを入れる）　
    - 　※Terminate時に一緒にEBSボリュームを削除してくれる
    - 　※停止して取得したほうが良いけど、停止しなくても大体、起動できるスナップショットが出来上がる

# 2. ディスク拡張

- EC2画面を開く　
- 対象ホストをクリック　
- ストレージタブをクリック　
- ボリュームIDをクリック
- 　アクション　
    - 　※変更ボタンではない！
- 　８→１２に変更する
- 　もう一度ボリュームをクリック
- 　ボリュームの状態をチェックする　
    - 　使用中　modifying 
    - 　 xx1中　
    - 　 使用中、になればOK）
- 　　※8GB足しただけでも、数十分かかる（AWSの状況次第なので、かかる時間はケースバイケース）


# 3. xvda-xvda1の場合

- sudo su
- df -h
    - 拡張前のサイズしかみれない

- lsblk
    - TYPEがdiskのほうは拡張されたサイズが見える
    - TYPEがpartのほうは拡張されていない

- growpart /dev/xvda
- df -h
    - 拡張前のサイズしかみれない

- lsblk
    - TYPEがdiskのほうは拡張されたサイズが見える
    - TYPEがpartのほうは拡張されていない

- xfs_growfs /dev/xvda1



# nvme0n1 - nvme0n1p1の場合　（CentOS7の場合など）

- growpart /dev/xvda 1
    - CHANGED: partition=1 start=4096 old: size=16773087 end=16777183 new: size=25161695 end=25165791

- df -h 
    - →何も変わらない

- lsblk
    - →diskもpartも拡張後のサイズになる

- #最近はこっちじゃダメらしい
- resize2fs /dev/xvda1
    - →resize2fs: Bad magic number in super-block while trying to open /dev/xvda1
　Couldn't find valid filesystem superblock.

- xfs_growfs /dev/xvda1
 ↓
```
meta-data=/dev/xvda1             isize=512    agcount=4, agsize=524159 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=0, rmapbt=0
         =                       reflink=0    bigtime=0 inobtcount=0
data     =                       bsize=4096   blocks=2096635, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
data blocks changed from 2096635 to 3145211
```

- df -h 
    - →拡張後のサイズになっている
- lsblk
    - →diskもpartも拡張後のサイズになっている



# 参考：nvme（Non-Volatile Memory Express）とは
　https://www.pro.logitec.co.jp/about_hdd/hddssd/20191129/

NVMe（エヌブイエムイー　Non-Volatile Memory Express）とは
SSDをはじめ、不揮発性メモリを使用したフラッシュストレージのために最適化された通信プロトコル（異なるデバイスが通信する際の手順やルールのこと）を指します
従来使われていたSATA（AHCI）規格に色々改良を加え、高速に通信できるようになっています。

より簡潔にいうと、データの読み書き速度が従来のAHCIよりも非常に速いのがNVMeです。
サーバー以外でも、より高速なデータ処理が求められる人工知能（AI）や、機械学習用のストレージ、市販のSSDなどにおいても、NVMeが活用される機会が多くなっています

M.2（エムドットツー）やU.2など、種類があります。
M.2でもSATA用M.2SSDもある。NVme用M.2SSDのほうが高速。
PCIe接続でNVMeのM.2 SSDがもっとも高速。ただし発熱に注意。
Anthropic社のLLM Claude3を試してみた

# Anthropic社のLLM Claude3を試してみた

最新の言語モデル技術を駆使したAnthropic社のLLM Claude3.0を手に入れ、その機能や性能を試してみました。驚くべき機能に触れると共に、実際の使用体験をお届けします。

## ユーザー登録の手順

まず最初に行ったのは、Anthropic社のLLM Claude3.0にユーザー登録です。
https://claude.ai/login
新規登録は英語画面でしたが、問題なく作成することができました。Googleアカウントを利用したため、簡単な手続きでアカウントを作成することができました。

## 新機能の紹介

ログインすると、新機能の紹介が表示されました。今回のバージョンでは、テキストだけでなく画像を認識し、様々な処理を行うことが可能になっています。具体的には、画像から料理のレシピを提案したり、画像中のテキストを認識してJSONファイルに変換したりすることができます。

## 画像認識の実験

興味深い機能を試すべく、ネット上から適当な画像を取得し、LLM Claude3.0に投入してみました。その結果、思ったより高性能でびっくりしました。ChatGPTの画像認識性能についてはまだ試していないので比較はできないのですが。

- 企業のLLMに関するプレゼン資料の図を投入したところ、LLMは図の内容をしっかりと理解し、テキストに変換して提供してくれました。これにより、プレゼン資料の内容をテキストデータとして簡単に取り出すことができるようです。会社だと社内のドキュメントをLLMに入れるのが簡単になりそうですね。PowerPointとか一括でいられて認識できるようになるといいのですが、いずれはそうなっていくと思います。
- 請求書の画像を投入してみたところ、一部の文字の誤認識はあったものの、請求書の全体的な内容理解に問題はありませんでした。請求書っていろいろなフォーマットがあるので事務の方が手入力しているケースが多いと思うのですが、解像度が高ければAIに置き換えできるようになる日も遠くないと思います。ただ誤認識はあるので人によるチェックは必要ですが、今後事務系の人数は大きく削減されると思います。

## 今後の展望
無料で提供される枠を使い切ってしまったため、今回の試行はここまでとなりました。普段は主にClaude2.1をメインで使用しているのですが、画像が読めるというのは大きいです。

Anthropic社のLLM Claude3.0は、その優れた画像認識技術や高度なテキスト処理能力により、様々な業務やプロジェクトに革新をもたらす可能性を秘めていると思います。
プロンプトでできる工夫とか精度とかも見ていけたらと思います。
AWSの記事を色々書いていきたい！！！ ～AWS100本ノック～ 1/100

## はじめに

久々の投稿になります。
私は今所属している会社で、中堅エンジニアand新米リーダー(and新米パパ)で日々働いています。

周りで記事を頻繁に投稿する同僚が多くいるので、私も何か定期的に記事を書かなきゃな～と思い、最近触れることが多いAWSについて100本ノックにチャレンジしてみたいと思います！！！

## 書くにあたって

正直、毎日の業務をこなしながら書くとなるとそれなりの意思が必要だと思っています。
何回か記事を定期的に書こうとは思っては挫折しています...

なので、
・週にxx本投稿する
・いいね数を稼げるような内容の濃い記事にする
・100本のタイトルを最初に決める
などはしないで、書けるときに書いていきたいと思います。

また、内容に関しても基本的には1サービスで1記事など書いていく予定ですが、機能を全てを説明するのは厳しい(機能が追加されるたびに、更新するのは難しい...😢)し。長いと読む側も大変なので、以下のような方針で書いていきます。


## 方針

・しばらく触ってなかったAWSサービスを久々に触るってなった時に、この記事を見ればだいたい思い出せる
👉私は、時が経つと色々忘れる...

・自社でライトな勉強会などでアウトプットする際の資料としてそのまま使える
👉勉強会の資料を別途作るのがめんどくさいので...

・AWS試験に（少しでも)役立つ
👉資格の本って、なかなか私は頭に入っていかないので...

・自社の業務に役立つ
👉結局、これが一番

## 理想

最初は、赤ちゃん（何もわからない）から始まって、徐々に小・中学生？（知識を付けて成長）になっていき、100本読み終わった時に大人(主要な部分は大体理解できる)になれる、そんな感じです！
※結果として、いろんな人から評価されれば尚うれしい:yum:

![432876ec92fc1d4a59729600ce7b7c67_t.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87924/1c17c541-1272-6403-c2b7-6e3b1cdb4809.jpeg)


## おわりに

ということで、こんな感じで1本目は特にAWSサービスの紹介はしないで終わります:bow_tone1:

次からはまず、AWSアカウントやリージョンなど最初に知っておくべき内容について、アウトプットしていきます。
Unityの C# のSortでハマった話

ある日、デバッガから「岩崎さん、ハングアップします」とレポートが上がってきた。
レポートに貼ってあるログを見ると…

```
NullReferenceException: Object reference not set to an instance of an object
HogehogeManager+<>c.<Gethogehoge>b__45_2 (HogeEntity a, HogeEntity b) (at Assets/Scripts/Battle/HogehogeManager.cs:448)
System.Collections.Generic.ArraySortHelper`1[T].PickPivotAndPartition (T[] keys, System.Int32 lo, System.Int32 hi, System.Comparison`1[T] comparer) (at <b89873cb176e44a995a4781c7487d410>:0)
System.Collections.Generic.ArraySortHelper`1[T].IntroSort (T[] keys, System.Int32 lo, System.Int32 hi, System.Int32 depthLimit, System.Comparison`1[T] comparer) (at 
```

**「は？」**  なんでSortがnull吐いてんのよ？
となって、調べると、落ちているのはなんと、こんなSort。

```C#
List<T>.Sort((a, b) => ((a.x - b.x)>0)?1:-1 );
```

どうして落ちているのかさっぱりわからず、でも試すと、確かに特定条件下でnullを吐く。
しょうがないので、とりあえずノームソートを書いて、それだと落ちないのを確認したのち、ふっと気がついた。
**「まさかとは思うけれど、ラムダ式の書き方で落ちる？」**
で、ラムダ式を以下に書き換えてみた。

```C#
List<T>.Sort((a, b) => ((a.x.CompareTo(b.x) );
```

なんてこったい、落ちなくなったぞ!?
なんでや!?　と、調べていくと、stackoverflowのこのスレッドに当たった。

https://stackoverflow.com/questions/1026044/list-sort-in-c-comparer-being-called-with-null-object

で、読むと、端的に書けば比較関数に一貫性がないとNull で落ちるという話が書かれている。
でも、 `a.x > b.x ? 1:-1` のどこに一貫性がないなんてことがあんだよ…と、考えていて気がついた。
 `a.x == b.x` のとき、 `a.x>b.x` と `b.x>a.x` の **どっちも-1を返す** 、すなわち一貫性がない、だからnull落ちしてたんだ！
と、気がついて、理由が腹落ちしたところに、この話をslackのスレッドで展開してたところ、スーパー出来る同僚が曰く。

:::note
てか、`List<T>.Sort((a, b) => (a.x - b.x)` だけでOKでは…
正負または0を返せばいいだけで、-1/1に限定する必要はない
:::

ｶﾞ━━(;ﾟДﾟ)━(　ﾟД)━(　　ﾟ)━(　　 )━(ﾟ;　 )━(Дﾟ; )━(ﾟДﾟ;)━━ﾝ!!!!!
俺って、バカ。
というわけで、教訓。

:::note
- UnityのC#のSortは比較関数が一貫性のない値を返すとnull落ちする。そしてこれはとてもわかりにくい
- だいたいSortを1/0/-1に限定する必要はない
:::

- コメントでこれはmonoの古い目のやつのバグだと思うという話があったのでUnityの、に限定しておきました
- なお、出ているソースはもちろん「そのまま」ではないのはご了承くださいｗ
Rent com Data Scraping in New York | Real Estate Scraping

Optimizing-Real-Estate-Strategies-with-Rent.com-Data-Scraping-in-New-York
About the Client
Actowiz Solutions, a leading data solutions provider, partnered with a client seeking comprehensive insights into the New York real estate market. The objective was to scrape Rent.com data in New York, a prominent real estate platform, to inform strategic decision-making.

Client Challenge
Client-Challenge
The client faced challenges in efficiently gathering and analyzing real estate data specific to New York from Rent.com. Manual data collection was time-consuming and prone to errors, hindering their ability to make informed decisions in the competitive real estate landscape.

Solution
Solution
Actowiz Solutions implemented a tailored Rent.com data scraping solution to streamline the extraction process. Leveraging advanced techniques, the real estate scraper efficiently collected data on New York apartments, including pricing trends, amenities, and location specifics.

Results
Efficiency: The Rent.com data scraping solution significantly reduced the time spent on data collection, enabling quick access to a vast array of relevant information.

Accuracy: Actowiz Solutions ensured precise extraction, minimizing errors associated with manual data gathering. This accuracy enhanced the reliability of the obtained real estate data.

Informed Decision-Making: The extracted data empowered the client to make informed decisions on property investments, pricing strategies, and market trends in the dynamic New York real estate landscape.

Benefits of Real Estate Data Scraping Services
Benefits-of-Real-Estate-Data-Scraping-Services
Time-Saving: Automation through Rent.com data scraping saved significant time compared to traditional manual methods.

Precision: Actowiz Solutions' real estate scraper ensured accurate and up-to-date information for informed decision-making.

Competitive Edge: Access to real-time data provided the client with a competitive advantage, allowing them to adapt swiftly to market changes.

Conclusion
Actowiz Solutions demonstrated its expertise in real estate data scraping services, providing a tailored solution to extract Rent.com data in new York for the New York market. The client gained a competitive edge, optimizing their real estate strategies and making well-informed decisions based on accurate and timely data. This successful collaboration showcases Actowiz Solutions as a reliable partner for real estate data collection and scraping services.

sources >>  https://www.actowizsolutions.com/case-study-real-estate-strategies-rent-com-data-scraping-new-york.php
【神ツール】ネットワーク勉強の最適解！GNS3について

# １．はじめに
私は数年前からネットワークの維持管理業務を行っていますが、それ以前は通信職ではあったが、ネットワークについてはそこまで深く考える業務ではなかった。現職に就いていざ大規模なネットワークを目の前にすると、複雑な構成、聞いたことのない用語（設定）、触ったことのない装置ばかりで、警報装置のアラームが鳴らないことを祈りながら日々勤務していました。（笑）



## 2.勉強の開始
恐怖のアラームへみずから立ち向かう？べく、休日等を利用しネットワークの勉強を開始することにしました。まずは本を読んでみようと思い、名著でもある[「マスタリングTCP／IP（第６版）」](https://www.amazon.co.jp/%E3%83%9E%E3%82%B9%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0TCP-IP%E2%80%95%E5%85%A5%E9%96%80%E7%B7%A8%E2%80%95-%E7%AC%AC6%E7%89%88-%E4%BA%95%E4%B8%8A-%E7%9B%B4%E4%B9%9F/dp/4274224473/ref=sr_1_1?adgrpid=123599780051&dib=eyJ2IjoiMSJ9.76r2OTRtT8oF7WOLVK0NyBqpaxD4owuriTga1qP8bI66TgwwXBV4T6clhIaAP-RmAHwCizyJy7wNwDD7rh_gTtEi2J8SfVmA86ogWyBB_iw1dUpubaQAZPMiAgeI4ivJqeohebZrQhgTs4lfSW2MvpntG6uAelEhR2EDLEz6-M6ouYBtznZk57SZqoutbOgtx7QyILR_oseZPS9sO_1z2592T-6xoH5S04rFSJ2fhH_KKsOoN9HCSB6cUAfPk4HVnAoQpmrRTmmnn0CLmxtRLm0cDrDHWwc-_2Nie-rV6ak.jCcChxbr-rQYnL6osK5ATzMzbun5uy99MzYzw7e_0Y4&dib_tag=se&gclid=CjwKCAiAopuvBhBCEiwAm8jaMSsQmkraRXBQDsCoDeg08MQSNOYKa9-DsBiJToAiDKaaV9HrTC0IihoCKD8QAvD_BwE&hvadid=678984677643&hvdev=c&hvlocphy=1009308&hvnetw=g&hvqmt=e&hvrand=3507712229708110119&hvtargid=kwd-417611595988&hydadcr=27271_14738618&jp-ad-ap=0&keywords=%E3%83%9E%E3%82%B9%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0+tcp+ip+%E5%85%A5%E9%96%80+%E7%B7%A8&qid=1709693395&sr=8-1)を購入し、読み始めましたが・・・

![61tPeRViVIL._SY522_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3734215/5fe88ce0-fcbc-09dd-2c4d-ba29a34d6ebd.jpeg)



### <font color="red">**よく分からん！！！**</font>
（※当時の知識不足での感想ですのでご心配なく。ネットワークに関して幅広くカバーされたとても良い本です）

「入門編」とありますが、ネットワーク初心者の私からすればなかなか理解に時間がかかりますし、身についた気になりませんでした。やはりネットワークの勉強は

### <font color="red">**作ってみる！！！**</font>

これに限るんではないでしょうか。


## ３.GNS３の導入
私の愛用M1Mac（AirのRAM：16g、SSD：512g）にインストールし、いざ勉強！
（M１発売当初は、アプリ動く・動かない問題ありましたが、GNS3については全く問題ありませんでした。）

![スクリーンショット 2024-03-06 19.29.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3734215/561f6951-e7bc-ab29-cf25-7fec82b2a19b.png)

おぉ！なんかそれっぽい画面でてきた！これでシミュレーションできるのかーと思っていましたが、GNS3のよさはアプリ上で仮想シスコのスイッチ、ルータ（IOS）を動かせるとこなんです！素晴らしい！！自宅で実機を置くって抵抗ありますし、予算もありますから、これは助かる。


IOS導入には以下を参考にしました。

[GNS3のインストールとセットアップ方法（CCNA / CCENT ネットワーク演習）](https://youtu.be/ltXaFa8FkEI?si=07coFTKbpsznvFk0)

こちらの動画通りに実施すれば問題ありませんでした。
（情報工学入門チャンネル様、大変参考になりました！！！ありがとうございました。）

![スクリーンショット 2024-03-06 19.46.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3734215/1450a0bd-d7ff-012a-eae5-80be1f891caf.png)

　無事に仮想シスコルータを動かすことができました。
 （この時はとても感動したのを覚えています✨）


 今では色々と気になったことをシミュレーションできるようになりました。
 ![スクリーンショット 2024-03-06 19.55.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3734215/394eeb5b-17f5-c43e-92d2-e097ff569290.png)

今後はやってきたことを色々発信して行きたいと思っています。

Youtube開設しました！！シミュレーション動画をアップしていきます！！

https://www.youtube.com/@Urapy_Netowrok

\:kissing_closed_eyes: chu☆シミュレーションした内容を記事にしていますので、こちらもご参考に！

https://qiita.com/ura_taka/items/58f96e0e9cf220ec5d03

https://qiita.com/ura_taka/items/0ab8057918d45082987b

https://qiita.com/ura_taka/items/764b25facff9fcf74bc3

## ４.さいごに
GNS3を使い始めてからは、ネットワークの知識向上や実務での機器操作に活かせています。また、

### <font color="red">**ネットワークって楽しい！！！**</font>

という気持ちが持てるようになりました。まだまだ勉強することはたくさんですが、引き続き楽しみながら勉強していきたいと思います。
Rails で jQuery.ajax してたら勝手に X-CSRF-token がつくんだけど

[jQuery](https://jquery.com/) 使ってますか？多くの方はもう使ってないと思いますが、歴史あるWebアプリを触ってる方は使ってると思います。で、Rails([jquery-rails](https://github.com/rails/jquery-rails/))との組み合わせで気付いていなかった挙動があったのでメモしておきます。

```js
jQuery.ajax({
  url: '/api/v1/some_resources',
  type: 'POST',
  data: {
    attr1: 'val1'
  }
})
```

こんなJSを書いて発行されたリクエストを見てみると、ヘッダに `X-CSRF-token` がくっついていました。 Rails の CSRF 防御機能で使うトークンです。つけた覚えがないのになんでついてるんだ！？ axios とか素の [`fetch`](https://developer.mozilla.org/ja/docs/Web/API/Fetch_API) でリクエストするとつかないぞ！？とおもってコードを読んでいたら、 [jquery-rails][jquery-rails] がやってくれてたんでした。

```js
    // Make sure that every Ajax request sends the CSRF token
    CSRFProtection: function(xhr) {
      var token = rails.csrfToken();
      if (token) xhr.setRequestHeader('X-CSRF-Token', token);
    },
```

[vendor/assets/javascripts/jquery_ujs.js#L72-L76 より](https://github.com/rails/jquery-rails/blob/12869dac3fcee107a9dabfbbe4f5054298d8877b/vendor/assets/javascripts/jquery_ujs.js#L72-L76)

あなたがやってくれていたんですね！

[jquery-rails]:https://github.com/rails/jquery-rails/
Rails.logger.log は Rails.logger.add と違って7.0以下だとbroadcastされない

[標準の `Logger#add` は `Logger#log` の alias](https://docs.ruby-lang.org/ja/latest/class/Logger.html#I_ADD)だけど、 Rails 7.1系未満の `ActiveSupport::Logger` だと`add`と`log`は挙動が違っていて、 `ActiveSupport::Logger#add` は broadcast されるが、 `ActiveSupport::Logger#log` だと broadcast されない。

```ruby
# 設定次第だけど
# 標準出力とログファイルに出る
Rails.logger.add(1, 'hello') 
# ログファイルだけに出る
Rails.logger.log(1, 'hello') 
```


[v6.1.7.7 activesupport/lib/active_support/logger.rb](https://github.com/rails/rails/blob/v6.1.7.7/activesupport/lib/active_support/logger.rb#L25-L28)をみてみると、6系はこんな感じで `add` だけがオーバーライドされてる。 `log` は標準 `Logger` と同じ動きをするはず。

```ruby
        define_method(:add) do |*args, &block|
          logger.add(*args, &block)
          super(*args, &block)
        end
```


[v7.1.3.2 activesupport/lib/active_support/broadcast_logger.rb](https://github.com/rails/rails/blob/v7.1.3.2/activesupport/lib/active_support/broadcast_logger.rb#L116-L119)をみてみるとは`add`と`log`がaliasになってる


```ruby
    def add(*args, &block)
      dispatch { |logger| logger.add(*args, &block) }
    end
    alias_method :log, :add
```
---
https://github.com/rails/rails/pull/48615
このPRで入ったみたい。このPRは7.1系のものなので、7.0系もたぶん6系と同じ挙動するはず。
timescaledbバージョン指定

    wget https://repo.zabbix.com/zabbix/6.0/ubuntu/pool/main/z/zabbix-release/zabbix-release_6.0-4+ubuntu22.04_all.deb
    dpkg -i zabbix-release_6.0-4+ubuntu22.04_all.deb
    apt update
    apt install -y zabbix-server-pgsql zabbix-frontend-php php8.1-pgsql zabbix-nginx-conf zabbix-sql-scripts zabbix-agent2

    apt install -y gnupg postgresql-common apt-transport-https lsb-release wget
    /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh
    echo "deb https://packagecloud.io/timescale/timescaledb/ubuntu/ $(lsb_release -c -s) main" | sudo tee /etc/apt/sources.list.d/timescaledb.list
    wget --quiet -O - https://packagecloud.io/timescale/timescaledb/gpgkey | sudo apt-key add -
    wget --quiet -O - https://packagecloud.io/timescale/timescaledb/gpgkey | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/timescaledb.gpg
    apt update

    apt-get install -y timescaledb-2-postgresql-14='2.13*' timescaledb-2-loader-postgresql-14='2.13*'



    apt-get update
    
    apt-get install -y postgresql-client

    vi /etc/postgresql/14/main/postgresql.conf
    →shared_preload_librariesを編集
    shared_preload_libraries = 'timescaledb'

    systemctl restart postgresql

    sudo -u postgres psql

    \password postgres

    \q

    psql -U postgres -h localhost

    CREATE database tsdb;

    \c tsdb

    CREATE EXTENSION IF NOT EXISTS timescaledb;

    tsdb-# \dx
    \q

    sudo -u postgres createuser --pwprompt zabbix
    sudo -u postgres createdb -O zabbix zabbix

    echo "CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE;" | sudo -u postgres psql zabbix

    zcat /usr/share/zabbix-sql-scripts/postgresql/server.sql.gz | sudo -u zabbix psql zabbix
    cat /usr/share/zabbix-sql-scripts/postgresql/timescaledb.sql | sudo -u zabbix psql zabbix

    vi /etc/zabbix/zabbix_server.conf
    DBPassword=
    vi /etc/zabbix/nginx.conf
    コメントアウト
    listen    8080;
    server_name Zabbix ServerName
    sudo apt install language-pack-ja-base language-pack-ja
    locale -a

    systemctl restart zabbix-server zabbix-agent nginx php8.1-fpm
    systemctl enable zabbix-server zabbix-agent nginx php8.1-fpm
    systemctl status zabbix-server zabbix-agent nginx php8.1-fpm

    systemctl kill apache2
    systemctl disable apache2
    systemctl status apache2
Azure Portal で CosmosDB の複数 Items を削除するには Stored Procedure を使う

# 背景

cosmos DB を利用していて、テストで使ってできたデータを一括削除しようとした。

https://learn.microsoft.com/ja-jp/azure/cosmos-db/nosql/quickstart-portal#query-your-data

てっきり、SQL で DELETE 使えば簡単だと思ってたら、DELETE は使えない・・

勿論、SDK を利用すれば削除は出来るが、Azure Portal からサクッとやりたい場合もある。
ということで、MS-Learn にて言及されている以下の方法で対処したお話

https://learn.microsoft.com/en-us/archive/msdn-technet-forums/ec9aa862-0516-47af-badd-dad8a4789dd8

日本語版 URLもあるけど・・一切翻訳されていない :laughing: 

::: note info

現在は、Portal上で、表示している分の全削除だけなら簡単にできるようになってます。

- 全選択✅
- [Delete] 

但し、大量の削除の場合には、Stored Procedure を使った方がよいと思います

:::
https://qiita.com/baku2san/items/021095d37359371bc3b1

# 結論

1. Stored Procedure を 実行したいコンテナに追加する<br>![Untitled (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/7834c908-e7a4-1913-3d84-7b53160f39d6.png)
1. あとは下の画像のようにする<br>![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/48376110-78db-21fb-e677-56d99fcd4fcf.png)
    1. 追加した Procedure を選択
    1. [Execute] で実行する
    1. <input parameters> で、Partition key の値を入力
    1. 消したい項目を選択する Query を入力
        - ex.) SELECT * FROM c WHERE c.id == 'guid'
    1. [Execute] で実行
    1. 結果確認

:::note info

- タブ選択時、[Execute] が出ないことがあります。そんなときは、タブ切り替えや、編集して [Update] すると出てきます。
:::

# Stored Procedure は GitHub に

https://github.com/Azure/azure-cosmosdb-js-server/blob/master/samples/stored-procedures/bulkDelete.js

# time to live 

チャットボットの履歴なら、一定時間過ぎたら勝手に消すのも手、かな

https://learn.microsoft.com/ja-jp/azure/cosmos-db/nosql/how-to-time-to-live?tabs=dotnet-sdk-v3


# あとがき

NoSQL を SQL で操作出来るってなんか不思議ですね。
【Next.js】.envで定義した環境変数がundefinedになった場合に確認すること

## 背景
Next.jsで開発をしていて、`.env.development`に定義した環境変数がundefinedになった。
その備忘録。

## やること

`.env.development`に定義した環境変数を呼び出す。

## クライアントサイド（ブラウザ）で確認する場合は環境変数にNEXT_PUBLIC_をつける
クライアントサイド、つまりブラウザで動作するJavaScriptコード内で環境変数を使用する場合、環境変数名の先頭にNEXT_PUBLIC_を付ける必要がある。
これは、ブラウザ側のJavaScriptが実行時に環境変数にアクセスする際、Next.jsがセキュリティ上の理由からどの変数が公開されていいかを識別するためである。

例:

```js:.env.development
NEXT_PUBLIC_API=YOUR_API
```

この例では、NEXT_PUBLIC_APIという環境変数はブラウザ側のスクリプトで利用可能となる。

ちなみにその環境変数の呼び出しは、

```typescript:
`/hoge?api_key=${process.env.NEXT_PUBLIC_API}`
```
でできる。

## 起動コマンド

開発環境では、yarn dev コマンドを使用してアプリケーションを起動。このコマンドが実行されると、Next.jsは自動的に .env.development ファイルを読み込む。このファイルには開発環境特有の環境変数が含まれているべき。

一方、本番環境でのアプリケーションのビルドや起動には、yarn build と yarn start コマンドが使われる。これらのコマンドが実行される際には、.env.production ファイルが読み込まれる。このファイルには本番環境で使用される環境変数を設定。

N.env.local ファイルについても触れておく。このファイルは、開発環境でも本番環境でも常に読み込まれる。もし同じ環境変数名が .env.development や .env.production にも存在する場合、.env.local の値が優先される。これにより、個々の開発者がローカル環境で特定の設定を上書きすることができる。

## envファイルの位置

各envファイルはルートに配置する必要がある。

## ビルド時の環境変数
Next.jsでは、ビルドプロセス（yarn build などのコマンド実行時）中に環境変数をアプリケーションに割り当てる。この時点で利用可能な環境変数は、ビルドされたアプリケーション内に組み込まれ、その後の実行中に使用される。しかし、ビルド時に利用可能でない環境変数は、undefined として扱われる可能性がある。

これは特に、ビルドプロセスがクラウド環境で実行される場合に注意が必要。クラウド環境の設定変更がビルド時に間に合わない場合、予期しない挙動が発生することがある。

## ランタイム時の環境変数
ビルド時に利用できない環境変数に依存する場合、ランタイム設定を利用することが望ましい。
ランタイム設定とは、アプリケーションが実行される際（ランタイム）に、その時点での環境変数の値を読み込むことを指す。これにより、アプリケーションは実行時に最新の環境設定を反映することができ、動的な設定変更に柔軟に対応することが可能になる。

ランタイム設定については[こちら](https://nextjs.org/docs/pages/api-reference/next-config-js/runtime-configuration)へ。

## お疲れ様でした。
わからないところ、間違っているところ、もっといい方法がある場合は、コメントでもDMでも教えてください。
AWS ClouldFormationの静的解析ツールcfn-lintコマンドをインストール

## はじめに

CloudFomationのcfn-lintコマンドを使いたくてインストールを試みました。
色々、試みた結果。
PHP利用者は大抵`brew`コマンドがインストールされていると思うので（偏見）、それ使ったら一発だよ！って教えてあげたかっただけです。

## インストールコマンド

```:ターミナル
brew install cfn-lint
```


```:ターミナル
which cfn-lint

// この情報はVScodeと連携するときに使用します
/opt/homebrew/bin/cfn-lint
```

## VScodeの拡張機能にをインストールし、設定する

まず、拡張機能からインストールしていきましょう。


![スクリーンショット 2024-03-06 21.26.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667254/45b79a32-6511-8717-1866-c6bb7a52adb7.png)

次に拡張機能を使用するために設定をしていきます。
右下の歯車マークで設定画面にいきましょう。

下記の図のように、検索ワードで`cfnLint.path`を入れます。
これは先ほど`which`コマンドを使用して判明したパスです。

![スクリーンショット 2024-03-06 21.28.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667254/0e0e9f00-6df5-0dca-aaf5-854906bbabfc.png)

ここまで、設定できたら一旦VScodeは閉じてもう一度開きましょう。

ymlファイルでテンプレートがあればぜひコマンドと叩いてみてください〜！


## こんなアラートが出てきても大丈夫〜！

VScodeでpathを設定していない場合、下記のようなアラートが上がります。

![スクリーンショット 2024-03-06 21.35.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667254/a1689e87-7118-3b8a-66a1-7443378bad41.png)

ですが、大丈夫です！パスさえしっかり記載していれば！
パスを設定したのに、エラーが出てる人は`再起動をしていない`もしくは、`パスが間違っている`といった可能性があるのでもう一度確認してみましょう。


## 参考URL

[cfn-lintでCloudFormationの静的解析を行う](https://memo.kkenya.com/cfn_lint/)
Praat scriptでシェルプログラミングができるようになった

# はじめに

~~お久しぶりです。音声分析しない系Praat記事の新作です。~~

Praat `6.3.17` で組み込み関数 `runSystem$` が追加され、コマンドライン実行の出力内容を戻り値で受け取れるようになりました。
これによって、シェルを扱う処理もPraat内で完結できるようになります。

# バージョン

- Praat 6.4.06

# コマンド実行関数 runSystem$

`runSystem$(コマンド文字列)` の形式でコマンドを実行すると、標準出力が返ってきます。

```praat
s$ = runSystem$("echo foo")
appendInfoLine(s$)
```

```
foo
```

終了ステータスが0でない場合はエラーが発生し異常終了します。(~~Windowsだとエラーメッセージが文字化けして読めない...~~)

文字列にはパイプ (`|`) も使えるため、複雑なコマンドを指定することも可能です。

# 実例：Qiitaのプロフィール画像を表示
もう少し実践的な例を見てみましょう。Qiita APIを使って自分のアイコンを取得しPraat上に表示します。

Praat自身にHTTPリクエストやJSON処理の機能はありませんが、`curl` や `jq` が使えればこちらのものです。

```praat:avator.praat
clearinfo

# Qiita APIでユーザー情報をリクエスト、JSONレスポンスを取得
user$ = "Syuparn"
response$ = runSystem$("curl https://qiita.com/api/v2/users/" + user$)

# jqでプロフィール画像のURLを抽出
profileImage$ = runSystem$("echo " + response$ + " | jq .profile_image_url")

# 画像をダウンロード
image$ = "avator.png"
# HACK: runSystem$は戻り値を変数に代入しないとコンパイルエラーになってしまう...(謎)
dummy$ = runSystem$("curl -o " + image$ + " " + profileImage$)

# 画像を読み込みPraat上に表示
do("Read from file...", image$)
do("Paint image...", 0, 0, 0, 0)
```

ちょっとアスペクト比がおかしいですが、アイコンが表示されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239887/1351e788-afe2-87e3-4593-307ee6fc11d1.png)

# おわりに

以上、`runSystem$` の紹介でした。~~本記事ではふざけた使い道しか紹介しませんでしたが~~ 音声処理の事前準備コマンド等を呼び出す際に使えそうです。

# 過去の記事はこちら

https://qiita.com/search?q=tag%3Apraat+user%3Asyuparn
参加レポート：JAWS DAYS2024に初参戦！

# はじめに
NTTデータの西川です。
普段は公共部門の技術集約組織でクラウドの導入支援に従事しています。

2024/3/2に開催されたJAWS DAYSに行ってきました。
今回初めてJAWS DAYSに参加したので簡単に参加レポートを書いてみました。
# JAWS DAYSとは
日本のAWSユーザーグループであるJAWS-UGのイベントです。
Amazon Web Services（以下AWS）を中心とした技術情報交換を目的とし、全国から企業や個人が集まるイベントです。今年は5年ぶりのオフライン開催だったということもあり、熱量がすごかったです。（登録者数1000人超）　

> JAWS-UG（AWS User Group – Japan）は、日本全国に60以上の支部を持つ AWSのユーザーグループです。全国の各支部では、AWSに関する技術交流や人材交流が毎週のように行われ、AWSユーザーの技術力向上およびビジネスの拡大に寄与しています。
https://jawsdays2024.jaws-ug.jp/

# なぜ参加したのか
昨年、とあるイベントでみのるんさん（@minorun365）と初めてお会いし、会話させていただいたことがキッカケでTwitterなどで情報発信の様子を拝見していました。みのるんさんの発信を通してJAWS DAYSに興味を持ち、今回は所属組織の同期を誘ってJAWS DAYSに参加してきました。

> みのるんさんはJAWS DAYSの中で「AWS Samurai 2023」に選出されていました。おめでとうございます！
※AWS Samurai：コミュニティの成長およびAWSクラウドの普及に大きく貢献または影響を与えたユーザーを表彰する制度。
https://qiita.com/minorun365/items/658a8f0365d38975b9fa



私は2つの理由があり、興味のあるイベントや勉強会に積極的に参加するようにしています。
1. 次のステップが明確になるため
イベントに参加して話を聞くと、次に何を見ようか？調べようか？が見つかると思います。全く分からないものの気になるキーワードを拾って調べるもよし、詳しい領域を深ぼるもよしかと思ってます。
2. 偶然好きなものに出会うかも
たまたま耳に入ってきた、人がたくさんいたから聞いてみた等、偶然興味を持つジャンルやトピックが見つかるかもしれないと思ってます。



# 参加した感想
以下、つらつらと感想を並べてみます。
- 退任報道があったAWS Japanの長崎社長が語るJAWSコミュニティ話が熱かった。（熱量の話2回目）
- AWS Evangelist Jeff Barrさんのコミュニティに関する言葉：数字は追わず、学び繋がる中で、自然と数字はついてくる。
- 人が多く、熱量がすごい。（熱量の話3回目）
- 技術面以外のキャリア、体験談、失敗談の話が面白く、学びの幅が広い。


# さいごに
丸一日とても充実した時間でした。最近は勉強会に参加する機会を増えてますが、今回のような多岐にわたるトピックを聞ける機会は中々ないので、今後も機会があれば積極的に参加していきます。

私が得た知見やノウハウについて社外発表しようと考えているので、来年度のJAWSイベントでの発表に是非挑戦してみようと思います！
※ 本ブログに記載した内容は個人の見解であり、所属する会社、組織とは関係ありません。
Controllerで定義したメソッドをViewでも使えるようにするhelper_method

controllerにはhelper_methodを定義すると、viewでも使えるようになる
```ruby
class ApplicationController < ActionController::Base
  helper_method :current_user, :logged_in?

  private
    def current_user
      @current_user ||= User.find_by(id: session[:user])
    end

    def logged_in?
      current_user != nil
    end
end
```
```erb
<% if logged_in? %>
    Welcome, <%= current_user.name %>
<% end -%>
```
[公式ドキュメント](https://api.rubyonrails.org/classes/AbstractController/Helpers/ClassMethods.html#method-i-helper_method)

---

これを応用して、タブの切り替えをしてみた。
ApplicationControllerに書いたhelper_methodをオーバーライドしていく用法。
```rb
class ApplicationController < ActionController::Base
  helper_method :trip_type

  def trip_type
    raise 'current_status not implemented'
  end
end

---

# activity controller
def trip_type
  :activity
end

---

# luxury controller
def trip_type
  :luxury
end

---

# food controller
def trip_type
  :food
end
```

```erb
<nav>
  <ul>
    <li><%= link_to " アクティビティ", xxx_path, class: (trip_type == :activity ? 'current' : '') %></li>
    <li><%= link_to "ラグジュアリー", xxx_path, class: (trip_type == :luxury ? 'current' : '') %></li>
    <li><%= link_to "グルメ旅", xxx_path, class: (trip_type == :food ? 'current' : '') %></li>
  </ul>
</nav>
```
こんな感じで、例えばfood controllerのページを開いていた時は、タブはずっと`グルメ旅`のところにcurrentクラスがついて、タブが押されたまま・有効になったままにすることができる
ViewComponentについての備忘録

### ViewComponentってなんやねん
- Rails 6.1 から標準で提供されるようになった
- Reactから影響を受けた、Presenter(ViewのためのUIのビジネスロジックを書く)パターンの進化版
- viewの再利用性を向上させるためのコンポーネントベースのアプローチ

### パーシャルと何が違うの？
- ViewComponent はパーシャルよりも独立したユニットとして扱われるため、コンポーネントごとにテストを書くことが簡単にできる

- パーシャルより読み込みが早い　＝ パフォーマンスが向上する
    従来のRailsテンプレートは実行時に読み込まれていたが、ViewComponentのテンプレートは、アプリケーション起動時にプリコンパイルされるため
- コードの品質が高まる
    ViewComponentは単なるRubyのオブジェクトのため、コードの品質基準を守ることが比較的に容易

### 使い方
gemをインストール
```
gem "view_component"
```
基本的に`rb`ファイルと`erb`ファイルがセットで生成される。
```ruby
rails g component コンポーネント名 引数

---

app/components/
├── コンポーネント名_component.html.erb
└── コンポーネント名_component.rb

```

---
例としてはこんな感じ。
```ruby
# app/components/example_component.rb
class ExampleComponent < ViewComponent::Base
  def initialize(title:)
    @title = title
  end
end
```

```erb
<%# app/components/example_component.html.erb %>
<span title="<%= @title %>"><%= content %></span>
```

```erb
# 呼び出し元
<%= render(ExampleComponent.new(title: 'my title')) do %>
  Hello, World!
<% end %>
```

```html
<!--出力結果-->
<span title="my title">Hello, World!</span>
```

`app/components/example_component.rb`だけでも表示することはできる
```ruby
class ExampleComponent < ViewComponent::Base
  def initialize(url:)
    @url = url
  end

  def call
    button_to('削除', @url, method: :delete)
  end
end
```
```erb
<%= render ExampleComponent.new(url: xxxx_path) %>
```

ViewComponentではクラス内で`call`メソッドを定義し、その中でビューをレンダリングするためのロジックが書かれてあるので、そこに表示したい内容を書くこともできる。

### 参考
- [【ViewComponentシリーズ①】ViewComponentを導入すべき理由5つ【Rails】](https://qiita.com/ginger-yell/items/f5b80f923c8e0eee4378#:~:text=1.%20ViewComponent%E3%81%A8%E3%81%AF,-%E5%86%8D%E5%88%A9%E7%94%A8%E5%8F%AF%E8%83%BD&text=%E3%81%96%E3%81%A3%E3%81%8F%E3%82%8A%E8%A8%80%E3%81%86%E3%81%A8%E3%80%81%E3%83%95%E3%83%AD%E3%83%B3%E3%83%88%E3%81%A7%E3%81%AF,%E3%81%95%E3%81%9B%E3%81%A1%E3%82%83%E3%81%8A%E3%81%86%E3%81%A8%E3%81%84%E3%81%86%E3%82%82%E3%81%AE%E3%80%82)
イメージをアップロードできるウェブページを CICD を適用して実装

自分が LT のために実装しながら、作った slide をもう一回整理したくてこれをかきます。

単純に silde をアップロードすることではなく、実装しながら、あったエラーとか、これが大事なということを qiita にアップロードして、こちらに url をつける予定です。

実装しながら、あちこちあらゆるブログや qiita をみたので、もれた url があるかもしれません。

## AWS

https://aws.amazon.com/

https://en.wikipedia.org/wiki/Amazon_Web_Services

Amazon Web Service

私たちがよく知っているアマゾン企業です。
その企業の cloud computing service で、cloud computer(virtual)に関連したサービスを使うことができます。自分が良く使うサービスはいかになります。
1. EC2
1. S3
1. Lambda
1. VPC

これ以外あらゆるサービスがあるので、wiki や AWS ページをご覧ください。

## CI/CD ってなに？

https://en.wikipedia.org/wiki/CI/CD

https://www.redhat.com/en/topics/devops/what-is-ci-cd?cicd=32h281b

Red Hat には以下に紹介されています。

```
CI/CD (継続的インテグレーションおよび継続的デリバリー/デプロイメントの略) は、ソフトウェア開発ライフサイクルを最適化し、加速することを目的としています。
```

継続的インテグレーション(continuous integration)は**コードの変更**を **共有ソースコードリポジトリ**に **自動的かつ頻繁に取り込む**手法

継続的デリバリーまたはデプロイメント (CD) は 2 つの部分からなるプロセスで、**コード変更の統合、テスト、デリバリー**を指します。

build, テスト、デプロイ...　などを自動化することで、アプリケーションのエラーをよく発見したり、開発を高速化します。

## slide url

https://docs.google.com/presentation/d/1i64yHq_21VLWm9MRPZKM3-khKZY53IFwkxeY9vJ3KMo/edit?usp=sharing

## 実装しながら、気になったこと

cors 問題: https://qiita.com/dkdidudtn/items/6b3c8235116d2f2afd9e


## まとめ

簡単なウェブページを作るとき、イレギュラーとかエラーを修正して、また、アップロードすることは結構、手間がかかることです。
その理由で、今回 CICD 勉強しながら、AWS にも実装する練習もしました。

-----

### 参考した page

https://www.redhat.com/ja/topics/devops/what-is-ci-cd?cicd=32h281b

https://circleci.com/ja/blog/what-is-ci-cd/

https://www.servicenow.com/kr/products/devops/what-is-cicd.html

https://www.ashisuto.co.jp/devops-portal/cat05/cicd.html

https://en.wikipedia.org/wiki/CI/CD