OmniAICreator/Qiita-1.07M huggingface dataset:
.NETのすすめ

# .NETとは？
.NETとはWebアプリケーション、コンソールアプリケーション、モバイルアプリケーション、デスクトップアプリケーションなどさまざまな種類のアプリケーションを開発するためのオープンソースフレームワークです。
.NETで最も一般的な言語がC#です。他にもVisual BasicやF#などで使用可能です。
OpenTelemetryやgRPCといった業界標準な実装が重視されておりこれらの実装が容易になっています。

# .NETの動作環境は？
WindowsのみならずMacOSやLinuxでも動作できます。
また、.NET MAUIというクラスプラットフォームフレームワークにおいてはiOSやAndroid開発も行えます。

また、そのアプリケーションの種類においてもWeb、デスクトップ、IoT、モバイルなどさまざまな分野においての開発が可能です。
まさに、様々な分野に適合したフレームワークといえます。

# C#はレガシーか？
そもそも、レガシーという定義は何でしょうか？
.NETの中心的な言語であるC#は常に新しい言語仕様を取り入れています。毎年アップデートを続けています。
例えば、現代的なプログラミング言語では当たり前になったLINQはC#ではC#3.0の機能として2007年11月に取り入られています。
例えば、async/awaitはC#5.0の機能として2012年8月に取り入られています。
このように現代的な言語では当たり前になった機能はいち早くC#が実装しています。

# 開発環境構築の容易さ
.NETの開発環境の第一選択肢といえばVisual Studioです。ほかにもVisual Studio CodeやRiderなどが使用可能です。
Visual Studioで開発する場合、このVisual Studioをインストールしてその開発したいフレームワークに合わせてオプション選択するのみでほぼ開発環境構築が終了します。
基本的にこれでコードを書き始めることができるのが素晴らしいところと思います。


# Nuget
NuGetパッケージマネージャーは大規模なエコシステムです。
ここからライブラリーを組み込むことで既存のライブラリー資産を活用することができます。
このライブラリーの多数は.NETを使用して構築されており依存性の深さという点からみてもほかの言語より根が浅いことが多いです。

# Generic Host

.NETの素晴らしい機能の一つとしてGeneric Host(汎用ホスト)が上げられる。
Generic HostはコンソールアプリをはじめとしてWebアプリでは標準ですし、WPFでもGeneric Hostの使用は推奨事項です。また、.NET MAUIでも採用されています。
主な機能としては

依存関係の挿入(DI)
ログ
構成
グレースフルシャットダウン
などです。

特に、DI（サービス）機構が強力です。

たとえば、ASP.NET CoreにおいてもともとBlazorのプロジェクトだったところにWebAPIの機能も追加したいということはよくある話です。
そうしたときにはGeneric HostにWebAPIのサービスを追加してミドルウェアを追加することで使用する準備が整います。

# .NET Aspire
.NET Aspireは監視可能で運用環境に対応したクラウド対応のアプリケーションを構築するためのサービススタックです。クラウドネイティブアプリケーションは通常データベース、ストレージ、キャッシュ、AIなど多数のサービスを使用します。このためにスケーラビリティ、レジリエンス、管理性を確保するため考慮事項がたくさんあります。これらを一貫性あるツールと設定のセットを提供し開発効率の向上を支援します。

たとえば、サーバーとクライアントの2つのプロジェクトを同時に起動しないと動かないような構成のものまた3つ4つみたいなものはよくあると思います。
こうした構成のものであっても順序関係正しく例えば、サーバーから立ち上げてクライアントを立ち上げるというような依存関係を構成してあげることも可能です。

可観測性という面では組み込みのダッシュボードが大変便利です。
アプリからOpenTelemetryを受信して独自UIで各種ログを表示します。また、最近のバージョンではそのログに対してGitHub Copilot Chatに問い合わせをすることができます。

# AI
.NETではAIについても対応が進んでいます。Microsoft.Extensions.AIライブラリーによって標準的なLLMクライアントに対する実装が可能になっています。
たとえば、OpenAIやOllamaなど異なるAIに対して同じ実装が可能になっていることを示します。
また、より強力なオーケストレーションをするためにSemantic Kernelもあります。これも一部、Microsoft.Extensions.AIライブラリーと型互換性がとられていたりしてとても使い勝手がよくなっています。

# Blazor
ASP.NET Coreの最もモダンなWebフレームワークで単一のプログラミングモデルでサーバーサイドのレンダリングとクライアントサイドのレンダリングの両方をサポートしています。また、ページ単位でその切替もできます。

特徴としては、C#でクライアント側のロジックとサーバー側のロジックを共有することができます。すなわち、同一の言語でサーバーとクライアント側を実装できるので型共有も可能ということになります。

.NETのこれまでのライブラリー資産を生かした開発ができます。

WindowsやLinux、MacOS上でVisual StudioであったりVisual Studio CodeやRiderなどの開発環境で開発できWindowsやLinuxなどにデプロイできます。もちろん、コンテナ化して可搬性を考慮した設計も可能です。
株式会社ログラス5daysインターンに参加して学んだこと・感じたこと

# ログラスってどんな会社？
https://www.loglass.co.jp/

「良い景気を作ろう」をミッションに掲げ、経営判断をより効率的にするためのサービスを提供している会社です。
2027年までに様々なプロダクトを展開する予定で、海外進出もしようとしています。
それこそ、私自身ログラスを日経新聞で見かけたことがあるぐらい、現在急成長しているスタートアップの会社です。


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4078488/07755e12-f619-4af1-93cc-781e3f19bb79.png" width=50%>


# DDD(ドメイン駆逐設計)
今回のインターンではDDDを用いて開発を行いました。
初日に松岡さんから直接講義をしていただきました！！とても分かりやすかったです！！！

そもそもドメインとは？ドメインとは「ソフトウェアで解消しようとする対象」のことです。そして、ドメイン駆逐設計はこのドメインにフォーカスして、複雑なソフトウェアを整理・設計をしていくアプローチです。

メリットとして
・ドメインの何らかの問題を解決できる機能面
・長期的な問題を解決し続けられる保守性
などがあります。

実装の流れとしては、まずドメインの理解から始まり、ドメインモデリング、ドメインの実装と続きます。この中で、ドメインの理解とドメインモデリングの設計が非常に時間と体力がかかる工程です。逆にここが終われば実装はさほど時間がかからない印象でした。

ドメインの理解の部分では、今回はまだそこまで難しい内容をやったわけではないので理解にさほど苦しまなかったが、将来的に複雑なドメインを扱うとなったら、エンジニアといえどやはり深く理解及び勉強する必要があるのだと感じました。というのも、作る側もしっかりとドメインを理解しないと、価値のあるプロダクトを作ることは難しいと身をもって体験しました。

ドメインモデリング設計の部分では、最初に完璧な設計を完了させる必要はなく、一度おおよそなものができたら実装に移り、必要に応じてまたモデリングに立ち返ることが大切なのだと学びました。どんなことでも同じだとは思うのですが、最初から100％良いものを作るって難しいですよね！実際に体験してその結果立ち戻ってより磨いていく、どんな分野にもつながる大事な考え方なのだと、改めて感じました！！


# チーム開発で大切なのは技術力だけではない！
今回のインターンではスクラムを組んで行いました。チームは5人(スクラムマスター役のメンター含む)で、5日間を2つのスプリングに分けるという、なんともハードなスケジュールで開発しました。

まず大前提の背景として、私は他のチームメンバーに比べてまだまだ技術力が弱く、どちらかというとビジネスマインドよりの人間です。なので、チームビルディングなどを考えて、チーム内のムードメーカーになり常にチームメンバー全員明るい空気が流れ、みんなが意見を言えるような空間を作ることを意識していました。

そんな中、最初のsprint1は精神的にも体力的にもとってもハードでした。慣れてないということもあり、ドメインモデリングの設計では何をやっているかをあまり理解できず、開発部分でもわからない部分が多く、他のチームメンバーにとても助けられました。正直、もう来たくないななんて思った瞬間もありました。

しかし、3日目の途中sprint1が終了したときに大きな転換が来ました。というのも、sprint2ではどのような方向性でプロダクトを作っていくのか、どのような機能を入れていくのかを議論する必要がありました。自分の強みを最も発揮できるのはここだと感じました。実際に、メンバーの議論が広く展開されすぎた時に、本質的に今回要求されているものは何なのかと立ち戻ったり、クライアント側の要求を満たすために実装すべき本質的な機能は何なのかを提案したりとチームの方向性を決める部分で活躍できたと思います。また、当初のチームビルディングが功をなして、私のチームでは白熱した議論もありました。ほんとの意味でチームが1つになったのだと心の底から感じたのと同時に、そこからの時間は楽しくてしかたがなかったです。

まとめると、技術力は開発においてとても大切です。しかしながら、チームでは明るいムードを作ったり、意見を言えるような空気を作ったりと、環境を整えられる力もとっても必要なのだと気づきました。メンバー全員が思っていること感じていることを議論に出せる、困った時に助けを求められる、そんなチームでの仕事は楽しくてなおかつ最高なプロダクトが作られると思いました。


# 就活における新たな軸
今回のインターンを通じて就活での新たな軸を自分の中で見つけられました。

一言で言うと、
「私がジョインすることでどのぐらいその会社を変えられるか」
です。

以前の私含め、多くの就活生はその会社から何を学べるのか？という視点で見ることが多いと思います。それもとっても大事な視点だとは思います。

しかし、私は一般的なエンジニアにないビジネス的な勘所だったり、チームビルディング力だったり、自分の才能を使ってジョインした会社に大きな良い変化をもたらしたいです。少々おこがましいかもしれませんが、新卒だからといってそれができないと私は思いません。エンジニアだから開発だけしろ、というよりかは新卒からの意見や指摘をエンジニア・ビジネス側関わらず受け入れてくれてディスカッションする機会を設けてくれる、そんな場所に身を置きたいなと感じました。

