OmniAICreator/Qiita-1.07M huggingface dataset:
FileMaker 一歩進んだシステム開発 -汎化-

![12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251813/309eeaed-cfab-b272-e35e-d7d2820e0499.png)
# 汎化って？
汎化という言葉をご存知でしょうか。e-Wordsによると、
「様々な異なる対象に共通する性質や、共通して適用できる法則などを見出すこと。」
とあります。
プログラミング的に捉えると、要は「同じ処理を何回も書かないようにしましょう」ってことですね。
気がついたら同じようなスクリプトを大量に作っていた、という経験がある方もいるのではないでしょうか。

## 例(Before)
例えば以下のような２つのスクリプトを作ったとします。

スクリプト①　名前のチェック

```
if [「名前」フィールドが空]
　ダイアログ表示　[名前が空だぞ]
　スクリプト終了
end if
```

スクリプト②　住所のチェック

```
if [「住所」フィールドが空]
　ダイアログ表示　[住所が入力されてないんだけど]
　スクリプト終了
end if
```

両方とも、フィールドが空ならダイアログメッセージを表示するスクリプトです。
例えば、ここで利用者から
「ダイアログメッセージがぶっきらぼうなので、丁寧語にしてください」
という要望があった場合、２つとも修正が発生しますね。２つならまだましですが、
これが１００箇所あるような状況だと、ため息が止まりませんね。
メンテナンスも大変だし、修正漏れのリスクもあります。なので、以下のように修正します。

## 例(After)
スクリプト名：入力チェック

```
if [ <スクリプトの引数>が空]
　　ダイアログ表示 [<スクリプトの引数>が空でございます。]
　　スクリプト終了
ene if
```

これなら呼び出し元から引数を渡せば、どこからでも１つのスクリプトで事足ります。
これが汎化です。

# 実用的な汎化例

最後にもう１つだけ、実用的な具体例を挙げておきます。
検索に使える汎用スクリプトを作成します。

## スクリプト(汎用検索)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251813/af867b8a-f028-a639-bbaa-0ab712c979ca.png)

### 解説
①FileMaker標準のエラーメッセージは邪魔なので、ＯＦＦにします。
②引数を２つ受け取って変数にセットしています。１行目がフィールド名、２行目が検索条件です。
　→GetValue(値一覧; 値番号)は、改行で区切られた文字から行番号を指定して値を取得する関数です。
③検索モードに切り替えます。
④念のためエラーが発生していないか確認し、エラーなら処理を終了します。
　→万が一切り替えに失敗した場合、次のフィールド設定で予期せぬデータ更新が行わるのを防ぐためです。
⑤フィールドを名前で設定します。ここで先ほど変数に入れておいた値を使います。
　→ここが汎化の要です！フィールド名を名前(文字列)で指定できるので、呼び出し元から好きな
　　フィールドを設定できます。
⑥検索を実行。

## 呼び出し側
ボタン等からスクリプトを呼び出します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251813/bf99177f-1ab1-404a-6d70-67b315b52df7.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251813/5cdbe8cd-b81f-f106-fd2d-d72fe19369df.png)
### 解説
引数を２つ渡したいので、改行(¶)で繋いでいます。
GetFieldNameというのはFileMakerの標準関数で、指定したフィールドの名前を文字列として返してくれます。

このスクリプトを使えば、検索ボタンごとにスクリプトを作る必要がなくなります。
（例：「性別」が"女性"のみ、「部署」が"総務"以外　などなど）

# 追記
Ver17からスクリプトを名前で指定して実行できるようになったようですね。
これも汎化に使えそうです。そろそろ自分も17使ってみようかな...。

# ばいちゃ
皆さんがこれまでに作成したアプリケーションも、汎化できるところが無いか
見直してみてはいかがでしょうか。また、これから作るという方も汎化を意識して、
１歩進んだシステム開発に挑戦してみてください。

