OmniAICreator/Qiita-1.07M huggingface dataset:
横に長いWebページで、右端までスクロールされたかを判定する【JavaScript】

もしかしたら他の方が記事にしていらっしゃるかもしれませんが、自分用メモとして。
最下部スクロールなどの記事はよく見かけるのですが、右端スクロールはあまり見ないので。

```javascript
var lastScrollx = 0;

$(function() {

    lastScrollx = window.pageXOffset;

	window.addEventListener('scroll', function(event) {
		var direction = 'vertical';
		var scrollValue = window.pageXOffset;

		if (lastScrollx != scrollValue) {
			if (lastScrollx > scrollValue) {
				direction = 'left';
			} else {
				direction = 'right';
				var docW = $(document).innerWidth();
				var winW = $(window).innerWidth();
				var maxScrollValue = docW - winW;
				if (scrollValue == maxScrollValue) {
					console.log('右端に到達');
				}
			}
		} else {
            direction = 'vertical';
        }
		lastScrollx = scrollValue;
	});
}

```
WAS設計その6 共有ライブラリ

WAS側としての要件はないですね。。。。

強いて言えば、
セル単位？
ノード単位？
クラスタ単位？
アプリケーションサーバ単位？

そういえば、アプリケーションデプロイ時に、この部分を上書きできるみたい。
基盤側は、指をくわえてみているだけですが。
※詳細は知りませんって言いたいだけです。
Microsoft Teamsで新しいチームを作る

### 名市大ではMicrosoft Teamsを利用可能

