OmniAICreator/Qiita-1.07M huggingface dataset:
APIにできることはまだあるかい

#APIを活用して音楽のサンプルトラックを取得してみた[初心者向け]
**所要時間：2分**　
**費用：無料**
**今回利用したAPI：Deezer (Rakuten RapidAPI掲載のもの)**
**API活用経験が無い方でも2分で簡単にテストができます**

1. まずは、[Rakuten RapidAPI](https://api.rakuten.net/signup) でのアカウント作成。表示名/ユーザ名、emailアドレスとパスワードの設定をし、I'm not a robotに✔をいれて、新規登録ボタンをクリック。
![NewAccount.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366970/3dbc6ca1-c065-00f4-94ac-3c0323670f6e.png)

2. アカウント作成後、ログインした状態で[Deezer API](https://api.rakuten.net/deezerdevs/api/deezer-1) にアクセス。GET* Searchエンドポイントが選択されている事を確認。

3. [q] 欄にお好みのアーティスト名、或いは曲名を入力(海外のAPIのため、洋楽の方が検索ヒットしやすいのですが、今回は日本のアーティストでテストしました)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366970/238cb678-0978-539c-a304-c87e77408439.png)

3. [テスト]ボタンを押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366970/40d3ee84-94f7-ec68-03cd-131e96fbbfb4.png)
4. 結果確認
1) [レスポンス]欄を確認
2) HTTP Status 200 が返り、正常処理されていることを確認
3) [レスポンスボディ]　欄にて [Data] > [＜任意の数字＞] > 
   [preview] へとナビゲート
4) [preview] フィールド中の URL を新しいブラウザタブ等で開く
5) 30 秒間のサンプルトラックを聴き、正しく検索できていることを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366970/3813b5f9-bbc6-ea67-6c82-9dd60d69b8f9.png)
 
5. 検証結果に問題がなく、実際に自分のアプリをAPIに接続するときは、「コードスニペット」タブに切り替えて、お使いのプログラミング言語を選択して、スニペットをアプリに挿入すれば完了です。APIを活用すると、画像認識技術等も簡単にアプリに取り込めます！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366970/8cbb032c-046d-db14-912b-ff048b122388.png)
欲張最良優先探索GBFS

ゲームプログラミングc++の中で出てきたのでメモついでに残しておく.
初投稿なので不足する点があるのはご容赦いただきたい.

GBFSはヒューリスティック関数h(x)を用いることで次に評価すべきノードを決定していく.現在までの道のりを考慮せず,次に進むべき道の予想のみに頼って探索を進めて行くために最適とは言い難いらしい. しかし場合によってはよく働く探索法にもなりうるとのこと.個人的にはA*アルゴリズムへの拡張も考えて,腰を据えて取り組んだ.

```cpp:GBFS.h
#ifndef GBFS_hpp
#define GBFS_hpp

#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <unordered_map>

struct WeightedEdge
{
    //エッジにつながっているノード
    struct WeightedGraphNode* mFrom;
    struct WeightedGraphNode* mTo;
    
    //エッジの重み
    float mWeight;
};

struct WeightedGraphNode
{
    //このノードから出て行くエッジを格納
    std::vector<WeightedEdge*> mEdges;
};


struct GBFSScrach
{
    const WeightedEdge* mParentEdge = nullptr;
    float mHueristic = 0.0f;
    bool mInOpenSet = false;
    bool mInCloseSet = false;
};


double ComputeHeuristic(int *edge);

using GBFSMap =
std::unordered_map<const WeightedGraphNode*, GBFSScrach>;

#endif /* GBFS_hpp */

```

###注意点としては
+ ここで使用している連想配列は使うにはunorderd_mapのインクルードが必要になる.
+ "WeightedEdge","WeightedGraphNode"については定義が必要.




```cpp:GBFS.cpp

#include "GBFS.h"
#include <algorithm>

bool GBFS(const WeightedEdge& g, const WeightedGraphNode* start, const WeightedGraphNode* goal, GBFSMap& outMap)
{
    std::vector<const WeightedGraphNode*> openSet;
    
    const WeightedGraphNode* current = start;
    outMap[current].mInCloseSet=true;
    do {
        for(const WeightedEdge* edge : current -> mEdges)
        {
            GBFSScrach& data = outMap[edge -> mTo];
            
            if(!data.mInCloseSet)
            {
                data.mParentEdge = edge;
                if(!data.mInOpenSet)
                {
                    //ヒューリスティックを計算してオープンセットに追加する.
                    data.mHueristic = ComputeHeuristic(edge -> mTo, goal);
                    data.mInOpenSet = true;
                    openSet.emplace_back(edge->mTo);
                }
            }
        }
        
        if(openSet.empty())
        {break;}
        
        //最もコストの低いノードをオープンセットから探す.
        auto iter = std::min_element(openSet.begin(), openSet.end(), [&outMap](const WeightedGraphNode a, const WeightedGraphNode* b)
                                     {return outMap[&a].mHueristic< outMap[b].mHueristic;
                                         
                                     });
        
        //それをカレントノードにして,オープンセットからクローズドセットに移す.
        
        current = *iter;
        openSet.erase(iter);
        outMap[current].mInOpenSet = false;
        outMap[current].mInCloseSet= true;
    }while(current == goal);
    
    //経路を見つけたか？
    return (current == goal) ? true : false; 
}


```

#### 注意点としては
+ <algorithm>のインクルードが必要
+ ComputeHeuristicに関しては書籍では省略されているので自分で定義する必要がある.

```cpp:GBFS.cpp
//ヒューリスティックを計算してオープンセットに追加する.
               data.mHueristic = ComputeHeuristic(edge -> mTo, goal);

```

この部分については下の図のような解釈でいいかと思われる.
現在見ているノードに接続された子ノードからgoalノードまでのヒューリスティックを計算している.

![IMG_7918.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/493232/23c21fff-5186-30da-9801-61b0d0effe1d.jpeg)


#### 参考文献
ゲームプログラミングC++ 著:Sanjay Madhav, 訳:吉川邦夫, 監修:今給黎　隆
ArgoCDのApplicationにhelmを使用する

# はじめに

KubernetesのCDツールとして[ArgoCD](https://argoproj.github.io/argo-cd/)を使用しています。
ArgoCDの管理対象(Application)にhelmチャートを指定してみたので、調べた内容をまとめました。

参考：[ArgoCD - Declarative Setup クイックリファレンス](https://argoproj.github.io/argo-cd/operator-manual/declarative-setup/#quick-reference)

# 動作環境

- Azure Kubernetes Service(AKS)
- ArgoCD v1.1.1

# yaml記述例

Applicationにはhelm公式の[nginx ingress](https://github.com/helm/charts/tree/master/stable/nginx-ingress)を使用しています。

```yaml:argocd-app-nginx-ingress.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: nginx-ingress
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/helm/charts.git
    targetRevision: 0ef8d0d9033417d17d2872f32c97b7f999f9eb8f
    path: stable/nginx-ingress
    helm:
      parameters:
      - name: "controller.replicaCount"
        value: "2"
      releaseName: nginx-ingress
      valueFiles:
      - https://raw.githubusercontent.com/user/sample/values-nginx.yaml
  destination:
    server: https://kubernetes.default.svc
    namespace: default
  syncPolicy:
    automated:
      prune: true
  ignoreDifferences:
  - group: ""
    kind: Service
    jsonPointers:
    - /spec/clusterIP
```

ArgoCDが動作しているクラスタに対し、上記リソースを作成すればApplicationを管理できます。

```bash
$ kubectl apply -f argocd-app-nginx-ingress.yaml
```

# 設定(spec.source)

## repoURL

helmを含むリポジトリのURL。

## targetRevision

管理対象リビジョン。`HEAD`やコミットハッシュを指定します。
`HEAD`を指定すれば、リポジトリへのコミット時に自動的にKubernetesリソースを更新します。

## path

リポジトリ内のhelmチャートを含むディレクトリパス。

## helm

### releaseName

helmに指定するリリース名。

### parameters

`name`で指定したhelmの設定項目を`value`で上書きします。
values.yamlでの設定と同じですが、values.yamlよりも優先されます。

### valueFiles

helmに適用するvalues.yamlをURLで指定。

# 補足

## spec.ignoreDifferences

ArgoCDで同期したくない項目を指定します。
`kind`、`group`にはKubernetesリソースの種類を、`jsonPointers`には対象項目を指定します。

## 実際はhelm template

内部では以下のようなコマンドを実行してマニフェストを作成しています。

```bash
$ helm template -n {helm.releaseName} --set {helm.parameters[0].name}={helm.parameters[0].value}... -f {helm.valueFiles[0]}...
```
Amazon VPC での IPv6

Amazon VPC ではほぼIPv4でのみしか設定したことがなく、IPv6も無視できなくなってきたため、メモ。
随時何かあれば追加していこうと思っている。

#1.Egress-Only インターネットゲートウェイ#
IPv6 アドレスはグローバルに一意であるため、デフォルトではパブリックアドレスになっています。
インスタンスがインターネットにアクセスできるようにしたいが、インターネット上のリソースがインスタンスとの通信をしたくない場合は、Egress-Only インターネットゲートウェイを使用できます。
[Egress-Only インターネットゲートウェイ](https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/egress-only-internet-gateway.html)

「Egress-Only インターネットゲートウェイ」から作成していく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/beff85d3-7b09-0917-963a-d9f2b4ddee06.png)

Egress-Only インターネットゲートウェイを作成する VPC を選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/a871ade3-7890-55d8-8655-46355fadaf5b.png)

後は、ルートテーブルを以下のとおり追加するだけである。
Destination  ::/0 
Target　Egress-OnlyインターネットゲートウェイID
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/9f933ffe-c19a-4bea-ab9f-a95296be18b9.png)


