OmniAICreator/Qiita-1.07M huggingface dataset:
【Swift】Resourcesのjsonが読み込めなくなった時はこうしろ

SwiftUIのチュートリアルをやっていたらなぜかResourcesフォルダーにある
jsonファイルが読み込めなくなった時のレポ
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633746/532965fd-3eb8-55c5-efb4-da243defd282.png)
こんな感じでPreviewが表示されずに困った

## 解決策❶: ファイル追加時にResourcesに自動登録する

D&Dでファイルをプロジェクトに追加するときに
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633746/5ecb3a8d-bcab-1520-86c6-f1121fe2c16e.png)
`Add to targets:` にチェックを入れることでResourcesが自動で追加される
これを忘れると手動でやる羽目になる

## 解決策❷: 後から自力でResourcesを追加する

`project` をクリック
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633746/52fa23d7-008e-f97a-d149-d62a8fea7e91.png)
`Build Phases` をクリック
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633746/9c782acd-6f9f-c97d-36b0-6bf61c2cdc7b.png)
`Copy Bundle Resources (Any items)` をクリック![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633746/d1f7e124-0969-c411-a726-65c438547e01.png)
`+` を押して読み込ませたResourcesをAddする
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633746/f4c69c3c-6e34-afb0-20e5-6f733088f3cf.png)
表示できるようになる
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633746/8dac9da1-af5f-c6d2-9e3c-459f7b6db0af.png)
エスペラント語の単語を4択問題で効率的に覚えるためのコード

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

ここの20230330_4択問題完成.ipynbを実行する。
with open('形容詞_25個ごとに分割_1.csv') as csvfile:　のファイル名をフォルダ内にあるcsvファイル名(25個ごとに分割　という文言が入っているもの)　を入れて順次実行する。 1周目で間違った単語はincorrect_answers.txtに出力してくれ、全部正解するまで、何周もしてくれる。

25個ごとの単語のリストを変えたければ、
単語をランダムに25個ごとに分けてcsvファイルとして保存.ipynb　を実行する。



エスペラント日本語基本辞書から名f,動f,形f,名oを削除した上で、エスペラント重要語リスト(2400語)に載っていて、エスペラント日本語基本辞書に含まれていないものは、"漏れ"として追加した。計2860個。
これだけ覚えておけば、完璧なはず。
chatGPTには大変お世話になった。
NotionでAPI定義書やコーディングルールのテンプレートを作成しました。（その他PHPコーディングルール）

# はじめに

お久しぶりです。
前職の弁護士ドットコムを退社して、フリーランスとして働き始めたナミザトです。
最近コードを書くより、DX改善や設計、その他ドキュメントを書くことがほとんどになってきて、その都度、ツール毎にドキュメントを書くのめんどくさいなーと思うようになりました。

そこでNotionにあらかじめテンプレートを用意しておけば、最初から作る必要もないなーと思いテンプレートを作成しました。

# 概要

いま用意しているテンプレート

- APIルール
- API定義書
- PHPコーディングルール

今後用意していきたいテンプレート

- ERD
- PHPツール関連のハウトゥ
- 質問テンプレート

# Notion テンプレート

https://daily-potassium-d1f.notion.site/Namizato-Free-Template-9af38af589c04a7da5895fbe885fc104

## API定義書の使い方

まずは自分のNotionに複製します。
そして `API定義書` を開いてください。

![スクリーンショット 2023-03-30 16.59.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293438/01da564d-2231-3eff-df62-ae4c3ef30c86.png)

機能毎に格納する親要素とその子要素にエンドポイントを用意しています。


![スクリーンショット 2023-03-30 16.59.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293438/b3e8799c-78c2-f3a6-e12e-85a66c6d162b.png)

詳細を見てみると、このようにAPIのサンプルが入力されています。

![スクリーンショット 2023-03-30 17.00.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293438/acdcce88-3a3b-eb35-28b0-2398bc15713e.png)

自分で新たに作成する場合は、HTTPメソッド毎にテンプレートを用意しているので、新たに作成してください。

おわり
List.of()メソッドとArrays.asList()メソッドの違いについて(備忘録)

自分用にList.of()メソッドとArrays.asList()メソッドの違いについてまとめていきたいと思います。
  
```
 List<Integer> number = new ArrayList<>(Arrays.asList(A, B, C));   
```  
と   
```
 List<Integer> number = new ArrayList<>(List.of(A, B, C));  
```  
 上記の2つのコードは、両方とも要素がA、B、CであるArrayListを生成するための方法ですが、いくつかの違いがあります。  

## ①可変か不可変か    

・Arrays.asList() メソッドは、引数として渡された配列要素を含む可変長引数リストを返します。  
・ist.of() メソッドは、不変のリストを返します。  

つまり、List.of() メソッドは、返されたリストを変更しようとするとUnsupportedOperationExceptionがスローされる可能性があります。  
一方、Arrays.asList() メソッドで作成されたリストは、変更が可能であり、要素を追加、変更、削除することができます。  
  
## ②要素の数の制限  

・Arrays.asList()もList.of() メソッドも、引数として指定された要素の数に制限があります。  
&emsp;最大で255個の引数を受け取ることができます。  
&emsp;ただし、配列を引数で渡す場合はこの限りではありません。
  
## ③要素の変更・追加・削除  

・Arrays.asList()で作成されたリストは固定長配列のビューであるため、要素の変更はできますが、追加や削除はできません。  
・List.of()で作成されたリストは不変であるため、要素の変更、追加、削除はできません。  
```  
Integer A = 1, B = 2, C = 3;

// Arrays.asList()で作成されたリスト  
List<Integer> number1 = new ArrayList<>(Arrays.asList(A, B, C));  
number1.set(2, 4); //要素の変更は可能  
number1.add(5); //要素の追加はできない（UnsupportedOperationExceptionがスローされる）  
  
// List.of()で作成されたリスト  
List<Integer> number2 = new ArrayList<>(List.of(A, B, C));  
number2.set(2, 4); //要素の変更はできない（UnsupportedOperationExceptionがスローされる）  
number2.add(5); //要素の追加はできない（UnsupportedOperationExceptionがスローされる）  
```  

## ④まとめ  
簡潔ですがList.of()メソッドとArrays.asList()メソッドの違いについてまとめてみました。  
何か間違いや気になる点があればご指摘いただけると幸いです。
ペアプロアンチだった私が心を入れ替えた話

## この記事を書こうと思ったきっかけ

ペアプロをディスったQiitaをわざわざ書くくらいには複数人開発を嫌っていた私ですが、最近ペアプロをしている時に「あれ、なんか楽しいかも」と思ったので記事にしてみることにしました。
息抜きのお供にどうぞ。

## ペアプロが嫌いだった理由

「何もわからない新人と2,3年目の先輩」という組み合わせで開発をすると、どうしても先輩が新人に教える構図が出来上がります。当たり前なんですけどね。
分からないことがあればすぐに質問でき、適切な答えが返ってくる。最高ですね。
これは逆にいえば、「分からなければすぐに質問しなければならない」ということでもあります。せっかくペアプロをしているのに、新人が一人で考え込んでいては意味がないですから。
私はこれがどうも苦手でした。なぜなら、分からないことがあればまず自分で考えて、それでも分からなければ質問する、というのが私の理想だからです。
特に新人の時はわからないことが多すぎたので、ペアプロ中の会話のほとんどが質問と回答みたいな状態でした。
Qiitaにも書きましたが、問題を解く前に解答を見るような感じがしてモヤモヤしちゃってたわけです。

## なぜ嫌悪感が消えたのか？

ではなぜ「あれ、なんか楽しいかも」と思えるようになったのでしょうか。
理由はシンプル。質問の回数が減り、逆に意見を言えるようになったからです。
深掘っていきましょう。

### システムの仕様に関する理解が深まった

うちの場合は既存システムへの機能追加・修正が主な業務です。
なので、そもそもそのシステムをある程度理解していないとどこをどう修正すればいいかさっぱり分かりません。やりたいことは分かっていてもロジックを組めないわけです。
ペアプロが嫌いだった頃は「どのファイルのどこをどう修正すればいいか」を全て先輩に聞いていましたが、今では「こういう方法はどうですか？」と提案ができるようになりました。
言われるがままの開発から、当事者意識を持った開発にシフトチェンジできたわけですね。

### コーディング力がついた
これも大きいですね。
当時は、どうコーディングするかさえもほぼ聞いていました。「eachの後は、、do？パイプパイプ？」みたいなレベルです。
理解するだけで精一杯のロジックをプログラミング初心者がコードに起こすんですから、そりゃあ大変でした。
打って変わって今では、ロジックさえ決まればそれ通りにコーディングするのは難しくないくらいにはコーディング力がつきました。
こうしてコーディングに持っていかれる脳みその割合が減ったことで、他のことを考える余裕が生まれたわけです。

### メンバーと仲良くなった

