OmniAICreator/Qiita-1.07M huggingface dataset:
スクリプト内で別スクリプトの関数を実行する

オブジェクトAからオブジェクトBの値を持ってくるとか、実行する的なことができる。
Hierarchyで  
"Create Empty"してオブジェクト名をGameObjectからAdminに変える（名前は何でもよい）  
次に2D Object → "sprite"でNew Spriteを追加し、Assetsに画像を追加して  
New Spriteに対応付けする。  
![admin_init.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149593/70ae5f0b-fa53-b78d-d89e-4fe244b2efe4.png)

AdminとNew Spriteにそれぞれ別のスクリプトをAdd Componentする。  
![admin_scriptadd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149593/2067bb50-a065-a765-432f-950d67102222.png)

New Spreteのスクリプトを以下のようにアタッチ  

```C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpriteScript : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        
    }
    // Update is called once per frame
    void Update()
    {
        
    }
    // public付けないとダメ
    public void PrintSpriteName()
    {
        print(this.gameObject.name);
    }
}
```

Adminのスクリプトを以下のようにアタッチ  

```C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AdminScript : MonoBehaviour
{
    // public付けないとダメ
    public GameObject sprite_object;
    // Start is called before the first frame update
    void Start()
    {
        //sprinte_object<>
    }
    // Update is called once per frame
    void Update()
    {
        //test[0].GetComponent<CurrentSelected>().aaa();
        sprite_object.GetComponent<SpriteScript>().PrintSpriteName();
    }
}
```

すると、AdminのInspectorのAdminScriptコンポーネントにスクリプト内で宣言した  
Sprite_object  
が追加されるので、の⦿マークを押してNew Spriteを入れる（もしくはドラッグ&ドロップ）。  
![admin_checkbox.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149593/38ff2c59-5a4a-c25e-f624-d80894ccadf4.png)

これで実行すれば、Adminスクリプト内でNewSpriteスクリプト内の関数を呼び出せる。  
![admin_result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149593/1313a68a-74f3-134a-8494-2c39538fc029.png)

値渡したい場合はset、getのプロパティ関数作ってやればよい。
studioXについて


StudioからStudioXへの切り替え
---------------------------------------
①<b>設定</b>を選択
②<b>ライセンスとプロファイル</b>を選択
③<b>プロファイルを確認または変更</b>を選択するとプロファイル選択画面が表示されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482005/2429220c-05cd-fef0-804b-802affcabda8.png)

④プロファイル選択画面で<b><font color="Blue">StudioXのプレビュー版</font></b>を選択します
※この後再起動確認画面が出るのではいを押して再起動してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482005/fafad116-e9f1-4647-32f3-984e8173e116.png)

設定を変更することでいつでもStudioとStudioXの切り替えができます！

新規タスクの作成
---------------------------------------

①新規プロジェクト下の<b>タスクオートメーション</b>を選択
②新しいタスクオートメーションの入力画面が表示されるので
　・<b><font color="Blue">プロセス名</font></b>:路線検索とか自動化する内容
　・場所：基本そのまま！他の場所に変えたいって時だけ変更
　・説明：タスクの説明を記載(書かなくても問題なし)
③入力完了したら作成ボタンを押します。
これでタスクが作成されました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482005/295b5b9e-6788-a9a8-bba5-b996f8800e04.png)
<b><font color="DarkOrange">※ここで詳細オプションにチェックいれるとExcelファイルの設定ができます</font></b>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482005/fff551a1-f617-97ff-f5d5-39d747e5912e.png)


各パネル名称
---------------------------------------
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482005/e5214ab1-b561-5a67-4e9d-898e475e81b7.png)

<b>リボン</b>：画像の緑の枠
<b>アクティビティパネル</b>：画像の赤枠、
<b>デザインパネル</b>：画像の青枠

アクティビティパネル
---------------------------------------
画面左側にある色んな種類のカードやアクションが置いてある場所です。

分類ごとに認識し易いようにカラー分けされている
・Excelなら緑・outlookなら青
・クリックなどの自動化はオレンジ　など
<b><font color="blue">※デザインパネルに設置した際はアクティビティの左端が対応したカラーになります</font></b>
カラー分けされてるので見やすくて非常に良いと思います！！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482005/4a8bba68-4055-a9df-ab06-2321135028eb.png)
ここからデザインパネルに使用したいアクションなどをドロップして使っていきます。

アプリケーションカード
---------------------------------------
アプリケーションカードには、自動化されるアプリケーションのスコープ
　※スコープって何？？
　　領域・範囲のことだよー！
　　「おまえの名前が通じるのは、ここまでだ！」な影響範囲
ExcelやOutlookや自動化のところにあるアプリケーションカードがある。
Studioの方であったExcelApplicationScopeのようにカード内にアクションを設置してあげて使っていきます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482005/07a5ebe8-00b6-b185-d2da-c3da1e385ac4.png)


StudioX導入時の注意など
---------------------------------------

●システム要件
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482005/31abbff5-c1b3-e868-c8fb-bd91de7c11d0.png)
●<font color="Red"><b>Office 2013、2016、2019、または Office 365</font> のいずれかのバージョンが必要です
●<font color="Red"><b>ディスプレイの解像度ですが1024x768 未満の解像度はサポートされていません。</font></b>
満たしていない状態でStudioX を実行すると、StudioX バックステージ ビューが正しく表示されないので注意！


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

ここの内容は随時更新していきます。
Svelte3 クリップボードにコピーするボタンを作る


Svelte3でクリップボードにコピーするボタンを作りたい時の実装方法デス。

こちらで動作を検証できます
https://svelte.dev/repl/3194502389af4e22991f8bb0c61d65cf?version=3.16.5


## コピーボタンの表示コンポーネント
```html
<script>
	import CopyClipBoard from './CopyClipBoard.svelte';
	
	let name = 'world';

	const copy = () => {
		const app = new CopyClipBoard({
			target: document.getElementById('clipboard'),
			props: { name },
		});
		app.$destroy();
	}
</script>

<input bind:value={name}>
<button on:click={copy}>copy</button>

<!-- クリップボードにコピーするためのテキストエリアを一時配置するための領域 -->
<div id="clipboard"></div>
```

コピーボタンを押した時に`CopyClipBoard`コンポーネントの作成、削除を行うだけです。
実際のコピー処理は`CopyClipBoard.svelte`に実装します。

## クリップボードにコピーするためのコンポーネント
```html
<script>
	import { onMount } from 'svelte';
	
	export let name;

	let textarea;
	
	onMount(() => {
		textarea.select();
		document.execCommand('copy');
	});
</script>

<textarea bind:value={name} bind:this={textarea}></textarea>
```

textareaの全選択(`select()`)を行いたいので`bind:this`でtextareaのDOMノードを取得しておきます。
あとは`onMount()`で`document.execCommand('copy')`を実行してコピーを行うだけになります。
32bit環境でsprintfやったらハマった件

４年くらい前の話なので今どき起きないだろうな～とは思いつつも備忘のために。

ちなみに古いPerlプログラム（2001年頃の奴がマジでヤバい）を他の言語で作り直したいという話はちょいちょい来る。

32bitのWindows2003で起きて、64bitのWindows2008では起きなかったので、内部で `int` に変換してんのかな～、とか思ったり。

```perl
my $id = '2234567890';
my $idstr = sprintf('%10d', $id);
# => '2234567890' ではなく負の値になる
```

`sprintf()` がどういう仕組みなのかは知らない。
解決方法はこんな感じ。正直なところ、 `sprintf` のところを触らずになんとかできたら一番よかった。

```perl
my $idstr = substr('0000000000' . $id, -10);
```

開発当初はIDが少なかったから起きなかったんだろうね……
Raspberry Pi 4でディスプレイを繋がずにVNCする

# 概要

デフォルトでは、ラズパイのHDMI端子にディスプレイが繋がっていないと、VNC Viewerで接続しても画面が見えない。

ディスプレイが繋がっていなくても、VNCで画面が見えるように設定する。

# 前提

Raspberry PiのOSセットアップは完了しており、SSH接続ができること。

# 設定

## VNCの有効化

1. SSH接続し、「sudo raspi-config」を実行する。
2. 「5 Interfacing Options」を選択する。
3. 「P3 VNC」を有効にする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253760/ccbe0cda-b56b-7b5d-5ea8-7f53fa4518fc.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253760/43b9ba5c-7f66-644b-b703-1ea0db4f60b7.png)

## HDMI

1. 「/boot/config.txt」ファイルを開く。
```
sudo vi /boot/config.txt
```
2. 「hdmi_force_hotplug=1」がコメントアウトされているため、有効にして保存する（行頭の「#」を削除する）。
3. Raspberry Piを再起動する。


これで、Raspberry Pi起動時にディスプレイが接続されていなくても、VNC接続して画面を確認できるようになる。
RecyclerViewとMarkerを対応させる(Kotlin)

### 作りたいもの
RecyclerViewをスクロールするとそのアイテムに対応するGoogle MapのMarkerに移動し、またMap上でMarkerをタップするとRecyclerViewがアイテムまでスクロールしてくれるやつ。
![ezgif.com-optimize.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/459816/9638d0bd-f0cd-d213-4e1f-d54fade6d4e1.gif)
CardViewとSnaphelperも使用していますがその説明は割愛します。

### 環境
Android Studio
Kotlin
Maps SDK for Android

