OmniAICreator/Qiita-1.07M huggingface dataset:
AWS API GatewayのAPIタイプ概要

## 動機

AWS API Gateway を触る機会があったので、メモする。REST API と HTTP API の機能比較を簡単にまとめる。

## REST API と HTTP API の概要

[よくある質問](https://aws.amazon.com/jp/api-gateway/faqs/)から抜粋した内容を下記に記載する。

> HTTP API は次のような場合に適しています。
1. AWS Lambda または HTTP エンドポイント用のプロキシ API を構築する
2. OIDC および OAuth2 の認証を備えた最新の API を構築する 
3. 非常に大規模になる可能性があるワークロード
4. レイテンシーに敏感なワークロード用の API

> REST API は次のような場合に適しています。
1. API の構築、管理、公開に必要なすべての機能が含まれているセットに対して単一価格の支払いを希望されるお客様。 

HTTP API は REST API と比較して機能を絞っている分、低レイテンシー低コストをウリとしているらしい。レイテンシーの差異について解説しているドキュメントは見つけられなかったが、料金については [Amazon API Gateway の料金](https://aws.amazon.com/jp/api-gateway/pricing/)に記載があり、単純計算で HTTP API の場合 REST API の約1/3のコストとなるようだ。

## REST API と HTTP API の比較

基本的な機能比較は[Choosing Between HTTP APIs and REST APIs](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-vs-rest.html)に書いてある。その他、気になった点について記載する。

### レスポンステンプレート

* REST API
レスポンステンプレート（[Gateway Response](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-gatewayResponse-definition.html)）が提供されており、レスポンス構造のカスタマイズができる。

* HTTP API
テンプレートが提供されていないので変更することはできない。例えば認証に失敗した場合に返すJSONオブジェクトのキーはデフォルトの値から変更できず、下記のようになる。

```json
{ "message": "Missing Authentication Token" }
```

### バックエンドに設定できるHTTPエンドポイント

REST API は VPC LinkによりVPC内にあるプライベートなHTTPエンドポイントへのリクエストを可能にする。[Set up API Gateway Private Integrations](https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-private-integration.html)
HTTP API でもつい数日前にβ版が取れ、REST API と同機能を利用できるようになったらしい。試してはいない。[Working with VPC Links for HTTP APIs](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-vpc-links.html)

## その他

ドキュメント内容に差分があり、多少混乱した。日本版ドキュメントは更新が遅いようなので参考程度に留めておくべき。

* [Amazon API Gateway とは?](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/welcome.html)
<img width="1434" alt="Screen Shot 2020-03-19 at 14.27.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170953/4aa3ccad-f0f0-e087-b89d-dfa1f91d8d6b.png">

* [What Is Amazon API Gateway?](https://docs.aws.amazon.com/apigateway/latest/developerguide/welcome.html)
<img width="1432" alt="Screen Shot 2020-03-19 at 14.28.01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170953/a8e1bbae-bba0-15ee-b741-e7c99917b721.png">

## 所感

REST API と HTTP APIの機能差分はより細かくあるはずなので、随時更新したい。
Automation Anywhere A2019 でトリガー実行中はブラウザーを開いておく必要はある？

Automation Anywhere A2019で実装されているトリガー機能 (ファイルやフォルダーの作成/削除/変更など)は、アクションリストの最初 (開始アイコンの前) にトリガーを挿入して保存してから**「トリガーで実行」**で起動します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479715/f1711fb0-1c9d-8454-d3ae-cde52c50d366.png)

トリガーを実行すると、**「トリガーをリッスンしています...」**という画面がブラウザー上で表示されて、アイコンがくるくる回ったままの画面になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479715/67aa08dd-ad17-7b50-4166-0f3ae627a4bf.png)

この後、このブラウザー画面を閉じて別の作業をしてもいいのか、タイムアウトでControl Roomからログオフしてしまったらどうなるのか、そもそもブラウザー自体を閉じてしまったらトリガーは動くのか...と心配になると思います。

さて、ここで問題です。
### このブラウザー画面を閉じてしまってもトリガー機能は動くと思いますか？

### <font color="Red">答えはYesです！</font>

おさらいをしておくと、ここで作成したトリガーはデスクトップにある「log.txt」(最初はサイズ0)というファイルが変更されたらトリガーを実行してメッセージボックスを表示する、という内容です。

いま、トリガーを実行したControl Roomのブラウザーを閉じた状態です。デスクトップにあるlog.txtを開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479715/33925efe-4c52-371e-ca55-c7685777cc48.png)

ひとまず、log.txtの中身はブランクです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479715/7ee23ab7-3528-53fa-6123-c1f4c6f3e5e0.png)

メモ帳の中にとりあえず適当な文字を入力します。この後`Ctrl`+`S`を押して保存します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479715/89a524df-a240-5b4f-b4da-0eecfc3a8686.png)

すると、しばらくして画面右下にBot Agentの進行画面が起動。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479715/7da1445c-0829-1a6f-09e0-11b0e1e652b4.png)

メッセージボックスが表示されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479715/2de70116-ab6b-37de-fb99-d6a0d2ecf7fa.png)

このことから、トリガー起動後、ブラウザー画面を閉じてもトリガーはちゃんと動作していることがわかります。

※ブラウザーを閉じても動く理由ですが、Automation Anywhere A2019を動かしているPCには、Bot Agentをインストールしますが、これはバックグラウンドでサービスとして常に起動しています。トリガーが実行されると、Bot Agentがシステムの状態を監視して、条件を満たしたらBotを起動しているということですね！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479715/9ea8c081-aa7a-6647-9906-32a0e0959f62.png)

※ トリガーをリッスンしている間に、そのPCで別のBotが実行されたとしても、その後でリッスンしている条件がヒットすればトリガーが実行されます。(ただし、同時に実行されるタイミングになると、片方がエラーになってしまいます)


>注: ただし、現状動きが不安定 (トリガー起動してこないことも...)なのと、トリガーを起動した後に一覧を見る方法がいまのところなさそうなのは改善してほしいところです。
PySpark DataFrameのgroupByでAUCを算出する(pandas_udfで集計関数を定義する)

# はじめに

PySparkでAUCを算出する際、`BinaryClassificationEvaluator`クラスを利用すれば簡単に求めることが出来る。
ただし、そのままではモデル間の違いを把握するために、テストデータ全体ではなく、セグメントごとにAUCを算出したいというニーズに対応することが出来ない。

この対処法として、`pandas_udf`を使ってAUCを算出する集計関数を定義し、`agg`メソッドで算出することを行った。

#　実装例

サンプルは以下の通り。

事前に正解ラベル(`true`)と予測スコア(`pred`)を算出の上、それを参照してAUCを算出する集計関数を定義している。

`agg`メソッドの中で、`pandas_udf`で定義した集計関数は、sparkで用意された集計関数と併用することはできないので注意。
(併用しようとすると、`Cannot use a mixture of aggregate function and group aggregate pandas UDF`というエラーが出る)


```python:UDF定義
from sklearn.metrics import roc_auc_score
from pyspark.sql.types import DoubleType
from pyspark.sql.functions import pandas_udf, PandasUDFType


@pandas_udf(DoubleType(), functionType=PandasUDFType.GROUPED_AGG)
def auc_udf(true, pred):
    return roc_auc_score(true, pred)

```

```python:算出方法
data.groupBy(key).agg(auc_udf('true', 'pred').alias('auc'))
```



# 参考

