OmniAICreator/Qiita-1.07M huggingface dataset:
Fat Controllerを避けるためのCruddy by Design

[Laravel Advent Calendar 2022](https://qiita.com/advent-calendar/2022/laravel) 10日目の記事です。

# Fat Controllerとは何か？
アプリケーションのアーキテクチャを、エンジニアのメンタルモデルに合致させるべく提唱されたものがMVCモデルだが、実際に使ってみるとControllerに処理が集中しやすく、結果Controllerが冗長になってしまってメンテナンス性を著しく毀損した状態となる。この状態をFat Controllerと呼ぶ。

# Fat ControllerのLaravel的回避手段
LaravelではMiddlewareやFormRequestが用意されており、Modelではミューテターやアクセサー、グローバルクエリスコープ、ローカルクエリスコープ、イベントフックといった仕組みが提供されている。これに、PHPが提供しているTraitを組み合わせれば、Fat Controllerを回避することはさほど難しくはない。

しかし、今回はさらにスッキリしたControllerを書くための「戦略」を紹介したいと思う。それが、タイトルにある「Cruddy by Design」である。

# DHH流のコントローラーの書き方
まず「Cruddy by Design」を語る前に、Railsの生みの親であるDHH氏の以下の記事を紹介したい。

DHHはどのようにRailsのコントローラを書くのか
https://postd.cc/how-dhh-organizes-his-rails-controllers/

この書き方は、2016年以降Laravelコミュニティでも広く受け入れられており、Taylor氏も[以前のラジオのインタビュー](https://blog.laravel.com/laravel-snippet-11
)で「この考え方を取り入れているので自身が書くControllerはとてもスッキリしている(意訳)」と述べている。

要約すると、「Controllerでは原則としてデフォルトのCRUDアクションのみを使用し、その範疇に収まらないアクションが出てきた場合、それに即したコントローラーを別途切り出し、その中でまた同様にデフォルトのCRUDアクションのみを使用する」ということだ。

# Cruddy By Design
基本的な考え方は、上で紹介したDHH氏が話した内容と類似しており、よりLaravelの事情に則ったものが「Cruddy By Design」である。これは2017年のLaraconにおいて、今ではTailwind CSSの生みの親として知られるAdam Wathan氏が提唱したものとなる。

当時の発表内容はGithubに残っているので、ざっと読み解いていきたい。
https://github.com/adamwathan/laracon2017

まず、`Cruddy By Design`とは、`I shared some strategies I use to split large controllers into multiple small controllers.` と述べている通り、大きなコントローラーを複数の小さなコントローラーに分割するためのいくつかの戦略をまとめたものである。

それら戦略の根底にあるアイデアは、「Laravelのリソースコントローラーが提供する標準のアクションのみを使用する」というものであり、以下の4つの具体的な戦略が提唱されている。
- Give nested resources a dedicated controller
- Treat properties edited independently as separate resources
- Treat pivot models as their own resource
- Think of different states as different resources

Adam氏はその4つそれぞれを掘り下げて以下のように説明している。

## [Give nested resources a dedicated controller](https://github.com/adamwathan/laracon2017/pull/1)
`/podcasts/{id}/episodes` のようなネストしたリソースの場合、EpisodesController@indexでは別のコンテキスト(全エピソード一覧の取得)になってしまうため、ネストした一覧を取得するための専用のコントローラーに切り出す。

## [Treat properties edited independently as separate resources](https://github.com/adamwathan/laracon2017/pull/2)
例えば対象のレコードのうち画像のような個別のプロパティのみを編集するケースでは、そのレコードを扱うリソースの中で扱わずに、別のリソースとして扱う。

## [Treat pivot models as their own resource](https://github.com/adamwathan/laracon2017/pull/3)
Laravelは、N:Nのリレーションを表現したときに2つのモデルを交差させた部分をpivotと呼んでいる。そのpivotのモデルは、それ自体を１つのリソースとして扱う。
 
## [Think of different states as different resources](https://github.com/adamwathan/laracon2017/pull/4)
単純に「保存」する場合でも、様々な状態があるので、それらの状態ごとの違いでリソースを分けて扱う。例では、記事の公開/非公開の状態にちなんだstoreとdestroyをその状態を示すコントローラー名で切り出している。

# 最後に
以上がCruddy by Designという戦略の概要である。Githubリポジトリを見ていただけばコードも一緒に掲載されているので、より深く理解できると思う。

なお私の場合は、このCruddy By Designに加えてartisanコマンドでも提供しているSingle Action Controller(`make:controller HogeController --invokable`)を使うことも多い。

いずれにせよこのような戦略を採用すると、Controllerに意味不明な名前のメソッドや、大量のpublicメソッドを抱えるControllerの爆誕を抑制できるので、個人・チームを問わず有効な戦略と言える。
【cvpaper.challenge】ECCV2022網羅的サーベイに参加した

# 目次
- [はじめに](#はじめに)
- [cvpaper.challengeとは？](#cvpaperchallengeとは)
- [ECCV2022網羅的サーベイとは？](#eccv2022網羅的サーベイとは)
- [論文サマリ&"基盤モデル×Robotics"](#論文サマリ基盤モデルrobotics)
- [おわりに](#おわりに)

# はじめに

"基盤モデル×Robotics"のAdvent Calendarの24日目です！
今日の記事では，cvpaper.challengeのECCV2022網羅的サーベイで読んだ論文の紹介をします．

# cvpaper.challengeとは？

[cvpaper.challenge](http://xpaperchallenge.org/cv/)は，

>コンピュータビジョン（CV）分野の今を映し、新しいトレンドを創り出す

研究コミュニティです．

# ECCV2022網羅的サーベイとは？

>CV分野のトップ国際会議ECCVを読破するチャレンジ

の2022年度版です．参加者は，読みたい論文を選び，読み終えたら論文サマリを書きます．

# 論文サマリ&"基盤モデル×Robotics"

|タイトル|Sim-2-Sim Transfer for Vision-and-Language Navigation in Continuous Environments|
|:-|:-|
|著者|Jacob Krantz; Stefan Lee|
|サマリ|http://xpaperchallenge.org/cv/survey/eccv2022_summaries/62|
|基盤モデル×Robotics|Vision-and-Language Navigation|

|タイトル|Generative Meta-Adversarial Network for Unseen Object Navigation|
|:-|:-|
|著者|Sixian Zhang; Weijie Li; Xinhang Song; Yubing Bai; Shuqiang Jiang|
|サマリ|http://xpaperchallenge.org/cv/survey/eccv2022_summaries/78|
|基盤モデル×Robotics|Visual Object Navigation|

|タイトル|Learning from Unlabeled 3D Environments for Vision-and-Language Navigation|
|:-|:-|
|著者|Shizhe Chen; Pierre-Louis Guhur; Makarand Tapaswi; Cordelia Schmid; Ivan Laptev|
|サマリ|http://xpaperchallenge.org/cv/survey/eccv2022_summaries/149|
|基盤モデル×Robotics|Vision-and-Language NavigationのためのデータセットをGPT-2を利用して自動生成|

|タイトル|Language-Grounded Indoor 3D Semantic Segmentation in the Wild|
|:-|:-|
|著者|Dávid Rozenberszki; Or Litany; Angela Dai|
|サマリ|http://xpaperchallenge.org/cv/survey/eccv2022_summaries/168|
|基盤モデル×Robotics|CLIPを利用して3次元特徴を学習|

|タイトル|Extract Free Dense Labels from CLIP|
|:-|:-|
|著者|Chong Zhou; Chen Change Loy; Bo Dai|
|サマリ|http://xpaperchallenge.org/cv/survey/eccv2022_summaries/187|
|基盤モデル×Robotics|CLIPを利用してSemantic Segmentation|

|タイトル|Tip-Adapter: Training-Free Adaption of CLIP for Few-Shot Classification|
|:-|:-|
|著者|Renrui Zhang; Wei Zhang; Rongyao Fang; Peng Gao; Kunchang Li; Jifeng Dai; Yu Qiao; Hongsheng Li|
|サマリ|http://xpaperchallenge.org/cv/survey/eccv2022_summaries/192|
|基盤モデル×Robotics|CLIPのFew-Shot分類性能を向上|

|タイトル|Learning to Detect Every Thing in an Open World|
|:-|:-|
|著者|Kuniaki Saito; Ping Hu; Trevor Darrell; Kate Saenko|
|サマリ|http://xpaperchallenge.org/cv/survey/eccv2022_summaries/337|
|基盤モデル×Robotics|Open-World Instance Segmentation|

|タイトル|MoDA: Map Style Transfer for Self-Supervised Domain Adaptation of Embodied Agents|
|:-|:-|
|著者|Eun Sun Lee; Junho Kim; SangWon Park; Young Min Kim|
|サマリ|http://xpaperchallenge.org/cv/survey/eccv2022_summaries/376|
|基盤モデル×Robotics|地図ベースのVisual Navigationにおける自己教師ありドメイン適応|

# おわりに

"基盤モデル×Robotics"に興味があります．特に，「周囲の環境を理解するAIモデルへの言語モデルの組み込み」に興味があります．

ECCV2022網羅的サーベイでは，「Vision-and-Language Navigationに関する論文」や「CLIPを利用した論文」を中心に読みました．他の参加者が書いたECCV2022論文サマリは，http://xpaperchallenge.org/cv/survey/eccv2022_summaries/ から閲覧できます．
【Playdate】コライダーを埋め込む

アクションゲームやシューティングゲームに欠かせない衝突処理を実装してみます。
今回も[こちらのプロジェクト](https://qiita.com/sada_lp1/items/1751040555361bae33b7)をベースに進めていきます。

プレイヤーと壁を用意して壁にぶつかったときに跳ね返るような動きをつけようと思います。


```main.lua
import "CoreLibs/object"
import "CoreLibs/graphics"
import "CoreLibs/sprites"
import "CoreLibs/timer"

local gfx <const> = playdate.graphics

local playerSprite = nil
local wallSprite = nil

function myGameSetUp()

	local playerImage = gfx.image.new("Images/playerImage")
	assert( playerImage )

	playerSprite = gfx.sprite.new( playerImage )
	playerSprite:moveTo( 200, 120 )
	playerSprite:setCollideRect(0, 0, playerSprite:getSize()) -- playerSpriteにコライダーセット
	playerSprite.collisionResponse = playdate.graphics.sprite.kCollisionTypeBounce -- コライダーとぶつかったときのふるまい
	playerSprite:add()
	
	local wallImage = gfx.image.new(20, 80)
	gfx.pushContext(wallImage)
		gfx.setColor(gfx.kColorWhite)
		gfx.fillRect(0,0,20,80)
	gfx.popContext()
	wallSprite = gfx.sprite.new(wallImage)
	wallSprite:moveTo( 300, 120 )
	wallSprite:setCollideRect(0, 0, wallSprite:getSize()) -- コライダーセット
	wallSprite:add()

	local backgroundImage = gfx.image.new( "Images/background" )
	assert( backgroundImage )

	gfx.sprite.setBackgroundDrawingCallback(
		function( x, y, width, height )
			backgroundImage:draw( 0, 0 )
		end
	)

end

myGameSetUp()

function playdate.update()

	local offsetX = 0
	local offsetY = 0
	if playdate.buttonIsPressed( playdate.kButtonUp ) then
		offsetY = -2
	end
	if playdate.buttonIsPressed( playdate.kButtonRight ) then
		offsetX = 2
	end
	if playdate.buttonIsPressed( playdate.kButtonDown ) then
		offsetY = 2
	end
	if playdate.buttonIsPressed( playdate.kButtonLeft ) then
		offsetX = -2
	end
	playerSprite:moveWithCollisions(playerSprite.x + offsetX, playerSprite.y + offsetY)

	gfx.sprite.update()
	playdate.timer.updateTimers()

end
```

まず`playerSprite`にコライダーを設定します。
コライダーのセットは`playerSprite:setCollideRect`で行います。それぞれ引数は以下の通りです。
第1引数:[スプライトの左上を始点にしたスプライトのx座標]
第2引数:[スプライトの左上を始点にしたスプライトのy座標]
第3引数:[コライダーのwidth,height]（第3引数をwidth、第4引数をheightにしてもよい）

次に他のコライダーにぶつかったときの振る舞いを設定します。
ここでは`playerSprite.collisionResponse`に直接代入しています。
代入できる値は以下の通りです。
- playdate.graphics.sprite.kCollisionTypeSlide : 他のオブジェクトの上をスライドする
- playdate.graphics.sprite.kCollisionTypeFreeze :他のオブジェクトと衝突するとすぐにスプライトの動きを停止する
- playdate.graphics.sprite.kCollisionTypeOverlap : スプライトの動きに影響を与えない(アイテムなどに使う)
- playdate.graphics.sprite.kCollisionTypeBounce : スプライトが他のオブジェクトから跳ね返る

`wallSprite`という壁スプライトを作成します。
width20、height80の白い壁を用意しました。
このスプライトにも`setCollideRect`でコライダーをセットします。

次にupdateでplayerSpriteをコライダーと一緒に動かします。
`sprite:moveWithCollisions(goalX, goalY)`でコライダーと一緒に目的地まで動かします。
この際、目的地にコライダーがあった場合、`sprite.collisionResponse`で設定した処理を行います。
この場合はコライダーにぶつかったとき、跳ね返るような動きになります。
![タイトルなし2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100912/4681498a-5c4d-1781-7d92-af9a8bcedc49.gif)
5Wノート作ってみた。


最近寒くなってきましたね～
実家が青森なんですが、母親から車の窓が凍ってきたといわれました。
今の車は凍るんでしょうか…すごく疑問です。

この話はさておき、今回は5Wノートというものを作ってみました。
こんなものです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404009/bd5ea26d-6ef4-73e4-3588-bd8dd7084871.png)

私は会議に出るときに使ってます。
こんなのがなくても覚えておかなきゃいけないですが。。

# 5Wノートアプリとは？？
5W1Hという言葉がありますよね。
「When：いつ」「Where：どこで」「Who：だれが」「What：何を」「Why：なぜ」「How：どのように」と英単語の頭文字をとった言葉です。

|5W1H|意味|
|:-----------------------:|:------------:|
|When：いつ　　 |日時・期限|
|Where：どこで　|場所・環境|
|Who：だれが    |人|
|What：何を　　 |物・対象物|
|Why：なぜ　　　|理由・原因|
|How：どのように|方法・手段|

メールを書くときや人に伝えるときと、いろんな場面で使えますよね。
あとで見返すときがあっても、すぐにわかったり。
5Wノートとは、自分が何をしなければいけないのか、自分のタスクや前の会議でこんな会話をしていたと見返して、タスクや会話の内容がすぐにわかるアプリです。

# 簡単な仕組み
Power Appsで入力したものをPower AutomateでTeamsへ通知させる仕組みです。
※今回、保存しようと考えていないので、Dataverseは使いません。
```mermaid
graph TD;
    PowerApps-->PowerAutomate;
    PowerAutomate-->Teams;
```

# アプリ作成
画面はこんな感じ。レイアウト皆無人間なので、もっといいレイアウトが絶対ある…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404009/4b3f344d-2c61-f762-5143-2496b8ac801a.png)

手順
1.ラベルとテキスト入力を必要な数を追加します。
* プロジェクト
* Why：なぜ
* What：何を
* When：いつ
* Who：だれが
* Where：どこで
* 備考

2.ボタンを一つ追加します。
Teamsに通知するとわかるようにボタンのテキストに「Teamsへ通知」と書いておきます。

一旦、アプリの作成はここまで。Power Automateを作成したら、また続きやります。

# フロー作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404009/1a57f39e-e03b-b1fa-016a-327d772f511f.png)

手順
1.Power Appsで使用したいので、トリガーをPower Appsにします。

2.変数の初期化を追加
Teamsへ通知させたい必要な数を追加します。
* プロジェクト
* 日付
* Why：なぜ
* What：何を
* When：いつ
* Who：だれが
* Where：どこで
* 備考

3.Teams通知を追加
変数の初期化で追加したプロジェクトや日付を追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404009/b82b8c31-ea62-a5e2-0888-0a3a517cea42.png)

これでフローの作成は完了。アプリ作成の続きに入る

# アプリ作成-続き
アプリ画面に戻り、Power Automateで作成したフローを追加して、Teamsへ通知できるようにする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404009/71b3080a-197b-a4e4-18a4-7342a698f721.png)

手順
1.ボタンのOnSelectプロパティにPower Automateで作成したフローを追加

2.Power Automateに連携したいものを式に追加
今回は8個あるので、1個の日付のラベルと7個のテキストインプットを追加します。

ここで、アプリの完成です。

# Teamsへ通知してみましょう～
アプリで今日のタスクを書いて、Teamsへ通知させてみたいと思います。

アプリ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404009/944fdb42-c241-a67e-f3eb-b18e7d5f5b3b.png)
Teams
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404009/d6bc1fc9-7553-8a7c-36e0-3f7c5f05b318.png)

アプリで書いたタスクがTeamsへ通知されましたね。

Dataverseに保存をして、追加した日から一週間たったら、通知させるってこともできそうですね。
【GAS】和暦を西暦に変換

# はじめに
友達からある日こんなことを言われました。
友「スプレッドシートに、平成8年8月8日みたいなデータを西暦にしたいんだけど？」
も「は？」
と言うことで、今回は和暦を気合いで、西暦にしていきたいと思います。

年号計算の部分は[こちらのサイト様](https://daily-coding.com/changeyear/) から引用させていただきました。
ありがとうございました。

僕は引用させていただいたところまでをサクッと作りました。
細かい説明はなしです。どーん。

```JavaScript
function convert_jc(arg){
  arg = arg.replace('月','/').replace('日','');
  var jc = '';
  var year_number = '';

  for(var i=0;i<arg.length;i++){
    if(arg[i] == '年'){ break }
    jc = jc + arg[i];
  }
  for(var i=0;i<2;i++){ year_number = year_number + jc[i]; }
  num = jc.replace(year_number, '');
  ad = changeYear(year_number, num); //引用元様の関数にぶん投げます
  return ad + arg.replace(jc, '').replace('年', '/');
}
```

あとは、`=convert_jc(セル)`と投げればあっという間に西暦にできます。

結果：できた！

以上です、ありがとうございました。
Tweepyなら簡単に初心者でもTwitterAPIを利用できました(Pythonで)

今後、TwitterAPIを活用する業務を行いたいのと、StripeやSpreadsheetのAPIをぼちぼち使用しはじめたので、学習を兼ねてTwitterデベロッパーアカウントを申請しました。

公式のドキュメントをみると、HTTP通信について理解してリクエストヘッダーやエンドポイントを記載しなれければならないようでした。
上記のワードは、言葉だけは知っていますが、きちんと学習していないものばかりでした。
また、アプリをOAuth認証しなければtweetの取得などが行えないのですが、その認証の仕方がなかなか理解できなくて困りました。
とにかくまずはTweetの取得をしたい！動いているところをみたい！と思い簡単な方法を調べました。

色々調べた結果、PythonではTweepyというライブラリが有名なようでした。
早速、pipを通してインストールし、Tweepy公式で最初の一歩を試しました。
https://docs.tweepy.org/en/stable/index.html
以下が公式HPにのっている最初の一歩(Get Started)のコードです。（少しわかりやすいように修正）
```
import tweepy

auth = tweepy.OAuth1UserHandler(
   yourapi_key, yourapi_secret, youraccess_token, youraccess_token_secret

)

api = tweepy.API(auth)

public_tweets = api.home_timeline()
for tweet in public_tweets:
    print(tweet.text)
```

ここで気を付けるポイントがあります。
一つ目は暗号鍵です。Get started上ではOAuth認証に使う鍵がconsumer_key等となっていますが、今はTwitter公式での呼び名がapi_keyに統一されています。
他の記事でもcomsumer_keyと記載されていることが多いので読み替えます。初心者はこういうものによく躓きます。
二つ目は、デベロッパーポータル上でアプリの権限をreadから　read and write等に変更し、そのあとで鍵を生成しておくことです。
私はこれを怠り先に鍵を生成してしまったため、後でアプリの設定から権限を変更しても、エラーが返ってきてしまいました。
あとでよく見たらデベロッパーポータルで表示されている鍵の下に小さく権限がreadのみの時に作成されました。と注意書きがありました。

このコードをpyhon上で実行すると簡単にOAuth認証をしてくれて、自分のホーム画面上の最新20tweetを取得し表示してくれます。httpメソッドなどのややこしいことを考えずにひとまずtweetを取得できます。
またとってきたtweetは、投稿日時や場所、id等の情報を辞書配列のようにもっているので,
例えば以下のようにするとtweetのidが表示できます。
```
for tweet in public_tweets:
    print(tweet.id)
```
tweetのidがわかれば、tweepyの便利な関数でretweetやいいねができるようになります。　
```
api.create_favorite(id_str)
```

上記はAPI v1用の関数で　v2からはClient.like()でいいねを行うようなのですが、引数　selfが不足していますとエラーがでてその解決方法が分かりませんでした。
APIのバージョンを確認してくださいと公式には書いてあったのですが。

他にも、get_favorites()で自分がいいねをしたツイートを見返すことなどができます。通常のtwitterクライアントよりも、自分の見たい情報が簡単に閲覧できると感じました。
また、公式の説明も平易な英語で書かれておりわかりやすいと思いました。
これで色々遊んでいこうと思います。

慣れたらこの記事を参考に基本を学んでいきたいと思います。
https://qiita.com/mpyw/items/b59d3ce03f08be126000
長文乱文失礼しました。

Wesołych Świąt Bożego Narodzenia
Pythonで問題を解いてみる

## はじめに
[MYJLab Advent Calendar 2022](https://qiita.com/advent-calendar/2022/myjlab)の12日目の記事です。
昨日は@momoyamaさんの[OpenCVで画像処理（平滑化）](https://qiita.com/momoyama/items/aecf831fbf887f067d42)という記事でした。
今日は、[AtCoder](https://atcoder.jp/home)(いわゆる競技プログラミング)の（たぶん）有名問題を解いてみようという記事です！
## 環境等
Python
Google colaboratory
## 問題
今回、解いてみる問題はC問題の「Repsept」です！
問題文はこちら→https://atcoder.jp/contests/abc174/tasks/abc174_c
問題文はこの記事に載せてないのでリンクを踏んでください！（著作権の関係）

**ここで考察を読む前に是非、問題を読んで考えてみてください！!**

## 考察
では、考察に入ります。
ぱっと問題文を読んだ感じ、7,77,777,...を無限に探索する必要があり、膨大な処理が発生しそうですよね。
でも安心してください！この問題は鳩ノ巣原理というものを利用して考えれば簡単（K項目目までの探索）に解くことが出来ます！

**鳩ノ巣原理とは...**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982097/b8d3140f-292e-5673-4f9e-804969b14703.png)
まあ、当たり前のことを言っているだけなんですが、これが中々奥深いんですね。興味のある人は調べてみてください。

で、この原理がどう役に立たせていくのかというのを今から順に書いていきます。

まずは、問題文の「Kの倍数が登場するのは何項目目か」を「Kで割った余りが0になるのは何項目か」と読み替えます。
次に、7,77,777,...をKで割った余りをどのように工夫して計算するのかを考えると、
* 7→77、77→777、...になるときは(前の数)*10+7と計算出来ること
* 余りの計算も同様に、(前の数をKで割った余り)*10+7で計算出来ること

がわかります。

次に、どこまで計算すればよいかを考えます。
Kで割った余りは0,1,2,...K-1までKパターンしか存在しないことから、
K+1項目目の余りを計算したとき、K項目目までの余りのどれかと必ずかぶってしまいます。

**ここで鳩ノ巣原理を使います！！**
先ほどの説明も踏まえると、この問題は
n個のグループ　＝　余りの種類
m個のもの　＝　項目の数
と対応しているといえます。

つまり、K項目目まで計算したとき
* K項目目までにKで割った余りが0になる項目があった場合、そこで答えを出力する
* K項目目までにKで割った余りが0になる項目がなかった場合、Kで割った余りが0になることはない=-1を出力する
(K項目目までに余りが0になることはなかった　＝　K+1項目目以降で余りが0になることはない)

とすればよいわけです！　あっという間でした！
## 実装
考え方がわかったところで、やっとコーディングに移ります。

入力の受け取り
```py
K = int(input())
```

Kで割った余りを格納する変数の用意
```py
amari = 0
```

1項目目からK項目目までKで割った余りの計算
```py
for i in range(1, K + 1):
    amari = amari * 10 + 7

    if amari % K == 0:
        print(i)
        exit()
    amari %= K

print(-1)
```

考え方を工夫したことで簡単にコーディングすることが出来ました！
## 検証
`K = 101`で検証してみました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982097/e335ac47-2857-fc01-7cf3-7b6f5200c329.png)

結果、4と出力されました。4桁→7777であり、101の倍数ですから無事成功です。

## 参考文献
[AtCoder](https://atcoder.jp/home)
[鳩ノ巣原理の意味と例（身近な例から超難問まで）](https://manabitimes.jp/math/692)
【cvpaper.challenge】CVPR2022網羅的サーベイに参加した

# 目次
- [はじめに](#はじめに)
- [cvpaper.challengeとは？](#cvpaperchallengeとは)
- [CVPR2022網羅的サーベイとは？](#cvpr2022網羅的サーベイとは)
- [論文サマリ](#論文サマリ)
- [おわりに](#おわりに)
# はじめに

cvpaper.challengeのCVPR2022網羅的サーベイで読んだ論文の紹介をします．

# cvpaper.challengeとは？

[cvpaper.challenge](http://xpaperchallenge.org/cv/)は，

>コンピュータビジョン（CV）分野の今を映し、新しいトレンドを創り出す

研究コミュニティです．

# CVPR2022網羅的サーベイとは？
>CV分野のトップ国際会議CVPRを読破するチャレンジ

の2022年度版です．参加者は，読みたい論文を選び，読み終えたら論文サマリを書きます．

# 論文サマリ

|タイトル|Diffusion Autoencoders: Toward a Meaningful and Decodable Representation|
|:-|:-|
|著者|Konpat Preechakul; Nattanat Chatthee; Suttisak Wizadwongsa; Supasorn Suwajanakorn|
|サマリ|http://xpaperchallenge.org/cv/survey/cvpr2022_summaries/124/|

|タイトル|Simple but Effective: CLIP Embeddings for Embodied AI|
|:-|:-|
|著者|Apoorv Khandelwal; Luca Weihs; Roozbeh Mottaghi; Aniruddha Kembhavi|
|サマリ|http://xpaperchallenge.org/cv/survey/cvpr2022_summaries/159/|

|タイトル|Interactron: Embodied Adaptive Object Detection|
|:-|:-|
|著者|Klemen Kotar; Roozbeh Mottaghi|
|サマリ|http://xpaperchallenge.org/cv/survey/cvpr2022_summaries/305/|

|タイトル|Real-Time Object Detection for Streaming Perception|
|:-|:-|
|著者|Jinrong Yang; Songtao Liu; Zeming Li; Xiaoping Li; Jian Sun|
|サマリ|http://xpaperchallenge.org/cv/survey/cvpr2022_summaries/317/|

|タイトル|OW-DETR: Open-World Detection Transformer|
|:-|:-|
|著者|Akshita Gupta; Sanath Narayan; K J Joseph; Salman Khan; Fahad Shahbaz Khan; Mubarak Shah|
|サマリ|http://xpaperchallenge.org/cv/survey/cvpr2022_summaries/360/|

|タイトル|SelfD: Self-Learning Large-Scale Driving Policies From the Web|
|:-|:-|
|著者|Jimuyang Zhang; Ruizhao Zhu; Eshed Ohn-Bar|
|サマリ|http://xpaperchallenge.org/cv/survey/cvpr2022_summaries/380/|

|タイトル|Towards Real-World Navigation With Deep Differentiable Planners|
|:-|:-|
|著者|Shu Ishida; João F. Henriques|
|サマリ|http://xpaperchallenge.org/cv/survey/cvpr2022_summaries/426/|

|タイトル|Towards General Purpose Vision Systems: An End-to-End Task-Agnostic Vision-Language Architecture|
|:-|:-|
|著者|Tanmay Gupta; Amita Kamath; Aniruddha Kembhavi; Derek Hoiem|
|サマリ|http://xpaperchallenge.org/cv/survey/cvpr2022_summaries/580/|

# おわりに

"基盤モデル×Robotics"に興味があります．特に，「周囲の環境を理解するAIモデルへの言語モデルの組み込み」に興味があります．

他の参加者が書いたCVPR2022論文サマリは，http://xpaperchallenge.org/cv/survey/cvpr2022_summaries/ から閲覧できます．
Javaで何か作ってみる(2022/12/12 Day53)

## 今日やった事
- オブジェクト指向の動画教材を見た。（**J2-補講_正規表現** まで見た。）
## 参考にしたもの
- [Spring 入門 ～ SpringBoot 2 を使ってお問い合わせアプリとToDoアプリを作る ～](https://www.udemy.com/course/java_spring_beginner/)  
- [【超初心者も必見】Javaプログラミングの「オブジェクト指向」が絶対理解できる講座【プロ講師が丁寧解説】](https://www.udemy.com/course/uz-java-obj/)  
## 所感
- 発生する可能性がある例外は、throws節を用いて明示出来、throws節がついたメソッドを呼び出す場合は、  
例外処理をしないとコンパイルエラーになるのは、便利だけど、忘れそうだから注意しないとなと思った。
- 正規表現は便利なので、使いこなせるようになりたい。

## 明日の予定
- 引き続き、動画教材を進めていく。
空間図形「前橋工科大学2020年第2問」をsympyでやってみた。

作図はありません

... ...
オリジナル

https://mathmathmass.exblog.jp/32616629/

上と同じです。大学入試数学問題集成＞

https://mathexamtest.web.fc2.com/2020/202011205/2020112050100mj.html#top-0102

# sympyで(positiveで)

```python
from sympy import *
a=Symbol('a', positive=True)
b=Symbol('b', positive=True)
c=Symbol('c', positive=True)
O=Point(0,0,0)
A1,B1,C1=map(Point,([  sqrt(a),0,0],[0,  sqrt(b),0],[0,0,  sqrt(c)]))
A2,B2,C2=map(Point,([1/sqrt(a),0,0],[0,1/sqrt(b),0],[0,0,1/sqrt(c)]))
H1=Plane(A1,B1,C1).projection(O)
H2=Plane(A2,B2,C2).projection(O)
print("#(1)",H1)
print("#(2)",H2)
print("#(3)",(H1-O).dot((H2-O))/(O.distance(H1)*O.distance(H2))           )
print("#(3)",(H1-O).dot((H2-O))/(O.distance(H1)*O.distance(H2)).simplify())
#(1) Point3D(sqrt(a)*b*c/(a*b + a*c + b*c), a*sqrt(b)*c/(a*b + a*c + b*c), a*b*sqrt(c)/(a*b + a*c + b*c))
#(2) Point3D(sqrt(a)/(a + b + c), sqrt(b)/(a + b + c), sqrt(c)/(a + b + c))
#(3) 3*a*b*c/((a + b + c)*(a*b + a*c + b*c)*sqrt(a/(a + b + c)**2 + b/(a + b + c)**2 + c/(a + b + c)**2)*sqrt(a**2*b**2*c/(a*b + a*c + b*c)**2 + a**2*b*c**2/(a*b + a*c + b*c)**2 + a*b**2*c**2/(a*b + a*c + b*c)**2))
#(3) 3*sqrt(a)*sqrt(b)*sqrt(c)/(sqrt(a + b + c)*sqrt(a*b + a*c + b*c))
```


# sympyで(varで)

```python
from sympy import *
var('a b c')
O=Point(0,0,0)
A1,B1,C1=map(Point,([  sqrt(a),0,0],[0,  sqrt(b),0],[0,0,  sqrt(c)]))
A2,B2,C2=map(Point,([1/sqrt(a),0,0],[0,1/sqrt(b),0],[0,0,1/sqrt(c)]))
H1=Plane(A1,B1,C1).projection(O)
H2=Plane(A2,B2,C2).projection(O)
print("#(1)",H1)
print("#(2)",H2)
print("#(3)",(H1-O).dot((H2-O))/(O.distance(H1)*O.distance(H2))           )
print("#(3)",(H1-O).dot((H2-O))/(O.distance(H1)*O.distance(H2)).simplify())
#(1) Point3D(sqrt(a)*b*c/(a*b + a*c + b*c), a*sqrt(b)*c/(a*b + a*c + b*c), a*b*sqrt(c)/(a*b + a*c + b*c))
#(2) Point3D(sqrt(a)/(a + b + c), sqrt(b)/(a + b + c), sqrt(c)/(a + b + c))
#(3) 3*a*b*c/((a + b + c)*(a*b + a*c + b*c)*sqrt(a/(a + b + c)**2 + b/(a + b + c)**2 + c/(a + b + c)**2)*sqrt(a**2*b**2*c/(a*b + a*c + b*c)**2 + a**2*b*c**2/(a*b + a*c + b*c)**2 + a*b**2*c**2/(a*b + a*c + b*c)**2))
#(3) 3*a*b*c/(sqrt(a*b*c/(a*b + a*c + b*c))*(a + b + c)*(a*b + a*c + b*c)*sqrt(1/(a + b + c)))
```
アナログな拠点間データ転送の話

謎のアドベントカレンダー、第 15 話です。

これは大体いまから 15 年ほど前の話です。

昔といえば昔ですが、大昔というほどでもないです。

## 士業の事務所は紙の資料だらけ

筆者の勤務先の母体は税理士事務所（税理士法人）だったりするわけですが（社労士など別の士業もやってます）、例年、2 月 3 月は確定申告の繁忙期で、社外向けに SaaS を提供している筆者の所属会社のメンバーも色々支援をしていました。

（ただし素人がやる作業が本当に「支援」になっていたかは不明）

で、筆者は当時体調面で問題を抱えていて、事務所内で書類を見て細かい作業をするのが辛かったので、少し離れた地域にある事務所との間を往復して、ひたすら書類を運んでいました。

微妙な距離だったので一部高速道路も使いましたが、トラブルの度に郊外のデータセンターに繰り返し通っていたので、ある意味通い慣れていたともいえます。

## 当時は

いまも紙の書類が多い業界ではあるものの、当時は電子申告も始まったばかりの使いづらいシステムで、ひたすら紙・紙・紙、でした。

入力チェックも紙に出力するのが基本（これはいまも多分そう）。

（確定申告の期日ギリギリ、というか日付が変わって消印が翌日付けになってしまう場合、管轄の税務署のポストに直接申告書を投函するムーブとかもあったりなかったり）

まだクラウド黎明期で大容量のデジタルデータを安全に保管する手段も少なく、遠隔地にデータを送るための回線も貧弱でした。

もちろん、顧問先の会計データは会計ソフトで入力してデジタル管理していましたが、それ以外の関連書類はほとんどが紙でした。

そういうわけで、「物理の運搬も大事」だったのでした。

## いまは

良い時代になりましたね。

電子申告も（問題はあれど）当時とは比べ物にならないぐらい「使える」ものになりましたし。

というわけで、今回は IT っぽい話はありません。

フィジカル大事。

---

16 日目の記事に続きます。

- **[リモートアクセスで困った話 (1)](https://qiita.com/hmatsu47/items/84f23351fb21e89bae70)**

https://qiita.com/hmatsu47/items/84f23351fb21e89bae70
[Day15] エラーハンドリング

本記事は一人アドベントカレンダー企画の一つです。
[30代未経験エンジニアが25日後にJavaScriptをマスターするカレンダー](https://qiita.com/advent-calendar/2022)

[JAVASCRIPT.INFO](https://ja.javascript.info/)を元にJavaScriptを勉強していき、そこで学んだ知識をアウトプットしていきます。
２５日でJAVASCRIPT.INFOをやりきり、未経験エンジニアがJavaScriptをマスターする過程を投稿していきます。



## 10.1 エラーハンドリング, "try..catch"
### 知らない単語
- コントロールフローとは
    - 受信側の処理が追いつかずにデータを取りこぼしたりするのを防ぐため、通信状況に応じて送信停止や速度制限などの調整を行う機能


### 学んだこと
- “try…catch” 構文

普通はエラーが発生するとスクリプトは即時に停止し、それをコンソールに出力するが、
「try..catch」を使用する事でエラーがあった時にcatchに入り、処理が停止しない
書き方は
```javascript
try {

  // code...

} catch (err) {

  // error handling

}
```
となっていて、(err)がある事でエラーになった場合、エラーの中身を見る事ができる

- try…catchの利用

JavaScriptで JSON.parse(str) を使う場合、
```javascript
let json = "{ bad json }";

try {

  let user = JSON.parse(json); // <-- エラーが起きたとき...
  alert( user.name ); // 動作しない

} catch (e) {
  // ...実行はここに飛ぶ
  alert( "Our apologies, the data has errors, we'll try to request it one more time." );
  alert( e.name );
  alert( e.message );
}
```
json が不正な形式の場合、JSON.parse はエラーになるのでスクリプトは停止する
この書き方では、もしデータが間違っている場合、間違っている事自体がわからないので、
どのようなエラーかを知る為に try..catch を使った方がよい
自分で怪しいと思った箇所にはtry..catch を入れてもいいかもしれない

- Throw演算子

Throw演算子は自分の出したいエラーを出せる
書き方は
```javascript
throw <error object>
let error = new Error(message);
```
であり、通常のブラウザが出してくるエラーより自分で設定したエラーの方が読みやすい

- 再スロー

catchに入ってもエラーを出すことができる

- try…catch…finally

finallyはtryの後でもcatchの後でも入る
最後に処理を加えたい時に使用する

### 感想
try…catchは自分でエラーが出るかチェックでき、Throw演算子は自分なりのエラー表示ができるので、自由度が高く便利である。


## 10.2 カスタムエラー, Error の拡張
### 知らない単語
- 無し


### 学んだこと
カスタムエラー

Throw演算子は自分でエラーメッセージが作れるが、カスタムエラーはさらに細かいものである
コードの書き方は
```javascript
// JavaScript自体で定義された組み込みのErrorクラスの「擬似コード」
class Error {
  constructor(message) {
    this.message = message;
    this.name = "Error"; // (組み込みのエラークラスごとに異なる名前)
    this.stack = <nested calls>; // 非標準だが、ほとんどの環境はサポートしている
  }
}
```
というようになり、class Error が決まりになっている

- さらなる継承

簡単に言えば、「class ValidationError extends Error」で1番細かいエラーを作る事ができる
```javascript
class ValidationError extends Error {
  constructor(message) {
    super(message);
    this.name = "ValidationError";
  }
}
```

- 例外のラッピング

下記のコードでは2種類のエラーがある
```javascript
try {
  ...
  readUser()  // 潜在的なエラーの原因
  ...
} catch (err) {
  if (err instanceof ValidationError) {
    // バリデーションエラーの処理
  } else if (err instanceof SyntaxError) {
    // シンタックスエラーの処理
  } else {
    throw err; // 未知のエラー、再スロー
  }
}
```
要は、バリデーションエラーとシンタックスエラーの時で違う処理を書く事ができる

### 感想
エラーメッセージはかなり自由に変更する事がよくわかる。実務でもよく使用する事になるのかはわからないが、わすれないようにする。

# 最後に
元ページに書いてある事をかなり簡単に要約しているが、解釈が間違っている可能性もあるので、自分で詳しく調べたり、周りのエンジニアに聞いて正しい知識を身につけたい。
2つの文字列の末尾に対して一致・不一致を判断するプログラムの実装

# 問題
2つの文字列の末尾の文字を比較して、一致する場合はTrue、
一致しない場合はFalseを出力するプログラムを実装します。

以下の要件を満たすend_otherメソッドを実装しましょう。

- メソッドの引数に、任意の2つの文字列を指定する。
- 引数に指定された2つの文字列のうち、
　どちらかがもう一方の文字列の末尾にある場合は、Trueを出力する
- 上記を満たせていない場合は、Falseを出力する
- 入力した文字が大文字でも小文字でも、同一の文字として処理を行う

##### 雛形
~~~ruby
def end_other(a, b)
  # 処理を記述
end

# 呼び出し例
end_other('Hiabc', 'abc')
~~~

# 解答
~~~ruby
def end_other(a, b)
  a_down = a.downcase
  b_down = b.downcase
  a_len = a_down.length
  b_len = b_down.length
  if b_down.slice(-(a_len)..- 1) == a_down || a_down.slice(-(b_len)..- 1) == b_down
    puts "True"
  else
    puts "False"
  end
end

# 呼び出し例
end_other('Hiabc', 'abc')
~~~

# 解説
sliceメソッドは配列から要素を取り出す事ができる。
~~~ruby
array = ["Ruby","Python","Java"]
p array.slice(0)
~~~
実行結果
~~~ruby
"Ruby"
~~~
逆にマイナス使って、配列の最後の要素から取り出すこともできる
~~~ruby
array = ["Ruby","Python","Java"]
p array.slice(-1)
~~~
実行結果
~~~ruby
"Java"
~~~

解答では
~~~ruby
a_down = hiabc
b_down = abc
a_len = 5
b_len = 3
~~~
と代入されている。
if文でabcの最後にHiabcが含まれているか、
Hiabcの最後にabcが含まれているか判別している。

#### 左辺
**b_down.slice(-(a_len)..- 1)** は、 **b_down.slice(-5..-1)**
**b_down = abc** となっているので範囲外(-5もない)
為切り取る事ができない。
その結果、nil == a_downとなるのでfalseが返される。

#### 右辺
**a_down.slice(-(b_len)..- 1)** は、 **a_down.slice(-3..-1)**
インデックス番号-3から-1という条件で切り取るとabcが残る。
結果、abc == b_downとなるので、trueで返される。
Stablediffusionをファインチューニングして校長Diffusionを作ってみた

この記事は[N/S高等学校 Advent Calendar 2022](https://qiita.com/advent-calendar/2022/n-s-highschool)の13日目です。
N高生です。普段はBlenderでモデリングをしています。

# はじめに
Stable Diffusion2.0がリリースされ人物画像の生成能力が上がったらしいので試してみたいと思い触れてみました。
ついでならファインチューニングもやってみて誰かを無限に生成したいな、と思ったのでS高校長に許可をもらいやってみました。感謝。

# Stable Diffusionとは
>Stable Diffusion（ステーブル・ディフュージョン）は、2022年に公開されたディープラーニング（深層学習）のtext-to-imageモデルである。主にテキスト入力に基づく画像生成（text-to-image）に使用されるが、他にもインペインティング、アウトペインティング、テキストプロンプトによって誘導される画像に基づく画像生成（image-to-image）にも使用される

[参考]
[ウィキペディア](https://ja.wikipedia.org/wiki/Stable_Diffusion)

ということで、話題の画像生成AIです。

# ファインチューニングとは
既存のモデル(ここではStablediffusion)に数枚の画像を追加学習させて新しい概念を学習させることです。
なので数枚画像があれば特定の人物や絵柄に寄せることができます。
Twitterなどで話題になっていたWiafu DiffutionなどはStable Diffusionをファインチューニングしたものです。

ファインチューニングには純粋な追加学習やDreambooth, Hypernetwork, DreamArtistなど様々な手法がありますが今回はDreamboothで行います。

# 環境
* GPU: RTX 3060
* RAM: 16G
* Docker 20.10.21
* dreambooth-gui v0.1.9 - alpha
* stable-diffusion-webui

# Dreambooth-GUIのインストール

stable-diffusion-webuiの追加機能にもDreamboothはあるのですがVRAMが足らず途中で落ちてしまうためこちらを使用します。(11/30 時点)
こちらはVRAMが10Gでもぎりぎり動くそうです。
[dreambooth-gui](https://github.com/smy20011/dreambooth-gui)のInstallに沿って進めていきます。

1. Dockerをインストール
2. WSL2をインストール
3. dreambooth-guiをインストール

# 学習元の準備
画像を10枚用意し学習したい人物以外の背景部分を白で塗りつぶします。
背景を白で塗りつぶすと学習を強くしたときに単純な背景になりやすいようですが今回は行いました。
そして背景部分に変な塗り残しがあるとそのミスも学習してしまうのできれいに切り抜くようにします。


# 実行
Dockerを起動しそのあとdreambooth-guiを起動します。
どちらも管理者権限で実行します。

そして用意した学習画像を読み込みます。
<img width="400" alt="image1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2988539/cf509bb8-cba4-e49a-a836-77dd314b48aa.png">

Config Trainerのタブで学習設定を行います

`Model` モデルを選択します
`Instance prompt` 学習する物の名前を決めます。既にある名前は避けることが望ましいです。
`Class prompt` どんなものなのかを決めます。
`Training Steps` どのくらい学習するのかを決めます。今回は1000でやります。
このステップを上げると再現性が上がっていきますが、一定の値を超えると過学習状態になってしまい出力される画像が崩壊してしまうので注意が必要です。

<img width="700" alt="image2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2988539/c14194d9-baf1-5354-a29b-d0f4fbb707d3.png">

あとは実行するだけです。


# 結果
ここで問題が発生しました。
SD2.0ではText Encoderが大きくなっており、VRAMが12Gでは足りないことが判明しました。
なんてこったい
なのでここではSD1.5で行います。

# モデルの実行
stable-diffusion-webuiでSifueDiffusionを使って画像生成します。

<img width="400" alt="image3.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2988539/c9a24144-0b09-f0b5-2651-6665f38ba767.jpeg">

<img width="400" alt="image4.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2988539/1fa6a9f9-dd0b-2640-2f8d-68def47c79dd.jpeg">

タコスを食べる校長とライオンと戯れる校長が生成できました。
スーツを着ている画像しか学習していないのでかなりの確率でスーツを着ます。

<img width="400" alt="image5.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2988539/68a4cf65-bc89-504d-fda2-f4e1ee3eaf90.jpeg">

学習は写真で行ったのですが絵画風にしたりもできます。


# まとめ
校長を無限に生成することに成功した。
改善点としては、まだ知らないおじさんが生成される確率が高いので学習を進めたり、SD2.0でor2.1での学習がある。
Slackの#ai-artでは様々なAIの話題などで交流できるので気になった方はぜひ。

# 参考サイト
[画像生成AI「Stable Diffusion」にたった数枚のイラストから絵柄や画風を追加学習できる「Dream Booth」が簡単に使える「Dreambooth Gui」レビュー](https://gigazine.net/news/20221103-dreambooth-gui/)
NPF(NetBSD Packet Filter)でパケットフィルタログを確認してみる

[NetBSD Advent Calendar 2022](https://qiita.com/advent-calendar/2022/netbsd) 12日目の記事です。今日はNPF(NetBSD Packet Filter)でフィルタログを確認する手順を紹介しようと思います。

## 実験用のネットワーク環境

まずはNPFでパケットフィルタの動作を試してみる実験環境を示します。今回は以下のように、2台のマシンを接続し、ホスト `h1` から `nr` へのICMPをフィルタする例で確認してみます。

```
    (n1)            (nr)
 172.17.0.2<---->172.17.0.1
```

## フィルタルールの例

NPFでのフィルタルールは以下になります。"icmp rule"グループにICMPをブロックするルールを記述しています。また、[11日目の記事](https://qiita.com/furandon_pig/items/0e6fe3065ae6ec32ad0d)のMSSクランプでも解説しているように、 `procedure` で宣言した内容は、フィルタルール側で `apply` しないと適用されません。NPFのフィルタログ機能もMSSクランプと同じく、拡張機能として実装されているため、 `procedure "log"` のような形で宣言しておき、マッチしたルールで `apply` します。

また、ICMPグループ内で宣言したルールにマッチした時点でフィルタ処理を行ないため、 `block {in|out} final ...` のように、 `final` キーワードを付与しておきます。

```
$int_if = "wm1"

# The logging facility can be used together with npfd(8).
procedure "log" {
  log: npflog0
}

group "icmp rule" {
  block in  final on $ext_if proto icmp all apply "log"
  block out final on $ext_if proto icmp all apply "log"
}
```

## NPFでのロギングはnpfdを動作させておく点に注意

NPFでログを記録するサンプルが[npf.conf(5)](https://man.netbsd.org/npf.conf.5)にありますが、そこには以下のようなコメントがあります。どうやらログを記録する場合は、フィルタルール側の設定だけでなく、併せて[npfd(8)](https://man.netbsd.org/npfd.8)という、ロギングと状態同期用のデーモンを動かしておく必要があります。

> procedure "log" {
>     # The logging facility can be used together with npfd(8).
>     log: npflog0
> }

さっそく `npfd` を動かします。これで準備は完了です。

```sh
$ sudo /etc/rc.d/npfd onestart
```

## NPFのパケットフィルタログを確認する

さっそく動作確認してみます。まずは `npfctl start` でパケットフィルタ動作を有効化します。

```sh
$ sudo npfctl start
$ sudo npfctl reload
```

前述した `n1` から `nr` に対し、 `ping` を実行します。想定通り応答が返ってこないため、パケットフィルタでICMPパケットがブロックされているようです。

```sh
ping -c 4 172.16.0.1
PING 172.16.0.1 (172.16.0.1): 56 data bytes
(応答が返ってこない(想定通りの挙動))
```

本当にパケットフィルタで止められているか確認してみます。`npfctl stats` でブロックしたパケットの数が確認できるため、ホスト `n1` 側で `ping` を実行したまま、ホスト `nr` 側で以下のようなコマンドを実行してみます。

```sh
$ sudo npfctl stats | grep -i block ; sleep 3 ; sudo npfctl stats | grep -i block
Packets blocked:
        0 default block
        337 ruleset block
Packets blocked:
        0 default block
        340 ruleset block
```

ブロックされているパケット数が増加しており、ちゃんとパケットがブロックされていることが分かります。

## パケットフィルタログを確認してみる

パケットフィルタログを確認してみます。ログの設定は `log: npflog0` のように記述し、この例では `/var/log/npflog0.pcap` というファイルにログが記録されます。

```
procedure "log" {
    log: npflog0
}
```

これはpcapファイルであるため、[tcpdump(8)](https://man.netbsd.org/tcpdump.8)コマンドで内容を確認できます。

```sh
$ sudo tcpdump -enr /var/log/npflog0.pcap
...
07:03:29.133664 rule 5.rules.0/0(match): block in on wm1: 172.17.0.2 > 172.16.0.1: ICMP echo request, id 518, seq 300, length 64
07:03:30.132875 rule 5.rules.0/0(match): block in on wm1: 172.17.0.2 > 172.16.0.1: ICMP echo request, id 518, seq 301, length 64
```

`n1` (172.17.0.2)から `nr` (172.16.0.1)への `ICMP echo request` をブロックしたというログがバッチリ残っていますね。

## まとめ

NPFでパケットフィルタログを確認する手順を紹介しました。今回の例では単一のpcapファイルにログを記録していますが、 `procedure` でのロギング宣言を複数行うことで、フィルタルール毎にログを変えるという運用もできそうです。
盾と矛。セキュリティ。類似の構造。

# 矛盾

盾（防御）は、すべての矛（攻撃）を防ぐ必要がある。　
矛（攻撃）は、一つの矛（攻撃）を破ればよい。

どちらが簡単か想像がつくだろう。　

# セキュリティ　

防御側は、すべての脆弱性を防ぐ必要がある。
攻撃側は、一つの脆弱性を破ればよい。　

どちらの仕事が楽だろうか。

# 類似の構造



## 試験の１番　

試験で１番を取り続ける人がときどきおみえになります。　
私も中学の頃、万年２番で、１番の独創を許していました。

どうして、１番のは、独創できるかわかりませんでした。　

何年か後になって、全く別の種類の試験では、１番を取ることができました。　
ある領域を絞った試験は、盾と矛、セキュリティとは条件が違う点に気がつきました。　

盾と矛、セキュリティでは、攻める側が規則を作れるのに対して、　
試験の１番は、攻める方とも守る方とも違うところで規則が決まっている。


## 文学賞
賞をとると敵は多数。　
賞を取らないと敵は賞を取った一人。

賞を取るつもりがあると、いつまでの敵は減らない。　
賞を取らずに、賞を取った人を超えるなにかを見つけるだけでよければ簡単。　

盾と矛、セキュリティと似ているかもしれない。
試験の１番と同じで、攻める方とも守る方とも違うところで規則が決まっている。

　# Advent Calendar 2022

今年企画した４つのAdvent Calendarと、それぞれの記事一つをご紹介します。

AUTOSAR Advent Calendar 2022

https://qiita.com/advent-calendar/2022/autosar

AUTOSAR References to ISO, IEC, ITU, IEEE, RFC and SEA etc.

https://qiita.com/kaizen_nagoya/items/d7d252211e10a79516df

Automotive Handbook Advent Calendar 2022

https://qiita.com/advent-calendar/2022/automotivehandbook

Basic principles, ボッシュ自動車handbook(英語)11版まとめ<2>

https://qiita.com/kaizen_nagoya/items/24a1ba5da3d09b2a95d1


2022 いいねをいただいた記事ランキング(O.K.版) Advent Calendar 2022

https://qiita.com/advent-calendar/2022/goods

2022年１月下旬　いいねをいただいた記事　16

https://qiita.com/kaizen_nagoya/items/0ee589a8edaeab24fd2a

AdCale(O.K.) Advent Calendar 2022

https://qiita.com/advent-calendar/2022/adventcalendar2022

「会議は15分未満」に。小耳にはさんだ話。

https://qiita.com/kaizen_nagoya/items/510c47c5d1e8d03145db

AdvencCalendar2022 報告

https://qiita.com/kaizen_nagoya/items/5b4b99cb9ad571f4094b


誤差の評価が苦手（専門分野以外）

https://qiita.com/kaizen_nagoya/items/cc3a50827b24ab80985f



 ＜この記事は個人の過去の経験に基づく個人の感想です。現在所属する組織、業務とは関係がありません。＞


# 文書履歴(document history)
ver. 0.01 初稿 20221212
要求と要件と仕様

システム開発やプログラム開発をしていると必ず出てくるけど、
よく意味の分からない単語などをメモする備忘録です。

自分の場合は、システム開発の工程としてこんな感じでよく作業してます。
[要件定義] - [概要/概念/基本設計] - [詳細設計] - [開発]（製造） - [試験](単体 - 結合 - システム - 受入)  - [運用]
今回は要件定義の周りをメモします。（次回があるかは不明です）

# ◆要求と要件と仕様

## それぞれの意味
 **要求**
　顧客がやりたいこと、必要なもの。
　例のあれですね(笑)
　※「顧客が本当に必要だったもの」でぐぐってね。

 **要件**
　顧客がやりたいことを実現するために必要なこと

 **仕様**
　要件を実現するためのもの

 **いや、どうなんだよ。 余計わからなくなったわ。**

# ◆うるう年で考えてみる

 **要求**
　正確な1年は365日5時間48分45.168秒であり、400年間で97日のずれが生じることが分かった。
　これを何とか是正したい。← **顧客のやりたいこと**

 **要件**
　では、400年間で97日をどこに入れるか。
　案.400年に一回だけ97日足す。← いや、400年とか忘れるわ。
　案.4年ごとに1日足す。← 3日オーバーするわ
　案.4年ごとに1日足す。但し、100で割り切れる年で400で割り切れない年が400年で3回あるので例外← それにしよう！

　みたいな会議があったとか（笑）
　※実際には、長い時間をかけて議論と調査、調整があったそうな。

 **仕様**
　400で割り切れる年はうるう年
　100で割り切れる年はうるう年ではない
　4で割り切れる年はうるう年

って見てみると、結構違いが分かるかな？

# ◆まとめ

実際の現場だと、顧客から出てくるのが要求と要件の真ん中みたいなのでよく惑わされたりしますが、
ただ顧客の言うことをするのではなく、本当にしたいことを一緒に考えると開発が楽になったりしたらいいなーと思います。
AIと作るグリードアイラ〇ド～DB設計編～

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181863/af4445d6-8808-4f42-ca4a-3a3a0a97beba.png)
最近ChatGPTを触りまくっている。兼ねてから作りたかったグリードアイラ〇ドをAIプログラマーと共に作成していきたいと思う。

まずは魔法カードのDB設計をやらせてみた。

前提として、魔法カードの詳細は全てを既に送り付けている

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181863/2310ed17-9732-3fb0-9a6d-08b1ff7a6827.png)

フィールドを歩き回れる系のゲームなら座標が足りないとか色々ありそうだが一旦これでOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181863/f712510b-e3fa-c39a-6e5d-32be817b3025.png)

バインダーもOK

今日はここまで、
いいね(?)があれば続けるかもしれません
【個人開発】料理の盛り付けレベルを判定してくれる機械学習を作成しました【暇つぶしWEBアプリ】


# はじめに

先日、【大人の盛り付けcom】というWEBサイトを作成した記事を投稿しましたが、
作成中に、機械学習の勉強をしてみたいと感じ、
【盛り付けレベルを判定してくれるAI】なるものを作成してみました。

https://qiita.com/bluenouni/items/b68004c832e000035fa9

次の見出しから、概要をご紹介します。
＊しかし、ローカルでは動くのに、herokuにデプロイしたらエラーが出てしまう状況が続いております。
　もし原因がお分かりの方いらっしゃりましたらアドバイスくださると嬉しいです🙏




# サービス概要


①TOPPAGEを開きます。
![top.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2866856/42e3bc05-f74a-478a-e97a-1229345b4275.png)


②ファイルを選択し、アップロードボタンクリック
![normal1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2866856/3e076a45-4ba8-1b49-6024-e93c090c5194.png)


### 普通クラス！！！

③他の画像でも試してみる（汚い盛り付けでやってみた）
![duty1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2866856/d4c9fc29-1c8c-4c29-cf0f-4a542b445144.png)


### もう少し綺麗に盛り付けましょう！！！が出た



Twitterの方で動画あるので、是非みていただけたらと思います！


https://twitter.com/blue_no_uniuni


# 使用技術について

モデルの学習はGooglecolabを用いて行いました

https://zenn.dev/zzz/articles/970e5df5cf1f65


画像投稿フォーム作成やviewsはこちらの中に記載のあったgithubを参考にしました！

https://stefanbschneider.github.io/blog/pytorch-django



# 限界

＊今回、「最高クラス」「普通クラス」「もっときれいに盛り付けましょうクラス」と３つに分類するよう機械に学習させました。
20枚ずつ画像を使用しましたが、「最高クラス」が何度やっても出ないのです。。
普通クラスと最高クラスの見分けの精度がまだまだ不十分でした。


# 困ったこと

### ローカルでは動くものの、デプロイ後にはエラーが出てしまう。


![localerror.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2866856/126a02e4-b364-c067-133d-3eda471d66c4.png)






### herokuにデプロイする際にPytorchの容量が大きすぎて全くデプロイが最初できなかった。
困って色々調べた結果、、自身がやってみて、容量を減らせたコツをブログにまとめたので、
同じくPytorchで今後herokuデプロイを考えている人は見てほしい


https://blueninini.com/bluenislugsize/

参考サイトはここ！

https://qiita.com/kawai_qt/items/2c04c94eb16cadb9c64f



# 終わりに

初めて機械学習を使用したものを作ってみました。
学習させるところから、精度を上げていくところ、、、と本当に試行錯誤しながらでしたが、
機械学習がどのように行われているのか、を入門書で読みながら作ると良いかもしれないと感じました。

なかなかPytorchのネット記事はまだまだ少ないです。。
スクールの先生に教えてもらいながらでしたが、これからどんどん精度を上げていきたいと思いました。
そしてエラーの解消も・・・・
【SwiftUI】Combineでキーボードを監視する

# はじめに
私は現在カスタムキーボードを作成していて、キーボードの状態を知る方法を色々試しています。
この方法はCustomKeyboardExtensionでは使用できませんでしたが、メインターゲットでは使用できました。
せっかく試したので記事にしておきます。

# サンプルアプリ
ちょっと見にくいですが、以下の2項目を表示しています。
- キーボード状態(開いている or 閉じている)
- キーボードサイズ(width, height)
![RPReplay_Final1670849788_MP4_AdobeExpress.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/b335fb1b-9182-a355-9d53-a64fab4642d1.gif)


# 実装
### View
```swift:ContentView
import SwiftUI

struct ContentView: View {
    @StateObject private var viewModel = ViewModel()
    var body: some View {
        NavigationStack {
            List {
                TextField("タップしてください", text: $viewModel.text)

                LabeledContent {
                    Text(viewModel.keyboardStatus.rowValue)
                } label: {
                    Text("状態")
                }

                LabeledContent {
                    Text(viewModel.keyboardRect.size.debugDescription)
                } label: {
                    Text("サイズ")
                }
                Button {
                    viewModel.closeKeyboard()
                } label: {
                    Text("キーボードを閉じる")
                }
            }
            .navigationTitle("キーボード監視")
        }
    }
}
```

### ViewModel
```swift:ViewModel
import Combine
import UIKit

final class ViewModel: ObservableObject {
    @Published var text: String = ""

    @Published var keyboardStatus: KeyboardStatus = .hide

    @Published var keyboardRect: CGRect = .zero

    private let notificationCenter = NotificationCenter.default

    private var cancellable = Set<AnyCancellable>()

    init() {
        notificationCenter.publisher(for: UIResponder.keyboardDidChangeFrameNotification)
            .sink { [weak self] notification in
                guard
                    let self,
                    let userInfo = notification.userInfo,
                    let rect = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect
                else { return }

                self.keyboardRect = rect

                if rect == .zero {
                    self.keyboardStatus = .hide
                } else {
                    self.keyboardStatus = .show
                }
            }
            .store(in: &cancellable)
    }

    func closeKeyboard() {
        UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
    }
}
```

### Model
```swift:KeyboardStatus
import Foundation

enum KeyboardStatus {
    case show
    case hide

    var rowValue: String {
        switch self {
        case .show:
            return "開いている"
        case .hide:
            return "閉じている"
        }
    }
}
```

# おわり
[助けを求む] Blazor Server を Playwright で E2E テストするとき、Playwright の初動が早すぎてテストが失敗する

## Playwright で Blazor Server の E2E テストを書いたらテスト失敗するようになってしまった!

Blazor アプリケーションのエンド・ツー・エンド (End-to-End, 略して E2E) テストを実装する際、ここ最近は Selenium ではなく、Playwright (の .NET バインディング) を使って Web ブラウザの自動操作を実装しています。

https://playwright.dev/dotnet/

先日も、とある手持ちの Blazro Server アプリケーションの E2E テストを、Seleinum を使って実装していたところを、Paywright を使った実装に置き換えたりしていました。

すると、その Playwright を使うように変更した Blazor Server アプリケーションの E2E テストが失敗するようになったのです。

例えば、Blazor プログラマであればお馴染みであろう (?)、例の「カウンター」ページの E2E テストを実装しているとしましょう。この「カウンター」ページの「Click me」ボタンをクリックしたら、カウンターの数字が 0 から 1 になっていることをテストする、とします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58450/02ba3662-c4f2-0d6b-e286-7a57f5a757d3.png)
Selenium で実装していたころはこのテストはもちろん成功していました。しかし、Playwright に置き換えて以降、このテストが失敗するようになってしまいました。失敗の原因は、**カウンターの数字が 0 のままで、1 に加算されない**、というものです。「Click me」ボタンが見つからないとかそういう原因ではないのです。一体何が起きているのでしょうか。

## もしかして... Playwright が早すぎる!?

いろいろ探っていくうちに、どうやら、次のような動作になっているのではないかと推測されるに至りました。

- (既定の実装だと) Blazor Server はサーバー側でプリレンダリングされる
- Playwright で自動操縦されている Web ブラウザが、このプリレンダリングされたコンテンツを読み込んで表示する
- ただし、**プリレンダリングされたコンテンツを読み込んで表示した直後**は、**サーバー側との SignalR 接続が確立され、かつ、すべてのイベントハンドラが配線される前のタイミング**が存在する!
- **Playwright の動作が高速**であることによって、この Blazor Server 起動時の**絶妙なタイミング**で、Playwright が (プリレンダリングされた)「Click me」ボタンをクリックしてしまう?
- しかし、「Click me」ボタンは (プリレンダリングされているので) たしかに存在するものの、**イベントハンドラは配線前**なので、ボタンクリックに対するカウンター加算は起動されない。結果、「Click me」ボタンをクリックしてもカウンターは 0 のまま!

上記仮説が正しいとして、サーバー側プリレンダリングを止めると、このようなことは起きなくなるのかもしれません。しかし、せっかくのサーバー側プリレンダリングはこのまま維持したいため、プリレンダリングを止めるという選択は避けたいです。どうしたらよいでしょうか。

## とりあえずの回避策を実装したものの...

今のところは、Blazor Server アプリケーション側に以下の "仕込み" を入れて、この E2E テストの失敗を回避するようにしました。

- `console.log` を呼び出せる JavaScript ヘルパ関数を用意
- Blazor Server の `MainLayout.razor` にて、**`OnAfterRenderAsync` のタイミング**で `IJSRuntime.InVokeAsync` を使って上記 JavaScript ヘルパ関数を呼び出し、"The Blazor Server app has been started." というテキストを `console.log` で出力
- Playwright による E2E テスト実装側では、ページナビゲーション後、**その `console.log` 出力を [`WaitForConsoleMessage`](https://playwright.dev/dotnet/docs/api/class-page#page-wait-for-console-message) で待機**してから、続くボタンクリックなどのテストを実行する

Blazor Server 側で Razor コンポーネントのライフサイクルメソッド `OnAfterRenderAsync` が呼び出されるタイミングは、ブラウザ側との接続も確立され、初回のレンダリングが完了した後になりますから、Playwright による E2E テストもこのタイミングに歩調を合わせることで、テストが安定化したと考えられます。

## もっとマシなやり方があれば教えてもらえると嬉しいです!

...ということで、どうにかこの「Playwright の初動が早すぎてテストが失敗する」問題をねじ伏せたものの、本来であれば無用な `console.log` 出力があるのが納得いきません。Blazor Server 側にこのような "実装" "改造" が必要なのも、汎用性がなくイヤです。E2E テスト実装側でページナビゲーション後に数百ミリ秒の待機を差し込むことでも改善できるかもしれませんが、これまた、そのような微妙なマジックナンバーの待機を挟むのも、もうこりごりです。

何か他に上手い方策はないでしょうか、もっとマシなやり方があれば教えてもらえると嬉しいです!
【Playdate】動画をクランクで操作してみる

[前回](https://qiita.com/sada_lp1/items/10b8edbc707bd6dedcc9)の動画再生プロジェクトを改造してクランクを回すことで動画の早回し、巻き戻しを実装してみます。
main.luaを以下のように更新しました。

```main.lua
-- 略 --

local CRANK_THREAD <const> = 2 -- 回したとされるしきい値
-- クランク回転
function playdate.cranked(change, acceleratedChange)
	if math.abs(acceleratedChange) > CRANK_THREAD then
		-- 再生している場合、コマ送りする
		-- NOTE: audio:setOffsetが動くのは　audio:isPlaying() == true　のときのみ
		if audio:isPlaying() == true then
			if acceleratedChange > 0 then
				local newTime = audio:getOffset() + 0.1
				audio:setOffset(newTime)
			else
				local newTime = audio:getOffset() - 0.1
				audio:setOffset(newTime)
			end
		end
	end
end

-- 略 --
```

`playdate.cranked(change, acceleratedChange)`でクランクを回したときの実装を記述しています。
時計回り、反時計回りの回転加速度を`acceleratedChange`で取得してしきい値を超えると現在の再生位置から0.1ずつ早回しまたは巻き戻しし、新しい再生位置をセットしています。
音声の再生位置を調整しているのは、前回解説の通り音声の再生位置から動画の現在のフレーム位置を求めているためです。
注意点としてはコメントの通り、`audio:setOffset`が動くのは`audio:isPlaying() == true`のときのみなので描画が更新されないときはこのあたりを見てみるとよいです。

以下がサンプルです。
![タイトルなし.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100912/896c0601-a645-b5c4-6b70-9518db3ae702.gif)
npmにパッケージを公開してみる

strapiとsupabaseをつなぐstrapi v4対応のupload providerがなかったので、自作のライブラリをnpmに投げることにしました。

https://www.npmjs.com/package/strapi-provider-upload-supabase-strage

その際に行ったことを書きます。

## ライブラリ名の重複を確認する

ライブラリ名の重複を確認しましょう。
当然ですが、被っていると公開できないです。


## リポジトリを作る

Githubリポジトリを作成しました。
この際、ライセンスファイルを手動で作成することが非常に面倒だったので、Githubに制作を任せています。
というか、このためだけに`gh`コマンドを使用せずわざわざブラウザ操作で手動で作成しました。

## 該当のリポジトリをクローンして中身を移す

自作ライブラリがいる場所にいたので、そこにクローンしてきて以下のコマンドで中身を取得しました。

```
mv strapi-provider-upload-supabase-strage/* ./
mv strapi-provider-upload-supabase-strage/.git ./
```

隠しファイルである`.git/`はワイルドカードで取ってこれなかったので個別に取得しています。(1敗)

## npmにログイン

公開用のメアドが必要なので、好き放題スパムが来ても良いよう新規にメアドを作成しました。
事前にnpmにアカウントを作成しておき、以下のコマンドでログインします。

```
npm adduser
```

yarnなどの癖で`npm add user`とかすると、当然ですがuserという謎のライブラリが落ちてきます。(1敗)
色々入力を求められるので、OTPがスムーズに認証できるようブラウザでメールフォルダを開いて準備しておきましょう。


## package.jsonにいろいろ書き足す

`homepage`や`repository`, 'author'や`engine`などを書き足していきます。
わたしの場合は、ちょうどstrapi v3まで対応していたsupabaseのproviderがあったのでそちらを参考にしました。

不安な場合は、著名なライブラリのpackage.jsonを見に行くとよいでしょう。

一通り書き終わったらgithubにpushします。

## tag付け

versionを付けます。
```
git tag -a <version> -m '<message>'
git push origin tags/<version>
```

こちらのコマンドでタグ付けができるので実行しましょう。
実行したらGithub上から手軽にtag -> versionができるので、ぽちぽちクリックしてversion1.0.0をリリースします。

## npmに公開

以下のコマンドで公開します。

```
npm publish ./
```

以上で完了です。
【Ruby】Gemのインストール先を確認する方法

## 確認方法

次のコマンドを実行することでGemのインストール先を確認できます。  

```terminal
gem environment gemdir
```

```terminal
$ gem environment gemdir
/usr/local/bundle
```

`gemdir`を除いて実行すると以下のような情報が出力される。  

```terminal
$ RubyGems Environment:
  - RUBYGEMS VERSION: 3.3.26
  - RUBY VERSION: 3.1.3 (2022-11-24 patchlevel 185) [aarch64-linux]
  - INSTALLATION DIRECTORY: /usr/local/bundle
  - USER INSTALLATION DIRECTORY: /home/ruby/.local/share/gem/ruby/3.1.0
  - RUBY EXECUTABLE: /usr/local/bin/ruby
  - GIT EXECUTABLE: /usr/bin/git
  - EXECUTABLE DIRECTORY: /usr/local/bundle/bin
  - SPEC CACHE DIRECTORY: /home/ruby/.local/share/gem/specs
  - SYSTEM CONFIGURATION DIRECTORY: /usr/local/etc
  - RUBYGEMS PLATFORMS:
     - ruby
     - aarch64-linux
  - GEM PATHS:
     - /usr/local/bundle
     - /home/ruby/.local/share/gem/ruby/3.1.0
     - /usr/local/lib/ruby/gems/3.1.0
  - GEM CONFIGURATION:
     - :update_sources => true
     - :verbose => true
     - :backtrace => true
     - :bulk_threshold => 1000
     - "install" => "--no-document"
     - "update" => "--no-document"
  - REMOTE SOURCES:
     - https://rubygems.org/
  - SHELL PATH:
     - /usr/local/bundle/bin
     - /usr/local/sbin
     - /usr/local/bin
     - /usr/sbin
     - /usr/bin
     - /sbin
     - /bin
```
データセンターなのに電源が全落ちした話

謎のアドベントカレンダー、第 14 話です。

前回の、

- **[ビルの電源が全落ちした話](https://qiita.com/hmatsu47/items/8f8304543acdeaba0fde)**

https://qiita.com/hmatsu47/items/8f8304543acdeaba0fde

から 10 年後の話です。

## 2006 年 8 月 14 日、事件は起きた

この日付でピンと来た方も割と多いのではないかと思います。

この頃、筆者の勤務先の社外向けサービスを、東京のデータセンターで運用していました。

というか、運用を他社に委託していました。

この日の朝、クレーン船がクレーンを伸ばした状態で（旧）江戸川を航行し誤って送電線に触れて溶断させたことをきっかけに、品川火力発電所が電力の需給バランスを崩して停止、東京湾周辺で大規模停電が発生しました。

## そのとき、某データセンターでは

商用電源の供給が止まるとともに UPS（CVCF）からの給電に切り替わり、いざ自家発電設備からの給電に切り替え！…ようとしたのに切り替えができず、そのうちバッテリーが尽きてサーバー室（ハウジング／コロケーションルーム）への電力供給がロスト。

結果、室内のサーバー・機器は突然停止、です。

当日は、停電により電車の運行に支障が生じたこともあってか、筆者の勤務先が運用委託していた会社のオペレーターの方も駆けつけるのが遅れ、復旧まで時間を要しました。

ただ、当日はお盆休みの会社も多く、サービスの利用者もそれほど多くなかったのが不幸中の幸いでした。

（10 年越しの伏線回収だ！）

## その後

データセンターを契約する際に、 **UPS や自家発電設備の点検とともに切り替え訓練を定期的に行なっているか** が選定の一つのポイントになりました。

とはいえ、切り替え訓練にはそれなりにリスクもあるので、 **過去何度もトラブルなく訓練できているか** もあわせて重視していました。

（他には、自家発電機と燃料タンクの設置場所、緊急時に燃料を運ぶ経路が建物崩壊などで全て塞がれたりしないか？などなど。燃料の優先供給については、東日本大震災でアテにならないことがわかったので、タンクの容量も大事かな、と）

## そして

筆者の勤務先のサービスは約 5 年前に AWS に全て移行し、その後はどちらかというと利用リージョン・ゾーン障害のことを気にしていたのですが。

某 K 社（元 N 社というか I 社というか）のデータセンター、2020 年と 2022 年の 2 度にわたって電源設備障害を起こし、しかも 2022 年は点検作業のミスで障害を発生させたという話なので、やはり **トラブルを繰り返すところは繰り返すんだな、** という認識です。

（AWS 東京リージョンも、これまでの比較的大規模な障害は 3 回中 2 回が空調設備のトラブルだったようなので、電源設備ではないけれど **弱い部分の障害は繰り返し発生するんだな、** という認識です）

🍥🍥🍥

---

15 日目の記事に続きます。

- **[アナログな拠点間データ転送の話](https://qiita.com/hmatsu47/items/1ebb9587bc24ff8e3c97)**

https://qiita.com/hmatsu47/items/1ebb9587bc24ff8e3c97