OmniAICreator/Qiita-1.07M huggingface dataset:
マウスカーソル位置を中心に画像を拡大・縮小する方法

地図アプリ操作のように、マウスカーソル位置を中心に画像を拡大・縮小したり、ドラッグでスクロールさせたりする方法
![ZoomableImage.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538053/58d02f48-13a1-d075-3e47-c8003a42b9c3.gif)
リポジトリ
https://github.com/yasuhto/ZoomableImage

# 拡大・縮小
マウスカーソル位置を中心に拡縮させるということは、カーソル位置の絵は動きません。つまり、拡縮サイズに応じて画像本体の中心位置（transform.position）を調整します。
ググったところ、mousepancyo さんがほぼ目的のコードを公開されていたので、[こちら](https://gist.github.com/mousepancyo/fe5daebc245e9f69670b6bb32ae39ab3)を参考にしました。

主な変更箇所は2か所です。
1. LocalScaleの更新タイミングをオフセット座標計算後に変更
1. 縮小時の画像がCanvas内に収まるよう調整

**LocalScaleの更新タイミングをオフセット座標計算後に変更**
参照元のコードを手元で動作確認したところ、拡縮時に拡縮したいポイントとマウスカーソル位置がズレる症状が確認できました。原因は、中心位置のオフセットを計算する際に使用した RectTransformUtility.ScreenPointToLocalPointInRectangle に渡す RectTransform が変更後のスケールになっていたためです。

LocalScaleの更新タイミングをオフセット座標計算後に変更します。
```c#:ZoomableImage.cs
// ズームするスケールを計算
var scale = this.transform.localScale * (1 + val * this.ZoomSpeed);

// カーソルを中心にズームするようにオフセット座標を計算
var offsetPos = new Vector3(this._CursorPotision().x * (scale.x - pastScale.x), this._CursorPotision().y * (scale.y - pastScale.y), 0f);
var pos = pastPos - offsetPos;

this.transform.localScale = scale;
this.transform.localPosition = pos;
```
```c#:ZoomableImage.cs
private Vector2 _CursorPotision()
{
    var canvas = this.GetComponentInParent<Canvas>();
    var imRect = this.GetComponent<RectTransform>();
    RectTransformUtility.ScreenPointToLocalPointInRectangle(imRect, Input.mousePosition, canvas.worldCamera, out var pos);

    return pos;
}
```
**縮小時の画像がCanvas内に収まるよう調整**
「ある点を中心に拡大 → 別の点を中心に拡大 → 縮小」して元のサイズに戻すと、初期の画像の中心座標に戻らず、Canvasから画像がはみ出してしまいます。

画像の中心座標を調整する際にCanvasサイズを超えないように調整します。
```c#:ZoomableImage.cs
public static Vector3 CalcAdjustedImageLocalPosition(Vector3 inPos, Vector3 scale, float width, float height)
{
    var posXMax = width * 0.5f * (scale.x - 1);
    var posYMax = height * 0.5f * (scale.y - 1);

    var outPos = Vector3.zero;
    outPos.x = inPos.x > 0 ? Mathf.Min(inPos.x, posXMax) : Mathf.Max(inPos.x, -1 * posXMax);
    outPos.y = inPos.y > 0 ? Mathf.Min(inPos.y, posYMax) : Mathf.Max(inPos.y, -1 * posYMax);

    return outPos;
}
```
# スクロール
マウスのドラッグ距離に応じて画像の中心座標を移動させることで、スクロールを実現しています。ここでも、拡縮時と同じように画像がCanvas内に収まるように調整します。
```c#:ZoomableImage.cs
var dragDelta = this.CalcMouseDragDelta();

var pos = this.transform.localPosition + dragDelta;
var scale = this.transform.localScale;

//  画像がCanvas内に収まるよう調整
var imRect = this.GetComponent<RectTransform>();
pos = CalcAdjustedImageLocalPosition(pos, scale, imRect.rect.width, imRect.rect.height);

this.transform.localPosition = pos;
```

# 参考資料
* https://gist.github.com/mousepancyo/fe5daebc245e9f69670b6bb32ae39ab3
nRF Connect SDK:C++使えるの？！(笑)

# 何気なくMatterのサンプルを開いてみたら…
あれ、このダブルコロンってもしかしてClassでは…とふとプロジェクトツリーを見てみるとファイル名が.cppと書いてあるじゃないですか！
なんと！NCS(VSCode?)はC++も使えるんですね。そんなこと全く気にかけていませんでしたがstringクラスとか使えるのであればメチャクチャ楽じゃないですか。stdクラスとか使えるんですかね？
あ、すみません。完全な雑談です、ええ(笑)。
今後はそこらへんも視野に入れてコーディングしていこうと思います。
kintone UI Component の歩き方(ほんの一歩目)

# はじめに
kintoneのjavascriptカスタマイズする際に、画面にボタンを追加したいときなどにチョー絶便利な **[kintone UI Component](https://kintone-ui-component.netlify.app/ja/)** を皆さんお使いでしょうか？？

弊社でも、UIの変更を伴うようなカスタマイズの依頼がたくさん来ますが、kintoneライクな各種パーツが用意されているので、色々な拡張をしていっても違和感なく実装することが出来るので、非常にありがたく使わせていただいています。

概要がdeveloper network に載っていますので、 **[こちら](https://cybozu.dev/ja/kintone/sdk/library/kintone-ui-component-v1/)** からご覧になってくださいませ！
何よりも、サイボウズ社が正式にサポートしてくれているので、安心して使えますね！

公式サイトには、サンプルコードなど丁寧に記載されているのですが、パッと見すると、英語サイトな感じになっていて、コーディング初級者にとっては、ちょっとハードルが高いかもなぁと思いましたので、公式サイトの見方などをご紹介できればと思います！

# まずはともかくググってみる
必要そうな情報がちゃんと上位に来ますので、必要な情報に合わせて適切にリンクを踏んでください。
他のページに飛んだとしても、飛び先の画面にもわかりやすくリンクが記載されているので、それほど迷わないと思います！

![2023-05-31_14h45_18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319512/5e437025-2e24-699a-09dd-dc596d08dd03.png)


# [トップページ](https://kintone-ui-component.netlify.app/ja/)についての注意事項
表示したときに文章が英語表記になっていたら、サイト上部から表示言語の設定を **『日本語』** に設定してください！
![2023-05-31_14h54_33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319512/0733c558-00be-68c3-603d-89418b946a04.png)



# [Quick Start](https://kintone-ui-component.netlify.app/docs/ja/getting-started/quick-start)について
![2023-05-31_15h12_54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319512/bf7f780b-214f-1fe6-9597-9d5107accbb5.png)


# kintone UI Component のjavascriptファイルの取得方法
**[Githubのサイト内](https://github.com/kintone-labs/kintone-ui-component/blob/master/README-JP.md)** に記載されているのですが、ファイルとして取得する方法がちょっと分かりにくいので手順を記載しておきます。

![2023-05-31_15h36_49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319512/1ffad92a-f938-f797-fc81-83c958d8b07b.png)

リリースページに遷移して、下部の方に記載してある **『Assets』** 内の **「kintone-ui-component-X.XX.X.tgz」** をダウンロードしてください。

拡張子 **「tgz」** はwindowsだと **[7zip](https://7-zip.opensource.jp/)** 等の解凍ソフトを使わないと解凍できませんので、必要に応じてパソコンにインストールして、適当な場所に解凍してください。(Macだと普通に解凍できるらしい…。)

何度か解凍することで、 **「package」** フォルダが生成されます。そのフォルダ内の **「umd」** 内に **「kuc.min.js」** があります。

ex) kintone-ui-component-1.11.0.tgz → kintone-ui-component-1.11.0.tar → package\umd\kuc.min.js

この **「kuc.min.js」** をkintoneにファイルアップロードすることで、カスタマイズ用のJavaScriptファイルにて **[kintone UI Component](https://kintone-ui-component.netlify.app/ja/)** を使えるようになります。

もちろん、お使いの環境に応じては、CDNやnpm使ってもらってももちろんOKです！


# 実装方法について
これについては、リファレンスページに丁寧に書いてあるので、そこを読むのがイチバンかなぁと思います！
例： **[ボタンの実装について](https://kintone-ui-component.netlify.app/docs/ja/components/desktop/button)** 

# Custom CSS について
コンポーネントのスタイルを変更することができます。詳しくは **[コチラ](https://kintone-ui-component.netlify.app/docs/ja/getting-started/custom-css)** をご確認ください。
例：ボタンの高さを低くするとか、幅を狭くするとかね。

カスタマイズ用のcssファイルに、カスタムプロパティを設定し、kintoneにアップロードすることで、様々なスタイルをセットすることが出来るようになりますので、ぜひ試してくださいね。

# まとめ
ほんの一歩目の紹介しかできていませんが、 **[kintone UI Component](https://kintone-ui-component.netlify.app/ja/)** を使うきっかけになっていただければと思います。

 **[kintone REST API Client](https://github.com/kintone/js-sdk/tree/master/packages/rest-api-client)** と一緒に使うことで、kintoneのUIに沿った検索窓(下記みたいなもの)の作成なども比較的容易にできるようになりますので、ぜひチャレンジしてみていただけると嬉しいです！
![2023-05-31_16h24_37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319512/48cfbe78-a1d3-501b-d26f-4f7860e63b4f.png)
わ

1. Wildfly のインストールディレクトリに移動して standalone.xml ファイルを編集します。

2. 以下の4つのサーバ設定を編集します。

・サーバの名前：サーバインスタンスに指定する名前を変更します。

・設定：ディプロイアプリケーションを指定します。

・バインディング：リモート機能を使用するために指定されているポート番号を変更します。

・インターフェイス：Wildflyで備えられたサービスの実行に使用されるインタフェースを指定します。

3. これらの設定を変更した後、standalone.xml ファイルを保存します。

4. Wildfly を再起動します。再起動で新しい変更を反映させることができます。

Wildfly26のstandalon.xmlのコードとその解説をしてください




<server name="default-server" xmlns="urn:jboss:domain:4.0">
    <!-- 指定した名前でサーバーが定義される -->
    <extensions>
        <extension module="org.jboss.as.clustering.infinispan"/>
        <!-- Infinispan を拡張機能として有効にする -->
        <extension module="org.jboss.as.connector"/>
        <!-- JDBC コネクタを拡張機能として有効にする -->
        <extension module="org.jboss.as.deployment-scanner"/>
        <!-- デプロイメントスキャナーを拡張機能として有効にする -->
        <extension module="org.jboss.as.ee"/>
        <!-- EE 拡張機能を有効にする -->
        <extension module="org.jboss.as.ejb3"/>
        <!-- EJB を拡張機能として有効にする -->
        <extension module="org.jboss.as.jacorb"/>
        <!-- JacORB を拡張機能として有効にする -->
        <extension module="org.jboss.as.jaxrs"/>
        <!-- JAX-RS を拡張機能として有効にする -->
        <extension module="org.jboss.as.jdr"/>
        <!-- JDR を拡張機能として有効にする -->
        <extension module="org.jboss.as.jmx"/>
        <!-- JMX 拡張機能を有効にする -->
        <extension module="org.jboss.as.jpa"/>
        <!-- JPA を拡張機能として有効にする -->
        <extension module="org.jboss.as.jsf"/>
        <!-- JSF 機能を拡張として有効にする -->
        <extension module="org.jboss.as.logging"/>
        <!-- ログ出力を拡張機能として有効にする -->
        <extension module="org.jboss.as.naming"/>
        <!-- JNDI 名前付け機能を拡張として有効にする -->
        <extension module="org.jboss.as.pojo"/>
        <!-- POJO の拡張機能を有効にする -->
        <extension module="org.jboss.as.remoting"/>
        <!-- プロキシとリモート機能を拡張として有効にする -->
        <extension module="org.jboss.as.sar"/>
        <!-- Service Archive の拡張を有効にする --> 
        <extension module="org.jboss.as.security"/>
        <!-- セキュリティ拡張機能を有効にする -->
        <extension module="org.jboss.as.threads"/>
        <!-- スレッド拡張機能を有効にする -->
        <extension module="org.jboss.as.transactions"/>
        <!-- トランザクション拡張機能を有効にする --> 
    </extensions> 
</server>

上記のコードがWildfly26のstandalon.xmlのコードです。このコードでは、サーバーの名前をdefault-serverとして、その他の拡張機能を有効にするために、いくつかの拡張を定義しています。具体的には、Infinispan、JDBC コネクタ、デプロイメントスキャナー、JBoss EE、EJB、JacORB、JAX-RS、JDR、JMX、JPA、JSF、ロギング、JNDI、POJO、プロキシおよびリモート、サービスアーカイブ、セキュリティ、スレッド、およびトランザクションなどを含めます。これらの拡張を有効にしておくと、Wildfly は期待通りに機能するように設定できます。
【2023年05月版】Ubuntu22.04 上での DRBD によるストレージレプリケーション メッシュ構築編

# はじめに

- 絶対に１ミリでもなくしてはいけないデータを手軽に管理したい
- 共有ディスクによるレプリケーションはお高い・・・ソフトウェアでできないものか
- オンプレだけでなく、AWS上でもレプリケーションしたい
- EBS利用である程度保証されるが、A-Zをまたいでストレージレプリケーションしたい
- そうだ DRBD しよう
- の、2023年05月版
- の、３ノードによるメッシュ版

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143127/e2708e2c-99b9-7e8f-5d62-e976cabbe37c.png)

まとめはこちら

[【2023年05月版】Ubuntu22.04 上での DRBD によるストレージレプリケーション](https://qiita.com/nouernet/items/31536b9f63837b0c9001)

# 前提条件

- 3台の ubuntu 22.04 で構築
- Primary を node1、Secondary を node2, node3 とする
- /dev/sda をシステム、/dev/sdb をストレージレプリケーションとして利用
- node1 の IPアドレスは 192.168.100.101 とする
- node2 の IPアドレスは 192.168.100.102 とする
- node3 の IPアドレスは 192.168.100.103 とする
- drbdで作成されるデバイスは、/dev/drbd0 とする
- マウント先は /export とする

# 手順

- DRBD のインストール
- 設定ファイルを作成
- メタデータの作成
- DRBD の起動
- Primary の決定

# 作業

## DRBD のインストール

- node1, node2, node3 で実行

```terminal
$ sudo add-apt-repository ppa:linbit/linbit-drbd9-stack
$ sudo apt update
$ sudo apt install drbd-utils drbd-dkms
$ sudo modprobe drbd
$ cat /proc/drbd
version: 9.2.2 (api:2/proto:86-121)
GIT-hash: 8435da3ec2a0a70dee0fedf354276d6f1c6ba708 build by root@drbd1, 2023-05-26 13:01:35
Transports (api:18): tcp (9.2.2)
```

## 設定ファイルの作成

- node1, node2, node3 で実行

```terminal
$ sudo tee /etc/drbd.d/global_common.conf <<EOF > /dev/null 
global {
    usage-count no;
}
common {
    net {
        protocol C;
    }
}
EOF
```

```terminal
$ sudo tee /etc/drbd.d/r0.res <<EOF > /dev/null 
resource r0 {
    volume 0 {
        device minor 0;
        disk "/dev/sdb";
        meta-disk internal;
    }
    on node1 {
        node-id 0;
        address 192.168.100.101:7789;
    }
    on node2 {
        node-id 1;
        address 192.168.100.102:7799;
    }
    on node3 {
        node-id 3;
        address 192.168.100.103:7809;
    }
    connection-mesh {
        hosts node1 node2 node3;
    }
}
EOF
```

## メタデータの作成

- node1, node2, node3 で実行

```terminal
$ sudo drbdadm create-md r0
```

## DRBD の起動

- node1, node2, node3 で実行

```terminal
$ sudo drbdadm up r0
$ sudo drbdadm status r0
```

## Primary 決定

- Primary だけで実行

```terminal
$ sudo drbdadm primary r0
$ sudo drbdadm status r0
$ sudo mount /dev/drbd0 /export
```

# さいごに

- かんたんでしたね

# 参考

[Ubuntu 22.04 man page drbdadm](https://manpages.ubuntu.com/manpages/jammy/ja/man8/drbdadm.8.html)
[Ubuntu 22.04 man page drbd](https://manpages.ubuntu.com/manpages/jammy/ja/man8/drbd.8.html)

[DRBD9 ユーザーズガイド](https://linbit.com/drbd-user-guide/drbd-guide-9_0-ja/)
[LINSTOR ユーザーズガイド](https://linbit.com/drbd-user-guide/linstor-guide-1_0-ja/)
2分でプロフェッショナルなデベロッパーの履歴書を作成


目を引くCVを作るのは簡単ではなく、通常、コンテンツ、タイポグラフィ、ロジック、UIデザインの面で磨く必要があります。 真っ当な開発者にとって、タイポグラフィとUIは見落としがちな部分です。

私は長年にわたり、何百人もの候補者と面接し、仕事の関係で何千もの履歴書を読んできました。 優秀な人事の場合、候補者の基本的な要件や強みを理解する以外に、候補者の態度、細部にこだわるかどうか、自分自身に何を求めているか、さらには一般的な性格、大工場の暗い言葉で言えば、センスがあるかどうかなど、履歴書から読み取れる追加情報がたくさんあるのです。

では、本当に良い履歴書とはどのようなものなのでしょうか。 私の審美眼では、次のようなスタイルが好ましいと思います。

![En-rs.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3329120/59898087-3ac3-4c35-ec08-6caec300aa2c.jpeg)

![ch-rs.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3329120/7b22e03c-1e60-fcdc-5a9a-01e13ace47a8.jpeg)

などなど、一見するととても楽しそうですが、実は細部にまでこだわりが詰まっています：

1. フォントの選択

2. サイズ、太さ、イタリック体

3. スペーシング

4. リスト

5. ブロック

6. タイポグラフィ

このように、ゼロから優れた履歴書をデザインするのは非常に複雑です。 ほとんどの学生はまだ一般的なWordのテンプレートを使う段階ですし、一部の厳しい学生にはLatexを使って、美しいが非常に複雑なものを作成することもあります。

さて、「Simple CV」（https://easycv.cn/）を使えば、わずか2分でプロフェッショナルな開発者向けCVを作成することができます。

![简单.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3329120/c357b58a-e1c7-5ee0-0e56-5169627e7788.png)


豊富な内蔵テンプレート
"シンプルレジュメ "には豊富な内蔵テンプレートがあり、基本的にインターネット上の様々な職種をカバーしています。 例えば、フロント・バックエンド、モバイル、Web3、運用・保守、テスト開発、デザイン・プロダクトなどです。

Image![产品.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3329120/8d20fa71-b942-b4d7-ad90-d45488fa44d5.png)


お好きなテンプレートを選ぶだけで、フォームリッチで論理的、UIにこだわった履歴書が作成できます。

![细腻.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3329120/05d73661-b7db-83a1-c2dc-351b09e16dd6.png)


開発者にとっては、自分の強みを生かすために、より多くのエネルギーを使うために、コンテンツに集中する必要があるのです。

最後に、もしテンプレートに不満があれば、コンテンツはそのままにいつでも変更できるのは、とても気が利いていると言わざるを得ません！

![贴心.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3329120/9f21bc9d-47e1-efb0-5e98-a31bd2dd5a36.png)



強力なコンテンツエディター
"シンプルレジュメ "のコンテンツエディターは非常に強力で、例えば、履歴書のレイアウトを並び替えることができます。

![调序.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3329120/bbe78325-eccf-e902-9669-b75b8662bb41.gif)


また、履歴書の内容についても、同様にドラッグ＆ドロップでソートすることが可能です。

![tuo dong.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3329120/e3536fb7-d008-a2b1-4e53-b3194e71bc61.gif)


交流や体験の面で本当に優れていると言わざるを得ません！

オンラインでの共有とダウンロード
CVを作成したら、公開で共有するか、PDFでダウンロードするかを選択できます（会員機能）。

驚くべきことに、PDFをダウンロードする際には、PCとモバイルの2つのレイアウトがサポートされています。通常のPDFの履歴書では携帯電話では読みにくいので、携帯電話を使って採用活動を行う人事担当者にはありがたいですね。

![会员.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3329120/8f1ce87e-ef40-532c-e352-2862ad18b428.png)

「简单简历」(https://easycv.cn/)
Google Bardにdocstringと型ヒントを追加してもらう

# 1.はじめに
* Google Bardで関数にdocstringと型ヒントを追加してもらった。

# 2.経緯
* pythonでdocstringと型ヒントを追加しなきゃいけないのは重々承知しているのだけど、いつもその場しのぎで関数など作成してました。喉元過ぎれば熱さを忘れるをしてたけど、さすがにまずいと思い、docstringと型ヒントを追加していこうと思います。
* ただ、自力ですぐに実行できないので、なんとかできないかと考えてGoogle Bardに聞いてみることに。お手本としてどんな感じに出してくれるのか。


# 3. 入出力

関数自体は、[ここ](https://www.wipo.int/classifications/ipc/en/ITsupport/Version20230101/index.html)に載っている特許分類(IPC)の階層構造をxmlで取得して、BeautifulSoupでパースした後にかける処理。


* 最初の関数
```python
def get_undersymbol(kaiso_list, kaiso_num):
    under_kaiso_list = []
    for present_symbol in kaiso_list:
        under_symbol = present_symbol.split("->")[-1]  # 下の階層のみ取得
        under_symbol_obj = soup.find("ipcEntry", {"kind": str(kaiso_num), "symbol": under_symbol})
        if under_symbol_obj is not None:
            pass
            #under_kaiso_list.append([present_symbol])
            if is_list_iterator_empty(under_symbol_obj.children):
                pass
                #under_kaiso_list.append([present_symbol])
            else:
                under_kaiso_list.append([under_symbol + "->" + tag["symbol"] for tag in under_symbol_obj.children])
    return list(itertools.chain.from_iterable(under_kaiso_list))

```


* [Bard](https://bard.google.com/)にはこんな感じにかなりアバウトに入れる。

```python
この関数にdocstringと型ヒントを入れてください。
####上記の関数をはりつけ###

```





* Bardに追加してもらった結果：
```python
from typing import List
def get_undersymbol(kaiso_list: List[str], kaiso_num: int) -> List[str]:
    """
    Get the undersymbol list of the given kaiso list.

    Args:
        kaiso_list: The kaiso list.
        kaiso_num: The kaiso number.

    Returns:
        The undersymbol list.
    """

    under_kaiso_list = []
    for present_symbol in kaiso_list:
        under_symbol = present_symbol.split("->")[-1]  # 下の階層のみ取得
        under_symbol_obj = soup.find("ipcEntry", {"kind": str(kaiso_num), "symbol": under_symbol})
        if under_symbol_obj is not None:
            pass
            #under_kaiso_list.append([present_symbol])
            if is_list_iterator_empty(under_symbol_obj.children):
                pass
                #under_kaiso_list.append([present_symbol])
            else:
                under_kaiso_list.append([under_symbol + "->" + tag["symbol"] for tag in under_symbol_obj.children])
    return list(itertools.chain.from_iterable(under_kaiso_list))


```

ちゃんと追加してくれる！Argsなどは日本語でもう少し説明してもいいかも。
Bardさまありがたや。
docstringと型ヒントあれば昔の自分も怖くない！
今後もちゃんと毎回使わせてもらおう。
無料で簡単にSlackからメールを送ってみる

## やりたいこと

- PCがなく、携帯でのGmailログインが許可されていない場合でもSlackから特定の宛先にメールを送りたい
- 無料版Zapierの2STEPしか組めないワークフローでもメール機能を実現したい

Zapierを使えばSlackから取得した情報を成型してメールや他のSaasに転送等できますが、
通常は成型のSTEPを挟むため、無料版の2STEPではかなりできることが限定的です。
それでも何とかSlackからのメールを送りたく方法を考えてみました。

## Zapierの設定
Zapierではノーコードで自動転送や通知bot、ワークフローを設定できます。
登録方法やできること概要はここがわかりやすい：https://notepm.jp/blog/5856

- ログイン後トップページからCrateZAPをクリックしてワークフロー作成を始める
- TriggarにSlackを選択(初回はSlackで連携の許可が必要)、Eventに「New Pushed Message in Slack」を選択
    - これでSlack側で明示的にPushを押すと開始するワークフローになります
<img alt="hogehoge" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3459205/ddbce5ac-5c97-480d-2fd1-3be3a085adbc.png" width="60%">

- TESTボタンをクリックし、Slackのメッセージがパラメータとして取得できることを確認
- ActionステップでGmailを選択（ここでも初回は連携の許可が必要）
- Eventに「SendEmail」を選択
- Actionの内容に以下を設定する
    - To:送りたい送信先アドレス
    - Cc,Bcc,Fromname,Reply to：お好みで
    - Subject:プルダウンから、Message Text
    - Body：TextAdded 
<img alt="hogehoge" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3459205/0c15f4e6-50e8-636e-5ee9-3f1321526f96.png" width="60%">

- Continue,Testをクリックし、問題がなければPublishボタンでリリース
※ワークフローの名前を送信先名称にしておくとよいでしょう。


## Slack側の操作
- Zapierでメール件名にSlack本文、メール本文にAddedTextを指定したので、まずは自分のチャットルームで件名をメッセージとして送信
![スクリーンショット 2023-05-31 151827.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3459205/eb5a8d93-556d-7d30-805d-0aea4a18adcf.png)
- メッセージのメニューから「その他」→「Push to Zapier」を選択
- Zap to triggerで先ほど作成したアプリ名（宛先名）を選択
- AdditionalTextにメール本文を入力
![スクリーンショット 2023-05-31 151218.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3459205/0da13ea7-5c84-8abf-459a-10ec734e9623.png)

- Pushを押してZapierから通知があれば完了
![スクリーンショット 2023-05-31 151835.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3459205/4c1342b1-ef5e-401a-cf62-52f684f24b51.png)

ではメールを見てみましょう。

![スクリーンショット 2023-05-31 152552.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3459205/97d6584b-8698-abe6-6fc0-b4f6d23920d2.png)

届いてますね。
メールのお作法は面倒に感じますが、とはいえ業務メールはもっと丁寧に書きましょう。

## 最後に

今回はZapierの無料枠でできる小技でしたが、有料版でできることはぐっと広がりますので、
さっさとライセンスを買ったほうが幸せになれそうです。
Slackでのメール検索とか画像の自動格納とかいろいろ試してみたいですね。
行列式と逆行列

予備：
まず２次元ベクトル空間において「面積とはなにか？」を考えてみる。
面積は、２つのベクトル${\bf a},{\bf b}$の関数である。ベクトル${\bf a}$を固定して考えると、${\bf a}$に垂直方向の成分を乗じたものが面積である。${\bf b}$の「${\bf a}$に垂直方向の成分」は${\bf b}$の線形関数である。ただし、マイナス方向にもなり得るので、「まずは線形関数である向き付き体積$S({\bf a},{\bf b})$」を考え、その絶対値を面積である、とする必要があることがわかる。

---
次に、3次元ベクトル空間において、3つのベクトル<B>a,b,c</B>のつくる平行六面体の向きつき体積関数$V({\bf a},{\bf b},{\bf c})$」を考えよう。この関数$V$に対して以下の１，２を要請する。以下の議論はN次元にも適用することができる。

#### 向きつき体積と行列式
以下の「向き付き体積」が行列式そのものである。要請１と２は上述の考察から、「向き付き体積」として自然なものである。

**要請１**
$V({\bf a},{\bf b},{\bf c})$が、それぞれの引数についての線形関数であることを要請する。例えば${\bf a}$,${\bf b}$を固定して${\bf c}$の関数として体積を考えるなら${\bf a}$,${\bf b}$の作る垂直面に対する成分のみが効くので加算的であるからである。これは２次元のときの議論と同じである。
**要請２**
$V({\bf x},{\bf x},{\bf y})=0$を要請する。体積なので同じベクトルが２個入るとゼロとなること.


このような性質を持つ線形関数は完全反対称線形関数である。すなわち2を用いて、$V({\bf a+b},{\bf a+b},{\bf c})=0$を１の線型性を用いて展開しさらに２を用いると、$V({\bf a},{\bf b},{\bf c})+V({\bf b},{\bf a},{\bf c})=0$となるのがわかる。これは１番目と２番めの引数について行ったが、他の組み合わせの引き数についても同様であり、完全反対称化線形関数と呼ばれる。

さて、要請１から、３つの基底ベクトル$e_1,e_2,e_3$を用いた3x3x3=２７個の$V(e_i,e_j,e_k)$が存在し、$V({\bf a},{\bf b},{\bf c})$は、この基底$e_1,e_2,e_3$による${\bf a},{\bf b},{\bf c}$の成分表示から計算できることになる。しかし、27個必要かというとそうではないー上述の完全反対称性より基底をひっくり返す（置換する）と符号が変わることになる。これはすべての置換について言えるから$V(e_1,e_2,e_3)$がわかれば体積が計算できることになる。

この向きつき体積こそが<B>a,b,c</B>の作る行列式そのものである。内積の定義とは無関係に導入されることにも注意しておく。長さ（内積で定義されるもの）は、ここで考える体積とは別の概念である。
（この時点での蛇足：外積代数の概念について。$V(e_i,e_j,e_k)$を${e_i}$^${e_j}$^${e_k}$などと書いたりもする。${e_i}$^${e_j}$も考えることができる。反対称化の要請から${e_i}$^${e_j}$^${e_k}$は３次元空間では１個しかないが、４次元空間中の${e_i}$^${e_j}$^${e_k}$は４個存在する。体積は線形性と反対称性を用いて${\bf a}$^${\bf b}$^${\bf c}$を基底ベクトルを用いて表現したときの${e_1}$^${e_2}$^${e_3}$の係数となる。

#### 逆行列
上述の体積関数において、${\bf a}$を${\bf x}$に置き換え$V({\bf x},{\bf b},{\bf c})$を考えよう。${\bf x}$に${\bf a}$をいれると元の行列式の値（＝向きつき体積⊿とおく）を再現する。一方で、${\bf x}={\bf b}$あるいは${\bf x}={\bf c}$とすると要請２からゼロとなってしまう。またV(<B>x,b,c</B>)はｘの線形関数であり、V(<B>x,b,c</B>)=<B>A</B>・<B>x</B>と書ける（・は内積である。これをまとめると、「⊿=V(<B>a,b,c</B>)として、<B>A</B>・<B>a</B>=⊿、<B>A</B>・<B>b</B>=0、<B>A</B>・<B>c</B>=0」である。同様にして、<B>B</B>と<B>C</B>も作れる。

<B>A,B,C</B>のそれぞれを行ベクトルとして（行、列は英語（横書き）で考える）上から並べた行列を考える。これに行列(a,b,c)（これは列ベクトルを横に並べる）を掛け合わせると、⊿を対角成分に持つ対角行列を得る。これを⊿で割っておけば逆行列となる。

上述の記述は多次元にも一般化できる。３ｘ３行列を教えたら一般的な話はだいたいみなわかる。線形代数の教え方には問題が多い、掃き出し方などを延々とやらせなくていいし、数値をいじるのならpythonと組み合わせて教えたほうが良い。サラスの公式を暗記させるなども悪弊だと思える； 数独と行列式の関係を考えてみたほうがいい。伝統的な余因子行列の教え方では意味がつたわらないことも多い。


#### 外積代数
$V(e_1,e_2,e_3)$のことを$e_1$^$e_2$^$e_3$などと書いたりする。N次元空間において完全反対称化線形関数$A(v_1,v_2,...,v_{M})$を考えると,その基底($A$の計算に必要なもの）は$A(e_1,e_2,...e_M)$など「N個の中からM個取り出す場合の数だけ」あることになる。これを$e_1$^$e_2$^$e_3$...^$e_{M}$などと書く。これが外積代数の基底となる。ベクトルの順序は意味がないが、これに含まれる$e_i,e_j$をひっくり返すとマイナスが出る。Mは１からNまで取りうる。たとえばN=3、M=2では3次元空間において$e_1$^$e_2$,$e_2$^$e_3$,$e_3$^$e_1$を考えることになる。３方向の射影面の基底である。

ここでもうちょっとアイデアを拡張してMの違うものも全て集めた集合$E$を考える。集合$E$はそれらの基底から線型結合を取ったものとしてよい。
そして定義域$E$における二項演算子として＾を定義する（注意：上の記述では＾を二項演算子として定義していない）。すなわち、$(e_1$^$e_2)$^$e_3$=$e_1$^$e_2$^$e_3$と定義すれば良い。これにより線形空間$E$に二項演算^が導入できた（双線形な写像）。


---
注：3次元空間における２次元の面積を議論するには、基底の等価性、基底の変換について議論しないといけない。これには内積の議論も必要になる。
Laravelの命名規則

## 記述方法について
①アッパーキャメルケース
単語の先頭の文字はすべて大文字で記述する。
例）ShoppingCart

②ローワーキャメルケース
先頭は小文字だが、続きの単語の先頭は大文字で記述する。
例）shoppingCart

③スネークケース
単語と単語をアンダースコアでつなぐ。
例）shopping_cart

④ケバブケース
単語と単語をハイフンでつなぐ。
例）shopping-cart
空の配列が渡されたらどうするか

```
bool isAllOk(Array array)
```

例えば、配列を調べていって、全てTrueならTrueを返す関数があるとします
このとき、空の配列が渡されたらどうするでしょうか

実例に合わせて考えると、箱の中の商品の品質をチェックして、
すべて合格なら出荷する、という例ですね

これは、箱が空なら合格とすべきです
0個で出荷とかどう考えてもエラーだから、不合格だ、と思うかもしれませんが
それは個数チェックであり、品質チェックとは別種のチェックです

なぜなら、品質チェックの目的は製品が問題なく組み立てられているかのチェックであり
商品のピックアップ部分に問題があるかをチェックするものではありません

# 一般化

上記の例ではTrueだったのですが、時にはFalseを返すのが正解の場合もあります

例えば、「1個でも合格品があれば合格」という検査の場合、空の場合はどうでしょうか
たとえば、最低1個はあたりが保証されているくじ、なんてものを考えてみましょう
それなら、空の場合は当然不合格ですね

これらを一般化すれば、「単位元」を返す、が正解になります

# 単位元とは

単位元とは、何もしない数と捉えればいいです
足し算に置いては0で、掛け算においては1です

「すべてTrue」というチェックでは、単位元とはTrueになり、
「どれか1個でもTrue」というチェックでは単位元はFalseになります

# 数学において

$1\times0 = 0$というのは、誰もが疑うことがないですが、冷静に考えると難しいです
1を0回足す、と言われて、すぐに行動が理解できる人は少ないでしょう
これは、足し算の単位元が0だから、という理由付けにもなっています

```math
1^0=1 \\
0!=1
```

掛け算の例です
0回掛け算をするときは単位元とすると都合がいいのですね

# 吸収元

余談ですが、「すべてTrue」でのFalseは、それを加えると必ずFalseに変化します
また、「どれか1個でもTrue」でのTrueは、それを加えると必ずTrueに変化します
このように、それと演算すると、結果が自分自身の値になるものを吸収元と言います

単位元が場を荒らさないものとしたら、
吸収元はすべてをぶち壊し自分の世界を造る乱暴者という感じがしますね

足し算に吸収源は存在しませんが、掛け算は0が吸収元です
SurrealDBとGo

# 本記事の目的

弊社で使用しているかなり参照用のRestAPIのストレージをRedisからSurrealDBへ置き換えた際の知見を基にした記事です。
所感としてはリレーショナルなストレージとしてはフットプリントがとても軽くて割り切った運用では有用だなと感じました。SQLiteやKeyValue系のストレージと競合する印象です。

# SurrealDB

Goのドライバは以下で提供されています。
https://github.com/surrealdb/surrealdb.go

以下のコードはGo1.18.4で動作確認しております。

## Signin

- 認証用のメソッドです。ユーザーとパスワードを指定します。

```golang	
	surrealdbHost := os.Getenv("SURREALDB_HOST")
	surrealdbPort := os.Getenv("SURREALDB_PORT")

	if surrealdbHost == "" {
		surrealdbHost = "127.0.0.1"
	}
	if surrealdbPort == "" {
		surrealdbHost = "8000"
	}
	db, err := surrealdb.New(fmt.Sprintf("ws://%s/rpc", surrealdbHost))
	if err != nil {
		panic(err)
	}
    surrealdbUser := os.Getenv("SURREALDB_USER")
    surrealdbPassword := os.Getenv("SURREALDB_PASSWORD")

	if _, err = db.Signin(map[string]interface{}{
		"user": surrealdbUser,
		"pass": surrealdbPassword,
	}); err != nil {
		panic(err)
	}

```
## Use

- 名前空間とデータベース（スキーマ）を指定します。

```golang

```


## Create

- レコード作成に使うメソッドになります。
- 第一引数に`{テーブル名}:{主キー}`の書式で記載します。主キーを省いた場合にはUUIDが割り当てられます。

```golang
		dbRecord := map[string]string{
			"zipcode": record[2],
			"pref":    record[6],
			"city":    record[7],
			"town":    record[8],
		}
		//createには作成したレコードがそのまま戻る
		create, err := db.Create("zipAddress", dbRecord)
		if err != nil {
			panic(err)
		}

```

## Query

- レコード参照に使うメソッドになります。複雑なSELECT(ORDER BY,GROUP BY等を使う場合)はほぼこちらを使うことになると思います。
- SmartUnmarshallを使うと変換するコードを書かずに済むのでとてもスッキリ書けます。

```golang
    // 郵便番号から都道府県・市区町村・町域を取得する。
	res, err := surrealdb.SmartUnmarshal[[]ZipAddress](db.Con.Query(
		"SELECT pref,city,town,zipcode FROM zipAddress WHERE zipcode=$zipcode ORDER BY zipcode",
		map[string]interface{}{"zipcode": zipcode}))
	if err != nil {
		return nil, err
	}
```


# SurrealDB

SurrealDBの内部構造やSurrealQLについては下記の記事が詳しいです。

https://qiita.com/iisaka51/items/45f23df873ea5be433c7
今更pytest&pytest-cov

## テスト対象

```main.py
import re


def sum_up(a: int, b: int) -> int:
    return a + b


def subtract(a: int, b: int) -> int:
    return a - b


def sum_up_str(a: int | str, b: int | str) -> int:
    # check if a and b are castable to int
    if re.match(r"^\d+$", str(a)) is None:
        raise ValueError("a is not castable to int")
    if re.match(r"^\d+$", str(b)) is None:
        raise ValueError("b is not castable to int")
    if isinstance(a, str):
        a = int(a)
    if isinstance(b, str):
        b = int(b)
    return a + b
```

## テストコード

```test_main.py
import pytest

from src.main import subtract, sum_up, sum_up_str


def test_sum_up():
    assert sum_up(1, 2) == 3
    assert sum_up(2, 2) == 4


def test_subtract():
    assert subtract(1, 2) == -1
    assert subtract(2, 2) == 0


def test_sum_up_str():
    assert sum_up_str(1, 2) == 3
    assert sum_up_str("1", "2") == 3
    assert sum_up_str("1", 2) == 3
    with pytest.raises(ValueError) as a_exc:
        sum_up_str("a", 2)
    assert a_exc.value.args[0] == "a is not castable to int"
    with pytest.raises(ValueError) as b_exc:
        sum_up_str("1", "b")
    assert b_exc.value.args[0] == "b is not castable to int"
```

## ディレクトリ構造

```bash
.
├── src
│   ├── __init__.py
│   ├── main.py
├── tests
│   ├── __init__.py
    ├── test_main.py
```

## 実行

インストールして

```bash
$ pip install pytest pytest-cov
```

実行

```bash
$ pytest tests --cov
---------- coverage: platform linux, python 3.10.9-final-0 -----------
Name                 Stmts   Miss  Cover
----------------------------------------
src/__init__.py          0      0   100%
src/main.py             24      0   100%
tests/__init__.py        0      0   100%
tests/test_main.py      18      0   100%
----------------------------------------
TOTAL                   42      0   100%
```

## test_main.pyの解説

`test_main.py`の`test_sum_up_str`の`assert`を幾つか削除するとカバレッジが低下します。
これはテスト対象のコードの一部が実行されなくなるため。

カバレッジを見ながらテストの網羅性を確認しましょう。
パスワード・ジェネレータを作った

---
## はじめに

Webブラウザ単体で動作するパスワード・ジェネレータ(パスワード生成)を作った。

パスワードをどうしようか悩んだ時に使ってみてください。

仕組みは、単純でJavaScript(またはWebAssembly)で乱数を生成して、それに対応する文字を羅列しているだけです。

JavaScriptもWebAssemblyもWebブラウザ上で動作しているので、生成したパスワードが通信経路上に流れることはないので、比較的安全です。

---
## JavaScriptで動作するパスワード・ジェネレータ

[http://rocketeer.dip.jp/sanaki/free/javascript/freejs12.htm](http://rocketeer.dip.jp/sanaki/free/javascript/freejs12.htm)

予測できる乱数なので、生成日時が判明すると安全性は低くなるので、注意。

---
## モダンなWebブラウザで動作するJavaScriptで動作するパスワード・ジェネレータ

[http://rocketeer.dip.jp/sanaki/free/javascript/freejs25.htm](http://rocketeer.dip.jp/sanaki/free/javascript/freejs25.htm)

こちらは、モダンなWebブラウザが実装している暗号論的な乱数を使っているので、より安全になっている。

---
## WebAssemblyで動作するパスワード・ジェネレータ

C#/.NETをWebAssemblyとして動作させるBlazorという仕組みで作りました。

[http://rocketeer.dip.jp/sanaki/free/free165.htm](http://rocketeer.dip.jp/sanaki/free/free165.htm)

[実物はこちら→http://rocketeer.dip.jp/sanaki/free/PassgenBlazor/](http://rocketeer.dip.jp/sanaki/free/PassgenBlazor/)

こちらも.NETの暗号論的な乱数を使ってパスワードを生成している

---
## 以上
【React】Uncaught ReferenceError: styled is not definedの対処法

<h2>症状</h2>
styledでいろいろいじっていたら、以下のエラーが発生しました。
翻訳すると「参照エラー: スタイルが定義されていません」でした。

```terminal:error
Uncaught ReferenceError: styled is not defined
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927880/d4aed83b-c9c0-0072-5a6a-63c8915ba8e2.png)

以下がソースです。

```react:MaterialUISaveButton
import React, { useState } from 'react';
import { makeStyles } from '@material-ui/core/styles';
import styled from "styled-components";
import SaveIcon from '@material-ui/icons/Save';
import LoadingButton from '@mui/lab/LoadingButton';
import { COLORS } from "../style_constants";

const useStyles = makeStyles((theme) => ({
  button: {
    margin: theme.spacing(1),
  },
}));


const CustomButton = styled(LoadingButton)({
  backgroundColor: COLORS.MAIN_COLOR,
  opacity: 0.9,
  "&:hover": {
    backgroundColor: COLORS.MAIN_COLOR,
    opacity: 1,
  },
});

export function SaveButton({ onClick, btnLabel }) {
  const classes = useStyles();
  const [loading, setLoading] = useState(false);

  function handleClick() {
    setLoading(true);
    onClick();
    setTimeout(function () {
      setLoading(false);
    }.bind(this), 5000);
  }

  return (
    <div>
      <CustomButton
        size="large"
        variant="contained"
        color="primary"
        onClick={handleClick}
        loading={loading}
        loadingPosition="end"
        endIcon={<SaveIcon />}
        className={classes.button}
      >
        {btnLabel}
      </CustomButton>
    </div>
  )
}

```

<h2>解決方法</h2>
importにstyledがなかったため、定義されないと怒られていたようです。
上のソースにimportを追加したら、解決しました。

```react:MaterialUISaveButton
import styled from "styled-components";
```

以下の記事では、importを消すと書いてあったのですが、別の事例だったので

https://zenn.dev/toshiokun/articles/a445b894f145ff

<h2>参考</h2>

https://zenn.dev/toshiokun/articles/a445b894f145ff
C#　イテレーターパターンを実装してみる

## はじめに
今回はイテレーターパターンを実装してみる。
ちなみにChatGPTにイテレーターパターンを訪ねるとこう返ってきた。

イテレーターパターン（Iterator Pattern）は、オブジェクトのコレクション内の要素に順番にアクセスするための方法を提供するデザインパターンです。このパターンは、コレクションの内部構造に依存せずに要素を反復処理するための共通のインターフェースを定義します。
イテレーターパターンの主な目的は、反復処理の詳細をコレクションから分離することです。これにより、コレクションの実装が変更されても、反復処理のクライアントコードに影響を与えることなく、反復処理の方法を変更できます。また、複数のクライアントが同時にコレクションを反復処理できるようにすることも可能です。


## 実装
今回はイテレーターパターンを使って、社員名簿を生年月日順、社員番号順に書き出すプログラムを実装してみた。
イメージはこう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3131319/f29b5673-f3fd-5a06-59eb-ad12fe299027.png)

イテレーターはhasnext()とnext()を持ち、具象のクラスで生年月日順か職番順かによってそれぞれ中身の実装を行った。
以下は、生年月日順のConcrete Iterator
![2023-05-31_15h23_41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3131319/bd82e281-bdaf-7ba0-f46e-47f66e3a2e4a.png)


Concrete AggregateのGetIteratorでは上記のインスタンスを生成して返すだけ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3131319/d25d6c6a-9e28-604f-de1b-bb031bcbb57d.png)

これでmainで生年月日順のみコンソール出力コードを書いてみる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3131319/87584587-fb98-23ec-de84-c82bec44e536.png)
hasnext()で要素があるかないかを判定し、next()で取り出している。
同じように職番順も実装すると、mainでは切り替えができる。

## 終わり
ここまで、上記設計に基づき実装してきた。今回は、大まかな流れをかいつまんで実装箇所を記載した。
引き続きデザインパターンの実装を行っていくのでそちらも見ていただければと思います。
本記事も不十分な箇所があるので随時更新します。
【その５】分岐処理を入れる

<br>[【その１】RPA初心者と歩むPower Automate活用日記【ポイ活】](https://qiita.com/tantanshio/items/2b741584f65d8ce967f8)


# ◆分岐処理を入れる

以下のクリック対象となる項目が無い場合はスキップさせる必要がある
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523511/d46c485e-959a-fceb-7333-f3010e1c9b12.png)


UIオートメーションから
「画像が存在する場合」を選択


フローにドロップすると以下設定が表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523511/6a5e1710-a80c-359a-0dcf-5335d1aa71a9.png)


分岐のポイントとなる画像を設定・選択する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523511/a9f453f1-2389-98fb-10c9-5c38e6a806a1.png)




このように表示される

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523511/b8e517ae-259d-fd42-aaa6-a74852ebb7f8.png)

画像が存在する場合
と
End
の間にある処理が存在する場合のみ実行される






画像が存在する場合のみ、ループを抜ける設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523511/4478b4ab-5dc5-6b05-afc3-81dde9fc9cf1.png)




実行すると無事ループ抜け




対象が無い状態で実行すると..

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523511/cd0efe5a-f85d-16e1-5768-315a75cf5cc8.png)

無限ループ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523511/9743c4be-831b-251e-09a5-c108ffa6658a.png)


# ◆次回　【その６】サブフローを活用する
リセットCSSは秒で解決

# はじめに
CSS崩れを回避する、リセットCSS。
秒で解決しましょう！

<details><summary>リセットCSSとは？</summary><div>
各ブラウザには、デフォルトでCSSの値が指定されています。
そのため、ブラウザを変えて表示するとCSSのデザイン崩れが起こってしまいます。

それをリセットすることで、デザイン崩れを予防するのが、リセットCSSです。
</div></details>

# レッツコピペ、リセットCSS
htmlのhead内に、下記のコードを追加しましょう!

```html
<link rel="stylesheet" href="https://unpkg.com/ress/dist/ress.min.css">
```
はいOKです！
別途CSSファイルも不要です！

ちなみに、これまでは自分でリセットCSSファイルを用意していました。
上記だとディレクトリもスッキリするし、何よりめっちゃ楽ですね😇

※ほかにもおすすめのリセットCSSがあれば教えていただきたいです！
【サイトセットアップ】Sharperlightユーザーの一括挿入を試みる

:sweat:[過去にも投稿済み](https://qiita.com/Miki_Yokohata/items/b7cc51d649ad09b3c2f8)

[Sharperlight](https://sharperlight.jp/)ユーザーの一括作成を行ってみたいと思います。
一度に大量のユーザーを作成したい時に役に立つと思われます。
同時にユーザーグループの作成は行われないので、あらかじめユーザー追加対象となるユーザーグループを作成しておきます。
今回は、**QiitaDemo**と**QiitaSample**ユーザーグループとしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/1d33d9e2-e3a2-6214-d759-82bfe8161424.png)

ユーザーの一括作成を行うためのデータは、コンマ区切りのCSVリスト形式で準備します。
Sharperlightアプリケーションメニューから**サイトセットアップ**を起動します。
サイトセットアップでは、`ユーザー`フォルダを選択します。
右クリックメニューより**ユーザーのインポート** -> **CSV**を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/1ab9d01d-83b9-ea02-c3f8-5794f77008be.png)
既定のテンプレートユーザーの選択を促すダイアログが表れるので、作成時にテンプレートとして使用する既存のユーザーを指定します。ここで指定したテンプレートユーザーの全ての設定が、ここでインポートされる全てのユーザーに設定されます。`OK`ボタンで先に進みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/d02b3a08-5062-8501-f3c2-fdf3c7158b46.png)
ここで一括作成するユーザーのリストを指定するダイアログが、フォーマット例とひとつの実例とともに表示されるます。
最初の２項目、つまり**ユーザー名**と**ユーザーグループコード**は必須ですが、残りの３項目はオプションです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/2bba811c-7dd8-f624-a809-715b64e8f582.png)
先にフォーマット例とひとつの実例を削除した後、指定のフォーマットに従って予め作成しておいたリストをここに貼り付けてもよし、テキストファイルとして準備しておいたファイルを`インポート`ボタンを利用して読み込んでもいいです。もちろん直接入力もできます。
今回はこのようなリストを準備してみました。
**QUSer1**から**QUser5**の５つのユーザーを追加します。そのうち**QUser1**から**QUser3**ユーザーは**QiitaDemo**ユーザーグループに属します。残りの**QUser4**と**QUser5**ユーザーは、**QiitaSample**ユーザーグループに属します。
又、**QUser1**ユーザーにはパスワードが指定されています。**QUser5**ユーザーに関してはパスワードが指定されていますが、Eメールアドレスは設定されていません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/00ab2079-5491-4dfa-c8ff-5ac470f5fcab.png)
`OK`ボタンでインポートしてみます。
このメッセージが表示されれば大成功！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/057802b4-b48b-e6ef-612c-28832ca7384a.png)
確認してみます。追加されたようですね。
パスワードを指定しなかったユーザーには`パスワードが空白です`という注釈が見えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/65d92aa9-8b99-af1b-5214-2d28ad233adc.png)
**QUser1**ユーザーの詳細をみてみます。指定したとおりになっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/c61ab2c0-41c7-e69b-4fb1-dabcfcfa8188.png)
**QUser5**ユーザーの詳細はどうかな？指定したとおりEメールは設定されていません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/e87d463a-9d59-d92a-c718-a20b1f33d3c1.png)

このようにしてSharperlightユーザー（WindowsドメインユーザーやAzureユーザー以外の）を一括して大量に追加したいといった場合、この方法が便利そうですね。
ご参考までに。

では失礼します。
WordNetのAPIをNext.jsのAPI RoutesとDynamic Routesでかきかきする話

# Hello world.
Hello world. 世界よこんにちはってわけですね。エンジニアの皆さんは一度は聞いたことがあるはず。(ちなみに私は中2)
今回は、ごく少ない需要(皆無)に応えるためWordNetから類義語(いわゆる、"Synonyms")が生成できるAPIをNext.jsのAPI Routesを使って作ったわけです。
なぜか知りませんが、WordNetは大体Pythonで扱うのが主流なようで、まあそれなりに記事が少ないわけです。
というか膨大なワードデータを生成できるAPIを作ってしまったらリソースが爆発しちゃうから、Next.jsでしかもAPI Routeだなんていう浅はかな考えをする人は私ぐらいしかいないわけですので、多少メモっぽく書きます。
# 環境構築
みんな大好き(私は嫌い)環境構築のお時間。
TypeScriptのNext.jsを使っている前提で、naturalというモジュールを入れます。
```
npm i natural
```
# Code
このコードを、コメントアウトにも書いてありますが、Next.jsのAPIディレクトリ(大体pages/api)の中にsynonymsディレクトリを作り、それをさらにDynamic Routesで配置するわけです。pages/api/synonyms/word.tsの中身がこれ↓
```js
// Next.js API route files must be inside the pages/api directory.
// In this case, create a file at pages/api/synonyms/[word].ts

import { NextApiRequest, NextApiResponse } from 'next';
import natural from 'natural';
const wordnet = new natural.WordNet();

const handleRequest = async (req: NextApiRequest, res: NextApiResponse) => {
  if (req.method === 'GET') {
    const { word } = req.query;

    wordnet.lookup(word as string, function(details: any) {
      let synonyms = details.map(function(detail: any) {
        return detail.synonyms;
      }).flat();

      synonyms = Array.from(new Set(synonyms)); // remove duplicates
      synonyms = synonyms.filter((synonym: string) => synonym !== word);

      res.status(200).json({word: word, synonyms: synonyms});
    });
  } else {
    res.setHeader("Allow", ["GET"]);
    res.status(405).end(`Method ${req.method} Not Allowed`);
  }
};

export default handleRequest;
```
TypeScriptの書き方に慣れてないので汚いわけなんですが、
動くのでよしとしましょう。naturalというモジュールが非常に便利で、WordNetだったり諸々が簡単に扱えるわけです。他にも似たようなものはあるのですが、書き方が自分的に自然だったのでこれを選びました。
応答は権利的に公開していいものなのかわからないので、自分で試してみてね。
くれぐれもリソースが爆発しないように、実行は自己責任でお願いします！
### おわり
Ruby on Railsプロジェクトの作成〜サーバーへのアクセスまで

3時間でGoかRailsでGraphQLかRESTfulなAPIをテスト付きでCRUDに作る必要があり、
GoだとAPIに対してのテスト導入やDBの設定にそれ以上掛かりそうだったので、
Railsでやってみようかなと。

久々にプロジェクトを新規作成していたので、備忘録用。

## 作成手順

### Rubyのインストール

```shell
$ brew install rbenv
$ brew upgrade ruby-build
$ rbenv install 3.2.2
```

```shell
$ rbenv local 3.2.2
$ ruby -v
ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-darwin20]
```

### Railsのセットアップ

Bundlerの設定。

```shell
$ bundle init
Writing new Gemfile to /Users/mitsuaki1229/Documents/90_Other/repo/ProjectName/Gemfile
```

Railsのアクティブ化。

```shell
$ sed -i '' "s/# gem/gem/g" Gemfile
```

```shell
$ bundle install --path=.bundle
```

```shell
$ bundle exec rails new .
```

### 起動

```shell
$ bundle exec rails s
=> Booting Puma
=> Rails 7.0.5 application starting in development
=> Run `bin/rails server --help` for more startup options
Puma starting in single mode...
* Puma version: 5.6.5 (ruby 3.2.2-p53) ("Birdie's Version")
*  Min threads: 5
*  Max threads: 5
*  Environment: development
*          PID: 98237
* Listening on http://127.0.0.1:3000
* Listening on http://[::1]:3000
Use Ctrl-C to stop
```

### アクセス確認

http://127.0.0.1:3000

## 感想

3時間以内で色々とやるためには色々と思い出す必要がありそうだ…。
iOS開発のキャリア捨てて現職に転職した理由って、Rubyやりたかったからなんだけど、
4年半働いて、結局のところ、Ruby on Railsの案件に携われたの半年ないな…。

## 参考

https://qiita.com/kaishuu0123/items/2a91495e7daa8c7783ed
CodeBuildでのソースコードのタイムスタンプはいつ時点？

CodeBuildでソースコードのタイムスタンプは毎回ビルド時点での日時になってしまうのか、それとも保存されているのかを実際に動かして確認してみました。

CodeBuildが毎度 git clone しているんじゃないかと思って、日時は保存されずにビルド時点での日時になるのではないかと予想していました。

 **結論** ：予想通り、gitリポジトリに含まれるすべてのソースファイルが毎回ビルド実行時点での日時に変わる


# やってみたこと

1. 適当な中身のあるGitリポジトリを用意
2. CodeBuild設定
3. `find . -ls` をCodeBuildで実行させ、ソースコードのタイムスタンプを確認（`buildspec.yml` に `find . -ls` を記載）
4. Gitリポジトリの中の適当なファイルを修正し、commit & push し、CodeBuildを実行するのを複数回試す
5. CodeBuildのログから `find . -ls` の実行結果を見て、ファイルのタイムスタンプを確認

以下は `buildspec.yml` のサンプルです。

```yml
version: 0.2
phases:
  pre_build:
    commands:
      - echo begin
  build:
    commands:
      - find . -ls
  post_build:
    commands:
      - echo end
```
給料の上げ方

少し前に話題になった記事で共感する部分が多分にあったので、自分の考えも含めてまとめました。

[｢給料が上がらない会社｣はいますぐお辞めなさい 日本人の｢給料安すぎ問題｣を解決する秘策 | 国内経済 | 東洋経済オンライン](https://toyokeizai.net/articles/-/660751)

# 「それで私の給料下がったらどうしてくれるんですか？」という

世の中の全ての人は自身の生活のために仕事をしていて、給料もらえなくなっても今の仕事を続ける人はいないと思います。
そんな生活どころか人生がかかっているライフラインをすべて他人任せにするのは非常に危険です。

世の多くの人は **「偉い人の言うことを聞いて怒られないように仕事をする」** ことを正義としていると思いますが、その偉い人のやり方が間違っていた時に一緒に被害を被るのは自分ですし、実際そのせいで生活が窮地に追い込まれた人はこれまで山ほどいると思います。

そうなったらそれはその時、くらいに考えている人もいるかもしれませんが、それはあまりにリスキーです。

自分の生活を守るために、 仕事に不満があったら **「それで私の給料下がったらどうしてくれるんですか？」** と文句を言う権利が全ての労働者にあると思います。

結果的に意見を取り入れてもらえないことももちろんありますが、何もしなければ何も変わりません。
その時は意見が通らなくても、その後にその意見の正当性が認められて、後になって意見が通りやすくなることもあります。

**愚直に上司の言うことを聞くのではなく、自分の意見を伝えて、自分の意思で今の行動をしていると自認することが大事です。**

# 「給料あげてください」と言う

日本ではお金に関して執着していると、がめついとしてよろしくない行動とされることが多いです。
そのため、「給料あげてください」というのもいやらしい行動と思われていますし、実際そう言われるのを嫌う経営者も多いと思います。

ただ、黙っていても給料がどんどんあがっていくことは有能な上司にあたらない限りまずないです。
黙っていれば「この給料で満足して働いてくれる人」と認識されるだけです。

給料に不満があるなら、 **「給料あげてください」** と声をあげましょう。
そして、 **「あげてくれないと転職しますよ」** と言いましょう。
そういった一人一人の行動が、組織全体の給与を上げるきっかけとなり、結果的に会社全体の利益にもつながります。

給与も賞与もシンプルに労働と貢献の対価です。
不満があるなら声を上げていきましょう。

# 返報性の原理

そうは言っても、ただただ「給料を上げろ」と声高々に言い続けても簡単には通りません。

そこで利用するのが返報性の原理です。

返報性の原理とは簡単に言うと「人から何かしてもらったらお返ししないといけないと思う心理」のことです。

太鼓持ちまでする必要はありませんが、社内で困っている事案や、みんながやりたがらない仕事を積極的にやっていきましょう。
その行動の積み重ねが「XXXさんにはいつもお世話になっているから・・・」につながります。
そうすると、多少無理な交渉も通りやすくなります。

**恩は売れる時に売りまくりましょう。**

# そもそも人件費はコストじゃない

社内の人件費や業務委託の発注額のコストを「安ければ安い方がよい」と考える人がいると思いますが、実際はそんなことなく、人のコストは「安かろう悪かろう」が特に出やすいので、「安ければ適当な仕事をする」だけです。

以前海外の宝石店で警備員がいたのにも関わらず深夜に空き巣が発生した事件がありました。
原因は警備員がバックヤードの小窓からたまに様子を見る程度の警備しかしていなかったことだったのですが、「なぜしっかり警備しなかったのか」と質問されたときの返答が「そこまでするほど給料をもらってない」でした。

[イギリスで360億円の盗難！駆けつけた警備員の言い分が流石！！ - Togetter](https://togetter.com/li/806591)

業務委託なども同じで、値切って安い値段で発注した場合に、外注先では「この仕事安いから適当でいいよ」と言う話で動いています（体験談）。

なので人件費はコストではなく投資と考えるべきです。

安い投資では安い成果しか得られないだけです。

# つまり

全ての労働者は自分のため仲間のため給与を上げる努力をしましょう！
また、給与を支払う側の皆様は、会社の価値を高めるため、人件費に投資しましょう！
(リンクだけです)「面積分(英:Surface integral)」を調べた。

# wikipediaより

https://ja.wikipedia.org/wiki/%E9%9D%A2%E7%A9%8D%E5%88%86

https://en.wikipedia.org/wiki/Surface_integral

# MATHEMATICAで
？？？記号的なベクトル変数を使う．？？？
？？？あらゆる領域上で積分する．？？？
？？？標準領域上での積分。記号 ∈ は el または ∈ と入力する：？？？
？？？rintt を使ってテンプレート？？？

領域上の積分 ＜　Mathematica 10の新機能 › 記号幾何学 ›

https://www.wolfram.com/mathematica/new-in-10/symbolic-geometry/integrate-over-regions.html

https://reference.wolfram.com/language/ref/Integrate.html.ja?source=footer

https://www.wolfram.com/mathematica/new-in-10/symbolic-geometry/formula-regions.html.ja?footer=lang

# WolframAlphaで

https://www.google.com/search?q=WolframAlpha+Surface+integral&rlz=1CAUHAM_enJP1038JP1038&sxsrf=APwXEddC_Ko3wMPRJSlDdALJ69R_DHDrdg%3A1685510556030&ei=nNl2ZNbBAdym2roPkZGnsAM&ved=0ahUKEwjW_9OP6J7_AhVck1YBHZHICTYQ4dUDCA8&uact=5&oq=WolframAlpha+Surface+integral&gs_lcp=Cgxnd3Mtd2l6LXNlcnAQAzIFCAAQogQyBQgAEKIEMgUIABCiBDIFCAAQogQ6CggAEEcQ1gQQsAM6BggAEAcQHjoICAAQCBAHEB46CggAEAUQBxAeEA86CggAEAgQBxAeEA86BwgAEIoFEENKBAhBGABQyxlY40hgr1xoAXABeACAAZ4BiAHFBZIBAzAuNpgBAKABAaABAsABAcgBCg&sclient=gws-wiz-serp

# sympyで

https://www.google.com/search?q=sympy+Surface+integral&rlz=1CAUHAM_enJP1038JP1038&oq=sympy+Surface%E3%80%80integral&aqs=chrome..69i57.8911j0j7&sourceid=chrome&ie=UTF-8

# 教科書より
 
# 過去問

# 参考

https://qiita.com/naoya_ok/items/cb3bc2e212bde8a18b81
なるほどわからんDDD ~ドメインサービスとアプリケーションサービス~

## はじめに

本記事は、『ドメイン駆動設計(DDD)』について少し勉強し始めた筆者が学ぶ中で「わからん！」→「なるほど！」と思ったことを書いたものです。

間違っていたらそっと教えていただけると幸いです。

## サービスって二種類あるんですか

ある日のレビュー中に「これはDDDのアプリケーションサービスだから～……」という会話がありました。
その時は「なるほどアプリケーションのサービスね！」と思ったものの、
**「そういえば、サービスはドメインサービスとアプリケーションサービスの二種類あったよね？」** 
**「何が違うんだっけ……？」**

というわけで、ちょっと調べ直してみました。

## ドメインサービスとは

ドメインモデルの振る舞いはドメインモデルが持つべきです。
たとえばToDoリストアプリケーションが、ToDoタスクひとつひとつを表すToDoItemというドメインモデルを持っていたとします。

```C#
// ToDoリストに登録するToDoを表すクラス
public class ToDoItem
{
    // ToDoのID
    public string Id {get; set;}
    
    // ToDoの内容
    public string Content {get; set;}
    
    // ToDoのチェック状態
    public string IsChecked {get; set;}

    // ToDoの期限
    public DateTime DeadLine {get; set;}

    // ...

    // ToDoの期限をチェックするメソッド
    public bool CheckToDoDeadLine(){ // 期限が近いやつはtrueが返る}

    // ToDoの内容の重複を検証するメソッド
    public bool ValidateToDo(){// 他のToDoと内容を比較して被ってたらfalseが返る}

    // ToDoの内容が100字を超えないようにするメソッド
    public bool CheckContentLength(){ // 100字を超えていたらfalseを返す}

    // ToDoを保存するメソッド
    public void SaveToDo(){// DBにアクセスしたりするごちゃごちゃした処理が書いてある}
}

```
例えば、上記のうち`ValidateToDo()`メソッドは、他のToDoItemのインスタンスを見て重複のチェックを行うことになりそうですが、それはToDoItemとしてはいささか責務を持ちすぎ感があります。
また、`SaveToDo()`メソッドはこのクラスに書くと随分複雑になりそうです。
しかし、二つともこのドメインにおいては絶対に必要な振る舞いです。そういったときに**ドメインサービス**という、状態を持たないサービスとしてこれらを切り出すことができます。

ドメインの振る舞いの中で、ドメインオブジェクト自身に責務を持たせにくい(ほかのインスタンスの情報を利用するなど)振る舞いを実現することがドメインサービスの仕事になります。
なお、すべての振る舞いをドメインサービスとして切り出すのはNGです。
[以前の記事](https://qiita.com/kamikawa_m/items/16110d56a5ec964672f9)で、すべての振る舞いをドメインサービスとして切り出してしまった結果である『**ドメインモデル貧血症**』について書いています。

## アプリケーションサービスとは
アプリケーションサービスは、システムのユースケースを実現するためのサービスです。

例えば、先のToDoリストの例でいえば、
- ToDoを追加できる
- ToDoを削除できる
- ToDoを並べ替えられる
- ToDoを保存できる
- 完了したToDoにチェックを付けられる

...といったものがToDoリストのアプリケーションで実現したいユースケースになります。
これらをドメインのオブジェクトを利用しながら実現するのがアプリケーションサービスの仕事です。

このとき、アプリケーションサービスにドメインのルールが漏れ出さないようにする必要があります。
アプリケーションサービスはあくまでドメインオブジェクトを使ってユースケースを実現することのみを行い、ドメインのルールをアプリケーションサービス内で実現してはならないのです。
アプリケーションサービス内にドメインのルールを書いてしまうことで、コピーコード(変更時にバグの温床になる)が発生しやすくなります。
そもそもドメインオブジェクトがどう使われるかはわからないので、「こういう使い方をしてほしくないなあ」というルールはドメインオブジェクト側に存在するべきです。

## 同じ"サービス"だけど全然違う

ドメインサービスは、ビジネスロジックの中でドメインモデルに責務を負わせにくい振る舞いをサービスとして切り出したもので、言ってしまえばドメインの一部です。
一方アプリケーションサービスはアプリケーションのユースケースを実現するために存在するサービスであり、アプリケーションの目的を達成するために対象のドメインオブジェクトやドメインサービスを「利用する」サービスになります。
Next.jsで、useEffectを使って無限ループを回避する

#### この記事で分かること
- useStateを使った無限ループの原因
- useEffectの必要性


#### 対象
- react, next.js初心者

#### 環境
rocal環境にNext.jsを構築
test.jsを src/pages　ディレクトリ配下に作成
laravelで、テスト用に現時刻を返すapiを作成

## 本題

テスト用のapi

```
Route::get('/test', function () {
    return ['date' => now()];
});
```

非同期処理
```javascript
import React, { useState } from 'react';

export default function Test() {
  const [data, setData] = useState(null);

  // 無限ループの発生
  fetch('http://localhost:80/api/test')
    .then(response => response.json())
    .then((data) => {
        console.log(data.date);
        setData(data.date);
    });

  return (
    <div>
      {data ? data : "Loading..."}
    </div>
  );
}
```

consoleを見てみると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3091295/4e369fb8-184f-1799-0298-d387829be203.png)
無限ループが発生していますね。。

### 原因
無限ループが発生するのは、fetch関数　がコンポーネントの描画毎に呼び出され、setData によってコンポーネントの状態が更新され、それがさらなる再描画を引き起こすからです。再描画時に再度 fetch が呼び出され、無限ループが発生します。

### 解決法
無限ループを防ぐためには、useEffect フックを使うのが一般的です。useEffect フックは、コンポーネントのライフサイクルに関連する副作用（API リクエストなど）を処理するために React によって提供されています。

```
import { useState, useEffect } from 'react';

export default function Test() {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch('http://localhost:80/api/test')
      .then(response => response.json())
      .then((data) => {
          console.log(data.name);
          setData(data.name);
      });
  }, []); // 依存配列が空なので、この副作用はコンポーネントがマウントされたときにのみ実行されます

  return (
    <div>
      {data ? data : "Loading..."}
    </div>
  );
}
```

#### state 更新の回避
[react公式ドキュメント](https://ja.legacy.reactjs.org/docs/hooks-reference.html#bailing-out-of-a-state-update)によれば、「現在値と同じ値で更新を行った場合、React は子のレンダーや副作用の実行を回避して処理を終了します。」「更新の回避が起きる前に React により該当のコンポーネント自体はレンダーされるかもしれない、ということに注意してください。」と記述されていました。

今回のTest function　の例では、fetchで取得するdataの値が毎回変わるので、state の更新は回避されません。
もし、値が毎回変わらなければ、更新は回避され、無限ループは発生しませんでした。
しかし、同様のコードを src/pages/_app.js (全ページで呼び出されるコンポーネント) に配置したとき、無限ループが発生したので、どのディレクトリでも、推奨されるuseEffectの使用をするのが良いでしょう。
Node.js REST APIサーバーに対してReact HTTPサーバーでGET以外の通信がCORSで許可されなかった。

## TL;DR
expressの設定`app.all( '/*', function( req, res, next ){`の中身は、`res.setHeader( 'Access-Control-Allow-Origin', * );`だけでは足りなかった。以下を追加したらCORSのエラーが消えて正常に通信できた。
```javascript
  res.setHeader( 'Access-Control-Allow-Methods', '*' );
  res.setHeader( 'Access-Control-Allow-Headers', '*' );
```

## 経緯
PostgreSQLを用いたDBサーバーに対して、Node.jsでアプリケーションサーバー（DBへのAPIとユーザーへの表示を兼ねたサーバー）を作っていました。expressを用いたDBへのCRUDが完成し、UIにこだわりたくなったため、フロントエンドフレームワーク（React）を用いてリッチな表示を試そうとしました。アプリケーションサーバー側のUI機能を一旦止めて、REST APIサーバーとして扱わせることに。

## React側でAPIサーバーと通信したかった
React側でaxiosを用いてAPIリクエスト（GET）を送ってみるとデータは正しく取り出せた。

じゃあPOSTしてみよう。
適当にフォームを作ってaxiosでPOSTリクエストを書いて送ってみると…
```shell:ブラウザのエラー
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://127.0.0.1:2501/api/db/person. (Reason: CORS request did not succeed). Status code: (null).
```
CORSで許可されてないと怒られた。ん？？
CORS許可されてなかったらなんでGETはできるんだ？


```javascript:APIサーバー側expressの設定
setting_cors = *; // 分かりやすくするため環境変数の値を表示してます

api.all( '/*', function( req, res, next ){
  if( settings_cors ){
  res.setHeader( 'Access-Control-Allow-Origin', settings_cors );
  res.setHeader( 'Vary', 'Origin' );
  }
  next();
});
```

`res.setHeader( 'Access-Control-Allow-Origin', * );`としてあるからCORSの設定はできているはずでは！？！？（できていない）
試しにコメントアウトしてみると、ReactのGETが動かなくなるので、CORSの設定は効いているようだなぁ〜…。
axiosの書き方がおかしいのかなぁ〜とかReact側で色々やってたら時間が溶けてしまった(^^;;

## 結局
APIサーバー側expressに`res.setHeader`の中身が足りなかった…
以下の表記を追加することで正しく動作した。
`Access-Control-Allow-Headers`については不要かもしれない。
```javascript
  res.setHeader( 'Access-Control-Allow-Methods', '*' );
  res.setHeader( 'Access-Control-Allow-Headers', '*' );
```

## ついでに

内容とは関係ないが、CORSはブラウザ側の配慮であり、terminalなどからcurlでPOSTなどを直打ちする分には関係ない要素らしい。
【Mac】コマンドでMagic Trackpadのバッテリー残量を取得する方法

## 取得方法
次のコマンドを実行することでバッテリー残量を取得できます。

```zsh
ioreg -arl -c AppleDeviceManagementHIDEventService -k BatteryPercent -d 1 > /tmp/hid_info.plist && /usr/libexec/PlistBuddy -c "Print 0:Product"  -c "Print 0:BatteryPercent" /tmp/hid_info.plist 2>/dev/null
```

実行すると次のように出力されます。

```terminal
$ ioreg -arl -c AppleDeviceManagementHIDEventService -k BatteryPercent -d 1 > /tmp/hid_info.plist && /usr/libexec/PlistBuddy -c "Print 0:Product"  -c "Print 0:BatteryPercent" /tmp/hid_info.plist 2>/dev/null
Magic Trackpad
15
```