### 方法
#### RecyclerView -> Marker
スクロール量でRecyclerView上の順番を判定し、そのアイテムの位置までMapを移動。

```kotlin
//recycler -> marker
recyclerView.addOnScrollListener(object :RecyclerView.OnScrollListener(){//スクロールでマーカーに移動
    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {//スクロールした量でposition判定
        super.onScrolled(recyclerView, dx, dy)
        val offset = recyclerView.computeHorizontalScrollOffset()
        val itemWidth = cafeCardRoot.width
        val edgeMargin = (recyclerView.width - itemWidth)/2
        val position = (offset + edgeMargin) / (itemWidth + edgeMargin/2)

        if (myCafesData[position].latitude == "" || myCafesData[position].longitude == "") {
            return
        }else{
            val moveLatLng = LatLng(myCafesData[position].latitude.toDouble(),myCafesData[position].longitude.toDouble())
            mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(moveLatLng, 16F))
        }
    }
})
```

#### Marker -> RecyclerView
マーカーの順番を判定してそのアイテムまでスクロール。

```kotlin
//marker -> recycler
mMap.setOnMarkerClickListener(object : GoogleMap.OnMarkerClickListener{
    override fun onMarkerClick(marker: Marker?): Boolean {
        val markerPosition = marker?.position
        var selectedMarker = -1
        for (i in 0..myCafesData.size-1) {
            if (myCafesData[i].latitude == "" || myCafesData[i].longitude == "") {
                continue
            } else {
                if (markerPosition?.latitude == myCafesData[i].latitude.toDouble() && markerPosition.longitude == myCafesData[i].longitude.toDouble()) {
                    selectedMarker = i//Markerのposition判定
                }
            }
        }
        recyclerView.smoothScrollToPosition(selectedMarker)//scroll
        return false
    }
})
```

### 課題
RecyclerViewとMarkerが直接連結してる訳ではないので、Recycler->Markerでマーカーのサイズ変えたりすることができない。
アイテムのデータにRecyclerViewとMarkerの情報を持たせるのですかね？

上記の課題の解決方法をご教授いただければ幸いです。お願いいたします！

### あとがき
この記事は私のブログからの転載です。
プログラミングの記事等更新していますので是非訪れてみてください。
https://www.imagawahibana.com/
WSLの個人的初期設定

WSLを作ってはぶっ壊してばっかりなので初期設定をメモっておきます。


```bash
sudo sed -i -e 's%http://.*.ubuntu.com%http://ftp.jaist.ac.jp/pub/Linux%g' /etc/apt/sources.list
sudo apt update
sudo apt -y upgrade
sudo apt -y install language-pack-ja
sudo update-locale LANG=ja_JP.UTF8
sudo apt -y install manpages-ja manpages-ja-dev
```
ドメインイベントをsplunk>で可視化する

