OmniAICreator/Qiita-1.07M huggingface dataset:
Bedrock Claude Night 2が超絶良かった件

6/18に開催された「Bedrock Claude Night 2（JAWS-UG AI/ML支部 × 東京支部コラボ）」に参加してきました。

https://jawsug-ai.connpass.com/event/319748/

AWS Summitがあったので少し遅くなりましたが、とても良いイベントでしたので紹介させてください。

## Anthropic キーノート

今回Anthropicの方が来日しリアル登壇してくれました。なんと通訳の方も現地にいて、 **re:Inventの基調講演さながら** の雰囲気で聴くことができました。
Maggieさんは日本に住んでいた時期があるとのことで、冒頭の挨拶を日本語でしてくれました。

Claude 3って何？というところは前回のBedrock Claude Nightで解説済みのため、マルチモーダルやツールにフォーカスしたディープな解説でした！

YouTube

https://www.youtube.com/live/Wultgk5ZdnA?feature=shared&t=353

資料

https://speakerdeck.com/minorun365/anthropickinoto-bedrock-claude-night-2


最後にデモビデオが3本流れましたが、ここは @Naoki_Ishihara さんの解説つきです。かなり複雑な動きをしているツールやエージェントですがわかりやすく解説してくださりました。

https://www.youtube.com/live/Wultgk5ZdnA?feature=shared&t=2585

## LT① Claude3 on Bedrock（with Converse API + Tool use）でチャットアプリを作成してみた

１つ目のLTは @ren8k さんです。

5月末に新しく登場したConverse APIとTool useの解説です。
概要の説明だけじゃなく、実装時のTIPSもあり、かなり興味深い発表でした。
（ちなみにJAWSの登壇が初めてとのことでしたが、説明が超お上手でした！！！）

YouTube

https://www.youtube.com/live/Wultgk5ZdnA?feature=shared&t=3254

資料

https://speakerdeck.com/ren8k/building-a-chat-app-using-claude3-on-bedrock-with-the-converse-api-plus-tool-use

## LT② AWS構成図からCloudFormationとパラメータシートを自動生成するシステムを作ってみた

