OmniAICreator/Qiita-1.07M huggingface dataset:
Flask migrateでcolumn typeの更新が検知されない場合の対処方法

## TL; DR
`env.py`を直接書き換えて再度`flask db migrate`を実行します[^1]。

[^1]: https://github.com/miguelgrinberg/Flask-Migrate/issues/24

## 詳細


`env.py`中の`run_migrations_online()`関数を以下のように書き換えます。

```python

def run_migrations_online():

# ・・・省略
 context.configure(
            connection=connection,
            target_metadata=target_metadata,
            compare_type=True, # ←これを追加します
            process_revision_directives=process_revision_directives,
            **current_app.extensions['migrate'].configure_args
        )
# ・・・省略
```

## 検索用
### 変更が検知されない場合のコンソール出力
```
INFO  [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO  [alembic.runtime.migration] Will assume transactional DDL.
INFO  [alembic.env] No changes in schema detected.
```
cronを間違って消さないようにするには愛が必要

### はじめに
初めてQiitaで記事を書きます。
Qiitaに記事を書いていただいている皆様にはいつもお世話になっています。ありがとうございます。

## 概要

Linuxでcronを触っているとcronを消しそうになったことがあると思います。
（消しちゃったこともある方もいるかも...）

`消しちゃったときにどうするか`というよりは`消さないようにするにはどうすれば`という内容です。

※`消しちゃったときにどうするか`は調べたら先人が対策を様々な方法を考えていらっしゃるので、そちらを調べてみてください


## 結論
crontabコマンドには必ず`-i`オプションを付けた状態にしておく。
(削除の予防する)

## 背景

`cron`を編集するとき、

```
crontab -e
```

と直接やることも多々あるかと思います。
（最近は直接編集したらあかん、もしくは直接サーバーに入るのがありえない、という話も上がっていますが、そんな素晴らしい環境ばかりではありませんので）

ドキドキするのが、オプション指定のときの`-e`やるとき。
キーボードの右隣にこいつがいるんです。`r`

御存知の通り`crontab -r`ってやるとcron全部消えちゃうんですよね。
そもそも、なんで事故ってください、というキー配列のオプション指定にしてるのよ、という気持ちもありますが現実はそうなんです。


## 対策

### 1. crontabのオプションを調べる

linuxのコマンドラインで`man crontab`(cronの説明書き)と実行すると英語でこんなのが書いてあります。

```
-i     This  option  modifies  the  -r  option to prompt the user for a
       'y/Y' response before actually removing the crontab.
```

英語はちょっとわからないのですが、

```
-iオプション　-rオプションでcron消す前にyとかYとかで答えないと消さないようにするよ
```

みたいなことが書いてあります。
こいつは使える。

ちょっとやってみますね。（間違っても本番環境でテストしないこと）

```
$ crontab -ir
crontab: really delete hogehoge's crontab?
```

hogehoge部分はユーザー名です。
このあと「やっべ」と`ctrl+c`で抜けてもらえればセーフです。
`y`とか`Y`とか押したらcronが消えますが、そこまでやるのであればもう知りません。

毎度

```
crontab -ie
```

って押せばOK。
間違えて右隣の恐ろしいキーを押しても、

```
crontab -ir
```

で聞いてくれるのでセーフ。
でもちょっとスマートじゃない。というかめんどい。
そもそも`-i`なんてついてて困ることは無さそうだし。
（`-l`のときは`-il`と書いても「ほんとに消していいかい？」と聞かれることはありません）

### 2. エイリアス
Linuxにはエイリアス(alias)っていうのがあります。
詳しくは別のサイトで調べてください。
すぐローマ字読みしてしまい、野球選手を思い出してしまうのですが（自分は神奈川の球団のファンです）

今回の例だと

```
alias crontab='crontab -i'
```

と実行すると
`crontabって実行したらcrontab -iをやったことになるぜ`
と宣言できたことになります。

そしたら、こいつをどこに宣言するか。

### 3. ~/.bash_profileに設定
自分は`~/.bash_profile`に設定しています。
ここに書くと、sshで真っ黒画面にログインするときに勝手に実行してくれます。

`~/.bashrc`ってやつもいて、ここに書いても勝手に実行してくれます。
どっちに書くかは個人の判断によります。

自分が`~/.bash_profile`に書いた理由は次のとおりです。
`man bash`(bashの説明書き)と実行すると

```
~/.bash_profile
       The personal initialization file, executed for login shells
~/.bashrc
       The individual per-interactive-shell startup file
```

って書いてあります。翻訳はしないです。
今回は

* サーバーにsshログインするときに適用したい
* それ以降は別に適用する必要もない

ということで`~/.bash_profile`に追記することにしました。

## まとめ

やることは以下です。
`~/.bash_profile`に`alias crontab='crontab -i'`を追記する
（ユーザーごとに設定が必要）
何が起きても責任持てませんので、テストしてください。

## 最後に

cronにドキドキする時間を減らしましょう。
中級者以上になるために行っている学習

# 概要
Webエンジニアとして実務経験は数年ありますが、今の自分はまだプログラマーとして初心者レベルだと思っています。
仕事はなんとかこなしていますが、一歩上にあがる必要を感じています。

そこで、どのような学習をすべきかを考え実践中なので共有したいと思いました。

## なぜ自分を初心者レベルだと思うのか？
海外のコンピューター専門の大学（カリフォルニア工科大学、スタンフォード大学、MITなど）では、一学期でコンパイラを作成するとのことです。
ドラゴンブックやタイガーブックなどを教科書として使っていると小耳に挟みました。
それらの本を買って読んでみましたがかなり難しいと感じました。
しっかりコンピューターサイエンスを学んでいる学生さんはレベルがかなり高いと感じています。

一方そのころ、日本人である自分は英語から学ばないといけないという。。。
２０代後半からコンピューターを学び始めたにわかの自分にとっては、この差を埋めるのはかなり至難だと思っています。

高度な設計もできないですし、オブジェクト指向でコードを書くこともできません。
これからはちゃんと設計ができ品質の良いコードをかける人が生き残ると勝手に予想しています。

## 使う側から作る側へいかないと厳しそう
今は先人たちや優秀な人が作ってくれたフレームワーク、ライブラリなどを「使う側」です。
誰かが作ってくれた便利なものを使わせてもらっている状態です。

業務では生産性が重視されるので、便利なフレームワークやライブラリなどを利用しますが、レベルの高い人材になるためには「作る側」に回らないといけないと思いました。

フレームワーク、ライブラリ、ツールなどを「作る側」になることがレベルアップへの最短の道だと考えています。

## スキルアップするために行っている学習法
### 低レイヤー
まず基本から学習することにしました。
機械語やアセンブリ言語を学びました。

アセンブリ言語は簡単と言われる方が多い印象ですが、自分はCPUのレジスタやメモリの仕組みなども知識がなかったです。
そのためアセンブリ言語は全くと言っていいほど読めなかったです。

そこでCPUの仕組みやレジスタ、スタックなどに関する学習を行いました。
そうすることで、アセンブリ言語はだいたい読めるようになり、裏側でどのようにコードが実行されているのかがわかるようになってきました。

### アルゴリズム
次に行ったのはアルゴリズムの学習です。
問題解決法であるアルゴリズムは知識として知っておくだけでも全然違うとベテランの方から教わりました。

最初に学んだのは「再帰処理」です。
アルゴリズムでは、いたるところに再帰処理が使われていて、これを理解しないと次へ進めないと思ったからです。
組み合わせ問題やコンパイラの基礎などをやりました。

「末尾再帰」や「繰り返し処理と再帰処理の違い」などを理解することができました。

### 数学
アルゴルズムを学んでいると嫌という程「数学」が出てきます。
時間計算量、行列、三角関数、対数、ネイピア数など、何かしら高度なトピックには数学がからんできます。

高校の授業を寝ていた自分としてはアルゴリズムの書籍を読んでも理解ができませんでした。
数学から学びなおす必要があることに気づきます。

せめて高校レベルの数学は理解していないと、データ構造、クヌース本などの良書も読めませんでした。
数学は現在、微分、積分、対数あたりを学んでいます。

数学も公式を使って問題を解けるというレベルではなく数学を理解しているレベルまで学ばないと理論を理解できないです。
先は長い。。。

### デザインパターン、リファクタリング
最後はデザインパターンとリファクタリングですが、ここまでまだ至っていません。
これまでの学習とはまた別で行う必要があると感じています。
フレームワークのお作法に沿ってコードを書いていても、大規模でないとなかなか実践で使える機会はないように思えます。
ライブライリやツールなどを「作る側」になると頻繁に活用することになりそうですが、業務でも最新の技術を追うための学習が必要です。
業務に関連しない学習を行う余裕がないのですが、その状態が良いことだとは思っていません。

具体的には設計理論を学んだり、コードを抽象化する練習になりそうです。
本当にオブジェクト指向を理解したいなら、オブジェクト指向言語のコンパイラを簡単に作ってみるのが早いと感じていますが、なかなかハードルが高いです。

