OmniAICreator/Qiita-1.07M huggingface dataset:
[WordPress]管理画面でcsvダウンロード

結構要望が多い機能だと思うが割と情報が無い。
投稿一覧(edit.php)かプラグインでやる。
それぞれに良し悪しあるんで状況によって判断。

### 投稿一覧でやる
バルクアクション（一括操作のプルダウン）に追加する。
ボタン単体でやらせたいけどいい感じのフック見つからずひとまず断念。

追記（2020/03/30）
いい感じのフック見つかる→ manage_posts_extra_tablenav

```php:manage_posts_extra_tablenav
    $format = '
<div class="alignleft actions">
    <button type="submit" class="button" name="action">ダウンロード</button>
</div>';
```


```php:functions.php

add_filter('bulk_actions-edit-member', function ($bulk_actions) {
	$bulk_actions['download'] = 'ダウンロード';
	return $bulk_actions;
});

add_action('load-edit.php', function () {
	$wp_list_table = _get_list_table('WP_Posts_List_Table');
	$action = $wp_list_table->current_action();
	if ( !$action || $action != 'download' ) return;
	check_admin_referer('bulk-posts');
	$row;
	if ( empty($row) ) return;
	$filepath = sprintf('%s.csv', date('YmdHis'));
	if ( touch($filepath) ) {
		$file = new SplFileObject($filepath, "w");
		$file->fputcsv([
				_s('タイトル'),
				_s('作成日'),
		]);
		foreach ($row as $r) {
			$file->fputcsv([
					_s($r['post_title']),
					$r['created'],
			]);
		}
		@header("Pragma: public");
		@header("Expires: 0");
		@header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
		@header("Cache-Control: private", false);
		@header("Content-Type: application/force-download");
		@header("Content-Disposition: attachment; filename=\"".basename($filepath)."\";" );
		@header("Content-Transfer-Encoding: binary");
		@readfile($filepath);
		unlink($filepath);
		die;
	}

});

function _s($val) {
	return mb_convert_encoding($val, 'SJIS-win', 'UTF-8');
}
```

### プラグイン作ってやる
プラグインはあんまり作らなくて諸々知らないので
きっとちゃんとしたやり方があると思われ。

```php:/plugins/{plugin-slug}/{plugin-slug}.php

/*
 * 省略
 */

add_action('init', function () {
	if ( is_admin() && ($_REQUEST['page']??'')=='{menu_slug}' && ($_REQUEST['cmd']??'')=='download' ) {
		$row;
		if ( empty($row) ) return;
		$filepath = sprintf('%s.csv', date('YmdHis'));
		if ( touch($filepath) ) {
			$file = new SplFileObject($filepath, "w");
			$file->fputcsv([
					_s('タイトル'),
					_s('作成日'),
			]);
			foreach ($row as $r) {
				$file->fputcsv([
						_s($r['post_title']),
						$r['created'],
				]);
			}
			@header("Pragma: public");
			@header("Expires: 0");
			@header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
			@header("Cache-Control: private", false);
			@header("Content-Type: application/force-download");
			@header("Content-Disposition: attachment; filename=\"".basename($filepath)."\";" );
			@header("Content-Transfer-Encoding: binary");
			@readfile($filepath);
			unlink($filepath);
			die;
		}
	}
});
```
PriceSeriesProviderクラス


```EasyLanguage
using tsdata.marketdata;	//PriceServiceProviderクラスの名前空間
using elsystem;


var:
	//PriceSeriesProviderクラスをPSPをいう名前で宣言
	PriceSeriesProvider PSP( NULL );

method bool IsChart()
begin
//GetAppInfo()  指定したキーワードに基づいて、呼び出しているアプリケーションの属性を指す数値を返します。 
return ( GetAppInfo( aiApplicationType ) = cChart );
end;

method void Init()
begin
	CreatePSP();
end;

Method void createPSP()
Begin
PSP = new PriceSeriesProvider();
PSP.Symbol = Symbol;
AlignPSP( PSP );

PSP.IncludeTicksInfo = false; 
PSP.IncludeVolumeInfo = true;
PSP.UseNaturalHours = false;
PSP.Realtime = true;

PSP.LoadProvider();
end;
method void AlignPSP( PriceSeriesProvider PSPToAlign )
begin

	if AnalysisTechnique.DataStreams.DefaultStream.UsesNaturalHours then
		RaiseRuntimeError( Name + " " + !( "cannot be used with natural hours selected." ) );

	PSPToAlign.Interval = DataInterval.FromCurrentSymbolData( BarType, BarInterval );
	PSPToAlign.Range.FirstDate = BarDateTime[MaxBarsBack];

	PSPToAlign.SessionName = 
	 AnalysisTechnique.DataStreams.DefaultStream.SessionName;	
end;
//************************************************************
// プログラムルート開始
//************************************************************

once	//初期化
begin
	Init();

end;

//チャートかレーダースクリーンかを判定して分岐させる
if IsChart() then
Begin
plot1( PSP.Volume[0], !( "Volume" ) );
Setplotwidth(1,2);
end

Else
Begin

end;

```
１行で書けるPowerShellスクリプト -エンコード編-

#はじめに
PowerShellのコマンドレットを活用してファイル単位でのエンコーディング操作を行います。

#こんな場合に使用します
・***受け取ったファイルのエンコーディングが想定と異なり文字化けする。***
・***古くからのサーバなどで自動生成されているファイルが「Shitf-JIS」形式などで
　別システムへのデータ連携（UTF8）においてエンコード変換が必要となる。***

#コード

```
Get-Content [コピー元 File-Path] | Set-Content [コピー先 File-Path] -Encoding UTF8
```
※注：（コピー元）と（コピー先）を同一にすると「Read/Write Lock」がかかります。

#最後に
上記コマンドレットをスクリプト(拡張子ps1ファイル)として保存することでバッチ処理に活用できます。
Android Studioとエミュレータで発生した事件まとめ

