OmniAICreator/Qiita-1.07M huggingface dataset:
Ratpack入門 (1) - Ratpackとは

## Ratpack入門シリーズ

1. [Ratpack入門 (1) - Ratpackとは](https://qiita.com/minebreaker/items/d7eeca815872a97069f5)
2. [Ratpack入門 (2) - アーキテクチャー](https://qiita.com/minebreaker/items/a9b256fd8a1513104669)
3. [Ratpack入門 (3) - hello world 詳解](https://qiita.com/minebreaker/items/b26d7d0677f91f17a7b5)
4. [Ratpack入門 (4) - ルーティング & 静的コンテンツ](https://qiita.com/minebreaker/items/8f26d8350f936ad669c2)
5. [Ratpack入門 (5) - Json & Registry](https://qiita.com/minebreaker/items/4353611cc541e3cb35fb)
6. [Ratpack入門 (6) - Promise](https://qiita.com/minebreaker/items/4689058d0d7b34d99c74)
7. [Ratpack入門 (7) - Guice & Spring](https://qiita.com/minebreaker/items/52b303bc18db5b33bd68)
8. [Ratpack入門 (8) - セッション](https://qiita.com/minebreaker/items/1ebaa492b257365e1e5e)
9. [Ratpack入門 (9) - Thymeleaf](https://qiita.com/minebreaker/items/50693a4d6614979f654c)


## Ratpackとは

RatpackはApache Licence v2で公開されている、Java/Groovy向けのWebアプリケーションライブラリーです。

[公式](https://ratpack.io)
[GitHub](https://github.com/ratpack/ratpack)
[Javadoc](https://ratpack.io/manual/current/api/index.html)


## 特徴

### イベント駆動

Ratpackは通信に[Netty](http://netty.io/)を使用しているため、node.jsなどと同様にイベント駆動で動作します。
そのためスケーラブルで高パフォーマンスなHTTP通信を実現できます。

### 非同期

通信が非ブロッキングで行われるということは、Javaが苦手とする非同期なプログラミングのサポートが必要になります。
Ratpackは`Promise`クラスでこれをサポートするとともに、RxJava用の拡張も用意されています。

### 非オピニオネイテッド

Ratpackは開発の目標の一つに、「他のツールやライブラリーと統合するとき、柔軟で非オピニオネイテッドであること」が挙げられています。

### 拡張性

`ratpack-groovy`, `ratpack-guice`, `ratpack-jackson`, `ratpack-rxjava`, `ratpack-session`などの拡張モジュールがあります。


## Ratpackが目指していないもの

公式ページによると、下記がRatpackの目標で**ない**ものとして挙げられています。

* 完全に統合された、「フルスタック」フレームワーク
* 必要になるかもしれないありとあらゆる機能を提供すること
* 「ビジネスロジック」のためのアーキテクチャーやフレームワークを提供すること


##  Hello World

```groovy:build.gradle
dependencies {
    compile 'io.ratpack:ratpack-core:1.5.1'
}
```

```java:Sample.java
public final class Sample {

    public static void main( String[] args ) throws Exception {
        RatpackServer.start( server -> server
                .handlers( chain -> chain.get( ctx -> ctx.render( "hello, world" ) ) ) );
    }

}
```

![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/231669/bc05ad63-f28e-7c99-d3dd-2151047a77b7.png)

見てのとおりラムダ式を多用する前提で作られていますので、ラムダ式に慣れていない人はぜひ習得しましょう。


## なんでこの記事を書こうと思ったのか

Springに嫌気がさして代わりのライブラリーを探していて、Ratpackに出会いました。
ただ日本語の情報が少なく、あってもJavaではなくGroovyだったり、公式のドキュメンテーションもわかりづらく感じることがありました。
そこで、これからRatpackを使おうとする人のサポートになればよいと思い、この記事シリーズを書くことにしました。

次のポストで、Ratpackの詳しい使い方を見ていこうと思います。
組込み | C > link > 変数の値の自動0初期化? | 初期化用関数を使ったRAM変数の初期化

```txt:動作環境
とある組込みシステム
```

現在読んでいる膨大なソースファイルの一部において、変数の宣言をしている部分がある。
その変数はそのままカウントアップに使用されている。

宣言はしているが、0に明示的に初期化はされていない。
記憶領域?の違いによる自動初期化を使っているのだろうか?


https://stackoverflow.com/questions/3373108/why-are-static-variables-auto-initialized-to-zero
> answered Jul 30 '10 at 15:50
Jerry Coffin
に対するJerry Coffinのコメント
> it's explicitly stated in K&R1 (Appendix A, §6.8): "Static and external variables which are not initialized are guaranteed to start off as 0; automatic and register variables which are not initialized are guaranteed to start off as garbage."

~~Cソースファイルにおいて、関数外でstatic修飾子なしで宣言された変数の記憶領域は上記でいうところの「Static」なのだろうか。~~

```.c
int val;

void count_up(void)
{
    val++;
};
```

~~マップファイルを見ればいいのだろう。~~
~~マップファイルの見つけ方はまだ未消化。~~
実行時にブレークして、インスペクトで変数のアドレスを探し、そのアドレスをメモリ内で確認した。
ユーザ用のRAM領域の変数であるということは分かった。

### 初期化処理用関数のコール

検索して見つかった資料に下記のようなことが記載されていた

- RAMは電源投入時に決まった初期値はない
    - 0が必要なら0を書き込むこと
- 初期化用関数が用意されている
    - 一つ一つの変数を初期化するよりも効率が良いため

対象コードを見ると、確かにその初期化用関数を使っているようだ。

**自動0初期化ではなく、初期化用関数を使ったRAM変数の初期化**、ということのようだ。

### マップファイル

マップファイルを見つけました。
マップファイル内には「グローバルのdata」「ローカルのdata」などの記載があります。

該当の変数は「グローバルのdata」のようです。


### 関連

- [組込みの門](https://www.uquest.co.jp/embedded/index.html) @ ユークエスト株式会社
    - [ヒープとスタック](https://www.uquest.co.jp/embedded/learning/lecture16.html)
    - [コードサイズを聞かれたら](https://www.uquest.co.jp/embedded/learning/lecture11.html) > この変数はどこに置かれる? (2)
        - var1: 初期値なしグローバル変数
- [メモリの4領域] (http://brain.cc.kogakuin.ac.jp/~kanamaru/lecture/MP/final/part06/node8.html) @ Takashi Kanamaru's Web Page
- [C | C++ > 配列の初期化 > int a[100] = {0}; | staticストレージと同じ方法で初期化](https://qiita.com/7of9/items/cfe186f70133ee813c60)
- 別のシステム(MSP430)の[資料](http://www.ti.com/sc/docs/products/micro/msp430/userguid/as_8.pdf)
    - p8-25にROM(.vectors, .text, .const)やRAM(.bss, .data)の記載あり
Python 3：クラスとインスタンス（オブジェクト）　（超基礎）

# クラスとは？

* クラス：オブジェクトを作るための設計図
    * インスタンス：クラスから作ったオブジェクトのこと
* クラスではオブジェクトの「属性」と「実行できること」を定義する
    * 属性は変数で，実行できることは関数（メソッド）で定義する
* 以下，クラス定義の構文

```python:ex2-1.py
class クラス名:
    ステートメント
```

# 銃（Gun）を例として，Gunクラスのオブジェクト仕様を定義してみる

* Gunクラスのオブジェクトには，次に示す変数と関数を仮定する
    * 変数
        * color：銃の色（初期値"black"）
        * number：装弾数（初期値 0）
    * 関数
        * shoot：引数で指定した数だけ弾を打つ

---

* 初期化メソッド
    * クラス定義にはインスタンス（クラスから作ったオブジェクト）が作られたときに実行される初期化メソッドを書くことができる

```python:ex2-2.py
def __init__(self, 引数1, 引数2, ...):
    初期化の処理
```

* 注意
    * 第1引数である`self`には初期値が設定されていないので省略不可
    * `self`にはインスタンス自身の参照が入っている

---

* Gunクラスをつくる

```python:ex2-3.py
class Gun: #Gunクラス
    def __int__(self, color="black") #初期化メソッド
        self.color = color #引数で受け取った値を代入 
        self.number = 0 #装弾数 0 から始める
```

* この後，`from ex2-3 import Gun`とやって，`gun1 = Gun()`とすれば良い

###### 要望有ればもう少し詳しくまとめます．
マイコン開発での失敗談

マイコン開発でハマったことを書いておく。2度同じミスをしないため。

## マイコンが一つ増えると考えるべき状況が格段に増して難易度が高くなる

SoC+マイコン1個 からSoC+マイコン2個に増えたときの難易度の増加を甘くみてはいけない。
相手の電源が入っていない時やハングアップしたときのリカバリ、共有すべき情報の同期のことを考えよう。
マイコンの個数は少ないほうがよい。もちろん増やさざるをえない場合もある。その場合は油断しないで覚悟しよう。

## ピン数が足りないためにデバッグ用のポートをつぶしてしまうと開発がつらい

フルカラーLEDを3つつけるとそれだけでGPIOポートが9つ必要になる。
部品コスト削減のためにピン数の少ないマイコンを使用し、デバッグ用のポートもGPIOに流用せざるをえないこともある。
マイコンのソフトはそれほど複雑なことはやっていないとはいえ、デバッガがつながらないと想定通りに動かない場合につらい。

## 低消費電力のマイコンだと外部ピンからのリセットとパワーオンリセットで動作が違うかも

私が使用したマイコンではRTC(リアルタイムクロック)の設定はパワーオンリセットのときだけリセットされ、外部ピンからのリセットでは設定がそのまま残る。
そして、超低消費電力の待機モードではシステムクロックとしてRTCを使用する。
その待機モードがうまくいくときといかないときがあるというバグで何日もハマった。
一度サンプルプログラムを動かしてから外部ピンでリセットかけて自分のプログラムを動かすと正常動作するが、翌朝電源を入れて動かすとダメという症状。
外部ピンのリセットとパワーオンリセットの違いを理解していなかった。

## 超低消費電力待機モードから復帰したところで暴走する

使用していないピンのpin muxを全てdisable にしたら暴走しなくなった。
超低消費電力モードではピンからのノイズに敏感ということがわかった。

## 待機中の電力消費がスペックの10倍も大きい
つまり、バッテリーが想定した時間の1/10しか持たない。
デバッグに使えるかもと思ってpin muxを有効のままにしていたUARTのピンから電流が漏れていた。
UARTのpin muxをdisableにして解決。

## インターバルタイマのクロックソースを確認しろ

HALの関数のインタフェースではインターバルタイマの間隔をマイクロ秒単位で指定できる。
それなのに、1ミリ秒以下にセットしたら異常動作になった。
インターバルタイマのクロックソースが1KHzだったため。
クロックソースを別のものに変更して解決。
サンプルプログラムでそれっぽく動いたので詳細を確認せずに、HALの関数の引数の変更だけでいけるはずと思い込んだのが敗因。
cakephp2 コア定義定数まとめ

#パス定数の基本定義

| 定数 | 説明 |
|:-:|:-:|
| **ROOT**  | ルートディレクトリーへのパス  |
| **APP_DIR**  | アプリケーションのディレクトリ名  |
| **CAKE_CORE_INCLUDE_PATH**  | Cakeライブラリへのパス  |
| **WEBROOT_DIR**  | webrootディレクトリ名  |
| **WWW_ROOT**  | webrootへのフルパス  |
| **DS** | PHPのDIRECTORY_SEPARATORの省略語。 <br>つまりLinux の場合は / Windows の場合は \ を指します。  |

## 基本定義から組み合わせた定数

| 定数 | 説明 |
|:-:|:-:|
| **CORE_PATH** | **CAKE_CORE_INCLUDE_PATH** + ディレクトリセパレータ <br> define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS);  |
| **CAKE**  | **CORE_PATH** + 'Cake' + ディレクトリセパレータ <br> define('CAKE', CORE_PATH . 'Cake' . DS);  |
| **APP**  |  **ROOT** + **APP_DIR** + ディレクトリセパレータ <br> define('APP', ROOT . DS . APP_DIR . DS); |
| **VENDORS** |  Vendorディレクトリ<br> define('VENDORS', ROOT . DS . 'vendors' . DS); |
| **APPLIBS**  | define('APPLIBS', APP . 'Lib' . DS);  |
| **TESTS**  | Testディレクトリ<br> define('TESTS', APP . 'Test' . DS);  |
| **TMP** | TMPディレクトリ(キャッシュやCakeログのベース) <br> define('TMP', APP . 'tmp' . DS);  |
| **CACHE**  | キャッシュが保存されるディレクトリ<br> define('CACHE', TMP . 'cache' . DS);  |
| **LOGS**  | Cakeログが保存されるディレクトリ <br> define('LOGS', TMP . 'logs' . DS);  |

## CSS JS 画像ファイルのパス

※下記は全て2.4からは非推奨となっています。

define('CSS', WWW_ROOT . 'css' . DS);
define('CSS_URL', 'css/');              // 2.4から非推奨 → App.cssBaseUrl
define('JS', WWW_ROOT . 'js' . DS);
define('JS_URL', 'js/');                // 2.4から非推奨 → App.jsBaseUrl
define('IMAGES', WWW_ROOT . 'img' . DS);
define('IMAGES_URL', 'img/');           // 2.4から非推奨 → App.imageBaseUrl

# 定義を変更する場合

tmpやcacheディレクトリを別に設定する場合下記のように変更する

    if (!defined('TMP')) {
        define( 'TMP', "TMPディレクトリへのパス");
    }

# Reference

http://kwski.net/cakephp-2-x/1228/

cakephp2だと、下記ファイルにdefineされています。
app/Vendor/cakephp/cakephp/lib/Cake/bootstrap.php
Qiitaで記事にCodePenが埋め込めるようになりました

Qiitaで記事にCodePenのPenが埋め込めるようになったので、実際に作りつつ埋め込み方を紹介します。

## CodePenのエディタの開き方

[CodePen](https://codepen.io)にアクセスし、ログインまたは登録後「Create」→「New Pen」を選びます。

<img width="1131" alt="スクリーンショット 2018-01-17 14.27.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/7048/ceb2dafb-8866-bc85-3e7a-a0eeb66d6c03.png">

するとエディタ画面が出ます。

<img width="1131" alt="スクリーンショット 2018-01-17 14.26.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/7048/99be6fe0-63c0-cd8f-210e-53be8d851f4d.png">

HTML, CSS, JSなどを入力してSaveします。

## 埋め込み方

エディタ画面の右下のバーに `Embed` という項目があるのでクリックします。

<img width="664" alt="スクリーンショット 2018-01-17 14.12.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/7048/7400ac6a-3c6b-d343-10da-ff6471dd1867.png">

するとモーダルが出るので、HTML形式を選択してボックス内のHTMLタグをコピーします。

<img width="880" alt="スクリーンショット 2018-01-17 14.14.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/7048/f42435ff-6b00-af5d-393b-b3ffea4c5df3.png">

コピーしたHTMLは以下のような感じになると思います。

```html
<p data-height="265" data-theme-id="0" data-slug-hash="dJgNLK" data-default-tab="js,result" data-user="tomoasleep" data-embed-version="2" data-pen-title="dJgNLK" class="codepen">See the Pen <a href="https://codepen.io/tomoasleep/pen/dJgNLK/">dJgNLK</a> by Tomoya Chiba (<a href="https://codepen.io/tomoasleep">@tomoasleep</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>
```

あとは、コピーした内容をQiitaのエディタに貼り付けて、投稿すると完成です。
現在のところ、エディタのプレビューには貼り付けたCodePenは表示されない仕様となっております。ご了承ください。

## 記事での表示

<p data-height="512" data-theme-id="0" data-slug-hash="dJgNLK" data-default-tab="js,result" data-user="tomoasleep" data-embed-version="2" data-pen-title="dJgNLK" class="codepen">See the Pen <a href="https://codepen.io/tomoasleep/pen/dJgNLK/">dJgNLK</a> by Tomoya Chiba (<a href="https://codepen.io/tomoasleep">@tomoasleep</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>


記事内でのJSやCSSのデモなどに使ってみてください:tea:
使ってないGCEインスタンスを洗い出す

## 経緯

- 社内のいろんな人がGCE使ってインスタンス作りまくった結果、色々と不要そうなインスタンスが溜まってきたので、それらの洗い出しがしたかった
- `gcloud compute instance list`とかで最終起動時間とか見れるかなーと思ったが見れなかったので

## 「使ってない」の定義

今回はインスタンスが指定の日数の間に稼動していなかった場合、「使ってない」と判断する

## 稼動しているかどうかの判断

今回はStackdriverLoggingの方のログが出ているかで判断することにした。なお、管理アクティビティ監査ログは400日間は保存されるので、それ以上の日数稼動していないとかの判断はできなさそう

## やってみた

```shell
#!/bin/bash
while read instance
do
  id="$(jq -r ".id" <<<"$instance")"
  name="$(jq -r ".name" <<<"$instance")"

  filterdate=$(date -d "-14 days" "+%Y-%m-%dT15:00:00.000Z")
  # log=$(gcloud logging read "resource.type=\"gce_instance\" resource.labels.instance_id=\"${id}\" jsonPayload.event_subtype=\"compute.instances.start\" timestamp>=\"${filterdate}\"" --limit=1)
  log=$(gcloud logging read "resource.type=\"gce_instance\" resource.labels.instance_id=\"${id}\" timestamp>=\"${filterdate}\"" --limit=1)

  if [ -z "$log" ]; then
    # ログがない=稼動してない
    echo $name
  fi

done < <(jq -c "{ id: .id, name: .name }" <<<"$(gcloud compute instances list --format=json --filter="status!=RUNNING" | jq -r ".[]")")
```

## 懸念

- なんかもっとスマートな方法がある気がしてならない
- メンテナンスかなんかで稼動してない場合でもインスタンスのログが出力されるのだったらこの方法使えない
- 稼動していても使ってないインスタンスは洗い出せない
latexmk のコンパイルが重いときの一策

`latexmk -pvc` を立ち上げたり消したり長時間作業していると、プロセスが複数走っている状態になる可能性があります。


![1_____ghq_github_com_cpslab_master_thesis_summary__zsh_.png](https://qiita-image-store.s3.amazonaws.com/0/40717/f284d23f-f31a-813a-2811-b160321b0df6.png)


# 解決策
一旦全部切ります。

```
$ killall perl
```


tex でつまづく原因はたくさんあるのでこれが解決につながるかはわかりません。
挙動がおかしいと感じた時に試す１つの方法として紹介です。
[Swift]UITableViewCellのaccessoryViewでaccessoryButtonTappedForRowWithIndexPathが来ない件の対応

UITableViewCellのaccessoryViewにはUISwitchなどを設定できますが、いくらUISwitch
をタッチしてもaccessoryButtonTappedForRowWithIndexPathが呼ばれない。これは仕様らしい。


で、色々調べて、これが一番シンプルそうだった。
UISwitchViewにaddTargetでactionを設定してから、cell.accessoryViewに設定する。

```xxxxxViewController.swift
func tableView(_ table: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell:UITableViewCell = table.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath)
    if cell.accessoryView == nil{
        let switchView = UISwitch(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
        switchView.isOn = false
        switchView.tag = indexPath.row
        switchView.addTarget(self, action: #selector(switchTriggered), for: .valueChanged)
        cell.accessoryView = switchView
    }
```


タッチされた時に呼ばれる処理。
（ここではUISwitchのON/OFFを配列に格納）

```xxxxxViewController.swift
    @objc func switchTriggered(sender: UISwitch){
        switchs[sender.tag] = sender.isOn
    }
```

[確認環境]
Swift:4.0.3
Xcode:9.2

---
以下、参考元（というか、ほぼそのまま。）
[ios - UISwitch in accessory view of a tableviewcell, passing a parameter with the selector to have selector function see the indexpath.row? - Stack Overflow](https://stackoverflow.com/questions/39566065/uiswitch-in-accessory-view-of-a-tableviewcell-passing-a-parameter-with-the-sele)
Planning Analytics Local のPlanning Analytics Workspace のサービスからの起動停止

#概要
Planning Analyticsとは、Cognos TM1の後継製品で、Planning Analytics Local(PAL)とは、オンプレで動くPlanning Analyticsです。
Planning Analytics Workspaceは、新規のWebインターフェースで、Windows 2012 Server R2では、以下のようにDockerの上で動作します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/147246/1f6754c0-b32e-a06d-a2d8-84bff8d9b6ad.png)

PALやWorkspaceに関しては、こちらの記事をご参照下さい。
**IBM Planning Analytics Local 2.0の紹介(Cognos TM1の後継製品)**
https://qiita.com/shinyama/items/77fddc9a84de04826bc9

Docker VMは、pawという名称で、Workspaceで提供されているstart.batスクリプトからDocker VMを作成します。
Docker VMは、Oracle VM Virtual Boxの上で動作しますが、最近行った検証で、リモートデスクトップでサーバーにログイン後、Docker VMを起動し、ログオフしてセッションを切ると、Docker VMは落ちてしまう事がわかりました。
Docker VMはセッションの中で動くものなので、そのセッションが切れてしまうと、サーバー上で動き続けるものではないようですね。

そうなると、本番でどういう運用すれば良いのやらと思い、開発元に聞いたところ、VBoxVmServiceを使ってDocker VMの起動をWindowsサービスに登録すれば良いかも知れない、という情報をもらい、実際に検証してみましたのでフィードバックします。

Planning Analytics Localで、Planning Analytics Workspaceを使用するプロジェクトでは必須の知識なので、覚えておいて頂ければと思います。
※Planning Analytics for Excel(PAx) を使用する環境でも、Planning Analytics Workspaceの実装は必須なのでご注意下さい。

#実装手順
まずは普通の手順で、PAWで提供されるStart.batからDocker VM(paw)を作成し、Workspaceアクセスできるところまで持っていきます。
デスクトップ上に「Oracle VM VirtualBox」のアイコンが表示されるので、バージョンを確認しておきます。
画像だと「5.1.8」ですね。
![001.PNG](https://qiita-image-store.s3.amazonaws.com/0/147246/840bca8e-73f8-e4d0-1328-492df7d5487f.png)

Docker VMは停止しておきましょう。
管理ツールがブラウザで開いている場合、ブラウザを閉じて、start.batのプロンプト画面ではCtrl + Cをしておきます。
以下のコマンドで、Docker VM(paw)を停止します。
docker-machine stop paw

以下のサイトから、VBoxVmServiceをダウンロードします。
ここで、最新バージョンをダウンロードするのではなく、先ほど確認したVirtualBoxに対応したバージョンをダウンロードしましょう。※VBoxVmService-5.1-Plum.exeをダウンロードしました。
http://vboxvmservice.sourceforge.net/

VBoxVmService-5.1-Plum.exeを管理者実行してインストールします。

C:\vmsフォルダにインストールされるので、VBoxVmService.iniを編集します。
![003.PNG](https://qiita-image-store.s3.amazonaws.com/0/147246/48ab4555-49cf-3ef2-fb47-f42cdbef95fb.png)

VBoxVmService.iniは以下の記載です。
Vm0の記載でVmName、ShutdownMehtodの変更を忘れないように。
VBOX_USER_HOMEのAdministratorは、実環境のユーザーに合わせて変更してください。

```html
[Settings]
VBOX_USER_HOME=C:\Users\Administrator\.VirtualBox
RunWebService=no
PauseShutdown=5000

[Vm0]
VmName=paw
ShutdownMethod=acpipowerbutton
AutoStart=yes
```

編集後、ファイルを保存し、TM1の各種サービスを停止した後に、WindowsOSを再起動します。

するとこの様に「VBoxVmService」がサービスに登録され、Docker VMがサービスから起動可能となります。
![004.PNG](https://qiita-image-store.s3.amazonaws.com/0/147246/2df15ca3-7b9a-f87f-8792-52cf6ed891e5.png)

リモートデスクトップでログオフしても、Workspaceへの接続が可能となります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/147246/ac05a477-c8b6-49a8-f130-11f9d1d2b538.png)


ポイントは、
①管理ツールとdocker VMをきちんと停止してから作業に入る事
②VBoxVmServiceとOracle VM VirtualBoxのバージョンをあわせる事
③VBoxVmService.iniを上記のように編集する事
ですね。

結構苦労してこれに辿り着きましたので、是非ご参考にして下さい。
aaptコマンドで9patchをバリデートする


9patchのリソースを幾つか追加したところ、次のエラーが出力されアプリがビルド出来なくなってしまいました。

```
Error:found an invalid color.
Error:Execution failed for task ':app:mergeDebugResources'.
> Error: java.util.concurrent.ExecutionException: com.android.tools.aapt2.Aapt2Exception: AAPT2 error: check logs for details
```

ぐぐるとAAPT2を無効にする方法が出てきましたが、AAPT2を無効にしても解決しませんでした。
今回は追加したのが9patchだったので画像の問題の可能性が高いと思い、更に調べていたところ、`aapt`コマンドで9patchのバリデーションが可能な事がわかりました。全ファイルバリデートして不正なファイルを除いたところ正常にビルドできるようになりました。

以下にaaptコマンドを使い方をまとめます。
# 9patchをバリデートする
バリデートするには以下のコマンドを実行します。

```
aapt s -i hoge.9.png -o /dev/null
```

正常な場合は結果は次のようになります。

```
Crunching single PNG file: hoge.9.png
        Output file: /dev/null
```


不正な場合には次のように何がわるいのか説明してくれます。


```
Crunching single PNG file: hoge.9.png
        Output file: /dev/null
ERROR: 9-patch image hoge.9.png malformed.
       Frame pixels must be either solid or transparent (not intermediate alphas).
       Found at pixel #267 along bottom edge.
```

今回は下のエッジに何故か1ピクセルだけ少し透過されたブラックが混じっていたことが原因でした。

# aaptコマンドのパス
今回の環境では `build-tools/27.0.1/aapt` にありました。
naming > 道は、二つに一つ


@ Star Trek: The NEXT GENERATION

>第76話「戦士の休息」
Family

http://www.usskyushu.com/guide/tng76.html

> ロベール：「その傷はこれからずーっとしょっていかなきゃならんぞ？ ずーっとな。…傷を抱えて生きるんだ。…道は、二つに一つ。選べよ、ルイスと海に潜るか？ …エンタープライズで空を飛ぶか？」

「その名前はこれからずーっとしょっていかなきゃならんぞ？ ずーっとな。…名前を使って活きるんだ。…道は、二つに一つ。選べよ、検索しにくい名前と作業停止に潜るか？ …エンタープライズで空を飛ぶか？」

### 関連

- [naming > define macroのprefix > 機能のON/OFF > USE_XXX / FEATURE_XXX / ENABLE_XXX](https://qiita.com/7of9/items/8fc31faa3fe90697d8ba)
- [naming > vx, vy, vxyの平均値 > avgの前置、後置](https://qiita.com/7of9/items/03d7e2c00746bfa11f9b)
- [naming > m_offset.offset_min > offsetがかぶる / offset_min: 最小と勘違いするかも](https://qiita.com/7of9/items/21a8e2c615d42e211ae2)
- [考察 > Add() | Clear() > コーディングは早い | リーディングは?](https://qiita.com/7of9/items/55eb96a40da2c271165b)
- [C++ Builder > thisを書く派 > this->Height > 検索するときを考慮](https://qiita.com/7of9/items/754d5e9d90f8710da339)
- and other


### 新人さんへ

良い名前を付ける習慣を身に付けましょう。
BlockSci環境構築（ローカル編）

[こちら](https://qiita.com/John110/items/67c0f5c3b82eda0f3b23)の記事のローカル編です。
自分のPCが`OS X High Sierra`ですが、`gcc` `g++`周りが`Linux`と違う影響やその他諸々でうまくいっていません。
もし環境構築に成功された方がいらしたら情報提供、もしくはQiitaに記事をあげていただけると幸いです。
データ解析については[BlockSciデータ解析編](https://qiita.com/John110/items/95d8b1028c10f9163b67)に書いてあります。

## インストール
推奨環境の`Ubuntu 16.04`を使ってやっていきます。
公式ドキュメントとほぼ同じですが公式にはまだ載っていない内容も多少混ざってますのでご注意ください。

```bash
sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
sudo apt-get update
sudo apt install build-essential cmake libssl-dev libboost-all-dev libsqlite3-dev autogen \
autoconf libcurl4-openssl-dev libjsoncpp-dev libjsonrpccpp-dev libjsonrpccpp-tools \
python3-dev python3-pip liblmdb-dev libsparsehash-dev libargtable2-dev libmicrohttpd-dev \
libhiredis-dev libjsoncpp-dev catch gcc-7 g++-7
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 60 --slave /usr/bin/g++ g++ /usr/bin/g++-7

git clone https://github.com/bitcoin-core/secp256k1
cd secp256k1
./autogen.sh
./configure --enable-module-recovery
make
sudo make install

cd ~
wget https://cmake.org/files/v3.10/cmake-3.10.0.tar.gz
tar xzf cmake-3.10.0.tar.gz
cd cmake-3.10.0/
cmake .
make
sudo make install
exec bash

cd ~
git clone https://github.com/rescrv/HyperLevelDB
cd HyperLevelDB
autoreconf -i
./configure
make
sudo make install
sudo ldconfig

cd ~
git clone https://github.com/citp/BlockSci.git
cd BlockSci
git submodule init
git submodule update --recursive
sudo cp -r libs/range-v3/include/meta /usr/local/include
sudo cp -r libs/range-v3/include/range /usr/local/include

cd libs/bitcoin-api-cpp
mkdir release
cd release
cmake -DCMAKE_BUILD_TYPE=Release ..
make
sudo make install

cd ../../..
mkdir release
cd release
cmake -DCMAKE_BUILD_TYPE=Release ..
make
sudo make install

# 公式に載っていないインストールコマンド
cd clustering
mkdir release #ディレクトリがない場合に実行
cd release
cmake -DCMAKE_BUILD_TYPE=Release ..
make
sudo make install
# ここまで

sudo -H pip3 install --upgrade pip
sudo -H pip3 install --upgrade multiprocess psutil jupyter pycrypto matplotlib pandas dateparser
```

clusterを生成するコマンドのインストールがReadmeに載っていないのですが`2017/12/21 時点`でプルリクエストが出されているので時期に公式に載るかもしれません。

### bitcoindのインストール
インストールディレクトリは各自で決めてください。

```bash
sudo add-apt-repository ppa:bitcoin/bitcoin
sudo apt-get update
sudo apt-get install libdb4.8-dev libdb4.8++-dev

git clone https://github.com/bitcoin/bitcoin.git
cd bitcoin
./autogen.sh
./configure
make
sudo make install
```

以上でインストールは終了です。

## 参考URL
- [BlockSci 公式ドキュメント](https://github.com/citp/BlockSci)
- [bitcoin coreのインストール（ubuntu）](https://qiita.com/tokuo/items/29596efdfc315967fceb)
CentOS6.xでglide installの処理が終わらないときはgitのバージョンを疑え

## 環境
CentOS (6.9)
go (1.9.2)
glide (0.13.1)

## 現象
`glide install`を実行後、コンソールにメッセージが表示されたまま処理が止まってしまう。  
`go get gopkg.in/go-playground/validator.v9`を実施しても同じように応答がなくなる。

```bash
$ glide install
[WARN]  The name listed in the config file (grow) does not match the current location (.)
[INFO]  Downloading dependencies. Please wait...
[INFO]  --> Found desired version locally github.com/aws/aws-sdk-go 25ef42b41b82230caae56ab23d872c81fb5c0eae!
[INFO]  --> Found desired version locally github.com/dgrijalva/jwt-go a539ee1a749a2b895533f979515ac7e6e0f5b650!
[INFO]  --> Found desired version locally github.com/fatih/structs f5faa72e73092639913f5833b75e1ac1d6bc7a63!
[INFO]  --> Found desired version locally golang.org/x/net a337091b0525af65de94df2eb7e98bd9962dcbe2!
[INFO]  --> Found desired version locally golang.org/x/oauth2 9ff8ebcc8e241d46f52ecc5bff0e5a2f2dbef402!
[INFO]  --> Found desired version locally golang.org/x/sys 314a259e304ff91bd6985da2a7149bbf91237993!
[INFO]  --> Found desired version locally google.golang.org/api b804618854e387dc7fdd9e50496183ddcbb4b120!
[INFO]  --> Found desired version locally google.golang.org/appengine 9d8544a6b2c7df9cff240fcf92d7b2f59bc13416!
[INFO]  --> Found desired version locally gopkg.in/yaml.v2 eb3733d160e74a9c7e442f435eb3bea458e1d19f!
[INFO]  --> Fetching gopkg.in/go-playground/validator.v9  #ここで処理が止まる



```

## 原因と対処
gitのバージョンが古い。yumの標準のレポジトリではgitをインストールすると1.7系のgitがインストールされていた。

```bash
$ git --version
git version 1.7.1
```

2系のgitをインストールする。

```bash
$ sudo yum remove git # 古いバージョンのgitを削除
$ sudo curl -s https://setup.ius.io/ | bash
$ sudo yum install git2u
$ git --version 
git version 2.15.1
```
参考: [CentOSにてGit v2系をパッケージでインストール](https://qiita.com/ohhara_shiojiri/items/36995e438dec68771089)

gitのバージョンアップ後に、`glide install`を実行すると処理が完了するようになります。
Sublime Text3 | 正規表現 > #define[space][tab]XXXや#define[space][space]XXXや#define[tab][tab]XXXや#define[tab][space]XXX を探す

```txt:動作環境
Windows 7 Pro (32bit)
Sublime Text 3 Build 3143 
```

### 希望処理

Find:にて以下のいずれかをヘッダーファイル*.hにて見つける。

```
#define     DELTA_FLYER // all space
#define 	DELTA_FLYER // space + tab
#define	    DELTA_FLYER // tab + space
#define		DELTA_FLYER // tab + tab
```

### 方法

Regular Expressionの機能をONにして(Alt+R)、以下で検索する。

```
#define *\t* *DELTA_FLYER
```


https://www.debuggex.com/r/xa_Qe-A6iW_tsSeo

### 参考

[正規表現 メタ文字一覧](http://www.megasoft.co.jp/mifes/seiki/meta.html) @ メガソフト株式会社
ESLint で Component definition is missing display name が出たら、 コンポーネントに名前を付ける

React のコンポーネントには名前を付けましょう、という名前のエラー。バグなどが発生したときに、コンポーネントを特定しやすくなるため。

よくあるのは、高階関数でコンポーネントを作ろうとして、 ESLintの `Component definition is missing display name   react/display-name` で怒られるパターン。

# 対応方法

## Before

下記はコンポーネントに名前が付かないため、表題のエラーが出ます。

```tsx
const createTabBarIcon = (iconName: string) => ({ tintColor, focused }: Props) => {
  return (
    <Icons
      name={iconName}
      size={26}
      style={{ color: tintColor }}
    />
  )
}
```

## After

明示的に名前を付けます。

```tsx
const createTabBarIcon = (iconName: string) => function TabBarIcon({ tintColor, focused }: Props) {
  return (
    <Icons
      name={iconName}
      size={26}
      style={{ color: tintColor }}
    />
  )
}
```

# メモなど

React Navigation の `TabNavigator` で、`navigationOptions` を共通化した関数に入れたい。
`navigationOptions` には関数を渡すので、Stateless Functional Component を返す関数を定義すれば良い。

この場合、関数内部で関数を定義することになるが、この定義された関数を無名関数にすると、 ESLintの `Component definition is missing display name   react/display-name` で怒られる。

このルールは、すべてのコンポーネントに名前が無いとデバッグしづらいからと、導入されたらしい。

で、考えてみれば当然だが、関数名をつけて返せば良い。つまりアロー関数ではダメ。

## コード

```js
// @flow

import React from 'react'
import HomeScreen from './HomeScreen'
import { TabNavigator } from 'react-navigation'

type Props = {
  tintColor: string,
  focused: boolean
}

const TabBarIcon = (iconName: string) => function TabBarIconContent({ tintColor, focused }: Props): React.Component {
  return (
    <Icons
      name={iconName}
      size={26}
      style={{ color: tintColor }}
    />
  )
}

export const MainNav = TabNavigator({
  Home: { screen: HomeScreen },
  navigationOptions: {
    title: 'ホーム',
    tabBarIcon: TabBarIcon('home')
  }
})
```

# 参考

- https://github.com/yannickcr/eslint-plugin-react/issues/1228
- https://github.com/yannickcr/eslint-plugin-react/issues/412
Google App Engine for Goを1.8にバージョンアップした

# はじめに
Google App Engine　for　Goが1.8に対応しGAになったため1.6からバージョンアップした際の手順をまとめてみました。

# gcloudコンポーネントUpdate
まず、gcloudに含まれるgoappをUpdateしましょう。
CloudSDKに含まれるgoappが1.8に対応します。

```
gcloud components update 
```

# Go1.8へバージョンアップのための修正
## app.yaml
```yaml
service: sample
runtime: go
api_version: go1.8 #go1から変更

handlers:
- url: /.*
  script: _go_app
```
api_versionを`go1.8`に変更します

## contextの修正
go1.7から`golang.org/x/net/context`パッケージは廃止され、`context`パッケージへ移行する必要があります。
ただ、特にパッケージの変更だけで大きな改修は必要ありません。
go toolを使うと自動でマイグレーションできます。

```
go tool fix -force=context *.go  
```

# dep（パッケージ管理ツール）の導入

必ずパッケージ管理を導入しなくてはいけないというものでもないです。
しかし、CI,CDを行っていると、ある日突然失敗するということもあるため導入したほうが良いと思います。
depは公式に提供されているパッケージ管理ツールツールです。depはGo１．８以上が要件となっています。Go1.8にバージョンアップしたことで利用可能になりました。

depをインストールします。

```
go get -u github.com/golang/dep/cmd/dep
```

GAEがGo1.8に対応したことで多くのライブラリはcontextに対応しはじめています。
自身のコードは`context`パッケージに対応しましたが、参照しているライブラリは古いままではコンパイルできないので最新に更新します。

```
go get -u ./... 
```

次にdepの初期化を行います。

```
dep init
```

`Gopkg.toml`,`Gopkg.lock`ファイルが作成されパッケージがインストールされます。
Gopkg.tomlは依存しているライブラリのリスト、Gopkg.lockすべての依存ライブラリのロックファイルです。
`vendor`フォルダが作成され依存しているライブラリが取得されます。
vendorフォルダはVendoringと言われ1.5から導入されたライブラリの依存性解決のための機能です。

git clone等で`Gopkg.toml`,`Gopkg.lock`ファイルからパッケージのインストールを行う場合は以下のコマンドを実行します。

```
dep ensure
```

# ここで問題
gcloudを使用してGAEにデプロイすると以下のようなエラーが発生します。

```
ERROR: (gcloud.app.deploy) Error Response: [9] Deployment contains files that cannot be compiled: Compile failed:
/work_dir/route.go:4: can't find import: "github.com/gin-gonic/gin"
/work_dir/github.com/hanenao/gaesample/vendor/github.com/gin-gonic/gin/binding/default_validator.go:11: can't find import: "gopkg.in/go-playground/validator.v8"
/work_dir/github.com/hanenao/gaesample/vendor/github.com/gin-gonic/gin/render/msgpack.go:10: can't find import: "github.com/ugorji/go/codec"
/work_dir/github.com/hanenao/gaesample/vendor/github.com/gin-gonic/gin/context.go:19: can't find import: "github.com/gin-contrib/sse"
2018/01/02 17:19:42 go-app-builder: build timing: 10×compile (9.603s total), 0×link (0s total)
2018/01/02 17:19:42 go-app-builder: failed running compile: exit status 2

```

うまく、`vendor`フォルダ内のライブラリの依存性解決がうまく言っていないようです。

https://stackoverflow.com/questions/46295469/gcloud-app-deploy-fails-cannot-import-internal-package
https://medium.com/veltra-engineering/be-careful-when-deploying-golang-app-with-vendor-to-gae-4a12ad12b65f
http://blog.wktk.co.jp/ja/entry/2017/10/11/google-app-engine-go-vendor-directory-structure

同様に困っている人がいるようです。
`gcloud app deploy`コマンドの代わりに`goapp deploy`で回避できました。
GoのVendoringはgcloudコマンドと相性が悪いよいで問題が発生しました。

これで無事にGAEのGo1.8に対応できました。
BlockSci環境構築（AWS編）

本記事は`hkalodner`氏が主に開発している [BlockSci](https://github.com/citp/BlockSci) についての記事です。
まだまだ開発途中で情報が少ないので色々試行錯誤した記録を書き出してみたいと思います。

## インストール
[BlockSci公式ドキュメント](https://github.com/citp/BlockSci)にあります[ami-7cf38706](https://console.aws.amazon.com/ec2/home?region=us-east-1#launchAmi=ami-7cf38706)を使ってEC2インスタンスにインストールします。
`ami-7cf38706`からインストールするとすでに必要なライブラリはセットアップされていて、またmainnetのデータをBlockSciでパースしたデータがすでに入っています。
初めから入ってるパースデータは`/home/ubuntu/bitcoin/`にあります。
このパースデータは`2017/12/12 15:54:15`までのデータでブロック高は`498919`です。
EC2が起動してから約3.5時間でデータが全て展開されデータ解析できるようになります。
`bitcoind`は入っていないので必要であれば別途インストールしましょう。
その際は残容量にご注意ください。

### 推奨スペック
|項目|スペック|
|:--|:--|
|SSD|200GiB以上|
|メモリ| 60GiB以上|
|インスタンス| r4.2xlarge|

### testnetのデータを使う場合
AMIが作成された後にマージされたコードがあるためそちらを自身で修正する必要があるかもしれません。

```cpp:BlockSci/src/parser/parser_configuration.cpp
ParserConfiguration<FileTag>::ParserConfiguration(const boost::filesystem::path &bitcoinDirectory_, const boost::filesystem::path &dataDirectory_) : ParserConfigurationBase(dataDirectory_), bitcoinDirectory(bitcoinDirectory_) { 
     auto bitcoinDirectoryString = bitcoinDirectory.native();
     if (bitcoinDirectoryString.find("litecoin") != std::string::npos || bitcoinDirectoryString.find("Litecoin") != std::string::npos) { 
         blockMagic = 0xdbb6c0fb;
         workHashFunction = doubleSha256;
     } else if (bitcoinDirectoryString.find("regtest") != std::string::npos) {
         blockMagic = 0xdab5bffa;
         workHashFunction = doubleSha256;
     } // diff ここから
       else if (bitcoinDirectoryString.find("testnet") != std::string::npos) {
         blockMagic = 0x0709110b;
         workHashFunction = doubleSha256;
     } // diff ここまで
       else {
         blockMagic = 0xd9b4bef9;
         workHashFunction = doubleSha256;
     }
 }
```

```bash:console
cd release
make
sudo make install
```

## データ解析
ローカルマシンのターミナルでsshトンネルを使用してEC2インスタンスの`jupyter notebook`に接続できるようにします。

1. `ssh -i your_private_key.pem -N -L 8888:localhost:8888 ubuntu@your_url.amazonaws.com`
1. ブラウザを開き`localhost:8888`で`jupyter notebook`が開きます。
1. `BlockSci Demo.ipynb`が用意してあるので全てのセルを実行します。
1. 初めに入っているパースデータを元にスクリプト形式別のトランザクション数のグラフやセカンドレイヤーのトランザクション数のグラフなどが描画されます。

### jupyter notebookを公開したい場合
1. `ssh -i your_private_key.pem ubuntu@your_url.amazonaws.com` でインスタンスに繋ぎます。
2. `jupyter notebook --generate-config`をして`jupyter_notebook_config.py`を生成します。
3. `.jupyter/jupyter_notebook_config.py`をエディタで開き`c.NotebookApp.ip = '*'` を追記します。（許可するIPは適宜編集してください）
4. `sudo shutdown -r now`で再起動します。

以上でsshトンネルを使わなくても`jupyter notebook`に接続可能になります。
公開設定する場合はセキュリティに配慮して、必ずAWS側でセキュリティグループを設定する等をしてください。

その他具体的なプログラムについては [BlockSciデータ解析編](https://qiita.com/John110/items/95d8b1028c10f9163b67) に書いております。

---

補足等ありましたら編集リクエストいただけると助かります。
How to enable/disable TeamViewer service on CentOS 7.x

### 

- use teamviewerd.sysv

```shell-session
# cd /opt/teamviewer/tv_bin/script
# cp teamviewerd.sysv /etc/init.d/
```


```shell-session
# service teamviewerd.sysv start
Starting teamviewerd...method return sender=org.freedesktop.DBus -> dest=:1.121 reply_serial=2
   uint32 2

# systemctl status teamviewerd.sysv
● teamviewerd.sysv.service - LSB: TeamViewer remote control daemon
   Loaded: loaded (/etc/rc.d/init.d/teamviewerd.sysv; bad; vendor preset: disabled)
   Active: active (running) since Wed 2018-01-17 13:26:49 JST; 8s ago
     Docs: man:systemd-sysv-generator(8)
  Process: 2596 ExecStop=/etc/rc.d/init.d/teamviewerd.sysv stop (code=exited, status=0/SUCCESS)
  Process: 3136 ExecStart=/etc/rc.d/init.d/teamviewerd.sysv start (code=exited, status=0/SUCCESS)
 Main PID: 3154 (teamviewerd)
   CGroup: /system.slice/teamviewerd.sysv.service
           └─3154 /opt/teamviewer/tv_bin/teamviewerd -d

# systemctl enable teamviewerd.sysv
teamviewerd.sysv.service is not a native service, redirecting to /sbin/chkconfig.
Executing /sbin/chkconfig teamviewerd.sysv on

```

cf. https://askubuntu.com/questions/427125/teamviewer-does-not-start-automatically-how-do-i-make-sure-it-does
vue-routerのgithub-pages用設定

[webpackでgithub pagesをdeployする際のハマりどころ](https://qiita.com/uriuriuriu/items/e764c4f1754d49754a0c) の続き。

SPAをgithub-pagesにdeployした場合、
サーバ上のroot dirが```https://USER_NAME.github.io/```となっているので
本番環境のSPA内でのroot dirを```https://USER_NAME.github.io/GITHUB_PROJECT_NAME```になるように変更しなければならない。
そうしないとSPA内でのページ遷移時に```GITHUB_PROJECT_NAME``` dirを無視した遷移となり404になってしまう。

### code

src/router/router.jsが

```javascript
import VueRouter from 'vue-router'
import Vue from 'vue'
import Index from 'src/pages/Index'
import About from 'src/pages/About'

Vue.use(VueRouter)

const routes = [{
  path: '/',
  name: 'index',
  component: Index
}, {
  path: '/about',
  name: 'about',
  component: About
}]

const scrollBehavior = (to, from, savedPosition) => {
  if (savedPosition) {
    // savedPosition is only available for popstate navigations.
    return savedPosition
  } else {
    const position = {}
    // new navigation.
    // scroll to anchor by returning the selector
    if (to.hash) {
      position.selector = to.hash
    } else {
      position.x = 0
      position.y = 0
    }
    return position
  }
}
var router = new VueRouter({
  mode: 'history',
  scrollBehavior,
  routes,
  linkActiveClass: 'active'
})

export default router
```
となっているとしたら

config/dev.env.js

```javascript
module.exports = merge(prodEnv, {
  NODE_ENV: '"development"',
  ROOT_BASE: '""' // new!
})
```

config/prod.env.js

```javascript
module.exports = {
  NODE_ENV: '"production"',
  ROOT_BASE: '"GITHUB_PROJECT_NAME/"' // new!
}
```

src/router/router.js

```javascript
var router = new VueRouter({
  mode: 'history',
  base: process.env.ROOT_BASE, // new!
  scrollBehavior,
  routes,
  linkActiveClass: 'active'
})

```

を追加する。
この設定で```https://USER_NAME.github.io/GITHUB_PROJECT_NAME```からの遷移で、GITHUB_PROJECT_NAME dirが無視されるは問題は解決。

## それから

しかし、
```https://USER_NAME.github.io/GITHUB_PROJECT_NAME/about```ページへ直接アクセスすると404ページになる。
SPAなのでabout.htmlの実態は用意していない。そのためサーバ側の設定が必要になる。

[GitHub Pages and Single-Page Apps](https://dev.to/_evansalter/github-pages-and-single-page-apps)

ここにあるように404ページにリダイレクトを仕込むかなんやかんやする必要がありそう。
もうnuxtで作った方がいいんじゃないのか感があるが、後日対応する。
esa.io > Excelの情報の保持 > Markdown化 | 非表示列の除外

情報共有サービスesa.ioにはEXCELの表をそのままMarkdownにする便利な機能がある。

使ってみた。

Excelファイルとしては以下のような表示のものを持ってくる。

![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/76a0420e-f819-952b-17dc-4f41e6f36b3d.png)

- Excelにて範囲を指定してCtrl + c
- esa.ioにてCtrl + v

esa.ioでは以下のようになる。
![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/ef1f1a8b-79c1-7371-1df9-7d6992cbc67d.png)

https://esa-pages.io/p/sharing/6206/posts/5278/bed845256db8149a4a9f.html

### 備考

Markdownにすることで検索できるようになる。
これは重宝する。

一方で、フォントの色やセルの色などはなくなる。
esa.ioのサービスとして色付けまでしてほしいかというと、そうは思わない。
(Markdownテキストの編集時に扱いにくくなるため）

色情報が欲しい場合は、別途、画像としてペーストすれば良いだろう。

### 非表示列の除外
(追記 2018/04/06)

非表示にした列は上記のコピペでは除外される。

Excelの見た目に合わせてMarkdown化されるのが良い点と思われる。

### 関連
(追記 2019-03-13)

- [onlineTool > Table Convert Online > 様々な形式からのimport, 様々な形式へのexport | UI > 項目の連続入力](https://qiita.com/7of9/items/12fe5d36221bc194265f)
    - Excel, HTML, Markdownなどから/などへの変換
Railsで複数行一気にInsert

メモとして残しておきます


## 普通に複数行Insertするとき

```sql

INSERT TO テーブル (id, name) VALUES (1, hoge1)
INSERT TO テーブル (id, name) VALUES (2, hoge2)
INSERT TO テーブル (id, name) VALUES (3, hoge3)

```

複数行挿入を一気に投げたいときに上のようにSQLを投げるとパフォーマンスが悪いのはわかると思います。

ActiveRecodeで書いた時おそらくこんな感じになると思います
(ざっくり頭の中で考えたことなので間違ってるかもしれません、、、)

```ruby

(配列???).each do |data|
   Model.create(data)
end

```

でもこれを下記のようにSQLを投げる方法について書いていきます。

```sql

INSERT TO テーブル名 (id, name) VALUES (1, hoge1),(2, hoge2),(2, hoge2)

```

## `gem` を入れる

下記のgemをGemfileに書いて `bundle install` します

```
gem 'activerecord-import'
```

## 書き方

```ruby
     imageArray = []
     params = なんかの配列

     params.each do |data|
       array << モデル.new(なんかのモデル)
     end
     
    モデル.import(array)
```


これで複数行のInsertを一回のSQLで実行することができます。
seleniumで、jsエラーと500エラーを探す。

# seleniumでエラー探し

## やりたいこと
サイトを修正した際に、今までのページにエラーが起きてないかを確認したかった。
しかしながら、自動テストが開発環境上できなかったので、とりあえずseleniumで、エラーが出てるページがないか探すようにした。

## 環境
python 3.6.0
mac

## プログラム

```pageCheck.py
import urllib.request
import ssl

from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

chrome_options = webdriver.ChromeOptions()
prefs = {"profile.default_content_setting_values.notifications" : 2}
chrome_options.add_experimental_option("prefs",prefs)

# エミュレーション利用時はこちらをコメントアウト
# mobile_emulation = { "deviceName": "Nexus 7" }
# chrome_options.add_experimental_option("mobileEmulation", mobile_emulation)

# こちらでLogTypeとか設定します。
# https://github.com/SeleniumHQ/selenium/wiki/Logging
caps = DesiredCapabilities.CHROME
caps['loggingPrefs'] = {'browser': 'SEVERE'}

driver = webdriver.Chrome(chrome_options=chrome_options, desired_capabilities=caps)

# HTTPS対応
ssl._create_default_https_context = ssl._create_unverified_context

# ここにチェックしたいURLを記載してください。
urls = [
    'https://www.google.co.jp/'
]

for url in urls:
    # レスポンスコードを取得
    req = urllib.request.Request(url)
    try:
        urllib.request.urlopen(req)
    except urllib.error.HTTPError as e:
        print(url, 'HTTP Response Error', e.code)
        continue
    
    # JSエラーを取得
    driver.get(url)
    for entry in driver.get_log('browser'):
        print(url, entry['message'])


driver.close();

```

```requirements.txt
certifi==2017.7.27.1
chardet==3.0.4
get==0.0.21
idna==2.6
post==0.0.13
public==0.0.38
query-string==0.0.12
request==0.0.13
requests==2.18.4
selenium==3.5.0
setupfiles==0.0.50
urllib3==1.22
```


## メモ
スクロールしてデザインの目視確認したい時用

```pageScroll.py
import ssl
from selenium import webdriver
from time import sleep

chrome_options = webdriver.ChromeOptions()
prefs = {"profile.default_content_setting_values.notifications" : 2}
chrome_options.add_experimental_option("prefs",prefs)
driver = webdriver.Chrome(chrome_options=chrome_options)

ssl._create_default_https_context = ssl._create_unverified_context

urls = [
    'https://www.yahoo.co.jp/'
]

for url in urls:
    driver.get(url)
    
    SCROLL_PAUSE_TIME = 0.1
    new_height = 0
    scroll_once = 200
    last_height = driver.execute_script("return document.body.scrollHeight") - scroll_once

    while True:
        next_height = new_height + scroll_once

        # Scroll down to bottom
        driver.execute_script("window.scrollTo(" + str(new_height) + ", " + str(next_height) + ");")

        # Wait to load page
        sleep(SCROLL_PAUSE_TIME)

        if new_height > last_height:
            break
        new_height = next_height
    

driver.close()
```

### 参考
https://watirmelon.blog/2016/06/29/using-webdriver-to-automatically-check-for-javascript-errors-on-every-page-2016-edition/
https://stackoverflow.com/questions/20986631/how-can-i-scroll-a-web-page-using-selenium-webdriver-in-python
Javascriptで簡単に更新！ヘッダーやフッターなどの共通部分を簡単に更新する方法！ 

![qiita01ai.jpg](https://qiita-image-store.s3.amazonaws.com/0/163786/c61a68c1-a7b2-c9a1-c4f1-8c1fd988c8f3.jpeg)

cms以外のhtmlで作った静的なサイトの共通部分、ヘッダーやフッターサイドバーなどを修正するとき一部分だけ変更する場合でも全ページのソースを修正しなければならないので大変です。
そこで何か一括で変換できるような方法がないかと思い、Javascriptで一括変換できるような方法を紹介します。

別にDreamweaverのtemplate機能やPHPで作成してもいいのですが、そもそもDreamweaverだとAdobeを購入しなければ行けないし、PHPだと「〜.php」になったり、html上でphpを使えるようにする為.accessの設定をしたりとかでサーバーごとの設定があるので今回はJavascriptを選択しました。

# Javascriptで共通化していこう

まず、ベースとなるHTMLにJavascriptを読み込めるようにします。

```html
<script src="main.js"></script>
```
そして共通化する部分に下記を記述。

```html
<script>header();</script>
```

次に読み込むJavascriptを作ります。
今回はajaxを使用した方法になります。

参考：
[jQuery リファレンス jQuery.ajax](http://www.jquerystudy.info/reference/ajax/ajax.html)
※`url: "header.html",`が読み込むHTMLファイルです。

```ruby:js
function header(){
	$.ajax({
		url: "header.html",
		cache: false,
		success: function(html){
			document.write(html);
		}
	});
}
```

パスを指定した作りになるなら

```html
<script>header('../');</script>
```
```js
function header(rootDir){
    $.ajax({
        url: rootDir + "header.html",  // 読み込むHTMLファイル
        cache: false,
        async: false,
        dataType: 'html',
        success: function(html){
            html = html.replace(/\{\$root\}/g, rootDir); //header.htmlの{$root}を置換
            document.write(html);
        }
    });
}
```

参考：
[更新するのが面倒！サイトの共通部分を簡単に作る様々な方法](http://webdrawer.net/other/templates.html)

共通化ファイルが複数あるならincludeフォルダを作りまとめた方がわかりやすいです。

```directory
index.html
style.css
main.js
include
 - header.html
 - footer.html
 - sidebar.html
```

フォルダをまとめる際はディレクトリーを気をつけてください。

```js
function header(rootDir){
    $.ajax({
        url: rootDir + "include/header.html", // ディレクトリー変更
        cache: false,
        async: false,
        dataType: 'html',
        success: function(html){
            html = html.replace(/\{\$root\}/g, rootDir); 
            document.write(html);
        }
    });
}
```

リンクがある場合は「{$root}」を追加します。

```html
<a href="{$root}index.html">TOP</a>
```

出力されると下記のようになります。
デメリットとしてはscript部分が余分なソースになる、ブラウザーのjsを切っている場合表示されないなどがあります。

```html
<script>header('../');</script>
<header>
	<ul>
		<li><a href="{$root}index.html">TOP</a></li>
		<li><a href="{$root}about.html">ABOUT</a></li>
		<li><a href="{$root}service.html">SERVICE</a></li>
		<li><a href="{$root}contact.html">CONTACT</a></li>
	</ul>
</header>
```

# 追記
この記事を書いた頃より開発の状況は随分と変化し現在はNuxt.js(Vue-CLI)を仕様しています。

Vue.jsベースで作りたい → Nuxt.js

Vue.jsあんまり使わない → GulpやGrunt

↑が使えないときこの記事のやり方になるのではないかなと思います。
digdagを使ってhive形式のクエリをinsertしようとするとエラーが出た話

`digdag`を使ってログから中間テーブルを起こそうとした時に起きた話です。
`hive`の独特な書き方みたいなところで引っかかりました。

# **結論**

#### **`with`句が終わって実際に`select`するところに**
#### **`-- DIGDAG_INSERT_LINE`を突っ込め！**

# **やろうとしたこと**

すでに`TD`上にある大量レコードのテーブルから、サマリーをした中間テーブルを作ろうとしました。

##### before（実データでは`time`は`timestamp`ではなく`long`が入ってます）
| user_id | event | time |
|:--|:--|:--|
| 1 | add | 2017/12/17 06:34 |
| 1 | add | 2017/12/17 06:35 |
| 1 | change | 2017/12/17 06:36 |
| 1 | add | 2017/12/17 06:37 |
| 1 | delete | 2017/12/17 06:49 |
| 1 | add | 2017/12/18 06:50 |

##### after
| user_id | event | date | count |
|:--|:--|:--|--:|
| 1 | add | 2017/12/17 | 3 |
| 1 | add | 2017/12/18 | 1 |
| 2 | add | 2017/12/17 | 1 |

こんな感じ。


##### 抽出クエリ
```sql:user_event_cnt.sql
with log as (
  select
    user_id
    ,event
    ,td_time_format(time,'yyyy-MM-dd','jst') as date
  from
    event_log
)

select
  user_id
  ,event
  ,date
  ,count(1)
from
  log
group by
  1,2,3,
```

なんてことはないですね。
実際にtd上で実行しても通りました。

# **digってみる**
```sql:user_event_cnt.dig
timezone: Asia/Tokyo

+transport_raw:
  _export:
    td:
      source_db: test
      to_db: event_log

  +drip_user_event_cnt:
    td>: queries/user_event_cnt.sql
    database: ${td.source_db}
    engine: hive
    create_table: ${td.to_db}.user_event_cnt
```

`td wf run --rerun user_event_cnt.dig`
えいっ！

…

あれエラー出ましたね。
`FAILED: ParseException line 2:0 cannot recognize input near 'with' 'log' 'as' in select clause
MapReduce time taken: 0.195 seconds`

予約語関連でエラー？そんなバカな

というわけで、もろもろ調べてみました。

# **原因判明**
`digdag`の`create_table`コマンドが何をしているかというと、
指定した`sql`の前にこの一文を発行しているようです。
```INSERT OVERWRITE TABLE `test `.`user_event_cnt`
```
`INSERT`の後に`WITH`句がおけないという`hive`のローカルルールに引っかかりエラーが起きていました。

実際に`select`をするところの前に`-- DIGDAG_INSERT_LINE`を記述してあげないといけません。

```sql:user_event_cnt.sql
with log as (
  select
    user_id
    ,event
    ,td_time_format(time,'yyyy-MM-dd','jst') as date
  from
    event_log
)

-- DIGDAG_INSERT_LINE

select
  user_id
  ,event
  ,date
  ,count(1)
from
  log
group by
  1,2,3,
```

これでおっけい！
実行結果もうまくいきました。

# **余談**
`td`といえば、クエリを`presto`と`hive`で選べますが、`presto `ではどうなってるでしょうか。

`presto`では、`with`の前で`insert`が記述されても特に問題なく実行されます。
なので気にせずに`insert`とできると思います。

`hive`でクエリ書き換えたけど動かねーぞ！となったら、ぜひ試してみてください。
EditorConfigで心の健康を保とう

## EditorConfigとは

エンジニアの心の健康を保つのに有効なもの。

ざっくり言うと、**コードのスタイルを統一するためのエディタ横断プラグイン**

.editorconfigというファイルを置けば、記載されたconfigに基づいて文字コードや改行コード、インデントサイズやインデントスタイルを自動で直してくれる優しいやつ。

EditorConfigを利用することで、

* プロジェクト移動するときエディタの設定いじるのめんどい問題
* そもそも細かいコード規約までexcelやスプレッドシートで管理するのつらい問題
* インデントスタイルはtabなのかspaceなのか問題
* インデントサイズは2つなのか4つなのか問題
* ファイルごとに改行コードが違う問題
* コードレビュー時に超どうでもいいこと(行末に無駄なspaceあるよなど)を指摘する時間が勿体無い問題

以上の悲しみに溢れる不毛な争いを根絶できる。

**参考リンク(というかこっち見ればこの記事見ないでも良い気もする)**

* [Qiita - どんなエディタでもEditorConfigを使ってコードの統一性を高める](https://qiita.com/naru0504/items/82f09881abaf3f4dc171)

## sublime,vimにおけるインストール方法

たまたま身の回りにsublime派とvim派しかいないのでそれぞれのインストール方法を書いておく。

先ほど挙げた[qiitaの記事](https://qiita.com/naru0504/items/82f09881abaf3f4dc171)を見れば大体わかると思うが一応補足として。

* sublimetext3
    * package controllで普通にinstallすればOK
    * パッケージコントロールって何って人は[Sublime Text 3 の参考書（実践編）Wiki](http://futago-life.com/sublime-text3-wiki/first-step/install/package-control)を参照
        * Install Package -> Editor Config

* vim
    * NeoBundleを利用
        * わからない場合は[vim NeoBundleによるプラグイン管理](http://kaworu.jpn.org/kaworu/2012-10-01-1.php)にまとまっているので参照
    * .vimrcのbundle管理箇所に以下を追記

```.vimrc
NeoBundle 'editorconfig/editorconfig-vim'
```

* 追記後Vim立ち上げて:NeoBundleInstall


### 補足：vim使ってるけどneobundleとか全然よくわかんない人用

**もう全然わかんないしvimrcなんて書き換えたことないvimmer向け手順**

* neobundleのインストール(mac向け。windowsはごめんなさい)

```
$ mkdir -p ~/.vim/bundle
$ cd ~/.vim/bundle
$ git clone git://github.com/Shougo/neobundle.vim ~/.vim/bundle/neobundle.vim
```

* .vimrcの記述

```
$ vim ~/.vimrc
```

以下の内容をペースト(余計なものも入ってるけど気にしないで)

```.vimrc
:set clipboard=unnamed
:syntax on
set nocompatible
filetype off            " for NeoBundle

if has('vim_starting')
        set rtp+=$HOME/.vim/bundle/neobundle.vim/
endif
call neobundle#begin(expand('~/.vim/bundle'))
NeoBundleFetch 'Shougo/neobundle.vim'
NeoBundle 'editorconfig/editorconfig-vim'
call neobundle#end()

filetype plugin indent on       " restore filetype
```

* bundleのインストール

```
$ vim
:NeoBundleInstall
```

## .editorconfigファイルの一例

* このファイルをプロジェクトのリポジトリに置いておけばpullした人のエディタに自動的に適用される
* 今回はphpしか扱わないプロジェクトに利用したので、php用しか書いてない。
* 拡張子ごとに設定を記述できるので、jsの場合はindent_size2とかも追記できる。


```
# This file is for unifying the coding style for different editors and IDEs
# editorconfig.org

# PHP PSR-2 Coding Standards
# http://www.php-fig.org/psr/psr-2/

root = true

[*.php]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 4

```

これで世界の平和は保たれた。

やったね！！！！！！！！！！！
『ゼロから作るDeep Learning』3章メモ（PHPで実装）

- 手書き文字認識
- データはMNISTを使用
    - テスト用のデータ（10000個）
        - t10k-images.idx3-ubyte：画像
        - t10k-labels.idx1-ubyte：ラベル
    - 学習用のデータ（60000個）
        - train-images.idx3-ubyte：画像
        - train-labels.idx1-ubyte：ラベル
    - データの中身を確認するスクリプト
        - https://github.com/kuredev/php-deep-learning-from-scratch/blob/master/3/test-mnist.php
- 3層のニューラルネットワーク
    - 本のサンプルでは、重みやバイアス等はあらかじめ与えられていた（sample_weight.pkl）ため、引っこ抜いてテキストで保存してPHPから使った
    - https://github.com/kuredev/php-deep-learning-from-scratch/tree/master/3/fixed
- 実装
    - https://github.com/kuredev/php-deep-learning-from-scratch/tree/master/3
    - コンソールの出力に判定した数値を出力される
    - neural-network.php#38Lのfor文のところで、判定する数字の範囲を記載する（一気に10000件やったらログファイルでいっぱいになっちゃったので適当に調整した）
    - あげてるスクリプトで判定すると正解率92.07%だった
    - 本の通りだと93.52%になるらしいので、微妙に何かが違うのかもしれないけど、深追いはしていない
jsonで受け取った値を、classのthisにしてしまう

Vue.jsの案件で用意したAPI叩いた時に得られた値を、`_.forEach`を使って`this`として扱うするclassを用意した。

---

lodashを使える用意しておく。

```
npm i lodash --save-dev
```

jsで読み込んでおく。

```js
import _ from 'lodash';
```

得られるjson

```js
var jsonSmaple = {
  "id": "0001",
  "type": "donut",
  "name": "Cake",
  "ppu": 0.55,
  "batters":
  {
    "batter":
    [
      { "id": "1001", "type": "Regular" },
      { "id": "1002", "type": "Chocolate" },
      { "id": "1003", "type": "Blueberry" },
      { "id": "1004", "type": "Devil's Food" }
    ]
  },
  "topping":
  [
    { "id": "5001", "type": "None" },
    { "id": "5002", "type": "Glazed" },
    { "id": "5005", "type": "Sugar" },
    { "id": "5007", "type": "Powdered Sugar" },
    { "id": "5006", "type": "Chocolate with Sprinkles" },
    { "id": "5003", "type": "Chocolate" },
    { "id": "5004", "type": "Maple" }
  ]
}
```


jsonを受け取った時、`_.forEach`を使って`this`に入れて行く汎用Classを用意する。

```js
class BaseEntity {
    constructor(attributes){
      this.from(attributes)
    }

    from(attributes){
      _.forEach(attributes, (value, key) =>{
        this[key] = value;
      });
    }
}
```

jsonのkeyをthisにさせるClass

```js
class Pancake extends BaseEntity{
  displayConsole(){

    console.log(this);

    let len = this.topping.length;
    let i = 0
    for(i; i< len; i++){
      console.log(this.topping[i].type);
    }
  }
}

```

```js
var test = new Pancake(jsonSmaple);
test.displayConsole();
```
<img width="581" alt="スクリーンショット 2018-01-17 11.55.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/206790/3352baf5-35bf-b5fb-b699-09694849851f.png">


----



・使わせていただいたjson
[https://adobe.github.io/Spry/samples/data_region/JSONDataSetSample.html](https://adobe.github.io/Spry/samples/data_region/JSONDataSetSample.html)