OmniAICreator/Qiita-1.07M huggingface dataset:
vagrant上でcreate-react-appのhot-reloadが効かない場合の対応

create-react-appでhot-reloadが効かずにはまったのでメモ

# 環境
Host OS: Windows 10
Guest OS: CentOS 7.2 
create-react-app 1.5.2
Vagrant 2.0.2
Webpack 3.11.0

# 手順
```bash
$ create-react-app foo
$ cd foo
$ npm start
# Host OSから起動する場合、localhost:3000で普通にhot-reloadが効く
# Guest OS側にsshログインしてから起動すると、{vagrantのネットワークip}:3000でアクセスできるがhot-reloadが効かない

# その場合は環境変数に以下を設定してから起動
$ export CHOKIDAR_USEPOLLING=true
$ npm start
```

# それでも駄目だった場合
- react, create-react-app, webpackあたりのバージョンがかなり古い
    - そもそも昔はデフォルトで有効ではなかったとのこと
- エディタのSafe write機能が有効なら無効にする（未確認）
    - JetBrainsのIDEとかにある機能らしいです
- 環境変数書き換えたくない
    - echo CHOKIDAR_USEPOLLING=true >> .env

# 理由
仮想環境でファイルの変更をwatchする場合の問題らしく、dockerやbabelの記事も引っかかります
box側か共有フォルダの設定次第な気もしますが確認中

# ハマったポイント
- 初めてのreact(create-react-app)で原因の切り分けに時間がかかった
- 検索すると、古い記事でhot-reloadがデフォルト対応ではなかったときの記事が引っかかった

# 迷走してた時に手を出したもの
- npm run ejectしてwebpack.config.dev.jsのあれやこれを書き換え
- module.hotを判定して処理書き換え

```
if (module.hot) {
  module.hot.accept('./App', () => {
    ReactDOM.render(
      <Provider store={store}>
        <App />
      </Provider>,
      document.getElementById('root'),
    );
  });
}
```