「チューリングマシンとは何か？を説明してくれ」と言われても説明できません。
今すぐに結果がでなくても、学習しておくことで長期的に効果が出てくるような基礎学習もやらないといけないなと思って学習中です。

言い訳せずに日々、地道に学習を積み重ねていくことが大事だと思いました。
上を目指そうとするなら遊んでる暇ないですね。。。
TwitterでAPIを使って自分のアカウントに投稿する

久しぶりにTwitter触って、自分のアカウントに自動でツイートをPOSTする処理作ろうとしたら思いがけずはまりポイントが多かったので備忘録です。


# 手順１：Twitterアカウント作成する

普通のユーザのアカウント作成手順でOK。

電話番号で登録できるようになっていたりと色々昔と変わっていて、多少ドキドキする。


# 手順２：APIの使用申請をする

去年あたりから使用するために申請が必要になったそうで…

[Twitter API 登録 (アカウント申請方法) から承認されるまでの手順まとめ](Twitter API 登録 (アカウント申請方法) から承認されるまでの手順まとめ)

を参照させていただいてクリア。

申請ではねられないために、真面目な人に見えるよう使用目的を**多少盛り気味**に頑張って書いたんですが（文字数のボーダーライン超えるためにわざわざ迂遠な言い回し使うとか姑息な手段まで駆使）、**申請した次の瞬間承認メールが飛んできて**拍子抜け。
内容をチェックしているとしても多分絶対人力じゃなさそう。


# 手順３：アプリを作成し、認証キーを発行

べつにアプリを作るわけじゃないんだが…と不安になるのですが、認証キーの発行のためには必要なのでおそるおそる `Create New App` ボタンをクリックしてアプリを作成し認証キーを発行。
以下のページが参考になるかと。

