OmniAICreator/Qiita-1.07M huggingface dataset:
Serverless Framework ランタイムRubyでgemを使えるようにする

## はじめに

AWSのLambdaでRubyが使えるようになって色々実務で触っているので、ちょこちょこ更新していこうと思います。

## 環境

* Ruby 2.5
* Node 11.9.0
* Serverless Framework 1.36.1
* Mac OS X 10.14.2

> rbenvとNodejsのインストールは完了している前提です。

## RubyのバージョンをLambdaランタイムのRubyバージョンに合わせる

> 2019/2/14現在 LambdaのRubyバージョンが2.5.0なので、それに合わせて、rbenvで2.5.0をインストールしておきます。
> すでにインストールしている場合はこの項目をスキップしてOKです

```
// 以下のコマンドでrbenvでインストール出来るRubyのバージョンを確認します
$ rbenv install -l

// 2.5.0がなかったら、以下を実行し、最新のRubyバージョンをインストール出来るようにします。
$ brew update
$ brew upgrade ruby-build

// 2.5.0があったら、以下を実行
$ rbenv install 2.5.0

// インストール出来ているか以下で確認をする
$ rbenv versions
```

## Lambda関数の作成

```
// serverless frameworkをグローバルにインストール
$ npm i -g serverless

// 作業ディレクトリの作成
$ mkdir Lambda

// 作業ディレクトリ内へ移動
$ cd Lambda

// serverlessコマンドのエイリアスslsを使って関数を作成
$ sls create -t aws-ruby -p myFunc

// 関数のディレクトリ内へ移動
$ cd myFunc

// この関数のRubyバージョンを2.5.0に設定
$ rbenv local 2.5.0

// おまじない
$ rbenv rehash
```

## Gemを使用出来るようにする

```
// bundlerをインストールしておく
$ gem install bundler

// Gemfileを手動で作成
$ touch Gemfile
```

Gemfileに`source`を記述してGemを使えるようにします

```yaml
source 'https://rubygems.org'

gem 'aws-record', '~> 2'
```

上記を記述したら、以下を実行

```
// いきなりdeploymentが出来ないため
$ bundle install --no-deployment

// 関数と一緒にデプロイするために以下を実行
$ bundle install --deployment
```

以上までで、`myFunc`ディレクトリは以下のような構造になります。

```
- handler.rb
- serverless.yml
- Gemfile
- Gemfile.lock
- vendor/
```

## handler.rbでrequire

```rb
require 'json'
require 'aws-record'

def main

end
```

みたいにしてあげれば、ライブラリが使えるようになります。
しばらく、serverless関連の話題を投稿していこうと思います。
[Hubspot] でウェブサイトを構築

インバウンドマーケティング統合型プラットフォームの「Hubspot」の一部であるCMS機能を使いウェブサイトを構築してみます。

# HubL
発音：ハボル？！を使って書き上げます。HubLはテンプレートエンジンであるJinjaをベースにしているそうです。 Jinjaに触れたことも見たこともないのでとりあえず進めてみます。

# Delimiters (デリミタ)
ここからステイトメントだよ、と示す場合にデリミタを使います。Stateme, Expression, Epxression Statement, Comments があります。

# Modules (モジュール)
ModuleはCMSを管理している人が編集することのできるパーツになります。

例：
HubL

```
{% text "simple_section_title" label='Enter text for this section title', value='This is a section title' %}
```

Output

```
<span id="hs_cos_wrapper_simple_section_title" class="highlight hs_cos_wrapper hs_cos_wrapper_widget hs_cos_wrapper_type_text"
style="" data-hs-cos-general-type="widget" data-hs-cos-type="text">
This is a section title
</span>
```


# Variables and macros (変数とマクロ)

下記のように変数を設定することもできます。

例：
HubL

```
{% set primaryColor = '#F7761F' %} {# defines variable and assigns HEX color #}
        
a {
color: {{ primaryColor }}; {# prints variable HEX value #}
    }
```

Output

```
a {
   color:#F7761F;
}
```


# Filters and Function (フィルターとファンクション）

下記のように変数を入れ替えることができます。

HubL

```
{{ content.publish_date_local_time|datetimeformat('%B %e, %Y') }} 
```
Output

```
April 29, 2015
```

# If (もし？)

選択された変数値によって表示を下記のように制御することができます。

```
{% choice "department" label='Choose department', value='Marketing', choices='Marketing, Sales, Dev, Services' export_to_template_context=True %}
        
{% if widget_data.department.value == 'Marketing' %}

<h3>Want to join our amazing Marketing team?!</h3>
<h4>We have exciting career opportunities on the {{ widget_data.department.value }} team.</h4>

{% elif widget_data.department.value == 'Sales' %}

<h3>Are you a Sales superstar?</h3>
<h4>We have exciting career opportunities on the {{ widget_data.department.value }} team.</h4>        
        
{% elif widget_data.department.value == 'Dev' %}
        
<h3>Do you love to ship code?</h3>
<h4>We have exciting career opportunities on the {{ widget_data.department.value }} team.</h4>
        
{% else %}
        
<h3>Want to work with our awesome customers?</h3>
<h4>We have exciting career opportunities on the {{ widget_data.department.value }} team.</h4>
        
{% endif %}      
```

# For loops　(ループ処理)

下記のようにループ処理することができます。

{% set bears = ['panda bear', 'polar bear', 'black bear', 'grizzly bear', 'koala bear'] %}

HubL

```
<h1>Types of bears</h1>;
<ul>
{% for bear in bears %}
<li>{{ bear }}</li>
{% endfor %}
</ul>
```

Output

```
<h1>Types of bears</h1>
<ul>
<li>panda bear</li>
<li>polar bear</li>
<li>black bear</li>
<li>grizzly bear</li>
<li>koala bear</li>
</ul>
```

# Include

テンプレート内に他のファイルも簡単にインクルードすることができます。

```
{% include "custom/page/web_page_basic/my_footer.html" %}
{% include 'generated_global_groups/2781996615.html' %}
{% include "hubspot/styles/patches/recommended.css" %}
```

# Block

より複雑なサイトを構築するために各コンポーネントをブロック化することができます。

```
{% extends "custom/page/web_page_basic/my_template.html" %}
{% block my_sidebar %}
<h3>Sidebar title</h3>
<ul>
<li>Bullet 1<li>
<li>Bullet 2<li>
<li>Bullet 3<li>
</ul>
{% endblock %}
```

---

一旦基本はここまでです。 次は実際に構築してみます。
カラーミーショップでページ下に全ページ共通で配送方法などの表記をする

