OmniAICreator/Qiita-1.07M huggingface dataset:
WindowsのUnityでWebRTCする

## サンプル
iOSとWindowsでUnityでWebRTCを使った映像通信のネイティブプラグインを実装しました。
Windows版のネイティブプラグインとサンプルプログラムを公開しました。



<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">WindowsのUnityから任意のサブカメラの映像をWebRTCに流せるようになった<br>凄く分かりにくいと思うけど⁽⁽◝( •௰• )◜⁾⁾≡₍₍◞( •௰• )◟₎₎ <a href="https://t.co/eBPGC1u2iH">pic.twitter.com/eBPGC1u2iH</a></p>&mdash; ふじき (@zikifu333) <a href="https://twitter.com/zikifu333/status/1025953033799122945?ref_src=twsrc%5Etfw">2018年8月5日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


## GiHiub
Unityのプロジェクトはこちら
https://github.com/fuziki/unityWebrtcWinTest

上動画とか異なり、Unityのワールド内のサブカメラの映像をWebRTCを使って、遠隔地のオブジェクトのテクスチャに張り付けるサンプルです。
ウェブカメラは使用しません。

## 使い方
### 1. MQTT Brokerを立てる
WebRTCは最初にストリームや経路の情報を交換する必要があります。
サンプルではMQTTを使用して交換するため、MQTTのブローカが必要です。
AWS EC2上などに、Mosquittoなどをインストールしてください。
Mosquitto
https://mosquitto.org/

### 2.MQTTのブローカのアドレスを設定する
MqttController.csの17行目
 mqttClient = new MqttClient("192.168.3.4", 1883, false, null);
のアドレス、ポート部分を立てたブローカに適合するように書き直してください。

### 3.Unityを起動する
Unityのプロジェクトを２台のPCで起動します。
起動時にMQTTがサーバと自動的に接続します。

### 4.Call Someoneボタンを押す
２台のPCがMQTTに接続されたことを確認し、片方のCall Someoneボタンを押します。
接続が確立されると、映像通信が開始します。

## ネイティブプラグインの使い方
### WebRtcMsgExchanger
WebRTCのSDPとICEの交換のためにWebRtcMsgExchangerを継承したオブジェクトが必要です。
descriptionとmessageをリモートのPCにそのまま送信してください。
ローカル側PCから送信すべきメッセージが生成された場合はRequiredSendingMessageが呼ばれます。
リモート側からメッセージを受信した場合は、WebRtcCtr_RecievedMessageを使ってWebRTCのコントローラにデータを渡します。

```csharp:WebRtcMsgExchanger.cs

public class WebRtcMsgExchanger: MonoBehaviour
{
    public WebRtcController WebRtcCtr;
    virtual public void RequiredSendingMessage(string description, string message)
    {
//        Debug.Log("WebRtcMsgExchanger, " + description + ", " + message);
    }
    public void WebRtcCtr_RecievedMessage(string description, string message)
    {
//        Debug.Log("WebRtcMsgExchanger, " + description + ", " + message);
        WebRtcCtr.RecievedMessage(description, message);
    }
}

```


### FrameGate
接続されたpeerにフレームを入力、受け取る場合はFrameGateを使います。

・フレームの入力：
 FramgeGate_Input(IntPtr image, int width, int height)
フレームを入力はFramgeGate_Inputを使います。
imageに送信したい画像のARGB32形式の2次元配列、幅、高さをそれぞれ渡します。

・フレームの受け取り：
FramgeGate_onRecieved(IntPtr rgb, int width, int height)
リモートのPCからフレームを入力されると、FramgeGate_onRecievedが呼ばれます。
rgbは受信した画像の2次元配列です。
LoadRawTextureDataを使って、Texture2Dに反映させます。


## 対応OS
現段階ではwindows10, x64にのみ対応しています。
今後、iOSは対応する予定です。
IPアドレスの基礎

# IPアドレスとは
インターネットでは、**TCP/IPプロトコル** では、通信先を特定するためにIPアドレスを用います。IPアドレスはネットワーク上のユニークな番号で、重複することは許されません。このIPアドレスが、**ネットワーク上の住所** に相当します。このIPアドレスは、32ビットで構成されていて、8ビットずつ **.（ピリオド）** で区切られています。ビットは2進数でデータを取り扱うので、1ビットで2通りのデータを表現することができます。つまり、8ビットだと2の8乗通りのデータを表現することができるわけです。

2の8乗を10進数に直すと256なので、256通りのデータを表現することができます。それがIPアドレスだと、0~255で振り分けられるわけです。そして、IPアドレスは8ビットごとに.で区切られ、32ビットで構成されているので、0~255の番号のまとまりが4個続くというわけです。つまり、IPアドレスは`0.0.0.0 ~ 255.255.255.255`の間となります。

IPアドレスの例

```
172.33.31.254
```

# パブリックIPアドレス
インターネットに接続する際に使用するIPアドレスのことを　**パブリックIPアドレス** と言います。このパブリックIPアドレスは、 **ICANN(Internet Corporation for Assigned Names and Numbers)** という団体が一括管理していて、プロバイダーやサーバー業者から貸りることができます。

# プライベートIPアドレス
プライベートIPアドレスとは、誰にも申請することなく自由に使えるIPアドレスで、インターネットでは利用されません。社内LANを構築するときや、個人的にネットワークの実験をする時には、このIPアドレスが利用されます。このプライベートIPアドレスには、以下のような範囲が決められています。

- 10.0.0.0 ~ 1.255.255.255
- 172.16.0.0 ~ 172.31.255.255
- 192.168.0.0 ~ 192.168.255.255
websocket 使ってみた

# 概要
npm でダウンロードできる node のモジュール `websocket`  を使って、コインチェックの websocket の API に接続し、ビットコインの価格をリアルタイムで取得してみた。

# 道具立て
websocket を Node で使うには websocket というライブラリを使う人が多いのでこれを使うことにした:

```
npm i -S websocket
```

接続先は、みんな大好きコインチェック。認証なしで使える Websocket のAPIがあるので使わせてもらう

- ドキュメント: https://coincheck.com/ja/documents/exchange/api#websocket
- エンドポイント: `wss://ws-api.coincheck.com/`
- 使い方
    - 接続後、この文字列を送信: `{type: "subscribe", channel: "btc_jpy-trades"}`
    - 以下の形式の文字列データが次々とやってくる

```js
[
  104749190, // ID
  "btc_jpy", // 取引ペア
  "783714.0", // レート
  "0.005", // 量
  "sell" // 方法
]
```

# 手順
プログラムの全体構造は、Client オブジェクトを作って、接続時に呼び出されるコールバックを登録した後に、実際に接続する、という形になる:

```js
const Client = require('websocket').client;

const main = () => {
  const client = new Client();
  client.on('connect', onConnect);
  client.connect('wss://ws-api.coincheck.com/');
};
```

コールバックが呼び出される際には、Connection オブジェクトが渡されるので、send メソッドを呼び出して送信したり、メッセージ受信時のコールバックを登録したりできる:

```js
const onConnect = (conn) => {
  console.log('connected');
  conn.on('message', onMessage);
  conn.send(JSON.stringify({ type: 'subscribe', channel: 'btc_jpy-trades' }));
};
```

メッセージ受信コールバックでは、メッセージオブジェクトが渡される。 utf8Data プロパティにアクセスすることで実際のデータにアクセスできるので、`JSON.parse` でオブジェクトに変換後、加工した:

```js
const process = (raw) => {
  const obj = JSON.parse(raw);
  return ({
    time: +new Date(),
    type: obj[4], // sell or buy
    rate: parseFloat(obj[2]),
    vol: parseFloat(obj[3]),
  });
};

const onMessage = (msg) => {
  console.log(process(msg.utf8Data));
};
```

出力結果はこんな感じ:

```
{ time: 1533639554906, type: 'sell', rate: 783180, vol: 0.005 }
{ time: 1533639554970, type: 'sell', rate: 783179, vol: 0.005 }
{ time: 1533639555035, type: 'sell', rate: 783179, vol: 0.005 }
{ time: 1533639555870, type: 'buy', rate: 783462, vol: 0.0178 }
{ time: 1533639555935, type: 'buy', rate: 783466, vol: 0.0022 }
...(後略)
```


# コード全体

```js
const Client = require('websocket').client;

const process = (raw) => {
  const obj = JSON.parse(raw);
  return ({
    time: +new Date(),
    type: obj[4], // sell or buy
    rate: parseFloat(obj[2]),
    vol: parseFloat(obj[3]),
  });
};

const onMessage = (msg) => {
  console.log(process(msg.utf8Data));
};

const onConnect = (conn) => {
  console.log('connected');
  conn.on('message', onMessage);
  conn.send(JSON.stringify({ type: 'subscribe', channel: 'btc_jpy-trades' }));
};

const main = () => {
  const client = new Client();
  client.on('connect', onConnect);
  client.connect('wss://ws-api.coincheck.com/');
};

main();
```
競プロに使えそうなVSのデバッグの超基本的機能とショートカット8つ