[Twitter REST APIの使い方](https://syncer.jp/Web/API/Twitter/REST_API/)

※上記ページで、アクセストークンについて「プログラミングなしで取得する」の手順が実行できればOK。

# 手順４：投稿用のAPIを呼ぶ（Python使用）

[公式ドキュメント](https://developer.twitter.com/en/docs/basics/authentication/guides/single-user)のサンプルコードを参考に、最終的にはこんな感じ。

```python:tweet.py
def tweet(text):
    url = "https://api.twitter.com/1.1/statuses/update.json?status={}".format(text)

    consumer = oauth2.Consumer(key='手順３で取得できるConsumer API keys の API key', secret='手順３で取得できるConsumer API keys の API secret key')
    token = oauth2.Token(key='手順３で取得できるAccess token', secret='手順３で取得できるAccess token secret')
    client = oauth2.Client(consumer, token)
    resp, content = client.request( url, method="POST")
    
    return content

tweet("test")
```

実はここが**最大のハマりポイント**でした。できあがったものはとても簡単だったのですが、簡単なのにというかそれゆえにというか、これについてさくっと解説しているようなページというのがなかなか見つかりませんでした。

そもそも、ツイートの投稿が「statuses/update」というパスなのがちょっと意外でそこにもしばらくはまっていたのですが、なによりもTwitterが公開している公式ドキュメントでも検索してヒットするページも **「第三者に認証させてそのユーザのアカウントに投稿する」サービスが前提**という感じで、**シングルユーザで使いたいだけ、というのは、あまりに簡単すぎて逆にないがしろにされている感（※）**すらありました。（被害妄想中）

ともあれこれにてツイート成功です。

以上、お役に立ちましたら幸いです。

# ※余談

なおシングルユーザでのAPI使用がどれくらいないがしろにされているかといえば、[Twitterが公開している公式ドキュメントのサンプルコードにシンタックスエラーが混入している](https://developer.twitter.com/en/docs/basics/authentication/guides/single-user)レベルです。

以下は上記ページの`Using Python-OAuth2 library`からコピペしたコードですが、引数`post_body`あたりに注目してください。

```python
def oauth_req(url, key, secret, http_method="GET", post_body=””, http_headers=None):
    consumer = oauth2.Consumer(key=CONSUMER_KEY, secret=CONSUMER_SECRET)
    token = oauth2.Token(key=key, secret=secret)
    client = oauth2.Client(consumer, token)
    resp, content = client.request( url, method=http_method, body=post_body, headers=http_headers )
    return content

home_timeline = oauth_req( 'https://api.twitter.com/1.1/statuses/home_timeline.json', 'abcdefg', 'hijklmnop' )
```

もう泣いちゃうだろこんなの。
PythonでProtocolを使って静的ダック・タイピング

この記事はニフティグループ Advent Calendar 2019の14日目の記事です。
昨日は@mito1296さんの「Terraformで立てたec2インスタンスをAnsibleで管理してみる」でした。
同様の問題に以前悩まされたことがあったのでタグ付けは非常に綺麗な解決方法だなと感心しました。
機会があれば、うちのチームでも導入したいですね！！

# TD;LD
Pythonは型安全で無いので大きめのプロジェクトになると心理的な安全が担保できないので敬遠していました。
しかし、Python3.5以降typingが導入されmypyと組み合わせることで、少し大きめのプロジェクトでもコーティングする際に心理的な安全を得ることができるようになったので中規模の開発に採用できるようになりました。

今回は、python3.8から`typing.Protocol`が正式に追加されたようなので紹介してみます。

# typing.Protocolとは

詳しくは、以下を見てください。
https://docs.python.org/ja/3/library/typing.html#typing.Protocol

今までPythonでダック・タイピングをする際は`abc`を使っていたのですが。場合によっては`typing.Protocol`ほうが自然に実装できそうです。

https://qiita.com/kaneshin/items/269bc5f156d86f8a91c4
こちらの記事でも紹介されているダックタイピングの問題を解消しているのかな？と思います。

# 試してみる

Protocolの使い方は簡単で、抽象クラスとなるものに継承させればOKです。
以下の例ですと`Animal`のクラスに該当します。
`Animal`の具象クラスには`str`を返す`sound`メソッドが実装されることを期待しています。

`Dog`はキチンとダックタイピングされていますが、`Book`は`sound`が実装されておらず、`Cat`は`sound`の戻り値が誤って実装されています。

```test.py
from typing import Protocol


class Animal(Protocol):
    def sound(self) -> str:
        ...


class Dog():
    "soundが実装されている"

    def sound(self) -> str:
        return "Bow-wow"


class Book():
    "soundが実装されていない"

    def read(self) -> str:
        return "hogeeee"


class Cat():
    "soundは実装されているが、戻り値が違う"

    def sound(self) -> None:
        print("Meow")


def func(animal: Animal):
    animal.sound()


func(Dog())
func(Book())
func(Cat())
```


このコードをmypyで解析すると、きちんと解析されてErrorが出ていることが分かります。
`Cat`に至っては、詳細なエラーが出ているので誤りが非常に見つけやすくなっています。

```
$ python -m mypy test.py
test.py:35: error: Argument 1 to "func" has incompatible type "Book"; expected "Animal"
test.py:36: error: Argument 1 to "func" has incompatible type "Cat"; expected "Animal"
test.py:36: note: Following member(s) of "Cat" have conflicts:
test.py:36: note:     Expected:
test.py:36: note:         def sound(self) -> None
test.py:36: note:     Got:
test.py:36: note:         def sound(self) -> str
Found 2 errors in 1 file (checked 1 source file)
```

# 最後に
`typing.Protocol`について、簡単ですが紹介してみました。
`abc`でも似たようなことができるのですが、具象化クラスが継承する必要やアノテーションのつけ方が直感的ではないので場合によっては`typing.Protocol`を使ったほうがいいかもしれません。
主要ブラウザごとの違いについてまとめてみた

# はじめに
個人開発していると複数のブラウザを使いたくなるので今までは `Google Chrome`と `safari`と使っていたが、
`safari`がなんとも使いにくくて `firefox`に変更した。そこで唐突に「なんで使いにくいんだろう。使用感の他に何か理由があるのかな。調べてみよう」と思い立って調べてみたのがきっかけです。

## そもそもブラウザとは
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282722/2506aee3-0c51-b2e5-96a9-d05fbd553bab.png)

ブラウザとは、WEBサイトを閲覧するために使うソフトのこと。
元になる英単語は 「閲覧する」という意味の`browse` 。その名詞形である `browser`が閲覧ソフトという意味になり、
ブラウザと呼ばれているそうです。

## ブラウザの種類
ブラウザの種類は以下の通りです。    

- Google Chrome
- safari
- Firefox
- Opera
- InternetExplorer
- edge

## 注意点
１記事１ブラウザの説明とさせていただき、今回は `GoogleChrome`のみのご紹介といたします。
上記全てをまとめようとすると長くなってしまうので記事を分けたいと思います。
記事が出来次第、そのブラウザと関連リンクとして下部にリンクを貼っておきます。

## Google Chrome
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282722/702c1726-a085-5361-a501-66efcb37e1f2.png)
 `Google Chrome` とはgoogleが2008年に公開したWebブラウザです。
それまでのWebブラウザのシェアトップは、InternetExplolerでしたが、今や日本国内、世界ともにGoogle Chromeが過半数のシェアを占めています。

`Google Chrome`の特徴とは、起動速度や読み込み速度が驚異的には早いこと、高機能でありながらシンプルな作りになっていて感覚的に操作が可能なことが挙げられます。

### 端末間の同期が可能

端末間の同期が可能で、どの端末のWebブラウザでも同じ情報を見れるというシームレスな使い方ができるWebブラウザでもあります。

### 拡張機能が豊富
「chromeウェブストア」から様々な拡張機能が提供されています。
Googleが提供しているものや、Evern otなどの有名なアプリケーションを連動するための拡張機能、他にもGoogle Chtomeの画面キャプチャやブックマークを管理するための拡張機能など、様々なものがあります。
ほとんどは無料でインストールできますが、一部の拡張機能は有料で提供されています。

### データセーバー
`Google Chrome`のデータセーバーは、ウェブトラフィックの大部分をGoogleサーバーに経由させてから端末にダウンロードできるようになります。
Googleサーバーではデータの圧縮が行われるため、端末にダウンロードされるデータ量が少なくなる。
 `Google Chrome`のデータ使用量を減らすと、通信料を抑えることができ、接続層度が遅い環境でウェブページの読み込み時間を短縮できるようになります。

### セキュリティが高い
 `Google Chrome`はセキュリティに詳しくなくても誰もが安全・簡単にウェブを利用できるように設計されています。
セーフブラウジングという技術が採用されており、不正なソフトウェア、フィッシングといった何者かからの一連の攻撃からユーザーを保護し、
パスワードの盗難や端末のウイルス感染を防止してくれます。
他にも疑わしいサイトにアクセスしようとすると警告メッセージが表示される仕様になっています。

### まとめ
世間一般で一番使われている `Google Chrome`　今回はその一部を紹介いたしました。
速くて拡張機能でカスタマイズできると言った感じですかね。その裏にデータセーバやセキュリティが備わっていることから運用が楽なのかもしれません。
次回以降は他のブラウザも紹介していきたいと思います。それでは。

### 参考文献
[「ブラウザとはいったい何？」初心者の疑問を解決！](https://tone.ne.jp/column/howtouse/whatsbrowser-beginner-smartphone/)
[Google Chrome(グーグルクローム)とは？使い方の基本も解説](https://appli-world.jp/posts/1537)
あれ？.bash_profileや.bashrcが効いてないな？って思った時に読む記事

[Macのバージョンアップに伴い、bashからzsh切り替わる](https://applech2.com/archives/201910-macos-10-15-catalina-default-shell-zsh.html)とターミナルの$が、%になるんやけどここで気づいて欲しいのは僕らの「~/.bash_profile」はどうなったんやということ
[bashからzshに移行メモ](https://qiita.com/hiroyuki827/items/4e87ce517a4894f092e8)にあるようにシンプルにとりあえず丸コピーでいいわっていう人はこれ

```  Bash:bash
$ cat .bash_profile >> .zprofile
```

なんやったら。あの上書きされると困る人もいるので一応[追記コマンド](https://hacknote.jp/archives/13756/)にしてます

```  Bash:bash
$ cat .bashrc >> .zshrc
```

#余談
あと余談なんやけどpyenvを入れた後に上記作業もやってると色々面倒で以下のようなことが起きてた
python2>3自動切り替えされんなんや分からんとりま「pyenv init」や

``` Zsh:zsh
 ~ % pyenv init
# Load pyenv automatically by appending
# the following to ~/.zshrc:

eval "$(pyenv init -)"
```

親切に「~/.zshrcに追加しろ！」って教えてくれるんですね。
なので、cat使って一行で追加すると

```  
echo "eval \"\$(pyenv init -)\""  >> .zshrc
```
前提環境：zsh

#蛇足
あれお前profileに追記してないやんけという人はこちら
[本当に正しい .bashrc と .bash_profile の使ひ分け](
https://qiita.com/magicant/items/d3bb7ea1192e63fba850)

いまさらですがzshって2013年には切り替えよっていわれてたんですね

[コマンド - とりあえずZshを使えば良いんだろう？ - Qiita](
http://qiita.com/ktr_type23/items/3eb782f98c7a5f4c60b0)
Python学習ノート_003

本の第一章のサンプルコードを理解した上で練習のために下記のように修正しました。

- ポイント：
 - バックスラッシュ（\）を使う（Macには「option + ¥」で入力する）
 - 文字列中にバックスラッシュを使うと改行後のスペースもそのまま出力される
 - ２つ改行した文字列の間にバックスラッシュを使うとスペースなしで連結できる

```python:sample_01.py
import random

#リストを定義する
subjects = ['私\
            は','あな\
            たは']
verbs = ['好き'\
         'です',
         '嫌い'\
         'です']
nouns = ['夏が','秋が']

#リストから１つ要素を選ぶ
subject = random.choice(subjects)
verb = random.choice(verbs)
noun = random.choice(nouns)

#単語を連結してフレーズを作る
phrase = subject + ' ' + noun + ' ' + verb

#フレーズを出力する
print(phrase)

#出力結果の１つ
#あな            たは 秋が 好きです
```
🌴【SourceTree】SourceTreeでBranchしてPushができなかった為、Git Bashで対応した

## 2020/06/25追記

こちらの方法で対応可能でした
https://qiita.com/nmss208/items/a212c242da64dce89332


## 環境

SourceTree
Windows 10
Git Bash 


## やったこと
 
ローカルでmasterからhoge/fuga branchを作成したのでリモートにpushしようとした

### SourceTreeにてBranchを追加してPush

```
The リモートブランチ '' (ローカルブランチ = 'hoge/fuga') is invalid. Ref names must follow git ref-format rules: 
https://www.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html
エラー終了しました。エラーの内容は上記をご覧ください。

```

　→✖リモートブランチが空白になっている（未作成だから？）

↓

### Git Bashで単純なgit push実行

```
$ git push
fatal: The current branch hoge/fuga has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin hoge/fuga

```

　→✖upstreamでないため実行コマンドを提示された

↓

### --set-upstreamを付加してコマンド実行

```
$ git push --set-upstream hoge/fuga master
fatal: 'hoge/fuga' does not appear to be a git repository
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

```

　→✖だめでした...

↓

### -u(追跡オプション)をつけてコマンド実行

```
$ git push -u origin hoge/fuga
```

　→🔵push成功！
レポート(深層学習)



###入力層～中間層
中間層は、隠れ層ともいう。
ニューラルネットワークは、層から層へ、値を変換していく。
層と層の間にあるノード間の結合は、一つ一つが重みを持っている。

総入力＝（重み×入力）の合計＋バイアス
Pythonでの入力：u1=np.dot(x,W1) + b1
→内積をとる際、数字をそろえる
→3*4 4*3


複数の項目を入力層にて入力し、次の層へ伝達
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491045/839c775d-8378-9ea5-7320-eba05bbbff85.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491045/c347e703-21e6-e19e-1b2f-42f331f33389.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491045/fcc34625-9005-cabd-4963-15b3effd5aad.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491045/609804ef-da36-979b-554f-9722c6011385.png)


###活性化関数 
中間層用の活性化関数

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491045/4e70e889-4976-695d-6db1-90659595772e.png)
➡Z1 = function.sigmoid(u)

ステップ関数
　→しきい値を超えたら発火する関数であり、 出力は常に１か０。
　　パーセプトロン（ニューラルネットワークの前身）で利用された。
　→線形分離可能しか学習できない

ReLU関数
　→今最も使われている活性化関数
　　勾配消失問題の回避とスパース化に貢献する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491045/7c3970aa-2982-dcc8-2dd4-7e4b5df16088.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491045/5f1392d6-c640-126c-6615-6785ee21398e.png)



シグモイド（ロジスティック）関数
　→0 ~ 1の間を緩やかに変化する関数
　→勾配消失問題を引き起こすことがある
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491045/dca43738-be5f-3a20-449b-c255e433e4d6.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491045/bc73ff89-6c3c-8ada-aea8-03ccb5cdc175.png)


###出力層

　誤差関数
→ある測定値が正規分布で与えられる場合に、その測定値が −aから aの範囲にある確率

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491045/fb95721f-9161-b36d-f727-9a96a175064c.png)
➡誤差関数に平均二乗誤差を用いている

ソフトマックス関数
→ソフトマックス関数の出力は0~1の実数値に落とし込むことができる

出力層の活性化関数
　　・中間層： しきい値の前後で信号の強弱を調整
　　・出力層： 信号の大きさ（比率）はそのままに変換
　　→出力層と中間層で利用される活性化関数が異なる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491045/96048bad-1f5a-6d09-8bbf-93a947106835.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491045/3bba5470-a2d7-6caf-8120-a970988c083d.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491045/f338957e-9970-678a-0063-1e466937552e.png)


###勾配降下法 

学習率の値によって、学習の効率が大きく異なる
学習率が大きすぎる場合：最小値にいつもでもたどり着かず発散

学習率が小さい場合：小さすぎると収束に時間がかかる

普通の勾配降下法のことをバッチ勾配降下法といい、確率的勾配降下法のことをオンライン勾配降下法ということがある。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491045/29a07fbd-8b3b-6d84-a8f3-84b96174acf0.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491045/4535cc90-f0c9-b2db-df8b-0139173848f7.png)


###誤差逆伝播法
算出された誤差を、出力層側から順に微分し、前の層前の層へと伝播。
教師データと実際と出力データとの間に生じる誤差情報を使ってネットワーク全体を学習する。
最小限の計算で各パラメータでの微分値を解析的に計算する手法
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491045/7f32489b-6395-1a5e-31bc-0c78dc9d6056.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491045/b745c68b-895d-8f60-7a44-07a393a1ce7c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491045/b63f76c6-9149-4f28-1926-4e1b068c8b2b.png)
Linux（CentOS）構築