# 最後に
本当に最高なチームでした！メンターの方も本当に親身になってサポートしてくれました！

今回のインターンに参加して本当に良かったです。
技術面の向上もしかり、自分を見つめ直すいいきっかけとなりました！！

本当におすすめのインターンです！興味のある方はぜひ参加してみてください！
`gets`メソッドを使って、標準入力から意図した値を取得する手順

## はじめに
こんにちは。KoSaxです！
今日は、paizaのプログラミングスキルチェックを初めて解いた時、苦戦したことを記事にしようと思います。
paizaのプログラミングスキルチェックは楽しくスキルを積み重ねられるのが、大きな魅力です。また、「paizaレーティング」というプログラミングスキルの指標を取り入れている点が最大の魅力でしょう。
paizaのプログラミングスキルチェックで、まず最初に値を受け取るために使う`gets`メソッドについて、本日はアウトプットしたいと思います。それでは早速見ていきましょう！

https://paiza.jp/challenges/info

https://www.mathenachia.blog/paiza-rating/

## paizaの問題文
D < C < B < A < S のランクに分けて問題が出題されます。
以下のような入力値が渡されるCランクの問題がありました。

**🟨入力される値**
```
入力は以下のフォーマットで与えられます。
---
N M
A B C
R_1
R_2
...
R_N
---
・１行目には、 nnn の数を表す整数 N および mmm の数を表す整数 M が半角スペース区切りでこの順で与えられます。
・２行目には、 aaa の数を表す整数 A 、 bbb の数を表す整数 B 、 ccc の数を表す整数 C が半角スペース区切りでこの順で与えられます。
・続く N 行のうちの i 行目 (1 ≦ i ≦ N)には i 番目の iii が M ヶ月間に販売した rrr の数を表す整数 R_i が与えられます。
・入力は合計で 2 + N 行となり、入力値最終行の末尾に改行が 1 つ入ります。

それぞれの値は文字列で標準入力から渡されます。
```

**入力例**
```
3 3
1000 1000 50
25
80
500
```
このような**標準入力**から値を取り出す方法を見ていきたいと思います。

## 標準入力とは
- プログラムがデータを読み込む先のこと
- 通常、「キーボードからの入力」「他のコマンドから渡されるデータ」などのことを指す
- 例：以下のテキストはユーザーが入力した値
```
5 10
5
11
20
8
7
```
-  このようなユーザーが入力した値を、　`gets`メソッドを使って変数に格納し、取得していきます。

# 標準入力から値を取得するために必要なメソッド

## `gets`メソッドとは
- **標準入力**から、**「１行分の文字列」＋「`\n`（改行文字）」を取得**するメソッド
### `gets`メソッドの注意点
- **文字列として取得すること**
- **`\n`（改行文字）を含んで取得すること**
- 「**文字列**」「**文字列の配列**」「**数値**」「**数値の配列**」として取得したい場合、他のメソッドを組み合わせる必要がある
- 標準入力のx行目を取得したい場合、x回`gets`メソッドを実行すると取り出すことが可能

## `.chomp`メソッドとは
- 文字列の末尾に`\n`（改行文字）がある場合、取り除くメソッド

## `.split`メソッドとは
- **文字列**を、指定した区切り文字で分割し、**文字列の配列にするメソッド**
- つまり、`文字列`＋`.split(区切り文字)` ➡︎ 文字列の配列＋区切り文字
- 引数なしの場合、空白で文字列を分割する

## `.map(&:to_i)`とは
- 配列に格納されている文字列を、整数に変換する役割
### `.map`メソッドとは
- 配列やEnumerableモジュールの各要素に対して、私たブロックを一度ずつ実行し、その戻り値を新しい配列に返すメソッド

---
以下の標準入力例をもとに実際のコードと実行結果を記述していきます。
```
5 10
5
11
```

## 文字列として取得（基本）
### `var`＝`gets`＋`.chomp`
**`gets`のみ＝文字列（`\n`あり）**
```ruby
n = gets
puts n
# 実行結果 => "5 10\n"
```
**`gets`＋`.chomp`＝文字列（`\n`なし）**
```ruby
n = gets.chomp
puts n
# 実行結果 => "5 10"
```

## 文字列の配列として取得
### `var`＝`gets`＋`.chomp`＋`.split`
```ruby
n = gets.chomp.split
puts n
# 実行結果 => ["5, 10"]
```

## 数値（整数integer）として取得
### `a, b` = `gets`＋`.chomp`＋`.split`＋`.map(&:to_i)`
```ruby
a, b = gets.chomp.split.map(&:to_i)
puts a
puts b
# 実行結果 => 5, 10
```

## 数値（整数integer）の配列として取得
### `var` = `gets`＋`.chomp`＋`.split`＋`.map(&:to_i)`
```ruby
n = gets.chomp.split.map(&:to_i)
puts n
# 実行結果 => [5, 10]
```
- `n = [5, 10]`であるから、インデックスで配列内の数値にアクセス可能
- 例：`n[0]   # => 5`

## 最後に
いかがだったでしょうか。
「文字列」「数値」「配列」のうち何を扱うことができるメソッドなのかを見極めないと、自分が意図した値を得られないことがわかります。
取得した値をループ処理する場合も、`.each`メソッドは**配列**にしか使えません。
プログラミング初学者として、意識して学習しないといけないポイントだと感じました。
今日からも頑張って勉強していきます。頑張るぞー！
cscの作法 その588

# 概要
cscの作法、調べてみた。
dxlibdotnet、見つけたので、windows10で、buildしてみた。
練習問題やってみた。

# 練習問題
3Dを表示せよ。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/fbb1bfc4-2e19-4bb6-84b0-697d8479014a.png)

# サンプルコード

```
using System;
using DxLibDLL;


class Test {
	[STAThread]
	static void Main() {
		DX.ChangeWindowMode(DX.TRUE);
		DX.SetGraphMode(640, 480, 32);
		if (DX.DxLib_Init() == -1) 
			return;
		while(DX.ProcessMessage() == 0 && DX.CheckHitKey(DX.KEY_INPUT_ESCAPE) == 0)
		{
			DX.ClearDrawScreen();
			DX.VECTOR p1 = DX.VGet(200, 200, 200);
			DX.DrawSphere3D(p1, 100.0f, 10, 0xffffff00, 0xffffffff, DX.FALSE);
			DX.ScreenFlip();
		}
		DX.DxLib_End();
	}
}


```

以上。
ChatGPTを使用したアプリ開発記【利用規約・プライバシーポリシーの追加】

## Terms.js、Privacy.jsの作成
```Terms.js
import React from "react";

const Terms = () => {
  return (
    <div className="max-w-3xl mx-auto px-4 py-10">
      <h1 className="text-2xl font-bold mb-6">利用規約</h1>
      <p className="mb-4">この利用規約（以下，「本規約」といいます。）は，本サービスの利用条件を定めるものです。</p>
      <h2 className="text-xl font-semibold mt-6 mb-2">第1条（適用）</h2>
      <p className="mb-4">本規約は，ユーザーと当社との間の本サービスの利用に関わる一切の関係に適用されるものとします。</p>
      {/* 以下、項目を必要に応じて追加 */}
    </div>
  );
};

export default Terms;
```
```Privacy.js
import React from "react";

const Privacy = () => {
  return (
    <div className="max-w-3xl mx-auto px-4 py-10">
      <h1 className="text-2xl font-bold mb-6">プライバシーポリシー</h1>
      <p className="mb-4">当社は、ユーザーのプライバシーを尊重し、個人情報の保護に努めています。</p>
      <h2 className="text-xl font-semibold mt-6 mb-2">1. 個人情報の取得</h2>
      <p className="mb-4">当社は、適正な手段によって、必要な範囲で個人情報を取得します。</p>
      {/* 以下、項目を必要に応じて追加 */}
    </div>
  );
};

export default Privacy;
```

## Footerの作成
```Footer.js
import React from "react";
import { Link } from "react-router-dom";

const Footer = () => {
  return (
    <footer className="text-center text-sm text-gray-500 mt-10 py-4">
      <div className="space-x-4">
        <Link to="/terms" className="hover:underline">
          利用規約
        </Link>
        <Link to="/privacy" className="hover:underline">
          プライバシーポリシー
        </Link>
      </div>
      <div className="mt-2">© {new Date().getFullYear()} YourAppName</div>
    </footer>
  );
};

export default Footer;
```

## Layout.jsの作成
```Layout.js
// src/Layout.jsx

//React：Reactコンポーネントを作るために必要です。
import React from "react";
//Outlet：react-router-dom の機能で、「ここにルーティングで切り替わるページコンポーネントを差し込む」という意味です。
import { Outlet } from "react-router-dom";
import Header from "./Header";
import Footer from "./Footer";

const Layout = () => {
  return (
    <div className="flex flex-col min-h-screen">
      <Header />
      <main className="flex-grow pt-20 px-4">
        <Outlet /> {/* 各ページがここに表示される */}
      </main>
      <Footer />
    </div>
  );
};

export default Layout;
```

## AppRouter.jsにLayout.jsの仕様を追加

```AppRouter.js
<Route path="/" element={<Layout user={user} setUser={setUser} />}>
  {/* ここにネストされるルートは全て Layout の中で表示される */}
</Route>
```
•	path="/"：/（つまり全体のルート）に対して、
•	element={<Layout />}：Layout コンポーネントを表示するようにしています。
•	そしてこの <Route> の 内側にネストされている Route たち は、すべて <Layout /> の中の <Outlet /> の位置に差し込まれます。

##  Login だけ Layout に含めない理由

React アプリでは、以下のように「どのページでも共通して表示したい要素」があります：
|要素|例|Layout の中で表示する理由
|-|-|-|
|ヘッダー|ロゴ・ナビゲーションバー|どのページでも共通表示したい
|フッター|コピーライト・利用リンク|同上
|レイアウト構造|min-h-screen など|全ページ共通の画面設計

