OmniAICreator/Qiita-1.07M huggingface dataset:
How to change Linux host name in EC2 user data

**This article is an automatic translation of the article[ead862e002c543070b49] below.
https://qiita.com/speaktech/items/ead862e002c543070b49**

# User data
Use fqdn key in cloud-init directive of user data.
This is all you need to do is change the host name.

```yaml:user-data.yaml
#cloud-config

fqdn: example.co.jp
```

** The hostname key also has a hostname key.
However, the hostname key is ignored if the fqdn key is used.
Since the AWS default host name is defined by the fqdn key, you need to use the fqdn key to overwrite it. **

# How to enter user data 1: GUI

Paste it in [User data] of [Create instance]> [Step 3: Detailed setting of instance]
Just create an instance.

[image.png] (https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218139/5f7976b3-c053-402b-6550-d75089419e88.png)

# How to enter user data 2: AWS CLI

Pass the raw text file with the --user-data option. As yaml, but the extension is OK.

```bash
aws ec2 run-instances --region $Region \
  --image-id $AmiId --count 1 \
  --instance-type $InstanceType --key-name $KeyName \
  --subnet-id $SubnetId --private-ip-address $PrivateIpAddress \
  --associate-public-ip-address \
  --security-group-ids $SecurityGroupIds \
  --tag-specifications "ResourceType=instance,Tags=[{Key=Name,Value=$NameTag}]" \
  --credit-specification CpuCredits=standard \
  --user-data file://userdata.yml
```

※ Please set the value of variable appropriately. Please change the line feed character from"\"to"`"when executing with Powershell.

# NOTE: The host name is initialized when launching from the created AMI

The default behavior is to initialize the hostname, locale and default user in cloud-init.
If you simply want to prevent this, set the preserve_hostname key to true in the user data.

```yaml:user-data.yaml
#cloud-config

fqdn: example.co.jp

runcmd:
 - echo "preserve_hostname: true" >> /etc/cloud/cloud.cfg
```

* If the preserve_hostname key is set to true, the hostname key and fqdn key will not function.


that's all.
AESでテキストを暗号化する（javascript）

# 暗号化方式
AES、TKIP、WEPなど色々なアルゴリズムがありますが、今回はAESで暗号化します。モードはCBC。

## キーのみで暗号/複号

```js
var CryptoJS = require('crypto-js');

var pwd = "password";

function Encrypt(word) {
    return CryptoJS.AES.encrypt(word, pwd).toString();
}

function Decrypt(word) {
    return CryptoJS.AES.decrypt(word, pwd).toString(CryptoJS.enc.Utf8);
}

var origin = 'test';
console.log(origin);
var mm = Encrypt(origin);
console.log(mm);

var jm = Decrypt(mm);
console.log(jm);
```

## キーとIVで暗号/複号

```js
var CryptoJS = require('crypto-js');

var key = CryptoJS.enc.Utf8.parse('0123456789abcede');
var iv = CryptoJS.enc.Utf8.parse('1234567812345678');

