OmniAICreator/Qiita-1.07M huggingface dataset:
Map.loadImage は Promise 化するのが吉

これは小手先のテクニックです。

[Add an icon to the map](https://docs.mapbox.com/mapbox-gl-js/example/add-image/?size=n_10_n) のように、Symbol Layer を表示するためには、アイコン画像を事前に ``Map.loadImage`` し、さらに ``Map.addImage`` で登録する必要があります(sprite を使わない場合)。

``map.loadImage`` は非同期の関数で、レスポンスは ``(error, image) => void`` のコールバックで通知されるため、上記のサンプルプログラムもインデントが深く見づらくなっています。

ここを Promise 化してあげれば、最近の JavaScript 動作環境では await 構文を使用してすっきり書けます。

```javascript
const loadImageAsPromise = (map, url) => {
  return new Promise((resolve, reject) => {
    map.loadImage(url, (error, image) => {
      if (image != null) {
        resolve(image);
      } else {
        reject(error);
      }
    });
  });
};

map.once('load', async () => {

  // Icons by https://icons8.com/
  const images = await Promise.all([
    loadImageAsPromise(map, 'https://img.icons8.com/material/48/FF0000/user-location--v1.png'),
    loadImageAsPromise(map, 'https://img.icons8.com/material/48/FF00FF/car.png'),
    loadImageAsPromise(map, 'https://img.icons8.com/material/48/0000FF/airplane-mode-on--v1.png'),
  ]);

  map.addImage('human', images[0]);
  map.addImage('car', images[1]);
  map.addImage('airplane', images[2]);

  map.addLayer({
    'id': 'points',
    'type': 'symbol',
    'source': 'points',
    'layout': {
      'icon-image': [ 'get', 'icon' ],
    }
  });
});
```

``loadImageAsPromise`` という関数を定義しています。これはコールバックだった戻り値を ``Promise<画像データ>`` にしたものです。
これを地図が読み込まれたイベントで ``await`` で呼び出します。

さらに、画像を複数読み込む場合は、``Promise.all`` を使用して並列に読み込みを行い、全てが読み込み終わってから次の行へ進む、という事が容易にできます。

### 完全なコードはこちら

- [How to initial map padding? - JSFiddle - Code Playground](https://jsfiddle.net/amay077/qu52f0ca/)
とある異国の回線事情と対策について

# はじめに
この記事は[Ateam Group Manager ＆ Specialist Advent Calendar 2020](https://qiita.com/advent-calendar/2020/ateam) 9日目の記事です。

# 簡単な自己紹介
株式会社エイチーム管理部IT戦略グループの中の人です。こういった記事でアウトプットすることが無いのでとても緊張しています。脚はガクガク腕はブルブル額に汗し口中ボーボー、三口でシャックリ。汗はタラタラ、耳までマッカ。目はパチパチ、十二指腸もビックリ。頭はガンガン、二日酔いもマイッタ。桃色吐息でキーボードを叩いています。

# この記事の概要
皆様が素晴らしい記事を書かれるということなので、思い切ってインフラの話にしました。
とある海外にオフィスを構築した経験から、回線選びや考えておくべき対策[^1]等、何かの際に参考になるかも知れません。
(※効果には個人差があります）
(※現地ではパートナーの皆様に多大なご支援をいただきました)

# で、とある国って？
はい、エンジニアなので結論から参りますと。日本から直線距離で約3,600km[^2]ほど南の国**ベトナム**です。
その中でも**ホーチミン市**というベトナムの南に位置する都市でのお話になります。
(※ベトナムは南北で事情が異なる部分が多いです)

# で、回線事情って？
## 1. まずはキャリアを選び
日本ではNTTをはじめ、様々なキャリアがいらっしゃいますがベトナムではどんなキャリアがいらっしゃるのでしょう？
通信事業系のみとなりますが大体こんな感じです。
![vietnam.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31724/055ef797-9cfe-4af9-3b5b-723d8d57df71.png)
日本とは違って、省庁直系の事業会社によって運営されている企業が多い事がわかると思います。
その中でも**太字**にしたVNPT、FPT、Viettelという3社が大きなシェアを占めている[^3]と言われます。
(国防省のネット回線とか胸アツですよね)
余談ですが、ドコモ回線をベトナムでローミングしたらVinaphone回線になります[^4]

右も左も分からない遠い異国の地ですが、シェアがわかれば
> 魔法のクアドラントのリーダーを狙え！

という法則に従うことで選定はできそうな気がしてきました！やったね！

## 2.回線種類を選びましょう
さてこの記事をご覧の奇特な皆様、50名を想定したオフィス設立時にどんなインターネット回線を引きますか？

1. ベストエフォート型でお安く済ませるか
2. お値段は張るがギャランティ型で速度保証をするか

利用方法や想定されるトラフィック量にもよりますが、まあ１Gbpsベストエフォートがあればまず問題無いかな、となりますよね。

**日本ならね！**

ということで現地で一般的に利用される回線で見積もりをオーダーしたところ…
> 100Mbpsベストエフォート(固定IPアドレス1個)

？？？ おや？ 100Mbps？
なるほど、そういうことね。OK理解した。であればオフィスでのトラフィックを再計算するまで。
ふむふむ、なるほど100Mbpsあれば事足りそう。よろしい。ではこれでお願いできますでしょうか。
さあ、回線も選定できました！やった！あとは開通を待つだけですね！
その間にオフィス内ネットワークの設計をしちゃいましょうね。

## 3.本当にあった怖い回線

> パートナー様「もう1回線別キャリアの契約をおすすめします」

？？？ なんですと？ 新しいオフィスの開所なのでなるべく費用は抑えたいのですが・・・
> パートナー様「割と頻繁に回線障害が発生します」
> 私「またまたご冗談を、どんな障害が発生するのですか？」

パートナー様いわく

* 設備故障(わかる)
* プロバイダ側の不具合(わ、わかる)
* 大雨が降る(雨季のある国ですが・・・)
* 電柱からケーブル抜かれる(！？)

等々、瞬断ならかわいいものでそこそこの時間停止する、などは頻繁にあるとのことでした。
こうしてもう1キャリアの見積もりを進めるのでした。めでたし。めでたし。

これらのソースを示すことはできませんが、開所からしばらくしてベトナムオフィスの方に聞いたところ、
> あー、ネットちょくちょく止まりますね〜、慣れましたけど

と、おっしゃっておりました。
**なんて恐ろしい！**

しかしベストエフォート品質が厳しかったため開所からしばらく後、ギャランティ型に変更したのは別のお話。

## 4.番外編-冗長化のススメ
キャリアと回線を選定したわけですが、
頻繁に障害が出るなんて話を聞いているからには冗長化をしておきましょう。
今回弊社のパターンでは2キャリアを冗長化目的で``マルチホーミング``とし``VRRP``を組むことで

* メイン回線
* スタンバイ回線(兼フリースポット用)

という運用にするよう設計いたしました。
めでたし。めでたし。

# まとめ

* 回線を選ぶ時は現地のシェアを調べましょう。こと回線においてはシェアが高い = 設備投資がされている。というのは概ね当てはまるのでは、と思います。
* 回線種類には気をつけましょう。ただやってみないとわからない事もあるのでコストと品質のバランスを検討した上でスモールスタートが望ましいと思います。
* 日本の常識は捨てて臨むこと。郷に入れば郷に従え。

# 次の方
明日の[Ateam Group Manager ＆ Specialist Advent Calendar 2020](https://qiita.com/advent-calendar/2020/ateam) 10日目はあの@getty104さんが登場です！ご期待ください。

[^1]: インフラ系では当たり前の話ばかりかもですが
[^2]: [地球の歩き方 ベトナムへの飛行時間](https://www.arukikata.co.jp/country/VN/info/flight.html)
[^3]: [海外だより〜大使館より〜 ベトナムの通信事情](https://www.ituaj.jp/wp-content/uploads/2018/07/2014_07-18_kai_viet.pdf)
[^4]: [コネクサスにベトナムの携帯電話事業者が加盟 - NTTドコモ](https://www.nttdocomo.co.jp/info/news_release/page/091117_00.html)
【Node.js】requireによるexportsオブジェクトの参照について

※当方駆け出しエンジニアのため、間違っていることも多々あると思いますので、ご了承ください。また、間違いに気付いた方はご一報いただけると幸いです。

あるファイルから、あるファイルをrequireメソッドで呼び出した場合、requireメソッドで呼び出されたファイルのexportsオブジェクトが返される。
どういうことかと言うと、今下のような２つのファイルがある。

```main.js
const sub = require("/sub");
sub.name("Taro");
sub.age("20");
```

```sub.js
exports.name = (name)=>{
console.log(name);
};

exports.age = (age)=>{
console.log(age);
};
```

sub.jsを見てみると、

exportオブジェクトのプロパティnameとageに関数が格納されている。
オブジェクトリテラルで表現すると下記のような状態。

```js
exports = {
  name: function(name){
  console.log(name),

  name: function(age){
  console.log(age)
  };
```

main.jsでsub.jsをrequireしている。requireすると、requireされたファイルのexportsオブジェクトが返る。
つまり、

```main.js
const sub = require("/sub");

// ↑ この式は ↓ こういうこと

const sub =  
  {
  name: function(name){
  console.log(name),

  name: function(age){
  console.log(age)
  };
```

よって

```main.js
sub.name("Taro");
sub.age("20");

//の結果は

//Taro
//20
```
mimiumによるオーディオプログラミング例

mimium
===

[オーディオプログラミング言語 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/audiolang)

# 概要

https://mimium.org/
https://github.com/mimium-org/mimium

サウンドと音楽を記述/生成するためのドメイン固有言語。
ミュージシャンやプログラマー向けのツールだけでなく、ソースコードの形式で音楽を配信するためのインフラストラクチャとして作成されているとのこと。  
九州大学の松浦知也さんが開発。2019年度未踏IT人材育成・発掘事業採択プロジェクト。


# 実装例

## セットアップ

mimiumは現在も開発中ということもあり、セットアップ方法は今後変わることも考慮して詳細は割愛します。
手元のmacOS Catalinaの場合は、ビルド済みファイルを取得してlibの内容を/usr/local/libにコピー、実行ファイルやライブラリのセキュリティ警告に対応したら動きました。


## サイン波生成

関数定義やクロージャ、if式など構文はRustに似ているように思います。オーディオ処理についてサンプルレベルの高精度処理や関数型言語的なアプローチはFaustやExtemporeなどからアイデアを取り込んでいるようです。低レベル処理はC++でのオーディオプログラミングにも通じるところがあります。

dsp関数がメインの処理で、ここに書いた処理は毎秒48000回実行されます。LLVMにコンパイルされるので高頻度で呼ばれる関数も十分高速に実行されます。

```Rust
SampleRate = 48000
PI = 3.1415956

theta = 0
delta = 0

fn sin_osc(freq:float) {
    delta = 2 * PI * freq / SampleRate
    theta = theta + delta
    return sin(theta)
}

gain = 0.5

fn dsp(time:float) {
    return sin_osc(440) * gain
}
```


## Delayエフェクト

mimiumにはdelay関数が用意されているのでそれを使います。
下記のseek関数はバッファのどこのデータを読むのか判断する関数です。mimiumの関数は前回の戻り値を覚えていてselfで参照できるので、seekのような関数でもポインタ的な変数を別途用意する必要がない点がユニークです。フィルター処理など1サンプル前の値を参照することが多いオーディオプログラミング用言語ならではの機能です。

```Rust
// delay fx

voice = "../voice.wav"
bufsize = loadwavsize(voice)
voicebuf = loadwav(voice)
fr = 44100 // sample rate of wavfile
sr = 48000 // sample rate of system
speed = fr / sr

delaytime = 0.4
feedback = 0.5
wetlevel = 0.5

pos = 0

fn fbdelay(dry:float, time:float, fb:float) {
    return delay(dry + self * fb, time) 
}

fn seek(rate:float, size:float){
    return min(self + rate, bufsize - 1)
}

fn dsp(time:float) {
    pos = seek(speed, bufsize)
    dry = voicebuf[pos]
    return dry + fbdelay(dry, delaytime * sr, feedback) * wetlevel
}

```

上のプログラムで使用しているdelay関数は2020年12月にリリースされたv0.2.0で実装されたものです。v0.2.0リリース前に自作したディレイプログラムも載せておきます。再帰呼び出しでディレイエフェクトのフィードバックを実現するアルゴリズムになっています。

fb_delay関数がディレイ本体です。ディレイ用のバッファを別途持つのではなく、wavファイルのバッファを直接参照しています。そのためストリームにかけることはできませんが、wavファイルのバッファ参照位置を工夫することでディレイが実現できます。下の例では毎秒48000回×5階層の再帰呼び出しをおこなっていますが軽快に動作しています。

```Rust
// recursive delay fx

voice = "../voice.wav"
bufsize = loadwavsize(voice)
voicebuf = loadwav(voice)
fr = 44100 // sample rate of wavfile
sr = 48000 // sample rate of system
speed = fr / sr

delay_time = 0.4
feedback = 0.5
num_feedback = 5

pos = 0

fn fb_delay(buf, size, delay, ptr, fb) {
    return if ((fb < 0) || (ptr < 0)) 0 else buf[min(ptr, size - 1)] + fb_delay(buf, size, delay, ptr - delay * fr, fb - 1) * feedback
}

fn dsp(time:float) {
	pos = pos + speed
    return fb_delay(voicebuf, bufsize, delay_time, pos, num_feedback)
}
```

# 感想

あらたな音楽用言語を設計して高速なコードを生成するコンパイラを作る、という野心的なプロジェクトなので以前から注目していました。
現状はまだ発展途上のところも多いですが、既存の言語を十分調査したうえで独自のアイデアを盛り込んでいるモダンな言語という印象です。

サンプル単位の処理をベースとしつつ、@による簡易タイマーや、selfによる過去への参照、再帰処理など、複数の時間軸が混在するオーディオプロセスにおいて、低レベル処理と抽象化をうまく共存させようとしているところにセンスを感じます。
これからどう進化するか期待しています。

[オーディオプログラミング言語 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/audiolang)
Mac OS のArduinoIDEでビルドエラーがおきるーー

#概要
__Mac book proでarduinoIDEをしようしてESP32用のプログラムをコンパイルしたところ下のようなエラーが起きたので対応策を書いておきます。__

raceback (most recent call last): file "esptool.py", line 57, in <module> file "/library/python/2.7/site-packages/pyinstaller/loader/pyimod03_importers.py", line 389, in load_module file "serial/tools/list_ports.py", line 29, in <module> file "/library/python/2.7/site-packages/pyinstaller/loader/pyimod03_importers.py", line 389, in load_module file "serial/tools/list_ports_posix.py", line 31, in <module> file "/library/python/2.7/site-packages/pyinstaller/loader/pyimod03_importers.py", line 389, in load_module file "serial/tools/list_ports_osx.py", line 32, in <module> valueerror: dlsym(rtld_default, kiomasterportdefault): symbol not found failed to execute script esptool exit status 255 /applications/arduino 1.8.13.app/contents/java/arduino-builderが255を返しました。 ボードesp32 dev moduleに対するコンパイル時にエラーが発生しました。

#設定方法

__Arduino IDEの環境設定から、__

1. /Users/...../preferences.txt のリンクをクリックして、フォルダを開く。

2. packages/esp32/hardware/esp32/1.x.x フォルダの中にある plathome.txtを開き、7行目にあるtools.esptool_py.cmd=esptool となっている部分を tools.esptool_py.cmd=esptool.py と書き換えて保存する。

3. packages/esp32/hardware/esp32/1.x.x/tools フォルダにある esptool.py をpackages/esp32/tools/esptool_py/2.x.x/ フォルダにコピーする。

4. 以下のコマンドで、コピーした esptool.py に実行権限をつける。

```
chmod +x packages/esp32/tools/esptool_py/2.x.x/esptool.py
```

これでArduino IDEを再起動すれば、ESP32のスケッチがコンパイルできるはずですが、私の場合はpythonライブラリのpyserialが無いというエラーが出ましたので、次のようにコマンドを入力してpyserialをインストールしました。

```
% sudo easy_install pip
% pip install pyserial
```

以上の操作を行い、無事ESP32のスケッチがコンパイルできるようになりました
STM32F303K8とOLED、AL12832AWWB-H-U02でHello Worldを表示(U8g2lib)



1.ardiuno ide 1.8.11にSTM32 Corasをインストール
2.u8g2ライブラリーをインストール
3.ソースの例からHelloWorldを選択
4.U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); // Adafruit ESP8266/32u4/ARM Boards + FeatherWing OLED
を選択


おまけ
3.3Vを5Vに変換する為にＰＦＭステップアップＤＣ／ＤＣコンバーター　ＨＴ７７５０Ａ（５個入）とコンデンサー2個とコイルとダイオードを使用した。
マイコンは、ＳＴＭ３２　Ｎｕｃｌｅｏ　Ｂｏａｒｄ　ＳＴＭ３２Ｆ３０３Ｋ８

```c++

#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);  // Adafruit ESP8266/32u4/ARM Boards + FeatherWing OLED

void setup(void) {
  u8g2.begin();
}

void loop(void) {
  u8g2.clearBuffer();					// clear the internal memory
  u8g2.setFont(u8g2_font_ncenB08_tr);	// choose a suitable font
  u8g2.drawStr(0,10,"Hello World!");	// write something to the internal memory
  u8g2.sendBuffer();					// transfer internal memory to the display
  delay(1000);  
}
```


![image_original (11).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/d4d3bf9e-1119-80b8-fd01-58426f29226f.jpeg)
RailsのApp作成のデータベース作成(rake db:create)でハマるところ

#環境
OS：AmazonLinux2
Ruby：ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-linux]
Rails：Rails 5.0.0

#初めに
Railsアプリケーションを作成してる際に`$ rake db:create`でDBを作れず、いろいろとエラーに苦戦したので、共有します。

# ハマるところ① $ rake db:create
`$ rake db:create`を実行すると、エラー発生。

```
The dependency tzinfo-data (>= 0) will be unused by any of the platforms Bundler is installing for. Bundler is installing for ruby but the dependency is only for x86-mingw32, x86-mswin32, x64-mingw32, java. To add those platforms to the bundle, run `bundle lock --add-platform x86-mingw32 x86-mswin32 x64-mingw32 java`.
#<Mysql2::Error: Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)>
Couldn't create database for {"adapter"=>"mysql2", "encoding"=>"utf8", "pool"=>5, "username"=>"root", "password"=>nil, "host"=>"localhost", "database"=>"shift-management_development"}, {:charset=>"utf8"}
(If you set the charset manually, make sure you have a matching collation)
Created database 'shift-management_development'
#<Mysql2::Error: Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)>
Couldn't create database for {"adapter"=>"mysql2", "encoding"=>"utf8", "pool"=>5, "username"=>"root", "password"=>nil, "host"=>"localhost", "database"=>"shift-management_test"}, {:charset=>"utf8"}
(If you set the charset manually, make sure you have a matching collation)
Created database 'shift-management_test'
```

これは、データベースのサーバーが起動してないから。
次のコマンドでデータベースサーバーを起動する。

`$ sudo systemctl start mysqld`

ここでエラーが発生した場合は、ハマるところ③へ。


#ハマるところ② $ mysql.server start 
`$ sudo systemctl start mysqld` ではなく `$ mysql.server start`を実行すると、

このエラーが出ることがある。

```
bash: mysql.server: command not found
```
これはMySQLを起動するコマンドは複数あり、使えないコマンドを実行したことが原因。
それぞれのコマンドを簡単にまとめると、
`$ mysql.server start`はローカル環境などでよく使われるが、使えない環境もある。
`$ sudo systemctl start mysqld`は環境に依存せず、MySQLを起動することが可能である。

より具体的な違いについては以下のリンクが参考になると思います。
[MySQL $ mysql.server startコマンドと$ systemctl start mysqldコマンドの違いを調べてみた](https://qiita.com/miriwo/items/ffe5cdbd7bbe0333259b)

なので、`$ sudo systemctl start mysqld`を実行する。

#ハマるところ③ $ sudo systemctl start mysqld
`$sudo systemctl start mysqld`

このエラーが出る場合。

```
Failed to start mysqld.service: Unit not found.
```

これは、データベースがMySQLではないことが原因。
AmazonLinux2では、MariaDB という MySQL とは別のデータベースがデフォルトで既にインストールされています。

DBサーバー（MariaDB）を起動
`$ sudo systemctl start mariadb`

起動状況の確認
`$ sudo systemctl status mariadb`

OS起動時に自動的に起動するように設定
`$ sudo systemctl enable mariadb`

これで、データベースを作成します。
`$ rake db:create`

```
The dependency tzinfo-data (>= 0) will be unused by any of the platforms Bundler is installing for. Bundler is installing for ruby but the dependency is only for x86-mingw32, x86-mswin32, x64-mingw32, java. To add those platforms to the bundle, run `bundle lock --add-platform x86-mingw32 x86-mswin32 x64-mingw32 java`.
Created database 'shift-management_development'
Created database 'shift-management_test'
```

できました。

#参考
[MySQL $ mysql.server startコマンドと$ systemctl start mysqldコマンドの違いを調べてみた](https://qiita.com/miriwo/items/ffe5cdbd7bbe0333259b)
【口コミ】エンジニア未経験者がテックキャンプのエンジニア転職に通ってみた

# テックキャンプの特徴は？
以下、３つです
**①オリジナルカリキュラムで好きな場所でできちゃう。**
**②ライフコーチ、メンター、キャリアアドバイザーという三本柱**
**③チーム開発を体験できる**

# どんなサービスを受けれた？
大まかに分けると以下の３つ。
**①Webサイトの作成**
**②チーム開発において、スクラム開発を学べる。**
**③転職サービス**

これだけ聞くと、イメージが沸かないと思うので一個ずつ掘り下げていきます。

## オリジナルカリキュラム
カリキュラムは基礎編と応用編で分かれています。
基礎編の最後には中間試験というものがあってこの中間試験に合格しないと、
応用編に進めません。
ただ、試験なので学んだ内容ばかりです。なのでしっかり学んでいる人であれば合格できるようになってます。
**カリキュラムは図解や動画解説も豊富で1人で理解できるよう最大限の工夫**が凝らされており、
自走できるようになってましたね。
**エンジニア未経験でもついていけるレベル**にまで落とし込みされています。

## ライフコーチ、メンター、キャリアアドバイザー
これが最大の特徴といってもいいかもしれません。
### ライフコーチ
まず1人に1人、ライフコーチがつきます。
このライフコーチの役割は以下の通りです。
**①学習進捗管理**
**②将来の人生設計を一緒に組み立ててくれる**
**③プライベートの悩みも聞いてくれる**

まるで高校の先生みたいですが、ぶっちゃけそれよりも親身でした。（自分の場合）

面談の時には学習進捗表を用いてどこまで進めればいいのか、
改めて目標設定をしてくれます。なので**目標をたてるのが苦手な人でも
目標がたてれちゃいますね。**

そして、自分自身将来どうなりたいのかを一緒に考えてくれます。
特に自分は未経験でふんわりとしたイメージしかなかったので、
エンジニアにも色々な職種があることを教えてくれたりしました。

そしてプライベートの悩みも聞いてくれます！
これは自分自身が実際に悩み相談したわけではないのですが、
ライフコーチからプライベートで悩みなどありませんか？大丈夫ですか？
と、面談時に声をかけてくれるほど。
受講生のことをかなり考え抜いてくれていることが分かります。

### メンター
メンターの役割はたったひとつ！
分からないところを根本から解決してくれます。
初心者がよくありがちな「何が分からないのか分からない」という現象。
**自分が今どういうところで詰まっているのか根気よく教えてくれます。**
答えをストレートで教えてもらうわけではないので、達成感も味わえます。
達成感を味わうとどうなるのか？
自信がつきます。自信がつかないと長く続けられませんが、自信がつくことによって
挫折しにくくなります。

### キャリアアドバイザー
転職サービスを受ける人はキャリアアドバイザーが1人につき、1人つきます。
履歴書作成からアドバイスをしてくれて、面接練習も付き合ってくれます。
**この面接対策がかなり本格的で、対策専用フォーマットが用意されており、**
サポートが充実してます。
至れり尽せり！！！



## ①Webサイトの作成
正直これだけでもかなり満足できる内容です。
まず簡単なホームページ作成から始まります。
（自分は、もうホームページを作成するのか…とビビってました。当初は。）
ただ、テックキャンプのオリジナルカリキュラムがあるので基本的にそれに沿って進めていきます。
**そして、最終的に1人でLINEのようなチャットアプリを作成**するまでに至ります。
これだけでかなり自信つきますし、達成感は今でも忘れられません。

## ②チーム開発
1人で開発した後は６人くらいのチームになってフリマアプリのクローンサイトを作成します。
（チームは勝手に運営側で割り振ってくれるので安心です。）
これがかなり手の混んでいるもので、中々やりがいがあります。
**このチーム開発にはカリキュラムは存在せず、**チームで役割を割り振ったりしないといけません。
そしてカリキュラムがないので、自分自身でどのようにコードを記述していけばいいのかを考える必要があります。
つまり、**実際の現場さながらの雰囲気で開発を行うことができる**のです。
（もちろん、ライフコーチやメンターのサポートはついているので安心です）
貴重な体験で、やり切った時にはかなりの達成感がありました。

## ③転職サービス
これはキャリアアドバイザーのところにかいてあるので省略します。


以上のように、かなりの手厚いサービスを受けられます。
気になる方は以下、公式ページなのでぜひ覗いてみてください。
[テックキャンプ公式ページ](https://tech-camp.in/)

私的にはかなりオススメです！！
Webページのコントラスト比をチェックしてみよう

- この記事は[MDCアドベントカレンダー](https://qiita.com/advent-calendar/2020/mdc)9日目の記事です
- 埋まってない日に書いてるのでもう4回目の登場ですがこれ以降はほぼ埋まってますね！

## 概要

- Webアクセシビリティと聞いて皆さんはどのようなことを思い浮かべるでしょうか
- あまり詳しくない人でも、スクリーンリーダーで読めるように画像にalt属性をつけるなど聞いたことがあると思います
- 今回は文字のコントラストを確保するべきという項目をテーマにとりあげます

## テキストのコントラスト確保

- テキストのコントラストに関しては[WCAG 2.1](https://www.w3.org/TR/WCAG21/)では以下のように定義されています(抜粋)
    - [コントラスト(最低限) レベルAA](https://waic.jp/docs/WCAG21/#contrast-minimum)
        - テキスト及び文字画像の視覚的提示に、少なくとも `4.5:1` のコントラスト比がある。
        - サイズの大きなテキスト及びサイズの大きな文字画像に、少なくとも `3:1` のコントラスト比がある。
    - [コントラスト(高度) レベルAAA](https://waic.jp/docs/WCAG21/#contrast-enhanced)
        - テキスト及び文字画像の視覚的提示に、少なくとも `7:1` のコントラスト比がある。
        - サイズの大きなテキスト及びサイズの大きな文字画像に、少なくとも `4.5:1` のコントラスト比がある。
- これらはテキスト色と背景色のコントラスト比が一定以上であることを求めています
    - テキスト色と背景色が同じ色であれば `1:1` でコントラスト比が大きいほど数値の差が広がります
- 以下は[コントラスト比チェックツール](https://webaim.org/resources/contrastchecker/)のキャプチャです

![スクリーンショット 2020-12-09 0.07.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/684724e4-03c9-6704-c8b6-a967df0dc464.png)
![スクリーンショット 2020-12-09 0.07.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/f3a673b2-ea7e-53dd-a6d5-9a65acf5438d.png)

- いろいろ試してみると分かると思いますが、健常者であると思っている人であってもコントラスト比が大きい方が読みやすいと感じるのではないでしょうか
    - より読みやすいページを作るためにもコントラスト比を気にしてみるといいかもしれませんね


## Webページのコントラストチェック

- 上で紹介したような2つの色を指定してコントラスト比をチェックするサイトはいくつも出てきますが、すでにあるWebページに対してコントラスト比に問題がある部分をチェックするツールがないかなと探してみました
- Chrome Devtoolsで使える[Lighthouse](https://developers.google.com/web/tools/lighthouse?hl=ja)でもチェックすることができますが、[WCAG Color contrast checker](https://chrome.google.com/webstore/detail/wcag-color-contrast-check/plnahcmalebffmaghcpcmpaciebdhgdf)というChrome拡張が便利だったので紹介します
    - Lighthouseは画面のどこが指摘されているかは分かるんですが、それぞれどんな色を使っていて何対何なのかが表示されずちょっと不便でした

![スクリーンショット 2020-12-09 0.50.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/3d3149b0-3b34-4459-758b-a5c44553de29.png)


## WCAG Color contrast checker

- 使い方は簡単です
- Chrome拡張を入れてチェックしたいページでアイコンをクリックすると画面左部に検証結果が表示されます

![スクリーンショット 2020-12-09 0.22.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/bf256206-60f3-7b1a-1df3-226769f19dc0.png)

- 画面上のテキストのコントラスト比が一覧で表示されます
    - 目のマークに斜線が入った行は非表示となっている情報なので無視しても大丈夫でしょう

![スクリーンショット 2020-12-09 0.27.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/483cb224-c04a-f1d6-1889-20c3e56f7c41.png)

- Chrome拡張で表示された行を選択すると対応する部分に赤枠が表示され、どの部分が指摘されているのか確認することができます
    - 白背景に緑の字でこれが `2.24:1`なんですね・・・！
    - 画面左下の部分で色を変更してコントラスト比をチェックすることもできます

## 最後に

- 今回調べる中でいろいろなサイトでツールを使ってみましたが指摘が入るサイトがほとんどでした
- ガイドラインに従うことも大切ですが、それぞれの事情に応じて判断している感じなんでしょうね
- ただ、何も知らずに作るのと知った上で判断するのでは大違いだと思いますので、まずは自分の作ったWebページにツールを適用してどのような結果になるか見てみてはいかがでしょうか

## 追記

- 記事を書いた後に[axe - Web Accessibility Testing](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd)というChrome拡張を知りました。こちらの方が使い勝手がいいかも。

## 追記2

- よくよく調べるとChrome DevToolsでもいろいろできることが分かったので別記事で書きました
    - [ChromeDevToolsでコントラスト比をチェックする
](https://qiita.com/ozaki25/items/434101dd561c4242e30d)
PHP swithc文で型比較に対応する

# 目的

- PHPのswitch文で詰まった部分を簡単にまとめる

# 前提情報

- 下記のサービスで動作を確認した。
    - [https://paiza.io/ja](https://paiza.io/ja) 

# 詳細

- 下記のように記載することで`$foo`にstringの1かintの1かを厳密に比較する事ができる。

    ```php
    <?php
    
    switch (true) {
        case $foo === 1:
            echo 'int';
            break;
        case $foo === '1':
            echo 'string';
            break;
    }
    ?>
    ```
- `$foo`にintの1が格納されている時には「int」と表示され、stringの1が格納されているときには「string」と表示される。
ESP32用のマイコン内蔵RGB LED WS2813Bドライバの製作

ESP32-WROOM-32Dでマイコン内蔵RGB LED WS2813Bを駆動するためにこのプログラムを作りました。ハードウェアタイマ割込みハンドラとして記述していますので、メインの処理を(ほとんど)邪魔することなくLEDをドライブできます。作者はSDカードからwavデータを読み出し再生するプログラムに本LEDドライバを組み込んで動作確認しました。

開発環境はVisual Studio Code + PlatformIOです。
RGB_LEDで定義している定数値がGPIOピン番号(任意)です。
CPUクロックについては、board_build.f_cpu = 240000000L に最適化してありますのでCPUクロック80MHzなどの場合は、LED_WAITの定義値を小さくしてみてください。

```c++:main.cpp
#define RGB_LED     (27)

const unsigned int ledMask[24] = {
  0b000000000000000000000001,
  0b000000000000000000000010,
  0b000000000000000000000100,
  0b000000000000000000001000,
  0b000000000000000000010000,
  0b000000000000000000100000,
  0b000000000000000001000000,
  0b000000000000000010000000,
  0b000000000000000100000000,
  0b000000000000001000000000,
  0b000000000000010000000000,
  0b000000000000100000000000,
  0b000000000001000000000000,
  0b000000000010000000000000,
  0b000000000100000000000000,
  0b000000001000000000000000,
  0b000000010000000000000000,
  0b000000100000000000000000,
  0b000001000000000000000000,
  0b000010000000000000000000,
  0b000100000000000000000000,
  0b001000000000000000000000,
  0b010000000000000000000000,
  0b100000000000000000000000,
};

// cnt == 1 : 0.08us @ 240MHz
void ledWait(unsigned int cnt) {
  volatile int timeWaster;
  for(int i = 0; i < cnt; i++) {
    timeWaster += i;
  }
}

#define LED_WAIT  (5)
// data sender for WS2813B
void IRAM_ATTR send24bits(unsigned int dat) {
  // reset
  //digitalWrite(RGB_LED, 0); ledWait(500);
  for(int i = sizeof(ledMask) / sizeof(unsigned int) - 1; i >= 0; i--) {
    if((dat & ledMask[i])) {
      // send '1'
      digitalWrite(RGB_LED, 1); ledWait(LED_WAIT << 2);   // 'H' about 0.8us
      digitalWrite(RGB_LED, 0); ledWait(LED_WAIT);        // 'L' about 0.4us
    } else {
      // send '0'
      digitalWrite(RGB_LED, 1); ledWait(LED_WAIT);
      digitalWrite(RGB_LED, 0); ledWait(LED_WAIT << 2);
    }
  }
}
```

使用例を以下に示します。

```c++:main.cpp
hw_timer_t *timerLed = NULL;

const unsigned int ledPattern[] = {
  0b000000000000000011111111,
  0b000000001111111100000000,
  0b111111110000000000000000,
};

void IRAM_ATTR ledOut() {
  static int idx = 0;
  send24bits(ledPattern[idx]);
  ++idx %= 3;
}

void setup(void) {
  pinMode(RGB_LED, OUTPUT);

  timerLed = timerBegin(2, 16, true);
  timerAttachInterrupt(timerLed, ledOut, true);
  timerAlarmWrite(timerLed, 300000, true);
  timerAlarmEnable(timerLed);
}

void loop() {

}
```
ScilabのsyslinはデフォルトでD=-1

#ScilabのsyslinはデフォルトでD=-1
Scilabのsyslinでシステムを定義した際，D項を指定しない場合,デフォルトで$D=-1$で$D=0$になっていないので注意してください．
この罠にかかり，1時間無駄にしました．

#例

```math
\frac{dx}{dt} = -x + u\\
y=x\\
\\
u=1(step)\\
x(0)=-1\\
```
というシステムで，ステップ応答を計算します．
理論的には

```math
x(t)=-2*exp(-t)+1
```
です．
d項の指定なしの場合のステップ応答を計算するプログラムは次のようになります．

```Scilab
for i=1:3
    close();
end

A=[-1]
B=[1]
c=eye(1,1);
x0=[-1]

sys=syslin('c',A,B,c,x0)
t=0:0.01:10;
y=csim('step',t,sys)
clf();
plot(t,y)

figure();
y1=-2*exp(-1*t)+1
plot(t,y1)
```
結果は
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/d6acc7f2-91c0-a936-029e-37dd5df91409.png)
こうなります．
理論的には
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/2b1c4774-c6b5-65eb-8289-d521ffb1d3d9.png)
こうです．
最終的に1か0に収束するかの違いがあります．

というわけで，皆さん，d=-1の罠にかからないよう，d項もちゃんと指定しましょう．
というか，scilabよりpythonを使いましょう．
scilabはうんちです．気を付けてください
ScriptAutoRunnerを使って出品作業を楽にしてみた！

##経緯
電子機器を転売しているのですが、出品作業でいろいろと入力するのが面倒で何とかして入力作業を簡素化できないかと思い、入力簡素化の仕組みを作ってみました。
##使うもの
###ScriptAutoRunner
こちらクロムの拡張機能で追加することができます。
https://chrome.google.com/webstore/detail/scriptautorunner/gpgjofmpmjjopcogjgdldidobhmjmdbm?hl=ja-jp

UIはこんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/709188/97c22fad-e671-ca8d-6502-373d517332c7.png)
このマークがクリックできて黄色の状態がON
灰色はOFF
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/709188/be20abec-b40f-2b8c-747a-0de58b60adfc.png)

##簡単な説明
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/709188/8d366401-5b2d-ac51-4403-900d7b47bc37.png)


###スクリプト追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/709188/95650487-0393-d317-bac7-7596cabad6c3.png)

###①JSスクリプトを追加
ここのいつも通りJSを書いていくようゴリゴリする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/709188/159ad70c-5dae-c89f-c19f-4251f1d367dc.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/709188/9272cee3-fa84-2779-cb12-99583b5e363a.png)

###②JSスクリプトを追加
こちらはURL参照用のスクリプト追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/709188/6ec3fbfe-ac07-39ef-579d-004b092919a5.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/709188/7a3da4e2-61c6-1338-8264-4b9f0c2357d5.png)

##まとめ
また明日描く
プライベートサブネットからNATゲートウェイを使って通信する。

## 背景
NATゲートウェイというものを理解したかった。

## 前提(NATゲートウェイとは)
EC2側からネットワークを使いたいがクライアントから通信したくないというときに利用する。パブリックなサーバー(踏み台サーバー)を介してインターネットを利用できる。

## 準備
VPCを準備する。
パブリックサブネットとプライベートサブネットを持つVPCを用意しよう！最終的にはこんな感じの構成になります。
![aws-nat.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667634/bfd5f306-03aa-2d8d-97eb-198a0c0a4130.png)
プライベートIPアドレスに172.31を指定した意味は特にないです。10.0.0.0/16とかでも大丈夫です。

ポイントはIGW(インターネットゲートウェイ)の付いたルートテーブルとNATゲートウェイをくっつけたルートテーブルを作ることです。

まずはパブリックのルートテーブルの定義です。IGWとローカルでの通信ができるようにします。

![2020-12-08_23h38_56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667634/bffe5dd5-3657-b6db-5945-345ae1c12473.png)

続いてプライベート用のルートテーブルを作ります。ローカルでの通信とNATゲートウェイでの通信がしたいのでNATゲートウェイを作ります。
ここでの注意はパブリックのサブネットに置きます。また、Elastic IPも割り当てます。
作ったらこれをルート編集でプライベートのルートテーブルに付け加えます。
最終的にはこんな感じになります。

![2020-12-08_23h51_56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667634/d34dd50d-2d6e-da81-237f-350133e6609f.png)

NATゲートウェイは文頭にnatが付きます。わかりやすい！

あとはEC2をパブリックとプライベートに置きます。もちろんパブリックのEC2にはパブリックIPを付けます。
キーペアはパブリック、サブネットで同じにするとスムーズです。今回はamazon linuxで作っておきます。

## SSH接続
まずはパブリックサブネットに入りましょう。

```console
$ ssh -i xxxxxxxxx.pem ec2-user@xx.xx.xx.xx(public-ip)
```

パブリックのEC2に、ローカルにあるキーペアをコピペしましょう。

```console
$ vim xxxxxxxxx.pem
コピペしましょう
$ chmod 600 xxxxxxxxx.pem
権利を変更します。
```

次にパブリックサブネットからプライベートサブネットにssh接続しましょう。この時に使うのはプライベートIPです。

```console
$ ssh -i xxxxxxxxx.pem ec2-user@xx.xx.xx.xx(private-ip)
```

これでプライベートサブネット内のEC2に入れます。

試しにgoogleにアクセスしてみましょう

```console
curl https://www.google.com/
<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="ja"><head>...
```

たくさん文字列が表示されたら成功です。インターネットゲートウェイを付けずにインターネットに接続できました。

## 所感
VPCウィザードでなんとなく一緒に定義していたNATゲートウェイですが、プライベート性を保持しつつインターネットに接続できる便利な機能だというのが理解できました。AWSは箱庭みたいで楽しいです。
djangoでDBのレコードをオブジェクトとして取得する仕組みを見ながら存在判定する(初心者向け)

約１年ぶりの投稿です。去年はdockerでdjangoの環境構築をする記事を書きました。

今年は新卒で入社しまして、djangoでquerysetsの操作はかなり頻繁にすることが多かったので、よくあるDBのテーブルに、あるレコードがあるかないかの存在判定を仕組みを見ながら、忘備録として残します。



# オブジェクトがあるかないかを判定したい。
例えば User にid=5を持ったユーザーがいるか、いないか存在判定をします。
検索するときにid=5と指定すればいいのは簡単にわかりますが、ググっていると

* get()
* filter()
* etc ...

を使ったりして検索しています。


```python

User.objects.get(id=5)

User.objects.filter(id=5)
```


ふむ、どっちやねん。。。となり混乱することがありましたので公式ドキュメント QuerySet API(https://docs.djangoproject.com/ja/3.1/ref/models/querysets/ )を見ていきます。

この書き方によってのちにかく判定方法が変わっていきます。


# QuerySetの仕組みを理解する

* モデルマネージャー
* クエリセットAPI

について理解します。

### モデルマネージャ

```python
User.objects.all()
```
のobjectsのことです。modelがクエリ操作をするインターフェースとして持っています。
しかしDBと直接にはやりとりしません。

### クエリセットAPI

モデルマネージャーさんはクエリセットAPIを呼び出してDBを操作します。シャイです。
<br>

クエリセットAPIは

* DBにアクセスして欲しいオブジェクト
* DBにアクセスしないでクエリセット

を返します。(正確にはapiが提供しているメソッドからも２種類ではない)

そしてクエリセットが帰ってきた場合、DBにアクセスしていないので(遅延評価)、さらにクエリセットAPIをチェーンして書くことができます。

```python
User.objects.filter(id=5).get()
```


# get()とfilter()でどう違うのか

get()はオブジェクトを返します。しかしfilter()はquerysetを返します。

なのでget(id=5)として存在しなかった場合は「オブジェクトが存在しない」という例外を出します。

```python
try:
    user = User.objects.get(id=9) #　９のユーザーは最初から存在しない
except User.DoesNotExist: #例外を出す
    # 例外が出た時の処理

```

```python
from django.core.exceptions import ObjectDoesNotExist

try:
    user = User.objects.get(id=9)
except ObjectDoesNotExist: #例外を出す
    
```
こっちのエラーをimportして書くより、上の書き方をした方がimportしないのでコード量がちょっと減ります。


# 判定する時の使い分けはどうすればいいのか？

* get()は１つのオブジェクトしか取らないので、例外処理で有無を判定

* filter()はクエリセットなので複数のオブジェクトが入っている可能性があり、その数を使って判定に使える。

存在をそのまま調べるときはfilter().exsits()

```python
# Returns True if the QuerySet contains any results, and False if not.
if User.objects.filter(id=5).exists():
   # 存在していた時の処理
```

# filter()での判定
### 複数ある
* len()で数える
* count()を使う

公式ドキュメントにあるようにメモリーをパンクさせないように、一度全部取得しないといけないlen(queryset)よりcount()を推奨。ただし

　　1)後々そのクエリセットを使う場合
　　2)あえてmemoryに積ませたい場合

はlen()

* exists()を使う(上のパートで既出)

```python

# len()を使用する場合
user = User.objects.filter(id=5)
if len(user) == 1:
  # もしquerysetのなかにid5のuserが１つだけの時の処理


# count()を使用する場合
user = User.objects.filter(id=5).count()
# Returns the number of users whose id contains 5
```

# まとめ
オブジェクトの判定をするのにもいろんな方法があるのですが、公式ドキュメントでquerysetを返すのか何を返すのかページの右のリストにわかりやすくまとまっているので、やはり公式ドキュメントを何度も見ながら作業をすることになるでしょう。

参考: django 公式ドキュメント
https://docs.djangoproject.com/ja/3.1/ref/models/querysets
Qiita学習記録　HTML/CSS #1

#Qiita学習記録　HTML/CSS 

本日からWeb制作学習の記録をQiitaに綴っていきたいと思います。


①
セレクタ・プロパティ・バリューの三つの要素がある
セレクタの指定方法は大きく分けて三つ！「要素で指定」「classで指定」「子孫を指定」の３パターン
Webサイトはボックスで敷き詰められている（ボックスレイアウト）
ボックスはコンテンツエリア・padding・border・marginでできている


<h2>floatの処理について</h2>
あちこちにdiv class{clear}を入れることになると見辛くなる為、
clear:afterを用いる↓(そのまま覚える)


```css:style.css
.clear::after {
    content:"";
    clear: both;
    display: block;
}
```
floatさせている"header-left"と"header-right"を囲っている親要素(ここではcontainer)の横に"clear"を代入する。
するとfloat がクリアされる。

```html:index.html
<body>
    <header>
        <div class="container clear">
            <!-- before -->
            <div class="header-left">
                <h1 class="header-title">30DAYSトライアル</h1>
            </div>
            <div class="header-right">
                <ul class="header-nav clear">
                    <li class="header-nav-item"><a href="#">デイトラとは</a></li>
                    <li class="header-nav-item"><a href="#">コース一覧</a></li>
                    <li class="header-nav-item"><a href="#">お問い合わせ</a></li>
                </ul>
            </div>
            <!-- after -->
        </div>
    </header>
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/898926/c55e6308-0f9a-ea26-bb80-f9cfeedbb131.jpeg" width=50%>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/898926/96a5adc5-1e60-ef52-9d53-941a5e611bb1.jpeg" width=50%>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/898926/704a7886-eeb5-73e3-019e-6593fde05c39.jpeg" width=50%>
人生で4回目の転職をして半年以上経過したのでポエム書く

この記事はPhone Appli Advent Calendar 2020の9日目です。
※記事の内容はあくまで個人の意見であり、所属企業とは一切関連がありません。

---

目標の勤続1年まであと4ヶ月になりました。@sabineko です。

色々な理由で2社連続で1年以内に転職してしまった筆者ですが、今の会社では1年以上頑張りたいと思っているのでここで決意表明しておきたいと思います。 ~~（黒歴史になる可能性も~~


## 今はなんの仕事してるの？
toBのウェブシステムを作っております。主にフロントエンドを担当します。というかここ数年はフロントばっかりやってる人になってます。

## 転職って面倒じゃない？
面倒です。事務手続きとか諸々。でも、その環境にいてストレスがたまるとか、やりたいことができないとか、やむを得ない状況だったら転職するしかないのです。実際にやってみると恐れるほどのものではないことがわかります。

## リモート＆フレックスで探した結果
今の会社に出会ったのは、転職エージェントに「リモート可、フレックス、私服勤務で！」と依頼して紹介してもらったのがきっかけです。
エージェントに登録してくれててありがとう人事の方。

転職先を探し始めたのは2019年の9月頃。
当時は「来年オリンピックだから開催期間中は出社したくないなぁ…」という理由でリモート化の会社を探していました。それがこんなことになろうとは。

## コロナ禍で得たもの
それは真のリモートワーク。
フルリモート。フルフレックス。完全な自由（規則はあります）。

入社当初、弊社はフルリモートは一部の社員のみの適用だったのですが、コロナ禍により全社員フルリモートになり、出社は現在月一ほど（人によります）。

通勤電車と遅刻の概念から開放され、服装髪型についてとやかく言われることもなくなった結果、耳のピアスは3個増え、自宅のオーディオ環境は強化されることとなりました。

## おちこんだりもしたけれど、私はげんきです
なんやかんやある社会人人生ですが、ひとまず今は望んだ環境で働けているということをお知らせしておきます。とくにTwitterのフォロワーのみなさまの中には前々職からお世話になった人もいるので。

同じ会社の方々に向けては、今後ともよろしくお願いしますという挨拶をしてこのくだらないポエムを終わりにしたいと思います。


---

余談

当初はPythonでちょっとしたものを作る予定だったのですが、あまりに作ったものがしょぼすぎて「人に見せられねぇ！」となったので今回はポエムになりました。なにげにQiitaには初投稿のポエムです。

全く誰の参考にもなりませんし、この記事は転職を推奨するものでもありませんが、少しでも転職への抵抗感を減らし、皆様のより良いエンジニアライフをおくることができることを祈っております。


Advent Calendarの10日目は @noooooym さんの記事です。お楽しみに！
GASのCSV出力は(日本語を含む場合)、文字コードにShift-JISを指定しないと文字化けする

##やったこと
blobでcsvを生成するときに、newBlobで一回空のblobを作ってから、setDataFromStringでcsvテキストの実体と文字コードを指定する

##コード

```JavaScript:exportCsv.gs

function exportCsv(){
  let nowDate = new Date();
  let values = sheet_master.getRange(NUM_FIRSTROW-1, 2, sheet_master.getLastRow() -NUM_FIRSTROW +1, 11).getDisplayValues();
  
  //セル配列をカンマ区切りに書き換え
  let csv = "";
  for(let i=0; i<values.length; i++){
    csv += values[i].join(",") + "\r\n";
  }//end for
  
  //ここで文字コードを指定
  let csvBlob = Utilities.newBlob("", MimeType.CSV, "吐き出したCSV.csv").setDataFromString(csv, "Shift_JIS");
  csvFolder.createFile(csvBlob);
}//end function

```

##経緯

日本語を含むcsvを作ろうとするときだけ文字化けする。
毎回出力したcsvをエクセルで開いては「なんだこれ文字化けしてんぞ」ってやってコード書き直してたので書き殴りレベルだけどメモ。
Vim基本操作一覧

#はじめに
この記事は、基本的なVimコマンドを一覧としたものです。
ふと忘れた時に見返すことを想定しており、初心者が見て学ぶためのものではないことをご了承ください。
初心者は、シェルプロンプトにて`vimtutor`と入力して、Vimチュートリアルを学ぶことをお勧めします。

#用語
コマンド = オペレータ + 数値 + モーション
例) `d2w` = 削除オペレータ`d` + 繰り返し回数`2` + 単語モーション`w`

#シェルプロンプトでの操作
`vim` : Vim起動
`vim fileA` : VimでfileAを開く
`vim -p fileA fileB` : 複数のファイルをタブ毎に同時に開く

#ノーマルモード
##移動
`h` : カーソル左移動
`j` : カーソル下移動
`k` : カーソル上移動
`l` : カーソル右移動

`w` : 次の単語の先頭に移動
`e` : 次の単語の末尾に移動
`b` : 前の単語の先頭に移動
`2w` : 2つ次の単語の先頭に移動
`2e` : 2つ次の単語の終端に移動
`2b` : 2つ前の単語の先頭に移動

`^` or `0` : 行頭に移動
`$` : 行末に移動
`fa` : 行内の次の｢a｣に移動(;で次のaに移動)

`ctrl + f` : 1画面下に移動
`ctrl + b` : 1画面上に移動

`gg` : ファイル先頭に移動
`G` : ファイル末尾に移動
`2G` : ファイルの2行目に移動

`ctrl + o` : 前のカーソル位置に戻る
`ctrl + i` : 次のカーソル位置に進む

`%` : カーソル位置に対応する括弧に移動

##表示
`ctrl + g` : ファイル名と行数を表示

##テキスト削除
`x` : 1文字削除

`dw` : カーソル位置から単語終端までを削除
`d2w` : カーソル位置から単語2つ分を削除
`d$` : 行末までを削除

`dd` : 行全体を削除
`2dd` : 2行分を削除

##コピー
`y` : 選択テキストのコピー
`yy` : 選択行のコピー
`2yy` : 2行分をコピー

##ペースト
`p` : コピー or 削除したテキストのペースト

##取り消し(undo)
`u` : 直前のコマンドの取り消し
`U` : 行全体の取り消し
`ctrl + r` : 取り消しの取り消し(redo)

##検索(`n` で次, `N`で前の候補)
`/word` : ｢word｣を下に検索
`?word` : ｢word｣を上に検索
`*` : カーソル位置の単語を下に検索
`#` : カーソル位置の単語を上に検索

##便利コマンド
`.` : 直前のコマンドを繰り返す
`=` : インデントを揃える
`ctrl + n` : コマンドの補完候補を表示
`cit` : htmlなどでタグの中身だけを削除して入力

#入力モード(`esc` : ノーマルモードに切替)
##テキスト追加
`i` : テキストをカーソル位置に挿入
`a` : テキストをカーソル位置に追加
`A` : テキストを行末に追加

##テキスト変更
`r` : 文字の置き換え
`cw` : 文字列の置き換え
`c$` : 行末までを置き換え
`cc` : 行全体を置き換え

#コマンドモード
##保存(write)
`:w` : 保存
`:w fileA` : fileAとして保存

##終了(quit)
`:q` : 終了
`:wq` : 保存して終了
`:q!` : 保存せず強制終了

##開く
`:e fileA` : fileAを開く

##置換(substitute)
`:s/old/new` : 最初の｢old｣を｢new｣に置換
`:s/old/new/g` : 行全体を置換
`:%s/old/new/g` : ファイル全体を置換
`:%s/old/new/gc` : ファイル全体を確認(confirm)を取りながら置換
`:5,10s/old/new/g` : 10〜15行目を置換

##外部コマンド
`:!ls` : 外部コマンドlsを実行

##画面の分割(split)
`:sp` : 上下に画面分割
`:sp` : 左右に画面分割
`ctrl + w` + `w` : 次の画面に移動
`:close` : 分割画面を閉じる

##タブ
`:tabnew` : 新規タブを作成
`:tabe fileA` : 別タブでfileAを開く(tab edit)
`:tabclose` : タブを閉じる
`:tabdo %s/old/new/g` : 開いているタブ全体で置換
(`gt` :  タブ切り替え(go to next tab))

##設定
`:set number` : 行番号を表示
`:syntax on` : コード色分け
`:set tabstop=2` : タブの空白数を規定

#ビジュアルモード(`esc` : ノーマルモードに切替)
##選択
`v` : テキスト選択
`V` : 行選択
`ctrl + v` : 矩形選択
`ctrl + v` → `i` : 複数同時入力
`ctrl + v` → `x` : 複数同時削除
CircleCIでテストを非同期っぽく行う

# はじめに
push時にCircleCIでテストを行っていますが、テストが終わるのは1秒でも速いほうがよいので以降の処理に依存関係がないテストをbackgroundモードで実行し、非同期っぽいテストにしました。

利用環境
CircleCI Enterprise version 2.0

# 並列で実行できるテスト
CircleCIでテストをするとき、このような流れでテストを行うことが多いのではないでしょうか。実際にはこれ以外にテスト用コンテナやDBコンテナなどを起動する処理が必要ですが、ここでは省略しています。

![flow-small.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19807/bb5b4fa1-3a95-0c85-4850-652f40aac403.png)

よく考えてみるとLintとユニットテストは独立した関係なので、Lintをしながら平行にDBマイグレーションをしたっていいはずです。
![flow-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19807/59be2dca-5cc9-89ed-03f0-6da3bcf7b1a6.png)

# Backgroundオプションによる並列化
CircleCIの場合Lintのジョブとユニットテストのジョブを分離させて並列テストを行うことができますが、無料プランだと並列実行はできませんし、mediumインスタンス（標準のサイズ）は2vCPU割り当てられているので、1ジョブの中で並列化させてみたいところ。
もしかしたらversion 2.1ではうまいことできるのかもしれませんが、残念なことに利用しているCircleCIは未だに2.0です。

あいにくCircleCIにはジョブの中で処理を並列化させる機能はありません（たぶん）。しかしbackgroundオプションを利用すると、コマンドの終了を待たずに次のステップに進みます。本当は名前の通り常駐プロセスを起動させる用途に使うオプションですが、処理の並列化にも使うことができます。
[Background commands](https://circleci.com/docs/2.0/configuration-reference/#background-commands)

Lintを実行するためにはcomposer install, bundle installなどパッケージのインストールは完了している必要があります。しかしDBマイグレーションは不要です。一方ユニットテストは、Lintが終わっている必要はありませんが、パッケージインストールに加え、DBマイグレーションも完了している必要があります。つまりこのような順番で実行すれば良いことになります。
![flow-background.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19807/85238983-f298-a8e1-8db9-ce58cb1a2d4b.png)

# config.ymlの修正
では実際にconfig.ymlを修正してみましょう。config.ymlからテストの部分を抜粋しました。

```yaml:config.yml
      - run:
          name: Waiting for DB connection
          command: dockerize -wait tcp://cidb:3306 -timeout 120s
      - run: mkdir -p ~/reports/coverage
      - run: composer cs-check-report > ~/reports/cs-check-results.xml # ←ここをbackground処理にしたい
      - run: php artisan migrate --database=cidb --path=database/migrations/foobar --seed
      - run: ./vendor/bin/phpunit -c ./phpunit.ci.xml --coverage-html ~/reports/coverage tests/
```

backgroud処理に変更するにはrunコマンドのアトリビュートにbackgroudをつけてあげます。この例ではこんな感じになります。

```yaml:config.yml
      - run:
          name: Waiting for DB connection
          command: dockerize -wait tcp://cidb:3306 -timeout 120s
      - run: mkdir -p ~/reports/coverage
      - run:
          command: composer cs-check-report > ~/reports/cs-check-results.xml
          background: true # ←バックグラウンド処理にした
      - run: php artisan migrate --database=cidb --path=database/migrations/foobar --seed
      - run: ./vendor/bin/phpunit -c ./phpunit.ci.xml --coverage-html ~/reports/coverage tests/
 ```

この設定を行うと、`composer cs-check-report`が実行されると同時に次の`php artisan migrate`が開始されます。
非常に分かりづらい画像で恐縮ですが、`composer cs-check-report`が実行中（水色）のまま、`php artisan migrate`が完了（緑色）になっているのがおわかりいただけるかと思います。出力表示部の右上にExit code出力がないことでもわかるかと思います。
![cci.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19807/d97aec29-1ecd-5e56-047f-041f3b241ea8.png)


# 注意点
backgroudの本来の使い方とは異なるので注意が必要です。コマンドの完了を待たずに次に進むため、テスト結果に依存する処理がある場合は利用できません。たとえばテスト結果をartifactとしてアップロードする処理などです。また成否に関わらず次のテストに進んでしまうため、どこかのテストで失敗したら、その場で打ち切りたいケースなどには向いていないでしょう。
Zabbix4.2でBacklogの課題数を種別ごとに取得する


Zabbixのアイテムタイプを片っ端から調べていたところ、HTTPエージェントというものが目にとまりました。
Zabbix4.0から追加された新しいアイテムタイプで、APIのレスポンスを監視データとして扱えるようになっています。
今まではスクリプトを作成して、外部チェックのアイテムで取得していたようなデータを
スクリプトなしで取得できるようになったということのようです。

さらにZabbix4.2からは、ディスカバリルールでLLDマクロを指定することができるようになっています。
HTTPエージェントと組み合わせることで、APIのレスポンスを元にディスカバリアイテムを作成することができます。

これらの機能を利用して、Backlogの種別をディスカバリし、種別毎に課題数を取得してみたいと思います。

#テンプレートを作成

##ディスカバリルール
ここでは種別一覧を取得し、LLDマクロを設定します。

テンプレなので、URLやapiKeyなどの可変部分はマクロにしておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99398/6d5c344a-01fe-4400-2f20-e6a18de1cd3e.png)

上記のURLでbacklogAPIをリクエストすると、以下のような形で種別一覧を取得することができます。

```json:backlog種別一覧の取得
[
    {
        "id": 1931,
        "projectId": 470,
        "name": "タスク",
        "color": "#ff3265",
        "displayOrder": 0,
        "templateSummary": null,
        "templateDescription": null
    },
以下略
]
```

この中でアイテムのプロトタイプを作るのに必要そうな情報はid,nameですので、LLDマクロで以下のように設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99398/f25b7d8c-a461-dcf0-fe0a-46380dbf6b06.png)


##アイテムのプロトタイプ

アイテムのプロトタイプは次のようにします。
キーがかぶるとディスカバリできてもアイテムが作成されなくなってしまうので、必ずキーにLLDマクロを入れるようにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99398/90597639-5950-c356-fa63-727174866ed6.png)


素の状態でどんな値が取得されているのか確認するため、いったんデータ型をテキストにして値取得してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99398/6a660321-9b17-5b16-ab0b-3bd94479ce92.png)

レスポンス本文はbodyの中に入るんですね。
今回は課題数である14の部分だけ取得したいので、データ型を整数にして、保存前処理は次のようにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99398/906d52f4-f289-9770-6703-3acfeb11ba4f.png)


##マクロ
最後にマクロを設定します。
値はホスト側で設定するので、テンプレート側は空にしておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99398/6398c029-0770-ee10-4859-67ce4e11450b.png)

#データを確認してみる
仮想ホストにテンプレートを適用し、マクロを設定します。

ちゃんと種別ごとにアイテム作成されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99398/a1086d60-dcfc-e825-1e86-e8eb814f2d4a.png)

種別毎の課題数も取得できています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99398/a52d015a-0602-ee65-2dca-fc6e47496415.png)

#最後に

スクリプトを書く必要がなくなった上に、現在の状況に合わせてアイテムが自動生成できるのはかなり便利だと思いました。
今回例にしたもの以外にも、ユーザー一覧をLLDで取得して、ユーザー毎の担当課題数を取得するとか
目的次第でいろいろな使い方がありそうですね。


#参考

https://blog.atgw.jp/archives/3831
https://blog.apar.jp/zabbix/10769/


4.2の環境が手元になかったので、こちらを参考に構築しました。
https://qiita.com/qryuu/items/c3fb49b33068d6cbabf1
Railsアプリでmp4動画ファイルを表示させたい

# はじめに
**Rails6.0で作成するアプリで動画を背景として表示させたい！**
そう思い、ググりまくった結果やっとやりたいことが実現できたのでアウトプットとしてまとめたいと思います。
画像ファイルのアップロードについては情報がたくさんあるのに。。。笑

# この記事のゴール

* mp4動画ファイルを背景として表示させる

# 目次
[1.mp4動画ファイルの格納先](#1-動画ファイルの格納先)
[2.記述方法とオプションの種類](#2-記述方法とオプションの種類)

## 1. 動画ファイルの格納先
まず最初に、使いたい動画ファイルをどのディレクトリに格納すればよいかを確認します。
結論から言うと、`public/assets/videos/xxx.mp4`が格納先になります。

1. `rails new`でアプリを作成すると自動的に`public`ディレクトリが作成される
2.  publicの下に`assets`ディレクトリを作成
3.  assetsディレクトリの下に`videos`ディレクトリを作成
4.  videosディレクトリに使いたい動画ファイルを格納

画像ファイルの場合は`image_tag`を用いて表示させると思います。
この場合は`app/aseets/images`に画像ファイルを格納していると思います。

これから説明する`video_tag`は`image_tag`と別のパイプラインでデータを探してくるので画像ファイルと同じように動画ファイルを格納してもエラーがでてしまうので注意してください。

## 2. 記述方法とオプションの種類
それでは実装に入ります。
hamlで記述する場合は`video_tag`というヘルパーを用います。
今回は例として、index.html.hamlファイルに記述することとします。

```php:index.html.haml
= video_tag "/assets/videos/test.mp4", playsinline: true, controls: true, autoplay: true, loop: true, muted: true, width: "320", height: "240", class: "index-video"
```
次にオプションの説明に入ります。

| オプション項目 | 説明 |
|:----------:|:------------|:------------:|
| controls       | 再生ボタンや再生位置（シーク）、ボリュームを表示するかしないか        |
| autoplay     | ページが読み込み終わったら自動的に動画を再生するか      |
| loop       | 動画をループさせるかどうか        |
| muted         | 音を出すか出さないか         |
| height       | 要素の高さの指定       |
| width    | 要素の幅の指定     |
| class         | 要素にクラスを追加          |
| playsinline       | インライン再生を可能にする       |

各属性の値はtrueまたはfalseで指定しましょう。

補足：playsinline属性はスマホでアプリを閲覧する場合を想定して設定します。
この属性をtrueにすることによって全画面表示をせずにその場で動画を再生させることができます。
インライン再生を可能にするためには**autoplay**、**muted**、**playsinline**の３つの属性をtrueにしてください。

## おわりに
以上で説明を終わります。動画ファイル形式はなにか理由がない限り、mp4形式をおすすめします。
ブラウザ環境によって表示できないファイル形式が存在するためです。
最後まで読んでいただきありがとうございます！
お疲れさまでした。。
M5Stackでマルチタスク

# 概要
以前、M5Stackを搭載し、[スマホから操作できるラジコンを作りました](https://qiita.com/Teppei_s/items/ac83045d4a9e9d8078d0)。
モーターを動作させる処理とLCD更新処理が同じループにいるため、操作遅延等を引き起こす可能性があったり、LEDをほわほわ光らせる制御を同時に行いたいとき等にかなり処理が煩雑になってしまいます。

M5StackはESP32が入っており、ESP32はデュアルコアかつFreeRTOSで動いているとのことなのでマルチタスクを実装してみようと思います。

# 参考記事
* [マイコン徹底入門](http://miqn.net/rtos/index.html)
* [FreeRTOSでマルチタスク (on ESP32)](https://qiita.com/hideakitai/items/bd95d0db63097b8808f9)
* [M5Stackでマルチタスクを使ってセンサ取得・ログ記録を行う](https://westgate-lab.hatenablog.com/entry/2020/03/28/113621)

# 環境
* OS: MacOS Mojave
* エディタ:Visual Studio Code
* IDE: PlatformIO (VSCodeの拡張機能)
* マイコン: M5Stack GRAY

# マルチタスクとは
複数のタスクを並行して処理すること。

複数のコアが乗っている場合、それぞれのコアで処理を並行して行うことができる。

１つのコアでマルチタスクをする場合はスレッドに分け、一つのタスクを一定時間処理し、次のタスクを一定時間処理し...みたいにすることで並列処理を行う。

# タスク生成関数
参考記事にわかりやすく書かれていますが、`xTaskCreatePinnedToCore`でマルチタスクを生成できる。
また、[こちら](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/freertos.html)に詳細に書かれています。


```cpp:

BaseType_t xTaskCreatePinnedToCore(
    TaskFunction_t pvTaskCode,
    const char *constpcName,
    const uint32_t usStackDepth, 
    void *constpvParameters,
    UBaseType_t uxPriority, 
    TaskHandle_t *constpvCreatedTask,
    const BaseType_t xCoreID)
```

### pvTaskCode
関数ポインタ

### *constpcName
タスク名

### usStackDepth
スタックサイズ(Byte)

### *constpvParameters
タスクへ渡すパラメータ

### uxPriority
タスクの優先度
数字が大きいほど優先度が高い

### *constpvCreatedTask
タスクを参照するためのハンドラー

### xCoreID
タスクを実行するコア(`tskNO_AFFINITY` or `0` or `1`)
値が`tskNO_AFFINITY`の場合、タスクはスケジューラーが勝手にコアを決めてくれる。
**コア0**はWiFiやBluetooth通信機能で使用されるので、機能を使用する場合は避けたほうがいいかも。
**コア1**はloop関数が実行されるコア

# マルチタスクを実装
注意する点は

* **実行するタスク(関数)は終了してはいけない。無限ループを実装しましょう**。これを見つけるまでに時間がかかりました...
* **タスクには`delay`関数をいれる。**入れないと待ち時間がなくタスクが切り替わりません。

このソースコードではコア１を指定しているのでコア１でスレッドを生成してマルチタスクが実行されているということになります。
`loop`関数は呼び出し元で無限ループとなっているので終了しません。

```cpp:main.cpp
#define M5STACK_MPU6886    // IMUの種類を指定

#include <Arduino.h>
#include <M5Stack.h>
#include "utility/MPU9250.h"

TaskHandle_t lcdTaskHandle = NULL;

float accX = 0.0F;
float accY = 0.0F;
float accZ = 0.0F;

float gyroX = 0.0F;
float gyroY = 0.0F;
float gyroZ = 0.0F;

float pitch = 0.0F;
float roll = 0.0F;
float yaw = 0.0F;

float temp = 0.0F;

// Task function
void lcdUpdateTask(void *args)
{
  while (1) // マルチタスクの処理は終了してはいけない
  {
    M5.Lcd.setCursor(0, 60);
    M5.Lcd.printf(" %5.2f   %5.2f   %5.2f   ", pitch, roll, yaw);
    M5.Lcd.setCursor(220, 82);
    M5.Lcd.print(" degree");
    M5.Lcd.setCursor(0, 120);
    M5.Lcd.printf("Temperature : %.2f C", temp);
    delay(10);
  }
}

void setup()
{
  // LCD設定
  M5.begin();
  M5.Lcd.setBrightness(100);
  M5.Lcd.setTextSize(2);
  M5.Lcd.setTextColor(WHITE, BLACK);

  // IMU設定
  M5.IMU.Init();

  // マルチタスク処理実行
  xTaskCreatePinnedToCore(lcdUpdateTask, "lcdTask", 4096, NULL, 1, &lcdTaskHandle, 1);
}

void loop()
{
  // IMUのデータを取得
  M5.IMU.getAhrsData(&pitch, &roll, &yaw);
  M5.IMU.getTempData(&temp);

  delay(1);
}

```
OCaml Upcoming Changes 2020: Either

この記事は[ML Advent Calendar 2020](https://qiita.com/advent-calendar/2020/ml) 9日目の記事です。

OCamlにそろそろ入りそうな機能を紹介します。

今回は、次のOCaml 4.12で入る `Either`モジュールの紹介をします。

## 背景

`Either.t` 型はタプル型の双対で、タプル型 `'a * 'b` が「`'a` と `'b` 両方」を表すのに対して、 `('a, 'b) Either.t` は「`'a` または `'b` のいずれか」を表す。

either型はOCaml以外にもHaskellやCoq, Scalaといったさまざまな言語に採用されている（この記事では[Coqの `sumbool` 型](https://coq.inria.fr/library/Coq.Init.Specif.html#sumbool)をeither相当として扱う）。

また、Either型には「左派」と「右派」がいることも知られている。コンストラクタが2つだけのinductive typeについて最初のコンストラクタを真値として扱う（[if式の仕様](https://coq.inria.fr/refman/language/extensions/match.html#pattern-matching-on-boolean-values-the-if-expression)）Coqは `left` を正常値とする左派であり、型パラメータの部分適用ができるHaskellは最後の型パラメータを使う `Right` が正常値とする右派だ。Scalaは左派、右派どちらでもない中道派だったのだが、2.12（2016年ごろ）から右派になった。

OCamlは、 either は左右中立な型であるべし、ということで、成功/失敗といったバイアスの入ったeither型は別に `result` 型と呼びならわしている。このような流派には他にRustがある。

そんなOCamlに `Either.t` が入ったのは、 `List.partition_map` の導入がきっかけだ。

`List.partition_map` は `('a -> ('b, 'c) Either.t) -> 'a List.t -> ('b List.t * 'c List.t)` のような型の関数で、mapした関数の戻り値に応じてリストをふたつに分割する。

OCamlでは、このような場合は多相バリアントを使い ``('a -> [`Fst of 'b | `Snd of 'c]) -> 'a List.t -> ('b List.t * 'c List.t)`` のようにして、わざわざ型を定義せずに済ませる人もいた（[containersライブラリ](https://github.com/c-cube/ocaml-containers/blob/v3.1/src/core/CCList.mli#L219)とか）。今回の `List.partition_map` のPRも[最初は `result` 型で書かれていた](https://github.com/ocaml/ocaml/pull/9047)が、 `result` 型の `Ok`/`Error` をそのような意味で使うのは気持ち悪いということで、 `Either.t` が導入されることになった。

## 実装

前置きはこのくらいにして[`Either` モジュールのシグネチャ](https://github.com/ocaml/ocaml/blob/e307d1ea82d11b11ce93eeaef702cb69c5d4a0e4/stdlib/either.mli) を見てみよう。とは言っても、実装上面白いことは特にないので型定義と `map` まわりの関数の型だけ見てみる。

```ocaml
type ('a, 'b) t = Left of 'a | Right of 'b

val map_left : ('a1 -> 'a2) -> ('a1, 'b) t -> ('a2, 'b) t

val map_right : ('b1 -> 'b2) -> ('a, 'b1) t -> ('a, 'b2) t

val map :
  left:('a1 -> 'a2) -> right:('b1 -> 'b2) -> ('a1, 'b1) t -> ('a2, 'b2) t
```

最初に言っていた通り、OCamlの `Either.t` は左右に偏らない型なので、 `Left` にmapする `map_left` と `Right` にmapする `map_right` があり、両方にmapする関数を `map` と呼んでいる。ラベル付き引数を使っているのがOCamlの標準ライブラリとしては新しめなスタイルだろうか。

他の関数も同様に `*_left` と `*_right` が用意されている。

## おまけ: 他のML語族の言語のeither型

OCamlの御先祖様であるLCF MLには `α + β` 型という形でeither相当の型が存在した。 `α × β` なタプル型が生き残ったのに対し、 `+` の方は現代のMLには受け継がれなかった。この型の値は `inl : α → α + β` や `inr : β → α + β` といった関数でつくる。

Standard ML 97のBasisライブラリにはeither型は存在しない。 Successor MLでは[Eitherモジュールが提案されており](https://github.com/SMLFamily/BasisLibrary/wiki/2015-002-Addition-of-Either-module)、こちらもOCamlと同じく左右の偏りのない定義になっている。

F#でeither型にあたるのは [`Choice<'T1, 'T2>` 型](https://fsharp.github.io/fsharp-core-docs/reference/fsharp-core-fsharpchoice-2.html)だ。判別共用体のタグ名も `Choice1Of2` や `Choice2Of2` と、leftやrightといった言葉すら使っていない（F#はリストの畳み込みも`fold`と`foldBack`だったりする）。似たような命名法として、OCamlの[Janestreet baseライブラリ](https://github.com/janestreet/base)では `type ('f, 's) t = | First of 'f | Second of 's` のようにfirst, secondを使っていたりする。