OmniAICreator/Qiita-1.07M huggingface dataset:
[JavaScript]input要素に入力した場所によって対応した場所に出力をする

## メモ
開発メモ

```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
	<title>練習</title>
</head>
<body>
	<input name="kanso" id = "num_1" rows="1" cols="10"></input>
	<input name="kanso" id = "num_2" rows="1" cols="10"></input>
	<p id="result_1"></p>
	<p id="result_2"></p>
</body>
<script>
	$("[id^=num_]").change(function () {
		let value = $(this).val(); // 値を取得
		let id = $(this).attr('id'); // id取得
		// idによってresult_{id}に値を入れる
		let res = id.replace(/[^0-9]/g, ''); // idの数字の部分のみを取得
		let result_id = "result_" + res; // 取得した数字でidを生成
		var result = document.getElementById(result_id); // 生成したidの要素を取得
		result.innerHTML = value ? value * 100 : ''; // 取得した要素に値を入れる（入力がない場合は空）
	});
</script>
</html>
```
[React]useStateで定義したstateを更新したのに再レンダーされない件(object / 配列)

少し詰まったので、書き記します。


newDataというstateを操作するfunction inputChange(e)を定義し、onChageイベントとして使ったが、再レンダーされず、入力値が変更できない。

```react:js

    const [newData, setNewData] = useState({name:'', content:''});


    function inputChange(e){
        const key = e.target.name;
        const value = e.target.value;
        newData[key] = value;  // newDataの値を更新
        const data = newData  //setNewDataするため、dataを定義
        setNewData(data);
     }

```

コードは問題なさそうと思って悩んでいましたが、公式に答えがありました。


https://ja.reactjs.org/docs/hooks-reference.html#bailing-out-of-a-state-update
現在値と同じ値で更新を行った場合、React は子のレンダーや副作用の実行を回避して処理を終了します。（React は Object.is による比較アルゴリズム を使用します）




↓これで行けました

```react:js

    function inputChange(e){
        const key = e.target.name;
        const value = e.target.value;
        newData[key] = value;
        let data = Object.assign({}, newData);  //オブジェクトを新しく作り直す必要がある
        setNewData(data);
     }

```

配列の場合はsplice()を使用して、新しい配列として、dataを定義します。


[学び] React.jsは公式が大事
Iotについて

時間もないので
さっと知った知識について書きます。

# Iot(Internet of Things)とは
モノのインターネットという意味で
様々な「モノ」がインターネットに接続され、情報交換することにより相互に制御する仕組みである。

# 実現できること

## スマートシティー/IoTと街
道路の信号や公園の草木のシャワーなどを
現在の状況から検知して実行する

## コネクティッド・カー/IoTと自動車
AIによる自動運転から
周辺の道路状況に応じて最適なルートを提示するナビゲーションシステムなど

## IoTと医療
ウェアラブル端末でバイタルサインを測定し、遠隔医療や適切なケアに結びつけます。
また、2017年7月にセコムが販売を開始したマイドクターウォッチは、リストバンドとして手首に装着することで、発作などの突然の体調不良時に自力で簡単に緊急通報できるほか、意識を失った場合の自動通報の機能なども備えています。

# Iotの目的
リソースを過不足なく配分し、仕事や生活をさらに快適にしてくれること、
世の中の最適化が目的
【GAS】指定範囲のセルから数式と値を両方取得する(getValues()&getFormulas())

# 概要
getValues()では値しか取得できません。
getFormulas()では数式しか取得できません。
数式と値が両方取れる関数が見つからなかったので作ってみました。
需要があるのかは謎です。
もっといい方法があるよ！という場合はコメントよろしくお願いします。

#以下サンプル


##ソースコード
```Javascript:main.gs
/*＊＊＊＊＊＊＊＊＊＊
指定範囲のセルから数式と値を取得する関数
@param:セル範囲
@return：2次元配列
*＊＊＊＊＊＊＊＊＊＊*/
function getValuesAndFormulas(range){
  //getValues()でまずは値だけ取得
  var valuesAndFomulas = range.getValues();
  Logger.log("valuesAndFomulas:%s", valuesAndFomulas);
  
  //getFormulas()で数式を取得
  var tempFormulas = range.getFormulas();
  Logger.log("tempFormulas:%s", tempFormulas);
  
  //getValues()で取得した配列とgetFormulas()で取得した配列を突合
  for(column = 0; column < valuesAndFomulas[0].length; column++){
    for(row = 0; row < valuesAndFomulas.length; row++){
      //getFormulas()で取得した数式の入っている要素を代入して更新
      if(tempFormulas[row][column].length != 0){
        //空ではなく数式が入っている
        valuesAndFomulas[row][column] = tempFormulas[row][column];
      }else{
        //空の場合
        ;//何もしない
      }
    }
  }
  Logger.log("valuesAndFomulas:%s", valuesAndFomulas);
  return valuesAndFomulas;
}

function main() {
  //紐づいているスプレッドシートにアクセス
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  Logger.log(spreadsheet.getName());
  
  //アクティブなシートを取得
  var sheet = spreadsheet.getActiveSheet();
  
  //B3：D7のセル範囲を指定
  var range = spreadsheet.getRangeByName('B3:D7');
  //var range = sheet.getRange(3, 2, 5, 3);//こちらでも可
  
  //チェック
  var checkGetValues = range.getValues();
  Logger.log("checkGetValues:%s", checkGetValues);
  
  var checkGetFormulas = range.getFormulas();
  Logger.log("checkGetValues:%s", checkGetFormulas);
  
  var checkGetValuesAndGetFormulas = getValuesAndFormulas(range);
  Logger.log("checkGetValuesAndGetFormulas：%s", checkGetValuesAndGetFormulas);
  
  //書き込み
  spreadsheet.getRangeByName('F3:H7').setValues(checkGetValues);
  spreadsheet.getRangeByName('B10:D14').setValues(checkGetFormulas);
  spreadsheet.getRangeByName('F10:H14').setValues(checkGetValuesAndGetFormulas);
}

```
##実行結果
<img width="844" alt="スクリーンショット 2020-01-15 22.08.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563987/d16d2e1d-581d-bfbc-c703-e714427e629b.png">

##ログ
<img width="669" alt="スクリーンショット 2020-01-15 22.10.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563987/57676081-ed14-3e1f-3cf6-cbba16910c91.png">
【離散コサイン変換】DFTを使ってDCTしてみる