:cat:こちらもよろしければご覧ください。:cat:
　[FileMakerで登録／キャンセル制御したい](https://qiita.com/nakatomodesu/items/aef768741a4b4108790e)
　[FileMakerで分離モデルしてみたい](https://qiita.com/nakatomodesu/items/0bbb9f4846c1d104e6ad)
　[FileMakerでアプリ作っていくよ【作って学ぼう】](https://qiita.com/nakatomodesu/items/3e4e343fb785d4fb3841)
　[FileMakerでレスポンスが悪いときに確認すること](https://qiita.com/nakatomodesu/items/19d061804481cf109ac7)
  [FileMaker 一歩進んだシステム開発 - 怖くないよカスタムメニュー -](https://qiita.com/nakatomodesu/items/04cba3d760503fbbc674)
RealSense+Pythonの1コマンド環境構築

# 追記
- **「USB3.0以上のポート」** に **「USB3.0以上対応のケーブル」** で刺さないと動かない/不安定になるので注意！

# 環境
- python3
- RealSenseD435

# 皆さん迷走してません?

![Screenshot from 2019-04-23 16-19-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188173/b27ca99d-ced8-1c15-28b0-6caeb15a5c46.png)

- 長いしわかりにくい
- とどのつまり、`cmake` & `make` とか `add-apt-repository` とか要らない気がします

# ↓に書いてありました
https://github.com/IntelRealSense/librealsense/tree/master/wrappers/python

「python wrapperならpipで入れれるよ」

```bash
pip install pyrealsense2
```
だけ

# 動作チェック！

- PCにD435挿して、じっこう！

- 以下(公式)から拝借
 - https://github.com/IntelRealSense/librealsense/blob/master/wrappers/python/examples/opencv_viewer_example.py

```python

## License: Apache 2.0. See LICENSE file in root directory.
## Copyright(c) 2015-2017 Intel Corporation. All Rights Reserved.

###############################################
##      Open CV and Numpy integration        ##
###############################################

import pyrealsense2 as rs
import numpy as np
import cv2

# Configure depth and color streams
pipeline = rs.pipeline()
config = rs.config()
config.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30)
config.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30)

# Start streaming
pipeline.start(config)

try:
    while True:

        # Wait for a coherent pair of frames: depth and color
        frames = pipeline.wait_for_frames()
        depth_frame = frames.get_depth_frame()
        color_frame = frames.get_color_frame()
        if not depth_frame or not color_frame:
            continue

        # Convert images to numpy arrays
        depth_image = np.asanyarray(depth_frame.get_data())
        color_image = np.asanyarray(color_frame.get_data())

        # Apply colormap on depth image (image must be converted to 8-bit per pixel first)
        depth_colormap = cv2.applyColorMap(cv2.convertScaleAbs(depth_image, alpha=0.03), cv2.COLORMAP_JET)

        # Stack both images horizontally
        images = np.hstack((color_image, depth_colormap))

        # Show images
        cv2.namedWindow('RealSense', cv2.WINDOW_AUTOSIZE)
        cv2.imshow('RealSense', images)
        cv2.waitKey(1)

finally:

    # Stop streaming
    pipeline.stop()
```

# 結果

![Screenshot from 2019-04-23 16-23-14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188173/f8df6583-c9a1-95a0-953b-078c88c2a398.png)

# 以上！
平成３元年問題

今さらですが、元号対応関連で残念な事故があったので考察してみました。

> [世田谷区の通知書類に「平成3元年」と誤表示、改元前に早くもトラブル](https://tech.nikkeibp.co.jp/atcl/nxt/news/18/04724/)

# 事象

**帳票**の日付が「平成３１年」ではなく「平成３元年」と印字される。

# 原因

明日は我が身なので詳しい原因が知りたいところですが、それらしい情報が見当たりませんでした。

## あくまでも推測

SVFの定義体で和暦変換していて、元年の変換条件が誤っている？

## なぜそう思ったか

* ギョームシステムの帳票といえばSVF！という安直な発想
* SVFの定義体と元号定義の変更だけならアプリケーションサーバ等の再起動が要らない
* SVF販売元のFAQに気になる記載があった

> [和暦変換関数は、和暦が次の元号になっても使用できますか。](https://customer.wingarc.com/support/SS_FaqDetailPage?lang=ja&key=kA05F000000kAjYSAU)
> 和暦変換関数（SEI2WA 等）を用いて和暦を出力する場合、「01年」 は 「元年」 に変換されません。

## 推測が正しいとするとどうなるのか

### 和暦変換する

３種類ありますが、お役所で「01年」という表記はしないと思うので、ゼロサプレスのあるSEI2WA1Zの一択になると思います。

|入力値→|2019/04/30      |2019/05/01      |
|:-------|:---------------|:---------------|
|SEI2WA  |平成310430      |令和010501      |
|SEI2WA1 |平成31年04月30日|令和01年05月01日|
|SEI2WA1Z|平成31年4月30日 |令和1年5月1日   |

### 全角変換する

お役所と新聞は全角が好き。理由は知らない。
TOJISで一発。

|入力値→|平成31年4月30日      |令和1年5月1日      |
|:-------|:--------------------|:------------------|
|TOJIS   |平成３１年４月３０日 |令和１年５月１日   |

### １年って何だよ元年だろ

REPLACEで「１年」を「元年」に置換しよう。

|入力値→|平成３１年４月３０日 |令和１年５月１日   |
|:-------|:--------------------|:------------------|
|REPLACE |平成３元年４月３０日 |令和元年５月１日   |

**ギャーーーーーー！！！**

# 対処方法

~~「令和１年」を「令和元年」に置換すれば解決だけど、それだと20年後くらいにまた困るんじゃない？~~
和暦対応をやめてすべて西暦にする。

# おまけ

令和元年５月元日
Vue.js のサンプル　(button クリック、JSON　読み込み)

こちらのプログラムを改造して JSON を読み込むようにしました。
[Vue.js のサンプル　(button クリック、text 表示)](https://qiita.com/ekzemplaro/items/398163a17bec675fdaf4)

```html:grimm.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta http-equiv="CONTENT-TYPE" content="text/html; charset=utf-8" />
<script src="https://unpkg.com/vue@2.6.14"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<title>グリム童話</title>
</head>
<body>
<h2>グリム童話</h2><p />
<button id='aa' onclick="doAction(this.id)">
赤ずきん
</button>
<button id='bb' onclick="doAction(this.id)">
いばらひめ
</button>
<button id='cc' onclick="doAction(this.id)">
ラプンツェル
</button>
<button id='dd' onclick="doAction(this.id)">
七わのからす
</button>

<div id="app0">
<blockquote>
{{ title }}
</blockquote>
<p />
{{ text }}
</div>

<script src="grimm.js"></script>

<p />
Apr/23/2019 AM 08:25<p />
</body>
</html>
```

```js:grimm.js
// ---------------------------------------------------------------
//	grimm.js
//
//						Apr/23/2019
//
// ---------------------------------------------------------------
var data_aa = {title: 'こんにちは。',
		text: 'テスト'}
new Vue (
{
	el: '#app0',
	data: data_aa 
})

// ---------------------------------------------------------------
function doAction(id)
{
	const file_json = "data/" + id + ".json"

	axios.get(file_json).then((res) => {
//		console.log("*** doAction *** check ***")
		data_aa.title = res.data.title
		data_aa.text = res.data.text
		})
}

// ---------------------------------------------------------------
```

JSON ファイル

```json:data/aa.json
{
  "title": "赤ずきん",
  "text": "　むかし、あるところに、ちいさな、かわいい女の子がいました。だれでも、ひと目見ただけで、この子がすきになりましたが、なんといっても一ばんかわいがったのは、この子のおばあさんでした。"
}
```

```json:data/bb.json
{
  "title": "いばらひめ",
  "text": "　昔むかし、王さまとおきさきががおりました。ふたりは毎日、「子どもがほしい！子どもがいればな！」と、言い暮らしていましたが、いつまでたっても、ひとりもさずかりませんでした。"
}
```

```json:data/cc.json
{
  "title": "ラブンツェル",
  "text": "　むかし、あるところに、亭主とおかみさんがおりました。長いあいだ、子どもがほしいと願っていましたが、さずかりませんでした。"
}
```

```json:data/dd.json
{
  "title": "七のからす",
  "text": "　むかし、ある男のひとに、むすこばかり、七人ありました。むすめをほしい、ほしいとねがってきたのですが、ひとりも、さずからなかったのです。"
}
```

フォルダーの構造

```text
├── data
│   ├── aa.json
│   ├── bb.json
│   ├── cc.json
│   └── dd.json
├── grimm.html
└── grimm.js
```

次のバージョンで確認しました。

```text
Vue.js v2.6.14
axios v0.27.2
```
ユーザーインタビューをする際の人数に関して(定性調査)

#インタビューする時に組織的に陥りやすいこと
顧客視点で「開発」「デザイン」「企画」をする際に、だいたいぶつかる問題があります。
**「やるのはいいが、果たして何人に聞けば充分なのか」**
この問題は、上長の承認(予算的な) がある限り受託でも事業会社でも発生すると思っています。
この問題を解決し、最適な人数を割り出せる文献があるのでご紹介します。
(自分も以前の会社でクライアントを説得する際に利用しました) 

#何を参考に人数を算出したのか？
私が参考にした文献は、ヤコブ・ニールセン博士のユーザーテストを参考にしました。
下記、博士が提唱している計算式です。

> **N(1-(1-L)n)**

> ここでNはデザイン上のユーザビリティ問題の数であり、Lは1人のユーザーでテストして発見できるユーザビリティ問題が全体に占める割合を示している。数多くのプロジェクトを調査した結果、典型的なLの値は平均して31％であることがわかった。L=31％として曲線を描いてみると、次のようになる。
(U-site参照)

![スクリーンショット 2019-04-22 11.23.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403827/cc784bcb-17cd-5066-5df8-06450105751e.png)

#結論
ヤコブ・ニールセン博士のユーザービリティー工学の観点では、**「5人にインタビューすればユーザービリティ問題の85%が発見できる」**
(下記、個人的な経験則) 
ただし、セグメントが別れている場合は各セグメントに3~5人は行わないと85%の問題発見は得られなと思います。


#参考になるサイト
下記、２つのサイトは参考になるものの、明記されている数字がバラバラなので注意が必要です。
個人的にはU-siteで掲載されているヤコブ・ニールセン博士の数字とグラフを参照しました。

▼U-site
https://u-site.jp/alertbox/20000319

▼Medium
https://medium.com/design-lab/%E7%B5%90%E5%B1%80-%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%93%E3%83%A5%E3%83%BC%E3%81%A3%E3%81%A6%E6%9C%80%E4%BD%8E%E4%BD%95%E4%BA%BA%E3%81%AB%E8%81%9E%E3%81%91%E3%81%B0%E3%81%84%E3%81%84-1ef502fdea88
RailsDBをMySQLに変更してHerokuでデプロイまでする手順


RailsのデフォルトDBはSQLiteですが、MySQLに変更してみようかと思います👨‍💻

# development環境

まずは開発環境でMySQLを使用する手順です。

## DB設定

```ruby:Gemfile
gem 'mysql2'
```

```ruby:database.yml
#編集
development:
  adapter: mysql2
  encoding: utf8
  database: tweet_app
  pool: 5
  username: root
  password:
  host: localhost
```


```
$ bundle install
```

## 新規DB作成

```
$ bundle exec rake db:create
```

```
$ bundle exec rails g model User name:string email:string password:string
```

```
$ bundle exec rake db:migrate
```

# production環境

実際にHerokuでデプロイした後もMySQLで動くよう実装する手順です。


##①Herokuでアプリケーション作成
[こちらの記事](https://qiita.com/kazukimatsumoto/items/a0daa7281a3948701c39)を参考にしつつ、`git push heroku master`をする手前まで進めます。

**後述するアドオンの追加のところで、Herokuにクレジットカード情報を登録しておく必要がある（お金はかかりません）ので、[登録](https://dashboard.heroku.com/)しておいてください。**

##②cleardbアドオンを追加する

```
$ heroku addons:add cleardb
```

##③heroku-postgresqlアドオンを削除する

```
$ heroku addons:destroy heroku-postgresql -a <アプリ名>
```

##④DATABASE_URLを編集する

```
$ heroku config | grep CLEARDB_DATABASE_URL
CLEARDB_DATABASE_URL:     mysql://aaaaa:bbbbb@ccccc.cleardb.net/heroku_ddd?reconnect=true
```

上記のURLをMySQL２に切り替えます。コピーペーストしつつ`mysql2`に書き換えてください

```
$ heroku config:set DATABASE_URL='mysql2://aaaaa:bbbbb@ccccc.cleardb.net/heroku_ddd?reconnect=true'
```

##⑤環境変数を設定

Herokuで使用する環境変数を設定していきます。

```
$ heroku config | grep CLEARDB_DATABASE_URL
mysql://aaaaa:bbbbb@ccccc.cleardb.net/heroku_ddd?reconnect=true
```
- aaaaa = username
- bbbbb = password
- ccccc = hostname
- heroku_ddd?reconnect = db_name

```
$ heroku config:add DB_NAME="[db_name]"
$ heroku config:add DB_USERNAME="[username]"
$ heroku config:add DB_PASSWORD="[password]"
$ heroku config:add DB_HOSTNAME="[hostname]"
$ heroku config:add DB_PORT="3306"
```

```ruby:database.yml
production:
  <<: *default
  database: <%= ENV['DB_NAME'] %> 
  username: <%= ENV['DB_USERNAME'] %>
  password: <%= ENV['DB_PASSWORD'] %>

```
※ご自身の出力結果と照らし合わせながら設定してください。

##⑥git push & migrate実行

```
$ git push heroku master
$ heroku run rake db:migrate
$ heroku open
```

独学でやっておりますので、間違っている or 動かないなどあれば、ご指摘いただけると幸いです🙇‍♂️

# 参考

- [mysqlを使ったRailsアプリをHerokuにデプロイする流れ](https://qiita.com/shou1012/items/bf55a185920e717f4011)
- [RailsのDBを(初めから| |後から)MySQLに変更する](https://qiita.com/reeenapi/items/9fc38c4f2f8186c78288)
- [HerokuでMySQLを使うときはDATABASE_URLを書き換える](https://qiita.com/SomeyaNaoki/items/1167fa816fa9647e4464)
対角線の長さを求める関数

対角線の長さを求めることがあったのでメモ

# コード
```javascript
(a,b)=>Math.abs(a===b?Math.SQRT2*a:Math.sqrt(a**2+b**2))
```

# 追記
htsign様から便利な関数を教えていただきました。
> Math.hypot 関数で求められます。

> Math.hypot(3, 4); // ==> 5

---
> MDN
> Math​.hypot()

> 概要
> 引数の二乗和の平方根を返します。

> https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Math/hypot

---

こんな関数があったとは。。

一応処理時間も測って見ました。

```javascript
console.time("original");
((a,b)=>Math.abs(a===b?Math.SQRT2*a:Math.sqrt(a**2+b**2)))(3, 4);
console.timeEnd("original");
console.time("Math.hypot");
Math.hypot(3, 4);
console.timeEnd("Math.hypot");
```
| Name | Time |
|:-----------------|------------------:|
original | 0.010009765625ms
Math.hypot | 0.005126953125ms

は、早い。。。

またひとつ勉強になりました。
simple_formのHTML5バリデーションでハマったことメモ

いままでParsley.jsのバリデーションにお世話になってました。
これといって大掛かりなバリデーションを仕掛けてた訳じゃなく、至って普通の制限かけてる程度だし、プラグインに依存するのは何かと弊害も発生しかねるんで、いっそのことHTML5バリデーションにしてみることに。

以前、スタティックな個人的作業環境で試したときは普通に動作したんですが、いざプロダクト内に実装しようと組み込んでみたら

うごかねーーーーー！！

で、コードをみると

```html
<form class="simple_form hoge" id="hoge" novalidate="novalidate" action="hoge" accept-charset="UTF-8" method="post"><input type="hidden" name="_method" value="patch"><input type="hidden" name="authenticity_token" value="xXK9MpDrqzLawGeDvoDhBc06UA3U+gUznIWCctfPi388lsaNIhfoQI5v8UHSMeoa0/4W4hNw/QILP47Y3EUyrg==">
```
novalidate="novalidate"
なんだと！！！
これじゃ動くわけなかろうｗｗｗ
ということで

```haml
= simple_form_for @hoge, url: hoge_path, html: {novalidate: false} do |f|
```
と書いてやると前出の属性は消えてバリデーションが動きましたとさ！ｗｗ
学生のためのJDK8インストーラーのダウンロード

[2020/10/17更新]
Javaを買収したオラクルが2019/4/16に規約を変更し、インストール手順が変わった。
JDK8のインストールのためには、Oracleのアカウントを作成する必要がある。

## アカウントの作成
1. <https://login.oracle.com/mysso/signon.jsp>にアクセス、プロファイルの作成をクリック
<img width="1280" alt="スクリーンショット 2019-04-23 15.31.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/355869/97b610f9-93d1-9a30-3c89-daec62d65527.png">

2. メールアドレスとパスワード、名前に加えて、以下の情報で登録する。
<img width="974" alt="スクリーンショット 2019-04-23 15.34.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/355869/29aae759-0456-4115-31a7-cefe274a27be.png">

3. 送られてくるメールのリンクをクリックし、アカウントを有効にする



## JDK8インストーラーのダウンロード・インストール
1. <https://www.oracle.com/jp/java/technologies/javase/javase-jdk8-downloads.html>にアクセス
~~1.<https://www.oracle.com/technetwork/java/javase/downloads/index.html>にアクセス~~
~~2. **Java SE 8u211 / Java SE 8u212**の**Oracle JDK**をクリック~~
3. ~~**Java SE Development Kit 8u211** のうち~~自分に合うものをクリック（**Accept License Agreement**を忘れずに)
4. Oracleプロファイルへのサインインが求められるので、先ほどのユーザー名(登録したメールアドレス)とパスワードでサインインし、ダウンロードする
OCamlMakefile をホームディレクトリに落としてパスを通して使う

OCamlMakefile の使い方に関する[日本語記事](https://qiita.com/progrunner17/items/a51bc4ff698c62aebff2)を読んでいたが、OCamlMakefileをわざわざターゲットのディレクトリにコピーして使うのは不便そうである。[公式ドキュメント](http://mmottl.github.io/ocaml-makefile/)を読むと

> 2\. Put OCamlMakefile somewhere else in your system. In this case you will have to set the variable OCAMLMAKEFILE in your project-specific Makefile. This is the way in which the examples are written. Now you only need one version of OCamlMakefile to manage all of your projects! See the examples for details.

とあるから、こちらを使ったやり方を~~後のISerのために~~後学のためにメモしておく。

まず

```bash
curl https://raw.githubusercontent.com/mmottl/ocaml-makefile/master/OCamlMakefile >> ~/OCamlMakefile
```

と入力すると、[リポジトリ](https://github.com/mmottl/ocaml-makefile)が死んでいなければ正しくホームディレクトリ直下に OCamlMakefile が配置されるはずだ。

あとは、Makefile に

```
OCAMLMAKEFILE = ~/OCamlMakefile
SOURCES = hello.ml
RESULT  = hello

-include $(OCAMLMAKEFILE)
```

こんな感じで、OCamlMakefile が置かれているパス `~/OCamlMakefile` を値に持つ変数 `OCAMLMAKEFILE` を定義し、この変数を include すればよい。
abemaビデオで、再生対象の動画を『ブラウザ全画面』するブックマークレットを、ものすごく雑に作る。

#### やりたいこと
- [abemaビデオ](https://abema.tv/video/)で再生している動画を、ツールバーから『ブラウザ全画面化』ができる。
- これを画面上の要素のクリックをせずに、同様の操作をしたい。
- 頑張らない。

#### 出来たもの

`javascript:document.querySelector("#main>div>main>div>.c-vod-PlayerContainer-container>div>.com-vod-VODScreen-video-control>div>div:nth-child(6)").click();`

Qiitaの仕様上、ブックマークレットのリンクの作成は出来ないようです。
もし登録や動作確認したい人は、↑をコピーして、ブックマークのURLに貼り付けてください。

#### やったこと
記憶ベース。使用環境/ブラウザはwindows10 home/chrome。デバッグや調査は省略。

1. abemaビデオの任意の動画を開く。
2. 『ブラウザ全画面』の要素を右クリックして検証。
3. 要素を選択した状態でデベロッパーツールが開かれる。
4. 内側のアイコンの要素が選択されていたら、最上位の『ブラウザ全画面』の親要素を探す。目的の要素であれば、右クリック→Copy→Copy JS Pathをクリック。
5. 以下のjavascriptが取得できた。
`document.querySelector('#main > div > main > div > div.c-video-EpisodeContainer-thumbnail.c-vod-PlayerContainer-container.c-vod-PlayerContainer-inlined > div > div.com-vod-VideoControlBar.com-vod-VODScreen-video-control.fade-in > div.abm_6043bbc3_a.abm_6043bbc3_q > div:nth-child(6)')`

6. ビデオ単位で変わりそうな要素を消す。また、長すぎるので必要最低限の要素のみにする。
`document.querySelector("#main > div > main > div > .c-vod-PlayerContainer-container > div > .com-vod-VODScreen-video-control > div > div:nth-child(6)")`

7. デベロッパーツールのconsoleタブで、動作確認。取得成功。
8. .clickをつけてconsoleタブで動作確認。動作成功。
`document.querySelector("#main > div > main > div > .c-vod-PlayerContainer-container > div > .com-vod-VODScreen-video-control > div > div:nth-child(6)").click()`

9. `javascript:;` でブックマークレット化＋空白だけ削除してブックマークに登録。冒頭の『出来たもの』の完成。

#### 備考

- 本当は『1.3倍速再生』もブックマークレット化したかったけどid中に `.` が入ってるためか、querySelectorが上手く動作せず、 getElementByIdでも`.checked=true`しても動作しなかったので諦めた。
- よければ、[abemaビデオで、無料のみを表示するブックマークレットを、ものすごく雑に作る。](https://qiita.com/iHok/items/75a3c2b9e6a73dad1e23)も併せてどうぞ。
ビルド時DLLを別フォルダに移動する

作業１（追加）：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329335/6afc5c1f-fe8e-f885-da37-564716829a98.png)

作業2（追加）：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329335/c14bff6a-d456-f61d-d8c3-2190adfadaf5.png)
Ubuntu初期設定

Ubuntu 18.04.1 LTS

## Ubuntu

### 何はなくともetckeeper

```console
$ sudo apt-get install etckeeper
```

### 最新版にアップデート

```console
$ sudo apt-get update
$ sudo apt-get upgrade
```

### ufw有効

```console
$ sudo ufw enable

# 自分のアクセスしているIPアドレスからの通信は全て通す
$ sudo ufw allow from 180.43.xxx.xxx
```

### tcp wrapper有効

```console
$ sudo vi /etc/hosts.allow
```

```vim:/etc/hosts.allow
sshd: 180.43.xxx.xxx
```

```console
$ sudo vi /etc/hosts.deny
```

```vim:/etc/hosts.deny
sshd: ALL
```

### タイムゾーン

```console
sudo timedatectl set-timezone Asia/Tokyo
```

### NTP

[systemd-timesyncd - ArchWiki](https://wiki.archlinux.jp/index.php/Systemd-timesyncd)

```console
$ vi /etc/systemd/timesyncd.conf
```

```vim:/etc/systemd/timesyncd.conf
[Time]
NTP=169.254.169.123
```

```console
$ sudo systemctl restart systemd-timesyncd.service
```

```console
$ systemctl status systemd-timesyncd.service
● systemd-timesyncd.service - Network Time Synchronization
   Loaded: loaded (/lib/systemd/system/systemd-timesyncd.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2019-04-24 00:22:46 JST; 2s ago
     Docs: man:systemd-timesyncd.service(8)
 Main PID: 4289 (systemd-timesyn)
   Status: "Synchronized to time server 169.254.169.123:123 (169.254.169.123)."
    Tasks: 2 (limit: 1152)
   CGroup: /system.slice/systemd-timesyncd.service
           mq4289 /lib/systemd/systemd-timesyncd

Apr 24 00:22:46 ip-172-26-6-45 systemd[1]: Starting Network Time Synchronization...
Apr 24 00:22:46 ip-172-26-6-45 systemd[1]: Started Network Time Synchronization.
Apr 24 00:22:46 ip-172-26-6-45 systemd-timesyncd[4289]: Synchronized to time server 169.254.169.123:123 (169.254.169.123).
```


### sysctl

```console
$ vi /etc/sysctl.conf
```

```vim:/etc/sysctl.conf
net.core.somaxconn = 2048
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.ip_local_port_range = 2048 65535
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 1048576 16777216
net.ipv4.tcp_wmem = 4096 1048576 16777216
```

```console
$ sysctl -p
```

## nginx

### インストール

https://nginx.org/en/linux_packages.html#Ubuntu

```console
$ sudo apt install curl gnupg2 ca-certificates lsb-release
$ echo "deb http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" | sudo tee /etc/apt/sources.list.d/nginx.list
$ curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo apt-key add -
$ sudo apt update
$ sudo apt install nginx
```

### 起動

```console
$ sudo systemctl start nginx.service
```

## php-fpm

### インストール

```console
$ sudo apt-get install php-fpm
```

### composer

```console
$ sudo apt-get install composer
$ sudo rm -fr $HOME/.composer
```

以下は必要に応じて

```console
# packagist.jp使う
$ composer config -g repos.packagist composer https://packagist.jp

# prestissimo入れる
$ sudo apt-get install php-curl php-zip
$ composer global require hirak/prestissimo
```



## mariadb

### インストール

```console
$ sudo apt install mariadb-server
```

### 起動

```console
$ sudo systemctl start mysql.service
```
POStudyナイト#01 ～プロダクト責任者への道 2019～ 参加レポート

２０１９年４月２２日（月）に開催された<a href="https://postudy.doorkeeper.jp/events/89726">「POStudy ナイト」第１回</a> に参加しました。
会場は５０人以上の参加者で、大盛り上がりでした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65426/7121cb17-f05c-c032-25fd-acdc58837566.png)

## 会場の様子
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65426/2325f7bd-4b64-7949-aa37-779dbe99a402.png)

## 『アジャイルソフトウェア開発宣言』に対する誤解と真意
<img width="960" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65426/22491ae8-03f2-0dcb-1127-bf9e675418ae.png">

ここでは<b>「 <font color="Blue">左記</font> のことがらに価値があることを認め」</b>と明記されていますが、日本にアジャイルが普及した当初、この部分が<b>抜けた</b>状態で広まった為、アジャイル開発に対する「誤解」が生じてしまったようです。


## グループワークショップ『アジャイル宣言の背後にある原則』

「アジャイル宣言の背後にある原則」を、
日本の企業・組織文化を考慮して言い換えられた「１２の原則」（IPA 作成）について、
グループ別にディスカッションを行い、
<b>「プロダクト責任者にに必要なマインドセットとは」</b>というテーマについて、
グループ毎に発表しました。


**アジャイル宣言の背後にある原則 〜一覧〜**
<img width="821" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65426/7b94b681-b08c-4775-fc24-5dd8e4c78fb2.png">

私は「原則04：全員で共通の目標に向かう」に参加しました。

### 原則04：全員で共通の目標に向かう
ビジョンを明確にすること、またワクワクするようなビジョンが必要。
部分最適化に目が行きがちだが、全体最適化をメンバー全員が意識するように。
最後までやり抜く精神力も必要。

<img width="994" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65426/9f5e94ff-1293-dafc-ba3a-8077ea0bbf45.png">

以下、その他のチームの発表です。

### 原則01：顧客の満足を求め続ける
経営者、現場のビジョンをまとめ上げることが大事。

### 原則02：要求の本質を見抜き、変更を前向きに
受入時点の変更、UIについての変更要求が多い。またSORとSOEでも変わってくる。
ここをどう考えるかが大事。

### 原則03：成果物を2-3週間で、リリースし続ける
２週間でリリースできるようにするため、プロダクトバックログの粒度が大事になる。
またステークホルダーへ随時共有をしないと、直前で戻りが発生してしまう。

### 原則04：全員で共通の目標に向かう（２チーム目）
心理的安全性、チームビルド、共通言語が大事。
何がしたいのかを、プロダクト責任者が自身とチームに問いかけること。

### 原則05：人の意欲は信頼から
なぜそれをするのかを、メンバーへ説明し、期待値を示す。
受託開発との関係についても、相互理解が必要。

### 原則06：顧客も開発チームも直接対話で
ユーザー、プロダクト責任者、開発チームで同じ空間を実現できない場合、
プロダクトバックログの透明性の確保を始め、
間の立場となるプロダクト責任者が中心となって動く必要がある。

### 原則07：進捗も品質も現物で
ドキュメントは必要な場合も、不要な場合もあるが、
チームとしてどうするかについては、プロダクト責任者の決断力が必要。

### 原則08：一定のペースでプロジェクトにリズムを

### 原則09：よい技術、よい設計、よい品質の追求
プログラムソースの可読性が高くないと、
ユーザーからのフィードバックへの対応に時間がかかるようになってくる。
逆に内部品質を高めれば、外部品質が良くなり、フィードバックループも回っていく。

### 原則10：ムダ＝価値を生まない、を探してやめる
「ムダ」の定義について共通認識を持つことは大事。
例えば高い学びを得られた失敗など、
チーム内では価値があると思えることでも、経営層から見たらムダに見えることはある。
このような場合は、経営陣に分かるように説明する必要がある。
また、失敗には再現性があるが、失敗からの学びを、プロダクト責任者間で共有するように努めているか。
失敗を活かす為のプロセスが大事。

### 原則11：よいモノはよいチームから
良いチームは全体最適性が高い。目的ニーズを揃える。伝え続ける。工夫も必要。

### 原則12：自分たちのやり方を毎週、調整する
どのようなチームにしたいのかをメンバーへ示して、向き・不向きを理解する。
チーム内のパーソナリティの理解も必要。

## 参考
<a href="https://www.ipa.go.jp/files/000065601.pdf">アジャイルソフトウェア開発宣言の読みとき方</a>
IPAのサイトで公開されています。

<a href="https://postudy.doorkeeper.jp/events/89726">POStudy ナイト ～プロダクト責任者への道 2019～</a>
毎月１回、全１１回で開催予定とのことです。
Vue.js のサンプル　(button クリック、text 表示)


```html:grimm.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta http-equiv="CONTENT-TYPE" content="text/html; charset=utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<title>グリム童話</title>
</head>
<body>
<h2>グリム童話</h2><p />
<button id='aa' onclick="doAction(this.id)">
赤ずきん
</button>
<button id='bb' onclick="doAction(this.id)">
いばらひめ
</button>
<button id='cc' onclick="doAction(this.id)">
ラプンツェル
</button>
<button id='dd' onclick="doAction(this.id)">
七わのからす
</button>

<div id="app0">
<blockquote>
{{ title }}
</blockquote>
<p />
{{ text }}
</div>

<script src="grimm.js"></script>

<p />
Apr/23/2019 AM 08:25<p />
</body>
</html>
```

```js:grimm.js
// ---------------------------------------------------------------
//	grimm.js
//
//						Apr/23/2019
//
// ---------------------------------------------------------------
var data_aa = {title: 'こんにちは。',
		text: 'テスト'}
new Vue (
{
	el: '#app0',
	data: data_aa 
})

// ---------------------------------------------------------------
function doAction(id){
switch(id)
	{
	case 'aa':
		title = '赤ずきん'
		text = '　むかし、あるところに、ちいさな、かわいい女の子がいました。だれでも、ひと目見ただけで、この子がすきになりましたが、なんといっても一ばんかわいがったのは、この子のおばあさんでした。'
		break

	case 'bb':
		title = 'いばらひめ'
		text = '　昔むかし、王さまとおきさきががおりました。ふたりは毎日、「子どもがほしい！子どもがいればな！」と、言い暮らしていましたが、いつまでたっても、ひとりもさずかりませんでした。'
		break

	case 'cc':
		title = 'ラブンツェル'
		text = '　むかし、あるところに、亭主とおかみさんがおりました。長いあいだ、子どもがほしいと願っていましたが、さずかりませんでした。'
		break

	case 'dd':
		title = '七のからす'
		text = '　むかし、ある男のひとに、むすこばかり、七人ありました。むすめをほしい、ほしいとねがってきたのですが、ひとりも、さずからなかったのです。'
		break

	}

	data_aa.title = title
	data_aa.text = text
}

// ---------------------------------------------------------------
```

実行結果
![grimm01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/e6f7da69-f62e-ed85-5435-1f6854c16edc.png)

![grimm02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/575fad9f-5682-2246-f4f7-3e4ad7809347.png)

![grimm03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/87f45966-4746-78fb-6ee8-2ed1c0e28bf1.png)

次のバージョンで確認しました。

```text
Vue.js v2.6.14
```
Cognos Analytics レポートでのデータの丸め方

#データの丸め方
割り算などの結果、少数点が非常に多い数値を表示する時の、数値の丸め方を学びます。
![014.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/0433dd91-659c-2b90-96b3-1ac846e2e31c.jpeg)


#手順
レポートを作成。
クエリーに「製品ライン」「年」を置き、クエリー計算として、「達成率」を画像のように[収益]と[計画収入]の割り算で作成する。
![001.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/7b5bf4f7-8c8d-ce2b-384e-8d3fddf49cba.jpeg)

「達成率」のプロパティで、詳細集計と概要集計を「算出」に指定。
![007.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/5611b42b-1f8b-3232-16c6-e6f7e962bf57.jpeg)

リストにデータアイテムを配置し、レポートを実行すると以下の表示となり、こんなに少数点を見たい事は通常ないため、少数点2桁に統一したい。
![008.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/079635ec-b118-c505-43b1-953cacd11c78.jpeg)

「ページ1」に戻り、達成率のリストの本体のプロパティで「データ形式」を選択し、表示形式を「数値」、少数点以下の桁数を「2」に変更しOK。
![003.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/83b7b0d5-c45b-e1e3-5d52-557eb5ffc80f.jpeg)

レポートを実行してみると、この通り「達成率」は少数点2桁で表現されているが、赤枠のプルダウンから「CSVを実行」を選択し、CSVにリストデータをダウンロードしてみる。
![009.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/03562c7b-4f7b-7cda-7b08-b7d12f9bcabc.jpeg)

ダウンロード結果は、以下となる。
先ほどの「データ形式」での指定では、あくまでHTML実行での見た目のみに設定が反映されている事がわかる。
![010.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/d63182ec-846f-6163-3ce8-ce05defc34c1.jpeg)

CSVダウンロードしても丸められているデータを取得した場合は、round関数を使用する。

「ページ1」に戻り、「データ形式」プロパティで、表示形式を「デフォルト」に戻す。
![006.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/5030bed1-7ff4-d481-39d8-1252d6222baf.jpeg)

「クエリー1」に移動し、達成率の式の定義を、以下のようにround関数を使用したものに変更。
※round関数の引数「2」は、少数点2桁の意味。
**round([販売 (クエリー)].[販売の実状].[収益] / [販売 (クエリー)].[販売の実状].[計画収入],2)**
![011.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/ed5e7bdd-1f77-0ca2-0e22-6d3d93ee2f28.jpeg)

レポートを実行。
![012.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/72b92d81-1f3d-7e72-4ce2-a7644cb9edd6.jpeg)

CSVダウンロードも問題なく少数点2桁で丸められている。
![013.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/a1b6c341-064d-f919-2f0f-b2d0b562783a.jpeg)


#自己学習記事一覧
**Cognos Analytics をエンドユーザーの方に自己学習して頂くためのサイト**
https://qiita.com/shinyama/items/95885c7246dc413b6448
[Unity] 正確な時間間隔で効果音を出す

#メトロノームがほしい、そんな夜もあります。
- そうして心を落ち着けたいのです。

## Unityで、たとえばメトロノームのように、正確な時間間隔で効果音を鳴らしたい場合あなたならどうしますか？
- 最初私はこうしました。

```c#:BadMetronome.cs

public class BadMetronome : MonoBehaviour {
	[SerializeField] AudioSource _ring;
	float _bpm = 140f;
	float _wait;

	//Updateは60FPSで回っているとします
	void Update() {
		_wait -= Time.deltaTime;

		if (_wait <= 0f) {
			_wait = _bpm / 60f;
			_ring.Play();
		}
	}
}
```

- 再生してもこのコードでは心が落ち着きません。処理落ちが一切ないとしても、間隔がガッタガタです。
- なぜ等間隔にならないのかというと、上記例でいうとBPMは140なので 60/140秒（約0.4285714）に一回Play()したいわけですが、60FPSだとUpdate1/60秒 （約0.0166667秒）に１回しか回ってきません。Updateとメトロノームのタイミングはめったに一致しないわけです

## スムースなメトロノームはどこ？
- Updateを140FPSで回してみる？
    - 尻から御飯食べるような解決法。これでもPC向けなら実装可能ですがモバイル向けだと60FPS超えられませんし、BPMを変更するたびにFPS変わる奇怪なアプリが存在していいのか私には疑問です。
- そのうえNotGoodMetronome。何が良くないかというとUpdate()が理想的に毎回同じ時間に回ってくることが期待できないのです。

## Updateでゆらぐことのない時計を探してみる
- Updateで処理落ちしても遅れることなく動いているものがあります。そう、音楽です。
- 音楽はUpdateが回ってこなくても動く時計、[AudioSetting.dspTime](https://docs.unity3d.com/ja/current/ScriptReference/AudioSettings-dspTime.html)を基準にしています
- そして、同期発音のための命令も実は準備されています[AudioSource.PlayScheduled(double)](https://docs.unity3d.com/ja/current/ScriptReference/AudioSource.PlayScheduled.html)です。Updateと独立に指定のdspTimeが来ると音を再生してくれるスグレモノです。
- ほとんど同じにみえる[AudioSource.PlayDelayed(float)](https://docs.unity3d.com/ja/current/ScriptReference/AudioSource.PlayDelayed.html)はfloat精度なので長い時間繰り返し続けるならdouble精度のPlayScheduledがよいようです

## メトロノームはこんなふうに書けた

```c#:GoodMetronome.cs
public class GoodMetronome : MonoBehaviour {

	[SerializeField] AudioSource _ring;

	double _bpm = 140d;
	double _metronomeStartDspTime;
	double _buffer = 2 / 60d;

	void Start() {
		_metronomeStartDspTime = AudioSettings.dspTime;
	}

	void FixedUpdate() {
		var nxtRng = NextRingTime();

		if (nxtRng < AudioSettings.dspTime + _buffer) {
			_ring.PlayScheduled(nxtRng);
		}
	}

	double NextRingTime() {
		var beatInterval = 60d / _bpm;
		var elapsedDspTime = AudioSettings.dspTime - _metronomeStartDspTime;
		var beats = System.Math.Floor(elapsedDspTime / beatInterval);

		return _metronomeStartDspTime + (beats + 1d) * beatInterval;
	}
}

```
- ぐっすり眠れます
【php】GoogleMapsAPI V3でもgeocodeの取得にapi_keyが必要だった話

## 背景
GoogleMapAPI (version 3)を使用しているのだが
いつからか下記の処理でgeocodeが取得できていない。

```
GoogleMapAPI->getGeocode($address)
```

## 原因
* api_keyが設定されていない

だがそもそも
https://code.google.com/archive/p/php-google-map-api/wikis/ChangeLog3.wiki

>Changes from 2.5
Removed references and everything dealing with Google Maps API key since keys are no longer necessary in V3 of the API!
Update geocaching to use new Google Maps V3 geocoder.
New API no longer requires API key - http://code.google.com/apis/maps/documentation/geocoding/

version3の変更点
APIキーは不要になったので、それに関係する処理は取り外したとのこと…。
たしかにapi_keyに関する記述がすべてなくなっていた。

## 苦肉の策
* api_keyを指定できるようにする

GoogleMapAPI (version 3)にapi_keyに関する記述を追加する（本当はパッケージのアップデートとか出来たら良いのだが）

```
    /**
     * YOUR GooglMap API KEY for your site.
     * (http://maps.google.com/apis/maps/signup.html)
     *
     * @var string
     */
    var $api_key = '';

    /**
     * sets YOUR Google Map API key
     *
     * @param string $key
     */
    function setAPIKey($key) {
        $this->api_key = $key;   
    }
```
geoGetCoords()も微修正

```
    public function geoGetCoords($address, $depth = 0)
    {
        switch ($this->lookup_service) {
            case 'GOOGLE':
                $_url = sprintf('https://%s/maps/api/geocode/json?sensor=%s&address=%s&key=%s', $this->lookup_server['GOOGLE'], $this->mobile == true ? "true" : "false", rawurlencode($address), $this->api_key);
                
                ・・・以下略
        }
        return $_coords;
    }
```
[Rails]SystemSpecで統合テストを行う手順

##対象者
プログラミング初学者、Ruby on Rails初学者。
こちらの記事は
・初学者の自分の知識整理
・同じような初学者向けにわかりやすく解説する
ことを目的としております。

##System Specとは

Rails5.1以降で追加されたFeatureSpesに代わるテスト。
ユーザーがアプリケーションを使用する流れと同じ動作をシミュレーションして、想定通りの動きをするか確認できます。
いわゆる「E2Eテスト」「結合テスト」「システムテスト」と呼ばれるテストができます。

seleniumの設定、database cleanerが不要でありセットアップが簡単なので
FeatureSpecではなくSystemSpecを使用します。

##使用する機能

今回は
テストフレームワークに**RSpec**
サンプルデータの生成に**FactoryBot**
を使用します。
FactoryBotはFixtureと違いActiveRecordを使用するため本番環境に近い状態でテストが可能になります。
その代わり動作がFixtureよりも遅くなるのでとにかく軽くしたいという場合は
fixtureをそのまま使用しても問題ありません。

##手順１：gemインストール
必要なgemはrspec, factory-bot, capybara, selenium-webdriver, chromedriver-helperです。

このうちデフォルトで書かれていないrspecとfactory-botを追加します。

```ruby:Gemfile
group :test do
  gem 'rspec-rails'
  gem 'factory_bot_rails'
end
```
bundleとrspecの設定ファイルを生成します。

```
$ bundle
$ rails g rspec:install
```

##手順２：FactoryBotの準備

FactoryBotはfactoriesディレクトリ以下を参照しますので
対応するディレクトリを作成します。
また、modelに対応するファイルも用意しておきます。

```
$ mkdir ./spec/factories
$ touch ./spec/factories/user.rb
```

またmodelに対応するサンプルデータも作成します。

```ruby:./spec/factories/user.rb
FactoryBot.define do
  factory :user do
    name {"sample"}
    email {"sample@example.com"}
    password { "password" }
  end
end
```
ruby文ですがかなりスッキリした形で書くことができます。
また、ファイル名とファイル内のシンボルはモデル名に対応するように書きましょう。

##手順３：SystemSpecファイルの準備

system specにはジェネレータが無いのでディレクトリとファイルを作成します。

```
$ mkdir ./spec/system/
$ touch ./spec/system/login_spec.rb
```

今回はユーザー登録の結合テストという想定にしました。

ファイルの雛形は次のような形になります。

```./spec/system/user_sign_up_spec.rb
require 'rails_helper'

RSpec.describe "User", type: :system do
  it "" do
    #expectations
  end
end

```

specファイルのtypeが :system という感じですね。
ここまで来るとrspecを実行するだけで
ブラウザテストができます。
例えば

```ruby
RSpec.describe "User", type: :system do
  before
    user = FactoryBot.create(:user)
  end
  it "user login" do
    visit '/login'
    fill_in 'email', with: user.email
    fill_in 'password', with: user.password
    click_button 'Sign up'
    expect(page).to have_content 'login successfully'
  end
end
```

と書けばchromeブラウザでのシミュレーションが実行されます。

##手順４：設定を変更する

使いやすいうように少し設定を変更して行きます。

###表示をドキュメンテーション形式に

```ruby:./.rspec
--require spec_helper
--format documentation
```

###headlessモードに変更

このままだと毎回chromeが起動してしまうのでテストに時間が掛かります。
その為headlessモードに変更しておきましょう。
この辺りの設定は
https://qiita.com/jnchito/items/c7e6e7abf83598a6516d
こちらに詳しく記載されています。

```ruby:./spec/rails_helper.rb
  config.before(:each) do |example|
    if example.metadata[:type] == :system
      driven_by :selenium, using: :headless_chrome, screen_size: [1400, 1400]
    end
  end
```
また、systemテストに時間がかかる場合は
通常はcapybara標準のrack_testドライバを使用し、
javascriptを使う場合だけchromeを使用するという設定にします。

```ruby:./spec/rails_helper.rb
  config.before(:each) do |example|
    if example.metadata[:type] == :system
　　   if example.metadata[:js]
        driven_by :selenium, using: :headless_chrome, screen_size: [1400, 1400]　　　　　　
      else
        driven_by :rack_test
      end

    end
  end
```


##参考リンク
https://leanpub.com/everydayrailsrspec-jp
https://github.com/thoughtbot/factory_bot_rails
https://qiita.com/jnchito/items/c7e6e7abf83598a6516d
macOS に Homebrew、nodebrew、Node.js をインストール

macOS に `Homebrew` `nodebrew` `Node.js` をインストールします。

## 環境

- macOS Big Sur バージョン 11.2.3

## インストールするパッケージ

2021/04/22 時点でインストールするパッケージは次の通りです。

- Homebrew 3.1.3
- nodebrew 1.0.1
- Node.js 14.16.1 LTS推奨版
- npm 6.14.12

## Homebrewのインストール

- インストールするには、以下のコマンドをターミナルで実行します。

```sh
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

[https://brew.sh/index_ja.html](https://brew.sh/index_ja.html)

## nodebrewのインストール

- インストールするには、以下のコマンドをターミナルで実行します。

```sh
brew install nodebrew
```

- nodebrewのディレクトリを作成します。

```sh
mkdir -p ~/.nodebrew/src
```

## Node.jsのインストール

- インストール可能なバージョンを確認するには、以下のコマンドをターミナルで実行します。

```sh
nodebrew ls-remote
```

- Node.js LTS(推奨版)をインストールします。

```sh
nodebrew install-binary v14.16.1
```

- インストールされたNode.jsの一覧を確認します。

```sh
nodebrew ls
```

- インストールされたNode.jsから、LTS(推奨版)を有効にします。

```sh
nodebrew use v14.16.1
```

※ Node.js のバージョンを切り替えて使えるので、とても便利です。

## パスを通す

- `vim` などで `~/.zshrc` に次を追加します。

```sh:~/.zshrc
export PATH=$HOME/.nodebrew/current/bin:$PATH
```

- 設定を読み込むために、ターミナルを再起動させるか、以下のコマンドを実行します。

```sh
source ~/.zshrc
```

- Node.jsのバージョンを確認します。

```sh
node -v
```

- npmのバージョンを確認します。

```sh
npm -v
```
kotlinで２つの異なるListから重複するIDのものだけ抽出する

## これなに
備忘録。よく調べてよく答え見つからなくてよく特定の記事にたどり着くので完全自分用です

kotlinにおいて
別のdata classをgenericsにもつListに共通するIDを用いて
片方のdata class listを取得したいってときに使う

参考にした記事
https://qiita.com/amay077/items/9d2941283c4a5f61f302

## 前提

こんなdata class×２があるとします

```kotlin
data class Hoge {
  val id: Int,
  val title: String
}

data class Fuga {
  val id: Int,
  val title: String,
  val url: String
}
```

Hogeがマスタ、Fugaがユーザー選択するものとして
選択されているFugaListの `id` が共通なHogeListだけ取得するという場合を想定します

## 結論
```kotlin
val commonIdList = fugaList.flatMap { fuga -> hogeList.filter { hoge -> hoge.id == fuga.id } }
```

以上です
Pytorchで日本語のbert学習済みモデルを動かすまで

## タイトル通りpytorchでbertを動かすまでにやったこと
やってみた系記事です
まとまってる記事がなかったので各サイトのドキュメント読めばわかりますが、一応
## 環境
MacOS High Sierra 10.13.3
## ダウンロード 
京大の学習済みコーパスを以下よりダウンロード
http://nlp.ist.i.kyoto-u.ac.jp/index.php?BERT日本語Pretrainedモデル
Jumanのインストール
https://qiita.com/riverwell/items/7a85ebf95647eaf18a6c
pytorch版bertモデルのダウンロード
https://github.com/huggingface/pytorch-pretrained-BERT

## 注意
http://nlp.ist.i.kyoto-u.ac.jp/index.php?BERT日本語Pretrainedモデル
の詳細に書いてあるので書くまでもないですが見落としてたので一応
 >注意: --do_lower_case False オプションをつけてください。これをつけないと、濁点が落ちてしまいます。また、tokenization.pyの以下の行をコメントアウトしてください。これを行わないと漢字が全て一文字単位になってしまいます。

```
 # text = self._tokenize_chinese_chars(text)
```

なおtokenization.pyの場所については以下参照
https://qiita.com/t-fuku/items/83c721ed7107ffe5d8ff

## コード
　mask言語モデルを試してみます
 
```python:prepare
import torch
from pytorch_pretrained_bert import BertTokenizer, BertForPreTraining, modeling
from pyknp import Jumanpp

config = modeling.BertConfig(vocab_size_or_config_json_file=32006,
                             hidden_size=768, num_hidden_layers=12,
                             num_attention_heads=12, intermediate_size=3072)
model = BertForPreTraining(config=config)
model.load_state_dict(torch.load("pytorch_model.bin"))
tokenizer = BertTokenizer("vocab.txt", do_lower_case=False)

jm = Jumanpp()
res = jm.analysis("今日は良い天気でサッカーがしたくなりますね。")
hoge = ["[CLS]"] + [i.midasi for i in res.mrph_list()]
hoge[6] = "[MASK]"
tokens = tokenizer.tokenize(" ".join(hoge))
ids = tokenizer.convert_tokens_to_ids(tokens)
print([(i, j) for i, j in enumerate(tokens)])
```

```
[(0, '[CLS]'), (1, '今日'), (2, 'は'), (3, '良い'), (4, '天気'), (5, 'で'), (6, '[MASK]'), (7, 'が'), (8, 'し'), (9, 'たく'), (10, 'なり'), (11, 'ます'), (12, 'ね'), (13, '。')]
```



```python:predict
ids = torch.tensor(ids).reshape(1,-1)
model.eval()
with torch.no_grad():
    output, _ = model(ids)
print([tokenizer.ids_to_tokens[i.item()] for i in output[0][6].argsort()[-10:]])
```

```
['サーフィン', '買い物', '歌', '旅', '試合', '勉強', '食事', 'ゲーム', '話', '仕事']
```

上手く動いてそうですね。
【Java】継承関係にあるクラスで、同じ名前の変数・メソッドが使用された時の優先順



```A.java
public class A {
	String val = "A";
	void print() {
		System.out.println(val);
	}
}
```

```B.java
public class B extends A {
	String val = "B";

    @Override
	void print() {
		System.out.println(val);
	}
}
```

これらのクラスを用いて以下を実装&実行

```Main.java
public class Main {
	public static void main(String[] args) {
		A a = new A();
		 // BクラスはAクラスを継承しているため変数の型としてAが使用できる
		A b = new B(); 
		
		// bの型がAであるため、valはA型に定義されたフィールドの値が使用される
		System.out.println("aのvalを表示 : " + a.val); // A
		System.out.println("bのvalを表示 : " + b.val); // A
		
        System.out.print("aのprint()メソッドを実行 : "); 
		a.print(); // A
		System.out.print("bのprint()メソッドを実行 : ");
		b.print();// B
     }
}
```

b.valを表示すると「A」が表示されるのは
変数bの型としてAを使用しており、Aのフィールドが使用されるため。

一方でb.print()で「B」が表示されるのは
Bクラスではprint()メソッドがオーバーライドされており、new B()をした時点でBクラスのメソッドが優先されるため。

メソッドはオーバーライドされるけれど、変数はフィールドに紐づいているので挙動が変わることに注意しましょう
Ubuntuを16.04 LTSから18.04 LTS にバージョンアップしたときの備忘録

## はじめに
Ubuntuを16から18にバージョンアップをしたときの備忘録


## 環境

Ubuntuのバージョン確認

```
cat /etc/lsb-release
```

or

```
lsb_release -a
```

環境はこんな感じ

```
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Linux Lite 3.4"
```

## Ubuntuバージョンアップ
`update-manager-core`のインストール

```
sudo apt-get install update-manager-core
```

確認

```
cat /etc/update-manager/release-upgrades
```

アップデートの実行

```
sudo do-release-upgrade -d
```

- sshの確認
- アップデート概要の確認
- `/etc/default/grub`の設定ファイルをどうするか？
- `/etc/ssh/sshd_config`をどうするか？
- いらないパッケージの削除確認
- 再起動の確認

完了！！！

バージョン確認

```
cat /etc/os-release
```

こんな感じ

```
NAME="Ubuntu"
VERSION="18.04.2 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.2 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic
```



## アップデートする前にしたこと

`apt-get`のupdate

```
sudo apt-get update
```

`apt-get`のupgrade

```
sudo apt-get upgrade
```

`apt`のupdate

```
sudo apt update
```

`apt`のupgrade

```
sudo apt upgrade
```

`apt`のdist-upgrade

```
sudo apt dist-upgrade 
```

### 参考：upgradeとdist-upgradeの違い
`upgrade`は現在のパッケージのみを更新し、`dist-upgrade`は現在のパッケージ更新と、必要に応じてパッケージのインストール、不要なパッケージの削除、カーネルの更新等もしてくれる。らしい..


### エラーの対処

```
sudo apt -f install
```

```
sudo apt-get install --reinstall
```

```
sudo apt-key update
```

```
sudo dpkg --configure -a
```

```
sudo apt --fix-broken install
```

アップグレードのときにめっちゃエラーが出たので、対処したときのコマンド群です。
何かの参考になれば

## おわりに
とりあえず、なんとかUbuntuのアップグレードは完了したけど、めっちゃ時間かかった。
しかもぼくのUbuntuじゃなくて、知り合いのやつっていうね...。
お疲れ様でした、ぼく。


## 参考
- https://qiita.com/TsutomuNakamura/items/bbd712e3afe5f4bacfac
- https://yoshinorin.net/2018/08/22/ubuntu1604-upgrade-to-1804/
- https://server.etutsplus.com/how-to-upgrade-to-the-latest-version-of-ubuntu-with-do-release-upgrade/
インタビューやアンケートの質問設計で大事なポイント

##前提
インタビューや質問設計で大事なポイントをまとめてみました。
前提として、テーマに関連した直接的な考え、感情、行動（Think-Feel-Do-Say）を探るためのポイントになります。

##意識すべきポイント
1）専門用語や業界用語を避ける
2）質問文は簡潔に分かりやすく。長文にしない
3）「〜ない〜ない」はNG！ 二重否定を避ける
4） 意味・解釈が複数ある言葉を使わない。「回答者を迷わせない」が大原則
5）質問文に2つ以上の要素を入れない（ダブルバーレル）
6） 同じ内容の質問をしない。設問の無駄をなくそう
7）モレなし、ダブリなし！ 選択肢はMECEにする
8）回答を誘導しない。フラットな印象の質問文にする
9）アンケートやインタビューの流れを意識して、質問の順番を整える
10）意図を持って「直近」「普段」を使い分ける
11）回答者の記憶に頼りすぎない
12）質問数を少なくする
13）アンケートにもターゲット設定を！
Macで立ち上げたlocalhostにローカルホスト名で接続できなかった原因

### はじめに

Mac 上で立ち上げた localhost で動いているウェブアプリケーションに iPhone 等のデバイスから接続するには [「MacとiPhoneでlocalhost接続を行う方法（iOS9）」](https://qiita.com/shymst/items/4517a9b904c2c7f908ed) にある通り、[Bonjour](https://ja.wikipedia.org/wiki/Bonjour) を利用することで、 iPhone でのプロキシ設定をすることなくローカルホスト名で接続（_http://{ローカルホスト名}.local:{ポート}_）できるので楽です。

この方法で iOS アプリの開発を進めていたのですが、あるタイミングからこの方法での接続ができなくなってしまいました。

### 接続できなくなった理由

１ヶ月くらい悩んだ結果、共有に関するサービスが一つもオンになっていないことが原因でした。下図のスクリーンショットにある通り、システム環境設定「共有」でファイル共有等のサービスを有効にしないと、Bonjour 自体が有効にならないようです。ちゃんちゃん。

<img width="780" alt="スクリーンショット 2019-04-23 14.06.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16508/c7eea67b-b034-c476-3cfe-e0286f4a0fd2.png">
React.useEffectで非同期処理をする場合に無駄に再レンダリングしないための手法2つ

## はじめに

React hooksのuseEffectで非同期処理を書くことができます。この時、コンポーネントのstateを変更する場合がしばしばありますが、場合によっては複数回レンダリングすることがあります。

## 複数回レンダリングする例

```jsx
import React, { useEffect, useState } from 'react';

const MyComponent = () => {
  const [greeting, setGreeting] = useState('Hello');
  const [name, setName] = useState('World');
  useEffect(() => {
    setTimeout(() => {
      setGreeting('Hi');
      setName('React');
    }, 1000);
  }, []);
  return (
    <div>{greeting}{' '}{name}</div>
  );
};
```

現状だと、setTimeoutのコールバックでsetGreeting, setNameでそれぞれレンダリングされます。これが問題ないケースもあるかと思いますが、改善したいケースもあるかもしれません。

## 解決策1

useReducerを使うことで解決できます。

```jsx
import React, { useEffect, useReducer } from 'react';

const initialState = {
  greeting: 'Hello',
  name: 'World',
};

const reducer = (state, action) => ({
  greeting: action.greeting,
  name: action.name,
});

const MyComponent = () => {
  const [state, dispatch] = useReducer(reducer, initialState);
  useEffect(() => {
    setTimeout(() => {
      dispatch({
        greeting: 'Hi',
        name: 'React',
      });
    }, 1000);
  }, []);
  return (
    <div>{greeting}{' '}{name}</div>
  );
};
```

## 解決策2

`unstalbed_batchedUpdates`を使うことでも解決できます。Reactの内部的にはイベントハンドラで使われているものです。

```jsx
import React, {
  useEffect,
  useState,
  unstable_batchedUpdates as batchedUpdates,
} from 'react';

const MyComponent = () => {
  const [greeting, setGreeting] = useState('Hello');
  const [name, setName] = useState('World');
  useEffect(() => {
    setTimeout(() => {
      batchedUpdates(() => {
        setGreeting('Hi');
        setName('React');
      });
    }, 1000);
  }, []);
  return (
    <div>{greeting}{' '}{name}</div>
  );
};
```

APIとしてはunstableなのでお気をつけください。

## おわりに

個人的にはできるだけuseStateを使ってシンプルに組み立てたいですが、場合によってはuseReducerを使う方が問題が起こりにくいため活用するのが良いとは思います。その場合は、カスタムフックにしてロジックを切り分けた方が良いかもしれません。
Andrew Ng on Building a Career in Machine Learning を訳してまとめてみた（後編）

##はじめに
後編の本記事では、Andrew Ng on Building a Career in Machine Learning の動画内で Andrew NG 氏に対する AI 分野に関する様々な質問と、その回答についてまとめました。
動画本編は[ここから](https://www.youtube.com/watch?v=4kiHsIaK9_w)どうぞ。

この記事の前編は[こちらから](https://qiita.com/Yoshiyuki03/items/35a795ed636f1ae5d2e1)。


##Building a Career in Machine Learning
####質問
- 質問1. 就職と大学院への進学はどちらを選ぶべきか？
 - どちらもやってみて、自分が本当に良いと思う方を選択すること
 - それより大事なのは、どういう環境に自分を置くかということ
     - 周りの身近な人間（10~30人）から受ける影響はとても大きい
     - あなたが成功するかどうかは、どういう環境に身を置くかが鍵となる
 - 大学や企業の「ブランド」だけで選んではいけない

- 質問2. 1つの分野に特化するか、それとも複数の分野の専門になるのか、どちらが良いか？
 - 全員が、全ての分野における専門家である必要はない
 - 異なる分野の人間と共同作業をするのも良い経験になる 

- 質問3. AI分野に詳しくなるのにどれだけ時間がかかるか？
 - 今のご時世、学ぶ手段はたくさんあるので2年くらいあればある程度分かるようになると思う
 - 大事なのはインプットとアウトプットを欠かさないこと
 - coursera などのコース学習はおすすめ
 - 論文も読むことで分野の理解が深まる
     - 論文 10~20:多少その分野が分かるようになる
     - 論文 50~  :その分野にかなり詳しくなる
     - 論文 100~ : 新しいアイデアも生まれるほどになる

- 質問4. 今後5年間で期待できる、または重要と思われる分野や技術は何か？
 - 機械学習の分野
     - 従来よりも少ないデータで学習可能となる技術 
     - 早い話が100枚のデータ画像からでも学習可能な技術 
 - 一般化
     - 型の旧い機器でも利用できるよう一般化させる技術
 - ソフトウェア分野 
     - ML の分野はまだまだ未発達（成長の余地あるとも言える）
     - ML 分野における優秀なプロダクトマネージャの育成が必要 

- 質問5. AIが統合された社会におけるエンジニアやプログラミングの役割は何か？ 
 - 昔は修道士など限られた人しか読み書きができなかったが、今はほぼ皆ができ、それによりコミュニケーションそのものが変化した
 - 識字が今は多くの人にとって当たり前の様に、コーディングも将来的には当たり前のものとなるだろう

- 質問6. ソフトウェア分野以外でAIの仕事を探すには？
 - 特によい回答は持ち合わせていない
 - 現状の問題点として挙げるなら 
     - CEO や上の人間の AI ビジネス戦略が乏しい
     - そもそも AI に対する理解が乏しい
     - 管理職や上の人間が技術分野に関するバックグラウンドが足りない

- 質問7. 学習コンテンツは何が良いか？
 - 学習方法としては、コース学習からまず始めること
 - 分野について学ぶ際は、ネット検索や論文を利用すること 
 - 論文を読む際のコツ
     - まず5つほどネット検索してサッと読む
     - その後で精読するものを取捨選択する
     - 精読した論文と関連する論文を検索し、読んで理解する
     - これを繰り返し行うことで、その分野に詳しくなれる  


- 質問8. 会社の上司や上の人間に AI を理解してもらうには？
 - 例えば coursera の教材を受けてもらう
 - " [AI For Everyone](https://www.coursera.org/learn/ai-for-everyone) " という coursera のコースがおすすめ 
 
- 質問9. 仕事のあり方の変化にどう対応していけば良いか？
 - 個人レベル
     - 子供がいる家庭は生涯勉強であることを子供に教える
     - ある程度の年齢ならプログラミングを教えるのも良し
 - 社会レベル
     - 伝統的なベーシックインカムの仕組みは賛同できない
     - 学習する限り受け取れるベーシックインカムなどにする
     - 条件を加えることで社会に役立つ人材を同時に育成する仕組みを作る
     - 現状、様々な分野で人材が不足している
 
- 質問10. Andrew Ng 氏が AI 分野に興味を持ったきっかけは？
 - 医者である父親の論文がきっかけ
 - 父親は機械学習を医療診断に応用しようとしていた


##おわりに
動画のまとめは以上です。10問の質問の中に、今後の AI 分野に取り組む姿勢を学ぶことができたかと思います。 Andrew Ng 氏の AI 分野に対する考えを聞ける動画なので、ぜひ本編も参照して頂ければと思います。