OmniAICreator/Qiita-1.07M huggingface dataset:
読書要点「プリンシプルオブプログラミング」第3章 アーキテクチャ非機能要件

## アーキテクチャ非機能要件

ソフトウェアに対して求められる、機能面以外の要件のことである。
ユーザに使われること、これから先使われていくことを考えたときに非機能的な要件は大きなウェイトを占めるようになってくる。
機能要件と同様に重視されるべきものである。
非機能要件が発生する観点には以下のものがある。

- 変更容易性
- 相互運用性
- 効率性
- 信頼性
- テスト容易性
- 再利用性

アプリケーションの運用時の大きなトラブルは、パフォーマスンスやシステムダウンなど、非機能的な特性によるものが多い。
開発の中でも非機能要件の重要性を認識し、どれだけ非機能面が必要とされるかを確認を行い、テストまでしっかり行うべきである。


### 変更容易性

ソフトウェアがどれだけ改善しやすいか、ということである。
改善には、修正、拡張、再編成、別プラットフォームへの移行などが含まれる。
この改善を素早く、品質を落とすことなく行われることがソフトウェアに求められる。

変更容易性を確保するため、以下の要素について設計段階から抑えておきたい。

- 保守性
- 拡張性
- 再構築
- 移植性

変更容易性を意識しすぎるあまり、シンプルであることと競合を起こすことがあるため、どこが変更容易であるべきなのかを考えて設計を行うのがよい。

### 相互運用性

ソフトウェアが、他のソフトウェアとどれだけやり取りしやすいかということである。
外部APIを利用したアプリケーションのように、相互運用性が確保されていることによってソフトウェア間での連携が容易に行える。
他のソフトウェアの利用により用途の選択肢は広がり、接続性がよいほど連携の実装を行いやすくなる。

連携してもらいやすいアプリケーションを作成するためには、標準規格に則って開発を行うのがよい。

### 効率性

ソフトウェアがリソースを使用する際に、どれほど適切な性能を引き出せているかということである。
時間的な観点からみた時間効率性、コンピュータの持つ性能からみた資源効率性を考える。

コンピュータのリソースを節約するだけではなく、積極的に活用していくことで効率性が高いソフトウェアへ近づく。
設計の段階から性能を最大限引き出すことを意識したい。

### 信頼性

例外的な場面、予期しない方法での利用をされた際に昨日を維持する能力である。
信頼性には、以下の2つの側面がある。

- フォールトトレランス

障害に対して寛容であること、つまり障害が発生した際に正常な振る舞いを続けることである。
振る舞いは正常でありつつ、内部的には修正を行う。
内部的に冗長性をもたせたり、障害時に機能を絞って処理継続を優先するフェールソフトを考慮する。

- ロバストネス

堅牢であること、つまり不正な使用方法からソフトウェアを保護する能力である。
不正な利用法を想定し、システムとして定義してある状態へ移行するようにする。
障害時に問題が発生した箇所を切り離すフェールセーフ、あらかじめ障害を発生させうる操作を想定した設計を行うフールプルーフを考慮する。

状況次第でソフトウェアに求められる信頼性は異なるため、需要にあった設計を行う必要がある。

### テスト容易性

ソフトウェアに対して効果的に、効率的にテストを行う能力のことである。
効果的なテストとは、ソフトウェアの機能を漏らすこと無くしっかりと確認を行えるテストである。
効率的なテストは、テストの作成にかかるコストが少ないテストである。

ソフトウェアの品質の担保にはテストが欠かせない。
そのテストを容易に作成できることはソフトウェアの設計の段階から求められている。


### 再利用性

ソフトウェアの一部、もしくは全部を別のソフトウェアの開発に再利用しやすいかということである。
ソフトウェアを再利用するという立場と、再利用されるためのソフトウェアを開発するという2つの立場から考える。
開発に再利用を取り入れるためには、あらかじめ再利用を前提とした設計を行い、プラグインを取り入れるためのモジュールを作る。
再利用されるようなソフトウェアを開発する場合、自己充足的になるような設計を行い、全体でもモジュール単位でも独立してビルドできるようなパッケージにする。
できるだけ他のソフトウェアから技術を借りてくることで、時間短縮や品質の担保につながる。
[作業記録] 野良GCPプロジェクトを組織に移行する

# これはなんですか
- [[作業記録] Cloud IdentityでGCPの組織をつくる](https://qiita.com/Hikosaburou/items/856134eb160990534f32) の続きです。
- Gmailアカウントで作っていたプロジェクトをCloud Identity組織に移行しました。
- Cloud IAMと請求の権限周りの追加削除作業がちょっと怖かったので注意が必要です。


# 作業内容
[プロジェクトと請求先アカウントを移行し、権限を設定する](https://support.google.com/cloudidentity/answer/7389975?hl=ja&ref_topic=7555414) を参考に移行設定をしました。

- 野良のプロジェクトに組織管理者を追加する
    - 請求管理者
    - オーナー
- 組織管理者としてプロジェクトを開き、Gmailアカウントの権限を削除する (怖い)
    - 請求管理者
    - オーナー
- プロジェクトを組織に移行する


# 作業記録

## プロジェクトに組織管理者を追加する

Gmailアカウントでコンソールに入り、 **[お支払い]** > **[アカウント管理]** を開きます。組織管理者を請求先アカウント管理者に追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236562/e94e9025-9c26-f740-4b0a-da5740903de5.png)
**[IAMと管理]**を開きます。組織管理者をプロジェクトのオーナーとして追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236562/bb5fceff-cc9b-6501-60b4-6ff7ed661eae.png)
組織管理者に招待メールが送られるので、リンクを踏んで招待を受け入れます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236562/4f1e1b4a-3de2-1117-3e61-e82a6a2d52cb.png)

## Gmailアカウントの権限を削除する

組織管理者としてプロジェクトを開き、請求先アカウント管理者とIAMからGmailアカウントを削除します。ここで操作を誤ると**プロジェクトと請求先アカウントから締め出される**恐れがあります。注意して作業しましょう。

## プロジェクトを組織に移行する
**[IAMと管理]** > **[リソースの管理]** を開き、対象のプロジェクトを選択します。**[移行]** を選択してプロジェクトを組織に移行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236562/766c8138-4db5-af90-e3aa-c1505e19d628.png)


# まとめ
- 作業自体はシンプルだった。
- 権限管理で削除対象を誤ると締め出されかねないので注意が必要。