# 背景
[【離散コサイン変換】DCT-IIの式をぼんやり理解する](https://qiita.com/jajagacchi/items/e7b427c71257860f95e6)の続きです。

# 使用したライブラリ
[【画像処理100本ノックに挑戦】独自の離散フーリエ変換クラスを作る](https://qiita.com/jajagacchi/items/0b5232aa8ae99b9b8114)

# DFTを使ってDCT-IIしてみる
$N$点のデータ$x_n$があったとして、$4N$点の$y_n$を

```math
\begin{eqnarray}
y_{2n+1} &=& y_{4N-2n-1}=x_n\;(0\leq n < N)\\
\end{eqnarray}
```

で定義してやってDFTすればOKです。上の点以外はゼロとします。

```c++
std::vector<double> dct(std::vector<double> in)
{
	int N = in.size();
	std::vector<double> out(N);
	for (int k = 0; k < N; k++)
	{
		out[k] = 0;
		for (int n = 0; n < N; n++)
		{
			out[k] += in[n] * cos(pi / N * (n + 0.5) * k);
		}
	}
	return out;
}

int main()
{
	int N = 128;
	std::vector<double> data(N), out(N);
	for (int i = 0; i < N; i++)
	{
		data[i] = cos(2 * pi * i / 10);
	}

	out = dct(data);

	std::vector<std::complex<double>> data2(4 * N);
	for (int i = 0; i < 4 * N; i++) data2[i] = 0;
	for (int i = 0; i < N; i++) data2[2 * i + 1] = data2[4 * N - 2 * i - 1] = data[i] / 2.;

	DFT dft;
	std::vector<std::complex<double>> out2 = dft.forward(data2);

	for (int i = 0; i < N; i++)
	{
		std::cout << out[i] << " " << out2[i].real() << std::endl;
	}

	return 0;
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520857/4dac0d73-660e-0ad8-3a9d-861e99ca1e48.png)
定義どおりにDCTした場合と結果が一致することが確認できました。

# DFTを使ってDCT-IIIしてみる
$N$点のデータ$x_n$があったとして、$4N$点の$y_n$を

```math
\begin{eqnarray}
0\leq n<N&\to& y_n = x_n\\
n=N&\to& y_n = 0\\
N<n\leq 2N &\to& y_n = -x_{2N-n}\\
2N<n<3N &\to& y_n = -x_{n-2N}\\
n=3N &\to& y_n = 0\\
3N<n<4N &\to& y_n = x_{4N-n}
\end{eqnarray}
```

で定義してやってDFTすればOKです。


```c++
std::vector<double> dct3(std::vector<double> in)
{
	int N = in.size();
	std::vector<double> out(N);
	for (int k = 0; k < N; k++)
	{
		out[k] = in[0] / 2.;
		for (int n = 1; n < N; n++)
		{
			out[k] += in[n] * cos(pi / N * (k + 0.5) * n);
		}
	}
	return out;
}

int main()
{
	int N = 128;
	std::vector<double> data(N), out(N);
	for (int i = 0; i < N; i++)
	{
		data[i] = cos(2 * pi * i / 10);
	}

	out = dct3(data);

	std::vector<std::complex<double>> data2(4 * N);
	for (int i = 0; i < 4 * N; i++) data2[i] = 0;
	for (int n = 0; n < N; n++) data2[n] = data[n];
	for (int n = N + 1; n <= 2 * N; n++) data2[n] = -data[2 * N - n];
	for (int n = 2 * N + 1; n < 3 * N; n++) data2[n] = -data[n - 2 * N];
	for (int n = 3 * N + 1; n < 4 * N; n++) data2[n] = data[4 * N - n];

	DFT dft;
	std::vector<std::complex<double>> out2 = dft.forward(data2);

	for (int i = 0; i < N; i++)
	{
		std::cout << out[i] << " " << out2[2 * i + 1].real() / 4. << std::endl;
	}

	return 0;
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520857/ab64e2cf-35ac-8d14-99a1-426cebb60bbf.png)
定義どおりにDCTした場合と結果が一致することが確認できました。

次回は二次元DCTについて少し考えてみるつもりです。
集合内包表記

```py:1
s = set()
for i in range(10):
    s.add(i)
print(s)
```

```:1の実行結果
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
```

これを内包表記にすると

```py:内包表記1
s = {i for i in range(10)}
print(s)
```

```:内包表記1の実行結果
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
```

リスト内包表記の時と同様に、
3で割って余り0の数字のみ集合に入れるには

```py:内包表記2
s = {i for i in range(10) if i % 3 == 0}
print(s)
```

```:内包表記2の実行結果
{0, 3, 6, 9}
```
focusイベントがキャンセルできない問題。

Vueを触っている時、ブラウザを切り替えたタイミングでフォーカスを外したいコンポーネントにあうことはありませんか？
そんな時まず思い浮かぶのは、eventをpreventDefaultすることだと思います。
事実、私もそう思い実行しました。
しかし、うまくいきませんでした。
なぜ？調べてみました。

#focusイベントについて

MDNを見てみる。
>focus イベントは、要素がフォーカスを受け取ったときに発生します。このイベントと focusin との違いは、 focusin がバブリングを行うのに対し focus は行わないことです。
focus の反対は blur です。

>| バブリング | なし |
|:--|:--|
| キャンセル可能 | いいえ |
>

キャンセル不可のため、preventDefalutは効かないらしい・・・。
というこで、フォーカスを発生させないためには逆にフォーカスを外してやればいい。
まぁそういえばそうかといった感じですが・・・


#正解コード(javascript)
el-tooltipはコンポーネント内のフォーカスを外したい要素のクラス名です。

```App.js
  mounted() {
    window.addEventListener("focus", () => {
      const onFocutElm = window.document.activeElement;
      if (onFocutElm && onFocutElm.classList.contains("el-tooltip")) {
        onFocutElm.blur();
      }
    });
  }
```

#正解コード(typescript)
```App.ts
  mounted() {
    window.addEventListener("focus", () => {
      const onFocutElm = window.document.activeElement;
      if (onFocutElm && onFocutElm.classList.contains("el-tooltip")) {
        (onFocutElm as HTMLElement).blur()
      }
    });
  }
```

#おまけ
上記コードではフォーカスを外すことができましたが、 Firefixブラウザではなぜかうまくいきませんでした。
その為、setTimeoutを挟むことで正しく処理されました。

```App.js
  mounted() {
    window.addEventListener("focus", () => {
      setTimeout(() => {
        const onFocutElm = window.document.activeElement;
        if (onFocutElm && onFocutElm.classList.contains("el-tooltip")) {
          onFocutElm.blur();
        }
      }, 0);
    });
  }
```

また、単にフォーカスを要素から外したいのであればbody自体にフォーカスを当てる方法もあります。
divなどの要素にフォーカスを当てるにはtabindex属性をセットする必要があります。

```App.js
  mounted() {
    window.addEventListener("focus", () => {
      const onFocutElm = window.document.activeElement;
      if (onFocutElm && onFocutElm.classList.contains("el-tooltip")) {
        const body = document.body;
        body.tabIndex = 0;
        body.focus();
      }
    });
  }
```
分散システムの各ノードを使用してプロセスの状態を判別したい

## はじめに
　今日、プロセスを監視・管理できる方法は今更作る必要がないほどあります(Zabbixだったりコマンドを打って見たり)。便利な世の中です。ですが、ここでは自分なりのプロセスの監視・管理方法を提案させていただこうと思います。
#### 障害の透過性
　分散システムには「透過性」という概念があります。簡潔に言うと、システムのあらゆる側面、処理を隠すことです。透過する対象はいくつかありますが、特に障害の透過性の実現は困難とされています。死んだプロセスと非常に反応が遅いプロセスの判別をつけることが難しいことが原因とされています。
####なにがしたい
　分散システム内の死んだプロセスと非常に反応が遅いプロセスの判別をしたい。
## 提案
### 登場人物
 - Leader
  - 全体の動きをコントロール、Reporterに処理を渡したりとみんなのまとめ役
  - 状態判別の決定を行う
  - 監視サーバにいる
 - Reporter
  - 分散システムを構成している各ノードに常駐する
  - Leaderからの要求に応じてプロセス状態の送信
  - Reporterは以下の返事を送ることができる
     - Alive：プロセスが生きていた
     - Dead：プロセスが死んでいた
     - NoReply：返事が無かった

## 処理の流れ
　下の図はReporter2が常駐しているノードのプロセスに異常の可能性が見られる状況を表しています。
<img width="399" alt="syori.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557264/63fdc314-1ef3-7870-cc97-a3dd1a0564ed.png">
1. 異常を検出したときのアラートをLeaderが受け取る
2. Leaderは健康なノードのReporter1,3へプロセス状態の確認を依頼する(返事が来なかったらNoReply)
3. 依頼を受けたReporter1,3はプロセス異常が疑われるノードのReporter2にプロセス状態の送信を依頼。Reporter2は自ノードのプロセス状態をReporter1,3へ送信
4. Reporter2から受けた応答(Alive or Dead)をLeaderへ返す。返ってこなかった場合はNoReplyをLeaderへ返す。
5. Leaderは返された状態(Alive or Dead)の数が過半数に達した方をそのプロセスの状態として決定する.
## 信頼度
　LeaderはReporterが送ってきたプロセス状態から過半数に至った状態(Alive,Dead)を最終決定とします。いわばプロセス状態選挙のようなものです。しかし、このままではどちらも過半数得られない、票が割れてしまった場合は一つに決定できません。そこで、これまでの各Reporterに信頼度という重みをつけてみる事を提案します。皆さんにも信頼できる人、できない人がいるはずです。そんな現実の人間関係のしがらみを持ち込みます。本提案の信頼度は以下の３つになります。
<img width="257" alt="sinrai.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557264/01580930-6949-aa18-043c-b6cf01df16ab.png">

<img width="466" alt="sinraidoseni.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557264/cc3e1941-f3e9-92b6-886b-d768300364a3.png">

normalを初期値として,Leaderへ返した状態が過半数に達したときに、そのReporterの信頼度を上昇させます。過半数に達しなかった場合は下降します。票が割れてしまった場合、Leaderは信頼度の高いReporterからの情報を優先して判断材料にします。以下に示す図のようになります。
<img width="389" alt="sinrai.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557264/64c721b3-d183-0dc0-100f-269120b39850.png">
　上の図ではAliveとDeadが2票で票数だけでは判断できません。しかし、Aliveと送ったtrustのReporterが2つと、Deadと送ったReporterよりも信頼度が高いのでAliveと判定されます。
## 会議ID
各ノードで通信する関係上、応答が遅延してしまう事も考えられます。前のプロセス判別の処理(会議1とします)が終了した後、次のプロセスの判別の処理(会議2とします)が開始されたとします。会議2の途中で、遅れていたReporterが会議1の返答を送ったとしたら大変です。前の議題の回答を送っているわけです(今晩の晩御飯のメニューについて話し合っているのに、遅れて参加してきて、すでに済ませた今日の昼食のメニューの回答をしてくるような感じ)。これが起こってしまったら正常に処理が行われなくなる可能性があります。
　その対策として,プロセス状態の決定の一連の処理(以下、会議とします)に会議IDという固有のIDをつけることを提案します。Leaderは会議が完了するたびに会議IDを１ずつ変更します。会議IDはLeaderのみ管理することが出来ます。このIDと共に通信を行う事により,現在の議題についての回答かわかるようになります。以前の会議の返答をしたReporterは会議に不参加とします。途中参加は認めません。
　以上の説明を以下の図にまとめてみました。
<img width="389" alt="sinrai.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557264/416fdce1-7d75-deac-0707-7d5e3ec0f077.png">

## まとめ
　本記事で提案の説明をさせていただきました。読んでいると気付かれる方もいるかもしれませんが、本提案は分散合意アルゴリズム(Raft,Paxos,etc)に多分に影響を受けています。さらに、現状では実験が出来ておらず定量的な評価を示せていない点もも私の力不足です。記述していませんが他にも問題点が山積みです。本提案を実用的なものには程遠いものです。最適なアプローチの模索、実験をすべきです。

　記事は以上になります。お疲れさまでした。
【離散コサイン変換】DCT-IIの式をぼんやり理解する

# 背景
画像処理100本ノックに挑戦中です。
Q.36から離散コサイン変換(DCT)の問題です。DCTはよく知らなかったので少し調べてみました。

# DCT-II
DCTにはいくつかバリエーションがあります。DCTの基底は実数のみで表されるところに特徴があります。フーリエ級数が実数成分のみとなるのは、関数が偶関数の場合なので、対象の関数を偶関数に拡張して定義します。離散フーリエ変換の場合、偶関数であることは要求せず、ただ周期的に拡張するだけでした。この拡張の仕方によってバリエーションがあります。
ここではDCT-IIを取り上げます。DCT-IIは

```math
X_k = \sum_{n=0}^{N-1}x_n\cos\left\{\frac{\pi}{N}(n+\frac{1}{2}k)\right\}
```
で定義されます。Wikipediaを見てみると、$x_n$が$n=-1/2$に対して偶対称うんぬんかんぬんの境界条件に対応するとかよくわからないことが書いてあります。
考えてみます。まず$x\geq0$で定義される$f(x)$を考えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520857/f97019d4-56c3-dad7-2601-5e91bc2287fa.png)

$x=-1/2$で偶対称になるように関数を拡張します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520857/53958b66-7e54-b278-9991-e8c76c7bd680.png)

