OmniAICreator/Qiita-1.07M huggingface dataset:
UIFlowでHTTP Requestを簡易的にテストする方法（httpbin.org/getを使用）

# 概要
UIFlowでHTTP Requestを下記を使って簡易的なテストをしました。
httpbinは自分でAPIサーバーを準備せずに試せるのでとても重宝しました。

>httpbin.org/get

# 動作フロー

M5StickC　Plus　のAボタンを押す
↓
httpbin.org/get　にパラメータを２つ送信（https://httpbin.org/get?param1=ABC&param2=DEF）
↓
httpbin.org/get　からレスポンスが返ってくる
↓
M5StickC　Plus　の画面に帰ってきた内容を表示する

# Code
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181708/99fa0b0c-3b6f-0ae0-22e9-c8d186b90d9b.png)

# ハマった点

httpbin.org/get
からは下記のようなレスポンスが返ってくるが、args内のparam1だけ切り取って表示する方法が分からず時間がかかりました。
```josn:qiita.json
{
  "args": {
    "param1": "ABC", ←★ここのデータが欲しい
    "param2": "DEF"
  }, 
  "headers": {
    "Accept-Encoding": "gzip, deflate, br", 
    "Accept-Language": "ja,en-US;q=0.9,en;q=0.8", 

```
結局、下記のような2段階で取得できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181708/41e440d2-c056-b869-d5c5-da1331991d38.png)

