OmniAICreator/Qiita-1.07M huggingface dataset:
いまさらRFBプロトコルについてまとめた

# RFBプロトコルってなに？
多くの人が使っているであろう**VNC**のサーバーとクライアントがデータのやり取りのために使っている通信プロトコルです。
RFBは"Remote FrameBuffer"の略で、その名の通り、サーバー側の[フレームバッファ](http://e-words.jp/w/%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%90%E3%83%83%E3%83%95%E3%82%A1.html)をリモートで見られるようにするものです。
ドキュメントを読んだので簡単にまとめました。
# 大まかな通信の流れ
大まかな流れは下記の図のように、ハンドシェイクフェーズで諸々取り決めをした後、通常のプロトコル対話でサーバー側の画像データやクライアント側の入力のやり取りが行われる感じです。

大きな流れを理解しやすくするため、エンコードやピクセルフォーマットに関しては端折っています。
気になる方は[コチラ](http://srgia.com/docs/rfbprotocol3.8.html)を参照
![Screenshot from 2019-12-17 16-05-15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278261/0f4f232a-2bc2-b30c-52f1-3266e0b03350.png)

## ハンドシェイクフェーズ
###ProtocolVersion
最初はサーバーからクライアントにメッセージを送る
サーバーとクライアントのRFBプロトコルのバーションを一致させる
メッセージ例：

|バイト数|値|
|:--:|:---:|
|12|"RFB 003.003\n" |
この場合、値が意味しているのはRFBプロトコルのバージョンが3.3ってこと
###Security
セキュリティタイプをお互い1バイトメッセージで示す。サーバーが決める

###ClientInit
クライアントとサーバーがお互いに合意したセキュリティタイプで通信準備ができたら、クライアントは1バイトの初期化メッセージを送信する

###ServerInit
clientinitのメッセージを受け取った後、サーバーはseverinitメッセージを送信する。メッセージ内容は以下の通り。
名前の長さ、名前はデスクトップに関連つけられた名前

## 通常のプロトコル対話
##【クライアントからサーバーへのメッセージ】
クライアントからサーバーへのメッセージタイプは以下の通り

|値|名称|
|:--:|:---:|
|0|SetPixelFormat |
|0|SetEncodings |
|3|FramebufferUpdateRequest |
|4|KeyEvent |
|5|PointerEvent |
###SetPixelFormat
　フレームバッファアップデートメッセージないで使用されるピクセル値のフォーマットを設定する。クライアントがこのメッセージを送らなかった場合serverinitialisationメッセージで指定した、サーバー自身の自然なフォーマットを使用する。

###SetEncodings
　サーバーが送信するピクセルデータに使用するエンコード形式を設定する。

###FramebufferUpdateRequest
　クライアントがフレームバッファのどこの領域に注目しているかをサーバーに知らせる。
　サーバーはこのメッセージに対してframebufferupdateメッセージで応答する。
（FramebufferUpdateRequestに対して複数のFramebufferUpdate を返すことも許されている）
↓メッセージ詳細:information_desk_person:

|バイト数|型|値|説明|
|:--:|:---:|:---:|:---:|
|1|U8 |3|message-type
|1|U8 ||incremental
|2|U16 ||x座標
|2|U16 ||y座標
|2|U16 ||幅
|2|U16 ||高さ
###KeyEvent
なんのキーが押されたor離されたことを示すメッセージ
↓メッセージ詳細:information_desk_person:

|バイト数|型|値|説明|
|:--:|:---:|:---:|:---:|
|1|U8 |4|message-type
|1|U8 ||down-flag
|2| ||padding
|4|U32 ||key

###PointerEvent
ポインタの移動、またはポインタのボタンが押された、放されたことを示すメッセージ
ポインタの位置は（ｘ座標、ｙ座標）で表される
↓メッセージ詳細:information_desk_person:

|バイト数|型|値|説明|
|:--:|:---:|:---:|:---:|
|1|U8 |5|message-type
|1|U8 ||button-mask
|2| ||padding
|4|U32 ||key

##【サーバーからクライアントへのメッセージ】
サーバーからクライアントへのメッセージタイプは以下の通り

|値|名称|
|:--:|:---:|
|0|FramebufferUpdate|
|1|SetColorMapEntries|
|2|Bell |
|3|ServerCutText|

簡略化のためFramebufferUpdateのみ詳細を紹介
###FramebufferUpdate
クライアントからのframebufferupdaterequestメッセージに対応する長方形のピクセルデータを送っている
↓ヘッダー詳細:information_desk_person:

|バイト数|型|値|説明|
|:--:|:---:|:---:|:---:|
|1|U8 |0|message-type
|1| ||padding
|2|U16 ||number-of-rectangles
↓メッセージ詳細:information_desk_person:

|バイト数|型|値|説明|
|:--:|:---:|:---:|:---:|
|2|U16 ||x座標
|2|U16 ||y座標
|2|U16 ||幅
|2|U16 ||高さ
|4|U32 ||encoding-type

# 参考
https://tools.ietf.org/html/rfc6143
http://srgia.com/docs/rfbprotocol3.8.html
Node.js+Selenium WebDriverでブラウザのエラーログを取得する話

## はじめに

こんにちは。
surimi_panです。

本記事は[North Detail Advent Calendar 2019](https://qiita.com/advent-calendar/2019/northdetail)の19日目の記事となります。
日付の数字(19)が西暦の下2桁(19)と一緒ですが、当記事に19に関わる要素は特にありません。

今回はNode.jsとSelenium WebDriverを利用して、
Google Chromeの開発者ツールにて出力されるログの中にエラーが無いかをチェックします。

## 要件

- Google Chromeの開発者ツールに出力されるエラーを取得したい。
- 取得するエラーログは深刻なものに限る。（WARNINGは含まない）

## 手段

Selenium WebDriverの、ログを取得する機能( `selenium-webdriver/lib/logging` )を利用します。
ブラウザのログをレベル（＝ログの重要度）で絞り込んで取得することができます。

## 実装

```javascript
require('chromedriver');
const chrome = require('selenium-webdriver/chrome');

const webdriver = require('selenium-webdriver');
const Builder = webdriver.Builder;
const capabilities = webdriver.Capabilities.chrome();
const {Preferences, Type, Level} = require('selenium-webdriver/lib/logging');

// ログを調べたいWebページのURL
const targetUrl = '調べたいWebページのURL';

const logPrefs = new Preferences();
logPrefs.setLevel(Type.BROWSER, Level.SEVERE);
capabilities.setLoggingPrefs(logPrefs);

const options = new chrome.Options(capabilities);

// エラーログを出力する
(async function printConsoleErrors() {
  const driver = await new Builder().forBrowser('chrome')
                                    .setChromeOptions(options)
                                    .build();
  
  await driver.get(targetUrl);
  await driver.sleep(5000);
  
  let errors = await driver.manage()
                           .logs()
                           .get(Type.BROWSER);
  for(var i=0; i < errors.length; i++) {
    console.log(errors[i].message);
  }
  
  await driver.quit();
})();
```

### 詳細

#### 取得するログの種類の絞り込み

```javascript
const logPrefs = new Preferences();
logPrefs.setLevel(Type.BROWSER, Level.SEVERE);
capabilities.setLoggingPrefs(logPrefs);
```

取得するログの種類、レベルを絞り込みます。
今回はブラウザのエラーログを取得したいので、
取得したいログの対象を`BROWSER`(ブラウザ)、
取得したいログのレベルを`SEVERE`(最も深刻なもの→エラー)に設定します。

#### ログの絞り込みの設定を適用

```javascript
const options = new chrome.Options(capabilities);
```

```javascript
const driver = await new Builder().forBrowser('chrome')
                                  .setChromeOptions(options)
                                  .build();
```
WebDriverインスタンスを作る際にログの絞り込み設定を反映させます。

#### ページの遷移と待機

```javascript
await driver.get(targetUrl);
await driver.sleep(5000);
```

チェックしたいページに遷移して一定時間待機します。
時間差でエラーが出るものを考慮して気持ち長めに待機時間を設定しています。

#### エラーログの取得

```javascript
let errors = await driver.manage()
                         .logs()
                         .get(Type.BROWSER);
```
ブラウザのエラーログを取得します。
取得されるログのレベルはSEVEREに設定されていますので、エラーのみ取得します。

#### 取得したエラーの出力

```javascript
for(var i=0; i < errors.length; i++) {
  console.log(await errors[i].message);
}
```
配列で返ってくるので、展開してコンソールに出力します。


## まとめ

実行すると、エラーを吐くページではエラーログが次々出力されます。

Webページのスクレイピングやフォームのテスト等で利用されがちなSeleniumですが、
変わったこともできますよ！という記事でした。

資料が少なく、[公式ドキュメント](https://selenium.dev/selenium/docs/api/javascript/index.html)とにらめっこしながらの実装となりました。
不備不足あればご指摘頂けると大変助かります。
RailsのenumをGem無しでi18nに対応させる

# この記事は一体？

Railsでenumの値をi18nに対応させる方法として、よく紹介されるのがGemを入れて対応させる方法です。
例えば [enum_help](https://github.com/zmbacker/enum_help) や、 [enumerize](https://github.com/brainspec/enumerize) がよく取り上げられます。

しかし、enum_helpは（2019/12/17現在）更新が2017年で止まっており、
継続してメンテナンスされてないGemをプロジェクトに入れるのは考えものでしょう。
enumerizeは高機能ではありますが見慣れたenumの書き方ではなくなるし、
やりたいことに対してオーバースペック気味なのでは？ と感じます。

そこで、Gemに頼らず自前でenumの値をi18nに対応させてみます。

ここでは以下の2点を実現します。

- モデルのインスタンスからenumのカラムの値を日本語化して取得する
- モデルからenumのカラムで設定可能な値の配列を日本語化して取得する

# 方法

各モデルの親クラスとなる`ApplicationRecord`にメソッドを追加します。
やってることとしては、モデル名とenumのカラム名、そしてenumの値から対応するi18nを取得しているだけです。

```ruby:application_record.rb
class ApplicationRecord < ActiveRecord::Base
  def enum_i18n(enum_name)
    return nil if self.send(enum_name).nil?
    I18n.t!("enums.#{self.model_name.i18n_key}.#{enum_name}.#{self.send(enum_name)}")
  end

  def self.enums_i18n(enum_name)
    self.send(enum_name.to_s.pluralize).map do |key, value|
      [I18n.t!("enums.#{self.model_name.i18n_key}.#{enum_name}.#{key}"), value]
    end.to_h
  end
end
```

あとはenumを設定した各モデルで、このメソッドを使うだけです。

```ruby:user.rb
class User < ApplicationRecord
  enum status: { hoge: 0, fuga: 1, piyo: 2 }
end
```

```yaml:ja.yml
ja:
  enums:
    user:
      status:
        hoge: ほげ
        fuga: ふが
        piyo: ぴよ
```

```ruby
user = User.new(status: :hoge)
user.enum_i18n(:status)
# => "ほげ"
User.enums_i18n(:status)
# => {"ほげ"=>0, "ふが"=>1, "ぴよ"=>2}
```

これだけやれれば、追加でGemなくしてi18nに対応できてるでしょう。

# 参考記事

https://www.kostolansky.sk/posts/localize-rails-enums/
faviconにSVG画像の指定がサポートされたようなので、試してみる

Chrome 80 からfaviconにSVG画像を指定できるようになっているみたいなので、試してみました。
[Support for SVG in favicons - Chrome Platform Status](https://www.chromestatus.com/feature/5180316371124224) 

ソースコード

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <link rel="icon" type="image/svg+xml" href="https://avataaars.io/?avatarStyle=Circle&topType=LongHairStraight&accessoriesType=Blank&hairColor=BrownDark&facialHairType=Blank&clotheType=BlazerShirt&eyeType=Default&eyebrowType=Default&mouthType=Default&skinColor=Light">
</head>
<body>
</body>
</html>
```

SVG画像には適当にSVGを返してくれるサービスを利用しました。
（Lorem Picsum のSVG版みたいなサイトを探しましたが、見つかりませんでした。誰か教えてください。）

実行結果
<img width="389" alt="SVG in favicon" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104942/ac09417c-d89f-37ee-ddfd-00906161cfac.png">

↓のような書式でSVGファビコンの指定ができます。
`<link rel=icon href=gnome.svg sizes="any" type="image/svg+xml">`

[仕様](https://html.spec.whatwg.org/#rel-icon) にも 
> The any keyword represents that the resource contains a scalable icon, e.g. as provided by an SVG image.

> Google翻訳「anyキーワードは、リソースにスケーラブルアイコンが含まれていることを表します。 SVG画像によって提供されます。」

と書かれているので、なくても動きますが `sizes="any"` を書いておきます。


そういえば、[Link type "icon"](https://html.spec.whatwg.org/#rel-icon) の説明に出てくる例で、属性値がダブルクォートで囲まれてないんですが、そういうものなんですかね？
違和感しかないです。
AWS Secrets Managerを使おう！

#AWS Secrets Managerとは
データベースの認証情報や、パスワードなどの任意のシークレット情報をAPIコールで取得できるためのAWSサービスの一つです。
各サーバからこのAPIを叩くことでシークレット情報を取得でき、認証やサーバセットアップに利用できます。

#何がメリット？

AWS Secrets Managerを利用する一番のメリットは**アプリケーションにシークレット情報を保存する必要がなくなること**です。
従来では、例えばデータベースにアクセスするためのパスワードの場合、パスワードをアプリケーションに保存しておき、データ処理をする場合にその情報を利用するという方法が一般的でした。
この方法の場合、認証情報を更新する場合などパスワードをアプリケーションに埋め込んでいる全ての箇所を更新する必要があり、**認証情報更新のリスクもコストも高かった**のです。。そうなるとパスワードが長期の間更新されず、セキュリティ観点でみるとあまり良いとは言えません。

また、アプリケーションに認証情報を書くことでgithubのようなバージョン管理ツールからパスワードを参照することが可能になってしまいます。
リポジトリにアクセス権のある開発ベンダー会社等からセンシティブな情報がある本番DBに接続できるパスワードを参照できてしまったり、不慮の事故でリポジトリが公開されてしまった場合などに**情報漏洩のリスク**が発生してしまいます。

AWS Secrets Managerを利用することでこれらの情報をアプリケーションに保存する必要は無いのでこれらの心配はなくなります。

#シークレット設定方法

まず、シークレット情報の登録を行います。
AWSコンソールでSecretsManagerを開きましょう。

**1.シークレットの種類を選択**
「その他」を選択することでただのテキスト情報等も登録可能なのでssh keyなどであっても登録可能です。
![キャプチャ1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541083/a9b30b0f-b653-e44c-a297-7a695149301f.png)

**2.シークレットの名前設定**
/区切りで分かりやすい名前を付けましょう。
ここで設定した名前がAPIで取得する際に必要になります。
![キャプチャ2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541083/90deb17c-1e85-a768-c67a-4563ab9a798c.png)

**3.自動ローテーションを設定**
データベースの認証情報を自動的に更新する設定が可能です。
この設定をすることによってSecrets Managerは自動的にRDSの認証情報を更新させることができます。(便利すぎ)
RDS以外のサービスにおいてもデータベースまたはサービスと連携するようにカスタマイズできる Lambda 関数を設定してやることでシークレットの自動更新設定を導入することが可能になっています。

![キャプチャ3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541083/6dcb571f-e0f8-0321-dbb0-d823293c5104.png)

**4.確認**
![キャプチャ4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541083/b0017429-f5d3-2ca3-c76e-f785be9ca67a.png)
確認・保存して完了です！

#シークレット取得方法

keyを取得するAPIの文法です。
結果はJSONで返ってきます。

~~~bash
#regionと2で設定したシークレットの名前を利用しAPIコール
aws secretsmanager get-secret-value --region ${REGION} --secret-id ${SECRETS_ID} 

#下記jqコマンドと併せて利用することでキーの値のみを取得可
aws secretsmanager get-secret-value --region ${REGION} --secret-id ${SECRETS_ID}  | jq -r .SecretString
~~~

ちなみにAPIの料金は下記の通りです。
とても簡単！

`10,000 件の API コールあたり0.05USD。
`
[AWS公式サイト](https://aws.amazon.com/jp/secrets-manager/pricing/)

AWS基盤を用いているのにSecretsManagerを利用していない方はこちらの利用をご検討してみてはいかがでしょうか！
（初心者向け）Scala：for yieldを使って見通しの良い手続きを書く（すべて成功、一部失敗）

# やりたいこと

複数の処理を直列で行い、すべて成功していれば次の処理へ　ってよく書きますよね
一般的な手続き型言語であればこんな感じでしょうか

```c
if(処理A && 処理B && 処理C){
 処理X
}
```

処理Aの結果を処理Bで処理し、結果Bを最後の処理Xで使いたい場合とかどうしましょう
Scalaでcase文だとこんな感じでしょうか

```scala
処理A match {
 case Right(結果A)=>{
   処理B(結果A) match {
     case Right(結果B) =>{
       if(処理C){
         処理X(結果B)
       }
     }
   }
 }
}
```

｛｝地獄。。。

#こんな風に書けたら見通しがいいです

```scala
(for{
  結果A<-処理A
  結果B<-処理B(結果A)
  結果C<-処理C
} yield Success(結果B)).merge match {
  //処理A,処理B,処理Cがすべて成功した場合、結果Bを処理Xで実行する。
  case Success(結果B)=>処理X(結果B)
  //処理A,処理B,処理Cのどれかが失敗した場合、エラー結果を出力する。
  case error:Failure=>println(error)
}
```


# 実際書いてみる。

## １．下準備
```scala
//sealed 基底クラス
sealed abstract class BaseResult

//Success(BaseResultを拡張）
case class Success(message:String) extends BaseResult

//Failure (BaseResultを拡張）
abstract class Failure extends BaseResult

//case　object を使って各エラーを定義（Failureを拡張）
case object Error1 extends Failure
case object Error2 extends Failure
```

## ２．処理を定義
```scala

def func_a:Either[Failure,String]={Right("A")}//処理A
def func_b(str:String):Either[Failure,String]={Right(str+"B")}//処理B
def func_c:Either[Failure,String]={Right("C")}//処理C
def func_c_error:Either[Failure,String]={Left(Error1)}//処理C失敗
def func_x(str:String):Unit={println("すべて成功:%s".format(str))}//処理X
```

## ３．結果

### すべて成功
```scala
scala> (for{
     |  resultA<-func_a.right //成功
     |  resultB<-func_b(resultA).right //成功
     |  resultC<-func_c.right //成功
     | } yield Success(resultB)).merge match {
     |  case Success(x)=>func_x(x) //←　
     |  case x:Failure=>println(x)
     | }
すべて成功:AB
```

### 一部失敗
```scala
scala> (for{
     |  resultA<-func_a.right //成功
     |  resultB<-func_b(resultA).right //成功
     |  resultC<-func_c_error.right //失敗
     | } yield Success(resultB)).merge match {
     |  case Success(x)=>func_x(x)
     |  case x:Failure=>println(x) //←　
     | }
Error1
```


# 最後に

基本形として覚えておきたい。
AWS Compute Optimizer を試してみた


#はじめに

この記事は株式会社ナレッジコミュニケーションが運営する [ Amazon AI by ナレコム Advent Calendar 2019](https://qiita.com/advent-calendar/2019/knowcom-amazonai) の18日目の記事になります。
18日目である今日は AWS Compute Optimizer について書いていきます。

#インスタンスタイプ最適化の難しさ
突然ですが皆さん、サービスを運用するにあたってこんなことに直面したこと、思ったことはありませんか？

* サービス稼働しているけどなんとなく重い
* メトリクス見る限りでは全然余裕がありそう。1つ下のスペックに下げてもいいんじゃ？
* そもそも今利用しているインスタンスってサービスにあった最適なものを選べているのか

インスタンスサイズが小さすぎればアプリケーションのパフォーマンスが低下し、ユーザの顧客満足度を得ることが出来ません。
かといってインスタンスサイズが大きすぎればコストがかかる。
サービス運用者にとっては悩みのタネの一つです。

しかし最適なインスタンスを選ぶのは中々に大変な作業。
平常時とピーク時のリソース利用状況を把握し、インスタンスタイプを選択。そしてまたリソース利用状況を取得し検証。 と繰り返しの作業になり期間を要するためです。

コスト削減のためにインスタンス最適化をしようにも、その結論を出すまでの工数が費用に見合ってなければ本末転倒ですしね。

今回はそんな悩みを解決してくれそうなサービスがAWSから発表されたので使ってみたいと思います。

#AWS Compute Optimizerとは
AWS Compute Optimizer は AWS re:Invent 2019 の期間中に発表された新サービスです。
AWSアカウント内の Amazon EC2 リソース利用状況に対して機械学習を行い、最適なインスタンスタイプを返してくれるといったサービスになります。

似たようなサービスである Cost Explorer の Resource Optimization Recommendations がありますが、こちらとの違いとして、AWS Compute Optimizer は異なるインスタンスファミリーへのレコメンドをしてくれる点があげられます。


#対応リージョン/対応言語
今回は AWS コンソールからサービスを利用してみたいと思います。
対応リージョンは下記の5つです。(2019年12月17日時点)

* 米国東部 (バージニア北部) us-east-1
* 米国西部 (オレゴン) us-west-2
* 米国東部 (オハイオ) us-east-2
* 欧州 (アイルランド) eu-west-1
* 南米 (サンパウロ) sa-east-1  

また現時点では日本語非対応のようで左下の言語選択から「English(US)」を選択する必要があります。

#AWS Compute Optimizer を使ってみる
それでは早速使ってみましょう！
AWSコンソールへログイン後「AWS Compute Optimizer」と検索し開くと、新サービスを開始する際のお馴染みの画面が表示されるので右上の「ご利用開始」から設定をしていきます。

![2019-12-16_18h38_36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322096/9e5aa9b6-775c-56dd-f8f3-fe80dc8c788e.png)

## セットアップ
アカウントのセットアップ画面が開くので「オプトイン」を押下します。
画像の下にも記載がありますが、分析対象となるCloudWatchメトリクスは直近2週間のものが対象となるそうです。
またレコメンドには最低30時間分のメトリクスが必要とのこと。

![2019-12-16_18h39_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322096/02f9f5ee-7d45-faf1-d560-724e40d1b7b9.png)

## ダッシュボード
セットアップが終わったので分析結果を見てみます。
※分析完了までの時間はリソース量によって異なります。

ダッシュボードからは分析の結果、利用中のインスタンスが「スペック不足・最適・過剰スペック」なのかを一覧として確認することが出来ます。
今回のテスト用に立てたサーバは「Optimized」の結果が出ていました。


![2019-12-17_16h03_46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322096/44bf4417-24ad-f263-a047-c2da386b2955.png)


## 結果画面
先程のダッシュボード画面では「Optimized」と出ていたので特に何もないかなと思ってましたが、詳細を確認すると最新世代のt3シリーズへ切り替えることで費用が抑えられますよ。と勧められているのがわかるかと思います。
![2019-12-17_15h56_41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322096/6fd22915-1fc3-849a-3f91-85921e70ba3c.png)

## 比較画面
現在利用しているインスタンスと推奨インスタンスへ変更した際の比較をみることができます。
料金のほかメトリクスについても確認ができるためスペック変更の指標とできそうですね。
ちなみにこのテストサーバには、 CloudWatch Agent が入ってないためメモリのグラフが空白となっていますが、メモリ利用率も分析対象とすることが可能です。
![2019-12-17_16h31_09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322096/62074703-8883-ecb1-3e48-af40a6ab2fbc.png)


#まとめ
インスタンスサイズの最適化にはサーバチューニングなどもありますが、
数クリックで推奨スペックが提示される上にこれが無料でできるというのだから驚きです。
東京リージョン対応が待ち遠しいですね。

#参考リンク
[公式サイト](https://aws.amazon.com/jp/compute-optimizer/)
[ユーザガイド](https://docs.aws.amazon.com/compute-optimizer/latest/ug/getting-started.html)
たった10行でOCR！RubyとGoogle Cloud Vision APIで飲食店のメニュー画像を文字認識してみた

# はじめに

今回はRubyとGoogle Cloud Platform(GCP)を利用して、飲食店のメニュー画像の中から料理名や金額等の文字を抽出してみます。

一般的に光学文字認識(OCR)と呼ばれる技術ですが、導入にはすごくハードルが高そうな気がしますよね。
しかし、Google Cloud Platform(GCP)が提供しているCloud Vision APIを利用することでとっても簡単に実装することができます。

今回は例として以下のメニュー画像を使用します。
<img width="300" alt="menu.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309621/db088aee-035c-8654-aebf-f51f02c659d5.jpeg">
まずはこの画像の文字が正しく認識できるか不安なので、Googleの提供しているAPIのデモで試してみましょう。
デモではこのように画像をアップロードするだけで解析結果の確認ができます。
<img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309621/90782053-3003-85df-7d7f-f91e8a45e778.png">
デモURL：https://cloud.google.com/vision/?hl=ja#vision-api-

実際に解析した結果がこちらです。
<img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309621/dd7c16d5-3c10-8eb7-3df2-5272b929225b.png">
なぜかラーメンと餃子は認識できませんでしたが、それ以外は問題なさそうですね。
また、単語がブロックごとに区切られて識別されていることがわかります。
こちらのデモでは他にレスポンスのJSON等も確認することができます。
開発に着手する前に、まずはデモで確認しておくと安心ですね。

(ラーメンと餃子はさておき)無事画像が解析できそうだとわかったので、今回はこちらの結果をAPIで取得することをゴールに進めていきます。

# 事前準備

Cloud Vision APIを利用するために、以下の事前準備を行います。

- Google Cloud Platform(GCP)に登録する
- Vision APIを有効にする
- 認証情報を設定する
- クライアントライブラリをインストールする

## Google Cloud Platform(GCP)に登録する

GCPへの登録方法の説明はここでは省略します。

## Vision APIを有効にする

Vision APIを有効にするGCPプロジェクトを選択または作成します。
その後、GCP管理画面の検索窓で「Cloud Vision API」を検索し、「有効にする」を押してAPIを有効化します。

※請求先が登録されていない場合はエラーになるので事前に登録してください
<img width="400" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309621/f3d45966-40df-4f2c-151e-46f63f382016.png">


## 認証情報を設定する

クライアントライブラルを使用するために、以下２つの作業を行い認証情報の設定を行います。

- サービスアカウントの作成
- 環境変数の設定

詳細は省略しますので、以下の公式ドキュメントを参考にして実施します。
https://cloud.google.com/vision/docs/libraries#client-libraries-usage-ruby

※言語を日本語にしていると情報が古い可能性があります。Englishでの閲覧をオススメします。

## クライアントライブラリをインストールする

今回はmac+Rubyを使用するので、以下のコマンドで「google-cloud-vision」gemをインストールします。

```
gem install google-cloud-vision
```

以上で事前準備は完了です。

# 実装

ほとんど公式の例と同じですが、実装は以下のようになりました。
コードの記述量としては10行もありません。

```ruby
require "google/cloud/vision"

image_annotator = Google::Cloud::Vision::ImageAnnotator.new

file_path = "/tmp/menu.jpg"

response = image_annotator.text_detection(image: file_path)

response.responses.each do |res|
  res.text_annotations.each do |text|
    p text.description
  end
end
```

# 実行結果

それでは先ほどのコードを実行してみましょう。
実行した結果がこちらです。

```
"メニュー\n750 円\nラーメン\n800 円\nチャーハン\n餃子\n500 円\n"
"メニュー"
"750"
"円"
"ラーメン"
"800"
"円"
"チャーハン"
"餃子"
"500"
"円"
```

認識した文字全体と、個々の単語が出力されました。
デモでは認識されなかったラーメンと餃子も無事認識されています:clap:

# おわりに

ハードルの高そうなOCRですが、GCPを使えば簡単に実装できることがわかりました。
事前にトレーニング済みの機械学習モデルを利用することができるので、こちらがトレーニングを行わなくてもかなり精度の高い解析ができる環境が整っているのも大きな強みだと感じました。

ただし、GCPの使い方によっては課金が発生してしまう場合があるので、注意してご利用ください。（2019/12/21時点ではCloud Vision APIは1000リクエスト/月まで無料）

また、今回は触れていませんが、Cloud Vision APIには物体の検出や顔認識等の機能もあるので試してみると面白いかもしれません。

明日は@tayu1605さんの「はじめてのElasticsearch」です！お楽しみに〜:snowman2:
COBOLERからweb系エンジニアへ移って

もうクリスマスまで一週間を切りましたね
今年のクリスマスは平日ですが皆様はどう過ごされるでしょう？<br>私は通常営業で仕事に邁進いたします:innocent:<br>それでは[パーソンリンクアドベントカレンダー](https://qiita.com/advent-calendar/2019/person-link)19日目になります。
##はじめに
軽い自己紹介です。<br>私が今の会社に勤めてから九ヶ月ほど経過しているのですが現在はWeb系のエンジニアとしてバックエンドを担当しています、それ以前は別の会社でITエンジニアをしており三年ほど生命保険のシステム開発に携わってきました。その時主に触っていた言語が「COBOL」です。ITエンジニアと一口に言っても種類によって扱う言語や環境は大きく変わっていきます。この記事ではそんな違いについての実体験をまじえて書いていきたいと思います。

##システム開発の種類
Web系、オープン系、汎用系、組み込み系、ゲーム系...と細分化していくとなかなかの種類になりますが今回はweb系と汎用系を中心に見ていきます。

- **Web系**<br>身近なものだとホームページやSNS、通販サイトなどWeb上のシステム開発を行います。おそらくもっとも一般的なITエンジニアとしてのイメージが強いのがこの系統ではないでしょうか。
Web系の業務は**フロントエンド（クライアントサイド）**、**バックエンド（サーバーサイド）**に分かれています。
<br>簡単にまとめるとフロントエンドはユーザーから見える部分を担当します。バックエンドはその逆でユーザーから見えていない部分の担当です。
![図解.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404045/f1c09bea-0307-a006-8d59-fbf131e3ea9e.png)
[図引用元](https://xn--lcs689i.net/frontend-backend/)
例えばWebサイトで考えてみましょう。ボタン操作や入力ができる部分、画面表示などのUI、UX部分、ここはフロントエンドの領域です。ログインに使用するユーザーやパスワードを管理しているデータベース、サーバー構築部分、ここがバックエンドの領域になります。
<br>担当している業務が変われば扱う言語も変わっていきます。フロントエンドで主に使用する言語はHTML、CSS、JavaScriptなど、バックエンドではJava、Python、PHP、Ruby、Golangなどでしょうか。この他にも言語は多岐に渡って存在しますので使用用途によって使い分けていきます。
<br>またWebの開発と密接に関わってくるものが**フレームワーク**です。
フレームワークを一言でいうととさまざまなシステム開発を効率化してくれる機能群です。ソフトウェアの骨組みが用意されており、目的に合わせて修正、追加を行っていくことで開発にかかる時間的コストを軽減、エンジニア間でのコードの統一化、一から自分で組み立てるよりバグが出づらいといったメリットがあります。
メジャーなフレームワークとして、Ruby on Rails、React、Laravelなどがあり、こちらも多種多様に対応言語も分かれています。
このようにWeb系の分野においては非常に多くの技術がありその流行り廃りも日々変化していくため常に学習し続けること、新しい技術をいち早くキャッチするアンテナを立てていくことが重要になっていきます。


- **汎用系**
  こちらは汎用機（メインフレーム）と言われる、企業の基幹システムなどに利用するコンピューターを用いてシステム開発を行います。主に保険会社、銀行、クレジットカード会社などの金融機関や企業の基幹システムの構築や運用保守の業務に使用します。汎用系の業務は一つの機器のみで完結するクローズドなもので、主に言語はCOBOLが使われます。
OS・アプリケーションソフトなどはほとんどが企業独自のものになります。私の以前勤めていた現場でも例にもれず独自の製品を使用していました。ただ同じ業界であれば基本的なシステムの構造は似通っているため独自のものを使っているからと言って全く応用ができないわけではありません。
また長年稼働しているところが多く安定してシステム運用が行われています。


##両者を経験して感じたこと
大きく違うのは開発時の考え方です。現在は使ってみたい技術があるから試してみよう、こうした方がより早く処理ができるからこっちに変更しよう、とより良いものができる可能性があればとりあえず試してみます。一方、汎用系での開発の場合、安全性を求めて開発します。障害を発生させないことを第一に考えるため既存を踏襲して設計します。既存を外れた設計をした場合、安全性の証明に膨大な検証をして既存に影響が出ないことや新規に追加部分のバグを潰していくためコストが多く発生するのでクライアントからも今まで通りで設計するように指示されることがほとんどです。汎用系はクライアント先が銀行や保険、行政機関等なのでどうしても保守的な考えになってしまうのは致し方ありません、
個人的な考えですが汎用系の場合だと新しい技術に触れることがないため業務を通して技術者としての成長はあまり無いように感じます。どちらかというとクライアント先の業務知識が身についていくためその分野での活躍を今後も考えているのならば意味はあるでしょう。
どちらを選ぶかは個人の考えによるかと思いますが、今後エンジニアとしての技術を伸ばしていきたいと考えているのならWeb系へ進むことをオススメします。
matplotlibを使ったplot系モジュールが作成したグラフの見切れラベルを回避する方法

# はじめに

内部で`matplotlib`を使っているグラフプロット系のメソッドが出力したグラフを保存してみると、軸ラベルが見切れてしまう場合がある。
メソッド内でレイアウト設定がされているため、調節するのも一苦労だが、そこをよしなに調整する方法を書き記しておく。

# やり方

`pylab`(`matplotlib.pylab`でも可)の`tight_layout`メソッドを呼び出せばよい。

グラフ内の軸ラベルやメモリラベルがうまく出力できるようにグラフレイアウトが変更される。

以下は、`shap`モジュールの`summary_plot`による例。

```python:shapのsummary_plotでの例
shap.summary_plot(shap_values, X, show=False)
pylab.tight_layout()
plt.savefig('./shap.png')
```

# 参考

- [bbox_inches = "tight"とかそれ系のやつ - virsalusの日記](http://virsalus.hatenablog.com/entry/2015/01/19/120931)
- [Tight Layout guide — Matplotlib 3.1.1 documentation](https://matplotlib.org/3.1.1/tutorials/intermediate/tight_layout_guide.html)
新世代ノードの「RA3」が発表されたついでにRedshift説明していきます

どうもこんにちは
今年2019年の12/03に新しいノードであるRA3ってのが発表されました．
![reinvent2019-amazon-redshift-ra3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543591/1a2264f7-eaba-f31a-d508-b4659ac5668e.jpeg)

Redshift使ったことのある人なら理解できると思いますが，
要は，従来のHDDを使ったノード作成よりももっと大量のデータを分析することが出来ます．

さっそくマネジメントコンソールをみてみると，
![スクリーンショット 2019-12-17 16.46.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543591/3e051c10-eb8f-f7a5-01fe-ac289d58fd35.png)

DSが隠れてるwww

もうDSいらんって話でしょう！！
その前にRedshiftの解説から．



#Redshift
Redshiftってなんだ？
データベースなの？
分析ツールなの？

って感じでふわっとした感覚の方いらっしゃると思います．

今回はRedshiftを完璧になるまで説明していきます!!

##データウェアサービスとかいう説明
よくある記事では，よくわかってもいないのに，
「データウェアサービス」なんて定義しますが，
説明できるのでしょうか．
そんな言葉覚えなくていいです．

「データベースではありません」
なんて言ってる方もいますけど，Amazonがデータベースとして定義しています

![スクリーンショット 2019-12-17 16.22.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543591/cd9ec2c5-d4f9-b091-a105-f39901218691.png)
ほらね



*Redshift*とは，
**データを蓄積して，分析してくれる**

これでOK.

##どんな時に使われるの？
**大量のデータを分析したい時**．
人間の目では判断できない，関連性なんかを教えてくれます．

なんで大量のデータ分析でRedshift使うんだ??

と思いませんか？

Redshiftでは並列でデータを処理しています．
なので超早い．

##Redshiftの構成
###クラスターの中に親と子が存在
クラスターっていうものをまず作ります．
(群れって意味です)
このクラスターで色々設定してRedshiftを作っていきます．
まず，最初にインプットしてほしいもの，

**リーダーノード
コンピューティングノード**

です

リーダーノードが親
コンピューティングノードが子
というイメージでまずはok
![fam.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543591/8b7f4600-b909-2993-cdd2-c04612911932.png)


リーダーノードはクラスターに1つしかありません．
こいつが子に命令をするんですね〜

コンピューティングノードはクラスターに複数持たせられます．
コンピューティングノードが多ければ多いほど，分析スピードは早くなります．

先ほど説明した並列処理ですね！！

![スクリーンショット 2019-12-17 16.25.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543591/d0e7f307-eec8-97cd-e3e9-afa6f70bb389.png)

複数のノードを持たせることが出来ます
これから説明しますが，DCなら1~32 , RA3なら1~128まで持たせられます．
多いと分析早いけど，お金がかかるよ！！

###ノードの種類
従来ではノードのタイプが二つありました．
**Dense Compute(DC)**...SSDを使って作成．500GB未満のデータを扱うときはこっち
**Dense Strage(DS)**... HDDを使って作成.容量が多いときはこっち．

SSDは内部にあるストレージでしたね
HDDは外部のUSBとか外付けのストレージです．

SSDの方が処理が早いけど容量に限界があります．
HDDは容量多いです．

しかし，12/03に発表があった「RA3」っていう新しいノードタイプが生まれたんですね〜

『RA3』の特長は、ストレージに「SSD Cache」と「S3」の2つのストレージ組み合わせた構成です。

具体的には、参照する頻繁が高いデータブロックはコンピュートノード本体のSSD Cacheにつねに保持して、更新・追加が生じたデータブロックはS3に保存します。

まだRA3使ってませんが，DSよりも10倍早いらしいですよ．


###列指向型のストレージ
Redshiftの特徴は，普通のDBは行指向型ですけど，列指向型なんです．
「は?」と思いました?

大丈夫!説明します!!

| name             | sex               |    age             |
|:-----------------|------------------:|:------------------:|
| A          |              m |        18       |
| B          |              w |        23       |
| C          |              m |        26       |
| D          |              m |        35       |
| E          |              w |        32       |
| F          |              w |        17       |

というテーブルがあります．
普通だと，
Aさん男性，18才というようなアクセスですが，
Redshiftの場合，
年齢は18才，23才, 26才，35才，32才，17才　がいます！！

というアクセスをするんですね！

つまり，平均は25才！！
データの分析に向いているんです！！

###ノードに障害がある場合
自動で検知して正常なノードと交換してくれます．
障害が発生したら別のノードで補ってくれるよ．(複数設定できましたよね！)

でも，1つしかノードを設定していない場合，復元不可能になります．
**実際に使うときは必ず2つ以上のノード**を使用すること!!


以上でRedshiftの説明は終わり．
これ読んで実際にクラスター作ってみましょう!!

ではでは
each を遅延評価しながら複数プロセスで並行処理

だいたい "[each を遅延評価しながら複数スレッドで並行処理](https://qiita.com/labocho/items/c8316e26aff8ace1baa1)" のプロセス版。

```ruby
require "thread"
require "thwait"

module MultiProcess
  DEFAULT_NUM_OF_WORKERS = 10

  module_function
  def each(enumerable, num_of_workers: DEFAULT_NUM_OF_WORKERS, &block)
    thwait = ThreadsWait.new

    enumerable.each do |item|
      # 子プロセスの数が上限に達していたら子プロセスの終了を待つ
      thwait.next_wait.join if thwait.threads.size >= num_of_workers

      # fork して block を実行
      cid = fork do
        block.call(item)
      end

      # 子プロセスの終了を待つスレッドを作成して ThreadsWait に登録
      thwait.join_nowait(
        Thread.new {
          _, s = Process.waitpid2(cid)
          raise "Worker process existed with #{s.exitstatus}" unless s.success?
        }
      )
    end

    # すべての子プロセスの終了を待つ
    thwait.all_waits(&:join)
    enumerable
  end
end
```


```ruby
# 下記のコードの実行は約 10 秒で完了する
MultiProcess.each(1..100) {|i|
  sleep 1
  puts [i, Process.pid].inspect
}
# [1, 19039]
# [2, 19040]
# [3, 19041]
# ...
# [98, 19136]
# [100, 19138]
# [99, 19137]
```
React Native の Text が上下の中央よりもズレて表示されてしまう問題

## 問題

Text にこのような style をあてると、Android で日本語フォントが切れて表示されてしまう。

```js
fontSize: 12,
lineHeight: 12,
```

（この場合、Text のコンテナの高さも 12 にしたかった。）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130756/621fd4ef-9b32-4d0d-d592-42358f09dadc.png)

## 解決

```js
fontSize: 12,
height: 12,
includeFontPadding: false,
textAlignVertical: 'center',
```

https://facebook.github.io/react-native/docs/text-style-props#includefontpadding
flake8でコードをチェック

[未来電子テクノロジー](https://www.miraidenshi-tech.jp/intern-content/program/)でインターンをしている[箕牧和廣](https://qiita.com/mimaki_kazuhiro)です。
今回はflake8について書いていこうと思います。

プログラミング初心者であるため、内容に誤りがあるかもしれません。
もし、誤りがあれば修正するのでどんどん指摘してください。

##flake8とは
flake8とはPythonの文法チェックツール。

##flake8の導入
実際に使ってみる。まずはインストール。

```sh:terminal
$ pip install flake8
```

以下のようにファイル名を指定してflake8を実行すると、コードチェックの結果が表示される。コマンド引数はファイル名ではなく、ディレクトリ名でも可。

```sh:terminal
$ flake8 test.py
test.py:1:1: F401 'sys' imported but unused
test.py:3:4: E222 multiple spaces after operator
test.py:4:7: E231 missing whitespace after ','
test.py:4:12: E202 whitespace before ']'
test.py:6:1: W293 blank line contains whitespace
test.py:6:1: W391 blank line at end of file
```
このように間違いを検出できる。
[UE4] OctotreeでUE4のソースコードを快適に読む

Unreal EngineのソースコードはGithubで公開されていますが、
複数のバージョンなどの違い等を見たい時にすべてのコードをダウンロードして閲覧するのは意外と手間です。
また、ローカルドライブの空き容量が必要になってしまいます。
そこでブラウザ上で全文検索やサクサク閲覧できるGithubのウェブページはソースコードを読むのに便利です。
今回はブラウザ上でIDEの様にサイドバーでツリー表示と選択を行うことができるOctotreeというChromeアドオンを紹介します。
![2019-12-17_16h36_42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363894/8fe293c7-d371-caab-9dc4-96ac2daf7903.png)

Octotreeを導入するとツリービューでファイルの選択が可能になるので、
以下GIFのようにリポジトリ内の構成をツリービューから辿るということが可能になり、
どこにいるかが分かりやすくなります。
![select0.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363894/2fd10018-52a3-3f3a-9f40-ef1e25d9a84d.gif)

Githubの機能にはなりますが、ブランチを変えてバージョンごとの違いを見たり、、、
![change.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363894/2d314f23-7daf-2e4e-1f83-129903809a87.gif)


リポジトリ内の全文検索も高速に行うことも可能です。
![search.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363894/616a898b-f68f-d784-90c2-fcd4a494615d.gif)



## インストール方法

Google Chromeに以下アドオンを追加します。
**Octotree - Chrome ウェブストア**
https://chrome.google.com/webstore/detail/octotree/bkhaagjahfmjljalopjnoealnfndnagc?hl=ja
![2019-12-17_15h46_13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363894/1b52a61b-89be-5910-8712-fb07bb1b7c5c.png)


## 設定方法
まず、Unreal Engineのソースコードを開くためにはEpicアカウントと
Githubアカウントを連携する必要があります。
**GitHub接続** https://www.unrealengine.com/ja/ue4-on-github

次にGithubのUnrealEngineリポジトリを開き右側に表示されるOctotreeのボタンをクリックすると、
以下のようなアクセストークンを求められます。
![token.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363894/5c443c9f-4327-0d87-d9d0-4d09d24f7d04.gif)


Generate New tokenをクリックしてトークン作成ページを表示します。
![2019-12-17_15h42_38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363894/e3c37c71-9e52-3b43-03df-188c5abd8685.png)

一番下のボタンをクリックすると生成が可能です。
![screencapture-github-settings-tokens-new-2019-12-17-15_50_37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363894/df23aca3-6e38-f988-11a1-c08321c98aef.png)

空欄にトークンを入力をして設定を完了します。
![2019-12-17_15h55_33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363894/55d4704b-2499-24dd-9a9b-041ad971e385.png)

以上の設定で使用できるようになります。ピン留めオプションを設定しておくと常に表示されて便利です。  
![2019-12-17_15h58_37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363894/a6352d7a-9736-6655-2705-e25d5709ed1b.png)

アクセストークンについて詳しく知りたい方は以下を参照ください。
**コマンドライン用の個人アクセストークンを作成する - GitHub ヘルプ** 
https://help.github.com/ja/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line

## さいごに
Githubを活用すると、複数バージョンを入れることによって発生するローカル容量の枯渇を防いだり、
比較的マシンパワーが必要な全文検索を非力なマシンでも行うことが可能です。
プラグインを使用することによってIDEに近い見た目で見ることができるので有効活用して快適にソースコードを読みましょう。
sshしようとしてIt is required that your private key files are NOT accessible by others. This private key will be ignored.が出た時の対応

こんなエラーが出た時の対処方法です。

```console
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for ‘/Users/XXX/.ssh/sample.pem’ are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "/Users/XXX/.ssh/sample.pem": bad permissions
ec2-user@XX.XXX.XXX.XX: Permission denied (publickey).
```

##対処法として

秘密鍵ファイルは他からアクセスできないことが必要と怒られているので、
permissionを変更してあげます。

```console
$sudo chmod 0600 sample.pem
```

これで無事sshすることが出来ました。
rubyを再インストール方法

**なぜ、version2.3.1を選んで書いているのかというと、2.3.1がなかなか入らなかったからです。**
`rbenv uninstall 2.3.1`
↓
`rbenv install 2.3.1`
↓
`re gem install bundler`
↓
`rebi`(reb install --path=vendor/bundle --binstubs=vendor/bin)
↓
`rm -rf vendor/` (-rfはコマンド のオプション)
↓
ここまでエラーなくうまく行けば下記のコマンド を実行:sparkles:
↓
`rebem`rebe middleman

**rubyのバージョン切り替えた後、ちゃんと毎回 rebiをする。**

`rebi`は(reb install --path=vendor/bundle --binstubs=vendor/bin)
知識の定着のためにしていること

この記事は、[TechTrain Advent Calendar 2019](https://qiita.com/advent-calendar/2019/techtrain-mentor)の15日目の記事です。

こんにちは、@yama_peterです。
普段は、某アプリのAndroidエンジニアをしてます。
※今回は、Androidの話はしません

## TL;DR
学生のうちに知識をさせる方法をある程度学んでください

## はじめに
最近、業務で「忘れてました」「そんなことありましたね」と聞く機会が増えてきました。
「エビングハウスの忘却曲線」によると、学習してなにもしなければ**1日で74%の情報は忘れる**と言われています。

| 時間 | 忘却度合 |
|:--|:--|
| 20分後 | 42%忘れる |
| 1時間後 | 56%忘れる |
| 1日後 | 74%忘れる |
| 1週間後 | 77%忘れる |
| 1か月後 | 79%忘れる |

http://nextglobaljungle.com/2008/12/post_373.php

初学者に多いですが、初学者に限った話ではありません。
しかし、業務だと忘れたでは済まない場合があります。

## なにをすれば定着するのか
よく記事で書かれているのが**「アウトプット」**だと思います。
アウトプットの仕方はいろいろあります。

開発に関することであれば以下のような方法があると思います。

* Qiitaに投稿する
* コードを書く
* メンターに確認する

どの方法にも言えることですが、簡単なことを書いたり、メンターに確認しただけだと意味がありません。
Qiitaへの投稿やコードを書く場合は、書く内容は**具体的**かつ、少し**苦労**したことを書くことが大事です。
メンターに確認する場合は、より**具体的**に確認することや、確認した上でまた**別のアウトプット**をすることが大事です。

## 最後に
知識が定着していない人より定着している人の方が役に立つ人であることは間違いないと思います。
**自分のスタイルにあったアウトプット**の方法を見つけて、知識を増やして定着させていってください！

質問の仕方でわからない場合は、TechTrainメンター@SuguruOoki さんの[初心者が「仕事で貢献する」ためにする質問の方法](https://qiita.com/SuguruOoki/items/657ff4fa24fe334a60aa)や以前書いた[質問する側が心がけること](https://qiita.com/yama_peter/items/3c4c9365fb38cc40c701)を参考にしてみてください！
Robot FrameworkでURLリストを読んでスクリーンショットをとりまくる

調べてもなかなか出てこなかったのでメモ。
（もっといい方法があればどなたか教えてください）

- URLリストを外部ファイル（list.tsv）から読み込んで
- それらに対してスクリーンショットを撮る
- フルページで撮る
- pythonの変数に行を突っ込んで回してます




```screen_shot.robot
*** Settings ***
Library    SeleniumLibrary
Variables   ./import.py

*** Keywords ***
Create Chrome Driver
	${options} =  Evaluate  sys.modules['selenium.webdriver'].ChromeOptions()  sys
	Call method  ${options}  add_argument    --headless
	Create webdriver    Chrome    chrome_options=${options}

*** Test Cases ***
キーワード
	Create Chrome Driver
    ${w} =    Execute JavaScript    return document.body.scrollWidth
    ${h} =    Execute JavaScript    return document.body.scrollHeight
    Set Window Size  ${w}  ${h}
    Set ScreenShot Directory    path=screenshot

    ${length}=  Get Length  ${conditions}
    :FOR    ${idx}  IN RANGE    ${length}
    \   Go To    @{urls}[${idx}]
    \   Capture Page Screenshot     filename=@{conditions}[${idx}].png
```

```import.py
import csv

with open('list.tsv') as f:
    reader = csv.reader(f, delimiter='\t')
    l = [row for row in reader]
    l_T = [list(x) for x in zip(*l)]
    conditions = l_T[0]
    urls = l_T[1]
```

```list.tsv
ねこ　https://www.google.com/search?q=%E3%81%AD%E3%81%93&tbm=isch
いぬ　https://www.google.com/search?q=%E3%81%84%E3%81%AC&tbm=isch
さる　https://www.google.com/search?q=%E3%81%95%E3%82%8B&tbm=isch
```
Hash#sliceでkeyによるフィルタリング

## やりたかったこと

タイトルの通り、Hashをキーの配列でフィルタリングしたかった

```ruby:want_to_do.rb
base_hash = {
  alpha: "α",
  beta: "β",
  gamma: "γ"
}

filters = %i[alpha gamma]

puts base_hash.somefunction filters # => { alpha: "α", gamma: "γ" }
```

## みつけた

```ruby:found_how_to_do.rb

# filters は * で展開してあげよう
base_hash.slice(*filters) # => { alpha: "α", gamma: "γ" }
```

## 結論

`filter`という言葉にとらわれ過ぎて、`Enumerable#filter`ばかり当たってしまった。検索は多角的にやろう。
FuelPHPのORMでリレーションの一括読み込みと遅延読み込みについて。クエリの発行回数は。

FuelPHPのORMはテーブル間のリレーションの設定ができますが、
**一括読み込み**と**遅延読み込み**というのがあって正確に理解して使えてなかったのでメモです。

- **一括読み込み**は、 一部のリレーションは、元の参照で全てフェッチされている。
- **遅延読み込み**は、 明示的にリレーションを要求するまでフェッチされない。

```
// 一括読み込み。join が使われます：
$post = Model_Post::find('all', array('related' => array('comments')));
// もしくは
$post = Model_Post::query()->related('comments')->get();
// これで $post->comments が使用可能です。これ以上のクエリは発生しません。
```

```
// もしくは、遅延読み込みを使用。joinは使われず、一度でも要求したときに改めてクエリが発生します。
// まず "post" を取得。join 無しの 1 クエリ。
$post = Model_Post::find('first');
// ここで (まだロードされていない) コメントを要求すると、 join 無しの別のクエリが自動的に実行されます。
$comments = $post->comments;
```

今回はサンプルなのでオブジェクトの中身までは記載しませんが、
実際にmodelを取得してvar_dumpなりで出力してみると、一括読み込みの方はオブジェクトにリレーションしたデータが紐づいていました。
遅延読み込みの場合は、参照した時にクエリが別途走りました。

全て一括でフェッチしておくのが正しいとも限らないですが、
relatedに関しては意識して使いたいものだなと思いました。
NucleoでSTLINKを切り取ることなくSTM32のVdd電圧を変える方法

#はじめに
Nucleoは通常はUSBからの5Vを、STLINKの基板を経由して、3.3Vに落としてSTM32のVdd電圧にしています。この電圧を変えるのは、Nucleo64のユーザーマニュアル(UM1724)を見ると、「STLINK部分を切り取るか、SB2とSB12を外すこと」と書いてあります。ハードウェア改造すると使い捨てになってしまうので、それなしに変更する方法を見つけました。

#外部からのVdd入力ピン
Nucleoを、STLINKを上、STM32を下、に置いたとき、JP6の右側がUSB 5Vを3.3Vに落としたレギュレーターの出力です。左側がSTM32のVddにつながっています。
![IMG_1259.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263486/9e166004-2947-3406-d95b-15307a4ea025.jpeg)

JP6を外して、左側に安定化電源をつなぎます。
![IMG_1266.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263486/cf1e3e42-d87d-8b6d-a1e2-c05d5d1e462d.jpeg)

#NRST
実は、このまま安定化電源を1.8Vにしても、STM32は起動しません。それは、STLINKがNRSTをLowに引っ張っているからです。本来はSB12を外すのですが、1kohm程度の抵抗でVddにプルアップして対応します。
![IMG_1260.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263486/b3f33a15-a64e-0055-7f8f-256a8de316ef.jpeg)

#電源投入
安定化電源を1.8Vにしてから、STLINKのUSBケーブルを指すと、STM32が起動します。動画では、あらかじめLチカのプログラムを書き込んでおき、LD2が弱弱しく点滅しているのが確認できます。
![IMG_1264.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263486/13804338-36e1-5645-3477-2f544d0a30d6.jpeg)
動画
https://twitter.com/kotetsu_yama/status/1206830992457007104

#おわりに
これで、STLINKを物理的に外さなくても、STM32の電源電圧を実験的に変えることができます。
Haskell初心者の備忘録

#はじめに
Haskell初心者が勉強しながら備忘録的に綴るページです
内容のミス等あると思われますのでご指摘がありましたらよろしくお願いします

#記事一覧
現在勉強中…

1:[Haskellの実行　まずはHello World](https://qiita.com/Nipper1357/items/4b4b9d60d8067fcf238c)
Pythonで負の数の余りを求めるとどうなる？

#目的
余りを求める計算はよく行う
例えばリストで余りを使えば要素数をオーバーしても最初に戻って参照できる

```python
array = ["a", "b", "c"]
index = 2

print(array[index])
#>> c

print(array[index+1])
#IndexError: list index out of range

print(array[(index+1)%3])
#>> a
```

ここで単純な疑問
__負の数の余りを求めたらどうなるんだろう__
数学としては余りは正の数になる
果たしてそうなるのか、もしくはエラーになるのか

#やってみた
負の数を3で割った余りを求めてみる

```python
print(-1%3)
#>> 2
print(-2%3)
#>> 1
print(-3%3)
#>> 0
print(-4%3)
#>> 2
print(-5%3)
#>> 1
print(-6%3)
#>> 0
```

全て正の数
(割られる数) = (割る数) * (商) + (余り)
を満たす余りになった
余りは割る数より小さいという法則も満たしている

#まとめ
予想通り計算結果は割る数の範囲でループした
使い道はなくはなさそう
ルートラボで今まで走ったルートを1つの日本地図にまとめる

Yahooのサービスであるルートラボが2020年3月に終了することになりました。
https://latlonglab.yahoo.co.jp/route/

サイクリング部としてこのサービスはとってもお世話になりました。
これまで走ったルートを1つに日本地図にまとめてみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404817/5e28b911-92b4-3f68-eb23-c03f1674f6c8.png)
https://souring001.github.io/routelab-map-generator/

能登半島、佐渡、伊豆大島、よかったなあ。

# 作り方
ルートラボで、ルート情報ファイルのGPXを一括ダウンロードする。
Leafletjsで日本地図を表示し、leaflet-gpxというプラグインでGPXファイルを描画する。
https://github.com/mpetazzoni/leaflet-gpx

# ソースコード
コードは以下に公開しています。
https://github.com/souring001/routelab-map-generator/blob/master/docs/index.html

# 終わりに
ルートラボのURLを載せるだけで日本地図に通ったルート全てを描画するようなサービスを作りたいなあ。
そしたらサイクリストみんなが使えるようになる。
スクロール量に応じて背景の色を変えたい

## スクロール量に応じて背景の色を変える方法

[デモページ](https://takuan423.github.io/memorandum/backgroundchange.html)
こんな風なのが作りたい人向けの記事です。
## サンプルコード
### HTML
```HTML
<div class="hogehoge" data-module="backgroundChange">
  <!-- ページのコンテンツ -->
</div>
```

ページのコンテンツ要素をラッピングする要素を用意します。
なんなら`body`でもいいです。

### CSS
```CSS
.hogehoge {
  width: 100%;
  height: 10000px;
  transition: background .4s ease-out;
}
```

CSSで要素の高さを指定します。
なんなら指定しなくても高さ持っていれば別にいいです。
大事なのは`background`に`transition`を指定することです。

### javascript
```javascript
export default class backgroundChange {
  constructor(elem) {
    this.elem = elem;
    this.elemHeight = this.elem.clientHeight;
    this.percentage = Math.round(this.elemHeight / 360);
    this.init();
  }
  init() {
    this.bindEvents();
  }
  bindEvents() {
    const bh = window.innerHeight;
    window.addEventListener('load', () => {
      this.setting(bh);
    });

    window.addEventListener('scroll', () => {
      this.setting(bh);
    });
  }
  setting(bh) {
    const offsetY = window.pageYOffset;
    const scrollBottom = bh + offsetY;
    const calc = Math.floor(scrollBottom / this.percentage);
    this.changeBackground(calc);
  }
  changeBackground(calc) {
    this.elem.style.backgroundColor = `hsl(${calc}, 100%, 50%)`;
  }
}

const elem = document.querySelector('[data-module="backgroundChange"]')

new backgroundChange(elem)
```

これでOKです。

## 解説

もう少し詳しく解説すると

```javascript
constructor(elem) {
  this.elem = elem;
  this.elemHeight = this.elem.clientHeight;
  this.percentage = Math.round(this.elemHeight / 360);
  this.init();
}
```

ここで、newするときに引数で指定した要素を受け取ります。
そして、その要素の高さを取得して、
さらにそれを360等分して、Math.round()で小数点以下を四捨五入します。

なぜ360等分しているか木になる方は、「HSLカラーチャート」でググってみてください。
円形のカラーチャートが出てくると思います。円、つまり360度。そういうことです。

```javascript
init() {
  this.bindEvents();
}
```

そしてイベンドバインドの関数を叩きます。

```javascript
bindEvents() {
  const bh = window.innerHeight;
  window.addEventListener('load', () => {
    this.setting(bh);
  });

  window.addEventListener('scroll', () => {
    this.setting(bh);
  });
}
```

`window.innerHeight`でブラウザの高さを取得します。
そして、ページロード時とスクロール時に、背景の色を変える準備用の関数を叩きます。
その時に引数で、ブラウザの高さを渡します。

```javascript
setting(bh) {
  const offsetY = window.pageYOffset; //垂直方向のスクロール量
  const scrollBottom = bh + offsetY; //ブラウザの高さ + 垂直方向のスクロール量
  const calc = Math.floor(scrollBottom / this.percentage); //ごにょごにょ計算してスクロールした割合出す
  this.changeBackground(calc);
}
```

ここがややこしいですが、ごにょごにょと計算して、
ページ全体のうちのどのくらいスクロールしたかを計算します。
そしてその計算した値を元に背景色を変える関数を叩きます。

```javascript
changeBackground(calc) {
  this.elem.style.backgroundColor = `hsl(${calc}, 100%, 50%)`;
}
```

いよいよ、newする時に受け取った要素の背景色を替えます。
上でごにょごにょ計算した値をHSL形式の色指定の第一引数に突っ込みます。

これで、スクロールするたびに色が変わるようになっているはずです。
オプショナル型ってなんだ

###煮る？似る？nil?
煮る？違う「nil」だ。

Swiftをしている人からしたら分かるが、初学者の僕にとっては鬼畜である。
０ではないの？nil入る可能性がある？
アンラップ？ダウンラップ？スーパークラス？

というようにワードが続々と登場してくる。
初学者の独学は難しいねぇ。
今回はオプショナル型について書いていく。

##オプショナル型
nilが使われるのはオプショナル型である。
！と？を使う事でオプショナル型だよ！と宣言をする事ができる。

色々調べると、nilというのはRubyなど他の言語にもあるようだ。
でもiOSだとnilに対する操作で、アプリが落ちるみたい。

そこで現れたのがオプショナル型だそう。
へー。

オプショナル型は、変数を作成する時に通常の値に対して、「空」の状態を表す変数の事。
うーん。

少し前にTwitterで
![nil.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546679/e82959df-3aa1-3ed4-f421-1b2f9a195ebf.jpeg)

この画像が分かりやすい！って回ってきた。

つまり、芯が残っている左が０で、右の芯ごとない状態が「空」つまりnilだ。

０と空の違いが確かに分かる！

けど、これをどう使うのかが微妙なんだよ。
でも、オプショナル型は、<b>変数</b>の宣言である事は理解したよ！

じゃあ使い方を調べよう！
と思ったら、有益すぎる記事を見つけてしまった。

https://qiita.com/maiki055/items/b24378a3707bd35a31a8

笑。
Hashmapを使って文字列にIDを振る。

何かの機能作ったとかじゃなくて申し訳ない。
きっと何かに使える！と思ってちょっとまとめてみました。
データの一覧をView側のフォームに使う場合とか。

```java

import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {

        // Map型のインスタンス生成。
        Map<Integer, String> map = new HashMap<>();
        String[] text = {"あ",
        "い",
        "う",
        "え",
        "お"};

        // 配列の要素数分mapに値を追加。その時、同時に番号(ID的な)を振る。
        for(int i = 0; i < text.length; i++){
            map.put(i, text[i]);
        }
        // mapを表示する。{key=value}の様に表示される。
        System.out.println("表示結果１＝" + map);
        
        // mapのvalueを取得しlist化。
        List<String> list = new ArrayList<>(map.values());
        System.out.println("表示結果２＝" + list);

        // mapのkeyを取得しlist化。
        List<Integer> list2 = new ArrayList<>(map.keySet());
        System.out.println("表示結果３＝" + list2);

    }
}

```

```console:表示結果

表示結果１＝{0=あ, 1=い, 2=う, 3=え, 4=お}
表示結果２＝[あ, い, う, え, お]
表示結果３＝[0, 1, 2, 3, 4]

```

## 補足
「keyからvalueを取り出す」といったのが主流らしいので補足します。
map.get(keyの番号)で表示できます。

```java
// keyを指定してvalueを表示
System.out.println("key1＝" + map.get(1));

```

```console:表示結果

key1=い

```
【中小企業のエージェントを選ぶ理由をフリーランスエンジニアに聞いてみた】

#こんにちは！:open_hands:

株式会社アイスタンダードの本橋です。:raised_hand:

今回はフリーランスエンジニアに有益な情報を提供させていただきます。

既に株式会社アイスタンダードの「at-engineer」
https://at-engineer.jp/
を利用している方は、

他のイケてるエンジニアの投稿を見て知識を蓄えてください。:pray:

##一般の考え

初めてフリーランスになった方、フリーランス経験の浅い方は大手のエージェントを使いがちです。

もちろん、「長い物には巻かれろ」という言葉があるように、

大手のエージェントを使えば、安心します。:relaxed:

しかし、大手のエージェントは登録量が半端ないです。

そして、フリーランスエンジニアの方へ担当をつけるために

企業は多種多様な営業マン（新卒含め）を大量に採用します。

大体30-40人のフリーランスエンジニアに対してエージェント1人って感じですかね。
もっと多いかもしれないです。:frowning2:

###---こっから本題---:point_up:
##【中小企業のエージェントのいいとこ】

中小企業のエージェントは登録数が少ないです。

よってエージェント1人当たりの担当フリーランスエンジニアが10-20と大手の半分くらいです。

湯水のようにフリーランスエンジニアの登録が増えれば、
エージェントだって注力するフリーランスエンジニアを選べます。

しかし、中小企業のエージェントは登録数が少ないので、
フリーランスエンジニアを選べません。

なので、フリーランスエンジニア一人ひとりに対して全力営業です。

そんなこんなで日々、中小企業のエージェントは営業力を鍛えるのです。

培った営業力、顧客層を駆使してフリーランスエンジニアの案件参画に結び付けるわけです。

営業力のあるエージェントは右から左へ人を流して終わりではありません。
顧客の情報を日々キャッチして、すぐにでも参画できるフリーランスエンジニアの登録を指くわえて待っているわけです。

どうせならハングリーなエージェントに対応してもらった方がいいでしょう。

で、登録と同時に顧客に提案し、すぐ面談の設定をします。

1. 登録
2. エージェント面談（希望条件など）
3. 客先面談（面談ていうより
4. 即日合格
5. 手続き（契約）
6. 2日後参画

上記な流れはイケてるエージェントだと1週間以内に行われます。
あ、僕です。:japanese_ogre:

###最後に:clap:

結局のところ、大手のエージェントにもイケてる営業はいますが、

確率でいえば中小企業の方が圧倒的に多いです。

なんでかって・・・？:alien:
企業も営業の採用もいればいいではなく、しっかり結果にコミットできるやつを採用するからです。:fist_tone5:
ほぼどこかで営業経験のある中途ですね。
だって仕事できなかったら会社傾いちゃいますもん。。。:skull:

ということで中小企業を選んだフリーランスエンジニアに聞くと

###「案件決まるまで早すぎ:thumbsup:」


とのことです。

ご愛読ありがとうございました。:lips:
【heroku】デプロイの方法、appの削除

#railsappのHerokuへのデプロイ時の設定方法

・Ruby 2,6,5
・Rails 5,2,2
・postgresql

##設定箇所
##1　Gemfile
Gemfileに group :production pgを追加　
sqllite3移動
→bundle install --without productionをコンソールで実行する


```
group :production do
       gem 'pg', '~>0.18.4' 
end　　
```

##2　config/datebase.yml下記に変更
config/datebase.ymlのproductionの箇所を変更

```config/datebase.yml
　　production:
 　 <<: *default
 　 adapter: postgresql
 　 encoding: unicode
```
##3  　config/environments/production.rbを変更

```config/environments/production.rb
config.assets.compile = false をtrueに変更
```
##4  　config/routes.rb
rootがあってるか確認

##.gitの設定
設定箇所の変更がすんだらgitの設定に入る

```
$ cd app
$ git init 
$ git add -A 
$ git commit -m "#"を実行
```
  add commitは変更がある都度実行していくと良い


##・railsアプリとherokuの関連付け
設定箇所の変更,gitの設定が終わったら

```
$ heroku login --interactive
heroku emali 
heroku password
```
これでまずherokuにログイン成功

次に

```
$ heroku create appの名前　→URLがでたら成功 エラーでたら名前が使われている
$ heroku create samplemyapp #例
```
##・最後にデプロイ
#####cd appにいることを確認して
```
＄ git push heroku master
＄ heroku run rails db:migrateを実行 #データベースの構築　これでひとまず終了。
$  heroku apps :info or $ heroku open ##URLが見れる
```
##おまけ　hekuroからappを削除するコマンド

```
$ heroku apps:destroy --app appの名前　#削除するかの確認で再度appの名前を入力
```
###変更した場合のgitの更新の例

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

##さいごに
まずはHerokuへのデプロイでのアプリ公開が1番簡単でおすすめです🤐
最低限押さえておきたい、IPv6でのネットマスクのお話

# はじめに

この記事は [IPv6 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/ipv6) の 18日目の記事として投稿しています。

# IPv6でのネットマスク(というか、ｐrefix長)のお話

## サーバ系で必要となるであろうIPv6でのネットマスク
IPv4だと、アドレス設計によっては /24 だったり、/29 だったりしたかと思いますが、サーバを扱う上では、基本的に

- /64

だけです。IPv4の時のように「そこにXX台ぶら下がる予定だから、ここは /29ね」みたいなことはないです。機器につけるIPv6アドレスはすべからく

2001:db8::cafe/64

こんな感じで、/64 固定です。他に扱うことがあるとすると、loopbackアドレスの /128 ぐらいですかね？(::1/128)

## ネットワーク系で必要となるであろうIPv6でのネットマスク

いままでは、基本的に「将来的に、このセグメントに何台の機器がつながるだろう？」とか考え、ネットマスクを切り詰めて（？）設計していたかと思いますが、/64固定、でOKです。

## ルータが、自分と対向の２台しかいないのに？！

もったいないおばけが出そうですが、メディアが Ethernetである場合は、/64 で問題ないですが、Point-to-Pointなメディアの場合は、懸念がありました[^1]。ということもあり、最近では /127[^2][^3]使えるようになったので、/127で設計してもいいかもね？

## 余談
default free zone で問題になっている /24 相当な経路は、IPv6では…… /48らしいよ[^4]



[^1]: point-to-point でピンと来ない方は、[JANOG22 忘れがちなIPv6のアドレス構成(PDF)](https://www.janog.gr.jp/meeting/janog22/program/day2/data/day2-1-j.pdf) を参照のこと。

[^2]: 昔はさておき、[rfc6164](https://tools.ietf.org/html/rfc6164) がサポートされてれば、なんの問題もないっす。

[^3]: [JANOG22 忘れがちなIPv6のアドレス構成(PDF)](https://www.janog.gr.jp/meeting/janog22/program/day2/data/day2-1-j.pdf) p.26 で触れられていた ‘use of /127 considered harmful’ [RFC3627] はRFC6547によって、廃止されています。

[^4]: [Internet Week 2018 2018年のインターネット運用動向(PDF)](https://www.nic.ad.jp/ja/materials/iw/2018/proceedings/d4/d4-yoshida.pdf) p.65
お笑い番組の情報をWebスクレイピングしてLINEで通知する

# 背景

![スクリーンショット 2019-12-17 15.24.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404817/cc507e5f-f4e6-0f78-7eed-ac6dd5b52c29.png)


お笑い番組の特番はとってもたくさんありますね！
しかし、特番であるために、突然放送されるので、見逃してしまいがちです。

うちはHDDで録画しているため、お笑いのジャンルを自動で録画してくれるような機能はありません。

大好きなお笑い番組を見逃した時はひたすら悲しくなっていました...。

そこで作ったのがこちら！

<img width="375" alt="IMG_3682.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404817/98c0d8fe-59da-8e69-fcb1-c679c8d300ef.jpeg">


毎朝6時にお笑い情報が僕の元のやってきます。
これで賞レースや特番を見逃すことはないでしょう。

# ソースコード
オープンソースで公開しています。
https://github.com/souring001/owarai-info

LINEだけでなくSlackでも使えます。

# Webスクレイピング
[Gガイド テレビ王国](https://tv.so-net.ne.jp/s/comedy)のお笑いジャンルから情報を取ってくることにしました。

# 通知
家にあるRaspberry Piから毎朝6時にプログラムを実行することで通知しています。

## LINEで通知
LINE Notifyでトークンを発行すれば、以下のコードで通知できます。
`message`に送信したいメッセージを入れます。

```py
line_notify_url = 'https://notify-api.line.me/api/notify'
line_notify_token = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'

headers = {"Authorization" : "Bearer "+ line_notify_token}
payload = {'message' :  message}

r = requests.post(line_notify_url, headers=headers, params=payload)
```

## Slackで通知

SlackのIncoming Webhookを使うことで、以下のコードで通知できます。
`text`に送信したいメッセージを入れます。

```py
slack_url = 'https://hooks.slack.com/services/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
slack = slackweb.Slack(url=slack_url)

slack.notify(text=text, username='owarai-info')
```


# 問題点
* 情報源であるGガイドの不具合のせいか、お笑い番組の情報が送られてこなかったことがあった。(エンタの神様を見逃した。)
* 毎朝6時にその日のお笑い番組情報をスクレイピングしているため、0時〜6時のお笑い番組の情報は送られてこない。(深夜帯に特番は少なく、毎週録画で対応しているため大丈夫)

# 終わりに
今年のM-1も楽しみですね〜！
12月22日(日)午後6時34分～ですよ！！！(SECCONと被って爆発する音)