$x=0$が中心になるように平行移動します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520857/609f9703-6912-e147-619f-c880f9eb617a.png)

どうもDCT-IIはこういう感じの拡張をするようです。これを周期的に並べてフーリエ変換を考えればよいようです。

面倒なのでここではDCT-IIの導出はしませんが、ごりごりやれば出てきそうだな、というところまでは理解したいと思います。
$f(x)$が$0\leq x$で定義されているとして、次のような関数を定義します。

```math
g(x) = 
\begin{cases}
f(x-1/2) & x\geq 1/2\\
f(-x-1/2) & x\leq -1/2
\end{cases}
```

$g(x)$の$x=\frac{2n+1}{2}$の点を離散サンプリングします($n$は整数)。

```math
\tilde g(x) = g(x)\sum_{n=-\infty}^{\infty} \delta(x-\frac{2n+1}{2})
```

$\tilde g$は偶関数なので、そのフーリエ変換は実となります。フーリエ変換してみます。

```math
\begin{eqnarray}
\tilde G(\nu) &=& \int \tilde g(x)e^{-2\pi i\nu x} dx\\
&=& \int g(x)\sum_{n=-\infty}^{\infty} \delta(x-\frac{2n+1}{2})e^{-2\pi i\nu x} dx\\
&=& \sum_{n=0}^{\infty} f(n)\cdot 2\cos\left(2\pi\nu \frac{2n+1}{2}\right)
\end{eqnarray}
```

DCT-IIの式っぽいものが出てきました。ここでは周期化していないので、周期化すればDCT-IIの式と一致すると思われます。

# DCT-IIとDFT
これでなんとなく、DCT-IIの式が導出できそうな感触がつかめました。

次に確認したいのは、DFTとの対応関係です。これがわかれば、FFTを用いて高速にDCTを計算することが出来ます。WikipediaによればDCT専用アルゴリズムの速度には敵わないようですが、実用的な問題はなさそうです。

Wikipediaの説明によれば、例えばデータがabcという実数列で表されるとき、DCT-IIはabccbaと拡張することに相当し、さらにDFTを用いて計算する際は0a0b0c0c0b0aとしてDFTすればよいそうです。この理由を考えてみます。

```math
\tilde G(\nu) = \sum_n g(n+1/2)e^{-2\pi i\nu(n+1/2)}
```

を元に考えれば、DFTと同じ式に持っていくためには$n+1/2\equiv m/2$という置き換えをしてexpの指数部をDFTと同じ形にします。

```math
\tilde G(\nu) = \sum_{m={\rm odd}} g(m/2)e^{-2\pi i\nu m/2}
```

DFTではm=oddという制限はないので、m=evenの点をゼロとして$g$を拡張してやればよいです。これが0を挿入する理由です。厳密な証明も難しくはありませんが、ここでは省略します。

まとめると、$N$点のデータ$x_n$があったとき、$4N$点の$y_n$を

```math
\begin{eqnarray}
y_{2n+1} &=& y_{4N-2n-1}=x_n\;(0\leq n < N)\\
\end{eqnarray}
```

と定義してDFTすればDCT-II出来ます。上記の点以外はゼロとします。

# DCT-IIの逆変換
DCT-IIの逆変換はDCT-IIIという変換です。DCT-IIIは

```math
X_k = \frac{1}{2}x_0 + \sum_{n=1}^{N-1}x_n\cos\left\{\frac{\pi}{N}(k+1/2)\right\}
```

で与えられます。これは偶関数への拡張を${\rm abc}\to\rm{abc0\tilde c\tilde b\tilde a\tilde b\tilde c0cb}$という方法で行うことに相当します。ややこしいですが、DCT-IIの結果は自動的にこれを満たしますので、逆変換がDCT-IIIとなります。

まとめると、$N$点のデータ$x_n$があったとき、$4N$点の$y_n$を

```math
\begin{eqnarray}
0\leq n<N&\to& y_n = x_n\\
n=N&\to& y_n = 0\\
N<n\leq 2N &\to& y_n = -x_{2N-n}\\
2N<n<3N &\to& y_n = -x_{n-2N}\\
n=3N &\to& y_n = 0\\
3N<n<4N &\to& y_n = x_{4N-n}
\end{eqnarray}
```

と定義してDFTすればDCT-II出来ます。上記の点以外はゼロとします。DCT-IIで変換後、フィルタ処理をしてDCT-IIIを行うときは、フーリエ空間上でこの対称性を満たす必要があることに注意を要します。

# まとめ
離散コサイン変換とは何ぞやということがわかってきました。次回は実際にDCTしてみたいと思います。
VBのブロック切り分けはこれでいける（のか？）

## VBで処理をブロックで切り分けたくなった

お仕事で１万光年ぶりにがっつりVBを読み書きすることになりました。[^1]
Web界にいることが多くお仕事でここまでVB使うのはほぼほぼ初めてで~~正直やりたくない~~まあやってみるかと引き継いだのはいいんですけど[^2]
4,000行あるサブルーチンやいろいろな値をとっかえひっかえお盛んなファジーな名前のグローバル変数をかきわけて保守しているうちに、変数の生存範囲を狭めるためにブロックに切り分けたくなりました。
ちなみにVisual Basic 2010です。

C#だとこんな感じのやつですね。

```C#
{
    var hoge = something();
}

{
    var hoge = something();
}
```

でもVBではこの書き方は不可能です。
なのでこんな書き方をする？

```VisualBasic 
If True Then
    Dim hoge = something()
End If

If True Then
    Dim hoge = something()
End If
```

必ずTrueになるIf文を使用して切り分ける。
確かに動きます。
でもIf文って条件の分岐に使うためのものでちょっとこの使い方はきもちわるいなって感じですよね。
というわけでIf以外の方法で書くことにしました。

```VisualBasic 
Call _
Sub()
    Dim hoge = something()
End Sub

Call _
Sub()
    Dim hoge = something()
End Sub
```

動く。　OK。


## 動くけど

もしかしたらVB的にはすごいBADな書き方なのかもしれないのでVBに強い方いらっしゃいましたらご指摘ください。


[^1]: 光年は時間の単位ではない
[^2]: 作成者も前任者も既に居ないのを引継ぎとはいわない
【備忘録】MacBookProのメモリを増設してみた。

##はじめに
MacBookProのメモリを増設したので、やり方を記載しておきます。

##参考
以下のページを参考にしました。
『MacBook Pro：メモリの取り外し方法と取り付け方法 - Apple サポート』
https://support.apple.com/ja-jp/HT201165

Appleは、こうした公式のリファレンスがしっかりあるので助かります。
でも、確か、自分でやった場合は、修理保証対象外だったような。。。

##スペック
ここで、MacBookProのスペックを記載しておきます。

**MacBook Pro**
**13-inch, Early 2011**
プロセッサ: **2.3GHz Intel Core i5**
メモリ: **4GB 1333MHz DDR3**
グラフィックス: **Intel HD Graphics 3000 384MB**
ソフトウェア: **Mac OS X Lion 10.7.5**