#2.デュアルスタックモード#
既存の VPC が IPv4 のみに対応しており、サブネット内のリソースが IPv4 のみを使用するように設定されている場合は、既存の VPC とリソースに対して IPv6 を有効化できます。
VPC は、IPv4 または IPv6 あるいは両方を経由して通信できます。（デュアルスタックモード）IPv4 と IPv6 は、互いに独立して通信されます。
[IPv6 への移行](https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/vpc-migrate-ipv6.html#vpc-migrate-ipv6-cidr)

##1.IPv6 CIDR ブロックを VPC およびサブネットと関連付ける##

**VPC**
「アクション」から「CIDRの編集」で、「IPv6 CIDRの追加」より追加する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/ed891766-c4e8-5f55-1eeb-99d25f4d1460.png)

**サブネット**
「アクション」から「IPv6 CIDRの編集」で、「IPv6 CIDRの追加」より追加する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/6fdbe3cb-f3c5-273c-ea4f-1230ec08008e.png)

##2.ルートテーブルを更新する##
これは、【1.Egress-Only インターネットゲートウェイ】の内容と同じように設定する。

##3.セキュリティグループの編集##
ここでは、http、sshを許可するように追加した。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/0de76d5c-b1e5-3ec8-66a2-5a7daa4d8899.png)

##4.IPv6 アドレスをインスタンスに割り当てる集##
対象のEC2インスタンスを選択し、「アクション」の「ネットワーキング」「IPアドレスの管理」で、IPv6 アドレスを追加する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/a9c792bb-0472-d4eb-6e22-6e412570dc1b.png)


後はOSごとのネットワークの設定はドキュメントで。
Apex Specialist Super Badge 復習[Challenge 5]

# REST コールアウトのテスト

