OmniAICreator/Qiita-1.07M huggingface dataset:
モニタの繋ぎ目で途切れさせないで表示させる方法(mac)

macで2台以上のモニタを使用していると，繋ぎ目で分断されていることに気づきます。![Screenshot 2023-06-10 at 1.07.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3474804/24fb5d04-203c-df36-d5f1-aae191edc090.png)
これを解消する方法は　macOS Ventura 以降に少し変更があったようなのでまとめておきます。

設定
→デスクトップとDock
→Mission Control　の　「ディスプレイごとに個別の操作スペース」をOffにする。

※macOS Ventura13.2.1 で確認
ナワバトラー分析用データセット

# なんの記事？


これからナワバトラーのデータ分析などを始めたい方向けに基本的な情報をまとめたデータセットを作成しました。

2024春シーズンのカードまで対応。(イイダまで収録。)


# データセットの内容

### スプレッドシート

https://docs.google.com/spreadsheets/d/1kBBjut-2koYzGB8YEXGHbfLqgBTk5x--3P1SbJJH99M/edit?usp=sharing

コピーして使ってください。
以下、各シートの具体的な内容。

- **カード**
  カード名、マス数、必要SP、レアリティに加え
カテゴリ、登場シーズン、マス配列、画像など

- **ステージ**
ステージ名、マス数、マス配列、画像など

- **NPC**
NPC名、対戦ステージ、AIタイプ、画像など

- **デッキ**
NPCが使用するデッキなど
- **デッキ_可視化**
デッキシートの情報を画像で可視化したシート(スプレッドシートのIMAGE関数を使っているため表示が少し遅い)

- **レアリティ**
かけらの獲得数、消費数など

- **アップデート**
公式パッチノートのナワバトラー関連のアップデート履歴

- **リンク集**
本データセットを作るにあたって参考にした記事やデータセット。正直このリンク先を見た方がいいです。





### カードイラスト画像

ゲーム画面のカード画像をキャプチャして切り抜いたものです。
イイダまで収録。

https://drive.google.com/drive/folders/1cmP5k0NW_49jnQLxe_wdaYZLh6iwp2Hb?usp=sharing


# 使用例


カード間同士の発火関係を調べPower BIで可視化

https://qiita.com/gigi/items/5099700c7af50c4b6350



# 課題


今後、以下データも一元化したいです。

- 言語

- SOZAI画像

- 発火表
【JavaScript】letとvarの違いについて

# はじめに
JavaScriptでは「let」と「var」があり、どちらも変数を宣言できるのですが、その性質には違いがあります。本記事ではその違いについてまとめます。

# var
### var のスコープ
スコープとは、宣言された変数が有効な範囲のことです。var宣言は、関数の外で宣言される場合はグローバルスコープ（どこでも使える）となり、関数の中で宣言される場合はローカルスコープ（関数の中だけで使える）となります。
```sample.js
var greet = "how are you?";
    
function newFunction() {
    var hello = "hello";
}
console.log(greet); // how are you?
console.log(hello); // ReferenceError: hello is not defined
```
上の例では、変数greetは関数の外で宣言しているため、グローバルスコープです。一方、変数helloは関数の中で宣言しているため、関数の外ではアクセスできません。

```sample.js
var japanese = false;
var greet = "how are you?";

if(japanese) {
    var hello = "こんにちは";
}else{
    var hello = "hello";
}

console.log(greet); // how are you?
console.log(hello); // hello
```
こちらの例では変数helloはelseの{ }内で宣言されていますが、関数内ではないので、{ }の外でも変数にアクセスできます。

### var は再宣言が可能
varでは同名の変数を再宣言することが可能です。
```sample.js
var hello = "hello";
var hello = "こんにちは";
console.log(hello); // こんにちは
```
varは上の例のように再宣言してもエラーを起こさず、実質上書きされます。

```sample.js
var hello = "hello";
hello = "こんにちは";
console.log(hello); // こんにちは
```
こちらのように、再宣言せず更新することも可能です。

### var 宣言の巻き上げ
varによる宣言では、「巻き上げ」と呼ばれる処理が行われます。
```sample.js
console.log(hello); // undefined
var hello ="hello";
```
上の例ではvar宣言がconsole.logの後に書かれています。しかし、処理の順番としては、helloの変数作成と初期値「undefined」の代入が最初に行われ、console.log()の後に、"hello"の代入が行われます。console.log()の時点で変数helloには初期値「undefined」が入力されていることがわかります。

### var 宣言の問題点

```sample.js
var japanese = false;
var greet = "how are you?";

if(japanese) {
    var greet = "こんにちは";
}else{
    var greet = "hello";
}

console.log(greet); // hello
```
上の例ではelse内での処理により、最初に宣言した変数greetが上書きされています。意図して行っていれば問題ありませんが、気づかずに宣言した場合は様々なバグの原因となるため、注意が必要です。

# let

### let のスコープ
let宣言はブロックスコープと呼ばれ、{ }に挟まれた範囲でのみ有効となります。

```sample.js
let japanese = false;
let greet = "how are you?";

if(japanese) {
    let hello = "こんにちは";
}else{
    let hello = "hello";
}

console.log(greet); // how are you?
console.log(hello); // ReferenceError: hello is not defined
```
var 宣言の場合と違い、{ }内で宣言された変数helloに{ }外ではアクセスできません。

### let は再宣言が不可能
letでは同名の変数を再宣言することができません。
```sample.js
let hello = "hello";
let hello = "こんにちは"; //Uncaught SyntaxError: Identifier 'hello' has already been declared
console.log(hello);
```
上記のコードはエラーを返します。

```sample.js
let hello = "hello";
hello = "こんにちは";
console.log(hello); // こんにちは
```
一方で、こちらのように、再宣言せず更新することは可能になっています。

### let 宣言の巻き上げ
let 宣言にも、「巻き上げ」処理が行われます。しかし、var とは挙動が異なります。
```sample.js
console.log(hello); // ReferenceError: Cannot access 'hello' before initialization
let hello ="hello";
```
let 宣言の巻き上げ処理では、helloの変数作成のみ最初に行われ、初期値の代入はありません。よって空白のデータを参照し、エラーを返しています。

# まとめ
・var 宣言はグローバルスコープまたは関数スコープであるのに対し、let 宣言はブロックスコープ。
・varで宣言された変数は再宣言可能だが、letで宣言された変数は再宣言不可能。
・varもletも巻き上げ処理が行われるが、letでは初期値の代入がないので注意。
・varは{ }外で宣言された変数を{ }内で上書きしてしまうので、扱いには注意が必要。（と言うよりも、基本的に変数にはletを使った方がよさそう）
|  |var|let|
|---|---|---|
|再宣言|可能|不可能|
|スコープ(有効範囲)|グローバルスコープ / 関数スコープ|ブロックスコープ（{ }の中で有効）|
AIコードジェネレーターとTDDって親和性高くない、、、？

# 目的
先日、GitHub Copilotに関するオンラインセミナーを受けていたところ  
「GitHub Copilotは、エディタ上で開かれているソースの内容も考慮してソースを推論する」という特徴を聞きました。
ふと、
**「テストコードさえ書いたらその要件を満たすコードを勝手に生成してくれるのでは、、、？**
なんて興味が湧いたので検証してみようと思います。
もし、期待通りになったらTDDが今後さらに熱を帯びるのではないでしょうか。

使用言語: python
テストフレームワーク: pytest

# まずは簡単なコードで試す
 関数名から推論されないように無機質な名前にしています。
```python
class Functions:
    def function(a ,b):
        return a + b
    

class TestClass:
    
    def test_function1(self):
        assert Functions.function(4,5) == 9
    
    def test_function2(self):
        assert Functions.function(100,150) == 250
        
    def test_function3(self):
        assert Functions.function(-5, -10) == -15
```
上記の関数部分を消して、GitHub Copilotに推論させてみると、、

**出た！！**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2725423/73f3daf8-786b-e104-788a-35b56cafb66d.png)

掛け算に変えると変換も変わりますね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2725423/32393c8e-13b3-4b9e-ce66-f4d1099852d9.png)

絶対値を返すような足し算には対応できない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2725423/dfaebb54-0807-6008-cab5-804ad0257ee5.png)

テストケースを増やしても変わらず、、、雲行きが、、、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2725423/77c979d8-cd3d-657f-5e94-4172f811f8ed.png)

# 問題の難易度を上げてみる
引数a,b,cに対して`a*b-c`の値を返すような関数を期待したテストケースを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2725423/37c44a7f-9335-af2f-aaaa-97c22bf48281.png)

それに対しての推論はこちら
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2725423/f3839bdb-e885-70f5-a511-6d718b26f570.png)


***う～ん、、、、***（テストはもちろん全部誤っていた）

ちなみにChatGPT4に同じ質問したところ


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2725423/03f4e94e-467f-0af7-2977-d3200d631bcf.png)