## 用意した物
家にあった、シリコンパワーのPC3-12800 DDR3 1600MHz 4GBメモリを使います。
https://www.amazon.co.jp/dp/B00GAJ2P9O/ref=cm_sw_r_tw_dp_U_x_wBbhEbPF6KPES

MacBookPro Early 2011の推奨は、下記の通りです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519347/2479ad97-5a72-bfdf-7dbe-e5741c628b38.png" width=75%>
（出典：https://support.apple.com/ja-jp/HT201165#1）
「**PC3-10600 DDR3 1333MHz**」とありますが、大きさや切り欠きの位置、ピンの数が同じですし、
1333MHzは転送速度の事で、「このMacはこの転送速度のメモリで十分ですよ」という意味なので、
「**PC3-12800 DDR3 1600MHz**」でも動作するはずです。
※もちろん、オーバースペックなので、DDR3 1333MHzのほうが安ければ、
DDR3 1333MHzにしたほうがお財布的にも優しいです。


##手順
###1.ネジ取り外し
MacBookの底面の10箇所のネジを外していきます。ドライバーは+00を使用します。
ヒンジ近くのネジ3箇所は、他のネジと長さが異なるので、ネジの位置を覚えておきましょう。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519347/d007643c-00f7-a7d2-2de0-621e74149988.jpeg" width=75%>

###2.メモリスロットの確認
ネジを外したら、フタを開け、メモリスロットの位置を確認します。
どうやら2GBメモリが2枚ささっているようです。
MacBookProのメモリ情報も、各スロットに2GBずつ、ささっている事が確認出来ます。
今回は、4GBメモリ1枚のみなので、手前の2GBメモリを4GBメモリに変更します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519347/bc444955-f324-0f44-5e62-9c08701dc22f.jpeg" width=75%>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519347/d2cf61f1-07a0-e218-29f7-d472bc0ec009.png" width=50%>

###3.メモリの取り外し
メモリスロットの側面にあるツメを外側に押すと、手前のメモリが浮いてきます。
浮いてきたメモリを抜きます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519347/d6bc665c-e1a6-477b-fbc6-261d8eb8596d.jpeg" width=75%>

###4.メモリの取り付け
用意したメモリを挿します。この時、金色の部分には触れないようにします。
挿した後は、メモリスロット側面のツメが挿したメモリに引っかかるまでメモリを押します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519347/083ff3fc-8625-1bfc-9cf8-d570aeb0ca3e.jpeg" width=75%>

###5.フタをしめ、ネジをしめる
ふたをしめ、ネジをしめます。

###6.動作確認
MacBookProを起動します。
メモリの情報を開き、メモリが認識しているか、確認します。無事認識出来ています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519347/ec9f7192-23fb-f118-24cf-b975521bb627.png" width=50%>

##まとめ
今回は、MacBookProのメモリ増設してみました。
メモリ増設前は、MacBookProのメモリへのアクセスは容易ではないと思っていましたが、
やってみて、意外と簡単だったなと印象です。
今回は、家にあったあまりものでやったので、近いうちに、8GB × 2の16GBにしたいなと思います。
増設した場合は、こちらに追記します。
集合のメソッド add remove clear

```py:1
s = {1, 2, 3, 4, 5}
s.add(6)
print(s)
```

```:1の実行結果
{1, 2, 3, 4, 5, 6}
```

```py:2
s = {1, 2, 3, 4, 5}
s.remove(5)
print(s)
```

```:2の実行結果
{1, 2, 3, 4}
```

```py:3
s = {1, 2, 3, 4, 5}
s.clear()
print(s)
```

```:3の実行結果
set()
```
空の辞書{}と区別する為に、
空集合はset()と表す。
「Prepare Android Developer Importer」が終わらない

### Android Stduio がアップデートが終わらない
Android Stduio をアップグレードしたとき、

プラグイン `Android Drawable Importer` が原因による*「Prepare Android Developer Importer」* と表示され、どれだけ待っても終わらないことがあります。
![prepare_android_drawable_importer_error.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486398/ce77f6b2-e9b1-09a2-7ae5-08b922c2105e.png)


### 対策1
Winows の場合、管理者権限が無いことが原因のようなので、
Android Stidio のプロセスをキルした後、右クリックから「管理者として実行」をすることでほとんどの場合、起動するようです。

しかし、これでも永久に待たされることがありました...

### 対策2

影響となっているプラグインを直接削除することで、起動する事ができます。

Android studio の現行バージョンの下記 config 配下にある
`config\plugins\android-drawable-importer-intellij-plugin` 

・フルパス表記
`%userprofile%\.AndroidStudio3.4\config\plugins\android-drawable-importer-intellij-plugin`

を削除することで、
起動時にプラグインの初期化がスキップされ、問題なく起動することができました。

