OmniAICreator/Qiita-1.07M huggingface dataset:
IDEやMavenはすべてのデバッグ情報を含めてコンパイルしてくれている

`javac`には`-g`というオプションがあります。これはクラスファイルへデバッグ情報を含めたり、逆に含めない設定をするためのオプションです。

- `-g:lines`とすればソースコードの行番号を含めます
- `-g:vars`とすればローカル変数名の情報を含めます
- `-g:source`とすればソースファイル名を含めます
- `-g`とすればすべてのデバッグ情報を含めます
- `-g:none`とすればデバッグ情報を何も含めません

次のようなコードを`javac -g Hello.java`したとします。

```java
public class Hello {
    public String say(String name) {
        return "hello ".concat(name);
    }
}
```

それから`javap -l Hello`すると次のようになります（`-l`は行番号とローカル変数表を出力するオプションです）。

```
Compiled from "Hello.java"
public class Hello {
  public Hello();
    LineNumberTable:
      line 1: 0
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0       5     0  this   LHello;

  public java.lang.String say(java.lang.String);
    LineNumberTable:
      line 3: 0
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0       7     0  this   LHello;
          0       7     1  name   Ljava/lang/String;
}
```

`LineNumberTable`に行番号が、`LocalVariableTable`にローカル変数名が、そして`Compiled from 〜`という箇所にソースファイル名が含まれています。

`javac -g:none Hello.java`の場合はどうなるか。`javap -l Hello`したものがこちらです。

```
public class Hello {
  public Hello();

  public java.lang.String say(java.lang.String);
}
```

デバッグ情報は何も含まれていません。

我々はふだん明示的に`javac`をすることはなくEclipseやIntelliJ IDEAのようなIDEや、Mavenを使用してコンパイルしています。でも特に気にすることなくデバッグ時には対応するソースコードが勝手に開いて変数名を見ながらステップ実行ができるはずです。それはつまりIDEやMavenがデフォルトでデバッグ情報を含めてくれているということです。

Eclipseだとデバッグ情報を含めるかどうかを設定できます。デフォルトの状態をスクショしてみました。`vars`も`lines`も`source`も含めるようになっていますね。

<img width="461" alt="eclipse.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19129/d8ff2853-96ab-a7c5-4579-7267539f1343.png">

IntelliJ IDEAは使用していないので知らないのですが、おそらく似たような設定ができるんじゃないかなと思っています。