これを毎ページ個別に書くと重複が多く、保守性が悪いですが、Layout で一括管理すれば 一度の定義で全ページに適用できます。
Geminiでドラゴンと遊ぶ魔法少女を描いてみた。

# 概要

Geminiでドラゴンと遊ぶ魔法少女を描いてみました。

# 実装

プロンプトと実行結果は以下の通りでした。

```
水のドラゴンと遊ぶ魔法少女を描いてください。
```

![水のドラゴンと遊ぶ魔法少女_20250617.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192024/96d38f30-0887-4b19-8b7d-ce13da6f4a85.png)

# まとめ

何かの役に立てばと。
本番環境にClerkでGoogleログインを追加する方法

# 手順

1. Clerkの「SSO connections」ページから、「Add connection」ボタンを押下する
    ![スクリーンショット 2025-05-29 7.34.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3456603/f6c6d142-449d-4bef-92ae-19db9ed8fae0.png)
2. Googleを選択する
    ![スクリーンショット 2025-05-29 7.34.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3456603/b8a86fe3-f559-48cf-83c2-d87e8a1f466e.png)
3. [Google Cloud Console](https://console.cloud.google.com/)を開く
4. 「プロジェクトの作成」「新しいプロジェクトを作成する」を押下し、新しいプロジェクトページへ移動する
    ![スクリーンショット 2025-05-29 7.53.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3456603/14e5fa4d-7809-44ac-8518-2076b8130953.png)
5. 適当なプロジェクト名を入力し、「作成」を押下する
    ![スクリーンショット 2025-05-29 7.57.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3456603/e36e372f-d72b-4cc4-9d89-bc7480bc4266.png)
6. サイトバーから、「APIとサービス > OAuth 同意画面」ページに移動する
    ![スクリーンショット 2025-05-29 7.52.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3456603/c535ee88-5c73-4d74-8caa-230206859a35.png)
7. 「開始」を押下する
    ![スクリーンショット 2025-05-29 8.01.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3456603/dccc0c36-388e-48a9-b8cd-0a240fb6694c.png)
8. 適当な情報を入力し、「作成」を押下する
    ![スクリーンショット 2025-05-29 8.03.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3456603/0a113a14-24e9-4503-abff-ddcc04b6b699.png)
9. サイトバーから、「APIとサービス > 認証情報」ページに移動する
    ![スクリーンショット 2025-05-29 7.52.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3456603/c535ee88-5c73-4d74-8caa-230206859a35.png)
10. 「認証情報の作成」から、「OAuth クライアント ID」を選択する
    ![スクリーンショット 2025-05-29 8.05.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3456603/1f4a395d-5ca2-46f1-8f25-982adb10a4f6.png)
11. 必須項目を入力した上で、承認済みのリダイレクトURIにClerk上で提示された「Authorized Redirect URI」を入力し、「作成」を押下する
    ![スクリーンショット 2025-05-29 8.07.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3456603/ec13ba39-6f39-4184-a3ef-acd391de506d.png)
    ![スクリーンショット 2025-05-29 8.08.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3456603/d34fda3f-6357-4cea-81a7-5a3697c7e10a.png)
12. Clerkの画面に戻り、表示されたClient IDとClient Secretを入力した上で、「Add connection」を押下する
    ![スクリーンショット 2025-05-29 8.10.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3456603/feda6dac-9105-48f2-954e-2a6677c1e329.png)
    ![スクリーンショット 2025-05-29 8.11.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3456603/1dbd633e-9e4c-4b6b-8cc8-ea771229cce0.png)

---

参考情報

- https://clerk.com/docs/authentication/social-connections/google
アジャイル開発、スクラムとは何か

## はじめに
アジャイル開発、スクラムとは何かをまとめた。

## アジャイル開発とは
- プロジェクト管理方法の一つ
- 従来の管理方法であるウォーターフォールの弱みを克服する
- ウォーターフォールは上から下に要件→開発→テストの各工程を進む
  - 時間やお金をかけた割に無駄な機能が多く失敗してきたプロジェクトが多い
- アジャイルは3~9人のチームでコンポーネント毎に要件→開発→テストを繰り返す
  - 細かい単位で素早く開発サイクルを回すことで品質・コスト効率が高まる

![ウォーターフォール.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3088985/dbad2e26-bc48-403a-8d67-0cda006181bd.png)


## スクラムとは
- アジャイル開発を実現するフレームワークの一つ
- Aha, Jiraなどを使いチームでPJ管理する

### チームメンバー・役割

|チームメンバー|役割|
|---|---|
|プロダクトオーナー|PJのコストと時間の監督、顧客との折衝|
|スクラムマスター|スクラムとは何かを説く(不要になるのが理想)|
|開発チーム|スプリントのタスクに取り組む|

### ワークフロー
- プロダクトビジョンの策定・共有
- プロダクトロードマップの策定・共有
- プロダクトバックログに落とし込む
  - AdobeXDなどでデザインのモック(プロトタイプ)を作る
  - drawioなどでアーキテクチャ図を作る
  - ユーザーストーリー(顧客のために何が必要かの要件)を作る
  - 工数、優先順位を見積もる
- スプリントプランニングの策定・共有 
- スプリントバックログに落とし込む
  - プロダクトバックログで決めたことの具体的な計画を立てる
  - 例えばアサインを決める
- スプリントで開発する
- デイリースクラム(進捗確認)の実施
- インクリメント(納入)の実施
  - 開発、テスト、レビューが必要
- スプリントレビューの実施
  - デモ(動作しているソフトウェア)を関係者に見せる
- スプリントレトロ(反省会)の実施
  - 次のスプリントに向けたTODOを決める 

![スクラム.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3088985/44526b69-bc28-44d6-ac92-2aff494bdd0c.png)


## おわりに
理論的なことはわかったので開発に落とし込んで実践していきたい。

## 参考文献

https://www.udemy.com/course/ajail-scrum/?couponCode=ST7MT290425G2
npmパッケージの公開方法

## 概要
初めてnpmパッケージを公開してみたのでその手順を記載します。

## 実装
npmを公開するだけであればgitを使用する意味はありませんが、定期的にメンテナンスしていきたいので使用します。


```bash
% git init
```
### ディレクトリ
ディレクトリ構成は以下にしています。
```bash
├── package.json
├── tsconfig.json
├── README.md
└── src/
    └── index.ts
```

### 詳細
`index.ts`に実際のロジックを記載しています。

package.jsonは下記のように定義しています。


```json
{
  "name": "offset-hours",
  "version": "1.0.1",
  "description": "Get a Date offset by N hours",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "scripts": {
    "build": "tsc",
    "prepublishOnly": "npm run build"
  },
  "license": "MIT",
  "devDependencies": {
    "typescript": "^4.9.0"
  },
  "files": [
    "dist",
    "README.md",
  ]
}
```

```json
"license": "MIT",
```
ライセンスはオープンソースとして扱いたかったのでMITに設定しています。

```json
  "files": [
    "dist",
    "README.md",
  ]
  ```

`"files": ["dist", "README.md"]` は、npm パッケージを公開するときに どのファイル・フォルダだけを含めるか を指定する設定です。

`dist/`
ビルド済みの JavaScript（index.js）と型定義（index.d.ts）が入っているフォルダ。

`README.md`
npm／GitHub 上でパッケージの説明として表示されるマークダウンファイル。

### 公開
機能が作成できたら、実施にnpmに公開します。

https://www.npmjs.com/signup にアクセスし、アカウントを作成します。
![スクリーンショット 2025-06-16 21.14.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/952574/6d79b81c-930f-496d-956a-83db5c8a4762.png)


アカウントを作成できたら、ビルドして、npmに公開するコマンドを入力します。
```bash
% npm install
% npm run build
```

```bash
% npm publish

> offset-hours@1.0.0 prepublishOnly
> npm run build


> offset-hours@1.0.0 build
> tsc

npm notice
npm notice 📦  offset-hours@1.0.0
npm notice Tarball Contents
npm notice 415B README
npm notice 310B package.json
npm notice 512B src/index.js
npm notice 407B src/index.ts
npm notice 0B tsconfig.json
npm notice Tarball Details
npm notice name: offset-hours
npm notice version: 1.0.0
npm notice filename: offset-hours-1.0.0.tgz
npm notice package size: 808 B
npm notice unpacked size: 1.6 kB
npm notice shasum: 465e0c2c7fa4b57d724774957f70071db97e1a01
npm notice integrity: sha512-EIDrD6clXRNYb[...]vDSCh1IyK9j+g==
npm notice total files: 5
npm notice
npm notice Publishing to https://registry.npmjs.org/ with tag latest and default access
+ offset-hours@1.0.0
+ ```
```

公開できたら、画面右上のPacckagesをクリックして確認できれば公開成功です。
![スクリーンショット 2025-06-16 21.26.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/952574/1c43180d-423d-4a63-8d2c-305ee98464a6.png)

以上です。

## 備考

公開したnpm
https://www.npmjs.com/package/offset-hours
Github
https://github.com/shintarou37/get-date
Amazon Q CLIで今度こそゲームを作成した

[前回記事の続きです。](https://qiita.com/sakat117/items/0337f1c99b3db68492ca)

今回もTシャツ目当てにAmazon Q CLIを使った記事と、作成過程での学びを書ければと思います。

https://community.aws/content/2xIoduO0xhkhUApQpVUIqBFGmAc/build-games-with-amazon-q-cli-and-score-a-t-shirt

## なんのゲームをつくるか

ドットアンドボックスというゲームがあり、古くより紙と鉛筆だけでできるゲームで親しまれているものです。
最近の子だと、Switchの「アソビ大全51」などにも入っているので、やってみた人もおられるのではないかと。

https://www.nintendo.com/jp/switch/as7ta/index.html?srsltid=AfmBOopvE64U-sscPAf4SW2TWYZDQdNob4O7km8AZ-C-K-tBrDMKiWg-

以前お遊びでつくってみて子供たちと遊んだのだが、ミスさえしなければ負けないような作りで、ちょっと遊びやランダム要素が足りないな、と感じていた。

そこで今回は、「ドットアンドボックス」に特定マスを開くと爆死する要素を追加し、「マインスイーパー+ドットアンドボックス」という多分世の中にはないゲームをpygameで作ることとした。
<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4108140/10ffac7a-4789-4187-97f4-52887c505ca7.png" "generated by chatgpt">
(generated by chatgpt)

## 指示からのゲーム作成
とはいえゲーム作りとかやったことないので、まずは「何の情報与えればゲームが作れるの？」と問い合わせして、様式を作成してもらった。
随分大規模な想定をされてしまったのだが、基本はあなたに任せますよのスタンスで提出、第一弾を作成してもらえる。
そこからどこが悪い、どうして欲しい、一から考え直して、など突き詰めることで、無事ゲーム最終版を完成させることができた。(最後にゲームのプログラムを添付する。)

![python_itzbKdP8bG.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4108140/6c0dff10-8d2d-4451-9ede-314305f4566b.gif)


## 気付き
### 1. 必要なプログラム全部を把握してくれる
今回のゲームに関するpythonファイルを、作成時点で分けて作成してくれるほか、修正時は各プログラムの関係を把握して修正してくれるので、個別にClaudeに頼んでいた時より断然楽だった。
### 2. テストプレイでのエラーを勝手に直してくれる
今回のプロンプトのミソとして、「該当のプログラムについて修正して。修正後テストプレイさせて」というと、一通りの作業が終わった後プログラムを起動してくれる。この時諸々の機能が動かなくてエラーが発生したりクラッシュしたりするのだが、その際プログラムを閉じた後エラーを検知して勝手に直して再度テストプレイさせてくれる。これはプロンプト回数減らせる上に、いちいちあれが起動しないなどのエラー内容を伝える必要がないため、非常に利便性を感じた。
### 3. 最初に考えたロジックを抜本的に変更できない
Amazon Q CLIに限った話ではないが、最初のプロンプトでAIが考えだしたロジックが根本的に実現不可能な場合、バグを指摘しても工夫だけで乗り越えようとしてしまう。
### 4. 抜本的な変更を指示しても前のコードが残りがち
「その方法は無理だよ、もっとこうしては？」と依頼すると聞き入れてくれて直してくれるのだが、途中まで書いたカードや変数を微妙に残したままへんしゅうしようとしてしまう。その結果、不必要なデータによりバグを発生させてしまう。(ここも指摘してあげればなおるが…)
### 5. 基本は継ぎ足しで対応していこうとする
これも生成AIの特徴として、修正をやるにあたってはコードを継ぎ足してなんとかしていこうとする。これにより4項のような事態が発生するし、万が一ver1.0にたどり着けたとしても、コードの九龍城状態になってしまい、何がなんやらどれが必要やらわからない、ひどいコードへと至ってしまう。

## まとめと感想

今回は企画に誘われてAmazon Q CLIというものを使って、ウェブで生成AIを使ってコード作成とは違う体験をした。

PC内情報を使って種々のコーディングや対応をしてくれるため、非常に強力なツールであると感じた。
またAmazon Q CLIというからにはAWSリソースとの連携が強力なはずなので、そこを交えて開発をすればやはり非常に強力であり、課金の価値は十二分にあるように感じた。

ただ生成AIとして気を付けなければならないところは同様にあるため、下記は留意して開発を進める必要があると思った。

1. 極力疎結合とし、一個一個の機能ごとに開発を進める
2. 可能であれば設計書などをしっかり作り上げ、1回目からちゃんとしたものを作ってもらうようする
3. コードの構成を理解し、ブラックボックスの状態で放置しない。

利用上限は月50回と一見少なそうに見えるが、テストプレイでのエラー自動修正を考えれば、案件を絞って活用すれば十分にトライからスタートできるため、皆さんもぜひ使ってみてほしい

https://github.com/sakat117/mine_dots_and_boxes
2025/6/17主にITとかセキュリティの記事

2025年5月29日～2025年6月4日までに報告されたWordPress関連の脆弱性情報(6/15)
https://news.mynavi.jp/techplus/article/wordpressvulnerability-6/

Discord招待リンク乗っ取りでAsyncRAT・Skuld Stealer配布、暗号通貨ウォレット狙う新手法(6/15)
https://innovatopia.jp/cyber-security/cyber-security-news/57653/

多要素認証「万全でない」と専門家＝「リアルタイムフィッシング」警戒―証券口座乗っ取り対策(6/14)
https://sp.m.jiji.com/article/show/3541237

インターポール 20,000以上のIPとドメインの削除、41のサーバーと100GB以上のデータの押収、違法なサイバー活動に関連する32人の容疑者の逮捕 (2025.06.11)(6/15)
http://maruyama-mitsuhiko.cocolog-nifty.com/security/2025/06/post-d9e745.html

AIを安心して使うには？　プライバシー侵害を防ぐ7つのベストプラクティス(6/15)
https://news.yahoo.co.jp/articles/1e4ca0b3b50d603e72361421ace79b4590321af3

MSI、AGESA 1.2.0.3e BIOS公開。TPM 2.0の脆弱性を修正。新しいRyzen CPUにも対応。Ryzen 9000Fシリーズか(6/15)
https://www.nichepcgamer.com/archives/msi-amd-am5-motherboards-agesa-1203e-bios-update.html

iPhoneで「知らない番号からの着信」に出なくて良い時代到来--iOS 26なら自動応答＋用件テキスト化(6/15)
https://japan.cnet.com/article/35234262/

関数型言語を採用し、維持し、継続する(6/14)
https://zenn.dev/siiibo_tech/articles/adopting-fp-languages

クレジットカード決済システムの解剖メモ(6/15)
https://zenn.dev/su8/articles/74b2055e16f030

パロアルトネットワーク:サイバー脅威に直面する自信のあるインドネシアの中堅企業(6/13)
https://voi.id/ja/teknologi/488412

中国人「闇バイト」　手順・ルール明瞭(6/15)
https://www.yomiuri.co.jp/local/osaka/news/20250614-OYTNT50204/

USBメモリを使うのは時代遅れ？紛失リスクが高いのに物理ストレージを使い続ける意味とは？(6/15)
https://news.yahoo.co.jp/articles/3ea09f2b9df1b22939c508cbcdc043bffc0765eb

IT技術ニュース要約 - 2025-06-14
https://qiita.com/sponge841841/items/06291a5f4c9439da635d

イスラエル・イラン戦争勃発：トランプ「外交解決」の嘘　antiwar.comニュース(6/14)
https://alzhacker.com/special-report-iran-and-israel-and-the-us-at-war/

セキュリティ人材育成へ 30年までに専門家5万人 経産省(6/15)
https://ab.jcci.or.jp/article/112555/

情報漏えいの原因、それは自社の「オウンゴール」かも？(6/15)
https://news.yahoo.co.jp/expert/articles/217f3a943a2f613929bdeee15084c8118113438a
【Python初心者】collectionsモジュールの使い方まとめ（Counter / defaultdict / OrderedDict / namedtuple）

`collections` モジュールの代表的なクラスの使い方を整理しました。  
特に `Counter` や `defaultdict` は、初学者でもすぐに使える便利ツールです。


## Counter：リストや文字列の要素を数える

`Counter` は、リストや文字列の中に「同じ値が何回あるか」を数えてくれるクラスです。

```python
from collections import Counter

data = ["apple", "banana", "apple", "orange", "banana", "apple"]
counter = Counter(data)

print(counter)
```

実行結果：

```
Counter({'apple': 3, 'banana': 2, 'orange': 1})
```

- `apple` が3回、`banana` が2回、`orange` が1回登場しています
- 出力は辞書のような形式ですが、`Counter` 型です

### よく使うメソッド：most_common()

よく登場する順に並べて、上位だけ取得できます。

```python
print(counter.most_common(2))  # 上位2つを取得
```

実行結果：

```
[('apple', 3), ('banana', 2)]
```


## defaultdict：キーがなくてもエラーにならない辞書

普通の辞書は、存在しないキーにアクセスするとエラーになります。

```python
d = {}
# d["a"] += 1  # → KeyError が出る（理由：読み取り時に "a" がないため）
```

`defaultdict` を使うと、キーが存在しなくても**自動で初期値を作ってくれる**ので安全です。

```python
from collections import defaultdict

dd = defaultdict(int)  # int() は 0 を返す
dd["a"] += 1  # キー "a" が自動で作られて 0 + 1
dd["b"] += 2
print(dd)
```

実行結果：

```
defaultdict(<class 'int'>, {'a': 1, 'b': 2})
```

### list や set を初期値にすることも可能

```python
dd = defaultdict(list)
dd["fruits"].append("apple")
dd["fruits"].append("banana")

print(dd)
```

実行結果：

```
defaultdict(<class 'list'>, {'fruits': ['apple', 'banana']})
```

## OrderedDict：登録順を保持する辞書

Python 3.6以降の `dict` は順序を保持するようになりましたが、`OrderedDict` は**順序を明示的に扱いたいときに使います**。

```python
from collections import OrderedDict

od = OrderedDict()
od["one"] = 1
od["two"] = 2
od["three"] = 3

for k, v in od.items():
    print(k, v)
```

実行結果：

```
one 1
two 2
three 3
```

- 登録した順番通りに出力されます
- 通常の辞書とほぼ同じように使えますが、順番が重要な場面では `OrderedDict` を使うと明示的で分かりやすいです


## namedtuple：名前付きでアクセスできるタプル

### 🔰 普通のタプルだと分かりにくい…

```python
p = (10, 20)
print(p[0])  # 10（xのつもり）
print(p[1])  # 20（yのつもり）
```

このように、普通のタプルは「番号」でアクセスするため、何が何の値かわかりづらくなります。

### ✅ namedtuple を使うと、意味のある名前でアクセスできる

```python
from collections import namedtuple

# "x" と "y" という名前を持つ Point 型を定義
Point = namedtuple("Point", ["x", "y"])

# 位置情報を表すデータを作成
p = Point(10, 20)

# 名前付きでアクセスできる（わかりやすい！）
print(p.x)  # 10
print(p.y)  # 20
```

### 📌 解説：この1行の意味

```python
Point = namedtuple("Point", ["x", "y"])
```

- `"Point"`：作成するクラス（型）の名前。見た目はクラスのように使える
- `["x", "y"]`：その型が持つフィールド名（インデックスの代わりに使える名前）

この行は、**「xとyという名前を持つデータ構造（Point）を作る」**という宣言です。

### 🧠 補足：クラスよりもお手軽なデータ構造

`namedtuple` は簡易的なクラスのようなものです。次のような特徴があります：

- 読み取り専用（値は変更できない）
- 軽量で高速
- `p[0]` でも `p.x` でもアクセスできる

可読性がよくなるので、「意味のあるデータのかたまり」を簡単に表現したいときに便利です。


## おわりに

今回は `collections` モジュールの中でも、実務や試験でよく登場するクラスについてまとめました。  
特に `Counter` や `defaultdict` は日常的に使える場面が多く、コードがシンプルになるのでおすすめです。  
`namedtuple` のような「意味をもたせたデータ構造」も知っておくと便利だと感じました。
Railsでローマ字スラッグを実装する

## 1. ローマ字スラッグとは？

日本語タイトルをアルファベット表記（ローマ字）に変換し、URL パスとして利用する手法です。つまり、記事の URL を数値 ID ではなく、タイトルに基づいた文字列（スラッグ）で生成します。


記事タイトル: 初めてのRailsガイド
↓
ローマ字スラッグ: /articles/hajimete-no-rails-gaido


## 2. ローマ字スラッグのメリット

* **SNS共有**: エンコードされず、URL がそのまま読める
* **グローバル対応**: 海外ユーザーも意味が想像しやすい
* **SEO**: 意味ある単語の組み合わせがランキング要因になる
* **UX**: コピペ時も見栄えが崩れない


## 3. Rails での実装手順（`friendly_id` + `romaji`）

### 3.1 Gem をインストール & 初期設定

```bash
# Gem 追加
bundle add friendly_id romaji

# friendly_id の初期設定ファイルと history 用テーブルを生成
rails generate friendly_id

# articles テーブルに slug カラムを追加（UNIQUE & INDEX 付き）
rails g migration AddSlugToArticles slug:string:uniq:index

# マイグレーションを適用
rails db:migrate
```

### 3.2 モデル実装

```ruby
# app/models/article.rb
require "romaji"

class Article < ApplicationRecord
  extend FriendlyId

  friendly_id :generate_slug, use: %i[slugged history]

  validates :slug, presence: true, uniqueness: true

  # タイトルが変わったら新しい slug を生成
  def should_generate_new_friendly_id?
    title_changed?
  end

  private

  # ひらがな・カタカナ → ローマ字化し、全体を parameterize
  def generate_slug
    Romaji.kana2romaji(title).parameterize
  end
end
```

### 3.3 ルーティング設定

```ruby
# config/routes.rb
resources :articles, param: :slug
```

`article_path(@article)` ➜ `/articles/hajimete-no-rails-gaido`

---

## 4. 実運用のための Tips

| 課題                | 解決策                                                                              |
| ----------------- | -------------------------------------------------------------------------------- |
| **同一タイトルの重複**     | `friendly_id` が `--2`, `--3` を自動付与して衝突回避                                         |
| **漢字混在タイトル**      | `Romaji.kana2romaji` でカナのみ変換→`parameterize`、または **手動 slug 入力欄 (slug\_base)** を用意 |
| **スラッグ変更による 404** | `use: %i[slugged history]` で旧 URL → 新 URL を 301 リダイレクト                           |
| **Sitemap 対応**    | sitemap.xml に slug ベース URL を出力し、Google Search Console へ送信                        |



## 5. ベストプラクティス

1. slug は **小文字 + ハイフン区切り** を徹底（SEO に有利）
2. タイトルが長すぎる場合は **slug を手動で短縮**
3. **自動生成 + 手動上書き** の二段構えにして運用を柔軟に（CMS 設計）
4. CI/CD に **slug 変更チェック** を組み込み、リダイレクト漏れをテスト



## 6. まとめ

* ローマ字スラッグは **共有性・国際化・SEO** を同時に向上させる王道手法
* Rails では `friendly_id` + `romaji` + 独自マイグレーションで簡単導入
* **漢字混在対策** と **URL 永続性（history）** を忘れずに、運用フローにテストを組み込む
Copilotカスタムインストラクションにオンボーディング情報を含める理由？

Copilot用のカスタムインストラクションを書いてChatGPTにレビューを求めたら、「新規参加開発者向けのオンボーディング要素を追加するとよい」という回答が返ってきました。「なんか勘違いしてない？」って質問したら、返ってきた回答が腑に落ちました。以下、そのまま貼り付けます。

----------------------------

## Copilotカスタムインストラクションにオンボーディング情報を含める理由

### 1. 誤解しやすい前提：

* **CopilotはAIペアプログラマ** = 常に新規参加エンジニアに近い状態
* プロジェクトの前提知識が無い状態で補完している

### 2. オンボーディング情報が役立つ場面

#### 2.1 用語・設計思想の統一

* 業界特有の特殊用語を理解
* 誤った汎用例の補完を防ぐ（例：海外法令の参照回避）

#### 2.2 コーディングスタイル定着

* 型ヒントの書き方、例外処理の標準、ディレクトリ構成の期待
* "過去のコード資産との一貫性" をAIが保持しやすくなる

#### 2.3 不要コードの抑制

* 不要な冗長処理や汎用エラーハンドリング提案を抑止
* 『このプロジェクトではYAGNI適用、不要な入力チェックは基本実装しない』等

#### 2.4 プロジェクト流儀の学習

* Clean Architecture推奨、Domain層責務の明確化、UIレイヤー分離方針
* サンプルの粒度：ドメイン層のUseCase例、Infrastructure層のService実装例 など

#### 2.5 アンチパターンの回避

* 『禁止している設計例』も共有可能
* 例：『Fat Service禁止』『全ての処理をUI層で持たせない』

### 3. 実はエンジニア経験に関係なく有効

* ベテランでも新規プロジェクトでは最初に全体像把握が必要
* AI補完が常に一定品質を保つには "プロジェクト知識の事前注入" が非常に有効

### 4. Copilotは "新規参加者モード" が基本動作

* 学習済みLLMは万能汎用知識だが、**個別プロジェクトの流儀は都度学習しない**
* カスタムインストラクションは事前知識注入の唯一の公式手段

### 5. まとめ

Copilotは「何も知らない新メンバー」に近い。だからこそ **オンボーディング情報がカスタムインストラクションに非常に有効**。熟練エンジニア相手とは逆の考え方で捉えるべき。

----------------------------

以上です。実はこれ以降も、カスタムインストラクションの話からいろいろ派生して、20本くらいのCanvasを生成してくれました。よりよいプロダクトに成長させるためのコツが満載で、出資者にアプローチする方法まで丁寧に伝授されました・・。
【Python初心者】ソートに使える組み込み関数の使い方まとめ

よく使うソートに関する組み込み関数の使い方をまとめました。
初学者の自分が学習中に整理した内容なので、同じく勉強中の方の参考になればと思います。

## sorted() の使い方

`sorted()` はイテラブルを昇順（または降順）に並べ替えて、新しいリストとして返してくれる関数です。

```python
numbers = [3, 1, 4, 1, 5]
result = sorted(numbers)
print(result)  # [1, 1, 3, 4, 5]
```

元のリストは変更されません。

```python
print(numbers)  # [3, 1, 4, 1, 5]
```

### reverse=True を使って降順にする

```python
sorted(numbers, reverse=True)  # [5, 4, 3, 1, 1]
```

## key 引数の使い方

`key` を使うと、ソートの基準を関数で指定できます。

```python
words = ["banana", "apple", "grape"]
sorted(words, key=len)  # ['apple', 'grape', 'banana']
```

`len` 関数を指定すると、文字列の長さでソートされます。

## operator モジュールと itemgetter

辞書のリストなどをソートしたいときは `operator.itemgetter()` を使うと便利です。

```python
from operator import itemgetter

fruits = [
    {"name": "apple", "price": 100},
    {"name": "banana", "price": 80},
    {"name": "grape", "price": 120}
]

sorted(fruits, key=itemgetter("price"))
```

実行結果：

```
[{'name': 'banana', 'price': 80}, {'name': 'apple', 'price': 100}, {'name': 'grape', 'price': 120}]
```

## reversed() の使い方

`reversed()` は元のイテラブルを逆順に並べた **イテレータ** を返します。

```python
numbers = [1, 2, 3]
rev = reversed(numbers)
print(list(rev))  # [3, 2, 1]
```

※ `reversed()` の戻り値はイテレータなので、`list()` で明示的にリスト化する必要があります。

## zip() の使い方

複数のイテラブルをまとめて、対応する要素をペアにして返します。

```python
names = ["apple", "banana", "grape"]
prices = [100, 80, 120]

for name, price in zip(names, prices):
    print(name, price)
```

実行結果：

```
apple 100
banana 80
grape 120
```

リストなどに変換して使うこともできます。

```python
list(zip(names, prices))  # [('apple', 100), ('banana', 80), ('grape', 120)]
```

## おわりに

今回の記事では `sorted()` や `zip()` など、Pythonでよく使われる基本関数やソートの書き方をまとめました。  
`key=` や `operator.itemgetter` は最初は戸惑いましたが、慣れてくると柔軟なデータ処理ができるようになってきました。
【Ruby初学者】RubyのHashクラスを学ぶ

# 【Ruby初学者】Hashクラスの基本まとめ（自分用メモ）

Rubyの `Hash` クラスについて、IRBで確認しながら学んだことを自分用にまとめたものです。
特に「これは何だっけ？」となりやすい `member?`, `to_a`, `update`, `clear` の挙動を確認していきます。

---

## `member?` でハッシュがキーをもつか判断できる

`Hash#member?` は `key?` や `has_key?` の別名。

```ruby
h = {a: 1, b: 2}
h.member?(:a)  # => true
h.member?(:z)  # => false
```

##  `to_a`でハッシュから配列を生成できる

`Hash#to_a`は、ハッシュを`[[:key, value], [:key, value]]`の形の配列に変換できる。
```ruby
h = {a: 1, b: 2}
h.to_a  # => [[:a, 1], [:b, 2]]
```
## `update`は破壊的メソッドである
`Hash#update`は`merge!`の別名で、元のハッシュを直接書き換える（破壊的）。
```ruby
h = {a: 1}
h.update({b: 2})  # => {:a=>1, :b=>2}
# h は変更されている
```

## `clear`の戻り値は空のハッシュ
`Hash#clear`はハッシュの中身をすべて消して、空のハッシュ {} を返します。
```ruby
h = {a: 1}
h.clear  # => {}
```

## まとめ

- `member?` でキーが存在するかチェックできる  
- `to_a` で配列に変換できる  
- `update` は破壊的（元のハッシュが書き換わる）  
- `clear` は中身を削除し、空のハッシュを返す  

Rubysilverの取得を目指してます。
がんばります。
Replitで遊んでみた（ポケモンバトル、kintoneER図生成＆JSカスタマイズツール）

# はじめに📝
こんにちわ、最近は生成AIやらガジェットにハマって1ヶ月で8万円溶かした、ノベルワークスのまとっち（[@matoi_thai](https://x.com/matoi_thai)）です。この前使ったReplitが非エンジニアの僕には扱いやすかったので、やったことをQiitaに残しておきます。

## こんな人に見てほしい👀
- 環境構築とかデプロイとかよく分からない非エンジニア
- コーディングせずに自然言語でアプリを作りたい人

## Replitとは🧠
Webブラウザ上でプログラムの作成・実行・共有ができるクラウド型の統合開発環境（IDE）です。Replitに搭載されているAIエージェントに自然言語で指示するだけで、WebアプリのUIからDB連携まで丸ごと自動構築してくれます。

https://replit.com/

# 作ったアプリ３つ
- ① ポケモンバトル⚔️
- ② kintone ER図生成ツール🧩
- ③ kintone JSカスタマイズツール⚙️

## ①ポケモンバトル⚔️
2時間足らずで完成しました。
### プロンプト
だいたいこんなプロンプトを入力しました。 ※他にも細かい追加プロンプトはしてます
```
通常のポケモンとは異なる動的なアニメーションで、３対３で乱戦するポケモンバトルを作って。
初代151匹のポケモンから３体選んだら、タイプ相性やステータスや運などで、勝敗が決まるようにして。
```

### アプリ作成時の画面
左から、ファイル構成、エージェントの処理ログ、画面プレビュー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713212/1a12feef-f5cc-4c66-a8fa-f3b835102548.png)

### 完成品
https://x.com/matoi_thai/status/1933918131640267161

## ②kintone ER図生成ツール🧩
4時間掛かったと思います。（ログイン情報でアプリ情報取得するところが手こずった）
### プロンプト
だいたいこんなプロンプトを入力しました。 ※他にも細かい追加プロンプトはしてます
```
kintoneにログインIDとパスワードで接続して、指定したアプリIDに紐付くアプリを全て洗い出して。
それらアプリのフィールド情報やリレーションを図示したER図を生成してくれるシステムを作りたいです。
```

### アプリ作成時の画面
左から、ファイル構成、エージェントの処理ログ、画面プレビュー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713212/1f7e9b54-ad2e-451f-b8d6-b29f86aa8bdc.png)

