OmniAICreator/Qiita-1.07M huggingface dataset:
GitHub のCLIでの認証をパスワードではなく、トークンで行うよう設定 

さて、Githubのgit CLIからのパスワード認証はdeprecatedになりました。近々廃止になるようです。

git pushなどした時にパスワードでの認証続けていると以下のようなメールがGitHubからきます。

```
Hi @XXX,

You recently used a password to access the repository at fukatani/AtCoderProblems with git using git/2.17.1.

Basic authentication using a password to Git is deprecated and will soon no longer work. Visit https://github.blog/2020-12-15-token-authentication-requirements-for-git-operations/ for more information around suggested workarounds and removal dates.

Thanks,
The GitHub Team
```

パスワードでの認証はやめて、SSH認証にするか個人アクセストークンでの認証を行う必要があります。
SSHでログインという手段もありますが、GitHub的にはhttpsを推奨しています。

個人アクセストークン(PAT)とパスワードの違いは、

- パスワードはGithub上で全ての権限が使えるようになってしまうが、個人アクセストークンは権限の範囲を指定することができる
- アクセストークンは複数発行したり、任意のタイミングで廃止したりできる

というところでしょうか。
最近はGitHubでスポンサーとして課金もできるようになりましたし、パスワードではなく個人アクセストークンでの認証に切り替えたほうがよいです。


### 個人アクセストークンを発行する

https://github.com/settings/tokens のページに入り、"Generate new token"をクリックします。
Noteで名前を付けられますが、なんでもいいです。

また、Select scopesのチェックボックスで今回発行するトークンの権限を設定することができます。
`git push`したりしたいだけなら、repoにチェックを入れるだけでいいでしょう。

![Screenshot from 2021-06-16 22-14-54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211651/2905c367-3e22-542f-2284-53cf0349e687.png)

これが終わったら、ページの一番下にある"Generate token"をクリックします。

すると、以下のように、トークンが表示されます。今回の場合、ghから始まる英数字の列です。(一部消してます。)

![aa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211651/7d75821d-82b2-0c3c-4f04-2444ee2a831d.png)

文字列の横のクリップボードでコピーできます。
**この文字列はこの画面を閉じると二度と表示させることができないので、ここで確実にコピーしてください。**
コピーできなかった場合はもうそのトークンは使えないのでDeleteして、もう一度発行し直せば大丈夫です。
**また、この文字列はパスワードのように認証に使えるものなので、ネットの海に公開しないでください。**
(私の上記ghから始まるトークンも念の為、無効にしました。)

ここまでくれば`git`コマンドでパスワードを求められた時に、パスワードの代わりにコピーした個人アクセストークンをペーストすれば認証を完了できます。
ユーザー名は従来通り入力します。

### 個人アクセストークンをローカルに保存する

さて、個人アクセストークンですが、ランダムに設定された英数字でとても覚えられません。
そこで、以下のコマンドを打てばgitでユーザー名とトークンを記憶してくれて、一回だけ打てば保存してくれます。

```
git config credential.helper store
```

これだけ。簡単ですね。

## 参考
https://docs.github.com/ja/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token
https://qiita.com/Kamo123/items/c92b03278b6302c641e3
Pythonエンディアン変換

```python:python
#整数読み込み
num = 9240
#16進変換(0x除く)
num_hex = hex(num)[2:]
#16進→バイト変換
bytes_be = bytes.fromhex(num_hex)
#エンディアン変換
bytes_le = bytes_be[::-1]
hex_le = bytes_le.hex()
print(hex_le)  # "1824"
```
ActiveStorage 画像プレビュー

<h1>前提条件</h1>

・ruby 2.6.6
・rails 6.0.3.4
・ActiveStorageをインストール済
・deviseを使用
・画像投稿システムを実装済

<h1>概要</h1>
　画像を投稿する際、特にデフォルトの設定であれば``ファイルを選択``をして画像を選ぶと、その画像の名前が表示されるだけで、どういった画像なのか確認することができません。

　そこで画像プレビュー機能を実装してどういった画像が投稿されるか確認できるようにしていきます。イメージ画像を以下に添付します。
![スクリーンショット 2021-06-16 12.43.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701865/0f60dbde-da89-2af6-f88f-b72f924d4c5b.png)

<h1>実装</h1>
　では実際にコードを書いていきます。新規投稿画面にも編集画面にも両方とも使えるので
必要な箇所に活用してください。

```ruby:posts/new.html.erb
<%= form_with model: @post, local: true do |f| %>
 <div class="form-group">
    <div class="field">
       <%= f.label :images, "写真" %><span class="must">*</span>
    </div>
    <p>[5MBまで、最大アップロード枚数5枚]</p>
    <%= f.file_field :images, class: "push", multiple: true, onchange: "loadImage(this);" %>
  </div>

  <div id="post_images" style="display: none;">
    <p id="preview"></p>
  </div>
<% end %>

<%= render "loadimage" %>
```
特段注意して欲しいのが、7行目の ``<%= f.file_field :images, class: "push", multiple: true, onchange: "loadImage(this);" %>`` の ``onchange: "loadImage(this);"``の部分です。この表記を入れることでjavascriptと関係付けをします。

もう一つが ``<div id="post_images" style="display: none;"></div>``の部分
ここに選択した画像を表示するようにjavascriptを記述していきます。記述するのは部分テンプレートとして``posts/_loadimage.html.erb``に記述していきます。

```ruby:posts/_loadimage.html.erb
<script>
  function loadImage(obj)
  {
    var allPreview = document.getElementById('post_images');
    var newPreview = document.createElement("p");
    allPreview.querySelector("p").remove();
    newPreview.setAttribute("id","preview");
    allPreview.insertBefore(newPreview, allPreview.firstChild);
    document.getElementById("post_images").style.display = "";
  	for (i = 0; i < obj.files.length; i++) {
  		var fileReader = new FileReader();
        fileReader.onload = (function (e) {
        	var img = new Image();
        	img.src = e.target.result;
      	    document.getElementById('preview').appendChild(img);
        });
      fileReader.readAsDataURL(obj.files[i]);
    }
  }
</script>
```
javascriptに関係付けている``id``の名前等は自身のidに置き換えてください。

4行目:``<div id="post_image">``を読み込む
5行目：``<p>``を生成
6行目：``<div id="post_image">``の中の``<p>``を削除
7行目：5行目で生成した``<p>``を``<p id="preview"></p>``に設定
8行目：7行目で設定した``<p id="preview"></p>``を``<div id="post_image">``の中の最初の要素として設定
9行目：viewの方で``<div id="post_images" style="display: none;">``としてたので``style="display: "";``に変更して、表示させるように設定。
10~18行目：ファイル選択した画像の枚数分for文を回し、15行目でその都度``<p id="preview"></p>``を生成。17行目で画像を読み込み表示させる設定を行います。

4~8行目で削除したり設定したりしていますが、これは更新するごとに画像を更新するためです。

ざっとですがコードの説明でした。
実装の手助けになれば幸いです。


<h1>参考サイト</h1>
https://kita-note.com/js-summary-of-how-to-add-elements
僕がよく使ってるnanoの設定やコマンド

##最初に
nanoについて、まとめてくれているサイト、掲示板は沢山あります。
つまり、ここではコマンド集や、設定ファイルの説明などのすべてをしません。
もし、そちらが目当てでしたら、こちらへ↓

