OmniAICreator/Qiita-1.07M huggingface dataset:
🤔csvデータの取り扱いでやっちまうこと🤔

# 概要
★シンプルだけど、結構新人あるあるの大事なお話★
よくよくcsvデータやtsvデータなどを開発時に扱うことがあります。
その中で、こんなこと起こったりしている「そこのあなた！」この記事は良記事になるかもしれませんよ？

* Excelで開くと文字化けしている、、、
* Excelで開くと列がズレてる、、、、
* 取り込みたい値は「0101」なのに、なぜかDBを見ると「101」になってしまっている。

などなど、あるあるなことは多数あります。
ちょっとでも躓いている人の助けになればという新人向けの投稿です。

## よく使うツールについて
* サクラエディタ（テキストエディタ）
* Excel

## あるある事例
Excel上で確認したいデータの内容
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124041/efaf8a8b-b1bd-c063-3821-14cda120ddf1.png)

### ①Excelで開くと文字化けしてる・頭の0も消えてる。。。
…![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124041/d00176e8-95cc-2485-ca1d-9114535b94d4.png)

■文字化けをしないように確認したいとき
1：文字コードを「UTF-8→S-JIS」に変更
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124041/04754ea8-d9a5-839b-322d-f5fb206dfd0e.png)

2：Excelで開いてみると文字化け解消！！！　ただ、0が消えちゃった、、、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124041/98702ed0-adc6-e3cc-d707-55ca4658d86f.png)

3：0が消えないように、Excelで取り込む
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124041/ca59175e-4f56-9515-7bf2-06ce5db795da.png)

・型を自動変換させなければ、0消えずに取りこんで確認ができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124041/3f7e4894-c374-b781-3a46-a130f57e35c7.png)


### ②Excelで開くと列がズレてる…
例えば、システムでcsvファイルを作成したときに、列がズレる理由としては以下が主
・1列の区切りに対して、エンクロージャー("")を付けていない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124041/76f2de4c-8c3c-4be5-d8a2-854e153c60f3.png)
以下の様になる修正を行うと解消する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124041/457b06da-8ebc-7e2c-edfa-b033e45935c9.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124041/ea1b3a30-8835-eaae-3573-d76ef4dae0ce.png)


## まとめ
PC作業をする中で、何を使うかによって、上手く誤ったデータとして取り扱わないように気をつけてくださいね！
また、csvデータを作成する場合は、エンクロージャーもセットして作成するようにしていきましょう。
ドキュメント用の IPv4アドレス範囲

よく忘れて毎回ググるので。

## IPアドレス範囲1

192.0.2.0/24

## IPアドレス範囲2

198.51.100.0/24


## IPアドレス範囲3

203.0.113.0/24

## RFC