# やりたいこと
![image.png](https://qiita-image-store.s3.amazonaws.com/0/356382/4a4604f0-98ba-e15b-3a85-7681599faa40.png)
（商品の下に設置するので「デザイン」＞「共通」の部分に表記する）

#やったこと
```HTML:共通ページ

<h3>お支払い情報</h3>
 <{section name=num loop=$sk_payment}>
 <h4><{$sk_payment[num].name}></h4>
 <{$sk_payment[num].other}>
<{/section}>
```

※事前にショップ作成＞決済＞ご利用中の決済方法で決済方法を入力、HTMLでテーブルタグだの諸々で入力はしてあるものとする←これで登録した内容をそのまま表示させたい

#試行錯誤

[独自タグ一覧（PC、スマートフォン） | カラーミーショップ　マニュアル](https://shop-pro.jp/manual/menu_06_02_01)を見て確認した処、共通ページ部分にある```shop payment_way```か```sk_payment name```かと思う。
けれどもこれをどう使うかわからない。というかそのあたり書いてくれ公式ページ（見逃しているだけかもしれない）。

というか、上記ページが現在
>【例１】共通html内に、【ショップタイトル】を表示するには、変数【shop_name】を使用します。
　記述例：<{ $shop_name }>  
　
【例２】商品詳細html内に、【商品ID】を表示するには、変数【product】と【id】を使用します。
記述例：<{ $product.id }>
　
【例３】<{section}>～<{/section}>で囲まれている部分は、リストの数分だけループします。
<{section name=num loop=$productlist}> ・ ・ （ここがループ） ・ <{/section}>

っていうのしかないのに一体どうやって理解しろっていうんだ……。numってなに！？から始まる人間には難易度が高い。

とりあえず```<{$shop.payment_way}>```で記入→表記されず
```<{$sk_payment.name}>```で記入→表記されず

ふと前回の[カラーミーでオプションプルダウンに価格も表示する方法 - Qiita](https://qiita.com/1asa1/items/bdce8a6a9557fac858c4)でやったことを思い出し、配列として表示させようとする。

```<{$sk_payment.name|@debug_print_var}>``` が前回と同様に連想配列っぽい表記がされたため、おそらくこれは連想配列と判断。
もしかして、カラーミーの上記独自タグ表記でタグが二列並んでるのは連想配列なのか？　とやっと気付く。

「カラーミー　連想配列　表示」などで検索し、[カラーミーショップ 独自タグの使い方まとめ | ホムペディア](https://homupedia.com/colorme-template-tags.html)にたどり着く。

>ループタグの使い方

のとこにめっちゃ普通に書いてあるーーーーー！！！！
しかもこのページめちゃくちゃわかりやすい……ありがたい……。

あとは前回やったこととホムペディアさんのページに書いてあることを見よう見まねでやったら成功、出来上がり。
同じようにすれば配送方法なども楽に設置できるので、変更したのでトップだの今日つページだのをもう一度編集という目に遭わないで済む。
[Ubuntu 18.04] 脳死でPythonの開発環境を構築するための備忘録


## Ubuntu用の前準備

`pyenv install`したときに発生するエラーは大体以下のパッケージが入っていないことが原因。


```
sudo apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev \
libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev \
xz-utils tk-dev libffi-dev liblzma-dev python-openssl
```

#### [補足] Mac用の前準備

下記パッケージをbrewでインストール

```
brew install readline xz
```

## pyenv

Cloneして`~/.bash_profile`に下記を追加

```
$ git clone https://github.com/yyuu/pyenv.git ~/.pyenv
```

```
export PYENV_ROOT=$HOME/.pyenv
export PATH=$PYENV_ROOT/bin:$PATH
eval "$(pyenv init -)"
```

## pyenv-virtualenv

Cloneして`~/.bash_profile`に下記を追加

```
git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv
```

```
eval "$(pyenv virtualenv-init -)"
```

## 新しい環境作成

```
pyenv virtualenv 3.6.0 buffo3.6.0
```

## 切り替えは`activate/deactivate`で行う

```
pyenv activate buffo3.6.0
```

今後のリリースでpromptの変更がなくなるみたいなので`export PYENV_VIRTUALENV_DISABLE_PROMPT=1`を`~/.bash_profile`に追加しておく。

```
pyenv-virtualenv: prompt changing will be removed from future release. configure `export PYENV_VIRTUALENV_DISABLE_PROMPT=1' to simulate the behavior.

```
ジェイウォークなカラムに格納された値のどれかが、リストのどれかと一致するものを検索したい

#まずは結論から
```SQL
SELECT * 
FROM "athena"."test_table" 
WHERE arrays_overlap(split("id_list",','), ARRAY['1','2','3','4','5'] );
```

#前提・背景・やりたいこと ...など
- AWS Athenaでcsvファイルに検索をかける
- AthenaでSQLを実行するため、Prestoの利用ができる
- csvファイルにはジェイウォーク[^1]なカラムが含まれる
- ジェイウォークなカラムに入っている値の"どれか"が、指定リストのどれかと一致するするものを検索したい
- 速度は今回未考慮

[^1]: １フィールドに複数の値がカンマ区切りで格納されているもの。本来のDBではアンチパターンだが、今回は色々な制約のもと中間ファイルを作ったり、RDBにしたりが不可なので、どうにかこのまま検索したい。

#解決法
Prestoに用意されている２つの関数を用いて解決
###split(string, delimiter)
stringをdelimiterで区切ってARRAY型に変換
###arrays_overlap(x,y)
xの要素のどれかがyの要素のどれかと一致した場合Trueを返す

#まとめ
比較的簡単に書けました。
速度は実測にて耐えられるかを確認します。
（きっと速度は遅くなるのでしょう。。。）

もっといい方法があれば教えてください。
にしても、タイトルが長い...

#参照
[Presto 0.172 Documentation](https://prestodb.github.io/docs/0.172/index.html)
ラズパイ Time Machine化で Failed to add service: Local name collision

USB接続のHDDを買ったので、Time Machineのバックアップ先として使っています。USBでMacに接続していると、いちいちアンマウントしたりするのが面倒なので、以下を参考にラズパイ経由でネットワーク越しに動作するようにしてみました。

* https://medium.com/@abjurato/using-raspberry-pi-as-an-apple-timemachine-d2fceecb6876
* https://github.com/mr-bt/raspberrypi-timemachine

おおよそこの手順に従って設定したところ、共有ドライブの設定まではできるものの、Time Machineのディスク選択には共有ドライブが現れませんでした。

ラズパイで、netatalkサービスのstatusを確認すると、`Failed to add service: Local name collision`というエラーが出ていました。

```
pi@raspberrypi:~ $ sudo systemctl status netatalk
● netatalk.service - Netatalk AFP fileserver for Macintosh clients
   Loaded: loaded (/lib/systemd/system/netatalk.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2019-02-13 17:38:42 JST; 16min ago
     Docs: man:afp.conf(5)
           man:netatalk(8)
           man:afpd(8)
           man:cnid_metad(8)
           man:cnid_dbd(8)
           http://netatalk.sourceforge.net/
  Process: 514 ExecStart=/usr/local/sbin/netatalk (code=exited, status=0/SUCCESS)
 Main PID: 546 (netatalk)
      CPU: 7.379s
   CGroup: /system.slice/netatalk.service
           ├─546 /usr/local/sbin/netatalk
           ├─547 /usr/local/sbin/afpd -d -F /usr/local/etc/afp.conf
           ├─548 /usr/local/sbin/cnid_metad -d -F /usr/local/etc/afp.conf
           └─773 /usr/local/sbin/cnid_dbd -F /usr/local/etc/afp.conf -p /media/tm -t 7 -l 5

Feb 13 17:38:42 raspberrypi systemd[1]: netatalk.service: PID file /var/lock/netatalk not re
Feb 13 17:38:42 raspberrypi systemd[1]: netatalk.service: Supervising process 546 which is n
Feb 13 17:38:42 raspberrypi systemd[1]: Started Netatalk AFP fileserver for Macintosh client
Feb 13 17:38:43 raspberrypi netatalk[546]: Netatalk AFP server starting
Feb 13 17:38:43 raspberrypi netatalk[546]: Failed to add service: Local name collision
Feb 13 17:38:43 raspberrypi netatalk[546]: Registered with Zeroconf
Feb 13 17:38:43 raspberrypi cnid_metad[548]: CNID Server listening on localhost:4700
Feb 13 17:38:49 raspberrypi afpd[547]: Netatalk AFP/TCP listening on 10.60.100.92:548
Feb 13 17:50:18 raspberrypi afpd[761]: pam_unix(netatalk:session): session opened for user p
Feb 13 17:51:05 raspberrypi afpd[788]: pam_unix(netatalk:session): session opened for user p
```

netatalkをインストールするとき、より新しいバージョン`3.1.12`があったので、それをインストールしたのがまずかった。

* https://github.com/mr-bt/raspberrypi-timemachine/issues/4

ここにある通り、不要な`/etc/avahi/services/afpd.service`を削除したところ、無事Time Machineのバックアップ先として利用できました。
Confluenceの記事をesa.ioに移行する方法

# 概要
Confluenceからesaに移行したい！
でもConfluenceはjson　exportなんて高度なことはできない！

ならparseすればいいじゃない。

ruby触ったことがほとんどないので好きなようにリファクタしてください。


# 手順

1. Confluence記事をhtml exportする。
2. esaのaccess_tokenを取得する
3. 以下のgemを入れる。

```Gemfile
gem "esa"
gem "nokogiri"
gem 'reverse_markdown'
```

3. 以下のscriptを走らせる


# コード

```ruby
#! /usr/bin/env ruby

require "nokogiri"
require "esa"
require "reverse_markdown"

client = Esa::Client.new(access_token: 'ここに発行したトークン', current_team: 'チーム名')

input = "/Users/hoge/落としてきた記事ディレクトリ/"
title_text = ""
body_text = ""
body_text_md = ""

Dir.glob("#{input}*.{html}"){ | file |
  doc = Nokogiri::HTML(open(file))

  doc.xpath('//head//title').each do |node|
    title_text = node.inner_text #記事タイトル
  end

  doc.search("//div[@id='main-content']").each do |node|
    body_text = node.inner_html #記事本文
    body_text_md = ReverseMarkdown.convert body_text #htmlをマークダウンに変換する
    body_text_md.lstrip #先頭の空文字を消す
  end

  #esaの/tempディレクトリに記事を作成
  client.create_post(
    name: title_text,
    category: "/temp",
    tag: "confluence",
    wip: false,
    body_md: body_text_md,
  )
}
```

# 問題点
- Confluenceはテーブル内改行をしまくるのでテーブルが壊れる。  
```
改行を`<br>`に置換して不要なスペースなどは削除するようにする。
```
- 画像が見れない  
```
記事データと一緒に落としてきてそれをみているがそのままだと画像が取れない。
一旦esaにあげる必要がある
```
Shellでファイルテンプレート的な機能を実現

# 発端
rubyの開発をする時、`.erb` などでテンプレートを記入して、いざ使う時変数展開(Rendering)すれば柔軟に対応できる。
しかしだいたいこういう機能はRuby、PythonやJavaScriptのような高水準言語でしか実装出来ない。Dockerのような極小システムを使う時、わざわざRubyをインストールするのもだるいし、Shellでなんとか対応してみた。

## 2019-2-15追記
@hnw さんがご指摘した通り、これはあくまでshellだけ作動する環境での一時対策であり、`nginx:alpine`などDockerのイメージを使う場合は素直に[envsubst](https://github.com/a8m/envsubst)を使った方が効率的である。

# TL;DR

![shut-up-and-show-me-the-code.jpg](https://qiita-image-store.s3.amazonaws.com/0/87438/40d979f7-07db-06e7-3d32-67532a79c2b6.jpeg)

コアなファンクションは下記の四行です

```sh
while read line || [ -n "${line}" ]
do
  echo $(eval echo "''${line}")
done < ./template.txt
```

上記`template.txt`の中身は:

```template.txt
This is ${USER}\\'s computer.
Home directory is ${HOME}.
```

Rendering結果は:

```
This is jerrylee's computer.
Home directory is /Users/jerrylee.
```

# 解説
## 原理
`template.txt`の内容を一行ずつ読み取り、`${USER}`のようなところを環境変数の該当変数で展開して吐き出す。
`'` などShellでの制御文字は `\\'` でエスケープする。いわば変数の*二重展開*である。

ここの変数の二重展開も少し特別のもので、ネット上は該当する記事は見つかっておらず、試行錯誤でやっとたどり着いたもの。

ネット上に出されたパターンをだいたい試してみた、結果はこちら。

```sh
echo $line
# `# File Template Demo` => `# File Template Demo`
# `home: ${HOME}` => `home: ${HOME}`

echo $(eval echo '$'${line}) # OR `echo $(eval echo '$'$line)`
# `# File Template Demo` => `0 File Template Demo`
# `home: ${HOME}` => `: /Users/jerrylee`

echo $(eval echo "'$'${line}")
# `# File Template Demo` => `$# File Template Demo`
# `home: ${HOME}` => `$home: /Users/jerrylee`

echo $(eval echo "${line}")
# `# File Template Demo` => `` # 改行だけでる、コメントアウトが効いたと思う
# `home: ${HOME}` => `home: /Users/jerrylee`

echo $(eval echo "''${line}")
# `# File Template Demo` => `# File Template Demo`
# `home: ${HOME}` => `home: /Users/jerrylee`
```

## readline
別に一気にファイルを読み込んで処理しても構わないが、２箇所つまずく場所がある。
- 改行、ファイルの改行は変数展開の時で予想外な動きをする可能性がある
- メモリ使用量、大きなファイルを処理する時、無駄にメモリを使うのはよくない

## `|| [ -n "${line}" ]`
この構文を追加すれば、仮にテンプレートの最後に改行がなくても、最後の行まで読み取れる。

# 実用例

```render.sh
#!bin/sh

if [ ! -f $1 ]; then
  echo "Usage:\n$ sh render-console.sh template.tpl > target.txt"
  exit 1
fi

while read line || [ -n "${line}" ]
do
  echo $(eval echo "''${line}")
done < $1
```

```template.txt
My name is ${MY_NAME}
```

上記 `render.sh` と `template.txt` を作成したら、以下コマンドを実行する。

```sh
$ export MY_NAME=Alice; sh render.sh template.txt > result.txt
```

`MY_NAME` が定義され、`result.txt` が生成される。

```result.txt
My name is Alice
```

# 余談
改めてShell Script ~~はただのオバハンではないことがわかった~~ の表現力に驚いた。

# 参考
https://askubuntu.com/a/121868
https://qiita.com/kod314/items/f8aa4929501882e97b38
https://orebibou.com/2015/01/シェルスクリプトでevalコマンドを用いた変数の2重/
https://qiita.com/Ets/items/a7fa24b138b8ee883dac
https://www.server-memo.net/shellscript/read-file.html
https://qiita.com/hnw/items/291090f8632f3b40e1a0
OUT PUT React Redux

# Reduxの流れ
OUTPUT場としてメモがてらに書く

## とりあえずインストール

```
npm i -S redux
```

## reducer

``` javascript
//初期state定義
const INITIAL_STATE = {
  tasks: []
}

//tasksReducerの定義
export const tasksReducer(state = INITIAL_STATE, action){
  switch(action.type){
    case 'ADD_TASK':
      return {
        ...state,
        tasks: [...state.tasks, action.task]
      };
    default:
      return state;
  }  

```

reducerでstoreの変更したいところを書く
今の所reducerが一つしかないので,ここのINITIAL_STATEだけがstoreのstateになる

## Action
``` javascript
const addTask = task => ({
  type: 'ADD_TASK',
  task
})
```

追加したいタスクを引数として受け取り、Actionオブジェクトをreturnするだけの関数

## store
``` javascript
import { createStore } from 'redux';

import taskReducer from './reducer' //reducerを置いてあるpath

const store createStore(taskReducer);

const addTask = task => ({
  //省略
})

store.dispatch(addTask('明日わさびを買う'))

```

createStoreでstoreを生成
store生成にはreducerが必要なのでcreateStoreの引数にreducerを渡す。

storeのdispatchメソッドを使ってactionを発行してreducerによって状態を変える
staticmockをmacOSで動かすためにPHP7とrunkitをインストールする

PHPで単体テストをするとき、 単体テストフレームワーク[PHPUnit](https://phpunit.de/) と static methodsの挿げ替えに [tototoshi/staticmock](https://github.com/tototoshi/staticmock) を利用している。

普段の開発サーバーで意識していなかったが、macOSで開発環境を構築するときに手間取った。

macOSにビルトインされているPHPは扱いづらいため、新たに [homebrew](https://brew.sh/index_ja) でPHPをインストールする

```
$ brew search php
==> Formulae
brew-php-switcher           php-code-sniffer            php@7.1                     phplint                     phpmyadmin
php                         php-cs-fixer                php@7.2                     phpmd                       phpunit

==> Casks
eclipse-php            eclipse-php            netbeans-php           netbeans-php           phpstorm               phpstorm
```

特に理由がなければ、 `php` フォーミュラをインストールすれば良い(私は `php@7.1` を利用)。 `php` フォーミュラを選んだ場合、2019年2月14日段階では、PHP 7.3.2がインストールされる。

`php@7.1` を選んだ場合、 brew link されないのでCLIの出力に従ってPATHに追加すること。

tototoshi/staticmock は実装の書き換えで[runkitを使用している](https://github.com/tototoshi/staticmock/search?q=runkit&unscoped_q=runkit)ため、 [runkit](https://pecl.php.net/package/runkit) のインストールを別途行う必要がある。ただし、peclのrunkitはPHP7に対応していないので、[runkit7/runki7](https://github.com/runkit7/runkit7)からインストールする。

- 関連記事:[PHP7でStaticMockを動かす](https://qiita.com/tototoshi/items/7304a3db7bb139a8ae1f)
- 関連記事:[runkit と uopz について](https://qiita.com/kunit/items/43ca86a461d2e5e051cf)

[インストール方法はrunkit7のリポジトリ](https://github.com/runkit7/runkit7#installation
)に従えば良い。runkit7のインストール前に、phpのパスがHomebrewでインストールされたパスであることを確認すること。

```
$ ls -al $(which php)
-r-xr-xr-x  1 tamanobi  staff  11559124  2 14 10:39 /usr/local/opt/php@7.1/bin/php
$ brew --prefix php@7.1
/usr/local/opt/php@7.1
```

Homebrewでインストールしたphpに、PHP拡張を伝えるためにphp.iniを編集する。php.iniのパスは `php --ini` で調べられる。

```
$ php --ini
Configuration File (php.ini) Path: /usr/local/etc/php/7.1
Loaded Configuration File:         /usr/local/etc/php/7.1/php.ini
Scan for additional .ini files in: /usr/local/etc/php/7.1/conf.d
Additional .ini files parsed:      /usr/local/etc/php/7.1/conf.d/ext-opcache.ini
```

php.iniを開くと `extension=msql.so` などのサンプルを見ながら `extension=runkit.so` を追加する。

最後に以下のコマンドで `runkit` が使えるようになっているか確認する。 `bool(true)` となれば読み込まれている。

```
$ php -r 'var_dump(extension_loaded("runkit"));'
bool(true)
```

もし、ApacheやNginxでPHPを利用している場合は、CLIと違ってリロードが必要。
Cloud Firestoreデータ型まとめ（JS版）

こんにちは、Firebase素晴らしいという想いを日々深めている私が来ました。先日Cloud Firestoreのベータ版から正式版への格上げ（？）が発表されて安心して使えるようになりましたね。こっち（開発者）はベータでも気にしないけどクライアントは気にするかもなのでよかったよかった。

[Cloud Firestore has Gone GA, Lower Pricing Tiers, New Locations, and more!（Firebase公式ブログ）](https://firebase.googleblog.com/2019/01/cloud-firestore-in-general-availability.html)

今回はそのFirestoreのデータ追加について書きます。公式ドキュメントが充実していますが、参照型はどうやって作成するのかとか、けっこう探したんでまとめてみました。コードは全部JSです。

Firestoreではいくつかのデータ型がサポートされていますが、文字列、数字、ブール値、配列、マップ（オブジェクト）は何も意識せずにリテラル書いて渡せばOK。マップの配列とかネストしててもまんまでいける。なんかもう簡単すぎてやばいぜ。

```Javascript
firebase.firestore().collection('users').doc('123').set({
    name: 'yuiken',
    lifepoint: 100,
    alive: true,
    hobbies: ['Origami', 'Insect', 'Bird watching'],
    lunch_histories: [
        {menu: 'Pasta', price: 1000, date: new Date('February 14, 2019')},
        {menu: 'Curry', price: 780, date: new Date('2019-02-08 00:00:00')},
    ],
    timestamp: firebase.firestore.FieldValue.serverTimestamp(),
    friends: [
        firebase.firestore().doc('users/456'),
        firebase.firestore().doc('users/789')
    ],
    location: new firebase.firestore.GeoPoint(35.681, 139.767),
});
```

リテラルで書けないタイムスタンプ、参照(reference)、地理位置情報(geopoint)は以下のように作成します。これも知ってしまえば簡単。

#### タイムスタンプ型

Dateオブジェクトを使います。文字列で "2019-02-10 12:00:00" とか書いてもダメです。

```Javascript
new Date('2019-02-10 12:00:00')
```

Dateオブジェクトでクライアントのタイマー取得してもしょうがないというケースが多いと思います。サーバ時間をセットする時は下記を使います。

```Javascript
firebase.firestore.FieldValue.serverTimestamp()
```

Firestoreから取得したドキュメントにセットされているタイムスタンプ型を扱うときはtoDate()でJSのDate型に変換します。

```Javascript
firebase.firestore().collection('users').doc('123').get().then(function(doc) {
    var timestamp = doc.data().timestamp.toDate();
}
```

#### 参照型

doc()メソッドでドキュメントへの参照を生成してそれをセットします。

```Javascript
firebase.firestore().doc('users/456')
```

Firestoreから取得した時も参照型のオブジェクトになっているので下記のような感じでドキュメントIDやパスにアクセスします。

```Javascript
firebase.firestore().collection('users').doc('123').get().then(function(doc) {
    console.log(doc.data().friends[0].id);    // "456"
    console.log(doc.data().friends[0].path);  // "users/456"
}
```

#### Geopoint型

下記のように緯度と経度を指定します。

```Javascript
new firebase.firestore.GeoPoint(35.681, 139.767);
```

数値は全て倍精度（64ビット）で扱われるもよう。他にバイナリデータを扱うと思われるバイト型というのもあるようなのですが、ドキュメント見つからず…
jQueryの読み込みについて

#jQueryの読み込みについて
---
メモ用に

HTMLファイルからjQueryを記述したjsファイルを読み込もうとすると
下記のエラーが発生して読み込めなかった。

`Uncaught ReferenceError: $ is not defined`

ファイル構成は下記の通り

- index.html
- stylesheet.css
- js/script.js

index.html内のheadとbody内に読み込みの処理を記述
`<script src="js/script.js"></script>`

###原因
---

jQuery本体を先に読み込まないといけなかったという初歩の初歩の所で躓いてました。

jQuery本体というのをjsディレクトリ内のjsファイルの事だと
勘違いしており、jQuery本体を参考先のURLから直接読み込み
or　ダウンロードしてローカルで読み込みの2通りで解決できました。

script.jsにjQuery本体
sample.jsにやりたい処理を実装
htmlファイルは下記の通り記述

```html:index.html
<head>
<script src="js/script.js"></script>
<script src="js/sample.js"></script>
</head>

<body>
<script src="js/script.js"></script>
<script src="js/sample.js"></script>
</body>
```


###参考
----

[jQueryファイルの読み込み方法(CDNや直接ダウンロード)](https://www.flatflag.nir87.com/cdn-1346#Google_Hosted_Libraries)
VSCode v1.31.1にアップデートしたらsettings.jsonを開いたときの表示が変わっていた件。

自分だけかもしれないのと需要がなさそうですが、一応メモとして書き記しておこうと思います。
先日、VSCodeを1.31.1にバージョンアップしたら、settings.json開いたときの見え方が変わっていました...!
どうやらデフォルト設定が変わったみたいです。

## 以前までのsettings.jsonを開いたときと起こっていた事象
いままではユーザー設定、ワークスペース設定のsettings.jsonを開くと下の画像のようにデフォルト設定もスプリットで見えていていたはずなんですが......。
<img width="1367" alt="スクリーンショット 2019-02-13 11.15.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/270133/ed5cd1a4-a0a7-c799-3000-3f0ed978dc6c.png">
<br>
これがアップデートしたらこんな表示に変わってしまってました！
自分が設定したものだけ見えている感じです。
<img width="1091" alt="スクリーンショット 2019-02-13 11.28.49.png" src="https://qiita-image-store.s3.amazonaws.com/0/270133/e4232050-ba9f-6dd3-8e86-5c7e80e7c057.png">

デフォルト設定がどうなってるか見えないので、追加で設定変更したいとき少し困るなと感じました。
公式を都度見ろよ！って話ですが、、、。
以前の使い勝手が良いなと思っているので、前みたいな表示に戻します。

## 解決策
公式[Updates January 2019](https://code.visualstudio.com/updates/v1_31)のUse simple text editor for editing settings as JSONを見てみると「分割されたJSONエディターの代わりに単純なJSONエディターが表示されます」みたいなことが書かれていました。

さらに少し先をみると以前のような左側にデフォルト設定がある分割されたJSONエディターに戻したいなら、
`workbench.settings.useSplitJSON`をアクティブにしてあげれば良いみたいです。

### JSONの場合
ユーザー設定のsetting.jsonに`workbench.settings.useSplitJSON: true`を加えるだけです。

```json:settings.json
{
  "guides.enabled": false,
  "workbench.colorTheme": "Monokai",
  ...
　　　　...
  // 以下を追記する
  "workbench.settings.useSplitJSON": true
}
```

### GUIの場合
設定の検索で"workbench settings"で絞り込むと画像のような表示になるので、一番下の`Workbench　›　Settings: Use Split JSON`にチェックを入れるだけです。
<img width="969" alt="スクリーンショット 2019-02-14 15.37.15.png" src="https://qiita-image-store.s3.amazonaws.com/0/270133/298e2d8d-827f-efab-655a-6147a50d180c.png">

## P.S.
普段からGUI使っている人はさほど意味のないことかもしれませんが、いままでJSONでエディター設定をいじっていたのでこの変更は一瞬困惑しました。でも、すぐに以前のものに戻せたのでまぁ良かったです。
Flutterのお気に入り機能(見た目だけ)

##はじめに
FlatButtonでお気に入り機能を実装します。
初期は、枠線だけのハートが表示されていて、押すと赤くなり、もう一度押すと枠線だけのハートに戻るという機能です。
今回は外見だけの説明で中身の実装は後々書きます。

##コード全体
```dart:main.dart
bool favorite;
FlatButton(
   child: Icon(
      favorite == true ? Icons.favorite : Icons.favorite_border,
      color: favorite == true ? Colors.red : Colors.black38,
     ),
   onPressed: () {
      setState(() {
         if (favorite != true) {
       //ハートが押されたときにfavoriteにtrueを代入している
           favorite = true;
         } else {
           favorite = false;
         }
       });
     },
   ),
```

##コードの詳細説明

```dart:main.dart

//ハートを押したかどうかを判定するためにある
bool favorite;

FlatButton(
   child: Icon(
      favorite == true ? Icons.favorite : Icons.favorite_border,
      color: favorite == true ? Colors.red : Colors.black38,
     ),
```

 ここでは、赤いハートか枠線だけのハートのどちらを表示するかを決め、表示しています。ハートが押されていればfavoriteにtrueが代入されています。

####【favorite == true ? Icons.favorite : Icons.favorite_border】
ここでは、favoriteにtrueが代入されていれば赤いハートを表示し、そうでなければ枠線のハートを表示するという処理です。

####【color: favorite == true ? Colors.red : Colors.black38】
ここでは色の設定。


```dart:main.dart
onPressed: () {
      setState(() {
         if (favorite != true) {
       //ハートが押されたときにfavoriteにtrueを代入している
           favorite = true;
         } else {
           favorite = false;
         }
       });
     },
   ),
```
ここでは、ハートボタンが押されたときにfavoriteにtrueかfalseを代入する処理と変更があったことを伝える処理が行われています。

####【setState】
setStateで変更があったことを伝えています。これがないとハートボタンを押しても再度読込しないと押されたことが反映されません。


その下のif文では、赤いハートであればfavoriteにfalseを代入。枠線のハートであればfavoriteにtrueを代入しています。

このtrueとfalseの変更で今どちらのボタンを表示すべきか判断できるようにしています。
関数やクラスを文字列を定義した変数で呼び出し

参考記事はこちら．
https://qiita.com/Chanmoro/items/9b0105e4c18bb76ed4e9

備忘録として記録．

```
eval("文字列")()
```
とすることで文字列に該当するクラスや関数を呼び出すことができます．関数の呼び出し処理をループにしたいときに便利ですね．ただし，コードの可読性が下がるので使い過ぎには注意．



```py
class a():
  def __init__(self):
    self.call_a()

  def call_a(self):
    print("クラスaを呼び出しました．")

class b():
  def __init__(self):
    self.call_b()

  def call_b(self):
    print("クラスbを呼び出しました．")


if __name__ == '__main__':
  cls_name = ["a", "b"]
  for cls in cls_name:
    c = eval(cls)()
```

出力結果

```
クラスaを呼び出しました．
クラスbを呼び出しました．
```

同様に関数に関しても以下の通り．

```py
def call_a():
  print("関数aを呼び出しました．")

if __name__ == '__main__':
  eval("call_a")()
```

出力結果

```
関数aを呼び出しました．
```
ES2015(ES6)のクラス、アロー関数の基礎

#前書き
Reactを使用するためにES6に関する知識が必要だったので、最低限の知識としてクラスとアロー関数について、簡単な例を通してまとめる。
#クラス

```javascript

class Person {
	
  // クラスの構造を決める
  constructor(name,age){
  	this.namae = name; // nameをthis.namaeに設定。
    this.toshi= age// ageをthis.toshiに設定。二つの属性を持ちました。
  }
  
  // クラス内にメソッドを作ってみる。
  sayHello(){
		console.log("Hello");
  }
    
  sayName() {
  	console.log(this.namae);
  }
  
  sayAge(){
		console.log(this.toshi);
  }
    
  // このメソッドはstaticで設定してみる。
  static sayBye(){
  	console.log("バイバイ")
  }
}
// クラスの利用はこんな感じ。構造はconstructorで確認しよう。
let me = new Person("太郎",18);
// メソッドを呼び出す
me.sayHello(); // Hello
me.sayName(); // 太郎
me.sayAge(); // 18

// 一つだけstaticで設定しました。これはクラス名から呼び出す。
Person.sayBye(); // バイバイ

// 継承
// クラス:Personと同じ機能を持つクラスを作る。
class Student extends Person{
}

// 呼び出してみよう。
let you = new Student("花子",18);
you.sayName(); // 花子
// Personと同じ機能を持っている。

// さらに継承。機能を加えたり、改変してみよう。
class club_member extends Person{

    // constructorにclubを加える。
	constructor(name, age, club){ 
  	super(name, age); // これでname,ageに関してはPersonと同じ設定を引きつぐ。
    this.club = club; // 属性:clubを追加。
  }
  
  // メソッドを追加してみる。
  sayClub(){
  	console.log(this.club);
  }
  
  // メソッドを上書きしてみる。オーバーライド。
  sayAge(){
		console.log("今"+this.toshi+"歳です");
  }
}

let him = new club_member("一郎",17, "卓球部");
him.sayClub(); // 卓球部
him.sayAge(); // 今17歳です
```

#アロー関数

```javascript
// アロー関数を使わない書き方
let Hello = function(day){
	console.log("今日は" + day + "日です。こんにちは");
}
Hello(12); // 今日は12日です。こんにちは

// これもあるね
function goodMorning(day){
	console.log("今日は" + day + "日です。おはよう");
}
goodMorning(21); // 今日は21日です。おはよう

// これをアロー関数で書いてみよう
let goodEvening = (day) => {
	console.log("今日は" + day + "日です。こんばんは");
}
goodEvening(31); // 今日は31日です。こんばんは

// 一行で収まるならこれでもいい。
let goodNight = (day) => console.log("今日は" + day + "日です。おやすみ");
goodNight(13); // 今日は13日です。おやすみ

// 変数が一つなら()がなくてもいい。
let goodEvening = day => {
	console.log("今日は" + day + "日です。こんばんは");
}
goodEvening(31); // 今日は31日です。こんばんは

// アロー関数を使うとthisに関する挙動がちょっと変わるぞ
let typeA = {
  val: "ドラゴン",
  show: function(){    
    let A = function (){
    	console.log(this); // thisの値には何が入っているでしょうか
    }
    A();
  }
}
typeA.show(); //Windowの情報が出る。 ※ブラウザで動作させた場合
    
let typeB = {
  val: "ドラゴン",
  show: function(){  
    let B = () => {
    	console.log(this); // thisの値には何が入っているでしょうか
    }
    B();
  }
}

typeB.show(); // {val: "ドラゴン", show: ƒ()}
// このようにthisの挙動が変化する。

```
以上です。```this```が簡単に宣言元を参照できる点でアロー関数の利点が大きいです。
Goで動的htmlを一定時間キャッシュさせる(Last-Modified)

# 動的な html をキャッシュさせる

基本的にブラウザは画像などのリソースについてはキャッシュするのですが、 HTML はキャッシュの対象外です。

キャッシュさせるためには、サーバー側からブラウザにキャッシュ可能であることを通知する必要があります。

今回はその方法を紹介します。

## なぜ Etag ではなく Last-Modified なのか？
キャッシュさせる方法として Etag という方法もあります。

こちらはハッシュ値等をやり取りし、前回のハッシュと差分があった場合にキャッシュを利用する、という利用目的で使うことが多いです。

動的な HTML では基本的にハッシュを取ることが難しいため、
時間を扱う Last-Modified で管理したほうが実装がしやすいのです。



## 手順
0. 最初のリクエスト時、HTMLレスポンスヘッダーに Last-Modified を設定して送信する
1. 次回以降のリクエストヘッダに If-Modified-Since がついてくるので、読み取る
2. 現在時刻と比較し、一定時間経過したか計測する
3. ↓

- 一定時間経過していなければ、ステータスコード304でレスポンスする
- 一定時間経過していれば、HTMLを生成して返す

## サンプル
下記は、最初にページをロードした後10秒間だけHTMLをキャッシュさせる例です。

時刻のパースやフォーマットは癖がありますが、すべてのユーザーが10秒間キャッシュの恩恵を受けられます。

```
package main

import (
	"flag"
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

var port = flag.String("http", ":8888", "HTTP port number.")

func init() {
	flag.Parse()

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

		sinceText := r.Header.Get("If-Modified-Since")
		if sinceText != "" {
			// JSTのまま time.Time にパースする
			loc, _ := time.LoadLocation("Asia/Tokyo")
			since, err := time.ParseInLocation("Mon, 02 Jan 2006 15:04:05 JST", sinceText, loc)

			// 10秒後の時間
			nowless10 := time.Now().Add(-10 * time.Second)

			// いろいろ表示
			fmt.Println()
			fmt.Println(since, err)
			fmt.Println(nowless10)
			fmt.Println(since.Before(nowless10))

			// 前回の記録から10秒以内であればキャッシュを読ませる
			if since.After(nowless10) {
				w.WriteHeader(http.StatusNotModified)
				return
			}
		}

		// HTMLの生成に3秒かかる想定
		time.Sleep(time.Second * 3)

		// Last-Modified を設定
		now := time.Now().Format("Mon, 02 Jan 2006 15:04:05 MST")
		w.Header().Set("Last-Modified", now)

		f, _ := os.Open("index.html")
		io.Copy(w, f)
	})
}

func main() {
	fmt.Printf("Start HTTP Server http://localhost%s/", *port)
	fmt.Println(http.ListenAndServe(*port, nil))
}

```

※ // いろいろ表示 というコメントの箇所は削除してもOKです。
※ 動作確認の際は適当に作った index.html を用意してください。

以上です。
Monaca(Cordova)で複数音源の同時再生をする

# やりたかったこと
iOS Android でBGMを流しながらSE音を再生する。

# 試してみたこと
**❌ Web Audio API**
iOSで再生されない。できればこれを使いたかった。
実は、大丈夫だろ〜！ということで、はじめに Web Audio API ですべて実装してしまいました。
痛い目をみました・・・。

**❌ cordova-plugin-media**
https://docs.monaca.io/ja/reference/cordova_7.1/media/
Monaca Docs にも載っているこちらです。
音源再生はされるのですが、再生できるのは一つの音源だけで、同時再生はできませんでした。

**⭕ cordova-plugin-nativeaudio**
https://github.com/floatinghotpot/cordova-plugin-nativeaudio
iOS Android 共に同時再生ができました。
・ 再生、停止、ループ、フェードイン・アウト、ぐらいの機能。
・ Monacaで使う場合はProプランでないと使用できない。
・ ミュート時でも音がでる（iPhoneの左上のスイッチがOFFの時）
ミュート時でも音が出るのは、今回のアプリではNGだったので改善しないといけませんでした。

# 導入手順

## Monaca にpluginの導入
通常なら

```
cordova plugin add cordova-plugin-nativeaudio
```

だけなのですが、Monacaは管理画面からpluginを導入しないといけません。
管理画面からcordova-plugin-nativeaudioと検索しても何も出てこないので
URL指定で https://github.com/floatinghotpot/cordova-plugin-nativeaudio と入れました。
結果はエラーが起こったので、**GitHubからzipデータをDL**して、そちらを登録しました。

## コード

```javascript

function onDeviceReady() {
  if (window.plugins && window.plugins.NativeAudio) {
    // プリロード処理
    window.plugins.NativeAudio.preloadComplex('sound', 'sound/sample.mp3', 1, 1, 0, function (msg) {
      // 再生 
      window.plugins.NativeAudio.play('sound');
    }, function (msg) {
      console.log('error: ' + msg);
    });
  }
}
document.addEventListener("deviceready", onDeviceReady, false);
```

これで、音源再生できれば一安心、あとはREADMEを見て好きにいじれます！

## ミュート時にも音が鳴ってしまう問題
https://github.com/floatinghotpot/cordova-plugin-nativeaudio/issues/82
issue にも上がっていました。
一通り目を通して、とりあえず plugin 内の　src/ios/NativeAudio.m　を見てみました。
そのなかに

```objc

    [session setCategory:AVAudioSessionCategoryPlayback error:nil];
```
という一文が、怪しい・・・検索してみました。↓
https://developer.apple.com/documentation/avfoundation/avaudiosessioncategoryplayback?language=occ

> your app audio continues with the Silent switch set to silent or when the screen locks. 

Silent switchがONでも再生し続けますよ。ということでしょうか。
上の一行をコメントアウトしてビルド

ミュートにしたら再生されなくなりました！！
これで使用条件を満たせました。
Cordovaのpluginは日本語記事がなかなかないので大変ですね。
Railsを始めてsqlite3まわりのエラーで躓いている人たちへ

2019/02/04から、ふつうにrails newをするとsqlite3まわりでエラーが起きるようになっています。
teratailを見ていたら、1日に数件これ関連の質問が上がってきて阿鼻叫喚な感じだったので、こちらにまとめておきます。

(2019/03/28 追記)
Rails5.2.3がリリースされました！
この問題は解消されています。めでたしめでたし。

## エラーメッセージ
> Puma caught this error: Error loading the 'sqlite3' Active Record adapter. Missing a gem it depends on? can't activate sqlite3 (~> 1.3.6), already activated sqlite3-1.4.0. Make sure all dependencies are added to Gemfile. (LoadError)

## 対処法
Gemfileを開いて、

```rb
gem 'sqlite3'
```
の行を

```rb
gem 'sqlite3', '~> 1.3.6'
```
に変更し、

```console
$ bundle install
```
を実行します。

## それでもエラーが出る場合
こんなエラーが報告されています。
> ActiveRecord::ConnectionNotEstablished No connection pool with 'primary' found.

もしくは
> 「プライマリ」の接続プールが見つかりません。

おそらく、gemの更新が反映されていません。
rails serverを再起動してください。

## 原因
Rails側のsqlite3のバージョン指定の問題です。
1.3.6以上、1.4.0未満しか受け付けないような指定になっていたのですが、2019/2/4にsqlite3のgemの1.4.0がリリースされたためエラーが出るようになりました。
以下の修正により、1.3.6以上、2.0.0未満のバージョンを受け付けるようになっています。
https://github.com/rails/rails/commit/6d5f2511e6d9b95a8ac8399c234aa6cd074af51d

既に5-2-stableブランチにもマージされているので、次のリリースでは問題が起きなくなっていると思います。

以下のissueとpull requestで議論されています。
https://github.com/rails/rails/issues/35153
https://github.com/rails/rails/pull/35154
【rails5】テーブルに複数の外部キーを追加する

#テーブルに複数の外部キー(foreign_key）を追加する

##パターン１、モデル生成時に、外部キーを生成する

１、Invitationテーブル作成。
２、user_idとproject_idカラムを生成し、両方のforeign_keyも生成出来る

フォーマット

```
rails g モデル名 参照先モデル名:references
```

```
複数でも同様
rails g モデル名 参照先モデル名:references 参照先モデル名:references
```

```
同時に他のカラムも追加
rails g モデル名 参照先モデル名:references 参照先モデル名:references カラム名:型
```

例

```
rails g model Invitation user:references  project:references destination_mail:string
```


##パターン２、モデル生成した後に外部キーを追加する

例
Issuesテーブル作成

```
rails g model Issues title:string created_user_id:integer project_id:integer assigned_user_id:integer description:text status:string deleted_at:timestamp
```

生成したマイグレーションファイル

```
class CreateIssues < ActiveRecord::Migration[5.2]
  def change
    create_table :issues do |t|
      t.string :title
      t.integer :created_user_id
      t.integer :project_id
      t.integer :assigned_user_id
      t.text :description
      t.string :status, default: 'open'
      t.timestamp :deleted_at

      t.timestamps
    end
  end
end
```

例、issuesテーブルに、２つの外部キー（created_user_idと、project_id）を追加する場合

```
フォーマット
add_foreign_key :参照元のテーブル名, :参照したいテーブル名, column: :参照元につける外部キー名
```

```
add_foreign_key :issues, :users, column: :created_user_id
add_foreign_key :issues, :projects, column: :project_id
```
調子乗り気味でWPFのWindowを開く

下記のようなアプリがあるとする。

・メニュー画面がある。
・そのメニューに複数のボタンがある。
・各ボタンを押すと、それぞれ別のWindowが立ち上がる。

#調子に乗る前の俺が書いたコード

```c#
// Window○○ は、自前のWindowクラス。

private void Button01_Click()
{
    var w = new Window01();
    w.Show();
}

private void Button02_Click()
{
    var w = new Window02();
    w.Show();
}

private void Button03_Click()
{
// 以下略
```

行数を節約するなら

```c#
new Window01().Show();
```
って書けば１行で書けるし、それでいいのかもしれない。

#調子に乗った俺が書いたコード

```c#
// Window○○ は、自前のWindowクラス。

/// <summary>
/// ウインドウを開く
/// <summary>
private void OpenWindow<T>() Where T : Window, new()
{
    var w = new T();
    w.Show();
}

private void Button01_Click()
{
    OpenWindow<Window01>();
}

private void Button02_Click()
{
    OpenWindow<Window02>();
}

private void Button03_Click()
{
// 以下略
```

Windowを開くメソッドが書きたかった。
だけど、インスタンスを生成してそのメソッドに渡すなら意味がない（Showすればいいだけだから）。
クラスを渡したら、メソッド内でインスタンスを生成して開いて欲しかった。

できたんだけど、インスタンス生成してShowする方が、シンプルでわかりやすくて良いのでは？という考えが消えない。
Linuxをインターネットへのゲートウェイにする

#背景

ESXi上で稼働しているVMをインターネットに接続したい
だが接続したいVMが稼働しているESXiとは異なるESXiにWi-Fiルータが接続されている
せっかくなのでWi-Fiルータが接続されているESXiにて稼働しているVMをルータ化して、他のVMはそいつをゲートウェイにしてインターネットに接続できるようにしてみる

![image.png](https://qiita-image-store.s3.amazonaws.com/0/354136/412844ce-0aa9-8efa-089b-5b4bb71a6077.png)

インターネットに接続したいVM : VM2
Wi-Fiルータが接続されているESXiにて稼働しているVM : VM1

※前提としてVM1がすでにインターネット接続できている状態とする

#環境
VM OS : RHEL7
ESXi Version : 6.5U1
Wi-Fiルータ : どっかのUQWiMaxモバイルルータにクレードルをぶっ刺したやつ

#いざ実践

以下のような流れで行う

1.VM1にてフォワーディング有効化設定
2.VM1にてNAT設定
3.VM2にてGatewayの変更

###[1] VM1にてフォワーディング有効化設定

カーネルの設定をいじくる
デフォルトでip_forwardは無効になっている
<pre>
 # cat /proc/sys/net/ipv4/ip_forward
 0</pre>

これを有効化する
<pre>
 # echo 1 > /proc/sys/net/ipv4/ip_forward
 # cat /proc/sys/net/ipv4/ip_forward
 1</pre>

これだけだと再起動したときに再び無効化されてしまうため、恒久的に有効化されるように/etc/sysctl.confに以下のエントリーを追加する。
<pre>net.ipv4.ip_forward = 1</pre>

###[2] VM1にてNAT設定
このままだとVM2からインターネットへの通信はできるが、インターネットからVM2への帰りの通信ができない。
なぜならWi-FiルータがNW2(10.0.0.0/24)の経路を知らないため
Wi-Fiルータにスタティックルートを登録することができればよいのだが、今回それはできない

そのためVM1にてNATができるように設定する必要がある
LinuxでNATをさせるにはiptables/firewalldを使用するのが手っ取り早い
RHEL7/CentOS7ではデフォルトでfirewalldが動作しており、firewallの設定でごにょごにょやれればよいがfirewallの設定に慣れていないため、今回はiptablesの関連パッケージをインストールしてiptablesでNATを実現させる

まずはfirewalldを停止させておく
<pre> # systemctl stop firewalld
 # systemctl disable firewalld</pre>

次にiptables関連パッケージをインストールする
<pre># yum install -y iptables-devel iptables-services
</pre>

iptabelsを起動する
<pre> # systemctl start iptables
 # systemctl enable iptables </pre>

NATを設定する
<pre> # iptables -t nat -A POSTROUTING -o ethXXX -j MASQUERADE </pre>
※ethXXXはNW1側のインターフェール名

###[3]VM2にてGatewayの変更

VM2のデフォルトゲートウェイをVM1のNW2のIFのIPアドレスにする


これでVM2がインターネットに抜けられるようになる！
Rubyでenum(Railsでない)

RubyでScalaみたいなEnumが欲しかっただけ。

```ruby
module C
  S = Struct.new(:a)
  No1 = S.new(1)
  No2 = S.new(2)
  VALUES = [No1, No2].freeze
end

p C::No1.a
p C::VALUES.find { |c| c.a == 1 }

```

んーもっとシンプルな方法ないかな
Amazon Connectを使ったフリーダイヤルの*電話番号への転送*について

# Amazon Connectを使ったフリーダイヤルの[電話番号への転送]について
半日使って調べた感じ、どうやっても電話番号へ転送した際に利用者の電話番号を通知できなかったが
理由がわかった (気がする）

# 結論
- 利用者(A:090) -> Amazon Connect (B:0800) -> スマホ等(C:080)への通話転送時は、利用者の番号(A:090)を転送先(C)に通知できない
    - これは総務省令により制限されている。
        - 総務省令、事業用電気通信設備規則における「異なる電気通信番号の送信の防止」
        - https://www.tca.or.jp/information/pdf/camouflage/guideline20081226.pdf
    - ここでいうと、(A)と(C)はDocomoとかのキャリアが管理してる。(B)はAmazonが管理してる
    - 上記の省令の中にこういう記載がある。で、たぶんAmazonは対応できてない。(する予定あるのかも不明)

```
「発信者番号設定事業者が、他の事業者が総務省から指定を受けた番号を発信者番号
（ここでは網間信号のパラメータではなく、着信者へ表示させるための発信者番号を意味する。以下同じ。）
に設定できるのは、予め番号指定事業者と発信者番号設定事業者の間で所要の運用ルールが確立されており、
且つ利用者と発信者番号設定事業者の間で必要な確認が行われている場合に限る。」
```

# Tips
- 転送先(C)がWEBアプリやスマホアプリだった場合、利用者番号を(C)に通知できる
- なぜならば、総務省令の範囲外だから ※電話回線(PSTN)ではなくSIPを使うため
- でも、電話回線つかいたい今回のケースではやっぱり通知できない

# 作ったフローはこんな感じ
- お問い合わせ属性にある、システム→お客様の番号を変数に格納して、転送先番号へパラメータで渡そうと思ったらそれができなかった..
<img width="1440" alt="Amazon_Connect_-_問い合わせフローの編集.png" src="https://qiita-image-store.s3.amazonaws.com/0/8571/b4ae0212-ab41-2757-4ac7-43d5d0b17290.png">


いや、出来るから！！って人が居たら、教えてほしいです m(_ _)m
PHP開発環境、フレームワークLaravel導入の簡単な流れ

MacBookPro2018にPHPの開発環境構築と人気フレームワークLaravelの導入したので、それについて流れをまとめます。ここでは初心者向けに、どういうものが必要か、僕が導入したものと流れを紹介します。なお具体的で詳細な構築方法は紹介しているサイトで確認して頂きたい思います。（実際、自分が導入したときは少し前だったのでコマンドのスクショ忘れたので、、、）

##想定
PHPエンジニア一年目、自宅の新しいPCにも開発環境を入れたいと思い構築。
iOS(MacBookPro2018年モデル)にてPHP開発環境とフレームワークLaravel5.5(LTS)を導入。


#目次
- なぜLaravel
- PHP開発環境に必要な「MAMP」とは？
- おすすめのエディタ「Atom」
- Laravel5.5(LTS)の導入
- まとめ

##なぜLaravel
PHPでのWebアプリケーション開発で最も使われている2つのフレームワークに、CakePHPとLaravelがあります。
cakePHPは「軽量だけどしっかり作れる使いやすいフレームワーク」であり、特にlaravelに押され気味ではありますが、いまだ日本で高いシェアを誇ります。
Laravelは「今一番伸びているとても書きやすいフレームワーク」といわれ、
世界的に一番勢いがあるフレームワークです。

フレームワークを使った開発の練習としてここら辺を触れておくのは良いのではないでしょうか？
Laravelは今後も需要の拡大が見込まれるので、一度触って見ようと思いました。

##PHP開発環境「MAMP」とは？

まずはPHPとDBを使えるようにするところからです。
PHPの開発環境であるMAMPのインストール方法を紹介します。
そもそもMAMPとは「Macintosh（Mac本体）」「Apache（Webサーバのソフト）」「MySQL」「PHP」の頭文字をとったものです。（ちなみちwindowsでもMAMPを使うことができます。）
MAMPは、これらを一括で使うことができ、PHPとMySQLの開発環境として使用できます。
MAMP同様に必要なソフトを一括でインストールできるサービスに「XAMPP」があります。大きな違いは「MySQL」の代わりにMySQL互換の「MariaDB」を使っていることです。

今回私は最低限のシンプルな構成であることかつ以前MySQLを使っていたという理由で、MAMPを使いました。

MAMPのインストール時、参考にしたサイトは以下です。
MAMPの使い方・設定を徹底解説！インストール/日本語化/xamppとの違い
https://aprico-media.com/posts/1435

##おすすめのエディタ
おすすめのテキストエディタはAtomです。
理由としてはまず、無料でかつ拡張性が高いことが挙げられます。
もともと高機能なATOMですが、「パッケージ」と呼ばれる拡張機能を追加して、さらに高機能にできます。
また周りでAtomを使っているエンジニアが多いこと。さらにAtomはGitHubの創業者が作ったオープンソースのエディタであることから将来性が高そうなので使っています。
https://atom.io/

##Laravel5.5(LTS)の導入
続いて、フレームワークの導入です。
参考にしたサイトは以下です。
MacにLaravel入れてみる
https://qiita.com/you-me/items/8794ed5344e1540e93d2

##まとめ
以上今回は、僕の環境構築の流れと参考にしたサイトを掲載しました。
僕でもできたので、一つ一つ対応していけば難しくないと思います。
Terraform Resourceのちょっと細かいテストの話 ForceNew編@Accテスト

前回、 [ConflictsWith編@Accテスト](https://qiita.com/keiichi-hikita/items/943f2d22177792ff8b4a)という話を書きました。

で今回は `ForceNew編` です。

## ForceNewとは？

Terraform では、リソースの属性に、 `ForceNew` というboolean型の属性を付与することができます。
こんな感じです。

```go
func resourceSomethingV1() *schema.Resource {
	return &schema.Resource{

		(略)

		Schema: map[string]*schema.Schema{
			"prop1": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},

			"prop2": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: false,
			},
```

これを `true` にしておくと、仮にこの属性がUpdateされた場合に、リソースが一旦削除され、その後作成されるという挙動をします。

例えば上記ですと、

- prop1 を変更するとインスタンスは削除新設される
- prop2 は変更しても既存のリソースが維持される

ということなんですが、さて、これって案外恐ろしい仕様だと思うんですよね。

うっかり tfファイルいじっちゃって、気づいたらリソース消えててもTerraform的には何も気づけ無いわけで。

ということで、Accテスト内で、リソースの変更を試験する際に、 `ForceNew発動してないよね？` というのを併せて試験しておくと安心だな・・・と思い実装をし、 `うまくいった！` ・・・と思っていました。

・・・が、その後で気づいたのですが、これ、普通に `OpenStack` のProviderとかに入ってましたね。
なんか自分で閃いた感があったんですが、全然でした（笑

とはいえ、有用なことだと思ったので書いておこうかと思います。


## 実装例

例えばこんなAccテストです。以下は、逆に `これを変更したら正しくForceNewされるよね？` というテストにしてますが、 `testAccCheckSomethingV1IDsDoNotMatch` の判定条件を変えればすぐ逆の挙動にできます。

### テスト本体部

`Something` をこのAccテストでCRUDされるリソースのtypeだとします。

```go
func TestAccSomething(t *testing.T) {
	var something_1 Something
	var something_2 Something

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		(略)
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccSomethingV1ForceNew1,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckSomethingV1Exists(
						"myprovider_something.something_1", &something_1),
				),
			},
			resource.TestStep{
				Config: testAccSomethingV1ForceNew1,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckComputeV2InstanceExists(
						"myprovider_something.something_1", &something_2),
					testAccCheckSomethingV1IDsDoNotMatch(&something_1, &something_2),
				),
			},
		},
	})
}

func testAccCheckSomethingV1IDsDoNotMatch(
	something1, something2 *Something) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		if something1.ID == something2.ID {
			return fmt.Errorf("Something was not recreated")
		}
		return nil
	}
}

```

### テスト用コンフィグ部

```go
const testAccSomethingV1ForceNew1 = `
resource "myprovider_something" "something_1" {
  region = "myregion1"
  name = "name1"
}`

const testAccSomethingV1ForceNew2 = `
resource "myprovider_something" "something_1" {
  region = "myregion2" <-- ここを変えたからForceNewされるという期待
  name = "name1"
}`
```

要は、

- リソースが再作成されるとIDが変わるはず
- コンフィグ変更後の `terraform apply` で特定のリソースのIDが一致しない＝ForceNewされた

ということです。

実際には通常変更可能な属性の変更テストにおいて、ForceNew **されてない** ことを確認するのに使ったほうがいい気がします。（リグレッション的な観点で）

ということで、 ForceNew編でした。
ExcelでUTF8のCSVを文字化けさせないで開く。（文字コードをUTF8のまま開く）

備忘録として残します。

会社の上司が`UTF8のCSVを文字化けなしで開けるよ`って教えてくれた。
マジ？と思ったけど、やってみたら、本当だった。
ちなみに**文字コードはUTF8のまま。変えません。**
SJISに変換するって人がよくいますが４バイト文字の絵文字はSJISには存在しないため、変換しても結局そこだけ化けます。

#■やり方
サクラエディタかなんかで対象のCSVファイルをひらきます。
↓こんな感じのCSVがあったとして、これを`UTF8のBOMあり`で保存します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/213462/570a8537-5782-3855-53ac-c2c9f55f7f21.png)

保存したCSVをExcelで開くと文字化けしないで表示されます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/213462/44f84047-db70-f148-6898-103207a86e54.png)

この方法を用いたとしても文字化けする場合は、Excelのフォントが表現できていない可能性がありますので、フォントを変更して確認してみてください。

以上です。

#■余談
UTF8のBOMは確かリトル、ミドル、ビッグのエンディアンとかを表しているわけじゃないはずなので、意味あるのか？って思います。
基本的にはBOMなしでUTF8は扱ったほうがいいはずです。
`ちなみにWindwos10のメモ帳で保存時にUTF8を選択できますが、こちらは、強制的にBOMありで保存されます。`
DroidKaigi 2019 2日目レポート

## 全体

### 公式サイト
https://droidkaigi.jp/2019/

### スライドまとめ

セッションで使われたスライドのまとめです(非公式)。

1日目(2月7日)
https://qiita.com/sacred-sanctuary/items/ec43f811193e7ec19399

2日目(2月8日)
https://qiita.com/sacred-sanctuary/items/f06accea3a879d006f18

### 動画

一部のセッションは動画が公開されています。

https://www.youtube.com/channel/UCgK6L-PKx2OZBuhrQ6mmQZw

## 雑感

1セッションが基本的に30分(まれに50分)と短く、密度の高い情報が受け取れます。

基本的にセッション内で質疑応答を受ける時間はありません。終了後にオフィスアワー(質問時間)が用意されているため、そこでより知識を深められます。セッションを聞いて核となる情報を受け取り、自分で実装して試すことを求められる雰囲気です。

会場ではお弁当やおやつ、飲み物を無料で受け取れるため、会場での時間を有効に過ごせます。会場(ベルサール新宿グランド)はオフィス街のため、昼食の心配が必要ないことは助かります。

展示ブースではAndroidの他にもIoTに近い分野の内容もあり、また1つ1つのブースで詳しい話を聞けたので、じっくり見て回る時間も確保しておくべきだったと感じました。

ここからは2日目(2月8日)に参加したセッションの感想です。

## セッションごとの感想

### Spek2+MockK+JaCoCoでイケてる Unit Test環境を手に入れろ！
- 11:20 - 11:50 / Room 1
- https://speakerdeck.com/subroh0508/spek2-plus-mockk-plus-jacocodeiketeru-unit-testhuan-jing-woshou-niru-rero

2017年にAndoroid開発言語でKotlinがサポートされてから1年半経ちました。プロダクションコードをKotlinで実装しても、テストコードは変わらずにJUnitやMockitoを使っている...というプロジェクト向けに、Kotlinをサポートしたライブラリを導入し、テスト環境をアップデートするための勘所を紹介するセッションです。各種ライブラリの概要や導入方法、既存のライブラリとの違いなど、始めるにあたってまず知りたいことが一通り学べました。

### SpekでUnitTestを書こう
- 14:00 - 14:30 / Room 2
- https://speakerdeck.com/moriiimo/unit-test-with-spek

テストコードのうち、Spekに焦点を合わせたセッションです。JUnitでのテストコードで起こりがちだった問題点(テストのカテゴライズが難しい、実行順が固定されない など)がSpekだとどのように解消できるかを学びます。TODO管理を題材に、実際のコードを見ながら説明されたので、自信を持って取り組めそうでした。

### ああ、素晴らしきTDD
- 17:40 - 18:10 / Room 3
- https://www.slideshare.net/SaikiIijima/tdd-130994383

ライブコーディングを交えながら、TDDのフェーズ(Red/Green/Refactor)やルールを学ぶセッションです。TDDのルールは知っていたものの、ここまで厳密な適用例は初めて見ました。「より良いアプリを提供する」という目標を達成するための道のりがわかりやすく、ただルールに沿うだけのTDDを見直す機会になると感じました。

また、Androidアプリ開発にTDDを導入する際に障害となりやすい部分のTIPSも資料に含まれるので、セッションが終わってからも実践しながら学べる内容です。

### The best practice for Android Text
- 12:50 - 13:40 / Room 3
- https://speakerdeck.com/nonanona/droidkaigi-2019-the-best-practice-for-android-text

資料は英語ですが、話の内容は日本語でした。

「文字列が遅い」という一見信じがたいフレーズから、文字列を描画する時に何が起きているのか、何が遅くなっているのかを丁寧に読み解きました。セッション冒頭では「まさか文字列が遅いなんて…」と半信半疑だったものが、セッション後には遅くなる原因とその対処方法も学べたためとても興味深かったです。

### ゼロから実装する縦書きTextViewとその周辺技術
- 15:40 - 16:30 / Room 6
- https://speakerdeck.com/cc4966/vertical-textview-from-scratch-and-related-technologies

文字列関連では、こちらの「縦書き文字列」が表示・編集できるTextViewのセッションでも詳しい実装が学べます。単純に「文字列を表示する」だけでも、多くの要素(文字コード・フォント・IME)にまたがる知識が求められることがわかり、それらの要素を段階的に理解するセッションでした。何気なく使っているTextViewを掘り下げる機会があるのもこういった機会があるからこそだと感じました。

### React NativeとExpoを用いたクロスプラットフォーム開発入門
- 10:30 - 11:00 / Room 4
- https://speakerdeck.com/mrtry/react-nativetoexpowoyong-itakurosupuratutohuomukai-fa-ru-men

AndroidとiOSでは、実行環境の違いから別々に実装する必要がありました。ここを共通化し、同じコードで2つのアプリが実行できるようにしたのがReact Nativeです。React Nativeの欠点をExpoで埋めつつ、効率よくアプリを開発するための方法を学びました。概要だけでなく、React Native+Expoが向いているアプリも知れたため、学んだことがすぐに役立てられそうでした。

### 今日から始める依存性の注入
- 14:50 - 15:20 / Room 1
- https://speakerdeck.com/kobakei/first-time-dependency-injection

依存性の注入(Dependency Injection : DI)の仕組みを踏まえつつ、Android特有の事情(ライフサイクルなど)も考慮して実装する方法を学ぶセッションです。各種ライブラリ(Dagger2やKoin)の使い方にとどまらず、なぜそれが必要なのか、DIすると何が便利なのかを含めてより深く理解できました。
TypeError: Cannot read property 'minify' of undefinedエラーの原因と対策

### 事象
`npm run build`で表題のエラーになりました

### 原因
最近（2019/2/3くらい）terserライブラリに作り込まれたバグが原因らしいです
イシューが上がってました
https://github.com/vuejs/vue-cli/issues/3407

### 解決策
暫定対応になりますが、terserのバージョンを下げると解決します

npmユーザーの場合：`npm i terser@3.14 --save`
yarnユーザーの場合：package.jsonに次のフィールドを追加してから`yarn`

```package.json
"resolutions": {
  "terser": "3.14.1"
}
```

根本的な対策も出てるかもしれないですが未確認です

以上です
PHPとSQLを使用したデータ送信フォーム

#作成の流れ
名前、年齢、番号、備考欄を送信するフォームを作成した。
1.保存されたデータ表示するindex.php
2.データを挿入するinput.php
3.挿入されたデータを確認するconfirm.php
4.完了画面complete.php

以上の四つの構成で作成した。

#作成に用いた構文や知識
##index.php
・SQLに接続するための構文

```PHP
 //接続設定
 $user ="ユーザー名";
 $pass="パスワード";
 //データベースに接続
 $dsn ="mysql:host=サーバー名;dbname=データベース名;charset=utf8";
 try {
    $dbh =new PDO($dsn, $user, $pass);
 }catch(PDOException $e){
	echo 'データベースにアクセスできません'. $e -> getMessage();
    exit();
 }
```
・SQLのテーブルを表示するための文

```PHP
 $sql= "select * from user_id order by name ASC";
 $stmt = $dbh->query($sql);
 foreach ($stmt as $row) {
     echo $rowを用いたカラム名;
     echo '<br>';
 }
```

##input.php
フォームはPOSTで送信した。
・POSTで送信する場合

```PHP
<form action="confirm.php" method="POST">
</form>
```

##comfirm.php
POSTで送られたデータはセッションで保存した。
また、XSS対策やバリテーション対策があり今回作成した中で一番難しかった。

・セッション・・・一時保存する

```PHP
session_start();
$_SESSION["変数名"]=$変数名;
```

・XSS対策・・・入力フォームにおいて悪意のあるコードを送信されることを防ぐ対策のこと

```PHP
$変数名= htmlentities($_POST[変数名], ENT_QUOTES, "UTF-8");
```

・バリテーション対策・・・空欄や全角数字などのエラーを防ぐ

```PHP
//定義（formValidationの中身にスーパーグローバル変数はつかえないため）
$postData = $_POST;
//エラー変数
$error = array();

//バリデーション
	    function formValidation($postData) {
			if (empty($postData['変数名'])) {
				$error[] = "メッセージ";
			} else if (!preg_match('それぞれ適した正規表現', $postData['変数名'])) {
				 $error[] = "メッセージ";
				}
			return $error;
		}
```
バリテーション対策の後は、エラーのある時とエラーのない時で場合分けをして、if文を用いてエラーのない時は登録ボタンがあるように、エラーのある時は登録ボタンを表示しないようにした。

##complete.php
先ほどと同様にSQLと接続し、データベースに送信されたデータを保存した。
・データを保存

```PHP
try {
    $dbh =new PDO($dsn, $user, $pass);
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    //データ追加
    $sql="INSERT INTO テーブル名 (カラム名) VALUES(登録するデータ)";
    $stmt=$dbh ->prepare($sql);
    //SQLインジェクション
    $stmt->bindValue('登録するデータ', 変数名, PDO::PARAM_INT);
    $stmt->execute();
}catch(PDOException $e){
    echo $e -> getMessage();
    exit();
}
```

#最後に
progate以外で初めて、自分で作ったプログラムなので色々調べたり、それでもわからないものは質問したりし、想像以上に苦労したができたときの達成感は気持ちいいものであった。
Macのpyenvでpythonインストール中にZipImportErrorが出たら


Xcodeのコマンドラインツールが必要なので、AppStoreでXcodeをインストールしてください。

すでにXcodeがある人は、Xcodeを最新にアップデートしましょう。

そのあと、下記を実行. 

```
$ xcode-select --install
```

完了したら、再度pyenv installしましょう

```
$ pyenv install <version>
```