OmniAICreator/Qiita-1.07M huggingface dataset:
Pythonのunittestでの、assertLogs()の使い方

Pythonのプログラムにおいて、「特定の処理が正しくログを出力していることを確認したい」というときはありませんか？unittestのメソッド`assertLogs()`はその疑問を解消するためのメソッドです。

* [unittest \-\-\- ユニットテストフレームワーク — Python 3\.8\.1 ドキュメント](https://docs.python.org/ja/3/library/unittest.html#unittest.TestCase.assertLogs)


ただ、日本語の利用例がなく、公式リファレンスももうちょっと分かりやすく書いて？な感じだったので、実動例を作ってみました。

# `assertLogs()`とは

`with`文を利用するメソッドの一つで、`with`文内で発生した、ログの出力を、指定のコンテキストマネージャオブジェクトに格納する というメソッドです。よって単体でアサート処理を行うわけではなく、別の`assertXXX`メソッドと組み合わせて利用します。

```py:test_XXX.py
import unittest
import logging

class Test_ProcessCaller(unittest.TestCase):

  # ...

  def test_processcaller_setlogger(self):
    logger = logging.getLogger("TEST")
    proc = ProcessCaller("python", "-V", logger=logger)
    with self.assertLogs(logger=logger, level=logging.DEBUG) as cm:
      proc.run()
    self.assertEqual(cm.output, ['DEBUG:TEST:python -V'])

```

上記コードは、「`ProcessCaller#run()`メソッドにおいて、デバッグレベルで呼び出したコマンドを出力することを確認する」というコードです。

`with`文のexpressionで、`assertLogs()`メソッドを呼び出すと、`with`ブロック内でのログ出力がすべて、`cm`変数に格納されます。`assertLogs()'の引数にロガーやログレベルを指定することで、収集するログを限定することができます。

そして、`with`ブロックを抜けると、`cm`変数には`output`と`record`という二つのプロパティが設定されます。

* output：すべてのログを「画面に表示したときの文字列」の配列
* record：すべてのログを示す`record`オブジェクトの配列

これを`assertEqual()`メソッドなどで期待した値と比較することで、「正しくログが出力されたか」を確認することができます。たとえば、上記のコードの`ProcessCaller`クラスのコンストラクタ引数から`logger`の指定を外すと・・・。

```py:test_XXX.py
import unittest
import logging

class Test_ProcessCaller(unittest.TestCase):

  # ...

  def test_processcaller_setlogger(self):
    logger = logging.getLogger("TEST")
    proc = ProcessCaller("python", "-V")
    with self.assertLogs(logger=logger, level=logging.DEBUG) as cm:
      proc.run()
    self.assertEqual(cm.output, ['DEBUG:TEST:python -V'])

```

一行目で作成した`logger`にはなにも出力されないため、テスト失敗となります。
AWS LambdaでLaravelを動かす

最近サーバーレス(Lambda)に興味があったので始めてみるかとは思ったものの
好きな言語であるPHPは標準でサポートされておらず。。。
どうにか動かす方法はないかと調べていたところ、[bref](https://bref.sh/)なるものを使えば簡単に動かせそう！しかもLaravelも動かせる⁉
だったので、その手順をまとめてみました。

## 準備

以下のものが必要になります.

- AWSアカウント
- AWS CLI
- AWSアカウントアクセスキー及びシークレットキー
- npmコマンド

こちらの準備については記事の内容ではないのでスキップします。

## serverlessコマンドをインストール

まずはserverlessコマンドをインストールします。
こちらはLambdaをデプロイする際に使用します。

```bash
$ npm install -g serverless
```

serverlessコマンドのインストールが完了したら、AWSアクセスキー及びシークレットアクセスキーを設定します

```bash
$ serverless config credentials --provider aws --key <key> --secret <secret>
```

注意点として、AWS CLIのデフォルトアカウントを設定している場合は
そのアカウントが使用されるので上記の手順は不要です。

## Laravelプロジェクト作成

まずはcomposerコマンドでlaravelプロジェクトを作成しましょう

```bash
$ composer create-project laravel/laravel serverless-laravel --prefer-dist
```

## brefを追加

```bash
$ cd serverless-laravel
$ composer require bref/bref
```

注意点として、brefの最新バージョンを使用するにはPHP7.2以上が要求されます。
PHP7.1以下で使用したい場合はbref0.5未満を使用する必要があるみたいです(未確認)
参考: https://bref.sh/docs/installation.html#bref

## serverless.ymlを用意

serverless.ymlをプロジェクトディレクトリ直下に作成します。

```serverless.yml
service: serverless-laravel

provider:
    name: aws
    region: ap-northeast-1
    runtime: provided
    environment:
        # Laravel environment variables
        APP_STORAGE: '/tmp'

plugins:
    - ./vendor/bref/bref

functions:
    website:
        handler: public/index.php
        timeout: 28 # in seconds (API Gateway has a timeout of 29 seconds)
        layers:
            - ${bref:layer.php-73-fpm}
        events:
            -   http: 'ANY /'
            -   http: 'ANY /{proxy+}'
    artisan:
        handler: artisan
        timeout: 120 # in seconds
        layers:
            - ${bref:layer.php-73} # PHP
            - ${bref:layer.console} # The "console" layer
```

### Lambda上でLaravelを動かすためにコードを変更

Lambdaでは`/tmp`ディレクトリ以外への書き込みは出来ないため、Laravelが書き込みを行う領域を変える必要があります。


```bootstrap/app.php
# $appを作成している行の直後に記載
$app->useStoragePath($_ENV['APP_STORAGE'] ?? $app->storagePath());
```

```..env
VIEW_COMPILED_PATH=/tmp/storage/framework/views
SESSION_DRIVER=array
LOG_CHANNEL=stderr
```

```app/Providers/AppServiceProvider.php
    public function boot()
    {
        if (! is_dir(config('view.compiled'))) {
            mkdir(config('view.compiled'), 0755, true);
        }
    }
```

### デプロイ準備

デプロイを行う前に、開発用パッケージなど不要なものを削除します。
**ただし、require-devでインストールした依存関係が削除されるので注意してください**

```bash
$ composer install --prefer-dist --optimize-autoloader --no-dev
```

### デプロイ

```bash
$ serverless deploy
.....
endpoints:
  ANY - https://XXXXXXXXXX.execute-api.us-east-1.amazonaws.com/dev
  ANY - https://XXXXXXXXXX.execute-api.us-east-1.amazonaws.com/dev/{proxy+}
```

デプロイが完了すると、コンソールにAPI GatewayのエントリーポイントのURLが表示されるのでアクセスしてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298811/f32d6d8e-716e-cbac-bf44-9b191995f678.png)

#### デプロイしたものを削除する

removeコマンドで削除できます。

```bash
$ serverless remove
```



---

参考:
https://bref.sh/docs/
jQueryでスクロールダウンを導入してみた

ボタンを押した際に同じページ内で指定の場所にスクロールするやり方を実装してみました!
##スクロールダウンの方法
今回はid名buttonを押した際にid名header部分にスクロールするように指定してみる

```js
//変数を指定する
var header = $('#header').offset().top;

//id名buttonをクリックした際の関数を指定する
$('#button').click(function(){
  $('html,body').animate({
  {
    scrollTop: header
 }
)};

```

##解説
.offset()ってなんぞや？となると思うので、自分はなりました笑
.offsetとは指定した要素のドキュメントの左上からのy軸方向の距離を取得する。
つまり今回の例で言うとid名headerの位置をドキュメントから見てのy軸の距離を取得したという事になります。そしてその取得した値を変数headerに代入したと言う事になります。
リファレンスが切れているシーンをスクリプトで開くときのTips

Mayaではリファレンスが切れていると、接続しなおすかそのままにするか毎回指定する必要があります。
![bTEuf3iQXjodhnR1577182342_1577182358.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79407/004e870c-8df8-3b2e-fab7-efa46cb22ae8.png)

このダイアログをスキップする小技のご紹介です。

---


fileオープン処理を次のように書いてみましょう。

```python
import maya.cmds as cmds

_show_dialog = cmds.file(q=True, prompt=True)
cmds.file(prompt=False)

cmds.file(
    "hoge.ma",
    f=True,
    options="v=0;",
    ignoreVersion=True,
    typ="mayaAscii",
    o=True)

cmds.file(prompt=_show_dialog)
```

この書き方をすることによって、ダイアログを表示せずにデータを開くことが可能になります。
【SIGNATE】機械学習コンペに初参加した話 Weather Challenge：雲画像予測【11位】

## はじめに

データ分析系コンペに初参加したことを振り返ります。

普段のデータ分析系の案件から離れて、コンペに参加することで新たな知見を得ようということで、会社の業務の一環として取り組みました。

参加したコンペは  [Weather Challenge：雲画像予測](https://signate.jp/competitions/169) 。バーチャルYouTuberポン子さんのライブ配信をよくみてて親しみがあったという理由で選びました。何かしら愛着があった方がモチベーションにつながります(結構大事)。

結果は87組中11位!! 初参加で何とか銀メダル🥈を獲得しました。

![スクリーンショット 2019-12-03 17.28.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469334/a125c921-25a8-9c1f-1a1e-dfaa817159aa.png)

また、共にコンペを格闘した数学つよつよのチームメイト [@myjm](https://qiita.com/myjm) さんに感謝します。

## コンペ概要
気象衛星で撮影された雲画像と、対応する気象解析データを使って24時間先の雲の**変化を予測**し、**画像を生成**するというタスクです。

「画像生成・未来予測」と複数のタスクが含まれる、チャレンジングなコンペでした。


### 衛星画像データ

気象衛星で撮影された雲画像の具体的なデータはこれ。
![スクリーンショット 2019-12-03 16.26.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469334/61a7d27f-d1e4-a1f0-4b75-56456f05d1d5.png)

このグレースケール画像(512, 672)が1時間ごとに1枚与えられます。

### 気象解析データ

気象解析データは(例えば850hPa等圧面の気温を)可視化するとこのような感じ。
![ダウンロード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469334/90ca9652-94f3-d8e5-d86c-b7f50c858e91.png)

(128, 168)の平面グリッドデータになっています。各グリットに気温、湿度、風速など、様々な気象データが格納され、さらにこの平面グリッドデータが3次元的に様々な高度で与えられています。

平面グリッドデータなので、数値データでありながら画像データのような振る舞いをするため、取り扱いに難儀しました。

### タスク詳細

2016年、2017年のデータで学習し、2018年のデータを予測します。

2018年のデータは一部データが非公開になっていて、公開されているデータを元に、未知のデータを予測します。

## 基本戦略
1. まずは一番最初に見つけた手法でどんなスコアでもいいからサブミットし、ベースモデルを作る
2. その後衛星画像・気象データの特徴量エンジニアリング

しかし、一切の特徴量エンジアリングや前処理がスコア悪化をもたらしてしまった。。しかたなく、最終的にこのベースラインをsubmitしました。

## モデル
画像 + 時系列 というタスクなので、CNN, RNN のキーワードで手法をサーベイしました。
見つかった Prednet という video prediction 手法を採用。

 [Prednet](https://coxlab.github.io/prednet/)

衛星画像を1セット48枚に分割し、24枚で学習 → 24枚で外挿予測した。気象データは使用していない。

外挿予測をするために正解画像を使ってウォーミングアップをするイメージです。よくみると、最初の24枚まではどんどん予測精度が良くなっていき、外挿からの24枚は精度がどんどん悪くなっているのがわかります。

![スクリーンショット 2019-12-03 15.45.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469334/c660ce2c-3eeb-3414-4ac7-3edf9e4a9f91.png)

アニメーションにしたもの

![ezgif.com-gif-maker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469334/8892a0e0-adc1-da99-df91-ad3d566643c8.gif)


## 前処理

- データサイズを1/4に縮小 (512, 672) → (128, 168)
- 欠損している画像は直前の画像をコピー

## その他試したこと
以下、試したことは全てスコア悪化をもたらした。

- データサイズを1/8, 1/16にして学習
- 大まかな季節分割をして季節ごとに学習
- ウィンドウサイズ24でデータをずらしてデータセットを2倍に水増し
- 96枚で学習 → 24枚で外挿予測
- 18枚で学習 → 24枚で外挿予測
- バッチサイズ1で学習
- 画像の正規化、ノイズ除去

## 反省点
- Prednetの改良に拘泥してしまい、別モデルのサーベイを怠った
- 「気象データは使わない」という戦略を取れなかった

この２点に尽きます！！スコアが伸びなかったらいったん冷静になって別の手法を探すことに徹した方がよかったです。

こちらのブログ [Kaggleを取り掛かるまでにやったこととと、モチベーションの維持のために必要だったこと - にほんごのれんしゅう ](https://catindog.hatenablog.com/entry/2018/05/20/221624) にその点が言及されていました。

![スクリーンショット 2019-12-03 17.00.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469334/9a65510e-7bd6-0699-103b-66b6a53fc111.png)

コンペに参加してスコアが伸び悩んだ場合、普段の案件でも煮詰まった場合はこのことを肝に命じておきます。

## おわりに

思うようにスコアが伸びなかったことが悔やまれますが、初のコンペ参加でやるべきことをしっかりやったので銀メダルを取ることができました。タスクの整理・タスクにあった手法の調査・データの前処理などデータ分析の定石はしっかりと抑えられていました。

また、コンペに参加することでチームでの分析、クラウドの活用、精度を上げるための試行錯誤のプロセスなど、スキルがガンガン上がった実感があります。

今後もスキルアップ目指してどんどんコンペに参加していきたいです。
PBSのプロセス・スレッド

PBSではプロセスやスレッドを、それぞれmpiprocs、ompthreadsで指定する。

### mpiprocs
> Number of MPI processes for this chunk. Cannot use sum from chunks as job-wide limit.
The number of lines in PBS_NODEFILE is the sum of the values of mpiprocs for all chunks requested by the job. For each chunk with mpiprocs=P, the host name for that chunk is written to the PBS_NODEFILE P times.

### ompthreads
> Number of OpenMP threads for this chunk.
Cannot use sum from chunks as job- wide limit.
For the MPI process with rank 0, the environment variables NCPUS and OMP_NUM_THREADS are set to the value of ompthreads. For other MPI processes, behavior is dependent on MPI implementa- tion.

## mpiprocs

MPIのプロセス数を指定する。通常、MPIのプロセス数は

```shell
mpirun -np <並列数(ie. プロセス数)> <実行コマンド>
```

で指定する。MPIプログラムをPBS管理下で実行するには、npオプションを指定する代わりにmpiprocsを指定する。

## ompthreads

OpenMPのスレッド数を指定する。通常、OpenMPのスレッド数は

```shell
!$omp parallel num_threads(3)
  !処理A
!$omp end parallel
```

のようにnum_threadsで指定するか、環境変数OMP_NUM_THREADSによって指定する。OpenMPプログラムをPBS管理下で実行するには、ompthreadsを指定する。これにより、環境変数OMP_NUM_THREADSが設定され、スレッド数が決まる。

## PS.

一部のスパコンでは、mpiprocsやompthreadsの代わりに、プロセス数やスレッド数として設定する。

---

## 参考

- [Qiita: MPIの環境構築や基本コマンドのまとめ](https://qiita.com/kkk627/items/49c9c35301465f6780fa)
- [OpenMP入門: スレッド数の設定](https://www.nag-j.co.jp/openMP/openMPHowToSetNumThreads.html)
８ヶ月かけてTODOアプリを作った話


#はじめに
今年の4月頃から開発していたTODOアプリが完成したのでリリースした。
今回はなぜアプリの開発に８ヶ月もかかってしまったのかを自戒も含めて公開したいと思う。

#どんなアプリ
リリースしたアプリはこちら
https://apps.apple.com/us/app/tickettask/id1491648458?l=ja&ls=1

####使用技術
開発にあたって使用した技術は以下
・Swift
・Xcode
・Firebase(Analytics集計のため)
・Realm

####アプリ概要
アプリの概要としては、根幹としてはよくあるTODOアプリ。
それ以外に設定した期間でのリセット機能、定期的なリマインド機能などがある。


ここまで見ていただいて、ある程度のアプリ開発の経験がある人はこう思ったんじゃないでしょうか。

**「ん？これくらいの用件のアプリだったら８ヶ月もかからなくないか？下手したら１ヶ月で作れるくらいの規模じゃないか？」**

はい。こういったご意見も含めてなぜこんなに期間がかかってしまったのかを書いていく。


#開発した経緯
まずなぜこのアプリを開発したかというところだが、当初作りはじめていたときこのアプリは公開などするということを全く考えていなかった。勉強のために様々なデザインのアプリを見ていたときに、すごく好みなUIのアプリがあったため自分でも作ってみたいと思いダラダラと作りはじめていった。

##行き当たりばったりの開発
表現したいUIができてきた頃にこんな思いになっていった
*「この土台のアプリを使えばストアに公開できるくらいのアプリが作れるんじゃないか？」*
こうして本格的に中身を作りはじめた。
もともと開発していたアプリは実験的な感覚で作っていたので画面仕様書だったりを全く作っていなかったし、ましてや公開する気もなかったので中身の部分も仕様なんて全く考えていなかった。
とりあえずTODOアプリを作ってみようと思い、仕様を考えはじめた。そしてざっくりと作りたいアプリのイメージを固めた。

#犯した２つの失敗
こうして開発を進める中で自分は２つの失敗を犯してしまった。これらが開発が伸びて行ってしまった原因だと考えている。

####・仕様の曖昧さ
一つ目が仕様の曖昧さ。アプリを作り出しがUI経緯なのに対して画面仕様書の一つも作っていなかった。これによってアプリ全体のスケールが想像できずに内部仕様を考えるときに足枷となっていた。
そして開発中にアイデアが浮かんだ時も作り出している構造だと実現できないような物もあったりしたのUIの構造を丸々作り変えたりしていた。これによって開発スケジュールが膨れたりしていた。

####・怠惰により開発の先延ばし
　二つ目が怠惰による開発の先延ばし。途中本業が忙しくなる時期があったりして個人プロジェクトを１、２ヶ月放置した期間があったりした。しかしこれも一つ目の仕様の曖昧さが生み出してしまった「スケールが想像できない」ことでモチベーションが保てなかったことが原因でもあると思う。

#学びのある開発を
開発を行ってきた中で確かに失敗はあったが次につながる失敗であったと思う。
次からはざっとでいいから画面一覧を作ろうと思ったし、ちゃんと仕様を決めてから開発に取り掛かろうと思った。

エンジニアをはじめたての頃Qiitaである記事を見てすごく衝撃を受けた記事があった。
ジャバ・ザ・ハットリさんのこの記事。
[開設後３週間で収益１０万円を得た個人開発サイトでやったことの全部を公開する](https://qiita.com/jabba/items/1a49e860a09a613b09d4#%E5%80%8B%E4%BA%BA%E9%96%8B%E7%99%BA%E3%81%A7%EF%BC%93%E5%A4%A7%E3%82%84%E3%81%A3%E3%81%A6%E3%81%AF%E3%81%84%E3%81%91%E3%81%AA%E3%81%84%E3%81%93%E3%81%A8)

この記事の中で以下のようなことが書いてある

>#個人開発で３大やってはいけないこと
・「マネタイズは後で考える」と言ってとりあえず作る
・「コンテンツ（ユーザー投稿数確保）は後で考える」と言ってとりあえず作る
・「ウケるかどうか出してみないと分からない」と言ってとりあえず作る
上記の３つとも推奨されている方もいる。ただ少なくとも私にとってはこの３つが最大の失敗要因だった。
映画「ソーシャル・ネットワーク」のジャスティン・ティンバーレイクのように「広告なんてクールじゃねーよ」と気取ってもいいが、そんなのが上手くいった試しが無い。
だいたいにおいて 考えることを放棄した時点で負けが決定している。じっくり考えるところが個人開発の一番おもしろいところだし「後で考える」ぐらいならその場でとことん知恵を
絞った方が楽しいだろう。

当時この記事を見ながら「自分が個人プロダクトを作るときはとことん思考を張り巡らさせて作りるぞ！！」なんて考えていたがいざアプリを作りおえてみると**アプリを完成させる**ということだけに拘って他のところか完全にお座なりになっていた。
もちろんこの考えが間違っているというわけではないが、結果アプリのコンセプトも開発途中でふわふわになっていろんな機能を追加したり削除したりして完成が遅くなってしまった。
**「コードを書く」**ことはすごく楽しいし刺激的だけど、それと同じくらい**「準備する期間」**という物が大事なのだとわかった。

#最後に
今回作ったアプリが受けるか受けないかに関わらずこれからもアプリを作り続けると思います。
やはり作ってきたアプリが公開される瞬間というのはすごく刺激的だしワクワクします。失敗を繰り返しながらより素敵なアプリが自分の中から生み出されていくのを夢見て明日からも開発に勤しんで行きます。
次はAndroid界にも出したいからFlutterで作ろうかなんて考えてます。もちろん技術だけではなく自分なりに「これは受ける！」ってアプリを作っていきます。

宣伝にはなっちゃいますが自分が作った[チケットタスク](https://apps.apple.com/us/app/tickettask/id1491648458?l=ja&ls=1)というアプリ、親バカですがすごく可愛いアプリなので是非インストールしてみてください。
[漏洞通告]CVE-2019-17571/Apache Log4j 1.2.X存在反序列化远程代码执行漏洞

### 漏洞描述
`Apache Log4j`是美国阿帕奇（Apache）软件基金会的一款基于Java的开源日志记录工具.`Apache Log4j 1.2.X`系列版本中存在反序列化远程代码执行漏洞.攻击者可利用该漏洞执行任意恶意命令.在`Log4j 1.2.X`中包含一个`SocketServer`类,该类很容易对不可信数据进行反序列化,当侦听日志数据的不可信网络流量时,与反序列化小工具结合使用时,可以利用该类远程执行任意代码.影响包含目前最新版本.

### CVE编号
CVE- 2019-12409

### 漏洞威胁等级
高危

### 影响范围
1.2.4 <= Apache Log4j <= 1.2.17(最新版)

### 简单分析
其实早在`Apache Log4j 2.8.2`时代就存在反序列化远程代码执行漏洞(CVE-2017-5645),当时触发的漏洞类为`org.apache.logging.log4j.core.net.server.TcpSocketServer`,到了`Apache Log4j 1.2.X`时代,漏洞类变为`org.apache.log4j.net.SocketServer`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491410/ff684fd9-c797-3f41-10ca-64666531dfb5.png)

大致原理和`CVE-2017-5645`类似,只需要找到可以利用的`gadget`即可触发.由于是socket协议,这里我使用nc发送序列化文件到其靶机端口,最终成功触发漏洞

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491410/bcb9b83c-9dad-adf4-5110-708770de1c26.png)
### 修复建议

- 1.升级到`Apache Log4j 2`系列最新版
- 2.禁止将该类所开启的socket端口暴露到互联网

### 时间轴
[0] 2019/12/20 NVD发布该漏洞
[1] 2019/12/24 亚信安全网络攻防实验室研究并复现该漏洞发布漏洞预警

### Reference
https://nvd.nist.gov/vuln/detail/CVE-2019-17571
EC-CUBE4 でテスト用のデータを生成する

EC-CUBE4 には沢山のテスト用ダミーデータを生成するコマンドが実装されています。

https://github.com/EC-CUBE/ec-cube/pull/2741

開発時にダミーデータが欲しい場合などに便利です。

### 下準備

EC-CUBE4 をインストールし、 `composer install` を実行してください.
([Composer](https://getcomposer.org/) がインストールされてない方はインストールしておいてください)

```
cd path/to/ec-cube
composer install
```

パッケージ版の場合は必要なライブラリが含まれていないため、このコマンドを実行する必要があります。
github から clone してきた場合は不要です。

ダミー画像生成機能を使用したい場合は、 PHP の GD Extension が必要です。

### 使用方法

以下のコマンドを実行します

```
bin/console eccube:fixtures:generate
```

デフォルトでは、以下のデータを生成します

- 商品数: 100点
- 会員数: 100名
- 注文数: 会員1名につき10件

これらは、以下のようなパラメータで設定できます
```
bin/console eccube:fixtures:generate --customers=2 --orders=1 --products=10
```

生成した会員のパスワードは `password` です。
**このデータを決して本番環境へ反映しないよう、くれぐれもご注意ください**

#### 大量のデータを生成したい場合

上記コマンドを何回か繰り返し実行することをおすすめします。

以下のように cron で 10分おきに実行してもよいでしょう。

```crontab
crontab <<EOF
*/10 * * * * cd /path/to/ec-cube && bin/console eccube:fixtures:generate
EOF
```
Open Source Compliance 関連

当初 12/24 記事として公開していた記事 「OpenChain Japan WG 第13回会合のご案内」 は、諸事情により「一般公開」ができなくなりました。Japan WG (JWG) の活動に関心のある方は [JWGのwiki](https://wiki.linuxfoundation.org/openchain/openchain-japanese-working-group) から "OpenChain Japan WG ML" への参加をご検討ください。第13回会合の案内なども共有予定です。

そのため、Open Source Compliance 関連で、"やってみました" ネタを提供します。ご了承ください。

# [番外編] Raspberry Pi ＋Docker で FOSSology を動かせるか... 

手元で気軽に使える OSS監査ツール環境を作りたかったのと、Linux を少しでも触ろうかなと思いやってみた~~... というか、やっているところ~~。

元ネタは、SONYの小保田さんが、[Japan Technical Jamboree 70](https://elinux.org/Japan_Technical_Jamboree_70) にて 「FOSSology - Install from Sourceのススメ([pdf](https://elinux.org/images/c/c3/FOSSology-InstallFromSource.pdf))」 を発表されたと OpenChain Japan WG の Tooling SWG 第5回(2019-10-17) で伺ったことによる。ただ、まったく同じ事をするのもどうかと思い、docker 上で動かしてみようかなと... 

えぇ、そうです、Raspberry Pi 4 (4GB) を買うための理由にしました...

## 2020/05/12 追加
長らく放置してしまいましたが、このネタの完了を次の記事で報告します。
[Raspberry Pi 4 + Ubuntu 18.04 (arm64) + Docker + FOSSology](https://qiita.com/TakashiNinjouji/items/7f5b6ac9af711680c8a5)



### 2019/12/29 追加
記録として残しておきます...
 - [Raspberry Pi 4 に Raspbian Buster の環境をつくる](https://qiita.com/TakashiNinjouji/items/1240c644f5c560e60f48)
 - [Raspberry Pi 4 (w/ Raspbian Buster) に docker をインストールする](https://qiita.com/TakashiNinjouji/items/ee6a769eb7dbd9587827)




# 以下は 12/24 公開のもの


更新されるまでの間、最近気になった情報を紹介しますので、そちらをご覧頂けると幸いです。


# [Tool] [OSS Review Toolkit](https://github.com/heremaps/oss-review-toolkit)

[FOSSology](https://www.fossology.org/) ＋ [SW360](https://github.com/eclipse/sw360) と同じように、OSS を OSS で管理するためのツールです。
業務ワークフローや、組織間での情報管理などを意識している設計のように思われるため、OpenChain Japan WG の Tooling SWG メンバーでも関心が集まりつつあります。



# [Article] [Open Source AI - What's 2020 Looking Like?](https://www.linkedin.com/pulse/open-source-ai-whats-2020-looking-like-ibrahim-haddad/)
Ibrahim Haddad, Published on December 22, 2019

Artificial Intelligence については、Ethics(倫理) に関する話題を目にしますが、利用する Open Source Software や Data といった構成する技術や要素についても議論があります。英文記事ですが、AI と Open Source について話題を振り返りつつ、来年に向けての課題整理のために目を向けて見るのはいかがでしょうか。

# 明日の記事は
明日12月25日は、この Advent Calendar 企画の締めくくりとなります。
トヨタ自動車の[遠藤さん](https://qiita.com/MasatoENDO)が、Promotion SWG を紹介し、そして、この25日間を振り返ります。国内外の産業界が Open Source Compliance に注目する中、どんな話しが出てくるのでしょうか。お楽しみに！
# おまけ：自己紹介
忍頂寺です。所属等は別記事「[Open Source Compliance のお役立ち情報まとめ・上 (12/14公開記事)](https://qiita.com/TakashiNinjouji/private/32aedf7102bab3a96efb)」 を参照ください。[「(同)下 (12/15公開記事)」](https://qiita.com/TakashiNinjouji/items/f84afc631a856eb30425)もあります。


---
リンク先を押した際に別タブを開いて表示させる方法

自分が普段ネットを閲覧している際に感じてたあー開いてるページ変わった！が割とイラっとするのでそちらの実装をポートフォリオサイトに実装してみた！
調べてみたらとても簡単でした！

aタグ内に**`target=”_blank”`**を記述するだけ！

```html
<a href="URL" target=”_blank” >
```

しかし、どうやらこの方法だけだと元のページをJavaScriptで操作できるようになるとのことです！
詳しい説明はこちらの記事に書いてあるので見てみてください！

[target="_blank"には気をつけよう](https://qiita.com/Apprentice_engineer/items/5db19a6d9bd4e7978aec)

```html

```html
<a href="URL" target=”_blank” rel="noopener noreferrer" >
```

```
Kairos3 API を使ってリード情報を取得するテスト

[Kairos3 API](https://kairos3.com/help/api.html) を使って、[Kairos3](https://www.kairosmarketing.net/)からリード情報などを取得してみました。

尚、Kairos3 APIは、有料オプションとなっております。

# Kairos3とは

https://www.kairosmarketing.net/
MAのクラウドサービスです。

>マーケティングオートメーション「Kairos3」は、あらゆる組織・どんな環境でも、「始めやすく理解しやすい」クラウド型マーケティングオートメーション（MA）サービスです。 

# API情報

* [Kairos3 API](https://kairos3.com/help/api.html)

## APIエンドポイント

| API Endpoint | https://api.kairos3.com |
|:---:|:---:|

## リクエストヘッダ

| X-Kairos3-Api-Key | Kairos3 アカウントオプション画面に記載されたAPI Key |
|:---:|:---:|

---

# cURL

まずはcURLを使って情報を取得してみます。

## リード情報取得

### HOTリード情報取得

GET /v1.0/customers/hot

パラメーター

* offset
* limit

#### HOTリードを5件取得

`$ curl -v -H "X-Kairos3-Api-Key:<API Key>"  "https://api.kaios3.com/v1.0/customers/hot?limit=5"`

#### HOTリードを5件取得（オフセット2）

`$ curl -v -H "X-Kairos3-Api-Key:<API Key>"  "https://api.kaios3.com/v1.0/customers/hot?offset=2&limit=5"`

### リード情報取得

#### リードを2件取得

`$ curl -v -H "X-Kairos3-Api-Key:<API Key>" "https://api.kairos3.com/v1.0/customers?limit=2"`

## SFA案件情報

### 案件一覧取得

#### 案件一覧3件取得

`$ curl -v -H "X-Kairos3-Api-Key:<API-Key>" "https://api.kaios3.com/v1.0/projects?limit=3"`

### 案件取得
プロジェクトIDを指定して案件情報を取得

#### プロジェクトID[1]の案件情報を取得

`$curl -v -H "X-Kairos3-Api-Key:<API Key>" "https://api.kairos3.com/v1.0/projects/1"`

---
# 次にやること

Nodeやら、Rubyやらで色々試してみたい。
Blink Shellの使い方【iPad Pro + Smart Keyboard】

# tl; dr
- Blink ShellでiPadからリモートサーバに繋ぐよ
- SSHもmoshも、もちろんscpも

# 当該環境
- Blink Shell (¥2,440, 2019/12, [ビルド可能](https://github.com/blinksh/blink))
- iPad Pro 11 inch
- Smart Keyboard
- EC2 t2.micro Amazon Linux

\* Blink Shell以外の検討対象は、iSH・Cloud9・Google Cloud Shell

# 使い方
- Key Pair作成時の.pemファイルはiPadOSではダウンロードできなかったので、Macbookから。
- Keysの部分にBegin RSAから始まるKey PairをBlinkに登録。
- SSH接続確認。Hostは自分のお好きな名前、HostNameはEC2インスタンスのIPv4 Public IP、Portに22、保存したKey Pairを指定し、シェルから`ssh <Host>`で接続。
- [ここ](https://ticklecode.com/step8-mosh-setting/) を参考にEC2のセキュリティグループのインバウンド欄を下記のように設定。

|      Type     |Protocol| Port Range | Source |
|:-------------:|:------:|:----------:|:------:|
|Custom UDP Rule|   UDP  |60000-61000|Anywhere|


- 下記コマンドを打っていってEC2側にmoshを入れる。

```

$ sudo yum install git autoconf automake gcc gcc-c++ make openssl-devel
$ sudo yum --enablerepo=epel install zlib-devel ncurses-devel protobuf-devel

$ mkdir work
$ cd work/
$ git clone https://github.com/keithw/mosh.git
$ cd mosh
$ ./autogen.sh
$ ./configure
$ make
$ sudo make install
```

- `$ mosh --version`でバージョン返してくれればOK
- 最後にBlink ShellのMoshの欄のPortを60000に指定すれば終わり。
- `$ mosh <Host>`で繋がるはず。

# SCP

## リモートからダウンロード（アップロードは逆）
### ファイルの場合
```
scp <Host>:~/ .
```
### ディレクトリの場合
[-r; 再起オプションが使えない](https://github.com/blinksh/blink/issues/565)ので圧縮して送る

``` 圧縮側.
tar czf <Compressed_filename> <filename>
scp <Host>:<Compressed_filename> .
```
``` 解凍側.
tar xf <Compressed_filename>
```
MIT Open CoursewareのPerformance Engineering of Software Systemsをやっていく(5)

MIT Open CoursewareのPerformance Engineering of Software Systemsをやっていきます。

以下のサイトから試聴できます。

https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-172-performance-engineering-of-software-systems-fall-2018/

Lecture１を要約していきます。

#コンピュータのパフォーマンスより重要なものは何か
コンピュータのパフォーマンスより重要なものはたくさんあります。パフォーマンスはコンピュータにおいての最優先事項ではありません。以下にリストします。

* 互換性
* 機能性
* 信頼性
* 正確性
* メンテナンスが可能であること
* 頑丈であること（Robustness)
* 明快であること
* 部品として再利用可能であること
* テスト可能であること
* デバッグ可能であること
* 移動可能であること
* 有用であること

プログラマはこれらの特性のために、しばしばパフォーマンスを犠牲にします。では、なぜ我々はパフォーマンスを研究するのか。それは以下の理由によります。

#パフォーマンスはコンピューティングにおいての通貨である。

つまり、これらの特性をパフォーマンスという通貨によって買うことができるからです。パフォーマンスによってシステムをセキュアにすることができる。パフォーマンスが劣化することによって、これらの特性が劣化します。
水は人間にとって本質的に重要であり、１００ドルは本質的に重要でありませんが、１ドルで水を買うことができます。パフォーマンスにおいても同じアナロジーが適応できます。
初期のコンピューティングにおいては、パフォーマンス工学は一般的でした。なぜなら、コンピューティング資源が限られていたからです。コンピュータは３３kHzのCPUを積んでいました。（今は２Ghzから4Ghz)

ここで、この時代からの名言を書いておきます。

未熟な最適化は邪悪の根源だ(Donald Knuth)
多くのコンピューティングの罪が他の理由よりまず効率化の名の下に行われてきた（それは達成されないこともある）。それは、闇雲な愚かさを含む（William Wulf)
プログラムの最適化の最初のルール：それをするな。二番目のルール：エキスパートのみだ。まだそれをするな（Michael Jackson)

結局、コードを速く、さらに読みやすくするのは技術がいるということですね。

ムーアの法則により、トランジスタ数はどんどん増えています。２００４年ぐらいまでは、クロックスピードも増えていました。なので、ソフトウェアの速度を上げたければ、時間を待てば速度は上がっていっていました。
ただ、２００４年以降、クロックスピードが増えなくなっていきました。しかし、トランジスタ数や密度は増えていきます。
クロックスピードが上がらなくなった理由の一つに、排熱の問題があります。排熱は一定量しかできないので、クロックスピードを上げれば熱はこもります。
漏れ電流の熱も大きくなっていきます。
そこでベンダーはどうしたか、トランジスタはたくさん使えるが、速く動かすことはできない。
そこで、マルチコアプロセッサの誕生です。
そして、CPUのコア数は増えていくことになりました。
ムーアの法則により、コンピュータのパフォーマンスは向上する。しかし今や、パフォーマンスは複雑なキャッシュ階層と広いベクトルユニット、GPU、FPGAを持つ、大きなマルチコアのプロセッサのことになりました。
よって、ソフトウェアはこのハードウェアを効率的に使うために適応する必要があります。

パフォーマンス最適化の仕事はどんどん増えているようです。ある生徒が6172個の仕事のうち、５個を実際にやったようです。なので、仕事は結構あるようです。（Qiitaにパフォーマンス最適化の記事がほとんどないのもあんまりこの仕事がエンジニアを魅了してないのを示しているようです）

現代のプロセッサはとても複雑です。現代的なマルチコアのプロセッサは並列プロセッシングコア、ベクトルユニット、キャッシュ、GPU、ハイパースレッディング、動的周波数スケーリングを含みます。
では、どのように書けば現代的なハードウェアを効率的に書けるのでしょうか？

次の章から、行列演算で例を示していきます。

ではまた次回
Cloud RunでnltkライブラリがインストールされたDockerコンテナをデプロイする方法

Cloud RunでnltkライブラリがインストールされたDockerコンテナをデプロイしようとしてハマったのでメモ。

# 事象

以下のように、`Dockerfile`に`nltk`ライブラリをインストールするよう記述し、Cloud RunでDockerコンテナをデプロイしようとするとエラーが発生します。

```:Dockerfile
RUN pip install nltk
RUN nltk.download('punkt')
```

```:error
2019-12-23 14:02:28.321 PDT Resource [93mpunkt[0m not found.
2019-12-23 14:02:28.321 PDT Please use the NLTK Downloader to obtain the resource:
2019-12-23 14:02:28.321 PDT
2019-12-23 14:02:28.321 PDT [31m>>> import nltk
2019-12-23 14:02:28.321 PDT >>> nltk.download('punkt')
2019-12-23 14:02:28.321 PDT [0m
2019-12-23 14:02:28.321 PDT For more information see: https://www.nltk.org/data.html
2019-12-23 14:02:28.321 PDT
2019-12-23 14:02:28.321 PDT Attempted to load [93mtokenizers/punkt/PY3/english.pickle[0m
2019-12-23 14:02:28.321 PDT
2019-12-23 14:02:28.321 PDT Searched in:
2019-12-23 14:02:28.321 PDT - '/home/nltk_data'
2019-12-23 14:02:28.321 PDT - '/usr/local/nltk_data'
2019-12-23 14:02:28.321 PDT - '/usr/local/share/nltk_data'
2019-12-23 14:02:28.321 PDT - '/usr/local/lib/nltk_data'
2019-12-23 14:02:28.321 PDT - '/usr/share/nltk_data'
2019-12-23 14:02:28.321 PDT - '/usr/local/share/nltk_data'
2019-12-23 14:02:28.321 PDT - '/usr/lib/nltk_data'
2019-12-23 14:02:28.321 PDT - '/usr/local/lib/nltk_data'
2019-12-23 14:02:28.321 PDT - ''
```
errorメッセージを読むと、「`nltk`ライブラリのダウンロード先を探してみたけど見つからない！」と言っているようです。
`Dockerfile`で`nltk`ライブラリをインストールしているにも関わらず不思議なエラーです。

# 原因
以下でヒントが述べられています。
https://stackoverflow.com/questions/58654672/after-adding-nltk-downloadwords-google-cloud-run
どうやら、`nltk`のインストール方法には以下の3つが存在していて、App EngineやCloud Runで動作させるためには、Manual installationが必要とのこと。

- Interactive installer
- Command line installation
- Manual installation

`nltk.download()`はInteractive installer(GUIを使う)なのでApp EngineやCloud Runで動作しなかったようです。

# 解決策
Dockerfileに以下を追記することでnltkライブラリを使えるようになりました。

```
# for install wget
RUN apt-get update && apt-get install -y wget

# for NLTK manual download
WORKDIR /usr/local/nltk_data/tokenizers
RUN wget "https://raw.githubusercontent.com/nltk/nltk_data/gh-pages/packages/tokenizers/punkt.zip" -O punkt.zip
RUN unzip punkt.zip
```
API Gatewayのlamdba連携時の引数のやり取りについて

API-Gatewayとlambdaで引数のやり取りする場合は、全部Stringで渡されるんだね。よく考えたら、QueryParameterの場合もあるし、JSONでやり取りするとは限らないか。

なので、

```request.json
{
  "user_id": "string",
  "lang": "string",
  "args": {
    "name": "string",
    "keyWord": "string"
  }
}
```

こんな感じのjsonをAPI-Gatewayに対してPOSTする場合、lamdba側では、以下のような処理を行う必要がありますね。

```python:sample.py
def lambda_handler(event, context):

    # request bodyはstringなので、jsonに変換する
    body = json.loads(event["body"])
    # こんな感じにすると、user_idが取得できる。
    user_id = body["user_id"]
```
こうしないと、lambda側で、`TypeError: string indices must be integers`になります。

またこれは応答時も同様で、JSONはAPI-Gatewayが受け取れないことから、json.dumpsする必要がありますね。

```python:sample.py
    return {
        'statusCode': 200,
        'body': json.dumps({
            'result': result,
            'error_code': error_code,
            'error_message': message})
        }
```
 こっちはAPI-Gateway側で、`Execution failed due to configuration error: Malformed Lambda proxy response`になりますね。
https://aws.amazon.com/jp/premiumsupport/knowledge-center/malformed-502-api-gateway/
gulpでコンパイルしたCSSの改行コードをLFからCRLFにする

#はじめに
タスクランナー(gulp)でscssをコンパイルした所、cssの改行コードがLFに切り替わってしまうという事案が発生し、色々と検索をかけてもなかなかヒットしなかったので、今後同じようなことが起こった時用の備忘録です。（備忘録しか書いていない気がする）

#インストールするnpm
##gulp-load-plugins

gulp-からはじまるnpmパッケージを簡素化してくれます。
 `require()`ばっかりにならなくて済みますね。
https://www.npmjs.com/package/gulp-load-plugins

##gulp-line-ending-corrector
これは参考文献がなかなかに少ないのですが、改行コードを変更できるnpmパッケージという解釈です。
※いまいち良くわかってない
https://www.npmjs.com/package/gulp-line-ending-corrector

#記述方法
 ```
const plugins = require('gulp-load-plugins')();
```

で`gulp-load-plugins`を読み込みます。

あとはgulpfile.jsのscss監視下の`task`配下に

```
.pipe(plugins.lineEndingCorrector({
  verbose: false,
  eolc: 'CRLF'
}))
```
MixPanelのデータをGASを使って取得する方法

MixPanelはサクサク動くし、分析もかゆいところに手が届くのでとても好きだが
他データソースのものと組み合わせて使おうとして躓いたのでメモ

# MixPanelで取得したPVを他のデータソースと横断して分析したい


サービスを取り巻くデータは下記のように色々なものがある

- アプリケーションのDB
- SalesForce
- Firebase
- その他SendGridなどのSaaSなど

これとかを見る限りだと、基本的には全てBigQueryに突っ込んでそこから見るというのがベストプラクティス化しているように感じている

[近年のデータ分析基盤構築における失敗はBigQueryを採用しなかったことに全て起因している](http://uma66.hateblo.jp/entry/2019/10/17/012049)

ということでMixPanelの情報もBigQueryに入れようとしたが、どうやら有料のサービスを使わないといけないらしい

https://mixpanel.com/data-pipeline/

[Segment](https://segment.com/unified-customer-data/) とかも注目していたので試してみたが、出力のみで、Mixpanelの情報を取得するということとかはできなさそう、定番のZapierも同じ

どうやらMixPanelは貯まったデータを取得する部分は弱いらしい

# 結局どうしたか
結局見たいデータがピンポイントだったのでGoogle App Scriptをスケジュール実行して
スプレッドシートに出力。そいつをredashで見に行くようにした

redashをspreadsheetの連携については下記が参考になる
[Redash と Google Spreadsheet を連携する](https://qiita.com/moaikids/items/157ec44ead7ec8d2d731)

```javascript

function fetchPV() {  
  
  
  var today = new Date();
  
  var fromDate = Utilities.formatDate(new Date(today.getFullYear(), today.getMonth()-2, 1), 'Asia/Tokyo', 'yyyy-MM-dd')
  var toDate = Utilities.formatDate(new Date(today.getFullYear(), today.getMonth()+1, 0), 'Asia/Tokyo', 'yyyy-MM-dd')
  var data = {
      'params'    : '{"from_date":"' + fromDate + '","to_date": "' + toDate + '"}',
      'script'    : 'function main(){return Events(params).filter(function(event) { return event.name == "PageView" }).groupBy(["properties.orgId"], mixpanel.reducer.count()).sortDesc("value")}'
    }
  Logger.log(data)
    var options = {
      "method": "GET",
      "headers" : {"Authorization" : "Basic " + Utilities.base64Encode(PropertiesService.getScriptProperties().getProperty('access_key'))},
      "payload": JSON.stringify(data)
    };

    var url = "https://mixpanel.com/api/2.0/jql"
    var response = UrlFetchApp.fetch(url, options);  

    if (!response) {
      Logger.log("no response");
      return;
    }
  　var json = JSON.parse(response);  
  var spreadsheet = SpreadsheetApp.openById("");
  var sheet = spreadsheet.getSheetByName("");
  sheet.clearContents();
  sheet.getRange(1,1).setValue("org_id");
  sheet.getRange(1,2).setValue("pv_recent_3_month");

  
  for (var i=0; i<json.length; i++){   
    sheet.getRange(i+2,1).setValue(json[i].key);
    sheet.getRange(i+2,2).setValue(json[i].value);
  }
}
```

MixPanelは検索条件やデータの見え方とかをGUIで設定したreportという機能があって
それをexpoertとかもできるため、最初はそれを使おうとしたものの
どうやら、JQLをHTTP Requestとして渡すのが一番早そうだということに気づき、このやり方でやってみた

同じようなことをやろうとしている方の参考になれば

類似サービスのGoogle AnalyticsだとMixPanelに比べて分析機能は弱いと感じる一方、他サービスとの連携については圧倒的。
割り切って２箇所に飛ばして、MixPanelでの分析、外部サービスとかとの連携はGoogle Analytics使うとかも一案だと思った
ガントチャート作成ツール「がんすけ」をMacで動かす

この記事は[Digital Identity Creative Div. Advent Calendar 2019](https://adventar.org/calendars/4714)の24日目です。

ガントチャート描いてますか？ディレクターの必須要件である「**進捗管理**」を行うには、エクセルから始まるスケジュール作成の試練が待っています。**ページ数が多いサイトや、外部サービスや他サービスとの連携、チームの稼働管理など、スケジュールを管理する人がいることでプロジェクトがスムーズに進む事が多い**でしょう。

## スケジュール管理にはガントチャート

多くの進捗管理ツールには、カレンダー表示やガントチャート機能が備わっています。これらは時系列で情報を可視化することができ、ぱっとひと目で状況を把握できる優れた機能です。なかでもガントチャートは、人気のBacklogやTrello、Redmineなどにも搭載され、馴染み深いものになりつつあります。

## 依存関係を作れるガントチャートがとにかくオススメ

https://qiita.com/2nose/items/f64904e887a47844eb92 でも書きましたが、**変更管理に強いツールが最も重要**です。作って終わりにならないためには、更新できる・変更できることの敷居をさげる必要があります。

依存関係を作れるガントチャートの場合、先行タスクのスケジュールが伸ばした場合、後方タスクも起点日が伸びます。このように自動でチャートが動くことで、チマチマと動かす作業がなくなり、サクサクと管理できるようになります。

## Windowsでおすすめしたい「がんすけ2」は、入門用のガントチャートツールとしてオススメ

がんすけ2というツールをご存知でしょうか？ [がんすけ2](http://www.gansuke.com/)
Windowsで動作するフリーウェア・シェアウェアのガントチャートい作成ツールです。
![ガントチャート がんすけ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237054/682f5428-a871-6326-8a16-716bd587cb05.jpeg)

> 「がんすけ」の特徴
> 「がんすけ」は、ガントチャートで表現されるスケジュール表を作成するソフトです。カレンダー上にマウスでチャートを配置して、スケジュール表を作成します。配置したチャートはマウスで移動させたり長さを変えることができますので、予定の変更もとても簡単です。
> カレンダー表示単位はワンタッチで１日～２年間の範囲で切り替え可能なので短期、長期の複数の視点で計画が立てられます。
「がんすけ」のデータは高い汎用性をもつデータ交換フォーマットとして普及してきたXMLで保存されます。XMLを扱える他のアプリケーションでのデータの活用など、さまざまな方法で再利用が可能です。また、任意のXSLを指定をすることも出来ます。```

マウスでグリグリできるガントチャートという印象ですが、インストール型のアプリらしく、立ち上がってからの安定感ある動き、**印刷時のきれいなレイアウト**など、なかなか味わい深いアプリなので。印刷がきれいというのは、客先に提出する資料としては非常に優れていますよね。見づらいスケジュール表は、なかなか状況が見えづらくなりがちです。

とにかくフリーウェアもあるので、Windowsユーザーの方はぜひ一度利用してみてください。

## Macでがんすけを動かす

MacでもWindowsアプリを動かす方法はいくつかあります。今回は、Wineで動かしてみました。
![WineHQ - Run Windows applications on Linux  BSD  Solaris and macOS.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237054/d7791c69-b532-a062-3d5d-1fa607063ded.jpeg)
Wineのサイト。右側にDownloadがある。

[Mac版のWineダウンロードページ](https://dl.winehq.org/wine-builds/macosx/download.html)
できるだけ最新版をインストールしましょう。

まずはWineをインストールします。ダブルクリックでインストールできますので、詳細は割愛します。

次に、がんすけをダウンロードしましょう。
[がんすけ](http://www.gansuke.com/)
対応OSがWindowsになっていますが、気にせずダウンロードします。

ZIPファイルを解凍すると、WineアイコンのSetup.exeが見えるようになります。
![スクリーンショット 2019-12-24 17.01.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237054/d2de0d10-dcc7-d0a3-50a7-016b9a6b0647.png)

Setup.exeをダブルクリックします。
![スクリーンショット 2019-12-24 17.01.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237054/5e14b9de-4659-b5e8-33eb-8bf0561e4bc2.png)
おなじみのWindowsのアプリインストール画面が表示されます。あとは画面に従ってインストールしましょう。

これでインストールは完了です。

## Wineでがんすけを動かす！

<img width="1433" alt="スクリーンショット 2019-12-24 17.32.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237054/93a8704a-4f2c-7833-f57e-c4c90330a9a6.png">
Wineを使ってがんすけでかんたんなガントチャートを作成

**依存関係をもたせたチャートもかんたんに作成でき、タブで期間を変更して俯瞰しながら負荷情報をみる**こともできます。実は、**負荷状況は別途グラフに表示される**ので、そこでも確認ができます。

Web系の案件にあっているかというとそうでもないのですが、業界問わずで利用できるのがガントチャートの良いところ。**がんすけはIT系というよりは、現場の工程管理をかんたんに可視化できるツールのイメージが強い**です。そしてなにより、とても使いやすいです。

今回はWineで動かしましたが、やっぱりWindows機で動かすのが一番いいですね。文字もきれいに出るし。

## 最後に

最近はクラウドサービスがほとんどなので、PCにアプリをインストールすることも少なくなりました。しかし、外出が多い人はネット環境がないと動かないアプリよりも、ローカルにインストールするほうがメリットがあるケースもあります。

使用するアプリも、ケースバイケースで使いこなせるといいですね。

明日は、おまつさんです。
シンボリックリンクと遊んだメモ

## 概要

シンボリックリンクに遊ばれたのでメモ。

## シンボリックリンクが中に入っちゃう

以下実行した時、

```bash
$ ln -s /home/dir dir 
```

`dir` ディレクトリが既に存在している時に実行すると、 `dir` の配下に `/home/dir` のシンボリックリンクが生成されてしまう。

## シンボリックリンクの削除

`rm -rf dir` では削除出来ない。
シンボリックリンクはディレクトリではないからです。

```bash
$ rm dir
```

でもこちらを使いたい( `rm` はおっかないので)。

```bash
$ unlink dir
```

## シンボリックリンク元ディレクトリよりも上にある.htaccess


無視されるそうです。

先に知れたため、未遂に終わりました。

## おわり

デプロイ、CI環境の構築を通してシンボリックリンクに遊ばれました。
ひやひやした場面もあったので、なんとなくでコマンド打たないよう気をつけようと思います。
Serverless FrameworkでAPIに対してProtocol Bufferを適用して作ってみる。

# TL;DR

Serverless Frameworkでもう少しAPI周りをなんとか扱いたい気持ちがあり、Protocol Bufferでお試ししたことがあったのでそれを共有します。

# Protocol Bufferとは
https://developers.google.com/protocol-buffers

そんなに新しい技術ではないんですが、インタフェース記述言語（IDL）です。Googleにて開発され、元はXMLよりも高速になるようデザインされたようです。
よくProtobufと略して記載されていたりします。
Protocol Bufferに関してはこちらの記事でよくわかりやすくサマらているのでご参考までに。
https://qiita.com/yugui/items/160737021d25d761b353

# なぜServerless FrameworkにProtocol Bufferを使う？

もともとServerless Frameworkを主体にサービスを構築して管理していたため、クライアント側がマルチに存在する場合に使用を共有できるようにしたいのが最初のモチベーションで、同じAPIをWeb,Native Appからアクセスすることが予想されるサービスや、センサーデータをまとめて送るにしても、通信量が大きいのでなんとかデータを圧縮できないかと考えていたので、検討しました。

# サンプル

https://github.com/hisato-kawaji/protocol-buffer-with-serverless-sample

# やること
LambdaのコードをPythonを前提としてAPI Gateway + Lambdaだけのサービスをやってみました。
(Serverless Frameworkの基礎的な内容は割愛して、Protocol Bufferにまつわるところに絞った話を記載します。)

## pluginの追加

pluginに`serverless-python-requirements`と`serverless-apigw-binary`を追加します。

```
sls plugin install --name serverless-python-requirements
sls plugin install --name serverless-apigw-binary
```

`serverless.ymlにも記載しておきます。`

```yml
plugins:
  - serverless-python-requirements
  - serverless-apigw-binary
```

```yml
custom:
.
.
.
  apigwBinary:
    types:
      - 'application/x-protobuf'
```

## requierement.txt
Lambda上でProtoBufを扱うので、protobufをimportする必要があります。
というわけで、requirement.txtを作ります。

```
protobuf==3.5.1
six==1.11.0
```

## スキーマ作成

事前にprotobufをインストールしておきます。

```shell
git clone git://github.com/openx/python3-protobuf.git
cd python3-protobuf
./autogen.sh
./configure --prefix=$PREFIX # protobuf インストール先を指定
make
make check
sudo make install

cd python # Python バインディング
python setup.py build
python setup.py test
sudo python setup.py install
```

`.proto`ファイルを作って、スキーマを定義していきます。

```proto:sample.proto
syntax = "proto3";

message Test {
  string test_id = 1;
  string hoge = 2;
}
```

スキーマを作成したら、ビルドです。

```shell

protoc -I=. --python_out=. sample.proto
```

コマンド実行後、`sample_pb2.py`が生成されます。

## Lambda Functionの実装
`serverless.yml`に関数を記載します。

```
functions:
  Get:
    handler: handler.get
    package:
      include:
        sample_pb2.py
      exclude:
        - serverless.yml
    events:
      - http:
          path: get
          method: post
          cors: true
          private: true
```

`handler.py`を用意して実際にProtoBufを組み込んでいきます。bodyにProtocolBufferでSerializeされたデータを与えて、LambdaにてParseすれば扱えるようになります。
Responseで返す場合はSerializeしてstringで扱ってあげればレスポンスできます。

```
mport json
import sample_pb2
import base64

def get(event, context):
    obj = sample_pb2.Test()
    obj.ParseFromString(base64.b64decode(event['body']))
    obj.test_id = 'bbb'
    response = {
        'statusCode': 200,
        'headers': { 
            "Access-Control-Allow-Origin": "*",
            'Content-Type': 'application/x-protobuf' 
        },
        'body': obj.SerializeToString().decode('utf-8'),
        'isBase64Encoded': True
    }

    return response
```

# あれ？簡単？
Protocol Bufferの扱いに慣れるのには苦労しましたが、組み込み自体はさほど時間がかかりませんでした。どちらかというとスキーマ定義した後にPython上で扱う際Lambdaでデバッグする作業がなかなか苦痛でした。

# まとめ・展望

* ProtoBufをServerless Frameworkで実現できるようにしてみました。

ありがとうございました。
ローカルのPostgreSQLをHerokuPostgresにリストアしようとして失敗し続けた

SQLを全然覚えてないから全部「DBeaver」任せでデータベースをいじってます。
CUIクライアント最高～！

と、そんな中、ローカルのPostgreSQLデータベースを、HerokuPostgreSQLにインポートしようと思ったら、かなり手こずったので記録に残します。

##インポート手順
HerokuPostgreSQLの導入と、ローカルからのインポートに関しては、
こちらの記事が参考になります。
[Heroku Postgres を利用してみよう](https://qiita.com/shosho/items/5ebabf11efb1f3b604f7)
[Herokuの公式ドキュメント](https://devcenter.heroku.com/articles/heroku-postgres-import-export#import-to-heroku-postgres)


##つまった個所
```powershell
heroku pg:backups:restore '<SIGNED URL>' DATABASE_URL
```
上記のリストアを試みたときにおこったエラー達。

ちなみにDATABASE_URLは実際のURLを使わず、そのままでも可能。
（一応、URLは「heroku config」で確認できます。）

###バックアップが見つからない
####エラー内容
```powershell
 !    Backup 'dumpファイルをアップロードしてる場所のURL' not found for ⬢
 !    アプリ名
```
####解決法
**Windowsではダブルクオーテーションを使う。**
[参考](https://stackoverflow.com/questions/43318429/heroku-pgbackupsrestore-from-public-url-backup-not-found/44710684#44710684)


###読み込み時エラー①
####エラー内容
```powershell
pg_restore -F c -d dbname dump.backup
pg_restore: [archiver] did not find magic string in file header
```
不適切な形式でdumpファイルが作成されているときに表示されるエラーらしい。
詳しくは[こちら](https://help.heroku.com/F5367R6T/magic-string-errors-while-attempting-to-restore-a-postgres-backup)

####解決法
**PowerShellを使わない。**

不適切なdumpファイルということには、思い当たる節はありました。
というのもpg_dumpを行った際に、下記の警告がたくさん表示されていたので…

```powershell
pg_dump: [カスタムアーカイバ] 警告: ftellで想定位置との不整合がありました -- ftellが使用されました
```
PowerShellでは、PostgreSQLのpg_dumpやpg_restoreは行えないようです。
[参考](https://landhere.jp/blog/a136.html)

<h3>読み込み時エラー②</h3>

####エラー内容
```powershell
Restoring... !
 !    An error occurred and the backup did not finish.
 !
 !    pg_restore: [custom archiver] could not read from input file: end of file
 !    pg_restore finished with errors
 !    waiting for download to complete
 !    download finished with errors
 !    please check the source URL and ensure it is publicly accessible
 !
 !    Run heroku pg:backups:info r007 for more details.
```

####解決法
分かりませんでした。

「pg_restore: [custom archiver] could not read from input file: end of file」って
ググって出てきたものを色々試してみたのですが、どうにもなりませんでした。

分かる方がいれば、教えていただけますとありがたいです。
「end of file」だから、おそらく改行コード周りっぽいんですが辿り着けず…

<h1>実際にリストアできた手順</h1>
こちらの下記の手順でリストア自体は行えました。
[https://stackoverflow.com/questions/36240600/cant-pg-restore-on-heroku-could-not-read-from-input-file-end-of-file](https://stackoverflow.com/questions/36240600/cant-pg-restore-on-heroku-could-not-read-from-input-file-end-of-file)

![コメント 2019-12-24 173804.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241763/f1c66cad-57d4-6ab1-8dad-bef60a88b73a.png)

カレントディレクトリ（リポジトリ）に作成したdumpファイルをそのままロードしたら行けた…
Amazon S3もGoogleドライブも何も使わずいけちゃっていいの…？

更新する都度、データベースをリセットして最新のdumpファイルを当てていく。

```powershell
heroku pg:reset DATABASE
pg_dump --no-owner -U ユーザー名 データベース名 > mydb.dump
heroku pg:psql < mydb.dump
```
SwiftUIからStoryboardを表示させる その2

# Storyboardを直接呼ぶ方法

> 利用方法は ?

- 新規でプロジェクト名はお好みで?
- User Interface: SwiftUIにして作成してください

# 新規プロジェクトが作成できたら?

> Storyboardを作成してください
>作成したStoryboardのViewの背景色とかを変えるとわかりやすいかも?

- 「Main.storyboard」と命名して作成します
- 「Main.storyboard」のCustom ClassのClassは「Viewcontroller」
- 「Main.storyboard」のIdentityのStoryboard IDは「idMain」

# Storyboardの設定が終わったら?

- ContentView.swiftを入れ替える


# ContentView.swift


```ContentView.swift

//
//  ContentView.swift
//  SwiftUIView
//
//  Created by 福田 敏一 on 2019/12/24.
//  Copyright © 2019 株式会社パパスサン. All rights reserved.
//

import SwiftUI

struct ContentView: UIViewControllerRepresentable {

    typealias UIViewControllerType = ViewController
    
    func makeUIViewController(context: Context) -> ViewController {
        
        let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
        let nextView = storyboard.instantiateViewController(withIdentifier: "idMain") as! ViewController
        nextView.modalPresentationStyle = .fullScreen
print("1-20・通過・makeUIViewController・")
          return nextView
        }
    
    func updateUIViewController(_ uiViewController : ViewController, context: Context) {
print("3-25・通過・updateUIViewController・")
    }
}

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

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
print("2-40・通過・ViewController")
    }

}

// 実行結果

1-20・通過・makeUIViewController・
2-40・通過・ViewController
3-25・通過・updateUIViewController・

```


# 私の感想と意見ですが ?

SwiftUIの使い方が? だんだんと? 理解が深まりました
なんとか「struct ContentView」からStoryboardを呼べないか? 試行錯誤してここまで辿り着きました? しかし、変な挙動なんですよね? 何がって? Storyboardで作成したMain.storybardのViewの背景色を変えると背景色は上部の時計とかがあるエリアまで指定した色になるのですが? SwiftUIで作成してMain.storyboardを追加した場合、Viewの背景色を赤にしても上部の時計の部分が白のままなんですよね? nextView.modalPresentationStyle = .fullScreenでは解決しないのでしょうか? これではまだまだ、理解が深まっていませんね? すぐに解決してみます、諦めない、諦めません?


ここまで
enebularのInfoMotionを使用して既存データを可視化してみた

# 今回やったこと

[enebular](https://www.enebular.com/ja/)の[InfoMotion](https://docs.enebular.com/ja/InfoMotion/Introduction.html)機能を使用して以前に公開した[Raspberry Pi Zero で自律飛行ドローンを作るぞ（第4回：気圧センサで高度を維持させる）](https://qiita.com/shigeru-yokochi/items/2264be3180272c9db262)でグラフ表示しているフライトデータを同じように可視化してみました。


# 今回のスコープ

- 計測結果をリアルタイムで可視化したいところですが、まずは既存のデータで同じような表示ができることを確認することにします。

# 手順

今回は[enebular-agent](https://docs.enebular.com/ja/EnebularAgent/Overview.html)をAWS EC2上にインストールして実施しましたので、その手順となります。
（EC2は全てt3a.microインスタンスを使用しています）

１．enebular-agentはAWS EC2(debian)上に[インストール](https://docs.enebular.com/ja/EnebularAgent/Installation.html)
２．csvファイルをenebular-egent上のnode-redでreadするフローを作成するため、[enebular editor](https://docs.enebular.com/ja/EnebularEditor/) を enebular-agentと同一ネットワークセグメント上にEC2(Windows2016server)にインストール
３．EC2(Windows2016server)にenebular editorを[インストール](https://docs.enebular.com/ja/EnebularEditor/)
４．EC2(Windows2016server)上のenebular editor から[remote mode](https://docs.enebular.com/ja/EnebularEditor/RemoteMode.html)でEC2(debian)上のenebular-agentに接続
５．[InfoType](https://docs.enebular.com/ja/InfoMotion/InfoTypeIntroduction.html)は[line-chart](https://docs.enebular.com/ja/InfoMotion/SampleInfoTypes.html)を使用する。InfoTypeに合わせたjson形式に変換するようにフローを作成
６．書き込み先の[Data Sources](https://docs.enebular.com/ja/InfoMotion/CreateDataSource.html)は[Firebase](https://docs.enebular.com/ja/infomotion/datasource/firebase/setup)とする
７．フローを実行してFirebase上にデータを書きむ
８．InfoMotionにてline-chartを表示

全体のイメージ図
![qiita-infomotion.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146154/7b7eef9d-800a-0a5e-9e39-9d3e3cd74691.png)


# フライトデータcsvファイル

![data.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146154/5c62c926-65ba-c1a5-85d0-efd4c6dbf1ad.png)

# 作成したフロー


![flow.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146154/1faaca48-711b-57a8-5c9b-c3dd26a9fb68.png)


# InfoMotionでline-chart表示結果



![infomotion.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146154/79821203-9619-3a00-acda-ec41e6c0d5df.png)

###  （参考）元のグラフ

![https___qiita-image-store.s3.amazonaws.com_0_146154_2f1792fb-79a8-e75a-9a61-2c0c2904e9ee.jfif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146154/dda0960c-ce31-a869-2061-91f43f2d08f4.jpeg)



# まとめ（感想）

- InfoMotionで表示したグラフと元のグラフの違いはないことが確認できました。（yx軸は自由に伸縮できるので問題ないです）
- リアルタイム表示が確認できればなにかと便利に使えそうな気がします。
- 次回はドローン本体にenebular-agent をインストールしてリアルタイム可視化ができるか確認してみたいと思いますが、直接FirebaseにInfoTypeのデータ形式で書き込んでも実現できそうなのでインストールしないかも。。enebular-agent-lightとかリソースをあまり使わないagentがあると嬉しいかも。。。。
- 今回初めて実データでInfoMotionを使用しましたが、思った通りに表示するまで苦労しました。もっと簡単な方法があれば教えてほしいです！
GMailで設定できる言語一覧

GMail用のChrome拡張を多言語化しようと、GMailで設定できる言語を調べました。

GMail上では現地語で表示されるので、日本語との対応もつけました。
Chromeストア上での説明などは、i18nのコードを使い、Chrome拡張ではhtmlタグのlang属性をみて言語を変更しています。

[GMailSend Address Checker \- 誤送信防止 \- \- Chrome ウェブストア](https://chrome.google.com/webstore/detail/gmailsend-address-checker/gdckkpniogfhndklmlgbnolnkbceeofp)

## リスト

※i18nで使うコードは確認したものだけ記載しています。(追加していく予定)


| html lang属性 | GMail設定 | 日本語名称 | 向き | i18n | 
| --- | -----------| --- | --- | --- | 
| af | Afrikaans | アフリカーンス語 |  | 
| az | Azərbaycanca | アゼルバイジャン語 | | 
| id | Bahasa Indonesia | インドネシア語 | | 
| ms | Bahasa Melayu | マレー語 |  | 
| ca | Català | カタルーニャ語、バレンシア語 |  | 
| cs | Čeština | チェコ語 |  | 
| cy | Cymraeg | ウェールズ語 |  | 
| da | Dansk | デンマーク語 |  | 
| de | Deutsch | ドイツ語 |  | de | 
| et | Eesti keel | エストニア語 |  | 
| en-GB | English (UK) | 英語 |  | 
| en | English (US) | 英語 |  | en-US |
| es | Español | スペイン語 |  | 
| es-419 | Español (Latinoamérica) | スペイン語 |  | 
| eu | Euskara | バスク語 |  | 
| fil | Filipino |  |  | 
| fr | Français | フランス語 |  | 
| fr-CA | Français (Canada) | フランス語 |  | 
| ga | Gaeilge | アイルランド語 |  | 
| gl | Galego | ガリシア語 |  | 
| hr | Hrvatski | クロアチア語 |  |  
| it | Italiano | イタリア語 | | 
| zu | IsiZulu | ズールー語 |  | 
| is | Íslenska | アイスランド語 |  | 
| sw | Kiswahili | スワヒリ語 |  | 
| lv | Latviešu | ラトビア語 |  | 
| lt | Lietuvių | リトアニア語 |  | 
| hu | Magyar | ハンガリー語 |  | 
| no | Norsk (Bokmål) | ノルウェー語(ブークモール) |  | 
| nl | Nederlands | オランダ語 |  | 
| pl | Polski | ポーランド語 |  | 
| pt-BR | Português (Brasil) | ポルトガル語 |  | 
| pt-PT | Português (Portugal) | ポルトガル語 |  | 
| ro | Română | ルーマニア語、モルドバ語 |  | 
| sk | Slovenčina | スロバキア語 |  | 
| sl | Slovenščina | スロベニア語 |  | 
| fi | Suomi | 	フィンランド語 |  | 
| sv | Svenska | スウェーデン語 |  | 
| vi | Tiếng Việt | ベトナム語 |  | vi |
| tr | Türkçe | トルコ語 |  | 
| el | Ελληνικά | ギリシア語 |  | 
| bg | Български | ブルガリア語 |  | 
| mn | Монгол | モンゴル語 |  | 
| ru | Русский | ロシア語 |  | 
| sr | Српски | セルビア語 |  | 
| uk | Українська | ウクライナ語 |  | 
| hy | Հայերեն | アルメニア語 |  | 
| iw | ‫עברית‬‎ | ヘブライ語 | ← | 
| ur | ‫اردو‬‎ | ウルドゥー語 | ← | 
| ar | ‫العربية‬‎ | アラビア語 | ← | 
| fa | ‫فارسی‬‎ | ペルシア語 | ← | 
| ne | नेपाली | ネパール語 |  | 
| mr | मराठी | マラーティー語 |  | 
| hi | हिन्दी | ヒンディー語 |  | 
| bn | বাংলা | ベンガル語 |  | 
| gu | ગુજરાતી | グジャラート語 |  | 
| ta | தமிழ் | タミル語 |  | 
| te | తెలుగు | テルグ語 |  | 
| kn | ಕನ್ನಡ | カンナダ語 |  | 
| ml | മലയാളം | マラヤーラム語 |  | 
| si | සිංහල | シンハラ語 |  | 
| th | ภาษาไทย | タイ語 |  | 
| lo | ພາສາລາວ | ラーオ語 |  | 
| my | မြန်မာဘာသာ (Myanmar language (Burmese)) | ビルマ語 |  | 
| ka | ქართული | グルジア語 |  | 
| am | አማርኛ (Amharic) | アムハラ語 |  | 
| chr | ᏣᎳᎩ (Cherokee) |  |  | 
| km | ភាសាខ្មែរ | クメール語 |  | 
| zh-HK | 中文 (香港) | 中国語(香港) |  | 
| zh-TW | 中文 (繁體) | 中国語(繁体字)台湾  |  | zh-TW | 
| zh-CN | 中文 (简体) | 中国語(簡体字)中国  |  | zh | 
| ja | 日本語 | 日本語 |  | ja |
| ko | 한국어 | 韓国語,朝鮮語 |  | ko | 


## 参考

[ISO 639\-1コード一覧 \- Wikipedia](https://ja.wikipedia.org/wiki/ISO_639-1%E3%82%B3%E3%83%BC%E3%83%89%E4%B8%80%E8%A6%A7)
[サポートされているロケール](https://docs.oracle.com/javase/jp/1.5.0/guide/intl/locale.doc.html)
【Unity】ParticleSytemのCustomDataを使うときの処理をcgincにまとめる

開発環境 : Unity2018.4.3f1

こちらの記事ではUnityのShaderでParticleSystemのCustomDataを利用するときの処理を共通化についてになります。
具体的にはテクスチャのUVスクロールをCustomDataで実現する場合になります。

## cgincで共通のコードを定義
UnityのShaderを書く際に重複コードになりそうな処理をcgincにまとめておくことができます。
今回は次のようなコードを定義しました。

```
#ifndef My_PARTICLE_INCLUDED
#define My_PARTICLE_INCLUDED

// CustomDataのプロパティ設定
#define SET_CUSTOM_DATA_PROPERTY(name) uniform int name##U; \
        uniform int name##USwizzle; \
        uniform int name##V; \
        uniform int name##VSwizzle;
    
// 該当のCustomDataを取得    
#define GET_CUSTOM_DATA(name) half2(customData[name##U][name##USwizzle],customData[name##V][name##VSwizzle])

#endif

```

`SET_CUSTOM_DATA_PROPERTY` は４つプロパティを定義している箇所をまとめています。
`GET_CUSTOM_DATA`はプロパティで設定した値を使ってCustomDataから必要なパラメータを取得しています。

## Shaderで利用する
プロパティ定義する

```
[HideInInspector]_MainU ("_mainucoord", int) = 2
[HideInInspector]_MainUSwizzle ("_mainuswizzle", int) = 0
[HideInInspector]_MainV ("_mainvcoord", int) = 2
[HideInInspector]_MainVSwizzle ("_mainvswizzle", int) = 0		
```

cgincをSubShaderのPassに定義します。

```
#include "my_Particle.cginc"
```

Passにプロパティを定義します。
ここで `SET_CUSTOM_DATA_PROPERTY`を使います。

```
SET_CUSTOM_DATA_PROPERTY(_Main);
```


### UVスクロール
バーテックスShaderでの処理を次のようになります。
`customData1とcustomData2`はCustomDataのストリームです。

```              
half4x4 customData = { v.customCoords1, v.customCoords2, half4(0,0,0,0), half4(0,0,0,0)};
half2 mainCustomCoord = GET_CUSTOM_DATA(_Main);
o.uv.xy = TRANSFORM_TEX(v.texcoords.xy,_MainTex) + mainCustomCoord;
```

## 最後に
cgincに定義をしておけば複数のShaderで使い回すことができますので、共通化して利用できそうな処理があればまとめておくと良いです。