function Encrypt(word) {
    srcs = CryptoJS.enc.Utf8.parse(word);
    var encrypted = CryptoJS.AES.encrypt(srcs, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
    return encrypted.ciphertext.toString().toUpperCase();
}

function Decrypt(word) {
    var encryptedHexStr = CryptoJS.enc.Hex.parse(word);
    var srcs = CryptoJS.enc.Base64.stringify(encryptedHexStr);
    var decrypt = CryptoJS.AES.decrypt(srcs, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
    var decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
    return decryptedStr.toString();
}

var origin = 'test';
console.log(origin);
var mm = Encrypt(origin);
console.log(mm);

var jm = Decrypt(mm);
console.log(jm)
```

# その他
「javascript側で暗号化→同じjavascript側で復号」ケースだけではなく、
「javascript/python/java側で暗号化->javascript/python/java側で復号」ケースにも活用できます。
Vagrant upで bash: Zeile 4: setup: Kommando nicht gefunden.のエラーが出た時の対処

# Vagrant upで bash: Zeile 4: setup: Kommando nicht gefunden.のエラーが出た時の対処

ITエンジニアの田中です。
本日は、Vagrant upでエラーが出力された時の対応について、記事を作成します。

下記のエラーが出た場合、Share Folderが使えません。

```
bash: Zeile 4: setup: Kommando nicht gefunden.
```

私の場合は、VirtualBoxのバージョンと Guest Additions Versionが異なるため発生していました。
つまり、Boxを作った時のVirtualBoxのバージョンと現在のVirtualBoxのバージョンが違うということです。
VirtualBoxのバージョンを上げたために発生します。

## 内容
default: Guest Additions Version: 4.3.28
default: VirtualBox Version: 5.2
下記のコマンドを実行して、Boxのバージョンを揃えてくれるプラグインを入れます。

vagrant plugin install vagrant-vbguest
下記のメッセージが表示されば成功！

Installed the plugin 'vagrant-vbguest (0.15.2)'!
再び下記のコマンドを実行

vagrant reload
しかし、失敗。
vagrant-vbguestのguestのバージョンアップが失敗したため・・・
多くの場合は、クライアントOSの何かが古い可能性が高い。。。

下記のコマンドでクラアントに入る。

vagrant ssh
下記のコマンドでクライアントOSをバージョンアップする

yum update
私の場合は、294個のRPMがアップデートされました！

ホストOSに戻り下記のコマンド

vagrant reload
無事、解決！
Is your Linux instance okay? Configurations that cloud-init initializes when restoring from AMI

**This article is an automatic translation of the article[52995b55477f7d8efd19] below.
https://qiita.com/speaktech/items/52995b55477f7d8efd19**

## What this article introduces
On AWS, the automatic configuration tool"cloud-init"is installed on most Linux instances.
The default settings for cloud-init include items that perform initialization when the AMI is launched for the first time.
If you leave the default setting, there is no problem during normal use, but starting from the AMI at the time of restore will cause some items to be initialized.

In this article, we will introduce the items that user data is initialized at AMI startup and how to prevent it.

## Verification environment
-Region: ap-northeast-1
-AMI: RHEL-7.6_HVM-20190515-x86_64-0-Hourly2-GP2-ami-04eb805483f5607a7
-Instance type: t2.micro

## Items where user data is initialized when AMI is launched
-Host name (set to a host name based on Private IP named ip-XX-XX-XX-XX)

-Default user (ec2-user is created)

-Locale (set to en_US.UTF-8)

-Package (security update is executed)

## How to prevent initialization

Just create a configuration file for initialization prevention with the following command.
(Time zone setting is added just in case, but it was not initialized in RHEL 7.6)

```bash
cat >> /etc/cloud/cloud.cfg.d/99_preservesetting.cfg << EOF
repo_update: true
repo_upgrade: none
preserve_hostname: true
locale: ja_JP.UTF-8
timezone: Asia/Tokyo

system_info:
  default_user:
    name: cloudinit-user
    lock_passwd: true
    gecos: Cloudinit User
    groups: [ adm, wheel, systemd-journal ]
    sudo: [ "ALL=(ALL) NOPASSWD:ALL" ]
    shell: /bin/bash
EOF
chmod 644 /etc/cloud/cloud.cfg.d/99_preservesetting.cfg
chown root:root /etc/cloud/cloud.cfg.d/99_preservesetting.cfg
```

#### Commentary
-** repo_update **: Update locally cached repository metadata (true)/not update (false)
-** repo_upgrade **: apply all updates (except for the repo_upgrade_exclude value) (all, on, true)/apply security updates (security)/do not apply updates (none, off, false)
-** preserve_hostname **: Maintain hostname (true)/Do not maintain (false)
-** locale **: Set the locale (locale)
-** timezone **: Set the time zone (time zone)
-** default_user **: Set the default user (default user information)


that's all.
Nginxを使って同一サーバーで複数アプリを動かす

# Nginxを使って同一サーバーで複数アプリを動かす

## 何がしたい？
* nginxとapacheを同一サーバーで共存させたい
* node + expres.jsで作ったアプリをPathで振り分けたい

## やりたいこと（例）
* `/` にアクセスするとnginxにアクセス
* `/apache/` にアクセスすると、apacheにアクセス
* `/express/` にアクセスすると、express.jsで動かしているアプリにアクセス

## やり方
* nginxのリバースプロキシを使おう

### インストール済
* nginx
* apache
* node.js + npm + express.js

それぞれ単体では動かせるのを前提にしています。

### 動作方法（例）
* apache
  * 8080 port で動作させる
* express.js
  * 3000 port で動作させる

### nginx.conf の設定

```nginx.conf
user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    server_tokens off;	

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile on;
	
	server {
		listen 80;
		server_name localhost;
		
		root html;
		index index.html;
		
		location /apache/ {
			proxy_pass http://localhost:8080/;
		}

		location /express/ {
			proxy_pass http://localhost:3000/;
		}
	}
}

```

### 起動
* `systemctl restart nginx.service`

* nginx
  * http://localhost/
* apache
  * http://localhost/apache/
* express.js 
  * https://localhost/express/

アクセスできることを確認 :thumbsup:
Flask + Mysql Insert文備忘録

MySQL-connectorを使ってInsert文を書いてみた。
formから持ってきた文字列を、そのままインサートすると上手く出来なかったので、対処法をメモ。

#　最初にやろうとしたこと。

テーブル設計はこんな感じ

```MySQL
+--------+---------------------+------+-----+---------+----------------+
| Field  | Type                | Null | Key | Default | Extra          |
+--------+---------------------+------+-----+---------+----------------+
| id     | int(10) unsigned    | NO   | MUL | NULL    | auto_increment |
| name   | varchar(255)        | NO   |     | NULL    |                |
| age    | tinyint(3) unsigned | NO   |     | NULL    |                |
| gender | varchar(10)         | NO   |     | NULL    |                |
+--------+---------------------+------+-----+---------+----------------+
```

このテーブルに対して、フォームから与えられた情報をインサートしようとした。

```python:
@app.route('/users/register', methods=["POST"])
def register():
	name = str(request.form.get('name'))      // yamada
	age = int(request.form.get('age'))        // 25
	gender = str(request.form.get('gender'))  // male


	cur.execute("INSERT INTO `users` (`id`, `name`, `age`, `gender`) VALUES (0, {name}, {age}, {gender});".format(name=name, age=age, gender=gender))
	conn.commit()
	return redirect(url_for('main'))
```

このときSQL文はこの様になる。

```sql
INSERT INTO `users` (`id`, `name`, `age`, `gender`) VALUES (0, yamada, 25, male}
```

しかし、文字列に対しては" "で囲って上げないといけないので、

```sql
INSERT INTO `users` (`id`, `name`, `age`, `gender`) VALUES (0, "yamada", 25, "male"}
```

## 従って、もとのインサート分はこうなる。

```python:
@app.route('/users/register', methods=["POST"])
def register():
	name = str(request.form.get('name'))      // yamada
	age = int(request.form.get('age'))        // 25
	gender = str(request.form.get('gender'))  // male


	cur.execute("INSERT INTO `users` (`id`, `name`, `age`, `gender`) VALUES (0, '{name}', {age}, '{gender}');".format(name=name, age=age, gender=gender))
	conn.commit()
	return redirect(url_for('main'))
```



## MySQL-connectorの使い方について紹介しているページ

●基本的なメソッド
[投資エンジニア](https://basicincome30.com/python3-mysql-connector#mysql_connector_python)

●fechの使い方
[Blow Up By Black Swan
](https://blowup-bbs.com/python-mysql-connector-python-fetchmethod/)
使いやすいインスタグラムのブログパーツ📷

# 作ったもの
[Insta Window Tool](https://insta-window-tool.web.app/)

こんな感じでインスタの写真をサイトに貼り付けられます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218/98dcfbc8-cd9e-fa7b-476c-e2ba11c6ceba.png" width="50%">

# 作った背景

インスタグラムの写真をサイトに貼る必要があったので調べたところ、ブログパーツは既にあったのですがブログパーツのサイトにリンクしてしまう残念仕様だったので自作しました。

# 技術スタック

- VueJs
- FirebaseHosting
- UIKit

くらいかな？

# 今後の予定

ブログパーツのサイズや色など設定できるようにしていくつもりです（いつか）

突貫で作ったものなのでキレイにしてくれたり機能追加してくれる方募集中です😉

なにかあれば[@kuronekopunk](https://twitter.com/kuronekopunk)へ💁‍♀️

※自ブログからの転載です
http://akinov.hatenablog.com/entry/2019/06/23/171234
BitriseとGitHub Organization

# はじめに
BitriseでGitHubのOrganizationを扱う時の流れです。
BitriseのFAQに[How to grant Bitrise access to a GitHub Organization?](https://devcenter.bitrise.io/faq/grant-access-to-github-organization/)というページがありますが、それを読んでも作業手順に戸惑った(英語恐怖症)のでスクショとともにまとめます。

# 手順
## 1.BitriseとGitHubの連携
BitriseにGitHubのアカウントを登録し、連携します。
連携できている場合、このようなチェックが入ります。
連携していない場合、ここから連携できます。
<img width="800" alt="スクリーンショット 2019-06-23 12.22.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356260/f2d7a9e1-4833-81f1-0b2d-9eed182d756b.png">

## 2.GitHubの設定
GitHubにログインし、`Authorized OAuth Apps`( https://github.com/settings/applications )にある`Bitrise`をクリックします。
<img width="994" alt="スクリーンショット 2019-06-23 12.21.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356260/7b284adf-56f8-b207-8046-b27816cb4ff3.png">
次に`Organization access`にあるOrganizationのアカウントの右側の`Grant`ボタンをポチります。するとパスワードの入力を促されます。
<img width="461" alt="スクリーンショット 2019-06-23 12.24.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356260/e2d5cb37-c646-08a2-31b1-85e13a53d62a.png">
成功するとこのようになります。
<img width="759" alt="スクリーンショット 2019-06-23 12.25.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356260/46c62c77-0836-3e83-3776-b4da82830fc7.png">

## 3.BitriseでOrganizationのリポジトリを選択
このようにBitriseで対象のリポジトリ選択時にGitHubのOrganizationのリポジトリが選択できるようになっていたらOKです。
<img width="1440" alt="スクリーンショット 2019-06-23 12.27.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356260/11d75717-dfdd-e4b7-2858-458d3384cf5e.png">

# 最後に
ついにBitrise User Groupが作成され、[Bitrise User Group Meetup #1](https://bitrise-japan.connpass.com/event/135945/)が開催されるようです！
LT枠で抽選に応募してみました。
当選したらいいなー。
vagrant box add centos/7 → SSL エラー

vagrant に [centos/7] (https://app.vagrantup.com/centos/boxes/7) を入れようと以下のコマンドを入力すると、エラーが出ます。

```
$ vagrant box add centos/7
The box 'centos/7' could not be found or could not be accessed in the remote catalog. If this is a private box on HashiCorp's Vagrant Cloud, please verify you're logged in via `vagrant login`. Also, please double-check the name. The expanded URL and error message are shown below:

URL: ["https://vagrantcloud.com/centos/7"]
Error: SSL certificate problem: self signed certificate in certificate chain
```

> ボックス 'centos / 7'が見つからないか、リモートカタログでアクセスできませんでした。 これがHashiCorpのVagrant Cloudのプライベートボックスの場合、あなたが `vagrant login`を通してログインしていることを確認してください。 また、名前を再確認してください。 展開されたURLとエラーメッセージを以下に示します。
URL：["https://vagrantcloud.com/centos/7"]
エラー：SSL証明書の問題：証明書チェーン内の自己署名証明書

[Vagrant Cloud] (https://app.vagrantup.com) のアカウントを作成して `vagrant login` してみましたが、同じエラーが出ます。困った。。

ググったところ、次の記事が見つかりました。
[vagrant up command throwing ssl error - Stack Overflow] (https://stackoverflow.com/questions/42718527/vagrant-up-command-throwing-ssl-error)

記事の通り `--insecure` を付けて入力すると、うまくいきました。

```
$ vagrant box add centos/7 --insecure
==> box: Loading metadata for box 'centos/7'
    box: URL: https://vagrantcloud.com/centos/7
This box can work with multiple providers! The providers that it can work with are listed below. Please review the list and choose the provider you will be working with.

1) hyperv
2) libvirt
3) virtualbox
4) vmware_desktop

Enter your choice: 
```
condaを黙らせる

### condaのサイレントモードの必要性
バッチファイルでインストールするときに[y/n]と入力する必要があると自動化の意味がありません。
そこで、[y/n]を尋ねないモード（キー入力の必要のないモード）のスイッチをさがしました。
https://stackoverflow.com/questions/34644612/conda-silently-installing-a-package
から引っぱると
```
-y
```
と入れるとキー入力なしで進みました。
gpsの研究　その54 & leafletを鍛える。その18

#概要

gpsを理解したかった。
nmeaをパースして、マーカーしてみた。

#写真

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/f825f7a2-1629-f2d0-b245-fe1cc3bebb98.png)

#成果物

https://embed.plnkr.co/eAfP1OUfKtjKQJHnatoY/

以上。
Pythonではじめる機械学習（5刷）に学ぶ

#目次
##1章はじめに
　機械学習、pythonについての説明。scikit-learnをなぜ使うかの説明。
　開発環境、実行環境について説明。
　自分は、Jupyter notebookを使うために、[Anaconda](https://www.anaconda.com/)をインストール。
　spyderで趣味程度のプログラミングをしたが、今回の学習においては、テキストにのっとってJupyter notebookを使うことに。

- 以下が実行環境。
 - matplotliv version:3.0.3
 - Numpy version:1.16.2
 - SciPy version;1.2.1
 - IPython version7.4.0
 - scikit-learn version:0.20.3


　pythonについては、昔Javaをしたことがあるので、コーディングについては何とかわかる。
　数学（行列、統計）についても、少し学生のときにかじったことがあるので、なんとかついていけそう。

#メモ
##p11 1.4.5 pandas In[6]:
display(data_pandas)
とコーディングしても、表が表示されない。

```python:
from IPython import display
display(data_pandas)
```

上記では、Ipython.display(data_pandas)として呼び出そうとしているが、これが間違っているみたい。正しくは、Ipython.display.display(data_pandas)なので、

```python:
import pandas as pd
from IPython.display import display
\# create a simple dataset of people
data = {'Name': ["John", "Anna", "Peter", "Linda"],
        'Location' : ["New York", "Paris", "Berlin", "London"],
        'Age' : [24, 13, 53, 33]
       }