### 完成品
https://x.com/matoi_thai/status/1932039678976503864

## ③kintone JSカスタマイズツール⚙️
6時間以上は掛かった気がします。（Gemini APIキーの設定やらで手こずった）
### プロンプト
だいたいこんなプロンプトを入力しました。 ※他にも細かい追加プロンプトはしてます
```
入力したカスタマイズ要望に応じたJavaScriptを生成してくれるkintone開発支援ツールを作って。
アプリフィールド情報を取得して、生成AIでJavaScriptを作って、それをkintoneにデプロイしたい。
```

### アプリ作成時の画面
左から、ファイル構成、エージェントの処理ログ、画面プレビュー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713212/cdfc59a1-8ff4-4c18-9a22-44fd45d1aceb.png)

### 完成品
https://x.com/matoi_thai/status/1931643637181583619

# おわりに
非エンジニアが手軽なアプリ開発をするならReplitはオススメです。環境構築・画面UI・DB設計・デプロイといった難しいところを、自然言語でお願いするだけで良い感じにやってくれます。
AndroidでTaskerを使ってみる（LINE音声通知）

# はじめに
基本は以下に記載していますので、ここではそこからの差分で記載をしています。

https://qiita.com/archem/items/e930b3edc4b6f4e37338

## やりたいこと
LINE新規メッセージ着信時の自動読み上げです。
基本編では使用しなかった、以下を使用します。
- Notification Listener

