OmniAICreator/Qiita-1.07M huggingface dataset:
Nagios使ってみた

# Nagios環境構築
ネットワーク機器やサーバのモニタリングツールであるNagiosの環境構築手順です。
頼りになる日本語の解説サイトがあったのですが、私の場合途中からそれがうまく機能しなかったのでその対処法を主に記します。
それに加えてVPN環境において、Nagiosそのもののに由来する原因ではありませんでしたが権限エラーが出てどのネット上の情報も当てはまらず困ったので、そのことも書き留めます。
### 環境
CentOS7
Nagios 4.4.6
## 手順
- [Apache httpd インストール](https://www.server-world.info/query?os=CentOS_7&p=httpd&f=1)
- [PHPインストール](https://www.server-world.info/query?os=CentOS_7&p=httpd&f=3)
- [Nagiosインストール](https://www.server-world.info/query?os=CentOS_7&p=nagios)

## 詰まった点1(監視対象機器の追加設定)
今回は、サーバとスイッチを監視対象として設定した。
これまで参考にしていた[このページ](https://www.server-world.info/query?os=CentOS_7&p=nagios&f=5)で設定を進めようとしたところ、上手く行かなかった。


[公式ドキュメント](https://nagios.fm4dd.com/docs/jp/monitoring-routers.shtm)に沿って設定をするとできた。
ドキュメント大事。

例えばスイッチの設定であれば、まずは```vi /usr/local/nagios/etc/nagios.cfg```の中に記述してある
```#cfg_file=/usr/local/nagios/etc/objects/switch.cfg```
という設定ファイルの定義のコメントアウトの"#"を削除する。

そして、```vi /usr/local/nagios/etc/objects/switch.cfg```の中で

```
define host{
    use          generic-switch         ; Inherit default values from a template
    host_name    linksys-srw224p        ; 自分でつけて良い名前。The name we're giving to this switch
    alias        Linksys SRW224P Switch ; A longer name associated with the switch
    address      192.168.1.253          ; IP address of the switch
    hostgroups   allhosts,switches      ; Host groups this switch is associated with
}
```
として定義して以下のserviceの設定時に、そのhost_nameを書き連ねれば複数のスイッチにどんどん適用していける。
hostで監視対象機器の設定、serviceで監視内容の設定が行える。

```
define service{
    use                    generic-service                ; Inherit values from a template
    host_name              linksys-srw224p                ; 自分でつけて良い名前。The name of the host the service is associated with
    service_description    PING                           ; The service description
    check_command          check_ping!200.0,20%!600.0,60% ; The command used to monitor the service
    normal_check_interval  5                              ; Check the service every 5 minutes under normal conditions
    retry_check_interval   1                              ; Re-check every minute until final/hard state is determined
}
```

## 詰まった点2(VPN環境における話)

```/var/www/html``` の下の他のhtmlファイルは表示されるのに、Nagiosの画面のみ403権限エラーが出る、ということがあった。

```
You don't have permission to access /nagios/
```
これは、Nagiosのアクセス元IPをプライベートIPに制限設定していたことに由来する。
Nagiosサーバと同じネットワークに居たのだが、VPN環境に繋いでおらず、プライベートIPがNagios許容範囲になかった。
Reactでお絵かき掲示板（の表示部分）を作る話

## この文章は、決意表明をすることにより、自分を追い詰めるものである。あと、zennに書いたもののコピーである。

https://zenn.dev/sakots/articles/c9765457ff90ce

---

実は昔こんなの書いてるんですよ。

https://zenn.dev/sakots/articles/fb6529ee401fd3

## なぜReactにしたのか

### Vue VS React

じつはどっちでやるか決めるのにかなりの時間がかかりました。VueもさわったしReactもさわったし、なんとなくそれなりに触りだけ弄ったりしました。結果、Reactで行こうと決めました。以下理由。

### Vueは世界上に2と3の記事が混在していて結構煩雑

あっこれ2の記事だ、ってなったりする。だいぶ書き方違うのでなんで動かないのか調べたら文法だったり、Amazonで本買ったらVue2の本だったり（悔しい）

### Vueはすぐそれっぽいものができる故に、逆に理解しにくい

とりあえず形ができるので構造を深く考えるまでに至らない。Reactは公式も言ってる通り、見た目難しい。見た目難しいということは、調べればわかるよ、と公式が言っているということである。

### Reactのほうが食えそう

知り合いにVueで食ってる人は見たことないけどReactで食ってる人は何人かいたため。

## ビジョン

現状の俺作お絵かき掲示板 [ROIS](https://github.com/sakots/ROIS) をベースにしようと思うので、こうなる。

- レンタルサーバーに設置できるようにしたいので、通信まわりはPHP
  - なかなかサーバーサイドでnode.jsが走ってるレンタルサーバーはなかったのだ。「ロリポップが対応してるよ！」って記事が出てきてビビったことがあるけどよく読んだらマネージドクラウドでした。
- データベースはSQLite
  - これも手軽にレンタルサーバーに設置するため。テキストのログより検索性が高いし、ローカルのXAMPPで動いてるのをそのままFTPでアップロードしてオッケーな軽い感じなのが良い。SQLiteの情報を調べているとPHPのバージョンが4時代のものだったりするのが非常に難点。いまPHPはバージョン8、なんと倍ですよ！
- Reactを使うのはスレッド表示や検索表示のみ
  - 「仮想DOMが他のDOMと排他的」って感じだから。要するにお絵描きのhtml5+javascriptに干渉しないようにするため。絵がバグる原因がReactとかイヤでしょ。
- サーバーのPHPはjsonを返す
  - 妥当。

## Reactでやる意味あるの？

うん、たぶん実装めんどくさいしPHPで直接書くほうが現段階では色んな意味で速い。プロジェクトの規模としてもそんなにメリットはないと思うけど、俺の学習でやるわけなので、生暖かく見守りながらアドバイスください。
Syslog-ng3.33 conf on RHEL7

前回インストールは済みましたが
今度はconfで引っ掛かりました

ようやくたどり着いた公式参照

https://www.syslog-ng.com/technical-documents/doc/syslog-ng-open-source-edition/3.33/administration-guide/27#TOPIC-1663256

RHEL7では自動でsystemd-journal()が使われるように書かれているが
インストールがコケているのかエラーしか吐かなかった

I got stack again.
This time was conf.
I couldn't see dhcp demon log on syslog.

I was using this conf on Centos5 and syslog-ng2.
CentOS5とsyslog-ng2では以下のconfで動いていた

```sh
source s_sys {
        file ("/proc/kmsg" log_prefix("kernel: "));
        unix-stream ("/dev/log");
        internal();
        udp(ip(0.0.0.0) port(514));
        tcp(ip(0.0.0.0) port(514));
};

filter f_local1 { facility(local1); };
log { source(s_sys); filter(f_local1); destination(d_dhcp_log); };
destination d_dhcp_log { file("/var/log/$YEAR$MONTH$DAY.dhcp.log"); };
```

but I got error below on source section.
confチェックをするとエラー

```sh
$ syslog-ng -s -f /etc/syslog-ng/syslog-ng.conf

Using /dev/log Unix socket with systemd is not possible.
Changing to systemd-syslog source, witch supports socket activation.;
```

So I searched a lot and found out that cannot use
/dev/log on syslog-ng 3.33.
systemd-journal();を使えばdhcpのlogを吐きました

a correct source setting is bellow.

```sh
source s_sys {
        file ("/proc/kmsg" log_prefix("kernel: "));
        #unix-stream ("/dev/log");
        systemd-journal(); # <- this is correct
        internal();
        udp(ip(0.0.0.0) port(514));
        tcp(ip(0.0.0.0) port(514));
};
```

どなたかの一助になれば
I hope this can help someone. :)
Arrays.toString()メソッドでハマった話

# はじめに
皆さん、[Arrays.toString()](https://docs.oracle.com/javase/jp/8/docs/api/java/util/Arrays.html#toString-boolean:A-)メソッドご存知ですか？
今回このメソッドを使用しようとして1時間くらいハマってしまったので、記事にします。
※Arrays.toString()メソッドを使うべきでないところで使ってしまった話です

# 今回の経緯

以下のようなListからどうにかして `s1,s2,s3,s4,s5`という文字列を生成したくなりました。

```test.java
List<String> temp = new ArrayList<String>();
temp.add("s1");
temp.add("s2");
temp.add("s3");
temp.add("s4");
temp.add("s5");
```

絶対便利なメソッドあるよな～と思って見つけたのがArrays.toString()メソッド！
試しに出力してみます。

```test.java
List<String> temp = new ArrayList<String>();
temp.add("s1");
temp.add("s2");
temp.add("s3");
temp.add("s4");
temp.add("s5");

System.out.println(Arrays.toString(temp.toArray()));
```

```console:出力結果
[s1, s2, s3, s4, s5]
```

いい感じじゃないですか。これでいける！となりました。

# ミスったこと
これ、最初と最後に鍵括弧がついた文字列である、ということに気付いておらず、処理がうまくすすまない…なぜ…？と1時間くらい格闘していました。
<b>[</b>s1, s2, s3, s4, s5<b>]</b>

# 結局どうしたの？
StringBufferに地道に「,」をappendして文字列を作りました。
単純な話ですが、同じ過ちにハマる人もいるかもしれないので、記しておきます…

2021/10/26追記
コメントにいただいたコードが素晴らしいです。
VoIP試験環境用SIPサーバー(kamailio)構築について

# 1.概要
Kamailio(旧称ser/openser)は、GPLv2+ライセンスでリリースされたオープンソースのSIPサーバーです。
VoIPの試験環境や、通信環境を構築する時、良く使われたSIPサーバーです。
Kamailioを使って、他のオープンソースプラットフォーム（webRTCなど）と組み合わせてVoIPプラットフォームを構築できます。
(ちなみに、2021年はKamailioが初代（ser/openser）からの20年目になりました。)

最新版は2021年5月リリースした5.5.0版です。

Kamalioのネット上の位置は下図の中心にある六つのKの部分です。
![Kamalioのネット上の位置](https://www.kamailio.org/wp-images/kamailio-sip-ucp.png)

# 2.Kamailioインストール
CentOS7環境で、yumによりkamailioをインストールできます。

下記のように、

```shell
yum -y install yum-utils
yum-config-manager --add-repo https://rpm.kamailio.org/centos/kamailio.repo
yum install kamailio
```

他のOSでのインストール手順は下記にご参照できます:
https://www.kamailio.org/wiki/start#installation

kamailioをインストールする前に、MySQLあるいはMariaDBをインストールする必要があります。

# 3.Kamailioの使用方法
## 3.1.起動/停止

下記のようにkamailioを起動/停止する：

```shell
kamailio start/ kamailio stop
systemctl start kamailio/ systemctl stop kamailio
```

## 3.2.SIPアカウント追加

```shell
kamctl add username password
```

その後、データベースのパスワードが入力必要となり、パスワードのデフォルト値はkamaiorwです。

## 3.3.コンフィグファイル

デフォルトコンフィグファイル/usr/local/etc/kamailio/kamailio.cfg
コンフィグファイルによりSIP Serverの動作を制御できます。例えば、認証必要か(401/407)等など。


# 4.その他
下記のHPを参考できます：

kamailioの公式サイト: https://www.kamailio.org/    

kamailioのwiki: https://www.kamailio.org/wiki/start
lightningでのリストメールで添付ファイルが開けない(iphoneの問題か？)



+ [lightningでのリストメールで添付ファイルが開けない](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000Bt1NwSAJ)
+ [Recipients of list emails with attachment link can't open the html-attachment on Iphone / Ipad](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000A8UpbSAF)

回避策？
As a workaround,  on iOS (iPhone) I long pressed on the HTML link in the email and selected COPY and then opened the Notes app, and long pressed in Notes and selected Paste – and it pasted the link. I tapped the link in Notes and it opened the page with the preview and download link, I tapped the download link and it downloaded and the attachment opened. 


+ [Top element of the email not showing on iOS devices]()
【メモ】バッチファイルの日本語の文字化け解消

#状況
バッチファイル内にechoではきだした日本語の文字列をテキストファイルとして保存する命令を書いた。出力されたファイルを確認すると、日本語の箇所だけ文字化けしていた。

##原因を探る
文字化けについては間違いなく保存ファイル形式が原因と踏んでいたので、出力されたファイルの形式をS-JISにしたりUTF-8にしたが文字化けは治らず、バッチファイル内に「chcp」で宣言を加えたがダメだった。

#結局
バッチファイルの内容に日本語の文字列が存在するバッチファイルを保存するときANSI（S-JIS）を指定して保存するが正解だった。以前のメモ帳の保存形式はANSIにだったらしい。現在（2021-10-25時点）のWindows10でのメモ帳のデフォルトの保存形式「UTF-8」なので、バッチファイル保存時に「ANSI」に変更して保存する必要がある。

参考：**「バッチファイル実行時にエラーが発生する場合や文字化け発生時は文字エンコードを見直そう」**
https://pkunallnet.com/pcinfo/windows/winencode/#st-toc-h-1
AWSアカウントの削除を自動化したい

# はじめに
AWS Organizations (組織) の登場で、AWSアカウントの作成はコマンド一発で自動化出来るようになり、それを書いたブログ等は山ほどあります。
しかし、AWSアカウントの「削除」を自動化する記事が全く有りません。
AWS CLIの説明書を読んでも作成する `create-account` は有りますが削除するコマンドは無し。
むしろやりたいのはこっちなのに。。

# 経緯
勉強会やハンズオンで一時的に使用するAWSアカウントを量産します。
これはAWS CLIでも

```
aws organizations create-account --email foo@bar.net --account-name hoge
```

とコマンド一発で完了します。

問題はここからで、勉強会終了後に量産したAWSアカウントを全て削除したい。
これはリソースの削除は手間がかかるからです。サービスコントロールポリシーで作成可能なリソースを制限していたとしてもそもそも面倒です。
AWSアカウントを削除すれば全てのリソースが一括削除されますから、これがスマートですよね。
（厳密には課金が停止するだけで、後はAWSが任意のタイミングでリソースを削除するのですが課金が停止されればこちらとしてはそれで良い）
ちなみにIAMユーザを使わないのは、同一AWSアカウントを複数人で共有するとリソースが競合が発生するからです。

# 結論
できない

# 何故できないのか
AWS OrganizationsにはAWSアカウントを削除するコマンドは無く、組織からAWSアカウントを排除する `remove-account-from-organization` しか有りません。
これは単独AWSアカウントになる事を意味しますが、AWS Organizationsで作成したAWSアカウントにはクレジットカード情報等の情報がAWSアカウント作成を実行したマスターアカウントから引き継がれていない為そのままでは組織から排除出来ず、これらを手動で登録する必要があります。
これが原因です。

# どうしてこうなった
単独AWSアカウントにすると決済情報が等が必要なのはそうですが、マスターアカウントからそれらを引き継いだAWSアカウントを作成するようにすれば済む話です。
百歩譲って、組織に所属した状態のままAWSアカウントを削除できれば組織に所属している間はマスターアカウントが支払うのですから問題無いはずです。
どうしてこうなった。。


# まとめ
AWSアカウントの削除は自動化できない。
【SwiftUI】おしゃれを導入！デザイン系ライブラリ


#はじめに
SwiftUIはAppleの標準アプリのような画面が実装できるので、デザインに関しては素人でも大失敗はしないという安心感があります。ただちょっと一工夫するのが意外と苦労したりします。今回はSwiftUIにおいて使えるデザイン系ライブラリのライブラリを紹介したいと思います。

:::note 
紹介するライブラリは全てSwift Package Managerによる導入が可能です。
:::

#[Liquid](https://github.com/maustinstar/liquid)


![スクリーンショット 2021-10-25 12.12.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/713689/bec2f5da-ed7c-d785-543b-28a5d1f6c247.png)



泡のような図形を表示できるライブラリです。アニメーションが含まれているので、ゆっくり動くのが特徴です。色をつけて背景にすることもできますし、写真のフレームのような使い方もできます。

画像はライブラリの用意したView、`Liquid`を3つ重ねて作っていますが、泡のような感じを出すために重ねて使うことが多いかと思います。ひとつひとつ設定を変えることもできるので、一番手前だけ色を変えるなど細かい調節が可能です。

#[Colorful](https://github.com/Co2333/Colorful)

![スクリーンショット 2021-10-25 11.36.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/713689/7b356244-bc0e-1b51-636c-4e0d277f5142.png)

画像のようなカラフルなViewを作成することができます。色やアニメーションの可否なども設定できます。色は複数指定できますし、逆に単色にして霧のような表現をすることも可能です。

基本的には背景として使うことになりそうですが、[以前紹介したグラスモーフィズム](https://qiita.com/KokumaruGarasu/items/681477515251c5d9d34f)とも相性がよいかもしれません。



#[StatefulTabView](https://github.com/NicholasBellucci/StatefulTabView)

![スクリーンショット 2021-10-25 12.23.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/713689/faf6c84b-e43e-db36-5948-7b1e380a5940.png)

Statefulの名前の通り、状態によってTabの表示を変更できるようにすることが主な使い方です。例えば、アイコンに数字や文字を表示して通知などを知らせることができます。

これだけでも便利なのですが、実はこのライブラリを使うとTab部分の色を細かく変更することができます。

#[SwiftClockUI](https://github.com/renaudjenny/SwiftClockUI)

![ClockViewClassic.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/713689/4094a80c-716d-8116-586a-932c7d1d47fe.png)

アナログ時計を表示するもので、文字盤は４種類用意されています。時計の色ももちろん変えられますし、アニメーションもなめらかです。

もともと画面に時間表示のあるiOSだとあまり出番がありませんが、MacOSのアプリだと活用の場面は増えてきます。例えば、ToDoアプリなどではアナログ表示で時間が見られると便利かもしれません。



#[MarkDownUI](https://github.com/gonzalezreal/MarkdownUI)

![スクリーンショット 2021-10-25 11.18.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/713689/e9239370-9c45-d4da-2c7d-4b5ab65f1483.png)


その名の通りマークダウンで文章を扱えるようになります。長文でもオフラインで表示したい規約や使い方などはこれを使うのがいいかもしれません。URL部分の色の変更など、細かい調整も可能です。

`Text`そのままよりもバランスが取りやすくなるのは非常に便利だと思います。マークダウン記法は広く普及しているので、サイトや文書を構成の参考にできるのが大きなメリットではないでしょうか。

記法としては[CommonMark Spec](https://spec.commonmark.org/0.30/)に完全に準拠しているそうです。



:::note warn
一行目に日本語のみを見出し表示すると文字の上半分が途切れてしまうことがあります。対策としては以下のように空のHeaderを挿入してください。
:::

>
 #
 #
 # 見出し１
 本文

#[DynamicColor](https://github.com/yannickl/DynamicColor)
`UIColor`と`Color`に便利な機能を追加できるものです。まず`UIColor`には色の調整を自動で行ってくれる機能が追加されます。下の画像のように基本の色に対して濃淡を変えたり、対抗色を生成したりすることが可能です。

![スクリーンショット 2021-10-25 11.33.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/713689/137183c5-ec6b-a283-83a3-38ca40cf6593.png)


SwiftUIの`Color`でもhex指定で色を決定できるようになるので、ちょっとした色の微調整も簡単になります。



#さいごに
SwiftUIに対応したライブラリもかなり増えてきたので今回はデザイン系に絞って紹介してきました。全てSwift Package Managerで簡単に管理できるのでとりあえず試してみるのも良いかと思います。ぜひ開発に役立ててください！



---

よかったらこちらもよろしくお願いします☺️

各種お知らせ：[Twitter](https://twitter.com/tokiwa16448392)

作成途中のアプリについて：[note](https://note.com/izumo092)
Xcode13で作成したプロジェクトにInfo.plistがないor あるが中の項目がほとんどない

Xcode13で作成したStoryboardプロジェクトはInfo.plistにほぼ項目がなく(SceneDelegate関連の１項目のみ)、SwiftUIアプリに至っては初期状態ではInfo.plistがありません。

代わりにTarget > Infoや、Target > build settingsから、過去にはInfo.plistで設定していた項目も変更できるようです。


https://developer.apple.com/documentation/xcode-release-notes/xcode-13-release-notes


> Resolved Issues
Projects created from several templates no longer require configuration files such as entitlements and Info.plist files. Configure common fields in the target’s Info tab, and build settings in the project editor. These files are added to the project when additional fields are used. (68254857)

参考 https://useyourloaf.com/blog/xcode-13-missing-info.plist/
webpack.config.js側で`--mode`の値によって処理を分岐する

よくあるパターン

```json:package.json
"scripts": {
  "build": "NODE_ENV=production webpack --mode production", //← NODE_ENVという環境変数を作ってる
  "dev": "webpack --mode development",
  ...
}
```

なんだか冗長に感じませんか？
正直、開発までのレベルだとそんなに困ることはないかと思いますが、それでも依存するファイルやコマンドは分散したくないです。

なので、こんな感じのシンプルなままキープしたい。

```json:package.json
"scripts": {
  "build": "webpack --mode production",
  "dev": "webpack --mode development",
  ...
}
```

公式にありました。

> If you want to change the behavior according to the mode variable inside the webpack.config.js, you have to export a function instead of an object:
[Mode | webpack](https://webpack.js.org/configuration/mode/#mode-none)

上記ページの公式的な手法としてはこの様になっています。

```javascript:webpack.config.js
var config = {
  entry: './app.js',
  //...
};
module.exports = (env, argv) => {
  if (argv.mode === 'development') {
    config.devtool = 'source-map';
  }

  if (argv.mode === 'production') {
    //...
  }

  return config;
};

```

予め設定用のオブジェクトを定義しておき、`--mode`の内容（など）を受け取れる関数の形にして、その値からオブジェクトに追加・変更したものをreturnすることで、処理を分岐できるようです。
しかしこの書き方だと、値を更新するのが困難な場合がありますし、個人的にもう少し直感的に読みやすい方がが好きなので下記のようにしてみました。

```javascript:webpack.config.js
//modeを利用する部分のみ抜粋
module.exports = (env, options) => {
  isCssSourceMapEnabled = options.mode !== 'production' ? true : false
  return {
  　　//...
  　　sourceMap: isCssSourceMapEnabled,
　　}
}
```

これは`--mode`が`production`以外の場合のみ`sourceMap`を`true`にする例です。開発中はSCSSのソースマップを出力してほしいけど、本番環境にはソースマップは不要というよくあるお悩みです。
（以前は第一引数からmodeを参照できたようですが、仕様が変更された模様）
もう少し略さず書くとこの様になり、公式の書き方だと少し困難であることがおわかりになると思います。

```javascript:webpack.config.js
module.exports = (env, options) => {
  isCssSourceMapEnabled = options.mode !== 'production' ? true : false
  return {
    module: {
      rules: [
        {
          test: /\.scss$/,
          use: [
            ...
            {
              loader: "sass-loader",
              options: {
                ...
                sourceMap: isCssSourceMapEnabled,
```

こちらも万能ではなく、変更する部分ごとに変数を定義することになり、変更箇所が多い場合など、向いていない場合もあるかと思います。また予め別のファイルなどで環境変数を定義している場合もあると思います。
少し特殊なWebpack.configの書き方の例として、こんなのもあるということを覚えておくと役立つことがあるかもしれません。
PHPMDの既存ルールセットのうち特定ルールだけ変更

# priorityを変更する

例えば、`rulesets/codesize.xml`のルールを読み込みつつ、特定のルールだけ変更したい。

1. `rulesets/codesize.xml`を読み込み、変更したいルールを除外する
1. 改めて`rulesets/codesize.xml/xxxx`で個別にルールを読み込み、設定を変更する

```xml:phpmd.xml
<?xml version="1.0"?>
<ruleset name="change priority"
         xmlns="http://pmd.sf.net/ruleset/1.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0
                     http://pmd.sf.net/ruleset_xml_schema.xsd"
         xsi:noNamespaceSchemaLocation="
                     http://pmd.sf.net/ruleset_xml_schema.xsd">
    <description>
        change prioriy
    </description>

    <!-- ルールセットを読み込む -->
    <rule ref="rulesets/codesize.xml">
        <!-- プライオリティを変更したいルールを除外 -->
        <exclude name="ExcessivePublicCount"/>
    </rule>
    <!-- 改めてルールを読み込んでプライオリティを変更 -->
    <rule ref="rulesets/codesize.xml/ExcessivePublicCount">
        <priority>5</priority>
    </rule>
</ruleset>
```
Firebase Authのカスタムクレームをターミナルから簡易に設定する

サービスの管理者でも、全権限がある人や、アルバイトで一時的に入った人など、細かく権限を設定したいものです。
Firebase Authのカスタムクレームという機能を使えば、細かい権限設定が行えます。

https://firebase.google.cn/docs/auth/admin/custom-claims?hl=ja

しかし、その登録はAdmin SDKを介するので、**NodeのRepl環境で行うのは、認証情報の初期化がややこしい**です。

個人的にかなりつまづいたので、共有させていただきます。

# localのfunctionsディレクトリでNodeを起動

まず、ターミナルで`functions/`のディレクトリに移動してNode Replを起動します。

```bash
cd XXX/functions/
node
```
# サービスアカウントの秘密鍵を作成

1. Firebase Consoleのプロジェクトの設定に移動する

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614389/25365623-77ac-5552-6d4a-ec5fda3ab1d7.png" width="300px">

2. サービスアカウント　のタブを開く

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614389/52e2149b-a5c0-b5b2-f232-23cbc1be20dc.png" width="300px">

3. 秘密鍵を生成してダウンロードして、保存したパスをコピーしておく

![スクリーンショット 2021-10-25 12.35.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614389/244b6183-e40d-9ade-f491-0706131a02dd.png)




# サービスアカウントの秘密鍵のパスを環境変数に設定


```
export GOOGLE_APPLICATION_CREDENTIALS='PRIVATE_KEY_PASS'
```

これにて、自動でAdmin SDKが認証情報を取り扱ってくれます。
公式ドキュメントによると、これ以外の方法である*認証情報をハードコードする*ことは推奨されていません。

# Admin SDKが正しく初期化できることを確認する

```js:NodeのReplへの入力
const admin = require('firebase-admin');
admin.initializeApp();
```

# カスタムクレームが既に存在するか確認

該当ユーザにカスタムクレームが既に追加されているか確認しましょう。
これは、**Admin SDKから行えるカスタムクレームへの操作が、既存のカスタムクレームに対する上書き操作**であるからです。

```js:NodeのReplへの入力
const uid = 'XXXXXXXX';
auth.getUser(uid).then((res,rej)=>{console.log(res.customClaims)});
```

このconsole出力が`undefined`なら、該当ユーザに対するカスタムクレームは追加されていないことを示します。

一方で、以下のようなオブジェクトが出力される場合は、カスタムクレームが既に存在するので、値を追加する場合は、既にある存在を保持しつつ値を使いするように注意する必要があります。

```:console出力
{ role: { tempStaff: true } }
```

ですので、これらの既にあるkey,valueのペアを保存し統合された値を上書きするということをお勧めします。

```js:疑似コード
let savedCustomClaimObject = { role: { tempStaff: true } };
savedCustomClaimObject.newKey = newValue;
admin.auth().setCustomUserClaims(uid, savedCustomClaimObject)
```

# トラブルシューティング based on my failures

## Error: Cannot find module 'firebase-admin'

```

Error: Cannot find module 'firebase-admin'
Require stack:
- <repl>
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:794:15)
    at Function.Module._load (internal/modules/cjs/loader.js:687:27)
    at Module.require (internal/modules/cjs/loader.js:849:19)
    at require (internal/modules/cjs/helpers.js:74:18) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [ '<repl>' ]
```

## 解決策: ディレクトリを確認

ローカルのfunctionsのディレクトリに移動してることを確認しましょう。このディレクトリで`node`起動する必要があります。

## Error: Failed to determine project ID

```

> (node:6503) UnhandledPromiseRejectionWarning:
Error: Failed to determine project ID: 
Error while making request: getaddrinfo ENOTFOUND metadata.google.internal.
Error code: ENOTFOUND
    at FirebaseAppError.FirebaseError [as constructor] 
...
```

## 解決策:秘密鍵の環境変数を再確認しよう

これが全てとは限りませんが、再度`export GOOGLE_APPLICATION_CREDENTIALS ...` の操作を実行しましょう。環境変数は現在のシェルのセッションのみで有効なので、違うターミナルウィンドウ開いた時は、再度環境変数を入れる必要があるので要注意です。


# References

公式ドキュメントしか勝たん

https://firebase.google.cn/docs/admin/setup?hl=ja#initialize-sdk
E:The repository 'http://security.debian.org./debian-security bullseye/updates Release' does not have a Release file.対処

```
# 1./etc/apt/sources.list編集
# 2.http://security.ubuntu.com/ubuntu/　→　http://deb.debian.org/debian-security/に変更
# 3.docker-compose build xxx エラー箇所を指定してbuild実行
#deb http://security.ubuntu.com/ubuntu/ bullseye-security main
#deb-src http://security.ubuntu.com/ubuntu/ bullseye-security main
deb http://deb.debian.org/debian-security/ bullseye-security main
deb-src http://deb.debian.org/debian-security/ bullseye-security main
```
S3 + CloudFront の環境下で、JavaScriptファイルが読み込まれない時の解決方法

## どんな時に読み込まれないのか

Chromeの開発者ツール(F12)でページを見たときに、
下記のエラーメッセージが出ていれば、後述する対処法に従うことで解決する可能性が高いです。

```
Refused to execute script from '<スクリプトのURL>'
because its MIME type ('binary/octet-stream') is not executable,
and strict MIME type checking is enabled.
```

## 原因

* 読み込もうとしたファイルのMIMEタイプが実行不可能なタイプ( `binary/octet-stream` )であるため
* 現在閲覧中のWEBサーバーで厳格なMIMEタイプ判別を行っているため

エラー説明文のままですが…

## 説明

`binary/octet-stream` は、正体不明のバイナリーファイルに用いられます。
厳格なMIME判別を行うWEBサーバーにおいて、このタイプはダウンロードされるのみで、
ブラウザ上で実行されないために、当該のJavaScriptファイルは読み込まれません。

S3アップロード時(PUT)のContent-Typeの既定値が `binary/octet-stream` らしく、
一部のファイルはこれが原因で表示されないみたいです。

何がトリガーで `binary/octet-stream` が設定されるのかはよくわかってません。すいません

## 解決方法

### Step1. S3でファイルのContent-Typeを `application/x-javascript` に変更する

※HTMLファイル上の記述に以下のように `type="text/javascript"`を追加しても意味はないです。S3でメタデータを編集する必要があります

```
<script src="common/js/common.js"></script>
↓
<script type="text/javascript" charset="utf-8" src="common/js/common.js"></script>
```

S3コンソールで以下の操作をします

![2021-10-25_122811.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130352/cceaca3f-dd42-48a7-2a05-f511744d7df9.png)

`Amazon S3 > {S3バケット名} > common > js` を開く

`common.js` にチェックを入れて、 `アクション > メタデータの編集` をクリック

※バケット名やディレクトリ名は皆さまのお使いの環境で読み替えてください

![2021-10-25_122845.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130352/66af8fdd-faf3-00ae-c0ac-2e7334134762.png)
メタデータ

タイプ: システム定義
キー: `Content-Type`
値: `binary/octet-stream` -> `application/x-javascript` に変更

メタデータの編集ボタンを押す

※ディレクトリ内のファイルを一括で変更するには以下のようにします

`Amazon S3 > {S3バケット名} > common > js` を開く

ディレクトリ左上にあるチェックボックスをクリックして一括チェック後、 `アクション > メタデータの編集` をクリック

※バケット名やディレクトリ名は皆さまのお使いの環境で読み替えてください

メタデータの追加

タイプ: システム定義
キー: `Content-Type`
値: `application/x-javascript`

メタデータの編集ボタンを押す

これにより、もともと定義されていた `Content-Type` の値が上記で設定した値に上書きされます。

### Step2. CloudFrontのキャッシュを削除する

メタデータを編集しても、キャッシュが削除されなければ反映されません。
ブラウザのキャッシュを削除しても、CDNサーバー上にキャッシュが残っているので無意味です。
CDNサーバー上のキャッシュを削除する必要があります。

以下の操作でCDNサーバー上のキャッシュを削除します。

`CloudFront > ディストリビューション > {ディストリビューションID}`

`キャッシュ削除 > キャッシュ削除を作成` をクリック

オブジェクトパスを追加

```
/common/js/common.js
```

※ディレクトリ名やファイル名はお使いの環境で読み替えてください

`キャッシュ削除を作成` をクリック

`ステータス: 進行中` が `完了済み` になるまで待ちます

※一括でキャッシュ削除するなら以下のようにします

オブジェクトパスを追加

```
/common/js/*
```

`キャッシュ削除を作成` をクリック

`ステータス: 進行中` が `完了済み` になるまで待ちます

### Step3. 動作確認

ステータスが完了になった後、改めてChromeで当該ページを開くと、
ちゃんと読み込まれるようになると思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130352/89ca95b1-12bf-6797-b90b-23a4f0675565.png)
開発者ツール(F12)を開いた状態でページをリロードした後、
開発者ツールの `ネットワーク` タブを開き、ちゃんと読み込まれていなかったJavaScriptファイルをクリック、
`ヘッダー > レスポンスヘッダー > content-type` の値が `application/x-javascript` に変わっていればOKです。

## 参考URL

* https://qiita.com/hihats/items/33872f88cf21b5aca952
* https://kenjiszk.hatenablog.com/entry/2014/05/08/090733
* http://norm-nois.com/blog/archives/2968
* https://qiita.com/baby-0105/items/0356b0af4ab4585d86c4
複数のモジュールをfor文によって一括で動的にimportする(JavaScript)



``` script.js
const moduleNames = ['module1', 'module2', 'module3'];
const modules = {};

for(let i=0;i<moduleNames.length;i++){
  import('./modules/' + moduleNames[i] + '.js')
    .then((module)=>{
      modules[moduleNames[i]] = module.default;
    });
}

```

ただしフォルダ構成が次のようになっているとする。
module1.js, module2.js, module3.jsたちはexport defaultしている。

``` 
root/
  ┣ script.js
  ┗ modules/
      ┠ module1.js
      ┠ module2.js
      ┗ module3.js
```

動的インポートと呼ばれるものを使う。
静的インポートとの違いは、Promiseで返って来るところ。

静的インポートはトップレベルのスコープでしか使えない。
for文の中で静的インポートをしようとすると`Uncaught SyntaxError: Unexpected identifier`のエラーが出る。
なんとかforで回せないかとこねくり回したらできた。


ただし参考ページ import - JavaScript - MDN Web Docs
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/import
には、

>動的インポートは必要な場合にのみ使用してください。

とある。こういう使い方は非推奨なのかな。
Linux 特定の文字列を含むファイルを検索する コマンド (find,xargs)

findとxargsコマンドを使用して、特定の文字列を含むファイルを検索する。
結果はファイル名とその中の検索文字ERRORを含む行が行番号付きで表示される。

###**■検索されるファイル**

$ cat test.log

```
 ERROR   2021年 10月 25日 月曜日 03:11:15 UTC
 NOMAL   2021年 10月 25日 月曜日 03:11:15 UTC
 ERROR   2021年 10月 25日 月曜日 03:11:15 UTC
 ERROR   2021年 10月 25日 月曜日 03:11:15 UTC
 NOMAL   2021年 10月 25日 月曜日 03:11:15 UTC
```

###**■特定の文字列(検索対象)**###

ERROR

###**■検索実行**###

$ find . -name "test.log" -print |xargs  grep -n "ERROR" /dev/null

```
./test.log:1:ERROR   2021年 10月 25日 月曜日 03:11:15 UTC
./test.log:3:ERROR   2021年 10月 25日 月曜日 03:11:15 UTC
./test.log:4:ERROR   2021年 10月 25日 月曜日 03:11:15 UTC
```

ファイル名とその中の検索文字ERRORを含む行が行番号付きで表示された。

***
for ループの大域脱出法

# for ループの大域脱出法

多重 for ループの最も内側から一挙に最も外側の for ループのさらに外へ脱出する方法を何通りか記述する。

## 状況を表す変数を使う方法

1. 一番外側の for ループに入る前に success = false としておく。<br>
2. もっとも内側の for ループから脱出するときに，success = true として break で脱出する。<br>
3. 脱出した for ループで success の値をチェックし true ならばさらに break する。<br>

これを繰り返して，一番外側の for ループも脱出する。<br>
脱出開始時と脱出完了時の変数の値をみれば，確かに大域脱出していることが確認できる。<br>
なお，`success && break` は<br>

```Julia
　if success<br>
　　　break<br>
　end<br>
```
と同じである。


```julia
success = false
count = 0
for i1 in 1:10
    for i2 in 1:10
        for i3 in 1:10
            for i4 in 1:10
                count += 1
                if i1 == 2 && i2 == 3 && i3 == 4 && i4 == 5
                    success = true
                    println("最も内側から break するときの状態　success = $success, count = $count")
                    break
                end
                success && break
            end
            success && break
        end
        success && break
    end
    success && break
end
println("脱出後の状態　success = $success, count = $count")
```

    最も内側から break するときの状態　success = true, count = 1235
    脱出後の状態　success = true, count = 1235


## 関数化する方法

当該処理を関数化しておけば，最も内側の for ループで return を使えば，大域脱出することになる。<br>
最も内側の for ループ中に確実に return するならば，最も外側の for ループの外に何があっても実行されない。


```julia
function f()
    count = 0
    for i1 in 1:10
        for i2 in 1:10
            for i3 in 1:10
                for i4 in 1:10
                    count += 1
                    if i1 == 2 && i2 == 3 && i3 == 4 && i4 == 5
                        println("最も内側から return するときの状態　count = $count")
                        return
                    end
                end
            end
        end
    end
    println("この println() は実行されない")
end
f()
```

    最も内側から return するときの状態　count = 1235


## Julia 独自の for ループ記法を使う方法

Julia では，多重 for ループを一行（for 文 1 個）で書く便法がある。これを使えば，見かけは一重の for ループのようであり，その中で break  すれば，最も外側の for ループの外まで一挙に脱出することになる。


```julia
count = 0
for i1 in 1:10, i2 in 1:10, i3 in 1:10, i4 in 1:10
    count += 1
    if i1 == 2 && i2 == 3 && i3 == 4 && i4 == 5
        println("最も内側から return するときの状態　count = $count")
        break
    end
end
println("脱出後の状態　count = $count")
```

    最も内側から return するときの状態　count = 1235
    脱出後の状態　count = 1235
【Swift】Firebaseでパスワード再設定メールを送信

Swiftを用いたiOS開発でFirebaseでパスワード再設定メールを送信するコード。

```swift
import Firebase

Auth.auth().sendPasswordReset(withEmail: "example@example.com") { error in
    if error != nil {
        print("error")
    }
    else{
        print("success")
    }
}
```

`sendPasswordResetWithEmail:completion: `メソッドを使用して、ユーザーにパスワードの再設定メールを送信している。

`import Firebase`を忘れずに。

## 参考

https://firebase.google.com/docs/auth/ios/manage-users?hl=ja

## Swiftのお役立ち情報

https://wagtechblog.com/programing/swift-iphone-application-school

https://wagtechblog.com/programing/swift-textbook.html
DBユーザーのパスワードに@があって怒られた

# 事象の説明
sqlalchemy を使って DB に接続する際に次のような方法で engine を生成します。

```python
username = 'pyuser'
password = 'Pyp@ssw0rd'
host = 'localhost'
port = 3306
database = 'pytest'
charset_type = 'utf8'

connection_url=f"mysql://{username}:{password}@{host}:{port}/{database}?charset={charset_type}"
engine = create_engine(connection_url)
```

ここではデータベースとして MySQL を使っています。この engine を用いて DB に接続してクエリを実行すると以下のように怒られます。

```python
session = sessionmaker(bind=engine)()
session.execute("SELECT 1;")
```
```
sqlalchemy.exc.OperationalError: (MySQLdb._exceptions.OperationalError) (2005, "Unknown MySQL server host 'ssw0rd@localhost' (11)")
```

DBに接続するためのURLをよく見ると、パスワードとホスト名の区切り文字が `@` となっています。上の例ではパスワードに `@` が含まれており、最初に現れたパスワード内の @ が区切り文字と判断されてしまったことがエラーの原因でした。

# 対応方法
sqlalchemy には [URL class](https://docs.sqlalchemy.org/en/14/core/engines.html#sqlalchemy.engine.URL) が用意されているので、こちらを使うとよいです。

```python
from sqlalchemy.engine.url import URL

connection_url = URL.create(
    drivername="mysql",
    username=username,
    password=password,
    host=host,
    port=port,
    database=database,
    query = {"charset": charset_type},
)
print(connection_url)
```

```:結果
mysql://pyuser:Pyp%40ssw0rd@localhost:3306/pytest?charset=utf8
```

上記結果からもわかるように、パスワードに含まれている `@` が単に URL encode されているだけですね。
Railsで関連モデルのレコード数を使って検索を行いたい時のメモ

# TL;DR

```ruby
# 基本スタイル
User.joins(:orders).group('users.id').having('COUNT(orders.id) > ?', 2)
=> User Load (0.9ms)  SELECT "users".* FROM "users" GROUP BY users.id HAVING (COUNT(orders.id) > 2)

# COUNT DISTINCT(いらないかも...)
User.joins(:orders).group('users.id').having('COUNT(DISTINCT orders.id) > ?', 2)
=> User Load (1.8ms)  SELECT "users".* FROM "users" INNER JOIN "orders" ON "orders"."user_id" = "users"."id" GROUP BY users.id HAVING (COUNT(DISTINCT orders.id) > 2)
```

```ruby
# 数値カラムと比較(購入数と年齢を比較する謎仕様(笑))
User.joins(:orders).group('users.id').having('COUNT(orders.id) > users.age')
=> User Load (3.9ms)  SELECT "users".* FROM "users" INNER JOIN "orders" ON "orders"."user_id" = "users"."id" GROUP BY users.id HAVING (COUNT(orders.id) > users.age)

# 別の関連モデルのレコード数と比較(購入数とレビュー数を比較)
User.joins(:orders, :reviews).group('users.id').having('COUNT(orders.id) > COUNT(reviews.id)')
=> User Load (13.5ms)  SELECT "users".* FROM "users" INNER JOIN "orders" ON "orders"."user_id" = "users"."id" INNER JOIN "reviews" ON "reviews"."user_id" = "users"."id" GROUP BY users.id HAVING (COUNT(orders.id) > COUNT(reviews.id))
```

# 注意
`GROUP BY ... HAVING ...` の構文は `or` 系の構文とたまに干渉し、エラーが生じるので、Ransackなどで複雑な条件で検索したい時は要注意です。


# 余談
上記構文は自動的に関連レコードのないものを検索対象外にしたが、***関連レコードがない***ことを検索したい場合は下記の構文でできます。

```ruby
# おすすめ
User.left_outer_joins(:orders).where(orders: {id: nil})
=> User Load (1.1ms)  SELECT "users".* FROM "users" LEFT OUTER JOIN "orders" ON "orders"."user_id" = "users"."id" WHERE "orders"."id" IS NULL

# 一応こちらもできるが、無駄なSQLが発行される
User.includes(:orders).where(orders: {id: nil})
=> SQL (1.3ms)  SELECT "users"."id" AS t0_r0, "users"."created_at" AS t0_r1, "users"."updated_at" AS t0_r2 ... 
```

# 参考
- [Rails GroupでまとめてCountした結果をHavingを使って絞り込む](https://akinov.hatenablog.com/entry/2017/05/13/163911)
- [Want to find records with no associated records in Rails](https://stackoverflow.com/questions/5319400/want-to-find-records-with-no-associated-records-in-rails)
2つのPyTorchモデルの重みの平均を計算する

# はじめに
PyTorchの2つの機械学習モデルの重みを平均してみました。

モデルの`state_dict`を取得することで、パラメータに直接計算を加えることができます。

# 環境
* Python 3.9.5
* torch 1.9.0+cu111
* torchvision 0.10.0+cu111

# 準備
モデル同士の足し算と、モデルの定数倍を行う関数を定義。
  
### モデル同士の足し算
```Python:sum_model.py
def sum_model_params(modelA, modelB):
    """ modelA + modelB """
    sdA = modelA.state_dict()
    sdB = modelB.state_dict()
    for key in sdA:
        sdB[key] = (sdB[key] + sdA[key])
    modelB.load_state_dict(sdB)
    return modelB
```

### モデルの定数倍
```Python:milti_model.py
def multi_model_params(model, a):
    """ a * model """
    sd = model.state_dict()
    for key in sd:
        sd[key] = sd[key] * a
    model.load_state_dict(sd)
    return model
```

# 2つのモデルの平均
```Python:average_model.py
# C = AとBの平均
C = multi_model_params(sum_model_params(A, B), 1/2)
```

足し算と定数倍で、平均以外にもある程度の計算が可能になると思います。

# 参考
[Average each weight of two models](https://discuss.pytorch.org/t/average-each-weight-of-two-models/77008)
Watson StudioのJupyter notebookからSQL Queryへのクエリー実行

以下の記事でWatson StudioでSQL Queryで登録した表にアクセスしました。

Watson StudioからSQLQueryへのアクセス - Qiita 

https://qiita.com/kawada2017/items/4a03974a49c67ee6e887

この記事ではさらにJupyter notebookのPyhonからSQL Queryでクエリー実行を行います。
まずSQLQueryのライブラリーを導入します。

```python
!pip install --upgrade ibmcloudsql
```

次にデータアクセスのメニューを開き、接続のタブを開きます。そして、前の記事で作成した接続オブジェクトを選択し、「コードに挿入」を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/be8035e3-9a0b-dd34-e466-dd67d55c82d3.png)

すると以下のようなコードが自動生成されます。

```python
# @hidden_cell
# The following code contains the credentials for a connection in your Project.
# You might want to remove those credentials before you share your notebook.

from ibm_watson_studio_lib import access_project_or_space
wslib = access_project_or_space()
sqlquerya4_credentials = wslib.get_connection("sqlquerya4")
```
取得されたオブジェクトsqlquerya4_credentials には以下のような資格情報が入っています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/2eaa4972-0e48-f229-eb43-92f5d2eec35f.png)

次にSQL Queryへの接続を行います。接続にはAPIキー、CRN、SQL Queryの出力先のICOSバケットの指定が必要ですが、これらは先ほど自動生成されたsqlquerya4_credentialsから取得できます。

```python
import ibmcloudsql
sqlClient = ibmcloudsql.SQLQuery(sqlquerya4_credentials['password'],
                                 sqlquerya4_credentials['crn'],
                                 sqlquerya4_credentials['target_cos_url'])
```

後は、SQLを書いてクエリーを実行するとpandasのdataframeに結果が返ります。

```python
query = """
select*
from COND4N_E104
"""

queryres = sqlClient.run_sql(query)
queryres.head()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/baa292be-8c26-47f4-69f7-3664fb5f15f6.png)

#サンプルコード

https://github.com/hkwd/211025watsonstudiosqlquery/blob/master/sqtest.ipynb

#参考
ICOS上のファイルをSQLでアクセスできるSQL Queryを利用する

https://qiita.com/tetsuya1969/items/b9381e0d8866769bcf38
Dr.Sum Data Funnel HTTP Agentでデータを投入してみた

#1. はじめに

Dr.Sum Data Funnelは「データ収集」する場合、以下の３つの方法（プロトコル）に対応しています。
　・MQTT
　・HTTP
　・OPC UA

また、クライアントからコマンドを実行することで、定期的に生成されるデータファイル（CSVファイルまたはJSONファイル）を入力データとすることもできます。

今回の記事ではHTTPプロトコルを利用するDr.Sum Data Funnel HTTP Agentを使用してデータ投入をしてみたいと思います。

Dr.Sum Data Funnelの概要、またはデータファイルでの連携については「[Dr.Sum Data FunnelでCSVファイルを連携してみた](https://qiita.com/LuiLui/items/ae0ce6b36a68ee134fed)」の記事を参考にして下さい。

#2. Dr.Sum Data Funnel HTTP Agentとは

Dr.Sum Data Funnel HTTP Agentは、HTTPで送信されたデータを受け取り、MQTTプロトコルでDr.Sum Data Funnel Message Brokerにパブリッシュします。

たとえば、MQTTトピック「http_topic」にパラメーターを付与して送信するときは、次のようにアクセス（指定）します。
####http\://<サーバー名またはIPアドレス>:6280/funnel/topics/http_topic?LIGHT=2.2&PRESSURE=985.22
この例では、
####{"LIGHT": "2.2","PRESSURE": "985.22"}
というJSONオブジェクトが組み立てられ、MQTTでDr.Sum Data Funnel Message Brokerにパブリッシュします。

※Dr.Sum Data Funnel HTTP Agentでのデータの投入についての詳細は以下のマニュアルを参照下さい。

https://cs.wingarc.com/manual/drsum/5.6/ja/UUID-1c19b66b-5572-9812-bb78-10c794724b61.html

#3. パイプライン定義の作成
任意の名前でパイプライン定義を作成し、以下を設定して「テーブル化の設定」をクリックします。
実行種別：ストリーム
データタイプ：JSON
MQTTトピック：http_topic
トリガー間隔：1秒
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1569715/b5db495c-0093-534b-1091-e7014b44f292.png)

「データを入力して推定」を選択して、赤枠部分に例で表示したJSON形式のテキスト
{"LIGHT": "2.2","PRESSURE": "985.22"}
を張り付けて「推定」ボタンを押すとテーブル化されますので、そのまま「ＯＫ」ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1569715/c6979de5-f0a3-adeb-6273-8192ba441b8c.png)

「時刻関連項目設定」画面で分析用日時項目を「ARRIVEDTIME」に指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1569715/1cc74954-06af-a23f-8053-90eef589491d.png)

「Dr.Sumに出力」画面で出力先を設定してパイプライン定義を保存します。
※「テーブルの作成SQLをクリップボードにコピー」ボタンを押すとCREATE文がコピーされるので、必要に応じてDr.Sum 側にテーブルを作成してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1569715/fedb4d6f-6798-2de1-7de2-62acfb5c2f4d.png)

作成したパイプライン定義を起動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1569715/4aa1146c-9252-a4a0-8ff5-e7c564eddd7a.png)

#4. Dr.Sum Data Funnel HTTP Agent経由でデータを投入してみる
以下のURLをブラウザから実行します。

####http\://<サーバー名またはIPアドレス>:6280/funnel/topics/http_topic?LIGHT=2.2&PRESSURE=985.22

※以下の例ではlocalhost宛にデータを送信しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1569715/447282ff-097d-8272-1324-60c0ea3c8aa9.png)

Dr.Sum Data Funnel HTTP Agent経由でDr.Sumにデータが格納されたことを確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1569715/ff01913c-9e51-d809-877c-0502e62eadf4.png)



#まとめ
Dr.Sum Data Funnel HTTP Agentを利用してHTTPで送信されたデータをJSON形式に変換してMQTTでDr.Sum Data Funnel Message Brokerにパブリッシュします。Dr.Sum Data Funnel ServerでJSON形式のデータをテーブル化してDr.Sumにデータ投入する一連の流れをご理解いただけたと思います。

ウイングアーク1st社のホームページからDr.Sum Data Funnelハンズオンの申込ができるようです。興味がある方はぜひ申込してみてください！
[Javascript] 一次元配列の要素をｎ個ずつに分割した新しい二次元配列を返す

## はじめに
ある案件の処理上、一次元配列を指定の要素数ごとに分割し、二次元配列にする必要があったため、そのロジックに関する小ネタです。即時関数、アロー関数式、通常関数（関数宣言）の３タイプのご紹介です。（備忘録扱いです）

### 補足
本記事執筆当初は**Array.reduce**を用いたロジックを紹介していましたが、コメントでご指摘いただいた内容より、**Array.flatMap**を用いた内容に修正いたしました。これに伴いタイトルも一部修正いたしました。

## ロジック

```Javascript:flatMap.js
const originalArr = [1,2,3,4,5,6,7,8,9,10,11,12,13];
const num         = 3; // 分割単位

// 即時関数
const chunkedArr = ((arr, size) => arr.flatMap((_, i, a) => i % size ? [] : [a.slice(i, i + size)]))(originalArr, num);
// console.log(chunkedArr); -> [[1,2,3],[4,5,6],[7,8,9],[10,11,12],[13]]

// アロー関数式
const hoge = (arr, size) => arr.flatMap((_, i, a) => i % size ? [] : [a.slice(i, i + size)]);
// console.log(hoge(originalArr, num)); -> [[1,2,3],[4,5,6],[7,8,9],[10,11,12],[13]]

// 通常関数（関数宣言）
function fuga(arr, size){
  return arr.flatMap((_, i, a) => i % size ? [] : [arr.slice(i, i + size)]);
}
// console.log(fuga(originalArr, num)); -> [[1,2,3],[4,5,6],[7,8,9],[10,11,12],[13]]
```

### Array.reduceを用いた方法
本記事自体備忘録扱いのため、執筆当時のオリジナルのロジックも残しておきます。以下を用いる場合、コメントでもご指摘いただいていますように初期配列の設定や作業用のコピーが発生するため、その分効率的とはいえません。`Array.reduce`を用いるならば、@tkturboさんのロジックを参考にしましょう。（丸投げ！）

```Javascript:reduce.js
// 即時関数
const chunkedArr = ((arr, size) => arr.reduce((previous, _, i) => i % size ? previous : [...previous, arr.slice(i, i + size)], []))(originalArr, num);
// console.log(chunkedArr); -> [[1,2,3],[4,5,6],[7,8,9],[10,11,12],[13]]

// アロー関数式
const hoge = (arr, size) => arr.reduce((previous, _, i) => i % size ? previous : [...previous, arr.slice(i, i + size)], []);
// console.log(hoge(originalArr, num)); -> [[1,2,3],[4,5,6],[7,8,9],[10,11,12],[13]]

// 通常関数（関数宣言）
function fuga(arr, size){
  return arr.reduce((previous, _, i) => i % size ? previous : [...previous, arr.slice(i, i + size)], []);
}
// console.log(fuga(originalArr, num)); -> [[1,2,3],[4,5,6],[7,8,9],[10,11,12],[13]]
```

コーディングスタイルは人それぞれですので、案件内容や前後の処理との関係など、必要な場面に応じて使い分ければいいと思います。

## 最後に
紹介したロジックが必ずしも最適解ということではございません。誰かの役に立てば幸いです。

@nagtkk様をはじめ、コメントいただいた皆様に感謝いたします。

### [参考]
+ [Array.prototype.flatMap() - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap)
+ [Array.prototype.reduce() - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce)
Xcode13になってXcodegenのインストールが失敗する Sources/Spectre/XCTest@4.swift': File not found.

最近XcodeGenのインストールが失敗するようになりました。mintを使ってXcodeGenをインストールしているんですが、 以下のようなエラーが出ました。

```
'Spectre' /private/var/folders/59/hx744wtd3h5d9nc5c17frm_m0000gp/T/mint/github.com_yonaskolb_XcodeGen/.build/checkouts/Spectre: warning: Invalid Exclude '/private/var/folders/59/hx744wtd3h5d9nc5c17frm_m0000gp/T/mint/github.com_yonaskolb_XcodeGen/.build/checkouts/Spectre/Sources/Spectre/XCTest@4.swift': File not found.
```

Swift コマンドラインインターフェース関係の問題だったようでXcodegen公式で対応されていました。

https://github.com/yonaskolb/XcodeGen/issues/1127

Xcodegenを2.25.0にすると解消されます。

```Mintfile
yonaskolb/XcodeGen@2.25.0
```
゛Cargo test テスト関数名゛は部分一致で対象関数全実行する

VSCode で `Run test` したときに、テストしたい関数以外の関数も実行されてしまってよくわからなかったので調べていたら `Cargo test` の仕様だったっぽいっていう話。


```rust
#[test]
Run test
fn test_aaa() {

}

#[test]
Run test
fn test_aaa_false_01() {

}

#[test]
Run test
fn test_aaa_false_02() {
}
```

こんな感じで作って行ってて、その都度都度単体テストしてたんだけど
改めて`test_aaa()` のテストをしようとして `Run test` 押したら
`test_aaa_false_01()` も `test_aaa_false_02()` も動いてしまって
よくわからなくなってしまいました。

まあ、テストしてくれるのは別に良いのだけど、意図していないテスト結果が出るのは邪魔なので・・・。

最初は、"Run test" 押した時に `VSCode` から `Cargo test` に渡されるパラメータがおかしいのかな？
って調べていたんだけど、 ターミナルから直接 `Cargo test test_aaa` って打ったら同じ結果だったので
`Cargo test` の仕様っぽいかなって結論しました。

ターミナルから操作する分には、関連テストが一括実行されて便利かなとも思うけど
VSCode で テスト関数のところの `Run test` 押すと別の関数も動いちゃうのは違和感あるかなぁ〜
Ubuntu で WebEX を使う

Ubuntu 21.10 で WebEX を使う方法です。

#起動直後の画面#
>![webex00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/60762e30-2584-fbf7-050c-c22e9e9be496.png)

#画面左の「ミーティング」をクリック#
>「ミーティング」という用語が複数の意味で使われているので、ちょっと操作が分かりにくいです。左の日にちが表示されている「ミーティング」をクリックして下さい。
![webex_aa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/f75f89d5-a5a1-625e-f8aa-ba99e0adbfb6.png)

#ミーティングに参加する時#
>「ミーティングに参加」をクリック
![webex_bb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/4d8e4c66-5a54-7201-9162-3d742846f537.png)

>ミーティング情報を入力します。（10桁の数字）
AWSのECインスタンスのSSHポートフォワーディングに対する振る舞いメモ

# AWS EC2にSSHでリモート/ローカルフォワーディングして気づいたこと
プライベートアドレスで立ち上げた`計算機1(Ubuntu)のHTTP(80)`を、SSH(22)だけ開いている`AWS EC2の8080ポート`へリモートフォワーディングして、そこへプライベートアドレスの`計算機2(Windows)の8080ポート`へローカルフォワーディングしようと考えた。

- 計算機1：Ubuntu ← private address(IP1)
- 計算機2：Windows ← private address(IP2)
- 計算機3：AWS EC2 ← グローバルIP(外向き：IP_AO)＋private IP(内向き：IP_AI)
    - EC2はUbuntuを採用、SSH(22)しかポートは開いてない
    - EC2のセキュリティポリシー(インバウンド) もSSH(22)しか開いてない


## 実験1

まずはリモートフォワーディング：

```shell_session:計算機1(Ubuntu)
$ ssh -R IP_AO:8080:localhost:80 username@IP_AO
```

続いてローカルフォワーディング

```shell_session:計算機2(Windows)
$ ssh -L 8080:IP_AO:8080 username@IP_AO
```

すると、リモートフォワーディングの方はできているが、ローカルフォワーディングの方で、Open channel的なエラーがでる。すなわち、計算機2（Windows）でブラウザからlocalhost:8080としても計算機1（Ubuntu）のWEBページは閲覧できない。


## 実験2

まずはリモートフォワーディング：

```shell_session:計算機1(Ubuntu)
$ ssh -R IP_AO:8080:localhost:80 username@IP_AO
```

続いてローカルフォワーディング

```shell_session:計算機2(Windows)
$ ssh -L 8080:IP_AI:8080 username@IP_AO
```

実験1との違いは`IP_AI`のところ。些細なことだけど気づきにくい。これで計算機2（Windows）でブラウザからlocalhost:8080として計算機1（Ubuntu）のWEBページが閲覧できた。
Django Rest Framework ListSerializerの書き方

フロントエンドの開発時に、より本格的なスタブを作るために、DRFをよく使っていました。
とても手軽に構築できて、いつも助かっています。
ただ、よりコアの使い方が必要なとき、PythonやDjangoに不慣れの人にはなかなか骨が折れます。

下記のような連想配列を一回のPOSTで複数のデータ更新と新規追加を同時に実現したいニーズがあって

![sample.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615519/0a18e20a-1a50-e76c-c0f3-755a83e1f865.jpeg)

公式サイトでは[このように](https://www.django-rest-framework.org/api-guide/serializers/#listserializer)解説されています。

つまり、「ListSerializer」を使えばよいとのことです。
公式サイトに紹介された構文でserializers.pyに書いてみると、それっぽい動きは確認できますが、
POST送信後、データの更新も確認できました。
しかし、正しいレスポンスが返ってこなく、さらに新規追加した分のIDがレスポンスの中に含まれず、判別できない残念な一面があります。
どうやら、views.pyもある程度カスタマイズする必要があるようです。

いろいろ調べているうちにようやく正しい挙動にたどり着きましたので、ご紹介いたします。
同じ使い方するときにお役に立てると幸いです。

## Serializers

```python:serializers.py
class TaskListSerializer(serializers.ListSerializer):
    def create(self, validated_data):
        new_tasks = [Task(**p) for p in validated_data if not p.get('id')]
        updating_data = {p.get('id'): p for p in validated_data if p.get('id')}
        # 既存データの定義
        old_tasks = Task.objects.filter(id__in=updating_data.keys())
        with transaction.atomic():
            # 新しいデータの処理
            all_tasks = Task.objects.bulk_create(new_tasks)
            # 既存データの更新
            for task in old_tasks:
                data = updating_data.get(task.id, {})
                # 一旦削除の実行
                data.pop('id')
                updated_task = Task(id=task.id, **data)
                updated_task.save()
                all_tasks.append(updated_task)
        return all_tasks

class TaskSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(required=False)
    class Meta:
        list_serializer_class = TaskListSerializer
        model = Task
        fields = '__all__'
```

## Views

```python:views.py
class TaskViewSet(viewsets.ModelViewSet):
    queryset = Task.objects.none()
    serializer_class = TaskSerializer

    def get_queryset(self):
         queryset = Task.objects.all()
         return queryset.filter(user=self.request.user.id)

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data, many=isinstance(request.data, list))
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        results = Task.objects.all()
        output_serializer = TaskSerializer(results, many=True)
        data = output_serializer.data[:]
        return Response(data)
```

## 一応 Models も

```python:models.py
class Task(models.Model):
    PERSON_NONE = "none"
    PERSON_DAD = "dad"
    PERSON_MOM = "mom"
    PERSON_SET = (
      (PERSON_NONE, "None"),
      (PERSON_DAD, "Dad"),
      (PERSON_MOM, "Mom"),
    )
    user = models.ForeignKey(get_user_model(), related_name='tasks', on_delete=models.CASCADE)
    master = models.ForeignKey(Master, related_name='tasks', on_delete=models.CASCADE)
    date = models.DateField()
    person = models.CharField(choices=PERSON_SET, default=PERSON_NONE, max_length=8)

    def __repr__(self):
          return "{}".format(self.pk)
    __str__ = __repr__
```
仮想マシンに入れた古いDebianとWindows10のファイル受け渡し

個人的備忘録として。

カーネルが古いためVIRTUALBOXの共有を実現できなかったのでゴリ押し。
Debian側にopenssh-serverをインストールする。
あとはWindows10側でよしなに。

```
apt-get install openssh-server
```

![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71585/b5a517f0-1ca9-d1d2-6d51-c7e5582a9878.png)

![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71585/aeaa9704-a0a8-9ee0-7288-794cf603a90d.png)

このように設定をして、WinSCPを設定する。

![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71585/ebf0c9ab-49b9-e600-be1e-94c8cd8f9b1a.png)
尺取り法の書き方

尺取り法について、こっちの記事のほうが良いと思います。

https://qiita.com/drken/items/ecd1a472d3a0e7db8dce


https://qiita.com/ngtkana/items/0b8f619a406d5f5b89de


この記事はしゃくとり法を理解してるが書き方を忘れる人向けです。
スタイリッシュでない地道な書き方のイメージとなります。

◇
方針
尺取りの範囲の左右をl,rで管理。
ただし、lを含み、rは含まない。半開区間[l,r)
①lはforで1づつ右に移動。
②その中でrを行けるところまで右に。
③rはそのままに①へもどる。

以下、プログラムのイメージ。 「 .. 」に必要な処理を入れる。

```
// 初期化
...
int val = 0; 
int r = 0; 

// lを一つずつ右に動かす。
for (int l = 0; l < n; l++)
{
  if (l > r)
  {
     // lを右に動かしたらrを追い越した時の処理
     r = l;
     ...
  }
  while(true) {
    if (r >= n) {
      // rが範囲の最後まで行ってる時の処理  
      ...
      break;
    }
    if (rの位置でも条件を満たすか) {
      // rが右にいけない時の処理
      ...
      break;   
    }
    // rを右に移動する処理
    r++;
    ...
  }
  // lを右に動かす前に値などを戻す処理
  ...
}
// 答えの表示など
...
```

◇
実例
https://atcoder.jp/contests/arc098/tasks/arc098_b

```c++
#include <iostream>
using namespace std;
using ll = long long;

int main()
{
    // 方針
    // 尺取りの右と左をl,rで管理。
    // l→rの範囲でlを含み、rは含まない。半開区間[l,r)
    // ①lはforで一個ずつ右に
    // ②その中でrを行けるところまで回す。
    // ③rはそのままに①へ。

    // 入力の受け取り
	int n;
	cin >> n;
	ll a[n];
	for(int i = 0; i < n; i++) {
		cin >> a[i];
	}

	// 初期化
	int val = 0; 
	int r = 0;   
	ll ans = 0;

	// lを一つずつ動かす。
	for (int l = 0; l < n; l++)
	{
        // lを右に動かしたらrを追い越した時の処理
        if (l > r)
        {
            r = l;
            val = 0;
        }

        while(true) {
			// rが範囲の最後まで行ってる時の処理
			if (r >= n) {
				ans += r - l;
				break;
			}
			// rの位置でも条件を満たすか
			int n_add = val + a[r];
			int n_xor = val ^ a[r];
			if (n_add != n_xor) {
				// rが右にいけないので終了する処理
				ans += r - l;
				break;
			}
			// rを右に移動する処理
			r++;
			val = n_xor;
		}
        
        // lを右に動かす前に値などを戻す処理
        val = val ^ a[l];
        
        
    }
	// 答えの表示
	cout << ans << endl;

	return 0;
}
```
【JavaScript】関数とオブジェクト⑩　prototype



#はじめに

Udemyの[【JS】ガチで学びたい人のためのJavaScriptメカニズム](https://www.udemy.com/course/javascript-essence/)の講座の振り返りです。

前回の記事

https://qiita.com/nao0725/items/1758ba807241ab4f4a43

#目的

* 関数とオブジェクトについての理解を深める

#本題
###1.プロトタイプとは

* コンストラクター関数と一緒に使用する
* オブジェクトに存在する特別なプロパティのこと
* インスタンス化した際にprototypeの参照が__proto__にコピーされる

####例1

`````javascript
function Person(name, age) {
    this.name = name;
    this.age = age;
}

// 以下にコンストラクター関数のメソッドを追加し無名関数を代入
Person.prototype.hello = function(){
    // Personのthis.nameを入れる
    console.log("Hello" + this.name);
}

const bob = new Person('Bob', 18);
const tom = new Person('Tom', 33);
const sun = new Person('Sun', 20);

// 実行するとHelloBobと出力
bob.hello();
``````

メソッドとして使いたいプロパティをプロトタイプに格納するとインスタンスごとに関数を実行できる
→　ないとエラーになった！

####例2

thisにhelloメソッドを登録した場合

````js
function Person(name, age) {
    this.name = name;
    this.age = age;
    this.hello = function(){
        console.log("Hello" + this.name);
    }
}

const bob = new Person('Bob', 18);
const tom = new Person('Tom', 33);
const sun = new Person('Sun', 20);

// 実行するとHelloBobと出力
bob.hello();
tom.hello();
sun.hello();
````

Prototypeを使わなくても実行できる
メモリの消費を抑えるためにprotoypeを使用する



今日はここまで！

#参考にさせて頂いた記事

* [【JS】ガチで学びたい人のためのJavaScriptメカニズム](https://www.udemy.com/course/javascript-essence/)