OmniAICreator/Qiita-1.07M huggingface dataset:
【Swift4】UILabelをコードで生成して位置決めする時に気をつけること

忘備録です。
sizeToFit()の仕様で躓いて悩んだので、どういう感じでどう解決するに至ったのか、書いておきます。
　リファレンスにはaddSubViewの後にsizeToFitしろって書いてはありますが、この現象については書いてないですね…。


# 前提
- swift4.2,xcode10
- UILabelをコードで生成
- 高さ、幅を動的に計算して同じView内に配置
- UILabelの個数はデータによって変わり、確定していない
- 配置すると言っても前のものの下に配置する形

# やったこと
- viewDidLoad()で処理
- sizeToFit()
- labe.bound.size.heightで高さを取る
- 変数offsetに+=してy位置を指定する


```swift:ViewController.swift

    override func viewDidLoad() {
        super.viewDidLoad()

        (中略）

        for nLoop in 0 ... labelTextData.count - 1 {
            let label = UILabel()
            label.numberOfLines = 0
            // ラベルのフォントのオートシュリンクの設定
            label.adjustsFontForContentSizeCategory = true
            label.adjustsFontSizeToFitWidth = true
            label.minimumScaleFactor = 0.3
                    
            // font
            if let customFont = UIFont(name: "Chalkboard SE", size: 17) {
                label.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: customFont)
            } else {
                label.font = UIFont.preferredFont(forTextStyle: .body)
            }
            label.text = labelTextData[nLoop].1

            // viewにラベルを追加
            // constraintsよりも前に追加する必要があるらしい
            view.addSubview(label)
            // AutoLayoutとバッティングしないためFalse
            label.translatesAutoresizingMaskIntoConstraints = false
                    
            // constraints
            label.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.8).isActive = true
            label.sizeToFit()

            // 大本のViewとX軸中心合わせ
            label.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
            // Top Anchorは大本のViewに合わせる(オフセットでずらす。）
            label.topAnchor.constraint(equalTo: view.topAnchor, constant: offset).isActive = true
   
            offset += label.bounds.size.height
        }
    }
```

# 結果
- ラベルの内容は表示されるがheightで取れる値が合わずに重なる
- ラベルの内容によってずれる高さは変わってくる

# 迷走
- UIImageViewに画像突っ込んだらどうなるの？と試して爆死
    - CGRectでUIImageViewを設定したら…駄目
    - Constraintsの設定？…違う
    - UIImageをリサイズしてサイズを確定、Viewも同じサイズで成功
- Contsraintsの問題？違うっぽい
- sizeToFit()の位置の問題？元から位置はあってそう
    - text,font等を設定してからsizeToFit()でOK
- もうめんどくさいオフセットの値に足したれ！
    - 当たり前だけどもきれいには行かない
    - やっぱりちゃんと値を取れるようになろう…。
- UIImageの時のように先に大きさを指定したらどうかな
    - frameにCGRectでサイズ指定は可能
    - InterfaceBuilderだと先に小さいのが出てくるから小さく…駄目
    - 大きくするにしても横幅は決まってるから、高さを大きく…成功

# 結論

- label.frameにCGRectで先に矩形を指定し、その後sizeToFit()
    - heightの値を中に入るテキストよりも絶対に大きくなるように設定


```swift:
    // 一度大きく高さを設定してからSizetofitで小さく収めないと正確な値が出てこない
    label.frame = CGRect(x: 0 ,y: offset, width: screenWidth * 0.8, height: sceenHeight * 10)
```


まさかこんな仕様が隠れていたとは…。
会社とかで複数人でやってるならばうまくいかないとか話してれば情報共有で知ってる人からすぐ教えてもらえるケースな気がします。
"request entity too large" の対応方法（Express.js, AWS Lambda）

# 事象
AWS Lambda（Express.js）で引数有りの関数を呼び出すと、エラー"request entity too large"が発生。

# 原因
ミドルウェア"[body-parser](https://github.com/expressjs/body-parser)"で引数のサイズ制限が設定されているため。

>bodyParser.raw([options])
*（中略）*
Options
The text function takes an optional options object that may contain any of the following keys:
*（中略）*
limit
Controls the maximum request body size. If this is a number, then the value specifies the number of bytes; if it is a string, the value is passed to the bytes library for parsing. Defaults to '100kb'

# 対応方法
```app.ts
// 制限サイズを増やす
app.use(bodyParser.urlencoded({ limit:'50mb',extended: true }));

// jsonメソッドに対しても制限サイズを設定する
app.use(bodyParser.json({limit: "50mb"}));
```

# 感想
最初、AWS Lambdaの環境設定を疑ったが、全然違った。