data_pandas = pd.DataFrame(data)
display(data_pandas)
```
これで表示できる。

##p17 1.7.2 成功度合いの測定：訓練データとテストデータ
　・モデルを構築するのに使ったデータを、モデルの評価に使うことはできない。
　　モデルの性能を評価するには、ラベル（答え）を持つ新しいデータを使う必要がある。
　　モデルを構築するためのデータを訓練データ、評価するためのデータをテストデータという。
　　これらはデータセットから関数（train_test_split）から生成できる。
　　
##p20 1.7.4 最初のモデル「k-最近傍法」
データの一番近くにある点を、正解とするモデル。
kは、固定されたk個の近傍点（複数可）を用いることができる。

モデルの評価には、テストデータによる正解率（テスト精度）とモデルを作ったデータによる正解率（訓練精度）があり、この二つの精度が適当となるモデルが最適と判断される。

##2.1 クラス分類と回帰
　教師あり機械学習問題は以下の2つに分けられる。
　クラス分類（2つないしはそれ以上のクラスに分離）
　回帰（連続地の予測）

##p44 2.3.2.3 k-近傍回帰
Out[21]のコメントに「テストセットに対する精度」とあるが、正しくは「テストセットに対する**ターゲット**」ではないか。

##p46 線形モデル
回帰モデルを「予測されるレスポンスは、入力特徴量の重み付き和とバイアスの和」とするもの。
（複数の特徴量にそれぞれ重みをかけてその和（＋バイアス）が、レスポンスとなる）

##p50 2.3.3.3 リッジ回帰
線形モデルによる回帰の一つ。
係数（ω）の要素をなるべく小さくする。（特徴量が出力に与える影響をなるべく小さくしたい）boston_housingデータセットを用いる、とある。
```python:
X,y=mglearn.datasets.load_extended_boston()
```
Ridgeモデルのalphaパラメータで、特徴量の影響を調整できる。
**alphaが大きいほど、制約が大きくなる**（係数はゼロに近くなる）、
**alphaが小さいほど、制約が小さくなる**（係数への制約が小さくなり、係数は大きくなる）（alphaが0の時、線形モデルと同じ）

alphaの値と係数の大きさを比較すると、なるほどalphaが大きいほどそれぞれの要素に対する係数はゼロに近くなり、汎化が進む（可能性がある）。
alphaが小さいほど係数は大きくなる（ニアリー、線形モデル）⇒複雑なモデルに適合

今回のテストデータにおいては、（たまたま）alphaが小さいほうがモデルの精度は高い。
\#モデルによって、適切なalphaを求める（モデルを決める）ことが重要

##p53. 2.3.3.4 Lasso
Ridgeに代わる線形回帰。リック回帰と似ているが、いくつか複数の係数が**完全にゼロ**になる
⇒モデルのいくつかが完全に無視される⇒モデルが簡略化される。

##p56 2.3.3.5 クラス分類のための線形モデル
線形の２クラス分類器は、２つのクラスを直線や平面、超平面で分割する。
線形モデルは、以下の２つのアルゴリズムに区別される
-係数と切片の特定の組み合わせと訓練データの適合度を測る尺度
-正規化を行うか。行うならどの方法か。

一般的な線形クラス分類アルゴリズムは以下の２つ
-ロジスティック回帰
-線形サポートベクタマシン

上記の正規化の強度を決定するパラメータをCとすると、Cが大きくなると正規化が弱くなる（個々のデータに反応する）、Cが小さくなると正規化が強くなる（全体のデータを見る）

回帰の場合と同様に、線形モデルによるクラス分類は、低次元空間においては制約が強すぎるかもしれないが、高次元の場合には過剰適合を回避する方法が重要である。（Cをいい塩梅にする必要がある！？）

#取り組み
##6/10
Pythonをjupyter notebookで開始。1.4章まで写経完了。

##6/23
2.3.3.2　線形回帰まで完了
訓練データとテストデータとの違いや意味が分かってきた。モデル構築などをAPIに任せて、人間は最適な特徴や重みを見つけることが重要なのかな。

##6/30
p53. 2.3.3.4 Lasso
 線形
Laravel Mixでサブディレクトリを使用した際にURLを書き換える

## 症状
MAMPを使ってサブディレクトリでLaravelプロジェクトを動かしていた際に、URLにそこが反映されず404が出てしまっていた

## 原因
初期のnpm run dev/productionで書き換えられるURLにはサブドメインが考慮されていなかった

## 対処方法
webpack.config.jsに`mix.setResourceRoot('/subdomain/');`を追加

## 参考
https://github.com/JeffreyWay/laravel-mix/issues/1026
React Nativeを簡単に利用できるExpo Snackでスマホアプリを作ってみる

# React Nativeを簡単に利用できるExpo Snackでスマホアプリを作ってみる

日経ソフトウエア2019.7でReact Nativeを利用したスマホアプリ開発の記事がありましたので簡単に纏めてみます。


## React Native?
米Facebookが開発したスマホアプリ開発用フレームワーク。
JavascriptでAndroid,iOSアプリを同時に開発できる事から近年注目を集めている。
React Native は、Facebookが開発したWebアプリのJavascriptフレームワーク、Reactから派生したもの。
ネイティヴAPIは隠蔽されており、JSXと呼ばれるHTMLに似たタグを使ってWebページを記載するのと同じ感覚で画面表示を記載することが出来る。
React Nativeを使うことで、Javascriptで開発できる、Andoroid,iOSアプリの同時開発が出来るなどのメリットがあります。

## 開発環境

開発環境をしっかり整備しようとすると、Node.js,Python2, Android Studio, Xcode....などいくらかのソフトウェアをインストールせなければならず面倒です。
そこで、Expo SnackというWebサービスで提供される開発環境を利用することで簡単に開発環境を揃えることが出来ます。
Expo Snackは、Expoベースのアプリを作成して実行できるWebベースの開発環境です。
Expoというのは、React Nativeで利用頻度の高いネイティヴモジュールやビルドツールなどを纏めたソフトウェアです。
ただし、Expo Snackでは、Expoが用意するアプリのビルド機能は利用できない。つまり、スマホにインストールするための実行ファイルの生成ができない。
しかし、Webブラウザ上のエミュレータで即時実行する、またはスマホアプリのExpoをインストールすればスマホの実機で実行させることも可能。
つまり、React Nativeを利用した本格的な開発を行う場合はPCに開発環境を揃える必要があるが、試用などの目的であればExpo Snackの利用で十分なのである。

```
https://snack.expo.io/
```

<img width="1678" alt="スクリーンショット 2019-06-23 15.06.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275331/2c7af922-e011-7f5b-7238-594635aed6fd.png">


## アプリを実行する

Expo Snackにアクセスし、Expoアカウントを作成しログインします。
まずは、表示されているサンプルアプリをSaveし、実行してみます。
実行方法は2つあります。

1. Webブラウザ上のエミュレータで実行
2. スマホアプリのExpoまたはExpo Clientを利用して実行

1.の方法では、画面右側に表示される「Tap to Play」をクリックすることでWebブラウザ上のエミュレータを1ヶ月100分まで無料で利用できます。が、多くの場合リソースの順番待ちとなる事が多く、課金する事で順番待ちせずに実行させる事が可能です。

2.の方法は、スマホの実機にExpoまたはExpo Clientのアプリをインストールし、このアプリ上から実行させる。

## ファイル構成

|名前|説明| 
|-----------|------------|
|App.js|アプリのプログラム本体|
|package.json|パッケージ情報|
|assetsフォルダ|画像などのアセットファイル（リソースファイル）を格納する|
|componentsフォルダ|コンポーネントと呼ばれるスクリプトを格納する。デフォルトではAssetExapmple.jsというファイルが入っている|
|README.md|README|

### App.jsの構成

ソースコードに相当するApp.jsを整理すると、以下のような構成となっている。

```Javascript
export default class App extends React.Component {
  render() {
    return (表示内容);
  }
}