# 参考
GCPのドキュメントにも説明があったのでリンクを貼っておきます。 → [組織へのプロジェクトの移行](https://cloud.google.com/resource-manager/docs/migrating-projects-billing?hl=ja)
Virtual Chara開発 - その2

店舗接客などに使える仮想のキャラクターが扱えるアプリ開発をしました。そちらの説明はこちらになります。
https://qiita.com/NestVisual/items/fe4dd168178e27156682

環境：
Windows 10
Unity 2018.4.1
RealSense D435i

###Nuitrack：
![Nuitrack Activation Tool.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626158/0af4b897-0aa1-641d-99b5-43fdf1bb1371.png)

Nuitrackは3Dセンサーを扱うソフトで、主に全身骨格のトラッキング、顔のトラッキング、に焦点を当てていますが、ジェスチャー認識もあります。RealSense D435は、フロントページに掲載されているいくつかのサポートされている3Dセンサーの中に含まれています。
https://nuitrack.com/
また、Unityだけでなく、Unreal Engineのインストール方法やチュートリアルが記載された文書化ページもあります。
https://download.3divi.com/Nuitrack/doc/Installation_page.html

Nuitrackをインストールして、現在のプロジェクトに統合しようとしたところ、OpenCVと干渉してエラーが発生しました。シーン内でNuitrackを無効にするとエラーが消えていました。Nuitrackには顔トラッキングが付いているので、それを使って何ができるかを見てみようと思って、とりあえずNuitrackだけで新しいシーンを作ってみました。

![Character Movement.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626158/3d1b10a2-388f-0dad-2a70-9ab1ea648251.png)

すべてのチュートリアルの中で、「Animating the avatar using skeleton」というのが一番参考になりました。無料のUnityアセットストアモデルの "Unity chan "をNuitrackのトラッキングされたスケルトンでアニメーションします。 結果はかなり良いものになりました。チュートリアルでは、間接マッピングと直接マッピングの使用例が紹介されています。 間接マッピングは、モデルを歪めることなく、追跡された骨格の四肢の位置に基づいてキャラクターの四肢を移動させるので、このプロジェクトには最適だと思いました。直接マッピングは、モデルを歪めて、手足の真の位置をより正確に表現します。 このタイプは、VR ゲームなど、没入感が大切なものに適しているかもしれません。キャラクターの体との解離を感じないようにするためです。また、モデルが利用者に近い等身であれば、間接マッピングよりも見栄えが良いかもしれません。

###Vroid:
<img width="1440" alt="VRoid screenshot.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626158/794c4186-a0a3-e0f4-413f-aa74aac3c635.png">

Unityちゃんモデルとは別のモデルが使えるかどうかを確認するために、VRoidというアプリケーションを使ってみました。
https://vroid.com/en/
キャラクターをカスタマイズしてオリジナルにする機能があります。一時的に使うだけなので、プリセットキャラの一つをエクスポートしました。

「Unityちゃん」のモデルとかなり似たような設定します。全ての手足にコリダーが付属しています。ぶつかるたびにギクシャクした動きをしていたので、これで手足が体に入れるようになったとはいえ、個別に外しました。

次回はNuitrackのデバッグに関して投稿します。それではまた
サクラエディタの並べ替え＆重複削除の最強コンピ

１．メニュー＞編集＞整形＞選択行の昇順ソート、選択行の降順ソート、連続した行副行の削除
２．メニューバーへの追加
　「設定＞共通設定＞ツールバータブ」から追加可能

以上
AWS EC2のSSHがすぐ切れる時の対処方法

TerminalでAWS EC2に接続していると、すぐ接続が切れることがあります。
その時、EC2側の設定変更で接続がすぐ切れないようにする方法を紹介(メモ)します。
※ OSはAmazon Linux 2です。

### AWS EC2のSSHがすぐ切れる時の対処方法

#### 1. EC2のsshd_configを修正

```console

$ sudo vi /etc/ssh/sshd_config
```

Default値はこうなっています。

```shell
#ClientAliveInterval 0
#ClientAliveCountMax 3
```

2時間は接続を保ちたいので、以下のように変更します。

```shell 
ClientAliveInterval 60
ClientAliveCountMax 120
```


#### 2. sshd 再起動

```console
$ sudo service sshd restart
Redirecting to /bin/systemctl restart sshd.service
```


### 解説
- ClientAliveInterval 60 : クライアントが生きているかチェックを60秒毎に行う
- ClientAliveCountMax 120 : クライアントが生きているかチェックを最大120回カウントする

つまり、1分毎にチェックして、120回までは接続を解除しないことになります。
これで2時間接続出来るようになりました。

以上。
DockerでGitLabサーバーを立てる

今日も小ネタです。
何番煎じってネタですけど、つまづきポイントあったのでメモがてら。

構築セット一式はこちら → https://github.com/yagrush/docker-gitlab

# 必要環境

* Linux または Mac
    * メモリ：8GB以上推奨（←これが意外とハマりどころ…）
    * Docker
    * docker-compose

MacとLinux(on AWS)で動作確認済です。

Linux(on AWS)は「無料でええやろ」ってt2.microとかでやってて、「なんで動かねんだぁ…」ってハマりました…
t2.large（メモリ8GiB）にしたら無事動作。

Macに関してもご注意があり、
Docker Desktopをお使いの場合は、設定画面でCPUやメモリ使用可能量などを上げておいた方が良いです。

ちなみにWindowsではうまく動きませんでした。
時間があるときにまた調べてみようかな。

# 使い方

## 0. 構築セット一式をダウンロードする
```shell
wget https://github.com/yagrush/docker-gitlab/archive/master.zip -O docker-gitlab.zip; unzip docker-gitlab.zip; rm -f docker-gitlab.zip

#ついでにディレクトリを移動しておく
cd docker-gitlab-master
```

## 1. ポート:80 を他のソフトウェアですでに使用していたら

`docker-compose.yml` の 

```yaml
    ports:
      - 80:80
```

`- 80:80` の左側の `80` を 

```yaml
    ports:
      - 8081:80
```
とか他の番号に変えてあげてください。

## 2. ビルド＆起動する
```shell
docker-compose up -d
```

## 3. GitLab の WEB UIにアクセスしてみる

`http://構築したホストのアドレス:80`
↑ 必ずしもドメイン振ってる必要は無く、IP直打ちでもOK。
手順1.でポート変更してたら、`:80` を書き換えて下さいね。

成功すると、まずはじめに管理者ユーザー `root` のパスワード設定を求められるWEB画面が開きます。
設定しおわったらあらためて `root` でログインしてみましょう。

## もしエラー画面になったら

念のため１分くらい待ってから再度アクセスしてみてください。
（中で結構色々起動しているようで重いので、待てば起動するかもしれません。）

それでもダメだったら、何か問題が発生しているかもしれません。
ブラウザでFFMPEGを使えます

##はじめに

こんにちは streampack チームのメディです。
https://cloudpack.jp/service/option/streampack.html

<img width="333" alt="Screen Shot 2020-06-18 at 12.41.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229807/56641143-ad7c-de33-50c0-0a43ec630c3c.png">


###What is ffmpeg.wasms  ・  ffmpeg.wasmとは
**ffmpeg.wasm** is a library that allows you to use FFmpeg directly in your browser without any backend services.
**ffmpeg.wasm**は、FFmpegをバックエンドサービスなしでブラウザーで直接使用できるライブラリです。

###Objective　・　目的
Learning how to use **ffmpeg.wasm** via a simple example.
簡単な例で**ffmpeg.wasm**の使用方法を学びます。


###Implementation ・ 実装
You can use this example to convert **.mov** files to **.mp4** files (x264).
この例を使用して、**.mov**ファイルを**.mp4**ファイル（x264）に変換できます。

```html

<html>
<head>
  <script src="//cdn.jsdelivr.net/npm/@ffmpeg/ffmpeg@0.8.3/dist/ffmpeg.min.js"></script>
  <style>
    html,
    body {
      margin: 0;
      width: 100%;
      height: 100%
    }

    body {
      display: flex;
      flex-direction: column;
      align-items: center;
    }
  </style>
</head>

<body>
  <h3>Upload a video to transcode to mp4 (x264) and play!</h3>
  <video id="output-video" controls muted autoplay></video><br />
  <br>
  <input type="file" id="uploader">
  <p id="message"></p>
  <br>

  <div>
    <textarea id='log' rows=30 cols=100 autofocus></textarea>
  </div>

  <br>
  <script>
    var txt = document.getElementById('log');
    const {
      createFFmpeg
    } = FFmpeg;
    const ffmpeg = createFFmpeg({
      log: true,
      logger: ({
        message
      }) => {
        txt.value += "\n" + message;
      }
    });

    const transcode = async ({
      target: {
        files
      }
    }) => {
      const message = document.getElementById('message');
      const {
        name
      } = files[0];
      message.innerHTML = 'Loading ffmpeg-core.js';
      await ffmpeg.load();
      await ffmpeg.write(name, files[0]);
      message.innerHTML = 'Start transcoding';
      await ffmpeg.transcode(name, 'output.mp4');
      message.innerHTML = 'Transcoding completed';
      const data = ffmpeg.read('output.mp4');
      ffmpeg.remove('output.mp4');

      const video = document.getElementById('output-video');
      video.src = URL.createObjectURL(new Blob([data.buffer], {
        type: 'video/mp4'
      }));


    }
    const elm = document.getElementById('uploader');
    elm.addEventListener('change', transcode);
  </script>
</body>

</html>
```

###DEMO　・　デモ
https://codepen.io/mr1985/pen/jOWVeGN

###Information sources ・ 情報元
https://github.com/ffmpegwasm/ffmpeg.wasm
https://github.com/ffmpegwasm/ffmpeg.wasm/blob/master/docs/api.md
natbib, supplement for pyhsical review

Physical reviewに久しぶりに投稿しようとrevtexを入れたら，natbibを使いなさいって．あんまり馴染みがなくて，変に誤解していたので，installや使い方のまとめ．

あまりに短いんで，もう一つsupplementでいいsolutionがあったので，そいつもメモがわりに同じところへおかしてもらいます．

# natbib
## platex
でかくなってよね．しかも全部入れるのが普通って．
- natbib
をctanからダウンロードして，local directoryに入れようとしたが，natbib.styがないって．

```
 $ platex natbib.ins
```
で展開．

## 原稿
natbibはstyと言いながらちょと違う．

```
\usepackage{natbib}%
...
\bibliographystyle{apsrev4-1}
```
などとするべし．

どうも最初から入っていたようです．
usepackageが入ってなくて，ズーーとエラーが出てた．

# supplement material
英語校正の人がsupplementにすべきだっていうんで，やり始めたが意外と面倒そうに見えて．．．
でも解決して見るとめちゃ便利．要は一つの論文として扱う．supplementはappendixみたいなものって．内容考える時もこの考え方便利．

```
main.org + supple.org > 
main.tex + supple.tex >
revhead.tex + main.tex[0..-1] + supplehead.tex + supple.tex + "\end{document}
```

ここで作ったsupple_head.texです．

```latex
%%%%%%%%%% Merge with supplemental materials %%%%%%%%%%
\widetext
\clearpage
\begin{center}
  \textbf{\large
#+title
  }
\end{center}
%%%%%%%%%% Merge with supplemental materials %%%%%%%%%%
%%%%%%%%%% Prefix a "S" to all equations, figures, tables and reset the counter %%%%%%%%%%
\setcounter{section}{0}
\setcounter{equation}{0}
\setcounter{figure}{0}
\setcounter{table}{0}
\setcounter{page}{1}
\makeatletter
\renewcommand{\thesection}{S-\Roman{section}}
\renewcommand{\theequation}{S\arabic{equation}}
\renewcommand{\thefigure}{S\arabic{figure}}
\renewcommand{\thetable}{S\arabic{table}}
\renewcommand{\bibnumfmt}[1]{[S#1]}
\renewcommand{\citenumfont}[1]{S#1}
%%%%%%%%%% Prefix a "S" to all equations, figures, tables and reset the counter %%%%%%%%%%
```

- [Options for supplementary materials in preprint version: revTeX + arXiv
](https://tex.stackexchange.com/questions/168169/options-for-supplementary-materials-in-preprint-version-revtex-arxiv/551019#551019)

sectionは私のコメント．bibtexがおかしいのはな．PRはもともとsupplementだけの参照文献を認めてないようなので．．，そのまま放置．


# non-breaking tilde
Fig.のあとはspaceを入れるんですが，これを普通のspaceでやると変に間が空きます．そこで，ページブレークが入らないスペースということで'~'をlatexで入れます．ところが，org-modeでやるとおかしくなる．正解は

```
 Fig.\nbsp{}1
```
とやるそうです．

- [Tips/TeX/正しいマークアップ](http://www.info.kochi-tech.ac.jp/y-takata/index.php?Tips/TeX/%C0%B5%A4%B7%A4%A4%A5%DE%A1%BC%A5%AF%A5%A2%A5%C3%A5%D7)
- [How to make non-breaking spaces (ties) in Org-mode that exports properly to LaTeX](https://stackoverflow.com/questions/9311538/how-to-make-non-breaking-spaces-ties-in-org-mode-that-exports-properly-to-late)
EKSのワーカーノードのバージョン更新時にPodDisruptionBudgetの挙動でハマったこと

## 概要

EKSクラスタをv1.14からv1.15にバージョンアップする検証を開発環境で行なった際にハマったことを紹介します。
バージョンアップ手順は基本的にAWSから提供されている以下の公式ドキュメントにしたがって実施しました。
[Amazon EKS クラスターの Kubernetes バージョンの更新](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/update-cluster.html)
環境情報として、ワーカーノードタイプはマネージド型、コンピューティングタイプはEC2です。

## ノードグループ更新時にエラー発生

上記のリンク内の手順の13を見ると、[マネージド型ノードグループの更新](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/update-managed-node-group.html)へのリンクがあるため、これに従ってAWSのマネジメントコンソールからノードグループを更新したところ、以下のようなエラーが発生しました。

<img width="1089" alt="エラーメッセージ.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316261/f768742f-5512-7997-308b-4ca9f5381983.jpeg">

エラーコードに `PodEvictionFailure` とあることから、既存のノードから新しいバージョンのノードにpodを移動する際の排出処理に失敗したのだろう、ということがわかります。

## PodDisruptionBudget設定時のpod排出時の挙動

podの排出処理に関わる設定なので、PodDisruptionBudgetにあたりをつけて検証しました。
PodDisruptionBudgetはノードからpodを排出する際、最低限確保したいpod数を保証する設定値です。

関連していそうな当該環境の設定値は以下の通りです。
この設定値は開発環境のものであるため、コスト重視でpod数は控えめに設定しています。

|オブジェクト種別|設定項目|設定値|
|:--|:--|:--|
|HorizontalPodAutoscaler|maxReplicas|2|
|HorizontalPodAutoscaler|minReplicas|1|
|PodDisruptionBudget|minAvailable|1|
|Deployment|strategy|rollingUpdate|
|Deployment|strategy.rollingUpdate.maxSurge|1|
|Deployment|strategy.rollingUpdate.maxUnavailable|0|

この設定でpodの排出時に以下のような挙動になることを期待しました。

### 期待した挙動（実際にはならなかった）
#### 1.更新前のノードに1podが起動中、更新後ノードが起動
![part1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316261/100e6c4f-b0ee-1cf8-3401-ea20f7fdbfa9.png)

#### 2.更新前ノードのpodが起動したまま、更新後ノードに新規podが起動
![part2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316261/eefdfa8c-7d96-41a8-c7c7-2386e31bd1ae.png)

#### 3.更新前ノードのpodが停止
![part3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316261/6c730581-ebcd-647f-b6cc-155128d00e5e.png)

しかし実際にはこのような挙動にはならず、上述のエラーが発生しました。
（エラーになるまで1時間半程度かかったので、すごく徒労感を感じました。）

PodDisruptionBudgetのminAvailableはpodの最低数を保証するもので、保証できなければそのままエラーで排出処理を停止する、という挙動になりました。決してpodの数を保証するためにスケールアウトしたりはしないようです。


## 事前にpod数を増やして再度実行

podの排出が可能な余白を作ってあげれば良さそうなので、minReplicasを1から2に増やして再度実行しました。
設定値としては以下のようになります。赤字箇所が変更点です。

|オブジェクト種別|設定項目|設定値|
|:--|:--|:--|
|HorizontalPodAutoscaler|maxReplicas|2|
|HorizontalPodAutoscaler|minReplicas|<font color="Red">2</font>|
|PodDisruptionBudget|minAvailable|1|
|Deployment|strategy|rollingUpdate|
|Deployment|strategy.rollingUpdate.maxSurge|1|
|Deployment|strategy.rollingUpdate.maxUnavailable|0|

### 期待した挙動（実際にそうなった）

この設定をいれて再度ワーカーノードを更新しました。
期待した挙動としては以下のようになります。

#### 1.pod数を2にして再実行
![real-part1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316261/b449a918-b927-d238-4d86-48ecbcb1e39a.png)

#### 2.PodDisruptionBudgetで指定した1podを残して排出
![real-part2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316261/6b4b4910-50dd-83c3-8f3a-beb958911ba5.png)

#### 3.更新後ノードでpodが起動したら残りのpodを排出
![real-part3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316261/d03cc042-9416-1ff6-7fb6-504150b7397b.png)

上記の通り、正常にpodが排出され、ワーカーノードのバージョンを更新することができました。

## 最後に

PodDisruptionBudgetは普段の運用の中ではあまり意識することなかったのですが、今回の作業で詳しい挙動を知るいい機会になりました。
SpeakerDeckでスライドがすべて非公開になったときの対応方法

# 事件発生

Facebook Messengerで友人から、「スライドが見えなくなってるよ」と連絡が来ました。
見えなくなっていたスライドはこちら。38スライド全部見えなくなっていました。
https://speakerdeck.com/viva_tweet_x

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221788/dea43991-7bbf-fe2b-fdd9-887a04afbf67.png)

上の画像の通り、非ログイン状態だと何も見えない。
スライドが全部消えた！？と思い青ざめながらログインして確認してみると、スライドは残っていました。全部非公開状態になっていたようです。

# 問題の切り分け

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221788/b1fe7cbb-4ef0-5f14-22dd-10e178bd6d57.png)

まずは、

**スライドを公開状態に再度反映してみて、確認（個人の問題かどうか）**
→ダメでした。非公開のまま。

**他の人のスライドを見に行って、同件が発生していないか確認（SpeakerDeck全体の障害かどうか）**
→何名か見ましたが、スライドは普通に見えました。

ということで心当たりもないので問い合わせることに。

情報収集がてら、Twitterで発生した事象を流したところ、@nihonbuson さんが同件で過去にハマっていたことを教えていただきました。
SNSの力は偉大です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221788/9c4a1e8c-534f-7562-261f-c81114b91f50.png)

# 問い合わせ

Twitterとメールで両方問い合わせました。Twitterで問い合わせした後に「メールのほうが早いよー」とアドバイスしていただいたため、メールでも送っています。

Twitter： @speakerdeckに問い合わせ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221788/2bbcafa6-2d58-eecf-695e-47e74e7f0669.png)