# 設定編
## 概要
Notification ListenerにLINE新規メッセージの通知を拾わせ、それをイベントトリガとして定義済みの読み上げアクションを発動させる。

## 技術情報
Notification Listenerが通知を拾うと、以下の変数に値が代入されます。
- %nlapp アプリ名が代入されます（未使用・未確認）
- %nltitle LINEの場合、送信者が代入されます
- %nltext LINEの場合、本文が代入されます（未使用・未確認）


### 設定1 タスク作成(LINE読み上げアクション)
変数%nltitleに値（送信者名）が入ってくるので、それっぽく音声で読み上げさせます。アクションの試走をすれば、変数に値が入っていなくても読み上げてくれます。（テストできます）
出力先は通話音やシステム音などから選べますが、該当のボリューム/ミュート設定に影響を受けます。

~~~
【タスクタブ】
1. 新規作成 (+) (CREATE) >> タスク名「ACT_LINE読み上げ」
2. アクション追加 (+) >> アクションカテゴリ/待機(Wait) >> 2秒
3. アクション追加 (+) >> アクションカテゴリ/アラート >> 読み上げ(Say) 
4. アクション編集
　文字：%nltitle さんからのメッセージです。
　エンジン声質：default:default（もしくは jpn-jpn）
　出力先：通知音
　<設定完了>
~~~