※セキュリティ等は考慮しておりません

selinuxを無効にする

```
# vi /etc/selinux/config

# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#     enforcing - SELinux security policy is enforced.
#     permissive - SELinux prints warnings instead of enforcing.
#     disabled - No SELinux policy is loaded.
SELINUX=disabled 
# SELINUXTYPE= can take one of three values:
#     targeted - Targeted processes are protected,
#     minimum - Modification of targeted policy. Only selected processes are protected.
#     mls - Multi Level Security protection.
SELINUXTYPE=targeted
```

SELINUX=`disabled`に変更する

firewallサービスを無効にする

```
# systemctl disable firewalld

以下のコマンドで状態確認可能
# firewall-cmd --state
not running
```

タイムゾーンを日本時間にする

```
# timedatectl set-timezone Asia/Tokyo

以下のコマンドで確認
# timedatectl
```

ロケールを日本語にする

```
# localectl set-locale LANG=ja_JP.utf8

以下のコマンドで確認する
# localectl
```

```
# localedef -f UTF-8 -i ja_JP ja_JP.utf8
```

日本語レイアウトのキーマップに変更する

```
# localectl set-keymap jp106

以下のコマンドで確認する
# localectl
```
ユーザーコミュニティ：UiPath Friends

#はじめに
皆さん こんにちは！
RPA界隈のガヤ担当：Dです。
技術的なネタは他の方にお任せし、私からは別の視点から「UiPath」に関する投稿を。

それでは、いってみましょう！

#その名は『UiPath Friends』
UiPath社が”オフィシャルにサポートしている”　ユーザーコミュニティ！
それが【UiPath Friends】です。
皆さん、ご存知でしょうか？
~~知らない方は本投稿で理解して下さいね。~~
![UF_header.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365842/edae389b-fa7c-e61d-0130-030cee0a7d2c.jpeg)