trailheadのとおり、Mockを作る
[Apex REST コールアウト 単元 | Salesforce Trailhead](https://trailhead.salesforce.com/ja/content/learn/modules/apex_integration_services/apex_integration_rest_callouts)

要件にHttpCalloutMockを使うとあるのでそのとおりにすればよいが、模擬データとなるJSONの作成が **けっこう面倒くさい** ので、リクエスト先のJSONデータを静的リソースとして保存して使うことにした。
ちなみに(このChallengeでは使えないが)静的リソースを使う場合は`StaticResourceCalloutMock `を使うこともできる。はず。

# 静的リソースの作成

File→new→Static Resourceと選択
MIME Type: `text/plain`

[コールアウト先](https://th-superbadge-apex.herokuapp.com/equipment)の情報を全部コピー&ペーストして保存。

## データをStringとして取得するには

1. StaticResourceオブジェクトとして取得
2. Bodyを参照してStringに変換

StaticResourceオブジェクトにSOQLを使ってリソースの取得を行うことができる。

```java
StaticResource sr=[SELECT id,Name,Body,ContentType
                   FROM StaticResource
                   WHERE Name='filename'
                   LIMIT 1];
//Name:ファイル名(拡張子なし)
//Body:本文
//ContentType:MIME/Type。今回はtext/plain
```

拡張子による区別もしたいなら`ContentType`を使えばできそう(未検証)

`StaticResource.Body`にファイル本文のデータが入っているのでStringに変換する。

参考

* [静的リソースの利用方法（Apex、Visualforce、カスタムボタン） | Xgeek](https://www.xgeek.net/ja/salesforce/access-static-resources-from-apex-visualforce-and-custom-button/)
* [StaticResource | SOAP API 開発者ガイド | Salesforce Developers](https://developer.salesforce.com/docs/atlas.ja-jp.api.meta/api/sforce_api_objects_staticresource.htm)

#ソースコード

※静的リソースは省略

## WarehouseCalloutServiceMock
<details><summary>コード</summary><div>

```java
@isTest
global class WarehouseCalloutServiceMock implements HttpCalloutMock{
    // implement http mock callout
    global HTTPResponse respond(HTTPRequest request){
        HttpResponse response =new HttpResponse();
        response.setHeader('Content-Type', 'application/json');
        //saved 'warehouseJSON.txt' as static resource
        StaticResource staticResource=[SELECT Body
                                       FROM StaticResource
                                       WHERE Name='warehouseJSON' LIMIT 1];
        response.setBody(staticResource.Body.toString());
        response.setStatusCode(200);
        return response;
    }
}
```
</div></details>

## WarehouseCalloutServiceTest

~~例のごとくassertする必要がないので、ひとまずCheck抜けるために作成。~~
assert要になった模様
<details><summary>コード</summary><div>

```java
@isTest
private class WarehouseCalloutServiceTest {
  // implement your mock callout test here
    @isTest static void testWarehouseCalloutService(){
        Test.setMock(HttpCalloutMock.class,new WarehouseCalloutServiceMock());
        WarehouseCalloutService.runWarehouseEquipmentSync();
    }
}
```
</div></details>

続き：[Apex Specialist Super Badge 復習[Challenge 6]](https://qiita.com/jitao/private/b3c53b0387ed5682c3c0)
【Android】対象別範囲ストレージとSAF

# SAF(StorageAccessFramework）とは？
* Androidでストレージ周りを取り扱う仕組みのこと。
* filepathではなく、Uriを使いコンテンツを特定する。
* **Contentスキーマなので、Uri.fromFile()による相互変換は効かない。**
* **特定のアプリは2020のアップデートで全てのSDKバージョンで対応必須になる（後述）**

```これは利用できない.
// uri <- file
val uri = Uri.fromFile(file)

// file <- uri
val file = File(uri.path)
```

---

# filepathでよくない？
* **アプリ内領域を使う分にはfilepathでよい。**
* getExternalFilesDir()はそのまま利用可能。
* アプリ内領域なので、アプリストレージを消去とかしたら当然消える

```
// 使える
Context.getExternalFilesDir()

// 使えない（API29よりDeprecated）
Environment.getExternalStorageDirectory()
Environment.getExternalStoragePublicDirectory()
```

---

# じゃあどういうときに使うの
* [対象範囲別ストレージ]
(https://developer.android.com/preview/privacy/scoped-storage)
* AndroidQより外部ストレージのアクセスが更に厳格化された
* **2020のアップデートでは全てのSDKバージョンで対応必須にするとのこと**
* 外部アプリが作成したものにアクセスする、外部ストレージに書き込みを行う等
* SAFを介して権限をユーザに要求することでアクセスが許可されるようになる

---

# 何を使えばいいかの判断
|判断材料|使うもの|
|---|---|
|アプリ内のみで使います|Content.getExternalFilesDir()|
|アプリ外でメディアを永続保存・共有します|MediaStore + ContentResolver|
|アプリ外でファイルを永続保存・共有します|SAF + ContentResolver|

--- 

# SAFの基本
* Intentを投げてピッカーを開く
* ユーザが操作する
* onActivityResultでUriを受け取って処理

```
fun performFileSearch() {
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
        addCategory(Intent.CATEGORY_OPENABLE)
        type = "image/*"
    }
    startActivityForResult(intent, READ_REQUEST_CODE)
}

override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
    if (requestCode == READ_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
        resultData?.data?.also { uri ->
            Log.i(TAG, "Uri: $uri")
            showImage(uri)
        }
    }
}
```

---

# SAFで権限付きアクセス
1. 権限を要求するIntentを発行
2. ユーザがいいよって言う
3. Resultでuriを受け取り、ContentResolverでクエリを発行

[SDカード保存](https://qiita.com/kksk/items/35c16e50466485e11ddc)(Android9以前)

* CreateAccessIntentの廃止により、権限を覚えさせておくことができなくなった？
  * リフレクションでパスを強引に取得したりURIいじくり回して権限を覚えさせるとか試されているらしい -> [リンク](https://stackoverflow.com/questions/56657639/how-to-check-which-storagevolume-we-have-access-to-and-which-we-dont)
  * 
![Screenshot_20190905-195443.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255401/c0a485ed-329f-28b9-d751-8ec039825a53.png)

---

# MediaStore
対象別範囲ストレージで外部に存在するが、それがメディア（画像・音楽・音声）である場合はMediaStoreからUriを取得できる

* 写真 - 保存場所: MediaStore.Images
* 動画 - 保存場所: MediaStore.Video
* 音楽ファイル - 保存場所: MediaStore.Audio

AndroidDeveloperに書いてあることが昨日と違う・・・最新情報を確認してください。
「クロマキー合成を使い透過動画をAR空間に表示する」リファレンス


# 資料

[iOSDC2019_ARKitChromaKeyVideoPlay.key (動画再生あり: GoogleDrive)](https://drive.google.com/open?id=1rFJyPJNxRQkF8EpNURR-qZ7M32FRF1Rs)

[クロマキー合成を使い透過動画をAR空間に表示する (動画再生なし: SpeakerDeck)](https://speakerdeck.com/satoshi0212/kuromakihe-cheng-woshi-itou-guo-dong-hua-woarkong-jian-nibiao-shi-suru)

[サンプルコード: GitHub](https://github.com/satoshi0212/ARKitChromaKeySamples)
Zone Apex (Apex Domain) にAliasレコードを使わずELBを割り当てる

# やりたいこと
1. Route53以外で管理されているZone Apex(ex. example.com)をHAなリソースに割り当てたい
    * ELBとかCloudFrontとか
    * Route53外なので、Aliasレコードは利用できない
    * Zone ApexなのでCNAMEも利用できない[^1]
2. HTTPSも使いたい
3. 証明書もACMを使いたい
4. 大層な仕組み無しでやりたい

# 結果
**NLBならできた**

# NLB
Network Load Balancer

LBを作成するとSubnetごとに**固定のIP**が払い出される。
固定ということは・・・Aレコードでまかなえる[^2]。

NLBはTLS終端もできる[^3]。

# まとめ
Route53以外で管理されているZone Apex（Aliasレコードは使えない）をACMでHTTPS対応させ、LBに割り当てることができた。
ALBとNLB、利用感はだいぶ違うが、どうしても・・・！というときには便利かも。

[^1]: [Zone apexとCNAME](https://qiita.com/haruyosh/items/95b20bef7beb63d200ab)

[^2]: CLB/ALBは負荷に応じてノードが入れ替わるのでIPは不定、CloudFrontもエッジが入れ替わるのでIPは不定

[^3]: [新機能 – Network Load Balancer の TLS 終端](https://aws.amazon.com/jp/blogs/news/new-tls-termination-for-network-load-balancers/)
PHPからIMAP接続で取得したメールを既読にしない方法

# PHPからIMAP接続で取得したメールを既読にしない方法

お客さんから、「メールが勝手に既読になって困ってるんです」という依頼を受けた際に
若干ハマったのでメモ。

そもそもの「Gmailからimap接続でメールを取得してくる」という部分は以下のサイト様を参考にさせていただきました。mm
(というかほぼそのまま）
https://blog.ver001.com/php-gmail/
https://nob-log.info/2015/03/16/connecting-to-gmail-through-imap-with-php/

## 結論
接続したメールボックスから、メールを1件1件回り、
imap_fetchbody()で本文を取得してるんですが、ココだった。
https://www.php.net/manual/ja/function.imap-fetchbody.php

```
imap_fetchbody ( resource $imap_stream , int $msg_number , string $section [, int $options = 0 ] ) : string

options
ビットマスクであり、以下の組合わせとなります。

FT_UID - msg_numberは UID である
FT_PEEK - 既に設定されていない場合、 \Seen フラグを設定しない
FT_INTERNAL - 内部フォーマットで文字列を返す。CRLF に正規化しない。
```

第4引数にFT_PEEKを指定できる。
これを指定しておくと、明示的に「既読しないぜ」って言えるので、取得したメールが既読にならずに済むってワケでした。

ちなみに、第4引数に複数指定したい場合は以下のような感じ。

```
imap_fetchbody($imap_stream, $msg_number, $section, FT_UID | FT_PEEK);
```


## 備考とごにょごにょ
そもそも、IMAP接続はPOP3とちがって、
「さまざまな端末、場所から同じところに接続しても、既読状況等を同期できる」
という部分が売りでもあるわけなので、
今回みたいな悩みがあるならPOPにしなよって話があるんですが。
(他にもっとやりたいところがあってなるべく早く解決したかったｺﾞﾆｮｺﾞﾆｮ）

あと、同じコードで運用してて今までは既読がつかずに運用できていたのに、
他のコードをいじったり環境をいじいじした時から、
当コードが走ると既読がつくようになってしまった。

きっと
「FT_PEEK - 既に設定されていない場合、 \Seen フラグを設定しない」

「既に設定されていない場合」ってところがミソなんだろうなー。
今まではほかの部分でうまく設定されてしまっていて、特に困っていなかったが、
変更を加えたことによりガバが露呈してしまったと。
Nuxt.js で app.html を作る際の注意


ちょっと躓いたので備忘録として残します。

# `app.html` は `srcDir` の指定場所に配置する

[公式サイト](https://ja.nuxtjs.org/guide/views/)より
>テンプレートを変更するために、プロジェクトのルートフォルダに app.html ファイルを作成します。

と書いてあったが、その通りにルートディレクトリに `app.html` を置いても全く変化なし。

`nuxt.config.js` で `srcDir` を指定していた場合、その指定場所に `app.html` を置く必要があったのです。

ということで、 `srcDir` を指定していた場所に `app.html` を置いたら無事反映されました。
python Bottleの基本4 特殊ルーティング(独自のフィルター)の話

正規表現文字列、URLフラグメントをpython値に変換する、その逆の呼び出し可能オブジェクト3つの要素を返す関数をつくり独自のフィルターをルーターに追加できます。

``` 例題.py
app = Bottle()

def list_filter(config):
    ''' 正規表現文字列'''
    delimiter = config or ','
    regexp = r'\d+(%s\d)*' % re.escape(delimiter)
    def to_python(match): #URLフラグメントをpython値に変換する
        return map(int, match.split(delimiter))
    def to_url(numbers): #その逆の呼び出し可能オブジェクト
        return delimiter.join(map(str, numbers))
    return regexp, to_python, to_url
app.router.add_filter('list', list_filter)
@app.route('/follow/<ids:list>')
def follow_users(ids):
    for id in ids:
        ...
```
以下のスニペットは、正規表現を用い　1,2,3,4のような1桁数字をカンマで区切ったルーティングを可能とします。
```
regexp = r'\d+(%s\d)*' % re.escape(delimiter)
```

```ex5.py
# bottleの基本5
from bottle import *
import re
app = Bottle()
def list_filter(config):
    ''' Matches a comma separated list of numbers. '''
    delimiter = config or ','
    regexp = r'\d+(%s\d)*' % re.escape(delimiter)
    def to_python(match):
        return map(int, match.split(delimiter))
    def to_url(numbers):
        return delimiter.join(map(str, numbers))
    return regexp, to_python, to_url
app.router.add_filter('list', list_filter)
@app.route('/follow/<ids:list>')
def follow_users(ids):
    x="\n".join(['<h3>%s</h3>'%x for x in ids])
    for id in ids:
        print(id)
    return x
@app.error(404)
def error404(error):
  return template("<h1>{{error_message}}</h1>", error_message="404 ページが存在しません。")
HOST,PORT='localhost',8080
if __name__ =='__main__':
    app.run(host=HOST,port=PORT)
```
上記のプログラムを実行すると　http://localhost:8080/follow/1,2,3

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274715/e5e26d57-a66a-2e47-566f-f9c208550473.png)
パラメータを配列を受け取ることができます。

また、urlをhttp://localhost:8080/follow/1,2,3,aにすると以下のようになります。
regexp = r'\d+(%s\d)*' % re.escape(delimiter)この正規化フィルタで除外されるので
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274715/807e38c3-3863-1e95-a05a-866d32b3de65.png)
となります。

Rest API などで可変長パラメータを使いたい時などの例をいかに示します。
Url http://localhost:8080/follow/東京,千葉,茨木
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274715/52a7782a-d5fc-1636-4853-8484ac7bee14.png)

``` ex6.py
# bottleの基本6
from bottle import *
import re
app = Bottle()

def list_filter(config):
    ''' Matches a comma separated list of numbers. '''
    delimiter = config or ','
    regexp = r'.*' #文字だったらなんでも許可する

    def to_python(match):
        return map(str, match.split(delimiter))

    def to_url(numbers):
        return delimiter.join(map(str, numbers))

    return regexp, to_python, to_url

app.router.add_filter('list', list_filter)

@app.route('/follow/<ids:list>')
def follow_users(ids):
    x="\n".join(['<h3>%s</h3>'%x for x in ids])
    for id in ids:
        print(id)
    return x
@app.error(404)
def error404(error):
  return template("<h1>{{error_message}}</h1>", error_message="404 ページが存在しません。")
HOST,PORT='localhost',8080
if __name__ =='__main__':
    app.run(host=HOST,port=PORT)
```
plunkerでtensorflow.js その7

#概要

plunkerでtensorflow.jsやってみた。
xorやってみた。
tf.variableで書いてみた。
weight、biasを取り出した。

#結果


```
Tensor
    [[-3.4681022, 0.379121 , -1.4711456, 2.2247136 , 2.3135107 , 2.7624693, -1.83576 , -1.1545312],
     [2.1978209 , 0.2895245, 2.0881913 , -1.3450832, -1.4154571, 1.9255028, 3.2867477, 1.956522  ]]
Tensor
    [-0.6591252, 0.3864409, 0.4982838, 0.3707547, 0.3982254, -0.3612466, 0.4284867, 0.2701645]
Tensor
    [[1.4324994 ],
     [0.7911373 ],
     [-2.3011343],
     [-1.7614117],
     [-2.4442003],
     [3.9701838 ],
     [-1.837263 ],
     [-1.3641325]]
Tensor
    [0.9285715]
```

#成果物

https://embed.plnkr.co/i45X33CRbYLexvyhLp1l/

以上。
plunkerでtensorflow.js その6

#概要

plunkerでtensorflow.jsやってみた。
xorやってみた。
tf.modelで書いてみた。
weight、biasを取り出した。

#結果


```
Tensor
    [[1.6774915, -1.8234038, 1.5142043, -2.1399791, -1.4323338, 2.0169325, 1.9337373, -1.9631947],
     [1.1229163, -2.4232562, 2.2655489, 1.9153926 , 1.974736  , 1.6609967, 1.2869064, 2.275655  ]],
Tensor
    [-2.1029015, 0.864454, -0.7386546, -1.0530509, 0.9525802, -0.6350285, -2.3191025, 1.2685804],
Tensor
    [[-2.8080974],
     [-1.6543933],
     [1.9982215 ],
     [2.2191041 ],
     [-2.2365394],
     [1.6570925 ],
     [-2.055619 ],
     [-2.0861378]],
Tensor
    [-0.9456517]

```

#成果物

https://embed.plnkr.co/weDSU4wsFVweSIfHjhcj/

以上。
plunkerでtensorflow.js その5

#概要

plunkerでtensorflow.jsやってみた。
xorやってみた。
tf.sequentialで書いてみた。
weight、biasを取り出した。

#結果

```
Tensor
    [[-0.8971094, 1.4029436 , -1.3633214, -0.775598 , 1.2531579 , 1.0529767, 1.3460118, -1.5597397],
     [1.57735   , -1.1888924, 1.6184694 , -0.5399966, -0.9783241, 0.9480417, 0.9573314, -1.1738404]],
Tensor
    [0.428151, 0.7863605, 0.8015493, 0.8869765, 0.6552361, 0.3099377, 0.1825127, 0.0495548],
Tensor
    [[-1.7588012],
     [-1.5193572],
     [-1.1239196],
     [0.8726832 ],
     [-1.7272931],
     [1.4907871 ],
     [1.1091278 ],
     [-0.9800876]],
Tensor
    [0.1271933]
```

#成果物

https://embed.plnkr.co/A9O03FdAwj2oXqOETND2/

以上。
Certbotで証明書を更新しようとした際に詰まったところ

`certbot renew --standalone`しようとしたところ、以下のようなエラーが出ました

```
Attempting to renew cert ({ドメイン名}) from {confのパス} produced an unexpected error: Problem binding to port 80: Could not bind to IPv4 or IPv6.. Skipping.
All renewal attempts failed. The following certs could not be renewed:
  {ディレクトリ名}fullchain.pem (failure)
```

# 原因
80番ポートがnginxに占有されていたため。
一旦nginxを止めたところ問題なく処理が完了しました。

そもそも該当のサービスでHttpは使っていないので、
nginxで使うポートは443のみにして80はSSLの更新時のみに開けるように対応するべきした。
php-master-changes 2019-08-22

この日は一部標準関数の警告のエラーへの昇格、heredoc 識別子に数値が続くとパースエラーになる問題の修正、arginfo の PHP スタブへの移行、strr(i)pos() の警告メッセージを str(i)pos() のものと統一化する修正、コンパイラの警告潰しの修正があった！

# 2019-08-22
## Girgias: Promote warnings to errors in range()
- https://github.com/php/php-src/commit/7c6acc2eefcaf1b3fd03b1730db84f1f58fffec6
- [range()](https://www.php.net/manual/ja/function.range.php) の警告を例外投げるエラーへ昇格

## Girgias: Promote warning to error in array_chunk()
- https://github.com/php/php-src/commit/c70f92caf81fe84ac8e58e27a695b1622805bfcc
- [array_chunk()](https://www.php.net/manual/ja/function.array-chunk.php) の警告を例外投げるエラーへ昇格

## Girgias: Promote warnings to errors in array_multisort()
- https://github.com/php/php-src/commit/eaf66df51748beb3df5c2431262ebaa76578ebf1
- [array_multisort()](https://www.php.net/manual/ja/function.array-multisort.php) の警告を例外投げるエラーへ昇格

## Girgias: Promote warnings to errors in array_combine()
- https://github.com/php/php-src/commit/7d4e3dc32d5bcf386f53607b3190e9a856844ad1
- [array_combine()](https://www.php.net/manual/ja/function.array-combine.php) の警告を例外投げるエラーへ昇格

## cmb69: Fix [#78441](https://bugs.php.net/bug.php?id=78441): Parse error due to heredoc identifier followed by digit
- https://github.com/php/php-src/commit/310708845ff02b9e252b7a02616290384dd846ba
- [7.3~]
- heredoc 識別子に数値が続くとパースエラーになる問題の修正

## LeSuisse: Add stub for ext zlib
- https://github.com/php/php-src/commit/70fa43edbe50d136d1f99182f897ee5ca8e7c8e0
- ext/zlib で、arginfo を PHP スタブへ移行

## Girgias: Normalise strr(i)pos offset messages with str(i)pos ones.
- https://github.com/php/php-src/commit/ab76c613fed4b05fac8496b40fbc0941ed25af30
- strr(i)pos() の警告メッセージを str(i)pos() のものと統一化

## cmb69: Fix var_unserializer debug code
- https://github.com/php/php-src/commit/69ba2b98d1aa3c5de6129ceb456da891c6b961b8
- [7.4~]
- var_unserializer のデバッグ出力コードでコンパイラ警告が出ていたのを修正
【UX的ユーザーへの配慮】特定の要素だけ、スクロールバーを常に表示させたい [CSS]

## 背景
### やりたい事
ユーザーに**「ここはスクロールできる場所だな」**というのを認識させたくて、一部の要素にだけ**常に**スクロールバーを表示させたい。

### やった事
『常にスクロールバー 表示 css』とかでググると、`overflow: scroll;`の使った実現方法が出てきましたが、表示されなかった。
一番上に出てくるのが2016年の記事だったので。ブラウザが進化した...?



## 解決方法
### スクロールバーをCSSでデザインする
CSSでスクロールバーをカスタマイズするって方法でやりたい事が実現できた。
バーが常に表示されているので、可視性が上がった。

[こちら](https://qiita.com/hibikikudo/items/ee1b913479bceddb654c)の記事を参考に、スタイルを調整しました。
ありがとうございます！
AWS Glue jobのpython shellをCloudFormationからpython3で指定して作成する方法

# 経緯
公式ドキュメントみてもなかなかみつけられなかったのでメモです。
※CLIのほうのドキュメントから推定しました。

# ソースサンプル
```
  GlueJob:
    Type: AWS::Glue::Job
    Properties:
      Command:
        Name: pythonshell
        ScriptLocation:  !Sub 's3://<ソースファイル置いてるバケット名>/xxx.py'
        PythonVersion: 3  # ←これで設定ができます。これを記載しないと現在(2019-09-06)はデフォルトがpython2
      # その他の設定は公式を参照 
```
Ajax + モーダル(Bootstrap4)でHTMLコードプレビュー機能 



##なぜかというと
HTMLタグも含めて投稿・表示できるコンテンツを作成しようとしていて、
「公開前に（HTMLの）プレビューが出来る機能が欲しい」という要望をいただきまして、めんどくさい。
PHPに[strip_tags()](https://www.php.net/manual/ja/function.strip-tags.php)という便利な関数がありますが、
下書き機能は、仕様がややこしくなるのでイヤだ、社内システムなので。
ページ遷移して戻ってくるとか子ウィンドウ出現は、今時流行らないですね。

なので、Ajax + モーダル(Bootstrap)です。
試してみました。

Ajaxって以前から少しづつ使って来ましたが、
どうにも自分の感覚的にイマイチなので、積極的にはやって来ませんでした。
（「データ操作は全てサーバーサイドでやるべき」というWeb開発大昔の刷り込み）
という事もあり、先々の備忘の為に書き記しておきます。

[参考サイト](https://agohack.com/ajax-post-array/)

##HTML
余分なタグやクラスなどは全て省いています。

```HTML
<!-- フォーム -->
<textarea id="doc">
<div class="text-danger">Bootstrapのクラスも使える</div>
<a href="#">リンク</a><br>
<p>段落</p>
<ul>
  <li>リスト</li>
  <li>リスト</li>
</ul>
<ol>
  <li>リスト</li>
  <li>リスト</li>
</ol>
<table border="1">
  <tr><th>項目</th></tr>
  <tr><td>値</td></tr>
</table>
<h1>例えばh1タグはストリップされる</h1>
</textarea>

<!-- ボタン -->
<button type="button" id="modalButton" >HTMLプレビュー</button>

<!-- モーダル -->
<div class="modal fade" id="modal01" tabindex="-1" role="dialog" aria-hidden="true">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-body text-left" id="modalHtml"><!-- text-leftしないとなぜか右寄りへ？ -->
      </div>
    </div>
  </div>
</div>
```

##JavaScript
```JavaScript

$(function(){
    $("#modalButton").on("click", function(){//ボタンが押された時
        var doc = $("#doc").val();//フォームのtextareaからデータ取得
        $.ajax({
            type: "POST",//メソッドはPOST
            url: "htmlpreview.php",//データを渡すPHPファイル名
            data: { "doc" : doc },//送信データ定義
            dataType : "json"//データタイプはJSON
        }).done(function(data){
            $("#modalHtml").html(data.doc),//PHPからデータを受取り⇒モーダルへ渡す
            $("#modal01").modal("show")//モーダル出現
        }).fail(function(XMLHttpRequest, textStatus, error){//エラー処理
            alert(error);
        });
    });
});
```
##PHP（htmlpreview.php）
allowable_tags（ストリップしないタグ）は、div a p br ul ol li table tr th td のみとしています。

```PHP
//POSTデータをstrip_tags()
//allowable_tagsは<div><a><p><br><ul><ol><li><table><tr><th><td>のみ
$doc = strip_tags($_POST['doc'], "<div><a><p><br><ul><ol><li><table><tr><th><td>");

//配列へ収納
$list = array("doc" => $doc);

//出力
header("Content-type: application/json; charset=UTF-8");
echo json_encode($list);

exit;
```

せっかくサーバーへデータを送ったので、除染やらチェックやらもやるべきですね。
php-master-changes 2019-08-21

この日はエラーの例外化で不要になった RETURN_FALSE の削除、不要コードの削除があった！

# 2019-08-21
## nikic: Remove some unnecessary RETURN_FALSE
- https://github.com/php/php-src/commit/85b17a04298389e2a1ecfe673ae9fcc23f0f93c4
- エラーの例外化で不要になった RETURN_FALSE の削除

## Girgias: Remove dead code in base64.c
- https://github.com/php/php-src/commit/01996c4b69ca1c22522dc7bec38a783c48861bec
- [7.4~]
- base64.c の不要コードの削除
AWS認定ビッグデータ - 専門知識 勉強記~EMR~

今回は EMR に関する勉強記録となる.なお,記事は適宜更新していく.

# 概要
## EMRの層

- Application:Hive,Pig,Sparketc
- Batch : MapReduce
- Interactive: Tez
- In Memory: Spark,Flink
- YARN: Cluster Resource Management
- Storage:S3(EMRFS),HDFS

**ビッグデータの中で、イベントプロセスとデータプロセスを担当**
**構成要素：分散処理基盤、分散処理アプリケーション**

# アーキテクチャ
マスター：コアとタスクを管理、F/O非対応、１つのみ。障害は滅多に発生しないけど、万が一を考えてデータはS3に退避するのが推奨。
コア：1つ以上のノード。データノードが動きローカルディスクがHDFS(インスタンスストア、EBS)が使われる。スレーブノードがダウンしてもじょ実行できる。コアノード追加可能。HDFS容量増加、CPU/MEM増設可能。
タスク：HDFSを持たない以外コアと一緒。RIやスポットを適用するならここ。

# アプリケーションの特徴
## 分散処理系
* Hadoop:文処理の基盤。YARN(リソース管理)+HDFS(分散ストレージ)の上で各種アプリが実行される。MapReduceもその1つ。多くのEMRアプリがYARNを使うのでほぼ必須
* Hive:YARN上で実行される、分散SQL実行環境。実行エンジンとして、MapReduceなどが使える。S3のでーたをチョ憶説読み書き可能
* Tez:YARN上でDAGを実行するのに最適化したエンジン・。Hiveの実行エンジンに指定するだけで、多くのHiveクエリが高速化する。
* Spark：分散処理のフッレームワーク。インメモリなMapReduce。YARN上で実行でき、MapReduceよりも高速化かつ簡単に分散処理可能。Spark SQL、Spark Streaming、MLlib(機械学習)もできる
* Flink:YARN上で実行でき、ストリーミング処理もバッチ処理もどちらも同一のランタイムで実行する
* Presto:分散SQL実行エンジン。HDFSとS3など複数のデータソースのデータを処理できる。対話的に処理できる。
* Pig:Pigは大規模データセットを処理するためのスクリプト言語(Pig Latin)であり、実行観光である。PigはHive同様、内部でMapperとReduceに置き換えてデータ処理を行う。Hadoopのシェルスクリプトのような動きができる。Pigはデータのグループと結合処理といったSQLのような処理も可能。
* HBase:HDFS上に構築される分散KVS。スループットと大容量
* Impale:SQL使ったインタラクティブ(対話的)アナアドホッククエリを行う。HadoopエコシステムのOSS。超並列処理(MPP)をMapReduceの代わりに使う。HBaseテーブルまたはHDFSのデータを素早く蹴りできる。
* Hunk:EMRとS3のデータをインタラクティブに探索、分析、可視化してSplunk分析に活用できる

### 個別のアプリケーションのメモ
#### Hive
SQLを使ってデータ処理ができるHadoopアプリ
Hiveを使う場合、ジョブフロー起動時にアプリケーション構成を決める必要あり：２つ。バッチジョブフロー、インタラクティブジョブフロー
前者は、データ処理が終了すると処理結果をS3に格納し、ジョブフローは消滅する
後者は、データ処理が終了してもジョブフローは存在し、次の作業指示待ちになる
HiveでKinesisのデータを処理できる:Stream内のシャードごとにMapperがデータを読み出す(Kinesisの保存デーータをフルスキャン、DynamoDBのチェックポイントを使うと前回読み出したデータ移行のみ読み込める)

**処理例**
１、テーブル定義でHDFSやS3をソースに指定してサーバーにアップ
２、テーブル定義がメタデータ(マスターのMySQL)として保存される
３、定義したテーブルに対して処理を実行(SQL
４、テーブルのメタデータを取得
５、クラスタに処理を以来
６、実際のデータソース(HDFS、S3)から読み出しつつ指定した処理を行う

# EMRとYARN
YARN: グローバルリソースマネージャー：システム全体のリソースの管理権限。役割は、スケジューラとアプリケーションマネージャー。
マシンごとのノードマネージャー：コンテナ、リソースの監視の状態
MapReduce,Hive,Pig,Spark on YARN
EMRクラスタがもつ計算資源をYARNがアプリケーションに割り振ってくれる
マルチテナントなクラスタも簡単に作れる

# HDFS
**ファイルシステム**

- インスタンスストア:レイテンシー
- EBS
- S3(EMRFS)：暗号化、ライフサイクルとセキュリティポリシー。DynamoDBがバックにいる。Kinesis Firehosとの統合も簡単。

## HDFS vs EMRFS
・拡張性：S3
・耐障害性：S3
・耐久性：S3
・コスト：S3
・スピード：EBS/インスタンスストア
・セキュリティ：S3(IAM、バケットポリシー、SSL)、EBS/インスタンスストア(ケルベロス、YARN、SSLアップロード)

### 結局どっち選ぶ？
S3:拡張性、持続性、勝ち
EBS:パフォーマンス、ParquetとORCsのような特別なフォーマット

# EMRのアンチパターン
* 小さなデータセット
* ACIDトランザクション要件：アトミック生、整合性、分離、堅牢性を要求するワークロードに対しては別のRDSやEC2を使うほうがいい
php-master-changes 2019-08-20

この日は Windows 1903 で OneDrive へのフォルダへアクセスできなくなっていた問題の修正、エラーの例外化で不要になった RETURN_FALSE の削除、不要コードの削除、mysqlnd への CLIENT_CONNECT_ATTRS のサポート追加と \_server_host の追加、C++ 形式のコメントを使っていた箇所の修正、arginfo の PHP スタブへの移行、Windows 版 7.4 での fstat() のバグ修正、ドキュメントの更新、opcache の func_info の修正、テストの修正があった！

# 2019-08-20
## cmb69: Fix [#78220](https://bugs.php.net/bug.php?id=78220): Can't access OneDrive folder
- https://github.com/php/php-src/commit/81f52158b42318f17f67468cccc4a8dc03bba942
- [7.2~]
- [scandir()](https://www.php.net/manual/ja/function.scandir.php) などで Windows 1903 だと OneDrive のフォルダへアクセスできなくなっていた問題の修正

## nikic: Remove some unnecessary RETURN_FALSE uses
- https://github.com/php/php-src/commit/af5c637f9667c97c83759dcf8581479aa6636c44
- エラーの例外化で不要になった RETURN_FALSE の削除

## Henrique Duarte: Add stubs for filter extension
- https://github.com/php/php-src/commit/a6e1094b6e0c59cd4180eb318b30a1365e90ed57
- ext/filter で、不要になった arginfo の削除

## GuuBu: fix the problem for connect_attr, set db condition, and add a new attribute _server_host
- https://github.com/php/php-src/commit/cdf16c010a11fc1f91c8807556ccc15b374c0922
- [7.2~]
- ext/mysqlnd で、CLIENT_CONNECT_ATTRS に対応していなかったのを修正し、connection attributes に _server_host を追加
- [PR:4340](https://github.com/php/php-src/pull/4340)

## cmb69: Don't use C++ style comments
- https://github.com/php/php-src/commit/963b40c9a8921c99320db83ca35968aa595f40b3
- [7.3~]
- ext/ldap で、C++ 形式のコメントを使っていた箇所の修正

## simPod: Add Calendar ext PHP stubs
- https://github.com/php/php-src/commit/3b2329dae9f8e393717d363976afa64fa220aaa2
- ext/calendar で、arginfo を PHP スタブへ移行

## simPod: Add Curl ext PHP stubs
- https://github.com/php/php-src/commit/4867864caee22f6e7333a295ad8ef5e709594c9c
- ext/curl で、arginfo を PHP スタブへ移行

## cmb69: Fix [#78386](https://bugs.php.net/bug.php?id=78386): fstat mode has unexpected value on PHP 7.4
- https://github.com/php/php-src/commit/c03114e55c7b9367fc9be895fe0df01cd1b62cab
- [7.4~]
- Windows 版で [fstat()](https://www.php.net/manual/ja/function.fstat.php) の mode が 7.3 以前と違っていた問題の修正
- ディレクトリでなくば通常ファイル、みたいな判定だった

## derickr: Update NEWS for PHP 7.4.0beta4
- https://github.com/php/php-src/commit/b3561e932944b048e8b034d65b8b8ad8ab1de5a3
- NEWS で beta3 が beta4 になった？もよう

## derickr: Update NEWS for 7.4.0RC1
- https://github.com/php/php-src/commit/cf678da52dd7e40a4d1f735a60431b1456ae4165
- NEWS へ 7.4 RC1 のエントリ追加

## TysonAndre: Fix opcache type info for stream_bucket_make_writable()
- https://github.com/php/php-src/commit/50be2ecbd7ca9a9c857a838a09073b2a08b1a9a5
- ext/opcache で、[stream_bucket_make_writeable()](https://www.php.net/manual/ja/function.stream-bucket-make-writeable.php) の返り値型情報へ MAY_BE_NULL を追加、MAY_BE_FALSE を削除
- [PR:4567](https://github.com/php/php-src/pull/4567)

## remicollet: ensure proper settings for test
- https://github.com/php/php-src/commit/08aafbe93e3ded391446fd84bb5f4a4573ce5f54
- [7.3~]
- ext/pcre で、テストの ini 指定が欠けていたのを追加
【ネットワーク】サーバーにアクセスできない時はpingを飛ばす

## ping XXX.XXX.XXX.XXX
以下のようにグローバルIPアドレスへpingを送ると
応答が確認できます。

```terminal:ターミナル
ping 35.190.247.0
```

## 最後に
IPアドレスはグローバルIPアドレスです。
ちなみに例に出したものは適当です。
Amazon Cognitoの認証前トリガーを用いたユーザーの論理削除の実装

#### やりたいこと
「論理削除済みのユーザーをログインさせない」処理の実装

#### 実装
Cognito ユーザープールの標準機能では論理削除というものが(多分)存在しない
そのためカスタム属性 [isDeleted]を追加して論理削除済みか否かを管理しようと思う
また、Cognitoのログインシーケンスではいくつかのタイミングで「トリガー」を挟み込むことが出来るので、今回はそのトリガーのうち「認証前トリガー」を用いて「論理削除済みのユーザーをログインさせない」処理を実装する

``` Python
def lambda_handler(event, context):
    print(event); #cloud watchに出力用
    isDeleted = event['request']['userAttributes']['custom:isDeleted'] #0:未削除, 1:削除済み
    if isDeleted == '1':
        raise Exception("'This user has already been deleted.'")
    return event

```
Lambdaができたらユーザープールと連携
サイドメニューから「トリガー」へ
認証前のドロップダウンリストから作ったLambdaを選ぶ
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124541/01f6c34e-155f-b52c-d1d1-9b83b08469c2.png)
一番下の保存ボタンをクリック

#### 結果
実際にログインしようとしてみるとこうなる
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124541/43742b30-3d4b-57eb-0385-06753adf4f7b.png)

####注意事項
正常系の場合はeventを返さないとなんかエラーになる
【運用設計】スマホアプリの証明書管理

スマートフォンアプリの運用設計をするにあたり、証明書の運用サイクルを確認したので下記にまとめます。

## iOS

* ビルド証明書（配布証明書）  
有効期限は1年（development）、もしくは3年（Distribution）。MacのキーチェーンでCSRを作成し、Developer Consoleにアップして、落としてきて、Xcodeでごにょごにょすることで作成できる。
AdHocの場合も証明書管理は必要（cf. https://qiita.com/isaac-otao/items/126bced83d9af86c7ce5）
* ProvisioningProfile  
有効期限は1年。Developer Consoleからダウンロードする。ProvisioningProfileはBundleIDとビルド証明書をひもづけるためのもの。基本的に1アプリごとに1ProvisionigProfileを作成することが多い。

## Android

* keystore  
CSRを作成し、Android Studioでkeystoreを作成する。
通常、有効期限は25年なので証明書の更新を行なうことはそうそうない。

iOS,Android共に、証明書自体の有効期限が切れてもアプリ自体が使えなくなることはない（※iOSのEnterpriseライセンスの場合は、アプリが起動しなくなる）。障害発生など緊急でビルドが必要になるケースに備えて、有効期限が切れるタイミングで証明書は予め作り直しておいたほうが安心
pythonとrubyのデフォルト引数の挙動

# デフォルト引数の評価される順番

redmineのソースコードを読んでいたら、デフォルト引数の右辺に関数を使っていたので、気になって調べてみました。
個人的には発見した感がありますが、実際にはデフォルト引数の右辺に関数持ってくる実装は可読性を下げる可能性が高そうなので、やめておいた方がいいかと思います。

# Pythonの場合

以下のコードを実行した時、標準出力されるのはどういう順番かと言う話です。

```python:exec.py
def func1():
    print("begin func1")
    return "func1"


def func2(a=func1()):
    print("begin func2")
    return "func2"

class ClassA():
    print("begin classA")

    def funcA(self, a=func2()):
        print("begin funcA")


print("main")
print(func2())
a = ClassA()
a.funcA()
```

正解は、以下の通り。

```shell-session
begin func1
begin classA
begin func2
main
begin func2
func2
begin funcA
```

関数の宣言が読み込まれた時点で評価されています。
ちなみにclass直下のところで呼び出される関数もclassの宣言を読み込んだ時点で評価されるので、このような順番になっています。

# Rubyの場合

同じ形でrubyも書いてみます。

```ruby:exec.rb
def func1
  p "begin func1"
  "func1"
end

def func2 a=func1
  p "begin func2"
  "func2"
end

class ClassA
  p "begin classA"

  def funcA a=func2
    p "begin funcA"
  end
end


p "main"
p func2
a = ClassA.new
a.funcA
```

この実行結果は以下の通り。

```shell-session
"begin classA"
"main"
"begin func1"
"begin func2"
"func2"
"begin func1"
"begin func2"
"begin funcA"
```

pythonと違いデフォルト引数の右辺に来ている関数は、関数が実際に呼び出されたタイミングで評価されます。
それ以外の違いはないのですが、だからこそ見つけづらい言語の違いかなとおもいました。

# さらにスコープについて

コメントで同じことを書いている記事をみていたらスコープについても検証されていたので確認してみました。

```ruby:exec.rb
class ClassA
  p "begin classA"
  xx = 100

  def funcA a=xx
    p a
    p "begin funcA"
  end
end

a = ClassA.new
a.funcA
```
このようにするとxxは存在しないとなってrubyではエラーとなり、pythonでは普通に参照され100が表示されます。
これは、元々の概念に置き換えると納得できるスコープの考え方で、rubyではデフォルト引数の部分は関数の中で評価されることになるので、関数の中と同じスコープとなり、xxは存在しないことになります。

一方でpythonとrubyでそもそもclass直下の変数の意味が違っています。
pythonの場合は、クラス変数扱いになり、rubyはclassブロックの処理という扱い（こっちは自信なし）になります。
なので、以下のようにするとrubyでもエラーにならずに動きます。
(@@xxはクラス変数、CCはクラス定数となります）

```ruby:exec.rb
class ClassA
  p "begin classA"
  @@xx = 100
  CC = 10

  def funcA a=@@xx
    p a
    p "begin funcA"
  end

  def funcB a=CC
    p a
    p "begin funcB"
  end
end

a = ClassA.new
a.funcA
a.funcB
```

# まとめ

書き出すと単純ですが以下のことが言えるかなと思います。

* rubyとpythonではデフォルト引数の右辺の評価タイミングが違う。
* rubyは関数が実行された時に実行（関数の中で実行されるのとイコール）
* pythonは関数の宣言が読み込まれた時に実行（関数の外で実行されるのとイコール）
* class直下の関数はpython、ruby共にclassの宣言を読み込んだ時点で実行される。
* スコープは評価と同じようにpythonは関数の宣言なので関数の外のスコープと一緒、rubyは関数の実行時に評価されるので関数の中と同じスコープ

この違いによりシンタックスエラーの見つかり方も若干変わってくるかなと思います。
pythonだと先に実行されるので、アプリケーション実行後すぐにエラーになるのに対して、rubyは関数が実行されるまでエラーにならないことになりますし、普通にエラーになりにくいのではないかと思います。
そして、この結果からさらに言えるのは、pythonではこの書き方は基本NGだと思います。moduleの読み込まれる順序に依存して関数の結果が変わる可能性があるため、実行結果が場合によって変わってしまいます。
一方で、rubyは可読性は下がるにせよ、それなりに安全にこの書き方を許容できるのではないかと思います。
sec属性が使えなかった

# 背景
Spring Bootを使った簡単なWebアプリの作成を研修で実施した際にsec属性で躓いてしまった。
具体的な引っかかりポイントはhtmlで以下のコードを書いた際にsec属性が全く反応してくれなかったので自分への戒めに備忘録を残す。

```html:home.html
<div class="navbar-text" sec:authorize="isAuthenticated()">
Welcome, <span sec:authentication="name">Username</span>
</div>
```

# 格闘
Gradle使ってたのでいろんな記事を見たり公式ページを観に行って調べたけどうまくいかず...
よく見かけた原因は以下の4つだった。

- バージョンの依存関係が問題
- dialectが必要（元々記述していなかった）
- dialcetをbean登録していない
- sec属性を定義するときのurlが違う

最終的に分けわかんなくなって`build.gradle`が以下のような惨状に...

```gradle:build.gradle
ext['thymeleaf.version'] = '3.0.9.RELEASE'
ext['thymeleaf-layout-dialect.version'] = '2.1.1'

dependencies{
    // 一部抜粋
    compile('nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect')
    compile('org.thymeleaf.extras:thymeleaf-extras-springsecurity4:3.0.1.RELEASE')
}
```

# 解決
結局バージョン間でうまく平仄が取れていないのかなぁとバージョン情報を全部書かなかったら解決した...

- やったこと
 - バージョン指定に関する部分を削除
 - thymeleaf-layout-dialectを依存関係から削除
 - thymeleaf-extras-springsecurityを4から5に変更

結局残ったのは下の部分だけ。

```gradle:build.gradle

dependencies{
    // 一部抜粋
    compile('org.thymeleaf.extras:thymeleaf-extras-springsecurity5')
}
```

Webアプリなんてまったく触ったことないのに研修でこんな壁にぶち当たるとは...
data-JPAが勝手にテーブル作成するところでも躓いたし...
先が思いやられる笑
VSCodeのRemote SSHで「プロセスが、存在しないパイプに書き込もうとしました。」と出て繋がらない

```
remote-ssh@0.45.6
win32 x64
SSH Resolver called for "ssh-remote+mate", attempt 1
SSH Resolver called for host: xxxxxx
Setting up SSH remote "xxxxxxx"
Using commit id "xxxxxxxxxxxxxxxxxxxxxxxx" and quality "stable" for server
Testing ssh with ssh -V
ssh exited with code: 0
Got stderr from ssh: OpenSSH_for_Windows_7.7p1, LibreSSL 2.6.5
Running script with connection command: ssh -o ClearAllForwardings=true xxxxxx bash
Install and start server if needed
> Bad owner or permissions on C:\\Users\\xxxxxx/.ssh/config
> プロセスが、存在しないパイプに書き込もうとしました。
> 
Got some output, clearing connection timeout
"install" terminal command done
Install terminal quit with output: プロセスが、存在しないパイプに書き込もうとしました。
Received install output: プロセスが、存在しないパイプに書き込もうとしました。
Failed to parse remote port from server output: プロセスが、存在しないパイプに書き込もうとしました。
```

権限とかの問題っぽいので色々調べて変更してみたが私には解決出来なかった。

# とりあえずの解決方法
` ~/.ssh/config ` を削除し、` C:\ProgramData\ssh\ssh_config ` に書き込むととりあえず接続出来た。
https通信であることをALBを利用した環境でhttpdに分からせる方法

# ALBを使ってバランシングをする
クライアントのリクエストは一旦ALBで引き受けて、その後はALBにwebサーバーとのやり取りを任せます。この時ALBに元々付いている無料SSLの設定をしており、webサーバー側にはhttps接続のために Apache HTTP Server の mod_sslを利用しているので、httpsでの接続が必須になります。しかし、ALBとwebサーバーのやり取りは、httpで行われるという制約があります。ではどうしようか・・・

## 解決策
クライアント側のhttpsリクエストをwebサーバー側で検知させる

###必要なディレクティブ

- [**SetEnvIf**](http://httpd.apache.org/docs/2.4/mod/mod_setenvif.html#setenvif)

リクエストのある側面が指定された正規表現 に合うかどうかによって環境変数を設定する機能のApacheモジュールmod_setenvifを使用して使えるようになるディレクティブです。

> リクエストの属性に基づいて環境変数を設定する

このディレクティブに使える引数は、

```
1.HTTP リクエストヘッダフィールド

2.以下のリクエストの一部分のどれか:
　Remote_Host - リクエストを行なっているクライアントのホスト名 (もしあれば)
　Remote_Addr - リクエストを行なっているクライアントの IP アドレス
　Server_Addr - リクエストを受け取ったサーバの IP アドレス (2.0.43 以降のみ)
　Request_Method - 使用されているメソッド名 (GET, POST など)
　Request_Protocol - リクエストが行なわれたプロトコルの名前とバージョン (例えば、"HTTP/0.9", "HTTP/1.1" など。)
 Request_URI - URL のスキームとホストの後の部分

3.リクエストと関連付けられる環境変数のリスト。
```

###必要なヘッダー

- **X-Forwarded-Proto**

> X-Forwarded-Proto (XFP) ヘッダーは、プロキシまたはロードバランサーへ接続するのに使っていたクライアントのプロトコル (HTTP または HTTPS) を特定するために事実上の標準となっているヘッダーです。

この２つを用いて、検知させる仕組みを作ります。自分でも作業しててたった1行でできたので、驚いたものです。

## 実際にconfに書いたもの

```
SetEnvIf X-Forwarded-Proto ^https$ HTTPS=on
```
になります。リクエストヘッダにX-Forwarded-Protoを使い、正規表現にはhttpsが引っかかるようにして、関連づけられる環境変数はHTTPS=onです。
ffmpeg-pythonを使って動画の一区画を切り取り（クロッピング・トリミング）する。

# はじめに
pythonで動画をいじりたいとき、一区画を切り取り（クロッピング・トリミング）するのに手こずったのですが、
ffmpeg-pythonを使ってうまくいったのでメモです。

# 環境
OS:MacOS Mojave 10.14.4
python:3.6
ffmpeg-python:0.2.0

# 準備
ffmpeg-pythonをインストールします。

```
$ pip install ffmpeg-python
```


# コード
```cropvideo.py
import ffmpeg

upper_left_x = XX
# 切り取りたい区画のx座標（px）
upper_left_y = XX
# 切り取りたい区画のy座標（px）
width = XX
# 切り取りたい区画の幅（px）
height = XX
# 切り取りたい区画の高さ（px）

stream = ffmpeg.input('sample.mp4')
# sample.mp4に切り取りたい動画を入れる

stream = ffmpeg.crop(stream, upper_left_x, upper_left_y, width, height)

stream = ffmpeg.output(stream, 'cropoutput.mp4')
# cropoutput.mp4が切り取った動画で出てきます。

ffmpeg.run(stream, overwrite_output=True)
# overwrite_output=Trueとすることで同じファイル名の動画がすでにあっても上書きします。
```
upper_left_x, upper_left_y, width, heightはそれぞれ切り出したいところを自分でpxで指定する必要があります。

# 「pxの位置なんか分からんやん！」という場合
動画から静止画を取り出して、それをGIMPで表示されることで目視確認ができます。

まず、動画から静止画を1フレーム取り出します。

```getimage.py
import ffmpeg

tpoint = XX
# 取り出したい静止画の時間（tpoint = 10 なら動画の10秒時点の静止画が取れる）

imagename = 'hogehoge.jpg'
#取り出したい静止画のファイル名を指定

stream = ffmpeg.input('sample.mp4')
# sample.mp4に切り取りたい動画を入れる

stream = ffmpeg.output(stream, imagename, ss=tpoint, vframes=1, f='image2')
ffmpeg.run(stream)
```

取り出した静止画をGIMPで開きます。

![スクリーンショット 2019-09-06 7.17.18.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458187/e912b507-cc97-e174-6995-a40096a7c051.jpeg)
そしてまず、切り取りたい部分の左上にマウスカーソルを合わせます。（画像にカーソルが表示されていませんが、大体赤丸が付いているとこらへんを指しています。）
そうするとGIMP画面左下に「x座標,y座標」がpxで表示されます。
この座標がupper_left_x, upper_left_yに対応します。


![スクリーンショット 2019-09-06 7.17.40.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458187/27fba17e-5bb1-0e70-6ea8-876c1b5ba686.jpeg)
次に切り取りたい部分の右下にマウスカーソルを合わせます。
同様にGIMP画面左下にある座標を確認し、
width = 右下のx座標 - 左上のx座標
height = 右下のy座標 - 左上のy座標
とすればOKです。

# おわりに
上記の手順を踏むことで動画の一区画の切り取りができたのですが、
切り取られた動画の画質が元の画質より低いような気がしているのが現状難点です。

「もっと上手くできるだろ！」っていうのあれば、教えて頂けると嬉しいです。
ubuntu16.04(gnome3デスクトップ環境)+vscodeでbackground-coverが動かなかった時のトラブルシューティング

https://qiita.com/hotsun/items/e83f89e26003867dc565
https://marketplace.visualstudio.com/items?itemName=manasxx.background-cover&ssr=false

ここで紹介されていたbackground-coverですが作者サイトに管理者権限で実行してくださいと書いてあり実際```sudo code --user-data-dir ./test```みたいなことをしないと言う動かないと言う問題がありました。



どうやら同じ問題を抱えて居た有志が居たらしく解決法を提案してくれていました。
https://marketplace.visualstudio.com/items?itemName=manasxx.background-cover&ssr=false#review-details

>>在win下面运行良好，在deepin linux上没有反应。。希望解决～
It works well,but does not work on linux.Tks~

>>linux已解决 ：
sudo chmod a+w $(find /usr/share/code -iname "workbench.main.css")

どうやらパーミッションをいじるとよさそうです

バージョン違いから私の```/usr/share/code/resources/app/out/vs/workbench/```には```workbench.main.css```には見つからず
```workbench.desktop.main.css```があったのでひとまず

```
 sudo chmod a+w /usr/share/code/resources/app/out/vs/workbench/workbench.desktop.main.css
```

別のubuntuマシンには```workbench.main.css```だったこともあったのでファイルが見つからないときはそれっぽい.cssを探すなりしてください（上のfindコマンドを使ってもいいと思います）

以上で解決しました。
![Screenshot from 2019-09-06 06-43-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232732/638f1a2f-bfa1-1b0b-539e-fe7ae2575834.png)


やったぜ
gitでリモートブランチにないローカルブランチを追加してみた

# 問題

`git clone`したときローカルブランチのmasterしか作られない。

`git help`を探してもリモートブランチをローカルブランチに追加する方法が見つからなかったのでコマンドを作って解決した。

# 解決策

```shell
$ git clone <CLONE URL>
$ git branch -a
* master #masterブランチしか作られない
  remotes/origin/HEAD -> origin/master
  remotes/origin/develop #ここから下の３つのローカルブランチを追加したい
  remotes/origin/feature/first
  remotes/origin/feature/second
  remotes/origin/master

$ git for-each-ref --format="git branch %(refname:lstrip=3) %(refname)" refs/remotes|grep -v HEAD|sh
Branch 'develop' set up to track remote branch 'develop' from 'origin'.
Branch 'feature/first' set up to track remote branch 'feature/first' from 'origin'.
Branch 'feature/second' set up to track remote branch 'feature/second' from 'origin'.
fatal: A branch named 'master' already exists. #既にあるブランチには何も起きない

$ git branch -a
  develop #追加された
  feature/first #追加された
  feature/second #追加された
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/develop
  remotes/origin/feature/first
  remotes/origin/feature/second
  remotes/origin/master
```
PC関連規格の覚書

個人的によく忘れるけどたまに知りたくなる各規格の覚書です。
気分で追記していきます。まちがってたらごめんね
今の所表記はgigabits per secondで統一してるつもりです。

#PCI Experss通信速度(双方向) Gbps
| 規格 | x1 | x2 | x4 | x8 | x16 |
| --- | ---: | ---: | ---: | ---: | ---: |
| PCI Experss 1.1 | 4 | 8 | 16 | 32 | 64 |
| PCI Experss 2.1 | 8 | 16 | 32 | 64 | 128 |
| PCI Experss 3.0 | 16 | 32 | 64 | 128 | 256 |
| PCI Experss 4.0 | 32 | 64 | 128 | 256 | 512 |
| PCI Experss 5.0 | 64 | 128 | 256 | 512 | 1024 |
#SSD通信規格　Gbps
プロトコル | インターフェース | 速度
--- | --- | ---:
AHCI | SATA 3.0 | 6.0
 | SAS 2.1 | 6.0
 | SAS 3.0 | 12.0
NVMe | PCIe 3.0 x2 | 16
 | PCIe 3.0 x4 | 32
 | PCIe 4.0 x2 | 32
 | PCIe 4.0 x4 | 64
#イーサネット規格
イーサネット規格 | 通信速度 | ケーブル規格
--- | ---: | :---:
10BASE-T | 10Mbps | Cat 3
100BASE-TX | 100Mbps | Cat 5
1000BASE-T | 1Gbps | Cat 5e
1000BASE-TX | 1Gbps | Cat 6
10GBASE-T | 10Gbps | Cat 6a
40GBASE-T | 40Gbps | Cat 8
10GBASE-SR | 10Gbps | マルチモードファイバ
10GBASE-LR | 10Gbps | シングルモードファイバ
10GBASE-ER | 10Gbps | シングルモードファイバ
#USB規格仕様
##世代ごとの比較
3.2?シラネ

規格 | 通信速度 | 給電能力
--- | ---: | ---:
USB 1.0 | 1.5Mbps | 100mA
USB 1.1 | 12Mbps | 100mA
USB 2.0 | 480Mbps | 500mA
USB 3.0 | 5Gbps | 900mA
USB 3.1 | 10Gbps | ~5A (USB PD)
USB4 | 40Gbps | ????

##混沌のUSB 3.2
規格名 | 旧名称 | 通信速度
--- | :---: | ---:
USB 3.2 Gen 1 | USB 3.0 | 5 x 1 = 5Gbps
USB 3.2 Gen 1x2 | - | 5 x 2 = 10Gbps
USB 3.2 Gen 2x1 | - | 10 x 1 = 10Gbps
USB 3.2 Gen 2x2 | - | 10 x 2 = 20Gbps
k8s statefulsetで任意のサイズのvolumeでreplicaを増やしたい

# 背景

Statefulsetは一度Deployしてしまうと、volumeClaimTemplatesなどの変更ができない。
しかし、Volumeの変更はやり方がある。https://kubernetes.io/blog/2018/07/12/resizing-persistent-volumes-using-kubernetes/

結果、コード上のvolumeClaimTemplates 内のVolumeサイズと実際に使われている大きさが異なる状況になる。その状態で、Scaleしようとすると、すでに拡大したVolumeとサイズがことなり、バランスがわるくなってしまう。


# 解決策

1. pvcをほしいVolumeサイズ + statefulsetで生成されるpvcの命名規則にしたがって作成
2. scale outする


## pvc 作成

VolumeClaimTemplateから作られるpvcは、`<volumeClaimTemplateName>-<pod_name>`となるので、今回の場合は、test-storage-test-3となった

```:test-sts.yaml
...
  volumeClaimTemplates:
  - metadata:
      name: test-storage
      annotations:
        volume.beta.kubernetes.io/storage-class: gp2-topology-aware
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 30Gi
```

```:test-storage-test-3-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  annotations:
    volume.beta.kubernetes.io/storage-class: gp2-topology-aware
  name: test-storage-test-3
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
```

```
kubectl -f test-storage-test-3-pvc.yaml
```

このときに、もしも `volumeBindingMode: WaitForFirstConsumer` を使っているとPodがClaimするまで待ち以下のメッセージが出る

```
kubectl describe  pvc test-storage-test-3 -n etl
...
Normal WaitForFirstConsumer 11s (x3 over 20s) persistentvolume-controller waiting for first consumer to be created before binding
Mounted By: <none>
```

## scale out

```:test-sts.yaml
- replicas: 3
+ replicas: 4 
```

```
kubectl -f test-sts.yaml
```


#おまけ

上記の`WaitForFirstConsumer`をチェックするだけなら以下のようなPodを作成して確認すれば良い

```
apiVersion: v1
kind: Pod
metadata:
  name: test-3
spec:
  volumes:
    - name: test-storage-test-3
      persistentVolumeClaim:
        claimName: test-storage-test-3
  containers:
    - name: test
      image: nginx
      ports:
        - containerPort: 80
          name: "http-server"
      volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: test-storage-test-3
```