OmniAICreator/Qiita-1.07M huggingface dataset:
any?メソッド

# 下のコメントは勉強になります（感謝！）
# 実際にないインスタンスを抽出する
```rb
irb(main):044:0> a = Model.where("column LIKE ?", "#{Date.today.year}-#{Date.today.month}%")
  Model Load (1.3ms)  SELECT `models`.* FROM `models` WHERE (column LIKE '2022-11%')
=> []   
```
### クラスは？
```
irb(main):048:0> a.class
=> Model::ActiveRecord_Relation
```
### 中身は空かどうか？
```rb                                           
irb(main):045:0> a.empty?
=> true
```
# 訂正 配列の中身の有無を判断には```empty?```が最適（コメントより）
# any? (instance method Array#any?)

any? -> bool
.
.
.
```すべての要素が偽である場合に false を返します```。真である要素があれば、ただちに true を返します。

ブロックを伴う場合は、各要素に対してブロックを評価し、すべての結果が偽である場合に false を返します。ブロックが真を返した時点で、ただちに true を返します。
```rb
p Set[].any?                             # => false
```
### 配列の中身を確認する
```rb                           
irb(main):046:0> a.any?
=> false
```
# 感想
また新しいメソッドを知ることができた。

# 出典
https://docs.ruby-lang.org/ja/latest/method/Array/i/any=3f.html
影響範囲の小さな小回りのきく管理画面ライブラリを作ってみた