# 概要
Visual Studio(以下VS)は、IDE(統合開発環境)[^1]です。
VSでc++のデバッグをする方法と、よく使うショートカットを載せます。
どの開発環境をつかおうか迷っている方などには簡単に構築できるVSをお勧めします。(これは少数派意見かもしれませんのでよく情報を見て)
デフォルトのVSCodeではc++のデバッグはできませんが、拡張でできるようになるので、VSCodeでのデバッグに慣れている方には必要のない情報だと思います。
[VSCodeでのデバッグをする方法](https://qiita.com/bigengelt/items/e4c6f08003fe15988b7d)

# デバッグ
## 1行ずつ実行
- 行番号の左をクリックすると、ブレークポイント[^2]がおけます。
- ブレークポイントを付けた状態でプログラムを実行すると、ブレークポイントの位置に黄色い矢印が出て、その行の位置よりまで実行され、そこで止まります。
- F10を押すと1行ずつ実行できます。
- F11を押すと、その行に関数があった場合矢印を関数の中に移動できます。
- 続行を押すと、今いる位置からプログラムを再開できます。
- F10をしたときに関数を通ると、何がその関数で返されたかが「自動」ウィンドウに表示されます。
![1.gif](https://j.gifs.com/YvL9WA.gif)



## 変数の値を見る
- 変数の上にカーソルをのせたり、自動をみると、変数の中身が見れます。
- 配列、vectorの中身などももちろん見れます。
- ウォッチをクリックして式を入力すると、（変数の値だけでなく）任意の式の値を見ることができます。
- ウォッチや自動では、変数の値が変更されると、その値が赤く表示されます。
![2.gif](https://j.gifs.com/2vZwvM.gif)

# よく使うショートカットキー
VSにはとても便利なショートカットキーがあります。そのうちよく使うものを紹介します。

|キー|動作|
|---|---|
|選択 => Ctrl+K+C|選択した範囲をコメント化する|
|選択 => Ctrl+K+U|選択した範囲のコメントを解除する|
|クリック => F12|クリックした識別子の定義に移動する|
|Ctrl+-|カーソルを直前の位置に移動する|
下のいくつかは競プロをするときよりも大きめのアプリを作るときに使うと、コードが見やすくなります

|キー|動作|
|---|---|
|選択 => Ctrl+M+H|選択した範囲を折りたたむ|
|Ctrl+M+L|全てのアウトラインを(折りたたむ,展開する)の切り替えをする|
|Ctrl+K+D|インデントを整形する({}の位置がバラバラになった時に使う)|
|Ctrl+Alt+PageUp/PageDown|タブの移動|

#### 脚注
[^1]: コンパイラ、テキストエディタ、デバッガなどがまとまったもの
[^2]: ブレークポイントとは、そこでプログラムが一時停止する所です。
SpringBootApplicationが無くてUnable to start ServletWebServerApplicationContext

<code>@SpringBootApplication</code>をつけずに実行するとこの例外がスローされる。

```java
//@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}
```

```
org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:155) ~[spring-boot-2.0.4.RELEASE.jar:2.0.4.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:544) ~[spring-context-5.0.8.RELEASE.jar:5.0.8.RELEASE]
```

メッセージが示すように```ServletWebServerFactory``` beanが何らかの要因でcontext上にロードされていないとこのエラーになる。spring-bootの場合はautoconfigに頼ってれば、<code>@SpringBootApplication</code>を付け忘れとかの凡ミスを除けば、問題ない。それ以外の場合は手作業でbeanを登録してやることになるかと。
Java:自前でカンマ区切りのフォーマッタを実装してみる

#始めに
[値段の表記などの数値3桁ごとにカンマを入れる簡単な方法](https://qiita.com/6rats/items/2b93e999b079b7c8497b)をみて、
「String#formatやNumberFormatを使わずに自前でカンマ区切りのロジックを書くとしたら、どのように実装するか」
ということに興味が湧いたので、簡単に実装してみました

#実装方針
正規表現で数値3桁の部分集合を取得して、reduceで折りたためばいい感じでできそうな気がする
~~tsubstringでちまちま切り出すと添え字の操作がめんどくさそう~~
文字数が３の倍数でないときは無理やり前ゼロを入れればよさそう

#実装してみた
```MyFormatter.java
package formatter;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MyFormatter {
    public static void main(String[] args) throws Exception{
    	System.out.println(format("11"));
    	System.out.println(format("111"));
    	System.out.println(format("1111"));
    	System.out.println(format("11111"));
    	System.out.println(format("111111"));
    }	
    public static String format(String str) {
        Matcher matcher = Pattern.compile("(\\d{3})").matcher(makeStr(str));
        List<String> strs =new ArrayList<String>();
        //前0を除去する
        if(matcher.find()) {
        	strs.add(Integer.parseInt(matcher.group()) + "");
        }
        while(matcher.find()) {
        	strs.add(matcher.group());
        }
        //,を付加するのはreduceを使ったほうがすっきりする
    	return strs
    			.stream()
    			.reduce((s,s1)-> s+","+s1)
    			.get();
    	
    }
    public static String makeStr(String str) {
    	if(str.length()%3 ==2)return "0" + str;
    	else if(str.length()%3 ==1)return "00" + str;
    	else return str;
    }
}
```

##実行結果
```
11
111
1,111
11,111
111,111
```

#感想
 - Javaは正規表現で部分文字列を取得するのが面倒くさい、group関数がstreamを返してくれればいいのに
 - このロジックは文字列を××文字ずつ切りだしたいとき、応用できそう
VC++における論理ドライブの文字列出力

#使用関数

DWORD GetLogicalDriveStrings(
  DWORD nBufferLength,  // バッファのサイズ
  LPTSTR lpBuffer       // ドライブの文字列を格納するバッファ
);

戻り値
格納された文字列サイズ

#コード

```main.cpp
#include "stdafx.h"
#define MEM256 256

int SearchDrive() {
	TCHAR buf[MEM256];
	LPTSTR lp;
	CString drive;

	GetLogicalDriveStrings(sizeof(buf), buf);
	
	for (lp = buf; *lp != _T('\0'); lp++) {
		drive = lp;
		wprintf(drive + _T('\n'));
		lp += drive.GetLength();
	}
	return 0;
}
```

```
>C:\
>D:\
```

windowsは文字列が気持ち悪くて嫌いですね。
CStringにさえ落とし込めればあとはこっちのもの（雑）
OSに依存しない形でnpm scriptsにglobを書く

# 2018/8/23追記

WindowsではGit bashを使うのがデフォになっていたので、powershellの存在をすっかり忘れていたことが今になって発覚。
powershell/bash v3/bash v4で動くように記事を訂正しました。

# 背景

Windowsで開発してたプロジェクトをMacのマシンで動かしたらnpm scriptsが思ったように動かなくて困った。
``rm -rf``なんかは気をつけていたけど、glob (``src/**/*.js``みたいなやつ) がMacでちゃんと認識されなくて困った。

# 結論

**2018/8/23 訂正**
npm scriptsに出てくるglobはすべて<font color="red">「\"」(バックスラッシュ + ダブルクォーテーション)</font>で囲む。

# 参考文献

ここを参考にしました。

https://medium.com/@jakubsynowiec/you-should-always-quote-your-globs-in-npm-scripts-621887a2a784

# 解決までの道のり

## ぶち当たった問題

今回解決したかったのは、以下のようなglobの含まれるnpm scriptsでした。

```json-doc
  "scripts": {
    "test": "mocha src/**/*.spec.ts"
  },
```

このプロジェクトでは、当初Windowsマシンを使って開発を進めていました。
そのときのテスト結果がこちら。

```text
  190 passing (277ms)
  2 pending
```

開発の途中でMacのマシンを購入することができたため、Macのマシンで開発を続けようと思い、環境セットアップしてテストを回すと…。

```text
  72 passing (88ms)
```

少ない？？

## 原因

普段意識せずに使っている、"\*\*"と書けばネストしたディレクトリを含む、というようなglobは``globstar``というシェル拡張を使っているそうです。

記事執筆時点のMacだとデフォルトでbashのバージョンが3系なので、そもそもglobstarが使えません。(globstarが追加されたのはバージョン4から)

その状態で"\*\*"を含むglobを書くと、**2段以上ネストされたディレクトリに対応できなくなった**わけです。

ではBashのバージョンを4系に上げ、globstarを有効にすればそれだけで使えるようになるかというと、**そういうわけでもありませんでした。**

どうも、npm scriptsに書いたスクリプトは``sh -c``に続く形で渡されるようです。
このとき、元のシェルセッションでglobstarを有効にしていたとしても、新しく作られたシェルのセッションでは**globstarが無効になって**しまっていました。

この時点で上記の参考ブログに出会うわけですが、mochaなどのnpm moduleでは引数にglobが含まれる場合、**``node-glob``というモジュールで解決する**そうです。

この``node-glob``というモジュールはglobstarにも対応しているため、npm scriptsに書くglobをglobとしてシェルに認識させないようにすると良いということが分かりました。

つまり、こうです。

```json-doc
  "scripts": {
    "test": "mocha 'src/**/*.spec.ts'"
  },
```

globをシングルクォーテーションで囲むことで、bashにとってはただの文字列として扱われるため、上記の場合だとmochaが使うnode-globで解決されるようになります。

**2018/8/23 訂
正**

上記スクリプトだと、Windowsのpowershell環境で正常に動かないことがわかりました。
その理由は、bashとpowershellではシングルクォーテーションの扱いが違うからだと思われます。(あんまり詳しくは分かってない)

なので、以下のように修正するとうまく動くようになりました。

```json-doc
  "scripts": {
    "test": "mocha \"src/**/*.spec.ts\""
  },
```

ここまで書いて考えたのですが、環境変数からglobを組み立てたり、ちょっと複雑なことしたくなったときは、powershellとbashを両立させるのはそもそも無理なのでは…？
(環境変数の参照の仕方が違う、bashだと``$var``でアクセスできるけどpowershellだと``$env:var``としなければいけない…。)

# まとめ

まさかOSが変わるとこんなところに影響があるとは思ってもいませんでした。
普段Windowsしか触らないといろいろ怖い。システムのデフォルトでIgnore Caseだったり、ついbashのスクリプト書いたら動かなかったり。UNIX系OS流行れ。

## 2018/8/23 訂正後に追記

そういえばpowershellというものがあったなぁ。
なんか使いにくくて敬遠してるけど。
bash + ImageMagick > rainbow colorのボックスを作る v0.1

```txt:動作環境
CentOS release 6.9 (Final)
GNU Bash-4.1
ImageMagick Version: ImageMagick 6.7.2-7 2017-03-22 Q16
```

### 処理概要

- 内側から外側までrainbow colorのボックスを作る
- ImageMagickコマンドをbashスクリプトで使う

### code v0.1

```bash:layered_image_180807_exec
#!/usr/bin/bash/env

set -eu # just in case

# v0.1 Aug. 07, 2018
#   - draw rainbow colored layered image

WRK1_FILE="wrk1.png"  # work file (arbitrary names)
WRK2_FILE="wrk2.png"  # work file (arbitrary names)
OUT_FILE="out.png"    # output

wrksize=100  # size of the image
incsize=10   # increment size

#------------------------------
#CONFIGURATION
#   colors from innermost to outer
COLS=("violet" "indigo" "blue" "green" "yellow" "orange" "red")
#------------------------------

#1. base image
sizestr=$(echo $wrksize | awk '{print $1"x"$1}')  # e.g. 100x100
convert -size $sizestr xc:${COLS[0]} $WRK1_FILE

#2. expand image
((maxloop=${#COLS[*]}-1))
for idx in $(seq 1 $maxloop)
do
  ((wrksize=wrksize+incsize*2))
  sizestr=$(echo $wrksize | awk '{print $1"x"$1}')  # e.g. 100x100
  echo $sizestr
  convert $WRK1_FILE -page +10+10 -background ${COLS[idx]} \
  	-extent $sizestr -flatten $WRK2_FILE
  cp $WRK2_FILE $WRK1_FILE
done

#3. output 
mv $WRK2_FILE $OUT_FILE

#remove temporary files
rm -f $WRK1_FILE

echo "[$OUT_FILE] is produced"
```

### 設定

上記のCONFIGURATION記載の色名のarrayを変更すると、それに合わせて色が付く。

### 実行

```txt:run
$ bash layered_image_180807_exec 
120x120
140x140
160x160
180x180
200x200
220x220
[out.png] is produced
```

`eog out.png`で見たのが以下。

![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/95ecf557-d239-7b97-604f-4259ecaea2b7.png)

### 参考

- [Bash $((算術式)) のすべて - A 基本編](https://qiita.com/akinomyoga/items/9761031c551d43307374)
- [Bashでいろいろループする](https://qiita.com/ytyng/items/d7afe80ef9da7aa8b721)

情報感謝です。

### 画像の用途

画像の一部を切り出して合成する時に、切り出しがうまく行ったかを確認するために上記のような画像を使う。
PHP: SJIS全角文字の後半1バイトだけを無理に変換しようとすると、次の文字を巻き込んでしまう仕様のようだ

```php
<?php

function sjis(string $s) {
    return mb_convert_encoding($s, 'SJIS-win', 'UTF-8');
}

function utf8(string $s) {
    return mb_convert_encoding($s, 'UTF-8', 'SJIS-win');
}

function bytes(string $s) {
    return strtr(urlencode($s), '%', 'x');
}

function strings(string $b) {
    return urldecode(strtr($b, 'x', '%'));
}

function println(string ...$x) { foreach ($x as $y) echo $y, PHP_EOL; }

ini_set('mbstring.substitute_character', 'long');

println(
    bytes(sjis("◎!")), // x81x9Dx21 (全角二重マルと半角の感嘆符)
    utf8(strings('x9Dx21')) // BAD+9D21
);

```

## 所感

<blockquote class="twitter-tweet" data-cards="hidden" data-lang="ja"><p lang="ja" dir="ltr">この仕様のため、CSVを読み取るプログラム(ストリーム処理でSJISからUTF-8に変換するやつ)で、ちょうどストリームチャンクの境界に全角文字が来てしまうと、文字化けするという現象が発生してしまっていた。 <a href="https://t.co/h4wwB1M5PY">https://t.co/h4wwB1M5PY</a></p>&mdash; ❄️suin (@suin) <a href="https://twitter.com/suin/status/1026773928063193088?ref_src=twsrc%5Etfw">2018年8月7日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
ElixirのUnicode操作でJSの「SyntaxError: '' string literal contains an unescaped line break」を回避する

[fukuoka.ex](https://fukuokaex.fun/)代表の[piacere](https://twitter.com/piacere_ex)です
今回もご覧いただいて、ありがとうございます:bow:

今回は、地味にあるあるなケースで、任意のWeb入力をJavaScriptで表示すると、JavaScriptがエラーを起こし、実行不全を起こすのを、Elixir側で回避するための技をご紹介します
<br>
:stars::stars::stars::stars::stars:<b>　お知らせ：LINE Fukuokaで、Elixir MeetUpを8/24に開催します　</b>:stars::stars::stars::stars::stars:

[<b>「fukuoka.ex#13：夏のfukuoka.ex祭＝技術のパラダイムシフト」</b>](https://fukuokaex.connpass.com/event/89472/)をLINE Fukuokaで、8/24（金）開催です

[![image.png](https://qiita-image-store.s3.amazonaws.com/0/155423/3f0fbb56-e5e8-2c4d-7c62-1b0b311d6d02.png)](https://fukuokaex.connpass.com/event/89472/)

fukuoka.exの1年の活動・実績を総括し、今後の方向性を示す重要なMeetUpでもあるので、どうぞライブでこの場にお立ち会いください
https://fukuokaex.connpass.com/event/89472/

今回のセッションでは、LINEから初のElixir登壇参戦で、ミラーチップ・アダムさんが、Clova（LINE AIアシスタントスピーカー）開発のために作成したElixirライブラリ「Clova」について登壇します

私は、この半年の「fukuoka.ex祭り」の中間成果・実績発表LTと、「2020年までに福岡を『エンジニアの楽園』にするには？」セッションの2本をお届けします

# JavaScriptで謎のエラー

DBやAPIから取得したデータを、JavaScriptで表示したり、CSVダウンロードしようとすると、ブラウザが以下のJSエラーを吐いて、うまく動かなくなるケースがあります

```
SyntaxError: '' string literal contains an unescaped line break
```

デバッグコンソールでも、何も表示されないか、「・」しか表示されず、エラーの原因はよく分かりませんが、何か不正な文字がある、ということは、エラーメッセージで推測できます

# エラーの原因は「U+2028」と「U+2029」

エラー発生箇所をバイナリダンプすると、「U+2028」や「U+2029」といった、あまり聞き慣れない、Unicode文字が混在しているケースがあります

U+2028／U+2029が、何者かと言うと、「Unicodeの改行文字」のようで、ASCIIコードで言うところの、「CR（0x0D、U+000D）」や「LF（0xA、U+000A）」と類似する文字のようです

正確には、U+2028が「LS（Line Separator）」＝「行分割」で、U+2029が「PS（Paragraph Separator）」＝「段落分割」とのことです

多くのブラウザのJavaScriptでは、この「Unicodeの改行文字」は扱えず、エラーとなるようです

# U+2028／U+2029がどこで混入するのか？

どうやら、任意のWeb入力をする際、Word等のオフィスドキュメントからコピペを行った場合、改行文字として、U+2028／U+2029が混入するようです

# ElixirでUnicode文字を削除する

DBやAPIからのデータ取得をElixirで行っている場合は、Elixirで以下のようにU+2028／U+2029をUnicodeとして指定し、削除することで、JavaScript側での処理時にエラーを出さないようにできます

```elixir:index.html.eex
data |> String.replace( "\u2028", "" ) |> String.replace( "\u2029", "" )
```

もし改行に変更するなら、以下のようにすればOKです

```elixir:index.html.eex
data |> String.replace( "\u2028", "\n" ) |> String.replace( "\u2029", "\n" )
```

# p.s.「いいね」よろしくお願いします

よろしければ、ページ左上の ![image.png](https://qiita-image-store.s3.amazonaws.com/0/155423/4d515047-cc48-382e-c2b1-3ad0cc50dbbf.png) や ![image.png](https://qiita-image-store.s3.amazonaws.com/0/155423/a4e3da58-70a3-4197-95a2-6a6906650d01.png) のクリックをお願いしますー:bow:
Docker&Ubuntu初心者がfluentdを使ってみた

#fluentdとは

fluentdはオープンソースのデータコレクターやデータログ収集ツールでデーモンとして動作します。デーモンとはUnix系のOSでいつも常駐しているプログラムのことです。今のところfluentdはLinux上での動作が主に想定されています。読み方ですが フルエントディーです。プラグインでGoogleのBigqueryが使えるので近いうちに導入しようと思います。

<h3>環境</h3>
macOs
Docker for mac
ローカル環境をぶっ壊すのがとても怖いので、Docker上でやることにしました。
Dockerのインストールは　こちらへ
https://www.docker.com/docker-mac


```バージョンの確認
$ docker --version
Docker version 18.06.0-ce, build 0ffa825
```
dockerがインストールされたことが確認できました。

<h3>Ubuntu:xenialのイメージを取得する。</h3>
とても簡単です。１行で終わります。

```
$ docker pull ubuntu:xenial
```
取得したイメージは以下で確認できます。

```
$ docker images

REPOSITORY   TAG      IMAGE ID     CREATED      SIZE
ubuntu      xenial   7aa3602ab41e 11 days ago   115MB
```

このイメージをもとに、Containerを起動しましょう
root@06b0ca1235f9:#
のようになれば成功です

```
$ docker run --name fdtest01 -it ubuntu:xenial /bin/bash

CONTAINER ID  IMAGE             COMMAND      CREATED              STATUS      PORTS     NAMES
06b0ca1235f9 ubuntu:xenial  "/bin/bash"  About an hour ago   Up About an hour         fdtest01
```
起動しました。

あとあと必要なコマンドが使えるようにしておきます。

```
# apt-get update 
# apt-get install sudo
# apt-get install curl 
# apt-get install vim
```

<h3>fluentdをインストールする。</h3>
いよいよfluentdのインストールです。
ここら辺は公式を見てあげればいいと思います。fluentdですが、td-agentというものをインストールします。以後もこれがよく出てくるんので一緒に覚えておくといいと思います。

https://docs.fluentd.org/v1.0/articles/install-by-deb#step-2:-launch-daemon

```
# curl -L https://toolbelt.treasuredata.com/sh/install-ubuntu-xenial-td-agent3.sh | sh
```

これでfluentdがUbuntu上にインストールされました。

td-agent(fluentd)の起動やストップ、再起動は以下のようにします

```
# /etc/init.d/td-agent start
# /etc/init.d/td-agent stop
# /etc/init.d/td-agent restart
```

スタートしてあげたのちに、設定ファイルを確認しましょう。
諸々の設定ファイルは、
/etc/td-agent にあります。conf.d , plugin, td-agent.conf らです。
td-agent.confをvimコマンドで見てあげると、http通信は

```
# HTTP input
# POST http://localhost:8888/<tag>?json=<json>
# POST http://localhost:8888/td.myapp.login?json={"user"%3A"me"}
# @see http://docs.fluentd.org/articles/in_http
<source>
  @type http
  @id input_http
  port 8888
</source>
## live debugging agent
<source>
  @type debug_agent
  @id input_debug_agent
  bind 127.0.0.1
  port 24230
</source>
```
とありますね。curlコマンドを使って、POSTメソッドでlocalhost:8888でhttp通信して見ます。

```
# curl -X POST -d 'json={"test":"hello fluentd"}' http://localhost:8888/debug.test
```

試しに、ログを確認してみましょう。
ログは　 /var/log/td-agentにある td-agent.logに出力されています。

2018-08-07 08:40:44.262606600 +0000 debug.test: {"test":"hello fluentd"}

ログに出力がされていました。
何か間違いや訂正等ありましたらご連絡ください。
emulate_booleansをモデルごとに有効にする



環境
---
Rails 5.0.6
ruby 2.5.1

はじめに
---
railsにはtinyintをbooleanとして認識することができる便利な機能があります。
しかし、昔から運用しているアプリケーションでは、容易にtrueにはできない状況が発生します。

```ruby
# たとえば以下のコードは、tinyint_columnがbooleanになってしまうと条件がコケる
if tinyint_column == 1
  ...
end
```

そのため、泣く泣くこのオプションをOFFにしていました :sob: 

```rb:config/application.rb
ActiveRecord::ConnectionAdapters::Mysql2Adapter.emulate_booleans = false
```

しかし、booleanで扱えるといろいろ便利な場面が多いのも事実です。
新規で作成するモデルや、利用するgemのモデルではぜひとも利用したい!! :smile: 

ということで、やってみました :muscle: 

対処法
---

今回は、moduleを作り、対象モデルでincludeすることで実現します。

```rb:app/lib/emulate_boolean_type.rb
module EmulateBooleanType
  extend ActiveSupport::Concern

  included do
    emulate_boolean_type!
  end

  class_methods do
    def emulate_boolean_type!
      return unless ActiveRecord::Base.connection.data_source_exists? table_name
      tinyint_columns = columns_hash.select{|_name, col| col.sql_type == 'tinyint(1)'}.keys.map(&:to_sym)
      tinyint_columns.each do |col|
        attribute col, ActiveModel::Type::Boolean.new
      end
    end
  end
end
```

```rb:app/models/hoge.rb
class Hoge
  include(EmulateBooleanType)
  ...
end
```

以上です。
めでたしめでたし :clap: 

参考
---
- [Ruby on Rails ガイド：体系的に Rails を学ぼう](https://railsguides.jp/configuring.html)
- [ruby on rails - Getting types of the attributes in an ActiveRecord object - Stack Overflow](https://stackoverflow.com/questions/2399556/getting-types-of-the-attributes-in-an-activerecord-object)
【いまさらですが】Javascriptの「undefinded」と「is not define」の違い

今更ですが、Javascriptの「undefinded」と「is not define」のエラーの違いについてです。
※以下、コードの実行環境はChromeの開発者ツールを使用しています。

#is not define
変数が定義されていないことを指します。
以下のようなパターンです。

```js

console.log(value);
// Uncaught ReferenceError: value is not defined
```


#undefinded
変数は定義されていますが、値が入っていない(初期化されていない)ことを指します。
以下のようなパターンです。

```js
var value;
console.log(value);
// undefined
```

初期化すると値が出力されます。

```js
var value = null;
console.log(value);
// null
```
【新卒エンジニア必読】ゼロからエラーを自分で解決できるようになるまで

# はじめに
一年目のエンジニアはみんな**「なんかプログラムが動かない」**という状況に陥っていると思う。
自分自身もそんな状況がとても多くあった。今でもある。一日潰れることもある。
ただ最初と比べて変わったことは、**「原因を調査して動かす状態に持っていく」**ことが出来るようになった。
そこに行きつくまでにどんな歴史があったか、振り返ってみることにした。
**この記事を読むことで新卒研修がより良いものになってもらえる事を期待する。**

# 歴史
## 第1フェーズ ~デバックってなんだ？~
ここはIDEを使ったりすることですぐにできると思う。
初歩なのでほとんどの人が出来ていると思う。
デバックポイントを張って、**ポイント毎に自分の期待する動きになっているか中身を確認する。**
期待する動きになっていなかったら、修正していく。ただの繰り返しだ。

## 第2フェーズ ~スタックトレースってなんだ？~
自分のコードが動かない時、必ずスタックトレースにエラー内容が書かれる。
このエラー内容を読むことで、どういった問題がプログラムにあるか事実がわかる。
最初はエラー文を最後まで読まずに、適当にコピーしてネットで調べていた。
まずは、**落ち着いてエラー文を全部読み今起きている事実を認識することが重要。**
適当に検索すると、問題でないことに対して検索している状態になる。

## 第3フェーズ ~英語？ I can read~
エラー文に関わる事だが、まずエラー文は基本的に英語で書かれる。
英語に抵抗があると、読まなかったり、上記と同じくコピペする。
**最初はゆっくりでもいいから英語でも頑張って読む。何度も読む。**
そうするとコツがつかめる。
また、ネットで検索するときも日本語でないなら英語で検索をする。
普通に英語の方が情報量も違うことは明白だ。

## 第4フェーズ ~ライブラリの中身を見ていく~
自分の書いたコードが動かない時、自分のソースコードは読むが、
フレームワークやライブラリの中身は読もうとしない。
理由は単純に「難しそうだから」だと思う。
だが、ライブラリの中身を読むことで、intしか受け付けないのに、stringで渡していた！
など気づくことがある。副産物として良いコーディング方法も知れたりする。

## 第5フェーズ ~仕様書を読むぜ~
qiita等のネットの情報はとても有効だが、あっているか間違っているかは自分で判断しなければいけない。
嘘もあれば、バージョンが違うこと、記事の内容が古いこともある。
**一番「正」は仕様書である。**
まずはqiitaで良いが、解決できなければ仕様書も読む。
※仕様書はまだ自分も読むのに苦戦している。

# まとめ
今回はコーディングに絞って自分がどうしてきたか振り返ってみた。
数年経験しているエンジニアからしたら当たり前の事かもしれないが、
一年目や二年目にとっては当たり前ではない事だと思う。
エンジニア歴2年目だからこそ新卒に伝えられる内容も多くあると思った。
また、振り返ってみることで、新しい発見もあった。
新卒エンジニアの参考になれば幸いです。
One Class SVMを使ってMNISTの数字画像の異常検知がしたい

#はじめに
One Class SVMとは異常検知などに使われる教師なし学習です．通常のSVMでは多クラス分類ができますが，One Class SVMはその名の通り１クラス分類（そのクラスか，それ以外か）となります．One Class SVMについて詳しくは[「異常検知のためのOne Class SVM」](https://qiita.com/kznx/items/434d98bf1a0e39327542
)の記事を参考にしてください．今回はこのOne Class SVMと，機械学習において超有名なデータセットであるMNISTを使って簡単な異常検知（？）をしたいと思います．実験設定はいたって簡単，「１」を正常画像「７」を異常画像とします．MNISTには同じ「１」でも形が様々なものがあるので，どれだけのパターンの「１」を正確に正常と判断できるかどうかも重要となってきますね．

今回の実装に関するソースコードは[こちら](https://github.com/mituki-suzu/OneClassSVM)からどうぞ．

#環境
|          |version|
|:---------|:-----:|
|Python    |3.5.5  |
|Keras     |2.1.5  |
|TensorFlow|1.7.0  |

#One Class SVMの実装
One Class SVMを実装するにあたって，scikit-learn(sklearn)を使用しました．このscikit-learnを使うとなんと２行でOne Class SVMの学習が可能となります．便利な世の中ですね．
scikit-learnのOne Class SVMについての公式ドキュメンテーションは[こちら](http://scikit-learn.org/stable/modules/generated/sklearn.svm.OneClassSVM.html)になります．
以下が今回のOne Class SVMの実装にあたるコードです．

```python:OCSVM_mnist.py
def execute_OCSVM(x_train_1, x_test_1, x_test_7):
	#One Class SVM を実行
	clf = svm.OneClassSVM(nu=0.2, kernel="rbf", gamma=0.001)
	clf.fit(x_train_1)
	#配列の頭から「１」を100個，「７」を20個取り出し予想
	test = np.vstack((x_test_1[0:100], x_test_7[0:20]))
	pred = clf.predict(test)

	return pred
```

上記のコードにおいて注意しなければいけない点は，nuとgammaです．nuとgammaはハイパーパラメータなのですが，これらの値を変更すると結果に大きな違いが生じます．初期設定ではnu=0.5，gamma=autoとなっています．[One Class SVMを用いた異常値検知](https://www.slideshare.net/YutoMori2/one-class-svm)の記事によると，gamma=1/特徴量の総数とされているので，今回はgamma=0.001としています．nuは異常の割合とされているので，nu=0.2としています（「１」が100枚，「７」が20枚で実験しているため約２割）．

#結果
### **とりあえず画像をそのまま入れてみる**
まずは何も考えずに，取得したMNISTの画像をそのままOne Class SVMに入力し，学習・分類をしてみました．結果が以下の図のようになっています．横軸が入力した画像（1～100が「１」、101～120が「７」），縦軸が判定結果（1なら正常，-1なら異常と判定）です．
![OCSVMmnist.png](https://qiita-image-store.s3.amazonaws.com/0/278707/06a66a69-ad5d-8fef-a149-79122c12274a.png)
accuracyは0.90(90%)でした．「７」はすべて異常と判定されていますね．やはり横に長い部分を異常と判定しやすいのでしょう．「１」はところどころ誤って異常と判定してしまっています．実際に異常と判定された「１」のうち，いくつかがこちらです．

![miss.png](https://qiita-image-store.s3.amazonaws.com/0/278707/39382a3e-77fa-727d-6b36-07b45f085921.png)



湾曲していたり，７に近い形の画像が異常と判定されてしまっています．人が書く「１」にも様々な形があるので難しいのかもしれません．

### **Autoencoderで特徴量を抽出して入れてみる**
簡単なAutoencoderをkerasで実装し，中間層で取得できた特徴量をOne Class SVMに入力すれば精度向上するのでは？と考え実際にやってみました．Autoencoderでは，MNISTの「１」のみの画像で学習を行いました．「１」のみを学習させることで再構築の際に「１」に関係する有効な特徴量が得られることを期待します．結果が以下の図のようになっています．
![OCSVMAE1mnist.png](https://qiita-image-store.s3.amazonaws.com/0/278707/0b5f9129-b644-7a9a-5030-597b452cc614.png)
**精度悪化してるやん！！！！！！！！**
accuracyが0.84(84%)に下がってしまいました．これは自分の不徳の致すところです．考えが甘かったです．ごめんなさい．MNIST自体簡単な画像ですし，様々な形の「１」を学習することで，どちらかといえば汎用的な特徴量が得られてしまったのではないかと考えます．（実際，Autoencoderに学習されていない他の数字の画像を入力しても，かなりいい精度で再構築できてしまっていたので・・・）実際に得られた中間層の出力画像が以下のようになっています．
![IntermediateImage.png](https://qiita-image-store.s3.amazonaws.com/0/278707/0449811f-d8d6-fd7f-dcec-f1c41e971c54.png)

#まとめ
今回はOne Class SVMとMNISTを用いて簡単な異常検知（？）を行いました．異常は正確に検知できていましたが，正常を正しく正常とみなすことが難しいという結果となりました．通常の異常検知の現場では，固定されたカメラである部品を同じ角度から撮影し，傷を検知することなどに用いますので，正常画像には全体としてあまり差がない状態となります．今回のような状態はまれですね．
また，Autoencoderを用いて有効な特徴量を得ようと試みましたが，思い通りにいきませんでした．有効な特徴量の取得の仕方は再度検討したいと思います．
Dockerコンテナでsshする時の鍵をホストから持ってくる

# 概要

docker コンテナから scp などしたい場合、 private key をホストから持ってくる必要があります。
agent-forwarding で sock ファイルをマウントすれば完了、と思ったらそうでもなかったのでメモ。

**docker内にprivate keyを持ち込むのは危険な行為です。自身の責任で実行してください。**

# 前提

// docker-composeを使っていることを前提としていなかったので追記しました

* docker-composeを使用します。  
使わなくてもできますが、最近もうdocker-composeにべったりなもんで・・・

# Linuxの場合

ホストで agent-forward でログインするか、 ssh-agent が起動していればこれで sock ファイルがマウントされます。

```yaml:docker-compose.yml
services:
  sshclient:
    environment:
      SSH_AUTH_SOCK: "/tmp/ssh-agent.sock"
    volumes:
      - "$SSH_AUTH_SOCK:/tmp/ssh-agent.sock"
```

# macOS の場合

macOSだと sock ファイルをvolumesでマウントしても使えませんでした。
なので .ssh/id_rsa をマウントしてしまいます。

```yaml:docker-compose.yml
services:
  sshclient:
    volumes:
      - "~/.ssh/id_rsa:/root/.ssh/id_rsa"
```

が、これだと id_rsa が存在するホストだと動きますが、
前述のlinuxのようにagent-forwardされた環境だと id_rsa が存在しないので、
マウントすると /root/.ssh/id_rsa/ というディレクトリが作成されてしまい、sshコマンドを実行するとエラーが発生します。

# 両方の環境で動くように

面倒ですがentrypointでid_rsaがあればコピーしてsshする動きにします。

```yaml:docker-compose.yml
services:
  sshclient:
    image: [sshコマンドのあるimage]
    environment:
      SSH_AUTH_SOCK: "/tmp/ssh-agent.sock"
    volumes:
      - "$SSH_AUTH_SOCK:/tmp/ssh-agent.sock"
      - "~/.ssh/:/root/.ssh_dir/"
    entrypoint: ["bash", "-l", "-c", "[ -f /root/.ssh_dir/id_rsa ] && mkdir -p /root/.ssh/ && cp -p /root/.ssh_dir/id_rsa /root/.ssh/id_rsa\nssh -A user@host" ]
```

あまりよろしくないですが、sshするケース自体がレアなので、とりあえずこれで暫定的に対処しました。
Windows 10 の AutoPilot 用の情報を取得するPowerShell

# 概要
AutoPilotを利用するためにはMicrosoftにPCのserialなどの情報を登録する必要があります。
各PCからその情報を抽出する方法のメモです

以下のPowerShellを連続で流せば、データを抽出できます
PowerShellモジュールのダウンロードからインストールまで一連の動きが記載されています。
c:\をテンポラリにしているので適宜書き換えてください。
また出力ファイルはc:\AutoPilotOutputfile.csvです。

```AutoPilot.ps
Install-Script -Name Get-WindowsAutoPilotInfo
Set-ExecutionPolicy unrestricted
Get-WindowsAutoPilotInfo.ps1  -OutputFile c:\AutoPilotOutputfile.csv
```
##動作確認
上記コマンドレットの実行画面です。
1. 管理者権限でPowerShellを起動します。
2. 上記のコマンドレットを順に実行します。この時確認を求められますので、承認していきます。
![キャプチャ252.JPG](https://qiita-image-store.s3.amazonaws.com/0/262585/25e6db75-d47b-af2b-3cc4-d9f7a8f7be7a.jpeg)
3. 出力ファイルができていることを確認します。
![キャプチャ253.JPG](https://qiita-image-store.s3.amazonaws.com/0/262585/6477f12d-eac0-b65c-2b1f-9f635bdf70e4.jpeg)
Pythonで世界地図-24(都府県の境界線、各国の州等の境界線)

日本の県境、世界の国々の州等の境界線（南北アメリカ大陸はありません）のシェイプファイルを利用する。

シェイプファイルのダウンロード

Natural Earth
http://www.naturalearthdata.com/downloads/

の
「Large scale data, 1:10m」　「Cultural」 「Admin 1 – States, Provinces」　「Download states and provinces」
をダウンロードする。


```python:
#!/usr/bin/python3
# coding: UTF-8

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from geonamescache import GeonamesCache
from matplotlib.patches import Polygon
from matplotlib.collections import PatchCollection
from mpl_toolkits.basemap import Basemap

font = {'family':'IPAGothic'} #日本語Fontを指定

map = Basemap(lon_0 = 155,resolution='i',projection='cyl')

map.drawcoastlines()
map.drawcountries()

map.drawmapboundary(fill_color='aqua')
map.fillcontinents(color='gray')

shapefile = 'ne_10m_admin_1_states_provinces/ne_10m_admin_1_states_provinces'

map.readshapefile(shapefile, 'prefectural_bound', color='#444444', linewidth=.2)

plt.show()
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/238800/a723b0a4-02b5-03f6-92ae-e3e29e81b463.png)

日本の県境及び南北アメリカ大陸を除く世界各国の州等の境界線が描画される。
[Vue.js]vue-loaderのバージョンを上げすぎてエラーが出た話

# はじめに
やらかしたので備忘録。

久々にVue.jsを立ち上げてパッケージをアップデートしたら、次のようなエラーメッセージががが。

```
Module not found: Error: Can't resolve 'vue-loader' in '(project)'
```

今まで `vue-loader` なしで動いてたんだけどなぁ…と思って `npm i vue-loader` を叩くと次はこのメッセージ。

```
vue-loader was used without the corresponding plugin. Make sure to include VueLoaderPlugin in your webpack config.
```

調べると [**バージョンを上げすぎると互換性の問題でエラーになる**](https://github.com/symfony/webpack-encore/issues/311) 場合があるとのことで、 `vue-loader` のバージョンを `14.2.3` まで下げてみた。
やっとトランスパイルは通ったものの、今度はブラウザ側に次のメッセージが。

```
Failed to mount component: template or render function not defined.

found in

---> <Anonymous>
       <VContent>
         <VApp>
           <Root>
```
# 対応したこと
* `node_modules` 配下を削除して再インストール
    * ダメ
* `vue-loader` のバージョンを落としてテスト
    * `vue-loader was used without the corresponding plugin. Make sure to include VueLoaderPlugin in your webpack config.` に効果あり
* コンポーネントの記述を見直す
    * `Failed to mount component: template or render function not defined.
` に効果あり

## `node_modules` 配下を削除
アップデートに失敗したらまずこれを試してます。
普通に `rm -rf node_modules` で削除した後、 `npm i` で再度インストール。
今回は効果なしでした。

## `vue-loader` のバージョンを落としてテスト

```bash:console
# 最新バージョンを確かめる
npm info [package_name] version
# もしくはパッケージのバージョン情報をすべて取得
npm info [package_name] versions

# 現在のバージョンを取得
npm ls(list) --depth=0
# 最新状態になっていないパッケージを取得
npm outdated

# バージョンを指定してインストール
npm i(install) [package_name]@[version]
# 例えば vue-loader@14 と指定すると14台の一番新しいパッケージをインストールできる
```

[**よく使うnpmコマンド**](https://qiita.com/yuch_i/items/3d5f562ac49e81705010) を参考にさせていただきました。

## コンポーネントの記述を見直す

今回はこれが元凶でした。
Laravelで構築するなら、最小構成で行けば `resources/assets/js/app.js` 内にコンポーネントとルートなんかを記述して行けばいいのですが、保守性を上げるために `routes.js` ・ `components.js` と切り分けていました。
ここの `routes.js` に問題があった模様。
ソースコード、構成は [**こちら**](https://qiita.com/tosite0345/items/f7a725eb9aa2bcff6aa3) をご参考に。

結論から先に書くと…。

```diff:resources/assets/js/routes.js
import VueRouter from 'vue-router';
console.log('initialized routes.');
+ import Index from './components/Index.vue';
+ import Test  from './components/Test.vue';
const routes = [
-    { path: '/',     name: 'index', component: require('./components/Index.vue') },
-    { path: '/test', name: 'test',  component: require('./components/Test.vue') },
+    { path: '/',     name: 'index', component: Index },
+    { path: '/test', name: 'test',  component: Test },
];

export default new VueRouter({
    mode: 'history',
    routes,
    linkActiveClass: 'active',
});
```
続編１：土壌湿度センサーを追加（前編：夏休みの工作におススメ！自動水やり機（Obniz＋電動灯油ポンプ）の製作）

#概要
前回の
[夏休みの工作におススメ！自動水やり機（Obniz＋電動灯油ポンプ）の製作](https://qiita.com/keicafeblack/items/7c667d5a9dcab9f56dd3)
をパワーアップさせて、土壌湿度センサーを追加し、Web上で土壌湿度をグラフで見れるようにしました。
夏休み限定の工作のため、土壌湿度センサーは釘で作った簡易的なものにしています。

#システム構成
![CIRC.JPG](https://qiita-image-store.s3.amazonaws.com/0/181708/90bb89ba-6a32-c499-8f5e-5c603d8c31bc.jpeg)

①Obnizサーバーサイドイベントで30分毎にプログラムを起動
↓
②土壌湿度センサー数値を取得
↓
③ThingSpeakに上記値を送信

#プログラム
```sendHumData.html
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="https://obniz.io/js/jquery-3.2.1.min.js"></script>
  <script src="https://unpkg.com/obniz@1.9.1/obniz.js" crossorigin="anonymous"></script>
</head>
<body>

<div id="obniz-debug"></div>
<h1>Soil Humidity</h1>
<button id="on">ON</button>
<button id="off">OFF</button>


<script>
var obniz = new Obniz("★ここにObnizのIDを入れてください★");
obniz.onconnect = async function () {


  var sensor = obniz.wired("SEN0114",  {vcc:0, output:1, gnd:2});

  var value = await sensor.getHumidityWait();
    //console.log('Humidity Level:' + value);
 
  
const request = new XMLHttpRequest();
request.open("GET", `https://api.thingspeak.com/update?api_key=★ここにthingspeakのキーを入れてください★&field1=${value}`);
request.send();

  
 // if (typeof done === "function") {
 //   done();
 // }  
  
}

</script>
</body>
</html>
```
#詳細説明
###①Obnizサーバーサイドイベントで30分毎にプログラムを起動
上記プログラムを起動
![Moisture.JPG](https://qiita-image-store.s3.amazonaws.com/0/181708/0fa9e213-2c91-485e-af35-79f9849afe29.jpeg)

###②土壌湿度センサー数値を取得
・自作土壌湿度センサーの説明と作り方は下記を参考に作成
>（参考サイト）[土壌湿度センサーとScratchで、植物を乾燥から守ろう](http://monoist.atmarkit.co.jp/mn/articles/1409/01/news013_2.html)

■注意
上記のプログラムはobnizの公式ページにある
[SEN0114 (Soil Moisture Sensor)](https://obniz.io/sdk/parts/SEN0114/README.md?iframe=false)
をもとに作っていますが、前提がSEN0114を使う想定のもののため、釘で自作したセンサーとは異なる動きなのかも。。。とりあえず動いた（濡れる＝数値があがる、乾く＝数値が下がる）のでそのまま使用しています。電子工作が得意な方、もし間違っていたらコメントお願いします。

###③ThingSpeakに上記値を送信
下記を参考にアカウントを作成して、Fild1（湿度用に設定した項目）に②で取得した値を付けて送信

>ThingSpeakの使い方の説明
>（参考サイト）[データを簡単に保存&グラフ化できるThingSpeakが便利！](http://iwathi3.hatenablog.com/entry/Data-to-Graph-ThingSpeak)

■データを送る部分
```
request.open("GET", `https://api.thingspeak.com/update?api_key=★ここにthingspeakのキーを入れてください★&field1=${value}`);
```
■画面
水をあげたときだけ湿度の数値が４まであがり、時間と共に徐々に下がっているのが分かります
![thingspeak.JPG](https://qiita-image-store.s3.amazonaws.com/0/181708/bfed9cd0-44d6-5b66-dd5e-244d952f3166.jpeg)


#感想
・ThingSpeakは電文を送るだけで、データが追加できるのでとても簡単で便利でした。
・さらに無料というのもうれしいです！
C＃PDF文書を作成する

日常業務では、PDFを作成する最も簡単な方法は、他のドキュメントフォーマットをWordのPDFなどのPDFドキュメントに変換することです。Spire.PDF for .NETは、.NETプログラムでPDF文書を作成、読み込み、書き込み、編集、操作するためのスタンドアローンのPDFコントロールです。Spire.PDFは、HTML、テキスト、イメージ、RTF、XPSおよび他のドキュメントフォーマットをPDFフォーマットに変換することをサポートしています。この記事では、簡単なPDFドキュメントを直接作成する方法を説明します。
ツールの使用：Spire.PDF for .NET。
アドレスをダウンロード：https://www.e-iceblue.com/Introduce/pdf-for-net-introduce.html
【C# 】

```ruby:Program.cs

//PdfDocumentインスタンスを初期化する
PdfDocument document = new PdfDocument();
//マージンを設定する
PdfUnitConvertor unitCvtr = new PdfUnitConvertor();
PdfMargins margins = new PdfMargins();
margins.Top = unitCvtr.ConvertUnits(2.54f, PdfGraphicsUnit.Centimeter, PdfGraphicsUnit.Point);
margins.Bottom = margins.Top;
margins.Left = unitCvtr.ConvertUnits(3.17f, PdfGraphicsUnit.Centimeter, PdfGraphicsUnit.Point);
margins.Right = margins.Left;
//新しいページを追加する
PdfPageBase page = document.Pages.Add(PdfPageSize.A4, margins);
//カスタムPdfTrueTypeFont、PdfPenインスタンス
PdfCjkStandardFont font = new PdfCjkStandardFont(PdfCjkFontFamily.HeiseiKakuGothicW5, 11f);
PdfPen pen = new PdfPen(Color.Blue);
//DrawStringメソッドを使用して、指定された場所にテキストを書き込む
string text = "私の最初のC＃PDFドキュメント";
page.Canvas.DrawString(text, font,pen,100,50);
//ドキュメントを保存
document.SaveToFile("PDF作成.pdf");

```


以下に示すように、実行中のプログラムをデバッグした後にドキュメントを生成する:
![1.jpg](https://qiita-image-store.s3.amazonaws.com/0/278784/5fc5ca39-f1d2-0fa9-a7c8-1e19bba14722.jpeg)
Androidで明示的に画面をOFFにさせない

## はじめに
動画系のアプリを作ることになって調べた時のメモです。

## 概要
Androidでは端末の設定次第で、操作がない場合一定時間経過後に画面がOFFになる挙動をとります。
今やどの動画再生系のアプリも常識的に実装されている機能だと思いますが、動画再生中に関しては画面を操作しなくとも画面がOFFにならないようにしないと、再生中も常に画面を触り続けないとならないストレフルな動画アプリになってしまいます。

##　実装
調べたところ、実装方法は2種類ありました。

### addFlagsする方法
Activity内で、 `FLAG_KEEP_SCREEN_ON`のフラグを追加します。
「フラグ立てるのはActivity内のみでな、サービスや他のコンポーネントではやるなよ。絶対にやるなよ。（意訳）」って書かれていました。

```kotlin:MainActivity.kt
class MainActivity : Activity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
    }
}
```

## レイアウトxml上でkeepScreenOn属性を有効にする方法

別の実現方法として、レイアウトファイル上でkeepScreenOn属性を有効するにする方法があります。

```xml:activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:keepScreenOn="true">
    ...
</RelativeLayout>
```

## 備考
どちらの実現方法でも同じ挙動になりますが、Activityのコード上で明示的にフラグを追加する方法の利点としては「動的にフラグを有効化/無効化することができる」とのことでした。

また、そもそも何故画面をOFFにしたくないのかの理由如何によっては別のアプローチを検討するべきのようです。

|理由|推奨|
|:--:|:--|
|長時間のHTTPダウンロード|[DownloadManager](https://developer.android.com/reference/android/app/DownloadManager)|
|外部サーバーとのデータの同期|[sync adapter](https://developer.android.com/training/sync-adapters/)|
|アプリがバックグラウンドサービスに依存している場合|[JobScheduler](https://developer.android.com/topic/performance/scheduling#js)もしくは[Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging/)|

## おわりに
開発中は `開発者向けオプション`の `スリープモードを有効にしない`をONにしながら開発を行っていたため、実際にアプリを使ったユーザーから指摘されるまで、動画再生中に画面がOFFになってしまう挙動に気づきませんでした:innocent: 
細かな部分ではあるかもしれませんが、動画再生系のアプリを作る際などは標準の挙動として抑えておくべきだと思います。

## 参考
https://developer.android.com/training/scheduling/wakelock
IntelliJ IDEAの設定やらフォーマットやら

メモ的な記事です。追加があれば増えます。

### フォーマットを部分的にオフにするコメントを有効化する
---
file -> settings ->  -> Code Style : Enable formatter markers in commentsにチェック
    // @formatter:off
    // 設定すると、ここの部分にはフォーマットが掛からない
    // @formatter:on

### 保存時に特定アクションを実行するプラグインを入れる（保存時にフォーマットかけるとか）
---
file -> settings -> Plugins -> Browse repositories -> Save Actions のプラグインを入れる
file -> settings -> Other Settings -> Save Actions 色々とあるがお好みで。

### コード重複の警告表示を消す
---
File - Settings - inspections - General Duplicated Code 　　のチェックボックスを外す

### コンソールのヒストリー数増やす
---
file - settings - General - Console

### 3行のメソッドを、ワンラインで表示する機能をオフにする（1行から3行表示になる）
---
IntelliJ
Settings > General > Code Folding を選択し、「One-line methods」のチェックボックスを外す

### タブが勝手にまとめられてしまうのでそれをオフにする
---
File - settings - Editor - General - Editor Tabs の「Hide tabs if ghere is no space」のチェックを外す

### SDKが自動で設定されていない場合、設定する
---
プロジェクトフォルダ右クリック - Open Module Settings - Dependencies - SDKを指定

### ソースコードの戻ると進むボタンを表示する
---

View - Toolbarにチェックを付ける（戻る・進むボタンを出す）

### IntelliJのフォーマッターをコマンドラインから掛ける方法（Ideaが起動していると実行できない）
---

基本は、下記を参照してほしいです。下記から抜粋しています。
[本家ドキュメント参照](https://www.jetbrains.com/help/idea/command-line-formatter.html)

```
linux
/home/user-hoge/idea-IU-181.4203.550/bin/format.sh

mac
/Applications/IntelliJ\ IDEA\ 15.app/Contents/bin/inspect.sh
```

`File - settings - Editor - Code Style`
`Scheme:の行の横の歯車ボタン`
から、設定をExportできる。
ExportしたIdeaの設定を指定したフォーマットも出来る

下記は、/tmpにExportした設定を読み込んだ場合の実行方法

```
/home/user-hoge/idea-IU-181.4203.550/bin/format.sh -s /tmp/Default.xml -r hogedir
```

拡張子指定も出来る

```
/home/user-hoge/idea-IU-181.4203.550/bin/format.sh -s /tmp/Default.xml -r -m *.js,*.html hogedir
```
新入社員がよくやるC/C++のミス

#新人教育を担当
新卒プログラマをそこそこ一人前にするのがミッション。
でも、コード書かせるとまぁまぁ同じようなミスをする。
よく使うのがC/C++なのでこんなタイトル。
言語関係ないものもあるかな

##free/deleteしない。間違っている
必ずやる。
単純な忘れ以外だと
delete[]　じゃない　とか、
newしたときのアドレスを持っていないか、変更してしまっている。

##sizeofでポインタを指定する
正しいこともあるんだけど、だいたい間違い。

##memmoveでなくmemcpyを使う
同一バッファ内で移動させたいときはmemmoveを使う。前づめとか。
memcpyで、領域が重なっていたときの挙動は不定…

##変数名がaとかbとか
リーダブルコード読んでもらってるんだけどなぁ
試行錯誤したコードをそのまま採用しがち

##コピペしてきたコードが動かない。説明できない。
必須のヘッダをインクルードしてないとか、変数名が違うとか。
理解しないでコピペするから、なんで動かないかわからない。
当然、コードの説明もできない。

##++hogeとhoge++の違いを意識しないで使う
あんまり使い分けることもない気がするけど
このミスで結構時間とられたみたい。
簡単に監査機能が実装できるlaravel-auditing が便利です


# Laravel Auditing とは

簡単にLaravelに監査機能を付け足すライブラリです。
公式サイト： http://laravel-auditing.com/



# 使い方

http://laravel-auditing.com/docs/7.0/installation

こちらにインストール方法が書いてあります。
5.4+ なら composer でrequire して

```sh
php artisan auditing:install
```

でファイル類をpublish、migrateするだけでインストールが完了します。

インストールが完了したら残りはModelを少し工夫するだけです。

http://laravel-auditing.com/docs/7.0/model-setup

こちらを参考に、Traitとインターフェースを取り込めば、あとは気にしなくても更新ログを残してくれます。


# 使い時

- 更新タイミングが謎な処理を解析するとき
- 深夜バッチの差分を確認したい時（そんな時間に起きてないよ！）
- 普通に監査機能が必要なプロジェクト
.vueの中でscss記述をする設定メモ

.vueファイル内styleタグでscss記述をしたかったが、ハマったのでメモ。
(ちなみにscssファイル自体からのコンパイルはgulp-sassをgulpfile.jsから設定し使用している。)

大体のサイトでは vue-cliを導入し lang="scss"つけたらすぐ使えると書いてあるが、vue-cliを入れてない場合はwebpack.configに自分でloaderを追加していなないと駄目みたいで、

```webpack.config.js
test: /\.vue$/,
        loader:"vue-loader",
        options: {
          loaders: {
            scss: 'vue-style-loader!css-loader!sass-loader'
          }
        }
```

これに加え、

```webpack.config.js
test: /\.scss$/,
        use: [
          'vue-style-loader',
          'css-loader',
          'sass-loader',
        ]
```

scss側にもvue-style-loaderを適用すると解決できた。
不要な記述などまだあるし全て把握してないけど、とりあえずは動作まで。
hubコマンド環境を整える　(Windows環境)

# hub環境を整えることになったきっかけ
ファイルの修正のアップ作業を別の開発者が受ける事があるので
Githubに使い慣れていない人でも
簡単にコマンドひとつでコミットからプルリクまでできるように
Gitのコミット～プルリクまで**自動化**したいのでhub環境を整えることに

プルリクコマンド**PullRequest**は　hubのコマンドなのでhubの使用環境を整える必要がある

## hubを直接インストール
hubコマンドを利用する為にhubをインストールする

1. [hubインストーラー](https://github.com/github/hub/releases)をダウンロードしinstall.batをたたく（ここでは**hub 2.5.0 for Windows 64-bit**)
2. 以下のように表示されればOK
```
hub version
hub version 2.3.0
```

## Gitアカウントの入力
hubコマンドを最初に実行した時にusernameが求められるのでGitアカウントを入力してください。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/278660/2e947903-9315-141e-b987-29c5e4e2d756.png)


## Cmderをインストール
hubコマンドを実行するターミナル環境はCmderをインストールする

1. コンソールとしてCmderをインストールする。
2. user-aliases.cmdの最終行に`git=hub $*`を追加
3. 再起動して`git version`を入力
以下のように表示されればOK
```
git version
git version 2.16.2.windows.1
hub version 2.3.0
```

## hubコマンドを使ってみて
### pull-requestのオプション
```
pull-request [-focp] [-b <BASE>] [-h <HEAD>] [-r <REVIEWERS> ] [-a <ASSIGNEES>] [-M <MILESTONE>] [-l <LABELS>]
pull-request -m <MESSAGE> [--edit]
pull-request -F <FILE> [--edit]
pull-request -i <ISSUE>
```
### pull-requestエラー[プルリクコマンド時に以下のエラーメッセージが表示される場合]
___
- Error creating pull request: Unprocessable Entity (HTTP 422)

```shell-session
git pull-request
Error creating pull request: Unprocessable Entity (HTTP 422)
No commits between develop and develop
```

こちらのエラーはプルリクのコマンドを正しく指定していない時に起こりました。
以下の様にコマンドを正しく指定しないと実行できません。

```shell-session
git pull-request -b develop -h develop_0806
```


例　-b　はbaseマージ先ブランチ名
　　-h　はマージしたいブランチ名(主に修正したもの）
___
- error using text editor for pull request message

こちらのエラー以下実行で解消しました。

```shell-session
git config --global core.editor Cmder`
```

これをしても解消しない場合は

```shell-session
`git config replace-all core.editor Cmder.exe`
```

## 注意点
- hubコマンドはCmderで実行する
- Win\Macとは手順が違うので注意

## 参考資料
[ハブコマンドを使ってみた](http://ytyaru.hatenablog.com/entry/2016/10/22/100000)
Mac High Sierra に compass をサクッとインストールする方法

従来の Ruby Sass を High Sierra にインストールする方法です。

Homebrew、Anyenv、npm、gulp とかは置いといて（LibSass node-sass を使わないで）、サクッと　compass を動かしたい時に。。

---
### インストール


環境：macOS High Sierra

1.Xcode Command Line Tools のインストール

```
$ xcode-select --install
```
2.Sass のインストール

```
$ sudo gem install -n /usr/local/bin sass
```

3.Compass のインストール

```
$ sudo gem install compass
```

おしまい。

---
以下、検索用のエラー文言

Command Line Tools をインストールする前に、
SASS をインストールしようとして、ERROR になる。

```
$sudo gem install sass
Building native extensions.  This could take a while...
ERROR:  Error installing sass:
    ERROR: Failed to build gem native extension.

    current directory: /Library/Ruby/Gems/2.3.0/gems/ffi-1.9.23/ext/ffi_c
/System/Library/Frameworks/Ruby.framework/Versions/2.3/usr/bin/ruby -r ./siteconf20180228-5487-11of4og.rb extconf.rb
mkmf.rb can't find header files for ruby at /System/Library/Frameworks/Ruby.framework/Versions/2.3/usr/lib/ruby/include/ruby.h

extconf failed, exit code 1

Gem files will remain installed in /Library/Ruby/Gems/2.3.0/gems/ffi-1.9.23 for inspection.
Results logged to /Library/Ruby/Gems/2.3.0/extensions/universal-darwin-17/2.3.0/ffi-1.9.23/gem_make.out
```

---
### アンインストール


```
$ sudo gem uninstall compass
```

```
$ sudo gem uninstall -n /usr/local/bin sass
```
「?.」検索できないアレは「Optional Chaining」undefinedでなければチェイン

「プロパティがnullでなければ参照したい」
「変数がnullでなければメソッドを実行したい」
そんな感じの記述がなにか思い出せなくて悩んだ話。[^1]
[^1]: 正しくはnullでなくundefinedなのかな？

タイトルで終わっているので以下雑談。

最初は「||.」だったかなと思って
「たてせん パイプ null」
などとググって失敗。

そもそもどの言語で見たかも思い出せない。
Rubyが記号(!?)を使うことが多そうなので、
「ruby nil check」
を調べて失敗。

トリッキーな書き方なのでAltJS系だろうと、CoffeeScriptを調べて失敗。

見かけた記憶が少ないので、検討中の新機能の線を疑う。

PHPかな？
[PHP7.2の新機能 - Qiita](https://qiita.com/rana_kualu/items/40ebed78742bfdbd1065)
違う。
PHPで入ったのは`??`だし。
でも確かこんな感じだった気がする…

他に新機能チェックするのはJSぐらいなので、「ES2018」で検索。
[ES2018で追加される機能まとめ - Qiita](https://qiita.com/Yuta_Yamamoto/items/dc083fb8855e314b86d7)
ちがう
[2018年に見直した現代的なJavaScriptの記法を紹介するぜ - ICS MEDIA](https://ics.media/entry/17262)
ちがう

うーん…
でもやっぱりJSで、やっぱりrana_kualuさんの記事っぽかったよなあ
ということで
[rana_kualu - Qiita](https://qiita.com/rana_kualu)
のitemを漁って、発見
[これから来そうなJavaScript新機能3選 - Qiita#1-optional-chaining](https://qiita.com/rana_kualu/items/9d9cf20ab5019143fdcb#1-optional-chaining)

proposalということでまだ全然使えないし、babelならなんとか`stage-0`。
でもない。
[Babel v7でStage Presetが削除される - Qiita](https://qiita.com/rana_kualu/items/20139057ea45d0321af3)
そうです。


[JavaScriptを読んでて「なにこれ！？」と思うけれど調べられない記法8選。 - Qiita](https://qiita.com/ukiuni@github/items/5f3d8620187905aea3d4)
に追加されててもいいレベル。
Adobe Illustrator から吐き出すSVGについてのメモ

#この記事について
完全なメモです。
#イラレのDPIとPPI
イラレはもともとベクター画像の生成ツールなので、
解像という概念を気にする必要はあまりない。
・・・が、SVGやJPEGとして吐き出すときには気にする必要が出てくることがある。
下記はSVGに限った話。

まずptのスタンダードな大きさは
DTPポイントと言われ、72ppi(1 pt = 1/72 in. = 0.352 777 7... mm)である。
※Wikipedia調べ

次にpx。
PC的にスタンダードなのは
Windowsなど 96dpi(1px = 1/96 in 0.2646) 
Macなど     72dpi(1 pt = 1/72 in. = 0.352 777 7... mm)
である。

ではDTP的にというと、
「72dpi」が一般的らしい。

で、イラレが吐き出すSVGも72dpiで72ppiであるようだ。

つまりイラレが吐き出すSVGは　1pt = 1pxで、72px＝1inch=25.4mmなのである。

ちなみにCSSのpxは96dpiでptは72ppiで計算されているらしい。

#matrix
マトリクスはアフィン変換行列のこと。
これ一つで、並行移動(translate)、拡縮(scale)、回転(rotate)、剪断(skew)を表現できる。
変換ロジックについては私はよくわかっていないので勉強しないといけない

で、変換行列の中で変な値を見つけた
6.985714e-10
e-10<=ってなんやねんとなって調べたところ、
6.985714 × 10の-10乗って意味らしい。つまりこの場合
6.985714e-10 = 6.985714 * 10000000000 = 0.0000000006985714
ということになる。
Faust:単純なディレイを作った

小ネタです。

微妙なタイミング合せの必要があって、単純に遅らせるだけのプラグインを作ってみました。

```c:
declare name "simpleDelay";
import("stdfaust.lib");

process = monoDelay, monoDelay;

monoDelay = de.sdelay(N, it, dt);
N = ma.SR/10;
it = 1024;
dt = ma.SR * hslider("time[unit:ms]",0,0,100,0.1) / 1000;
```
[Faust Libraries #de.sdelay](http://faust.grame.fr/library.html#de.sdelay)によれば、sdelayというのがsmooth delayってことらしい。dtを動かしてもノイズが出ないとか。
でも、すこしは出るので用途によってはitの値を調整する必要があるのかも。

これをFaustLive.app でVSTプラグインにしました。
<img width="525" alt="スクリーンショット 2018-08-07 15.48.22.png" src="https://qiita-image-store.s3.amazonaws.com/0/61597/da452cb1-3737-419e-2817-31aea28a6aa2.png">
ちゃんと使えてます。かゆいところに手が届く感じでちょっと嬉しい。
Rubyで標準入力をしてみる

最近Rubyを書きはじめました。

Rubyを勉強していく中で自分が感じたことや、学び取ったことを書いていきたいと思います。

初回の今回は、Rubyでの標準入力について書いてみます。


#Rubyでの入力

Rubyでは標準入力のメソッドとしてgetsがあります。
ただ、普通に入力してしまうと改行文字がその中に含まれてしまいます。

```.rb
a = gets
puts "私は「#{a}」と言った"
```
例えばこれを実行して「こんにちは」と入力してみましょう、すると

```
こんにちは
私は「こんにちは
」と言った
```

といった具合に出力されてしまいます。

ここで入力された文字を正確に見てみるためにpで出力してみると

```.rb
p a
#=> "こんにちは\n"
```

こんな風に表示されます。
これからわかるように改行文字の"\n"が入力した文字に含まれています。

これを解消するために.chompを使用してみます。

```.rb
a = gets.chomp
puts "私は「#{a}」と言った"
```
すると

```
こんにちは
私は「こんにちは」と言った
```
という感じで、欲しい出力が得られました。

#最後に
自分は初めて記事を書いたわけですが、今までこういう風に自分で学んだことを記事にして様々な人に知らせたり、意見をもらい改善するという環境・気風があることを全然知らなかったのでとても興味深いと感じました。

今回は「入力について」という初歩的な内容ですが、これから学び取ったことを色々と共有していきたいと思います。またこれが次にRubyを始める人の参考になれば幸いです。