OmniAICreator/Qiita-1.07M huggingface dataset:
BeanStalk アプリケーションライフサイクル, アプリケーションバンドルについて

https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/applications-lifecycle.html

### アプリケーションバージョンライフサイクルの設定
- Elastic Beanstalk は、新しいアプリケーションバージョンを作成するたびにアプリケーションのライフサイクルポリシーを適用し、ライフサイクルポリシーが適用されるたびに、最大 100 個のバージョンを削除
- デフォルトでは、Elastic Beanstalk はデータの損失を防ぐため、アプリケーションバージョンのソースバンドルを Amazon S3 に残します。ソースバンドルを削除すると、領域を節約できます。


### アプリケーションバンドル
ソースバンドルの要件

- 単一の ZIP ファイルまたは WAR ファイルで構成される (WAR ファイル内に複数の ZIP ファイルを含めることが可能)

- 512 MB 以下

- 親フォルダまたは最上位ディレクトリを含まない（サブディレクトリを除く）
Golangでhttp通信をやってみる

[Link-1]:https://qiita.com/melty_go/items/c977ba594efcffc8b567

[Pre-1]:https://qiita.com/zasshyu6/items/c85de49a7265c65945a3

[Golang-1]:https://golang.org/
[Golang-2]:https://golang.org/pkg/net/http/

[JSON-1]:http://www.jsontest.com/

#はじめに
`Golang`にはまったときに`Codewars`で遊んでました。
楽しかったのですが、そのあと`Swift`や`C#`で`http`通信やったのでせっかくなので`Golang`でもやってみようかと思います。

##開発環境
 - `Windows 10 Home 64bit`
 - `Visual Studio code 1.41.1`
 - `go version go1.13.6 windows/amd64`

#開発環境構築
開発環境の構築は以下の記事を参考にさせていただきました。
本当につまるところなく動いたのですごいなぁと思います。

>[VSCodeでGo言語の開発環境を構築する][Link-1]

#`Http`通信してみよう
[前回の記事][pre-1]で`Swift`でやってみたサイトにアクセスしてみます。

##Packegeを調べる
[公式のドキュメント][Golang-1]が優秀ですね。
ちゃんと英語版で読みましょう(助けてGoogle翻訳先生!)

>[Package http][Golang-2]

`https`を使い場合は、`Transport`を設定する必要あるようです。
また、`Go 1.6`以降は`HTTP/2`に対応しているようですね。

#やってみよう
試したコードはこちらになります。

```main.go

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
)

func main() {
	url := "http://md5.jsontest.com/?text="
	url += "examble"
	resp, err := http.Get(url)
	if err != nil {
		fmt.Println("handle error")
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	fmt.Println(string(body))
}

```

[このサイト][json-1]の`webAPI`なのかな？にアクセスしてテキストのMD5を出してくれるそうです。
結果は`Println`で出力しています。`string`に変換してあげないと`Rune`のリストが出力されるので全くわかりません。

#最後に
久しぶりに`Golang`使いましたがやはり楽しいですね。
本当は`M5stack`で`webAPI`使って`Twitter`にアクセスしたりしてみたかったのですが、どうやら`HTTPS`のライブラリで証明書を更新しないで読み込むので中間サーバー傍受ができるとかなんとか書いてたので今停滞中です・・・
とりあえずマイコンだろうが`Golang`だろうがライブラリの使い方次第なのでまずは`Golang`で使えるようにしようかなと思います。
iOS13 SceneDelegateが導入され、Push遷移につまづいた時の解決策

# はじめに

久々にアプリを０から作り始めたところ、何やらSceneDelegate.swiftが自動生成され、AppDelegateのライフサイクル関数群が移動したことにより、AppDelegateがすっきりした印象を受けた。

開発し初め早々につまづいたのですが、Main画面(Main.Stroryboard)から **Push遷移** ができない事件が発生...
普段つまづくことのない部分のため問題解決に時間がかかってしまいましたので、
もし同じようなことでつまづいていましたら、参考にしていただけたらと思います。


# 本題

<img width="1440" alt="スクリーンショット 2020-01-26 19.13.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168714/6eee393c-0c8e-08d9-01c4-3e7e32fdf6b3.png">

### <解決したい内容>
ボタンを押して、コードから **ExamViewController** へPush遷移をしたい

### <現状>
スクリーン内の「Button」をタップすると、tapButton関数が呼び出されます。
ストリーボード名「Exam」、StoryboardID「Exam」で定義されている、 **ExamViewController** をインスタンス化しており、ここまでは問題がない。
Push関数を実行してもPush遷移が行われない。

### <解決方法>

```SceneDelegate.swift
class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?


    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        
        guard let _ = (scene as? UIWindowScene) else { return }
        
        self.window?.rootViewController = createFirstViewController() // <- 新規追加
        self.window?.makeKeyAndVisible() // <- 新規追加
    }

// 途中省略 ----

extension SceneDelegate { // <- 新規追加 & createFirstViewController関数作成
    
    func createFirstViewController() -> UINavigationController {
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let viewController = storyboard.instantiateInitialViewController() as! ViewController
        
        let navigationController = UINavigationController()
        navigationController.view.backgroundColor = .white
        let firstViewController = viewController
        navigationController.viewControllers = [firstViewController]
        navigationController.setNavigationBarHidden(true, animated: false)
        return navigationController
    }

}
```

MainのViewController配下に、NavigationControllerが定義されていないため、このような現象が起きていた。
上記のコードを **SceneDelegate.swift** 内に追加してあげることで、問題解決！
Swiftメモ:クラスの継承　〜鳥🐥とオードリー👦👱‍♂️で継承を理解する〜

#クラスの継承とは？
新しいクラスを作成する際に、似たようなプロパティやメソッドを持つクラスがあった場合、それを流用するためにクラスの継承を行います。
元になるクラスのプロパティやメソッドを引き継いだまま、さらに追加したいプロパティ・メソッドを定義して使用することが可能です。
<img width="320" alt="スクリーンショット 2020-01-26 18.16.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489221/531fd043-8749-d5ce-2774-7b5749186f16.png">

#鳥🐥とオードリー👦👱‍♂️の鳴き声(?)で継承を実践
理解のためにplaygroundで継承を実施してみました。
鳥クラスとオードリークラスを用意し、継承元のクラス(鳥クラス)と継承先のクラス(オードリークラス)の違いをみたいと思います。

```
import UIKit
//鳥クラス
class Bird {
    var name = ""
    
    func bark(_ names: String) {
        print("🐥：\(names)です！ぴよぴよ！")
        print("=========================================================")
    }
    
}

//オードリークラス
class Audrey: Bird{
    override func bark(_ names: String) {
        print("👱‍♂️：\(names)です！トゥース！")
    }
    
    func wakabayashi(){
        print("👦：これスルーでいっちゃいますけれどもね")
        print("=========================================================")
    }
}

var bird1 = Bird()
bird1.name = "ひよこ"
bird1.bark(bird1.name)

var bird2 = Audrey()
bird2.name = "春日"
bird2.bark(bird2.name)
bird2.wakabayashi()
```
【実行結果】
<img width="432" alt="スクリーンショット 2020-01-26 18.52.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489221/6a252ea0-a173-fef2-7dd9-007e68a24ddc.png">

見事にbird1ではひよこを、bird2ではオードリーを鳴かせることができました。

#今回のポイント❗️
・クラスの継承の記述方法
  　クラスの継承を行うには
 
　　　　class 継承先**: 継承元**{}
  
 　というように**継承元の記述が必要**になります
　 今回の場合ですと、Audreyクラスの後ろに継承元のBirdクラスを記述しています。
   　そうすることで若林さんのツッコミメソッドを追加して使用することができます。

```
//オードリークラス
class Audrey: Bird{
    override func bark(_ names: String) {
        print("👱‍♂️：\(names)です！トゥース！")
    }
    
    func wakabayashi(){
        print("👦：これスルーでいっちゃいますけれどもね")
        print("=========================================================")
    }
}
```

・barkメソッドのオーバーライド
     override func メソッド名{
         変更したい処理内容を記述
     }
 オードリークラスでbarkメソッドをオーバーライドすることで
　鳴き声を変更することができます。

#まとめ
継承を使えば基本のインスタンスにどんどんプロパティ・メソッドを追加できる！
継承ってすごい！オードリーっておもしろい！！
ajaxで取得したデータでrenderすると、Cannot read property xx of undefined エラーになる

# 問題点

例えば以下のように、バックグラウンドで取得したデータを表示させたいとします。