### 設定2 プロファイル作成(Notification ListenerがLINE通知を検知するプロファイル)

~~~
【プロファイルタブ】
1. 新規作成 (+) (CREATE)
2. 発動条件/イベント >> プラグイン/Notification Listener >> Notification Listener 
3. Notification Listener設定
　Notification event：Posted
  Apps：jp.naver.line.android（右のアプリ一覧から選択）
　<設定完了>
4. プロファイルのアクション（矢印右側の欄を長押し）を作成済みの「ACT_LINE読み上げ」を指定
5. プロファイル名を長押し、プロファイル名を変更「LINE名前読み上げ実行」
6. 右端の有効/無効スイッチは、有効にする
~~~

### 設定完了後
画面右上のチェックマークを押して適用する。
適当な通知を待つか、以下のようなツールで通知を発生させても良いです。

https://reminekun.com/
springsecurity。javaconfig。urlとhttpヘッダーの値で、認識有り無しを分岐



---

## 1. URL だけでの認可分岐（通常の方法）

requestMatchers() は URL や HTTP メソッド（GET、POSTなど）に対するマッチング専用で、HTTP ヘッダーの値を直接見ることはできません。

例1
URLパターン
```java
http
    .authorizeHttpRequests(auth -> auth
    .requestMatchers("/public/**").permitAll()
    .requestMatchers("/admin/**").hasRole("ADMIN")
    .anyRequest().authenticated()
  );
```

例2

httpメソッドとURLパターン
```java
http
    .authorizeHttpRequests(auth -> auth
    .requestMatchers(HttpMethod.GET, "/api/public/**").permitAll()
    .requestMatchers("/admin/**").hasRole("ADMIN")
    .anyRequest().authenticated()
);
```

---

## 2. **HTTP ヘッダーの値で認可を分岐したい場合**

これは以下のように**カスタム `OncePerRequestFilter`** を使うことで実現可能です。

### 例：特定ヘッダー（例: `X-API-KEY`）の有無で認証をスキップまたは適用

#### ① カスタムフィルターの実装

```java
public class HeaderBasedAuthBypassFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain)
            throws ServletException, IOException {

        String path = request.getRequestURI();
        String apiKey = request.getHeader("X-API-KEY");

        if (path.startsWith("/external/") && "skip-auth".equals(apiKey)) {
            // 認可対象外にしたい場合
            SecurityContextHolder.clearContext();
        }

        filterChain.doFilter(request, response);
    }
}
```

#### ② SecurityFilterChain に登録

```java
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
        .addFilterBefore(new HeaderBasedAuthBypassFilter(), 
         UsernamePasswordAuthenticationFilter.class) // (1)
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/external/**").permitAll() // フィルターで認可制御
            .anyRequest().authenticated()
        );

    return http.build();
}
```

**// (1)**

addFilterBeforeは、第1引数に指定したフィルタークラスを第2引数に指定したフィルタークラスより前で動かします。