Mavenもデバッグ情報を含めるかどうかを[maven-compiler-pluginのdebugで設定できます](https://maven.apache.org/plugins/maven-compiler-plugin/compile-mojo.html#debug)。

ちなみに`javac Hello.java`とした場合はソースファイル名と行番号が含まれます。つまりデフォルトでも`javac -g:source,lines Hello.java`と同じということですね。

以上をまとめると、

- `javac`は`-g`オプションでクラスファイルにデバッグ情報を含める
- デフォルトではソースファイル名と行番号が含まれる
- IDEやMavenはデフォルトでソースファイル名と行番号に加えてローカル変数名も含んでくれる

ということになります。
アロー関数を理解していなくてツマッタ。

#はじめに
アロー関数に慣れてアロー関数ばかりを書いて、ふと通常の関数に戻して処理をしてみたら動かなくなった。

 ```javascript:script.js

 const food = {
    肉: ["豚肉", "牛肉", "鶏肉", "魚肉"],
    野菜: ["レタス", "玉ねぎ", "キャベツ", "人参"]
  };
  const target_food = "レタス";
  const result = Object.entries(food).filter(([category, food]) => food.includes(target_food));
  result.forEach(([category, food]) => console.log(category));
//結果　=>　野菜
```

 ```javascript:script.js

 const food = {
    肉: ["豚肉", "牛肉", "鶏肉", "魚肉"],
    野菜: ["レタス", "玉ねぎ", "キャベツ", "人参"]
  };
  const target_food = "レタス";
  const result = Object.entries(food).filter(function([category,food]){
    food.includes(target_food);
  });
  result.forEach(function([category, food]){
    console.log(category);
  });

//結果　=>　コンソールで何も表示されない
```

resultに対してconsoleで見ても空になっていた。なぜだ。。。
[アロー関数と関数の違いとthisの評価のされ方](https://qiita.com/shoichiimamura/items/aec874fc5cf55cde7fa1)
こちらの記事を参考にさせてもらうとアロー関数にするとreturnを省略できるみたい。
他にも色々と省略されてますが。。。

 ```javascript:script.js

 const food = {
    肉: ["豚肉", "牛肉", "鶏肉", "魚肉"],
    野菜: ["レタス", "玉ねぎ", "キャベツ", "人参"]
  };
  const target_food = "レタス";
  const result = Object.entries(food).filter(function([category,food]){
    return food.includes(target_food);
  });
  result.forEach(function([category, food]){
    console.log(category);
  });

//結果　=>　野菜
```

#結果

ただの凡ミスなんですが関数ごと特徴を理解して使うことが大事だなと思った次第です。
GoでBMI計算機を作ってみた

# 作成したもの

https://github.com/usk81/go-pi

# 設計

BMIだけの計算するものはあったので、実際の使われ方に合わせて、年齢ごとに使用する体格指数を変えるようにしてみました

## 仕様に関して

今回は一般的になものを使いましたが、体格指数はいろいろな種類があるので、Interfaceを用意しています

```go
type PonderalIndex interface {
	Calc(weight, height float64) (result float64, err error)
}
```

測定結果

```go
// Result is a ponderal index calculation result
type Result struct {
	Classification string
	Index          float64
	IndexType      string
	Status         string
}
```

### Classification (分類) / Status

| Classification | ステータス | 分類 |
|---------------|-------------|-------------|
| Severe thinness | Fatal | 痩せすぎ |
| Underweight | Warning | 痩せぎみ |
| Normal | Normal | 通常体重 |
| Overweight | Warning | 太り気味 |
| Obesity | Fatal | 肥満 |
| Severe obesity | Fatal | 太り過ぎ |

### IndexType (インデックスの種類)

| 年齢           | 種類  | 参照 |
|---------------|-------------|----|
| 5歳未満       | カウプ指数    | https://www.benricho.org/bmi/02youji.html |
| 5歳以上、15歳未満 | ローレル指数  | https://www.benricho.org/bmi/03jidou.html |
| 15歳以上     | BMI 　　　　　| https://www.wikiwand.com/en/Body_mass_index |

# 使い方

## インストール

```bash
git clone git@github.com/go-shway/shway.git
cd shway
go build -ldflags '-w -s' -o go-pi
```

## 基本的な使い方

```bash
# go-pi height(cm2) weight(kg) age 
e.g. go-pi 180 70 20
> Classification: Normal
> Index: 21.604938
> IndexType: Body Mass Index
> Status: Normal
```
IoT開発者向け疑似データ送信サービス「mockmock」とは

この記事は、[mockmockアドベントカレンダー](https://qiita.com/advent-calendar/2019/mockmock)1日目の記事です。

今回はアドベントカレンダー初日ということで、mockmockの概要を書いてみようと思います。

## mockmockとは
[mockmock](https://mock-mock.com/ja/)は、一言で言えば、「IoT開発者向け疑似データ送信サービス」です。
仮想デバイス"mock"が、指定したIoTバックエンドに向けて疑似データを送信します。
<img width="665" alt="スクリーンショット 2019-11-14 12.34.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39565/0f6913d4-3f62-9f16-d793-539de46fc715.png">

送信するデータの内容や送信先はコンソール画面から簡単に設定可能です。
<img width="813" alt="スクリーンショット 2019-11-14 12.34.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39565/c657a6c2-f639-09e4-68a1-24ff25cf19ae.png">

## IoTのテストデータ調達は難しい
IoTバックエンドは、データが来なければ動作しません。IoTはデータが命！
しかし、動作確認や負荷試験のためにデータを調達しようとするとなかなか難しいのです。

従来は、大きく分けて2つの方法がありました。

- 実デバイスからのデータ調達
- 自作シミュレーターからのデータ調達

### 実デバイスからのデータ調達
最も素直な方法ですが、物理的なモノが絡むがゆえに問題が出てきます。

#### 使いたいときに使えない場合がある
たとえば、
- 調達中 / 開発中だったり
- 故障してしまったり
- テスト機が少なく、ほかの人が使用中で使えなかったり

#### テストのたびに操作が必要
デバイス側の操作だけで結構時間を取られたりします。

#### 思い通りのデータを出すのが難しい
特に異常値やエラーデータは大変です。

たとえば温度センサーを使ったIoTシステムで、80度でアラートが来るとして、
それを確認するために実物の温度センサーを80度にするのはかなりの手間です。

エラーデータに至っては、出すためにデバイスを壊すのは非現実的ですし、
そもそも意図的に出せない場合もあります。

#### 大量デバイスでの負荷試験が難しい
大規模なシステムになると、リリース前に負荷試験をしておきたいという需要はあると思いますが、
それを実デバイスで行うのは非現実的です。
負荷をかけられるだけのデバイスの用意がまずできませんし、
用意できたとしても1台ずつセットアップしていくのも大変です。

### 自作シミュレーターからのデータ調達
実デバイスと同じデータフォーマットを送るシミュレーターを作る方法です。
異常値やエラーデータのテスト、負荷試験に関してはこちらの手段を取ることが多いと思います。
しかし、こちらも問題が。

#### 十分な開発時間が取れない
シミュレーターの開発は開発の本筋ではありません。
それゆえに、優先度が下げられてしまうケースが多々あります。
製品レベルのIoTデバイスのシミュレーターを真面目に作ろうとするとかなりの規模になるため、
しっかりとしたものを作るのは非常に難しいです。

#### 操作が洗練されない
十分な開発期間が取られなければ、UIも洗練されませんし、ドキュメントも作られません。
場合によっては開発した人しか使えないというケースも。

#### 仕様変更時にメンテナンスされない
仕様変更があっても、シミュレーターのメンテナンスにまで手が回らず、
久しぶりに動かすとうまく動かないということもあります。

## mockmockによる新たなデータ調達
mockmockという"専用サービス"からデータを調達することで、IoTのテストデータ問題を一気に解決します。

- いつでもすぐに必要なデータが送信可能
- 数千、数万台規模のデータも生成可能
- Webコンソールでテスト内容の共有も簡単
- 仕様変更時のメンテナンスコストが低い

これにより、開発・テストの工数削減や、テストの安定運用が見込めます！

## 連携サービス・対応プロトコル
2019年12月現在、以下に対応しています。
<img width="797" alt="スクリーンショット 2019-11-14 12.34.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39565/7205e6af-2e3c-6e73-0078-8e68fd9ffe58.png">

独自サーバー(=独自に構築したAPIサーバー/MQTTブローカー)や、各種パブリッククラウドのIoTでよく使われるサービス、そしてSORACOMへの送信も対応しています。

SORACOMはとても便利ではあるのですが、
SORACOMのサービスは基本的にAirSIMを挿したデバイスからのデータしか受け付けてくれず、テストが大変です。
しかし、mockmockはAirSIMを挿したデバイスのようにBeam/Funnel/Funkにデータを送ることが可能です！

## 利用料金
基本的には従量課金です。
同時に立てられるmockの数に対して単価が決まります。詳細は[こちら](https://console.mock-mock.com/pricing/price/calculation?currency=jpy&capacity=cn)。

また、無料枠もあります。アカウント登録から1年間、mock1台が利用できます。
クレジットカード等の支払情報を登録せずに利用できるので、気軽にお試しできます。

## まとめ
個別の機能に関しては、これからのアドベントカレンダーで紹介されていくと思います。
待ちきれない人はひとまず[チュートリアル](https://console.mock-mock.com/docs)をば！
IoT開発にはもはや障壁なんて無い。キミにはmockmockがある！

明日は@withelmoです。
独自サーバー向けプロジェクトを作るときのポイント、認証まわりについてです！
Chrome Dev Tool のコンソールの値をクリップボードにコピーする方法

開発をしていると巨大なデータの一部を変更してテストしたりだとか、API の返り値である値のみ変更してみたりだとか、とにかくJSON をコピーしたい！ああん！という衝動に狩られることがたくさんあります 笑

そんな時にはこの Tips を知っていれば大丈夫です。

まずはどうにかしたいデータを通常通りコンソールに出力します。

```js
console.log(json);
```

コンソールの出力結果を右クリックして `Store as global variable` を選択すると `temp1` という自動で生成される変数に出力結果がコピーされます。

あとは copy 関数でクリップボードに変数をコピーするだけです。

```js
copy(temp1);
```

`Store as global variable` のたびに `temp2,3,4・・・` とインクリメントされるので、画面の再読み込みまで保持してくれるので無限にコピーし放題です。

ちなみに

```js
keys(temp1) // Object のキーのみを配列で出力
values(temp1) // Object の値のみを配列で出力
```

こちらも大きなデータの内容確認に活躍します。

地味に便利 笑
データ分析人材のキャリアに関するAdvent Calendar始まります！！（データラーニングギルド）

データラーニングギルド代表の村上です。

みなさん、今年一年、いかがお過ごしだったでしょうか？

今年は、データ分析業界も、LookerがGoogleに買収されたり、TableauがSalesforceに買収されたり、Auto MLが一気に存在感を出して来たり、自然言語領域でbertが流行りだしたりと、例年に漏れず色んなアップデートがありましたね～！！

自分としては、実はこの一年のスタートとしては、会社を立ち上げたことや、今後に関して思い悩み、非常に悶々とした状況からスタートだった訳ですが、無事こうやってAdvent Calenadarを企画して、23名物メンバーに参加して頂けているので、感無量です！！

1年間もあると、何が起こるか分からないものですね～！！

自分のこの一年に関しては別の記事に書くとして、この記事では、Advent Clendarの趣旨を説明させて頂こうと思います。

## このAdvent Calendarに関して
[データラーニングギルド](https://data-learning.com/guild)に所属するデータ分析に関わっているメンバー23人に、以下のような記事を執筆して貰う予定です。

- この一年でどのような事に取り組んだのか？
- なぜそのようなことに取り組んだのか？
- 今後どのような方向性でキャリアを構築して行こうと考えているのか？
- 来年はどんな活動をする予定か？
- なぜそのようなキャリアと活動を考えているのか？

これらの記事を読みつつ、振り返りの参考だったり、キャッチアップする技術や観点等をブラッシュアップして抱ければと考えています。

## データラーニングギルドって？
詳しくは[データラーニングギルド](https://data-learning.com/guild)のページを参照して頂ければと思うのですが、簡単に言うと、「データ分析領域で働く人達の互助組織」です。名前に「ギルド」とついているように、ギルド型組織を目指して、データ分析人材がお互いに助け合えるような環境を目指しています。

今年の7月にテスト運用を始めた、立ち上げからまだ半年も経っていないコミュニティです。

執筆時点での参加メンバーは73名なのですが、そのうち23名の方にAdvent Calendarに参加して頂けているので、非常にアクティブですね！！

## なぜAdvent Calendarを企画したのか？
今年のGW明け辺りに、「[データ分析者のキャリアなんもわからん問題](https://note.com/0_u0/n/n601338a4dad8)」という記事がデータサイエンティスト界隈で話題になり、それに応える形で、「[データ分析人材の長期的キャリアという迷宮](https://tjo.hatenablog.com/entry/2019/05/10/190000)」、「[データ分析・機械学習業界で生き残るということ](https://note.com/yukinagae/n/n9eefa5fef8fb)」などなど、様々な方がキャリアに関する記事を執筆されました。

業界ででデータサイエンティストとして働いている人たちは、今のAI・人工知能ブームに関しては、期待値と実体にギャップがある、「バブル」であるということを感じながら仕事をしているかと思われます。

その一方で、データを活用したプロジェクトが増えて行くのも自然な流れで、人材が全然足りていないというのもまた間違いない事実です。

統計学・ビッグデータブーム、データサイエンティストブーム、AI・人工知能ブームと名前を変えながらも、ずっと同じような領域でブームが続いてきているので「なんだかんだ続くんじゃないだろうか？」という思いもあったりします。

ただ、この一年で「Auto MLとデータサイエンティストが勝負して Auto MLが勝った」というような話題も何度か耳にしました。

Auto MLに関してはモデリングや特徴量エンジニアリングの自動化を主とするので、まだまだ領域としては限定的ですが、実際にAuto MLを業務で使用してみて圧倒的な工数削減を実感しました。そんな技術革新がどんどん起こっている領域なので、

**「スキル選定をミスったら、時間をかけて習得したスキルが一瞬で技術が無に帰す可能性がある」**

ということ常に意識ながら、慎重にスキル選定をしなければいけないのです。まさに、どんなキャリアを選べばいいか「なんもわからん」、「迷宮」的な業界ですねｗ

そんな右も左も分からない、一寸先は闇のような業界ので働く方々に、以下のように活用して頂ければと思って、このAdvent Calendarを企画させて頂きました。

- 様々な立場の様々な人の視点を参考にデータサイエンスのキャリアを考えるきっかけになって欲しい
- データサイエンスの領域で働いている人達の統計的な情報として活用して欲しい

## どんな人が所属しているのか？（執筆する予定か？）
以下のように、未経験、初級者、現役、隣接領域といった感じで幅広いバックボーン、メンバーが執筆する予定となっております。

- データサイエンティストを目指しているメンバー
- データサイエンティストになりたてのメンバー
- データサイエンティストとして現役で活躍するメンバー
- 学生としてデータサイエンスを学んでいるメンバー
- エンジニアとして活動しているけど、これからデータ領域の技術も身に付けて行きたいメンバー

## みんなで協力して灯を照らしながら進みましょう！
このAdvent Calenarを読んで、この先どうなるか分からないデータ分析業界を明るいものだと思って貰えたり、新しい選択肢に気づいて貰えたりしてくれると嬉しいです！！

自分もどんな記事を執筆していただけるのか、非常に楽しみです♪
gcc で 64bit と 32bit のコードを使い分けるために便利なマクロ

### 動機
卒論のための開発の中で、64bit と 32bit の両方で実験する必要があり、コードを使い分けたい、と思い調べました。
めっちゃ忘れそうなので備忘録として残しておきます。
なお、テスト環境以外でも同じマクロの定義になっているかは確認できていないことをご留意ください。

### テスト環境
* Ubuntu 16.04.6 LTS
* gcc 5.4.0

## プリプロセッサが定義するマクロの確認方法
gcc では、プリプロセッサが定義してくれるマクロがいろいろあります。
それらは、以下のコマンドで確認可能です。
参考: [gcc のプリプロセッサの定義済みマクロ(Predefined Macros)の確認方法](https://qiita.com/naohikowatanabe/items/a4e1a3f8080210257a42)

```
echo | cc -dM -E -
```

## 64bit 環境で 32bit 用にコンパイルする方法
`-m32` をつけてコンパイルすることで、32bit 用のコードを生成することができます。
参考: [64bit Linuxで32bit ELFをコンパイル](https://qiita.com/mas9612/items/d680a5b4307bafd2d3a0)

```
gcc -m32 hello.c
```

## 32bit のときに定義されるマクロの確認方法
32bit 用にコンパイルしたときには、 `__code_model_m32__` というマクロが定義されます。
先ほどのプリプロセッサのマクロの表示を、32bit と 64bit の両方で行って、diffを取ってそれっぽいものを探すと出てきました。
筆者の環境と違う場合でも、同じ方法で調べられそうですね。

```
$ diff <(echo | gcc -dM -E -m32 - | grep 32) <(echo | gcc -dM -E - | grep 32)
9c9
< #define __INT_FAST32_MAX__ 0x7fffffff
---
> #define __INT_FAST32_MAX__ 0x7fffffffffffffffL
14,15c14
< #define __code_model_32__ 1
< #define __INT_FAST32_TYPE__ int
---
> #define __INT_FAST32_TYPE__ long int
17c16
< #define __UINT_FAST32_MAX__ 0xffffffffU
---
> #define __UINT_FAST32_MAX__ 0xffffffffffffffffUL
19a19
> #define __ORDER_BIG_ENDIAN__ 4321
24d23
< #define __ORDER_BIG_ENDIAN__ 4321
27c26
< #define __UINT_FAST32_TYPE__ unsigned int
---
> #define __UINT_FAST32_TYPE__ long unsigned int
```

## 実際にマクロを使ってみた

```c
#include <stdio.h>

int main() {
#ifdef __code_model_32__
  printf("32bit ");
  printf("sizeof(void *): %d\n", sizeof(void *));
#else
  printf("64bit ");
  printf("sizeof(void *): %ld\n", sizeof(void *));
#endif
  return 0;
}
```

```bash
$ gcc -m32 test.c
32bit sizeof(void *): 4
$ gcc test.c
64bit sizeof(void *): 8
```

以上になります。
誤り等があればご指摘いただけると幸いです。

### もっと便利な方法があるらしい

@ SaitoAtsushi さん、ご指摘ありがとうございます:pray:
> この記事の例の場合であれば sizeof の返却値の型である size_t の大きさによって分岐したいはずなので stdint.h にある SIZE_MAX を使うのが手頃かと思います。
ubuntuにpyenv環境を一発で建てるshellscript

# 結論
非常に使う機会の多い、pyenv環境でのpython。
その導入を自動化するための簡易なスクリプトです。
shファイルにまとめられた形式の記事が意外と見当たらなかったので、自分用も兼ねて投稿。
早速スクリプト本体を載せます。ただし...

**※注意※**
`$ source pyenv_setup.sh`で実行しましょう。
- `sh` とか `./` ではダメです。script内で実行しているsourceが上手く機能せず、pyenvのpathが通りません。
- 理由についてはこちらの[他記事様](https://qiita.com/YumaInaura/items/00437e6ab14d96adb71f#-source-%E3%81%A8--bash-%E3%81%AE%E9%81%95%E3%81%84)をご参照下さい。

```pyenv_setup.sh
# 依存モジュールの導入
sudo apt install -y build-essential libffi-dev libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev
# libssl-dev -> openssl
# libbz2-dev -> sqlite3
# libreadline-dev -> bz2
# libsqlite3-dev -> readline

# pyenv本体のダウンロード
sudo apt install -y git
git clone https://github.com/pyenv/pyenv.git ~/.pyenv

# .bashrcの更新
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init -)"' >> ~/.bashrc
source ~/.bashrc
pyenv -v # pyenvがインストールできたかを確認

# pythonのインストール
pyenv install 2.7.0
pyenv install 3.6.0
pyenv versions

# 使用バージョンの選択
pyenv global 3.6.0
pyenv versions
```
# 背景
普段良く使うものであれば、何でも一発で環境構築できるようにしておくと気持ち良いですよね。
特に、vagrantでubuntuを建てては壊し、建てては壊し、、、というのをよくやります。
そういうときも、Vagrantfileにこのスクリプトを読み込むよう書いておけば、`vagrant up`したときに一発でpython環境が構築できて楽ちんです。

# 参考
- [Linux — source コマンドは何をしているのか > 実は環境をリロードするためのものではない](https://qiita.com/YumaInaura/items/00437e6ab14d96adb71f)
Railsチュートリアルに載ってないトラブルへの対処法～私がよくつまづいた流れと対処法～

・gitの扱いがわからない～私が失敗してた流れ～

設定はRailsチュートリアルで設定できるので省略
git init
git add -A
git commit -m "namae"
これでセーブができるのだが…

・「おかしくなった、、戻したい！」
git log
でハッシュ値（パスワード的なやつ）チェック
git reset --hard ハッシュ値


・「前の状態に戻ってないんだが！？」
gitはあくまで「以前の状態へ戻す」
ということをしているのであって
「新規で作ったファイルを消してくれない」
という性質があります。

まぁ
全部消してからgitすればいいのですが
それもなんだかこわいので
こまめにgitしましょうってことなのですが、、

「あれ？これってどこ？」
これはgitの仕様として慣れるしかないでしょう。


・「…うげ、戻しすぎた」
未来から過去に戻れても
過去から未来には戻れません
要注意です。

そして、
戻りすぎるとgithubとherokuにコミットできなくなるので
なんとかしてこの状態を打開しましょう。

でも、
こんな状況の対処法はどこにも載ってない、、

対処法としては色々あると思います。
githubから取り出したり、gitのコミット履歴を消したり、、

その中でも
一番単純でわかりやすい方法としては

「新しくgithubとherokuの場所を作る」
というのがいいです。

しかし
そのときに問題があります。

「こっち側で設定したgitがpushの場所を覚えているから、新しい方にpushしてくれないぞ、、」

ここで

git push 新しいgithubやherokuのurl

という方法もありますが、
このままでは従来の方法でherokuをマイグレーションすることができないので、データベースが使えないことになってしまいます。

【既存の設定を変更する方法】
今設定されているURL（リモートリポジトリ）が出るコマンドが
git remote -v

ここまでわかればあとは簡単

削除して追加をすればよい。
（編集でもよいがここでは削除・追加する）

削除
git remote rm 名前
追加
git remote add 名前 url

【終わりに】
もっと良い対処法があれば追記したい
いつものように本番作業してたはずなのに

この記事は「本番環境でやらかしちゃった人 Advent Calendar 2019」の1日目です。
https://qiita.com/advent-calendar/2019/yarakashi-production

なかなか濃いラインナップが期待されますが、まずはさらっといきたいと思います。
具体性が乏しい部分もあると思いますが、そこはお察しください。。。

# やらかし

## 背景（前提条件）

- いっていに昔の話です
- ETL（データ加工）サーバ
    - 数十を超えるシステムからデータを集める
    - BIツールなどで活用できるように各種加工処理を行い、DBなどにロードする
    - 繁忙の違いはあれど、24/365で常時一定量の処理は稼働している
    - 複数のチームが共存しているサーバ
        - アプリ面では比較的疎
- ETL処理のリリース前に本番サーバ上で試験をする取り決めになっていた
    - 性能や本番相当データのテストが安全に行えるような環境が（当時は）存在しなかった
    - 修正リリースの場合、当該処理が動かない時間帯を狙って試験を行う（当然）
- 私はアプリチーム
 
## 問題編（経緯）

- ある日、チームメンバ（Aさんとする)がいつも通りの修正リリースすることを承認し、作業自体は任せていた
    - よくある修正で規模も小さく、局所的な対応のため、いつも通りやっといてください、という形で
- しばらくすると、隣のチームの電話がなった。定常ジョブが１０以上複数エラー終了したと連絡あり。
- そのとき自分は時間も権限もあったので、軽い気持ちで「ジョブ見ますよー」と言って、作業部屋に移動。
- SSHログインしたものの、ほとんどのコマンドが通らない。
    - `cd`は通る。`ls`やそのたツールのコマンドが通らない
    - この時点でいやーな予感はしたが。。。
- すると他のチームメンバの電話もバンバン鳴り出した。ジョブが落ちまくっているらしい。だが調査もできないので焦りが増していく。。

---

さて何が起きたでしょうか、、わかる人はわかるのでは。。。

## その時の思考と行動

- あれ、コマンド通らないのか、なんでだろ。しかも一部？
- 急にドカンドカン落ちるのか、ハード系障害かなあ、流石に影響範囲広いし
- そういや何やってんだろ、Aさん〜
    - Aさん「試験できなくなっちゃって、いったん障害対応優先ですかねー」
    - 自分「そうっすねー、どこまでやったんですか？」
    - Aさん「ちょうど試験用に共通ユーザの環境変数を書き換えたところです、試験用のモジュールを置く場所決めて、別途読み込めるようにしたんですけどね」
    - 自分「なるほどー。。。えっ何それ」
    - Aさん「`.profile`のPATHを直接書き換えましたよー」
    - 自分「…それやん絶対。。。」

## 原因

- バッチ処理が使っている共通ユーザの`.profile`を **手動でエディタで** 書き換えた
- その際、PATHのあるある間違いをやってしまった

```bash
#(修正前)
export PATH=$PATH:/app/bin
#(修正後)
export PATH=/home/xxx/work_test/bin
```

- 結果バッチ処理含め大量にエラーが発生

## 対応

- 部屋全員に「動くな！」と叫ぶ（logout禁止)
- `ls`などが通る、修正前のprofileでログインしている人を探した
- その人のターミナルを大事にして、`.profile`を元に戻した
- 周知し、ジョブの再実行大会を促す
- やってたリリース作業は延期。

---

ということで、以下は本アドベントカレンダーの必須項目です

# 振り返り

## 惨劇はなぜおこってしまったのか

- 普段の手順と変わっていたことに気づかなかった
    - 今までは本番のモジュールを上書きして手動テストしていた
    - Aさんは上書きよりも別場所においてテストしてから、確認済みのものを上書きすれば良いのでは？と考えた
    - 考えて工夫した結果ではあったが、裏目にでた
- 本番に手をいれる作業についての影響を甘くみていた
    - その作業が他の何に影響を及ぼすのか、ということは常に考えないと、本番環境だから。。。
        - 個別モジュール上書きだけなら自分のチームしか最悪落ちないが、、
    - 特にエディタで直接編集する、のようなアドホックな（ヒューマンエラーが混入しやすい）手順になっていた

## 二度と惨劇を起こさないためにどうしたのか

- ヤバイファイルはカジュアルにさわれないように権限制御
    - アプリチームが触れないroot管理に
- 経緯をまとめてグループ内へ周知、教育
    - 個人的に、新人などには影響ないところでPATHエラーを踏ませたりして、身をもって学ぶようにさせた
- その他（人の力で回避。チェック強化とか。。。）

# 終わりに

- 設計時にどの程度機能分離するか、やリリース時の手順をどうするか、などを考えるときに毎回思い出します
- 結局のところヒューマンエラーなので、仕組み化、自動化などで人の手をできる限りかけないようにするのが本質的には良いとは思います
    - 今の時代なら、安価・容易に、クラウド、各種サービスなどの組み合わせ、すなわち技術で解決できる、解決すべきである、と思います

以上です。。２日目以降も楽しみにしています！
AWS技術簿 その1 - EC2 -

AWSを勉強するにあたり、身につけた技術や知識を記そうと思い技術簿を作成しました。
初心者が書いてる事もあって、初歩中の初歩的な内容が多々あると思いますが、ご了承ください。
今回はEC2とAMI、それに付随する用語についてまとめます。

#EC2とは

EC2とは`Elastic Compute Cloud`の略。
ElasticのEにComputeとCloudのCが二つあるから先頭をくっつけてEC2になった。
AWSクラウドにある仮想サーバーで誰でも使用可能。
後ほど説明するが、AMIがないと起動ができない。

#特徴

- 数分で起動が可能な高性能なサーバー
- サーバーの増設や削除、マシン自体のスペック変更もとても簡単
- OS等の種類も豊富で好きなように変更ができる。(LinuxやWindowsなど)
- 1時間、または秒単位での従量課金が発生する

#AMIとは
`Amazon Machine Image`の略。
EC2のインスタンスを起動させる際に、必要な情報が全て入っているOSのイメージファイル。

#特徴

- AWSの他にもサードパーティからもAMIを提供を行っている。
- 自作でAMIを作成することも可能
- カスタムAMIを使用することにより、何台でもEC2を起動することができる。

##インスタンスってなんぞや？

ここでは、サーバースペックのことを指す。例えば、無料枠でよく使用されるインスタンスタイプ
>t2.micro

を見本で見ると、
>t = インスタンスファミリー
そのインスタンスの特徴を示す。詳しくは[インスタンスタイプ](https://aws.amazon.com/jp/ec2/instance-types/)に詳細な説明があるが、簡単に書くと以下の通り。

>>t系 -> 無料枠でおなじみt系インスタンス。
負荷が少ない時に`CPUクレジット`を貯めておき、高負荷時にCPUクレジットを消費して`バースト`と呼ばれる高い処理が行える系統。
CPUクレジットがない状態で高負荷になってしまうとサーバーへのアクセスが遅くなるなどのデメリットが発生する。

>>m系 -> CPUやメモリ、ネットワークをバランスよく提供しているインスタンス。
どこを見てもm系はバランスがいいと専らの噂なので一般利用だとm系がいいのではないだろうか。

>>c系 -> 高負荷用インスタンス。
性能が高いプロセッサエンジンを積んでいる為、コンピューティングの負荷が高いことを行っている時に非常に便利。

>2 = インスタンス世代
数字が大きければ大きいほど、インスタンスファミリーの性能が良くなる。

>micro = インスタンスサイズ
CPUやメモリ等のスペックによって名前が変わる。
下はnanoから上はmetalなんてものもある。

#ストレージとはなんぞや
簡単言うと、データの保存場所。EC2のストレージには2種類ある。

###EBS
`Elastic Block Store`を略してEBS。

- 高い可用性と耐久を併せ持っている
- 他のインスタンスに付け替えが可能
- EC2インスタンスを止めたりしても保持し続ける
- スナップショットを取得してS3に保存がきく
- 別途お金がかかる

以上の特徴が挙げられる。
そのため、OSやDBといった、永続的に使用したり、耐久性が必要なデータを置くときに非常に優れている。

##インスタンスストア

- インスタンス専用ストレージ
- 他のインスタンスとの付け替えはできない
- EC2インスタンスを止めたりしたらクリアされる
- 追加料金はなし

以上の特徴がある。
そのため、先ほどのEBSとは違い、一時ファイルなどの削除されても良いデータをこちらに保存することが多い。
【MQL4 : MT4】GUI の インジケータ | EA を作る【備忘録】【Dialog】

noteにて更に詳しく解説！
https://note.com/iceseeds/n/nfdae2c5ac2ef

2020/08/24追記
Youtubeにて動画解説
https://www.youtube.com/watch?v=imVHPZQanWs&list=PLAekJGpx3pyPZJjlnPF_cM0mwNLy5l1Vl&index=2&t=0s
List
https://www.youtube.com/playlist?list=PLAekJGpx3pyPZJjlnPF_cM0mwNLy5l1Vl


# シンプルなPanelを作る

標準ライブラリのPanel、Dialogクラスを使ってGUIを作って行きます。

#### ①CAppDialog にパネルベースを作成する
CAppDialogは、結合されたアプリケーションダイアログコントロールのクラスです。

**↓↓　Panelを作成するを作成する最低限のコード　↓↓**

```guiwindow.mq4
#include <Controls\Dialog.mqh> --- 1

CAppDialog AppWindow; --- 2

int Reason;

int OnInit()
{
   if( Reason != REASON_CHARTCHANGE && Reason != REASON_PARAMETERS )
   {
      if( !AppWindow.Create( ChartID(), "SampleTitle", 0, 50, 50, 500, 400 ) ) --- 3
         return( INIT_FAILED );
      if( !AppWindow.Run() ) 
         return( INIT_FAILED );
   }   
   return( INIT_SUCCEEDED );
}

void OnDeinit( const int reason )
{
   if( reason != REASON_CHARTCHANGE && reason != REASON_PARAMETERS && reason != REASON_ACCOUNT )//3 && 5 && 6
   {
      AppWindow.Destroy( reason ); --- 4
   }
   Reason = reason;
}

void OnChartEvent( const int    id,
                   const long   &lparam,
                   const double &dparam,
                   const string &sparam)
{
   AppWindow.ChartEvent( id, lparam, dparam, sparam ); --- 5
}
```
## ソースコード詳細
**1. Controlsフォルダの中のDialog.mqhをインクルードする。**
　MT4/Include/Controls　フォルダの中に部品が入っている。

```
#include <Controls\Dialog.mqh>
```

**2. グローバルでAppDialog クラスのインスタンスを宣言**

```
CAppDialog AppWindow;
````


**3. AppWindowのパネルを作成　と　AppWindow実行**
　AppWindow.Create( int ChartID(), string "Title", int subwin, int x1, int y1, int x2, int y2 )
　AppWindo.Run() で実行

```
if( !AppWindow.Create( ChartID(), "SimpleOrder", 0, 50, 50, 250, 170 ))
      return( INIT_FAILED );
if( !AppWindow.Run() ) 
      return( INIT_FAILED );
```

**4. AppWindowを破棄**
***ココは 最重要Point!***
パネルの破棄をしないと、時間枠やシンボルの各変更に、
既存のもの上に新しいパネルを追加にするので、無駄なパネルの生成になります。

```
void OnDeinit( const int reason )
{
   AppWindow.Destroy( reason );
}
```
**5. ChartEventイベントをAppWindow に渡す**

```
void OnChartEvent( const int    id,
                   const long   &lparam,
                   const double &dparam,
                   const string &sparam)
{
   AppWindow.ChartEvent( id, lparam, dparam, sparam );
}
```

## 実行結果
![Screenshot_9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542117/1908dfb9-850c-e915-a772-c48956523c4a.png)

## 最後に
これで最小限のコードでシンプルなPanelを作ることが出来ます。
ただ勿論Panelを作るだけだと何も出来ません。
次回があれば、ボタンの設置、ボタンイベントなどをやります。
ご意見、ご要望があればコメントください。
お疲れ様。


2020/08/24追記
Youtubeにて動画解説
https://www.youtube.com/watch?v=imVHPZQanWs&list=PLAekJGpx3pyPZJjlnPF_cM0mwNLy5l1Vl&index=2&t=0s
List
https://www.youtube.com/playlist?list=PLAekJGpx3pyPZJjlnPF_cM0mwNLy5l1Vl
たった2日でマスターできるiOSアプリ開発　集中講座

# じゃんけんアプリの作成

### 構築時環境
- Xcode (11.2.1)
- Swift 5
- Mac Mojave

### 準備

1. xcodeをApple Storeからインストールする
https://apps.apple.com/jp/app/xcode/id497799835?mt=12

2. プロジェクトの作成
XcodeでCreate new project → Single View Appを選択する
ProductNameを適当につける

#### オプション gitを使うなら 
3. Gitlabにアカウントを作成する (githubでも可)
https://gitlab.com/

4. GitLabと連携
Projectを作成するとGitのレポジトリーが自動で生成されている
リモートレポジトリを追加する

```
git remote add origin https://gitlab.com/****/****
git add .
git commit -m "Initial commit"
git push -u origin master
```

### 実装

ストーリーボードに部品を追加する  

```
@IBOutlet weak var answerImageView: UIImageView! 
@IBOutlet weak var answerLabel: UILabel!
// じゃんけん数字
var answerNumber = 0
```
ボタンが押された時にじゃんけん画像を切り替える
(じゃんけんの画像は本にあるリンクからダウンロードができる)

```
@IBAction func shuffleAcction(_ sender: Any) {
    
    // 新じゃんけんの結果を一時的に格納する変数
    var newAnswerNumber = 0
        
    // ランダムに結果を出すが、前回と異なる場合のみ採用
    repeat {
        // 0,1,2の数値をランダムに算出(乱数)
        // arc4ramdom_uniform()の戻り値はUInt32だがswiftの標準的な整数型にキャスト(変換する)
        newAnswerNumber = Int(arc4random_uniform(3))
            
    } while answerNumber == newAnswerNumber
        
    answerNumber = newAnswerNumber
        
    if answerNumber == 0 {
        // グー
        answerLabel.text = "グー"
        answerImageView.image = UIImage(named: "gu")
    } else if answerNumber == 1{
        // チョキ
        answerLabel.text = "チョキ"
        answerImageView.image = UIImage(named: "choki")
    } else if answerNumber == 2 {
        // パー
        answerLabel.text = "パー"
        answerImageView.image = UIImage(named: "pa")
    }
        
    // 次のコードの削除
    answerNumber = answerNumber + 1
}
```

### 注意
Xcodeを画面分割(Assistant Editor)モードを使うときは、メニューバーのEditor→Assistantを選択する
Xcode11とXcode9では少し画面分割の呼び出し方が違う
[Java] Core Java Reading Memo

- Keep result of mod be positive.

```java
Math.floorMod(-1, 10); // 9
```

- Quick-and-dirty list of the elements of a two-dimensional array

```java
System.out.println(Arrays.deepToString(arrays));
```

- In java, arrays of subclass references can be converted to arrays of supperclass reference without a cast. But attempting to store an Employee reference causes an ArrayStoreException at runtime.

```java
// Manager is superclass of Employee
Manager[] managers = new Manager[2];
managers[0] = new Manager();

Employee[] employees = managers;

// compile succeed, runtime exception java.lang.ArrayStoreException
employees[0] = new Employee(); 
```

- If the subclass constructor does not call a superclass constructor explicitly, the no-argument constructor of the superclass is invoked. If the superclass does not have a no-argument constructor and the subclass constructor does not call another superclass constructor explicitly, the Java compiler reports an error. 

```java 
class Employee {
    public Employee(int id) {

    }
}

class Manager extends Employee {
    // Compile Error: Implicit super constructor Employee() is undefined
    public Manager(int id, String name) {
    }
}
```

- Nowadays, some Unicode characters can be described with one char value, and other Unicode characters require two char values. 

```java 
"𝕆".length(); // 2
"A".length(); // 1
```

- If the method is private, static, final, or a constructor, then the compiler knows exactly which method to call. This is called static binding. Otherwise the method to be called depends on the actual type of the implicit parameter and dynamic binding must be used at runtime. 

```java
class Employee {
    public static void getInstance() {
        System.out.println("Employee");
    }
}

class Manager extends Employee {
    public static void getInstance() {
        System.out.println("Manager");
    }
}

public class Inheri {
    public static void main(String[] args) {
        Employee e = new Manager();
        e.getInstance(); // Employee

        Manager m = new Manager();
        m.getInstance(); // Manager
    }
}
```
RustでPythonのinput()みたいに標準入力を取得する

###はじめに
　単純に面白そうという興味からRust言語を勉強し始めたのですが、成果が見えるとやっぱりモチベーションがあがるので、AtCoderとかの競技プログラミングで使ってみたいと思いました。ここで問題になるのが標準入力、なにせめちゃくちゃ冗長でネットの記事にも「これだ！」とピンとくるのが無く途方に暮れていました。なので作りました、Pythonのinput関数っぽく。まだ本格利用していないのでRustaceanの方はいろいろ改造してください。そして私に教えて。

###環境
```
> rustc --version rustc 1.39.0 (4560ea788 2019-11-04)
```

###この記事の内容
1.作ったもの
2.軽い解説

###成果物
```Rust:input_rs.rs
fn input() -> String{
    let mut buf = String::new(); //A
    std::io::stdin().read_line(&mut buf).unwrap(); //B
    buf.trim().to_string() //C
}

fn main(){
    let s = &input();
    println!("{}", s);
}
```

###解説
input関数は引数なしで標準入力をString型で返します。
A. mut String型として`buf`を定義する。
B. `read_line`の一連の流れで`buf`に標準入力を格納する。
C. `trim`を用いて空白とかを除去して返却する。
String型として明確なので&input()とすると&str型として扱うこともできます。


###What is "trim()" ?
　「このtrim()ってなんだよ。こいついる？」と思った方はもう少しお付き合いください。
　皆様はどのような環境でRustを実行されていますでしょうか？上の`rustc --version`を見ればわかるかもしれませんが私はWindows10環境で実行しております。
　実験としてtrim()を外した状態の関数で以下のようなソースコードを作ります。

```Rust:input_test.rs
fn input() -> String{
    let mut buf = String::new();
    std::io::stdin().read_line(&mut buf).unwrap();
    buf.to_string()
}
fn main(){
    let s = input();
    let mut i = 0;
    for c in s.as_str().chars(){
        println!("{} : {} ({})", i, c, c as u8);
        i += 1
    }
}
```

標準入力に`hello`と入力します。

```
PS> ./input_test.rs
hello
0 : h (104)
1 : e (101)
2 : l (108)
3 : l (108)
4 : o (111)
 (13)
6 :
 (10)

```
**？？**
　理想としてはhelloのところだけ表示してほしいのですが13と10という謎の記号が出力されておりこれではようわかりません。
　ちなみにwslのubuntu(`rustc 1.38.0 (625451e37 2019-09-23)`)で同じソースをコンパイルし実行すると以下のようになります。

```
$ ./main_rs
hello
0 : h (104)
1 : e (101)
2 : l (108)
3 : l (108)
4 : o (111)
5 :
 (10)
```
**おわかりいただけただろうか？**
　この最後に出力されてた記号はラインフィード(10)とキャリッジリターン(13)で、親切なことにread_lineではここまで読み込んでしまう上に、windowsとlinuxだと改行の仕様がちょっと違うのでこうなってしまう。
このOS間の差を埋めるためにtrim()を用いて空白文字を削除しているのである。

###おわりに
　「Rustの標準入力について調べていたら改行文字の話がはじまってた…」という感じになったらごめんなさい。自分が実際にはまりかけた所を共有して少しでも何かの役に立てたら良いなという程度の記事です。ここまで読んでくださって本当にありがとうございました。
　ちなみに私はread_lineにはunwrapじゃなくてexpectを使った方が良いと思います。
[Python備忘録] 各種時間検証・While文の1回目が異常に遅い

# 環境
Python 3.6.8 :: Anaconda, Inc.
pyenv + virtualenv利用
Ubuntu 18.04（ノートPC，サーバともに）

# print文は当然遅い
print文はまじで遅い

```python
now = time.perf_counter() 
print(now) 
post = time.perf_counter() 
post2 = time.perf_counter() 
print(post-now) 
print(post2-post)
```

サーバにて強めのCPUで回した結果

```
3076898.47890643
0.00023056520149111748
3.0534807592630386e-05
```

ノートPC（core i5 vPro 8th Gen）で回した結果

```
144989.874304118
0.0001471959985792637
4.1409977711737156e-05
```

100~200マイクロ秒のオーダーで時間がかかるんですね

# while文の1回目が異常に遅い
While文に入るときの初回って異常に遅いんですね…オーダーが数桁違います…1~100マイクロ秒は決して無視できない（こともたまにあるの）です…

```python
import time

now = time.perf_counter()  
print(now)  
print("1: ", time.perf_counter() - now)  
now = time.perf_counter()  
i = 0
print("2: ", time.perf_counter()-now)  
now = time.perf_counter()  
while(True):  
    print("3: ", time.perf_counter()-now)  
    i+ = 1  
    now = time.perf_counter()  
    if i > 10:  
        break
```

サーバにて強めのCPUで回した結果

```
3038070.24794605
1:  0.00013073207810521126
2:  4.219589754939079e-05
3:  4.715612158179283e-05
3:  4.00003045797348e-07
3:  2.752058207988739e-07
3:  2.169981598854065e-07
3:  2.1094456315040588e-07
3:  2.1280720829963684e-07
3:  2.05356627702713e-07
3:  2.1373853087425232e-07
3:  2.039596438407898e-07
3:  2.100132405757904e-07
3:  2.9010698199272156e-07
```

ノートPC（core i5 vPro 8th Gen）で回した結果

```
105718.03308281
1:  0.00013153199688531458
2:  0.00010217200906481594
3:  0.00010353099787607789
3:  7.040071068331599e-07
3:  3.370078047737479e-07
3:  3.1400122679769993e-07
3:  3.2399839255958796e-07
3:  3.2500247471034527e-07
3:  6.600021151825786e-07
3:  3.949971869587898e-07
3:  3.789900802075863e-07
3:  3.180030034855008e-07
3:  4.6400236897170544e-07
```
[Swift]新規プロジェクト起動するとCould not find a storyboard named ‘Main’ in bundle NSBundleでひたすら動かない

## 状況
`Main.storyboard`を消して`Home.storyboard`とかを新しく作ったら

```
Could not find a storyboard named ‘Main’ in bundle NSBundle
```
がでてクラッシュする

#### ポイント
- `Home.storybord`にあるViewControllerと(例えば)`HomeVC`の紐付けはできている
- `Is Initial View Controller`はチェック入れてる
- `Main storyboard file base name`を消す or Main->**Home**に変更も両方やった
![スクリーンショット 2019-12-01 0.22.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427937/235a6284-2ecd-8f95-c568-7c65bc11f6b6.png)
- `Copy Bundle Resources`にもドラッグした
![スクリーンショット 2019-12-01 0.23.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427937/a6b4216c-fe58-86ed-3774-f119fef993ca.png)

## 対策
- **初期で生成される`Main.storyboard`は残したまま**プロジェクトの作成を続ける
->何らかの形で初期で生成したstoryboardの情報や参照状況が残っているからバグが起こる？
- 名前を変えたい場合は`Main.storyboard`を**残したまま名前だけ変える** or `Main.storyboard`の削除時に`Move to trash`せずに**`Remove reference`するにとどめる**

## 参考
**・[Could not find a storyboard named 'Main' in bundle NSBundle 対処方法 - Qiita](https://qiita.com/kakipo/items/f93cc2bdc8b36b67adbb)**
**・["Could not find a storyboard named 'Main' in bundle NSBundle" のエラーを吐いてしまい実機で動かない | makotton.com](https://makotton.com/2014/06/28/170)**
**・[xibをロードしようとしたらアプリ落ちる問題に少しハマったのでメモ - Qiita](https://qiita.com/akira581/items/aaa8bc1ae16262179670)**
GitHub Actions で PR のマージ前に rebase

# はじめに

この記事は[GitHub Actions Advent Calendar 2019](https://qiita.com/advent-calendar/2019/github-actions)の８日目の記事です。

５日目にも書いたんだけど、枠が余ってたので書いておこうかなって。

本当はリリースノートの準備をするActionについて書こうかと思ったんだけど、明日の人が書くっぽいので今日はお手軽なネタで、Git のログを綺麗にする rebase について書こうと思います。

# rebase

今更機能的な説明は必要ないですよね？
チームで開発してたり、複数機能を並行して開発してたりして、ブランチが入り乱れることってよくありますよね。
気にせずにPRをマージすると、ログが汚くなったり、コミットグラフが入り組んでしまって、割れ窓理論よろしく開発意欲が失われる気分になる諸兄も多いのではないかと。
個人的には交差したグラフを見るとあーぁって気になります。私、気になります。
交差ってほどじゃなくても[このレベル](https://twitter.com/raki/status/1200673079254372355)で、もうちょっとなぁってなる派。

スカッシュマージやリベースマージにする手もありますが、元コミットを残しておきたいとか、リバートするのにマージコミットは必要とかいろいろあるので、できればリベースしてからマージしたいかなと。
すると[こうなる](https://twitter.com/raki/status/1200673316765237248)わけで。


# cirrus-actions/rebase

そこで GitHub Actions でリベースできるようにすれば、ローカルでどうこうしなくても（PRの段階でコミットを整理してあれば）マージボタンを押す前に `/rebase` とコメントするだけでリベースしてくれる素敵 Action があります。

[GitHub action to automatically rebase PRs](https://github.com/cirrus-actions/rebase)

何も考えずに、`.github/workflows/rebase.yml` として、README に書かれているフローを保存しましょう。

後は PR をレビューしてもらって、マージしてもいいことになったら、 `/rebase` とコメントを打って、少し待ちましょう。

自動的にそのブランチが master から生えたようにリベースされます。

その後普通にマージボタンを押すだけで見やすいグラフの出来上がりです。簡単。

コミットについては言及していません。
typo とか test とかちょっと修正、みたいなコミットメッセージを乱発してれば、それはそのまま残ります。
このコミットを掃除するのはPRを投げた人の責任範囲だと思います。その範囲内でリベースもしてくれれば必要ないのですが、必ずしもみんなが対応できるとは限らないので、こういった簡単な Actions があると便利ですね。

# 最後に

GitHub Actions 便利ですよね。こういう小さい便利を積み上げていけるといいなと思います。
terraform-jp で 2020 年にやりたいこと

# はじめに

この記事は[全国ITコミュニティ運営者の2020こんなことやりたい妄想 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/community)の７日目の記事です。

[terraform-jp](https://terraformjp.github.io/) というコミュニティをやっています。
妄想というか、来年やってみようと思っているイベントについて書いてみようと思います。

# 半日ワールドカフェ

[既出](https://qiita.com/raki/items/c0a0b6eed83e39139e47)なのですが、普段の平日就業後のミートアップでは１時間しか取れないワールドカフェを、土日祝日などを使って半日くらいの時間でゆっくりじっくりやりたいなと思っています。

そもそもミートアップの際も運営側で動いていると、ゆっくりワールドカフェに参加できる時間も少なくて、どうにかしたいと思っているのと、ワールドカフェとはいえ人見知りが打ち解けて濃い話をするにはそれなりに時間が欲しいってゆうかｗ

昼過ぎから夕方までの間でおやつをメインに据えるか、午前中から始めてランチをメインに据えるか、会場とスポンサーと人数によって検討しようと思っています。場所とお金なら出すぜっていう素敵な会社様からのお声がけをお待ちしていますｗ
お声がけがなければたぶんいつもどおり大崎で開催になります。

# 実コード共有会

terraform は基本的に簡単なので（難しいのはクラウド等のリソース側、その組み合わせやベストな設定のほうです。概ね。）誰にでも書けるのですが、綺麗な書き方、素敵な使い方、便利な考え方、はやっぱりそれなりにあって、知見の蓄積が必要です。

業務で使っているコードを堂々と晒すのは、場合によっては憚られるかもしれませんが、それでもあえて実コードを晒しながら知見を共有する場が欲しいなと考えています。

流石に普段のミートアップのように誰かれ構わず参加ってわけにはいかないと思うので、募集の仕方含めて要検討な段階ですが、10名前後の少人数できちんと共有ができる人を募ってやってみたいと思っています。

# terraform じゃないんだけど会

先にも書いたとおり、terraform 自体は難しいところはほとんどなく、大事なのはクラウド側リソースがどのような状態になっていればいいのか、のほうが重要です。

あんまり terraform から離れるとコミュニティの意味がないので、terraform で作る前提で、AWS や GCP や Azure で、こういうところはどう設定するのがいいの？みたいな話がメインに持ってこられる会がやりたいなと思っています。

思ってはいるけど、これはあんまり賛同を得られないかもしれないので、大人しく Loft に行くだけにするかもしれません。

# HashiCorp Certified: Terraform Associate を勉強する会

HashiConf US の参加者は受験できたらしい terraform の認定試験があるのだけど、現時点（2019年11月末）ではクローズされていて、英語でも日本語でも受けられません。

ただ、[試験概要だけはまだ見る](https://www.hashicorp.com/certification/#terraform-associate)ことができるので、これを元に出題内容、回答に対して、予想、予測、検討する会がやれたらいいなと思っています。

HashiCorp とパートナー契約を結んでいる会社さん（ラックさんとかクラスメソッドさんとか）向けに、別の試験もあるので、それもやってみたいお気持ちはあるのだけど、一介のフリーランスにはやらせてもらえないってゆうかｗ

ともかく、試験がリリースされた時にはなる早で取りたいじゃないですか。その事前準備がしたいなって。
もちろん他の製品の勉強もしたいけど、terraform から大きく外れるので、それはそれ別のところでって感じで。

# 例えばAWSのステップバイステップガイドを terraform 化する勉強会

[AWSのステップバイステップガイド](https://aws.amazon.com/jp/getting-started/?nc2=h_ql_le_gs) っていうのがあって、マネージメントコンソールとか CloudFormation とかで環境を作って学びましょう、みたいなコンテンツなんだけど、これを terraform で表現する勉強会とかもくもく会とか、そういった感じのことがやりたいかなとか。

１つのガイドはさほど大きくないので、集まったメンバーで分担してコードを書いて、後でレビュー会をするとか。
エンジニアならコードで語れよ。みたいな？

# 地方遠征

コアメンバーがほとんど東京に集中していることもあって、自然に開催は東京になっているのだけど、きっと東京以外の場所にも terraform に強い人はきっとたくさんいると思うので、俺より強い奴に会いに行く、の精神で地方開催を推奨して、そこに遊びに行きたいと思っています。

terraform のことで地方遠征とか、想像するだけでうれしくなっちゃうね（少しおかしいｗ

# 終わりに

いろいろ好き勝手書きましたが、来年もいろんなことができたらいいなと思っているので、よかったら[terraform-jp](https://join.slack.com/t/terraform-jp/shared_invite/enQtNTM2NTYzNDY0OTkyLTUwMjVlMzZjODM4ODdkNTk3NTIyMDI5MDQ0ODg0YTZlNmU0YjA2MGJmNmFjNzNlYjI0Mjk3NmEzODhjYjBkYWU)に参加してみてください。
DataDog の Synthetics IP range を terraform で WAF に突っ込んで CloudFront を通過させる

# はじめに

この記事は[Datadog Advent Calendar 2019](https://qiita.com/advent-calendar/2019/datadog)の6日目の記事です。

みんな大好き DataDog の Synthetics で SSL 監視やら API テストやらする時に CloudFront が挟まってると 403 になっちゃうケースがあると思います。
IP アドレスで制限してたり、UserAgentで制限してたり、Geo Match だったり。
面倒なんで DataDog の IP Range を WAF の IP Address に突っ込んでやれば手っ取り早い。ということで。
社内からはOK、社外からはNG、DataDog などは通したい、とかあるあるですね。


# 前提

* https://aws.amazon.com/jp/cloudfront/
* https://aws.amazon.com/jp/waf/
* https://www.datadoghq.com/
* https://docs.datadoghq.com/ja/synthetics/
* Synthetics の IP Range https://ip-ranges.datadoghq.com/synthetics.json
* あと [terraform](https://www.terraform.io/)

# 代替手段

* そもそも制限しない（まぁ開発中とか本番以外の環境では閉じるよね）
* WAF じゃないところ、例えば LB や Web Server で制限
* UserAgent などの HTTP Header で判断。その場合は[この辺り](https://docs.datadoghq.com/ja/synthetics/identify_synthetics_bots/?tab=browsertests)を参照
* terraform を使わないなら前述のIP RangeのjsonからIPを取得して何かに登録して許可する

まぁぶっちゃけ通常の手段はそれなりに運用が面倒かなって。

# コード（の必要なとこ）

terraform が使えるならこれだけで十分（のはず）

```provider_datadog.tf
variable "datadog_api_key" {
  description = "DataDog Integration API Key"
  type        = string
}

variable "datadog_app_key" {
  description = "DataDog Integration Application Key"
  type        = string
}

provider "datadog" {
  api_key = var.datadog_api_key
  app_key = var.datadog_app_key
}

```

```aws_waf.tf
data "datadog_ip_ranges" "this" {}

resource "aws_waf_ipset" "datadog_ip" {
  name = "datadog_ip"

  dynamic "ip_set_descriptors" {
    for_each = data.datadog_ip_ranges.this.synthetics_ipv4

    content {
      type  = "IPV4"
      value = ip_set_descriptors.value
    }
  }
}

```

~~DataDog Provider は AWS Provider と違って api/app key を環境変数から自動的に読み込む機能が今の所ないので、いちいち書かないといけないのちょっと面倒。~~

2019/12/16 修正ここから

provider required なので書かないとダメだと思っていた API_KEYとAPP_KEYについて、ドキュメント内でも `DATADOG_API_KEY`と`DATADOG_APP_KEY`で環境変数渡しできると書いてあると [Twitter](https://twitter.com/k_bigwheel/status/1206362218230472704) で教えてもらいました。
試してみたところ確かにいけたので、`prodiver_datadog.tf`は書かなくても大丈夫です。
[k_bigwheel](https://twitter.com/k_bigwheel) さん、ありがとうございました。

2019/12/16 修正ここまで

値はいちいち入力するよりも direnv 等を使って適当に export するの楽でおすすめ。
github actions に突っ込んじゃうのも楽で可。

できた WAF の IP Address Conditions は普通に rule に組み込めるので、例えば PATH(/)やPATH(ヘルスチェックパス）と組み合わせてルールにして、ACL にして CloudFront に食わせてから Synthetics はそのパスを見にいくようにすればOK

# 気になる料金

Condition だけならお金はかからない、はず（なんの意味もないけどｗ）
WAFの料金は ACL(5USD) と Rule(1USD) と処理量（100万リクエスト辺り0.60USD） のはずなので、適当に計算してください。
[WAF料金](https://aws.amazon.com/jp/waf/pricing/)


# 最後に

以前の DataDog Provider は対応機能不足や、APIの仕様バグのせいで terraform 使う必要ないなって感じだったけど、この[datadog_ip_range data source](https://www.terraform.io/docs/providers/datadog/d/ip_ranges.html) ができたのと、 terraform v0.12 で追加された [Dynamic blocks](https://www.terraform.io/docs/configuration/expressions.html#dynamic-blocks) のおかげで面倒な IP 管理から解放された。。。。うれしさのあまりつい記事にしてしまいました。
serverless-python-requirements利用時のファイル構成

こんにちわ。Patheeの廣瀬です


`serverless-python-requirements`利用時の
ファイル構成についての情報があまり見当たらなかったので書いていきます

## 状況
会社で`AWS lambda`を利用したAPIを開発している
新規プロジェクトのバックエンドの一部です

## 概要

- 言語は`Python3.7`
- パッケージ管理は`Pipenv`
- `Serverless Framework`を利用して開発・実行・デプロイ
- パッケージは`serverless-python-requirements`を利用してLayer化
- 開発環境はDocker内に構築し、Docker内でローカルテスト(UT等)を実施する

## ディレクトリ構成

```
root
├── lambda
│   ├── env
│   │   ├── dev
│   │   │   └── resource.yml
│   │   └── prod
│   │       └── resource.yml
│   ├── handler
│   │   └── aaa # 各APIの単位
│   │       └── aaa.py
│   └── serverless.yml
├── layer
│   └── package
│       ├── Pipfile # ※1
│       ├── Pipfile.lock # ※2
│       └── serverless.yml
├── stepfunctions
│   └── sf_aaa.yml
├── docker-dompose.yml
├── Dockerfile
├── Pipfile # ※1へのSymbolic Link
└── Pipfile.lock # ※2へのSymbolic Link
```

## `Serverless Framework`のカバー範囲
### 作成
- Lambda
    - Layer
- API Gateway
- Stepfunction

### 利用のみ
- RDS
- SNS
- SQS
- VPC
- S3

## 問題点

Pipenvは以下の２つのシチュエーションで実施している

- Docker内にパッケージをインストール
- `serverless-python-requirements`でLayerを作成

上記の両シチュエーションで同じパッケージを利用されている状況にしたいため、
Pipfileを共通のものを使いたいが、
それぞれPipfileをディレクトリ指定することができなかった

ので、解決方法として、`serverless-python-requirements`で利用する方に実態をおき、
Docker内でのインストールではシンボリックリンクを上記ファイルに貼って凌ぎました

と、この記事を書くのに改めて調べていて、
[pipenvでPIPENV_PIPFILE環境変数を指定する場合は絶対パスにする](https://qiita.com/yohm/items/9675eb79126cea4a1a4e)で問題が解消されるのかも、、、
実際このディレクトリ構成を構築したのは数ヶ月前で、その時に上記を試したような記憶もあるのだけど曖昧、、、
時間があれば続報書きたいと思います
Terraform GitHub Actions

# はじめに

この記事は[GitHub Actions Advent Calendar 2019](https://qiita.com/advent-calendar/2019/github-actions)の５日目の記事です。

みんな大好き GitHub Actions で terraform を実行する[Terraform GitHub Actions リポジトリ](https://github.com/hashicorp/terraform-github-actions)の話をします。

早い話が workflow のテンプレートでも置いておこうかなって。

# Actions で terraform を動かすと何が嬉しいか

- 適用の抜け漏れが減る
    - fmt 漏れ、複数ディレクトリの関連チェック漏れなど、ついうっかりミスしてしまうことが減ります
- 自分の環境以外でもちゃんと動くことが保障できる
    - 普通動きますけど、たまにワーキングディレクトリ ~~が汚い~~ の整理が苦手な人とかいますよね。コードの適用漏れとか防げます
- ローカル実行しなくてもいいので、クラウドに対して権限のない人でも（適切に設定すれば）PRベースで作業が可能です
    - terraform が利用する IAM Role 等の権限は、基本的に強権限になりがちなので複数人で使いまわすのは本来は不適切です
    - もっとも、本当にこの辺りをちゃんとしていると自信持って言えるチームがどれほどあるの。。。（自戒
- 基本的に PR 実行かつ apply しない（planまでしかしない）ので、差分チェックが楽
    - 前述のとおりウチも強権限共有ローカル適用組なので（ダメ）PRを投げる時は plan 差分がない状態でマージするルールにしています
    - 簡単に言えば、ローカルで開発、apply して問題ない状態のコードをPRして、plan差分がない（リモートステートは同じものを見ている）状態を維持することで、リソースにコードを合わせる、タイプの運用をしています
    - コードでリソースをコントロールできるほど強くなりたいものですｗ

# テンプレート

リポジトリのトップにどーんと出ていますが、サンプルなので実運用には向いてません。バージョンをベタ書きするは複数個所に書かせるわ実行ディレクトリ（working_dir）は１つだわ。。。

ドキュメントとしては別にこれでいいですが、不親切なのは否めません。

というわけで、再利用しやすい実運用で実績のあるワークフローファイルを置いておきます。

使い勝手はいい自負はあるのでぜひご活用ください。

```/.github/workflows/pr_tf_all.yaml
name: pr_tf  # この名前がマージボタン付近の checks の名前に使われるので短いほうが見やすい
on:
  pull_request:
    paths:
    - "terraform/all/*/*.tf"
    # PR 中でこの paths にマッチするファイルが更新されている場合に実行される
    type:
    - opened
    - synchronize
    - rerequested
env:
  GITHUB_TOKEN:          ${{ secrets.GITHUB_TOKEN }}
  TF_ACTION_TFE_TOKEN:   ${{ secrets.TF_ACTION_TFE_TOKEN }}
  TF_ACTIONS_VERSION:    0.12.16
  # 各 step で何度も同じのを書くのが嫌なので一括してまとめた
  # 大体の env はこっちに書ける
  # が、tf_actions_xxx は現在のバージョンでは with で渡さないと受け取らなくなった
jobs:
  terraform:
    name: plan all   # この名前も checks の表示に利用されるので短くわかりやすい名前が望ましい
    runs-on: ubuntu-latest
    strategy:
      matrix:
        dir:
        - "terraform/all/dir1"
        - "terraform/all/dir2"
        - "terraform/all/dir3"
        # ディレクトリを分けてステート管理をしている（working_dirが複数ある）場合に
        # この strategy matrix を使うと、同時にそれぞれ実行される
        # たくさんあると実行時間がかかるので、適当に分割しておくのがおすすめ
    steps:
    - uses: actions/checkout@master
    - name: Terraform - Format
      uses: hashicorp/terraform-github-actions@master
      with:
        tf_actions_version:     ${{ env.TF_ACTIONS_VERSION }}
        tf_actions_working_dir: ${{ matrix.dir }}
        tf_actions_subcommand: 'fmt'
        # バージョンを変数化することで１回指定にした
        # working_dir を matrix.dir から拾うことで逐一書かなくていいようにした
        # 以下 validate, init, plan について同じ

```

# おまけ

ちなみに TF_VAR_ は plan だけあればいいので、plan の step で env 渡ししてる。本家にも[サンプル](https://github.com/hashicorp/terraform-github-actions/blob/master/examples/variables.md)がある。
Tensorflow DockerでTensorBoardを使う

# 環境
Ubuntu 18.04
Docker 19.03

# 手順

## 1. コンテナの起動。

```
$ docker run --runtime=nvidia -it -p [ホスト側のポート]:[コンテナ側のポート] tensorflow/tensorflow:latest-gpu-py3 bash
```

-pオプションで`[ホスト側のポート]`にアクセスすると、`[コンテナ側のポート]`にフォワードされるように起動する。
公開先のIPはデフォルトで`0.0.0.0`が指定されている。（`$ docker ps`で確認できる。）

【参考】
http://docs.docker.jp/engine/userguide/networking/default_network/binding.html
https://qiita.com/tifa2chan/items/a58e34019d4f10097a4d


## 2. tensorboardの起動

```
# tensorboard --port [コンテナ側のポート] --logdir [logのディレクトリパス] --bind_all
```

`--bind_all`もしくは`--host=0.0.0.0`でIPを指定。

【参考】
https://qrunch.net/@diatonic/entries/fPGdT6VC7FKEpCVm

## 3. ブラウザで開く。
`http://0.0.0.0:[ホスト側のポート]`をブラウザに入力する。

`TensorBoard 2.0.0 http://0.0.0.0:[コンテナ側のポート]/`と表示されるが、ホストからは直接コンテナのポートにアクセスできないので、コンテナ起動時に指定した[ホスト側のポート]からアクセスする。
鉄道ポモドーロタイマーなるものを作ったー。

こんにちは。N高等学校1年次のなっかのうです！

N高アドベントカレンダー、sifue先生の次ですが頑張りたいと思います。

#何作ったの？

今回は、勉強法でおなじみの「ポモドーロタイマー」に、

鉄道の駅名をくっつけた「鉄道ポモドーロタイマー」なるものを作成しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515312/43e513fa-581d-bdd2-4c3a-c38e105f6d62.png)

[GitHub](https://github.com/nakano1120/pomodoro)

[実際にやってみる](https://nakano1120.github.io/pomodoro/)

##どんなものや？

ポモドーロタイマーとは、

「勉強と休憩の時間を設定して繰り返すことでより集中できるようになる」

勉強法のためのタイマーです。

そこで、私は「駅間所要時間ってバッチリじゃないか？」と思い、

休憩駅と勉強駅を繰り返す鉄道ポモドーロタイマーを作成しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515312/3217b3f1-4be0-b1f8-a8ed-37742bd652be.png)

##利点

基本的にはポモドーロタイマーと一緒ですが、

現在の駅名などが表示されるため、

今どのくらいかなどがわかりやすく、

とても実用性のあるものになっています。

#コード（長いので一部）

```js
    function timermain(){
        let now = new Date();
        let diftime = (now.getTime() - start.getTime());
        let point = Math.floor(diftime / 100);
        let point2 = Math.floor(point % 10);
        let point3 = parseInt(9)-Math.floor(point % 10);
        let sec = Math.floor(diftime / 1000);
        let secsec = Math.floor(sec % 60);
        let sec3 = parseInt(59)-Math.floor(sec % 60);
        let min = Math.floor(sec / 60);
        let minmin = Math.floor(min % 60);
        let min3 = (parseInt(time[nowstation])-parseInt(time[nowstation-1]))-(parseInt(Math.floor(sec / 60))-parseInt(time[nowstation-1]))-1;
        let hour = Math.floor(min / 60);
        secsec = addZero(secsec);
        sec4 = addZero(sec3)
        min2 = addZero(minmin);
        min4 = addZero(min3);
        hour = addZero(hour);
        if(min+departuretime>=time[nowstation]){
            nowstation++
            coffeecount++
            let b = document.getElementById("bell");
            let d = document.getElementById("door");
            b.play();
            b.addEventListener("ended", function(){
		        d.play();
	        }, false);
            changenext();
            if(waittime==1){
                waittime=0;
                document.getElementById("study").innerHTML="勉強"
                document.getElementById("study").style.color="#ff0000"
            }
            if(coffeecount>stu){
                coffeecount=0;
                waittime=1;
                document.getElementById("study").innerHTML="休憩"
                document.getElementById("study").style.color="#00B2E5"
            }
        }
        if((min+departuretime)+1>=time[nowstation] && secsec>30){
            document.getElementById("next").innerHTML="まもなく"
        }else{
            document.getElementById("next").innerHTML="次は"
        }
        let numbering=47-nowstation
        numbering=addZero(numbering);
        section=station[nowstation]+"(JK-"+numbering+")"
        document.getElementById("nowstation").innerHTML=section;
        document.getElementById("nowtime").innerHTML=""+hour+":"+min2+":"+secsec+"."+point2;
        if(min>=alltime){
            clearInterval(stationtimer);
            alert("終了です。")
        }
    }
```

##今後の展望

 - 様々な路線に対応
 - 現実のトレインビジョンに似せる
 - コードをもうちょっと綺麗に
AWS ALB Ingress は時期尚早って話

# はじめに

この記事は[Amazon EKS #2 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/amazon-eks-2)の3日目の記事です。
WordPress on AWS EKS 的な作業をしたんだけど、AWS ALB Ingress は時期尚早だったわ、という話をします。
2019年11月半ばくらいの話であり、この記事が表に出た後にバージョンアップしてる可能性はゼロじゃないです。


# TL;DR

- やってみた系ブログのやってみた、は、そりゃできる
- ただし、AWS ALB として出来ることの多くが（たぶんもうしばらくは） **できない**
- つまり、表向き動くものはできる、が、顧客が本当に必要だったもの、は（今は）できない、のがわかったという話

# 環境構築

- terraform module を使いましょう
- https://github.com/terraform-aws-modules/terraform-aws-eks/tree/master/examples/basic
- ちなみに [terraform advent calendar](https://qiita.com/advent-calendar/2019/terraform) もよろしくお願いしますｗ

# AWS ALB Ingress Controller

- https://github.com/kubernetes-sigs/aws-alb-ingress-controller
- Setup のところに導入方法があります
- 今回の作業では helm のインストールやらコントローラのインストールやらも terraform の k8s provider を使ったんだけど、null_resource や file 関数を乱発したし、概ねマニフェストが公開されているのをいちいちリソースに直すのも面倒だった。k8s provider も正直いらんかった
- ExternalDNS とセットで使えば、作成された ALB を Route53 に登録してくれて便利。これは便利。

# （現時点でも）できることリスト

1. ALB(Application Load Balancers) - LR(ListenerRules) - TG(TargetGroups) の基本構成
2. 80,443 ポートリスナー
3. ACM 設定
4. パスベースのLR
5. Cognito を挟んでアクセス制限的なこと
6. 複数のTGへの振り分け（今回はWP本体とWP管理画面用の２つに分けた）

うん、まぁ一通りできる雰囲気はあるよね。ところがどっこい。

# （現時点では）できなかったことリスト

- ポートリスナー別のLRは書けない
    - 80 -> 443 へのリダイレクトルールは書ける
    - 80 用、443用と分けて書くことができない（別々のLRが書けない。両方に同じLRが同じ順序で登録される。これは酷い）
    - でもまぁ正直そんなに問題じゃない（80の最初で443へリダイレクトで特に困らないから）
- Cognito を挟むと全てのLRに適用される
    - 一部だけ外す、はできない
    - WP管理画面にCognitoを残してブログ面は外す、ができない。これは辛い
- パスベース以外のLRは書けない
    - IPベースやヘッダベースが使えない（もうどうしようもない）
    - [ISSUE](https://github.com/kubernetes-sigs/aws-alb-ingress-controller/issues/1070) はあがってる
    - ヘッダーベースのルールが使えないので、CloudFront からのアクセスのみ受け入れ、等ができない。完全に詰んだ。
- ALBの名前が自由に付けられない
    - 逆にそれさえあれば ExternalDNSなくても困らないのに
    - クラスター別の数字-deploymentで付ける名前-よくわからない英数字、みたいな名前になる
    - たくさんあると管理がめんどくさい
- できないこと、ではないけど、裏で頻繁に書き直し？が走っていて、コンソールやCLIでALBに手を加えてもマニフェストどおりに戻る
    - 手でLRを追加したり変更したりしても、元に戻ってしまう。Ingress を削除するわけにもいないので手が打てない
- コスト無視なら表向き用の ALB を Ingress でもう一つ作って(ブログ用と管理画面用と分ける)、CloudFront オリジンの1つとして追加して、パスベースルーティングを CloudFront にやらせることも可能だけど、ソウジャナイ感があったのでやらなかった

# 対策できたこと

- Cognito はなしの方向で、CloudFront + WAF でがんばった
- LBの名前はどうにもならないけど、ExternalDNS で Route53 record は固定の名前で登録できるので、それをオリジンにした
- CloudFront からだけ接続許可、は未だに出来ていないので、オリジンLBでアクセスされると普通のWPと同じ。セキュリティが気になるならここは致命的

# 最後に

- 遊びや勉強目的で使う分には特に問題ない
- 仕事で使うなら今はやめといたほうが無難
- 先のISSUEのコメント先のリンク先にもあるけど、今コミッタたちもどうやってマニフェストを書いて展開するか、を議論しているようなので、経過観察
- 一番欲しいところ、パスベース以外のルール対応なので、[この辺](https://github.com/kubernetes-sigs/aws-alb-ingress-controller/blob/master/internal/alb/ls/rules.go)どうにかすればワンチャン。。。