OmniAICreator/Qiita-1.07M huggingface dataset:
【Swift】実は２つ以上使える！トレイリングクロージャ

# 目次
[1.実は２つ以上使える！トレイリングクロージャ](#1-実は２つ以上使える！トレイリングクロージャ)
[2.実例](#2-実例)
[3.おわりに](#3-おわりに)

# 1. 実は２つ以上使える！トレイリングクロージャ
トレイリングクロージャって便利ですよね。
関数の引数にクロージャが最後にあった時に呼び出す側で見やすくしてくれる記法です。
でも実は、、、引数に２つ以上クロージャがある時にも使用できるんです！！

# 2.　実例
関数定義側
~~~swift:function.swift
func example1(
    value: Int,
    closure1: (Int) -> String,
    closure2: (String) -> Bool,
    closure3: (Bool) -> Int
) -> Int {
    let value1 = closure1(value)
    let value2 = closure2(value1)
    let value3 = closure3(value2)
    return value3
}
~~~
引数にクロージャが最後３つ続いています。
呼び出す側
~~~swift:call.swift
let value = example1(value: 420) { number in
    String(describing: number)
} closure2: { string in
    string.count.isMultiple(of: 69)
} closure3: { boolean in
    boolean ? 1 : 0
}
~~~

closure1の引数名だけ省略されていいます。
なぞだけどそういうものみたいです。

:::note info
トレイリングクロージャの始まりは引数名が省略されます！
:::

# 3. おわりに
トレイリングクロージャは慣れるまで大変ですが、見慣れたら見やすいとなる記法です。
折れずに学習していきましょう！
ありがとうございました〜
【Git】マージコミットを取り消す方法

どうもこんにちは。

今回はわかりづらい「マージコミットを取り消す方法」を調べましたのでメモします。

# 通常のコミットとマージコミットの違い

通常のコミットは、**修正をしたコードを修正ブランチへ反映させる**という意味を持ちます。

マージコミットは、**修正が反映されたブランチをmasterブランチやdevelopブランチへマージした時に生じるコミット**です。

# マージコミットを取り消す手順

今回はdevelopブランチからaa11bb22cc33dd44ee55というコミットIDを持つコミットを取り消す想定で話を進めます。

## 1. マージを取り消したいブランチへ移動する

```git
git checkout develop
```

## 2. revertする

```git
git revert -m 1 aa11bb22cc33dd44ee55
```

これでマージコミットが取り消されました。`-m`がないとマージコミットの取り消しができないので注意してください。

# revertコマンドについて解説

`-m`の後の`1`は、以下の`Merge`項目の`ff66gg77`を指す「親番号」となります。

```
% git show aa11bb22cc33dd44ee55
commit aa11bb22cc33dd44ee55
Merge: ff66gg77 hh88ii99
Author: test_user <test_user@mail.com>
Date:   Fri Jan 19 17:10:33 2024 +0900

    コミットメッセージ
```

![スクリーンショット 2024-01-25 12.37.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711491/23090723-9182-d8cf-9152-387a94d6bf26.png)

以上
Python YouTube クリッププログラム

# YouTubeの、クリッププログラム
目次から、本分または、学習法を検索し、
あれば、時間をクリップ、
無ければ、60ｓで、クリップするという、
プログラムを作りました。^^
ChatGPTに、レービューを依頼したのですが。。
高度すぎて、よくわかりませんでしたので、^^;
かなり冗長ですが、
ひとまず、動いたものを、
アップします。^^
よろしくお願いします。

```python
# Run
from selenium import webdriver
from time import sleep
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.keys import Keys

driver = webdriver.Chrome('C:\chromedriver')
	
driver.get('https://www.youtube.com/watch?v=n5zNGvvrg4Q')

# ブラウザが展開されるまで、20s待つ
sleep(20)

#もっと見る をクリックして、リンクを展開
element_target = driver.find_element_by_id("expand")
element_target.send_keys(Keys.ENTER)

# 比較用の配列の準備
element_t = []

# 最大10秒間、テキストが"element_id"の要素がDOMに現れるまで待つ・テキスト取得
for i in range(9, 19):
    element_t.append(WebDriverWait(driver, 20).until(
        
        EC.presence_of_element_located((By.CSS_SELECTOR, "#description-inline-expander > yt-attributed-string > span > span:nth-of-type(" + str(i) + ")"))
    ))

# 表示秒数字 初期化
e_s = ""

# 検索結果の表示
for i in range(10):
    
    if "本文" in element_t[i].text:
        # 要素が見つかった後の処理
        # 要素のテキストを取得
    
        element_text = element_t[i-1].text

        # 時間文字列の秒を取得
        e_s = element_text[3:]

        # 時間文字列の分を取得
        e_m = element_text[:2]

        # 秒に変換
        e_s = str(int(e_s) + 60 * int(e_m))
        break

      
    if "学習法" in element_t[i].text:
        # 要素が見つかった後の処理
        # 要素のテキストを取得
    
        element_text = element_t[i-1].text

        # 時間文字列の秒を取得
        e_s = element_text[3:]

        # 時間文字列の分を取得
        e_m = element_text[:2]

        # 秒に変換
        e_s = str(int(e_s) + 60 * int(e_m))
        break
    else:
        e_s = "60"
    

# 動画のURLに、クリップ時間の追加

ul = "https://www.youtube.com/watch?v=n5zNGvvrg4Q"

ul = ul + "&t=" + e_s + "s"


# クリップ済みの動画を開く
driver2 = webdriver.Chrome('C:\chromedriver')
	
driver2.get(ul)

driver.close()
```
Rで多重比較（Bonferroni, Wilcoxon, Kruskal-Wallis, Dunn）

# 多重比較
3群以上のデータに対して、どの群間に平均値の差があるかを検定には多重比較を用いる。2群間の検定を繰り返し行ってはいけない。これは、<b>第一種の過誤(αエラー)</b>が増大し、検定の精度が低下するためである。

https://istat.co.jp/sk_commentary/Multiple-comparison/M-comparison

複数回の検定を行った際に適切な有意水準が保たれるようにする方法の一つに**ボンフェローニ(Bonferroni)補正**がある。

# Rで多重比較を行う

Bonferroni補正を用いた多重比較をRで行う方法を記す。

* [Wilcoxon rank sum 検定](#wilcoxon-rank-sam-検定ボンフェローニ補正)
* [Dunn検定](#dunn検定)
* [t 検定](#t-検定ボンフェローニ補正)


## Wilcoxon rank sam 検定（ボンフェローニ補正）
まずはサンプルデータの入力。
```R
data <- c(301, 311, 320, 291, 388, 412, 325, 361, 287, 197, 180, 247, 260, 248, 199, 179, 134, 163, 200, 209, 302, 187, 166, 234, 290, 175, 116, 342, 216, 316, 386, 324, 145, 254, 228)

group <- factor(rep(c("A", "B", "C", "D"), c(9, 10, 8, 8)))
```

`pairwise.wilcox.test`を実行。[公式ドキュメント](https://www.rdocumentation.org/packages/stats/versions/3.6.2/topics/pairwise.wilcox.test)。

`x=`：インプットするデータを指定。
`g=`：群のラベルを指定。
`paired=`：データの対応の有無を指定。
`p.adjust.method=`：p値の補正方法を`"bonferroni"`に指定。
```R
pairwise.wilcox.test(x=data, g=group, paired=F, p.adjust.method="bonferroni")
```
**結果**
```
	Pairwise comparisons using Wilcoxon rank sum exact test 

data:  data and group 

  A       B       C      
B 0.00013 -       -      
C 0.00592 1.00000 -      
D 1.00000 0.20568 0.49790

P value adjustment method: bonferroni 
```

## Dunn検定

パッケージ`"dunn.test"`のインストールと読み込み。[公式ドキュメント](https://www.rdocumentation.org/packages/dunn.test/versions/1.3.5/topics/dunn.test)。
```R
install.packages("dunn.test")
library(dunn.test)
```

`dunn.test`を実行。

`x=`：インプットするデータを指定。
`g=`：群のラベルを指定。
`paired=`：データの対応の有無を指定。
`method=`：：p値の補正方法を`"bonferroni"`に指定。
```R
dunn.test(x=data, g=group, method="bonferroni")
```

**結果**
```
  Kruskal-Wallis rank sum test

data: data and group
Kruskal-Wallis chi-squared = 17.0615, df = 3, p-value = 0


                         Comparison of data by group                        
                                 (Bonferroni)                                  
Col Mean-|
Row Mean |          A          B          C
---------+---------------------------------
       B |   3.655600
         |    0.0008*
         |
       C |   3.210627  -0.252028
         |    0.0040*     1.0000
         |
       D |   1.352870  -2.155103  -1.805415
         |     0.5283     0.0935     0.2130

alpha = 0.05
Reject Ho if p <= alpha/2
```

## t 検定（ボンフェローニ補正）

`pairwise.t.test`を実行。[公式ドキュメント](https://www.rdocumentation.org/packages/stats/versions/3.6.2/topics/pairwise.t.test)。

`x=`：インプットするデータを指定。
`g=`：群のラベルを指定。
`paired=`：データの対応の有無を指定。
`p.adjust.method=`：p値の補正方法を`"bonferroni"`に指定。

```R
pairwise.t.test(x=data, g=group, paired=F, p.adjust.method="bonferroni")
```
**結果**
```
    Pairwise comparisons using t tests with pooled SD 

data:  data and group3

  A       B       C      
B 0.00013 -       -      
C 0.00070 1.00000 -      
D 0.30912 0.05520 0.16404

P value adjustment method: bonferroni 
```
Auroraテストデータ作成

# 概要
Auroraでテストデータを作成した際のメモ

## 作成方法
pythonで下記を実行
```
import mysql.connector
from datetime import datetime

# MySQL接続情報
db_config = {
    'host': 'host名',
    'user': 'ユーザー名',
    'password': 'パスワード',
    'database': 'DB名'
}

# MySQLへの接続
connection = mysql.connector.connect(**db_config)
cursor = connection.cursor()

# データ生成と挿入
start_time = datetime.now()
insert_query = "INSERT INTO `user` (`user_id`, `huga_id`, `created_at`) VALUES (%s, %s, %s)"

for i in range(10001, 100001):
    data = (i, i, datetime.now())
    cursor.execute(insert_query, data)

connection.commit()
end_time = datetime.now()
execution_time = end_time - start_time

print(f"データ挿入完了。実行時間: {execution_time}")

# 接続を閉じる
cursor.close()
connection.close()
```

## ログ
```
# 100件
% python3 mysql_insert.py
データ挿入完了。実行時間: 0:00:02.237398
# 1000件
% python3 mysql_insert.py
データ挿入完了。実行時間: 0:00:26.129877
# 10000件
% python3 mysql_insert.py
データ挿入完了。実行時間: 0:03:47.581217
# 100,000件
% python3 mysql_insert.py
データ挿入完了。実行時間: 0:38:31.234051
```


## メモ
CWのメトリクスだとクラスターはwriter+readerで表示されていた
![スクリーンショット 2024-01-25 10.55.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94267/a142f649-073c-de51-7731-3906695b361b.png)
Google Apps ScriptでJSON APIを取得

Google Apps ScriptでJSONPlaceholderからデータを取得したので、忘れないようにメモとして記事にすることにしました。

# 開発環境
- Google Apps Script

# 内容
- JSONPlaceholderからデータを取得
- GoogleSpreadSheetに書き込む

# コード

```javascript
class DataFetchError extends Error {}
class DataInvalidError extends Error {}

function myFunction() {
  const URL_TEXT = "https://jsonplaceholder.typicode.com/posts/1/comments";
  const response = UrlFetchApp.fetch(URL_TEXT);

  if (response.getResponseCode() !== 200) {
    throw new DataFetchError("データの取得に失敗しました");
  }

  const dataList = JSON.parse(response.getContentText());

  const spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = spreadSheet.getActiveSheet();

  if (!Array.isArray(dataList) || dataList.length === 0) {
    throw new DataInvalidError("データリストが配列ではないか、空です");
  }

  const columnNames = Object.keys(dataList[0]);

  // シートに列名を追加
  sheet.appendRow(columnNames);

  // シートにデータ行を追加
  for (let data of dataList) {
    sheet.appendRow(Object.values(data));
  }
}
```
IISからExcelファイルを開けない

IISで作成したサーバーからExcelファイルを開くときにエラーが表示される。(ファイル作成できるが、下記ソースコードで開くときにエラー)
```vba:vba
'/* エクセルファイルをオープンします       */
Dim xlBook As Excel.Workbook = xlBooks.Open(sFile)
```

エラー内容：
> xxアプリケーションでサーバー エラーが発生しました。
> ファイル '...' にアクセスできません。次のいずれかの理由が考> えられます。
>
> • ファイル名またはパスが存在しません。
> • ファイルが他のプログラムによって使用されています。
> • 保存しようとしているブックと同じ名前のブックが現在開かれています。

 ファイル、フォルダに権限をフル付与、IISの設定をすべて会社の手順書通りに設定したが、エラーが解消されない。

 結局下記サイトの内容を読んで解消された。

Link: [Stackoverflow](https://stackoverflow.com/questions/22459127/why-does-systemprofile-need-desktop-folder-to-open-excel-file)

 C:\Windows\SysWOW64\config\systemprofile\ に Desktop という名前のフォルダを作ること

この対応でなんとか無事、ファイルが開けるようになった。
でも根本原因は分からず。
会社のほかのメンバーはこれを実施しなくてもExcelファイルを普通に開ける。

一応メモする。

ほか、参考したページ：
https://hub.uni-face.co.jp/netoffice_excel/
【ChatGPT有＋DALL-E3】与えた画像から特徴を解析して、描画指示プロンプトを作成するやり方。


　どうも、カーブミラーです。

　今回は、画像がすでにあり、それをアップロードして、そこから解析して特徴を取り出す。その特徴から指示プロンプトを作成する方法をお伝えします。

:::note info
本記事は、ChatGPT（有料版）
＋DALL-E3で行なっております。

あしからず。
:::

　言っておきますが、
　　完コピは無理ですw

　また、
　　画像全体のすべてを
　　　解析しようとすると
　　　　断片的な情報しか
　　　　　収集できないです。

　おそらく
　　将来的には
　　　可能かと思いますけどね(=^･^=)

　さて、
　　説明は
　　　ここまでにして
　　　　やり取りをごらんください。
　　　　　そこにプロンプトも
　　　　　　登場します。
***
***user***（一番目）
（キャラ弁の画像をアップ）
これはお弁当です。
詳細な特徴を捉えて教えてください。
箇条書きでお願いします。

***ChatGPT***
このお弁当は以下の特徴を持っています：

- 主要な要素はキャラクターの顔を模しており、お米で作られた大きな丸い顔が中心にあります。
- 顔の周りにはピンク色の飾りがあり、これが髪の毛を表しているようです。
- 目は大きく、茶色の海苔で瞳が作られ、白い部分はカットされたチーズか薄い卵の白身で作られています。
- 頬はピンク色の薄切りの食材でできており、おそらくかまぼこや魚肉ソーセージです。
- 口元には赤い蝶ネクタイがあり、これも海苔や他の食材で作られています。
- 弁当箱の右上にはイチゴが数個添えられていて、新鮮さを加えています。
- 左側には緑のレタスが敷かれており、色と食感のコントラストを提供しています。

デザインは非常に工夫されており、食べるのがもったいないほどの可愛らしさがあります。

***user***（二番目）
上記の箇条書きをDALL-E3に渡すためのプロンプトにまとめ直してください。描画はなし。

***ChatGPT***
以下のプロンプトはDALL-Eに渡すために再構成されたものです：

キャラクター風の可愛らしいお弁当が特徴的な弁当箱に入っている。中心にはお米で作られた大きな丸い顔があり、ピンク色の髪の毛を模した飾りが顔の周りに配されている。目は茶色の海苔で大きく描かれ、白い部分はチーズか薄い卵の白身で作られている。頬はピンク色の薄切りの食材であり、口元には赤い蝶ネクタイがある。右上には新鮮なイチゴが数個、左側には緑のレタスが敷かれている。全体として、食材を使って繊細に作り上げられた、食べるのが惜しいほどのアートピースのような弁当。

***user***（三番目）
上記プロンプトを英訳して、それをDALL-E3に渡してください。

***ChatGPT***
（キャラ弁画像が描画される）
***

　一番目のプロンプトの
　　「これはお弁当です」は
　　　解析したい対象を指示します。
　　　　“お弁当”を“女性”とかに
　　　　　変更してやってみて
　　　　　　ください。

　二番目のプロンプトで
　　“描画はなし”と書いていますが、
　　　これは作成された
　　　　プロンプトを
　　　　　確認するためのものです。

　三番目は
　　作成されたプロンプトを
　　　確認したので、
　　　　英訳して描画を
　　　　　指示しました。

　なぜ、
　　英訳するのか？
　　　英語の方が、DALL-E3が
　　　　出力する画像の質が
　　　　　いいからです。

　もちろん、
　　日本語であっても
　　　ChatGPTが翻訳してから
　　　　DALL-E3に渡しているはず
　　　　　なので、英訳の必要性は
　　　　　　ないような気もします。

　それから、今思い出しましたけど
　　日本語のままだと、
　　　ChatGPTさんが盛る可能性が
　　　　ありますので、
　　　　　その対策ですね(=^･^=)

　それはさておき、
　　修正や追加が
　　　必要な場面もあります。

　その場合は
　　プロンプトをコピって、
　　　編集、そのプロンプトを
　　　　入力して、描画指示すれば
　　　　　いいわけです。

　ちなみに、
　　描画されたお弁当は
　　　食べられそうでしたけど、
　　　　アメリカンヒーローや
　　　　　ピカチュウなんかは
　　　　　　色がヤバそうでした(笑)

　これが、
　　みなさんの
　　　作品制作の糧になれば
　　　　幸いです。

　今回は、ここまで。
img{width:100%,height:auto}の認識を改めた話

## はじめに
現役エンジニアではありません。
2020年ごろにほんの少しWeb系フリーランスの方のお手伝いをしていた程度です。
現在はこれからWebデザイナーを目指す方に、HTML/CSSのさわりを教える仕事をしています。

ですので、現場でhotな技術を持ち合わせておらず、化石状態。
これからの方に誤った情報を伝えないためにも、考え方が間違っている、もっとよい方法がある等、ぜひご指導お願いいたします。

## imgタグへの漠然とした恐怖
imgタグそのものに任意の幅を与えるとなんかおかしい。（ことになる気がする）
もちろん大丈夫なこともあるけれど、レスポンシブ対応やposition:absoluteにしたときになんか変。

そんなわたしを救ってくれたのが

```html:hoge.html
<div class="img-wrapper">
    <img src="hoge.png" alt="hoge">
</div>
```

```css:hoge.css
.img-wrapper{
    width:任意の幅;
    /*height:任意の高さ;*/
}

.img-wrapper img{
    width:100%;
    height:auto;
}

/*img-wrapperに高さも指定した場合*/
.img-wrapper img{
    width:100%;
    height:100%;
    object-fit:cover;
}
```

imgを入れる箱をつくり、箱には任意の箱いっぱいに画像を表示する。縦横比を固定するためにheightにはautoを指定。
img-wrapperにheightが指定されている場合は、imgのheightを100%にしてobject-fit:coverを設定。

おまじないだよ。
箱の幅をいじって、imgのwidthは100%にしておく。先生との約束だよ。

そんな風に教えていました。（昨日まで）

## ほんまにそれでええんか？

これから活躍する生徒さんに、数年前、アルバイトエンジニアのわたしが、頼れる先輩もいない中、悪戦苦闘のすえ仕入れた情報をお伝えしてよいのか？
そんな疑問が頭をよぎりました。

とりあえずなんで↑のようなコードを書くようになってしまったのかを思い出してみる。

・
・
・

色々思い当たる節はあるのですが、一番は

**写真をCSSで丸くトリミングする。**

これが原因なのではないかと思います。
その後、img-wrapperに任意の幅をもたせ、img自体は親であるimg-wrapperいっぱいに表示した方が汎用的でなにかと都合がよかったので、imgに任意のwidthを指定することに抵抗が生まれてしまったというわけです。

## imgにwidth/heightを指定すべき！という主張

img width 100%でググると見出しのような記事がでてきます。
imgにwidthとheightを指定しておかないと、レイアウトシフトが起こってしまうということでした。
lazy-load(遅延ロード)などを利用した時に起こるということです。


## 最終的にどうしたか

最終的に別にwidth:100%は悪くないということ、そしてaspect-ratioをプラスで記述することに行きつきました。
脳死でheight:autoを書いていたことの方がダメだったのかな。

height/width指定とaspect-ratio指定のどちらがよいのか論争も行われいましたが、個人的にしっくりきた書き方だったのでaspect-ratioを採用です。
問題がおきたらまた考えようと思います。

```css:hoge-new.css
.img-wrapper{
    width:任意の幅;
    /*height:任意の高さ;*/
}

.img-wrapper img{
    width:100%;
    aspect-ratio: 任意のアス比;
    object-fit: cover;
}
```

ただ、これできちんとレイアウトシフトが起こらなくなったのかというと、
画像が高速で読み込まれてしまったために確認が出来ておりません。
時間のある時にきちんと確認したいと思います。

### 追記
検証ツールでCPU 4x slowdownにして確認できました。
height:autoではやはりレイアウトシフトが起きていて、aspect-ratioを設定することで予め高さが用意されるので、レイアウトシフトが回避できています。
Vuetify3 Beta環境で、process.env.DEBUGにアクセスできない

（以前社内ブログに投稿していた記事の再掲です）

Nuxt3 Beta + Vuetify3 Beta環境で発生するUncaught TypeError: Cannot read properties of undefined (reading ‘DEBUG’)エラーとその対処法についてまとめました。

# **発生エラーについて**

状況としては、**DevToolのコンソールに以下エラーが表示される**、v-onなどの**ディレクティブが動作せず反応しない**などです。

process.env.DEBUGにアクセスできないことが原因のようでした。

```
Uncaught TypeError: Cannot read properties of undefined (reading 'DEBUG')
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681767/7da343d9-3798-aa94-b8f8-86391851a9be.png)

# **解決策**

[こちらの記事](https://zenn.dev/winteryukky/articles/87a40b60fddb96)を参考に、nuxt.config.tsを以下のように変更することで解決しました。

1. `@vuetify/vite-plugin`が`@vitejs/plugin-vue`の後に読み込まれるよう順序を変更

2. `@ts-ignore`でTypeScriptの型エラーを無視させる

3. process.env.DEBUGにアクセスできない問題を回避するハックを追加

```nuxt.config.ts
import { defineNuxtConfig } from 'nuxt3'

// https://v3.nuxtjs.org/docs/directory-structure/nuxt.config
export default defineNuxtConfig({
  serverMiddleware: [
    { path: "/server-api", handler: "~/server-middleware/index.ts" },
  ],
  css: ['vuetify/lib/styles/main.sass'],
  build: {
    transpile: ['vuetify']
  },
  vite: {
    plugins: [
      {
        // https://github.com/nuxt/framework/issues/2798
        configResolved(config) {
          const vuetifyIdx = config.plugins.findIndex(
            (plugin) => plugin.name === "vuetify:import"
          );
          const vueIdx = config.plugins.findIndex(
            (plugin) => plugin.name === "vite:vue"
          );
          if (~vuetifyIdx && vuetifyIdx < vueIdx) {
            const vuetifyPlugin = config.plugins[vuetifyIdx];
            // @ts-ignore
            config.plugins.splice(vuetifyIdx, 1);
            // @ts-ignore
            config.plugins.splice(vueIdx, 0, vuetifyPlugin);
          }
        },
      },
    ],
    define: {
      "process.env.DEBUG": "false",
    },
  },
})
```

# **参考**

[https://zenn.dev/winteryukky/articles/87a40b60fddb96](https://zenn.dev/winteryukky/articles/87a40b60fddb96)
Vuetify3 beta で Could not find injected Vuetify layout エラーが表示される

（以前社内ブログに投稿していた記事の再掲です）

Vuetify3 betaで**500：Could not find injected Vuetify layout**エラーが表示される原因と対策についてと、<v-app>タグについてまとめました。

# **エラー内容**

[公式](https://next.vuetifyjs.com/en/components/app-bars/)の<v-app-bar>コンポーネントのサンプルコードを実行したところ、以下画像のようにCould not find injected Vuetify layoutエラーが発生しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681767/b01810f1-bdd1-86af-da8e-f8d190317c2d.png)

原因は、**公式ページに記載されているサンプルコードが<v-app>で囲われていないから**です。

以下のように書くと、上記のエラーが発生しますが、

```sample.vue
<template>
  <div>
    <v-app-bar>
      <v-app-bar-title>test</v-app-bar-title>
    </v-app-bar>
  </div>
</template>
```

以下のように書けばエラーは発生せずにAppBarは表示されます。

```sample.vue
<template>
  <v-app>
    <v-app-bar>
      <v-app-bar-title>test</v-app-bar-title>
    </v-app-bar>
  </v-app>
</template>
```

# **<v-app>について**

そもそも<v-app>タグとは、<div id=”app”>と同様の役目を果たす**Vuetifyを利用する上で必須**とされるタグです。

Vuetifyのコンポーネントタグはすべて<v-app>タグの内側に記載する必要があります。

<v-app>で囲わなくてもエラー無く表示されるコンポーネントもありますが、**予期せぬ動作を招く原因**になるので以下のように囲うようにしましょう。

```sample.vue
<template>
  <v-app>
    // Vuetifyコンポーネントの記述
  </v-app>
</template>
```

# **参考**

[https://vuetifyjs.com/ja/components/application/](https://vuetifyjs.com/ja/components/application/)

[https://dev83.com/vue-vuetify-basic/](https://dev83.com/vue-vuetify-basic/)
Nuxt3 Beta環境にVuetify3 Betaを導入する

（以前社内ブログに投稿していた記事の再掲です）

Nuxt3 Beta環境にVuetify3 Betaを導入する手順をまとめました。

なお、Nuxt3 Betaの環境構築については以前の記事を参考にしてください。

# **はじめに**

**Vuetifyとは**

Vue.jsのUIフレームワークです。マテリアルデザインに則って、おしゃれなUIを作ることができます。

Vuetifyの公式サイトは[こちら](https://vuetifyjs.com/en/)

# **手順**

### **１ Vuetify3 Betaをインストール**

早速Vutify3 Betaをインストールしていきます。

yarn addコマンドを使用してインストールします。

```bash
yarn add 'vuetify@3.0.0-beta.0'
```

### **２ Sassのインストール**

Sassとは、**CSSを拡張して扱いやすくしたスタイルシート**のことです。

これも、yarn addコマンドを使用してインストールします。

```bash
yarn add sass -D
```

### **３ Plugin登録**

NuxtのプラグインにVuetifyを登録します。

１．プロジェクト直下にpluginsディレクトリを作成します。

２．pluginsディレクトリにplugins.jsを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681767/3f0bc52f-923a-ff2f-48c8-18b1977b6b6d.png)

３．plugins.jsに以下内容をコピーします。

```plugins.js
import { defineNuxtPlugin } from '#app'
import { createVuetify } from 'vuetify'
import * as appAll from 'vuetify/components'

export default defineNuxtPlugin((nuxtApp) => {
  const vuetify = createVuetify({
	  components: {
      ...appAll
    }
  })
  nuxtApp.vueApp.use(vuetify)
})
```

### **４ nuxt.configの設定**

既存のnuxt.config.tsを以下に変更します。

```nuxt.config.ts
import { defineNuxtConfig } from 'nuxt3'

export default defineNuxtConfig({
  css: ['vuetify/lib/styles/main.sass'],
  build: {
      transpile: ['vuetify']
  },
})
```

お疲れ様でした！以上でNuxt3 Beta環境上でVuetify3 Betaを動かす準備が整いました。
Vuetify3 Betaで、v-card-actions内のv-btnをボタンっぽくする

（以前社内ブログに投稿していた記事の再掲です）

v-card-actions内にv-btnを配置した際のスタイルについてです。

Vuetify3 Beta環境で素直にやってみると、思っていた動きと違ったので注意点をまとめました。

**2023/09/23 追記**

Beta版じゃなくなったことで、以前書いた記事より仕様が変更になっていましたので,
Vuetify3の仕様に合わせて更新してます。

具体的には、variant=”contained”が書けなくなりAPIに記載されている状態を直接指定する形に変更になっています。

# **やりたいこと**

以下のような感じの画面を作りたいと思います。

v-cardを使用して、下部にボタンを配置するような感じです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681767/f10d8a21-e0ac-3f6d-a83f-0d34a50798b2.png)


# **問題点**

上記のような画面を作りたいとき、v-card-actions内にv-btnを配置すれば良いのでは？と思う方が多いと思います。

実際それで良いのですが、普通にボタンを配置したときに表示が思っていたのと違う…なんて経験ないでしょうか。

例えば以下のようにボタンを配置した時、画像のようなボタンが表示されます。

```sample.vue
<v-card-actions class="justify-end" >
  <v-btn color="black">button1</v-btn>
  <v-btn color="black">button2</v-btn>
</v-card-actions>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681767/58a1f58a-5c5a-f00f-11ad-7cacdd4aa8bf.png)


ここで、あれ？と思われる方が多いと思います。

v-btnコンポーネントは通常デフォルトで以下のようにボタンらしい見た目で表示されますが、

v-card-actions内に配置した場合は上の画像みたいに文字だけのようなボタンが表示されてしまいます。

通常のデフォルトボタン

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681767/4e0b2eaf-a55a-31f8-0b39-afb29e0e7a18.png)


# **解決方法**

結論から言うと、これは仕様です。詳しくは[こちら](https://github.com/vuetifyjs/vuetify/issues/14845)を参照してみてください。

普通にボタンコンポーネントを配置すると、**~~variantがデフォルトでcontained**となっているのですが~~、**v-card-actions内に配置した場合のみ、variantがデフォルトでtextとなる**ようです。

~~そのため、variant=”contained”を指定することで目的の挙動が確認できます。~~

**追記**

**variant**から**contained**が消え、**elevated**に変わったようです。

variant=”elevated”と指定してあげることで解決します。
また、[公式](https://vuetifyjs.com/en/api/v-btn/)の項目を設定することで意図したボタンの見た目に変えることが可能です。

```sample.vue
<v-card-actions class="justify-end" >
  <v-btn color="black" variant="elevated">button1</v-btn>
  <v-btn color="black" variant="elevated">button2</v-btn>
</v-card-actions>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681767/a8e93e14-c8f2-f986-fdfa-23c30788caec.png)


~~また、**ボタン回りの陰影も削除される**ようですので、通常のボタンのようにボタン回りに陰影を付けたい場合はelevation=”3″を追加すると通常のデフォルト状態のボタンと同様の見た目が作れます。~~

**追記**

**elevated**を指定した場合、影は消えていないようですので以下の対応は不要そうです。

影を無くしたボタンにしたい場合は、**flat**を指定しましょう！

```sample.vue
<v-card-actions class="justify-end" >
  <v-btn variant="contained" elevation="3">button1</v-btn>
  <v-btn variant="contained" elevation="3">button2</v-btn>
</v-card-actions>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681767/845aa252-37b8-35c4-f261-618331f4631c.png)

これで目的のボタンのようなv-btnをv-card-actions内に配置することができました。

# **参考**

[https://github.com/vuetifyjs/vuetify/issues/14845](https://github.com/vuetifyjs/vuetify/issues/14845)
Nuxt3 Beta 環境構築

（以前社内ブログに投稿していたものの再掲です。）

Nuxt3 Betaの環境構築手順をまとめました。

# **手順**

### **1. apt-getをアップデートする**

まず、以下コマンドでパッケージリストを最新に更新します。

これを実行しても実際のパッケージインストールやアップデートは行いません。

パッケージリストを最新にすることで、**古いバージョンのソフトウェアがインストールされる**、**ダウンロード先が変更となっていてダウンロードできない**、などを防ぐことが出来ます。

```bash
sudo apt-get update
```

### **2. gitをインストール**

gitをインストールしておきましょう。

まず、以下コマンドでgitをインストールします。

```bash
sudo apt-get install git
```

コンソールの表示に従い、yを入力後Enterを押下します。

以下コマンドでバージョンが表示されればインストール出来ています。

```bash
dpkg -l git
```

続いてgitの初期設定もしておきます。

```bash
git config --global user.name [ユーザ名]
git config --global user.email [ユーザ名]
```

```bash
ex.
git config --global user.name Miho.Yamamoto
git config --global user.email miho.yamamoto@amayz.co.jp
```

### **3. Nuxt3 Betaプロジェクト作成**

ここからが本題です。

以下コマンドでNuxt3 Betaプロジェクトを作成します。

```bash
npx nuxi init [プロジェクト名]
```

```bash
ex. npx nuxi init amayz-project
```

lsコマンドなどでディレクトリが作成されていることを確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681767/95e40b3a-9c09-a230-ea78-0fbb1c4dcd6e.png)

### **4. yarnをインストール**

プロジェクトの作成が出来たら、yarnのインストールを行います。

yarnとはJavaScriptのパッケージマネージャで、色々なソフトウェアのインストール・管理などが出来ます。

```bash
npm install -g yarn
```

### **5. Nuxt3 Betaプロジェクトの関連パッケージをインストール**

先程作成したNuxt3 Betaプロジェクトのディレクトリへ移動します。

```bash
cd amayz-project
```

yarnコマンドでパッケージをインストールします。

```bash
yarn install
```

### **6. Nuxt3 Betaプロジェクトの実行**

以下コマンドでプロジェクトを実行します。

```bash
yarn dev
```

表示されたアドレスにアクセスします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681767/c97839c8-fd16-fcc7-1af0-009745b84b8c.png)


以下画面が表示されればOKです！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681767/c64d3372-d054-fd03-d400-f640f3266350.png)


お疲れ様でした！以上でNuxt3 Betaの環境構築は完了です！

この記事が皆さんのお役に立てていれば幸いです。
IT資格は必要なのか

# はじめに
ITの資格について気になることがあり色々調べてまとめてみました。
この記事の内容が全てではないのでご承知の上お読みください。

## IT資格について

IT関連の国家資格は複数あります。
どんなものがあるかというと、、
+ ITパスポート（IP）
+ 情報セキュリティマネジメント（SG）
+ 基本情報処理技術者（FE）
+ 応用情報技術者（AP）
+ ITストラテジスト（ST）
+ システムアーキテクト（SA）
+ プロジェクトマネージャ（PM）
+ ネットワークスペシャリスト（NW）
+ データベーススペシャリスト（DB）
+ エンベデッドシステムスぺシャリスト（ES）
+ ITサービスマネージャ（SM）
+ システム監査技術者（AU）
+ 情報処理安全確保支援士（SC）

これらの国家資格は初心者からマネージャ、エンジニア向けと様々あります。
IT業界での仕事を目指すのなら必須なのかというと
そうでもありません。

みなさんは「業務独占資格」というものをご存じでしょうか。
これは、弁護士、医師、税理士などの職種に必要な資格であり、
資格を持っていないとその職種に就けません。

一方で、**IT業界には「業務独占資格」は存在しません。**
つまり、資格がなくても仕事ができるし、資格がないからと言って
就職できないなんてこともありません。

ならば、IT業界で働く上で資格を取る必要はあるのだろうか、、、

## 資格の意義、メリットとは
資格を取得することのメリットとして
調べていく中で多く言われていたのが
+ 勉強の過程で、網羅的に知識を学ぶことができる。
+ スキルを証明することで社内評価を上げることができる。
+ 就職や転職の際にキャリアの一つとしてアピールできる。

昨今は社会全体でIT人材不足というのもあり、(今後も加速するそうです、、)
資格の有無に関わらずIT職に就職することは難しくないだろうと言われています。
ですが、自身の就きたい仕事がある場合や、今後のキャリアの面を考慮すると
知識や経験が必要となるので、その点においては有効な手段だそうです。

ただ、「**資格がある＝仕事ができる**とは限らない」という意見もあるそうです。

## 資格をめぐる疑問
資格に対してよく目にする疑問というのが

+ 資格を持っていても、仕事では当てにならない
+ 資格の勉強よりも、まずは業務を優先すべき
+ 資格だけじゃダメ、経験がないと意味がない

上記3つの疑問が多く挙げられていました。

実際に資格は取得したものの、業務にあまり活かせなかった。
取りっぱなしのままで終わっているなどの意見を持つ人も多いようです。


## 資格の活用法
資格の活用方法についての意見は様々ありましたが一部抜粋すると

+ いかに資格と経験を結びつけることができるか
+ 資格と仕事は別々で考えるべき


1つ目の資格と経験の結び付け方については
コラムニストの46氏が「５つの資格活用法」を提示している。(以下引用)
>１．業務をより深く理解する：現場の仕事を理解するという、資格活用の王道手段
２．間接的に業務に生かす：直接業務と関係なくても、社内外の人とコミュニケーションする際に使える
３．仕事のチャンスを増やす：TOEICなど、ほかの人と差別化できるスキルを身に付けて、より良い仕事を得る
４．キャリアアップに活用する：「一目見てスキルレベルがある程度分かる」のが、資格の良いところ
５．資格でもって、独立・開業する：社労士などの資格を取得できれば、独立だってできる

https://el.jibun.atmarkit.co.jp/46/
***

2つ目の資格と仕事は別々に考えるべきについては
同じくコラムニストのケーワイケー氏はこのような意見を持っていました(以下引用)
>仕事と資格は結びつけて考えるものではない。資格で示せるのは「仕事ができるか否か」ではなく、探究心や向上心を持っていること、一定以上の「知識」を持っていること、この2つだけだ。

上記を述べた上で
「興味はあるけれど経験がない分野を知るため」「業務で使う技術の知識確認のため」に、資格を活用していると語っています。

https://el.jibun.atmarkit.co.jp/ityuutu/
***

## さいごに
資格については様々な意見がネット上でも確認できました。
その多種多様な意見には共通点もあるように見えます。
それは「資格は、取得目的よりどう活かすか」、
「活かすかどうかは、結局のところ自分次第」ということです。

資格の取得を考えるのであれば、
「自身が何のために取得しようとしているのか」
「取得したことによって何ができるようになるのか」
まずはこれらを考えて、
資格の必要性を見つけてみるのもいいかもしれないですね。


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


## 参考

https://www.e-xtreme.co.jp/topics/3526/
***
https://atmarkit.itmedia.co.jp/ait/subtop/jibun/
***
Node.jsの環境構築

Node.jsの環境構築手順についてまとめました。

# **はじめに**

**Node.jsとは**

JavaScriptをブラウザ上以外でも動くようにしてくれる実行環境のことです。

Node.jsを使用することで、JavaScriptでOSの機能（ファイルの読み書きなど）を扱えるようになります。

要するに、Node.jsを使用することでバックエンドでもJavaScriptを使用することが出来ます。

# **手順**

### **１ apt-getをアップデートする**

初めにパッケージリストを最新に更新しておきます。

```bash
sudo apt-get update

```

### **２ Node.jsをインストール**

apt-getコマンドを使用してNode.jsをインストールします。

```bash
sudo apt-get install nodejs
```

Do you want to continue? [Y/n]が表示されたら、yを入力して続行します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681767/90ecdb16-ad9f-c0d2-7a9e-4037c81c1eda.png)

地域を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681767/df3ee39a-dc44-7602-2683-8732667f013f.png)

続いてタイムゾーンを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3681767/1231af04-442d-c1a5-614f-dfda76bf7f54.png)

### **３ npmをインストール**

続いて、npmもインストールします。

ここでもDo you want to continue? [Y/n]が表示されるので、yを選択して続行します。

```bash
sudo apt-get install npm
```

### **４ インストール確認**

以下コマンドでそれぞれのバージョンが表示できればインストール完了です。

```bash
node -v
npm -v
```

nodeコマンドが使えない場合は、コマンド名がnodejsになっている可能性があります。

その場合は以下コマンドを実行してみてください。

```bash
sudo update-alternatives --install /usr/bin/node node /usr/bin/nodejs 10
```

お疲れ様でした！以上でNode.jsの環境構築は終了となります。
【Laravel】マルチパートアップロードを使って動画をS3へアップロードする

## はじめに
この記事が私の初投稿になります。
アウトプットの機会を増やしていくため、継続的に記事を書いていこうと思います。

今回は実際の業務で苦戦した「マルチパートアップロードを使用したAWS S3へのファイル保存」についてです。
この辺のトピックはネットの情報が古かったり有益な情報に出会えなかったため、私と同じような状況の方の手助けになれば幸いです。

また間違いなどがございましたら、ご指摘のほどよろしくお願い致します。

## 背景
私が業務でS3を使用した背景ですが、以下のような理由から採用することにしました。
※S3の詳細は割愛しますが、サーバーとは別のところにファイルを保存したい場合に使用するドライブみたいなものですかね！（ざっくりしすぎかな、、、）

* 容量が1GBを超える動画コンテンツを扱うため
* S3に置いたコンテンツはCloudFront（詳細は[公式](https://aws.amazon.com/jp/cloudfront/)を参照してください）経由で高速でアクセスできるため

## 実行環境など
* PHP8.2
* Laravel10
* MySQL
* EC2
* RDS
* S3
* github

などなど。
S3のバケット作成やcloudfrontのディストリビューションは作成済みの前提で記載します。

# マルチパートアップロード
今回のwebアプリはS3へ動画をアップしてそこから配信したわけですが、LaravelでのS3アップロード処理は以下のように非常にシンプルに記述できるようになっています。
`Storage::putFile('s3', $request->file('inputタグのname属性値'));`

しかし、容量がせいぜい1MBにも満たないような軽量ファイルなら上記で全然OKなのですが冒頭でも記載した通り、扱うコンテンツが1GBを超えてくるので上記の方法では処理時間が長くなるだけでなく、リクエストタイムアウトやCPU負荷など様々なネガティブ要素が出てきてしまいます。

そこで登場するのが**マルチパートアップロード**です！
詳細は[こちら](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/mpuoverview.html)に記載の通りです。これを使えば処理時間も早くなりかつ大容量のファイルも扱えます。（公式によると最大5TBのファイルまでOKだそうです笑）。原理としては大きなファイルを手元で分割してS3へアップしていき、最後に結合する処理をSDKとして行ってくれます。（ありがたい！！）

## 処理例
前置きが長くなりましたが、ここで具体例を記載していきます。実際のプロダクトのコードは載せれないので、それに近い記載をしています。
```php:UploadController.php
// S3への保存
$file = $request->file('適宜差し替え');
if (!$file->isValid() || !file_exists($file->getRealPath())) {
    return \back()->with('message', 'アップロードに失敗しました ');
}

$contents = fopen($file->getRealPath(), 'r');

$s3Client = App::make('aws')->createClient('s3', [
    'region' => env('AWS_DEFAULT_REGION'), 
]);


$key = 'ここはS3オブジェクトを格納するパスを指定';
$uploader = new MultipartUploader($s3Client, $contents, [
'bucket' => env('AWS_BUCKET'),
    'key' => $key,
    'ACL' => 'public-read',
    'ContentType' => $file->getMimeType(), 
]);

try {
    $result = $uploader->upload();
    
    // matadataの更新
    $copyResult = $s3Client->copyObject([
        'Bucket'     => env('AWS_BUCKET'),
        'Key'        => $key,
        'CopySource' => env('AWS_BUCKET') . '/' . rawurlencode($key),
        'ACL'        => 'public-read',
        'ContentType' => $file->getMimeType(), 
        'MetadataDirective' => 'REPLACE'
    ]);
} catch (MultipartUploadException $e) {
    echo $e->getMessage() . "\n";
}
```
SDKの導入は[こちら](https://docs.aws.amazon.com/ja_jp/sdk-for-php/v3/developer-guide/s3-multipart-upload.html)を参照しました。

上記コードのポイントとしてはまず以下の記述です
` $s3Client = App::make('aws')->createClient('s3', [
    'region' => env('AWS_DEFAULT_REGION'), 
]); `
Laravel標準のAppクラスによってS3クライアント情報を作成できます。

マルチパートアップロードを実施しているのは以下の記載です。
` $result = $uploader->upload(); `
また、この直後にメタデータの更新を行っている理由ですが、マルチパートアップロードを行うと動画ファイルのmimeTypeがvideo/mp4となっていないためここで書き換えています。
（もっと最適なやり方ご存じの方いましたらご教示いただけると幸いです。）

上記でS3へのアップができるかと思います！

# 最後に
今回はlaravel側の設定やS3の設定はネット上に沢山記事があるため割愛しました。
アプリ側の記述に関してはあまり記事が見当たらなかったのでそこにフォーカスして書きました。
最後まで目を通していただきありがとうございます！！
【Typescript】構造的型付け

## はじめに
構造的型付けの意味を理解していなかったので、自分なりに噛み砕いてみました。

以下は本当に良い記事でした↓

https://qiita.com/suin/items/52cf80021361168f6b0e

## 構造的型付け
Typescriptは「構造的型付け」を型システムでは採用している。

例えば、カラスがいる。カラスを鳥という型かどうかをチェックしたい。
では、鳥は何を持って鳥とするのか？
クチバシがあること？羽があること？
そういったチェックを行う。
### 先に宣言し後で型チェック
```js
  type Bird = {
    kuchibashi: boolean;
    wing: boolean;
  }

  const karasu = {
    kuchibashi: true,
    wing: true,
    age: 12
  }

  const bird: Bird = karasu
```
ここでは型`Bird`は`age`に対応していないがエラーになることはないです。
なぜなら、型`Bird`は`species: string`以外は言及しないから。だから`age`については触れられない。
つまり、ここではカラスは`Bird`型に当てはまるなら鳥だね！ってチェックしていることになります。

しかし、以下だと`age`が型`Bird`にないよ！って怒られます！
### 宣言するときに型をチェック
```js
  type Bird = {
    kuchibashi: boolean;
    wing: boolean;
  }

  const karasu: Bird = {
    kuchibashi: true,
    wing: true,
    age: 12 //Object literal may only specify known properties, and 'age' does not exist in type 'Bird'.
  }
```
先ほどはカラスを先に宣言していたので`karasu`が型Birdかどうかをチェックしていました。
今回は、型`Bird`の変数を作ると宣言しているときなので、Bird型のを作るって言ったじゃん！`age`とか聞いてないんだけど！！ってなります。
## おわりに

間違っているところ気になるところがございましたら教えていただけますと嬉しいです。
静的WEBサイトにCloud Frontを設置する


# 《目的》
前回S3の静的ウェブサイトホスティングを有効にして、独自ドメインを割り当てたWEBmサイトを公開しました。そこにCloud Frontを追加で設置して、下記の構成にしたいと思います。
 ![スクリーンショット 2024-01-24 13.09.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3570384/e9001430-aed6-eb2b-d33c-f6bd218ea2a3.png)


# 《まとめ》
想定していた以上にハマって時間がかかったポイントのみ記載。

#### 1. S3バケットの設定
AWS公式には下記の注意事項がありました。
> オリジンアクセスコントロール (OAC) を作成して設定する前に、Amazon S3 バケットオリジンを持つ CloudFront ディストリビューションが必要です。このオリジンは、ウェブサイトエンドポイントとして設定されたバケットではなく、通常の S3 バケットである必要があります。S3 バケットオリジンを使用した CloudFront ディストリビューションのセットアップの詳細については、「簡単な CloudFront ディストリビューションの開始方法」を参照してください。

この注意事項に則って静的ウェブサイトホスティングを無効に設定したのですがうまくいかず。結局は静的ウェブサイトホスティングは有効のまま設定を進めています。

#### 2. CloudFrontの設定
ディストリビューション作成時の画面に以下の注意が出ていたのと、上記の公式のS3の設定に関しての注意事項でちょっと混乱しました。
> オリジンは、ウェブサイトエンドポイントとして設定されたバケットではなく、通常の S3 バケットである必要があります。(私の理解不足)

![スクリーンショット 2024-01-24 16.44.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3570384/63c8e289-4868-9628-89c7-1fbfb5e908b7.png)

結局は、以下の記事などを参考にしてS3のコンソールで表示される以下のS3ウェブサイトエンドポイントを設定しています！(あっているのかな…)
![スクリーンショット 2024-01-24 18.19.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3570384/10a5f264-556c-92a9-db7b-08ed90825e59.png)
参考記事　
* [CloudFront を使用して Amazon S3 バケットの HTTPS リクエストを処理する方法を教えてください。](https://repost.aws/ja/knowledge-center/cloudfront-https-requests-s3)
* [CloudFront を使用して Amazon S3 でホストされている静的ウェブサイトを提供する方法を教えてください。](https://repost.aws/ja/knowledge-center/cloudfront-serve-static-website)
* [【Amazon S3】REST API エンドポイントとウェブサイトエンドポイントの違い](https://blog.serverworks.co.jp/2022/03/02/100000)


### 追記　
S3ウェブサイトエンドポイントとエンドポイント、どちらを使うかは下記の点が違う。
* Amazon S3 の**静的ウェブサイトエンドポイントを使用する場合**、CloudFront と Amazon S3 の間の接続は**HTTP のみ**で利用できます。[参照URL](https://repost.aws/ja/knowledge-center/cloudfront-https-requests-s3)
* [CloudFront を使用して Amazon S3 でホストされている静的ウェブサイトを提供する方法を教えてください。](https://repost.aws/ja/knowledge-center/cloudfront-serve-static-website)
![スクリーンショット 2024-01-25 10.51.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3570384/c8385dd1-ff91-36fe-ff4a-7ddb6ddec0b3.png)
* AWS推奨のベストプラクティスは下記の設定。
 ![スクリーンショット 2024-01-25 10.56.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3570384/b4a2a430-6105-c846-e02e-40c968cc47cf.png)
* 私が今回設定したのは下記のパターン。ベストプラクティスではないが設定はできているみたい。
![スクリーンショット 2024-01-25 10.58.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3570384/0edb6de7-944f-a822-51de-b472311140f5.png)

# 《結果》
`https://`でアクセス可能になりWEBサイトエンドポイントのURLからの直接なアクセスは 403 Forbidden とエラーになり、CloudFront経由でアクセスできるようになりました！→ https://kwtkd.net


そのほか、CloudFront、Route53でCloudFront経由にルートの変更、ACMでの証明書発行リクエストからのCNAME登録などはスムーズにいき、たくさんわかりやすいブログで公開していただいているので割愛します。
Microsoft Fabric アイテムが作成できない場合にはテナント設定を確認する

## はじめに

Microsoft Fabric を試すとき、https://app.fabric.microsoft.com/home にアクセスすると以下のような画面表示になりアイテムが作成できず、調査を進めたところテナント設定で無効化されている場合の表示だということがわかりました。

一応ドキュメントで示されている部分ではありますが、一部だけ表示されていたり、試用版では別の設定があるなど、ややこしいですね。
- https://learn.microsoft.com/ja-jp/fabric/admin/fabric-switch

Fabric アイテムが作成できない場合の表示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/2b439697-c70c-8025-1cff-69693bb39eab.png)

Data Engineering とか出てますが、一部のプレビュー機能のみが作成可能な状態になってます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/121caab3-815b-aff3-fbcf-55ac8d977cb6.png)


Fabric が利用できる場合の表示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/79d72365-6bfc-7871-b692-c1a1bada8d6d.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/dc1063e8-d975-c5ad-d4e7-e6570d463e79.png)


※2024/01/25 時点での情報です。特にワークアラウンドについては今後できなくなる可能性があるため、原則、正攻法＝テナント設定を見直してください

## テナント設定

結論から言うとテナント設定でFabric アイテム作成が無効化されている場合になります。

### ユーザーは Fabric アイテムを作成できます

以下のように、アイテム作成を無効化しているとユーザーはFabric アイテムを作成できなくなります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/aafa20f1-a739-83cd-817b-5e00a6f677ad.png)

### ユーザーは Microsoft Fabric の有料機能を試すことができます

ただし、試用版にサインアップした場合については、以下の設定で作成可否が制御されます。
なので、 **「試用版にサインアップした人だけが正常に表示されるけど、他の人は冒頭のような作成不可を示す表示になる」** といった状況が発生し、ワークスペース上の権限は同じなのにどうして人で変わるのか、という混乱が生まれました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/d787956d-a77d-8e0a-6f93-9ea465ab3a98.png)

### Data Activator (プレビュー)

また、冒頭で表示されていた Data Activator も以下の設定を変更することで作成ができなくなります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/bc5337de-751e-4669-cd21-effcb315e9fd.png)


## ワークアラウンド
 **ユーザーは Fabric アイテムを作成できます：無効**
 **ユーザーは Microsoft Fabric の有料機能を試すことができます：有効**

の場合には、以下の手順で試用版にサインアップしていないユーザーも一部の作業ができます。

二人のユーザーで実施するような場合を例にします。
Aさん：試用版にサインアップ済み
Bさん：試用版にサインアップしたことがない。

この場合、AさんしかFabric アイテムを作成できませんが、以下の手順でBさんもFabric アイテムの編集と一部の作成が可能です。
1. ユーザーA さんがワークスペースを作成し、試用版容量を割り当てる
1. ワークスペースへのアクセス権をBさんに付与する
1. Aさんにて、ワークスペース内で、ウェアハウスやレイクハウスなど作業の起点になるアイテムを作成する
1. BさんはAさんの作成したアイテムを表示することができるので、アイテムの画面に入ったあと、「データを取得」など、別のアイテム作成を呼び出すボタンを使用すると作成が可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/08a97e15-a057-4af4-d714-59ee4f34e6fa.png)
【Android／Java】BootCompleteでの起動時処理（Android11）

## やりたいこと
色々と記事があるけど、BootCompleteの動作の整理を行いたい

## Step1．通常設定（BootCompleteの受信）
（出尽くしている内容だが）以下を追加する

#### AndroidManifest.xml
~~~xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:sharedUserMaxSdkVersion="31">

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

    <application
        <activity></activity>
        <receiver
            android:name=".StartReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </receiver>
~~~~

#### StartReceiver.java
~~~java
public class StartReceiver  extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
             :(起動時に実行したい処理)
        }
    }
}
~~~~

## Step2．実行結果
Activity起動などを実行した結果は以下の通り
|実行処理|結果|
|---|---|
|Activity起動(StartActivity)|起動しない|
|Service起動(StartService)|起動しない|
|SharedPreferencesの書き込み|起動する|

### 解説
1. Activity起動/Service起動：単純に起動制限がかかっているため（https://developer.android.com/guide/components/activities/background-starts?hl=ja）
1. SharedPreference書き込み：起動制限対象外のため、書き込みができていると思われる


起動直後にActivityなどの起動は行えないが、「端末が起動したか？」の状態を管理することぐらいはできると思われる


## Step3．それでもActivity/Serviceを起動させたい！
条件を整えることができれば、上記の制限を突破することが可能
|条件|概要|
|---|---|
|端末の証明書ファイル|対象となる端末の証明書ファイルを用いてＡＰＫを生成する|
|システム管理権限|AndroidManiestで android:sharedUserId="android.uid.system"を定義する|

#### AndroidManifest.xml
~~~xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:sharedUserMaxSdkVersion="31"
    android:sharedUserId="android.uid.system">
~~~
　
証明書があれば、上記をAndroidManifestに設定することで、システム管理者に昇格することが可能。
ただ、ハードの製造元でもなければ証明書ファイルを入手することは不可能と思われる。
どちらかというと、自社でハードを製造しているような場合でしかできない手法だと思われます。

なお、システム管理者になることでWebViewがセキュリティ上の理由から使用できなくなるなど制約もあり一長一短（…実は抜け道もある）


### 最後に
BootCompleteでの処理は、あまり現実的なことはできないかんというのが感想
年々制限が厳しくなっており、実現したいことが実現しにくくなっている気がします
チームでGithub Copilotを導入してみた結果

# 記事の背景
・個人的には愛用しているものの、ネガティブな感想をあまり見たことがない
・公式の発表でも満足度の向上は60~75%程度
ということで、チームで導入した結果の意見をネガティブなものも含めてまとめました

# 良い点
・ロギングやORマッパー、javadocなどの定形に近い処理はうまく省力化できる
・知らない関数を提案してくれたりして勉強になる
・詳しくない言語やフレームワークの場合は特に助かる
・コーディング以外にも、readmeやメールを書くのにも便利
・小さな関数であればリファクタもなかなかの精度で提案してくれる
・全体的に大きく的はずれな提案は少ない

# 悪い点
・IDE起動直後や複数プロジェクト同時立ち上げなどすると反応してくれないことがある。再起動で大体治る。
・複雑なロジックは間違っている事が多い
・間違っているときにしつこくサジェストが出てくるのが邪魔に感じる
・便利すぎてコーディング力が下がりそう
・コードを理解しないまま採用してしまうリスクがある（ググって理解しないままコピペするより更に起こりやすくなる）

# 事前アンケート
よく分からないので期待していない: 0票
理解しているけど期待していない: 3票
よく分からないので興味がない: 1票
理解しているけど興味がない: 0票
よく分からないけど勧められたので期待している: 3票
理解しているので期待している: 2票

# 事後アンケート
ぜひ継続して利用したい: 7票
どちらでもいい（あれば使うけどなくても良い、など）: 1票
不要: 1票

# 導入した感想
導入のために部内でデモを含めたプレゼンもしていたのに、実際に試すまで便利さが伝わっていなかった。
短時間のプレゼンでさっと流してしまったのを反省。
それでも全体的には好評で、導入してよかった。

# トラブル
うちの環境ではNetskopeによりWindows + Jetbrains製のIDEの場合に認証がうまく行かず、追加で設定が必要でした。
[DLP環境下でのJetBrains IDE + github copilot](https://qiita.com/yukyt/items/223aac674d2aa5ab3521)

# 参考
公式のデータ
[調査：GitHub Copilotが開発者の生産性と満足度に与える影響を数値化](https://github.blog/jp/2022-09-15-research-quantifying-github-copilots-impact-on-developer-productivity-and-happiness/)
ゆめみさんのレポート
[GitHub Copilot 導入で開発者の満足度が向上！プルリクエスト数も増加したデータ公開](https://qiita.com/hironaito/items/989e11fd0efb566089bc)
[Oracle Cloud] フロー・ログ




## はじめに

フロー・ログの設定を試みる

## 設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/15b285ac-6815-a521-4352-5115121cae65.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/16d8797a-2e21-9bc1-7cfb-1e8bb801457a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/b2ed6a47-5a65-8f6b-e20f-15a6f552ff29.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/faa4e42e-c388-3876-0277-8e80cd8390a6.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/4afecf95-a678-f7c3-5e33-7a704aa371cb.png)

## 確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/ea1a77f7-b3c9-82e0-ca16-4cb9937ad803.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/395bebe9-4d38-ad2a-7b3c-aa2bb1e39b15.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/a26baf11-bc61-1864-3521-e2516345bbfc.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/80ff1e62-0029-096e-cf05-cfb73d52f5ba.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/ca87206f-1d9c-32ab-c443-cc2bb970af2e.png)

淡々と流れるログを見るのもアレなので、VCN内のインスタンスにsshをして、ログに残るかチェック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567355/d16da7f3-8203-e3bc-e8f0-a89f7bb1bf2d.png)
[Windows/Linux/macOS] 環境変数 PATH を改行して表示する

ターミナルやコマンドプロンプトで環境変数 PATH を表示すると 1 行で表示されて見にくいので、各 OS 別にワンライナーで改行で分割して見やすく表示する方法です。Windows の場合は ; を、Linux/macOS の場合は : を改行に置換します。

# Windows: コマンドプロンプト
```bat
echo %PATH:;=&echo.%
```

# Windows: PowerShell
```powershell
$env:PATH -split ';'
```

# Linux, macOS: bash, zsh
```bash
echo $PATH | tr ':' '\n'
```
構造体の作成

https://paiza.jp/works/mondai/class_primer/class_primer__make

PHPはこちら

https://qiita.com/Atsulabo/items/bdb81382c89c52f1b930

今度はPythonでやってみました。
ちなみに今回始めて。（仕事ではまあまあ作ってたけど。。。）

なんか、、、outputの文字列を作るところがきたないなあ。。。
と思ったのだけど、なかなかいいサンプルが見つからず。
（こちらで成功はしました）
とりあえずあげておきます。
f文字列を使えればいいのだけど、｛｝の扱いがうまくいかず、
他の方法で対応しました。
どうも｛｝はfのなかだと、エスケープをつかってもなかなかうまくいかない。
知ってる方いましたら教えて下さい。。。


```py
#class
class Member():
    def __init__(self, nickname, old, birth, state):
        self.nickname = nickname
        self.old = old
        self.birth = birth
        self.state = state
        
    def getOutput(self):
        output = "User{\nnickname : " + self.nickname  \
                + "\nold : " + self.old  \
                +  "\nbirth : " + self.birth  \
                + "\nstate : " + self.state  \
                + "\n}"

        print(output)
        
# main
N = int(input())
for i in range(N):
    arr = input().split()
    member = Member(arr[0], arr[1], arr[2], arr[3])
    member.getOutput()
```
pythonには回答があったのでありがたく見させてもらうことに

```py
N = int(input())

for _ in range(N):
    n, o, b, s = input().split()

    print("User{")
    print("nickname : " + n)
    print("old : " + o)
    print("birth : " + b)
    print("state : " + s)
    print("}")

```
え、、、、？
そんな書き方でいいんだ。。。と思ってしまいました。
まあ、クラスを使わなければこれでいいのだとは思うけど。
色々調べたらたいていクラス使ってるんだけどなあ。
とりあえず文字列の書き方は期せずしてわかったのでまあいいかな。
Cusor エディタでプライバシーモードを途中から有効にする

# コマンドパレットでSettingsを選んで

![image](https://github.com/YumaInaura/YumaInaura/assets/13635059/64f07cfc-f06a-46bb-9fc7-d2ec654b9448)

# こうだ

![image](https://github.com/YumaInaura/YumaInaura/assets/13635059/a9d3bc14-128e-4442-ac53-54d571daec8c)


# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ


# Twitter

https://twitter.com/YumaInaura
可読性の高いテーブル設計

可読性の高いテーブル設計には、いくつかの重要なポイントがあります。以下に、理解しやすく、効率的なテーブル設計のための基本的なガイドラインをご紹介します。

##### 明確な命名規則:

テーブル名やカラム名は、その内容を直感的に理解できるような名前を付けましょう。
例：ユーザー情報を格納するテーブルは users、商品情報を格納するテーブルは products といった具体的な名前が適しています。

##### 正規化:

データの重複を避け、効率的なデータ管理を実現するために、テーブルを正規化しましょう。
例：ユーザーの住所情報は addresses テーブルに分け、ユーザーIDで関連付けることで、情報の重複を防ぎます。

##### データ型の適切な選択:

カラムに保存するデータに合ったデータ型を選びましょう。
例：日付や時刻を扱う場合は DATE や DATETIME、数値は INT や DECIMAL を選択します。

##### 主キーと外部キーの使用:

各テーブルには一意性を保証する主キーを設定し、関連するテーブルとは外部キーを用いて関連付けましょう。
これにより、データの整合性が保たれ、関連データの検索が容易になります。

##### コメントの活用:

テーブルやカラムにコメントを付けることで、他の開発者がデータベースの構造を理解しやすくなります。

##### 適切なインデックスの使用:

頻繁に検索されるカラムにはインデックスを設定することで、クエリのパフォーマンスを向上させます。

##### 例

例として、シンプルなユーザー管理システムのテーブル設計を考えてみましょう。

```sql
CREATE TABLE `users` (
   `user_id` int(11) NOT NULL AUTO_INCREMENT,
   `username` varchar(50) NOT NULL,
   `email` varchar(100) NOT NULL,
   `created_at` datetime DEFAULT CURRENT_TIMESTAMP,
   `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
   PRIMARY KEY (`user_id`),
   UNIQUE KEY `email` (`email`),
   KEY `username` (`username`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `addresses` (
   `address_id` int(11) NOT NULL AUTO_INCREMENT,
   `user_id` int(11) NOT NULL,
   `street` varchar(100) NOT NULL,
   `city` varchar(50) NOT NULL,
   `state` varchar(50) NOT NULL,
   `country` varchar(50) NOT NULL,
   `postal_code` varchar(20) NOT NULL,
   PRIMARY KEY (`address_id`),
   KEY `user_id` (`user_id`),
   CONSTRAINT `addresses_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
```

この設計では、users テーブルがユーザーの基本情報を保持し、addresses テーブルがユーザーの住所情報を保持します。各テーブルは主キーによって一意性が保たれ、addresses テーブルは外部キーを通じて users テーブルに関連付けられています。
投稿されたフォームの再度開くの設定


+ [Microsoft Forms: 回答者が回答後に回答を編集できるようにする設定](https://art-break.net/tech/?p=18128)

「フォームの設定項目『回答者に回答の編集を許可する』にチェックを入れた直後は編集の準備ができておらず回答結果の閲覧しかできないが、編集できるようになった頃には」ということになります。
SQLパフォーマンス向上？ネステッドループの詳細解説と実践的なヒント

## 概要
本記事では、Oracleの表結合方法におけるネステッドループに焦点を当て、その詳細な検証を行います。ネステッドループは、分かりにくい側面があるかもしれませんが、理解しやすいように解説します。記事がお役に立てれば幸いです。

## ネステッドループとは
ネステッドループは、ループ処理をネストにして結合処理が行われるアルゴリズムです。外側のループが内側のループを制御し、条件に合致する行を探索する仕組みを持っています。ネステッドループ結合は、結合対象のデータサブセットが比較的小さい場合に特に適しています。

## ネステッドループの基本的な動作
- 外側のテーブル（ドライブテーブル）から1行ずつ取り出します。
- 外側のテーブルの各行に対して、内側のテーブル（プローブテーブル）が順次走査されます。
- 条件に合致する行が見つかると、結合された行が結果に追加されます。
- 外側のテーブルの次の行に進み、同じ手順を繰り返します。

## 使用シナリオ
ネステッドループは強力なクエリの選択肢であり、制約が高く、結果セットがわずかなレコードのみを返す場合に適しています。通常、ドライブテーブルのレコードは少なく、被駆動テーブルの接続列にはユニークなインデックスまたは選択性の高い非ユニークなインデックスがある場合、ネステッドループの効率が高まります。

ネステッドループは最初の数行のレコードを非常に迅速に返すため、エンドユーザーは速やかに最初の一連のレコードを取得でき、同時にデータベースは他のレコードを処理して返すことができます。ただし、クエリのドライブテーブルのレコードが非常に多い場合や、被駆動テーブルの接続列にインデックスが存在しないか、またはインデックスが高い選択性を持たない場合、ネステッドループの効率は低下します。

## 使用例
### 検証用データ作成
```sql
-- 表作成
CREATE TABLE t1 (
    id     INT,
    name   VARCHAR2(20)
);

CREATE TABLE t2 (
    id1    INT,
    name   VARCHAR2(20)
);

 -- データ導入
BEGIN
    FOR i IN 1..5 LOOP
        INSERT INTO t1 VALUES (
            i,
            'A' || i
        );

    END LOOP;

    COMMIT;
END;

BEGIN
    FOR i IN 1..100000 LOOP
        INSERT INTO t2 VALUES (
            i,
            'B' || i
        );

    END LOOP;

    COMMIT;
END;

-- インデックス作成

CREATE INDEX idx_t2_id1 ON
    t2 (
        id1
    );
```

### 実行計画確認
#### 検証用SQL
```sql
 select a . * , b . *
from t1 a , t2 b
where a . id=b . id1 and a . name like 'A1%';
```
#### 実行計画確認
実行計画が以下の通りです。
```sql
Plan hash value: 3013014930
 
-------------------------------------------------------------------------------------------
| Id  | Operation                    | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |            |     1 |    50 |     5   (0)| 00:00:01 |
|   1 |  NESTED LOOPS                |            |     1 |    50 |     5   (0)| 00:00:01 |
|   2 |   NESTED LOOPS               |            |     1 |    50 |     5   (0)| 00:00:01 |
|*  3 |    TABLE ACCESS FULL         | T1         |     1 |    25 |     3   (0)| 00:00:01 |
|*  4 |    INDEX RANGE SCAN          | IDX_T2_ID1 |     1 |       |     1   (0)| 00:00:01 |
|   5 |   TABLE ACCESS BY INDEX ROWID| T2         |     1 |    25 |     2   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   3 - filter("A"."NAME" LIKE 'A1%')
   4 - access("A"."ID"="B"."ID1")
 
Note
-----
   - dynamic statistics used: dynamic sampling (level=2)
```

#### 実行計画説明
- 1つ目のループに関しては、以下のSQLで取得したデータに対して、ループ制御を行います。
```　
 select * from t1 a where a.name like 'A1%';
 ```
- 2つ目のループに関しては、以下の結合条件を基づいて、テーブルt2に対して、ループ制御を行います。
```　
 select * from t2 b where b.id1 = a.id;
 ```

## パフォーマンス向上のためのポイント
- 外部テーブルのカーディナリティを低く保つ
  カーディナリティ（Cardinality）は、データモデリングやデータベース設計の文脈で使用される用語で、ある関係における1つの集合から別の集合へのマッピングの度合いを示します。
- 内部テーブルの結合列はインデックスに含める