OmniAICreator/Qiita-1.07M huggingface dataset:
PythonでIPアドレスの文字列表現が正しいフォーマットか確認する

# はじめに

タイトルのとおり、Pythonで「192.168.1.100」のようなIPアドレスの文字列が正しいフォーマットか確認する簡単なやり方のメモです。以前は正規表現をがんばって書いていました。

# やりかた

```python
from socket import inet_aton

def is_valid_ip(addr):
    try:
        inet_aton(addr)
        return True
    except:
        return False

is_valid_ip("192.168.1.100") # True
is_valid_ip("192.168.1.xxx") # False
```

以下のライブラリのソースを眺めていて、あーこうやるのかと納得した次第です。

* [Pythonからpingで他のマシンの死活監視をするライブラリ - Qiita](https://qiita.com/satoshi03/items/2bbd546880846e4d6d41)
    * [pings/ping.py at master · satoshi03/pings](https://github.com/satoshi03/pings/blob/master/pings/ping.py#L46-L51)

# 余談

inet_atonが何なのか知らなかったのですが `man inet_aton` したところ色々わかりました。

```
man inet_aton
...
DESCRIPTION
       inet_aton()  converts  the  Internet host address cp from the IPv4 numbers-and-dots notation into binary form (in network byte order) and stores it in the structure that inp
       points to.  inet_aton() returns nonzero if the address is valid, zero if not.  The address supplied in cp can have one of the following forms:

       a.b.c.d   Each of the four numeric parts specifies a byte of the address; the bytes are assigned in left-to-right order to produce the binary address.

       a.b.c     Parts a and b specify the first two bytes of the binary address.  Part c is interpreted as a 16-bit value that defines  the  rightmost  two  bytes  of  the  binary
                 address.  This notation is suitable for specifying (outmoded) Class B network addresses.

       a.b       Part a specifies the first byte of the binary address.  Part b is interpreted as a 24-bit value that defines the rightmost three bytes of the binary address.  This
                 notation is suitable for specifying (outmoded) Class A network addresses.

       a         The value a is interpreted as a 32-bit value that is stored directly into the binary address without any byte rearrangement.
...
```

inet_atonで変換可能なフォーマットは「192.168.1.100」のような見た目以外でも、「3232235876」とか「192.11010404」とか「192.168.356」でもいいみたいです。4オクテットのシリーズでないと正しいとみなさない、といった要件がある場合は、inet_atonに加えてそこのチェックを入れたほうがいいかも。

以下は、「192.168.1.100」と同じ変換結果になるものの変換の例です。

```console
ipython
...
In [1]: from socket import inet_aton

In [2]: hex(192), hex(168), hex(1), hex(100)
Out[2]: ('0xc0', '0xa8', '0x1', '0x64')

In [3]: 0xc0a80164
Out[3]: 3232235876

In [4]: inet_aton("3232235876")
Out[4]: '\xc0\xa8\x01d'

In [5]: 0xa80164
Out[5]: 11010404

In [6]: inet_aton("192.11010404")
Out[6]: '\xc0\xa8\x01d'

In [7]: 0x0164
Out[7]: 356

In [8]: inet_aton("192.168.356")
Out[8]: '\xc0\xa8\x01d'
```
【Laravel】 ネストした既定の Eager Loading を一時的に無効化する

最近 Laravel の Eager Loading ネタ無限に書いてる気がする…ｗ

# 問題

`Community` `Member` `Plan` というエンティティがある。
（有料コミュニティが存在し，それにメンバーが異なる料金プランで加入しているイメージ）

```php
class Community extends Model
{
    protected $with = ['members'];

    public function members(): HasMany
    {
        return $this->hasMany(Member::class);
    }
}
```

```php
class Member extends Model
{
    protected $with = ['plan'];

    public function plan(): BelongsTo
    {
        return $this->belongsTo(Plan::class);
    }
}
```

```php
class Plan extends Model {}
```

ここで，

```php
$communities = Community::all();
```

として取得すると， `$communities[0]->members[0]->plan` の階層まで Eager Loading が行われる。

このとき `->plan` の階層の Eager Loading は行いたくない場合，どうすればいいだろうか？所詮1クエリしかないので多くの場合は支障は無いが，すでに別のクエリで取得済みなので余分なことは行いたくないというケースを想定する。

# 解決策

## 間違い

`without` はドットチェーンで記述するネストしたリレーションには対応できない。

```php
$communities = Community::without('members.plan')->get();
```

## 解法 (1)

`with` で既存リレーションを `without` 付与したもので上書きしてしまう方法。

```php
$communities = Community::with(['members' => function (HasMany $relation) {
    $relation->without('plan');
}]);
```

## 解法 (2)

基本は解法 (1) と同じだが， スコープとして定義してしまう方法。記述量が少なくシンプルになるため，非常におすすめ。

```php
class Community extends Model
{
    protected $with = ['members'];

    public function scopeWithoutMemberPlans(Builder $query): Builder
    {
        return isset($query->getEagerLoads()['members'])
            ? $query->with(['members' => function (HasMany $relation) {
                $relation->without('plan');
            }])
            : $query;
    }
}
```

```php
$communities = Community::withoutMemberPlans()->all();
```

## 解法 (3)

Eloquent Collection クラスに実装する場合はこう書く。いったん `members` のロードをやめてコレクションを取得したあと，追加でメソッドを呼ぶイメージ。

```php
class Community extends Model
{
    protected $with = ['members'];

    public function newCollection(array $models = []): CommunityCollection
    {
        return new CommunityCollection($models);
    }

    public function members(): HasMany
    {
        return $this->hasMany(Member::class);
    }
}
```

```php
class CommunityCollection extends Collection
{
    public function loadMembersWithoutPlan(): self
    {
        return $this->load(['members' => function (HasMany $relation) {
            $relation->without('plan');
        }]);
    }
}
```

```php
$communities = Community::without('members')->loadMembersWithoutPlan();
```

# まとめ

- ドットチェイン形式ではネストした Eager Loading 制約を除外できない
- 連想配列形式での Eager Loading 制約の付与は以下のメソッドでできる
  - Eloquent Collection → `load`
  - Eloquent Builder および Relation → `with`
Ubuntuターミナルでのコピー＆ペースト

UbuntuではターミナルでCtrl + c/vによるコピペができない
間違ってCtrl + cを使いコピペしようと思ったコマンドを消してしまうことも

少し面倒だけど以下のキーを使えばコピペができる

#コピー
・Ctrl + Shift + c
・Ctrl + Insert

#ペースト
・Ctrl + Shift + v
・Ctrl + Shitt + Insert
UnityのIL2CPPビルドにおいてGPU Instancingだと何故か描画されない問題について

藍澤光の誕生日なので初透光です。

#前提環境

 - Unity 2018.3.0b2

#問題
GPU Instancingで超大量のオブジェクトを描画しようとするとエディター上では描画できますがIL2CPPビルドした実機上で描画されません。

#解決策
Edit &gt; Settings &gt; Graphics &gt; Shader Stripping &gt; Instancing Variantsの設定をStrip UnusedからKeep Allに変更します。
エディター上では全てのシェーダーがメモリ上に乗っているため描画できますが、IL2CPPビルドをするとGPU Instancing有効なシェーダーを不要と判断して捨ててしまい、結果として実機上で何も描画しないようです。

Unity2018.3からPreferencesはSettingsに統合されました。設定を探す手間が省けますね。 ~~なぜこれまで分けていたのか？~~

#感想
こういうピットフォールほんとひで
Google Cloud SDK Shellで、python3.6を実行するまで（Windows）

ブラウザのGoogle chromeをインストールしておきます

![chrome.png](https://qiita-image-store.s3.amazonaws.com/0/293513/ea5bbe50-7f2e-4966-981c-b52b33d0018a.png)

----

ブラウザのGoogle Chromeに以下のurlを入力して、Google Cloudを開きます

https://cloud.google.com/

![google cloud.png](https://qiita-image-store.s3.amazonaws.com/0/293513/3d4ddd51-3d93-f9af-ec59-4f91f069274c.png)

----

Google Cloud Platformのスタートガイドの「Cloud SDKをインストール」からCloud SDKを設定します

![Google Cloud Platform1.png](https://qiita-image-store.s3.amazonaws.com/0/293513/a9da374e-92a5-bf26-ace6-4e4a0c5a653b.png)

----

![Google SDK.png](https://qiita-image-store.s3.amazonaws.com/0/293513/b2a3fba4-1caa-fcef-0e87-325891e90184.png)

インストール後、デスクトップにCloud SDKアイコンが生成するので、これをダブルクリックします

![Google SDK shell.png](https://qiita-image-store.s3.amazonaws.com/0/293513/ed90b650-2312-1d92-2eba-7249ebba372e.png)

----

Google Cloud SDK Shellに以下のコマンドを入力してpythonコードを実行します
C:\Program Files (x86)\Google\Cloud SDK>  python C:\\(フォルダ名)\\(ファイル名).py


**hello.py**
_print ('hello')_

https://github.com/tsukuba103/sdk/blob/master/hello.py

![hello world.png](https://qiita-image-store.s3.amazonaws.com/0/293513/82916fb4-d97b-3c53-99e5-8f0aa758fa50.png)
Android Studio, Support Library, Play Service, Kotlin等の最新バージョンを知りたい

Androidサポートライブラリの最新バージョンについて調べると以下記事が出てくるが、ちょっとリンクが古い。

Androidの最新情報を追いかけるリンクメモ - Qiita 
https://qiita.com/takahirom/items/9411cb6e4a6d74fcd038

なので、開発に必要な最新バージョンを知るための情報リンクをメモとして載せておく。

## Android Studio

Android Studio Release Updates
https://androidstudio.googleblog.com/

## Support Library

Recent Support Library Revisions  |  Android Developers 
https://developer.android.com/topic/libraries/support-library/revisions

## AndroidX

### バージョン一覧
見やすいけど量がすごい
Migrating to AndroidX  |  Android Developers 
https://developer.android.com/jetpack/androidx/migrate

### リリース履歴
Recent Release Notes  |  Android Developers 
https://developer.android.com/jetpack/androidx/releases

## Play Service

Release Notes  |  Google APIs for Android  |  Google Developers 
https://developers.google.com/android/guides/releases

#### こちらは個々のバージョンがテーブルになっていて分かりやすい
Set Up Google Play Services  |  Google APIs for Android  |  Google Developers 
https://developers.google.com/android/guides/setup#add_google_play_services_to_your_project

## Build Tools Version

SDK Build Tools release notes  |  Android Developers 
https://developer.android.com/studio/releases/build-tools

app/build.gradleで使うやつ

```groovy
android {
    compileSdkVersion 27
    buildToolsVersion '27.0.3' // <-これ
```

## Android Gradle plugin

Android Gradle plugin release notes  |  Android Developers 
https://developer.android.com/studio/releases/gradle-plugin

```groovy
buildscript {
...
    dependencies {
        classpath 'com.android.tools.build:gradle:3.2.0' // <-これ
```

## Firebase Android

Firebase Android Release Notes 
https://firebase.google.com/support/release-notes/android

## Kotlin
公式のブログからリリースされたバージョンを見れる
Releases | Kotlin Blog
https://blog.jetbrains.com/kotlin/category/releases/

## Google's Maven Repository
### ここが今のところ一番最強
https://dl.google.com/dl/android/maven2/index.html

## Google の Maven リポジトリ
公式が各Android ライブラリの最新バージョンを紹介してる
https://developer.android.com/studio/build/dependencies#google-maven

ここの [プログラムからのアクセス](https://developer.android.com/studio/build/dependencies#gmaven-access)をWebページで見やすく作れば最高だね。

誰か作ってくれ！
macOS Mojaveへの更新

## 概要
HighSierraからMojaveへ更新した時のメモ
お昼前後を想定していますが、帰る時でも良いと思います
時間や困りそうなことの参考に

## 手順
- AppStoreからMojaveをインストール。20分くらい
- インストールしたMojaveが開いたら、お昼休みに行く前にインストーラを実行して進める(再起動を繰り返す状態にする、1時間くらい)。
- 完了後、外付けディスプレイのアンチエイリアスを修正。以下のコマンドを叩いた後ログアウトしてログインし直す。  
`defaults write -g CGFontRenderingFontSmoothingDisabled -bool NO`

## その他
普段使っているアプリケーションが動かなかったことを修正しました

### iTermのHotkeyが動かなくなった
アプデやら設定をやりなおしたけど、
たぶんiTerm自体を再起動したのをキッカケに動くようになりました。

### Virtualboxが起動できなくなった
docker-machineが動かなくて焦った(Virtualboxアイコンの上にバツマークが付いていた)
Virtualboxは自動でアプデする設定ではなかったようで、最新版インストールしなおしたら起動できました。

## 雑感
ダークモード最高です
アプデしわすれ注意

## 参考
https://hatebu.me/entry/mojavefont
ターミナルソフト「Terminator」のショートカットキー

Linuxで使える便利なターミナルソフト「Terminator」の画面操作用のショートカットをまとめました。

| 操作 | キー | 
|:-----------|:------------|
| 水平分割 | Ctrl + Shift + o |
| 垂直分割 | Ctrl + Shift + e |
| パネル間移動(↓→+パネルサイズ順) | Ctrl + Shift + n |
| パネル間移動(任意の方向) |Alt + カーソルキー |
| パネルの拡大・拡大解除 | Ctrl + Shift + z |
| パネルのサイズ変更 | Ctrl + Shift + カーソルキー |
| パネルを閉じる | Ctrl + Shift + w/d |
| 新規タブを開く | Ctrl + Shift + t |
| タブ間移動 | Ctrl + Shift + PageUp/PageDown |
| 文字サイズ変更 | Ctrl + Shift + +/- |

非常に便利！
deviseでno method in devise::registrationscontroller#create undefined method current_sign_in_at

deviseで 
`no method in devise::registrations controller#create undefined method current_sign_in_at
`
が出ました。
調べてみると、rakedb:migrate忘れが原因だということだった。
https://stackoverflow.com/questions/21383860/nomethoderror-in-devisesessionscontrollercreate-undefined-method-current-sig

という訳ではないらしい。（英語読めないからもっと勉強しよう）

試した方法は、

```rb
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
  t.string :first_name
  t.string :last_name
  t.string :profile_name
  t.string :college_name
  ## Database authenticatable
  t.string :email,              :null => false, :default => ""
  t.string :encrypted_password, :null => false, :default => ""
```

```rb
  ## Recoverable
  t.string   :reset_password_token
  t.datetime :reset_password_sent_at
```

```rb
  ## Rememberable
  t.datetime :remember_created_at
```
```rb
  ## Trackable
  t.integer  :sign_in_count, :default => 0
  t.datetime :current_sign_in_at
  t.datetime :last_sign_in_at
  t.string   :current_sign_in_ip
  t.string   :last_sign_in_ip
```

deviseのmigtration fileのcurrent_sign_in_atが書かれている##のところのコメントアウト（trackableのところですかね）を外してrollback => migrateすると動きました。（以前はこんなエラーにならなかったのに・・・）

なぜエラーが出てたのかはわかりませんでしたので、わかる方御教授ください。
【Xcode10】とうとうstackView.removeArrangedSubview(_:)で痛い目を見た

# 環境
iOS 12
Xcode 10
Swift 4.2

# 大事なこと

UIStackViewの`removeArrangedSubview(_:)`ではStackViewの**Stackの配列からは消える**けど**View階層からは消えない**

# 今回の問題

Xcode10でBuildすると今まで`removeArrangedSubview(_:)`だけでも問題なく表示されていたが、**Xcode10からどうも許されなくなった**っぽい(以前からバグっていた人もいたのかな？)。
そのため、removeしたはずのViewがぐちゃぐちゃになって表示されてしまい、**大変怒られた**。

# 一応解決方法

```swift
self.stackView.removeArrangedSubview(self.subView)
```

↓

```swift
self.stackView.removeArrangedSubview(self.subView)
self.subView.removeFromSuperview()
```
OR

```swift
self.subView.isHidden = true
```

# 感想

`removeArrangedSubview(_:)`の仕様はもちろん把握していたし、レビューをしてチェックもしていたが、普通に漏れていた。
[mysql]処理前と処理後のデータを比較する（2つのテーブルの比較）

###内容
tableAを一括更新するバッチのリファクタリングをしたい
リファクタリング前後それぞれのバッチを実行した結果を比較したい
※tableAはすでにリファクタリング前バッチが実行された後の状態

###実際にやったこと
- tableAのコピーを作成する（tableA_beforeとする）
- バッチ実行後のtableAとtableA_beforeを比較する

###詳細
- tableAのコピーを作成する（tableA_beforeとする）

```
mysql> create table tableA_before like tableA;
mysql> insert into tableA_before select * from table A;
```
- バッチを実行する
（実行に必要なコマンドを入力）

- tableAとtableA_beforeを比較する

```
mysql>select
        tableA.id,
        tableA.columnA as columnA_after,
        tableA_before.columnA as columnA_before
    from tableA
        inner join tableA_before 
            on tableA.id = tableA_before.id
    where
        tableA.columnA != tableA_before.columnA;
```

- テストのために作成したtableA_beforeを削除する

```
mysql> drop table tableA_before;
```
Invalid Signature - A sealed resource is missing or invalid. The file at path [アプリ名] is not properly signed.

# Invalid Signature - A sealed resource is missing or invalid. The file at path [アプリ名] is not properly signed.

いつも通りアプリを申請に出してもこんなメールが来てバイナリが受け付けられない場合

```
Dear Developer,

We identified one or more issues with a recent delivery for your app, "My ルーレット". 
Please correct the following issues, then upload again.

Invalid Signature - A sealed resource is missing or invalid. The file at path [MyRoulette.app/MyRoulette] is not properly signed. 
Make sure you have signed your application with a distribution certificate, not an ad hoc certificate or a development certificate. 
Verify that the code signing settings in Xcode are correct at the target level (which override any values at the project level). 
Additionally, make sure the bundle you are uploading was built using a Release target in Xcode, not a Simulator target. 
If you are certain your code signing settings are correct, choose "Clean All" in Xcode, 
delete the "build" directory in the Finder, and rebuild your release target. 
For more information, please consult
 https://developer.apple.com/library/ios/documentation/Security/Conceptual/CodeSigningGuide/Introduction/Introduction.html

Best regards,

The App Store Team
```
## 全角が入ったファイルが原因
全角の名前を使った画像などのリソースがないかチェック　あれば削除か名前を変更
GCPにsshログインした時にチョコボ4匹を出現するようにしてみた


こちらの記事を参考にGCP版のオマージュです。
パクってすみません。
https://qiita.com/tu-kun/items/d38452161bfb9da54bcd#%E3%82%AA%E3%83%AA%E3%82%B8%E3%83%8A%E3%83%AB%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E5%A4%89%E6%9B%B4

## なぜやったか

AWSがあるならGCPもだろ！
ってな感じで、記事見た瞬間に業務をほったらかしにしてやってしまいました。

全く後悔はありません、むしろ清々しいです。

## チョコボを調達

https://github.com/dot-motd/final-fantasy
こちらのgistを拝借させていただきました。

![2018-09-27 11.38.13 からのスクリーンショット.png](https://qiita-image-store.s3.amazonaws.com/0/145671/629565cf-a5c2-fa4a-f2b4-2730556ad707.png)

## 設定の確認

```
$ ssh gcp-test

Last login: Tue Sep 25 17:26:06 2018 from s8.hfukuokafl1.vectant.ne.jp

     __ ____  _______ ___    _   _____   __________
    / //_/ / / / ___//   |  / | / /   | / ____/  _/
   / ,< / / / /\__ \/ /| | /  |/ / /| |/ / __ / /
  / /| / /_/ /___/ / ___ |/ /|  / ___ / /_/ // /
 /_/ |_\____//____/_/  |_/_/ |_/_/  |_\____/___/

    Version 8.4.0-3, Powered by Prime Strategy.

```

sshしたときにkusanagiを使っているので、それっぽいのが出てきます。

`/etc/motd`をrootユーザーで確認。

```
$ cat /etc/motd

     __ ____  _______ ___    _   _____   __________
    / //_/ / / / ___//   |  / | / /   | / ____/  _/
   / ,< / / / /\__ \/ /| | /  |/ / /| |/ / __ / /
  / /| / /_/ /___/ / ___ |/ /|  / ___ / /_/ // /
 /_/ |_\____//____/_/  |_/_/ |_/_/  |_\____/___/

    Version 8.4.0-3, Powered by Prime Strategy.
```

これですね。

試しに書き込んで、もう一度ssh接続してみる。

```
$ vim /etc/motd
     __ ____  _______ ___    _   _____   __________
    / //_/ / / / ___//   |  / | / /   | / ____/  _/
   / ,< / / / /\__ \/ /| | /  |/ / /| |/ / __ / /
  / /| / /_/ /___/ / ___ |/ /|  / ___ / /_/ // /
 /_/ |_\____//____/_/  |_/_/ |_/_/  |_\____/___/

    Version 8.4.0-3, Powered by Prime Strategy.

     テストでやんす

# sshログアウト
$ exit 

$ ssh gcp-test
Last login: Tue Sep 25 17:26:06 2018 from s8.hfukuokafl1.vectant.ne.jp

     __ ____  _______ ___    _   _____   __________
    / //_/ / / / ___//   |  / | / /   | / ____/  _/
   / ,< / / / /\__ \/ /| | /  |/ / /| |/ / __ / /
  / /| / /_/ /___/ / ___ |/ /|  / ___ / /_/ // /
 /_/ |_\____//____/_/  |_/_/ |_/_/  |_\____/___/

    Version 8.4.0-3, Powered by Prime Strategy.

     テストでやんす
```

じゃあこれに直接書き込めば良さそう。

## 設定

ちゃんとcurlで取れているか確認。

![2018-09-27 11.46.47 からのスクリーンショット.png](https://qiita-image-store.s3.amazonaws.com/0/145671/895daa03-b575-d0ab-0a40-28b687b8c8cc.png)

おっけい。

```
$ curl -s https://gist.githubusercontent.com/makocchi-git/9775443/raw/70b3e0250a0d07be3c4dcdaed3dff5662e2a7ab4/chocobo-allstar.txt | sudo tee -a /etc/motd
```

上記のコマンド実行後、最後sshで接続。

![2018-09-27 11.51.57 からのスクリーンショット.png](https://qiita-image-store.s3.amazonaws.com/0/145671/b3c00a62-bc9a-c539-ee39-6eeb742d92a3.png)

## 問題点

AWSのように`update-motd.d`がなかったので、サーバーを再起動すると設定が消えちゃう可能性があります（試してない）。

特に調査せずやったので、後日暇があればやってみようとおもいます。

現状再起動をほとんどやらないサーバーでやったので、今回はこのままにしときます。

## チョコボ可愛い

スライム可愛い

チョコボも可愛い

今度上司が接続するサーバーにチョコボ仕込んどきます。

## 宣伝

ブログやってるので是非。
http://smot93516.hatenablog.jp/

## 追記

はぐれメタルも可愛い。

![2018-09-27 14.38.39 からのスクリーンショット.png](https://qiita-image-store.s3.amazonaws.com/0/145671/099f2d80-ee3f-3fa4-da9a-2923a1a02a43.png)
サードパーティ圧縮解凍ツールのススメ

# サードパーティ圧縮解凍ツールのススメ

Windowsが標準でZIPフォルダをサポートしているので、不要になりつつあるけど、それでも、サードパーティ圧縮解凍ツールの使用場面が見つかった。

## 場面

1. 客先で、ファイルサーバにつなげて、これ(40GBのZIPファイル、仮想環境)をダウンロードして使って・・・と
2. って、こちらは出先なので、ノートPC。しかも、空き利用域が 50GB程度
3. 念のため、こちらのノートPCのコピー先フォルダは、事前に NTFS 圧縮の設定をしておく
4. zipダウンロードして解凍するって方法だと、空き領域は倍必要だけど、ない
5. ~~ネットワークファイル、というかネットワークドライブでは、どうやら Windows標準の ZIP フォルダが使えない~~
 - Windowsのファイルサーバだとzipフォルダが使える。となるとあの客先はSMB互換のサーバだったんだろうか・・・となると、ファイルサーバでNTFS圧縮というわけにもいかないわけで、(容量がひっ迫しているという事だったので)zip圧縮は妥当な選択だったのかもしれない
6. ファイルサーバの ZIP ファイルを ZIP フォルダとして開いて、こちら側へコピーする、という方法は頓挫...orz
7. ということで、圧縮解凍ツールの保存先を、NTFS圧縮されたフォルダにして、ネットワークファイルから解凍

という事にあいなった。

と、実はこのアイデアは、この場面に出くわした後で気づいたもので(その時は、解凍済みのをコピーできるようにしてもらった)、まだ試していないけど、うまくいくのではないかと思っている。


## その他、関連

- [NTFS圧縮のススメ](https://qiita.com/tomoki0sanaki/items/e5da146512e34dc65df8)
- [可変ディスク使用のススメ](https://qiita.com/tomoki0sanaki/items/99ff8c55f4c996dd8892)
最近覚えたスプレッド構文の便利な使い方: Electron-IPC

こんにちわ。

Electronで`Main <=> Renderer`間IPCの引数に、ドラッグドロップで拾ったファイルパスを使いたくて色々試してたら、スッキリ爽快な書き方を発見したので備忘録。

# 使用例
```html:HTML
<div id="dnd">ここにファイルをドロップ</div>
```
こんな感じのHTMLにファイルをどんどん投げ込んでいきます。
ファイル操作は比較的重いので極力メインプロセスで処理させたいものです。

```javascript:Renderer
const ipcRenderer = require("electron").ipcRenderer;

// ドロップされたファイルのパスだけIPC送信
document.getElementById("dnd").addEventListener("drop", (event)=>{
    ipcRenderer.send("ch1", ...Array.from(event.dataTransfer.files).map(file=>file.path));
}
```
ドロップされたファイルオブジェクトが格納されている`event.dataTransfer.files`はArrayLikeなので、`Array.from()`で叩き直してArrayにします。
叩き直した後、`Array.map()`で各ファイルオブジェクトの`.path`プロパティだけ拾った、新しいArrayを生成します。
生成されたArrayは、スプレッド構文`...`によって引数へ展開されます。

```javascript:Main
const fs = require("fs");
const const ipcMain = require("electron").ipcMain;

ipcMain.on("ch1", (event, ...paths)=>{
    for(const path of paths){
        fs.readFileSync(path);
    }
});
```
IPCコールバックの第2引数以降は可変長(ドロップされた分だけ引数が増える)の為、スプレッド構文`...`で纏めて格納します。
格納された引数はArrayなので、`for-of`等で反復処理が可能です。

# まとめ
`Array <=> args`をたった`...`記述だけで相互に変換してくれるスプレッド構文めちゃ便利！
Cloud ComposerのdocからリンクされているAirflowのdocはバージョン差異があるので注意

# 注意点
[Cloud Composerのドキュメント](https://cloud.google.com/composer/docs/?hl=ja)からリンクされている[Airflowのドキュメント](https://airflow.incubator.apache.org/code.html)はバージョン差異があります。(2018/9/27時点)

Cloud ComposerのAirflowのバージョン -> 1.9
Airflowのドキュメントのバージョン -> 1.10

各オペレータの仕様が異なる場合があるので要注意です。

# 回避策
Airflow-1.9のソースをDLして各オペレータの仕様を確認しています。
https://github.com/apache/incubator-airflow/releases/tag/1.9.0

もっと良い方法があれば教えていただきたいです。

# バージョンの確認方法
## Cloud Composer側
Release Notesで確認できます。
https://cloud.google.com/composer/docs/release-notes

## Airflow側
Airflowのgithubリポジトリのリリースで確認できます。
https://github.com/apache/incubator-airflow/releases
可変ディスク使用のススメ

# 可変ディスク使用のススメ

客先でコピーする仮想環境が固定ディスクで大変だったので、ススメとこうと思う。

# 可変ディスクとは

VMWare の ESXi でも Workstation でも、仮想環境の作成時のディスクの設定で、出てくるもの。

- 固定ディスクとは、20GB のストレージと設定すると、実際のストレージに 20GB あらかじめ確保されるタイプ。
- 可変ディスクとは、20GB のストレージと設定しても、実際のストレージには使った分だけ確保されるタイプ。

昔は、ストレージと言えば HDD が主流で、HDD では連続で確保された(フラグメントされていない)領域の方が、ディスクI/O には有利で速くなる、という事でそれが既定となっているのだろうけど、今のストレージは SSD だし、あまり事前確保のメリットはないと思う。
一方で、仮想環境のコピーなどの際には、ストレージに使っていない部分も含めて確保されているため、コピーなどに時間がかかったり、ストレージの空き領域を圧迫したり(使っていないのに確保だけされていれば非効率)、いいところはないと思う。

# 可変ディスク設定の画面(VMWare ESXi)

![001.jpg](https://qiita-image-store.s3.amazonaws.com/0/182822/9d7ea0bb-4967-cb33-33d2-dc8d13544d08.jpeg)

**ThinProvision** を選択するようにしよう。

# 可変ディスク設定の画面(VMWare Workstation)

![002.jpg](https://qiita-image-store.s3.amazonaws.com/0/182822/0982f622-3d48-c4db-b3fd-b547126fe925.jpeg)

Workstationの場合は、既定で可変ディスクになっているようだ。(良いことだ)
**そのままにしておくこと、チェックしてはいけない**

ちなみに単一ファイルとか複数ファイルとかは、古いWindowsでは 1ファイルの上限が2GBだった名残りなので、特に古いWindowsがホストとか、仮想ディスクのファイルのバックアップ先が古いWindowsとかでない限り、**単一ファイル** 選択でよいと思うぞ。

# ディスクの最適化

ゲストOS上で、ファイルを消せば、可変ディスクがすぐさま小さくなるわけではないので、適時**ディスクの最適化**を実施して、ゲストOS上で使っていないけど可変ディスクで確保している部分を解放するとよいだろう。
特に、全体をコピーしたりする前にやっておくとよいと思う。

![003.jpg](https://qiita-image-store.s3.amazonaws.com/0/182822/b568a55e-923a-cea1-50c3-8b3b73147f30.jpeg)

# NTFS 圧縮との併用

これも便利だよ。仮想ディスクを NTFS 圧縮しておくと、大体半分ぐらいになるんではないかと、個人的な印象。

NTFS圧縮のススメは → [NTFS圧縮のススメ](https://qiita.com/tomoki0sanaki/items/e5da146512e34dc65df8)

# その他、関連

- [サードパーティ圧縮解凍ツールのススメ](https://qiita.com/tomoki0sanaki/items/327072a94b236d54a9e0)
スペースやカンマを入れる箇所に注意

コードレビューをしていただいている中で何度も指摘されているのでさすがに忘れないようにメモしておく

```
// NG：開きかっこの右、閉じかっこの左にはスペースを入れてはいけない
if ( $value == 3 ) {

// OK
if ($value == 3) {
```

```
// NG：カンマの左にスペースを入れてはいけない
explode(',' , $array);

// OK
explode(',', $array);
```

```
//NG：コメントを書く際には半角スペースを1つ入れる

// OK
```

```
// NG：関数を定義するときの開きかっこは改行する
public function test() {
    echo 'test';
}

// OK
public function test()
{
    echo 'test';
}
```

##追記
KEINOSさんのコメントを受けてphpcsを導入してみました。

```
$ phpcs --standard=PSR2 testfile.php                           

FILE: testfile.php
---------------------------------------------------------------------------------------------------------------------------------------------------
FOUND 64 ERRORS AND 17 WARNINGS AFFECTING 69 LINES
---------------------------------------------------------------------------------------------------------------------------------------------------
   1 | WARNING | [ ] A file should declare new symbols (classes, functions, constants, etc.) and cause no other side effects, or it should execute
     |         |     logic with side effects, but should not do both. The first symbol is defined on line 10 and the first side effect is on line
     |         |     2.
  10 | ERROR   | [ ] Each class must be in a namespace of at least one level (a top-level vendor name)
  10 | ERROR   | [x] Opening brace of a class must be on the line after the definition
  22 | ERROR   | [x] Spaces must be used for alignment; tabs are not allowed
  22 | ERROR   | [x] Whitespace found at end of line
  24 | ERROR   | [ ] Method name "RepRating::update_rating" is not in camel caps format
  28 | ERROR   | [x] Spaces must be used to indent lines; tabs are not allowed
  28 | ERROR   | [x] Expected 1 space(s) after SWITCH keyword; 0 found
  29 | ERROR   | [x] Spaces must be used to indent lines; tabs are not allowed
…etc
```
いっぱいエラーがあったおorz
Win10のVirtualBoxのマネージャーが起動しなくなった

# きっかけ
いつもVirtualBox上のCentOSで作業するのだけれど、ホストOSのWin10を起動してVirtualBoxのアイコンをダブルクリックしても画面が開かない。

# 状況を確認
タスクマネージャを見ると、VirtualBox Managerのプロセスは上がっている。
あと、VirtualBox Interfaceが立ち上がっている。（ネットワーク系のプロセスかな？？）

PCを再起動しても状況は変わらず。

# やってしまった悪手
最新のVirtualBoxを、アンインストールしないでインストール。
　→　中途半端にインストールできず。たぶんこれでネットワークドライバ消えた。

# 回復の兆し
これも悪手かもしれないけど、VirtualBox ManagerとVirtualBox Interfaceのプロセスをタスクマネージャで落として`c:\Program Files\Oracle\VirtualBox\VirtualBox.exe`を実行したらマネージャが起動。
→　しかし、ゲストOS立ち上がらず
どうやら、ホストオンリーアダプタがなくなってしまった。
じゃぁ追加すればいいんだろ？ということでネットワークアダプタの追加の操作をしてみると以下のエラー。

```
Could not find Host Interface Networking driver! Please reinstall.
```

# 直した方法
ホストオンリーアダプタはVirtualBoxの再インストールで回復するとのことで、結局アンインストール　→　最新版インストールで元に戻った。

元々あったゲストOSの状態はキープされるんだ。（アンインストールせずにインストールしたのはこれが心配だったから）

# 後々こんな情報も
似たように？ネットワークのところが壊れた人もいる様子。
どうやらVirtualBoxの再インストールまではいらないらしい。
https://qiita.com/tanishilove/items/aafcad7260c5acfee90c
学協会でslackは導入できるのか

ぜんぜん考えがまとまらなくてメモ、殴り書き。適宜修正、追記するかも。

◆
学協会の委員会に所属すると、対面の会議とかメーリングリストとかで議論することになる。対面はいいとして、メールベースの議論が多くなったり続いたりすると、メールボックスがしんどくなる。どうにかしたい→はやりのslackかしら...？


◆
とりあえず試験的にやってみる。


◆
ひとつの社内、組織内なら導入や意思疎通も比較的できそうなもんだが、
さまざまな大学、企業の人たちがいる。IT系企業でも客先とか取引先をslackに巻き込むという話もあるらしいので出来ないことはない...？

◆
メリットの説明がうまくできない。
自身が、まだ納得感を持ってないからだろうか。

◆
人に説明するのがめんどい→がんばろう。



参考　
絵でわかるSlackの使い方！第1回:そもそもどんなもの？メリットは？
https://jimon.info/series-slack-1st/


Qiita記事
Slackを導入して直面する疲れ（利用者視点）
https://qiita.com/Will_meaning/items/4e4e9e1876e7dd995574

Slack運用術〜Slackがない時どう仕事してたかもう思い出せない〜
https://qiita.com/crasae/items/efe2840577806b914f5d


追記　2018/09/28
どういう具合で導入されているのかはわからないが、twitterなんかを見てると、情報系の学会はやはりslack導入しているような雰囲気がある。
建築系の編集委員会でslackを導入しているらしき投稿もあった。

研究室単位では、やってるところはやってる、といった感じ。
【Java】文字列の比較法や正規表現を用いた比較法

#はじめに
文字列を比較する時は、int型のように単純に`(int1 == int2)`では比較ができません。
文字列の比較をする時には、比較演算子ではなく、文字列メソッドの１つである**equals()**を使います。
##文字列の比較 - equals()
**equals()**の使い方は極めて簡単で、引数に比較したい文字列を入れるだけです。
例えば以下のように使います。

```java
if(String1.equals(String2)){
   // 実行したい命令
}
```
if文の条件を決める時には、()内に`String1.equals(String2)`を入れればOKです。
#おまけ
equals()メソッドを学んだついでに、正規表現やその比較法、文字列の取り出し方について紹介します。
##正規表現とは？
正規表現とは、パターン化された文字列を表現したい時に用いる書き方です。
例えば、郵便番号やクレジットカード番号を表現する時に使います。

詳しい使い方については、[正規表現の基本](https://qiita.com/sea_ship/items/7c8811b5cf37d700adc4)にわかりやすく書いてあるので、確認してみてください。
##正規表現の比較 - matches()
正規表現を用いた変数を比較する場合は、`matches()`を使います。

```java
if(String1.matches(String2)){
   // 実行したい命令
}
```
使い方は`equals()`とあまり変わりません。
##文字列を取り出す - substring()
特定の文字列を取り出したい場合は、`substring()`を使います。
第１引数には文字列の始まりである開始インデックスを、第２引数には文字列の終わりである終了インデックスに+1した数字を入れます。

```java
String str = "AppleLemonApple";
String strget = str.substring(5,10); // Lemon
```
この例では、`Lemon`という文字列を取り出しています。Javaではインデックスが0から始まるので、Lは５番目となります。
openssl

# command

## hash
### sha256
- calculate that data's sha256 value.

```
openssl sha256 <file_path>
```

## certificate
### check certificate information

- If SNI(Server Name Indication) is used, '-servername' option is needed. If not, <b>routines:SSL23_GET_SERVER_HELLO:tlsv1 alert internal error</b> error might be appeared.

```
_domain='target domain name'
openssl s_client -connect ${_domain}:443 -showcerts -servername ${_domain}
```

### check certificate and key pair

```
# key
openssl rsa -noout -modulus -in <key_file> | openssl md5

# certificate
openssl x509 -noout -modulus -in <cert_file> | openssl md5
```

### show certificate contents

- cer extension

```
openssl x509 -inform der -noout -text -in <cerficiate>.cer
```

### download remote host's server certificate chain
- showcerts: display the whole server certificate chain

```
_domain='www.feistyduck.com'
echo | openssl s_client -showcerts -connect ${_domain}:443  -servername ${_domain} 2>&1 | sed -n '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ${_domain}
```

### show bundled certificate chain

```
openssl crl2pkcs7 -nocrl -certfile <bundled_file> | openssl pkcs7 -print_certs -text -noout
```

## random
- generate 48 random characters

```
openssl rand -base64 48
```

## performance
- check openssl performance

```
openssl speed -multi 2 aes
```
Node.jsでGravatarの画像を取得するメモ


Gravatarの画像をNode.jsから取得します。 事前に利用するメールアドレスで[gravatarに登録](https://ja.gravatar.com/)してある前提です。

* step1: emailハッシュを作成
* step2: URLを作成

## step1: email ハッシュ

md5でemailハッシュを作成します。外部依存モジュール使わないで出来ますね。

>参考:  https://ja.gravatar.com/site/implement/hash/

```js
'use strict'

const crypto = require('crypto')

//md5ハッシュを作る関数を作成
const md5hex = str => crypto.createHash('md5').update(str, 'binary').digest('hex')

const mail = 'hogehoge@hoge.com' //ここにメールアドレス

console.log(`email hash: ` + md5hex(mail));
//email hash: ca0740a1455580936ff1bdc634fb8e2f
```

## step2: URLを作成

```
https://www.gravatar.com/avatar/ + ハッシュ
```

という形式でアクセスするとアイコンが取得できます。

例: `https://www.gravatar.com/avatar/dae1d4cc4599a65a5da6e1a1f9d96f05`

![](https://www.gravatar.com/avatar/dae1d4cc4599a65a5da6e1a1f9d96f05)

## おまけ ?s=xxxでサイズ変更

* s=10

`https://www.gravatar.com/avatar/dae1d4cc4599a65a5da6e1a1f9d96f05?s=10`
![](https://www.gravatar.com/avatar/dae1d4cc4599a65a5da6e1a1f9d96f05?s=10)

* s=50

![](https://www.gravatar.com/avatar/dae1d4cc4599a65a5da6e1a1f9d96f05?s=50)
`https://www.gravatar.com/avatar/dae1d4cc4599a65a5da6e1a1f9d96f05?s=50`

* s=100

![](https://www.gravatar.com/avatar/dae1d4cc4599a65a5da6e1a1f9d96f05?s=100)
`https://www.gravatar.com/avatar/dae1d4cc4599a65a5da6e1a1f9d96f05?s=100`

* s=200

![](https://www.gravatar.com/avatar/dae1d4cc4599a65a5da6e1a1f9d96f05?s=200)
`https://www.gravatar.com/avatar/dae1d4cc4599a65a5da6e1a1f9d96f05?s=200`
Node初日　生粋のメモ

Node.jsはV8エンジンでJavascript動くランタイムで
V8はC++で書かれたJavascriptのオープンソースエンジンでJavascriptをマシン語に変換するものです(ドヤ

実行は　node ファイル名　で実行できる。

Node自体にライブラリが存在していて
fsはファイルの読み書きを行う
const fs = require(fs);

appendFile()を使うと指定したファイルに入力した文字を入れる事ができる。
もしファイルがない場合は自動的に作成される。

fs.appendFile('greeting.txt,'Hello World!');


fs.appendFileSync（）はappendFile()と同じだけど、こっちは同期的に追加するらしい。
こちらもファイルがなければ自動的に作成される。

Nodeのライブラリの中にはosってのもある、
多分os関係で色々出し入れ出来る。たぶん。
const os = require(os);

os.userInfo()これを使うとものすごいでかいオブジェクトを持ってきてその中の色々を使える。

const user = os.userInfo();
console.log(user.userName);みたいな感じ。

require()は他のファイルを参照することも出来る。
require('./file2');

module.exportで他のファイルにexport出来る。

作成したディレクトリで　npm init　を打ち込むとそのディレクトリ自体をnpmで管理できる。
色々質問されるけど基本的には適当にしてていいみたい。
終了するとその質問事項が入ってるjsonファイルが作成される。



lodashとは便利メソッド詰め合わせパッケージ

このURLでドキュメントを見ることができる。
https://lodash.com/docs/4.17.10

npm install パッケージ名　--s
で欲しいパッケージをダウンロードしてくる事が可能。

そしてこんな感じで代入しておく。

const _ = require(lodash);

_.isString()を使うと文字か文字でないかを判別できる。

_.uniq()を使うと配列の中で被っている要素も１回しか表示されない。

nodemonというのがある。
nodemonを使えばいちいちファイルを実行しなくても、ファイルの結果をリアルタイムにコマンドラインに表示してくれる。

nodemonは npm install nodemon -g　で　インストールできるが、自分はできなかったので、
sudo npm install nodemon -g　でインストールする事ができた。

installした後は nodemon ファイル名　でnodemonでファイルを立ち上げる事ができる。
ここからはファイルを変更するだけで自動的に値が更新されてめちゃくちゃ便利！！！
なんかローカル開発環境でしか使わないっぽい。

porcess.argv[]で入力を受け取る事ができる。
[0]node　[1]は実行ファイル　[2]はコマンドラインを指すらしい。

すなわち const command = process.argv[2]でコマンドラインからの入力を受け取る事ができる。
この値をif文で分岐して処理を振り分ける事が可能。
NTFS圧縮のススメ

# NTFS 圧縮のススメ(まとめ)

Windowsでディスクの空き領域に不安がでてきたら、NTFS圧縮は一番最初に試す価値あり

# NTFS 圧縮のススメ

Windowsを使用している場合、ファイルシステムは NTFS だと思う。

NTFS には、標準でNTFS圧縮と呼ばれているデータ圧縮機構が組み込まれている。

大体、半分ぐらいのサイズになる印象が個人的にはある。

これを活用すれば、ディスクの空き容量が少なくなったファイルサーバのファイルを緊急にZIP圧縮するよりも便利だと思う。

ZIPファイルにまとめるよりも、NTFS標準機能なので、非圧縮のファイルとまったく同様に扱う事が可能だ。

老婆心までに、圧縮ファイル(zipとかjpeg)とかにはあまり効果がないぞ。

~~例えば、ZIPフォルダは、ネットワークドライブでは有効に機能しないと思うが~~(Windowsのファイルサーバでは開いたので、有効に機能しなかったあのお客様の環境はWindows互換サーバだったのだろうか!?)、そういう点でも NTFS 圧縮は便利だ。

ただし、サイズ制限を行うクォータ機能では、圧縮前サイズで計算されるので、利用者としてクォータ機能が働いたのでNTFS圧縮でサイズ制限を回避する。ってわけにはいかない。

また、ファイルサーバ上のNTFS圧縮されたファイルを開くと、ファイルサーバ上で伸張されて、それがネットワークを流れて、やってくるのでネットワーク帯域は変化しない事にも注意が必要だろう。

個人的な印象では、フラグメントが通常より多く発生する印象なんだが、HDD から SSD が主流になりつつあるので、より重要なポイントではないかもしれない。

ついでに、圧縮された分だけファイルI/Oが低減するような気がするのだが、計測していないので、よくわからない。

最後に NTFS 暗号とNTFS圧縮は同一ファイル/フォルダに同時に設定できないので注意。


## NTFS 圧縮の使い方。

ファイル/フォルダのプロパティで、圧縮を有効にするだけだ。

![001.jpg](https://qiita-image-store.s3.amazonaws.com/0/182822/37ca8a57-0685-b703-d3b9-ae936a7b9f58.jpeg)

すると、既定では、こんな感じに青くなる。

![002.jpg](https://qiita-image-store.s3.amazonaws.com/0/182822/64b14c42-84c1-68c4-e7b5-e61cd17a6680.jpeg)

ちなみに緑色だと、NTFS暗号されている。

既定では、色が付くようになっている

![003.jpg](https://qiita-image-store.s3.amazonaws.com/0/182822/525dfa24-5678-c4cc-e94d-4a55fa1962ce.jpeg)

## NTFS 圧縮と WinAPI

GetFileSize() 関数で、データサイズ(伸張後)が返る。
GetCompressedFileSize() 関数で、圧縮されたサイズが返る。

昔、COM ラッパを作ったので、ActiveScript 系統からでもアクセスできると思う。
[NTFS 関連の API の COM ラッパ](http://rocketeer.dip.jp/sanaki/free/free91.htm)

## NTFS 圧縮と MS-SQL Server

MS-SQL Server のデータファイルを NTFS 圧縮フォルダに入れてはいけないと昔どこかの雑誌の記事で読んだけど、失念した。
ので、この点は注意。


## その他、関連

- [可変ディスク使用のススメ](https://qiita.com/tomoki0sanaki/items/99ff8c55f4c996dd8892)
- [サードパーティ圧縮解凍ツールのススメ](https://qiita.com/tomoki0sanaki/items/327072a94b236d54a9e0)
- [NTFS のスパースとか圧縮とかと、実際のディスクサイズとか](https://qiita.com/tomoki0sanaki/items/ac640846762a9c6f0cf0)
CreateJsでリッチな画面遷移を作ろうとしてみた話

#はじめに 
動きのあるリッチな画面に憧れを抱き、cnavasでアニメーションを実現できる、CreateJsなるものを見つけ、どんなものだろうかと使ってみた。

# CreateJsとは
本家→https://createjs.com/
使い方は、[こちら](https://ics.media/tutorial-createjs/index.html)の入門サイトがサンプルも豊富。

Create.jsを使うと、HTML5のCanvas技術を用いてリッチな描画表現ができます。
Create.jsの中には以下のような4つのライブラリが含まれています。
>・EaselJS : HTML5 Canvasでの制作を扱うためのJSライブラリ。キャンバス(画布)に対するイーゼル(画架)を意図した名前になっています。
・TweenJS : JavaScriptのトゥイーンエンジンです。モーション制作に役立てることができます。
・SoundJS : サウンドを利用するためのJSライブラリ。簡単にクロスブラウザでの音声再生が実現できます。
・PreloadJS : 素材（画像、音声、JS、データ）を先読みできるJSライブラリ。

#作ろうとしたもの
・画面遷移をもっときれいに見せたい！
　⇒本をめくるような感じとか

#動かしてみた

![デモ](https://qiita-image-store.s3.amazonaws.com/0/153290/a32262bf-75f2-6593-4a79-f726c92dc28b.gif)

```javascript
// EaselJS系の読み込み
import { Shape, Stage } from '@createjs/easeljs/dist/easeljs.module';
// TweenJS系の読み込み
import { Tween } from '@createjs/tweenjs/dist/tweenjs.module';

const stage = new Stage('myCanvas');

const circle = new Shape();
circle.graphics.beginFill('DarkRed').drawCircle(0, 0, 50);
stage.addChild(circle);

circle.x = 300;
circle.y = 200;

Tween.get(circle, { loop: true })
    .wait(300)
    .to({ x: 740, y: 400, scale: 2 }, 700)
    .to({ x: 400, y: 0, scale: 1.4 }, 1200)
    .to({ x: 500, y: 300, scale: 3 }, 1200)
    .to({ x: 300, y: 200, scale: 1 }, 700);

update();

// 毎フレームステージを自動更新する
function update() {
    stage.update();
    requestAnimationFrame(() => update());
}
```
このくらいのお手軽に、アニメーションを表現できた

#結論
create.jsで実現しようとすると、自分で物理演算を考えなければいけなったので、難易度が高いことが分かった
探してみたらすでに良さそうなライブラリがあった　→　turn.js

## turnjs
簡単に本をめくるようなUIが実現できるライブラリ

例えばこんな実装↓

```html
<!doctype html>

<head>
</head>

<body>
<!-- ↓↓↓flipbookがturn.jsを使って、本として表示する部分↓↓↓ -->
    <div id="flipbook">
        <div style="background-color: #FDD17E"></div>
        <div style="background-image:url(pages/animal2.jpg);"></div>
        <div>
            <canvas id="myCanvas" width="960" height="540"></canvas>
        </div>
        <div style="background-image:url(pages/animal3.jpg);"></div>
        <div style="background-image:url(pages/animal4.jpg);"></div>
        <div style="background-image:url(pages/animal5.jpg);"></div>
    </div>
<!-- ↑↑↑flipbookがturn.jsを使って、本として表示する部分↑↑↑ -->

    <script type="text/javascript" src="lib/jquery.min.1.7.js"></script>!

    <script type="text/javascript" src="lib/turn.min.js"></script>
    <link rel="stylesheet" href="style.css">
    <script src="bundle.js" defer></script>

<!-- ↓↓↓実際にDOMに適用している部分↓↓↓ -->
    <script>
        $(function () {
            $('#flipbook').turn({
                width: 996,
                height: 646,
                autoCenter: true
            });
        });
    </script>
<!-- ↑↑↑実際にDOMに適用している部分↑↑↑ -->

</body>

</html>
```
![book.gif](https://qiita-image-store.s3.amazonaws.com/0/153290/6f3e69c7-b632-2178-1f38-656c35dcd342.gif)

Create.jsで先ほど作成したボールのアニメーションも、本の中で動かすことができた！（動く絵本とか作れそう・・・）

#まとめ
実現したいことがある程度決まっているのならば、探してみると意外とライブラリはすでに作られていることもあるため、
探してみると、実は楽に実現できることもあると感じた

#参照
[Create.js(本家)](https://createjs.com/)
[CreateJS入門サイト](https://ics.media/tutorial-createjs/index.html)
[turn.js(本家)](http://www.turnjs.com/)
Hibernate Validator の使い方メモ

自分用の覚書のつもりで書いています。
書きかけです。

【:frowning2: はまったポイント：パラメータの順番】
------
```
public String confirm(HttpServletRequest request, Model model
		, @Validated @ModelAttribute("user") User user
		, @RequestParam("mode") String mode
		, BindingResult result) {
```
だと結果が、
![Error画面.jpg](https://qiita-image-store.s3.amazonaws.com/0/295558/dad63b33-4847-5cfa-27da-9ed1f77d5bec.jpeg)
になりました。
で、以下のように、
@Validated をつけたパラメータと、BindingResult を並べる形に、
パラメータの並び順を変更しました。

```
public String confirm(HttpServletRequest request, Model model
		, @RequestParam("mode") String mode
		, @Validated @ModelAttribute("user") User user
		, BindingResult result) {
```
これで成功しました。


【参考になるサイト】
------
制約条件の使い方がわかりやすい
:point_right_tone3: <a href="https://access.redhat.com/documentation/ja-jp/jboss_enterprise_application_platform/5/html-single/hibernate_validator_reference_guide/index">VALIDATOR リファレンスガイド</a>

メッセージのデフォルト値はここで見られるっぽい
:point_right_tone3: [Git > ValidationMessages.properties](https://github.com/hibernate/hibernate-validator/blob/master/engine/src/main/resources/org/hibernate/validator/ValidationMessages.properties)
【VSCode】エディタ、サイドバー、ターミナル間のフォーカスのショートカットを設定する

これまでエディタやターミナル間の切り替えをクリックで行っていたのですが、少しストレスに感じていました。そこで、キーバインドを設定してみたところかなり快適になったのでご紹介します。

今回設定したものはこちらです。僕はVimmerなのでVimっぽいショートカットにしました。

|キーバインド|動作|
|---|---|
|Ctl + h|エディタ→サイドバー|
|Ctl + j|エディタ→ターミナル|
|Ctl + l|サイドバー→エディタ|
|Ctl + k|ターミナル→エディタ|

## 環境

- Visual Studio Code 1.27.2
- macOS Sierra

## 手順

`Code > Preferences > Keyboard Shortcuts`をクリック

<img width="707" alt="Screen Shot 2018-09-27 at 10.27.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/261245/c31b9be9-a06b-eaba-f46f-71bae8d59114.png">

「keybindings.json」をクリックして設定ファイルを開きます

<img width="740" alt="Screen Shot 2018-09-27 at 10.04.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/261245/e46cdc8a-7cff-4aed-6a04-4a5e220c47f5.png">


このように設定します。「key」はお好みで設定してみてください。

```json:keybindings.json
[
  {
    "key": "ctrl+h",
    "command": "workbench.action.focusSideBar",
    "when": "editorTextFocus"
  },
  {
    "key": "ctrl+j",
    "command": "workbench.action.terminal.focus",
    "when": "editorTextFocus"
  },
  {
    "key": "ctrl+l",
    "command": "workbench.action.focusFirstEditorGroup",
    "when": "filesExplorerFocus"
  },
  {
      "key": "ctrl+k",
      "command": "workbench.action.focusFirstEditorGroup",
      "when": "terminalFocus"
  }
]
```

よいVSCodeライフを！

参考にさせていただいた記事
https://qiita.com/rai_suta/items/05e69f0b9065989b19c1
写経「nginx + uwsgi でアプリケーションをサブディレクトリで動かす設定」


[nginx \+ uwsgi でアプリケーションをサブディレクトリで動かす設定 \- Qiita](https://qiita.com/methane/items/e0949a37c112eedf2b74)の写経


`/`にアクセスが来たら`/abort`にリダイレクトする簡単なWebアプリケーションを作ったとする。
一つのサーバーの`/`を占有するのは勿体無いのでディレクトリを切ってその下で動かしたい。

再配置可能プログラム（リロケータブル）なものにしたいのでアプリ側は上位パスをハードコードしないようにする。


```py:app.py
from flask import Flask, redirect, url_for

app = Flask(__name__)

@app.route('/')
def index():
    return redirect(url_for('about'))

@app.route('/about')
def about():
    return 'The about page'

if __name__ == '__main__':
    app.run()
```

```ini:subdir.ini
[uwsgi]
module = app:app
callable = app
home = %v/venv
socket = /var/run/uwsgi/subdir.sock
chmod-socket = 666
http-socket = :5000 # これはデバッグ用
```

```nginx:/etc/nginx/default.d/subdir.conf
location ~ ^/subdir/(.*)$ {
        include uwsgi_params;
        uwsgi_pass unix:/var/run/uwsgi/subdir.sock;
        uwsgi_param SCRIPT_NAME /subdir;
        uwsgi_param PATH_INFO /$1;
}
```

```bash
// これは管理者で
# mkdir -m 777/var/run/uwsgi

// ここからは一般ユーザーで
$ python36 -m venv venv
$ source venv/bin/activate
$ pip install flask uwsgi
$ uwsgi --ini subdir.ini

// リクエストすると生きている
$ curl localhost:5000 -I
HTTP/1.1 302 FOUND
Content-Type: text/html; charset=utf-8
Content-Length: 219
Location: http://localhost:5000/about

// nginxの設定によってルーティングが効いている
$ curl localhost/subdir/ -I
HTTP/1.1 302 FOUND
Content-Type: text/html; charset=utf-8
Content-Length: 233
Connection: keep-alive
Location: http://localhost/subdir/about　// subdir以下にリダイレクトされる
```



# 追加

```html:layout.html

当然ながら、パスが変わるのでcssやjsのパスはjinja2でurl_for()を使っておく方がよい。
具体的には

<script src="/static/js/bootstrap.min.js"></script>
ではなく
<script src="{{url_for('static', filename='js/bootstrap.min.js')}}"></script>
としておかないと追従しない
```


# 参考

[メモ帳 \| DockerizedしたFlaskをサブディレクトリで運用する](https://blog.sky-net.pw/article/82)
コードでやる方法。nginx側とflask側両方の小細工が必要。

[アプリケーションの発送 \- Flask 1\.0\.2ドキュメント](http://flask.pocoo.org/docs/1.0/patterns/appdispatch/#app-dispatch)
Dispatch by Pathがそれらしいが使い方がわからなかった

[djangoとuwsgiとnginxを使って、複数のアプリを公開する時の話 \- Qiita](https://qiita.com/murabo/items/f367f102a2c467588f16)

[flask\_script\_name\.md](https://gist.github.com/Larivact/1ee3bad0e53b2e2c4e40)

[nginx \+ uwsgi \+ flask の連携でつまずく \- 達人ドヤリストへの道](http://tatsudoya.blog.fc2.com/blog-entry-283.html)
この人と同じところでつまづいた。Blueprintという手もあるがpythonだけのアプリとは限らないのでnginxでやるのがよさげ

[Nginx support — uWSGI 2\.0 documentation](https://uwsgi-docs.readthedocs.io/en/latest/Nginx.html#hosting-multiple-apps-in-the-same-process-aka-managing-script-name-and-path-info)

[Nginx\+uwsgi\+Bottle\.pyで環境変数を使いたい\|ご注文はスタートアップですか？](https://blog.seekgeeks.net/2018/05/use-environment-variables-nginx.html)
これを使えばサブディレクトリパスがアプリ側で取れそう

[Mounting flask under subpath through nginx · Issue \#527 · zalando/connexion](https://github.com/zalando/connexion/issues/527)
みんな同じ悩みを持つ
vue-cliを 使って Vue.js を簡単に触ってみる

## vue-cliをインストール

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

## プロジェクトを作成

```
$ vue init webpack my-project
```

↑色々質問されますが、全て「Enter」ボタンを押下し
以下のコマンドを打つ

```
$ cd my-project
$ npm run dev
```

## ブラウザで確認

http://localhost:8080/ へアクセスするとサンプルが表示されます。

## ビルド

下記コマンドを押下したら、
./dist というフォルダが作られその中に
実際に動くソース（./dist/index.html）が作られます。

```
$ npm run build
```
変更を一時的に退避する、git stash


Gitを使う場合、修正はトピックブランチを作成して作業する。だいたい機能追加とかバグ修正とかの単位でブランチを作って作業していると思います。もとになっているブランチに変更が入ったり、別の作業を優先して実施しなければならない場合、現在の修正内容を保存しておくことが出来ます。

## 修正を退避する
```bash
git stash
```

## 退避した内容の一覧を見る
```bash
git stash list
```

## 変更内容を表示する
```bash
git stash show stash@{n}
```
nは、listで表示した番号を入れる

## 退避した内容を元に戻す
```bash
git stash pop
```
list で表示される一番最後にstashした内容を元に戻す

## stash名を指定して、退避した内容を元に戻す
```bash
git stash pop  stash@{n}
```
WSLが立ち上がらない⁉

## 現象
WSL（Windows Subsystem for Linux）のLinuxターミナルが立ち上がらない！

```
Installing, this may take a few minutes...
WslRegisterDistribution failed with error: 0x800703fa
Error: 0x800703fa ????????????????????? ???????????????????????

Press any key to continue...
```

キーを押すと、ターミナルが閉じてしまいます。

## 対策
Windowsを再起動すると直る、と各所に書かれています。（[ここ](https://va2577.github.io/post/175/)や[ここ](https://qiita.com/rog-works/items/a319a7eee7220a183a4f)）

また、[ここ](https://github.com/Microsoft/WSL/issues/2576)には、Windowsの再起動にまじって、「**LXSSマネージャーサービスを再起動する**」という手順も挙げられています。

「サービス」で見てみると、確かに実行していませんでした。実行すると、無事、ターミナルが立ち上がるようになりました。

![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/293884/5b8bc5ba-a8da-b6e6-9ab9-411db56a68e8.png)

## 補足
ちなみに、「スタートアップの種類」が「手動」になっていますが、通常はLinuxターミナルを立ち上げるときに実行されるようです。

いったん正常に立ち上がるようになった後、サービスを停止しても、再度ターミナルを立ち上げれば、サービスも実行されます。Windowsを再起動してもOKです。なんらかの特殊事情で、LXSSマネージャーサービスが一時的に実行されなかったような感じですね。
[memo] pip install eigency でこけた時の対処


pkg_resources.VersionConflictが発生していた．

>
-i, --index-url <url>
Base URL of Python Package Index (default https://pypi.org/simple). This should point to a repository compliant with PEP 503 (the simple repository API) or a local directory laid out in the same format.

```
$> pip install --upgrade -I setuptools 
```

で解決．
Windowsでselenium

Windows環境でseleniumを使えるようにします

#1. seleniumをインストールします
- python 3.x（3.6など）が使える仮想環境を用意します
- `pip install selenium`でseleniumをインストールします

#2. ChromeDriverを準備します
- [ChromeDriver - WebDriver for Chrome](https://sites.google.com/a/chromium.org/chromedriver/home) から [Getting Started](https://sites.google.com/a/chromium.org/chromedriver/getting-started)　→ [Downloads](https://sites.google.com/a/chromium.org/chromedriver/downloads)へアクセスし、最新のChromeDriverのダウンロードページ（当稿執筆時点で2.42なので[Index of /2.42/](https://chromedriver.storage.googleapis.com/index.html?path=2.42/)へアクセスして、ChromeDriverをダウンロードします
- ダウンロードしたChromeDriverを適当なフォルダに置き、PATH環境変数でそのフォルダを指します。PATH環境変数の設定は、Windowsの検索で「システム環境変数」などを検索すると「システムのプロパティ」が見つかります

#3. seleniumを試してみます

- 下記のようなコードを試してみます

```python:seleniumのテスト
# coding:utf-8
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait


if __name__ == "__main__":
    driver = webdriver.Chrome()

    # page 1
    driver.get('https://google.co.jp')
    search_text_field = driver.find_element_by_id('lst-ib')
    search_text_field.send_keys('りんご')
    button = driver.find_element_by_name('btnK')
    button.click()
    button.click()
```

-検索結果が表示されることを確認します
スクレイピングの学習 Python3系 その5

# 前回の内容
[スクレイピングの学習 Python3系 その4](https://qiita.com/mizssy07/items/c156cc9aa3aa33e2e9bc)

# 改善点
- 重複している記事を取得しないようにする
([参考URL](https://note.nkmk.me/python-pandas-duplicated-drop-duplicates/))


# 手順
- データフレームの中から記事名が重複している行を削除

# 追加したコード
```python:
df.drop_duplicates(subset='name', inplace=True)
```

# 補足
`subset`は列名、`inplace`は元のデータ保持。指定しないと元のデータフレームが保持されてしまうみたい。仕様要確認。
`inplace=True`はクォーテーションで囲むとエラーになる


# 次回への課題
- ~~CSVでダウンロード~~
- 1時間に1回取得などの動き
- ~~重複する内容を取得しないようにする~~
- ~~次ページ以降の取得~~
- 元リンクを取得
- ~~ローカル環境で動かす~~
python

# general
## separate config file from script

- read mongo_url value from env.cfg file.
- https://www.reddit.com/r/learnpython/comments/264ffw/what_is_the_pythonic_way_of_storing_credentials/

**env.cfg**

```
[coordinate]
mongo_url=xxxxxxxx
```

**script.py**

```
import ConfigParser
config = ConfigParser.RawConfigParser()
config.read('env.cfg')

mongo_url=config.get('coordinate','mongo_url')
```


# numpy
- dtype: Data-type of the array's elements
- ndim: Number of array dimensions
- shape: Tuple of array dimensions
まだPythonista3使ってないの？ースクレイピング編ー

今回は簡単めなスクレイピングについてやりたいと思います。

# 事前準備

事前準備としてStaShのインストールが必要です。
StaShはPythonista3の中で使えるシェルです。
Pythonista3の基本操作とStaShのインストールについてはこちらを参考にしてください。
[まだPythonista3使ってないの？ー基本操作・StaShインストール編ー](https://qiita.com/n_oshiumi/items/4a647f2c8a3c209fd87b)


# beautiful soupをpythonista3にインストール

StaShで、beautiful soupをインストールしていきます


```
pip install BeautifulSoup
```

# コードを書いていく

[ココナラのリクエストボード](https://coconala.com/requests)のタイトルと依頼内容を取得したいと思います。

※ココナラはCtoCのお仕事依頼のサービスです。リクエストボードとは、〇〇をしたいんですけど、誰か仕事引き受けてくれませんか？っていうリクエストをするところです。

## とりあえず、やってみた

最初に書いてみたコードはこんな感じです。

<img width="320" alt="image.png" src="https://qiita-image-store.s3.amazonaws.com/0/238739/762b7a81-5868-5289-fc01-de72c0891172.png">

コピペしたい方はこちら

```python3
import numpy as np
import urllib. request from bs4
import Beautiful Soup
import matplotlib.pyplot as plt import re

target_url = 'https://coconala.com/ smartphone/requests'
html = urllib. request.urlopen(target_url).read()
root = Beautiful Soup(html, 'html5lib')

titles = root.find_all(class_=' requestdetail-title')
for title in titles:
    print(title.string)
```

出力結果はこちら

（なぜか曲の作成が2つあるけど、まあいいや・・・）
<img width="320" alt="image.png" src="https://qiita-image-store.s3.amazonaws.com/0/238739/fc3f9158-0f8c-6b56-9c98-26632c247084.png">

このときのリクエストボードの様子がこちら

<img width="320" alt="image.png" src="https://qiita-image-store.s3.amazonaws.com/0/238739/ac4de88d-ad74-3b15-4cd8-049e2fa6f3d9.png">


# もう少しだけ頑張ってみた

タイトルと内容を取得します。

<img width="320" alt="image.png" src="https://qiita-image-store.s3.amazonaws.com/0/238739/4ff05fed-7cf4-ed19-d8e3-35ff254663d7.png">


コピペしたい方はこちらのコードを参考にしてください。

```python3
import numpy as np
import urllib.request
from bs4 import BeautifulSoup
import matplotlib.pyplot as plt
import re


target_url = 'https://coconala.com/smartphone/requests'
html = urllib.request.urlopen(target_url).read()
root = BeautifulSoup(html, 'html5lib')

requests = root.find_all(class_='request')

for request in requests:
	title = request.find(class_='request-detail-title').string
	content = request.find(class_='request-detail-content').string
	print('【リクエスト】\n' + title + '\n' + content + '\n\n\n\n')
```

出力結果はこんな感じ
なぜか空白があるけどそれは置いといて・・・。

<img width="320" alt="image.png" src="https://qiita-image-store.s3.amazonaws.com/0/238739/e02fb07c-3dd7-2d51-dbdd-0480390b27f0.png">


# おわりに

実はあんまりpython勉強したことがなくてこれからなんですけど、スマホでちょっとしたスキマ時間にできるのでおすすめです。

他のpythonista3についての記事はこちら

[まだPythonista3使ってないの？ー基本操作・StaShインストール編ー](https://qiita.com/n_oshiumi/items/4a647f2c8a3c209fd87b)


※書いたら随時更新していきます