```jsx:xxx.js
  constructor(props) {
    super(props);
    this.state = {
      result: {}
    }

    fetch("http://localhost/api/test")
      .then(response => response.json())
      .then(json => this.setState({ result: json }));
    // /api/testは、以下のようなレスポンスを返す
    //  { 
    //    test1 : "aaa",
    //    test2 : {
    //      test3 : "bbb"
    //    }
    //  }
  }

  render() {
    return (
      <div>
        <p>{this.state.result.test1}</p>        // "aaa"が表示される 
        <p>{this.state.result.test2.test3}</p>  // "bbb"が出てほしいがエラーになる
      </div>
    )
  }
```
このとき、this.state.result.test2.test3の部分で、以下のようなエラーが出てしまいます。
`Cannot read property 'test3' of undefined`
test3 の親であるthis.state.result.test2がundefinedですよ、というエラーです。

# 原因
恐らく、this.state.resultの中身が全部セットされる前にrenderメソッドが動いてしまっているためだと思います。

# 解決法
## 1.描画前にチェックを行う
undefinedチェックを入れてあげると、エラーなく動くようになります。

```jsx:xxx.js
  render() {
    return (
      <div>
        <p>{this.state.result.test1}</p>        // "aaa"が表示される 
        <p>{this.state.result.test2 ? this.state.result.test2.test3 : ""}</p>  // "bbb"が表示される
      </div>
    )
  }
```
JSX内ではif文が使えないので、三項演算子を使っています。

## 2.あらかじめ空のプロパティをセットしておく
どのような要素が返ってくるかが最初からわかっているのであれば、以下のように予めセットしておくことでも対応できます。

```jsx:xxx.js
  constructor(props) {
    super(props);
    this.state = {
      result: {      
        test2 : {}   // あらかじめ空をセットしておく
      }
    }

    fetch("http://localhost/api/test")
      .then(response => response.json())
      .then(json => this.setState({ result: json }));
  }

  render() {
    return (
      <div>
        <p>{this.state.result.test1}</p>        // "aaa"が表示される 
        <p>{this.state.result.test2.test3}</p>  // "bbb"が表示される
      </div>
    )
  }
```


# 最後に
もっといい方法がありそうな気もするので、何かわかったら追記します。
Unity入門 01 環境構築

#はじめに
メインはサーバサイドJavaなのだけど、業務でUnityとC#使うかもってことで学習開始。

# 参考書籍
- 新・標準プログラマーズライブラリ なるほどなっとく C#入門
- Unityの教科書 Unity2019完全対応版 2D&3Dスマートフォンゲーム入門講座

# 環境
Windows 10 で勉強開始。
Macはもっていません。

# Unity Hubのインストール
https://unity3d.com/jp/get-unity/download
上記からダウンロード
exeを実行するとUnity Hubがインストールされる。
参考書籍では合わせてVisual Studioがインストールされる記述になっていたがインストーラーが変わったのかわたしのやり方がまずかったのかインストールされなかった。

#Visual Studioのインストール
Unity Hubを実行し、「インストール > インストール済みUnityのメニュー（3つの点） > モジュールを加える > Microsoft Visual Studio Community 2017」を選択し、「次へ」を押してインストール。
個別にインストールしてもいいし、もともと入っている場合はそれを使えるみたい。

# Android Studioのインストール
https://developer.android.com/studio/install?hl=ja
上記からアンドロイドスタジオをインストール。基本的に「次へ」を押していくだけ。
Wubiを使ってインストールしたUbuntuがInitramfsで止まり起動できない時の対処法

## 一時的に起動できるようにする

grubの画面になったら`e`キーを押してエディット画面に入る

以下のような行があるので確認

```
linux   /boot/vmlinuz-5.3.0-26-generic root=UUID=A8765346315IMAS loop=/ubuntu/disks/root.disk ro rootflags=sync  quiet splash $vt_handoff
```

マウントが読み取り専用になっているので`ro`を`rw`に変え`F10`を押しブート

## 恒久的に変更する

上記のやり方だと一回しか適用されないので`grub.cfg`のマウントの行が`rw`になっている必要があるが
`grub.cfg`は`update-grub`で自動生成されるので元のファイルを変更する必要がある。
`/etc/grub.d/10_lupin`の138行あたりの`ro`を`rw`に変更する

```
linux   ${rel_dirname}/${basename} root=${LINUX_HOST_DEVICE} loop=${loop_file_relative} rw ${args}
```

変更後`update-grub`を実行して`/boot/grub/grub.cfg`を確認し使用するブートのマウントが`rw`になっているか確認をする

今回`10_lupin`を変更していますが同ディレクトリの他ファイルにも同じように`ro`になっているファイルがあったので環境によって違うかもしれません。

必ず生成したあと確認をしてから再起動してください。
入門Python3  正誤表P288　改行が余計に追加される