名古屋市立大学では、[Microsoft365](https://www.microsoft.com/ja-jp/microsoft-365)のオンライン版が教育用に提供されており、学生が使うことが出来ます。Word, Excel, PowerPointなどの定番ソフトが提供されています。この中に、大学の活動でも利用頻度が高いアプリとしてビジネスチャットツール「Microsoft Teams」があります。Teamsはチャットツールとしての機能、またオンラインビデオ会議機能があり、Microsoft365の中では頻繁に使うツールの１つです。特に、他のアプリとの連携機能が優れており、AI設計研究室ではPower Automate・Power Virtual Agents等と連携させて使っています。今回は「**Microsoft Teamsで”チーム”を新規に作成する方法**」を紹介します。

### Microsoft Teams画面から「チームを作成」

まずTeamsのアプリ画面の左にはメニュがあり、上から「アクティビティ」「チャット」「チーム」と選択用アイコンが並んでいます。この中からまず「チーム」のアイコンをクリックします(1.)。次に画面右上の「チームに参加/チームを作成」のボタンをクリックして(2.)プルダウンメニュが出たら「チームの管理」のボタンをクリックします(3.)。
![Teams1edit.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77235/5bdf1d9e-6e88-ca73-0119-f93a4c6e39ce.png)

次に「チームを作成」のボタンを選択します。
![Teams2edit.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77235/a14bf399-edc0-cf79-cc79-6cba87a7303b.png)


### チームの種類を選択して、チーム名を記入

ポップアップでチームの種類が出てきます。ここでは「その他」を選択しておきます。
![Teams3edit.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77235/cbd4d1ec-4d87-93f3-10a9-15b272e95cce.png)

次にチーム名を記入して「次へ」のボタンを押します。チームの説明欄は、後で記入すれば大丈夫です。
![Teams4edit.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77235/01f458ed-51fa-4506-bc03-2a631f06b4d5.png)

メンバー追加の画面が出てきますが、後からメンバは追加ができるので「スキップ」を選択します。
![Teams5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77235/6420946d-2b84-1411-5d44-41d17282074b.png)

これで新しいチーム「NewTeam」が作成出来ました。
![Teams6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77235/0aee3d3e-1d5c-e019-896c-cd0f35e66098.png)


### 新チームでメッセージ投稿

試しに新しいチームで、メッセージ文を投稿してみます。左下にある「新しい投稿」ボタンをクリックすると、メッセージ文の入力画面になります。画面の白枠の所に、メッセージを記入してみましょう(1.)。メッセージの作成が完成したら、折紙飛行機のマークを押すことで、メッセージ投稿が完了します。
![Teams7edit.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77235/92a8569d-d34f-de50-650c-580be5810a48.png)

### チームアイコンの右上から「チームの削除」が可能

チームアイコンの右上の「・・・」をクリックするとチーム管理メニュが出て来ます。この中に「チームの削除」メニュもありますので、作成したチームの消去が可能です。

![Teams11edit.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77235/90de3864-046e-8d1d-6700-7eb91aaae690.png)

今回は、Microsoft Teamsで新規にチームを作成する一通りの流れを紹介しました。グループでのメンバ間の連絡に、Microsoft Teamsのメッセージ機能は役立ちます。Teamsを利用する事で、学生のグループ活動が活発になればと期待しています。
YOLOv5を使って動画から物体検出をする

#はじめに
Google Colaboratory上でYOLOv5を使用して、物体検出をしました。

#参考
参考にしたのはこちら：[Google ColabでYOLOv5を使って物体検出してみた/@shoku-pan](https://qiita.com/shoku-pan/items/31bf3c975b73db153121)
このページに書いてあるものをそっくりそのままやれば画像の検出ができます。

YOLOv5のGithubはこちら：[Github YOLOv5](https://github.com/ultralytics/yolov5)

#Google Colabを用意する
Google Colabを開き、「ファイル」→「ノートブックを新規作成」でワークスペースを作ることができます。

#コードを書いていく
参考にあるページのやり方をそっくりそのまま書いていきます。
こちらのページの環境もGoogle Colabのため、Google Colabで作っていく分には修正は必要ありません。
しかし、Google Colabの無料のバージョンを使っているためか、以下のコマンドを実行する場合にエラーが発生しました。(Runtime Errorと実行画面の1番下に出てきます)

```
!python train.py --img 640 --batch 16 --epochs 300 --data coco128.yaml --weights yolov5x.pt
```

このコマンドでは、YOLOv5xという最も大きなモデルで学習を行おうとしています。(その分精度は良いです)
容量が大きすぎるためか、無料の環境では学習は難しいようでした。
そのため、1番小さいモデル(5s)で学習させます。
上のコマンドの1番最後の部分「yolov5x」を「yolov5s」に変更します。変更したものが以下のコマンドです。

```
!python train.py --img 640 --batch 16 --epochs 300 --data coco128.yaml --weights yolov5s.pt
```
こうすると実行できるはずです。

*それでも実行できない場合はエポック数を減らしてみます(その分精度は下がるでしょう)*
*エポック数を半分にしたコマンドは以下のようになります*

```
!python train.py --img 640 --batch 16 --epochs 150 --data coco128.yaml --weights yolov5s.pt
```

もう一つ上のコマンドと見比べてみると「--epochs」の後の数字が半減していることがわかると思います。

#動画から物体検出をする
参考ページでは推論の際に画像を使っています。それを動画から検出できるようにしましょう。
まずは動画をアップロードすることから始めなければなりません。今回は自分のPCからmp4ファイルをアップロードします。

```
from google.colab import files
uploaded = files.upload()
```

上のコマンドを実行すると、「ファイル選択」というボタンが出てくるため、そこから物体検出をしたい動画をアップロードしましょう。
次に、物体検出をします。

```
!python detect.py --source data/images --weights yolov5x.pt --conf 0.50
```
これは参考ページの推論のコマンドです。
まず、学習を5sを用いて行いましたのでこちらも「yolov5x」から「yolov5s」に変更します。
そして、検出する対象(--source部分)を変更します。(下コマンド)

```
!python detect.py --source (自分がアップロードした動画ファイル名) --weights yolov5s.pt --conf 0.50
```

ファイル名がわからない場合、!ls -lとコマンドを打ち込み、確認してみると良いかもしれません。
さて、実行するとどんどん検出していきます。当たり前ですが、動画時間が長ければ長い程時間がかかります。

#動画を保存する
全て検出し終えたら「Results saved to (場所)」というのが出てきます。
そこにアクセスして動画ファイルをダウンロードしましょう。コマンドは以下のようになります。

```
rom google.colab import files
files.download('(保存場所)/(ファイル名)')
```

これで動画ファイルがPCにダウンロードされます。
![スクリーンショット 2021-11-22 15.08.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2311664/0157edea-d7ba-456f-cb39-ca99607a2e82.png)



このように検出したものに対して枠で囲まれます。
1番小さいモデルでの検出ですが、手のみでも人間を検出していたり、後ろのぼやけている女性も検出していたり、想像していたよりも中々の精度で検出できました。

#さいごに
今回は1番小さいモデルでも満足のいく結果が得られましたが、どのくらいの精度が必要なのかを考えてモデルを選ぶと失敗しないでしょう。
また、今回はPCからファイルのアップロード/ダウンロードをしましたが、Google Driveからファイルのコピーを行うなどの操作もできますので、適宜置き換えて自分のやりやすい環境でやってみてください。(方法は参考文献3つ目のページに載っています)

#参考文献
[Google ColabでYOLOv5を使って物体検出してみた](https://qiita.com/shoku-pan/items/31bf3c975b73db153121)
[YOLOv5/Github](https://github.com/ultralytics/yolov5)
[Google Colabのファイルのアップロードとダウンロード](https://note.com/npaka/n/n0b942a95ca5b#uQi98)
WAS設計その5　接続タイムアウト・読み取り/書き込みタイムアウト

接続タイムアウトは、TCPレベルでのタイムアウト

読み取り・書き込みタイムアウトは、TCP接続後、アプリケーションサーバでの処理時間が設定した値までに終わらない場合の値。
（※アプリで無限ループに入ったとか、DBや外部システムからの応答が返ってこないなど）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2291303/ec83a920-0ff4-10e5-2cfa-87201647b68e.png)

すごく大事な値なのできちんと設計する必要があります。

まぁ、DBのタイムアウトより長く。
IHSのタイムアウトよりは短くがいいんですかね。
Overleafで日本語の表示がうまくいかない

#この記事について
Overleafでコンパイラの設定とlatexmkrcの作成をしても日本語の表示がうまく行かなかった時の備忘録です．

#状況
情報処理学会研究会の提供フォーマットのzipファイルをダウンロードし、Overleafにアップロードして使った所 package inputenc error unicode character というエラーなどが大量に出て使えませんでした。[こちらの記事](https://doratex.hatenablog.jp/entry/20180503/1525338512)などを参考にし、コンパイラの設定とlatexmkrcの作成をしましたが解決しませんでした。

#解決方法
latexrkmcを一番上の階層に移動します。
もともとフォーマットをアップロードして使ったため、そのフォルダができていてその中にlatexrkmcを入れてしまっていました。
![スクリーンショット 2021-11-22 15.35.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610292/377f3bc7-bc52-6cba-cbbf-9bb79fc06477.png)



latexrkmcを下にドラッグしてフォルダの外に移動させた所、無事に日本語を表示することができました。
![スクリーンショット 2021-11-22 15.35.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610292/c7499221-f02c-7380-c213-1df241d031b7.png)
コマンドプロンプトでnode.js+Express運用時に停止してしまう

# Node.js + Express がなぜか止まっている

手軽にWebサーバが立てられるこの環境に重宝しています。
staticに公開フォルダを指定すれば、画像でもテキストファイルでもhttpで出せるなんて、ありがたい。

フロントエンドVue.js、バックエンドNode.js+Expressで開発中に、途中でいいから公開して使わせてと言われて、テストもろくにできていないものを公開することになった時、問題が発生したため、備忘録として、ここに記載することにした。

結論から言うと、Node.jsとか関係ない、コマンドプロンプトの問題というオチです。

# 環境

* フロントエンド
 * node.js 16.13.0
 * Vue.js 2.6.11
 * express 4.16.1
* バックエンド
 * node.js 16.13.0
 * express 4.16.1
* (簡易公開時)実行環境
 * Windows 10 Enterprise 20H2
 * コマンドプロンプトを起動し、フロント/バックともに nodeを起動

# 問題

* 何かをきっかけにバックエンドのnodeの応答がなくなる
* 何がきっかけなのか公開側では判断できず、httpサービス利用者からの指摘で判明。確かに応答がないため、Node.jsの再起動をするの繰り返しをしていた。（無知だった。）

# 原因

コマンドプロンプトでクリックしたことにより、「簡易編集モード」になり、コマンドプロンプト上のバッチ処理が一時停止になって、動けなくなったのが原因だった。
コマンドプロンプトが「簡易編集モード」であるか否かは、タイトル表示に「選択」とあるかどうかで判断できる。（が、わかりづらい）

![プロンプト.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2311754/b6419a12-9a97-b0df-e90e-12a92f3d9875.png "コマンドプロンプトが簡易編集モード時であることを示すタイトル表示")

# 対処方法
「簡易編集モード」に移行させない設定にする。設定方法は、以下の記事にお任せ。

https://qiita.com/gdofrank/items/64d13e364b773246f72d

# フロントエンドでは現象は起きない
で、解決したのだけども、フロントエンド側は簡易編集モードでも、httpでリロードがかかっても問題なくSPAのページを表示してくれる。キャッシュが残っているからなのか、Node.js+ExpressのStaticフォルダを指定しているとこの問題が起きないのか、切り分けはできていない。なんでだろう。わかったら、追記する予定。

# 最後に
　 いいかどうかは別として、スクリプトのセットをエンドユーザに提供して、エンドユーザ自身にNode.jsサーバを立ててもらう運用があり、この問題があることを知らないと私みたいに「なぜか動かない」という状態になってしまうのが難点。
　 それから、この問題のためにググったけど、Node.js初心者であったこともあって、Node.jsの仕様との切り分けに手間取り、簡易編集モードにたどり着くのに時間がかかった。コマンドプロンプトの側から検索をかけても、PAUSEコマンドの仕様の紹介ページが多く引っかかったのも悔やまれる。
　 わかってしまえば単純だね。しかし、サイレントにバッチ処理を止めるこの仕様はなんなんだ。
AthenaのSQLでPandasのresampleのようなことを行う

以下のようにAWS Data Wrangler使ってAthenaからロードした時系列データを時間単位毎に集計する処理を実行していました。

```python
df.resample("min").mean()
```

よく考えればSQLでもWindow関数使えばできるよな。Athenaでもできるなかな。ということでAthena（というかPresto）のリファレンス読みながら探ってみました。

https://docs.aws.amazon.com/ja_jp/athena/latest/ug/presto-functions.html

結論として `date_trunc関数` を使うことで似たような実装が可能でした。以下にサンプルを書いておきます。

使うのは以下のsampleテーブルです。

|Col|Type|Desc|
|:--|:--|:--|
|time|string|ISO8601形式の文字列形式で入っている|
|value|int|サンプル値|

WINDOW句で定義したもの使い回せなそうなのでPARTITION BYを何度も書くのが面倒ですが。

```sql
SELECT
  time,
  DATE_TRUNC('minute',from_iso_timestamp(time)),
  value,
  MAX(value) OVER (PARTITION BY DATE_TRUNC('minute',from_iso8601_timestamp(time)) ORDER BY time) AS value_max,
  MIN(value) OVER (PARTITION BY DATE_TRUNC('minute',from_iso8601_timestamp(time)) ORDER BY time) AS value_min,
  AVG(value) OVER (PARTITION BY DATE_TRUNC('minute',from_iso8601_timestamp(time)) ORDER BY time) AS value_avg,
  ROW_NUMBER() OVER (PARTITION BY DATE_TRUNC('minute',from_iso8601_timestamp(time)) ORDER BY time) AS row_num
FROM "sample"
ORDER BY time
```

上記のSQL実行してみた結果です。WINDOW関数慣れてない人向けに少し注釈付けています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116068/b542bd8d-5153-98f4-5b49-98a793b16f24.png)


つまりはパーティションを作れば良いので、UNIXTIMESTAMP形式にしてEXCELのFLOOR関数のように特定の秒毎に切る方法もあります。

```sql
-- 15秒毎のパーティション作成
FLOOR(unix_timestamp/15) * 15

-- 30秒毎のパーティション作成
FLOOR(unix_timestamp/30) * 30
```




# 参考URL
https://prestodb.io/docs/0.217/functions/datetime.html
WAS設計その4 セッション管理

たいていの場合、Cookieを使用する。
※ほぼ間違いない。

あとセッションタイムアウト時間は業務要件によって異なるので
確認が必要。
WASの本にもあったけど、あんまりセッションタイムアウト時間が長いと、ヒープがいっぱいになるから気を付けること。
あと接続数がすごくある場合は、メモリー内の最大セッション・カウントも気を付けること。
※10万人が接続する場合などは1000では足りない。
※同時接続数を考慮に入れて。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2291303/0f3d94d6-d48a-7182-db66-6fff8a3e51a6.png)

んでもってCookieをクリックする。

必要に応じてCookie名を変更する。

ちなみに、Cookieを使用して、同じアプリケーションサーバに処理させることを、セッションアフィニティといいます。

CookieをHTTPSセッションに制限
→これに関しては、LB→IHS→WASの構成の場合、チェックを外す
※キャプチャーがよくない。

HTTPOnly属性にすること。セキュリティ観点から。

Cookie　最大経過時間
→まぁデフォルトのブラウザセッションでOKだと思う
※ブラウザ閉じたらセッション忘れますで。
※スマフォアプリ等だとここは1週間とかにすることもある。
※PCの場合はこのままでOK。



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2291303/460bf584-8070-3b14-8279-abb6a85350f3.png)

メモリまたはデータベースを使って、セッション情報を維持することを、セッションパーシステンスといいます。

セッション保管方法
なし
メモリ
データベース

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2291303/a57fb88e-ff83-8914-6d33-713138910dc0.png)

データベースの場合は、設定を入れると勝手にDB側に接続して、テーブルを作ってくれる。
またどこかでエビデンス張ります。
【Android】ViewPager2の削除がずれる

# この記事に登場するもの
* ViewPager2
* FragmentStateAdapter
* DiffUtil
* 削除がなんかズレる

# AndroidDeveloper
https://developer.android.com/training/animation/vp2-migration?hl=ja

# ViewPager2ざっくり実装部分
MyFragmentがViewPagerを保持し、1つ1つのPageFragmentが削除ボタンでadapterに削除をかける想定。
PagerAdapterはDiffUtilを使って画面を更新する。
※この実装だと、削除すると1つずれたページが何故か削除される。

```MyFragment.kt
    lateinit var pagerAdapter: PagerAdapter

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        pagerAdapter =　PagerAdapter(this, pageList)
        binding.viewPager.apply {
            adapter = pagerAdapter
        }
    }
```

```PagerAdapter.kt
    private val list = mutableListOf<PageItem>()

    override fun getItemCount() = list.size

    override fun createFragment(position: Int) = PageFragment.newInstance(list[position])

    fun refresh(newList: MutableList<PageItem>) {
        val diff = DiffUtil.calculateDiff(object : DiffUtil.Callback() {
            override fun getOldListSize(): Int {
                return list.size
            }

            override fun getNewListSize(): Int {
                return newList.size
            }

            override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
                return list[oldItemPosition].name == newList[newItemPosition].name
            }

            override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
                return list[oldItemPosition].name == newList[newItemPosition].name
            }
        })

        list.clear()
        list.addAll(newList)

        diff.dispatchUpdatesTo(this)
    }
```
```PageFragment.kt
    binding.deleteButton.setOnClickListener {
        val newList = viewModel.deletePage()
        (parentFragment as MyFragment).pagerAdapter.refresh(newList)
    }
```

# 解決策
PagerAdapterに以下を実装する

```PagerAdapter.kt
    override fun containsItem(itemId: Long): Boolean {
        return list.map {
            it.hashCode().toLong()
        }.contains(itemId)
    }

    override fun getItemId(position: Int): Long {
        return list[position].hashCode().toLong()
    }
```
実はAndroidDeveloperの真ん中らへんにしっかり書いてあるのだが、こんなの気づかないよ。。。
> 注: DiffUtil ユーティリティ クラスは、ID に基づくアイテムの識別に依存します。ViewPager2 を使用して編集可能コレクションのページングを行う場合は、getItemId() と containsItem() もオーバーライドする必要があります。
また、getPageWidth() メソッドは、ViewPager2 ではサポートされていません。現在 ViewPager で getPageWidth() を使用して隣接ページへのピーキングを有効にしている場合は、代わりに、RecyclerView の clipToPadding 属性を使用する必要があります。詳細については、サンプルアプリをご覧ください。
Kotlin/JS ReactNode型に文字列以外入れたい

ちょっとハマってしまったのでメモ

これだとエラー

```kotlin
OutlinedInput {
  attrs {
    id = "savecode-adornment"
    label = ReactNode("セーブコード")
    multiline = true
    endAdornment /*:ReactNode?*/ = InputAdornment { //Error!!!!
        attrs.position = "end"
        IconButton {
          CopyAll()
        }
    }
  }
}
```
createElementで囲むとOK

```kotlin
createElement {
  //いれる
}
```

例

```kotlin
OutlinedInput {
  attrs {
    id = "savecode-adornment"
    label = ReactNode("セーブコード")
    multiline = true
    endAdornment = createElement {
      InputAdornment {
        attrs.position = "end"
        IconButton {
          CopyAll()
        }
      }
    }
  }
}
```
adb コマンド

この記事では、よく使う adb コマンドをまとめます。
Android Debug Bridge version 1.0.41
Version 31.0.3-7562133

######adb が使用可能な（adb サーバーに接続している）デバイス（シリアル番号）の確認
adb devices

```
$ adb devices
List of devices attached
emulator-5556   device
```

adb を使用する際に、デバイスが複数接続されている場合は、コマンドを送るデバイスのシリアル番号を ```-s``` (use device with given serial)　で指定します。

```
adb -s emulator-5554 ...
```

######アプリのインストール
adb install [apkのパス]

```
$ adb install app-debug.apk
adb: failed to install app-debug.apk: Failure [INSTALL_FAILED_TEST_ONLY: installPackageLI]
-t
```

上記のようなエラーが出る場合は、```-t```(allow test packages)を付加します。

```
$ adb install -t app-debug.apk
Performing Streamed Install
Success
```

######デバイスからファイル/ディレクトリをコピーする
adb pull [コピー対象のパス] [コピー先のパス]
例：デバイス上の data/data/com.sample.app/log.txt ファイルを PC の test フォルダにコピーする場合

```
adb pull data/data/com.sample.app/log.txt test
```

######デバイスにファイルをコピーする
adb push [コピー対象のパス] [コピー先のパス]
例：PC 上の log.txt ファイルをデバイスの data/data/com.sample.app/ フォルダにコピーする場合

```
adb push log.txt data/data/com.sample.app/
```

######アプリ起動
adb shell am start -n [パッケージ名プレフィックス付きのコンポーネント名]

```
adb shell am start -n com.sample.app/com.sample.app.MainActivity
```

######アプリ停止
adb shell am force-stop [パッケージ名]

```
adb shell am force-stop com.sample.app
```

######アプリのキャッシュ削除
adb shell pm clear [パッケージ名]

```
adb shell pm clear com.sample.app
```

######Activityの状態確認
下記のコマンドは、フォーカスロスト等の不具合解析時、Activityの状態を確認するのに役立ちます。

```
adb shell dumpsys activity top
```

出力内容の```View Hierarchy```の部分には、Viewの状態（表示状態や位置、フォーカスの有無）が出力されます。

下記の場合は、MainActivityのListViewにフォーカスが当たっていることがわかります。
詳細な見方は、[別の記事](https://qiita.com/yoshihiro-kato/items/840d3e8b4ccf7ca286e6)に記載しています。

```
...
    View Hierarchy:
      DecorView@1f98dbe[MainActivity]
        android.widget.LinearLayout{f656e1f V.E...... ........ 0,0-1080,2148}
          android.view.ViewStub{b7856c G.E...... ......I. 0,0-0,0 #10201af android:id/action_mode_bar_stub}
          android.widget.FrameLayout{652e735 V.E...... ........ 0,171-1080,2148}
            androidx.appcompat.widget.ActionBarOverlayLayout{bbcc7ca V.E...... ........ 0,0-1080,1977 #7f080065 app:id/decor_content_parent}
              androidx.appcompat.widget.ContentFrameLayout{47ccd3b V.E...... ........ 0,154-1080,1977 #1020002 android:id/content}
                androidx.constraintlayout.widget.ConstraintLayout{64d8c58 V.E...... ........ 0,0-1080,1823 #7f08009d app:id/main}
                  android.widget.ListView{3d7c1b1 VFED.VC.. .F...... 0,0-1080,1823 #7f0800cb app:id/sampleList aid=1073741824}
...
```

######キーイベントを送る
デバイスに対してキー操作を行う場合は下記のコマンドで、キーイベントを送ることが出来ます。

例：十字キーの下のイベントを送る場合

```
adb shell input keyevent KEYCODE_DPAD_DOWN
```

キーコードは[KeyEvent](https://developer.android.com/reference/android/view/KeyEvent)に記載があります。

######バグレポートを取得する
バグレポートには、logcat　や実行されているスレッドの情報などが含まれ、不具合の解析に役立ちます。
※　スレッドの不具合解析は[別の記事](https://qiita.com/yoshihiro-kato/items/5f9653c48bdd906c618f)に記載しています。

```
adb bugreport
```
Ectoでsoft deletion


ectoでsoft deletionを実装する流れについてまとめます。

Phoenixで新しいコンテキストを作成するときに論理削除をつける手順が多いため、毎回毎回調べるのが面倒でした。今後の作業が楽になればと思ってます。

以下例としてブログ作成をした際にPostスキーマに論理削除をつけます。

楽をしたい場合は[ライブラリ](https://hexdocs.pm/ecto_soft_delete/api-reference.html)を使用できます😂

## コンテキストをLiveViewとして作成

```
mix phx.gen.live Blog Post posts title body deleted_at:datetime
```

## スキーマファイルにdelete_changesetを追加

```elixir:myapp/blog/post.ex
defmodule MyApp.Blog.Post do
  use Ecto.Schema
  import Ecto.Changeset

  schema "posts" do
    field :body, :string
    field :title, :string
    field :deleted_at, :naive_datetime

    timestamps()
  end

  @doc false
  def changeset(post, attrs) do
    post
    |> cast(attrs, [:title, :body]) # <- do not include :deleted_at
    |> validate_required([:title, :body]) # <- do not include :deleted_at
  end

  @doc false
  def delete_changeset(post, attrs) do
    post
    |> cast(attrs, [:deleted_at])
    |> validate_required([:deleted_at])
  end
end

```

## Soft Deleteされたエントリがクエリされないようにコンテキストファイルを変更する

```elixir:myapp/blog/post.ex
defmodule MyApp.Blog do
  import Ecto.Query, warn: false
  alias MyApp.Repo
  
  alias MyApp.Blog.Post
  
  def list_posts do
    query = from p in Post, where: is_nil(p.deleted_at) # <- added
    Repo.all(query)
  end

  def get_post!(id) do
    query = from p in Post, where: is_nil(p.deleted_at) # <- added
    Repo.get!(query, id)
  end

  ...

  def delete_post do
    now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second) # <- added
    post
    |> Post.delete_changeset(%{deleted_at: now})
    |> Repo.update() # <- altered to update
  end
end
```

## Soft Deletionの是非
しかし論理削除はデータベースのデータベース専門の方々からは[あまり好意的ではない意見](https://qiita.com/Jxck_/items/156d0a231c6968f2a474)が散見され、是非が問われているようです。
ユーザーがデータを削除したいというニーズに応えるにはどのようなDB設計をするのが正解なのかがよくわからんです。
SwiftのCLIで出力に色をつける

Xcode上のコンソールには色をつけて表示することができませんが、ターミナルで実行するCLIには色をつけて表示することができます。

# 実装

```swift
extension String {
    enum ConsoleColor: Int {
        case black = 30
        case red
        case green
        case yellow
        case blue
        case magenta
        case cyan
        case white
    }

    enum ConsoleStyle: Int {
        case `default`
        case bold
        case thin
        case italic
        case underline
        case blink
        case fastBrink
        case reverseFrontBack
        case hidden
        case cancel
    }

    func colored(_ color: ConsoleColor, style: ConsoleStyle = .default) -> String {
        "\u{001B}[\(style.rawValue);\(color.rawValue)m\(self)\u{001B}[0m"
    }
}
```

# 使い方

```swift
let text = "This is bold yellow text\n".colored(.yellow, style: .bold)
    + "This is blue background text\n".colored(.green, style: .reverseFrontBack)
    + "This is default color text"
print(text)
```

**結果**

![スクリーンショット 2021-11-22 15.03.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197742/fecb426b-692b-874b-24a9-6a0be89da1b7.png)

参考までに、こちらのリポジトリで使用しております。
https://github.com/s2mr/memo-cli
MongoDBの重複データをレコードから削除

# 始めに

MongoDBを利用している際に、重複したデータを複数一括で削除する必要があったので、その際に実行したクエリを共有します。やりたいことは単純だったのですが、ドキュメントがあまりなくクエリ構築に悩んだので備忘録として残しておきます。

MongoDBのデータ操作コマンドに関しては、以下のリンクを参照。

[Database Commands — MongoDB Manual](https://docs.mongodb.com/manual/reference/command/)

# 実行

## 前準備

MongoDBに、以下のように`username`に同じ値を持つユーザが複数登録されてしまっている。この状態の際に、`username`で重複するデータを削除したい。

```sh:
> db.user.find()
{ _id: ObjectId("619b2dfa75ca1af74dbe6d8d"),
  username: 'taro',
  age: 18 }
{ _id: ObjectId("619b2e0275ca1af74dbe6d8f"),
  username: 'taro',
  age: 18 }
{ _id: ObjectId("619b2e1175ca1af74dbe6d91"),
  username: 'saburo',
  age: 22 }
{ _id: ObjectId("619b2e1875ca1af74dbe6d93"),
  username: 'saburo',
  age: 22 }
{ _id: ObjectId("619b2e1c75ca1af74dbe6d95"),
  username: 'saburo',
  age: 22 }
{ _id: ObjectId("619b2e2e75ca1af74dbe6d97"),
  username: 'siro',
  age: 25 }
```


## 重複削除のコマンド

`username`要素の重複を削除する場合、以下のコマンドを実行する。

```sh:
> db.user.aggregate([
  { $group:
    { 
    _id: "$username",
    dups: { "$addToSet": "$_id" }, 
    count: { "$sum": 1 } 
    }
  }, 
  { $match: 
    { 
    count: { "$gt": 1 }
    }
  }
]).forEach(function(doc) {
    doc.dups.shift(); 
    db.user.remove({_id : {$in: doc.dups }});
})
```

実行後再度確認すると、重複が削除されていることが確認できる。

```sh:
> db.user.find()
{ _id: ObjectId("619b2dfa75ca1af74dbe6d8d"),
  username: 'taro',
  age: 18 }
{ _id: ObjectId("619b2e1875ca1af74dbe6d93"),
  username: 'saburo',
  age: 22 }
{ _id: ObjectId("619b2e2e75ca1af74dbe6d97"),
  username: 'siro',
  age: 25 }
```

# クエリの解説

先ほど実行したクエリの各要素の意味は以下の通り。

```sh:
> db.user.aggregate([
  { $group: # 同じusernameを持つものでグループ化
    { 
    _id: "$username", # ここに重複を集約したいキーを指定する
    dups: { "$addToSet": "$_id" },  # dupsと言う辞書に重複が発生した_idを格納する。
    count: { "$sum": 1 }  # usernameの出現回数をカウント
    }
  }, 
  { $match: # 上記のクエリで集約した結果に対して条件に合うもののみを抽出
    { 
    count: { "$gt": 1 } # countが2以上(=重複が存在するもの)のみ抽出
    }
  }
]).forEach(function(doc) {
    doc.dups.shift(); # 重複が存在するキーのうち、先頭1つ残すために、先頭の要素を削除対象から除外
    db.user.remove({_id : {$in: doc.dups }}); # キーの配列より一致する_idを持つ要素を削除
})
```
R 3dplot3通り

※備忘録

使用データセット
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1347377/e83214b4-8982-d88e-d90d-b784ce35377a.png)

①RGLパッケージで静的な3次元プロットを得る。

```
data(trees)
library("rgl")
plot3d(trees)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1347377/47ad378e-8a88-4662-3908-1fc2b1f787c9.png)

一応マウスドラッグで回転可能。出力もplot3dの構文かRGLパッケージの関数を使えばできそう(やらないけど)。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1347377/16b43b79-4072-c41f-975a-12e3dfd0ad85.png)


②RGLパッケージでWebGLで動くHTMLファイルを保存できるらしい。

```
# webgl形式？で出力してくれるはずなのだが、手元のchromeだとjs有効にしても表示されない
data(trees)
library("rgl")
plot3d(trees)
writeWebGL(width=500, height=550)
```
上記手順で出力したいWebGLフォルダの中に目的のファイルを出力できる。
あとはブラウザで表示するだけなのだが、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1347377/af551e8f-f432-4f84-a0a0-d815282a8d8c.png)

以下のようになぜかjs有効でも見ることができない。今回はメモなのでこの辺は深く立ち入らない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1347377/c38f4107-a6da-b4c8-271b-267a116f05d4.png)


③アニメーションライブラリを使用してアニメーション形式で出力
ここも深く立ち入らないが、以下の構文でアニメーションファイルを出力できる。
ggplot2の拡張機能にも類似の機能があるらしいので、後々調べる。

```
install.packages("animation")
library("animation")
library("scatterplot3d")
# ani.start()
animation::saveHTML(expr=for(i in 0:35) {
                        scatterplot3d(trees, angle = i*10+5)
                      })
```
上記実行でhtmlファイルを得られるので興味がある方は実行してみてください。
[iOS]Xcode13・iOS15・Storyboardから設定したUIButtonに設定した画像がうまく設定されない。

Xcode13でStoryboardからUIButtonを設定すると、iOS15からの`UIButton.Configuration` (https://developer.apple.com/documentation/uikit/uibutton/configuration )= plain, filled, gray, tintedの４つのうちのplainが最初から設定された状態になり、iOS14以前のUIButtonと違う感じになる。

従来と同じ感じで使いたい場合は、Attributes Inspector > UIButton > Style > Default に設定すると、元に戻る。

意図せずplain設定になっており、設定した画像や文字が想定と違って表示されてしまい、少し混乱してしまった。
React NativeでSVGを扱う

# はじめに
React Nativeでは、htmlのようにsvgファイルを素の状態で利用することができません。
react-native-svgというライブラリを使用する必要があり、React Nativeで扱えるように変換する必要があります。
変換にはいくつか方法がありますが、下記のような種類があります。

- [react-native-svg-transformerでsvgファイルをそのまま使う](#react-native-svg-transformerでsvgファイルをそのまま使う)
- [CLI - @svgr/cliでコンポーネントファイルに変換](#cli---svgrcliでコンポーネントファイルに変換)
- [GUI - SVG Playgroundでコンポーネントファイルに変換](#gui---svg-playgroundでコンポーネントファイルに変換)
- [最初からreact-native-svgで書く](#最初からreact-native-svgで書く)

# 各方法のメリット・デメリット

## react-native-svg-transformerでsvgファイルをそのまま使う

https://github.com/kristerkari/react-native-svg-transformer

svgファイルを直接importする方法です。
大量のsvgファイルを扱う場合に、設定を書くだけで利用できます。

- メリット
    - 変換の手順を踏まず、svgファイルを直接読み込める。
    - 設定を書けば、propsによるfillやstrokeの色指定等可能
- デメリット
    - svgファイルの構成が統一されていない場合、設定での調整が難しい
    - TypeScriptを使用する場合、declarationが必要
        - 公式参照 https://github.com/kristerkari/react-native-svg-transformer#using-typescript

## CLI - @svgr/cliでコンポーネントファイルに変換

https://github.com/gregberge/svgr

svgファイルをCLIでreact-native-svgに変換したファイルをimportする方法です。
変換後のファイルがどうなっているか確認が容易です。

- メリット
    - 変換後のファイルを確認、調整可能
    - 設定を書けば、propsによるfillやstrokeの色指定等可能
- デメリット
    - オプションが一部しかconfigファイルに書けないため、細かい設定、調整をしたい場合にコマンドが長くなりがち
    - svgファイルの構成が統一されていない場合、設定での調整が難しい

## GUI - SVG Playgroundでコンポーネントファイルに変換

https://react-svgr.com/playground/

GUIでsvgファイルを変換、調整可能な方法です。
ローカルのsvgファイルをドラッグアンドドロップして読み込めます。

- メリット
    - 各ファイルに対して個別の設定、調整が可能
    - CLIや細かい設定での調整が苦手でも扱いやすい
- デメリット
    - 一つひとつのファイルに対して手動変換を行うので、svgファイルの数が増えれば増えるほどしんどい

## 最初からreact-native-svgで書く

通常、svgエディタを使用してsvgを作成、その後React Native用に変換という手順をすっ飛ばし、コードで書いちゃうマンの方法です。
自作のグラフを作成する場合などに有効な方法です。

https://github.com/react-native-svg/react-native-svg

- メリット
  - svgファイルとはなんだったのか
- デメリット
  - しんどい。しんどくない？

# さいごに

react-native-svgではまだサポートされていないsvgの機能があります。
変換後の見え方に違和感がある場合は、cliやguiで変換するとサポートされていない機能についてコメントされるので確認してみてください。

他にも良い方法やおかしな点がある場合には、コメント頂けるとありがたいです。
サービスアカウントキーなしでTerraformを実行する方法

## 概要

Terraformの実行方法で多くの場合サービスアカウントキーをダウンロードする手順となっているため、
GCP上のリソース作成をサービスアカウントキーを生成せずにTerraformで行う方法を記載する

## 手順

### 1. Terraform用のサービスアカウント作成

```sh
gcloud iam service-accounts create terraform --display-name "Account for Terraform"
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member serviceAccount:terraform@${PROJECT_ID}.iam.gserviceaccount.com \
  --role roles/editor
```



### 2. 操作ユーザにサービス アカウント トークン作成者 (roles/iam.serviceAccountTokenCreator) 権限を付与

```sh
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member user:${USER_EMAIL} \
  --role roles/iam.serviceAccountTokenCreator
```

### 3. 実行するMakeFileを作成する

"sa"を「1.」で作成したサービスアカウント名に変更

```sh
SERVICE_ACCOUNT = "sa"

SHELL := /usr/bin/env zsh

init:
	@GOOGLE_OAUTH_ACCESS_TOKEN="$(shell gcloud --impersonate-service-account=${SERVICE_ACCOUNT} auth print-access-token)" terraform init

plan:
	@GOOGLE_OAUTH_ACCESS_TOKEN="$(shell gcloud --impersonate-service-account=${SERVICE_ACCOUNT} auth print-access-token)" terraform plan

apply:
	@GOOGLE_OAUTH_ACCESS_TOKEN="$(shell gcloud --impersonate-service-account=${SERVICE_ACCOUNT} auth print-access-token)" terraform apply

destroy:
	@GOOGLE_OAUTH_ACCESS_TOKEN="$(shell gcloud --impersonate-service-account=${SERVICE_ACCOUNT} auth print-access-token)" terraform destroy

.PHONY: init plan apply destroy
```

## 4. TerraformをMakeFile経由で実行

```console
make plan
```

### 「make: Nothing to be done for `plan'.」が発生

コマンド行がTABで始まっていない場合発生する。


### 参考サイト (元ネタ)

[Stop Downloading Google Cloud Service Account Keys! | by Ryan Canty | Medium](https://jryancanty.medium.com/stop-downloading-google-cloud-service-account-keys-1811d44a97d9)
GitからGitHubにpush

初Gitだったので今後のために

#1.Gitの準備(リポジトリの作成)
```
$ git init
```



#2.共有するファイルの選択
```
$ git add ファイル名
```

#3.ファイルのコミット
```
$ git commit -m  "メッセージ"
```

#4.リモートリポジトリの登録
```
$ git remote add origin (GitHubのURL)
```

#5.push
```
$ git push origin main
```


## ※参考
### ユーザー名とメールアドレスの設定
```
$ git config --global user.name ユーザー名
$ git config --global user.email メールアドレス
```


以上
押した手応えのあるボタンの作り方

ボタンが押されたときに何も手応えがないと、「本当に押したのかな？」とちょっと不安にさせてしまいます。そこで押した感が出るような効果をボタンにつけてみましょう。とはいっても効果のため素材を作るのは大変なので、元の素材をプログラムで変化させて効果を出してみます。
基本は「1. 最初の状態」→「2. ちょっとずつ変える」→「3. 最初の状態」というプログラムを書きます。
このサンプルでは「大きさを変える」「色を変える」「位置を変える」の三通りの効果をボタンに与えてみました。お気に入りの効果は見つかったでしょうか？

<img width="55%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75307/222e9f76-fb3b-589d-3810-0258a43a6d2e.png">

サンプルプロジェクト

https://scratch.mit.edu/projects/605002285

![スクリーンショット](https://cdn2.scratch.mit.edu/get_image/project/605002285_480x320.png)
C# 参照型の代入でハマった話

基本も基本、参照型変数代入で半日ハマってしまいました。同じオブジェクトを参照している変数は、どの変数を操作してもすべての変数が影響を受けるはずですが、そうならない！！　んなアホな。
よくよく考えれば何でもない話なのですが。

##参照型
C#には参照型という種類の型があります。クラスを使って定義した型は参照型になります。
参照型の変数は値そのものは持っておらず「値への参照」を保持しています。変数値を別の変数へ代入する時も、実際には値のコピーは行われず、この「値への参照」がコピーされます。なので、コピー先の変数で変数値を操作したらコピー元の変数も同じように変わります。
これは、C++でポインタや参照を使う場合と同じです。C++と違うのは、これが言語側で勝手に処理されるという点です。

##参照型代入の例（１）

```C#:参照型の代入
	class Program
	{
		class RefType
		{
			public int val1 = 0;
			public int val2 = 0;
		}

		static void Main(string[] args)
		{
			RefType A = new RefType { val1 = 1, val2 = 2 };
			RefType B = A;
			B.val1 = 111; // Bのval1を変更
			B.val2 = 222; // Bのval2を変更

			Console.WriteLine($"A=[{A.val1} ​{A.val2}]");
			Console.WriteLine($"B=[{B.val1} {B.val2}]");
		}
	}
```
```:結果
A=[111 222]
B=[111 222]
```
変数Bを操作して、変数Aも変化しています。普通です。

##参照型代入の例（２）
これがハマった原因です。

```C#:参照型の代入
	class Program
	{
		class RefType
		{
			public int val1 = 0;
			public int val2 = 0;
		}

		static void Main(string[] args)
		{
			RefType A = new RefType { val1 = 1, val2 = 2 };
			RefType B = A;
			// 新しいオブジェクトCを作って、
			RefType C = new RefType { val1 = 111, val2 = 222 };
			B = C; // Bのval1とval2を同時に変更

			Console.WriteLine($"A=[{A.val1} {A.val2}]");
			Console.WriteLine($"B=[{B.val1} {B.val2}]");
		}
	}
```
```:結果
A=[1 2]
B=[111 222]
```

変数Bを**そのクラスオブジェクトの代入で**変更したのですが、変数Aは変化しません。
これは、変数Bに変数Cを代入した瞬間に変数Bは変数Aの値の参照をやめて、変数Cの値の参照になるからです。Cを代入した時点で変数AとBはなんの関係もなくなってしまいます。

##実際にハマったコード

```C#:
public void function()
{
    private Setting setting = mainWindow.setting;
    ....
    setting = (Setting)xml.Deserialize(sr);
    ....
}
```
mainWindowクラスのsettingの参照にxmlファイルを読み込もうとしました。しかし、何故か、どうしてもmainWindowクラスのsettingは変更されませんでした。チャンチャン。
lambdaでno module errorが出る

## やりたいこと

AWS Lambda にて、pythonのスクレイピングをしたい。

## 詰まったこと

ソースコード内で使用しているrequestsについて、no moduleエラーが発生する。

```
Response
{
  "errorMessage": "Unable to import module 'lambda_function': No module named 'requests'",
  "errorType": "Runtime.ImportModuleError",
  "stackTrace": []
}
```

## 対処方法

LambdaのLayerを使用し、使用するモジュールをzipファイルにまとめて読み込んでもらう設定をする。

### ec2内の作業

ec2内でpip installを行い、使用したいモジュールをまとめたフォルダを作成する。
今回は「requests」が対象。「python」フォルダにまとめる。

```
$ mkdir python
$ cd python
$ sudo yum -y install gcc gcc-c++ kernel-devel python-devel libxslt-devel libffi-devel openssl-devel
$ sudo yum -y install python-pip
$ pip install -t ./ requests

```

ec2で作成したフォルダをzipでまとめて、S3バケットに配置。
LayerにオブジェクトURLを指定して、そのLayerを追加。

## 結果

無事動いた。
Active/Standby と Active/Passive の違い

## 勉強前イメージ

どっちも似たようなイメージではある。
切り替えるって感じよね。

## 調査

### Active/Standby と Active/Passive の違い

同じシステムを複数用意して、メイン以外は待機系にしておく方式。
稼働系をactive、待機系をstandby,passiveという
結果的には `Active/Standby` も `Active/Passive` も同じ意味で使われている
Active/Standby(Active/Passive) にも待機の種類が2つある。

### 待機の種類

- ホットスタンバイ

平常時から待機系の電源を入れておく。
常時稼働系とのデータの同期を行っておくことになります。
いつでも障害が起きたら切り替えることができます。

- コールドスタンバイ

待機系の電源を落としておく。
障害が発生したら電源を入れて切り替えますが、データの同期も必要なので
切り替えまでに少し時間がかかります。
電源も入れてないし、データの同期も走らないのでホットスタンバイよりはコストが安くすみます。

## 勉強後イメージ

書き方が違うことが多いからちょっと違う意味なのかなーって思ったけど
結局一緒の意味なのかー

## 参考

- [第15回「冗長化（じょうちょうか）」](https://www.fielding.co.jp/column/it_words/202003_1/)
一个单套打法引发的思考

群里讨论单套打法，林师布置作业：

>北：💗AKT9x
>南：💗xx

互相不缺进手，单套要拿4墩牌，怎么打？

潜艇掏出书本：
![微信图片_20211122144858.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2311521/b6a632b0-53d6-20fa-e0b4-59e15256aab1.jpeg)

一众人表示实战基本都会选择AK连砸

OK,开始验证比较连砸AK和双飞西家QJ的成功率吧

令：
事件A:连砸AK成功拿到4墩
事件B:双飞西家QJ成功拿到4墩

则根据全概率公式：

```math
\begin{align}
P(A)&=P(取4墩|33分布)*P(33分布)+P(取4墩|西4东2)*P(西4东2)+P(取4墩|西2东4)*P(西2东4) \\
    &\quad+P(取4墩|西5东1)*P(西5东1) \\
    &\quad+P(取4墩|西1东5)*P(西1东5)+P(取4墩|西0东6)*P(西0东6)+P(取4墩|西6东0)*P(西6东0) \\
    &=100\%*P(33分布)+(100\%-P(西持有QJxx|西4东2))*P(西4东2)　\\
    &\quad+P(100\%-P(东持有QJxx|西2东4))*P(西2东4)+P(东持有单张Q或J|西5东1)*P(西5东1) \\
    &\quad+P(西持有单张Q或J|西1东5)*P(西5东1)+0+0
\end{align}
```

尼哥大喊一声："慢，在对手51分布时，因为对方持有💗8,所以任何情况下坐庄者也拿不到4墩牌"
好吧，重新计算如下：

```math
\begin{align}
P(A)&=P(取4墩|33分布)*P(33分布)+P(取4墩|西4东2)*P(西4东2)+P(取4墩|西2东4)*P(西2东4) \\
    &\quad+P(取4墩|西5东1)*P(西5东1)+P(取4墩|西1东5)*P(西1东5) \\
    &\quad+P(取4墩|西0东6)*P(西0东6)+P(取4墩|西6东0)*P(西6东0) \\
    &=100\%*P(33分布)+(100\%-P(西持有QJxx|西4东2))*P(西4东2) \\
    &\quad+P(100\%-P(东持有QJxx|西2东4))*P(西2东4)+0+0+0+0 \\
    &=35.53\%+（1-6/15）*24.225\%+（1-6/15）*24.225\%+0+0+0+0 \\
    &=64.48\%
\end{align}
```

```math
\begin{align}
P(B)&=P(取4墩|33分布)*P(33分布)+P(取4墩|西4东2)*P(西4东2)+P(取4墩|西2东4)*P(西2东4) \\
    &\quad+P(取4墩|西5东1)*P(西5东1)+P(取4墩|西1东5)*P(西1东5) \\
    &\quad+P(取4墩|西0东6)*P(西0东6)+P(取4墩|西6东0)*P(西6东0) \\
    &=(1-P(东持有QJx|33分布))*P(33分布)+(1-P(东持有QJ|西4东2))*P(西4东2) \\
    &\quad+(1-P(东持有QJxx|西2东4))*P(西2东4)+0+0+0+0 \\
    &=(1-1/5)*35.53\%+(1-1/15)*24.225\%+(1-6/15)*24.225\%+0+0+0+0 \\
    &=65.51\%
\end{align}
```

**可见，双飞比连砸的成功率高1%左右。**
结果基本与书本吻合。
难道至此大功告成了？
No,作为严谨的研究者，还远远不够。

# 进一步讨论，前方高能
以上P(33分布)等，都是首功后各家持有13张牌的前提下的概率，那在牌局进行到后期时会怎么样？
各家最后剩7张时，

P(33分布):

```math
P(33分布)=C_{6}^{3}*C_{8}^{4}/C_{14}^{7}=40.79\%
```
P(24分布):

```math
P(24分布)= 2*C_{6}^{2}*C_{8}^{5}/C_{14}^{7}=48.95\%
```

P(15分布):

```math
P(15分布)= 2*C_{6}^{1}*C_{8}^{6}/C_{14}^{7}=9.79\%
```

P(06分布):

```math
P(06分布)=2*C_{8}^{7}/C_{14}^{7}=0.47\%
```
 
代入上面式子：

连砸AK：

```math
\begin{align}
P(A)&=100\%*40.79\%+(1-6/15)*24.475\%+(1-6/15)*24.475\%+1/3*4.9\%+1/3*4.9\% \\
    &=70.16\%
\end{align}
```

双飞QJ:

```math
\begin{align}
P(B)&=(1-1/5)*40.79\%+(1-1/15)*24.475\%+(1-6/15)*24.475\% \\
    &=4/5*40.79\%+23/15*24.475\% \\
    &=70.158\%
\end{align}
```

**居然连砸AK比双飞成功高了0.02%左右**
可见，当牌局只剩最后7张牌时，理论计算结果发生变化，连砸AK成功率超过了双飞。
但林师指出，这种情况实战基本不可能发生，所以可以忽略。
M1 Mac(ARM 64bit)で32bit用にクロスコンパイルして実行する方法

今回は、`M1 Mac`で`32bit`の`C/C++`ライブラリを実行できるようにします。

# 準備

`M1 Mac`で`Ubuntu 20.04`を簡単に扱えるハイパーバイザー型のVMである`multipass`を使う。

`Ubuntu20.04`を`ubutu20`という名前のインスタンスで立ち上げる。

```
$ multipass launch 20.04 --name ubuntu20 
```

```
$ multipass shell ubuntu20
```

```
$ sudo apt install build-essential
```


```
.
├── sample.c
├── lib
│   └── libsample.a

1 directories, 2 files
```

# さぁ、やるぞ！

`ARM`アーキテクチャーは、そのままでは`32bit`をコンパイルすることはできないため、クロスコンパイルする必要がある。

アーキテクチャ追加

```
$ sudo dpkg --add-architecture armhf
```

アップデート

```
$ sudo apt update
```

`32bit`環境用の標準ライブラリをインストールする。

```
$ sudo apt install libc6:armhf libstdc++6:armhf
```

シンボリックリンクを追加

```
$ cd ~
$ cd /lib
$ sudo ln -s arm-linux-gnueabihf/ld-2.23.so ld-linux.so.3
```

`32bit`クロスコンパイラのインストール

```
$ sudo apt install gcc-arm-linux-gnueabihf
```

`gcc`を`arm-linux-gnueabihf-gcc`に変更

コンパイル実行

```
$ arm-linux-gnueabihf-gcc -c ./sample.c
```

リンク実行

`libhoge.a`の場合、ライブラリ名は`hoge`になる。

```
$ arm-linux-gnueabihf-gcc -o sample sample.o -Lライブラリ(lib)の絶対パス -lm -lライブラリ名
```

# QEMUのインストール

そのままでは実行することができない。
そこで`QEMU`でエミュレートする。

```
$ sudo apt install qemu-user-binfmt
```

ダイナミックリンクされた`ARM`の実行ファイルは以下のようにルートディレクトリを`QEMU`に明示的に指定すれば実行できるようになる。

```
$ qemu-arm -L /usr/arm-linux-gnueabihf/ ./sample
```

シンボリックリンクを貼ることでそのまま実行できるようにする。

```
$ sudo ln -s arm-linux-gnueabihf/lib /lib/arm-linux-gnueabihf
```

```
$ ./sample
```

できた！

以上の手順で`ARM 64bit`環境にて`32bit`ライブラリのコンパイル・実行ができた。
RHEL設計　その1 OSのPATHの件（RHEL7）

RHEL7のOSのPATHの通し方

```
cat /etc/redhat-release
#Red Hat 7の場合
Red Hat Enterprise Linux Server release 7.7 (Maipo)
```


■■■■■■一般ユーザーの場合■■■■■■

パターン①
org
PATH=\$PATH:\$HOME/.local/bin:\$HOME/bin:

修正後
PATH=\$PATH:\$HOME/.local/bin:\$HOME/bin:/home/aaa



パターン②
OS情報
cat /home/ユーザー情報/.bash_profile
以下の一文がある。
PATH=\$PATH:\$HOME/.local/bin:\$HOME/bin

そのため、一般ユーザーで自分のOSの/home/ユーザー名/binという
ディレクトリを作成し、bin以下にcommandというファイルを作成する

```
touch command
ls command
chmod 755 command
```

commandがtabの候補で出てくることを確認。

rootユーザでも同じことができます。

パターン①
パターン②
でも。
好みだと思うけど、まぁ「/home/ユーザー名/.bash_profile」に追加していくのがよいかなぁと。
[Swift] Combine の flatMap で failure になると、以降は値が流れなくなる問題に対処する


# 初めに

タイトル通りですが、`Combine`の`flatMap`で行う処理が、一度でも`failure`になると、それ以降は値が流れなくなるという困った挙動があります。

かなり前から`Swift Forums`とかでも上がっていますが、現在もなお直っていません。

https://forums.swift.org/t/combine-flatmap-can-result-in-values-after-failure-bug/27834

ということで、色々と対応方法を調べたので掲載しておきます。

## 前提

実装に先立ち、まずは問題の発生したコード例で紹介します。

### 1. Combine を使ったネットワークコード例

`Combine`を用いて、以下のような簡単な API クライアントとレスポンス例を用意しました。

```.swift
final class Repository: NSObject {

    static func fetch() -> AnyPublisher<Response, Error> {
        URLSession.shared
            .dataTaskPublisher(for: URL(string: "https://xxx/yyy/zzz")!)
            .map(\.data)
            .decode(type: Response.self, decoder: JSONDecoder())
            .eraseToAnyPublisher()
    }
}
```

```.swift
struct Response: Decodable {}
```

### 2. flatMap を使った呼び出しのコード

先のネットワークコードを呼び出す時の例を用意しました。
（例えばボタンを押したときにAPIが呼び出されるようなコード）

```.swift
var cancellable = Set<AnyCancellable>()
var didTapButton = PassthroughSubject<(), Never>()

func bind() {
    didTapButton
        .flatMap { // ここで呼び出す
            Repository.fetch() 
        }
        .sink(receiveCompletion: { result in
            switch result {
            case .failure(let error): break
            case .finished: break
            }
        }, receiveValue: { response in
            // do something
        })
        .store(in: &cancellable)
}
```

```.swift
// 実行
didTapButton.send(())
```

### 3. 実装の問題

このとき、API が失敗して一度でも `failure` に来ると、、、

以後 ``didTapButton.send(())`` をいくら呼んでも**値が流れてこない問題**が発生します。
これがタイトルでも述べている `Combine` の `flatMap` の問題です。

## 対応方法

今回はこのコード例を修正する形で対応方法を記載したいと思います。
また、方法を２つ掲載しておきます。

### ① `replaceError` で回避する



```.swift
didTapButton
    .flatMap {
        Repository.fetch()
            .replaceError(with: Response())
    }
    .sink { response in
        // do something
    }
    .store(in: &cancellable)
```

`replaceError` を経由することで、暗黙的に `AnyPublisher<Response, Never>` になるため、`failure` に入ってくることは無くなります。ただし、成功でも失敗でも `sink` に一括で値が入ってくるため、何かしらの判定が必要になっています。

### ② `Result` で返す

① の `sink` では帰ってきた値を**判定する方法がなかった**ので、`Result` 型にすることでこれを実現します。


```.swift
didTapButton
    .flatMap {
        Repository.fetch()
            .map { Result.success($0) }
            .catch { Just(Result.failure($0)) }
    }
    .sink { result in
        switch result {
        case .success(let response): break
        case .failure(let error): break
        }
    }
    .store(in: &cancellable)
```

`map` で `Result` 型にして、失敗時は `catch` でハンドリングしています。こちらも先と同様に、暗黙的に `AnyPublisher<Result<Response, Error>, Never>` になるため、`failure` に入ってくることは無くなります。

この書き方は、せっかく `Combine` で `Response` と `Error` でハンドリングできるものを１つに流してしまうため、`Combine` の良さは失われてしまいます。

ただし、`RxSwift` のような書き方ができるため、人によっても見やすいかもしれません。さらに `RxSwift` の `materialize` のようなものがあれば、さらに分割できたりもしますが、 `Combine` にはないのは残念です。



# 終わりに

~~**Apple が直してくれ！！！**~~

コメントになぜそうなるかのやりとりがあり、わかりやすかったので読んでみてください！

## 余談

`Combine` で `materialize` を実装する方法を載せておきます。

- 自前で実装する場合

https://qiita.com/rizumita/items/8d8365817bd064e838dd


- ライブラリで実装する場合

https://github.com/CombineCommunity/CombineExt#materialize
GCP Compute Engine その①


クラウド勉強のメモ　※2021/11時点

まずは、GCPのConputeEngine(GCE)の勉強。
新規アカウント取得の場合は、90日間/300$相当が無料で使用可能。
また、多くのサービスではある程度の無料枠が設定されているため、それらを利用することで安価に学習することが可能であるが、従量課金のため不要なリソースは停止することを推奨する。

【GCEの無料枠】
・リージョン(us-west1/us-central1/us-east1)
・マシン(e2-micro)
・ディスク(標準永続30GB)
・スナップショット(5GB)
・OS(プレミアム以外)
==>RHEL/Windows/SLES/SQLがプレミアムに該当する。

【無料枠案内】
https://cloud.google.com/free/docs/gcp-free-tier/?hl=ja

【公式料金】
https://cloud.google.com/compute/all-pricing?hl=ja

【構築】
・仮想インスタンス名(free-instance)
・リージョン/ゾーン(us-central1/us-central1-a)
・マシンスペック(E2/e2-micro)

***

![スクリーンショット 2021-11-22 11.40.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396218/252dccc6-7a71-6b00-c3c0-d068feb20ad2.png)

***
・OS(CentOS)
・ディスク(標準永続30GB)
![スクリーンショット 2021-11-22 11.48.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396218/1a0c376e-869f-aa8d-f353-443b91d73cf4.png)

***

上記の図のように設定ができたら「作成」します。
そのほかにも設定項目はありますが、今回は最小限の設定で構築します。
構築が完了すると、VMインスタンスに先ほど構築したサーバが表示されます。

***
![スクリーンショット 2021-11-22 11.54.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396218/f30fdd95-cbf4-a756-76c6-c10b5a3f5d8c.png)

Linuxサーバになるので接続方法はSSHとなります。「接続」の「SSH」をクリックすることでサーバにアクセスすることが可能です。現在はインターネット上から接続できませんが、特定の会社やインターネットからのみSSHにてアクセスさせることが理想のため、また次回に。
設計書の作成・管理ツールを比べてみた(Gitbook, Growi, Confluence)

#目的#
個人開発のアプリの設計書を作成・管理するツールを比較し、よさそうなものを選ぶ。
また、下記の点について留意する。
　・Excelなどのソフトウェアへの依存度が高いものではなく、マークダウンで記述できるもの
　・使用・導入のコストが低そうなもの（実際に支払うお金や参考になる情報があるかなど）

#比較したもの#
調べたところ、下記の3つが検討対象になりました。
 1. GitBook
 2. Growi
 3. Confluence

#結論#
個人開発だったらGitbookかGrowiのどちらかで十分だと思う。

出来ることはどちらもほぼ同じだおもうので、
あとは画像貼り付けが楽とかの使用感とか、
環境(nodejsだけかnodejs+mongodbか）などでどちらを使うが決まりそう。

Confluenceはもっと大人数のチーム向けの管理ツールのように思われた。

いかに調べた限りの長所・短所(Pros, Cons)[メリット・デメリット]を書いていきます。

#Gitbook#
https://www.gitbook.com/

Gitで管理ができるBookみたいな意味のアプリ名だと思います。（開発元的な意味合いではGithubは関係ないようです。)

よさそうな点
　・無料
　・マークダウンで記述ができる
　・目次がつけられる（階層化が簡単そう）
　・.md->.htmlへ変換をするので、それをGithubのリポジトリへあげてGithub Pagesで公開ができる
　・UML、チャートなどの記述がプラグインによってできる。
　・デフォルトで記事の全文検索ができる。
　
微妙そうな点
　・pdfの出力ができない
　・CLIがあるけど、メンテが止まってる（らしい）

動作環境に必要なもの
　・nodejs

以下の記事を参考にしています。

https://akerun.hateblo.jp/entry/2017/12/26/110102

https://gomachan46.gitbooks.io/how-to-use-gitbook/content/index.html

https://zenn.dev/mebiusbox/articles/703e934c78fa20

https://r-ngtm.hatenablog.com/entry/2020/06/18/193235#GitBook%E3%81%A7Web%E3%82%B5%E3%82%A4%E3%83%88%E3%82%92%E4%BD%9C%E3%82%8B%E3%81%BE%E3%81%A7

https://qiita.com/mamohacy/items/98c0d790074c9bdfef1a

https://re-engines.com/2018/09/06/markdown%E3%81%A7%E6%9B%B8%E3%81%91%E3%82%8B%E3%83%89%E3%82%AD%E3%83%A5%E3%83%A1%E3%83%B3%E3%83%88%E3%83%84%E3%83%BC%E3%83%AB%E3%81%AEgitbook%E3%82%92%E8%A9%A6%E3%81%99/

#Growi#
よさそうな点
　・無料
　・マークダウンで記述ができる
　・目次がつけられる（階層化が簡単そう）
　・差分がとれる
　・動作が早い（らしい）
　・UMLの記述がプラグインによってできる。
　・デフォルトで記事の全文検索ができる。
　・表が書きやすい
　・画像がはりやすい
　・環境構築が簡単
　
微妙そうな点
　・印刷がむずかしい
　・CLIがあるけど、メンテが止まってる（らしい）

動作環境に必要なもの
　・nodejs
　・mongodb

https://qiita.com/gakuri/items/93b06fb47eb538d2e447

#Confluence#
よさそうな点
　・無料（10ユーザーまで）
　・テンプレートが多そう

微妙そうな点
　・情報がすくない。

https://www.slideshare.net/ChizuruSugimoto/confluence-173333413

https://www.ricksoft.jp/qa/questions/23364125/confluence%E3%81%A7%E4%BB%95%E6%A7%98%E6%9B%B8%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6

https://www.atlassian.com/ja/software/confluence/pricing

#おわりに#
結論に書いた通り、GitbookかGrowiを使ってみます。
どちらも導入がかなり簡単だと思うので、いくらかつかってみて決めようかな。

下記記事をみると、その後のメンテで自分以外の人を使う必要が出てきたときとかにGitbookのほうがよいのかな？と思うけど、
Markdownで記述してあるからGrowiを使ってもきっとなんとかなるのかなと思ってみたり。
https://qiita.com/KeitaMoromizato/items/04ac6058010248b3ce82
3ヶ月間のチーム開発で学んだこと

## はじめに

大学3年生2名でチーム開発を約3ヶ月して感じたことや学んだことをまとめようと思います。（2名なのでチーム開発かどうかは怪しいところです…）
ちなみに、価値観や方向性の違いからチームは解散しました。

## 作ったもの
### 概要

MokuMokuというみんなで勉強することを目的とした勉強アプリです。C_2102の竹二世というチームでJPHACKS2021のファイナリストまで行きました。
[JPHACKS 2021 Award Day」進出チーム 16組を発表](https://jphacks.com/information/award-finalists2021/)

### 使用技術

- Flutter
- Firebase

### 開発期間

2021年8月10日～2021年11月20日

## チーム開発して良かったこと
### アイデアや発想が広がる

自分には無かったアイデアや発想が得られたり、議論することで新しいアイデアが生まれたりします。考え方の幅が広がるので、チーム開発の1番の良いところだと個人的には思います。

### 開発スピードが上がる

当たり前のことですが、チームで手分けして開発を進められるので1人でやるよりもスピードが格段に速くなります。

## チーム開発をする上で気を付けるべきポイント
### 目的を一致させる

**アプリのゴールはどこなのか。誰に何を届けたいのか。**
を必ずチームで決めておきましょう。チームで違う方向を向いているとどこかで痛い目見ると思います。最初に決めておくのがベストです。

### 決定権を最初にハッキリさせておく

**決定権は誰にあるのか。**を最初に決めておきましょう。
一例として以下の通りです。

- チーム全員で決める
    - 皆が納得しない限りやらない
- チームの過半数の賛成で決める
- リーダー個人で決める
    - 他のメンバーが何と言おうとリーダーがGo出せばやる

途中で自分に決定権が無いと分かるのはかなり辛いです…。

### 否定だけしない（否定するときは具体例を添える）

ダメ出しするときは具体的な案を出すようにしましょう。どんなに仲が良くても、どんなに一緒にいる期間が長くても相手へのリスペクトの気持ちを忘れないようにしたいですね。

### 報告はこまめする

チーム内の認識が異なっている可能性があります。困ったらすぐに聞く、ある程度作ったらこれで正しいのか確認する、など少しでも迷ったら確認を取ることをおすすめします。

## おわりに

最後まで読んでいただきありがとうございました。

感想としては、最初の段階で色々決めておくべきだったと感じました。今回はお互いの認識違いから起きたことなので、あらかじめ決めておけばこの様な状況にはならなかったと思います。色々思うことはありますが、結果としてとても良い経験が出来ました。この経験を今後に活かすとともに、今度は3名以上のチーム開発に挑戦していきたいです。
freeRADIUSのAccountingログについてのあれこれ

#前置き
初投稿です、宜しくお願いします。
freeRADIUSのAccountingに関して、
あまり日本語の説明記事がなく調べるのに苦労したため備忘録がてらまとめました。

Accountingの概要やログメッセージの例については以下のサイトが大変参考になりました。
[FreeRADIUSとdaloRADIUSのアカウンティング - デージーネット](https://www.designet.co.jp/ossinfo/radius/accounting/)

#内容
以下について記載します。
使用機器はLinuxのCentOS7の想定です。
1. Accountingログの場所
2. Accountingログのファイル名、ディレクトリ名の設定
3. logrotateの設定

#Accountingログの場所
デフォルトでは**/var/log/radius/radacct**配下に各NASのIPアドレスごとにディレクトリが生成され、
その中にそれぞれ溜まっていきます。(radacctはradius-accountingの略だと思われる)
ファイル名は**details-YYYYMMDD**という形で日ごとに別ファイルになっています。

```
# cd /var/log/radius/radacct
# ls -l
合計 10
drwx----- 2 radiusd radiusd 4096 11月 10 08:52 192.168.0.1 
drwx----- 2 radiusd radiusd 4096 11月 10 08:20 192.168.10.99 
drwx----- 2 radiusd radiusd 4096 11月 10 08:01 192.168.99.33

# cd 192.168.0.1
# ls -l
-rw------ 1 radiusd radiusd 12542 11月 1 23:03 details-20211101 
-rw------ 1 radiusd radiusd 13675 11月 2 23:12 details-20211102 
-rw------ 1 radiusd radiusd 19847 11月 3 23:54 details-20211103 
-rw------ 1 radiusd radiusd 22456 11月 4 23:57 details-20211104 
-rw------ 1 radiusd radiusd 12980 11月 5 23:59 details-20211105
（省略）
```

#Accountingログのファイル名、ディレクトリ名の設定
続いてこのログファイルのファイル名や格納場所を変える場合の設定です。
freeRADIUSは設定ファイルがたくさんあって分かりにくいです、、
今回変更が必要なファイルは以下です。
　-**/etc/raddb/mods-enabled/detail** 
　　(/etc/raddb/mods-available/detailのシンボリックリンクなのでそちらでも可)

33行目あたりに以下の記載があります。

```conf:/etc/raddb/mods-enabled/detail
filename = ${radacctdir}/%{%{Packet-Src-IP-Address}:-%{Packet-Src-IPv6-Address}}/detail-%Y%m%d
```
ここを変更することでファイル名や保存するディレクトリを変更できます。
**変更後プロセスの再起動を実施すれば反映されます。**


ちなみに**radacctdir**という変数は**radiusd.conf**で定義されています。

```conf:/etc/raddb/radiusd.conf
localstatedir = /var
logdir = ${localstatedir}/log/radius
radacctdir = ${logdir}/radacct
```
そのため、ログが/var/log/radius/radacct配下に各NASのIPごとにディレクトリ分けされ、
日ごとにファイル分けされて溜められています。

#logrotateの設定
デフォルトではfreeRADIUS自体で簡易的に日ごとにAccountingログファイルを生成していました。
ただ、10世代だけ残しておきたい、月ごとにローテーションしたい、●時×分にローテーションしたい...
などの小回りは効きません。
細かくローテーションの設定をしたい場合は、logrotateを利用すると良いです。
freeRADIUSはインストールすると
**/etc/logrotate.d/radiusd**というlogrotate用の設定ファイルを生成してくれているので、
そちらを編集するのがおすすめです。

デフォルトでは以下のように対象ファイルを**/var/log/radius/radacct/*/detail**と記述しているため、
detail-YYYYMMDDとして生成されるAccountingログファイルは対象外となっており、
logrotateではローテーションされていません。

```conf:/etc/logrotate.d/radiusd
/var/log/radius/radacct/*/detail{
    monthly
    rotate 4
    nocreate
    missingok
    compress
    su radiusd radiusd
}
```

ローテーションの設定がしやすいように、
まずは**/etc/raddb/mods-enabled/detail**を編集してファイル名が動的に変化しないものにしたうえで、
組み立てていくと良いと思います。

# 参考サイト
https://networkradius.com/doc/3.0.10/index.html
UnityEditor上でGameObjectをUpdateさせる方法

# はじめに
クラスにExecuteAlways属性をつければUpdateが呼ばれるだろうと思いましたが呼ばれなく、詰まったのでUpdateを呼ばれる方法を備忘録として残したいと思います。

# テンプレートコード

```csharp
using UnityEngine;

#if UNITY_EDITOR
using UnityEditor;
#endif

[ExecuteAlways]
public class CustomInspectorTemplate : MonoBehaviour {
    void Update() {
#if UNITY_EDITOR
        if (!Application.isPlaying) {
            Debug.Log("EditModeUpdate");
        }
#endif
    }

    void OnRenderObject() {
#if UNITY_EDITOR
        if (!Application.isPlaying) {
            EditorApplication.QueuePlayerLoopUpdate();
            SceneView.RepaintAll();
        }
#endif
    }
    

#if UNITY_EDITOR
    
    [CustomEditor(typeof(CustomInspectorTemplate))]
    public class CustomInspector : Editor {
        public override void OnInspectorGUI() {
            base.OnInspectorGUI();
        }
    }
#endif
}
```

# 解説
## ExecuteAlways
Editor上でもAwake,Start,Updateなどを呼ぶようにするための属性です。
以前はExecuteInEditModeが使われていたらしいのですが、PrefabModeの対応などから現在ではExecuteAlwaysが推奨されているようです。

## OnRenderObject
EditorModeではUpdateは毎フレーム呼ばれないので、代わりに描画ごとに呼ばれる関数を使用して、

```csharp
EditorApplication.QueuePlayerLoopUpdate();
```

を呼び出すことでUpdateを呼ばれるようにして、

```csharp
SceneView.RepaintAll();
```

でシーンを再描画するようにします。

OnRenderObject以外にも、OnDrawGizmosを使用することでも実現できました。
(SceneViewのGizmosがOnになっていないとUpdateされませんが)

## CustomInspector.OnInspectorGUI
UpdateをEditorModeで呼び出したい時には、インスペクターの拡張も考えられるので、
テンプレートに入れています。
WAS設計その3 JMSのバインディング接続とクライアント接続

備忘のような勉強メモのような

自分の理解
WebSphereのJMSの機能を使用した際の話。

バインディング接続　相手のキューマネージャーに接続する


クライアント接続　　WAS自身がMQクライアントとして動作して、接続を行う。
相手のIPアドレス、ポート番号等を指定して接続する。

両方存在する理由
MQ側がMQクラスタを構成している場合、クライアント接続しか許可されない。
※バインディング接続は使えない。
※詳細は不明だけど、MQクラスタってキューマネージャーのグループに参加するようなイメージだから
WAS側からは参加できないような気がしますね。

キュー接続プール数が重要！！　デフォルトの最大１０では足りないこともある。
セッション数でなくて