それぞれのテストに通すための分岐が生成されているため、こちらの方が未来を感じますね。
※ミスり方がプログラミング初心者レベルなのが愛着が持てる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2725423/fa326144-164d-a601-6a36-7ec51c8ea416.png)


# 最後に
TDDを促進するような使い方はまだできなさそうな感じを受けました。
こういった使い方はまだまだ実用レベルには及ばないですね。
GitHub CopilotはChatGPT3.5ベースとのことなので、今後、Chat4ベース、もしくはそれ以上になってくるともっと有用性が増すと思うので、期待したいと思います。
【初心者】export defaultのあとに勝手にawait import(’vue)).definecomponentと記述されてしまう問題

# 困ったこと
export defaultのあとに勝手にawait import(’vue)).definecomponentと記述されてしまう

# カーソルを当ててみる
This is virtual code that is automatically wrapped for type support, it does not affect your runtime behavior, you can customize it via vueCompilerOptions.optionsWrapper option in tsconfig / jsconfig. To hide it, you can set "vue.inlayHints.optionsWrapper": false in IDE settings.
と出た。
なるほどわからん。

# 翻訳してみると
「これは型サポートのために自動的にラップされる仮想コードであり、実行時の動作には影響しません。tsconfig / jsconfig のvueCompilerOptions.optionsWrapperオプションを使用してカスタマイズできます。これを非表示にするには、IDE 設定で"vue.inlayHints.optionsWrapper": false を設定します。」

# つまり
VSCodeの設定をいじれば消せそう

# 設定の仕方
①[メニュー]-[Code]-[基本設定］-［設定］の順に選択。
②開いた検索タブに【vue.inlayHints.optionsWrapper】と入力。
④vue.inlayHints.optionsWrapperを【false】に。
        
# 結果
await import(’vue)).definecomponentが消えた！
ブラウザ毎のCookieのSameSite属性の動きを確認した

## 環境
- Chromium: 114.0.5735.110（2023/06/05）
- Firefox: 114.0（2023/06/06）
- Safari: 14.1.1（iOS 14.6）（2021/05/24）

## クロスオリジンのとき

-| Chromium | Firefox | Safari
-|-|-|-
遷移(GET)|None/**Lax**|**None**/Lax|**None**/Lax
遷移(POST)|None|**None**|**None**
fetch(GET/POST)|None|-|- (**None**※1)

- 太字はデフォルト値
- MDNの記載通り。
- Firefox,Safariのfetchでは、アンチトラッキングによりNoneでも送信されない
- ※1 設定「サイト越えトラッキングを防ぐ」がOFFの場合

## 同一ドメインのスキーム違いのとき（HTTP->HTTPS）

-| Chromium | Firefox | Safari
-|-|-|-
遷移(GET)|None/**Lax**|**None**/Lax/Strict|**None**/Lax/Strict
遷移(POST)|None|**None**/Lax/Strict|**None**/Lax/Strict
fetch(GET/POST)|None|**None**/Lax/Strict|**None**/Lax/Strict

- 太字はデフォルト値
- SameSite=StrictのCookieも送信された。
    MDNでのStrictの説明(2023/06/10時点)と相違している。
    [If a request originates from a different domain or scheme (even with the same domain), no cookies with the SameSite=Strict attribute are sent.](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#strict)

## おまけ：Secure属性がついたCookieをHTTPで上書き

| Chromium | Firefox | Safari
|-|-|-
|不可|不可|不可
AWS Cloud Practitioner取得まで道のり

# 取得目的
エンジニア未経験（上流工程経験あり）の人間が４月に転職して、インフラエンジニアなりました。
AWSは触ってみてとても楽しかったのでインフラの中でもクラウドエンジニアを目指そうと思いその足掛かりになればいいなぁと思ったからです。

# 勉強期間
１ヶ月
通勤の往復２時間で勉強時間は足りました。

# 使った教材
【2023年版】この問題だけで合格可能！AWS 認定クラウドプラクティショナー 模擬試験問題集（6回分390問）

https://www.udemy.com/share/101I2O3@cuCza8mEPtRWvByoojQRo2wFcf6oJuTyw7F6EALHQkNS8xHicwbQ4QgHQbgcHMb6Wg==/

chatgpt

https://chat.openai.com/


# 勉強方法
以下の順序で勉強をすすめていました。
1. すべての問題を無回答で終わらせる。
2. 各設問の解説を頭に叩き込む。
3. 模擬試験を回答する。
4. 間違えた問題と選択肢を１個に絞れなかった問題の解説を見る。
    4-1.解説を見ても腹落ちしない物はchatgptで概要をつかんでからリファレンスを読む。
    4-2.AWS環境で構築できるものは構築してみる。 
5. エビングハウスの忘却曲線に従って再度模擬試験を行う。  
6. 4-5の繰り返し
7. 6つの模擬テストすべて90%以上の正答率で受験に臨む。

# 結果
最初の2、3問がほんとにわからなくてやばいかなって思いましたが蓋を開けてみれば楽々でした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3218631/d2c97542-04bf-7a9d-2d40-136395343de8.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3218631/19ace20f-8cc9-eec1-2b19-f8b9d5ad0cf4.png)

# 最後に
一日2時間、20日で取得できるので学習コストはかなり低いと思います。
Udemyの教材が優秀すぎるのでこれだけで十分だと思います。
次回はSAAですね。模擬試験見ただけど難しそうです。
Powershellでワンライナー(ファイル名に連番を振ってリネーム)

# はじめに
今はバッチで色々スクリプト組んでますが、やりたいことを簡単に実現させたいので(1行で貼りつけるだけで簡単にできるので楽)

# ワンライナー
```powershell:FilenameReplace.ps1
# ファイル名に連番を振ってリネーム
ls | sort Name | % {$i = 1} {mv $_.Name ("{0:000}.txt" -f $i++)}

# 指定フォルダ移動⇒ファイル一覧ソート⇒in/outセットでファイル名に連番を振ってリネーム
Set-Location bak; Get-ChildItem | Sort-Object Name | ForEach-Object {$i = 1;$j = 0} {if(($i % 2) -eq 1 ) {Move-Item $_.Name ("{0:000}_in.txt" -f $j);$i++} else {Move-Item $_.Name ("{0:000}_out.txt" -f $j);$i++;$j++}}
```

# 参考サイト
※関係ないサイトもあるのですが、後で使うことあるかもなので
◆Powershellでファイル名に連番を振ってリネームする
　https://helve-blog.com/posts/powershell/powershell-rename-files-serial-number/
異色VSCode 混合テーマの作成


VSCodeであるテーマとあるテーマの色を同時に利用したいとき、ありませんか？

たとえば、テーマ色はDraculaが良いけど、シンタックスハイライトはDark+が良いといったときです。

あまり役に立たない知識になりますが、参考程度までに載せておきます。

環境: Arch Linux

## テーマのインストール

今回はDraculaテーマにシンタックスハイライトをDark+のものを使用します。

とりあえずDraculaをインストールします。

## テーマのjsonファイルを移植

インストールした拡張機能(テーマ)は`.vscode/extensions/`以下に格納されています。
catなどでテーマファイルを開いてください。参考までに、Draculaのテーマの一部を載せておきます。
```json:dracula.json
....
    "colors": {
        "terminal.background": "#282A36",
        "terminal.foreground": "#F8F8F2",
        "terminal.ansiBrightBlack": "#6272A4",
        "terminal.ansiBrightRed": "#FF6E6E",
...
```
ここで`colors`を移植する際は、`colors`のところを`workbench.colorCustomizations`に書き換えてください。
あとはこれを自分のsettings.jsonに移すだけです。

# 実装後

+ Dark+テーマ

![Screenshot from 2023-06-09 23-49-29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729508/1c1f6259-5fd6-3ce4-3114-ac58cae1ad5b.png)


+ Draculaテーマ
![Screenshot from 2023-06-09 23-49-54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729508/e4f0346c-f81b-7eff-dd77-b4d853368160.png)

+ 混合テーマ(テーマ: Dracula, シンタックス: Dark+)

![Screenshot from 2023-06-09 23-50-15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729508/6c505438-6d35-8d83-d939-6dbd1e7d16c8.png)

以上です。お疲れ様でした。

Dark+のjsonファイルはどこに格納されているのかわからなかったので知っている人がいれば教えてください。
[AWS Q&A 365][ECS]AWSのよくある問題の毎日5選 #75

# 1. Amazon Elastic Container Service（ECS）とは何ですか？
回答：Amazon Elastic Container Service（ECS）は、Amazon Web Services（AWS）上でコンテナ化されたアプリケーションを簡単に実行、スケーリング、およびセキュリティを確保するための、完全に管理されたコンテナオーケストレーションサービスです。

# 2. Amazon ECSの主要なコンポーネントは何ですか？
回答：Amazon ECSの主要なコンポーネントは、クラスター、タスク定義、タスク、およびサービスです。

# 3. クラシックAmazon ECSコンソールを使用してクラスターを作成する方法はありますか？
回答：クラシックAmazon ECSコンソールを使用してクラスターを作成するには、「クラスター」ページに移動し、「クラスターの作成」ボタンをクリックし、クラスタータイプを選択し、クラスターの設定を構成することができます。