[thoughtbot/administrate](https://github.com/thoughtbot/administrate) が有名ですが、これが厄介でした。管理画面の特にフォームのHTMLって結構デフォルトから変更しないと要件を満たせないやつがあるんですよね。**それでカスタマイズすると、いつの間にか本体の仕様が変わって見事にアップデートしにくくなりました。**

でも同時に、管理画面って共通化できる箇所がかなり多いというのも分かります。ライブラリを上手く利用できるならそうしたい。

この辺のもやもやをまとめるためにこれを作りました。

[cc-kawakami/micro-admin: A minimal Administration dashboard parts.](https://github.com/cc-kawakami/micro-admin)

中身は [trailblazer/cells](https://github.com/trailblazer/cells) です。なので、Rails に限らずいろんなところで使えます。

使い方は、まず `ApplicationDashboard` を書いて、

```ruby
class ApplicationDashboard < MicroAdmin::Dashboard::Base
    # もし Rails を使うなら
    self.view_paths = [Rails.root.join("app", "views", "dashboards")]
end
```

それを継承して、モデルに対応するダッシュボードClassを用意します。
そしてここにattributesのリストを定義していきます。

```ruby
class UserDashboard < ApplicationDashboard
    def index_attributes
        [:id, :name]
    end

    def show_attributes
        [:id, :name]
    end

    def form_attributes
        [:name]
    end

    def model_class
        User
    end
end
```

ここがキモの一つですが、このgemでは、フォームのHTMLは用意してません。なので、必ず自分で用意してください。

```html:/app/views/dashboards/user_dashboard/new/name.erb
<input type="text" name="name" class="form-control">
```

editのテンプレートには`value`が渡ってきます。
```html:/app/views/dashboards/user_dashboard/edit/name.erb
<input type="text" name="name" value="<%= value %>" class="form-control">
```

あとは、以下のように呼び出すだけで、管理画面のパーツがレンダーされます。

```ruby
smith = User.new(id: 1, name: "Smith")
james = User.new(id: 1, name: "James")
dashboard = UserDashboard.new
```

```erb
<%= dashboard.index([smith, james]) %>
```

```erb
<%= dashboard.show(smith) %>
```

```erb
<%= dashboard.new(errors: ["Name is required!"]) %>
```

```erb
<%= dashboard.edit(id: 1, values: {name: "Smith"}, errors: []) %>
```

例として、editなら以下のようなHTMLが出力されます。

```html
<header class="navbar border-bottom py-4">
  <h2 class="m-0">Create TestModel</h2>
  <div>
    <a href="/admin/user" class="btn btn-primary">
      Back to index
    </a>
  </div>
</header>
<main class="p-4">
  <ul class="alert alert-danger">
    <li class="ml-3">Name is required</li>
  </ul>
  <form method="patch" action="/admin/user/1">
    <div class="mb-3">
      <label for="name" class="form-label">name</label>
      <input type="text" name="name" value="Smith" class="form-control"/>
    </div>
  </form>
</main>
```

**あとは、Bootstrapを読み込めばいい感じにデザインがハマるようになってます。**

ポイントとしては、
- フォームはカスタマイズ前提で
- それ以外は完備
- Rails 以外でも（Hanamiとか）使える
- ライブラリのメンテナンスが楽

でした。
nodenv installで yarn command not found になった時の対処法

```
> nodenv install 18.12.1
Downloading node-v18.12.1-darwin-x64.tar.gz...
-> https://nodejs.org/dist/v18.12.1/node-v18.12.1-darwin-x64.tar.gz
Installing node-v18.12.1-darwin-x64...
Installed node-v18.12.1-darwin-x64 to /Users/watabe/.nodenv/versions/18.12.1
```

```
> yarn
zsh: command not found: yarn
```

下記コマンドで解決
```
npm install --global yarn
nodenv rehash
```
Test

# テスト記事

テストです。:fist:
``` Objective-C:qiita.m
// コメントアウト
- (void)testMethod:(NSString*)str1 str2:(NSString*)str2 str3:(NSString*)str3 str4:(NSString*)str4 {
    a = x;
    b = y;
    c = z;
    d = w;
}
```
Workato：カンマ区切りの値をリスト（配列）に変換するには

以下のようなカンマ区切りの値を配列に変換するには、CSV by Workatoコネクタを利用します。
```
aaa@example.com,bbb@example.com,ccc@example.com
```

## 実装例と手順
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64876/fd3c7663-2818-3b2a-c38d-534d10168305.png)


### ステップ２
※既にカンマ区切りの値を出力するアクションが存在する場合は、本手順は不要です。（次のステップでは、本ステップの代わりにカンマ区切りの値を出力するアクションの出力（データピル）を指定します。

#### １．「Variables by Workato」コネクタを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64876/18a29013-449e-e33e-21b9-2ae96550911a.png)

#### ２．「Create variable」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64876/94a4eca1-18ae-2406-37f1-99381c9766c5.png)

#### ３．「Add variables」をクリックし、変数を追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64876/e9c973bd-c192-564a-3d32-eb70d41cd921.png)

#### ４．追加した変数に値をセットします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64876/a02da9c3-69b7-45b8-3cd6-e756b6b70c84.png)

### ステップ３
#### １．「CSV by Workato」コネクタを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64876/f9199d59-1371-490f-0c9c-eb3e982fd189.png)

#### ２．「Parse CSV」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64876/7b91c96d-101a-ac47-f10a-cc78bb7ee22d.png)

#### ３．次の通り設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64876/b0363210-29eb-bcf3-3a08-1218ca2f7880.png)

##### CSV contents
Formulaモードへ切り替え、ステップ２で定義した変数の出力（データピル）を追加します。データピルを追加後、そのデータピルに続けて `.gsub(",","\n")` と入力します。

##### Column delimiter
「comma」を選択

##### CSV contents contain header line?
「No」を選択

##### Header schema
「Add field」をクリックし、スキーマを1つ追加します。

##### Quote character
カンマ区切りのフォーマットに合わせて変更します。例えば、ダブルクォーテーションやシングルクォーテーションで値が囲まれていない場合は、「None」とします。

## 出力例
カンマ区切りの文字列が、リスト（配列）に変換されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64876/de829859-7163-6354-954c-462a9c0fa9f1.png)
同じ値の連続データから、値が変わったタイミングの行を取り出すSQL

タイトルの表記がとても難しいのですが、要するに以下のようなデータから、★の行のみ取り出したいときのSQLです。

|Year|Month|data| |
|---|---|---|---|
|2022|1 |A  |★|
|2022|2 |A  ||
|2022|3 |A  ||
|2022|4 |A  ||
|2022|5 |A  ||
|2022|6 |B  |★|
|2022|7 |B  ||
|2022|8 |B  ||
|2022|9 |B  ||
|2022|10|B  ||
|2022|11|B  ||
|2022|12|C  |★|

以下のようなSQLで取得できます。
```SQL
Select
    Year
    ,Month
    ,data
From(
    Select
    *
    ,ROW_NUMBER() OVER(PARTITION BY data ORDER BY Year, Month) as rn
    From Table
) d
Where rn = 1
```
結果

|Year|Month|data|
|---|---|---|
|2022|1 |A  |
|2022|6 |B  |
|2022|12|C  |
学校祭のナビシステムを作成した話

# はじめに
豊田工業高等専門学校の加藤愛斗です。私は今年度の学校祭(こうよう祭)において、副実行委員長を務めさせていただきました。
こうよう祭は学生主体で運営されています。運営の最上層組織である幹部は、実行委員長により任命されます。(実行委員長は立候補者の中から、前年度の幹部により選ばれます。)
今年度の実行委員長は私の友人でした。彼は、私のプログラミングなどのスキルを理解してくれており、かつ、彼の作りたいこうよう祭のイメージの１つにIT化を進めるというものがあったため、私に副実行委員長のオファーを寄せてくれました。
私は、自分のモットーの１つに、「あるチャンスは掴む」というものがあるため、オファーをありがたく受け入れました。

# なぜナビシステムを作成したか
**前年度のこうよう祭**において、当時の実行委員長より、**各展示の待ち時間が分かるシステムの作成**をお願いされて作成してました。

https://github.com/youngeek-0410/share-times-front

https://github.com/youngeek-0410/share-times


今年は、実行委員長の**IT化を進める**という目標も相まって、**前年度学んだ反省を存分に生かして**、学校祭のナビシステムを作成することにしました。

# ナビシステムの機能
## オンラインMAP
本校は大変広く初見では迷うことが多いです。紙のMAPも配布しているのですが、数に限りがあるためオンラインMAPを開発しました。展示の位置と内容が簡単に把握できます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593838/fd8ad57a-eee6-458f-84e5-c100fe10a1b0.gif" width="350px">


## 展示の待ち時間
来場者は、コロナ禍開催であるため各展示の混雑状況が知りたかったり、単純に待ち時間が知りたいという要望がありました。そこで、展示の待ち時間を表示する機能を開発し、上記のMAPと同じ画面で確認できるようにしました。

|<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593838/19a873a4-0ad2-8667-a350-94f51822efb1.jpeg" width="350px">|<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593838/da8f759c-fb26-7f36-7425-9d74e7ccf3cf.jpeg" width="350px">|
|:-:|:-:|




## BINGO景品
こうよう祭は、潤沢な予算が与えられ、その使い道も我々に委ねられています。そのため、BINGO景品も大変豪華です。しかしながら昨年までは、**どんな景品があるのかはBINGOした人しか分からないような運営方式でした**(パンフレット等に載せていない)。せっかく、**予算を使って豪華景品を用意しているのにもったいないと感じたため、BINGO景品並びに残数が分かる機能を開発**しました。


|<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593838/dd41bb7f-f195-c446-5429-533ffc76ee49.jpeg" width="300px">|<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593838/ecd51062-56bd-b7ee-4cbe-b40ae9881f0a.jpeg" width="300px">|
|:-:|:-:|

# 技術
## フロントエンド
友人が担当してくれた部分であるため割愛します。

## バックエンド
FastAPI x Djangoで実装されています。
https://github.com/kathmandu777/koyofes-navi-backend
 
※こうよう祭の他の仕事が忙しく、ものすごい短時間で書き上げたため、あまりきれいなコードではありません。

工夫したポイントは、**adminの一覧ページから各景品の残数を変更出来る**ようにしたことです。(写真右側のPlus, Minusというボタン)
私はdjango adminがものすごく好きなため、わざわざ FastAPI x Djangoという組み合わせでサーバーを実装しています。通常であれば、オブジェクトのアップデートをする際は、個別ページに移動してから修正する必要があるのですが、手間であるため、一覧ページから直接修正できるようにしました。

![django-admin.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593838/16964a54-09ea-e7d3-18fa-26c91b0441bf.png)


## インフラ
知見がなく時間もなかったため、AWSのEC2をサーバーにしました。

# 運用
事前に`locust`を用いて負荷試験などを行っていましたが、想定していたアクセス数よりも多くのアクセスがあったため、かなりサーバーダウンが発生しました。

![locust.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593838/ef690c4a-344b-8aec-eccc-fb4e511603d9.png)


そのため二日目は、サーバーを**スケールアップ**して対応しました。

# 感想
インフラの知見が少なく苦労が多かったため、これからゆっくりと勉強していきたいです。色んな人にしっかりと使ってもらうサービスを作成する機会はあまりないため、よい機会となりました。

# 教訓
## 仕様はしっかり把握しよう
BINGO景品について、同じものが複数あると思っていましたが、1種類1つでした。そのため、残数というフィールドは必要なく、残っているか残っていないかのみ表示するほうがスマートでした。

## AWSのリソース全部消せよー
かなり高いインスタンスタイプを指定していたため、本番終了後すぐにEC2は停止したのですが、ボリュームを消していなかったため、しばらくの間課金されてしまっていました。

# まとめ
限られた時間・リソースでのPJ開発であったため、かなり大変でしたが、何とか形にすることが出来てよかったです。また、今回の経験を生かして、もし来年度の実行委員長にお願いされれば、より良いシステムを作成できるように頑張りたいと思います。
【文字検出_備忘録】OpenCV X Python エッジ処理画像における物体検出

続き

エッジ処理あとの画像で物体検出をしようと思う。待て待て焦るんじゃない。
たくさんネット記事が出てくるので、何となくできそうな気はするけど
ちょっとここで立ち止まって、画像をちゃんと確認したい。

### エッジ処理後の画素値
早速画素値を見てみよう。
```
y_num[0] x_num[0]:255
y_num[0] x_num[1]:255
y_num[0] x_num[2]:255
y_num[0] x_num[3]:255
...
y_num[186] x_num[116]:255
y_num[186] x_num[117]:0
y_num[186] x_num[118]:0
y_num[186] x_num[119]:0
y_num[186] x_num[120]:0
...
```
ちゃんと、255か0になってますね。この255->0に落ちる点が特異点な気がするなー。
なんかそういうのできないかなーと思って。この2次元行列をX軸方向に一つずらして計算する方法を考えてみました。ちょっと文字では言いづらいので頑張って残しますね。
![元行列.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2969158/ac1e11b0-c8b9-3f2a-aeeb-7b949b5d45ef.png)
🌾本来は255か0かですが、簡易的に1と0にしています。
元の画素値行列がこれだったとします。

物体ってどこのことを言うんだろうって考えた時に、こういう検出ができたらいいのでは？と思いました。
![元行列.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2969158/f4ad28df-1c89-c274-f8d5-ea0e8a194a1a.png)

つまり、一番左の列を基準として、右のお隣に増えてるかな、減ってるかなって言うのがこの四角の始点・終点でありそれをもとに一つのグループを作っていけば良いのかなと。

よって、この行列だと、以下の二つの行列を先に作ります。
行列１ 左にゼロをパディングした行列
![左にパディング.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2969158/4b967ca0-2ab4-7d1c-5e93-715bb1b4717f.png)

行列２ 右にゼロをパディングした行列
![右にぱでイング.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2969158/23feb873-ec6b-a958-53de-7cdda0d63bd5.png)

そして、行列１ー行列２をすると、一番左を基準として右のお隣さんとの比較ができますね。

この場合だと、計算結果がこんな感じかな。
![比較結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2969158/ba5876ba-21ba-85d0-4884-4ea1035195a9.png)

それで、一番左の列と右の列を無視すると以下のような行列ができますね。

![比較結果最終.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2969158/dc5ec174-61a1-a127-d5c4-10ff9b98cff6.png)

ちなみに、元の行列の左から二番目以降にこの値が出ている点を取り出してみると
![元画像比較.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2969158/d7cd7abc-6f00-78f5-c081-5b68d8ef0241.png)

こんな感じになって、なんか良くない？（語彙力）

ここからこのエッジから周りを探索して、同じグループをグルーピングすればいいじゃん。

と言うことで、こんなコードを書いてみました。

```
#物体検出処理
y_depth = edges.shape[0]
x_depth = edges.shape[1]

#ゼロパディングを実施した行列をそれぞれ作る
zero_padding = np.zeros((y_depth,1))
edges_zero_padding_right = np.hstack([edges,zero_padding])
edges_zero_padding_left = np.hstack([zero_padding,edges])

#zero_padding同士を比較
edges_compare = edges_zero_padding_right - edges_zero_padding_left
```
いい感じのファイルができたのでbool行列にでもしておこうかなと思います。

```
edges_compare_bool = np.copy(edges_compare)
for y_num in range(y_depth):
	for x_num in range(x_depth):
		if (edges_compare[y_num][x_num] == 0):
			edges_compare_bool[y_num][x_num] = False
		else:
			edges_compare_bool[y_num][x_num] = True
```
さて、ちょっとここまでで、Trueの点プロットでもしてみようかなと思います。


![失敗.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2969158/86d4977e-8def-9485-8874-204c9933fe3a.png)

逆ですね。xとyが逆ですね、見事に、どっかでミスってますねーこれは。



さてさて、妊婦健診もあるし、ご飯を作るので、もうそろそろやめます。笑
AWS Lambda の 環境変数のTZ 指定してもよさそう

# 結論
環境変数TZは予約されてないらしい

# 過去記事は信用しすぎるなって話

LambdaのタイムゾーンはデフォルトではUTCになっていて、タイムゾーンをAsia/Tokyoに変えたい
というのはよくある話だと思う。

しかし、「Lambda TZ」などで検索すると
Lambdaの環境変数は予約されていて、それを上書きできるというのが今後もできる保証がないから環境変数で指定しない方がいい

という記事が結構たくさんある。

しかし、AWSのドキュメントを見ると

> 以下の追加の環境変数は予約されていないため、関数設定で拡張できます。
> 予約されていない環境変数
> ...
> TZ － 環境のタイムゾーン (UTC)。実行環境は、システムクロックを同期するために NTP を使用します。

(2022/11/16時点）

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/configuration-envvars.html#configuration-envvars-runtime

予約されてないってさ

AWSは更新があるから、公式ドキュメントをちゃんと確認することが大事よ。
「主成分分析とは何なのか、とにかく全力でわかりやすく解説する」で学習したときのメモ

# はじめに
https://recruit.cct-inc.co.jp/tecblog/machine-learning/pca-kaisetsu/

こちらのサイトで主成分分析を勉強させていただきました。非常にわかりやすくおすすめ度100です。このサイトを読んだ後にサイト内で言及されていなかった用語いくつかについて調べたのでメモします。文系学部生の独学なので粗が目立つかと思いますが、どしどしご指摘ください。

## 主成分得点
主成分スコアともいう。得られた主成分にしたがって変換したあとの変数の値。

## 寄与率
第i主成分/分散の総和のこと
リンク先で証明されているように2次元の場合の主成分の正体はそれぞれのカテゴリごとのデータの分散。寄与率はそれぞれの分散(主成分)の全体の分散における割合を示すもの
寄与率を第一主成分から累計していったものを累積寄与率と呼ぶ。実際のデータ分析の時には累積寄与率がある程度高くなるとデータ削減のために残りの主成分は捨てることもある。(というかそれが主成分分析の目的そのもの)

## 因子負荷量
元のデータとその主成分スコアの相関係数のこと
ストレージの規格入門（ATA,  SCSI,  SATA, SAS）

### SATA (Serial ATA)

現在主流となっている規格。IDEに比べデータ転送速度が速く、ほとんどのPCで標準的に搭載。シリアル通信。

### SAS (Serial Attached SCSI)

SATAよりも高速で、信頼性や接続台数など拡張性が高い。主にサーバ用途で使用。SATAより高価。シリアル通信。

### ATA (**Advanced Technology Attachment)**

SATAが登場する前は、主流だった規格。IDEと実質同等の意味。（IDEを標準化したものがATA）パラレル通信。

### SCSI (**Small Computer System Interface)**

コマンドをマルチスレッドで処理できることから、性能が重視されるサーバー用途で利用される。SCSIデバイスを使うには、SCSIホストアダプタ（SCSIカード）が必要。1979年に考案され業界標準として広く普及していたSASIを元に改良し、1986年にANSIによって最初の規格が標準化された。パラレル通信。

#### つまり、

|  | パソコンで利用 |  サーバーで利用 |
| --- | --- | --- |
| シリアル通信 | SATA |  SAS |
| パラレル通信 | ATA |  SCSI |

ってこと。

### LinuxにおけるIDE以外のハードディスク

Linuxでは、IDE 以外のハードディスクはすべてSCSIデバイスとして扱われる。つまり、SATAハードディスクもSCSIハードディスクとして扱われる。カーネル2.6.21 以降では基本的にすべてのハードディスクが/dev/sd*になる。

###### 参考
[「パラレル通信」と「シリアル通信」の違い](https://wa3.i-3-i.info/diff87parallel.html)
[「IDE」と「ATA」の違い](https://wa3.i-3-i.info/diff186ide.html)
[SCSI 【Small Computer System Interface】](https://e-words.jp/w/SCSI.html)
[【ストレージ入門】ATA/SATA/SCSI/SASの用語整理](https://www.mtioutput.com/entry/2019/01/14/112823)
[Linux教科書 LPICレベル2 Version 4.5対応](https://www.amazon.co.jp/dp/4798151254)
フレームグラフを読むのは簡単ではありません

フレームグラフを読むのは簡単ではありません。練習が必要です。ですが、ちょっとしたコツもあります。ここではそれを紹介します。

フレームグラフやウォーターフォールチャートを呼ばれる種類の可視化を見ないで1日を過ごすことは、ほとんどありません。大抵はSpeedscopeやChrome DevToolsで、そういった可視化を目にしています。

著書の多くやワークショップの中でフレームグラフの読み方を教えていると、そこでつまづく人を見かけます。フレームグラフを読んで理解するのは、ある程度はスキルの話です。スキルを身につけるには、絶え間ない練習が必要です。

ただ、フレームグラフを読むスキルはサブスキルに分解できます。その場合に最も重要だと私が考えるのは、「どのフレームが重要で意味があるのかを判断できる」スキルです。

プロセスは、Xミリ秒ごとに停止します。停止されると、プロセスの現在のスタックが記録されます。例えば、フレームAはフレームBを呼び、フレームBはフレームCを呼び出すといった具合です。念のために言っておくと、実行スタックとは、例外のバックトレースを見るときなどに表示されているもののことです。例外はスタックを一度だけキャプチャしますが、パフォーマンスプロファイラはミリ秒単位の一定間隔でスタックをキャプチャします。

フレームグラフは、そうやって記録されたスタックを並べることで、このプロセスを視覚化したものです。その視覚化の結果が「炎」のように見えることから、「フレームグラフ」と呼ばれるようになりました。この可視化を、すべてのスタックフレームの「親」が下ではなく上になるように行うと、滝のように見えるので「ウォーターフォールチャート」になります。どちらも同じことなんですけどね。SpeedscopeやDevToolsはウォーターフォール形式でこれを可視化するのですが、私は気にせずにフレームグラフと呼んでいます。

フレームグラフを効果的に読むのに必要なのは、どのフレームを無視すればいいかを理解することです。どのスタックにも、私が「パススルー」と呼ぶフレーム、つまり基本的に何もしないフレームが存在します。パススルーフレームは簡単に見分けられます。
* ... パススルーフレームは、フレーム内で実際に費やされる時間が非常に短いです。そうしたフレームは、決してスタックの最上位にはなく、子フレームを呼び出すことだけをしています。これは通常、そのフレームが大したことを行っていないのを示す良い指標です。
* ... パススルーフレームは、ルートフレームの近く、フレームグラフのベース部分にあります。スタックの「上」に行けば行くほど、アプリケーションコードに近くなり、読む価値のあるフレームとなります。
* ... パススルーフレームは、依存関係の中にあります。フレームのソースコードの位置を見て見ましょう。それは、ライブラリの内部を指しているでしょうか。それともアプリケーション内を指しているでしょうか？ アプリケーションディレクトリにあるほとんどすべて* のフレームは重要です。ですが、しばしば依存関係が姿を表し、面白くないフレームをたくさん追加します。

逆に、どのフレームが興味深いかを知っておくのも大切です。

興味深いフレームとは、ソースコードの位置がアプリケーションのルートディレクトリにあるフレームです。フレームグラフツールは、異なるソースコードディレクトリを異なる色で視覚化するのが一般的です。どの色が「アプリケーションのディレクトリ内」を意味するのかを素早く探し、他のほとんどの色は無視して見始めるのが良いでしょう。

子フレームを呼び出していない、「自己完結」している時間が長いフレーム。これは、スタックのさらに上のフレームがないことを意味します。

そうしたフレームこそ、私がフレームグラフを見る際に最も時間を費やす場所です。

フレームグラフのキャプチャは、最近は非常に簡単で、何をプロファイリングしようとしているかに依存します。
1. rack-mini-profilerは、Railsのバックエンドリクエストのフレームグラフを生成してくれます。
2. Chrome DevToolsは、ブラウザの動作やページのロードについて、パフォーマンスタブで優れたフレームグラフを生成します。
3. stackprofは単体で任意のRubyコードのフレームグラフを生成できます。
4. TestProfは、Rubyのテストスイートのフレームグラフを取得するために使えます。

フレームグラフはパフォーマンス向上のための重要なツールです。ですが、最初にそれを理解できなくても、気にしないでください。みんなも同じです。試し続け、見続けていけば、最終的には効果的に使用するのに必要な「パターン認識」を学べるはずです。

それでは、また来週。
Java で System.getProperty("xxxx") で取得される値の一覧を調べる

## やりたいこと
`java.lang.System#getProperties` から取得できる値の一覧を調べます。

## 手法

* 以下のようにして調査すれば一覧が確認できます。

```java
public class HogeMain {
  public static void main (String... args){
    System.getProperties().list(System.out);
  }
}
```
paiza.ioでelixir その76

# 概要
paiza.ioでelixirやってみた。
練習問題やってみた。

# 練習問題
sin波を描け。

# サンプルコード

```
IO.puts """
<html><head></head><body>
<canvas id="canvas" width="300" height="300"></canvas>
<script type="text/javascript">
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
function draw(data) {
    ctx.strokeStyle = "#f0f";
    ctx.lineWidth = 2;
    ctx.moveTo(0, 150);
    for (var i = 1; i < canvas.width; i++) 
    {
        ctx.lineTo(i, 150 - data[i] * 30);
    }
    ctx.stroke();
}
var src = [
"""
for i <- 0..300 do 
    v = :math.sin(i * 440.0 * 2.0 * :math.pi / 48000.0);
    IO.puts(v)
    IO.puts ","
end
IO.puts """

];
draw(src);
</script></body></html>
"""



```

# 実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/84304aaf-b721-5df5-e11e-34272ccc968a.png)


# 成果物

https://paiza.io/projects/rDheotZJJYF-3BhjQRt4kQ?language=rust


以上。
Brainfuckの基礎

昨今ではあらゆる言語を学べる環境が整っています。
しかしながら、esolangに関しては正確な資料なども少なく、学習コストが比較的高いのが現状です。
~~仕様はこんなにも簡単なのにもったいないですよね。~~

# Brainfuckの基本
:::note warn
不正確な内容が含まれる可能性があります。
また、動作環境によって仕様が異なる場合があります。
:::
Brainfuck仕様がとても単純な言語です。
しかしながら、それは可読性を損ねたり手続きを複雑にすることが大半です。
これは同じ意味の文章を日本語で書くより英語で書く方が長くなるのと似ています。

## 仕様
Brainfuckには以下のような特徴があります
- 命令は8つのみ
- 記憶域は十分な長さ[^1]のbyte配列のみ

:::note warn
ただし、一部実行環境では異なるようです。

* byte以外の配列
* 長さが異なる
* 端が存在しない

などの仕様の実行環境もあります。
:::

これをC言語であらわすと以下の通りです。

```c
#define LENG 30000 //30000以上なら良い
char tape[LENG]={0},*p=tape;
```

そしてこの配列はこのようなイメージで考えることができます。

```
|00|00|00|00|00|00|00|00|...
  ^
```

## 命令
Brainfuckには8つの命令が存在しており、それぞれ特定の一文字に対応しています。

|命令文字|動作|対応するCのコード|
|:-:|:-|:-|
|`,`|ポインタが指す値を入力された値に変える|`*p=getchar();`|
|`.`|ポインタが指す値を文字として出力|`putchar(*p);`|
|`>`|ポインタをインクリメント|`p++;`|
|`<`|ポインタをデクリメント|`p--;`|
|`+`|ポインタが指す値をインクリメント|`(*p)++;`|
|`-`|ポインタが指す値をデクリメント|`(*p)--;`|
|`[`|ポインタが指す値が`00`なら，対応する`]`に飛ぶ|`while(*p){`|
|`]`|対応する`[`の直前の文字に飛ぶ|`}`|

以下では特筆すべき命令を紹介します。

### ポインタ移動命令(`>`,`<`)
Brainfuckのポインタのインクリメントは`>`です。
Brainfuckのポインタのデクリメントは`<`です。
上の説明はC言語的な説明となっていますがいささかわかりにくいです。

そこでBrainfuckの配列を一次元に広がる帯のようなものだと考えるとわかりやすいでしょう。
この帯は左端が存在し、初期状態ではポインタは左端にあります。帯の右端はあまりにも遠いので考慮しません。
初期状態は以下のような状態です。

```
|00|00|00|00|00|00|00|00|...
  ^
```

これに対して`>`が行われると

```
|00|00|00|00|00|00|00|00|...
     ^
```

のようになります。
これは`>`命令によってポインタが左端から右に移動したとみなせます。

このように、`>`命令が配列に対してポインタを右に移動、`<`命令が配列に対してポインタを左に移動させるような命令と考えることができます。
この考えはBrainfuckのインタプリタをBrainfuckで書く時などに使います。

### 加減算命令(`+`,`-`)
Brainfuckはbyte配列です。
すなわち`0(0x00)`~`255(0xFF)`までの数字を扱うことができます。
`FF`の時に`+`命令を行うとデータがオーバーフローして`00`になります。
`00`の時に`-`命令を行うとデータがアンダーフローして`FF`になります。

:::note warn
ただし、一部実行環境では異なるようです。
:::

[^1]: 30000以上といわれているが出典は不明。
バーチャルオフィスツールMetaLifeをSlackやTeamsと連携してWebhookで通知を流す

自分が働いている会社では、現在「MetaLife」というバーチャルオフィスとして使えるツールを開発しています。最近MetaLifeで**Webhookを使った外部サービスとの連携**ができるようになったので、今回こちらを紹介していこうと思います！

https://metalife.co.jp/

## そもそもMetaLifeってなんすか？

MetaLifeは今年8月にリリースされたばかりなので、知らない人も多いかと思います。改めてMetaLifeとはなんぞやというのを紹介します。

<iframe width="560" height="315" src="https://www.youtube.com/embed/7tXNYou2mfw" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" loading="lazy" allowfullscreen></iframe>

ユーザ一人一人が「アバター」としてMetaLife上のスペースに入り、キーボード（モバイル端末ではコントローラーが出現します）を使って歩き回れます。**他のアバターと自分のアバターが近づくと、相手の映像と音声がつながり、通話できるようになる**、というのが基本的な機能になります！

`React`を使って開発されており、ブラウザで動くアプリケーションになっているので、PCでもスマホでもタブレットでも、ダウンロード不要ですぐに使い始められます。

また、2Dのドット絵で実現されている分、3Dの描画が必要になるメタバースツールに比べて処理が軽いです。

そのため弊社では、**「裏でMetaLifeのタブをずっと開いたままにしておいて、表で仕事を進め、会話の必要が生まれたときに起動したままのMetaLifeに戻ってちょっとだけ会話して、すぐにまた表で仕事を再開する」** というような使い方をしています。

他のツールを使ってビデオ通話をするとなると、通話の「開始」「終了」という区切れが生まれ、どうしてもミーティングをしている感が出てしまいます。そのため、現実のオフィスにいたときにはできていた、ちょっとした質問や、どうでも良い雑談（ただこういう雑談が実は新しいアイディアのために重要だったりするんですよね）が、とてもしづらくなってしまいます。

その点MetaLifeでは、**会話と作業をシームレスに**切り替えられます。まるで現実のオフィスにいるかのように、近づけば会話できて、離れれば一人になる。**バーチャルな空間でありながら、現実に存在する会話の距離の概念をもたらしている**のが、MetaLifeの最大のポイントだと自負しています。

![コードレビューの様子を画面共有](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017980/bd784c11-76a4-2309-a81d-f1b2b985e53a.png)

画面共有もいつでもできるので、コードレビューでエディタの画面を見せながら議論する、なんてことも容易にできます。チャットやホワイトボードもあるので、他のサービスを同時並行で利用する必要もなく、**MetaLifeこれ一つでなんでも解決できちゃいます。**

また、25名までの利用なら、**永続的に無料**でご利用いただけます！！導入を迷っている方も、お問合せ等は不要のまま、すぐにお試しいただけます。

さらに詳しくは、弊社CTOの書いた紹介記事もご覧いただけると嬉しいです：

https://qiita.com/yanolii/items/18739784df2249181638

## そうは言っても外部サービスを使いたい！

なんでも解決できるとは言いましたが、残念ながら本当に「なんでも」できるわけではありません…

ブラウザ上で動くアプリである以上、slackのように端末にいつもの見慣れた通知を送ったりすることはできません。また、外部のチームと連携して仕事をしているのにいきなりMetaLifeに移行する、というのは難しく、Teamsをそのまま使い続けたい、という気持ちもわかります。実際、リリース以降、MetaLifeのユーザの皆さまから、外部サービスとの連携が欲しい！！！とのご意見を数多くいただきました。

そこで今回、Webhookを利用した外部サービスとの連携を実装いたしました。

## 外部サービスに通知できるMetaLife上のイベント

MetaLifeでは、以下のようなイベントを外部サービスに通知することができるようになりました：

- スペースに入室したこと
- スペースから退出したこと
- ミーティングルームに入室したこと
- ミーティングルームから退出したこと
- 離席したこと
- 着席したこと
- インターホンを押したこと
- フロアを移動したこと
- （パブリックな）チャンネルでチャットを投稿したこと

例えば、slackで今まで出勤退勤を管理していた会社の場合、

- スペースに入室したこと
- スペースから退出したこと

をMetaLifeから通知できるように設定しておけば、だれがスペースにいるかslack上で確認できるようになります。

![CFDD2C2C-2774-4BB8-9263-50BFF8FAA82F.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017980/2a008af3-1988-387c-e1e9-88ae5ba48157.jpeg)



詳しい設定方法は、ヘルプページをご覧ください！

https://support.metalife.co.jp/44363d6b05554ca2b0090e52eafb491e

:::note info

エンジニアの方向けのinfo

技術的には難しいことは使用しておらず、単純に「外部サービスが用意しているIncoming Webhook URLに対し、MetaLife側からPOSTリクエストを送信しているだけ」です。

ですから、会社でオリジナルのアプリケーションを使っていろいろな情報を管理している、という場合でも、POSTリクエストをうけられるようにして、MetaLifeから送られてくるテキストを適当にパースしてあげれば、自前のDBにも情報を登録できるようになります。
:::

## さいごに

- MetaLifeについての紹介
- 外部サービスとの連携機能の紹介

をさせていただきました。皆さまから頂く情報を多いに参考にしながら、こまめに新機能・修正をリリースしています。なにかお困りの際は、気軽にお問合せください。

MetaLife面白そうと感じていただけた場合は、ぜひ下のリンクから、使ってみてください！

https://metalife.co.jp/
Google Cloud資格のオンライン受験で苦戦したこと (GC-PCA)

# 受験資格
Google Cloud Certified - Professional Cloud Architect
# 結論
試験開始までにかなり時間がかかってしまったが、合格できた

また本人書類確認などの試験開始までにかかった時間は、試験時間には含まれないので焦る必要はない

# 学習方法
・[図解即戦力 Google Cloudのしくみと技術がこれ1冊でしっかりわかる教科書](https://amzn.asia/d/0FP5qm2)
・Udemy教材

学習期間: 約二週間

# オンライン受験にあたっての準備
- 個人用PCの利用
- スタートアップ・起動中のソフトを終了
- Windowsdefenderの一部停止
- 試験受験用ソフトのインストール
- 本人確認書類の準備
    - アカウントに登録している名前と同じ表記(日本語or英語)のものが望ましい
- 受験環境・部屋の用意
    - 身の回りから試験に必要のないものを全て取り除く必要がある
    - 自分は風呂場を選択
   
# 試験の流れ
1. 試験開始10分前にWebassesorにアクセスし、予約済み試験の[開始]ボタンをクリック
※10分以上前だとボタンが[?]になっており開始できません
2. 証明写真撮影
※眼鏡をかけている場合は撮影時のみ外す必要がある
3. しばらく待機した後、試験官との本人確認＆受験環境の確認(受験環境の様子をカメラで映す)フェーズに移る。
※相手の会話は見えず、チャットで会話する(稀に英文でメッセージを送ってくる場合があるが、お願いすれば和訳したものを送ってくれるので問題なし)
4. 試験開始

# トラブル
### - 自分のカメラの映像が試験官に届かない
ノートPC本体のカメラ使用しており、自分の画面ではカメラにちゃんと映っているが、試験官には届いていなかった

試験官の指示に従い試験を別時間に再予約してもらい、USB接続のカメラを使用し、再起動後に試験を開始したところ解消

原因は不明

### USBカメラの接続が切れてしまい、挿し直しても受験用ソフトがUSBカメラを認識してくれない

不正防止の為、カメラで受験環境の周りをカメラで映している際にUSB端子の接触が悪かった為か接続が切れてしまった。

試験官の指示に従い試験を別時間に再予約してもらい、端子を変えて再起動後に試験を開始したところ解消

原因は恐らく受験用ソフトが、起動後にUSBデバイスを接続しても認識しないようになっている為
Trailheadハンズオンチャレンジで公式解答一覧

今回の内容は動画でも紹介しています


https://www.youtube.com/watch?v=Me3n7QUhrA8

<iframe width="560" height="315" src="https://www.youtube.com/embed/Me3n7QUhrA8" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>


こんにちは。

SalesforceのTrailheadにはハンズオンチャレンジがございますね

ハンズオンチャレンジはSalesforceのplaygroundで特定の設定をするのですが、このハンズオンチャレンジは結構複雑な設定なので難しいな。と思った方たくさんいるのではないでしょうか


そのような方のためにSaelsforceは公式的にハンズオンチャレンジの解説をいくつか公開しています


今回は公式的に公開されているハンズオンチャレンジの公式解説を集めました

どうしても解答できない場合にチェックしてみてください

### 『Lightning Experience のカスタマイズ』

『Lightning Experience のカスタマイズ』(2300ポイント)
https://trailhead.salesforce.com/ja/content/learn/modules/lex_customization?trailmix_creator_id=welcome4&trailmix_slug=mazuyaru-mix

『Lightning Experience のカスタマイズ』の日本語訳および公式解答
https://trailhead.salesforce.com/ja/users/welcome4/trailmixes/mazuyaru-mix


### レポート関連

『クイックスタート: レポート & ダッシュボード』(75ポイント)
https://trailhead.salesforce.com/ja/content/learn/projects/quickstart-reports?trailmix_creator_id=welcome4&trailmix_slug=mazuyaru-mix2


『Lightning Experience のレポートおよびダッシュボード』(2100ポイント)
https://trailhead.salesforce.com/ja/content/learn/modules/lex_implementation_reports_dashboards?

『クイックスタート: レポート & ダッシュボード』および『Lightning Experience のレポートおよびダッシュボード』の日本語訳および公式解答
https://trailhead.salesforce.com/ja/users/welcome4/trailmixes/mazuyaru-mix2


### Chatter関連

『Lightning Experience の Chatter』(1600ポイント)
https://trailhead.salesforce.com/ja/content/learn/modules/chatter_basics_for_users?trailmix_creator_id=welcome4&trailmix_slug=mazuyaru-mix3
『Salesforce Classic の Chatter の管理』(1700ポイント)
https://trailhead.salesforce.com/ja/content/learn/modules/chatter?trailmix_creator_id=welcome4&trailmix_slug=mazuyaru-mix3

『Lightning Experience の Chatter』と『Salesforce Classic の Chatter の管理』の日本語訳および公式解答
https://trailhead.salesforce.com/ja/users/welcome4/trailmixes/mazuyaru-mix3

いかがでしたでしょうか

こちらの公式解答を参考に、Trailheadのハンズオンチャレンジに挑戦してみてください
nginx,laravel,vue3,gcp を aws で使うと激重

結論から言えば

・ドメインの設定ミス
・nginxの設定ミス


# まずはドメインの設定ミス

参考
https://teratail.com/questions/44231

症状はこの方と一緒
https://qiita.com/mako0104/questions/f655206741c14a77ada8

# chromeツールで app と表示するだけなのに21.56秒もかかっている

![3a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31338/c13f0988-3c71-227b-0075-a9c510fca771.png)


# 原因 Aレコード、twikon.clubに複数のIPアドレスが設定されている

![1a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31338/9fe8fedd-b90c-a3d9-f743-12a392a24410.png)

これがあると、ドメインのネーム解決に時間がかかって激重になるので、
正しいIPアドレスのみ入力すること。

また、AAAAレコードも正しいのに変更。


# nginxの設定 gcp を使う

nginxのエラーログに以下の表記が

```
2022/11/14 14:04:44 [warn] 10748#10748: *5502 an upstream response is buffered to a temporary file /var/lib/nginx/tmp/proxy/8/06/0000000068 while reading upstream, client: 49.105.92.152, server: twikon.club, request: "GET /gcp-storage/photo-300x300-51610.jpg HTTP/2.0", upstream: "https://142.250.196.112:443/twikon/photo-300x300-51610.jpg", host: "twikon.club", referrer: "https://twikon.club/user-show"
```

```default.conf

//最上部に以下を追記
proxy_buffering on;
proxy_buffer_size 32k;
proxy_buffers 50 32k;
proxy_busy_buffers_size 32k;
proxy_max_temp_file_size 0;

```

以上
正規表現とmatch,subメソッド

# はじめに
正規表現を用いた任意の文字列のチェック方法やその他できることをまとめる。

## matchとsubメソッドについて
### subメソッド
subメソッドは、文字列の指定した部分を別の文字列に置き換えるためのメソッドです。
第1引数に置き換えたい文字列を指定し、第2引数に変換後の文字列を指定します。また、操作したい文字列は/で囲みます。

    【例】
    irb(main):001:0> str = "りんごを食べる"
    => "りんごを食べる"
    
    irb(main):002:0> str.sub(/りんご/,"みかん")
    => "みかんを食べる"
    「りんごを食べる」という文字列が「みかんを食べる」という文字列に置換されました。

### matchマッチ
matchメソッドは、引数に指定した文字列がメソッドを使用した文字列に含まれているか否かをチェックするためのメソッドです。含まれている場合は、指定した文字列がMatchDataというオブジェクトが戻り値で得られます。また、含まれていない場合は、戻り値としてnilが得られます。

    【例】
    irb(main):001:0> str = "Hello, World"
    => "Hello, World"
    
    irb(main):002:0> str.match(/Hello/)
    => #<MatchData "Hello">
    
    irb(main):003:0> str.match(/Good/)
    => nil
    上の例では「Hello World」という文字列に、「Hello」という文字列が含まれているか否かをチェックしています。

### MatchDataマッチデータ
マッチした文字列はまず、MatchDataという種類のオブジェクトで返されます。MatchDataから実際にマッチした文字列などを取り出したい場合は、以下の様に配列から最初のデータを取り出す時と同様の形で取り出すことができます。

 コード内において、変数「md」は「MatchData」を意味します。

    【例】
    irb(main):001:0> str = "Hello, World"
    => "Hello, World"
    
    irb(main):002:0> md = str.match(/Hello/)
    => #<MatchData "Hello">
    
    irb(main):003:0> md[0]
    => "Hello"


これらの正規表現や関連するメソッドをプログラムに適用する際は、if文を用います。

パターンにマッチした場合はマッチしたオブジェクトが返されます。またマッチしなかった場合はnilが返ってくるため、その性質を使用してif文で処理を分けます。

    【例】
    str = gets.chomp
    if str.match(/good morning/)
      puts 'おはようございます！'
    else
      puts 'あいさつが異なるようです。'
    end

## 補足
### gsubジーサブ
gが意味するのはグローバルマッチという言葉です。文字列内に指定した文字が複数含まれている場合、その全てを置換するという意味になります。
第一引数には正規表現、第二引数に置換する文字列を指定します。
gsubではなくsubを使用した場合、最初にマッチした１つだけが置換されます。

    ターミナル
    irb(main):001:0> tel = '090-1234-5678'
    => "090-1234-5678"
    
    irb(main):002:0> tel.sub(/-/,'')
    => "0901234-5678"
    # 最初のハイフンしか置換されない
    
    irb(main):003:0> tel.gsub(/-/,'')
    => "09012345678"
Android アプリがバックグラウンドの時にヘッドアップ通知する

# やりたいこと

アプリがバックグラウンドの時にヘッドアップ通知する
なお、フォアグラウンドの場合は従来通りFirebaseMessagingServiceのonMessageReceivedで通知を作成すればよいので割愛


# やること

### 事前準備

今回はFirebaseCloudMessagingを使用しますので以下のURLを参考にPush通知を受ける準備はしておく

https://firebase.google.com/docs/cloud-messaging/android/client

### 通知チャネルの作成

いろんなサンプルコードには通知チャネルと通知(NotificationManagerCompat.Notify)をするところが一緒に実装されていることが多いので盲点だったのですが、通知チャネルは永続化されていて一度作成するだけでOK。
つまり実装箇所はFirebaseMessagingServiceで通知を受けた時ではなく、Applicationクラスなどアプリの初期処理で通知チャネルを作成しておく。

通知チャネルは一度作ると同じ名前で再度作成しようと思っても実行されない、なので既存で利用している通知チャネルの重要度だけ変更するとかもできない。新しいChannelIDで作成しましょう。
↓ここにもちゃんと書いてる
https://developer.android.com/training/notify-user/channels?hl=ja#CreateChannel

この時にNotificationManager.IMPORTANCE_HIGHをセットしておく。
```kotlin:App.kt
val name = getString(R.string.channel_name)
val descriptionText = getString(R.string.channel_description)
val importance = NotificationManager.IMPORTANCE_HIGH // ←ここ必須
val mChannel = NotificationChannel("CHANNEL_ID_HEAD_UP", name, importance)
mChannel.description = descriptionText
val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(mChannel)
```


### 配信側

あとは通知を送る側で上で作成した通知チャネルIDを指定していればOK
例えばFirebaseのCloud Messagingだと通知の作成の項目にあるAndroid通知チャネルに上で作成した"CHANNEL_ID_HEAD_UP"を指定する。

![スクリーンショット 2022-11-04 16.36.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351880/ac51f371-692b-afce-9472-4184a5da10bc.png)

![スクリーンショット 2022-11-04 16.37.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351880/94378484-9f8e-946e-55f8-ee7c49a215c6.png)

### テストメッセージを配信

事前にLogcatなどから取得しておいたFCM登録トークンをコピーしておいて
Cloud Messagingからテストメッセージを配信してみます。

![スクリーンショット 2022-11-16 11.00.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351880/d1b3f6bb-c82c-0638-424d-15c07ac612e1.png)

アプリがバックグラウンドの状態でヘッドアップ通知が出来ました！

![Screenshot_20221116-105809_One UI Home.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351880/58e3119e-3668-9113-8f0d-4a9dbea2f930.jpeg)

## ソースコード

https://github.com/tokuyama-san/HeadUpSampleApp
バリデーションの記法と正規表現

# はじめに
バリデーションに用いる正規表現をまとめる。

## 正規表現
|  パターン |  意味  |
| ---- | ---- |
|  [a-z]  |  角括弧で囲まれた文字のいずれか 1個にマッチ  |
|  \d  |  数字にマッチ  |
|  {n, m}  |  直前の文字が少なくともn回、多くてもm回出現するものにマッチ  |
|  {n}  |  直前の文字がn回出現するものにマッチ  |
|  .  |  改行以外のどの1文字にもマッチ  |
|  +  |  直前の文字の1回以上の繰り返しにマッチ  |
| \A |  直後の文字が先頭にある文字列にマッチ  |
| \z |  直前の文字が末尾にある文字列にマッチ  |
|  [ぁ-んァ-ヶ一-龥々]  |  角括弧に囲まれたかな、カナ、漢字のいずれかにマッチ（ヴ、ヵ、ヶ、々を含む） |
|  ?=  |  直後に設定した文字が続く文字列にマッチ  |
|  *?  |  直前に設定した文字が0回以上続く文字列をチェックし、?の直後の文字が出た段階でその1文字を返す |
|  \  | エスケープ文字といい、「正規表現において特別な意味を持つ文字」の直前に入れることで、「正規表現において特別な意味を持つ文字」をただの文字列として扱うことができる文字|

<strong>＜正規表現と意味（一例）＞</strong>
- /\A[ぁ-んァ-ヶ一-龥々ー]+\z/	
1字以上の全角ひらがな、全角カタカナ、漢字にマッチ

- /\A[ァ-ヶー]+\z/	
1字以上の全角カタカナにマッチ

- /\A[a-z0-9]+\z/i	
1字以上の半角英数にマッチ（大文字小文字問わない）

## 具体的なバリデーションの記述例
- <strong>with_options</strong>
with_optionsは複数のバリデーションをグループ化し、共通の制限をかけるためのメソッドです。
さらに、formatヘルパーを使用することで、正規表現を用いた条件を設定することができます。

- <strong>formatフォーマット</strong>
formatは、withオプションに指定された正規表現と属性の値がマッチするかどうかをチェックします。マッチしない場合は、messageオプションに指定された文字列をエラーメッセージとします。

- <strong>numericality</strong>
numericalityとは、指定されたカラムに対して数値かどうかを検証するヘルパーです。
また、オプションでonly_integer: trueを指定すると、「整数のみ」という制限を加えることができます。

        ＜記述例＞
          with_options presence: true do
            # ひらがな、カタカナ、漢字のみ許可する
            validates :name, format: {with: /\A[ぁ-んァ-ヶ一-龥々ー]+\z/, message: "is invalid. Input full-width characters."}
            # カタカナのみ許可する
            validates :name_reading, format: {with: /\A[ァ-ヶー]+\z/, message: "is invalid. Input full-width katakana characters."}
            # 半角英字数字のみ許可する
            validates :nickname, format: {with: /\A[a-z0-9]+\z/i, message: "is invalid. Input half-width characters."}
          end

            # 数字3桁、ハイフン、数字4桁の並びのみ許可する
            validates :postal_code, presence: true, format: {with: /\A[0-9]{3}-[0-9]{4}\z/, message: "is invalid. Include hyphen(-)"}
            # 0以外の整数を許可する
            validates :prefecture, numericality: {other_than: 0, message: "can't be blank"}

            # 1以上、1000000以下の整数を許可する
            validates :price, presence: true, numericality: {only_integer: true, greater_than_or_equal_to: 1, less_than_or_equal_to: 1000000, message: "is invalid"}


- passwordの英数字混合の判断

        #モデルにて
        PASSWORD_REGEX = /\A(?=.*?[a-z])(?=.*?[\d])[a-z\d]+\z/i.freeze
        validates_format_of :password, with: PASSWORD_REGEX, message: 'には英字と数字の両方を含めて設定してください'

- 全角かな/カナ漢字のあらゆる日本語に対応
    
      with_options presence: true, format: { with: /\A[ぁ-んァ-ヶ一-龥々ー]+\z/, message: '全角文字を使用してください' } do
          validates :first_name
          validates :last_name
      end

- ¥300〜¥9,999,999までの整数値に限定する
    
      validates :price, format: { with:  /\A[0-9]+\z/ },
                        numericality: { only_integer: true, greater_than_or_equal_to: 300, less_than_or_equal_to: 9999999 }

<strong>numericality</strong>で整数のみにする設定や数値の最大値、最小値を設定できる。

<strong>only_integer: true</strong>で整数値のみに設定。

<strong>greater_than_or_equal_to: 300, less_than_or_equal_to: 9999999}</strong>で最小値、最大値を設定。
情報システム投資計画

# 情報システム投資計画
経営戦略との整合性をとり、情報システム戦略にそって策定する。
計画の決定に際しては、システムや機器の導入で```発生する影響```、```期待できる効果```とその期間、```実現の可能性```などを基に、```複数の案を比較検討```する必要がある。

### ROI(Returen On Investment: 投資収益率）
ROIは行った投資（かかった費用)とその案件によって得られる利用の比率を表し、計算式```ROI=利益額÷投資額```で求めることができる。```この値が高ければ投資によって得られる効果が大きく```、```低ければ効果が小さい```と判断することができる。

### ITポートフォリオ
システム化計画の策定に際し、情報システム投資をどのようなバランスで行なって行くかを、ポートフォリオ分析を使って検討・管理する手法。
```投資の目的や含まれるリスクなどの特性によって投資対象をカテゴライズ（分類)```し、カテゴリごとにプロットすることで、視覚的に```全体の資源配分バランスが評価できる```。

#### ポートフォリオ分析
2つの評価項目を２軸に取った```グラフを作成```し、検討対象の要素が```どの位置にプロットされるか```でその```特徴を掴む図法```

# 出典
https://gihyo.jp/book/2022/978-4-297-12375-8
railsでJSONファイルの値を分割して受け取る

railsでひとつのJSONで二つのテーブル分のデータを受け取った際の処理を書く際に手間取ったのでメモ。
## 受け取るJSONファイル
```json:event.json
{
	"category_id": 1,
	"name": "TestEvent",
	"is_public": true,
	"description": "テストイベントです",
	"proposed_at": [
		"2022-11-14T18:15:45.087+09:00",
		"2022-11-14T19:1６:45.087+09:00",
		"2022-11-14T18:52:09.671+09:00"
	]
}				
```
イベントの名前だったりそのイベントの候補日のデータ

## コントローラー側の処理
```ruby:event_controller.rb
  def event_params
    params.require(:event).permit(
      :category_id,
      :name,
      :is_public,
      :description,
      :delete_at
    )
  end

  def possible_dates_params
    params.require(:proposed_at)
    # params.permit(proposed_at: [])
    # params[;proposed_at]
  end
```
`event_params`にはeventテーブルに入れるデータ、`possible_dates_params`にはpossible_datesテーブルに入れるデータが入る。
コメントアウトされている書き方でも実装できるが２行目の`params[;proposed_at]`ではストロングパラメータにならないため要件的にどうなのと思い今回はパス。１行目の`params.permit(proposed_at: [])`は同じように実装できるが受け取る値が
```
{"proposed_at"=>[
    "2022-11-14T18:15:45.087+09:00", 
    "2022-11-14T18:1６:45.087+09:00", 
    "2022-11-14T18:52:09.671+09:00"
]}
```
って感じになってeach文とかで回すときにわざわざ
```ruby
proposed_days = possible_dates_params
proposed_days[proposed_at].each do |proposed_at|
```
というような書き方になる。取り出す値、使う値が決まってるならできるだけそれだけ入れた方がいいよねって思い今回は`params.require(:proposed_at)`の方法で実装した。
もしJSONファイルのネストが深かったりハッシュのキーを使わないといけないならコメントアウトしてる書き方を採用したほうがいい時もあるかもしれない。

##　参考
https://zenn.dev/shogo_matsumoto/articles/1dd51149d088e6
情報システム戦略とシステム企画

# To-be モデル
### To-beモデル
```あるべき姿```を示すもの。システム構築の```目標```として作成。
### As-isモデル
```現状の姿```を示す。```両者を比較```しながら新モデルを考える。
### Can-beモデル
```To-beモデルに対して制約条件を加味```したもの。

# エンタープライズアーキテクチャ
## エンターブライズアーキテクチャ(EA: Enterprise Architecture)
```企業の業務と情報システムを統一的な手法でモデル化```し、業務とシステムの```統合的な改善を目的```とする管理手法。試験では、主にアーキテクチャモデルについて問われる。
## アーキテクチャモデル
```業務とシステムの構成ようを記述したモデル```のこと。
* 組織全体の```業務プロセス```
* 業務に```必要な情報```
* 情報```システムの構成```
* 利用する```情報技術（アプリケーションや情報テクノロジ）```
の4つの要素についてアーキテクチャモデルを作成し、システムの現状を整理して把握することで、理想とする目標を定めていく。

### ビジネスアーキテクチャ(BA: Business Architecture)
組織の目標や組織全体として```業務プロセスを体系化```したもの。
#### 手法・成果物
情報システム戦略図、機能構成図（UMM)、機能情報関連図（DFD)

### データアーキテクチャ(DA: Data Architecture)
業務に利用する情報、すなわち```組織の目標や業務に必要となるデータの構成```、及びデータ間の関連を体系化したもの。
#### 手法・成果物
業務で扱う情報の流れ図、実態関連ダイアグラム（ERD)、データ定義表

### アプリケーションアーキテクチャ(AA: Application Architecture)
情報システムの構成、すなわち組織としての目標を実現するための```業務と、それを実現するアプリケーション関係を体系化```したもの。

#### 手法・成果物
情報システム関連図、情報システム機能構成図

### テクノロジーアーキテクチャ(TA: Technology Architecture)
業務に利用する情報技術、すなわち業務を実現するための```ハードウェア、ソフトウェアネットワークなどの技術を体系化```したもの。

#### 手法・成果物
ネットワーク構成図、ハードウェア、ソフトウェア構成図

# 出典 
https://gihyo.jp/book/2022/978-4-297-12375-8
ggplot2 の aes 内で、変数を使って列を指定する方法

## 結論

下記のように、`base::get` を使うと上手くいく。

### 下準備

```r
library(tidyverse)
data(iris)
```

### 上手くいく方法

```r
draw_hist <- function(x, data) {
    data |> 
        ggplot2::ggplot(aes(x = get(x))) +
        geom_histogram()
}

draw_hist("Sepal.Length", iris)
```
## 補遺

get: Return the Value of a Named Object の詳細は下記。
https://www.rdocumentation.org/packages/base/versions/3.6.2/topics/get


下記のような方法だと、上手くいかない。

### 上手くいかない方法 1

```r
draw_hist <- function(x, data) {
    data |> 
        ggplot2::ggplot(aes(x = x)) +
        geom_histogram()
}

draw_hist("Sepal.Length", iris)
```

### 上手くいかない方法 2

```r
draw_hist <- function(x, data) {
    data |> 
        ggplot2::ggplot(aes(x = as.name(x))) +
        geom_histogram()
}

draw_hist("Sepal.Length", iris)
```
Leetcode 374. Guess Number Higher or Lower

# 374. Guess Number Higher or Lower

https://leetcode.com/problems/guess-number-higher-or-lower/description/

## アプローチ
### 二分探索
O(log n)

```java
/** 
 * Forward declaration of guess API.
 * @param  num   your guess
 * @return 	     -1 if num is higher than the picked number
 *			      1 if num is lower than the picked number
 *               otherwise return 0
 * int guess(int num);
 */

public class Solution extends GuessGame {
    public int guessNumber(int n) {
        int start = 1;
        int end = n;

        while(start <= end){
            int mid = start + (end- start) / 2;
            int check = guess(mid);
            if(check == 0){
                return mid;
            }else if(check == 1) {
                 start = mid + 1;
            }else{   
                 end = mid -1;
            }
        }
        return 0;
    }
}
```
QGISにおける「.qgs」と「.qgz」拡張子の違い

## TL;DR

`.qgz` を使うとよい

## 内容

- 二つのファイル形式
    - `.qgs` : XMLファイル
    - **`.qgz` : zipアーカイブ**
- QGZの経緯
    - 2017年に実装された
    - QGIS3.2よりQGZ形式がデフォルト
- なぜQGZ
    - 従来のXMLファイルをzipしている
    - 加えて、**それ以外のファイルもまとめることができる**
    - 例えば、従来だと `.qgs` ファイルに加えて `.qgd` ファイルという補助DBファイルが保存された ⇒ それが一つのzipファイルになる
- **可能性: 色々なものを同梱できる**
    - フォント、SVG、color ramps等の情報
    - プラグイン、スクリプト、プロセシングアルゴリズム、モデラー
    - etc.


## 例

`.qgz` （zipアーカイブ）の方がファイルサイズが小さくなる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6438/08eadac7-0efe-bdbe-2834-a393aa5c0ba1.png)

`.qgs` はプレーンテキスト、XML記述

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6438/6a86779d-7817-19af-a007-25051c6132e6.png)

`.qgz` はバイナリファイル

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6438/faa2775d-6828-891c-34a6-281f50f069ac.png)