[入門Python３　BillLubanovic著」を、読んでうまく動かなかったところのメモです。



###　不具合 
P.288 
with open('villains', 'rt') as fout:
	csvout = csv.writer(fout)
	csvout.writerows(villains)

を実行した際に、各行に改行が余計に追加されてしまう問題がある。




###　対策
open関数に newline引数を指定したら正しく(参考書通りに)動作しました。

 > with open('villains', 'rt', newline='') as fout:


https://docs.python.org/ja/3/library/csv.html#examples
このページの一番下に書かれてました。










###
Skype理工学勉強会では、同書の読書写経会をしています。
Skype上の無料オンライン会です。

https://engineeringskype.connpass.com/
入門Python3 正誤表　P267- オライリー本 BillLubanovic

[入門Python３　BillLubanovic著」を、読んでうまく動かなかったところのメモです。



###
不具合　P267
(P.267)conn.zadd('logins', 'smeagol', now)　で下記のエラーが出る。


>>> conn.zadd('logins', 'smeagol', now)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/ec2-user/.local/lib/python3.6/site-packages/redis/client.py", line 2388, in zadd
    for pair in iteritems(mapping):
  File "/home/ec2-user/.local/lib/python3.6/site-packages/redis/_compat.py", line 161, in iteritems
    return iter(x.items())
AttributeError: 'str' object has no attribute 'items'




###
対策
$ pip install "redis < 3"
のように、Redisのバージョンを下げたら　動作するようになりました。

参考記事
https://github.com/rq/rq-scheduler/issues/197





###
その他

Skype理工学勉強会では、同書の読書写経会をしています。
Skype上の無料オンライン会です。

https://engineeringskype.connpass.com/
TensorFlow2 からTensorFlow Liteへのモデル変換

TensorFlow2で作ったモデルファイルをTensorFlow Lite形式に変換するメモ

[TensorFlow Lite converter](https://www.tensorflow.org/lite/convert)に従う

- SavedModelディレクトリやtf.kerasのmodelをtfliteに変換できるらしい
- pythonのAPIで変換する方法が推奨されてる
- CLIもある

## python APIでコンバーター書く

[Converter Python API guide](https://www.tensorflow.org/lite/convert/python_api)

### SavedModelの変換

```python
converter = tf.lite.TFLiteConverter.from_saved_model("my_savedmodel")
tflite_model = converter.convert()
open("converted_model.tflite", "wb").write(tflite_model)
```

### Keras modelの変換

```python

# 事前にmy_modelオブジェクトを用意しておく

converter = tf.lite.TFLiteConverter.from_keras_model(my_model)
tflite_model = converter.convert()
open("converted_model.tflite", "wb").write(tflite_model)
```

## CLI

https://www.tensorflow.org/lite/convert/cmdline

```bash

$ tflite_convert --saved_model_dir=my_savedmodel --output_file=my_model.tflite
```

Kerasのmodelの場合は `--saved_model_dir` を `--keras_model_file` に置き換える

Quantizationやその他色々弄りたいならpython API使ってね、とのこと

## toco?

tfliteへの変換についてWeb検索しているとtocoというcliツールが時々出てくるが、今はdeprecatedらしい

https://stackoverflow.com/questions/57372937/the-relation-between-toco-tflite-convert-and-tfliteconverted
Incoming Webhookを使ったSlack通知ライブラリを作った

# Incoming Webhookを使ったSlack通知ライブラリを作った
おはこんばんにちは！和尚です:open_hands:


今日は初めてPHPの自作ライブラリをcomposer化までしてみました！
手順をざっくり書いて、作った自作ライブラリについての使い方を説明していくーーー！:cherry_blossom:

## 経緯
そもそも何故、今更Slack通知のライブラリを作ろうと思ったのかについて軽くお話させていただきたい:point_up:

今年からチャットサービスをSlackに乗り換えるぞ！という会社の方針で、以前チャットワークAPIを使って問合せ通知やらエラー監視ツールの通知やらをチャットワークに送っていたのですが、それらをSlackに移行しなければいけなくなってしまいました。

簡単に使えて便利なPHPのライブラリがあればよかったのですが、Slackの通知の仕組みが去年変わってしまっていて軒並み使えなさそうなライブラリたち...。とはいえ新しい仕組み自体もチャンネル毎にWebhookを使って通知するといった大したものではなかったのでPHPの自作クラスを作って対応しました。

そんなこんなで先月に移行作業を完了したわけなのですが、会社でPHPを使うことも多くSlack通知しないといけない処理が欲しいと言われたときにわざわざクラスコピーしてくるのも面倒だなーと思っていたのですが、もっと汎用的にしてcomposer化しちゃえば後々便利じゃない？とふと帰り道に思ったので今回作ってみることにしました。

### 参考サイト
- [自作Composerのパッケージの基本的な構成](https://qiita.com/busyoumono99/items/5c328e48ea3b5469ac58)
- [[PHP]自作ライブラリをComposer化＆Packagistの登録方法](http://vdeep.net/composer-packagist)

## 自作ライブラリを作る手順
ざっくりとですが、自作のライブラリを作る手順は以下の順番になります。

1. 自作ライブラリ用のディレクトリを作成する
2. `$ composer init`でcomposerファイルを作成する
3. 必要なパッケージをcomposer.jsonに記載し、`$ composer install`する
4. srcディレクトリを作成し、autoloadの設定をcomposer.jsonに記載して`$ composer dump-autoload`する
5. 自作クラスを作成する
6. テストコードを書く
7. サンプルファイルを作成する
8. ライセンスファイルを作成する
9. readme.mdを書く
10. githubにpushする
11. [packagist](https://packagist.org/)にgithubリポジトリを登録する

大体の作業は参考記事を見ながら作成したので、自作ライブラリが既に出来てるよ！って方は上記の参考サイトを見ながら登録してみてください。

## Slack Notification
[githubリポジトリ](https://github.com/osyou84/slack-notification)
[packagist](https://packagist.org/packages/osyou84/slack-notification)

## Slack Notificationの使い方

ライブラリ自体はかなりシンプルな作りになっています。
※ sendメソッドの第二引数にwebhookのURLが必要になります。Slackの通知を行いたいチャンネルにてアプリ追加ボタンを押し、incoming-webhookを追加してwebhookのURLを控えておいてください。

１. インストール

```bash
$ composer require osyou84/slack-notification
```
２. SlackNotificationを使用するphpファイルで、autoload.phpを読み込む(既に読み込まれている場合はスキップ)

```php
require_once(__DIR__ . '/vendor/autoload.php');
```
３.インスタンスの作成

```php
use osyou84\SlackNotification\SlackNotification;

$slack_notificaiton = new SlackNotification;
```

４.メンションを設定し、送信する

```php
$message = 'スラックに通知する';
$webhook_url = 'https://hooks.slack.com/services/XXXXX/YYYYY/ZZZZZ';
$slack_notification->targetChannelAll()
                   ->send($message, $webhook_url);
```

### メンションの設定方法
Slack Notificationではメンション用に4つのメソッドを用意しています。
#### 1.ワークスペース全員に送る(#generalに向けて)

```php
(new SlackNotification)->targetWorkspace()
                       ->send($message, $webhook_url);
```
#### 2.チャンネル内の全員に送る

```php
(new SlackNotification)->argetChannelAll()
                       ->send($message, $webhook_url);
```
#### 3.チャンネル内でアクティブなメンバーに送る

```php
(new SlackNotification)->targetActive()
                       ->send($message, $webhook_url);
```
#### 4.指定したユーザーに送る
user_idはワークスペースの管理者がユーザー管理にてCSVダウンロードできます。

```php
$user_ids = ['user_id_1', 'user_id_2', 'user_id_3'];
(new SlackNotification)->setTargets($user_ids)
                       ->send($message, $webhook_url);
```

## まとめ
かなりざっくりですが、incoming webhookを簡単に使えるPHPライブラリ作ってcomposer化したので、使ってみてね！という記事でした:relaxed:
改良案を思い浮かんだら随時アップデートしていきたいところ...
Angular Material で作ったプロジェクトに登録画面を追加する

## はじめに

以下のポストでAngular（Material)の初心者用プロジェクトを作った。

Angular スターターキットを作った
https://qiita.com/shinno21/items/b072e48d28f2ee7d34d9


発展編その１として、もともと簡単な一覧画面しかなかったこのプロジェクトに、登録画面を追加してみた。


## 登録画面の追加コミット

以下の通り、コードを追加している

**Angular**
https://github.com/shinno21/sk-app/commit/28df4808312f832098dc869a907939fab66ebaa6

**Django Restframework**
https://github.com/shinno21/drf_sample/commit/6822ade6ab8c9811cedea47a14ba7169b4fdf4de


## 解説

以下の手順でコードを追加している

* Angular CLIで登録画面として使うコンポーネントのテンプレートを追加
* app-routing.module.ts　に登録画面のURLを追加
* app.module.ts　に必要なコンポーネントを追加
* 登録画面の実装を行う
* その他


### Angular CLIで登録画面として使うコンポーネントのテンプレートを追加

```
> ng g component components/sample/sample-reg
```

Angular的には１画面 = １コンポーネントでは必ずしもないのだが、あまり細切れにコンポーネント分割しても良いことはないので、基本的にはそうしている。

* src/app/components/sample/sample-reg/ 以下にhtml, css, ts, spec.ts のセットが作られる

ここでは登録画面用のコンポーネントを追加。

#### (参考)Angular CLIの generate
https://angular.io/cli/generate

### app-routing.module.ts　に登録画面のURLを追加

以下の変更を加える。
https://github.com/shinno21/sk-app/commit/28df4808312f832098dc869a907939fab66ebaa6#diff-959f71d9b4ce6d41e637aaf363c42a18


### app.module.ts　に必要なコンポーネントを追加

以下の変更を加える。
今回はカレンダー入力とプルダウン入力のUIを使うので、Angular Materialからコンポーネントを追加する。（MatNativeDateModule, MatDatepickerModule, MatSelectModuleの辺りのコード）
https://github.com/shinno21/sk-app/commit/28df4808312f832098dc869a907939fab66ebaa6#diff-fc6b22833aeaf77f8440c4970ade705e


#### (参考)Angular Material のコンポーネント利用方法
##### 自分が利用したいコンポーネントを見つける。

公式サイト参照。このあたりに利用出来るコンポーネントが書いてあります。
https://material.angular.io/components/categories

##### 利用したいコンポーネントをプロジェクトに適用する

公式サイトのこの辺にやり方が載っています。
https://material.angular.io/guide/getting-started#display-a-component

### 登録画面の実装を行う

今回は画面のレイアウトは特に気にしない。テストも作らないので、htmlとtsの実装のみ。
登録用のAPIを呼び出すのに、既存のServiceクラスに登録用のメソッドを追加。

https://github.com/shinno21/sk-app/commit/28df4808312f832098dc869a907939fab66ebaa6#diff-2da8c65a14d0d2226a9d6bd4dad8485f

https://github.com/shinno21/sk-app/commit/28df4808312f832098dc869a907939fab66ebaa6#diff-02461ed95a1deba26d430e32d5250d22

https://github.com/shinno21/sk-app/commit/28df4808312f832098dc869a907939fab66ebaa6#diff-645693f765af55d812b748e4780b68cf

### その他

HTTP Headerに入力する値を定数として設定。
Postクラスの作成日属性の変数名をAPI側と合わせる修正を加えた。

また、API側にAngular画面から渡される日付フォーマットの形式を考慮した修正を加えた（blackというフォーマッターのせいで不要な部分の変更も入っているが）

https://github.com/shinno21/sk-app/commit/28df4808312f832098dc869a907939fab66ebaa6#diff-5f99a1ffc9abec09e80c4cb21d00b682

https://github.com/shinno21/sk-app/commit/28df4808312f832098dc869a907939fab66ebaa6#diff-07d0f2c8810384675209f8256b731f92

https://github.com/shinno21/drf_sample/commit/6822ade6ab8c9811cedea47a14ba7169b4fdf4de#diff-eef9d10b9aaddbd37cb292a035e576af
UI設計覚書

 ウェブアプリケーションの UI を設計、実装するに当たり、常日頃注意している事等をまとめてみました。

## ボタンは消さない。非活性化する

操作不可能なボタンを画面から消してしまうのは好ましくないと思ってます。ユーザーは完全に操作を理解してアプリケーションを利用しているとは限りません。たとえ自分のアクションが原因で後続の操作ができなかったとしても、いつもある位置にボタンが無い事をすぐに認識できない場合があります。「あのボタンはどこだっけ？」と画面内を探し回る事になり、余計なストレスを与えてしまいます。

### 解決策

利用できないボタンは消すのではなく淡色表示や暗転させて利用できない事をアピールします。ツールチップ（吹き出し）等で操作できない理由を明示してあげるとより親切かも知れません。

## アクションの送信を認識させる

重たい操作を実行する時等、操作が完了するまで画面に何も変化が発生しないのは好ましくありません。ユーザーは自分がボタンクリックを失敗したのかと思い、何度も同じ操作を繰り返してしまう場合があります。

### 解決策

ユーザーのアクションを受領した事を、視覚的に表現します。表現方法としては、例えばボタンを非活性化させる、プログレスバーを表示する、ウェイトカーソルに変更する等があります。重たい操作を実行する前に、確認ダイアログボックスを表示するのも有効です。

## 「戻るボタン」は常に利用可能にする

ウェブブラウズにおいてユーザーがもっとも利用するボタンは「戻るボタン」であると言われています。スマホにおいてもスワイプによってバックする操作はよく利用されるでしょう。「戻るボタン」やスワイプ等、一般的な「戻る」のアクションでいつでも前の画面に戻れる事は、ユーザーを安心させます。

### 解決策

非 SPA アプリケーションにおいては、POST メソッドが実行された直後の画面は一旦リダイレクトを行う事で「戻るボタン」は有効に作用します。大抵はフレームワークのサポートがあるので昨今ではあまり考えなくても良いかも知れません。SPA では実装が難しい局面もありますが、各画面において戻るボタンが意図に反するような動作になっていないか、注意しましょう。

## 戻った時はスクロール位置を元に戻す

従来的ウェブサイトにおいては、「戻るボタン」を押してひとつ前の画面に戻った時はスクロール位置も保たれているのが基本です。SPA においては実装が難しい事もあり、戻った時にスクロール位置がリセットされてしまうアプリケーションが少なくありません。一覧画面から進む、戻るを繰り返してブラウズするケースはよくあります。このような時にスクロール位置がリセットされてしまうとストレスが溜まります。

### 解決策

これは実際難しい場合も多いと思います。特に最下部までスクロールさせた時に追加のコンテンツを読み込むようなページでは、状況によっては実装が難しいと思います。別タブを開く等の対応は暫定的な解決策としては有効かも知れません。なお、ページトップに戻った方が良い場合もあるので使い分けが必要です。

## エラーメッセージは簡潔に2つの文で書く

エラーメッセージで重要な事は「何が失敗したのか」「どうすれば良いのか」の2つを伝える事です。特に「どうすれば良いのか」が重要です。また「何が失敗したのか」もユーザー目線で伝えるようにしましょう。

### 解決策

例示した方が分かりやすいと思います。

悪い例|悪い理由|良い例
----|----|----
制約違反が発生しました|開発者の言葉で説明している。どうすれば良いか書いていない|商品名が重複しているので商品を追加できませんでした。別の商品名を利用して下さい。
エラーです。管理者に連絡して下さい|このエラーによって何ができなかったのかが書いていない|システム障害により商品を追加できませんでした。管理者に連絡して下さい。
バックトレースをそのまま表示|言うまでもなく、処理系のエラーをそのまま表示というのは駄目です。バックトレースが欲しいのならログに記録しましょう|


## それぞれの情報に URL を持たせる

ある情報を表示している時に、その情報に紐づく URL を用意しましょう。これは JavaScript を利用しないような古典的なサイトではむしろ当たり前でした。高度化した昨今のページにおいては、表示されている情報に URL が紐づいていないケースが昔より増えているような気がします。例えば一覧画面の各項目をクリックした時にポップアップして詳細を表示するようなアプリケーションでは、表示中の詳細情報に紐づく URL が存在しないケースを見かけます。URL が無いとメール等で誰かに情報の所在を通知する時に不便になります。

### 解決策

各フレームワークのルーティング機能等を利用して、それぞれの情報に対して一意な URL を紐づけるようにすると良いと思います。

## スマホに傾向しすぎない

レスポンシブデザインが当たり前の昨今ではスマホやタブレットで出来ない事はやらないというのがひとつの考え方ではありますが、その事が PC ユーザーにストレスを与えていないか考慮してみる必要があります。外出先ではスマホやタブレットで操作しつつ、オフィスでは PC で効率良く作業したいというケースも少なくありません。

### 解決策

大量の情報を一画面に表示した方が効率が上がる場合は、レスポンシブデザインをあきらめた方が良い場合もあります。

## 見せながら作る

昨今の高度化した UI はいくら仕様書で説明しても、操作した時の感覚も含めて理解してもらうのは大変難しいです。設計者自身が理解できない場合も多いです。ユーザーに見せながら作る事でこの問題は大きく緩和できます。アジャイル開発の現場においては「何を当たり前の事を」と言われると思いますが、契約上の問題等でウォーターフォール開発の体を外せない開発においても重要です。

### 解決策

ウォーターフォール開発においては、要件定義フェーズにプロトタイプ開発の期間を設けておきましょう。

## UI は視覚言語であるという意識でデザインする

UI とはユーザーのやりたい事をコンピューターに伝えるための言語であると言えます。言語は整然としており、憶えた知識を元に新しい事を表現しようとした時に、意図通りに表現できる事が重要であると思います。これこそが「直感的な操作」であると、個人的には常々思っています。

### 解決策

同じ機能、似た機能のボタンは、同じような色、形、位置にするべきだと思います。例えばユーザー詳細画面のユーザー削除ボタンが画面右上にあるとしたら、商品詳細画面の商品削除ボタンも画面右上に配置しましょう。


----

かつてソフトウェアは、マニュアルを熟読し十分理解した上で利用する事が当たり前でした。昨今では覚えながら使ってもらうのが当たり前ですし、利用者の増加に伴い、平均的なリテラシーも下がってきています。熟練者を満足させつつ初心者を迷わせない UI は実際なかなか難しいと思いますが、頑張って取り組んでいきたいですね。
Flutter Webでスクロールしたらコンテンツがふわっと出てくるやつ

Flutter Webって書いたけど別にスマホでも動く

# こういうやつ

<img src="https://i.gyazo.com/6d681510d6732e2fe6d74675beeba1ed.gif" width=300 />

# ソース

```dart
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  var duration = const Duration(milliseconds: 200);
  var widgetHeight = 500.0;
  var _animationParams =
      List.generate(10, (i) => {"top": -50.0, "opacity": 0.0});
  List<Widget> _animationWidgets() =>
      List.generate(10, (i) => createAnimationWidget(i));
  var _scrollController = ScrollController();

  @override
  void initState() {
    _scrollController.addListener(_scrollListener);
    super.initState();
  }

  void _scrollListener() {
    var offset = _scrollController.offset;
    var index = (offset / widgetHeight).ceil();
    setState(() {
      print(index);
      _animationParams[index] = {"top": 0.0, "opacity": 1.0};
    });
  }

  Widget createAnimationWidget(index) => Stack(
        children: <Widget>[
          Container(
            constraints: BoxConstraints.expand(height: widgetHeight),
          ),
          AnimatedPositioned(
            duration: duration,
            top: _animationParams[index]["top"],
            child: AnimatedOpacity(
              duration: duration,
              opacity: _animationParams[index]["opacity"],
              child: Center(
                child: ClipRRect(
                  borderRadius: BorderRadius.circular(8.0),
                  child: Image.network(
                    "https://geinou-tomodachi.work/wp-content/uploads/2018/10/761835_615-e1538578576474.jpg",
                    fit: BoxFit.fitWidth,
                  ),
                ),
              ),
            ),
          ),
        ],
      );

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: SafeArea(
        child: SingleChildScrollView(
          controller: _scrollController,
          child: Column(
            children: _animationWidgets(),
          ),
        ),
      ),
    );
  }
}
```

# まとめ

最初の画像がデフォで出てないのが気持ち悪い
入門Python3 正誤表　P260- オライリー本  BillLubanovic  

[入門Python３　BillLubanovic著」を、読んでうまく動かなかったところのメモです。


＃＃＃
P260-
Redisのコードが動かない。

＃＃＃
対策：PCにRedisをインストールしたら、コードが正常に作動した。

具体的には下記です。
8.5.3.1 文字列のところで、redisに接続できなくてエラーになってたのは、
(1)先ずRedisをインストールして、
　　https://qiita.com/stoshiya/items/b8c1d2eb41770f92ffcf
(2)$ redis-server コマンドでredisを起動する
　　https://qiita.com/yoh-nak/items/69c26e7d627e2b5a95e2
を行う必要がありました。






###
Skype理工学勉強会では、同書の読書写経会をしています。
Skype上の無料オンライン会です。

https://engineeringskype.connpass.com/
VSCodeにPHP_CodeSnifferを導入する。

## VSCodeにPHP_CodeSnifferを導入する。

VSCodeにPHP_CodeSnifferを導入する方法を記事にしていきます。

### 何ができるようになるのか
PHPのコーディング規約違反(PSR違反)をエディタ(VSCode)で視覚的に確認できるようになる。

### 下準備
`Homebrew`をインストール
[Homebrew公式サイト](https://brew.sh/index_ja)

### 手順
1. 拡張ツール、`phpcs`をVSCodeでインストールする。
※ 下記スクショ赤下線部参照
<img width="394" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456901/41e86dd5-7688-eb31-3641-71d856613ffc.png">

![be378075.png](:storage/6bcbd256-fcc0-432e-88b8-68ace02dad43/be378075.png)

2. 以下のQiita記事を参考に、`Composer`をインストール。

※ [macOS に composer をインストールする](https://qiita.com/tomk79/items/e6e1db94ea8b661b1e86)

3. VScodeのメニューバー > Preference > Setting > Workspace > Extensions > PHP_CodeSniffer configurasionにて、
`setting.json`の項目を見つけ以下のように、編集する。

```
	"phpcs.executablePath": "/Users/:自分のmacの名前/.composer/vendor/squizlabs/php_codesniffer/bin/phpcs",
	"phpcs.standard": "PSR1",
```
※ "phpcs.standard": "PSR1"について
=> ここでは、`PSR1`に準拠するように設定しています。こちらの左辺を変更することによって、`PSR2`, `PSR12`など自由に設定できます。

### 結果
<img width="1032" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456901/b175bade-0ab4-3c75-c835-bf38525fc579.png">
![7508d4f1.png](:storage/6bcbd256-fcc0-432e-88b8-68ace02dad43/7508d4f1.png)

コーディング規約違反がエラーとして表示されるようになりました。

※ こちらのコードの正

```PHP
if ($hoge) {
    var__dump('piyo');
}

exit;

```
実務未経験者がUdemyの講座を参考にして、RailsでInstagram風アプリを作ったので感想をまとめます

現在22歳の大学生です。就職先としてweb形自社開発企業を目指し、ポートフォリオ作成と就活を頑張っています。

今回はUdemyの講座を参考にInstagram風アプリを作成したので、感想などを書いていきます。

##参考にした教材

今回はUdemyにある「[Beautiful Ruby on Rails Apps in 30 Days & TDD - Immersive](https://www.udemy.com/course/8-beautiful-ruby-on-rails-apps-in-30-days/)」を使用しました。

こちらの教材はInstagram、Evernote、Tumblrなどの有名アプリを含めた、8つのアプリの作り方をRuby on Railsで学ぶという盛りだくさんの内容です。

しかもこの教材、**無料**です。ただその代わり、教材の内容は2014年ぐらいと少し古いです。
あと解説は英語で日本語字幕などはありません。まあ内容は難しくないので大丈夫です。

##難易度はProgate以上、Railsチュートリアル未満

Railsチュートリアルができるなら、この教材は難しくありません。ただhamlやscss、新しいgeｍなどの使い方は覚える必要があります。

逆にProgateレベルの一般的な知識がないと、この教材は難しいと思います。理由は説明が少ないからです。
講座内で解説はありますが、それでも基本を理解していないと追いつけません。

##作った成果物

![Screen Shot 2020-01-26 at 17.21.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517805/d9f9f7f2-1b81-abc3-f9b9-54b084f05d27.png)

講座内で配布されているCSSを使っていないので、UIが貧弱です。

ちなみに講座内で配布されているCSSを使うとこんな感じになるようです。[配布場所はここ。](https://github.com/CrashLearner)

![Screen Shot 2020-01-26 at 18.08.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517805/63feadff-a90f-9632-cd40-5ffaa102bc0a.png)


##学んだこと

- hamlとscssの使い方
- gemのsimple_formでformが簡単に作れる。
- gemのdeviseでログイン認証が簡単にできる。
- gemのpaperclipで画像の扱いが簡単にできる。
- gemのact_as_votableでlike機能が簡単に実装できる。

##不満なこと

- gemを用いて簡単にアプリができてしまったので、学べた感じがしない。
- レベルが高い内容ではない。

##まとめ

Instagram風アプリが作りたかったので受講しましたが、そこまでレベルの高い内容ではありませんでした。
ですが無料の教材ということを踏まえれば、内容は充実していたと思います。

Instagram風のアプリを作成してみたい方は利用してみてはいかがでしょうか？
Flutter Webで真ん中のタブだけ強調する

Flutter Webって書いたけど別にスマホでも動く

# こういうやつ

<img src="https://i.gyazo.com/8aedee5edc7650d94d24be85ce350ad4.png" width=300 />

# ソース

概要としては
・bottomNavigationBarに普通に３つ並べて真ん中を透明ボタンにする
・floatingActionButtonの領域を広げてFloatingActionButtonを好きな位置に貼る

```dart

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _selectedIndex = 0;

  static const TextStyle optionStyle =
      TextStyle(fontSize: 30, fontWeight: FontWeight.bold);

  static const List<Widget> _widgetOptions = <Widget>[
    Text(
      'Index 0: Business',
      style: optionStyle,
    ),
    Text(
      'Index 1: Home',
      style: optionStyle,
    ),
    Text(
      'Index 2: School',
      style: optionStyle,
    ),
  ];

  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: SafeArea(
        child: Container(
          color: Colors.white,
          child: Center(
            child: _widgetOptions.elementAt(_selectedIndex),
          ),
        ),
      ),
      bottomNavigationBar: BottomNavigationBar(
        items: [
          BottomNavigationBarItem(
            icon: Icon(Icons.business),
            title: Text('Business'),
          ),
          BottomNavigationBarItem(
            icon: Opacity(
              opacity: 0,
              child: Icon(Icons.home),
            ),
            title: Text(""),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.school),
            title: Text('School'),
          ),
        ],
        currentIndex: _selectedIndex,
        selectedItemColor: Colors.amber[800],
        onTap: _onItemTapped,
      ),
      floatingActionButton: Container(
        width: 90,
        height: 100,
        child: FittedBox(
          alignment: Alignment.topCenter,
          child: FloatingActionButton(
            elevation: 0,
            hoverElevation: 0,
            highlightElevation: 0,
            child: Icon(Icons.home),
            backgroundColor: Colors.redAccent,
            onPressed: () {
              _onItemTapped(1);
            },
          ),
        ),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
    );
  }
}
```
rails newする際のエラー（can't find gem railties）の解決法

新しいアプリを作成する際のrails _○○○○_ new で困ったので解決法を共有します。

  rails _○.○.○.○_ new app名　_○.○.○.○_　はrails -vした際のバージョンと同じにする必要があります。

私の場合ですと、rails -vをするとRails 6.0.2.1というバージョンが出てくるので、

```rails _6.0.2.1_ new app名```
としてあげると新しいアプリとファイルが作成されます。


備忘録として手短に。何かあれば追記します。
ロリポップFTPをFilezillaへつなぐ

皆さんこんにちわ ^^

たった一人の恋人と付き合っていくのも大分面倒臭いのに、３年間も二人目をキープし続けるとか逆にすげえな、よっぽど暇だったんだろうなと感心しております

hujisawaでございます。

## ロリポップFTPをFilezillaへ

本日の記事は、ロリポップFTPのお話しでございます。

私はFilezillaから、ロリポップFTPへ繋ぎたいと思ってました。

だから、それを実行しました。

## 環境

こちらが現在の私のFilezillaとパソコンのosの状況でございます。

<img width="487" alt="スクリーンショット 2020-01-26 17.42.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135794/4860dd56-27e2-ad30-ce28-aee06e5952eb.png">
<img width="583" alt="スクリーンショット 2020-01-26 17.41.50.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135794/67023960-b2cc-4e71-8d3a-fca9409116c0.png">


## 実行

画像が沢山あって失礼しますが

1枚目の写真は、ホスト名に関する部分でございます。ホスト名を知るには、ロリポップftpへウェブから接続して、ftp画面へ入ったところの、ちょうどヘッダーの下に書いてあります。ここの `< > ` で囲まれてる部分をFilezillaのホスト名の部分へ入力してくださいませ。

<img width="891" alt="スクリーンショット 2020-01-26 17.25.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135794/6126fd59-34c4-5d9c-3871-c230ee2f7bfe.png">

次、ユーザー名の部分でございます。こちらは、ロリポップへログインした後に、サーバー情報をみる部分があります。その中の項目のFTP・WebDAVアカウントと書かれている部分がユーザー名になりますので、この部分を、Filezillaのユーザーの部分に入力してくださいませ

<img width="853" alt="スクリーンショット 2020-01-26 17.27.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135794/f5bbfcdd-171f-9c88-ab00-4bbbd8debd15.png">

最後に、パスワードでございます。こちらも、ロリポップへログイン後、サーバー情報をみる部分があり、その中の項目にありますので、そこを参照してくださいませ。

<img width="1177" alt="スクリーンショット 2020-01-26 17.28.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135794/6a2f0ecb-8694-4202-8fa0-7e0a6e8bd154.png">

以上になります＾＾
よく使用するgsutilコマンド

# はじめに
* 題名の通りですが、よく使用するgsutilコマンドをまとめました。
* 注意)gsutilコマンドを使用するには実行環境の構築が必要です。今回はgsutilコマンドを既に使用できる状態として話を進めますのでご注意ください。

## gsutilコマンドとは？
* gsutilコマンドとは、GCS(Google Cloud Storage)をコマンドラインから操作できるPythonアプリケーションのこと
* 動作するのは、Linux、Unix、Mac OS、Windows(XP以降)
 * gsutilをスタンドアロンとしてインストールした場合は、Windowsのみ事前にPython 2.7.xをインストールする必要がある。理由は、windowsにはデフォルトでPythonがインストールされいないため。また、Python 3.xでも動作しないため注意が必要

## 使用方法
* gsutilのバージョンを確認する場合

```
$ gsutil version
gsutil version: x.xx
```

* バケットの一覧を出力する場合

```
$ gsutil ls
gs://bucket_name1/
```

* バケット内のオブジェクト一覧を出力する場合

```
$ gsutil ls gs://bucket_name1/
gs://bucket_name1/file.txt
```

よく上記コマンドに「| wc -l」を付けてオブジェクトの数を確認したり、「| grep」で検索したりします。

* オブジェクトの内容を出力する場合

```
$ gsutil cat gs://bucket_name1/file.txt
aaa
bbb
```

* 新しくバケットを作成する場合

```
$ gsutil mb -c class -l location -p project_id gs://bucket_name2
Creating gs://bucket_name2/...
```

オプションを何も付けずに実行した場合、クラスがMulti-Regilnal、ローケーションがUSで作成されます。デフォルト値で作成されると困るのでオプションを付けて基本的には実行しています。-pについてはproject_idが複数なければ特に付けなくても大丈夫です。

* バケットを削除する場合

```
$ gsutil rb -r gs://bucket_name1
Removing gs://bucket_name1/...
```
-rを付けている理由は、バケットの中身が空ではない(オブジェクトが存在する)場合エラーが出るため、バケット・オブジェクトをまとめて削除するために付けています。

* オブジェクトを削除する場合

```
$ gsutil rm gs://bucket_name1/file.txt
Removing gs://bucket_name1/file.txt...
```

* 別バケットからオブジェクトをコピーする場合

```
$ gsutil cp gs://bucket_name1/file.txt gs://bucket_name2/
```

ちなみにGCS上だけでなくローカルからGCSへ、GCSからローカルへコピーすることも可能です。

* 別バケットからオブジェクトを移動する場合

```
$ gsutil mv gs://bucket_name1/file.txt gs://bucket_name2/
Copying gs://bucket-name1/file.txt...
Removing gs://bucket-name1/file.txt...
```

cpと同様でGCS上だけでなくローカルからGCSへ、GCSからローカルへ移動することも可能です。また、オブジェクトをリネームすることも出来ます。

## まとめ
* 今回よく使用するコマンドのみ記載しましたが、他にもコマンドがあるので興味がある方は調べてみてください。何か間違いなどございましたらお手数ですがご指摘ください。

## 参照元
[gsutil ツール(公式)](https://cloud.google.com/storage/docs/gsutil?hl=ja)
おすすめ自作 React hooks集4 (useMemoBuffered)

# おすすめ自作 React hooks 集 4

* [おすすめ自作 React hooks集1](https://qiita.com/pikohideaki/items/1464e13020b3777607c7)
* [おすすめ自作 React hooks集2](https://qiita.com/pikohideaki/items/4238dd17818e58c33799)
* [おすすめ自作 React hooks集3](https://qiita.com/pikohideaki/items/5b87fedb6f1218f07d21)

## 公式ドキュメントへのリンク

- [React hooks API](https://ja.reactjs.org/docs/hooks-intro.html)
- [カスタムフックの作成](https://ja.reactjs.org/docs/hooks-custom.html)

## useMemoBuffered

`useMemo` (→ [フック API リファレンス#useMemo](https://ja.reactjs.org/docs/hooks-reference.html#usememo)） でメモ化したい値が、頻繁に更新される他の値に依存しており、一定時間（200msとか）その更新が止むまで再計算を待ちたい、という状況がたまに存在します（たとえばinput要素の入力された文字列に基づきリストをフィルタリングしたいときなど）。

メモ化したい値が頻繁に更新される値に依存しているが再計算も毎回必要というわけではなく適宜間引きたいという状況では、次のようなcustom hooksが役に立ちます。（RxJSの `debounceTime` オペレータのような動作です。）

```ts
import { useEffect, useRef, useState } from 'react';

export function useMemoBuffered<ResultValue>(
  fn: () => ResultValue,
  deps: any[],
  bufferMilliSec: number
): ResultValue {
  const ref = useRef<{ timerId: number | undefined }>({ timerId: undefined });

  const [value, setValue] = useState<ResultValue>(fn);

  useEffect(
    () => {
      // 前の予約をキャンセル
      clearTimeout(ref.current.timerId);
      // fnの実行をbufferMilliSecミリ秒後に予約
      ref.current.timerId = setTimeout(() => {
        setValue(fn());
      }, bufferMilliSec);
    },
    deps // eslint-disable-line react-hooks/exhaustive-deps
  );

  return value;
}
```

使い方はほとんど `useMemo` と同じです。

```tsx
export const SomeComponent = () => {
  const [name, setName] = useState<string>('');

  // nameの値が更新されたとき、その更新が200ミリ秒間止むまで待ってからresultを再計算する。
  const result = useMemoBuffered(() => computeExpensiveValue(name), [name], 200);
  
  return (
    <div>
      <input value={name} onChange={event => setName(event.target.value)} />
      <SomeChildComponent result={result} />
    </div>
  )
}
```

---

## 2020/03/06追記

`useEffect` で[クリーンアップ](https://ja.reactjs.org/docs/hooks-effect.html#effects-with-cleanup)を忘れていたためメモリリークの危険がありました。正しくは以下のように書き、`useMemoBuffered` hooks が使われるcomponentが破棄されたときにtimerを破棄する必要があります。


```ts
import { useEffect, useRef, useState } from 'react';

export function useMemoBuffered<ResultValue>(
  fn: () => ResultValue,
  deps: any[],
  bufferMilliSec: number
): ResultValue {
  const ref = useRef<{ timerId: number | undefined }>({ timerId: undefined });

  const [value, setValue] = useState<ResultValue>(fn);

  const clearTimer = useCallback(() => {
    clearTimeout(ref.current.timerId);
  }, []);

  useEffect(
    () => {
      // 前の予約をキャンセル
      clearTimer()
      // fnの実行をbufferMilliSecミリ秒後に予約
      ref.current.timerId = setTimeout(() => {
        setValue(fn());
      }, bufferMilliSec);

      return clearTimer; // ← これが必要
    },
    deps // eslint-disable-line react-hooks/exhaustive-deps
  );

  return value;
}
```


---

おすすめ自作 React hooks集は随時追加予定です。
AWS Batchでインスタンスストレージを使う方法

# 欲しいのはEBSじゃなくてエフェメラルなディスク

AWS BatchでEBSを使う方法なら、どこにでも書いてある。でもインスタンスストレージは？　2020年1月25日調べでは、どうやらどこにも書いてない。
エフェメラルなディスクが欲しいときにEBSを使うと、アホな管理の手間が発生するし、おそらくはインスタンスストレージのほうが速い。

# 結論

### 1. BatchのCompute environmentで、Instance typesにc5dなどのインスタンスストレージつきのを選ぶ

### 2. ジョブが走るコンテナ内で`lsblk`する

c5d.4xlargeの場合、ログはこうなる：

```bash
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
/dev/nvme2n1 259:0 0 372.5G 0 disk
/dev/nvme1n1 259:1 0 22G 0 disk
└─/dev/nvme1n1p1 259:5 0 22G 0 part
/dev/nvme0n1 259:2 0 8G 0 disk
├─/dev/nvme0n1p1 259:3 0 8G 0 part /etc/hosts
└─/dev/nvme0n1p128 259:4 0 1M 0 part
```

どう見ても`/dev/nvme2n1`がインスタンスストレージ。これを直にマウントしようとしても、コンテナ内のファイルシステムからでは見つからない。ファイルシステムから見えないものが、なぜか`lsblk`では見えるのだ。この盲点を発見するまで、地獄めぐりをさせられた。

### 3. Job definitionの`Linux Parameters`でデバイスをマッピング

ホストもコンテナも、パスは`/dev/nvme2n1`でOK。パーミッションは当然全部加える。privilegedもオン。

### 4. ジョブの最初に走るbashスクリプトの冒頭で、フォーマットしてマウント

```bash
mkfs.ext4 -E nodiscard /dev/nvme2n1
mkdir $HOME/scratch_dir
mount -o discard /dev/nvme2n1 $HOME/scratch_dir
```
Visual Studio 2019 で Ant Design of Angular を使う

VS2019でASP.NET Core Webアプリケーション(Angular)を作ろうとした際にはまったのでメモです。
まだ触り始めたばかりなので、細かい設定は間違ってたりするかもしれません。

## 参考サイト
[Ant Design of Angular - NG-ZORRO](https://ng.ant.design/docs/introduce/en)

## 前提
- Visual Studio Community 2019 (Version16.4.2)
- .NET Core (ASP.NET Core 3.1)
- ASP.NET Core Webアプリケーション(Angular)
- Ant Design of Angular

## 導入方法
#### 1. ASP.NET Core Webアプリケーション(Angular)を作成
「新しいプロジェクトの作成」からポチポチ進んでいくとできます。

#### 2. `ng-zorro-antd`をインストール
1. 開発者コマンドプロンプトを起動する 
    - `ツール(T)` > `コマンドライン(L)` > `開発者用コマンドプロンプト(C)`
2. コマンドプロンプトで下記のコマンドを実行
    - `cd <プロジェクト名>\ClientApp`
    - `npm install ng-zorro-antd`
    
#### 3. `app.module.ts`を修正する
テンプレートで作成された`app.module.ts`に必要な文言を追加する。
参考サイト: [Getting Started - NG-ZORRO](https://ng.ant.design/docs/getting-started/en#customized-work-flow)

``` app.module.ts
//...(省略)...
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgZorroAntdModule, NZ_I18N, en_US } from 'ng-zorro-antd';

//...(省略)...

/** config angular i18n **/
import { registerLocaleData } from '@angular/common';
import en from '@angular/common/locales/en';
registerLocaleData(en);

@NgModule({
  //...(省略)...
  imports: [
    //...(省略)...
    BrowserAnimationsModule,
    NgZorroAntdModule
  ],
  providers: [
    { provide: NZ_I18N, useValue: en_US }
  ],
  //...(省略)...
})
export class AppModule { }
```

#### 4. `angular.json`を修正する
テンプレートで作成された`angular.json`に必要な文言を追加する。
参考サイト: [Getting Started - NG-ZORRO](https://ng.ant.design/docs/getting-started/en#customized-work-flow)

``` angular.json
{
  "assets": [
    //...(省略)...
    {
      "glob": "**/*",
      "input": "./node_modules/@ant-design/icons-angular/src/inline-svg/",
      "output": "/assets/"
    }
  ],
  "styles": [
    //...(省略)...
    "node_modules/ng-zorro-antd/ng-zorro-antd.min.css"
  ]
}
```

#### 5. Componentを利用する
[Ant Design of Angular - NG-ZORRO](https://ng.ant.design/docs/introduce/en) を参考に、Componentを利用する。


## [備考] うまくいかなかった方法
Visual Studio 2019から下記の手順で追加しようとすると、「復元中...」から先に進まずうまくいきませんでした。
設定が間違っているだけで、うまく使う方法があるのかもしれません。

1. `ClientApp`のフォルダ上で右クリック
2. `追加(D)` > `クライアント側のライブラリ(L)`
3. プロバイダーを`unpkg`、ライブラリを`ng-zorro-antd`で検索
4. ライブラリが表示されるまで待つ
5. ターゲットロケーションを`ClientApp/node_module/ng-zorro-antd`に設定
6. `インストール(I)`を選択
ドメインが凍結された話

開設して間もないサイトが急にアクセスできなくなった。

:small_red_triangle_down: Google Chrome での表示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236222/f35e7da2-572c-3ce8-5866-9ec9fbc386c7.png)
**NXDOMAIN**というキーワードから「あ～その名前のドメインが存在しないのだな」というのがエンジニアならピンと来るだろう。そうでなくても「IPアドレスが見つからない」とわざわざ言ってくれているのだから話が早い。
これが IE とか Edge になると「このページを表示できません」としか案内されないので、ヘルプデスクとしては Chrome を推奨したい理由のひとつにもなっている。

# ネームサーバに聞いてみよう
digコマンドでドメインを問い合わせてみる。
ちなみに、hoge.com も hogehoge.com も hogehogehoge.com も hogehogehogehoge.com も全部実在するドメインだったのは笑った。英語圏でメジャーな foo、bar、baz を組合せたドメインも実在する。

```
$ dig hogehogehogehogehoge.com

; <<>> DiG 9.11.3-1ubuntu1.11-Ubuntu <<>> hogehogehogehogehoge.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 40185
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
```

見るべきところは `status:` の直後。通常なら **NOERROR**（正常）が返るはずだが、ここが **NXDOMAIN**（名前が存在しない）になっているので名前が引けてないのは明らか。ステータスには他にも **REFUSED**（リクエスト拒否）、**FORMERR**（フォーマット不正）、**SERVFAIL**（DNSサーバ異常）などがある。

# whoisサーバに聞いてみよう
WHOIS情報はレジストリまたはレジストラが提供している。
**レジストリ**とはICANNの認定を受けドメインを管理している機関（例：JPRS）。**レジストラ**とはレジストリと登録者の間に入ってドメインの登録申請・審査・情報登録を行う事業者（例：お名前ドットコム）である。さくらインターネットなどはレジストラを通してドメインの登録・販売を行う代理店だ。

今回は、開設して間もないサイト、というのがポイント。
何らかの不備があって、レジストラがレコードを無効にした可能性がある。

```
$ whois hogehogehogehogehoge.com
   Domain Name: HOGEHOGEHOGEHOGEHOGE.COM
      :
   Registrar WHOIS Server: whois.discount-domain.com
   Registrar URL: http://gmo.jp
      :
   Registrar: GMO Internet, Inc. d/b/a Onamae.com
   Domain Status: clientHold https://icann.org/epp#clientHold
   Name Server: NS-1437.AWSDNS-51.ORG
   Name Server: NS-1701.AWSDNS-20.CO.UK
   Name Server: NS-427.AWSDNS-53.COM
   Name Server: NS-900.AWSDNS-48.NET
   DNSSEC: unsigned
   URL of the ICANN Whois Inaccuracy Complaint Form: https://www.icann.org/wicf/
```

見るべきところは `Domain Status:` の直後。
gTLDドメインやccTLDドメインの主なステータス文字列を下表に示す。汎用JPドメインはステータス文字列がちょっと違う。

|ステータス文字列|意味|
|:--------------------------|:---------------------------------------------------------------------------|
|active / ok    |ドメインは使用可能   |
|inactive    |ネームサーバが設定されていない   |
|renewPeriod   |ドメインの有効期限がレジストラによって更新された   |
|pendingRenew  |ドメインを更新するリクエストがレジストリに受信され、処理中である   |
|pendingTransfer |ドメインを新しいレジストラに移管するリクエストを受信し、処理中である  |
|clientTransferProhibited   |レジストリに対し、現在のレジストラから別のレジストラへのドメイン転送リクエストが拒否されている   |
|clientHold / serverHold   |レジストラによってドメインが停止された   |

今回は clientHold になっていた。何の事はない、アクティベーションが済んでいなかっただけだ。
[【参考】お名前ドットコム ヘルプサポート](https://help.onamae.com/answer/15333)

クレジットカード決済をした人（購入手続きをした人）にメールが届いているはずなので、メール本文に記載のURLへアクセスし、認証を完了してもらった。
本番移行前だったので、事なきを得たが、代金未払いとかでも起こり得る話なので、いざという時のためにも切り分け方は覚えておくと良い。

迷惑メール等を恐れ、whoisに架空のメールアドレスや住所を登録する人もいるらしいが、近年レジストリによるチェックが厳しくなっており、存在しない情報を登録したまま放置すると、ある日突然ドメインが停止されることもある。
気をつけよう。
EMR? Kinesis?

## 参考
https://dev.classmethod.jp/cloud/aws/emr-dynamo/
https://cloud-textbook.com/8/#emr
https://cloud-textbook.com/8/#kinesis
https://www.slideshare.net/AmazonWebServicesJapan/aws-black-belt-tech-amazon-kinesis

### Amazon Elastic MapReduce (EMR) とは
AWS 上で Hadoop や、Hive や、Apache Spark を簡単に使う仕組み。 何ができるかと言うと、Hadoop や Spark を使って、ビッグデータの分散処理が行える。 Hadoop は、複数マシンにデータを分散させて MapReduce ができる仕組み。 Hive は Hadoop を SQL で操作可能にする仕組み・ Spark は MapReduce 部分の代替品でオンメモリにより高速化するのが狙い。 向き不向きはあるものの、一般的には Amazon Redshift の方が高速かつ高額という評価らしい。

### Amazon Kinesis Data Analytics は、
ストリームデータを SQL で処理することができる。 分析結果を S3 や Redshift に格納することができる。 また、SQL で一定条件のものを抽出し、再度 Kinesis Streams に流して、Lambda で処理し、通知したり DynamoDB や RDS に反映させたりすることができる。

※https://www.slideshare.net/AmazonWebServicesJapan/aws-black-belt-tech-amazon-kinesis より
![aws-black-belt-tech-amazon-kinesis-12-638.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153684/4c35415b-f5dd-dfde-825b-b3b16aa618c8.jpeg)
VirtualBox+Vagrantを用いた仮想環境構築を行いHelloWorldを出力するまで

# はじめに
VirtualBox+Vagrantを用いた仮想環境構築を学習したく
ドットインストールをベースにVagrant上のファイルをVisual Studio Codeで編集して
HelloWorldを出力するまでのメモです。

# 目標
VirtualBox+Vagrantにて仮想OSを構築する。
Visual Studio Codeを使用して仮想OS上でファイル作成する。
HelloWorldを出力する。

# 手順
## VirtualBoxをインストール
https://www.virtualbox.org/wiki/Download_Old_Builds_6_0

## Vagrantをインストール
https://www.vagrantup.com/

### vagrant up ができなかった
Vagrantが最新版のVirtualboxを認識していないとのこと
下記記事を参考に設定ファイルを書き換えました。
[[Mac] Vagrant 2.2.6 と Virtualbox 6.1でうまくvagrant up ができなかった時の対処法](https://qiita.com/shuu1222/items/7a6d04172363be44025c)

## Visual Studio Code をインストール
https://code.visualstudio.com/

### Vagrant上のファイルをVisual Studio Codeで編集
下記記事を参考にしました。
[Vagrant上のファイルをVScodeで編集 for Mac（初学者向けの注釈付記レポート）](https://qiita.com/seeden/items/15111f3ddc9ef4b06e7e)

## Rubyをインストール
下記記事を参考にしました。
[CentOSにrbenv, Rubyをインストールする](https://qiita.com/NaokiIshimura/items/ff04b6eaa40b33c4bea8)


#参考情報
[ローカル開発環境の構築 [macOS編]](https://dotinstall.com/lessons/basic_localdev_mac_v2)
[[Mac] Vagrant 2.2.6 と Virtualbox 6.1でうまくvagrant up ができなかった時の対処法](https://qiita.com/shuu1222/items/7a6d04172363be44025c)
[Vagrant上のファイルをVScodeで編集 for Mac（初学者向けの注釈付記レポート）](https://qiita.com/seeden/items/15111f3ddc9ef4b06e7e)
[CentOSにrbenv, Rubyをインストールする](https://qiita.com/NaokiIshimura/items/ff04b6eaa40b33c4bea8)
netaddrでアドレス集約

##前提
本稿はnetaddrでアドレスの集約やソートを行うための手引きです。
下記環境で構築していますが、Linuxで構築した場合もコマンドは全く同じです　

Windows10 64bit
Anaconda3
https://www.python.jp/install/anaconda/windows/install.html

##準備
###netaddrインストール
Anaconda Prompt起動
\> pip install netaddr

###netaddrインストール(ローカル資材)
下記サイトで資材(wheel)をダウンロード
https://pypi.org/
資材：netaddr-0.7.19-py2.py3-none-any.whl (1.6 MB)

Anaconda Prompt起動し、資材を格納している場所へ移動
\> cd downloads
ファイル名を指定してインストール
\> pip install netaddr-0.7.19-py2.py3-none-any.whl

##使い方

###1.アドレス集約
\> python
\>>> from netaddr import *
\>>> import random
\>>> import pprint
\>>> ip_list = [
IPNetwork('192.168.1.0/24'),
IPNetwork('192.168.0.0/24'),
IPNetwork('10.20.30.0/24'),
IPNetwork('10.0.0.0/8')
]
\>>> random.shuffle(ip_list)
\>>> ip_list.sort()
\>>> pprint.pprint(cidr_merge(ip_list))
####出力
[IPNetwork('10.0.0.0/8'), IPNetwork('192.168.0.0/23')]
※出力が3つ未満の場合1行で表示される

###2.アドレスソート(昇順)
\> python
\>>> from netaddr import *
\>>> import random
\>>> import pprint
\>>> ip_list = [
IPNetwork('192.168.1.0/24'),
IPNetwork('192.168.0.0/24'),
IPNetwork('10.20.30.0/24'),
IPNetwork('10.0.0.0/8')
]
\>>> random.shuffle(ip_list)
\>>> ip_list.sort()
\>>> pprint.pprint(ip_list)
####出力
[IPNetwork('10.0.0.0/8'),
IPNetwork('10.20.30.0/24'),
IPNetwork('192.168.0.0/24'),
IPNetwork('192.168.1.0/24')]
※出力が3つ以上の場合複数行で表示される

###3.mask → prefix
\> python
\>>> from netaddr import *
\>>> ip_list = [
IPNetwork('192.168.24.0/255.255.255.0'),
IPNetwork('192.168.24.0/255.255.255.128'),
IPNetwork('192.168.24.0/255.255.255.192'),
IPNetwork('192.168.24.252/30')
]
\>>> for i in ip_list:
...   print(i)
...   (enter)
※for文の中は半角スペースでインデント
####出力
192.168.24.0/24
192.168.24.0/25
192.168.24.0/26
192.168.24.252/30

###4.prefix → mask
\> python
\>>> from netaddr import *
\>>> ip_list = [
IPNetwork('192.168.24.0/255.255.255.0'),
IPNetwork('192.168.24.0/255.255.255.128'),
IPNetwork('192.168.24.0/255.255.255.192'),
IPNetwork('192.168.24.252/30')
]
\>>> for i in ip_list:
...   print(str(i.ip)+'/'+str(i.netmask))
...   (enter)
※for文の中は半角スペースでインデント
####出力
192.168.24.0/255.255.255.0
192.168.24.0/255.255.255.128
192.168.24.0/255.255.255.192
192.168.24.252/255.255.255.252

##参考
https://netaddr.readthedocs.io/en/latest/index.html
【Pythonやってみた！】「みんなPython!Python!って何なのよ！」から今日で卒業！

私がPython超初心者ですので，偉そうなことは言えないのですが，
本日は，最近流行りの「Python」について，ざっくりとどんなもんかお話できればと思います．

この記事を読んで，「みんなPython!Python!って何なのよ！」という悶々とした日々の気持ちから，
今日でめでたくご卒業される方が増えることを切に願っています．

##■Pythonって何？
端的に申しますと，Pythonはプログラミング言語です．
wikipediaから引用させていただきますが，
私が思うPythonの利点は下記３つです．
（１）無料で始めることができる
（２）無料のパッケージが色々ある
（３）統計解析に使いやすい

上記３つとも，流行した要因になっていると思いますが，
（３）はわりと大きい要因である気がします．

##■統計解析に使いやすいことがどうしてPythonが流行することにつながるの？
ここ最近AI（人工知能）が話題になっていますが，
私の考えでは，AIの理論は，統計や数学の応用です．
したがって，AIの注目度に比例して統計解析が得意なPythonも注目度が上がっているのではないでしょうか．

##■AIとか機械学習とか少し興味あるけど，難しそうやから私には無理でしょう？
私はそうは思いません．
文系，理系関係ないと思っています．
私も初心者ですので，一緒に頑張りましょう！！

##■Pythonのソースコードってどんななの？どうせ，難しいのでしょう？
ちょっと，命令文と実行結果の例を記載しますので，ご覧ください．

【命令文１】

```
print("Hello,Python!")
```
【実行結果１】

```
Hello,Python!
```

どうでしょうか...？すみません．これでは実感がわきませんね...

【命令文２】

```
df['Age'].hist()
plt.show()
```

【実行結果２】
※タイタニックデータ（Kaggleより入手）の「Age」データを使用
　横軸：年齢
　縦軸：数（人）
![ヒストグラム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573636/aa4cfb38-e732-727b-4930-89d60c96b22d.png)


どうでしょうか？
難しいかどうかは，人それぞれですが，
2行の命令で，ヒストグラムという，統計分析では欠かすことのできない，立派な統計分析の結果（図）を出力できます．

先程のPythonの利点には挙げていませんでしたが，
シンプルな命令文で統計的な解析が可能なことも，
Pythonの利点だと考えられます．

##■Python興味あるけど，何から始めればいいかわからん！
おすすめは，今すぐ，Pythonを自分のPCにインストールして
（私はwindowsのノートPCにインストールしてます），
手を動かしながら学んでいくことです．
幸運なことに，インターネットが充実しているこの時代ですから，
無料のデータと無料の教材がネット中にあふれています．
もちろん，PythonをPCにインストールする方法もネット中にあります！
（私もそれを頼りにPCの環境を整えました！）

##■何を目標にしたらいい？
私自身は，
世界的なデータ分析コンペである「Kaggle」に参加すること！と，
日本のデータ分析コンペである「SIGNATE」に参加すること！を目標にしています．

##■結論
Pythonはシンプルなプログラミング言語で，統計解析が得意です．
少しでも興味があれば，今すぐ自分のPCにインストールしてデータを分析することをおすすめいたします．

##■最後に
本日も最後までお読みいただきありがとうございました．
なんだか，Pythonの説明から話がそれた気もしますが...
Python興味あるのに，踏み出せない人がいるとしたら，とてももったいないという気持ちに駆られて，
今回の記事を書いてみました．
よかったら，「いいね！」を頂けると，投稿の励みになりますので，
お願いいたします．
お叱りも受け付けます．（毎度のこと，受付方法が分かっていませんが...）
またどこかでお会いしましょう！
さようなら～（^^）／”