OmniAICreator/Qiita-1.07M huggingface dataset:
Laravel のバリデーションルール exists に Eloquent を使う

千株式会社の初 Advent Calendar、私の初 Qiita !

追記：強化版ができました
[Laravel のバリデーションルール exists に Eloquent を使う v2](https://qiita.com/mikankari/items/a44fe1e0a7510cb15c52)

## 背景

Laravel の DB レコード存在チェックをするバリデーションルールとして [exists](https://laravel.com/docs/5.7/validation#rule-exists) がある

しかしハードコーディングな要素が多いので、Eloquent を使って要素を意識させないようにしたい

例えば、ソフトデリートを考慮するには、

- テーブル名
- 検索するカラム名
- ソフトデリートのカラム名
- ソフトデリートの削除されていないときの値

を知って、コントローラかフォームリクエストに書く

```php
'id' => [
    'required',
    'integer',
    'exists:hoges,id,deleted_at,null', // これ
],
```

Eloquent を使っていると、グローバルスコープでカラム名やその値を意識せずに書けるので、バリデーションもそうしたい


## 解決策

カスタムバリデーションルールのなかでは、[ルールオブジェクト](https://laravel.com/docs/5.7/validation#using-rule-objects)がシンプルに書けるので使う


ルールオブジェクトのクラスのソースコードが次
コンストラクタが使われていないので、そこでモデルクラスを渡す

```php
<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class Exists implements Rule
{
    protected $modelName;
    protected $propertyName;

    public function __construct(string $modelName, ?string $propertyName = null)
    {
        $this->modelName = $modelName;
        $this->propertyName = $propertyName;
    }

    public function passes($attribute, $value)
    {
        if ($this->propertyName === null) {
            $this->propertyName = $attribute;
        }

        return $this->modelName::where($this->propertyName, $value)->exists();
    }

    public function message()
    {
        return ':attribute はデータが存在しません';
    }
}
```

## 使い方

リクエストのフィールド名と同じカラム名で探すなら

```php
use App\Hoge;
use App\Rules\Exists;
```

```php
'id' => [
    'required',
    'integer',
    new Exists(Hoge::class), // これ
],
```

と書けば、ソフトデリートなどのグローバルスコープも考慮してくれる

リクエストのフィールド名と異なるなら、カラム名を指定できる

```php
'hoge_id' => [
    'required',
    'integer',
    new Exists(Hoge::class, 'id'), // これ
],
```

すっきり！


## 追伸

使ってみるとカラム名を指定することが多い＆主キーで探すことが多いので、指定がないときはフィールド名と同じではなく主キーのほうがより良さそう

あとで変えるかも
ElasticStackで機械学習Tips～Model Boundsを表示して分かりやすく

# はじめに
ElasticStackに触れ始めて約3ヵ月の初心者ですが、そろそろナレッジも貯まってきたので少しずつアウトプットしてみたいと思います。
第一段として、Advent Calendar3日目の記事を書かせていただきます！

# 環境
この記事ではCentOS 6.8上にElasticStack 6.4.0を稼働させています。

# Model Boundsってなんだ？
Model Boundsというのは、機械学習のジョブがデータの振る舞いを学習した結果、「正常な状態であればこの範囲内を推移する振る舞いをするはずだ！」と判定された範囲のことを指します（以下の画像[^1]の中の薄い青色の帯）。
[^1]: elastic公式より引用。https://www.elastic.co/jp/products/stack/machine-learning
このModel Boundsから実際の値が乖離すればするほど「異常な値」と判定されることになります。
![machine-learning-forecasting.jpg](https://qiita-image-store.s3.amazonaws.com/0/236354/99d7bfaa-4bc3-4df4-ee98-1e25d02ec0d9.jpeg)


このModel Boundsが見えていると、学習モデルがデータの振る舞いをどう捉えているのかを視覚的に分かりやすいですね。


# でもデフォルトでは非表示

こんな便利なModel Boundsですが、Multi Metricジョブを作成するとき、どうやらデフォルトでは表示されません。
普通に機械学習のジョブを作ると以下のように`学習データの推移`が見えるだけとなります。
![Model_bounds_not_available.png](https://qiita-image-store.s3.amazonaws.com/0/236354/fb0b27b4-2f43-156c-aa48-6467a785d314.png)


# 解決策
Model Boundsを表示させるには、機械学習のジョブを作成するときにJSONを直接編集すればOKです。
analysis_configの後に以下の設定を追記してください。

```
  "model_plot_config": {
    "enabled" : true
  },
```

![EditJson画面](https://qiita-image-store.s3.amazonaws.com/0/236354/84289b61-bd80-bf26-d2b9-a3502287c6ef.png)

再度学習させると以下のとおりModel Bounds（薄い青色の帯）が表示されました！

![Model_bounds_available.png](https://qiita-image-store.s3.amazonaws.com/0/236354/ae8fe128-a5c8-e199-04c5-a90e43a4cffc.png)



## 注意点
- 「EditJson」 は `Advanced wizard` に切り替えないと表示されません。もし `Single Metric wizard`や`Multi Metric wizard`を使って機械学習ジョブを作成する場合、作成の最後に saveボタンの真上くらいにある`Move to advanced job configuration` のリンクから Advanced wizardに切り替えてから操作してください。
- 一度作成したジョブ自体をあとあからjsonをいじることはできません。既存のジョブをcloneしてからjsonをいじる必要があります。
- 学習データのカーディナリティ[^2]が高いとそもそも「Model Bounds表示すると大変なことになるよ？」と諭されてしまいます。
どうやらModel Boundsのサーバリソースを多く食ってしまうため、システム的にキャップが掛かっている様です。
試した感じ、カーディナリティが100以下なら諭されずに設定出来ました。

![validate-mljob.png](https://qiita-image-store.s3.amazonaws.com/0/236354/bebb7a40-638a-d9c5-946e-11a25dda84b7.png)




# まとめ
機械学習における学習モデルはどうしてもブラックボックスな感じになってしまうので、それがModel Boundsで可視化できるのは非常に分かりやすいですね。
制約もありますが、使える場合は積極的に使っていく方がよいと思います。

ということで、次は [whale_shark](https://qiita.com/whale_shark) さんの「Beatsシリーズへの貢献するには」になります。お楽しみに！

[^2]: カーディナリティってなんだよ？って思った方は以下の記事が分かりやすいと思います。https://qiita.com/soyanchu/items/034be19a2e3cb87b2efb
ExcelのDATE関数で月途中の〆処理 (2018年13月1日って?!)

# Excelの関数で月途中の〆処理

Excelで毎月15日〆の処理が必要だったときに、複雑な考え方をしていたら、DATE関数の仕様でサクッと解決してしまったので、備忘録として。

まず、`$A$1` (別に`TODYA()`でも構わないのですが) に日付が入っているとして、`DAY($A$1)<=15`なら単純に`$A$1-DAY($A$1)+1`で計算できるけど、`DAY($A$1)>15`なら翌月にしなければならないし、年末は更に翌年になるし、式が複雑になるな～とセルの中に複雑な式を組み立てていました。

でもね。

ふと、**セルに`=DATE(2018,13,1)`と入力すると`2019/1/1`って表示されるじゃないですか?!**
目からウロコの一瞬でした。そんな訳で、15日以前なら当月1日、16日以降なら翌月1日と計算する式は以下のようになりました。

```
=DATE(YEAR($A$1),MONTH($A$1)+IF(DAY($A$1)<=15,0,1),1)
```

ちなみに13ヶ月後とかも以下のような式でできました。

```
=DATE(YEAR($A$1),MONTH($A$1)+13,DAY($A$1))
```

う～む、DATE関数恐るべし。
herokuでrubyのバージョンに合わせてherokuのバージョンを下げる

herokuでデプロイする際に現状のruby(2.3.1)をバージョンアップが難しくheroku側で対応する際にうまく行かなかったのでメモ。

ターミナルから

```
heroku stack:set heroku-16
```
と打ってもエラーが出る。

```
 >   Error: Missing required flag:
 ›     -a, --app APP  app to run command against
 ›   See more help with --help
```

```heroku help```で確認するとアプリケーション名を明示しないといけないようだ。だが、今の所アプリはなし。そこで先に```heroku create```して

```
heroku stack:set heroku-16 -a [app-name]
```
で解決。
メソッド名の暗黙的ルールとその他

随時更新

##メソッド名
### 既存の名前を敢えて変えるのは混乱するのでやめたほうがいい
特に複数人で開発されている環境において、名前を統一しないとよくわからない変数が乱立したり その変数になにが入っているのか元の処理を確認する手間が生まれて効率が悪くなる。

### 主語がないと対象を具体的に掴むことができない
EX. parseJsonToString
"JSONをStringに変換する"機能を持っている

### クラスと変数
クラスは１文字目は大文字 ex. class Japan
変数は１文字目は小文字　ex. var tokyo

## その他
### for
for-in文は、役割的に一方を複数形の名称、
一方を単数形の名称にするのが正しい

### Bool
Boolの変数名はis-- で表現するのが一般的。
ex.isGetOn
DBから取得した値がnilでエラーになったので調べた

## 起きたこと
以下のようなユーザーをDBから取得する関数を記述していた。

```go
func (u *User) Find() error {
	if err := connector.Postgres.QueryRow(`SELECT id, uuid, name, encrypted_password FROM users where email = $1`, u.Email).Scan(&u.ID, &u.UUID, nullName, &u.EncryptedPassword); err != nil {
		return err
	}
	return nil
}

```

実行すると、以下のエラーが出た。

`unsupported Scan, storing driver.Value type <nil> into type *string`


## 原因
usersテーブルのnameの値が`null`だったことが原因。
Scanメソッドは`*Row`から該当するフィールドをコピーする。
このときカラムがnullだと割り当てるポインタがnilになる。

そしてstring型はゼロ値が""（空文字）でnilに対応していない。
DBからの取得結果がnilだったのにu.Name（string型）に値をコピーしようとしたことが原因だった。

## 解決案
`database/sql`パッケージに`NullString`があるので、それを使う。
NullStringはScanerインターフェースを実装してるので、スキャンのコピー先として使える。

使い方は、前もってNullString型の変数を定義しておき、
Scanメソッドの引数として渡し、値をコピーする。

nullStringはStringとValidというフィールドを持ち、ValidはStringがNULLでないときにtrueになっている。
これを利用して、条件分岐をする。
Validがtrueなら、文字列を使用する（自分の場合はインスタンスのフィールドに値を代入した）
falseならよしなにできる（自分の場合は空文字を代入した）

```go
func (u *User) Find() error {
	nullName := new(sql.NullString)
	if err := connector.Postgres.QueryRow(`SELECT id, uuid, name, encrypted_password FROM users where email = $1`, u.Email).Scan(&u.ID, &u.UUID, nullName, &u.EncryptedPassword); err != nil {
		return err
	}
	if nullName.Valid {
		u.Name = nullName.String
	}
	return nil
}
```


## 参考
[database/sql#NullString](https://golang.org/pkg/database/sql/#NullString)
[unsupported Scan, storing driver.Value type <nil> into type *string](https://github.com/mattn/go-sqlite3/issues/389)

## あとがき
SQLで`SELECT IF(name IS NULL, "", name)`みたいにしてもいけるのでは？と思った。

Goを始めて2ヶ月くらいの初心者なので、コードでおかしいところ、もっときれいに書けるところなどありましたら、
コメントなどで指摘してもらえると嬉しいです。
gradlewコマンドを実行したくてJDK 11をインストールしてしまった時の対処方法


新しいMacでAndroidアプリをコマンドラインからビルドしようとしたらJDKが入ってないと怒られた
何も考えずにJDKをインストールしたところ、以下のエラーが表示された

```
Could not determine java version from '11.0.1'.
```

上記でググると色々出てくるが、11.0.1は利用できないようである。
仮の対応としてJDKの８を利用するように設定する。

JDKの８をインストール
https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

JAVA_HOMEを設定

```gradle:.bash_profile
export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home/
```
上記を追加してsoruce .bash_profile を実行

何か他に良い解決方法があれば、教えてください

# 参考
https://stackoverflow.com/questions/32796797/android-studio-could-not-determine-java-version
表示名(tag:Name)に任意の文字列が含まれた停止済みのEC2インスタンスの一覧を表示するコマンド

ドンピシャなコマンドが探しても見当たらなかったので

```
aws --profile [プロファイル名] ec2 describe-instances \
--query 'Reservations[].Instances[].Tags[?Key==`Name`].Value[]' \
--filter "Name=instance-state-name,Values=stopped"  "Name=tag:Name,Values=*[任意の文字列]*"| sort
```
削除機能の設計(物理削除とは/論理削除とは)

#背景
ECサイトで商品削除機能を追加する際、物理削除と論理削除を明確にしてから実装設計に着手する。
(自分用メモ)

#物理削除とは
データをDELETE(Railsだとdestroy)でデータベースから完全に削除すること。
データは完全に削除され復元や参照が出来ない。

#論理削除とは
実際に削除するのではなくデータベースに削除の目印(フラグ)を設定し、削除フラグをもつデータは表示させないことでユーザーには削除しているかのような振る舞いに見せること。
###メリット
・謝って削除したデータを復元できる。(後からメーカーに商品を復活してほしと以来された時も過去のデータをそのまま復元できる)
・削除したデータも参照できる
###デメリット
・物理削除よりも処理が複雑（考慮すべき項目が増える）
・データ表示の際where句で絞り込みを行うのに削除フラグの条件を追加する必要がある(コードが削除フラグだらけになる)
・データが増加し続け、データベースの容量の圧迫・パフォーマンス性の低下を起こす可能性がある

#物理削除と論理削除どちらが良いのか
基本的にデータの削除自体が推奨されていない。
例えば１度オーダーのあった商品を削除してしまうと、オーダー一覧には存在するのにその商品データは存在しないという状態はバグを引き起こす一因になってしまう。
一方で、販売中止になった商品がいつまでも商品一覧に残っているのは運営管理者には作業の非効率化に繋がる。
また論理削除デメリットにも上げた通りデータ量の増大に伴う検索等のパフォーマンスの低下にも繋がる。

大切なのは業務要件を踏まえて残すべきデータ・物理削除するデータ・論理削除するデータを精査すること。
また論理削除したデータについても一定の期間を過ぎたものは物理削除するなどのメンテナンスも必要。


#商品(product)削除の設計[自分用メモ]

自分メモ用なのでデータ構造については省略

***①関連テーブルを洗い出す***
・productのPK(プライマリーキー)を持つテーブル（product_idを参照しているテーブル）の洗い出し
・productが参照しているFK(フォーリンキー)のテーブル洗い出し
・上記２つを元にER図を作成

***②商品と紐づけて削除するテーブルと残しておくテーブルを分ける***
例)
メーカー・・・残しておくテーブル
カテゴリー中間テーブル・・・削除するテーブル
削除する場合→depedent::destroy

***③削除するテーブルの中で論理削除か物理削除か分ける***
例)
カテゴリーの中間テーブル・・・物理削除
オーダーの中間テーブル・・・論理削除
※論理削除はgem:paranoiaを使用
Slack チャンネルごとにメールを受け取れるようにした話

:christmas_tree: k この記事は [JX通信社 Advent Calendar 2018](https://qiita.com/advent-calendar/2018/jxpress) の 3 日目の記事です。

---

Slack のメール連携を便利にしてみた話。


![image.png](https://qiita-image-store.s3.amazonaws.com/0/25168/f4eabc4e-bbd1-878a-315c-d8dae3b82eef.png)

皆さん、Slack のメール連携って利用されていますか？
Slack 公式のプラグインでメールを直接チャンネルで受け取ることができるようになっています。
外部との連絡も Slack で完結し、受信者だけでなくチームにも内容を共有できるので便利ですよね。

ただ、このプラグインによる連携、運用しているといくつか手の届かないところがあります。

* タップしないと詳細がわからない
* 1 チャンネルごとにメアドを生成しないといけない
* メンション飛ばしたりなどのカスタムができない

具体的にはこのあたりですね。
特に日本語のメールはタイトルだけでは内容が分からないものが多いので、タップしないと詳細が読めないというのは不便です。

そこで自作のメール連携を作って便利に使おう！というのが今回の趣旨になります。

## 作ったメールサービス
最初に完成形から。

|![image.png](https://qiita-image-store.s3.amazonaws.com/0/25168/cd48f109-0d91-ab2b-2247-66580c9f4fb5.png)|
|:-:|
こんなメールを今回作成したシステムのメール宛に飛ばすと、以下のような感じで Slack に届きます。

|![image.png](https://qiita-image-store.s3.amazonaws.com/0/25168/64d64ba2-530b-5d42-030a-cc7aad2f08bf.png)|
|:-:|


Slack 上でのフォーマットの仕方についてはまだ改善の余地がありそうですが、Python で本文が取れる状態になっているので、変えたい人に変えてもらうというスタンスです。`#WelcomeContribution`
カスタマイズの方向性としては、送信元に応じて表示フォーマットを変えたりだとか、特定のキーワードでメンション飛ばしたりだとかいろいろできそうです。

### 任意チャンネルへ送信
このシステムもう一つ仕掛けがあって、なんと任意のSlackチャンネルにメールを送れます。

```
{チャンネル名}@{メールのドメイン}
```

というメールアドレスに向けてメールを送るだけです。

仮にドメインを `channel.example.com` とするなら、

* `general@channel.example.com` で `#general` チャンネルに
* `test@channel.example.com` で `#test` チャンネルに

といった使い方ができます。
ドメインを覚えてしまえば、もういちいちメアドを発行する必要はありません。

|![image.png](https://qiita-image-store.s3.amazonaws.com/0/25168/a9409805-8de1-86d2-67b9-209aec6df32b.png)|
|:-:|

一つ問題があるとすれば、日本語チャンネルには RFC 5321 の規約上送れないということですね…。
Base64などでエンコードしてしまう手はありますが、エンジニア以外だと利用するのが難しくなってしまいそう。

## サーバレスなメールシステム
続いて、メール連携のシステムについて紹介していきます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/25168/e3c1898a-f0a0-35e1-034e-bc4d9336f89e.png)
このメールシステムは AWS を利用して、[^serverless]サーバレスな構成で実現しています。


SES(Simple Email Service) というサービスを利用すると、メールの受信から AWS 内の他サービスへの受け渡しまでをまるごと面倒見てくれます。
メールサーバーの構築や運用は自分でやろうとするとかなり大変ですが、こうやってサービスとして提供されているとありがたいですね。
受け取ったメールをS3 へ保存し、同時にメールを処理するための Lambda を発火させてあげます。

```python3
def lambda_handler(event, context):
    for mail in event['Records']:
        if 'ses' not in mail:
            continue
        mail = mail['ses']['mail']
```

Lambda ではイベントという形でデータが (ときには複数まとめて) 送られてくるので、上記のように SES のメール情報を取り出してあげます。

```python3
        obj_id = mail['messageId']
        obj = bucket.Object(f'{obj_id}')
        raw_mail = obj.get()['Body'].read()
```

このメール情報にはメール本文自体は含まれないので、別途 S3 に保存したデータを messageId から持ってきてあげる必要があります。

これで Slack に送るのに必要な情報が揃いましたね。
あとは煮るなり焼くなり好きにいじって Slack に送るだけです。


https://gist.github.com/pistatium/defe9cd71a9d0487b92d922f871ddbfa
Slack への送信等は改めて説明するほどでもないので、こちらにサンプルのソースを置いておきます。
メールの生データを処理するのが結構鬼門ですが、一応 Python の標準ライブラリで処理することが可能です。
サンプルだと HTML タグはすべて外してしまってますが、うまくやれば Slack 表記に変換してあげるとかもできそうです。


[^serverless]: <宣伝>サーバレスについては (私を含め) 弊社エンジニアが執筆した[こちらの特集](https://gihyo.jp/magazine/wdpress/archive/2018/vol105)が参考になるかもしれません。</宣伝>
機能変更による影響範囲可視化の第一歩

#背景
- 過去から、市場不具合の中で影響範囲の考慮が漏れており、テスト範囲外とした箇所で発生する不具合の割合が**全体の3割**を占めている
- 内容を分析するとQAチームでの考慮漏れもあるが、開発チームでも考慮できていないケースが多かった
- そこで、影響範囲を可視化することで、QA/開発双方で、影響範囲を想定しやすくする環境を構築中
<img src="https://qiita-image-store.s3.amazonaws.com/0/312027/7a192315-ddd7-73f5-4a52-fd4b58a02a34.png" width="600px">

#ゴール
- 影響範囲の考慮漏れが起因する市場不具合数の削減

#市場不具合をベースに可視化
- 全ての機能の影響範囲を可視化することは難しいため、市場不具合をベースに、変更元の機能と発生先の機能をラベリング
<img src="https://qiita-image-store.s3.amazonaws.com/0/312027/d05ced8e-214d-b038-1f51-853ef76f6e9b.png" width="700px">

- 上記ラベルを基にして、**変更元の機能**と**発生先の機能**の2軸で表を作成
<img src="https://qiita-image-store.s3.amazonaws.com/0/312027/3680b5a1-616d-6ddc-f7b6-1493cabbc4fa.png" width="700px">

#テスト設計時とテスト実行中の不具合修正時に参照
- 上記可視化した表を基に、以下のタイミングで利用

|フェーズ|概要|
|:----------|:----------------------|
|テスト設計|機能変更時、影響表から該当の変更元機能を探し、影響先機能を**テスト設計に含める**|
|テスト実行|開発側の不具合修正時、影響表から該当の変更元機能を探し、修正確認時に、**修正箇所に加えて確認**を行う|


#運用は開発側と連携
- 市場不具合の発生した機能は、QAチーム側でも把握できる部分もあるが、変更元の機能は見えない部分が多いため、ラベリングは**開発チーム側に依頼**
<img src="https://qiita-image-store.s3.amazonaws.com/0/312027/4b0e9bf0-6b72-2385-af70-435b333d4041.png" width="700px">
- 導入時のみ、直近3ヵ月の市場不具合を一気に分析し、以降毎週発生した市場不具合に対して、ラベルを入力する運用に移行

#導入結果
- 市場不具合ベースのため、見える範囲は限定的だが、導入前と比較すると、影響範囲の考慮漏れによる市場不具合数を**半減**させることに成功
<img src="https://qiita-image-store.s3.amazonaws.com/0/312027/57a73d97-7db9-4203-6366-3cdf4330bdba.png" width="600px">


#現状の課題と今後の発展
- 普段の分析プロセスはBTSで実施しているが、今回はトライアルで別途スプレッドシートを用いてラベリングしたため、まだQA側から定期的に入力リマインドが必要な状況
- 今後は完全なフロー化に向けて、BTS側を改修し、ラベルを設け、既存の市場不具合分析プロセス内で対応する運用を検討中
- また、今回は市場不具合だけを対象としたが、次はQA中の不具合も対象にすることで、より信頼性を高めた形で、影響範囲を可視化していきたい
Javascriptの理解を深めるクイズ

## 問1

AとB どちらかの記述は誤りである

### A

```javascript
let a = 10;
if (a <= 0) {
    console.log(a);
} elseif {
    while (a >= 0) {
        console.log(a);
        a--;
    }
}
```

---
<!-- *template: invert -->

### B

```javascript
let a = 10;
if (a <= 0) {
    console.log(a);
} else while (a >= 0) {
    console.log(a);
    a--;
}
```

---
<!-- *template: gaia -->

### 答え: 誤りは `A`

**Javascriptに `elseif` も `else if` も実は無い**

```javascript
} else {
    if {
    	・・・
    }
}
```

の短縮表記が **こう**

```javascript
} else
	if {
		・・・
	}
```

---
<!-- *template: gaia -->

なので

```javascript
} else
	while (a >= 0) {
		・・・
	}
```

```javascript
} else while (a >= 0) {
		・・・
	}
```

```javascript
} else while (a >= 0) {
	・・・
}
```

と、書けるので `B` は有効で  
`A` は未知の構文として***シンタックスエラー***となる

---
<!-- *template: invert -->

## 問2

AとB それぞれのコードの実行結果として
コンソールにはどうログ出力されるか？

### A

```javascript
function f() {
  let x = 1;
  console.log(x);
  {
    let x = 2;
    console.log(x);
  }
  console.log(x);
}
f();
```

---
<!-- *template: invert -->

### B

```javascript
function f() {
  var x = 1;
  console.log(x);
  {
    var x = 2;
    console.log(x);
  }
  console.log(x);
}
f();
```

---
<!-- *template: gaia -->

### 答え: `A`は `121` `B`は `122`

**Javascriptは `{ let xxx }` でブロックスコープを作れる**

```javascript
  let x = 1;
  console.log(x);
  {
    let x = 2; ← このxは別のスコープになる
    console.log(x);
  }
  console.log(x);
```

---
<!-- *template: invert -->

## 問3

`let b`の型は何が返ってくるか

```javascript
function a<T>(x: T): T {
  return x;
}

let b = a("123");
```

---
<!-- *template: gaia -->

### 答え: `引数で渡した型情報`が返ってくる

**Javascriptも `<T>` で `Generics` が使える**

```javascript
           ↓ Tと言う仮想の型を定義
function a<T>(x: T): T {
                     ↑ 返却する変数の型を仮想のTとする
                 ↑ 引数で受取る変数の型を仮想のTとする
  return x;
}

let b = a("123");
    ↑ 型Tはつまり引数指定した`文字列型`となり
    返ってくる型Tは文字列型となる
```

---
<!-- *template: invert -->

## 問4

AとB 正しく実行されるとそれぞれどうなるか

### A

```javascript
var a = 'hoge';
(function(){
	console.log(a);
})();
```

### B

```javascript
var a = 'hoge';
!function(){console.log(a);}();
```

---
<!-- *template: gaia -->

### 答え: 全く同じ用に `hoge` と出力され、実行に違いは無い

**`()();` も `!();` も `即時実行関数` のバリエーション**  
古いJS仕様には無かった `ブロックスコープ` の代用と言う用途で利用されている

```javascript
!function(){
	var a = 'hoge';
}();
console.log(a);
```

この場合は `a` は即時関数内と外でスコープが区切られる為***コンソールには何も出力されなくなる***

---
<!-- *template: invert -->

## 問5

AとB それぞれのコードの実行結果として、コンソールにはどうログ出力されるか？

### A

```javascript
(function ($) {
	let a = $("body").text();
	console.log(a);
})(jQuery);
```

---
<!-- *template: invert -->

### B

```javascript
(function (_) {
	let a = _("body").text();
	console.log(a);
})(jQuery);
```

---
<!-- *template: gaia -->

### 答え: どちらもbodyが出力され、実行に違いは無い

**javascriptは変数名に `$` と `_` が利用出来る**  
**なので`$` や `_` に特別な言語仕様は無く変数名である**  

```javascript
(function (htmlDomObj) {
	let bodyText = htmlDomObj("body").text();
})(jQuery);
```

変数名なので、本当はこうでも良い。  
`$`を使っているのは **恐らくただの短縮表記目的なだけ** である


# 全部知ってた？？

面白かったら **イイね** お願いしますね(*´ω｀*)
C70K2 レストア日誌 その3 〜 エンジン始動！

## リプロ品のキーシリンダーに交換
ミニモトのキーシリンダーに交換 送料別で1650円。 
https://minimoto.jp/index.php?main_page=product_info&cPath=5&products_id=7034

基本的にスーパーカブは東南アジアでパリバリ走ってて古いのも現役なのでパーツは比較的安く容易に手に入ります。
![IMG_0536.JPG](https://qiita-image-store.s3.amazonaws.com/0/230921/14b5c82a-f5e8-a1d9-9ee5-a3b9607ecaf3.jpeg)


## スパークした！
改めてプラグをチェックすると、ちゃんとスパークしてる！パチパチ！してるよ！
キック！キック！キック！！ 掛かりそうでかからない。

## エアーダクト（通称胃袋）を摘出
![IMG_0542.JPG](https://qiita-image-store.s3.amazonaws.com/0/230921/405fd1cc-c4c1-32a0-0964-8e9415c3d2d0.jpeg)
とりあえず、キャブレターに直接パーツクリーナーを吹いて爆発させようとエアクリーナーと繋がってるバンドのネジを緩めようとするも硬い。。。
ラスペネを吹きながら、コンコンカンカン叩いたけど埒が明かないので、ネジを切断。

キャブレター側は単なるクリップなのですぐ外れたよ
![IMG_0543.JPG](https://qiita-image-store.s3.amazonaws.com/0/230921/52bf47a8-88a3-9302-16fe-4f07ec9fb43d.jpeg)

外れると給気口が上向きについてる。ゴミが入らないようにネットもついてる。
![IMG_0543.JPG](https://qiita-image-store.s3.amazonaws.com/0/230921/601418f2-394b-59fd-e941-fb9def2121e1.jpeg)
ここにエンジンコンディショナーを吹き込みながらエンジンを掛けることを試みること数回。。。

## 見事エンジン始動！ やる気が漲ってきた！（写真が無い） 

### エンジンを掛けたけど、以下の不具合がある
- やたら排気音が大きい。たぶん純正マフラーが腐って穴開いてる
- バッテリーが死んでるので回さないと色々電気がつかない
- アイドリングが不安定。高止まりしておかないと止まっちゃう。

### でもこの点は問題なかった。
- 一度エンジンかかると、次からは比較的すんなりエンジンがかかる
- アクセルワイヤーも一応動く
- アクセルを煽ればウインカーは正常に点滅する
- ブレーキスイッチも正常

エンジン内を何もしなくても復活するあたりが流石世界のスーパーカブといったところか。
次はパンクしてるリアタイアの修理、欠品のシートの交換。消耗品の交換などをやってみる予定。
Discord Botをお手軽に作る！

## `Glitch`と言うネ申ツールを使う事で死ぬほど簡単に実現可能

- https://glitch.com/
- `Glitch`はNodeJSの **ソースコードをシェアするサービス**
- シェアと同時にそのコードを動かす事が出来る => **ホスティングする機能を備えている！！**
- **しかも無料**
- **Discord Botのソースの多くはNodeJS製なので相性もバッチリ★**

### => コレを使わない手は無いっ！！！


## `Eris`と言う派生のライブラリを使うと更に簡単！

- https://abal.moe/Eris/
- 本家をより格段に手続き少なく色々実装出来るようにラップされているスグレモノ！
- `Glitch`用のテンプレートもある！
	+ https://glitch.com/edit/#!/eris-discord-bot-example


## `Glitch`と`Eris`でお手軽Bot制作！

### 先ずはBotとなるユーザーを用意

- https://discordapp.com/developers/applications/
	+ 参考: https://discordpy.readthedocs.io/ja/latest/discord.html
- **作成したBotの`Token`を控えて置く**

### `Eris`を`Remix`する！

- https://glitch.com/edit/#!/eris-discord-bot-example
	+ `Remix`を押す

### => 後はコーディングするだけ！！

## 出来上がったボットはコチラ

僕がやっているスマホゲーム「リネージュ2レボリューション ( https://l2.netmarble.jp )」のギルド管理の為のボットを`Glitch`と`Eris`を使って作って公開・利用しています(*´ω｀*)

<img width="872" alt="スクリーンショット 2018-11-28 15.10.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/151630/6743b59f-46ae-4932-a19c-8a4481251aa4.png">

エリカ様ボット => https://discordapp.com/oauth2/authorize?client_id=496203597198131201&scope=bot&permissions=131072
NEMアカウントを調べてみよう！

NEM#2の2日目です。今日からじっくりとNEMについて学んでいきましょう。あれ？そんな企画でした？

さて、最近よく話題に上がるブロックチェーン。
そのブロックチェーンへのアクセスは難しいと思っていませんか？

まずはノードを建てるためにサーバをレンタル。
coindとかいうものをインストールして同期で待つこと数時間。
意味不明な文字列を打ち込んで、やっと接続完了。。。。？

いいえ、NEMはブラウザでアクセスするだけでノードの情報が閲覧できます。
NEMノードへの問い合わせ結果はjsonというフォーマットで返ってきます。jsonを観察するにはFierFoxを利用しましょう。

まずは、zaifのアカウントを調べてみます。
URLはこちら http://alice2.nem.ninja:7890/account/get?address=NAGJG3QFWYZ37LMI7IQPSGQNYADGSJZGJRD2DIYA
NAGJG3QFWYZ37LMI7IQPSGQNYADGSJZGJRD2DIYAという部分がZaifのアカウントになります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/29187/48f12e56-d6a1-1b53-2670-cf3fdb91031a.png)


大きくmeta部分とaccount部に分かれます。もちろん秘密鍵は載ってません。

誰もが気になる残高はずばり balance ですね。
56015495502434

うん？いちじゅうひゃくせんまん...56兆XEM！？
違います。ITの世界では小数点を使うと誤差が発生するためすべて整数値で扱うことがよくあります。
XEMは小数点6ケタなので、

56015495.502434

となり、 5600万XEMとなります。
このアカウントはホットウォレットとよばれ常にネットワークにつながっているアカウントになります。

ネットワークから完全に分離された場所に保管されるコールドウォレットはこちら。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29187/04cda73f-7dde-981f-8834-cc2bacf9461d.png)

ものすごい額ですね。そもそもネットワークにつながっていないのでマルチシグの設定も行われていません。
マルチシグの情報はcosignatoriesで知ることができます（ホットウォレットは3つ、コールドウォレットは0）
どういった場所に保管されているのか非常に気になります。おそらく組織が解散するまで日の目を浴びることはないのでしょう。
ホットウォレットは multisigInfoが（cosignatoriesCount:3,minCosignatories:2)とあるので、
3人の署名者のうち、2人が署名すれば送金可能という設定です。


次にCCのアカウントを調べてみましょう。


こちらがホットウォレットです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29187/1862fa4d-df57-7ef1-7cf2-bf725dd522c2.png)

おっと、マルチシグの指定がありませんね。大丈夫でしょうか？
つぎにコールドウォレットを見てみます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/29187/e3c83791-224a-31d2-f6b0-022618c16279.png)

なるほど、こちらに 2-of-4 のマルチシグがされていました。

おそらく、CCはXEM出金時にマルチシグフォーマットで出金されるのを嫌がったのだと思われます。
たとえばマルチシグ着金対応していない取引所に直接送金してしまった場合、XEMをGOXしてしまう可能性があります。
CCへの入金に対しては、費用をかけて開発したりサポート体制を整えればなんとかなりますが、
出金してしまったものに対しては、どうしようもありません。

その対策として窓口となるアカウントはシングルシグのウォレットとして利便性を高め、
盗難時のリスクを抑えるために、残高を低めにしておきその代りコールドウォレット(?)からいつでも引き出せるように
設計したのでしょう。

取引所によってホット・コールドウォレットの構成が真逆なのは興味深いですね。
次回は、今回取り上げたNEMアカウントを作ってみます。

JavaScriptの知識が必要になるので、勉強しておいてくださいね。
Javaソースの解析ツールをJavaで書いてみた…い

# なぜ作るのか？

いろいろ考えてみましたが<strong>ド初心者</strong>の僕には難しいのです。
考えをまとめるためにもアウトプットしときます。

とりま現在の流れを3行で。

1. 現場で簡単な仕様のDiffツール作ってくれって言われる
2. 仕様を踏まえた上で考えたらソース解析必要やなーって思う
3. なんやこれ構文解析ってこんなむずいんか

まぁライブラリ使ったら余裕なのかもですけど、いろいろ制約があるもんで、とりあえず標準ライブラリで作ろうとしてます。

# 解析ツールの仕様

### 概要

1. 比較元と比較先のJavaファイルのパス受け取る
2. 比較する
3. Diffの結果のステップ数を出力する

※ただし、２つのJavaファイルはメソッドやフィールドの順番は入れ替わってたりする

### 入力と出力

INPUT
  ・javaファイル2つ（絶対パス）

OUTPUT
  ・diffした結果のステップ数（コメントも含む）

### 今現在想定している実装メソッドの実行順序

1. 受け取ったjavaファイルのパスからファイル内の文字列を取得
2. <font color="red">比較元、比較先のjavaファイルからメソッドとフィールドの文字列に分け、マップに格納（フィールド、メソッド用の両方のマップインスタンスを作成）</font>
3. 比較元、比較先のフィールドの並び替え
4. 比較元、比較先のメソッドの並び替え
5. 比較元、比較先を文字列インスタンスに代入
6. 比較元と比較先の両文字列インスタンスを比較
7. ステップ数を算出し、出力する

こんな感じだと思います。

# で、何に悩んどんねん

悩んでいるのは上の<font color="red">赤文字</font>の部分になります。

例えば以下のようなクラスがあるとします。

```
public class Main {

    public static final String hoge;
    public static final String fuga;

    public static void main(String[] args){
        if (compareStr(args[0], hoge)) {
            System.out.println(hoge);
        }
    }

    public static boolean compareStr(String arg1, String arg2) {
        if (arg2.equals(arg1)) {
            return true;
        } else {
            return false;
        }
    }
}
```

これをフィールドとメソッドに分けて以下のマップインスタンスに格納しようとしました。

```
Map<String, Map<String, String>> codeMap;
```

…。
ん？どうやってメソッドとフィールドに分けるんや？？

っていうところで詰まりました…。

素のままの状態でやるには馬鹿な僕には少々無理があったようです😭

ライブラリ使えば余裕ですね。
git diffとか。
VoyagerをXAMPP環境でVirtualHostを用いてLAN公開する

# やりたいこと
社内LANの中に設置したXAMPP環境+VoyagerをVirtualhostを用いて公開したい。

ただ、80番ポートは社内HPの公開に使用しており、それはそのまま生かしたい。

なので8000番ポートをVoyagerに割り当てて公開する。


#XAMPPのVirtualHostの設定

##1.「httpd.conf」の設定

```conf:...\xampp\apache\conf\httpd.conf

#下記の設定を一番下に追記する
Listen 8000
```

##2.「httpd-vhosts.conf」の設定

```conf:...\xampp\apache\conf\extra\httpd-vhosts.conf

#下記の設定を一番下に追記する
<VirtualHost *:80>
    DocumentRoot "...\xampp\htdocs"
    ServerName localhost
</VirtualHost>

<VirtualHost *:8000>
    DocumentRoot "...\xampp\htdocs\<Voyagerプロジェクト名>\public"
    ServerName localhost
     <Directory "...\xampp\htdocs\<Voyagerプロジェクト名>\public">
        AllowOverride All
        Options All
        Require all granted
    </Directory>
</VirtualHost>
```

#上記完了後、XAMPPのApacheを再起動

LAN内のPCからは

```
IPアドレス(例：000.00.000.00):8000/admin
```
でvoyagerにアクセスできます。

#参考リンク
http://mypcmemo.com/xampp-vertualhosts
ひさしぶりのプレミアムフライデー（GO言語）

# はじめに
気づけば今日はプレミアムフライデーです（死語？）
せっかくなので久しぶりにプレミアムフライデーを求める処理を書いてみます。

# コード
## メイン
```go:main.go
package main

import (
	"fmt"
	"strconv"
	"time"
)

func main() {
	r := GetPremiumFriday(2018, 10)
	fmt.Println(r)
}

func GetPremiumFriday(year int, month int) time.Time {
	l := time.Date(year, time.Month(month+1), 0, 0, 0, 0, 0, time.UTC)
	w := l.Weekday()
	dh := strconv.Itoa(int(-(w+2)%7) * 24)
	d, _ := time.ParseDuration(dh + "h")
	return l.Add(d)
}
```
### 解説
あまり説明もないですが`time`パッケージを使っています。
`time.Date`関数の引数部分にある**日付部分**に0を渡すことで前月の末日が設定されます。
なので受け取った月＋１を設定して設定した月の末日を取得しました。

`ParseDuration`へ文字列で期間を渡すことで、シンプルに日付の減算が可能なのですが、
最大単位が**Hour**のようなのでちょこっとだけ計算を行っています。


## テスト
せっかく標準でテスト機構が備わっているのでどんどん使っていきましょう！
VSCodeだとコード上で`run test`できるのでこういう時すごく便利です

```go:main_test.go
package main

import (
	"testing"
)

type Fixture struct {
	Yaer      int
	Month     int
	ExpectDay int
}

var fixtures = []Fixture{
	Fixture{2016, 2, 26},
	Fixture{2018, 9, 28},
	Fixture{2018, 10, 26},
	Fixture{2018, 11, 30},
	Fixture{2018, 12, 28},
	Fixture{2019, 1, 25},
}

func TestGetPremiumFriday(t *testing.T) {
	for _, f := range fixtures {
		d := GetPremiumFriday(f.Yaer, f.Month).Day()
		if d != f.ExpectDay {
			t.Error(f)
		}
	}
}
```

#　まとめ
やってみたかっただけでした
そのうちシャイニングマンデーもやるかな

おしまい
自社導入の経験からSlack導入のアンチパターン

# 概要

　部門内Slack導入「[50人規模の部門にSlackを導入してみた結果](https://qiita.com/comefigo/items/8fbc4e34c07d141e328a)」と全社向けSlack導入「[500人（全社）規模にSlackを導入する道のり（途中）](https://qiita.com/comefigo/items/0dd629a6b27ee8cdb0a8)」の経験から導入のアンチパターンとして残したいと思います

　部門内Slackは前述のように部門内の**文化**として根付いていて、個人的には**成功**していると感じています。しかし、全社用は残念ながら成功とは言えない状況（**現時点失敗**）です。Slackの適用範囲や企業文化によっては様々な対応が必要かもしれないが、これから導入を考えている方や導入しているがうまくいかない方の参考になれば幸いです

## 導入したらフォローしない（もしくは遅い）

　導入直後に使い方や要望などの各種問い合わせがありますが、その返信に時間がかかったり、返信しなかったりすることで利用者の熱量が下がっていき、結果的に使う気がなくなっていきます

### 対策

　とにかくすぐにフォローする。即断できない内容はいつまでに回答すると期限を設けて対応すること。のちに経過報告や結果の返答を忘れずに！（鉄は熱いうちに打て）

## ハードルが1mmでも大勢の人がコケる

　全社Slack導入では、参加するためには利用申請しなければならないことになった。そのため、あえて参加しようと思わない人もそれなりにいるので、未だに参加していない人がいる。そうするとチーム内でそうした人がいると結局連絡手段が従来のままに引きずられるので、アカウントを発行したが、使わない人が続出する状況になりました

### 対策

　好奇心旺盛なメンバーではない限り、使い始めるまでの心理的ハードルがどうしても高く感じるので、使い始めるまでのハードルを無くす事に努めるべき。最初は一般的な活字コミュニケーションのマナーと必要最低限かつ最重要な禁止事項で運用開始し、徐々にルールを加えていく

## 誰も発言しない

　導入直後は多くの人が様子見状態です。その中で誰も発言しなければ、結局発言しづらい雰囲気になってしまって、結局誰にも使われないプラットフォームになる

### 対策

　運営局や協力者が積極的に話題（業務関連、趣味、育児、食べ物など）提供していくことが必要です。個人用のつぶやき用チャネルや旬の話題などを投稿して、何かと情報が発信されている場なんだなっと印象づけることで、発言するハードルを下げることに繋がる
　さらに誰か投稿した内容に積極的に返信しましょう。誰か1人でも返信があると意外と他の人が発言し始めることがあるので、最初は居酒屋のマスターになったつもりで話を広げるように頑張りましょう

## ビジネスパートナー（BP）さんの参加問題

　弊社ではBPさんと協力して業務を実行しているチームが多くあります。そのため、日々の業務連絡は既存のGoogle Apps（ドメイン内のみ利用可能）で行っています。しかし、一部の契約形態のBPさんにSlack経由でプライベート時間に業務連絡していいのか？とかが議論になり、いまだにその問題が解決されていない。結果的にBPさんを含むチームメンバーが参加しきれていないので、利用者も思うように増えていない

### 対策

　Slackには特定のユーザに特定のチャネルのみに参加してもらえる仕組みがありますので、BPさんや外部ユーザにも限定した情報公開が可能（有償版）。ただ、上記のように契約上のリスクをどう解決していくかはBPさんとチーム内でルール作りが必要です。契約上でそういうリスクがあるからと言って、何もしないよりもどうしたらスムーズに利用できるのかを考えるべき

## 工数確保

　業態特有のものですが、何をするにも工数を予め見積もってから作業しなければならない。そうすると運営メンバーのSlackサポート用工数も予め確保しないと対応できないため、結果的に対応がおろそかになる（前述のフォローが遅くなったりする）

### 対策

　質問の返答、設定変更、導入直後の盛り上げタスクに要するコストは組織として理解する必要があり、本業として見なしてあげる必要がある。対応時間が大幅に大きくなった時は、時間を確保してしっかりと対応する

## なんでもかんでもチャットで会話しようとする

　隣にいるのに全部チャットで会話する。かえってコミュニケーションコストが増える

### 対策

　チャットはあくまでもコミュニケーションのきっかけでしかないので、**リアルなコミュニケーションを大事に**してください！ただし、全体に周知しなければならないことや履歴として残したい時の一つの手段にしましょう

# まとめ

　最後になりますが、一番大事なこととして単なるツール導入に留まらず、**組織文化を形成するまでがゴール**になります。こう聞くと壮大で手間がかかると感じられるかもしれないですが、現実問題そのぐらいの覚悟が必要だと思います。もちろん組織規模によってかかるコストが異なりますので、大きな組織の場合は、小さい単位（部門単位）から順に適用していく。それに合わせて理解者や協力者を増やすことで、徐々に定着されていくと思います。可能ならばトップレベルの理解を得られると進みやすいので、まずそこから理解を得られるように努力しましょう！
ニュースをランダムにガチャして読める「ガチャっとニュース」を4時間でリリースした話【個人開発】

[じぇい](https://twitter.com/jyouj__)です！こんにちは。

ニュースをガチャすることで、ニュースをランダムに読める「[ガチャっとニュース](https://gachat-news.herokuapp.com/)」をリリースしました！

https://gachat-news.herokuapp.com/

<blockquote class="twitter-tweet" data-lang="en"><p lang="ja" dir="ltr">【拡散希望】<br>ニュースをランダムにガチャして見れる「ガチャっとニュース」をリリースしました㊗️<br><br>情報の偏りが問題になるこの世の中でランダムにニュースを見れたなら、偏りも減るのでは？と思って作りました<br><br>楽しめるようにガチャ風にニュースが出るようになってます<a href="https://t.co/95AlF0d9Tr">https://t.co/95AlF0d9Tr</a></p>&mdash; じぇい👨‍💻 (@jyouj__) <a href="https://twitter.com/jyouj__/status/1068155029582864384?ref_src=twsrc%5Etfw">November 29, 2018</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

ぜひいろんな人に触ってもらいたいのでリツイートしてもらえると泣いて喜びます:stuck_out_tongue_closed_eyes:

## 作った背景
上のツイートにも書いてあるように、情報の偏りを無くそうと思いました。ただランダムにニュースを閲覧できるようにしても面白くないので、ガチャというエンターテイメント性を入れました。

ガチャしてニュースを読むという新たなアプローチ方法です！

## 製作期間
水曜日3時間、木曜日1時間の計4時間で完成させました。

水曜日にメインの機能であるNewsAPIでニュースをランダムで取得するコードや大まかなサイトのレイアウトを作成しました。

木曜日はTwiiterでシェアされる画像の設定や細かいレイアウトを作成しました。

## ガチャっとニュースってどんなサービス？
「ガチャっと」というボタンを押すとランダムでニュースが一つガチャされます。

<img width="1252" alt="スクリーンショット 2018-11-30 18.31.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/252295/c6babb97-62cc-50e8-dd48-1f6e18aa3082.png">

<img width="1248" alt="スクリーンショット 2018-11-30 18.32.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/252295/5706c062-30ca-867d-2faf-0a6ac3a1c63d.png">

1ページで完結している、シンプルなサービスです。

もちろんスマホ対応してます。

<img width="321" alt="スクリーンショット 2018-11-30 18.35.15.png" src="https://qiita-image-store.s3.amazonaws.com/0/252295/f01547b4-ae28-bfaf-c91f-d67a7aa9837f.png">

<img width="314" alt="スクリーンショット 2018-11-30 18.35.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/252295/a44e31fc-26e5-b19d-116c-142d2f6c178e.png">

## 使ったもの
- Django
  - 使い慣れているから、サクッとできる
  - Flaskとかでもよかったかも

- Bulma
  - 1ページだけだけどレイアウトはそれなりには整えたかった
  - サクッとCSS適用できて便利
  - モーダルウィンドウやボタン、画像サイズの部分で活躍しました

- jQuery
  - モーダルウィンドウの表示の部分で活用しました
  - 小さな機能ならjQueryで十分
  
- News API
  - 国別、カテゴリー別など様々なニュースを取得できるAPI
  - newsapi-pythonというパッケージがあってよかった
  - 最新のニュースを常に取得できるのもいい！

NewsAPIについては僕自身が使い方をブログに記事書いてます(笑)

[［Django］NewsAPIを使ってニュースサイトを作ってみる](https://jyouj.hatenablog.com/entry/2018/11/26/222639)
[［Django］NewsAPIを使って色々なニュースを取り出してみよう](https://jyouj.hatenablog.com/entry/2018/11/27/214832)

- Github
  - 使わない選択肢がなかった
  
- Heroku
  - とりあえず無料のを使った
  - サーバーの知識なくてもOKなのありがたい

## 最後に
今回で二つ目のサービスのリリースとなります。個人で色々開発する上のメリットは思い立ったらすぐ形にできたり、自分の気分の乗るときに作れるところだと思います。

まだまだ開発するぞ！

いいねくれたら舞って喜びます:sunglasses:

お読みいただきありがとうございました！
shell でネストされた変数を展開したい

# 問題

Ruby の bundle install 時に
`RAILS_ENV=development` なら `bundle install --without development` で
`RAILS_ENV=production` なら `bundle install --without development:test` みたいなことをやりたい

例えば

```bash
$ config_staging=hoge
$ config_production=fuga
$ target=staging
```

のとき、 `config_${target}` の中身の `hoge` を呼び出したい

# 解決策

eval を使う

```bash
$ echo "$(eval echo \${config_${target}})"
hoge

# or

$ config=\$config_${target}
$ echo $config
$config_staging

$ echo "$(eval echo $config)"
hoge
```
create-nuxt-app を使って Nuxt.js を NOW(ver.2)で簡単に公開する方法

Nuxt.js を NOW(ver.2)で公開するまでを簡単に手順にしました。
今回は、Nuxt.js を SSR で使えるようにして、NOW で公開しています。
Static な場合は、NOW の example ページにサンプルがあるのでこちらを参照するといいと思います。[Static Nuxt](https://zeit.co/examples/nuxt-static/)

## 手順に入る前に

`Node.js`と`npx`もしくは、`yarn`、`now`をインストールしておきましょう。
ここでは、`yarn`を使って手順を書いたので、`npm`派の人は置き換えて読んでください。

## Nuxt.js の導入

まずは、`create-nuxt-app`の導入と実行を行います。
下記の`nuxt-test`はプロジェクト名かつ、この名前でフォルダが作成されるので適宜置き換えてください。

```zsh
yarn create nuxt-app nuxt-test
```

質問があるので、答えます。
`Choose rendering mode`を`Universal`にしているのと、
`eslint`と`prettier`で`yes`を選択しています。

```zsh
> Generating Nuxt.js project in /work/nuxt/nuxt-test
? Project name nuxt-test
? Project description My remarkable Nuxt.js project
? Use a custom server framework none
? Use a custom UI framework none
? Choose rendering mode Universal
? Use axios module no
? Use eslint yes
? Use prettier yes
? Author name takutakuma
? Choose a package manager yarn
Initialized empty Git repository in /work/nuxt/nuxt-test/.git/

  To get started:

    cd nuxt-test
    yarn run dev

  To build & start for production:

    cd nuxt-test
    yarn run build
    yarn start

✨  Done in 212.97s.
```

作成されたフォルダに移動して、実行し

```zsh
cd nuxt-test
yarn run dev
```

[http://localhost:3000](http://localhost:3000)にアクセスすると、
下記のようなエラーが表示されます。(`create-nuxt-app@2.1.1` の時点では、、、)

```bash
ERROR in ./pages/index.vue
Module Error (from ./node_modules/eslint-loader/index.js):

/Users/takuma/work/nuxt/nuxt-test/pages/index.vue
  36:1  error  Delete `⏎`  prettier/prettier

✖ 1 problem (1 error, 0 warnings)
  1 error and 0 warnings potentially fixable with the `--fix` option.
```

このままだと、困るので、一度閉じてから以下のコマンドを実行しましょう。

["error Delete `⏎` prettier/prettier" in .vue files #114](https://github.com/prettier/eslint-plugin-prettier/issues/114)

```zsh
yarn run lint  -- --fix
```

再度、サーバを立ち上げて、[http://localhost:3000](http://localhost:3000)にアクセスすると、
Nuxt.js の初期画面が表示されました。

```zsh
yarn run dev
```

## NOW の設定と実行

NOW に公開する前に、`package.json`への追記と、`now.json`の追加を行ってから、NOW コマンドを実行します。

### package.json の追記

`package.json`の`scripts`に`now-build`を追記します。

```diff
  "scripts": {
    "dev": "nuxt",
    "build": "nuxt build",
    "start": "nuxt start",
    "generate": "nuxt generate",
    "lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
-    "precommit": "npm run lint"
+    "precommit": "npm run lint",
+    "now-build":"nuxt build && nuxt start"
  },
```

### now.json の追加

フォルダ直下に以下の内容で、`now.json`を追加します。
`name`に関しては、適宜変えてください。

```json
{
  "version": 2,
  "name": "nuxt-test",
  "builds": [{ "src": "package.json", "use": "@now/node" }]
}
```

### NOW コマンドの実行

```zsh
now
```

コマンドを打って待っていると、URL が表示されるので、問題なければ公開されます。
曲者に権限が渡らない OSS 権限移譲プロセスが難しい

曲者に OSS の権限が付与され、悪意のあるコードを埋め込まるような事件をおこさない OSS 権限移譲フローを考えてみました。

# TL;DR

基本的に OSS の権限譲渡を **選ばない方** が安全といえそうです。なぜなら、次のように権限譲渡の安全性を担保することはとても難しく、かつ高価につくからです。

代わりに、プロジェクトを停止するか、信頼できる人物に fork を依頼する（現状の project は archive）のが、責任回避の意味で有効だと思われます。


# 背景

「[2018/11/27に判明したnpmパッケージ乗っ取りについて](https://qiita.com/azs/items/b15bc456bee3a7892950)」が世間を騒がせていますが、個人的に驚いたのは件の package の元々の作者である方への非難の声が多いことでした。

個人的には、この事件の根本は npm 側の機能不足が問題という認識（postinstall フックなどの自動的なフックによって操作ユーザーの権限で任意のコマンドを実行できるのにサンドボックス機能を用意しなかったこと）ですが、世間的にはそうとみなさなず、軽々しく権限を譲渡するなという意見もかなり見受けられました。

では、**軽々しくない**権限譲渡とはどのようなものでしょうか。この条件がなかなか難しいように思えたので、その方法を考えてみました。

<dl>
<dt>面識のある人物でセキュリティリテラシに問題がなければ信頼する
<dd>移譲先がすでに面識のある人物で、移譲先のアカウントが確かにその人物のものであれば信頼する。
<dt>面識のない人物は身辺調査で問題がなければ信頼する
<dd>移譲先が面識のない人物であれば、GitHub や SNS などで身辺調査をおこなう。身辺調査の内容は、GitHub の継続年数や著名な他プロジェクトへの貢献、SNS 上での発言からセキュリティリテラシの分析など。もし情報がない/不透明ならば信頼しない。
<dt>信頼した人物が3人未満にならないようにし、過半数の合意でリリースがおこなわれるようにする
<dd>上記2条件で信頼したとしても、まだ悪意のある人物な可能性を否定できないので、過半数が悪意のある人物になる確率が十分低くなるような（これはプロジェクトに要求される品質レベルによる）人数に同時に譲渡する。ただし、これは現在の GitHub の機能では不可能に見える。
</dl>

# 条件1: 面識のある人物でセキュリティリテラシに問題がなければ信頼する

この条件では、移譲先がすでに面識のある人物で、移譲先のアカウントが確かにその人物のものであれば信頼できるとみなします。これは、ブラックハットは足のつきやすい顔出しのリスクを避けるだろう、という推測から設定しました。

ただし、この条件の確認に手間がかかる場合があります。というのも、別のアカウントと誤解させる目的で見分けのつきにくい文字置換がされたアカウント（`@kuniwak` → `@kun1wak` のような）を QR コードなどで提示された場合、なりすましの成立する可能性があります。

ここで、「所有しているリポジトリやそのスター数でわかるのでは？」と思われるかもしれませんが、スター数が数十程度であれば **スパムアカウントによって自演が可能**です。したがって、そのリポジトリのアクティビティが実体のあるアカウントによってなされたかどうかを確認しなければなりません。また、Issue や Pull Request の本文や差分は、他プロジェクトの物をそっくり盗用して同期するという方法は安価で実現できますから、本文などからだけでは判断できないのです。したがって、これを考慮したアカウントの本人確認はとても手間ですね。

また、面識があったとしても本人のセキュリティリテラシが低ければ、リスクは段違いに高くなります。したがって、本人にきちんとしたセキュリティリテラシがあることを確信できければなりません。これを確かめるのは非常に骨が折れますが、SNSや対面でセキュリティの質問をするしかないと思います。


# 条件2: 面識のない人物は身辺調査で問題がなければ信頼する

この条件では、移譲先が面識のない人物であれば GitHub や SNS などで身辺調査をおこない、問題がなければその人物を信頼できるとみなします。この身辺調査の内容は、GitHub の継続年数や著名な他プロジェクトへの貢献、SNS 上での発言からセキュリティリテラシの分析などが考えられるでしょう。そして、もし情報がない/不透明ならば信頼しないというのが原則になります。

面識のない人物であれば、面識のある人物よりリスクが高くなります。したがって、条件1よりも厳しい身辺調査が必要なのは明白です。例えば、GitHub アカウントに記載された SNS アカウントなどは容易に詐称可能で、その本人確認を安価にできないかもしれません[^1]。したがって、幸運にもこのような身辺調査が可能で問題がなさそうであれば、ようやく信頼できるとみなせるでしょう。

[^1]: SNS の profile から GitHub へのリンクがなく、SNS での投稿に本人と GitHub アカウントとの関係を示唆するような投稿がない状況を想定しています。また、リンク先の SNS アカウントもなりすましという可能性さえありえます。


# 条件3: 信頼した人物が3人未満にならないようにする

上記の2条件で信頼できたとしても、まだ悪意のある人物な可能性を否定できません。そのため、権限をもつアカウントの過半数が悪意のある人物になる確率を十分低くできるような（これはプロジェクトに要求される品質レベルによる）人数に譲渡するといった方法が考えられるでしょう。

しかし、これは1つの悪意あるアカウントによって、他の善良なアカウントを締め出せるようなら意味がありません。これを防ぐ方法は、譲渡元の人物が Admin 権限を渡さないことが条件になります。しかし、少なくとも Write 権限を他者へ渡せなければ、実質的に負担が減らないず権限移譲をする意味がありません。そのため、悪意のある一人の人物によって悪性のコードを、短時間リリースされるリスクは呑まなければならないでしょう。これが GitHub における現状の権限移譲の限界かと思われます。


# 結論

ここから見えてくることは、**権限譲渡の安全性を担保することはとても難しく、かつ安全を担保するプロセスはとても高価**だということです。そのため、基本的には権限移譲を考えない方がセキュリティの観点からはよさそうです。

代わりに、信頼できる人物に fork を依頼（現状の project は archive）するという方法があります。ただし、この方法は本質的にはユーザーに信頼の判断を委ねるということになりますから、実質的な安全性は変わっていません。セキュリティ担保の責任の主体がユーザーへ移動するだけで、依然として信頼を確認することが難しいためです。
TypeScriptの文字列enumでrawValue→enumを実現する

TypeScriptの仕様上、文字列enumはreverse mapping(rawValue→enum)ができません
（文字列の場合、生の値が重複する可能性があるから・・・？）。
実際に公式のドキュメントにも記述があります。(https://www.typescriptlang.org/docs/handbook/enums.html)
>Keep in mind that string enum members do not get a reverse mapping generated at all.

仕組みがないなら作ってしまおうということで、ヘルパーメソッド的なものを自作してみました。v3.1.6で動作確認しています。

```typescript

export function mapToEnum<T>(enumObject: T, value: any): T[keyof T] | undefined {
  if (typeof enumObject === 'object') {
    for (const key in enumObject) {
      if (enumObject.hasOwnProperty(key) && enumObject[key] === value) {
        return enumObject[key]
      }
    }
  } else if (enumObject instanceof Array) {
    return enumObject.find(value)
  }
  /* 3.0.x
  } else if ((enumObject as any) instanceof Array) {
    return (enumObject as any[]).find(value)
  }
  */
}

////////////////////

enum Meta {
  Hoge = 'hoge',
  Fuga = 'fuga',
  Foo = 'foo',
  Bar = 'bar'
}

const meta: Meta = mapToEnum(Meta, 'hoge')
console.log(meta) // hoge

```

本当はenumに存在する文字列だけ受け取れるようにしたいところですが、それができなかったので戻り値でundefinedを許容するようにしました。
Pepperのイベント登壇やデモの成功率をちょっと上げる方法【事前準備編】

#概要
Pepperをイベントに連れて行ったり、誰かにデモを行ったりした事がある方は、１度くらい「さっきまで正常に動いてたんですけど・・・」と言いたくなる経験をしたことがあるのではないかと思います。私もその一人ですので、これまでに何度かイベントに持って行ったりデモを行った経験で得た、デモの成功率をちょっと上げる簡単なひと工夫をご紹介いたします。
失敗できないデモの時には是非お試しを！

##事前準備編
ネットワークを必要する部分以外は極力Pepper単体で完結するようにします。特にアプリの転送・アプリのスタートがネットワーク環境によって上手くいかない事があるので、可能な限り対策しておきたいですね。

###① Pepperが起動したらそのアプリが起動するように設定しておく
Choregrapheからのアプリ起動がうまくいかない事があるので、電源を入れたら自動でアプリが立ち上がるようにしておくと安心です。また、こうしておくと現場で再起動しなければいけない事があった時も直ぐにアプリが立ち上がってくれるので心強いです。
私の知る限りではデフォルト起動アプリ設定か、お仕事かんたん生成2.0の機能で実現できました。
（お持ちのPepperがPepper for bizなら、お仕事かんたん生成の機能を使った方が良いのかなと思います。デフォルト起動機能だと何かと干渉することもありそうですしね・・・）

#####1.デフォルト起動設定
Choregrapheのアプリパネルで旗のマークをクリックすると、Pepper起動時に立ち上がるアプリとして設定できます。詳しくは公式ドキュメントでご確認ください。
http://doc.aldebaran.com/2-5/software/choregraphe/panels/robot_applications.html#default-behaviors

#####2.お仕事かんたん生成2.0
ベンダーアプリボックスを使うと自作のアプリを起動する事ができます。呼び込みをオフ→ベンダーアプリボックスだけのお仕事を作っておくと延々とアプリをループで起動してくれるので便利です。
↓こんな感じ
![スクリーンショット 2018-11-30 17.22.20.png](https://qiita-image-store.s3.amazonaws.com/0/321294/8dc36f58-6ba3-32c1-9c95-abb3e055fc5e.png)

###② アプリはPepperを物理的に触る事で始まるようにしておく
Pepperが最初の動作を始めるタイミングを現場で自由に制御できるように、物理的にPepperを触ることを処理開始のトリガーにすると便利です。
アプリの起動後は黒画面などを出しておき、頭のセンサータッチなどを契機に処理を開始するようにアプリを作っておきましょう。
頭や手・タブレットのタッチはうっかり触っちゃったり、イベントだと子供に触られたりで暴発しますので、あまり触られない後部バンパーの押し込みなどがオススメです。

###③ 有線LANで対応する場合を想定しておく
イベント会場などでは無線接続が安定しない事が多いので、有線で動かす準備をしておきます。（有線接続する方法は既に書かれている方がいらっしゃいましたので割愛）
特に注意が必要なのは、タブレットで表示するコンテンツ（HTML・javascriptなど）がネットワークを使用する場合です。
Pepperのネットワークは本体とタブレットの２つに分かれていますが、有線で繋げるのはPepper本体側だけですので、タブレット側の動作に影響が出るのか本番前に一度確認しておくと安心です。
インターネット上にあってもローカルにあっても良いようなファイルは、アプリ内に抱えておくと良いかもしれません。

##最後に
最終的にうまく行くかどうかはPepperの機嫌次第なところはありますが、できる限りの事はやっておきたいですね！
次回は現場でできる工夫を紹介したいと思います。
rails コントローラーの"アクション"progateから

アクションを 理解しよう
アクション
コントローラ内のアクションは、ブラウザに返すビューをviewsフォルダの中から見つけ出す役割を担っています。具体的には、アクションは、コントローラと同じ名前のビューフォルダから、アクションと同じ名前のHTMLファイルを探してブラウザに返します。
￼
![image.png](https://qiita-image-store.s3.amazonaws.com/0/284608/aa72ea01-5055-7da4-3bef-27007e96360c.png)
docker networkとAWSのIP帯がかぶったときの話

Retty Advent Calendar 2018 3日目の記事です。
昨日は @tkngue さんの記事で、 [Webサービスを支えるユーザログ基盤開発＠Retty](https://engineer.retty.me/entry/2018/12/01/120019) でした。

# はじめに

今年は[Docker本を出版](https://www.amazon.co.jp/dp/B07D3474QP/)したりと割とDockerに絡む機会が多かったのでアドベントカレンダーでもDockerについてのネタを書きます。
今回のネタはdocker-composeでローカルの開発環境を立ち上げたときにAWSのRDSに接続できなかったときの話です。

# docker networkとAWSのIP帯がかぶったときの話
## 顛末
自分は普段からDockerで開発環境を動かしながらローカルディスクの内容をvolume mountさせつつ開発をしてます。
それもあり、docker-composeで開発環境の定義をして up するだけで立ち上がるようにしています。
その時にアプリケーションサーバやRedisなどのサーバはDockerでたてているのですが、データベースだけは共用のAWSにあるRDSインスタンスにつないでいます。

ちょうどこんな感じのイメージです。
![IMG_1442.JPG](https://qiita-image-store.s3.amazonaws.com/0/34824/46266ebf-139c-053b-c67d-e63f98862ad9.jpeg)

日々平穏に開発できていたのですが、ある日 `docker-compose up -d` とやったところコンテナは立ち上がるけれど、アプリケーションサーバからDBサーバに接続がうまくできなくてエラーになってしまうことが起きました。

なんでだろうと調べまくってましたが、周りのメンバーは別に困ってないし、つながっていないのは自分だけでした。
Dockerを使って発生するようになったことだったので、Docker周りのネットワークが怪しいと踏んで調査をしました。

## 確認したこと
まず対象のRDSインスタンスのプライベートIPをAWSコンソールで確認したところ、 `172.aaa.bbb.ccc` というアドレスでした。
（RettyではオフィスのネットワークとAWSのネットワークをつないで、172系の**一部のプライベートIP**（全部じゃないよ！）のAWSのサーバとはオフィスのネットワークからたどり着けるようになっています）

次にDockerのnetworkが利用しているIP帯を調べてみました。

```
$ docker network ls -q | xargs docker network inspect
[
    {
        "Name": "bridge",
        "Id": "6c89228e028c7125d70ecc6a1754d3e33e5c21fc866c15b94e17b0213741164c",
        "Created": "2018-11-22T11:15:24.003600281Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },

    ・・・中略・・・

        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]
```

上記コマンドを打つと利用しているdocker network帯がずらずらっと出てくるのですが、デフォルトでは利用するのが172系のIPを利用したネットワークが作られてます。
上記の出力の中の `Subnet` という箇所をgrepするとプライベートIPのサブネット定義がわかります。

出力を確認していったところ、今回はRDSの `172.aaa.bbb.ccc` のIPをサブネットに含めてしまうようなネットワークができあがっていました。
つまりRDSに送ろうとしていたネットワークリクエストはdocker networkのほうに吸い込まれて行き場を失い接続に失敗していた、というのが原因でした。

図にするとこんな感じ。

![IMG_6097.JPG](https://qiita-image-store.s3.amazonaws.com/0/34824/854168d1-ac82-80a0-17ea-4449d5ae06c9.jpeg)


## 解消方法
docker-compose.yml ではdocker networkに関する定義もかけます。
また自分の定義したnetworkに対してサービスを所属させたい場合にはサービスの `networks` に定義したネットワーク名を指定することで、そのネットワークに所属させることができます。
下記の例でいえば `172.xxx.yyy.0/24` というサブネットに redis と application のサービスが所属した状態で起動できるようになります。

```yml
version: '3'

services:
 redis:
   image: redis
   networks:
    - retty
 application:
   image: sample:latest
   ports:
    - "8080:80"
   volumes:
    - .:/srv/apps
   networks:
    - retty

networks:
  retty:
    driver: bridge
    ipam:
      driver: default
      config:
       - subnet: 172.xxx.yyy.0/24
```

# おわりに
最初はなんで接続ができないんだよ！とめっちゃ憤ってましたが、単純に自分が不用意にdocker-composeでnetworkを作りまくってしまっていたせいでした。
今回のこの記事が誰かの助けになれば幸いということで年末の禊としたいと思います :pray:
LINE ClovaのハッカソンでぐるなびAPIを使った話

LINE Clova のハッカソンが開催されていたので参加してみました。
折角なので、その場で集まった人間で即席チームでやってみました。

っで、何を作るかアイデア出しすることになったんですが、自慢を言うと褒めてくれる案が採用されました。
本当は言った自慢をストックして他の人が聞くものを提案したのですが、一字一句正確に聞き取るのは難しいなと判断。
なお、この段階ではぐるなびAPIを使うことは一切考えていなかったです。

自慢を聞いてレスポンスする機能は全体の半分くらいの時間で完成したので、他の人が提案したおすすめのレストランを探す機能を実装することになりました。
レストラン系の他のAPIもいくつか探してみましたが、ぐるなびAPIを使うことになりました。

#作ったもの
ソースはここにまとめております。
https://github.com/ri-zhi/boast-about-line-clova

ハッカソンに参加した後にぐるなびAPIがバージョンアップしたので、せっかくなので全体的に書き直しております。
また、ハッカソンはMP3音源で喋らせていたのですが、割愛してLINE Clovaに話させています。

##イメージ画像
実際はclovaと音声会話でやりとりするのですが、イメージ画像を用意しました。
下記のように会話して行く想定です。

スキルを起動するとこのように起動します。
<img width="479" alt="スクリーンショット 2018-11-30 16.53.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/176199/d150c083-c30f-9c82-eeae-7269380ffbdb.png">

なお、「おだてる君」ではなくて「おだてるちゃん」になった理由は「君」だと反応が鈍かったからです。

その後、適当に自慢するとこのように反応いたします。
![スクリーンショット 2018-11-30 16.19.25.png](https://qiita-image-store.s3.amazonaws.com/0/176199/2ba8ce06-9e80-c6a9-32e8-6bf14d1c82ed.png)

特定のワードを言うと、このようにレストランを紹介してくれます。
ワード自体は一旦「仕事、結婚、うまくいった」を設定していました。
![スクリーンショット 2018-11-30 16.21.34.png](https://qiita-image-store.s3.amazonaws.com/0/176199/caad9112-416b-0bdf-fd59-9905518d7404.png)

なお、実際には歓声のmp3音源が一度流れております。(ソースでの解説になりますが…
https://github.com/ri-zhi/boast-about-line-clova/blob/master/index.js
公開しているソースはトークンなどがオープンにならないよう割愛させていただいております。

```javascript:index.js
// 6行目
async function getRestaurant(){
  const url = 'GNAVI_SEARCH_API_URL'
  const response = await axios.get(url)
  return {name: response.data.rest[0].name_kana, url: response.data.rest[0].url}
}

// 46行目
const restaurant = await getRestaurant()
outputSpeech = {
  "type": "SpeechList",
  "values": [
    {
      "type": "URL",
      "lang": "",
      //mp3音源のURL
      "value": "SOUND_URL"
    },
    {
      "type": "PlainText",
      "lang": "ja",
      "value": `やったね。今度頑張ったご褒美として${restaurant.name}に行こうよ`
    }
  ]
}
sendLine(restaurant.url)
responseHelper.setOutputSpeech(outputSpeech)
```

また紹介したお店はLINEで届きます。
（お店に迷惑が掛からないようモザイクを入れさせていただいております。
![line.png](https://qiita-image-store.s3.amazonaws.com/0/176199/df58b484-92da-87fa-9043-8607276ff4b1.png)


# ぐるなびAPI
正直、公開しているソースだと何もわからないと思うので公式のマニュアルを参照してください。
https://api.gnavi.co.jp/api/

#反省
この後も時間が余り、旅館紹介など機能がどんどん盛り盛りになったので、シンプルさがなくなったこともあり入賞は逃しました。
また、利用者の好みや場所に合わせて紹介するなど改良点も考えられます。
ただ、お試しで参加してみて即席チームでそれぞれの提案を最終的に盛り込めたので満足しております。
XSS対策とは

PHPでフォーム作成をするにあたって、「XSS対策」を行うことをおすすめします。
しかし、「XSS対策」についてわからなければ、有効活用できません。
そこで、今回は、「XSS対策」についてご説明いたします。

# XSSとは？
クロスサイトスクリプティング（XSS）とは、アクセス時に表示内容が生み出される「動的Webページ」を脆弱させる攻撃方法のことです。
具体的には、Webページに任意のスクリプトが紛れ込み、Webページを閲覧したユーザー環境でそのスクリプトが実行されてしまうのです。

このような、不正スクリプトが実行されてしまうと、情報詐取やフィッシング詐欺の被害にあう可能性があります。

##対策方法
XSSの対策方法の一つに**エスケープ処理**があります。
**エスケープ処理**とは、プログラミング言語を特別な意味を持つ文字を、別の文字に置き換える文字列の処理のことです。

そこで、使うのが**htmlspecialchars**です。
「htmlspecialchars（エスケープする文字列、エスケープの種類、文字列コード）;」のように使用します。
このとき、エスケープの種類は**「ENT_QUOTES」**を用います。







以上のように、XSS対策を行うことをおすすめします。
HerokuにデプロイしたRoRをターミナルで更新するコード4行

```
$git add -A
$git commit -m "Update application"
$git push heroku master
$heroku run rails db:migrate
```

# 参考

参考にしたWebサイトや技術書などを列挙する

- [【初心者向け】railsアプリをherokuを使って確実にデプロイする方法【決定版】](https://qiita.com/kazukimatsumoto/items/a0daa7281a3948701c39)

# 次にやること

アクセスカウンタをつける。
Spring Boot で ダウンロード

# 環境
* Spring Boot v1.3.0
* java 8
* jquery

# 動機
画面遷移をせずダウンロードしたいが、HttpResponseHeaderクラスを使うのはなんだか気が引けたため、Springパッケージのクラスのみを使って実装。クライアント側の実装も忘れそうなため備忘。

# 実装
## Controller
```java
@RequestMapping("/download")
@ResponseBody
public ResponseEntity<byte[]> download() {
    byte[] data = xxx; // xxx:byte[]形式のオブジェクト
    
    // ResponseHeader
    HttpHeaders header = new HttpHeaders();
    header.add("Content-Type", "yyy"); // yyy:任意のContent-Type
    header.add("Content-Disposition", "attachment; filename*=utf-8''" + URLEncoder.encode("zzz", "UTF-8")); // zzz:任意のファイル名
    header.add("Set-Cookie", "fileDownload=true; path=/");

    return new ResponseEntity<byte[]>(data, header, HttpStatus.OK);
}
```
* Content-Dispositionで強制的にダウンロード、かつ日本語ファイル名に対応。
* Set-Cookieしてるのはこの後クライアント側で使うため。

## javascript
```javascript
// formのサブミット時にイベント追加
$("#myform").submit(function() {
  startLoading(); // ぐるぐる出す的メソッド
  const COOKIE_KEY_FILEDOWNLOAD = 'fileDownload=';
  var isFileDownload = false;
  // ダウンロード完了まで繰り返す
  var intervalId = setInterval(function() {
    // cookieから fileDownload の取得
    const COOKIES = document.cookie;
    var position = COOKIES.indexOf(COOKIE_KEY_FILEDOWNLOAD);
    if (position >= 0) {
      var startIdx = position + COOKIE_KEY_FILEDOWNLOAD.length;
      var endIdx = COOKIES.indexOf(';', startIdx);
      if (endIdx < 0) {
        endIdx = COOKIES.length;
      }
      isFileDownload = decodeURIComponent(COOKIES.substring(startIdx, endIdx)) == 'true';
    }
    // fileDownloadがtrueなら繰り返し終了
    if (isFileDownload) {
      clearInterval(intervalId);
      var date = new Date();
      date.setTime(date.getTime() - 1);
      document.cookie = COOKIE_KEY_FILEDOWNLOAD + 'false; path=/; max-age=0';
      stopLoading(); // ぐるぐるやめる的メソッド
    }
  }, 500);
});
```
* Set-Cookieされた値を参照することでダウンロード成功時にぐるぐるを止めるようにしている。

# 参考
* 日本語ファイル名ダウンロード https://www.greptips.com/posts/869/
* ResponseEntityの使い方 https://qiita.com/YAKINIKU/items/abaa54ba531a30850d10
* ファイルダウンロード完了後に画面遷移などをjavascriptで行う http://nabehiro.hatenablog.com/entry/20140208/1391850498
* javascriptでcookie https://so-zou.jp/web-app/tech/programming/javascript/cookie/