OmniAICreator/Qiita-1.07M huggingface dataset:
Google Homeから音声でOmniFocusにタスクを追加する

## 本記事概要  

本記事では[Omnifocus](https://www.omnigroup.com/omnifocus)と呼ばれるタスク管理ツールに対してGoogle Homeから音声でタスクを追加する方法を記載しています。  
有名なタスク管理ツールのToDoistやiOS標準のリマインダーなどはIFTTTの連携可能サービスとして載せられていますが、Omnifocusについては、有料かつ、あまり日本では有名ではないこともあり、残念ながら連携対象サービスではありません。そのため一度Omni Sync ServerのMail Drop機能を経由させることで、Google Homeからタスク追加をさせることができました。  
![image.png](https://qiita-image-store.s3.amazonaws.com/0/237130/60ad4334-25e3-6e46-b073-82e2d1690c91.png)


## OmniFocusとは  

OmniFocusとは簡単に言ってしまうとタスク管理ツールですが、ただのタスク管理ツールではなく、**GTD**を精密に再現するために作られたツールです。  

GTDとは「Getting Things Done」と呼ばれるデビットアレンが提唱したストレスフリーで本当にやるべきことにのみ集中する仕事術のことです。この手法は私はとても気に入っていて、いつかブログの方で紹介したいと思いますが、今回は本筋と異なるので紹介だけに留めておきます。気になった方は[こちら](https://oldno07.com/think-about-gtd-omnifocus/)の記事を見ていただくと本手法の概要は理解していただけるかと。


##  設定手順   

### 1. OmniFocusをメールで受け取れるように設定  
OmniFocusへメールでタスクを追加するためには、[Omni Sync Server](https://manage.sync.omnigroup.com/)で設定する必要があります。リンクからOmni Groupの管理ページに入っていただいて、ログインしてください。  
ログイン後は以下画面で`ADD AN ADDRESS`を押していただくと自動でメールアドレスが発行されます。このメールアドレスに対して、タスクの内容をタイトルに入れて送ると、OmniFocusのInboxに自動で追加されるようになります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/237130/2eb2f1d8-501a-8e7a-a127-19b7e5afcff4.png)



### 2. IFTTTの連携準備  
IFTTTのアカウントは持っている前提とします。IFTTTのアカウントを持っていない方は[こちら](https://ifttt.com/)から。  

My Appletsから New Appletに遷移  
![image.png](https://qiita-image-store.s3.amazonaws.com/0/237130/ad3fa00d-eea2-06bd-a273-54bc1c9d74db.png)


### 3. Google Assistantの設定    
#### Google HomeのTriggerとなる文言を設定  
![image.png](https://qiita-image-store.s3.amazonaws.com/0/237130/bb466dd8-916d-5a05-f5d6-dbde613a854a.png)


#### +that としてGmailを追加  
![image.png](https://qiita-image-store.s3.amazonaws.com/0/237130/5266e97b-59ff-d5ae-91e5-eae302a82c94.png)

上記で完了となります。  
あとはAppletがRunの状態になっていれば検証可能状態になっているので、お手元のGoogle Homeを使って、試してみましょう。
VirtualBoxにCentOS 5.6 Install

# VirtualBoxにCentOS 5.6 Install

### 前提：
・VirtualBoxをInstall済み
・ImageをInstallしたことがある。

[ブラウザ]Cent_OS 5.6のダウンロード
一通りの機能を使用するため下記の1-8(CDROMに入るサイズに分割されているiso)をダウンロードします。

http://archive.kernel.org/centos-vault/5.6/isos/x86_64/

![image.png](https://qiita-image-store.s3.amazonaws.com/0/250215/ed919f17-bda5-11a4-bb9d-c32d74b616a3.png)

[VirtualBox]新規仮想マシンの作成
新規ボタンをクリックします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/250215/6780f0d2-4b28-f201-96b8-447eb0100ae0.png)

[VirtualBox]名前を入力するとタイプ、バージョンは自動で選択されます。
ネットワーク設定はブリッジに変更。それ以外は次へボタンをクリックし作成完了します。（ストレージのサイズはデフォルトの8GB）

![image.png](https://qiita-image-store.s3.amazonaws.com/0/250215/f7b75415-6d6c-6fe9-8905-2fd4761d2093.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/250215/7e98e470-7f43-4001-43df-c99c6f9a3c60.png)

[CentOS]IPをGUIから設定。(本環境では固定IPを使用)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/250215/6998096b-f536-7a06-2a5e-73920120122b.png)

[CentOS]Devices, DNSを設定します。

[CentOS]Firefoxを起動。ネットが閲覧できることを確認。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/250215/eb940c4a-fccc-821f-8122-6f652f0aa61e.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/250215/daa55db7-024d-41e8-847c-70b6312b04e1.png)

yumの設定

Terminal起動。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/250215/17a0fc9a-58bb-766e-4116-15501c1c5fdf.png)

Repositoryの編集
![image.png](https://qiita-image-store.s3.amazonaws.com/0/250215/6b442a1a-35fa-ab17-5faf-026abebe43b0.png)
①base,updates,extras,centosplus,contrib全てのbaseurlをhttp://vault.centos.org/5.6/os/x86_64/ に設定する
②base,updates,extras,centosplus,contrib全てのmirrorlistはコメントアウトにする

```repo:CentOS-Base.repo
[base]
baseurl=http://vault.centos.org/5.6/os/x86_64/

[updates]
baseurl=http://vault.centos.org/5.6/os/x86_64/

[extras]
baseurl=http://vault.centos.org/5.6/os/x86_64/

[centosplus]
baseurl=http://vault.centos.org/5.6/os/x86_64/

[contrib]
baseurl=http://vault.centos.org/5.6/os/x86_64/

```
gccをinstall

$ yum install gcc

![image.png](https://qiita-image-store.s3.amazonaws.com/0/250215/98927ef9-ab57-fd16-1b99-6c248e630094.png)

install出来たことを確認。

以上
Colaboratory でそのまま使えるようにした強化学習と転移学習の雛形2種

雛形プログラムを2019年5月のkerasとpython3で動くように更新した。以前のグーグルアカウントが消滅したので、新しいグーグルフォルダにおきなおした。

[Google Colaboratory](https://colab.research.google.com/notebooks/welcome.ipynb?hl=ja) でそのまま各セル左上の再生ボタンを押すだけで動くようにした雛形2種を [このグーグルドライブ公開フォルダ](https://drive.google.com/drive/folders/1OHN_atjRjMV6WAHPImR3nqGii_2J_iVj?usp=sharing) に置いた。フォルダに置いてあるノートブックをそのままColabで実行出来るが、以下その概要を紹介する。詳しい使い方はColabノートブック内のコメント欄を見て欲しい。

<dl>
<dt>転移学習による物体識別</dt>
<dd><a href="https://www.amazon.co.jp/dp/4839964262">PythonとKerasによるディープラーニング</a>の5章を参考にして、比較的少ない学習データで犬と猫を識別させる雛形を作った。与える学習データを換えれば何でも識別出来る（はず）</dd>
<dt>強化学習を用いた教師なしの重力四目並べを打つ雛形</dt>
<dd><a href="https://postd.cc/applied-data-sciencehow-to-build-your-own-alphazero-ai-using-python-and-keras/">PythonとKerasを使ってAlphaZero AIを自作する</a>にGoogle Alpha Zeroの方法を用いて全く教師データ無しに<a href="https://ja.wikipedia.org/wiki/%E5%9B%9B%E7%9B%AE%E4%B8%A6%E3%81%B9">重力つき四目並べ</a>の打ち方を学ぶサンプルプログラム(著作権はGPLv3)がついているが、これをGoogle Colab (Python 3)で動かすと結構エラーが出て動かない（特に人間相手に対戦する部分のコード）ので、それを修正し、さらにGoogle Colabで9時間学習したニューラルネットも添付して人間が学習したニューラルネット相手にすぐに対戦できるようにした。私は9時間学習したニューラルネット相手に勝てません。<br> これはまったく学習データを与えず、ゲームのルールを(Pythonプログラムとして) 与えるだけで強い打ち手を学習するところに感動した。Alpha Zeroの解説本として「<a href="https://www.amazon.co.jp/dp/4798157775">最強囲碁AI アルファ碁 解体新書 増補改訂版 アルファ碁ゼロ対応 深層学習、モンテカルロ木探索、強化学習から見たその仕組み</a> (7月発売予定)」 が気になっている。</dd>
</dt>
Deviseを入れたApplicationでVue(Webpack)を入れるとログアウトができなったのでメモ

**ちょっと詰まったのでメモ**

## Vueの導入の仕方
https://qiita.com/cohki0305/items/582c0f5ed0750e60c951

ここら辺を参考にするとできました。
しかしバージョンによってはバグが出るので要注意です。

## 本題
とりあえずVueをSetupし終わってVueのScriptは動くようになったと。

それで元々deviseが入っているサービスだったため`ログイン,ログアウト`は当然できる

しかし、Vueを入れて確認のためHeaderの挙動を見るためログインした後にログアウトしたら

![スクリーンショット 2018-05-27 12.17.35.png](https://qiita-image-store.s3.amazonaws.com/0/260218/f0dc9ffa-7486-fe36-4eb4-a3ad96c20539.png)

こんなエラー。

```
= javascript_include_tag 'application', 'data-turbolinks-track': 'reload'
= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload'
```
これを

```
 = javascript_pack_tag 'application', 'data-turbolinks-track': 'reload'
 = javascript_include_tag 'application', 'data-turbolinks-track': 'reload'
```

こんな風にすることで解決。
pytorchで手書き文字認識

とりあえずpytorchを使用して機械学習を動かしてみる．

## 環境構築
pythonを使用して作業を進めるが他環境と混ざるのを防ぐため，Minicondaを使用してpython環境を構築していく．

### MiniCondaで環境を用意
Condaの環境作成+起動

```sh
conda create -n [Env name] python=3.6
source activate [Env name]
```

### pytorchのインストール
[公式ページ](https://pytorch.org/)

```sh
conda install pytorch-cpu torchvision-cpu -c pytorch
```

## MNISTのサンプルを実行
下記サンプルからmain.pyをダウンロード，src以下に配置
[MNISTサンプル](https://github.com/pytorch/examples/tree/master/mnist)

実行に必要な物が不足していないかをとりあえず実行してusageを見ようとして下記コマンドを発行．
...と思ったら何故かこれだけで動いてしまった．

```sh
python -u ./src/main.py
```

```
Train Epoch: 1 [0/60000 (0%)]	Loss: 2.376790
Train Epoch: 1 [640/60000 (1%)]	Loss: 2.332813
Train Epoch: 1 [1280/60000 (2%)]	Loss: 2.291239
...
Train Epoch: 1 [58240/60000 (97%)]	Loss: 0.326841
Train Epoch: 1 [58880/60000 (98%)]	Loss: 0.338434
Train Epoch: 1 [59520/60000 (99%)]	Loss: 0.523333

Test set: Average loss: 0.2073, Accuracy: 9415/10000 (94%)

Train Epoch: 2 [0/60000 (0%)]	Loss: 0.352124
Train Epoch: 2 [640/60000 (1%)]	Loss: 0.380363
Train Epoch: 2 [1280/60000 (2%)]	Loss: 0.330867
...
Train Epoch: 10 [58240/60000 (97%)]	Loss: 0.182195
Train Epoch: 10 [58880/60000 (98%)]	Loss: 0.294599
Train Epoch: 10 [59520/60000 (99%)]	Loss: 0.147527

Test set: Average loss: 0.0491, Accuracy: 9850/10000 (98%)
```

## なぜ動いたのか
MNISTのデータはmain.pyの中で取得するように出来ていた．
[データセットの取得](https://pytorch.org/docs/stable/data.html#torch.utils.data.DataLoader)
[MNISTのデータ取得](https://pytorch.org/docs/stable/torchvision/datasets.html#mnist)
取得したMNISTの画像は../dataに保存される．
→main.pyを上位層から呼び出してしまうと作業フォルダの外にdataファイルを作られてしまう．
Windows TImeがCMOS Clockになって困った話

Windows Server 2012 R2でとある時刻系のアプリを起動したら
Windows Timeで時刻同期が出来なくなったのでシェア。


Source: Local CMOS Clockから復帰できない
=============

経緯を説明すると、
① Windows Server 2012 R2でとある時刻系のアプリを導入
② 動作が良くなかったので、アプリを止めてW32Timeに戻す
③ どうやってもNTPで時刻同期できない(Local CMOS Clockになってしまう)

W32Timeはスタートになっていて
![pct1.png](https://qiita-image-store.s3.amazonaws.com/0/191932/8e47d2b1-279e-06f7-062b-24b7de59766d.png)

コンフィグも問題無いように見えるのに
![無題.png](https://qiita-image-store.s3.amazonaws.com/0/191932/c334bf9c-a866-15b5-cb1a-535d706d9e4b.png)

CMOS Clockになってしまう
![無題2.png](https://qiita-image-store.s3.amazonaws.com/0/191932/5ea4491b-692f-706b-755f-77fffb343af0.png)

レジストリが書き換わっていた
=============

NTPで時刻同期出来ているサーバとの差分を探していったら、
レジストリの値が書き換わっていることに気づく。

○レジストリ
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpClient

InputProviderの値が0(無効)になっている

![無題3.png](https://qiita-image-store.s3.amazonaws.com/0/191932/ef210d65-7e1a-2885-a392-74e980cbb509.png)

InputProviderの値を1(有効)に修正して
![無題4.png](https://qiita-image-store.s3.amazonaws.com/0/191932/f8351391-c009-a18f-08e0-6fee691acac6.png)

Windows Timeを再起動して
![無題5.png](https://qiita-image-store.s3.amazonaws.com/0/191932/35c8e6e7-7709-4225-d501-91675da6ef84.png)

ステータスを確認して、NTPで時刻同期できていることを確認!!
![無題6.png](https://qiita-image-store.s3.amazonaws.com/0/191932/008b07c7-8ae1-66ef-90bf-ccbf2bb273f3.png)

正常復帰した時のコンフィグ
![無題10.png](https://qiita-image-store.s3.amazonaws.com/0/191932/6129cd79-1a31-f36c-7577-cae2d111049a.png)


(補足)レジストリのNtpClientのEnabledを0にすると…
=============
ネットに記事が見当たらなかったので補足

○レジストリ
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpClient

Enabledを0(無効)に設定すると

![無題7.png](https://qiita-image-store.s3.amazonaws.com/0/191932/158d692b-e27b-3f9b-d912-effab80647fd.png)

やっぱりCMOS Clockになってしまう
![無題8.png](https://qiita-image-store.s3.amazonaws.com/0/191932/68b54f2a-7a0e-c1ff-b95d-ea5ea381758b.png)

この場合はコンフィグも差分がある
![無題9.png](https://qiita-image-store.s3.amazonaws.com/0/191932/19c10edf-aa98-ce07-d134-7c231cff51ca.png)

NtpClientに関しては、記載している情報が少なかったので良い勉強になりました。
UbuntuのCLI上でGitを快適に使えるようにする方法

UbuntuのCLI上でGitを快適に使えるようにする方法についてまとめます。

# スクリプト
* __git-completion.bash__  
Gitコマンドで補完が効くようにするスクリプト
* __git-prompt.sh__  
CLI上にGitリポジトリの状態を表示するスクリプト

# 導入方法
1. `mkdir ~/.git_completion/`コマンドを実行し、スクリプト用のディレクトリを作成します。
1. `cd ~/.git_completion/`コマンドを実行し、カレントディレクトリをスクリプト用のディレクトリに移動します。
2. `git init`コマンドを実行し、Gitのリポジトリとして初期化します。
3. `git config core.sparsecheckout true`コマンドを実行し、sparsecheckoutを有効化します。
4. `echo "contrib/completion/" > .git/info/sparse-checkout`コマンドを実行し、Cloneするディレクトリを指定します。
5. `git remote add origin https://github.com/git/git`コマンドを実行し、リモートブランチを追加します。
6. `git pull origin -t`コマンドを実行し、タグの一覧をpullします。
7. `git checkout v$(git --version | awk '{print $3}')`コマンドを実行し、インストールされているGitのバージョンに合ったタグをcheckoutします。
3. `echo "git-completion.bash" "git-prompt.sh" | xargs  -n 1 bash -c 'chmod a+x contrib/completion/${0}'`コマンドを実行し、スクリプトに実行権限を付与します。
4. `cd`コマンドを実行し、カレントディレクトリをホームディレクトリに移動します。
5. `wget https://gist.githubusercontent.com/massongit/40620659e72f8c87ef734323443fe706/raw/e91ab87a3f6d83d24f9a9a37aa0b1519935622f4/.bashrc.patch ~/.bashrc.patch`コマンドを実行し、[`.bashrc`のパッチファイル](https://gist.github.com/massongit/40620659e72f8c87ef734323443fe706#file-bashrc-patch)をダウンロードします。
4. `patch ~/.bashrc ~/.bashrc.patch`コマンドを実行し、ダウンロードしたパッチファイルを適用します。
5. `rm ~/.bashrc.patch`コマンドを実行し、ダウンロードしたパッチファイルを削除します。
1. `source ~/.bashrc`コマンドを実行し、変更を反映させます。

# CLIの表示内容の設定
[bash-git-completion、__git_ps1のオプションを設定して様々な情報を表示する - 
gnarl,
技術メモ”’<marquee><textarea>￥](http://d.hatena.ne.jp/gnarl/20110901/1314846241)を参考に、`~/.bashrc`に変数を設定することで、表示内容をカスタマイズすることができます。

# 参考文献
* [「Git補完をしらない」「git statusを1日100回は使う」そんなあなたに朗報【git-completionとgit-prompt】 - Qiita](https://qiita.com/varmil/items/9b0aeafa85975474e9b6)
* [Git でサブコマンドを補完しようとしたときに Unknown option: --list-cmds と表示される問題の解決法 - Qiita](https://qiita.com/noraworld/items/aa73932d001d0746373d)
* [Gitで特定のディレクトリだけcloneする方法 - Qiita](https://qiita.com/kuriya/items/3b72c90eebd79a10b7a4)
Google Apps Scriptを利用して明日の天気を自動ツイートする

## 参考にさせて頂いた記事
- https://qiita.com/Ikanogo/items/1dce33c26559eac56a03
- https://tonari-it.com/gas-api-weather/
- https://webird-programming.tech/archives/274
- https://qiita.com/hkusu/items/1ba2de200f731e5ef374
- https://qiita.com/Yuta/items/b8106fabd5a1e2e0cd34


## **GASスクリプトを作成して天気予報を取ってくる**

```javascript
function getWeather(){
  var url = "http://weather.livedoor.com/forecast/webservice/json/v1?city=130010";
  result = UrlFetchApp.fetch(url); //WebAPIから情報取得
  var retw = result.getContentText(); //テキストだけ抜き出す
  var retjson = JSON.parse(retw); //JSON形式データを配列に格納
  var statement = "明日の天気("+ retjson.forecasts[1].date + ") - " + retjson.forecasts[1].telop; 
　　　　　//明日の日付と天気だけ抜き出す
  return statement;
}
```

LiveDoorから提供されている
「Weather Hacks（気象データ配信サービス）http://weather.livedoor.com/weather_hacks/ 」を利用します
(商用抜きという条件で無料利用可能、レスポンスがJSON形式)
スクリプトを書いたらファイル→プロジェクトのプロパティよりスクリプトIDを控えておく

## **Twitter Application Managementでアプリ作成**
https://apps.twitter.com/
<img src="https://qiita-image-store.s3.amazonaws.com/0/229696/0eea4d3e-dc03-c67f-d435-f8e8dd17590f.png" width=50%>
Nameとdescriptionは何でもいい、websiteも自由です（自分はbotにするtwitterアカウントのホームURLを入れました）
Callback URLsだけ指定
`https://script.google.com/macros/d/[Script ID]/usercallback`
(先ほど控えたスクリプトIDを入力)
Create My Twitter Applicationして、
・Consumer Key (API Key)
・Consumer Secret (API Secret)
を控えておく

## **bot本体の作成**

```javascript
var API_KEY = '****';
var API_SECRET = '****';
/* サービスの設定 */
function getService() {
  return OAuth1.createService('Twitter')
      .setAccessTokenUrl('https://api.twitter.com/oauth/access_token')
      .setRequestTokenUrl('https://api.twitter.com/oauth/request_token')
      .setAuthorizationUrl('https://api.twitter.com/oauth/authorize')
      .setConsumerKey(API_KEY)
      .setConsumerSecret(API_SECRET)
      .setCallbackFunction('authCallback')
      .setPropertyStore(PropertiesService.getUserProperties());
}
/* コールバック関数 */
function authCallback(request) {
  var service = getService();
  var authorized = service.handleCallback(request);
  if (authorized) return HtmlService.createHtmlOutput('認証成功');
}
/* 認証リセット */
function reset() {
  getService().reset();
}
/* 認証用URL */
function getOAuthURL() {
  Logger.log(getService().authorize());
}
/* リクエスト */
function request1(text) {
  var service = getService();
  if (service.hasAccess()) {
    var url = 'https://api.twitter.com/1.1/statuses/update.json';
    var payload = {
      status: text
    };
    var options = {
      method: 'post',
      payload: payload,
      escaping: false
    };
    var response = service.fetch(url, options);
    var result = JSON.parse(response.getContentText());
    Logger.log(JSON.stringify(result, null, 2));
    return result;
  }
}
function tweet(){
  request1(getWeather());
}
```
（https://qiita.com/Ikanogo/items/1dce33c26559eac56a03
より引用　tweetの部分だけ、getWeatherの実行結果をツイートしたいので変えています）
API_KEYとAPI_SECRETは先ほど控えたものを入力
初めにgetOAuthURLを実行して認証を通す
その後tweetを実行すればお天気ツイート完了

## **トリガー設定**
定期的に毎日実行したいのでトリガーを設定します
「編集 → 現在のプロジェクトのトリガー」より
<img src="https://qiita-image-store.s3.amazonaws.com/0/229696/d5b10805-2aea-63d6-b643-2955c04e37da.png" width=50%>
tweetを実行したい頻度、時間帯を設定すればOK
RailsのActiveRecord, ActiveModelのバリデーションエラーメッセージを日本語化

Railsのバリデーションエラーメッセージを日本語化する方法はすでにQiitaにいくつか上がっていますが、網羅的でなかったりするので、半分自分のメモ用に作成します。

## バージョン情報
```
'rails', '~> 5.1.4'
```


## Gemファイルの設定
Gemfileに下記を追記後、bundle install。

```
gem 'rails-i18n'
```

## config/application.rbの設定

```config/application.rb
config.i18n.default_locale = :ja
```

## カラム名の日本語化
* 日本語変換用のymlファイルを作成する。config/locales/models/に、ja.ymlというファイルを作成して、以下のようにカラム名と日本語の対応表を記述する。
* activerecordとactivemodelで別々に記載。検証したいモデルが複数ある場合は、modelsにmodel名を記載し、attributesで日本語化したいカラムを記載。

```config/locales/models/ja.yml
ja:
  activerecord:
    models:
      team: チーム
      user: 利用者
    attributes:
      team:
        name: 名前
        path: パス
      user:
        role: 役職
        name: 名前
        email: メールアドレス
  activemodel:
    models:
      request_form: 申請フォーム
    attributes:
      request_form:
        description: 申請理由
```

## config/application.rbの設定
config/application.rbにこのymlファイルの読み込む一文を追記。

```config/application.rb
config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.yml').to_s]
```

## 参考
[Railsのバリデーションエラーのメッセージの日本語化](https://qiita.com/Ushinji/items/242bfba84df7a5a67d5b)
PhotoshopとSwipeGeneratorでアニメーションを作る 2


# SwipeとSwipeGeneratorについて
SwipeとSwipeGeneratorの説明やインストールについては以下のページを参照してください。
[PhotoshopからSwipeを作成するSwipeGenerator](https://qiita.com/isamua/items/4d328b587434d111e495)
[PhotoshopとSwipeGeneratorでアニメーションを作る １](https://qiita.com/isamua/items/ef9b7bafdb7422ebbcc9)

# Swipeのプロパティー

ページ、素材のレイヤー名にSwipeのプロパティーを指定できるようになりました。Swipeの素材のプロパティーを指定することにより、画像に揺れなどのアニメーションを加えたり、半透明にする、またページのプロパティーを指定することにより、ページ遷移時の効果を変えることができます。

素材のレイヤー名に、

```
loop:style:wiggle:count:3 opacity:0.9 repeat:false
```

ページのレイヤーグループ名に

```
transition:fadeIn play:scroll duration:0.2 repeat:true vibration:false
```

のように、指定すると、生成されるswipeに反映されます。それぞれの要素は:で接続し、プロパティーは半角スペースで区切っています。


## 素材プロパティー

### loop
繰り返しのアニメーションを指定できます。

```
loop:style:{以下のスタイルのいずれか}:count:{number}:{options_key}:{options_value} 
```
のような形式で指定します。

- *vibrate*: 左右に揺らします。deltaで揺れの大きさを指定できます。

```
  loop:style:vibrate:count:5:delta:10
```
- *blink*: 点滅します。

```
 loop:style:blink:count:10
```

- *wiggle*: 揺れます。deltaで揺れの角度を指定。

```
 loop:style:blink:count:10:delta:30
```
- *spin*: 回転します。

```
 loop:syle:spin
```

- *shift*: 一方向に動きます。directionで上下左右（東西南北、"n", "s", "e" or "w", the default is "s"）に移動します。

```
 loop:style:shift:direction:e
```
### bc

背景色を指定します。

```
bc:#33aaca
```
### opacity
透明度を指定します。0 ~ 1。

```
opacity:0.3
```

### repeat
繰り返しを指定。

```
repeat:true
```

## ページプロパティー

### transition
ページのtransitionを指定します。

- *scroll*: 新しいページがスクロールします。
- *fadeIn*: フェードインします。
- *replace*: ページが置きかわります。

### play
 playはアニメーションの動作タイミングを指定します。
- *auto*: ページの表示が終わった後にアニメーションが動作します。
- *pause*: アニメーションが動作しません。
- *always*: ページの表示が終わった後にアニメーションが動作します。昇降順と逆順の両方のページ移動の時にアニメーションが動作します。
- *scroll*: ページがスクロールしている間にアニメーションが動作します。

### bc
背景色を指定します。
```
bc:#33aaca
```
### duration
 アニメーションの動作する時間の長さを指定します。標準は0.2秒です。

### repeat
 アニメーションがリピートするかどうかをしています。defaultはfalseです。

# サンプル

実際のレイヤー名指定のサンプルです。

<img width="444" alt="スクリーンショット 2018-05-27 8.55.42.png" src="https://qiita-image-store.s3.amazonaws.com/0/25071/b90704f1-2b23-8326-63af-9c0874f803e3.png">

生成されたアニメーションです（後半部分）

http://to-kyo.to/~isamu/swipe_sample_movie2/#0
Golangの`json.Unmarshal`と`json.NewDecoder`の使い分けについて


- `JSON`をデコードする時に`json.Unmarshal`と`json.NewDecoder`を使っているパターンがあって、どっち使えばいいねんって人向けに書きました
- [ここ](https://blog.golang.org/json-and-go)に詳しく書いてありました

## 結論
- ストリームから情報を読み込んだ時は`json.NewDecoder`を使おう！
- それ以外の場合は`json.Unmarshal`を使おう！

## 解説

- どちらでも大まかな流れとして
	1. デコードしたものを格納する`Struct`を用意する
	2. 用意した`Struct`へのポインタをメソッドに渡し、デコード情報を流し込んでもらう

という所は変わらない

- 今回は便宜上、データを格納する`dataStruct`という型がある前提で話を進める

### `json.NewDecoder`について
- `http.Get`で帰ってきた`resp.Body`などの **io.Reader型**に対して使う
- 主な使い道としては、今あげた`http.Get`のレスポンス処理がほとんどだと思う

```go
resp, err := http.Get("http://api.sample")
// 中略
var d dataStruct
if err := json.NewDecoder(resp.Body).Decode(&d); err != nil {
  // ...
}
```

### `json.Unmarshal`について
- `[]byte`型のデータをデコードする
- ストリームの関係ない所（極端な話、自分で作ったJSON型の文字列をデコードしたい場合など）で使う

```go
var jsonStr = `{"Name":"Bob","Age":"24"}`
var d dataStruct
json.Unmarshal([]byte(jsonStr), &d)
```
C++ の http クライアントの使い方 (Post)

```cpp:http_post.cpp
// --------------------------------------------------------------------
/*
	http_post.cpp

					May/27/2018

*/
// --------------------------------------------------------------------
#include	<string>
#include	<iostream>
#include	<cstring>

#include	<curl/curl.h>

using namespace std;

// --------------------------------------------------------------------
size_t callBackFunk(char* ptr, size_t size, size_t nmemb, string* stream)
{
	int realsize = size * nmemb;
	stream->append(ptr, realsize);
	return realsize;
}

// --------------------------------------------------------------------
string url_post_proc (const char url[],const char post_data[])
{
	CURL *curl;
	CURLcode res;
	curl = curl_easy_init();
	string chunk;

	if (curl)
		{
		curl_easy_setopt(curl, CURLOPT_URL, url);
		curl_easy_setopt(curl, CURLOPT_POST, 1);
		curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data);
		curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(post_data));
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callBackFunk);
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, (string*)&chunk);
		curl_easy_setopt(curl, CURLOPT_PROXY, "");
		res = curl_easy_perform(curl);
		curl_easy_cleanup(curl);
		}
	if (res != CURLE_OK) {
		cout << "curl error" << endl;
		exit (1);
	}

	return chunk;
}

// --------------------------------------------------------------------
int main (int argc,char *argv[])
{
	cerr << "*** 開始 ***\n";

	char url_target[] = "https://httpbin.org/post";
	char post_data[] = "user=jiro&password=123456";

	string str_out = url_post_proc (url_target,post_data);

	cout << str_out << "\n";

	cerr << "*** 終了 ***\n";

	return 0;
}

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

```text:Makefile
http_post.exe: http_post.cpp
	clang++ -o http_post http_post.cpp -lcurl
clean:
	rm -f http_post
```

実行結果

```text
$ ./http_post 
*** 開始 ***
{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {
    "password": "123456", 
    "user": "jiro"
  }, 
  "headers": {
    "Accept": "*/*", 
    "Content-Length": "25", 
    "Content-Type": "application/x-www-form-urlencoded", 
    "Host": "httpbin.org", 
    "X-Amzn-Trace-Id": "Root=1-5f25462e-4f05abfe4fb47190dc0ef00c"
  }, 
  "json": null, 
  "origin": "219.126.139.62", 
  "url": "https://httpbin.org/post"
}

*** 終了 ***
```

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

```text
$ clang++ --version
Ubuntu clang version 15.0.2-1
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
```
C++ の http クライアントの使い方 (Get)

Ubuntu 22.10 でのライブラリーのインストール

```bash
sudo apt install libcurl4-openssl-dev
```

```cpp:http_get.cpp
// --------------------------------------------------------------------
/*
	http_get.cpp

					May/27/2018

*/
// --------------------------------------------------------------------
#include	<string>
#include	<iostream>

#include	<curl/curl.h>

using namespace std;

// --------------------------------------------------------------------
size_t callBackFunk(char* ptr, size_t size, size_t nmemb, string* stream)
{
	int realsize = size * nmemb;
	stream->append(ptr, realsize);
	return realsize;
}

// --------------------------------------------------------------------
string url_get_proc (const char url[])
{
	CURL *curl;
	CURLcode res;
	curl = curl_easy_init();
	string chunk;

	if (curl)
		{
		curl_easy_setopt(curl, CURLOPT_URL, url);
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callBackFunk);
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, (string*)&chunk);
		curl_easy_setopt(curl, CURLOPT_PROXY, "");
		res = curl_easy_perform(curl);
		curl_easy_cleanup(curl);
		}
	if (res != CURLE_OK) {
		cout << "curl error" << endl;
		exit (1);
	}

	return chunk;
}

// --------------------------------------------------------------------
int main (int argc,char *argv[])
{
	cerr << "*** 開始 ***\n";

	char url_target[] = "https://httpbin.org/get";

	string str_out = url_get_proc (url_target);

	cout << str_out << "\n";

	cerr << "*** 終了 ***\n";

	return 0;
}

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

```text:Makefile
http_get.exe: http_get.cpp
	clang++ -o http_get http_get.cpp -lcurl
clean:
	rm -f http_get
```

実行結果

```text
*** 開始 ***
{
  "args": {}, 
  "headers": {
    "Accept": "*/*", 
    "Host": "httpbin.org", 
    "X-Amzn-Trace-Id": "Root=1-5f253e0e-8f5d92c07e9684c0788f1b40"
  }, 
  "origin": "219.126.139.62", 
  "url": "https://httpbin.org/get"
}

*** 終了 ***
```

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

```text
$ clang++ --version
Ubuntu clang version 15.0.2-1
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
```

関連ページ
[C++ の http クライアントの使い方 (Post)](https://qiita.com/ekzemplaro/items/97bc000576a6210a3068)
優しすぎる、Firebaseで音速hostingしてカスタムドメインの適応したおはなし

#firebaseとは

**mBaaS**と呼ばれる```（mobile Backend as a service）```
簡単に言えばサーバーをわざわざ組み立てなくても、視覚的にサポートしてくれるよというものですね。とりあえず音速開発するためには、めちゃくちゃ助かるものです・・・。
なんならデザイナーでも「音速で」出来ちゃいます。

今回は、知識のない手だけ動く猿の僕でもホスティングが音速でしかもSSL認証までサクッと対応できた話をします。

でもお高いんでしょと思ったあなた、かかった値段はドメイン取得費だけ（めっちゃアクセスとか来ると、任意での課金になるシステムです。その辺は省くので調べて見てください）

※先に言って起きますが、備忘録ということで、読みにくいかもしれません。そしてめちゃくちゃラフに書いています。

#はじめよう

## 準備1 firebaseプロジェクトを立ち上げる

以下のリンクから、どうぞ
https://firebase.google.com/?hl=ja

![スクリーンショット 2018-05-27 8.04.00.png](https://qiita-image-store.s3.amazonaws.com/0/98160/46520eda-26c0-6da8-3c00-5cc36695707b.png)

使って見るを押してください。

![スクリーンショット 2018-05-27 8.04.53.png](https://qiita-image-store.s3.amazonaws.com/0/98160/324baf51-38a7-4a51-66ff-27a46b9543ac.png)

追加してください

## 準備2 ドメインを取ろう
今回は　お名前.comでとりました。
メールアドレスの認証手続きしておかないと、せっかく取得したドメインも使えないのでその点だけ注意してください。
https://www.onamae.com/
だいたい1円ドメインだと手数料込みで200円行かなかったです。

## はじめてのデプロイ

めんどくさそうですが秒殺です。
https://firebase.google.com/docs/hosting/deploying?hl=ja
このサイトを参考に CLIツールをインスコします
その前に、Node.jsをインスコしておいてください。
```「Node.js バージョン 5.10.0 以降が必要です。」```
らしいです。 


```

npm install -g firebase-tools
```
してください。npmというのが、node.jsを入れた時に付いて来ます

適当にディレクトリを作ってその中で

```
firebase init hosting
```
してください。
「Select a default Firebase project for this directory」
とコマンド上で聞かれるので、準備1で作ったプロジェクトを選択してください

その後で
? What do you want to use as your public directory? 
? Configure as a single-page app (rewrite all urls to /index.html)

と聞かれるので、聞かれたことをコマンドに向けて回答しましょう。

そうするとfirebase.jsonと「? What do you want to use as your public directory? 」で回答した名前のディレクトリが作られます。
single pageだと、そのディレクトリの中にindex.htmlが作られました。
（この辺教えてください、お兄さん。）

public　directoryの中にindex.htmlとかimageディレクトリとかそういうのをぶっこんでいく感じです。
そして、ぶっこんでローカル環境で動くことを確認したら

firebase.jsonがあるところ（つまり作業ディレクトリのルートで）

```
firebase deploy
```

おしまいです。
コマンド上にurlが表示されます。また、firebase console　からhosting タブを選択するとそこにも表示されます。

## カスタムドメインの適応
![スクリーンショット 2018-05-27 8.26.13.png](https://qiita-image-store.s3.amazonaws.com/0/98160/b45a2880-b849-8bb5-0699-fa6f66523295.png)

ドメインを接続を押しましょう。
そして、ドメインを書いてねっていう画面が出るので、準備2で取得したドメインを入れてください。
完了すると、

![スクリーンショット 2018-05-27 8.26.52.png](https://qiita-image-store.s3.amazonaws.com/0/98160/84245ef9-a8fb-a077-96bf-0e3223fbaa78.png)

こんな感じで指示されます。

次にお名前.comへ移動して
![スクリーンショット 2018-05-27 8.28.34.png](https://qiita-image-store.s3.amazonaws.com/0/98160/0e40f940-26f0-c5b0-1007-9791f72bad58.png)
してください

この辺は
https://support.google.com/a/answer/1659753?hl=ja
ここでわかりやすく説明してくれているので、僕は説明しません。

![スクリーンショット 2018-05-27 8.31.23.png](https://qiita-image-store.s3.amazonaws.com/0/98160/ea917c21-325e-bd3a-2dd7-4fdaff8fa684.png)

ここに上記で指定されたTXTと値を入れるだけです。
TTLが何かというのはググってください。そのままで良いです

そして数分〜何時間か待つと

![スクリーンショット 2018-05-27 8.32.51.png](https://qiita-image-store.s3.amazonaws.com/0/98160/57cb67e5-2433-bdcf-bd37-0e41b83dc0d2.png)
こうなるので、

お名前.comの方で
TTLを入れた時のようにAを入れてあげてください。

その後数時間から数十時間待つと、
完了します。


おしまい。


秒速でびっくりしましたね！！！
Meteor で Cannot find module 'fibers' と怒られた時の対処

**注意: この記事は 2018.5.27 時点での latest stable = Meteor 1.6.1.1 向けに書かれています。**~~Meteor 1.6.1.2 および 1.7系では役にたたないかもしれません。~~

2018.8.15 追記： **この記事の内容は Meteor 1.6.1.2 以降では役に立ちません。**

# 症状

Windows で Meteor (1.6.1.1) を使っていると、Development server が突如として起動しなくなります。

こんなかんじ。

```
W20180527-07:08:33.559(9)? (STDERR) module.js:549
W20180527-07:08:34.405(9)? (STDERR)     throw err;
W20180527-07:08:34.419(9)? (STDERR)     ^
W20180527-07:08:34.420(9)? (STDERR)
W20180527-07:08:34.422(9)? (STDERR) Error: Cannot find module 'fibers'
W20180527-07:08:34.422(9)? (STDERR)     at Function.Module._resolveFilename (module.js:547:15)
W20180527-07:08:34.423(9)? (STDERR)     at Function.Module._load (module.js:474:25)
W20180527-07:08:34.424(9)? (STDERR)     at Module.require (module.js:596:17)
W20180527-07:08:34.425(9)? (STDERR)     at require (internal/module.js:11:18)
W20180527-07:08:34.426(9)? (STDERR)     at Object.<anonymous> (C:\Users\masayuki\Documents\project\fgw\.meteor\local\build\programs\server\boot.js:1:75)
W20180527-07:08:34.427(9)? (STDERR)     at Module._compile (module.js:652:30)
W20180527-07:08:34.428(9)? (STDERR)     at Object.Module._extensions..js (module.js:663:10)
W20180527-07:08:34.429(9)? (STDERR)     at Module.load (module.js:565:32)
W20180527-07:08:34.430(9)? (STDERR)     at tryModuleLoad (module.js:505:12)
W20180527-07:08:34.431(9)? (STDERR)     at Function.Module._load (module.js:497:3)
```

`fibers`モジュールがないんだから、と `npm` や `meteor npm` でインストールしようとしても、うまくいきません。

というのも、Windows では シンボリックリンクがうまく動かないからです。

# 解決

無理くり `fibers` をインストールしてごにょごにょしてたのですが、次の RC で解消したらしいのでおとなしくアップデートしましょう。

```bash
$ meteor update --release 1.6.1.2-rc.0
```

1.7系の RC にアップデートしてもいいようです。
ちなみに、安定版では依存関係を手動で解消するしかありません。
枯れていない技術だからと割り切るしかなさそうです。Meteor らしい。

サーバー側でエラーは出なくなったけれどクライアントで読み込めないなら、
依存パッケージのアップデートを試してみましょう。

```bash
meteor update
```
改行・ブランクのみのgit差分を一気にResetするPowershellスクリプト

[git diffからのvimで変更行数が少ないファイルの順番にソートして無駄ファイルをコミット対象から外す](https://qiita.com/naoya21/items/9564f1b116b45786a382)の続き、と言うか改良。

自動でストアドやらテーブル定義やらを作成するスクリプトを自作したはいいが、変にブランクやら改行やらが含まれてしまうことが原因で、上記記事の通り、それらは除外した上で本当の差分を出す手順を作ったものの、非常に煩雑でなかなか他の人にやってもらうのにはハードルが高いので、Powershellスクリプトを書いて同じことを実行することにした。

```powershell
$diffs = git diff --stat-width=800 -w --ignore-blank-lines

foreach($diff in $diffs){
    if($diff -match "\|\s+0"){
        $diff -match "\S+"
        $filename = $matches[0]
        git checkout $filename
        echo "$filenameをResetしました。"
    }
}
```

このクエリをファイルに保存するだけで、改行・ブランクだけのgit差分が一度にResetされる。
ddlgenerator ： ファイルからDDLを簡単作成する

データベースに新規データを追加する際にDDL(SQL)作成は意外と面倒。

そんな時は、GitHubで公開されているddlgeneratorが便利。

例えば、以下のコマンド一発で、対象ファイルからデータ構造を推察して
対応するデータベース向けのCREATE TABLE文とINSTERT文を自動作成してくれる。

```
ddlgenerator -i postgresql sampledata.csv
```

ddlgenerator GitHub：
https://github.com/catherinedevlin/ddl-generator

###インストール

python3環境対応で、以下でおしまい。

```
pip3 install ddlgenerator
```

###サポート入力ファイル

Pure Python
YAML
JSON
CSV
Pickle
HTML


##対象データベース

drizzle
firebird 
mssql
mysql
oracle
postgresql
sqlite
sybase
sqlalchemy
django
heroku + python + flask + selenium + headless-chrome を本番公開

この環境でいろいろとやる機会があったので、いっそメモっとこうと思いました。
Local で動いてる前提です。

## heroku に chromedriver と chrome を追加する
heroku create して push した後、次の Buildpacks を追加する

```shell:terminal
$ heroku buildpacks:set https://github.com/heroku/heroku-buildpack-chromedriver.git
$ heroku buildpacks:set https://github.com/heroku/heroku-buildpack-google-chrome.git
```

### 念の為に heroku の管理画面を確認する
heroku > personal > [project] > Settings > Buildpacks
![スクリーンショット 2018-05-27 6.17.44.png](https://qiita-image-store.s3.amazonaws.com/0/1931/b9b09489-44c4-33ec-47b1-de2e6ede07cd.png)

これが追加されていれば成功。(若干ディレイがある)
追加されない場合は管理画面から入れる

- https://github.com/heroku/heroku-buildpack-google-chrome.git
- https://github.com/heroku/heroku-buildpack-chromedriver.git


あとは再度 push すれば公開されます。
VPS などで最初から環境構築すると chromedriver 周りの設定がめんどいので、
heroku だと簡単です。
AWS Beanstalk で作ったLaravel環境にBASIC認証をかける最もカンタンな方法


# 結論

public ディレクトリにいつものように、```.htpasswd``` を作って、同じディレクトリの ```.htaccess``` を書き換えます。
ポイントは、htpasswdが設置されている絶対パスがどこなのか？ですが、ふつうに ```/var/www/html/public```だったと。

```:/public/.htpasswd
admin:(パスワード生成ツールなどで作ったハッシュ)
```

```:/public/.htaccess
AuthType Basic
AuthName "Input your ID and Password."
AuthUserFile /var/www/html/public/.htpasswd
require valid-user

<IfModule mod_rewrite.c>
....以下はそのまま
```

## パスが違うようです

もしかしたら構成によって変わるかもしれません。不安な場合は ```info.php``` を作って確認後に消すとかすると良いかと思います。

```php:/public/info.php
<?php
phpinfo();
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/129854/3072c3f8-acf1-be31-b73e-81bba71a4321.png)


# なんなのこの投稿？

いや、ググらせていただいたんですが、「開発環境だけ利くようにする」とか「パスワードを自動的に作る」とかカッコいい方法がいろいろ出てきて、逆に「いや、とりあえず環境分けなくていいんで」とか「いつものやりかたはダメなの？」と思ってしまったけど、**そんなことないよ！** と言いたかっただけです。

Elastic Beanstalk すごいっすねー。前にLaravel環境構築したときは、サーバーにあれやこれやと前提条件がついた上に、MySQLでデータベース開いてvendorをFTPでアップして……とかやっていたのですが。もう作成も更新もGITにPUSHするだけとは。

そんな話もまた機会と需要があれば書きたいですね
（＾＾）
AWS Lambdaでpandasとscikit-learn使おうとしてハマった話 (/tmp からのモジュールの読み込み)

機械学習モデルを利用したAPIを作成しようと思い、
Lambdaで`pandas`と`scikit-learn`を使おうとしてみたら思いのほかハマった。

## 今回のハマりポイント
- lambdaのデプロイパッケージ容量制限(ZIPで50MB)
- Amazon Linuxの環境依存
- pythonでのモジュールのインポート

## lambdaのデプロイパッケージ容量制限(ZIPで50MB)
まず問題になったのはデプロイパッケージ容量だ。
`pandas`と`scikit-learn`と依存ライブラリを含めると、zipで圧縮しても60MBほどあって、制限を超えてしまう．．．

そこで、**/tmp フォルダ** を使う

lambdaではユーザーが使用できる容量512MBの`/tmp`が割り当てられている。
つまり、デプロイパッケージに入りきらないライブラリを
実行時にs3からダウンロードして`/tmp`に展開してパスを通した後インポートすればいい。

今回やりたいのはコレだけだけど、付随する問題がいろいろ出てきて死んだ。

## Amazon Linuxの環境依存
まず、容量制限に引っかからない`pandas`と依存ライブラリを含めたデプロイパッケージ(30MBほど)を作成し動作確認してみた。

なんかエラー出る．．．
`Unable to import module 'main': Missing required dependencies ['numpy']`

`numpy`はパッケージに含めているのに、、なんで？

調べてみるとこんな記事が見つかった。
[Amazon Linuxと同じオプションでビルドされたPythonを使って安全にLambda functionをデプロイしよう](https://qiita.com/marcy-terui/items/8cf32632d6548e2f310c)

つまりlambdaで正常に動作させるためには、
**lambda実行環境である Amazon Linux でデプロイパッケージを作成する必要がある**、ということ。

めんどいかよ

`docker`環境、以前ec2で使ってたのがあるけど、
アクセスキー紛失してアクセスできなくなったんだよ(え？)

インスタンス作り直すのめんどいなー、と思ってggってたら、
すばらしい人がすでに`Amazon Linux`でビルドしたパッケージを公開してくれてた。
[https://github.com/chennavarri/aws-lambda-pandas-sample](https://github.com/chennavarri/aws-lambda-pandas-sample)
[https://github.com/ryansb/sklearn-build-lambda](https://github.com/ryansb/sklearn-build-lambda)

．．．だめでした。
`python`のバージョンがそれぞれ違った。

しかたないのでec2で`Amazon Linux`環境作ってパッケージ作った。
これを使うとlambda環境まで再現できる。
[https://github.com/lambci/docker-lambda](https://github.com/lambci/docker-lambda)

## pythonでのモジュールのインポート
ようやくデプロイパッケージができたのでlambdaで実行してみる。
`pandas`はデプロイパッケージに含めて、`sklearn`は`/tmp`以下に展開することにした。

コードは単純で、
s3から`sklearn`のzipファイルを`/tmp`にダウンロードし、展開するというもの。

```main.py
import boto3
import os
import sys
import zipfile
import pandas as pd
from pprint import pprint

s3 = boto3.resource('s3')
bucket = s3.Bucket('data')

def main():
    load_sklearn()
    pprint(os.listdir("/tmp/site-packages/"))

    import sklearn

    return "done"

def load_sklearn():
    bucket.download_file("sklearn-packages.zip", '/tmp/sklearn-packages.zip')

    zip_ref = zipfile.ZipFile('/tmp/sklearn-packages.zip', 'r')
    zip_ref.extractall('/tmp')
    zip_ref.close()

    os.remove("/tmp/sklearn-packages.zip")

def handle(event, context):
    return main()
```

実行結果 (抜粋)

```
['bin',
 'scipy-1.1.0.dist-info',
 'sklearn',
 'scipy',
 'scikit_learn-0.19.1.dist-info']
No module named 'sklearn': ModuleNotFoundError
```

`sklearn`はちゃんとダウンロードされて展開されているのに、
モジュールが見つからないというエラー．．．

どうやらlambdaの環境変数で`PYTHONPATH`に`/tmp/site-packages`を追加していたのが原因らしい。
`PYTHONPATH`から`/tmp/site-packages`を消し、**モジュール追加後にモジュールパスを追加する**ようにすると正常に動作した。

```main.py(抜粋)
def main():
    load_sklearn()
    pprint(os.listdir("/tmp/site-packages/"))

    sys.path.append('/tmp/site-packages') # ←これを追加
    import sklearn

    return "done"
```

実行結果

```
"done"
```

あらかじめ環境変数で指定したモジュールパスについては、実行の初めに探索されて、以降に追加されたモジュールは検知しない、とかなのかな？
`import`文のタイミングで探索すると思ってたから、最初は詰んだかと思った。
詳しい方はコメントぜひ！

## まとめ
`cold start`だと数秒かかるので実用は厳しい
おすすめを教えてほしい
hyperターミナル

Zsh + preztoの環境にも飽きてきた頃、hyperというターミナルを見つけました。

https://github.com/zeit/hyper

Macなら

```
brew update
brew cask install hyper
```

でインストール可能です。
WindowsやLinuxでも利用できるようです。

そして、醍醐味のプラグインをインストールすると面白いことになります。

```
hyper i hyper-pokemon
```

あっという間にポケモンターミナルの完成です。


<img width="634" alt="スクリーンショット 2018-05-27 3.22.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/250158/53839bee-31a8-3a19-b59b-c491c7c4320d.png">

<img width="637" alt="スクリーンショット 2018-05-27 3.22.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/250158/45f284b9-5e92-735b-8c35-70a4f52d8c61.png">

<img width="638" alt="スクリーンショット 2018-05-27 3.23.28.png" src="https://qiita-image-store.s3.amazonaws.com/0/250158/ab7ea404-5842-a462-0674-f41389371bea.png">

すぐに反映されるのも良い点です。

```
hyper i hyperline
```

残念なことに日本語が正しく表示されないのが難点。
hyper.jsのfontFamilyに日本語フォントを指定してもダメでした。
MaxIfsを使ったユニークソート

# MaxIfsについて

WorksheetFunction の maxifsを使うと簡単にユニークソートが出来る事に。

同じテーブルのR列をソートして結果をU列 (=TSLU([R],[U]))に表示します。




```vb
Function TSLU(R, U, Optional S = "") ' TABLE SORT LARGE UNIQ
    On Error Resume Next
    Dim M: M = MM(U)
    Dim J: J = DI(U, M - 1)

    S = IFC(M = 1, WorksheetFunction.Max(R) _
                 , WorksheetFunction.MaxIfs(R, R, CC("<", J)))
    TSLU = IFZS(S)
End Function
```

但し、R列に0を含む場合はSPACEになって、出力結果が正しくないので、以下の処理を足します。

```vb
    If S = 0 Then
       If MI(R, 0) = "" Then
          S = ""
       Else
          If M > 1 And (J <= S Or J = "") Then S = ""
       End If
    End If
```
長いので、一行にまとめて、最終的には、以下のようになります。

```vb
Function TSLU(R, U, Optional S = "") ' TABLE SORT LARGE UNIQ
    On Error Resume Next
    Dim M: M = MM(U)
    Dim J: J = DI(U, M - 1)

    S = IFC(M = 1, WorksheetFunction.Max(R) _
                 , WorksheetFunction.MaxIfs(R, R, CC("<", J)))
                  
    TSLU = IFZS(S, IFNC(MI(R, 0) = "", IFNC(M > 1 And (J = "" Or J <= S), 0)))
End Function

Function IFNC(C, V, Optional S = "")    ' IF NOT C THEN V ELSE S
    If C Then IFNC = S Else IFNC = V
End Function
```




以上
mdfindの結果をtestコマンドにパイプできない

# mdfindの結果をtestコマンドにパイプしたかった

**最初に書いていたコード。
何回やっても `0` しか出力しない。**

```bash

mdfind -name ファイル名 | test -z; echo $?

```

それもそのはず、上記コードだと`test -z`の結果が毎回出力されるだけです。
デフォルト出力が`0`なので、毎回`0`だったわけです。
パイプすると、`test -z パイプされたもの`ってなるかと思ったのですが、違うようです。
標準入力と引数の違いかと推測してます。
ということで、`test`コマンドにはパイプできないようです:information_desk_person:


# 動作するコード

```bash

result=$(mdfind -name ファイル名);test -z "$result"; echo $?
```

`test -z 検証ち`という風に指定してあげました。
これなら動作するようです。


# 少し改良

```bash
[ -z $(mdfind asfdsd.txt) ]; echo $?
```

以上！！:runner_tone2:
GCP超初心者がローカルのgsutilを設定してた際のメモ

## 経緯

昨日参加させて頂いたGCPの勉強会で、Dataflowのハンズオンをしていた際、
gsutilで少し引っかかったため、ググりながら構築してた際の手順を備忘録として纏めてみます。

## 対象環境

* MacBook Pro (13-inch, 2016, Two Thunderbolt 3 ports) 256GB
* Mac OS High Sierra

## 前提

* [Homebrew](https://brew.sh/index_ja.html)がインストールされていること

## gsutilって何？

Google Cloud Storageを操るコマンドツールらしいです

[gsutil ツール  |  Cloud Storage ドキュメント  |  Google Cloud](https://cloud.google.com/storage/docs/gsutil?hl=ja)

## インストール

Cloud SDKインストール

```
$ brew cask install google-cloud-sdk
```

パスの設定

```
$ cd
$ echo source '/usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/path.bash.inc' >> .bash_profile
$ echo source '/usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/completion.bash.inc' >> .bash_profile
$ source .bash_profile
```

## クラウドのプロジェクト設定

コンポーネントアップデート

```
$ gcloud components update
All components are up to date.
```

プロジェクト設定開始

```
$ gcloud init
```

GCPを利用するGoogleアカウントにログインします

```
You must log in to continue. Would you like to log in (Y/n)? Y
```

ブラウザが表示されたら、GCPで利用するアカウントを選択

![スクリーンショット 2018-05-27 1.25.58.png](https://qiita-image-store.s3.amazonaws.com/0/25578/9bf46ee0-e406-9e4b-b583-a18398715952.png)

アクセスを許可します

![スクリーンショット 2018-05-27 1.26.07.png](https://qiita-image-store.s3.amazonaws.com/0/25578/282d33c6-3051-6b71-707b-4534583e0d5a.png)
![スクリーンショット 2018-05-27 1.26.17.png](https://qiita-image-store.s3.amazonaws.com/0/25578/aeb938c2-629d-fc0d-04ca-ad99f9867d5c.png)

コンソールに戻るとログインしたアカウントが表示されています

```
You are logged in as: [メールアドレス].
```

プロジェクト選択は既存プロジェクトを選択

```
Pick cloud project to use:
 [1] プロジェクト名
 [2] Create a new project
Please enter numeric choice or text value (must exactly match list item): 1
Your current project has been set to: [プロジェクト名].
```

リージョンのデフォルト設定は東京に

```
Do you want to configure a default Compute Region and Zone? (Y/n)? Y
~~省略~~
[29] asia-southeast1-b
~~省略~~
Please enter numeric choice or text value (must exactly match list
item):  29
```

## 結果

gsutil cpコマンドを利用し、GCPのストレージにハンズオン用のデータをアップロードするのになんとか間に合いました

## オチ

Macにインストールせずとも、Google Cloud Shellでもgsutil使えたっぽいです。。
コンソールになにがあるのかまだ把握できてません。。

![スクリーンショット 2018-05-27 1.40.41.png](https://qiita-image-store.s3.amazonaws.com/0/25578/731fa95b-a43b-8d6d-4d99-51b4ba9199f8.png)
xamppのPHPを最新バージョンに上げる

##はじめに
Laravelを試さなくてはいけなくなったので、Laravel開発環境を作らなければいけなくなりました。



WindowsPCなので開発環境はxamppで構築しようと考えていますが、以前PHP開発環境を作るためxamppをインストールしており、PHPのバージョンが古いため、PHPのバージョンを上げることでLaravelの開発環境構築の準備を行いました。

##PHPの最新バージョンをダウンロード
[ダウンロードはこちら](https://windows.php.net/download) から最新のPHPをダウンロードする。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/215529/069955a2-8e36-d4e5-aa49-340a3ea9efda.png)

##ダウンロードしたPHPファイルを配置

xamppフォルダの既存のPHPファイルを念のためバックアップで確保し、上記でダウンロードしたファイルと入れ替える。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/215529/8a05103d-2386-9f54-4f62-e4e5d45827c2.png)


##Apacheが起動しない・・・

これで起動すればPHPのバージョンが上がっているはず！
と思ったのですが、エラーが発生してApacheが起動しない・・・


###エラー1

phpファイル書き換えにより、Apacheが起動できなくなってしまった。。。
エラーメッセージは以下参照。

```
1:20:13  [Apache] 	Error: Apache shutdown unexpectedly.
1:20:13  [Apache] 	This may be due to a blocked port, missing dependencies, 
1:20:13  [Apache] 	improper privileges, a crash, or a shutdown by another method.
1:20:13  [Apache] 	Press the Logs button to view error logs and check
1:20:13  [Apache] 	the Windows Event Viewer for more clues
1:20:13  [Apache] 	If you need more help, copy and post this
1:20:13  [Apache] 	entire log window on the forums
```

###対策
PHPとApacheの設定を変更
xampp\php\php.ini-development ファイルのファイル名を[php.ini]に変更する。

xampp\apache\conf\extra\httpd-xampp.conf ファイル[php5]という記載を[php7]に変更する。
※僕の環境では元のphpバージョンが 5 なので[php5]という記載になっていたので、環境によっては 5 という数字は変わる可能性があります。


##Apacheが起動した

Apacheを起動したことを確認し、xamppシェルでphpのバージョンの確認を行った。

```
# php -v
PHP 7.2.6 (cli) (built: May 23 2018 20:51:04) ( ZTS MSVC15 (Visual C++ 2017) x86 )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
```

PHPのバージョンが 7 になっていることが確認できた。
VimでNginxの設定ファイルのシンタックスを効かせる

CentOS7の環境にNginxをインストールして、設定ファイルを書く機会が結構あり、ちょっとでも作業しやすくしたいと思ってやってみた。

# 手順
## 全体に設定する場合
1. フォルダを移動する

    ```
    # cd /usr/local/share/vim/vim81/syntax
    ```

2. シンタックスファイルをダウンロードする

    ```
    # curl -Lkvf https://www.vim.org/scripts/download_script.php?src_id=19394 -o nginx.vim
    ```
3. filetype.vim を修正する

    ```
    # cd ../
    # vi filetype.vim
    ```

    ```filetype.vim    
    au BufRead,BufNewFile /etc/nginx/*,/usr/local/nginx/conf/* 
        \  if &ft == ''
        \|   setfiletype nginx
        \| endif
    
    (以下の内容を追加)
    au BufRead,BufNewFile /etc/nginx/*,/usr/local/nginx/conf/* 
            \  if &ft == ''
            \|   setfiletype nginx
            \| endif
    ```

## 個人の環境でやる場合
1. あらかじめ必要なフォルダを作成する（すでにある場合は不要）

    ```
    $ mkdir -p ~/.vim/syntax/
    ```

2. `nginx.vim`ファイルを`~/.vim/syntax/`直下にダウンロードする

    ```
    $ cd ~/.vim/syntax/
    $ curl -Lkvf https://www.vim.org/scripts/download_script.php?src_id=19394 -o nginx.vim
    ```

3. `filetype.vim`ファイルを`~/.vim/`直下に作成する

    ```
    $ cd ~/.vim/
    $ vi filetype.vim
    ```
    
    ```filetype.vim
    au BufRead,BufNewFile /etc/nginx/*,/usr/local/nginx/conf/* 
            \  if &ft == ''
            \|   setfiletype nginx
            \| endif
    ```

これで出るはず

# 参考
- [nginx.vim : initial version](https://www.vim.org/scripts/script.php?script_id=1886)
Chart.jsで散布図を作る

# web上にグラフを表示させる

> 今回初めてhtml, css, jsをちゃんと書いた
> 超入門者向け

グラフ描画をweb上でやりたい。
フリーのライセンスで使えそうなものとして、Chart.jsを使ってみた。
今回描画するのは散布図。

### ファイル構成
[作業ファイル]
├── index.html
├── stylesheet.css
└── chartjs_exercise.js

---

## html

```index.html
<html>
    <head>
      <meta charset="utf-8">
      <!-- Read chart.js 2.x. -->
      <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.js"></script>
      <!-- Read a css file. -->
      <link rel="stylesheet" type="text/css" href="stylesheet.css">
      <title>chart.jsの練習</title>
    </head>
    <body>
      <div id="chartContainer" style="height:70%; width:70%">
        <!-- Show canvas here.-->
        <canvas id="canvas"> </canvas>
      </div>
      <!-- Read a javascript file here below canvas. -->
      <script src="chartjs_exercise.js"></script>
    </body>
</html>
```

---

## css

```stylesheet.css
#canvas {
  /*background: #000;*/
  /*background: #FFF;*/
  /*background: #C0C0C0;*/
  background: #EEEEEE;

  /*position: relative;*/
}

```

---

## javascript

```chartjs_exercise.js
window.chartColors = {
  red: "#FF0000",
  blue: "#00FF00"
};

var color = Chart.helpers.color;
var scatter_data = {
  datasets:[{
    label: "schatter dots",
    borderColor: window.chartColors.red,
    backgroundColor: color(window.chartColors.red).alpha(0.2).rgbString(),
    pointRadius: 10,

    data: [{
      x: 20.3,
      y: 13.43
    },{
      x: 17.9,
      y: 4.2
    },{
      x: 10.9,
      y: 15.2
    }]

  }]
};

var ctx = document.getElementById('canvas').getContext('2d');
window.myScatter = Chart.Scatter(ctx, {
  data: scatter_data,
  option:{
    title: {
      display: true,
      text: "Chart.js Scatter Chart"
    },
  }
});


```

---

### サーバを立てる

- 以下のコマンドでサーバを立て、[http://localhost:9000](http://localhost:9000)にアクセスする

```zsh
php -S localhost:9000
```

- もしくは、```index.html```をブラウザで直接読み込む

---

### 結果

![image.png](https://qiita-image-store.s3.amazonaws.com/0/133933/5d4cbe79-ad32-308f-48ed-f1600b60cfe4.png)


<p data-height="265" data-theme-id="0" data-slug-hash="OZKbBa" data-default-tab="js" data-user="berry_clione" data-embed-version="2" data-pen-title="OZKbBa" class="codepen">See the Pen <a href="https://codepen.io/berry_clione/pen/OZKbBa/">OZKbBa</a> by Berry Clione (<a href="https://codepen.io/berry_clione">@berry_clione</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
単調増加数 (Ruby / AIR-lang / Python)


|問題|http://nabetani.sakura.ne.jp/hena/orde24tancho/|
|:--|:--|
|Ruby / **AIR-lang** / Python|https://qiita.com/cielavenir/items/6de720c9a12813c5f469|
|Perl / C / Crystal / D / Go|https://qiita.com/cielavenir/items/51f260519b62a3330234|
|**Ruby-alpha**|https://qiita.com/cielavenir/items/9048c60498a9385b25c0|

## 前説

[第24回の追加答案で勢いづいた](https://qiita.com/cielavenir/items/d804f61412fb4f07ba06)ため今回はしょっぱなから「ツインテールdeエンジェルモード!!」での参戦にしようと思いましたが、やはり少し厳しかったようです。
Rubyからの移植になります。

## 方針

単調増加ということは、組み合わせだけ考えて、出力時にソートしたことにすれば良いです。
あとは[HKDnetさんの解説](http://hkdnet.hatenablog.com/entry/2018/05/26/235501)が近いです。

## 感想

シンプルなのに、立式するのが今回すごく大変でした…(オンサイトだったら **土** です)

ちなみに、全答案、テストケース

```
/*100*/ test('36,30000000000','134689bdefhijkrstuwyz');
```

を1秒以内で突破できます。これが突破できる答案が意外と少ないような…

## Ruby

```rb:tyama_henae24.rb
#!/usr/bin/env ruby
#http://nabetani.sakura.ne.jp/hena/orde24tancho/
#https://qiita.com/Nabetani/items/928d6a94d83c21ef64d7

def comb(n,k)
	r=1
	k.times{|i|
		r=r*(n-i)/(i+1)
	}
	r
end

STDOUT.sync=true
while gets
	b,n=$_.chomp.split(',').map{|e|e.to_i-1}
	topdigit=1
	loop{
		#b種類で作れるitopdigit桁の数
		x=comb(b,topdigit)
		break if b<topdigit || x>n
		n-=x
		topdigit+=1
	}
	if b<topdigit
		puts :-
		next
	end
	topdigit-=1
	curnumber=0
	topdigit.downto(0){|d|
		curnumber+=1
		loop{
			#b-curnumber種類の数で作れるd桁の数
			x=comb(b-curnumber,d)
			break if x>n
			n-=x
			curnumber+=1
		}
		print curnumber.to_s(b+1)
	}
	puts
end
```

## Twintail

```tt:tyama_henae24.tt
#!/usr/bin/env tt
#http://nabetani.sakura.ne.jp/hena/orde24tancho/
#https://qiita.com/Nabetani/items/928d6a94d83c21ef64d7

def comb(n,k){
	r=1
	for(i=0;i<k;i++){
		r=r*(n-i)/(i+1)
	}
	retn(r)
}

while(line=gets()){
	_=split(line,',')
	b=int(_[0])-1
	n=int(_[1])-1
	topdigit=1
	for(;1;){
		x=comb(b,topdigit)
		if(b<topdigit || x>n)break
		n-=x
		topdigit++
	}
	if(b<topdigit){
		print("-\n")
		continue
	}
	topdigit-=1
	curnumber=0
	for(d=topdigit;d>=0;d--){
		curnumber++
		for(;1;){
			x=comb(b-curnumber,d)
			if(x>n)break
			n-=x
			curnumber++
		}
		print("%c",curnumber+(curnumber<10 ? 48 : 87))
	}
	print("\n")
}
```

## Python

- いつもながら Py2/3両対応です

```py:tyama_henae24.py
#!/usr/bin/env python
#http://nabetani.sakura.ne.jp/hena/orde24tancho/
#https://qiita.com/Nabetani/items/928d6a94d83c21ef64d7
from __future__ import print_function,division
import string
o = string.digits+string.ascii_letters

def comb(n,k):
	r=1
	for i in range(k):
		r=r*(n-i)//(i+1)
	return r

if __name__=='__main__':
	import sys
	if sys.version_info[0]>=3: raw_input=input
	try:
		while True:
			b,n=[int(e)-1 for e in raw_input().rstrip().split(',')]
			topdigit=1
			while 1:
				x=comb(b,topdigit)
				if b<topdigit or x>n: break
				n-=x
				topdigit+=1
			if b<topdigit:
				print('-')
				sys.stdout.flush()
				continue
			topdigit-=1
			curnumber=0
			for d in range(topdigit,-1,-1):
				curnumber+=1
				while 1:
					x=comb(b-curnumber,d)
					if x>n: break
					n-=x
					curnumber+=1
				print(o[curnumber],end='')
			print()
			sys.stdout.flush()
	except EOFError:
		pass
```