#で、何やってるの？
活動内容は以下の通り。
ぶっちゃけた話、[RPACommunity](https://rpacommunity.connpass.com/) とあまり変わりが無い…。
 1. ユーザーによるLT
 2. UiPath 最新情報の展開
 3. 懇親会

**ただ、「UiPathFriends」ならでは【独自性】を出そうと日々努力しております！**
※乞うご期待！
![UFT02_集合.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365842/1b83e973-f4d6-1c81-4297-ed3e10aa141a.jpeg)
↑ 写真は先日行われた【UiPath Friends 2nd】の集合写真です。

#派生イベント
UiPathFriends では、東京で開催している「本体」以外にも色々なイベントを企画 ＆ 実施。
※今回は各イベントの詳細は省略！
1. UiPathわちゃわちゃ会
2. 女子会
3. ハンズオン会
![KD.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365842/5bc95c6c-0739-653b-d0a6-f27b6be0dc0e.png)

#参加条件は？
**誰でもOK**

#参加方法は？
DoorKeeperに [UiPathFriends](https://uipath-friends.doorkeeper.jp/) があります。
イベント参加に問わず、UiPathユーザーなら　**まずは登録すべし！！**

#UiPath社のポジションは？
下記のポイントでサポートしてもらっています。
1. イベント会場（費用
2. 懇親会（費用
3. UiPath最新情報の提供
4. イベント当日のロジまわり
5. ノベルティ提供
**★いつも、ありがとうございます★**
![nobelty.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365842/5200991d-a7b5-fb02-91a2-e4439b919431.png)
※写真はイメージです。

#UiPathFriends の存在意義
UiPathの最新情報が得られたり、ノベルティが貰えるのは当然うれしいし有意義なことなのですが、
最大の魅力は**【UiPathユーザーとのリアルな交流】**です。
1. UiPath MVP と直接話せる！
2. SNSで気になる「あのヒト」に会える！
3. 単純に新たな出会いがある！
4. UiPathFriendsメンバー全員で盛り上げる「一体感」！！

特にNo.4は高校生時代、クラス全員で頑張った「文化祭」や「部活動」に似た感覚がありますね★
**※個人の主観です**

#最後に
『コミュニティ』に参加した事が無い方は色々と躊躇するポイントがあると思います。

「なじめないかも」
「他人に話しかけられない…」
「盛り上がれないかも」

わかります。
**スゴクわかります！！**

私も初参加したコミュニティイベントでは、懇親会で誰とも会話できず、
少し寂しい気持ちで帰宅しました。

それでも実業務で UiPath を利用している事もあり、イベント参加の回数を重ねるうちに
気持ちが変わっていったんです。
**少し寂しい ⇒ 楽しいかも ⇒ 楽しい！**
**LT登壇者ってスゴイな ⇒ 私もやってみたい ⇒ LT楽しい！**

是非、UiPathユーザーの皆様、 [UiPathFriends](https://uipath-friends.doorkeeper.jp/) に参加してみて下さい。
一緒に楽しんで、学んで、情報共有して行けたら、最高です。

それでは、次回の UiPath Friends でお会いしましょう★
<img width="576" alt="loveUipath.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365842/0c89383d-c262-38a3-64ad-e9f65d60f3eb.png">
AWS CLIのコマンド補完する設定


## Zshに設定する


パスを確認する

```
$ which aws_completer 
/usr/local/bin/aws_completer
```

`.zshrc`に以下追加する

```
source '/usr/local/bin/aws_zsh_completer.sh'
```

`.zshrc`の内容を反映する。

```
source ~/.zshrc
```

## Bashに設定する

パスを確認する。

```
$ which aws_bash_completer
/usr/local/bin/aws_bash_completer
```

`.bashrc`に以下追加する。

```
complete -C '/usr/local/aws/bin/aws_completer' aws
```

`.bashrc`の内容を反映する。

```
source ~/.bashrc
```
Cell tombstones

CassandraのCell tombstonesについて

Cell tombstoneは、特定のセルの削除で生成するtombstone

### before

```
cqlsh:sitest01>  select * from test_tomb where pkey1 = 'rei' and pkey2 =1;

 pkey1 | pkey2 | skey1 | v1
-------+-------+-------+---------------------
   rei |     1 |     1 |              Bombay
   rei |     1 |     2 | Brazilian Shorthair

(2 rows)

  {
    "partition" : {
      "key" : [ "rei", "1" ],
      "position" : 290
    },
    "rows" : [
      {
        "type" : "row",
        "position" : 336,
        "clustering" : [ 1 ],
        "liveness_info" : { "tstamp" : "2019-12-15T08:45:48.827508Z" },
        "cells" : [
          { "name" : "v1", "value" : "Bombay" }
        ]
      },
      {
        "type" : "row",
        "position" : 336,
        "clustering" : [ 2 ],
        "liveness_info" : { "tstamp" : "2019-12-15T08:45:48.833270Z" },
        "cells" : [
          { "name" : "v1", "value" : "Brazilian Shorthair" }
        ]
      }
    ]
  }

```

### delete

```
cqlsh:sitest01> delete v1 from test_tomb where pkey1 = 'rei' and pkey2 =1 and skey1 = 1;
```

### after

```
cqlsh:sitest01>  select * from test_tomb where pkey1 = 'rei' and pkey2 =1;

 pkey1 | pkey2 | skey1 | v1
-------+-------+-------+---------------------
   rei |     1 |     1 |                null
   rei |     1 |     2 | Brazilian Shorthair

(2 rows)

  {
    "partition" : {
      "key" : [ "rei", "1" ],
      "position" : 290
    },
    "rows" : [
      {
        "type" : "row",
        "position" : 335,
        "clustering" : [ 1 ],
        "liveness_info" : { "tstamp" : "2019-12-15T08:45:48.827508Z" },
        "cells" : [
          { "name" : "v1", "deletion_info" : { "local_delete_time" : "2019-12-15T09:04:53Z" },
            "tstamp" : "2019-12-15T09:04:53.756348Z"
          }
        ]
      },
      {
        "type" : "row",
        "position" : 335,
        "clustering" : [ 2 ],
        "liveness_info" : { "tstamp" : "2019-12-15T08:45:48.833270Z" },
        "cells" : [
          { "name" : "v1", "value" : "Brazilian Shorthair" }
        ]
      }
    ]
  }


Estimated tombstone drop times:
1576400700:         1

```
Row tombstones

CassandraのRow tombstonesについて

Row tombstoneは、パーティションの特定行の削除で生成するtombstone

### before

```
cqlsh:sitest01>  select * from test_tomb where pkey1 = 'rei' and pkey2 =1;

 pkey1 | pkey2 | skey1 | v1
-------+-------+-------+---------------------
   rei |     1 |     1 |              Bombay
   rei |     1 |     2 | Brazilian Shorthair

(2 rows)

  {
    "partition" : {
      "key" : [ "rei", "1" ],
      "position" : 290
    },
    "rows" : [
      {
        "type" : "row",
        "position" : 336,
        "clustering" : [ 1 ],
        "liveness_info" : { "tstamp" : "2019-12-15T08:45:48.827508Z" },
        "cells" : [
          { "name" : "v1", "value" : "Bombay" }
        ]
      },
      {
        "type" : "row",
        "position" : 336,
        "clustering" : [ 2 ],
        "liveness_info" : { "tstamp" : "2019-12-15T08:45:48.833270Z" },
        "cells" : [
          { "name" : "v1", "value" : "Brazilian Shorthair" }
        ]
      }
    ]
  },

```

### delete

```
cqlsh:sitest01> delete from test_tomb where pkey1 = 'rei' and pkey2 =1 and skey1 = 1;
```

### after

```
cqlsh:sitest01>  select * from test_tomb where pkey1 = 'rei' and pkey2 =1;

 pkey1 | pkey2 | skey1 | v1
-------+-------+-------+---------------------
   rei |     1 |     2 | Brazilian Shorthair

(1 rows)

  {
    "partition" : {
      "key" : [ "rei", "1" ],
      "position" : 291
    },
    "rows" : [
      {
        "type" : "row",
        "position" : 332,
        "clustering" : [ 1 ],
        "deletion_info" : { "marked_deleted" : "2019-12-15T09:18:36.270399Z", "local_delete_time" : "2019-12-15T09:18:36Z" },
        "cells" : [ ]
      },
      {
        "type" : "row",
        "position" : 332,
        "clustering" : [ 2 ],
        "liveness_info" : { "tstamp" : "2019-12-15T09:16:08.359657Z" },
        "cells" : [
          { "name" : "v1", "value" : "Brazilian Shorthair" }
        ]
      }
    ]
  }

Estimated tombstone drop times:
1576401540:         1

```
Partition tombstones

CassandraのPartition tombstonesについて

Partition tombstoneは、パーティションの削除で生成するtombstone

### before

```
cqlsh:sitest01>  select * from test_tomb where pkey1 = 'rei' and pkey2 =1;

 pkey1 | pkey2 | skey1 | v1
-------+-------+-------+---------------------
   rei |     1 |     1 |              Bombay
   rei |     1 |     2 | Brazilian Shorthair

(2 rows)

  {
    "partition" : {
      "key" : [ "rei", "1" ],
      "position" : 290
    },
    "rows" : [
      {
        "type" : "row",
        "position" : 336,
        "clustering" : [ 1 ],
        "liveness_info" : { "tstamp" : "2019-12-15T08:45:48.827508Z" },
        "cells" : [
          { "name" : "v1", "value" : "Bombay" }
        ]
      },
      {
        "type" : "row",
        "position" : 336,
        "clustering" : [ 2 ],
        "liveness_info" : { "tstamp" : "2019-12-15T08:45:48.833270Z" },
        "cells" : [
          { "name" : "v1", "value" : "Brazilian Shorthair" }
        ]
      }
    ]
  },

```

### delete

```
cqlsh:sitest01> delete from test_tomb where pkey1 = 'rei' and pkey2 =1;
```

### after

```
cqlsh:sitest01> select * from test_tomb where pkey1 = 'rei' and pkey2 =1;

 pkey1 | pkey2 | skey1 | v1
-------+-------+-------+----

(0 rows)

  {
    "partition" : {
      "key" : [ "rei", "1" ],
      "position" : 290,
      "deletion_info" : { "marked_deleted" : "2019-12-15T09:31:53.167848Z", "local_delete_time" : "2019-12-15T09:31:53Z" }
    },
    "rows" : [ ]
  },

Estimated tombstone drop times:
1576402320:         1

```
HTMLのtextarea でインデント、アンインデント

# HTMLのtextarea でインデント、アンインデント

HTMLのtextareaでタブを入力すると次のフィールドにフォーカスが移動しますが、そのままタブを入力したい。ついでに複数行選択しているときは、まとめてインデントしたい。更にスペースでのインデント、アンインデントにも対応したい。
ということで、書いてみました。
作ってから IE/Edge で setRangeText がサポートされていない事に気づいたけれど、このまま載せておきます．．．

```html:indent_sample.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta http-equiv="Content-Type" context="text/html; charset=UTF-8" />
  <meta charset="UTF-8" />
  <title>インデントのサンプル</title>
<script type="text/javascript">
'use strict';

window.onload = function() {
	const onKeyDown = function(ev) {
		if (((ev.keyCode != 9) && (ev.keyCode != 32)) || ev.ctrlKey || ev.altKey) { return true; }
		ev.preventDefault();
		const str = (ev.keyCode == 32) ? " " : "\t", TABWIDTH = 4, CRLF = [13, 10];
		let e = ev.target, start = e.selectionStart, end = e.selectionEnd, sContents = e.value, top = e.scrollTop;
		if ((start == end) || !sContents.includes("\n")) {
			e.setRangeText(str, start, end, "end");
			return;
		}
		if (CRLF.indexOf(sContents.charCodeAt(end - 1)) < 0) {
			for ( ; end < sContents.length; end++) {
				if (CRLF.indexOf(sContents.charCodeAt(end)) >= 0) { break; }
			}
		}
		for ( ; start > 0; start--) {
			if (CRLF.indexOf(sContents.charCodeAt(start - 1)) >= 0) { break; }
		}
		let v = sContents.substring(start, end).split("\n");
		for (let i = 0; i < v.length; i++) {
			if (v[i] == "") { continue; }
			if (!ev.shiftKey) {		//indent
				v[i] = str + v[i];
			} else {				//unindent
				if (str == "\t") {
					for (let j = 0, c = " "; (j < TABWIDTH) && (c == " "); j++) {
						c = v[i].substring(0, 1);
						if ((c == " ") || (j == 0 && c == "\t")) { v[i] = v[i].substring(1); }
					}
				} else if (v[i].substring(0, 1) == " ") {
					v[i] = v[i].substring(1);
				}
			}
		}
		e.setRangeText(v.join("\n"), start, end, "select");
	}

	document.getElementById("txtSample").addEventListener("keydown", onKeyDown);
}
</script>
</head>
<body>
<ul>
<li>文字列を未選択でスペース → スペース入力</li>
<li>文字列を未選択でタブ → タブ入力</li>
<li>文字列を選択してスペース → スペースインデント</li>
<li>文字列を選択してタブ → タブインデント</li>
<li>文字列を選択してシフト＋スペース → スペースアンインデント</li>
<li>文字列を選択してシフト＋タブ → タブアンインデント</li>
</ul>
<textarea id="txtSample" rows="30" style="width:100%;resize:none;"></textarea>
</body>
</html>
```
型シノニムでString型に命を吹き込む

# はじめに

[いなたつアドカレ](https://qiita.com/advent-calendar/2019/allinatatsu)の十五日目の記事です。

Haskellいいぞって布教したいので簡単なところで魅力を感じてもらいたいので、、、


# 型シノニムってなんぞ

Haskellには型に別名シノニムをつけることができます。
型シノニムそのものには特になにもありませんが、型シノニムがあることで、String型に意味を与えられます。

# 実例
Char型の配列をString型として扱っている言語はよくあると思います。これをHaskell流に書くと以下のようになります。

```hs
type String = [Char]
```
これだけで、Char型配列にStringと言う名前を与えられます。
Stringという型はChar型の配列と同意義であることを定義しました。


# String型に意味を持たせる

```hs
type FirstName = String -- 名前
type LastName = String -- 苗字
type FullName = (FirstName, LastName) -- 苗字,名前
```

人の名前は文字列なので、String型ですんr、しかしこれをString型と言ってしまうと味気がありません。同じString型でも、FirstNameって意味を持つString型ですよ、
って明示できると読みやすくて人間にやさしいですよね。

FullName型はつまるところString型とString型のタプルですね。。。

# 関数に適用する

では、先ほど作った型を関数に適用させていきます。

まずはString型を使った読みにくい例

```hs
toFullName :: String -> String -> (String, String)
toFullName firstName lastName = (firstName, LastName)
```
これでは引数のどちらが苗字でどちらが名前、そして返り値もどちらがどっちかよくわからないですね。

型シノニムを使って書き換えます、

```hs
toFullName :: FirstName -> LastName -> FullName
toFullName firstName lastName -> (firstName, lastName)
```

これだと型定義をみた瞬間に引数のじゅんばんが　わかりますね！！
戻り値の中身の順番もFullNameの型を見ると順番がわかります。とても人間に優しいですね！！

# おわりに

Haskellをすこれ
ECSでTCPソケットエラー 事象と対応

# ECS　+ Nginx,GunicornでTCPソケットエラー

- Jmeterで負荷をかけると503 Bad Gatewayが多発した
- どうやらECSには以下の制約があるそう。

 `net.core.somaxconn=128`
 `現時点では Fargate では変更できないので、タスクを多く起動して頂くことで解決して下さい。`
[【週刊 Ask An Expert #04】AWS Loft Tokyo で受けた質問まとめ #AWSLoft](https://aws.amazon.com/jp/blogs/startup/weekly-aae-04/)

- 他にもDBのチューニングも考慮した方が良い

 `ディスクI/O`
 `RDSのパフォーマンスインサイトでIndexの分析`
　 `パフォーマンスインサイトではIndexの使用率やクエリの結果が確認可能`

# 対応方法の検討
1 ECSを予め増やしておく
 一番ナンセンスだが、即時で対応が可能。
 ELB + ECSの環境であれば、最小コンテナ数と最大コンテナ数の設定を変えるだけで済む。必要に応じて、ELBのPre-Warmingをすること！

2 ELBでのコネクション数を閾値にコンテナを動的に増やす
 ELBのActiveConnectionCountを閾値にして、コンテナ数を増やす。
 `ECSのポリシーの追加-アラームを追加で設定できる`

3 スケジューリングでECSをオートスケールする
 利用開始時間の前にECSをスケールアウトさせておく。
 `アプリケーションオートスケーリング-lambda-コンテナの数`


# 余談
EC2の監視間隔はデフォルトで5分間隔だが、ECSはデフォルト1分間隔で監視できる。
JavaScriptで配列の要素の重複をチェックする

業務で学んだJavaScriptで配列の要素の重複をチェックする方法について書きます。


## コード

引数で渡した配列の要素に重複がある場合、`true`を返します。重複がない場合は、`false`を返します。

```javascript
function isDuplicated(elements) {
  // Setを使って、配列の要素を一意にする
  const setElements = new Set(elements);
  return setElements.size !== elements.length;
}
```

### Setについて
##### Setオブジェクト
> プリミティブ値・オブジェクト参照を問わず、あらゆる型で一意の値を格納できます。

```javascript
const setElements = new Set([1, 2, 3, 3]);

console.log(setElements);
// => Set { 1, 2, 3 }

setElements.size;
// => 3
```

#####Setの要素数の求め方
> Set に含まれる要素の数を知りたい場合は Set.prototype.size を使います。

```javascript
const setElements = new Set([1, 2, 3, 3]);

setElements.size;
// => 3

setElements.length;
// -> undefined
// lengthは使うことができない
```

### 例

```javascript
// 重複がある場合
const foods = ["りんご", "ケーキ", "ブロッコリー", "りんご"];

console.log(isDuplicated(foods));
// => true

// 重複がない場合
const countries = ["日本", "アメリカ", "中国", "インド"];

console.log(isDuplicated(countries));
// => false
```
　
以上です！この記事が役に立つと嬉しいです！

## 参考
- [Set - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Set)
SPA作成に特化した静的型付け言語Mintをご紹介します。

**Mint** という名前のプログラミング言語がありますので、ご紹介します。

公式サイトは、[https://www.mint-lang.com/](https://www.mint-lang.com/) になります。

# ググラビリティめっちゃ低いやんけ

`Mint` で検索すると、Googleなら葉っぱのミントやLinux Mint、地元のなにかしらの店舗などが上位にヒットします。

そこで`mintlang`で検索すると、ようやくトップに出てきます。なんでこんな名前にしたのやら。

また Qiita 内では探した限り、「[Mint - SPA に特化した言語](https://qiita.com/acro5piano/items/021a5696c25afeeba59a)」という一記事しか見つかりませんでした。

# おいおい、出遅れとるやんけ

先の記事は2018年7月に書かれています。2019年12月現在、Mintのバージョンは0.7.0で、まだまだ開発中という状態です。

一年半出遅れていて今さら何を紹介するのかと言ったら、もうちょっと深く掘り下げるしかありませんね。

# ざっくり特徴いうたろやないけ

MintLangには以下のような特徴があります。

* 強い静的型付け言語
* Mint言語自体がCrystal言語で作られていて、そのためコンパイル速度が爆速
* `mint`コマンドにコンパイル、サーバ機能、テストランナー、フォーマッタが全部含まれている
* ほかにもいろいろ組み込まれている
    * スコープが限定されたCSSスタイリング
    * 状態管理
    * ルーティング
* 変数はイミュータブル
* 同期・非同期処理をかんたんに使える
* すべてが表現（詳細はのちほど）

# 小ネタを出したろやないけ

ちなみに、先ほどご紹介した[公式サイト](https://www.mint-lang.com/)自体も、Mint言語で記述されています。[https://github.com/mint-lang/mint-website](https://github.com/mint-lang/mint-website)

# インスコしよやないけ

インストールは簡単です。[https://www.mint-lang.com/install](https://www.mint-lang.com/install)から実行バイナリをダウンロードして、適切なPATHに置くだけです。

Windowsでは今のところDockerなりなにがしかの仮想環境で使用することを推奨します。WSLでは、罠があります（後述）。

# 使こてみよやないけ

`init`コマンドで、新規プロジェクトを作成します。

```
mint init my-app
```

以下のようなファイルが生成されます。

```
my-app
├── source
│   └── Main.mint
├── tests
│   └── Main.mint
├── .gitignore
└── mint.json
```
my-appディレクトリ内で、`mint start`でサーバが起動します。[^1]

[^1]: WSL上ではサーバが起動しないという[Known Issue](https://github.com/mint-lang/mint/issues/54)があります。v0.7.1（2019/12/15）時点では、Windows環境の方はDockerかvagrantか、何かしらの仮想環境で実行する必要があります。

# 言語としてどないやっちゅー話やんけ

`mint init`で作成されるScaffoldは、以下のようなコードです。

```
component Main {
  style base {
    font-family: sans;
    font-weight: bold;
    font-size: 50px;

    justify-content: center;
    align-items: center;
    display: flex;
    height: 100vh;
    width: 100vw;
  }

  fun render : Html {
    <div::base>
      "Hello Mint!"
    </div>
  }
}
```

Styleとタグがひとつのコンポーネントとしてまとまっていることが分かるかと思います。

# で、VueとかReactと比べたらどないやねん

いや、それはもちろん色々ライブラリが揃っているという意味でVueやReactの方が現時点では使い勝手や表現の豊富さでは勝っています。

その分、コントリビュートのチャンスはMintの方が余地が残っていると言えます。

**Mintの今後にご期待ください！！**
.msixbundle ってなんだ？

[Microsoft の GitHub から Windows Terminal のプレリリース版を入手する](https://github.com/microsoft/terminal/releases)と、インストーラとして `.msixbundle` 形式のファイルが提供されていることがわかります。この見慣れない[^0] 拡張子はいったい何者なのでしょうか？

[^0]: 主観です

## MSIX パッケージ

前段として、MSIX パッケージに触れなければなりません。MSIX パッケージは Windows 10 v1809 から利用可能になった新しいインストーラ形式です。[^2]

[^2]: v1709 および v1803でもサポートされていますが、ダブルクリックからのインストールができない等の制約があります。また、`.msixbundle` 形式がサポートされていません。

以下にMicrosoft公式の説明を引用します：

> あらゆる Windows アプリに最新のパッケージ化エクスペリエンスを提供する Windows アプリ パッケージ形式です。 MSIX パッケージ形式では、Win32、WPF、および WinForm の各アプリに対して新たな、最新のパッケージ化および展開機能が有効になるだけでなく、既存のアプリ パッケージとインストール ファイルの機能が維持されます。 [^3]

[^3]: https://docs.microsoft.com/ja-jp/windows/msix/overview

具体的には、[MSIX Packaging Tool](https://www.microsoft.com/p/msix-packaging-tool/9n5lw3jbcxkf) を利用することで、 従来型の各種インストーラ( `.msi` 形式だけではなく、任意の実行形式ファイルやインストール用バッチファイルも含みます) を MSIX パッケージとして出力することができます。

MSIX パッケージは WEB 等を通じて自由に配布を行うことができるほか、Microsoft Store での配布が可能となります。適当な自家製インストールバッチにも電子署名を追加できたり、良い感じの GUI を付け加えたりできたりするのは嬉しいですね。[^0]

## MSIX パッケージのバンドル

`.msixbundle` は複数アーキテクチャ向けの MSIX パッケージを一つのファイルにバンドルしたものです。[^1] 

[^1]: 見た目からも明らかではありますが。

Windows 10 は複数のアーキテクチャ（ x86、 x64 そして ARM ）上で動作します。各アーキテクチャ向けのインストーラは別々の MSIX パッケージを用意しなければなりませんが、それらを MSIX パッケージバンドルにまとめることができます。`.msixbundle` の作成には Windows 10 SDK の [`MakeAppx.exe`](https://docs.microsoft.com/ja-jp/windows/msix/packaging-tool/bundle-msix-packages) を利用します。

`.msixbundle` ファイルの実態は Zip 形式のアーカイブであり、Zip ファイルとして取り扱うことでファイルの抽出を行うことができます。[^4]

![msixbundled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463374/689fa9c1-fcc0-c00a-dcb2-56a35a188d7f.png)


[^4]: ただし暗号化が行われている場合、この限りではありません。

Windows Terminal の場合、3 アーキテクチャ向けの MSIX パッケージが 1 つの `.msixbundle` ファイルにバンドルされていたことがわかります。`.msixbundle` ファイルをダブルクリックして実行すると、環境に応じた `.msix` ファイルが呼び出されます。Microsoft Store に登録するファイルの数を減らすことができるほか、WEB 上の配布についても、ユーザにアーキテクチャの違いを意識させないで済むメリットがあります。

## 参考リンク

* [MSIX ドキュメント](https://docs.microsoft.com/ja-jp/windows/msix/)
* [[DesktopBridge] 非UWP(WPF等)をパッケージする方法のまとめ](https://qiita.com/tera1707/items/78cdd03419b1f3cf707e)
起動中のDockerコンテナのstdinに入力する

# 概要
こんにちは、haniokasaiです。
Dockerでdocker attach するとき、インタラクティブに操作できるのはpid 1だけです。[^1]
通常それで困りませんが、私は困りました。
私のコンテナではDockerfileはシェルスクリプトを呼び出し、そのシェルスクリプトがPHP CGIを実行します。その場合は、phpのpidは1ではないので入力するすべがありません。（出力はattachで見れます。）
ですので、stdinに直接入力してあげました。

# 環境
- Ubuntu 18.04 on XFS
- Docker

# ホスト to コンテナのstdin

*注意*
docker attachはしていても構いませんが、interactiveにはしないでください。
していると、stdinは「Text file busy」と返して成立しません。
attach時には以下のようにします。（この場合はattachではstdinを受けません。attachかファイル直接入力かどちらかを選ぶということ。）

```bash:attach
docker -H DOCKERHOST attach コンテナ名 --no-stdin
```

まず、topで標準入力先のpidを確認します。

```bash
# docker top zzzzzzzz_container
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                25312               25287               0                   16:09               ?                   00:00:00            /bin/sh -c sh /minecraft/resources/run-Main.sh
root                25366               25312               0                   16:10               ?                   00:00:00            sh /minecraft/resources/run-Main.sh
root                25434               25366               0                   16:10               ?                   00:00:00            sh /minecraft/resources/run-BE-BDS.sh
root                25472               25434               13                  16:10               ?                   00:14:22            /minecraft/bin/bedrock_server
```

標準入力をコマンドで実行します

```bash
# echo "help" > /proc/25472/fd/0
```

helpをbedrock_serverに標準入力すると、ヘルプがちゃんと返されます。

```bash
# docker logs zzzzzzzz_container --tail=10
[2019-12-15 08:09:39 INFO] Player disconnected: hanicraft, xuid: 2535460621431466
§2--- Showing help page 1 of 18 (/help <page>) ---
/? [command: CommandName]
/? <page: int>
/alwaysday [lock: Boolean]
/changesetting allow-cheats <value: Boolean>
/changesetting difficulty <value: Difficulty>
/changesetting difficulty <value: int>
/clear [player: target] [itemName: Item] [data: int] [maxCount: int]
§2Tip: Use the <tab> key while typing a command to auto-complete the command or its arguments
```

# コンテナ to コンテナのstdin

送信元コンテナ作成

```
docker create --name コンテナ名 --memory=3500mb --network="host" --storage-opt size=2G  --cap-add SYS_PTRACE  -v /proc:/newproc:ro
```

注目ポイントは

- SYS_PTRACE権限の追加
- ホストの/procを/newprocとして読み取り専用でマウント

あとはさっきと同じです。

```bash:コンテナ内
# echo "help" > /newproc/25472/fd/0
```



# 利用して作ったライブラリ
@itsu_dev と作りました。
いつくんがtopのスクレイピングしてくれているので興味深いでしょう。

 - https://github.com/itsu-dev/MiRmDockerClient


# 参考文献

https://serverfault.com/questions/178457/can-i-send-some-text-to-the-stdin-of-an-active-process-running-in-a-screen-sessi
https://orebibou.com/2016/04/linux%E3%81%A7%E5%8B%95%E4%BD%9C%E4%B8%AD%E3%81%AE%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9%E3%81%AE%E5%87%BA%E5%8A%9B%E5%86%85%E5%AE%B9%E3%82%92%E3%81%BF%E3%82%8B/

# 脚注
[^1]: http://docs.docker.jp/engine/reference/commandline/attach.html
SQLをテストする

テスト、書いてますか？

私の担当業務の1つに、データマートの構築があります。
分析しやすいような分析用テーブルをいくつかのSQLを元に作っているのですが、元データ自体のバリデーションが弱かったり、ビジネスロジックが複雑ゆえ、論理エラーが多く発生していました。

そこで、Pythonの`unittest`ライブラリを活用したテストを現在は導入しています。

# 良かったこと
テストを書くことで、枕を高くして寝れるようになりました。

具体的には、
- 過去指摘された論理エラーをテストに組み込むことで再発防止になる
- 別テーブルで発生した論理エラーが起きそうなテーブルに、同じテストを組み込む
- 将来発生しうるリスクに対して予めテストを仕込んでおく

といった取り組みができており、アウトプットの品質向上につながっています。

# unittestとは
Pythonにおける標準のユニットテストフレームワークです。
テストの自動化、テストのセットアップおよびシャットダウンコードの共有、テストのコレクションへの集約、レポートフレームワークからのテストの独立性などを提供しています。
[25.3. unittest — Unit testing framework — Python 2.7.17 documentation](https://docs.python.org/2/library/unittest.html)

# テストのセットアップ
下記のように、setUpModule()関数を作れば、特別な呼び出し不要でセットアップが可能です。
今回はテストを実行したい`create table`するSQLをここで呼び出して、実際にテーブルを作成しています。
このとき、本メソッドは単にテーブルを作るだけでなく、prefixとして`test_`をつけるようにしています。

```python
def setUpModule():
    print("Setting up…")
    test_table_name = test_util.generate_test_table(executing_file_name)
```

# 実行したいテストの記述
このように、事項したいテストを`test_hoge`という形式で記述します。
`setUpModule()`によって作られたテスト用テーブルに対して集計をかけるSQLを記述しておいて、それを呼び出します。
結果は真偽値で返ってくるようにすることで、最後の`self.assertTrue()`で一律で判定しています。
ここは、より複雑な判定方法も取ること可能ですが、今回はロジックをSQL側に持たせて関心を分離しています。

```python
class TestQuery(unittest.TestCase):
    def test_mrr_growth(self):
        query = test_util.get_query_by_execution_info(executing_file_name, sys._getframe().f_code.co_name)
        rows = test_util.get_result_in_dataframe(query)
        actual = rows.iloc[0][0]
        self.assertTrue(actual)

    def test_gap_between_new_and_old_less_than_n(self):
        query = test_util.get_query_by_execution_info(executing_file_name, sys._getframe().f_code.co_name)
        rows = test_util.get_result_in_dataframe(query)
        actual = rows.iloc[0][0]
        self.assertTrue(actual)

    def test_uniqueness(self):
        query = test_util.get_query_by_execution_info(executing_file_name, sys._getframe().f_code.co_name)
        rows = test_util.get_result_in_dataframe(query)
        actual = rows.iloc[0][0]
        self.assertTrue(actual)
```

# テストのシャットダウン
最後に環境を汚さないよう、テーブルを削除して完了です。

```python
def tearDownModule():
    test_util.delete_test_table(test_table_name)
    print("Tear down.")
```

# 工夫
このようにシンプルに扱うために、上記では`test_util`という独自ライブラリを作成しています。
これは実装しているSQLスクリプトをよしなに扱うためのスクリプトです。
今回コードは公開しませんが、上記のように各`create table`スクリプトに対するテストが、シンプルに書けるような設計にしておくと良いでしょう。
これは写真なのかアニメなのか？

## はじめに
遊び（Python&機械学習の勉強）で人物の画像を入れるとそれがアニメか写真かを判断するようなことをやってみたかった:writing_hand:
顔を基準にしているので、リアルな絵を入れると写真だと判断することがあるが

## 準備
python3.x
pythonのバージョンに対応したOpenCV(参考: https://www.sejuku.net/blog/54272)
写真用アニメ用のカスケード分類器（後述）

## 実装
```
（フォルダ）img-画像置き場
（フォルダ）haarcascade-カスケード分類器置き場
（ファイル）auto_anime_classifier.py
```

これらを同一ディレクトリ内に配置

haarcascadeフォルダに置くファイルは
- haarcascade_frontalface_alt.xml
- lbpcascade_animeface.xml
この2つ
前者はOpenCVにデフォルトで入っている
後者はhttps://github.com/nagadomi/lbpcascade_animeface

```auto_anime_classifier.py
import cv2
import numpy as np

if __name__ == '__main__':

    CASCADE_PATH = 'haarcascade/'
    face_count = []

    print('Plz input filename')
    img_name = input('>> ')
    img = cv2.imread('img/'+str(img_name), cv2.IMREAD_COLOR)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    photo = cv2.CascadeClassifier(CASCADE_PATH + 'haarcascade_frontalface_alt.xml')
    anime = cv2.CascadeClassifier(CASCADE_PATH + 'lbpcascade_animeface.xml')

    face_count.append(len(photo.detectMultiScale(gray, 1.1, 3)))
    face_count.append(len(anime.detectMultiScale(gray, 1.1, 3)))

    if face_count[0] > face_count[1]:
        print('Maybe photo.')
    elif face_count[1] > face_count[0]:
        print('Maybe anime.')
        elif face_count[0] >= 1 and face_count[1] >= 1:
        print('Both attributes.')
    elif face_count[0] == 0 and face_count[1] == 0:
        print('Undeciable.')
```

## 解説
OpenCVについては解説ブログ等が山ほどある為割愛。
imgフォルダ内の画像を入力、それをimread()で読み込み。その後グレー加工する

```
print('Plz input fiｌename')
img_name = input('>> ')
img = cv2.imread('img/'+str(img_name), cv2.IMREAD_COLOR)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
```

写真、アニメそれぞれのカスケード分類ファイルを読み込んだ分類器を作成

```
photo = cv2.CascadeClassifier(CASCADE_PATH + 'haarcascade_frontalface_alt.xml')
anime = cv2.CascadeClassifier(CASCADE_PATH + 'lbpcascade_animeface.xml')
```

face_count内にそれぞれの分類器で読み取れた数を格納、これの有無が判断基準となる

```
face_count.append(len(photo.detectMultiScale(gray, 1.1, 3)))
face_count.append(len(anime.detectMultiScale(gray, 1.1, 3)))
```

最後に判断部分、シンプルに認識できているかそうでないかで比較

```
if face_count[0] > face_count[1]:
   print('Maybe photo.')
elif face_count[1] > face_count[0]:
   print('Maybe anime.')
elif face_count[0] >= 1 and face_count[1] >= 1:
   print('Both attributes.')
elif face_count[0] == 0 and face_count[1] == 0:
   print('Undeciable.')
```

現実の近さ
Maybe photo（多分実写っす） → Both attributes（どっちでもイケる） → Maybe anime（多分絵っす） → Undeciable（わからん）

![Schermafbeelding 2019-12-15 om 17.57.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212851/2181e09e-241f-42a5-0fc4-2b8a86378cb4.png)

King Of Pop Michael Jacksonです:cd:

```
Plz input filename
>> mj.jpeg
Maybe photo.
```

## 最後に
今回はただそれぞれの判断器が顔を認識できるかどうかの物だった。改良するとすれば各判断器から細かい判断要素について出力させ数値としてパラメータをつくってやる必要がありそう。
今度は画像を修正、加工しているかどうか判断するのとか作ってみたい（インスタにあげてる画像の加工の有無を暴く:cop_tone1:）
[Ruby on Rails] 他のテーブルを参照してidを取得し、外部キーとしてデータを挿入する

# 実現したい事
データを挿入するテーブルとは別のテーブルの情報を参照して、該当するデータのidを外部キーとして、元のテーブルにデータを追加する
![スクリーンショット 2019-12-15 17.32.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533650/335ca023-8bf4-cfdb-f144-2840dac78afd.png)
# 前提
テーブルは生産量のデータを持つProductions(生産量)テーブルと製品の情報を持つItems(製品)テーブルがあります。Productionsモデルには、idとamount(生産量)、Itemsテーブルと紐づけるためのItem_idを持っています。Itemsテーブルにはidとcode(製品コード)とname(製品名)のカラムを持ちます。また、Goodsテーブルにはすでに、製品の情報が入っているものとします。

#### 今しようとしている事
Productionsコントローラのcreateアクションで、Prodectionsテーブルに生産量と製品情報を追加します。
フォームでは**amount(生産量)**と**Itemsテーブルのcodeの値**を入力する形になっています(フォームでは、nameをItem_idとしています)。
この時、amount(生産量)はそのままProductionsモデルに追加できますが、item_idは外部キーなので当然そのまま入力できません。なので、**入力された値からItemsモデルのcode情報を参照して、ItemsのidをProductionsのitem_idに追加します。**
#方法
まずはフォームは簡単にこのようになっています。

```html:index.html
<%= form_for [@production], url: productions_path do |f| %>
  <%= f.text_field :amount %>
  <%= f.text_field :good_id  %>
  <%= f.submit '追加' %>
<% end %>
```
そして、コントローラのcreateアクションを以下のように書きます。

```ruby:controller/productions_controller.rb
class ProductionsController < ApplicationController
  def create
    item_id = Item.find_by(code: params[:production][:item_id]).id
    Production.create(production_params.merge(item_id: item_id))
  end

  private
  def production_params
    params.require(:production).permit(:amount)
  end
end
```
permitではamountだけを許可して、createアクション内で、find_byを用いて、**item_id = Item.find_by(code: params[:production][:item_id]).id**と記述し、Itemテーブルでデータを探して、item_idに入れ直しています。
そして、createアクションをする際に、item_idをmergeする事で外部キーとしてidの値を挿入することができました。
#### 注意点
フォームで、form_forを使っているので、値を渡すときは**params[:production][:item_id]**と書きましょう。params[:item_id]と書くと、値が渡せず、エラーになります。

#補足情報
Rails 5.0.7.2
ruby 2.5.1
MediaPipe の Hand Tracking を mac で動かす

すでにやっている人がたくさんいるけど、復習ということで。

## 環境

MacBookPro + catalina 10.15.2 + Xcode 11.3 (11C29)

## 準備

先に brew のインストールが必要。bazel のインストールで jdk8 を要求されるかもしれない(下のコマンドには含む)。 bazel を普通に brew install bazel すると 1.2.1 とかインストールされるけど、bazel のバージョンが 1.1.0 以降だとダメぽいので、公式の通りにする。これ後で何か弊害でそう。

    $ git clone https://github.com/google/mediapipe.git
    $ brew cask install homebrew/cask-versions/adoptopenjdk8
    $ brew install https://raw.githubusercontent.com/bazelbuild/homebrew-tap/f8a0fa981bcb1784a0d0823e14867b844e94fb3d/Formula/bazel.rb
    $ brew link bazel
    $ brew install opencv@3

xcode 関係で何かエラーが出たら、以下をためしてみる (自己責任で!)。

    $ sudo xcodebuild -license accept
    $ sudo xcode-select -r
    $ sudo xcode-select -p

## Hellp World のビルド

    $ export GLOG_logtostderr=1
    $ bazel run --define MEDIAPIPE_DISABLE_GPU=1     mediapipe/examples/desktop/hello_world:hello_world

Hello World が 10 回表示されたら OK。

## Hand Tracking のビルトと実行

https://github.com/google/mediapipe/blob/master/mediapipe/examples/desktop/README.md
上記 URL には次のコマンドでビルドできると書かれているけど、うちの環境では six module がないといわれて途中で止まった。

    $ bazel build -c opt mediapipe/examples/desktop/hand_tracking:hand_tracking_cpu --define MEDIAPIPE_DISABLE_GPU=1

six を pip3 でインストールしたらいけた。

    $ pip3 install six

ビルドを通ったら下記で実行できる。

    GLOG_logtostderr=1 bazel-bin/mediapipe/examples/desktop/hand_tracking/hand_tracking_cpu     --calculator_graph_config_file=mediapipe/graphs/hand_tracking/hand_tracking_desktop_live.pbtxt

5fps くらいは出てる気がする。

## Multiple Hand Tracking を試す

あっさり動いた。

    $ bazel build -c opt --define MEDIAPIPE_DISABLE_GPU=1 \
              mediapipe/examples/desktop/multi_hand_tracking:multi_hand_tracking_cpu
    $ GLOG_logtostderr=1 bazel-bin/mediapipe/examples/desktop/multi_hand_tracking/multi_hand_tracking_cpu \
    --calculator_graph_config_file=mediapipe/graphs/hand_tracking/multi_hand_tracking_desktop_live.pbtxt

## landmark データの検証

手と指の位置のデータ (landmark) を取得して、表示させてみたのが次の図。手ひとつについて21点の landmark を認識して、それぞれ0番から20番まで手の各ポイントに割り当てられているようだ。番号は固定で、手の各位置と対応している。x,y,z の座標データが含まれているが、z は常に 0 になっている、つまり、奥行は取れていない。

<img width="647" alt="pos.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/2bd5d622-5cfe-608a-5076-663516696af1.png">

データもシンプルで使い勝手もいいので、いろいろできそうな気がしてきた。すごいよね google の人たち。