こちらは [ドメイン駆動設計#1 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/ddd-1) の23日目の記事です。

こんばんは、現在は業務で [splunk>](https://www.splunk.com/) の運用に携わっている crossroad0201 です。
この記事では splunk> を ドメイン駆動設計（以下、DDD） の文脈でなにか活用できないか？と考えていたアイデアをご紹介したいと思います。

アイデアをご紹介、と言ってもまったくもって大した内容ではないのですが...（笑）

# splunk> とは

みなさん、 **splunk>** をご存知でしょうか。

一言で言ってしまうと [Elasticsearch](https://www.elastic.co/products/elasticsearch) のようなものですが、大量のデータを蓄積し、独自のクエリ言語を使ってフィルタや各種集計、グラフ化などのデータ分析ができるプロダクトです。

ピンクがコーポレートカラーらしく、Webサイトや公開されているスライドなど、あっちこっちがピンクです（笑）

<img width="1042" alt="スクリーンショット 2019-12-22 22.51.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94618/cc235269-001d-550f-65ed-00753d2d2060.png">

SPL(Search Processing Language)と呼ばれるクエリ言語が使えたり、さまざまなデータソースからデータを取り込む仕組みを持っていたり、データ構造を自動解析してインデックス化したり、大規模なクラスタを構築・運用する仕組みが用意されていたり...と言った特徴があります。
さまざまなOS、ミドルウェア、アプリケーションのログを一元化して可視化したりするのに使われることが多いようです。

僕自身、業務で扱うまでは実はまったく知らなかったのですが、国内外の大手企業などにも多く導入されており、米国での大規模イベント [.conf](https://conf.splunk.com/) や、国内の [GOJAS(Go Japan Splunk User Group)](https://twitter.com/gojas_jp) などのコミュニティ活動も活発なようです。

splunk> がどのようなものかは、 [こちらのデモ](https://www.splunk.com/en_us/resources/videos/splunk-web-demo.html) を見るとイメージできると思います。

# DDDで splunk> を

さて、そんな splunk> ですが、DDD Loveな自分としてはなんとかDDDと関連付けて使えないものか...と言うことで、 **ドメインイベントを splunk> につっこんで見える化する** と面白いのではないか？と思っています。

「できたらえーなー」と思っているだけで実践はしていませんのでそこはご了承を...（笑）

## ドメインイベント

**「ドメインイベント」** については、 ヴァーノンの [実践ドメイン駆動設計](https://www.amazon.co.jp/dp/B00UX9VJGW) で解説されているのでご存知の方が多いかと思いますが、ドメイン内で発生する事象をモデル化したものです。

例えば...

* 新規会員が入会した
* 注文を受け付けた
* 商品を出荷した

のような、ドメインの文脈の中で過去形で表現される知識がドメインイベントの候補になります。

## マイクロサービスとドメインイベント

マイクロサービスアーキテクチャを採用する場合にも、ドメインイベントは非常に重要になります。

書籍[マイクロサービスアーキテクチャ](https://www.amazon.co.jp/dp/4873117607) などでも述べられているように、マイクロサービス間の連携には **1.リクエスト-レスポンス型** と **2.イベント型** があり、マイクロサービス間を疎結合にして独立性を高めるには、 2.イベント型 による連携が望ましい選択肢になります。（ [こちらの記事](https://qiita.com/crossroad0201/items/23864b3b177fb1fce966#サービス間の連携方法) もご参考に）

DDDを採用する場合は、マイクロサービス間でやり取りするイベントとして、ドメインイベントが使えます。

ここで悩ましいのは、マイクロサービスをまたいでやり取りされるイベントを一元的に見るのが難しい点です。

## ドメインイベントの見える化

ここで **splunk>** の登場です。（まぁ Elasticsearch でも良いんですが...）

各マイクロサービスから発生するイベントを splunk> に蓄積していけば、クエリ言語SPLを使って 「注文番号XXXXXの注文が、いつ誰によってどのように処理されたのか」 と言ったようなことを簡単に見ることができます。

また、あるイベントの発生する曜日や時間帯を調べることでユーザーの行動傾向を分析したり、先行-後続関係にあるイベント間のタイムラグを見ることで業務のボトルネックを特定することもできるかもしれません。

splunk> のクエリ言語は（もちろん学習は必要ですが）アナリストのようなエンジニアではない人でも扱えるので、ビジネスをカイゼンさせていくためのフィードバックを誰でも得ることができるのではないかと思います。

## アーキテクチャ

実現のアーキテクチャですがいたってカンタン（なはず）です。

例えばAWSを利用していて、マイクロサービス間のイベントを送受信するために **Kinesis Streams** を使っているなら、そのストリームをサブスクライブして splunk> にデータ投入する **Lambda Function** を作るだけです。
Lambada function から splunk> へのデータ投入には [HEC(HTTP Event Collector)](https://dev.splunk.com/enterprise/docs/dataapps/httpeventcollector/) と呼ばれるHTTPでデータ投入する仕組みがあるので、これを利用すれば良さそうです。

また、 splunk> には [Kafkaからデータを取り込むアドオンがある](https://www.splunk.com/en_us/blog/tips-and-tricks/splunk-connect-for-kafka-connecting-apache-kafka-with-splunk.html) ので、イベント伝播に Kafka を使っている場合はそれが使えるかもしれません。

# おわりに

と言うわけで、かんたんな記事で恐縮ですが、DDD界隈でもこのあたりはあまり話題に上がらないと思うので、何かのヒントになれば幸いです。
Flutterでデバイスにファイルを保存する

アプリのサイズを減らすために画像ファイルをアセットに追加しないで、初回起動時などのタイミングで端末に保存し、表示する方法について書きます。

今回使用するプラグインはhttpのみです
ちなみに`cached_network_image `などのプラグインを使用したファイルキャッシュでも同等の動きをすると思いますが、１００枚ほどのキャッシュした画像をPageViewで表示してページめくりしているとアプリがクラッシュしてしまいます。（体験済み）
たしかFlutterのIssuerにも上がっていた気がします。

###ファイルのダウンロード
画像ファイルの保存は下記のコードになります。
httpで画像ファイルを取得し、ローカルのファイルに書き込むという流れになっています。
ローカルにファイルがない場合は書き込めないので、書き込む用のファイルを先に生成してください。
下記のコードでは`await file.create();`がファイル生成の処理をしています。

```dart
final http.Response res = await _httpClient.get(fileUrl);
final file = File('$filePath');
await file.create();
await file.writeAsBytes(res.bodyBytes);
```

###ダウンロードしたファイルを表示する
ダウンロードしたファイルを表示するには [Image.file](https://api.flutter.dev/flutter/widgets/Image/Image.file.html) を使用します。


```dart
final file = File('$filePath');
return Image.file(
  file,
  width: 100,
  height: 100,
);
```

とくに難しいことはなく単にファイルを保存して呼び出し表示するだけです。
Androidではパーミッション`READ_EXTERNAL_STORAGE `を許可が必要になる場合があるので許可しておいてください
Vuexの状態定義を抽出してやる！

## なぜ？

SPAで開発してると状態管理が大変になり、参照したい状態がどこにあるか探すのが大変。
そこで、状態のみを抽出して構造化したら全体像を把握できて探すのが楽になるのでは？
と思いやってみます。

## どうやって？

AST(Abstract Structure Tree)を使って、静的構文解析をして状態を抽出します。
とりあえず、モジュールは考えないでやってみる。

### 環境
- Node.js(v10.15.3)
- babylon(6.18.0)
- @babel/traverse(7.4.3)

### 想定するファイルと構成
```js:store/index.js
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

const store = new Vuex.Store({
  state: {
    account: {}
  },
  getters: {},
  mutations: {},
  actions: {}
});
```

### 期待する出力
```js:state.json
{
  'root': {
    'account': {}
  }
}
```

### 状態を抽出するコード
```js:extract-state.js
const fs = require('fs')
const babylon = require('babylon')
const traverse = require('@babel/traverse').default

const IsParentState = Symbol('IsParentState')
const ast = babylon.parse(fs.readFileSync('./store/index.js', 'utf8'), {sourceType: 'module'})
const state = {
  'root': {}
}

const visitor = {
  ObjectExpression: {
    enter(nodePath) {
      // 親ノードがオブジェクトのプロパティかつ、キーがstate
      if (nodePath.parent.type === 'ObjectProperty' && nodePath.parent.key.name === 'state') {
        nodePath[IsParentState] = true
      }
    },

    exit(nodePath) {
      // state(Vuex)キーのvalueを評価して、出力用のstate.rootのvalueとする
      if (nodePath[IsParentState]) {
        const { value } = nodePath.evaluate()
        Object.assign(state.root, value)
      }
    }
  }
}

traverse(ast, visitor)
console.log(state)
```
### 実行
```
node extract-state.js
```
### 結果
```
{ root: { account: {} } }
```

```js:store/index.js
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

const store = new Vuex.Store({
  state: {
    account: {},
    isSignIn: false
  },
  getters: {},
  mutations: {},
  actions: {}
});
```
で実行すると、

```
{ root: { account: {}, isSignIn: false } }
```
となる。

## 今後の課題
- stateがショートハンドで初期化されてる場合、抽出できない
- stateキーがあるオブジェクトすべてを対象としてしまってるので正しく抽出できない場合がある
- モジュールの状態が抽出できてない

モジュールの状態が抽出できないと目的達成できないですが、時間切れなので
また別の機会に解決したいと思います。
Docker+GitHub+HerokuでCI/CDっぽく

#やった事
前に記事で公開した[Qiitaタグ自動ジェネレータ](https://qiita.com/fukumasa/items/7f6f69d4f6336aff3d90)をWebアプリとして手軽に試せる様に公開しました。
ついでにGitHubで[ソース](https://github.com/fukumasa/auto-create-qiita-tags)も晒しています。

https://auto-create-qiita-tags.herokuapp.com/

※Freeプランなので３０分間アクセスがないと休眠してしまいます。少し時間がかかる時があるのはご愛嬌という事で...


#全体図
Webアプリを公開するにあたり**Heroku**を使いました。GitHubとも連携させたのでこんな感じです。
GitHubにソースをpushすると自動的にHerokuでビルドが走りDockerコンテナのデプロイまでやってくれます。仕事での開発だと今時CI/CDなんて当たり前だと思いますが、個人でお金をかけずに環境作ってみたという感じです。

![qiita投稿用.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206972/66225e47-f8e6-69ae-349a-8578853767d6.png)


#Herokuって？
*アプリケーションの開発から実行、運用までのすべてをクラウドで完結できるPaaS*です。（[公式サイト](https://jp.heroku.com/)より）
結構前からあるサービスで知名度も高く知っている人も多いと思います。
以下を魅力に感じ今回使いました。

- **無料でWebアプリを公開**することが出来る　※稼働時間など一部制約あり
- **GitHub連携**できる
- **Docker**対応している（[Heroku dyno](https://jp.heroku.com/dynos)）


#GitHub連携するには？
Herokuの画面から設定するだけ、すごく簡単。`Automatic deploys`を有効にするだけで、GitHubにpushされたらHerokuにアプリをデプロイするところまでやってくれます。
![スクリーンショット 2019-12-21 18.10.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206972/9346411d-87f1-1c82-40bb-a536b621b340.png)


#Dockerビルドするには？
連携したGitHubにDockerfileはもちろんですが、`heroku.yml`という設定ファイルが必要になります。
今回用意したheroku.ymlはこちら。

```heroku.yml
build:
  docker:
    web: Dockerfile
```

色々出来るらしいですが、単純にDockerfileからビルドするだけなのでシンプルな内容となってます。
詳細な書き方は[公式ドキュメント](https://devcenter.heroku.com/articles/build-docker-images-heroku-yml)を見てみてください。

ちなみにDokerfileはこちら。
PythonのWebアプリケーションフレームワークである`flask`を使いました。

```Dockerfile
FROM python:3-alpine

WORKDIR /work
RUN wget http://gensen.dl.itc.u-tokyo.ac.jp/soft/pytermextract-0_01.zip
RUN unzip pytermextract-0_01.zip
RUN cd pytermextract-0_01 && python setup.py install

RUN apk update
RUN apk --no-cache add git gcc libc-dev libxml2-dev libxslt-dev

RUN git clone https://github.com/fukumasa/auto-create-qiita-tags

WORKDIR /work/auto-create-qiita-tags
RUN pip install -r requirements.txt

ENV FLASK_APP /work/auto-create-qiita-tags/app.py
CMD flask run -h 0.0.0.0 -p $PORT
```

Herokuでは起動時のポートがPORTという環境変数に格納されているため、flaskアプリケーション起動時に`$PORT`でポート指定しています。
これでコンテナがビルドされると`CMD`の内容が実行されます。

起動したDockerアプリには80ポートでアクセスするため、おそらくですが、コンテナ内部の`$PORT`ポートとコンテナが稼働しているサーバの80ポートが自動的にフォワーディングされていると思われます。
Dockerコンテナを`docker run`で実行する際は、通常`-p 80:5000`のようにポートフォワーディングを明示的に行う事が多いと思いますが、Herokuではこの辺りはあまり意識しなくても良さそうです。


#まとめ
Herokuを使ってDockerアプリを公開してみました。
GitHubを使えば、既存のソース＋heroku.ymlで手軽に連携することが出来ます。
そもそもHerokuの使い方とかより詳細なコマンドとかは以下の参考ページを見てみてください。


#参考ページ
- [先週 GA になった、heroku.yml を使った Docker Deploy を試した](https://masutaka.net/chalow/2018-11-21-1.html)
- [Qiita : heroku.ymlからDockerビルドが可能になった](https://qiita.com/nkumag/items/7d026c73a89c9907065a)
- [Qiita : FlaskアプリケーションをHeroku上のDockerで起動](https://qiita.com/nanakenashi/items/d3572989d76a651262b5)
【TypeScript】Genericに対して as const のようなことをする方法

次のようなクラスがあったとします:

``` typescript
class X<T> {
	val: T;

	constructor(val: T) {
		this.val = val;
	}
}
```

このクラスを使ったコードを見てください:

``` typescript
const makeX = <T>(val: T): X<T> => new X(val);

const x = makeX('foo').val;
```

ここで、`x`の型は`string`です。
場合によっては、これを`string`ではなく値そのものの型、`'foo'`にしたいときもあるかと思います。
TypeScriptでは`as const`を使うと、値そのものの型を表現することができます。ただジェネリックに対しては`as const`を使えません。
どうするかというと、`<T extends keyof any>`のように書きます:

``` typescript
const makeX = <T extends keyof any>(val: T): X<T> => new X(val);

const x = makeX('foo').val;
```

こうすると、`x`の型は`'foo'`になります。めでたし

---

もっと良い方法があるよ！という方はお知らせください :pray:
ぼく（令和エンジニア）の144日間奮闘記

この記事は[エイチーム引越し侍 / エイチームコネクト Advent Calendar 2019](https://qiita.com/advent-calendar/2019/hikkoshi) 23日目の記事です。アドベンドカレンダーも終盤・・・今年も残り少しでございます。2回目の登場@halktです。

## はじめに
エンジニアになりはや4ヶ月。今までと比べて学ぶことが非常に多く、苦労もありましたがとても充実した1年でした！エンジニアとして知らなかった技術にもたくさん触れてできることも大きく増えましたが、今回は仕事を進める上での考え方とか、自分にとって影響の大きかった事柄を振り返ってまとめてみることにしました〜！

## ペアプログラミングを駆使してスキルを吸収！
開発しはじめて間もない頃、**「一人で悩む時間が非常に多い」**という問題を抱えていました。実装方法（技術的な要素）調査にかかる時もあれば、業務や仕様の理解不足でわからないこともありました。

これを先輩に相談したところ、**ペアプログラミングの提案**を受け、二人一組でコーディングを行いました。おかげで、どのようにデバッグしているのか、どういうアプローチで対象ファイルを特定していくのか、コードリーディングにどのぐらい時間を割いているのか、どんなツールを使っているのかなど、決して一人だけでは得られない様々な情報を得られることができました。

私の所属するチームでは、仕様や業務知識に詳しい人、フロントに強い人、テストコードが得意な人など、強みを持っている方がたくさんいるので毎日学ばせてもらっています。積極的に活用して先輩エンジニアのスキルを知識を吸収していきたいと思います！

## 調査と質問をバランス良く行おう！
先ほどの話ともつながりますが、どこまでを自分で調べて、どこから質問するのか？という境界線がわからず苦労していました。

結論からいうと「**15分間調べてわからなければ聞く**」というルールを自分に課すことでことで解決をしました。これは、Googleの機械学習チームが実際に使っていたルールで、15分以上調査せずに質問に行くことはチームの時間を無駄にし、15分以上の調査は個人の時間を無駄にする、というデータに基づいたルールです。
http://tkybpp.hatenablog.com/entry/2016/08/16/173055

悩みすぎて時間を浪費することも良くありませんが、かといってろくに調査をせずにすぐに人に聞いてしまうと、他の人の時間を奪ってしまいます。上記のルールを徹底してから、以前に比べて自分で調べて解決できることも増え、質問して期待する回答が返ってくる頻度も高めることができました。

### おまけ（ライブラリやプラグインの調べ方）
あまり使っていなかったので、最初は人に聞いてしまっていましたが、対象のライブラリ名などまでわかっている場合は、まずは**公式ドキュメント**、もしくは**実際に使った人の記事など**を読んでみることにしています。

問題解決するだけであれば後者の方が答えが早いこともありますが、なるべく一次情報である公式ドキュメントには目を通すようにしています。記載している内容が確実ですし、体系的になっているので知識としてはこちらをなるべく読むようにしています。

## 自動テストを書いて未来の不具合を防げ！
ある日、とあるWebサービスの改修にて大きな不具合を起こしてしまいました。利用者に迷惑をかけたことは勿論、事業としても実際に損失を出してしまいました。前職でも不具合を出すことは何度かありましたが、今回のようにWebサービスの機会損失とその金額を初めて算出したことで事の重大さを痛感しました。。。

この問題の直接的な原因は、私個人のテストパターンの洗い出しが甘かったためです。ただ、この不具合の再発防止を考えたときに、テストコードを書くことができていれば、今回の不具合が防げたことは勿論、**その後同じミスが起きることを防ぐことができる**ことに気がつきました。

実際振り返ってみると、今までの開発で過去のテストコードのおかげで助けられたりしてきました。テストコードを書く意義をしっかりと胸に刻み、のちに開発をする人たち（自分も含めて）にとって価値のあるテストを書くことを徹底していきたいです！！


## 課題を明確にし、最適な提案をできるエンジニアを目指せ！
最近あった実際の業務の話ですが、業者の方が利用する機能にて利用者からの予約などを通知するために、特定の条件でポップアップ（モーダルウィンドウ）を開く、というチケットを対応しました。私は、チケットを消化することに気がいってしまい、言われるがまま実装しようとしてしまいました。

ただ、先輩から**「本当にここでポップアップを表示する必要があるの？」**と指摘を受けて何も答えることができませんでした。その後何度かヒアリングをした結果、ポップアップを表示したいのは別の目的だったため、表示する場所を変更し、デザインを微修正して対応することに落ち着きました。

こうなってしまった原因は、無意識的に自分が作業者となっていたことにあります。実装する機能に注力してしまい**本当に解決したい課題が何なのか**をわかっていなかったからです。

チケットに書かれていた実装内容に捉われず、「真の課題が何か？」をわかってさえいれば、今回のような手戻りにもならず、さらに言えばもっといい提案をすることにつながったはずです。逆に言えば、何が課題なのかを明確にしていなければ良質な提案なんて絶対にできないということでもあります。

この失敗を糧に、最適なソリューションを素早く提案できるエンジニアを目指します！！

## まとめ
まだまだ1人前には程遠いと日々考えながら過ごしていましたが、こうして振り返って言語化することで、着実にできることが増えていることを実感できつつあります。しっかりと振り返った上で具体的な行動に落とし込み、成長につなげていきたいと思います！

## 参考記事
+ [ペアプログラミングして気がついた新人プログラマの成長を阻害する悪習](https://qiita.com/hirokidaichi/items/27c757d92b6915e8ecf7)
+ [質問は恥ではないし役に立つ](https://qiita.com/seki_uk/items/4001423b3cd3db0dada7)
+ [エンジニアとしての問題解決思考](https://qiita.com/ritukiii/items/37441d3e93dbd034fb82)

## お知らせ
エイチームグループでは一緒に活躍してくれる優秀な人材を募集中です。
興味のある方はぜひとも[エイチームグループ採用ページ](https://www.a-tm.co.jp/recruit/)よりご応募ください。
[WEBエンジニア詳細ページ](https://www.a-tm.co.jp/recruit/requirements/career/lifestylesupport-webengineer/)よりお問い合わせ下さい。

## 明日
明日はクリスマスイヴです！爆速エンジニアの@shgktさんのE2Eに関する記事になります！
乞うご期待！
Arduino で Serial が動作しないと思ったら Serial1 を疑う。

編集前タイトル: Arduino で Serial を受信しないと思ったら Serial1 を疑う。

# 環境
What's Next Pink (Arduino Micro 互換)


# 症状
### Serial が何も受信しない
SoftwareSerial から RXピン データを与えてやっても，`Serial.available()` が0を返す。

# 原因
Arduino Micro の `Serial` は 0/1 番ピン (RX/TX ピン) とつながっていない。

# 解決方法
0/1 番ピン (RX/TX ピン)とつながっているのは `Serial1` なのでこちらを使う。


# 参考資料
https://www.arduino.cc/reference/en/language/functions/communication/serial/
【Mac】goenvを使ったGoのインストール

# はじめに
Macデビューしたのに当たって、Goの開発環境構築を"goenv"を使って行ったので、そのまとめです。

# goenvとは?
[goenv](https://github.com/syndbg/goenv)は、pyenvから複製されたGo用のバージョン管理ツールです。
プロジェクトに応じて、GoのVersionを変更がある場合などに、Versionを切り替えて開発をすることができます。

# goenvのインストール
まずは`goenv`をインストールする前にhomebrewをアップデートします。

```shell
$ brew update
```
アップデートが終了したら、次に`goenv`をインストールしていきますが、最新のgoのVersionをインストールしたい場合は、`HEAD`をオプションにつけた方が良いです。
(ちなみに後からでもgoenvのリポジトリを最新にすることは可能です。)

```shell

$ brew install --HEAD goenv
```
`goenv`がインストールできたら、`~/.bash_profile`に下記の設定を追加します。

```~/.bash_profile
export GOENV_ROOT="$HOME/.goenv"
export PATH="$GOENV_ROOT/bin:$PATH"
eval "$(goenv init -)"
```
これでTerminalから`goenv`がコールできるようになっているはずなので、Version
を確認します。
設定が有効になっていない場合があるので、その場合はShellの再起動を行って設定を有効にします。

```
$ exec $SHELL
```

ここまで実行したら、goenvのVersionを確認します。

```
$ goenv --version
goenv 2.0.0beta11
```

Version情報が表示されれば、goenvの準備は完了です。

# Goのインストール
次にgoをインストールしていきます。
今回は、私事で1.13.0で開発をする必要があるため、このVersionをインストールしていきます。

まずは対象のVersionがリポジトリで管理されているかを調べます。

```
$ goenv install -l
 .
 . 
 .
 1.13.0
 1.13beta1
 1.13rc1
 .
 .
```

インストールする対象のVersionが見つかったら、`goenv`を介してgoをインストールします。
と言っても、ここまで来てしまえば、後は対象のVersionを指定するだけで、インストールが始まります。

```
$ goenv install 1.13.0
```

# Goの環境設定
最後に使用するGoの設定を行います。
今回は先ほどインストールした1.13.0を使用するので、それを設定していきます。

まずは先ほど、インストールしたVersionがLOCAL環境に存在しているか確認します。

```
$ goenv versions
1.13.0
```

上記のように表示されればOKです。ですが、このままではLOCAL環境でGoを使うことができないので、対象となるVersionを指定して、Goを使える状態にしていきます。
まずは全体に適用するGoのVersionを指定します。

```
$ goenv global 1.13.0
```

文字通り、`goenv global`を指定することで、対象のVersionを設定することができます。
初回の設定では、`$GOPATH`,`$GOROOT`の設定が出来ていないので、設定を追加します。

```~/.bash_profile
...
export PATH="$GOROOT/bin:$PATH"
export PATH="$PATH:$GOPATH/bin"
```

上記を追加したら、.bash_profileを再度読み込みます。

```
$ source .bash_profile
```

最後にGoのVersionが確認できれば、インストールは終了です。

```
$ go version
go version go1.13 darwin/amd64
```

# 【おまけ】VSCodeとGo拡張設定
ついでにVSCodeの設定も行っていきます。
必要になるのは言わずもがな、[Go言語拡張](https://github.com/microsoft/vscode-go)。
![go-extension.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198150/5d094161-5cf2-5c3c-591e-691f0d999701.png)

これがないと、ほぼ何もできません。

今回使用している`goenv`のVersionが`2.0.0beta11`なのですが、下記記事にあるように、2.0.0beta6の段階で仕様変更があったようです。
そのため、今回の設定では、GOROOTを見つけられず下記のようなErrorが出力されます。
![goroot-error.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198150/055b9cb7-61b3-b41e-0739-1a1f04d8bf70.png)

この状態では、当然なからGOROOTを見つけられていないので、コード補完等も全く機能しません。
このままでは、非常に不便なので、作業フォルダに存在する`.vscode/settings.json`に設定を追加します。

```'.vscode/settings.json'
{
    "go.goroot": "~/.goenv/versions/1.13.0"
}
```
上記のように明示的に$GOROOTのパスを宣言することで、コード補完がされるようになります。
後はVSCodeを再起動して、再度作業ディレクトリを開きコード補完がされていることを確認します。
![gofmt.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198150/d6342196-ebcc-b2c5-251f-bbf66e9f3911.png)
Raspberry pi を使って、デスクトップパソコンの電気代を節約する（SSH、etherwake、WordPress）

この記事は、UECアドベントカレンダー22日目の記事です。
Raspberry 4 を購入したので、デスクトップパソコンやVPSで行っていた処理を Raspberry pi 4 に移すことができないか検討していきたいと思います。

# 動機：電気代が明らかに高くなった！

4月にコンピュータを組み立てたのをきっかけに、明らかに電気使用量が増えました…汗。
僕は実家住みなので電気代は親に負担していただけるとはいえ、これは流石に去年より使いすぎですねぇ・・・。
グラフより、電力使用量がかなり増加していることが読み取れます。
~~（でも、同じ料金プラン・契約容量のお客様の平均ご使用量より低いんですね）~~

![](https://gyazo.com/ead2a8d85b2250adaa519abde8f3df52.png)

※ グラフは、東京電力 電気家計簿より

# ラズパイに移したいもの・やりたいこと
今回は、とりあえず次の３つをできるようにしたいと思います。

- SSH 踏み台サーバー
- デスクトップパソコンの電源を付ける
- WordPress の運用

~~（本当は他にもやりたい計画があるのですが、アドベントカレンダーに間に合わせるため、今回は時間の都合で簡単そうなの３つということで…汗
→また時間があるとき書きます。）~~

# 使用機材
- Raspberry Pie 4 (4GB)
- micro SDHC 32GB (Sun disk)
- Windows 10 pro

# 行ったこと

なお、改めて記事を見直した結果、内容にまとまりがなく、記事を分割して参照する形とした方が良いと考えた為、記事を分割しました。

- [Raspberry Pi のセットアップ](https://takoyaki3.com/index.php/2020/04/28/raspberrypi_setup/)
- [Raspberry Pi からPCの電源を点ける](https://takoyaki3.com/index.php/2020/04/18/wake_on_lan/)
- [RaspberryPiによるWordPressの構築](https://takoyaki3.com/index.php/2020/04/28/raspberrypi_wordpress/)
- [RaspberryPiでバックアップを取る](https://takoyaki3.com/index.php/2020/04/28/raspberrypi_buckup/)

今回、SSH踏み台とデスクトップパソコンの起動、WordPressの運用をラズパイでできるようにしたので、使いたいときだけリモートでデスクトップパソコンの電源を点けられるようになりました。
なので、デスクトップパソコンを起動させる時間が減り、電気代が多少元に戻るはず・・・。来月の電気使用量が楽しみです。

時間があるときに、今回はデスクトップから移しきれなかったVPNサーバーや、あると便利かなと思うOwnCloudなどもラズパイ上に構築しようと思います。
DVCで学習モデルのバージョンコントロール

この記事は、[LeapMind Advent Calendar 2019](https://adventar.org/calendars/3954)の22日目の記事です。

# はじめに
ディープラーニングなどの機械学習で様々な実験を行なっていると、それに応じてたくさんのモデルが作られます。その際にどのモデルがどの学習によるものなのか、わからなくなってしまった経験はないでしょうか。プログラムのソースコードであればGITのようなバージョン管理システムを使うことで管理することができます。しかしながらGITは実験モデルのような巨大なバイナリファイルを扱うには適していません。そのようなソースコード以外のデータを管理するためのツールとして、[DVC](https://dvc.org/)を紹介します。

## 前提
DVCを説明する上、こちらの[Tensorflow Tutorial](https://github.com/tensorflow/docs/tree/master/site/en/r1/tutorials)を題材として使っていきます。見ての通り、学習したモデルを `model.h5` というファイルに出力します。この `model.h5` ファイルをDVCで管理していきます。

```main.py
import tensorflow as tf

mnist = tf.keras.datasets.mnist

(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(input_shape=(28, 28)),
  tf.keras.layers.Dense(512, activation=tf.nn.relu),
  tf.keras.layers.Dropout(0.2),
  tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])

model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

model.fit(x_train, y_train, epochs=5)
model.evaluate(x_test, y_test)

model.save('model.h5')
```

## DVCのインストールと初期化
まずはDVCのセットアップです。DVCはpipからインストールできます。

```
＄ pip install dvc
```

まんまですね。次にDVCをプロジェクトに対して初期化します。 と、その前にGITのリポジトリを作成します。DVCはGITと併用して使う前提となっています。

```
$ git init
```

次に、今度こそDVCの初期化をします。

```
$ dvc init
```

このコマンドにより `.dvc/` というディレクトリが作られ、DVCの設定などが置かれるようになります。

次に、以下のコマンドでモデルをDVCの管理下に置きます。

```
$ dvc add model.h5
100% Add|██████████████████████████████████|1.00/1.00 [00:00<00:00,  2.70file/s]

To track the changes with git, run:

	git add .gitignore model.h5.dvc
```

これにより `model.h5` のコピーがDVCの管理下に置かれます。 そして`model.h5.dvc` が生成され、代わりに `model.h5` は `.gitignore` に追加されます。 `model.h5.dvc` はテキストファイルで、 `model.h5` のハッシュ値など、DVCでの管理情報が記録されます。GITには `model.h5` の代わりに `model.h5.dvc` をコミットすることで、GITに直接大きなファイルを置かなくて済むようになります。

次に、DVCの管理下においたデータを異なるディレクトリにプッシュし保管します。

```
$ dvc remote add -d origin ~/Projects/leapmind-advent-calendar-2019-12-22.dvc
Setting 'origin' as a default remote.
$ dvc remote list
origin	/Users/takumi.nakaso/Projects/leapmind-advent-calendar-2019-12-22.dvc
$ dvc push
```

これにより、 `dvc remote` で指定したディレクトリに `model.h5` がコピーされて保管されます。これで、 `model.h5` それ自体はDVCに、 `model.h5.dvc` はGITに管理されるという状態になります。逆に、

```
$ dvc pull
```

とすることで `model.h5` を戻すこともできます。

# 終わりに
いかがでしたでしょうか。gitのような使い方で、ソースコードだけではなく実験モデルのようなデータも管理することができました。他にもPipelineなど独自の便利な機能がありますので、興味があれば使ってみてください。
[AWS] VPCでネットワーク構築３

[[AWS] VPCでネットワーク構築１](https://qiita.com/hosochin/items/5124c017d80b506a63ce)
[[AWS] VPCでネットワーク構築２](https://qiita.com/hosochin/items/b312c13b4734339c5158)
の続き

プライベートサブネットを作って、DBサーバを配置するまで

### 1.プライベートサブネットを作る

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384069/49ac2633-3b96-81bb-7746-5ea35ac6a8ff.png)
・リージョンが東京になっていることを確認
・VPCに作成済みのVPCを選択
・アベイラビリティゾーンに作成済みパブリックサブネットのアベイラビリティゾーンを選択（サブネット ＞ パブリックサブネットを選択 ＞ 説明タグで確認できる）

### 2.インスタンスを作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384069/b55aba7a-ba6d-2482-e039-b54dd54b697a.png)
・パブリックサブネットに作成したEC2インスタンスのときと同じ流れ
・ネットワークに作成済みのVPCを選択
・サブネットに1で作成したプライベートサブネットを選択
・自動割り当てパブリックIPにはネットワークに接続させないため「無効化」を選択
・プライマリIPは10.0.2.10にしてみる

### 3.サーバ名をつける
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384069/d050251f-104b-6116-e0df-ae93aa508bb9.png)


### 4.セキュリティグループを設定する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384069/1a35ef60-4b7d-e271-3ae7-31ae12760c6c.png)
・セキュリティグループ名に「DB-SG」と入力する
・今回はDBサーバでMySQLを使用するため、ルールを追加する
・送信元は任意の場所にしておく

### 5.作成済みのWEBサーバを踏み台にしてDBサーバにログインする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384069/17677cb2-c2b2-de8b-7a5a-52ad509cb5e9.png)
・キーをsshで転送する（画像はwindowsの場合の例、teraTerm ＞ ファイル ＞ SSH SCPから送信）

```
[ec2-user@ip-10-0-1-10 ~]$ ssh -i my-key.pem ec2-user@10.0.2.10
The authenticity of host '10.0.2.10 (10.0.2.10)' can't be established.
Warning: Permanently added '10.0.2.10' (ECDSA) to the list of known hosts.

       __|  __|_  )
       _|  (     /   Amazon Linux AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-ami/2018.03-release-notes/
[ec2-user@ip-10-0-2-10 ~]$ hostname
ip-10-0-2-10
```

・配置したキーを使用してssh接続する

### 6.プライベートサブネットに配置したサーバにMySQLをインストールする
プライベートサブネットはインターネットに接続できないため、yumなどのコマンドでインストールできない
NAT(Network Address Translation)という仕組みを使ってインストールしてく

- VPC ＞ NATゲートウェイ ＞ NATゲートウェイの作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384069/893caa58-e191-b2ec-a9f9-b6d81605023e.png)
・パブリックサブネットを選択し、新しいEIPの作成をクリック

### 7.デフォルトゲートウェイにNATゲートウェイを設定する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384069/4fb02454-df18-ce4d-273c-3958c9dc3aa1.png)
・VPC ＞ ルートテーブル ＞ メインが「はい」になっているルートテーブルを選択 ＞ ルートの追加
・送信先にはデフォルトゲートウェイを表す0.0.0.0/0を、ターゲットには作成したNATゲートウェイを選択する

### 8.MySQLをインストール

```
[ec2-user@ip-10-0-2-10 ~]$ sudo yum -y install mysql-server

sudo service mysqld start

[ec2-user@ip-10-0-2-10 ~]$ mysqladmin -u root password
New password:
Confirm new password:
```

 
　　
AWS無料枠を超えてしまうのでNATゲートウェイは使い終わったら削除しちゃいます
　
これで今回作成しようとした環境は完成です！
Three.jsとIndexedDBでMMDモデルビューアーを作った

# はじめに
Three.jsにはMMDモデルを読み込んでくれるMMDLoaderというツールがあり、これでMMDモデルを確認できるビューアーアプリを作りたいと思ったのですが、MMDモデルをサーバーにアップロードする形だと著作権的にグレーな気がしました。

そのとき、「ローカルで見るだけならわざわざサーバーに送る必要ないのでは？」ということに気づき、サーバーに送らなくて済むタイプのMMDモデルビューアを作ってみることにしました。

そのために一時的にブラウザからアクセス可能なローカルの領域を用意する必要があるのですが、今回はそれにIndexedDBを使いました。
(Githubのissueを調べたところ、IndexedDBについては何かしら[議論したあと](https://github.com/mrdoob/three.js/issues/5650)があったのですが、この感じだとまだサポートは無いんだと思います)

# 作ったもの
## デモ
[こちら](https://one-color-low.github.io/MMDSaver/app/)のデモをご覧ください。
MMDモデル(pmd/pmx)のファイルを選択すると、そのMMDモデルが表示されるはずです。
※MMDモデルはてきとうに「MMDモデル 配布」とかでググって見つけてください。
※申し訳ありませんがまだテクスチャは貼れません...

## プログラム
https://github.com/one-color-low/MMDSaver

- `app/MMDSaver.js`というのがIndexedDBのあれこれを操作してるjsです。
- `app/js/loaders/MMDLoader.js`はarraybufferを直接読み込めるように改造してあります。

# 仕組み
MMDLoaderに限らず、Three.jsの3Dモデルローダーは第一引数に静的ファイルのパスを渡す仕様になっていると思います。MMDLoader内ではこのパスに基づいて xhrリクエストをサーバーに送信し、レスポンスとしてArrayBuffer形式のモデルファイルを受け取っています。 このことから、ローダーにパスではなく直接ArrayBufferを渡せばいいと思いました。

## 流れ
1. フォームからバイナリ形式のファイルを取得
2. ファイルを`readAsArrayBuffer`でArrayBufferに変換
3. IndexedDBに保存
4. IndexedDBから取り出し
5. 一度blobに変換しローダーに渡す   ※なぜかArrayBufferのままではローダーに渡せなかったため
6. ローダー内でblobに対し`readAsArrayBuffer`をかけArrayBufferに戻す
7. 本来xhr処理するはずだった場所でこのArrayBufferを受け取る


# さいごに
初心者なので間違ったことを書いてしまっているかもしれません。もし何かあればコメントください！！
Javascriptレシピ⑤

Javascriptの簡単なメモです。
アプリ制作に応用できる基本レシピですので、参考にされたい方はどうぞ。


###連想配列のループ処理

連想配列とはキーと値のペアで構成される配列です。

```js

const array = {
    key: 'value',
    key:'value',
}
```

プロパティを指定するには2種類の方法があります。

```js

//ドット記法
array.key

//ブラケット記法
array['key']
```

```js

const obj = {}
for(const i=0; i<5; i++){
    obj[i] = i*100;
}

for(const key in obj){
    if(obj.hasOwnProperty(key)){
        const val = obj[key];
        console.log(val);
}

//for in文でループ処理をしてプロパティを出力しています。
```

###Javascriptの実行が遅い時

JSは外部ファイルに記述する
JSファイルの読み込みは/bodyの直前にする
無駄な変数宣言や毎回のDOM生成をしない

###ファイルのダウンロード

Blobオブジェクトとwindow.URL.createObjectURLメソッドを使います。

```js

<a href='./wanko.txt' download='wanko'>ダウンロード</a>

const blob = new Blob(
    [text],
    {'type':'text'})
    const url =window.URL.createObjectURL(blob)
    document.getElemntById('link') = url
}
```

###JSでselect要素にoption追加

selectタグを取得
optionタグを作成、テキストとvalueを設定
appendChildでタグ追加

```js

<button onVlick='add()'>add</button>

<select name='name' id='select'>
    <option value='1'>1</option>
    <option value='2'>2</option>
</select>


function add(){
    const select = document.getElementById('select');
const option = dociument.createElement(option);
option.text=3;
option.value=3;
select.appendChild(option);
}

```


###JSでのセッションの情報管理

セッションとはフロント側でデータを一時保存できる機能のことです。

```js

//SessionStorageが使用可能か判定
if(('sessionStrage' in window) && (window.sessionStotagr !== null)){
    //ok
}    else{
    //no
}

//SessionStorageへデータを保存
sessionStorage.setItem('session_save',1);
window.sessionStorage.seiItem('session_save',1);
sessionStorage.session_save = 1;

//データを取り出す
get_storage = sessionStorage.getItem(session_save);
get_storage = window.sessionStorage.getItem(''session_save);
get_storage = sessionStorage.session_save;

//データを削除
sessionStorage.removeItem('session_save');
window.sessioStorage.removeItem('session_save');

//全削除（初期化）する
sessionStorage.clear();
window.sessionStorage.clear();
```

###文字コードを変換


文字コードとは機械語を人が読める文字に変換するための規約です。

文字列の1文字の文字コードの確認には

```js

文字列.charCodeAt(数値)
```

文字コードのデコードには


```js

String.fromCharCode(数値);
```

###処理の順番の変更

```js

console.log('a');
cetTimeout(()=>{
    console.log('b')},0
);
console.log('c');


let num = 100;
console.log(num);
new Promise((resolve,reject) => {
    num +=100;
    console.log(num);
    resolve(num);
}).then((num)
 =>{
    setTimeout(()=>{
    num+=200},0);
    console.log(num);
}).then((num) =>{
    console.log(num);
})

//100 200 400 400
```

###配列の最後の要素を書き換える

```js

const array = ['a','b','c']

array[array.length - 1] = 'e';

array.pop();
//削除

delete.array[2];
```


###配列の最後の要素を書き換える

```js

const array = ['a','b','c']

array[array.length - 1] = 'e';

array.pop();
//削除

delete.array[2];
```

###動的変数

varでの変数宣言はやめましょう。

let:動的変数、最大代入可能
const:静的変数、再代入不可能

関数内で宣言した変数は外部から参照できず、constは値の変更はできません。

###textareaオブジェクト

textarea要素を扱うことが出来ます。

```js

document.getElementById('wanko').value
//valueでプロパティを使用できます
document.getElementById('wanko').value = pome

document.getElementById('wanko').value.row = '10'

const input_message = document.getElementById('message').value;
message = 'input_message';
document.getElemtntById('output_message').innerHTML = message;
```
Python基礎 if文

#Python基礎①
アウトプット用にメモ
##if文
```

number = 40
if number > 30:
     print "hello world!"
     print "Hello World!"
```

###比較演算子 > < >= <= == != 論理演算子　and or not

```

if number > 50 and number < 70:
     print "hello world!"
     print "Hello World!"
if 50 < number <70
     print print "hello world!"
     print "Hello World!"`

number = 60
if number > 50:
     print "hello world!"
elif number > 30:
     print "Hello World!"
else:
     print "HELLO WORLD"

print "yes" if number > 60 else "no"
```


[エンジニア転職活動参考サイト](https://engineer-work.com)
Nutanixのコンポーネントとギリシャ神話

ALH Advent Calenderです。
仲のいい社員に誘われて参加してみました。
qiitaの投稿自体初めてなので、ドキドキしてます。


#背景
インフラエンジニアやってます。

最近現場でNutanixを扱うことが増えたため、HCIとはなんぞや！？から勉強しています。
全然理解できていませんが、本番機も数回触らせていただいている今、
勉強の第一歩として**ギリシャ神話**から入ろうとしています。

なぜギリシャ神話？となると思いますが、
ある時、Nutanixでお馴染みの`cluster status`を実行したときに気付きました。

`Zeus、Medusa、Chronos、、、、`

とりあえず最初の`Zeus`で吹きました。
今まで真面目な(?)製品しか扱ったことがなかったのかもしれませんが、神の名前は私にとっては新鮮でした。
何を投稿するか悩んでいた時期に気付いたので、「記事にするしかない！」となり、未熟ながらも投稿させていただきます。

今回は超多忙期により全然時間を取れなかったため、一旦Zeus、Medusaのみです。
（色々落ち着いたら、もっとわかりやすく追記させてください。）


#Nutanixコンポーネントとギリシャ神話
##Zeus
###ギリシャ神話では・・・
ギリシャ神話の中で全知全能の最高神ともいわれるほど、最強な神。
そして恋多き神としても知られています。
有名な英雄であるヘラクレスの父であったりもします。
とりあえず今は**ギリシャ神話の最高神**として記憶してください。

###Nutanixでは・・・
**単刀直入に言うと、ゼウスが止まるとNutanixは止まっちゃいます。**
ゼウスは全てのコンポーネントがクラスタ構成にアクセスするために使用するNutanixライブラリインターフェースで、
クラスタ構成やリーダーシップロックといった重要なクラスタ全体のデータを処理します。
すなわち、他の全てのコンポーネントはゼウスに依存しています。
なので、ゼウスが停止してしまうと、他のコンポーネントがクラスタ構成にアクセスできなくなり、止まっちゃうということになります。

じゃあ`cluster status`でZeusがUPしてなかったら他のもUPしないのか...
ちょっと見てみたいです。（お金持ちになって家にNutanixを買えたら...）

##Medusa
###ギリシャ神話では・・・
蛇の頭で知られる怪物。
ペルセウスに退治される話は子供の時によく聞きました。（意外とこの話が好きだった）
退治後には敵を石化させるために使われて大活躍してます。
[古代ギリシアでは子供の悪戯防止と魔除けの意味を込めていたようで竈にメドゥーサの絵を描いていた事が分かっています。](https://spirituabreath.com/girisyasinnwa-medhu-sa-11576.html)
と、魔除けの意味もあるみたいですね、

###Nutanixでは・・・
メドゥーサはクラスタのメタデータをもつデータベースの前にいるNutanixの抽象的レイヤーです。
（若干棒読みです）
抽象的レイヤーとは、Wikipediaによると[ある特定の機能の詳細な実装を隠す手段である](https://ja.wikipedia.org/wiki/%E6%8A%BD%E8%B1%A1%E5%8C%96%E3%83%AC%E3%82%A4%E3%83%A4%E3%83%BC)らしいです。
なるほど、何かしらを隠したいんですね。
あとで書き足したいのですが、スターゲイトとキュレーターなるものが、Cassandra（データベース）と通信するためにメドゥーサを介さないとといけません。
私の今の理解では、**データベースを守るためにいる存在なんだなー**くらいです。



#終わりに
締め切り直前にやってしまったので「内容がないようだ」の状態で申し訳ないです。
今までミドルウェアばかりやっていたこともあり、HCIはおろか、ストレージやら何が何だかわからん状態で、とっても苦労している途中です。
手探り状態でやっと掴んだのがZeus...（だが全然わかっていない！）
興味深い名前を付けていただいたおかげで、未曾有の地に一歩踏み入れられました。と言うことにします。

（書きながら、自分の知識のなさを痛感）


####追記予定
Cassandra・・・2020年のどこか


#参考
* [【YouTube】Nutanix University - Medusa+Cassandra](https://youtu.be/vzEBmcBvVKc)
* [【YouTube】Nutanix University - Zeus+Zookeeper](https://youtu.be/OYi9yB38ivY)

* [Nutanixのクラスタのコンポーネントを覚えてみよう！](https://blog.lenovojp.com/entry/2018/10/31/010016)
* [Nutanixバイブル](http://nutanixbible.jp/)
いつもお世話になっております。

* [1分でわかるNutanix - ネットワールド](https://www.networld.co.jp/product/nutanix/movie/1minute/) 
Nutanixの概要を楽しい動画で学べます 

* [世界雑学ノート - ゼウス](https://world-note.com/zeus/)
* [ギリシャ神話 メデューサにまつわる５つの話](https://spirituabreath.com/girisyasinnwa-medhu-sa-11576.html)
スクラムマスター体験談~理想のチーム論と学んだこと~

##はじめに!
　某プログラミングスクール最終課題にて、スクラムマスターを経験させて頂きました！
スクラムマスター何それおいしいの？状態からのスタートでしたが、
勉強になったことや、未だに思い返しても嬉しかったことが多々ありましたので、
備忘録として体験談を書かせていただきます:grin:

本来のスクラムマスターの役割と違う部分や、顧客のいない中での開発なので、
間違っていたり、非現実的な部分もあるかとは思いますが、
私個人の理想のチーム論として見ていただけますと幸いです:bow_tone3:

## 理想としたチーム状態
#####『チームメンバーが主体的に、コードを書くこと（＋チームと顧客）にだけ集中している状態。』
以下、イメージ図です。
<img width="1018" alt="スクリーンショット 2019-12-22 22.16.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542326/1ec193b6-1751-fb61-39a7-64a42110ad85.png">
（今回の投稿は、この図が作りたかった、と言うのが動機のほとんどです:sweat_drops:）

## 開発環境
・チームメンバー：6人
・制作物：某ECコピーサイト(Ruby on Rails)
・システム：アジャイル開発（スプリントレビュー: 1回/週、デイリースクラム: ３回/日）
　　　　　　 プロダクトオーナーさんは、スプリントレビュー時のみ登場。
・開発期間：3週間
・開発時間：10 h/日

## マスターとして心がけたこと
　行動方針は、「__理想の状態 ”チームメンバーが主体的にコードを書くこと（＋チームと顧客）にだけ集中している状態"になることを妨げる障害物を取り除くこと。__」として、具体的には以下の行動を心がけました。
####1.　行動の賞賛
　コードを書く、発言をする、自分の意見を言う、など、行動することは全てウェルカム！:clap:
####2.  ターゲット（やるべきこと）の明確化
　Trello（タスク管理アプリ）に、一目で課題がイメージできるレベルまで落とし込むよう、カードを量産する！:hammer:
　（何をしたらいいかがわからない状態は辛いです。非効率です。）
####3.  全体における、各人の仕事の位置付けの共有
　常に頭の中で全体像をイメージする、パワーポイントなどで可視化する。:mag:
　（なんのためにやっているのか、がわかった方がやる気が出るはず。コラボレーションも進むはず！）
####4. 不満の察知
　とりあえず話す。表情を見る。毎朝話すことが大事かと感じています。朝スクラムは大事:sunny:

## 学んだこと
####チームでまとまるためには、共通の目的が絶対必要！！

 チームメンバーは様々な考え、目的、思い、価値観を持って行動している。
 上記の行動をしたところで、簡単にまとまることは決してありえない。
何が大切かを共有する、それをベースに話し合う、というのが効果的なのではないかと思いました。
『〇〇のために、ここは××をすべき』のような感じですかね。
#####自分の意見が正しいと思わない。きちんと相手の話を聞く。
 これが二番目に大事だと思いました。かなり難しいですが。

#####（感情のコントロールも大事。。。）
 人の考えはそんな簡単に伝わりません。。。

## 反省点
#####・タスクの見積もりを失敗すると死ぬ。
　基本的にチーム内のトラブルのほとんどは、個人のスキルをタスクが大きく上回った時に発生しました。そして、その原因は、タスクの難易度を軽く見積もった、あるいは見積もれなかったこと、つまり、技術の理解不足、に起因していました。ある程度難易度を当てることは絶対に必要だと思いました。。。勉強あるのみ！
（タスクのアサインがスクラムマスターの本来の仕事かどうかはさておいて）
#####・自分の弱さを自覚する。
　感情が乱れるのは、自分の未熟な部分が出てきた時かと思います。
自分で認識していれば、多少は対処可能、のはず！


## 個人的に嬉しかったこと
####『チームメンバーがマスターの期待を上回る行動をした時』
　難しいと思っていた人同士で協力し始めた時とか、スキルの低かった人が自分で勉強して武器を手に入れて、むしろチームを引っ張ってくれたりとか、もっと仕事下さいとか言ってくるとか、本当に楽しそうに課題に取り組んでくれるとか、グイグイ来てくれるとか、不和を乗り越えた時とか、そういう時は、胸が熱くなります:fire:



####以上です。
####読んでくださった方、最後までお付き合い頂き、ありがとうございました。:bow_tone3:
JavaScriptで要素が画面に表示されているかの判定

Vue.jsで要素のCSSアニメーションをつける際に「要素が画面に入ってきたら」という条件を判定したく、調査をして実装したのでそのまとめとなります。

elementの取得方法については今回はVue.jsの機能で取得していますが、document.getElementByIdなどで取得しても同様に動きます。

[こちらの](https://github.com/m-mogi-ojs/portfolio/blob/master/src/components/SkillCard.vue)コンポーネントで実装しています。

```javascript
// 画面最上部と要素の上端の距離
// こちらの値はスクロール値がすでに引いてある値となるので注意。
// 要するにこの値が0の場合要素の上端が画面の上端となっている状態
var positionY = this.$el.getBoundingClientRect().y
// 要素の縦幅
var clientHeight = this.$el.getBoundingClientRect().height
// 表示している画面の領域の高さ
var windowSize = window.innerHeight

/**
 * 画面上部の判定
 * 画面最上部との距離 + 要素サイズ > 0
 * = 画面上部に要素の一番下部が表示されているか
 * かつ
 * 画面下部の判定
 * 画面最上部との距離 < 画面サイズ
 * = 画面下部に要素の一番上部が表示されているか
 */
if (positionY + clientHeight > 0 && positionY < windowSize) {
  // 画面に要素が少しでも表示されている場合
} else {
  // それ以外
}
```
具体的には、下記のようにしています。

```javascript
if (positionY + clientHeight > 0 && positionY < windowSize) {
  // 画面に要素が少しでも表示されている場合
  // 画面に表示されるclassを付与する
} else {
  // それ以外
  // 画面に表示されなくなるclassを付与する
}
```
表示だけでなく、様々なエフェクトをかけたい場合はここからさらにsetTimeoutなどの非同期処理で順を追ってclassを付与していくと良いと思います。
riot.jsでAmazon S3使う際にリロードすると403が出てしまう時にすべきこと

## はじめに
どうもです。
Riot.jsを利用して作成したコンテンツをAmazon S3で配信する際に、404エラーが想定通り処理されなかったので対応した内容を書きます。

Riot.jsアドベントカレンダー2019の5日目、@nekijakさんの記事を見ながらふんふんとルーティングについて学び、最高にわかりやすかったです。ありがとうございます。
その後、じゃーいつも使ってるS3に乗っけてみるかと漫然と乗っけたところうまく行かなかったのでじゃあこれを書こうと思った次第です。

### 参考にさせていただいた記事
* Riot.js v4対応 Router - Qiita （件の@nekijakさんの記事）
    * https://qiita.com/nekijak/items/bb87e1eec71f4b95190c

## 問題点

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146594/3e5ae79e-12e5-bdb4-93bd-8dba08ac4baa.png)

例えば、一度 `/hello` にアクセスし、そのままブラウザでリロードした場合に、デフォルトではスクショのように403エラーが返ります。

直接的な原因は「hello」に対応するオブジェクトがないという事に対し、S3側から403エラーが返ってきていることです。根本的には色々とすべきことはありそうですが、ここではまずちゃんと **対応するオブジェクトがない場合404エラーが返るように修正する必要がある** という問題認識だとします。

## 解決方法
CloudFrontを利用して、コンテンツを配置したバケットに対して設定を行います。403エラーの場合に404エラーを返すようにした上で、所定のエラーページを表示されるようにします。

### Distributionの作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146594/6e244e72-a85e-9929-1581-b387ff5f5af7.png)

1. CloudFrontで「Create Distribution」を選択します。
2. delivery methodとしてWebかRTMPか聞かれるので「Web」を選択します（ちなみにRTMPはCFとS3で動画ストリームを配信するやつです）
3. Originの設定画面に移るので「Origin Domain Name」にコンテンツを配置したバケットのパスを入力します。めっちゃ項目ありますが、他はデフォルトのままでOKです。
    * 余談ですがここでComment欄にも入力することをオススメします。また内容はこのDistributionを作った日付や目的にするのがオススメです。なぜなら、空欄のままだと後からなんで作ったのかわからなくなりがちだからです。
    * <Distribution一覧画面での見え方> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146594/38d15f15-0ff9-9e95-47d8-4b58400d4ff9.png)

### Error Pagesの設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146594/81abd6db-bfc4-490b-71ed-203aefc76c20.png)

Distributionが作成されたら、「Error Pages」の設定タブを開きます
「Error Pages」の設定タブで「Create Custom Error Response」を選択します
設定画面に移るので、次の項目をそれぞれ設定します。

| Key | Value |
| ------ | ------ |
| HTTP Error Code | 403:Forbidden |
| Customize Error Response | Yes(これを選択すると、下のパスやエラーコードの入力欄が展開されます） |
| Response Page Path | エラーページのコンテンツのパス |
| HTTP Response Code | 404: Not Found |

設定が完了したら、StatusがDeployedになるまで待ちます。
Distributionの設定が反映されるまでは、結構時間がかかります。私の実績としては今回のような設定で毎回20-30分くらいかかりました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146594/c9ed3d66-21e6-d4ab-73b3-d03cdf29c9f0.png" width="100px">
▼
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146594/432aa7b4-c88c-e364-ab37-66c8bb40b02f.png" width="100px">

## 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146594/57f2bc7b-20e7-56fc-607d-d9d18bc0fca3.png)

404.htmlの画面が表示されます。

また、存在しないオブジェクトへのURLを指定した場合にも404.htmlの画面が表示されます（404として処理されます）

## さいごに
404エラー以外にも同様にエラーをハンドリングできます。
Riot.jsっていうかAWSの話になってしまったんですが、同じ問題にあたった方の参考になれば幸いです。

やっぱAWS面倒くさいって思います？でも、なれればかゆいところに手が届くクラウドサービスなので僕は好きです。

Riot.jsもAWS使ってやっていこう。
Dockerでscssを書く

#Dockerでscssを書く
普段のちょっとした開発を試すときとか、scss使って効率よくしたいなと思ったので、備忘録です。
前準備としてはこちらが必要です。
[Dockerで開発環境構築（Mac + Nginx + PHP-FPM）](https://qiita.com/art_porokyu/items/788bf943c45855475bfe)

##docker-compose.ymlの編集
npmを使います。

追加

```
  node:
    image: node:latest
    ports:
      - "8000:80"
    volumes:
      - ./:/src
    working_dir: /src

```

``node``の部分は好きな名前に変更してください。
``latest``の部分は任意のversionに変更可能です。

##node install

```
$ docker-compose run --rm node npm init
```
package.jsonが作成されます。

##sassをインストール

sassをコンパイルできる``node-sass``をインストール。

```
$ docker-compose run --rm node npm install node-sass
```

package.jsonへの記述

```package.json
  "scripts": {
    "css/scss": "node-sass src/scss/style.scss -o src/dist/css --output-style expanded",
  }
```

scssファイルを作りstyle.scssの中にscss記法で何か書きます。

その後npmを実行します。

```
$ docker-compose run --rm node npm run css/scss
```

srcディレクトリの中に``dist``でディレクトリが作成されるはずです。
このdistディレクトリの中にcss/style.cssがあるはずです。

それがコンパイラされたstylesheetです。

以上になります。
jsでマルチスレッド的にループを回す

# マルチスレッド的にループを回す

```js:worker.js
self.addEventListener('message', (message) => {
    for (let index = 0; index < 100; index++) {
        console.log(message.data + "_" + index);
        
    }
});
```

```js:実行側
// メッセージを送信する
const worker1 = new Worker('worker.js');
worker1.postMessage('こんにちは1');
const worker2 = new Worker('worker.js');
worker2.postMessage('こんにちは2');
const worker3 = new Worker('worker.js');
worker3.postMessage('こんにちは3');

```

これでこんにちはが入り乱れて実行される。
年末まで毎日webサイトを作り続ける大学生 〜65日目 文字を泳がせる〜

##はじめに
こんにちは！@70days_jsです。
今日は文字を泳がせてみました。(gif)↓
![test3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/516248/e6eed18d-8e5b-7aae-4bd2-6dcca6a803c4.gif)

65日目。(2019/12/22)
よろしくお願いします。

##サイトURL
https://sin2cos21.github.io/day65.html

##やったこと
文字を泳がせてみました。
別の言い方をすると、文字がランダムなスピードでY方向の移動をくり返しています。

html↓

```html

 <body>
    <canvas id="canvas"></canvas>
  </body>
```

canvasを使っています。

css↓

```css
body {
  margin: 0;
}
#canvas {
  background-color: black;
}
```

bodyのmarginを消して、背景を黒にしています。

JavaScript↓

```javascript

let canvas = document.getElementById("canvas"),
  ctx = canvas.getContext("2d"),
  twidth = (canvas.width = window.innerWidth),
  theight = (canvas.height = window.innerHeight),
  chars = [],
  fontSize = Math.random() * 100,
  countNumber = 1,
  flag = true;
chars2 = [
  "あ",
  "い",
  "う",
...略...
  "を",
  "ん"
];

function Character(ctx) {
  this.ctx = ctx;
  this.x = Math.floor(Math.random() * twidth);
  this.y = Math.floor(Math.random() * theight);
  this.size = fontSize;
  this.char = chars2[Math.floor(Math.random() * chars2.length)];
  this.v = Math.floor(Math.random() * 5);
}

Character.prototype.render = function() {
  this.draw();
  this.positionChange();
};

Character.prototype.positionChange = function() {
  this.y -= this.v + 1;
  if (this.y < 0) this.y = theight;
  if (this.y > theight) this.y = 0;
};

Character.prototype.draw = function() {
  let ctx = this.ctx;
  ctx.beginPath();
  ctx.fillStyle = "rgba(31, 227, 13, .5)";
  ctx.font = this.size + "px Arial";
  ctx.fill();
  ctx.fillText(this.char, this.x, this.y);
  ctx.closePath();
};

for (var i = 0; i < 100; i++) {
  fontSize = Math.random() * 15;
  let char = new Character(ctx);
  chars.push(char);
}

function render() {
  ctx.clearRect(0, 0, twidth, theight);
  for (var i = 0; chars.length > i; i++) {
    let char = chars[i];
    char.render();
  }
  requestAnimationFrame(render);
}

render();

```

昨日作ったCharacterコンストラクターを再利用しています。
メソッドは新たにpositionChange()メソッドを加えました。

Y方向の移動をthis.vを使って変更しています。
this.vはランダムで作っているので、あまり遅すぎるものを警戒して最後に+1しています。


##感想
とてもシンプルなコードですが、文字が動いているのはワクワクしますね。
ひらがなっていいな。

最後まで読んでいただきありがとうございます。明日も投稿しますのでよろしくお願いします。