const styles = StyleSheet.create({
  スタイル設定
});
```

このAppクラスは、React.Componentクラスを継承している。React.Componentは、Reactのクラスである。つまり、ReactNativeは、Reactのシステムをそのまま利用している。
React.Componentは、renderメソッドを持っており、これは画面の表示を返すメソッドである。

```Javascript:App.js
export default class App extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.paragraph}>
          Change code in the editor and watch it change on your phone! Save to get a shareable url.
        </Text>
        <Card>
          <AssetExample />
        </Card>
      </View>
    );
  }
}
```

このメソッド内にはHTMLの様なタグが記載されているが、これがJSXタグである。
JSXはJavascriptの文法を拡張したものである。

styles変数の中には画面に表示するJSXタグで利用されるスタイルシートの情報を変数に纏めたものである。
ReactNativeではHTMLと異なるJSXタグを利用するが、スタイル設定はHTMLとほぼ同じ。
JavaScriptのsetTimeoutで指定できる時間には限界値があるって話

# setTimeoutの挙動がおかしい

`setTimeout`で指定した時間が経過したら、関数を発火させたいって話があったんすよ。(`setTimeout`なんだから当たり前感)
それで頼まれた通り実装したら、、、、なんやこれ、**引数によって挙動が違う**やんけ

#そのときの状況
○秒経過したら〜とか、○分経過したら〜とかそんな可愛らしいもんじゃなくて、**数日単位**で経過時間を指定してました。数が大きいものだと2週間とか1ヶ月とか。それに加えて`setTimeout`の引数ってミリ秒単位で指定しないといけないから**引数がでかいことでかいこと**。

#で、原因は引数が大きすぎたってこと
まんまやんけ！みたいなね、仕方ないじゃん、本当にそうなんだもん。
これは私の推測なんだけど、**setTimeoutの引数には32bit符号付き整数の最大値までしか設定できない**んだと思う。具体的な数字で表すと、**2,147,483,647**までです。実際、この21億なんちゃらまではきちんと動いていたものの、これよりたった1増えただけの2,147,483,648だとすぐおかしな挙動(=指定時間を経過していないのに発火)しだすもん。
##もう少し賢そうな感じで書くと
**桁あふれ**だっけ？多分その辺なんだと思う。1増えた瞬間いろいろ起きて2進数上の表記だと負の数になっちゃうみたいなやつ。その現象が起きてるから、引数に負の数が設定されたと思われる=すぐ発動しちゃうってことだったんだと思う。~~つーか誰か1人ぐらいこの話書いといてくれたっていいじゃんって思ったからワシが書く、手柄は自分のものにするスタイル~~

#余談
大学で数値計算の授業を受けていた時に、教授が散々この話をしていたな〜と思ってなんとなく実験したらビンゴ！
JSで扱える数値に関して詳しい方がいらっしゃったら教えてください。
JavaScriptで配列のfilterにasync関数を使いたい

表題の通りなんですが、JavaScriptで配列のfilterにasync関数を使う方法を調べていたところ、StackOverflowでカッコいい書き方を見つけたので紹介します。

## いつ必要なのか？

次のコードのように、`Array.prototype.filter(callback)` を使えば配列から特定の条件を満たす要素だけを抜き出すことができます。

```javascript
const arr = [1,2,3,4,5,6];
console.log(arr.filter(n => n % 2 == 0)); // [2,4,6]
```
このコールバック関数は配列の要素を受け取ってbooleanを返すような関数である必要があります。

ところが、このコールバックとしてasync関数を書きたいことがあります。つまり、返り値が `Promise<boolean>` である関数でfilterしたいというわけです。

そんなことあるのかって言われると困るんですが、先ほど人生で初めて必要になりました。

## スマートな解

私が良いと思った実装は次のようなものです（注：当初より随分シンプルになりました）。

```javascript
async function asyncFilter(array, asyncCallback) {
  const bits = await Promise.all(array.map(asyncCallback));
  return array.filter((_, i) => bits[i]);
}
```

この実装について解説します。

コールバック関数がasync関数なので、処理したい配列にいきなり`filter()`を適用するわけにいきません。そこでまず`map()`を適用してPromiseの配列にします。そして`Promise.all()`でbooleanの配列のPromiseにして、awaitで受ければPromiseがresolveされてbooleanの配列が得られます。

このbooleanの配列を`filter()`のコールバック関数で利用します。コールバック関数の第2引数は配列のindexなので、これを使って対応する真偽値を取り出します。（コメントいただいたttatsfさん、41semicolonさん、ありがとうございました！）

## 利用例

[Puppeteer](https://pptr.dev/)の`page.$$()`で取り出した要素のうち、viewport内に見えている要素だけを取り出したい場合、下記のように書けます。

```javascript
const errorBlocks = await my.page.$$('div.error').then(
  els => asyncFilter(els, el => el.isIntersectingViewport())
);
```

なかなか実用的ですね！

## 参考URL

- [javascript \- Filtering an array with a function that returns a promise \- Stack Overflow](https://stackoverflow.com/questions/33355528/filtering-an-array-with-a-function-that-returns-a-promise)
Nuxtの勉強としてタスク管理アプリを作ってみた

# Nuxtの勉強としてタスク管理アプリを作ってみた

VueやらNuxtやらが流行っている中で、一度も触ったことがなかったので、エンジニアとして置いて行かれるわけにはいかない！というわけでNuxtでタスク管理アプリを作ってみた。

[light_todo](https://spadeloves.github.io/lightTODO/)

正直まだまだ使えるものじゃいないと思います。。。
現時点ではローカルストレージにデータを保存するので、同一ブラウザのみでデータを保持できます。

Githubにソースを公開していますので、もし使っていただいて、「こう改善すべき！」みたいなご意見をいただけると嬉しいです！

[GitHub - spadeloves/lightTODO: easy todo app made with Nuxt.js](https://github.com/spadeloves/lightTODO)

## 機能のイメージ

イメージは[Todoist](https://todoist.com/app?lang=ja)と[Asana](https://asana.com/)の良いとこどりをしたようなものを想像してました。

- カテゴリ機能がある
- カテゴリにタスクを登録する
- カテゴリは以下の情報を持つ
  - カテゴリ名
  - 色
- タスクは以下の情報を持つ
  - タスク名
  - カテゴリ
  - タスク期日
  - メモ
  - コメント（複数登録可能）

最低限の機能として、上記を満たすTODOアプリをNuxtで開発しました。

## 画面のイメージ

画面イメージはFigmaで作成しました。

実際に作った画面イメージはこれ

![コンポーネントのイメージ](https://spadeloves.cf/wp-content/uploads/2019/06/Desktop.png)

左から

- カテゴリ一覧
- タスク一覧
- タスク詳細

といった感じ

## 実装の流れ

Nuxt（というよりVue）が初めてだったので、つまっては調べて、詰まっては調べてを繰り返しました。
Vueのコンポーネントを活用しようと思っていたのですが、実装しているうちにあまりコンポーネント化がうまく行かず…まだまだ勉強不足だなと感じました。

### コンポーネントのイメージ

実際の画面ベースで、どのようなコンポーネントに分けられているかを簡単に説明します。

こんな感じなコンポーネントで構成されています。

![コンポーネントのイメージ](https://spadeloves.cf/wp-content/uploads/2019/06/スクリーンショット-2019-06-23-15.26.41.png)


作っているときは、**再利用する可能性のあるものをコンポーネントとして分けよう**という考えで作っていました。
なので、タスクの完了を切り替えるチェックボックスや、追加フォームの表示を切り替えるトグルボタンをコンポーネントとして再利用できたのは良かったなと思いました。

### データの管理

#### JSONでのデータ管理
データはすべてJSONで管理しています。
JSはJSONが扱いやすいので良いかなと思いましたが、コードがかなり冗長になってしまった反省もありました。

例として、カテゴリの名前を表示する部分が

```vuejs
<p>
{{$store.state.todos.todoData[$store.state.todos.activeCategory-1].category_name}}
</p>
```

といった形になってしまい、可読性が低くなってしまい、データの構成に少しでも変更があるとかなり改修が必要になりそうです。

#### Vuexの利用

また、データはVuexを利用し、すべてのコンポーネント間で共通のデータを見ているので、実装がかなり簡単になりました。

チェックボックスでタスクの完了ステータスが更新
↓
タスク一覧側のチェックボックスにも反映
↓
タスク一覧から完了したタスクを削除

といった処理が、Vuexで**共通のストアのデータを見ているので、各コンポーネントで条件分岐を行っておけば、データの変更による表示更新が実装できる**のはとても良かったです。

### デザイン

デザインは専門ではないので、Bootstrapを利用しました。
グリッドデザインの勉強になったので良かったかと思っています。

## まとめ

モダンなJSによる開発を勉強したいと作成したタスク管理アプリですが、Nuxt（Vue）関連の基礎を学ぶのに効果的かなと思いました。
まだまだ勉強不足で、タスク管理アプリとして使えるものではないかと思いますが、少しずつ改善していこうと思います。
バッチ処理とcronの書き方について解説！


# はじめに
- バッチ処理とcronの書き方について本やネットの情報から調べて理解したことをまとめました。
- もし、書いていることに何か間違いがある場合はご指摘いただけると嬉しいです。

# バッチ処理とは
バッチ処理とは、一定の時間に対象のデータをまとめて処理することです。

## バッチ処理の具体例
- 毎朝今日の天気を知らせるメールを送る
- 毎日その日の終わりに売上の集計を行う
- 毎日決まった時間にTwitterでツイートする


## バッチ処理の流れ
大まかな流れは以下になります。

- 1.実行のタイミング
  - トリガー起動
     - 前提となる処理が完了したときに開始するもの 
  - 時間起動
     - 毎日0時や5分毎になど、決まった時間に開始するもの
- 2.処理の実行
- 3.バッチ処理終了時に成功、失敗のログを出力


# cronとは
- 定期的に自動で処理を実行させるプログラムです。
- 「1分毎に〇〇の処理を実行する」「毎日0時に〇〇の処理をする」など、設定した時間に自動でコマンドを実行することができます。

## cronの設定方法
「crontabコマンド」を使って、cronに実行したいコマンドを設定することができます。

crontabコマンドの書き方は以下になります。

```
crontab　[オプション]
```

オプションの設定は以下になります。

- `-e`：cron設定を編集・登録
- `-l`：cronの設定を表示
- `-r`：cron設定を削除
- `-u`：cronを設定するユーザーを指定


## cronの書き方

- `crontab -e`でcronを設定、編集することができます。
- 実行時間は、左から分・時・日・月・曜日を指定します。また、それぞれに半角スペースを空けます。

```
分 時 日 月 曜日  [コマンド/プログラムファイル名]
```

設定は以下のようになります。

- `分`：0~59で設定
- `時`：0~23で設定
- `日`：1~31で設定
- `月`：1~12で設定。または jan〜dec
- `曜日`：0~7で設定。0=日曜,1=月曜,2=火曜,3=水曜,4=木曜,5=金曜,6=土曜,7=日曜。または sun〜sat
- `,`：分,時,日を複数で指定
- `–`：分,時,日を範囲で指定
- `/`：分,時,日を間隔で指定
- `*`：「全て」を表します


## cronのコード例
cronで以下のような処理を実行させるプログラムを書きます。

### 処理の内容

- 一分毎に`こんにちは`という文字列を`text.txt`ファイルに書き込んでいくプログラム

### 準備
以下の設定で進めていきます。
#### 開発環境
- Mac 
- MAMP

#### ファイルの構造

```
- MAMP/htdocs/cron
 - cron.php
 - text.txt