早い段階で全リクエストを捕まえたい（URL・ヘッダー分岐など）。	認証前（SecurityContextHolder も未初期化）
→ SecurityContextPersistenceFilter.class をaddFilterBeforeの第2引数指定

JWT の検証など、認証処理の前にチェックしたい。認証はされていないが、SecurityContext は初期化済み
→ UsernamePasswordAuthenticationFilter.class をaddFilterBeforeの第2引数指定

すでに認証が済んでいる前提で認可ロジックに関与したい
→ FilterSecurityInterceptor.class をaddFilterBeforeの第2引数指定

HTTP Basic 認証より前
→ BasicAuthenticationFilter.class をaddFilterBeforeの第2引数指定


---

## 3. より柔軟な条件分岐にしたい場合

* Spring Expression Language（SpEL）を `access()` に使う方法もありますが、ヘッダーには直接アクセスできません。
* よって、**カスタム `AuthorizationManager`** を使う方法もあります（より高度なケース）。

---

## まとめ

| 条件              | 方法                                         |
| --------------- | ------------------------------------------ |
| URL パターンで分岐     | `requestMatchers()` を使う                    |
| ヘッダーの値で分岐       | `OncePerRequestFilter` などのカスタムフィルターを挿入     |
| URL + ヘッダーの複合分岐 | カスタムフィルターで両方の条件を判定して、`SecurityContext` を調整 |

---
Jacksonでjson文字列生成

```java
package com.example.todo.api.todo;

import java.util.LinkedHashMap;
import java.util.Map;

import com.fasterxml.jackson.databind.ObjectMapper;

public class JsonUtil {

    public static String createErrorMessageJson(String messageId, String message) {
        try {
            Map<String, String> map = new LinkedHashMap<>();
            map.put("messageId", messageId);
            map.put("message", message);
            ObjectMapper mapper = new ObjectMapper();
            return mapper.writeValueAsString(map);
        } catch (Exception e) {
            throw new RuntimeException("JSON生成失敗", e);
        }
    }
}
```

```java
String json = JsonUtil.createErrorMessageJson("E002", "無効な入力です");
System.out.println(json);
```

実行例
```sh
{"messageId":"E002","message":"無効な入力です"}
```
extends keyofを使って汎用的なオブジェクト更新関数を作成する

## オブジェクトが入ったuseStateを更新したい

次のような型定義のオブジェクトがあったとする

```tsx
type UserProfile = {
  name: string;
  email: string;
  age: number;
};

const [profile, setProfile] = useState<UserProfile>({
  name: '',
  email: '',
  age: 0,
});
```

### 更新関数を愚直に書いていく

これでも動きはしますが重複コードが多いです。フィールドが増えるたびに関数が増えていくのでメンテナンスも面倒くさそう。

```tsx
// name用
const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  setProfile((prev) => ({ ...prev, name: e.target.value }));
};

// email用
const handleEmailChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  setProfile((prev) => ({ ...prev, email: e.target.value }));
};

// age用
const handleAgeChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  setProfile((prev) => ({ ...prev, age: Number(e.target.value) }));
};
```

### 共通の更新関数にまとめる

オブジェクト内のプロパティ名やプロパティの値の型が変更されたとしても、関数に変更は加えなくて良い保守性の高い関数になりました

```tsx
  const handleProfileChange = <K extends keyof UserProfile>(
    field: K,
    value: UserProfile[K],
  ) => {
    setBlackboard((prev) => ({
      ...prev,
      [field]: value,
    }));
  };

  // 使用例
  <input
    type="text"
    value={profile.name}
    onChange={(e) => handleProfileChange('name', e.target.value)}
  />
```

### 解説

- `extends keyof T`でオブジェクトのプロパティを型にしている。それに`extends` で部分型制約をつけている
- 型引数を使っているので、関数を使用するときに型を指定してやる必要がある。その指定する型に制約がついている
- 制約というのは、`UserProfile` オブジェクトのプロパティ名のいずれかでなければならないというもの
- オブジェクトのプロパティの型を取得することで、valueの型を定義することができる



### 参考
https://typescriptbook.jp/reference/type-reuse/keyof-type-operator

https://typescriptbook.jp/reference/generics/type-parameter-constraint#%E5%9E%8B%E5%BC%95%E6%95%B0%E3%81%AB%E5%88%B6%E7%B4%84%E3%82%92%E3%81%A4%E3%81%91%E3%82%8B
【Google Cloud】Associate Cloud Engineer認定試験合格体験記

## はじめに。
Google Cloud Associate Cloud Engineer（ACE）認定試験に合格いたしました。

![Associate Cloud Engineer Google Meets Background.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334980/8b3fcdfd-62f4-46a4-870c-1ba0945a8fe1.png)


本記事では、以下の4部構成で合格体験記を記載したいと思います。
- きっかけ
- 試験対策
- 当日の雰囲気
- 感想(受けてよかったか)

これから受験を検討されている方の参考となれば幸いです。

## 1. きっかけ。
### その前に自身の経験を紹介します。

普段の業務では、アプリケーションの開発を行うことがメインです。
実案件では、(ありがたいことに)多くのAWSサービスとアプリを連携することが多いです。
「各サービスの特徴を抑えている」、「アプリ接続や連携における実装をやっている」という温度感。
（実務で1から構築する等のほとんど経験がありません。遊びで触る程度。）

awsは比較的触るんですが、Google Cloudは全く知見がない状態でした。
個人開発でもほとんど、VercelやSupabase等を使ったり一部AWSを活用する(S3やDynamoDB)と行った感じ。

### きっかけ。
Google Cloudの認定試験に挑戦しようと思った理由はいくつかあるんですが...。
一番は「クラウドが全くわかんない人」と舐められたくないから。

アプリだけをやってる人、もしかしたら共感していただけるかもですが、「クラウドわかんない人」というレッテル貼られがちです（実際否定できない）。

あと、なんでAWSじゃなくてGCPなの？ってところですが。
「無知スタートでも僕の学習能力なら行けるだろ、これ取れなかったら、それまでなんだろうな」っていうのを試したかったから。

## 2. 試験対策。
僕、**学習のための学習**が一番嫌いです。
あまり知識欲があるタイプではないので、勉強という行為はあまり意味がないと思っています。
(ものづくりは好きです。)

なので、**最初の半分は概念理解の意味を込めて実践**、あとの**半分は机上学習**という風に進めました。

学習時間は正確に計測してないんですが...。
期間は1ヶ月弱、時間だと30~40hくらいです。GWあったので移動とかでCoursera聞いてました。

**実践(開発)** に時間をかけたので**試験対策**に限って言えば、振り返るとそこまでかけていないです。

机上学習は感覚で15h〜20hくらい。
### 実践。
- Terraform(GCP)チュートリアル
  (肩慣らし)
- Google Cloudのチュートリアル
- Google Cloud のコストを Discord Botと接続して日時で通知するサービス
	- Cloud Function
	- Cloud Scheduler
	- Cloud Builling
	- Big Query
- Vercel で利用しているアプリケーションをGoogle Cloudに移行
	- Cloud Run
	- Cloud Build
	- Artifact Resistory

そこまでやったこと多くないです。
Dockerfileとかの書き方など、今回の機会でちゃんと調べてデプロイまで行けたのはよかったかなぁと思っている所です。