シンプルですがめちゃくちゃ大事ですよね。
関係が浅いうちは、お互いにどこか遠慮してしまいがち。
意見があっても、「間違っていたら嫌だな」とか「先輩は私には見えていない何かを見据えてこうしているに違いない」とか考えてしまい、全く積極的になれていませんでした。
しかし時間と共に仲良し度がアップしたことで、些細なことでも意見や疑問をバンバン言えるようになり、より有意義にペアプロに取り組めるようになりました。

## 見えてきたペアプロの良さ

### ミスや手戻りを防げる

一人で開発する時よりも単純に目が多くなるので、些細なミスを防げるようになります。
また考える頭も増えるので、一人の時よりも多くの選択肢の中から最善策を選ぶことができます。これは大きな手戻りを防ぐことにつながりますね。
さらに、意見をぶつけ合っているうちに、全く別の解決策が思いつくこともあります。そう、シナジーまで生めちゃうんです。
### シンプルに勉強になる
私の場合、ペアプロをするときの相手は基本的に先輩です。
なので、先輩が書いているのを見るだけで「そんな書き方もできるんだ」と勉強になるし、自分のコードを指摘された時は「そういう観点でコードを読むんだな」「そんなことまで考える必要があるんだな」というように、開発をする上での心構えみたいなものを知ることができます。

# 最後に
まあ、一番好きなのは個人開発なんですけどね。

<br>
<br>