# 4. クラシックAmazon ECSコンソールを使用してタスク定義を作成する方法はありますか？
回答：クラシックAmazon ECSコンソールを使用してタスク定義を作成するには、「タスク定義」ページに移動し、「新しいタスク定義の作成」ボタンをクリックし、タスクタイプを選択し、タスクの設定を構成することができます。

# 5. クラシックAmazon ECSコンソールを使用してサービスを作成する方法はありますか？
回答：クラシックAmazon ECSコンソールを使用してサービスを作成するには、「サービス」ページに移動し、「サービスの作成」ボタンをクリックし、タスク定義を選択し、展開タイプ、希望する数、および負荷分散などのサービスの設定を構成することができます。
[AWS Q&A 365][ECS]Daily Five Common Questions #75

# 1. What is Amazon Elastic Container Service (ECS)? 
Answer: Amazon Elastic Container Service (ECS) is a fully-managed container orchestration service that helps you easily run, scale, and secure containerized applications on Amazon Web Services (AWS). 

# 2. What are the key components of Amazon ECS? 
Answer: The key components of Amazon ECS are clusters, task definitions, tasks, and services. 

# 3. How can I create a cluster using the Classic Amazon ECS console? 
Answer: To create a cluster using the Classic Amazon ECS console, you can navigate to the "Clusters" page, click the "Create Cluster" button, select the cluster type, and configure the cluster settings. 

# 4. How can I create a task definition using the Classic Amazon ECS console? 
Answer: To create a task definition using the Classic Amazon ECS console, you can navigate to the "Task Definitions" page, click the "Create new Task Definition" button, select the task type, and configure the task settings. 

# 5. How can I create a service using the Classic Amazon ECS console? 
Answer: To create a service using the Classic Amazon ECS console, you can navigate to the "Services" page, click the "Create Service" button, select the task definition, and configure the service settings such as deployment type, desired count, and load balancing.
QGISプラグイン開発におけるQActionのsetWhatsThisについて

# 環境

- QGIS 3.28 LTR

# QGISプラグインにおけるQActionのsetWhatsThisについて
QGISのプラグインのサンプルコードを見ていると、`QAction` オブジェクトの `setWhatsThis()` という関数を呼び出している例が見られます。

QGIS公式ドキュメントのサンプルコードでも以下のように呼び出されています。

```mainPlugin.py
  def initGui(self):
    # create action that will start plugin configuration
    self.action = QAction(QIcon("testplug:icon.png"),
                          "Test plugin",
                          self.iface.mainWindow())
    self.action.setObjectName("testAction")
    self.action.setWhatsThis("Configuration for test plugin")
    self.action.setStatusTip("This is status tip")
    self.action.triggered.connect(self.run)
```

https://docs.qgis.org/3.28/ja/docs/pyqgis_developer_cookbook/plugins/plugins.html

しかし、上記のような処理で作成したプラグインのアイコンをQGISのGUI上でマウスホバーして表示されるのは `QAction` の引数で指定した `Test plugin` の文字列で、`setWhatsThis()` で指定した `Configuration for test plugin` の文字列は確認できません。

![mousehover.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591150/6f35d541-2066-91c6-2013-c6998cc0089f.png)



PyQtのドキュメントを参照すると、`setWhatsThis()` で指定した文字列は What’s This? モードに移行することで確認できるようです。

https://doc.qt.io/qtforpython-5/PySide2/QtWidgets/QWhatsThis.html

ただ、QGIS 3.28 LTRのインターフェイスで確認する限り、この What’s This? モードに移行する機能は提供されていないようです。調べてみると、以前はヘルプメニューに存在していたものの、`setWhatsThis()` による説明を記載している機能が少なかったため、このメニューは削除されたようです。

https://github.com/qgis/qgis3_UIX_discussion/issues/34

なので、QGISのプラグイン開発においては基本的に `setWhatsThis()` は使用しないことで問題なさそうです。


# 参考：Pythonコンソールを使用して What’s This? モードに移行する方法
QGISのインターフェイス上では What’s This? モードに移行する方法は提供されていませんが、Pythonコンソールを使うことで呼び出しが可能です。

QGISのPythonコンソールを開き、以下の関数を呼び出します。

```python
QWhatsThis.enterWhatsThisMode()
```

すると、What’s This? モードに移行してカーソルが変化します。

![console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591150/a29bf802-f4e1-c9b8-ec49-0553815e4ed9.png)

この状態でプラグインのアイコンをクリックすることで、`setWhatsThis()` のテキストの表示が可能です。

![whatsthis.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591150/fbbf7d92-9438-3150-5ab8-8b368cabb5df.png)

# 関連記事
QGISのプラグインの実装例をこちらの記事で紹介しています。

https://nujust.hatenablog.com/entry/2023/06/10/101433
Google Compute Engine へ Ed25519 で SSH 接続する話

Google Compute Engine は接続するだけなら、ブラウザで十分ですし、ポート変更やらある程度対策してれば問題ないと考えていますが、現在の選択の中では最も強固と言われている Ed25519 で接続したいと思いかきかきしてます。

はじめに
---
2023年6月現在の Google Compute Engine では、
- ブラウザからアクセスすると、ECDSA 鍵が自動生成
- gcloud CLI からアクセスすると、RSA 鍵が自動生成

されるようになっています。
また、ブラウザの「指定された秘密 SSH 鍵を使用してブラウザ ウィンドウを開く」では、ECDSA か RSA しか選択できないあたり、公式には Ed25519 を対応する気も無さげに見えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461400/d1c73cee-3690-dd90-be89-932e90f0f4fd.png)
こんな感じなので、Ed25519 でアクセスしたいなら、外部のSSHクライアントからじゃないとアクセスできないようです。

必要なもの
---
- [gloud CLI](https://cloud.google.com/sdk/docs/install?hl=ja)（VMにアクセスする時に必要になります）
- 外部のSSHクライアント（TeraTerm など）

手順
---
1. 手順に従って、gcloud CLI をインストールを行う
1. クライアントにて `gcloud compute config-ssh` を実行する（ログインして実行してください）
![2023-06-09 232110.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461400/dad28c3e-efb1-2fab-b687-6c5e96c6e7a8.png)
1. `ssh-keygen -t ed25519 -f gce_ed25519 -C <ユーザー名>` をクライアントで実行して Ed25519 鍵を作成する（ファイル名は変更OK）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461400/4c840938-4fb6-a0b4-ddfc-9d62b97c264a.png)
1. `.ssh`フォルダに生成された公開鍵（gce_ed25519.pub）の中身のテキストをコピー
1. Google Cloud Console から VM の編集ページを開き、SSH 認証鍵に貼り付け
![pic.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461400/b287daa0-a937-7df5-5024-ff7b10c85db5.png)
1. `.ssh`フォルダに`config`ファイルが生成されているので、中身を確認する
    1. `IdentityFile`の部分を 生成した秘密鍵（gce_ed25519）に変更する
    1. `Host`の部分をコピーする（これがホストになります）
![pic2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461400/368bd48c-1981-ffee-463a-0cd38629c988.png)
1. 外部のSSHクライアントで `ssh <ユーザー名>@<ホスト>` を実行して、VMへアクセスする


さいごに
---
あとは、ポート変更とファイアウォールの設定変更でもしてセキュリティを高めましょう。また、お使いの回線が IPoE であれば、SSH できる IPv4 を制限するとより良いかと。

なお、**ネットワーク インターフェース** の **外部 IPv4 アドレス** を **エフェメラル** にしている場合、ホスト名が定期的に変わります。
ホスト名の変更があると、ホスト名の解決ができなくなり、外部のSSHクライアントから接続できなくなってしまいます。`gcloud compute config-ssh` を実行して、configファイルを再生成してあげてください。
【CSS】bodyの罠

実際はbodyが悪いわけではなくただの仕様ですが、知らないとbodyが悪いように見えます。

# その1 marginが0でない