# 参考サイト
- [APIクライアント開発時のモックに使えるhttpbinの紹介](https://qiita.com/sameyasu/items/adacceb8a1bee893599b)
    - 詳しい説明がありとても分かりやすかったです
- [上記の「ハマった点」で参考にしたサイト](https://qiita.com/tatsuya1970/items/42d163e4512b2e01ed78)
    - このサイトではリストを使用していましたが、この方法ではうまくいかず、上記のような２つのMapでうまくいきました。
- [上記の「ハマった点」で困った時に、他の方法だとうまくいくのか確認に参考にしたサイト。ビットコインの金額を取得する方法](https://bluemon0919.hatenablog.com/entry/2021/02/14/140129)
)
【Python】pythonでwifi接続をしてみた。【pywifi】

### pywifiを使用する経緯
自宅回線に"レオネット"と"ソフトバンクエアー"を引いていおり、普段はソフトバンクエアーを利用してたまにレオネットを使います。
そんなたまにしか出番がないレオネットは90分インターネットにアクセスしないとIPアドレスが払い出されなくなり、ネットワークから切り離れてしまいます。
対処法としてルータのNTPを60分おきに取得する方法があるのですが、設定してもなぜか毎回パスワードをも止められ始末。。。
そこでラズパイのログローテーションで毎分インターネットにアクセスしようと考えましたが、普段はソフトバンクエアーに繋いでいるため、一度レオネットに繋いでからインターネットにアクセスしないといけません。
しかし、レオネットに自動で接続するにはどうすれば。。。

そこで登場しますのがpythonモジュールの"pywifi"です。

>pywifiはPythonでWi-Fiを操作するためのライブラリで、Wi-Fiのスキャン、接続、切断などを行うことができます。

### インストール

以下コマンドでインストールしてください。
```python
pip install pywifi
```
### 作成コード

以下に作成したコードを記載します。
```python
import time
import pywifi
from pywifi import const


wifi = pywifi.PyWiFi()  # pywifiオブジェクトのPyWiFi属性を参照する。
iface = wifi.interfaces()[0]    # コンピューターに接続されているWi-Fiインターフェースのリストを返す。
Name = iface.name() # 取得したWi-Fiインターフェースの名前を取得する。

#profileの作成
profile = pywifi.Profile()
profile.ssid = 'xxx'
profile.auth = const.AUTH_ALG_OPEN
profile.akm.append(const.AKM_TYPE_WPA2PSK)
profile.cipher = const.CIPHER_TYPE_CCMP
profile.key = 'xxx'  
 
iface.remove_all_network_profiles() #Wi-Fiインターフェースからすべてのネットワークプロファイルを削除するための関数。
tmp_profile = iface.add_network_profile(profile)    #Wi-Fiインターフェースに新しいネットワークプロファイルを追加するための関数。
iface.connect(tmp_profile)  #インターネットに接続する。

#"接続成功""接続失敗"の表示。
time.sleep(1)
if iface.status() == const.IFACE_CONNECTED:
    print('接続成功')
else:
    print('接続失敗')
```

### コード解説

xxxは各自の環境にあった値を入力してください。

暗号化方式がAESの場合は以下コードとなります。
```python
profile.cipher = const.CIPHER_TYPE_CCMP
```
レオネットの暗号化方式がAESと表示されいましたが、pywifiのドキュメントをみてもAESの記載がないのでAESは対応していないのか？？
と焦りましたが、実際はそうではなくAESは暗号化アルゴリズムであって、CCMPはAESを用いた暗号化方式なんですよね。
なのでイメージは”AES＝CCMP”でOKです。

以下サイトがとても参考になりました。
[無線LANの暗号化方式について整理してみた](https://security.nekotricolor.com/entry/difference-in-wireless-lan-protocol-wep-wpa-wpa2-tkip-ccmp-aes)

参照先
[pywifi github](https://github.com/awkman/pywifi)
ペンテスト/バグバウンティハンターによって使われているFirefox拡張機能トップ14。

1. FoxyProxy Standard
FoxyProxyは、Firefoxの限られたプロキシ機能を完全に置き換える、高度なプロキシ管理ツールです。

2. Firefox Multi-Account Containers
Multi-Account Containersはあなたのオンラインライフの一部を色分けされたタブに分離し、プライバシーを保護することができます。
Containers+authorize = 壊れたアクセスコントロールのバグ! 

3. PwnFox
PwnFoxはセキュリティ監査ツールです。
機能: 
    - シングルクリックでBurpProxy
    - コンテナ・プロファイル
    - ツールボックスインジェクション
    - セキュリティヘッダーリムーバ

4. FoxyProxy + Containers = pwnfox

5. HackTools
Hacktoolsは、Webアプリケーションの侵入テストを容易にするWeb拡張機能で、XSSペイロードやリバースシェルなど、テスト中に使用するすべてのツールと同様にチートシートが含まれています。

6. Wappalyzer
Webサイトで使われている技術を特定します。

7. Shodan
Shodanプラグインは、ウェブサイトがどこでホストされているか（国、都市）、誰がIPを所有しているか、どのような他のサービス/ポートが開かれているかを教えてくれます。

8. DotGit
訪問したウェブサイトで.gitが公開されているかどうかをチェックするための拡張機能です。

9. Open Multiple URLS
URLのリストを開きます

10. Cookie-Editor
Cookie-Editorは、現在のタブのCookieを効率的に作成、編集、削除することができます。開発、迅速なテスト、あるいはプライバシーのために手動でクッキーを管理するのに最適なツールです。

11. S3 Bucket List
ブラウジング中にAmazon S3バケットを検索し、アドオンコンテンツに記録します。

12. Hackbar
機能:
    - アドレスバーからURLの読み込み、分割、実行ができます。
    - リファラーURL、ユーザーエージェント、クッキーのカスタム/追加。
    - ツール: md5, sha1, sha256, rot13 暗号化, url, baseb4 エンコーディング, json 正規化, sql, XSS features.

13. Hunter
Web上の任意の場所から、1クリックでメールアドレスを検索します。

14. Modify Header Value
任意のドメインの任意の要求のヘッダーを追加、変更、または削除します。
Dockerのapacheにcomposerを追加した時のメモ

# はじめに
私はphpのプログラマです。インフラの知識はありません。
そんな自分がDocker環境をいじってみたところ、composerがなかったので追加してみたら大変にハマりました。なのでメモしておく。

# DockerFileにコレを書けばおk

```
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
```

# なぜハマったのか
apacheで立てていたのに、
nginxの環境でcomposerを追加する記事を見てそのままコピペしたのが敗因。

# DockeFileをいじったあとは
```
# コレを叩く。コレしないと編集した部分が反映されない。
docker-compose up -d --build
```

# 最後に
読んでくださりありがとうございました。
Dockerどころかインフラが解らないとつまづいてばかりで嫌になります。
けど、少しずつでも、1つずつ解決はできるはず。
世の中の頭の良い人、努力家の人が残してくれたブログやQiitaの記事を読んで助けられたことが多かったので、これからもたまにこういうメモを残そうと思います。
Salescloud Consultant 学習メモ④

<h3>商談の収益分割</h3>
１つの商談に関連するメンバーで収益を分ける機能
<h5>収益分割</h5>
商談の100%金額に対して分割する

<h5>オーバーレイ分割

任意のパーセントで分割する

<h3>商談チーム</h3>
商談に関わるメンバーを管理する機能

<h3>注文</h3>
サービスを提供したり、商品を納入したりするための会社と顧客間の契約

※ 注文を有効化するためには、注文商品が必要
※注文を修正するためには、ドラフト状態（有効化する前の段階）になる必要

<削減注文の作成方法＞
①削減注文レコードを作成
②削減したい注文を登録

<h3>取引先と取引先責任者の関係</h3>
<h5>取引先の役割</h5>
取引先を紐づけるできるのは、Classicのみ

<h5>取引先責任者-to-複数取引先
　

１人の取引先責任者を複数の取引先に関連することができる機能
LEX版の「取引先責任者の役割」


<h3>個人取引先</h3>
１名に限定された顧客を登録するオブジェクト

取引先or取引先責任者オブジェクトからアクセス

<h3>重複データを特定する方法</h3>
・重複管理の「一致ルール」で定義

<h3>重複データをマージする方法</h3>
・重複が発生しているレコードに表示されるメッセージからマージ
サイクロマティック複雑度について調べてみた

こんにちは。最近よくソフトウェアの品質の改善について考えています。
@Esperna です。今回はサイクロマティック複雑度について書きます。

# 背景

ソフトウェアの品質を改善しようと思った時にソフトウェアの品質を改善するにも、
そもそもソフトウェアの品質の定義って何なのだろうと思いました。
定性的にはコードにバグが多い・少ないとか、コードの読みにくい・読み易いとか？
定量的にはソフトウェアメトリクスとか？
ソフトウェアメトリクスにはサイクロマティック複雑度、SLOC、関数のネストの深さなどがあるかなと思うのですが、Microsoftが言及している[Maintainability Index](https://learn.microsoft.com/ja-jp/visualstudio/code-quality/code-metrics-maintainability-index-range-and-meaning?view=vs-2019)というものがよく使われているようです。

```
Maintainability Index = 171 - 5.2 * ln(Halstead Volume) - 0.23 * (Cyclomatic Complexity) - 16.2 * ln(Lines of Code)
```
これは式だけ見ると小難しく見えるのですが、対数取ってるのは
スケール調整してるだけと思われるのと、
細かい係数も重み付けのための係数と思われるのでそちらはあまり気にせず。

Maintainability Index(保守容易性指数)というのは

* Halstead Volumeが増えると下がる(減ると上がる)
* Cyclomatic Complexity(サイクロマティック複雑度)が増えると下がる(減ると上がる)
* SLOC(コード行数)が増えると下がる(減ると上がる)

と言っていると理解しました。
となると、Halstead VolumeとCyclomatic Complexity(サイクロマティック複雑度)が分かれば
Maintainability Index(保守容易性指数)を完全理解できる！
というわけで、まずはCyclomatic Complexity(サイクロマティック複雑度)をググりました。

# サイクロマティック複雑度

結論から言うと、実用上はコードの分岐の数（分岐網羅数）に1を足したものと理解するのが良さそうです。

[循環複雑度の定義](https://ja.wikipedia.org/wiki/%E5%BE%AA%E7%92%B0%E7%9A%84%E8%A4%87%E9%9B%91%E5%BA%A6)によると、

```
M = E − N + 2P
ここで
M = 循環的複雑度
E = グラフのエッジ数
N = グラフのノード数
P = 連結成分の個数
```

グラフ、エッジ、ノード、連結成分の定義が分からないので調べてみると、グラフ理論で定義される用語らしいです。

* ノード：頂点(下図で言うところの○)
* エッジ：ノードをつなぐ線(下図で言うところの-)
* グラフ：ノードとエッジの集合
* 連結成分：部分グラフのうち極大で連結なもの。関数の場合、連結成分の数は1。

![graph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244232/bf120e30-f52e-0bf2-49f6-9b15a117eec6.png)

仮に下記のような処理を行うコードがあった場合に

```c
if (isXXXEnable) {
    //trueの場合の処理
} else {
    //falseの場合の処理
}

if (isYYYEnable) {
    //trueの場合の処理
} else {
    //falseの場合の処理
}
```

グラフにしてみると以下の通りで

![graph2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244232/68ab5bef-e9d2-44f8-2ef5-992a2e38595e.png)

```
E(グラフのエッジの数) = 8
N(グラフのノードの数) = 7
P(連結成分の数) = 1
```
なので、
```
M = E - N + 2P
  = 8 - 7 + 2
  = 3
```
この M = 3というのは分岐網羅数2より大きく経路網羅数4より小さいです。
結局サイクロマティック複雑度Mは何者かというと、コードの分岐の数（分岐網羅数）に1を足したものということになリます。なお、Halstead Volumeはプログラム全体をビット配列で表現したときの長さだそうです(参考資料参照)。

# 所感

* サイクロマティック複雑度が上がると、分岐の数が増えて、Maintainabilityが下がりますよねということだと理解しました。
* 調べていくうちに [保守容易性指数(Maintainability Idex)の計算方法を理解する](https://qiita.com/AngryMane/items/4d5d1238405e66374aa6)という記事が書かれていることを知り、車輪の再発明だったなと。でも、自身の理解を深める目的で書いていたのでそれでもいいかなと思いました。
* 行数が長く、分岐の数が多く、プログラム全体をビット配列で表現したときの長さが長いコードはMaintainabilityが悪いということですね。
* 上記のMaintainabilityの意味を踏まえると、当たり前ですが追加実装を行えばリファクタリングしたとしてもMaintainabilityは下がることが多そうですね（まさにコード負債だなと思いました）。

# 参考資料

* [コード メトリック - 保守容易性指数の範囲と意味](https://learn.microsoft.com/ja-jp/visualstudio/code-quality/code-metrics-maintainability-index-range-and-meaning?view=vs-2019)
* [保守容易性指数(Maintainability Idex)の計算方法を理解する](https://qiita.com/AngryMane/items/4d5d1238405e66374aa6)
* [グラフ理論](https://ja.wikipedia.org/wiki/%E3%82%B0%E3%83%A9%E3%83%95%E7%90%86%E8%AB%96)
* [循環的複雑度](https://ja.wikipedia.org/wiki/%E5%BE%AA%E7%92%B0%E7%9A%84%E8%A4%87%E9%9B%91%E5%BA%A6)
ESP32-CAMでラジコンを作った時の回路

やっとESP32-CAMでラジコンが完成しました。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ひとまず完成<br>カメラ見ながら動かすの楽しい！！<br>カメラに合わせて画角を変えられるようにコントローラーを改修<br>なんとか手のひらサイズに収まった<a href="https://twitter.com/hashtag/esp32?src=hash&amp;ref_src=twsrc%5Etfw">#esp32</a> <a href="https://twitter.com/hashtag/Kotlin?src=hash&amp;ref_src=twsrc%5Etfw">#Kotlin</a> <a href="https://twitter.com/hashtag/%E3%83%A9%E3%82%B8%E3%82%B3%E3%83%B3?src=hash&amp;ref_src=twsrc%5Etfw">#ラジコン</a><a href="https://twitter.com/hashtag/%E3%83%9E%E3%82%A4%E3%82%B3%E3%83%B3?src=hash&amp;ref_src=twsrc%5Etfw">#マイコン</a> <a href="https://t.co/TiCrpCU5v2">pic.twitter.com/TiCrpCU5v2</a></p>&mdash; 亀吉 (@by2aE1WOPoBdfLo) <a href="https://twitter.com/by2aE1WOPoBdfLo/status/1617532052706033666?ref_src=twsrc%5Etfw">January 23, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
その時の回路をFritzingで作成したので公開します。

回路図描くのにこんな便利なものがあるとは知らなかった。
![TANK_回路図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1852162/d0a43501-6149-0efd-6b62-ce0b11cb2693.png)
リポバッテリーは3.7V
DC/DCコンバータで5Vに昇圧してESP32-CAMを動かしてます。
映像にノイズは入りますが、操作する分には問題ない程度です。
モータードライバのSTBYにESP32-CAMのVCCをつなげているため、起動直後、GPIOが0出力されるまでモーターが動く点に注意。

使用したモジュール群のリンクは以下

・DC/DCコンバータ
https://www.amazon.co.jp/gp/product/B07N8TBJB3/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&psc=1

・モータードライバ
https://www.amazon.co.jp/gp/product/B098Q24ZV9/ref=ppx_yo_dt_b_asin_title_o01_s00?ie=UTF8&psc=1
初めてのPython、じゃんけんゲーム

こんにちはkmdと申します。

初投稿になります。
タイトル通り今回はPythonで簡単なじゃんけんのプログラムを組みました。
私は普段ネットワークの畑にいるためプログラムについてほぼ全くの無知です…

自動化やRPAを最近職場で見ることがあり、私も興味を持ったためプログラミングへ挑戦することにしました。
Udemyで少し勉強して基本的な？もので書けたと思います。

今回はさわり程度でアルゴリズムを理解するのに苦労しました。


```janken.py
import random

print('じゃんけんをします。 手を選んでね  \n')

global human
global com

def nyuryoku():
    global human
    human = int(input('1:グー 2:チョキ 3:パー \n ---> '))
    if human not in [1, 2, 3]:
        print('1か2か3を入力してください')
        nyuryoku()
    else:
        janken()

def janken():
    global com
    com = random.randint(0, 2) + 1
    if human == com:
        print('引き分けです。もう一度選んでね！ \n ')
        nyuryoku()
    elif human == 1 and com == 2:
        print('あなたの勝ち')
    elif human == 2 and com == 3:
        print('あなたの勝ち')
    elif human == 3 and com == 1:
        print('あなたの勝ち')
    else:
        print('あなたの負けです')

nyuryoku()

```
１つ目反省点としては、変数をもう少しうまく設定できたんじゃないかな…って 
def内だとローカル変数ってのになるらしくて、結構悩みました。
global変数というものにすることでいろいろ行けるらしいので使ってみました。
global変数はなんだかよくなさそうな気がします。

２つ目の反省点は再起処理がなんだか美しくない気がします。
これに関してはそんな気がするって感じです…
ちょっと例外処理まで考えられなかったので今度は例外処理にも気を使って書いてみます。
文字型とか数字型とかあんまわからない…

プログラミングってどんな書き方が美しいのかわからないので、何か改善点があれば教えてくれたらうれしいです！

以上になります！
【Linux】コマンドで特定の文字列を含む行以降を削除する方法

## はじめに

以下のファイルから「ここまで」という文字列までの内容を残しそれより後の文字列は削除する方法について記載します。  

```sample.txt
あああああ
いいいいい
ううううう
えええええ
おおおおお
ここまで
aaaaa
bbbbb
ccccc
ddddd
eeeee

```

## 削除方法

`sed`コマンドを使用して次のように実行することで特定の文字列より後の行を削除できます。  

```
sed -i "/文字列/q" ファイルパス
```

```terminal
$ sed -i "/ここまで/q" sample.txt 
$ cat sample.txt
あああああ
いいいいい
ううううう
えええええ
おおおおお
ここまで
```

なお「ここまで」も含めて削除する場合には以下のように実行します。  

```
sed -i '/文字列/,$d' ファイルパス
```

```terminal
$ sed -i '/ここまで/,$d' sample.txt
$ cat sample.txt
あああああ
いいいいい
ううううう
えええええ
おおおおお
```
クラシックマウス　作ってみた　その2 　Arduino, ステッピングモーター

# はじめに
* 作成したクラシックマウスの各パーツの解説。
* 今回は「ステッピングモーター」と「Arduino　Uno」。

# ステッピングモーター
* KH39EM2-801: ユニポーラ、ステップ角1.8°、電圧 5.6V、39mm角、厚さ20.8mm
    * 過去の大会で使用実績があるのと、厚みが薄いので選んでみた。トルク等は正直よくわからないまま選んでます。
    * Arduinoではユニポーラ用のライブラリが使えるので、ユニポーラを選んでいます。
    * たまたまオークションで安く入手できましたが、品薄なのかも。代替としてはなるべく小さい（薄い）ものが良い気がします。作例の多い28BYJ-48でも動きますが、スピードはかなり遅いです。
    * 2個のステッピングモーターを、モーター軸を合わせて両面テープやガムテープで固定しています。間に薄い板（プリント基板）をはさんで、距離センサーの土台にしていますが、ここら辺はお好みで。
* ドライバ: ULN2803AN、8chトランジスタアレイ
    * ArduinoではULN2003の作例が多いのですが、ULN2003は7CH。モーター1個に4CH必要なので、2個必要になります。2803は8CHなので、１個で済みます。
* 接続
    |Arduino|2803|2803|KH39|
    |:-:|:-:|:-:|:-:|
    |D2|1 |18 |左橙11   |
    |D3|2 |17 |左茶5   |
    |D4|3 |16 |左黄7   |
    |D5|4 |15 |左黒1   |
    |D6|5 |14 |右黒1   |
    |D7|6 |13 |右黄7   |
    |D8|7 |12 |右茶5   |
    |D9|8 |11 |右橙11   |
    |GND|9 |10 |7.4V+左右赤3青9   |
    * ULN2803の10番ピンにはモーター駆動用の電源を接続し、モーターの赤・青も接続します。
    * 電圧はリチウムイオン電池（直列）を降圧せずそのまま接続しています。特に問題は起きていません。
    

* ライブラリ
    * Unistep2を使っています。左右両輪を同時に動かすライブラリはこれしか見つからなかったので。本来は自分でPWMで操作すべきですが…
    * 上記の接続に合わせた設定は以下の通り。右と左では逆の回転になるようにしている。
    * 直進する場合の関数runxy()をこんな感じで書いています。
    * 本モーターはステップ角1.8°なので、200Stepで1回転のようだが、本ライブラリはハーフStepを用いているようで、400Stepで1回転と設定している。
    * Step Delay は2500で1回転/秒となる（400*2500μs = 1s)。本モーターは1000ぐらいまでは動きますが、加減速を考慮して使用しています。

```
#include "Unistep2.h"
// Define some steppers and the pins they will use
const int st_l=2500; //StepDelay 
Unistep2 stepperX(2, 3, 4, 5, 400, st_l); // 左　pins for IN1, IN2, IN3, IN4, steps per rev, step delay(in micros)
Unistep2 stepperY(6, 7, 8, 9, 400, st_l); //右　cross connection
```
```
void runxy(int steps, int st_delay){
 Unistep2 stepperX(2, 3, 4, 5, 400, st_delay);
 Unistep2 stepperY(6, 7, 8, 9, 400, st_delay); 
 stepperX.move(steps); 
 stepperY.move(steps);
 while(stepperX.stepsToGo()!=0){
 stepperY.run();
 stepperX.run();
 }
}
```
# マイコン　Arduino Uno
* マイコンはArduino Unoの互換品を利用。プロトタイプシールドを挿して、その上にミニブレッドボードを乗せて利用しています。
* スケッチが大きく（93％）、メモリが少ない旨の警告がでます。特に問題は起きていませんが、もう少し余裕のあるマイコンの方が良いかもしれません。
* 給電は、リチウムイオン電池（直列）からV-in端子に給電しています。

以上
Pythonでほぼ日手帳形式のmarkdownメモ帳を作ろう(1年分)

# 概要

私は1年に1度markdown形式のメモ用ファイルをたくさん作っている。これを日常のあらゆるメモとして使用している。自動生成するためのコードを書き直したので忘れないように記録しておく。

### 作るもの

以下のような構成のmarkdownファイルを作る。

```
.
└── 2023
    ├── 1
    │   ├ 2-8.md
    │   ├ 9-15.md
    │   ├ 16-22.md
    │   ├ 23-29.md
    │   └ 30-5.md
    └── 2
    │   ├ 6-12.md
    │   ├ ...
    │   ... 
    │    
    └── 3
    └── 4
    └── ...
```

生成時点でファイルごとに以下のような内容を書いておく。

```markdown
# 1/2 (月)

# 1/3 (火)

# 1/4 (水)

# 1/5 (木)

# 1/6 (金)

# 1/7 (土)

# 1/8 (日)

# メモ



```

それぞれの日付が書かれた段落内には、「その日の予定」「その日のメモ」「日々の振り返り」等好きなことを書く。メモを書く場所に迷ったらその日付にひとまず記載しておく。だいたい[ほぼ日手帳](https://www.1101.com/store/techo/)として使う。

```markdown: 使用例
# 2/2 (木)

* 19:00より○○と会う
* 燃えるゴミ出すこと

## タスク1

#### サブタスク
* ...
* ...

## 読書記録

...

```

1週間ごとに1ファイルとしている。スケールを大きくしすぎると(1年で1ファイルとか)だんだん散らかってくるし、あまりスケールが小さくても(1日ごとに1ファイルとか)不便なので1週間区切りとしている。

## Pythonで作ろう

### 使うもの

#### `open`
ファイル書くやつ。```with```を使うとcloseの手間が省けて便利。
```py
with open("dir/filename", "w", encoding="utf-8") as f:
    f.write("hello, world!\n")
```
日本語を書く時は```encoding="utf-8"```を指定しておこう
#### `os`モジュール

ディレクトリを作る時に使うやつ。
```py
import os

dir = "src/1/2/"
os.makedirs(dir, exist_ok=True)
```
```os.makedirs```なら深い階層まで一気に生成できる。また、```exist_ok=True```オプションを付けることですでにそのディレクトリが存在してもエラーを吐かなくなる。

#### ```datetime.date```モジュール

日付操作に使う。
```py
import datetime

date_newyear = datetime.date.fromisoformat('2023-01-01')
date_today = datetime.date.today()
date_tommorow = date_today + datetime.timedelta(days=1)
```

## コード全文

```py
import os
import datetime

date = datetime.date.fromisoformat('2023-01-02')

while date.year == 2023:
    dir = f"{date.year}/{date.month}"
    os.makedirs(dir, exist_ok=True)
    date_weekend = date + datetime.timedelta(days=6)
    weekday = ["月", "火", "水", "木", "金", "土", "日"]
    with open(f"{dir}/{date.day}-{date_weekend.day}.md", "w", encoding="utf-8") as f:
        for i in range(7):
            f.write(f"# {date.month}/{date.day} ({weekday[i]})\n\n")
            date += datetime.timedelta(days=1)
        f.write("# メモ\n\n")
```

以上です。
PIVをやってみる．part 2 直接相互相関法で作成

# はじめに
part 1で無料のOpenPIVを試してみたが方向の反転に気をつければ使えそうに感じた．ソースコードを変更するには時間を要する．更なる理解のために自分でPIVのプログラムを作成することを検討した．今回はPIVの原理に近く精度が高いと言われている直接相互相関法を試す．

# 直接相互相関法
計測時間が前の画像を第1画像，後の画像を第2画像とする．画像を一定のサイズに区切って第1画像の探査領域を設定して，この輝度分布のパターンが第2画像のどこに一致するか調べる方法である．画像全体で相互相関を調べると計算に時間がかかるため，探査領域の近傍だけ相互相関を調べる．相互相関係数の分布からピークを移動量として，これを各探査領域で計算して速度分布を求める．

# プログラムの作成，結果
OpenPIVと比較するために前回と同様に画像は[PIVChallenge](https://www.pivchallenge.org/)のから1st PIV Challenge (Sept.14-15, 2001, Göttingen, Germany) のCase 3: medium particle density and small particle を使用した．相関係数はOpenCVの関数（cv2.matchTemplate）を利用して，第1画像と第2画像を適宜トリミングして利用した．類似度は正規化相互相関 (normalized cross-correlation) で計算した．img_b_trimはimg_a_trimよりも大きく設定して，大きすぎると計算量が多くなり遅いので，粒子の移動量を考えて設定する．

```Python
results = cv2.matchTemplate(img_b_trim, img_a_trim, cv2.TM_CCORR_NORMED)
```

![B003_1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3121335/c005eace-1c01-2806-17c4-5960b6e453f3.gif)

自作のプログラムでは渦が計測できており，うまくいっている気がする．ただ一対の画像の計算に6秒程度かかるため，高速度カメラ等で画像を撮影すると1万枚以上のデータになるため，解析に半日以上かかってしまう．実際には出力した結果を見ながらパラメーター調整が必要で実用には耐えない．そのため，今後は並列化するなどして高速化をするかもう一つのFFT相互相関法を試してみる．

![Figure_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3121335/7ad17fb2-843a-482d-c552-5870a98974f0.png)

# 終わりに
OpenPIVが上手くいかなかったため自分で直接相互相関法のプログラムを作成した．OpenCVを用いて相互相関係数を求めてPIVをしたが，渦を計測できていて上手くいったが速度は遅かった．次回はFFT相互相関法を試したい．

# 参考
PIVハンドブック，可視化情報学会
[OpenCV-Python Tutorials 1 documentation » OpenCV-Pythonチュートリアル » OpenCVを使った画像処理 »](http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_imgproc/py_template_matching/py_template_matching.html)
[OpenCV – cv2.matchTemplate でテンプレートマッチングを行う方法](https://pystyle.info/opencv-template-matching/)
QiitaにGoogleアナリティクスのトラッキングIDを登録してみようと思ったらすぐに躓いた件



:::note warn
Googleアナリティクスとはなんぞや、などで調べて来ていただいた方には大変申し訳無いが、この記事は大変ニッチな道標とテストであるため、恐らく得るものは何もありません。
:::
:::note info
「戻るボタン」か「ALT+←」もしくは「閉じるボタン」か「ALT+F4」または「option + command + W」などを利用してご退室ください。
:::

# Qiitaにユーザ登録した
Qiitaはいつも見るだけのサイト。ログインできるようになったらもっと使いやすくなるのかな？と考えて、GoogleアカウントでQiitaにユーザ登録してみた。

## ユーザ登録したら何ができるのだろう？
設定画面を眺めていたら「GoogleアナリティクスのトラッキングIDを登録」することができるようなので登録を試みた。

### 眺めていた Qiita の Googleアナリティクス設定ページ
https://qiita.com/settings/analytics

設定ページにはご丁寧に「詳しくは設定手順の解説記事をご覧ください。」とあり、勧められた解説記事を読み進めながらやればきっと出来るだろうと思ったのだが・・

https://qiita.com/Qiita/items/c7f704e3786df3aa7a11

## Googleアナリティクスに登録
### 公式のヘルプがあれば無敵だろ、と思っていた
1. (事前準備)Googleのアカウントを持っていない場合は作る
2. 新しいアカウントを作る

ここでまず迷子になった。

> ログインしたら、Googleアナリティクス へアクセスし、「無料で設定」リンクよりアカウントを作成してください。

とあるが、案内されたURLで表示されるページには「無料で設定」というリンクはなかった。そりゃ、GoogleアナリティクスのページはQiitaに許可なく更新するし連絡もよこさないよね。

Qiitaも別のサイトのどんな記事でも情報が古いとぶち当たる「調べ物あるある」なのだが、公式が案内する公式ページでこうなると不安は増大する。

仕方がないので、表示された押せそうなボタン「測定を開始」を押すことにした。

### 通貨を入力するところでまた不安になった

解説記事の通りに入力していくと国と通貨を選択させられた。やっぱり無料じゃないところに来ちゃったのかな、とまた不安になった。

この不安が次の失敗を招いた。

> 詳細オプションを表示をクリックし、ユニバーサル アナリティクス プロパティの作成を有効にします。
ウェブサイトのURLに「 https://qiita.com 」を入力し、ユニバーサル アナリティクスのプロパティのみを作成するを選択します。
ビジネスの概要を入力し、作成は完了です。

これを見落としてしまった。

さっさと次へ進んでしまった自分を待っていたのはログイン後のアナリティクスホーム画面だった。あとから見直して見落としに気づいたときにはもう遅い。どこで何を選べば同じことが出来るのだろう？わからなくなった。

あちこちいじってみたが同じ言葉を見つけることは出来なかった。

## Googleアナリティクスに登録(二度目)

### もう一度やり直せたら？と藁をも掴む思いで再チャレンジ

もう一度同じことをやってみようと、ダメ元でログアウトしてログインしてやりなおした。すると何故かうまく行った。

> 詳細オプションを表示をクリックし、ユニバーサル アナリティクス プロパティの作成を有効にします。
ウェブサイトのURLに「 https://qiita.com 」を入力し、ユニバーサル アナリティクスのプロパティのみを作成するを選択します。
ビジネスの概要を入力し、作成は完了です。

これがうまく行ったのだ。

どうやら、当初ログインしていたGoogleアカウントがQiitaと連動したものではなく別の目的で作ったアカウントだったため、今回改めてログインしたQiita用のアカウントはGoogleアナリティクスには未登録だった。不幸中の幸い…というかただの手違いである。

## で、この記事は何だったのか

Googleアナリティクスに登録してQiitaの設定画面に入力して動きを見たかっただけである。だが、記事がないと機能しないらしい。記事を書くつもりがなかったので、自分の使い方では設定を追加しても意味がないことに終わってから気がついた。それならば仕方あるまいと、腹を括ってこれまでの経緯をチラシの裏レベルの日記で書くことにした。

QiitaとGoogleアナリティクスを連携したいと思った人が、例の場所で迷ったり不安にならず、焦って手違いを起こさなければ幸いである。
この後、まずやるべきことは記念すべき第一記事目をQiitaに投稿することだ。

上記文章を打ってから二度「Qiitaに投稿」の緑のボタンを押下してようやく気づいたのだが、記事にはタグを追加しなければならなかったらしい。本当に初めてでわからないことしかない。とりあえず、思いつきで3つ付けておいた。

[初心者](https://qiita.com/tags/%e5%88%9d%e5%bf%83%e8%80%85)
[Googleアナリティクス](https://qiita.com/tags/google%e3%82%a2%e3%83%8a%e3%83%aa%e3%83%86%e3%82%a3%e3%82%af%e3%82%b9)  
[同じ轍を踏むなかれ](https://qiita.com/tags/%e5%90%8c%e3%81%98%e8%bd%8d%e3%82%92%e8%b8%8f%e3%82%80%e3%81%aa%e3%81%8b%e3%82%8c)

# 追記

## Googleアナリティクスの管理画面を開くと注意書きが表示された

> このプロパティでは 2023 年 7 月 1 日にデータの処理が停止されます。2023 年 3 月以降もウェブサイトの測定を継続するには、新しい Google アナリティクス 4（GA4）プロパティを作成する必要があります。作成しない場合、元のプロパティに基づき、既存のサイトタグを再利用して GA4 プロパティが作成されます。

[GA4 への移行を管理する] を押すと「Google アナリティクス 4 プロパティの設定アシスタント」画面が開いた。

どうやら先程踏んだ手順で作成したGoogleアナリティクスの設定は古いらしく、新しい設定にしないと良しなにやっとくけど自分でやりたいなら今のうちやっておけということのようだ。また彷徨う事になろうとは。

[GA4の詳細](https://support.google.com/analytics/answer/9744165)

まぁとりあえず、放っておくとする。
SQLを学習する前に知っておきたい、データベースに関する必要最小限の基礎知識

# はじめに
今回はSQLの学習する前に、必要最低限のデータベースに関する知識を簡単にまとめました。
最後までご覧いただけると幸いです！

# データベースとは？
データベース(以後、DB)とは、テキストや数値などの<b>データを保存するための保管庫</b>のようなものです。
例えば、twitterでのツイートした文、画像、動画はDBに保存されています。
その他にも、Googleアカウント作成時に入力した個人情報、銀行に登録した個人情報...等々も全てDBに保存されています。
このようにデータベースに保存することによって、いつでも簡単にデータを取り出すことができます。

# テーブル・カラム・レコード

DBは様々な種類がありますが、現在は表で保存することがほとんどです。
表で保存することを「<b>リレーショナルデータベース(RDB)</b>」と呼びます。
RDBで保存するにあたって覚える用語「テーブル」「カラム」「レコード」を説明します。

<h3>テーブル

|id          |name           |age           |
|:----------:|:-------------:|:------------:|
|1|かいと|22|  
|2|あゆみ|31|
|3|ノブヨ|81|

↑この表を「<b>テーブル</b>」と呼びます。

<h3>カラム

|age|
|:---:|
|22|
|31|
|81|

表の縦の部分を「<b>カラム</b>」と呼びます。
また、一番上に表示されている「age」は「<b>カラム名</b>」です。
（元のテーブルでいう「id」「name」もカラム名です)

<h3>レコード

|2|あゆみ|31|
|:---:|:---:|:---:|

表の横の部分を「<b>レコード</b>」とよびます。
ここに１行分のデータを保存しています。

これら３つの用語は、SQLを学習するにあたって理解が必要になる言葉となります。

# 最後に
今回はデータベースに関して簡単にですが、説明してみました。
してみたはいいものの説明不十分の部分があるかもしれないです。そこはすみません。。。
もし、こんな説明文が追加されたらもっと分かりやすいよ!
こんな言い回し、表現だともっと伝わりやすくなるよ！　などなど...
ご指摘ございましたらコメントにお願いいたしますm<__>m
Glue JobのJDBC経由のデータソースにWHERE句を付与

Glue Jobでデータソースから一部のデータだけを処理したく、JDBC経由のアクセスにWHERE句を付与する方法です。

DynamicFrameではできなさそうで、DataFrameを使います。

DataFrameで接続するときにはJDBCでの接続情報を明示的に指定する必要があるようで、 `glueContext.extract_jdbc_conf` を利用してGlue Connectionから情報を取得しています。

```python
from pyspark.context import SparkContext
from awsglue.context import GlueContext
from awsglue.dynamicframe import DynamicFrame

sparcContext = SparkContext()
glueContext = GlueContext(sparcContext)
logger = glueContext.get_logger()
sparkSession = glueContext.spark_session

CONNECTION_NAME = "test-connection" # Glue Connectionの名前
DB_NAME = "testdb" # 接続先PostgreSQLデータベース名

# Glue Connectionから接続情報を取得
jdbc_conf = glueContext.extract_jdbc_conf(connection_name=CONNECTION_NAME)
logger.info(jdbc_conf)
# 以下のような出力がされる
# {'enforceSSL': 'false', 'skipCustomJDBCCertValidation': 'false', 'url': 'jdbc:postgresql://hogehoge.xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com:5432', 'customJDBCCertString': '', 'user': 'postgres', 'customJDBCCert': '', 'password': 'xxxxxxxxxxxx', 'vendor': 'postgresql'}

# jdbc_conf["url"] には
# jdbc:postgresql://HOST:5432
# という形式の文字列で、最後のデータベース名が欠けている
# DynamicFrame.fromDF に渡すときにはデータベース名の付与が必要
jdbc_url = jdbc_conf["url"] + "/" + DB_NAME

# SQLは以下のように書く
query = "(SELECT * FROM public.testtable WHERE id <= 100) t"

dyf0 = DynamicFrame.fromDF(sparkSession.read.format("jdbc").
    option("url", jdbc_url).
    option("driver", "org.postgresql.Driver").
    option("user", jdbc_conf["user"]).
    option("password", jdbc_conf["password"]).
    option("dbtable", query).load(), glueContext, "dyf0")

# あとはなにか処理
```

このGlue Jobを実行するとPostgreSQLには以下のようなクエリが発行されます。

```sql
SELECT "id","col1","col2","col3" FROM (SELECT * FROM public.testtable WHERE id <= 100) t
```

`"id","col1","col2","col3"` は実際のこのテーブルのカラム名です。
【React】 Stateのリフトアップとは

## 環境
React 18.2.0
## はじめに
Reactは双方向バインディングではなく、単方向のデータフローを採用しています。
双方向バインディングだと、データの状態がどのように変更されているかや、状態管理が複雑になる問題がある一方、単方向データフローだとその状態を管理しているコンポーネントのみが変更することができるので、デバッグや状態管理が容易になるという利点があります。

そのためコンポーネント間で状態を管理する場合は、「**Stateのリフトアップ**」をする必要があります。
要するに「Stateのリフトアップ」とは複数のコンポーネント間で共有される状態を、上位の親コンポーネントで管理することです。
## サンプル
今回は例として、郵便番号を入力し完了次第、都道府県、市が表示されるという画面を作成します。
![スクリーンショット 2023-02-04 22.13.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/888600/be11d183-64c1-4734-312b-081fa548a0f8.png)

親コンポーネントから作成していきます。
````Parent.jsx
import { Card } from "./Card";
import { ZipCodeInputText } from "./ZipCodeInputText";

export const Parent = () => {
  return (
    <>
      <ZipCodeInputText />
      <Card />
    </>
  );
};
````


そして子コンポーネントに該当する郵便番号のInput要素と、結果を表示するコンポーネントを作成します。

````ZipCodeInputText.jsx
import { useState } from "react";

export const ZipCodeInputText = () => {
  const [zipcode, setZipCode] = useState("");

  return (
    <div style={{ margin: "10px 0" }}>
      <label htmlFor="zipcode" style={{ marginRight: "10px" }}>
        郵便番号 :
      </label>
      <input
        name="zipcode"
        type="text"
        value={zipcode}
        onChange={(event) => setZipCode(event.target.value)}
      />
    </div>
  );
};
````

````Card.jsx
const Addresses = [
  {
    zipcode: "100001",
    prefecture: "東京都",
    city: "千代田区"
  }
];

export const Card = ({ zipcode }) => {
  const address = Addresses.find((address) => address.zipcode === zipcode);

  return (
    <div>
      <p>都道府県 : {address?.prefecture}</p>
      <p>市 : {address?.city}</p>
    </div>
  );
};
````


`ZipCodeInputText`では郵便番号を、コンポーネントの内部で制御される`State`で**zipcode**として定義して管理しています。
ここで今回の仕様について確認しましょう。
都道府県と市は郵便番号によって、表示されるという仕様でした。
そのため、`Card`コンポーネントは郵便番号という**状態**を知る必要がありそうです。
これがコンポーネント間で状態を管理するケースに該当します。
現時点の実装ではこれらの仕様を再現するのは厳しいため、「Stateのリフトアップ」利用して実装し直していきましょう。

## 実装
やり方は簡単です。導入で説明した通り、上位の親コンポーネントで管理すれば良いのです。
それでは実装していきましょう。

````Parent.jsx
import { useState } from "react";
import { Card } from "./Card";
import { ZipCodeInputText } from "./ZipCodeInputText";

export const Parent = () => {
  const [zipcode, setZipCode] = useState("");

  const updateZipCode = (zipcode) => {
    setZipCode(zipcode);
  };

  return (
    <>
      <ZipCodeInputText update={updateZipCode} />
      <Card zipcode={zipcode} />
    </>
  );
};
````

````ZipCodeInputText.jsx
export const ZipCodeInputText = ({ update }) => {
  return (
    <div style={{ margin: "10px 0" }}>
      <label htmlFor="zipcode" style={{ marginRight: "10px" }}>
        郵便番号 :
      </label>
      <input
        name="zipcode"
        type="text"
        onChange={(event) => update(event.target.value)}
      />
    </div>
  );
};
````

`Card`コンポーネントは変更がないためそのままです。
郵便番号を親コンポーネントである`Parent`で定義し、更新関数を渡して入力された郵便番号で更新するようにしました。
これによって、コンポーネント間で状態を管理することが可能になりました。

## おわりに
「Stateのリフトアップ」という言葉をよく聞き、その実体についてあまりわかっていなかったので今回記事にしました。
おそらくほとんどの人が無意識のうちにやっていることだと思います。私もそうでした。
ただ複雑なUIになってくるとグローバルで管理しようとしたりするので、その際は「「Stateのリフトアップ」で解決できないか検討しましょう。
そうすることで、状態の管理がしやすくなったり、再利用しやすいコンポーネントを作成することができるため、保守性の向上にもつながるかと思います。

## 参考ドキュメント

https://ja.reactjs.org/docs/lifting-state-up.html
【PHP】S3 ファイル(オブジェクト)の有無をチェックする方法

# 概要
S3に保存したファイルの有無をチェックする方法がないかと思い調べたら、良い方法があったので、備忘録も含めてその方法を説明します。

# 設定方法
1. 最初に、AWS SDKをインストールします。インストール方法は、開発している環境によって異なる為、下記の公式ドキュメントを確認して行って下さい。
[インストール:AWS SDK for PHPバージョン 3](https://docs.aws.amazon.com/ja_jp/sdk-for-php/v3/developer-guide/getting-started_installation.html)

2. SDKとAWSを繋ぐ方法については、下記を参照して行って下さい
[AWS SDK for PHPバージョン 3 の基本的な使用パターン](https://docs.aws.amazon.com/ja_jp/sdk-for-php/v3/developer-guide/getting-started_basic-usage.html)

3.　公式内に`doesObjectExist`のメソッドがある為、そのメソッドを使用してS3に保存してあるファイルの有無を確認する
```php
# S3にコネクトをする
$s3 = new S3Client($config);

# $bucket：バケット名
# $key：S3内のファイルパス
$resurt = $s3->doesObjectExistV2($bucket, $key, false, []) 
if ($resurt === true) {
    echo 'ファイルが存在します。';
} else {
    echo 'ファイルが存在しません。';
}
```

## 公式ドキュメントの内容

- 説明
オブジェクトの名前が存在するか判断します。このメソッドは、S3のHeadObjectの設定を使用する為、エラーにならないようにバケットとオブジェクトの許可設定を行う必要があります。

- メソッド名
```php
doesObjectExistV2( string $bucket, string $key, boolean $includeDeleteMarkers = false, array $options = [] )
```

- 返り値
` boolean `

- パラメーター

|  型  | 変数  | 説明 |
| ---- | ---- | ---- |
|string|$bucket|The name of the bucket|
|string|$key|The key of the object|
|boolean|$includeDeleteMarkers = false|Set to true to consider delete markers existing objects.<br> Using the default value of false will ignore delete markers and return false.t|
|array|$options = []|Additional options available in the HeadObject operation <br> (e.g., VersionId).|

- 例外
```php
Aws\S3\Exception\S3Exception|Exception
# もし、処理されない例外がある場合
```


# 参考資料
- [【公式ドキュメント】doesObjectExistV2](https://docs.aws.amazon.com/aws-sdk-php/v3/api/class-Aws.S3.S3ClientInterface.html#_doesObjectExistV2)
- [[PHP] AWS S3 オブジェクト(ファイル)の存在チェック](https://agohack.com/aws-s3-does-object-exist/)
ウォッチナビゲーション用に小江戸大江戸コースのGPXファイルを作成する方法

# はじめに
エンジニアとはあまり関係ないかもですが、手こずっている方が多いようなので共有いたします。

[小江戸大江戸](https://trainic-world.org/coedo-oedo/)というウルトラマラソンが毎年3月に開催されています。距離が100kmとか200kmあるドM向けのレースです。そのコースマップをGarminやSuuntoなどのウォッチにインポートする際に必要なGPXファイルの作成方法についてです。


# GPXファイルの作成手順
## 1. 小江戸大江戸のホームページからGoogle mapを開く

![6f70c812f1370ae631852dcc9526ec1b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727548/157dcb72-4d14-bf40-a8cc-a99d7eea47d4.png)

## 2. コースのKMLファイルをダウンロードする。
![d9f647b8f325d7e84e9eb3eafc743dd7.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727548/19e56d6c-f4c4-1038-fbb0-91ef1c2a77db.jpeg)
![ab7f2f25e59f79b29a3f050564232537.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727548/d4df6b89-47a4-2c76-929b-c3fc7a975396.png)

## 3. ダウンロードされたKMLファイルをGPXファイルに変換しダウンロードする
適当なサイトで変換します。私は[AnyConv](https://anyconv.com/ja/kml-to-gpx-konbata/)を利用しました。
![6031a4c413285f64fe6de793ecf662db.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727548/bf61e8e4-133c-80b1-d1ca-09e161c5b39b.png)
![ba5aaacc534c1013f5daaae622521630.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727548/0e4cd3e7-4660-4b74-93e9-edc4c3f38770.png)

**ここまでの手順は他のサイトでも紹介されているのですが、この後の手順にややテクニックが必要です。**

ダウンロードしたファイルをそのままウォッチにインポートしてもルートの一部分しか読み込まれません。

理由はトラックデータが分割されているからです。おそらく、トラックデータが分割されていると最初のトラックしかウォッチ側で表示できない仕様になっていると思われます。なので分割されたトラックデータを結合してひとつのトラックデータにする必要があります。

## 4. GPXファイルの分割されたトラックデータを結合する
適当なアプリを用いて結合します。私はMac使いなので[TrailNote](https://www.trail-note.net/)を使用しました。
Windowsでも似たようなアプリがあると思います。おそらく[カシミール３Ｄ](http://www.kashmir3d.com/)で可能ではないでしょうか。
結合方法の詳細は[ここ](http://www.trail-note.net/usage/track/)を参考にしました。

![b3d90164b0523de124e7ee725351b4c3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727548/428a909b-d323-5118-e21a-7bff7999b638.jpeg)
![a76189ba340aab995bc8dee012b7c40b.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727548/885c5b18-1fee-6729-7eb9-2652b6195384.jpeg)
![abb3783ddcb4be468331539ff861c9a4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727548/029beb82-fdd5-2e89-ba7a-9bf2729531ed.jpeg)
![4a514b55fdd7da7f2efd14751c281bc2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727548/67ae0f3c-0893-a7d6-539e-b32d8ec4856a.png)

## 5. 保存したGPXファイルをGarminやSuuntoなどのウォッチにインポートする
ウォッチへのインポートのやり方は先人の皆様が各種記事で説明されていますのでググってみてください。

# おわりに
参考になりましたら幸いです。
もし間違いがありましたらご指摘お願いいたします。

# その他参考になりそうな記事
- [Google My MapのデータをGarminやiPhoneのナビゲーションで使う。](https://www.otakuhouse.org/entry/2021/05/09/182515)
- [GPXトラックログを間引く・簡略化](https://www.330k.info/software/simplify_gpx/)
ChatWorkの絵文字(emoticon)を全部まとめてzip化してダウンロードする

タイトルそのままです。
Pythonのスクリプトで、ChatWorkが公開している絵文字をまとめてzip化してダウンロードします。

標準ライブラリのみ使用しているので、依存モジュールのinstall等は不要でそのまま実行可能です。

```python
import io
import zipfile

import requests

BASE_URL = "https://www.chatwork.com/image/emoticon/"
file_paths = [
    "emo_smile.gif",
    "emo_sad.gif",
    "emo_more_smile.gif",
    "emo_lucky.gif",
    "emo_surprise.gif",
    "emo_wink.gif",
    "emo_tears.gif",
    "emo_sweat.gif",
    "emo_mumu.gif",
    "emo_kiss.gif",
    "emo_tongueout.gif",
    "emo_blush.gif",
    "emo_wonder.gif",
    "emo_snooze.gif",
    "emo_love.gif",
    "emo_grin.gif",
    "emo_talk.gif",
    "emo_yawn.gif",
    "emo_puke.gif",
    "emo_ikemen.gif",
    "emo_otaku.gif",
    "emo_ninmari.gif",
    "emo_nod.gif",
    "emo_shake.gif",
    "emo_wry_smile.gif",
    "emo_whew.gif",
    "emo_clap.gif",
    "emo_bow.gif",
    "emo_roger.gif",
    "emo_muscle.gif",
    "emo_dance.gif",
    "emo_komanechi.gif",
    "emo_devil.gif",
    "emo_star.gif",
    "emo_heart.gif",
    "emo_flower.gif",
    "emo_cracker.gif",
    "emo_cake.gif",
    "emo_coffee.gif",
    "emo_beer.gif",
    "emo_handshake.gif",
    "emo_yes.gif",
]

zip_buffer = io.BytesIO()
with zipfile.ZipFile(zip_buffer, "a", zipfile.ZIP_DEFLATED, False) as zip_file:
    for file_path in file_paths:
        image_url = BASE_URL + file_path
        img_data = requests.get(image_url).content
        zip_file.writestr(file_path.split("/")[-1], img_data)

with open("chatwork_emoticons.zip", "wb") as f:
    f.write(zip_buffer.getvalue())
```

`zipfile.ZipFile()`でインメモリのfile-like objectをそのままzip化できます。

Gistにも公開しています。
https://gist.github.com/sin9270/eea6769b1e86786a415871b355f6f1e3

## 参考にした記事
https://gist.github.com/ttsuruoka/32b764ecd8254aaa214c
https://stackoverflow.com/questions/2463770/python-in-memory-zip-library
Vue3, Vuetify, Typscript  の環境構築

自分が後で見返す用のやつなので適当なこと言ってるかもです。
[やりたいことリスト](https://qiita.com/OTA_nagisa/private/9588ef8ef9f69f18bbd5)

## 流れ
・Nodejsのインストール
・yarnインストール（別に要らなかったかも）
・Vue CILインストール
・vuetifyでcreate

## Nodejsのインストール
どのサイトを見ても、npmが使えることが前提だった、、、
（それすら知らないとか笑って言われた）

僕はWindowsなので、https://nodejs.org/ja/ ここから推奨版のほうをインストールして、脳死でnextおしてinstallした。

最初使えんやんけ！ってなったけど、ターミナル開きなおすかなんかした行けた
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125193/b3be9e5a-b89e-c77b-b365-a58e3431bfb5.png)

## yarnインストール（別に要らなかったかも）
Vueの公式のところが、yarn使ってたからそっちのほうがいいのかなって思ってインストールしたけど、別にnpmでいい気もした（よくわかってない）
```
npm install -g yarn
```
## Vue CILインストール
フォルダ移動して
```
npm install -g @vue/cli
```
バージョン確認（5.0以上ならいいらしい）
```
vue -V
```
## vuetifyでcreate
先にviteとやらでクリエイトして、vuetifyを入れるやり方やったら、betaが入ったから、こっちでやってみた。
（やり方が悪かっただけ説）
https://next.vuetifyjs.com/en/getting-started/installation/

### Create
```
yarn create vuetify
```
### プロジェクト名入力
（そのまま入力すればデフォルトのやつ上書きされる）
多分後からでもフォルダ名変えればいいだけな気がする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125193/8a676de3-8108-1dc6-7301-728a414052f0.png)
### preset選択
これなに
よくわかんないけど大は小を兼ねるからEssentialsを選択した.。

一応[こちら](https://tedate.jp/vue-js/i-tried-installing-vuetify3-1-that-called-valkyrie)を参考にして、Storeも使うかもなーという理由もある
>・Vuetifyのみ(Default)
>・Vuetify と VueRouter をインストール(Base)
>・Vuetify と VueRouter、そして状態管理ができる Pinia をインストール(Essentials)
>・独自選択(Custom)
>の4つがあります。
>コンポーネントの階層がそんなに深くなる予定がなければ Base でも充分使えるかと思います。
>もし初めから Store を使う予定があるなら Essentials を選択、といったところでしょうか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125193/63da2b37-46fb-1575-286e-252bc6ffd7d0.png)

### TypeScript使うか
もちろんYes
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125193/e282d2bd-9129-d877-6833-974a358b1145.png)

### インストールに何使うん？みたいなやつ
よくわかんないけどyarnにした
せっかく入れたし、yarnのほうが早いとかなんとか（まあ勉強だしね）
（スクショは忘れた）

### 完了
Doneって言われたので、終わったらしい。
デイレクトリが作られてるので、そこに移動して、run
```
cd vuetify-project
yarn dev
```
出てきたlocalのURLに飛べばたぶんよし
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125193/98c9e7c6-ab22-6385-89df-a2197820419a.png)
Composerの世界情勢ネタ #StandWithUkraine

```
composer update
```
をしてみると、、、
![スクリーンショット 2023-02-04 213851.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3005822/392a2d0a-90e3-7173-3272-7a0f999b5ecb.png)
**<font color="blue">#StandWith<font><font color="orange">Ukraine</font>**
とウクライナカラーで表示されるようになっています。

:::note info
国旗の青は空、黄色は小麦と農業を表しているみたいです
:::
こちらのコミットに載ってます。

https://github.com/composer/packagist/commit/86244a3695fcaaac9c5ba4257a4314eae1c6d981#

ただ、コメントを見てみると、
* **#StandWithPeace**を使用して欲しい
* ウクライナを応援してくれてありがとう
* テクノロジーに関係ないものは削除して
* 個人的な意見を世界中のPHP開発者に押し付けないで
* 政治をオープンソースに持ち込まないで

などなど賛否両論のようです
Google formをhtmlに埋め込む

## 0. はじめに
フォーム作りに手を抜きたい人向けです。
## 1. フォームの作成
元となるフォームをつくります。
https://docs.google.com/forms/u/0/

お問合せフォームを想定しているのでこんなかんじで。パレットボタンを押すとスタイルが変更できます。
ここまでできたら右上の「送信」ボタンを押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636551/c86337e3-4089-b367-508b-035121a3b669.png)

次のダイアログが表示されるので「<>」アイコンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636551/a3bd7e6a-cbff-e76f-7ecf-c4755497c49b.png)
必要に応じて幅と高さを変更し、コピーボタンをクリックすると生成されたhtmlタグがコピーされます。


## 2. フォームの埋め込み
先ほどコピーしたhtmlタグを埋め込み先に貼り付けます。
<iframe src="https://docs.google.com/forms/d/e/1FAIpQLSfcTwBCtxa38OtZR_MGaZOpms5DBAtp8xFSP3BivHeMtkkBXA/viewform?embedded=true" width="640" height="350" frameborder="0" marginheight="0" marginwidth="0">読み込んでいます…</iframe>
こんな感じでそのままのフォームが張り付きます。
溢れ出る既製品感ですが手抜きなのでオッケーです。あとはCSSで幅やマージンを整えてあげれば完璧です。

## 3. フォームの編集権限変更
最後にサイトを見た人ならだれでもフォームを送信できるように設定を変更します。

まず右上のポチが3つ並んだアイコンをクリックしてメニューを表示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636551/53b5e49d-6b29-17e1-14b1-94b3b27820d7.png)

次に「共同編集者を追加」を押下
![スクリーンショット 2021-11-30 22.53.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636551/4b2c7755-6fef-ccee-ee23-397f9f10c906.png)

左下の変更ボタンをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636551/2984409b-9e65-47b0-957b-2e115a912987.png)

「制限付き」とかかれたプルダウンを押下し、権限を「リンクを知っている全員」に変更します。
これで、フォームの権限の変更は完了です。

## 4. さいごに
これなら２分もあればフォームが作成できると思います。自家製のロジックを組むより遥かに手軽で信頼性も抜群です。さすがに見た目がちょっと、、という方向けに[こちら](https://qiita.com/egsrkntr/private/e6aa90b1f1ca884e3714)の記事もつくりました。
アロー関数で波括弧のなかに判定式がある場合はreturnが必要

```example.js
arr = []
arr.push(1,2,3,4,5)

// ネストしない場合はreturnは不要
const exist = arr.some(number => number == 1)
console,log(exist)//true

// false ネストしている場合はreturnが必要
const exist = arr.some(number => {
    number == 1
})
console.log(exit)//false

// ネストしている場合はreturnが必要
const exist = arr.some(number => {
    return number == 1
})
console.log(exist)//true
便利なReact Hooksの紹介

# はじめに
コピー＆ペーストですぐに使える便利なReact Hooksを紹介する。

# useMount
コンポーネンがマウントされたときに登録されたコールバックを実行する。

```tsx
// hooks の実装
export const useMount = (callback: () => void) => {
  const mountRef = React.useRef(callback);
  mountRef.current = callback;
  React.useEffect(() => {
    mountRef.current?.();
  }, []);
};

// 使い方
function Example() {
  useMount(()=>{
    // 実行するコールバック
  });

  return ...
}
```

# useUnmount
コンポーネンがアンマウントされたときに登録されたコールバックを実行する。

```tsx
// hooks の実装
export const useUnmount = (callback: () => void) => {
  const unmountRef = React.useRef(callback);
  unmountRef.current = callback;
  React.useEffect(
    () => () => {
      unmountRef.current?.();
    },
    [],
  );
};

// 使い方
function Example() {
  useUnmount(()=>{
    // 実行するコールバック
  });

  return ...
}
```

# useOnEvent
イベントの登録と解除を自動的に行う。

```tsx
// イベントの登録
export function on(
  element: Element | Window | Document,
  eventName: string,
  callback: (ev: Event) => void,
  options?: boolean | AddEventListenerOptions
): () => void {
  element.addEventListener(eventName, callback, options);

  return () => element.removeEventListener(eventName, callback, options);
}

// hooks の実装
export function useOnEvent<TElement extends Element, TEvent extends Event>(
  element:
    | React.RefObject<TElement | undefined | null>
    | TElement
    | Window
    | Document
    | undefined
    | null,
  eventName: string,
  callback: (ev: TEvent) => void,
  useCapture?: boolean
) {
  const callbackRef = React.useRef(callback);
  callbackRef.current = callback;

  React.useEffect(() => {
    const actualElement =
      element && 'current' in element ? element.current : element;
    if (!actualElement) {
      return;
    }

    const dispose = on(
      actualElement,
      eventName,
      (ev) => callbackRef.current(ev as TEvent),
      useCapture
    );
    return dispose;
  }, [element, eventName, useCapture]);
}

// 使い方
function Example() {

  const onKeyDown = (ev: KeyboardEvent) => {
    // 実行するコールバック
  }
  useOnEvent(document, 'keydown', onKeyDown);

  return ...
}
```
【デプロイ】リポジトリからの環境構築④(Laravel)

この記事では以下の環境で行ったものです。
・OS：Windows10 Pro
・IDE(統合開発環境)：Cloud9
・Cloud9に入っているPHPバージョン：7.4.30
・レンタルサーバー：Conoha WING
・Conohaに入っているPHPバージョン：8.1.12
・バージョン管理システム：GitHub

ここでは、<font color='red'>「Cloud9(ローカル環境)で作成したLaravelプログラムがGitHubと繋がっている」</font>という前提で、そのプログラムをCloneし、Conoha WINGのサーバーを使って、本番環境に公開(デプロイ)する方法をお伝えします。

＜方針＞
Ⅰ. Conoha WINGでサーバーを作成し、Cloud9からサーバーへログイン
Ⅱ. GithubのプログラムをClone
Ⅲ. 本番環境の設定
Ⅳ. 本番データの投入
Ⅴ. 動作確認、本番環境の更新

長編になるため、方針ごとで記事を分けております。

今回は、「Ⅳ. 本番データの投入」に関する記事です。

前編Ⅰ～Ⅲの記事は下記URLからご覧ください。
「Ⅰ. Conoha WINGでサーバーを作成し、Cloud9からサーバーへログイン」
https://qiita.com/kamitch/items/87030f98e5deb49badf9
「Ⅱ. GithubのプログラムをClone」
https://qiita.com/kamitch/items/a0c1198f65f8c8e837ee
「Ⅲ. 本番環境の設定」
https://qiita.com/kamitch/items/e6422eb5ec7b5fd84459

#### Ⅳ. 本番データの投入
前編の記事で、Conohaのサーバー内にデータベースを作成し、それをクローン先のフォルダ(Laravelプロジェクト)と紐付けしました。ただ、まだデータベースのテーブルは無い状態です。
ですので、ここでデータベースを編集し、Laravelプロジェクトと同じテーブル構成にしましょう。
(前編に続きCloud9のターミナルを使って、サーバーにログインし編集していきます。ターミナルの作業フォルダ先は前編と同じく、クローン先のフォルダにしてください。)

##### ①マイグレーションの実行
・ローカル開発環境でデータベースのテーブルを作った時と同じく、
`php artisan migrate` を入力してください。

・接続情報が正しく設定されていれば、下図のように今回のプロジェクトで利用されるテーブルがまとめて設定されるので、phpMyAdminで確認しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2835861/37a4c198-d2a9-977c-48ab-296f59a8c820.png)
(任意)
・`php artisan db:seed` で、シードデータ(初期データ)をデータベースに投入しましょう。

#### あとがき
いかがでしたしょうか。

今回は「本番データの投入」についてお伝えさせていただきました。

次回は「動作確認、本番環境の更新」ということで、クローンしたLaravelプロジェクトがブラウザに表示できるようにしましょう。

できるだけ細かく書いたつもりですが、分からないことなどありましたら、ぜひコメントなどお願いいたします。
GASで複数のカレンダー情報から特定のカレンダー情報を取得する

## はじめに
標題通り、Gasでカレンダー情報を取得します。特定のカレンダーで、会議室管理、イベント管理を実施したいと考えています。色々工夫したので、メモ程度にコードを残しておきます。

## ファイル一覧
```js:ファイル一覧
getCalendar.gs 　//カレンダー取得 
color.gs　　　　　　　　　　　　　　//色の定義
constants.gs  // 定数
model.gs // model
```

## ソースコード
```js:getCalendar.gs
// 本日の会議室一覧の予約取得
function getTodayMTGList() {
  const googleCalendar = CalendarApp.getCalendarById(CALENDAR_ID);
  const nowDate = new Date()
   
  // 本日のイベント一覧取得
  const calendarEvents = googleCalendar.getEventsForDay(nowDate)
  // MTGの色(1)でフィルターを実施
  const mtgs = calendarEvents.filter(mtg => mtg.getColor() === EVENT_COLOR)

  const results = []

  for(const event of mtgs){
    const calendar = new Calendar()
    calendar.title = event.getTitle()
    calendar.startTime = event.getStartTime()
    calendar.endTime = event.getEndTime()
    calendar.description = event.getDescription()
    calendar.type = MTG_TYPE
    results.push(calendar)
  }
  return results
}
```

```js:color.gs
const EVENT_COLOR = CalendarApp.EventColor.PALE_BLUE // 1
const MTG_COLOR = CalendarApp.EventColor.PALE_GREEN // 2 

// =======================【色のプロパティ】===========================
// 色名称：色表示名：色のID
// Pale_Blue：ラベンダー：1
// Pale_Green：セージ：2
// Mauve：ブドウ：3
// Pale_Red：フラミンゴ：4
// Yellow：バナナ：5
// Orange：ミカン：6
// Cyan：ピーコック：7
// Gray：グラファイト：8
// Blue：ブルーベリー：9
// Green：バジル：10
// Red：トマト：11
```

```js:constants.gs
const CALENDAR_ID = PropertiesService.getScriptProperties().getProperty("CALENDAR_ID");

const MTG_TYPE = "mtg"
const EVENT_TYPE = "event"
```

```js:model.gs
/**　Calendarモデルの定義 */
function Calendar() {
  this.title = null;
  this.startTime = null;
  this.endTime = null;
  this.description = null;
  this.type = null
}
```

## 実行ログ
```ts:実行ログ
results:  [ { title: '2階会議室予定',
    startTime: Sat Feb 04 2023 20:00:00 GMT+0900 (Japan Standard Time),
    endTime: Sat Feb 04 2023 21:00:00 GMT+0900 (Japan Standard Time),
    description: '説明実施',
    type: 'mtg' } ]
```
クラシックマウス　作ってみた　その1 ToF, Gyro, Arduino, ステッピングモーター, OLED　


# はじめに
* 電子工作で何か作ってみたくなり、昔から興味のあったロボコンを調べてみた。マイクロマウスが面白そうだったので作ってみることにした。最初なのでクラシックマウスから。キットもあるが、折角なのでなるべく自分で組み立てることにした。
* パーツも入手しやすいものにしてみたが、ステッピングモーターは難しいかも。プログラムも、わかりやすく、割込みは使わずに、逐次処理で書いてみた。
* タイミングが悪く、大会には参加できていない。自作の迷路ではよい感じになってきているが、16ｘ16では試せていないので、RTさんの試走会で試してみるつもり。

# 目標、狙い
* 過去の大会の映像を見るとびっくりするような速さ、動きだけれど、まずは完走を目指すところから。最短経路などは考えない。
* モーターはコントロールしやすそうなステッピングモーター。
* センサーは、光量ではなく、使いやすそうなToFセンサーを使ってみた。
* Gyroセンサーは、途中から使ってみたが、安価なのにかなり精度が高く、機体の傾きが相当コントロールしやすくなった。
* マイコンはお馴染みのArduino Uno。プログラムサイズにあまり余裕がないので、他の機種の方が良いかも。
* なるべく小さく作って、壁に衝突しないようにしたい。ぶつかってしまうとリカバリーが難しい。

# 使用したもの
* ステッピングモーター
    * KH39EM2-801: ユニポーラ、ステップ角1.8°、電圧 5.6V、39mm角、厚さ20.8mm
    * ドライバ: ULN2803AN、8chトランジスタアレイ
* マイコン
    * Arduino Uno 互換品
* 距離センサー　3個
    * VL53L0X: Amazonで購入
* Gyroセンサー
    * MPU6050: Amzonで購入したもの
* OLED
    * 0.96インチ　128×64　SSD1306　I2C、どこで買ったか忘れました。
* バッテリー
    * リチウムイオン電池　10440　端子付き　2個直列　単4ホルダーに入れてます。
* フレーム、ホイールなど
    * プリント基板、タミヤユニバーサルプレートなど
    * ホイール：　朱雀技研　GTFRobots アルミホイール 50mm、両面テープで少し大きくしています。

# 動画
https://youtube.com/shorts/EOuVEYKTElc
* この迷路は4×4ですが、プログラム上は16×16で、中央がゴールになっています。左下をスタートし、中央のゴールを目指して足立法で探索し、最後は左上で探索エラーとなって往復運動になっています。

# 外観
上面
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482773/26a83140-9f70-fdcb-a9ef-d0b8347dd418.jpeg" width=50%>
左
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482773/018a2137-41f2-402a-ad8d-6736f7f02483.jpeg" width=50%>
右
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482773/7ddf6277-65fc-ad84-ae02-732f886e22b7.jpeg" width=50%>
前面
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482773/cb0fdf22-bd0b-357b-bfc4-7dc25ec55fc3.jpeg" width=50%>
後ろ
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482773/e77ab4ff-ab03-efa8-fc31-ce95dd707a86.jpeg" width=50%>
下面
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482773/2eee40b0-e459-39ee-b47b-0bfa9ea7d245.jpeg" width=50%>


# 解説予定
以下を解説していく予定。
* ステッピングモーター
* ToFセンサー
* Gyroセンサー
* OLED
* フレーム、ホイールなど
* 段差対策
* プログラミング
* 機体座標など
* 足立法、壁情報
* 自作迷路

以上
Elixirの文字列はUTF-8だけど、RegexはUTF-8ではない

# はじめに｜Elixirの文字列はUTF-8なバイナリである
Elixirの文字列はバイナリ。文字エンコーディングは、UTF-8。
ここまでは、駆け出しのアルケミスト(私を含む)だって知っている。
[Elixir School](https://elixirschool.com/ja/lessons/basics/strings/)にもそう書いてある。
```bash
$ elixir -e 'IO.puts "本日は晴天なり"' | nkf --guess
UTF-8 (LF)
$
```
しかし、である。

# 問題点｜Elixirの正規表現はUTF-8ではない
以下を実行して欲しい。
```elixir
iex> String.match?("覚", ~r/[：]/)
true
iex>
```
は?! **「覚」に全角の「：」がマッチする?** んなわけあるかーい!

# 原因
こーゆー事のようです。
```elixir
iex> <<0>> <> "覚"
<<0, 232, 166, 154>>
iex> <<0>> <> "："
<<0, 239, 188, 154>>
iex>
```
3バイト目の154(0x9A)が両文字に共通している。
つまり、
```elixir
iex> <<0xE8, 0xA6, 0x9A>>
"覚"
iex> String.match?("覚", ~r/[\xE8\xA6\x9A]/)
true
iex> String.match?("覚", ~r/[\x9A]/)
true
iex>
```
「覚」も全角の「：」も、一つの文字として認識されておらず、1バイトづつバラバラの文字からなる文字列と認識されている様だ。
つまり、**ElixirのRegexは、UTF-8ではない!**

# 解決策｜Unicodeをサポートする修飾子を付ける
正規表現を生成するシギル~rに、修飾子uを付けると、期待通りに動作する。
```elixir
iex> String.match?("覚", ~r/[：]/u)
false
iex> String.match?("：", ~r/[：]/u)
true
iex>
```

# 感想
日本語を含むUnicode文字列を扱うとき人がハマりやすいハマりどころだと思い、この記事を書いてみました。

いやしかし、[ElixirのRegexドキュメント](https://hexdocs.pm/elixir/1.14.3/Regex.html#module-modifiers)にそんなこと書いてないやん。
> :unicode (u) - enables Unicode specific patterns like \p and causes character classes like \w, \W, \s, and the like to also match on Unicode (see examples below in "Character classes"). It expects valid Unicode strings to be given on match

Unicodeに対応した文字クラスが使えるようになるよ、って意味でしょ、これ。
むしろ、この修飾子を付けないと、UTF-8を扱えない、US-ASCIIとして扱われる、と書くべきではないか。

てか、Elixirの文字列はUTF-8のバイナリと言ってるんだから、u修飾子をデフォルトにするべきではないか。

[Issues](https://github.com/elixir-lang/elixir/issues)書くかな…
[プルリク](https://github.com/elixir-lang/elixir/pulls)の方が…

# 実行環境
この記事は、以下の環境で検証しました。
```bash:環境
 $ iex --version
Erlang/OTP 25 [erts-13.1.4] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [jit:ns]

IEx 1.14.3 (compiled with Erlang/OTP 25)
$
```

# 追記
関係しそうな[Issues](https://github.com/elixir-lang/elixir/issues)の中にを発見。
https://github.com/elixir-lang/elixir/issues/3711
Joséは以下のように回答している。
> Regex works on bytes by default so the second one is probably matching by accident due to the bytes involved. If you are using \p and friends, you likely want to use the u modifier:

つまり、Regexはデフォルトではバイト単位で動くよ、と。マルチバイトでは動かないよ、と。
こう認識されているのなら、Regexのドキュメントを修正すべきなんじゃないかなぁ。