OmniAICreator/Qiita-1.07M huggingface dataset:
google home miniにしゃべらせる。

# 流れ
* Google Home Miniを特定する
* テキストから音声ファイルを生成する
* Google Home Miniをchromecastデバイスとして捉え、音声ファイルをキャストする

# Google Home Miniを特定する
2パターンある。ただし、前提として、Google HomeへアクセスできるLAN内の端末であること。
自分の環境では、有線LANと無線LANを両方とも有効化した状態で確認できた。

* Google Homeアプリで設定から端末のipを特定する。
要固定IP化。→DHCPでMACアドレスとIPで固定IPにする。
* mDNSで端末を動的に特定して、アドレスを都度得る。  
Google Home 端末を操作するなら、前者の方が現状、楽。  

## 簡易的に端末までの経路が確立されているかを確認する方法
いずれもmDNSでネットワーク内の端末を列挙する方法
### Windowsなら、bonjourbrowserで検索
[bonjourbrowser](https://hobbyistsoftware.com/bonjourbrowser)で検索できる。

### ubuntuなら、Avahi

`avahi-browse -alr`で一覧出来た。

### Chrome拡張のMDNS Browser
私の環境では捕捉出来なかった。

# テキストから音声ファイルを生成する

* [text-to-speech(google)](https://cloud.google.com/text-to-speech/docs/reference/libraries?hl=ja)
* 他のtext to speech api  
  * https://cloud.voicetext.jp/webapi/docs/api  
  * watosonとか
  * azureとか

# Google Home Miniをchromecastとして、へ音声ファイルをキャストする
[castv2-client](https://github.com/thibauts/node-castv2-client#readme)を使う。

この方の実装方法が良いかと思われる。
[Google Homeに話をさせる](https://www.gesource.jp/weblog/?p=8083)
ただし、google-tts-apiは、非公式な使い方[^1]をしているので、上のtext-to-speechを正しく利用したもののほうがよいかと。

cstv2-clientにて、[デフォルトのメディアレシーバー](https://developers.google.com/cast/docs/caf_receiver#default_media_receiver)のインタフェースを得ているように見える。

## google-home-notifierはおすすめしない
Google Home端末のip特定からメッセージ送信までワンパッケージになっているgoogle-home-notifierがあるが、
ローカル環境へのライブラリインストールや依存ライブラリのバージョン修正、依存ライブラリの実装修正などの手作業が多いため、おすすめしない。
こちらも、内部でgoogle-tts-apiを使っているが、非公式な使い方[^1]をしていると思われる。

# GoogleのCloud API
テキストを送信して、話させるためのCloud APIはわからなかった。
ユーザの発話をトリガーにするか、ルーティーンでの時刻起動をトリガーにする方法はあったが。
自分としては、異常検知のような使い方をしたかったため、上記の使い方を模索していた。

[^1]: グーグル翻訳のフロントサイトにクエリ付きURLを投げて翻訳時の発声ファイルを取得しているように見える。
macOSでGCCのg++を使用する。

# 動機

macOSにXcodeをインストールした状態(おそらくほとんどの開発用Macはこの状態)では、g++コマンドでclang版が動作するため、GCC版と若干挙動が異なる。
Linuxで`gcc`,`g++`を使う場合はGCC版が基本となることが多いので、maxOSでの動作もLinux版に合わせておきたい。

## maxOSの初期状態でのg++

バージョン情報を出力すると、Apple clangと表示されていることがわかる。

```sh
$ g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/4.2.1
Apple clang version 11.0.3 (clang-1103.0.32.59)
Target: x86_64-apple-darwin19.4.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
```

## macOSにGCCのg++を導入する

HomebrewでGCCをインストールする。

```sh
brew install gcc
```

インストールされたものを `g++` コマンドで使えるようにシンボリックリンクを張る。
コマンドとしては、g++のバージョンによってインストールされるファイル名が`/usr/local/bin/g++-9`などのように異なるので、最新のものを`g++`として使用するようにしている。

```sh:bash
sudo ln -sf $(ls -d /usr/local/bin/* | grep "/g++-" | sort -r | head -n1) /usr/local/bin/g++
```

```sh:fish
sudo ln -sf (ls -d /usr/local/bin/* | grep "/g++-" | sort -r | head -n1) /usr/local/bin/g++
```

## 導入後

GCC版に切り替わった。

```sh
$ g++ --version
g++ (Homebrew GCC 9.3.0_1) 9.3.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
```


## 元に戻したいとき

作成したシンボリックリンクを解除する。

```sh
sudo unlink /usr/local/bin/g++
```
Keystonejs 入門 Tutorials #7/Custom Field1

前ページ https://qiita.com/bontensuzuki/items/9982196b4f7956ba0fd9
次ページ https://qiita.com/bontensuzuki/items/7e9b5b7483b30324e9da

Keystonejsのtutorialsから学んでいきます。（ほとんど機械翻訳です）
https://www.keystonejs.com/tutorials/custom-fields

#カスタムフィールド：星
このチュートリアルでは、星評価用のシンプルなカスタムフィールドタイプを作成します⭐️⭐️⭐️⭐️⭐️

このコンポーネントの場合、データ要件は単純です。星の数を表す整数を格納する必要があります。組み込みのInteger型を拡張して、その実装を活用し、必要に応じてカスタム動作とUIコンポーネントのみを提供できます。

###フィールドタイプの定義
これが完了すると、カスタムフィールドのディレクトリは次のようになります。

```
.
└── Stars
    ├── index.js
    ├── Implementation.js
    └── views
        ├── Cell.js
        ├── Field.js
        ├── Filter.js
        ├── Stars.js
        ├── star-empty.svg
        └── star-full.svg
```


カスタムフィールドには、フィールド定義をエクスポートするindex.jsファイルが必要です。フィールド定義は、フロントエンドコードとバックエンドコードを含むフィールドを構成するすべての部分をまとめます。

スターフィールドの場合、次のようになります。

```javascript
const { Stars, MongoIntegerInterface, KnexIntegerInterface } = require('./Implementation');

const { Integer } = require('@keystonejs/fields');

module.exports = {
  type: 'Stars',
  implementation: Stars,
  adapters: {
    mongoose: MongoIntegerInterface,
    knex: KnexIntegerInterface,
  },
  views: {
    Controller: Integer.views.Controller,
    Field: require.resolve('./views/Field'),
    Filter: Integer.views.Filter,
    Cell: require.resolve('./views/Cell'),
  },
};
```


実装とアダプターはKeystoneによって使用されるバックエンドコードを参照し、ビューの下のすべては、管理UIまたはGraphQLアプリのいずれかで使用されるフロントエンドコードを参照します。

フロントエンドとバックエンドのコードを同じファイルにバンドルできないことに気付いたかもしれません。そのため、フロントエンドコードをインポートするのではなく、require.resolveを使用して文字列値を提供します。文字列値は、ファイルの場所への参照です。 Keystoneには、フィールドタイプのフロントエンドコードをコンパイルする特別なビルドステップがあります。

>
注：独自のプロジェクトの外で使用するためにフィールドタイプをパッケージ化する場合は、追加の手順が必要ですが、これらはこのチュートリアルの範囲外です。

前ページ https://qiita.com/bontensuzuki/items/9982196b4f7956ba0fd9
次ページ https://qiita.com/bontensuzuki/items/7e9b5b7483b30324e9da
SwiftUIでNavigationController(NavigationView)

##SfirtUIで画面遷移(navigationBar)

swiftUIを用いて画面遷移を行います。
navigationBarのようなものを作成したい時、その前提となる知識です。


遷移元となる画面

```swift
import SwiftUI

struct FirstView: View {
    var body: some View {
        
        NavigationView {
            NavigationLink(destination: SecondView()){
                Text("画面遷移")
            }
            .navigationBarTitle("遷移前")
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        FirstView()
    }
}
```

`NavigationLink(destination: 遷移先のView)`{}を用います。
遷移先のViewに特別に書くことはありません。

```swift
import SwiftUI

struct SecondView: View {
    var body: some View {
        Text("Hello, World!")
    }
}

struct SecondView_Previews: PreviewProvider {
    static var previews: some View {
        SecondView()
    }
}
```
Keystonejs Tutorials #5/Creating relationships２

前ページ https://qiita.com/bontensuzuki/items/7cd598a7075f6c970f14
次ページ https://qiita.com/bontensuzuki/items/9982196b4f7956ba0fd9

Keystonejsのtutorialsから学んでいきます。（ほとんど機械翻訳です）
https://www.keystonejs.com/tutorials/relationships

###ユーザーとTodoの間に双方向の関係を設定する(Setting up a two-sided relationship between User and Todo)


タスクと担当者が単一の関係の2つの異なる側面にすぎないことを示すために、設定を更新する必要があります。User.jsでタスクフィールドを次のように調整します。


/lists/User.js

```javascript

task: {
  type: Relationship,
-  ref: 'Todo',
+  ref: 'Todo.assignee',
}
```


Todo.jsの、担当者(assignee)フィールドを更新します。

```javascript

assignee: {
  type: Relationship,
-  ref: 'User',
+  ref: 'User.task',
}
```


管理UIを開始し、Todoを作成してユーザーを割り当てます。ユーザーのタスクフィールドを確認して、すでに設定されていることを確認してください。

管理UI/Todo

![スクリーンショット 2020-05-04 14.45.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30363/94d35255-9f65-2600-a7d9-89dfde70044a.png)

![スクリーンショット 2020-05-04 14.45.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30363/fbffa11c-4c78-79de-3279-0f5e29f3762f.png)

管理UI/Users
![スクリーンショット 2020-05-04 14.45.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30363/61d1bb6f-6db5-8ebc-2ee0-ff5766563ba9.png)

![スクリーンショット 2020-05-04 14.45.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30363/082efb19-80b3-90ab-bfb2-89a0c8b39931.png)

前ページ https://qiita.com/bontensuzuki/items/7cd598a7075f6c970f14
次ページ https://qiita.com/bontensuzuki/items/9982196b4f7956ba0fd9
Flask-SQLAlchemyでUPSERTを実装する方法

# Flask-SQLAlchemyでUPSERTを実装する方法

## はじめに

サンプルアプリ(feedback-api)を用いてご紹介します。

`Mac環境の記事ですが、Windows環境も同じ手順になります。環境依存の部分は読み替えてお試しください。`

### 目的

この記事を最後まで読むと、次のことができるようになります。

| No.  | 概要       | キーワード            |
| :--- | :--------- | :-------------------- |
| 1    | UPSERT実装 | on_conflict_do_update |

### 実行環境

| 環境             | Ver.    |
| :--------------- | :------ |
| macOS Catalina   | 10.15.3 |
| Python           | 3.7.3   |
| Flask-SQLAlchemy | 2.4.1   |

### ソースコード

実際に実装内容やソースコードを追いながら読むとより理解が深まるかと思います。是非ご活用ください。

[GitHub](https://github.com/nsuhara/python-docker-flask.git)

### 関連する記事

- [SQLAlchemy](https://docs.sqlalchemy.org/en/13/dialects/postgresql.html#insert-on-conflict-upsert)

## UPSERTの実装

### UPSERTステートメントの作成

モデルにUPSERTステートメントを記述する

```app/feedback/models/t_feedback.py
class Feedback(db.Model):
    __tablename__ = 't_feedback'

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    service = db.Column(db.String(255), nullable=False)
    title = db.Column(db.String(255), nullable=False)
    detail = db.Column(db.String(255), nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    updated_at = db.Column(db.DateTime, default=created_at.default)

    """省略
    """


def upsert_stmt():
    """upsert_stmt
    """
    stmt = insert(Feedback)
    return stmt.on_conflict_do_update(
        index_elements=['id'],
        set_={
            'service': stmt.excluded.service,
            'title': stmt.excluded.title,
            'detail': stmt.excluded.detail,
            'updated_at': stmt.excluded.updated_at
        })
```

### UPSERTステートメントのコール

コミット処理でUPSERTステートメントをコールする

```app/feedback/views/api.py
"""
clause – An executable statement (i.e. an Executable expression such as select()) or string SQL statement to be executed.
params – Optional dictionary, or list of dictionaries, containing bound parameter values. If a single dictionary, single-row execution occurs; if a list of dictionaries, an “executemany” will be invoked. The keys in each dictionary must correspond to parameter names present in the statement.

e.g.) params
[
    {
        'id': 1,
        'service': 'service1',
        'title': 'title1',
        'detail': 'add as new record1'
    },
    {
        'id': 2,
        'service': 'service2',
        'title': 'title2',
        'detail': 'add as new record2'
    },
    ...
]
"""

def _upsert(payloads):
    db.session.execute(clause=upsert_stmt(), params=payloads)
    db.session.commit()
```
Railsで過去履歴のmigrationを修正して再実行する

# 環境
- Vagrant + Ubuntu 16.04.5 LTS
- Rails 5.2.4.2

# はじめに
Railsの開発を進めていくと、開発途中で、テーブルの項目に変更が発生する事がよく出て来ます。チームで開発する場合は、新規にマイグレーションファイルを作成して、個別に、カラムの修正や追加などを行うと思うのですが、個人で開発をしている場合は、いちいちそんな面倒な事はせずに、**create_table**を直接修正する方が手っ取り早いという事になります。

そこで、マイグレーションファイルの履歴を遡って、特定のバージョンのみ、マイグレーションファイルを修正して再実行する方法についてまとめてみました。

# 手順
現状のマイグレーションの履歴を表示して、再実行したいマイグレーションファイルのバージョンを確認する

```
$ rails db:migrate:status
```

特定のマイグレーションをdownさせる

```
$ rails db:migrate:down VERSION=20200504051127
```

エラーが出てdownできなかった場合は、中身を一時的にコメントアウトして、空のメソッドの状態にすると、強制的にdownさせる事ができます

```
def change
end
```

down状態にしてから、マイグレーションを修正する

再び、マイグレーションをupさせます

```
$ rails db:migrate:up VERSION=20200504051127
```

再実行したマイグレーションファイルのバージョン以降に、修正したテーブルに対して、**add_reference**で、リンクを貼っている場合は、当然、クリアされているので、再実行が必要なマイグレーションを拾い上げて、個別に、再実行してやる必要がありますので、ご注意。

下記の例は、親テーブル（endusers）に子テーブル（tasks）を関連づけています。このマイグレーションファイルも一旦、downさせてから、upさせてやると、tasksテーブルに反映されます。

```xxxxxxxxx_add_enduser_id_to_tasks.rb
def up
    execute 'DELETE FROM tasks;'         # 子テーブルのデータをクリアしないとリンクは張れません
    add_reference :tasks, :enduser, null: false, index: true
end

def down
    remove_reference :tasks, :enduser, index: true
end
```

最後に、**schema.rb**の中身を見て、思い通りの内容に作成されていればOK
Keystonejs Tutorials #8/Custom Field2

前ページ https://qiita.com/bontensuzuki/items/8f91e3f0128b6be1ecbb

Keystonejsのtutorialsから学んでいきます。（ほとんど機械翻訳です）
https://www.keystonejs.com/tutorials/custom-fields

###実装

ここにあるソースを説明しています
https://github.com/keystonejs/keystone/tree/master/demo-projects/custom-fields/


まず、Implementation.jsを見てみましょう。

```javascript

const { Integer } = require('@keystonejs/fields');

class Stars extends Integer.implementation {
  extendAdminMeta(meta) {
    return { ...meta, starCount: this.config.starCount || 5 };
  }
}

module.exports = {
  Stars,
  MongoIntegerInterface: Integer.adapters.mongoose,
  KnexIntegerInterface: Integer.adapters.knex,
};
```
アダプターインターフェイスと共にフィールド実装クラスをエクスポートするための既存のフィールドタイプとの規則。

アダプターは、フィールドとデータベース間のインターフェースを提供します。ここでは、クエリとミューテーションをSQLまたはMongoDBアクションに変換する方法を定義します。繰り返しますが、Startsの実装はIntegerフィールドタイプと同じになるため、Integerフィールドタイプのアダプタを再エクスポートするだけで済みます。

データの保存方法については何も変更しないので、ここでは、Integerフィールドのアダプターを再エクスポートします。

実装クラスは、Keystoneバックエンドで使用されます。それは多くのものを定義します。まず、タイプ、クエリ、リゾルバを含むGraphQLインターフェース。次に、フィールドが順序付け可能かどうかなどのフィールドプロパティ。最後に、Keystoneが管理UIに渡す必要のあるデータ。

Starsフィールドの場合、Integerの実装から変更したいのは、星の数の構成オプションを追加することだけです。このため、Integer実装クラスを拡張し、メソッドextendAdminMetaをオーバーライドできます。


###ビュー(Views)
これでバックエンドインターフェイスが用意できたので、UIコンポーネントを見てみましょう。

これは通常、コントローラーから始まります。コントローラーは、フィルタリング、デフォルト値、データのシリアル化、ラベルリゾルバー、一部のGraphQlオプションなど、フロントエンド機能の動作を定義します。この例のフィルタリングでは、デフォルト値とコントローラーのアスペクトはすべてIntegerフィールドと同じになります。もう一度、Integerコントローラーを参照するだけにします。

>
注：Integer.views.Controllerもnode_modulesフォルダー内のパスに解決され、ビルド時にKeystoneによってバンドルされます。

残りのビューは、管理UIでレンダリングされるReactコンポーネントに関連しています。まず、カウントと値の小道具に応じて、塗りつぶされたまたは輪郭が描かれた星の数をレンダリングする一般的な<Stars>コンポーネントを作成します。したがって、5つの評価のうち3つ星は次のようになります。

```jsx
<Stars count={5} value={3}>
```

このコンポーネントの例は、custom-fieldsデモプロジェクトにあります。

星評価用のコンポーネントを作成したら、これをKeystoneで使用できます。


###Cell
セルコンポーネントは、Keystone管理UIのアイテムのリストを示すテーブルにレンダリングされます。作成したstarコンポーネントを使用します。セルコンポーネントは、整数値になるデータと、Implementation.jsファイルに追加したstarCountフィールド構成オプションを使用します。セルを操作して、コンポーネントにonChangeプロップを提供しないようにすることができます。


```jsx
import { jsx } from '@emotion/core';
import Stars from './Stars';

export default function StarsCell({ field, data }) {
  const { starCount } = field.config;
  return <Stars count={starCount} value={data} />;
}
```


###Field
フィールドコンポーネントは、Keystoneでリストアイテムを作成または編集するときに使用されるメインインターフェイスを提供します。一貫性のある外観を得るために、@ arch-ui / fieldsからラッピングコンポーネントをインポートします。これはKeystoneのUIライブラリです。これにより、ラベルがレンダリングされ、一定の間隔が確保されます。これ以外は、ユーザーが星をクリックするときに値を更新できるように、onChangeイベントを星に委任するだけです。

```jsx

import { jsx } from '@emotion/core';
import { FieldContainer, FieldLabel, FieldInput } from '@arch-ui/fields';
import Stars from './Stars';

const StarsField = ({ field, value, errors, onChange }) => (
  <FieldContainer>
    <FieldLabel htmlFor={`ks-input-${field.path}`} field={field} errors={errors} />
    <FieldInput>
      <Stars count={field.config.starCount} value={value} onChange={onChange} />
    </FieldInput>
  </FieldContainer>
);
export default StarsField;
```
これで、基本的なカスタムフィールドが作成されました。

前ページ https://qiita.com/bontensuzuki/items/8f91e3f0128b6be1ecbb
scikit-learnを使用した機械学習でよく使う手法覚書き（初学者用）

#はじめに
機械学習をする時によく使う手法をまとめました。随時、加筆修正していきます。



#前処理
###標準化
```python:StandardScaler
from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()  #インスタンス作成
scaler.fit(pd_sample)      #パラメータの計算（平均、標準偏差など）
pd_sample_sc = scaler.transform(pd_sample)  #データ変換

#pd_sample_sc = scaler.fit_transform(pd_sample)でまとめて実行できる
```

###ダミー変数化
```python:get_dummies
#pandas.get_dummies()関数
pd_sample = pd.get_dummies(pd_sample)
```

###学習データ/評価データ分割
```python:train_test_split
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y)
```


#教師なし学習
###クラスタリング
```python:KMeans
from skleran.cluster import KMeans

kmeans = KMeans(n_clusters=4, random_state=0)  #K-meansモデル定義
clusters = kmeans.fit(pd_sample)               #クラスタリング実行
pd_sample['cluster'] = clusters.labels_        #クラスタリング結果の取得
```

###次元削減
```python:PCA
from sklearn.decomposition import PCA

pca = PCA(n_components=2)         #PCAモデル定義
pca.fit(pd_sample)                #主成分分析
x_pca = pca.transform(pd_sample)  #データ変換（戻り値はarray型オブジェクト）
x_pca = pd.DataFrame(x_pca)       #DataFrame型に格納し直す

#x_pca = pca.fit_transform(pd_sample)でまとめて実行できる
```



#教師あり学習
###回帰モデル
```python:LinearRegression
from sklearn.linear_model import LinearRegression()

model = LinearRegreession()  #モデル初期化
model.fit(X_train, y_train)  #モデル作成

#学習用データ、評価用データの精度検証
print(model.score(X_train, y_train))
print(model.score(X_test, y_test))

#説明変数ごとに寄与度を表す係数を出力
coef = pd.DataFrame({"feature_names":X.columns, "coefficient":model.coef_})
print(coef)

#未知のデータに対して回帰値を予測
print(model.predict(x_pred))
```

###分類モデル
```python:DecisionTreeClassifier
from sklearn.tree import DecisionTreeClassifier

model = DecisionTreeClassifier(random_state=0)  #モデル初期化
model.fit(X_train, y_train)                     #モデル作成

#学習用データ、評価用データの精度検証
print(model.score(X_train, y_train))
print(model.score(X_test, y_test))

#説明変数ごとに寄与度を表す係数を出力
importance = pd.DataFrame({"feature_names":X.columns, "coefficient":model.feature_importances_})
print(importance)

#未知のデータに対して分類値を予測
print(model.predict(x_pred))

#0/1の予測確率を出力
print(model.predict_proba(x_pred))
```

###分類モデルの検証
```python
#正解率 = (TP+TN)/(TP+FN+FP+TN)
model.score(X_test, y_test)

#混合行列
from skleran.metrics import confusion_matrix
matrix = confusion_matrix(X_test, y_test)

#混合行列のヒートマップ
import seaborn as sns
sns.heatmap(matrix, annot=True, cmap='Blues')
plt.xlabel('Prediction')
plt.ylabel('Target')
plt.show()

#適応率 = TP/(TP+FP)
from sklearn.metrics import precision_score
precision_score(X_test, y_test)

#再現率 = TP/(TP+FN)
from sklearn.metrics import recall_score
recall_score(X_test, y_test)

#F値　 = 2*(Precision*Recall)/(Precision+Recall)
from sklearn.metrics import f1_score
f1_score(X_test, y_test)
```
Laravelでセッションを使う

# 目次
Laravelの記事一覧は下記
[PHPフレームワークLaravelの使い方](https://qiita.com/toontoon/items/c4d0371e504c37f6576e)

# Laravelバージョン
動作確認はLaravel Framework 7.19.1で行っています

# 前提条件
[eclipseでLaravel開発環境を構築する。デバッグでブレークポイントをつけて止める。(WindowsもVagrantもdockerも)](https://qiita.com/toontoon/items/76fa7f8845b20776077c)
本記事は上記が完了している前提で書かれています
プロジェクトの作成もapacheの設定も上記で行っています

# Controllerにメソッド追加
(1) /sample/app/Http/Controllers/SampleController.phpにsession1メソッド、session2メソッドを追記

```
    public function session1(Request $request)
    {
        $request->getSession()->put("key1", "value1");
        $request->getSession()->put("key2", "value2");
        return view('sample.session1');
    }

    public function session2(Request $request)
    {
        $data = [
            'key1' => $request->getSession()->get("key1")
        ];
        return view('sample.session2', $data);
    }
```

(2) /sample/routes/web.phpに下記を追記
`Route::get('sample/session1', 'SampleController@session1');
Route::get('sample/session2', 'SampleController@session2');`


# viewの作成
(1) /sample/resources/views/sample/session1.blade.phpファイル作成

```session1.blade.php
<html>
    <head>
        <title>sample</title>
    </head>
    <body>
        <form action="{{ url('sample/session2') }}" method="get">
            <input type="submit" >
        </form>

    </body>
</html>
```

(2) /sample/resources/views/sample/session2.blade.phpファイル作成

```session2.blade.php
<html>
    <head>
        <title>sample</title>
    </head>
    <body>
        <div>{{$key1}}</div>
        <div>{{ session('key2') }}</div>
    </body>
</html>
```

`$request->getSession()->get`
`session`
どちらでもセッションに格納した値を取れます
ただし、`session`関数は配列を引数として与えられた場合、取得ではなく、セッションへの値の保存になってしまうので気を付けましょう

# 動作確認
`http://localhost/laravelSample/sample/session1`

送信ボタンクリック

実行結果

```
value1
value2
```

http://localhost/laravelSample/sample/session1
でsessionにputした値が
http://localhost/laravelSample/sample/session2
で表示されました
node.jsでgoogleapisを使い、gmailでメール送信

# 事前準備

https://developers.google.com/gmail/api/quickstart/nodejs
とりあえずこの通りにして、ラベルが表示されるまでやってみる

# スコープの変更

サンプルコードだとreadonlyだけなので、メール送信出来るように[スコープを変える][1]

```js
const SCOPES = ['https://www.googleapis.com/auth/gmail.readonly'];
```
を下のように変更

```js
const SCOPES = ['https://www.googleapis.com/auth/gmail.send'];
```

既に出来上がっている`token.json`はスコープが最初のままなので、このファイルを消す

# メールの作成

メールは素のテキストで書くか、何らかのライブラリを使って組み立てるかして、最終的にはテキストにして、さらにBase64でエンコードしたものを使う必要がある
[参考1][1]
[参考2][5]

探した所、nodemailerのmail-composerが良さそうだった

```js
import mailComposer from "nodemailer/lib/mail-composer"

const createMail = async (subject, to, text) => {
  const mail = await new mailComposer({
    to,
    text,
    subject,
    textEncoding: "base64",
  })
    .compile()
    .build()
  
  const raw = Buffer.from(mail)
    .toString("base64")
    .replace(/\+/g, "-")
    .replace(/\//g, "_")
    .replace(/=+$/, "")  

  return raw
}
```

# メールの送信

サンプルコードの`listLabels`の要領で、`gmail`を作っておく

[参考1][3]
[参考2][4] これを見る限り、`raw`は`requestBody`の中に入れるっぽいし、typescriptの定義を見てもそうらしい（巷のサンプルコードは`resource`だったりする）
(今回インストールのバージョンは`npm install googleapis@39 --save`)

```js
const sendMail = async (subject, to, text) => {
  const raw = await createMail(subject, to, text)
  await gmail.users.messages.send({
    userId: "me",
    requestBody: {
      raw,
    },
  })
}
```

# 自分のメールアドレスを動的に取る

fromアドレスをハードコードしたくない場合

```js
const FROM_ADDRESS_PATH = "from.json"

gmail.users
  .getProfile({ userId: "me" })
  .then(({ data: { emailAddress } }) => {
    fs.writeFile(
      FROM_ADDRESS_PATH,
      JSON.stringify({ from: emailAddress }),
      (err) => {
        if (err) return console.error(err)
        console.log("from address stored:", FROM_ADDRESS_PATH)
      }
    )
  })
```

こんな感じで自分のプロファイルを呼んで、ファイルに落とし込んでおいたりしてメール作成時にFROMの設定をこの書き出したファイルからやるとか、出来る


[1]: https://developers.google.com/gmail/api/auth/scopes
[2]: https://developers.google.com/gmail/api/guides/sending
[3]: https://developers.google.com/gmail/api/v1/reference/users/messages/send
[4]: https://googleapis.dev/nodejs/googleapis/latest/gmail/interfaces/Params$Resource$Users$Drafts$Send.html

[5]: https://medium.com/@parakh.js/how-to-use-gmail-api-with-node-js-part-2-72f3e9b6b060
ブラウザだけでMQTT  Pub/Sub からのリアルタイムストリーミングのチャート作成

# はじめに

仕事柄、今後は IoT センサが出すデータをリアルタイムに可視化するようなのをやっていかないとなぁ、と考えていて、実装のイメージを掴むため・関係者と合わせるために、こんな `PoC` 作ってみたという話です。ブラウザだけでもやればできる

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32540/f219852b-3acd-2ca2-b934-a36e0f6e1ab8.gif" width=70%>

# 今回の PoC の構成

* `MQTT.js` で `Mosquitto™` のテストサーバへ Pub / Sub
* `Vue.js` と `Chart.js` でストリーミングを可視化

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32540/6518cc21-7a63-099c-56d8-8a0c30d16e6f.png)


1. 巨人の肩の上に乗りまくり[^1]の構成
2. MQTTは自分で pubって、自分で subる 自作自演型（いちおう、インスタンスは分けたが）
3. Mosquitto™ のテストサーバーさまさま。多謝。

[^1]: 「巨人の肩の上にのる矮人」（きょじんのかたのうえにのるわいじん、ラテン語: nani gigantum umeris insidentes）という言葉は、西洋のメタファーであり、現代の解釈では、先人の積み重ねた発見に基づいて何かを発見することを指す

# ライブデモ

Github Pages に置いてます

| デモ                                                    | 内容                                                         | ソースコード                                                 |
| ------------------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| [Version 1](https://narutaro.github.io/mqtt-dashboard/) | MQTT Subscriber がデータを受け取るのをトリガにチャートをリフレッシュ | [GitHub](https://github.com/narutaro/mqtt-dashboard/blob/master/index.html) |
| [Version 2](https://narutaro.github.io/mqtt-dashboard/realtime.html)                                           | MQTT Subscriber と Chart.js がそれぞれのタイマーでデータを待ち受け。その間を Queue でつないでいる。チャートの見栄えはいいが、タイマーが複数回っていておそらくCPU的にはよくないと思われる | [GitHub](https://github.com/narutaro/mqtt-dashboard/blob/master/realtime.html) |

# やったこと

このあたりに書いたことを組み合わせて、できあがり

* [MQTT.js でブラウザから MQTTブローカ に Pub/Sub する](https://qiita.com/narutaro/items/2819ce79eb82a87357eb)
* [Chart.js でリアルタイムストリーミングデータをグラフ化](https://qiita.com/narutaro/items/320b35a712bb3f058a75)

<!--
# TODO
* 二つもループを回さなくてもいいのではないか。MQTTからChart.jsに `push` するべきでは？
* https://teratail.com/questions/216345
* https://www.youtube.com/watch?v=De-zusP8QVM
* -->
スタートアップでデータ分析（あるいは集計）をするということ

## はじめに
こんにちは。@pp_ykykです。
現在スタートアップにて、データ分析兼エンジニアをやっております。
創業間もないスタートアップで、データ分析（あるいは集計）を頼まれたときに気をつけていることをまとめました。

### 想定している読者
- データ分析をやろう（もしくはやって）と言われたが、社内にそれっぽいことをやってる人もチームもいない人
- エンジニア・マーケターだが、そろそろなにがしかのデータをみたいと思い始めた人

### ターゲットじゃない読者
- データ分析の実践例・機械学習のプラクティスを知りたい人
- 整えられたデータが会社・チームにもうあるのでどうやって使えばいいのか探してる人
- 分析基盤のDevOpsを学びたい人

## これをやっとけ
大事なことは2つです。**「データに責任を持つこと」**と**「出したデータを価値につなげること」**


### 「データに責任を持つこと」
-  **属人的でいいからデータの性質に詳しくなれ**

再現性はもちろん大事だけど、自分一人でデータの取り込み、整頓、集計、（可視化）できる。どんなデータが存在してるのか語れる。

- **定義とゴールを明確にしろ**

何のために、どんなデータをいつまでに出すのか？社内で完結する分、曖昧になりがちです。また、依頼者も雰囲気で頼むということはよくあります。

### 「出したデータを価値につなげること」
- **とにかく早く形にして、他の人のフィードバックを受けろ**

「データによって何らかの結果が出る」までには時間がかかります。結局何ができるの？と言われる前に最速でアウトプット出すのが大事。（完成度はおいおい上げていきましょう・・・）

- **セキュリティとかOpsとか不安になってきたら巻き込め**

一人だけでやってると落としがちになります。社内データ基盤作成という一大プロジェクトにしたいのであれば、他の人を巻き込みましょう。

### 1. 属人的でいいからデータの性質に詳しくなれ
スタートアップでは、プロダクトの成長スピードに重きを置かれている場合が多いと思います。
データベースの構造や、スキーマ定義、ビジネスロジックなどもドキュメント化をすっ飛ばしてリリースされることもあるでしょう。
先週までこんなテーブルなかったよね？とか日常茶飯事です。

- **このテーブル・カラムって今も使われてるの？**
    - もちろん全てを把握するのは難しいですが、主要なデータについては語れることが大事
- **データの特性、StateをあらわすのかLogをあわらすのか**
    - この辺は別記事で解説します！

この2点は必ず押さえておきましょう。

### 2. 定義とゴールを明確にしろ
データ集計を依頼された、もしくはやってみたいという際に陥りがちなのが、「アウトプットイメージの要件決め」を行なっておらずになんとなく終わってしまうことです。依頼者もあやふやなニュアンスでオーダーを出してしまうことがよくあります。

「ユーザのログイン率を出してくれ」と言われたとしても、複数端末でログインしてたら、セッションは存在したが3秒でアプリを落としたら・・・など無数に考えることがあります。

- 依頼内容の整理、それを表現するためにどのようなデータが必要かを洗い出す
    - そもそも依頼者と認識にギャップがあるというパターンは意外とあります。
    - データの抽出結果は、今回だけでいいのか。毎月見るのか。頻度も大事。
- データの不足がおきた時に、プロダクトの開発者と協力する
    - スタートアップでは、データがそもそも存在しないというパターンが大いにあります。

**依頼に応じて最適だと思われる定義を策定し、それに応じたデータを抽出する**ことが大事です。

### 3. とにかく早く形にして、他の人のフィードバックを受けろ
2とも近い話ですが、自分も依頼者もまだ未熟な場合、出したアウトプットがイメージと違ったということは存在します。
また、「データ分析」自体の価値がまだ会社・チームに浸透していない場合もあるかもしれません。

こんなことができるよ。こんな示唆がうまれるよ。に関してはいち早く他の人に共有して、ビジネスとしてどう役立てるか、デザイナー・エンジニアにとって価値が提供できたかを常に意識することが必要です。

**未熟であればあるほど、早くアウトプットをだして、ギャップをうめるリードタイムを短くすること**が大事です！

### 4. セキュリティとかOpsとか不安になってきたら巻き込め
データ分析もある程度サイクルが回ってきたら、「このデータって社内に公開されてていいんだっけ？」「毎週同じようなオーダーがくるな」といったフェーズに達してきます。
とにかく早く出すことが大事と上でいいましたが、セキュリティリスク・技術的負債を抱えたままスケールすることはできません。

SREや情シス部門、プロダクトの開発者をうまく巻き込んで、会社としてのプロジェクトにすることが大事です！

## まとめ
自分自身、データウェアハウス・社内BI環境の構築、データ集計・分析、プロダクト開発など様々な仕事に携わってきましたが、「データを集計すること」だけで価値を生み出せることは稀です。
ただの「データ集計する人」ではなく、「定量的なデータを元に、ビジネス・プロダクトに価値を提供できる、新しい視点を与えることができる」ことを目指して頑張っていきましょう！！
java Eclips　javaScriptのデバック方法について

java Eclipsのデバック方法について

Step Filtering

デバックからクラスを選択して、右クリックから
ステップフィルターの選択をしてから、ステップふぃるたー
にチェックをいれると、チェックが入ったクラスはデバックしても
中に入らない

参考資料
https://www.slideshare.net/kompiro/eclipse30tips

JavaSCRIPTのデバック
https://www.sejuku.net/blog/68574
辞書のValue値が最も高いkeyの値を出力する

##概要
辞書のValue値が最も高いkeyの値を出力する方法について考えてみた。

辞書の値
s = {"C":10, "A":8, "B":10, "D":7, "E":5, "F":4, "G":6}

###ケース1：value値が同じ場合は、アルファベット順が小さいkeyを出力する。
1.sortedでvalue値を昇順(Default)並び変える
  sortedは辞書型に使えないので、list(s.items())としています。
2.maxでvalueが最も大きいタプルを抜き出す。

```python
s = {"C":10, "A":8, "B":10, "D":7, "E":5, "F":4, "G":6}
sorted_s = sorted(list(s.items()), key= lambda x:x[1])
print(sorted_s)
[('F', 4), ('E', 5), ('G', 6), ('D', 7), ('A', 8), ('B', 10), ('C', 10)]
max_value_key = max(sorted_s,key=lambda x:x[1])
print(max_value_key[0])
B
```

###ケース2：value値が同じ場合は、アルファベット順が大きいkeyを出力する。

1.sortedでvalue値を降順(reverse=True)で並び変える
  sortedは辞書型に使えないので、list(s.items())としています。
2.maxでvalueが最も大きいタプルを抜き出す。

><b>Tips!</b> 
max(iterable, *[, key, default])
位置引数が1つだけ与えられた場合、それはは空でない iterable でなくてはいけません。その iterable の最大の要素が返されます。2 つ以上のキーワード無しの位置引数が与えられた場合、その位置引数の中で最大のものが返されます。
最大の要素が複数あるとき、この関数はそのうち最初に現れたものを返します。

ということはsortedするときのkeyにkey値も対象として、reverse=Trueにすれば出力できそう。※注意keyに複数指定した場合、keyごとに昇順/降順を指定することはできない。

```python

s = {"C":10, "A":8, "B":10, "D":7, "E":5, "F":4, "G":6}
sorted_s = sorted(list(s.items()), key= lambda x:(x[1], x[0]) reverse=True)
print(sorted_s)
[('C', 10), ('B', 10), ('A', 8), ('D', 7), ('G', 6), ('E', 5), ('F', 4)]
max_value_key = max(sorted_s,key=lambda x:x[1])
print(max_value_key[0])
C
```

###ケース3：value値が同じ場合は、同じkeyをすべて出力する。

1.maxでvalueの最大値を抽出
2.辞書をリストに変換しvalueとなる値が1.と同じkey値を抽出

リスト内包でスッキリ

```python

s = {"C":10, "A":8, "B":10, "D":7, "E":5, "F":4, "G":6}
max_value_key = [ i[0] for i in list(s.items()) if i[1] == max(s.values())]
print(" ".join(max_value_key))
C B
```
###ケース4：1つ目のvalue値が同じ場合は、2つめのvalue値が小さいkeyを出力する。
複数のkeyを対象にソートを行う。
reverse=Trueとした場合、複数のkeyすべてに対して降順で並び替えが行われるので、
指定したkeyごとに昇順/降順でのソートが必要。

1.sortedの時に複数keyを指定する。この際、reverseではなくkeyごとに降順/昇順を行うよう指定する。
2.maxで1つ目のvalueが最も大きいタプルを抜き出す。

辞書
s = {"C":(10,4), "A":(8,2), "B":(10,8), "D":(7,9), "E":(5,8), "F":(4,7), "G":(6,2)}

```python
s = {"C":(10,4), "A":(8,2), "B":(10,8), "D":(7,9), "E":(5,8), "F":(4,7), "G":(6,2)}
sorted_s = sorted(list(s.items()),key=lambda x:(-x[1][0],x[1][1]))
print(sorted_s)
[('C', (10, 4)), ('B', (10, 8)), ('A', (8, 2)), ('D', (7, 9)), ('G', (6, 2)), ('E', (5, 8)), ('F', (4, 7))]
max_value_key = max(sorted_s,key=lambda x:x[1][0])
print(max_value_key[0])
C
```
keyを複数指定する場合はタプルで指定する。比較優先はタプルの前のほうから。
keyの比較対象に"-"を入れると、そのkeyに対してのみ降順に並び替えが行われる。
reverseと併用した場合はreverseが優先される。

```python
#reverse=Trueの場合
sorted_s = sorted(list(s.items()),key=lambda x:(x[1][0],x[1][1]),reverse=True)
print(sorted_s)
[('B', (10, 8)), ('C', (10, 4)), ('A', (8, 2)), ('D', (7, 9)), ('G', (6, 2)), ('E', (5, 8)), ('F', (4, 7))]

#key比較値の1つ目のvalue値に"-"をつけた場合
sorted_s = sorted(list(s.items()),key=lambda x:(-x[1][0],x[1][1]))
print(sorted_s)
[('C', (10, 4)), ('B', (10, 8)), ('A', (8, 2)), ('D', (7, 9)), ('G', (6, 2)), ('E', (5, 8)), ('F', (4, 7))]
```
##まとめ
駆け出しパイソニスタのためモジュール知識がなく。。。sortedやmaxの組み合わせにより抽出をしてみましたが、便利な関数等があれば是非教えていただきたいです。

##参考リンク
[python Document](https://docs.python.org/ja/3/library/functions.html#max)
[pythonのソートで複数キーを指定するとき](https://qiita.com/Arvelt/items/01affefb156f443c62f7)
Django2 Form(フォーム)のBound/Unboundと初期値の関係

# 前提
Djangoの基本的な機能を一通り使ったことがある程度の初心者向けです。

# 環境
- Windows 10
- Python 3.7.x
- Django 2.2.x

# はじめに
フォームを使う上でハマりがちだと感じる初期値設定の説明です。なお、説明では Form / ModelForm の違いを明確に区別しない場合があります。

## フォームを使うイメージ
まずは、フォームの大雑把なイメージを図示します。
![フォームイメージ1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542213/7547b4a3-8d27-1759-e1d7-de69ab80f406.png)

## フォームの入力
次に、フォームの主要な入力項目（\_\_init\_\_()メソッドの引数の項目）まで表します。
![フォームイメージ2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542213/df53da06-4bb1-ce67-6ab9-c3a3aecf4ec0.png)

各入力項目が何に対応するかを以下に示します。
<dl><dt>data</dt><dd>request.GET, request.POST</dd>
<dt>files</dt><dd>request.FILES</dd>
<dt>instance</dt><dd>モデルインスタンス/dd>
<dt>initial</dt><dd>初期値を設定した辞書</dd></dl>

## Bound / Unbound とは
公式ドキュメントに「Bound/Unboundの区別が重要」との記述がありますが、その通りここを押さえておかないとフォームの挙動が理解しにくいです。Bound/Unboundの定義は以下の通りです。

<dl><dt>Boundフォーム</dt><dd>request.GET、request.POST、request.FILESのいずれかを設定したフォーム</dd>
<dt>Unboundフォーム</dt><dd>request.GET、request.POST、request.FILESのいずれも設定していないフォーム</dd></dl>

これは、BaseFormクラスのソースコードからもわかります。

```python
# BaseForm クラスのコードの一部
self.is_bound = data is not None or files is not None
```

実施に、どのような引数でフォームをインスタンス化するとBound（またはUnbound）になるのか、いくつか例を示します。

```python
# Bound/Unbound フォームの例
form_bound_1 = SomeForm(request.GET)
form_bound_2 = SomeForm(request.POST)
form_bound_3 = SomeForm(request.POST, request.FILES)

form_unbound_1 = SomeForm()
form_unbound_2 = SomeForm(initial={"some_field": "some_valule"})
form_unbound_3 = SomeModelForm(initial={"some_field": "some_valule"}, instance=some_instance)

form_bound_4 = SomeModelForm(request.POST, initial={"some_field": "some_valule"}, instance=some_instance)
```

## Bound / Unboundと初期値の関係
これまで見てきた「フォームの主要な入力項目」と「Bound/Unbound」が、初期値の設定に関わります。フォームには１つまたは複数の入力項目、つまりフィールドが定義されていますが、その各フィールドがHtmlマークアップをレンダーするために値を取得するコードを見てみましょう。

```python

# BoundField クラスのメソッド
def value(self):
    """
    Return the value for this BoundField, using the initial value if
    the form is not bound or the data otherwise.
    """
    data = self.initial
    if self.form.is_bound:
        data = self.field.bound_data(self.data, data)
    return self.field.prepare_value(data)
```
上記から、<b>Boundフォームのフィールドの値はinitialが使われない（上書きされる）</b>ことがわかります。また、<b>request.GET 等が空（≠None）の場合でもBoundフォームになる</b>ことには注意が必要です。

## 対策
検索フォームを作ったり、Ajaxを使って１画面であれこれするような場合、以下のように分岐することで初期値設定を有効にできます。（コードはあくまで一例です。）

```python
if "some_field" in request.GET:
  form = SomeForm(request.GET)
else:
  form = SomeForm(initial={"some_field": "some_value"})
```
モデル作成・モデル更新をそれぞれ個別のビューで実行しているうちは問題は起こらないのですが、応用し始めるとハマることがあります。

## 値の優先順
そのほか、フォームフィールドの値は以下の優先順で設定されることにも注意が必要です。
(正確には、Bound/Unbound の差異など無視した「優先度のイメージ」のようなものです)

1. data (request.GET, request.POST)
2. initial
3. instance
4. フォームフィールド初期値  
⇒ フォームフィールドの定義において「some_field = forms.CharField(initial="init value")」 のように設定する値のこと

なお、ModelFormにおいて、Modelのdefault値がフォームフィールドのinitialにりそうに思えますがならないようです。

# おわりに
「Bound / Unbound」と「初期値設定」の部分は想像できそうで出来ない部分なので、少し理解を深めておくと良いです。
Edgerouter (ER-X) で IPoE + DS-lite で IPv6/IPv4 環境を構築する (ひかり電話なし)

何週間もかけて IPv6/IPv4 環境を構築し、フレッツ光ネクスト環境を増速の道へと進めているしょっさんです。

ひとまず、一般のご家庭でIPv4/IPv6を快適に利用するところまでの記録をここにまとめておきます。追加で、更に課題が発生したときの解決策も提示していく予定です。

# 前提条件

IPoEとして利用できる条件が整っていることが条件です。

- フレッツ光クロス、フレッツ光ネクスト、またはフレッツ光ライトなど NTT東日本・西日本のNGN回線引き込み済み
- 「フレッツ・v6オプション」契約済み
- DS-lite利用可能なIPoEプロバイダ(IIJ/Interlink/BB.Exceite/ぷららなど)に契約済み

なお、今すでに`PPPoE`を使っている状況の利用でも問題なく設定できます。安心して設定してください。また、WAN側(我が家ではeth0)にIPv4のアドレスを振っておく必要はありません。振っててもいいです。好きにしてください。

# この設定でできること

[INTERNET MULTIFEED](https://www.mfeed.ad.jp/)系のIPv6接続サービスプロバイダを利用して、IPv6/IPv4 いずれも接続できるようになること。イメージとしては、次の図です。

<img width="1107" alt="Screen Shot 2020-05-04 at 16.26.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37263/5ec5f93c-f72f-1c80-49a6-1915d538d275.png">

# 設定手順

## まずとにかく、IPv4だけでもいいから接続するには

1. 「[Edgerouter (ER-X) で DS-lite だけしてみる (ひかり電話なし)](https://qiita.com/sho7650/items/23d668d246166338c398)」

## NDプロキシを準備して、IPv6アクセスできるようにするには

1. 「[Edgerouter X(ER-X) 用に ndppd をカンタンにビルドする (ひかり電話なし)](https://qiita.com/sho7650/items/da9bc34f1640223aaf99)」
2. 「[Edgerouter (ER-X) で NDプロキシを使って IPv6通信を行う (ひかり電話なし)](https://qiita.com/sho7650/items/f0d90957e860456f4481)」

# もし接続が急に切れるようになったら...

一般のご家庭では想定できない端末数や、同時に起動するアプリケーションが多すぎると[INTERNET MULTIFEED](https://www.mfeed.ad.jp/)側で設定されている制限に引っかかる場合があります。

これは、ほとんどのプロバイダが NAT変換テーブル用のポート数制限(1024)となっているためです。

#### 制限の確認できているプロバイダ

プロバイダ | 制限ポート数 | 備考
|:----:|:----:|:----:|
[Interlink/ZOOT NATIVE](https://www.interlink.or.jp/service/zootnative/) | 1024 | [インターネットに接続している端末数が多い方](https://faq.interlink.or.jp/faq2/View/wcDisplayContent.aspx?id=654)
[IIJmio FiberAccess/NF](https://www.iijmio.jp/guide/outline/nbd/) | 1024(非公開) | サポートから確認済み
[IIJ FiberAccess/Fサービス タイプIPoE](https://www.iij.ad.jp/biz/faf6ipoe/) | 12800 | ホントに12800ポート開放しているか確認中

実際にこの制限に引っかかると、`transix`内の`AFTR`から`ICMP host unreachable`でバチッと一瞬で来られます。その結果ブラウザでは「ERR_CONNECTION_REFUSED」される感じです。

## 対処法

検討の経緯は「[せっかくのIPoE化もDS-liteの制限で台無しだったので、代替策を考えた](https://note.com/sho7650/n/n5a00e1a582bf)」をご覧いただくとして、いくつか今判明している解決策を載せておきます。AFTRの作り方などは、ゆくゆく情報を載せていきますので、完成次第リンクをはっつけていきます。

1. 安価なVPSをAFTRとして構築する (NW:100Mbps前後)
2. AWS上で効果なAFTRを構築する (NW: 数千円〜お金をつぎ込んだだけ)
3. [IIJ FiberAccess/Fサービス タイプIPoE](https://www.iij.ad.jp/biz/faf6ipoe/)にする (初期¥10k/月額¥14k)
4. データセンター内にAFTR配置してしまう(交渉次第)
ryuが上手くinstallできない

ryuのインストールを行っており、usr/local/bin には ryu と ryu-managerがあるのですが、ryu-managerを起動しようとすると以下のような表示が出て実行できません。この場合どのような操作をすることで正しく実行させることが出来るのか教えていただけないでしょうか？
cpu : ryzen7 2700x
OS : Windows10 home
VM OS : ubuntu16.04
VM : virual box
で起動しています。![キャプチャ_2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631565/3894ffa8-230d-ffa8-3eae-3af80b72b2b7.png)
Ruby on Rails scaffoldの使い方

Rubyのフレームワークには、コードを自動生成してくれる便利な機能が多く存在しますが、その内の一つであるscaffoldについて紹介します。

##scaffoldとは
コマンドを一つ実行するだけで、アプリケーションに必要なコントローラー、ビュー、モデルを自動的に作成してくれる。
使用するデータ型を指定し、自分の作りたいものの土台を作ることができる。
以下のようにコマンドを入力します。

```console
$ rails g scaffold モデル名
$ rails g scaffold モデル名　カラム名:データ型...
```

例えば、お問い合わせ機能を作成したい場合、モデル名をContactとし、カラム名をname,email,contentとします。

```console
$ rails g scaffold Contact name:string email:string content:text
```

実行したら、マイグレーションを実行します。

```console
$ rails db:migrate
```

これでお問い合わせ機能を作成できました。
【Ruby】for in・whileによるループ処理まとめ初心者・自分用


##for inについて

```
for a in 5..10
    puts "hello world #{a}"
end
```

これでhello world数字が6回表示されます。

###気を付けるポイント
・変数名はなんでも良い。
・0..1で二回繰り返す。
・5..6と0..1は同じ。
・0も1つと数える。
・endを必ずつける。
・ループ処理の中で表示するにはputs、pなどの出力するメソッドを使用する。



##whileについて
for a inに比べて柔軟な処理が可能らしい。


```
while　条件式
  繰り返し処理
  カウンタ変数を更新
end   
```

数字、変数を当てはめます。

```
a = 1   #変数の初めの値を定義
while a <= 5 #変数が5以上になったら終わり
puts "ハロー、paizaラーニング" 繰り返し処理するメソッド
a = a + 1 変数aの値を更新して再び繰り返す。
end
```

##例題

1から10までの偶数を1行ずつ表示する。


```
i = 2
while i <= 10
	puts i
	i = i + 2
end
```



##例題

1から10までの数字を2乗した値を表示する。


```
a = 1
while a <= 10
puts "#{a}" *2
a = a + 1
end
```

###気をつけるポイント
・変数の定義を間違えると無限に繰り返す。
・変数の定義を間違えないようにする。
・


##例題

20から10までの奇数を一行ずつカウントダウン表示する。

```
c = 19
while c >= 10
puts c 
 c -= 2 
end
```
Vue.js でフローチャートを描く(vue-mermaid)

### モチベーション
* ブラウザ上で樹形図を編集したい

### 要求
* Vue.js に組み込みたい
* ブラウザ上のボタン操作等で樹形図を編集したい
* 上記操作を反映して図を更新したい
* 樹形図要素に外部サイトへのリンクを貼りたい

### ライブラリ探し
フローチャート図を作成できるライブラリを探した.


* [flowchart-vue](https://github.com/joyceworks/flowchart-vue)
  * [demo](https://joyceworks.github.io/flowchart-vue/)
  * ドラッグアンドドロップ可

* [vue-simple-flowchart](https://github.com/Jeffreyrn/vue-simple-flowchart)
  * [demo](https://jeffreyrn.github.io/vue-simple-flowchart/demo/)
  * ドラッグアンドドロップ可

* [vue-mermaid](https://github.com/robin1liu/vue-mermaid)
  * demo無し

* [VuePress mermaid](https://vuepress-examples.netlify.app/demos/diagrams/)
  * demo無し
  * mdからの図生成

### 選定
* 下２つのベースとなっている「mermaid」について調べてみたところ、どうやら樹形図上にリンクを埋め込む機能があるらしい（[参考](https://mermaid-js.github.io/mermaid/#/flowchart?id=interaction)）ので、こちらを利用することとした。
* VuePressは静的ページ向けっぽいのでvue-mermaid を利用することにした。

### vue-mermaidを触ってみる
READMEの通りに作業すれば動く。
（今回はNuxt.jsでの動作確認だったのでplugins周りもいじった。）
触ってみたやつ：[bwsunkist/vue-mermaid-demo](https://github.com/bwsunkist/vue-mermaid-demo)
画面操作に応じて図を更新することができた。
また、ノードのクリックに応じてmethodを呼び出すことができた。（今回はalertを表示）
クリックイベントを有効にするにはconfig設定をする必要あり（[参考](https://github.com/robin1liu/vue-mermaid/issues/3#issuecomment-546283743)）

![Peek_2020-05-04_15-53.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373512/20ffbaef-8f6c-4d8b-368b-be08a12c7896.gif)

### その他
外部サイトへのリンクはmermaid本家にあって vue-mermaidには無い機能なようだったので、実装してプルリク済み。[リポジトリ](https://github.com/bwsunkist/vue-mermaid)
* url: "URL" をnodeに設定することで外部リンクへの遷移を実現している

後々調べてみたら外部サイトリンクはmethodの中からでも呼び出せるぽいので、これでよかったかも。調査不足だった。
参考：[Vue.jsで動的にリンク先やクエリの値を操作する](https://designsupply-web.com/knowledgeside/5762/)
さくらのレンタルサーバにてpythonで記述したCGIを動かす

# はじめに
さくらのレンタルサーバでスタンダードプランを利用しています。
Pythonで記述したシンプルな「Hello World」プログラムを作成して、
CGIとして動作させるまでを説明します。

# Pythonで記載したプログラム

```python:Hello.cgi
#!/usr/local/bin/python
print "Content-Type: text/html\n\n"
print "Hello World"
```
# ファイル作成に関する留意点
## ファイルの拡張子
「py」ではなく「cgi」にする必要があります(※1)。

※1：実は、拡張子をpyのままでcgiとして動作させる方法もあり、
　これにについては、後述の「.htaccessの要否」をご参照ください。

## 文字コードと改行記号
文字コードを「UTF-8」にして、
改行記号を「LF」にすると良いです。
他の組み合わせだとエラーになることがあるそうです。
## pythonへのコマンドパス
上記の「Hello.cgi」の１行目に記載されているpythonへのコマンドパス。
最新の情報は、さくらのサポートページ＞「レンタルサーバサービス仕様」＞「CGI・PHP・SSI について」のページで「プログラムのコマンドパス」という項目があるのでここで確認してください → [さくらのサポートページ](https://help.sakura.ad.jp/206206041/)

# レンタルサーバへのアップ
## アップ先
作成したファイル「Hello.cgi」のアップ先は、ドキュメントルート（/home/アカウント名/www/）以下であればどこでも良く、ドキュメントルート以下に新しく作成したフォルダでも良いです。
## 権限の設定
ファイルパーミッションは、 755、705、700(※2)のいずれかに設定する必要があります。

また、ドキュメントルート以下に作成されたフォルダ内にファイル「Hello.cgi」をアップした場合は、ファイル「Hello.cgi」があるフォルダに対しフォルダパーミッションとして755、705、700(※2)のいずれかに設定する必要があります。

※2：さくらのサポートページには、
「755または705のいずれかに設定」と記載されていますが
コメント欄でご指摘を頂いた通り「700」でも動作しました。
セキュリティ面を考えると「700」がより良いように思います。

## .htaccessの要否
「.htaccess」は不要です。

ただ、コメント欄でご指摘を頂いた通り、
このままですと拡張子「py」を「cgi」に直さないといけないので非効率です。
そこで、以下を記述した.htaccessを作成して
拡張子「py」のままでもcgiとして動作できるようにする
という方法もあります。

```:.htaccess 
AddType application/x-httpd-cgi .py
```

## 参考（さくらのサポートページ）
最新の情報は、
さくらのサポートページ＞「レンタルサーバサービス仕様」＞「CGI・PHP・SSI について」のページで「ファイル、ディレクトリの設定」という項目があるのでここで確認してください → [さくらのサポートページ](https://help.sakura.ad.jp/206206041/)

#動作確認
ブラウザで「hello.cgi」が配置されているURLを指定して
「Hello World」が表示されることを確認します。
URL指定例：
「hello.cgi」をドキュメントルートへ配置した場合は、
「https://(ドメイン名)/hello.cgi」となります。

#あとがき
ちょっとPythonでCGIを試してみようとしたときに、
簡単な事例があると便利だ！と思いましたので、
この投稿をしました。誰かのお役に立てれば幸いです。
コメントアウトの記述（HTML,CSS,JavaSprict,Ruby)

#はじめに
自分が学習している中で、言語ごとに
コメントアウトの方法が違うためまとめます。



##HTML
```index.html

<!-- ここに書く -->

<!-- 改行するなら
こんな感じで書きます。 -->

```
##CSS
```main.css

/* ここに書く */

/*
改行するなら
こんな感じで
書きます。
*/
```

##JavaScript
```main.js

//ここに書く

/*
改行するなら
こんな感じで
書きます。
*/
//CSSと同じですね。

```

##Ruby
```main.rb
#ここに書く

=begin

改行するなら
こんな感じで
書きます。

=end

#こっちでも
#大丈夫
```
アップロードされたファイルが正常な画像ファイルかどうかをチェックする（Node.js）

「呼び出し元からアップロードされた画像ファイルが正常な画像ファイルか」を、サーバーサイドで ある程度チェックしたくなりました。（Node.js）

他の方がすでに実現してるんだろうな、と思って探してみたものの意外に見つからず・・。しょうがないので実装してみた次第です。

# やりたいこと

私の場合、後続のビジネスロジックで 「呼び出し元から入力されたファイルが、**画像として開ける**」 ということを前提としていました。

その前提を満たすためには、ビジネスロジックの前に以下の入力値チェックが必要と考えました。

* 受け取ったファイルのマジックナンバーが正当かチェック。例えばjpegであれば、開始バイトは`ff d8`(16進数)であるはずです。
* 受け取ったファイルの中身が壊れていないかチェック。
* 受け取ったファイルの中身が、画像と全く異なるものでないかチェック（攻撃スクリプトを装っていないか）。

これ以上のチェックについては、別タイミングで実行するウイルスチェックに任せます。例えば、jpegのExifにスクリプトが仕込まれていないか（[参考ページ](http://blog.f-secure.jp/archives/50742508.html)）、といったことまではチェックしません。Exifのチェックをすることもできるのですが、中途半端ですし、そもそも目的から外れます。

なお、呼び出し元が指定するファイル名や拡張子、Content-Typeヘッダーの中身は信用できませんので、それらをチェックしても意味がありません。

また、HTTPリクエストサイズの上限チェックなど、他のチェック処理も当然ながら必要です。この記事では、そういったことは省略します。

# 実装

かなり広く使われている模様の[sharp](https://github.com/lovell/sharp)を使って、実装してみました。

```javascript:index.js
'use strict'

const sharp = require('sharp')

// ここでチェックしています。
const check_image_validity = file_path => sharp(file_path).toBuffer()

const image_file_names = ['valid.jpg', 
                          'invalid_magic_number.jpg', // [Error: Input file contains unsupported image format]
                          'jpeg_magic_number_but_corrupted.jpg'] //[Error: Input file has corrupt header: VipsJpeg: Corrupt JPEG data: 597 extraneous bytes before marker 0xd4 VipsJpeg: JPEG datastream contains no image]

image_file_names.forEach(file_name => {
  check_image_validity('input_images/' + file_name)
    .then(() => console.log('it is a valid image! file name:', file_name))
    .catch(err => console.log('invalid image detected. file name:', file_name, ' error:', err))
})
```

sharpでファイルを読み込み、sharpの`toBuffer()`でメモリに書き出しています。この時、エラーが起こるのであれば、入力した画像ファイルが不正ということです。

コメントの通り、valid.jpg以外のファイルでは、エラーが発生します。不正な画像ファイルを良い感じに検知できているというわけです。

* valid.jpg ： 正当なJPEGファイル
* invalid_magic_number.jpg : マジックナンバー（冒頭のバイト列）が不正なファイル
* jpeg_magic_number_but_corrupted.jpg : マジックナンバーはJPEGのものだが、中身が不正なファイル。


# ソースコード

https://github.com/nyandora/invalid-image-detection
dockerを使ったlaravelで'npm run watch'コマンドが使えない時の解決例

# どんな状況
`npm run watch`を使って自動的にscssをコンパイルさせようと思ってコマンドを打ったところ下記のようなエラーが出ました

```
 % npm run watch
npm ERR! code ENOENT
npm ERR! syscall open
npm ERR! path /Users/user/projects/construction_management_system/package.json
npm ERR! errno -2
npm ERR! enoent ENOENT: no such file or directory, open '/Users/user/projects/construction_management_system/package.json'
npm ERR! enoent This is related to npm not being able to find a file.
npm ERR! enoent 

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/user/.npm/_logs/2020-05-04T07_12_15_852Z-debug.log

```

# 原因
コマンドを打つディレクトリを間違っていました。（筆者はエラーの三行目を見て気がつきました。）

こうなった理由はdockerを使用する時にローカルのディレクトリをsrcという名前で一つ下げているのですが、それに気づかなかったためプロジェクトの一番上のディレクトリでこのコマンドを打ってしまい上記のエラーが出てしまいました。

# 解決方法
srcにディレクトリを変えて、同じコマンドを打つことでエラーを解消することができました。（下記の手順）

```
% cd src
% npm run watch
```

# 余談
artisanのコマンドを打つ時大抵は`docker-compose exec php`をつけていると思うのですがこのコマンドはローカルのファイルを変えるコマンドなので特につけなくていいみたいです

あとlaravelの使い方として、コンパイルして `Users/user/construction_managment_system/src/public/css/app.css`を呼び出してトップページに反映させられなくて苦しんだのですが、下記の呼び出しのコマンドを使うことで無事反映させることができました。

```php:Users/user/construction_managment_system/src/resources/views/welcome.blade.php
~前略~
<link rel="stylesheet" href="{{ asset('css/style.css') }}">
~後略~
```

[cssの当て方を解決してくれた記事が気になる方はこちらをご参照ください](https://qiita.com/kotsuban-teikin/items/9b00d0faa0b7eaf70796)
Djangoで新規アプリを作成するまで

#Djangoのインストール

```
$ pip install Django
```

コマンドを実行してDjangoをインストールします。

#仮想環境を作成
Djangoのプロジェクトを開始する前に仮想環境を作っておきます。

```
$ python -m venv [仮想環境名]
```

作成出来たら[仮想環境名]\Scriptsディレクトリに移動して、仮想環境を実行してみます。

```
$ activate.bat
```

仮想環境が起動できていることが確認出来たら

```
$ deactivate
```

を実行して仮想環境から抜けます。
基本的にここからはこの仮想環境を起動した状態で作業をしていくことになります。


#Djangoプロジェクトの作成

Djangoのプロジェクトを作成するディレクトリ(今回は先ほど作成した仮想環境のディレクトリ)に移動して仮想環境に入ります。

仮想環境に入れたら

```
$ Django-admin startproject [プロジェクト名]
```

コマンドを実行します。
プロジェクト名は好きなものを設定してください。

#新規アプリ作成

仮想環境に入ったままmanage.pyがあるディレクトリに移動し

```
$ python manage.py startapp [アプリ名]
```

コマンドを実行します。
ここまでで完成となります。
Docker + FlaskでWebサービスを作成する

# Docker + FlaskでWebサービスを作成する

## はじめに

サンプルアプリ(feedback-api)を用いてご紹介します。

`Mac環境の記事ですが、Windows環境も同じ手順になります。環境依存の部分は読み替えてお試しください。`

### 目的

この記事を最後まで読むと、次のことができるようになります。

| No.  | 概要       | キーワード                              |
| :--- | :--------- | :-------------------------------------- |
| 1    | docker設定 | install, Dockerfile, docker-compose.yml |
| 2    | docker起動 | docker run, docker-compose up           |

### 実行環境

| 環境           | Ver.    |
| :------------- | :------ |
| macOS Catalina | 10.15.3 |
| Python         | 3.7.3   |
| Docker         | 19.03.8 |

### ソースコード

実際に実装内容やソースコードを追いながら読むとより理解が深まるかと思います。是非ご活用ください。

[GitHub](https://github.com/nsuhara/python-docker-flask.git)

### 関連する記事

- [Docker](https://www.docker.com/)

## 0. 開発環境

```tree.sh
/
│── config/
├── app/
└── Dockerfiles/
     ├── app/
     │   ├── Dockerfile
     │   ├── docker-compose.yml
     │   └── entrypoint.sh
     ├── docker_compose_up.sh
     └── docker_run.sh
```

## 1. dockerのインストール

```command_line.sh
~$ brew install docker
~$ brew cask install docker
```

## 2. 共通定義

### 2-1. Dockerfile定義

```Dockerfiles/app/Dockerfile
FROM python:3.7

RUN mkdir /code
WORKDIR /code

ADD entrypoint.sh /code/entrypoint.sh
ADD app/ /code

RUN pip install --upgrade pip --no-cache-dir
RUN pip install -r requirements.txt --no-cache-dir

EXPOSE 5000
ENV PYTHONPATH "${PYTHONPATH}:/code/"
ENV FLASK_APP "/code/run.py"
CMD ["/code/entrypoint.sh"]
```

### 2-2. entrypoint定義

```Dockerfiles/app/entrypoint.sh
#!/bin/sh

sleep 5

flask db init
flask db migrate
flask db upgrade

flask run --host=0.0.0.0 --port=5000
```

## 3. ローカルホストのRDBと接続する場合

docker(flask) <-> localhost(postgres)

### 3-0. 前提条件

localhostでpostgresを`start`しておくこと。

### 3-1. sh定義

```Dockerfiles/docker_run.sh
#!/bin/sh

docker stop $(docker ps -q)
docker rm $(docker ps -q -a)
# docker rmi $(docker images -q) -f

rsync -av --exclude=app/tests* app Dockerfiles/app

docker build -t feedback-api Dockerfiles/app
docker run -it -p 5000:5000 feedback-api:latest
```

### 3-2. sh実行

```command_line.sh
Dockerfiles/docker_run.sh
```

## 4. コンテナのRDBと接続する場合

docker(flask) <-> docker(postgres)

### 4-0. 前提条件

localhostのpostgresを`stop`しておくこと。

### 4-1. sh定義

```Dockerfiles/docker_compose_up.sh
#!/bin/sh

docker stop $(docker ps -q)
docker rm $(docker ps -q -a)
# docker rmi $(docker images -q) -f

rsync -av --exclude=app/tests* app Dockerfiles/app

docker-compose -f Dockerfiles/app/docker-compose.yml up --build
```

### 4-2. yml定義

```Dockerfiles/app/docker-compose.yml
version: '3'
services:
  docker_postgres:
    image: postgres:11.5
    ports:
      - 5432:5432
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: feedback
      POSTGRES_INITDB_ARGS: --encoding=UTF-8

  app:
    build: .
    depends_on:
      - docker_postgres
    ports:
      - 5000:5000
    environment:
      ENV_CONFIG: docker
      SQLALCHEMY_POOL_SIZE: 5
      SQLALCHEMY_MAX_OVERFLOW: 10
      SQLALCHEMY_POOL_TIMEOUT: 30
```

### 4-3. sh実行

```command_line.sh
Dockerfiles/docker_compose_up.sh
```
max msp drag&dropでフォルダ内のメディアファイルを取得する


フォルダ内にあるwavファイルを一括で `umenu` にItemに追加したかった

## dropfile & umenu パッチ
　
`dropfile`パッチを使うことでフォルダのパスを取得できる

`umenu` に `autopopulate 1` をつけることでフォルダ内容を取得できる



<img width="500" alt="dropfine.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45348/90144e06-667c-fe4b-5400-a30a334d36b9.png">




## sample

<pre><code>
----------begin_max5_patcher----------
1167.3ocuXsziaaCD9r8uBAgdzwVj5ctk1zrs.In8ROTDTXPKQuKWHIJPQsq
SCR9s2gCk7SYu1dcpNHINhVy7MO9lQ9qiG4tPth2357VmO6LZzWGOZDJxHXT
25QtkrUYErFbatk7lF18b2I1mo4qzn7Ft14mH8hks5BtV+kZt8c6557OcORj
i6Wt3w2Dzu8ZlN6AQ08yU7Ls8WPCSm5Mwg3SLWBvyT5Tu0ump1RQEnDzrnaD
ZUMJkXD9swiMmlbl3CdCK3pMFlhUx0b0bdEaQAhFuihwINtKXU2OHVouLVS8
LmC8NMTICBU5U.0LYYIuRePnLWwt2gUk6jqj0NLmRdtf4rTVjuwwrExR6k0n
+h0C49.undonfOufsfWbBjGQlF3GGBn1Gi1QwSgETuKC7dWA3MXyXhtmJZNX
jjPNAfBBmFkX.DMwfDRJFYiR+wGMs+7AhOwmJyCb0n456iFpuW+4Kx+2IsOg
xn40FRUNe00FjVzp0xpqpX7nEhgmk6vCyGoA8muD2w0P6bLZUVqVVKqaKXZt
yERu5epHOIHxB0NF1jjCncVJqzMh+E0AAdvEP7t0anBhYnI8NkfU3dMTx7mA
3bfqYQ6xkb02cXs4B4eTyqNp2YYgjoOI6bR5obUfGxVSGQQVJuj+unnOBzqU
b.u4NvkBVF+BSK7NKrRCwdRgWCTulJfVf5ns2xdhoVm2ryCFhCfbL3Kpvn9d
L4ZdY2DOtRvKN2ya5yrmLaZh4jUFY.YzAj4Ofr.T1NkQKMQosnq1tcB8T4dP
UJgZpRSPpHBLi.tl5erBU+gKT6cRPpyRAFGb+DKC7PxlGb9s2+1Y+UCW0L6i
+9G904e5c+hevr2KyLtdcyrOwV4jL6OUxGA6pY1cb8GvgA9nnQOSyazzYtCl
G3ebdf9YFXOwymyzZk.H64atqoKUoKWwjRTzxkK6E2Ke6ThlGjJ8f4M6k4zV
NbBvdw98B66EwGJXuid5yDoC7rBY08urkJpDZvYcXt9N6pDpiLOK33uAKbw1
518fEm8WtsjRcYXWDmDg5eNEAzzoIliPO6QrOz3J9pZbQdEMtPE4VHp1+SmP
a2HeWuWirUk0i+tO7wYi4lCUPhJlV.i5rYOHuvV6pTjWKg50NURirCXFg8hB
gwNo8Ksw3CBpmqwQOCiqC.uJ8X545PdAEEdCTT3Y.n3afd7ie8gURXzT7Ch9
ADXMM9eQ6KI8F3Irf7khs81yqTU9WhW+0oKxYoJ+CTkkvfUW+Dzisa6nV.h0
GkJyxjI3RQkcIRD4p3OI52O1K0ko.xQMvL1prjSqhr+KJtkRnibUqna9K.ei
69j78HoVyqY4w+Yns5a59xB.RKYsE5c8CrrLXLfLYg0zL8Q7IwQAw.LmFEFj
5QM2kZDQfv9lD0IctWkYLh0+6.c5pDTjn+KC2NbrmAdmhyqtXKzyXRg9lCyc
P8SDM91ab+MunP97ostsaG8YrgTXpmWx57nAr9DZHAcuwIjDh4F32DFDdSA.
9OccGLI2E6bMQZuHzCmRIgnkR7HoQWe32VhfCYXrvl5tIlwYQF+sw+GvSb.d
D
-----------end_max5_patcher-----------
</code></pre>