## 参考

- [“QGZ” – A new default project file format for QGIS – Oslandia](https://oslandia.com/en/2018/06/01/qgz-a-new-default-project-file-format-for-qgis/)

> This will offers many possibilities like embbeding:
> - Resources like fonts, SVG, color ramps, and all styling informations
> - A unified container for off-line editing embedding data into a gpkg format
> - plugins, scripts, processing algorithms and modelers
４０代おっさんStreamlitを学ぶ②

## 本記事について

この記事はプログラミング初学者の私が学んでいく中でわからない単語や概要を分かりやすくまとめたものです。
もし不正などありましたらコメントにてお知らせいただければ幸いです。

## 前回の記事

<https://qiita.com/kou1121/items/bff63bb2372106bbecff>

## Streamlit

### Input widgets

```python
import streamlit as st
import pandas as pd
import numpy as np

csv = pd.read_csv('dummy.csv') # csv読み込み適当なの入れました

df = pd.DataFrame(csv)

if st.button('住所'): # ボタン
    st.dataframe(df['住所'])

if st.checkbox('氏名'): # チェックボックス
    st.dataframe(df['氏名'])

options = st.multiselect( # オプションで選択肢の中から選んだものを使える。
    '選択肢',['氏名','住所','血液型']
)

st.dataframe(df[options]) # オプションで選ばれたものを表示

number = st.slider('Num', 0, 10) # スライダー（表示名, 始まりの値, 終わりの値）

st.dataframe(df.loc[number]) # df.locでnumberの値をいれて列を表示
```

### Layouts and Containers

```python
import streamlit as st
import pandas as pd
import numpy as np

csv = pd.read_csv('dummy.csv') # csv読み込み適当なの入れました

df = pd.DataFrame(csv)
left_col, right_col = st.columns(2) # カラムを2つ作成

with left_col:
    if st.button('住所'):
        st.dataframe(df['住所']) # left_colを作成　withがないとif文が上手く行かない

with right_col:
    if st.checkbox('氏名'):
        st.dataframe(df['氏名']) # right_colを作成　withがないとif文が上手く行かない

```

- with分
  - Pythonでは、ある一定の期間だけオブジェクトを使用したり、いろいろな設定を行って用事がすんだら元に戻したい、という処理を行うとき、with文を使用します。

## 参考

https://www.udemy.com/course/python-fastapi
JupyterNotebook+Docker+VSCode(Devcontainer)の開発環境構築

![my image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109639/b13af8f9-04ce-5021-dbf8-36c9266a03c4.png)

## 経緯
- 環境を汚さずにパッとVSCodeのDev Containerで動くPython（Jupyter notebook）の開発環境が欲しかった
- Githubに上げたので共有

## 動作検証した環境
- Windows 11+WSL2 (Ubuntu)
- Docker 20.10.20
- VSCode 1.73.1
上記の環境構築に関しては[こちら](https://lethediana.sakura.ne.jp/tech/archives/steps-ja/1169/)

## 手順
1. [jupyter-docker-devcontainer](https://github.com/ttnt-1013/jupyter-docker-devcontainer)をcloneし、VSCodeでフォルダを開く
`git clone https://github.com/ttnt-1013/jupyter-docker-devcontainer.git`
2. VSCodeに拡張機能 Dev Containerを追加
3. 左下の「><」をクリックしReopen this folder in Containerを選択
3. 新しいウインドウが開き、コンテナのビルドが開始される
    - 初回はビルドに時間がかかる
    - ビルドに失敗するときは、Rebuildするといけたりする

- より詳細手順は[**こちら**](https://lethediana.sakura.ne.jp/tech/archives/steps-ja/1416/)
- 異なるPythonのバージョンを使いたいときは、リポジトリ内のDockerfileを変更
人はなぜ刀の柄にロケットランチャーを仕込みたくなるのか

## 誰向けの何
- これから事業やプロダクトを立ち上げようとしている人向け
- エセ昔話風にあるあるな落とし穴を話す記事

### 注意
- 全てフィクションです。架空の戦国時代です。
- あるあるを想像して書きました。具体的な人物・組織を思い浮かべて書いたわけではありません。
- 筆者は世界史選択なのでお殿様のシステムとかなにも知りません。

## 昔々あるところに
新しいもの好きで発想力の豊かな殿様がいました。殿様はあるとき思いつきました。

**「刀とロケットランチャーを融合させれば近距離、中距離、遠距離、隙がないのではないか！！」**

弓よりも破壊力があり、なんなら砦や城にも大きなダメージを与えられます。より強い国になれること間違いなしです。
自国で実績をあげれば良い値段で同盟国に売りつけることも視野に入ります。
逆に弓に刀を取り付けてしまうとか、槍にチェーンソーをつけるというアイデアも追って湧いてきました。ロケラン刀がウケたら融合シリーズとして次々と売り出すビジョンまで見えてきました。
この画期的なアイデアが盗まれないよう気をつけつつ、いちはやく実践投入しなくてはなりません。

殿様は早速高名な鍛冶屋を呼びつけ、すぐ作るよう命じました。
鍛冶屋は（遠距離は弓兵、城攻めは攻城部隊がいるし、運用もメンテもだるいんじゃねえか？）と思いましたがそんなこと言うと大変なことになるので、おとなしく作ることにしました。

## できた
さすが高名な鍛冶屋、半年くらいで作ることができました。情報が漏れてしまうと大変なので工房に缶詰でしたし誰とも話さず過ごしてきましたが、ようやく報われます。
鍛冶屋は「ASAPで」という殿様のオーダーに応えるための激務でげっそりした、しかしもらえる報酬への期待から口角の上がりきった顔でお城に馳せ参じました。

「お殿様、ご依頼いただいていたものができあがりました」

しかし、殿様は怪訝な顔をしています。

「柄ってあれじゃろ、最近は滑り止めつきのが流行っとるじゃろ？みんなもうあれに慣れてるからそんな普通の柄じゃ誰も使わないんじゃないか？」

**ラバーグリップ**。輸入素材を活用したもので、滑りづらさが売りです。10年ほど前に外国船が訪れてから最先端の鍛冶屋が取り入れたオプションでした。
武士たちの評判はぼちぼちですが、加工難易度の高さや籠手との相性、湿気によってむしろ滑りやすくなってしまう点などから鍛冶屋界隈では敬遠されているものです。しかも言うほど普及してないので「あれに慣れてる」というのはダウトです。

「しかもなんじゃその形。トレンドは半月形じゃろ？そんなまっすぐな刀、古臭くて外に出せんわい」

**ハーフムーンシルエット**。少し前に公開された小説によって「反りこそすべて」という風潮が生まれ、過剰な反り競争の結果、半円程度まで反るのが最も美しいとされるようになりました。
都で見せびらかす分には良いですが、実用性についてはもちろん不評です。しかも加工に非常に手間がかかります。

さて、逆らえない鍛冶屋は泣く泣くロケラン刀を抱え工房に帰りました。

## 改修した
技術力や情報収集能力は一流の鍛冶屋。見事にトレンドを取り入れた最高の刀を作り上げました。
素材や加工の手間により、もはや量産は不可能な代物と化しましたがなんとか希望通りです。
「今度こそ」という期待と「また何かクソオーダーが出てくるんじゃないか」という不安を胸にお城に向かいます。

「おお！見事じゃ！今風な刀に、最先端の組み合わせ！早速明日の紅白戦に投入しようぞ！！」

テンションの上がったお殿様は報酬そっちのけでそう言いました。こうなったら手が付けられません。落ち着いたころに報酬の話をしようと、鍛冶屋は一旦あきらめることにしました。

## おしまい
ロケラン刀のデビュー戦。鍛錬を目的とした、国を二分しての紅白戦が終了しました。
重くて握りづらい柄、慣れないラバーグリップ、実用性のないおしゃれなハーフムーンシルエット、そして使いどころ不明なロケットランチャー…。

現場では大不評でした。しかしそれを殿様に伝えると激怒するに違いないので、
「量産されて安くなったら買いたい」
「確かに自分が城攻めできたらなって思うタイミングはあった」
「現代では遠距離を主体にした製品の方がニーズが高いかもしれない」
「槍の方が得意な人向けにそういうオプションがあるともっとよさそう」
といった**一見すると好意的なフィードバック**を行いました。

大成功だと思った殿様は近隣の同盟諸国とNDAを結び、ロケランとラバーグリップとハーフムーンシルエットを扱えるシニア鍛冶屋たちを招集し、莫大な費用をかけロケラン刀の量産体制を整えました。

～

数年後、例の鍛冶屋は腕を買われ都に移籍し、刀でも槍でも弓でもない全く新しい製品の開発プロジェクトに関わることになりました。
一方でお城の倉庫は売れ残ったロケラン刀で埋め尽くされ、国は量産にかかわる多額の借金によって貧困にあえいでいました。

おしまい。

## 教訓
#### いま考えている画期的なアイデアも、他人からみたらロケラン刀ばりに怪しいものかもしれません。

論理的に考えて良さそうだったり様々な課題を解決できるように思えても、実現してみると非合理的だったり多くの課題を抱えていたりします。
いきなりロケラン刀を作るのではなく、「刀の使用者は遠距離も対応したいのか？」「刀の柄にロケランを仕込むのは実用的なのか？」などを**ユーザーヒアリング**や**プロトタイピング**で検証するのがよいでしょう。

#### みんなが見慣れているものは贅沢品です
みんながよく使うアプリは、莫大な資金や時間がつぎ込まれた最高級品です。
そこで活用されている「現代のスタンダードな仕様」は不足すると致命傷のように思いがちですが、実はプロダクトの成否にそこまで大きな影響はないです。
**狩野モデル**のような思考法を活用して採否を検討するのがよいでしょう。

#### ユーザーからの正しいフィードバック（=本音）こそが正義です
**「好意的・肯定的な意見が出る」** と、**「購入や確約といったアクション」** の間には大きな隔たりがあります。
また、自分に都合の良い解釈はしないようにしましょう。
フィードバック者は「自分がほしいもの」ではなく **「作ってみてもらいたいこと」** を話すことがあります（真偽不明、肌感）。
しっかり見極めましょう。

武士にヒアリングしたり、まずは弓刀をつくってみたり、フィードバックを匿名化したりしたらもうちょっと建設的だったかもしれません。知らんけど。
Spring Bootで共通レイアウトを作成

# はじめに
Spring Bootを使ってWEBページを作成する際、ヘッダー/フッターを読み込むhtmlは共通したものを使いたいと思いました。
今回はthymeleaf-layout-dialectを使っていきますが、なかなか画面に反映させるのに手間取ってしまったので、そのメモ書きです。


# ディレクトリ構成
```
java
└─ com.example.demo
    └─ ServletInitializer.java
       TestApplication.java
       BaseLayOutConfig.java
       LayoutController.java

resources
└─ templates
     └─ layout
         └─ layout.html
            content.html

```

# build.gradleの修正
build.gradleに以下を追記します
```gradle
dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect:3.1.0' ★追記
```
今回はthymeleaf-layout-dialectの3.1.0を使用します。

# BaseLayOutConfig.javaの作成
```java
package com.example.demo;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import nz.net.ultraq.thymeleaf.layoutdialect.LayoutDialect;

@Configuration
public class BaseLayOutConfig {
	
	@Bean
	public LayoutDialect layoutDialect() {
	    return new LayoutDialect();
	}
}
```
thymeleaf-layout-dialectを使用するにBeanの設定が必要です。
※クラス名やメソッド名は任意です。


# layout.htmlの作成
```html
<!doctype html>
<html xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
    <head>
        <meta charset="UTF-8" />
        <title>Base Layout</title>
    </head>
    <body>
        <h1>BaseLayoutです！</h1>
        <div layout:fragment="content">
        </div>
    </body>
</html>
```
共通レイアウト側のhtmlです。
layout:fragment="content"と記述しているところに、contnt.htnmlが入ります。


# content.htmlの作成
```html
<!doctype html>
<html xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="~{layout/layout}">
    <body>
        <div layout:fragment="content">
            Contentです！
        </div>
    </body>
</html>
```
こちらが呼び出される側のhtmlです。
layout:decorate="~{layout/layout}"で、共通レイアウトファイルを指定します。
layout:fragment="content"と記述することで、共通レイアウトが適用されます。

# LayoutController.javaの作成
```java
package com.example.demo;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class LayoutController {

    @GetMapping("/layout")
    public String method() {
        return "layout/content";
    }
}
```
http://localhost:8080/layout にアクセスすることで、先ほど作成したhtmlが表示されるようにします。
ここまで作成したら、上記にアクセスし、画面表示されればOKです。