```

### cron.php
- 文字列をファイルに書き込む`file_put_contents関数`を使っていきます。
- cronで処理を実行する場合、ファイルパスは`絶対パス`で記述する必要があります。

```php:cron.php
<?php

$file = "/Applications/MAMP/htdocs/cron/text.txt";
$text = "こんにちは" . "\n";

file_put_contents($file, $text, FILE_APPEND); 
```
### cronの設定

ターミナルで`crontab -e` コマンドを入力すると、viが立ち上がると思うので、cronを設定します。
パスは`絶対パス`で記述する必要があります。

```linux:cronを設定
*/1 * * * * /usr/bin/php /Applications/MAMP/htdocs/cron/cron.php
```

### 実行結果
一分毎に`こんにちは`という文字列が書き込まれていきます。

```text:text.txt
こんにちは
こんにちは
こんにちは
こんにちは
```
multiprocessingでnumpy配列を扱うためのメモ

multiprocessingで生成したプロセス同士で変数を共有するには共有メモリを生成する必要があります。生成した共有メモリとnumpy配列のデータを相互に変換する方法がわからなかったのでここにメモしておきます。

共有メモリを生成する方法はいくつかありますが、ここではmultiprocessingのValueクラスを使用します。Valueクラスはctypesオブジェクトの同期ラッパーです。つまりnumpy配列とctypes配列の相互変換ができれば、今回やろうとしていることが実現できます。

numpy配列とctypes配列の相互変換についてはこちら
https://qiita.com/maiueo/items/493d321f0c9a804b3672

# ライブラリの読み込み
```python
import ctypes
import numpy as np
import multiprocessing as mp
```

# ndarray -> Value
```python
n = np.zeros((3, 4)).astype(np.uint8)  # ndarray型の3x4の配列を生成
n_w, n_h = n.shape  # nのサイズを取得
v = mp.Value((ctypes.c_uint8 * n_h) * n_w)  # nと同じサイズのctypesの配列を共有メモリに生成
v_c = v.get_obj()  # 生成したctypesオブジェクトを取得
v_n = np.ctypeslib.as_array(v_c)  # 生成したctypesオブジェクトを参照したndarrayを生成
v_n[:] = n  # nから値をコピー(v_nのインスタンスはそのまま)
```
**np.uint8, ctypes.c_uint8の部分は配列に用いる型の指定**
`n`と`v`はそれぞれ別のアドレスを参照しているので、片方を書き換えても、もう片方には書き換えは反映されません。
同じアドレスを参照させる方法もあるかもしれませんが、見つけることができませんでした。

# Value -> ndarray
```python
v = mp.Value((ctypes.c_uint8 * 4) * 3)  # ctypesの3x4の配列を共有メモリに生成
v_c = v.get_obj()  # 生成したctypesオブジェクトを取得
n = np.ctypeslib.as_array(v_c)  # 生成したctypesオブジェクトを参照したndarrayを生成
```

**ctypes.c_uint8の部分は配列に用いる型の指定**
`v`と`n`はともに同じアドレスを参照しているので、片方を書き換えるともう片方にも書き換えが反映されます。

# サンプル1
cv2で読み込んだ画像(ndarray型)をValueクラスに変換し、それをまたndarray型に戻すプログラムです。
画像ファイルのパスの箇所を適宜変更してください。

```python
import ctypes
import numpy as np
import multiprocessing as mp
import cv2

def valueToNdarray(v):
	return np.ctypeslib.as_array(v.get_obj())  # Valueからndarrayに変換

def ndarrayToValue(n):
	n_h, n_w, n_ch = n.shape  # サイズ、チャンネル数を取得
	v = mp.Value(((ctypes.c_uint8 * n_ch) * n_w) * n_h)  # 同サイズ、同チャンネル数の共有メモリを生成
	valueToNdarray(v)[:] = n  # コピー
	return v

if __name__ == '__main__':
	# 適当な画像からndarrayの生成
	input_img = cv2.imread("画像ファイルのパス")

	# Valueに変換
	v = ndarrayToValue(input_img)

	# ndarrayに変換
	output_img = valueToNdarray(v)

	# プレビュー
	cv2.imshow("input", input_img)
	cv2.imshow("output", output_img)
	cv2.waitKey(0)
```

# サンプル2
cv2で読み込んだ画像(ndarray型)に別プロセスでフィルターをかけるプログラムです。
読み込んだ画像を45度回転します。
画像ファイルのパスの箇所を適宜変更してください。

```python
import ctypes
import numpy as np
import multiprocessing as mp
import cv2

def valueToNdarray(v):
	return np.ctypeslib.as_array(v.get_obj())  # Valueからndarrayに変換

def ndarrayToValue(n):
	n_h, n_w, n_ch = n.shape  # サイズ、チャンネル数を取得
	v = mp.Value(((ctypes.c_uint8 * n_ch) * n_w) * n_h)  # 同サイズ、同チャンネル数の共有メモリを生成
	valueToNdarray(v)[:] = n  # コピー
	return v

def filter(v):
	n = valueToNdarray(v)  # Valueからndarrayに変換
	n_h, n_w, n_ch = n.shape  # 画像サイズ、チャンネル数の取得
	M = cv2.getRotationMatrix2D((n_w / 2, n_h / 2), 45, 1)  # 画像の中心を軸に45度回転する行列を求める
	n[:] = cv2.warpAffine(n, M, (n_w, n_h))  # 生成した行列で画像を回転させる

if __name__ == '__main__':
	# 適当な画像からndarrayの生成
	input_img = cv2.imread("画像ファイルのパス")

	# Valueに変換
	v = ndarrayToValue(input_img)

	# 画像を45度回転するプロセスを生成
	p = mp.Process(target = filter, args = (v, ))
	p.start()  # プロセスの開始
	p.join()  # プロセスの終了待機

	# 処理結果をndarrayに変換
	output_img = valueToNdarray(v)

	# プレビュー
	cv2.imshow("input", input_img)
	cv2.imshow("output", output_img)
	cv2.waitKey(0)