・[GNU nanoを使いこなす](https://qiita.com/snct_hu/items/971d512c26dd8b3a3b3c)

今から、僕がよく使ってるnanoの設定やコマンドを紹介します。

##nanoとは?
#####nanoとは？
UNIXを中心に[curses](https://ja.wikipedia.org/wiki/Curses)を使ったテキストエディタです。

macOSやUbuntuなどに既存に入っていたりして、
さっと編集したい時などすごく便利ですよね？<-個人的な意見 :)

>nano以外にVScode、Vim、Atomなど、色々便利なエディタがあるのに
nanoを使う理由ってやっぱり、
CUIで操作するというロマンですよね？？<- Vi使えよ <-:punch_tone2:

##インストール
CentOS/RedHat系

```
$ sudo yum install nano
```

Ubuntu/Debian/Raspbian系

```
$ sudo apt-get install nano
or
$ sudo apt install nano
```

##nano option -T
nanoを使って開く際にちょっとした裏技
1. 開き方
2. ファイルを一気に作りたい
3. Tabの空白指定

```
1. nanoを開く
$nano [ファイル名]

2. ファイルを一気に作っていく
$nano [ファイル名] [ファイル名]....

3. nanoでTabの空白数指定  *初期は8マス*
$nano -T [数字] [ファイル名]
```

##nanoでのコマンド
nanoは基本的にctl + [] 、AltやEscなど、何かをホールドしながら押すコマンドがあります。
![kk.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1212967/b44001ce-cb80-c5cc-bcfa-3f61bf8a5af6.png)
下に表記されてますね!!
特に使うのはこちら

<strong>Ctrl + x</strong>
これは、閉じるという意味なのですが、変更があった場合保存するか聞かれます!
そして、名前を変更するかどうか聞かれます。
つまり、Ctrl + o(名前を付けて保存)などやらなくても
このコマンドだけで、保存できます。

<strong>Ctrl + w</strong>
検索
検索したい文字を聞かれるので、途中までのワードを打つとそこまで、連れてってくれます。

<strong>Ctrl + K</strong>
>一行削除

<strong>Ctrl + A</strong>
>行頭に行く

<strong>Ctrl + E</strong>
>行末に行く

<strong>Esc + G</strong>
>任意の行にいきます。
>行番号聞かれますので、入力

とまぁ、正直コマンドに関しては、便利なものが多いので、一番最初にあるURLの一覧表を見ながらいろいろ使ってみるのが良いです。
##nanorcを編集して、自分好みに!!
nanoの設定ファイルnanorcを編集して、自分の使いやすいようにしたい
1.マウスを反応

2.行数を表示
![hhaa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1212967/c3aa2ce7-2543-57f4-5f76-3f472a005c4c.png)

3.初期tab設定

4.color設定(ご自由に)
![ghh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1212967/809f49bd-9949-81aa-b9b2-cab6f96697ac.png)


```path:path
/etc/nanorc
or
~/.nanorc
```
ctrl + w 使って検索しましょう
「#」を消す or 新たに入力します。

```file:nanorc
1. マウスを反応させます
set mouse

2. 行数を表示
set linenumbers

3. 初期tab設定
set tabsize 8 <-数字の部分はご自由に変更を

4. color設定(ご自由に)
set titlecolor brightwhite,blue        #タイトル表示
set statuscolor brightwhite,green      #ステータス表示
set errorcolor brightwhite,red         #エラー表示
set selectedcolor brightwhite,magenta　#選択した時の色
set numbercolor cyan 　　　　　　　　　　#行数の色
set keycolor cyan                      #キーの色
set functioncolor green                #コマンドの色

colorの例 
set numbercolor white, black           #文字が白,バックが黒
```


ちなみに、set mouseをonにした場合、
<strong>shift</strong>
を押しながら選択できます。

##Gitのデフォルトエディタをnanoにする
あなた「Oh!! git rebase で履歴を編集しようとしたらVimが開いちまったよぉぉぉ」
nano「僕を呼んでる?!」
nano「以下のコマンドを入力してみな!」

```
#デフォルトエディタを設定
$git config --global core.editor 'nano'

#確認したい時
$git config --global --list
core.editor=nano

#例:Tabを四マス分だけ空けたい
$git config --global core.editor 'nano -T 4'
```

YOU「ていうか、この説明はgitの説明じゃん」
nano「nano関係あるじゃん!」

##参考
・[Wikipedia](https://ja.wikipedia.org/wiki/Nano_(%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%82%A8%E3%83%87%E3%82%A3%E3%82%BF))
・[GNU nanoを使いこなす](https://qiita.com/snct_hu/items/971d512c26dd8b3a3b3c)
Pythonのいろんな書き方 for-else リスト内包など


for-else


```python
list = [0,1,2,3,4]

#普通
for i in list:
  print(i)
print('for分終わりました！')

#for-else
for i in list:
  print(i)
else:
  print('終わりました')

#出力
#0
#1
#2
#3
#4
#終わりました

#forの処理が終わると、elseに飛んで処理を実行する

```

break

```python
for i in range(1,10):
  print(i)
  if i >= 90:
  break

  #breakで処理を中断できる
```

リスト内包

```python
#リスト内包表記
# [式 for 変数 in イテラルオブジェクト]

#listに1を足してあげる
plus_one = [i+1 for i in list]
print(plus_one)

# インクリメントではダメらしい
[i++ for i in list]

```
Flutterでfirebase authでPlatformExceptionでステップ実行になってしまうのの解消方法

[Flutter unable to catch PlatformException while attempting firebase auth](https://stackoverflow.com/questions/50423645/flutter-unable-to-catch-platformexception-while-attempting-firebase-auth)この記事を参考にしたら直った。

どうやらAndroid Studioの設定で例外発生時に自動的にステップ実行になるようで、それをオフにした。

 Run > View BreakpointsでDartのEnabledのチェックを外す
Unity コンソール画面にコメントを出す方法、Debug.Log関数の使い方

##0.0 はじめに
Debug.Log関数を使用することでコンソール画面にコメントを出力することができます。
スクリプトからのコメント出力や実行中の変数の中身が確認できます。
不具合を取り除くためにデバッグのログ（記録）を取り出すことができるのでとても便利です。
Debugはいろいろな使い方がありますがここでは最もシンプルな初心者向けの使い方を紹介します。


##1.0 Debug.Log関数の使い方
####1.1 コメントの表示



```c#:Test.cs
Debug.Log("Hello World"); // Hello Worldをコンソールに表示
```



####1.2 変数の中身の表示
```c#:Test.cs
int num = 123;
Debug.Log(num); // numの値をコンソール画面に表示
```



####1.3 いろいろな表示
```c#:Test.cs
int num = 1234;
Debug.Log("numの値は" + num + "です"); // numの値は1234です　とコンソール画面に表示されます
```


####1.4 いろいろな表示２
引数に$を頭に入れると{}で変数をそのまま使えます。
（下のスクリプトは1.3と同じ結果になります。）

```c#:Test.cs
int num = 1234;
Debug.Log($"numの値は{num}です"); // numの値は1234です　とコンソール画面に表示されます
```




##2.0 コンソール画面での表示
コンソール画面では1行目にログの内容、2行目以降にログが呼ばれた場所が示されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352037/4f8dcf37-3012-6efd-c289-97102bbd4c90.png)
👍**ポイント**
3行目ではTestクラスのStart()関数で呼ばれていること、()内ではTest.csの10行目から呼び出されていることが示されています。



##3.0 おまけ
リッチテキストで色やフォントサイズを変更できます。

```c#:Test.cs
int num = 1234;
Debug.Log("<color=#ff0000ff>numの値は</color>" + num + "<size=20>です</size>"); // とコンソール画面に表示されます
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352037/48f64412-c8b8-e568-679d-4a8004d578f5.png)
【Unity】シェーダーでTime.timeScaleを無視する

# ``Time.timeScale``と``_Time``
``Time.timeScale``はUnityの時間進行速度（倍率）です。こいつを0にすると``Time.time``が停止し、PhysicsやらAnimatorやらが（デフォルトでは）停止するため、Unityでポーズ画面などを作る際によく使います。
ですが、時にはTimeScaleを0（や他の1以外の値）にした時でも、通常時と同じようにふるまってほしい場合があります。このとき、スクリプトでは``Time.time``や``Time.deltaTime``のかわりに``Time.unscaledTime``、``Time.unscaledDeltaTime``を使うことで期待する動作を実現できます。AnimatorもUpdate Modeを``Unscaled``にすることでTimeScaleを無視して時間を進め続けてくれます。

ではシェーダーではどうかというと……
シェーダーでアニメーションなどを行う際は``_Time``プロパティを使いますが、これは**Time.timeScaleの影響を受けます**。つまりシェーダーでポーズメニューUIのかっこいいアニメーションエフェクトなどを作ろうとすると、Time.timeScaleの影響を受けてあえなく停止……

# ①愚直な方法
シェーダープロパティはスクリプトから設定できるのですから、こうすれば動かせそうです。

```csharp
private void Update()
{
   material.SetFloat("_UnscaledTime", Time.unscaledTime);
}
```

シェーダーに_UnscaledTimeプロパティを設定して参照できます。
ですが……使用箇所毎にこれを書くのはちょっとキモいですね。MonoBehaviourの数も増えてよろしくありません。

# ②多少マシな方法
Unityではシェーダーのグローバル変数、つまりマテリアル間で共有されるプロパティを設定できます。

[UnityEngine.Shader - Unity スクリプトリファレンス](https://docs.unity3d.com/ja/current/ScriptReference/Shader.html)

ここにある`Shader.SetGlobalFloat`やらがそれです。

```csharp
private void Update()
{
   Shader.SetGlobalFloat("_UnscaledTime", Time.unscaledTime);
}
```

これでシェーダー内で`float _UnscaledTime`を宣言すれば、timeScaleに左右されない時刻が取得できます。
これならSceneに一個だけ置いとけばいいので、前の方法よりラクそうです。大抵のケースはこれでカバーできるでしょう。

# ③もっと根本的な方法

専用スクリプトいっさい置きたくない！！！という方向けに、もっと強力な方法を紹介しておきます。
PlayerLoopをいじってMonoBehaviour非依存でグローバルプロパティを更新する方法です。

PlayerLoopにカスタムの処理を挟む処理ですが……私が以前書いたPlayerLoopをいじるためのヘルパースクリプトをつかってちゃっちゃと書きます。
こちらの[PlayerLoopModifier.cs](https://gist.github.com/ruccho/122eddafaf70a391c8a4d564c903f35e#file-playerloopmodifier-cs)をインポートし、ついで以下のコードを書きます。

```csharp
using UnityEngine;
using UnityEngine.LowLevel;
using UnityEngine.PlayerLoop;

public static class UnscaledShaderTime
{
    [RuntimeInitializeOnLoadMethod]
    private static void Register()
    {
        using (var modifier = new PlayerLoopModifier())
        {
            modifier.InsertAfter<Update.ScriptRunBehaviourUpdate>(new PlayerLoopSystem()
            {
                updateDelegate = OnUpdate,
                type = typeof(UnscaledShaderTimeUpdate)
            });
        }
    }

    private static void OnUpdate()
    {
        Shader.SetGlobalFloat("_UnscaledTime", Time.unscaledTime);
    }

    public struct UnscaledShaderTimeUpdate
    {
    }
}
```

キモは`RuntimeInitializeOnLoadMethod`属性で、これをつけたメソッドはMonoBehaviourだろうが関係なくスタートアップ時に実行されます。つまりMonoBehaviourに一切依存することなく、シーンを編集することもなく、任意の処理を挟み込めるわけなのです。あとはUpdate.ScriptRunBehaviourUpdateの直後にUnscaledTimeを設定する処理を挟み込んで終了。

すっきりしててうれしいですね。
MySQL効率化Tips

#MySQLの作業効率化Tips
　1.ログインシェルにスキーマを設定する
　2.MySQLモニターの設定を変更する
　3.SQL実行結果の色を変更する

#1.ログインシェルにスキーマを設定する
```
【実行コマンド】 mysql -uroot -p -D testDB
 上記コマンドでログインと同時にtestDBスキーマにアクセス可能。
```

#2.MySQLモニターの設定を変更する
MySQLログイン後の設定。どこのサーバのどのスキーマに誰がログインしたのかをデフォルトで表示する。

```
~/develop $ $MYSQL_LOGIN 
mysql: [Warning] Using a password on the command line interface can be insecure.
root@localhost [testDB] > 
```
上記例の場合、localhostサーバのtestDBスキーマにrootアカウントがログインしている。

```
【設定ファイル】 /etc/my.cnf
【設定値】
 [mysql]
  prompt='\\U [\\d] >\\_'
```

3.SQL実行結果の色を変更する
grcを利用しSQLの実行結果を変更する。
※grcはbrew install grc でインストールできます。

```
【設定ファイル1】 /etc/my.cnf
[mysql]
pager = grcat ~/.grcat | less -iMSx4 -FX -R
prompt='\\U [\\d] >\\_'

【設定ファイル2】.grcat
~/develop $ cat ~/.grcat 
#row delimeter when using \G key
regexp=[*]+.+[*]+
count=stop
colours=white
-
#table borders
regexp=[+\-]+[+\-]|[|]
colours=cyan
-
#default word color
regexp=[\w]+
colours=green
-
#data in ( ) and ' '
regexp=\([\w\d,']+\)
colours=white
-
#numeric
regexp=\s[\d\.]+\s
colours=yellow
-
#column names when using \G key
regexp=\w+:
colours=white
-
#date
regexp=\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}
colours=yellow
-
#IP
regexp=(\d{1,3}\.){3}\d{1,3}(:\d{1,5})?
colours=yellow
-
#schema
regexp=`\w+`
colours=magenta
-
#email
regexp=[\w\.\-_]+@[\w\.\-_]+
colours=magenta
```
Docker イメージとコンテナ

UdemyでDockerを勉強し、いちチャプターで学んだことをまとめてみました。
自分用の備忘録として書いたので分かりにくいと思います。


##Dockerとは
開発環境や実行環境をチームで同じものを使うために使うアプリ。
例えばAさんとBさんがチームを組んでアプリを作っている場合、AさんとBさんの開発環境は全く同じである必要があり、更にテスト環境、本番環境も同じである必要がある。
環境を全て同じにするのは難しいがDockerがそれを簡単にしてくれるみたいです。
コンテナという技術を使って、コンテナの中で環境構築をしたり、コードを実行したり開発をしたりする。
AさんとBさんが同じコンテナを使っていれば同じ環境で開発をしていることになる。





##docker image

docker imageとは簡単に
・コンテナを立ち上げるための基となるもの
・コンテナに必要なファイル群のまとまり
・親レイヤーの上に子レイヤーが1つづつ重なってできている


<font color="Orange">docker image をホスト(自分のPC)にpullする</font>

```
$docker pull <image名>
```

<font color="Orange">ホストの中にあるimageを確認</font>

```
$docker images
```

<font color="Orange">imageを削除</font>

```
$docker rmi <imageのID>
```

##コンテナ

####imageからコンテナを作成
(例) ubuntuイメージからコンテナを作成しbashを実行する

bashとはKernelに命令をするために使うshellの一つ
docker runはホストにimageが無ければDockerHubからpullしてくれる

```
$docker run -it ubuntu bash
```

<font color="Orange">名前を指定してrun</front>

```
docker run --name <つけたい名前> bash
```

<font color="Orange">全てのコンテナを確認</font>

```
$docker ps -a
```

<font color="Orange">コンテナから出る</font>

```
$exit プロセスを消す(statuがexited)

detach(ctrl+p+q) プロセスを残す(statusがupのまま)
```

####再度コンテナに入る

<font color="Orange">再起動する</font>

```
docker restart <コンテナ名>
```

<font color="Orange">コンテナを指定してbashを実行するかたちで再度コンテナに入る</font>

```
$docker exec -it <コンテナ名> bash
```

###コンテナからimageを作成

imageをpullしてコンテナを作成して、そのコンテナの中で環境構築などをする。
そのコンテナを他メンバーに共有するために、コンテナからimageを作成してDockerHubにimageをpushする。
pushされたコンテナを他メンバーが使うことによって、同じ環境で開発できることになる。

```
$docker commit <コンテナ名><image名>:タグ名
```

### コンテナ削除

statusがUpの場合はstopでExitedにする必要がある

```
$docker stop <コンテナid>
```

コンテナ削除

```
$docker rm <コンテナid>
```

Exitedになっているコンテナを全て削除する

```
$docker system prune
```
HerokuでLaravel + Vue.jsのアプリをデプロイするとき知りたかったこと

# 結論
Herokuを用いてLaravel + Vue.jsで作られたアプリをデプロイするにはBuild Packが必要となる。

Build Packは、Heroku上で設定できる。
本記事のようにLaravel + Vue.jsで構成されるアプリをデプロイするには
'node.js'
と
'php'
以上2つのBuild Packを導入する必要がある。

##### この手順を踏まないとHeroku上でのBuildができないからか、画面が真っ白のままである。

https://zenn.dev/shimotaroo/articles/8896edaf30f57d
↑参考にさせていただいた記事、SEOの都合か見つかりにくいが、
わかりやすいのでぜひご覧いただきたい。

# 本記事について
最近はPHPといえばLaravel、LaravelのフロントエンドといえばVue.jsという風潮が強くなっている。
そんなビギナーが「自作アプリを公開したい!!」と思ったとき、真っ先に考えるのは
Herokuでのデプロイである。

しかし、Herokuを用いる上で注意しなければならないことがある。
それは
##### ほとんど英語で書かれている。
##### ある程度インフラやビルド(特にVue.jsを用いる場合)についての造詣が不可欠

ことである。世間一般のイメージほど「初心者向け」ではない。

そんな事情もあってか「HerokuでLaravel + Vue.jsのアプリをデプロイする方法」について
知りたいというニーズはあるようで、いくつもわかりやすい記事を見つけた。

ただ、
##### デプロイしてみたら画面が真っ白になった

という私のような事例はなかなか見つからなかった。

このような事象を私は一応解決したものの、念のため同じように困っている方がいるかもしれないと思い、執筆した次第である。

# 対処法
Herokuにログイン後、対象アプリケーションのSettingsタブを押す。
そしてしばらくスクロールすると
![スクリーンショット 2021-06-16 21.28.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/961542/b0937e64-6131-dd89-0a67-798b04608101.png)

↑のように、Buildpacksという項目が表示される。
お使いの環境に合わせ、Add buildpacksから追加が可能である。

ちなみに私がデプロイしようとしたアプリケーションはVue.js + Laravelだったため上記のような構成である。

# P.S
今回の例に限らず、「開発環境でうまくいっていたことが本番環境でうまくいかない」ときは、開発環境にあって本番環境で用意できていない要素を洗い出すことが不可欠だと考える。
闇雲に「ググる」より、せっかくうまくいった事例(開発環境)があるのだから、本番環境と比較する方が短時間で解決が期待できるだろう(特に自作アプリでは、参考となり、かつ役に立つ情報を集めるのは難しい)。

また、webpackなどビルドツールを用いて開発を進めておいて本番環境でビルドが必要だということに気付けなかった方は、改めてJavaScriptの歴史などからやり直すことをお勧めする。
※私を含めて

現代では、動画で学べることも多いのでがんばっていきましょう!!
https://www.youtube.com/playlist?list=PLwM1-TnN_NN4SV6DEs4OtfA51Up6XzTfB

それでは

以上
【GTM】JSON-LD形式の構造化データから必要な情報を取得する

近頃はSEOのためにJSON-LD形式で構造化データを用意しているサイトが増えてきました。
本記事ではその構造化データから情報を抽出してGTMで変数として利用するためのコードをご紹介いたします。


https://developers.google.com/search/docs/guides/intro-structured-data?hl=ja

https://developers.google.com/search/docs/data-types/product?hl=ja


## サンプルコード
以下サンプルコードの`TARGET_KEY`の値と`jsonld`の値の数字を取得したいJSON-LDのデータに合わせて変更の上、カスタムJS変数に登録して使用して下さい。

```js
function(){
  var TARGET_KEY = '##ここで欲しいデータを指定##';
  var jsonld = JSON.parse(document.querySelectorAll('script[type="application/ld+json"]')[0].innerText);
  var val = jsonld;
  var keys = TARGET_KEY.split('.');
  for(var i=0; i<keys.length&&keys[i]!==''; i++){
    val = val[keys[i]];
  }
  return val;
}
```

GTMへの実装例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103957/09347ced-c58c-ec80-fbd2-2f9c7e0e91b1.png)


## 使用例
実際のサイトの構造化データを元に、目的のデータを取得するためのコードの調整例を示します。

### AppleのAirPods Proの商品詳細ページで商品名を取得したい場合
対象ページ https://www.apple.com/jp/airpods-pro/ 
商品詳細に関わる構造化データはHTML内に存在しているJSON-LDの中で上から1番目にあるJSON-LD内に存在しており、
JSON内オブジェクト内のプロパティnameの値に商品名が出力されているので、

- jsonldの値の角括弧内の数字 : `0` （配列は上から0番目、1番目、…と数えるため、1番目→0）
- TARGET_KEYの値 : `name`

```js:
function(){
  var TARGET_KEY = 'name';
  var jsonld = JSON.parse(document.querySelectorAll('script[type="application/ld+json"]')[0].innerText);
  var val = jsonld;
  var keys = TARGET_KEY.split('.');
  for(var i=0; i<keys.length&&keys[i]!==''; i++){
    val = val[keys[i]];
  }
  return val;
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103957/8fe52f64-b81e-c791-0c3d-ece0ff3ff3fe.png)
※ Console内で動かすため、コードを `(function(){…})();`で囲って実行しています。


### 楽天市場の商品詳細ページで商品価格を取得したい場合

対象ページ https://biccamera.rakuten.co.jp/item/4548736121133/ 
商品詳細に関わる構造化データはHTML内に存在しているJSON-LDの中で上から1番目にあるJSON-LD内に存在しており、
JSON-LDの中が配列となっており、配列の2つ目の要素の中のオブジェクトのoffersの中のpriceプロパティに目的のデータがあるのでこれをドット区切りで表現して、

- jsonldの値の角括弧内の数字 : `0` （配列は上から0番目、1番目、…と数えるため、1番目→0）
- TARGET_KEYの値 : `1.offers.price` （配列は上から0番目、1番目、…と数えるため、2つ目→1）

```js:
function(){
  var TARGET_KEY = '1.offers.price';
  var jsonld = JSON.parse(document.querySelectorAll('script[type="application/ld+json"]')[0].innerText);
  var val = jsonld;
  var keys = TARGET_KEY.split('.');
  for(var i=0; i<keys.length&&keys[i]!==''; i++){
    val = val[keys[i]];
  }
  return val;
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103957/7d62a60e-7842-4122-19be-66b22f79f58d.png)
※ Console内で動かすため、コードを `(function(){…})();`で囲って実行しています。



以上
【Rails】gemを使わないで手軽にenumをi18nに対応させて日本語化する

ご覧いただきありがとうございます。
この記事は[こちら](https://hnnsk.hatenablog.com/entry/2021/06/26/114515)へ移動致しました。
お手数おかけしますが、よろしくお願いいたします。
Teamsで検索や固定メッセージの前後スレッドを見る為のLink生成フロー

# こんな時に役立つフローを作ってみた
- プライベートチャットなどリンクを取得出来ない場合でも、メッセージリンクの取得ができる。
- 以下のような時に、リンクを踏んでスレッドの前後が見える。
    - 固定表示したが、古くなってスレッド単体が開いてスレッド前後が不明
    - 検索したらスレッド表示されてしまい、その前後が不明
- Automateで動的コンテンツが使えないときに、各種ID を取得して使える。

# 使用例
1. 対象メッセージから起動
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/fa28deae-b140-adbe-81a0-ca25a25db2d8.png)

1. 受信したチャット
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/663a2248-62c7-0f07-d521-a5534f4beac9.png)
 
# フローはこんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/9d428cf9-8f37-d43f-1742-47420c4df254.png)

Messageの内容

``` html
<p><a href="@{triggerBody()?['entity']?['teamsFlowRunContext']?['messagePayload']?['linkToMessage']}">リンク元へ</a></p>
<p>@{triggerBody()?['entity']?['teamsFlowRunContext']?['messagePayload']?['subject']}</p>
<BLOCKQUOTE>@{triggerBody()?['entity']?['teamsFlowRunContext']?['messagePayload']?['body']?['content']}</BLOCKQUOTE>
<table border = "1" cellspacing="1"  align="center" style="border: 1px ;color:silver;">
　<tr style="vertical-align: middle;">
　　<td>Team ID</td>
　　<td>@{triggerBody()?['entity']?['teamsFlowRunContext']?['channelData']?['team']?['aadGroupId']}</td>
　</tr>
　<tr  style="vertical-align: middle;">
　　<td>Channel ID</td>
　　<td>@{triggerBody()?['entity']?['teamsFlowRunContext']?['channelData']?['channel']?['id']}</td>
　</tr>
　<tr  style="vertical-align: middle;">
　　<td>Message ID</td>
　　<td>@{triggerBody()?['entity']?['teamsFlowRunContext']?['messagePayload']?['id']}</td>
　</tr>

　<tr  style="vertical-align: middle;">
　　<td>Conversation Name</td>
　　<td>@{triggerBody()?['entity']?['teamsFlowRunContext']?['conversation']?['name']}</td>
　</tr>
　<tr  style="vertical-align: middle;">
　　<td>Conversation ID</td>
　　<td>@{body('Parse_JSON_Conversation')?['Id']}</td>
　</tr>
　<tr  style="vertical-align: middle;">
　　<td>Is Group</td>
　　<td>@{body('Parse_JSON_Conversation')?['IsGroup']}</td>
　</tr>
</table>
```

# 余談
リンクも検索も改善されてすぐに不要になっちゃいそうです・・
wingetでAndroid Studio Chipmunk | 2021.2.1をインストールし日本語化してみた

#はじめに
wingetで開発環境作りをしてみた際に、Android Studioがインストール出来ることに気付いたため、コマンドラインだけで開発環境を作ってみます

|Soft    |Ver    |
|:-:     |:-:    |
|Windows10  |21h2|
|Android Studio|2021.2.1 Patch 2|

#Android Studioのインストール&日本語化
一応、GitとOpenJDKも入れておく。
PowerShellを管理者モードで起動しておいたほうが楽です。
ユーザーモードでもUACを「はい」を連打すれば良いのだけどね

```
winget install -h -e --id Git.Git
winget install -h -e --id Microsoft.OpenJDK.11
winget install -h -e --id Google.AndroidStudio
New-Item -ItemType Directory ~\AppData\Roaming\Google\AndroidStudio2021.2\plugins\
Invoke-WebRequest -uri https://plugins.jetbrains.com/files/13964/141385/ja.212.324.zip -outfile ~\ja.212.324.zip
Expand-Archive -Path ~\ja.212.324.zip -DestinationPath ~\AppData\Roaming\Google\AndroidStudio2021.2\plugins\
Remove-Item ~\ja.212.324.zip
```

#(おまけ1)アップデート
パッケージのアップグレードはコマンド一発です。
Windowsでもこんな日が来るなんて・・・

```
winget upgrade --all
```


#(おまけ2)
Ubuntuと違いFlutter環境はコマンド一発とは行きませんので省略

#所感
wingetでかなりWindowsの環境作りが楽になってきましたね。
AppleWatch の振動機能

## 概要
AppleWatchの振動機能を使うアプリを作ってみようと思い
振動の機能を簡単に試してみた。

そしてAppleWatchの振動機能は Haptic(触覚) と呼ぶんですね

## ソースコード
```swift:ContentView.swift
import SwiftUI

struct ContentView: View {
    
    let types:[String] = [
        "notification",
        "directionUp",
        "directionDown",
        "success",
        "failure",
        "retry",
        "start",
        "stop",
        "click",
    ]
    
    var body: some View {
        List{
            ForEach(0..<types.count) { idx in
                Button(types[idx]) {
                    knock(type: WKHapticType(rawValue: idx))
                }
            }
        }.listStyle(CarouselListStyle())
    }
    
    func knock(type: WKHapticType?) {
        guard let hType = type else { return }
        WKInterfaceDevice.current().play(hType)
    }
    
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
```

##解説

AppleWatchの画面に表示される種別名が書かれたボタンをタップすると対応する振動をします。

肝は ```WKInterfaceDevice.current().play(hType)``` だけですね。

play(..)メソッドの型はこんな感じ

``` swift
    open func play(_ type: WKHapticType)
```

```WKHapticType``` は、こんな感じみたいです。


```swift:WKInterfaceDevice.h
public enum WKHapticType : Int {

    case notification = 0
    case directionUp = 1
    case directionDown = 2
    case success = 3
    case failure = 4
    case retry = 5
    case start = 6
    case stop = 7
    case click = 8
    // The following types can only be used while the app has an active navigation session running:
    @available(watchOS 7.0, *)
    case navigationLeftTurn = 9
    @available(watchOS 7.0, *)
    case navigationRightTurn = 10
    @available(watchOS 7.0, *)
    case navigationGenericManeuver = 11
}
```

##感想
びっくりするくらい簡単でした。
wingetでIntelliJ IDEA2022.2をインストールし日本語化してみた

#はじめに
wingetで開発環境作りをしてみた際に、Intellijがインストール出来ることに気付いたため、コマンドラインだけで開発環境を作ってみます

|Soft    |Ver    |
|:-:     |:-:    |
|Windows11  |21h2で確認|
|IntelliJ IDEA|Ultimate2022.2確認|

#IntelliJ IDEAインストール前準備
一応Git,OpenJDKをインストールしておく
PowerShellを管理者モードで起動しておいたほうが楽です。
ユーザーモードでもUACをはいを連打すれば良いのだけどね

```
winget install -h -e --id Git.Git
winget install -h -e --id Microsoft.OpenJDK.11
```

#IntelliJ IDEAのインストール&音声不具合対応&コマンドラインで日本語化
無料版のCommunity

```
winget install -h -e --id JetBrains.IntelliJIDEA.Community
Invoke-WebRequest -uri https://plugins.jetbrains.com/files/13964/202548/ja.222.168.zip -outfile ~\ja.222.168.zip
Expand-Archive -Path ~\ja.222.168.zip -DestinationPath ~\AppData\Roaming\JetBrains\IdeaIC2022.2\plugins\
Remove-Item ~\ja.222.168.zip
```

<BR>
学生の方はEducational

```
winget install -h -e --id JetBrains.IntelliJIDEA.Edu
Invoke-WebRequest -uri https://plugins.jetbrains.com/files/13964/202548/ja.222.168.zip -outfile ~\ja.222.168.zip
Expand-Archive -Path ~\ja.222.168.zip -DestinationPath ~\AppData\Roaming\JetBrains\IdeaIE2022.2\plugins\
Remove-Item ~\ja.222.168.zip
```

<BR>
有料版をご購入の方はUltimate

```
winget install -h -e --id JetBrains.IntelliJIDEA.Ultimate
Invoke-WebRequest -uri https://plugins.jetbrains.com/files/13964/202548/ja.222.168.zip -outfile ~\ja.222.168.zip
Expand-Archive -Path ~\ja.222.168.zip -DestinationPath ~\AppData\Roaming\JetBrains\IntelliJIdea2022.2\plugins\
Remove-Item ~\ja.222.168.zip
```

#日本語化プラグインのインストール(GUIで日本語化)
コマンドラインで日本語化した方は飛ばしてください
ここからの手順はWindowsもmacOSも同じです。なんで、わかりにくい場合は他のサイトを参照してもらっても構いません。正し、2019.3以前の記事は参考にならないので注意です。

Welcaome画面 > Pluginsから「Japanese Language Pack」をインストール。
プラグインをインストールするとIDEAの再起動をかける必要があるため、他のプラグインもインストールしたい場合は、ここで追加する。
![Screenshot from 2020-12-02 08-41-36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253664/bab154db-63f2-d1a5-9646-efbef95c71a4.png)
![Screenshot from 2020-12-02 08-41-51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253664/8afd383d-4a48-9ed3-e5af-59fd6c356596.png)
![Screenshot from 2020-12-02 08-42-12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253664/b93107e7-724b-f306-277e-402d15113bef.png)


#Android SDKインストール
Welcaome画面 > カスタマイズ > すべての設定　から設定画面を開く。
Appearance & Behavior > System Settings > Android SDKのAndroid SDK LocationのEditをクリック。
SDK Components Setup画面で次を連打。
![Screenshot from 2020-12-02 08-43-09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253664/b3a8e8d2-b715-a568-1ea3-8f50d0ca0f21.png)
![Screenshot from 2020-04-24 21-58-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253664/d60050e1-737a-5ef8-1de8-6e02e8776050.png)
![Screenshot from 2020-04-24 21-58-18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253664/512c7848-5caf-d6a5-2c9b-23690cf7dc93.png)

#(おまけ1)アップデート
パッケージのアップグレードはコマンド一発です。
Windowsでもこんな日が来るなんて・・・

```
winget upgrade --all
```


#(おまけ2)
Ubuntuと違いFlutter環境はコマンド一発とは行きませんので省略

#所感
wingetでかなりWindowsの環境作りが楽になってきましたね。
terraform initでunexpected EOFエラー発生原因の一例

# エラー文

```
[xx@MacBook-Pro ~/terraform/example_2]# terraform init

Initializing the backend...

Initializing provider plugins...
- Finding latest version of hashicorp/aws...
- Installing hashicorp/aws v3.45.0...
╷
│ Error: Failed to install provider
│ 
│ Error while installing hashicorp/aws v3.45.0: unexpected EOF
```

# 原因

コードの記載方法の誤り。
GitHubのissueでも、コーディングが原因の場合もあると記載されています。

https://github.com/hashicorp/terraform-provider-aws/issues/6410

```terraform:誤
resource "aws_ecr_lifecycle_policy" "example" {
  repository = aws_ecr_repository.example.name

  policy = <<EOF
  {
    "rules": [
      {
        "rulePriority": 1,
        "description": "Keep last 30 release tagged images",
        "selection": {
          "tagStatus": "tagged",
          "tagPrefixList": ["release"],
          "countType": "imageCountMoreThan",
          "countNumber": 30
        },
        "action": {
          "type": "expire"
        }
      }
    ]
  }
EOF
}
```

```terraform:正
resource "aws_ecr_lifecycle_policy" "example" {
  repository = aws_ecr_repository.example.name

  policy = <<EOF
{
  "rules": [
    {
      "rulePriority": 1,
      "description": "Keep last 30 release tagged images",
      "selection": {
        "tagStatus": "tagged",
        "tagPrefixList": ["release"],
        "countType": "imageCountMoreThan",
        "countNumber": 30
      },
      "action": {
        "type": "expire"
      }
    }
  ]
}
EOF
}
```
【半導体メモリ】基本情報技術者試験のためのコンピュータの構成

※この記事は
「栢木先生の基本情報技術者教室」を参考に学んだことをまとめた記事です。

##半導体メモリについて

* **RAM(Random Access Memory)** とは読み書きできるメモリです。電源をきると、記憶していた内容が消えてしまう特性がある
* **ROM(Read Only Memory)** とは読み出し専用メモリです。　電源を切っても記憶していた内容は消えない特性がある

* RAMの種類にはDRAMやSRAMがある

###DRAM(Dynamic RAM) 
メリット
構造が簡単で高集積化に適しているため、SRAMに比べて大容量で安価　

デメリット
リフレッシュ動作（再書き込み）が必要

###SRAM(Static RAM)
メリット
フリップフロップ回路で構成されるため高速。
電源が供給されている限り、記憶内容を保持し続けるため、リフレッシュ動作が不要

デメリット
構造が複雑で集積度が高めにくい
値段が高価

###フロップフロップ回路
フリップフロップ回路は二つの安定した状態を持つ回路です。
1ビットの情報を記録することができる

* ROMにも種類があります。

###マスクROM
書き込み✖️
消去✖️
利用者は書き込むことができない

###UV-EPROM
書き込み○
消去○
紫外線照射で全消去できる

###EEPROM
書き込み○
消去○
電圧をかけて部分消去可能。

###フラッシュメモリ
書き込み○
消去○
電圧をかけて全・部分消去できる

* キャッシュメモリとは主記憶よりも高速でCPUと主記憶の間に配置するメモリのこと
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/965248/5d16602a-049f-6fcf-43f4-860afc2b7f26.png)

* **ヒット率**とはアクセスするデータがキャッシュメモリに存在する確率のこと

###実行アクセス時間の求め方
ヒット率✖️キャッシュメモリのアクセス時間+(1-ヒット時間)✖️主記憶のアクセス時間

* 主記憶のアクセス時間とのCPUの処理時間の差が大きい場合、1次キャッシュ,2次キャッシュと多レベルのキャッシュ構成にするとより効果が上がる

| 方式 | 概要 |
|:-|:-|
|ライトスルー方式| キャッシュメモリと主記憶の両方を書き込む方法  |
|ライトバック方式|  キャッシュメモリだけ書き込み、主記憶にはデータがキャッシュメモリを追い出されるときに書き込む |


###ライトスルー方式
メリット
キャッシュメモリと主記憶との一貫性が保たれる
デメリット
主記憶へのアクセスが頻繁なため、低速
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/965248/88905168-a9a8-b3ee-fe9a-f23560fcd2fa.png)


###ライトバック方式
メリット
主記憶へのアクセスが減るため、高速
デメリット
キャッシュメモリと主記憶の内容が一致しないため、一貫性を保つための制御が複雑になる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/965248/06b663fc-c100-9c87-532d-711e72b34209.png)

* **メモリインタリーブ** とは、主記憶装置を複数の区画にわけ、連続するアドレスの内容を並列アクセスすることでアクセスの高速化を図る方式
2Dアクションゲームを作りながらUnity学習　#4~5日目

# 環境
* MacBookAir(M1,2020)
* UnityHub 2.4.3
* Unity バージョン2020.3.10f1

# 学習内容
* StageNumber・Life・Score作成
* スコアアイテム・ダメージ床作成
* タイトル画面作成
* Game Over画面作成
* 各種シーン遷移設定

# 苦労した点
* スコアアイテム取得・敵キャラ撃破の際にスコア上昇をするように設定したこと
* 各種シーンの遷移にフェード効果を付与したこと

# 感想
シーン遷移はゲームを作成する上で必須なので是非とも習得をしていきたいです。
【RxSwift】debounce でエラー "Cannot convert value of type 'Int' to expected argument type 'RxTimeInterval' (aka 'DispatchTimeInterval')"

# どういうことか

『textFieldに文字を打って1秒なんもしなかったら処理する』といったことがしたい。
どこかで見つけてきたRxSwiftの記事をマネして書いてみた。

```swift
textField.rx.text.orEmpty
            .debounce(1, scheduler: MainScheduler.instance)
// 中略
```

ところが掲題のエラーが出る。

## RxTimeInterval

`debounce` をこう書き換える。

```swift
.debounce(RxTimeInterval.seconds(1), scheduler: MainScheduler.instance)
```

ミリ秒 `.milliseconds` なども設定できる。
おわり(´・ω・｀)
java.lang.ClassCastException: class org.springframework.web.filter.HiddenHttpMethodFilter cannot be cast to class jakarta.servlet.Filter

# 事象 : Tomcatを起動したらエラー
- 環境
  - macOS BigSur バージョン11.3.1
  - Eclipse Version: 2020-12 (4.18.0)
  - Apache Tomcat/10.0.6

```log
重大: フィルタ [HiddenHttpMethodFilter] の起動中の例外です
java.lang.ClassCastException: class org.springframework.web.filter.HiddenHttpMethodFilter cannot be cast to class jakarta.servlet.Filter (org.springframework.web.filter.HiddenHttpMethodFilter is in unnamed module of loader org.apache.catalina.loader.ParallelWebappClassLoader @76f7d241; jakarta.servlet.Filter is in unnamed module of loader java.net.URLClassLoader @97e1986)
	at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:250)
	at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:103)
```

1. EclipseでSpringBootのプロジェクトを作った
1. パソコンにインストールしてあるTomcat10を設定
1. Tomcat10を起動したらエラーになった

<details><summary>▼エラーメッセージにあるHiddenHttpMethodFilterはweb.xmlに定義していました。▼</summary><div>

```xml:pom.xml
<?xml version="1.0" encoding="UTF-8"?>
    <!-- ...省略... -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.3.7</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
      <version>2.5.1</version>
    </dependency>
    <!-- ...省略... -->
```

```xml:web.xml
<?xml version="1.0" encoding="UTF-8"?>
  <!-- ...省略... -->
  <filter>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>
```
</div></details>

## 原因 : Tomcat10だから
> Don't use Tomcat 10 yet, it works with the new jakarta packages.
> Switch to version 9 instead.
> [Wicket 9 &amp; Tomcat 10 Can&#39;t Cast jakarta.servlet.Filter - Stack Overflow](https://stackoverflow.com/questions/61906447/wicket-9-tomcat-10-cant-cast-jakarta-servlet-filter)

2020年の5月ぐらい投稿のことなのに・・・・違うのかと思ったけど・・・Tomcat9にしたうまくいった。

### 対応 : Tomcat9に変える
1. Tomcat9をインストールする
1. EclipseにTomcat9を設定して起動する
Laravelでキャッシュファイルパスを変更する

## 環境

Laravel: 8.x

## 内容

`php artisan optimize` などでキャッシュファイルを作成することができるが、デフォルトのパスは、 `<project_name>/bootstrap/cache/`となっており、それを変更したい場合。

これらのパスは Application.php（[例としてConfigファイル](https://github.com/laravel/framework/blob/8.x/src/Illuminate/Foundation/Application.php#L1015)） で設定される。

`APP_*_CACHE` を環境変数に設定すれば良い。（*は適宜実体と置き換える）
【Gitしくじり先生】プルリクエストでマージしたはずなのに差分が取り込まれていなくて焦った話

# 起こったこと
developブランチにマージしたプルリクエストたちを確認して、masterに上げる準備をしていた時のこと。
**やったはずの作業がきれいさっぱり消え去っていました。**ショック。

# 対処
わたしはよくGitでやらかすので分かるのですが、
Gitでやらかしているときはたいてい**コンフリクト解決**の時にやらかしています。

## 1.再度コンフリクト解決の作業ができる状態にする
まずは、取り込まれていない作業のコミットを探してみます。ありました！
さらに、developブランチへのマージコミットを見てみると、
かなりハデにコンフリクトしてしまい、コンフリクト解決の作業をやったみたいです。

たぶんここでミスったのでしょう。もう一度コンフリクト解決させてほしい…。

とりあえず、CherryPickできないか試してみます。できません。
対象コミットにcheckoutして、新規ブランチを切ってプルリクエストを出してみます。Diffありません。

コンフリクト解決してマージしているので、
developと対象コミットにDiffがないことになってるってことなんでしょう。
文字にしてみると、そりゃそうなんですが、developブランチと対象コミットだけ見ていると、
「Diffあるよ！取り込んで欲しい！」という思いでいっぱいになります。

### 解決
何回か調べているのに毎回こんがらがってしまうのですが、
**GitHubのFile Changedはマージ対象ブランチが「分岐点以降に積み上げた差分」。**
参考：[GitHubのプルリクエストの差分はどこと比較しているか？(git diffの".."と"..."の違い)](https://qiita.com/m-yamazaki/items/e57e357116e95ae370dc)

つまり、コミット同士を比較しているわけではないです。
今回、マージベース上はDiffがないってことなんですね。
感覚的にはコミット同士で比較しているつもりになっちゃいがちです。

対象コミットの親を変えてあげることで、マージベースでdiffが発生し、
プルリクエストを出したときにdevelopに対するDiffを認識してくれる状態にできました。

## 2.丁寧にコンフリクト解決する
ようやく、やらかしをなかったことにするスタートラインに立てました。

まずは、対象ブランチにdevelopブランチをマージして、コンフリクト箇所を明らかにします。
消え去って焦った内容が含まれているファイルをひとつ開いて見てみると、
コンフリクト行はその焦った内容の部分ではありませんでした。

ここで、急にハッと記憶がよみがえったのですが、
コンフリクトの量がえげつなさすぎて、全て片側の変更を適用しよう！で、
`git checkout -theirs .`を使ったのでした。

コンフリクト行はすべてdevelop側の変更で良い！でその判断だったのですが、
今回はそのファイルのコンフリクト行以外にも変更が加わっていたのがまずかった。
コンフリクト行以外の変更も採用されず、
結果的にdevelopブランチに取り込まれずじまいの変更になってしまっていました。
（しかもよく見たら、コンフリクト行もすべて両方の変更取り込むべきだった。ダメダメ。）

### 解決
横着しすぎず、VScodeで確認しながら解消します。
ただし、本当にえげつない量だったので、一ファイル一ファイルは現実的ではないです。

いくつかのファイルをとりあえず見ていってみると、
コンフリクト行に出ている変更自体、VScodeの一括置換でなされているものなので、
すべて同じ変更のようです。安心。

今回は両方の変更を取り込みたいので、VScode一括置換を活用して、
サーッとコンフリクトマーカーを消していきます。

置換結果をいくつか確認してみます。いい感じ。

編集したファイルをステージして、コンフリクト解消をgitに知らせます。
コミット・プッシュします。

プルリクエストのコンフリクトはもちろん解消されています。
file changedを見てみると…やりました！無事に作業が反映されているようです。

# 結論
コンフリクト解決をめんどくさがってはダメ。
かえってめんどくさいことになる（自戒）。

きちんと変更内容に向き合って解消させよう。

参考：[Git コンフリクト解消手順](https://qiita.com/crarrry/items/c5964512e21e383b73da)
なぜエンジニアはコンマ１秒でも早い方法(ショートカット等)が好きなのか考えてみた。

# どうも7noteです。なぜエンジニアはみなそこまで時短にこだわるのかの考察です。

まがりなりにもエンジニアとして数年はたらいてきた中で、一つの疑問があります。
それは、自分にも当てはまることなのですが

「なぜ、エンジニアはコンマ１秒でも早い方法が好きなのか」

※あくまで個人の感覚です。

## なぜエンジニアはコンマ１秒でも早い方法が好きなのか

ぜひエンジニアの方は思い返してみてください。きっと覚えても対して仕事が早くならないショートカットや拡張機能などをいくつか試したことはあるんじゃないでしょうか？

中には、

*「時短するための方法を探した時間」>「その方法で時短できた時間」*

といった事もあるのではないでしょうか？
頑張って方法を調べた割にはそこまで時短にならず、ただ探していた時間がほぼ意味のない時間になってしまうことが。
私は、あります。

それでも時短の方法を調べるのは何故か、個人的な考えをまとめてみました。

### 理由①: 仕事の効率化

ほとんどがこれが大々的な理由になるかなと思います。
単純に1時間かかる仕事が、30分で終わるようになれば、2倍の効率で働けることになりますからね。

でも実際、効率が2倍になるような画期的な短縮方法はそうそうありません。トータルすれば1時間のうちの数秒短縮できるようなテクニックがほとんどなのではと思います。
せいぜいよくても1時間のうち、タバコ休憩分の短縮ができれば良い方なのではと思います

こう考えると、時短テクニックに労力を割くのは、割いた時間に対しての見返りが少ないように思いませんか？
ではきっと他にも理由があるのではないでしょうか。

※宝探し的に、とても時短が図れる方法に出会うためという考え方もあるかもしれません。


### 理由②:知識欲を満たすため

**エンジニアには勤勉で努力家な方がたくさんおられます。**
英語すら使うことが難しい日本人が、複数の言語をマスターしようとしてるのですから、その努力はすごいものでしょう。
しかし、なぜその努力ができるのかと問われればきっとほとんどの方はこう答えるのではないでしょうか？

**「好きだから」**

最近は副業でエンジニアなどをやる方も増えてきているので**「儲かるから」**と答える人も中にはいるかもしれませんね。
しかしそんな方も儲ける事が好きだから続けられているのではと思います。

**好きなことはもっと知りたい。**
恋人の事は家ではどんなふうに過ごしてるのだろうとか、なんでも気になりますよね？
好きなことに対して、人は知りたいという欲求を表します。
だからそこまで時短にならなくても、そういう時短方法もあるんだ！と知れる事自体が目的になっていると考えました。

時短するための手段そのものを知る事が目的だったのかもという見解です。

### 理由③:他人に伝えられる
ほとんどの方は会社のエンジニアとして働いているか、エンジニアの仲間と共にフリーランスとして働いている方がほとんどかなと思います。

つまり**知識の共有が可能になる**わけです。
5人で働いていたとすれば、誰が一人が時短の方法を見つけて共有すれば5倍の効果が得られます。
こんなふうに自分以外の人でも使える方法であれば共有することでチーム全体の時短につながるわけですね。これはとても合理的だなと思います。

さらにこれを心理的観点から見ると、それなりに良い時短方法を共有した人は**周りから承認されることにより承認欲求が満たされます。**
「すごいね」とか「めっちゃ早いじゃん！」など、同じエンジニアから言われればそれはとても心地よくなります。
こうして承認欲求を満たされたいがために時短効率が高くないものでも、頑張って調べて共有したいという心理が働くのではないかと考えます。

## まとめ

ここまで「なぜエンジニアはコンマ１秒でも早い方法が好きなのか」を個人的見解剥き出しで考察してきました。
まとめると、以下の3つがあるのではないかと考えています。

**①仕事の効率化**
**②知識欲を満たすため**
**③他人に伝えられる(＋承認欲求)**

私としてはこれからも時短できる方法はどんどん調べて自分のものにしていきたいと思っていますし、それを記事にもして公開をしていきたいなと思います。
web制作における時短方法について過去にいくつか記事を書いているので、よかったら見ていってください。

#### おそまつ！
~ Qiitaで毎日投稿中!! ~
[【初心者向け】WEB制作のちょいテク詰め合わせ](https://qiita.com/7note)
【オリジナルアプリのDBを考える】

# What
DB設計をREADMEに書く前にmarkdownで書く

# Why
明白にするため(メモ)

# DB設計

# usersテーブル
| Column    | Type   | Options      |
| --------- | ------ | ------------ |
| username  | string | null: :false |
| email     | string | null: :false, unique: true |
| password  | string | null: :false |

#Association

・
・
・
・
・
・

# blogsテーブル
| Column    | Type       | Options      |
| --------- | ---------- | ------------ |
| user_id   | references | null: :false |
| image     |            |              |
| title     | string     | null: :false |
| text      | text       | null: :false |
| date      | date       | null: :false |

#Association

・
・
・
・
・
・

# videoテーブル
| Column    | Type       | Options      |
| --------- | ---------- | ------------ |
| user_id   | references | null: :false |
| video     |            |              |
| title     | string     | null: :false |
| text      | text       | null: :false |
| date      | date       | null: :false |

#Association

・
・
・
・
・
・

# photosテーブル
| Column    | Type       | Options      |
| --------- | ---------- | ------------ |
| user_id   | references | null: :false |
| image     |            |              |
| title     | string     | null: :false |
| text      | text       | null: :false |
| date      | date       | null: :false |

#Association

・
・
・
・
・
・

# profilesテーブル
| Column     | Type       | Options      |
| ---------- | ---------- | ------------ |
| user_id    | references | null: :false |
| image      |            |              |
| username   | string     | null: :false |
| birthday   | text       | null: :false |
| birthplace | date       | null: :false |
| bloodgroup | string     | null: :false |
| height     | integer    | null: :false |

#Association

・
・
・
・
・
・
pixi-soundで音ファイルをpixi.jsでの画像ファイルと同様に扱う

HTML5用の描画ライブラリであるpixi.jsは、音周りをサポートしていない。
他のオーディオライブラリである[howler.js](URL:https://github.com/goldfire/howler.js/)とかを使っても良いが、pixi-soundというライブラリを使うとPIXI.Loaderを画像等と共有できるので使い勝手が良い。


[公式のgithub](URL:https://github.com/pixijs/sound)によると、npmでのインストールが可能らしい。
>Installation is available by NPM:
`npm i @pixi/sound --save`

もしくは[ここ](URL:https://www.jsdelivr.com/package/npm/pixi-sound)から直接`pixi-sound.min.js`をダウンロードして、pixi.min.jsの後に読み込む。

```html:index.html
<html>
<head>
  <script src="pixi.min.js"></script>
  <script src="pixi-sound.min.js"></script>
</head>

<body>
  <div id="game"></div>
  <script src="script.js"></script>
</body>
</html>
```

あとは、音ファイルを画像ファイルと同等に扱うことができる。
ただし`index.html`と同一ディレクトリに`pixi.min.js`, `pixi-sound.min.js`, `script.js`, `image.png`, `sound.mp3`のファイルがあるとする。

```js:script.js
//Aliases
let Application = PIXI.Application,
    loader = PIXI.loader,
    TextureCache = PIXI.TextureCache,
    resources = PIXI.loader.resources,
    Sprite = PIXI.Sprite,
    Container = PIXI.Container,
    Sound = PIXI.sound.Sound,
    id = loader.resources;

//アプリケーション宣言
const width = 500;
const height = 600;
let app= new Application({
    width:width, 
    height:height,
});

//appをdivに貼り付け
document.getElementById("game").appendChild(app.renderer.view);

//素材ファイルの読み込み
loader.add("imageName", "image.png");
loader.add("soundName", "sound.mp3");
loader.load(setup);

//スプライト
let spr;
//音オブジェクト
let snd;

function setup(){
    spr = new Sprite(id["imageName"].texture);
    app.stage.addChild(spr);//画面にスプライトを貼り付け

    snd = new Sound.from(id["soundName"].sound);
    snd.volume = 0.25;//SoundオブジェクトのプロパティもSpriteと同じように変更できる

    app.ticker.add(loop);
}

function loop(delta){
    snd.play();//毎フレーム音が鳴る（うるさい）
    spr.rotation += (0.5-Math.random())*0.01;//スプライトが動く（うざい）
}
```

細かい使い方等は[公式の説明書き](URL:https://pixijs.io/sound/examples/index.html)を参考に。
MacでCreative Cloud Appがインストールできない_エラーコード702の対処法

#症状
ある日、突然 Creative Cloud appが起動しなくなる。

#アプリが使用できなくなるまでの流れ
Macでスリープから起動すると、Creative Cloud のappが応答していないため、アプリの強制終了をする
↓
Creative Cloud App を再起動する
↓
「Creative Cloudのデータが破損した」という内容のダイアログが表示される
↓
以降 Creative Cloud App が起動できなくなる
↓
アプリのアンインストールと再インストールにチャレンジするもアンインストールすらできない状態になる
(アンインストーラーをダウンロードして起動しようとしても無反応)

#アクセス権を変更することで解決できた
####インストールに必要なフォルダへのアクセス権限を確認して修正する

* macOSの場合は以下の4つ
    * /private/tmp ※Finderメニューの「移動→フォルダへ移動」で「/private」へ移動し、 「tmp」フォルダのアクセス権を修正する
    * Macintosh HD/Library/Application Support/Adobe
    * Macintosh HD/Users/＜ユーザー名＞/Library/Application Support/Adobe
    * Macintosh HD/Applications/Utility

#アクセス権の変更方法
アクセス権を変更したいフォルダを右クリック
↓
「情報を見る」
↓
「共有とアクセス権」
↓
鍵マークを押してパスワードを入力
↓
該当のアクセス権を変更
↓
○の中に点3つのアイコンを押して「内包している項目に適用」を選択
↓
変更完了


アクセス権の変更をしたら、Creative Cloud Appのアンインストール＆インストールができるようになったので、
再びアプリが使用できるようになれば無事解決です！
前にも同じ症状になったことがあり、だいぶ時間をロスしたので、同じところにハマった方がいたら是非試してみてください。

以上！
[SQL]すっきりわかるSQL入門のまとめ②

#はじめに

前回の記事に引き続いてアウトプットしていきます！
[[SQL]すっきりわかるSQL入門のまとめ①はこちら](https://qiita.com/tochisuke221/items/49d1b16672aa3ee2bfbf)

#副問い合わせ

副問い合わせとは、SQL文の中にさらにSQL文をネストすることで、副照会またはサブクエリともいう。

副問合せのパターンとしては以下の3つ

- 単一の値の代わりとして、副問い合わせの検索結果を用いる。
- 複数の値の代わりとして、副問い合わせの検索結果を用いる。
- 表の値の代わりとして、副問い合わせの検索結果を用いる。

####単一の値の代わりとして利用

```SQL
UPDATE 家計簿集計
SET 平均 = (SELECT AVG(出金額)
           FROM 家計簿アーカイブ
           WHERE 出金額 > 0
           AND 費目='食費')
WHERE 費目='食費'
```

####複数の値の代わりとして利用

・INを使った副問合せ

```SQL
SELECT * FROM 家計簿集計
WHERE 費目 IN (SELECT DISTINCT 費目 FROM  家計簿)
```

・ANY/ALLを使った副問い合わせ

```SQL
SELECT * FROM 家計簿
WHERE 費目 = '食費'
 AND 出金額 < ANY (SELECT 出金額 FROM 家計簿アーカイブ　
                  WHERE 費目 = '食費')
```

・COALESCE関数を使用した副問い合わせ

```SQL
SELECT * FROM 家計簿アーカイブ
WHERE 費目 IN(SELECT COALESCE(費目,'不明') FROM 家計簿)
```

####表の値の代わり

通常はFROM句などで使用する。
INSERT文で使う場合は、以下のように特殊な記述になる。
(VALUES以降の記述に相当する内容に化けるもの)

```SQL
INSERT INTO 家計簿集計 SELECT ~~
```

```SQL
INSERT INTO 家計簿集計(費目,合計,平均,回数)
SELECT 費目,SUM(出金額),AVG(出金額),0
  FROM 家計簿
 WEHRE 出金額　> 0
```

#テーブルの結合

テーブルの結合にはJOINを使用します。

```SQL
SELECT 日付,名前 AS 費目,メモ
FROM 家計簿
JOIN 費目
ON 家計簿.費目ID=費目.ID
```

<ポイント>
・ 結合相手が重複している場合は、複製した上で結合。
・ 結合相手の行がない場合は、その行は結合結果から消滅。

ところで、NULLだったら消滅ではなく、NULLとして出したい時があるはずです。そうした場合は、`LEFT JOIN`や`RIGHT JOIN`などがあります。また、それら両方の特徴をもつ、`FULL JOIN`などもあります。

#トランザクション
1つ以上のSQL文をひとかたまりとしたものを、トランザクションといいます。
トランザクションが終了する際に、いままでの「仮の処理」を確定事項にすることをコミットといい、逆になかったことにすることをロールバックと言います。

トランザクションは以下のように指定します。

```SQL
BEGIN;

処理

COMMIT;
```

##トランザクションの分離

DBMSに対して複数の利用者が同時に処理を要求することで発生する副作用には次の3つのものが知られています。

#####ダーティーリード
まだコミットしてない未確定の変更を他の人が読めてしまう副作用。これがあると、まだ決定してない預金残高（後でロールバックするもの）に対して操作してまって整合性がずれてしまうということある。

####反復読み取り
あるテーブルに対してSELECT文を実行した後、他の人がUPDATEすると、二度目のSELECT文を実行した際に結果が変わってしまうということ。

####ファントムリード
反復読み取りと似ていて、2回目のSELECT文の間に他の人がinsert文で行を追加すると2回目のSELECTで結果行数が変わってしまうという副作用。

以上のような副作用を避けるために、トランザクションの読み書き中にロックをかけます。このロックはDBMSのパフォーマンスを下げるため、正確なデータベースと二律背反の関係です。とはいえ、完全に2分の1の選択をしにといけないわけではなく、トランザクション分離レベルといった形でどの程度厳密に分離するか指定できます。

|分離レベル|ダーティーリード|反復不能読み取り|ファントムリード|
|--------|-----------|-------------|----------|
|REA UNCOMMITTED|恐れあり|恐れあり|恐れあり|
|READ COMMITTED|発生しない|恐れあり|恐れあり|
|REPEATABLE READ|発生しない|発生しない|恐れあり|
|SERIALIZABLE|発生しない|発生しない|発生しない|

トランザクション分離レベルのん指定は以下のようにします。

```SQL
SET TRANSACTION ISOLATION LEVEL　分離レベル
```

####ロックの活用
上記でも少し触れたロックについては、対象の一行をロックするものと表そのものをロックする二つ方法があります。

<行のロック>

```SQL
BEGIN;
SELECT * FROM ~ 
WHERE ~
FOR UPDATE;
--省略
```

<表のロック>

```SQL
BEGIN;
LOCK TABLE テーブル名 IN モード名 MODE
--省略
```

モードについては、EXCLUSIVEとすると排他ロック,SHEREとすると共有ロックとなる。

#おわりに

まだまだもっと基礎を叩き込まねば！
練習問題もしっかりやっていきます！
【JavaScript】指定したフォルダにURLリソースを取得する

# はじめに

### FileSystemAccessとは

ユーザーのデバイス上のファイルやフォルダーへの変更を直接読み取ったり保存したりするためのAPIです。

公式githubレポジトリ : https://github.com/WICG/file-system-access

GoogleChrome, Edge, OperaなどのChronium系ブラウザにしか対応していませんので使用する際にはご注意ください。

参考：[Can I use file system access?](https://caniuse.com/?search=file%20system%20access)

### 基本的な使用方法について

以下の記事が参考になります。
[Native File System APIを試してみる](https://qiita.com/pentamania/items/ada07c45d4e5cc139c03)

## コード

``` App.jsx
import { useState } from 'react'

const App = () => {
  const [imgUrl, setImgUrl] = useState('')
  const [dirText, setDirText] = useState('')
  const [dirHandle, setDirHandle] = useState(null)

  async function openDir() {
    try {
      const handle = await window.showDirectoryPicker()
      setDirHandle(handle)
      setDirText(handle.name)
    } catch (e) {}
  }

  async function saveImg() {
    if (!imgUrl) return false
    if (dirHandle) {
      save(imgUrl)
    } else {
      alert('保存先を選択してください')
    }
  }

  async function save(url) {
    const fileHandle = await dirHandle.getFileHandle(`test.png`, {
      create: true,
    })
    const writable = await fileHandle.createWritable()
    const response = await fetch(url)
    await response.body.pipeTo(writable)
  }

  const onChangeImgUrl = (e) => {
    setImgUrl(e.target.value)
  }

  return (
    <div>
      <button className="directory" type="button" onClick={openDir}>
        Open directory
      </button>
      <pre className="directory">{dirText}</pre>
      <br />
      <input type="url" value={imgUrl} onChange={onChangeImgUrl} />
      <button onClick={saveImg}>保存</button>
      <br />
      {imgUrl && <img src={imgUrl} alt="" id="img" />}
    </div>
  )
}

export default App

```

## コード解説

### フォルダの指定
```app.jsx
  async function openDir() {
    try {
      const handle = await window.showDirectoryPicker()
      setDirHandle(handle)
      setDirText(handle.name)
    } catch (e) {}
  }
```

`window.showDirectoryPicker`でフォルダを指定します。
フォルダの選択時にキャンセルを行うと例外をスローするのでtry catchを書いています。

### ファイルの保存
```app.jsx
  async function save(url) {
    const fileHandle = await dirHandle.getFileHandle(`test.png`, {
      create: true,
    })
    const writable = await fileHandle.createWritable()
    const response = await fetch(url)
    await response.body.pipeTo(writable)
  }
```
`dirHandle`は`window.showDirectoryPicker()`で取得したフォルダ情報です。
ファイルハンドラーに書き込むために`createWritable`を使用します
`dirHandle.getFileHandle`では取得したフォルダに対して書き込むファイルを生成しています。test.pngと画像ファイルが前提となっていますが、使う際はファイル名、拡張子名などはURLリソースに応じて指定できるようにしてください。

fetchでURLリソースに対してアクセスをし、pipeToにて書き込みを行っています。

## 参考

[The File System Access API: simplifying access to local files](https://web.dev/file-system-access/)
[File System Access API - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/File_System_Access_API)
[W3C File System Access](https://wicg.github.io/file-system-access/)