OmniAICreator/Qiita-1.07M huggingface dataset:
（現在は解決しました）PHPの外部への接続でSSLのエラーが出てしまう@KUSANAGI PHP7.2

# 2018年7月4日に解消されました
[KUSANAGIモジュール更新情報](https://kusanagi.tokyo/archives/4748/)

https://users.kusanagi.tokyo/support/topic/kusanagi-php7-7-2-5-1でcurlなどからの外部httpsサイトへの接続でエラ/

# はじめに
KUSANAGIを使っています。

一ヶ月ほど前（2018年5月）ごろからKUSANAGIをアップデートすると一部でエラーがでてしまうようになりました。

[問題の経緯](https://qiita.com/yousan/items/4c98cbee20b2d89e91a3)

```
Warning: file_get_contents(): SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed in /mnt/example.com/test.php on line 4

Warning: file_get_contents(): Failed to enable crypto in /mnt/example.com/test.php on line 4

Warning: file_get_contents(https://example.com/test.jpg): failed to open stream: operation failed in /mnt/example/test.php on line 4
```

PHPで外部へ接続に行く際にエラーになってしまうようです。

# 解決方法
`/etc/php7.d/php.ini`に`openssl.cafile=/etc/ssl/certs/ca-bundle.crt`を追記すれば問題が回避できました。

```conf:/etc/php7.d/php.ini
(中略)
 ; be overridden on a per-stream basis via the "cafile" SSL stream context
 ; option.
openssl.cafile=/etc/ssl/certs/ca-bundle.crt

 ; If openssl.cafile is not specified or if the CA file is not found, the
 ; directory pointed to by openssl.capath is searched for a suitable
(中略)
```

# 問題の確認など

`phpinfo`を設置して、環境変数`openssl.cafile`が設定されているのか、居ないのかを確認します。

```php:/home/kusanagi/example.com/DocumentRoot/phpinfo.php
<?php phpinfo();
```

アップデート後は`openssl.cafile`の値が空欄になっていました。

上記の解決策を入れると`/etc/ssl/certs/ca-bundle.crt`が設定されています。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/47327/60062b9a-4817-a4e6-9415-bf98efaf717e.png)

自分の場合はPHP7-FPMを使っていたので`/etc/php7.d/php.ini`が設定ファイルでした。
環境変数を読み出す対象となるファイルは確認が必要です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/47327/421507fe-4dbe-55eb-eb64-70dd85b30d4b.png)

特にKUSANAGIの場合にはいろんなphp.ini系のファイルがあるので注意が必要でした。

# 解決できなかったけどヒントになった情報

エラーメッセージでググると情報がたくさん出てきます。

```php
$url = "https://xxxxxx";
$options['ssl']['verify_peer']=false;
$options['ssl']['verify_peer_name']=false;
$response = file_get_contents($url, false, stream_context_create($options));
```

> 開発環境で自己署名しているhttps環境において、file_get_contentsすると、
> Warning: file_get_contents(): SSL operation failed with code 1. OpenSSL Error messages:
error:14090086:SSL > routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed in xxxxx

> というエラーが表示されます。
> 証明書入れてくれよと思うのですが、導入できない時もあります。その場合は、optionを付与することで回避できます。

https://qiita.com/izanari/items/f4f96e11a2b01af72846

https://github.com/composer/composer/issues/2798

なのですが、cURLや`file_get_contents()`の情報がでてくるのですが、PHPの根本から解決する情報がありませんでした。

GuzzleなどのcURLをラッピングしてしまうライブラリの場合、中のオプション設定が結構大変そうだったため、解決策を探していました。

うまく解決出来てよかったです。
自分なりに成長するために必要だと思ったこと

## 主体的に行動をする
- 会社で自分が〇〇な点で不安、いらなくてね？と思ったとことりあえず稟議書出してみる
- 思いつかなかったら、自分から先輩に何かやれることはありませんかと聞いて、どんどん先輩から 
仕事を奪っていく
理想は、〇〇先輩を仕事をさせないこと（まぁ、それでもほんとに仕事をしてなかったら〇〇先輩はやばいけどw）

## どんどんアウトプットを出す
- めっちゃ質が悪くてもまずはアウトプットを出すことが大事
- アウトプット先は、FaceBookとかTwitterとか、それこそ自社ツール（Slack）とか
- 勉強会で知り合った人とかに話すとかでも良いからとりあえず出してみる
- アウトプットをしていくと、自分の中の情報が枯渇してくると思うので、どんどんインプットをすることも大事

## これらのことをすると何がいいのか？
- いろんな人からフィードバックが貰える
- フィードバックをもらうと、自分では気づけ無かったいろんな観点からの気付きがある

## 上記のことをやっていて、俺全然成長してなくね？って思ったことがあった...
- 実際には前の自分よりは確実に成長をしていて、それに自分が気づけていなかったんじゃないかと思う
だから、心が苦しくなったときは振り返ってみて前の自分よりは〇〇のとこができるようになったし、これもできるようになった。心を支えることも大事

## 振り返りを終えたらまたすぐに前を向くこと！
- 結局成長するときってのは、前を向いているとき（目標に向かっているとき）だけだと思うから
LumenのDatabaseMigrationsトレイトの初期化問題に対処する

# はじめに

LumenでDBを使用したテストを行う際にDBの初期化を行うために `Laravel\Lumen\Testing\DatabaseMigrations` というトレイトが提供されています。これは基本的には開始時に`migrate`を行い終了時に`migrate:rollback`することできれいにする、という動作をしますが、テストが異常終了するときちんとrollbackできずDBに中身が残ることがあって、その状態になると次回のテストが中身が残った状態で開始されてしてしまいテスト内容によっては失敗してしまいます。