２つ目のLTは [つくぼし](https://dev.classmethod.jp/author/tsukuboshi/)さんです。

「エンジニアの仕事をAIは奪えるのか？？」という疑問から検証を始めたとのことです。画像で与えたAWSの構成図からCloudFormationのテンプレートを生成できるか挑戦し、その過程で出たいろいろな工夫について説明いただきました。仕事を奪えるのかどうか、ぜひご確認ください。

Youtube

https://www.youtube.com/live/Wultgk5ZdnA?feature=shared&t=3887

資料

https://dev.classmethod.jp/articles/jaws-ug-aiml-bedrock-claude-night-2-lt/

## LT③ LangChain Agent with RetrieverをBedrock(Claude3 Opus)で実装してみる

３つ目のLTは @tubone さんです。LLM歴３ヶ月での発表とのことですが、なかなかディープな内容でした。
「いい感じに考え、行動するやつ」を実際に検討された際の課題と解決方法を解説していただきました。これも実際にやってみないとわからないのでとても勉強になりました。発表の途中に出てくるReActエージェントの図がスッと頭に入ってくる素敵なものでした。

YouTube

https://www.youtube.com/live/Wultgk5ZdnA?feature=shared&t=4384

資料

https://speakerdeck.com/tubone24/agenthale-siizo

## LT④ AWS BedrockでLLMOps / 評価をどう行うのか？

４つ目のLTは [r-kagaya](https://twitter.com/ry0_kaga) さんです。
LLMアプリは作ってるだけで楽しいので、なかなか「評価」についてはなかなか踏み込めてませんでしたが、オフライン評価やオンライン評価の基礎からわかりやすい解説でした。
Bedrockのモデル評価を実際に使った内容の解説もあり、まだ使ったことがない方にとても有用な情報だと思います。

YouTube

https://www.youtube.com/live/Wultgk5ZdnA?feature=shared&t=5015

資料

https://speakerdeck.com/rkaga/introduction-to-model-evaluation-with-amazon-bedrock

## インタラクティブセッション

最後はAnthropicのAlexさんに直接質問をするインタラクティブセッションです。「ロングホライズンタスク」というキーワードも出てきましたので、ぜひ動画を御覧ください。

動画
https://www.youtube.com/live/Wultgk5ZdnA?feature=shared&t=5779

## まとめ

すごかった。
何がすごいって、Anthripicの方の登壇がメインでLTはおまけかなと失礼ながら思ってた部分はあるのですが、どちらもすごかった、なんなら **LTが聞けてよかった** という感想です。　

AnthripicのAlexさんも、LTは最先端で素晴らしいものばかりだと感想を行っておられました。東京は開発者コミュニティが特に活発とのことでした。

私は現地参加でしたが、JAWS-UGのイベントはオンラインで参加できるものもあり、気軽に参加できるので気になる内容のものはフラッと参加してみてはいかがでしょうか？？

来月あたり、Bedrock Claude Nightの３回目があるようですので、一緒に参加しましょう！
ローカル環境でdocker buildしたときにcurlでエラーになった

# 何が起きたか
- buildができない環境にコンテナを立てるためにはローカルで一旦buildしてimageを持ち込む必要があった
- 今まではローカルPC上のDockerで`docker-compose up -d --build`しても特に問題なくできていた
- 以下コマンド実行したらエラーになった
- 実行コマンド
`docker build -t test .`
- 実行結果
`ERROR: failed to solve: process "/bin/sh -c apt-get`

# 原因
- ローカルPCはM2Macを使っているのでbuildのオプションでplatformを指定してあげる必要があった
- docker-compose.ymlでplatformを指定しているが、buildの場合はそこを見ない

# 解決
- 以下実行コマンドでできた。(ついでに--no-cacheも）
`docker build --no-cache --platform linux/x86_64　-t test .`
- M1以降のMacはarmということを忘れないようにしておこう
【React】useStateとuseEffectで画像スライドショー（フェード効果付き）を実装する方法

## 概要
この記事では、ReactのuseStateとuseEffectフックを使って、フェード効果付きの画像スライドショーを実装する方法を紹介します。


↓以下イメージ
![React画像フェードスライド.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817219/2b631da5-5111-023d-d1e6-6f92d22cb876.gif)

## 前提知識
この記事を理解するためには、以下の知識が必要です。

* Reactの基本的な使い方
* Reactのフック（useState, useEffect）の使い方

## 背景
画像スライドショーは、多くのウェブサイトで見かける一般的なUIコンポーネントですが、Reactを使って、簡単に実装することができます。
特にフェード効果を加えることで、視覚的に魅力的なコンポーネントを作成することができます。

## 学んだ技術の説明
### 技術の概要
ReactのuseStateフックは、関数コンポーネントで状態を管理するために使用されます。

useEffectフックは、副作用（データフェッチ、DOMの更新、タイマーの設定など）を実行するために使用されます。

この2つのフックを組み合わせることで、画像スライドショーの状態管理とタイマー設定を簡単に実装することができます。

### 基本的な使い方
以下に、画像スライドショーを実装するためのサンプルコードを示します。

```jsx
"use client";

// useStateとuseEffectをインポート
import React, { useState, useEffect } from "react";
// 画像を表示するためのImageをインポート（今回Next.jsプロジェクトのため）
import Image from "next/image";

export default function Home() {
  // 表示したい画像のパスを配列imagesに格納
  const images = ["/sample1.jpeg", "/sample2.jpeg"];

  // 表示する画像のindexをStateで管理(JSX内で使用)
  const [currentImageIndex, setCurrentImageIndex] = useState(0);

  // useEffectとsetIntervalを使用して、指定した秒数おきに、上記Stateで管理したindexを切り替えるようにする。
  useEffect(() => {
    // 4秒おきに画像を切り替える（現在のindex+1を画像の数で割ることでループする）
    const timer = setInterval(() => {
      setCurrentImageIndex((prevIndex) => (prevIndex + 1) % images.length);
    }, 4000);

    // ページを離れるときにインターバル処理を終了する（これがないとずっと裏でインターバルが動いてしまう。）
    return () => clearInterval(timer);
  });

  return (
    <div className="relative w-96 h-72">
      {/* 配列imagesをマップ関数で展開し、indexがcurrentImageIndexと一致した場合に、opacity-100となり画像が表示されるようにする。
          スタイル「absolte inset-0」によって、すべての画像が同じ位置に表示されるようになる。 
          スタイル「transition-opacityduration-1000」でopacityに対するフェードアニメーションを設定。（1秒かけて実行） */}
      {images.map((image: string, index: number) => (
        <div
          key={index}
          className={`absolute inset-0 transition-opacity duration-1000 ${
            index === currentImageIndex ? "opacity-100" : "opacity-0"
          }`}
        >
          <Image
            src={image}
            alt={`Slide ${index}`}
            width={400}
            height={300}
            objectFit="cover"
            className="border-4 border-black rounded-xl"
          />
        </div>
      ))}
    </div>
  );
}

```

## 問題点と解決方法
この実装で考えられる問題点とその解決方法をいくつか挙げます。

### 画像の読み込み時間

画像の読み込みが遅い場合、フェード効果がうまく機能しないことがあります。
next/imageコンポーネントは画像の事前読み込みをサポートしているため、これを活用すると良いでしょう。

### タイマーのメモリリーク

コンポーネントがアンマウントされたときにタイマーがクリアされないと、メモリリークが発生する可能性があります。
この問題はuseEffect内でclearIntervalを適切に使用することで解決します。


## まとめ
ReactのuseStateとuseEffectフックを使うことで、シンプルかつ効果的な画像スライドショーを実装することができました。

このようなコンポーネントは、ウェブサイトのデザインを向上させるための強力なツールとなります。

ぜひ、自分のプロジェクトに取り入れてみてください。

## 参考資料
https://ja.react.dev/reference/react
【プロダクトマネジメント】仕事での余白が良い成果を生み出す

## はじめに
仕事において、目の前のタスクに追われている状態、つまり「余白がない状態」は、多くの方が経験する問題だと思います。
そして、目指すべきゴールを見失い、本質的な課題から離れてしまうこともよくあるかと思います。

余白を持つことがどれだけ重要かを理解することができれば、プロダクトマネジメントにおいて良い成果を生み出す鍵になると思います。
そのため、この記事では、余白の重要性と、それを作るためにマネージャーができることについてまとめます。

## 余白がない状態の問題点
:::note alert
- **目の前の仕事に手がいっぱいになる**
- **本質的な課題から離れていく**
:::
余白がないと、目の前の仕事に追われ、ただ頼まれた仕事をこなすだけになってしまいます。
そのため、タスクを完了させること自体が目的となり、クリエイティブな思考や本質的な課題解決から遠ざかることになります。

そして、タスクに追われることで、長期的な視野を持つことが難しくなり、結果としてプロジェクトの根本的な課題解決が後回しになってしまいます。

## 余白が生み出す良い成果
:::note
- **本質的な課題に向き合う時間が生まれる**
- **新しい技術や別アプローチに挑戦できる**
:::

余白があることで、深く考える時間が確保され、本質的な課題に取り組むことができます。
この時間は、問題の根本原因を探り、最適な解決策を見つけるために重要です。

また、新しい技術や別のアプローチを試す機会にもなります。これにより、イノベーションが促進され、チーム全体のスキルアップにもつながります。

## 余白を作るためにマネージャーができること

### ⚪︎ 時間的な余裕を作る
仕事の余白を作るためには、プロジェクトのスケジュールに余裕を持たせることが重要です。
納期に追われる状況では、チームメンバーが焦りやストレスを感じやすくなります。
バッファを長めに設定することで、余裕を持って仕事に取り組むことができます。

### ⚪︎ 挑戦のヒントを与える
単に時間的な余裕を作るだけでは不十分です。
そのため、マネージャーは、メンバーに対して挑戦の機会やヒントを提供する必要があります。

具体的には、求めるレベルや挑戦してほしいことを共有し、成長のための目標を設定します。
これにより、メンバーは新しいスキルを習得する機会や成長の機会を得ることができます。

### ⚪︎ サポートできる準備をする
新しいことに挑戦する際には、一歩目を踏み出すのが難しいです。
そのため、マネージャーはサポートできるようにしておくことが重要です。
このサポートには、適切なフィードバックを行ったり、ドキュメントにまとめたりすることが含まれます。

## 副次的に得られること
:::note
- **売上アップや働きがいの向上**
- **業務スピードのアップ**
:::

余白での挑戦が成功すれば、売上のアップやメンバーの成長を実感することができます。
これは、メンバーの働きがいに直結し、チーム全体のモチベーションを高める要因となるでしょう。

また、余白があることで、業務を効率的に進めるために脳のリソースを割くこともできます。
これにより、結果として業務スピードがアップし、全体の生産性が向上します。

## まとめ
プロダクトマネジメントにおいて、余白を持つことは良い成果を生み出すために不可欠です。
マネージャーは、時間的な余裕を作り、挑戦のヒントを与え、サポート体制を整えることで、チーム全体のパフォーマンスを向上させることができます。

余白を活用して、目の前のタスクだけでなく、本質的な課題に取り組み、新しい技術やアプローチに挑戦することで、より良い成果を生み出していきましょう。

---

最後まで読んでくださってありがとうございます！

普段はデザインやフロントエンドを中心にQiitaで記事を投稿しているので、ぜひQiitaのフォローとX(Twitter)のフォローをお願いします。

https://twitter.com/degudegu2510
paiza.ioでc#

# 概要
paiza.ioでc#、やってみた。

# 練習問題やってみた。
３次元配列を使え。

# サンプルコード

```

using System;

namespace App
{
	class test0 {
		static void Main() {
			int[ , , ] array3D = new int[ , , ] {
				{ { 1, 2, 3 }, { 4,   5,  6 } },
				{ { 7, 8, 9 }, { 10, 11, 12 } }
			};
			for (int i = 0; i < array3D.GetLength(0); i++)
			{
				for (int j = 0; j < array3D.GetLength(1); j++)
				{
					for (int k = 0; k < array3D.GetLength(2); k++)
					{
						Console.Write(array3D[i, j, k]);
						Console.Write(" ");
					}
					Console.WriteLine();
				}
				Console.WriteLine();
			}
			Console.WriteLine("ok");
		}
	}
}


```

# 実行結果

```
1 2 3 
4 5 6 

7 8 9 
10 11 12 

ok
```

# 成果物

https://paiza.io/projects/PHzL2NGTKddi-Xab8kewoA

以上。
6GiBVRAMで4300万パラメータのモデルをバッチサイズ64で学習する

はじめは私も無理だろって思ってました。意味があるのかは知りません。
# そもそもバッチサイズ=1にして勾配を累積させればいいんじゃね？
駄目です。バッチサイズ=1でも余裕で`OOM`です。
# GradientCheckpointingを使う。
https://qiita.com/masashi-ai/items/df9b81908d7d7639b7fb

上の記事に「Transformerでやるなら、`gradient_checkpointing=True`と書いてやるだけでいい」っぽいことが書いてある。

え、生tensorflowでできないっすかねそれ。
[gradient-checkpointing](https://github.com/cybertronai/gradient-checkpointing)では、tensorflow1.xでの実装が書いてある。これを流用しようと思ったがダメだった。

自分で実装するしかないかぁ。
# 方針
Functionalモデルを使っているので、モデルを切り分けるのが少々面倒だが、切り分けてしまえばチェックポイントごとに逆伝播していけばいいだけなので、切り分けたものをchunksとしておいておく。
# 実装
```py
xs = ...
ys = ...

# 順伝播
chunkOuts = []
x = xs
for chunk in chunks[:-1]:
    chunkOuts.append(x)
    x = chunk(x)

# 変数初期化
total_grads = [tf.zeros_like(var) for var in model.trainable_variables]
# 逆伝播(一番上のレイヤーだけ損失関数を計算する。)
f = x
with tf.GradientTape(persistent=True) as tape:
    tape.watch(f)
    x = chunks[-1](x)
    x = tf.keras.losses.sparse_categorical_crossentropy(ys, x)
grads = tape.gradinet(x, model.trainable_variables, None, "zero")
next_grads = tape.gradient(x, f)
loss = tf.reduce_mean(x).numpy()
total_grads = [tg + g for tg, g in zip(total_grads, grads)]

# 逆伝播(残りのレイヤー)
for i, chunk in enumerate(reversed(chunks[:-1])):
    f = chunkOuts[~i]
    with tf.GradientTape(persistent=True) as tape:
        tape.watch(f)
        x = chunk(f)
    grads = tape.gradient(x, model.trainable_variables, next_grads)
    next_grads = tape.gradient(x, f, next_grads)
    total_grads = [tg + g for tg, g in zip(total_grads, grads)]

optimizer.apply_gradients(zip(total_grads, models["trainer"].trainable_variables))
print(loss)
```
こんな感じで実装できた。
# まとめ
- gradient-checkpointingをtensorflowでするのは案外簡単
- tapeは`persistent=True`にしないと2回以上勾配を計算できないのに躓いた
Apex Web Services

[まとめページに戻る](https://qiita.com/Keiji_otsubo/items/60afc2a8d211b6f7d89f)
[まとめA～M](https://qiita.com/Keiji_otsubo/items/f3ddedee6793bf1576f8)


# Executing the method 'getAccount' from the Apex class 'AccountManager' failed. Either the service isn't configured with the correct urlMapping, is not global, does not have the proper method name or does not return the requested account and all of its contacts.

+ [Apex Web Services](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000G6aVCSAZ)
+ [Apex Web Services](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007CumWs)
+ [I am getting below error while i try to complete the Apex web services .can anyone help on this](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007FUdFR)

:::note
The point is on your urlMapping, 'Contacts' should start with lower case in all classes. Please check it, should work. 

重要なのは、urlMapping にあり、「連絡先」はすべてのクラスで小文字で始まる必要があります。チェックしてください。動作するはずです。
:::

+ [Apex Web Service Challenge](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007MZs9R)

:::note
Try changing the first T to lower case.

Test Account --> test Account

Account objAccount = new Account(Name = 'test Account');
Account accountTest = new Account(Name='Test Account');

https://developer.salesforce.com/forums/?id=9060G000000MPHzQAO
:::


# Error:Executing the method 'getAccount' from the Apex class 'AccountManager' failed. Either the service isn't configured with the correct urlMapping, is not global, does not have the proper method name or does not return the requested account and all of its contacts.  

+ [Apex Web Services Hands on Challenge](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007T5vyp)

:::note
重要なのは、urlMapping にあり、「連絡先」はすべてのクラスで小文字で始まる必要があります。チェックしてください。動作するはずです。

The point is on your urlMapping, 'Contacts' should start with lower case in all classes. Please check it, should work.

https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007FUdFR

https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007MZs9R
:::

+ [Apex Web Services - Challenge not yet complete](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007cm9aH)

コード有

# よく分からん

+ [Executing the method 'getAccount' from the Apex class 'AccountManager' failed.](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000MaAWG)
PythonでJSON形式のデータを読み取る

# 目的
PythonでJSON形式のデータを読み取る処理の一例を記す。

# 読み取るJSONデータ
``` .json
{
	"lunches" : [
		{
			"drink": "Green Tea",
			"dessert": "Vanilla Icecream",
			"foods": [
				{
					"name": "Rice",
					"item": []
				},
				{
					"name" : "Curry",
					"item" : ["Chiken", "Onion", "Carrot"]
				},
				{
					"name": "Omelette",
					"item": ["Egg", "Butter", "Cheese"]
				}
			]
		},
		{
			"drink": "Ice Coffee",
			"dessert": "Chocolate Cake",
			"foods": [
				{
					"name": "Bread",
					"item": []
				},
				{
					"name": "Bamburger",
					"item": ["Beef", "Onion", "Egg"]
				},
				{
					"name": "Salad",
					"item": ["Lettuce", "Cucumber", "Tomato"]
				}
			]
		}
	]
}
```

# 実行結果
```
-----    
Green Tea
Vanilla Icecream
Rice
Curry
  Chiken        
  Onion
  Carrot        
Omelette        
  Egg
  Butter        
  Cheese        
-----
Ice Coffee      
Chocolate Cake  
Bread
Bamburger
  Beef
  Onion
  Egg
Salad
  Lettuce
  Cucumber
  Tomato
```

# 処理するPythonソースコード
``` .py
import sys
import json
import collections

def main(args):
	menu_file = args[1]
	menu = getMenu(menu_file)


def getMenu(menu_file=''):
	'''
	ファイル名を受け取りJSONオブジェクトを返す
	エラー発生時はNone返す

	Parameters
	----------
	menu_file : string
		メニューファイル名
	Returns
	-------
	menu : Any
		メニュー
	'''
	try:
		with open(menu_file, 'r') as food:
			try:
				decoder = json.JSONDecoder(object_pairs_hook=collections.OrderedDict)
				menu = decoder.decode(food.read())
			except json.JSONDecodeError as e:
				print('catch error : ', e)
	except FileNotFoundError as e:
		print('catch error : ', e)
	except IOError as e:
		print('catch error : ', e)

	try:
		for lunch in menu['lunches']:
			print('-----')
			print(lunch['drink'])
			print(lunch['dessert'])
			for food in lunch['foods']:
				print(food['name'])
				for food_item in food['item']:
					print(' ', food_item)
	except KeyError as e:
		menu = None
		print('catch error : ', e)
	except TypeError as e:
		menu = None
		print('catch error : ', e)

	return menu

if __name__ == "__main__":
	main(sys.argv)
```
Pythonで配列の前項と現項の処理の間違えにくい書き方

配列の要素を順に処理する場合で、前の要素と今の要素を比較して処理することがある。その場合、以下のように書いていた。
```python
a = [1, 2, 2, 3, 4]
prev = a[0]
for cur in a[1:]:
    if prev == cur:
        print('same', prev, cur)
    prev = cur
```
しかし、この`prev = cur`をよく書き忘れる。内部の処理が長くなったり編集したりすると間違って削除してしまっても気づきにくい。

というわけで今は以下のような書き方をしている。
```python
a = [1, 2, 2, 3, 4]
for prev, cur in zip(a[:-1], a[1:]):
    if prev == cur:
        print('same', prev, cur)
```
これなら`prev = cur`を書き忘れないし、２行短い^^/
Average Precisionとは？（初心者向け）

# 1. 一言で表すと？
偽陽性と偽陰性の両方をどれだけ抑えられたか評価する指標

以降、Average PrecisionをAPと呼びます。

# 2. 何に使われる？
異常検知・発病リスク予測など、正例が極端に少ない予測を行うモデルの評価に役立ちます。

### 2.1 ちなみに他の評価指標は？
最も単純なものの一つとしてAccuracy（正答率）を挙げます。学校の試験の点数と一緒で、予測データのうち教師データと合致している割合を計算します。正例と負例のバランスが良いデータなら評価指標として機能します。

### 2.2 APとAccuracyとの比較
Accuracyは正例と負例の分布が片方に偏っていると機能しません。例えば異常検知タスクの場合、ほとんどのデータが負例と分かりきっています（＝故障は頻繁に起こらない）。予測なんてせずに当てずっぽうで全部負例にしてもそこそこ当たるでしょう。
きちんと学習したモデルと当てずっぽうで予測したモデルとの差がつかないので、評価指標として機能していません。

# 3. APの定義をきちんと理解する
まずPrecision, Recall, Precision-Recall曲線を理解します。
### 3.1 Precision
・定義：正と予測したもののうち、実際に正だった割合
・計算式：

![スクリーンショット 2024-06-21 20.44.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820324/cf9135af-d7f3-7772-3b89-8467cd731f1b.png)
・つまり
これが高い＝偽陽性が少ない

### 3.2 Recall
・定義：実際に正であるもののうち、正と予測できた割合
・計算式：
![スクリーンショット 2024-06-21 20.50.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820324/08d99ceb-73c4-4b07-0d2c-24c3633189e0.png)
・つまり
これが高い＝偽陰性が少ない

### 3.3 Precision-Recall(PR)曲線
偽陽性を減らしたいなら多めに陰性と判断すればよいですし、偽陰性を減らしたいなら多めに陽性と判断すればよいです。つまりPrecisionとRecallはトレードオフの関係にあります。
PR曲線を使うとPrecisionとRecallの関係を表すことができます。
例えば発病予測タスクで、発病予測データと正解データがあるとします。
![スクリーンショット 2024-06-21 21.25.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820324/562db790-9d14-ba23-224c-bff5fa78edc8.png)

もし確率が0.9以上の場合に正例として検知するなら、PとRはそれぞれ下記の通りです。

![スクリーンショット 2024-06-22 9.29.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820324/e2bfb690-fd8d-2562-aebe-dd4261e58269.png)

この0.9を閾値と呼びます。
閾値を変えていくと、サンプル6つに対してPとRの組み合わせが合計6通り求められます。

・閾値0.8
![スクリーンショット 2024-06-22 9.32.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820324/17bdb06a-6a53-910c-04a2-c5151b0c203c.png)

・閾値0.75
![スクリーンショット 2024-06-22 9.32.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820324/dab0fcd8-a0dd-97ad-a8da-b09125a6b382.png)

・閾値0.60
![スクリーンショット 2024-06-22 9.33.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820324/f6b8f24c-1ccd-9f47-71b3-b236236c1d2c.png)

・閾値0.55
![スクリーンショット 2024-06-22 9.33.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820324/e0864622-ba51-3819-2389-4ce5e0cf5504.png)

・閾値0.40
![スクリーンショット 2024-06-22 9.34.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820324/c90af9c7-4268-6350-3d7c-4cca05d78035.png)

上記PとRの組み合わせを二次元平面にプロットしたものがPrecision-Recall曲線です。

![スクリーンショット 2024-06-21 21.22.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3820324/77f086b2-83d5-a877-5023-8bed01032811.png)

# 4. じゃあAPの正体は？
PR曲線の下側の面積(AUC:Area Under the Curve)です。
### 4.1 APが最大
正例と負例を寸分の狂いなく当てているパターン。負例のものを全て確率0、正例のものを全て確率1と予測したことになります。このとき偽陽性=偽陰性=0個です。全てのプロットがP=1かR=1上に存在することになり、AUCは最大値=1になります。

### 4.2 APが0.5
予測結果に偽陽性or偽陰性合わせて50%含まれているパターン。一般的にモデルが当てずっぽうに予測しているとAPは0.5となります。

# 終わりに
間違いがあれば教えてください！
Windows 11 on ARMにDocker Desktopをインストール

Snapdragon X Eliteを搭載したLenovo Yoga Slim 7x Gen 9にDocker Desktopをインストールしてみました。他のSnapdragon X Eliteを搭載したCopilot+ PCでも大きな違いはないかと思います。

# インストール
1. 現時点ではDocker DesktopのWindows版を普通にダウンロードするとx64版がダウンロードされてしまいます。
![スクリーンショット 2024-06-21 190355.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/84287cda-3a57-d61e-5d84-90019305dcd8.png)

1. リリースノート(Docker Desktop release notes)のページ(https://docs.docker.com/desktop/release-notes/ )からWindows ARM Beta版のDocker Desktopのインストーラー(`Docker Desktop Installer.exe`)をダウンロードします。
![スクリーンショット 2024-06-21 190455.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/b2452b1e-4fa6-0aef-ed38-481f74c53c7d.png)

1. ダウンロードの際、「ダウンロードできませんでした - ウイルス スキャンに失敗しました」と表示される場合、「マカフィーが提供するウェブアドバイザー」をアンインストールする。マカフィー(McAfee)はアンインストールしていても、(ライセンス費用不要な)ウェブアドバイザーが残っている場合があるので、アンインストールしておく。
![スクリーンショット 2024-06-22 073038.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/7884987f-9a46-764c-feaf-0ae3d737a0a8.png)

1. ダウンロードできたのを確認して、インストーラーを起動する。インストールが完了すると、Windowsの再起動を要求されるので、再起動するようにする。
1. Windowsの再起動後、Docker Desktopが自動起動する。起動時に、「クラスが登録されていません」(Wsl/CallMsi/Install/REGDB_E_CLASSNOTREG)が表示されて、Docker Desktopが起動できない場合(WSL update failed)、[Windows 11 on ARMにWSL2をインストール](https://qiita.com/mfunaki/items/615e4bd5b356230164c1)を参考にして、WSL2をインストールした後、(Windowsの再起動後)Docker Desktopが問題なく起動することを確認する。
![スクリーンショット 2024-06-22 073930.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/e2a677dc-73c8-319f-c66e-4ff34544552e.png)

# 動作確認
1. コマンドプロンプトから`docker run -d -p 8080:80 docker/welcome-to-docker`を実行し、ブラウザ上で http://localhost:8080/ にアクセスし、Congraturations! 画面が表示されることを確認する。
1. 
# リンク
- [Windows 11 24H2 on ARM での環境構築・動作検証](https://qiita.com/mfunaki/items/6ee512eaefafec562754)
- [Windows 11 on ARMにWSL2をインストール](https://qiita.com/mfunaki/items/615e4bd5b356230164c1)
Pythonでの開発で使用しているVSCode拡張機能

## はじめに
Pythonを使ってVSCodeで開発を始めてから数カ月のPython初心者です。
数か月の中で、VSCodeのPythonに関連する拡張機能を様々使ってみて、タイプミスに気付きやすくなったり、効率化が出来るなどの拡張機能もあり、開発が非常に進めやすくなりました。
本記事では「これからVSCodeにてPythonで開発をしたいと思っている方」を対象として、よりPythonで開発が進めやすくなるVSCodeの拡張機能を紹介します。



**開発環境**
・WSL2/Ubuntu環境
・Python: 3.10.12

※WSL2/Ubuntu環境で以下codeコマンドを実行することで、VSCodeを起動しています。

```
code .
```

## Pythonでの開発で使用しているVSCode拡張機能

### Japanese Language Pack for Visual Studio Code
VSCodeで「メニュー」・「設定」などを日本語表示できる拡張機能です。

https://marketplace.visualstudio.com/items?itemName=MS-CEINTL.vscode-language-pack-ja

### Python・Pylance
「Python」をインストールすると、「Pylance」もインストールされます。
インデントミスや文法ミスなどをチェックし、ミスがあれば「エラー」や「警告」として画面上に表示するなどの機能を持ち、Pythonの開発をサポートする拡張機能です。

https://marketplace.visualstudio.com/items?itemName=ms-python.python

https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance

### Error Lens
「Pylance」などのツールで検出した「エラー」や「警告」をコード上に表示する拡張機能です。コード上で確認できるので、視覚的にわかりやすい利点があります。

https://marketplace.visualstudio.com/items?itemName=usernamehw.errorlens

### Python Extension Pack
複数のPython拡張機能を含んだ拡張機能です。
後述する「Black Formatter」と「Flake8」は本拡張機能に依存しています。

https://marketplace.visualstudio.com/items?itemName=donjayamanne.python-extension-pack

### Black Formatter
Pythonのコードフォーマッタ「Black」の拡張機能です。
この拡張機能を使用するまでは、コマンドライン上でblackコマンドを実行し、手動でフォーマットしていましたが、本拡張機能を使用することで「ファイルを保存した時にBlackを自動で実行する」ことができるようになり、非常に便利です。

https://marketplace.visualstudio.com/items?itemName=ms-python.black-formatter

### Flake8
PythonのLinter「Flake8」の拡張機能です。
「Black」と同様に、これまでコマンドラインでflake8コマンドを実行していましたが、本拡張機能を使用することで、Flake8の実行をVSCode上で行うため、開発が効率的になりました。

https://marketplace.visualstudio.com/items?itemName=ms-python.flake8

### 参考）settings.jsonの設定
「Flake8」と「Black Formatter」についての設定を以下「settings.json」に記載します。
```settings.json:
{
    "flake8.args": [
        "--max-line-length=88"
    ],
    "[python]": {
        "editor.defaultFormatter": "ms-python.black-formatter",
        "editor.formatOnSave": true
    }
}

```

## おわりに
本記事では、よりPythonで開発が進めやすくなるVSCodeの拡張機能を紹介しました。
本記事の内容が少しでも何かの役に立てば幸いです。

## 参考文献
本記事は以下情報を参考にして執筆しました。

https://qiita.com/momotar47279337/items/73157407ae824751afc4

https://qiita.com/nujust/items/e0985240fd461e5c4c0a

https://qiita.com/keitean/items/341ec1bff790a420cf84
【個人開発_#2】Next.jsをDockerで動かしてみた #2

https://qiita.com/okalog/items/f144123bb7c0cbe0ff89

前回は、開発するための身の周りの準備を行いました。
今回は、ずっと逃げてきたDockerを導入してみようと思います。

Web制作からキャリアをスタートした僕にはDockerとはかけ離れたところにおり、「コンテナね✌️」という軽いノリできたけど流石にもう少し理解をせねばと思い個人開発でも導入することを決めました。

## Dockerとは？
Dockerは、アプリケーションをコンテナとしてパッケージ化するオープンプラットフォームです。コンテナは、アプリケーションのコードとその依存関係を含む軽量な仮想環境であり、どこでも一貫した動作を保証します。

## Dockerの利点
- 一貫性：開発環境と本番環境の差異をなくし、一貫した動作を保証します。
- ポータビリティ：異なる環境間でアプリケーションを簡単に移行できます。
- 依存関係の管理：各コンテナは独立しており、依存関係の衝突を防ぎます。

## Dockerfileの作成
まず、プロジェクトのルートディレクトリに`Dockerfile`を作成します。このファイルには、コンテナのベースイメージや必要なコマンドを記述します。

```Dockerfile
# ベースイメージを指定
FROM node:18.17.0-alpine

# 作業ディレクトリを設定
WORKDIR /app

# pnpmをインストール
RUN npm install -g pnpm

# package.jsonをコピー
COPY ./package.json ./

# 依存関係をインストール
RUN pnpm install

# 開発サーバーを起動
CMD ["pnpm", "dev"]
```
この`Dockerfile`では、`Node.js 18.17.0`のAlpineイメージを使用し、`pnpm`をグローバルインストールしています。その後、依存関係をインストールし、開発サーバーを起動するよう設定しています。

## 4. docker-compose.ymlの作成
次に、`docker-compose.yml`を作成します。これにより、複数のコンテナを一括して管理できます。
```docker-compose.yml
version: '3.7'
services:
  app:
    build: .
    ports:
      - '3000:3000'
    volumes:
      - .:/app
    command: pnpm dev
```
このファイルでは、appサービスを定義し、コンテナをビルドしてポート3000でホストします。また、ホストのディレクトリをコンテナ内の/appにマウントし、開発サーバーを起動します。

## Dockerコンテナのビルドと起動
`Dockerfile`と`docker-compose.yml`を設定したら、以下のコマンドでコンテナをビルドし、起動します。
```bash
docker-compose build
docker-compose up
```
これで、Next.jsの開発サーバーがDockerコンテナ内で起動します。ブラウザで`http://localhost:3000`にアクセスすると、アプリケーションが表示されるはずです。

## まとめ
今回は、Next.jsプロジェクトにDockerを導入し、開発環境をコンテナ化する方法を紹介しました。
まだまだ理解度は低いですが、多分ネットワークとかその辺の勉強せんと理解できん気がするので本でも読もうと思います。

気づいたらこちらのUdemyをポチっていました。
また別の記事でまとめます。

https://www.udemy.com/course/docker-from-linux-and-networking/?couponCode=JPOF62224

最後に今回のDockerを追加したPRになります。

https://github.com/takahiro-okada/nextjs-jocv/pull/4
Pendulum使って簡単日時実装②

# Pendulumとは
日時の操作を容易にするPythonパッケージ
https://pendulum.eustace.io/

# 前回
[Pendulum使って簡単日時実装①](https://qiita.com/i-am-misaki/items/2ad110049ee541c4c3ee)

# format()
localeで設定した言語に変換され表示される
(デフォルトは英語)

```python
import pendulum

dt = pendulum.datetime(1975, 5, 21)
dt.format('dddd DD MMMM YYYY')
# 'Wednesday 21 May 1975'

dt.format('dddd DD MMMM YYYY', locale='de')
# 'Mittwoch 21 Mai 1975'
```

# diff_for_humans()
デフォルトは英語なのでpendulum.set_locale()を使用して言語を設定

```python
print(pendulum.now().add(years=1).diff_for_humans())
# in 1 year

pendulum.set_locale('ja')
print(pendulum.now().add(years=1).diff_for_humans())
# 1 年後
```
上記のコードだとローカルが変わってしまう。
###### ローカル変更を避けるための記述法
```python
dt = pendulum.now().add(years=1)
dt.diff_for_humans(locale='fr')
# 'dans 1 an'
# localはjaのまま
```

# 最後に
認識間違っていればご指摘お願い致します。
【エラー解消メモ】Try this:   Kill the process running on port 1717 or use a custom connected app and update OauthLocalPort in the sfdx-project.json file.

#  結論
PC再起動で解決
※もっとスマートな方法が他にあるかも知れないですが、私はこれで解決しました😅

#  発生した事象
:::note info
多要素認証(MFA)設定済みの組織
:::

VS CodeでSalesforceの開発を始めるため
下記手順を実際して組織の認証を行おうとした。
1. SFDX: 組織を認証 (Authorize an Org)を実行  
1. 組織の種別の選択  
1. ブラウザにてログイン画面が起動  
1. ユーザーID・パスワードを入力
1. 多要素認証画面の表示
1. Authenticatorに表示されるワンタイムパスワードを入力
1. 組織の認証完了

しかし、3.の手順で多要素認証除外ユーザーを使用して組織の認証するつもりだったが、誤って多要素認証必須ユーザーのユーザーID・パスワードを入力してしまった。
5.の画面でキャンセルボタンや戻るボタンなどが見つからなかったため、そのままブラウザを閉じて1.の手順から組織の認証を本来使用したかったユーザーで行おうとしたところ本件のエラーが発生した。
DBeaverでCSVをインポートしようとしたら外部キー制約に阻まれた時に見てほしい

# こんな状況になった人向けの記事
- DBeaverで外部キー制約のあるテーブルへCSVをインポートしようとして失敗した人
- CSVの値自体は外部キー制約に違反していないのになぜかエラーになる
- SQLを書いて値の挿入は問題なくできる

# 可能性のある原因
**NULLとしてインポートしたいカラムが空文字としてインポートされようとしている。** 親テーブルに空文字は無いため、外部キー制約違反となっているのかも。

# 解決方法
CSVのインポート設定で「Set empty strings to NULL」にチェックを入れてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579871/6298ee42-fa92-a652-98b8-c0e7a14c6aaa.png)

# お詫び
あくまで本記事は解決方法の1案を示すものです。他の原因であることも十分考えられますのでその点はお許しください。
cscの作法 その511

# 概要
cscの作法、調べてみた。
練習問題やってみた。

# 練習問題
３次元配列を使え。

# サンプルコード

```

using System;

namespace App
{
	class test0 {
		static void Main() {
			int[ , , ] array3D = new int[ , , ] {
				{ { 1, 2, 3 }, { 4,   5,  6 } },
				{ { 7, 8, 9 }, { 10, 11, 12 } }
			};
			for (int i = 0; i < array3D.GetLength(0); i++)
			{
				for (int j = 0; j < array3D.GetLength(1); j++)
				{
					for (int k = 0; k < array3D.GetLength(2); k++)
					{
						Console.Write(array3D[i, j, k]);
						Console.Write(" ");
					}
					Console.WriteLine();
				}
				Console.WriteLine();
			}
			Console.WriteLine("ok");
		}
	}
}

```

# 実行結果

```

>a3
1 2 3
4 5 6

7 8 9
10 11 12

ok

```


以上。
nushellでリダイレクト

bashやcmd.exeだと
```
$ pip freeze > modules.txt
```
とできるんだけどnushellだと`>`がない
パイプとsaveをつかうとできる
```
> pip freeze| save modules.txt
```

もともとは`pip uninstall -y -r <(pip freeze)`したかったんだけど、結局こうするしかなさそう
```
> pip freeze | save modules.txt
> pip uninstall -y -r modules.txt
> rm modules.txt
```
一行でできないものでしょうか
issueにPRを貼る時のちょっとしたtips


以下のように issue に PR のリンクを貼ることがあるかと思いますが、
![スクリーンショット 2024-06-21 10.12.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518928/2bb05387-93d3-b8df-c69a-ddb2643c3036.png)

編集時にプルリクのリンクの頭にハイフンをつけると、
プルリクのタイトルが表示され、マージ状態も分かるようになります！
![スクリーンショット 2024-06-21 10.15.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518928/ca31d082-301f-e5a5-9a30-251b6ff9a19d.png)
↓
![スクリーンショット 2024-06-22 6.55.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518928/fdfba2d7-cfd4-fb34-2c90-0462c554af14.png)

PR がマージ済みの場合はこちら。
![スクリーンショット 2024-06-22 7.02.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518928/51c94bf9-9b2c-c13a-c567-54e3fc0d5494.png)

これをやるとぱっと見で、PR の状態が分かるので便利です。

逆に PR に issue のリンクを貼る時も同様で、リンクの頭にハイフンをつけると、
issue が open なのか close なのかすぐ分かります。

![スクリーンショット 2024-06-22 6.59.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518928/11e94f9b-2698-d924-6b5a-6f5d2611bc38.png)
LeetCode挑戦日記：Day15

# はじめに

最近、業務で実装する時間よりも資料作成やレビューをする時間が多くなってきました。
このままでは自身のコーディング能力が落ちそうで怖いので、LeetCodeを始めてみました。

自身の学習の記録 & LeetCodeに興味のある人が挑戦しやすいように、記事に残していきます。
このような競技プログラミングをした経験がないので、ひよってEasyからやっていきます...

# [Medium] 1456. Maximum Number of Vowels in a Substring of Given Length

文字列`s`と整数`k`が与えられたとき、長さが`k`の任意の部分文字列に含まれる母音の最大数を返してください。

英語の母音は `'a'`, `'e'`, `'i'`, `'o'`, `'u'` です。

## 素直に解いてみる

### 考え方

以下の記事と同様の考え方

https://qiita.com/tkmsk/items/c7693e800b165974bb0a

### コーディング

```typescript
function maxVowels(s: string, k: number): number {
    const isVowels = (s: string) => { return (s === 'a') || (s === 'e') || (s === 'i') || (s === 'o') || (s === 'u'); }

    let counter = 0;
    let max = 0;

    let rightIndex = k - 1;
    let vowelsCount = 0;
    for (let i = 0; i <= rightIndex; i++) {
        if (isVowels(s.charAt(i))) { max++; }
    }

    vowelsCount = (isVowels(s.charAt(0))) ? max - 1 : max;
    rightIndex++;

    while (rightIndex < s.length) {
        if (isVowels(s.charAt(rightIndex))) {
            vowelsCount++;
        }
        if (max < vowelsCount) {
            max = vowelsCount;
        }
        if (isVowels(s.charAt(rightIndex - k + 1))) {
            vowelsCount--;
        }
        rightIndex++;
    }

    return max;
};
```

### 結果

Runtime：73ms
Beats 84.36%

Memory：53.10MB
Beats 84.75%
Dart で Welcome to AtCoder を解いてみた

[Qiita Engineer Festa 2024（キータ・エンジニア・フェスタ 2024） - Qiita](https://qiita.com/official-campaigns/engineer-festa/2024)
において、約1ヶ月で38記事という大量の記事の投稿を要求されることがわかった。
そこで、あまりコストをかけずに記事数を稼ぐ方法を考えた結果、「Welcome to AtCoder を様々な言語で解く」ことを思いついた。
単に解くだけでなく、使用する言語仕様の解説を入れれば、記事として一応成立するだろう。

# Welcome to AtCoder

[PracticeA - Welcome to AtCoder](https://atcoder.jp/contests/abs/tasks/practice_1)

Welcome to AtCoder では、以下の形式で整数 $a$, $b$, $c$ および文字列 $s$ が入力として与えられる。

```text
a
b c
s
```

この入力をもとに、与えられた整数の和 $sum = a + b + c$ および文字列 $s$ を、以下の形式で出力することが求められる。

```text
sum s
```

# 今回用いた Dart の機能

## エントリポイント

[The main() function](https://dart.dev/language/functions#the-main-function)

アプリケーションでは、エントリポイントとなる `main()` 関数を定義する。
たとえば以下のように定義できる。

```dart
void main() {
  // 処理内容
}
```

## 変数

[Variables | Dart](https://dart.dev/language/variables)

`final` を用いると、実行時に値を計算し、その後変更しない変数を宣言できる。
変数の型は値の型から推論されるので、明示しなくてよい。

```dart
final 変数名 = 値;
```

:::note info
ほかにも以下のキーワードがあるが、今回は用いない。

|キーワード|意味|
|:-:|---|
|`var`|値を変更できる変数を宣言する|
|`const`|値がコンパイル時に決まる定数を宣言する|
:::

## 数値の加算

[Operators | Dart](https://dart.dev/language/operators)

`+` 演算子を用いると、数値を加算することができる。

## 文字列の処理

[Strings](https://dart.dev/language/built-in-types#strings)
[Numbers](https://dart.dev/language/built-in-types#numbers)
[Strings and regular expressions](https://dart.dev/libraries/dart-core#strings-and-regular-expressions)
[Lists](https://dart.dev/language/collections#lists)

`''` (または `""`) で囲むことで、文字列を表現できる。
文字列中に `${式}` を入れると、式の値を文字列中に埋め込める。

`int.parse(文字列)` を用いると、文字列をそれが表す数値に変換できる。

`文字列.split(区切り文字列)` を用いると、「文字列」を「区切り文字列」で区切ってリストに変換できる。
リストの要素には `リスト[添字]` でアクセスできる。リストの最初の要素に対応する添字は `0` である。

## 標準出力

[Printing to the console](https://dart.dev/libraries/dart-core#printing-to-the-console)

```dart
print(値);
```

を用いると、「値」を標準出力に出力し、さらに改行を出力できる。

## 標準入力

[Standard output, error, and input streams](https://api.dart.dev/stable/3.4.4/dart-io/dart-io-library.html#standard-output-error-and-input-streams)
[Libraries | Dart](https://dart.dev/language/libraries)
[Other operators](https://dart.dev/language/operators#other-operators)

以下のようにして、入出力を行うライブラリ `dart:io` をインポートする。

```dart
import 'dart:io';
```

すると、標準入力から1行読み込む関数 `stdin.readLineSync()` が使えるようになる。
この関数は、「`null` の可能性がある型」`String?` を返す。
そこで、`!` 演算子をつけて `stdin.readLineSync()!` とすると、`null` の可能性を排除 (`null` の場合は例外発生) して `String` 型にできる。

# 提出コード

```dart
import 'dart:io';

void main() {
  final firstLine = stdin.readLineSync()!;
  final secondLine = stdin.readLineSync()!;
  final thirdLine = stdin.readLineSync()!;

  final firstNumber = int.parse(firstLine);
  final secondLineParts = secondLine.split(' ');
  final secondNumber = int.parse(secondLineParts[0]);
  final thirdNumber = int.parse(secondLineParts[1]);
  final sum = firstNumber + secondNumber + thirdNumber;

  print('${sum} ${thirdLine}');
}
```

[提出 #54772985 - AtCoder Beginners Selection](https://atcoder.jp/contests/abs/submissions/54772985)
Azure リソースの特定の値が取得できない場合は api-version を確認

Azure REST API を使って何かしらのコードを書いている場合、`api-version` に指定する値は、ドキュメントサンプルに記載されている値をそのまま使っていたり、Azure ポータルの `JSON ビュー` を開いたりして `api-versin` とそのレスポンス JSON の中身を確認していたりすると思います。

今回は、例えば Azure CLI や Azure Resource Graph で仮想マシンの作成日時は取得できるのに、Azure REST API で仮想マシンの作成日時が取得できない場合の確認方法を試してみした。

## Azure CLI で仮想マシンの作成日時を取得

```bash:bash
az vm show \
  --resource-group mnrwp-rg \
  --name mnrwp-vm \
  --query timeCreated \
  --output tsv

2024-05-02T04:19:24.452556+00:00
```

## Azure Resource Graph で仮想マシンの作成日時を取得

```bash:bash
az resource show \
  --resource-group mnrwp-rg \
  --name mnrwp-vm \
  --resource-type "Microsoft.Compute/virtualMachines" \
  --query properties.timeCreated \
  --output tsv

2024-05-02T04:19:24.4525565+00:00
```

## Azure REST API で仮想マシンの作成日時を取得

```bash:bash
vmid=$(az vm show \
  --resource-group mnrwp-rg \
  --name mnrwp-vm \
  --query id \
  --output tsv
)

az rest \
  --url "$vmid?api-version=2021-03-01" \
  --query properties.timeCreated \
  --output tsv
```

作成日時が取得できません。

## 使用できる api-version を調べる

あえて存在しない値を指定して実行します。

```bash:bash
az rest \
  --url "$vmid?api-version=2021-03"

Bad Request({"error":{"code":"NoRegisteredProviderFound","message":"No registered resource provider found for location 'japaneast' and API version '2021-03' for type 'virtualMachines'. The supported api-versions are '2015-05-01-preview, 2015-06-15, 2016-03-30, 2016-04-30-preview, 2016-08-30, 2017-03-30, 2017-12-01, 2018-04-01, 2018-06-01, 2018-10-01, 2019-03-01, 2019-07-01, 2019-12-01, 2020-06-01, 2020-12-01, 2021-03-01, 2021-04-01, 2021-07-01, 2021-11-01, 2022-03-01, 2022-08-01, 2022-11-01, 2023-03-01, 2023-07-01, 2023-09-01, 2024-03-01, 2024-07-01'. The supported locations are 'eastus, eastus2, westus, centralus, northcentralus, southcentralus, northeurope, westeurope, eastasia, southeastasia, japaneast, japanwest, australiaeast, australiasoutheast, australiacentral, brazilsouth, southindia, centralindia, westindia, canadacentral, canadaeast, westus2, westcentralus, uksouth, ukwest, koreacentral, koreasouth, francecentral, southafricanorth, uaenorth, switzerlandnorth, germanywestcentral, norwayeast, jioindiawest, westus3, swedencentral, qatarcentral, polandcentral, italynorth, israelcentral, spaincentral, mexicocentral'."}})
```

サポートされている api-version で新しいものを見つけます。

## 最新の api-version で仮想マシンの作成日時を取得

```bash:bash
az rest \
  --url "$vmid?api-version=2024-07-01" \
  --query properties.timeCreated \
  --output tsv

2024-05-02T04:19:24.4525565+00:00
```

## 参考

https://learn.microsoft.com/ja-jp/cli/azure/vm?view=azure-cli-latest#az-vm-show

https://learn.microsoft.com/ja-jp/cli/azure/resource?view=azure-cli-latest#az-resource-show

https://learn.microsoft.com/ja-jp/rest/api/compute/virtual-machines/get?view=rest-compute-2024-03-01&tabs=HTTP#get-a-virtual-machine
Windows 11 on ARMにWSL2をインストール(REGDB_E_CLASSNOTREG対応含む)

Snapdragon X Eliteを搭載したLenovo Yoga Slim 7x Gen 9にWSL2をインストールしてみました。他のSnapdragon X Eliteを搭載したCopilot+ PCでも大きな違いはないかと思います。

# インストール
コマンドプロンプト、Windows PowerShellを起動し、`wsl.exe --install`を実行すれば、WSL2に必要な各種モジュール、および、デフォルトのLinuxディストリビューション(Ubuntu)がインストールされる「はず」。

クラスが登録されていません(Wsl/CallMsi/Install/REGDB_E_CLASSNOTREG)エラーが発生して、インストールができない場合、次の手順で解決するかどうかを試してみる。
![スクリーンショット 2024-06-21 191637.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/ec4fba7b-d4e7-91c9-55c8-ac1b1da7b9f7.png)

1. システム > システム コンポーネント > Linux用Windowsサブシステム のリセットオプションから、修復、リセット をクリックして、再度、`wsl.exe --install`が実行できるか確認する。
![スクリーンショット 2024-06-22 075713.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/b4d446d8-16a8-cfd0-dca1-33247c14287d.png)

1. 修復、リセットでうまくいかない場合、WSL2を再インストールしてみる。前述の システム > システム コンポーネント > Linux用Windowsサブシステムの先頭に現在インストールされているWSL2のバージョン番号が表示されているので控えておく(画面例では2.2.4.0)。
![スクリーンショット 2024-06-22 082028.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/dee99897-aabc-20a2-212f-2f70ed4c9e8c.png)

1. WSL2は(Arm64版も含め) GitHub 上のWSLリポジトリ(https://github.com/microsoft/WSL/releases )からダウンロードできる。ダウンロード可能なバージョン(画面例では2.2.4)が現在インストールされているバージョンと同じ、またはそれよりも新しいのであれば、arm64版のmsiファイルをダウンロードして、インストールする。インストール後(念のため、Windowsを再起動して)、再度`wsl.exe --install`を実行してみる。
![スクリーンショット 2024-06-22 083850.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/167073a9-c597-3748-d176-1b7d12396c35.png)

# 起動確認
1. インストールが完了すると、Ubuntuのユーザ名、パスワード設定画面になるので、それぞれ設定しておく。

# リンク
- [Windows 11 24H2 on ARM での環境構築・動作検証](https://qiita.com/mfunaki/items/6ee512eaefafec562754)
- [Get started with Windows Subsystem for Linux (WSL) on Arm](https://learn.arm.com/learning-paths/laptops-and-desktops/wsl2/)
MongoDB Shellで複数DBを一気にパッチする

# はじめに
MongoDB Shellで複数のDBに対し、一気に更新することは出来ないかなーって考えたのでその際の備忘録です。
一つのDBに対する更新はともかく、それを複数のDBに展開しようとすると手作業だとかなり面倒ですしね。

構造が同じDBが複数存在している時にしか使えないので、他の人にとって役立つか？というと微妙ですが…

# 実際の処理
さて、早速ですが本題のスクリプトになります。
```
const dbNames = db.getMongo().getDBNames();
dbNames.forEach((dbName) => {
  const currentDB = db.getSiblingDB(dbName);
  // 以下、各DBで実行したい処理を行う
  currentDB.any_collection.updateMany({}, { $set: { test: true } });
  currentDB.any_collection.createIndex({ key: 1 }, { name: 'INDEX_TEST' });
  // ここまで
});
```
`db.getMongo()`でMongoDBのインスタンスを取得し、`getDBNames()`でDB名を配列で取得します。
あとは取得したDB名をループし、`db.getSiblingDB(dbName)`で対象DBのオブジェクトを取得して各クエリを実行していきます。

こう見ると単純ではありますが、通常ではまず使わないようなメソッドを使うので普通にMongoDBを使っているだけだと知ることは恐らくほぼ無いです。
通常のアプリでDB跨ぐような処理ってまずやらないし…
全部のDBだけじゃなくて一部特定のDBだけでいいなら、上記の`dbNames`に固定で配列を記述するなど応用すれば使える機会はもっと増えそうです。

:::note warn
`getDBNames()`は**DBに接続しているユーザーが権限を持っている**DB名を返します。
つまり、ユーザーによっては`admin`や`config`などのDB名も取得され、処理の対象となってしまいます。
DB権限を制限しているユーザーで接続する、if文で対象のDBを判定するなど対策の上使用してください。
:::

# 余談：試したこと
本題は終わっていますが、上記に辿り着くまでの経緯も備忘録として記載しておきます。

まずDB名を取得する方法ですが、単にリストが見えればいいのであれば`show dbs`というコマンドもあります。
```
> show dbs
< admin    40.00 KiB
  config   96.00 KiB
  local    72.00 KiB
  sandbox  72.00 KiB
```
ただこれは変数で受け取れないので、後続の処理に使うことはできません。あくまで見るだけですね。

また、DBの切り替えなら`use DB名`というコマンドもあります。
普通にMongoDB ShellでDBの切り替えを行うならこのコマンドですね。
```
> use sandbox
< switched to db sandbox
```
最初は`db.getSiblingDB(dbName)`の代わりにこれを使おうとしていましたが、後続のクエリが実行されないのでこれも今回は使えませんでした。
普通の切り替えならuseでよいので、用途によってちゃんと使い分けていきたいですね。

# 参考リンク
- [db.getMongo() - MongoDB Manual v7.0](https://www.mongodb.com/docs/manual/reference/method/db.getMongo/)
- [Mongo.getDBNames() - MongoDB Manual v7.0](https://www.mongodb.com/docs/manual/reference/method/Mongo.getDBNames/)
- [db.getSiblingDB() - MongoDB Manual v7.0](https://www.mongodb.com/docs/manual/reference/method/db.getSiblingDB/)
【Ruby】数値Nを３桁ずつカンマ区切り

## はじめに
学習記録のために自分なりに解説したいと思います。
 
# 問題
大きな数値 N が入力されます。3 けたごとにカンマ区切りで出力してください。
ただし、N のけた数は 3 の倍数です。


# 解答例
```ruby

num = gets.chomp  # 数値を入力

reversed_num = num.to_s.reverse  # 数値を文字列に変換し、逆順にする

comma_separated = reversed_num.gsub(/(\d{3})(?=\d)/, '\1,') # 3桁ごとにカンマを挿入

puts comma_separated.reverse  # 文字列を再度逆順にして出力
```

## 考え方
Rubyには組み込みの形式設定機能があり、それを利用して数値を指定した桁数ごとに区切って出力します。まず、`to_s`を用いて数値を文字列に変換し、その後に`reverse`と`gsub`を使って3桁ごとにカンマを挿入します。最終的に`reverse`で文字列を正しい順序に戻します。

--- 
## 使用したメソッドについて

### reverseメソッド
文字列や配列の要素を逆順にするためのものです。たとえば "Hello"という文字列に対して `reverse`メソッドを呼ぶと "olleH"という文字列が返ります。

### gsub メソッド
  文字列中の特定のパターンに一致するすべての部分を置換するためのものです。引数として2つ受け取ります。最初の引数がマッチさせたいパターンで、2番目の引数がそのパターンに一致した部分を置換する新しい文字列です。パターンは通常、正規表現で指定します。たとえば "Hello, world!"という文字列に対して `gsub(' ', '_')`を呼ぶと "Hello,_world!"という文字列が返ります。これは半角スペースをアンダースコアに置換しています。

  --- 


## 正規表現　`/(\d{3})(?=\d)/, '\1,`について

このコードでは、正規表現 `/(\d{3})(?=\d)/` を使用して3桁の数字を探しています。

- `\d` は全ての数字にマッチします（0-9）。
- `{3}` は直前のパターン（この場合は `\d`）がちょうど3回続くところにマッチします。つまり、 `\d{3}` は3桁の数値にマッチします。
- `( )` はグループを作り、その中のパターンにマッチする部分をキャプチャします。この部分は後で参照することが可能となります。
- `(?=\d)` は先読みアサーションと呼ばれ、これによりマッチする部分の後ろに直接数字が続くところにマッチします。しかし、ここでマッチした部分はキャプチャや置換の対象にはなりません。
- `'\1,'` は置換する新たな文字列を表します。ここでの `\1` は最初のキャプチャグループ（この場合は `(\d{3})`）にマッチした文字列を参照します。つまり、3桁の数値の後にカンマ (`,`) を挿入します。


## 終わりに
プログラミング初心者のため、間違いあればご指摘ください。
また別の解答あれば教えてください。
Javaで「2つの配列の要素の値を比較する(equals,deepEquals)」の動作を確認してみた

# 概要

Javaで「2つの配列の要素の値を比較する(equals,deepEquals)」の動作を確認してみました。
以下のページを参考にしました。

https://www.javadrive.jp/start/array/index11.html

# 実装

以下のファイルを作成しました。
```JSample11_1.java
import java.util.Arrays;

class JSample11_1{
  public static void main(String[] args){
    int[] a = {85, 78, 92};
    int[] b = a;
    int[] c = {85, 78, 92};

    System.out.println(a == b);
    System.out.println(a == c);
    System.out.println(b == c);
    System.out.println(Arrays.equals(a, b));
    System.out.println(Arrays.equals(a, c));
    System.out.println(Arrays.equals(b, c));
  }
}
```

```JSample11_2.java
import java.util.Arrays;

class JSample11_2{
  public static void main(String[] args){
    int[][] a = {{10, 8} ,{9, 14}};
    int[][] b = a;
    int[][] c = {{10, 8}, {9, 14}};

    System.out.println(Arrays.equals(a, b));
    System.out.println(Arrays.equals(a, c));
    System.out.println(Arrays.equals(b, c));
    System.out.println(Arrays.deepEquals(a, b));
    System.out.println(Arrays.deepEquals(a, c));
    System.out.println(Arrays.deepEquals(b, c));
  }
}
```

以下のコマンドを実行しました。
```
$ javac JSample11_1.java 
$ java JSample11_1 
true
false
false
true
true
true
```

```
$ javac JSample11_2.java 
$ java JSample11_2 
true
false
false
true
true
true
```

# まとめ

何かの役に立てばと。
ITパスポート ソフトウェア

・OS（オペレーティングシステム）
ハードウェアとアプリケーションの間で動作し、アプリケーションがハードウェアを効率的に利用できるように管理・制御するソフトウェア

・マルチタスク
１台のコンピュータで、複数のアプリケーションを少しずつ互い違いに並行して実行することで、あたかも複数のアプリケーションが同時に実行しているように見せかけるOSの機能

・OSの他の機能
・スプーリング
主記憶と低速な入出力装置（プリンタなど）とのデータ転送を、補助記憶を介して行うことで、システム全体の処理能力を高める機能
・仮想記憶方式
補助記憶の一部をあたかも主記憶のように使用する機能

・BIOS
PCの基盤（マザーボード）上のROMに搭載されているプログラム

・ミドルウェア
OSとアプリケーションの中間に位置するソフトウェア

・OSS（オープンソースソフトウェア）
ソースコードが公開され、自由に利用や改変、再配布ができるソフトウェア
用途（OSSの例）
OS（Android,Linux）
オフィスツール（OpenOffice.org）
Webサーバ（Apache）
Webブラウザ（Firefox）
電子メール（Thunderbird）
データベース管理システム（MySQL,PostgreSQL）
ファイル共有（Samba）
Pendulum使って簡単日時実装①

# Pendulumとは
日時の操作を容易にするPythonパッケージ
>datetimeインスタンスは基本的なケースでは十分ですが、より複雑なユースケースに直面すると、制限が見られることが多く

>標準ライブラリに依存しながらも、よりクリーンで使いやすい API を提供します。つまり、依然としてdatetimeですが、より優れています。

https://pendulum.eustace.io/

# インストール
```
pip install pendulum
```

# 使い方
```python
now = pendulum.now()
print(now) 
# 2024-06-22 07:06:08.923470+09:00

timezone_name = now.timezone.name
print(timezone_name) 
# Asia/Tokyo
```
## timezoneのインスタンス, 名前取得
```python
tzone = pendulum.now().timezone
# Asia/Tokyo
tzone = pendulum.now().tz
# Asia/Tokyo
tzone = pendulum.now().timezone_name
# Asia/Tokyo
```


###### タイムゾーンを変更して日時を取得
```python
now_in_london_tz = pendulum.now('Europe/London')
# 2024-06-21 23:19:06.440404+01:00 
```


## 今日・明日・昨日 取得
```python
today = pendulum.today()
# 2024-06-22 00:00:00+09:00

tomorrow = pendulum.tomorrow()
# 2024-06-23 00:00:00+09:00

yesterday = pendulum.yesterday()
# 2024-06-21 00:00:00+09:00
```

## from_format()
>from_format() は、ネイティブの datetime.strptime() 関数に似ていますが、[カスタムトークン](https://pendulum.eustace.io/docs/#formatter:~:text=14%3A15%3A16%27-,Tokens,-The%20following%20tokens)を使用してDateTimeインスタンスを作成

データ型は class 'pendulum.datetime.DateTime'

```python
dt = pendulum.from_format('2024-06-22 09', 'YYYY-MM-DD HH')
# 2024-06-22 09:00:00+00:00
````


###### class 'datetime.datetime'に変換
```python
converted = datetime(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second)
```

######  class 'datetime.datetime'を class 'pendulum.datetime.DateTime'に変換
```python
import datetime 
now = datetime.datetime.now()
pendulum_now = pendulum.instance(now)
```
SalesforceをExcelライクに変えるAppExchange

## はじめに
SalesforceをExcelのように使いたいと思ったことはありませんか？
そんなときは、AppExchangeの導入を検討してみましょう。
SalesforceをExcelライクに変えるAppExchangeはいくつかあります。
今回はその一部を紹介していきます。

## Mashmatrix
株式会社マッシュマトリックスが販売しているAppExchange製品です。
レコード一覧がExcelのような表形式で表示され、縦横にスクロールが可能です。
レコードのコピー&ペーストなどの直感的な操作が可能になるので、Excelに慣れている人であれば簡単に操作ができます。
また、Salesforceの外に保管されているデータも、Excelからのコピー&ペーストで簡単に転記することができます。

参考URL：https://www.mashmatrix.co.jp/service/

## SALESCORE
SALESCORE株式会社が販売しているAppExchange製品です。
Salesforceの中でもSFA機能のデータ管理に特化しています。
取引先や取引先責任者、商談、活動など複数オブジェクトの項目の入力を一画面で完結させることができ、Excelのような操作やショートカットキーの使用が可能になります。
また、ダッシュボードからデータを直接編集することも可能で、入力が非常に容易です。

参考URL：https://salescore.jp/

## RaySheet
メシウス株式会社が販売しているAppExchange製品です。
こちらの製品も、SalesforceをExcelのように扱うことができるようになるものです。
ExlelのようなUIと操作性が得られることはもちろん、1画面に複数のビューを配置して複数オブジェクトを表示させることもできます。このレイアウトパターンは18種類あります。複数画面を行ったり来たりすることの多い業務においては、RaySheetを導入することで効率アップに繋がる可能性が高いです。

参考URL；https://raykit.mescius.jp/products/raysheet.html

## PlainReport
最後に、株式会社ADX Consultingが販売しているAppExchange製品、PlainReportをご紹介します。
PlainReportはSalesforceをExcelライクに変える製品ではなく、SalesforceのデータをExcel帳票として出力するためのツールです。好きなレイアウトでExcelの帳票を作成し、セルにSalesforceオブジェクトのAPI参照名を入力するだけでExcel帳票が可能になります。

参考URL：https://crm.adxc.co.jp/appexchange/plainreport/

## おわりに
以上が、SalesforceをExcelライクに変えるAppExchangeのご紹介でした。
Excelをよく活用している企業はたくさんあるので、SalesforceがExcelのように操作できたり、Excelとの互換性が高くなればそれだけで社内への定着化が進みそうですね。
最後までお読み頂きありがとうございました。
サーバー設定のパラメータ操作方法あれこれ＜PostgreSQL自習室＞

## サーバー設定のパラメータ操作方法の種類

- 設定ファイルによるパラメータ操作
- SQLを通じたパラメータ操作
- シェルによるパラメータ操作

## 設定ファイルによるパラメータ操作とは

　（通常 data ディレクトリに格納されている）postgresql.conf ファイル上に、パラメータを指定する方法。
 
　[20.1.2. 設定ファイルによるパラメータ操作](https://www.postgresql.jp/document/16/html/config-setting.html#CONFIG-SETTING-CONFIGURATION-FILE "PostgreSQL 16.0文書 第20章 サーバ設定 20.1. パラメータの設定")
内のサンプル：

```
# This is a comment
log_connections = yes
log_destination = 'syslog'
search_path = '"$user", public'
shared_buffers = 128MB
```
　postgresql.auto.confファイルは、postgresql.confの設定を上書き（優先）する。
　`ALTER SYSTEM`コマンドによるパラメータ設定されると、postgresql.auto.confファイルに反映され、次回サーバー起動時にもpostgresql.auto.confファイルから読み込まれてパラメータ反映される。
　postgresql.auto.confファイルを**直接修正してはならない**。
　サーバー稼働中に、postgresql.confファイルやpostgresql.auto.confファイルを変更しても反映されない。

　[20.1.5. 設定ファイルの内容の管理](https://www.postgresql.jp/document/16/html/config-setting.html#CONFIG-INCLUDES "PostgreSQL 16.0文書 第20章 サーバ設定 20.1. パラメータの設定")に依ると、《複雑なpostgresql.confファイルを複数の小さなファイルに分割する複数の方法を提供》しており、`include`ディレクティブと`include_dir`ディレクティブが使える模様。

## SQLを通じたパラメータ操作とは

- `ALTER SYSTEM`コマンドによる、データベースクラスタ全体にわたるサーバの設定パラメータを変更
- `ALTER DATABASE`コマンドによる、データベース単位でグローバルな設定値を上書き
- `ALTER ROLE`コマンドによる、グローバルとデータベース単位の両方をユーザ固有の設定値で上書き

　セッションローカルな設定変更方法として下記2つ。

 - `SHOW`コマンド、もしくは`current_setting()`関数
 - `SET`コマンド、もしくは`set_config()`関数
 - システムビューの`pg_settings`を介して、セッションローカルな値を参照したり変更することも可能

　`SET`コマンドによる一時的な設定変更を永続化させるために、`ALTER SYSTEM`コマンドを使う。

## シェルによるパラメータ操作とは

- サーバ起動時に、-cコマンドラインパラメータを使ってパラメータ設定値をpostgresに渡す方法
- libpqを使ってクライアントセッションを開始するプログラムやツール(psqlとか)の場合、PGOPTIONS環境変数でパラメータ設定値を渡すことも可能

　コマンドラインパラメータで渡されるパラメータ設定値は、postgresql.confや`ALTER SYSTEM`コマンドによるパラメータ保存を上書きする。

 ## 参考

　PostgreSQL 16.0文書 より

 - [20\.1\. パラメータの設定](https://www.postgresql.jp/document/16/html/config-setting.html)
 - [ALTER SYSTEM](https://www.postgresql.jp/document/16/html/sql-altersystem.html)
【CakePHP5】CodeSnifferをGitHubActionsで使う

# はじめに

こんにちは、エンジニアのkeitaMaxです。

前回CodeSnifferをローカルでコマンドを打って実行したので、今回はPushした時にGitHub上で実行するようにしようと思います。

https://qiita.com/keitaMax/items/3147a3e56c4c2a3b8fde

# GitHubActionsの設定ファイルの作成

`.github/workflows/phpcs.yml`ファイルを作成します。

```yml:phpcs.yml
name: phpcs

on: [pull_request]

jobs:
  phpcs:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: ./src
    steps:
      - uses: actions/checkout@v2
      - name: dokcer-compose up
        run: |
          docker-compose up -d
      - name: composer install
        run: |
          docker compose exec app composer install
      - name: Run CodeSniffer
        run: |
          docker compose exec app composer cs-check

```
これは以前の記事で作成したLaravelのymlファイルを参考にしています。

https://qiita.com/keitaMax/items/650aa738ce87c259fb41

# Pushして実行する

実際にGitHubにPushしてみます。

すると以下のようにGitHubActionsが動いているのがわかります。

![スクリーンショット 2024-06-11 22.44.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715123/acc0a601-8b79-67c8-0117-135232d1c25e.png)

実行が終わると、以下のようになります。

![スクリーンショット 2024-06-11 22.47.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715123/523e246c-54ca-686b-5f05-87b84dc57f7d.png)

これでGitHub上でCodeSnifferを実行することができました。

# 失敗させてみる

正しく動いているか確かめるために失敗させてみます。

AppControllerのinitialize(): voidこの記述をinitialize():voidこのように半角スペースを消してPushしてみます。

すると以下のようにエラーになるのがわかります。

![スクリーンショット 2024-06-11 22.51.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715123/6de43a21-5b8b-0e2a-c7e3-4591d61a2820.png)

ただしくCodeSnifferがGitHub上で動作していることが確認できました。


# おわりに

この記事での質問や、間違っている、もっといい方法があるといったご意見などありましたらご指摘していただけると幸いです。

最後まで読んでいただきありがとうございました！

# 参考

https://qiita.com/keitaMax/items/650aa738ce87c259fb41

# 次の記事