メール： support@speakerdeck.comに問い合わせ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221788/c9f7c926-68e7-cf1c-9d7d-31a2c58d5c79.png)

# 対応完了

メールを送ってから2時間半後に解決してくれました。素早い。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221788/fdb4749e-d35f-d885-5ebe-950c3435fdab.png)

# 原因の推察

アカウントが**スパム判定された**のではないか、というふうに推察しています。
短い期間でスライドをupするとスパム判定されていた、という事例は以下から見れますが、

[Speaker Deckのアカウントが凍結されて直らない話](https://korosuke613.hatenablog.com/entry/2019/01/28/014355)

今回のケースは、そういうことはしていません。1か月に1度くらいのuploadペースなので、頻度ではスパム判定されていないはずです。
多分ですが、スライドの中身で全く同一のページを入れているものがいくつかあるので、それでスパムとして判定されたのかな…と。

# 困ったら

とりあえずサポートにメールしてみましょう。
Apache2 の PHP で virtual を使う

Apache2 の PHP で virtual を使う方法です。

参考情報
[Apache 関数 > virtual](https://www.php.net/manual/ja/function.virtual.php)

>```text
CGI スクリプトの場合、そのスクリプトは、有効な CGI ヘッダを
生成する 必要があることに注意してください。
最低でも、Content-Type ヘッダを生成する必要があります。 
```

```php:test_virtual.php
<?php
// ------------------------------------------------------------------
//	test_virtual.php
// ------------------------------------------------------------------
echo '<!DOCTYPE html>';
echo '<html  lang="ja">';
echo "<head>";
echo '<meta http-equiv="CONTENT-TYPE" content="text/html; charset=utf-8" />';
echo "<title>virtual</title>";
echo "</head>";
echo "<body>";
echo "<h2>test_virtual.php</h2>";
echo "<blockquote>テスト</blockquote>";
virtual('./some_script.pl');
echo exec('whoami');
echo "<p></p>";
echo "<p>Mar/21/2021 AM 08:00</p>";
echo "</body>";
echo "</html>";
?>

```

```pl:some_script.pl
#! /usr/bin/perl
#
#	some_script.pl
#
print "Content-type: text/html; charset=utf-8\n\n";
print "Hello<br />\n";
print "おはようございます。<br />\n";
print "Good Morning<br />\n";
print "Jun/24/2020 AM 07:30<br />\n";
print "<p></p>\n";
#
```

ブラウザーで test_virtual.php にアクセスした結果
![test_virtual_jun19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/9a82b59a-b896-b0ee-dbb3-299abbfc4091.png)
go修行8日目　Panicとか


## エラーハンドリング

```golang

package main

import (
	"fmt"
	"log"
	"os"
)

func main() {
	file, err := os.Open("./tt.go")
	if err != nil {
		log.Fatalln("Error")
	}
	defer file.Close()
	data := make([]byte, 100)
	// errは上書きでinicializeしている
	count, err := file.Read(data)
	if err != nil {
		log.Fatalln("Error")
	}
	fmt.Println(count, string(data))
}
```

```
2020/06/19 08:37:42 Error
```


## パニック

- 例外エラーの中の例外
- 何をしたらいいかわからない状態なのでなるべくエラーハンドリングするとよい

```golang

package main

import "fmt"

// DB接続パッケージ
func thirdPirtyConnectDB() {
	panic("Unable to connect database")
}

func save() {
	// 強制終了させないようにrecoverする
	defer func() {
		s := recover()
		fmt.Println(s)
	}()
	thirdPirtyConnectDB()
}

func main() {
	save()
	fmt.Println("OK?")
}
```

```
Unable to connect database
OK?
```
JavaScriptワンライナー #1 任意長のランダムな文字列を作る

シェル芸ならぬワンライナー芸@JavaScriptで色々やってみようという試みです。

---

今回はテストデータを作るときに役に立つかもしれない「任意長のランダムな文字列を作る」というのをやってみます。
「ランダムな文字列を作る」というのをざっと調べるとよく見つかるコードにこんなのがあります。

```js
Math.random().toString(36).slice(-8);
```

- 乱数を発生させます。
- それを36進数としてパースすれば`0～9a～z`で値が表現されます。
- そのままでは先頭に`0.`というのが付いてしまうのでお尻から使えるところを拾っています。

都合の良いワンライナーですので、ここから発展させてみたいと思います。

## `0.`を捨てる

```js
Math.random().toString(36).split('.')[1];
```
- ピリオドで分割します。
- 後ろを拾います。

## もっと長くしたい
このままでは得られる文字列の長さに限界があるので適当に繋げてみます。
先ずは4つぐらいかな...

```js
[0,1,2,3].map(() => Math.random().toString(36).split('.')[1]).join('');
```
- 先程の文字列を返すアロー関数を用意します。
- 4つの要素を持つ適当な配列から`map`メソッドで文字列を配列化します。
- `join`で連結して1つの文字列にします。

## 任意長にしたい
この方法で任意長にするためには配列の要素数を適切に設定する必要があります。
そのためには1回で得られる文字列の長さを把握しておきたいものです。
試しにこんな事をしてみますと...

```js
for (let i = 0; i < 8; i++) console.log(Math.random().toString(36));
```

結果が

```
0.tss9ygi8yk7
0.cbl7c75unf
0.oi3ntqpk9f
0.3u3sulrw5ig
0.ph9gzmq637c
0.2pn7h79139
0.eqdmmpp0kyg
0.q1zz93b8csc
```
少なくとも10桁は使えそうです。
念の為、9桁使うという想定で進めます。(小心者)

欲しい長さを変数`len`で与えたとして必要な要素数の配列を得るには...

```js
[...Array(Math.ceil(len/9))]
```
- 欲しい長さを一度に得られる文字数で割ります。
- 切り上げで整数化します。
- 便利なオマジナイで配列を生成します。

これを予め作っていたコードに適用してみます。

```js
[...Array(Math.ceil(len/9))].map(() => Math.random().toString(36).split('.')[1]).join('').slice(-len);
```
- 必要な長さを十分に満たす文字列を作ります。
- 与えられた長さを切り出します。

## 長さ`0`以下を指定された場合の対策
このままでは長さに`0`を指定されると都合が悪いので、その場合は長さ`0`の文字列を返すことにします。

```js
const randomString = (len) => len > 0 ? [...Array(Math.ceil(len/9))].map(() => Math.random().toString(36).split('.')[1]).join('').slice(-len) : '';
```

## 結果
出来上がりました。
動かしてみましょう。

```js
const randomString = (len) => len > 0 ? [...Array(Math.ceil(len/9))].map(() => Math.random().toString(36).split('.')[1]).join('').slice(-len) : '';

for (let i = -1; i < 20; i++) console.log(randomString(i))
```

結果は

```


f
in
bso
2qz6
6ywe9
1hdq1r
a7nxjoa
yaamsm56
0mu9x06ft
5vogkds05g
e49k52cmq1m
l9lqg4npbdag
mtlygyh0dntn5
zkvbccv93eqbcg
0ywlv1k5wq9fj6q
k8amki0fo5de4r4h
vn05f4lic4ls3z3jd
knmcn6l5nex6xflnvk
c0h63fzghj9rfkq97qo
```

狙い通りです。
めでたしめでたし
BootStrap5のα版がリリースされました

## 概要

2020-06-16にBootstrap5のα版が公開されました！！

[Bootstrap 5 alpha! | Bootstrap Blog](https://blog.getbootstrap.com/2020/06/16/bootstrap-5-alpha/)

公式のブログを読むと、以下の対応が挙げられていました。

- **jQueryを捨てたよ**
- **IEサポートを捨てたよ**
- 公式ドキュメントを改善したよ
    - Hugoを使っているよ
- ロゴを新しくしたよ
- form系の要素を見直したよ
- Utilitiesを強化したよ
- htmlとcssのみでボタンのトグルを実装したよ
- CSSのカスタムプロパティを使い始めたよ
- カラーパレット拡張したよ

近日公開予定のものは割愛しております。
BootstrapのためにjQuery入れてたりしてたので、脱jQueryは嬉しいですね。

## 容量を測ってみる

公式でCDN提供されているものから取得しました。
少なくともjQueryの分だけ早くなっているはず……！

```html:Bootstrap5
<!-- css -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/css/bootstrap.min.css" integrity="sha384-r4NyP46KrjDleawBgD5tp8Y7UzmLA05oM1iAEQ17CSuDqnUK2+k9luXQOfXJCJ4I" crossorigin="anonymous">
<!-- js -->
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/js/bootstrap.min.js" integrity="sha384-oesi62hOLfzrys4LxRF63OJCXdXDipiYWBnvTl9Y9/TRlw5xlKIEHpNyvvDShgf/" crossorigin="anonymous"></script>
```

```html:Bootstrap4
<!-- css -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<!-- js -->
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
```

### 結果

||Bootstrap5|Bootstrap4|
|----:|:------:|:------:|
|bootstrap.min.css|21.7kB|24.2kB|
|jquery-3.5.1.slim.min.js|0kB|25.1kB|
|popper.min.js|8kB|8kB|
|bootstrap.min.js|16.4kB|15.2kB|
|合計|46.1kB|72.5kB|

26.4kBの減量に成功していております！
まだリリースしていない機能もあるみたいですが、jQueryが消えたのでBootstrap4を超えることはないと思います。 
だいぶダイエットしてますね。

## 参考
- [Bootstrap5公式](https://v5.getbootstrap.com/)
- [Bootstrap4公式](https://getbootstrap.com/)
MSYS2上で動作するnkfコマンドのパッケージを普通にmakeする

↓がうまくいかなかったので、別の方法
[MSYS2上で動作するnkfコマンドのパッケージを作成する](https://qiita.com/magichan/items/1af5befb2b9750d585a2)

捻ったことはなく、普通にmakeする方法です。


### スクリプト

```sh:nkf.exeを作成
$ mkdir -p ~/abs/nkf && cd $_  # absディレクトリ作って移動
$ curl -fsSL https://ja.osdn.net/projects/nkf/downloads/70406/nkf-2.1.5.tar.gz/ -o - | tar xzv  # ダウンロードして解凍
$ cd nkf-2.1.5
$ make install
```

### スクリプトの解説
* [Archlinux Wiki パッケージの作成](https://wiki.archlinux.jp/index.php/%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E3%81%AE%E4%BD%9C%E6%88%90)によると PKGBUILD置くところは`~/abs/[パッケージ名]`が推奨　とのことでした。
* `curl -fsSL [URL] -o -` はダウンロード先を標準出力に吐き出すコマンド
* パイプして`tar xzv`は標準入力から受け取ったtar.gzファイルを解凍するコマンド
* それ以外はディレクトリ作ったり、移動したり、`make`してできたexeをパスの通った場所にコピーするだけです。
Vue.jsからaxiosでGoにパラメータ渡せなくてつまり続けたが、Echo導入したら即解決した

Vueで入力された値をJson形式でGoに渡して処理をさせたかった。
うまい感じに渡せず、詰まったがEcho導入したら即解決した。

## やりたいこと
- VueからPost（非同期）でパラメータを渡して、Goで処理をさせたい。
   - とりあえず、Axiosで送信したparamsがGoで受け取れていることを確認したい。

## VueとAxios
あるボタン押下時にtestを実行して、data1とdata2をjson形式でpostする。
Goの処理結果をconsoleに表示する。

**axiosはpost時、以下のように渡せば自動的にjson形式にしてくれるらしい。**

```ruby:vue.js(一部抜粋)

<script>

export default {
  name: 'SqlGenerater',
  data() {
    return {
      data1:'1',
      data2:'2',
    }
  },
  methods:{
    test(){
      let params= {
        data1: this.data1,
        data2: this.data2,
      }
      this.$axios.get('/api',{ params: params })
      .then(response => {
        console.log(response.data)
      })
    }
  }
}
</script>
```
## Go(Echo)
[Echo公式](https://echo.labstack.com/guide/request)のrequestにかなりわかりやすく書いてある。
下記のようにすれば自動でバインドできるみたい。すごく便利ぃ

```ruby:main.go
package main

import (
	"net/http"

	"github.com/labstack/echo"
)

type Test struct {
	Data1  string `json:"data1" form:"data1" query:"data1"`
	Data2  string `json:"data2" form:"data2" query:"data2"`
}

func main() {
	e := echo.New()
	e.GET("/", index)
	e.Logger.Fatal(e.Start(":8081"))
}

func index(c echo.Context) (err error) {
	t := new(Test)
	if err = c.Bind(t); err != nil {
		return
	}
	return c.JSON(http.StatusOK, t)
}

```

実行したら、ちゃんと取れてることが確認できた。

```ruby:console
{data1: "1", data2: "2"}
```

ありがとうEcho
WKWebView オブジェクトの破棄後にデバッグ領域に "Could not find specified service" というメッセージが出力される

# 概要

`WKWebView` オブジェクトを破棄してから30秒ほど経過したら、以下の2つのエラーメッセージが Xcode のデバッグ領域に出力されます。

```sh
Could not signal service com.apple.WebKit.WebContent: 113: Could not find specified service
```

```sh
Could not signal service com.apple.WebKit.Networking: 113: Could not find specified service
```

このメッセージが出力される原因について調査したところ、いろいろな情報を見つけたのですが、Apple Developer Forums のページで Apple Staff が返信しているものが最も信頼できる情報であると判断しました。そのページによると、このメッセージについては特に気にする必要はないとのことです。

# 確認環境

## ビルド環境
* macOS 10.15.5
* Xcode 11.5 (11E608c)
* Deployment Target: iOS 13.0

## 実行環境
* iPhone 11 Pro Max (iOS 13.5.1)

# Apple Developer Forums での情報

下記リンク先の Apple Developer Forums のページで Apple Staff が返信しています。

[com.apple.WebKit errors after deallocating WKWebView |Apple Developer Forums](https://forums.developer.apple.com/thread/112095)

返信内容の一部を抜粋します。

```
These are two XPC Services used by the web view to implement core functionality (page rendering and networking, respectively).
I suspect what’s going on here is that the web view has shut down and, 30 seconds later, its XPC Services are shut down.  That does not seem particularly worrying in and of itself.
```

この返信を読む限りでは、 `com.apple.WebKit.WebContent` と `com.apple.WebKit.Networking` についての `113: Could not find specified service` は特に気にする必要はなさそうです。

# その他の情報

他の情報源の中には、 次のリンク先の記事のように、Xcode プロジェクトの設定や `WKWebView` の扱いに問題がある可能性に言及しているものもありました。

[Xcode - Could not signal service com.apple.WebKit.WebContent: 113: Could not find specified service とは？｜teratail](https://teratail.com/questions/121129)

このリンク先のページでは、 `com.apple.WebKit.WebContent` と `com.apple.WebKit.Networking` についての `113: Could not find specified service` の原因として、以下2つを挙げています。

1. `addSubview` をする前に `loadHTMLString` を呼び出していた
2. `Info.plist` で `NSAppTransportSecurity` を設定せずに `http` のURLに接続していた

今回はこれらの問題がない状態でもエラーメッセージが出力されていたので、最終的には上の Apple Developer Forums のページが最も信頼できる情報であると判断しました。けれども、原因として挙げられているこれら2つについても、これはこれで気をつけるべき点かもしれませんので、本記事で紹介しておきます。
pip install apache-beam[gcp] がコケる

Macでzshを使っている場合、下記のコマンドが失敗する

```bash
$ pip install apache-beam[gcp]
zsh: no matches found: apache-beam[gcp]
```

うまくいくのは下記のコマンド

```bash
$ pip install 'apache-beam[gcp]'
```

参考URL
https://stackoverflow.com/questions/60638242/error-with-installing-apache-beamgcp-on-mac-zsh-terminal-zsh-no-matches-fo
HSVに変換

```py
    import numpy as np
    import cv2
    import time

    cam = cv2.VideoCapture('ling-f1-good1.mp4')

    while(cam.isOpened()):# 動画終了まで繰り返し
        t = time.time()
        #時間測定
        ret, img = cam.read()
        #画像に切り取り

        if not ret:
            break
        #動画が最後なら終了


        img = cv2.resize(img, (640, 380))
        #画像のリサイズ

        hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV_FULL)
        #HSVに変換
        h = hsv[:, :, 0] #Hは色相
        s = hsv[:, :, 1]

        mask = np.zeros(h.shape, dtype=np.uint8)
        #マスク用の空配列を作成
        mask[((h < 20) | (h > 200)) & (s > 60)] = 255
        #２００度～２０度でマスクを作成　※赤以外をマスク

        # マスキング処理
        masked_img = cv2.bitwise_and(img, img, mask=mask)

        cv2.imshow("Frame", masked_img)

        print(time.time() - t, ret)

        if cv2.waitKey(1) & 0xFF == ord('q'): break
        #「ｑ」が押されたら終了
```
SIビジネスの根本は、「人月費用課金」と知っておくと、全てがはかどりますよ！

別ストックへのレスで、いいねを沢山頂いたので需要があると思い、記事化します。

SIerにとって、根幹となる部分は西暦2000年で止まっているふしがあります。
当時、西暦2000年においては、バッチファイル & ExcelVBA & ドキュメント内参照
などは「最先端の技術」であり、みんなこぞって学んだわけです。
そしてそれが「定型」になりました。

プライムSIerになればなるほど、Excelですべてを設計しています。
笑えるほど20年前の技術をそのまま、工夫なく使っています。

以前所属していたSIerでは、一人が作ったExcelドキュメントのシートを
マージして、一日を費やしている人がいました。
ひどいときは別の人がそれをもう一回分割していましたｗ

そんな仕事を何年も続けたあと、彼らは退職時、何を得ているのでしょうか・・・？
吉田栄作さんならこういうでしょう「ノースキルでフィニッシュです」

～～～～～～～～～～～～～～～～～～～～～～～～～～～～～～～～～～～～～～～～

以下は特定の人に対する批判などではないので、軽く読みながしてもらえると幸いです。

SIビジネスの根本には、「人月費用課金」があります。これがすべてだといっていいでしょう。

皆さんがこの課金システムで経営者になったことを想像してみて下さい。

1. できるだけ多く人月を見積もりたい
2. 客には、人月の中身まで理解してもらう必要はない、そうなると困る
3. もしスーパーマンがいて、10人の作業を1人で終わらせちゃったら困る

となるわけです。もうお分かりでしょうが、
「平均的な人がたくさんいたほうが会社がもうかる」ということです。

建設業では、これはなりたちます。
大前提として、人間には2本の腕しかありませんから、
1人が10人分をやってしまう「心配」はないわけです。

ところがITだと、たった一つのアイデアやプロダクトが、
すべての労力を帳消しにしてしまう、クオンタムリープがありえるわけです。
神戸職員がPower Platformで2週間で開発したニュースがありましたが、
あれをSIerがやってしまうと、一人分のお金しかとれないから破綻です。

「自社開発」「コロナ緊急事態」だから生まれた、日本人が本来もっている力です。

つまり、これをご覧になっているあなたをはじめとする優秀な日本人は、
SIerに所属することでこうした力を、「ほかの何か」で浪費してしまうのです。

「ほかの何か」とは、社内調整・社内報告・顧客調整といったものでしょう。
それは「人月を担保するための時間浪費」なのです。
それが本当にもったいない。

もしあなたがSIerに3年もいたのなら、長すぎると思います。
おそらく2年目くらいに、SIerの環境が快適だと思ったことがあると思います。
「あ、これで稼げるんだ」と。そこが落とし穴なのです。

・顧客とは「ツーカー」であってはならない。時間をかけろ。
・顧客を煙にまけ。人月の中身は知らせず多くとれ。
・優秀なIT人材はとるな。たくさんのデク（下請け）を作れ。

言葉は悪いですが、そういうビジネスなんです。

人間がついやす熱量・熱心さはすばらしいことだと思います。
ただ、SIerにおいてその先には、吉田栄作の言葉が待っています（吉田さんすみませんｗ）。

究極的には、以下の二択なんだと思います。
・「金かせげりゃいいじゃん」「新しいこと覚えるのめんどくせ」「俺と家族が一番大事」
・「技術と知恵をフル活用して、客も同僚もハッピーになってほしい」
Qiitaにいる皆さんの多くは、後者なんでしょうね。

このプラットフォームを作った方こそ、賞賛されるべきですが。
吉田栄作「Qiitaさん、マネー成立です」
FIFOについてもう少し（追記

#FIFOとは
パイプに名前をつけたものがFIFO。終わってしまった。
```ls -l | grep keyword```
における | がパイプで、これにファイルシステムグローバルな名前をつけたものがFIFOということになる。性質はパイプと変わらない。上記の例だと

1.grepが起動してパイプのopen(O_RDONLY)でブロッキング
2.lsがパイプをopen(O_WRONLY)で開き
3.lsが出力をパイプにwrite()
4.grepのブロックが解除され、入力をread()
5.lsがパイプをclose()
6.grepがパイプをclose()

みたいな動きになる。
~~open()でブロッキングするのであってread()やwrite()ではブロッキングしない。~~
**O_RDONLYではopen()でブロック**
**O_RDWRではread()でブロック**
**という挙動になる。**
**こんなのどこに書いてあるんだ？**

これは日本語man pagesに書いてあるのだがわかりづらい。つまりこうだ。

seekのきかないファイル（パイプやFIFO）は現在位置から読み込みを開始して、データがない場合はEOFとみなして0を返す。
**EOFを返すのはO_RDONLYでのopenが成功した（有効なfdが返された）場合、かつFIFOにデータがない場合だけである。**

~~ゆえにread()ではブロッキングしない。~~**openモード次第でブロックの挙動が変わる。上記参照。**通常はこれで困ることはないが、プロセス間通信でスレッドを立てて、ループでデータの到着を待つような処理をする場合、open()でブロッキングしてCPUの浪費を防ぐ必要がある。しかし人情として、いちいちループ中でopen()/close()はしたくない。read()でブロッキングが可能ならそれがベストだ。
**些細な問題を除いてreadでもブロッキングはできるのだが、mqで解決したのでそれはまあ良しとしよう。**

#そこでメッセージキュー
POSIXメッセージキューは固定サイズのメッセージを有限個格納できるキューである。作成時にブロッキング属性を付与するため、キューの受信を実行しても（ブロッキングキューであれば）メッセージ到着までブロッキングしてくれる。
なのでスレッドのループ中でメッセージの到着を待つような処理に向いている。パイプのようにSIGPIPEを発生することもなければ、FIFOの両端が閉じるとデータを失うようなこともない（カーネル寿命なのでシャットダウンまでデータを保持してくれる）。
#プロセス間のデータ交換
プロセス間通信の方法は、ほかにもセマフォやシグナル、共有メモリなどがあるそうなのだが、データ交換を目的に行う場合はFIFOかキューかドメインソケットになると思う。それぞれ一長一短はあると思うのでいずれまとめてみたい。
#で、些細な問題って何？
googleでman fifoとかで検索するとヒットするのだが、

**FIFOに対してO_RDWR指定でopenした場合の動作は未定義である。readでブロッキングできる代償は未定義動作だ。**

まあ承知の上で使うならいいのではないだろうか。個人的にはこういう逃げ口上のようなマニュアルは大嫌いだが。
非同期処理にPromiseが使いたくて調べた

## promiseで実現したいこと

「3秒のカウントダウン後に、30秒のタイマーをスタートさせたい」

処理を待ってから、次の処理を実行する為に`Promise`について調べました。

## Promisは何をしてくれる？

- Promiseオブジェクトは非同期処理を扱える機能。
- `new Promise`でpromiseオブジェクトを呼ぶことができる。
- Promiseのコンストラクタ引数には、非同期処理を行う関数を指定する。

### サンプルコード
`promise`を使用することで最初の処理が終わるまで、次の処理を待機をさせることができる。

```Javascript
let promise = new Promise((resolve) => {
    setTimeout(() => {
       // resolve()を呼び出すとPromiseの処理が終了
       resolve();
    }, 1000);
});

// then()メソッドで次の処理を記述
promise.then(() => {
    console.log('次の処理'); // 1秒後に実行
)};
```

`resolve()`の引数に値を入れて、`then()`で引数を処理することも可能。
`promise`の引数は、コンソールの`[[PromiseValue]]`で確認することができる。

## PromiseStatus

Promiseは`Status`[状態]によって、処理を分岐できる。

```Javascript
[[PromiseStatus]]: "pending" // 待機状態（最初はここ）
[[PromiseStatus]]: "resolved" // 処理の分岐
[[PromiseStatus]]: "rejected" // 処理の分岐
```

###サンプルコード

if文で引数に条件を設けて、promiseオブジェクトの`status`を分岐させて`Value`を操作できる。

```javascript
 // 引数payが支払うお金として、100円より多ければchange（おつり）を返し、足りなければメッセージ（エラー）を返す
 function promiseSmaple(pay) {
      return new Promise((resolve, reject) => {
        if (pay > 100) {
          let change = pay - 100;
          resolve(change);
        }
        reject('お金が足りません');
      });
    }
```
初心者によるプログラミング学習ログ 349日目

#100日チャレンジの349日目
twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。
100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。
349日目は、
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">おはようございます<br>349日目　1.5h<br>・架空LP15日目2.0h(<a href="https://twitter.com/ririru_123?ref_src=twsrc%5Etfw">@ririru_123</a>)<br>・ipad版のプロフィール部分作成<br>残業をしいられた（3h）のであんまりできなかったわ<a href="https://twitter.com/hashtag/%E6%97%A9%E8%B5%B7%E3%81%8D%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8?src=hash&amp;ref_src=twsrc%5Etfw">#早起きチャレンジ</a><a href="https://twitter.com/hashtag/%E9%A7%86%E3%81%91%E5%87%BA%E3%81%97%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%A8%E7%B9%8B%E3%81%8C%E3%82%8A%E3%81%9F%E3%81%84?src=hash&amp;ref_src=twsrc%5Etfw">#駆け出しエンジニアと繋がりたい</a><a href="https://twitter.com/hashtag/100DaysOfCode?src=hash&amp;ref_src=twsrc%5Etfw">#100DaysOfCode</a></p>&mdash; ぱぺまぺ@webエンジニアを目指したい社畜 (@yudapinokio) <a href="https://twitter.com/yudapinokio/status/1273712006382542849?ref_src=twsrc%5Etfw">June 18, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
chocoでPythonとpipをインストール時のエラーの対処法

# tl; dr
chocoでpythonを入れても，環境変数は自分で通せ．
pipを使いたければ，自分で入れろ．

# 困ったこと
ROS2を入れるために，chocoを使ってpython3.7をインストールした後，powershell上で

```WindowsPowerShell
$ python
```

と入力したとき，MicrosoftStoreが開く．

また，chocoでpipをインストールしようとしてもエラーでインストールできない．

#解決方法
まず，pythonをインストールした後，

```WindowsPowerShell
$ refreshenv
```

と入力し，反映させる．

この後，再び

```WindowsPowerShell
$ python
```

と入力してもMicrosoftStoreが開く場合，環境変数を自分で入れる必要がある．
自分の場合はCドライブ直下にpython(バージョン)というフォルダがあったのでこれを環境変数のpathに設定する．
そうすると，pythonが使えるようになった．

次に，chocoでpipをインストールしようとした際に，エラーが起こる．
このときのエラーログは，取り忘れたので割愛する．

このときは，ネットからpipインストール用スクリプトをダウンロードする．
pythonがインストールされたフォルダ内で以下を実行する．

```WindowsPowerShell
$ wget "https://bootstrap.pypa.io/get-pip.py" -O "get-pip.py"
$ python get-pip.py
```

そうするとフォルダ内に，Scriptsフォルダが作成されるのでこれも環境変数のpathに登録する．
すると，pipが使えるようになる．

#参考
https://index.ros.org/doc/ros2/Installation/Eloquent/Windows-Install-Binary/
https://qiita.com/kangetsu121/items/b6352b547cd32e71bc65#%E5%8F%82%E8%80%83
https://bamch0h.hatenablog.com/entry/2019/09/29/162601
SQLSTATE[HY000] [1045] Access denied for user エラー

#http://localhost:8888にアクセスし、MySQKのデータをlaravelのDBクラスを使って表示するときにでたエラー

##実際に出たエラー
```SQLSTATE[HY000] [1045] Access denied for user 'root'@'localhost' (using password: YES) (SQL: select * from information_schema.tables where table_schema = laravel-project and table_name = migrations and table_type = 'BASE TABLE')
```

##エラーを出してしまった理由
ターミナル からアクセスしていたmysqlのsocketが必要なのにphpmyadminのsocketを.envのDB_SOCKETに記述してしまっていた。

##解決した方法
mysqlコマンドの\sでサーバー情報を表示してsocketを.envのDB_SOCKETにコピーし、
ターミナルに戻り、（一度設定した.envを再編集した場合は）キャッシュをクリアにする
```$ php artisan config:cache
```

###参考サイト
MySQLサーバー情報取得
https://phpjavascriptroom.com/?t=mysql&p=info
Google Driveにアップロードした音声ファイルをHTMLに埋め込む話

# GoogleDriveの共有可能なリンクを取得から得られるURL形式が変わった
2020年6月19日現在、GoogleDriveのシステムにアップデートが入ったことが要因なのか、`右クリック->共有可能なリンクを取得`で得られるURL形式が

`https://drive.google.com/open?id=XXXXXXXXXXXXX`のような形式から、
`https://drive.google.com/file/d/YYYYYYYYYYYY/view?usp=sharing`という形式に変更が入りました。

私は、従来得られたURLを改変し、
`https://docs.google.com/uc?id=XXXXXXXXXXXXX`として、`Audio`タグでsrc指定することでサイトに音声を埋め込んでいましたが、アップデート後のURLも同様に、
`https://drive.google.com/file/d/YYYYYYYYYYYY/view?usp=sharing`から`YYYYYYYYYYYY`の部分を抽出し、
`https://docs.google.com/uc?id=YYYYYYYYYYYY`としたURLをsrcに指定することで音を鳴らすことができることを確認しました。

## 結論
ファイル指定している位置が変わっただけなので`/d/`と`/view?usp=sharing`に挟まれている部分を指定してあげれば従来どおりGoogleDriveの音声を埋め込んで使える。
(自分用)Flask_3(form,POSTとGET)

# 項目
1. 入力フォームと軽くフォームとは
2. POSTメソッドで掲示板的なやつ
3. GETメソッドで掲示板的なやつ

# 1.入力フォームでフォームを触る
- ただフォームを作るだけならpy側は何もいじらなくて大丈夫

```html:html
<form action="/result" method="post">
    <label for="article">投稿</label>
    <input type="text" name="article">
    <p></p>
    <label for="name">名前</label>
    <input type="text" name="name">
    <button type="submit">送信する</button>
</form>
```
- `action="/result"`で/resultにデータを送るよと指定している
- `method="post"`でなんのメソッド使うかを決める
- `input type="text" name="article"`は`text`で1行入力欄を作るって決めて、そこに入力されたデータにarticleって色付けをしている
- 下もだいたい同じ
- `<button type="submit">送信する</button>`は`submit`って指定する事で、データを送るボタン作ってる
<br><br>
- この`<form>`は入力・送信フォームを作成する際に使用する

# 2.POSTメソッド使って入力データを受信する
- まず受信するためのpython側での準備

```python:python
from flask import Flask, request, render_template
app = Flask(__name__)

@app.route("/")
def show():
    message = "Hello World"
    return render_template("form.html", message = message)

@app.route("/result", methods=["POST"])
def result():
    article = request.form["article"]
    name = request.form["name"]
    return render_template("form.html",article = article, name = name)
```
- `request`を使うって上で宣言する
- `@app.route("/result", methods=["POST"])`で上のhtml側で指定したアドレスを指定して、POSTメソッドを使うよとも書いとく
- 変数やってた所は`request.form["~~~"]`で、html側でつけたname属性のデータを受け取れるようにする<br>ここでは`article`とかを受け取ってる
- あとは大体見たまま

```html:html
<form action="/result" method="post">
    <label for="article">投稿</label>
    <input type="text" name="article">
    <p></p>
    <label for="name">名前</label>
    <input type="text" name="name">
    <button type="submit">送信する</button>
</form>
<p>{{ article }} {{ name }}</p>
```
- 上のhtmlと大体同じなんだけど、`{{ article }} {{ name }}`ここだけ違う<br>まあ変数表示するのと同じこと

# 3.GETメソッド使って入力データを受信する
- GETメソッド使うと、入力データを受信して`/result`を表示する時、<br>`/result?article=Hello&name=World`って感じで、アドレスに入力内容が出ちゃう

```python:python
from flask import Flask, request, render_template
app = Flask(__name__)

@app.route("/")
def show():
    message = "Hello World"
    return render_template("form.html", message = message)

@app.route("/result", methods=["GET", "POST"])
def result():
    if request.method == "POST":
        article = request.form["article"]
        name = request.form["name"]
    else:
        article = request.args.get("article")
        name = request.args.get("name")
    return render_template("form.html", article = article, name = name)
```
- `methods=["GET", "POST"]`でどっちのメソッドも対応するようにしてる
- `if request.method == "POST":`でリクエストしたメソッドがPOSTの時...って感じ
- GETは`article = request.args.get("article")`の様に、`request.args.get("~~~")`って書く
<br><br>
- htmlに関してはメソッド書いたところを`method="get"`にしておけばOK

# 4.終わりに
- とりあえずこんな感じで
コロナ自粛期間に高専生が思ったこと・やったこと。学校に対しての不満

# はじめに
こんにちは。現役高専生で課題多すぎて最近萎えてるMarnyです。

世界では**新型コロナウイルス**によりさまざまな被害が起きています。そこで我々学生は長期による**自粛期間**というのが設けられました。

しかし、今となっては自粛解禁ムード。徐々に回復しているので、もう大丈夫じゃね？ムード。　　~~また感染者増えそうだけど~~
この自粛期間というのは、いいのか悪いのかわかりませんが、**開発**をするのにはもってこいの期間で、いろんなことしました。

今回は、自粛期間に起こった色々(学校についてなり、開発についてなり)を喋っていきます。

# 開発したもの

この期間、僕が開発したのは

- Go言語によるCTF用のスコアサーバ
- 脆弱性のあるWebページ作成、攻撃
- Vue.jsを用いたWebページ作成(進行中)


こんなもんですね

思い出になっているのは、なんといっても**Go言語によるスコアサーバ**の作成ですね。まじでGo信者になった。えぐいこの言語。

こいつに関しては、また別の記事で、、、

~~約3か月半とかで、これらをやったのですが、かなり疲れてメンタル的にも割ときつい状態なのは内緒。~~

# しかし、学校はどうだったのか。

今回の本題は実はここなのかもしれない。自粛期間にでる課題。お前多すぎるぞ。

課題のほかにもいろいろ不満があります。

### 不満点1

- 課題の配布方法がバラバラで確認が困難＋そもそも課題に気づかない
- オンライン授業がマジでぐだぐだ
- そもそも授業をしてないからテストやれ！って言われたらできるきがしない。

文句なんかいくらでも出てきます。

特に**課題の配布方法**。マジでやめてほしい。

僕の通っている学校では、**「Google　Classroom」**にて課題の配布が行われています。
こいつが諸悪の根源。

### 不満点2

- 授業ごとにクラスを作成してるのと、してないのがある。→単純に見づらい
- そもそもClassroomが使いずらい。

~~マジでくそ。~~

なんかクリックして戻ったら、ページの先頭に戻されて、過去の投稿を見たい場合また下まで行って探さないといけない。とても不便。

さらに通知も来なかったりで、課題の提出にきづかないなんてザラにある。

あと先生がpcをうまく使えなかったり、オンライン授業があるのとないのが事前に言われてない。あと時間割も。まじでしんどかった。

もうきりがないからやめとこ・・・

# SGGに加入
SGG:[すごくなりたいがくせいぐるーぷ](https://qiita.com/organizations/sgg)とは、開発する系な学生の集まりですね。

4月ごろにできたらしいんですけど、6月初めほどに加入しました。
同世代の知り合いを増やしたくて入ったんですけど、メンバーが化け物ぞろい、、、

開発しなきゃといういい刺激になります。　イイね。



# まぁこんだけ不満があるんですけど・・・

結局、学校に分散ではありますが登校することになってしまいました。開発もしたし、またテストに向かって勉強もしないとです。

学生はつらいです。

未来に向かって勉強していきます。

Go言語最高。


# 追記 06/20更新
06/20現在、中間テストの日付が発表されました。全然延期されてなく、まともな授業が一個もないのに何をテストするんですか？？？？？？？？

まじで切れそう
【Golang】テスト

#【Golang】テスト
Golangの基礎学習〜Webアプリケーション作成までの学習を終えたので、復習を兼ねてまとめていく。 基礎〜応用まで。

```
//main.go
package main
//testing
//テストを書く位置は、テストしたいファイルと同じ階層に書く.
//math.go = math_test.go　という名前で作成。_test.goを探して実行される
//math_test.goに移動

//ターミナルで プロジェクトの中で、go test ./... で実行できる
//詳しいテスト内容を表示　go test -v ./...
/*
?   	kiso_blog/go_test	[no test files]
ok  	kiso_blog/go_test/alib	0.328s
*/

//相対パスでテストをやる場合、go test ./alib 
/*
aoyagimasanori@aoyagimasanorinoMacBook-Pro go_test % go test ./alib 
ok  	kiso_blog/go_test/alib	0.302s
*/

//カバー率 go test -cover ./alib 
/*
ok  	kiso_blog/go_test/alib	0.246s	coverage: 100.0% of statements
*/

//mainパッケージのテスト
//go test -v
/*
=== RUN   TestIsOne
    TestIsOne: main_test.go:15: 2 != 1
--- FAIL: TestIsOne (0.00s)
FAIL
exit status 1
FAIL	kiso_blog/go_test	0.226s
*/


//ユニットテストをやる場合は、Ginkgo(rubyっぽい),Gomega(jsっぽい）などを使ったりする
import (
	"fmt"
	//ここのエラーは相対パスだから
	//"./alib"
	"kiso_blog/go_test/alib"
)

func IsOne(i int) bool {
    if i == 1{
		return true
	}else{
        return false
	}
}

func main() {
	s := []int{1,2,3,4,5}
	fmt.Println(s)
	fmt.Println(alib.Average(s))
}
```

```
//main_test.go
package main
//mainパッケージのテスト

import "testing"

var Debug bool = false

func TestIsOne(t *testing.T) {
	i := 2
	if Debug{
		t.Skip("スキップする")
	}
	v := IsOne(i)

	if !v{
        t.Errorf("%d != %d",i, 1)
	}
}
```

```
//alib/alib.go
package alib


func Average(s []int) int {
	total := 0
	for _, i := range s {
		total += i
	}
	return int(total / len(s))
}
```

```
//alib/alib_test.go
package alib

//テスト用パッケージを読み込み
import "testing"

//このテストを飛ばしたい時はtrueにする
var Debug bool = false

//テスト
//Average関数のテスト例
//Test関数名にする
//引数はtにする。Errorなどの関数が使える。Skipなど
func TestAverage(t *testing.T) {
	if Debug {
		t.Skip("スキップします")
	}
	//ave3.5(1,2,3,4,5,6)は3になるらしい。
	//7までにすると、下記エラーが出る
	/*
			=== RUN   TestAverage
		    TestAverage: alib_test.go:22: 3じゃない 4
		    TestAverage: alib_test.go:23: 4 != 3
			--- FAIL: TestAverage (0.00s)
			FAIL
			FAIL	kiso_blog/go_test/alib	0.308s
			FAIL
	*/
	v := Average([]int{1, 2, 3, 4, 5}) //6,7 でエラー
	//もし、３でなければエラー
	if v != 3 {
		//エラー文字、値
		t.Error("3じゃない", v)
		t.Errorf("%d != %d", v, 3)
	}
}

```
手乗りクラッピングちりんちりんのつくりかた。

#まず必要な材料から
1.自転車ベル（レバーがベル取り付け軸と同方向に回転するもの）
![20C9A4E4-DE2B-47E0-AA31-2F17CE47468F.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567140/554f819a-5384-61f2-9afb-de968ecbfdc5.jpeg)

2.クラッピーの手
![ABDC8DCC-2FE1-4F4A-AAD2-7C60F02BC77B.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567140/d25b4233-b3d0-154e-2fd0-0b1de188a1ec.jpeg)

3.100均　目玉シール
こんなやつ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567140/24290cc7-482d-cdff-d80c-c8adb02c6d27.png)

4.樹脂粘土(唇つくるよ)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567140/77dc5663-04f1-cbb0-b712-bcedcf946a10.png)

5.針金(ぶっといやつ)少々、りゃんめん(強力なやつ)少々

#つくりかたは後ほど･･･
React（Redux）でselectタグとoptionタグを使う時の注意点

## はじめに

Reactでselectタグとoptionタグを使ってreduxのステートを更新させようとしたがなかなかうまくいかなかったので方法を紹介します。


## 困ったこと

- 初期値はdefaultValueとvalueのどっちを使った方がいい？
- onCangeとonClickどっちを使った方がいい？

## 結論
```
<select value={値} onChange={関数}>
    <option>{要素の値}</option>
```

で書かないと動かない。

## 試したこと
```
<select defaultValue={値} onChange={関数}>
    <option>{要素の値}</option>
```

```
<select defaultValue={値} >
    <option onClick={関数}>{要素の値}</option>
```

## まとめ
どれだけ調べても記事が見つからなかったので解決するまでに非常に時間がかかりました。
オンラインストリートライブをやってみた。

##マエセツ
このところ高校時代のバンド仲間などとオヤジバンドを組んでたまにライブハウスで演奏したりしている（というかやっていた）。･･･コロちゃんがブームになってからライブハウスはおろかスタジオで練習すらちょっとという感じで、次男に無理やりベース弾かせて[ホシノゲンさんとのコラボネタ動画](https://www.youtube.com/watch?v=j0qiA6dRZLU)作ったり、同じくブライアンメイコラボとか･･･。

【NETTODUETTOとは？】
最近YAMAHAがサービスしている[NETDUETTO](https://www.netduetto.net/)なるものがある。音楽を合奏するのに特化して遅延を極力配したオンラインシステムで、まさかこんなものが実現できるとはちょっと想像を超えていた(5Gでリアルタイムといっても光速は超えられないしパケットの遅延とか思ってた)。大学のJAZZ研の後輩が[こんな紹介動画](https://www.youtube.com/watch?v=oTi1jQkk8uc)を作ってたのを見て(最後の方に遠隔セッションを実演している)、時々音が途切れたりするが音楽として成り立ってると驚いた。

早速音楽系の技術ワークショップやっているメンバーでお試ししてみたが、私だけちょっとつながってはお部屋から追い出されてしまう…どうやら回線が遅すぎるようだ(いまだにADSL)。ちょっと悔しかったのでネット増強計画でまずはWi-Maxに申し込んだ…がこれまたこのコロナ禍のせいかデバイス発送は1か月後以降だという…。なんだかなぁと思ってたとき、先ほどのJAZZ研後輩が今度は楽天モバイルUN-LIMITに入ったという。エリア内なら無制限で40Mぐらい出ると書いている人もいた。エリアを調べたらウチエリア内ということでこっちも申込み…をしたけどなかなかデバイス発送の連絡が来ない…ついには勝手にキャンセルされる始末ｗｗ
サポートに問い合わせてもなかなかつながらなかったが、なんとかつないだらもう一度申し込んでくれとのこと…ｗｗ
申し込み直してみたら緊急事態宣言終了して店舗受け取り可能とのことで即日稼働できた。
家で測ると確かに40M出てる。ということでWi-Maxはキャンセルし、さっそくネットセッションしようと準備に取り掛かる。

#機材をそろえる。
・まずはPC：これはうちにはグラボ積んだデスクトップからノートPC,MACまでごろごろしてる。前回のお試しですでにインストールしてある1世代前のグラボ積んだデスクトップを使います。
・USB－AUDIOインタフェース：これが一番重要。一応[ちょっと前のTASCAMのやつ](https://tascam.com/jp/product/us-600/top)を前から持っていたが、自粛生活になってすぐ暇つぶし用に[8ch同時入力ミキサー付きのやつ](https://www.zoom.co.jp/ja/products/multi-track-recorder/r16-recorder-interface-controller)(コロナ禍で株価が上がったと話題のZOOM製ですｗ)を使うことにした。
・音声信出力のある楽器、またはマイク：これがないとセッションできないですね。うちにはギターやベースは何本も、あと生ドラム、エレドラ、鍵盤系、エレキ＆生バイオリンなどたいがい揃っているけど手元でとっかえひっかえできるようにギター＆ベースと[ドラムマニア用コントローラ改造して作ったエレドラ](https://qiita.com/stake2722/items/4f4aeda9d8e4e79eec1f)を用意した。
こんな感じ
![kizai.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567140/4e7a3b3a-8379-1d0a-813f-f48e67f6903f.jpeg)
しっかし部屋きたねぇなぁｗ（これでも自粛生活でだいぶ片づけた）

#オンラインストリートライブシステム。
ただ、NETDUETTO使って合奏しただけではつまらないのでストリートライブがオンラインでできる仕組みを考えてみた。
だいたいNETDUETTOは遅延が最小化された音だけに特化したネットワークサービスなので、他の演奏者などとのコミュニケーションはZOOMなどのオンライン会議システムを併用したり、さらにはその模様を配信したりなどすることになる。

ざっくりシステムはこんな感じにした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567140/46de6252-1afe-7311-a9d2-fd8f1f70d9d4.png)

演奏者側は音声はNETDUETTOだけを聞いて、Spatial.chatからの音はホストが一度NETDUETTOの入力として入れて、他の演奏者も含めお客さんの拍手や歓声などはNETDUETTO越しに聞きます。
NETDUETTOで束ねた演奏音をホストがSpatial.chatに流してお客さんはSpatial.chat上で演奏音や他のお客さんの拍手、歓声などを聞くことができ、ライブの臨場感を醸成します（さすがに曲に合わせた手拍子は無理そうだけどｗ）。

で実際に試してみた映像がこれ。
https://youtu.be/bOrLkXv0q6M
（リズムが不安だったのでちょっとゆっくり演奏してて躍動感がないですｗｗ）

ちなみにこれらのサービス、Spatial.chatは有料化が発表されたし、NETDUETTOもベータ版ということで今後SYNCROOMというサービスに移行することが決まっており、こちらもじきに有料化されるでしょうね。
Spatial.chatをVRChatやclusterに置き換えたらVR空間上でのオンラインストリートライブもできそうです（すでにやってる人もいるらしい）が、URLに入って名前入れてクリックですぐ参加できるSpatial.chatのお手軽さは捨てがたいです。
また同じやり方でお客さんと演奏者を適宜入れ替えればオンラインジャムセッションもできそうです。

というわけで無料でお気楽にオンラインストリートライブができるのはここしばらくなので皆さん自粛ライフを楽しみましょうｗｗ
Formファサード

#Formファサードの記録

Form::open()：HTMLフォームを作成する
Form::model()：モデルをベースにしたフォームを作成する
Form::close()：フォームを閉じる
Form::label()：フォームのラベルを作成する
Form::input()：入力フィールドを作成する
Form::text()：テキスト入力フィールドを作成する
Form::password()：パスワードフィールドを作成する
Form::hidden()：hiddenフィールドを作成する
Form::number()：数値フィールドを作成する
Form::email()：メールアドレス入力フィールドを作成する
Form::url()：URL入力フィールドを作成する
Form::file()：ファイルアップロードのフィールドを作成する
Form::textarea()：テキストエリアを作成する
Form::select()：セレクトボックスを作成する
Form::selectRange()：選択肢の範囲を指定してセレクトボックスを作成する
Form::selectYear()：年を選択するセレクトボックスを作成する
Form::selectMonth()：月を選択するセレクトボックスを作成する
Form::checkbox()：チェックボックスを作成する
Form::radio()：ラジオボタンを作成する
Form::reset()：リセットボタンを作成する
Form::image()：画像ボタンを作成する
Form::submit()：Submitボタンを作成する
Form::button()：ボタンを作成する
Form::getSessionStore()：フォームで利用するセッションクラスを取得する
Form::token()：CSRFトークンを生成する
Form::getIdAttribute()：フィールド名のID属性を取得する
Form::getValueAttribute()：優先度を付けた入力値を取得する
Form::old()：セッションから前の入力値を取得する
Form::oldInputIsEmpty()：以前の入力値が空かどうかを確認する
Form::getSelectOption()：選択オプションを取得する
Form::setSessionStore()：フォームで利用するセッションを設定する