OmniAICreator/Qiita-1.07M huggingface dataset:
[k8s]Static Pod について確認したときのメモ

Static Pod について確認したときのメモ

以下を参考にした

[Create static Pods](https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/)

[Static Pod の取り扱い](https://yokohei.com/docs/k8s-static-pod.html)

# Static Pod って何？

[Create static Pods](https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/)

>Static Pods are managed directly by the kubelet daemon on a specific node, without the API server observing them. Unlike Pods that are managed by the control plane (for example, a Deployment ); instead, the kubelet watches each static Pod (and restarts it if it crashes).

Udemy のユースケースを見ると Master ノードで API Server を Pod として起動する場合などに使うという事が言及されていた。

[kubernetes-the-hard-way ](https://github.com/kelseyhightower/kubernetes-the-hard-way) だと binary を使って systemd による起動のようだが以下のような記事もあり、この辺りどうするかはいくつかの選択肢があるということだと思われる

[Running Static Pods in Kubernetes](https://medium.com/faun/running-static-pods-in-kubernetes-f6d1587c31f1)

# どうやって Static Pod を作るのか

以下の2つの方法がある

+ [Filesystem-hosted static Pod manifest](https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/#configuration-files)
+ [Web-hosted static pod manifest](https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/#pods-created-via-http)

前者は `kubelet` 起動時の引数もしくは設定ファイルで指定されたフォルダに Pod のマニュフェストを配置することで `kubelet` が Pod を自動的に起動させるというもの。
後者はフォルダでははなく、Web 上にマニュフェストファイルを配置し、`--manifest-url=<URL>` で URL を指定して利用するというもの。

# どのような挙動か

[Observe static pod behavior](https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/#behavior-of-static-pods)

+ `kubelet` を起動すると Static Pod が起動される
+ Pod は `kubectl get pods` でも確認出来る。
+ `kubectl deletel pod` をしても Pod は起動し続ける
+ `docker stop` によってコンテナは停止するが、一定時間経過によって `kubelet` によって再度 Pod(コンテナ)は起動する
new Promise(function(onFulfilled, onRejected))　のonFullfilledとonRejectedってなにもの？？ 



JSの勉強会をしていたときに
`new Promise(function(onFulfilled, onRejected))　のonFullfilledとonRejectedってなにもの？？`
となったので自分なりにまとめてみることにした

##### まず、なにが疑問なのか
Promiseのインスタンス生成のとき
非同期処理の内容を記述した関数を引数に指定する
こんな感じ

```
new Promise(
  function(onFulfilled, onRejected) {
    /* 非同期の処理を記述 */
  }
)
```
これの`onFulfilled`, `onRejected`が何なのか・どういう関数なのかという話

##### onFulfilledとonRejected
onFulfilledとonRejectedの説明書きはされていて、以下のように書かれている

`onFulfilled`
  処理が正常に終了し結果が得られた場合に実行させるもの
  これが実行される時はプロミスはfulfilled(成功)の状態

`onRejected`
  処理の結果エラーが起こった場合に実行させるもの
  これが実行される時はプロミスはrejected(失敗)の状態

ふむふむ、そうね、成功のときはonFulfilled、失敗のときはonRejectedという認識でした
この説明はわかっていそう

ひとまず、Promiseについて書かれているコレを読んでみた
[JavaScript Promiseの本](https://azu.github.io/promises-book/#promises-overview)

Promiseのリファレンスも読んでみて、なんだかわかったような、さらに深みにハマっているような、、、そんな気持ちになってしまった。。。

Promiseの処理の例を書いてみた

```
function dispSmile(str) {
  return new Promise(
    function(onFulfilled, onRejected) {
      if(str != 'OK') {
        onRejected(new Error()); // 失敗の状態を返す
      }
      else onFulfilled(console.log(☺︎)); // 成功の状態を返す
      // onFulfilledまたはonRejectedのどちらかを返さなければこのPromiseは終了しない
    }
  )
}
```
引数の値が'OK'のときは`Fulfilled`の状態を返し、onFulfilled()の引数の値は次の処理に渡す値になってる
引数の値が'OK'以外は`Rejected`の状態を返し、onRejected()でエラーを返すようになっている
なので結果はこんな感じ

```
// 実行結果
dispSmile('OK'); // ☺︎
dispSmile('No'); // Error
```
例えば以下のようなPromiseを返すと、状態は呼び出されてもPending(初期状態)のままになる

```
function dispSmile(str) {
  return new Promise（function(onFulfilled, onRejected) {})
}
```

onFulfilledとonRejectedは、関数で、状態によって実行される処理、ということかな・・・

うーん、まだスッキリという感じではないけれど
Promiseの状態の持ち方は以前より理解できた気がするのはよかった

もう少し勉強してみて理解を深めていきたい
WEBカメラ取り込み

忘れない為のメモ書き程度となります。

WEBカメラを使用した画像取得及び保存に関するプログラム。
初学者が何とか辿り着いた答えの1つなので
見る人が見れば拙いのがご了承下さい。

出来ればアドバイスを頂けるとありがたいです。

環境
Windows10(64bit)
anacondanavigator
python3(3.7.7)
opencv(3.4.2)

## 使用ライブラリ
```python:cap_save.ipynb
import cv2
import sys
import os
from datetime import datetime
```
ディレクトリ作成及びファイル名に日付を使いたいので
`os`と`datetime`を使用しています。

## 保存先とファイル名の定義
```python:cap_save.ipynb
#保存ディレクトリの指定及びデータ名の定義
dir_path = '保存先'
basename = 'ファイル名'
```

## 使用デバイスの定義
```python:cap_save.ipynb
cap = cv2.VideoCapture(0)
```
`(0)`はＰＣ内蔵カメラを使用する設定となっているので
webカメラ(USBカメラ)を接続した際は`(1)`にすると認識。

## ディレクトリの作成
```python:cap_save.ipynb
os.makedirs(dir_path,exist_ok=True)
base_path = os.path.join(dir_path,basename)
datename = datetime.now().strftime('%m%d%H%M')
```
`os.makedirs`で保存先ディレクトリ(dir_pathにて設定した場所)に画像保存先を作成する。
保存先が存在すれば異常なく次に行きます。
`os.path.join`でパスを結合。
`datetime`はファイル名に取得時間を付けたい為に設定しています。

## 画像撮影
```python:cap_save.ipynb
n = 0
while True:
    
    ret,frame = cap.read()
    cv2.imshow(basename,frame)
    key = cv2.waitKey(1) & 0xFF    
    if key == ord('o'):
        cv2.imwrite((base_path + datename +'_'+ str(n) + ".png"),frame)
        n += 1
    elif key == ord('q'):
        break
        
cap.release()
cv2.destroyAllWindows()
```
撮影画像自体に連番をつけたいので最初に`n = 0`を設定
あとはキーボード『O』を押せば`cv2.imwrite((base_path + datename +'_'+ str(n) + ".png"),frame)`で
指定したフォルダ内に画像を保存します。
もっとスタイリッシュな書き方があると思いますが
私自身が『どこに』『どんな名前で』とわかりやすくするためにこのフォーマットにしています。

画像撮影→保存に関しては特に問題なく出来ました。

raspberrypi(stretch)にthonnyで実装しても問題なく走りました。

以上です。
【Day76】積み上げ日記

##学習内容
■クラス、インスタンスの復習
■クラスの継承
■モジュール
■メソッドの種類（別記事にて）

##学習ポイント
■クラス：設計書（抽象的）

■インスタンス：完成品（具体的）

■クラスの継承
class 親クラス extends Car {}

■モジュール
・エクスポート
export default 値

・エクスポート（名前付き）
export {値の名前};

・インポート
import 値 from “./ファイル名”

・インポート（名前付き）
import {値の名前} from “./ファイル名”
ジェネリクスの引数使用で型を定義

# ジェネリクスの引数使用で型を定義

ちょっとわかりにくいのですが以下のような感じです。
ジェネリクスのデフォルトの型を指定して `Data` を定義しております。
(そもそもジェネリクスはそういうのものですが・・・)
[Generics - TypeScript](https://www.typescriptlang.org/docs/handbook/generics.html)

```ts:assigned-default-type
type Data<T = { [key: string]: string | number }> = T

// { [key: string]: string | number }
const data1: Data = {}
// { id: number; name: string }
const data2: Data<{ id: number; name: string }> = { id: 1, name: 'Taro', abc: 'aaa' } // abc はエラー

// さらに加工する場合など
type PartialData<T> = Partial<Data<T>>
```

テーブルのデータなどに使えるかも・・・？
Laravelのコレクションでユーザー(グループ)ごとに最新のメッセージを取得

うちでLaravelで質問回答アプリを実装しています。
対話者のメッセージボックスを作りたい、要件をまとめました：<img width="400" alt="スクリーンショット 2020-06-02 6.44.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117741/6bab8862-3ebb-ddac-4aa2-8989815dbdb2.png">

ログイン中のユーザーはuser_meとし、他のユーザーごとに一番新しいメッセージを提示するメッセージリストを作りたいです。
そこでクリックしたら、そのユーザーとのメッセージモダルに飛ぶ。
ユーザー名は相手の名前、メッセージは対話中の一番新しいメッセージ（自分からメッセージのも含む）

SQLよりLaravelのコレクションはもっと使いやすいと思い、以下で案を。
まずuser_meと関わる全てのメッセージを時間順に並べて取得、

次に対話両方をグループとし、一番新しいメッセージだけ、リストにプッシュする。
リストに登録済のグループのメッセージはプッシュしません。

以下はMessageRepositoriesのメソッドの一部です。


```php5
namespace App\Repositories;


public function selectMessageByEachUser()
    {
        $me_id = user('api')->id;
        $messages = Message::with(['fromUser', 'toUser'])
            ->where('to_user_id', $me_id)
            ->orwhere('from_user_id', $me_id)
            ->orderBy('created_at', 'desc')
            ->get();

        $chat_room_groups = [];
        $new_messages = collect();
        foreach ($messages as $message) {
            $match_ids_1 = [$message->from_user_id, $message->to_user_id];
            $match_ids_2 = [$message->to_user_id, $message->from_user_id];
            if ($new_messages->isEmpty()) {
                $new_messages->push($message);
                array_push($chat_room_groups, $match_ids_1);
            } else {
                $res = !in_array($match_ids_1, $chat_room_groups, true)
                    && !in_array($match_ids_2, $chat_room_groups, true);
                if ($res) {
                    $new_messages->push($message);
                    array_push($chat_room_groups, $match_ids_1);
                }
            }
        }
        return $new_messages;
    }

```

次にメッセージコントローラは処理したリストをもらい、APIリソースをフロントエンドに発信

```php5
namespace App\Http\Controllers;

public function messageList()
    {
        $message=$this->message->selectMessageByEachUser();
        return new MessageCollection($message);
    }
```



どうせチャットルームグループは必要なら、グループに入るユーザーのIDと最新メッセージを保存するチャットルームのテーブルを作る方がいいかも？
メーセージを送信する際、新しいメッセージをテーブルに保存し、後処理はなしで、効率は上がります。
初心者によるプログラミング学習ログ 332日目

#100日チャレンジの332日目
twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。
100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。
332日目は、
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">おはようございます<br>332日目　2h<br>・ポートフォリオ作成<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/1267552417836457985?ref_src=twsrc%5Etfw">June 1, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
国連ベクトルタイルツールキットのプロジェクト運営プラットフォームをどうしよう

「あなたに長い手紙を書いたのは、短い手紙を書く時間がなかったからです」という趣旨のことをパスカルが書いたことがあるそうです。このエントリもそういうところがあります。

国連ベクトルタイルツールキット（UNVT）について、プロジェクト参加者の心理的安全性も確保しておきつつ、プロジェクト運営の透明性を高めたいと思います。

UNVT の運営における「オフィシャルな野望」は、引き続き「OSGeo incubation process に載せる」ですが、プロジェクト運営に割けるリソースが見込めない、もっと言えばプロジェクト運営にリソースを割り当てることで、実質的な開発・運用・設計に回せるリソースが枯渇する、ということを考えると、まだ当面はオフィシャルな野望を実現に至らせる線にはありません。

そこで、オンラインのツールを使って、内部判断の透明性を高めたいと思っています。

なお、上記目的のチャンネルは英語運用が基本になると思います。チャンネルを作れるのであれば、ローカル言語を使えるチャンネルを附設するかもしれません。

検討可能な候補は次の通りであると思っています。

## 国連事務局が運用する Microsoft Teams
国連事務局が国連事務局員用に運用している Microsoft Teams に、ゲストアカウントを追加してもらって参加する方法です。

この方法だと、国連オープン GIS イニシアティブの他のプロジェクトからも見えやすくなる、利用するシステムの個数を最小化できる、といった利点があると思います。また、アーカイブが消える可能性が低いと思います。

他方で、発行されるのがゲストアカウントなので、できることが少ないという欠点があります。実質上、チャットしか使えないかもしれません。

## Slack
UNVT はすでに Slack を持っていますが、私の運用がうまくないために、それほど議論を進めるツールとして活用できていない状況です。これを利用してプロジェクト運営プラットフォームにすることは考えられます。

この方法の場合、Teams と比べるとソフトウェア開発向けの機能が豊富であるという利点があると思います。

他方で、アカウント管理を私が行わなければならず、結果としてアカウント管理がいい加減になり、UNVT の透明性は今回検討する候補の中では最小になる可能性が高いと思います。また、無料のアカウントを使っているので、アーカイブが消えていくことになります。

## GitHub (issues)
GitHub (issues) を使って、誰でも見ることができるが、誰でも編集できるわけではない、というアレンジメントで運営をしていくということができるような気がします。

チャットがわりに issues を使うという案になりますね。

# 仮の結論
もう一個の、あまり使われていないチャンネルを増やす結果になってしまうだけになる恐れはありますが、GitHub (issues) でプロジェクト管理事項を処理していくということを考えてみようかなと思っています。

GitHub でいくのであれば、次の手順になると思います。

1. GitHub レポジトリを作ってみる unvt/pm とでもするのでしょう。
2. 最初のイシューを書いてみて、うまくいくのか試してみる。
3. Slack と Teams の既存チャンネルにアナウンスをし、参加者を誘導する
4. 適宜、オープンなチャンネルでも広報していく

## GitHub issues の運用イメージ
- milestone を丁寧に使って、タイムラインが見えるように工夫する
- 「日本語」といったラベルを使うことで、複数言語でも同一の issues に入れていく。この issues はあらゆる言語が可能であるが、英語以外の言語の場合には、言語でラベルを使って良い、といったルールをイメージする。

## GitHub projects の運用イメージ
- 言語ごとに違うビューがあってもいいのかもしれない
- Kanban は使うのかも
[IFTTT] Spotifyでもボタン１つで#NowPlayingで自動ツイート！

#経緯
Spotifyからの#NowPlayingのツイート、
iPhoneからもAndroidからも出来るようにしたい。

ってことでどっからでもSpotifyから#NowPlayingって自動ツイート出来るようにしよう。

結論、IFTTT使えばめっちゃ簡単！
iPhoneだけじゃなくSpotify使える端末ならAndroidでもPCでもどっからでも可能！

こんな感じ↓
（#NowPlaying:「曲名」by「アーティスト名｣ on Spotify >> SpotifyのURL+アルバム画像）

(クリープハイプのバンドって曲です)
<img width="295" alt="iOS の画像 (1).jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486822/990933a7-44c3-ad5c-d1df-2f7b64526da1.jpeg">



#IFTTTとは
[IFTTTのサイト](https://ifttt.com/)

簡単に言うと
「もし〇〇のなら、××する」
ってのを作れるアプリケーションです。

例:  8時になったら、おはよーとツイートする。

---
では実際に作っていきましょう！

#作成

今回はiPhoneのIFTTTのアプリから作っていきます。(AndroidでもPCでも同じ)

[Apple Store](https://itunes.apple.com/app/apple-store/id660944635?pt=1752682&ct=/login&mt=8)
[Google Play](https://play.google.com/store/apps/details?id=com.ifttt.ifttt&utm_source=/login&utm_medium=web)

まずアプリをインストールしたら、google等のアカウントでログイン、

そして最下部のGet Moreを押し、Createをタップ。

下のような画面になると思います。
<img width="375" alt="IMG_0012.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486822/6e485e33-2cd6-fd3f-4109-fd79b0108fd9.png">


「If this then that」は、上で言う「もし〇〇なら、××する」です。

## "this" と "that"　の選定

### "this"

まずThisをタップし、Spotifyと入力して選択
(上で言う〇〇)

<img width="375" alt="IMG_0014.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486822/c292bf0e-2d3d-f8bb-9236-235347da6aac.png">


---
New saved track >> ハートマークを押したら
New track added to a playlist >> 任意のプレイリストに追加したら

---

このうち好きな方を選択し、「もし〇〇なら」を確定させます。
（僕はボタン1つでツイートさせたいので上を選びました）


### "that"

次にThatをタップし、twitterと検索し選択
(上で言う××)

<img width="375" alt="IMG_0016.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486822/34f54aa4-dbc8-7a3a-c20e-32807a8de323.png">

今回使うのは

---
post a tweet >> ツイートする
post a tweet with image >> 画像つきでツイートする

---

のどちらかです。
ここで「××する」を確定させます。

僕はアルバムジャケットと一緒にツイートしたかったので下を選びました。

するとこのようになります。

「もしハートマークを押したら、画像つきでツイートする」

ツイート内容は余計な部分を消して　#NowPlaying　を追加しました。

<img width="375" alt="iOS の画像.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486822/ce5f5461-3409-7da0-8088-33b919fdc8de.png">


---
"TrackName": 曲名
"ArtistName": アーティスト名
"TrackURL": Spotifyのリンク
"AlbumCoverURL": アルバム写真

---


##完成！

名前を決めて(任意)、ツイート時に通知を送るか否かを設定して、finish!

名前は「ハートを押したら#NowPlayingでツイート」にしときました。
<img width="375" alt="IMG_0019.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486822/111af179-c359-dd11-d258-fd1656304a65.png">


##動作確認

これでどっからでもハートマーク押せば自動ツイートできるようになりました！
もともと押されていても押し直せばツイートされます。
ちょっとツイートまで遅いときもありますが...()
(たまに10分くらいかかる…)
この利点はiPhoneでもAndroidでもPCでも出来るとこですね！

それでは
Let's enjoy MUSIC !
android の alfred を　使った面会システム　（ポケットWiFiで距離延長）

##コロナのため　患者さんを直接　家族に会わすことはできません。　そこで　使用しなくなった古いアンドロイドタブレットのカメラを利用し、家族はノートPCの画面を使って面会します。　目玉（カメラ）さえついていればスマホでもOKです。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/1038d9be-dc6d-7cec-3741-a35f1c52172f.png)

閑話休題
------
聖書によると
神は人をご自身のかたちとして創造された。

ところが
![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/577cb4ae-da51-e31b-72a3-bf41f9b6f358.jpeg)
は　西洋人から見れば化物、顔が３つ　腕が６本、　でも凄い美人

でもヒンズー教の創造神ブラフマーは
![b.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/7e45bc90-b016-6873-74d4-d833c3e5b03c.jpeg)

なので　ヨーロッパ人は仏教をヒンズー教の一派とみているらしい

-------

|wifi電波状況がよければ　下図のポケットwifiは省略できます|
|:---|
|古物ばかり使ってるので安価です。なおandroidアプリのalfredは無料版で十分ですし、あとノートPCに無料のgoogle クロミウムをいれたら　準備完了です|
|二人　（タブレットとノートPC）は　銀河いやちがったインターネットの上で出会います、彦星と織姫のように|

![alfred.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/15a2af8b-4692-5243-aa4c-77f82fe8b56d.jpeg)

なお
１）本来ならばwifi ルーターだけで行けるはずですが
廊下から直角に曲がって病室に入っていくので
ポケットwifiを使わなくてはタブレットに電波が飛んでいきませんでした
　
２）alfredは古いandroid のvirsionでもOK
で　自分のタブレットのは5でした

![11.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/bb986e54-aef0-058c-2946-04e71e3da8f5.jpeg)


##恋愛歌だった君が代
いざな **き** （男）
いざな **み** （女）
君ー＞きみー＞き（男）：み（女）ー＞love is forever( **とこしえに** )
https://www.youtube.com/watch?v=0czO0ZNA0J4　より
なんとのどか
アドレナリンを出すためには、フランス国家
https://www.youtube.com/watch?v=-irf0TtQI3Y



|考察|
|:---|
|タブレットも　ノートPCも　双方とも　インターネットの仮想空間のなかにいます。　そしてここにトンネルがあって　このトンネルに入るには　同じgmailアドレス（もちろんそのパスワード）でないと入れません。　そういったことで秘密性が確保されてます|
|従ってこれを自宅のワンちゃんに対してすると　ハワイからでも　インターネットを通してワンコの様子がみれます|
|古いandroidしかインストールできないタブレットあるいはスマホでいいのが嬉しい|



--------------------
##近況　　患者さん<---タブレット　   スマホ<---家族
現在はtabletで患者さんを撮って

家族はパソコンではなく　**スマホ**　の画面を見ます
こっちの場合は　スマホでは　クロームは使わず　**alfredを立ち上げるだけ**です
スマホのalfredのマイクを押してる間だけ　家族の声が　患者さんに伝わります

--------------------


##現況　

![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/8a81f1c5-92df-396d-074d-b93a5dc5243c.jpeg)


**まず**
患者さんには　古い古いandroidのスマホでalfredを
ユーザー　　hp1@gmail.com 
パスワード　12345678
で起動し
このスマホのカメラを向けます

**その後**

家族にも　もうちょっと新しいandroidのスマホのalfredを起動します
すると　ユーザーを求められます
hp1@gmail.comとします
そして　
パスワード　12345678
をいれると
患者さんがでてきます


##マニュアルは

![IMG_20211118_141911.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/77d57a8c-d5cf-06e6-0f39-9f44956ec9b2.jpeg)
WSL(WSL2)でビルドが遅くて重くてホットリロードが効かないとき

# 結論

WSLを使うとき、`/mnt/c`配下で開発せず、`~`で開発しなさい。

# 概要

WSL(WSL2)上でVue(Nuxt)やReact(Next, Gatsby)などの開発をしていて、ビルドすると始まりが遅いしビルド時間もかなり長くなるという方や、ファイル名の変更ができなかったり、保存時にホットリロードが効いていないなどで悩んでいる方用の対処法。

# なぜ？

- WSLでのビルド時間が長くなってしまう原因の一つとして`/mnt/c`配下で作業していることが挙げられる。
`/mnt`はWSL内からWindows側のファイルへアクセスするためにあるディレクトリで、`/mnt/c`配下はWindowsのCドライブのディレクトリを指す。つまり、Windows側の`C:\`は、WSLでは`/mnt/c`ということ。
- Windows側のファイルシステムを経由してしまうと、ビルドに時間がかかったり、一部の機能が制限されてしまうため、ファイル名の変更ができなかったり、ホットリロードが効かなかったりする
- 解決策としては`/mnt/c`配下で作業するのを避け、WSLの`~`配下などで作業をすることで、期待通りの動きをしてくれるはず。
Javascript　初めてのGSAPアニメーションの使い方　その6　TweenMax.setとTimelineMaxプロパティ

前回の記事はこちら
[Javascript　初めてのGSAPアニメーションの使い方　その5　staggerTo/staggerFrom](https://qiita.com/fumiya0414/items/38c86d9a4df253005218)

今回はTweenMax.setとTimelineMaxのプロパティーを
組み合わせたアニメーションについて説明します。

#TweenMax.set

今回使用するhtmlは以下です。
※CSSで配置調整と色付けしています。

```html
      <div class="column col5">
        <p>パネル 5 (.oval)</p>
        <div class="oval shape"></div>
      </div>
```

[![Image from Gyazo](https://i.gyazo.com/dd1da46aaa37c27c9f24fcc97565a575.png)](https://gyazo.com/dd1da46aaa37c27c9f24fcc97565a575)

jsシートに以下を記述します

```js
TweenMax.set('.oval', { x: -100});
```
実行結果
[![Image from Gyazo](https://i.gyazo.com/5c3ce20afd83e28d84220f43452a0e69.png)](https://gyazo.com/5c3ce20afd83e28d84220f43452a0e69)

TweenMax.setを使用することによってアニメーションの初期位置をずらすことができます。
※この段階ではアニメーションはしません。
CSSのtransform: translate();と同じ意味です。

##TimelineMaxのプロパティ

ここからTimelineMaxを使用してアニメーションを設定しています。
まずは繰り返しを３回にしてみます。

```js
TweenMax.set('.oval', { x: -100});

const tlAnimation = new TimelineMax({ repeat:3 }); //繰り返しを３回に設定
tlAnimation.to('.oval', 0.5, { x: 100 })
.to('.oval', 0.5, { x: -100});

```

実行結果
[![Image from Gyazo](https://i.gyazo.com/6fe1a7ff3e9132345060d4436ebfc45a.gif)](https://gyazo.com/6fe1a7ff3e9132345060d4436ebfc45a)

タイムラインでx軸方向に100px,動かしてから-100px方向に動かす処理を入れています。
ここで気をつけるのは基準位置は.setで取得したx:-100にはならず
htmlで設定した位置になるという点です。

そのため見た目には最初の動き幅は200px動きますが実際に指定するのは左右100pxです。

回数制限なく繰り返す場合は数値に-1を入れます。なんとなくrepeat:trueにしたくなりますが
それでは無制限にならないので注意しましょう。

```js
TweenMax.set('.oval', { x: -100});

const tlAnimation = new TimelineMax({ repeat:-1 });
tlAnimation.to('.oval', .5, { x: 100 })
.to('.oval', .5, { x: -100});

```

実行結果
[![Image from Gyazo](https://i.gyazo.com/902f2717ee45f52617c3fa2e3f7c86bd.gif)](https://gyazo.com/902f2717ee45f52617c3fa2e3f7c86bd)

プロパティにrepeatDelayを入れるとリピート間隔の指定（秒）になります。

```js
TweenMax.set('.oval', { x: -100});

const tlAnimation = new TimelineMax({ repeat:-1, repeatDelay:2 }); //２秒の間隔を開けて繰り返し（無制限）
tlAnimation.to('.oval', .5, { x: 100 })
.to('.oval', .5, { x: -100});

```

[![Image from Gyazo](https://i.gyazo.com/40e996fbcb32659768324ced7f954abb.gif)](https://gyazo.com/40e996fbcb32659768324ced7f954abb)

プロパティにyoyo:trueを入れると名前の通りヨーヨーの動きになります。

```js
TweenMax.set('.oval', { x: -100});
const tlAnimation = new TimelineMax({ repeat:-1, yoyo: true });
tlAnimation.to('.oval', 1, { x: 100 })
```

[![Image from Gyazo](https://i.gyazo.com/8c0dc1210e1f0501aa35736968c95436.gif)](https://gyazo.com/8c0dc1210e1f0501aa35736968c95436)

次回はTimelineMaxのラベルと同期処理です。

[Javascript　初めてのGSAPアニメーションの使い方　その7　TimelineMaxのラベルと同期処理](https://qiita.com/fumiya0414/items/e401cb70769a9f2206aa)
マルチストリーム GZIP は GZipStream でそのまま読み込める (C#)

# マルチストリーム GZIP は GZipStream でそのまま読み込める (C#)

\# 以下の記事が書かれた時の版数は .NET Core 3.1 (3.1.300) となります.

あるシステムで複数回追記しないといけない CSV(中間ファイル)が大きくて困っていて、サイズ・圧縮データのチャンクの連続にするか、圧縮データ・サイズのチャンクの連続にするか悩んでいたのだが(※1)、[.NET Frameworkのbzip2ライブラリを調査](https://qiita.com/7shi/items/235328dbdc5c0c85edcb) の記事で世の中にマルチストリーム bzip2 というものがあることに気づいた. bzip2 だと外部ライブラリが必要でちょっと嫌なので、世の中にマルチストリーム GZIP は存在しないのかを調査した. Go 言語のビルトインの GZIP パッケージは[マルチストリーム対応](https://golang.org/pkg/compress/gzip/#Reader.Multistream)していた. また gzip コマンドも普通に対応していた.

```sh
$ echo -n "hello " | gzip > /tmp/hello.gz
$ echo -n "world" | gzip >> /tmp/hello.gz
$ gzip -dc /tmp/hello.gz
hello world
```

.NET の `GZipStream` を試したところ、マルチストリームでもそのまま読み込めた. マルチストリームで BOM 付き UTF-8 を書き出すのめんどくさいっすね…….

```cs
[TestMethod]
public void GZipMultiStreamTest()
{
    var text1 = "Hello ";
    var text2 = "World!";
    var expected = text1 + text2;
    var ms = new MemoryStream();
    using (var writer = new StreamWriter(new GZipStream(ms, CompressionLevel.Optimal, true), Encoding.UTF8))
    {
        writer.Write(text1);
    }
    using (var writer = new StreamWriter(new GZipStream(ms, CompressionLevel.Optimal), new UTF8Encoding(false)))
    {
        writer.Write(text2);
    }
    ms = new MemoryStream(ms.ToArray());
    using (var reader = new StreamReader(new GZipStream(ms, CompressionMode.Decompress), Encoding.UTF8))
    {
        Assert.AreEqual(expected, reader.ReadToEnd());
    }
}
```

なお .NET Framework 4.8 では動作しなくて調査したところ、RFC レベルでマルチストリームは動作するのが当然で、.NET Core 3.0 / 2.2 で動作するようになったようである([Add support for concatenated GZip streams. #30442](https://github.com/dotnet/corefx/pull/30442)). なんで .NET Framework にもバグ修正を反映してくれないんだよ…….

※1: xxx.001.csv.gz, xxx.002.csv.gz みたいな連番ファイルにすることや、xxx.csv.zip の中に 001.csv, 002.csv みたいな連番データを入れることも考えたが、002 以降に CSV ヘッダを入れても入れなくても微妙だなあと思いボツに. 前者はファイル数が多いことも微妙.
PlayCanvasでTypeScriptを使うためのメモ(Webpack編)

#概要

[前回の記事](https://qiita.com/riafeed/items/3af6117be7a7ca38b461)でwebpackを使わず、無理やりコードを追加することでモジュール問題を解消しましたが、
今回は、そもそもああいったモジュール問題を解決するためにあるWebpackを利用したgulpタスクを作ります。

#Webpackの設定

ポイントとしては、PlayCanvasライブラリは実行時に別の形で(たぶんScriptタグで)読み込まれるため、externalで生成されるJavaScriptコードに組み込まないように設定しておく必要があります(そうしないと競合するのでたぶん動かない)

```webpack.config.js
const path = require("path");
const glob = require("glob");

module.exports = {
  mode: "development",
  //mode: 'production',
  devtool: "",
  entry: glob.sync("./src/*.ts"),
  output: {
    filename: "output.js",
    path: path.resolve(__dirname, "dist/"),
  },
  externals: [
    {
      playcanvas: 'pc'
    }
  ],
  module: {
    rules: [
      {
        test: /\.ts$/,
        exclude: /node_modules/,
        loader: "ts-loader"
      },
    ]
  },
  resolve: {
    extensions: [".ts", ".js"]
  },
};
```

#gulpfile.js

WebPack未使用版との違いは、TypeScriptのトランスパイルをWebpack経由にしていることです。その関係で前回はgulpfile.js上で直接TypeScriptのオプションを設定していましたが、今回はtsconfig.jsonで設定をしておく必要があります。

```gulpfile.js
const gulp = require("gulp");
const playcanvas = require("gulp-playcanvas");
const pcOptions = require("./playcanvas.json");
const webpackStream = require('webpack-stream');
const webpack = require('webpack');
const webpackConfig = require('./webpack.config.js');

gulp.task("ts", () => {
  return webpackStream(webpackConfig, webpack)
  .pipe(gulp.dest('./dist/'))
  .pipe(playcanvas(pcOptions));
});

gulp.task("js", () => {
  return gulp
    .src(["src/**/*.js", "!src/**/_*.js", "!./node_modules/**"])
    .pipe(gulp.dest("dist/"))
    .pipe(playcanvas(pcOptions));
});

gulp.task("watch", function() {
  gulp.watch(["src/**/*.ts", "!src/**/_*.ts", "!./node_modules/**"], gulp.task("ts"));
  gulp.watch(["src/**/*.js", "!src/**/_*.js", "!./node_modules/**"], gulp.task("js"));
});
 
gulp.task("default", gulp.parallel("watch"));
```


#感想

これで、トランスパイルに成功するとoutput.jsという単一のJavascriptファイルが生成され、PlayCanvasにアップロードされます。

眺めるとそこそこの量のコードがWebpackによって追加されるので、小規模なものだと気になるかもしれませんね…

規模によって使い分けるといいのではないでしょうか。
AWS Cloud9でRVMのアップデートをする

Cloud9の環境でプリインストールされている「RVM」ですが、Rubyの最新の安定版をインストールする際にRVMをアップデートしないといけなかったのでメモします。

## RVMとは
**RVM**は**R**uby **V**ersion **M**anagerの略です。
Rubyのバージョンを管理するのに使います。
例えばインストール、アンインストール、バージョンの切り替えなどを実行できます。

公式サイト
[RVM: Ruby Version Manager -      RVM Ruby Version Manager - Documentation](https://rvm.io)

## RVMのサイトからキーをインストールしておく
セキュリティを確保するため、RVMでは署名をチェックしています。キーをインストールしていない場合はしておきます。


[RVM: Ruby Version Manager -](https://rvm.io/rvm/security)
からコマンドをコピーします。トリプルクリックすると便利です。
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538652/8dbc62c2-8ea9-b4dd-e343-26c0ba6274d8.png)



Cloud9のコンソールで、sudo(root権限で実行)の後にコマンドを貼り付けて実行します。
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538652/74ab11a2-4075-2b1c-6714-583cd273bb17.png)


これでキーをインストールできました。

## RVMのバージョンを確認する
`rvm -v`
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538652/d084bec6-22bd-81b0-3118-b705d120edb2.png)

今1.29.8ですが、これを1.29.10にしたいんです！

## RVMのバージョンを更新する
アップデート(アップグレード)はgetコマンドです。
`rvm get <version>`

1.29.10に更新したい場合は以下のようになります。
`rvm get 1.29.10`

ではバージョンを指定してgetコマンドを実行します。
<img width="807" alt="スクリーンショット 2020-06-01 14.50.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538652/21adf889-af17-d84c-7172-7ea2b61e3de9.png">


確認のため、RVMのバージョンを表示します。
`rvm -v`
<img width="657" alt="スクリーンショット 2020-06-02 2.38.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538652/020e141e-a456-2b9c-b97f-0b80cf471aed.png">
これでアップデートできました。



## (おまけ)RVMのヘルプを表示する
コマンドを調べたいときに使います。

`rvm help`
または
`rvm`
どちらでも表示されます。
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538652/aa5545b1-a46d-cbdf-0779-1cf892fc0f5c.png)
PlayCanvasでTypeScriptを使うためのメモ(Webpack未使用編)

#概要

[前回の記事(準備編)](https://qiita.com/riafeed/items/d79615260c0cf3f47e92)でアセットをアップロードするための設定までやりましたが、今回はgulpを使ってトランスパイルからアップロードまで一括で行えるようにgulpタスクを作ります。

なぜgulpを使うのかというと、前回の記事にも書いた通り、[PlayCanvas用のgulpタスクが公開されている](https://qiita.com/yushimatenjin/items/5f0f178e8a4ba4a5ee57)からです。

#gulpfile.js

後述の問題のため、through2というgulp用のプラグインを使い、トランスパイル後のコードの先頭に2行ほどコードを書き加えるという泥臭い処理を行っています…(´・ω・`)

```gulpfile.js
const gulp = require("gulp");
const playcanvas = require("gulp-playcanvas");
const pcOptions = require("./playcanvas.json");
const typescript = require("gulp-typescript");
const through2 = require('through2');

gulp.task("ts", () => {
  return gulp
    .src(["src/**/*.ts", "!src/**/_*.ts", "!./node_modules/**"])
    .pipe(typescript({target: "ES5", module: "commonjs"}))         //ES5
    //.pipe(typescript({target: "ES2015", module: "commonjs"}))    //ES2015(ES6)
    .pipe(through2.obj((file, enc, callback) => {
      if (file.isBuffer()) {
        let contents = String(file.contents);
        contents = "var exports = {};\nvar require = function(mod){};\n" + contents;
        //contents = "/*jshint esversion: 6, asi: true, laxbreak: true*/\n" + contents;   //ES2015(ES6)
        file.contents = Buffer.from(contents);
      }
      callback(null, file);
    }))
    .pipe(gulp.dest("dist/"))
    .pipe(playcanvas(pcOptions));
});

gulp.task("js", () => {
  return gulp
    .src(["src/**/*.js", "!src/**/_*.js"])
    .pipe(gulp.dest("dist/"))
    .pipe(playcanvas(pcOptions));
});

gulp.task("watch", function() {
  gulp.watch(["src/**/*.ts", "!src/**/_*.ts"], gulp.task("ts"));
  gulp.watch(["src/**/*.js", "!src/**/_*.js"], gulp.task("js"));
});
 
gulp.task("default", gulp.parallel("watch"));

```



#モジュール問題

トランスパイルしたコードの先頭に付け足す理由はモジュール機構の問題になります、ざっくり挙げると

- トランスパイルしただけのJavascriptコードそのままではモジュール機構の関係でPlayCanvas上ではエラーになります。
- ブラウザ環境ではES2015(ES6)形式のモジュールしかサポートされていません(IEの場合はモジュール自体対応していません)
- ES2015形式でimportすると、Playcanvasの実行時にエラーが出ます(importはトップレベルに記載する必要があるのですがランタイム上でスクリプトは下位へ移動されるから？)
- AMDやUMDはブラウザ上でも動くモジュール形式だそうですが、非同期だからなのかPlayCanvasエディタでアトリビュートを読み込めないので意味がありません


これをいろいろどうにかする方法を探りましたが、最も簡単で無難だったのが、commonjs形式でトランスパイルした上で

```javascript
var exports = {};
var require = function(mod){};
```

という何もしないモジュール関係の変数と関数を定義するコードを付け足すことでした。
もっといい方法があればだれか教えてください…

#そのためのWebpack

そもそもこういったモジュール機構の問題を解決するためにWebpackがあるので、
次回はWebpackを使ってあんなことをしなくてもPlaycanvasで使えるコードを生成するためのタスクを作ります。
Javascript　初めてのGSAPアニメーションの使い方　その5　staggerTo/staggerFrom


前回の記事はこちら
[Javascript　初めてのGSAPアニメーションの使い方　その4　easing設定](https://qiita.com/fumiya0414/items/a0cc791c96f56472ca5a)

今回はstaggerFrom/staggerToについて説明します。

staggerは繰り返す複数の要素に対して連続したアニメーションを設定できます。

#staggerFrom

htmlは以下のように三角形を連続して表示させています。

```html
      <div class="column col4">
        <p>パネル 4 (.triangle)</p>
        <div class="triangleContainer">
          <div class="triangle shape"></div>
          <div class="triangle shape"></div>
          <div class="triangle shape"></div>
          <div class="triangle shape"></div>
          <div class="triangle shape"></div>
          <div class="triangle shape"></div>
          <div class="triangle shape"></div>
          <div class="triangle shape"></div>
          <div class="triangle shape"></div>
          <div class="triangle shape"></div>
          <div class="triangle shape"></div>
          <div class="triangle shape"></div>
          <div class="triangle shape"></div>
          <div class="triangle shape"></div>
          <div class="triangle shape"></div>
          <div class="triangle shape"></div>
          <div class="triangle shape"></div>
          <div class="triangle shape"></div>
          <div class="triangle shape"></div>
          <div class="triangle shape"></div>
        </div>
        <!--triangle container -->
      </div>

```

[![Image from Gyazo](https://i.gyazo.com/eff339b5070a8513681f5b5ea5cf02dd.png)](https://gyazo.com/eff339b5070a8513681f5b5ea5cf02dd)

ここにstaggerを使用してアニメーションを設定します。

```javascript

TweenMax.staggerFrom('.triangle', 1, { x: 200, y:200, opacity:0 }, 0.1)

```

三角形(.triangle)に対して
・各要素のアニメーションの時間は１秒
・x方向へ2００px,y方向へ200pxから
・透明度0から徐々に
・各要素のずれは0.1秒ずつ
という設定にします。

実行結果
[![Image from Gyazo](https://i.gyazo.com/d733263de51178fd883ad0399dca036f.gif)](https://gyazo.com/d733263de51178fd883ad0399dca036f)

#staggerTo

続いてstaggerToの動きを見てみましょう

```javascript
TweenMax.staggerTo('.triangle', 1, { x: 200, y:200 }, 0.1)
```

三角形(.triangle)に対して
・各要素のアニメーションの時間は１秒
・x方向へ2００px,y方向へ200px
・透明度0から徐々に
・各要素のずれは0.1秒ずつ
という設定にします。

実行結果
[![Image from Gyazo](https://i.gyazo.com/231ad34be81de5c99a3ebe743207eeca.gif)](https://gyazo.com/231ad34be81de5c99a3ebe743207eeca)

このように初期位置から指定位置へ向かっていく動きとなります。

プロパティとしてeasingを設定することもできます。
[easingの記事はこちら](https://qiita.com/fumiya0414/items/a0cc791c96f56472ca5a)

```javascript

TweenMax.staggerFrom('.triangle', 1, { x: 200, y:200, ease:Back.easeOut }, 0.1)
```

[![Image from Gyazo](https://i.gyazo.com/14ef107cb1e0a0e9ff8289a3a3d546a3.gif)](https://gyazo.com/14ef107cb1e0a0e9ff8289a3a3d546a3)

次回はTweenMax.setとTimelineMax プロパティです。
[Javascript　初めてのGSAPアニメーションの使い方　その6　TweenMax.setとTimelineMaxプロパティ](https://qiita.com/fumiya0414/items/09605bc01683e57efa76)
PlayCanvasでTypeScriptを使うためのメモ(コーディング編)

#概要

せっかくTypeScriptでPlayCanvasをコーディングできるようになっても、
従来のPlayCanvasサンプルによくみられるプロトタイプベースのコーディングをしていたのでは意味がないので
(最近まで古いJavaScriptしかサポートしていなかったので致し方ないのですが…)

サンプルとして同じコードをクラスベースに書き換えたものを載せておきます。
TypeScriptではなく、ES2015(ES6)で作る際の参考にもなるかもしれません。

コードは新規登録したときに作成された「My First Project」のfollow.jsというコードをクラスベースに書き換えてみます。

#プロトタイプベース

```javascript
var Follow = pc.createScript('follow');

Follow.attributes.add('target', {
    type: 'entity',
    title: 'Target',
    description: 'The Entity to follow'
});

Follow.attributes.add('distance', {
    type: 'number',
    default: 4,
    title: 'Distance',
    description: 'How far from the Entity should the follower be'
});

// initialize code called once per entity
Follow.prototype.initialize = function() {
    this.vec = new pc.Vec3();
};

// update code called every frame
Follow.prototype.update = function(dt) {
    if (!this.target) return;

    // get the position of the target entity
    var pos = this.target.getPosition();

    // calculate the desired position for this entity
    pos.x += 0.75 * this.distance;
    pos.y += 1.0 * this.distance;
    pos.z += 0.75 * this.distance;

    // smoothly interpolate towards the target position
    this.vec.lerp(this.vec, pos, 0.1);

    // set the position for this entity
    this.entity.setPosition(this.vec); 
};
```

#クラスベース

上記のプロトタイプベースのコードをクラスベースに書き換えるとこうなります。
コメントで書き換えるポイントを載せてあります。

```typescript
import 'playcanvas';   //PlayCanvasライブラリ

//クラスベースの場合はpc.ScriptTypeを継承する。
class Follow extends pc.ScriptType {

    public vec!: pc.Vec3;

    //TypeScript上ではアトリビュートは下記のattributes.addとは別に、フィールドとして別途設定しておく必要があります。
    //DRY原則に反していて面倒ですが、typeとクラス名を合わせれば正しくコード補完が効くので便利です。
    //(PlayCanvadのwebエディタではアトリビュートのコード補完は未対応のようです)
    //トランスパイル後にはこのフィールドは消える模様
    public target!: pc.Entity;
    public distance!: number;

    // update等の各種メソッドはprototype.メソッド名に関数を代入するのではなく、pc.ScriptTypeクラスのメソッドをオーバーライドする。

    // initialize code called once per entity
    public initialize() {
        this.vec = new pc.Vec3();
    }

    // update code called every frame

    public update(dt: number) {    //updateメソッドの引数であるdtはnumber型です。
        // called each tick

        if (!this.target) {
            return;
        }
        // get the position of the target entity
        var pos = this.target.getPosition();
        // calculate the desired position for this entity
        pos.x += 0.75 * this.distance;
        pos.y += 1.0 * this.distance;
        pos.z += 0.75 * this.distance;
        // smoothly interpolate towards the target position
        this.vec.lerp(this.vec, pos, 0.1);
        // set the position for this entity
        this.entity.setPosition(this.vec);
    }
}

//クラスベースで作る場合はpc.createScriptではなく、pc.registerScriptを使う。
//またコードの先頭ではなく、クラス定義の後に呼び出す。
pc.registerScript(Follow, "follow");

//アトリビュートはクラス定義かつpc.registerScriptの後に追加する
Follow.attributes.add('target', {
    type: 'entity',
    title: 'Target',
    description: 'The Entity to follow'
});

Follow.attributes.add('distance', {
    type: 'number',
    default: 4,
    title: 'Distance',
    description: 'How far from the Entity should the follower be'
});

```
PlayCanvasでTypeScriptを使うためのメモ(準備編)

#概要

2020年5月現在、Playcanvas(の公式エディタ)ではTypeScriptをサポートしていないので、
どうにか使えないかと試行錯誤した結果をまとめるためのメモです。

#そもそもPlayCanvasとは

誤解を恐れずざっくり言えばエディタも実行環境もブラウザでスクリプトがJavaScriptなUnityといったところでしょうか。
詳しくは[公式サイト](https://playcanvas.com/)、[日本語公式サイト](https://playcanvas.jp/)、[関連リンク集の記事](https://qiita.com/yushimatenjin/items/ae2e3056422c1889590d)あたりでも。

#実現方法

PlayCanvasはREST APIを使ってアセット(ファイルみたいなもの)をアップロードする機能を持っているので、
それを使ってnode.js環境でTypescriptコードをトランスパイルし出来上がったJavaScriptコードをアップロードすればエディタの環境を生かしつつスクリプトをTypeScriptでコーディングする環境が実現できます。
タスクランナーを使ってトランスパイルからアップロードまで一括でまとめて行うこともできます。

#インストール

node.js環境が必要ですので、お手持ちのPCにインストールするか、インストールされている環境を用意してください。
IDEはなんでもいいですが、VSCodeがおすすめです。
PlayCanvas同様IDEもブラウザ上で開発したい場合はコマンドラインが使えるWebIDEが必要です。
探した範囲で無料でもコマンドラインが使えるWebIDEは[GitPod](https://www.gitpod.io/)(無料ユーザーは月50時間までの使用制限あり)くらいでした。

以下のモジュールをインストールします。

gulp
typescript
gulp-playcanvas
gulp-typescript
playcanvas
through2 (Webpackを使う場合は不要)

WebPackを使う場合は以下をインストールします
webpack
webpack-cli
webpack-stream
ts-loader

基本的にはローカルでもグローバルでもどちらでもいいようですが、gulpだけはグローバルとローカル両方に入れる必要があるようです。

#node.js環境でPlayCanvas APIを使う

「[Gulpのプラグインを書いたらPlayCanvasでの開発がめちゃくちゃ便利になった](https://qiita.com/yushimatenjin/items/5f0f178e8a4ba4a5ee57)」という記事で
Playcanvas APIのラッパとglupタスクをnpmやyarnでインストールできる形で公開された方がいましたので、有難く使わせていただきます。
ただ残念ながらAPIの使用に必要な設定ファイル(playcanvas.json)の説明が欠けているようなので、自分なりに探ってみた結果をのせておきます。

```playcanvas.json
{
  "accessToken": "",
  "projectName": "",
  "projectId": "",
  "scenes": [""],
  "branchId": "",
  "remotePath": ""
}
```

PlayCanvasのログイン直後の画面(HOME)から辿るものは先頭に＊、対象にするプロジェクトを開いたエディタ画面から辿るものは先頭に＋をつけておきます。
エディタ画面の各種名称は[チュートリアル](https://support.playcanvas.jp/hc/ja/articles/224228548-%E3%83%81%E3%83%A5%E3%83%BC%E3%83%88%E3%83%AA%E3%82%A2%E3%83%AB-PlayCanvas%E3%81%AE%E5%9F%BA%E6%9C%AC%E6%93%8D%E4%BD%9C-2-7)の「PlayCanvas Editor」に記載の名称に準拠しています。

####＊accessToken:

右上のユーザーアイコンからメニューを開き、「Account」を選んでアカウント設定に行くと、下のほうに「API Tokens」という項目があるのでその中の「GENERATE TOKEN＋」をクリック、ダイアログが出て名前の入力を求められるので適当に名前をつけるトークンとなる文字列が現れるのでそれをコピーアンドペーストします。

####＊projectName:

プロジェクト名を直接記述するか、右上のユーザーアイコンからメニューを開き、「Projects」を選んでプロジェクト一覧から対象のプロジェクトをクリックしてoverviewを開き、上のプロジェクト名をコピーアンドペーストします。

####＊projectID:

右上のユーザーアイコンからメニューを開き、「Projects」を選んで出てきた画面から対象のプロジェクトをクリックしてoverviewを開くとURLに6桁の数字が載っているはずなのでその数字をコピーアンドペーストします。

https://playcanvas.com/project/******/overview/[プロジェクト名]

*の部分が設定する数字になります。

####＋scenes:

対象のシーン名を直接記述するか、エディタを開き、対象のシーンを開いた後、ビューの左上からシーン名をクリックすると右側のインスペクタにシーン名の設定が表示されるので、そこからコピーアンドペーストします。配列形式なので複数指定できるっぽい感じになっていますが、やるとどうなるかは未確認。

####＋branchID:

ビューにあるブランチ名、または左側にあるメニュー上のPlayCanvasアイコンをクリックして表示されるメニューから「Version Control」を選ぶとブランチの一覧が出てくるので(初期状態ではmasterというブランチ1つだけ)対象のブランチ名の下に表示されている長ったらしい英数字とハイフンの組み合わせになってる文字列をコピーアンドペーストします。

####＋remotePath:

スクリプト(アセット)をアップロードしたいフォルダアセット名を記述します。フォルダアセットがない場合はあらかじめ作っておく必要があります。


#準備はここまで

これでアセットをアップロードする準備はできたのでgulpタスクを用意するのですが、モジュール機構の関係で(詳細は後述)Webpackを使わない場合と使う場合で内容が異なるので続きの記事に載せたいと思います。
OWASP Juice ShopをHerokuにデプロイする

1. [Heroku](https://jp.heroku.com/)にログインしておきます

1. [OWASP Juice Shopのサイト](https://owasp.org/www-project-juice-shop/)に行き、サイドメニューの`From Source`をクリックします
( https://elements.heroku.com/buttons/bkimminich/juice-shop でもいい)
    <img width="1280" alt="スクリーンショット 2020-06-02 0.37.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461309/c40cfbbd-4d3b-c2fe-8463-138789c7d939.png">

1. `Deploy to Heroku`をクリックします
    <img width="1280" alt="スクリーンショット 2020-06-02 0.38.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461309/6e7b1652-d1cc-0dd9-4ac5-e9158ff886e2.png">

1. 適当にApp nameを入力して、`Deploy app`をクリックします
    <img width="1280" alt="スクリーンショット 2020-06-02 0.40.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461309/daed61e9-1471-c39e-b8a4-9d83abef46bc.png">

1. 暫く待ちます(30分くらい)
    <img width="1280" alt="スクリーンショット 2020-06-02 0.41.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461309/7ebfbc48-91e7-3460-289c-60efae33b3f5.png">

1. deployが完了しました。`view`をクリックします。
    <img width="1280" alt="スクリーンショット 2020-06-02 0.33.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461309/e4538c63-87ae-34a4-e29a-661783dd0aef.png">

    <img width="1280" alt="スクリーンショット 2020-06-02 0.34.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461309/d743b622-6642-ec01-9cfa-97881c19b01b.png">

1. `Score Board`ページにアクセスすると色々あるので遊んでみましょう
<img width="1280" alt="スクリーンショット 2020-06-02 1.31.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461309/7cf496e5-0f91-252d-316c-8a4a56a873b2.png">

(`hogehoge-juice-shop`は削除しました)
VSCode操作メモ

検索
今開いているファイルを検索
command + f

行の操作
行の移動
option + ↑ または ↓
行の複製
option + shift + ↑ または ↓

マルチカーソル
クリックした場所にカーソルを追加
option + クリック
カーソルを下（または上）の行に追加
command + option + ↑ または ↓
【自己学習メモ】違いから見る Kubernetes @Kubernetes Meetup Tokyo #31

# なぜ比較？ 
別オーケストレータ（ECS）と比較することでk8sの理解を深めることを目的にする

スピーカー（アマゾンウェブサービスジャパン シニアコンテナスペシャリスト ソリューションアーキテクト Hara Tori氏）がECS→k8sで技術に触れたため、ECSに触れたことがあって、Kubernetesの始めたいという人向けのセッションだった

https://speakerdeck.com/toricls/see-kubernetes-through-an-amazon-ecs-lens

# ポイント
- NWレイヤ～データプレーンの思想差分
- ログに対する思想差分

## NWレイヤ～データプレーンの思想差分
### マトリクス整理
|オーケストレータ|L4|L7|データプレーン（コンテナ）|
|---|---|---|---|
|ECS|(ELB)|(ALB)|Task Definition
|Kubernetes|Service|Ingress|Deployment|
### セッション資料
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640480/691fc546-c8bb-5aac-4c3f-55334d94d6fd.png)
### 学び
application開発者がNWレイヤまで設定管理できるので、設計の意図を表現しやすい
→基盤チームと開発チームが別部隊となるような組織ではECSの方が向いていそう

## ログに対する思想差分
### セッション資料
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640480/8b0c7fe2-2ea7-398b-957f-e148f99c97b7.png)
### 所感
k8sはプライベートクラウド前提の技術（そもそもGoogleの基盤技術だから）であり、パブリッククラウドを利用したサーバレスコンテナを実現しようとすると制約が多そう
Goでよく使われるgormを理解する：目次

##はじめに
golangでアプリケーション開発を行なっている方だと、gormを使用されている方も多いのではないでしょうか。
自分もここ最近、golangを使ったWEBアプリケーションの開発を業務で行なっていますが、十分にgormの仕様を理解できておらず、実装で詰まってしまうことがあったので、この辺りで改めてgormのドキュメントと向き合い、Qiitaにまとめていければと思っています。

基本的には、[GORMドキュメント](https://gorm.io/ja_JP/docs/associations.html)に沿って挙動を確認していきますので、ドキュメントも合わせて見ていただけるとよいかと思います。ただし、個人的に確認不要と判断した箇所については割愛していますので、予めご了承ください。

##目次
**はじめに**
・[はじめに](https://qiita.com/tsubasaozawa/items/b8917c57a20ba6daa316)

**CRUD Interface**
・[Goでよく使われるgormを理解する：Query編](https://qiita.com/tsubasaozawa/items/19889340194cb6faa649)

**Associations**
・[Goでよく使われるgormを理解する：Associations編](https://qiita.com/tsubasaozawa/items/5cde0b9b5df87d2334d5)
・[Goでよく使われるgormを理解する：Preloading編](https://qiita.com/tsubasaozawa/items/ac5a8a515fe4f7a139b0)
[JavaScript] 正規表現の Firefox 限定問題の回避方法 (flags s)

# 概要

* JavaScript の正規表現で flags の一部にブラウザ依存があり、それの回避方法を説明します。

# Firefox で生じる問題

* 以下のコードは Google Chrome と Safari では動作しますが、Firefox では動作しません。

```JavaScript
const str = `aaa
bbb
ccc`

str.match(/.{11}/s)
```

* 正規表現の説明。
    1. 正規表現中の `.` は、ディフォルトでは「改行以外の任意の一文字」にマッチします。
    2. `/.{11}/` は「11文字の長さの文字列」にマッチします。
    3. `/.{11}/s` の最後の `s` は正規表現の flags で、「正規表現中の `.` を、改行文字にもマッチさせる」と云う指定です。
    4. `aaa ... ccc` は、アルファベット9文字と `aaa` と `bbb` の後ろの改行を含めて11文字あります。


# 原因

* flags の `s` は比較的新しい仕様で、Firefox (v76.0.1) が未対応のため。  
（2020/06/01 現在）

* Firefox の例外
    
```JavaScript
const str = `aaa
bbb
ccc`

str.match(/.{11}/s)
// SyntaxError: invalid regular expression flag s
```

# 回避策

1. ~~flags に `m` を指定する。（複数行指定）~~  
コメントでご指摘いただいた通り、不要でした。
2. `.` の代わりに `[^]` を使う。

```JavaScript
const str = `aaa
bbb
ccc`

str.match(/[^]{11}/)
```

* Q.E.D.

* `[^]` の意味が知りたい方は、最寄りの StewEucen までお尋ね下さいな。
フィボナッチ数列を表示するシェルプログラム

# はじめに
Bashプログラミングの小ネタとして作成しました。
第5弾です。

##フィボナッチ数列を表示
フィボナッチ数列とは何か、詳しくは[こちら](https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A3%E3%83%9C%E3%83%8A%E3%83%83%E3%83%81%E6%95%B0)をご確認ください。

簡単にいうと、2つ前の項と1つ前の項を足し合わせていくことでできる数列です。

###ソース
```bash
#!/bin/bash

m=0
n=1

echo -n "please input number => "
read num

if (( $num <= 1 || $num >= 2))
then
  echo $m
  echo $n
fi
(( num +=2 ))

for i in $(seq 1 $num)
do
  (( o = $m + $n ))
  echo $o
  m=$n
  n=$o
done
```
もっときれいに書けそうですね…

###実行結果
```bash
$ ./fibonacci.sh
please input number => 8
0
1
1
2
3
5
8
13
21
34
55
89
```

# おわりに
このプログラムを作成することで

- readコマンド
- 条件式
- 条件演算子
- 変数
- Bashのお作法

が理解できました。
九九を表示するシェルプログラム

# はじめに
Bashプログラミングの小ネタとして作成しました。
第4弾です。

## 九九の表を表示する

###ソース

```bash

#!/bin/bash

ans=0
spc=' '

for i in $(seq 1 9)
do
  for j in $(seq 1 9)
  do
    ((  ans = $i * $j ))
    printf "%2d" $ans
    echo -e "${spc}\c"
    if (( $j == 9 ))
      then
      echo #改行させる
    fi
  done
done
```
printfを使って、1桁のときも強制的に2桁になるようにしました。
数字が連続すると見づらいため、各値の間に空白を入れました。

### 実行結果
```
$ ./kuku.sh
 1  2  3  4  5  6  7  8  9
 2  4  6  8 10 12 14 16 18
 3  6  9 12 15 18 21 24 27
 4  8 12 16 20 24 28 32 36
 5 10 15 20 25 30 35 40 45
 6 12 18 24 30 36 42 48 54
 7 14 21 28 35 42 49 56 63
 8 16 24 32 40 48 56 64 72
 9 18 27 36 45 54 63 72 81
```

# おわりに
このプログラムを作成することで

- 繰り返し構文
- printfコマンド
- (( ))を使用した計算
- Bashのお作法

が理解出来ました。
VSCode Remote DevelopmentにおけるRemote側のエディタ設定について

# はじめに
VSCodeにはRemote Developmentと呼ばれる拡張機能があり，SSHで接続した先のファイルを手元のVSCodeで編集する便利機能があります．

リモート接続については過去の記事をご覧ください．
[VSCodeのRemote Developmentを使ってみる](https://qiita.com/HoriThe3rd/items/b2f6c440f096106cf89e)

本記事では，SSHで接続したリモート側のエディタ設定（settings.json）について述べます．メモ的な感じです・・・

結論としては，SSHリモート接続先のsettings.jsonが存在するので，そちらに設定を書かなければならない機能も存在するということです．

# 環境

- VSCode実行マシン：MacOS 10.15
- 接続先マシン：Ubuntu 18.04

# ことの始まり
フォーマッタをインストールしてC++のコードを自動的にきれいに整形してくれるようにしていました．

しかし，リモートで接続すると，これが効かないのです．そこで，settings.jsonを開いてみると，以下のようなメッセージが出ていました．

```txt
この設定は，このウィンドウでは適用できません．ローカル　ウィンドウを開いたときに適用されます．
```

<img width="594" alt="スクリーンショット 2020-06-01 17.49.01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/357417/f7c851ee-640e-ee7a-828d-e66009ced515.png">

つまり，リモート接続した先ではこの設定は効かない，と・・・

# 設定は別だった
リモートで接続して動作する拡張機能に関しては，リモート用の設定ファイルに記載しなければならなかったようです．
GUIで設定したい場合は，Code > 基本設定 > 設定，を開くと，”リモート”タブがあるのでこちらに設定します．

<img width="529" alt="スクリーンショット 2020-06-01 17.58.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/357417/c4ef9229-57eb-9d78-1fd7-a7adc3a1f542.png">

settings.jsonで設定ファイルで設定したい場合は，command + shift + pでコマンドパレットを開いて，settingsと入れると，"リモート設定を開く"があるので選択します．

 <img width="600" alt="スクリーンショット 2020-06-02 0.35.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/357417/478fc242-8b78-1fa3-6fb9-d85b0d2f3b52.png">

これで開いたリモート用の設定ファイルにSSH接続先のマシンで動作する拡張機能の設定を書けば良いようです．今回のフォーマッタの設定はこれでうまくいきました．

# おわりに
VSCodeの拡張機能では，

- ローカルにインストールすれば適用されるもの（カラー設定など）
- リモートにもインストールが必要なもの（C/C++など)

があります．リモートマシンの機能を使用するような拡張機能だとおそらく，リモート側の設定をする必要があるのかもしれません．
Ruby+LambdaでAWS SDKを使おうとしたら `sam local` がめちゃくちゃ遅くなったんだけど

# 起こった現象
LambdaをRuby実装で使っていました。AWS SAM CLIを利用して開発を行っていました。開発自体は何事もなくすすんでいたのですが、機能追加のためにAWS SDKを使うように変更したところ `sam local` がすごく遅くなったのでした。こんな簡単なサンプルアプリでここまで遅くなるのはおかしいでしょ…と調べてみました。

サンプルプロジェクトは[こちら](https://github.com/suruseas/lamba-gemfile-test)
※deployして試したあとはstack及びcloudwatchのロググループを忘れずに削除してください！

# さっさと結論だけ
Lambdaのランタイムには、各環境に合わせてAWS SDKがインストールされているのでLambdaのデプロイパッケージには含めなくてもよいです。

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-runtimes.html

特にRubyであれば **Gemfileへの「gem 'aws-sdk', '~> 3'」のような記載は不要** です！
普段利用するGemをGemfileに書く癖がついているとすごく気持ち悪いですが、グローバルなgemにインストールされたgemはそのままrequireできますので問題ないです。

# Gemfileに「gem 'aws-sdk', '~> 3'」を書いた場合(修正前)と、削除(修正後)して比較する

Gemfileに書くかどうかでpackageのサイズが大きく変わります（AWS SDKだけで23M近くある）ので、その差が大きくでる結果となりました。

ちなみに修正前だと `sam local` はかろうじて動きましたのでその比較だけ。デプロイ後はLambdaのメモリ及びタイムアウト時間をかなり伸ばさないとうまく動きませんでした。


### 修正前

`Init Duration: 54544.65 ms` とかなり時間がかかります。

```
$ sam local invoke HelloWorldFunction --event events/event.json --env-vars env.json
Invoking app.lambda_handler (ruby2.5)

Fetching lambci/lambda:ruby2.5 Docker container image......
Mounting /home/ubuntu/environment/test/.aws-sam/build/HelloWorldFunction as /var/task:ro,delegated inside runtime container
START RequestId: 22ddc38d-745a-1d37-0ce9-324760f75ec4 Version: $LATEST
END RequestId: 22ddc38d-745a-1d37-0ce9-324760f75ec4
REPORT RequestId: 22ddc38d-745a-1d37-0ce9-324760f75ec4  Init Duration: 54544.65 ms      Duration: 801.49 ms     Billed Duration: 900 ms Memory Size: 128 MBMax Memory Used: 60 MB

{"statusCode":200,"body":"{\"message\":\"t2.micro\"}"}
```

### 修正後

`Init Duration: 2266.99 ms` と改善！

```
$ sam local invoke HelloWorldFunction --event events/event.json --env-vars env.json
Invoking app.lambda_handler (ruby2.5)

Fetching lambci/lambda:ruby2.5 Docker container image......
Mounting /home/ubuntu/environment/test/.aws-sam/build/HelloWorldFunction as /var/task:ro,delegated inside runtime container
START RequestId: a81dffd9-915d-13db-3ed7-4fe0e3b63464 Version: $LATEST
END RequestId: a81dffd9-915d-13db-3ed7-4fe0e3b63464
REPORT RequestId: a81dffd9-915d-13db-3ed7-4fe0e3b63464  Init Duration: 2266.99 ms       Duration: 557.91 ms     Billed Duration: 600 ms Memory Size: 128 MBMax Memory Used: 58 MB

{"statusCode":200,"body":"{\"message\":\"t2.micro\"}"}
```


### 最後に

Lambdaを使うならサイズやパフォーマンスには注意を払わないと余計な費用が掛かってしまいますね。処理時間もパッケージサイズも軽く。Lambdaの分割や、AWS Lambda Layersなども使って対応していきたいと思います。
ITパスポート（本に載ってない）

職務分掌　
組織においてそれぞれの職務が果たすべき責任や職責を果たす上で必要な権限を明確にするために、職務ごとの役割を整理すること

ネットワーク組織
企業間、部門間を超えて対等な関係を構築する組織

タスクフォース
特定の課題を達成するために設置される組織のこと

アウトソージング
外注のことです。下請け企業にシステムの製造やテストを任せること


サブネットマスク
IPアドレスのうちネットワークアドレスとホストアドレスを識別するための数値

avi　動画
mp3　音声
jpg　png　静止画
txt　doc　文章

情報リテラシ
ITを活用して必要な情報を利用すること、利用に際してのセキュリティルールなどを理解することを指す
C# HEAD HTTPリクエストを送信する

# まえがき

URLからデータをダウンロードするとき、サーバーの負荷等を考えてデータが新しい場合だけダウンロードしたいことがあります。HTTPプロトコルではHEADメソッドのリクエストに対するレスポンスヘッダーが日付やETagといった情報を持ち、これらを利用して前述の目的を達成できます。

これらの情報はGETメソッドのリクエストに対するレスポンスヘッダーにも含まれますが、GETメソッドはデータそのものを取得するのでサーバーの負荷等は軽減できません。

# C#における実装

C#では`System.Net.Http`名前空間の`HttpClient`クラスを使用してURLにHEADメソッドのリクエストを送信できます。以下にサンプルコードを示します。

```cs
using System;
using System.Net.Http;

namespace ConsoleApp1
{
    class Program
    {
        // HttpClientのインスタンスは再利用すべきです。
        // https://docs.microsoft.com/ja-jp/dotnet/api/system.net.http.httpclient?view=netcore-3.1#remarks
        private static readonly HttpClient httpClient = new HttpClient();

        static void Main()
        {
            // HTTPリクエストを送信するURL
            // ここではQiitaのURLをお借りしています。
            var url = "https://qiita.com/";
            // URLに対するHTTP HEADリクエストメッセージを作成して送信
            // ここではResultを呼び出して同期処理にしています。
            var headMessage = new HttpRequestMessage(HttpMethod.Head, url);
            var response = httpClient.SendAsync(headMessage).Result;
            // ETagを出力する
            // nullの可能性があります。
            var headers = response.Headers;
            Console.WriteLine($"ETag:{headers.ETag?.Tag}");
        }
    }
}

```

# 参考

HTTPヘッダーやETagについてはMDNを参照ください。

- [HTTP ヘッダー - HTTP | MDN](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers)
- [ETag - HTTP | MDN](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/ETag)
WebAppsでのサーバログ取得方法

#WebAppsでのサーバログ

W3C拡張ログをファイル形式で出力できる。
ソースIPとかリファラとかあれこれのHTTPリクエストログ
設定は以下の通り。WebAppsのストレージへログ吐き出しする設定。
#### App Serviceログの有効化
Webサーバーログをストレージ or ファイルシステムを選択して保存する。
※今回はファイルシステムを選択。ストレージも試したら更新します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158138/0e755ce3-0c59-62f2-6699-fefd9be94745.png)

#### ログの確認
高度なツールからkuduを開き、Debug ConsoleからCMDを選ぶ。
LogFiles配下にhttpディレクトリが新たに作成されている。
http →　RawLogsディレクトリ配下にログファイルが作成されている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158138/0b2e2421-31c8-e6a8-9476-308b026f0262.png)
スペース区切りで出力されるので、あとは煮るなり焼くなりすればよい。
※s-ip、s-computername、cs-versionはサポートされておらず出力されないので注意

参考
https://docs.microsoft.com/ja-jp/azure/app-service/troubleshoot-diagnostic-logs