OmniAICreator/Qiita-1.07M huggingface dataset:
【ロックアウト】Heroku 二段階認証のコード紛失【備忘録】

# はじめに
<!-- 発端や概要を記載 -->
Heroku をお使いのみなさんは二段階認証を設定していますか？
セキュリティを強化するためには、設定していた方がいいと思います。
しかし、強化したが故にログインできなくロックアウトする方もいると思います。
（ただセキュリティ上絶対に二段階認証を設定しておいた方がいいので、設定しましょう）

今回はロックアウトしたときのメモを残しておきます。

# 目次
<!-- タイトルとアンカー名を編集 -->
1. [そもそものそもそも二段階認証はどうやって設定し運用するのか？](#Chapter1)
1. [そもそもなぜロックアウトしたのか？](#Chapter2)
1. [どのようにして解除したのか？](#Chapter3)
1. [今後の対策](#Chapter4)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# そもそものそもそも二段階認証はどうやって設定し運用するのか？

簡単に説明するとスマートフォンなどで二段階認証コード作成アプリをインストールして、Heroku の Account Setting より QRコードを発行し、読み取ります。するとワンタイムパスワードがタイムスタンプ認証方式で発行されます。

そちらで発行されたパスワードを、通常ログイン後の画面でログインの度に入力します。

詳しい設定は[こちらを](https://devcenter.heroku.com/ja/articles/two-factor-authentication#enabling-two-factor-authentication)参照してください。


<a id="#Chapter2"></a>
# そもそもなぜロックアウトしたのか？
私もアプリを使用し、パスワードを発行していたのですが、アプリ側のバグでパスワードが２つずつ表示されてしまっていました。

そのときの私は「うわぁ、なんか２つあるぅ。邪魔やし１つ消したろ〜(っ’ヮ’c)ｳｩｯﾋｮｵｱｱｧｱｱｱｧ」と思い１つずつ消しました。
そのときは問題なく表示されていたのですが、次の日に確認すると

「きっ、消えてる。。。」

なんと全てのワンタイムパスワードが消えていました。。。OMG



<a id="#Chapter3"></a>
# どのようにして解除したのか？
先に結論を書いてしまうとサポートセンターにメールを送りました。。。
[こちら](https://devcenter.heroku.com/ja/articles/two-factor-authentication#recovering-from-lock-out)に載っているアドレスにメールを送りました。。。

1、2回やりとりをすると、セキュリティのために本人確認の質問が送られてきてそれに返信すると、サポートセンター側でリカバリーコードを発行し送信してくれます。（私の場合サポートセンターの営業日の都合上５日間ぐらいかかってしまいましたが、迅速に対応していただけました。）

本人確認の質問（英文）

```
We can provide you with a temporary recovery code so you can access your account. 
However, account security is not something we take lightly.
 As such, we would need you to verify all of the following information before pursuing this request further.

・If your account is connected to GitHub, please provide:
　　　　・the name of the GitHub account
　　　　・the app or pipeline name of a connected GitHub repository
　　　　・the repository name
・Your billing zip/postal code
・The invoice date, amount & number (#) for 2 of the last 6 months

Note if you are not billed on your personal account, please provide the above billing info for your team account instead.
```

本人確認の質問（和訳）

```
一時的なリカバリーコードをご提供しますので、アカウントにアクセスできます。
しかし、アカウントのセキュリティは、私たちが軽視するものではありません。
そのため、このリクエストを進める前に、以下の情報をすべて確認していただく必要があります。

・お客様のアカウントがGitHubに接続されている場合は、以下の情報を提供してください。
　　　　・GitHubアカウントの名前
　　　　・接続されているGitHubリポジトリのアプリ名またはパイプライン名
　　　　・リポジトリ名
・請求先の郵便番号
・過去6ヶ月間のうち2ヶ月分の請求書の日付、金額、番号（#）。

個人アカウントで請求書が発行されていない場合は、代わりにチームアカウントの上記の請求情報をご記入ください。
```

余談ですが先程のリンクのページが日本語だったので、日本のサポートセンターのメールアドレスなのかと思い、最初に送信したメールは全文日本語で送信したのですが、英語で送信してくださいと返信がきました。


<a id="#Chapter4"></a>
# 今後の対策
対策と言いますか、以下をしっかりしておけば今回のロックアウトは起こらなかったので、まだやってない方は是非一緒に設定しましょう。

- リカバリーコードを発行する
    - こちらは一度しか使用できないので、使用した際は忘れずにもう一度発行しましょう。
- SMS 番号の設定
    - こちらを設定していると、SMS　経由で二段階認証コードを発行できるので問題ない方は　SMS　番号を登録しましょう。
開発でよく使うツール系サイト

# 開発でよく使うツール系サイト
こんにちは。開発をしているときに、私がよく使うツール系サイトをまとめてみました。
最近は、リモート開発に便利なツール系サイトを使うことが多いです。
良いサイトが有りましたら、随時更新していく予定です。
他にも便利なツール系サイトがありましたら教えて下さい!

2021年10月作成

## JSON Editor
こちらは、JSONを整形してくれるサイトです。
JSONが読みにくかったりしたときに、こちらのサイトを使って整形しています。

https://jsoneditoronline.org/

## codic

変数名の命名に迷ったらこちらのサイトを使っています。
キャメルケースやスネークケースなど様々に対応しており、自動で英語にしてくれるので便利です。

https://codic.jp/engine

## Cukoo

モブで開発するときに、タイマーとしてこちらを使ってます。
タイマーの音が可愛いです。

https://cuckoo.team/

## hatjitsu
アジャイル開発でプランニングポーカーをするときにこちらを使っています。
リモートでプランニングポーカーをすることが多くなり、こちらをよく使うようになりました。
使い方も簡単で便利です。

https://hatjitsu.toolforge.org/

## Spatial Chat

開発とは関係ありませんが、リモート飲み会を開催するときはこちらを使ってます。
オンライン上で場所の移動ができたりするので、少人数で別れて会話したりすることができます。
50人までは無料で使えます。

https://spatial.chat/
Power Automate: Delve の設定取得と更新

# 背景

社員マッチングをするとしたら、Delve の情報を使えるといいな、ということで以下調査

- Delve 情報取得
- Delve 情報設定

MyProfile は問題ないが、他人のは権限がないからやっぱり駄目でした、という記録

# 方法
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/8088a993-a720-3d0a-3816-49f63b8a7068.png)

## 自分のプロファイルを取得する (V2)

https://docs.microsoft.com/ja-jp/connectors/office365users/#%E8%87%AA%E5%88%86%E3%81%AE%E3%83%97%E3%83%AD%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B-(v2)

## プロファイルを更新する
|対象|英語名|型|補足|
|-|-|-|-|
|自分について|aboutMe|string|
|誕生日|birthday|date-time|
|関心|Interests|string|
|自分のサイト|mySite|string|Delve では表示されてなさそう|
|過去のプロジェクト|Past Projects|string|
|学校|Schools|string|
|スキル|Skills|string|
https://docs.microsoft.com/ja-jp/connectors/office365users/#%E3%83%97%E3%83%AD%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E6%9B%B4%E6%96%B0%E3%81%99%E3%82%8B

# Delve の表示内容と、Update Action との比較

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/17457ee6-4632-3586-d838-14cb71507a2f.png)

# 課題
- Action 自体が、"My" となっている為、以下が必要
    - Run Only Users に実施者を追加して承認依頼
    - 実施者自身の実行

# Graph API で直接編集
とはいえ、権限無い他人の設定を変えられる訳はなく・・
自分のは問題なく実施可能ということが確認出来ただけ

```url:UpdateUser
https://graph.microsoft.com/v1.0/users/@{outputs('Get_my_profile_(V2)')?['body/id']}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/5be858bc-334b-5e4b-3494-e4c84b6c1f83.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/fbc0fa49-9e63-7308-9c5f-b22a55697b9e.png)


https://docs.microsoft.com/en-us/graph/api/user-update?view=graph-rest-1.0&tabs=http

# あとがき
実行時に、利用者に権限承認確認出来る方法がないものか・・
カリー化の背後にある随伴について

『ベーシック圏論』で圏論の勉強をしているのですが、Set圏での随伴がカリー化と結びついているというトピックが色々な概念を含み、あとで随伴の復習をする際に便利な素材だと思いました。具体的には Set圏における関手 -×B とその右随伴である (-)ᴮ の構成を通じて Set がカルテシアン閉であることを確認します。

『ベーシック圏論』p49, p56, p110, p196 あたりのトピックをまぜこぜにしたような記事です。


## 表記
基本的に『ベーシック圏論』に準じます:

- **Set**はSet圏をあらわします
- 圏𝓐 とその対象 A,B について 表記 𝓐(A,B) は、AからBへの射の集合を表します。たとえば **Set**(B, C) は B→C なる関数集合を表します。
- 集合B,C にたいして Cᴮ で B→C なる関数集合 **Set**(B,C) を表します。集合の場合は三つの表記 Cᴮ, B→C, **Set**(B,C) は同じものを指します。


## カリー化
2変数関数を、1変数関数に変換する操作をプログラミング言語ではカリー化と呼びます。例えば、足し算`plus`は2変数関数ですが、対応するカリー化された関数`cplus`を以下のように曖昧なく構成できて相互変換できます:

```javascript.js
// plus をカリー化した cplus を簡単に構成できる
const plus = (x,y) => x + y;
const cplus = x => y => x + y;

// 足し算に限らず任意の2変数関数をカリー化・アンカリー化できる
const curry2 = f => x => y => f(x, y);
const uncurry2 = f => (x, y) => f(x)(y);

// カリー化関数を使ってカリー化した cp は cplus は関数としては同じ
const cp = curry2(plus);
```

## 集合の言葉にすると
上記の議論を集合の言葉で言うと

「A×B→C と A→Cᴮ との同型写像とその逆写像を構成した」

となります。A×B→C なる関数の例が`plus`で、 A→Cᴮ なる関数の例が`cplus`で、カリー化関数`curry2`: (A×B→C)→(A→Cᴮ) はそれらの同型写像です。逆写像はアンカリー化関数`uncurry2`です。

## 随伴をみつける

以上のように全てを **Set**内の射としてとらえるのも一つの見方ですが、別の見方をすることで随伴が見つかります。随伴があると思って先の式を少し書き直します:

 **Set**(A×B, C) ≅ **Set**(A, Cᴮ)

すると **Set**→**Set** なる二つの関手 ×B と (-)ᴮ が見えてきます。なぜなら、それぞれに F,Gと名前をつけると

 **Set**(F(A), C) ≅ **Set**(A, G(C))

となり随伴の定義である同型性と同じ見た目になるからです。Bを任意だが固定された集合とすると、FやGが具体的にどのような関手なのか（どのような関手を構成するべきか）は自明です。FとGが随伴であるためには、これに加えて自然性を満たすことを確かめる必要があります。つまり集合の言葉で言えば「二つの写像 A×B→C と A→Cᴮ とが上記関手で対応づくように、二つの合成写像 A×B→C→D と A→Cᴮ→Dᴮ とが対応する」、同様に「二つの写像 A→Cᴮ と A×B→C とが上記関手で対応づくように二つの合成写像　X→A→Cᴮ と X×B→A×B→C とが対応する」となりますが、これを満たすのはほぼ自明です（……それほど自明でもないという人がいるかもしれませんが具体例を考えればわかるはず……）。

## 随伴性による射の構成

『ベーシック圏論』p50. では随伴性を射の構成法とみなす記述があり、示唆に富んでいます。

> 射の配列 A₀→A₁→..→Aₙ, F(Aₙ)→B₀, B₀→B₁→..→Bₘ からちょうどひとつの射 A₀→G(Bₘ) を構成できる

これを、以上の議論に適用するとこのような言明になります:

「どれか一つの2変数関数を選ぶと、そのカリー化された関数をちょうどひとつ構成できる」

まあ、`curry2`をすでに構成してしまっているのでありがたみはない言明ですが、「関数を部分適用された世界」と「関数を全部適用（？）した世界」が随伴性によって並行して議論できるという感触が味わえます。

## カルテシアン閉

以上の議論は、ひとことでいえば「**Set** はカルテシアン閉である」を丁寧に追っただけの話です。『ベーシック圏論』p197 の定義を引用すると

> 圏𝓐がカルテシアン閉とは, 𝓐が有限積を持ち, 各B∈𝓑について関手 ×B: 𝓐→𝓐 が右随伴―――(-)ᴮと表記する――を持つことをいう。

なお、𝓐(A×B,C) ≅ 𝓐(A,Cᴮ) が自然に成り立つことは随伴の定義から直接従います。

カルテシアン閉圏は、圏論的アプローチでプログラム意味論を展開する第一歩なので、**Set**をその具体例として確認しておいて損はなかったはず。
JavaScriptの論理演算子について

#falsyとtruthy
falsyとはBooleanで真偽値に変換した場合にfalseになる値のことを指します。逆にtruthyはBooleanで真偽値に変換した場合にtrueになる値のことを指します。イラストでわかりやすくまとめてみました。![スクリーンショット 2021-10-20 21.08.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1265227/8390a43e-d0e0-4000-4f26-ffbe1552b868.png)
コードでも確認してみましょう

```JS:JS
let a = null;
console.log(Boolean(a)); //false

let b = 1
console.log(Boolean(b)); //true
```

#論理演算子(OR:論理和), && (AND:論理積)
JavaScriptには|| (OR:論理和), && (AND:論理積)の論理演算子があります。 

###OR:論理和
論理和（or条件）の記法は||になります。論理和orでは4つの取りうる論理的な組み合わせがあります。

```JS:JS
console.log( true || true );   // true
console.log( false || true );  // true
console.log( true || false );  // true
console.log( false || false ); // false
```
or条件は最初の真値を探す挙動をとります（左から順に）。

```JS:JS
console.log( 1 || 0 ); // 1 (1 は真)
console.log( null || 1 ); // 1 (1 は最初の真値)
console.log( null || 0 || 1 ); // 1 (最初の真値)
```

##AND:論理積
論理積（and条件）の記法は&&になります。and条件は左から順に真値を評価し、最初の偽値、または偽値がない場合には最後の値を返します。

```JS:JS
console.log( true || true );   // true
console.log( false || true );  // false
console.log( true || false );  // false
console.log( false || false ); // false
```

```JS:JS
console.log( 1 && 0 ); // 0
console.log( 1 && 5 ); // 5
```
( 1 && 0 )では１では真で次に進み０は偽なのでそこで処理がストップし0を返しています。
( 1 && 5 )では１では真で次に進み5も真なので最後に評価された真の5を返しています。

##ANDとORの応用例
まず関数helloを用意します。引数にはnameを設定し、ブラウザ上でhello nameと出力できるようにします。

```JS:JS
function hello(name) {
    console.log('hello ' + name);
}

hello('Tom'); //hello Tom
hello(); //hello undefined
```

引数を設定しなければhello undefinedと出力されます。これをif文を利用して引数なしの時にもhello Tomと出力されるように書き換えます。(!はNOT演算子と呼び、真偽値型に変換した後逆の値を返します。)

```JS:JS
function hello(name) {
    if(!name) {
        name = "Tom"
    }
    console.log('hello ' + name);
}

hello(); //hello Tom
```
このif文を論理演算子を用いて書き換えてみます。

```JS:JS
function hello(name) {
    name = name || "Tom"
    console.log('hello ' + name);
}

hello(); //hello Tom
```

この場合まず引数に何も設定されていないので引数にはundefined（falthy）が渡されます。次にname || "Tom"では"Tom"がtruthyなのでTomが返され、結果的にnameには"Tom"が格納されます。
したがってコンソールではhello Tomが出力されます。

##参考
Udemy： 【JS】ガチで学びたい人のためのJavaScriptメカニズム
現代の JavaScript チュートリアル:https://ja.javascript.info/logical-operators
Colaboratoryにてtar.gzファイルを解凍する

なぜかわからないが、Colaboratory 上で素直に tar.gz ファイルを解凍することができなかったので、その際の対応のメモを記しておく。

状況としては Colaboratory から My Drive にマウントしており、回答したいファイルが My Drive 上にあるという状況を考えている。

```[python]
# まず拡張子をtar.gzからtarに変換する
!mv FILE_PATH/hoge.tar.gz FILE_PATH/hoge.tar

# tar.gz ファイルを解凍する
!tar xvf FILE_PATH/hoge.tar
```
git submodule絡みのメモ

あちこち情報があるけど、たまに使うコマンドのメモ
git clone --recursive 親プロジェクト.git
git submodule update --init --recursive
git submodule foreach --recursive "git pull origin main"
あたりを覚えておけば良さそう。
submoduleはブランチでなくコミット単位で保存され、git pullでは更新されないので扱いに注意が必要。

# 最初にやること
すでにsubmoduleで管理されているプロジェクトをcloneしたものとする。

```bash
git clone --recursive 親プロジェクト.git
```
* `git clone 親プロジェクト.git`と普通に持ってきても以下のコマンドでsubmoduleを更新できる。
* git cloneで--recursiveを忘れた時は以下と同じく`git submodule update --init --recursive`で取得できる。


## 親プロジェクトのsubmoduleを取得、更新
* 管理しているsubmoduleを取得（決まったcommit idのものが取得される）
* git pullするときに合わせて行うとよい。

```bash
cd 親プロジェクトのパス
git pull
git submodule update --init --recursive
```

## Git LFSを使っていたら

```bash
cd 親プロジェクトのパス
git lfs pull
git submodule foreach --recursive "git lfs pull"
```

# 修正したらやること
基本的にはsubmoduleでcommit,pushしたあと、親プロジェクトでcommit,pushすれば良い。

##  submoduleの修正（local -> remote）
* 普通にsubmoduleのフォルダで編集、git操作(commitしてpush、ここでは"main"ブランチを更新したとする)

```bash
cd submoduleのパス
git commit -a -m"update submodule contents"
```

## 親プロジェクトのsubmoduleを更新（local -> remote）
* 普通にcommit、pushすると、他の人も同じ環境を使えるようになる

```bash
cd 親プロジェクトのパス
git commit -a -m"update commit id of submodule"
```

## 親プロジェクトのsubmoduleを一括更新(local)
* submoduleで管理しているgitリポジトリの特定ブランチ("main")の最新版に一括取得
* ブランチ名が違うと一括更新できないので一つづつ行う必要がある。
* 利用するsubmoduleのブランチ名を合わせておいた方が便利。
* 親プロジェクトで管理しているsubmoduleを一括で変更するときなどに使う。
* --recursiveしているので、全部のsubmoduleを把握していないと意図せずupdateされてしまう。

```bash
cd 親プロジェクトのパス
git submodule foreach --recursive "git pull origin main"
```
GitHub Pagesにカスタムサブドメインを割り当てる

ついに自分のドメインを取得した（以下の記事参照）ので、GitHubPagesで公開していたプロジェクトにカスタムドメインを割り当ててみようと思います。


https://qiita.com/teracy164/items/2903708c78f44fe12e0c


# ①GitHub Pagesにカスタムサブドメインを入力

対象リポジトリの「Settings→Pages」からCustom domainにカスタムサブドメインを入力し、「Save」押下

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/f1384a27-60d5-670b-30bc-c22530d3a604.png)

# ②Route53でCNAMEレコードを追加

以下のレコードをホストゾーンに追加

- レコード名：*
- レコードタイプ：CNAME
- 値：<username>.github.io

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/dfcaba64-9f1b-36ac-3389-23d250da921d.png)

（2025/04/14 修正）
~~※ワイルドカードを指定することを強く推奨と参考ページに書いてあったので、レコード名はワイルドカードを指定します~~
ワイルドカードは推奨されてないため、正式運用する場合はちゃんとサブドメインをしていしましょう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/149e7f33-b37b-2d53-f7e1-08027479cef5.png)

引用：https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site/managing-a-custom-domain-for-your-github-pages-site#configuring-a-subdomain


# ③GitHub側でチェック

「Check again」を押下します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/ecbd7099-7caa-2820-a2a4-c0db695b8eeb.png)

TLSの設定を自動でやってくれるので、しばらく待ちます。（15分くらいかかるかもとのことです）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/104c7d16-7439-1f93-f5dd-811231d868ac.png)


※HTTPSを強制するために、「Enforce HTTPS」にチェック入れましょう

# アクセスする

無事に指定したカスタムドメインで公開することができました！！！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/5508687b-6018-90ba-80b4-80fef95b2c81.png)

※GitHub Pagesのデフォルトドメイン（<username>.github.io/<repo>）で公開していたプロジェクトをカスタムドメインに変更する場合、`base href`を`/<repo>`から`/`に変更する必要があるので注意が必要です。

※今回試したURLはまだ開発中のシステムなので、使えません。。


# 参考

https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site/managing-a-custom-domain-for-your-github-pages-site#configuring-a-subdomain
Jetson nano ＋ USB カメラでCheese（カメラアプリ）が動かないときの対処

###１．はじめに
"Jetson" のイントネーションは「コッペパン」と同じだと思っていた私ですが、あるとき半導体商社の人と会議して、「コックさん」と同じだと気づかされました。
まあ、それはよいとして。

###２．トラブルの状況
Jetson Nano 2GB に　JetPack4.5.1をインストールしました。
初期設定のおまじないをいろいろやって、USBカメラを接続しました。
/dev　のフォルダ内を lsで見ると、video0 が見えます。
カメラ自体は、ちゃんと認識されているようです。
![video0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/6c984fd4-7c85-870d-d860-60d7c6f5bcec.png)
問題は、デフォルトでインストールされているカメラアプリCheeseが動かないことです。
![Cheese.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/2fd3eec9-b1f0-ddb0-46eb-ad45a6b96837.jpeg)
起動しないというか、起動しかけて終了してしまうという感じです。

###３．解決方法
この問題は、すでにNVIDIAのフォーラムに投稿した人がおり、回答が出ていました。

[Jetpack 4.5: USB Camera does not work in Cheese and opencv 4.1](https://forums.developer.nvidia.com/t/jetpack-4-5-usb-camera-does-not-work-in-cheese-and-opencv-4-1/166908)
このページの一番下のあたり（５月11日のところ）にあるように、
[Jetsonのパッチ](https://elinux.org/Jetson/L4T/r32.5.x_patches)の、

[camera] 3rdparty application fails to open with USB cameraのリンクをクリックして、表示されたページにある、"Topic168303_Apr21_libv4l2_nvargus.zip" をダウンロードします。

ファイル名を"Topic168303_Apr21_libv4l2_nvargus.zip "から"libv4l2_nvargus.zip"  に変えます。

変えたファイルを /usr/lib/aarch64-linux-gnu/tegra/ にある同名のファイルと置き換えます。

これでCheeseを起動すると、まともに立ち上がります。
![スクリーンショット.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/8352bd43-7c55-c6c7-fa25-013c75faa98f.png)


というところです。
備忘録ですみません。
管理者のみに新規ユーザー登録を許可する[laravel8.*, laravel/breeze]

社内システム的なものを作る場合、Laravel標準のユーザー登録では好ましくない動作をしてしまうのでそこをいい感じに修正します。
**Laravel標準の動作**
URLを知っていれば誰でもユーザー登録可能
ユーザー登録後、そのユーザーで自動的にログイン
↓
**このように修正します。**
管理者のみユーザー登録できるようにする
ユーザー登録のみ行い、そのユーザーに切り替わらない

## version
```
PHP 8.0.11
laravel/framework 8.65.0
laravel/breeze 1.4.2
```

## guestの新規ユーザー登録をガードする
/routes/auth.php

```
Route::get('/register', [RegisteredUserController::class, 'create'])
                ->middleware('guest')
                ->name('register');

Route::post('/register', [RegisteredUserController::class, 'store'])
                ->middleware('guest');
```
↓ 上記の２箇所の guest を auth に変更します。

```
Route::get('/register', [RegisteredUserController::class, 'create'])
                ->middleware('auth')
                ->name('register');

Route::post('/register', [RegisteredUserController::class, 'store'])
                ->middleware('auth');
```

## ルートにアクセスした場合の遷移を変更する
未認証ユーザーの場合はログインページへ、認証ユーザーの場合はdashbordへ遷移するよう修正します。
/routes/web.php

```
Route::get('/', function () {
    return view('welcome');
});
```
↓

```
Route::get('/', function () {
    return view('dashboard');
})->middleware(['auth'])->name('dashboard');
```
/resources/views/welcome.blade.php は削除してしまいましょう。

## 新規ユーザー登録後の挙動を変更する
標準の動作ではユーザー登録後、登録したユーザーで自動的にログインしてしまいます。
これをユーザー登録のみ行い、登録したユーザーに切り替えないよう修正します。
breezeではAuth周りの処理が /app/Http/Controlers/Auth に追加されるようになりましたので気にせず直接修正してしまいましょう。

/app/Http/Controlers/Auth/RegisteredUserController.php

```
event(new Registered($user));

Auth::login($user);
```
上記の2行をコメントアウトします。

主な作業は以上になります。
/register へのリンクを /dashbord など適当な場所に追加しておきましょう。

Laravel7以前のlaravel/uiと比べてAuth周りの処理がvendor以下に追加されなくなったのでカスタマイズが非常に楽になりました。
次のLTSバージョンとなるバージョン9でも引き継がれていることに期待します。

以上、お疲れ様でした。
Route53でドメイン取得してみたので、FirebaseHostingで公開してたサイトにカスタムドメインを割り当ててみる

いままではGitHubPagesだったりFirebaseHostingとかで自動で付与してくれるドメイン使ってましたが、そろそろ自分のドメインが欲しいなーと思い、Route53で`teracy164.com`ドメインを取得してみました。

`www.teracy164.com`を以前に作ったブログに割り当ててみようかと思います。

https://qiita.com/teracy164/items/bc35bb21f98d3d493f9f


ちなみに`.com`ドメインは$12なので、年間1500円ほどで利用できます。


# ①FirebaseHostingでカスタムドメインを追加

FirebaseコンソールからHosting⇒「カスタムドメインを追加」を押下します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/1a10ae93-6f0d-f172-a9b1-afcbd8fcf507.png)

ドメインを入力し「次へ」を押下します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/4868c8e5-bb19-aec8-5703-65ab6d66dca1.png)

TXTレコードが生成されるのでコピーします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/b712ff03-7e1a-67e9-d901-305047b124a9.png)


# ②Route53でTXTレコードを作成

Route53のホストゾーンから追加したドメインを選択します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/cea7a46f-243e-2e83-fe24-722c605249c7.png)

「レコードを作成」を押下します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/330a223a-059a-1571-64a6-644c5f628a5f.png)

必要事項を入力して「レコードを作成」を押下します

- レコード名：`www`
- レコードタイプ：`TXT`
- 値：①でコピーした値

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/fa60af58-d377-189c-45c7-903afb943581.png)



# ③FirebaseHostingで所有権の証明およびAレコード情報の取得

Route53でTXTレコードの登録が完了したらFirebase側に戻って「所有権を証明」を押下します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/83e5bb9c-4442-4a42-ba78-ec5a6b9ca990.png)


プロバイダ側でAレコードを追加するように言われるので、表示されたIPアドレスをコピーします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/28cc1689-9e37-a9ce-e628-050a2d5317ed.png)

# ④Route53でAレコード追加

Route53で再度「レコードを作成」から、必要事項を入力して「レコードを作成」を押下します

- レコード名：`www`
- レコードタイプ：`A`
- 値：①でコピーした値（IPアドレス）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/120e85f0-e85f-9106-1cf1-eb25196808ca.png)


# アクセスしてみる

早速 https://www.teracy164.com にアクセスしてみます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/e7f0f1ba-bd08-d503-ba09-a4de7b5a84b1.png)

表示されました！！！
ちなみに、SSL証明書の発行はFirebase側で自動でやってくれます（自分の場合は2時間ほどで有効になりましたが、最大24時間かかるそうです）



# 参考

https://firebase.google.com/docs/hosting/custom-domain?hl=ja
管理者のみに新規ユーザー登録を許可する[laravel6.*, laravel/ui]

**1年近く前に書いた記事が下書きに眠ったままでした...**

社内システム的なものを作る場合、Laravel標準のユーザー登録では好ましくない動作をしてしまうのでそこをいい感じに修正します。
**Laravel標準の動作**
URLを知っていれば誰でもユーザー登録可能
ユーザー登録後、そのユーザーで自動的にログイン
↓
**このように修正します。**
管理者のみユーザー登録できるようにする
ユーザー登録のみ行い、そのユーザーに切り替わらない

## version
```
laravel/framework 6.18.41
laravel/ui 1.2.0
```

## 管理者のみユーザー登録できるようにする
参考サイト
[Laravel：管理者のみに新規ユーザー登録(register)を許可](https://qol-kk.com/wp2/blog/2019/01/18/post-1045/)
こちらを参考にファイルをいくつか修正しまし。
## ユーザー登録処理後の動作を変更する
ここからが本題です
vendor以下を変更すると後々大変ですので、それを避けつつユーザー登録処理後の動作を変更します
参考サイト
[Laravel：管理者によるregister実行後の動作を変える](https://qol-kk.com/wp2/blog/2019/01/18/post-1048/)
[Laravelでvendor内の処理をオーバーライドする方法](https://qiita.com/hamkiti/items/d06367927e1a4ac1971d)
### ユーザー登録後の処理を行なっている箇所
`vendor\laravel\framework\src\Illuminate\Foundation\Auth\RegistersUsers.php`

```php:RegistersUsers.php
public function register(Request $request)
{
    $this->validator($request->all())->validate();

    event(new Registered($user = $this->create($request->all())));

    $this->guard()->login($user);  // <- ここでログインしている

    return $this->registered($request, $user)
                    ?: redirect($this->redirectPath());
}
```
### 任意のディレクトリに RegistersUsers.php をコピーし、修正
オーバーライドするために対象のファイルを任意の場所にコピーします。
今回はこのようにしました。
`app\Vendor\laravel\framework\src\Illuminate\Foundation\Auth\RegistersUsers.php`
問題のログイン部分をコメントアウトしてしまいましょう

```php:RegistersUsers.php
public function register(Request $request)
{
    $this->validator($request->all())->validate();

    event(new Registered($user = $this->create($request->all())));

    // $this->guard()->login($user);

    return $this->registered($request, $user)
                    ?: redirect($this->redirectPath());
}
```

### リダイレクト先を指定する
ユーザー登録後のリダイレクト先です。任意で指定
`app\Http\Controllers\Auth\RegisterController.php`

```php:RegisterController.php
    protected $redirectTo = '/user_list';
```

### composer.jsonのautoloadを修正
ここが肝になります。
`exclude-from-classmap`で元のファイルを読み込まないように、
`files`で修正後のファイルを読み込むように指定します。

```json:composer.json
    "autoload": {
        
        "exclude-from-classmap": [
            "vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Auth\\RegistersUsers.php"
        ],
        "files":[
            "app\\Vendor\\laravel\\framework\\src\\Illuminate\\Foundation\\Auth\\RegistersUsers.php"
        ]
    }
```

### composer.jsonの変更を反映する
composer.jsonに行なった変更を反映するためコマンドを実行します

```bash:コマンド
composer dump-autoload
```

以上になります。
お疲れ様でした。
staticの意味と使い方

#staticとは
通常クラスの中で定義した変数（プロパティ）やメソッドを呼び出すためにはインスタンスを生成する必要がある。
元々存在しないものを生み出すのでdynamig(動的)なメソッド・プロパティ。

一方、static(静的)では、<font color="red">インスタンスを生成せずクラスを直接指定して、変数やインスタンスを呼び出せるメソッド・プロパティ</font>のこと。

##名称
***動的（dynamic）な変数***
インスタンスごとに管理されるため、
　・<font color="LimeGreen">インスタンス変数</font>
と呼ばれる

***静的（static）な変数***
各インスタンスで異ならないもの。
　・<font color="LimeGreen">static変数</font>
　・<font color="LimeGreen">クラス変数</font>
と呼ばれる


##staticのメリット
アプリケーションの中で複数回登場する関数やプロパティを定義するときに使え、staticはそのクラスを呼びした場合のみ使えるため、
プロパティ名やメソッド名が被りそうな場合や、***ある特定の目的のプロパティをメソッドまとめる場合に使うと、処理がまとまる***という利点がある。
→static変数を変更した場合、すべてのインスタンスに変更が反映される

##staticの使用例

```php
<?php 

class TestClass
{
  public $name = "名前";
  public static $staticname = "staticな名前";
}

//クラスの外部で呼び出し
echo TestClass::$staticname;
// "staticな名前が表示

echo TestClass::$name;
// インスタンスを生成していないのでエラー

```
次に実際にインスタンス化を行って例を示す。

```php
// 人間クラスを定義
class Human {

  // メンバ
  public $name;                     // 「名前」というインスタンス変数
  public static $family = ""ヒト科""; // 「科」というstatic変数/クラス変数

}

// 「名前」が青木という人間
$aoki = new Human();
$aoki->name = ""青木"";

// 「名前」が山田という人間
$yamada = new Human();
$yamada->name = ""山田"";

// static変数はクラスから直接呼び出せます！
echo Human::$family.PHP_EOL;    // ヒト科

// それぞれのインスタンについて確認してみましょう！
echo $aoki->name.PHP_EOL;       // 青木
echo $aoki::$family.PHP_EOL;    // ヒト科
echo $yamada->name.PHP_EOL;     // 山田
echo $yamada::$family.PHP_EOL;  // ヒト科

// static変数を変更してみると、クラスとすべてのインスタンスで共有しているので、全部に影響します！
Human::$family = ""哺乳類"";
echo Human::$family.PHP_EOL;    // 哺乳類
echo $aoki::$family.PHP_EOL;    // 哺乳類
echo $yamada::$family.PHP_EOL;  // 哺乳類
```
M1 MacbookでDockerでMySQLを立ち上げる時にハマった

## docker compose up でつまずいた
Dockerfile NGパターン

```
FROM mysql:5.7
```

エラー内容

```
docker: no matching manifest for linux/arm64/v8 in the manifest list entries.
```

Dockerfileまたはdocker-compose.ymlでplatformを指定する
Dockerfileの場合

```
FROM --platform=linux/x86_64 mysql:5.7
```

docker-compose.ymlの場合

```
  mysql:
    image: mysql:5.7
    platform: linux/x86_64
```

これで、docker compose upは問題なく通りました。

## DBがうまく起動していない
migrateで失敗したため、DBコンテナを調べると以下のようなログが出てMySQLの起動に失敗していました。

```
[ERROR] [Entrypoint]: MYSQL_USER="root", MYSQL_PASSWORD cannot be used for the root user
    Use one of the following to control the root user password:
    - MYSQL_ROOT_PASSWORD
    - MYSQL_ALLOW_EMPTY_PASSWORD
    - MYSQL_RANDOM_ROOT_PASSWORD
```

エラー内容を翻訳すると
> MYSQL_PASSWORDはrootユーザーには使用できません

開発環境なので以下のような設定をしていたのがダメになったみたいです...
docker-compose.yml NGパターン

```
  mysql:
    build: ./docker/mysql
    container_name: "hogehoge-db"
    restart: always
    environment:
      MYSQL_DATABASE: hogehoge-db
      MYSQL_USER: root
      MYSQL_PASSWORD: root
      MYSQL_ROOT_PASSWORD: root
```

MYSQL_USERがrootなのが問題なので以下のように修正しました。
docker-compose.yml OKパターン

```
  mysql:
    build: ./docker/mysql
    container_name: "hogehoge-db"
    restart: always
    environment:
      MYSQL_DATABASE: hogehoge-db
      MYSQL_USER: user
      MYSQL_PASSWORD: password
      MYSQL_ROOT_PASSWORD: passw0rd
```

以前から動いていた設定だったため見つけるまでに時間がかかってしまいました...
初心にかえってログを見る、これ大事。

以上、お疲れ様でした。
新型MacBook Proのノッチをいち早く体験してみた

Apple から新型 MacBook Pro が発表され、iOS エンジニア界隈は盛り上がりましたね。新型 MacBook Pro は高性能な M1 Pro チップやさらに高性能な M1 Max チップが搭載されたり、Touch Bar が立場を失ってリストラされたり、高品質なスピーカーが搭載されたり、HDMI ポートや SD カードスロットが復活したりと様々注目ポイントがありますが、パッと見でもわかる変化としては iPhone のようにディスプレイにノッチが採用されたことが大きいのではないでしょうか？

ということで、世界的に見ると何番煎じかわかりませんが、例に漏れず私も macOS アプリ開発者の端くれとしてノッチが体験できるクソアプリを作って体験してみました。

## iNotch

![demo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67153/e65c4f23-1b18-8ab1-564f-4e66b09feeb4.png)

https://github.com/Kyome22/iNotch

Releases からアプリをダウンロードして試せます。

## 技術要約

- `NSScreen.main.frame`で画面の中央上部の座標を算出
- `NSPanel`で最前面に透明なウインドウを固定
  - `styleMask`に`[.borderless, .nonactivatingPanel]`を指定
  - `level`を`.popUpMenu`に指定
  - `hasShadow = false`でパネルの影を消す
- `NSView`で`NSBezierPath`を描画してノッチを再現
- ノッチへのクリックを`mouseDown`で取得して`Combine`の`PassthroughSubject`を使ってイベント伝搬

## 所感

ノッチは結構威圧感があって邪魔ですね 😅
Swift Combine の練習としては良かったと思います。


- item
- item
- item "</ul>"
AtCodeログ：0135 - ABC 221 B

# 問題

https://atcoder.jp/contests/abc221/tasks/abc221_b

# 回答
## 回答1 (AC)
文字列 $S$ と $T$ が等しければ、操作するまでもなく $S$ と $T$ は一致しています。等しくなければ、最初の文字から順番に比べてていき、$S$ のはじめて一致しなかった文字とその次の文字を入れ替え、新しい文字列 $S$ が $T$ に等しくなれば Yes, そうでなければ No を出力して終了となります。コードは以下のようになりました。

```C++:abc221a-1.cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
  string s, t;
  cin >> s >> t;

  string answer = "Yes";
  if ( s!=t ) {
    for ( int i=0; i<s.size(); i++ ) {
      if ( s[i]!=t[i] ) {
        swap(s[i],s[i+1]);
        if ( s!=t ) {
          answer = "No";
          break;
        } else {
          break;
        }
      }
    }
  }

  cout << answer << endl;
}
```

# 調べたこと
## [AtCoder の解説](https://atcoder.jp/contests/abc221/tasks/abc221_b/editorial) → [公式解説](https://atcoder.jp/contests/abc221/editorial/2717)
回答1と同じ解法でした。

# リンク
## 前後の記事
- 前の記事 → [AtCoderログ：0134 - ABC 221 A](https://qiita.com/RoadLynton/items/c3edc5f8b0c43878517b)
Windows11に更新したらWSL2でGPUが認識しない

# はじめに

昨日やっとの思いで、GPUのDocker + PyTorchの環境を作成でき、次の日に記事を書こうと思い放置しました。
そして朝になり、`nvidia-smi`コマンドを叩いたところ、エラーが発生するようになっていました。

まさかとは思い、WindowsのUpdate履歴を確認したところ、

![bandicam 2021-10-20 20-37-00-143.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/78d763bc-5b0c-4c8d-7b1e-6954f54076a5.jpeg)

朝に勝手に更新が走って、Windows11になっていました。

せっかく苦戦して設定したのに、また動かなくなるという悪夢が起きました。
今回はこれに対処したので記事にまとめていきます。

# 問題

Windows11に勝手に更新されたのが原因で`nvidia-smi`を叩くと以下のエラーが発生するようになりました。

```
NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver. Make sure that the latest NVIDIA driver is installed and running.
```

これを調べると以下の記事を発見。

[いつの間にか壊れてしまっていたGPU環境を直す](https://blog.mktia.com/fix-broken-gpu-environment/)

ここには、GPUを起動しっぱなしにすると壊れてしまうことがあると書いてあり、朝まで放置したのが原因かとも思いましたが、とりあえずWindows11になったことがわかったのでその線で調べることにしました。

# 解決方法

以下の記事を見つけました。

[Windows 11公式対応版となる「GeForce 472.12 Driver」がリリース](https://www.4gamer.net/games/022/G002210/20210921035/)

まさかとは思い、一応NVIDIA DRIVERを新しくインストールしました。

https://developer.nvidia.com/cuda/wsl/download

すると、Windows11番があります。

インストールした後に`nvidia-smi`を叩くと、しっかり認識されていました。
まさかのドライバが原因でした。

# それ以外に疑ったところ

buildが古くなっているのでインストールしてください。というのもWindowsを起動すると出ていました。
これは結果的には関係ありませんでした。

[期限切れの Insider Preview ビルドからの更新](https://docs.microsoft.com/ja-jp/windows-insider/build-expiration)

# おわりに
GPUの設定にかなり悪戦苦闘してやっと設定が終わりました。
一難去ってまた一難でした。もうエラー出てほしくないです。

# 参考
- [いつの間にか壊れてしまっていたGPU環境を直す](https://blog.mktia.com/fix-broken-gpu-environment/)
- [Windows 11公式対応版となる「GeForce 472.12 Driver」がリリース](https://www.4gamer.net/games/022/G002210/20210921035/)
- [期限切れの Insider Preview ビルドからの更新](https://docs.microsoft.com/ja-jp/windows-insider/build-expiration)
1秒毎に実行する

```C#:Player
void Start()
    {
        Invoke("Pltime", 1f);
    }

    void Pltime ()
    {
        //1秒毎にやりたいこと
        this.transform.Translate(0.0f, -1.0f, 0.0f); 
        //関数名と何秒毎に実行したいのか
        Invoke("Pltime", 1f);
    }
```
3秒毎に実行したければ、1fの所を3fにすれば大丈夫です！
go pprof snippet

cpu, trace, memory, block and goroutine

```go
cw, err := os.Getwd()
	if err != nil {
		panic(err)
	}

	f, err := os.Create(path.Join(cw, "cpu.prof"))
	if err != nil {
		panic(err)
	}
	defer f.Close()
	if err := pprof.StartCPUProfile(f); err != nil {
		log.Fatal("could not start CPU profile: ", err)
	}
	defer pprof.StopCPUProfile()

	tf, err := os.Create(path.Join(cw, "trace.out"))
	if err != nil {
		panic(err)
	}
	defer tf.Close()
	if err := trace.Start(tf); err != nil {
		log.Fatalf("profile: could not start trace: %v", err)
	}
	defer trace.Stop()

	old := runtime.MemProfileRate
	runtime.MemProfileRate = 4096
	defer func() {
		cw, err := os.Getwd()
		if err != nil {
			panic(err)
		}
		f, err := os.Create(path.Join(cw, "mem.prof"))
		if err != nil {
			panic(err)
		}
		defer f.Close()

		defer func() {
			runtime.MemProfileRate = old
		}()

		runtime.GC()
		if err := pprof.WriteHeapProfile(f); err != nil {
			log.Fatal("could not write memory profile: ", err)
		}
	}()

	runtime.SetBlockProfileRate(1)
	defer func() {

		cw, err := os.Getwd()
		if err != nil {
			panic(err)
		}
		f, err := os.Create(path.Join(cw, "block.prof"))
		if err != nil {
			panic(err)
		}
		defer f.Close()

		runtime.SetBlockProfileRate(1)
		defer func() {
			pprof.Lookup("block").WriteTo(f, 0)
			runtime.SetBlockProfileRate(0)
		}()

	}()

	defer func() {

		cw, err := os.Getwd()
		if err != nil {
			panic(err)
		}
		f, err := os.Create(path.Join(cw, "goroutine.prof"))
		if err != nil {
			panic(err)
		}
		defer f.Close()

		runtime.SetBlockProfileRate(1)
		defer func() {
			if mp := pprof.Lookup("goroutine"); mp != nil {
				mp.WriteTo(f, 0)
			}
		}()

	}()
```
ABC203 A～C問題 ものすごく丁寧でわかりやすい解説 python 灰色～茶色コーダー向け #AtCoder

ABC203(AtCoder Beginner Contest 203)　A～C問題の解説記事です。
灰色～茶色コーダーの方向けに解説しています。

その他のABC解説、動画などは以下です。

https://qiita.com/sano192/items/54accd04df62242b70f0

# パナソニック株式会社様について
このコンテストはパナソニック株式会社様がスポンサードされています。
興味のある方は採用情報をご覧ください。

https://recruit.jpn.panasonic.com/rd/

# A - Chinchirorin

https://atcoder.jp/contests/abc203/tasks/abc203_a

問題文の条件をif文で実装します。
a=bの場合：cを出力
b=cの場合：bを出力
c=aの場合：aを出力
それ以外：0を出力
これらをifとelif、elseで実装します。

入力の受け取り、出力がわからない方は以下の記事を参考にしてください。

https://qiita.com/sano192/items/eb2c9cbee6ec4dc79aaf

**【提出】**

```python:
# 入力の受け取り
a,b,c=map(int, input().split())

# a=bの場合
if a==b:
    # cを出力
    print(c)
# b=cの場合
elif b==c:
    # cを出力
    print(a)
# c=aの場合
elif c==a:
    # cを出力
    print(b)
# それ以外(同じものがない場合)
else:
    # 0を出力
    print(0)
```

# B - AtCoder Condominium

https://atcoder.jp/contests/abc203/tasks/abc203_b

101,102,...10K,201,202,...,20K,...,i0Kまでそれぞれ実際に数字を作って足せばよいです。
i,jについてfor文でi=1～Nまで、j=1～Kまでそれぞれ処理を行います。

部屋番号(room)はまず文字列として作ります。
(str(i)と書くことでiを文字列に変換できます。str(i)+"0"+str(j)とすれば「i0j」の部屋番号を作れます)
その後int(room)として文字列→数値に変換して足し算しましょう。

**【提出】**

```python:
# 入力の受け取り
N,K=map(int, input().split())

# 答えを格納する変数
ans=0

# i=1~Nまで
for i in range(1,N+1):
    # j=1~Kまで
    for j in range(1,K+1):
        # 部屋番号(文字列)
        room=str(i)+"0"+str(j)
        # 部屋番号を整数へ→答えに値を足す
        ans+=int(room)

# 答えを出力
print(ans)
```

# C - Friends and Travel costs

https://atcoder.jp/contests/abc203/tasks/abc203_c

この問題は拙著 **「AtCoder　凡人が『緑』になるための精選50問詳細解説」** にて解説しています。
サンプルとして全文 **無料** 公開しているので下記の記事を御覧ください。

https://qiita.com/sano192/items/2193fbb57ab66237ed9e

# 【広告】
## 『AtCoder　凡人が『緑』になるための精選50問詳細解説』

AtCoderで緑になるための典型50問を**ひくほど丁寧に**解説した本(kindle)、pdf(booth)を販売しています。
値段：**100円(Kindle Unlimited対象)**
**【kindle】**

https://www.amazon.co.jp/gp/product/B09C3TPQYV/

**【booth(pdf)】**

https://sano192.booth.pm/items/3179185

**1～24問目まではサンプルとして無料公開しています**

https://qiita.com/sano192/items/eb2c9cbee6ec4dc79aaf

## 『AtCoder ABC201～225 ARC119～128 灰・茶・緑問題 超詳細解説』

**ABC201~225、ARC119~128** の **灰・茶・緑DIfficulty問題(Dif：0～1199)** を解説しています。
とにかく **細かく、丁寧に、具体例を豊富に、実装をわかりやすく、コードにコメントをたくさん入れて** 解説しています。

**サンプルを5問分公開しています**

https://qiita.com/sano192/items/3258c39988187759f756

Qiitaにて無料公開している『ものすごく丁寧でわかりやすい解説』シリーズをベースにしていますが、 **【キーワード】【どう考える？】【別解】を追加** し、 **【解説】と【実装のコツ】を分ける** ことでよりわかりやすく、 **具体例や図もより豊富に** 書き直しました。
Qiitaには公開していない **ARC119~128の灰・茶・緑DIfficulty問題も書き下ろし** ています。

値段：**300円(Kindle Unlimited対象)**
**【kindle】**

https://www.amazon.co.jp/dp/B09TVK3SLV

**【booth(pdf)】**

https://booth.pm/ja/items/3698647

**ARC119~128の部分のみ抜粋した廉価版** もあります。
値段：**200円(Kindle Unlimited対象)**
**【kindle】**

https://www.amazon.co.jp/dp/B09TVKGH17/

**【booth(pdf)】**

https://sano192.booth.pm/items/3698668

## 『Excelでリバーシを作ろう!!　マクロ、VBAを1から学ぶ』

Excelのマクロ(VBA)で「三目並べ」「マインスイーパー」「リバーシ」を作る解説本です！
マクロ、VBAが全くわからない人でも大丈夫！　丁寧な解説と図でしっかり理解しながら楽しくプログラミングを学ぶ事ができます！
**値段：300円(Kindle Unlimited対象)**

サンプルとして「準備」～「三目並べ」を無料公開しています。

https://qiita.com/sano192/items/9a47e6d73373d01e31fb

**【kindle】**

https://www.amazon.co.jp/dp/B09XLM42MW

**【booth(pdf】**

https://sano192.booth.pm/items/3785312
BufferedReaderはJavaでどのくらいの速さで行を読み取ることができますか？

[前回の投稿](https://qiita.com/chenyh/items/ed86364a8bdb6c635a4d)で、C++のgetline関数がテキストファイルの行をどれだけ速く実行できるかを尋ねました。答えは約2GB / sで、確かに1 GB / sを超えていました。これは、いくつかの最高のディスクドライブやネットワーク接続よりも低速です。ソフトウェアが行に「ただ」アクセスするだけでよいことはめったにないことを考慮に入れると、ディスクやネットワークにバインドされるのではなく、テキストファイルの処理がプロセッサにバインドされるシステムを簡単に構築できます。

Javaはどうですか？Javaでは、テキストファイルの行にアクセスする標準的な方法は、BufferedReaderを使用することです。システムコールを回避するために、多くのテキスト行を含む大きな文字列を作成してから、文字列の長さを記録するだけの非常に単純な処理関数を呼び出します…

```java
StringReader fr = new StringReader(data);
BufferedReader bf = new BufferedReader(fr);
bf.lines().forEach(s -> parseLine(s));

// elsewhere:
public void parseLine(String s) {
  volume += s.length();
}
```

その結果、このベンチマークでは、同じシステム上でJavaはC ++よりも少なくとも2倍遅くなります。

**BufferedReader.lines： 0.5GB/s**

これはJavaが実行できる最善の方法ではありません。Javaはデータをはるかに高速に取り込むことができます。ただし、私の結果は、最近のシステムでは、Javaファイルの解析は、システムにバインドされているのではなく、プロセッサにバインドされていることが多いことを示しています。つまり、はるかに優れたディスクとネットワークカードを購入でき、システムがこれ以上速くなることはありません。もちろん、本当に優秀なJavaエンジニアがいない限り。

多くの企業は、おそらく問題に対してより多くのハードウェアを投入するだけです。

[私のソースコードが利用可能](https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/tree/master/2019/07/26)です。

**更新：**以前のバージョンのコードには、1つの巨大な行を作成する小さなタイプミスがありました。これは、結果にあまり影響を与えないことがわかりました。一部の人々は、より技術的な詳細を求めました。ベンチマークは、GNU GCC8.1をC ++コンパイラとして使用し、Java12をすべてLinuxで使用してSkylakeプロセッサで実行しました。結果は、正確な構成によって異なります。

英語原稿：https://lemire.me/blog/2019/07/26/how-fast-can-a-bufferedreader-read-lines-in-java/
C ++でのgetlineの速度はどれくらいですか？

C ++でテキストファイルを読み取る標準的な方法は、getline関数を呼び出すことです。ファイル内のすべての行を繰り返し処理してその長さを合計するには、次のようにします。

```C++
while(getline(is, line)) {
    x += line.size();
}
```

これはどれくらい速いですか？

ディスクにアクセスできない最近のGNUGCCコンパイラを搭載したSkylakeプロセッサでは、約2GB /秒で動作します。これは、優れたフラッシュドライブの最大スループットよりも低速です。これらの結果は、さらに高速なディスクを購入してもシングルスレッドのスループットが向上しないという意味で、C ++でテキストファイルを読み取るとCPUが制限される可能性があることを示しています。

nanoseconds per byte:	0.46 ns
speed:	2.0 GB/s

[私のコードは利用可能です。](https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/tree/master/2019/06/18)

getline関数呼び出しによって生成された文字列を処理するコードを作成する場合、最悪の場合、合計時間はgetline関数に必要な時間とコードに必要な時間の合計になります。つまり、2 GB / sに近い速度を達成する可能性はほとんどありません。
それに比べて、[simdjsonのようなソフトウェアライブラリ](https://github.com/lemire/simdjson)は、2 GB / sを超える速度で、Unicode検証から数値解析まですべてを実行してJSON入力を解析および検証できます。
私はそうしようとはしていませんが、2 GB / sよりもはるかに速い速度で、線を見つけて反復することができます。


英語原稿: https://lemire.me/blog/2019/06/18/how-fast-is-getline-in-c/
高速な16ビット乱数ジェネレーター？

ソフトウェアでは、多くの場合、乱数を生成する必要があります。通常、疑似乱数ジェネレーターを使用します。

単純なジェネレーターはwyhashです。これは乗算とそれに続くXORです。

```C++
uint64_t wyhash64_x; 

uint64_t wyhash64() {
  wyhash64_x += 0x60bee2bee120fc15;
  __uint128_t tmp;
  tmp = (__uint128_t) wyhash64_x * 0xa3b195354a39b70d;
  uint64_t m1 = (tmp >> 64) ^ tmp;
  tmp = (__uint128_t)m1 * 0x1b03738712fad5c9;
  uint64_t m2 = (tmp >> 64) ^ tmp;
  return m2;
}
```

64ビットの数値を生成します。私は最近、同等であるがより小さな規模を構築できるかどうか尋ねられました。
16ビット整数のみが必要で、wyhash64関数のモデルに従いたい場合はどうなりますか？これは、限られたプロセッサで作業していて、必要性がそれほど高くない場合に役立つことがあります。これが私の提案です：

```C++
uint16_t wyhash16_x; 

uint32_t hash16(uint32_t input, uint32_t key) {
  uint32_t hash = input * key;
  return ((hash >> 16) ^ hash) & 0xFFFF;
}


uint16_t wyhash16() {
  wyhash16_x += 0xfc15;
  return hash16(wyhash16_x, 0x2ab);
}
```

このコードを使用するには、最初にwyhash16_xを選択した値に初期化する必要があります。増分（0xfc15）を他の奇数の整数に置き換えることもできます。このジェネレーターの周期は65536です。これは、65536の値の後、完全な円に戻ることを意味します。

本質的なアイデアはhash16関数にあります。特定のキー値に対して、16ビット値から16ビット値へのマップがあります。一般に、マップは反転できません。キー値を0xfc15に選択します。この選択により、アバランシェ効果が「最大化」されます。つまり、指定された値を取得し、hash16でハッシュしてから、1ビットを変更し、再度ハッシュすると、2つの出力の差は約8ビット（16ビットのうち）反転するはずです。つまり、入力値を少し変更すると、出力が大幅に変わるはずです。

hash16の機能が可逆ではない...それは私が雪崩効果が非常に弱いようにする必要があります可逆にします。0xfc15の場合、そのドメイン（出力値のセット）のサイズは44,114のみですが、65536個の異なる16ビット値があります。それは悪いですか？良い。0から65536までの65536のランダムな値を生成する場合、いくつの異なる値を期待しますか？答えは約41,427です。したがって、どちらかといえば、私のhash16関数のドメインが大きすぎる可能性があります。

数千の16ビット値を生成するだけでよい場合は、この単純なジェネレーターで十分な場合があります。高速の32ビット乗算器がある場合も高速になります。明らかに、あなたが深刻な数の計算をすることを計画しているなら、それはすぐにその限界を示します。それらのどれもそのような小さな発電機のために設計されていないので、私はそれを標準的な統計的検定に押し込もうとさえしませんでした。
面白いと思ったのは、なだれ効果を最適化することで、まともな画像サイズのジェネレーターも手に入れたということです。

この問題の分析に使用したソースコードは入手可能です。
付録。さらに、[0、s）の範囲の整数値を効率的に生成できます。

```C++
uint16_t rand_range16(const uint16_t s) {
    uint16_t x = wyhash16();
    uint32_t m = (uint32_t)x * (uint32_t)s;
    uint16_t l = (uint16_t)m;
    if (l < s) {
        uint16_t t = -s % s;
        while (l < t) {
            x = wyhash16();
            m = (uint32_t)x * (uint32_t)s;
            l = (uint16_t)m;
        }
    }
    return m >> 16;
}
```
英語原稿: https://lemire.me/blog/2019/07/03/a-fast-16-bit-random-number-generator/
Safariの表示でフォントサイズが変わってしまう

## 不具合の概要
HTMLタグの`::before`に対しCSSプロパティでcontentにテキスト、font-sizeに文字サイズを指定。
Google Chromeやその他OSでは意図した通りであったが、Safari版だけフォントサイズの指定が効かず小さく(検索すると大きく表示されるケースもある様子)表示されてしまう。

## 対処
cssに以下を追記

```css:css
-webkit-text-size-adjust: 100%;
``` 

## 参考にさせていただいた記事
[スマホページだけフォントサイズ指定がうまくいかない場合](https://myscreate.com/text-size-adjust/)
DependabotでTerraformのproviderのバージョンを上げる

DependabotがTerraformのproviderとmoduleに対応してました。
https://github.blog/changelog/2021-06-10-dependabot-now-supports-terraform-1-0/

以下のように設定することで、DependabotがPRを出してくれるようになります。

```yaml:.github/dependabot.yml
version: 2

updates:
  - package-ecosystem: terraform
    directory: /
    schedule:
      interval: monthly
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214526/10da7072-64b7-6fa2-aa6f-cc41a390ebc4.png)

`terraform init -upgrade` を実行して `.terraform.lock.hcl` を更新しなくてよくなるのが楽ですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214526/08ff3a70-0468-f20f-ed76-7bba5b6c1c8e.png)

Terraform Cloud等、Privateなmodule registryを使っている場合は、以下のように設定します。
`TOKEN` はSettings > Secrets > Dependabotから設定します。

```yaml:.github/dependabot.yml
version: 2

updates:
  - package-ecosystem: terraform
    directory: /
    schedule:
      interval: monthly
    registries:
      - terraform-cloud

registries:
  terraform-cloud:
    type: terraform-registry
    url: https://app.terraform.io
    token: ${{ secrets.TOKEN }}
```
テスト50

```vb

Option Explicit

Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)

'日報を送るときの時間別件名チェックサンプル
'(ThisOutlookSession)
'ﾒﾓﾒﾓφ(･ω･*)
'---------------------------------------------
'朝
If InStr(Item.Subject, "【○○】") > 0 _
And TimeValue(Now) >= TimeValue("8:30") _
And TimeValue(Now) <= TimeValue("9:30") Then

    If InStr(Item.Subject, "開始") > 0 Then
        '問題なければ送信
        Exit Sub
    
    Else
    
        MsgBox "件名が違っています。もう一度確認をお願いします。", vbCritical
        Cancel = True
        Exit Sub
        
    End If

End If

'---------------------------------------------
'昼
If InStr(Item.Subject, "【○○】") > 0 _
And TimeValue(Now) >= TimeValue("8:30") _
And TimeValue(Now) <= TimeValue("9:30") Then

    If InStr(Item.Subject, "開始") > 0 Then
        '問題なければ送信
        Exit Sub
    
    Else
    
        MsgBox "件名が違っています。もう一度確認をお願いします。", vbCritical
        Cancel = True
        Exit Sub
        
    End If

End If

'---------------------------------------------
'退社
If InStr(Item.Subject, "【○○】") > 0 _
And TimeValue(Now) >= TimeValue("8:30") _
And TimeValue(Now) <= TimeValue("9:30") Then

    If InStr(Item.Subject, "開始") > 0 Then
        '問題なければ送信
        Exit Sub
    
    Else
    
        MsgBox "件名が違っています。もう一度確認をお願いします。", vbCritical
        Cancel = True
        Exit Sub
        
    End If

End If

End Sub
【Githubエラー】you need to resolve your current index first

##状況

ブランチを切り替えようと思ったら下記のエラー

```
error: you need to resolve your current index first
```

##解決法

```
%　　git reset --merge
```

#### --mergeオプション
インデックスをリセットし、commitとHEADの間で異なるワークツリー内のファイルを更新しますが、インデックスとワークツリー間で異なるファイル（つまり、変更が追加されていないファイル）は保持します。commitとインデックスの間で異なるファイルにステージングされていない変更がある場合、リセットは中止されます。


##参考

https://tracpath.com/docs/git-reset/
FilezillaとAtomの連携方法

#動機
自宅から大学のサーバーに接続してプログラムを回したい。。
けどファイルをいちいちコマンドラインでSFTP経由移動するのはだるい。。
そこでFilezillaを使ってみるととても楽だったけど、せっかくなら直接ファイルを編集できればもっと便利なんじゃね？と思った次第。

#前提
クライアント:macOS Big Sur version 11.6
サーバー:Ubuntu 20.04.1

#インストール
###Filezilla
まずはFilezilla cliantとAtomをMacにインストール。
入れ方はその辺に転がってるサイトに従えば難なくいける。。ハズ

ただ、今回はFilezillaのサイトマネージャーからサーバーへ繋げるところで詰まった。

どうやら、プロトコルをSFTPにしないといけないみたい。よくわからないけどFTPより安全なのでヨシ。
また、ポート番号もSFTP用の22に設定する。

ちゃんとサーバーに接続できればOK.

###Atom
公式サイトを覗くと適切なバージョンを勝手に選んでくれる。優しいね。
いろんなサイトを参考にしてインストール。ついでに日本語化も行っておく。

#設定
この状態ではFilezillaでファイルを右クリック→表示/編集してもデフォルトでメモ帳が開いてしまう。
これをAtomにしようということ。

Mac左上のFilezilla→設定→ファイルの編集を選択。
「デフォルトのエディター」の項目から、「カスタムエディターを使用」に丸をつける。また、参照をクリックしてAtomのある場所を指定する。

次に、「常にデフォルトのエディターを使用」に丸をつける。

ちゃんとOKを押して画面を閉じる。

###おまけ
FIlezilla→設定→インターフェイス→ファイルリストを選択。
「ダブルクリックしたときのアクション」から、「ファイルをダブルクリックした時のアクション」のプルダウンを表示/選択に設定する。
こうしておけばファイルをダブルクリックですぐ編集できる。
AzureのRHEL８VMのディスク バックアップからのファイル回復方法について

## AzureのRHEL８VMのディスク バックアップからのファイル回復方法について

**RHEL8**のVMでOSディスク バックアップからファイルを復元したい時、同じVMからデータにアクセスする方法について説明します。

**Microsoft Marketplace**の**RHEL8**のイメージはLVMを使用して、構成は以下の通りです。

```
NAME              MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda                 8:0    0   64G  0 disk
├─sda1              8:1    0  500M  0 part /boot
├─sda2              8:2    0   63G  0 part
│ ├─rootvg-tmplv  253:0    0    2G  0 lvm  /tmp
│ ├─rootvg-usrlv  253:1    0   10G  0 lvm  /usr
│ ├─rootvg-homelv 253:2    0    1G  0 lvm  /home
│ ├─rootvg-varlv  253:3    0    8G  0 lvm  /var
│ └─rootvg-rootlv 253:4    0    2G  0 lvm  /
├─sda14             8:14   0    4M  0 part
└─sda15             8:15   0  495M  0 part /boot/efi
```

最初にディスク バックアップをVMに接続します。
元のOSディスクとディスク バックアップの構成が同じため、VGも同じです。
そのため以下のWARNINGが表示されます。ディスク バックアップ（/dev/sdd2)のVGのUUIDが元のディスク（/dev/sdb2)と同じとのことです。

```
# vgs
  WARNING: Not using device /dev/sdd2 for PV PdWL55-qIlK-A96n-2XJ9-D8bd-Svkk-FCMH8B.
  WARNING: PV PdWL55-qIlK-A96n-2XJ9-D8bd-Svkk-FCMH8B prefers device /dev/sda2 because device is used by LV.
  VG     #PV #LV #SN Attr   VSize   VFree
  rootvg   1   5   0 wz--n- <63.02g <40.02g
```

バックアップのVGを使うにはバックアップのVGをインポートする必要があります。VGをインポートするとVGの名前とUUIDが変わります。名前は指定できますので、rootvg_newにします。

```
# vgimportclone -n rootvg_new /dev/sdd2
  WARNING: Not using device /dev/sdd2 for PV PdWL55-qIlK-A96n-2XJ9-D8bd-Svkk-FCMH8B.
  WARNING: PV PdWL55-qIlK-A96n-2XJ9-D8bd-Svkk-FCMH8B prefers device /dev/sdb2 because device is used by LV.
# vgchange -ay rootvg_new
  5 logical volume(s) in volume group "rootvg_new" now active
# vgs
  VG         #PV #LV #SN Attr   VSize   VFree
  rootvg       1   5   0 wz--n- <63.02g <40.02g
  rootvg_new   1   5   0 wz--n- <63.02g <40.02g
 ```
 
 バックアップVG（rootvg_new)をアクティブにしてボリュームは使用できます。
 しかし、ファイルシステムをマウントするとまたエラーが発生します。

 ```
 # mkdir /backup
 # mount /dev/rootvg_new/rootlv /backup
mount: /backup: wrong fs type, bad option, bad superblock on /dev/mapper/rootvg_new-rootlv, missing codepage or helper program, or other error.
```

これはXFSファイルシステムもUUIDを使用しているからです。

元のVG（rootvg）とバックアップのVG（rootvg_new)のXFSファイルシステムのUUIDが同じということが問題です。

```
# blkid /dev/rootvg*/rootlv
/dev/rootvg_new/rootlv: UUID="9c542500-f63c-43ca-bdb9-90b000ecb9eb" BLOCK_SIZE="4096" TYPE="xfs"
/dev/rootvg/rootlv: UUID="9c542500-f63c-43ca-bdb9-90b000ecb9eb" BLOCK_SIZE="4096" TYPE="xfs"
```

その問題の解決方法は二つあります。

一つはマウントする時にnouuidオプションを使うことです。

```
# mount -o nouuid /dev/rootvg_new/rootlv /backup
# cat /backup/etc/redhat-release
Red Hat Enterprise Linux release 8.4 (Ootpa)
``` 

もう一つはコピーのファイルシステムのUUIDを変更することです。

```
# xfs_repair -L /dev/rootvg_new/rootlv
Phase 1 - find and verify superblock...
..
done
# xfs_admin -U $(uuidgen) /dev/rootvg_new/rootlv
Clearing log and setting UUID
writing all SBs
new UUID = d000e632-25c5-4cb2-a02e-40acf021bfe2
# mount /dev/rootvg_new/rootlv /backup
# cat /backup/etc/redhat-release
Red Hat Enterprise Linux release 8.4 (Ootpa)
``` 

どちらの方法を使ってもコピーのファイルシステムをマウントでき、ディスク バックアップのファイルをアクセスできます。

以上です。
HTMLで複数動画を連続再生する方法

[html単独動画の自動再生](#html単独動画の自動再生)
[html複数動画の自動再生](#html複数動画の自動再生)
[css複数動画を同時に表示しない](#css複数動画を同時に表示しない)
[jquery設定](#jquery設定)
[参考記事](#参考記事)

`目標`：WordPress内で複数動画を順次再生させる

#html単独動画の自動再生
表示させたいウェブページにHTML記述

```
<video id="video1" width="640" height="360" autoplay>
    <source src="＜動画URL＞.mp4">
</video>
```
`autoplay`：自動再生


#html複数動画の自動再生

```
<video id="video1" width="640" height="360" autoplay>
    <source src="＜動画1URL＞.mp4">
</video>
<video id="video2" width="640" height="360">
    <source src="＜動画2URL＞.mp4">
</video>
<video id="video3" width="640" height="360">
    <source src="＜動画3URL＞.mp4">
</video>
```

#css複数動画を同時に表示しない
子テーマ内style.cssで設定

```:&nbsp;#nbsp;vim/var/www/html/example.com/wp-content/themes/子テーマ/style.css
#video2, #video3 {
    display: none;
}
```

#jquery設定
###JQuery読み込み
<head>内に記述

```
<head>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>