### 机上学習。
1つ目はCourseraです。
[Preparing for Your Associate Cloud Engineer Journey 日本語版](https://www.coursera.org/learn/preparing-cloud-associate-cloud-engineer-exam-jp/)

英語で講座を聞いて練習問題を解く感じです(字幕あります)。
Service Accountの理解がとても深まりました。

GCPの概要を抑えるのにとってもおすすめです。

2つ目はUdemyです。
[これだけで合格！Google Cloud Associate Cloud Engineer模擬試験問題集（4回200問）](https://www.udemy.com/course/google-cloud-associate-cloud-engineer4200/?couponCode=LOCLZDOFFPJPCTRL)
本番の試験が50問です。僕が受けた講座は「50問 x4セット」あります。
「合格の秘訣は模擬試験周回！」といっても過言じゃないくらいこの講座に助けられました。

「50問 x4セット x 4週」くらいやった気がします。

## 3. 当日の雰囲気。
早朝(3時頃)にリモートで試験を受けました。

海外の企業の試験を受けるのが始めてではなかったのであまり戸惑わなかったんですが、はじめてだとちょっと緊張するかもです。
受験前に、PCのカメラで受験する環境の確認を行ったり、身分証明書の確認を行ったりと、ちょっとした山場が試験前にあります。

もちろん英語でのやり取りですが、試験監督者が翻訳アプリで上手いこと汲み取ってくれたので、比較的スムーズに試験を受けることができました。

問題についてはあまり言及はしませんが、模擬試験問題集をやり込んどいてよかったなぁと思いました。

また、「CLI操作」や「各サービスの間の連携はどうすればいいのか」、などは実践をやっといてよかったなぁと感じた所。

## 4. 感想(受けてよかったか)。
受けてよかったです！

本音は、試験勉強に時間を使うよりも、「作りたいアプリの開発」や「気になってる技術を試してみる」とか、いろいろやりたいことがある中でのGCP認定試験だったので、
合格するまでは、「ちょっとの寄り道だよな...。」とも思ってたところでした。

ただ、実務でも早速活きる場面が増えたり！
要件に対して、**アプリでどう実現しようか**、ではなく**システム全体としてどうする選択肢があるだろう**と考える場面がちょこちょこと増えました。

あとはなんだかんだ自信に繋がりました！
**しっかりと目標立てて成果を出せたのはよかったなぁ**と思っている所です。

## まとめ。
意外と現場で得られることって偏っていること多いなぁ、と感じました。

**ものによる**とは思いますが、「挑戦できたこと」・「成果を出せたこと」はよかったなぁと思っています。

## 最後に。
>「資格って意味あるの？」「現場の実務が全てじゃない？」という声を聞くが、受けてもない人が言うのは違う。

こんなニュアンスでどなたかが、記事を書かれてたのを拝見しました。
たしかにそうだなぁとも思い、今回自分も挑戦しようと思えるきっかけに繋がっています。

本記事がその方に届けばうれしいです。
【Project Euler】#012

https://qiita.com/umekikazuya/items/7062d91ddb8db112ef84

12問目です！

## 問題
三角数の列は自然数を加算して生成されます。したがって、第 7 番目の三角数は $1 + 2 + 3 + 4 + 5 + 6 + 7 = 28$ となります。最初の10個の項は以下の通りです:
$1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...$

最初の7つの三角数の約数を列挙してみましょう:

 $1: 1$
 $3: 1,3$
 $6: 1,2,3,6$
$10: 1,2,5,10$
$15: 1,3,5,15$
$21: 1,3,7,21$
$28: 1,2,4,7,14,28$

ここで、$28$ が初めて5個を超える約数を持つ三角数であることが分かります。
では、500個を超える約数を持つ最初の三角数の値はいくつでしょうか？

https://projecteuler.net/problem=12
## わたしの回答
```go
func solve() {
	x, y := 1, 0
	for {
		if 500 <= count(y) {
			break
		}
		y += x
		x++
	}
	fmt.Println(y)
}

// 約数をカウントする関数
func count(num int) int {
	if num == 1 {
		return 1
	}
	x := 2
	count := 1
	for x*x <= num {
		if num%x == 0 {
			if x*x == num {
				count++
			} else {
				count = count + 2
			}
		}
		x++
	}
	return count
}
```
1. 三角数をループで求め続ける。
2. 約数数を計算する。
3. 約数数が500以上の三角数が見つかったらループ終了。
といった感じです。

約数計算は...。
1. 2で割り切れたら、その対となる数字の分もカウント。
2. 3で割り切れたら、その対となる数字の分もカウント。
3. ...。
4. 平方根で割り切れたら、対は同じ数なのでカウントは1。

約数計算だけちょこっと工夫しました。

## GPT-4oの回答
```go
func countDivisors(n int) int {
	if n == 1 {
		return 1
	}

	count := 1
	num := n

	for i := 2; i <= int(math.Sqrt(float64(num))); i++ {
		exp := 0
		for num%i == 0 {
			exp++
			num /= i
		}
		if exp > 0 {
			count *= (exp + 1)
		}
	}
	if num > 1 {
		count *= 2
	}
	return count
}

// 最初に約数がlimitを超える三角数を探す
func findTriangleNumberWithDivisors(limit int) int {
	n := 1
	for {
		triangle := n * (n + 1) / 2

		// 三角数の約数数を効率よく求めるために、nと(n+1)の約数数を別に求める
		var divCount int
		if n%2 == 0 {
			divCount = countDivisors(n/2) * countDivisors(n+1)
		} else {
			divCount = countDivisors(n) * countDivisors((n+1)/2)
		}

		if divCount > limit {
			return triangle
		}
		n++
	}
}

func solve() {
	result := findTriangleNumberWithDivisors(500)
	fmt.Println("The first triangle number with over 500 divisors is:", result)
}
```
あー、そういうことか。
素因数分解する感じなんですね。
```go
for i := 2; i <= int(math.Sqrt(float64(num))); i++ {
    exp := 0
    for num%i == 0 {
        exp++
        num /= i
    }
    if exp > 0 {
        count *= (exp + 1)
    }
}
```

## Gemini2.5 Proの回答
```go
// 約数の数を計算する関数
func countDivisors(n int) int {
	count := 0
	sqrtN := int(math.Sqrt(float64(n)))
	for i := 1; i <= sqrtN; i++ {
		if n%i == 0 {
			count += 2
		}
	}
	if sqrtN*sqrtN == n {
		count--
	}
	return count
}

func solve() {
	num := 1
	triangleNumber := 0
	for {
		triangleNumber += num
		if countDivisors(triangleNumber) > 500 {
			fmt.Println(triangleNumber)
			break
		}
		num++
	}
}
```
平方根の求め方以外は、ほとんどわたしのロジックと流れが同じようですね。
## ベンチマーク

| 計測        | 実行回数 (b.N) | 平均実行時間 (ns/op)   |
| --------- | ---------- | ---------------- |
| わたしの回答    | 25         | 46,459,480 ns/op |
| GPT4.1    | 892        | 1,446,054 ns/op  |
| Gemini2.5 | 24         | 46,290,273 ns/op |

Geminiには僅差で勝ちました🦖
## 感想
GPTには素因数分解を見せつけられましたが、Geminiにはなんと勝てたのでよかったです。
今日から本気出す。

# まず、お前だれやねん？
もりもりおと言います。
最近30代になったばっかの若輩です←

職業はインフラエンジニア（弱々）。

現場業務では、官公庁向けシステムの現場で保守/構築をやっています。

# なんの本気？
資格取得。まずはLPIC L1・・・

# 今更、LPIC L1とか遅すぎやしないか・・・？
いや、まったくもってその通り。

学習グセが抜けやすい自分は、「今度こそ取るから！！」とか「もう後が無いから取らなきゃやばい・・・」とか言っておきながら、なんだかんだここまで来ちゃった人間でございます。。。

そんな自分を今回こそは変えるべく、ここQiitaに書き起こしている次第っす。（ニッコリ）

# んで、どんな計画でいくん？
「小さな目標から立てるのが良き丸」とか、色々聞いたけどそもそも計画表を更新するのがダルくなることが多々あったので、マクロマネジメント的な考え方でザックリ計画を切ることにしました。

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2990741/2e104abc-b909-4757-ba6c-468270b9603e.png)

ノリと勢いで決めた計画なので、もうこれで行きます。
・・・はい、前からちゃんと計画して勉強できていれば、こんな短期スケジュールを組む必要なんかなかったんや。。。。泣

# まさかL1学習だけじゃないよな？？？
9月から新しい会社に入るので、それまでにカッコがつくようにしたい・・・
今んところ、以下のように考えているっす。

    ■ 絶対取る奴（要は2025年8月までに取るやつ）
        ・LPIC L1
        ・AWS CLF
    ■ 取得は9月以降でもいいが、いつか必ず取るやつ
        ・LPIC L2
        ・AWS SAA

# まとめ
Qiitaで書くのも恥ずかしい内容にはなりましたが・・・
ここの場をアウトプットする場として活用したいと考えているっす。

まずは、L1とCLFに関するアウトプットを「質より量」の思考で投稿していく感じで考えています。

あとはできれば、実務で関わっているエアギャップ装置構築とかそれに伴うAnsibleとかのナレッジをガシガシ残していけたらいいな。。。

とりま、やろうな、おれ。
【Project Euler】#010


https://qiita.com/umekikazuya/items/7062d91ddb8db112ef84

10問目です！

## 問題
> The sum of the primes below $10$ is $2 + 3 + 5 + 7 = 17$.
> Find the sum of all the primes below two million.

2000000未満の素数の和を求める問題ですね。
素数問題多いですね。

https://projecteuler.net/problem=10
## わたしの回答
```go
func solve() {
	sum := 0
	for i := 2; i < 2000000; i++ {
		if isPrimeNumber(i) {
			sum += i
		}
	}
	fmt.Println(sum)
}

func isPrimeNumber(num int) bool {
	x := 2
	for x*x <= num {
		if num%x == 0 {
			return false
		}
		x++
	}
	return true
}

```

2~200000でループを回して、素数だったら変数`sum`を更新していく、というロジックです。

## GPT-4.1の回答
```go
func solve() {
	const limit = 2000000
	isPrime := make([]bool, limit)
	for i := 2; i < limit; i++ {
		isPrime[i] = true
	}

	for i := 2; i*i < limit; i++ {
		if isPrime[i] {
			for j := i * i; j < limit; j += i {
				isPrime[j] = false
			}
		}
	}

	sum := 0
	for i := 2; i < limit; i++ {
		if isPrime[i] {
			sum += i
		}
	}

	fmt.Println("Sum of all primes below 2 million:", sum)
}
```
ちょっと理解に苦しんだんですが、素数かどうかをふるいにかけていく感じのようです。

1. 最大制限値までの整数をキーにした素数かどうかを判定する連想配列を生成(デフォルトTRUE)
2. 連想配列をループさせる。
3. 素数フラグがTRUEであれば、その倍数の素数フラグを全部FALSEにする。
4. 連想配列を再度ループさせて、素数フラグがTRUEのものを加算していく。

理解できました。でも、2のループと4のループは処理まとめれると思います。

## Gemini2.5 Flashの回答
```go
func solve() {
	limit := 2000000
	isPrime := make([]bool, limit+1)

	for i := 0; i <= limit; i++ {
		isPrime[i] = true
	}

	isPrime[0] = false
	isPrime[1] = false

	for p := 2; p*p <= limit; p++ {
		if isPrime[p] == true {
			for i := p * p; i <= limit; i += p {
				isPrime[i] = false
			}
		}
	}

	var sum int64 = 0
	for i := 2; i <= limit; i++ {
		if isPrime[i] == true {
			sum += int64(i)
		}
	}

	fmt.Printf("200万以下の素数の合計は: %d\n", sum)
}
```
GPT4.1の解き方とほぼ同じですね。
## ベンチマーク

| 計測        | 実行回数 (b.N) | 平均実行時間 (ns/op)             |
| --------- | ---------- | -------------------------- |
| わたしの回答    | 9          | 118,894,889 ns/op（約119ミリ秒） |
| GPT4.1    | 322        | 3,493,777 ns/op（約3.49ミリ秒）  |
| Gemini2.5 | 321        | 3,505,954 ns/op（約3.51ミリ秒）  |

## 感想
GPTとGeminiに置いてけぼりにされました。
いくら平方根での計算だとしても、ふるいにかけたほうが速いのか...。