OmniAICreator/Qiita-1.07M huggingface dataset:
npm install エラー「npm ERR! g++: error: unrecognized command line option」解決法

# 環境
Mac OS：Monterey 12.0.1
Node.js：16.3.0
npm：7.15.1

# エラー内容
npm install した際、以下のようなビルドエラーが発生する。

```
MacBook-Air:××× $ npm install
（省略）
npm ERR! command failed
npm ERR! command sh -c node ./build.js
npm ERR! make: Entering directory '×××/node_modules/deasync/build'
npm ERR!   CXX(target) Release/obj.target/deasync/src/deasync.o
npm ERR! make: Leaving directory '×××/node_modules/deasync/build'
npm ERR! gyp info it worked if it ends with ok
npm ERR! gyp info using node-gyp@7.1.2
npm ERR! gyp info using node@16.3.0 | darwin | x64
npm ERR! gyp info find Python using Python version 3.6.8 found at "/Users/×××/anaconda3/bin/python3"
（省略）
npm ERR! g++: error: unrecognized command line option ‘-std=gnu++14’
npm ERR! g++: error: unrecognized command line option ‘-stdlib=libc++’
（省略）
npm ERR! gyp ERR! node -v v16.3.0
npm ERR! gyp ERR! node-gyp -v v7.1.2
npm ERR! gyp ERR! not ok 
npm ERR! Build failed
```
これらのエラーそのものを調べても、直接の解決方法が出てこなかったため、解決した手順をここに記載する。

# 解決手順
g++エラー部分を調べると、似たエラーがあり、どうやらgccのバージョンが低いことが原因のようである。

```
macbook-air:××× $ gcc --version
gcc (GCC) 4.8.5
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
```

gccを11.2.0_3にアップデートして、バージョンを確認するが、アップデートしたバージョンになっていない。

```
macbook-air:××× $ brew install gcc

macbook-air:×××$ gcc --version
gcc (GCC) 4.8.5
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
```
gccを確認すると、anacondaのgccを使ってしまっている。

```
macbook-air:×××$ which gcc
/×××/anaconda3/bin/gcc
```

インストールされたgccを確認し、~/.bash_profileに優先されるようにpathを追加する。

```
macbook-air:××× $ ls /usr/local/bin | grep gcc
gcc-11
gcc-ar-11
gcc-nm-11
gcc-ranlib-11

macbook-air:×××　$ vi ~/.bash_profile
macbook-air:×××　$ source ~/.bash_profile
```
gccのバージョンを確認する。

```
macbook-air:×××　$ gcc --version
gcc (Homebrew GCC 11.2.0_3) 11.2.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
```

# 補足・参考情報
gccの環境構築については、[こちらの記事](https://qiita.com/DaikiSuyama/items/09f5aa399aad37783146)がとても参考になります。
Zoomで参加を自動承認にする

# 英語

Security > Enable Waiting Room をオフにする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89618/ce69b7cb-61bd-d05e-99ab-9729d5e46e1e.png)

# 日本語

セキュリティ >  待機室を有効化 をオフにする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89618/36180cdc-1d7c-03b5-36fa-ceb5a7dd4bc5.png)











<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
python --versionの出力は、python3.4からstdoutに出力されるようなっていた

少しハマったのでメモです

`python --version`の出力は、python3.4からstdoutに出力されるようなっていた

検証コード

```python:test.py
import subprocess
ret = subprocess.run("python --version", shell=True, stdout=subprocess.PIPE , stderr=subprocess.PIPE ,encoding="utf-8")
print(ret)
```

```python:python2.7の場合
python3 test.py 
CompletedProcess(args='python --version', returncode=0, stdout='', stderr='Python 2.7.17\n')
```

```python:python3.7の場合
$ python3 test.py
CompletedProcess(args='python --version', returncode=0, stdout='Python 3.7.1\n', stderr='')
```

以下のリリースノートにpython3.4からstdoutに出力されるようになったと書いていた。

> [view Doc/whatsnew/3.4.rst]
> * The python command and most stdlib scripts (as well as :mod:`argparse`) now
> output ``--version`` information to ``stdout`` instead of ``stderr`` (for
> issue list see :ref:`other-improvements-3.4` above).



