OmniAICreator/Qiita-1.07M huggingface dataset:
「Webを支える技術」内容メモ 第2部

## はじめに
[前回](https://qiita.com/skonishi1125/items/df69f80b01187c27ce1d)の続きです。


#### 第4章

###### URI(Uniform Resource Identifier)について
直訳すると、「統一リソース識別子」
URIを使うことでweb上に存在する全てのリソース(名前を持ったあらゆる情報)を一意に示すことができる

###### URIの例

```
http://yohei:pass@blog.example.jp:8000/search?q=test&debug=true#n10
```

- URIスキーム : http
URIの始まりであることを示す
また、そのURIが利用するプロトコルを示すのが一般的
後ろに続く部分は「://」で区切られる

- ユーザ情報 : yohei:pass
リソースにアクセスする際のユーザ名とパスワード
間が「：」で区切られる。また、ない場合もある

- ホスト名 : blog.example.jp
DNSで名前が解決できるドメイン名かIPアドレスが出現する。
また、インターネット上で必ず一意である

- ポート番号 : 8000
ホストにアクセスするときのプロトコルで用いるTCPのポート番号を表す。
ポート番号が省略されている場合は、各プロトコルのデフォルト値が使われる(HTTPの場合、80番)

- パス : /search
ディレクトリ階層を表す。ホストの中でリソースを一位に指し示す

- クエリパラメータ : q=test&debug=true
「?」が付き、"名前=値"形式のクエリ(処理要求を文字列で表したもの)が続く
複数ある場合、「&」で連結される
1つ以上のクエリの集合を、「クエリパラメータ」と呼ぶ。検索サービスに検索キーワードを渡す時など、クライアントから動的にURIを生成するときに利用する

- URIフラグメント : #n10
その前までの文字列で表現するURIが指し示すソース内部の、さらに細かい部分を特定するときに利用する
「#10」の場合、HTMLでid="n10"である要素までページが移動する


URIは「インターネット上で必ず一意になるホスト名の仕組み」と、「ホスト内で必ず一意になる階層的なパスを組み合わせる」ことで、リソースのURIが世界中のどのリソースのURIとも重複しないような仕組みとなっている

###### 絶対URI,相対URI
絶対パス、相対パスとも呼ぶ
以下の例のように、/(ルート)から記述したパスのことを絶対パスと呼ぶ

```
/foo/bar/baz
```

###### 例

```
現在いるディレクトリ -> /foo/bar/

      ↓現在地↓
[foo]--[bar]--[hoge]--[huga]
     ｜
      ∟[hoge]

相対パス　　　　　絶対パス
hoge　　　　　　 /foo/bar/hoge
hoge/huga      /foo/bar/hoge/huga
./hoge　　　　　 /foo/bar/hoge
../　　　　　　　 /foo
../hoge　　　　　/foo/hoge

```

###### ベースURI
相対URIは単体ではどの位置にあるのか解釈することができないので、相対URIの起点となるベースURIを指定する必要がある
上記の場合、ベースURIを「`http://example.jp/foo/bar`」とすると相対URIの意味が理解できるようになる

###### URIに利用できる文字
アルファベット(A-Za-z) , 数字(0-9) , 記号 - ~ : @ ! $ & ' )(

###### %エンコーディング
URI使用が許可している文字以外を、URIに入れることができる
`http://ja/wikipedia.org/wiki/あ => http://ja/wikipedia.org/wiki/%E3%81%82`
(日本語はURIに入れることができないが、%直後につけることでエンコードしてサーバに転送する)

###### URIの長さ制限
仕様上は存在しないが、実装上は存在する
IEだと2038バイト程度まで

###### URIの実装で気をつけること
- 相対URI
クライアントで相対URIを理解しようと思ったら、面倒な処理が必要となる
WebサービスやWeb APIを実装する場合は指定がない限りは絶対URIを利用した方がよい

- %エンコーディング
URIにエンコードされた文字列が複数並ぶと可読性が低下し、非常に分かりづらい
混乱を避けるため、なるべくUTF-8に対応した文字列を用いた方がよい

#### 第5章

###### 良いURI(クールURI)とは
基本的に「変わらないこと」が好ましい

###### クールURIを設計するためには
以下の3つを意識する

- 言語に依存した拡張子やパスを含めない
- メソッドやセッションIDを含めない
- リソースを表現する名詞であることを心がける

要するに、シンプルであることが大事

###### URIのユーザビリティ
シンプルなURIは、ユーザビリティ(使いやすさ、使い勝手)も良い

```
・複雑なURI
http://example.jp/servlet/LoginServlet

・シンプルなURI
http://example.jp/login

```
シンプルである方が覚えやすく、開発者ではない普通の人にも使いやすい

###### URIを変更したい場合
リダイレクト(古いURIから新しいURIに転送させること)処理を記載しておくと、ユーザに配慮が利く

###### URIのテクニック
・ 拡張子で表現を指定する
「.cgi」「.pl」といった、基本的に実装に依存した拡張子は好ましくない
しかしながら、「日本語か英語かどちらかのページを表示する」といったようなリソースの表現を特定できるような拡張子は、可読性が上がったりと良い作用が起こる

```
・日本語ページ
http://example.njp/2010/05/01/press.ja

・英語ページ
http://example.njp/2010/05/01/press.en
```

###### URIの不透明性
上記のような、言語コードが拡張子でついたページのフランス語版(.fr)のページが欲しい場合
->`http://example.njp/2010/05/01/press.fr`というようなURIではないかと推測できる

しかしながら、用意されているとは限らない
URIをクライアント側で組み立てたり、拡張子からリソースの内容を推測したりすることができないこと = 「URIがクライアントにとって不透明であること」と呼ばれる
設計したクライアントアプリケーションを作る際は不透明性を意識することも大事


## 終わりに

第2部、URIについてのメモでした。
大変ではありますが、前回同様に文字に起こすことで知識が定着するということはかなり実感できました。

次の第3部はHTTPなんですけど、多分これが一番大変そう・・・
【Laravel】シーダーの複数あるテストデータをforeachでスマートに書く

## はじめに

Laravelでシーディングのテストデータが複数ある場合、コードが冗長になってしまいます。
今回はforeachを使ってスマートにまとめる書き方をお伝えします。

今回の例ではCarbonを使っておりますが、Carbonについて詳しくは以下の記事が参考になります。
[PHPで日付時刻処理を書くならCarbonを使うべき - Qiita](https://qiita.com/yudsuzuk/items/ff894bd0b76d4657741d)


#### 対象
LaravelでWebアプリを作っている初学者向けの内容となっております。
本記事はLaravel青本をベースに書いております。
[PHPフレームワークLaravel入門 第2版 \| 津耶乃, 掌田 |本 | 通販 | Amazon](https://www.amazon.co.jp/PHP%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AFLaravel%E5%85%A5%E9%96%80-%E7%AC%AC2%E7%89%88-%E6%8E%8C%E7%94%B0-%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4798060992/ref=tmm_hrd_swatch_0?_encoding=UTF8&qid=&sr=)


#### 環境

Laravel：6系
PHP：7.4.13


***

それではまず通常のシーダーファイルの書き方の一例です。

```:PostsTableSeeder.php
class PostsTableSeeder extends Seeder
{
    public function run()
    {
        $param = [
            'name' => '竈門 炭治郎',
            'body' => '水の呼吸',
            'created_at' => Carbon::now(),
            'updated_at' => Carbon::now()
        ];
        DB::table('sizes')->insert($param);

        $param = [
            'name' => '我妻 善逸',
            'body' => '雷の呼吸',
            'created_at' => Carbon::now(),
            'updated_at' => Carbon::now()
        ];
        DB::table('sizes')->insert($param);
        
        $param = [
            'name' => '嘴平 伊之助',
            'body' => 'ケダモノの呼吸',
            'created_at' => Carbon::now(),
            'updated_at' => Carbon::now()
        ];
        DB::table('posts')->insert($param);        
    }
}
```

`created_at`と`updated_at`が同じなのに何度も書いているのはあまりスマートではありません。
foreachを使って以下のように書くことができます。


```:PostsTableSeeder.php
class PostsTableSeeder extends Seeder
{
    public function run()
    {
        $params = 
        [
            [
                'name' => '竈門 炭治郎',
                'body' => '水の呼吸'
            ],
            [
                'name' => '我妻 善逸',
                'body' => '雷の呼吸'
            ],
            [
                'name' => '嘴平 伊之助',
                'body' => 'ケダモノの呼吸'
            ]
        ];

        $now = Carbon::now();
        foreach ($params as $param) {
            $param['created_at'] = $now;
            $param['updated_at'] = $now;
            DB::table('posts')->insert($param);
        }
    }
}
```

内容が変わるテストデータ(今回は`'name'`と`'body'`)を`$params`の配列に入れます。
そして共通項目(`'created_at'`と`'updated_at'`)をforeachの中で書きます。

こうすることで無駄な記述を減らすことができ、見事スマートなシーダーファイルの完成です！

いかがでしたでしょうか？
今回はテストデータが少ないのであまり変わりないですが、共通する項目が多いほどすっきりと可読性の高いコードになります。

是非お試しいただければと思います。
Xcode12以降でシミュレータビルドできない時の対処法

# Xcode12以降でシミュレータビルドできない時の対処法

- こちらはメモ的なものになります
- いろいろ調べて対応したので残しておきます。

## 対応方法
project ->　architectures -> Excluded Architectures

ここに

- arm64を記入
- Any SDKのままでもビルドできたけど、AnyiOS SDKの方が良いと思う


![スクリーンショット 2021-01-25 11.49.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403613/9dd1ab8b-2335-5792-de28-2b51e0d24c42.png)



## Pods関係

- これを記入する

```  ruby
post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64"
    end
  end
end

```


### 参考

https://developer.apple.com/forums/thread/656509
https://stackoverflow.com/questions/63391793/xcode-12-build-target-in-wrong-order-for-simulator/63405201#63405201
Git②【ローカルリポジトリとリモートリポジトリ 】

#はじめに
これは学習用のメモになります。


#①ローカルリポジトリ
##ローカルリポジトリ流れ
ローカルは3つのエリアに分かれている。
①ワークツリー→②ステージ→③リポジトリ


①ワークツリー・・・・ファイルを変更する作業場
②ステージ・・・・コミットする変更を準備する場所
③リポジトリ・・・・スナップショットを記録する場所


##1.ワークツリーの変更をステージに追加する

```
git add <ファイル名>
git add <ディレクトリ名>
git add .
```

##2.変更を記録する（コミット）
`git commit`コマンドでリポジトリにスナップショットを記録します。

```
git commit
git commit -m '<メッセージ>'
git commit -v
```

###現在の変更状況を確認する
変更されたファイルを確認する

```
git status
```

###変更差分を確認する

```
#git addする前の変更分
git diff
git diff <ファイル名>

#git addする後の変更分
git diff --staged
```

###変更履歴を確認する

```
git log
#１行で表示するオプション
git log --oneline

#ファイルの変更差分を表示するオプション
git log -p index.html

#表示するコミット数を制限するオプション
git log -n <コミット数>
```

###ファイル削除を記録する

```
#ファイルごと削除
git rm <ファイル名>
git rm -r <ディレクトリ名>

#ファイルを残したいとき
git rm --cached <ファイル名>

#ファイルの削除を取り消す
①git reset HEAD <ファイル名>
②git checkout <ファイル名>

```

###ファイル名の移動を記録する

```
git mv <旧ファイル><新ファイル>

#以下のコマンドと同じ意味
mv <旧ファイル><新ファイル>
git rm <旧ファイル>
git add <新ファイル>
```

##３.リモートリポジトリ(GitHub)へ送信する
###リモートリポジトリを新規追加する

```
git remote add <リモート名> <リモートURL>
```
ローカルリポジトリの内容をリモートリポジトリに送ることを「プッシュ」と言う。


```
git push <リモート名><ブランチ名>
git push origin master
```

#②GitHub上にあるプロジェクトプロジェクトから始める場合
Gitリポジトリのコピーを作成する

```
git clone <リポジトリ名>
```
クローン（コピーを）作成する


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

##リモートの情報を表示する

```
git remote

git remote -v
```

##リモートリポジトリを新規追加する

```
git remote add <リモート名> <リモートURL>
```

##リモートから情報を取得する
リモートから情報を取得するには２種類のやり方があります。

###1)フェッチ
フェッチとは取ってくるという意味です。
①フェッチ
リモートブランチからローカルブランチに情報を取得する

```
git fetch <リモート名>

#例
git fetch origin
```
②マージ
ローカルブランチからワークツリーに情報を取得する

```
git merge
```


##2)プル
プルはリモートから情報を取得（プル）してマージまでを一度にやりたいとき（プル）。
フェッチとマージを同時にしてくれる。

```
git pull <リモート名> <ブランチ名>
git pull origin master

#上記コマンドは省略可能
git pull

#これは下記のコマンドと同じこと
git fetch origin master
git merge origin/master
```

##フェッチとプルの使い分け
フェッチを基本的に使うのがオススメ。
プルした際に今いるブランチが開発環境にいれば問題ないが本番環境（masterブランチ)にいるとプルしようとしたものが反映されてしまうのでファイルがグチャグチャになってしまうので注意です。（する際は今どのブランチいるのか確認が必要）


#リモートを変更・削除
##変更
```
git remote rename <旧リモート名> <新リモート名>
#例
git remote rename tutorial new_tutorial
```

##削除
```
git remote rm <リモート名>
#例
git remote rm new_tutorial
```
k-means法を理解する

本記事は教師なし学習において代表的な「k-means」に関するもの。

初学者
・PythonとScikit-learnを用いてk-meansを実装したい。
中級者
・k-meansの発展、k-means++までしっかりと理解したい。
・エルボー法を用いてクラスタ数kの最適化を行いたい。

## 初学者
アルゴリズムの深い理解は必要なく、とりあえずk-mean法の実装だけを目的とした方向けの内容。
### k-means法のアルゴリズム（視覚的理解）
k-means法では、下記手順に従ってデータのクラスタリングを行う。
初めにクラスタ数Nを決定する。（今回の場合 N=2 とする）
　①クラスタ数Nに従い、データにクラスタをランダムに付与する。
　②各クラスタの重心を求める。
　③各データにおいて最も距離が近い重心のクラスタに変更する。
　④各クラスタの重心が収束するまで②、③の処理を繰り返す。
![k-means1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617816/87365485-ece7-590a-55f6-02e60dd4eb85.png)

### k-means法の実装（ライブラリScikit-learnを使用）
scikit-learn とはPythonのオープンソース機械学習ライブラリであり、比較的簡単にk-means法の実装が可能。

コードは下記の通り。

```python:JyupyterNotebook
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.cluster import KMeans

# Irisデータセットを読み込む
iris = load_iris()
iris_hstack = np.hstack((iris.data, iris.target.reshape(-1,1)))
x_data = iris_hstack[iris_hstack[:,4] != 2, :][:, [0, 2]] #　今回は'setosa', 'versicolor'のデータのみ使う

# クラスタリング前の散布図を描画
fig, ax = plt.subplots(figsize=(10, 4), dpi=100, ncols=2)
ax[0].scatter(x_data[:,0],x_data[:,1])
ax[0].set_title('クラスタリング前')
ax[0].set_xlabel('Sepal Width')
ax[0].set_ylabel('Petal Width')

# ハイパーパラメータのクラスタ数を3に設定(再現性を持たせるため、random_state100固定)
km = KMeans(n_clusters=3, init='random', n_init=10, random_state=100)
# Kmeansを実行
y_km = km.fit_predict(x_data)

# クラスタ1を作成
# 散布図の作成
ax[1].scatter(x_data[y_km == 0, 0], x_data[y_km == 0,1], s=50, edgecolor='black', marker='s', label='cluster 1')
# クラスタの中心を作成
ax[1].plot(np.mean(x_data[y_km == 0, 0]), np.mean(x_data[y_km == 0, 1]), marker='x', markersize=15, color='red')

# クラスタ2を作成
# 散布図の作成
ax[1].scatter(x_data[y_km == 1, 0], x_data[y_km == 1,1], s=50, edgecolor='black', marker='o', label='cluster 2')
# クラスタの中心を作成
ax[1].plot(np.mean(x_data[y_km == 1, 0]), np.mean(x_data[y_km == 1, 1]), marker='x', markersize=15, color='red')

# クラスタ3を作成
# 散布図の作成
ax[1].scatter(x_data[y_km == 2, 0], x_data[y_km == 2, 1], s=50, edgecolor='black', marker='v', label='cluster 2')
# クラスタの中心を作成
ax[1].plot(np.mean(x_data[y_km == 2, 0]), np.mean(x_data[y_km == 2, 1]), marker='x', markersize=15, color='red')

ax[1].set_title('クラスタリング後(k-menas法)')
ax[1].set_xlabel('Sepal Width')
ax[1].set_ylabel('Petal Width')
plt.show()

# グラフを保存
fig.savefig("k-means_graph.png")
```

![k-means_graph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617816/4c0bcb09-7e62-8414-5697-0275b9d3a21f.png)

長ったらしくコードが書かれているが、実際にk-means法を実装しているのは19~21行目のみ（それ以外のコードは前処理やグラフ表示に関するもの）

<!--
中級者
k-meansの発展、k-means++までしっかりと理解したい方向け。

k-means法の問題点
1. 結果が初期値に依存している（初期値をランダムに設定しているため）

k-means++とは？
初期値依存問題を初期のクラスタ中心点をデータ点間の距離に基づいて確率的に決定することで解決した手法。

k-means++法のアルゴリズム（視覚的理解）

k-means法では、下記手順に従ってデータのクラスタリングを行う。
初めにクラスタ数Nを決定する。（今回の場合 N=2 とする）
    ①各点xiの中からランダムに1点を選び、クラスタの中心とする
    ②各点xiに関して、既存のクラスタ中心の中から最も近いクラスタ中心との距離D(x)D(x)を計算する
    ③各点xiに関して重み付き確率分布D(x)2∑D(x)2D(x)2∑D(x)2を用いて、新しいクラスタ中心をランダムに選ぶ
    ④2.と3.の工程をk個のクラスタ中心が選定できるまで行う

-->
2021/01/24　今後追記予定
いま見ているTwitterアカウントに限定してツイートを検索するブックマークレット

# はじめに
ブラウザ版Twitter用ブックマークレットです。
アカウントを指定してツイートを検索する時に、コピー＆ペーストする手間をひとつ省く便利なやつです。

```.js
javascript:(()=>{const t=location.href.split("/");if(t[2].endsWith("twitter.com")&&t[3]){const o=t[3].split("?")[0],i=prompt("Search from @"+o,"");i&&(location.href="//twitter.com/search?f=live&q="+i+"%20from:"+o)}})();
```

# 使い方
1. 検索対象とするTwitterアカウントのホーム、またはツイートのページを予め開いておく。
2. ブックマークレットを実行。
3. 入力画面が表示されるので、キーワードを入力する。

# 簡潔な説明

圧縮前のコードはこちら。

```.js
(
    () => {
// ----------

const path = location.href.split('/');

// twitter ID check
if (path[2].endsWith('twitter.com') && path[3]) {
    // id
    const id = path[3].split('?')[0];// no parameters
    // keywords
    const keywords = prompt('Search from @' + id, '');

    // search results
    if (keywords) {
        location.href = '//twitter.com/search?f=live&q=' + keywords + '%20from:' + id;
    }
}

// ----------
    }
)();
```

大体の流れは次の通りです。

1. URLからtwitter IDを取得する => `path[3]`
2. `window.prompt`で検索キーワードを取得する => `keywords`
3. 取得した値をもとに検索パラメータをセットする
4. 組み立てたURLを開く


# 註
+ iPhone: Safari, Chromeで動作確認しました。
+ 以下の例のように、`https://twitter.com/` にアカウントが続くURLでのみ実行可能です。

**OK** :smiley:
https://twitter.com/Qiita
https://twitter.com/Qiita/status/1351820856100487168

**NG** :confounded:
https://twitter.com
https://twitter.com/search?q=qiita

# あとがき
今どき`window.prompt`を使うのがちょっとアレなんですが、取り敢えず動けばOKです。

いつもお世話様です。
本日もありがとうございました。

# 参考
**【簡単にできる】ブックマークレットのすゝめ【初心者向け】**
https://qiita.com/len_crow/items/189603f2c5f462bb670c

**Twitterの高度な検索**
1. https://twitter.com/search-advanced?lang=ja
2. https://help.twitter.com/ja/using-twitter/twitter-advanced-search
WordPressの個別記事をページ遷移ではなく、モーダル表示にする方法

※前提として、カスタム投稿を表示させる場合のコードになります。

①Remodalをダウンロード
http://vodkabears.github.io/remodal/
読み込むファイルは「remodal.min.js」「remodal.css」「remodal-default-theme.css」の３つ。
※パスは任意で変更してください。

```
<link rel="stylesheet" href="remodal.css">
<link rel="stylesheet" href="remodal-default-theme.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="remodal.min.js"></script>
```


②投稿部分を作成
ポイントとしてはaタグのリンク先を記事のIDに設定すること。
モーダルのdata-remodal-idと揃えることで、紐付けが完了する。
※表示させたい内容は任意で変更してください。

```
<?php
$args = [
'post_type' => 'works', // カスタム投稿名が「works」の場合
'posts_per_page' => 5, // 表示させる数
];
$my_query = new WP_Query($args); ?>
<?php if ($my_query->have_posts()): ?>

<?php while ($my_query->have_posts()) : $my_query->the_post(); ?>
<article class="">
<a href="#<?php the_ID(); ?>">
<figure class=""><img class="" src="" alt=""></figure>
<h3 class="mod-slide__title"></h3>
<p class=""><?php the_title(); ?></p>
</a>
</article>
<?php endwhile; ?>
<?php else: ?>
<?php endif; wp_reset_postdata(); ?>
```


③モーダル部分を作成
先程記載した通り、data-remodal-idに記事のIDを設定してください。
また、モーダルの親要素にclass="remodal"を付与してください。
こちらで完了です。

```
<?php
$args = [
'post_type' => 'works',
'posts_per_page' => 5,
];
$my_query = new WP_Query($args); ?>  
<?php if ($my_query->have_posts()): ?>
<?php while ($my_query->have_posts()) : $my_query->the_post(); ?>
<article class="remodal" data-remodal-id="<?php the_ID(); ?>">
<button data-remodal-action="close" class="remodal-close"></button>
<figure><img src="" alt=""></figure>
<h3 class=""></h3>
<p class=""></p>
</article>
<?php endwhile; ?>
<?php else: ?>
<?php endif; wp_reset_postdata(); ?>
```
Unity 子オブジェクトのチェック（非アクティブ含む）・Component削除


### 全Prefabの子オブジェクトからTextMeshProを含むものを探し出す

```
// Resources内からPrefabを全検索
var allPrefabs = AssetDatabase.FindAssets("t:Prefab", new string[] { "Assets/Resources" });

foreach (var guid in allPrefabs)
{
    var path = AssetDatabase.GUIDToAssetPath(guid);

    GameObject currentObject = AssetDatabase.LoadAssetAtPath<UnityEngine.GameObject>(path);

    // trueを入れると非アクティブも含めて全て取得
    var textMeshProUGUIArray = currentObject.GetComponentsInChildren<TextMeshProUGUI>(true);

    if (textMeshProUGUIArray.Length > 0)
    {
            // ※0より大きければデータ存在する。
    }
}



```


### 指定したComponentが親オブジェクトにアタッチされている場合、削除する。

```

// Resources内からPrefabを全検索
var allPrefabs = AssetDatabase.FindAssets("t:Prefab", new string[] { "Assets/Resources" });


foreach (var guid in allPrefabs)
{
    var path = AssetDatabase.GUIDToAssetPath(guid);

    GameObject currentObject = AssetDatabase.LoadAssetAtPath<GameObject>(path);

	// アタッチされているかをチェック
    if (currentObject.GetComponent<アタッチ済みクラス名>() != null)
    {
        // Trueを入れると削除可能になる。
        DestroyImmediate(currentObject.GetComponent<アタッチ済みクラス名>(),true);
    }
}

// 変更を保存する
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();


```
Webの仕組み

## 【Webの仕組み】
これまでのRuby on Rails での開発経験と、Webの仕組みを勉強した経験から、
利用者がRailsアプリケーションのURLをクリックした時に裏側ではどのような処理が実行されているのかをただ順番に列挙していく。

- 利用者がURLをクリック。

- クライアントがURLをリクエストとして送信。
- Webサーバーがそのリクエストを受信、解析し何を要求しているかを判断する。
- HTMLをレンダリングするアプリケーションサーバーに処理を渡す。
- アプリケーション(アプリケーションサーバー)は（これがMVCモデルのアプリケーションの場合）届いたURLを解析し、どのControllerのどのアクションを実行するかを判断する。これがroutes.rbに記述されている。
- リクエストのURLからたとえば投稿一覧画面を見たいという要求であることが分かれば、Postコントローラーのindexアクションを実行し、Postモデルがデータベースから一覧画面に必要な情報を取ってくる。
- データベースから取得したデータを変数に格納し、Viewを呼び出す。
- Viewはそのデータを使ってHTML文書を作成しControllerへ返す。
- HTML文書を受け取ったControllerは、そのデータをレスポンスとしてアプリケーションサーバーを通してWebサーバーに送り、Webサーバーから、クライアントへ送信する。
- 利用者が見ているブラウザ上に返されてきたHTML文書が表示される。

以上になります。プログラミングを勉強し始めてから1年ほど経ちましたが、知識不足なこともあるかと思いますので、何か間違った記述があればご指摘いただけると助かります。

## 【参考にしたサイト、書籍】
サイト:
 https://www.javadrive.jp/rails/ini/index7.html
https://qiita.com/jnchito/items/3884f9a2ccc057f8f3a3  
書籍 : 
[Webを支える技術] (https://www.amazon.co.jp/Web%E3%82%92%E6%94%AF%E3%81%88%E3%82%8B%E6%8A%80%E8%A1%93-HTTP%E3%80%81URI%E3%80%81HTML%E3%80%81%E3%81%9D%E3%81%97%E3%81%A6REST-WEB-PRESS-plus/dp/4774142042/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1AXE9N0Z5R8DV&dchild=1&keywords=web%E3%82%92%E6%94%AF%E3%81%88%E3%82%8B%E6%8A%80%E8%A1%93&qid=1611540720&sprefix=web%E3%82%92%2Caps%2C267&sr=8-1)
'ruby/config.h' file not found

# 問題

```zsh
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/include/ruby-2.6.0/ruby.h:33:
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/include/ruby-2.6.0/ruby/ruby.h:24:10:
fatal error: 'ruby/config.h' file not found
#include "ruby/config.h"
         ^~~~~~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/include/ruby-2.6.0/ruby/ruby.h:24:10:
note: did not find header 'config.h' in framework 'ruby' (loaded from
'/Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/System/Library/Frameworks')
1 error generated.
make: *** [generator.o] Error 1

make failed, exit code 2
```

# 解決策

ここに書いてあった
https://github.com/orta/cocoapods-keys/issues/198#issuecomment-510909030

自分の場合は以下を実行後、

```zsh
brew install rbenv ruby-build
echo 'if which rbenv > /dev/null; then eval "$(rbenv init -)"; fi' >> ~/.zshrc 
rbenv install 2.6.3
rbenv global 2.6.3
```

`which gem` でパスが以下になっていなかったので、ターミナルを再起動して再度パスを確認後直った。

```zsh
$ which gem
/Users/<youruser>/.rbenv/shims/gem
```
【AT Command】HTTP GET(SIMCom: SIM7500JC)

## MEMO
HTTP GETリクエストのマニュアル


## 環境

- OS: windows10
- ターミナル: m-center v.02.03.00

## ターミナルログ

### GPRSネットワークの確認

> GPRS network is available

```
AT+CSQ //電波の強度

AT+CSQ

+CSQ: 19,99

OK

AT+CREG? //ネットワークの登録状況

AT+CREG?

+CREG: 0,3

OK

AT+CGREG? //PSドメイン:データ通信用ネットワークへの登録状況

AT+CGREG?

+CGREG: 0,1

OK
```

### PDPコンテキスト

```
AT+CGSOCKCONT=1,"IP","soracom.io"

AT+CGSOCKCONT=1,"IP","soracom.io"

OK

AT+CGPADDR

AT+CGPADDR

+CGPADDR: 1,10.224.194.152
+CGPADDR: 2,36.10.0.3.72.2.189.243.68.16.48.18.69.96.40.1
+CGPADDR: 3,0.0.0.0,0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0

OK
```

### Send HTTP GET Request 

```
AT+HTTPINIT // HTTPサービス開始、PDPコンテキストの有効化

AT+HTTPINIT

OK

AT+HTTPPARA="URL","http://opinion.people.com.cn/GB/n1/2018/0815/c1003-30228758.html" // パラメータの設定

AT+HTTPPARA="URL","http://opinion.people.com.cn/GB/n1/2018/0815/c1003-30228758.html"

OK

AT+HTTPACTION=0 // HTTP GET リクエストの送信

AT+HTTPACTION=0

OK

+HTTPACTION: 0,200,22505 // リクエストの結果(200番、22505byteのリスポンス情報)

AT+HTTPHEAD // HTTPリスポンスヘッダーの読み込み

AT+HTTPHEAD

+HTTPHEAD: 1338 // 1338byteのリスポンスヘッダー

HTTP/1.1 200 OK
Date: Mon, 25 Jan 2021 01:57:29 GMT
Content-Type: text/html
Content-Length: 22505
Connection: keep-alive
Last-Modified: Wed, 15 Aug 2018 00:55:17 GMT
ETag: W/"5b7379f5-57e9"
X-Cache-Hits: 1
Accept-Ranges: bytes
X-Via: 1.1 PSbjwjBGP2qk179:6 (Cdn Cache Server V2.0), 1.1 ianxin96:13 (Cdn Cache Server V2.0), 1.1 PS-KUL-01mgj108:0 (Cdn Cache Server V2.0)
X-Ws-Request-Id: 600e2588_PS-KUL-01mgj108_3966-55320
...

OK

AT+HTTPREAD=0,500 // HTTPリスポンスの情報を500byte読み込む

AT+HTTPREAD=0,500

+HTTPREAD: 500
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
...

OK

AT+HTTPTERM //HTTPサービスの終了

AT+HTTPTERM

OK

```
AWS CLIの設定（Windows）

AWS CLIを設定する。
AWS CLIでS3のリスト、アップロード、ダウンロードをしたい。

#インストール
公式ガイド：https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-chap-install.html

AWS CLI Version2であれば以下からインストーラをダウンロードできる。
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/install-cliv2-windows.html

↓入った。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342082/4f8336f5-517f-8cf0-aba9-13e30eed675a.png)

#構成

####（なければ）アクセスキーとシークレットキーを作成する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342082/ccc1f488-7009-f850-22b8-792a5d721150.png)

ペアは最大2個なので、すでに2個あれば新規作成はできない。

aws configureで以下の通り聞かれるので、ひとつひとつ答えていく。

```
aws configure
AWS Access Key ID [None]: （アクセスキー）
AWS Secret Access Key [None]: （シークレットキー）
Default region name [None]: ap-northeast-1
Default output format [None]: text
```
※Default output formatはjson, table, textから選べる。
※IAMコンソールからDLしたCSVファイルはAccess key ID,Secret access keyの形式で記載されている。
慌ててアクセスキーもコピーしないように注意

#確認

S3のファイルがリストできるか試してみる。（s3 URI）には自分がアクセスできるS3 BucketのURIを入れる。

```
aws s3 ls （s3 URI）
```

ファイルがリストされていればOK。
【検討中】Youtube Data Apiを使ってWEBアプリを作る【未遂】

# はじめに
これは推し活する為に頑張った者の壮大な物語である。（結果失敗に終わる

前提として、何か適当にAPI使ってFirebaseとか使って簡易アプリを作ろうかなという軽い気持ちの事でした。

まず個人で使えそうなAPIを調べる事に。先人様が調べてるものをざらっと見て自分の趣味と合致した[YouTupeAPI](https://developers.google.com/youtube/v3)ってEんじゃないの？と思ったのが発端。

【先人様の参考情報】（他にもおすすめがあればコメントください
https://qiita.com/mikan3rd/items/ba4737023f08bb2ca161

結論から述べると辛いのでもうちょいアイデアか天才のひらめきが必要

# やりたい事
日頃常にYouTubeを見てるハードユーザーなので登録チャンネルの量が非常に膨大。
左側のサイドバーにずらっと登録チャンネルが並び配信マークがついてるものの何をやっているかはさっぱりわからないストレス。ホロライブとかにじさんじとかなんでもいい推しがみんないるはずだ。そう、自分は個人の人しかあまり見ないけどいっぱいいる。出来れば ***登録チャンネルで配信されているものをずらっと見回したい*** 要件はただこれだけである。

要件は決まったのでさっそくどうやるか設計を考える。
外部APIを叩くだけだしサーバーレスでいいだろう。すると[FirebaseHosting](https://firebase.google.com)で余裕そうだなぁ。
フロントはとりあえず動かしてみる為にvue-cliでさくっとすることにする。

次にどの情報を取得するかを考える。
YouTubeAPIには4種のAPIが存在する
（あ、ちなみにGoogleさんのAPIについては[こちら](https://developers.google.com/apis-explorer)）

- YouTube Data API v3 v3(https://developers.google.com/youtube/v3/docs)
- YouTube Analytics API(https://developers.google.com/youtube/analytics/reference/)
- YouTube Live API v3(https://developers.google.com/youtube/v3/live/docs/)
- YouTube Reporting API(https://developers.google.com/youtube/reporting/v1/reference/rest/)

ざらっと見てAnalyticsとReportingは配信者向けっぽいからDataかLiveをいい感じに使えば行けそうな気がする。
詳しくはリンク先にいろいろ書いてあるので割愛だけどここに来てふと気づく。
「これ、クォータ足りないんじゃね？」

[クォータとは](https://developers.google.com/youtube/v3/determine_quota_cost)YouTubeAPIを使用するために必要な命の源である。

要約すると1日10,000上限。一番使用頻度高そうなsearch:listが1reqest100ということはつまり1日100回しか取得できないクソアプリが完成する事になる。

Live配信してるか判定するにはsearchもしくはvideoで行わないといけないがsearchは１００かかるvideoは軽いがvideoidがなければ ***ほぼ無差別に配信してる動画を取得してしまう始末*** これはいけない

しかもうまく行きそうならWebに公開しようと思った俺達一行はどうにかならないか別案を考える。まず個人じゃなくてgoogleOAuth使ってユーザーの力を借りる方法にしてみよう、そしたら１００００×ユーザー数で割と現実的になりそう❕いや普通に考えて1日一人100回でも十分クソアプリだろ・・・と思いこの方法は辛い。じゃあYouTubeトップからスクレイピングして配信中のチャンネルIDを拾ってくれば！と思うがYouTubeはスクレイピング禁止（日頃から重かったりするので労ろう）なので無理ぽ。仕方ないのでじゃあクォーターの上限突破を申請するしかないか←今ここ

なんとか回避策を日々検討中なのでナイスなアイデアをお待ちしてます。

（プロトタイプで登録チャンネルの一覧は取得するまではやっていたのだった・・・）
![スクリーンショット 2021-01-25 9.09.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241708/4e6a7453-fb07-fb2f-fc6e-e4715be4d809.png)

## 追記

ほぼやりたい事をやっているページを見つけてしまって情弱を晒しました😇
https://www.youtube.com/feed/subscriptions
CentOS8 ffmpeg install

### 準備
```
# dnf install https://download.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
# dnf localinstall --nogpgcheck https://download1.rpmfusion.org/free/el/rpmfusion-free-release-8.noarch.rpm
# dnf install http://rpmfind.net/linux/epel/7/x86_64/Packages/s/SDL2-2.0.10-1.el7.x86_64.rpm
# dnf -y install epel-release
# rpm -Uvh http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-1.el7.nux.noarch.rpm
```
### ライブラリ反映

```
# vi /etc/ld.so.conf
* /usr/local/lib を追加
# ldconfig
```

### インストール

```
dnf -y --enablerepo=epel,nux-dextop install ffmpeg
```

### 追記
http://rpmfind.net/linux/epel/7/x86_64/Packages/s/SDL2-2.0.10-1.el7.x86_64.rpm　が404 になっていてインストールできない場合は

```
# yum config-manager --set-enabled powertools
```
No template for interactive request IdeasController#index is missing a template for request formats: text/htmlというエラーが出た

#rails s を行ったら以下のエラーが発生

```
No template for interactive request
IdeasController#index is missing a template for request formats: text/html

NOTE!
Unless told otherwise, Rails expects an action to render a template with the same name,
contained in a folder named after its controller. If this controller is an API responding with 204 (No Content),
which does not require a template, then this error will occur when trying to access it via browser,
since we expect an HTML template to be rendered for such requests. If that's the case, carry on.
```

#対処法

view以下のideasディレクトリの名前がいつの間にか（自分がいじっていたみたい、、）変わっていたのでideasに変更したら解決しました。
Ideasコントローラーに対応するビューがないという意味のようです。
パブリック MQTT ブローカーの使い方

次のブローカーを使ってみました。
[Free Public MQTT 5 Broker Server](https://www.emqx.io/mqtt/public-mqtt5-broker)

## MQTT

publish

```bash:go_pub_mqtt.sh
message="Hello Mqtt "`date`
mosquitto_pub -d -m "${message}" \
	-h  broker.emqx.io \
	--topic example/testTopic
```

subscribe

```bash:go_sub_mqtt.sh
mosquitto_sub -d -h broker.emqx.io \
    --topic example/testTopic
```

実行結果

```text
$ mosquitto_sub -d -h broker.emqx.io --topic example/testTopic
Client (null) sending CONNECT
Client (null) received CONNACK (0)
Client (null) sending SUBSCRIBE (Mid: 1, Topic: orz, QoS: 0, Options: 0x00)
Client (null) sending SUBSCRIBE (Mid: 1, Topic: example/testTopic, QoS: 0, Options: 0x00)
Client (null) received SUBACK
Subscribed (mid: 1): 0, 0
Client (null) received PUBLISH (d0, q0, r0, m0, 'example/testTopic', ... (53 bytes))
Hello Mqtt 2021年  8月 10日 火曜日 18:39:44 JST
Client (null) sending PINGREQ
Client (null) received PINGRESP
Client (null) received PUBLISH (d0, q0, r0, m0, 'example/testTopic', ... (53 bytes))
Hello Mqtt 2021年  8月 10日 火曜日 18:40:12 JST
```

## MQTTS

publish

```bash:go_pub_mqtts.sh
message="Hello Mqtt "`date`
mosquitto_pub -d -m "${message}" \
	-h  broker.emqx.io \
	 -p 8883 --capath /etc/ssl/certs/ \
	--topic example/testTopic
```

subscribe

```bash:go_sub_mqtts.sh
mosquitto_sub -d -h broker.emqx.io \
	 -p 8883 --capath /etc/ssl/certs/ \
    --topic example/testTopic
```

## 確認したバージョン

```text
$ mosquitto_pub --version
mosquitto_pub version 2.0.18 running on libmosquitto 2.0.18.

$ mosquitto_sub --version
mosquitto_sub version 2.0.18 running on libmosquitto 2.0.18.
```
MODXメモ

#MODXメモ
随時更新予定

##ID指定で呼び出す
```
[*見出し@6*]
```
ID:6のテンプレート変数「見出し」を呼ぶ

##URLを取得
```
[~306~]
```
ID:306のURLを取得

##コメントアウト
```
<!--@IGNORE:BEGIN-->
内容
<!--@IGNORE:END-->

```
HTMLソースにも表示されないコメントアウト


##条件分岐
```
<@IF: [*メール*]>
<a href="mailto:[*メール*]">[*メール*]</a>
<@ELSE>
なし
<@ENDIF>
```
テンプレート変数「メール」の中身が空なら「なし」と表示する


#スニペット＜作成系＞
##リソースIDからURLを取得
```
$url = $modx->makeUrl($docid, '', '', 'full');

結果：
https://～～
```
OData vs REST 両者の違いとは？

これまで、システム間の通信条件を定義するためのプロトコルや標準が数多く登場してきました。これらのテクノロジーをみていくと、ODataとRESTという2つのキーワードに出くわしたことがあるかもしれません。

ODataとRESTは密接に関連した概念ではありますが、全く同じものではありません。このブログでは、「RESTとは何か？」と「ODataとは何か？」とともに、両者の違いについて解説します。

#RESTとは？
REST (REpresentational State Transfer) は、HTTP プロトコルを使用して2つの異なるシステム間でメッセージを送信する方法を定義するソフトウェアアーキテクチャスタイルです。20年前にRoy Fieldingによって開発されたRESTは、World Wide Web上で情報を交換するための最も一般的なアーキテクチャに成長しました。

REST標準は、Webサービスのための6つの異なる原則やアーキテクチャ上の制約を概説しています。

- **統一されたインターフェース**：RESTシステム内のすべてのコンポーネントは、お互いに通信するために同じルールとインターフェースに従わなければなりません。各リソースは URIによって一意に識別されます。
- **クライアント-サーバー**：RESTでは、情報の保存と送信に関わるサーバと、情報の取得と適切な利用に関わるクライアントを分離しています。この分離により、両者の独立性と拡張性を高めることができます。
- **ステートレス**：RESTを使用して行われるすべてのリクエストはステートレスです。リクエストが完了した後、サーバーはパラメータや状態を保存する必要がありません。例えば、クライアントが制限されたリソースへのアクセスを要求した場合、クライアントはリクエストを行うたびに認証トークンをサーバに送信しなければなりません。
- **キャッシュ可能**：RESTのクライアントとサーバーの両方でリソースをキャッシュすることができ、トラフィックを減らしてパフォーマンスを向上させることができます。
- **レイヤードシステム**：クライアントはシステム内の1つのサーバとのみ通信し、他のサーバは認証やデータ保存などの機能を実行します。クライアントは、エンドシステムと通信しているのか仲介者と通信しているのかを見分けることができません。
**コード・オン・デマンド**：これは必須の原則ではありませんが、RESTリクエストは必要に応じてロジックや実行可能なコードを返すことができます。

上記の原則を守ったAPIをREST（またはRESTful）APIと呼びます。

#ODataとは？
ODataのウェブサイトによると、OData（Open Data Protocol）は「RESTful APIの構築と使用のためのベストプラクティスを定義しています。ODataは、リクエストヘッダとレスポンスヘッダ、ステータスコード、HTTPメソッド、URL規約、メディアタイプ、ペイロードフォーマット、クエリオプションなどを定義するための様々なアプローチを気にすることなく、RESTful APIを構築しながらビジネスロジックに集中できるようにします。」

マイクロソフトで最初に作成されたODataは、非営利コンソーシアム [OASIS (Organization for the Advancement of Structured Information Standards)](https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=odata) によって標準化されました。IBM、SAP、Salesforceなどの巨大テクノロジー企業は、いずれも社内のIT環境でODataを使用しています。

ODataの最も重要な構成技術はRESTです。OData 3.0標準によると、ODataのユーザーは 「正当かつ具体的な理由がない限り、RESTの原則に従うべきである」とされています。

OData標準は、RESTリクエストに応答してデータを転送するために使用されるデータモデルも定義しています。ODataはデータ転送のために2つの異なるプロトコルをサポートしています。XMLベースのAtomフォーマット（ウェブリソースの公開と編集目的）とJSON（人間が読める形でのデータの保存目的）です。

最後に、変更のトラッキング、再利用可能なプロシージャの定義、複数（バッチ）のRESTリクエストの送信などのアクションを実行する方法についてのガイダンスが含まれています。

#両者の違いをまとめると？
前述した内容を整理すると、ODataとRESTの違いは次のようになります。

- RESTはHTTPプロトコルで情報をやり取りするためのアーキテクチャスタイルです。REST標準は、あらゆるREST APIが遵守しなければならない6つの原則（1つはオプション）を定義しています。
- ODataはRESTフレームワークの上に構築され、HTTPメッセージ形式やAPIのクエリ方法など、REST APIを構築するためのベストプラクティスを定義しています。ODataはユーザーに常にRESTの原則に従うことを推奨していますが、やむを得ない理由がある場合は、この要件を緩和することができます。さらに、ODataでは、データはAtomまたはJSON形式で転送することを指定しています。

ちなみにXplentyのRest APIコネクターは、Rest APIだけでなく、ODataへも接続可能です。
XplentyからどのようにOdataへ接続し、データを取得できるかに興味のある方は、[こちらのブログ](https://qiita.com/Azabu10ban/items/d29d0f4c7021dbc91520)をご覧ください。
amplify-authenticator のサインアップを無効化する方法メモ

## はじめに

ユーザーの登録は管理者側で行いたいので、amplify-authenticator(@aws-amplify/ui-vue) のサインアップリンクを無効化しようとしてハマったのでメモを残す。

`isSignUpDisplayed: false` を食わせれば良いという記事はたくさんあるが、
肝心の食わせ方がまちまちでなかなか適用することができなかった。

## 結論

```vuejs
<template>
  <amplify-authenticator>
    <amplify-sign-in slot="sign-in" hide-sign-up="true"></amplify-sign-in>
    <amplify-sign-out></amplify-sign-out>
  </amplify-authenticator>
</template>
```

`amplify-sign-in` に `slot="sign-in" hide-sign-up="true"` を渡すことで無効化できた。

## 参考リンク

https://github.com/aws-amplify/docs/issues/1653
PowerAutomateで祝日の判定を自動化する

# あらすじ
`PowerAutomate`で祝日の判定をしたいが、祝日マスタのようなものを持つと手動メンテナンスが必要なので面倒・・・
何か自動で判定する方法ないかな？

ということで、便利な方法を考えました。
# 祝日判定の方法
`Googleカレンダー`に、`日本の祝日`という便利なカレンダーが存在します。
それを利用し、祝日の判定を`Googleカレンダー`側へ委譲します。

1. `Googleカレンダー`の`日本の祝日`カレンダーから、今日の0時～1時のデータを取得する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352434/a6b7d929-bedd-7c03-7c8f-4c5f474aecb4.png)  
※`変換後の時間`となっているのは`PowerAutomate`側が`UTC`なので`JST`に変換しています。
1. データが取得できた場合は、今日は祝日ということが判断できる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352434/dc0ee3ee-378e-2b74-c85e-fb941dbb4c25.png)
データが取得できたかどうかの判定は以下のように、取得データの件数にて判断しています。  

>length(outputs('カレンダーのイベントの一覧を表示する')?['body/items'])

# まとめ
`Googleカレンダー`を活用して祝日判定を楽しよう！
楽しい自動化ライフを！
CentOS7 laravelをインストールしてアプリを作成する

# 目的

- CentOS7にlaravelをインストールしてアプリを作成する方法をまとめる

# 条件

- 下記作業が全て完了していること。
    - [CentOS 7 selinuxを無効化する](https://qiita.com/miriwo/items/64950324c86d4e542542)
    - [CentOS7系にChromeをインストールする](https://qiita.com/miriwo/items/9b43678bec462c8db70f)
    - [CentOS7 Apacheを使ったWebサーバを立てる](https://qiita.com/miriwo/items/a3fe176d45c9032f2d0f)
    - [CentOS7 MySQLを入れてデータベースを作成する](https://qiita.com/miriwo/items/2d5ad51df95ad6671b36)
    - [CentOS7 Laravel環境構築のためにPHP7.4をインストールする](https://qiita.com/miriwo/items/04326679e95420be0670)
    - [CentOS7 Composerをインストールする](https://qiita.com/miriwo/items/b4dcf5cb4250fcca89ea)

# 情報

- 今回はあくまでCentOS7のPCにlaravelをインストールしてアプリを作成しローカルサーバを起動する方法をまとめる。
- CentOS7に立てたApacheでlaravelアプリを起動させる方法とは別なので注意していただきたい。
- 各ソフトバージョンを下記に記載する。

    | 項目 | 情報 |
    | --- | --- |
    | MySQL | 8.0.23 |
    | PHP | 7.4.14 |
    | Composer | 2.0.8 |

# 方法

1. 下記コマンドを実行してlaravelをインストールする。

    ```terminal
    $ composer global require laravel/installer
    ```

1. 下記コマンドを実行してtestという名前のlaravelアプリ（laravelプロジェクト）を作成する。

    ```terminal
    $ cd
    $ laravel new test
    ```

1. 下記コマンドを実行して作成されたアプリ名ディレクトリに移動する。

    ```terminal
    $ cd test
    ```

1. 下記コマンドを実行してローカルサーバを起動する。

    ```terminal
    $ php artisan serve
    ```

1. 下記にアクセスする。
    - [http://127.0.0.1:8000](http://127.0.0.1:8000)
1. 下記画面が表示されていたらアプリの作成は完了である。（下記はMacで環境構築を行った際の[http://127.0.0.1:8000](http://127.0.0.1:8000)の表示であり細部が異なる可能性がある。あくまでイメージとして確認していただきたい。）

    ![ウィンドウ_と_Laravel.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/fe043370-77f0-bdcd-9f17-382ca01ed362.png)
movable type のローカル環境を作る

movable typeの環境構築が難しく4989していましたところ、sixapartから簡単に環境作れるよという記事を発見しました。
https://www.movabletype.jp/blog/mt-dev.html<br>
設定について<br>https://github.com/movabletype/mt-dev/blob/master/README.ja.md

<h2>環境</h2>
* mac/ macOs Mojave ver.10.14.6
* github
* Docker (Docker for Mac)

<h2>構築準備</h2>
* githubアカウント作成
* sshでgithubのmovabletypeのブランチにつなげるようにしておく
* movabletypeの<a href="https://www.sixapart.jp/inquiry/movabletype/personal_download.html" target="_blank">個人無償版</a>を入手しておく
* <a href="https://docs.docker.jp/docker-for-mac/install.html" target="_blank">dockerのセットアップ</a>


<h2>構築</h2>
<h3>READMEの手順に進めていく。</h3>
* githubからクローンする<br>*クローンする場所は任意で決めてください。<br>

```
$ git clone git@github.com:movabletype/mt-dev.git mt-dev
$ cd mt-dev
```

* 用意した無償版のMTをクローンしたファイルにコピーする

```
$ cp /path/to/MT7-R0000.zip archive/
```

* mt-config.cgi.originalからmt-config.cgi.localを作成してlocalhostに変更

```
CGIPath    http://192.168.7.25/cgi-bin/mt/
↓
CGIPath    http://localhost/cgi-bin/mt/
```
```
StaticWebPath    http://192.168.7.25/mt-static
↓
StaticWebPath    http://localhost/mt-static
```
* 起動
セットアップのコマンドを実行してMTを起動させます
READMEに記載してあるRECIPE=mt-plugin-My-AwsomePluginは独自で作成したプラグインを起動する場合のオプションで、dockerで起動する場合はRECIPEではなくREPOオプションがいいらしい。

```
$ make up ARCHIVE=MT7-R0000.zip  MT_CONFIG_CGI=mt-config.cgi-local
```

* データベース作成

```
$ make exec-mysql SQL='CREATE DATABASE mt /*!40100 DEFAULT CHARACTER SET utf8mb4 */'
```

* ブラウザで設定画面にアクセス

``
http://localhost/cgi-bin/mt/mt.cgi
``

![スクリーンショット 2021-01-25 9.33.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376588/cf93f50d-c122-92a6-d3ae-7ce07bcb557b.png)


<h2>参考</h2>
[@noritakaIzumiさんのMovable Type 公式の開発環境を Docker で構築してみた](https://qiita.com/noritakaIzumi/items/294308b7cb31718f155a)
すごく参考にさせてもらいました。
MSAL(Microsoft Authentication Library)を使用したSSOにおけるアクセストークンの有効期限について

# 背景
師いわく、MSALを使用してSSOを行うと、アクセストークンの有効期限が1時間だから
1時間毎に再認証が必要で、スマホ使っている人がアカウントを再選択する必要があるらしい。

ほんまか？
って思ったんですけど、ちゃんと調べた事は無かったので調査しました。

# 結論
1時間毎に再認証する必要はない。
ドキュメントから、デフォルト90日間連続して操作しなかった場合には再選択が必要になる。

# ドキュメント調査
以下のリファレンスには期限切れが近いトークンを更新できると記載がある。
https://docs.microsoft.com/ja-jp/azure/active-directory/develop/msal-acquire-cache-tokens#acquiring-tokens-silently-from-the-cache
> また、期限切れが近いトークンを更新することもできます (トークン キャッシュには更新トークンも含まれるため)。

また、以下のページではトークンの有効期限が記載されている。
https://docs.microsoft.com/ja-jp/azure/active-directory/develop/active-directory-configurable-token-lifetimes

デフォルト値は以下の通り
アクセストークン：1時間
更新トークン：90日間

イメージとしては [ここ](https://jpazureid.github.io/blog/azure-active-directory/aad-token-lifetime/#ADAL-%E3%82%AF%E3%83%A9%E3%82%A4%E3%82%A2%E3%83%B3%E3%83%88%E3%81%AB%E3%82%88%E3%82%8B%E8%AA%8D%E8%A8%BC%E3%83%95%E3%83%AD%E3%83%BC%E3%81%A8%E6%9C%89%E5%8A%B9%E6%9C%9F%E9%99%90%E3%81%AE%E8%80%83%E3%81%88%E6%96%B9) のブログに乗っている図がわかりやすい。(書いてあるのはADALの話だけど大きくは変わらないでしょう)


また、具体的な実装としては
`acquireTokenSilentAsync(scope, authority, callback)`
メソッドを呼び出すことで、アクセストークンをユーザに通知することなく取得する事ができる。
https://javadoc.io/doc/com.microsoft.identity.client/msal/2.0.2/com/microsoft/identity/client/ISingleAccountPublicClientApplication.html

```
Perform acquire token silent call.
If there is a valid access token in the cache, the sdk will return the access token;
If no valid access token exists, the sdk will try to find a refresh token and use the refresh token to get a new access token.
If refresh token does not exist or it fails the refresh, exception will be sent back via callback.
```
> トークンのサイレントコールの取得を実行します。
> キャッシュに有効なアクセストークンがある場合、SDKはアクセストークンを返します。
> 有効なアクセストークンが存在しない場合、SDKは更新トークンを見つけようとし、更新トークンを使用して新しいアクセストークンを取得します。
> 更新トークンが存在しないか、更新に失敗した場合、例外はコールバックを介して返送されます。

なので以下のような実装をすればトークンを自動的に更新できるはず。

``` java
ISingleAccountPublicClientApplication pca = ...; // 適当に取得する
IAccount mAccount = ... // サインインして取得
SilentAuthenticationCallback callback = ... // 適当にインターフェースを実装する
pca.acquireTokenSilentAsync({"user.read"}, mAccount.getAuthority(), callback);
```

結論として、1時間毎に再認証する必要はなく
デフォルトでは90日間ずっとアクセスしなかった場合に、スマホ利用者がADアカウントを再選択する必要がある。
【Python】データベースがいらない！？gspreadが便利！

#概要
つい、先日Twitterにて
「あ〜、Herokuのデータベース無料枠に収まりきらない」
とか、
「わい、クレカ持ってないからHerokuのデータベース使えないのだが」
みたいな投稿を見掛けました。

お、それだったらSpreadSheetで管理すればいいやん。って思ったので
PythonからHerokuでも使えるSpreadSheetの操作方法の解説です。

#Gspreadとは何ぞや？
Google社が提供するspreadsheetをPythonから管理できるモジュールのこと


##環境

Python 3.9.1

gspread
(インストール)

```
pip install gspread
```

oauth2client
(インストール)

```
pip install --upgrade oauth2client
```

#事前準備
詳しい説明は省きますが、
[GDC](https://console.developers.google.com/cloud-resource-manager?pli=1)にアクセスしてプロジェクトを作成し、
- spreadsheetAPI
- GoogleDriveAPI

を有効にし、サービスアカウントを作成します。
認証情報キーはJson形式でダウンロードしておいてください。

——
データベースとしたいSpreadsheetを作成します。
そして、そのURLの/d/の後の部分(以下:ワークブックID)をあとあと使うので、記録しておく。

右上の`共有`というボタンから先程のサービスアカウントメールアドレスを追加し、編集者の権限を与えておく。


#何でスプレッドシートが便利なの？

① スプレッドシート上で参照やソートを行えるため、コードを略せる。

②ドライブ上に保存してあるので、スマホからもアクセスできる

③手動更新も簡単にできる。

④デザインや見た目を工夫することで見やすいデータベース代わりになる。

⑤共同編集が楽

#実装
認証情報jsonはプロジェクトフォルダに移動させ、名前をkey.jsonなどとわかりやすい名前にしておくことを推奨します。

なお、今回はそれぞれの処理がわかりやすいようにclassにまとめます。

```spread.py
import gspread
from oauth2client.service_account import ServiceAccountCredentials 

import json

class SpreadSheet():
  #初期化(認証情報読み込み,ワークブックID指定)
  def __init__(self,ID:str):
    self.id = ID
    #リフレッシュトークンを1時間ごとに生産する必要があるのをを回避
    scope = ['https://spreadsheets.google.com/feeds','https://www.googleapis.com/auth/drive']
    #認証情報を読み込み
    credentials = ServiceAccountCredentials.from_json_keyfile_name('key.json', scope)
    #APIへログイン
    self.gc = gspread.authorize(credentials)

  #spread sheetへアクセス
  def access(self):
    res = self.gc.open_by_key(self.id)
    return res
  
  #スプレッドシートのワークシートを開く
  def read_sheet(self,sheet:str):
    #アクセス
    book = self.access()
    sheet = book.worksheet(sheet)
    return sheet
  
  #セルを指定してデータを取得
  def get_val(self,cell:str):
    sheet = self.read_sheet('シート1')
    val = sheet.acell('A1').value()
    return val
    
  #セルの値を更新
  def update(self,cell:str,text:str):
    sheet = self.read_sheet('シート1')
    sheet.update_acell(cell,text)
```

メイン部分の実装をします、
例えばこの場合、水道料金を取得するものを作りましょう
水道の価格帯をスプレッドシートにまとめます。

**シート1**

|行/列 | A | B |
|:-:|:-:|:-:|
| 1 | 1 | 4810 |
| 2 | 2 | 4870 |
| 3 | 3 | 4940 |
| 4 | 4 | 5010 |
| 5 | 5 | 5090 |
...
やけに高い水道ですね。

```main.py
from spread import SpreadSheet

s =SpreadSheet('my spreadsheet id')

use = int(input())
fee = s.get_val(f'B{use}')
print(f'{use}㎥の水を使用した場合料金は{fee}円になります。')
```

spreadsheetの機能としては十分だと思います！
容量も取らないので、

以上です。
table列の幅を変更できる方法をedgeで試すと古いedgeだとうまくいかない

tableの列幅変更を実装したところ、chromeではうまくいくが、
edgeで効かない。。


```css
.customtable thead td{
	resize: horizontal;
	overflow: hidden;
}
```

```html
<table class="customtable">
<thead >
	<tr>
		<td>HOGE</td>
		<td>FUGA</td>
	</tr>
</thead>
<tbody>
<tr>
	<td>
		<textarea>ほげ</textarea>
	</td>
	<td>
		<textarea>ふが</textarea>
	</td>
</tr>
</tbody>
</table>
```
chromeだと、サイズ変更用のマークが表示されるが、edgeだとこれが表示されず、
幅変更もできない。
【chromeで確認】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653035/1c5bebba-362f-e6dd-03a9-e3876a08924f.png)

こちらにedgenのバージョン79以降だとOKと書いてある。
https://developer.mozilla.org/ja/docs/Web/CSS/resize

で、自分の環境を調べてみると。ver44だった。。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653035/391f057d-eeef-674e-9a7e-a9910e61e4f0.png)


edgeのバージョンを上げて確認
https://answers.microsoft.com/ja-jp/microsoftedge/forum/msedge_other-msedge_win10/%E3%82%AA%E3%83%95%E3%83%A9%E3%82%A4%E3%83%B3/30cde173-deec-4bc0-a03c-9e1b86f95abe

結果：edgeでもchromeと同様サイズ変更できた。
ECSの環境変数に悩んだ末の結論


# ECSの環境変数（CI/CD,IaC含む）
これまでAKSやECS(Fargate、EC2)を構築してきてずっと悩んでいた環境変数の自分的結論を書こうと思います。
ご参考になったり、より良い方法を教えて頂ければ幸いです。

##◼️環境

|サービス概念|サービス |
|:---:|:---:|
|コンテナ環境|ECSのFagate|
|CI/CD|github,codepipeline(codebuild,codedeploy)|
|IaC|Terraform|

##◼️環境変数には２つの考え方がある

環境変数にはconfigとsecretの考え方があると思います。
configは各環境によって変更する必要のあるパラメータのこと。
secretは各環境によって変更する必要のあるパラメータであり、セキュアな情報をして保護する必要のある情報のこと。

2つの考え方を基にしつつ、AWS特有のパラメータに対して個別対応していく必要があります。

| 大項目 | 中項目 | 説明 |
|:-:|:-:|:--|
| 環境変数 | Secret  | パスワード類。セキュリティエンジニア、SRE、インフラエンジニアが守る  |
| 環境変数 | Config  | .envで設定。アプリケーションエンジニアが管理する |
| 環境変数 | Config  | .envで設定できないAWSのパラメータ。例えばIaCで作成したRDSのHost情報などAWSリソースを作成した後に分かる情報。セキュリティエンジニア、SRE、インフラエンジニアが守る  |

##■環境変数を設定できるのは3か所ある
+ IaCに必要な環境変数　　　 ⇨　TerraformやCDKで設定できる環境変数
+ CI/CDに必要な環境変数　　 ⇨　CodebuildやGitAcrionで設定できる環境変数
+ サービスに必要な環境変数　⇨　.envに記載

##■ECSはTaskdefで環境変数をSSMから取得する
ECSはFargate,EC2に関わらず、taskdef.jsonでパラメータを設定できます。
Secretとenvironmentの二つの設定方法がありますが、configは.envに全て寄せてアプリケーション側管理とするため、Secretのみ設定をします。
SSMパラメータをしてするので実際の値は入らないため安心です。

#実行例
##IaCに必要な環境変数
###AWS自動パラメータはSSMで取得する（String,SecureString）
TerraformでSSMを設定する方法

```tf:ssm.tf
locals {
  secret_parameter = {
    #Secret情報
    "SSM_DB_PASSWORD" = var.DB_PASSWORD
  }
  config_parameter = {
    #Config情報
    "DB_HOST" = aws_rds_cluster.<自身のリソース定義名：main>.endpoint
  }
}
resource "aws_ssm_parameter" "secure_string" {
  for_each = local.secret_parameter
  name      = each.key
  value     = each.value
  type      = "SecureString"
  overwrite = true
}
resource "aws_ssm_parameter" "string" {
  for_each = local.config_parameter
  name      = each.key
  value     = each.value
  type      = "String"
  overwrite = true
}
```
以下のようにTerraform環境を作っている。（exportでも同様に設定可能）
https://qiita.com/Tocyuki/items/0cb655e6357d9bf0c40f

```txt:.env(tf)
TF_VAR_DB_PASSOWRD = <DBパスワード：****>
```
```tf:variabes.tf
#.envで指定したTF_VAR_がとれて代入される
variable "DB_PASSOWRD" {}
```
```tf:main.tf
DB_PASSOWRD = var.DB_PASSWORD
```
##CI/CDに必要な環境変数
###CodeBuildのパラメータはTerraformのvariables.tfで設定する
```tf:codebuild.tf
resource "aws_codebuild_project" "admin_project" {
'''
  environment {
    '''
    #Codebuildはimageをインストールする場合エラーになることがあるため、Dockerアカウントを作成しておくこと。
    #https://aws.amazon.com/jp/premiumsupport/knowledge-center/codebuild-docker-pull-image-error/
    environment_variable {
      name  = "DOCKER_HUB_USER"
      value = var.DOCKER_HUB_USER
    }
    environment_variable {
      name  = "DOCKER_HUB_PASSWORD"
      value = var.DOCKER_HUB_PASSWORD
    }
}
```
###TaskdefでSSMを呼びだして設定する
```tf:taskdef.json
#SSMで指定したkey名を見に行ってくれる。（同一アカウント同一リージョンの場合）
#secret情報、config情報関わらずSSMから値を取得する場合は"secret"内に定義する
"containerDefinitions": [
  {
    "secrets": [
        {
            "name": "DB_PASSOWRD",
            "valueFrom": "SSM_DB_PASSOWRD"
        },
        {
            "name": "DB_HOST",
            "valueFrom": "SSM_DB_HOST"
        }
  }
]
```
##サービスに必要な環境変数
###.envに記載する
```txt:.env(app)
DB_CONNECTION=mysql
DB_HOST=<taskdefで値を上書き>
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=app-user
DB_PASSWORD=<taskdefで値を上書き>
```
`python -m easy_install pip` now installs pip incompatible with Python2 (specify pip~=20.0)

pip 21.0 has been released on Jan 23 (2021). It is not compatible with Python2. However, `python -m easy_install pip` now installs pip 21(.0). This will be a problem when we want to use latest pip while python-setuptools is provided by system package.

For now, `python -m easy_install 'pip<21'` seems working.

---

210311: maybe `python -m easy_install 'pip~=20.0'` is better as system-pip needs to be updated.
[JavaScript] 実は使えるようになっていた、論理積代入 (&&=)と論理和代入 (||=)とNull 合体代入 (??=)

皆さんが待望していた（？）演算子が実は使えるようになっています！（ただし、IEは除く）
無くても困らないが、ちょっと助かったりするそんな演算子たち。
早速どんな機能なのかをサッと確認していきましょう。


## [論理積代入 (&&=)](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Logical_AND_assignment)

> 論理積代入 (x &&= y) 演算子は、x が truthy である場合にのみ代入します。

```js
let truthy = true;
let falsy = false;

truthy &&= false; // => false
falsy &&= true; // => false
```

ちなみに、truthyな値とは[falsy](https://developer.mozilla.org/ja/docs/Glossary/Falsy)な値以外のことを指します。
`0`、`""`(空文字)、`false`、`NaN`、`null`、`undefined`はfalsyって覚えておけば、ほぼ大丈夫です。


## [論理和代入 (||=)](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Logical_OR_assignment)

> 論理和代入演算子 (x ||= y) は、x が falsy である場合にのみ代入します。

```js
let truthy = true;
let falsy = false;

truthy ||= false; // => true
falsy ||= true; // => true
```

論理和演算子(||)の短略評価を利用した、値を代入するやつが若干スッキリしますね！

```js:例
// val => ""
const val = val || "default" // => valに"default"が代入される
const val ||= "default" // => 上記と同じ結果
```

## [Null 合体代入 (??=)](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Logical_nullish_assignment)

> Null 合体代入 (x ??= y) 演算子は、x が nullish (null または undefined) である場合にのみ代入を行います。

```js
let nullish1 = null;
let nullish2 = undefined;
let truthy = true;
let falsy = false;

nullish1 ??= "nullish"; // => "nullish"
nullish2 ??= "nullish"; // => "nullish"
truthy ??= "nullish"; // => true
falsy ??= "nullish"; // => false
```

論理和代入のスコープが狭まった感じですね。
nullishである場合にのみ代入されるってのを上手く使える場面で使用していきましょう。

```js:例
// val => null 
val == null ? "" : val; // => ""
val ??= ""; // => 上記と同じ結果
```

## 参考
https://developer.mozilla.org/ja/docs/Web/JavaScript
○○まで後何日？アプリを作成してみた

jsのDateオブジェクトは使いにくいのでmoment.jsというライブラリを使って作成する。

日付はドラえもんが生まれる日に設定した。

```js
var timer //タイマー設定

const will = moment("2112-09-03 12:00")//日付選択

const doraemon = document.createElement("p")//要素作成
const body = document.querySelector('body');//親ノード取得
body.appendChild(doraemon)//子ノード追加




function count() {
    let date = moment();
    let secondLeft =(will.diff(date,"second")%60)
    let minuteLeft=(will.diff(date, "minute") % 60)
    let hourLeft=(will.diff(date, "hour") % 24)
    let dayLeft=(will.diff(date, "days") % 24)
    let monthLeft=(will.diff(date, "month") % 12)
    let yearLeft=(will.diff(date, "year"))
    doraemon.textContent = `ドラえもんが生まれるまで後${yearLeft}年${monthLeft}${dayLeft}日${hourLeft}月${minuteLeft}分${secondLeft}秒`
}

count()
timer = setInterval("count()", 1000)
```
manimの作法 その29

#概要

manimの作法、調べてみた。
九九、やってみた2。

#サンプルコード


```
from manimlib.imports import *

class test(Scene):
	def construct(self):
		for x in range(9):
			for y in range(9):
				A = TextMobject("{} x {} = {}".format(x + 1, y + 1, (x + 1) * (y + 1))).scale(3)
				A.shift(UP * 3)
				self.play(ShowCreation(A))
				for i in range(y + 1):
					for j in range(x + 1):
						X = i * 0.5 - 3
						Y = 2 - j * 0.5
						self.add(Dot(point = np.array([X, Y, 0.0])))
					self.wait(0.2)
				self.wait()
				self.clear()




```

#生成した動画

https://www.youtube.com/watch?v=3-99Uvp-YAQ

以上。
MacbookProの5GHzWifiの不調解消

ググって色々やったけど解消しなかった症状が、小康状態になったので自分用に記録。
→210128全面的に改稿
　→210131再発。降参。ルータをWSR-3200AX4Sに買い換え。
　　何の問題も無く解消。相性問題？処理能力の問題？
   →と思ったら買った翌日（2/1）にWSR-2533DHPのファーム1.07が出やがった。
　　 これ適用したら解消しやがった。まぁWPA3になったし若干早いし、と負け惜しみ。

----以下、役に立たないけど一応取っておく。----

●やったこと
・WiFiルータ側のチャンネルをチャネルボンディング分を含めてもW52に収まるように固定。
(80MHZなら36固定一択)

●今までの状況
・MBP2020intel。OSはCatalina。ルータはBuffaloのWSR-2533DHP （ファームは1.06）
・不定期に不調。アイコン等は接続状態なのにページの表示がやたらと遅くなる。
・同じWifiに接続しているiPhone,iPad,WindowsPCでは発生しないしMac不調時にも問題なし。
・2.4GHzでは発生しない。もちろん有線でも。
・Lan内のアクセスもできなくなり、IPであたりに行ってるNASも切断される（＝DNSの問題じゃないと推測）
・WiFiのオフ／オンで解消するも、不定期に不調にもどる。
・IPV6の設定やらリセット系やらルータのキー更新間隔変更やら色々やったけど解消せず。

●今までの設定
・DFSを嫌ってW52に固定していた。が、近隣に36がいたのでそこは避けていた。
・速度を出そうと考え帯域は80Mhz。

●原因の推測
・場所がらDFSをよく喰らうが、W52からはみ出す感じでチャネルボンディングしてる場合に52ch付近で食らった時のルータ側の挙動とMac側の挙動が相性悪い？
何故かiPhone、iPad、WinPCは問題ないのだけど。
32で80Mhzとか44で40Mhzとかにしとくと安定してる？
・DFSよく喰らうのは気のせいじゃなく、W53とかでチャネル固定しとくと、よく変わってる。

●今後の作戦
・今は32Chの80MHzで小康。
・ただし、そもそも発生が不定期なのでしばらく使ってみないと分からん。
・動画見てる時とかNASに重いファイル送ってる時が多いんだよなあ。
・ダメなら一旦帯域を40MHzとかにもしてみる。よそからの干渉も微妙に気になるし。40Mhzにしても実測で150Mbpsとか出るから実はそんなに困らないし。
・それでもだめならそろそろ買い替えどきかな。WPA3とかWiFi6とか気になるし。
【Java】StringBuilderの使い方　

#はじめに
本記事では2つ以上の文字列を連結させる際に使用するStringBuilderの使い方についてアウトプットします。

#+演算子で文字列結合する問題点
文字列結合で最も簡単な方法は+演算子を使うことですが、以下のような問題点があります。
・Stringインスタンスは不変 (値の変更ができない)
・＋によって連結が行われる場合、古いインスタンスは捨てられ、newによって新たなインスタンスが生成される
・大量の文字列を連結させる場合、JVMへの負担が大きくなる

この問題を解決するのがStringBuilderです。


#書き方
StringBuilderは可変なクラスとして設計されているため、newをしなくても文字列の連結が可能です。
そのためJVMへの負担が軽減され、処理が高速化します。

toStringメソッドで文字列ビルダーから文字列を取得する方法が一般的に推奨されています。

```java
StringBuilder sb = new StringBuilder();

sb.append("Hello ");
sb.append("Qiita!");

System.out.println(sb.toString());  //Hello Qiita!
```

#参照
[Java Platform SE8 StringBuilder](https://docs.oracle.com/javase/jp/8/docs/api/java/lang/StringBuilder.html)