(ペアプロをディスったQiitaは[こちら](https://qiita.com/ueaaoe/items/40214bba75ac77df528a))
3/30 git part2

# 個人的リマインド用
変更を元に戻す、リモートリポジトリとのやりとり

## ファイルへの変更を取り消す
**git restore**
### ワークツリーでの変更を取り消す
```
git restore <ファイル名>

ステージの状態をワークツリーに反映させる
```
### ステージでの変更を元に戻す
```
git restore -S <ファイル名>

最新のコミットの状態をステージに反映させる
ワークツリーの状態が変わるわけではない
```
### 直前のコミットを消す
**※リモートリポジトリにプッシュしたら絶対にそのコミットの内容を修正してはいけない**
```
git restore -s HEAD^ <ファイル名>

一気にワークツリーまで落ちる(修正した部分も元に戻る)
```
### 直前のコミットをやり直す
コミットした後に、修正忘れに気づいたとき
```
git commit --amend

1.修正したものをステージまで持っていく
2.git commit --amendでcommitメッセージを修正
```
おまけ
```
git log -p -n 1 
ログで変更された部分の中身(-p)を最新のコミットだけ(-n 1)
```

## リモートリポジトリについて
### リモートリポジトリとは
オンライン上にあるリポジトリ(GitHub)

### リモートを表示する
```
git remote

git remote -v 対応するURLを表示
```
### リモートリポジトリを追加
**リモートリポジトリは複数登録することができる**
複数のチームそれぞれでリポジトリを持っている時とか

```
リモートリポジトリを新規追加
git remote add <リモート名>

git remote add tutorial https://github.com/user/repo.git
(tutorialというショートカットでurlのリモートリポジトリを登録)
```
### リモートから情報を取得する(フェッチ)
```
git fetch <リモート名>
git fetch origin

流れ：リモートリポジトリからローカルリポジトリに情報を落とす(ワークツリーには入っていない)
     ワークツリーに持ってくるならgit mergeをする
```
### リモートから情報を取得する(プル)
プル→リモートから情報を取得してマージまでを一度にやりたい時(fetchとmergeを一気にやる)
```
git pull <リモート名> <ブランチ名>
git pull origin master

git pull (origin masterは省略可能)
```
### フェッチとプルはどちらがいいのか
**基本はfetchを使うのがいい**
pullすると(リモート→ローカル→ワークツリー)自分が今いるブランチにマージされる
うっかり別ブランチにいる時やっちゃったら危険
mainにいる時だけやったらいいかも

### リモートの詳細情報を表示する
```
git remote show <リモート名>
git remoteより詳しく(fetchとpushのurl, リモートブランチ, git pullやgit pushの挙動)
```
### リモートを変更・削除
```
変更する
git remote rename <旧リモート名> <新リモート名>
git remote rename tutorial new_tutorial
```
```
削除する
git remote rm <リモート名>
git remote rm new_tutorial
```
数学オリンピックの問題をC#で

すみません。つぎの[Youtube動画](https://youtu.be/69LEUObcRQ0)で紹介されていた問題で、こたえについても`JAVA`でかかれていたものを、`c#`にしただけです。

問題は、
$ab+c=2020$, $a+bc=2021$
を満たす正の整数$a$,$b$,$c$求めてねってもの。

c#で書いたコードは以下の通り.
整数型は、キャレット(^)使えないっていわれた。
```
for(int i = 1; i <= 2021; i++){
    for(int ii = 1; ii <= 2021; ii++){
        if(i+2020*ii-i*ii*ii==2021)
        {
            Console.Write("a=");
            Console.Write(i.ToString());
            Console.Write(", b=");
            Console.Write(ii.ToString());
            Console.Write(", c=");
            Console.WriteLine((2020-i*ii).ToString());
         }
        }
  
}
```
こたえは、$a = 673$, $b=2$, $c=674$....
curlでhostsファイルを書き換えずに名前解決する

ローカル環境やテスト環境にホスト名やドメイン名でアクセスしたい場合、`hosts`ファイルに設定を書き加えることがよくありますが、curlでちょっと確認したいだけといった場合は、いちいち`hosts`ファイルを書き換えなくても、`--resolve`オプションで指定できます。

`hosts`ファイルを書き換える例:

```text:/etc/hosts
# ローカルホストをmyapp.example.comでアクセスできるようにする
127.0.0.1       localhost myapp.example.com

# 開発用のVMをfoobar.example.comでアクセスできるようにする
192.168.56.123  foobar.example.com
```

## `--resolve`オプション

curlの`--resolve`オプションを使用すると、その場限りでマッピングを指定できます。

```
--resolve ホスト名:ポート番号:IPアドレス
```

例えばローカルホストに`http://myapp.example.com`でアクセスしたい場合、次のようにします。

```console
$ curl -v --resolve myapp.example.com:80:127.0.0.1 http://myapp.example.com
```

今回は`-v`オプションを指定したので、どのような処理が行われているのか確認してみましょう。

```
* Added myapp.example.com:80:127.0.0.1 to DNS cache
* Hostname myapp.example.com was found in DNS cache
*   Trying 127.0.0.1:80...
* Connected to myapp.example.com (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: myapp.example.com
> User-Agent: curl/7.79.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Server: SimpleHTTP/0.6 Python/3.9.6
< Date: Thu, 30 Mar 2023 06:50:49 GMT
< Content-type: text/html; charset=utf-8
< Content-Length: 1304
<
以下レスポンスボディ
```

`myapp.example.com`として処理しつつも`127.0.0.1`に接続していることがわかると思います。

先頭2行を見た感じ、curlの持つDNSキャッシュにエントリを追加する、みたいな仕組みなんですかね（詳しい実装内容は知りません）。

## どのような場合に使うのか

例に挙げたような開発環境の場合は、ブラウザでアクセスしたいことも多いと思うので、結局`hosts`ファイルを書き換えることになるのですが、例えば次のようなケースで有用だったりします。

- テスト環境のサーバーに本番環境のドメイン名でアクセスする
- サーバー移転やドメイン切り替え時に、（DNSを実際に切り替える前に）切り替え後の場合のアクセスを確認する
- CDNやProxy等を経由せずに直接アクセスして検証する
- TLSのSNI(Server Name Indication)の動作確認

## Hostヘッダではダメなこともある

ところで、こんな難しいオプションを使わなくても、次のように`Host`ヘッダを指定すればいいのでは？　と思うかもしれません。

```console
$ curl --header 'Host: myapp.example.com' http://127.0.0.1/
```

HTTPの場合は実はこれでも大丈夫なことが多いです。
ですが、HTTPSでSNI(Server Name Indication)を使用している場合は、TLSハンドシェイクの時点でホスト名を指定する必要があるため、HTTPヘッダではダメなのです（HTTPヘッダはTLS接続後の話なので）。
WSLで 0x80040326 エラー → 黙って wsl --update

# 症状

WSL2 が起動してくれません。

```
Error: 0x80040326
Error code: Wsl/Service/0x80040326
```

# 解決

突然今朝こうなったので何が原因かはわかりませんが…
[StackOverflow](https://stackoverflow.com/questions/75883240/ubuntu-crashes-on-windows-0x80040326-wsl-error) や [はてブロ](https://akiki0106.hatenablog.com/entry/2023/03/30/114624) でも紹介されてますが、こうしたら解決しました。謎すぎます…。

```PowerShell
wsl --update
```
ブックマークを別のPCや別のブラウザに移行する方法

## はじめに

よく使うサイトやページをブックマークしてすぐ開けるようにしていますよね。
PCを買い替えたり、使用するブラウザを変更した際にも同じブックマークをすぐ使える方法を紹介します！！

今回はGoogleからEdgeへの移行手順をメインとして記載していきます。

## 移行手順

1. 3点リーダーの設定から**ブックマーク**⇒**ブックマークマネージャー**を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100940/fdc5845b-24c0-f615-3781-70ed5a40f400.png)

2. 検索窓の横の3点リーダーから**ブックマークをエクスポート**を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100940/67101dbf-6daf-a491-db96-fdea78796f52.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100940/f6b2e0e6-8913-3687-6597-f3e86315e680.png)

3.htmlファイルが生成されるので自分のPCに保存

4.別のPCに移行する場合は3.のhtmlファイルをドライブなどに保管しておいて、2.の**ブックマークをインポート**を選択して、保存したhtmlファイルをインポートする。

5.別のブラウザ（ここではEdgeを対象）へ移行の場合は、お気に入りの3点リーダーから**お気に入りをインポートする**を選択して、3.のhtmlファイルをインポートする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100940/da49778f-3075-2a94-eec6-137e2d737081.png)




以上で、今までと同じブックマークを別のPCやブラウザですぐに使うことができます。
とても簡単なので是非やってみてくださいね！
Organization でプライベートな GitHub Action を作成してみた

Organization でプライベートな GitHub Action を試しに作成してみた記録です。

## 前提

Ubuntu 20.04 に Docker がインストールされている([Zscaler 環境下で作る WSL2(Ubuntu 20.04) + Docker 環境](2022-10-28_Docker_WSL2_Zscaler_5a04a732524c72ff809a.md))。

## nektos/act のインストール

ローカルでワークフローの try&failure が出来るように[nektos/act](https://github.com/nektos/act)を導入しておきます。

各種パッケージマネージャーに対応していますが、apt に対応していないので手動でインストールしました。

```bash
# インストール
$ cd ~
$ curl -s https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash
nektos/act info checking GitHub for latest tag
nektos/act info found version: 0.2.43 for v0.2.43/Linux/x86_64
nektos/act info installed ./bin/act
```

## Hello GitHub Action

### プライベートトリポジトリを準備する

デフォルトではプライベートリポジトリの Action は同一オーナーであっても他のリポジトリから使えないようになっているので、プライベートリポジトリの設定を更新しておきます。

Settings->Actions->General の一番下に Access というセクションがあります。

![2023-03-30-08-48-40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435938/53437e19-8ebb-1972-a796-cf82d599d7df.png)

Accessible from repositories in the '\<Organization名\>' を選択し、 Save をクリックして設定を保存します。
なお、個人リポジトリの場合はここの文言は Accessible from repositories owned by the user '\<ユーザー名\>' になります。

### 最低限のファイルを作成する

[Docker コンテナーのアクションを作成する](https://docs.github.com/ja/actions/creating-actions/creating-a-docker-container-action)を参考に最低限のファイルを作成します。

- Dockerfile
- action.yml
- entrypoint.sh

また、`entrypoint.sh`には実行権限を付与しておきます。

```bash
$ chmod a+x entrypoint.sh
```

### ローカルで動作確認する

1. ワークフローファイル(`.github/workflows/main.yml`)を記述する(ポイントは★印を付けている部分です)

   `yml
   on: [push]

   jobs:
   hello_world_job:
       runs-on: ubuntu-latest
       name: A job to say hello
       steps:
      # (★)docker cp src=<local> dst=<container>が行われる
      - name: Checkout
        uses: actions/checkout@v3
        with:
          repository: <ユーザー名>/<リポジトリ名>
       - name: Hello world action step
           id: hello
           uses: ./ # (★)localからコピーされたリソースを元にactionが実行される
           with:
            who-to-greet: 'Mona the Octocat'
       # Use the output from the `hello` step
       - name: Get the output time
           run: echo "The time was ${{ steps.hello.outputs.time }}"
   `

2. シークレットを指定して実行する
   `bash
   $ act push -s GITHUB_TOKEN=<GITHUB_TOKEN>
   `

### 作成した Action をコミットしてプッシュします

```bash
$ git add action.yml entrypoint.sh Dockerfile
$ git update-index --chmod=+x entrypoint.sh
git commit -m "My first action is ready"
git tag -a -m "My first action release" v0.0.1
git push --follow-tags
```

## 参考

- [Docker コンテナーのアクションを作成する](https://docs.github.com/ja/actions/creating-actions/creating-a-docker-container-action)
- [nektos/act](https://github.com/nektos/act)
GitHub プライベートリポジトリアクセス

**概要**
GitHubのプライベートリポジトリへアクセスする場合、ssh or トークン認証が必要になるので
以下のどちらかの設定をgitコマンドで行う。

sshの場合([sshは別途秘密鍵/公開鍵をセットする必要があります](https://qiita.com/shizuma/items/2b2f873a0034839e47ce))
```shell
git config --global "url.ssh://git@github.com.insteadof https://github.com"
```

トークンの場合
```shell
git config --global "url.https://oauth2:(トークン)@github.com/(organization).insteadOf https://github.com/(organization)"
```
Error code: Wsl/Service/CreateInstance/0x80040326【Error: 0x80040326】

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3127414/4c982360-6b5b-1113-6130-62af4eb16725.png)

WSLを更新しましょう

```powershell
PS C:\Users\wsl-user> wsl --update
更新プログラムを確認しています。
Linux 用 Windows サブシステムを更新しています。
PS C:\Users\wsl-user> wsl --shutdown
```

https://akiki0106.hatenablog.com/entry/2023/03/30/114624

https://stackoverflow.com/questions/75883240/ubuntu-crashes-on-windows-0x80040326-wsl-error
【備忘録】ポートがすでに使われている場合の対応

# はじめに
　Laravelで開発を始めようとしたところ、8000番のポートがすでに使われていると怒られてしまったので、対応内容を備忘録。

# 状況
```terminal
% php artisan serve
// Failed to listen on 127.0.0.1:8000 (reason: Address already in use)
// PHP 8.2.4 Development Server (http://127.0.0.1:8001) started
```
　8000番を使おうとしたけど、すでに使われていたから、代わりに8001番を使っといたよ、という内容。前回使用時にプロセスを適切に終了出来てなかった様子。
　開発するにあたっては特に問題なく作動していたが、気持ち悪いので8000番のプロセスを終了したい。

# 進行中のプロセスの調べ方
　特定のポートを調べたい場合
```terminal
% lsof -i:[Port number]
```
　プロセス一覧を取得したい場合
```terminal
% ps -f
```

# プロセスの終了
　上記コマンドにより、PIDが取得できたので、下記コマンドによりプロセスの強制終了
```terminal
% kill -9 [PID]
```

# まとめ
　初心者として勉強中なので、アドバイス、ご指摘等あればよろしくお願いします。
Jenkinsの公開鍵のアップデート

Jenkinsをyumでupdateしようとしたところ、公開鍵がないと言われてこけたので、ざっくり調べた解決策だとうまくいかず（ファイルが違っていた）、本家ブログまで見に行ったら鍵を新しくしたよと書いてあったので解決しました。

当該ブログ：[Jenkins 2.397 and 2.387.2: New Linux Repository Signing Keys](https://www.jenkins.io/blog/2023/03/27/repository-signing-keys-changing/)

2日前に変更されてたらしい。マジか。
【AWS】Lambda Layersで共通関数活用

Lambda Layerということは、複数のLambda関数でライブラリを共有できる仕組みです。
複数のLambda関数は処理を行う前に、Lambda Layerのライブラリを呼び出してから、処理を実行することはできます。
現在、サーバーレス開発が進んでおり、CloudWatch Logsへログを出力していますが、出力する際の規定は無い為、既存の監視システムで処理するのは大変で、既存監視システムの仕様を踏まえてCloudWatch Logsへ出力する共通モジュールを作成し、各業務Lambda処理結果を出力してもらう形で対応することを想定しています。

■構成図
![kannsiイル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600067/599d56f1-a63a-13cd-7e30-ded18b998fe1.png)

■設計
① 業務バッチLambda毎に、CloudWatch Logs書込み共通処理をレイヤーを参照し、レイヤー関数経由にてCloudWatch Logsへ業務バッチ処理結果を出力する
② 出力先のCloudWatch Logsロググループは構成毎に出力する
③ 開始終了監視業務Lambdaにて、定時に該当条件の結果を取得して判断し、結果をメールにて通知する
④ エラー監視は、サブスクリプションフィルターを使用し、指定文字を検知した際に監視業務Lambdaを起動、リアルタイムにメール通知を行う

■処理後のログ（綺麗に出力されている）
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600067/6f29bd53-ddf9-82e4-24e9-9a41f8260bd5.png)

■まとめ
設計の通り実装して実現できましたが、以下の懸念事項があり、継続で改善方法を探しています。
・CloudWatch Logsへのログ出力の際、出力タイミングについては、AWS側で保証していない為、書込みまでにラグが発生する可能性がある
・監視側で取得する際に、取得できない可能性もある為、監視時間はある程度開ける必要がある
Pythonのstr.splitは短い時間に大量に呼んではならない

## splitの仕様確認

`aaaa#bbbb#cccc`のように、文字列を任意の区切り文字（例の場合`#`が区切り文字）で分割し、分割した文字列に対して何かしらの処理を行いたい場合に、`str.split`の利用がまず思いつきます。

```python
s = "aaaa#bbbb#cccc"
s_list = s.split("#")
print(s_list)
# ['aaaa', 'bbbb', 'cccc']
```

`str.split`のリファレンスを読むと、`maxsplit`を使うことで、分割数を指定できるらしいです。戻り値であるリストの長さは最大で`maxsplit+1`になります。

> **str.split(sep=None, maxsplit=- 1)**
> --
> 文字列を sep をデリミタ文字列として区切った単語のリストを返します。maxsplit が与えられていれば、最大で maxsplit 回分割されます (つまり、リストは最大 maxsplit+1 要素になります)。 maxsplit が与えられないか -1 なら、分割の回数に制限はありません (可能なだけ分割されます)。

https://docs.python.org/ja/3.10/library/stdtypes.html#str.split

つまり、`maxsplit=1`の場合、例で挙げた文字列は`aaaa`と`bbbb#cccc`に分割されることになります。`maxsplit=2`の場合`aaaa`と`bbbb`と`cccc`に分割されます。

では、`maxplit`を使いたくなる場面はどんな場面でしょうか？私がまず思いつくのは、splitするデータが後からどんどん追加されていく状況です。例えば文字列の方が別スレッドで外部から受信したデータになっていて、処理スレッド側で逐次セパレータで分割して1件ずつ処理するようなプログラムを実装する必要がある場合です。そんなときは、次のようなプログラムを書きたくなります。

```python
while True:
    # データを受信してbuffの末尾に追加
    buff += recv_data()
    # 処理対象データdataとそれ以外buffに分割
    data, buff = buff.split(sep, maxsplit=1)
    # 何かしらの処理
    process(data)
```

ただし、文字列比較などの文字列操作はアルゴリズムによりますが一般に重たい処理です。`buff`が長くなればなるほど`split`の処理に時間がかかってくることが想定されるので、処理するデータの内容によっては意図せず時間のかかる処理を何度も実行してしまう可能性があります。こんな実装をしてしまって処理時間は大丈夫なのでしょうか。

というわけで、実験してみました。

## 実験

```python
import time

class Counter:
    cnt = 0

    def process(self, split_str):
        self.cnt += 1

def generate(length, sep):
    buff = "0123456789"
    for i in range(length - 1):
        buff += sep
        buff += "0123456789"
    return buff

if __name__ == "__main__":

    length = 100000
    sep = "#"

    print("--- 手法1 ------------")
    counter = Counter()
    buff = generate(length, sep)
    t_start = time.time()
    for _ in range(length - 1):
        split_str, buff = buff.split(sep, maxsplit=1)
        counter.process(split_str)
    counter.count(buff)
    t_end = time.time()

    print(f"processが呼ばれた回数: {counter.cnt} 回")
    print(f"実行時間: {t_end - t_start} 秒")

    print("--- 手法2 ------------")
    counter = Counter()
    buff = generate(length, sep)
    t_start = time.time()
    split_str_list = buff.split(sep)
    for split_str in split_str_list:
        counter.process(split_str)
    t_end = time.time()

    print(f"processが呼ばれた回数: {counter.cnt} 回")
    print(f"実行時間: {t_end - t_start} 秒")
```

`Counter`は`split_str`にないかしらの処理をさせる想定のクラスです。実験ではとりあえず関数が呼ばれた回数をカウントしています。

また、手法1は`maxsplit`を利用して1回の分割をセパレータの個数回実行する方法、手法2は`maxplist`を利用せずセパレータ個+1の分割を1回だけ実行する方法です。

## 実験結果

```
--- 手法1 ------------
processが呼ばれた回数: 100000 回
実行時間: 3.0889523029327393 秒
--- 手法2 ------------
processが呼ばれた回数: 100000 回
実行時間: 0.022452116012573242 秒
```

見ての通りで、splitをセパレータの個数回呼んだ場合、セパレータで一括分割した場合に比べて100倍以上の時間がかかることがわかりました。予想よりも時間の差が大きいことがわかりました。

## おわりに

実際には1ループの処理時間のオーバヘッドは大したことがありませんが、ループが短い時間にたくさん回る場合で、性能要件が厳しい場合は、面倒くさがらずに`split`の回数を減らすよう注意したほうがよさそうです。

`maxsplit`は使うべきではない！とまではいいませんが、個人的にはどういう場面で`maxsplit`を使うのかよくわからなくなりました。。。
Vimを少しやってみる

## はじめに
Vimは度々聞くけど触ったことがなかったので手探りで触って初心者用のまとめになります。

## Vimって何？
一言でいうと、高機能なメモ帳(らしい)。

## どうやって使うの？
コマンドラインにて`vim`と打てば使える
- Mac
だいたい全部動く

- Windows
○:GitBash
×:コマンドプロンプト,PowerShell

- Linux
○:Ubuntu

今回はGitBashを使用する。

どこのディレクトリでもよいのでvimと打って以下の画像のように出れば大丈夫

```
vim
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2706288/f8dbb09a-ec23-65f0-53f0-10f98ea5d4e1.png)

Vimから抜ける
```
:q
```

## ファイルを少し操作してみる

vimで特定のファイルを開くときには`vim [ファイル名]`
```
mkdir vim
cd vim
touch test.txt
vim test.txt
```
vimでファイルは開けたけど操作ができない！
→VimにはいくつかモードがあってデフォルトはNormal Mode(閲覧のみ)になっているため

###  Insert Mode
Normal Modeで`i`を押すとInsert Mode(編集可能)になる
下の画像のように --INSERT--の文字が見えれば大丈夫
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2706288/61bf75ec-49b9-3ba2-43c4-32da917403cb.png)

`ESCキー`でNormal Modeに戻る

Normal Modeで`:w`を押すと変更が保存される
`:w`でエラーが起きた場合は`:w !sudo tee %`を使用してください

編集画面の強制終了は`:q!`を使用してください

### Command Line Mode

`:`というのはNormal ModeからCommand Line Mode(コマンドのみ打てる)に切り替えるためのものであり、`:q`や`:w`などはCommand Line Modeに切り替えてからコマンドを打っているという意味になる。

### Visual Mode
Normal Modeの状態で`v`を押すとVisual Mode(範囲選択できる)に移行する
`ESCキー`でNormal Modeに戻る

基本的にはここまでで操作の流れは終了になりますがさらにコマンドを覚えることでより編集などを加速させることができるのがVimの利点(らしい)なのでVimをさらに知りたい方は以下リンクにてコマンドを叩いてみるといいかもしれないです。

https://qiita.com/hide/items/5bfe5b322872c61a6896
【メモ】Docker DesktopからColimaに乗り換える

# 乗り換える


```bash
# Docker for Macを消す
# brewでdockerdesktopをinstallしてなかったらhttps://docs.docker.com/desktop/uninstall/をみてアンインストール
brew uninstall --casks docker
```

colimaインストール

```bash
# docker と docker-composeも必要なのでもし入ってないなら一緒にいれる
brew install colima docker docker-compose
```

起動

```
colima start
```

[その他オプションは公式みる](https://github.com/abiosoft/colima)

あとはdocker,docker-composeを利用する
以下のエラーでたら

```
[+] Running 0/0
 ⠋ xxx Pulling                                                        0.0s 
error getting credentials - err: docker-credential-desktop resolves to executable in current directory (./docker-credential-desktop), out: ``
```

configを消す

```bash
rm ~/.docker/config.json
```

## ColimaでもBuildxをつかう

こちらより

https://github.com/abiosoft/colima/discussions/273


```
brew install docker-buildx
mkdir ~/.docker/cli-plugins
ln -sfn $(which docker-buildx) ~/.docker/cli-plugins/docker-buildx
docker buildx install
```
QUERY関数で任意のデータを取得したい

## QUERY関数って便利だね

### はじめに

この記事ではスプレッドシートのQUERY関数について触れていきます。

### きっかけ・課題


![レビュー管理台帳-のコピー-Google-スプレッドシート (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1648958/b31cf351-7ff4-b124-6781-896eae53c210.png)

上記のような表を複数人で更新する作業があり、
こちらに案件を各々で記載してレビューを依頼する運用なのですが、、、、
　



「来週何件記載があるのか直観的にわからない！！！！」:sob:
日付の並びもバラバラに記載されたりして、週ごとの件数が分かりにくくなるという問題がありました。

今週は何件、来週は何件とすぐわかるようにしたい！！！！！！
　
### いざ実践！！
QUERY関数を使って、見たいデータのみ勝手に抽出してくれるようにしていきます！

まず、別シートを作り任意の箇所に下記の記載をしてみます。
第1引数に取得したいシートのデータ範囲を指定し、
第2引数でSELECT句を使って取得したい列を指定しています。
`=QUERY('一覧'!$A1:$H500,"SELECT A,B,C,D,E,F,G")`

結果は
![レビュー管理台帳-のコピー-Google-スプレッドシート (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1648958/7af56bd0-ae16-14ec-455c-87ac06742f4f.png)

一覧のシートの情報をA～G列分とってこれました。



続きまして～
来週の情報のみを取得してみたいと思います。
本記事を記載している現在の日付が2023/3/29なので
来週は月曜始点で4/3～4/9の情報が欲しい！！

先ほどの関数にWhere句を足していきます。
一覧シートのB列が日付を入力する列なので
B列の値が4/3より後で4/9より前のものという条件を追加。
`=QUERY('一覧'!$A1:$H500,"SELECT A,B,C,D,E,F,G WHERE B >= date '2023-4-3' AND B <= date '2023-4-9'")`

結果は
![レビュー管理台帳-のコピー-Google-スプレッドシート (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1648958/68a98d86-6616-3383-eca6-fa83eaa7c0b0.png)

取れました！


（あれ、、でもこれわざわざ書いてたら余計時間かかるんじゃ、、、）


更に手を加えていきます。
別途TODAY関数とWEEKDAY関数を組み合わせて
今週、来週、再来週を自動で取得する表をあらかじめ作っておきます。

・今週初め`=TODAY()-WEEKDAY(TODAY(),2)+1`
・今週終わり`=TODAY()-WEEKDAY(TODAY(),2)+7`

・来週初め`=TODAY()-WEEKDAY(TODAY(),2)+8`
・来週終わり`=TODAY()-WEEKDAY(TODAY(),2)+14`

こんな感じ
![レビュー管理台帳-のコピー-Google-スプレッドシート (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1648958/616e1bcc-a7e3-7b8f-7cfb-8e8d2264d5ff.png)


準備は整いました。
では仕上げです！

先ほどは日付を直書きしていましたがセル参照にします。
TODAY関数さんたちが勝手に週を切り替えてくれるので、いつ見ても来週の情報が取得できるようになりました！
`=QUERY('一覧'!$A1:$I504,"SELECT A,B,C,D,E,F,G WHERE B >= date '"&TEXT(X13,"YYYY-MM-DD")&"' AND B <= date '"&TEXT(Y13,"YYYY-MM-DD")&"'")`

各週の表を作成してみた結果がこちら
![レビュー管理台帳-のコピー-Google-スプレッドシート (7).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1648958/b44b754e-bac3-91ac-68c4-5ef20f597636.png)

改めて元の一覧はこちら
![レビュー管理台帳-のコピー-Google-スプレッドシート (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1648958/b31cf351-7ff4-b124-6781-896eae53c210.png)

一目瞭然になりました！！！！！！:point_up::point_up:




### おわりに
データベース触ったことがある方はとっつきやすい関数だと感じました。
今回はWhere句の日付はあらかじめ決め打ちした期間を表で作成して指定しましたが
「閲覧したい日付を入力してください」みたいな項目作って閲覧者が自由に期間設定できる形にしても良いなぁと思いました。


### 参考資料
出典：いつも隣にITのお仕事　（最終閲覧日：2023年3月25日）
https://tonari-it.com/spreadsheet-query-where-date/
分割、配列の削除、拡張子の削除を組み合わせてファイル名から必要な部分を取得するPowerShellコマンドレット

```# ファイル名を指定
$fileName = "example_file_name.txt"

# ファイル名を"_"で分割
$fileParts = $fileName -split '_'

# 最初の配列を削除
$fileParts = $fileParts[1..($fileParts.Count - 1)]

# 拡張子を削除
$fileParts[-1] = $fileParts[-1] -replace "\.[^.]+$", ""

# 必要な部分を取得
$result = $fileParts -join "_"

# 結果を表示
Write-Output $result
```
テキストファイルに記載された文字列をExcelから検索して、隣のセルの値を取得するプログラムをpowershellで書く

```# 検索する文字列を指定
$searchString = "検索する文字列"

# Excelファイルのパスを指定
$excelFilePath = "C:\path\to\your\excel\file.xlsx"

# Excelオブジェクトの作成
$excel = New-Object -ComObject Excel.Application

# Excelファイルを開く
$workbook = $excel.Workbooks.Open($excelFilePath)

# 検索を実行するシートを指定
$worksheet = $workbook.Sheets.Item("Sheet1")

# テキストファイルのパスを指定
$textFilePath = "C:\path\to\your\text\file.txt"

# テキストファイルを読み込み、行ごとに処理
Get-Content $textFilePath | ForEach-Object {
    # 行の中に検索文字列がある場合
    if ($_ -match $searchString) {
        # 検索文字列が含まれる列の値を取得
        $cellValue = $worksheet.Cells.Item($_.Split(",")[1], $_.Split(",")[2]).Value2
        Write-Output "検索文字列: $searchString が見つかりました。値: $cellValue"
    }
}

# Excelファイルを閉じる
$workbook.Close($false)

# Excelオブジェクトを解放する
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($worksheet) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($workbook) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel) | Out-Null
Remove-Variable excel
```
maya python dump ass transform

https://github.com/aizwellenstan/maya_python_ass

```python
import pymel.core as pm
import json
import sys
import os

def ReplaceAssPath(assPath):
    # Define the directory where the asset files are located
    asset_dir = "J:/xkx/work/lib/asset/PR/"
    if asset_dir in assPath: return assPath
    assName = standin.dso.get().split("/")[-1].split("_")[-1].split(".")[0]

    assDir = asset_dir + assName + "Night/shd/ass/"
    if not os.path.isdir(assDir): 
        assDir = asset_dir + assName + "/shd/ass/"
        if not os.path.isdir(assDir): 
            if assDir in missing: return assPath
            missing.append(assDir)
            return assPath
    else:
        # Find the latest version folder
        version = max([f for f in os.listdir(assDir) if f.startswith("v")])
    
        # Create the file path using the latest version
        assPath = "%s%sNight/shd/ass/%s/PR%sNight_shd_%s.ass" % (asset_dir, assName, version, assName, version)
        standin.dso.set(assPath)
    return assPath

standins = pm.ls(type='aiStandIn')
standinTransforms = [pm.listRelatives(standin, parent=True, f=True)[0] for standin in standins]

assXYZ = {}
missing = []
for standin, transform in zip(standins, standinTransforms):
    xformDict = {}
    xformDict['tx'] = transform.tx.get()
    xformDict['ty'] = transform.ty.get()
    xformDict['tz'] = transform.tz.get()
    xformDict['rx'] = transform.rx.get()
    xformDict['ry'] = transform.ry.get()
    xformDict['rz'] = transform.rz.get()
    xformDict['sx'] = transform.sx.get()
    xformDict['sy'] = transform.sy.get()
    xformDict['sz'] = transform.sz.get()

    # Get the asset name from the standin file path
    assPath = standin.dso.get()
    # assPath = ReplaceAssPath(standin.dso.get())
    nodeName = transform.name()
    if assPath not in assXYZ:
        assXYZ[assPath] = {}
    assXYZ[assPath][nodeName] = xformDict

json_str = json.dumps(assXYZ, indent=4)
with open('D:/assXYZ.json', 'w') as f:
    json.dump(assXYZ, f, indent=4)

```
Rocket Push 開発環境

## 本体
- 開発環境では、localhost:3000で立ち上げることを想定
- オプトイン取得やプッシュ配信は全てキューに入ってくるので、実行したい場合はコンソールから`bundle exec sidekiq -C config/sidekiq.yml` を実行

## rocket-push-cdn
- 開発環境でmain.jsやサービスワーカの動きを確認するためのデモサイト
- localhost:4000で立ち上げることを想定
- application.html.erbで読み込むスクリプトを指定している

### main.js
- public/main.jsを読み込み
- 本番環境か開発環境かは、isProductionの値を変更することで定義

### serviceworker
- public/firebase-messaging-sw.jsを読み込み
- 本番環境でのサービスワーカ本体は、`importScripts('https://cdn.rocket-push.com/firebase-messaging-sw.js')` という記述があるのみ
- https://cdn.rocket-push.com/firebase-messaging-sw.js の中に書かれているソースを開発環境ではいじっていく
- 本番か開発かは、`forProduction` の値を変えることで変更

### sitepush.js
- public/sitepush.jsを読み込み

### cv.js
- public/cv.jsを読み込み

### manifest.json
- public/manifest.jsonを読み込み
python maya reload ass

```python
import pymel.core as pm
standins = [i for i in pm.ls(type='aiStandIn')]
standinTransforms = [pm.listRelatives(i, parent=True, f=True)[0] for i in standins]

assPath = {i: i.dso.get() for i in standins}

for standin, path in assPath.items():
    standin.dso.set(path)
```
Googleフォトの写真を別アカウントに移行する際の注意点と解決用スクリプト

エンジニアの技術と直接関係のある記事ではないのですが、途中でPoiwershellを使ったりするので備忘録として残します。

# 今回の手順
おそらくいろいろやり方があるのでしょうが、今回は単純にバックアップリストアをする方法です。
今回のバックアップは以下の手順で行いました。

1. 旧アカウントのGoogleフォトからデータをエクスポート
2. エクスポートした画像があるフォルダを新アカウントのGoogleフォトに紐づけて同期させる

本題は注意点なので、手順の説明はしません。

# 注意点
どういうわけか、`2. エクスポートした画像を新アカウントのGoogleフォトに紐づけて同期させる`を行うと画像の日時がすべて`エクスポートした日時`になります。

# 解決方法
これでは不便なのでPowershellで解決します。

```Adjust.ps1
function GPhoto-Adjust ([Switch]$HideDetails = $false) {
    # カレンとディレクトリのjsonファイルを再帰的に探索
    forEach($file in (Get-ChildItem -Recurse | Where-Object {$_.Extension -eq '.json'})){

        # jsonに対応する画像(動画)ファイルの有無を確認
        $picPath = $file.FullName.Substring(0, $file.FullName.Length - 5)
        if (-not (Test-Path $picPath -PathType Leaf)) {
            continue
        }

        # jsonに対応する画像(動画)ファイルを取得
        $pic = Get-Item $picPath

        # jsonをパース
        $json = Get-Content $file.FullName -Raw -Encoding UTF8 | ConvertFrom-Json
    
        # 画面に変更前の作成日時を出力
        if (-not $HideDetails) {
            Write-Host -NoNewline "$($pic.FullName)`t"
            Write-Host -NoNewline -ForegroundColor Yellow "$($pic.CreationTime)"
            Write-Host -NoNewline ' -> '
        }
    
        # 作成日時と更新日時をメタデータから変更する
        $pic.CreationTimeUtc = $json.creationTime.formatted.Replace(' UTC', '')
        $pic.LastWriteTimeUtc = $json.creationTime.formatted.Replace(' UTC', '')
    
        # 画面に変更後の作成日時を出力
        if (-not $HideDetails) {
            Write-Host -ForegroundColor Cyan "$($pic.CreationTime)"
        }
    }
}
```

## 使い方
1. スクリプトを読み込みます。
2. バックアップした画像ファイルがある親フォルダに移動します。
3. `GPhoto-Adjust`コマンドレットを実行します。

```cmd
. ./Adjustor.ps1
cd C:\Photo
GPhoto-Adjust
```

## 結果
実行すると作成日時や更新日時が撮影日時で上書きされます。

![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884998/9f7e7d3c-0acc-d585-6854-b514567290a4.png)

この画像ファイルをGoogleフォトと同期すればしっかり日時を分けて表示できます。

公式が提供する機能だけで簡単に移行できるといいんですけどね・・・
有料契約してるユーザーだけでも機能を提供してほしいです。

# リポジトリ
GitHubにソースコードと使い方をアップロードしました。
MITライセンスです。ご自由にご活用ください。

https://github.com/HoppingGanon/PhotoAdjustor
GAS で Slack に Google Calendar の「予定までの日数」を通知する

# Motivation
- 何番煎じかは知らないが作ってみたかった
- これは作業メモです

# 作業
1. Slack の Webhook URL を取得
1. 2. Google Apps Script 作成 ＆ Google Calendar API 有効化

# 1. Slack の Webhook URL を取得
- 投げるだけなので Webhook の token を取得する

## 1.1. app 作成
- https://api.slack.com/apps?new_app=1

## 1.2 webhook URL 取得
- app 選択
    - https://api.slack.com/apps 
- サイドメニュー `Features/Incoming Webhooks`
- Activate Incoming Webhooks を ON
- Add New Webhook to Workspace を選択、チャンネルを選択
- Webhook URL をメモ
    - `https://hooks.slack.com/services/T*****/******/**************************`

# 2. Google Apps Script 作成 ＆ Google Calendar API 有効化
## 2.1 プロジェクト作成
- https://script.google.com/home

## 2.2 スクリプト
- ド初心者なので動けば OK
- 以下は置き換え
    - `WEBHOOK_URL`
    - `CALENDAR_NAME`
    - `CALENDAR_ID`
    - `CALENDAR_THRESHOLD`
        - 単位：[日]


```js:main.gs
let webhook_url = "WEBHOOK_URL";

let upcoming_threshold = {
  "CALENDAR_NAME": ["CALENDAR_ID", CALENDAR_THRESHOLD],  
  "CALENDAR_NAME": ["CALENDAR_ID", CALENDAR_THRESHOLD],  
};

function main() {
  let today = new Date();
  let todayMS = today.getTime();
  let upcoming = "------------------------------";

  for (let calendar_name in upcoming_threshold) {
    let v = upcoming_threshold[calendar_name];
    let calendar_id = v[0];
    upcoming = upcoming + "\n" + "*" + calendar_name + "*";

    // day => milliseconds (hour * minutes * seconds * milli)
    threshold = v[1];
    thresholdMS = threshold * (24*60*60*1000);
    console.log("CalendarId: %s, Threshold: %d", calendar_id, thresholdMS);

    const params = {
      timeMin: (new Date()).toISOString(),
      singleEvents: true,
      orderBy: 'startTime'
    };
  
    try {
      const events = Calendar.Events.list(calendar_id, params).items;
    
      for (const event of events) {
        let eventDate = new Date(event.start.date);
        if (event.start.date === undefined) {
          eventDate = new Date(event.start.dateTime.slice(0, 10));
        }
        
        let eventDateMS = eventDate.getTime();
        if ((eventDateMS - todayMS) < thresholdMS) {
          let diffDate = Math.floor((eventDate - today) / 1000 / (24 * 60 * 60));
          upcoming = upcoming + "\n" + "* " + event.summary + " @ " + eventDate.toLocaleDateString("ja-JP") + " (_*+" + diffDate + "*_ days)";
        }
      }
    } catch (err) {
      // ignore
      console.error(err)
    }

    upcoming = upcoming + "\n";
  }

  console.log(upcoming);
  
  let options = {
    "Content-Type": "application/json",
    "method": "post",
    "payload": JSON.stringify({
      "text": upcoming
    })
  }
  UrlFetchApp.fetch(webhook_url, options);
}
```


## 2.3 サービス追加
- サイドバー「サービス」から `Google Calendar API`
- 追加

## 2.4 動作確認 
- 「このアプリは Google で確認されていません」と出たら「詳細」から「****（安全ではないページ）に移動」

## 2.5 定期実行
- サイドバー「トリガー」
- 実行する関数：`main`
- 実行するデプロイ：Head
- イベントのソース：時間主導型
- 時間ベースのトリガーのタイプ：日付ベースのタイマー
- 時刻：午前7～8時
HTMLについて

初めての投稿になります。
プログラミングに関する勉強を始めたばかりで学習途中ですが、学んだことを記録として残していこうと思い投稿しています。間違っている部分がありましたらコメントなどをください。

## HTMLとは
HyperText Markup Languageハイパーテキストを記述するためのマークアップ言語の1つです。小なり記号（＜）大なり記号（＞）を使ったタグというもので構成されていきます。拡張子は`.html`になります。
## 基本の書き方と名称
![HTML、CSS.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778076/92fe7736-2339-164f-670b-59ec1c97fc53.jpeg)
①タグ：小なり記号（＜）大なり記号（＞）で囲まれている部分をいう。②開始タグ、③終了タグ、④タグ名、⑤属性、⑥属性値、⑦コンテンツなどが含まれます。
タグの記述は基本的には半角でおこないます。タグには開始タグと終了タグがあります。終了タグにはバックスラッシュを使います。
さらに開始タグから終了タグまでを要素といいます。

### 空要素
タグは基本的には開始タグと終了タグがありますが、中にはコンテンツを持たない、終了タグがないタグもあります。そのタグを空要素といいます。

<table>
<caption>代表例</caption>
 <thead>
   <th>タグ名</th>
   <th>説明</th>
 </thead>
<tr>
   <td>br</td><td>改行に使う</td>
</tr>
<tr>
   <td>img</td><td>画像を挿入する</td>
</tr>
<tr>
   <td>input</td><td>テキストフィールドなどのフォームの部品を表示する</td>
</tr>
</table>

## すべてのHTMLに共通するタグ
`<!doctype html>`DOCTYPE宣言といいます。ファイルにかいたHTMLのバージョンを宣言するものになります。

`<html></html>`HTMLには必ず出てくるタグになります。ルート要素と呼ばれ、すべてのHTMLタグの親要素になります。`<html>`タグには`<head>`タグと`<body>`タグの２つ含まれます。
### HTMLドキュメントの基本構造
HTMLドキュメントンの基本構造は、大きくは`<head>`タグと`<body>`タグの2つのパートに分かれています。
`<head></head>`ブラウザウィンドウに表示されないが、HTMLドキュメント自体の情報が書かれている部分。
`<main></main>`ブラウザウィンドウに表示される見た目の部分。

<details><summary>サンプルコード</summary>

~~~HTML
<!doctype html>
<html>
   <head>
   </head>
   <main>
   </main>
</html>
~~~
</details>

## `<head>`タグの内容
`<meta charset>`メタデータと呼ばれる、HTMLドキュメントの情報を記述します。メタデータには、HTMLファイルの文字コード方式やページのタイトルなどが含まれるが、ブラウザウィンドウに情報が表示されることはありません。
`<title>`HTML自身の「タイトル」になります。ブラウザのタブに表示されたり、ブックマークや履歴のタイトルに使われます。
<details><summary>サンプルコード</summary>

~~~HTML
<!doctype html>
<html>
   <head>
　　　<meta charset = "UTF-8">
      <title>hoge</title>
   </head>
   <main>
   </main>
</html>
~~~
</details>

## まとめ
HTMLの基本をまとめてみました。
初めてのことなので間違っている部分がありましたらコメントよろしくお願いします。
Databricksの新たなワークスペースブラウザ

先ほど気づきました。

サイドバーの**ワークスペース**を開くと、下の部分に**新しいワークスペースブラウザを試す**と表示されます。
![Screenshot 2023-03-30 at 14.08.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/2633fd6e-9eba-c561-440b-ccb2817acc88.png)

こちらをクリックすると説明文が表示されます。**オプトイン**をクリックして有効化します。
![Screenshot 2023-03-30 at 14.02.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/c9aa8fd4-590a-972b-3210-81efe42d6b0f.png)

新たなワークスペースブラウザが表示されます。
![Screenshot 2023-03-30 at 14.10.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/d2ddac9f-8e78-7d37-5951-bc43c798ea87.png)

より広いスペースを活用してワークスペースをブラウジングすることができます。
![Screenshot 2023-03-30 at 14.17.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/951dbe95-8419-985d-198f-3bd377ebb3bc.png)

ノートブックを開いた後にも変更があります。左側にフォルダアイコンが追加されています。
![Screenshot 2023-03-30 at 14.18.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/2cbd9991-4f55-88f8-7431-ce94673f5c76.png)

ノートブックが格納されているパスにある、他のオブジェクトにクイックにアクセスすることができます。これまではブラウザの別タブで開いていたので何気に便利。
![Screenshot 2023-03-30 at 14.19.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/73d54e2c-afba-2c49-a9a2-d5597e8b092f.png)

なお、前のブラウザに戻したい場合にはユーザー設定でトグルをオフにします。
![Screenshot 2023-03-30 at 14.02.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/a36cd6e8-057e-9ca5-740c-0d6235988fc3.png)

是非試してみてください！

### Databricksクイックスタートガイド

[Databricksクイックスタートガイド](https://www.amazon.co.jp/dp/B09V1YXFVQ/)


### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
macのターミナルからVSCodeを開く方法

# zshからVSCodeを開く方法
ターミナルでcode .で開くのが楽そうだったので色々試したが、なんやかんやハマってしまったので記事に残しときます。

今回参考にさせていただいた記事
https://www.crossroad-tech.com/entry/babylonjs-editor-visual-studio-code-path
本当にありがとうございます

## 手順
簡潔にいうと.zshrcにPATHを記載する
```
1. ターミナルを開く
2. cd
3. touch ~/.zshrc
4. open ~/.zshrc
5. ファイルが開くので下記のパスを記載する
```
```
export PATH="\$PATH:/usr/local/bin:/Applications/Visual Studio Code.app/Contents/Resources/app/bin:$PATH"
```
```
5. 入力が終わったら、.zshrcを実行
   source ~/.zshrc
6. 念の為、VSCodeにて下記のものを実行
　　Shell Command: Install 'code' command in PATH

command + shift + pを押したら出てくる検索欄で shell commandとか打ったら出てきます
```

自分はこれでできました。参考にさせていただいた記事を書かれた方、本当にありがとうございました。

※**補足**
これでもできないという方は一度、VScodeがアプリケーションの中に入っているかを確認してください。自分はダウンロードの中に入っていて、アプリケーションに移すことでできるようになりました。
'devise'gem導入後、名前(name)とパスワードだけでログインするように実装したいが、ログインができない方に。エラー内容Unpermitted parameter

# この記事の内容
deviseをgemで導入し、デフォルトではemailとパスワードでログインしますが、名前とパスワードでログインする機能に変更してみました。ですが、ログインする事ができず、沼りましたので、備忘録として記事を上げました。解決策①は理屈がさっぱりわかりません‥。解決策②は、自分でも納得できたものになります。

# 付記
とにかく初心者です。記事の投稿も初めてです。Markdownもままなりません。優しくして下さい。

# 前提
deviseをgemでインストール済

# 解決前
他記事を参考に以下のように編集しました。(シンプルにnameでいいのですが、なぜか私はnicknameに統一しています‥。)
```ruby:\\config\initializers\devise.rb
config.authentication_keys = [:nickname]　#49行目
```

```ruby:\\app\views\devise\registrations\new.html.erb
<div class="field">
  <%= f.label :nickname %><br />
  <%= f.text_field :nickname, autofocus: true, autocomplete: "nickname" %>
</div>
```
```ruby:\\app\controllers\application_controller.rb
class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?

  private
  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:email])
  end
end
```

# 原因の把握
このような形で実装した所、ログインができず…。ターミナルを確認した所、以下のようなエラーが…！（実際は赤色です）
```
Unpermitted parameter: :nickname
```
ログイン時にnicknameが上手く送信できていないのが原因みたいです‥。

# 解決策①
コード見直していた所、devise.rbに他にもemailの記載があったため、nicknameに変更してみました。
```ruby:\\config\initializers\devise.rb
config.case_insensitive_keys = [:email]　#変更前　61行目
config.case_insensitive_keys = [:nickname]　#変更後　61行目

config.strip_whitespace_keys = [:email]　#変更前　66行目
config.strip_whitespace_keys = [:nickname]　#変更後　66行目
```
この変更で、名前とパスワードだけで、ログインできるようになりました。理屈はわかりません‥。また、他記事に記載してあったのですが、61行目と66行目をコメントアウトしてもできるそうです。

# 解決策②
解決策①は一旦、忘れて下さい。こちらの方が正攻法？のような気がします。
nicknameがUnpermitted parameterというエラーが気になり、以下を試したところ、問題なくいけました。
```ruby:\\app\controllers\application_controller.rb
class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?

  private
  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:email])
    devise_parameter_sanitizer.permit(:sign_in, keys: [:nickname])　#←これを追記
  end
end
```
sign_up(新規登録時)と、sign_in（ログイン時）のキーになる名前を使い分ければいけなかったのかなと、理解することにしました。
解決策①でおこなった61行目と66行目のコードは変更前に戻しました。

# 最後に
今思えば、ストロングパラメーターのpermitの引数（特にsign_upとかsign_in）について理解していれば、解決できる内容でした。実は、この名前とパスワードでログインできないこの事象に、２日間悩まされました。
同じような事で、悩まれた方の手助けになっていれば幸いです。
そして、もっと良いコードの書き方などありましたら、ご教授いただけますと幸いです。
【ドラゴンボール風解説】S3について

# はじめに
この記事はAWSの説明は今ひとつよくわからないのでドラゴンボールに例えて説明してほしい。
というAWS初学者向けの記事です。
※投稿記事作成にはchatGPTを使用しております

# S3
S3っていうのはな、データを保存するための超強力なバケツみたいなものだ！超神水のようなもんだ！データを保存するバケツを作って、そこに大事なデータを入れておけば、**いつでも取り出せるし、安全に保管できるんだ！**

でもな、S3を使うにはAWSアカウントを作ったり、**適切なアクセス権を設定する必要がある**。修行をしないと界王拳を使えないのと同じで、S3も使う前に準備が必要だぞ！

それに、データを保存するだけじゃないんだ！S3を使って、**データを移動させたり、複製したり、アプリケーションから直接読み書きすることもできる**んだ！これにはオラもワクワクしてきたぞ！

そして、もし誤ってデータを削除してしまっても、大丈夫だ！ピッコロ大魔王の攻撃をも耐える、不滅の存在だからな！**バックアップが取られているから、データが消えてしまっても復旧できるんだ！**

さあ、オラも使ってみようかな！オラにとっても、これはとってもワクワクする技だ！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3304054/d7343697-61fa-44f0-a9d7-39150f3f3e74.png)
git cherry-pickを使って特定のコミットを取り込む

## はじめに
今回プルリクを出した際に1つ前のプルリクのコミットが入ってしまっており、今回のプルリクのコミットだけを反映させたいと考え、`cherry-pick`を使用した。

## git cherry-pickとは
cherry-pickは、特定のコミットのみを指定して、取り込むことができる。

今回のケースでいうと、
新たにプルリクを作る必要があるが、`cherry-pick`を使用することで特定のコミットだけを取り込むことが可能になるので、余計なコミットを取り込まないで済む。

## Issuesを作成し、ブランチを切る
https://qiita.com/yastinbieber/items/2643085cf429fc367b61

## cherry-pickを使い特定のコミットを取り込む
ここでcherry-pickを使って特定のコミットを取り込むのだが、コミットIDを把握する必要がある。

### コミットIDを調べる
```
CA8775:nb-saiyo-web-test 01048656$ git log
commit 79c801dfb7967302734444c5cf403e5386962d (HEAD -> 88-be-webtest-userfindofcoursecontentapi, origin/88-be-webtest-userfindofcoursecontentapi, 92-be-useranswercreateapi)
commit 79c801dfb7967302734444c5cf403e5386962d
Author: testuser <◯◯◯◯@gmail.com>
Date:   Mon Mar 27 15:47:15 2023 +0900

    コミット名

```

こんな感じで`git log`で調べることができる。

### cherry-pickを使う
```
git cherry-pick [取り込むコミットID]
```
上記の様な形で特定のコミットを取り込むことができる。

今回の場合は以下のようになる。
```
git cherry-pick 79c801dfb7967302734444c5cf403e5386962d
```

これで特定のコミットをブランチに取り込むことができる。
以上。

## 参考
https://www.sejuku.net/blog/71544
Visual Studio CodeからDatabricksでSQLクエリーを実行する

[Run SQL Queries on Databricks From Visual Studio Code \- The Databricks Blog](https://www.databricks.com/blog/2023/03/29/run-sql-queries-databricks-visual-studio-code.html)の翻訳です。

:::note warn
本書は抄訳であり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
:::

本日、人気のSQLTools拡張向け[プレビュードライバー](https://marketplace.visualstudio.com/items?itemName=databricks.sqltools-databricks-driver)経由で、Visual Studio Code内からDatabricks上でSQLクエリーを実行できる様になったことを発表できることを嬉しく思っています。このプレビューリリースは、最近[パブリックプレビュー](https://qiita.com/taka_yayoi/items/08f3a170827ab8df56bd)を発表した、ユーザーがローカルで開発したコードをDatabricksが管理する計算資源と同期して実行できるVS Code向けDatabricks拡張を補完するものです。

Databricks SQL (DBSQL)は、Databricksレイクハウス上に構築されているサーバレスデータウェアハウスであり、レガシーなデータウェアハウスと比較して最大12倍すぐれたコストパフォーマンスを用いた大規模SQL、BIアプリケーションのすべてを実行することができます。DBSQLでは、お好きなツールと統合されたガバナンスモデルを通じて、オープンなフォーマットとAPIを活用します。今では、快適でパワフルなエディターから離れることなしに、VS CodeからDBSQLやAll Purposeクラスターに接続し、SQLクエリーを実行して結果を参照することができます。これは特に、Databricks上の[dbt](https://docs.databricks.com/partners/prep/dbt.html)プロジェクトを操作しており、データモデルを構築する際にSQLクエリーを試行錯誤する必要がある際には有用なものとなります。

以下のデモでは、どのように拡張をインストールし、DatabricksでSQLクエリーを実行するのかを示しています:
![](https://cms.databricks.com/sites/default/files/inline-images/db-458-blog-img-1.gif)

人気の[SQLTools](https://marketplace.visualstudio.com/items?itemName=mtxr.sqltools)拡張の著者であるMatheus Texieraと、この拡張を成功に導いたオープンソースのコントリビュータに感謝の意を表します。是非この拡張を試していただければと思っています。

[VS Code](https://marketplace.visualstudio.com/items?itemName=mtxr.sqltools)から拡張をインストールしてみてください。詳細については[ドキュメント](https://docs.databricks.com/dev-tools/sqltools-driver.html)をご覧ください。[GitHub](https://github.com/databricks/sqltools-databricks-driver)に対するフィードバックや機能リクエストは大歓迎です。

### Databricksクイックスタートガイド

[Databricksクイックスタートガイド](https://www.amazon.co.jp/dp/B09V1YXFVQ/)


### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
mtappVarsのほしい箇所の値を取得したい

プラグイン「MTAppjQuery」をインストールすると
「mtappVars」というJavaScriptのグローバル変数が使えるようになります。

jsのオブジェクト操作の練習がてら色々やってみます。

# ブラウザのコンソールログで表示する
コンソールに以下を打ち込めば、現在表示している管理画面でのオブジェクトが返ってきます。
```javascript
mtappVars
```
もしくは、json形式で表示したいのであれば以下。
```javascript
// Movable Type 7 r.5401以前はこちら
Object.toJSON(mtappVars);

// Movable Type 7 r.5401以降 / MTAppjQuery v2.8.0以降はこちら
JSON.stringify(mtappVars);
```
### 参考サイト
https://tinybeans.net/blog/2019/01/30-171105

https://tinybeans.net/blog/2022/12/mt7-r5401-json-stringify

# 各プロパティの値を取得する
以下は、コンテンツデータ（Movable Type 7）の入力画面を開いた状態で。

## mtappVarsの中身はこんな感じになっています
※一部のプロパティを省略しています。
```json:mtappVars
"author_id": 1,
"blog_id": 1,
"content_data": {
    "blog_id": 1,
    "content_type_id": 4,
    "data": {
        "6": "あああ", // 識別ラベル
        "10": ["15"], // カテゴリ
        "11": [] // コンテンツタイプ
    }
}
```

## ブログID（サイトID）を取得する場合。
```javascript
let blogID = mtappVars.blog_id;
console.log(blogID);

// コンソール内ではこれでもよし
mtappVars.blog_id;
```
```javascript:コンソールでの出力結果
1
```

## 少し深いコンテンツフィールドの値を取得する場合
キー名を階層ごとに繋いでいく。
```javascript
let contentID = mtappVars.content_data.content_type_id;
console.log(contentID);
```
```javascript:コンソールでの出力結果
4
```
### 対象の値がオブジェクトだった場合
オブジェクトでかえってくる。
```javascript
let contentData = mtappVars.content_data.data;
console.log(contentData);
```
```javascript:コンソールでの出力結果
Object { 6: "あああ", 10: ["15"], 11: [] }
```

#### オブジェクトの中の値のみを求める場合
「forEach」メソッドで配列の中身を順に出力
```javascript
Object.values(mtappVars.content_data.data).forEach(function(data) {
    console.log(data);
})

// アロー関数で書いた場合
Object.values(mtappVars.content_data.data).forEach(data => {
    console.log(data)
});
```
```javascript:コンソールでの出力結果
あああ
Array [ "15" ]
```

## 特定のコンテンツフィールドの値を取得する場合
### キーで指定する場合
{"6": "あああ"} の「6」がキーにあたる。
```javascript
let contentData = mtappVars.content_data.data["6"];
console.log(contentData);
```
```javascript:コンソールでの出力結果
あああ
```
### index番号で指定する場合
指定したオブジェクトの先頭の値を取得するには、「Object.values」メソッドを使用します。
※indexは0から始まるので、最初を指定する場合は「0」になる。
```javascript
let contentData = Object.values(mtappVars.content_data.data)[0];
console.log(contentData);
```
```javascript:コンソールでの出力結果
あああ
```


# コンテンツフィールドのID名を取得する
今度は、プロパティの値ではなく、キー部分（コンテンツフィールドのID名）を取得したい。
「Object.keys」メソッドを使います。
```javascript
// 配列で出力
Object.keys(mtappVars.content_data.data);

// forEachでリスト出力
Object.keys(mtappVars.content_data.data).forEach(function(data) {
    console.log(data);
})

// アロー関数で書いた場合
Object.keys(mtappVars.content_data.data).forEach(data => {
    console.log(data)
});
```
```javascript:コンソールでの出力結果
// 配列で出力
Array(3) [ "6", "10", "11" ]

// forEachでリスト出力
6
10
11
```

### 参考サイト
https://mebee.info/2022/06/21/post-61237/
windows 10 から windows 11 への移行

ハマったことを随時メモ

・アイコンにダンボールアイコンがつく
https://support.microsoft.com/ja-jp/office/onedrive-%E3%82%A2%E3%82%A4%E3%82%B3%E3%83%B3%E3%81%AE%E6%84%8F%E5%91%B3%E3%81%AF-11143026-8000-44f8-aaa9-67c985aa49b3

onedriveをオフにしましょう。
https://pc119.toyama.jp/work/%E3%82%A2%E3%82%A4%E3%82%B3%E3%83%B3%E3%81%AB%E3%83%80%E3%83%B3%E3%83%9C%E3%83%BC%E3%83%AB%E7%AE%B1%EF%BC%9F%E3%83%9E%E3%83%BC%E3%82%AF%EF%BD%9C%E3%81%AA%E3%82%93%E3%81%A0%E3%81%93%E3%82%8C%E8%8C%B6/

こういうわけわからんの勘弁して欲しいですね。
【git】git cloneができないときの解決方法

# はじめに
ターミナルで「git clone」をしたときになぜかうまくいきませんでした。
この問題にはどこかでまた遭遇しそうなので記録として残しておきます。

# 問題
以下の画像のようにgitHubからHTTPのURLを取得して、ターミナルで`git clone https://github.com/△△△△/○○○○.git`と叩くとクローンできるはずができない。 
![スクリーンショット 2023-03-30 13.19.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2644705/ef7247a3-b1c2-474b-f688-b977387489c9.png)

# 解決方法
github.comの前に`アカウント名＋@`を追加してコマンドを叩いたら解決しました！
```
git clone https://<アカウント名>@github.com/△△△△/○○○○.git
```
※実際に叩くときは`<>`は消してね。
# おわりに
短いですが以上です！
おーわーり。