ほんまに聞いてくださいよ！
Flutterでアプリ開発して、さて動かそうとなったときにね、アプリが立ち上がらなかったんですわ。
そんな時に、Android界隈で有名な[中田大先生](https://twitter.com/nkt0615) が立ち上がって下さり、サポートいただきました。
本当にありがとうございました！

発生していた事件
1.　SocketException
2.　Caused by: java.lang.ClassNotFoundException
3.　AndroidStudioでemulatorのログが出力されない問題を解決する(←未解決)

### SocketException
ほんま聞いてくださいよ！
Flutterで通信系のアプリを開発して、iOSでは表示確認できて、Androidで確認できなかったわけです。
で、確認してみるとそもそもエミュレータでgoogle chromeを使ってサイトの閲覧なんかもできなくなっていたわけです。
調査したところ、こんな事例が掲載されていました。
[Mac OS High Sierra 10.13.2 - Android Emulator has no internet connection
](https://stackoverflow.com/questions/48411091/mac-os-high-sierra-10-13-2-android-emulator-has-no-internet-connection)

この中で、

```sh
./emulator -avd YOUR_EMULATOR_NAME -dns-server 8.8.8.8,8.8.4.4
```

これじゃない？と思い、実際に試してみることに。。。
が、そもそもこのemulatorってどこにあるんや？ってなるわけですよ。
場所は大抵の人はここかと思います。

```sh
/Users/<username>/Library/Android/sdk/emulator
```

なので、ここでまずはavdのリストを出力して、その中のemulator名をYOUR_EMULATOR_NAMEから置き換えします。
以下は実際に使用したコマンドです。

```sh
# emulatorの場所に移動
cd /Users/takehiro/Library/Android/sdk/emulator

# emulator一覧を表示
./emulator -list-avds

# emulatorのdns serverを変更
./emulator -avd Pixel_2_API_28_2 -dns-server 8.8.8.8,8.8.4.4
```

これで無事通信ができるようになりました。

### Caused by: java.lang.ClassNotFoundException

これはかなり注意が必要な案件です。
アプリを作った時に、idが自動的につくかと思います。
僕、このidがおかしな形で生成されていたので、以下のファイルで該当箇所(com.example.flutt.flutt)を(com.example.flutt)に修正したわけです。

```
- android/app/src/main/AndroidManifest.xml
- android/app/build.gradle
```

しかし、*android/app/src/main/kotlin/com/example/flutt/flutt/MainActivity.kt*とその中の情報がおかしかったわけです。
まず、idが変わった時点で、
*android/app/src/main/kotlin/com/example/flutt/flutt/MainActivity.kt*
は
*android/app/src/main/kotlin/com/example/flutt/MainActivity.kt*
にならないとおかしい。
ディレクトリ構造もcom.example.fluttと合わせる必要があります。

次に、このMainActivity.ktの中のidがcom.example.flutt.fluttだったので、com.example.fluttに修正。
このあと、flutter  cleanをしてから再度flutter runしたところ無事表示されました。
ブロッホ球をくるくるして遊べるゲームができました

**※2019/03/01追記：Challenge Blochはアップグレードされました！**遊び方が少し変更されました．

※この記事は，[こちらの記事](https://qiita.com/nisuikiba/items/62075884a6df1cf3c4ce)の続編にあたる記事です．
## [●ここからとべます](https://qease.herokuapp.com/bloch/challenge/)
[前回の記事](https://qiita.com/nisuikiba/items/62075884a6df1cf3c4ce)でつくったもので遊んでくださった方から，こういうゲームができるのでは？というご提案をいただき，さっそくつくってみました！
みなさんどうぞくるくるして遊んでみてください．

## 遊び方
- このゲームは，単一量子ゲートをつかって，目標の状態(Target State)を実現するゲームです
- まず，難易度を選択してください
    - 現在，イージーモードのみ遊べます
- GENERATEボタンを押して，問題を生成してください
    - 目標の状態(Target State)がランダムに生成されます
    - 解きたい問題が出るまで，繰り返し生成することが可能です
- 単一量子ゲートを適切に使用して，あなたのブロッホ球を，目標の状態に近づけます
    - **できるだけ少ないステップ数**(ゲートを適用させる回数)で，目標の状態を実現してください
- 目標の状態を実現できたら，CHECKボタンを押して，あなたのステップ数を確認しましょう
    - 理想的な(最小の)ステップ数で目標を達成していれば，*"CONGRATULATION！You realized the target state with the ideal number of steps!"*と表示されます
    - 理想的な(最小の)ステップ数を超えてしまった場合，*"WELL DONE！You realized the target state with more　steps than ideal."*と表示されます
    - もし，目標の状態を実現せずにCHECKボタンを押した場合，*"ERROR! It is not the target state."*と表示されます
- 問題によっては，適切なステップの組み合わせは一通りではない場合があります

#### こんなかんじです
<img width="1437" alt="スクリーンショット 2019-03-01 22.47.21.png" src="https://qiita-image-store.s3.amazonaws.com/0/252893/78795c16-2b8f-949b-2d44-0415bcffb69b.png">


- **ソースコードは[こちら](https://github.com/nisuikiba/Q-ease)**
- **動画は[こちら](https://drive.google.com/file/d/1aB_8l9Z2wp64BCDmvJ4D96leEAM4nfOg/view?usp=sharing)**
- ブロッホ球自体が常にくるくるしていますが，これに特に意味はありません．見にくいようであれば，球自体の回転や，光源等，変更が可能ですので，コメントをお寄せください．
- PC,フルスクリーン表示推奨です

こんな機能足したら面白そうじゃない？とかありましたら，是非是非コメントに！
また，不具合や誤動作等も，ご報告いただけると嬉しいです．
ブラウザで完結するnpm packageのデカさを調べる方法

Node.js界隈にはnpmというパッケージマネージャがあり、様々なパッケージを配布している。

ところでnpmの各パッケージのページにはパッケージのデカさが記述されていない。あんまでかいパッケージはちょっとなぁって思うのは私だけだろうか。

そこで手軽にパッケージのデカさを調べられるツールがあったのでメモしておく。

ネタ元は
[How do I view the size of npm packages? - Stack Overflow](https://stackoverflow.com/questions/40642008/how-do-i-view-the-size-of-npm-packages)

## bundlephobia

かなりグラフィカルに表示してくれる。内部でcacheしてるんか動作も早い。

https://bundlephobia.com/

![bundlephobia](https://qiita-image-store.s3.amazonaws.com/0/94177/51d0f004-ce88-214c-8772-3dcf0db37bd9.png)

## npm-download-size

極めてシンプル。わかりやすさの塊。

https://arve0.github.io/npm-download-size/

![npm-download-size](https://qiita-image-store.s3.amazonaws.com/0/94177/3fe0493e-7d8b-8c37-0d08-a38e24e593fd.png)

# License

[CC BY 4.0](https://creativecommons.org/licenses/by/4.0/deed.ja)

<a href="https://commons.wikimedia.org/wiki/File:CC-BY_icon.svg#/media/File:CC-BY_icon.svg"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/16/CC-BY_icon.svg/1200px-CC-BY_icon.svg.png" alt="CC-BY icon.svg" width="88px"></a>
フォーム入力有無バリデーション

自分用メモ。
フォームの入力有無だけチェックしたいときに使い回せるかと。
基本的に`type`と`name`だけ設定すれば動くようなイメージ。
他に必要な項目が増えたときに追記する。

こういうのはプラグイン化すれば良いんかなぁ(´・ω・｀)

## HTML

```html
<form id="form" action="/">
	<table>
		<tr>
			<th>お名前</th>
			<td><input type="text" name="nameName"></td>
		</tr>
		<tr>
			<th>メールアドレス</th>
			<td><input type="email" name="nameEmail"></td>
		<tr>
		<tr>
			<th>ラジオボタン</th>
			<td>
				<input type="radio" name="nameRadio" value="1">
				<input type="radio" name="nameRadio" value="2">
				<input type="radio" name="nameRadio" value="3">
			</td>
		</tr>
		<tr>
			<th>チェックボックス</th>
			<td>
				<input type="checkbox" name="nameCheckbox" value="1">
				<input type="checkbox" name="nameCheckbox" value="2">
				<input type="checkbox" name="nameCheckbox" value="3">
			</td>
		</tr>
	</table>
	<button type="submit">送信</button>
</form>
```



## JS

```javascript
$(function() {
	var btn_enabled = function() {
		var $_form     = $('#form'),
			$_inputs   = $_form.find('input'),
			$_btn      = $_form.find('button[type="submit"]'),
			config_arr = [
				// お名前
				{
					'type' : 'text',
					'name' : 'nameName',
				},
				// メールアドレス
				{
					'type' : 'text',
					'name' : 'nameEmail',
				},
				// ラジオボタン
				{
					'type' : 'radio',
					'name' : 'nameRadio',
				},
				// チェックボックス
				{
					'type' : 'checkbox',
					'name' : 'nameCheckbox',
				}
			];

		// 読み込み時に発火
		change_btn_prop();

		// 値を変更したときに発火
		$_inputs.change(function() {
			change_btn_prop();
		});

		// チェック実行結果に応じてボタンのプロパティを変更
		function change_btn_prop() {
			execute_check(config_arr)
				? $_btn.attr('disabled', false)
				: $_btn.attr('disabled', true);
		}

		/* ****************************** */
		/* チェックの実行
		/* array = [
		/* 	{
		/* 		type    : input.attr('type'),
		/* 		name    : input.attr('name'),
		/* 	}
		/* ]
		/* ****************************** */
		function execute_check(array) {
			var check_arr = [],
				check_cntr = 0;
			for(var i=0; i<array.length; i++) {
				var result;
				switch(array[i]['type']) {
					case 'text':
						result = check_text(array[i]['name']);
						break;
					case 'radio':
						result = check_radio(array[i]['name']);
						break;
					case 'checkbox':
						result = check_checkbox(array[i]['name']);
						break;
				}
				check_arr.push(result);
			}
			return check_arr.filter(function(elm) { return elm === true }).length >= array.length ? true : false;
		}

		// テキストの入力チェック
		function check_text(name) {
			var $_input = $('input[name="'+name+'"]');
			return $_input.val() !== "" ? true :  false;
		}

		// ラジオボタンの入力チェック
		function check_radio(name) {
			var $_input = $('input[name="'+name+'"]'),
				result = false;
			$_input.each(function() {
				if($(this).attr('checked')) {
					result = true;
					return false;
				}
			});
			return result;
		}

		// チェックボタンの入力チェック
		function check_checkbox(name) {
			var $_input = $('input[name="'+name+'"]'),
				cntr = 0;
			$_input.each(function() {
				if($(this).attr('checked')) cntr++;
			});
			return cntr > 0 ? true : false;
		}
	}();

});

```
GCPで数値計算がしたい（要求編）

Google Cloud Platform（AWSでもAzureでも良いのですが）を使って数値計算を行いたい

要求
-----
- 自前で計算資源を持たずに数値計算とその可視化・分析を行う
- 可視化・分析はJupyter互換環境で行う
- 計算の対象は偏微分方程式系、特に時空カオス系の研究用
    - 長時間の計算もありうる（stable chaos等）
    - 運動のシミュレーションだけでなく複雑なアルゴリズム（分岐追跡等）の実行も含む
    - 可視化以外はそのまま三次元に適用できる事が望ましい
        - Paraview等を使った三次元計算の可視化については今回は考えない
- 計算データは毎回生成するのではなく一旦保存し、そのデータに対して分析・可視化、及びそのデータを初期値としての計算等を行う
    - データは一回で数GB程度、全体で少なくとも数十TB程度

### 計算
計算自体は単一ノードで行う想定（複数ノードのMPIは使わない）。スレッド並列は計算をRustを書くのでRayonに頼る形になりそう。計算時間は

- 数時間から数日レベルの計算（要データ保存）
- 数秒から数分程度の計算（データの加工含む）

の両方が必要になる予定。

### データの保存
データサイエンスの普及のおかげで多くのサービスがある。どれを選ぶべきかは[ストレージ オプションの選択](https://cloud.google.com/storage-options/?hl=JA)が詳しい。
今回は可視化サーバーを計算サーバーとは共有しないので、必要なデータはすべてストレージに保存する。

1. 計算の進捗や収束状況のような時系列データ
  - 反復法の誤差のログや分岐追跡のログ
2. 計算の出力の構造化データ
  - msgpackやprotocol/flat buffersでシリアライズされた場の生データ
3. デバック・アルゴリズム検討の為の非構造化データ
  - Krylov法の途中のベクトルとか、その時のデバッグで必要なもの
【ロボホン開発】Could not find com.android.tools.build:gradle:3.0.1.　の対処法

# ロボホンのアプリのコンパイルでエラーが出る
Could not find com.android.tools.build:gradle:3.0.1.

# この場合は、build.gradle に google() を追加すればOK

```
buildscript {
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.1.3'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}
```
PHPでランダムトークン

* トークンはユニークにしたい。（衝突は知らない・・・）
* トークンはURLセーフにしておいた方が良い。
* トークン自体はユーザーに教えるために出力しないといけないので復号できなければならないので、DBに保存する際は暗号化。
* セッションやKVSに一時的に保持するような長期間使わないようなもの（有効期限付きURLアクセスのトークンとか）は暗号化はしなくても良いと思う。
* 一度きりの画面表示の場合はハッシュ化したものを保存して付け合わせれば良いので暗号化は不要です。

```php
$token = hash_hmac('sha1', uniqid(bin2hex(random_bytes(20))), 'key');

// ここで$tokenを暗号化して$encrypted_tokenを作る処理を記述

$token_pair['token'] = $token;
$token_pair['encrypt_token'] = $encrypt_token;// こっちをDBで保持
```

チェックは`$token`を暗号化してDBに登録した`$encrypt_token`を検索して取得できるかで判断

```php:ハッシュ化しない例
var_dump(uniqid(), uniqid(bin2hex(random_bytes(20))));
```

```
string(13) "5c6d73835289f"
string(53) "5f583b866a5e252acfcc5b2321ac3951941447b75c6d7383528a5"
```

uniqidのみだと時間を元に出しているのでランダムな文字列になりません。`5c6d7383528`が共通

```php:ハッシュ化した例
var_dump(hash_hmac('sha1', uniqid(bin2hex(random_bytes(20))), 'key'));
var_dump(hash_hmac('sha256', uniqid(), 'key'));
```

```
string(40) "5d893e491a7ec752c05acc7602cab9f9adeb1b5c"
string(64) "6f3bd3a96ac0ddf7210f6f7b9cddd41c92d1992aac8bb562eee3aa9e0eea7576"
```
Nuxt.js: storeモジュールから別のstoreモジュールのstateを参照する方法

前回の投稿からだいぶ間が空いてしまいました。

11月にG’s Academy LABコースを卒業して、フロントエンドエンジニアとしてキャリアをスタートしました。
Nuxt.jsで開発してるのですが、ググってもなかなか出てこなかったstoreのモジュールの扱い方で新たに学びがあったので記事にしました。

G’s時代にNuxtで５つアプリ作ったんですが、どれもstoreモジュールは一つだけでした。
ですが、現場の大規模開発となるとモジュールが何個もあるのが当たり前な状態です。

そこで今回ハマったのが、**storeモジュールA**から**storeモジュールB**のstateの状態を参照しようとして調べたけども、会社の人に教えてもらうまで、中々正解に辿りつけなかったので今回記事にしよう思いました。

以下の図のように、vueファイルでクリックなどのイベント発火時にcommitしてmutationsの関数を呼んで、その処理の中で別モジュールのstateを参照する必要がどうしてもあったのです。
rootStateを使う事はわかったんですが、延々とmutationsから参照しようと悪戦苦闘していたら、このrootStateはmutations内では使えず、gettersとactionsの中でしか使えないとのこと。。

![名称未設定-2_アートボード 1.jpg](https://qiita-image-store.s3.amazonaws.com/0/173182/02f53fe3-487a-9479-5187-2542cae97b2b.jpeg)

なので、今回のケースでいうと、actionsを経由する必要があったのです。
まず、vueファイル側でcommitからdispatchに変えてactionsの関数を呼びます。その中で別のstoreモジュールのstateを参照し、mutationsに引数で渡すという流れで作る必要があったそうです。。

![名称未設定-2_アートボード 1 のコピー.jpg](https://qiita-image-store.s3.amazonaws.com/0/173182/a41b7334-6d48-c3b6-99a9-021adda0d711.jpeg)

コードは以下の感じ。dispatchとmutationsは省略します。

```
export const actions = {
  add({ rootState, commit }, id) {
    const jobData = {
      cast: rootState.B.data,
      id,
    };
    commit('add', jobData);
  },
};
```

rootState.モジュール名.変数名でアクセスできます。
= rootState.B.data

これでうまくいきました。このrootStateの使い方がわからず、vueファイル側でcommitする時にstoreモジュールBを参照して、その値を引数で渡そうと思ったんですが、大規模開発だと修正箇所が増えてしまい、ミスも増えるのでこのやり方がすっきりしていいと思います。
PySparkで協調フィルタリング実装してみる

# 協調フィルタリングの概要

## 協調フィルタリング

協調フィルタリングとは、ユーザの商品の購入・閲覧・評価などの利用情報を基に、ユーザに対しておすすめの商品をレコメンドするアルゴリズム。
ベーシックなアルゴリズムとして、以下の2つがある。

- アイテムベース
 - ある商品と関連する商品レコメンデーションを行う手法
 - 履歴から同じユーザが利用している商品の類似性を計算する
 - 「この商品を見た人におすすめの商品」
- ユーザベース
 - ユーザごとに異なる商品レコメンデーションを行う手法
 - アイテムの利用傾向が似ているユーザが利用した商品を重視した評価値を計算する
 - 「あなたにおすすめの商品」

古典的ではあるが、パーソナライズレコメンデーションの中でも実装が簡単でかつ効果が出やすいので人気がある。

## スパース性と行列因子分解、ALS

協調フィルタリングにはいくつか問題があり、その中の1つが計算に使用するデータの「スパース性」である。
ユーザは取り扱っている商品のうちほんの1部しか利用しない。つまり、全ユーザ×商品の組み合わせのうち、ほとんどのデータが存在しない状態になっている。
この状態は、前述のレコメンド計算にあたっては、商品間やユーザ間で類似性の計算が難しくなる。

そこで、ユーザと商品を低次元の特徴量行列で表現し、その組み合わせで元のユーザ×商品の行列を再現する（行列因子分解）。
ユーザと商品にはそれぞれ何らかの固有の特徴量があり、その組み合わせ（内積）によって、ユーザが商品を利用するかどうかを推定するという考え方である。

協調フィルタリングでは、ユーザが使った商品あるいは商品を使ったユーザの情報を特徴として類似性の計算を行うが、この操作をすると、スパース性が解消されたユーザ・商品の特徴量行列が手に入り、類似性の計算が容易になる。

ALSは、行列因子分解をして、特徴量行列を計算するためのアルゴリズムである。

 - ユーザの特徴量行列を固定して、誤差が小さくなるように商品行列を変更
 - 商品の特徴量行列を固定して、誤差が小さくなるようにユーザ行列を変更
 - 上記を繰り返す


# 協調フィルタリングの実装

## アイテムベース

商品間の類似度としてコサイン類似度を使用する。
[こちら](https://qiita.com/calderarie/items/6ee90063487057e7e4eb)にあるように、`pyspark.mllib.linalg.distributed.RowMatrix`を使って計算する。

※MLライブラリで同様の機能は知る限り提供されていない
~~古典的なアイテムベースは、わざわざサポートする必要がないのかもしれない。~~

## ユーザベース

ALSアルゴリズムを使用して、ユーザベースを計算する。
Sparkでは、ALS用のライブラリの`pyspark.ml.recommendation.ALS`が存在し、これを用いることでユーザベースの計算が行える。

※厳密には、ALSの目的関数に正規化項を加えたALS-WSというアルゴリズムが採用されている

```python:ALSモデルの学習
from pyspark.ml.recommendation import ALS

# data: user_id, item_id, scoreのDataFrame

als = ALS(userCol='user_id', itemCol='item_id', ratingCol='score')
model = als.fit(data)
```

```python:ALSモデルの推論
N = 10  # レコメンド商品数
model.recommendForAllUsers(N)
```

### ALSクラスの主要なパラメータ

詳しくは[リファレンス](https://spark.apache.org/docs/2.2.0/api/python/pyspark.ml.html#pyspark.ml.recommendation.ALS)を参照


|引数|型|デフォルト値|説明|
|:-------------|:------------:|:------------:|:---------------|
|rank|int|10|特徴量行列の次元|
|maxIter|int|10|反復計算回数|
|regParam|float|0.1|正規化係数|
|implicitPrefs|bool|False|評価値がレビューなどの明示的(explicit)な値であるか、行動データなどの暗黙的(implicit)な値であるか|
|seed|int|None|シード|
|nonnegative|bool|False|非負値行列因子分解(NMF)を行うか|
|userCol|str|'user'|入力DataFrameのユーザ列名|
|itemCol|str|'item'|入力DataFrameの商品列名|
|ratingCol|str|'rating'|入力DataFrameの評価値列名|

### ALSモデルの主要メソッド

詳細は[リファレンス](https://spark.apache.org/docs/2.2.0/api/python/pyspark.ml.html#pyspark.ml.recommendation.ALSModel)参照

|メソッド|説明|
|:-------------|:-------------|
|recommendForAllItems(numUsers)|全商品にスコア上位numUsers人のユーザを割り当て|
|recommendForAllUsers(numItems)|全ユーザにスコア上位numItems件の商品を割り当て|

ここでは触れないが、ALSで作成したユーザや商品の特徴行列を取得することが出来るので、ユーザ間や商品間の類似度を定義することもできる。

# 参考

- 協調フィルタリングについて
 - [Amazonの推薦システムの20年](takuti.me https://takuti.me/note/two-decades-of-amazon-recommender/)
- ALSやNMFといった行列分解手法について
 - [カエルでもわかる！Spark / MLlib でやってみる協調フィルタリング（前編）](http://tech.albert2005.co.jp/277/)
 - [Algorithmic Music Recommendations at Spotify](https://www.slideshare.net/MrChrisJohnson/algorithmic-music-recommendations-at-spotify/21-Alternating_Least_Squares_Note_that)
 - [第2回　marbleーMixChannelで活用されるレコメンドシステム]( https://gihyo.jp/dev/serial/01/mixchannel/0002)
[WordPress]タームにカスタムフィールド追加

最新のバージョンは対応したか知らんけど
Advance Custom Fieldsだとwp_termmetaに保存しなくて
まあまあ不便だったので自前でやる。

```php:functions.php
//新規
add_action('{taxonomy}_add_form_fields', function() {
	$format = '<div class="form-field"><label for="%1$s">%2$s</label><input type="text" name="%1$s" id="%1$s" value="" size="40"></div>';
	printf($format, '{slug}', '{label}');
});
add_action('create_term', function ($term_id) {
	if ( array_key_exists('{slug}', $_POST) ) update_term_meta($term_id, '{slug}', esc_attr($_POST['{slug}']));
});

//編集
add_action('{taxonomy}_edit_form_fields', function ($term) {
	$format = '<tr class="form-field"><th><label for="%1$s">%2$s</label></th><td><input type="text" name="%1$s" id="%1$s" value="%3$s" size="40"></td></tr>';
	$value = get_term_meta($term->term_id, '{slug}', true);
	printf($format, '{slug}', '{label}', esc_attr($value));
});
add_action('edit_terms', function ($term_id) {
	if ( array_key_exists('{slug}', $_POST) ) update_term_meta($term_id, '{slug}', esc_attr($_POST['{slug}']));
});
```

inputのtypeやらsizeやらは適宜変更。
フォーマットはどこかしらから引っ張ってこれそうだけども。
Go2ジェネリクスとC++20コンセプトって雰囲気ちょい似てる？

Go2のジェネリクス/コントラクトと、C++20のコンセプトって雰囲気が似てるんじゃないかと思って対比させてみただけの記事。（※個人の感想です）

```go
// Go2
contract stringer(x T) {
  var s string = x.String()
}

func Stringify(type T stringer)(s []T) (ret []string) {
  for _, v := range s {
    ret = append(ret, v.String())
  }
  return ret
}
```

```c++
// C++20
#include <string>
#include <span>
#include <vector>
using namespace std;

template <typename T>
concept Stringer = requires (T x) {
  { x.to_string() } -> string;
};

template <Stringer E>
auto stringify(span<E> s) -> vector<string>
{
  vector<string> ret;
  for (auto&& v: s) {
     ret.push_back(v.to_string());
  }
  return ret;
}
```

<del>いかがでしたか？</del>いくらなんでも無理がありますね。

## 免責事項
2019年2月現在、Go2もC++20も策定段階のプログラミング言語仕様です。最終的に本記事の内容は陳腐化する可能性があります。

Go2ジェネリクス仕様は [Contracts - Draft Design, Aug/27/2018](https://go.googlesource.com/proposal/+/master/design/go2draft-contracts.md) を参考にしました。
C++20コンセプト仕様は [N4800 Working Draft](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/n4800.pdf) 仕様に基づきます。
Keynote 「ペンで描画」 の場所が変わった！

#Keynoteでベジェ曲線を描く
皆さんはMac付属のプレゼンソフト「Keynote」を使ってますか？
Keynote の旧バージョンでは、以下のような「ペンで描画」というツールでベジェ曲線を描いていました。iPhone アプリ作成時にpdfの画像ファイルを「ペンで描画」ツールで描いていました。（以下は、ネットから拾ってきた画像なので解像度が荒いです。）
![oldKeynote.gif](https://qiita-image-store.s3.amazonaws.com/0/193431/a05f0bbc-e9d7-eaa1-afeb-7625413e4fd4.gif)
##新バージョンで「ペンで描画」がなくなった？
Keynote が新バージョンになったら驚いたことに「ペンで描画」がなくなっていました!
あんな便利なツールがなくなってしまってどうしようと一時困りましたが、よく探したら場所が変わっていただけでした。下図右上の赤で囲ったペンのマークが「ペンで描画」ツールでした。この機能のために Keynote を使っていたので、ホッとしました。
![newKeynote.gif](https://qiita-image-store.s3.amazonaws.com/0/193431/14209202-9ad0-0ecd-e4c5-fdd8238c5667.gif)
このベジェ曲線作成機能はとても便利ですので皆さまも使ってみてください。
例えばビットマップで描かれたイラストを「ペンで描画」ツールでなぞればベクター画像に変換することができます。
WSLにDAKOTAをインストールする方法

#概要
今まではcygwinでDAKOTAを使っていたけど、OpenFOAMと連携させるためにWSLでDAKOTAを使う必要が出てきたので、忘備録として書きます。COMPUTER-AIDED ENGINEERINGのページを参考にして、インストールするのでDAKOTAは v6.4を使用しました
#手順
####必要なコンパイラのインストール

`$sudo apt-get install gcc g++ gfortran cmake cmake-curses-gui libboost-dev libboost-all-dev libblas-dev liblapack-dev libopenmpi-dev openmpi-bin openmpi-doc xorg-dev libmotif-dev `

####ダウンロード、展開
展開するディレクトリを作る
`$mkdir ~/DAKOTA`
[DAKOTA　ダウンロード]https://dakota.sandia.gov/download.html
今回はdakota-6.4-public.src.tar.gzを使います。
ダウンロードしてきた.gzを~/DAKOTAにコピーしてきて展開
`$cp /Download/dakota-6.4-public.src.tar.gz .`
`$tar -xzf dakota-6.4.0-public-src.tar.gz`

####make
`$cp ~/DAKOTA/dakota-6.4.0.src/cmake/BuildDakotaTemplate.cmake ~/DAKOTA/dakota-6.4.0.src/cmake/BuildDakotaCustom.cmake `してからのccmake
`$ccmake -C ~/DAKOTA/dakota-6.4.0.src/cmake/BuildDakotaCustom.cmake ~/DAKOTA/dakota-6.4.0.src -DCMAKE_INSTALL_PREFIX=~/DAKOTA/dakota-6.4.0 `
CmakeのGUIが起動しますので、とりあえず`c`でconfigureします。
BUILD_SHARE_LIBSが標準ではONですが、OpenFOAMのlibsampling.ioと競合するのでOFFにします。
再度cでconfigureしてgでgenerating the configuration.

makeをします。4プロセッサーでmakeする場合は、
`$make -j4`

make install
`$make install`

ここまでできたら、あとはPATHを通すだけで完成

####PATH
geditでbashrcを書き換えてPATHを通します．
`$gedit ~/.bashrc`
この時，Xwindowはいってないとエラーで立ち上がらないです．

PATHを追加します．CFD Onlineでは
`$export PATH=~/DAKOTA/dakota-6.4.0/bin:~/DAKOTA/dakota-6.4.0/test`
`$export LD_LIBRARY_PATH=~/DAKOTA/dakota-6.4.0/bin:~/DAKOTA/dakota-6.4.0/lib `
になってますが，僕はこれではPATHが通らず，
`$export PATH=＄PATH:~/DAKOTA/dakota-6.4.0/bin:~/DAKOTA/dakota-6.4.0/test`
`$export LD_LIBRARY_PATH=~/DAKOTA/dakota-6.4.0/bin:~/DAKOTA/dakota-6.4.0/lib `
で動きました．
助けてくれた先輩ありがとうございました．

以上で忘備録おしまい


#参考サイト
[COMPUTER-AIDED ENGINEERING]https://caetools.wordpress.com/2017/04/21/installing-dakota-on-ubuntu-16-04/
[CFD Online]https://www.cfd-online.com/Forums/openfoam-installation/174860-dakota-6-4-installation-ubuntu-16-04-a.html#post612814
【Unity】GameViewをショートカットキーからMaximizeするエディタ拡張

# はじめに

game-view-maximizerはGameViewをショートカットキー(Ctrl + Shift + X)からMaximizeするエディタ拡張です。

Unityの標準機能ではプレイモードでなければShift + Spaceでマウスが乗っているエディターウィンドウをMaximize出来ます。
[【Unity】エディタ上で Shift + Space を押すとマウスが乗っているウィンドウが最大化する](http://baba-s.hatenablog.com/entry/2017/12/27/180200)

今回はプレイモードで使用したかったため開発しました。

# game-view-maximizer

## 導入方法

[game-view-maximizer](https://github.com/tomori-hikage/game-view-maximizer) (GitHub)からダウンロードして、インポートしてください。

## デモ

![gif1.gif](https://qiita-image-store.s3.amazonaws.com/0/126970/75bb940e-82bb-bd9a-e072-e9e5af8979c4.gif)

# 配布ライセンス

[MIT](https://github.com/tomori-hikage/game-view-maximizer/blob/master/LICENSE.md)
【java】【ibatis】1対N関係のレコードをList<Map<>>で取得する方法

それがこれ。
ポイントはresultMap="A0160Plus"のgroupBy属性

◆SQLMap

	<resultMap id="A0162ResultMapPlus" class="java.util.HashMap"							
		groupBy="A0162＿NO">						
		<result column="SEIRINO" property="A0162_SEIRINO" />						
		<result column="BUYER＿NO" property="A0162_BUYER＿NO" />						
		<result column="A0162＿NO" property="A0162＿NO" />						
		<result column="A0162＿NAME" property="A0162＿NAME" />						
	</resultMap>							
	<resultMap id="A0164ResultMapPlus" class="java.util.HashMap"							
		groupBy="A0164＿NO">						
		<result column="SEIRINO" property="A0164_SEIRINO" />						
		<result column="BUYER＿NO" property="A0164_BUYER＿NO" />						
		<result column="A0164＿NO" property="A0164＿NO" />						
		<result column="A0164＿NAME" property="A0164＿NAME" />						
	</resultMap>							
	<resultMap id="A0168ResultMapPlus" class="java.util.HashMap"							
		groupBy="A0168＿NO">						
		<result column="SEIRINO" property="A0168_SEIRINO" />						
		<result column="BUYER＿NO" property="A0168_BUYER＿NO" />						
		<result column="A0168＿NO" property="A0168＿NO" />						
		<result column="A0168＿NAME" property="A0168＿NAME" />						
	</resultMap>							
	<resultMap id="A0160Plus" class="java.util.HashMap" groupBy="SEIRINO,BUYER＿NO">							
		<result column="SEIRINO" property="SEIRINO" />						
		<result column="BUYER＿NO" property="BUYER＿NO" />						
		<result column="BUYER＿NAME" property="BUYER＿NAME" />						
		<result property="A0162" resultMap="user.A0162ResultMapPlus"						
			javaType="java.util.ArrayList" />					
		<result property="A0164" resultMap="user.A0164ResultMapPlus"						
			javaType="java.util.ArrayList" />					
		<result property="A0168" resultMap="user.A0168ResultMapPlus"						
			javaType="java.util.ArrayList" />					
	</resultMap>							
	<select id="getA0160Plus" resultMap="A0160Plus" parameterClass="Map">							
		select						
		c.seiriNo, c.buyer＿no as buyer＿no,c.buyer＿name as buyer＿name, 						
		o.seiriNo as A0162_SEIRINO, o.buyer＿no as A0162_BUYER＿NO,o.A0162＿no as						
		A0162＿NO,o.A0162＿name as A0162＿NAME, 						
		a.seiriNo as						
		A0164_SEIRINO,a.buyer＿no as A0164_BUYER＿NO, a.A0164＿no as						
		A0164＿NO,a.A0164＿name as A0164＿NAME ,						
		b.seiriNo as A0168_SEIRINO,b.buyer＿no as A0168_BUYER＿NO, b.A0168＿no as						
		A0168＿NO,b.A0168＿name as A0168＿NAME						
		from						
		((A0160z c 						
		left outer 						
		join						
		A0162 o on c.SEIRINO = o.SEIRINO and						
		c.buyer＿no = o.buyer＿no) 						
		left						
		outer 						
		join  A0164 a on o.SEIRINO =						
		a.SEIRINO and o.buyer＿no =						
		a.buyer＿no )						
		left outer						
		join  A0168 b on						
		c.SEIRINO = b.SEIRINO and c.buyer＿no = b.buyer＿no						
		order by c.SEIRINO ,						
		c.BUYER＿NO,o.A0162＿no,a.A0164＿no,b.A0168＿no						
								
	</select>							



◆java側

・List<Map<String, Object>> ListmapPlus =
 queryDAO.executeForObjectList("user.getA0160Plus", null);
nginxの$sent_http_ってなんだ


### 注意点
残念ながら今の所明確な結論、原因は書かれていません。

## 概要
nginxはその圧倒的な設定項目の量ゆえ、整っているように見えるのだがなんか細かい挙動がよくわからんという話。

## 対象バージョン
nginx 1.15.4

## 問題の内容

nginxはバックエンドにポストするAPIに対して自前の認証・認可をかけることができる。

```
    location = /auth {
      internal;
      proxy_pass http://auth_server/auth;
    }

    location = /v1/api {
      auth_request /auth;
      proxy_pass http://api_server;
    }

```
こういうふうに書くと`http://api_server/v1/api`というapiを実行する前に`http://auth_server/auth`を実行して2xxならapiを実行それ以外ならエラーのステータスコードを返すみたいな挙動ができるわけだ。

大変便利なんだがふとしたときにauth_serverから返ってきたレスポンスが401の場合そのheaderを利用して挙動を変えたいという要求が出た。

例えば401がauthから返ってきた時に再認証画面にリダイレクトさせるか、システムやアプリケーションアカウントからのアクセスなので、そのまま401を返すかとかだ。
どうもauth_requestはレスポンスボディを返すことができないようなので(多分)レスポンスヘッダーにシステムからのアクセスの場合`System-Error: system`というカスタムヘッダーを追加する事でnginx上で挙動の変更をさせてたかった。
多分auth_serverもまぁupstreamの一種だろうと雑に考えた結果、以下のような設定なら期待する挙動になるかなと思った。

```
    error_page 401 = @error401;
    location @error401 {
      if ($upstream_http_system_error = 'system') {
        return 401;
      }
      # 人の場合認証サーバーにリダイレクトさせる
      rewrite ^ http://認証サーバー/login;
      break;
    }
```

以下upstream_http_の説明

\$upstream_http_name
keep server response header fields. For example, the “Server” response header field is available through the \$upstream_http_server variable. The rules of converting header field names to variable names are the same as for the variables that start with the “$http_” prefix. Only the header fields from the response of the last server are saved.

ここでいうkeep server response header fieldというのがauthサーバーからのレスポンスだと思ったのだがどうにもupstream_http_ではauthからのレスポンスヘッダを取得することができなかった。

そこで以下のように設定すればauthからのレスポンスヘッダを取得することができた。

```
    error_page 401 = @error401;
    location @error401 {
      if ($system_error = 'system') {
      # こうも行けます if ($sent_http_system_error = 'system') {
        return 401;
      }
      # 人の場合認証サーバーにリダイレクトさせる
      rewrite ^ http://認証サーバー/login;
      break;
    }
    location = /auth {
      internal;
      proxy_pass http://auth_server/auth;
    }

    location = /v1/api {
      auth_request /auth;
      auth_request_set $system_error $sent_http_system_error;
      proxy_pass http://api_server;
    }
```

auth_request_setディレクティブで\$system_error変数に$sent_http_system_errorの値を入れて
`location @error401`で出し分ける。みたいなことができる。
でこのsent_http_system_errorとは

http://nginx.org/en/docs/http/ngx_http_core_module.html#var_sent_http_

```
$sent_http_name
arbitrary response header field; the last part of a variable name is the field name converted to lower case with dashes replaced by underscores
```

これだけ。

任意のレスポンスヘッダってだいぶ範囲広いっすね。snipptでも書いたけどauth_request_setで定義すると
その他のロケーションでも`$sent_http_system_error`が読めるようになってこれもまた謎。
(auth_request_setディレクティブで設定しないとerror401 locationで`$sent_http_system_error`にヘッダが設定されない。)

動くには動くのだけれども何故auth_requestのレスポンスヘッダが$sent_http_に入るのかは結局良く理解できなかった。
いまいち\$sent_http_はどのタイミングでどういう値が入るのかがちょっと理解できなかった。
だれか教えて(他力本願)

## 参考リンク

http://mogile.web.fc2.com/nginx/http/ngx_http_auth_request_module.html
http://nginx.org/en/docs/http/ngx_http_core_module.html#var_sent_http_
http://nginx.org/en/docs/http/ngx_http_upstream_module.html
Javascript初心者が自分なりに高階関数を解説してみた

Javascriptを勉強している人たちの多くがつまづくであろう **高階関数** 、自分もその例外ではなく最初は全く理解ができませんでした。

ここではその高階関数を自分なりに説明してみました、もし間違えていたり変な部分があればご指摘いただけたら恐縮です。

---
## 高階関数とは

高階関数とは関数を引数、戻り値に使う関数のことです。

例えば関数には引数をセットし、宣言時にそこに値または変数を入れ渡すことができます。

```js
function test(a, b){
  console.log(a + b);
}

const num1 = 10;
const num2 = 5;

test(num1, num2); // 実行結果: 15
```

また、関数式によって変数に関数を代入することもできますね。

```js
const test = (a,b) => { //変数testに関数を代入している
  console.log(a + b);
}
```
高階関数は、引数に関数(を代入した変数)を渡して呼び出してやろうと言うわけです。


## コードを書いてみた
```js
// 高階関数
const quiz = (answer, callback) => {
  answer = parseInt(answer); // 入力された文字を数字に変換
  let result;
  if(isNaN(answer)){ // 入力された文字が数字以外の場合反応する
    result = '数字を入力してください';
  } else if(answer === 1){
    result = '正解です!';
  } else {
    result = '不正解です!';
  }
  callback(result);　//callbackにresultを返す（代入する）
}

// resultを出力するための関数式
const outputResult = result => {
  console.log(result);
}

// 文字入力用の変数
const inputAnswer = prompt('1 + 1 = ?');

quiz(inputAnswer,outputResult);

// outputResultを使わず直接引数内に関数式を記入する書き方もできます
quiz(inputAnswer, (result) =>{
  console.log(result);
});

```
[サンプル(codepen)](https://codepen.io/atlansien/pen/pGMQwq?editors=0011)

ここでは、まず最初に高階関数、次に高階関数の引数となる関数を定義しています。
この高階関数`quiz`は、入力した文字によって引数に代入される文字を変える処理を持っています。


次に、代入された引数を出力する処理を持つ関数`outputResult`、最後に文字を入力する処理をもつ変数`inputAnswer`を用意しました。
最後に高階関数の引数に関数を設定することで、それぞれの機能をまとめた処理をすることができるようになるました。
また、高階関数の引数に直接関数を記入しても問題なく機能します。

それと、高階関数内で、最後に関数に引数を渡していますが、こういった処理のことを`コールバック関数`と言います。詳しくはまた別の記事で書こうかと、、、
Microsoft Formsに回答があったらMicrosoft Flowへ連携する

Formsに回答がきたらメール通知したいけどできるか？と聞かれ、そういえばどこまで出来るんだろう、と調べたところ、これぐらいならFormsの標準機能で出来るようだった。
しかし、もっと発展したやり方は今時は出来るはずだと思い、掲題の件で調べた。

やりたいこと
--------------

Formsに回答があったら、回答毎に（Flowで出来る範囲の）任意の形で連携できるかどうかを試した。

軽く調べた所、そういったテンプレートがあるので大体出来そうだ、というのは分かっていました。
ただ、主観ですがFlowは微妙にかゆいところに手が届かないモノもあったので、実用的かどうかも判断してみます。


やりかた
--------------

適当に「test」というフォームを用意します。

![Microsoft Formsのイメージ図](https://qiita-image-store.s3.amazonaws.com/0/52527/c00bff43-9046-4065-3f6f-1bac7f3772f1.png)

こんな感じにFlowを組みます。フォーム名を指定している点に注意してください。

![Formsの結果を連携するFlowのイメージ図](https://qiita-image-store.s3.amazonaws.com/0/52527/ed103c93-412c-5369-284f-8169fc3a34a9.png)

一応、文字起こしすると以下のように作っています。

- （トリガー）Forms: 新しい応答が送信されるとき
- 制御: Apply to Each
    - Forms: 応答の詳細を取得する
    - Yammer: 投稿メッセージ

Formの応答は配列になっているため、Apply-to-Eachする必要があります。
（同タイミングに複数回答があると複数入ると予想してますが、実際には見たことはないです...）

今はYammerに投稿メッセージとして送っていますが、ここは好きに組み替えることができます。
また、見ての通り、Formで設定している質問項目に対する回答を「応答の詳細を取得する」によりちゃんと取れています。（項目名がいい加減すぎました）


さて、回答して動作をみます。

![Formsの回答イメージ図](https://qiita-image-store.s3.amazonaws.com/0/52527/40f03f93-c94a-6a37-a874-1ce72c282f92.png)

Yammerを見るとこんな感じになっていればよいです。

![Formsの回答結果をFlowで連携されYammerに投稿されているイメージ図](https://qiita-image-store.s3.amazonaws.com/0/52527/7655ef7a-d901-1b0e-926a-81722696507b.png)

今回はYammerでしたが、Formsのメール通知をカスタマイズしたり、Teamsに通知したり、HTTPで送りつける事で独自のシステムと連携することもできます。

ということで、Formsはちゃんと**使える**ものになっていそうです。ここから先が大変だと思いますが。

なお、Yammerの「フォームに投稿がありました」の文言は、Flowの投稿メッセージの詳細設定で仕込んでいるものです。



### Flowの日時の罠

Flowで日時の扱いをちょっと変えたいと思うたびに、いつも引っかかるので。

まず、見ての通り、Formsに記録される日時がUTCなので日本時間なら9時間足す必要があります。そういうとこやぞ。

というわけで、以下の式で置き換えるとよいでしょう。bodyのAction名は適当に併せてください（デフォルトだとこのまま。）

```
convertTimeZone(body('応答の詳細を取得する')?['submitDate'], 'UTC', 'Tokyo Standard Time', 'yyyy-MM-dd HH:mm:ss')
```

4つ目の引数で使える[日時フォーマットのドキュメントはこちら](https://docs.microsoft.com/ja-jp/dotnet/standard/base-types/standard-date-and-time-format-strings)です。

UTCと分かっているなら`convertFromUtc`という打ってつけな感じのものがありますがこれは使えません。騙されないように。`convertTimeZone`だけです。`convertTimeZone`だけが我々を救ってくれます。

TimeZoneの指定もクセがあります。Flowにおいては`'UTC'`, `'Tokyo Standard Time'`の2つを覚えておけばよいです。`'JST'`ではないです。
もしそれ以外のタイムゾーンの対応を行う場合は、[こちらがお役立ちドキュメント](https://docs.microsoft.com/ja-jp/previous-versions/windows/embedded/gg154758(v=winembedded.80))です。

convertTimeZoneのタイムゾーンは見ての通り、名前を文字列を指定する必要があります。ドキュメントにはIDは数字で振られており、数値でも行けそうと思うと騙されます。関数のヘルプもIDと出てきますが、文字列でIDを指定してもダメです。悲しいな。
Google DocumentsからExcelやPowerPointに一括変換する

# Google Documentsは超便利！

Google Documentsのスプレッドシートやスライド、本当に便利ですよね。チームで共有できて、更新がリアルタイムに反映されて、コメントを使って簡易的なToDo管理までできて。
一度使ってしまうと、ExcelやPowerPointのファイルで管理するのがものすごく面倒になってきます。

# しかし、外部との共有が・・

作成したファイルを外部の組織にも共有する必要がある場合、Googleのアカウントを教えてもらって権限を与えるのが一般的です。

でも世の中にはまだまだこんな会社があるんです。

「ウチの会社はGoogle Driveは使用禁止です」
「ファイルはzipで圧縮してメールで送ってください。解凍パスワードは別のメールで送ってください」
「宅○ァイル便で送ってください」
「FTPサーバで送ってください」

宅フ○イル便は言うに及ばないですが、zipをメールで送るより二段階認証しているGoogleアカウントの方がずっと安全なのに・・・
まあ、共有したくない場合や静的なアーカイブとして保存しておきたい場合もありますね。

# なので変換します

ファイル数が少ない場合には、手動でスプレッドシートからExcel、スライドからPowerPointに書き出しすれば問題ありません。
しかし、仕様書や定義書はどんどん数が増えるものです。
なので、一括して変換する方法を調査しました。

まず、新規でスプレッドシートを作成し、下記のように変換したいドキュメントのドキュメントIDを１列目に入れておきます。
ドキュメントIDは、ファイルを開いたときのURLからすぐにわかります。

```
https://docs.google.com/spreadsheets/d/（ドキュメントID）/edit
```

２列目には、スプレッドシートなら「xlsx」、スライドなら「pptx」と入力します。

<img width="696" alt="スクリーンショット 2019-02-20 23.18.35.png" src="https://qiita-image-store.s3.amazonaws.com/0/31032/d543c411-7c96-c8fa-a7c2-a7774a5d5f0f.png">

そして、「ツール＞スクリプトエディタ」を選択し、下記のコードを入力します。

```JavaScript
function exportFiles()
{
  var sheet = SpreadsheetApp.getActiveSheet();
  var rowIndex = 2;
  var documentId,outputFileName,type;
  
  while(true)
  { 
    documentId = sheet.getRange(rowIndex,1).getValue();  
    type = sheet.getRange(rowIndex,2).getValue();  
    
    if (!documentId || !type) break;
            
    var file = DriveApp.getFileById(documentId);
    outputFileName = file.getName();
    
    convertFile(documentId,outputFileName,type);
    
    rowIndex++;
  }
}

function convertFile(documentId,outputFileName,type) {
  outputFileName += "." + type;
  var url;
  
  if(type == "pptx")
  {
    url = 'https://docs.google.com/presentation/d/' + documentId + '/export/pptx?access_token=' + ScriptApp.getOAuthToken();
  }
  else if(type == "xlsx")
  {
    url = 'https://docs.google.com/spreadsheets/d/' + documentId + '/export?access_token=' + ScriptApp.getOAuthToken();
  }
  else
  {
    return;
  }  

  var rootFolder = DriveApp.getRootFolder();
  var response = UrlFetchApp.fetch(url);
  var blob = response.getBlob();
  var result = rootFolder.createFile(blob.setName(outputFileName));
}
```

そして、スクリプトエディタからexportFiles関数を実行すると、Google Driveのルートディレクトリに、xlsx形式やpptx形式のファイルが生成されます。

# ToDo

Docs形式に対応
タイプの自動判別
書き出しフォルダを指定
変換対象のファイルをフォルダ単位で指定
Hass.io Yahoo 気象情報APIセンサー

[Hass.io カスタムコンポーネントを作ってみる](https://qiita.com/yambal/items/2539dfa989f8347eef46)では「Hass.io」で WEB API をウォッチする センサーをの作り方を調べてみました。

今回は実際に[気象情報API](https://developer.yahoo.co.jp/webapi/map/openlocalplatform/v1/weather.html) で***降水強度実測値***と***降水強度予測値***を取得するセンサーを作ってみましょう。このセンサーで、雨降り前に Google Home に「10分後に雨が降ります」などと喋らせること Automation が作成できますね。

## ソースコード
[実際のソースコード](https://github.com/yambal/hass/blob/master/config/custom_components/sensor/precipitation.py)
↑このコードを
`/config/custom_components/sensor/precipitation.py`
として保存して再起動するとセンサーと稼働します

![precipitation.PNG](https://qiita-image-store.s3.amazonaws.com/0/70983/f97be3d2-336c-a0d0-8418-e8d76fbeedbd.png)

## 使い方と設定
ドキュメント [Hass.io Yahoo 気象情報APIセンサー](https://github.com/yambal/hass/blob/master/config/custom_components/sensor/Precipitation.md) をご参照ください

------

##### ヒント

乱暴にAPIアクセス部分を切り出せばこんな感じか

```sample.py
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import json
...

url = 'https://map.yahooapis.jp/weather/V1/place'
params = {
  'coordinates':[LAT_AND_LON],
  'output': 'json',
  'appid': [YOUR APPID],
}

websession = async_get_clientsession(self.hass)
res = await websession.get(url, params=urlparams)

jsonText = await res.text()
jsonDict = json.loads(jsonText)
rainfall = jsonDict['Feature'][0]['Property']['WeatherList']['Weather'][0]['Rainfall']
```
##### 参考：気象情報APIの返り値 (JSON)
これをパースして利用するわけですね

```place.json
{  
   "ResultInfo":{  
      "Count":1,
      "Total":1,
      "Start":1,
      "Status":200,
      "Latency":0.004484,
      "Description":"",
      "Copyright":"(C) Yahoo Japan Corporation."
   },
   "Feature":[  
      {  
         "Id":"[ID]",
         "Name":"地点([LAT_AND_LON])の2019年02月16日 01時55分から60分間の天気情報",
         "Geometry":{  
            "Type":"point",
            "Coordinates":"[LAT_AND_LON]"
         },
         "Property":{  
            "WeatherAreaCode":6200,
            "WeatherList":{  
               "Weather":[  
                  {  
                     "Type":"observation",
                     "Date":"201902160155",
                     "Rainfall":0.00
                  },
                  {  
                     "Type":"forecast",
                     "Date":"201902160205",
                     "Rainfall":0.00
                  },
                  {  
                     "Type":"forecast",
                     "Date":"201902160215",
                     "Rainfall":0.00
                  },
                  {  
                     "Type":"forecast",
                     "Date":"201902160225",
                     "Rainfall":0.00
                  },
                  {  
                     "Type":"forecast",
                     "Date":"201902160235",
                     "Rainfall":0.00
                  },
                  {  
                     "Type":"forecast",
                     "Date":"201902160245",
                     "Rainfall":0.00
                  },
                  {  
                     "Type":"forecast",
                     "Date":"201902160255",
                     "Rainfall":0.00
                  }
               ]
            }
         }
      }
   ]
}
```
ディレクトリ内のjsファイルを全てminifyする方法

ディレクトリ内のjsファイルを全てminifyする方法を解説します。

次のコマンドにより行うことができます。

```bash
npm i -g uglify-es
cat *.js | uglifyjs -o script.js
```
参考になれば幸いです。
## 終わりに
私は現在、Web3のサービスの開発をしています。詳しくはこちらの記事をご覧下さい。
        [無料でイーサリアムが当たる、Web3時代の寄付サイトを作った話](https://note.com/kenroda/n/n814347fbdcd7)
MyFirstRails #9 RefineryCMS の導入

# Refinery CMS サンプル
## 概要

Railsにこれから初めて触れる方を対象にしたチュートリアルです
[`Refinery CMS`](https://github.com/refinery/refinerycms)というRailsで使用できるCMSをインストールするチュートリアルです

なお、実際に作ったものは[こちら](https://github.com/S-H-GAMELINKS/MyFirstRails/blob/master/refinerycms)

## チュートリアル
### Refinery CMSのテンプレートでひな型を作る

まず、`rails new`を実行し、ひな型を作成します

```shell
rails _5.1.6_ new refinerycms -m https://www.refinerycms.com/t/4.0.0
```

`_5.1.6_`は使用するRailsのバージョンを指定しています
`Refinery CMS`ではRalsのバージョンが`5.1`以上`5.2`以下である必要があります

なお、最新の`5.2.2`を使用すると`bundle install`の段階で`gem`がインストールできません

### サイトのタイトル変更

`config/initializers/refinery/core.rb`の`# config.site_name = "Company Name"`を修正します

```ruby:config/initializers/refinery/core.rb
config.site_name = "Refinery CMS"
```

これでサイトのタイトルが`Refinery CMS`に変更されています

### Refinery CMSの日本語化

`Refinery CMS`は初期状態では英語表記になっています
これを日本語に変更するには`config/initializers/refinery/i18n.rb`を以下のように修正します

```ruby:config/initializers/refinery/i18n.rb
Refinery::I18n.configure do |config|
  config.default_locale = :ja

  config.current_locale = :ja

  config.default_frontend_locale = :ja

  config.frontend_locales = [:ja]

  # config.locales = {:en=>"English", :fr=>"Français", :nl=>"Nederlands", :pt=>"Português", :"pt-BR"=>"Português brasileiro", :da=>"Dansk", :nb=>"Norsk Bokmål", :sl=>"Slovenian", :es=>"Español", :ca=>"Català", :it=>"Italiano", :de=>"Deutsch", :lv=>"Latviski", :ru=>"Русский", :sv=>"Svenska", :pl=>"Polski", :"zh-CN"=>"简体中文", :"zh-TW"=>"繁體中文", :el=>"Ελληνικά", :rs=>"Srpski", :cs=>"Česky", :sk=>"Slovenský", :ja=>"日本語", :bg=>"Български", :hu=>"Hungarian", :uk=>"Українська"}
end
```

これで日本語表記に変更されています！

### Refinery CMSの起動

作成した、`refinerycms`に移動し、`bundle exec rails s`でローカルサーバを起動します

```shell
cd refinerycms
bundle exec rails s
```

これで`localhost:3000`にアクセスするとホーム画面が表示されます

次に、新しいページなどを追加してみましょう
`localhost:3000/refinery`にアクセスすると初期ユーザーの登録画面にリダイレクトされます

名前やメールアドレスなどを入力後、`sign up`をクリックしてアカウントを作成します

アカウント作成後、管理画面に移動します

左のメニュー欄から「ページ」をクリックし、「Home」右横の`+`を選択し、子のページを作成します

タイトルとコンテンツを記入後、「保存」をクリックして変更を保存します

`localhost:3000`にアクセスすると`Home`以下に先ほど作成したページが追加されています
このように新しいページを追加していきます！
TOEIC285学生のためのSwift

#分からない部分を徹底的に無くす
Swiftで新規プロジェクトを立ち上げて、ViewController.swiftを確認すると初期状態はこうなってると思う。

```swift:ViewController.swift
//
//  ViewController.swift
//  tesutodayo
//
//  Created by このしゅうかつせいれべる１ on 2019/02/20.
//  Copyright © 2019 このしゅうかつせいれべる１. All rights reserved.
//

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }


}
```
文字の色が違うのは**仕様**なので勘弁してほしい。

```swift
//
```

まずは // の部分、これはこの行がコメントだということを表している。
コメントとは、プログラムに自由に記述できるメモのようなもの...え？知ってる？
知らない人もきっと中には居るはず....基礎の基礎からやっていくのでご容赦いただきたい。
灰色の文字はプログラムに影響しないコメントです。

```swift
//行の最初に // を打ち込むことでプログラムに影響しない文字を入力することが可能になります。
```

ただし毎行毎行 // を打ち込むのは面倒で数行にわたってコメントを書き込みたいときは

```Swift
/*
   じゅげむ じゅげむ ごこうのすりきれ. かいじゃりすいぎょの すいぎょうまつ.
 　うんらいまつ ふうらいまつ. くうねるところに すむところ. やぶらこうじの ぶらこうじ. 
   パイポパイポ. パイポのシューリンガン. シューリンガンのグーリンダイ. グーリンダイのポンポコピー...
*/
```

このように /* */で囲むことで数行でコメントの書き込みが可能になります。

```swift
//  ViewController.swift
```

Swiftのファイル名が自動で挿入されている。

```swift
//  tesutodayo
```
プロジェクト名が自動で挿入されている。

```swift
//  Created by このしゅうかつせいれべる１ on 2019/02/20.
//  Copyright © 2019 このしゅうかつせいれべる１. All rights reserved.
```

5行目には作者の名前と制作日、6行目には著作者の名前が挿入されている。
All rights reservedは直訳すると**全著作権所有**という意味。

さて、ここまでは全てコメントであったが、ここからはプログラムに影響を及ぼすものになる。
**（コメントには何を書こうが原則影響は出ないが、極論で日本語で10億文字コメントを書き込むとプログラムデータがおおざっぱに計算して約2GB重くなる...（はず）そんなに書き込むことはないので気にしないで良い。仮に10億文字コメントを書いたプログラムを他のプログラマーに見せたら発狂すると思われ）**

```swift
import UIKit
```

いむぽあと、ういきっと...違う、インポート、ユーアイキットである。
【import】インポート・・・持ち込む
**【UIKit】UIKitとはiOSのUIのコンポーネントである**

iOSは分かりますよね？え、分からない？
アップル社が開発提供しているオペレーティングシステムのことで、iPhoneやらiPod touchやらiPadに搭載されているもの。

UIは、"うい"じゃなくて"ゆーあい"で...いや、友愛じゃなくてユーアイ。
ユーザインタフェースを略してユーアイ。
ええ....ユーザインタフェースをご存知ない...

人が端末の画面をみて、これをこうすればこうなるんだな、と分かるようにするものがユーザインタフェース。
![UI.png](https://qiita-image-store.s3.amazonaws.com/0/364635/79ddce98-06fa-33fd-6fab-a078dd0bd99f.png)
（上記画像はTwitterの操作画面）
TwitterのホームボタンやツイートボタンなどもＵＩ、視覚的な要素で人が分かりやすくなるものを指す。
アプリの画面やらなんやらを管理したりするときに必要になるものがUIKitという箱に入っているのでそれを
**import UIKit** で、開ける感じです。
**import パンドラの箱** でパンドラの箱を開けるみたいな、いや、そんなもんはないけども（作ればある）
パンドラの箱って何が入ってるんでしょうねぇ、不採用通知とか解雇通知とか退学通知とかそんな（おいやめろ

長くなったので続きはまた後日
**[NEXT](https://qiita.com/KonoLv1/items/475475b8f7ad2e62155f "NEXT")**
[Microsoft] PowerBIカスタムビジュアルでInfragistics Ignite UIのData Gridを使う

# はじめに

[PowerBI](https://powerbi.microsoft.com/ja-jp/)のカスタムビジュアルで[Infragistics Ignite UI](https://www.infragistics.com/products/ignite-ui)を使う方法です。

こんなんできました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/59475/d55c9004-6f61-fc77-6744-946798351f8b.png)

# やらないといけないこと

* JQuery等のグローバルなオブジェクトを使えるようにする
* pbiviz.jsonのexternalJSセクションでJQuery, JQuery UI, Ignite UIを読み込む

## JQuery等のグローバルなオブジェクトを使えるようにする

PowerBI内では、Windowオブジェクトがフェイクに置き換えられているそうです。
jQuery等が見えなくなります。

回避策として、以下のファイルを作成します。

```js:src/jquery.adapter.js
var jQuery = typeof jQuery !== 'undefined' ? jQuery : window['$'];
```

Infragistics Ignite UIも見えなくなるので、以下のファイルを作成します。

```js:src/infragistics.adapter.js
var igRoot = typeof igRoot !== 'undefined' ? igRoot : window['igRoot'];
var MSApp = typeof MSApp !== 'undefined' ? MSApp : window['MSApp'];
```


## pbiviz.jsonのexternalJSセクションでJQuery, JQuery UI, Ignite UIを読み込む

pbiviz.jsonで作成したファイルを読み込みます。

```json:pbiviz.json
  "externalJS": [
    "node_modules/jquery/dist/jquery.js",
    "src/jquery.adapter.js",
    "vendor/jquery-ui-1.12.1/jquery-ui.js",
    "vendor/ignite-ui/js/infragistics.core.js",
    "vendor/ignite-ui/js/infragistics.lob.js",
    "src/infragistics.adapter.js",
    "node_modules/powerbi-visuals-utils-dataviewutils/lib/index.js"
  ],
```

順番大事みたいです。


# 使い方

IVisual継承クラスのコンストラクタの中で、グリッドを作成します。

```ts:src/visual.ts
module powerbi.extensibility.visual {
    export class Visual implements IVisual {
        constructor(options: VisualConstructorOptions) {
            const target = jQuery(options.element);

            const table = jQuery('<table>');
            table.appendTo(target);

            try {
                table.igGrid({
                    dataSource: [
                        { Label: 1, Value: 100 },
                        { Label: 2, Value: 200 },
                        { Label: 3, Value: 300 }
                    ]
                });
            } catch (err) {
                console.log(err);
            }
        }
// （略）
```

ここではとりあえずお試し用の値を入れています。


スタイルシートも読み込んでおきます。

```less:style/visual.less
@import './vendor/ignite-ui/css/themes/infragistics/infragistics.theme.less';
@import './vendor/ignite-ui/css/structure/infragistics.css';
```
modelに新しいカラムを追加する

## 属性足りないや…

開発中、モデルにカラムが足りないことに気がついてしまった。
[DBの中身を吹き飛ばして作り直す方法](https://qiita.com/ginger893/items/54d911fc8443be26f48f)は以前やりましたが、今回は中身を飛ばしたくないなぁ…とカラムだけ追加する方針に。
controllerやmodelを作るrails generateでカラムを足していきましょう。
ということで、魔法の呪文「rails generate **migration**」を唱えましょう。

```console:console
$ rails generate migration Circle event_id:integer
Running via Spring preloader in process 8856
      invoke  active_record
   identical    db/migrate/20190220120407_circle.rb
```

よしよし、出来…identical？
「同じ」って意味だっけ。
rails db:migrateしても何も変わらないので調べて再実行したのが以下。

```console:console
$ rails generate migration AddEventidToCircle event_id:integer              
Running via Spring preloader in process 8923
      invoke  active_record
      create    db/migrate/20190220120833_add_eventid_to_circle.rb
```

migrationの後ろに記載する「AddXXXXToYYYY」がミソ。
この名前になってないとrails db:migrateが反応しません。
ちゃんと名前を指定したら、rails db:migrateして、インスタンスをnewして確認しましょう。

```console:console
$ rails db:migrate
== 20190220120833 AddEventidToCircle: migrating ===============================
-- add_column(:circles, :event_id, :integer)
   -> 0.0017s
== 20190220120833 AddEventidToCircle: migrated (0.0024s) ======================

$ rails console
Running via Spring preloader in process 8955
Loading development environment (Rails 5.2.2)
2.4.1 :001 > c = Circle.new
 => #<Circle id: nil, name: nil, space: nil, memo: nil, url: nil, created_at: nil, updated_at: nil, event_id: nil> 
```

末尾に増えてますね。
よかったよかった。
【gemのコードってどこから取得しているのか】

Gemfileの先頭行に書いてある***sourceメソッドの引数のサイト***から取得されます。
```source "https://rubygems.org"```
このgemのgitリポジトリの中のコードが該当部分。
それがどこにインストールされたのか調べるには
例えばrails のソースを見たいときは

```$ gem which rails```

```
/Library/Ruby/Gems/1.8/gems/railties-3.1.0.rc4/lib/rails.rb
```

みたいな感じで確認することができます。

参考
http://d.hatena.ne.jp/zucay/20110722/1311298429
https://woshidan.hatenablog.com/entry/2015/04/12/224554