例えば以下のようなhtmlの場合、左上端に隙間ができます。  
![bodymargin1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/a8f54102-8480-9857-cf31-e92ff4b42493.png)  
```html
<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <style>
        div {
            height: 30px;
            width: 30px;
            background-color: blue;
        }
    </style>
</head>

<body>
    <div></div>
</body>

</html>
```
原因はブラウザのデフォルトスタイルが設定されるためです。  
[ブラウザのデフォルトスタイルをリセットする (1/3)|CodeZine（コードジン）](https://codezine.jp/article/detail/3018)

左上端にピッタリくっつけるためには明示的に`margin`を`0`にしてやる必要があります。  
```css
body {
    margin: 0;
}
```
![bodymargin2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/83060e0d-0e96-e238-804b-e7243e26e815.png)  

# その2 背景色が`<html>要素`にも適用される

画面左側全体に青い長方形を描こうとして、以下のように記述しても何も表示されません。

```html
<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <style>
        body {
            margin: 0;
        }

        div {
            height: 100%;
            width: 30px;
            background-color: blue;
        }
    </style>
</head>

<body>
    <div></div>
</body>

</html>
```
![bodycolor1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/d8c7177e-ceff-41fb-c14b-a403c804e3ac.png)  

`<body>要素`の`height`が`0`なのかと思って背景色を設定してみると、
```css
body {
    margin: 0;
    background-color: antiquewhite;
}
```
色が変わります。  
![bodycolor2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/6ea53580-2d9f-2cc6-b4a1-1c010e556d18.png)  

* [`background-clip`](https://developer.mozilla.org/ja/docs/Web/CSS/background-clip)の初期値は`border-box`なのでパディング領域まで背景色が適用されるはず。  
* [`padding`](https://developer.mozilla.org/ja/docs/Web/CSS/padding)の初期値は`0`なので色がついたところがコンテンツ領域のはず。  
* [`box-sizing`](https://developer.mozilla.org/ja/docs/Web/CSS/box-sizing)の初期値は`content-box`なので色が変わった部分の高さが`height`のはず。  

にも関わらず`<div>要素`が描画されません。結論からすると`<body>要素`の`height`が`0`であることが原因なので、
```css
body {
    margin: 0;
    background-color: antiquewhite;
    height: 100vh;
}
```
とすることで、きちんと表示されます。  
![bodycolor3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/a878f61f-4940-3c81-b99e-633f1ffdd923.png)  

結局何が分かっていなかったというと、  

`root要素`（ここでは`<html>要素`）が`background-image:none`かつ`background-color:transparent`の場合（＝つまりどちらも初期値の場合＝明示的に設定されていない場合）、**`<body>要素`の背景プロパティが`root要素`に伝播する**、ということです。  
参考）[CSS Backgrounds and Borders Module Level 3](https://drafts.csswg.org/css-backgrounds/#body-background)    
  
設定により`<body>要素`だけでなく`root要素`の背景色も変わったので、あたかも`<body>要素`が画面いっぱいにあると誤認したということです。

# 補足

最初から開発者ツールで`<body>要素`の確認しておけばよかっただけ。`margin:8`、`height:0`であることが一目瞭然。  

![bodycolor4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/d6131e0c-d818-d7a4-692b-09f3a6ad8657.png)
【ポケモンSV】一撃必殺パーティの勝率を計算してみる

ポケットモンスター、縮めてポケモン。この文言を記事の先頭に持ってくることによって、グッと雰囲気が増しますよね。本記事で紹介するのは、ポケモンのランクマッチにおいて、一撃必殺技だけで相手ポケモン3体を倒せる確率、ひいてはランクマッチ1位になる確率の計算方法です。漸化式を使って求められるので、高校生3年生でも理解できるかと思います。目指せランクマッチ1位。

# 一撃必殺技とは
一撃必殺技は、命中すれば相手のポケモンを一撃で瀕死にできます。チート技である反面、命中率は30%とポケモンの技の中で最も低く設定されています。ランクマッチ環境でもしばしば使われていて、どうしようもなくなった場面で打つことが多い。一撃必殺技を主体としているパーティは非常に珍しく、その理由はやはり、運任せよりも実力プレイのほうが上位帯に食い込めるからでしょう。筆者が知る限り、近年で、一撃必殺技パーティがランクマッチ1位を取った例はないかと思います（筆者がプレイしているのは、サンムーン～スカバイです)。しかし、確率を熟知していれば、実力で運を引き寄せることも十分可能です。何回打てば、どれくらいの勝率なのか。どれくらいの勝率だと、どれくらいの順位なのか…。打つべき目標回数が決まっていれば、耐久ラインへの意識や立ち回りも変わってきます。以下の本文では、一撃必殺技の試行回数ごとの勝率を計算しております

# 計算方法
計算は、「n回一撃必殺技を打つと、3回以上命中する」確率を求める計算とします。そのため、漸化式を用いました
### 勝利条件
今回、計算に際し、勝利条件を「一撃必殺技がちょうど3回命中したとき」としました。2023/06/09現在のポケモン対戦では、きあいのタスキによる体力満タン時の1発耐久保証や、特性「がんじょう」による一撃必殺技無効仕様が存在しますが、今回は考慮しません。以下が、コードです

```python:ichigeki.py
from scipy.special import comb
import matplotlib.pyplot as plt

p = 0.3 #一撃必殺技の命中率
n = 24 #試行回数の上限

#3回打ったときの確率
q0 = p**0*(1-p)**3*comb(3,0,exact=True) #0回命中
q1 = p**1*(1-p)**2*comb(3,1,exact=True) #1回命中
q2 = p**2*(1-p)*comb(3,2,exact=True) #2回命中
q3 = p**3 #3回命中
print("{0}回一撃必殺技を打つと{1}%の確率で3回以上命中する".format(3,round(q3*100,3)))

x = []
y = []
for i in range(4,n+1):
    q3 = q3 + q2*p
    q2 = q2*(1-p) + q1*p
    q1 = q1*(1-p) + q0*p
    q0 = q0*(1-p)
    print("{0}回一撃必殺技を打つと{1}%の確率で3回以上命中する".format(i,round(q3*100,3)))
    x.append(i)
    y.append(q3)

plt.plot(x,y)
plt.xlabel("試行回数",fontname="MS Gothic")
plt.ylabel("3回以上命中する確率",fontname="MS Gothic")
plt.show()
```
以下が出力結果です
```
3回一撃必殺技を打つと2.7%の確率で3回以上命中する
4回一撃必殺技を打つと8.37%の確率で3回以上命中する
5回一撃必殺技を打つと16.308%の確率で3回以上命中する
6回一撃必殺技を打つと25.569%の確率で3回以上命中する
7回一撃必殺技を打つと35.293%の確率で3回以上命中する
8回一撃必殺技を打つと44.823%の確率で3回以上命中する
9回一撃必殺技を打つと53.717%の確率で3回以上命中する
10回一撃必殺技を打つと61.722%の確率で3回以上命中する
11回一撃必殺技を打つと68.726%の確率で3回以上命中する
12回一撃必殺技を打つと74.718%の確率で3回以上命中する
13回一撃必殺技を打つと79.752%の確率で3回以上命中する
14回一撃必殺技を打つと83.916%の確率で3回以上命中する
15回一撃必殺技を打つと87.317%の確率で3回以上命中する
16回一撃必殺技を打つと90.064%の確率で3回以上命中する
17回一撃必殺技を打つと92.261%の確率で3回以上命中する
18回一撃必殺技を打つと94.005%の確率で3回以上命中する
19回一撃必殺技を打つと95.378%の確率で3回以上命中する
20回一撃必殺技を打つと96.452%の確率で3回以上命中する
21回一撃必殺技を打つと97.287%の確率で3回以上命中する
22回一撃必殺技を打つと97.933%の確率で3回以上命中する
23回一撃必殺技を打つと98.431%の確率で3回以上命中する
24回一撃必殺技を打つと98.813%の確率で3回以上命中する
```
![一撃必殺グラフ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3474165/0e51800f-956d-accd-9b8f-aba8518ee5af.png)



# ランクマッチで1位を取れる一撃必殺パーティは？
　ポケモンSVランクマッチ シーズン1の最終1位はバンビーさんで233勝136敗、勝率63.1%でした。そのため、1位ないしは上位帯に食い込むためには、**11回一撃必殺技を打てるパーティを組む**必要があると言えます(11回打つと、68.7%の確率で3回以上命中する)。
### 一撃必殺技を11回打つには
 1体で4発撃つ必要があるので、相手の技を4発耐えられるように耐久調整が必要です。幸い一撃必殺技を打てるポケモンには、キョジオーン、カバルドン、ヘイラッシャ、ドドゲザンのような高耐久ポケモンがいますので、十分に可能ではないでしょうか？一撃必殺技といえば運ゲーの印象が強いですが、命中させる目標回数を設定して、調整や立ち回りを決めておくと、ものすごくいけそうな気がしますよね

# 最後に
筆者はあまりポケモンが上手くないです。強者の皆様、この理論を盾にパーティを組んで、戦ってみてください。みんなのうれしい報告待ってるよ。
ExcelVBAフォーム最大化時のフォームサイズ変更

# 最大化時にサイズが変更できないエラー384
1. <font color=red>**Win32API**</font>を使用すると下図のようにUserFormの**タイトルバー**に<font color=red>**最小化、最大化ボタンを追加**</font>することができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394814/f8bead36-5869-87da-b1a6-b88b2b3fc861.png)

1.  **最大化**された状態で「UserForm1.Height = 500」のように<font color=red>**フォームサイズを変更**</font>しようとすると下図のような「実行時エラー'384'最大化または最小化されているフォームは、移動またはサイズ変更することができません。」という<font color=red>**エラーが発生**</font>する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394814/caf5d473-b84b-8b4b-01a1-6428faaf48a9.png)


    


# 解決方法

タイトルバーの**拡大縮小ボタン用のＡＰＩに加え**以下のＡＰＩを追加する。
```vb
Option Explicit
'Windows API宣言
Private Declare Function ShowWindow Lib "User32" (ByVal Hwnd As Long, ByVal nCmdShow As Long) As Long

```

<br>

次にフォームを変更するプログラムの前に「Call ShowWindow(GetActiveWindow(), 1)」を追加する。
```vb
Private Sub CommandButton1_Click()
    Call ShowWindow(GetActiveWindow(), 1) 'フォームのサイズを元に戻す
    UserForm1.Height = 500 'フォームのサイズ変更
End Sub
```

これでサイズ変更が可能になる。
Next.jsにおけるStreaming機能とは

## はじめに
こちらはNext.jsにおけるStreaming機能についての記事になります。

よろしければ公式ドキュメントのほうも併せてご覧ください。

https://nextjs.org/docs/app/building-your-application/routing/loading-ui-and-streaming

## Streaming機能を使うメリット
Streaming機能を使うメリットは、ユーザーに対してのレスポンス(HTML返却)を早くすることが可能となることです。

![スクリーンショット (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1220815/9616f41f-2b6e-7c53-37ce-a341541adf41.png)

上記はStreaming機能を使わない図を表していますが、例えばNext.jsのサーバー側で非同期通信を行って取得したデータをもとにして生成されるコンポーネントがあった場合、そのコンポーネントが生成されるまでHTMLが返却されないのでユーザービリティが悪くなってしまいます。

その問題はStreaming機能を使うことで解消されます。

![スクリーンショット (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1220815/27a63fbc-5cc1-052d-8846-f22d717f4afe.png)

上図の青い枠で囲まれたコンポーネントが非同期通信で取得したデータを基にしてコンポーネントが生成されるのですが、非同期通信でNext.jsのサーバー側がコンポーネントを生成している間、デフォルトのコンポーネント(ローディングアイコンなど)をクライアント側に返却しておき、サーバー側のコンポーネントが生成されたらそれをクライアント側に返却して取り替えます。そうすることで初期画面の表示が早くなり、ユーザービリティが向上します。

では次にコードで実際に確認していきたいと思います。

## 環境構築

```terminal: gitbash
$ npx create-next-app@latest .
```

### Package.json
![スクリーンショット (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1220815/fc409374-18b4-087b-9f2b-e7c9f369c6c3.png)

### ディレクトリ構成
![スクリーンショット (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1220815/d1dc1a01-adb7-3fbc-4abd-a6f1bf44861b.png)

### ファイル構成
```typescript: page.tsx
import { Suspense } from 'react';
import UserList from './UserList';

const Page = async () => {
  return (
    <div className="m-4">
      <h1 className="text-lg font-bold">ユーザ一覧</h1>
      <Suspense fallback={<p>Loading...</p>}>
        <UserList />
      </Suspense>
    </div>
  );
};

export default Page;
```

```typescript: UserList.tsx
type User = {
  id: string;
  name: string;
  email: string;
};

const UserList = async () => {
  await new Promise((resolve) => setTimeout(resolve, 5000));
  const response = await fetch('https://jsonplaceholder.typicode.com/users');
  const users: User[] = await response.json();
  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
};

export default UserList;
```

### Streamingの手順
1. page.tsxとUserList.tsxをsrc/appに作成。
1. UserListは非同期処理を使って外部API(jsonplaceholder)からデータを取得するコンポーネント。意図的にsetTimeout関数を使い5秒間待機後にデータを取得。
1. page.tsxはReactのAPIsから`Suspense`をインポートし、UserListコンポーネントをラップする。
1. `http://localhost:3000`にリクエストを送った時、`Suspence`でラップされていない`ユーザー一覧`は表示されるが、UserListは非同期処理のデータが取得されていない為コンポーネントが作成されておらず、`fallback`に記述した`Loading...`が表示される。
![スクリーンショット (1231).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1220815/8a196831-3b88-942f-54d4-c75c3452231d.png)
5. 5秒後に非同期処理でAPIから取得したデータがUserListに渡ってきて、コンポーネントが生成されクライアント側に送信されて表示される。
![スクリーンショット (1232).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1220815/eb337c88-2dd8-250f-f4e0-a076b6c5ccce.png)

## おわりに
最後まで記事をご覧いただきありがとうございました。

間違いなどありましたらご指摘いただけると幸いです:bow:

## 参考
https://nextjs.org/docs/app/building-your-application/routing/loading-ui-and-streaming#example
JavaScriptの三項演算子とtruthy・falsyな値について

# 三項演算子とは 
三つの非演算子（オペランド）をとり、条件式から真の場合の値もしくは偽の場合の値を返す演算子になります。　
同じく真偽値によって処理を分ける関数としてif文がありますが、機能としてはそれとよく似たものになりますが、条件判定から値返却まで一行で記述できるというメリットがあります。　


# 構文 
三項演算子は以下のように表現します。 
```.js
条件式 ? 真の場合に返す値 : 偽の場合に返す値
```
以下ではその使用方法を詳しく確認します。

# 使用例 
## 一般的な使用方法 
単純な条件式の真偽値を判定し、それに応じて値を返す例です。 
この例では`mathScore`として`90`の値を格納し、その後三項演算子の処理を行っています。 
三項演算子の条件式として`mathScore > 80`を評価し、`80`より大きければ`Larger Than 80`、小さければ`Smaller Than 80`と表示します。 
最初の定数として`90`を代入しているので、`console.log`には`Larger Than 80`と表示されます。

```.js
const mathScore = 90;

const isMathScoreLT80 = mathScore > 80 ? "Larger Than 80" : "Smaller Than 80";

console.log(isMathScoreLT80);
//Larger Than 80 と表示されます。
```

## else ifを繋げる
三項演算子では、`if`文で言うところの`else if`を複数繋げるといった処理も可能です。　
以下のようにして使用します。

```.js
let examScore = function (score) {
  return score < 60 ? "drop a class"
       : score < 80 ? "good score"
       : "excellent score";
};

console.log(examScore(70));
//good scoreと表現されます。
```

# Truthy・Falsyな値について 
`Boolean()`メソッドなどを用いて真偽値に変換した際、TrueやFalseに変換される値のことを指します。つまり、Boolean関数にて変換した時、Trueに変換されるものをTruthyな値、Falseに変換されるものをFalsyな値と言います。　

基本的にはFalsyな値の数は少ないので、こちらを覚えたのち、それ以外のものをTrythyな値だと認識しておくといいと思います。　

Falsyな値の一例 
- False
- 0(数字)
- ""(空文字)
- null
- undefined
- NaN
　
# 論理和（OR条件）と論理積（AND条件）について
論理和とは、条件式を左側から順番に調べていき、一つでも条件を満たすものがあればTrueを返し、全ての条件を満たさない場合のみFalseを返します。 
論理積とは、すべての条件を満たした場合のみTrueを返し、それ以外のものはFalseを返します。
metabaseをセルフビルドする

# 初めに
https://qiita.com/m4549071758/items/253a9c806fc862dd8656
この記事のセルフビルドから抜き出したものです。


# インストール

### ソースのクローン
gitからソースをクローンします。

```
$ git clone https://github.com/metabase/metabase.git
$ cd metabase/
```

### 最大列数変更
ソースをクローン後、列数制限している部分を変更します。
``` src/metabase/query_processor/middleware/constraints.clj
(ns metabase.query-processor.middleware.constraints
  "Middleware that adds default constraints to limit the maximum number of rows returned to queries that specify the
  `:add-default-userland-constraints?` `:middleware` option."
  (:require
   [metabase.models.setting :as setting]
   [metabase.util.i18n :refer [deferred-tru]]))

(def ^:private ^:const default-max-results-bare-rows <任意の桁数に変更>)

;; NOTE: this was changed from a hardcoded var with value of 2000 (now moved to [[default-max-results-bare-rows]])
;; to a setting in 0.43 the setting, which allows for DB local value, can still be nil, so any places below that used
;; to reference the former constant value have to expect it could return nil instead
(setting/defsetting max-results-bare-rows
  (deferred-tru "Maximum number of rows to return specifically on :rows type queries via the API.")
  :visibility     :authenticated
  :type           :integer
  :database-local :allowed)

(def ^:private max-results
  "General maximum number of rows to return from an API query."
  <任意の桁数に変更>)

(defn default-query-constraints
```

### ビルド環境
DockerHubから、すでにClojure環境構築済みのコンテナイメージを使用します。


> https://hub.docker.com/_/clojure

bashをコンテナ側に渡すことで、ターミナルから直接操作できるようになります。

```
$ sudo docker run -it --rm -v $(pwd):/tmp/metabase --workdir /tmp/metabase clojure:openjdk-11-tools-deps-slim-bullseye /bin/bash
```

必要なモジュールをインストールします。

```
# apt update && apt install -y curl gnupg

# curl -sL https://deb.nodesource.com/setup_lts.x | bash -
# apt update && apt install -y nodejs

# curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg |  apt-key add -
# echo "deb https://dl.yarnpkg.com/debian/ stable main" |  tee /etc/apt/sources.list.d/yarn.list
# apt update && apt install -y yarn
```

モジュールをアップデートします。
```
# npx update-browserslist-db@latest
# npx browserslist@latest --update-db
# yarn upgrade
```

ビルドします。
```
# yarn
# ./bin/build.sh

Copyright © 2023 Metabase, Inc. 

Metabase Enterprise Edition extensions are PRESENT.

Usage of Metabase Enterprise Edition features are subject to the Metabase Commercial License. See https://www.metabase.com/license/commercial/ for details.
        Finished compilation in 74.0 seconds.
      Copy resources
        Copy src
        Copy shared/src
        Copy resources
      Create uberjar
Building uber jar: /tmp/metabase/target/uberjar/metabase.jar
        Created uberjar in 32.0 seconds.
      Update META-INF/MANIFEST.MF
      Built target/uberjar/metabase.jar in 110.8 seconds.
    Uberjar built successfully.
  All build steps finished.
```

### 実行
`/tmp/metabase/target/uberjar`にjarファイルが出力されるので、dockerコンテナからexitして
```
$ java -jar metabase.jar 
```
で実行できます。

:::note
実行するホストOSにOpenJDK 11が必要です。
:::
【SwiftUI】iOS17からScrollViewのページングが簡単になった！

# はじめに
iOS17からスクロールのページングが簡単にできるようになったみたいなので試してみます！

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">SwiftUI&#39;s ScrollView became very powerful! It allows you to tune scroll targets and enable paging very easily.<a href="https://t.co/7ydUWE5sSa">https://t.co/7ydUWE5sSa</a> <a href="https://t.co/jRG4pO9w9R">pic.twitter.com/jRG4pO9w9R</a></p>&mdash; Majid Jabrayilov (@mecid) <a href="https://twitter.com/mecid/status/1666738317948334081?ref_src=twsrc%5Etfw">June 8, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# サンプルアプリ
|縦ページング|横ページング|
|:-:|:-:|
|![Simulator Screen Recording - iPhone 14 Pro - 2023-06-09 at 21.06.56.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/326637b7-b5c9-38bd-f15d-8ddcb31292da.gif)|![Simulator Screen Recording - iPhone 14 Pro - 2023-06-09 at 21.10.33.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/d1bb0133-8691-055d-e2b2-a30d89c14674.gif)|

# 実装
### 縦ページング
```swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        ScrollView(.vertical) {
            VStack {
                ForEach(0..<50, id: \.self) { index in
                    Text("ページ: \(index)")
                        .frame(maxWidth: .infinity)
                        .frame(height: UIScreen.main.bounds.height - 125)
                        .background(Color.cyan)
                        .cornerRadius(15)
                        .padding(20)
                }
            }
            .scrollTargetLayout()
        }
        .scrollTargetBehavior(.paging)
    }
}
```

### 横ページング
```diff_swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        ScrollView(.horizontal) {
            HStack {
                ForEach(0..<50, id: \.self) { index in
                    Text("ページ: \(index)")
                        .frame(width: UIScreen.main.bounds.width - 45)
                        .frame(maxHeight: .infinity)
                        .background(Color.cyan)
                        .cornerRadius(15)
                        .padding(20)
                }
            }
            .scrollTargetLayout()
        }
        .scrollTargetBehavior(.paging)
    }
}
```

# ドキュメント
https://developer.apple.com/documentation/SwiftUI/View/scrollTargetBehavior(_:)

# おわり
めっちゃ簡単にできるようになってて感動です！

![スクリーンショット 2023-06-06 17.23.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/db95fd18-31ae-6410-6ae7-029a5673996c.png)
「Appleが一般に開示した情報」に該当してると思うので大丈夫だとは思いますが、
もしアウトだったらコメントで教えて欲しいです。
【UiPath】ブラウザのほかのタブをすべて閉じるのが意外と苦労した話

# はじめに

Chromeの操作をUiPathで実装したのですが、他のタブをすべて閉じるのに意外と苦労したので記録として残します。

# 結論

アクティビティの「タブを閉じる」ではなく、Chromeの機能である「ほかのタブをすべて閉じる」を使って
今開いているタブ以外をすべて閉じます。

# 前提

## ChromeにUiPathの拡張機能を入れておく

アクティビティの「ブラウザにアタッチ」を使用するために、Chromeの拡張機能追加が必須になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1846796/2fe20016-2a59-3ab7-6c27-4bc8627cb914.png)


# 実際にやってみた

## 今回の実装

こんな感じで作ってみました。
汎用性を持たせるなら、相対要素の取得部分は外だししてもいいかもしれません。

フロー内での「メニューバー」はこいつのことです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1846796/bfd6b84a-4163-8940-3512-24e36173a379.png)

### 全体

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1846796/7e9ec111-276f-fcda-c6b5-9beb314d5314.png)

簡単なな流れとして、

1. ブラウザにアタッチする
2. 今開いているタブを相対要素として取得
3. タブ上で右クリックでメニューを出現させる
4. メニューない「ほかのタブをすべて閉じる」でタブを閉じる

ということを本フローで行っています。

### ブラウザにアタッチの中身

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1846796/2d46d87c-35df-4611-919b-8e2db94240a7.png)

# 備考（要検証）

今回試したのはChromeですが、Edgeにも「ほかのタブを閉じる」機能があるので、同じ感じでいけると思います。
検証したらまた追記します。

# 動かした

![プレゼンテーション1_AdobeExpress.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1846796/8534b050-1d60-064c-0530-cf04f8809de7.gif)


無事にタブを閉じることができました。

# おわりに

なんてことないだろ…と思っていた操作が意外と頭使ったので、自分としても非常に勉強になりました。
（当初タブの個数取得→都度タブ閉じる？想定しているウィンドウはどう判断する？事前に変数でとっとく？とかぐるぐるかんがえてました）
今後も励んでいきたいと思います。

ここまでお読みいただきありがとうございました。
Django学習備忘録　-urlpatternsとpath関数-

# はじめに

Djangoの私的学習メモです。
ChatGPT4にて調べた内容と追加で調べた内容を見返せるように記事としてまとめました。
情報の裏取りはしていないので間違いがありましたらご指摘いただけると幸いです。


# urlpatternsの役割
`urlpatterns`はDjangoフレームワークにおける重要なコンポーネントで、URLとビューの間のマッピングを定義します。これによりDjangoは受け取ったHTTPリクエスト（具体的にはURL）を適切なビュー関数またはビュークラスにルーティングすることができます。

具体的には、`urlpatterns`は`urls.py`という設定ファイルに定義されるPythonのリストで、その各要素は`path()`関数または`re_path()`関数によって生成されたURLパターンです。これらの関数は特定のURLパターンをビューと関連付ける役割を果たします。


# urlpatternsとpath関数の記載方法について

urlpatternsはPythonのリストで、その各要素はpath()関数またはre_path()関数によって生成されたURLパターンです。

path()関数は3つの引数を受け付けます：

+ ルート（route）: URLのパターンを文字列で指定します。このパターンはビューが呼び出されるべきURLを定義します。

+ ビュー（view）: 指定されたURLパターンがマッチしたときに呼び出されるビュー関数またはクラスベースビューを指定します。

+ 名前（name、オプション）: URLパターンに名前を付けることができます。これにより、テンプレートやビュー内からこのURLパターンを参照することが可能になります。

たとえば、次のようにurlpatternsを定義することができます：

```python:urls.py
from django.urls import path

from . import views

urlpatterns = [
    #path('root', view, name='name')
    path('', views.home, name='home'),
    path('contact/', views.contact, name='contact'),
    path('about/', views.about, name='about'),
]
```

path（）関数のルートにはドメイン以降を記載する。
この例では、上から順に
'http://yourwebsite.com/'
'http://yourwebsite.com/contact/' 
'http://yourwebsite.com/about/'
に対するリクエストにそのページのviewをマッピングしている。

path()関数に加えて、re_path()関数もURLパターンを定義するために使用することができます。re_path()関数は正規表現を使ってより複雑なURLパターンを定義することができます。

また、include()関数を使って他のurls.pyモジュールからURLパターンをインクルードすることができます。これは特に大規模なプロジェクトや、複数のDjangoアプリケーションを使用している場合に有用です。

```python:myApp/urls.py
from django.urls import include, path

urlpatterns = [
    path('posts/', include('posts.urls')),
]
```

```python:posts/urls.py
from django.urls import path

from . import views

urlpatterns = [
    path('',views.index, name='index')
]
```

上記の場合、`posts/`のURLは`posts.urls`モジュール内のURLパターンにマッピングされる。具体的には、`posts/`がリクエストされたとき、`posts.urls`モジュール内の``（空文字列）にマッピングされる。

そして`posts.urls`モジュール内では、``（空文字列）が`views.index`ビューにマッピングされているので、`posts/`のURLがリクエストされたとき、`views.index`ビューが呼び出される。

したがって、この設定により`'posts/'`URLは`views.index`ビューにマッピングされ、views.pyにて定義されたindex関数が実行される。

```python:views.py
from django.shortcuts import render

def index(request):
    return render(request, 'posts/index.html')
```
views.pyのindex関数はpostsディレクトリ内のindex.pyをレンダリング（HTMLに変換）し返す。
このテンプレート（今例はposts/index.html）はposts/templates/posts/ディレクトリ内に存在する必要がある。

これは、Djangoのテンプレート検索アルゴリズムがアプリケーションのtemplates/サブディレクトリ内を探すからです。
※postsは各アプリケーション名に置き換えてください

したがって、'http://yourwebsite.com/' のリクエストが来ると 'posts/index.html' を返すという結果が得られる。

以上がurlpatternsの基本的な使用方法です。
Flutter でアプリを作ってみよう　＃1

### アプリ開発全体の流れ
案件にはプログラミングのお手伝い程度でしか入ったことがなく右も左も　
わからないため、まず、アプリ開発における一連の流れから確認していく。　

<dl>
  <dt>① 要件定義</dt>
  <dd>アプリの全体的な概要や備え付ける機能や性能を定め、どのようにシステムを組むか決める。</dd>
  <dt>② 設計</dt>
  <dd>構成やレイアウト、アプリ内の操作方法などを決める<strong>外部設計</strong>と、外部設計の実現に必要なシステム構築の手順を決める<strong>内部設計</strong>がある。</dd>
  <dt>③ 開発</dt>
  <dd>開発には<strong>ウォーターフォール開発</strong>と<strong>アジャイル開発</strong>の二つの方法がある。</dd>
  <dt>④ テスト</dt>
  <dt>⑤ ストア申請、公開</dt>
</dl>

大まかに上記の流れとなることがわかった。　
今更だが今回は、HIPHOPに関するイベント情報をチェックできるアプリを作っていこうと思う。　
というのも題材はなんでも良かったのだが、３ヶ月という期間内で終わらせるということに対して、スケジュールを立てようにもどの工程にどのくらい時間がかかりそうという見立てがかなり曖昧だった。　
そこで、比較的開発しやすそうな題材で且つ、アジャイル開発にて一週間のスパンで搭載したい機能を追加できる限り追加していこうという目論見だ。　

### 要件定義、 設計
本来であれば要件定義でどれだけ詳細を詰められるかが鍵ということはたくさんのサイトを見てとれた。
が、今回とりあえず形にしたい最低限の機能を積んだアプリというのが２、３画面にしかならなさそうなので、ノートに手書きでざっくりとしたレイアウトや機能などを書き、それを元にコードを書き始めてしまうことにした（多分あんまり良くないことなのだろう）。
![image0.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3461823/6b0642a0-2a1f-ada9-57f1-2710dace6646.jpeg)
このようなイメージ。
細かいレイアウトやデザインは一旦置いといて、　
選択したエリアの開催予定のイベントが日付順に上からリストで表示され、　
タップでそのイベントの詳細ページ（webview）に遷移する機能の実装を優先しようと思う。　


dartだけでまだあっぷあっぷなのにMarkdown記法ってなんやねんというツッコミを最後に本日はここまで。
AWS Certified Solutions Architect - Professional に合格したので振り返り

先日AWS Certified Solutions Architect - Professional(以下SAP) に合格できたので、合格体験記的なものを書いておく。何番煎じだよという感じではあるが、サンプルの一つくらいにはなると思うのでネットの海に放流。

### 基本情報
- エンジニア歴: 5年目
- 業務経験: アプリ開発がメイン。4ヶ月程前にAWSを業務で触り始めた。それ以外にインフラの業務経験はなし。
- 保有資格: 応用情報, SAA, DVA, SOA
- 学習期間: 大体4ヶ月
- 点数: 798点
- 受験回数: 1回

### 学習方法

#### 教材
主に使った教材は次の3つ。ただしSAP-CO2に対応前の教材なので、これから受ける人は対応済みの教材を使う方がいい。

**AWS認定資格試験テキスト&問題集 AWS認定ソリューションアーキテクト - プロフェッショナル**
https://amzn.asia/d/hB38JXO

**AWS認定ソリューションアーキテクト-プロフェッショナル ~試験特性から導き出した演習問題と詳細解説**
https://amzn.asia/d/6lFHxU8

**【01版】AWS 認定ソリューションアーキテクト プロフェッショナル模擬試験問題集（全5回分375問）**

**公式サンプル問題**
https://d1.awsstatic.com/ja_JP/training-and-certification/docs-sa-pro/AWS-Certified-Solutions-Architect-Professional_Sample-Questions.pdf

**公式の問題集**
https://explore.skillbuilder.aws/learn/course/external/view/elearning/13272/aws-certified-solutions-architect-professional-official-practice-question-set-sap-c02-japanese


#### 進め方
基本的には問題演習を繰り返して、分からないところは解説、書籍、BlackBelt やDevelopersIO などで学習していくようなやり方を取った。これはアソシエイトの試験を受けていた時からあまり変わってないが、SAPでは、解答の根拠に加えて、周辺知識を積極的に学習することを意識した。
アソシエイトの時は雑に言えば問題を解くだけで合格できた印象だが、SAPでは範囲が大分広がるので、一つ一つの問題から得る情報量を増やさないと必要な知識を網羅するのが難しい。
解説を読んでもよくわからないところはChatGPTも多用した。当然100%正確なわけではないが、それは自分で調べても同じ(詳しくない分野ならなおさらそう)なので、内容に矛盾がなければ大体鵜呑みにして先に進めた。

#### 模試の結果について
書籍とUdemy合わせて計7回分の模試を受けたが、初見で正答率が75%を上回ることはなかった。試験1週間前に解いた模試ですら、正答率は45/75程度。試験本番の手応えも模試と同じくらいで、終了直後は、次また頑張ろう、くらいのテンションだったが、蓋を開けてみれば50点程度のマージンをもって合格していたので、模試の正答率はそこまで気にしなくてよさそう。ちなみに公式の問題集は試験の2週間前に受けたが、正答率は65%だった。

#### 受験の目安
書籍とUdemyの8割程度の問題で解答の根拠が説明できれば、私が受験した時と同じくらいの学習進度にはなっていると思う。

### 問題を解く際の注意点

#### メリハリを付けて読む
SAPの問題文は長いものだと10行以上になることも珍しくないが、問題を解くには関係のない文も多分に含まれている。
例えば、大量のストリーミングデータを処理するアーキテクチャを作る問題を解く上で、データが工場の機器から取得されるものか、畑に設置されたセンサーから取得されるのかは正直どうでもいい（実際の業務では大切だが）。
アプリケーションの用途などはなるべく読み飛ばし、インフラ構成については慎重に読むといった、濃淡をつけた読み方が必要。そうしないと時間と集中力がなくなる。

#### 要件は丁寧に整理する
選択肢の中には実現可能なものが複数含まれていることがある。こういう場合は要件によって正答が決まるので、見落としがあると知識はあっても点が取れない悲しい状況に陥ってしまう。そのため下記のような情報には目を光らせる必要がある。
- コスト
- 可用性
- 運用の手間
- 構築期間
- シンプルさ
- ダウンタイム
- 実行時間
- セキュリティ

テストセンターでもペンとホワイトボードのようなものが渡されるので覚えていられない時はメモを取ってもOK。書いたら消せないタイプであることが多いが、テストセンターの人に頼めば追加でもらえるので、空きスペース等は心配せずに書き込んでよい。

### 所感

知らないサービスがほぼなくなるので、AWSに関する会話については大体ついていけるようになるし、サービス概要の調査などは不要になって、業務の一部を省けるようにもなってきた。こういうのは実力アップと言っていいと思う。
デメリットという程ではないが、ハイブリット構成やSSOなどに詳しくなるものの、私の環境では使う機会がほぼないのは悲しいところ。このあたりは資格試験の宿命というか、不特定多数の受験者を対象としたものなので、使わない知識が出てくるのは仕方がない。
こういう無駄が気になる場合資格試験に向いてるメンタリティではないと思うので、別の学習や、アピール方法に力を注いだほうがいい。資格試験は数ある学習方法の一つでしかないので、自分の好み、適正、会社の評価体系などを鑑みながら受験を検討するのがおすすめ。
Dockerイメージを圧縮ファイルとして保存・配布する



### 元記事

https://docker.hatenablog.jp/entry/2023/06/08/163311




ビルドしたDockerイメージを圧縮ファイルとして配りたい場合。

### 解決策:`docker export`コマンドを使用する

まずは`docker ps`でコンテナの一覧を取得する

```sh
docker ps -a
```

```
CONTAINER ID IMAGE COMMAND CREATED ... NAMES
77d9619a7a71 ubuntu:14.04 "/bin/bash" 10 seconds ago ... high_shockley
```

ここで、CONTAINER IDが
77d9619a7a71 
のコンテナのイメージを圧縮ファイルとして保存、共有したい場合。

次のように`docker export`コマンドを使用する。

```sh
docker export 77d9619a7a71 > update.tar
```

exportされた圧縮ファイルは、`docker import`でコンテナイメージを読み込む素材として使える。

```sh
docker import - update < update.tar
```


### 別解：`docker save`コマンドを使用する

`docker save`コマンドでもDockerイメージを圧縮ファイルとして保存することができる。

```sh
docker save [オプション] <イメージ名>[:<タグ>] -o <アーカイブファイル名>
```

例えば、myimage:latestの最新のDockerイメージを保存しておきたい場合。

```sh
docker save myimage:latest -o myimage.tar
```

このようなコマンドを入力することで、`myimage.tar`ファイルが作成されます。

圧縮されたファイルを再度読み込むには`docker load`コマンドを使用します。

```sh
docker load < myimage.tar
```


### 関連記事

https://docker.hatenablog.jp/entry/2023/06/08/155723


https://docker.hatenablog.jp/entry/2023/06/04/120438
vimの削除と切り取りを分離する

# ヤンクしたテキストが削除で上書きされる問題
vimではヤンクしたテキストも削除したテキストも無名レジスタに登録される。
そのため、ヤンク&rarr;削除の順番で操作すると、無名レジスタの内容は、削除したテキストで上書きされてしまう。
プットする際に`0`レジスタを指定すればヤンクしていたテキストを貼り付けられるが、面倒なのでクリップボードのように使える方法をデフォルトにしておきたい。

# 解決策
- `d`は削除専用
- `c`,`s`で消した内容も削除
- `x`は本来の`d`の挙動を再現 = 切り取り


xを削除専用にすれば設定の量は減るが、
削除= "**d**"elete
切り取り = `ctrl + x`
のイメージで、こっちのほうがしっくりきたので。

## `d`は削除専用
まず`d`を使用した場合は、ブラックホールレジスタを使って削除内容をどのレジスタにも登録しないようにする。これで削除による無名レジスタの上書きを防げる。
```vim:vimrc
nnoremap d "_d
nnoremap D "_D
xnoremap d "_d
```

## その他の削除系のキー
`c`, `s`を使用した場合も削除されたテキストが無名レジスタに登録されてしまうので、ブラックホールレジスタを使用する。
```vim:vimrc
nnoremap c "_c
nnoremap C "_C
nnoremap s "_s
nnoremap S "_S
xnoremap c "_c
xnoremap C "_C
```

## `x`は`dl`で代用
カーソル上の文字を削除する`x`は`dl`で、カーソルの直前の文字を削除する`X`は`dh`でそれぞれ代用可能である。
このように本来`x`,`X`で行う操作を他のキーで代用すれば`x`,`X`のキーを別の操作に使用できるので、これを切り取り専用にすればOK。
キーのタイプが一回増えてしまうが、個人的には`x`や`X`よりも`dl`や`dh`のほうが押しやすいと感じるのでとくに問題はない。

## `x`を切り取りに使用する
`x`はvim本来の`d`の挙動をするように設定。つまり`x`を使用して削除した場合は無名レジスタに登録されるようにする。
`d`の操作と合わせるために、`xx`は行の切り取りに割り当てた。
`X`も空くので、`D`と同じ挙動をするようにした。
もちろん`xiw`や`3xx`といったモーションやカウントとの組み合わせも、本来の`diw`や`3dd`と同じ挙動をする。
```vim:vimrc
nnoremap x d
nnoremap xx dd
nnoremap X D
xnoremap x d
```
Notion DBをJavaScritクライアントからAPIで更新してみる


NotionのDBをAPIから触って更新してみます。
JavaScriptクライアントを使うサンプルがあまりなかったのでメモ的に残しておきます。

## 公式ドキュメントだとクライアントのリクエストサンプルしかない模様...?

調査不足かもですが、公式にはJavaScriptクライアントでの更新の実装例がなさそうでした。

> 参考: https://developers.notion.com/reference/update-a-database
> 参考: https://developers.notion.com/reference/post-database-query

[こちらのTwilioのブログ](https://www.twilio.com/blog/manipulate-notion-database-using-node-js)にて、以下のような指定を発見。

```js
const response = await notion.pages.update({
                    page_id: pageId,
                    properties: {
                        'Status': {
                            checkbox: status,
                        },
                        'Date': { 
                            type: 'date',
                            date: {
                                "start": inputDate
                            }
                        },
                    },
                    });
```

## 特定の値を更新する処理

ブログのコードを参考に以下でいけました。

- name(テキスト): n0bisuke
- score(数値): 80

みたいなDBがあったとして、n0bisukeさんを検索してスコアの更新をしてみます。

```js
'use strict';

const { Client } = require("@notionhq/client")
const DB_ID = 'xxxxxxxxxxxxxxxxxxxxx'; //自身の利用するデータベースID
const API_KEY = 'zzzzzzzzzzzzzzzzzzzz'; //NotionのAPIキー

// Initializing a client
const main = async () => {
    const notion = new Client({
        auth: API_KEY,
    })
    
    //1. ユーザーn0bisukeをnameプロパティから検索
    const response = await notion.databases.query({
        database_id: DB_ID,
        filter: {
            "and": [
                {
                  "property": "name",
                  "rich_text": {
                    "equals": 'n0bisuke'
                  }
                }
            ]
        }
    })
    
    const userInfo = response.results[0].properties; //n0bisukeさんの情報が入っている
    const userRecordId = response.results[0].id; //n0bisukeさんの情報があるレコードのID
    let userScore = userInfo['score'].number || 0; //スコアの値がなかったら0で
    userScore++; //1点追加
    
    
    //2. レコードのIDを指定して更新
    const response2 = await notion.pages.update({
        page_id: userRecordId,
        properties: {
            'age': { 
                type: 'number',
                number: userScore //追加された点数でDB更新
            },
        },
    });
    
    console.log(response2);    
}

main();

```

## 所感

page_idを指定することでいけましたが、ここがrecord_idではなくpage_idという部分がNotionの仕様を感じますね。
あとテキスト型の場合は`text`では動かず`rich_text`という指定にしないといけないのは少し罠っぽいです。


APIのそもそもの使い方という面だとスプレッドシートを使う場合はGoogleの認証がすごく面倒な印象ですが、APIキーとDBのIDで使えるのでGoogleとNotionを比較するとAPI利用は楽な印象です。
【Android】バナー広告を実装してみた

# はじめに
こんにちは！
今回は、Androidにadmobのバナー広告を実装したので、そのことについてまとめていこうと思います。

# バナー広告とは
バナー広告とは最も簡単に実装できて、アプリのレイアウト内の一部分を使用する長方形の広告が表示される広告のことです。
画面上部や画面下部など好きな箇所に実装することができます。
以下がバナー広告の概要になります。

https://support.google.com/admob/answer/9993556?hl=ja

# バナー広告の実装
実際にバナー広告を実装していきます。
バナー広告では一番簡単なやり方としてはxmlとActivityに処理を入れます。
まず以下がxmlです。<code>com.google.android.gms.ads.AdView</code>で好きな箇所にレイアウトを入れます。
この時注意しなければいけないのは<code>app:adSize</code>と<code>app:adUnitId</code>は必須で入れないとエラーが起きます。
次にActivity側ですが、以下の１行を追加するだけです。
とても簡単です。他に色々とオーバライドできるメソッドがあるので都度活用すると実装の幅が広がりそうです。
``` xml: activity_main.xml
<com.google.android.gms.ads.AdView
    android:id="@+id/adView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:layout_alignParentBottom="true"
    app:adSize="BANNER"
    app:adUnitId="ca-app-pub-3940256099942544/6300978111"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintBottom_toBottomOf="parent">
</com.google.android.gms.ads.AdView>
```
```kotlin: MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // バナー広告をロードする
        Binding.adView.loadAd(AdRequest.Builder().build())
    }
```

# バナーの種類
バナー広告には色々なサイズの広告が用意されており、アプリや対応端末により変えてみると良いと思います。
今回以下の3つのサイズを実装してみました。<code>app:adSize</code>の設定を変えるだけです。
## BANNER
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3117699/8f95be66-4b65-14e0-6ed3-b2c32ae02bdf.jpeg" width="300px">

## LARGE_BANNER
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3117699/7768db30-ca62-fdea-34a9-02410748e87b.jpeg" width="300px">

## MEDIUM_RECTANGLE
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3117699/8e85b634-f824-d81b-0aa3-6f4bd2bf2728.jpeg" width="300px">

# 最後に
バナー広告自体は実装は簡単でした。
今回のユニットIDはテスト用で行いましたが、実際は登録したユニットIDで行ってください。
最後までご覧いただきありがとうございました。

# 参考
実際の実装方法など記載されています。

https://developers.google.com/admob/android/banner?hl=ja

テスト用のユニットIDが記載されています。

https://developers.google.com/admob/android/test-ads?hl=ja¥