# 参考
[create-react-appをdockerを使って試したメモ](https://qiita.com/hibohiboo/items/3c895c44b1f38eb353af)
[React auto reload with vagrant](https://stackoverflow.com/questions/42025225/react-auto-reload-with-vagrant)
Python から MMDモデルを動かせるライブラリを作った。

前回のこと.
https://qiita.com/shirobu2400/items/18988c41370062510e60

# Python から MMD モデル動かしたい
Python からメソッドを使ってpmd, pmx を動かしたい。
boost-python で C++ のライブラリを弄れるらしい・・・

# MMDPIPY 
公開中です。
https://github.com/shirobu2400/mmdpipy
RaspberryPi でMMDのファイルを表示、動作させたい！

そこそこ前に作り始めたものですが...

# MMDPI
公開中です。
https://github.com/shirobu2400/mmdpi
![mmdpi_screen.png](https://qiita-image-store.s3.amazonaws.com/0/204794/fb6635f3-a4bc-d666-84a2-ec9f5ff268f4.png)
こんな感じのことができる。

# 使い方(ビューア)
mmdpiv -p "モデルパス" -v "モーションパス"

# メソッド群(C++ ライブラリ)
<table>
<tr><td>int mmdpi::load( const char* model_name ) </td><td> モデルファイル(.pmd, .pmx)の読み込み(PATH で指定)</td></tr>
<tr><td>int mmdpi::vmd_load( const char* file_name ) </td><td> モーションファイル(.vmd)の読み込み(PATH で指定)</td></tr>
<tr><td>void mmdpi::draw( void ) </td><td> 表示</td></tr>
<tr><td>void mmdpi::set_bone_matrix( uint bone_index, mmdpiMatrix& matrix ) </td><td> 指定されたボーンのindexと対応するボーンの姿勢行列を matrix で上書き。</td></tr>
<tr><td>void mmdpi::set_bone_matrix( const char* bone_name, mmdpiMatrix& matrix ) </td><td> 指定されたボーンの名と対応するボーンの姿勢行列を matrix で上書き。</td></tr>
<tr><td>mmdpiVmd* mmdpi::get_vmd( int index ) </td><td> vmd情報の取得。indexはvmdを複数読み込んだうちの読み込んだ順番でvmdを変更できる。</td></tr>
<tr><td>*mmdpi::get_vmd( int index ) += frame </td><td> frame 分だけモーションフレームを進める </td></tr>
<tr><td>*mmdpi::get_vmd( int index ) = frame </td><td>指定されたフレームにジャンプ </td></tr>
<tr><td>mmdpi::get_vmd( int index )->is_end() </td><td>モーションの終了判定 </td></tr>
<tr><td>void　mmdpi::set_fps( int fps ) </td><td> モーション実行時のfps を指定。</td></tr>
<tr><td>void mmdpi::set_projection_matrix( const GLfloat* p_projection_matrix ) </td><td> プロジェクション行列の指定。</td></tr>
<tr><td>void mmdpi::set_projection_matrix( const mmdpiMatrix_ptr p_projection_matrix ) </td><td> プロジェクション行列の指定。</td></tr>
</table>

# コンパイル
cmake . (-Dpi=on ラスパイモード -Dbullet=on Bullet Physics インストール時のみ物理演算可)
make -j N (Nは並列スレッド数)
make install <= お好みで

# ここからは開発のあれこれ
# 動機 
RaspberryPi で 3DCG をやってみたい。
RaspberryPi 上で3DCG 関連のことができたらうれしい！ <= 手軽に！
やっぱり、可愛らしいモデルを躍らせたい！
3DCG の勉強したい！!
![mmdpi_screen.png](https://qiita-image-store.s3.amazonaws.com/0/204794/fb6635f3-a4bc-d666-84a2-ec9f5ff268f4.png)
上みたいなことしたい

# 問題発生
ラズベリーパイは OpenGL ES 2.0 にしか対応してないらしい。。
=> 頂点シェーダで頂点テクスチャ使えないらしい！
各シェーダ共通でアクセスできるメモリがない。
頂点と関連するボーンの情報をどうしよう。。。
(OpenGL でMMD 表示したという記事でよく見るのは頂点テクスチャ上にボーンの情報を置いて各頂点シェーダから共通でアクセスするらしいのに・・・)
モデルをバラバラにして(細かい部分に分けて)頂点シェーダで使う GPU キャッシュに収めればいけるかも。。

# 完成
何とかそれっぽい動きをしているのでいいのかな・・・？
こんなポプテピピックは嫌だ

## 元ネタ

* [ランダム出力で「ポプテピピック」が完成したら竹●房を破壊するJavaScript登場　文字を眺めて竹生会をドゴォ！ \- ねとらぼ](http://nlab.itmedia.co.jp/nl/articles/1803/27/news124.html#utm_source=niconico&utm_medium=feed&utm_campaign=20180327-094&utm_term=nl&utm_content=link)
* [「ポ」「プ」「テ」「ピピック」をランダムに出力して「ポプテピピック」が完成したら竹●房を破壊するJavaScript](https://renidentia991.bitbucket.io/pptp.html)

## いままで書いたやつのまとめ

* [ズンドコキヨシについて \- Qiita](https://qiita.com/shinderuman@github/items/027d13625e20f29114d7)

## 今回のいやなやつ

* 肝心の破壊するAAめんどかったから省いた
* **requireでループってキモくねってのをやってたのに気づいたらただの再帰になってた**

```index.php
<?php
function happyEnd($p) {
    if (preg_match('/ポプテピピック/', $p)) {
        echo 'happy end!!', PHP_EOL;
        exit();
    }
}
function りくわいあ() {
    global $p;
    require [
        'po.php',
        'pu.php',
        'te.php',
        'pipikku.php',
    ][mt_rand(0,3)];
    usleep(10000);
    happyEnd($p);
    りくわいあ();
}
りくわいあ();
```

```po.php
<?php
$p .= 'ポ';
echo 'ポ';
```

```pu.php
<?php
$p .= 'プ';
echo 'プ';
```

```te.php
<?php
$p .= 'テ';
echo 'テ';
```

```pipikku.php
<?php
$p .= 'ピピック';
echo 'ピピック';
```
新型iPad 9.7とiPad Pro 9.7の違いまとめ

## まえふり
2018/03/28 0:00に教育分野向けイベントでAppleが新製品を発表をしました。
iPad 9.7としてApple Pencil対応と低価格で販売が魅力的ですが、すでに過去に出て入るiPad Pro 9.7との違いが何なのか気になったのでザッと作りました。

※おそらく、どこかの企業さんが似たようなやつ作ると思うので、あくまでそれまでのものとして見るものです。

## 比較表

製品名| 9.7インチiPad Pro | New 9.7インチiPad
---|---|---
画面サイズ| 9.7型 | 9.7型
ディスプレイ解像度（画素密度）| 2048×1536ピクセル （約264ppi） | Retinaディスプレイ 2048x1536ピクセル （264ppi）
プロセッサ| A9X | A10
モーションプロセッサ| M9 | M10
ストレージ| 32／128／256GB | 32／128GB
無線LAN| IEEE802.11a/b/g/n/ac （MIMO） | IEEE802.11a/b/g/n/ac （MIMO）
Bluetooth| Bluetooth 4.2 | Bluetooth 4.2
FaceTime HDカメラ（前面）| 500万画素（720p 動画） | 720p HDビデオ撮影
Retina Flash| ○ | ○
iSightカメラ（背面）| 1200万画素 （4K 3840×2160ピクセル 動画） | 1200万画素 （4K ?）
Live Photos| ○ | ○
スローモーションビデオ| 1080p（120fps）／720p（120fps） | 1080p（120fps）／720p（120fps）
内蔵スピーカー| ステレオ（4スピーカー） | ステレオ（2スピーカー）
内蔵マイク| デュアル | ?
インタフェース| Lightning、Smart Connector、ヘッドフォン（3.5ミリステレオミニ） | Lightning、Smart Connector、ヘッドフォン（3.5ミリステレオミニ）
Apple Pencil| ○ | ○
Smart Keyboard| ○ | ×
センサー| Touch ID、デジタルコンパス、3軸ジャイロ、加速度、環境光、GPS、気圧計 | Touch ID、3軸ジャイロ、加速度センサー、気圧計、環境光センサー
バッテリー駆動時間| 最大10時間 | 最大10時間
幅×奥行き| 240×169.5ミリ | 240×169.5ミリ
厚さ| 6.1ミリ | 7.5ミリ
重量（Wi-Fi／Wi-Fi＋Cellular）| 437／444グラム | 469／478ララム
カラーバリエーション| ゴールド、スペースグレイ、シルバー、ローズゴールド | ゴールド、スペースグレイ、シルバー
税抜き価格（WiFi/Cellular）| 32GB:¥66,800/¥82,800、128GB:¥84,800/¥100,800、256GB:¥102,800/¥118,800 | 32GB:¥37,800/¥48,800、128GB:¥52,800/¥63,800
vue-cliでvueを始めてみる

vue-cliをインストール。

```
$ npm install -g vue-cli
```

バージョン確認。

```
$ vue -V
2.9.3
```

プロジェクトを作成。

```
$ vue init webpack hoge
```

対話形式で色々聞かれるが全部yes。

プロジェクトディレクトリに移動し、`npm run dev`コマンドを叩く。

```
$ cd hoge
$ npm run dev
```

するとlocalhost:8080/でサーバが立ち上がる。アクセスしてみると、welcomeページが表示される。
Uniqe関数っぽいものを作ってみる

C++にはUniqe関数という便利なものがあるよう。
例えば以下に二つの配列があるとして、

```C++:
int a[5] = { 3,2,5,7,2 };
int b[5] = { 6,2,3,5,3 };
```

Uniqe関数に入れると以下のような配列が返ってくる。

```C++:
c[2,3,5,6,7];
```

今回はそんなUniqeっぽい感じのものを作ってみた（配列渡せない色々アレだけど）
まあ実際は仕事で必要に迫られたから作ってみただけだけど

以下、ソース

```C++:main.cpp

#include <stdio.h>
#include <stdlib.h>

void uniqe(int *a,int alen,int *b,int blen) {
	//結果格納用配列、0で初期化
	//本当は可変（vector）とかがいいんだろうけど、今回は固定
	int c[10] = {};
	int work[10] = {};

	int i, j;
	int tmp;
	int cnt;

	for (i = 0;i < alen;i++) work[i] = a[i];
	for (i = alen;i < (alen + blen);i++) work[i] = b[i - blen];

	//一つ目の配列の並び替え
	for (i = 0;i < (alen+blen);i++) {
		for (j = (alen+blen) - 1;j > i;j--) {
			if (work[j] < work[j - 1]) {
				tmp = work[j];
				work[j] = work[j - 1];
				work[j - 1] = tmp;
			}
		}
	}
	cnt = 0;
	for (i = 0;i < (alen + blen);i++) {
		if (i <= 0) {
			c[i] = work[cnt];
			cnt++;
		}else {
			if (c[i - 1] < work[cnt]) {
				c[i] = work[cnt];
				cnt++;
			}else if(cnt>(alen+blen)){
				c[i] = -1;
			}else {
				i--;
				cnt++;
			}
		}
	}
	for (i = 0;i < (alen + blen);i++) printf("[%d]", c[i]);printf("\n");
}

int main() {
	//今回はあらかじめ配列数が分かっているものとする
	int a[5] = { 3,2,5,7,2 };
	int b[5] = { 6,2,3,5,3 };

	int c[10];

	int i;

	for (i = 0;i < 5;i++) printf("[%d]", a[i]);printf("\n");
	for (i = 0;i < 5;i++) printf("[%d]", b[i]);printf("\n");

	uniqe(&a[0],5,&b[0],5);

	system("pause");
	return 0;
}
```
行ごとに要素の割合を計算する（python,R）

#行ごとに要素の割合を計算する（python,R）

### はじめに
初投稿です。

独学でpythonとR両方習得する必要があったため、
<b>実業務で使う処理</b>を、
python,Rそれぞれでまとめてみました。
（おすすめの書き方/別解などあれば、是非教えてください！）

## テーマ
今回のテーマは、考え方はシンプルなものの、なぜか個人的に毎回悩んでしまう、
<b>データフレームに対して、行ごとに要素の割合を計算する</b>
コードになります。

excelやtableau等での加工ももちろん可能ですが、
加工の手順をコードとして残せるメリットもあると考え、このテーマにしました。

### 本題
以下のデータフレームを例に挙げます。
（indexのid列は、イメージのために付けており、コードでは省略しています）

id| a | b | c |
|:-:|:-:|:-:|:-:|
d| 1 | 11 | 21 |
e| 2 | 12 | 22 |
f| 3 | 13 | 23 |

各行の合計を1とした際の、a,b,c各要素の割合を出すためのコードです。
（使用例: id=dにおけるaの割合を、id=e,fにおけるaの割合と比較したい　など）

実際に業務で集計するデータには、
idや属性など、要素に含めたくないものが付くことも多いかと思いますが、
今回はシンプルに、全て要素として扱う前提で進めます。


## コード
### pythonの場合（pandas）

```python:code
import pandas as pd
# データフレーム作成
df = pd.DataFrame({'a':[1,2,3],'b':[11,12,13],'c':[21,22,23]})

# 行ごとに計算
df_kekka = df.apply(lambda x:x/sum(x),axis=1)
```


```python:結果
a	b	c
0.030303	0.333333	0.636364
0.055556	0.333333	0.611111
0.076923	0.333333	0.589744
```
### Rの場合

```R:code
# データフレーム作成
df <- data.frame(a=c(1:3),b=c(11:13),c=c(21:23))

# 計算
data.frame(df/rowSums(df))

```

```R:code_別案
#library(purrr)でも。magrittr（の%>%）をよく使うため、まるっと
library(tidyverse)

# データフレーム作成
df <- data.frame(a=c(1:3),b=c(11:13),c=c(21:23))

# 計算　繰り返し処理のイメージに近くなる
df %>%
  map_df(~.x/rowSums(df))
```


```R:結果
a	b	c
0.03030303	0.3333333	0.6363636
0.05555556	0.3333333	0.6111111
0.07692308	0.3333333	0.5897436
```

## 終わりに
すごくシンプルな内容ですが、少しでも実務にお役立ちできれば嬉しいです。
ありがとうございました！
OpenCVforUnity.Matの四則演算

#エラー
四則演算ができない。
足し算したら中身が空っぽになる。
それぞれの要素はちゃんとある。
#原因
それぞれのMatのtypeが異なると中身が死ぬ。
エラーログが出ないあたり害悪。
さくらVPS FTP接続

vsftpdをインストールする。

```
$ sudo yum install vsftpd
```

起動。

```
$ systemctl start vsftpd
```

システム起動時に自動起動するように設定。

```
$ systemctl enable vsftpd
```

firewall設定。

```
$ sudo firewall-cmd --add-service=ftp --permanent
```

設定ファイル編集。

```
anonymous_enable=NO
ascii_upload_enable=YES
ascii_download_enable=YES
userlist_enable=YES
userlist_deny=NO
tcp_wrappers=NO
local_root=/var/www/html/
```

`userlist`ファイルにftp接続するユーザを追加する。

```
hoge
```

ftp接続するディレクトリの所有者を変更する。

```
$ sudo chown -R hoge /var/www/html/
```
ping疎通確認結果を機械的に判定する

## 結論
pingコマンドの終了ステータスが0であれば疎通成功、と判定しよう

### コマンド
```
ping (対象ホスト) -w (タイムアウト時間(秒)) -c 1
```

### ping オプション解説
- `-w`
    - タイムアウト時間
    - 指定した時間を超えると、pingレスポンスを取得できていなくても強制的に終了する
- `-c`
    - 指定した回数レスポンスを取得できたらok
    - 1を指定したからといって1回しかpingが送信されないのではない
    - pingリクエスト自体は基本1秒に1回送られている(別オプションで間隔の調整は可能)

## Pythonバージョン
```Python
#! /usr/bin/python
import subprocess
def is_connectable(host):
	ping = subprocess.run(["ping", "-w", "1", "-c", "1", host], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
	return ping.returncode == 0
```


## 参照
[PythonでOSのPingコマンドを叩いて死活監視する - hadacchi blog](https://www.hadacchi.com/wp_blog/?p=2220)
[[Python] Pingコマンド実行 : Edo::World:: cctv Blog](http://edo.blog.jp/archives/1790336.html)
Capybaraでheadless chromeと戯れるための覚書。spider on ruby

いまいち手になじまないので、試行錯誤しているところ。
scraperはpythonが強いのかしら。

phantomjsよりheadless chromeのほうが問題が少ないらしいので、chromeで試す。

```ruby
#!/usr/bin/env ruby
require 'capybara'
require 'capybara/dsl'
require 'selenium-webdriver'

chrome_option_arg = ['headless', 'disable-gpu', 'window-size=1680,1050']

Capybara.register_driver(:selenium) do |x|
  Capybara::Selenium::Driver.new(
    x,
    browser: :chrome,
    desired_capabilities: Selenium::WebDriver::Remote::Capabilities.chrome(chrome_options: { args: chrome_option_arg })
  );
end

Capybara.javascript_driver = :chrome

Capybara.configure do |x|
  x.default_max_wait_time = 10
  x.default_driver = :selenium
end

@b = Capybara.current_session
# include Capybara::DSL;

@b.visit('http://xxx')
@b.first(:xpath, "//h3[@class='xxx-title']/a").click

@b.windows.each do |w|
  @b.switch_to_window(w)
  @b.save_screenshot
end
````
Ubuntuに素のLXDEをインストールする

はじめに
------

Vagrantを使って開発環境を作っていたらいつの間にかデスクトップを軽くするのが目的になっていた(あるある...よね？)。
以下のページには"最低限lxde-common,lxsession,openboxが必要だ"と書いてあるが、それだけだとグラフィカルログイン画面が出なかったから試行錯誤した。
https://wiki.archlinux.jp/index.php/LXDE

Vagrant boxとパッケージ
------

以下でグラフィカルログインできた。

- vagrant box
  - ubuntu/xenial64
- インストールするパッケージ
  - lightdm
  - openbox
  - lxde-common
  - lxsession

リンク先の3つのパッケージでグラフィカルログインできなかったのはディスプレイマネージャがインストールされていないから。
だからlightdmを追加したらグラフィカルログインできた:smile:
(ちなみにリンク先をちゃんと読めばディスプレイマネージャが必要だということが分かる)

追加
------

上４つだとログアウトできない。
ログアウトするには以下を追加。
- lxsession-logout

ターミナルアプリがない。
Byobuは入っているが、起動するとステータスバー(?)の再描画でスクロールし続けてしまうので実質使えない。
ターミナルとして以下を追加。
- lxterminal


感想
----

Xの仕組み難しすぎ。完全には理解できていないが勉強になった。
そして素のLXDEはそっけなさすぎ
Oldtweets-Pythonで過去ツイートを１００件以上(２ヵ月半前ぐらいまで）取得する

#Inrtoduction
はじめまして。はにおかさいです。

ツイッターで過去ツイートを分析したいと思ったのですが、過去のツイートを取得するすべをなかなか思いつきませんでした。日本語でググっても意図したものは発見せず。

そこで、Githubで検索してみました。すると

<a href=https://github.com/olivierthereaux/oldtweets>oldtweets</a>

<a href=https://github.com/Jefferson-Henrique/GetOldTweets-python>GetOldTweets-python</a>

この二つを発見しました。
今回はこのうち１つのoldtweetsを紹介します。コードの解説は別の機会に。

#Setup
特に指定がなかったので、Windows 10,Python 3.6.4で試しました。

```shell
pip install python-twitter

git clone https://github.com/olivierthereaux/oldtweets

cd oldtweets
```

credentials.txtにAPI情報を埋めといてください。

次にoldtweets.pyを見て、

```python
tweet_text = tweet.text.encode('utf-8').strip()
```
と記述があるので

```python
tweet_text = tweet.text.strip()
```
人間に読ませないようにしてどうする、、、

あと、

```python
# delete
            if option_delete == 1:
                try:
                    status = api.DestroyStatus(tweet.id)
                    # wait a bit, throttled api.
                    time.sleep(2)
                except Exception as e:
                    pass
```
は何か消しといたほうがいいと思います。事故ってツイート消えたら嫌ですしおすし。

#Execute

```shell
　cat credentials.txt | oldtweets.py --dry-run
```
これを実行するだけです。少し待ってあげてください。

#Result
![image.png](https://qiita-image-store.s3.amazonaws.com/0/245977/f640fea6-0714-7b38-8a03-068194fc953e.png)

RTもまとめて表示されます。古いものから順に表示されるらしいです。

ただ困ったことに２カ月半程度しか取得できませんでした。１５００ツイートほど。あとあと解決したい。 
"all tweets older than 4 weeks" とのことで、１か月前からのデータを表示していますね。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/245977/23c79bba-0bdc-4380-d9c1-86e62c06b5ce.png)


ツイート取得系はまた書きます。
コンソールプログラムで一瞬でコンソールが閉じる時の簡単な対処法

C/C++でコンソールプログラムを作っている時、
実行するとコンソール画面が一瞬で消えてしまって実行結果が確認できない！！！
と言ったことがあると思います。

そんな時はプログラムからpauseコマンドを呼び出しましょう。

```C++:main.cpp
#include<stdio.h>
//system関数はstdlibをincludeしないといけない
#include<stdlib.h>

int main(void){
    system("pause");
    return 0;
}
```

```:結果
続行するには何かキーを押してください . . .
```

何か他にも方法はあるのかもしれないけど、とりあえず備忘録として
tmuxステータスラインにホームディレクトリのdotfilesのカレントブランチを表示したい

gitのブランチ一覧を見るとき


```shell-session:gitブランチ一覧
$ git branch
develop
* master
feature/test_config
```


gitでカレントブランチ名だけ切り出すとき

```shell-session:gitカレントブランチのみ
$ git branch | grep '*' | cut -d ' ' -f2
master
```


`#(git branch | grep '*' | cut -d ' ' -f2)`をセットしてtmuxのステータスラインにホームディレクトリのブランチを表示する

```
set -g status-left "#[fg=colour233,bg=colour125,bold] #H #[fg=colour125,bg=colour240,nobold]#[fg=colour233,bg=colour240] #(git branch | grep '*' | cut -d ' ' -f2) #[fg=colour240,bg=colour235]#[fg=colour240,bg=colour235] ###S W#I P#P #[fg=colour235,bg=colour233,nobold]"
```


![Screenshot from 2018-03-27 23-59-22.png](https://qiita-image-store.s3.amazonaws.com/0/113494/cd2e2d91-23c4-8a83-1f7b-480383a7e4c6.png)
tmuxステータスラインの左から二番目(archlinux.vagrant.vmの隣)がdevelopブランチを表示

![Screenshot from 2018-03-28 00-29-28.png](https://qiita-image-store.s3.amazonaws.com/0/113494/22145e5e-c649-8e9e-dd2f-e51e46aef8ba.png)
tmuxステータスラインの左から二番目(archlinux.vagrant.vmの隣)がmasterブランチを表示

![Screenshot from 2018-03-28 00-32-22.png](https://qiita-image-store.s3.amazonaws.com/0/113494/92b3aa6e-c605-0694-8924-43293630ad10.png)
developブランチであるディレクトリに移動してもホームディレクトリのdotfilesはmasterブランチなのでステータスラインはmasterを表示




tmuxステータスラインは[jimeh/tmux-themepack](https://github.com/jimeh/tmux-themepack)
zshプロンプトは[bhilburn/powerlevel9k](https://github.com/bhilburn/powerlevel9k)をそれぞれカスタムして使用しています。
[u1and0/dotfiles](https://github.com/u1and0/dotfiles)


## 追記
[Gitのブランチ名を返すエイリアスを設定したら地味に捗った](https://qiita.com/kmszk/items/3de61ef75e30dedd6f6e)より、

```shell-session
$ alias brname='git symbolic-ref --short HEAD'
```

とエイリアス設定することで

```shell-session
$ echo $(brname)
master
```

とかいうように現在のブランチを返してくれます。

```shell-session
$ git branch | grep '*' | cut -d ' ' -f2
```

と同じ結果ですが、パイプをはさまない純粋gitサブコマンドなので、お好みで使うとよいでしょう。
PuTTYでGCPのインスタンスにSSH接続する

### 1. PuTTYのダウンロード&インストール
[PuTTYのサイト](https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html)からインストーラーをダウンロード&インストールする。

### 2. puttygenで認証鍵を生成
PuTTYをインストールしたディレクトリ配下に「puttygen.exe」があるのでそれを開き、「Generate」ボタンを押下する。
![1.png](https://qiita-image-store.s3.amazonaws.com/0/23101/6221590e-5ee1-0199-80be-2a2f530480b6.png)

緑のメーターが一番右に来るまでマウスカーソルをクルクル回す。
![1.png](https://qiita-image-store.s3.amazonaws.com/0/23101/fff24061-4c94-12f3-f385-f9c0835e15cf.png)

「key_comment」にデフォルトでテキストが入っていると思うので、それを削除して自分のGCPアカウントを入力する。
![1.png](https://qiita-image-store.s3.amazonaws.com/0/23101/22bcca0d-927f-f48a-6ecd-fc0a7dc5021c.png)
「Save private key」ボタンを押下し、任意の名前で秘密鍵を保存する（ファイルの形式は、ファイル名.ppkとなる）。

公開鍵（下記の赤枠の部分）をコピーして控えておく。
![1.png](https://qiita-image-store.s3.amazonaws.com/0/23101/2d6eb201-74c9-9c08-3e13-0594faed7e12.png)

### 3. GCPに公開鍵を登録する
GCPコンソールにアクセスし「Compute Engine」→「メタデータ」を選択する。

「SSH認証鍵」タブを選択し「編集」ボタンを押下する。
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/23101/7e7e9231-fcd0-ad0e-56c4-d64cce79618d.png)

「項目を追加」ボタンを押下し、「2. puttygenで認証鍵を生成」でコピーしておいた公開鍵を貼り付ける。
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/23101/a6bc9961-8e41-28d8-2012-f119ded9ba99.png)

自分のGCPアカウント名になっていることを確認したら、保存ボタンを押下する。
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/23101/5fa40fb0-f51e-f293-6024-3eb0b9f76919.png)

### 4. PuTTYでSSH接続
PuTTYを開き、接続したいGCPのインスタンスのIPもしくはホスト名を入力する。
![無題.png](https://qiita-image-store.s3.amazonaws.com/0/23101/f8a57067-1259-2b79-8d4e-90b804ae0c34.png)

「Connection」→「Data」の「Auto-login username」に自分のGCPアカウントを入力する。
![無題.png](https://qiita-image-store.s3.amazonaws.com/0/23101/af296bc7-366e-3727-dc11-1d4371490338.png)

「Connection」→「SSH」→「Auth」で「2. puttygenで認証鍵を生成」で保存しておいた秘密鍵を設定し、「Opne」ボタンを押下する。
![無題.png](https://qiita-image-store.s3.amazonaws.com/0/23101/a8ee07db-9831-6106-7c96-141313125c4f.png)

こんな感じで接続されれば成功。
![無題.png](https://qiita-image-store.s3.amazonaws.com/0/23101/86e54f7c-380c-8301-b22f-e907e99c4c91.png)

### 参考
[メタデータでの SSH 認証鍵の管理](https://cloud.google.com/compute/docs/instances/adding-removing-ssh-keys?hl=ja)
【未経験系エンジニア】新卒でエンジニア職について一年経とうとしているので振り返ってみる

ということで一度自分が一年間エンジニアとしてやってきたことを、気持ちと一緒に棚卸ししようと思いました。

# しばらく回想シーンです

## プログラミングとの出会い

大学では経営学を勉強していた。
授業でVBを触って単位を落としたのが私の初プログラミングの思い出。

新卒でSIerに入社し、新人研修で`Java`と`Oracle`を学ぶ。
正直**プログラミング楽しい！なんか作りたい！！もっと勉強したい！！！**とかならなかった。
`CSS`と少しの`JavaScript`で画面描画作り込むのは面白かった。
プレゼンテーションとかディスカッションの研修の方が楽しかった。

配属されてからは設計書を綿密に描くためにExcelを触っている時間のほうが圧倒的に長い。
**正直つまんないし辛かった。**
その間プログラミングはほとんどしてなかった。

## 個人開発をやってみた

なんかこのままじゃプログラミング忘れるんじゃね？と思って、個人開発をしてみた。
ドットインストール見て、`vagrant`と`VurtualBox`で仮想`Linux`立てて、`PHP`の基本構文をちょろっと勉強した。
（なんとなく`Java`以外の言語を使ってみたかった）

スクレイピングしてPDFをかき集めて、データ抜いてDBに入れて画面に出すだけの簡単なWebアプリを2週間もかけて作った。
週次で公開されるPDFをいちいちダウンロードするのが不便だなあと思っていたものを解決するために作った。
検索機能あったら面白いなあと思って実装した。

バッチ処理は`Jenkins`を使って定期実行させた。
そういうものじゃないって何となく察してはいたけど、他のやり方を知らなかったからそうした。

オブジェクト志向？知らない子ですね、ってな全部ひとつながりの酷いソースコードでも、動いた時の興奮は確かだった。
まあ運用してみるとバグだらけでほとんど機能しなくなってしまったけれど。そのうちリファクタリングしたい（**書き直したほうが早い**）。

自分は**課題を解決するためにプログラム書くなら楽しめる**んだなあ、と思った。

## Javaを体系的に勉強しなおした

仕事が開発フェーズに入る前に、`Java`（というかプログラミング）について知らなすぎるのを上司に突っ込まれて、とりあえずSE8 Bronzeくらいとれるように本買って勉強しろと言われたので、勉強した。
レビューとかいろいろみて、BronzeじゃなくてSilverの問題集を買って2周やった。
会社では資格に補助がつかないので、受検はしていないが、継承も、実現も、カプセル化も、新人研修で何にも身につけてなかったんだなあと思った（そしてこの前開発した`PHP`アプリのソースがとんでもなく酷いんだなあとも思った）。

## 開発が楽しかった

それから、プログラミングは自分にとって**面白い**しちょっと**楽しい**ものになった。
仕事では上司が業務自動化とか効率化のタスクをどんどん振ってくれたおかげで、知らない技術に触れる機会が増えた。
SQLパッチで帳票作成を半自動化した。`Git`でソース管理した。社内の`Java`製ツールを`Maven`でビルドした。`Jenkins`でジョブのスケジューリングした。`Python`と`Selenium`でブラウザ操作した。`AWS`と`Docker`も使うらしいから勉強してる。

日報から一言コメントを抽出してメールで毎日送付するだけのものを作って、チーム内でこそこそ楽しんでたら偉い人に**プロジェクト全体でやってよ**と言われて、ちゃんとしたやつに作りなおすために夜遅くまで会社でソースを書いた。
リリースして、**ユーザの反応が見えるのが楽しかった。**

業務でも開発の工程は今までで一番楽しかった。
先輩にデバッグのコツ、リファクタリングの仕方、JUnitテストの書き方、知らないことをたくさん教えてもらった。
稼働も上がりまくったけど、方眼Excelで設計書書いてるより時間が過ぎるのは早かった。
でもバグ出しまくってチームの人に迷惑をかけて**本当に申し訳ない気持ちでいっぱいになった。**
もっと**書けるエンジニア**になりたいと思った。

-------------回想終わり--------------

**ここから振り返り**

# 僕が一年間で出会った技術たち

## 言語
* Java
* JavaScript
* PHP
* Python
* Ruby
* VBA
* PL/SQL

## ライブラリ
* Spring Framework
* JUnit
* jQuery
* Ruby on Rails
* Keras

## データベース
* Oracle
* MySQL
* SQLite

## OS
* Windows
* ubuntu
* CentOS

## その他いろいろ

* SubVersion
* Git
* Jenkins
* Maven
* Selenium
* vagrant
* VurtualBox
* PowerShell
* AWS
* Docker

# 振り返って思うこと

## 意外とたくさん触った
決して多くはないと思うが、思ってたよりも色んなものに触れてきたなあという感覚。

## 知識の深堀が足りない
これについてなら教えてあげられるよ！みたいなのがない。
「使ったことがある」とは言えても「使えるよ」って言えるやつ少ない。

## 外向きにアウトプットできてない
触ってみてハマったところとかあったはずなのに、ナレッジとして残せてない。
なんらかのアピールとか人の役にたつ日が来るかもしれないので、Qiita書きます。

# これからやろうと思うこと

## もう少し体系的に知識を深める
全体的に浅いので、これからも使う機会がありそうなものに関しては、技術書なんかを使ってもう一段階深く勉強する時間を作る。

## アウトプットする
Qiita書く。社内のRedmineでwiki書く。
なんか作ったら恥ずかしがらずにGithubに上げる。
社内の勉強会とかで話せるように整理してみる。

## 社外に出てみる
社外のエンジニアと交流してみたい。
カンファレンスとかパブリックな勉強会なんかに参加してみる。
得られたものは社内で共有したり、なんか書いたりする。

## フロントエンドやってみたい
業務では恐らくほとんど触れることがないので、個人的にやってみたい
Webデザインにも興味がある

```java
/*
その他
=> MacBookPro欲しい
*/
```

おわり
そのうち追記します
Discord Bot 『Roboty』の裏側 ~採用技術と開発環境まとめ~

# はじめに

[こちらの記事](https://qiita.com/otuhs_d/items/86fc7cda767b5682311f)で紹介したDiscord Bot『Roboty』で採用している技術や開発環境のまとめです。
できる限りイマドキな技術を取り入れる & 触ったことないものを触るようにしています。

# 全体図

絵にしてみるとこんな感じです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/222294/9c2a6a59-b85d-f68f-5775-1f83dcc40a7d.png)

# 各要素について

## 開発言語

[Ruby](https://www.ruby-lang.org/ja/)

### 採用理由

* 少しだけ触る機会があった
* せっかくならちゃんと書けるレベルになりたい

## ソースコード管理

[GitLab](https://gitlab.com/)

### 採用理由

* CI/CD環境が充実している(後述のGitLab-CI)
* 無料で非公開リポジトリを作れる

## CI/CD環境

[GitLab-CI](https://about.gitlab.com/features/gitlab-ci-cd/)

* ソースコードがpushされるたびに静的構文解析を実行
	* [rubocop](https://github.com/bbatsov/rubocop)
* masterブランチが更新されるたびに
	* [Docker](https://www.docker.com/)イメージのビルド
	* [Google Kubernetes Engine](https://cloud.google.com/kubernetes-engine/?hl=ja)にデプロイ

~~テストはさぼっています。。。~~
自動テストも走らせる予定です。

### 採用理由

* 少し触る機会があった
* 他のものを知らない

## 実行環境

* [Docker](https://www.docker.com/)
* [Google Kubernetes Engine](https://cloud.google.com/kubernetes-engine/?hl=ja)

### 採用理由

* とりあえず今熱いDockerとk8sを触りたい
* GKEについては特になし

## ChatOps

* [Discord](https://discordapp.com/)
* [Google Spread Sheet](https://www.google.com/intl/ja_jp/sheets/about/)

ChatOpsというほどでもないですが、GitLabのイベント通知をDiscordで受け取れるようにしています。
詳細はこの記事 → [GitLabの通知をWebhookでDiscordに送信する](https://qiita.com/otuhs_d/items/fbb80a0bad8d0921b8e6)

### 採用理由

* DiscordのBotを作っているのでDiscordでChatOpsしたい
* Google Spread Sheet
	* 中継サーバをどうするか考えていたら、ちょうどいい記事を見つけた(詳細は上の記事)

## 使用API

* Discord API
	* 実際は[discordrb](https://github.com/meew0/discordrb)
* [Spla2 API](https://spla2.yuu26.com/)
	* 詳細はこの記事 → [DiscordのBotにSplatoon2のステージ情報を教えてもらう](https://qiita.com/otuhs_d/items/3882472cd36cd31f8503) 
* [iTunes Search API](https://affiliate.itunes.apple.com/resources/documentation/itunes_search_api_jp/)

### 採用理由

* discordrb
    * 開発言語にRubyを選択したから
    * 他を知らない
* Spla2 API
	* 公式のAPIが公開されてない
* iTunes Search API
	* 先人が作っているのはYoutubeとニコ動のAPIを使っているようだったので、せっかくなら別のものでやってみたい

# おわりに

これからはじめてみる方の参考に少しでもなれば幸いです。
あと定期的にモチベーション問題にぶつかるから共同開発してみたい。
アンドロイドアプリを作る。（1日目）

本日から３連休なので、Android開発を始めることにしました。
その上で、重要と思ったことや、つまずいたことをメモ的に残して行きます。

##Tools>Androidがない
![FD61EF42-966A-4A57-AE0D-5E2C5926C090.jpeg](https://qiita-image-store.s3.amazonaws.com/0/185846/72402a10-67e4-ac52-003a-d672a53eb499.jpeg)

`AVD Manager`を起動するようにテキストに記載されているが、ToolsにAndroidがない。。。
よく見ると、下の方にエラーが出ていた。
![スクリーンショット 2018-03-27 16.51.25.png](https://qiita-image-store.s3.amazonaws.com/0/185846/8db4cbab-b573-81b6-762b-163067874061.png)
とりあえず、リンクをクリックする。
また、新たにエラーが出た。
![スクリーンショット 2018-03-27 16.52.15.png](https://qiita-image-store.s3.amazonaws.com/0/185846/e9d9f1ee-21e8-a214-e989-1951b3b0fa2d.png)
もう一回リンクをクリックする。
すると、エラーが消えた。再度Toolsを見ると表示された。
![スクリーンショット 2018-03-27 16.54.41.png](https://qiita-image-store.s3.amazonaws.com/0/185846/fc3b23ba-cb46-8498-6f1f-d15ff238a8b8.png)

##重要なファイル
###/java
文字通り、Javaのソースコードを保存するフォルダ。
アプリの中核。

###/res/layout
アプリの見た目（レイアウト）
`/res/layout/activity_main.xml`でレイアウトを決めているが、ここでテキストの値を変えると、他言語への対応ができない。
そのため、値は`/res/Value`を参照する形でレイアウトに表示している。

###/res/Value
アプリで使用する文字列データやスタイル情報など

##アプリの国際化
英語、日本語、ドイツ語に対応したい場合は、/value(英語)、/value-ja(日本語)、/value-de(ドイツ語)のようにフォルダを分ける事で、端末の言語設定によって、参照するValueファイルが変わる。
該当しないValueファイルがない場合は、/valueがデフォルトファイルとなるため、上記の場合は英語表記となる。

##layout_centerInParentとlayout_width
テキスト内で、表題の項目を選ぶように指示があったのだが、該当の項目がどうしても見つからなかった。
どうしても見つからないから、teratailで質問した結果、Android Studioのヴァージョンがテキストと異なり、仕様が少し変わったことが要因だった。
https://teratail.com/questions/119231?whotofollow=

teratailすごい！

#感想
Android開発一日目、一番の感想は分からなければteratailに聞けばいい！でした。
明日もある程度進めようと思います。
SQLアンチパターンon Rails Ⅳ部（アプリケーション開発）

# はじめに
SQLアンチパターンをRailsの文脈で読み解いていきます。
この記事では、Ⅳ部 アプリケーション開発のアンチパターン（19~25章）を取り上げます。

# リンク
- [SQLアンチパターンon Rails Ⅰ部（論理設計）](https://qiita.com/eduidl/items/8620787ffaf2b18922bf)
- [SQLアンチパターンon Rails Ⅱ部（物理設計）](https://qiita.com/eduidl/items/d535a25cd02c9007da29)
- [SQLアンチパターンon Rails Ⅳ部（アプリケーション開発）](https://qiita.com/drafts/f6383517dea9ad13c6ce/edit)

# 本文
## 19. リーダブルパスワード（読み取り可能パスワード）

[devise](https://github.com/plataformatec/devise)とか使いますよね。
bcryptを使う手もあります。

```rb
class CreateUser < ActiveRecord::Migration[5.1]
  def change
    create_table :users do |t|
      t.string :password_digest, null: false
    end
  end
end
```

`password_digest`カラムを用意して、クラス定義に`has_secure_password`を書けば、
viewのフォームで`password`と`password_confirmation`が使えるようになります。

```rb
class User < ApplicationRecord
  has_secure_password
end
```

オレオレ実装はNG。平文は論外。

## 20. SQLインジェクション
基本的にはHashで書くか、placeholderを使う。

```rb
Model.where(value: params[:value])
Model.where('value > ?', params[:value])
```

ActiveRecordを使ったSQLインジェクションの例はhttps://rails-sqli.org/ で見られる。

## 21. シュードキー・ニートフリーク（擬似キー潔癖症）

レコードを削除してできたidの歯抜けが嫌で、詰めようとしてしまう行為。
気持ちはわかるが我慢。気にしない。

## 22. シー・ノー・エビル（臭いものに蓋）
エラーを無視しない。当たり前。

Railsでいうと、`save`と`save!`の使い分けだったり、バリデーションとかか？
範囲が広すぎるので、書ききれない。割愛。

## 23. ディプロマティック・イミュニティ（外交特権）
一部の企業では、DBAが存在して、DB, SQLはバージョン管理しないみたいなことがあるそう。
本書では、文書化・バージョン管理・テスティングが有効と書かれている。

1. 文書化
本にはER図がデータベースドキュメントの中で最も重要と書かれていますが、[rails-erd](https://github.com/voormedia/rails-erd)というgemを使うと自動生成できたりもします。

2. バージョン管理
`app/db`にあるので、管理しない理由が見当たらない。

3. テスティング
RSpecやMinitest書いてください。


## 24. マジックビーンズ（魔法の豆）
アクティブレコードパターンがアンチパターンというのでどうしようもなさがある。

とはいえ、 ActiveRecordは単なるアクティブレコードパターンではありませんし、100%当てはまるかは疑問です。
例えば、「24.2.2　アクティブレコードはCRUD機能を公開してしまう」の例を挙げます。

```rb
# 擬似コード
bug.assign_user(account)
mail_to(account)
```
のようにバグの修正担当にある人に割り振るとき、一緒にメールを送信するというロジックを作っても、それを知らない別のプログラマが

```rb
bug.assign_user(account)
#　メールは送らない
```
みたいに書いてしまう危険性があるとあります。
ただ、Railsの場合、コールバックを使えばいいのではと思います。それでも、`skip_callback`等の抜け道はありますが、意図的にやらない限り上のような状況にはならないでしょう。

## 25. 砂の城
データサイズが一ヶ月で3倍になったとか、色々イレギュラーなケースに想定しておきましょうという話。
この章にコメントを書けるほどの経験がないので、わかりません。
何もわからない。

# 全体通しての感想
経験がなくてよくわからないという箇所がいくつもあって、色々と限界を感じた。
プログラマ歴&Rails歴1年では厳しかったのか。
もうちょっと経験を積んだら追記したいところ。
（とはいっても、来月からC/C++を書くようなので、しばらくRailsからは遠ざかってしまうのですが。）
Memo:[Django]バージョンによるurls.py内のincludeの仕様の違い

# Django Tutorial Memo
## 概要
Urlディスパッチャの記述でハマった。

## 問題
旧DjangoのTutorialでは、下記のようにしなければならなかった。

```python:old_version

urlpatterns = [
    url(r'^testapp/', include('testapp.urls', namespace='testapp')),
]
```

新しいDjangoで上記を写経すると下記のエラーがでる。(Django==2.0.3を使用）

```python:Error
    url(r'^testapp/', include('testapp.urls', namespace='testapp')),
  File "C:\Users\****\PycharmProjects\Tutorial\venv\lib\site-packages\django\urls\conf.py", line 39, in include
    'Specifying a namespace in include() without providing an app_name '
django.core.exceptions.ImproperlyConfigured: 
Specifying a namespace in include() without providing an app_name is not supported. Set the app_name attribute in the included module, or pass a 2-tuple containing the list of patterns and app_name instead.
```

'Specifying a namespace in include() without providing an app_name '
Googleさん：`'app_nameを指定せずにinclude（）で名前空間を指定する'`

## 解決策
新Django(Django==2.0.3)では、下記のようにすることでエラーをはかなくなった。
要するに、namespaceでapp_nameを指定するのではなく、2-タプルで渡してね。ってことみたい。

```python:new_version
urlpatterns = [
    url(r'^testapp/', include(('testapp.urls', 'testapp'),)),
]

```
Kotlin + Spring boot2 + Webflux + RouterFunctionsのFormとかパスとかQueryParamとか

# はじめに
FormでPost飛ばしてデータ処理するとか動的パスはどうやるとかQueryParamはどうやるとかの話です。
データ取得した結果を簡単に見たいので、本記事内では`block()`を使用して値を取得していますが、たぶん本当はやってはいけないのでご注意ください。

# 環境
IntelliJ IDEA
Kotlin 1.2.20
Java 8
Spring Boot 2.0.0.RELEASE

# Form
まずは適当なFormが書かれたHTMLを用意します。

``` html
<form action="post" method="POST">
    <textarea name="str"></textarea>
    <button type="submit">投稿</button>
</form>
```

このFormの受け先を作ってBodyを受け取ります。
bodyからMonoに変換するメソッドは用意されているそれを使えば大丈夫です。

``` kotlin
val str= req.bodyToMono<String>().block()
println(str)
>>> str = test
```

文字列でそのまま受け取る場合はStringに変換して`block()`でデータを取得します。
この場合はbodyの中身そのままなので、Formなら一手間加えてあげる必要があります。
一手間を毎回するのは面倒なので、データクラスにいきなり変換出来るようにしたいというのが人情ですが、`bodyToMono`に`data class`を渡してもうまくいきません。

``` kotlin
val str = req.bodyToMono<PostData>().block()
println(str)
>>> Failed to handle request [POST http://localhost:8080/post]: Response status 415 with reason "Content type 'application/x-www-form-urlencoded' not supported"
```

どうやら`PostData`に変換しようとした際にエラーになっているようです。
2時間ほど調べたのですが、`Mono<PostData>`にはうまく変換できませんでした。
`bodyToMono()`が`application/x-www-form-urlencoded`に対応していないために変換が出来ない状態となっています。

``` kotlin
val map = request.body(BodyExtractors.toFormData()).block()
```

しょうがないので、`BodyExtractors.toFormData()`でFormDataに対応した変換をすることで対応しました。
戻り値の型は`Mono<MultiValueMap<String, String>`になっています。

比較的納得いかない状況ではありますが、現状はしょうがない感じです。

# 動的パス
動的パスは簡単です。

```kotlin
// "/{str}"とRouteを設定している前提
val str = req.pathVariable("str")
```

``` kotlin
// まとめてMapで取得したい場合はこちらで
val map = req.pathVariables()
```

``` kotlin
// パスがそのまま欲しい場合
val path = req.path()
```

# QueryParam
QueryParamもパスと同じ感じで取得できます。

``` kotlin
// 指定して取得したい場合
val str = req.queryParam("str")
```

``` kotlin
// まとめて取得したい場合
val map = req.queryParams()
```
実装リンク集

■■■■ Vue＋JavaScriptライブラリ実装リンク■■■■

ElementUI バリデーション
http://element.eleme.io/#/en-US/component/form#custom-validation-rules

ElementUI マルチセレクト(複数選択)
http://element.eleme.io/#/en-US/component/select

ElementUI アラート情報
http://element.eleme.io/#/en-US/component/alert

ElementUI ドロップダウンリスト
http://element.eleme.io/#/en-US/component/dropdown

AXIOSの例外処理うんぬん
http://kimulla.hatenablog.com/entry/2018/01/19/001135

AXIOSライブラリ(エラーハンドリングの実装あり)
https://www.yoheim.net/blog.php?q=20170801

AXIOSのasync/await時の実装
https://zukucode.com/2017/08/asynct-await-ajax-error.html


■■■■Spring Bootの実装リンク■■■■

SpringBoot例外処理
https://www.kaitoy.xyz/2017/01/13/goslings-development-memo3-spring-boot-exception/

SpringBoot例外処理2
https://int128.hatenablog.com/entry/2016/11/27/230529

ymlを読み込む
http://javatechnology.net/spring/spring-boot-yaml-configurationproperties/

例外について
https://qiita.com/NagaokaKenichi/items/a279857cc2d22a35d0dd
Wio-LTE + Arduino のメモ

ソースコードを探して回った結果のメモ。

Board Manager に入力する json ファイルでのバイナリ配布物は https://github.com/Seeed-Studio/Seeed_Platform/ で管理されている。

このバイナリのソースコードは https://github.com/Seeed-Studio/STM32F4_Arduino_Library/ のリポジトリで管理されている。

Board 設定の後、いろいろ便利にアクセスできるライブラリは　https://github.com/SeeedJP/WioLTEforArduino/ のリポジトリにある。

突っ込んでいくと、AT コマンドのリファレンスなどが必要になってくるけれども、 https://github.com/SeeedDocument/Wio_LTE に zip で固めた状態で配布されている。もちろんユーザ登録して本家サイト http://www.quectel.com/product/ec21.htm からダウンロードしてもよい。

製品ページ http://wiki.seeedstudio.com/Wio_LTE_Cat.1/ にあるように、STM32F405RG, ARM 32-bit Cortex-M4, 168MHz で動いている。ST のサイト http://www.st.com/ja/microcontrollers/stm32f405rg.html にいくと、どういうソフトウェア実装を期待していたかわかる。

## その他便利リンク

- soracom でハンズオンをやっていたらしい https://github.com/soracom/handson/wiki/Wio-LTE-%E3%83%8F%E3%83%B3%E3%82%BA%E3%82%AA%E3%83%B3
- http://www.seeed.co.jp/blog/wio-lte-with-int/
- https://qiita.com/ma2shita/items/66b5dd473aa8eadd05e0
- https://qiita.com/ma2shita/items/a50f6b2b1cc438b1f8b7

## 使っていて気が付いたメモ

`Wio::TurnOnOrReset` が `false` を返す。結局原因は SIM がきっちり刺さっていなかった事。隠れるぐらいまで入るものらしい。

`WioLTE::getLocation` は、Wio-LTE デバイスの存在する位置を取得するものでは**なく**、LTE 接続している**基地局の位置**を取得するものになっている（フェリー乗船時のログで気が付いた）。これはこれで役に立つのだけど、誤解しないように気を付けるべし。リファレンスは [wiki](https://github.com/SeeedJP/WioLTEforArduino/wiki/Reference-ja#getlocation) にある。

ちなみに [EC21](http://www.quectel.com/product/ec21.htm) はもともと GPS 内蔵だが、WioLTE **JP バージョン**では削除されていて使えないので、日本では外付けの GPS モジュールが**別途必要**。最初から[Grove IoT スターターキット for SORACOM](https://blog.soracom.jp/blog/2017/12/01/wio-lte-grove-iot-starter-kit-for-soracom/)を買うのが吉。

なぜか I2C がソフトウェア実装されているので、うまく通信できない場合は、タイミングを調整すべし。

`SerialUSB` を使うタイプなので、`Serial` でやっていたところは読み替えるべし。`Serial` は GROVE 端子の`UART` に出ている。`Serial1` は LTE モデムの AT コマンド入出力 UART につながっている。

ボード全体でリセットがかかる現象を観測中。`millis()` をログするとよい。同時に LTE 電場強度が弱いログが出ているけれど、原因なのか結果なのかは不明。消費電力が問題か？
WindowsのDOS窓でls叩いたらdirして欲しい、ほか

# 要約
- WindowsのDOS窓でうっかりls叩いたら代わりにdirが動く、など
- Qiitaの類似記事をまとめ
- 類似記事たちのタグが揃ってないから情報が分散しがちだけど、タグが5個までの制約があるので、参考タグもリンクしちゃう
 - [dos](/tags/dos)
 - [cmd](/tags/cmd)
 - [cmd.exe](/tags/cmd.exe)
 - [コマンドプロンプト](/tags/コマンドプロンプト)
 - [bat](/tags/bat)
 - [batch](/tags/batch)
 - [バッチファイル](/tags/バッチファイル)

# 参考リンクたち
- [ついついwindowsでlsとか叩いちゃう時って、あるじゃん？](https://qiita.com/Real_analysis/items/07ed30a3dde4bc1f2145)
 - tee、ls
- [Windowsで「cd -」や「ls」](https://qiita.com/dhun/items/ac8f7b062eb61a3fbc1e)
 - pwd、cat、ls、ll、la、mv、rm、ln、clear
- [windowsでunixコマンドを使う準備](https://qiita.com/asterisk9101/items/7da60f8c8859d6e4dffe)
 - pwd、ls、grep、head
- [Windowsのコマンド忘れてて使いづらかったのでMacやLinuxのコマンドぽく使えるようにしてみた](https://qiita.com/teradonburi/items/660b4b59ff1a5c6765de)
 - alias、unalias、h、history、ls、pwd、ll、lv、cat、cp、mv、touch、rm、ifconfig、open、ps、kill
- [Linux/WindowsでもMacOSXみたいにopenでファイルを開きたい](https://qiita.com/hkato/items/95e4e0ec5c0e57508d7e)
 - open
- [【Windows】コマンドプロンプトをLinuxライクに設定](https://qiita.com/naoto_koyama/items/3768e187274f26a6b425)
 - cd、ps
- [バッチファイルでよく使う書き方まとめ](https://qiita.com/sta/items/8cab80fe74b8dcfa5336)
 - pwd
- [【備忘録】新しいPCにセットアップするものまとめ](https://qiita.com/koryuohproject/items/ba9290e183325d69605f)
 - ls、history、quit
- [windowsをwindowsのままで使う開発環境備忘録](https://qiita.com/Real_analysis/items/70664782b7b2a64dda31)
 - cat、history、ll、touch

# まとめ
1. 擬似コマンドの表現は**自作batにPATHをとおす**または**エイリアスをはる**に二分類される。
1. エイリアスをはるbatの読み込み方法は**レジストリ**または**cmdのkオプション**の二通りがメジャー。
1. すぐに素の環境に戻せる or ポータビリティがある or 権限の制約等を受けづらいなどの観点から、エイリアスを代替コマンドや自作batにはる、そのbatをcmdのkオプションで渡す、この方法が幸せになれそう。

以下に構成例をしめし、参考リンクから気に入ったエイリアスを「.doskeys」へ追加してください。

```console:タスクバーやデスクトップにショートカット作成
%windir%\system32\cmd.exe /k %HOMEDRIVE%%HOMEPATH%\cmdrc.bat
```

```console:tree
%HOMEDRIVE%%HOMEPATH%
│  .doskeys
│  cmdrc.bat
│
└─bin
        _grep.bat
        _cd.bat
        _sudo.cmd
```
```sh:cmdrc.bat
@echo off
set PATH=%~dp0bin;%PATH%
doskey /MACROFILE=%~dp0.doskeys
_cd
```
```sh:.doskeys
alias=if "$1"=="" (doskey /macros) else for /f "delims== tokens=1,*" %i in ("$*") do @if "%j" neq "" (  doskey $* ) else (  doskey /macros $b findstr /b /c:"%i=" )
unalias=doskey $*=
history=doskey /history $*

man=help $*
cp=copy $*$b find /v "個のファイルをコピーしました"
mv=move $*$b find /v "個のファイルを移動しました"

cd=_cd $*
sudo=_sudo $*
grep=_grep $*
```
```sh:_cd.bat
@echo off
if "%1x"=="x" pushd %HOMEDRIVE%%HOMEPATH% && goto :_view
if "%1x"=="-x" popd && goto :_view
pushd %1

:_view
title %CD%
call :_getcd "%CD%"
if %HOMEDRIVE%%HOMEPATH%==%CD% (
 prompt [%USERNAME%@%COMPUTERNAME%$S~]$$
) else (
 prompt [%USERNAME%@%COMPUTERNAME%$S%xcd%]$$
)
set xcd=
goto :eof

:_getcd
set xcd=%~nx1
exit /b
```
```sh:_grep.bat
@echo off

if "x"=="x%2" goto usage
if "x"=="x%1" goto usage

call :write_ps %1 %2
call :run_ps
call :del_ps

goto :eof

:write_ps
set XSCRIPT=Select-String -Path %1 -Pattern "%2"
>%~dpn0.ps1 echo %XSCRIPT%
set XSCRIPT=
exit /b

:run_ps
powershell -NoProfile -ExecutionPolicy Unrestricted %~dpn0.ps1
exit /b

:del_ps
del %~dpn0.ps1
exit /b

:usage
echo usage: %~nx0 filepath pattern
>nul pause
goto :eof
```
```sh:_sudo.cmd
@powershell -command "Start-Process -Verb runas %1"
```

おしまい
Zeller's  公式　（曜日を求める）

```java
public class Main {

    public static void main(String[] args) {
        System.out.println(calc(2018, 3, 28)); // 水曜日
        System.out.println(calc(2018, 2, 28)); // 水曜日
        System.out.println(calc(2018, 1, 28)); // 日曜日
    }

    public static String calc(
            double y,
            double m,
            double d) {

        double M = 0;
        if (m < 3) {
            M = m + 12;
            y = y - 1;
        } else {
            M = m;
        }

        int C = (int) (y / 100);
        int Y = (int) (y % 100);

        double R = 0;

        if (y >= 1582) {
            R = (C / 4) - C - C;
        } else if (y >= 4) {
            R = 5 - C;
        } else {
            throw new IllegalArgumentException("year >= 4");
        }

        Double h = (d + ((26 * (M + 1)) / 10) + Y + (Y / 4) + R) % 7;

        String[] weekday = new String[] {
                "土",
                "日",
                "月",
                "火",
                "水",
                "木",
                "金"
        };
        return weekday[h.intValue()];

    }

}
```
PythonからEvernoteにアクセスする下準備(その2)

#### やったこと

[前回の下準備](https://qiita.com/FrozenVoice/items/75e59daaae8676127f08) で最低限の確認環境は出来たので、ノートの中身を取得してみる。

また、ノートの中身はHTMLっぽく記載されているが、中身のテキストだけ欲しいのでElementTreeを使って必要な部分だけ取得する方法を確認してみた。

#### おまじない部分

動作確認で使ったEDAMTEst.pyから必要な部分をそのまま利用する。

```python
authToken = "your auth token"
evernoteHost = "sandbox.evernote.com"
userStoreUri = "https://" + evernoteHost + "/edam/user"

userStoreHttpClient = THttpClient.THttpClient(userStoreUri)
userStoreProtocol = TBinaryProtocol.TBinaryProtocol(userStoreHttpClient)
userStore = UserStore.Client(userStoreProtocol)

noteStoreUrl = userStore.getNoteStoreUrl(authToken)

noteStoreHttpClient = THttpClient.THttpClient(noteStoreUrl)
noteStoreProtocol = TBinaryProtocol.TBinaryProtocol(noteStoreHttpClient)
noteStore = NoteStore.Client(noteStoreProtocol)
```

#### ノート情報の取得

SDKのNoteFilterとNotesMetadataResultSpecを使ってノート名指定で検索してguidを取得する。

```python
filter = NoteStore.NoteFilter()
filter.words = "TestNote01"

resultSpec = NoteStore.NotesMetadataResultSpec()
metaDataList = noteStore.findNotesMetadata(authToken, filter, 0, 100, resultSpec)
```

#### 必要な部分だけ取得

ElementTreeを使ってノートの内容から文字列を拾って表示する。

```python
for noteGuid in metaDataList.notes:
    note = noteStore.getNote(authToken, noteGuid.guid, True, False, False, False)
    print("  - ", note.title)
    tree = ElementTree.parse(StringIO(note.content))
    for div in tree.findall('.//div'):
        text = ""
        if div.text  != None:
            text = text + div.text

        for child in div.findall('.//*'):
            if child.text  != None:
                text = text + child.text
            if child.tail  != None:
                text = text + child.tail

        if div.tail  != None:
            text = text + div.tail

        print(text)
```

#### 雑記

Sandbox環境に普段使っているノートの内容をコピーして、上記の方法にて欲しい情報が取れそうなことは確認出来た。
あとで本番環境でちゃんと情報が取れるか確認してみよう。
SELECT文の検索結果をCSVへ出力するSQL(Oracle)

## はじめに

システムに不具合が発生し、データに問題があることまで調査できたとします。
そのとき、手っ取り早くDBの中身をCSVで出力して確認したいとき、ありませんか？
私はありました。

OracleにはSQLの実行結果をファイルに出力する `SPOOL` コマンドが用意されているので、それを応用してCSVへ出力するSQLを実装しました。
調査の際などにご活用ください。

## 環境

- DB：Oracle Database 10g Release 10.2.0.5.0 - 64bit Production

## CSV出力SQL

```sql:output_csv.sql
-- 検索結果をCSVへ出力する

-- ①SQL設定
-- コンソールメッセージを非表示にする
SET ECHO OFF
-- 1行に出力するバイト数
-- 少ないと見切れるので最大に設定する
SET LINESIZE 32767
-- 1ページの行数
-- 少ないとヘッダーが多くて見づらいので無制限に設定する
SET PAGESIZE 0
-- 「○○行が選択されました」メッセージを非表示にする
SET FEEDBACK OFF
-- 区切り文字をカンマに指定する
SET COLSEP ','
-- 各行の右端にあるスペースを削除する
SET TRIMSPOOL ON

-- ②出力開始
-- 出力パスは適宜変更する
SPOOL C:\output.csv

-- ③出力内容
-- 検索文は適宜変更する
SELECT *
  FROM {テーブル名}
;

-- ④出力終了
SPOOL OFF
```

## 追記

[コメント](https://qiita.com/uhooi/items/7d5e9b5deb5968dbbe8c#comment-9e9ccaaced6692a0618e)を頂いて気づいたのですが、この方法だと固定長となり、各列の右にスペースが含まれてしまいます。

CSV出力したデータを目視以外で使うなど、可変長で取得したい場合は、列をカンマで結合して1つの列として検索するしかなさそうです。

```sql
SELECT {列1} || ',' ||
       {列2} || ',' ||
       {列3}
  FROM {テーブル名}
;
```

## 参考リンク

- [ＯＲＡＣＬＥ／オラクルＳＱＬリファレンス（SQLPLUS）](http://oracle.se-free.com/utl/C1_csv.html)
- [SQL*Plus で実行した結果をテキストファイルに出力する - Oracle - Project Group](http://www.projectgroup.info/tips/Oracle/Oracle_000003.html)
- [SET LINESIZE - オラクル・Oracle SQL*Plus リファレンス](http://www.shift-the-oracle.com/sqlplus/system-variable/linesize.html)
- [SET PAGESIZE - オラクル・Oracle SQL*Plus リファレンス](http://www.shift-the-oracle.com/sqlplus/system-variable/pagesize.html)
nginx ベーシック認証

`htpasswd`コマンドで.htpasswdファイルを作成しようとしたが、コマンドが存在しないとのこと。

どうやら`htpasswd`コマンドはApache付属のコマンドらしいので、`httpd-tools`をインストールする。

```
$ sudo yum install httpd-tools
```

さて打ってみる。

```
$ sudo htpasswd -c /var/www/html/.htpasswd password
```

パスワードを聞かれ入力し、無事に`htpasswd`ファイルを作成完了。

設定ファイルを開く。

```
$ sudo vim /etc/nginx/nginx.conf
```

設定を追加。

```
server {
    auth_basic "Restricted";
    auth_basic_user_file /var/www/html/.htpasswd;
}
```

nginxを再起動。

```
$ systemctl restart nginx
```

ブラウザで該当のURLにアクセスすると、ベーシック認証を聞かれた。成功。
S3+ACM+CloudFront+Route53で独自ドメインでhttpsホスティングする

# S3にアップロード

example.comバケット作成。

コンテンツをアップロード。

```bash
aws s3 cp --recursive /path/to/example.com s3://example.com/
```

## S3でホスティングする場合

Cloudfrontと組み合わせる場合はS3でのホスティングは不要だが、テスト時はS3ホスティングの方が便利なので、以下の手順でホスティングする。

コンテンツを公開。

```bash
aws s3 ls --recursive s3://example.com | awk '{print $4}' | xargs -I{} aws s3api put-object-acl --acl public-read --bucket ticket.top4.jp --key "{}"
```

Static website hostingを有効化。

```
aws s3 website s3://example.com/ --index-document index.html
```

http://example.com.s3-website-ap-northeast-1.amazonaws.com でサイトが公開されていることを確認。

## S3ホスティングを無効化

テストが済んだらStatic website hostingを無効化。

コンテンツを非公開。

```bash
aws s3 ls --recursive s3://example.com | awk '{print $4}' | xargs -I{} aws s3api put-object-acl --acl private --bucket example.com --key "{}"
```

http://example.com.s3-website-ap-northeast-1.amazonaws.com や https://s3-ap-northeast-1.amazonaws.com/example.com/index.html で見られなくなっている事を確認。

# ACMでSSL証明書を作成

North Virginia Regionでexample.comの証明書を取得

# CloudFrontのWeb distributionを作成

## Origin Settings

1. Origin Domain Nameでexample.comバケットを選択

2. Restrict Bucket AccessをyesにしてS3への直接アクセスを禁止

3. Origin Access IdentityはIdentityが無ければCreate a New Identityで新しいIdentityを作成

4. Grant Read Permissions on Bucketはyesにしてバケットポリシーを自動設定

## Default Cache Behavior Settings

[Viewer Protocol Policy]でhttpからhttpsへリダイレクトするようにする。

## Distribution Settings

1. Alternate Domain Names(CNAMEs)にexample.comを設定

2. SSL証明書を設定

## 動作確認

作成したDistributionでWebサイトが公開されている事を確認。

https://xxx.cloudfront.net

# Route53

example.comのAliasレコードを作成してxxx.cloudfront.netに向ける。

しばらく待ってから`nslookup example.com`でDNS設定が反映されている事を確認。

https://example.com でWebサイトが公開されている事を確認。

# 補足

https://xxx.cloudfront.net と https://example.com のどちらからでもアクセス出来る状況になってしまうので、SEOが気になる場合はcanonical URLで https://example.com へ向けるように設定しておいた方が良いです。
ZFSでsend/recvについてのメモ

# 概要
CentOS 6でZFS(zfs-fuse)でsend/recvを使ったときのメモ。

# メモ
iSCSIのボリューム*/dev/mapper/mpatha*に既にZFSのプールが作成してあるが、このボリュームサイズを変更したい。暫定的に別のiSCSIボリューム*/dev/mapper/mpathb*にデータを移行してボリューム拡張後に再度データを戻す。その一部についてのメモ。

ZFSプール*tank*が既にあるときに別のZFSプール*tank2*を作成。

```
# zpool create tank2 /dev/mapper/mpathb
```

各ZFSプールの利用状況は以下のような感じ。プールサイズは*tank > tank2*だがデータ量は*tank2*に充分収まる。このような場合には問題なくスナップショットの転送が可能。

```
# zpool list
NAME    SIZE  ALLOC   FREE    CAP  DEDUP  HEALTH  ALTROOT
tank   3.41T  1.28T  2.13T    37%  1.86x  ONLINE  -
tank2  1.94T  95.5K  1.94T     0%  1.00x  ONLINE  -
```

今回は*tank/data/*以下のデータを*tank2*に移行させる。*tank/pool*以下にはゴミしかないので無視。

```
# zfs list
NAME                USED  AVAIL  REFER  MOUNTPOINT
tank               1.80T  2.07T    23K  /tank
tank/pool          1.13T  2.07T   705G  /zfs
tank/data           686G  2.07T   498G  /tank/data
tank2              73.5K  1.91T    21K  /tank2
```

ZFS sendするにはスナップショットが作成してある必要がある。スナップショットはスケジュールで毎日作成されているのでとりあえず最新版を利用することにする。

```
# zfs list -t snapshot -r
NAME                              USED  AVAIL  REFER  MOUNTPOINT
(snip)
tank/data@20180325               21.9M      -   498G  -
```

```
# zfs list -o space
NAME               AVAIL   USED  USEDSNAP  USEDDS  USEDREFRESERV  USEDCHILD
tank               2.07T  1.80T         0     23K              0      1.80T
tank/pool          2.07T  1.13T      451G    705G              0          0
tank/data          2.07T   686G      188G    498G              0          0
tank2              1.91T  73.5K         0     21K              0      52.5K
```

zfs send/recvを利用してスナップショットを転送する。データ量が多いので相当時間がかかる。

```
# zfs send tank/data@20180325 | zfs recv tank2/data
```

スナップショット転送後は転送先にもスナップショットが存在している。

```
# zfs list -t snapshot -r
NAME                              USED  AVAIL  REFER  MOUNTPOINT
(snip)
tank/data@20180325               21.9M      -   498G  -
tank2/data@20180325                  0      -   498G  -
```

ZFSプールにアクセスしているアプリケーションを停止し、手動でスナップショットを作成して差分を転送する。差分があまりないので短時間で転送が完了する。

```
# zfs snapshot tank/data@20180325-2

# zfs send -i tank/data@20180325 tank/data@20180325-2 | zfs recv -F tank2/data
```

スナップショットの差分転送後は転送した差分も反映されている。

```
# zfs list -t snapshot -r
NAME                              USED  AVAIL  REFER  MOUNTPOINT
(snip)
tank/data@20180325               21.9M      -   498G  -
tank/data@20180325-2                 0      -   499G  -
tank2/data@20180325              22.1M      -   498G  -
tank2/data@20180325-2                0      -   498G  -
```
またrailsの環境構築ではまった

http://tomoprog.hatenablog.com/entry/2017/02/03/015936

↑ありがとうございます。

rails newする
sudo gem install railsしなさいと言われる
上記のようにする
無限ループ。


結論：.bash_profileにてrailsが参照するgemのパスを書き違えた。
sourceし忘れた。
GAS＋Vue.jsでサーバレスなWebアプリ①

#はじめに
GASの[HtmlService](https://developers.google.com/apps-script/reference/html/html-service)を使ってSPAライクなWEBアプリケーションを書くことになったのでその時のメモです。
GASに合わせてフロント書くのしんどかった〜

#環境
[Google Apps Script](https://developers.google.com/apps-script/)
[Vue.js 2.x](https://jp.vuejs.org/)

#今回のアウトライン
1. GASプロジェクト作成
2. スクリプトのコーディング
3. GASのウェブアプリケーション設定

#さっそく書いていくよ
とりあえず[GAS公式のベストプラクティス](https://developers.google.com/apps-script/guides/html/best-practices)に沿ってプロジェクト内にスクリプトファイルを作成していきます。

今回は簡単のため、必要最小限の以下のファイルを用意しました。

```server.gs
function doGet(request) {
  var template = 'index';
  return HtmlService.createTemplateFromFile(template).evaluate();
}
```

```index.html
<!DOCTYPE html>
<html>
<head>
  <base target="_top">
  <meta charset="utf-8">
  <style>
    p {
      color: #4aac00;
    }
  </style>
  <!-- vue.js -->
  <script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
  <div id="vm">
    <p>{{ message }}</p>
  </div>
  <script>
    var vm = new Vue({
      el: "#vm",
      data: {
        message: "Hello GAS and Vue!"
      }
    })
  </script>
</body>
</html>
```

server.gsのdoGet(request)はエンドポイントがGETリクエストを受け取ったときに呼び出される関数。
変数templateの値は、HTMLファイル名の拡張子を除いた形にしておきます。
詳しいことは[公式のここ](https://developers.google.com/apps-script/guides/html/)に書いてあるので、気になる人は目を通しておくといいかも。

index.htmlでは[jsDelivr](https://www.jsdelivr.com/)上に置いてあるVue.jsのライブラリを読み込んでいます。
Google Apps Scriptのプロジェクトの作り方やVueの基本的な使い方はここでは説明しませんので、
公式や他の記事を探してみてください…

ひとまずこれでserver.gsのエンドポイントにリクエストがあったときに、
index.htmlがレスポンスとして返される仕組みが整いました。

次に実際にHTTPリクエストを受け取るためのエンドポイントの設定を行います。
設定といってもワンクリックだから簡単簡単。

![スクリーンショット 2018-03-27 16.56.01.png](https://qiita-image-store.s3.amazonaws.com/0/94505/431b734d-ca0c-2cca-2caf-79023403d5e2.png)

アクセス権限などの設定が完了するとエンドポイントが発行される。
![スクリーンショット 2018-03-27 16.57.03.png](https://qiita-image-store.s3.amazonaws.com/0/94505/dc7ad5e2-c4aa-1b24-4fb1-8152af9abf9b.png)

実際にエンドポイントへアクセスしてみると…
![スクリーンショット 2018-03-27 22.40.43.png](https://qiita-image-store.s3.amazonaws.com/0/94505/0277ffd0-c37f-c279-4b2c-92fe5ffa45e4.png)

お疲れ様でした！！

ちなみに開発途中のコードを見たいときは、
https://script.google.com/a/hogehoge/yourendpoint/exec
ではなく
https://script.google.com/a/hogehoge/yourendpoint/dev
にアクセスするとエンドポイント発行時のスナップショットではなく最新状態が確認できます。


ひとまず最低限の準備はできたので今日はここまで。

いまの状態だとCSSもJSもindex.html内にぶちこまれていて開発が進んでくると大変管理し辛いので、
次はプロジェクト内のjavascriptやcssファイルの別ファイル化について書きます。
ReadtheDocsでAuto Generateするときの注意

ReadtheDocsでautosummaryして、stubページを自動生成する時、RTD上のSphinxは記述するモジュールをimportします。ですので、localにはインストールされているパッケージがRTDではインストールされていない場合、モジュールが見つからず、ImportErrorとなってそのstubページが作成されないので注意が必要です。