削除した後は [Plugin Marketplace](https://plugins.jetbrains.com/plugin/7658-android-drawable-importer/) から再インストールしました。
AWS EC2に新しいバージョンのNode.jsをインストールする

AWSのEC2のNode.jsはデフォルトだと6系がインストールされていて、
古すぎて困って新しいバージョンをインストールしたくなったので手順をメモしておきます。

## ドキュメント
https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v2/developer-guide/setting-up-node-on-ec2-instance.html

公式で紹介されている方法が一番確実でした。

## nvmのインストール
nvmはnodeのバージョン管理ツールです。
公式サイトで推奨されているようなので利用することにしました。

GithubのREADME.mdをみてcurlコマンドでインストールします。

[nvm/README.md at master · nvm-sh/nvm · GitHub](https://github.com/nvm-sh/nvm/blob/master/README.md)

```
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.2/install.sh | bash
```

## nvmの有効化
```
. ~/.nvm/nvm.sh
```

上記のコマンドでnvmを有効化します。

## Node.jsをインストール

```
nvm install 13.2.0
```

次にNode.jsのバージョンを指定してインストールします。

```
nvm use 13.2.0
```

これで使いたいバージョンのNode.jsがインストールされました。

## ハマったこと
* nvmの有効化の時にsudo権限が必要かと勘ぐってパスワード設定ググってたけど必要なかった
* テストサーバーでディスク容量が足りなくてNode.jsインストール時になることがあった。ログを削除したら上手くいった
[PHP]クラスのプロパティーのDocコメントのannotaionの取得

## 前提
c#のattribute的な書き方をしたい

## 作ったもの
PropertyのDocCommentにhiddenがあったら、

```html
<input type="hidden" name="{property-name}" value="{property-value}"/>
```

を返します。

## 実装
まずは値を格納するだけのクラス。
ViewModelを想定しました。

```php
class ExampleViewModel extends ViewModel{
	/**
	 * 返す
	 * @hidden true
	 */
	public $hidden_prop;
	/**
	 * 返さない
	 * @oden
	 */
	public $not_hidden_prop;
	/**
	 * 返さない
	 * @hidden false
	 */
	public $false_hidden_prop;
	/**
	 * 返す
	 * @hidden true
	 */
	public $hidden_prop2;
	// 返さない
	public $no_annotation;

	function __construct(){
		$this->hidden_prop = '1';
		$this->not_hidden_prop = '2';
		$this->not_hidden_prop = '3';
		//$hidden_prop2 valueがない時も返します
		$this->no_annotation = '5';
	}
}
```

お次はhtmlを作成するクラスです。

```php
class HtmlHelper{

	/**
	 * '@hidden true'が付いたプロパティーを
	 * input tag のHTMLタグとして返す。
	 *
	 * @param ViewModel $class
	 * @return string
	 */
	public function getInputHiddenTags(ViewModel $class){
		// クラスからプロパティーを取得
		$reflection = new \ReflectionClass($class);
		$properties = $reflection->getProperties();

		$input_hidden_tags = '';
		
		// ぐるぐる
		foreach($properties as $property){

			// プロパティーのコメントを取得します

			// 下記コメントいただいた通り修正しました、ありがとうございます
			// $reflection_property = new \ReflectionProperty($class, $property->name);
			// $doc = $reflection_property->getDocComment();
			$name = htmlspecialchars($property->name, ENT_QUOTES, 'UTF-8');
			$value = htmlspecialchars($class->$name, ENT_QUOTES, 'UTF-8');

			// 正規表現の極み
			if(preg_match('/\@hidden true\s*\n/', $doc)){
				$name = $property->name;
				$value = $class->$name;
				$input_hidden_tags .= <<<HTML
					<input type="hidden" name="${name}" value="${value}" />
				HTML;
			}
		}

		return $input_hidden_tags;
	}
}
```

## まとめ
必要あらばアノテーション判定部分を切り出します。

## 参考
https://www.php.net/manual/ja/class.reflectionclass.php
https://www.php.net/manual/ja/class.reflectionproperty.php
Linuxデスクトップ環境でマウスの加速を完璧に無効化する

（おことわり）この記事は、Arch LinuxのWikiサイトに書かれていた情報を引用しただけの、個人的な備忘録のために書きました。

大半（ほぼ全て）のGUI環境（デスクトップOS／ウィンドウマネージャ等）ではマウスの加速機能が実装されています。Linuxのデスクトップ環境であるxorgにももちろんそういう機能があります。マウスの加速機能とは、マウスを机上でゆっくり動かしたときは、画面上でのポインタ（マウスカーソル）がゆっくり動き、マウスを机上で速く動かしたときには、画面上でのポインタがより長い距離動く仕組みです。

ここで問題なのは、物理的なマウスの移動距離と画面上でのポインタの移動距離が比例していないことです。普段マウスを動かしている感覚で、ちょっと離れた場所にあるボタンなどを押そうとして、通常より速い速度でマウスを動かすと、ポインタが勢い余ってすっ飛んでいき、狙った場所にマウスポインタを停止させられずに行きすぎてしまい、戻そうと思ってマウスを動かすと、反対方向にポインタが行きすぎてしまい、目的の座標をポイントするだけで3秒くらいマウスをフラフラ操作することとなり、猛烈なストレスになります。

人によっては、マウスの加速機能に容易に順応できるようですが、筆者はPC-9801の時代からマウスを使用している経験があるにもかかわらず、マウスの加速機能に慣れることができず、OSをインストールする度にイライラしています。また、ゲームのプレーヤー、特にFPSというジャンルのゲームにおいては、正確で緻密なマウス操作が要求され、マウスの加速機能が障害になることがあります。Windows環境では「ポインタの精度を高める」という設定がこれであり、このチェックボックスを外して加速機能を無効にすることが、FPSゲーマーの間で推奨されていたりします。ゲームに限らず、一般的なデスクトップGUIでも、操作性に大きく影響するのは、既に書いたとおりです。

Ubuntu 18環境では、`gnome-tweak-tool`というパッケージをインストールし、`gnome-tweaks`という設定ツールで、マウスのアクセラレーションプロファイルを「Flat」に設定することで、加速機能をオフにすることができます。それはそれでいいのですが、筆者はGnomeセッションではなく、Xfce4セッションを好んで使用しています。Ubuntu16までは設定できたはずなのに、Ubuntu18のXfce4環境でマウスの加速設定を変更しても、実際の挙動に反映されない不具合に遭遇しました。

こうなったら意地でもマウスの加速を無効にしてやるぞ！！というわけで、探して見つけたのが**[これ](https://wiki.archlinux.jp/index.php/%E3%83%9E%E3%82%A6%E3%82%B9%E3%81%AE%E3%82%A2%E3%82%AF%E3%82%BB%E3%83%A9%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3#.E3.83.9E.E3.82.A6.E3.82.B9.E3.81.AE.E3.82.A2.E3.82.AF.E3.82.BB.E3.83.A9.E3.83.AC.E3.83.BC.E3.82.B7.E3.83.A7.E3.83.B3.E3.81.AE.E7.84.A1.E5.8A.B9.E5.8C.96)**です。

/etc/X11/xorg.conf.d/50-mouse-acceleration.conf というファイルを編集します。最初はディレクトリ自体が存在しないと思いますので、ディレクトリを作成した上でファイルを作ります。

`sudo mkdir -p /etc/X11/xorg.conf.d`
`sudo nano /etc/X11/xorg.conf.d/50-mouse-acceleration.conf`

``` /etc/X11/xorg.conf.d/50-mouse-acceleration.conf
Section "InputClass"
	Identifier "My Mouse"
	MatchIsPointer "yes"
	Option "AccelerationProfile" "-1"
	Option "AccelerationScheme" "none"
	Option "AccelSpeed" "-1"
EndSection
```

これで、OSを再起動すると、マウスの加速機能を根本から絶つことができました。
WSL上のUbuntu 18.04 LTSでgit cloneができない問題への対処

# git cloneができない！(致命的)
ある日のこと。あるリポジトリをクローンしようとしたところ…

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252940/65a86ce6-5c2c-4e6a-6111-8a6fea48e42b.png)

fatal: unable to access: gnutls_handshake() failed: Error in the push function.

と言われクローンができなくなった。
さてaptもカスペルスキーのせいで止められていたので、もしやと思い…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252940/6464d911-c40f-7d77-d3c3-0288951679aa.png)
カスペルスキーの設定からHTTPSの443番ポートを無効化した。すると…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252940/a572409b-d0b0-2192-1e27-aa074f066cae.png)
クローン成功。やったぜ。
iPadのplaygroundsはプログラミングの学習ツールではなくガチの開発環境だった

パッと見で、子供でもプログラミングを学ぶことができる学習ツールに見える iPad の Playgrounds ですが、各種フレームワークも呼び出せるガチの開発環境だったので、SceneKitで3Dオブジェクトを表示するまでを紹介します。

# 新規プロジェクトの作成

<img width="768" alt="E7B50CD2-B173-4752-9B36-BB7088199426.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36064/2e7563f7-9d40-1014-adc5-0358d13a3d1e.jpeg">

Playgrounds を起動したら、左上のアイコンをタップして新しい空のプロジェクトを作成します。

# コードの入力

<img width="768" alt="8314A241-833A-4898-9706-C15D6F09DF18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36064/c20b400e-7b75-612e-6550-602486d84a59.png">

ダブルタップでソフトウェアキーボードが出てくるので下記のコードを入力します。

内容は SceneKit を使って、ライトとカメラと立方体を作成して配置しているだけのシンプルなものです。

```swift:scenekit01.swift

import PlaygroundSupport
import UIKit
import SceneKit

var sceneView = SCNView(frame: CGRect(x: 0, y: 0, width: 1000, height: 200))
var scene = SCNScene()
sceneView.scene = scene
sceneView.backgroundColor = .black
sceneView.allowsCameraControl = true
PlaygroundPage.current.liveView = sceneView

var lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light?.type = .omni
lightNode.light?.intensity = 1000
lightNode.light?.shadowMode = .deferred
lightNode.position = SCNVector3(x: 2, y: 2, z: 2)
scene.rootNode.addChildNode(lightNode)

var cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(x: 0, y: 0, z: 5)
scene.rootNode.addChildNode(cameraNode)

var material = SCNMaterial()
material.diffuse.contents = UIColor.red

var box = SCNBox(width: 1, height: 1, length: 1, chamferRadius: 0.2)
var boxNode = SCNNode(geometry: box)
scene.rootNode.addChildNode(boxNode)

box.materials = [material]
boxNode.rotation = SCNVector4(x: 1.0, y: 1.0, z: 0.0, w: 0.0)
boxNode.scale = SCNVector3(x: 1.0, y: 1.0, z: 1.0)
```

# 実行してみる

![AD7687D8-A20A-44FA-8982-2CE63B835561.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36064/b9d3114b-f882-75d9-1820-e7b777dd1211.png)

allowsCameraControll を True にしているので、ドラッグで回転とかをする事ができます。

# 最後に

エディタの反応が少し悪くイラつく事もあるのですが、 iPad だけで、ガチの swift コードが書けることに感動しました。

これで自宅外でいつでもプログラミングができます！
WSL上のUbuntu 18.04 LTSでapt updateができない問題への対処


# apt updateができない！(致命的)
ある日のこと。あまり定期的にapt updateをしていないので、久々にupdateしておくかーってことでおもむろにapt updateしたところ…

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252940/2232f700-2ef6-dfb5-e4b7-8df67179ee6c.png)

なんてこった！updateできないじゃないか！
どうして接続失敗ってなってるんだ？ブラウザからは見れるのに…あるのに…

# 紆余曲折あって
カスペルスキー(アンチウイルスソフト)のせいと分かった。aptはHTTPのポート80を使っているけど、そのポートがアンチウイルスソフトでブロックされていたのでupdateが使えなかったらしい。
ということで

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252940/7af1b731-4fc2-4c6c-ca21-cd97da38dea1.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252940/5e8c1ebd-6d04-837a-a50b-f50a2e8e2c52.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252940/7348c49a-f019-d214-9d6b-f27df3ac334f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252940/3010c283-c057-177b-9856-1e1aa75c882e.png)

この赤丸で囲ったところをクリックしていってHTTPポート80の監視を無効にして完了。
そして再びapt updateを走らせると

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252940/b0dddfad-61e8-5e4c-24f7-e7c33ca7f859.png)

助かった。

参考: https://qiita.com/YKInoMT/items/a6505b7dcc7bafeacc83
AWS EC2でCould not find pg-1.1.4 in any of the sources Run `bundle install` to install missing gems.と表示される