- [Sparkでpandas UDFを利用する](https://qiita.com/paulxll/items/98cd3d3d8adbf6197660)
- [apache spark - Applying UDFs on GroupedData in PySpark (with functioning python example)](https://stackoverflow.com/questions/40006395/applying-udfs-on-groupeddata-in-pyspark-with-functioning-python-example)
【Python】QRコードをインメモリに生成


QRコードを生成しAPI等で返したり、メール送信する場合、
一度ファイルにセーブし、それを読み出ししたりする処理が入ります。
この処理の場合、I/Oでの速度的問題や、並列処理時に問題が生じます。

`BytesIO`モジュールを使えば、一度ファイルに吐き出すことなく、インメモリに画像を生成出来ます。


## 環境

- Python 3.7.4
- qrcode 6.1
- Pillow 7.0.0

qrcodeおよびPillowライブラリが必要です。

```ｓｈ
pip install qrcode pillow
```

## 生成


```python
from io import BytesIO
import base64
import qrcode


class QRImage():

    @staticmethod
    def to_bytes(text: str) -> bytes:
        stream = BytesIO()
        img = qrcode.make(text)
        img.save(fp, "PNG")
        stream.seek(0)
        byte_img = stream.read()
        stream.close()
        return byte_img

    @classmethod
    def to_b64(cls, text: str) -> bytes:
        byte = cls.to_bytes(text)
        return base64.b64encode(byte).decode("utf-8")

if __name__ == "__main__":
    binary = QRImage.to_bytes(text="some_text")
    base64_encoded = QRImage.to_b64(text="some_text")
```

`BytesIO()`でバイナリストリームを生成、ファイルストリームのようにmakeやread、saveを行うだけです。


StringIO等も存在し、stringを格納することが出来ます。
また、with構文もサポートしています。

```python
from io import StringIO

def main():
    with StringIO() as fp:
        fp.write("Hello")
        print(fp.closed)     # True
        print(fp.getvalue()) # Hello
    print(fp.closed)         # False

main()
```


これで中間ファイルとはおさらばしましょう。
アプリづくりを通して、感染症を考えてみた


コロナです。


最近、コロナウイルスがはやっていて、僕のアカウント名が危機にさらされています
そんな時に、けど「数値だけ見たら」インフルエンザや花粉が大ごとだなーとか考えていました

今来ている「東京」では、花粉症が結構多いと聞きました。
そこで、

## 花粉の情報を調べられるアプリを考えてみよう！？

・コロナウイルスほどじゃないですが、「空気」に関するお勉強を兼ねて、花粉を調べられるアプリを作ったら、今の時期いいのでは！？

・過去の業務実績にある「緯度と経度のプログラムデモ」として説明がしやすいと考えて

### 対象とした人

・花粉症に悩まされている人
・これから花粉の強い地域へ行く人

対象となる方のイメージイラスト

![kafun_kusyami.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45396/5175f7fc-c2d2-019e-5333-abfd1f286898.png)


＊ゲームじゃない

## 本アプリの想定シナリオ

出かけるときの一シナリオを図形にしてみたのでご参照ください

![Untitled Diagram (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45396/a5057dbf-5843-a035-284c-b431ff3fa476.png)

## ここで大事な体験

・花粉情報っておまけだから、聞かないことが多い
・人は文字だけだと、苦痛なのでスルーする層がいる
　→画像やゲームに近い表現にすることで認識してもらおうという試み

## 技術構成
フロントツール　Unity
天気情報取得元 https://lab.life-socket.jp/life_socket
モデリング Vroidで髪型を調整したり

## 実際に作ってみた


ビデオ(クリックすると、youtubeに飛びます)

[![ビデオが開けなかった場合に表示されるテキスト](http://img.youtube.com/vi/JN1GhaYUc60/0.jpg)](http://www.youtube.com/watch?v=JN1GhaYUc60)



## アプリの操作内容
　1.地名をクリック
　2.クリックした地名に移動して、花粉情報を取得する
　3.取得した花粉情報を取得する
　4.花粉の強さは0～4で返ってくる
　5.かえってきた花粉の強さに応じて、アプリ内の空に花粉を発生させた

## システムイメージ図

![Untitled Diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45396/4f063488-8633-1193-0d45-eb0429d9d76b.png)


＊キャラクターが巨大化しているのは当時「無観客」が話題になっていたので、観客が多かったら巨大化するキャラクターを作ってみようと個人の趣味で実装していた演出です。

## 位置情報の設定方法（今回はコード内)

```C#
    // 都道府県ごとの地域情報
    LocationData[] locations = new LocationData[] {
        // 東京
        new LocationData( 35.6895f, 139.6917f),
        // 北海道
        new LocationData( 43.062f, 141.3543f),
        // 名古屋
        new LocationData(35.1814f, 136.9063f),
        // 神奈川
        new LocationData(35.4475f, 139.6423f),
        // 和歌山
        new LocationData( 34.2259f, 135.1675f),
        // 栃木
        new LocationData(36.5657f, 139.8835)

    };
```


## 今日改めて撮影を

今日お世話になっている会社で「花粉症」の話が出ているのでデプロイしたアプリを起動して、見てみました

ビデオ(クリックすると、youtubeに飛びます)

[![ビデオが開けなかった場合に表示されるテキスト](http://img.youtube.com/vi/1JMJzsPVlTU/0.jpg)](http://www.youtube.com/watch?v=1JMJzsPVlTU)



関東の花粉が紫色の濃い紫を表しているのを確認できました。


## 感想と宣伝

・位置情報＋時間で変わる情報について、意外と覚えていて実装もすんなりできた

・ご興味のあるかたは交流してください

・業務機密があるため、サンプルの動画やデモ＋NDA後に技術的な部分だけをお話をさせていただくようになります

### こんなことに応用できます

・よく行く場所で花粉対策が必要な時期なのか
・旅行に行きたい場所の確認
・花粉症に弱いので家に出る前に知っておきたい

googlemapだと、以下の数値と差し替えて対応できます

東京駅の例

url

https://www.google.com/maps/place/%E6%9D%B1%E4%BA%AC%E9%A7%85/@35.6812362,139.7671248,17z/data=!3m1!4b1!4m5!3m4!1s0x60188bfbd89f700b:0x277c49ba34ed38!8m2!3d35.6812362!4d139.7671248

埋め込み方として以下の情報で場所を指定するようになっています

35.681をlat
139.767をlon

「〇〇に使えないかな」一部カスタマイズ等のご相談や雑談も待っています



## イラストの参考元

https://www.irasutoya.com/2015/03/blog-post_94.html
クラウドネイティブでよく聞くサービス概要

## CNCFとは

CNCF（Cloud Native Computing Foundation）とはinux Foundationのプロジェクトで、コンテナ技術の発展と、その進化に関連するテクノロジ業界の連携を支援するための団体。

https://labs.mobingi.com/cncf/

## ✨ Kubernetes

* 公式: https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/
* ジャンル: オーケストレーションツール
* GitHub: [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes)
* 実装言語: Go
* 概要: コンテナ化したアプリケーションのデプロイ、スケーリング、および管理を行うための、オープンソースのコンテナオーケストレーションシステム
* 参考: https://qiita.com/Kta-M/items/ce475c0063d3d3f36d5d

## ✨ containerd

* 公式:
* ジャンル: Container Runtime
* GitHub: https://github.com/containerd/containerd
* 実装言語: Go
* 概要: OCI Runtime Specificationに基づいて作られたKubernetesやDockerの高レベルなランタイム
* 参考: https://qiita.com/mamomamo/items/ed5db2ab1555078f8a24

## ✨Envoy

* 公式: https://www.envoyproxy.io/
* ジャンル: Service Proxy
* GitHub: [envoyproxy/envoy](https://github.com/envoyproxy/envoy)
* 実装言語: C++
* 概要: Webサービスのためのロードバランサー
* 参考: https://i-beam.org/2019/01/22/hello-envoy/

## ✨ Prometheus

* 公式: https://prometheus.io/
* ジャンル: Monitoring
* GitHub: [prometheus/prometheus](https://github.com/prometheus/prometheus)
* 実装言語: Go
* 概要: サーバーやインフラなどの監視ツール
* 参考: https://knowledge.sakura.ad.jp/11633/

## ✨ Grafana

* 公式: https://grafana.com/
* ジャンル: Monitoring
* GitHub: [grafana/grafana](https://github.com/grafana/grafana)
* 実装言語: Go
* 概要: 
* 参考: https://qiita.com/MahoTakara/items/7b414c2a0d47e75d7234

## ✨Fluentd

* 公式: https://www.fluentd.org/
* ジャンル: Logging
* GitHub: [fluent/fluentd](https://github.com/fluent/fluentd)
* 実装言語: Ruby 
* 概要: 
* 参考: https://qiita.com/ritorut18/items/4230ec6b524be15ede01
Railsで、どちらか一方のカラムを入力必須（二者択一）にするバリデーション

## はじめに
Ruby on Rails で どちらか一方のカラムを入力必須にするバリデーションについて書きます。

具体的な例をあげると、ユーザーモデルの`email`と`phone`、どちらか片方だけに必ず値が入るようにバリデーションします。両方に値が入っている場合もNGです。

## 要件に合わなかったバリデーション
ググって下記のようなバリデーションを見つけましたが、両方入力した場合にバリデーションを通ってしまうので、要件には合いません。

```ruby:app/models/user.rb
class User < ApplicationRecord
  # phoneが空ならば、emailを必須にする
  validates :email, presence: true, unless: :phone?

  # emailが空ならば、phoneを必須にする
  validates :phone, presence: true, unless: :email?
end
```

```ruby
User.create!(name: "たなか", email: "test@example.com", phone: "08011112222")

=> #<User id: 1, name: "たなか", email: "tanaka@example.com", phone: "08011112222", created_at: "2020-03-19 12:29:20", updated_at: "2020-03-19 12:29:20">

```

## 要件にあったバリデーション
要件を満たすために、次のカスタムバリデーションを作成しました。

```ruby:app/models/user.rb
class User < ApplicationRecord
  validate :required_either_email_or_phone

  private

  def required_either_email_or_phone
    # 演算子 ^ で排他的論理和（XOR）にしています
    # emailかphoneのどちらかの値があれば true
    # email、phoneどちらも入力されている場合や入力されていない場合は false
    return if email.present? ^ phone.present?

    errors.add(:base, 'メールアドレスまたは電話番号のどちらか一方を入力してください')
  end
end
```

```ruby
User.create!(name: "たなか", email: "tanaka@example.com", phone: "08011112222")

# => ActiveRecord::RecordInvalid (バリデーションに失敗しました: emailまたはphoneのどちらか一方を入力してください)

User.create!(name: "たなか", email: nil, phone: nil)

# => ActiveRecord::RecordInvalid (バリデーションに失敗しました: emailまたはphoneのどちらか一方を入力してください)

User.create!(name: "たなか", email: "tanaka@example.com", phone: nil)

# => <User id: 2, name: "たなか", email: "tanaka@example.com", phone: nil, created_at: "2020-03-19 13:06:55", updated_at: "2020-03-19 13:06:55">
```

## おわり
普段は論理和 `||` 演算子 か論理積 `&&` 演算子 ばかりで、`^` 演算子は使わないので、上記のコードを思いつくまでに時間をかけてしまいました…！
ラズパイ4B+BU-353S4でGPSトラッキング(Python)

# ラズパイ4 + BU-353S4 + PythonでGPSトラッキング
ラズパイを用いて、GPS情報を取得する
Raspberry Pi 4Bを使いますが、別に3とかでも同じだと思います。

### 用意するもの
- GLOBALSAT BU-353S4 => USB接続のGPSセンサー
- Raspberry Pi 4

# 手順

必要なパッケージをインストール

```shell
sudo apt-get upgrade
sudo apt-get install gpsd gpsd-clients python-gps cu
```

USBにBU-353S4を差込み、以下のコマンドで接続を確認

```shell
lsusb
# Prolific Technology, Inc. PL2303 Serial Portがあればok
ls /dev/ttyUSB*
# => /dev/ttyUSB0
# 使用されているポートを確認（あとで使います）
```

USBの接続が確認できたら、以下のコマンドでgpsd設定ファイルを作成（既存の場合は下に追加）

```bash
vi /etc/default/gpsd
# vim /etc/default/gpsd
```

```bash:/etc/default/gpsd
# 以下の2行を追加（DEVICESには先ほどのデバイス番号）
DEVICES="/dev/ttyUSB0"
GPSD_OPTIONS="-n"
```

```bash
# 自動起動を設定して再起動
sudo systemctl enable gpsd.socket
sudo systemctl start gpsd.socket
sudo reboot
```

Pythonサンプルコード

gps3をインストール

```bash
pip3 install gps3
```

```python:gps.py
from gps3 import gps3

gps_socket = gps3.GPSDSocket()
data_stream = gps3.DataStream()
gps_socket.connect()
gps_socket.watch()

for new_data in gps_socket:
  if new_data:
    data_stream.unpack(new_data)
    print('time : ', data_stream.TPV['time'])
    print('lat : ', data_stream.TPV['lat'])
    print('lon : ', data_stream.TPV['lon'])
```

```bash
python3 gps.py
# 以下のように出力されます。
# time :  2020-03-19T13:24:08.000Z
# lat :  35.633116667
# lon :  139.703893333
# alt :  17.1
```
# まとめ
意外と簡単だったけど、まともな解説記事やサンプルコードを探すのに苦労した。

### 参考記事
https://qiita.com/t2hk/items/572c72fbe99362d92e32
画面キャプチャ画像を連続して文書に貼れるように、画面に常駐するキャプチャーツールを作った



windowsには、snipping toolという、画面キャプチャがあって、画面の一部分をクリッピングできるが、連続で切り抜いて、文書にぺたぺた貼っていくような場面には向かないので、csharpで、画面に常駐するクリッピングツールをつくった


```scr_cap.cs

//コンパイルは、コマンドラインから以下
//c:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /target:winexe scr_cap.cs

using System;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Imaging;


namespace scr_cap
{
  public class Form1 : Form
  {
    public Button button1;
    public Form1()
    {
      this.Text = "scr_cap";
      this.TransparencyKey = this.BackColor;
      this.TopMost = true;
      //this.SizeGripStyle = 1;
      this.FormBorderStyle = FormBorderStyle.Sizable;

      button1 = new Button();
      button1.Size = new Size(30, 1000);
      button1.Location = new Point(0, 0);
      button1.Text = "-";
      this.Controls.Add(button1);
      button1.Click += new EventHandler(button1_Click);
    }

    private void button1_Click(object sender, EventArgs e)
    {

  try
  {
    var r = this.ClientRectangle;
    var bmp = new Bitmap(r.Width-30, r.Height, PixelFormat.Format32bppArgb);
    var g = Graphics.FromImage(bmp);
    var iSource = this.PointToScreen(new Point(30, 0));
    var iDestination = new Point(0, 0);

    g.CopyFromScreen(
      iSource, iDestination,
      this.ClientSize, CopyPixelOperation.SourceCopy);
    //bmp.Save(".\\capture.png", ImageFormat.Png);
    Pen redPen = new Pen(Color.Red, 1);
    Rectangle rect = new Rectangle(0, 0, bmp.Width-1,bmp.Height-1);
    g.DrawRectangle(redPen, rect);


    Clipboard.SetDataObject(bmp, true, 20, 500);
  }
  catch(Exception ex)
  {
    MessageBox.Show("エラー:\n\n" + ex);//
  }

    }
    [STAThread]
    static void Main()
    {
      Application.EnableVisualStyles();
      Application.Run(new Form1());
    }
  }
}
```
PythonでのDB接続管理の良さそうな方法の紹介

# はじめに
とあるOSSのコードを眺めてて、良さそうなのがあったのでそれの紹介をば。

# コード
とあるOSSというのは、[Apache Airflow](https://github.com/apache/airflow)。
この中で、[airflow/utils/session.py](https://github.com/apache/airflow/blob/master/airflow/utils/session.py) がいい感じでした。

## 簡単な説明

まずは、 `session.py` から。

```python
import contextlib
from functools import wraps

from airflow import settings

# contextlib.contextmanager を指定すると with を使って close を自動でやってくれる
@contextlib.contextmanager
def create_session():
    """
    Contextmanager that will create and teardown a session.
    """
    session = settings.Session()
    try:
        yield session
        session.commit()
    except Exception:
        session.rollback()
        raise
    finally:
        session.close()

# Sessionを使いたい function で使うといい感じに Session を補完してくれる
def provide_session(func):
    """
    Function decorator that provides a session if it isn't provided.
    If you want to reuse a session or run the function as part of a
    database transaction, you pass it to the function, if not this wrapper
    will create one and close it for you.
    """
    @wraps(func)
    def wrapper(*args, **kwargs):
        arg_session = 'session'

        func_params = func.__code__.co_varnames
        session_in_args = arg_session in func_params and \
            func_params.index(arg_session) < len(args)
        session_in_kwargs = arg_session in kwargs
        # function の引数で session があるならそれを使い、なかったら作るという処理
        if session_in_kwargs or session_in_args:
            return func(*args, **kwargs)
        else:
            with create_session() as session:
                kwargs[arg_session] = session
                return func(*args, **kwargs)

    return wrapper
```

で、次に使う側のコード。
[airflow/models/baseoperator.py](https://github.com/apache/airflow/blob/master/airflow/models/baseoperator.py) の [940行目](https://github.com/apache/airflow/blob/master/airflow/models/baseoperator.py#L940)にある

```python
@provide_session
def get_task_instances(self, start_date: Optional[datetime] = None,
                        end_date: Optional[datetime] = None,
                        session: Session = None) -> List[TaskInstance]:
    """
    Get a set of task instance related to this task for a specific date
    range.
    """
    end_date = end_date or timezone.utcnow()
    return session.query(TaskInstance)\
        .filter(TaskInstance.dag_id == self.dag_id)\
        .filter(TaskInstance.task_id == self.task_id)\
        .filter(TaskInstance.execution_date >= start_date)\
        .filter(TaskInstance.execution_date <= end_date)\
        .order_by(TaskInstance.execution_date)\
        .all()
```

のように `session` を使う function でデコレータとして指定すると
呼び出し元で `session` を設定していない場合は新規に作成され（且つ終了時にcloseされる）
`session` を設定している場合はそれをそのまま使うといういい感じなことが実現できる。

# 終わりに
この方法はDB接続以外にも色々応用ができそうだなと思う。

# 参考
* [Pythonのデコレータにはwrapsをつけるべきという覚え書き](https://qiita.com/moonwalkerpoday/items/9bd987667a860adf80a2)
* [with 文と @contextlib.contextmanager が便利](https://qiita.com/QUANON/items/c5868b6c65f8062f5876)
Github使い方

#Githubの使い方備忘録

自分がgithubを使うにあたり、メモ書きとして残します。
sshでの通信を想定しています。
##はじめて連携する時

```
ssh-keygen
```
ここで設定したパスワードを後々毎回連携する際に使用することになるので忘れずに。

```
cat  ~/.ssh/id_rsa.pub
```

鍵情報をコンソールに表示。

github→右上のアイコンからSettings→SSH and GPG keys→New SSH kews
のところにさっき表示した鍵情報を貼り付ける。

以上で連携は終わり。

##リモートリポジトリ→ローカルリポジトリのやり方

リモートリポジトリの、Clone or Downloadで表示されるやつ（ただしUse SSH）をコピー。

ローカルリポジトリを作りたいディレクトリに移動して、

```
git clone (さっきコピーしたやつ)
```

ディレクトリ内に生成しているはず。

###pull
これは使いたいブランチに依存する、

```
git pull origin master
```


##ローカル→リモート

とりあえずディレクトリ作って入る。ここにリポジトリを作るには、

```
git init
```

このディレクトリ内にリポジトリが生成される。
**これはGUIのファインダー内にはひょうじされないから注意！！！**

addするには、

```
git add addしたいファイル名
```

ここでそのディレクトリすべてaddしたいってなったら、

```
git add .
```

commitは、

```
git commit -m "なんらかのメッセージ"
```

**コミットには何らかのコメントが必須**

pushは、

```
git remote add origin git@github.com:自分のGitHubアカウント名/作ったプロジェクト名
git push -u origin master
```

##ブランチ！！！

めんどいので詳細は省きます。

```
git branch
git branch gh-pages
git checkout gh-pages
touch index.html


git checkout master
git merge gh-pages
```

以上が基本的な使い方。。のはず
Tips To Hire Dedicated Mobile App Development Team

Mobile devices now offer a smooth and efficient method to reach customers. Attract new consumers and retain existing customers. Indeed, a mobile application is better than a website. To do this, you can create an application yourself if you have the right knowledge of the process. Or you can choose to hire the best app development company.

Here are some tips, which can help you make the right decision when hiring fast services offered by professional Mobile App Developers. 

Don’t rely on the first meeting – there are options!

The app development market is broad. So, it is entirely baseless that you decide to rely on the first meeting. Avoid the first developer you encounter. He/they may offer you an exciting deal, but it will not be a game-changer. It will be more rewarding if you take the time to find and Hire Dedicated Mobile App Developers.

A survey will help you ideally to understand which app developing team fits according to your needs. Then only you can hire the App Development team wisely. Choose what you think is best suited for the job. Discuss your expectations and evaluate your developer’s knowledge and experience before making the final decision. 

hire mobile app development team
さくらVPSでウェブアプリ公開まで

## はじめに
ローカル環境で作ったものをサーバー上にアップロードして公開する流れをまとめます。
その中で詰まった部分などを備忘録的にまとめます。

## ざっと流れ
１　さくらVPSを契約
２　Linux環境の構築
３　ドメイン取得
４　ドキュメントルート変更
５　SSL化

##１さくらVPS契約
まずはさくらVPSの契約から。
[さくらVPS申し込みはこちら](https://vps.sakura.ad.jp/)
![スクリーンショット 2020-03-19 20.49.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464231/531a5750-5520-923e-c156-52cdd90f7b75.png)

14日間お試し期間があるのでその期間に一通りできれば無料でお勉強が可能。
※プランは1Gを選択

登録が完了する下のようなコントロールパネルにログイン。
![スクリーンショット 2020-03-19 20.54.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464231/8fb2fd03-2b2e-3aaa-f2f5-83fe2de63162.png)

契約したVPSを情報が記載されている。

## Linux環境構築
Linuxを勉強するにあたって下記のUdemyの講座を購入。
[【3日でできる】はじめてのLinuxサーバー構築入門（CentOS 7・PHP 7・Docker対応）](https://www.udemy.com/course/linux_vps_3days/)

VPS上にCentOSをインストールしてLAMP環境を構築するまでの流れがわかりやすく勉強できたので個人的にはおすすめ。

#### Linux環境構築する上で躓いたポイント
**・ファイヤーウォールを設定してSSHでログインする**
　→ファイヤーウォールを設定したポートを確認
　→更新した内容をリロードし反映させる
　→SSHのサーバーにも反映させるためにデーモンを再起動する

**・サーバー上の一般ユーザーと特権(root)ユーザーでできること**
`一般ユーザー`＝自分のディレクトリ以下のファイルの読み書きができる
`特権(root)ユーザー`＝管理者権限を持つユーザー
※インストールや設定ファイルの変更には管理者権限が必要

一般ユーザーに管理者権限を与える
rootユーザーの命令は絶対であり間違えてシステムファイルなども削除してしまう可能性があるため、基本的には一般ユーザーに管理者権限を与えて操作を行うことが好ましい。

**・サーバーに外部からアクセスできるようにファイヤーウォールの設定変更**
→これが設定できないとアクセスできない

これが完了してVPSのIPアドレスに接続するとApacheの標準ページが表示される。

デフォルトのドキュメントルートが`/var/www/html`なので
例えばこの配下に`index.html`を置くとその中身が表示される。
URLはこんな感じ
`xx.xx.xx.xx/index.html`

##ドメイン取得
IPアドレスのままでも表示はできるが、ウェブアプリを公開するにあたってそのサービスを認知いただくためにドメインの取得は必要。

さくらインターネットやお名前.comなどからドメインを取得する。
※今回はさくらインターネットから取得

ドメインの設定方法に関しては下記リンクを参照
[【ドメイン設定】さくらインターネットで取得・管理中のドメインを利用](https://help.sakura.ad.jp/206053802/)

要するにサーバーのIPアドレスと取得したドメインを紐付けさせる。

設定が完了すると、上記の`xx.xx.xx.xx/index.html`で表示させていたところのIPアドレス部分（`xx.xx.xx.xx`）を取得したドメイン書き換えても同じようにアクセスできるようになる。


##Let's encryptで無料SSL証明書発行してSSL化
無料でSSL証明書を発行するために今回はLets encryptを使用

**躓いたポイント**
インストールして証明書も発行したのにSSL化されない
**→証明書発行してからApacheに設定が必要**
/etc/httpd/conf.d/ssl.confに

```
SSLCertificateFile /etc/letsencrypt/live/[サーバーのドメイン]/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/[サーバーのドメイン]/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/[サーバーのドメイン]/chain.pem
```

それぞれ設定する
参考記事
https://weblabo.oscasierra.net/letsencrypt-2/

##ドキュメントルート変更
取得したドメインにアクセスした時にサイトが表示されるようにデフォルトのドキュメントルートを変更する。

この変更を行わないと、例えばデフォルトの`/var/www/html`配下に`example`ディレクトリを作り、その配下に`index.html`を置いた場合、URLが`ドメイン/example/index.html`と少しブサイクになってしまう。

ドメインだけを入力した時にトップページが表示されるように下記の設定を行う。

`/etc/httpd/conf/httpd.conf`の下の方にある`<VirtualHost *:80>`の中にある
DocumentRootを自分が表示させたいディレクトリに変更する。

上の例であれば`/var/www/html`になっているドキュメントルートを`/var/www/html/example`にすることによってドメインにアクセスした時に`index.html`の内容が表示される。
Texでスタイルファイルを追加する方法

## 環境
WSL Ubuntu 18.04
pLaTeXでコンパイル

## 問題
単にファイルをコピーしただけでは読み込めなかった

## 手順
### １ .styファイルをコピーする

```
sudo cp hoge.sty /usr/share/texmf/tex/latex
```
※コピー先のフォルダは環境によって異なるかも

### ２ データベースを更新する
```
sudo texhash
```

## （ちなみに） .styファイルがなく.insのみの場合
```
latex hoge.ins
```
毎度忘れる GitHub へ SSH公開鍵登録作業

# はじめに
仮想環境でサクッと開発環境を作ったり、消したりしていると、GitHub への接続設定をうっかり消し込んで、なんで git push できへんねん！！となったので、面倒な作業を bash で自動化しました。
ssh-agent と ssh-add に関しては、手動で作業になりますが、やればいい作業は表示してくれます。

# 実装
以下を参照してください。
https://github.com/nlog2n2/scissor

# やったこと
## 1. GitHub からスクリプトを落としてくる
GitHub で接続したいマシンで以下のコマンドを実行する。

```bash:
$ git clone https://github.com/nlog2n2/scissor.git
$ cd scissor
```
## 2. スクリプトを実行する
```bash:
$ bash generate.sh
```
すると以下のように表示される。

![スクリーンショット 2020-03-19 21.19.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54900/f644c720-7e0d-a183-e7d5-1b119b0b469e.png)

※補足：GitHubに関する設定は適宜変更すること

## 3. 表示された公開鍵を GitHub へ登録
Webブラウザで GitHub へログイン。
その後、Settingにいき、SSH ang GPG Keys をクリック。
"New SSH key"という緑色のボタンがあるのでクリック。
Titleに開発環境のユーザー名＠ホスト名を入力。
key にコマンドで表示された公開鍵をコピーしてペースト。
"Add SSH key" と書かれた緑色のボタンをクリック。

## 4. 表示されたコマンドを実行
スクリプト実行時に表示されたコマンドを実行していく。
![スクリーンショット 2020-03-19 21.21.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54900/2a501e30-7e45-89fd-5acc-0aceb879eff4.png)

## 5. SSH への接続テスト
![スクリーンショット 2020-03-19 21.20.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54900/4e2032ae-c261-452c-df4e-cc19f0a9259b.png)

## 6. リポジトリの接続方法を変更
あとは開発中のコードがあるリポジトリに移動して以下のコマンドを実行する。

```bash:
$git remote set-url origin git@github.com:ユーザ名@レポジトリ名
```
# おわりに
俺たちの戦いはこれからだっ！
これから python のコードを書き始めますorz

# 参考文献
[パスワードに使えるランダム文字列を生成するコマンド](https://qiita.com/speg03/items/ec404c217e417160e2d5)
[GitHubの初期設定（SSH接続からリポジトリへのpushまで）](https://qiita.com/drapon/items/441e18452b25060d61f1)
[GitHubにssh接続できるようにする](https://qiita.com/0ta2/items/25c27d447378b13a1ac3)
Vueの$routeがどうしてもundefinedになってしまう

# 反省文

Vueでルーターの設定をしようとしていましたが、なぜか何をやっても設定がVueに反映されません。

下のどちらかのコードには間違いがあります。

```a.js
import router from "./router";

new Vue({
  router,
  render: h => h(App)
}).$mount("#app");
```

```b.js
import Router from "./router";

new Vue({
  Router,
  render: h => h(App)
}).$mount("#app");
```

a.jsの方は動きますが、b.jsの方は動きません。動かそうとするとこんなエラーが出て止まります。

```javascript
vue.esm.js?efeb:628 [Vue warn]: Error in render: "TypeError: Cannot read property 'meta' of undefined"

found in

---> <App> at src/App.vue
       <Root>
```

上記の該当箇所はこんなかんじです。

```javascript
export default {
  computed: {
    layout() {
      console.log(this);
      return this.$route.meta.layout || "default"; // << ココでエラー発生
    }
  }
};

```

$routeに何も代入されていません。

この様に書き直すと、今までのエラーが嘘の様に動き出しました。

```b.js
import Router from "./router";

new Vue({
  router: Router,
  render: h => h(App)
}).$mount("#app");
```

`router`と、オブジェクトのキーをちょいと書き加えてやるだけ。
【AWS】CDKで出力されるテンプレートからCDKMetadataを除く方法

# TL;DR

* コマンドで制御するならこれ

```shell
cdk synth {app_name} --version-reporting false
```

```shell
cdk synth {app_name} --no-version-reporting 
```

* 設定ファイルで管理したい場合
    * cdk.jsonに`"versionReporting": false`を加える

```json
{
  "app": "...",
  "versionReporting": false
}
```


* 詳しいことはここの「Opting Out from Version Reporting」見てください
    * [AWS CDK Toolkit (cdk)](https://docs.aws.amazon.com/cdk/latest/guide/tools.html#cli)


# なぜ除きたいか

* 社内のルールでは、AWSのリソース管理は基本的にCFNテンプレート管理
    * テンプレートを出荷して商用環境に適用する
* CDKMetadataはcdkのversionなどが含まれるので、CDKのversionupをするとdiffが生まれてしまう。
    * リポジトリ内のCFNテンプレートすべてが変わってしまうので、本当に見てほしいDiffが隠れる

# 除くとなにが消える？

* CDKMetadataだけでなく、CDKMetadataAvailableも消えます

```diff
-  CDKMetadata:
-    Type: AWS::CDK::Metadata
-    Properties:
-      Modules: aws-cdk=1.24.0,@aws-cdk/aws-iam=1.24.0,@aws-cdk/core=1.24.0,@aws-cdk/cx-api=1.24.0,@aws-cdk/region-info=1.24.0,jsii-runtime=Python/3.8.1
-    Condition: CDKMetadataAvailable
-Conditions:
-  CDKMetadataAvailable:
-    Fn::Or:
-      - Fn::Or:
-          - Fn::Equals:
-              - Ref: AWS::Region
-              - ap-east-1
-          - Fn::Equals:
-              - Ref: AWS::Region
-              - ap-northeast-1
-          - Fn::Equals:
-              - Ref: AWS::Region
-              - ap-northeast-2
-          - Fn::Equals:
-              - Ref: AWS::Region
-              - ap-south-1
-          - Fn::Equals:
-              - Ref: AWS::Region
-              - ap-southeast-1
-          - Fn::Equals:
-              - Ref: AWS::Region
-              - ap-southeast-2
-          - Fn::Equals:
-              - Ref: AWS::Region
-              - ca-central-1
-          - Fn::Equals:
-              - Ref: AWS::Region
-              - cn-north-1
-          - Fn::Equals:
-              - Ref: AWS::Region
-              - cn-northwest-1
-          - Fn::Equals:
-              - Ref: AWS::Region
-              - eu-central-1
-      - Fn::Or:
-          - Fn::Equals:
-              - Ref: AWS::Region
-              - eu-north-1
-          - Fn::Equals:
-              - Ref: AWS::Region
-              - eu-west-1
-          - Fn::Equals:
-              - Ref: AWS::Region
-              - eu-west-2
-          - Fn::Equals:
-              - Ref: AWS::Region
-              - eu-west-3
-          - Fn::Equals:
-              - Ref: AWS::Region
-              - me-south-1
-          - Fn::Equals:
-              - Ref: AWS::Region
-              - sa-east-1
-          - Fn::Equals:
-              - Ref: AWS::Region
-              - us-east-1
-          - Fn::Equals:
-              - Ref: AWS::Region
-              - us-east-2
-          - Fn::Equals:
-              - Ref: AWS::Region
-              - us-west-1
-          - Fn::Equals:
-              - Ref: AWS::Region
-              - us-west-2

```

# 余談

* cdk.jsonでの制御などは意外と日本語では書かれてなかったので投稿しました。
* CDKおすすめなので、もっと広まってほしい
Flutterのサンプルのコメントを日本語にした(自分用メモ)

Flutterのサンプルのコメントを日本語にした(自分用メモ)

```Dart:main.dart
import 'package:flutter/material.dart';

//flutter runで実行

//エントリポイント(起動したときの定義)
void main() => runApp(MyApp());

//アプリ自体の定義(状態を持たないStatelessWidget)
class MyApp extends StatelessWidget {
  //描画・UI構築処理
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      //アプリ自体のタイトル
      title: 'Flutter Demo',
      //タイトルバーのテーマ
      theme: ThemeData(
        primarySwatch: Colors.blue, //色
      ),
      //画面を表す要素を内包する
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

//画面の定義1(状態を持つStatefulWidget)
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 _counter = 0;

  //ボタンをタップされた時のイベント定義
  void _incrementCounter() {
    //状態の変化を通知するにはsetStateを使う。これによりbuildが再コールされる
    setState(() {
      _counter++;
    });
  }

  //描画・UI構築処理(setStateが呼び出されるたびに呼ばれる)
  //フレームワークで管理されているため、更新が必要なものだけ更新される
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        // MyHomePage objectから値をとってきてタイトルにセット
        title: Text(widget.title),
      ),
      body: Center(
        //レイアウト構築(1つしかないので中央に置かれる)
        child: Column(
          //垂直に並べる
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            //テキストを配置
            Text(
              'You have pushed the button this many times:',
            ),
            //テキストを配置($変数で動的に表示)
            Text(
              '$_counter',
              //スタイルを適用
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      //フローティングアクションボタンを追加
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}
```

#参考文献
Flutter でサンプルプログラムを理解する
https://qiita.com/kurararara/items/73deac522ad9fea36abc
EC2サーバで生成した公開キーはどこからどこまでなのか




>cat ~/.ssh/id_rsa.pub

コマンドで作った公開キーは、どこからどこまでなのか？

###結論

ssh-rsa AAA...
から始まって、

...== ec2-user@ip-000-00-00-000
までが

公開キーです



GitHub で SSH keyを登録するときの参考になればと。
【Python3】リクルートカードの支払いが来月幾らか確認しよう【Selenium】 

#クレジットカードの来月の支払いの確認が面倒くさい！
タイトルの通り、わたしは__来月の支払いを確認するのを怠ったばっかりに__、
__何となくリボ払いにして借金が減った気がした錯覚に陥りました。__
という事で、今回は前回と同じパターンで、

__スクリプトでサクッと支払情報をサクッと貰ってきましょう。__

例によってあなたがPCを起動した時に走らせるcronを使えば、全てのクレジットカードの支払を管理する事が出来ます。
カード会社毎に支払日が違うので、後々グラフ化も考えています。

__グラフ化や、他の会社のクレジットカードの請求情報の取得解説の要望があったら言って下さい。__

##注意するべき点
__ 今回は特にないです。

OS：Windows10
GoogleChrome バージョン: 70.0.3538.110（Official Build） （64 ビット）
Python：3.70
Selenium Webdriver：この記事を書いた時点で最新のもの
chromedriver.exe：この記事を書いた時点で最新のもの

※スクリプトと同じフォルダに'chromedriver.exe'を置いてください。

```python:recruit_card.py
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait

browser = webdriver.Chrome()
browser.get('https://www2.cr.mufg.jp/newsplus/?cardBrand=0011&lid=news_mufg')

elem_username = browser.find_element_by_xpath('//*[@id="loginFormNavi"]/div/dl[1]/dd/input')
elem_username.send_keys('ID')
elem_password = browser.find_element_by_xpath('//*[@id="loginFormNavi"]/div/dl[2]/dd/input')
elem_password.send_keys('PASSWARD')
elem_login_btn = browser.find_element_by_xpath('//*[@id="submit1"]')
elem_login_btn.click()

elem_username = browser.find_element_by_xpath('//*[@id="webBirthDay"]')
elem_username.send_keys('190011')# 生年月。サンプルは1900年11月生まれ
elem_login_btn = browser.find_element_by_xpath('//*[@id="submit"]')
elem_login_btn.click()

elem_riyou = browser.find_element_by_xpath('//*[@id="pc_login"]/ul[1]/li[1]/a')
elem_riyou.click()

# ページ遷移対応
WebDriverWait(browser, 3).until(lambda d: len(d.window_handles) > 1)
browser.switch_to.window(browser.window_handles[1])

# 来月の支払代金を出力
elem_money_next_month = browser.find_element_by_xpath('//*[@id="main"]/div[3]/div[2]/table[2]/tbody/tr[1]')
elem_money_next_month.text
```

今回は以上になります。何かご要望があったらご意見下さい。
Swift Network.framework Study 20200319「Receive and Send」

# Study

Network.framework
Study：Receive and Send

## 環境

Client：Java、NetBeans
Server：Swift、Xcode

# Server Source Swift

## main.swift

```swift
import Foundation
import Network

var receiveANdSend = ReceiveAndSend()
receiveANdSend.startListener()
while receiveANdSend.running {
    sleep(1)
}
```

## ReceiveAndSend.swift

```swift
import Foundation
import Network

class ReceiveAndSend {
    public var running = true

    func startListener() {
        let myQueue = DispatchQueue(label: "ExampleNetwork")

        do {
            let nWListener = try NWListener(using: .tcp, on: 7777)
            nWListener.newConnectionHandler = { (newConnection) in
                print("New Connection!!")
                newConnection.start(queue: myQueue)
                self.receive(nWConnection: newConnection)
            }
            nWListener.start(queue: myQueue)
            print("start")
        }
        catch {
            print(error)
        }
    }
    
    func receive(nWConnection:NWConnection) {
        nWConnection.receive(minimumIncompleteLength: 1, maximumLength: 5, completion: { (data, context, flag, error) in
            print("receiveMessage")
            if let data = data {
                let receiveData = [UInt8](data)
                print(receiveData)
                print(flag)
                self.sendMessage(nWConnection)
                if(flag == false) {
                    self.receive(nWConnection: nWConnection)
                }
            }
            else {
                print("receiveMessage data nil")
            }
        })
    }

    func sendMessage(_ connection: NWConnection) {
        let data = "Answer".data(using: .utf8)
        let completion = NWConnection.SendCompletion.contentProcessed { (error: NWError?) in
            print("応答送信完了")
            self.running = false
        }
        connection.send(content: data, completion: completion)
    }
}
```

# Client Source Java

```java
public class ExampleSendAndReceive {
   public static void main(String[] args) {
        try(Socket socket = new Socket("localhost", 7777);
            PrintWriter printWriter = new PrintWriter(socket.getOutputStream(), true);) {

            Runnable runnable = () -> {
                System.out.println("Receive start");
                try {
                    int data = socket.getInputStream().read();
                    while(data != -1) {
                        System.out.print(data + " ");
                        data = socket.getInputStream().read();
                    }
                    System.out.println("end");
                }
                catch(Exception e) {
                    System.out.println(e);
                }
            };
            Thread thread = new Thread(runnable);
            thread.start();
            
            for(int i = 0; i < 5; i++) {
                printWriter.println("12345");
                Thread.sleep(5000);
            }
        }
        catch(Exception e) {
            System.out.println(e);
        }
    }    
}
```
Seabornが簡単便利で感動した話

# Seaborn

matplotlibで描くにはちょっと面倒なグラフでも、seabornを使えば割と簡単にかけてしまうことに感動した。

<img width="1328" alt="スクリーンショット 2020-03-19 20.20.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104153/ab826fc6-8067-55dd-57b2-304c2fba87df.png">

matplotlibでこれを描こうとすると、だいたいこんな感じになるとおもう。超適当だから間違ってるかもしれんが、

```python
import itertools
fig, axes = plt.subplots(2, 3)
col_f = 'Pclass'
col_f_domain = [1, 2, 3]
row_f = 'Sex'
row_f_domain = ['male', 'female']
for i, (r, c) in enumerate(itertools.product(row_f_domain, row_f_domain)):
    row_i = i // 3
    col_i = i % 3
    ax = axes[row_i][col_i]
    # (以下略)
```

そうそう、forループ回すよな。
これ、seabornだと１行なんだぜ・・・

```python
sns.relplot(x='Age', y='Fare', hue='Survived', col='Pclass', row='Sex', data=train_data)
```

# 最後に

EDA(Exploratory Data Analysis, 探索的データ探索)をするときは、比較対象とする特徴量や水準を変えながらたくさんグラフを書くことになるから、このように複雑なプロットもサクッとかけてしまうツールは重宝する。
逆に、matplotlibは、こう言ったハイレベルなツールでは手の届かない痒いところまでできるのが良いところ。Seabornじゃ描けなそうなプロットはmatplotlibで描こう、って感じかなと。
AWS-CDKのData Pipelineのライブラリの使い勝手が悪すぎたのでnpmでラッパーをつくった

# はじめに
仕事の関係で[AWS-CDK](https://aws.amazon.com/jp/cdk/)で[Data Pipeline](https://aws.amazon.com/jp/datapipeline/)を構築していたのですが、そのライブラリの使い勝手があまりにも悪かったので自分のためのnpmパッケージをつくってそれを公開しただけの話です。

# パッケージについて

[レポジトリはここ](https://github.com/ufoo68/data-pipeline-d2s-cdk)で、[パッケージはここ](https://www.npmjs.com/package/data-pipeline-d2s-cdk)です。
このパッケージはData Pipelineを用いて[DynamoDB](https://aws.amazon.com/jp/dynamodb/)のバックアップデータを[S3](https://aws.amazon.com/jp/s3/)に吐き出すシステムをシンプルに構築することができます。

# 使い方

以下はREADMEの抜粋したサンプルコードです。

```typescript

const { tableName } = new dynamodb.Table(this, 'Table', {
  partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING }
})
const { bucketName } = new s3.Bucket(this, 'MyBucket')

new DataPipelineD2SCdk(this, 'DataPipeline', {
  tableName,
  bucketName,
  throughputRatio: 0.2,
  period: {
    value: 1,
    format: TimeFormat.Day,
  },
  emrTerminateAfter: {
    value: 1,
    format: TimeFormat.Hour
  },
})

```

基本はData PipelineのCloudFormationのパラメーター名に準拠しています。`period`がこのData Pipelineのシステムが走る周期で、`emrTerminateAfter`がデータのバックアップのために走る[EMR](https://aws.amazon.com/jp/emr/)の最大稼働時間となっています。`throughputRatio`はあまりよくわかってません。

# さいごに

AWS-CDKはまだラッパーがちゃんと整備されてないリソースが何個かあったりするので、苦労する場面が多々ありそうですね。
【Sign In with Apple】iOSアプリから投げられたidentityTokenをPHPで認証する

# 概要
`identityToken` というJWTがアプリから届いてパースして`sub`をユニークキーとして認証するのですが
改ざん防止の為、正しくデコードする必要があります。

細かいことはバージョンが違ったり環境で変わってくると思うので大まかな流れだけ書いておきます。
~~※コメントで指摘をもらったのですが、これだけではAppleが発行したことしか担保出来ないため
別のアプリからの認証もしてしまうので足りていません。後日ドキュメントを追加するなりします。~~
追記しました。


- appleの公開鍵を取得
- 取得した公開鍵を利用して検証
- `aud` で自分のアプリの値かどうか
- `exp` で有効期限切れかどうか
- 問題なければ取得できた値から `sub` を利用して認証

[Sign In with Appleの公式ドキュメント](https://developer.apple.com/jp/sign-in-with-apple/get-started/)はこちら

以上！！

要所要所の僕が使った部分を以下に記載してるので参考になれば幸いです。

# JWTとは
> JWT（ジョット）とは JSON Web Token の略で、電子署名付きの URL-safe（URLとして利用出来る文字だけ構成される）な JSONのことです。
電子署名により、JSON の改ざんをチェックできるようになっています。

> ざっくり言うと、改ざんできない JSON ということになります。

[JWT について調べた内容をまとめました。](https://qiita.com/t-toyota/items/8d0ffb265845ab8cc87c)

# パースしてみる
こちらのサイトでパース出来るので便利でした。
https://jwt.io/ 

# Appleの鍵を取得する
Appleの鍵はこちらにありました。
[Fetch Apple's public key for verifying token signature](https://developer.apple.com/documentation/signinwithapplerestapi/fetch_apple_s_public_key_for_verifying_token_signature)

# Appleの鍵をFirebaseのJWTライブラリが理解出来る形に変更する
JWTの検証に[Firebaseのライブラリ](https://github.com/firebase/php-jwt)を使ったのですが、複数の鍵で署名されてる場合
配列で鍵を指定出来るのですが形式が以下のような形なので変換して上げる必要があります。

Appleの鍵の中にある`e`と`n`を使ってPEMを作れるので頑張って作ります。
この方の記事をめちゃくちゃ参考にさせてもらいました。
[【PHP】AzureAPIなどで配布されている公開鍵の「e」「n」とはなにで、どう使うのか](https://qiita.com/ishiitakeru/items/d285674785218c2e031b)


```php
$publicKeys = [
    'kidの値' => 'PEM形式のテキスト',
    'kidの値' => 'PEM形式のテキスト',
];
```

# JWTの検証をして中身を取得する
[Firebaseのライブラリ](https://github.com/firebase/php-jwt)を使って
アプリから投げられた `identityToken`とさっき作った公開鍵の配列とAppleの鍵に書いてあった `alg` の値 `RS256`を指定すれば
改ざんされてなければJSONが返ってきます。

```php5
$payload = JWT::decode($identityToken, $publicKeys, ['RS256']);
```
チーム開発 3/19

メモです
最終課題二日目
トップページを担当

検索機能をつける際に検索ボタンを画像に引っ付けたい
https://teratail.com/questions/60004
参考サイト
button_tagもしくはimage_submit_tagを使うと解決

画像の大きさを自由に変えた（ブロックに合わせた大きさ）
https://qiita.com/jag_507/items/79af40e12a2e50bbc04e
https://teratail.com/questions/39407
参考サイト
まず大きさを変えたい画像のimgにクラスをつける
そこに
max-width: 100%;
height: auto
を記述する

検索機能にクラスを書きたいがエラーが出た
多分form_tagの書き方が悪い
form_withで解決した

Formにcssの要素をつけたい
form{}で要素をつけれる

html li リストマーク（・）消す方法
list-style: none;

ブロック全体に画像を貼る時に使う
background-image: url(pict/bg-mainVisual-pict_pc.jpg)


まとめ（全体）
トップページ
部分テンプレート完成

デバイス
サーバーサイドの新規は完成
見た目も90％ほど完成

マイページ
ビューを作りました
サイドバーの中身をみんなで考えたいです

商品の出品ページ
見た目のみ
Java言語で学ぶデザインパターン入門のSingletonパターンまとめ

お久しぶりです。白々です。
先日エンジニアの先輩にデザインパターンをご存知でない！？という冷静なツッコミを頂き、その後結城浩さんが書かれた「Java言語で学ぶデザインパターン入門」を渡されたので勉強することにしました。
ただ、本を一読しても覚えられないので覚書として記事にしようと思いました。
今回で5回目です。
完走できるように頑張ります。
また、「Java言語で学ぶデザインパターン入門」には、サンプルプログラムも有りますが、著作権の都合上省かせて頂きます。御了承ください。

前回は、「Factory Methodパターン」に関しての記事を作成しました。
前回の記事は、以下です。
https://qiita.com/sirajirasajiki/items/3a779d3529fbc14af801

今回は、「Singletonパターン」に関して記載したいと思います。
また、「Singletonパターン」には、サンプルプログラムも有りますが、著作権の都合上省かせて頂きます。御了承ください。

#第5章 Singletonパターン-たった1つのインスタンス
「Java言語で学ぶデザインパターン入門」には、
>インスタンスが1個しか存在しないことを保証するパターンをSingletonパターンと呼びます。

という記述がありました。

例えば、プログラム上で複数の種類の演算をするプログラムがあるとします。
それぞれの演算は、演算結果を次の演算に使う物とします。
これらの演算の結果を一挙に管理する演算管理クラスがあるとします。
このとき複数の演算クラスを作成できてしまう場合、インスタンス毎に演算結果が変わってしまいます。
なので、インスタンスは、1つにすることで本来求めていた演算結果を取得できます。
このように、プログラム上で、特定のクラスを継承したインスタンスが1つしか使いたくない時に使用します。

よくある例としては、機械を管理するパラメータのクラスが挙げられます。
例えば、機械の温度や、機械の動作状況などのパラメータを管理するインスタンスが同じ機器の中で複数あったら、機器はどのインスタンスを参照していいかわからなくなりますよね？また、インスタンス毎にパラメータが異なりどれが正しいかわからないかもしれないですよね？
このような時にこのSingletonパターンを使用します。

##Singletonを使った例
今回は、麻雀の点数管理をSingletonパターンで行うという状況を考えたいと思います。
麻雀の同じゲーム内で毎回インスタンスを立て直すと点数の最終結果がおかしいことになってしまうためSingletonパターンを使う物とします。
Mahjongというクラスの中には、プライベート変数で点数とインスタンスが管理されています。
また、Mahjongのインスタンスの取得、点数の取得及び、点数の計算をするメソッドが管理されている物とします。

###クラス図
![singleton.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521126/ddffb0d4-1260-637c-6601-7af44187869a.png)

このクラス図は、PlantUMLというもので記載しています。
私が、書いたPlantUMLのコードは以下のGitHubに記載がありますのでReadMeを読んでお使いください。
singleton.txtです。
https://github.com/sirajirasajiki/design_pattern_uml/tree/master/singleton
PlantUMLのインストール方法と使い方に関しては、後述のappendixに記載しています。

###クラス図を元にPythonで実装
以下に実装したコードを公開しています。Python 3.7で実装しました。
https://github.com/sirajirasajiki/design_pattern_python/tree/master/Singleton

##Singletonパターンを使う時の注意事項
- コンストラクタはprivateにしておく。
    - 理由： 他のところで継承させないようにするため。

#まとめ
インスタンスをプログラム上で1つしか作成することができないSingletonパターンについて学びました。

#第5章感想
Singletonパターンを使うことで、複数インスタンスが作成されると、インスタンス同士が干渉してプログラムの挙動に影響が出るようなクラスでも、安心して使うことができるということが分かりました。
~~説明で使った例は、後日Pythonで実装しようと思います。~~
Pythonにて実装しました。


#最後に
何か間違っているところがあれば、ご指摘していただけると嬉しいです！

#appendix
##次回の記事
https://qiita.com/sirajirasajiki/items/02bde7075f8edd3570f1

##Python実装中に参考にした記事
https://qiita.com/ttsubo/items/c4af71ceba15b5b213f8

#変更履歴
- 説明の追加
定義してないのになぜか使える activated? admin? メソッド Ruby on Rails チュートリアル

こんなメソッド定義してないぞ？と思いきや、
Railsでは真偽値をとるカラムであれば、モデル.カラム名?で真偽値を取得できるらしいです。



![user_model_account_activation.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/302052/40210e47-806e-0e05-dd08-862827f486e0.png)



```ruby
>> user = User.first
  User Load (0.1ms)  SELECT  "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, name: "Example User", email: "example@railstutorial.org", created_at: "2020-03-15 10:30:06", updated_at: "2020-03-15 10:30:06", password_digest: "$2a$10$XvC6suqKbRRIHIm8nQOyjeQcKJixPXdm1b331TQJ7y5...", remember_digest: nil, admin: true, activation_digest: "$2a$10$5/9pDzSQIJdzpaAbFCJZO.qptq0BYtnH.Q/sBwP5epB...", activated: true, activated_at: "2020-03-15 10:30:06">

user.admin?
=>true

user.activate?
=true
```
Base64で Cloud KMS の複合化

[公式ドキュメント](https://github.com/googleapis/nodejs-kms) の `Source Code` では、**ファイル経由**で暗号化／複合化しますが、**Base64** の方法も記録します。

## 公式ドキュメントの例
```javascript:File
// [START kms_decrypt]
async function decrypt(
  projectId = 'your-project-id', // Your GCP projectId
  keyRingId = 'my-key-ring', // Name of the crypto key's key ring
  cryptoKeyId = 'my-key', // Name of the crypto key, e.g. "my-key"
  ciphertextFileName = './path/to/plaintext.txt.encrypted',
  plaintextFileName = './path/to/plaintext.txt.decrypted'
) {
  const fs = require('fs');
  const {promisify} = require('util');

  // Import the library and create a client
  const kms = require('@google-cloud/kms');
  const client = new kms.KeyManagementServiceClient();

  // The location of the crypto key's key ring, e.g. "global"
  const locationId = 'global';

  // Reads the file to be decrypted
  const readFile = promisify(fs.readFile);
  const ciphertext = await readFile(ciphertextFileName);
  const name = client.cryptoKeyPath(
    projectId,
    locationId,
    keyRingId,
    cryptoKeyId
  );

  // Decrypts the file using the specified crypto key
  const [result] = await client.decrypt({name, ciphertext});

  // Writes the decrypted file to disk
  const writeFile = promisify(fs.writeFile);
  await writeFile(plaintextFileName, result.plaintext);
  console.log(
    `Decrypted ${ciphertextFileName}, result saved to ${plaintextFileName}.`
  );
}
// [END kms_decrypt]
```

## Base64の例
```typescript:Base64
const kms = require('@google-cloud/kms');

const PROJECT_ID = 'kms-project';
const KMS_KEYRING_LOCATION = 'asia-northeast1';
const KMS_KEYRING_ID = 'keyring-envs';
const KMS_KEY_ID = 'api-key';

const decode = async (text: string) => {
  const client = new kms.KeyManagementServiceClient();
  // 複合化キー情報
  const name = client.cryptoKeyPath(PROJECT_ID, KMS_KEYRING_LOCATION, KMS_KEYRING_ID, KMS_KEY_ID);
  // 複合する
  const [result] = await client.decrypt({ name, ciphertext: text });

  // Base64から変換する
  return Buffer.from(result.plaintext, 'base64').toString();
};
```
プログラムはなぜ動くのか？を読んでみてまとめることで知識の定着を図る投稿#9

[プログラムはなぜ動くのか第２版](amazon.co.jp/プログラムはなぜ動くのか-第２版-知っておきたいプログラムの基礎知識-矢沢久雄/dp/4822283151/ref=sr_1_1?adgrpid=53631245656&gclid=Cj0KCQjw0pfzBRCOARIsANi0g0tajATNcn3H7Ogokqrdst5O2JctSzMRb6A0XyW5GegcPbJwaEvZO84aAlK8EALw_wcB&hvadid=338517958683&hvdev=c&hvlocphy=2392&hvnetw=g&hvqmt=e&hvrand=9776556383623440456&hvtargid=kwd-334563073858&hydadcr=27265_11561134&jp-ad-ap=0&keywords=プログラムはなぜ動くのか&qid=1583760691&sr=8-1)

を僕が師匠と読んでいる方に進めていただき、読んでみようと思いました。
そこで、僕的にはかなり難しいこともあり、この本をまとめながら読み進めていくことによって理解度を高めようと思いました。

こちらはあくまでも推奨する記事ではなく、僕がこうした方が定着しやすいかもと思い、記録に残すことにしました。

##シフト演算と乗除算の関係

2進数の仕組みが理解できたところで、テーマを演算に移します。（はーい）

四則演算は、2進数の場合も、10進数の場合と同様に行えます。
２まで数えると桁上がりすることだけに注意すればなんの問題もありません

「桁上がり」（なんかかっこいいと思ったので書いてみました

2進数ならではの演算とは、コンピュータならではの演算であり、そこにプログラムの動作原理を知る鍵があります。


###シフト演算
最初に取り上げるのは「シフト演算」です。

シフト演算とは、２進数で表された数値の桁を左右にシフトする(shift=ずらす）演算です。

桁を左方向にずらす左シフトと、桁を右方向にずらす右シフトがあります。
１回の演算で複数行をシフトすることもできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253981/a13463ba-3a90-0939-97bc-ee363eb11874.png)
*画像に特に意図はありません。疲れているだけです。

C言語での左シフトのプログラムです。

```
a = 39
b = a << 2
```

なんということでしょう。さっきまで

```
00100111
```
と表されていた２進数が

```
10011100
```

シフトによって最上位桁または最下位桁から溢れてしまった数字はそのままなくなってしまいます。
（桁溢れやオーバーフローといいます）
まぼろし〜
つまり今まで隠れていた黒子が出てくるわけですな。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253981/b7310753-4671-1c75-4271-98cb042c4e83.png)

ちなみに

```
10011100
```

は15６です。

計算式としては倍倍チャンスのようになります。

左に一つシフトすると２倍、2つだと4倍と右シフトすると1/2とかになっていきます。

でも右シフトするときに開いた上位桁はどうなるかは後ほど説明してくれるそうです。

##まとめ

少しずつではありますが着実に進んでいる感じがあります。