[RFC5737](https://www.rfc-editor.org/rfc/rfc5737.html)

> 3.  Documentation Address Blocks
> 
>  The blocks 192.0.2.0/24 (TEST-NET-1), 198.51.100.0/24 (TEST-NET-2),
>  and 203.0.113.0/24 (TEST-NET-3) are provided for use in
>  documentation.
シビックテックに入門してみた

この記事は　[CivicTech ＆ GovTech Advent Calendar 2022](https://qiita.com/advent-calendar/2022/civictech)　19日目の投稿です。

初めてシビックテックに参加してみたので、感想を書きます。

# シビックテックとは
シビックテック（Civic Tech）とはCivic（市民）がTechnology（技術）を用いて社会課題を解決していくものです。社会課題というと難しく捉えがちですが、もっと幅広い意味で捉えてもよいかと思います。

# やってみて
## WordPressプラグイン作成
Webサイト閲覧者がクレジットカードで寄付し、その金額や定期的な寄付を管理するWordPressプラグインを作成しました。

### 体制
PM1人、自分を含めたエンジニア3人のチームで開発を進めました。普段はそれぞれが別の組織に所属していましたが、何かの役に立ちたいと考え集まったような形です。

### やりがい
自分ひとりではなく複数のメンバーで協力して作り上げていくことへのやりがいを再認識しました。

### 難しかったこと
私自身、社外の方と共に開発するのが初めてでいろいろ不慣れな点が多かったと思います。バックグラウンドが異なる方とミーティングの時間帯が合わないことから始まり、認識合わせがうまくいかないこともありました。
今考えると、もう少しコミュニケーションをとるべきだったかと思います。

## Webサイト構築
行政に関する見える化サイトを構築しました。

### 体制
約10名が関わるプロジェクトで、エンジニアの方は5名ほどおられました。

### やりがい
上記のプロジェクトと比較するとより幅広く、高めの技術を用いて開発ができました。自分なりに工夫することができたり、メンバーの方とより深く関わることができたりしてやりがいは大きかったです。

### 難しかったこと
自分の技術では解決できないようなところもあり、いろいろと助けて頂きました。それ自体はいい経験になったと思います。
また、サイトを作り上げた後に使い続けてもらえるのかというところは、自分たちだけでは難しいところもあるなと感じました。

# シビックテックに参加するには

## Code for JapanのSlack、Social Hack Day
 - [Code for JapanのSlack参加方法](https://www.code4japan.org/activity/community)
 - [Social Hack Day](https://hackday.code4japan.org/)
     - 開催は[Peatix](https://peatix.com/group/5894/events)で告知され、最近は[Notion](https://www.code4japan.org/activity/community)（ページ下部）でプロジェクト案内があります。

Slackは誰でも入れますので、気軽に見てみてください。「#04_join_project」にたまにメンバー募集があるので、チェックしておくとよいです。
もくもく会のような形の「Social Hack Day」というイベントが月1回あります。その場で気になったプロジェクトに参加することができます。いろいろな種類のプロジェクトがあるので、どういった立場の方でも気軽に参加できます。

## GRANT
 - [GRANTホームページ](https://grant.community/)
NPO団体などが作ってほしいものや手伝ってほしいことを投稿し、対応できるユーザがそれに立候補できます。
基本的にひとりでの対応となりますが、高い技術力（プログラミングなど）を要求されるわけではないのでそんなに心配はいらないと思います。
（IT関連以外の要望もあるので、募集内容は確認する必要あり）

# まとめ
やり始める前は自分にできることはあるのかなと不安に思う面もありました。実際にやってみると意外とできることはあり、社外の方との繋がりも増えたり、感謝されることもありました。今後も活動を続けていきたいと思います。
PHPUnit のモックのメソッドを二回呼び出したら、違う結果が返ってきた

## 発生した事象

作成したモックオブジェクト (スタブ) に `willReturn()` で返り値を設定したが、一度目の呼び出しと二度目の呼び出しで結果が異なる。

### 実行するテスト

```
<?php

namespace Test;

use PHPUnit\Framework\TestCase;
use stdClass;

class MyClass {
    public function testMethod(): stdClass
    {
        return new stdClass();
    }
}

class DummyTest extends TestCase
{
    public function test_willReturn()
    {
        $expect = new stdClass();
        $expect->a = 'a';
        $mock = $this->createStub(MyClass::class);
        $mock->method('testMethod')
            ->willReturn($expect);
        $result = $mock->testMethod();
        $result->a = 'b';

        $another_result = $mock->testMethod();
        $this->assertSame('a', $another_result->a);
    }
}
```

### 期待する結果

一度目のモック呼び出し ($mock->testMethod()) でも二回目のモック呼び出しでも同じ結果が返ってきて、ともに `$result->a` の値は 'a' となる。

### 実際の結果

二回目の呼び出しにおいて 'b' が返ってきて、テストが失敗する。

```
Failed asserting that two strings are identical.
Expected :'a'
Actual   :'b'
```

## 解決方法

二回以上、決まった回数呼ぶ場合は、 `onConsecutiveCalls()` を利用するのがよさそう。

回数を指定せず繰り返し同じ値を呼ぶ場合は、 `returnCallback()` を利用するのがよい。今回はこちらによって解決した。

先ほどのテストケースを、以下のように変更。期待通りにテストが成功した。

```
    public function test_willReturn()
    {
        $mock = $this->createStub(MyClass::class);
        $mock->method('testMethod')
            ->willReturnCallback(function () {
                $expect = new stdClass();
                $expect->a = 'a';
                return $expect;
            });
        $result = $mock->testMethod();
        $result->a = 'b';

        $another_result = $mock->testMethod();
        $this->assertSame('a', $another_result->a);
    }
```

## 詳細

単なるリテラルの値であれば問題ないが、オブジェクトを `willReturn()` でモックオブジェクトのメソッドにバインドした場合、参照が渡されるためこのような挙動となる。

一度目に呼び出して取得した結果を書き換えると、次に呼び出した際の結果に影響を与えることになる。

## 余談

このような単純な例では大丈夫だが、少し複雑なテストケースで発生するとハマる。ハマった。
M5STACK BASIC / M5StickCPlus nvsを利用する

不揮発な記憶領域を使おうと思い，nvsとやらを使ってみました。v1.11.0です。

UiFlowだとEEPROMと書かれていて，使うのはとても簡単でした。keyを指定して何らかの文字列を書き，同じkeyで呼び出すだけです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533274/e16f698e-55c5-3d82-95d9-d5900be8d487.png)

REPLや素のMicroPythonではこんな感じでした。

```
>>> import nvs
>>> nvs.write_str('A','AA')
>>> nvs._key_map
{'A': 'AA'}
>>> nvs.read_str('A')
'AA'
```

いくつか気になる，不明点が。

- 値の更新 実験したところできませんでした。
- キーの削除 実験したところできませんでした。唯一，M5Burnerを使ったら全部消えました。
- `str`から`int`の変更 できませんでした。
- 値の一覧 `nvs._key_map` で少し見えますが，全部ではないようでした。

Arduinoを使えばもっといろいろできるのかもしれませんが...
Slackに「あとで読む」と書いたらリマインドしてくれるbotを作った

![image-20221218094732659.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201348/9343550b-a571-1e35-9b66-bf0bd025a875.png)

# 背景

私は仲間内だけのSlackワークスペースや自分のtimesに「あとでよむ」という言葉と一緒に記事のURLを貼るような使い方をすることがときどきあります。

![image-20221218085949273.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201348/671167d7-24b6-dd7f-2a89-6fb6ea76dda4.png)

「あとでよむ」といいつつもしばらくしたら忘れかねないのでリマインドしてくれるやつがほしいなーと思っていて、Slack botの勉強を兼ねて作ってみました。




# 作ったもの

「あとでよむ」などの特定のワードが入ったメッセージがあると起動します

（:eyes:のemojiを付けさせることで動作したことがわかるようにしています）

![image-20221218085906903.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201348/d240c894-1221-8291-73f8-4acd943db656.png)




1時間後にリマインドのメッセージを送ります

（内部的にはイベント検知時に予約投稿しています）

![image-20221218094732659.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201348/9343550b-a571-1e35-9b66-bf0bd025a875.png)




「読んだ！」ボタンを押すと「お疲れ様でした！」と返します

![image-20221218100232619.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201348/0fc5ffff-8796-2a40-6931-6fc1da5f5863.png)
![image-20221218100150907.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201348/81ae0b89-2216-7e8e-a681-f82f3a1756d6.png)




「また1時間後にリマインド」ボタンを押すと再度1時間後にリマインドします

![image-20221218100818318.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201348/4695c5e5-35b4-38ea-5189-9d1f989910cc.png)
![image-20221218100832433.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201348/cc7afd6b-df89-47ee-7a54-55e35ad071d9.png)



## 中身の概要

[Slack Events API](https://api.slack.com/apis/connections/events-api) を使うとSlackでなにか動きがあるたびに通知してくれるので、これを利用しています。POSTメソッドを受け取るAPIを自分で用意してURLをSlackに登録することでイベントの情報を受け取っています。

emojiによるリアクションは[reactions.add](https://api.slack.com/methods/reactions.add)メソッドを、リマインドは[chat.scheduleMessage](https://api.slack.com/methods/chat.scheduleMessage)メソッドを使用して実現しています。

```mermaid
sequenceDiagram
    Slack->>MyAPI: メッセージを通知（Events API）
    MyAPI->>Slack: emojiでリアクション（reactions.add）
    MyAPI->>Slack: リマインドメッセージをセット（chat.scheduleMessage）
    Slack->>MyAPI: リマインドに対するユーザーのボタン操作
    MyAPI->>Slack: ユーザーの操作に応じて描画変更（chat.update）
```

メッセージ上のボタンに対するユーザーの操作に応じてAPIにPOSTリクエストが送られてくるため、API側でリクエストボディを見て対応する処理を行います（参考：[Creating interactive messages](https://api.slack.com/messaging/interactivity#components)）

具体的には、

- 「読んだ！」ボタンが押されたら[chat.update](https://api.slack.com/methods/chat.update)でメッセージを書き換える
- 「また1時間後にリマインド」ボタンが押されたら[chat.update](https://api.slack.com/methods/chat.update)した上でもう一度[chat.scheduleMessage](https://api.slack.com/methods/chat.scheduleMessage)でリマインドを設定する

としています。

## 中身の詳細

serverless frameworkを使ってAWS Lambda + API Gatewayの構成でAPIを作成しています

詳細はリポジトリをご覧ください

https://github.com/nigimitama/atode-reminder



# 現状の課題

リマインドメッセージは全員に見えるものなので、**リマインドを設定した人以外の人にボタンが押される可能性**があります…

とりあえず一旦そのままで性善説を信じて運用しています（/remindがbotから設定できるといいんですが）
Trello で、特定のステータスのタスク名一覧を取得したい

<!-----

Yay, no errors, warnings, or alerts!

Conversion time: 0.398 seconds.


Using this Markdown file:

1. Paste this output into your source file.
2. See the notes and action items below regarding this conversion run.
3. Check the rendered output (headings, lists, code blocks, tables) for proper
   formatting and use a linkchecker before you publish this page.

Conversion notes:

* Docs to Markdown version 1.0β34
* Sat Dec 17 2022 18:32:25 GMT-0800 (PST)
* Source doc: 2022-12-06 Trello で、特定のステータスのタスク名一覧を取得したい
* Tables are currently converted to HTML tables.
----->

## やりたいこと

ボード「My Tasks」に「TODO」というリストがあり、その中に「TaskA」「TaskB」「TaskC」というタスクがあるとき、以下のような出力を得たい


```
TaskA
TaskB
TaskC
```



## スクリプト

以下のように、curl と jq を利用して実現できる。



* list_id
* api key
* token

の 3つの情報が必要となる。取得方法は後述する。


```
curl --request GET \
  --url 'https://api.trello.com/1/lists/<list_id>/cards?key=<api key>&token=<token>' \
  --header 'Accept: application/json' \
  | jq -r '.[].name'
```



## list_id の取得

下記の方法で、対象としたいリストの ID を取得する。

[Trello API: getting boards / lists / cards information - Stack Overflow](https://stackoverflow.com/questions/26552278/trello-api-getting-boards-lists-cards-information)


## api key, token の取得

下記ページを参照して、 api key, token の情報を取得する。

[API Introduction (atlassian.com)](https://developer.atlassian.com/cloud/trello/guides/rest-api/api-introduction/)


## 余談

余談だが、私はここから更に、パイプをつなげてメールを送信している。


```
curl --request GET \
  --url 'https://api.trello.com/1/lists/<list_id>/cards?key=<api key>&token=<token>' \
  --header 'Accept: application/json' \
  | jq -r '.[].name' \
  | mail -s "Today's Task" -r <送信元アドレス> <宛先アドレス>
```



## Ref

API エンドポイントの情報


* [The Trello REST API (atlassian.com)](https://developer.atlassian.com/cloud/trello/rest/api-group-lists/#api-lists-id-actions-get)
* [jq Manual (development version) (stedolan.github.io)](https://stedolan.github.io/jq/manual/#Basicfilters)
* [[jq] 出力を JSON 形式ではなくプレーンテキストにする | DocumentRoot](https://documentroot.org/articles/output-raw-string.html)
* [mail(1): send/receive Internet mail - Linux man page (die.net)](https://linux.die.net/man/1/mail)
依存含む RPM パッケージを yum でローカルにダウンロードしたい

## 実現したいこと

あるパッケージをインストールする際に必要となる RPM パッケージをすべて手元にダウンロードしたい。

インターネットへの接続が行えない閉鎖環境に RPM ファイルを持ち込んでローカルインストールしたいというようなケースで、このような需要が発生する。

## 実現方法

`yum --downloadonly` オプションを利用することで実現できる。

以下コマンドを実行すると、 mariadb と、 mariadb が依存する mariadb-libs の RPM パッケージがダウンロードできていることがわかる。

```
$ sudo yum --downloadonly install mysql
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
...
Background downloading packages, then exiting:
No Presto metadata available for base
(1/2): mariadb-libs-5.5.68-1.el7.x86_64.rpm                                                        | 760 kB  00:00:01
(2/2): mariadb-5.5.68-1.el7.x86_64.rpm                                                             | 8.8 MB  00:00:02
--------------------------------------------------------------------------------------------------------------------------
Total                                                                                     3.3 MB/s | 9.5 MB  00:00:02
exiting because "Download Only" specified
```

パスは以下のように確認できる。

```
$ sudo find / -name mariadb-5.5.68-1.el7.x86_64.rpm 2>/dev/null
/var/cache/yum/x86_64/7/base/packages/mariadb-5.5.68-1.el7.x86_64.rpm
$ sudo find / -name mariadb-libs-5.5.68-1.el7.x86_64.rpm 2>/dev/null
/var/cache/yum/x86_64/7/base/packages/mariadb-libs-5.5.68-1.el7.x86_64.rpm
```

## 注意事項

なお、閉鎖環境に依存パッケージの一覧を持ち込んでローカル適用したいという場合、パッケージ取得のために可能な限り、本番環境と同様の環境を作成する必要があることに注意。

例えば、すでにインストール済みのパッケージはローカルインストールでパッケージがダウンロードされない。
これは依存パッケージについても同様である。

例えば先ほどの例において、すでに mariadb-libs をインストール済みの環境で同様のコマンドを実行すると、 mariadb-libs パッケージはインストールされない。

```
$ sudo yum install /var/cache/yum/x86_64/7/base/packages/mariadb-libs-5.5.68-1.el7.x86_64.rpm
Loaded plugins: fastestmirror
Examining /var/cache/yum/x86_64/7/base/packages/mariadb-libs-5.5.68-1.el7.x86_64.rpm: 1:mariadb-libs-5.5.68-1.el7.x86_64
...
Complete!
$ sudo rm -rf /var/cache/yum/*
$ sudo yum --downloadonly install mysql
Loaded plugins: fastestmirror
Determining fastest mirrors
...
Dependencies Resolved

==========================================================================================================================
 Package                     Arch                       Version                            Repository                Size
==========================================================================================================================
Installing:
 mariadb                     x86_64                     1:5.5.68-1.el7                     base                     8.8 M

Transaction Summary
==========================================================================================================================
Install  1 Package

Total download size: 8.8 M
Installed size: 49 M
Background downloading packages, then exiting:
mariadb-5.5.68-1.el7.x86_64.rpm                                                                    | 8.8 MB  00:00:10
exiting because "Download Only" specified
```

先ほどと異なり、mariadb-libs のパッケージが存在しないことが確認できる。

```
$ sudo find / -name mariadb-libs-5.5.68-1.el7.x86_64.rpm 2>/dev/null
$
```
システムの現状を知るためによく利用する rpm コマンド

## このファイルって、どのパッケージからインストールされてるんだっけ？

```
$ rpm -qf /etc/httpd/conf/httpd.conf
httpd-2.4.6-97.el7.centos.5.x86_64
```

## このパッケージにはどんなファイルが含まれるっけ？

```
$ rpm -ql httpd | head -n 5
/etc/httpd
/etc/httpd/conf
/etc/httpd/conf.d
/etc/httpd/conf.d/README
/etc/httpd/conf.d/autoindex.conf
```

## このパッケージが依存するパッケージやファイルは？

```
$ rpm -q --requires httpd | head -n 5
/etc/mime.types
system-logos >= 7.92.1-1
httpd-tools = 2.4.6-97.el7.centos.5
/usr/sbin/useradd
/usr/sbin/groupadd
```
Sphinxで画像を横並び表示

# はじめに

　最近はSphinxを使用することで便利にアウトプットできるようになりました。

　あまり体裁を気にすることはSphinxの方針に反するものだとは思いますが、
ブラウザをフルスクリーンで使用するような場面ではどうしてもグラフや画像を
横並びにして表示したくなり、その方法をまとめました。

# 環境

* Windows10
* Python 3.10
* Sphinx 5.3.0

# 方法

　figureとlist-tableを複合して、下記のように記載すると
横並びで表示できます。


```graph.rst
.. list-table::

    *   - .. figure:: ファイル名

            キャプション
        - .. figure:: ファイル名

            キャプション
```
Leetcode 739. Daily Temperatures

https://leetcode.com/problems/daily-temperatures/description/

# アプローチ
### 1. ~~Brute-force~~ → TLE
### 2. Stack

```java
package com.leetcode.midium;

import java.util.Stack;

public class DailyTemperatures739 {
    public static void main(String[] args) {
        int[] count = dailyTemperatures(new int[]{99, 99, 99, 99, 100});
        for (int i = 0; i < count.length; i++) {
            System.out.println(count[i]);
        }
    }

    // Stack
    public static int[] dailyTemperatures(int[] temperatures) {
        int length = temperatures.length;
        int[] count = new int[length];
        Stack<Integer> stack = new Stack<>();
        for (int now = 0; now < length; now++) {
            while (!stack.empty() && temperatures[now] > temperatures[stack.peek()]) {
                int pastIndex = stack.pop();
                int different = now - pastIndex;
                count[pastIndex] = different;
            }
            stack.add(now);
        }
        return count;
    }

    // Brute-force
    public static int[] dailyTemperatures_TLE(int[] temperatures) {
        int length = temperatures.length;
        int[] count = new int[length];
        for (int i = 0; i < length; i++) {
            for (int j = i + 1; j < length; j++) {
                if (temperatures[i] < temperatures[j]) {
                    count[i] = j - i;
                    break;
                }
            }
        }
        return count;
    }
}

```

- [こちら](https://leetcode.com/problems/daily-temperatures/solutions/109832/java-easy-ac-solution-with-stack/)解説を参考しました
[Swift] 画面遷移時にタブバーを非表示にする

## 前提
MainViewController→TransitionViewに遷移する際に、遷移先のTransitionViewでタブバーを非表示にしたい。
TransitionView→MainViewControllerに戻る際には、タブバーを再表示する。
## 実装内容
navigationViewControllerにTransitionViewをpushする前に、
MainViewControllerのhidesBottomBarWhenPushedをtrueに設定し、
push後にhidesBottomBarWhenPushedをfalseに設定。

```ruby: TransitionViewに遷移するコード
        self.hidesBottomBarWhenPushed = true  //push遷移前に設定
        self.navigationController?.pushViewController(transitionView, animated: true)
        self.hidesBottomBarWhenPushed = false  //push遷移後に設定
```
「スカラーポテンシャル」ってナンだ？

# はじめに
こんにちは、清水です。
意識のモデル化に興味があります。
そこで、物理で外界をどのようにモデル化しているかを知るために、つぎの輪読を行っています。

**「一般相対性理論を一歩一歩数式で理解する」 読書会 第9回、 §9　ポテンシャル** 
https://akbrobot.connpass.com/event/269485/

この中で、**スカラーポテンシャル** $f(x)$、**ベクトルポテンシャル** $B(x)$ がでてきます。数式からイメージしずらいので調べてみました。（意識ポテンシャルに向けて？）

　　　$A(x)=- \nabla$ $f(x)$　　　（ただし$\nabla \times A(x)=0$ ）
　　　$A(x)=- \nabla \times B(x)$　　　（ただし$\nabla \cdot A(x)=0$ ）

ここで、 $A(x)$ はベクトル場、$ \nabla $ はベクトル微分演算ナブラ$、 \times$ はベクトル積、$\cdot$ は内積です。

$ \nabla $ は形式的に、$(\frac{\partial \bf }{\partial x},\frac{\partial \bf }{\partial y},\frac{\partial \bf }{\partial z})$ を表しています。
$ \times$ は2つの３次元ベクトルから新たな３次元ベクトルを与える二項演算です。外積やクロス積とも呼ばれます。
ベクトル積を定義できるのは、**0次元、1次元、3次元、7次元ベクトル**だけのようです。機械学習で高次元（１万次元とか）のベクトル積は欲しくならないのだろうか？

# スカラーポテンシャルの定義　

（定理1.23）ベクトル場 $A(x)$ が、直方体の領域$R$全体で、$rot$ $A(x)=0$ となるとき、スカラー場 $f(x)$ が存在して、
$A(x)=-grad$ $f(x)=- \nabla$ $f(x)$ と表される。
$f(x)$ を**スカラーポテンシャル**という。

# スカラーポテンシャルの例
## 重力ポテンシャル
重力ポテンシャルは単位質量当たりの重力ポテンシャルエネルギーである。

$A(x)$ を重力ベクトル場、$f(x)$ を重力ポテンシャルとする。   
$g$ を重力加速度、$e3 = (0, 0, 1)$ を鉛直上向きの単位ベクトルとする。このとき

$A(x) = −ge3$ である。また、$A(x) = −∇(gx3)$ と書けるので、$f(x)=gx3$ となる。

## 電位ポテンシャル

電位は電場（単位電荷当たりの静電気力）に関連するスカラーポテンシャルである。この場合、電位は単位電荷当たりの静電ポテンシャルエネルギーである。
$A(x)$ を電場、$f(x)$ を電位ポテンシャルとする。   

# ベクトルポテンシャルの定義　

（定理1.24）ベクトル場 $A(x)$ が、直方体の領域$R$全体で、$div$ $A(x)=0$ を満たす時と、ベクトル場 $B(x)$ が存在して、
$A(x)=-rot$ $B(x)=- \nabla \times B(x)$ と表される。
$B(x)$ を**ベクトルポテンシャル**という。

# ベクトルポテンシャルの例
## 電磁ポテンシャル
電磁ポテンシャルは電磁場のポテンシャル概念で、スカラーポテンシャル$f(t,x) $とベクトルポテンシャル$B(t,x)$の総称である。

$E=-\nabla   f(t,x) - \frac{\partial \bf B(t,x)}{\partial t} $
$A=-\nabla \times B(t,x)$

ここで、$E$ は電場（電場の強度ベクトル）、$A$ は磁場（磁束密度ベクトル）である。
電磁ポテンシャルが電磁気の本質であって、電場や磁場は二次的なものらしい？
# おわりに

ベクトル場$A(x)$ を直接扱うのではなく、かわりに$A(x)$を導出するスカラーポテンシャル$f(x)$、ベクトルポテンシャル$B(x)$ を使用すると、話が**本質的で簡素**になることがあるようです。

例えば、4元ポテンシャルの使用により、マクスウェル方程式の等式数を４本から１本にできる。
https://ja.wikipedia.org/wiki/マクスウェルの方程式#マクスウェルの方程式と特殊相対性理論

いつか、意識ポテンシャルを定義できるか？

# 参考文献
一般相対性理論を一歩一歩数式で理解する 2017/3/27 石井 俊全

# 参考URL
数学解析第１　第１２回講義ノート　スカラーポテンシャル
https://www.math.keio.ac.jp/~iguchi/Lectures/pdf/2013/Note_MA_12.pdf

電磁ポテンシャル　果たしてこれは実在か？
https://eman-physics.net/electromag/potential.html

ベクトルポテンシャルとは何ぞや？
http://www.phys.u-ryukyu.ac.jp/~maeno/cgi-bin/pukiwiki/index.php?%A5%D9%A5%AF%A5%C8%A5%EB%A5%DD%A5%C6%A5%F3%A5%B7%A5%E3%A5%EB%A4%C8%A4%CF%B2%BF%A4%BE%A4%E4%A1%A9

七次元の外積
https://hooktail.sub.jp/vectoranalysis/SevenDCrossProd/

https://ja.wikipedia.org/wiki/ポテンシャル
https://ja.wikipedia.org/wiki/スカラーポテンシャル
https://ja.wikipedia.org/wiki/ベクトルポテンシャル
https://ja.wikipedia.org/wiki/電磁ポテンシャル
https://ja.wikipedia.org/wiki/クロス積
インフラ周りでお金をかけずに SSR したかった（AWS + Cloudflare）

SSR（Server Side Generation） というのをやってみたくて、Twitter のトレンドを時系列でチャート化するサイトを作った。
結局 SSR は必要なくて、SSG になっちゃったけど。

https://twitter-trend.ahyaemon.com/

見た目はこんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244354/8439e1b2-3148-edc8-2acf-a569520c6b75.png)

# 実現したかったこと

最近のツイッターのトレンド推移を把握できるサイトを作りたい。
トレンド情報は一時間に一度 Twitter API を叩いて取得する。
-> トレンド情報をどこかに保持しておく必要がある

# 実現方法の遷移

## 構成

### Backend + SSR
当初考えていたのは「Twitter API を叩いてレスポンスを保存しておくバックエンド」 + 「バックエンドを見にいく SSR サーバー」で、一時間毎の更新なら適当にフロント html のキャッシュ時間を長くしておけば良いかな、と言うもの。
予算の都合上バックエンドサーバーと SSR サーバーは同じ EC2 に置いた。
それぞれ Docker Image を作って ECR にプッシュしておいて、EC2 からプルして使う。
あとは Cloudfront のオリジンとして EC2 を使う形。

ここでドメイン周りが問題になった。
Cloudflare で管理してるドメイン（ahyaemon.com）のサブドメインを Route53 で管理したかったんだけど、Cloudflare の無料範囲内でそれができない？っぽかった（自分のやり方が悪かっただけかも知れない）。
Cloudflare 側で SSR できないかとも思ったけど、対応してるフロントエンドのフレームワークが Remix だけみたいなのをどこかで読んで、面倒いなと思ってしまった。


### Backend + SSG

色々考えた結果、一時間に一回 SSG したほうが楽かなーという結論に至った。
で、一つの EC2 内にバックエンドサーバーと SSG サーバーを置き、cron で一時間毎に SSG してた。
`next export` して、その結果を S3 に置いた。

でも流石に t2micro の力ではそれを支えきれなかったみたいで、CPU クレジットを使い果たして瀕死になる事態が多発した。
実際は ssh で入ってなんやかんや試してる時に瀕死になってたんだけど、そういう試行錯誤が頻繁に中断されるのも微妙だからやり方を変える必要があった。

そこで、SSG は別の場所でやることにした。
定期実行だから ECS Fargate でやればいいかなと思ったんだけど、EC2 バックエンドサーバーとの通信が上手くいかず途方に暮れた。
あと ECS だと pull の時間がオーバーヘッドになるんじゃないかと言う不安。
あと Fargate は無料枠だと使えない。

結局、家で眠っていた MacBook Air に定期実行させるという最終手段に落ち着いた。
多分 Fargate を使うよりもマックつけっぱの電気代のほうが安いはず、、

あと何処かの時点で S3 ではなく Cloudflare R2 を使うようにした。
`aws s3` コマンドで R2 にプッシュできたのは感心した。

フロント系は全て Cloudflare でなんとかなったので、 Route53 と CloudFront もやめた。
Route53 に微妙にお金が掛かってたから良かった。

# 最終的な構成とか技術スタック

SSG とバックエンドとインフラの Terraform を全部ひっくるめてモノレポにしたけど、個別でデプロイしたい時にめんどかったりするから分けるかも知れない。

# フロントエンド

- React
- Next
    - ローカルマックから launchctl で定期的に SSG
        - SSG 結果は Cloudflare R2 にプッシュ
- TypeScript
- MUI
- Recharts
- ドメイン周りは Cloudflare

# バックエンド

- Kotlin
- SpringBoot
    - @Scheduled を使って定期的に Twitter API を叩く
        - 取ってきたデータは DB じゃなくてメモリに置いておくと言う暴挙
    - @Controller でエンドポイントを用意
- EC2
    - docker build して、ECR プッシュして、EC2 にプルして起動するまでを github actions で実行

# おわりに

家のマックの充電器の数がマックの数より少ないため、取り合いになる。
LunarVim使ってみた Part2 :null-lsのroot_dirを変える

前回[「LunarVim使ってみた」](https://qiita.com/kokardy/items/4efa3723abbfe820303d)の続き

# null-lsのroot_dirを変えるのに苦労した話

## TL; DR
```config.lua
lvim.lsp.null_ls.setup.root_dir = function(fname)
  local util = require "lspconfig.util"
  local root_files = {
    "pyproject.toml",
    "setup.py",
    "setup.cfg",
    "requirements.txt",
    "Pipfile",
    "manage.py",
    "pyrightconfig.json",
  }
  return util.root_pattern(unpack(root_files))(fname) or util.root_pattern ".git" (fname) or util.path.dirname(fname)
end
```

設定書くとこれだけなんだけど、設定の仕方が見つけられず、
timeoutを変更する方法が
`lvim.lsp.null_ls.setup.timeout= 5000` だよ
というタイムアウトに関するissueのコメントを見つけて予想して書いたらうまくいった

結論: LunarVimのドキュメントにない設定変更は、プラグインのドキュメント見てもわからんのでとても苦労する。

## 経緯

自分用競プロ用のリポジトリがこんな構成

```
competitive
├── README.md
├── .git
├── go
│   └── 省略
└── python
    ├── pyproject.toml
    ├── src
    │   ├── BIT.py
    │   ├── __init__.py
    │   ├── bsearch.py
    │   ├── combination.py
    │   ├── factorial.py
    │   ├── primes.py
    │   ├── tree.py
    │   └── unionfind.py
    ├── tests
    │   ├── BIT_test.py
    │   ├── __init__.py
    │   ├── bsearch_test.py
    │   ├── combination_test.py
    │   ├── factorial_test.py
    │   ├── primes_test.py
    │   ├── tree_test.py
    │   └── unionfind_test.py
    └── typings
```

null-lsでpflake8を設定しても、pyproject.tomlの設定値を読んでくれない。

## 原因調査


1. コマンドラインで `pflake8` 実行すると期待通りなので`pyproject.toml` は悪くない
1. `pyproject.toml` を1個上の階層、つまり、`competitive` 直下に置くとうまくいく
1. つまり、 `.git` がある場所がrootとして認識されているっぽい
1. よっしゃ `null-ls` の root_dir判定の設定を変えればいけるはず

## で、どう書いたらいいん？

もちろん、LunarVimのnull-lsのセットアップしてる処理にnull-lsのLSPの設定方法通り直接かけばうまくいった。
でも、そこはLunarVimのアップデートで書き換わる部分なわけで。
`config.lua` にどうかけばいいのかというのがどこにも書いてない。

printfデバッグして、setup処理より前にconfig.luaが実行されているのは確認したけど、
LunarVimがデフォルトで設定するnull-lsの設定値を変えたりしてもうまく行かない。
(luaをpandoc filter書く時とvimの設定するときしか使わないので知識も足りてない)

ググってもroot_dirの件はpyrightのしかひっかからない。
他のLSP設定の仕方をまねてやってみたけど、setupに渡したオプションは反映されない。

最終的に[timeoutの変え方](https://github.com/LunarVim/LunarVim/discussions/2767#discussioncomment-3080103)を見て、rood_dirに変えてみたらうまく行った。

## 結論

Pluginに詳しくなかった自分としては、LunarVim美味しいとこどりしてあって気に入ってたんだけど、
細かい設定を変えようとすると使ってる人少ないし、けっこう苦労する。

Vimの入口としてはけっこういいから、LunarVimの使ってるpluginでいい感じのをneovimのinit.luaに輸入していく感じがいいかもしれない。
chikkarpyで使える同義語辞書の書き方

こちらの記事でchikkarpyの使い方について説明してあります。

https://qiita.com/katsuta/items/fcfb45cc372b65efb869

今回はそのchikkarpyで使う同義語辞書を自作する方法について紹介します。

# 同義語辞書のフォーマットについて
まず同義語辞書の内容について軽く説明をしておくと、この辞書のフォーマットでは以下の情報がcsv形式で付与できます。
> 0 : グループ番号
1 : 体言/用言フラグ (省略可)
2 : 展開制御フラグ (省略可)
3 : グループ内の語彙番号 (省略可)
4 : 同一語彙素内での語形種別 (省略可)
5 : 同じ語形の語の中での略語情報 (省略可)
6 : 同じ語形の語の中での表記ゆれ情報 (省略可)
7 : 分野情報 (省略可)
8 : 見出し
9 : 予約
10 : 予約

[Sudachi 同義語辞書](https://github.com/WorksApplications/SudachiDict/blob/develop/docs/synonyms.md)から引用

同義語辞書を作成する際に、chikkarpyが使う情報は`0,1,2,8`のカラムのみとなるので他は無視して大丈夫です。
8は見出し語となるので必須で、その他 0:グループ番号, 1:体言/用言フラグ, 2:展開制御フラグについて説明しています。

# 同義語辞書の作成

## グループ番号について
同義語辞書の作成で一番重要な情報がグループ番号となります。
グループ番号が同じであれば同義語としてchikkarpyが出力してくれます。

例えば以下のような辞書を作ると、
```bash
$ cat sysnonym_dict.csv
000001,1,0,0,0,0,0,,金,,
000001,1,0,0,0,0,0,,現金,,
000001,1,0,0,0,0,0,,キャッシュ,,

$ chikkarpy build -i synonym_dict.csv
(略)
$ echo "金" | chikkarpy -d synonym.dic 
金      現金,キャッシュ
```
同じグループ内の単語を検索できています。

さらに、金の別の意味を同義語グループとして追加してみましょう。
すると以下のような動作になります。

```bash
$ cat sysnonym_dict.csv
000001,1,0,0,0,0,0,,金,,
000001,1,0,0,0,0,0,,現金,,
000001,1,0,0,0,0,0,,キャッシュ,,

000002,1,0,0,0,0,0,,金,,
000002,1,0,0,0,0,0,,金色,,

$ chikkarpy build -i synonym_dict.csv
(略)
$ echo "金" | chikkarpy -d synonym.dic 
金      現金,キャッシュ,金色
$ echo "キャッシュ" | chikkarpy -d synonym.dic 
キャッシュ      金,現金
$ echo "金色" | chikkarpy -d synonym.dic 
金色    金
```
金に対して2つの同義語グループを作りましたが、金からは「現金, キャッシュ, 金色」が検索できており、「現金」から「金色」(逆も然り)が同義語として検索に引っかからないようになっています。

この様に、同義語辞書はグループ番号で管理されています。

## 体言/用言フラグ
次に、体言/用言フラグについてです。「1:体言, 2:用言」を表しています。
これはその見出し語が体言か用言であるかを表すフラグとなっており、体言から用言が検索に出ないように抑制するためのフラグです。体言と用言を同じ同義語グループに入れない場合や品詞による出し分けをする必要がなければ気にする必要はありません。すべて「1」にしておけば辞書として使うことができます。

例としては以下の通りです。
```bash
$ cat sysnonym_dict.csv
000001,1,0,0,0,0,0,,会計,,
000001,1,0,0,0,0,0,,勘定,,
000001,2,0,0,0,0,0,,支払う,,

$ chikkarpy build -i synonym_dict.csv
(略)
$ echo "会計" | chikkarpy -d synonym.dic 
会計    勘定
$ echo "会計" | chikkarpy -d synonym.dic -ev
会計    勘定,支払う
```
体言/用言フラグを使うと普通に検索する場合は「会計」からは「支払う」が出てきませんが、`-ev`フラグによって用言の検索を可能にできるので、状況によって出し分けることができます。

## 展開制御フラグ
最後に、展開制御フラグについてです。「0:抑制なし, 1:抑制あり」となります。
語義の曖昧性が大きい単語に対して複数の同義語グループに展開させることを抑制する場合に使います。

```bash
$ cat sysnonym_dict.csv
000001,1,1,0,0,0,0,,cod,,
000001,1,0,0,0,0,0,,CoD,,
000001,1,0,0,0,0,0,,Call of Duty,,

000002,1,1,0,0,0,0,,cod,,
000002,1,0,0,0,0,0,,COD,,
000002,1,0,0,0,0,0,,化学的酸素要求量,,

$ chikkarpy build -i synonym_dict.csv
(略)
$ echo "cod" | chikkarpy -d synonym.dic
cod
$ echo "COD" | chikkarpy -d synonym.dic
COD     cod,化学的酸素要求量
```
"000001,1,**1**,0,0,0,0,,cod,,"のように展開制御フラグが1となっているため、「cod」をキーとして同義語検索がされないようになっています。ほかの単語から「cod」は検索できます。

# まとめ
以上、同義語の書き方の紹介でした。
今回は自作する方法を紹介しましたが、ワークスでは同義語辞書を人手で作って更新もしています。是非使ってみてください。
http://sudachi.s3-website-ap-northeast-1.amazonaws.com/sudachisynonym/
データサイエンス100本ノック①～⑩

# データサイエンス100本ノック（構造化データ加工編）
練習のためにPythonで100本ノック始めました。
記録として残していきます。

スタート：2022.12

https://github.com/The-Japan-DataScientist-Society/100knocks-preprocess

GitHubにColaboratoryが用意されているので、自分のドライブにコピーするだけで簡単に始められます。

# 解答
※協会が出している書き方と同じではありません
※コードの書き方はいくつもあるので、出力としては同じものが出るようになっています

### P001
>レシート明細データ（df_receipt）から全項目の先頭10件を表示し、どのようなデータを保有しているか目視で確認せよ。
```Python:P001
df_receipt.head(10)
```

### P002
>レシート明細データ（df_receipt）から売上年月日（sales_ymd）、顧客ID（customer_id）、商品コード（product_cd）、売上金額（amount）の順に列を指定し、10件表示せよ。
```Python:P002
df_receipt.head(10)[['sales_ymd','customer_id','product_cd','amount']]
```

### P003
>レシート明細データ（df_receipt）から売上年月日（sales_ymd）、顧客ID（customer_id）、商品コード（product_cd）、売上金額（amount）の順に列を指定し、10件表示せよ。ただし、sales_ymdsales_dateに項目名を変更しながら抽出すること。
```Python:P003
df_receipt.head(10)[['sales_ymd','customer_id','product_cd','amount']].rename(columns = {'sales_ymd' : 'sales_date'})
```

### P004
>レシート明細データ（df_receipt）から売上日（sales_ymd）、顧客ID（customer_id）、商品コード（product_cd）、売上金額（amount）の順に列を指定し、以下の条件を満たすデータを抽出せよ。
顧客ID（customer_id）が"CS018205000001"
```Python:P004
df_receipt.query('customer_id == "CS018205000001"')[['sales_ymd','customer_id','product_cd','amount']]
```

### P005
>レシート明細データ（df_receipt）から売上日（sales_ymd）、顧客ID（customer_id）、商品コード（product_cd）、売上金額（amount）の順に列を指定し、以下の全ての条件を満たすデータを抽出せよ。
顧客ID（customer_id）が"CS018205000001"
売上金額（amount）が1,000以上
```Python:P005
df_receipt.query('customer_id == "CS018205000001" and amount >= 1000')[['sales_ymd','customer_id','product_cd','amount']]
```
### P006
>レシート明細データ（df_receipt）から売上日（sales_ymd）、顧客ID（customer_id）、商品コード（product_cd）、売上数量（quantity）、売上金額（amount）の順に列を指定し、以下の全ての条件を満たすデータを抽出せよ。
顧客ID（customer_id）が"CS018205000001"
売上金額（amount）が1,000以上または売上数量（quantity）が5以上
```Python:P006
df_receipt.query('customer_id == "CS018205000001" and (amount >= 1000 or quantity >= 5)')[['sales_ymd','customer_id','product_cd','amount']]
```
### P007
>レシート明細データ（df_receipt）から売上日（sales_ymd）、顧客ID（customer_id）、商品コード（product_cd）、売上金額（amount）の順に列を指定し、以下の全ての条件を満たすデータを抽出せよ。
顧客ID（customer_id）が"CS018205000001"
売上金額（amount）が1,000以上2,000以下
```Python:P007
df_receipt[['sales_ymd','customer_id','product_cd','amount']].query('customer_id == "CS018205000001" and (2000 >= amount >= 1000)')
```
### P008
>レシート明細データ（df_receipt）から売上日（sales_ymd）、顧客ID（customer_id）、商品コード（product_cd）、売上金額（amount）の順に列を指定し、以下の全ての条件を満たすデータを抽出せよ。
顧客ID（customer_id）が"CS018205000001"
商品コード（product_cd）が"P071401019"以外
```Python:P008
df_receipt[['sales_ymd','customer_id','product_cd','amount']].query('customer_id == "CS018205000001" and product_cd != "P071401019"')
```
### P009
>以下の処理において、出力結果を変えずにORをANDに書き換えよ。
```df_store.query('not(prefecture_cd == "13" | floor_area > 900)')```
```Python:P009
df_store.query('prefecture_cd != "13" and floor_area <= 900')
```
これはドモルガンの法則ですね。

### P010
>店舗データ（df_store）から、店舗コード（store_cd）が"S14"で始まるものだけ全項目抽出し、10件表示せよ。
```Python:P010
df_store[df_store['store_cd'].str.startswith('S14')]
```

# 感想
ここらへんまではあまり悩まずに書けました。
dataframeから特定の列の抽出の仕方はqueryを使用する方法に慣れるのがオススメです。
検索すると[[]]を使用する方法が出てきがちなので自分自身もqueryを使い慣れていないなぁと実感しました。
ReactでonClickを引数付きで呼び出したいけど動かない場合

# onClickを引数つけて呼び出したけど動かない
私は最初以下のようにして呼び出してました。
```
const check=(name)=>{
   console.log(name)
}
return(
    <p className="name" onClick={check("たけし")}>たけし</p>
)
```
しかしこれではconsole.logが読み込み時に動いてしまい、onClickが適応されているたけしを押しても何も反応せず、コンソールも何も表示されません
# 解決方法
次のように書くことで解決しました。
```
const check=(name)=>()=>{
   console.log(name)
}
return(
    <p className="name" onClick={check("たけし")}>たけし</p>
)
```
１行目のcheck「=(id)=>」が「=(id)=>()=>」に変わっていますね
これでたけしをクリックすると「たけし」がコンソールに現れます！

正直なぜこれで動くのか詳しい原理は分かっていませんが、解決方法としてもし同じようなことで詰まっている方がいらっしゃったらこの記事が力になれば幸いです。
docker-composeでcifs(smb)をマウントする

# docker-composeでcifs(smb)をマウントする

[docker自体にcifsをマウントする仕組みがあるため](https://matsuand.github.io/docs.docker.jp.onthefly/storage/volumes/)、コンテナには別途パッケージを追加することなく使えます

```yaml
version: '3'
services:
  hoge-service:
    image: ubuntu:latest
    volumes:
      - my-smb:/smb

volumes:
  my-smb:
    driver_opts:
      type: cifs
      o: "username=user,password=password"
      device: "//192.168.1.1/hoge"
```

## ポイント
* 接続対象には生のipアドレスを指定する必要がある
    * ホスト名では名前解決出来ずに繋がらない

## 参考
https://matsuand.github.io/docs.docker.jp.onthefly/storage/volumes/
https://stackoverflow.com/questions/66921235/smb-cifs-volume-in-docker-compose-on-windows
https://blog.cles.jp/item/12831
Ruby+MechanizeでjsonデータをPOSTする方法

## 概要
Ruby+MechanizeでPOSTリクエストをしようと思ったのですが、調べてみるとフォームを選択して...ってやり方がたくさん出てきたので、そうではなく純粋なpostリクエストをする方法を紹介する

## だめだった例
### パターン1
自分がやってみて行けそうだったけどだめだった書き方
```rb
require 'mechanize'

agent = Mechanize.new
payload = {
  text: 'こんにちわ'
}
page = agent.post('https://xxx.yyyy.zzz', payload)
```
一見POSTできそうなのですが、
```
/var/task/vendor/bundle/ruby/2.7.0/gems/mechanize-2.8.5/lib/mechanize/http/agent.rb:333:in `fetch': 400 => Net::HTTPBadRequest for https://xxx.yyyy.zzz -- unhandled response (Mechanize::ResponseCodeError)
```
これではだめでした...

### パターン2
次に試したのがpayloadのデータを`to_json`する方法
```rb
require 'mechanize'
require 'json'

agent = Mechanize.new
payload = {
  text: 'こんにちわ'
}
page = agent.post('https://xxx.yyyy.zzz', payload.to_json)
```
これも同様のエラーが出てだめでした
```
/var/task/vendor/bundle/ruby/2.7.0/gems/mechanize-2.8.5/lib/mechanize/http/agent.rb:333:in `fetch': 400 => Net::HTTPBadRequest for https://xxx.yyyy.zzz -- unhandled response (Mechanize::ResponseCodeError)
```

## うまくいったコード
```rb
require 'mechanize'
require 'json'

agent = Mechanize.new
payload = {
  text: 'こんにちわ'
}
page = agent.post('https://xxx.yyyy.zzz', payload.to_json, {'Content-Type' => 'application/json'})
```
失敗2にプラスして`Content-Type`を指定しました。

これで問題なくPOSTできました！！
Udemy英語教材のすゝめ

# 序文
「天は人の上に人を造らず人の下に人を造らず」と言えり。されども言語においてはその限りにあらず、広くこの人間世界を見渡すに、教材が豊富な言語あり、貧相な言語もありその有様雲と泥どろとの相違あるに似たるはなんぞや。その次第はなはだ明らかなり。

# 本記事で説明すること

Udemyの英語教材くそおすすめ

# Why?
もちろん日本語のコンテンツも良質なものはたくさんありますが、いくつか受けた感想では英語教材は教材の質量共に圧倒的に優っていると思います。

**量**

「AWS」で検索をかけた時の画像です。
![スクリーンショット 2022-12-04 23.21.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1059259/a3489f8d-6c16-4f0a-3e80-344464a0820b.png)

英語が4000件を超えているのに対し、日本語は261件です。
もちろん「量が多い = 良い」訳ではないですが、分母が多く選択肢があるというのは教材を選択する際にプラスであることは間違い無いでしょう。

**質**

質に関しては定量的に測れないため紹介は難しいですが、一つの目安として教材の長さと評価を紹介します。

こちらはReactの英語教材で検索をかけ、一番上に出てきた教材です。
![スクリーンショット 2022-12-04 23.27.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1059259/97927f9e-d3ed-4d03-7447-9d04d59408da.png)

合計時間49.5時間です。セール時では2000円くらいで買えます。ここまで長い教材は日本語教材ではほとんどありません。
もちろんこちらも「長い = 良い」訳ではありませんが、長い教材の方が幅広い分野まで網羅していることは間違い無いでしょう。

また、個人の感想になってしまいますが英語教材の方が以下の点関して圧倒的に優れていると感じています。
- 丁寧な説明
- 幅広い分野に対する講師の理解力
- 初級から中級レベルまでを対象とした幅広い解説

# せやかて英語じゃん

それはもうその通りなんですが、普段英語のドキュメント読んでる方なら結構抵抗なく理解できるのでは無いかと思います。
- 講師の方も英語ネイティブではない人が多い
    - これは持論ですが、ネイティブの英語が一番聞き取りづらいと思っています。その一方でUdemyの講師はフランス人やドイツ人やインド人など幅広い国籍の方々が講師をしており、英語の教材を出しております。彼らももともと外国語として英語を学んでいるので、文法が丁寧であったりスラングを使っていなかったりと、外国人の私たちにも理解しやすい話し方をしてくれます。
- 使っている単語が限られる
    - エンジニアリングをする上で、使用する英単語は日常会話の英単語よりもはるかに少ないと考えています。そのため英語のドキュメントを読める程度の英語力があれば、教材の英語もそれほど苦労しないと思います。
- 自動生成の字幕が優秀。
    - 自動生成の字幕が非常に優秀で、リスニングが苦手でも精度の高い字幕をリアルタイムで確認できます。また、日本語字幕がある教材もあるのでそういった教材を選べば英語がわからなくても理解することができると思います。

# おすすめ講座

### The Complete JavaScript Course 2023: From Zero to Expert!
https://www.udemy.com/course/the-complete-javascript-course/

JavaScriptの教材。教材の長さ69時間ってもう意味わからん。
これが良すぎてこの講師の方が出しているNode.jsの講座も買いました。

### Ultimate AWS Certified Solutions Architect Associate SAA-C03
https://www.udemy.com/course/aws-certified-solutions-architect-associate-saa-c03/

AWSの教材といえばこの方、というくらい教材出している。
この方がいなければソリューションアーキテクトプロフェッショナルは取れなかった。

### React - The Complete Guide (incl Hooks, React Router, Redux)
https://www.udemy.com/course/react-the-complete-guide-incl-redux/

Reactの教材。Reactの教材とはよく言ったもので、実際はRedux、Typescript、Jestなども教えてくれる。神。

# まとめ
とりあえず騙されたと思って買ってみ。Udemyは30日の返金保証もあるし。
ABC282回答メモ

0.はじめに
　Cまでは簡単だけどD以降異次元の難しさ。
　Cでもちょっとてこずって結局Cまででレート-14でした。

1.A - Generalized ABC
　先週丁度A~Zの文字列を使ってたので、それを利用して
　K文字分先頭から表示してACでした。

　https://atcoder.jp/contests/abc282/submissions/37325486

2.B - Let's Get a Perfect Score
　Bにしては、ややこしい問題でした。
　なんとなく論理和とか使うとよいのかなと思いつつ
　まぁB問題なので、単純に全組合わせで
　全問正解するかをチェックしてカウントする仕様で実装しました。

　https://atcoder.jp/contests/abc282/submissions/37333475

3.C - String Delimiter
　文字列を頭からチェックしつつ回答文字列に転記していき
　ダブルコーテーションの時フラグオン
　”,”の時、フラグがオンなら”.”に置き換えて転記
　と、単純な実装。
　テスト環境で、20万文字でも問題なく行けたので
　提出したらLTEに。
　いつも高速になるかなーとpypy3で提出しているけど
　試しにPython3で提出したらAC。
　ちゃんとコードテストで時間も見ないとなと思いました。

　https://atcoder.jp/contests/abc282/submissions/37340369

4.D - Make Bipartite 2
　苦手なタイプな問題だ・・・と思いましたが、E以降もまぁ行ける気は
　しなかったのでググりながら挑戦。
　
　多重辺・・・かってに辺を直線イメージでしたが、曲がるのもありの場合に
　　　　　　　２つの点に2本の辺があるイメージの事と理解
　二部グラフ・・・問題文の説明をググってさらに理解を深め
　　　　　　　　　合わせてpythonでの二部グラフチェックロジックも頂く

　【考え方】
　　１）問題のグラフについて、色分けをする
　　２）各点の組み合わせ毎に同じ色ではないか、つなぐ辺がないかをチェック

　まあ、LTE＆REでした。
　REは再帰の深さ設定を変えることでクリアしました。　　

　その後、各点を白組黒組に分けてチェックしたりと工夫を重ねるも
　LTE等で時間終了。

　終了後、解説を見ると、色分け後、各点毎チェックではなく　
　１）色分け情報をもとに、不足辺を求めるという考え方
　２）グラフは1つの固まりではないという考え方

　が必要と分かり、方向性も間違っていたことを知って
　一日を終えました・・・。

以上
AnsibleでNewRelic Infrastructure Agentを導入する

## 前提
- ホストは**AWS EC2 (Amazon Linux2)**
- NewRelicでAPI Keyを発行済みである


## playbookを作成

```yaml
- hosts: ec2-instance
  become: yes
  environment:
    NEW_RELIC_ACCOUNT_ID: "{{ account_id }}"
    NEW_RELIC_API_KEY: "{{ license_key }}"
  tasks:
  - name: インストール実行シェルの取得
    ansible.builtin.uri:
      url: https://download.newrelic.com/install/newrelic-cli/scripts/install.sh
      return_content: yes
    register: nrinstall
  - name: インストール実行シェルの実行
    ansible.builtin.shell:
      cmd: /usr/local/bin/newrelic install
      stdin: nrinstall.content
```


上記のplaybookは、以下のコマンドを入力した時と同じ結果が得られるコードとなっている。

`curl -Ls https://download.newrelic.com/install/newrelic-cli/scripts/install.sh | bash && sudo NEW_RELIC_API_KEY=NRAK-XXXXXXXXXX NEW_RELIC_ACCOUNT_ID=0000000 /usr/local/bin/newrelic install
`

**ansible.builtin.uri**でインストール実行用のシェルスクリプトを取得し、
`register`で指定した変数(nrinstall)に取得したコンテンツを格納する。

**ansible.builtin.shell**のstdinで取得したコンテンツ（シェルスクリプト）を読み込んだ上で、cmdで指定したコマンドを実行する。

以上のような記述方法で、curlでスクリプトを取得 + 取得したコンテンツを読み込んだ上でコマンド実行といった、パイプさせた処理を行うことができる。


## Ansible Galaxyを使う

Ansible Galaxyでnewrelic-infraをインストールするRoleがあるのでそっちを使うとはやい

https://galaxy.ansible.com/newrelic/newrelic-infra

ただし、動作環境によってはエラーが発生することもあるので、playbookを自作するのもアリ。

## 参考

https://docs.ansible.com/ansible/latest/collections/ansible/builtin/shell_module.html

https://ymotongpoo.hatenablog.com/entry/2021/03/01/224610
Adaloについての初歩的な知識

# ジャンル
　ノーコードのウエブアプリ、モバイルアプリ開発

# プラットホーム

1. ウエブ版

# 価格 (USD)

1. Free
    - ウエブ公開
    - アプリアクション 1,000/月
    - アプリ発行 0
    - テストアプリ　無制限
    - 共同編集 1名
    - データストレージ 200レコード/アプリ
    - アプリ画面　無制限
    - マーケットプレイスコンポーネントの利用
1. Starter ($45/月)
    - ウエブ公開
    - カスタムドメイン
    - App Store、Google Playストアへの公開
    - アプリアクション 10,000/月
    - アプリ発行 1
    - テストアプリ　無制限
    - 共同編集 1名
    - データストレージ 1チームあたり５GB
    - アプリ画面　無制限
    - フォントライブラリ
    - プッシュ通知
    - マーケットプレイスコンポーネントの利用
1. Professional ($65/月)
    - ウエブ公開
    - カスタムドメイン
    - App Store、Google Playストアへの公開
    - アプリアクション 30,000/月
    - アプリ発行 2
    - テストアプリ　無制限
    - 共同編集 5名
    - データストレージ 1チームあたり25GB
    - 外部データベースコレクション
    - Google Map
    - アプリ画面　無制限
    - フォントライブラリ
    - プッシュ通知
    - バージョン管理
    - ジオロケーション
    - マーケットプレイスコンポーネントの利用
1. Team ($200/月)
    - ウエブ公開
    - カスタムドメイン
    - App Store、Google Playストアへの公開
    - アプリアクション 100,000/月
    - アプリ発行 5
    - テストアプリ　無制限
    - 共同編集 10名
    - データストレージ 1チームあたり125GB
    - 外部データベースコレクション
    - Google Map
    - アプリ画面　無制限
    - フォントライブラリ
    - プッシュ通知
    - バージョン管理
    - ジオロケーション
    - マーケットプレイスコンポーネントの利用
1. Business ($250/月)
    - ウエブ公開
    - カスタムドメイン
    - App Store、Google Playストアへの公開
    - アプリアクション 1,000,000/月
    - アプリ発行 10
    - テストアプリ　無制限
    - 共同編集 無制限
    - データストレージ 1チームあたり500GB
    - 外部データベースコレクション
    - Google Map
    - アプリ画面　無制限
    - フォントライブラリ
    - プッシュ通知
    - バージョン管理
    - ジオロケーション
    - マーケットプレイスコンポーネントの利用

https://ja.adalo.com/pricing#chart

　無料アカウントでは、無制限のアプリを作成することができますが、Adaloドメイン上で、アプリにAdaloブランディングが表示され、データは200行までとなります。自分で楽しむくらいのアプリは作れそうです。有料版になると、カスタムドメインが使用でき、App Store、Google Playストアで公開できるのが魅力ですね。App Storeは、Adaloに限ったことではないですが、1回でパスすることは難しく、何度も修正が必要になるでしょう。

# 概要
　David Adkinは、建築学の修士課程でデザインを理解することが重要なスキルであると感じました。新しいものを創造する力こそ最終的に成功するスキルになるはずと、技術系スタートアップでUXデザインからプロダクト、ブランディングまでを学びました。

　UXデザインの世界では、コードを書けなければ本物のUXデザイナーではないという風潮でしたが、Davidはコードの書き方を知りませんでした。学習する時間もなく、デザイナーが皆そうであるように彼も完璧主義者なので、自在にコードが書ける様になるには長い時間が必要で、その頃には誰かがデザインツールをもっと使いやすくしているはずだと考えました。そして、いつか誰かがやるのなら、今自分が始めようということで、エンジニアリング担当Jeremy Blalock、デザイン担当David Adkin、プロダクトとオペレーション担当Ben Haefeleのチームによって2018年にミズーリ州セントルイスでAdaloが設立されました。

　Adaloはコードを1行も書かずに、リスト、フォーム、ボタン、ナビゲーションなど、美しくデザインされたコンポーネントを利用してアプリのインターフェイスを作成することができます。ページのリンク、プッシュ通知、ログインなどのアクションやサードパーティとの連携でアプリが豊かなものとなり、ビルトインのデータベースや、外部データベースを使って、データドリブンのアプリの作成ができます。

　Adaloは、2019年11月にローンチして以来、2021年5月時点では22万人のユーザーを獲得しており、そのうち約1,000名が有料プランを利用しています。

# 機能
 サンプルを展開してみると、あまりに良くできているのでびっくりです。このようなツールを使い慣れている方は、サンプルをいじって学ぶのが早いかもしれませんし、初心者なら1から作ってみるといいかもしれません。
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/ba68b702-5816-8d87-10da-f32aa8ca364f.png"/>

　チュートリアル・ビデオがYoutubeに上がっているいるので、日本語字幕を見ながら学習ができます。

<a href="https://www.adalo.com/learn"><img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/ee30775d-8ae4-70f2-17c4-39a76e7b18ec.png"/></a>

https://www.youtube.com/@Adalo/videos

　また、その他にも学習用のビデオやドキュメントがたくさん見つかりますので、初心者でも始めやすいと思います。
イーサリアム 2.0：The Merge の意義

2022年9月15日15時ごろ、イーサリアムの大型アップグレード The Merge が完了しました。
The Merge は、イーサリアムエコシステムに対して非常に重要なので、その内容を紹介します。

https://twitter.com/VitalikButerin/status/1570306185391378434?s=20&t=8hnI5tabERoHxu2J4agg_A

## The Merge とは
[イーサリアム 2.0：ロードマップ概観](https://qiita.com/blueplanet/items/d935b0eba7f0a8887c01) のロードマップに書かれてありますが、The Merge は、主にイーサリアムのコンセンサスアルゴリズムを PoW から PoS への移行です。

![Screen Shot 2022-12-18 at 8.58.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4777/c6c78c04-1bc2-7ee5-fa68-38dabed712e6.png)
引用元：https://twitter.com/VitalikButerin/status/1588669782471368704?s=20&t=ZtLG5cL_rLK0aUSAe1ypTA

この移行で、もともと並走していたビーコンチェーンとイーサリアム 1.0 のメインネットのチェーンは、合体して一緒に稼働するようになりました。

![](https://camo.githubusercontent.com/12063b5815ef4b66d0f58fb8bb06d24840b0b24b20343547749cd27e4216c6d9/68747470733a2f2f692e696d6775722e636f6d2f75645a6c6b51722e706e67)

引用元：https://github.com/ethereum/annotated-spec/blob/master/merge/beacon-chain.md

２つのチェーンで稼働するというのは、
- ビーコンチェーンが `コンセンサスレイヤー` としてコンセンサス処理（PoS）を実行する
- もともとのイーサリアムメインチェーンは、シャードチェーンとして、コンセンサス処理をなくし、トランザクションの処理・スマートコントラクトの実行などの `実行レイヤー` として稼働する

ようになっています。

|             |The Merge の前|The Merge の後|
|-------------|:-------------:|:--------------:|
|コンセンサス処理|Ethereum Chain|Beacon Chain|
|トランザクション処理<br />スマートコントラクト実行|Ethereum Chain|Ethereum Chain<br/>(Shard Chainとして)|

## The Merge の意義
- PoS に移行したため、マイニングが要らなくなり、電力の消耗が 99.95% 減少し、世界中全体の電力消耗が 0.2% 削減できたようです。

https://twitter.com/VitalikButerin/status/1570299062800510976?s=20&t=NzNVuXoFtNbR0trh8iAAYw

- ビーコンチェーンとシャードチェーンで稼働するように、イーサリアム 2.0 のアーキテクチャを構築できました。現時点では、シャーディングの実装もできてなく、シャードチェーンもイーサリアムメインチェーンの１つしかないですが、コンセンサスレイヤーと実行レイヤーの分離ができたため、アーキテクチャとして、他のシャードチェーンを追加する準備が備えたと言えるイメージです。
    - プログラミングの例で例えますと、もともとコンセンサス処理とトランザクション実行処理とすべての処理が全部１つのソース・ファイルに書いていましたが、The Merge の後は、コンセンサス処理モジュール・トランザクション処理モジュールのように綺麗にモジュール化して、分離できました。おかげで、今後はトランザクション処理のタイプを追加するとかの改修もよりやりやすくなるイメージです。

## The Merge　実施のすごいところ
エンジニア視点からすると、素晴らしいお仕事だと思っています。
どんなイメージかを例をあげてみます。

- システム開発で例えますと、 `メンテナンス時間を設けずに、本番環境をオンプレ環境から AWS に切り替えた` 難しさです
- 日常的な例をあげますと、 `旅客機が飛びながら、空中でエンジンを交換できた` ような素晴らしさです

## まとめ
The Merge の実施は、イーサリアム 2.0 に対して大きな一歩です。シャーディングの実装など、これからまだ課題いっぱいですが、すごく期待しています。
Lambdaのパフォーマンスチェックに便利なx-rayの基本的な書き方をまとめる

# はじめに
aws xrayはプログラムのパフォーマンス分析を行うのに非常に便利な機能です。
本記事はxrayのLambdaで使用するときの基本的な記法についてまとめた記事になります。


# 環境
使用している環境は以下です。
```bash
$ uname -a
Linux XX 5.15.79.1-microsoft-standard-WSL2 #1 SMP Wed Nov 23 01:01:46 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
```
プログラムの実行環境は[aws sam](https://aws.amazon.com/jp/serverless/sam/)を使用して用意し、`requirements.txt`に`aws-xray-sdk`を追記します。  
```requirements.txt
requests
aws-xray-sdk
```

(SAMについての基本的な使い方は[こちら](https://qiita.com/abemaru/items/b5deac7a218475e75ca1)に書いてあります。)



# 使い方
### 1. `patch_all`
`patch_all`を使うことでlambdaから他のサービスへ通信するものがxrayに記録されるようになります。対応しているライブラリは[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/xray/latest/devguide/xray-sdk-python-patching.html)を参照してください。
```python
from aws_xray_sdk.core import patch_all

patch_all()
```

### 2. `patch`
`patch`は`patch_all`の機能を特定ライブラリに適応させるためのものです。
[サポートされているライブラリ](https://docs.aws.amazon.com/ja_jp/xray/latest/devguide/xray-sdk-python-patching.html)を`patch`に対して適応することで指定されたライブラリにのみxrayを適応されることができます。
```python
import boto3
import requests

from aws_xray_sdk.core import patch

libraries = (["boto3"])
patch(libraries)
```

### 3. 関数セグメント
特定の関数にかかる処理時間を計測したいときは`xray_recorder.capture`を使います。
下記のように定義することで`do_something`関数にかかる処理時間をxrayで計測することができます。
```python
from aws_xray_sdk.core import xray_recorder

@xray_recorder.capture("Blabla function")
def do_something():
   ...
```

非同期関数の場合は、`capture_async`関数を使用します。
```python
from aws_xray_sdk.core import xray_recorder

@xray_recorder.capture_async("Foo function")
async def do_something():
   ...
```

### 4. 特定の区間
`xray_recorder.capture`で関数の計測はできますが、関数の中の特定区間を計測することも可能です。

計測したい区間を`begin_segment`と`end_segment`でくくることで指定した区間の処理時間を計測することが可能です。

また、セグメントの中に更に`begin_subsegment`を設定することで更に細かい区間をxrayで表示することができます。

```python
from aws_xray_sdk.core import xray_recorder

xray_recorder.begin_segment("計測したいセグメント")

xray_recorder.begin_subsegment("サブセグメント1")
# なにかしらの処理
xray_recorder.end_subsegment()
xray_recorder.begin_subsegment("サブセグメント2")
# なにかしらの処理
xray_recorder.end_subsegment()

xray_recorder.end_segment()

```

# さいごに
xrayの基本的な記法についてまとめました。
これらを使うことによって処理速度を高速化するために非常に役立ちます。

基本的な記法を調べる中で[DjangoやFlask, Bottleにもxrayを適用](https://docs.aws.amazon.com/ja_jp/xray/latest/devguide/xray-sdk-python-middleware.html)させることができるようです。
余裕があればこのあたりの使い方もまとめておきたいですね。
NextJsについて情報収集

## NextJsのメリット
https://cloudsmith.co.jp/blog/frontend/react/2022/04/2064536.html


## 使い方

https://zenn.dev/stripe/books/stripe-nextjs-use-shopping-cart/viewer/step0

## クライアント側のデータ取得

サーバーサイドレンダリングが必要ない場合は、データ取得用の React フック ライブラリ（useSWR）を使う。

https://nextjs.org/docs/basic-features/data-fetching/client-side
レガシーな環境に、保守の第一歩を取り入れた話

# はじめに
- この記事では、PHPで長年運用されてきたWebサービスにおける経験談を語っていきます
- [リファクタリングでシステムを安定化！日頃の取り組みや工夫を教えてください by カオナビ Advent Calendar 2022](https://qiita.com/advent-calendar/2022/kaonavi)という、プレゼントカレンダー応募記事です

# どんな状況だったのか
- 主に3点困るポイントがあったため、それらに手を打ちました
- 保守にあまり工数を割けておらず、動的・静的問わず、未使用ファイルや関数が残っていました
    - (1) グローバルに配置されたPHPのサービスクラスファイルが複数アプリケーションから呼び出されており、アプリケーション側の実装が無くなってもメソッドが残り続けている状態
    - (2) 数万に及ぶ画像やcss, jsファイルが、未使用と使用中のものが混在している状態
- 日々書いたコードは全てコードレビュー後にmergeされますが、そこに依存している状態でした
    - (3) コード行数や循環的複雑度といった定量的な指標はなく、レビュワーの感覚に頼っている状態

# その状況だとどう辛いのか
- (1) に関して
    - 使っているか分からないメソッドや定数が大量に存在していました
    - するとコードの可読性や保守性が著しく低下します
    - エンジニアの仕事は"コードを書く時間より読む時間の方が長い"と言われるぐらいなので、当然業務効率が落ちている状態でした
- (2) に関して
    - これも同様に、可読性や保守性が低下していました
    - また、これらファイルがgit管理下のため、gitのリポジトリが肥大化し、デプロイ時間が増加するといった弊害も起きていました
- (3) に関して
    - ユニットテストも無く、数百行に及ぶメソッドがいくつか存在していました
    - 下手に手を付けると障害になりうる、誰も触りたがらないけど触らざるを得ないシステムが存在していました

# そこにどう手を打ったのか
- それぞれ別のアプローチをしました
- 前提としてレガシーなPHP環境のため、モダンなツールはほぼ使えないものと考え、だいたいは自前でツール実装をしました

## (1) PHP未使用メソッドや定数の削除ツール
- 結論、シェルスクリプトを自作しました
- スクリプト内容
    - PHPファイル内のメソッドを自動的に洗い出します
    - そのメソッドに対し、リポジトリ内でgrepをかけます
    - phpファイルとymlファイルで使用されていない場合、それらメソッドが抽出されるため、それらを削除します
- これにより、数万行に及ぶ未使用メソッドや定数が削除できました

## (2) 静的ファイルの削除ツール
- 画像やcss, jsファイルでも似たようなスクリプトを自作しました
- こちらはPHP製です
- スクリプト内容
    - 静的ファイルを配置しているディレクトリから、ファイルを全て洗い出します
    - それぞれのファイルに対し、リポジトリ内でgrepをかけます
    - phpファイルで使用されていない場合、そのファイルを削除します
- この時厄介だったのは、ファイル名を動的に指定している場合です
    - 例えばMVCのViewレイヤーにあたるファイル内で、for文による動的なファイル名指定をされているケースです
        - `item{$i}.jpg`のような指定
    - これらは正直検知が困難でした
    - 結果としてそういった連番ファイルは一度削除してしまい、404エラーを返すログを見て復活…という手順を辿りました
    - また、それらファイルは除外リストに加えて、次回以降は自動削除されない仕組みにしました
        - ここは若干悩ましいポイントではあります
- これにより、数千ファイルの削除ができました

## (3) PHPで複雑なメソッド乱立問題
- 結論、PHPMDを使用しました
    - レガシーなPHP環境においても導入可能だったためです
- また、"複雑なメソッド"の定義においては、循環的複雑度を測定しました

### 循環的複雑度とは
<!-- textlint-disable -->
> 循環的複雑度（英: Cyclomatic complexity）とは、ソフトウェア測定法の一種である。Thomas McCabe が開発したもので、プログラムの複雑度を測るのに使われる。プログラムのソースコードから、線形的に独立した経路の数を直接数える。
> 引用：[循環的複雑度- Wikipedia](https://ja.wikipedia.org/wiki/%E5%BE%AA%E7%92%B0%E7%9A%84%E8%A4%87%E9%9B%91%E5%BA%A6)<!-- textlint-enable -->
- 分かりやすく言うと、そのメソッド内に存在するifやforといった制御文があるたびに+1カウントすることにより、メソッドごとの複雑度を定量的に測定する手法です

### 実際やったこと
- これを利用し、まずは循環的複雑度40以上のメソッドを洗い出しました
    - 結果として数十個の複雑なメソッドが出てきました
    - 最も数値が高かったメソッドは120を超えていました
- その後は循環的複雑度40を超えるメソッドを、1つずつ分割やリファクタリングしていきました
    - 1ヶ月ほどで40以上のメソッドは0になり、その後基準を30に下げることで、より保守性を高めることができました
- また、これに関しては自動化が必須です
    - なぜなら一度潰したところで、また循環的複雑度30を超えるメソッドが生まれてしまうためです
    - というわけで、このPHPMDの処理をCI/CDに組み込みました
    - これにより、循環的複雑度30超えのメソッドが再び生まれないように手を加えました
- 最後に、分割したメソッドにユニットテストを導入しました
    - もともとテストが無い環境だったため、テストカバレッジは追っていません
        - 追ったところで、1%未満をウロウロする未来しか見えないため
    - ですが、手を付けるのも怖い状態からは大幅に改善したと言えるでしょう

# 最後に
- 今回は長年運用されてきたレガシーなWebサイトについて、リファクタリングで行ったことを紹介しました
    - いかに手を入れづらい状況かはお察しいただけたでしょう
- 何より重要なのは、**技術的負債は定期的に解消すべきである**、ということです
    - 変えるべきなのはソースコードよりも、"保守を軽視してきた文化そのもの"です
    - 一度無法地帯と化してしまうと、それを元に戻すのには莫大なコストと時間がかかります
- あらゆる書籍で『2割は保守に充てる』といった話が出てきますので、それぐらい常に工数を確保して、リファクタリングをしていきましょう
自分から見てターゲットとなるオブジェクトの角度の取得方法


Unityで自分から見てターゲットとなるオブジェクトの角度の取得方法
「あ、そんなのでいいの？」って感じだったのでメモ

＋－を付けてくれるのでとっても便利

``` cs
    Vector3 to = target.transform.position - transform.position;
    var angle = Vector3.SignedAngle(transform.forward, to, Vector3.up);
```

リファレンスを確認しておくのは大事ですね（自戒