```

# 参考
https://docs.python.org/ja/3/library/multiprocessing.html#multiprocessing.Value
https://codeday.me/jp/qa/20181210/61068.html
[Linux][Mac]cpで階層構造を保ったままコピーしたい

## したいこと
`/etc/nginx/nginx.conf` を `./etc/nginx/nginx.conf` にコピーしたい

またこのとき `./etc` も `./etc/nginx` もそれぞれ存在しなかったとしてもいい感じにディレクトリを作ってコピーしてきたいとします。

## どうするか
### Linux 環境
```
cp --parents -v /etc/nginx/nginx.conf ./
# つまり
cp --parents -v ${コピーしたい元ファイルのフルパス} ${コピー先のディレクトリ}
```
とすることで階層構造を持ったままコピー出来るようです。

ただし、Mac の cp コマンドではこのオプションは存在しませんでした。ではどうするのか

### Mac 環境
```
rsync -R /etc/nginx/nginx.conf ./
# つまり
rsync -R ${コピーしたい元ファイルのフルパス} ${コピー先のディレクトリ}
```

`rsync -R` を使うことで出来るようです。

## まとめ
`rsync -R` であればどちらでも使えそうなのでこれを使うのが良さそうですね。
初めてのDockerHubにイメージPush

DockerHubにイメージをPushする方法です。
Dockerを普段あまり触らないので面倒で敬遠していたのですが、必要に迫られ使ってみました。

# 環境と前提
Docker CEインストール済

|種類|バージョン|内容|
|:--|:--|:--|
|OS|Ubuntu18.04.1 LTS|仮想で動かしています|
|Docker|Community Edition 18.09.6|2019/6/21時点で最新|

# 手順
## 1. ユーザ登録 
[Sign upページ](https://hub.docker.com/signup?next=%2F%3Fref%3Dlogin)からユーザ登録

## 2. リポジトリ登録
["Create a Repository"](https://cloud.docker.com/repository/create)ボタンを押してリポジトリ登録。
"test-image"というリポジトリ名を入力して、「Public」に設定します。

##3. Dockerfile作成
適当にDockerfileを作成します。

```Dockerfile
FROM ubuntu:18.04
MAINTAINER Admin <admin@admin.com>
# RUN: docker buildするときに実行される
RUN echo "now building..."
# CMD: docker runするときに実行される
CMD echo "now running..."
```

ローカルでイメージをBuildします。

```bash
docker build --tag=yoheifukuhara/test-image .
```

## 4. DockerHubログイン
"docker login"と打ったあとに、ユーザ名とパスワードを入力してDockerHubにログインします。

```bash
docker login
```

## 5. Docker イメージPush
あとはpushするとDoucker Hubでイメージが更新されます。

```bash
docker push yoheifukuhara/test-image
```
APIのバージョン管理について悩んで考えたことを共有します。

自社のECサイトからアクセスされるAPIのバージョンの管理についていろいろ調べて悩んだので共有します。


課題:
自社ECサイトのAPIとフロントエンドアプリケーションのリリースと切り戻しを独立させたい
(APIは社内のフロントエンドアプリケーションからしか利用されていません。)

状況:
・バックエンドのAPIはフロンドエンドのアプリケーションからのみ参照されていてそれ以外はない。
・現状はリリースする際に、フロントエンドとバックエンドのリリースタイミングを調整してリリースしている。
・apiを先にリリースしなければならないのはしかたないが、切り戻しが必要になった時などにフロントだけ切り戻せばすむようにしたい。
  ->下位互換でapiをつくればいいが、すぐに不要になる下位互換性のためにどんどんコードがよごれていくのはいや。
  ->リリース終わってしばらくしたら、下位互換のコードを削除というのもまたテスト必要になって不便。

ということでうまいことバージョンを管理したい。

解決方法案:
1. 下位互換がある形でつくる。リリースしてしばらくしたら、下位互換のためのコードを削除
    下位互換でつくったものを技術負債を解消するために後から下位互換のためのコードを削除するというのは
    テストも含めて手間。多分放置される。
2. URLにバージョンを付加し、互換性のない変更がある場合はバージョンをあげていく
    https://api.company.com/v1/users/1
    良さそう。
3. ヘッダーにバージョンを付加する
    既存のヘッダーにバージョンが付加されていないものはどうするか?という問題がある。
    バージョンがない場合は最新のバージョンと判断するということもできるがそれだと、api側でーバージョンをあげた場合に
    バージョン指定がないリクエストはフロント側でも急にバージョンがあがってしまうのでよくない。

解決方法案3つ検討しましたがどうやら2のURLにバージョンを付加するというのが一番良さそうな気がします。
ここからは2の選択肢について検討したことを見ていきます。

・ バージョン毎にコントローラを作成するのか?
  API::V2::UsersController などのようにバージョン毎にコントローラを作成するのが正しいような気もします。
  ただ現状だと古いバージョンはなる早で消していき古いコントローラもすぐに消してしまうと思うので今回の場合はコントローラは一つで良いと判断しました。
・ ルートによってバージョンがv1だったりv2だったりしたらごちゃごちゃしてわかりにくいのでは?
   フロントチームが開発をするときやテスト用にURLをブックマークしていたりする他のapi開発者とかもバージョンが変わることで
   混乱する可能性はあります。がしかし、コードに互換性を持たせたりそれを削除したりするストレスや手間に比べればたまにurlがわからないくらい
   大したことではないでしょう。と判断しました。swaggerやエラーメッセージの利用でなるべくこの辺は改善するようにしましょう。

ということで今回は以下の方針でいくことにしました。

1. 互換性のない変更はURLにバージョンを付加する。
2. バージョン毎にコントローラをつくったりはしない。すぐ削除するので。

みなさんの参考になれば幸いです。
助言あればぜひお願いします。
Ruby on Rails [学習記録-第15章-] Mechanizeの整理

#Mechanize
* Mechanizeはスクレイピングを行うためのGem。
* MechanizeのGemを入れるとMechanizeクラスが使えるようになる。
* このMechanizeクラスにはスクレイピングをするための様々なメソッドが用意されている。

```bash:Gemfile
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.5.1'

~中略~

gem 'Mechanize'
```
* Gemをインストールするために、`bundle install`をする。

```bash:
$ bundle install
```
* まずMechanizeクラスのインスタンスを生成します。

```rb:
agent = Mechanize.new # Mechanizeクラスのインスタンスを生成
```
#getメソッド

* getメソッドはMechanizeクラスのインスタンスメソッド。
* get("スクレイピングしたいウェブサイトのURL")と引数にURLの文字列を指定することで、そのURLのウェブサイトのHTMLを取得する。

```rb:
agent = Mechanize.new
page = agent.get("http://review-movie.herokuapp.com/") # HTMLを取得
puts elements
```
* 出力結果は以下のようになる。
* ここで取得できたpageは単なるHTMLの文字列ではなくそのウェブサイトのHTMLの情報を持った**Mechanize::Pageオブジェクト**。

```rb:
puts page
# <Mechanize::Page:0x007fcdda803dd8>
```


#searchメソッド
* searchメソッドはgetメソッドで取得したページの情報が入ったオブジェクトに対して使用。
* これにより取得したウェブサイトのHTML情報の中から指定したHTML要素の内容を検索できる。
* 該当するHTMLのタグ要素が1つでも、返り値は配列の形式で返ってきくる。

```rb:
elements = Mechanize::Pageオブジェクト.search('セレクタ')
```
```rb:
agent = Mechanize.new　#Mechanizeクラスの作成
page = agent.get("http://review-movie.herokuapp.com/")　#getメソッドでMechanize::Pageオブジェクトを取得
elements = page.search('h2')　#searchメソッドでh2要素のHTMLの情報が取得
```
```html:
<h2 class="entry-title index-entry-title">
<a href="/products/1" title="Single Post">あのひと</a>
</h2>

<h2 class="entry-title index-entry-title">
<a href="/products/2" title="Single Post">海よりもまだ深く</a>
</h2>

<h2 class="entry-title index-entry-title">
<a href="/products/3" title="Single Post">ディストラクション・ベイビーズ</a>
</h2>
```

#inner_textメソッド
* searchメソッドで得られたHTML情報のテキストを取得したい場合、inner_textメソッドを使用する。

```rb:
agent = Mechanize.new
page = agent.get("http://review-movie.herokuapp.com/")
elements = page.search('h2 a') # h2要素の下のa要素を検索

elements.each do |ele|
  puts ele.inner_text
end
```
```rb:
あのひと
海よりもまだ深く
ディストラクション・ベイビーズ
少女椿
```
#get_attributeメソッド
* aタグ要素のHTMLはリンク先のURLを値とする属性hrefを持っている。
* このようなHTMLの属性の値を取得したい場合、get_attributeメソッドを使う。
* 同様にget_attributeメソッドを当てると以下のようになる。

```rb:
agent = Mechanize.new
page = agent.get("ttp://review-movie.herokuapp.com/")
elements = page.search('h2 a') # h2要素の下のa要素を検索

elements.each do |ele|
  puts ele.get_attribute('href') # puts ele[:href]としても良い