こんにちは[@yukifreeworld12](https://twitter.com/yukifreeworld12)です。
EC2でエラーが出て解決したのでメモとして、そして後世の同じエラーにハマった人の為にも...

#1. エラー文
EC2でGitと連携しクローンしていた終盤

```
＄ rake secret
Could not find pg-1.1.4 in any of the sources
Run `bundle install` to install missing gems.

$ gem install pg
Building native extensions.  This could take a while...
ERROR:  Error installing pg:
	ERROR: Failed to build gem native extension.
＜略＞

To see why this extension failed to compile, please check the mkmf.log which can be found here:

  /home/name/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/extensions/x86_64-linux/2.4.0/pg-1.2.2/mkmf.log

extconf failed, exit code 1
```

と長いエラー文。

#2. 解決策
解決したコマンド
`sudo yum install -y postgresql-devel`
このコマンドでpostgresql-develをインストールした後
`bundle install`でちゃんといけました。

#3.しかしその後
やりたかった`rake secret`を実行したところ...

```
$ rake secret
rake aborted!
Gem::LoadError: You have already activated rake 13.0.1, but your Gemfile requires rake 12.3.3. Prepending `bundle exec` to your command may solve this.
```

`bundle exec`と書いてあるのでbundle execを付けて
`bundle exec rake secret`としたところいけましたとさ。

##最後に
今日も見てくれてホンマありがとな!!
記事がええなと思ったらフォローといいねホンマよろしくな!!
(ジョーブログ風に)
Mac Vagrant の起動 接続 終了

# 目的

- Vagrantの基本をまとめる

# 起動

- Macのterminalを用いて下記コマンドを実行する。

    ```terminal
    $ vagrant up
    ```

# 接続

- MacのterminalからVagrantを用いて仮想マシンに接続する。
- 下記コマンドを実行して接続を行う。

    ```terminal
    $ vagrant ssh
    ```

# 終了

- `$ vagrant ssh`実行後、仮想マシンから出て、VirtualBoxを終了する。
- 下記コマンドを実行して終了する。

    ```terminal
    [vagrant@localhost]$ exit
    $ vagrant suspend
    ```
押すと色が変わるボタンの作り方を教えてください

初めましてプログラミング初心者です

個人アプリ作成しています

ボタンが押されたときにボタンの色が変わるように実装しています

教えていただける方いましたらお願いします

haml
 %input{type: "button", value: "12", class: "btn"}


js
$(function(){
  $('.btn').on('click', function(event){
      event.preventDefault();
      $(this).toggleClass('active');
  });
});

scss
input{
          width: calc(100% / 5);
          height: 40px;
          color:whitesmoke;
          margin-left: 8px;
          .btn.active{
            color: red;
            background-color: red;
          }
Prometheus Meetup #3 参加報告

Prometheus Meetup #3 参加の記録です。

https://prometheus.connpass.com/event/157721/

# Remote Write API と Thanos を活用したメトリクス永続化

https://speakerdeck.com/summerwind/using-thanos-as-a-long-term-storage-for-your-prometheus-metrics

ZLabには500以上(5~10Nodeが多め)のK8sクラスタがある。それぞれのクラスタにPrometheusがある。
ただし、永続化なし。また数週間で再作成。

Prometheusのメトリクスがノードの再作成時に失われてしまう課題があった。
180日を超える長期間のメトリクスを参照できるようにしたかった。

理想は、Prometheusは短期間のメトリクスを保持、メトリクスをオブジェクトストレージに保持

**第一案**
最初はCortexの利用を検討
アーキテクチャが複雑。オブジェクトストレージにメトリクスが保存されないため見送り

**第二案**
独自アダプターの開発
TSDBをForkし、オブジェクトストレージにChunkを保存するように修正
Remote Read/Write APIを利用

```
# 例
remote_write:
- url: xxxxxxxx
```

**Remote Write APIの注意点**
・API Endpointを複数指定しても、ラウンドロビンでの負荷分散はできない(受ける側で負荷分散する)
・エンドポイントがダウンすると、Prometheusがリトライするので、復帰してもやられてしまうことも

**第三案**
Thanos

Thanosのコンポーネント: Sidecar, Store, Query, Rule, Compact, Receive

Receiveとアダプターを組み合わせて、メトリクスをオブジェクトストレージに保存する
Receiveは複数並べて、ロードバランサーで負荷分散する

Thanos Receiveでメトリクスの冗長化もできる

**Thanos Receiveの利用の注意点**
ドキュメントが少ない

**現状と今後の課題**
・シンプルな環境においては設定したゴールをクリア
・500クラスタから受けられるようにするにはまだ工夫が必要
・複数のメトリクスが混在しないようにする


# Victoria Metricsで作りあげる大規模・超負荷システムモニタリング基盤

https://speakerdeck.com/inletorder/monitoring-platform-with-victoria-metrics

Victoria Metricsで1500億のDataPoint

コロプラのこれまでの構成: Single Tenant(ゲームタイトルごとにKubernetes環境がある)
Kubernetes: Prometheus = 1:1

負荷試験時に1/8, 1/4, 1/2, 1/1と負荷を順番にかけた時に、1/4の時点でPrometheusが死んだ:cry:

Prometheusが落ちないように、3rd-Party Productを検討

大規模環境のPrometheusのうち、TSDBへの直接アクセスでOOMが発生しやすくなっていた

Cortex, Thanos, M3DBなどを検討

Cortex: 複雑だったため見送り

Thanos: 当時の問題で通常の2倍近くメモリを消費していた(Prometheusに起因)ため、試したが見送り

M3DB: 構築コスト、学習コストが高かったため、試したが見送り

Victoria Metricsを最終的に採用！

アーキテクチャとしては、VMSelect, VMStorage, VMInsertの3つが構成要素
Scale Outも容易(VMStorageはScale InをするとDataLoss)

Consistent hashingと全StorageへのQueryへのSelect・Mergeによって、StorageのScale Outを可能にしている。

PrometheusがRead + Writeを行ってOOMが発生していた
→ PrometheusはRead(Scrape)に専念。データの集約はVictoriaMetricsに任せる。その役割分担がよく効いた

**Victoria Metricsの課題**
・VMStorageのScale Inが実質不可能
・Alert機能なし
・WebUI未実装

パラメータをいくつかチューニングしている(詳細は資料参考)

**その他工夫**
Memoryを多く使うため、スケジューリングを工夫してNodeを占有にした

Prometheusは落ちなくなったが、Grafanaは相変わらず重いまま
→ レンダリングの時間を減らすために、パネルを減らす
→ GPUの性能の良いPCを使う(!)


# 次世代のログ基盤 Grafana Lokiを始めよう！

https://speakerdeck.com/uesyn/prometheus-meetup-tokyo-3-lets-start-the-loki

Lokiはログの収集・可視化のツール

UIでのGrepもできる

Lokiのアーキテクチャ: ほぼCortexのアーキテクチャ
主要コンポーネント: Distributor, Ingester, Chunk Store, Querier, Table Manager

Lokiのコンポーネントはすべて一つのバイナリなのが特徴

マルチテナントにも対応

Prometail: Like Prometheus, but for logs.
後半はprometail.yamlの項目説明について説明(詳細は資料参照)

ログからアラートを生成
pipeline_stagesを定義する

他設定項目の説明が続くため、詳細は資料参照


## 感想

今回のテーマは、Prometheusのエコシステムということでしたが、Prometheusで解決できなかった課題を解決するための実践的な話題が多かったように感じました。
参加できてよかったです。

以上
Laravel で MySQLのTime型の最大値を超えて集計する

# やりたいこと
MySQLのTime型は
>'-838:59:59' から '838:59:59' 
にまでしか対応していません。

なので仮にDBに○○した時間をtime型で保存し、合計を取り出そうとすると上限に当たる可能性がありませす

#集計方法
MySQLのTime_TO_SEC関数を使います。
その名の通りこれは、Timeを秒数に直してくれます。
秒数に直したものを合計し、それを取得します。

取得した秒数をPHPでHH:MMに整形してあげれば、上限を超えた状態になります。

```PHP:TestController.php

public function summary()
{
    $user = User::selectRaw('SUM(TIME_TO_SEC('sleep_time')) as total_sleep_time')
      ->where('name','太郎')
      ->first();

    $time = $user->total_sleep_time;
    // HH:MM
    sprintf('%02d:%02d', ($time / 3600),($time / 60 % 60))
}
Python で任意の関数をカリー化……もどき。

Python で任意の関数をカリー化するのは、結構面倒です (参考: [Pythonでカリー化を書いてみる](https://kazuhira-r.hatenablog.com/entry/20120401/1333295408))。

ですが、呼び出し可能オブジェクトを利用して一見カリー化できているように見せかけることはできます。 カンタンナコト。

## あぁ、そんな簡単に言うな

カリー化というとラムダ式を頑張ってこねくり回したくなりますが、この方法だと Dunder メソッドの実装を工夫するだけで同様のことができます。

```python
import re

class Curried:
    def __init__(self, f, regex=None, *args, **kwargs):
        self.__f = f
        self.__regex = regex if regex is not None else \
            re.compile('{}\\(\\) missing \\d+ required'.format(f.__name__))
        self.__args = args if args is not None else ()
        self.__kwargs = kwargs if kwargs is not None else {}

    def __call__(self, *arg, **kwarg):
        cls = type(self)
        new_args = self.__args + arg
        new_kwargs = dict(**self.__kwargs, **kwarg)
        try:
            return self.__f(*new_args, **new_kwargs)
        except TypeError as e:
            if self.__regex.match(e.args[0]):
                return cls(self.__f, self.__regex, *new_args, **new_kwargs)
            else:
                raise e

    @property
    def __name__(self):
        return self.__f.__name__
```

この`Curried`インスタンスは引数を一つずつ受け取りながら元の関数の引数に満ちるまで`Curried`インスタンスを生成し続けます。 返るのはあくまでも関数ではありませんが、関数のように呼び出し可能なオブジェクトです。

## 右手上げるならその手に責任が宿ると思え

このようにして使うのだ。

```python
def add(x, y):
    return x + y

def add3(x, y, z):
    return x + y + z

print(Curried(add)(2)(3))
print(Curried(add3)(2)(3)(4))
```

```
5
9
```

一見カリー化した関数を呼び出しているように見えますね?

オブジェクトのメソッドに対しても使えます。

```python
class Foo(object):
    def __init__(self, seed=1):
        self.seed = seed

    def add(self, x, y):
        return self.seed * (x + y)

    def multiply(self, x, y):
        return self.seed * x * y

f = Foo(3)
print(Curried(f.add)(2)(3))
print(Curried(f.multiply)(2)(3))
```

```
15
18
```

また、参考記事ではできなかったカリー化関数 (しつこいようですが、こっちのは本当は関数ではないです) の使い回しもできます。

```python
add2 = Curried(add)(2)
print(add2(3))
print(add2(4))
```

```
5
6
```
【ライフハック】さくらサーバで独自ドメイン設定・リダイレクト

![4bfb974a1e877af300f0ac4a78df13e9-380x190.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348026/11d5dd3b-bdcc-d255-75eb-8abd6c0993de.jpeg)

##TL;DR
- 独自ドメイン取得後、htaccessを利用してリダイレクト設定をしました
- 結論、ここらへんの話は「信じて待つ」がいいソリューションになるよというお話です

##はじめに
http://xxx.jp にアクセスされると、
https://peraichi.com/landing_pages/view/hogehoge にリダイレクトされて欲しいです

ペライチというサービスでwebページを作ったのですが、(いつもお世話になってます)
このサービスでは、お試し期間が終わると、できることが限られてしまいます。

お試し期間中は
「独自ドメインにアクセス」->「リダイレクト」->「ペライチのページ」

をペライチから簡単にできたのですが、
お試し期間が終わると無料ではできないので

「独自ドメイン」->「さくらサーバーのhtaccessファイル」->「ペライチのページ」

というようにしなくてはなりません(課金せずに済むならしたくないですもんね)

そこで、[ここ](https://help.sakura.ad.jp/206054622/)に書いてあることをやったらハマったのでメモ。


##環境
- 執筆時は2020/1/15環境
- 独自ドメインは取得済み(お名前ドットコムなど)
- さくらサーバーを使います
    - xxx.jpをさくらサーバーに追加登録済み([こちら](https://help.sakura.ad.jp/206053802/)がわかりやすいです)


##解決につながったこと
- さくらサーバーのファイルマネージャーを開く
- ルートに'.htaccess'という名前のファイルを作成
- 中身をこれに書き換えます


```
Redirect permanent https://peraichi.com/landing_pages/view/hogehoge
```

あとは待ちます。ひたすら待ちます。

##「こういうのは待った方がいい」の理由
2点です。

- ブラウザにキャッシュされている可能性がある
- 追加ドメインの登録に時間がかかる

1点目はブラウザを変えるなどして対応すればokですが、
2点目は普通に待ちましょう。

最大48時間待つ可能性もあるみたいですが
僕の場合は追加ドメインを登録してから「は？全然リダイレクトされないやん」って~~5億回くらい~~言っていたら1時間くらいで更新されてました。
Q8.ワークシートをコピーするには？

今回はワークシートをコピーするマクロを作っていく方法を考えていきます。
前回も使用した以下の画像をご覧ください。

![7-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560479/d5972b4d-2b4c-9a0c-78de-c1ec932f9ebc.png)

この画像では、田中、高橋、山田という個人のデータを取り扱ったシートがあります。

ここに新たに別の人のシートを追加するというマクロを作っていきましょう。
追加の元となるデータは田中のシートとなります。
田中のシートをコピーしてデータを書き換えていきます。


###■ポイント
ポイントとなるのは、ワークシートをコピーするにはどういう記述をするか？というところです。
今回は以下のメソッドを使います。

Worksheets("田中").Copy After:=Worksheets(Worksheets.Count)

これは、田中というシートを末尾にコピーするという意味になります。
Worksheets.Countというのは、ワークシートの数を表しています。
Afterへこれを指定することにより、末尾に指定したシートをコピーすることができます。



###■回答
```VB
Sub Q8_Answer()
    Dim i As Integer
    For i = 1 To 10
        Worksheets("田中").Copy After:=Worksheets(Worksheets.Count)   ' 末尾に追加
        ActiveSheet.Name = "サンプル" & i
        ActiveSheet.Range("B3").Value = "サンプル" & i
        Randomize
        ActiveSheet.Range("C3").Value = Int(100 * Rnd + 1)
        ActiveSheet.Range("D3").Value = Int(100 * Rnd + 1)
        ActiveSheet.Range("E3").Value = Int(100 * Rnd + 1)
    Next i
End Sub
```
###■解説
今回はfor文を利用して、10個のシートを作成しています。

ActiveSheet.Range("C3").Value = Int(100 * Rnd + 1)
ActiveSheet.Range("D3").Value = Int(100 * Rnd + 1)
ActiveSheet.Range("E3").Value = Int(100 * Rnd + 1)

この3行は何をしているかというと、乱数で得点となるデータを取得しています。
これは、１～100の間の整数を指定のセルへ格納することを意味しています。

これで、サンプル1～サンプル10までの10人分のダミーデータができました。
しっかりと点数まで入っています。

ただし、このマクロ、1つだけ注意があって、同じことを2回できないことです。

つまり、このマクロは2回目に実行した時にはエラーとなります。

なぜなら、すでにサンプル１～10というシートが存在するからです。
エクセルは同名のシートは共存することができません。
一意の名前である必要があるのです。


最後のマクロを実行した後のエクセルの画像を載せておきます。

![Q8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560479/6006c0fd-7a39-4f7b-d687-85c97b75f428.png)



画像では切れていますが、しっかりとサンプル10まで作成されています。

国語1点とか英語6点とかはちょっとひどい有様ですね・・・
数学バカみたいなデータが作成されてしまいました(笑)
初心者によるプログラミング学習ログ 211日目

# 100日チャレンジの211日目

twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。

100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。

211日目は

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">おはようございます<br>211日目<br><br>udemyでjavascript<br><br>あんまりやった感がない<a href="https://twitter.com/hashtag/100DaysOfCode?src=hash&amp;ref_src=twsrc%5Etfw">#100DaysOfCode</a> <a href="https://twitter.com/hashtag/%E9%A7%86%E3%81%91%E5%87%BA%E3%81%97%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%A8%E7%B9%8B%E3%81%8C%E3%82%8A%E3%81%9F%E3%81%84?src=hash&amp;ref_src=twsrc%5Etfw">#駆け出しエンジニアと繋がりたい</a> <a href="https://twitter.com/hashtag/%E6%97%A9%E8%B5%B7%E3%81%8D%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8?src=hash&amp;ref_src=twsrc%5Etfw">#早起きチャレンジ</a></p>&mdash; ぱぺまぺ@webエンジニアを目指したい社畜 (@yudapinokio) <a href="https://twitter.com/yudapinokio/status/1217176282053500929?ref_src=twsrc%5Etfw">January 14, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
Linuxのディスク丸ごとデータ移行をSSH経由で行う話

パソコンの買い替えを行い、新しい環境にSSH経由でディスクを丸ごとデータ移行したのでそのメモ

## なぜ必要になったのか
* パソコン買い換えを行ったが、新しい環境にはUbuntuをクリーンインストールしたかった
* 古いパソコンは返却する必要が有り、システムファイル丸ごと新環境に取り込みたかった
    * 最悪の場合仮想環境で古い環境を再現できるように
* SSDを引っこ抜いてもアダプタが無いのでLAN経由で行いたかった

## どのように実施したか
ddコマンド実行しデータをssh経由で転送、それをmountするだけです。

### データのコピー
古い環境の方からddコマンドを実行し、新しい環境に転送します。
私の環境では新しい環境から実行したらデータが正常に転送できませんでした。
（hexdumpしてみた所、データの並びが変わってました。Endian関連を疑いましたがどうなんでしょう）

```bash
dd if={device} | ssh {user}@{host} dd of={file}
```

#### user
* リモート先のユーザ名

#### host
* リモートのホスト名 or IPアドレス

#### device
* ダンプするデバイス名
    - Ex) /dev/sda1

#### file
* 作成するイメージファイル名

### マウント

```bash
sudo mount -t auto -o loop {file} {mount_point}
```

#### file
* 作成したイメージファイル名

#### mount_point
* マウントする先のディレクトリ
Redash APIで動的に結果を取得する

# 前提
- Redash 10.0.0

※ Redash 2.0.0+b2990の際に書いた記事でしたが、上記バージョンに挙げても同様でした。

## 記事中の記法
- `<host>`はRedashのホストを意味します。たとえば、あなたの環境のRedashのGUIにアクセスする際、 `https://www.example.com/redash/` にアクセスしているのなら、これがホストです。`<host>/api` と記載した場合、`https://www.example.com/redash/api`を意味します。
- その他、`<>`で囲った文字は適宜変数を意味します。`<query_id>` 等

# User API Keyを取得
メニュー>ユーザー名＞API Key
![redash01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102032/311de1ff-5d4a-8224-6da4-9655e3f8c627.png)

# クエリを実行
以下のURIをPOSTすると、クエリを実行できます。

```
<host>/api/queries/<query_id>/refresh?api_key=<user_api_key>
```

## クエリ中にパラメータがある場合
クエリ中のパラメータは`p_<parameter_name>=<value>`の形式でURLクエリパラメータとして渡します。
たとえば、

```sql
select
  *
from
  users
where
  user_id = {{user_id}}
```

というクエリを、`user_id=12345`で実行する場合、POSTするURIは、以下のようになります。

```
<host>/api/queries/<query_id>/refresh?p_user_id=12345&api_key=<user_api_key>
```


## 応答
以下のようなJSONが返ってきます。

```json
{
  "job": {
    "status": 2,
    "error": "",
    "id": "XXXXXXXXXXX",
    "query_result_id": null,
    "updated_at": 0
  }
}
```

※以降、上記のJSONの`job.id`の値を`<job_id>`として扱います。

# ジョブの状態を取得
以下のURIをGETするとジョブの状態を取得できます。

```
<host>/api/jobs/<job_id>?api_key=<user_api_key>
```

応答は`/api/queries/<query_id>/refresh`と同じ形式です。
ジョブが終了していれば、`query_result_id`に値が設定されます。
`query_result_id`の値が`null`の場合は、ジョブの終了を待つ必要があります。

# ジョブの結果を取得
以下のURIをGETすると、ジョブの結果が取得できます。

```
<host>/api/queries/<query_id>/results/<query_result_id>.json?api_key=<user_api_key>
```
ファイルの拡張子は`.json`のほかに`.csv`があります。

# スニペット（GAS用）
…を踏まえたコードをGAS用に書くとこうなります。

```JavaScript
/**
 * 
 * @param {String} host https://redash.example.com 的なもの。末尾にスラッシュはつけないでください。
 * @param {String} queryId 123等
 * @param {String} apiKey 
 * @param {any[]} param クエリのパラメータの連想配列
 */
function callRedash(host, queryId, apiKey, param) {
    let queryParams = [`api_key=${apiKey}`]
    if (param) {
        for (let key in param) {
            const queryParam = `p_${key}=${param[key]}`;
            queryParams.push(queryParam);
        }
    }
    const refreshUri = `${host}/api/queries/${queryId}/refresh?${queryParams.join('&')}`;
    const refreshResult = UrlFetchApp.fetch(refreshUri, { "method": "POST" });
    const jobId = JSON.parse(refreshResult).job.id;

    const jobStatusUri = `${host}/api/jobs/${jobId}?api_key=${apiKey}`;
    let queryResultId = null;
    const startMills = new Date().getTime();
    while (true) {
        const endMills = new Date().getTime();
        if (endMills - startMills > (4 * 60 * 1000)) {
            // GASの実行時間上限は5分なので、4分経過した時点で中断します。
            throw new Error("Redashへの問い合わせ開始から4分以上経過したため、中断します。");
        }
        const jobStatus = JSON.parse(UrlFetchApp.fetch(jobStatusUri)).job;
        const status = jobStatus.status;
        if (status === 3 || status === 4) {
            queryResultId = jobStatus.query_result_id;
            break; // 結果を取得できたのでbreak
        }
        Utilities.sleep(5000); //  5秒待機
    }

    const jobResultUri = `${host}/api/queries/${queryId}/results/${queryResultId}.json?api_key=${apiKey}`;
    const result = JSON.parse(UrlFetchApp.fetch(jobResultUri));
    return result.query_result.data.rows;
}
```
PythonでOSの空きポート番号を取得する

ユニットテストで一時的なサーバプロセスを立ち上げたりする際にポート番号がバッティングしないようにしたかった。

`psutil`パッケージを使用する。

```shell
$ pip install psutil
```

```python
import psutil


def unused_portnumber(start=49152):
    # "LISTEN" 状態のポート番号をリスト化
    used_ports = [conn.laddr.port for conn in psutil.net_connections() if conn.status == 'LISTEN']
    for port in range(start, 65535 + 1):
        # 未使用のポート番号ならreturn
        if port not in set(used_ports):
            return port
```

ちなみに[RFC](https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml)によると ダイナミック/プライベートポート番号の割当ては**49152番以降**らしい。
【#PowerAutomate】Excel から ブログの記事を自動生成してメールで送る方法

# 概要

Excel のテーブルに書かれた情報を元に ブログの記事ファイルを1日1回自動生成し、メールで送ります。

このアーキテクチャは Microsoft アカウント(outlook.jp)または企業アカウントや有料ライセンスが必要です。詳しくはこちらをご参照ください。
[個人で無料で始める Microsoft Flow](https://www.powerplatform.work/blog/2019/06/23/%E5%80%8B%E4%BA%BA%E3%81%A7%E5%A7%8B%E3%82%81%E3%82%8BMicrosoft-Flow/)

個人アカウントでも作成可能ですが、SLA がないので、実行に失敗することもあります。（ほとんど起きませんが。）

# アーキテクチャ

この仕組みは私のブログでも利用し、RSS や Tweet 等を取得し、ファイル生成するのに役立っています。(ブログは GitHub Pages を利用し作成している為、Markdownファイルでの記事投稿を行っています)
https://www.powerplatform.work/blog/

その為、仕様として、
「1日1回 18時にその日に投稿するブログ記事のファイルを添付ファイルとして複数のメールで送信する」とします。

![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183354/0d7c0cff-a51b-74e1-3074-da7a1b4a87e0.png)

今回はわかりやすさと汎用性の高さを優先で、トリガーにスケジュールトリガーを用いていますが、別のトリガーにすることも可能です。（例えば、あるブログが更新された時や位置情報がとか、HTTP Request時等。ただし、有料ライセンスが必要なものも存在します。）

# 作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183354/a00e9f8a-18bf-1c2b-9086-4e4082e86bcd.png)

こちらが Automate の全体像になります。

まずは Excel の準備を行いましょう。

## Excel を用意

お使いの OneDrive に Excel ファイルを配置、作成します。
今回は AutoBlog.xlsx を作成しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183354/71435b89-475c-909d-0517-b48cfc2d7a3d.png)

続いてテーブルを用意します。
Power Automate から Excel のデータを取得するには、テーブル形式からしか取得できません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183354/96facc1a-7f58-3256-f401-f6fefe378fac.png)

カラムは自由で構いませんが、同じ記事が何度もメール送信されるのは面倒ですので、「pushDay」等の投稿日付(ODATA フィルターを行うため、できればデータ型標準で[yyyyMMdd]形式で保存しておくと良い)が分るカラムを作成しておきましょう。
レコードを一意に特定するための ID 列等もあると後々、レコードを検索するのに役立ちます。

## Automate の解説

### 時刻
トリガーは時刻トリガー（スケジュールトリガー）を選択します。
当日に投稿したい内容を取得するので、「現在の時刻」を選択します。ただし、ここで取得できる時刻は UTC の為、「タイムゾーンの変換」を利用し、日本時間に変換します。また書式の設定として、[pushDay]と同じ書式にします。今回は **yyyyMMdd** としました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183354/bea8a3a3-ff32-38b6-aafa-0b12189c21af.png)

### Excelからデータを取得する

フィルタークエリである、OData を用いてその日に投稿するレコードだけに絞ったデータを取得します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183354/0496f903-bff1-68c9-e630-ec66ac4bd102.png)

書き方はこちらをご参照ください。
https://personium.io/docs/api/1.3.25/Japanese/docs/ja/rest_api/common/common_query/FilterQuery.htm

注意点として、 ge や le といった一部クエリは対応していません。基本的には eq で検索を行う必要があります。

### 記事を生成し、メールで送信

今回利用している私のブログで利用しているフレームワークの仕様がこのようになっている為、作成しているデータもこのようになっていますが、ここはご自身の形式に合わせて「作成」と「添付ファイル名」を設定してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183354/4e84bf98-36e2-ea8b-3d74-5746c5d6c8c3.png)


## 完成

テストデータを作成し、添付ファイル付きのメールが送られてくることを確認しましょう。

# まとめ

今回は ブログ記事を作成する内容ですが、Tweet や社内への周知、定期的な投稿などにも役立つ仕組みですので、ぜひチャレンジしてみてください。
次回以降で用意した Excel にコンテンツを追加する仕組みを作ります。