# 参照
- [Express4でエラー「request entity too large」が発生する](https://qiita.com/PianoScoreJP/items/3fbcebc43ebf821074d8])
- [Error: request entity too large](https://stackoverflow.com/questions/19917401/error-request-entity-too-large)
全てのCIM Classを取得して出力

一部の名前空間は管理者としてアクセスする必要があるようです。

```powershell
# 全名前空間の再帰出力
function getAllNameSpace() {
Param([string]$ns = "root");
$r = @($ns);
(Get-CimInstance __NAMESPACE -Namespace $ns -ErrorAction Continue).Name|
?{$_}|
%{getAllNameSpace("$ns/$_")|%{$r += $_}};
return $r;
}
# 全名前空間の取得
getAllNameSpace|
# 各名前空間でのクラス情報を取得
%{(Get-CimInstance meta_class -Namespace $_ -ErrorAction Continue)}|
# テーブル型に整形出力
Format-Table CimClass -AutoSize -HideTableHeaders|
# "名前空間:クラス名" 形式の行ごとの文字列に書き出し
Out-String -Stream|
# 前後の空白文字を除去
%{$_.Trim()}|
# 空行を除去
?{$_}|
# 名前順にソート
Sort-Object
```
引数の削除(Remove Parameter)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/257568/fdaf5b9d-a029-52fa-35b6-44022684defa.png)


1つずつリファクタリング技法まとめ
個人的に簡単かつ取り入れ易いと思うものから

## 目的
すぐ引き出せるようにする

## 基本作業サイクル
- システムを動かして仕様を精査
- テストメソッドを作成
- テストの失敗を確認
- テストの成功を確認
- 小さい変更、随時テスト実行(パターン追加失敗確認->成功確認)
- 最後テスト実行
- 最後動作確認

## 引数の削除(Remove Parameter)とは
メソッド本体が引数を使わなくなり、引数を削除するもの
引数の追加の逆
 
## ポイント
- 必要じゃなくなったものは消す。
- インスタンス変数として扱うべきでないか検討する
- 同じシグネチャのメソッドが存在しないか確認する(同じように削除する必要がある可能性がある)

## 例

```
def setting(url, id, password, date, logger)
  @date = date
  @logger = logger
  login = {
    url: url,
    id: id,
    password: password
  }
end
```
　　　↓

```
def initialize(url, id, password, date, logger)
  @date = date
  @logger = logger
end

def setting(url, id, password)
  login = {
    url: url,
    id: id,
    password: password
  }
end
```

## 書籍情報
Jay Fields (著), Shane Harvie (著), Martin Fowler (著), Kent Beck (著),
長尾 高弘(訳), リファクタリング:Rubyエディション
https://amzn.to/2VlyWML

## 雑感
「引数の追加」と「引数の削除」と「引数オブジェクトの導入」は一度にまとめて行えそう
【Rails】１つの検索フォームで複数カラムをまたいで検索する方法

##検索フォームの実装は簡単
検索フォームは意外と簡単に実装出来ます。下記の記事など参考にすればすぐ出来ます。
・[railsで検索フォームを作ろう！！](https://qiita.com/yusuko/items/cff4e46aeafbc3beecf2)
・[Ruby on Rails 検索機能拡張 (railsチュートリアル)](https://qiita.com/mochikichi321/items/5c9630c5d87b47130942)
・[【開発メモ】Railsアプリに検索機能を実装する方法をわかりやすくまとめてみた。](https://freesworder.net/rails-search/)

##ここからが本題
上記の記事はいずれも１つのカラムに対して検索をかける方法です。
複数のカラムを１つの検索フォームだけで検索したい場合は下記のようにすれば出来ます。これも知っていれば簡単です。

```
適切なオブジェクト名.where(['検索したいカラム名 ? OR 検索したいカラム名 LIKE ? OR 検索したいカラム名 LIKE ?', "%#{search}%", "%#{search}%", "%#{search}%"])
```

検索したいカラムが３つある場合は、"%#{search}%"も３つつけましょう。そうすれば１つのフォームで複数カラムまたいで検索出来ます！
RubyMine-EAP を日本語化

# RubyMine-EAP
Ruby on Rails を勉強中です。ATOM を使っているのですが、評判のよい RubyMineに乗り換えを検討中です。無料で使うには、１ヶ月の体験版の他に、「EAP = Early Access Program」版があります。EAP版を乗り継いで行けば、長く使用できるとのことで（せこいですが...）、こちらを使ってみることにしました。

# 日本語化
RubyMineの日本語化については、こちらの記事を参照
RubyMine：Macで日本語対応
https://qiita.com/iwaseasahi/items/e59ac503373adf1a7f11

こちらの手順で、RubyMine（１ヶ月の試用版を含む）は問題なく日本語化できました。
この記事では日本語化ファイル「pleiades.jar」をターミナルで移動（mv）していますが、何も考えずフォルダからのドラッグ＆ドロップで移動させました。これが悲劇の原因になります。

# RubyMine-EAP が起動しなくなる
RubyMine-EAP を同じ手順で日本語化しようとすると、起動しなくなります。うんともすんとも言わなくなって、困ってしまいました。
RubyMine-EAP で「rubymine.vmoptions」を編集したのですが、RubyMine-EAP自体が立ち上がらなくなって、設定を戻せなくなってしまったのです。「rubymine.vmoptions」でファイル検索しても出てこないし、途方に暮れてしまいました...

# RubyMine-EAP の復旧
もう一台、Macがあって助かりました。２台目の Macで同じ手順をして、「rubymine.vmoptions」の場所は探しました。こんな所に隠れていました。
![snap_1224.png](https://qiita-image-store.s3.amazonaws.com/0/320718/7fd23820-c891-8ddb-2d07-0defa9a7f323.png)

追記した１行を削除して、RubyMine-EAP がまた起動するようになりました。
```rubymine.vmoptions
-javaagent:/Applications/RubyMine.app/Contents/plugins/jp.sourceforge.mergedoc.pleiades/pleiades.jar
```

# RubyMine-EAP を日本語化
なぜ起動しなくなったのでしょうか？　設定ファイルを見直して、考えること５分。
日本語化ファイルの参照場所が間違っていたのです。RubyMine-EAP はアプリケーション名が「RubyMine 201x.x EAP.app」になっています。したがって正しい参照位置は次のようになります。201x.x の部分は自分の環境に合わせてください。
```rubymine.vmoptions
-javaagent:/Applications/RubyMine 2019.1 EAP.app/Contents/plugins/jp.sourceforge.mergedoc.pleiades/pleiades.jar
```

初歩的なことなのですが、詰まってしまい時間を無駄にしてしました。同じ問題で困る人がいるかもしれないので情報共有いたします。
無限アラートはブラクラではない

_まずこの記事はChrome最新版に基づくものです。その他のブラウザの情報や検証結果などありましたらコメントいただけるとありがたいです。_

今回の**無限アラートがブラクラだとして、不安を煽るような記事が多数存在**しており、もちろんエンジニアなら簡単にわかることですが、その会社の影響なのかブラクラだと勘違いする人が自分の観測範囲に多くいたので、なぜブラクラではないのか**技術的な観点から検証**していきたいと思います。

まずブラクラ（ブラウザクラッシャー）は**広い意味で使われている**ので、齟齬が無いようにこの記事内での言葉通り**ブラクラはブラウザをクラッシュさせるものだと定義**します。実際にブラウザがクラッシュする他に**著しく不安定になったり、正規の方法で閉じれなくなるようなこともクラッシュに含め**、**ブラウザのバグに起因するものは除外**するとします。

無限アラートがブラクラではないことを検証する前に、ブラクラがどんな物なのか理解しやすいようにブラクラとされてきたものをいくつか見ていきましょう。比較するためにソースを載せますが、**実行する際は必ず自己責任で**お願いします。

## 実際のブラクラ

### 無限ループ

何もしないただの無限ループです。しかし何もしないというのは１回のループに時間がかからないことになり、短時間で**大量の繰り返しが発生し無限に繰り返されます**。あっという間にChromeが管理する**CPU使用率が100%近くになりました**。Chromeが不安定になりタブは閉じられませんしページの反応もありません。Chromeのタスクマネージャで実行したタブを強制終了することで終了できました。

```js
while (true);
```

JavaScriptでは非同期性を実現するために、１つの処理が終わってからキューにある次の処理を実行していくイベントループというシステムというものがあり、スクリプトの実行以外にも描画を含めたページ全体の処理がイベントループ上に実装されています。しかし無限ループは処理が永遠に終わらないので、イベントループ自体をブロックしてしまいます。

※ちなみに一時期はGIFアニメーションですら、無限ループによってブロックされていました。（今は確認できていません）

### 無限に新しいページを開く

無限に新しいページを開く処理です。上記の無限ループの問題点に加えて新しいページが開かれるというコストがあるかと思いきや、２回目以降の`window.open()`はChromeによってブロックされるので１つしか新しいページは開かれません。しかし無限ループが止まるわけではないので上記の問題は顕在です。

```jsx
while (true) window.open()
```

※ウィンドウが開かれていく状況を重視してあえて時間を開けているものもありましたね（今Chromeではどれも動きませんが...）

## 無限アラート

実際のブラクラを軽く見たところで、今回の無限アラートを見てみましょう。

`while (true)`と無限ループが入っていて、上記の無限ループの問題点を含むように一瞬思いますが、実際は`alert()`も**アラートが閉じられるまで処理がブロックされる**ので、**一回閉じるごとに１回しかループが発生しません**。閉じたときに一回だけループされますが、数十ミリ秒で連続して何百個も閉じれば変わってきますが、とても現実的ではないので**負荷という観点からしたら問題はなさそう**です。

```js
while (true) alert('!')
```

本題とは少しそれますが、ブラクラに続いて言われる問題として、アラートが絶え間なく表示されることが上げられるので、それについても見てみましょう。

確かに上に書いた通りアラートはページ全体の処理を止めてしまうのでページの操作ができなくなります。しかしChromeではアラートが表示されていても、ウィンドウや、URLバー、メニュー、戻るボタン、タブの×ボタンや、ショートカットまで、**ページ内以外は通常通り操作でき**、**タブの×ボタンから通常通りタブを閉じれます**。

## 終わりに

ということで、**無限アラートはブラウザをクラッシュさせませんし、操作に支障もきたしません**。**つまりブラクラではない**ことがわかりました。

最後に僕は**なにかある度に便乗してプログラムを有害だとしてユーザーの不安を煽り、世論をミスリードする記事を書く記者や、セキュリティソフト会社に反対**します！そしてそんな会社によってCoinhive事件の被害者にされたモロさんには健闘を祈ります。
ソフトウェア技術者のための英語習得法の案

この記事は[「Hastega @ Lonestar ElixirConf 2019」]
(https://zacky1972.github.io/blog/2019/03/02/Hastega.html) から一部転載しております)

私にとって劇的に効果的だった英語習得方法をご紹介します。

1. フォニックス
2. 多読
3. 海外技術交流のSlack

番号は取り組む順番です。

1,2 については，既存のリソースがいろいろあるので，活用しましょう。この2つを教えてくれるトレーナーが身近にいると，本当に助かります！ 私の場合は身近に相談できる人がいたのが幸いでした。

3については，[「parcel に Pull Request を送って merge されるまでの顛末記〜生まれてはじめて国際的に OSS への貢献をしてみたら，とても歓待された」](https://qiita.com/zacky1972/items/0ce05454b67506edc634)に経緯を書いています。(Shawn は元気かな。。。parcel Slack から Shawn が姿を消して以来，parcel からすっかり遠のいてしまいました。。。)

ソフトウェア技術者の皆さんには，お気に入りの OSS について，今時はだいたい Slack があるんじゃないかと思うので，join して commit することを強くオススメします！ 英語だけでなく，技術力も高まります！

コツは，英作文するときに，できるだけ時間をかけないで，自分の語彙力の範囲でベストを尽くして平易に説明することです。

書き終わった後で，自分の書いた英文法を見直し，人の書いた文章から文法や語彙を学び，英英辞典やシソーラスを使って単語やフレーズの語彙力を広げるふりかえりをしましょう。さらにフォニックスの要領で，一連のチャットをできれば大きな声で読み上げましょう。そうすると，reading, writing, listening, speaking の4技能が，自然と鍛えられます。

私はこれから Medium (英語版)と arXiv での発信を頑張ります。慣れてきたら英語プレゼンテーションを作って，YouTube 発信もしてみたい。私がこういうときにいつもやっている「素振り」です。

あと，日本語を英語に「逐語訳」しようと思わないほうがいいです。英語話者には英語話者に向けた説明のしかたで，一から説明を考えたほうが伝わります。

けっきょくのところ，外国語でのコミュニケーションで大事なのは，表面的な外国語能力だけでなく，自分や相手の文化や背景をどれだけ理解しているかだと思います。普段から，文化について教養を身につけることが，とても大事です。自分の興味の赴くまま，読書をしましょう。もちろん洋書で読めると良いのですが，和書でも構いません。そして，外国人相手に日本や各国の文化や歴史，哲学といったことを説明するつもりで，英作文して読み上げてみるといいでしょう。たとえば，オタク趣味のある人は，オタク文化について英語で語ってみると良いのです。技術文書だけでなく，趣味の話も Medium が良いですね。
Reactで実装する虫眼鏡レンズ

## はじめに
いいライブラリがなかったので、Reactで虫眼鏡のような拡大鏡をパワーで実装してみましたというパワー系の記事です

## ポイント
ポイントはhoverした時点で、imageタグの`opacity`を０にし、`background-image`を拡大していくことで拡大鏡を実装しています。
マウスカーソルの位置を取得して、その値に応じて`transform-origin`と`background-position`を変えていきます。

## デモンストレーション
![magnifying_glass.mov.gif](https://qiita-image-store.s3.amazonaws.com/0/265344/10eb61a1-156f-af77-39e3-0bc1578ee3a4.gif)


## ソースコード
```javascript:JS
const imageUrl = 'http://img.kb-cdn.com/imgviewer/NVpIM2ptOHhYRzVmUk5rM1NrNlFxYVV6enV4aGk2UFRJMmxPckdDUUVNYmF1RnpSNUZYSGVySnNpclp0dGpMT2xQcndrSmo1U0dxdHR4WmNjZHZoM2RKUmpwbktBZ0E5eDFOd0I0RFdsNE1XbS9NbE1QWFMxa2JCaVVDRzdNMUtNWHcrWGkxdjdUQ2Jya25ZZ2t4Z2M5MEM3MGdZUGwvTEx3RHRScVhBdzM2QjFYNVNHQ2trNDhnWUFlelBZU2Jr?square=0'

class ZoomImage extends React.Component {
  state = {
    backgroundImage: `url(${imageUrl})`,
    backgroundPosition: '0% 0%',
    transformOrigin: '50% 50%',
    transform: 'scale(1)',
  };

  handleMouseMove = event => {
    const {
      left,
      top,
      width,
      height,
    } = event.currentTarget.getBoundingClientRect();
    const x = ((event.pageX - left) / width) * 100;
    const y = ((event.pageY - top) / height) * 100;
    
    this.setState({
      ...this.state,
      transformOrigin: `${x}% ${y}%`,
      backgroundPosition: `${x}% ${y}%`,
    });
  };

  handleMouseOver = () => {
    this.setState({ ...this.state, transform: 'scale(2.5)' });
  };

  handleMouseLeave = () => {
    this.setState({ ...this.state, transform: 'scale(1)' });
  };

  render = () => {
    return (
      <div className="zoomImgContainer">
        <div
          onMouseMove={this.handleMouseMove}
          onMouseOver={this.handleMouseOver}
          onMouseLeave={this.handleMouseLeave}
          style={this.state}
          className="zoomImgSection"
        >
          <img
            className="zoomImg"
            src={`${imageUrl}`}
            alt="画像がありません"
          />
        </div>
      </div>
    );
  };
}

React.render(<ZoomImage />, document.getElementById('app'));
```

```css:CSS(Stylus)
.zoomImgContainer
  overflow hidden
  width 416px
  height 416px
  margin 0 auto

.zoomImgSection
  background-repeat no-repeat

.zoomImgContainer:hover
  .zoomImg
    opacity 0

.zoomImg
  display block
  width 100%
  pointer-events none
```

```html:HTML
<div id="app"></app>
```

## CodePen
<p class="codepen" data-height="265" data-theme-id="0" data-default-tab="js,result" data-user="kazukiii" data-slug-hash="VRKGJq" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="React at CodePen">
  <span>See the Pen <a href="https://codepen.io/kazukiii/pen/VRKGJq/">
  React at CodePen</a> by kazukiii (<a href="https://codepen.io/kazukiii">@kazukiii</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

以上です。
twitter APIで遊んでみる #4(形態素解析してみる(MeCabの環境作り))

## 前回までのお話
[twitter APIで遊んでみる #1(環境作り)](https://qiita.com/tomozo6/items/747036c49a8b6bca49e4)
[twitter APIで遊んでみる #2(ユーザータイムラインの取得)](https://qiita.com/tomozo6/items/18ce99726ec9af168faf)
[twitter APIで遊んでみる #3(検索結果の取得)](https://qiita.com/tomozo6/items/d7fac0f942f3c4c66daf)

## はじめに
`twitterAPI`でいろいろなツイートを収集できるようになったので、収集したデータをもとに`形態素解析`をしてみようと思います。形態素解析には`MeCab`という解析エンジンが有名らしいので使ってみます。

※今回の話にはtwitterAPIは全くでてきませんのであしからず…

##環境作り
前回までの環境作りは実施済みのうえで、以下を実施します。

```bash

# yumからMeCabをインストールできるようにするため，Groonga リポジトリを追加
sudo rpm -ivh http://packages.groonga.org/centos/groonga-release-1.1.0-1.noarch.rpm

# MeCabのインストールする．
sudo yum install mecab mecab-devel mecab-ipadic mecab-ipadic-utf8
```
これで`MeCab`がコマンドラインから使えます。まだこの状態だとpythonからはMeCabを使用できませんが、それは次回実施することにします。

## MeCabで遊んでみる
コマンドラインで`mecab`と打つと入力待ちになるので、適当に文章を入力してみます。

```bash
root@localhost:~$ mecab
昨日はモスバーガーを食べたので、 今日はマックを食べたいですね。
昨日    名詞,副詞可能,*,*,*,*,昨日,キノウ,キノー
は      助詞,係助詞,*,*,*,*,は,ハ,ワ
モスバーガー    名詞,一般,*,*,*,*,*
を      助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
食べ    動詞,自立,*,*,一段,連用形,食べる,タベ,タベ
た      助動詞,*,*,*,特殊・タ,基本形,た,タ,タ
の      助詞,連体化,*,*,*,*,の,ノ,ノ
今日    名詞,副詞可能,*,*,*,*,今日,キョウ,キョー
は      助詞,係助詞,*,*,*,*,は,ハ,ワ
マック  名詞,固有名詞,一般,*,*,*,マック,マック,マック
を      助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
食べ    動詞,自立,*,*,一段,連用形,食べる,タベ,タベ
たい    助動詞,*,*,*,特殊・タイ,基本形,たい,タイ,タイ
です    助動詞,*,*,*,特殊・デス,基本形,です,デス,デス
ね      助詞,終助詞,*,*,*,*,ね,ネ,ネ
。      記号,句点,*,*,*,*,。,。,。
EOS
```
MeCabすげ～！

更に`-Owakati`オプションをつけると、品詞などの情報が無く単に文が形態素で区切られた形で出力されます。これを`分かち書き`と言うそうです。読み方はワカチガキでいいのかな?

```bash
root@localhost:twitter$ mecab -Owakati
昨日はモスバーガーを食べたので、 今日はマックを食べたいですね。
昨日 は モスバーガー を 食べ た ので 、 今日 は マック を 食べ たい です ね 。
```


## 終わりに
とりあえず`MeCab`が使えるようになりました。次回は`python`から`MeCab`を使ってみようと思います。
GAS初心者が抑えるべきポイント徹底解説！

今回作成したのはタイトルにある通り、「GAS初心者が抑えるべきポイント徹底解説！」です！
今までいくつかに分けて書いていた記事をまとめる時間を作ったので、改めてまとめてみました。
https://bzbot.work/

##紹介記事
https://bzbot.work/2019/03/07/gas-firststep/


![image.png](https://qiita-image-store.s3.amazonaws.com/0/363116/707561f8-fea0-1548-9639-24c00d749a8d.png)

##1.GASとは
Googleが提供してるスクリプト『Google Apps Script』の略です。
このGASというスクリプトはGoogleが提供しているサービス（スプレッドシート等）をクラウド上で実行することで操作できるサービスを指します。

利用にお金は一切かからずGoogleアカウントがあれば無料で利用できるため、プログラマーを目指す初心者はまず学んで損はないです。
※GASとJavaScriptはイコールではありません!


##2.GASのルール
GASは処理の時間が6分を超える事ができません。理由は単純にGoogle利用サービスを共通して使うクラウド上のリソースでで動くスクリプトのため、一人特定の重たい処理が実行されないように、6分で処理が終了するようになってます。

##3.記述エディタ表示
GASを記述するスクリプトエディタを表示する方法です。エディタを表示する方法はスプレッドシートやGoogleFormサービスの様々なところにあるので、用途ごとに使い分ければOKです。

まず、GoogleDriveの画面から『新規』をクリックします。
すると、新規追加するべき項目の候補（フォルダやアップロード）が表示されるので、『その他』の中の『アプリ通知』をクリックします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/363116/e48d5d58-9f38-f768-b767-8be95587a4f4.png)
ドライブにアプリを追加が表示されるので、『+ 接続』をクリックして、Drive上に追加します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/363116/3a7fab0b-f3f2-d3ac-e21b-d6a04f922926.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/363116/adb4db7b-c2de-4570-2ea3-394d1541d5c4.png)


4.コードの実行
これから実際にコードを書いて進めますが、書いた処理を実行する方法が記載されていなかったので、記載します。
虫のマークの横に『function xxxxx』に記載されている『xxxxx』がプルダウンで表示されるので、実行したい処理を選択します。

それ以外にも『 https://bzbot.work/ 』紹介しているので、ぜひみてみてください😄
無視してはいけないエンジニアの健康管理


健康とは、病気でないとか、弱っていないということではなく、肉体的にも、精神的にも、そして社会的にも、すべてが満たされた状態にあることをいいます。（日本WHO協会訳）

肉体的にも精神的にも満たされるにはどうすればよいかを健康に生きていくためには考える必要があります。

人間が精神的に満足するためには一般的には２つの行為があると言われています。

創造的行為　・・・何かを作ったりすること。
消費活動　　・・・何か買ったり、体験したりすること。

エンンジニアとしては作ったものが世の中で使用されたりすることに高い満足を感じはずです。
そのため、自分の裁量が著しく低い仕事などは健康からは遠ざかったいくんですよね。。

肉体的に健康になるためには、私は湯治をおすすめします。週の２、３回は近くの温泉のような施設に行って体を温めています。

新しいものを産みだし、なおかつ自分の健康も向上させるエンジニアはどの時代でも生きていけるんだろうと思います。
Rubyのあれこれ

# if分でエラー出た話

C言語と一緒とか書いたけど
これでエラーがでた

```
# まぁC言語と一緒
if score > 80
  puts "good"
else if score > 20
  puts "good!"
else
  puts "so...daiso.."
end
```

エラーの意味は読み取ったけど、どこも可笑しくないよな！？
って思ってた
✖　else if
〇　els if

慣れって怖いよねってお話です
[Truffle]コントラクトのイベントをテストする

Dappのテストを書いているときにイベントのテスト方法が分からなかったので、調べてみました。
結果的には`truffle-assertions`という外部ライブラリを使うことで何とかできました。ライブラリなしで簡単にできる方法は見つかりませんでした。教えて下さい。

## コントラクト
簡単なルーレットアプリを作りました。
0~36までの番号があって、数字が当たったら掛け金の36倍もらえて、色が当たったら掛け金の2倍がもらえるやつです。
コントラクト自体は単純なのでコードは説明文だけ入れておきます。

```javascript:roulette.sol

// _betは掛け金、 _randNumはルーレットが止まった数字です。
function judgeResult(uint8 _bet, uint8 _randNum) public payable{
        
        if(数字にベットした時){
            _betと_randNumが同じだったら36倍の返金
            違かったら掛け金没収
        }else if(色か偶数、奇数にベットした時){
            偶数に賭けていて_randNumが偶数だったら2倍の返金（色とか奇数の場合も）
            違かったら賭金没収
        }else if (列か1~12とかにベットした場合)
           列に賭けていて_randNumがその列だったら3倍の返金（他の条件も）
           違かったら賭金没収
        }
        // 結果をブラウザに表示するためにイベントでルーレットがどこに止まったかと、返金額（もしくは没収）をemitします。
        emit JudgeResult(resultNum, returnAmount);
    }
```
## truffle-assertionsの導入
[公式チュートリアル](https://kalis.me/check-events-solidity-smart-contract-test-truffle/)で説明されている通りに導入します。
`npm install --save-dev chai truffle-assertions`

chaiは使わなくても私のテストでは問題ありませんでしたが、この辺はよく分からないのでとりあえず入れときました。


## テスト
数字が当たったら、ちゃんと掛け金の36倍が返ってくることを確認したいので、下記の様に書きました。

```javascript:TestRoulette.js

var Roulette = artifacts.require("Roulette");
const assert = require("chai").assert;
const truffleAssert = require('truffle-assertions');

contract("RouletteTest", function(accounts){
  
    it("should be possible to win and get ether (36times)", function(){
        var rouletteInstance;
        return Roulette.new({from: accounts[0], value: web3.utils.toWei("1", "ether")}).then(function(instance){
            rouletteInstance = instance;
            return rouletteInstance.judgeResult(5, 5, {value: web3.utils.toWei("0.01", "ether")});
        }).then((result) => {
            //ファンクションを呼び出したときに発火されるJudgeResultイベントで賭金の36倍がリターンされているか確認する。
            truffleAssert.eventEmitted(result, 'JudgeResult', (ev) => {
                return ev.returnAmount == web3.utils.toWei("0.36", "ether")
            }, 'Contract should return 36 times as much as bet');
        }).catch(err => {
            console.log(err);
        })
    });
}

```

`ev.returnAmount == web3.utils.toWei("0.36", "ether")`で厳密等価演算子（===）を使うとテストが通りません。これは、ev.returnAmountがbig numberオブジェクトで、web3.utils.toWei("0.36", "ether")がstring型だからです。

## 参考
https://github.com/rkalis/truffle-assertions
kubernetesのeventをSlackに通知する

## 対象

- kubernetesのeventが大好き
- Slack中毒

## 要約
ツール作った
https://github.com/buildsville/kube-event-watcher

## 経緯

kubernetesのeventには、クラスタで起こったイベントや、<a href="https://github.com/kubernetes/node-problem-detector">node-problem-detector</a>が検出したものなどが流れています。
トラブル時のデバッグに役立つような情報がさりげなく流れてたりするのですが、一定時間（デフォルト1h）経つと消えたり、`kubectl get ev`などで見ないといけなかったり（+見やすいようにフィルタしたり整形したかったり）微妙に取り回しにくいと感じていました。

そこでこれをいい感じにハンドリングできるよさげなツールがないかと探したところ、

https://github.com/bitnami-labs/kubewatch
これはresourceの変更を通知するものだから今回の目的とは違う…

https://github.com/GoogleCloudPlatform/k8s-stackdriver/tree/master/event-exporter/
まさにこういうのが欲しかった、が…
`Event exporter exports only to Stackdriver.`
とのことで、現状AWSオンリーの私には非情なツールでした。
というかAWSとかGCPとかじゃなくてSlackと連携したいんす。

で、結局見当たらなかったので作りました。

## 工作

https://github.com/buildsville/kube-event-watcher

こんな感じで通知されます
<img src="https://i.imgur.com/aZ7CbfT.jpg">

実際に使ってますが、結構いい感じに役立っています。
使い方はREADMEに書いたので全部なのでここでは触れませんが、使ってみた感想やらを書いてみます。

- 全部受け取ると相当量が多い
    - __楽しいのはほんの最初だけ__
    - podひとつdeployするだけで5個6個と通知が来る…
    - configでしっかりフィルタリングしよう
- 重要度が恐ろしくピンキリ
    - WarningとNormalがあるし当然だが
    - これもconfigで通知するチャンネルを割り振られるようにした
- countをprometheusのmetricsとして出してみたが油断すると描画が重い
    - メトリクスとしてそれほど重要な項目にはならなそうだけど、もし使うならpromQLできちんと制御するしか
- 同じeventが短時間にドバドバ出るやつがある
    - 例えばNodeを増やす時に立ち上がるのを待ってる間、 `FailedScheduling` がすごいたくさん出る
    - eventのcreateだけを通知するようにすれば最初の1回だけ通知されるが、当然通知してほしいupdateも通知されなくなる
        - kube-apiserverのflag `--event-ttl` を短めに調整するなどと組み合わせていい感じにチューニングするか
        - 気になったら都度configを細かく設定してやるか
- 後からeventの流れを追いたい時にslackだとちょっと厳しい
    - のでCloudwatchLogsにも出せるようにした
- 私が知らないだけでそもそもこんなもの必要がないイケてるeventのハンドリング方法があるんじゃないか

結局こういうのって見える所に流れてこないとなかなか見ないものなんですよね。
今回は以上です。

## 追記
あった…
https://github.com/ultimateboy/slack8s
BottomNavigationViewをiOSのTabBarっぽくする

## 概要
MaterialDesignから提供されているBottomNavigationViewを用いることでiOSのTabBarのような下タブのナビゲーションを作成することが容易に可能になりました．
そこでiOSライクにAndroidでも下タブのアプリを開発してやるぜー！と思っていると選択範囲しかアイテム名が表示されなかったりとBottomNavigationView **独特のクセ**が目立ちました．
もちろんこれがMaterialDesignガイドラインが示している解だとはわかっているものの下タブといえばiOSのアレをどうしても想像してしまうため**クセ**は気になります．
この記事ではそれらの**クセ**を ~~完全に断ち切って~~消してiOSライクな下タブを目指します

## アイテムの色を選択状態によって変える
リソースファイルに`color`フォルダなどを作成し以下のファイルを追加します．
選択・非選択時の色は各自変えてください．
選択状態の色がプライマリーカラーにする場合は以下の操作は不要で一番下の`checked`に`true`をセットしてやるだけで可能です．

```nav_color.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_checked="true" android:color="@color/colorPrimary" />
    <item android:state_checked="false" android:color="@android:color/darker_gray"/>
</selector>
```

次に`BottomNavigationView`が記述されているレイアウトファイルに以下の文を追加します

```activity_main.xml
app:itemIconTint="@color/nav_color"
app:itemTextColor="@color/nav_color"
```

最後にコード上から選択時に選択状態を直接変更すれば，選択に合わせてアイテムの色を変更できます．

```MainActivity.java
menuItem.setChecked(true);
```

## アイテムの名前を常に表示させる
デフォルトの設定ではアイテム数が増えるとアイテムの名前は**選択状態**のものだけが表示されていて，常時表示にはなっていません．
これを常時表示にするにはBottomNavigationViewに以下のパラメータを指定することで解決できます．

```activity_main.xml
app:labelVisibilityMode="labeled"
```
<img src="https://qiita-image-store.s3.amazonaws.com/0/82263/1729e6dd-f20a-11ff-fb26-5158af98ffc4.png" width="300">


## 選択時のアイコン拡大アニメーションを無効化

このアニメーションは選択・非選択の状態においてアイテム内のアイコン・テキストの大きさが変動するために起きています．そもそも標準のフォントサイズは若干大きいのでiOSと同じ`10sp`に統一します．
`dimes.xml`に以下の文を追加します．

```dimes.xml
<dimen name="design_bottom_navigation_text_size" tools:override="true">10sp</dimen>
<dimen name="design_bottom_navigation_active_text_size" tools:override="true">10sp</dimen>
```
これで選択・非選択でも文字の大きさが固定され選択中のアイテムが大きくなるアニメーションなどは起こらなくなります．
<img src="https://qiita-image-store.s3.amazonaws.com/0/82263/eef7effc-371a-3eee-cd76-9d82279107ad.png" width="300">


## BottomNavigationViewが手前に来るのを防ぐ

どういうわけかデフォルトではBottomNavigationViewは画面下に固定されている状態ではなく，EditText時などにはFloatingActionButtonの様にNavigationViewごとキーボード上に浮上してきます．
それを防ぐのが以下のコードです．

```AndroidManifest.xml
<activity android:name=".MainActivity"
          android:windowSoftInputMode="adjustPan"></activity>
```
ManifestファイルのBottomNavigationViewが入っているActivityの部分をこのように書き換えることで，BottomViewNavigationが文章編集時でも所定の位置にいてくれます．
水上ドローン作りたい7、配線

# 内部の配線について
Rasberrry PI本体はボートに搭載しました。次は各コンポーネントを結ぶ配線が必要になります。最初はジャンパワイヤを一本一本つなげて対処していたのですが、すぐにぐちゃぐちゃになってしまい収集がつかなくなります。そのため配線にコネクタをつないで機能毎に纏めました。こういうのをハーネスと言うそうです。
## ハーネスの作成
ハーネスの製作にはケーブル、コネクター、工具が必要です。
### ケーブル
#### ケーブルの規格
ケーブルの太さに規格があり、AWG(アメリカ規格)、SQ(JIS規格)の2つがあります。AWGの方が一般的らしいのでAWGで話を進めます。
#### ケーブルの太さ
ケーブルの太さは規格化されていて(AWG1～AWG40)、数字が小さい方が太くて流せる電流が大きいです。この辺は下記のサイトに纏めれています。
[バッテリースペース AWG 導線のサイズと許容電流について](https://www.batteryspace.jp/html/page28.html)

今回は1.5A流せれば十分なので、AWG27以下であれば対応する事になります。しかしあまり細すぎるとコネクターを取り付けづらいので、少し太めのAWG24を選択しました。買ったのはこれです。
[協和ハーモネット UL耐熱ビニル絶縁電線 黒白赤黄緑青茶 各2m UL1007 AWG24 2m <7>](https://www.amazon.co.jp/dp/B010SBSX4K/)
#### ケーブルの色
電子工作のケーブル色に決まりがあるか調べたのですが、特に無いそうです。電源の＋側が赤で、マイナス側が黒にするのが慣例のようです。
### コネクタ
ケーブル終端に付けるコネクタはQIコネクタにしました。Rasberry PIのGPIOピンに直接さす事が出来ます。
[【610個入】2.54mm ピッチ 雌ピン 圧着 ハウジング コネクタ ジャンパーワイヤケーブル 雄/雌ピンコネクタキット](https://www.amazon.co.jp/gp/product/B076M2YDM1/)
### 工具
[エンジニア 精密圧着ペンチ オープンバレル端子用 PA-09](https://www.amazon.co.jp/gp/product/B002AVVO7K/)
### コネクタの取り付け方法
以下のページを参考にして取り組みました
[デジット 【Tips】電子工作でよく使う『QIコネクタ』の圧着方法](http://blog.digit-parts.com/archives/51796900.html)
## 配線の整理
コネクター作成前に図に落としました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/359316/6b197163-0d91-c8c6-8a92-fcc00904a924.png)
解りずらいですね(苦笑)。自分の作業の役には立ったのでいいのですが、こういうのを綺麗に書ける人が羨ましい。

作ったのがこれです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/359316/bbb01583-960c-b006-f9e6-68d70dda8d34.png)

これを作ったことによって、大幅に配線の見通しが良くなりました。
トイレセンサを作ってみた: プロトタイプ編

## 目次

* プロトタイプ編（本記事）
* ハードウェア編
* 3Dモデル編
* ファームウェア編
* Webサービス編
* Slackボット編

## 1. 背景と概要（各記事共通）

筆者がお伺いしている企業は成長まっただ中の企業で、どんどんメンバーが増えていっています。
しかし、現在のビルには1フロアにつきトイレが1つがなく、トイレに行っても「使用中」の事が増えてきました。特に、昼食後のトイレの稼働率の高さときたら！

そこで、よくある感じの「トイレセンサ」を作ってみました。このシステムは、以下の4つの要素で構成されています。

* トイレに設置し、トイレの使用状況をネットワークに送信する「トイレセンサ」
* トイレに向かう通路の途中に設置し、LEDでトイレの使用状況を知らせる「トイレインジケータ」
* Webブラウザからトイレの使用状況を知ることができる「Webアプリ」
* 「トイレセンサ」の情報を取得して判断し、トイレインジケータ、Webアプリに配信する「コントローラ」

## 2. プロトタイピング

まずは簡単にプロトタイプを作成し、実現可能性の検討を行いました。結論から言えば、問題なくトイレの使用状況を検出できました。

今回、「トイレが使用中である」ことの検出には、光センサを用いました。使用者によってトイレの照明が灯されていれば「使用中」と判断します。
ちなみに、完成版では焦電センサ（人感センサ）も併用しています。

また、状態表示器としてマイコン内蔵フルカラーLEDを用いました。

### 2.1. 回路図

とても雑ですが、プロトタイプの回路図は以下の通りです。

![DSC_6018.jpg](https://qiita-image-store.s3.amazonaws.com/0/58479/7967636c-ca16-785d-7a93-ea4596e47564.jpeg)

回路図ではIO24、IO25を使用していますが、あとにIO33、IO13に変更しています。

### 2.2. 部品リスト

使用した部品のリストは、以下の通りです。

| No | 種別 | 品番など | 入手元 | 参考価格 |
|---:|:---|:---|:---|---:|
| 1 | ESP32開発ボード | ESP32 DevKitC | [秋月電子](http://akizukidenshi.com/catalog/g/gM-13628/) | 1,480円 |
| 2 | リニア光センサ | LLS05-A | [秋月電子](http://akizukidenshi.com/catalog/g/gI-05713/) | 150円 |
| 3 | マイコン内蔵フルカラーLED | NexPixel系 | [秋月電子](http://akizukidenshi.com/catalog/g/gM-08414/) | 70円 |
| 4 | 抵抗 | 10kΩ | - | - |

### 2.3. 仮組み

ブレッドボード上に仮組みを行い、動作確認を行いました。

![DSC_6008.jpg](https://qiita-image-store.s3.amazonaws.com/0/58479/ee69aa48-5475-0b2f-8117-7a9a872dfa04.jpeg)

また、とても雑な感じではありますがトイレに実際に設置し、機能することを確認しました。

![DSC_6014.jpg](https://qiita-image-store.s3.amazonaws.com/0/58479/9eab9afe-69c0-f823-2aef-823a311c0648.jpeg)

ちなみに完成品はこんな感じです。

![DSC_6134.jpg](https://qiita-image-store.s3.amazonaws.com/0/58479/2f790a21-f992-55b2-ea66-e19e66588905.jpeg)

## 3. 検出から表示への流れ

使用状況の検出から、トイレインジケータへの表示の流れは、ざっと以下の通りです。

1. トイレセンサは、光センサの値（電圧値）をESP32に内蔵されているADC（アナログ/デジタルコンバータ）で読み出します。
2. トイレセンサは、光センサの値を定期的、または一定以上変化時にMQTTトピックに送信します。
3. コントローラは、MQTTトピックの値を受信します。
4. コントローラは、光センサの値が閾値以上であれば「使用中」（照明が点灯中）、そうでなければ「空き」（照明が消灯中）と判断します。
5. コントローラは、判断した結果をMQTTトピックに送信します。
6. トイレセンサは、MQTTトピックから受信した判断結果を前面のLEDに表示します。（使用中:赤、空き:緑）
7. トイレインジケータは、MQTTトピックから受信した判断結果を前面のLEDに表示します。（使用中:赤、空き:緑）

## 4. ソースコード

ソースコードは[nayutaya/iot](https://github.com/nayutaya/iot)リポジトリにてMITライセンスで公開しています。

トイレセンサのファームウェアは[project/restroom_sensor/firmware](https://github.com/nayutaya/iot/tree/master/project/restroom_sensor/firmware)にあります。

## 5. 終わりに

今後、各構成要素について、少しずつ書き下していきます。
Mistel Barocco MD600日本語配列バージョンをMac風にカスタマイズするメモ

### はじめに

Mac の日本語配列キーボード使いの僕が、肩甲骨の痛みを緩和するために、日本語配列の貴重な分割キーボード [Mistel Barocco MD600](http://www.archisite.co.jp/products/mistel/barocco-jp/) を購入してカスタマイズしたメモです。

### カスタマイズ内容

macOS のキーボードカスタマイズツール [Karabiner Elements](https://pqrs.org/osx/karabiner/) と Barocco 自体のカスタマイズ機能で下図のように変更しました。ほぼ Mac の配列が再現されています。

![barocco_cusomize.001.jpeg](https://qiita-image-store.s3.amazonaws.com/0/16508/818cb675-a144-c603-797e-d1a24e5b4bf4.jpeg)

#### Barocco のカスタマイズ機能

- `FN` を押しながら `¥` を押すと、`E/J` が `ESC` キーに変わる（キーが青色に光る）
- `WIN` と `KANA` と右スペースを同時に押すと、右下の `\`, `FN`, `PN`, `CTRL` キーがそれぞれ `↑`, `←`, `↓`, `→` のカーソルキーに変わる。

※ `FN` + `I`, `J`, `K`, `L` でカーソルキーとして動作するが、カーソルキーを多用する僕としてはこの位置では打ちにくいためこのように変更。`FN` が使えなくなるが僕はほぼ使わないので問題なし。

#### Karabiner Elements (Simple Modifications)

<img width="1112" alt="スクリーンショット 2020-04-12 15.16.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16508/675922df-6fcf-741b-eb7f-af353118b2a4.png">


下記のようにキー配置を交換。

- CAPS LOCK -> 左Control (`caps_lock ` ->  `left_control`)
- 左CTRL -> Caps Lock (`left_control ` ->  `caps_lock `)
- WIN -> 左ALT (`left_command ` -> `left_option `)
- WIN -> 左Command (`left_option` -> `left_command`)
- 左スペースの左の謎のキー -> 英数 (`international4` -> `lang1`)
- 右スペースの右の謎のキー -> かな (`international5` -> `lang2`)
- KANA -> 右Command (`international2` -> `right_command`)

※ 僕は入力切替に英数・かなキーを多用する。

#### Karabiner Elements (Complex Modifications)

右シフトを押しながら↑（変更前の `\`）を押すことで `_` の入力になるように、Karabiner Elements のカスタムコード（下記）で設定。

```json
{
  "title": "Custom",
  "rules": [
    {
      "description": "右Shift + ↑ -> `_`",
      "manipulators": [
        {
          "from": {
            "key_code": "up_arrow",
            "modifiers": {
              "mandatory": [
                "right_shift"
              ],
              "optional": [
                "any"
              ]
            }
          },
          "to": [
            {
              "key_code": "international1"
            }
          ],
          "type": "basic"
        }
      ]
    }
  ]
}
```

このカスタムコードを反映させるためには次の手順を行う。
- 上記のコードを `.json` 形式で `~/.config/karabiner/assets/complex_modifications` ディレクトリ派以下
- Karabiner-Elements Preferences の Complex modifications タブで **Add rule** ボタンをタップ
- カスタムコードで追加した "右Shift + ↑ -> `_`" という名前のルールが増えているので **Enable** ボタンをタップして有効化する

<img width="1112" alt="スクリーンショット 2020-04-12 15.22.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16508/04a7d129-611f-e901-a6ce-a45d5d11f14d.png">
#### 慣れる

最後の難点として、僕は右手人差し指で押す `B` キーが左側のキーボードにあるということ。これは２日くらいがんばったら左手人差し指で自然に押せるようになった。
Paramikoのssh認証でハマった話

新PCで既存プロジェクト資源のparamiko ssh認証を実行した際に以下のエラーが発生した。

```
raise SSHException("not a valid " + tag + " private key file")
paramiko.ssh_exception.SSHException: not a valid RSA private key file
```

なんの話や

調べてみるとparamikoのissueに同じ報告が上がってた
https://github.com/paramiko/paramiko/issues/1226

原因はparamikoの以下ソース
https://github.com/paramiko/paramiko/blob/master/paramiko/pkey.py#L285
https://github.com/paramiko/paramiko/blob/master/paramiko/pkey.py#L265

秘密鍵のヘッダーがRSAまたはDSAじゃないとダメみたい
で、自分の秘密鍵を見てみると

```
$ cat id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
```

あれなんか違う

また調べてみるとOpenSSHで仕様変更があったみたい
https://www.openssh.com/txt/release-7.8

 * ssh-keygen(1): write OpenSSH format private keys by default
   instead of using OpenSSL's PEM format. The OpenSSH format,
   supported in OpenSSH releases since 2014 and described in the
   PROTOCOL.key file in the source distribution, offers substantially
   better protection against offline password guessing and supports
   key comments in private keys. If necessary, it is possible to write
   old PEM-style keys by adding "-m PEM" to ssh-keygen's arguments
   when generating or updating a key.

※自端末のOpenSSHのバージョンは以下の通り

```
$ ssh -V
OpenSSH_7.9
```

リリースノートに従って-m PEMオプションをつけて鍵を作り直してみる

```
$ ssh-keygen -t rsa -m PEM
$ cat id_rsa
-----BEGIN RSA PRIVATE KEY-----
```


paramikoも無事動きました。
小一時間ハマったのは内緒。
twitter APIで遊んでみる #2(ユーザータイムラインの取得)

## 前回までのお話
[twitter APIで遊んでみる #1(環境作り)](https://qiita.com/tomozo6/items/747036c49a8b6bca49e4)

## はじめに
前回は、とりあえず`python`で`twitter API`が叩ける環境まで作りました。今回は実際にAPIを叩いて、特定ユーザーのタイムラインを取得してみます。
なんとなく今ハンバーガーが食べたいので、モスバーガーの公式twitter(@mos_burger)のタイムラインを取得してみました。

## APIのリファレンス
今回使用する`user_timeline`APIのリファレンスです。
https://developer.twitter.com/en/docs/tweets/timelines/api-reference/get-statuses-user_timeline.html

パラメータはいっぱいありますが、今回は`count`と`screen_name`を指定しました。
`count`は検索結果のレコード数です。最大が200、デフォルトは20とのことです。今回はそんなにいらないので、とりあえず`5`にしました。
`screen_name`はtwitterアカウント名です。@マークはいりません。またscreen_nameを指定しないと、API取得元の自分のアカウントの情報を引っ張ってくるようです。

早速結果を見てみよう。

##コード
**getTimelines.py**

```python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import json
import config
from requests_oauthlib import OAuth1Session

# OAuth認証部分
CK      = config.CONSUMER_KEY
CS      = config.CONSUMER_SECRET
AT      = config.ACCESS_TOKEN
ATS     = config.ACCESS_TOKEN_SECRET
twitter = OAuth1Session(CK, CS, AT, ATS)

# Twitter Endpoint(ユーザータイムラインを取得する)
url = "https://api.twitter.com/1.1/statuses/user_timeline.json"

# Enedpointへ渡すパラメーター
params ={
         'count'       : 5,             # 取得するtweet数
         'screen_name' : 'mos_burger',  # twitterアカウント名
        }

req = twitter.get(url, params = params)

if req.status_code == 200:
    res = json.loads(req.text)
    for line in res:
        print(line['user']['name']+'::'+line['text'])
        print(line['created_at'])
        print('*******************************************')
else:
    print("Failed: %d" % req.status_code)
```
##実行結果

```bash
root@localhost:twitter$ python getTimelines.py
モスバーガー::ご好評いただいている #麻辣モスバーガー🍔のクーポンもあります(∩˃o˂∩)♡
モスバーガーアプリを是非ご利用ください😊💕
https://t.co/C5jbyoCcmw
Wed Mar 06 06:00:04 +0000 2019
*******************************************
モスバーガー::モスバーガーもご紹介いただきました！
TRiP EDiTOR（@TRiPEDiTOR）さん、ありがとうございました♪(*’-^)-☆
https://t.co/uOjrQXcLLS
Wed Mar 06 04:16:41 +0000 2019
*******************************************
モスバーガー::＼#モスシェイク ファン必見😋／

お好きなセットに【+30円】でモスシェイクMが選べるってご存じですか？
ちょっと甘いものが欲しいときに、ぴったり✨✨
ストロベリー・コーヒー・バニラ、あなたはどのフレーバーがお好き❓… https://t.co/xSU9IOYUZ1
Wed Mar 06 02:00:04 +0000 2019
*******************************************
モスバーガー::＼#私の好きモス キャンペーン／

モス商品のデジタルギフトを毎月抽選で30名様にプレゼント🎁
モスの推しメニューを教えてねヾ(o´▽`)ﾉﾞ

★応募方法★
①モスバーガー公式TwitterまたはInstagramをフォロー
②… https://t.co/iV5vVsrLt4
Tue Mar 05 06:00:04 +0000 2019
*******************************************
モスバーガー::バンズからはみ出すほど大きな #ハンバーグ に、たっぷりのとろーり #濃厚チーズ がベストマッチ☝

ハンバーグもチーズもとびきり😍モスファンに根強い人気の一品です🍔

#モスバーガー
https://t.co/BpMVyh285n https://t.co/SWYD0TUmIn
Tue Mar 05 02:00:04 +0000 2019
*******************************************
```

問題なく取得できたようです。

## 終わりに
次回は、他のAPIも同じように使ってみようと思います。
gulp の Typetalk 通知プラグインを作った話

## 概要
gulp の Typetalk 通知プラグイン [gulp-typetalk](https://www.npmjs.com/package/gulp-typetalk) を作ったので紹介する記事です。

## 前提知識
Typetalk って何？という方は [こちら](https://www.typetalk.com/)

## gulp とは？
https://gulpjs.com/
> gulp is a toolkit for automating painful or time-consuming tasks in your development workflow, so you can stop messing around and build something. 

Node.js 製のタスクランナーです。

## 使い方

1) Typetalk でボットを作成します。

<img width="906" alt="Screen Shot 2019-03-07 at 1.00.27.png" src="https://qiita-image-store.s3.amazonaws.com/0/27079/91241f64-218d-c008-8f2b-9441c5d1bd55.png">

*メッセージの投稿を行うので、topic.post にチェックを入れます*

| 項目 | 値 |
|-----|----|
| ID | gulp-typetalk |
| Full Name | gulp-typetalk

2) gulpfile を作成します。

サンプルコード

```javascript
// gulpfile.js
const typetalk = require("gulp-typetalk");

function typetalkExample (cb) {
    typetalk({
        token: YOUR_TYPETALK_TOKEN,
        topicId: YOUR_TOPIC_ID,
        message: "Hello, World!"
    });
    cb();
}

exports.default = typetalkExample;
```

*YOUR_TYPETALK_TOKEN は手順1で作成したボットのトークン、YOUR_TOPIC_ID はボットがいるトピックのIDで置き換えてください*

3) package.json を作成します。

```javascript
{
  "scripts": {
    "gulp": "gulp"
  }
}
```

4) 依存ライブラリをインストールします。

```
$ npm i --save-dev gulp gulp-typetalk
```

5) 実行します。

```
$ npm run gulp
```

6) メッセージが投稿されます。

<img width="908" alt="Screen Shot 2019-03-07 at 1.11.13.png" src="https://qiita-image-store.s3.amazonaws.com/0/27079/bb19388f-c90a-7131-b0fa-bad721d30491.png">

手順は以上となります。いかがだったでしょうか？フィードバック歓迎です :pray:
CentOS7にTomcat9をインストール[Ansible]

CentOS7のyumはTomcat7しかありません。
Ansibleを使ってTomcat9をインストールします。

## Ansibleのインストール

```bash
$ sudo yum install -y ansible
```

## Playbook

CentOS上の適当なところにplaybook.ymlを用意します。

TomcatのインストールはAnsible Galaxyから対応しているroleを持ってきます。
変数についてはサイトを参照してください。
https://github.com/zaxos/tomcat-ansible-role

```yml:playbook.yml
- hosts: localhost
  vars:
    tomcat_version: 9.0.16
    tomcat_java_version: 11
  roles:
    - role: zaxos.tomcat-ansible-role
```

`tomcat_java_version`はデフォルトは1.8ですが、11を指定しています。
これで`java-11-openjdk`がインストールされます。

## インストール実行

Ansible Galaxyから取得して、playbookを実行します。

```bash
$ sudo ansible-galaxy install zaxos.tomcat-ansible-role
$ sudo ansible-playbook playbook.yml
```

`/opt/tomcat`にインストールされます。

```bash
$ ls -l /opt
total 4
drwxrwsr-x 9 tomcat tomcat 4096 Mar  6 15:27 apache-tomcat-9.0.16
lrwxrwxrwx 1 root   root     25 Mar  6 15:27 tomcat -> /opt/apache-tomcat-9.0.16
```

## インストール後

インストール直後は起動しています。

### 起動

```bash
$ sudo systemctl start tomcat
```

### 停止

```bash
$ sudo systemctl stop tomcat
```

以上です。
19日目。PHPに大苦戦！

19日目の今日はPHP中級編に挑戦しました。
しかしこれが難しかった！

インスタンス、プロパティ、メソッドの違いが分からず混乱するし
同じ変数を何度も呼んだり定義したり、その法則が読めなくて迷子になるし。

プロパティへのアクセス、メソッドへの追加あたりはもう、頭ぐるぐるです。
ゲッターとセッターの違いもいまひとつ飲み込めず。
よく分からないのですが、手探りでなんとかクリアしたところです！

これを教科書から学ぶとなるともっとずっと大変だと思います。
形になりながら、動きを見ながら学習できるっていいなあと思いました。

お料理注文サイト
http://appdays.herokuapp.com/Day19/

(所要時間 ４時間）


###オブジェクト指向の基礎を学ぼう
目標物を確認しよう
クラスとインスタンス
プロパティ
メソッド
$this
コンストラクタ
コンストラクタとプロパティ
###完成物に近づけよう
HTMLとPHP
HTMLとPHP（2）
ファイルを分けよう
画像と価格を表示しよう
税込価格を表示しよう
###カプセル化
カプセル化を学ぼう
注文個数を管理しよう
###注文サービスを完成させよう
フォームを作ろう
フォームの値を受け取ろう
注文の小計を出そう
注文の合計金額を出そう
【JavaScript】現在地からwifiのあるカフェを探すアプリを作って見た

Wifi環境下で勉強できる場所を見つけるのが大変だったので、現在地からwifi付きのカフェを探すアプリを作成して見ました。

##実装環境
Mac OS Sierra
Atom

#使用するもの
ぐるなびAPIのKey
Google Map APIのKey

##作成手順
### 1. 地図とカフェのリストを表示するhtml作成とgoogle mapのAPIの読み込み
```javascript
<script async defer src="https://maps.googleapis.com/maps/api/js?key=[グーグルマップのAPIKEY]"></script>
<div id="content">
  <h1>現在地周辺のWifiが使えるカフェ</h1>
  <div id="map" class="map"></div>
  <ul id="shop-list"></ul>
</div>
```

### 2. グーグルマップの準備
```javascript
let map;
function initMap() {
  map = new google.maps.Map(document.getElementById('map'), {
    zoom: 15,
  });
}
```
### 3. javascriptで現在地を取得して地図に表示
```javascript

let a = navigator.geolocation.getCurrentPosition(test2); 
function test2(position) {
let lat = position.coords.latitude;
let lng = position.coords.longitude;
let myPosi = new google.maps.LatLng(lat, lng);
var marker = new google.maps.Marker({
  position: myPosi,
  map: map,
  icon: {
    url: 'Octocat.png',
    scaledSize: new google.maps.Size(40, 40)
    } 
  });
```
### 4. 現在地の近くのwifiのあるカフェを探す
さっきの続きです。

```javascript
  $.ajax({
    type : "get",
    url　: "https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=[ぐるなびAPIのKEY]&wifi=1&latitude="+lat+"&longitude="+lng+"&range=4&category_l=RSFST20000,RSFST18000",
    dataType : 'json',
    success　: function(json){
      let num_shop = json.rest.length;
      for( let i = 0; i < num_shop; i++){
        console.log(json.rest[i].url);
        let latLng = new google.maps.LatLng(json.rest[i].latitude, json.rest[i].longitude);
        var marker = new google.maps.Marker({
          position: latLng,
          map: map,
          label: {
            text: String(i+1),
            color: "#fff",
            fontWeight: 'bold',
            fontSize: '14px'
            },
            url: json.rest[i].url,
          });
          google.maps.event.addListener(marker, 'click', (function(url){
            return function(){ location.href = url; };
          })(json.rest[i].url));
          $('<li class="each-shop"><i class="fas fa-map-marker fa-3x"></i><span class="icon">'+ String(i+1) + '</span><a href="' + json.rest[i].url + '"><img class="shop-img" src=' + json.rest[i].image_url.shop_image1 + '><span class="shop-content"><span class="shop-name">' + String(i+1) + " " + json.rest[i].name + '</span><span class="time">営業時間：' + json.rest[i].opentime + '</span></span></a></li>').appendTo('#shop-list');
         }
      },
      error: function(json){
        console.log("error")
      }
 });
}
```
##まとめ
デモページ
https://map-wifii.herokuapp.com/index.html
詳細
http://yukimonkey.com/js-application/map-wifi/

探すことはできるのですが、そもそもぐるなびAPIにスターバックスやドトールなどの情報がなく、リソース不足だったので、他のAPIと組み合わせる必要があると思います。
node.jsでタイムゾーンの変換処理にdate-fns-timezoneを利用する

# date-fns-timezone

node.jsで日付処理するにはdate-fnsを利用すると便利に実装できます。

参考: https://www.webprofessional.jp/date-fns-javascript-date-library/

ですがこのライブラリのみだとタイムゾーンの計算がうまくできず何か使えるものがないか調べてみたところ、date-fns-timezoneというライブラリが良さげだったので使ってみました。

### 今回やりたいこと

日付がUTCで格納されているデータソース(DynamoDB)に対して日本時間の日付範囲でクエリをかけたい

```javascript:指定日に含まれるデータを取得するDynamoDBクエリを組み立てる
const targetDate = new Date(); // '2019-03-06T11:36:25.533Z' (ここはUTC)

// 日本時間の0時
const d1 = startOfDay(targetDate); // '2019-03-05T15:00:00.000Z'
// 日本時間の翌日0時
const d2 = endOfDay(targetDate); // '2019-03-06T15:00:00.000Z'

const param = {
  TableName : 'Comment',
  KeyConditionExpression: "#key= :key AND #date >= :d1 AND #date < :d2",
  ExpressionAttributeNames:{
    "#key": "key",
    "#date": "date"
  },
  ExpressionAttributeValues: {
    ":key": key,
    ":d1": d1,
    ":d2": d2,
  }
};
```

## 使ってみる

### date-fns-timezoneのインストール

npmからインストールできます。

```
$ npm install date-fns-timezone
```

依存ライブラリとして date-fns もインストールされるのでこちらも利用します。

今回利用したのはライブラリバージョンは以下です。

- date-fns-timezone : 0.1.4
- date-fns : 1.30.1

### 日本時間での0時を計算する

```javascript
// import
const { startOfDay, addDays } = require('date-fns');
const { convertToTimeZone } = require('date-fns-timezone');

// タイムゾーン定義
const timeZone = "Asia/Tokyo";

// 現在時刻(UTC)を取得
const targetDate = new Date();
// TimeZone付きDateに変換
const zonedTargetDate = convertToTimeZone(targetDate, { timeZone: timeZone });
// date-fnsでstartOfDayを計算
const startDate = startOfDay(zonedTargetDate);
const endDate = addDays(startDate, 1);

// 文字列化
const d1 = startDate.toISOString(); // => '2019-03-05T15:00:00.000Z'
const d2 = endDate.toISOString(); // => '2019-03-06T15:00:00.000Z'
```

convertToTimeZoneを利用するとTimeZone情報を持ったDateに拡張されるため、date-fnsのstartOfDay()などもそのまま使えるのが便利ですね。
指定のフォーマットでフォーマットするにはdate-fns-timezoneのformatToTimeZoneも使えます。

詳細ドキュメントはこちら。
https://www.npmjs.com/package/date-fns-timezone
RealSence  D435をPythonで使う（Windows10）

#はじめに
CNN-SLAMの学習データ収集に使えないかと買ったはいいけど忙しくて放置していたRealSense D435を使うべく
Pyhonのラッパーをビルドしたところ、若干はまったのでうまくいったやり方をメモ

え？**pip install pyrealsense2**で入るの？orz

#使ったソフトとバージョン
下記バージョンでビルド出来ました。

1:VS2017 ```professional Ver15.9.6```または```Community Ver15.9.7```
下記からダウンロード
https://visualstudio.microsoft.com/ja/free-developer-offers/
「C++によるデスクトップ開発」「Python開発」にチェックを入れてください
2:CMake ```Ver3.14.0-rc2```
下記からダウンロード
https://cmake.org/download/
3:github ```Ver2.21.0```
下記からダウンロード
https://git-for-windows.github.io/
4:ソースコード ```Ver2.18.1```と```Ver2.19.0```
https://github.com/IntelRealSense/librealsense
ダウンロードなりクローンしたフォルダに```build```フォルダを新規作成します。

**注意**
ANACONDAの(root)のPythonが```3.7```だとビルドしたpydが```3.7```でビルドされるようです。
仮想環境が```3.6*```の場合(root)のPythonを```3.6*```にダウングレードしてください

#(1)CMake
先ほどインストールしたCMakeを起動します

**①Browse Sourceをクリックして先ほどクローンした```librealsense```フォルダを選択します**
**②Browse Buildをクリックして先ほど作成した```build```フォルダを選択します**

![cmake_1.jpg](https://qiita-image-store.s3.amazonaws.com/0/286585/d87c15a4-6a2a-c579-263f-750151573870.jpeg)

**③左下にある```Configure```をクリックします**
**④新規にウィンドウが開くので下記のように設定し```Finish```をクリック**
![cmake_2.jpg](https://qiita-image-store.s3.amazonaws.com/0/286585/59cdb50f-c84e-2019-7c35-854f6c6e39fd.jpeg)
**③```+Add Entry```をクリックし、出てきたウィンドウを下記のように設定し```OK```**
![cmake_3_1.jpg](https://qiita-image-store.s3.amazonaws.com/0/286585/c8efe4f2-d4dd-852d-9f2d-294fb8d1814e.jpeg)

**⑤ラッパーだけビルドの場合**
BUILD_EASYLOGGINGPP
BUILD_PYTHON_BINDINGS
BUILD_SHARED_LIBS
HWM_OVER_XU
をチェックし```Generate```をクリック

**⑤サンプルプログラムもビルトする場合**
BUILD_EASYLOGGINGPP
BUILD_EXAMPLES
BUILD_GRAPHICAL_EXAMPLES
BUILD_PYTHON_BINDINGS
BUILD_SHARED_LIBS
BUILD_UNIT_TESTS
HWM_OVER_XU
をチェックし```Generate```をクリック

下枠に```Generating done```が出たら終了
![cmake_6.jpg](https://qiita-image-store.s3.amazonaws.com/0/286585/1565897e-cba7-9322-2b5f-e593036459ab.jpeg)

#(2)ビルド
 
①```build```フォルダにファイルが複数生成されていると思いますので```librealsense2.sln```をダブルクリックします。
![vs_1.jpg](https://qiita-image-store.s3.amazonaws.com/0/286585/e155fdb7-293e-8370-81c2-fc2235072300.jpeg)

②VSが起動しますので、左下に```準備完了```が出るまで放置します（赤矢印）
![vs_22.jpg](https://qiita-image-store.s3.amazonaws.com/0/286585/f883a570-bc61-1870-2ac5-a503b7ac64b2.jpeg)

③ビルド（B)の下にある```Debug```を```Release```に変更
![vs_3.jpg](https://qiita-image-store.s3.amazonaws.com/0/286585/9cf585d0-88d3-671b-c1f4-42fe3b2f3567.jpeg)

④```ALL_BUILD```を右クリックし```ビルド（U）```をクリック
![vs_4.jpg](https://qiita-image-store.s3.amazonaws.com/0/286585/26483420-249e-8470-3389-aa1c7b6c1cff.jpeg)

先ほどのbuildの中にReleaseフォルダが作られ、下記のファイルが生成されていれば成功です
![vs_5.jpg](https://qiita-image-store.s3.amazonaws.com/0/286585/78917d9a-101d-c823-c693-e49063647fa6.jpeg)

#(3)インストール（？）
ANACONDAで仮想環境を作成している場合
作成した```pyrealsense2.cp36-win_amd64.pyd```と```realsense2.dll```を下記フォルダにコピーします
※ユーザー名、仮想環境名は適宜変更してください

**C:\Users\ユーザー名\Anaconda3\envs\仮想環境名\Lib\site-packages**

```python
import pyrealsense2
```
でエラーが出なければ完了です

#参考
https://qiita.com/akapiku1025/items/8b92cf66ed4dce8e2fc7
HTTPSとはなんぞや

# HTTPSとはなんぞや。
お金が絡むようなサイトやログインページなどは昔からhttpsで接続するページが多く、逆にそれ以外については基本的には暗号化されていない印象でした。
最近SEO対策なのかhttpsに対応したページが多くなっているように感じています。
それと自分のウェブアプリケーションをhttps化したのだが、詳しい仕組みについては正直よくわかっていなかった。
ので、これもいい機会かと思い少し調べることにしました。

# HTTPプロトコルのよくない点
まず、HTTPでは何故ダメなのか？について考えてみます。
HTTPでは自分のリクエストが何も暗号化されていない平文の状態で見たいサーバーに送られることになります。
この時、同じネットワークに存在している機器からはこの情報は丸見えである。スターバックスやらマックやらのフリーWifiにつないでいる時、同じネットワークにつないでいる人からはリクエストの内容が全てわかってしまいます。
つまり、idやパスワードを含むようなリクエストがいとも簡単に盗聴されてしまいます。
また、間にプロキシサーバなどを挟んでいる場合にはそこで内容が改竄される可能性もあります。
ということでこのままではよくないということで、しっかり暗号化して情報をやり取りしましょうという話になる訳です。
そして、それだけならSSL証明書という仰々しいものをつけなくとも、ただ単純に暗号化して通信すればいいじゃないかということになりそうです。
しかしことWEBサイトの場合には、少しURLを変え似たようなレイアウトにしてしまえば、正直ほとんど見分けがつかないサイトを作ることができてしまいます。それを防止し、このサイトがしっかり信用できるサイトであるということを証明するために特別に証明書というのを発行しているようです。

# HTTPSプロトコルの良い点
ざっくりまとめてしまうと、
1. 暗号化通信ができる
2. サーバの信用を担保できる
という二点です。

## 暗号化通信ができる
暗号化通信については通信を確立するまでは公開鍵暗号方式を、実際のやり取りは共通鍵暗号方式を用いて通信を行なっています。これによって盗聴・改竄などをされることなく安全に通信を行うことができます。

## サーバの信用を担保できる
信頼のある第三者機関である認証局がSSL証明書を発行することによって、通信先のサーバーが本物であるという証明ができるので、悪意のある第三者による「なりすまし」を防止することができます。

# 参考
https://zenlogic.jp/aossl/basic/ssl-what/
http://www.stockdog.work/entry/2017/06/02/232327
https://www.atmarkit.co.jp/ait/articles/0710/26/news131.html

## 少し思ったこと
参考にある例では自前のプロキシサーバーを使って改ざんを行なっていますが、これと同じことは見たいサーバとの間に存在するようなサーバーにおいても可能なのでしょうか？
ネットワークに関する知識が十分でないため少し気になりました
競プロのテストを「go test」でやりたかったので作った

# 競プロのテストを`go test`でやりたかったので作った。

競技プログラミング*(以下競プロ)*でよく使われる、 *標準入力からデータを取得して標準出力へ結果を吐き出す*プログラムを簡単にテストしたかった。というお話。

## いきさつ

競プロは、いくつかテストケースとその回答が与えられており事前にテストできるようになってます。
しかし動作確認のたびに「テストケースをコピーして…」とかやってたので非常に効率が悪い……
時間との戦いでもあるし、こんな事で時間使いたくねぇな…
**「これ自動化できないかな……テストなんだし`go test`とかでテストできるならむっちゃ楽。」**


## リポジトリ / 実行イメージ
という事で自動化してしまったのがこちらになります。
[github.com/0Delta/GolangSkeletonForSpeedrun](https://github.com/0Delta/GolangSkeletonForSpeedrun)
使い方は`README.md`か本体コードをどうぞ。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/150591/a58940ad-0dfe-e502-a905-a8bf4f70e2dd.png)

## 実装

### 標準出力の取得

テストなので、結果を変数に格納して期待値と同じか評価する必要があります。
…が、結果は標準出力に吐き出してしまいます。

これは、テストコードに定義してある`captureStdout`を噛ませ、一時的に**標準出力を表す`os.Stdout`を自作パイプに置き換え**ることで実現させてます。
こちらは先人の知恵を~~丸パク~~借りていますので、[詳細はこちら -> Goで標準出力をテストする方法](https://qiita.com/kami_zh/items/ff636f15da87dabebe6c)

### 標準入力の代替

テストなので、標準入力へのデータ入力は自動化したいです。可能なら通常のテストと同じように、配列とかに格納して`for`で一気に行きたい。

ここはメイン処理を少し変更することで対応しました。
`getLine`で、**プログラムの引数が存在する場合はその最後、ない場合は標準入力を取得**するようにしています。
何故最後なのかというと、`go test`の後に続くフラグの数がわからないから。入力が一行だけなのであれば、コレで十分です。*(つまり複数行には非対応)*
後は、テストコード側でプログラムの引数を表す`os.Args`に入力されるべき文字列を追加してあげればテスト時は変数を、通常実行時は標準入力を見るようになります。

## で、どうなった？

**めっちゃ良い**

思いっきり自画自賛だが気にしない。
結果がわかりやすいし自分でテストケース増やすことも簡単、`go test`はGoの標準機能なのでほぼ全ての開発環境で使えて親和性もバッチリです。

これでスケルトンを作ってしまったので、競プロが開催されたときに「標準入力からの取得どうすんだっけ…」とか「動作確認の度にテストケースをコピーして目で確認して…」とかいう悩みから完全開放され、**問題を解く為に全時間を捧げることができるのが一番良い**ですね。


以上！
皆さんもテストを自動化して、良き競プロライフを。