end
```
```
/products/1
/products/2
/products/3
/products/4
```

#atメソッド
* searchメソッドは該当要素全てを取得するのに対して、atメソッドは該当1件のみを取得。


#スクレイピングの流れ
* Mechanizeクラスのインスタンスを生成。
* Mechanizeクラスのインスタンスメソッドget(情報を取得したいウェブサイトのURL)で、ウェブサイトのHTML情報を取得。
* 欲しいデータのあるタグ要素をsearchメソッドで指定して取得。
* 取得したタグ要素のHTML情報にたいしてinner_textメソッド、またはget_attributeメソッドを使って欲しい値を取得。
AWS EFSの設定とマウント

## やりたいこと

* EFSの作成
* EC2インスタンスにEFSをマウントしたい
* EC2が起動した際に自動でEFSにマウントさせたい

### EFSの作成

* VPCの設定
* 使用するアベイラビリティーゾーン
  * 使用するインスタンスの場所に割り振りしておけばOK
* セキュリティグループの指定
  * 複数のインスタンスで使用するので共通のセキュリティグループに設定を合わせた

![キャプチャ2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181414/1d452668-3d16-f773-a928-db173752453b.png)

**次のステップへ**

* 設定は基本デフォルトで、タグだけ編集(後で整理する時に便利)

![キャプチャ3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181414/f689a4a7-3b77-9ddd-2906-c20db2a61acd.png)

**次のステップへ**

* 設定を確認したら「ファイルシステムの作成」へ

![キャプチャ4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181414/8af0d31b-7178-70c5-e533-207327509ea5.png)

* ファイルシステムの作成が完了したら「ファイルシステムID」を記録しておくこと(後で使う)

![キャプチャ1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181414/b48449a5-7f6c-b265-9c5b-d52b10d105a9.png)

###  EC2インスタンスにEFSをマウント

* ファイルシステムをEC2マウントする

```
sudo mount -t efs -o tls (ファイルシステムID):/ efs
```

* dfコマンドでマウントされる事を確認する

```
[ec2-user@***** ~]$ df -h
Filesystem                                 Size  Used Avail 
(ファイルシステムID).efs.us-east-2.amazonaws.com:/  8.0E     0  8.0E   0% /mnt/efs
```

この状態だと再起動したらマウントが解除されてしまうので、自動でマウントされるように設定をする。

### EC2が起動した際に自動でEFSにマウントさせたい

* マウント設定が記載されている"/etc/fstab"ファイルを編集するが、まずはバックアップを取る

```
sudo cp /etc/fstab /etc/fstab.backup
```

* "/etc/fstab"に下記の通り記載する

```
(ファイルシステムID):/                                 /mnt/efs    efs    defaults,_netdev  0   0
```

**再起動してマウントされていればOK!!**
AWS RDSを外部接続可能にする手順

# 前書き

検証のため開発環境RDSを端末から繋ぎたいということがある。
（通常はproxy経由で接続してもらったりしているのだが、それもできない場合）
その時の設定手順とハマるポイントをまとめたので記載します。

# 設定手順

今回はDBのクローンで作ります

- クローンの作成を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276477/9cc000ab-619a-46d5-3525-458589670a98.png)

- ネットワーク&セキュリティを設定
サブネットグループ: publicアクセス可能なものを選択
パブリックアクセシビリティ: `はい`を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276477/1d16c8fd-fd33-1d8d-081d-6d82ff2e777d.png)

- セキュリティグループ
インバウンドで3306ポート（MySQLなら）を接続可能にしたセキュリティグループを設定します
この時ソースを`0.0.0.0/0`にすることは絶対にやめましょう
信頼できるIPからのみ接続可能にしてください

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276477/c4be0ef2-c473-df94-ef8a-ab302f3d4f87.png)

# 確認

- digコマンドでRDSのエンドポイントにGIPが設定されていることを確認しましょう

```
dig hogehoge.rds.amazonaws.com
```

- MySQL接続確認

```
mysql -hhogehoge.rds.amazonaws.com -uhogehoge -ppassword
```

期待通り接続できればOKです。

もし、Timeoutするような(遅くても10秒以上接続にかかる)反応が見えた場合はルーティング周りの設定を疑って見てください。すぐに応答があればセキュリティグループやmysqlコマンド周りを疑ってみてください。

### ハマりポイント
サブネットグループはpublicアクセス可能なものを選択しましょう
具体的にはVPCのサブネットでインターネットゲートウェイをルートテーブルの関連付けに設定しているものを作ります
※グループを作るので最低２つ必要です

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276477/558b2e99-4a2b-bdc7-96f3-7da0fe7b597f.png)

RDSのサブネットグループで作成したサブネットでDBサブネットグループを作成します
これを`ネットワーク&セキュリティを設定`で選択します

# あとがき
今回開発環境DBを一時的に設定しましたが、もし本番環境DBもやるとなると暗号化とかIAMとかしっかり設計しないといけないと思います。この手順はセキュリティという面では不足しているのでそれを理解した上で利用してください。
BCDのマイナスを克服する方法

はじめまして。りかけいのしゃちくです。
仕事でつまづいたりしたところを忘備録がてら公開していこうと思います。

今回投稿する内容はBCDの桁下がりを克服する方法です。
そもそもBCDとは？という方は下記のサイトを参考にしてください。

[シーケンス制御講座「BCD出力」] (https://news.aperza.jp/%E3%82%B7%E3%83%BC%E3%82%B1%E3%83%B3%E3%82%B9%E5%88%B6%E5%BE%A1%E8%AC%9B%E5%BA%A7%E3%80%8Cbcd%E5%87%BA%E5%8A%9B%E3%80%8D/)

ふつうのプログラミングではあまり使いませんが、PLCをつかった制御だとごく普通に使います。上記サイトを見ていただくとわかりますが、BCDは4bitごとに区切って数字を表現する方法です。表現できる桁数は0～ビット数/4(32bitなら8桁)です。
例えば下記の計算

0001 0011(12 BCD)-1000 1000(88 BCD)

について単純に計算すると答えは1000 1011(8BHex)となります。これをBCD変換しても本来欲しい-76BCDにはなりません。

PLCによってはキャリー付きBCD減算(CY付BCD-)の機能がありますが、ない場合もあります。
下のコード例はCY付BCD-がなくて、反復してBCD減算を行う場合に使用できます。

```ruby:qiita.rb
for i:=0 to hoge 

    if(BCD1[i] > BCD2[i]) then
        BCD減算命令(BCD1[i], BCD2[i], bcdsub); /*減算命令はメーカーによって違う*/  
    else
        BCD減算命令(BCD2[i], BCD1[i], bcdsub);
        Cyflag := true; /*キャリーフラグ*/
    end_if

    result[i] := bcdsub;

end_for
```

減算命令の前に2値の大小を比較して-を出さないように計算した後キャリーフラグを付けるという簡単なものです。
ローカル変数・インスタンス変数・クラス変数の違い(Ruby)

各変数の使い方が分からなかったので備忘録として記します。
間違い等ありましたら、コメントいただけると嬉しいです！

# ローカル変数
ローカル変数は、使用できる範囲(スコープ)が他の変数よりも限られている。
メソッドやブロック内で変数を定義した場合は、そのメソッドやブロック内で有効となる。
定義は、メソッド、ブロック内外で可能。
~~メソッド内(ブロック内)で使用できる変数。~~

```ruby:ローカル変数
 class Person
  def greeting(name)
    personal_name = name  　　　　　　　　   ←ローカル変数の定義
    "My name is #{personal_name}"
  end
 end
 
 person = Person.new('Taro')
 person.greeting  
 #=> "My name is Taro" 
```
**注意点：　メソッド内でローカル変数を定義した場合は、そのメソッド内で=を使用して引数を代入しないと、エラーが帰ってくる。(下記のような感じ！)**

```ruby:error-example
 class Person
   def initialize(name)
     personal_name = name
   end

   def greeting
     "My name is #{personal_name}"
   end
 end

 person = Person.new('Taro')
 person.greeting
 #=> Name error: undefined local variable or method "personal_name"・・・・
```

#インスタンス変数
同じオブジェクト内(同クラス内)で共有可能な変数のこと
**変数名に「@」をつける**

```ruby:インスタンス変数
 class Person
   def initialize(name)
     @personal_name = name 　　　　　　　　←インスタンス変数の定義
   end

   def greeting
     "My name is #{@personal_name}"
   end
 end
 person = Person.new('Taro')
 person.greeting  
 #=> "My name is Taro" 
```

#クラス変数
同じクラス内の全てのインスタンスメソッド内や継承されたクラス内(そのインスタンスメソッド内)で使用できる変数
**変数名に「@@」をつける**

```ruby:クラス変数
 class Person                           
   @@personal_name = 'Taro'　　　　　　　　　　　　←クラス変数の定義

   def greeting
     @@personal_name
   end
 end

 class Personname < Person
   def name
     @@personal_name
   end
 end

 person = Person.new
 personname = Personname.new

 person.greeting  
 #=> "Taro" 
 
 personname.name
 #=> "Taro" 
```
ファジィと確率の違い（サイコロの場合）

# ファジィと確率の違い
確率は結果に**客観性がある事象**。
ファジィは結果に**主観性がある事象**。


## これが確率の世界で扱うサイコロ。
<img width="375" alt="PNGイメージ.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310125/ccebee48-5d5e-1367-1ef6-8f56328f7317.png">

六面体になっていて、どの目が上を向いているか**客観的に明らか**なサイコロ。このサイコロの出目を表現するのが確率論。

## これがファジィの世界で扱うサイコロ
<img width="375" alt="PNGイメージ 2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310125/236990ac-9f70-ef9e-29d4-322e06bc7681.png">

球体になっていて、どの目が上を向いているか**主観的に決められる**サイコロ。このサイコロの出目を表現するのがファジィ理論。

### 聞きかじった内容を自分なりに理解した図式ですので、詳しい方はご指摘ください。
linux でユーザー名とグループ名が同じなのはなぜ？

# はじめに
linux で、ユーザーアカウントを作成すると、デフォルトでは同じ名前のグループが作成され、そのグループに所属します。
以前は、みんな users グループに所属したものです。
なぜでしょう？

# 結論
以前と違って、最近は同じファイルをグループみんなで編集することが増えたからです。
以前は、`umask 022`と設定することが一般的でしたが、今は `umask 002` と設定されることが多くなりました。

# umask とは
`umask`とは、ファイルやディレクトリを作成したときのデフォルトのアクセス権を設定するコマンドです。
詳細は[ググって](https://www.google.co.jp/search?q=umask&oq=umask&aqs=chrome..69i57j0l5.3044j0j7&sourceid=chrome&ie=UTF-8)もらうとして、`umask 002`と設定すると、`umask 022`と設定した時に比べて、グループの書き込み権限がプラスして付与されます。
グループにデフォルトで書き込み権限を付与することで、アクセス権を変更し忘れてグループの他のメンバーが書き込めない ;_; という事態を回避したのです。

# セキュリティは？
デフォルトでグループへの書き込みを許可すると、セキュリティが心配になります。
そこで、グループは、デフォルトでユーザー名と同じグループを作成し、所属するようにしました。

# グループでの書き込みがしたくなったら？
ユーザーは、複数のグループに所属することができます。グループによる管理が必要になったら、`groupadd` コマンドでグループを作成して、作成したグループにユーザーを追加すればよいです。`umask 002` により、ファイルやディレクトリには、元からグループへの書き込み権が設定されています。あとは所有グループを、作成したグループに変えるだけで、グループでの書き込みができるようになります。

# つまり違いは？
グループによるアクセス権の設定が、柔軟にできます。
所属グループが変更になった場合にも対処できます。

# どこで設定されているの？
/etc/bashrc に、以下の記述があります。

```shell:/etc/bashrc
    if [ $UID -gt 199 ] && [ "`/usr/bin/id -gn`" = "`/usr/bin/id -un`" ]; then
       umask 002
    else
       umask 022
    fi
