OmniAICreator/Qiita-1.07M huggingface dataset:
オンラインゲームでよく聞くDDoS攻撃について0から学ぼう！

# DDoS攻撃とは？
複数のマシンから、対象のコンピュータに対して大量の処理負荷を掛けることで、サービスを機能停止状態へ追い込む手法。サーバーへ大量のリクエストを送り、サーバーダウンさせてしまう。通称F5アタックとも呼ばれます。
![internet_ddos_attack.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840696/6b852d27-7823-e865-1495-d1559d864437.png)

#SYNフラッド攻撃
まずDDos攻撃には様々な攻撃方法があります。今回はSYNフラッド攻撃について紹介します。
データを送受信する仕組みであるTCPを理解する必要があります。詳細は[こちら](https://qiita.com/miumi/items/b485c23dad94ca9da973)をご覧ください。
###通常のTCPのイメージ
![スクリーンショット 2020-12-09 9.28.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840696/54f73944-562e-0112-1dcb-23d932713dfb.png)
**SYNフラッド攻撃のやり方は下記の通りです。**

1.悪い奴がデータ送っていい?という確認（SYN）を大量に送信する。
↓
2.サーバーは受け取ったSYNに対して「自分はOKだよ！こっちもデータ送っていい？(SYN+ACK)」を送り続けます。
↓
3.ここで悪い奴は「こっちもOKだよ！(ACK)」を送らないのでサーバーは永遠と存在しないユーザーの応答を待ち続ける事になります。
↓
4.応答を待ち続けるけど、新たにデータ送っていい?という確認（SYN）は受け続けるのでサーバーが重くなります。
###SYNフラッド攻撃のイメージ
![スクリーンショット 2020-12-09 9.28.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840696/49987b0a-03ae-ae46-3f68-777e6c4eedda.png)


#攻撃する理由
### 交渉のタネにする
DDos攻撃の中止を条件にして金銭を要求する目的で行われることがあります。
業務に影響が出てしまうとまずいのでやむおえず交渉に応じてしまうパターンです

### 嫌がらせ
何らかの恨みを持って仕掛ける場合や、何の恨みも無く、ただ状況を楽しんでいる愉快犯など様々。
ちなみにDDoS攻撃だけでは、システムの破壊、改ざん、盗聴などはできません。

###別のサーバー犯罪のおとり
DDoS攻撃に意識を向け、別のコンピュータからのシステム破壊、改ざん、盗聴などをバレないように行おうとするため。
DDoS攻撃を受けてしまった場合、システム管理者はDDoS攻撃だけに注意を向けずに、DDoS攻撃以外の攻撃が発生していないかを確認することも大切となるでしょう。

### 抗議活動
特定の団体や法人、政府に対しての抗議活動として利用する。DDoS攻撃がニュースになれば多くの人が注目するでしょう。


# 対策
DDos攻撃を0にするのは非常に難しい問題です。
DDos攻撃で有名な事件の１つである[FF14](https://jp.finalfantasyxiv.com/lodestone/news/detail/60713eb72c1afa8b2500135ed5c414cac33c2ca6)の記事例えが分かりやすかったので引用します。

>たとえば、コンサートなどの入場口に、「偽のチケット」を持った人間を「大量に並ばせ」て、入場管理スタッフや、待機列管理スタッフの仕事を麻痺させるようなものです。様々な場所から同時に並びにくるため、命令している人を特定するのも、事前に食い止めるのも難しいといったイメージです。
(finalfantasyxiv.comより引用)

このように事前に誰が悪いやつか特定するのが難しいのが現状です。
最近ではCDN（Content Delivery Network）を活用した対策方法も有効とされてます。
CDNは簡単に言うと負荷を肩代わりしてくれるレンタルサーバのようなものです。一部の負荷を肩代わりしてもらうおかげで自分のサーバの負荷が下がり、安定してサービスを提供できるようになるわけです。
###CDNなしイメージ
![スクリーンショット 2020-12-09 10.29.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840696/f1db4b8f-7567-1838-9924-22bae5ffe5af.png)

###CDNありイメージ
![スクリーンショット 2020-12-09 10.29.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840696/542c9cbd-4fc8-fa81-514f-5014c98c405f.png)


続きまして、アルサーガパートナーズ Advent Calendar 2020 17日目の記事は、@Takamasa_Fukase さんです
Amplify CLIで「No credentials found for appId」が発生する

## 初めに
`amplify env checkout prod` でenvを切り替える際に
`No credentials found for appId: hoge`というエラーが発生してしまい
環境が切り替えられなくなってしまいましたので、対処法をメモしておきたいと思います。

```
% amplify env checkout prod
⠋ Initializing your environment: prod
No credentials found for appId: hoge
If the appId is correct, try running amplify configure --appId hoge
```

※本記事のhogeは全て自分のappIdに置き換えてください

## 原因
AmplifyのAdmin UI managementをOnにしてしまったのが原因だと思われます。

## 試したこと

#### エラー内容で指定されたコマンドを実行

```
amplify configure --appId hoge
```
→ 一通り入力するが変化なし。

#### 以下で挙げられているコマンドを実行
https://github.com/aws-amplify/amplify-cli/issues/6084

```
% amplify pull --appId hoge --envName prod
⠋ Fetching updates to backend environment: prod from the cloud.
No credentials found for appId: hoge
If the appId is correct, try running amplify configure --appId hoge
```
→ こちらも同じく変化なし

## 解決した方法

1. Amplify > アプリの設定 > Admin UI management の Access control settings から 「Invite users」 でユーザを作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52392/19104315-1c28-dc85-b813-3928a3a8873f.png)

2. 以下のURLにアクセスしログインすると、CLIとの連携に失敗した旨とコマンドが表示される
https://ap-northeast-1.admin.amplifyapp.com/admin/hoge/prod/verify/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52392/8064b1c9-83c9-070a-2d1a-387a404f42c5.png)

3. 指定されたコマンドを実行する

```
% amplify configure --appId hoge --envName prod
Opening link: https://ap-northeast-1.admin.amplifyapp.com/admin/hoge/prod/verify/
✔ Successfully received Amplify Admin tokens.
```

成功。
これで正常に動きました。

## 参考
https://github.com/aws-amplify/amplify-cli/issues/6084
rex0220 休日プラグイン

kintone 休日アプリ専用のプラグインです。
日本の祝日を取得して、テーブルに設定します。
[休日Plusプラグイン](https://qiita.com/rex0220/items/197cdc31b0bb928b4cdb)で休日アプリを参照して、休日をカレンダーに表示します。

# 概要

休日プラグインは、[holiday_jp-js](https://github.com/holiday-jp/holiday_jp-js)により対象年の日本の祝日を取得して、テーブル行に設定します。
休日アプリに、年毎に祝日・休日・その他の日付をレコード登録します。

- 休日アプリのレコード
![2020-12-16_08h58_27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/92101c1d-0cc1-0701-345d-dc9e255dbb38.png)

- 休日アプリのレコード一覧
![2020-12-16_01h12_41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/461caee2-de4f-466a-29d1-54bdfe3cae6a.png)

# 休日Plusプラグインとの連携

休日Plusプラグインで休日アプリを参照して、休日をカレンダーに表示。
休日アプリの休日をカレンダーアプリに連携して、カレンダーに休日を表示します。

- カレンダー表示画面
![2020-12-16_01h16_11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/c93763b2-80e3-b332-8ce5-55e174b0daa8.png)

休日Plusプラグインで休日アプリを参照して、休日を[カレンダーPlus](https://radical-bridge.com/product/calendarPlus.html)に表示

- カレンダーPlus表示画面
![2020-12-16_01h16_28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/827a2fd3-0ab5-5f3d-6db0-3852c77dd438.png)

# 休日アプリ

休日テンプレートよりアプリを作成します。
年毎に祝日・休日・その他の日付をレコード登録します。

- 「祝日データを取得」ボタン：　休日プラグイン実行。
    - テーブル内の区分が祝日の行を削除し、祝日のテーブル行を作成
- カレンダー名：　任意の名称。規定値：「CALENDAR」
- 年：　対象年
- 国：　カレンダー識別用
- カレンダー年：　「カレンダー名＋対象年」でユニークチェック
- テーブル
    - 日付：「年」内の日付を指定
        - 複数行に同じ日付を指定した場合、「祝日」>「休日」>「その他」の優先順位
    - 曜日：自動設定
    - 区分：
        - 祝日：「祝日データを取得」ボタンで設定
        - 休日：会社の休日等を指定
        - その他：記念日等を指定
    - 名称：祝日・休日等の名称
    - 名称（日）：祝日・休日等の名称（日本）
    - 名称（英）：祝日・休日等の名称（英語）
    - 名称（中）：祝日・休日等の名称（中国）

![2020-12-16_00h04_50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/5405ae63-dab7-3c03-c487-f202e0f7d186.png)

# 休日プラグイン

rex0220 stores より、休日プラグインをダウンロードし、kintone にインストールします。

![2020-12-16_00h57_59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/dcbc8f7e-8d3f-41c6-99d2-fe428a8052fe.png)

休日アプリには、休日プラグインが設定済みです。

![2020-12-16_00h59_35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/656ec419-3d7e-0f3b-3ffa-18f234be9d88.png)

休日アプリの休日プラグイン設定画面
設定項目はありません。

![2020-12-16_01h01_35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/a1322a4f-0d88-cb6f-4ad2-64da3b7ff869.png)

## 休日テンプレート

rex0220 stores より、休日テンプレートをダウンロードし、アプリを作成します。

休日プラグイン用アプリを作成するためのテンプレートファイルになります。
このテンプレートから作成されたアプリで、休日プラグインが動作します。

下記の手順で、テンプレートファイルからアプリを作成してください。

[kintone ヘルプ テンプレートファイルからアプリを作成する](https://jp.cybozu.help/k/ja/user/create_app/app_csv/add_app_template_file.html)


## 休日レコードの作成

カレンダー名毎に必要な年数文のレコードを作成します。

![2020-12-16_01h12_05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/a9ca7ce8-7f2c-5e30-2a8f-1f8b1f9a02b5.png)

## 項目の追加・変更について

項目の追加：　必要に応じ追加して下さい。
項目の変更・削除：　アプリ作成時からある項目は、変更・削除不可です。

# 注意事項

- 休日プラグインは、休日テンプレートから作られた休日アプリ専用プラグインです。
【Laravel】validateメソッドを用いたバリデーション方法 

# validateメソッドとは
Laravelではフォームバリデーション機能が提供されており、validateメソッドはその内の一つです。
実体はIlluminate\Http\Requestクラスのメソッドです。

ちなみに、Illuminateは`vender/laravel/framework/src/Illuminate`にあります。

# validateメソッドによるバリデーションの実装方法
## viewの作成
viewを作っていきます。

```resources/views/test.blade.php
<form action="submit" method="post">
    <div>
        <label for="title">タイトル：</label>
        <input type="text" id="title" name="title">
    </div>
    <div>
        <label for="body">本文：</label>
        <input type="text" id="body" name="body">
    </div>
    <div>
        <input type="submit" value="送信">
    </div>
    @if ($errors->any())
        <div>
            <ul style="list-style: none;">
                @foreach ($errors->all() as $error)
                    <li style="color: red; font-size: 14px;">{{ $error }}</li>
                @endforeach
            </ul>
        </div>
    @endif
    {{ csrf_field() }}
</form>
```

`$errors`はLaravelの定義済み変数です。
バリデーションエラーが発生すると、自動的に`$errors`にエラーメッセージが格納されます。
`@foreach`で取り出して使いましょう。

ちなみに、`@csrf`を書き忘れると、419エラーになってしまうのでちゃんと書きましょう。

参考：【Laravel5】たまに出てくる「the page has expired due to inactivity. please refresh and try again」を表示させない
https://qiita.com/sola-msr/items/8a0ea0abe510245760ac

遷移先ページは以下の感じです。

```resouces/views/submit.blade.php
<p>submitted!!</p>
```

## Controllerの作成
TestControllerを作成します。

```
php artisan make:controller TestController
```

メソッドを書いていきます。

```app/Http/Controller/TestController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class TestController extends Controller
{
    public function index()
    {
        return view('test');
    }

    public function submit(Request $request)
    {
        // バリデーションルールの定義
        $rules = [
            // titleとbodyに入力必須
            'title' => 'required|min:3|max:5',
            'body' => 'required|min:1|max:10',
        ];

        // バリデーション実行
        $request->validate($rules);

        return view('submit');
    }
}
```

`$rule`に連想配列でルールを定義し、`$request->validate($rules)`でバリデーションを実行しています。

バリデーションルールは、Laravelで定義済みのルールを適用できます。
定義済みルールの一覧は、以下の記事が参考になるのでどうぞ。

参考：Laravelのバリデーションで指定できる内容をざっくりまとめ直しました。
https://qiita.com/fagai/items/9904409d3703ef6f79a2

バリデーションの実行は、`$request->validate($rules);`の一行で完結です。
OKの場合は処理を続行、NGの場合はリダイレクトの処理を自動でやってくれます。

裏の処理をほとんど意識せずに実装できてしまいますね。

## ルーティングの作成
TestControllerのルートを通します。

```
Route::get('/', 'TestController@index');
Route::post('submit', 'TestController@submit');
```

## 表示の確認
以下のようなフォームができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599831/314c9dc2-b557-14bf-c8ba-36aa0d4bdb40.png)

何も入力せずに送信ボタンを押してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599831/e0fe7134-e570-3aa8-b92d-a4e61d916166.png)
このようにエラーメッセージが表示されます。

バリデーションルールを満たすように、フォームに値を入れて送信ボタンを押すと、問題なく次ページに遷移します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599831/b714d8c2-8bf4-eee8-a077-1b144bbc7a4e.png)
Windows の Explorer で、位置が離れたファイルを一括で選択したいんだけど？

記事を探すのが面倒だったのでメモ。人に見せる用。

# ◤ TL;DR

CtrlキーとSpaceキーを使おう。

![20201216083518.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253921/d481b383-8460-5c4e-06bf-be995f6ff2f7.gif)

もしくは、（ファイル名 or 拡張子で判別できるなら）エクスプローラーの絞り込み機能を使おう。

# ◤ 説明

- `Shift` キーを長押ししながら、方向キーで複数選択できるのを知っている人は多いと思います。しかし、この方法はファイル／フォルダがエクスプローラー上で隣接している場合にしか使えません。
- `Ctrl` キーを長押ししながら、マウスクリックで複数選択できるのを知っている人もいると思います。しかし、この方法は何となく面倒です。
- キーボードから手を放したくないなら、次の方法を試してください。

## とりあえず複数選択したいとき

- 対象のファイル／フォルダのうちのひとつを選択します。
- その状態で `Ctrl` キーを長押しし、それを維持します。
- `Ctrl` キー長押しのまま、方向キーを動かし、フォーカスを移動します。
- 対象のファイル／フォルダにフォーカスが移ったら、`Space` キーを押下します。
    - さらにほかの対象を選択したい場合は、`Space` キーから指を離す際、`Ctrl` キーから指を離さないように注意してください。
- `Ctrl` キーを押したまま、フォーカスを移動し、`Space` キーで選択をトグルしていきます。
    - 選択済みの対象上で、`Space`キーを押下すると、選択が解除されます。
    - また、未選択／選択解除済みの状態で `Space` キーを押下すると、対象が選択されます。

## 複数選択したうちのいくつかを除外したいとき

- 対象のファイル／フォルダ群の先頭／終端を選択します。
- `Shift` キーを押しながら、方向キーで選択範囲を広げていきます。
- 任意の対象を含むファイル／フォルダ群を選択し終えたら、`Shift` キーを離したあと、そのほかのキー／マウス操作をせずに、`Ctrl` キーを長押しします。
- `Ctrl` キーを長押ししたまま、方向キーでフォーカスを移動します。
- 除外対象にフォーカスが移ったら、その場所で `Space` キーを押下し、選択状態をトグルします。
- 同じ要領で、選択中の対象群から、任意の対象を除外／再選択できます。


# ◤ さいごに
意味が分かりにくいところがあれば、コメント／編集リクエストで、ご指摘・ご提案いただければと思います。


## 謝辞

執筆にあたり、以下の OSS にお世話になりました。ありがとうございます。

- 画面の録画：　https://github.com/NickeManarin/ScreenToGif/
- キー操作の表示： https://github.com/mieki256/tinyosdkey
メモ：完全数と２進数

完全数を２進数表現すると

| 10進 | 2進 | 対応素数 |
|--:|--:|:-:|
| 6 | 11 0 | $3 = 2^2-1$ |
| 28 | 111 00 | $7 = 2^3-1$ |
| 496 | 1 1111 0000 | $31 = 2^5-1$ |
| 8128 | 111 1111 00 0000 | $127 = 2^7-1$ |
| 33550336 | 1 1111 1111 1111 0000 0000 0000 | $8191 = 2^{13}-1$ |
| 8589869056 | 1 1111 1111 1111 1111 0000 0000 0000 0000 | $131071 = 2^{17}-1$ |
| ... | ... | ... |

なので、完全数の（自身を除く）約数は「素数となる $\left( 2^m-1 \right)$」と「$2^n \left[ n:0,1, \cdots, \left( m-1 \right) \right]$」の組み合わせで、約数の総和が完全数になることが、シフト演算（$2^n$ の約数は 2 のみ）のお陰で直感的にわかる。「496」を例にすると

| 10進 | 2進(A) | 2進(B) |
|:-:|--:|--:|
| $1 \times 496$ | 1 | 1 1111 0000 |
| $2 \times 248$ | 10 | 1 1111 000 |
| $4 \times 124$ | 100 | 1 1111 00 |
| $8 \times  62$ | 1000 | 1 1111 0 |
| $16 \times 31$ | 10000 | 1 1111 |

列(A) の総和 $31_{10進} = 11111_{2進}$ に、列(B) の下から順に加えていくと、左シフト操作の連続になります。上から二番目まで加えたら、一番上と同じになります。値を気にせず 0,1 の並びを操作する感じになります。
gccとclangのエラーメッセージに関する所感

clangはgccよりエラーメッセージが良いという話を聞いたことがあったのですが、先日なるほどと思う出来事がありました。
エッセンスとしては以下のようなコードをコンパイルしたときのことです。

```Foo.cxx
#include <iostream>

void foo(int i)
{
	std::cout << "foo(int)" << std::endl;
}

class Foo
{
public:
	void foo();
};

void Foo::foo()
{
	std::cout << "Foo::foo()" << std::endl;
	foo(0);
}
```

判るだろ？俺の意図を汲めよ！と思わないでもないですがエラーになります。
g++は

```
sample.cxx:17:7: error: no matching function for call to ‘Foo::foo(int)’
  foo(0);
       ^
sample.cxx:14:6: note: candidate: void Foo::foo()
 void Foo::foo()
      ^~~
sample.cxx:14:6: note:   candidate expects 0 arguments, 1 provided
```

と言ってくるのですがclang++だと

```
sample.cxx:17:2: error: too many arguments to function call, expected 0, have 1; did you mean
      '::foo'?
        foo(0);
        ^~~
        ::foo
sample.cxx:3:6: note: '::foo' declared here
void foo(int i)
     ^
```

言語仕様上エラーにしなければならないのは同じですが「お前は **::foo** と言いたいのか？」と察してくれます。
それにclangは関数呼び出しの始まり（関数名の１文字目）を発生場所として指しているのに対して、gccは終わり（閉じ括弧）を指しています。

バージョンはそれぞれg++ 7.5.0とclang 6.0.0です。
Javascriptの関数や引数について

# Javascriptの関数や引数について

##  関数



```js:callName.js
console.log('太郎起きなさい！'); // 太郎起きなさい！
console.log('太郎起きなさい！'); // 太郎起きなさい！
console.log('太郎起きなさい！'); // 太郎起きなさい！
```

例えばこのようなjsファイルがあるとする。

<b>次郎起きなさい!</b>  と表示させたくなった場合

```js:callName.js
console.log('次郎起きなさい！'); // 次郎起きなさい！
console.log('次郎起きなさい！'); // 次郎起きなさい！
console.log('次郎起きなさい！'); // 次郎起きなさい！
```

上記のように <b>3回 次郎起きなさい! と書き換えなければならない</b>ので面倒。

つまり、コードの修正が大変になる。

なので、このような場合は<b>関数</b>を使用すると便利！！

```js:callName.js
function callName(){
  console.log('次郎起きなさい！');
}

callName(); //　次郎起きなさい！
callName(); //　次郎起きなさい！
callName(); //　次郎起きなさい！
```

上記のように、callName() という関数をあらかじめ定義する。

関数を定義することで、関数の中身だけを修正するだけで済むので保守性が向上する！！

##  引数

関数の中の一部分だけを変えたい場合、<b>引数</b>が便利。

例えば、<b>太郎</b>起きなさい！ <b>次郎</b>起きなさい！ <b>三郎</b>起きなさい！　という感じに一部分だけ変えたくなったとする。

こういう場合は、

```js:callName.js
function callName(name){           // 関数を定義する際に渡す引数(name)を  仮引数  という。
  console.log(` ${name}起きなさい！ `);
}

// 関数を呼び出す時に渡す引数(太郎)を　実引数　という。↓

callName('太郎'); // 太郎起きなさい！  
callName('次郎'); // 次郎起きなさい！
callName('三郎'); // 三郎起きなさい！
```

上記のように callName という関数と仮引数 name を定義する。

そして関数の中身で、引数として渡された値を展開する。

そうすることで、関数の中身の一部分を実引数として渡した値に変えることができる。
Python pandasでExcel集計 その2 可変引数

##モチベーション
[Python pandasでExcel集計 その1](https://qiita.com/atmaru/items/f895d30ab188eda468dd)の続きです。
dictを繋げる関数を2回呼び出している箇所がダサい。1関数にしたい。
解決策の1つとして、可変引数化する。

##環境
windows10
python3.9
VS Code
Pandas
openpyxl

##準備
python、pandasのinstall(pip使ってね)は済んでる前提

## 早速答え

#### pandas_lib.pyで2関数定義
dict型の引数を複数持てる関数concatenateDictsを追加。

``` pandas_lib.py
import pandas as pd # pandasは、Pythonにおいて、データ解析を支援する機能を提供するライブラリ
import numpy as np

# keyでGroupingしてカウント
def countByKeyFromFileAndSheet(filename, sheetname, key):
  df = pd.read_excel(filename, sheet_name=sheetname, engine="openpyxl")
  dict = df[key].value_counts().to_dict()
  return dict

def concatenateDicts(*dicts):
  newdict = {} # empty dict

  for dict in dicts:
    print(dict)
    for k in dict:
        if k in newdict: # key detected in newdict
          newdict[k] += dict[k]
        else: # not detected
          newdict[k] = dict[k]  
  return newdict
```

#### pandas_main.py
concatenateDictを2回呼び出していたところをconcatenateDictsの一回呼び出しにできた。

``` pandas_main.py
import pandas_lib as pl

dict1 = pl.countByKeyFromFileAndSheet("./example.xlsx", "Sheet1", "部署")
dict2 = pl.countByKeyFromFileAndSheet("./example.xlsx", "Sheet2", "部署")
dict3 = pl.countByKeyFromFileAndSheet("./example.xlsx", "Sheet3", "部署")

dict = pl.concatenateDicts(dict1, dict2, dict3)

print(dict)
```

### 実行結果
当然ですが、結果は変わりません。

```
{'営業部': 4, '開発部': 3, '総務部': 3}
{'営業部': 5, '開発部': 3, '経理部': 2}
{'開発部': 9, '経理部': 1}
{'営業部': 9, '開発部': 15, '総務部': 3, '経理部': 3}
```
【Java・SpringBoot】Springセキュリティ⑥ - CSRF

#CSRFとは
* クロスサイトリクエストフォージェリ（CrossSiteRequestForgeries）
* ユーザーが意図しないリクエストをWebサイトに送るという攻撃
    * ex:例えば、抽選で**2億円**が当たるというサイトを見つけました
        * そのサイトには**個人情報の入力**が必要と書いていて。。
        * 個人情報を入力してしまって、**"応募"**のボタンを押すと、
        * そのユーザー情報で、**別のWebサイトにアクセス**させて、高い物を購入させる
    * といった攻撃です。。💀😱

#トークン
* これを防ぐため、Springで作ったWebサイトからは、**トークン(ランダムな文字列)をパラメーターに加えてサーバーにリクエストする**ようにします
* トークン無しでリクエストを送ると、外部からのリクエストと判断できるため、Springは**リクエストを拒否**します
* 一方GETメソッドで画面を表示する場合には、トークンをパラメーターに含める必要はありません。
* Springセキュリティでは、**CSRF対策がデフォルトで有効**になっています

#ログイン画面にトークンをパラメーターに含める
* ログイン画面のhtmlで、CSRF対策用トークンをパラメーターに含める

```html:login.html
 <!-- CSRF対策用トークン -->
   <input type="hidden"
    th:name="${_csrf.parameterName}"
    th:value="${_csrf.token}" />
```

###CSRF対策用トークン
* 上記のように`hidden`でCSRF対策用のトークンをサーバーに送ります
* CSRF対策を有効にしている場合、フォームを使っている画面では上記のコードを追加しないと、Springが何も応答しないです
* formタグを使用している画面は他にもありますが、CSRF対策用のトークンを送らなくても動作する。
* 実は、CSRF対策用のトークンを送らなくても、**タイムリーフが自動でトークンを追加してくれる**のです🌟
    * **`th:action`属性**を使っていると、タイムリーフが自動追加してくれるが、
        * 以下のログイン画面では**formタグ内にaction属性**を使っているので、自分でトークン追加しました!
* 基本はth:action属性を使えばOK！

```login.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"></meta>

    <!-- Bootstrapの設定 -->
    <link th:href="@{/webjars/bootstrap/3.3.7-1/css/bootstrap.min.css}" rel="stylesheet"></link>
    <script th:src="@{/webjars/jquery/1.11.1/jquery.min.js}"></script>
    <script th:src="@{/webjars/bootstrap/3.3.7-1/js/bootstrap.min.js}"></script>

    <title>Login</title>
</head>
<body class="text-center">
    <h1>Login</h1>
    <form method="post" action="/login">
        <!-- エラーメッセージ -->
        <p th:if="${session['SPRING_SECURITY_LAST_EXCEPTION']} != null"
            th:text="${session['SPRING_SECURITY_LAST_EXCEPTION'].message}"
            class="text-danger">
            ログインエラーメッセージ
        </p>
        <!-- ユーザーID -->
        <label>ユーザーID</label>
        <input type="text" name="userId" /><br/>
        <br />
        <!-- パスワード -->
        <label>パスワード</label>
        <input type="password" name="password" /><br/>
        <br />
        <!-- ログインボタン -->
        <button class="btn btn-primary" type="submit">ログイン</button>
        <!-- CSRF対策用トークン -->
        <input type="hidden"
            th:name="${_csrf.parameterName}"
            th:value="${_csrf.token}" />
    </form>
    <br />
    <!-- ユーザー登録画面へのリンク -->
    <a th:href="@{'/signup'}">ユーザー新規登録はこちら</a>
</body>
</html>
```

#ログインできることを確認！
* http://localhost:8080/login
* OKですね★
備忘３ 4H070V

Sub Sample3()

    '集計
    Dim Dic, Dic2, Dic3, Dic4, Dic5, Dic6, i As Long, buf As String
    Set Dic = CreateObject("Scripting.Dictionary")
    Set Dic2 = CreateObject("Scripting.Dictionary")
    For i = 2 To Cells(Rows.Count, 4).End(xlUp).Row
        buf = Cells(i, 4).Value
        If Not Dic.Exists(buf) Then
            Dic.Add buf, 1
            Dic2.Add buf, 0
        Else
            Dic.Item(buf) = CLng(Dic.Item(buf)) + 1
        End If
        buf = Cells(i, 5).Value
        If Not Dic.Exists(buf) Then
            Dic.Add buf, 0
            Dic2.Add buf, 1
        Else
            If Not Dic2.Exists(buf) Then
            Else
                Dic2.Item(buf) = CLng(Dic2.Item(buf)) + 1
            End If
        End If
    Next i
    
    'データシートを追加
    Dim OldSheet As Worksheet
    Set OldSheet = ActiveSheet
    Dim OSN As String
    ODN = OldSheet.Name
    
    Dim NewWorkSheet As Worksheet
    Set NewWorkSheet = Worksheets.Add()
    NewWorkSheet.Name = ODN & "_DATA"
    
    
    '集計結果出力
    Columns("A:F").Clear
    Cells(1, 1).Value = "日付"
    Cells(1, 2).Value = "予定数"
    Cells(1, 3).Value = "実績"
    Cells(1, 4).Value = "計画線"
    Cells(1, 5).Value = "実績線"
    Cells(1, 6).Value = "理想線"
    
    i = Dic.Count
    With Application
    Cells(2, 1).Resize(i).NumberFormatLocal = "m""月""d""日"";@"
    Cells(2, 1).Resize(i).Value = .Transpose(Dic.keys)
    Cells(2, 2).Resize(i).Value = .Transpose(Dic.items)
    End With
    Set Dic = Nothing
    
    i = Dic2.Count
    With Application
    Cells(2, 3).Resize(i).Value = .Transpose(Dic2.items)
    End With
    Set Dic2 = Nothing
    
    '空白削除
    For i = Cells(Rows.Count, 1).End(xlUp).Row To 2 Step -1
        If ActiveSheet.Cells(i, 1) = "" Then
            'A列が空白なら行削除
            Application.Rows(i).Delete
        End If
    Next
    
    '元シートをアクティブに
    OldSheet.Activate
    
    
End Sub
Linux版のOpenSiv3Dをfind_packageでちょっと楽にアプリを作る

OpenSiv3DのLinux版が、クローンしてきたファイルの`OpenSiv3D/Linux/App`でしかビルドできないのが面倒くさいので、`make install`に対応させる。
以下のパッチを`diff.patch`として保存し、

```patch:diff.patch
diff --git a/Linux/CMakeLists.txt b/Linux/CMakeLists.txt
index f59da581..fe1e7c97 100644
--- a/Linux/CMakeLists.txt
+++ b/Linux/CMakeLists.txt
@@ -2,7 +2,7 @@ cmake_minimum_required (VERSION 3.0)
 
 find_package(PkgConfig)
 
-project(OpenSiv3D_Linux CXX)
+project(Siv3D VERSION 0.4.3 LANGUAGES CXX)
 enable_language(C)
 
 set(CMAKE_CXX_FLAGS "-std=c++17 -Wall -Wextra -Wno-unknown-pragmas -fPIC -msse4.1 -D_GLFW_X11")
@@ -26,10 +26,8 @@ endif()
 #set(CMAKE_BUILD_TYPE Release)
 
 pkg_check_modules(LIBSIV3D REQUIRED glib-2.0 gobject-2.0 gio-2.0 gl libpng libturbojpeg x11 xi xinerama xcursor xrandr gl glu freetype2 openal opencv4 ogg vorbis zlib)
-include_directories(
-	"/usr/include"
 
-	"."
+set(INCLUDE_DIRS
 	"../Siv3D/include"
 	"../Siv3D/src/Siv3D"
 	"../Siv3D/src/Siv3D-Platform/Linux"
@@ -725,6 +723,22 @@ set(SOURCE_FILES
 
 add_library(Siv3D STATIC ${SOURCE_FILES})
 
-target_link_libraries(Siv3D
-)
-
+install(DIRECTORY ../Siv3D/include/ DESTINATION include/Siv3D)
+find_package(Boost REQUIRED COMPONENTS filesystem)
+target_link_libraries(Siv3D GLEW pthread dl udev freetype harfbuzz glib-2.0 gobject-2.0 gio-2.0 png turbojpeg gif webp openal ogg vorbis vorbisenc vorbisfile /usr/local/lib/libboost_filesystem.a avformat avcodec avutil swresample ${LIBSIV3D_LIBRARIES})
+target_include_directories(Siv3D PUBLIC
+	$<BUILD_INTERFACE:${INCLUDE_DIRS}>
+	$<INSTALL_INTERFACE:include/Siv3D>
+	$<INSTALL_INTERFACE:include/Siv3D/ThirdParty>)
+install(TARGETS Siv3D
+	EXPORT Siv3DConfig
+	LIBRARY DESTINATION lib
+	ARCHIVE DESTINATION lib
+	INCLUDES DESTINATION include/Siv3D include/Siv3D/ThirdParty)
+install(EXPORT Siv3DConfig
+	DESTINATION lib/cmake/siv3d
+	EXPORT_LINK_INTERFACE_LIBRARIES)
+include(CMakePackageConfigHelpers)
+set(VERSION_CONFIG ${CMAKE_CURRENT_BINARY_DIR}/Siv3DConfigVersion.cmake)
+write_basic_package_version_file(${VERSION_CONFIG} COMPATIBILITY ExactVersion)
+install(FILES ${VERSION_CONFIG} DESTINATION lib/cmake/siv3d)
```
```bash
$ git apply diff.patch
```
で適用する。あとはいつもどおり必要なライブラリを入れ、cmakeしたあとに

```
make install
```
することにより、デフォルトのパスだと`/usr/local/`に必要なファイルがインストールされる。インストールが終わったら、クローンしてきたファイルは要らないので消す。

アプリを作成する際には、以下のCMakeファイルとSiv3Dのソースファイルを同じディレクトリに作成し

```cmake:CMakeLists.txt
cmake_minimum_required (VERSION 3.0)
project(アプリ名 CXX)

find_package(Siv3D 0.4.3 REQUIRED)

add_executable(アプリ名 Main.cpp)
set_target_properties(アプリ名 PROPERTIES CXX_STANDARD 17)

target_link_libraries(アプリ名 Siv3D)
```
```bash
$ mkdir build && cd build
$ cmake ..
$ make
```
と唱えるだけで、こんな感じのファイル構成で

```
CMakeLists.txt
Main.cpp
build/
├──アプリの実行ファイル
└──ビルドのログ等
```
Siv3Dのインストール先を気にせずにビルドできます。

更に、これができるとfind_packageの第2引数だけで、バージョンを変えられるので、管理がしやすくなります。
#lesson 3 tableau public で100万行以上（エクセルでは無理）のオープンデータを公開 計算フィールドの追加

# 計算フィールドの追加

取り込んだデータを編集したいことは良くあります。コード化されている項目（カラム）をコード内容がわかるテキストに変換します。exp_imp(輸出輸入コード）は、1,2 です。これに輸出、輸入を割当てます。データは、冗長になりますが、表示のときにわかりやすくなります

[この動画](https://youtu.be/zkpf_f7dMjc)をご覧ください。
Android11でメディアコントロールが出なかった。

#結論
きちんとMediaSessionにメタ情報を設定することでメディアコントロールが出ましたので、きちんとメタ情報が設定されているか確認をしましょう。

```java

mediaMetadata = new MediaMetadataCompat.Builder();
    .putString(MediaMetadata.METADATA_KEY_TITLE, title) 
    .putString(MediaMetadata.METADATA_KEY_ARTIST, artistName)
    .putString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI, imageUri)) 
    .putLong(MediaMetadata.METADATA_KEY_DURATION, duration)
    .build();
mediaSession.setMetadata(mediaMetadata)
```
また`putLong(MediaMetadataCompat.METADATA_KEY_DURATION, -1);`とすることで、シークバーを無効化することができますが、シークバー自体を消すことはできないようです。

##経緯
AndroidにはMediaSessionという、外部デバイスなどからメディアが操作されたことをうまく制御する仕組みがあるのですが、
その中で、再生情報はMediaMetadataで管理するということになっています。
(詳しい記事はたくさんあるのでここでは詳しい解説は省きます。)

しかし、MediaMetadataとは別にデータを管理していたため設定せずに完結していたこと。
メタ情報を設定せずともAndroid11以前はプレイヤーの表示・操作ができていたため、メタ情報の設定がされていないことに気付きにくかった。

以上のことからメタ情報の設定がされていなかったことに現在まで気づくことができていませんでした。

##最低限必要なメタ情報とメディアコントロールの表示の調査

Notificationのタイトル情報とMediaMetadataの関係を調査したところ以下のことがわかりました。

- MediaMetadataに対応するデータがある場合メタ情報が表示に使用される。
- 対応するメタ情報がないときはNotificationへ設定した値が表示される。
- MediaMetadataの中身が空っぽでも、Notificationに設定した情報が表示される。

インスタンスを生成して渡すだけでNotificationの情報から表示がされるようですが、しっかりと設定しましょう。

## あとがき

本当はAndroid11から追加されたバブルに触れてみたのですが、ギリギリまで試行錯誤して、
一部端末でバブルの機能が動かないという報告を発見して断念しました。
そちらについては確認次第また別の機会に記事にしようと思います。
行番号を付加する空行の単位を変更するnlコマンドのlオプション

nlコマンドはlオプションを指定することで、行番号を付加する空行の単位を変更することができます。

# lオプションの使い方
`-l`のあとに数値を指定します。デフォルトは`1`です。[`-b` `-h` `-f` オプションの付番方式に`a`（すべての行に番号を振る）を使う](https://qiita.com/Carol_815/items/997de8239ce3402b46dc)必要があり、これも同時に指定します。

## info nl (GNU coreutils)
```console
‘-l NUMBER’
‘--join-blank-lines=NUMBER’
     Consider NUMBER (default 1) consecutive empty lines to be one
     logical line for numbering, and only number the last one.  Where
     fewer than NUMBER consecutive empty lines occur, do not number
     them.  An empty line is one that contains no characters, not even
     spaces or tabs.
```

ここにきて「空行とは何か」の説明がありますね。タブもスペースも含まない行が空行です。

## man nl (BSD)
```console
     -l num       If numbering of all lines is specified for the current logical
                  section using the corresponding -b a, -f a or -h a option, spec-
                  ify the number of adjacent blank lines to be considered as one.
                  For example, -l 2 results in only the second adjacent blank line
                  being numbered.  The default num value is 1.
```

## POSIX
>-l  num
Specify the number of blank lines to be considered as one. For example, -l 2 results in only the second adjacent blank line being numbered (if the appropriate -h a, -b a, or -f a option is set). The default shall be 1.



# lオプションを試す

単純なデータで試してみましょう。

```console
$ echo -e 'a\n\n\n\n\nb\n\n\nc\n' 
a




b


c

$ echo -e 'a\n\n\n\n\nb\n\n\nc\n' | nl 
     1	a
       
       
       
       
     2	b
       
       
     3	c
       
$ echo -e 'a\n\n\n\n\nb\n\n\nc\n' | nl -b a
     1	a
     2	
     3	
     4	
     5	
     6	b
     7	
     8	
     9	c
    10	
$ echo -e 'a\n\n\n\n\nb\n\n\nc\n' | nl -b a -l 2
     1	a
       
     2	
       
     3	
     4	b
       
     5	
     6	c
       
```

正直なところ何に使うオプションなのか検討つきません。私は`-l`を今まで使ったことがありません。

---

# ToDo

なんとかユースケースを考えたいのですが思いつきませんでした。何か思いついたら追記します。
連続したn個の空行で1つの空行としてみなすマークアップ言語などがあるのかもしれませんね。
AndroidエミュレータのFlutterアプリ内でネットワーク接続ができない

パーミッションとDNS

# 環境
macOS Big Sur バージョン11.0.1
Android Studio 4.0.1
Android Emulator 30.0.12

# エラー
```
socketexception: failed host lookup: 'hoge.com' (os error: no address associated with hostname, errno = 7)
```

# 解決方法
## アプリのパーミッション設定
`android/app/src/main/AndroidManifest.xml`
\<manifest>下に以下を追加

```xml:AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET"/>
```

これでもエラーが変わらなければ↓

## macのDNS設定
`システム環境設定>ネットワーク>Wi-Fi>詳細...>DNS`
DNSサーバに8.8.8.8を追加
![スクリーンショット 2020-12-16 5.51.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/956942/2d3d6814-e8ab-70c0-063b-309dab20854a.png)

# 参考
- [How to solve SocketException: Failed host lookup: 'www.xyz.com' (OS Error: No address associated with hostname, errno = 7)](https://stackoverflow.com/questions/54551198/how-to-solve-socketexception-failed-host-lookup-www-xyz-com-os-error-no-ad)
- [Androidエミュレータがネットワークに繋がらないときの対処](https://kgarage.hatenablog.com/entry/2019/11/11/091205)
【Python】これだけ簡単！Twitterのツイートを検索する

python3.6.3で、tweepyをインストール済みです。
これをpythonで実行するだけです。

```python
# coding: utf-8

import tweepy

CONSUMER_KEY = "コンシューマーキー"
CONSUMER_SECRET = "コンシューマーシークレットキー"
auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)

ACCESS_TOKEN = "アクセストークン"
ACCESS_SECRET = "アクセスシークレットトークン"
auth.set_access_token(ACCESS_TOKEN, ACCESS_SECRET)

api = tweepy.API(auth)

for tweet in api.search(q=u"iphone"):
    print(tweet.text)
```

情報改変元：https://gist.github.com/kurozumi/fee149ff02a968b5990e98f63c049320

「コンシューマーキー」「アクセストークン」などの日本語で書かれた部分は、こちらに！
https://qiita.com/kngsym2018/items/2524d21455aac111cdee
「IndentationError: expected an indented block」の対処【一瞬で理解できる】

「expected an indented block」のエラーは、インデント（字下げ）がないことが原因です。

```python
numbers = ['1', '2', '3']

for n in numbers:
print (n)

# 結果
IndentationError: expected an indented block
```

print(n)に字下げを入れてましょう！

```python
numbers = ['1', '2', '3']

for n in numbers:
    print (n)

# 結果
1 2 3
```
bc コマンドが新しくなる

#current で既にデフォルトになってる、新たな bc コマンド

お手軽にコマンドラインで計算するのに使う、おなじみの bc コマンドのお話です。あまり変化なさそうな分野だと思っていたら、current ではいつの間にやら新しいバージョンに差し替わっていました。
実行すると一目瞭然、「>>>」というプロンプトがつくようになりました。

<pre>
$ bc
>>> 1+2
3
</pre>
以下ではプロンプト以外の従来bcとの違いや、FreeBSD で選ばれた理由などを適当にまとめます。

# Gavin Howard さん作、gh-bc

FreeBSD では今まで OpenBSD 由来の bc (usr.bin/bc)が入っていました。新しい bc コマンドはGavin Howard さんが独立にスクラッチから作られたものです。ビルドに C99 コンパイラを要求する点など、モダンさが伺えます。
FreeBSD のソース上は usr.bin/gh-bc というディレクトリに入っています。本稿でもこの bc は gh-bc と呼ぶことにします。

**開発元 URL** https://git.yzena.com/gavin/bc
**FreeBSD リポジトリ** https://svnweb.freebsd.org/base/head/usr.bin/gh-bc/


開発元のREADME.mdによると、Linuxなどで広く使われている GNU bc (FreeBSDだと pkg/ports からインストール出来ます)と比べると

* スクリプトに便利な拡張機能
* パフォーマンス
* 安定性
* より POSIXに準拠している

などが優れていると謳っています。
パフォーマンスに関しては GNU bc との比較を公式でベンチマーク比較していて、それを見ると桁違いな速さを見せつけてるケースが多いです。
https://git.yzena.com/gavin/bc/src/branch/master/manuals/benchmarks.md

# FreeBSD で選ばれた理由

FreeBSD でこの gh-bc を使用するようにした理由に関しては、上記のパフォーマンスなどの点以外に、

* 多桁計算用ライブラリが他のライブラリに依存していない
* man 文章が非常に詳細である

などがあるようです。詳細は以下の commit log を参照してください。

https://svnweb.freebsd.org/base?view=revision&revision=362681

従来の bc は OpenSSL の多桁計算ライブラリに依存しているようで、確かにそれに依存しないというのは魅力ですね。

# 12 release では明示的ビルドが必要
currentではすでにデフォルトが切り替わってますが、12-releaseではどうでしょうか。

12-release でもソース自体は入っている状態ですが、通常はビルドはされないようになっています。明示的に gh-bc に切り替えるには、「WITH_GH_BC=yes」というオプションをつけて  buildworld する必要があります。

# sinがsin

使ってわかりやすい違いとして、sin関数がちゃんと「sin()」として使えることがあります。従来のbcではsinは「s()」、cosは「c()」、logは「l()」とかいう、省略しすぎな名称でしたが、それぞれちゃんと省略しない関数名が使えるようになっています。
また、「pi()」という関数が定義されていて、引数に桁数をすると、その桁数の円周率を返してくれます。

# 詳しくは man で

記事での紹介ではかなりかいつまんでになりましたが、FreeBSDでの採用理由になったように man が詳細ですので興味のある方はmanを参照してください。

gh-bc
https://www.freebsd.org/cgi/man.cgi?query=bc&apropos=0&sektion=0&manpath=FreeBSD+13.0-current&arch=default&format=html

従来のbcのmanはこちら
https://www.freebsd.org/cgi/man.cgi?query=bc&apropos=0&sektion=0&manpath=FreeBSD+12.2-RELEASE&arch=default&format=html
Flash Advent Calendar 9日目 - WebGL導入への道のり02 -

基礎部分はできたので、実際にシェーダーにデーターを渡していこうかと思います。
サンプルとしてdrawImage関数を作ってみようかと思います。


利用するイメージ

```javascript
context.fillStyle = [1, 1, 1, 1];
context.setTransform(1, 0, 0, 1, 0, 0);
context.drawImage(texture, 0, 0, width, height);
```

# シェーダーの準備

今回は色とmatrixも使ってdrawImageを実装していきます。

## 頂点シェーダー
```javascript
const TEXTURE_VERTEX_SHADER = "\
precision highp float;\n\
attribute vec2 a_coord;\n\
varying vec2 v_coord;\n\
uniform vec2 u_position;\n\
uniform vec2 u_size;\n\
uniform vec2 u_viewport;\n\
uniform mat3 u_transform;\n\
void main() {\n\
    v_coord = a_coord;\n\
    vec3 pos = u_transform * vec3(u_position + vec2(a_coord.x, 1.0 - a_coord.y) * u_size, 1.0);\n\
    pos.x = (2.0 * pos.x / u_viewport.x) - 1.0;\n\
    pos.y = -((2.0 * pos.y / u_viewport.y) - 1.0);\n\
    gl_Position = vec4(pos.xy, 0.0, 1.0);\n\
}";
```

## フラグメントシェーダー
```javascript
const TEXTURE_FRAGMENT_SHADER = "\
precision highp float;\n\
uniform sampler2D u_texture;\n\
uniform vec4 u_color;\n\
varying vec2 v_coord;\n\
void main() {\n\
    gl_FragColor = texture2D(u_texture, v_coord) * u_color;\n\
}";
```

## drawImageを実装

```javascript

/**
 * @param  {array} uniforms
 * @return {void}
 * @public
 */
updateUniforms (uniforms) 
{
    var length = uniforms.length;
    for (let idx = 0; idx < length; idx++) {

        const uniform = uniforms[idx];

        var value = uniform.value;
        if (Util.$isArray(value)) {
            value = new Float32Array(value);
        }

        var info = this.uniformInfo[uniform.name];
        if (!info.location) {
            info.location = this.gl.getUniformLocation(this.program, uniform.name);
        }

        switch (info.type) {

            case gl.FLOAT_MAT2:
            case gl.FLOAT_MAT3:
            case gl.FLOAT_MAT4:
                info.method.call(this.gl, info.location, false, value);
                break;
            // ...他の関数も同様に値をセットしてコールする

        }
    }
}


/**
 * @praram {WebGLTexture} texture
 * @praram {number} x
 * @praram {number} y
 * @praram {number} width
 * @praram {number} height
 * @return {void}
 * @public
 */
drawImage (texture, x, y, width, height) 
{
    // 生成したプログラムをセット
    this.gl.useProgram(this.program);

    // 描画したいtextureをbind
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, texture);

    // 変数データを送る
    this.updateUniforms ([
        { "name": "u_size",      "value": [x, y] },
        { "name": "u_position",  "value": [width, height] },
        { "name": "u_transform", "value": this.matrix },
        { "name": "u_color",     "value": this.color },
        // ...今回は他の変数は割愛
    ]) 

    // buffer objectやattributeは長くなるので、今回は割愛します。

    gl.drawArrays(gl.TRIANGLES, 0, 6);
}

```

っという感じで、一番最初はCanvas2Dで出来上がったcanvasデータをtextureに変換してWebGLで描画する事からはじめました。

次はlineToやquadraticCurveToのパス情報について書こうと思います。
M1 macOS で python + numpy/scipy/pandas/matplotlib/jupyterlab 環境構築のメモ(2020/12/24 時点)

M1 macOS で arm64 native な python と numpy/scipy/matplotlib, Jupyter-lab など入れてデータサイエンスしたい.

現状だと x86 の時と同じやり方でインストールしようとすると, M1(arm64) の場合はコンパイルがコケたりなどしてうまく行きません
(pip とか, macports 経由とかでインストールとか)

例えば `altivec`(みんな知っているかな!) コンパイルフラッグが clang 未サポートで numpy ビルドできないなどの issue があります.

https://github.com/numpy/numpy/issues/17807

いずれ時が解決するでしょうが, 待つのもめんどいです. 
ソースからビルドするのはもっとめんどい.

ぺろっとお手軽に Arm64 native なデータサイエンス環境セットアップしたいですよね.

## miniforge

Apple Silicon, run Scikit-Learn and TensorFlow on the new Macs M1
Run Machine Learning tools natively compiled for Apple Silicon
https://towardsdatascience.com/new-apple-silicon-m1-macbook-air-the-dream-laptop-for-machine-learning-engineers-a1590fbd170f

で動作確認されているように, miniforge を使います. もともと Raspberry Pi むけなどを想定して Arm64 版がパッケージング & メンテされているようですので, M1 でも問題なく動いてくれます. 

https://github.com/conda-forge/miniforge

arm64 版の osx インストーラー使います.

あとは普通に (mini)conda として使えます.

```
conda create -n myenv python=3.9
conda activate myenv
```

などとして環境にはいり,

```
conda install numpy
```

として arm64 な numpy インストールできます!

![Screen Shot 2020-12-16 at 3.36.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36275/3cb617bd-733f-3f46-395c-d6c45960ae15.png)

Voila! :tada:

最初に起動に少し時間がかかるのですが, Rosetta2 ではなく何か別ので時間がかかっている...はず?(`__pycache__` 生成とか?)

## matplotlib

特に問題なく動きました.

https://docs.scipy.org/doc/scipy/reference/tutorial/interpolate.html

を参考に, numpy/scipy/matplotlib を使うスクリプトを動かしてみます.

```
import numpy as np
from scipy.interpolate import interp1d
x = np.linspace(0, 10, num=11, endpoint=True)
y = np.cos(-x**2/9.0)
f = interp1d(x, y)
f2 = interp1d(x, y, kind='cubic')

xnew = np.linspace(0, 10, num=41, endpoint=True)
import matplotlib.pyplot as plt
plt.plot(x, y, 'o', xnew, f(xnew), '-', xnew, f2(xnew), '--')
plt.legend(['data', 'linear', 'cubic'], loc='best')
plt.show()
```

![Screen Shot 2020-12-25 at 1.33.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36275/d67d0d1f-7071-4280-ff94-86f7d4fd2c64.png)

:tada:

Macで使うmatplotlibのbackendエラー
https://qiita.com/typecprint/items/0d4bea1251ab3f816303

ありがとうございます.

miniforge ではデフォルト `MacOSX`(native?) backend のようです.

必要であれば, 上記リンクを参照し, `matplotlibrc` ファイルを編集して backend を変更しましょう.

`WebAgg` などのネットで画面を飛ばすのも試してみるといいかもしれません.

## Jupyter-lab

https://forum.pine64.org/showthread.php?tid=10299

にありますように, Arm64 環境では miniforge が recommended のようで, 同様に miniforge の conda でそのままインストールできます!

```
$ conda activate myenv
$ conda install jupyterlab
```

あとは普通に jupyter-lab で起動するだけです!


![Screen Shot 2020-12-25 at 2.00.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36275/74c134f3-cd46-7a43-6cc4-ffea27e3e489.png)

Ultra super cooooooooooooool!!!!!! :tada:


## 動作しないもの

macports になりますが, `ffmpeg` が `libvpx` が arm64 未対応のためインストールできませんでした.

ffmpeg を使って動画を作る場合は, しばらくは x86-64 版でしょうか.


## TODO

* [x] matplotlib の画面表示(backend)をどうすれば良いか調べる(~~そのままだと何も表示されない~~ 何か plot させてから show しないとウィンドウ出ないだけだった)
* [ ] Jupyterlab の extension(e.g. interactive widgets, vim keybinding)が動くか確認する
* [ ] ファンレス M1 Macbook Air を持って山に籠り, **ひとりでできるもんデータサイエンティスト Youtuber として生計を立てるスキーム**を確立する旅に出たい
（めも）Ubuntu20.04でダミー出力の解決方法

Ubuntu20.04LTSをインストールしたら音が出ず、オーディオデバイスが認識すらしなかった。
設定のサウンド欄ではダミー出力。色々調べてpulseaudioとかalsamixer確認したが、結局以下のカーネル更新で解決した。
```sudo apt install linux-image-generic-hwe-20.04
```
メモ。
【事例紹介】プロジェクト管理にGitLabのissueを使用し、ストーリーポイントを導入してみた ~Ateam Brides~

こんにちは！
エイチームブライズでサイト開発を行っている@aoi_coro_です。

この記事は[Ateam Brides Inc. Advent Calendar 2020](https://qiita.com/advent-calendar/2020/ateam-brides)　17日目の記事です。

# はじめに

プロジェクト管理、どうしていますか？

私もまだまだプロジェクト管理には頭を悩ませているのですが、
弊社のプロジェクト管理に対する取り組みの一環として、
GitLabのissueを使用し、ストーリーポイントおよびベロシティを導入してみました。

本記事では事例の一つとして、
その導入前後によるGOOD,TRYと、導入方法ついて、ご紹介させていただきます。

【用語説明】
ストーリーポイント・・・人月管理ではなく、対応内容によって相対的に換算する難易度
ベロシティ・・・チームが指定した期限内に対応できる仕事量
※詳しくは他の方々が素晴らしい記事をたくさん書いてくださっているので、そちらをご覧ください。

# 導入前

## :sunny:GOOD:sunny:
- redmineのチケット機能にて案件管理ができていた
- 人数が少なかったため、マネージャーがほぼ全ての案件を把握できていた
  - メンバーには週一のMTGで共有されていた!
  - マネージャーによる意思決定が素早くなされていた

## :cloud:TRY:cloud:
- 全体の仕事量が見えないため、差し込み案件によるスケジュールの遅延が多発していた
- 案件毎の工数・優先度・進捗の確認がし辛かった

# 導入方法

## 使用したもの
使用tool：[GitLab](https://www.gitlab.jp/)
使用機能：issues,milestones

## 方法は3ステップ！
1. 案件単位にissueを作成し、ストーリーポイントで見積もった値をweightに設定する。
2. 月単位にmilestonesを作成し、その月に対応したissueを紐づける。
3. weightを幾つ消化できたかでその月のベロシティを算出する。

【案件一覧はboardで管理】
![image_2020_12_16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253515/1677bdb9-3203-2ca8-e73e-d7337e02f488.png)

# 導入後

## :sunny:GOOD:sunny:
- 毎朝weightを振る作業をチーム全員で行うことで、**メンバー間で案件の共有が容易に**なった
- weightを振ることでメンバー間で**難易度の認識が統一**された
- 全体の仕事量を毎月数値化することで、**仕事量が見える化**された
- issueによる案件の一覧化を行ったことで、**案件の工数・優先度・進捗確認が容易に**なった
  - これにより依頼部署との進捗確認・スケジュール調整がしやすくなった

## :cloud:TRY:cloud:
- この手法では月を跨いだ案件について個別対応を行う必要がある
- ベロシティ算出を行っても、仕事量を適量に収められるかと言うと、そうではなかった・・・
- 他部署と話す際に、ベロシティを工数換算して話している

# さいごに

今回は案件管理にGitLabのissueを使用した、
ストーリーポイントとベロシティの導入についてご紹介いたしました。

これはプロジェクト管理の最初の一歩です。

いまだ道半ばですが、プロジェクト管理は
エンジニア・依頼する側、双方が気持ちよく働く上でとても大切だと思っています。

エンジニアが何をしているのかを「わかりやすく見える化」することで、
依頼部署のみんなに安心感を与え、
エンジニアも無理のないスケジュールで対応ができる。

皆が楽しく働けるように、今後も改善を進めていくつもりです。
Angular Elementsを使ってみた

この記事は [Angular Advent Calendar 2020](https://qiita.com/advent-calendar/2020/angular) の 16 日目の記事です。

# はじめに
最近、レガシーなフロントエンド環境を採用したプロジェクトで開発をする機会があり、これまで制作したAngularコンポーネントを再利用するため、Angular Elementsを使用してみました。

Angular Elementsの導入はとても簡単でうまくいったのですが、その過程でWeb ComponentsにおけるコンポーネントやCSSの設計に悩まされることが多かったので、それについて調べたり考えたことをまとめてみようと思います。

# Angular Elements とは
Angular Elementsは、AngularのコンポーネントをCustom Elementsに変換する機能です。
Custom Elementsに変換されたコンポーネントは独自のHTML要素として定義され、フレームワークに依存せず通常のHTML要素のように扱うことができます。

```html
<!-- 独自のHTML要素 -->
<my-elem></my-elem>
<!-- Custom Elementsの読み込み -->
<script src="my-elem.js"></script>
```

コンポーネントの`@Input`はHTML要素の属性、`@Output`はHTML要素のイベントとして定義されます。
注意点として`@Input`から定義される属性名には、元のプロパティ名をケバブケースに変換したものが使用されます。
また、それらの属性に渡した値はすべて文字列として扱われます。
文字列でない値を渡したい場合は、JavaScriptで取得した要素のプロパティから値を渡す必要があります。

```html
<!-- 属性の値の代入 -->
<my-elem my-string="Hello, world!"></my-elem>

<script>
  const myElem = document.querySelector('my-elem');

  // @Inputプロパティの値の代入
  myElem.myNumber = 123;
  myElem.myArray = ['a', 'b', 'c'];

  // @Outputイベントのハンドリング
  myElem.addEventListener('myEvent', (e) => {
    console.log(e);
  });
</script>
```

# CSSのカスタマイズ
コンポーネントに適用したスタイルは、もちろんCustom Elementsとして表示される際も適用されます。
しかし、Custom Elementsを表示するページのデザインに合わせてカスタマイズしたいケースも多くあると思います。
今回は適用したスタイルが直感的にCustom Elements全体に反映されるように、以下のように意識してみました。

- Custom Elementsの内部で使用されているコンポーネントに適用するスタイルを最小限にする
- `font-size`などサイズの指定にできるだけ`em`や`%`を使用する

よりカスタマイズ性を高めるには、CSS Variablesによるカスタマイズ用のCSS変数の定義や、要素内部のDOMツリーを追ってスタイルを適用するといった方法があるようです。

# Custom Elementsの粒度
今回はすでに制作してあるコンポーネントで、サービスの使用が前提になっていたため、使いたい部分を1つのコンポーネントでラップしてCustom Elementsを作成しました。
その結果1つのウィジェットとして目的を達成することができましたが、変更が容易でなく、使用するアプリケーション側からすると汎用性に欠ける、モノリシックなCustom Elementsになってしまったような気がします。

Custom ElementsはAtomic DesignでいうところのAtomsからMoleculesぐらいのまでの粒度で作成し、それらとビジネスロジックを組み合わせて機能を実装していくようなイメージなのかなと思いました。
Custom Elementsに限った話ではなく、普段からコンポーネント設計に向き合っていくことが重要だと再認識させられました。
AnacondaでPythonが立ち上がってしまう時に意外に出てこない対処法

Mac OsにてPython3.9.0をインストール済みでpyenvで確認するとしっかり3.9.0と表示されるのに、

```
$ python -V
```

と入力すると

```
Python 3.8.5
```

と表示されてしまいました。挙げ句の果てにDjangoをinstallして使っていたはずが何故か立ち上がらず。

困ったもので、

```
$ which python
```

で確認するとAnacondaのPythonで立ち上がっていました。

開発に参加するためPythonとDjangoのバージョンを合わせておきたかったのですが、自分の制作でJupyter Labは使いたかったのでアンインストールはしたくない。

そんな時役立つのが調べてもあまり出てこないコマンド

```
$ conda deactivate
```

です。

ターミナルを落とすまではAnacondaを終了させることができるのと、ターミナルを再起動させれば再びAnacondaが起動している状態になります。

またとにかく原因はわからないけど今はAnacondaの環境では動かしたくないという時にも良いコマンドではないかなと思います。
react-draggableにクリックイベントを追加する

こんにちは、フロントエンドエンジニアの[てりー](https://twitter.com/teriteri_code)です。
僕の詳しいプロフィールは[こちら](https://terrblog.com/about/)


この記事は[React #2 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/react-2)の16日目の記事です。

# 2024年2月 追記
本編はこちらのブログに移しました。

https://terrblog.com/react-draggable/
safari : <input type="file">でバグるときの対応

titleの通り。

202021216追記
既存のバグらしい。
https://discussionsjapan.apple.com/thread/252057820

# 環境
- Mac OS Mojave 10.14.6
- Safari : バージョン14.0.1 (14610.2.11.51.10)

# 結論
`accept`を書いたらうまく行った

# 問題のコード
ざっくりと以下の通り。

```html

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8" />
	<meta name="viewport" content="width=device-width, initial-scale=1.0" />
	<title>Document</title>
</head>

<body>
	<!-- ↓このinputが動かん -->
	<p>test1Input</p>
	<input type="file" id="hoge" name="fuga" />
	<br />

	<!-- ↓こっちは動く -->
	<p>test2Input</p>
	<input
      type="file"
      id="avatar"
      name="avatar"
      accept="image/png, image/jpeg"
    />
	<br />
  </body>
</html>
```

# 具体的な問題
- ２個めinputをクリックすると正常に起動。
- その後、１個めのinputをクリックすると無反応。
- １個めをクリックしたあとだと、２個めも動かなくなる。
- safariを再起動すると治る。

参考
[stackoverflow大先生](https://stackoverflow.com/questions/64843459/input-type-file-on-html-form-not-working-on-safari-version-14-0-1-14610-2-11-51)
UnityWebRequestでAudioのリクエスト時にメモリを大量に消費してしまう問題

# UnityWebRequestでAudioのリクエスト時にメモリを大量に消費してしまう問題

記事探していても全く見つからなかったので自分の備忘録として記しておきます．
（当たり前の事過ぎて記事を書く人がいなかった可能性・・・）

- [streamAudio](https://docs.unity3d.com/ja/2019.4/ScriptReference/Networking.DownloadHandlerAudioClip-streamAudio.html)をONにする事で解決

```
//ストリーミングをONにする
((DownloadHandlerAudioClip)request.downloadHandler).streamAudio = true; 
```
```
//ロード処理の前にwhileでrequest.isDoneで確認・待機する
while (!request.isNetworkError && !request.isDone) {    
yield return null;
}
```
この処理をするだけで処理落ちせず，Audioのダウンロードを行う事が出来ます．
[JavaScript][aws-sdk] AWS Cognitoの招待メッセージを再送したい場合の対応

## はじめに
AWS Cognitoでは、管理者がユーザーアカウントを新規作成すると一時パスワードを発行し、ユーザーの初回ログイン時にパスワード変更をさせることができます。
(参考： [Creating User Accounts as Administrator](https://docs.aws.amazon.com/cognito/latest/developerguide/how-to-create-user-accounts.html))
 
一時パスワードが記載された招待メッセージをSMSまたはEメールでユーザーに通知できるのですが、気づかぬ内にメールが迷惑メールとして扱われてしまうといったように招待メッセージの再送が必要になるケースがあります。

今回はこのユーザーアカウントを新規作成時の招待メッセージを再送する方法についてまとめました。

## 今回やりたいこと
管理者がユーザーアカウントを新規作成した際に送信される招待メッセージの再送

今回はJavaScriptでユーザーアカウントを招待メッセージの再送をしたいので、aws-sdkを利用します。(aws-cliでの対応は[こちら](https://dev.classmethod.jp/articles/allow-to-reset-expired-cognito-user-password/)をご参照ください)

## 対応方法
aws-sdkの`CognitoIdentityServiceProvider.adminCreateUser`を利用します。
こちらのapiはユーザープールに新規ユーザーを作成するときに利用されるのですが、paramの`MessageAction`に`RESEND`を指定すると招待メッセージの再送が行えます。
(参考: [CognitoIdentityServiceProvider.adminCreateUser](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/CognitoIdentityServiceProvider.html#adminCreateUser-property))

#### サンプルコード
```javascript
const params = {
  UserPoolId: userPoolId /* 必須 */,
  Username: userName, /* 必須 */
  DesiredDeliveryMediums: ['EMAIL'],/* 通知方法 */
  ForceAliasCreation: true,/* エイリアス利用時のみ必要 */
  MessageAction: 'RESEND', /* 再送のため'RESEND'にする */
  TemporaryPassword: password, /* 再発行時の一時パスワード */
};

try {
  const res = await cognitoServiceProvider.adminCreateUser(params).promise();
  return res;
} catch (err) {
  console.log(err, err.stack)
}

```

## まとめ
ユーザーを作成するapiでparamを変更するだけで「メッセージの再送」と「一時パスワードの再発行」ができるというのに気づかず最初つまづいたのと、aws-sdkを利用した事例があまり見つからなかったので、今回の対応内容をまとめました。

同じような点でつまずいた方の助けになれば幸いです。

## 参考リンク
* [一時パスワードが使用されないまま有効期限が切れたCognitoユーザーをリセットして、新しい一時パスワードを発行する](https://dev.classmethod.jp/articles/allow-to-reset-expired-cognito-user-password/)
* [aws-sdk: CognitoIdentityServiceProvider.adminCreateUser](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/CognitoIdentityServiceProvider.html#adminCreateUser-property)
* [How do I reset a Cognito user's password that has expired?](https://stackoverflow.com/questions/51109154/how-do-i-reset-a-cognito-users-password-that-has-expired)
Railsで、"Mysql2::Error: Operand should contain 1 column(s) " エラーが出た際の対処法

みなさんこんにちは、@ryosk7です。

## 状況
さくっと本題から入ります。

```
Mysql2::Error: Operand should contain 1 column(s)
```

このようなエラーが出た場合の対処法です。

状況としては、

```ruby
user_ids = @current_user.sample_contents.pluck(:to_user_id)

@samples = SampleModel.where('
                              (user_id = ? and status = ?) or (user_id = ? and status is not null)',
                              user_ids, SampleModel.statuses[:open], @current_user.id)
                      .order(id: "DESC")

```

このようなコードを書いた際に出力されました。

## 解決方法
こちらです。

```ruby
user_ids = @current_user.sample_contents.pluck(:to_user_id)

@samples = SampleModel.where('
                              (user_id = ? and status = ?) or (user_id = ? and status is not null)',
                              user_ids.join(","), SampleModel.statuses[:open], @current_user.id)
                      .order(id: "DESC")

```

違いにお気づきでしょうか。

配列をカンマで連結した文字列に変えています。

```ruby
user_ids.join(",")
```

## 原因
Active Recordを利用した場合なら、user_idに配列のまま渡しても問題なく認識されますが、
SQL上でも同じようにやっていたことが原因でした。
単一の値であれば問題ないですが、複数の値であれば、リストにした文字列を渡す必要があります。

実際にはこんな感じでSQLが作られます。joinで変換したところはそのままですね。
SQLに強くないので、勉強になりました。

```sql
SELECT `sample_models`.* FROM `sample_models` WHERE ((user_id = '10,23,55' and status = 0) or (user_id = 14 and status is not null))  ORDER BY `sample_models`.`id` DESC
```

参考記事では、INを使ってクエリを叩いています。
同じように書くと、

```ruby
user_ids = @current_user.sample_contents.pluck(:to_user_id)

@samples = SampleModel.where('
                              (user_id in (?) and status = ?) or (user_id = ? and status is not null)',
                              user_ids.join(","), SampleModel.statuses[:open], @current_user.id)
                      .order(id: "DESC")

```

このようになります。

SQLもINで作成されていますね。

```sql
SELECT `sample_models`.* FROM `sample_models` WHERE ((user_id in ('10,23,55') and status = 0) or (user_id = 14 and status is not null))  ORDER BY `sample_models`.`id` DESC
```

どちらも同じ結果が得られます。

## 参考
https://stackoverflow.com/questions/10012695/sql-statement-using-where-clause-with-multiple-values
PostgreSQLレプリケーション構成のスタンバイ側で、リカバリとバックエンドのデッドロックを発生させる手順

レプリケーション構成のスタンバイ側では、「リカバリを実行するstartupプロセス」と「リードオンリー・トランザクションを実行するバックエンドプロセス」の間でデッドロックが発生する可能性があります。このデッドロックは、以下2つの待ちが重なることで発生します。

- バックエンドプロセスが取得済のバッファ・ピンを、startupプロセスが取得しようとして待ち状態になる
- startupプロセスが取得済のテーブルロックを、バックエンドプロセスが取得しようとして待ち状態になる

今回は、このデッドロックを発生させる手順を記載します。

## リカバリとバックエンドのデッドロックを発生させる手順
- ① レプリケーション構成をセットアップする。

- ② プライマリ側で、テーブルAとBを作成する。

```sql
CREATE TABLE testA AS SELECT id FROM generate_series(1, 10) id;
CREATE TABLE testB AS SELECT id FROM generate_series(1, 10) id;
```

- ③ プライマリ側で、テーブルAから1レコード削除する。

```sql
DELETE FROM testA WHERE id = 1;
```

- ④ スタンバイ側で、テーブルAをスキャンするカーソルを作成して、1件レコードを取得する。
    - この手順により、バックエンドはテーブルA上でバッファ・ピンを取得する。

```sql
BEGIN;
DECLARE testcursor CURSOR FOR SELECT * FROM testA;
FETCH NEXT testcursor;
```

- ⑤ プライマリ側で、テーブルBに対してACCESS EXCLUSIVEロックを取得して、ロック取得のWALがすぐにスタンバイに転送されるようにpg_switch_wal()を実行する。
    - この手順により、startupプロセスはテーブルBに対するACCESS EXCLUSIVEロックを取得する。

```sql
BEGIN;
LOCK TABLE testB IN ACCESS EXCLUSIVE MODE;
SELECT pg_switch_wal();
```

- ⑥ スタンバイ側で、④と同じセッションで、テーブルBをSELECTする。
    - この手順により、バックエンドはテーブルBに対するACCESS SHAREロックを取得しようとして待ち状態になる。

```sql
SELECT * FROM testB;
```

- ⑦ プライマリ側で、⑤とは別のセッションを開始して、テーブルAをVACUUMする。
    - この手順により、startupプロセスはテーブルA上でバッファ・ピンを取得しようとして待ち状態になる。

```sql
VACUUM testA;
```

## リカバリとバックエンドのデッドロック検出時のエラーメッセージ

リカバリとバックエンドのデッドロックも、通常のロック取得同士のデッドロックと同様に、deadlock_timeoutパラメータの設定値の時間後に検出されます。今回の手順で発生させたデッドロックが検出されると、以下のエラーメッセージが出力されて、バックエンドのトランザクションがキャンセルされます。

```
ERROR:  canceling statement due to conflict with recovery
LINE 1: SELECT * FROM testB;
                      ^
DETAIL:  User transaction caused buffer deadlock with recovery.
```