</head>
```

###子テーマ内にディレクトリ`js`作成
その中に`video.js`作成
JQueryで最初の動画の終了をendedイベントで処理

```:&nbsp;#nbsp;vim/var/www/html/example.com/wp-content/themes/子テーマ/js/video.js
jQuery(function () {
    for (var i = 1; i <= 3; i++)
    {
        // 1
        (function() {
            // 2
            var nextIndex = (i != 3) ? (i + 1) : (1);
            var $nextVideo = $("#video" + nextIndex);
             
            // 3
            $("#video" + i).on("ended", function() {
                $(this).hide();
                $nextVideo.show();
                 
                $nextVideo.get(0).play();
            });
        })(i);
    }
});
```

WordPress内でJQuery設定をするときは、通常なら
`$(function () {`
とするところを、
`jQuery(function () {`
と記述


###functions.php設定

```:&nbsp;#nbsp;vim/var/www/html/example.com/wp-content/themes/子テーマ/functions.php
if (!is_admin()) {
   function register_script(){
        wp_register_script( 'video', get_stylesheet_directory_uri() . '/js/video.js', array( 'jquery' ), '', false);
        }
    function add_script() {
        register_script();
        wp_enqueue_script('video');
        }
    add_action('wp_enqueue_scripts', 'add_script');
}
```

***
#参考記事
`http://chicketen.blog.jp/archives/6539298.html`
`https://hsmt-web.com/blog/js-jquery-wp/`
`https://affiliate150.com/function-javascript`
sklearnのStratifiedKFoldの実装の注意点について

#コード
実装例は次のようになる。

```python
from sklearn import model_selection
import numpy as np
#説明変数X
X = np.array([['A','B'],['C','D'],['E','F'],['G','H']])

#目的変数y
y = np.array([0,0,1,1])

kf = model_selection.StratifiedKFold(n_splits = 2)

for fold,(train_index, test_index) in enumerate(kf.split(X=X,y=y)):
 print("kfold:",fold)
 print(f"train:{X[train_index]}")
 print(f"test:{X[test_index]}")
```

出力は次のようになる。

```python
kfold: 0
train:[['C' 'D']
 ['G' 'H']]
test:[['A' 'B']
 ['E' 'F']]
kfold: 1
train:[['A' 'B']
 ['E' 'F']]
test:[['C' 'D']
 ['G' 'H']]
```

#注意点
kf.splitの戻り値は渡したデータのインデックスであること。上のコードなら`k=0`のときtrainのインデックスは1,3で、testのインデックスは0,2である。

このインデックスを用いて目的変数を参照すると`y[1]=0,y[3]=1`かつ`y[0]=0,y[2]=1`であるのできちんと割合一定で分割ができていることが確認できる。

fold数は出力しないのでenumerate関数を用いてこちらで番号を付けている。

#参考にさせたいただいたサイト
[sklearnの交差検証の種類とその動作](https://qiita.com/chorome/items/54e99093050a9473a189)
[Python, enumerateの使い方: リストの要素とインデックスを取得](https://note.nkmk.me/python-enumerate-start/)