```

ユーザーID が 200 以上で、ユーザー名とグループ名が同じユーザーは、umask が 002 になります。

# まとめ
RHEL 的には、[ユーザープライベートグループ](http://web.mit.edu/rhel-doc/4/RH-DOCS/rhel-rg-ja-4/s1-users-groups-private-groups.html) というようです。

疑問に思ってた方の参考になれば幸いです。
機械学習論文読みメモ_166

[Semantic Visual Localization](https://arxiv.org/abs/1712.05773)
三次元幾何及びセマンティクス理解のための新手法を提案する。
この手法はdescriptorを生成モデルとして 学習させる。
この学習時には、semantic scene completionをauxiliary taskとして学習させる。
semantic scene completionは不完全なsemantic segmentationが与えられた際に、
それを補完するようなタスクでautoencoderベースの手法で実現する。
学習されたdescriptorは観測できなかった部分がある対象に対してロバストである

[Context Encoding for Semantic Segmentation](https://arxiv.org/abs/1803.08904)
dliated/atrous convolutionの利用により、マルチスケールの特徴、セマンティクスを得る事は
pixelwise labeling taskにおいて効果を発揮してきた。
本論では、新たにsemantic contextを捉える事が可能なcontext encoding moduleを提案する。
提案するネットワークはCNNで抽出される各ステージの特徴を元に、
クラス毎のそれに依存する特徴をscale factorと共に抽出するよう学習される。

[Low-Latency Video Semantic Segmentation](https://arxiv.org/abs/1804.00389)
video入力に対するリアルタイムなsemantic segmentationを行うことは難しい。
この問題に対し、提案するフレームワークは以下の特徴を持つ。
1つ目に、時間方向への特徴伝搬モジュールを持たせることでフレーム毎の計算量を低減した。
２つ目に、予測精度に応じて計算リソースを動的に割り当てを行う。
事前調査（社会調査法）仮説（155）

社会事象を調査する場合には、
調査する行為自体が、調査対象に影響を与えることを
調査する前に確認しているとよい。

調査したことによって起きた事象か、
調査しなくても起きた事象かの識別方法を確立している必要がある。

量子力学で、粒子性と波動性が、測定方法でどちらかしか確認できないか、
両方確認できるかの違い。

測定行為によって、測定時点の位置はわかっても、測定前の位置と速度、測定後の位置と速度はわからないかもしれない。

#事例
読書メーター
https://bookmeter.com/users/121023

読書メーターは、http://amazon.co.jpのようにシステム側が勝手に感想を削除することはない。
読書メーターは、http:://booklog.jpのように登録のない書籍の追加が有料ではない。
また、利用者間の情報交換の場を設けている。

読書メーターは、数年前まで、いいねの数、友達の数でランキングをつけていた。
そのため、内容を読まずにいいねを押す人や、相手のことを理解しようとせずに友達登録する

### 最後までおよみいただきありがとうございました。

いいね　💚、フォローをお願いします。

#### Thank you very much for reading to the last sentence.

Please press the like icon 💚　and follow me for your happy life.
双击事件-- 显示信息详情

- 做一个显示详情的窗口

```teacherList.html
<!-- 弹出详情窗口 -->
	<div id="detail"  class="easyui-window" title="企业详情" >
		<table border="1px" bordercolor="#000000" width="100%" hight="100%" 
		cellspacing="0px" style="border-collapse:collapse">
								
			<tr>
				<td>登录名</td>
				<td id="desc_tid"></td>
			</tr>
		
		<tr>
			<td>密码</td>
			<td id="desc_tpwd"></td>
		</tr>
		<tr>
			<td>老师姓名</td>
			<td id="desc_tname"></td>
		</tr>
		<tr>
			<td>性别</td>
			<td id="desc_tgender"></td>
		</tr>
		<tr>
			<td>年龄</td>
			<td id="desc_tage"></td>
		</tr>
		<tr>
			<td>电话</td>
			<td id="desc_ttel"></td>
		</tr>
		<tr>
			<td>老师地址</td>
			<td id="desc_taddress"></td>
		</tr>
		 <tr>
			<td>班级</td>
			<td id="desc_tclass"></td>
		</tr> 
		<tr>
			<td>状态</td>
			<td id="desc_tstatus"></td>
		</tr>
		
		
		</table>
	
	
	
	
	
	
	</div>
```

- 设定一下这个详情窗口 在js代码中，$(function(){  中})

```teacherList.html
$(function() {	
		//详情页面
		
		$("#detail").window({
			
			minimizable:false,
			width:600,
			height:400,
			modal:true,//模态化
			iconCls:'icon-large-clipart',
			//关闭状态么？ 是的。 
			closed:true		
			
		});	
```



- 在datagrid 初始化中 

```teacherList.html
  //详情页面 
	        onDblClickRow:function(index,Teacher){
//设置老师的显示值。
	        	var status = "";
				if(Teacher.tstatus == 0){
					status = "在职";
				}
				if(Teacher.tstatus == 1){
					status = "离职";
				}

//设置班级的显示值  step1:先combobox 遍历拿到一个List 
				var sclassList = $("#search_tclass").combobox("getData");
	        	
	        	
	        	$("#detail").window('open');//打开窗口
	        	
	        	$("#desc_tid").html(Teacher.tid);
	        	$("#desc_tpwd").html(Teacher.tpwd);
	        	$("#desc_tname").html(Teacher.tname);
	        	$("#desc_tgender").html(Teacher.tgender);
	        	$("#desc_tage").html(Teacher.tage);
	        	$("#desc_ttel").html(Teacher.ttel);
	        	$("#desc_taddress").html(Teacher.taddress);	

//设置班级的显示值  step2: 显示下标在集合里对应的元素的 班级名字。 
	        	$("#desc_tclass").html(sclassList[index].cname);
	
	        	$("#desc_tstatus").html(status);	        		        	
	        }
	    }); 

```
Anaconda に theano 1.0.4をインストールする（pymc3エラー対策)

###困った点
anaconda(pythonは3.6）でpymc3を使おうとするとnumpyまわりでエラーが出ました。
エラーメッセージは'_get_ndarray_c_version'です。
調べてみるとtheanoとnumpyのバージョンがあっておらず、theanoを１．０．４以上にすればいいようです。
https://github.com/pymc-devs/pymc3/issues/3340
今回少し苦労したので、そのことを書いておきます。
###うまくいかなかったこと
次のコードを試してみましたがダメでした。

```python:
conda update theano
```
1.0.3のままです

```python:
conda update theano==1.0.4
```
そんなバージョンはないと怒られました。

###うまくいったこと
https://anaconda.org/conda-forge/theano
にある

```python:
conda install -c conda-forge theano 
```
がうまくいきました。理由はわかりません。
以上です
UdemyでVue.jsの講座を受講しました

# Vue.jsを学習する目的

普段jQueryか素のJavaScriptを書いています。
いろいろな人の話を聞くと、今はReact.jsやVue.jsを使用して開発するのが主流になりつつあるとのことで、
キャッチアップするつもりで学習しました。

# Udemyを選んだ理由

いままで新たな言語を習得しようとする場合には、
書籍を読んだり、インターネットのサンプルコードを打ち込んで習得することが多かったです。
Vue.jsも同じ手法で理解できると思ったのですが、うまくいきませんでした。

おそらく、JavaScirptの発展にはさまざまな途上があり、
Vue.jsも過去に主流だったjQueryの不便だった点を便利に使えるように改良を繰り返しているのだと思います。
書籍とサンプルコードからではそうした経緯を読み取ることができませんでした。

こうすれば動くといった一つ一つの操作は分かるのですが、
なぜそうするのかを直感的に理解できなかったのです。

その点、動画の講座だとVue.jsを使用して有利になる点を直感的に理解できました。

# 購入した講座

Vue JS入門決定版！jQueryを使わないWeb開発 - 導入からアプリケーション開発まで体系的に動画で学ぶ
https://www.udemy.com/learn-vuejs

セールの時に購入しました。1600円でした。
Udemyは定期的にセールをしていますが、JavaScript関連はセール対象になることが多いような気がします。
JavaScirptは業務で使われる頻度が高いので、セールの恩恵を受ける人が多いのではないでしょうか。

# 受講してみて

## 写経は必要

購入した講座には一定の区切りごとに演習問題が設定されていました。

動画なのでぼーっと観ていてもどんどん先へ進むのですが、
何も考えずに見ているだけだと演習問題で詰まってしまいます。
観るだけでは理解するのが難しそうだ、と感じたらその都度写経して自分の手元で動かしました。

## 語彙の説明をきちんとしてくれていた

Vue.jsでは「リアクティブ」といった他ではあまり耳にしない言葉がでてくるのですが、
購入した講座ではこうした語彙もきちんと説明してくれていました。
人との会話で話題に出す際には語彙をきちんと把握しないと意思疎通を図れないので、
言葉の意味を理解できるのはありがたかったです。

他の講座でも同様なのかは分かりませんが、良かった点として挙げます。

## 本をよむのも必要

動画は8時間あり時間をかけて学べます。
ですが、これでVue.jsを使う業務で即戦力になれるかと言われると、学習不足を感じています。
改めて、下記に挙げたような書籍を通じて、プロジェクトでのチーム開発における手法も学ぶ必要があると思います。
（私はまだ読めていません）

Vue.js入門 基礎から実践アプリケーション開発まで 
https://www.amazon.co.jp/dp/B07J6FP6NQ

Udemyの動画では学習できないということではなく、
まず動画で直感的にその技術がある意義やいままでの課題をどう解決しているのかを把握し、
その後、書籍で深く知識を掘り下げていくと良いのではと思いました。