これは[DatabaseMigrations trait doesn't revert DB inserts and deletes #775](https://github.com/laravel/lumen-framework/issues/775)で報告されている問題です。本家のLaravelでは開始時に`migrate`ではなく`migrate:fresh`を行うようになっていてこの問題は解決済みですが、Lumenには取り込まれていません。

# Laravelの修正を取り込む

Lumenはそのうち直るとしてもいつになるかわからないので、今できる対処として`Laravel\Lumen\Testing\DatabaseMigrations`が開始時に実行する`migrate`コマンドを`migrate:refresh`[^1]にした`MyDatabaseMigrations`トレイトを作ってそれを使うようにしようというのはすぐ思いつきます。

そこで最初以下のようなものを作ってみたのですがうまくいきませんでした。migrationが全く行われません。

```php
trait MyDatabaseMigrations
{

    public function runDatabaseMigrations()
    {
        $this->artisan('migrate:refresh');

        $this->beforeApplicationDestroyed(function () {
            $this->artisan('migrate:rollback');
        });
    }
}
```

呼び出し元を調べたところ、`runDatabaseMigrations`を呼ぶかどうかは`Laravel\Lumen\Testing\DatabaseMigrations`トレイトをuseしているかどうかで判定していました。(Laravel\Lumen\Testing\TestCaseクラスのsetUpTraitsメソッド)

```php
    protected function setUpTraits()
    {
        $uses = array_flip(class_uses_recursive(get_class($this)));

        if (isset($uses[DatabaseMigrations::class])) {
            $this->runDatabaseMigrations();
        }

        ...
    }
```

従って正解はさらに`Laravel\Lumen\Testing\DatabaseMigrations`をuseするようにして以下のようになります。

```php
trait MyDatabaseMigrations
{
    use \Laravel\Lumen\Testing\DatabaseMigrations;

    public function runDatabaseMigrations()
    {
        $this->artisan('migrate:refresh');

        $this->beforeApplicationDestroyed(function () {
            $this->artisan('migrate:rollback');
        });
    }
}
```

`runDatabaseMigrations`しかないトレイトをuseしてその唯一のメソッドがいきなり上書きされてしまうわけですが、そのトレイトをuseしたという事実が重要です。

[^1]: `migrate:fresh`ではなく`migrate:refresh`になっているのは、Lumenにはいまのところ`migrate:fresh`コマンドがないからです

さらによくよく見ると、`beforeApplicationDestroyed`で行っているロールバックも開始時に`migrate:refresh`を行うという前提なら無駄な気がします。むしろテスト後にDBの中身をちょっと見られて便利でもあるので自分は削ってしまいました。

最終的には以下のようなものを使用しています。

```php
trait MyDatabaseMigrations
{
    use \Laravel\Lumen\Testing\DatabaseMigrations;

    public function runDatabaseMigrations()
    {
        $this->artisan('migrate:refresh');
    }
}
```
Linux　viエディタの切り取り・コピー・貼り付け・検索・設定コマンドと、コマンドの繰り返し・取消し

viエディタのコマンドについての覚書です。

###切り取り・コピー・貼り付けコマンド

| コマンド|意味|
|:------|:----|
|dd   |カーソルのある行を切り取る|
|p  |カーソルがある行の１行下に貼り付ける|
|yy| カーソルのある行をコピーする|
|x　|カーソルの右側１文字を切り取る|
|X　|カーソルの左側１文字を切り取る|
|/|文字列の検索|
|:set|設定の変更|

###コマンドの繰り返し・取り消し

★繰り返しをしたいときには、コマンドの直前に繰り返したい数を入力します

例：）　下記の文章の１行目で　２dd と入力する

1.first_row　　◀ここで2ddと入力
2.second_row
3.thid_row

⇓　結果

3.thid_row

※切り取りが２回繰り返され、1行目と２行目が切り取られます

★操作の取り消しは「u」コマンドを、取り消しの取り消しは　Ctrl + R 　キーで実行します
Firebase の匿名ユーザーのアカウントを無効にする方法

## 概要

　違反ユーザーのアカウント停止を行おうとした時にちょっと困ったので書いておきます。内容は、Firebase の Authentication を使って匿名ログインをしているユーザーのアカウントを無効にする方法です。

　てっきりコンソールの Authentication から「アカウントを無効にする」で簡単にできるのだろうなと思っていたのですが、匿名ユーザーに対しては出来ませんでした。（メールアドレス認証の場合、認証時にエラーが返っていたと思います）これは、Auth クラスの  [signInAnonymously((completion:))](https://firebase.google.com/docs/reference/swift/firebaseauth/api/reference/Classes/Auth?hl=ja#/c:objc\(cs\)FIRAuth\(im\)signInAnonymouslyWithCompletion:) メソッドが新たに新規匿名ユーザーを作成してサインインしてしまうからです。つまり、コンソールから「アカウントを無効にする」を行っても、対象のユーザーは新しい匿名ユーザーとしてアプリを引き続き利用することができてしまいます。

## 対応方法

　対応方法は簡単です。DB に無効アカウント用のコレクション(bannedUser)を用意して、そこに対象ユーザーのIDのドキュメントを作成しておきます。次に、DBルールでリクエストしたユーザーがコレクションに含まれているかどうかの条件を追加します。下記のようになります。

```swift

service cloud.firestore {
  match /databases/{database}/documents {
  
    function isAuthenticated() {
      return request.auth != null;
    }

    function isBannedUser(userID) {
      return exists(/databases/$(database)/documents/bannedUser/$(userID));
    }
    
    match /comment/{commentID} {
        allow read: if isAuthenticated();
        allow write: if isAuthenticated() &&
                        !isBannedUser(request.resource.data.userID);
    }
    ...
}
```

　上記の例では、対象ユーザーからのコメントの書き込みを防ぐことができます。`rules.firestore` の [exists](https://firebase.google.com/docs/reference/rules/rules.firestore?hl=ja#.exists) メソッドを利用するところがポイントです。

## まとめ

　この方法以外にも例えば `User` オブジェクトに `isActive` のようなプロパティを持たせてアプリ側で制御する方法が考えられますが、その場合、考慮しなくてはいけないことが増え、アプリの実装が複雑になってしまうのが難点です。

　最近 [Rules Simulator](https://firebase.googleblog.com/2018/06/announcing-firestore-security-rules.html) のアナウンスがありましたが、これを使えばわざわざデプロイしなくても動作確認ができます。コンソールの機能が充実していくとより使いやすくなって良いですね。
個人学習メモ#1  ターミナル　学んだコマンド

pwd
作業しているところの確認

cd
ディレクトリ（フォルダ）を移動する

ls
今居るところにどんなファイルがあるのかを表示
(ls -aは隠しファイルの表示)

mkdir
ディレクトリ作成
mkdir images

cp
コピー

mv
ディレクトリを移動させる

mv 移動させたいファイル 移動先

名前変更の場合
mv top.jpg main.jpg

rm
削除する jpgなどのファイルを完全に削除する

history
前に使ったコードを表示

history -ｃ 
historyを削除
【Android】Unexpected view type nested under text node というエラーの理由

# はじめに
React Nativeでアプリ開発中に、ずっとiOSのシミュレータで動作確認をしていて、
Androidで動かそうとしたら

`Unexpected view type nested under text node: class com.facebook.react.uimanager.LayoutShadowNode`

というエラーに遭遇しました。

# エラーの原因
このエラーは、`<Text></Text>` タグの中に `<View>` や `<TouchableOpacity>` などが入っていると起こるようです。
（`<Text`>タグの入れ子はエラーになりません）

今回のエラーの該当箇所のコードは

```
<Text>
  <TouchableOpacity>
    …
  </TouchableOpacity>
</Text>
```

となっていました。

# おわりに
このエラーはAndroidでしか出ず、iOSでは正常に表示されてしまいます。

iOSのシミュレータで確認しつつ開発→ある程度出来上がったらAndroidで確認、という開発方法を取っていたので、Androidで起動した際にエラーになって、しかもエラー該当箇所が表示されないため場所を特定するのがとても大変でした…。

これからReact Nativeで開発する際は、 `<Text>` タグの中には `<Text>` 以外入れないように気をつけようと思います。
有線LANのメリットデメリット

#はじめに
今回は有線LANのメリットデメリットについて調べてみたのでまとめてみました。

#有線LANとは
パソコンでインターネットをするには、回線契約時に設置業者が設置した機器（回線終端装置（ONU）または加入者網終端装置（CTU）など）と、有線ルーターとパソコンをLANケーブルでつなぐ必要があります。このLANケーブルを使った接続方法が「有線LAN」です

#有線LANメリット
1)ルーターや接続機器の性能にもよりますが、一般的に無線LANよりも高速で通信できるのが特徴です。データ通信量の多い動画鑑賞なども、ストレスなく楽しめる。
2)無線LANのように電波干渉を受けたり、距離による大幅な速度低下が起こったりすることもありません。
一度設置できれば、それ以降は安定して高速インターネットが楽しめます。

#有線LANデメリット
有線LANのデメリットは“配線のわずらわしさ”にあります。複数の端末に接続する場合、それぞれにLANケーブルを用意しなくてはなりません。
また、部屋が複数ある場合は距離的な問題もあります。長いLANケーブルを壁などにはわせるのは大変ですし、端末が増えるごとにその作業を行わなくてはならないのは大きな手間です。また、ルーター付近にLANケーブルが集まるため、配線がグチャグチャになりやすい点もデメリット

#最後に
有線LANはそれぞれにLANケーブルを接続しないと使えないなどのデメリットがありますが、無線LANよりも高速に通信できストレスなくゲームができ、動画も見れるので素晴らしいと思います。
Hyperledger Composer をたじたじと使ってみた(環境構築編)

# is 何
[Hyperledger fabric](https://www.hyperledger.org/projects/fabric) をいい感じに操作するためのライブラリとRESTサーバがセットになったやつだよ。
簡単な定義体でDBからいい感じのクエリから定義してくれるからビジネスロジックの作成に専念できるよ。

私の英語の読解力がないのかなんかどこ見ればいいのかすごい迷ったから覚書

# 環境設定

https://hyperledger.github.io/composer/latest/installing/development-tools.html

## Installing components

### Step 1: Install the CLI tools

```bash
npm install -g composer-cli
npm install -g composer-rest-server
npm install -g generator-hyperledger-composer
npm install -g yo
```

### Step 2: Install Playground

```bash
npm install -g composer-playground
```

### Step 3: Set up your IDE

VSCodeを入れて拡張機能 `Hyperledger Compose` をインストール

### Step 4: Install Hyperledger Fabric

```bash
mkdir ~/fabric-dev-servers && cd ~/fabric-dev-servers

curl -O https://raw.githubusercontent.com/hyperledger/composer-tools/master/packages/fabric-dev-servers/fabric-dev-servers.tar.gz
tar -xvf fabric-dev-servers.tar.gz
./downloadFabric.sh
```

`downloadFabric.sh` はHyperledger Fabric を入れてくれる便利なやつ


## Controlling your dev environment

### Starting and stopping Hyperledger Fabric

`startFabric.sh` を叩けばDockerコンテナが走るよ。止める時は `~/fabric-dev-servers/stopFabric.sh` だよ。

`createPeerAdminCard` は管理者用の鍵とかを作るやつだよ。多分。

```bash
cd ~/fabric-dev-servers
./startFabric.sh
./createPeerAdminCard.sh
```

開発を進める時は `~/fabric-dev-servers/stopFabric.sh` と `~/fabric-dev-servers/teardownFabric.sh` を使ってコンテナを止めてね。
コンテナを止めたらまた AdminCard を作らなきゃだめだよ。

開発用だからビジネスロジックの更新の度にいちいち止めたり上げたりしなきゃだめなんだよ。めんどくさいと思ったら Kubernetes 経由でやったりIBMクラウドで動したりするといいよ。

### Start the web app ("Playground")

```bash
composer-playground
```

ブラウザが上がってページを表示してくれるよ。
PeerAdmin@hlfv1 のカードが表示されてなかったら何かが間違っているよ
sayコマンドで定期的に時間を知らせる

# Macのバージョンの確認
```
$ sw_vers
ProductName:	Mac OS X
ProductVersion:	10.13.5
BuildVersion:	17F77
```

# 日本語を話せる人のリスト
```
$ say -v ? | grep ja_JP
Kyoko               ja_JP    # こんにちは、私の名前はKyokoです。日本語の音声をお届けします。
Otoya               ja_JP    # こんにちは、私の名前はOtoyaです。日本語の音声をお届けします。

```
# Kyokoの声
```
$ say -v Kyoko $(date +"%H時%M分")

```
# Otoyaの声
```
$ say -v Otoya $(date +"%H時%M分")

```
# バッチファイルの内容
```
$ cat $HOME/say.sh
#!/bin/bash

/usr/bin/say -v Kyoko $(/bin/date +"%H時%M分")

$ chmod 755 $HOME/say.sh
```

# crontabで一時間毎にコマンドの設定
```
$ crontab -e
```

## crontabの内容
```
$ crontab -l
0 */1 * * * /bin/sh $HOME/say.sh
```
【勉強ノート】ウェブサイトからデータ収集のための 環境構築

## 概要
ウェブ上から特定のデータを集めて分析する方法に興味があり、勉強をはじめました。
今後、数回に渡ってWeb Scrapingの勉強記録を書いていきたいと思っています。

## 注意事項
この投稿は単純な勉強の記録です。私はWeb Scrapingに経験がないですから、間違ったことをやる可能性も高いと思います。その時はコメントで教えていただけると幸いです。

## 今後の流れ
1. 環境構築
2. Web Scrapingの基礎
3. Web Scrapingのプロトタイプ作成
4. 定期的にScraping
5. クラウド上にサーバ構築
6. 本稼働

## 環境構築
今回はDockerを活用し開発を行います。Dockerを活用することで今後、クラウド上のdeployが楽になると考えています。ちなみに、Dockerも初心者なので何か間違ったところがありましたら教えてください。

#### Dockerfile
今回作ったDockerfileは下記の通りです。

```Dockerfile
FROM ubuntu:18.04 

LABEL maintainer="Suckgeun Lee <leesuckgeun@gmail.com>"

# install basic packages 
RUN apt-get update \
    && \
    apt-get upgrade -y \
    && \ 
    apt-get install -y \
        python3.7 \
        python3-pip \
        git \
        unzip \
        vim \
        software-properties-common \
        locales \
        locales-all 

# install basic python packages
RUN pip3 install \
        h5py \
        ipykernel \
        jupyter \
        matplotlib \
        numpy \
        pandas \
        scipy \
        sklearn
        
# install Scrapy related packages
RUN pip3 install \
        lxml \
        parsel \
        w3lib \
        twisted \
        cryptography \
        pyOpenSSL \
        Scrapy \
    && \
    python3 -m ipykernel.kernelspec

ENV LC_ALL en_US.UTF-8
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US.UTF-8

WORKDIR /app

# Ipython
EXPOSE 8890
```

ご覧の通り、Scrapyをインストールしています。Web Scrapingを行うために私はScrapyを使用します。


#### docker image の作成

このDockerfileで docker imageを作成します。

```
leesuckgeun$ docker build -t scrapy_image:v0 . 
```


#### docker container の作成
作ったイメージでcontainerを作成します。

```
leesuckgeun$ docker run -it --name scrapy_practice scrapy_image:v0 /bin/bash
```

docker imageとcontainerを作る詳細は省略します。上記のコマンドで一応作成できます。

#### 動作確認
docker containerにて scrapy と入力すると

```
docker$ scrapy
Scrapy 1.5.0 - no active project

Usage:
  scrapy <command> [options] [args]

Available commands:
  bench         Run quick benchmark test
  fetch         Fetch a URL using the Scrapy downloader
  genspider     Generate new spider using pre-defined templates
  runspider     Run a self-contained spider (without creating a project)
  settings      Get settings values
  shell         Interactive scraping console
  startproject  Create new project
  version       Print Scrapy version
  view          Open URL in browser, as seen by Scrapy

  [ more ]      More commands available when run from project directory

Use "scrapy <command> -h" to see more info about a command

```

Scrapyがちゃんと起動していることが分かります。


## 最後に
これで環境構築が終わりました。
pythonでWeb Scrapingをするには色々あるらしいですが、一番有名そうだったScrapyを選ぶことにしました。今回作成したDockerfileで勉強を続けていきますが、足りないものは徐々に追加していきたいと思います。

次回はScrapyの基礎を勉強します
動画サイトにおけるWebスクレイピング

##背景
近年，様々な動画サイトが誕生している．
各サイト工夫を凝らしているが，その工夫が各ユーザに対してフィットしているとは言い難い．

そこで，動画サイトにある動画情報だけをWebスクレイピングで収集し，
収集したデータからユーザが使いやすいようにデータを加工できれば有用でないかと考えた．

##目的
動画サイトにある動画情報を収集するWebスクレイピングプログラムを作成する

##構築
・Python 3.0
・selenium webdriver
・Microsoft Edge

##必要な事
1.特定のサイトを把握
2.そのサイトの構造を把握
3.何を出力したいか（動画のタイトル，id，タグなど）

##実践
以下の点に注意
1.csvファイルに出力していますが，出力先などは個人のお好きなように
2.webdriverはEdge,Firefoxなどに対応
3.このプログラムでは動画のid，タイトル，現在の日付をファイルに書き込んでいます
<b>各サイトでHTML/CSSの構造は異なるのでしっかりと個々のサイトに対応するようにしましょう！！</b>

```python:
from selenium import webdriver
import numpy as np
import pandas as pd
import datetime
import sys
sys.setrecursionlimit(10000)
today=datetime.date.today()

#csvファイル（既存データ）の読み込み
df=pd.read_csv("既存データ先")
#df=pd.DataFrame(index=[],columns=["id","name","date"])

#ブラウザ開く(most-popular today)
driver=webdriver.Edge('webdriverのインストール先')
for i in np.arange(1,11):
    if i==1:
        driver.get("対象のスクレイピング先")
    else:
        a="対象のスクレイピング先/%s/" % str(i)
        driver.switch_to.default_content()  #最上位に戻す
        driver.get(a)
#    time.sleep(5)

    #動画のリスト取得
    l=driver.find_element_by_class_name("wrapper")
    l=l.find_element_by_class_name("main")
    l=l.find_element_by_class_name("row row3")
    l=l.find_element_by_class_name("content")
    l=l.find_element_by_class_name("thumbs-items")

    #そのページの動画一覧
    for i in l.find_elements_by_class_name("thumb"):
        a=i.find_element_by_tag_name("a")
        index=a.get_attribute("href").find('/',27)
        #id,nameをDataFrameに追加
        df=df.append(pd.DataFrame([[int(a.get_attribute("href")[27:index]),a.get_attribute("href")[index+1:-1],today.isoformat()]],columns=["id","name","date"]),ignore_index=True)
        #df.append(df2,ignore_index=True)
  
#重複データの削除（前残し）
df=df.drop_duplicates(["id"])
#dataframeの出力
df.to_csv("csvファイル出力先",index=False)
        
driver.close()
driver.quit()

```

##終わりに
上記のプログラムでは動画のidとタイトルを出力していましたが，プログラムを書き換えればタグや再生回数なども抽出できます．
もし，ある動画サイトを使用していて使いにくいと感じたら，スクレイピングを行い自分好みにカスタマイズする必要があるでしょう．
今後は蓄積したデータからフィルタ処理を行っていきたいと思います．
それでは！！

以下，Githubで公開しているURLです．
https://github.com/minna30waiwai/web-scraing-movie-site
2018-06-28 SmartGit > v18.1から64-bit化 | link > 32-bit対応方法

```
Windows 7 Pro (32bit)
SmartGit 17.1.6 #11221, installed: #11182
```

SmartGit起動時、v18.1.1のUpgradeダイアログが表示される。
Upgradeと選択してもUpgradeされない。

理由としては、v18.1から64-bit化しているためのようだ。

32-bitの場合は下記のリンク先の方法で対応できると教えていただいた。
https://www.syntevo.com/blog/?p=4558

SmartGitで使うソフト側で32-bitサポートがいつまで続くか分からないので、今後の使用については要検討。

### サポートの停止
(2019-01-31)

- [SmartGit > 32bit OS > v18.1.5が最終サポート?](https://qiita.com/7of9/items/1fa5001f3bbee5572c64)

に書いた通り、SmartGitの32bit対応は終了したようだ。
bower installをしたら502が返ってきて失敗する時の対処法

## 状況
2018年6月26日の夕方頃、bowerを使っているプロジェクトをcloneしてきてbower installを実行したらエラーが起きました。

```
$ bower install
bower radar-chart-d3#1.2.1     EINVRES Request to https://bower.herokuapp.com/packages/radar-chart-d3 failed with 502
```

パッケージが置いてあるURLから502が返ってきています。

## 対処法
対処法を先に書いてしまいますが、bowerを最新バージョンに上げたところ、bower installができるようになりました。

OSや環境によっては、バージョンを上げる時にsudoを付けたり、バージョンが上がったことを反映させるために一度シェルからexitする必要があるかもしれません。

```
# アップデート前のバージョンを確認
$ bower -v
1.8.0

# bowerのバージョンを最新にする
# パーミッションエラーが出る時はsudoを付ける
$ npm i -g bower

# 最新バージョンに上がっているか確認
# 反映されていなかったらシェルからexitして再度ログインする
$ bower -v
1.8.4
```

## 解決法を見つけた経緯
まずエラーメッセージに表示されているURLにブラウザで遷移してみました。

https://bower.herokuapp.com/packages/radar-chart-d3

以下のようなメッセージがブラウザに表示されています。

> This Bower version is deprecated. Please update it: npm install -g bower. The new registry address is https://registry.bower.io

「このbowerのバージョンは非推奨なのでbowerをアップデートしてください。新しいレジストリのURLは変わっています。」というような内容です。

`bower "EINVRES"` でGoogle検索したところ、同じ状況で困っているという質問が海外版のStack Overflowに投稿されていました。

https://stackoverflow.com/questions/51020317/einvres-request-to-https-bower-herokuapp-com-packages-failed-with-502

2018年6月28日時点で回答は2つあります。

- 1つ目

 .bowerrcでregistryの指定をする

```
{
  "registry": "https://registry.bower.io"
}
```

- 2つ目

bowerを最新バージョンにする

1つ目の回答の方がvote upは多いですが、そもそもブラウザでのメッセージでは「bowerをアップデートしてください」と書いてあります。

なので、とりあえずbowerをアップデートしてみたところ、僕の環境では問題が解決ができました。
GAS スクリプトで再承認が必要だった話

今日、下の記事のスクリプトで、エラーが発生した。
　https://qiita.com/hatakkkk/items/9e593e3e6a5d50761f66
"その操作を実行するには承認が必要です。"

対応として、再度、スクリプトを実行して、"承認しますか？" に"はい" したら直りました。

特に触っていなかったので、操作ミスの線はないので、考えられる原因は以下か
　原因案１．承認が継続する期間がある（例えば1ヶ月だけ有効など）
　原因案２．仕様変更

まずは、
原因案１．からググってみる
下のサイトを参考にさせてもらい、どうも1ヶ月で切れるっということは無さそう。
https://qiita.com/soichiro_nishizawa/items/f6ce9290440a33d18d7c
https://qiita.com/zk_phi/items/7220b67afa84c58cc160

原因案２．からググってみる
も、、、特に発見はなし。。。

下のコミュニティーで問合せてみたので、いい回答あれば共有します。
https://plus.google.com/communities/102471985047225101769

"I don’t know if this is the issue or not, but I have heard of issues with  being signed on to multiple accounts throwing errors. "

同じような事が何名かで起きてました。
一番可能が高いのは、
"マルチアカウントで運用しているから"　かも。
私は、マルチアカウントで切り替えながら使っている。
切り替えてると、一定期間でスクリプトの認証が切れてしまうのかもしれない。

結論として、
私は、継続してスクリプトを利用する、シングルアカウントで承認を取りながら。
【Vue.js】入れ子のリストをドラッグアンドドロップで各階層の中だけで並び替えする

こんにちは。Vue.js勉強中の者です。
  
ドラッグアンドドロップでリストを並び替えて色々したいって時あるじゃないですか。
しかも入れ子のリストで、子が親を飛び越えたりせずに同じ階層同士でしか並び替えしたくないって時もあるじゃないですか。あるか？  
jQueryUIでも頑張れば出来そうですが、Vue.js導入してVue.Draggableを使えばアホ簡単に出来たのでその備忘録です。
  
# Vue.Draggable
ドラッグアンドドロップで並び替えすることをうまいことやってくれるプラグインです。  
導入とか詳しい使い方については他の方たちが解説してくださっているので、そちらをご参照ください。  
  
- [Vue.Draggableを使ってサクッとTrelloっぽいものを作る](https://qiita.com/kimuray/items/d728fa1635aeacad359f)  
- [【Vue.js】Vue.Draggableを使ってドラッグ＆ドロップで並べ替えをする表をつくる方法メモ](http://sagatto.com/20171031_vuejs_sortable)
  
  
# 使用例
では実際に使ってみます。今回並び替える入れ子のリストは以下になります。

```javascript:test.js
let animals = [
    { emoji: '🐄', name: 'うし' },
    { emoji: '🐕', name: 'いぬ' },
    { emoji: '🐈', name: 'ねこ' },
    { emoji: '🐓', name: 'にわとり', child:[
        { emoji: '🐤', name: 'ひよこ兄' },
        { emoji: '🐤', name: 'ひよこ弟' },
    ]},
    { emoji:'🐖', name: 'ぶた' }
];
```

かわいいね  
  
上記リストをHTMLに描画します。

```javascript:test.js
new Vue({
    el:'#app',
    data: ()=>{
        return {
            animals: animals
        }
    }
});
```

```html:index.html
<div id="app">
    <ul>
        <li v-for="(animal, i) in animals">
            <span>{{ i }} : {{ animal.emoji }} {{ animal.name }}</span>
            <ul>
                <li v-for="(child, j) in animal.child">
                    <span>{{ i }} - {{ j }} : {{ child.emoji }} {{ child.name }}</span>
                </li>
            </ul>
        </li>
    </ul>
</div>
```
  
こうなります  
  ![animals.png](https://qiita-image-store.s3.amazonaws.com/0/267011/6fa1ae3e-a110-6be0-fac1-8390d0b6e88f.png)

  
Vue.Draggableで並び替えできるようにします。

```html:index.html
<div id="app">
    <draggable v-model="animals" :element="'ul'">
        <li v-for="(animal, i) in animals">
            <span>{{ i }} : {{ animal.emoji }} {{ animal.name }}</span>
            <ul>
                <draggable v-model="animal.child">
                    <li v-for="(child, j) in animal.child">
                        <span>{{ i }} - {{ j }} : {{ child.emoji }} {{ child.name }}</span>
                    </li>
                </draggable>
            </ul>
        </li>
    </draggable>
</div>
```
  
最上位のul要素をdraggableに置き換えています。  
draggableは何も指定しないとレンダリングの際にdivになってしまうので、`:element="'ul'"`でul要素になってくれるよう指定しています。  
  
  
入れ子になっている部分のリストはli要素をdraggableで囲むようにします。  
このdraggableを`:element="'ul'"`で指定して`<li><span/><ul></ul></li>`ってやろうとするとエラーになります…これよく分からないので知っている方いたら教えてください…  
  
v-modelを使うことも出来るので、HTML側からドラッグアンドドロップで並び替えた結果を、js側のdataで管理しているanimalsリストに反映させています。
![animals_sort.gif](https://qiita-image-store.s3.amazonaws.com/0/267011/db11c911-a724-a5c8-b405-fb90fb646877.gif)

  
indexの値が変わっているのが確認できますね。
また、ちゃんとひよこがにわとりを超えないようになっています。
  
  
# おわり
例では動物たちを並び替えただけですが、TODOリストに応用してタスクとサブタスクで分けて、優先度に応じて並び替えて、endイベントでlocalStorageに保存…みたいな使い方もできると思います。Vue.jsの入門記事で作ってそのままのTODOリストをちょっと実用的にできるかもしれません。
【React Native】lottie-react-nativeでframework No such file


## Build Error!!!

```
error: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator11.3.sdk/System/Library/Frameworks/Lottie.framework: No such file or directory
```
## 解決策
xcodeの**Embed FrameWorks にLottieを追加する**

`General > Embedded Binaries > add Lottie.framework`


![image.png](https://qiita-image-store.s3.amazonaws.com/0/103475/497ced69-f38e-ec80-ebcf-4ab392c200b3.png)

https://github.com/airbnb/lottie-react-native/issues/177
【ご指摘求む】Dockerfileの環境変数がDocker Composeより優先された

# 背景

開発環境用のDockerコンテナを作ろうとしたら、
内部でoss.sonatype.orgからのパッケージダウンロードに3時間以上かかってるので、
オレオレDockerfileを作ったら、それと一緒に使っていたdocker-compose.ymlの環境変数が
Dockerイメージに適用されなかったのでメモする。


# 実行サンプル

```Dockerfile
FROM ubuntu:latest
ENV HOGEFUGA_VALUE=hoge
RUN "lgtm-script.sh install"
CMD ["lgtm-script.sh", "run"]

# 補足
#
# HOGEFUGA_VALUE は lgtm-script.sh の中の
# 下記のyml内で展開される。
#
# lgtm-script.sh の installで、
# erbファイルを元にymlを生成し、
# 生成されたymlを元に
# oss.sonatype.orgからパッケージを取得する。
#
# run でcatalina.shを叩く（tomcatが起動）
```

``` docker-compose.yml
lgtm:
  image: lgtm:dev-ours
  environment:
    - HOGEFUGA_VALUE=FUGA
```

そしてホスト環境で以下を実行。

``` shell-session
# docker build -t lgtm:dev-ours /path/of/dockerfile/
# docker-compose up -d
# docker-compose exec lgtm /bin/bash

$ printenv
HOGEFUGA_VALUE=hoge
```

ゑ……、docker-compose.ymlの方が適用されると思ったのだが……。


# 解決方法

Dockerfile内で環境変数を指定してるところを省いてDockerイメージの再ビルド後、
`docker-compose up -d` を実行後、期待通り `HOGEFUGA_VALUE` が `FUGA` になった。

```diff
FROM ubuntu:latest
- ENV HOGEFUGA_VALUE=hoge
RUN "lgtm-script.sh install"
CMD ["lgtm-script.sh", "run"]
```

# 考察

とはいえ、自分が見てきた事例ではDocker Composeの方が優先される様な気がするので、
ご指摘等ありましたら、よろしくお願いいたします。

# 参考資料

* [Docker-Compose の変数定義について - Qiita](https://qiita.com/kimullaa/items/f556431b8103e686f356#%E5%A4%89%E6%95%B0%E3%81%AE%E5%84%AA%E5%85%88%E9%A0%86%E4%BD%8D)
* [Environment variables in Compose | Docker Documentation](https://docs.docker.com/compose/environment-variables/)
CocoaPodsを導入してみた

iOS開発で使うOSSライブラリをcocoapods経由でインストールするようにしとけばライブラリの管理が楽です。  というわけでCocoaPodsを導入してみた。

## インストール環境
- macOS High Sierra 10.13.5
- Xcode Version 9.4.1


## CocoaPodsを導入する

ターミナルで実行する  
  
インストール

```
$ sudo gem install -n /usr/local/bin cocoapods
```

バージョン確認

```
$ pod --version
1.5.3
```

セットアップ。ちょっと時間かかる

```
$ pod setup
Setting up CocoaPods master repo
```

## CocoaPods経由でライブラリを導入してXodeで使ってみる
ライブラリを使用したいXcodeプロジェクトに移動(プロジェクト名:Sample)

```
$ cd Sample
```

Podfileを作成する

```
$ pod init
```

作成直後のPodfileの中身はこんな感じ

```
$ cat Podfile
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'Sample' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for Sample

end
```

Podfileを編集して、試しにAdMob使えるようにしてみる

```bash 
$ vi podfile
```

編集後のPodfile

```
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '9.0'

target 'Sample' do
  use_frameworks!
  pod 'Google-Mobile-Ads-SDK', '~> 7.0'
end
```

ライブラリ（今回の場合はGoogle-Mobile-Ads-SDK）をインストールする

```bash
$ pod install
```
Sample.xcworkspaceが作成される。

```
$ ls
Podfile			Pods			Sample.xcodeproj
Podfile.lock		Sample			Sample.xcworkspace
```

今後のXcodeでの開発はSample.xcodeprojではなく、Sample.xcworkspaceで行う

## ライブラリが使えるか確認してみる

上記作業まででライブラリのインストールは終わっているので、Sample.xcworkspaceを開いてimport GoogleMobileAdsすればビルドが通る。

## 備考

ライブラリを追加・削除する場合はPodfileを編集して pod update

```
$ vi Podfile
$ pod update
```
単眼画像からStixelを試算

![vlcsnap-2018-04-25-14h24m16s177.png](https://qiita-image-store.s3.amazonaws.com/0/266436/8c536e21-eed0-739d-c1c8-cde5f00986a5.png)

*交通シーンで物体を覆う棒状のようなものがstexilと呼ばれ、中レベルの画像表現として障害物検出などに使われています。Stexilを計算するときに、通常ステレオカメラで視差画像 (Disparity)を求める必要があります。本記事はDeepLearningを用いて、単眼カメラ画像よりStexilを求める方法を紹介します。*本記事は[こちらの記事](https://www.cyberailab.com/home/stixel-monocular)を和訳したものです。

# Stixel Overview
画像の構成について考えてみます。例えば、最も小さい単位が画素値 (pixel) です。画素値は画像において一つの微小領域における明るさのことです。このほか、2次元画像において、ある物体の位置情報の集まりを一つの単位として考える場合は、物体領域 (region)があります。例えば、下記の画像の青い領域がその一つです。画素値に比べると、物体領域はよりハイレベルな情報を表す。具体的には、物体の2次元形状や視覚的な情報：carなどがあります。しかし、このようなハイレベルな情報を求めるには計算量が大変多くて、リアルタイムアプリではボトルネックとなることがあります。

Stixelはpixelとregionの間に位置し、画像領域に固定幅の棒状に区切ってその領域を障害物とする手法です。Stixelの色は障害物からカメラまでの距離を表します。

![stexil.png](https://qiita-image-store.s3.amazonaws.com/0/266436/48d5c1b8-a7cc-666a-6871-0978c9ae5141.png)
Pixels, Stixels and Regions


# Stixel計算-ステレオ画像

Stixelを求めるときに、まずステレオ画像から視差画像 (Disparity Map)を計算します。次にDisparity Mapを等間隔の列に区切り、各列に対して高さが異なるSegmentまで分割し、Sky, Object, Groundいずれかに分類します。ここで各Segmentに対して、
Data項：Segmentがあるクラスに属しているとき期待される視差値と実際の視差値の誤差
Prior項：Segmentの割り当て方に関する先験情報。入力とは無関係
からなるコスト関数を定義し、これらの和が最小となる分割を求めます。
![stexil_flow1.png](https://qiita-image-store.s3.amazonaws.com/0/266436/9fc7b478-a1f9-9c8e-b2f4-37fe76781fd0.png)
Stixel Computation Process Flow: The original way

# Stixel計算-単眼画像
上記の処理の流れからわかる通り、Stixelの計算はあくまでもDisparity Mapの分類問題に過ぎない。その前提として、２枚のステレオ画像は欠かせないことに気づいたと思いますが、問題は、全てのシステムにステレオカメラを設置できるわけではありません。また単眼画像しかない古い走行データセットなどは、Stixel画像を取得したいという需要があるかもしれません。そこでDeepLearningの出番です。Depth Estimation Networkというモデルを使用して、単眼画像からDisparity Mapを求めることができるのです。

Depth Estimation Network modelとは、pixel-wise単眼画像から視差を推定するモデルで、学習データセット以外の画像でも効果的です。 (Related work: [Paper](http://visual.cs.ucl.ac.uk/pubs/monoDepth/) & [Implementation](https://github.com/mrharicot/monodepth)。
Disparity関連のモジュールをDepth Estimation Networkに変えると単眼画像でもDisparity Mapを作ることができるようになります。その流れは下記の通りです。
![stexil_flow2.png](https://qiita-image-store.s3.amazonaws.com/0/266436/60321de1-d6ba-b8ff-78af-9a96a06033eb.png)
Stixel Computation Process Flow: Our proposal

# Demo
Stixelの２次元の座標は物体の位置を、Stixelの色は物体とカメラとの距離を表しています。右の鳥瞰図では、色がStixelの高さで、位置がz軸に沿ってStixelの分布状況を示します。
処理時間: 50ms / frame
CPU: i7-7700 3.6GHz
GPU: NVidia 1050Ti
[![SSD FPGA](http://img.youtube.com/vi/8ypwwJbhC-c/0.jpg)](http://www.youtube.com/watch?v=8ypwwJbhC-c)
# まとめ・今後の課題
- DeepLearningを用いて単眼画像から視差を推定可能
- 学習として使っていないシーンでもうまく推定できる
- 学習データセットにない物体があった場合、視差画像に誤差が生じる
- Stixelを求めるときにカメラのz座標をパラメータとして使用したため、下図のように突然の揺れが起きるとノイズが発生する。

![bump.gif](https://qiita-image-store.s3.amazonaws.com/0/266436/71bd865c-2d68-2b32-b27a-0fbf5ecf71db.gif)
Stixels are sensitive to camera bumping
# Reference
- [Multilayer Stixel World](https://github.com/gishi523/multilayer-stixel-world)
- [Unsupervised Monocular Depth Estimation with Left-Right Consistency](http://visual.cs.ucl.ac.uk/pubs/monoDepth/)
Node.jsでTwitterに画像投稿するメモ


Node.js v8.11.3でやってみました。

## ライブラリインストール

```
npm i twitter
```

## コード

こちらを参考に

> https://github.com/desmondmorris/node-twitter/tree/master/examples#media

`POST 'media/upload'`を実行してアップロードしてからmedia_id_stringをセットして`POST 'statuses/update'`を実行すると画像付き投稿がされます。

```imagepost.js
'use stritct';

const twitter = require('twitter');
const config = require('./config');
const client = new twitter({
    consumer_key: config.twitter.consumerKey,
    consumer_secret: config.twitter.consumerSecret,
    access_token_key: config.twitter.accessTokenKey,
    access_token_secret: config.twitter.accessTokenSecret
});

const data = require('fs').readFileSync('./image.jpg'); //投稿する画像
const mes = 'Hey Hey Hey'; //投稿するメッセージ

(async () => {
	 //画像のアップロード
    const media = await client.post('media/upload', {media: data});
    console.log(media);
    
    //Twitterに投稿
    const status = {
        status: mes,
        media_ids: media.media_id_string // Pass the media id string
    }
    const response = await client.post('statuses/update', status);
    console.log(response);
})();
```

## 実行

![](https://i.gyazo.com/49c68534a07edd82d5aab4e9bbc12cfa.png)
TypeScript3.0 予習 - NightlyBuild -

先日このPRがマージされていたので早速試してみた。
https://github.com/Microsoft/TypeScript/pull/24897

以下で NightlyBuild が試せる。

```
npm install typescript@next
```

## spread expression

v2.8 から Type inference in conditional types で、推論中に n番目のキャプチャ をとることができていた。 v3.0 からは spread expression が可能になるため以下の様な Tuple n番目のキャプチャをとることが可能。

```typing.ts
// v2.8 から可能になった Type inference in conditional types による
// n番目引数のキャプチャ

type A1<Func> = Func extends (a1: infer A, ...args: any[]) => any ? A : never
type A2<Func> = Func extends (a1: any, a2: infer A, ...args: any[]) => any ? A : never

// v3.0 NightlyBuild では以下の spread expression が可能

type I0<Tuple> = Tuple extends [infer A, ...any[]] ? A : never
type I1<Tuple> = Tuple extends [any, infer A, ...any[]] ? A : never
```

以下の通り可変長引数を Tuple として扱えることが書かれている。

## Strong typing of bind, call, and apply

PR に書いてある通りで、この機能の追加 + ThisType で mixin などの推論が強力になると思われる。また、可変長引数によって処理を振り分けたりするAPIを持つライブラリに有効。雑に何かを書いてみた。(こんな節操のないコードが存在しないことを祈りたい…)

```convert.js
function convert(...args) {
  if (typeof args[0] === 'string') {
    return [...args].map(arg => String(arg))
  }
  if (typeof args[1] === 'boolean') {
    return [...args].map(arg => Boolean(arg))
  }
  if (typeof args[2] === 'number') {
    return [...args].map(arg => Number(arg))
  }
  return args
}
```

```convert.ts
type NSB = number | string | boolean

type I0<T> = T extends [infer A, ...any[]] ? A : never
type I1<T> = T extends [any, infer A, ...any[]] ? A : never
type I2<T> = T extends [any, any, infer A, ...any[]] ? A : never

type isFirstArgString<T> = I0<T> extends string ? T : never
type isSecondArgBool<T>  = I1<T> extends boolean ? T : never
type isThirdArgNumber<T> = I2<T> extends number ? T : never

type ConvertedList<T>  = T extends isFirstArgString<T> ? string[] :
                         T extends isSecondArgBool<T> ? boolean[] :
                         T extends isThirdArgNumber<T> ? number[] :
                         T

function convert<T extends NSB[]>(...args: T) {
  if (typeof args[0] === 'string') {
    return [...args].map((arg: NSB) => String(arg)) as ConvertedList<T>
  }
  if (typeof args[1] === 'boolean') {
    return [...args].map((arg: NSB) => Boolean(arg)) as ConvertedList<T>
  }
  if (typeof args[2] === 'number') {
    return [...args].map((arg: NSB) => Number(arg)) as ConvertedList<T>
  }
  return args as ConvertedList<T>
}
const T1 = convert('0', true, 2) // T1: string[] = ["0", "true", "2"]
const T2 = convert(0, true, 2)   // T2: boolean[] = [false, true, true]]
const T3 = convert(0, '1', 2)    // T3: number[] = [0, 1, 2]
const T4 = convert(0, '1', '2')  // T4: [0, "1", "2"] = [0, "1", "2"]
```

スキーマが微妙に違うインスタンスを配列に保持している場合、抽出したインスタンスの規約を推論出来るなども考えられそう。強い。
Git LFS lockを使うためのエイリアス メモ

Git LFS（2.4系)のロック機能は、以下の点であんまりイケてないです。

- 自分の持ってるすべてのロックを一気に外す方法がない
  - 外すのに軽いシェル芸が要る 
  - `git lfs locks | grep [my-git-user-name] | cut -f 1 | xargs git lfs unlock` みたいな
- lock/unlockコマンドの引数にファイルを1つしか指定できない
  - 例えば、  `git lfs unlock A.xlsx B.xlsx` すると、エラーを吐かずにA.xlsxだけロックが外れる。 
- lock/unlockのコマンドに lfs が入っていて、長い。 ex) `git lfs lock A.xlsx`


せめてコマンドインターフェースだけでも解決するためaliasを書いたので共有しておきます。


```git.config
[alias]
        lock = "!f(){ git pull ; for file in \"$@\"; do git lfs lock $file; done };f"
        unlock = "!f(){ for file in \"$@\"; do git lfs unlock $file; done };f"
        unlockall = "!f() { git lfs locks | grep [my-git-user-name] | cut -f 1 | while read -r file; do git lfs unlock $file; done; };f"
        locks = "!f() { git lfs locks; };f"

# [my-git-user-name] は、自分のアカウント名に書き換えてください。
```

```bash
$ git lock A.xlsx B.xlsx #2つのファイルのlockを取る（ファイル数だけlockリクエストが走る)
$ git unlock A.xlsx B.xlsx #2つのファイルのlockを外す
$ git unlockall #自分の持っているすべてのlockを外す
$ git locks #全員のlock状況を見る
```

GitHub+Bashのみでテストしてあります。
atom上のターミナルからDockerを起動する方法(Windows)

Atomのターミナルを起動したときに、すぐにDockerが使える手順を示します。(Windows環境)

###Step1 ターミナルパッケージをダウンロード
atomのターミナルパッケージはいくつかありますが、自分はplatformio-ide-terminalを使ってます。

###Step2 パッケージ設定

ダウンロードしたパッケージの設定を開きます。
Core項目のAuto Run Command に以下を入力。

```
cd /c/'Program Files'/'Docker Toolbox' \ 
sh start.sh 
```

Shell Overrideに以下を入力。

```
C:\Program Files\Git\bin\bash.exe
```

これでターミナルを開いた時に、すぐにDokcerが使えるようになります！！！
TypeError: require.extensions.hasOwnProperty is not a function ［gulp実行時のエラー対応］

以前作成した、プロジェクトを修正するのに当たって、gulpコマンドを叩いた時にタイトルのようなエラー文が出た時の対応策です。

このエラー、結構見受けられるらしいですが、ググっても解決策が日本語では見つからなかったのでかき残しておきます。

エラー例はこんな感じ。（ここではLaravelーelixirの表記が出ていますが、関係ないです。）

```
TypeError: require.extensions.hasOwnProperty is not a function
    at requireDir (/Users/user/workspace/project/node_modules/laravel-elixir/node_modules/require-dir/index.js:93:37)
    at Elixir (/Users/user/workspace/project/node_modules/laravel-elixir/index.js:2:27)
    at Object.<anonymous> (/Users/user/workspace/project/gulpfile.js:15:1)
    at Module._compile (module.js:652:30)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)
    at Module.require (module.js:596:17)
    at require (internal/module.js:11:18)
```

#原因
node.jsのバージョンアップによるものです。
僕はこのプロジェクトには途中から修正で関わったのですが、製作されたのは数年前らしく、僕のnodeのバージョンよりも古いもので作られていたみたいです。

#解決方法
node.jsのバージョンを切り替えるのに便利なnvmを使用しましょう。


```
# nvmのインストール
git clone git://github.com/creationix/nvm.git ~/.nvm

# 設定の読込（こちらでうまくいかない場合は手動でバッシュを書き換えてください。）
echo "source ~/.nvm/nvm.sh" >> ~/.bash_profile && source ~/.bash_profile

# nvmのバージョン確認
nvm --version

# install 可能なnode確認
nvm ls-remote

#nvmから v6のインストール（v6.11.0がもっとも安定してるぽい）
#僕の時はv6が該当しました。node-v8以上を使用していることでこのエラーに出会っているのであれば、
#おそらくv6を使用すればいけるんじゃないかと思います。
nvm install 6.11.0

# インストールされたか確認
node -v

#gulp実行
gulp
```

##参考元
https://github.com/tjunnone/npm-check-updates/issues/367
https://github.com/tjunnone/npm-check-updates/issues/363#issuecomment-308452577


もしも間違い・ご指摘ありましたらよろしくお願いします。
hello, Qiita

##自己紹介 
22歳の情報系学生です。乃木坂46が好きです、与田ちゃん...。
##きっかけ
最近よくpythonでプログラムを書くようになったので、備忘録というか記録も兼ねて文章と共に残しておきたいと思うようになりました。
あとは広告収入とは何ぞや、という興味からアフィサイトを開設したのでhtmlやcss、sassなんかも勉強しないとな～と感じていて、Qiitaで記事投稿しながら楽しくやろうと思い立ちました。
##目標
webエンジニアに最低限必要なスキルがいつの間にか身に付いてた！なんて夢を胸に秘め、~~最低でも週1での投稿を目指します~~記事を書きます。具体的な目標は追々探します。
##最後に
スキルアップ目指して気楽にやっていこうと思います。至らぬ点もあるかと思いますが、よろしくお願いします！
td-agent3（Fluentd v1.0）でS3に「laravel.log」（複数行になるログ）を保存する。2018-06-28

# 内容
Laravelのログ `./storage/logs/laravel.log` を `td-agent` を使ってS3に送る方法について記します。

`laravel.log` に関して言えば [monologから出力したログをfluentdで集約する](https://qiita.com/imunew/items/632616b59820272a5447) あたりが参考になりますが、今回はいろいろな事情から「テキストで出力された `laravel.log` を `td-agent` で送る」というところにこだわります。

# ポイント
`laravel.log` にはstack traceが出力され複数行になることがあります。

例

```
[2018-06-28 03:21:38] local.DEBUG: <デバッグログ>
[2018-06-28 03:21:38] local.DEBUG: <デバッグログ>
[2018-06-28 03:21:38] local.ERROR: <エラー>
Stack trace:
#0 <trace #0>
#1 <trace #1>
#2 <trace #2>
[2018-06-28 03:21:39] local.DEBUG: <デバッグログ>
```

このような複数行に渡るログを `td-agent` で送るところがポイントです。

[multiline Parser Plugin](https://docs.fluentd.org/v1.0/articles/parser_multiline) を使うと容易に設定できます。

# 準備
[td-agent3（Fluentd v1.0）でS3にログを保存する](https://qiita.com/abetomo/items/f7cf264525d92f1c9154) を一通り設定した状態にする

# 設定例
## 設定ファイル
参考: [multiline Parser Plugin](https://docs.fluentd.org/v1.0/articles/parser_multiline)

```conf:/etc/td-agent/td-agent.conf
# <source> の内容が本題
<source>
  @type tail
  path /ログが出ているPATH/laravel.log
  tag laravel.log
  pos_file /var/log/td-agent/laravel_log.pos

  <parse>
    @type multiline
    format_firstline /^\[2\d{3}-[01]\d-[0-3]\d [012]\d:[0-5]\d:[0-5]\d\]/
    format1 /^\[(?<time>2\d{3}-[01]\d-[0-3]\d [012]\d:[0-5]\d:[0-5]\d)\] (?<level>(.*?)): (?<message>.*)/
  </parse>
</source>

# <match> についての詳細は割愛
<match laravel.log>
  @type s3
  format json
  include_time_key true

  aws_key_id YOUR_AWS_KEY_ID
  aws_sec_key YOUR_AWS_SECRET_KEY
  s3_bucket YOUR_S3_BUCKET_NAME
  s3_region us-east-1
  path logs/${tag}/%Y-%m-%d/
  s3_object_key_format %{path}%{time_slice}_%{index}.%{file_extension}

  # if you want to use ${tag} or %Y/%m/%d/ like syntax in path / s3_object_key_format,
  # need to specify tag for ${tag} and time for %Y/%m/%d in <buffer> argument.

  <buffer tag,time>
    @type file
    path /var/log/td-agent/s3
    timekey 60
    timekey_wait 60
    chunk_limit_size 256m
  </buffer>
</match>
```

# 動作確認
以上の設定例で `td-agent` を起動してログ（`/var/log/td-agent/td-agent.log`）を確認します。
特に問題がなさそうであれば `laravel.log` に出力があるような処理をしてログを出します。

S3にログがたまっていく確認します。

## ログデータの確認
今回の設定だと、S3に以下のようなテキストのログがたまっていきました。

```YOUR_S3_BUCKET_NAME/laravel.log/2018-06-28/201806280321_0.gz
{"level":"local.DEBUG","message":"<デバッグログ>","time":"2018-06-28T03:21:38+00:00"}
{"level":"local.DEBUG","message":"<デバッグログ>","time":"2018-06-28T03:21:38+00:00"}
{"level":"local.ERROR","message":"<エラー>\nStack trace:\n#0 <trace #0>\n#1 <trace #1>\n#2 <trace #2>","time":"2018-06-28T03:21:38+00:00"}
```

# まとめ
* `td-agent3`（`Fluentd v1.0`）で `S3` に `laravel.log` を保存できました
* `td-agent3`（`Fluentd v1.0`）で `S3` に 「複数行に渡るログ」 を保存できました
Nuxtでcross-envを使い環境ごとに環境変数を分ける


cross-envはNodeのライブラリでnpmスクリプト実行時に任意の環境変数を設定できます。
これを利用して、開発（ローカル）、検証、本番環境の設定切り替えが可能なビルドを実現します。

各環境の英語と日本語の対応付は以下です。

- 開発環境 = development environment
- 検証環境 = staging environment
- 本番環境 = production environment


利用するファイルは以下です。すべてディレクトリ直下に置いています。

- env.development.js (開発環境用ファイル)
- env.staging.js (検証環境用ファイル)
- env.production.js (本番環境用ファイル)
- package.json (環境変数設定を含んだnpmスクリプトを記述するファイル)
- nuxt.config.js (環境変数に応じた設定ファイルを読み込む）

## npmライブラリのインストール

まずプロジェクトのディレクトリでcross-envをインストールします。

```bash
$ npm install --save cross-env
```

## 各種設定ファイルの作成

JavaScriptファイルで作ります。
今回はAPIのベースURLを定義します。値は適宜読み替えてください。

- env.development.js

```js
module.exports = {
  apiBaseUrl: 'http://localhost:8000'
}
```

- env.staging.js

```js
module.exports = {
  apiBaseUrl: 'http://stg.your-api.com/api'
}
```

- env.production.js

```js
module.exports = {
  apiBaseUrl: 'http://your-api.com/api'
}
```


## `package.json`のnpmスクリプトの記載

npmスクリプトの`build`と`start`を、開発、検証、本番環境用に3つに分けます。そして先頭に`cross-env NODE_ENV=XXXXXX`と足すことで環境変数`NODE_ENV`を切り替えコマンド実行させます。
コマンドは、開発用に`build`、検証用に`build:stg`、本番用に`build:prod`といった形に分けています。（開発が`build:dev`でないのはもともとある`build`コマンドを消すことで発生する影響のリスク回避です）

```json
{
  ...
  
  "scripts": {
    "dev": "nuxt",
    "build": "nuxt build",
    "build:stg": "cross-env NODE_ENV=\"staging\" nuxt build",
    "build:prod": "cross-env NODE_ENV=\"production\" nuxt build",
    "start": "nuxt start",
    "start:stg": "cross-env NODE_ENV=\"staging\" nuxt start",
    "start:prod": "cross-env NODE_ENV=\"production\" nuxt start",
    "generate": "nuxt generate",
    "lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
    "precommit": "npm run lint"
  },
  
  ...
  
}
```

## `nuxt.config.js`の修正

`nuxt.config.js`ではnpmスクリプトで渡された変数を元に読み込むファイルを切り替えます。
テンプレートリテラルを使い、`${process.env.NODE_ENV}`の部分で読み込む環境を指定します。
その後、Nuxtの設定の1つであるenvプロパティを利用してアプリで利用可能な値として定義します。

```js
const environment = process.env.NODE_ENV || 'development';
const envSet = require(`./env.${environment}.js`)

module.exports = {

  ...
  
  env: envSet
  
  ...

}
```

## envで利用した値の利用方法

[env プロパティ(Nuxtドキュメント)](https://ja.nuxtjs.org/api/configuration-env)

コード内で`process.env.apiBaseUrl`と定義することで値を利用できます。

## 注意点

2018/06/15現在、日本語ドキュメントでは翻訳されていないのですが、Nuxtの`process.env`は少しクセがあります。というのは、上記の設定で`process.env.apiBaseUrl`は問題なく取得できるのですが`process.env`は空のオブジェクトとして認識される点です。

これはNuxtがWebpack内で`process.env.XXXXXX`を実体として変換した状態でビルドを行うからです。

ビルド前

```js
if (process.env.test == 'testing123')
```

ビルド後

```js
if ('testing123' == 'testing123')
```

なのでコード内で`process.env`は利用しないで、`process.env.XXXXX`まで利用するようご注意ください。
javaで文字列を連結する方法

C#と同じく、(+)演算子を使って文字列の連結ができる。

<pre>
String str1 = "清風";
String str2 = "清風情報工科学院";
        
String str3 = str1 + str2;
        
System.out.println(str3);
</pre>

結果：
![スケッチ (7).png](https://qiita-image-store.s3.amazonaws.com/0/251603/77d387c0-a07e-d44c-efaa-c09ec2c4d750.png)
Javaで現在の日付を表示する

Javaプログラミングにおいて、日付型を扱うときに使用する代表的なクラスは以下の通りだ。
―　java.util.Date;
―　java.text.DateFormat;
―　java.text.SimpleDateFormat;

Date クラスを使って取得する場合、引数なしで Date オブジェクトを生成することで現在日時が設定された Date オブジェクトを取得することができます。
出力形式を任意のフォーマットに成型したい場合は、SimpleDateFormat クラスなどを使用します。

<pre>
Date date=new Date();
        
DateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm");
        
String formattedDate=dateFormat.format(date);
        
System.out.println(formattedDate);
</pre>

結果：
![スケッチ (7).png](https://qiita-image-store.s3.amazonaws.com/0/251603/b7241d2a-dcce-583d-926e-35b15e575a49.png)
複数のFacebookアカウントの投稿を取得し、1つのAPIで返す

#背景
個人ではあまりないことですが、企業だと複数のFacebookアカウントを持っていることがあると思います。縦割り組織の場合だと、商品のカテゴリーごとに勝手にアカウント作って運用していることはよくあることだと思います。それぞれのカテゴリー毎に発信することも重要ですが、まとめて閲覧できる場を作りたいと思い開発しました。

##前準備
(1) facebook for developersでアカウント開設

(2) マイアプリを作成後、設定画面でapp secretとApp IDをコピー

(3) 無期限アクセストークンの取得
無期限APIの取得方法はこちらが参考になりました。
画面のキャプチャ付きでわかりやすいです。
[Facebook API ページの無期限 Access Token 取得方法](https://hirofukami.com/2017/06/30/facebook-page-access-token/)


###構成
![図1.png](https://qiita-image-store.s3.amazonaws.com/0/263539/17dedfe7-2003-7dd2-af96-68ef9c5d2852.png)

LambdaでTokenやFacebookのアカウント情報を記載し、GraphAPIを使用します


###コード

```python:lambda_function.py
import os
import json
import datetime
import requests
import boto3
from dateutil.parser import parse
from boto3.dynamodb.conditions import Key, Attr

endpoint = os.environ['endpoint']
# https://graph.facebook.com/v3.0/

aaaaAccount = {'123456789':'***************'}
bbbbAccount = {"987654321":"***************"}
# id : token

accountlist = aaaaAccount
accountlist.update(bbbbAccount)

def lambda_handler(event, context):

    feedList = {}

    for key, item in accountlist.items():
        jsonData = get_accountList(key,item)
        for feedData in jsonData['feed']['data']:
            if 'message' in feedData.keys() and 'shares' in feedData.keys():
                feedList[feedData['created_time']] = {'message':feedData['message'],'sharecount':feedData['shares']['count'],'name':jsonData['name'],'picture':jsonData['picture']['data']['url'],'link':jsonData['link']}
    sortData = sorted(feedList.items(),reverse=True)
    retrun sortData

def get_accountList(facebookId,token):
    param = '?fields=about%2Cfeed.limit(3)%7Bmessage%2Ccreated_time%2Cshares%7D%2Cfan_count%2Cpicture%2Clink%2Cname&access_token=' + token
    url = endpoint + facebookId + param
    return requests.get(url).json()
```

#改善したい点
・管理用のアカウントで無期限のtokenを発行 or 毎回tokenを取得できれば、管理下のアカウント毎にAPI実行しなくて済むので方法があればそちらに変更したい。
・API用のパラメーターをエンコードしたものを記述しているが、視認性向上のためプログラムでエンコードしたい。(下記コードだとlimit(3)の()がエンコードされたせいかうまくいかなかった。)
・dynamoDB or CloudFrontを使用して毎回APIをたたかないようにして、レスポンス向上したい

```python
param = urllib.parse.quote('/?fields=about,feed.limit(3),fan_count,picture,link&access_token=') + token
```
【Rails】 deviseで承認制でユーザー登録の際にメールを飛ばす時に気をつける事

## はじめに

Railsで認証システムを作るときに便利なGemとして `devise` が挙げられます。
[https://github.com/plataformatec/devise](https://github.com/plataformatec/devise)
deviseは認証システムを作るツールとしては強力であり、カスタマイズなしでも高度な機能が一通り揃っています。
しかし、いざカスタマイズして使おうとすると色々と考えなくてはいけないこともあります。
今日は、ユーザ登録を行なってからすぐにログインはできないようにし、管理者が承認してから初めてログインできるようなプロセスで運用したいときに気をつけておかなければならないことを共有します。

## ユーザー登録後に管理者の承認プロセスが踏んでからログインできるようにするには

deviseのwikiに以下のようなものがありました。

[https://github.com/plataformatec/devise/wiki/How-To:-Require-admin-to-activate-account-before-sign_in](https://github.com/plataformatec/devise/wiki/How-To:-Require-admin-to-activate-account-before-sign_in)

その中でも特に、 ActiveRecordのメソッドを使っている部分に注目します。

```ruby:app/models/user.rb
  after_create :send_admin_mail
  def send_admin_mail
    AdminMailer.new_user_waiting_for_approval(email).deliver
  end
```

```erb:views/admin_mailer/new_user_waiting_for_approval.erb
<p><%= @email %> has registered to join your site!</p>
<p>An admin can approve this registration by visiting the website and editing the user</p>
```

ユーザー作成後にメールを飛ばすメソッドが走っています。これを参考に、ユーザーテーブルに、承認フラグのカラムを追加して、管理者が承認した場合、アカウントが承認された旨を伝えるメソッドを追加しました。

* 管理者画面や承認プロセスを走らせるメソッド関連は省略

```ruby:app/models/user.rb
+ after_update :send_approved

+ def send_approved
+   AdminMailer.user_approved(email).deliver
+ end
```

## after_update だけだとサインイン時にもメールが飛んでしまう

しかし、これには致命的な問題があります。
deviseでサインインをした場合、DBではサインインした回数やユーザがアクセスして来たIPアドレスの情報などのデータのupdateが走ってしまいます。

```
  User Update (2.3ms)  UPDATE "users" SET "current_sign_in_at" = $1, "last_sign_in_at" = $2, "current_sign_in_ip" = $3, "last_sign_in_ip" = $4, "sign_in_count" = $5, "updated_at" = $6 WHERE "users"."id" = $7  [["current_sign_in_at", "2018-06-28 01:07:42.733295"], ["last_sign_in_at", "2018-06-28 01:07:42.733295"], ["current_sign_in_ip", "172.19.0.1/32"], ["last_sign_in_ip", "172.19.0.1/32"], ["sign_in_count", 1], ["updated_at", "2018-06-28 01:07:42.737637"], ["id", 1]]
```

これでは、 after_updateでメールを送っているためサインイン時にもメールが飛んでしまいます。
そこで、 `条件付きコールバックを利用して、コールバックが実行されるべきか否かをチェックすることにします。`

```ruby:app/models/user.rb
+ after_update :send_approved if: [:saved_changes?, :saved_change_to_approved?]
```

`saved_changes?` メソッドはレコードに保存されていないオブジェクトがあるかどうかをチェックします。
このメソッドは、どのコールバックで実行するかによって、結果が変化します。
* 参照 -> [https://qiita.com/ysKey2/items/7e429e478069b61b53bd](https://qiita.com/ysKey2/items/7e429e478069b61b53bd)

いずれにせよ、これだけではサインイン時にもメールが飛んでしまうことを解決できないため、 `saved_change_to_approved?` で `approvedに変更が加わっているか否かをチェック` します。
このメソッドを利用しているプロジェクトでは管理画面のみ登録申請を行なったユーザーの承認チェックを行なっているためひとまずこれで、approvedに変更が加わっている = 管理画面で承認されたということになります。

なお、Rails 5.1以前では save_changes?メソッドではなく changed?メソッドが使われていましたが、changed? メソッドは `Deprecate`されているため、これから使うなら save_changes? を使いましょう。

## まとめ

以上、短いですが 急遽deviseのバグ対応を行なっていた際に調べたことをまとめて執筆しました。
おそらく、これからもdevise関係で何かとカスタマイズするかと思いますので、その際はバグ対応中心に執筆していきたいと思います(deviseのカスタマイズ関係の記事は他の方が多く書かれていますしね)
それでは。

## その他の参考文献

* [https://www.levups.com/en/blog/2017/undocumented-dirty-attributes-activerecord-changes-rails51.html](https://www.levups.com/en/blog/2017/undocumented-dirty-attributes-activerecord-changes-rails51.html)
TouchDesigner | Timer CHOP


![timerCHOP.gif](https://qiita-image-store.s3.amazonaws.com/0/199903/9bf546c6-e440-fd43-d62d-0bb9338cedcc.gif)
<br />

```
def onDone(timerOp, segment, interrupt):
	import random
	op('constant2').par.value0 = random.random()
	op('constant2').par.value1 = random.random()
	return
```
<br />

![screenshot 2018-06-28 11.19.17.png](https://qiita-image-store.s3.amazonaws.com/0/199903/dd9cdab4-1900-cc9e-06c1-898bc198b41f.png)
<br />
<br />

**Reference Source**
http://station.backspace.tokyo/satoruhiga/TDWS_2018/post/day4/
日付時刻として正しいか判定する正規表現(JavaScript)

YmdHis形式で保存した日付時刻が正しいか検証する正規表現(JavaScript用)を書きました。
もっと短くできると思いますが、自分の力では無理なので、何か方法あったら教えてくださいm(_ _)m

```javascript
let re = /^((([02468][048]|[13579][26])00|[0-9]{2}([2468][048]|[13579][26]|0[48]))(02(0[1-9]|1[0-9]|2[0-9]))|([0-9]{4}((0[1-9])(0[1-9]|1[0-9]|2[0-8])|(0[1[3-9]]|1[0-2])(0[1-9]|[12][0-9]|30)|(0[13578]|12)31)))([01][0-9]|2[0-3])[0-5][0-9]([0-5][0-9]|60)$/;
re.test('20180628114959') // => true
```

規則的に入る閏年の対応はできましたが、閏秒に関しては不定期ではいるので、毎分の「60秒」を正しい時刻として判定する仕様になっています。