# 参考
[view Doc/whatsnew/3.4.rst](https://hg.python.org/cpython/file/fc089cf0cf32/Doc/whatsnew/3.4.rst)
[changeset 89325:fc089cf0cf32](https://hg.python.org/cpython/rev/fc089cf0cf32)
[Why does python print version info to stderr?](https://stackoverflow.com/questions/26028416/why-does-python-print-version-info-to-stderr)
pythonのsubprocessから実行結果を取得する

pythonのsubprocessから実行結果を取得する時のメモ

試したバージョンは以下の通り

```
$ python --version
Python 3.7.1
```

`subprocess.run`を使う場合は以下のようにすれば良い

```python:test.py
import subprocess
ret = subprocess.run("python --version", shell=True, stdout=subprocess.PIPE , stderr=subprocess.PIPE ,encoding="utf-8")
print(ret)
if "Python 2" in ret.stdout:
    print("python")
if "Python 3" in ret.stdout:
    print("python3")
```

実行結果

```
$ python test.py
CompletedProcess(args='python --version', returncode=0, stdout='Python 3.7.1\n', stderr='')
python3
```

# 参考
[python で subprocess を使ってコマンドを実行する方法](https://blog.goo.ne.jp/dak-ikd/e/473f9dedd54fb65bf51d251307bb4286)
[標準エラー出力へ出力する (sys.stderr)](https://maku77.github.io/python/io/stderr.html)
`python3`系を使いたいのに、`python`と実行すると`python2`系が使われてしまう時の対策


例えば、以下のように実行すると`python2`系が使われてしまう

```
$ python --version
Python 2.7.17
```

`/usr/bin/python`を`/usr/bin/python3`のシンボリックリンクにする方法もあるが、それが難しい事もある。
この場合は、以下のようにエイリアスを設定すれば簡単に`python3`系を使えるようになる。

```
alias python="python3"
```

以下のように確認できる

```
$ python --version
Python 3.6.9
```

`~/.bashrc`に記載しておくとターミナル起動時に設定されるので便利

```
echo "alias python=¥"python3¥"" >> ~/.bashrc
```
KVM上のWindows 10のスワップ領域(仮想メモリ)にホスト側Linuxのtmpfsを使用する

Windowsの場合、メモリが足りなくなるとページファイルにメモリの中身が退避されますが、HDDのような遅いストレージでは読み書きが終わるまで全体の処理がストップしてしまうため、この処理が頻繁に起こると非常にストレスとなります。また、SSDでは貴重な書き込み回数を浪費してしまいます。
特に仮想マシンではメモリが限られていることが多いのでスワップの処理が頻繁に起こりがちです。
そのため、WindowsのページファイルをホストのRAM上に配置して動作の高速化を図ってみます。

# 準備
NTFSパーティションをフォーマットするため、ntfs-3gが必要です。

```shell-session
$ sudo dnf install ntfs-3g # Red Hat
$ sudo apt install ntfs-3g # Debian
```

# ホストの設定
このようなスクリプトを用意します。

```shell:/usr/local/bin/vmswap-attach
#!/bin/sh

if [ -e /tmp/vmswap ]; then
  exit 1
fi

mkdir /tmp/vmswap
mount -o size=0,noatime -t tmpfs tmpfs /tmp/vmswap
truncate -s 8G /tmp/vmswap/disk.img
loop=$(losetup -b 4096 -Pf --show /tmp/vmswap/disk.img)
parted -s -a optimal ${loop} mklabel gpt mkpart Volume ntfs 0% 100%
mkfs.ntfs -s 4096 -p 256 -H 0 -S 0 -If "${loop}p1"
parted -s ${loop} set 1 msftdata on
losetup -d ${loop}
```

```shell:/usr/local/bin/vmswap-detach
#!/bin/sh

if [ ! -e /tmp/vmswap ]; then
  exit 1
fi

umount /tmp/vmswap
rm -rfv /tmp/vmswap
```

`vmswap-attach`を実行すると`/tmp/vmswap/disk.img`にスワップ領域が作成され、`vmswap-detach`を実行すると削除されます。
もう少し詳しく解説すると、tmpfs上に8GBのスパースファイルを用意し、そこにGPTのパーティションを切り、NTFSでフォーマットします。
最後に`set 1 msftdata on`するのが重要なポイントで、`mkfs.ntfs`だけではWindowsはNTFSとして認識してくれませんでした。

systemdで自動起動できるようにユニットファイルを作成しておきます。

```systemd:/etc/systemd/system/vmswap.service
[Unit]
Description=Swap space for Windows on KVM
Before=libvirtd.service

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/bin/vmswap-attach
ExecStop=/usr/local/bin/vmswap-detach

[Install]
WantedBy=multi-user.target
```

```shell-session
$ sudo systemctl enable --now vmswap
```

# ゲストの設定
作成したスワップ領域をVMのストレージとして追加します。
使わなくなった領域を解放させるため、Discard modeはunmapを選択します。
![Screenshot from 2021-12-21 16-01-34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677297/c1013d31-5578-590a-dc7d-b03db83bc948.png)

XMLを編集し、ブロックサイズを4096バイトに設定して完了です。
(論理セクタサイズをページサイズに合わせて4096バイトでフォーマットしているため、これをしないとWindowsから見えない)

```xml
<disk type="file" device="disk">
  <driver name="qemu" type="raw" cache="writethrough" io="io_uring" ioeventfd="on" discard="unmap" iothread="4" detect_zeroes="off" packed="on"/>
  <source file="/tmp/vmswap/disk.img"/>
  <backingStore/>
  <!-- ブロックサイズを4096バイトに設定 -->
  <blockio logical_block_size="4096" physical_block_size="4096"/>
  <target dev="vdb" bus="virtio"/>
  <address type="pci" domain="0x0000" bus="0x08" slot="0x00" function="0x0"/>
</disk>
```

次に、ページファイルを置くための設定をします。
Windowsを起動したら、スタートボタンを右クリック→システム→関連設定の「システムの詳細設定」→詳細設定タブ→パフォーマンスの「設定」→詳細設定タブ→仮想メモリの「変更」をクリックします。
すると仮想メモリの設定ウィンドウが表示されます。
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677297/616391d1-0892-2fa5-64e9-08612cd3f7a3.png)
設定後の画面がこちらです。
Dドライブが先程追加したストレージです。
カスタムサイズの場合、空き領域から5MB引いた8124MBが最大でこれ以上は大きくできません。
ここではストレージの領域を最初から目一杯使うように設定していますが、通常はシステム管理サイズで問題ないと思います。
入力後は必ず「設定」ボタンを押さないと反映されないので忘れずにクリックしておきます。
![無題2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677297/7e68c655-0d5b-9940-c3b4-fa1e1e7bfb7d.png)
再起動後、追加した領域が仮想メモリとして反映されているのが確認できます。
kubernetesでphpを動かすパターン

kubernetes環境でphpアプリケーションを運用しようと思った時に、構成は意外と悩む部分かと思います
nginxやapacheが必要になるところが問題なんですよね
今回は nginx + php-fpm をkubernetesで動作させるパターンを考えていきます

観点は

- 耐障害性
- 管理しやすさ
- socket接続
- 静的ファイルの取り回し
    - アプリケーション内にjsやcssがある場合、それらはnginxがホスティングして、phpファイルはnginxを通してphp-fpmコンテナへという流れになる
        - CDNを使おうという話ではあるけども
- 好み

このへん+αな感じですかね

# 1.Supervisor

![スクリーンショット 2021-12-18 23.21.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122084/bbfc7d2d-caad-89f7-ee41-ac04e3651991.png)
ひとつのコンテナでphp-fpmとnginxプロセスを動かします
docker以前のphp環境を持ってくるような感じになりますか
1コンテナ1プロセス？頭が固いなあ！

- 耐障害性
    - コンテナ内部が複雑なので、面倒そうな雰囲気は感じる
    - supervisorを理解していないと、liveness/readinessの設定は難しい
        - nginxやphp-fpmの動作に異常が起きるとどうなるのか、など
    - コンテナとしては単独なので、上記をクリアできれば安定しそうではある
- 管理しやすさ
    - imageを作るのが難しい
        - supervisorガチ勢なら余裕か
    - ログの取り回しは地獄
- socket接続はもちろん可能
- 静的ファイル配信も問題なし

非常に玄人向けなイメージ
1コンテナに全部詰め込むのが気持ち悪くない人

# 2.サイドカー

![スクリーンショット 2021-12-18 23.45.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122084/c5917d74-c6cc-4e7b-a92b-1c53f21c3c97.png)
php-fpmとnginxそれぞれ独立したコンテナを1つのpodで動かします
1.からnginxとphp-fpmのコンテナを独立させた形
個人的にはこれにスタンダードを感じます

- 耐障害性
    - 両方ともアプリケーションとしての動作に不可欠なコンテナなので、liveness/readinessは複雑になる
        - それぞれにlivenessを設定して、両方通したreadinessを設定するなど
    - nginxとphp-fpmがペアなので、基本は一蓮托生かな
- 管理しやすさ
    - nginxのimageは公式を使えばいいし、php-fpmもベースになる部分は公式でimageが出てるので比較的作りやすい
    - ログに関してはphp-fpmをどうクリアするか次第
        - nginxはstdout/stderrで問題ない
        - nginxとphp-fpmがペアなのはログが見やすくなるかも
- socket接続は可能
    - コンテナ間の共用ボリュームを設定する必要がある
- そのままだとアプリケーションファイルはphpコンテナ側にあるはずなので、静的ファイルがある場合は対策が必要
    - 静的ファイルをnginxがホスティングできるようにする必要がある

supervisorなんてわからんわ、という人向け
バランスはいいと思います、なんのバランスか知らんけど

# 3.独立
![スクリーンショット 2021-12-19 0.37.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122084/e7315181-ff26-52bc-315e-65b09bd15edd.png)
php-fpmとnginxを別のpodにしてservice間通信にします
2.のサイドカー構成をpod単位で独立させた形
kubernetesっぽい構成です

- 耐障害性
    - それぞれ完全に独立しているので、liveness/readinessの設定がわかりやすい
        - けど、php単独のreadiness的なヘルスチェックは少し面倒
    - 落ちてもコンテナひとつpodひとつなので、他の部分に影響を与えない
- 管理しやすさ
    - 基本は2.と同じ
    - nginxとphp-fpmのログを関連付けるのに分散トレーシング的なのは欲しい…
- socket接続は不可能
- 静的ファイルの対応も2.と同じく必要
- マルチAZの場合、nginxとphp-fpmがAZまたぎになることがあるので、パフォーマンスの問題がある

2.とあんまり変わらないし、kubernetes的でよさそうな雰囲気
ただしsocket接続ができなかったり、AZ問題があるなど、パフォーマンスの問題があります

# 4.NGINX Ingress Controller
![スクリーンショット 2021-12-19 1.28.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122084/e0526f4b-774e-b5dc-8c0b-2b8a21a8252a.png)

https://github.com/kubernetes/ingress-nginx/

ingress controllerにNGINX Ingress　Controllerを使用すれば、FastCGIをサポートしているので自前のnginxが必要なくなります
3.から間のnginxがなくなる形
設定方法は以下の公式ドキュメントで

https://kubernetes.github.io/ingress-nginx/user-guide/fcgi-services/

- 耐障害性
    - 単純に障害点が減るので強い
    - php-fpmのreadinessについては2.3.と同じ
- 管理しやすさ
    - これも単純に管理するものが減るので強い
    - nginx側の細かいチューニングはnginx ingress controllerを完全理解する必要があるのはしんどい点かも
- socket接続は不可能
- nginxでの静的ファイルホスティングはちょっと厳しそう
- マイクロサービス的にクラスタ内でphpから別のphp…となる場合は結局間のnginxが必要になるのでは？
    - internal ingressみたいな感じでnginx ingress controllerで捌けるかどうか（わからん）

条件が揃えばかなり有力な選択肢になります
これのためにingress controllerを乗り換える、まではいかないかな

# ちなみに
私は無難に2で運用しています
3はAZまたぎの遅延が受け入れられなかった
nginx ingress controllerも使ってない
青空文庫を使って、日本語でよく使われる子音をカウントしてみた

# TL;DR

* 日本語でよく出てくる子音が何なのか気になった
* 青空文庫のテキストデータを使ってカウントしてみた
* 子音単体だと k が多くて、調音位置でいうと歯茎音が多かった。

# きっかけ

私、元々大学院まで言語学研究室に居て日本語の文法を研究しておりました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">欧州各言語で最も多く使用される子音<br><br>フランス語はS，英語はT，イタリア語はN… <a href="https://t.co/r91E6J5ppr">pic.twitter.com/r91E6J5ppr</a></p>&mdash; Spica (@Kelangdbn) <a href="https://twitter.com/Kelangdbn/status/1471610724661460992?ref_src=twsrc%5Etfw">December 16, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

先日院生時代の友人がこのツイートを紹介して「やっぱり歯茎音が無標なのか」[^1]と言っていまして、「でも日本語ではどうなんだろうな？」と気になったのです。
Wikipediaだと普通の日本語の文章じゃない箇条書きや外国語も大量に混入してくるので、青空文庫のテキストデータを活用してみることにしました。


[^1]: ざっくり一般用語に直すと、「ほっとくと舌を歯の根元あたりに付けて出す音が多いんだな」くらいの意味です。

# 集計した結果

というわけで早速日本語に出てくる子音の集計結果。多い順。

|子音|	出現数|備考|
|:--|--:|:--|
|k|	31,661,222||
|t|	27,074,053||
|n|	25,796,136||
|r|	21,022,666||
|m|	17,144,365||
|s|	13,053,226||
|ʃ|	11,926,160|「シ」の子音|
|d|	10,568,933||
|g|	9,496,824||
|ɲ|	9,019,203|「ニ」の子音。「ニ」「ジ」「チ」の直前の「ン」もこれ|
|w|	7,836,892||
|h|	7,273,092|ちょっと面倒だったので「ファ」は全部h扱いにしてしまいました・・・|
|j|	6,167,702|ヤ行の子音|
|b|	4,836,853||
|t͡s|	4,704,255|「ツ」の子音|
|d͡ʒ|	4,320,056|「ジ」の子音|
|t͡ʃ|	3,929,212|「チ」の子音|
|N|	2,876,175|語末や母音などの前の「ン」|
|z|	2,806,214||
|ŋ|	1,945,590|か行・が行の前の「ン」。鼻濁音はカウントできないので全部g扱いに。|
|p|	772,335||
|v|	108|「ヴ」の出現回数です|

これを調音位置で分類すると・・・（←これが本題だった）

|調音位置|頻度|比率|対応する子音|
|:--|--:|--:|:--|
|両唇	|30,590,553	|13.6%|p, b, w, v|
|歯茎	|125,200,911	|55.8%|t, n, r, s, ʃ, d, t͡s, d͡ʒ, t͡ʃ, z|
|軟口蓋	|50,376,728	|22.5%|k, g, h, ŋ|
|硬口蓋	|15,186,905	|6.8%|ɲ, j|
|その他	|2,876,175	|1.3%|N|

おお、たしかに歯茎音が圧倒的！
でも単独の子音でいうと k が多いんですね。
(hは軟口蓋扱いでいいのかとか言いたいことは色々あると思いますが・・・)

# Qiitaなのでコードも載せておこう

ソースコードはこちらにおいてます。
https://github.com/moriwo/aozorabunko_mining

やっていることとしては、青空文庫の各ファイルに対して、

1. 読み込んで書誌情報等を削除
1. fugashi を使って読みがな（カタカナ）を取得
1. カタカナからローマ字に自前で変換して、子音の数をカウント

というだけです。
ただ、この「ローマ字への変換」にはいくつか注意点がありまして、そこをどうにかしているのが以下のメソッドです。

```python
def kana_to_phonemes(s: str):
    p = list("".join(phonemes[c] for c in s))
    for i in range(0, len(p)):
        if p[i] == 'N':
            if i+1 >= len(p):
                # 文末の「ん」はNとする
                break
            elif p[i+1] in 'kg':
                # 軟口蓋音の前の「ん」はng
                p[i] = 'G'
            elif p[i+1] in 'ztcdnr':
                # 歯茎音の前の「ん」はn、ただしサ行の前はN
                p[i] = 'n'
            elif p[i+1] in 'YZC':
                # 硬口蓋音の前の「ん」はY (nj)
                p[i] = 'Y'
            elif p[i+1] in 'pbmv':
                # 両唇音の前の「ん」はm ※なお日本語にfは認めません(めんどいから・・・)
                p[i] = 'm'
            elif p[i+1] in 'aiueojhwsSN':
                # 母音、半母音、サ行、は行の前の「ん」は鼻母音化のNとする
                # N の前のNは面倒なのでNのままにする
                pass
            else:
                raise # 想定できてない場合エラーに
    return p
```

ここで何をやっているかといいますと、日本語の「ン」は実は直後に来る文字によって音が違うんですね。
日本語話者は人生で一度は必ず「Shimbashi」なのか「Shinbashi」なのか気になって眠れない夜があります。
マ行やパ行、バ行の前の「ん」は m だし、タ行などの前の「ん」は n です。
その他色々なバリエーションが「ん」にはあるので、それをどうカウントするかがキモとなります。
細かいことは、ここらへんのサイトを見ると面白いです。
https://ipa-mania.com/japanese-n/

# 果たして

この記事はQiitaに書く種類の記事だったのか？
N-Nマッチング実装時の考え方について



別管理されているリストA,B同士をKeyと日付で突き合わせ、一方へ時点状態として情報を寄せるプログラム実装の実務があったので考え方を整理。

![7B7291A3-56A3-430F-97ED-688899B0F22A.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151818/50617692-5ea9-3ce0-ef45-868ce5c2eed0.png)


![33C420D9-8553-4B3C-94B8-6D8765153E54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151818/edff3ece-ca49-ad31-19aa-f88224c8cc14.png)
ペライチにおけるオフショア開発について

## はじめに
この記事は[ペライチアドベントカレンダー](https://qiita.com/advent-calendar/2021/peraichi)の19日目の記事です。

こんにちは　株式会社ペライチ エンジニアリングマネージャーのみついです。入社時からペライチのオフショア開発の立ち上げ、プロジェクト推進を行っております。

現在ペライチでは保守案件として、CakePHPのアップグレードに伴う大規模なマイグレーションを行っているのですが、この案件で会社として初めてオフショア開発を採用し、プロジェクトを進めております(これまでもQAではオフショアを利用してはいましたが開発は初です)
。

本記事ではオフショア開発の状況をお伝えすることで、SaaSのスタートアップがどのようにオフショアを活用しているか、またペライチの中の様子が少しでも伝わったらなあと思い執筆しています。

## 基本情報
#### 契約体系とオフショア体制
ペライチでは開発（単体テストまで）とQAで別のオフショア会社さんにお願いしています。これは前述の通りもともとペライチのQAを行っていたオフショア会社さんがおり、彼らにドメイン知識（業務知識）があったため、QAはそのまま既存の会社さんにお願いしたためです。
それぞれラボ契約で行っており、人数は専任/兼任、時期によって変わりますが、ピークで開発で15人、QAで8人くらい携わっています（QAは自動テストの実装なども取り組んでいるので多めです）。
結構な人数ですが専任のペライチの担当は私だけです笑

ちなみにペライチ開発全体の体制につきましてはこちらの記事をご覧ください。
[ペライチ開発チームのご紹介](https://qiita.com/katsukii/items/a37b0afc9cc37d512ecb#%E9%96%8B%E7%99%BA%E4%BD%93%E5%88%B6)

気が向いたらオフショアベンダー選定編なんかもやるかもしれません。


#### オフショア会社の拠点はダナンです
そうダナンです。リゾート地です。両社ともです（開発会社はハノイ、ホーチミンにも拠点があります）。
ベトナムオフショアといえばハノイ、ホーチミンを浮かべる方もいるかと思いますが、次点で来るのがダナンかと思います。
ちなみに現地の有識者曰く、ダナンの人材はハノイ、ホーチミンの人より頑張り屋さんで日本人に合っているようです。その上でスキルレベルはハノイ、ホーチミンと変わらないので良いそうです。実際私もそう感じています。
![ダナン](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2341009/5d4b47a2-068b-b416-6c13-87e6d2af5e71.png)

#### そもそもなんでオフショア？
今回の案件は大規模なマイグレーションのため、かなりの工数が必要です。しかしながらペライチではやりたい機能開発がまだまだ山ほどあり、内製化するとその分開発リソースがそちらに割かれ、機能開発スピードが落ちます。
そのためオフショアを活用し、機能開発のペースを落とさずマイグレーションを行うことにしました。
案件の特徴的に保守開発でドメイン知識がそれほどいらないというのも決め手になりました。


## ペライチにおけるオフショア開発の特徴
#### オフショア側に日本人がいない
開発会社に限った話ですが、全員ベトナム人です。とはいえコミュニケーションは日本語で行っています。ブリッジSEは日本語の話せるベトナム人が行っています。
よくオフショア会社のブリッジSEが日本人のパターンも多いかと思いますが、コストの問題もありこの形で実施しています。

#### 完全リモートです
このご時世なので特徴にもならないかもしれませんが、完全にリモートで行っています。
その分、毎朝朝会を行いコミュニケーションはしっかりと取っています。コミュニケーションはZoomとSlackです。
とはいえ早く国外に行けるようになって現地視察したいものです。

#### ２社が関わっている
前述の通り、開発とQAで会社が分かれています。コミュニケーションは必ずペライチを通すようなこともなく、両社で直接調整なども行ってもらってます。


## 今どんな感じ？
#### なかなかリスキーじゃないっすか？
前項までの案件内容や体制、特徴を聞いて察しがいい人は気付くかもしれませんが、いきなりの大規模案件でオフショアって結構リスキーじゃないっすか？ということです。
はい、私も思います。が我々もバカじゃありませんのでリスクヘッジはしっかりと行っています。

#### どうやってリスクヘッジしたの？
まず、いきなり本開発は行いませんでした。
ベンダ採用段階で技術力などは高く評価していましたが、担当する方の能力、アウトプットを見たかったため、
PoCと称して、実際に一部機能のマイグレーション作業を行ってもらい、評価するフェーズを設けました（契約も分けています）。
また、今回のマイグレーションにおいては段階移行方式をとったため、段階移行中の共存環境の構築、フィージビリティもPoCフェーズに含めました。

ちなみにオフショアベンダの評価は以下の観点で行いました。
- ソースコード品質
- 日本語コミュニケーションは問題ないか
- ドキュメント品質
- 技術力

結果として、問題ないことが分かったためそのまま本開発に進みました。

#### んで現状どんな感じ
プロジェクトも佳境に入り忙しい日々が続いてますが、現状進捗通りに進んでおりうまく行っていると思います。
直近はW杯最終予選で日本とベトナムが対戦しており、その話題で盛り上がったりしてます（ベトナム人はサッカー好き多いです）。


## 最後に
個人的に割と昔からオフショアに携わっており、今回久々にオフショア活用したのですが、全てにおいてレベルがめちゃくちゃ高くなっていました。コストメリットだけでなく、技術力活用という意味で今後もオフショア活用したいと思っています。
（オフショア拠点作って現地滞在とかしたいなー笑）

以上です。ここまで読んでいただきありがとうございました！
PHP財団にふるさと納税する手順の考察

先日設立の発表された「PHP財団」にふるさと納税する手順を考察してみた。

## PHP財団とは

PHP財団については、こちらの記事が詳しい。
[Nikita Popov、PHP開発から離れる & PHP財団設立のお知らせ](https://qiita.com/rana_kualu/items/eaf97694f25a62f93a7e)

## なぜ「ふるさと納税」？

先日の[【PHP8.1リリース記念】PHPerのためのPHP8.1をもっと語り合うPHP TechCafe](https://rakus.connpass.com/event/230475/)
で、「PHP財団に寄付してスポンサーになりたいね」みたいな話題があり、俺が「ふるさと納税したいね」と言ったら「その発想はなかった」と言われたことによる。

勤務中の8割に当たるヒマな時間（中間管理職が本気で管理したらみんな死ぬため）を少し使って考えた。

## ふるさと納税の手順

### 納税する自治体を担ぎ上げる

架空の実在する日本の地方自治体として[埼玉県和光市](https://ceron.jp/url/chaos2ch.com/archives/1659491.html)を用意した。
埼玉県和光市がPHP財団に寄付をし、その財源として我々の「ふるさと納税」が使われれば良い。

返礼はこれである。

![埼玉県和光市.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569616/97edcebd-84c2-71fa-f0c8-5b72d00475e0.png)

## 返礼品に困っている日本の地方自治体のかた、いかがですか！？

※自治体がこれに税金を使っていいかは別問題とする。
改行を取り除いてくれるプログラム

大学生で論文を読む方なら誰しもこのような悩みに陥るのではないでしょうか。

**論文って改行のせいで機械翻訳がめんどくさい！！**

そのような悩みを解決するために、このようなプログラムを作成しました。


``` replaceCR.uws
cnt = 0
limit = 10*60 // 10分間起動

repeat
	ifb getkeystate(vk_ctrl)and getkeystate(vk_c)
		sleep(0.5)
		// クリップボードの文字列を取得
		str=getstr(0)
		sleep(0.2)
		
		// 改行を空白に変更
		str=replace(str,"<#CR>"," ")
		sendstr(0,str)
		
		// ログを出力
		id=getid(get_logprint_win)
		ctrlwin(id,show)
		short=copy(str,1,20)
		print short
	endif
	cnt = cnt + 1
	sleep(0.5)
until getkeystate(vk_esc) or cnt > limit*2
```

（コードの説明）

*Ctrl+C*が入力されると、クリップボードの文字列を変換して
改行を取り除いてくれます。

*Ctrl+V*で張り付けをすると機械翻訳のサイトに
改行が取り除かれた文章を送ることができます。

10分間でプログラムが終了するという設定にしているので、
ランチメニューに登録しておくとよいでしょう。

お役に立てれば幸いです。
Failed to load SWC binaryのエラー

## エラー内容
DockerでNext.jsをyarn devで立ち上げようとしたら、下記のエラーが発生。ローカルでは立ち上がったのになんでだろう。

```sh:
front_1  | yarn run v1.22.15
front_1  | $ next dev
front_1  | ready - started server on 0.0.0.0:3000, url: http://localhost:3000
front_1  | error - Failed to load SWC binary, see more info here: https://nextjs.org/docs/messages/failed-loading-swc
front_1  | info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
front_1  | error Command failed with exit code 1.
app_front_1 exited with code 1
```

## 設定内容

```sh:ファイル構成
.
├── docker-compose.yml
└── front
    ├── Dockerfile
    ├── next.config.js
    └── （省略）
```

```yml:docker-compose.yml
version: "3.8"

services:
  front:
    build:
      context: ./front
    volumes:
      - ./front:/usr/src/app
    command: sh -c "yarn dev"
    ports:
      - 3000:3000
    stdin_open: true
```

```Dockerfile:Dockerfile
FROM node:14-alpine
WORKDIR /usr/src/app
```

## 原因
とりあえず、エラーの言う通り、下記の公式ページを見てみる。
https://nextjs.org/docs/messages/failed-loading-swc

要約すると、「高速なコンパイルやリフレッシュを実現する"SWC"が、あなたの環境では互換性がなくてエラーを起こしている。必要なパッケージをインストールするか、"SWC"の設定をオフにしてくれ。」ということらしい。

## 解決方法
具体的にやることとしては、こちらの記事の通り！
https://stackoverflow.com/a/69820670

STEP1〜3 SWCの設定をオフにする方法
STEP4 SWCに必要なパッケージをインストールする方法

STEP1

```js:next.json.js
module.exports = {
  swcMinify: false // 追記
}
```

STEP2

```sh:ファイル構成
.
├── docker-compose.yml
└── front
    ├── Dockerfile
    ├── next.config.js
    ├── .babelrc # ファイル追加
    └── （省略）
```

STEP3

```:.babelrc
{
  "presets": ["next/babel"]
}
```

以上でSWCの設定はオフになるので、Dockerコンテナを再起動すると立ち上がるはず！


それでもダメなら、SWCに必要なパッケージ（next@canary）をインストールする方法を実施する。
バージョンでも動作するものとそうでないものがあり、この記事によると、バージョンnext@11.1.1-canary.7なら問題なく動作するらしい
https://zenn.dev/sora_kumo/articles/09a1369e53e5d0

STEP4

```sh:zsh
$ yarn add next@11.1.1-canary.7 # npmなら npm install next@11.1.1-canary.7
```

以上です！
[Firestore][iOS] Ballcap-iOS 使用時に子 View が更新されない場合がある

Firestore のラッパーライブラリ [Ballcap-iOS](https://github.com/1amageek/Ballcap-iOS) を使っていた時に、思っていたのと違う挙動が起きたので、解消法についてメモします。

# 問題は何？

以下の View で ``recreate item`` をタップすると ``vm.item`` が更新され、 ``ChildView`` の表示（ ``item`` の生成時刻 = ``item.dateDebugDescription`` ）が変わるはずですが、変わらないという問題です。

```swift:
import SwiftUI

struct MyView: View {
    
    @ObservedObject var vm = MyViewModel()
    
    var body: some View {
        VStack {
            ChildView(item: vm.item)
            Button("recreate item") { vm.recreateItem() }
        }
    }
    
    struct ChildView: View {
        @ObservedObject var item:Item
        var body: some View {
            Text(item.dateDebugDescription)
        }
    }
    
}

class MyViewModel: ObservableObject {
    
    @Published var item:Item
    
    init() {
        let item = Item(id: "a")
        item.dateDebugDescription = Date().debugDescription
        self.item = item
    }
    
    func recreateItem() {
        let item = Item(id: "a")
        item.dateDebugDescription = Date().debugDescription
        self.item = item
    }
    
}


// GithubレポジトリのREADMEの「using-ballcap-with-swiftui」
// （https://github.com/1amageek/Ballcap-iOS#using-ballcap-with-swiftui）
// のクラス定義をコピーして
// クラス名を Item に変えて
// 「var dateDebugDescription = ""」を追加した
import Ballcap
import FirebaseFirestore

final class Item: Object, DataRepresentable, DataListenable, ObservableObject, Identifiable {

    typealias ID = String

    override class var name: String { "items" }
    
    struct Model: Codable, Modelable {
        var name: String = ""
    }

    @Published var data: Item.Model?

    var listener: ListenerRegistration?
    
    // MARK: -
    
    var dateDebugDescription = ""
}
```

# 原因は何？

Ballcap の Object.swift に次のコードがありました。

```swift:
public extension DataRepresentable where Self: Equatable, Self: Object {

    static func == (lhs: Self, rhs: Self) -> Bool {
        lhs.path == rhs.path && lhs.data == rhs.data
    }
}
```

``path``と``data``が一致していれば、インスタンスが異なっても``==``が成立するみたいです。

> ちなみに、
> 
> - ``Item``クラスは``DataRepresentable``プロトコルに準拠している。
> - ``DataRepresentable``プロトコルは``Hashable``プロトコルに準拠している。
> - ``Hashable``プロトコルは``Equatable``プロトコルに準拠している。
> 
> というわけで、 ``Item``クラスは``Equatable``プロトコルに準拠しているみたいです。

``MyView``の再描画時に``ChildView(item: vm.item)``の引数の新旧で``==``が成り立っていることが原因かと思い色々調べると、そうでした。

# 解消法

少なくとも、``Object.swift``、``DataRepresentable.swift``、``DataListenable.swift``では``==``を使っていなかったので、``==``の実装を上書きすることにしました。

インスタンス識別子を比較するようにします。
どこかにこのコードを書けばOKです。

```swift:
public extension DataRepresentable where Self: Equatable, Self: Object {

    static func == (lhs: Self, rhs: Self) -> Bool {
        // インスタンス識別子で比較
        ObjectIdentifier(lhs).hashValue == ObjectIdentifier(rhs).hashValue
    }
}
```
【python】癒される・嫌がるpython（第2弾）

# TL;DR

ソースコードは[こちら](https://github.com/YomamaBanana/Random_Scripts/blob/main/Custom_Error/improved_version.py)！

# はじめに

こんにちは！YomamaBananaです！
この記事は以前の[記事](https://qiita.com/YomamaBanana/items/2ea9f8bb5a693e2f9eed)の発展形です。

以前はPython開発する際に出くわすエラーを面白く表示しようぜ、について書きました。しかしその時のやり方はあまりにも単純すぎて、どこかで面白さが欠けていると感じました。

そこで今回は別の方法でエラーを面白く表示するチャレンジになります！

# 使用するツール

今回は[asciimatics](https://asciimatics.readthedocs.io/en/stable/)というライブラリーを利用します。

asciimaticsとはterminalにいろんなものを表示したら、機能を追加したりするライブラリーです。

```shell
pip install asciimatics
```

# 画像データ

今回エラー表示に使う画像は下記の二つになります。

画像１
![simle.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2290515/ed1b039b-1c82-afad-4bde-5e1cd14f39ba.png)

画像２
![404.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2290515/fca60e1a-3049-ddf0-25f6-b9e404fc1d22.png)

# デモ

実行結果は下記の通りです。
![custom_error.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2290515/c064227b-ec29-3a8b-91ce-e291c952b46a.gif)

# ソースコード

```improved_version.py
# 必要なライブラリーをimportする
from __future__ import division
from asciimatics.effects import BannerText, Print, Scroll
from asciimatics.renderers import ColourImageFile, FigletText, ImageFile
from asciimatics.scene import Scene
from asciimatics.screen import Screen
from asciimatics.exceptions import ResizeScreenError
import sys

# 笑顔EMOJIを用いたエラー
def simle_error(screen):
    scenes = []
    effects = [
        BannerText(screen, ImageFile("img/simle.png", screen.height - 2, colours=screen.colours),
              0, 0),
        Print(screen,
              FigletText(
                "www ERROR www",
                font='banner3' if screen.width > 80 else 'banner'
                ),
              screen.height//2-3,
              colour=Screen.COLOUR_RED, bg=7 if screen.unicode_aware else 0)
    ]
    scenes.append(Scene(effects))
    screen.play(scenes, stop_on_resize=True)

# 404エラー画像を用いたエラー
def error_404(screen):
    scenes = []
    effects = [
        Print(screen,
              ColourImageFile(
                screen, 
                "img/404.png", 
                screen.height-2,
                uni=screen.unicode_aware,
                dither=screen.unicode_aware
                ),
            0,
            stop_frame=200)
    ]
    scenes.append(Scene(effects))
    screen.play(scenes, stop_on_resize=True)

# 自前のエラー関数
def CustomError(demo):
    while True:
            try:
                Screen.wrapper(demo)
                sys.exit(0)
            except ResizeScreenError:
                pass    

if __name__ == "__main__":
    try:
        1 + "str"
    except:
        # エラーを発動させる
        CustomError(error_404)
```

# あとがき

今回はハードコーディングなく、スマートにエラー発生と予測するところに面白く表示することができました。
この記事の目的はあくまで**エラーを面白く表示する**であり、asciimaticsのたくさんの機能については触れませんでした。
asciimaticsには様々な機能が入っており、気になる人はぜひ試してみてください。

公式githubにはたくさんのsampleがありますので、ご参考までに！

前回と今回の記事を通して分かったことは、**開発は楽しく面白くやっていこうぜ**とのことです。

開発者のみなさん、なろうとしているみなさん、楽しくやって行きましょう！

https://github.com/peterbrittain/asciimatics/tree/770a097cb532cc1fdbcf5f7889bfcdeeddd92b3c/samples
[Next.js]styled-componentsのスタイルが適用されない時の対処

#Next.jsでstyled-componentsが適用されない

先日、Next.jsで`styled-components`を使おうと思い作成していたら
困ったことに更新された直後などしか、スタイルが当たらない現象がありました。
最初は、何かミスったかなと思い、色々みていましたが
全く関係なく、設定が必要だったのです！

この設定はすぐにできます！

## 設定内容
現在では`.tsx`が主流かなと思っているので、そちらのものを記載します。
作成箇所は`pages`配下に
ファイル名：`_document.tsx`
です。

``` _document.tsx
import Document, { DocumentContext } from 'next/document';
import { ServerStyleSheet } from 'styled-components';

export default class MyDocument extends Document {
  static async getInitialProps(ctx: DocumentContext) {
    const sheet = new ServerStyleSheet();
    const originalRenderPage = ctx.renderPage;

    try {
      ctx.renderPage = () =>
        originalRenderPage({
          enhanceApp: (App) => (props) => sheet.collectStyles(<App {...props} />),
        });

      const initialProps = await Document.getInitialProps(ctx);
      return {
        ...initialProps,
        styles: (
          <>
            {initialProps.styles}
            {sheet.getStyleElement()}
          </>
        ),
      };
    } finally {
      sheet.seal();
    }
  }
}
```

コピペでOKです。

こちらでスタイルが当たるようになります。

## 最後に

閲覧ありがとうございます。
皆さんのお役に立つと嬉しいです。

## 参考

https://zenn.dev/nbr41to/articles/c0c691653e3d55
格安lidar mb_1r2t 使ってみた

# 経緯
lidarっていろんなことできるから家に一個は欲しいけど、どうみても大学生が買えるような値段じゃないんですよね…
（Amazonで安くても5,6kから）
なんとか安く買えないかなと探していたら、かつて格安lidar CamsenseX1というlidarが売っていたとの情報を見つけました。
しかし、2021年12月現在売ってないみたいです…
他になんとか使えるやつを探していると、こんなlidarを見つけました。

https://ja.aliexpress.com/item/1005002601075062.html?spm=a2g0o.detail.0.0.5c325ba0u6qVcS&gps-id=pcDetailBottomMoreThisSeller&scm=1007.13339.169870.0&scm_id=1007.13339.169870.0&scm-url=1007.13339.169870.0&pvid=f125e800-45ad-4f43-8a57-2c903e53d2dc&_t=gps-id:pcDetailBottomMoreThisSeller,scm-url:1007.13339.169870.0,pvid:f125e800-45ad-4f43-8a57-2c903e53d2dc,tpp_buckets:668%232846%238108%231977&pdp_ext_f=%7B%22sceneId%22:%223339%22,%22sku_id%22:%2212000021344818600%22%7D

![aliex.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017430/ee2df893-0cf5-8d57-f247-ce2f4dbc1adc.png)

1個あたり1.5kです。めちゃくちゃ安いです。てことで2個買いました。

# 到着
2021年の7月くらいに購入して、大体1ヶ月くらいで到着しました。
![DSC_1894.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017430/d04057fc-3099-5e4b-0628-71b7af58142e.jpeg)

見た目はTurtleBotについてるlidarとそっくりだなーって感じです。

# 実際に使ってみる
## 接続
お高いlidarだとUSBケーブルが伸びてたりEthernetがついてたりしますが、こいつにはそんなものはついてません。
ピンむき出しです。
ピンは合計8つで、そのうち使うのは4つ（5V,GND,Serial OutPut,回転速度調節）しか無いです。他の4つ何に使うんだ…

てことで、USB-Serial変換基板を使ってPCと接続します。

## ドライバ
実は買ってから2ヶ月くらいはドライバが見つからなくてガチの文鎮と化してました。
探し回ってやっと見つけたのがこれです。

https://github.com/Vidicon/mb_1r2t_ros

これがあって本当によかった。開発チームの方々に感謝します。

## 実行
上のリポジトリをcloneしてきて、`view.launch`を実行してみます。

実際の部屋はこんな感じです。
![DSC_2615.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017430/602cd778-56b2-c3e9-8c2d-58a7a4450d83.jpeg)

このように写ります。
![screenshot1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017430/1e96c195-372e-8a7a-efe8-60b1225ab42b.png)

ちゃんと枠を認識できてる！
この値段でlidarの役割を果たしてくれるのはすごいですね。


僕の足を入れてみました。
![DSC_2616.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017430/4163c510-ea04-4269-5bd2-6a18139e1676.jpeg)

![screenshot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017430/ee304b7d-bee1-9854-2ddc-61b40d1dde68.png)

人間もちゃんと写ってます。

#感想
## 良かったところ
- 値段が安い
- ちゃんとlidarとして機能する
- 2021年12月現在手に入る

## 良くないところ
- 値段相応に性能は低い
- 粒度が荒いので使いにくい
- 品質が保証されてない

#おわり
本記事では激安lidarを使ってレビューをしました。この値段でlidarが手に入るのは個人的にはとても魅力的だと思います。
友人や恋人へのクリスマスプレゼントにいかがでしょうか？

#参考文献
https://github.com/Vidicon/mb_1r2t_ros
python + tkinterでWebページを選択して移動する方法

tkinterで作成したボタンをクリックするとwebページに遷移できる
プログラムを作成しました。

まずはコードから。

```transition.py
import tkinter as tk
import webbrowser

buttons=[]
urls = {"Google" : "https://www.google.co.jp/",
        "yahoo"  : "https://www.yahoo.co.jp/",
        "baido"  : "https://www.baidu.com/",
        "duck"   : "https://duckduckgo.com/"}

def callback(i):
    def transition():
        webbrowser.open(list(urls.values())[i])
    return transition

root = tk.Tk()
root.title("search engine")
root.geometry("300x100")
for i in range(len(urls)):
    buttons.append(tk.Button(root, text = list(urls.keys())[i], command = callback(i)))
    buttons[i].pack(fill="x")
root.mainloop()
```

このプログラムを実行すると、検索エンジン候補で4つのボタンが出力され
クリックするとそのページに遷移することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2405683/d73d3b4e-c705-1204-951f-f3ad905f329f.png)

また、５行目の変数urlsに新たな辞書を追加すると
ボタンの数を増やすこともできます。
↓

```
urls = {"Google" : "https://www.google.co.jp/",
        "yahoo"  : "https://www.yahoo.co.jp/",
        "baido"  : "https://www.baidu.com/",
        "duck"   : "https://duckduckgo.com/"}
```


初投稿なので、pythonの初歩的なプログラムをアップロードしました。
これをベースに様々なプログラムを組むことができそうですね。
Latexで簡単に文字数カウントしたい人へ

# 前準備

VSCodeプラグインにLatex Workshopをインストールしてビルドが通るようにする．
これさえできていれば .tex ファイル単位で文字数をカウントできます．

# 結論

VSCodeで文字数カウントしたい .tex ファイルを開きます．

Macなら Cmd+Shift+p，Windowsなら Ctrl+Shift+p を押して，`count words`とかで検索をかけ，↓を選択すると数えてくれる．

```
LaTeX Workshop: Count words in LaTeX document
```

※ どうやら句読点や節の見出しなどはカウントされないようです

# ついでに

いや俺はショートカットを設定しないと気がすまないんだという方は，`keybindings.json`にテキトウなキーで登録すると良いと思います．

```
{
  "key": "",
  "command": "latex-workshop.wordcount"
}
```
大規模業務アプリケーションの秘伝のソースコードを継ぎ足していく2つのコツ

私は、Works Human Intelligenceで給与計算領域の大規模業務アプリケーションの
企画、開発を生業としているエンジニアである。

時に20数年前から継ぎ足されていることもある秘伝のソースコードを読み解き、
うまく動かない箇所に手を加えてうまく動くようにしたり、
新しく動かしたい動きを継ぎ足したりしている。

今回は、こういった秘伝のソースコードと付き合って
大規模業務アプリケーションを開発する
2つのコツとして私が考えるポイントをシェアする。

# 業務をプロが使う資料から学び、ソースコードのコンテキストを大きく吸収する

大規模業務アプリケーションの開発課題を解決するための初手としてよく採用するのは、
アプリケーション対象となる業務を業務のプロが使う資料から学び、
ソースコードのコンテキストを大きく理解することである。

例えば、私の開発者としての主領域である公共機関の給与計算業務を例にすると、
・人事院規則
・人事院規則の解説書
　（『国家公務員の給与 － その仕組みと取扱い －』や、『諸手当質疑応答集』）
といった現場の業務担当者が業務遂行をするために参照している資料を机の横に起き、
どういった取扱をするかを都度参照するようにしている。

こういった資料の参照によって得たコンテキストにより、
ソースコードにかかれているロジックは何のためにあるのか、
を雄弁に語れる状態に効果的に変えていっている。
もし、「ここのソースコードにかかれているロジックは、こういうことをやりたいからあるんだ」と
雄弁に語れるようになれば、秘伝のソースコードを自由に、すばやく変えることができる力を得られる。
この段階にすばやく達するための手として、
「アプリケーション対象となる業務を学ぶ」を採用している。

「開発者ならソースコードからすべて対話してコンテキストを読み解くべき」と
思われる方もいるかもしれない。
しかし、1人が管理するソースコード量が数十万行にも及ぶ大規模業務アプリケーションになると、
例えば一つ一つのif文の分岐にどういった意図を込められているかを
解読するだけでも日が暮れてしまう。
このため、業務を学ぶことでコンテキストをごっそり吸収できるところは
吸収するという手を私は使っている。

また、参照する資料のセレクトが、
現場の業務担当者が業務遂行するために参照しているようなプロ向けの資料を
セレクトしている点に驚くかもしれない。
しかし、業務アプリケーションでは、
現場の業務担当者が普段忘れてしまうようなルールが
ソースコードの中に埋め込まれていることが往々にある。
その傾向は、イレギュラーな取扱の自動化が必要になるほどの件数が発生しうる
大規模業務アプリケーションになればなるほど、
こういったルールがソースコードの中に埋め込まれる傾向は強くなる。
このため、ソースコードの読み解きには、入門書レベルの知識ではコンテキストの補完ができず、
現場の業務担当者が困ったときに読むようなプロ向け資料が必要になってくる。

# ソースコードから業務像を想像し、小さくコンテキストを復元する

多くの場合、現場の業務担当者が業務遂行をするため
に参照している資料を入手して読み解けば、コンテキストを補うことができるが、
細かな指針を実現するためにソースコードに埋め込んでいるケースについては
根拠資料がない場合もある。
特によくあるのは、業務慣習をソースコードに埋め込んでいるパターンであり、
このパターンについては現場の業務担当者が業務遂行するために
参照する資料に記載がないことは往々にある。
前述のとおり、イレギュラーな取扱についても
自動化が必要になるほどの件数が発生しうる大規模業務アプリケーションでは、
こういった細かな指針もソースコードに織り込まれていることは往々にある。
そういった場合は、上記で「日が暮れる」と述べたソースコードから
コンテキストを復元することが必要になる。

このソースコードからコンテキストを復元する際によく使うのは、
「このソースコードの書き方であったら、こう動くしかないので、こういった業務像になるであろう」
という動きから逆算した業務想像という手である。

もちろん、こういった動きから逆算した業務想像は
一つ一つのif文の分岐にほどこしていたら日が暮れるので、
どうしても資料からコンテキストが復元できない箇所にピンポイントで使うのが、
効果的に「ここのソースコードにかかれているロジックは、
こういうことをやりたいからあるんだ」という状態に
たどり着くためのコツである。

つまり、大きなコンテキストはプロの資料から学び、
そこからこぼれ落ちた小さなコンテキストはソースコードの動きから逆算して復元する、
という使い分けをする、ということである。

# まとめ
秘伝のソースコードと付き合って大規模業務アプリケーションを開発するポイントは
　1.業務をプロが使う資料から学び、ソースコードのコンテキストを大きく吸収する。
　2.ソースコードから業務像を想像し、小さくコンテキストを復元する。
という2つのコツを組み合わせ、
「ここのソースコードにかかれているロジックは、こういうことをやりたいからあるんだ」と
雄弁に語れる状況にすばやくたどり着くことである。

このシェアが、大規模業務アプリケーションの秘伝のソースを読み解いて問題解決するエンジニアの
問題解決のヒントになれば、幸いである。
Azure Static Web Appsをもっと知ってほしい

# Azure Static Web Apps というサービス

Azure Static Web Appsというサービスがしばらく前からGAされています。

HTMLやCSSやJavaScriptだけのサーバーレスのサイトを公開する場合、
これまではAzureStorageに展開したりGitHubPagesが選択肢に挙がりました。
今回紹介するAzure Static Web Appsではファイルの公開機能に加えて
・独自ドメイン/証明書のサポート
・GitHubActionsでのデプロイ
・AzureFunctionとの連携
・Vue.jsやReactといったフレームワークのサポート
があります。
これらの機能が基本**無料**で使えるところも特筆すべきところです。

FreeTierのサービスは幾つかありますが、
Azure Static Web Appsを試す敷居が低いかを知っていただき、
今後はどんどん開発と遊びに活用していってください。

# リソースの作り方

Portal画面でのリソースの作成方法をご紹介します。
クリックする回数と入力する箇所が非常に少ないです。

管理画面のホームから**リソースの作成**を選び、
**静的Webアプリ**ないし**Static Web Apps**でリソースの作成に進みます。

## 入力

以下は、作成画面の最初の入力フォームです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123580/4f335306-be81-e475-3409-18497c68c353.png)

リソースの作成をするには、

1. リソースグループ
1. リソース(サービス)の名前
1. プランの種類(とりあえずFreeでいいでしょう)
1. リージョン
1. GitHubとの連携

の入力を行うだけです。
入力箇所が少なくてとても簡単です！

GitHubとの連携をクリックすると、

* ユーザー
* ブランチ
* ビルドのフレームワーク

などを選択します。

その後、**確認および作成**をクリックしてください。

## 作成!!

確認画面が出るため、画面下の作成ボタンを押しましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123580/e0146738-b476-80b4-42a2-3f199457534a.png)

## プロビジョニング中...

私の経験上2分程度で完了します。

## 完了!!

リソースの作成完了後、URLの箇所をクリックしてみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123580/47fe0b73-d774-cc9d-ddcd-2adfa55c27ec.png)

正常にWebサイトが表示されました！
今回はVue.jsを選択したため、Vue.jsの初期画面が表示されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/123580/0f9d4c90-2f14-0c45-cc1a-51e565d0e9e7.png)

# 終わりに

* HTML/CSS/JavaScriptだけで簡単なWebサイトを作りたい
* 無料でWebサービスを作りたい

そのような要望をお持ちの方はぜひ試してみてください！
速い！安い(無料)！簡単！という三拍子揃った最高のサービスです。
レジスタについて

[う　え　き　ぷ　に　き　あ　く　ん　笑 Advent Calendar 2021](https://adventar.org/calendars/6939 "うえきです") 18日目です

##この記事について
本記事では、アセンブリを読む際に必要となるレジスタの知識について説明します。
環境はx64アーキテクチャを想定しています。

##レジスタって？
レジスタとは、プロセッサ内にある記憶装置のことで、メモリなどと比べると高速に動作しますが、容量が非常に小さいです。容量はプロセッサによって変わり、現在は64bitのものが広く使われています。
主に、プロセッサが命令を実行する際に使用されます。

##レジスタの種類
レジスタには、
・RAX, RBX, RCX, RDX, RSI, RDI, R8, R9, R10, R11, R12, R13, R14, R15の汎用レジスタ（RSI, RDIはインデックスレジスタとも呼ばれます）
・RBP, RSP, RIPの特殊レジスタ
・RFLAGSのフラグレジスタ　
・CS, DS, ES, SSのセグメントレジスタ

などがあります。これらは全て64bitです。

##レジスタの名称と用途
レジスタにはそれぞれ正式名称と主な使用用途があります。
汎用レジスタについての使用用途は、あくまでも主に用いられる用途であるため、必ずこの用途に使われるということではありません。
ここでは、執筆時間と重要度の観点から（は？）、セグメントレジスタを除いた名称と用途について記します（後日追記します）。

###汎用レジスタ
RAX：アキュムレータレジスタ　演算の結果を格納
RBX：ベースレジスタ　アドレスのベース値を格納
RCX：カウンタレジスタ　ループなどのカウンタの値を格納
RDX：データレジスタ　演算に使用するデータを格納
RSI：ソースインデックスレジスタ　一部のデータ転送命令において、データの転送元を格納
RDI：デスティネーションインデックスレジスタ　一部のデータ転送命令において、データの転送先を格納

###特殊レジスタ
RBP：ベースポインタレジスタ　現在のスタックにおける底のアドレスを保持
RSP：スタックポインタレジスタ　現在のスタックにおけるトップのアドレスを保持
RIP：インストラクションポインタレジスタ　次に実行する命令のアドレスを保持

###フラグレジスタ
OF：オーバーフローフラグ　演算命令で桁溢れが発生した際に1になる
DF：ディレクションフラグ　ストリームの方向を制御する
IF：割り込み可能フラグ　割り込みを有効化する際に1になる
TF：トラップフラグ　デバッグ時に1になる
SF：サインフラグ　演算命令の結果が負になった際に１になる
ZF：ゼロフラグ　演算命令の結果が0になった際に1になる
AF：調整フラグ　BCD演算時に桁上がりあるいは桁借りが発生した際に1になる
PF：パリティフラグ　演算命令の結果について、1となるビットの数が偶数個の際に1になる
CF：キャリーフラグ　演算命令で桁上がりあるいは桁借りが発生した際に1になる


##汎用レジスタの部位
汎用レジスタには部位によって名前があり、RAXレジスタを例にあげると、
RAXレジスタの下位32bitはEAXレジスタ
EAXレジスタの下位16bitはAXレジスタ
AXレジスタの上位8bitはAH, 下位8bitはALレジスタと呼ばれます。
<img width="600" alt="RAXレジスタ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/389480/a0aef823-93fa-794d-1717-884a05ce6b80.png">
RBX, RCX, RDXレジスタはRAXレジスタと同じように、
下位32bitはEBX, ECX, EDXレジスタ
下位16bitはBX, CX, DXレジスタ
下位9~16bitはBH, CH, DHレジスタ
下位8bitはBL, CL, DLレジスタ
と呼ばれています。

インデックスレジスタは、
<img width="600" alt="RSIレジスタ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/389480/4fd6a8ab-aeb1-3470-f8db-833d57949e8e.png">
このようになります。
RDIレジスタもRSIレジスタと同様です。

##最後に
いかがでしたか？レジスタの意味を理解することは、アセンブラを読み解く上でとても役に立ちます。
目指せrevマスター！なりたい、revマスター...

明日の分の記事はうえきさんが書きます！では！
Reactテスト道場 〜hooks編〜


hooksのテストを通常の単体テストで書こうとすると、下記のようなエラーが出てしまいます。

> Invariant Violation: Hooks can only be called inside the body of a function component.

hooksは、本来はComponentの世界でしか機能しないためです。
hooksでテストを行う際は、擬似的にComponentの世界を作り出してテストを実現するツール
`@testing-library/react-hooks`を使います。


## 下準備

### ライブラリのインストール
下記コマンドを実行します。

```sh
yarn add -D @testing-library/react-hooks
```

### コンポーネントとカスタムフックに処理を分離する
コンポーネントに依存したhooksをテストする場合、単体テストではなくComponentテストになります。
(※ Componentテストは明日の記事で紹介します！)

そのため、Componentとhooksの処理は分離しておきましょう。

## ステートを更新するシンプルなhooksのテストの実装
下記のようなとてもシンプルなStateを更新するhooksがあるとします。

```jsx
export const useCounter = () => {
  const [count, setCount] = useState(0);

  const increment = useCallback(() => setCount((prev) => prev + 1), []);
  const decrement = useCallback(() => setCount((prev) => prev - 1), []);

  return {
    count,
    increment,
    decrement,
  };
};

```
### 1. `renderHook`を使って、hooksの返り値を使う
`renderHook`の引数にhooksを実行するコールバック関数を渡すと、オブジェクトが返ってきます。
そのオブジェクトの中にある`result`に、hooksが返すステートや関数が含まれています。

```js
import { useCounter } from './use-counter'
import { renderHook } from '@testing-library/react-hooks';

describe('useCounterのテスト', () => {
  test('increment関数を実行すると、countが1増える', () => {
    const { result } = renderHook(() => useCounter());
  });
});
```

### 2. 現在のステートの値を取得する
resultオブジェクトに含まれる`current`に、現在のステート・関数の値が格納されています。

```js
result.current.count
```

### 3. ステート更新関数を実行する
ステートの更新関数を実行したい時は、`act`関数の中で実行する必要があります。

```js
act(() => {
  result.current.increment();
});
```


### 4. 完成

```js
describe('useCounterのテスト', () => {
  test('increment関数を実行すると、countが1増える', () => {
    const { result } = renderHook(() => useCounter());
    act(() => {
      result.current.increment();
    });

    expect(result.current.count).toBe(1);
  });
});
```

### 補足
`cleanup()`はレンダリングされたフックをアンマウントする関数です。
hooksが副作用をもっている可能性があるため、テスト毎にcleanupした上でテストをすると良いです！

```js
import { useCounter, cleanup } from './use-counter'
import { renderHook } from '@testing-library/react-hooks';

describe('useCounterのテスト', () => {
  beforeEach(() => {
    cleanup();
  });

  test('increment関数を実行すると、countが1増える', () => {
    const { result } = renderHook(() => useCounter());
    act(() => {
      result.current.increment();
    });

    expect(result.current.count).toBe(1);
  });

  test('decrement関数を実行すると、countが1減る', () => {
    const { result } = renderHook(() => useCounter());
    act(() => {
      result.current.decrement();
    });

    expect(result.current.count).toBe(-1);
  });
});
```
【ABC227】 C - ABC conjectureをC++で解説 (Atcoder)

#初めに
　皆さんこんにちは！ 競プロの問題の理解を深めるために解説記事を書いていこうと思います！今回は **ABC227 C** です！
 気に入っていただけたら**LGTM**して頂けるとうれしいです！
何かあれば**コメント**や[Twitter](https://twitter.com/python05238919)からお願いいたします!

#[C - ABC conjecture](https://atcoder.jp/contests/abc227/tasks/abc227_c)
####問題概要
 正の整数$N$が与えられたとき以下を満たす正の整数の組$(A, B, C)$を求める．
・$A \leq B \leq C $
・$ABC \leq N $
####制約
・$1 \leq N \leq 10^{11} $
・$Nは整数$
##考察
####ポイント
・全探索ですが工夫して計算量を短くしましょう．

####解説
 $A, B, C$をそれぞれ$N$まで確認していたら間に合いません．そこで条件の式を変えてみると，
 　　　　$C \leq \tfrac{N}{AB} \tag{1} $
と変更することができます．また$A$の範囲の最大値は条件より$A = B = C$のときであるので，
　　　　$1 \leq A^3 \leq N \tag{2}$
となります．
　同様にして$B$の範囲の最大値は$ B = C$のときであるので，
　　　　$ A \leq AB^2 \leq N \tag{3}$
となります．
$C$の範囲は$(1)$式で範囲の最大値が求まっています．しかし，これだと計算量は$O(N)$となり，間に合いません．そこで$B \leq C\leq \tfrac{N}{AB}$より$C$の最大値から$B$を引けばそれぞれの$A, B$における$C$の数は$C = \lfloor \tfrac{N}{AB} \rfloor - B+1 \tag{4}$
です．
これを実装していきましょう．
#実装
$A, B$の範囲に気を付けながら全探索で，2重ループで解きましょう．計算量は$O(N^{\frac{2}{3}})$となります．

##正解コード

```C++:
#include <bits/stdc++.h>
using namespace std;

int main(){
    //入力
    long long N;
    cin >> N;
    long long ans = 0;

    //全探索
    for(long long a = 1; a * a * a <= N; a++){
        for(long long b = a; a * b * b <= N; b++){
            ans += (N / (a * b) - b + 1);
        }
    }
    
    cout << ans << endl;
}

```
着XYM通知botをM5Stack ビジュアルプログラミングのみで作ってみた

#はじめに
マイコンモジュール「M5Stack」とビジュアルプログラミング環境である「UIFlow」を使って、
Symbol のトランザクションを検知し、知らせてくれるbotを作成してみました。

このbotは、予め設定しておいたSymbolアドレスへのトランザクションを検知し、画面とビープ音でお知らせしてくれます。
プログラマーでない方でも簡単に作れるんだ！ということを実感頂ければ幸いです。

今回は、Symbolアドベントカレンダーということで、M5StackのUI部分は触れずに、Symbolの情報取得までの部分を記事にします。

![image0.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256819/20548033-af3f-1ba0-83de-9bee98db07e2.jpeg)

#それぞれの紹介
##M5Stack とは
M5Stack とは、IoT機器開発などで現在注目を集めているマイコンモジュールです。
従来のArduino などと比べて、液晶画面や、ボタン、マイクやスピーカー、その他周辺部品がひとつにまとまっており、
取り合えずマイコンを触ってみたい！を叶えるにはぴったりのモジュールだと思います。

詳しくは、下記の記事などを参考下さい。

https://deviceplus.jp/hobby/what-is-m5stack/

##UIFlow とは
UIFlowはM5Stack社が開発した、ブロック/micropythonの開発環境です。
Scratchのようにブロックを組み合わせることで、直感的にプログラミングが出来ます。

##Symbol とは
すべてのエンタープライズを拡張するNEMの次世代ブロックチェーンです。
RESTAPIから、容易に利用可能なことが特徴です。

https://jp.symbolplatform.com/

##完成イメージ
このようなものを作成します。
![tmp 1.GIF](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256819/cb3f73d4-abd5-5cad-903d-89492f7b7046.gif)

# 必要な物
・M5Stack本体
・Wi-Fi環境
・Webブラウザ


#０．M5Stackを準備しよう！

まずはM5Stackを用意しましょう。
お持ちでない方は、スイッチサイエンスやAmazonさん等でご購入下さい。

また、M5StackでUIFlow を利用するところまでの手順は本記事では割愛いたします。
下記のリンクなどをご参考に、セットアップを完了させてください。

https://qiita.com/mashed-p/items/1ba7a3dc54e3b766c2a8

#１．M5StackでHello World!してみよう！

##まずは、M5Stack上で『Hello World!』をしてみましょう。
中断の「グラフィック」から、図のブロックを配置して、『Hello World!』と入力してみましょう。
出来たら、右上のRUNボタン(再生ボタンみたいなやつ)から実行しましょう！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256819/1bc52619-5d8a-7301-d100-bce5c1e67916.png)
![image0 (1).jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256819/3f42f2fb-e336-ef46-2adf-d88d5508babb.jpeg)


上記が表示されたら完了です。

##Symbolのトランザクション情報を取得しましょう。
Symbolノードにアクセスし、特定アカウントの直近のトランザクション情報を取得しましょう。
「高度なブロック」→Http→HttpRequest を選択し、下記のように設定します。
なお、URLは適宜環境に合わせて変更してください。

https://"Symbolノードホスト名":3001/transactions/confirmed?recipientAddress="Symbolアドレス"&pageSize=10&order=desc

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256819/8b56edb9-742a-93e5-d830-86313c88e2cd.png)
![image2.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256819/b86d77c7-5ff1-a2fc-dd23-690f1a05394e.jpeg)


##取得したデータを成形し、必要なデータのみを表示させましょう
上で取得したデータはjson形式と呼ばれるデータ構造になっており、人間には読みづらく、不要なデータも多い状態です。
取得したデータから必要情報のみを取得して表示するようにしましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256819/36598221-aaf2-9256-b4da-ef4aa3400864.png)
![image3.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256819/f3949286-0241-d988-4ea0-4207fbf40dff.jpeg)





##その後について
Symbol との接続部分は以上になります。
これ以降は取得したデータを使って、分岐させたり、UIを整えれば完成です。
その他部分については、需要があれば記載したいと思います。
HTTPの基礎①

# HTTPリクエストとHTTPレスポンス
### HTTPリクエスト

:::note info
HTTPリクエスト　＝　リクエスト行　＋　メッセージヘッダー　＋　メッセージボディ
:::

リクエスト行の例（Webページの場合）
`GET /index.html HTTP/1.1`　→ `HTTPメソッド パス名 バージョン`


### HTTPレスポンス

:::note info
HTTPレスポンス　＝　ステータス行　＋　メッセージヘッダー　＋　メッセージボディ
:::

ステータス行の例（Webページの場合）
`HTTP/1.1 200 OK`　→ `バージョン ステータスコード テキストフレーズ`


メッセージヘッダーにはWebブラウザの種類やWebサーバーなど細かな情報がたくさん載ってます。
メッセージボディはWebサーバーに情報を送信するためのもの。POSTメソッド使うときはここにデータを入れて送信する。


# HTTP/1.1の特徴
### 1. HTTPキープアライブ
　WebブラウザとWebサーバーは、`TCP`というプロトコルによって`コネクション`と呼ばれる通信経路を確立してからデータのやりとりをします。
　HTTP1.0以前では、`「コネクションを確立→HTTPリクエストを送る・HTTPレスポンスを受け取る→コネクションを閉じる」`という方式が用いられてきました。
　しかし、Web　ページ内に複数の画像などが含まれていた場合、各々の画像データを送受信するたびにコネクションを確立させていると多くの手間がかかってしまいます。
　そこで表れたのが`HTTPキープアライブ`。一度のHTTP通信でコネクションを閉じることなく、複数のHTTP通信ができるように持続的に同じTCPを接続します。


### 2. HTTPパイプライン
　HTTPは一つのHTTPリクエストを送ったらそれに対応するHTTPレスポンスが帰ってくるまでは次のHTTPリクエストを送信することはできませんが、`HTTPパイプラインはHTTPレスポンスが返ってくるのを待つことなく複数のHTTPリクエストを送ることができます。`


# 参考
[イラスト図解式 この一冊で全部わかるWeb技術の基本](https://www.amazon.co.jp/%E3%82%A4%E3%83%A9%E3%82%B9%E3%83%88%E5%9B%B3%E8%A7%A3%E5%BC%8F-%E3%81%93%E3%81%AE%E4%B8%80%E5%86%8A%E3%81%A7%E5%85%A8%E9%83%A8%E3%82%8F%E3%81%8B%E3%82%8BWeb%E6%8A%80%E8%A1%93%E3%81%AE%E5%9F%BA%E6%9C%AC-%E5%B0%8F%E6%9E%97-%E6%81%AD%E5%B9%B3/dp/4797388811)
iPhoneでSMSが送れない時

#電話番号しか知らない宛先（iPhone以外）にメッセージ送りたいのにSMS送信が出来ない
出勤前、諸事情で上司に連絡取りたい！
けど電話番号しか知らない。
でも電話するほどでもないのでメッセージでいいや。・・・ってことたまにありませんか？

iPhone to iPhoneならiMessageでいいのですが、相手がiPhoneユーザーでない場合、電話番号しか知らないならSMSでメッセージを送る必要があると思います。
そういう状況が私も何度かありましたが、いざiPhoneアプリのMessagesでテキスト送信しようとしても送れませんでした。なので結局電話したり会社のメーリスにプライベートのメアドから送信したりと（不本意）。

ググってもなかなか答えが見つからず（最終的にキャリアプランがSMS対応してるか確認する、的な情報が多かったような）、しばらく放置してました。

でも実は簡単な設定で、iPhoneの設定 > メッセージ の下に**SMSで送信する**ってあるんです。
でもこの設定、**iMessage**をオフってると出てきません。
私は上司に送れない理由が「宛先がiPhoneキャリアじゃないのに私のiPhoneが勝手にiMessageで送ろうとしてるから送信できないんだ！」と思って**iMessage**を**オフ**にしてました。なので**SMSで送信する（デフォルトはオフ）**をずっと見つけられず。。。（泣）

雑記感すごいですが、とりあえず記事にしてみました。
cacti とは

## 勉強前イメージ

ｶｸﾁ...?
検索前は聞いたこともなかった

## 調査

### cacti とは

カクタイと読み、The Cacti Group社が開発している
システム監視のソフトウェアになります。
Ngiosと並んで監視系では古く、
サーバやネットワーク機器の状況を基本設定のみで行うことができる。
ライセンスは [GPL](https://qiita.com/miyuki_samitani/items/3478df16ae66da84c3ee) になります。

MRTGというこちらもシステム監視のソフトウェアですが、
開発終了となり、cactiがMRTGの代替として使用されているそうです。

### cactiの構成について

1台のcactiサーバと監視対象のクライアントがいて
SNMPを使用して監視対象の情報を取得、グラフ化を行います。

cactiサーバでは監視は数百台が限度で、
それ以上を行う場合は、pollerを複数配置してcactiの分散構成を行うことで実現は可能になります。

cactiサーバを冗長化する際には
OSSのクラスタソフトウェアのPacemaker, Corosync, DRBDを使用します。

### zabbixとの違い

よくzabbixを触ってるけど、zabbixとは何が違うのか。

- サービスについて
	- cacti : サーバの情報を取得・グラフ化
	- zabbix : データを取得し、障害検知

- 大規模になる場合
	- cacti : cacti自身とpollerを分けて、分散構成にする
	- zabbix : zabbix proxyを立てて配置

- サポートについて
	- cacti : サポートなし
	- zabbix : 有償サポートはあり

## 勉強後イメージ

zabbixと何が違うの？って思ってたけど、
zabbixはそもそも障害の検知のためよね・・・忘れてた。
cactiはあくまでもデータを取得してグラフ化するだけ。

## 参考

- [Cactiとは](https://www.designet.co.jp/faq/term/?id=Q2FjdGk)
- [CactiとZabbixの分散構成](https://www.designet.co.jp/mailmagazine/201511/)