OmniAICreator/Qiita-1.07M huggingface dataset:
統計用語 P値とは

このページでは、統計用語の指標として耳にする「**p値**」について記述する。

1～3章では、p値を理解するにあたり必要な前提知識について説明する。
**前提知識のある方は、「4. 考え方の手順」から**読むことをお勧めします。

#p値を理解するに当たっての手順
1. 「p値」とは、簡潔に言うと何なのか
2. p値は確率
3. 有意水準とは
4. 考え方の手順
5. 例
6. 最後に

#1. 「p値」とは、簡潔に言うと何なのか
**確率のこと**

では、そもそも確立とは、何なのか。
ジャンケンを例に挙げる。
この場合、直感的に確立を頭で考えてジャンケンをしている人も少なくないのではないだろうか。つまり、自分の出した手に対して、勝てる相手の手は、1通りしかないということである。したがって、グー・チョキ・パーの中で勝てる手は1通りしかないのである。よって、自分が勝てる確率は 1/3 = 0.33...ということになる。
これらをまとめると、確率とは
**「ある事象が起こる割合」**である。ここで言う、ある事象とは、自分の出した手に対し、相手の手が負けることである。

#2. p値は確率
上記の項を踏まえると、確率10%というのは、ジャンケンで100回に10回勝つということである。
これを、p値で例えるとp値が0.05(5%)というのは、100回に5回起こりうるということになる。
また、p値を表す際、「p < 0.05」の形が多いと思う。この式が表す意味をこれまでのことを踏まえると、
***「p値は、5%より小さい確率」***ということになる。つまり、p値が小さいほど、確率が小さくなる。なので、起こり得る確率が低いことを意味する。

#3. 有意水準とは
ここでは、有意水準とは何かについて説明する。
上記の「p < 0.05」の式を用いて説明する。
ここでの0.05という数字が、有意水準を表している。
また、0.05は、例として設定した値だが0.01でも0.001でも何でも良い。
つまり、有意水準とは、**「p値を判定するときの基準であり、値は自由に決めて良いもの」**である。
(ただし、0.05に設定されていることが多い)
「p < 0.05」の意味は、偶然にその事象が起こる確率が5%未満。つまり、***その事象が起こらない確率が95%以上***となる。

#4. 考え方の手順
ここでは、p値を使った考え方の手順を列挙する。
**①**主張とは、逆のこと(帰無仮説)を言う
**②**帰無仮説が成立する確率(p値)を求める
**③**p値と有意水準を比べる

#5. 例
ここでは、上記の考え方の手順に従って、例を交えて説明する。

**①主張とは、逆のこと(帰無仮説)を言う**
例えば、以下の仮説について考える。
「彼はカレーが好きだ」

この時、主張とは逆のこと(帰無仮説)を言うので、帰無仮説は以下のようになる。
「彼はカレーが嫌いだ」

**②帰無仮説が成立する確率(p値)を求める**
帰無仮説を上記で立てたが、この帰無仮説が偶然成立してしまうかも知れない。そのため、偶然成立する確率を求める。
この、「**帰無仮説が偶然成立する確率**」こそがp値である。

**③p値と有意水準を比べる**
上記で求めたp値(帰無仮説が偶然成立する確率)と有意水準(上記で説明)を比べることで、帰無仮説が成立するかどうかを確認する。

**③-ⅰ  p値 < 有意水準の時(主張成立)**
帰無仮説が偶然成立する確率が低いと言うことになり、
**帰無仮説は成立せず棄却。**
つまり、帰無仮説はほぼ成立せず、その逆の意味の①の主張は成立するということになる。

**③-ⅰⅰ  p値 > 有意水準の時(主張不成立)**
帰無仮説が偶然成立する確率が高いと言うことになり、
**帰無仮説は成立する確率が高い。**
つまり、帰無仮説はほぼ成立してしまい、その逆の意味の①の主張は成立しないということになる。

#6. 最後に
自分の理解をまとめただけなので、間違っている可能性があります。
その際は、ご指摘いただけると幸いです。

#参考記事
[p<0.05とはいったい何のことか～薬のパンフレットやグラフでよく見かける有意差の表記](https://www.fizz-di.jp/archives/1039688423.html)
[確率(かくりつ)とは - コトバンク](https://kotobank.jp/word/%E7%A2%BA%E7%8E%87-2326)
foreman起動時に読み込まれるProcfileに環境変数を設定する

## 環境

* Ruby 2.4.2

## foremanとは

複数の同時プロセスを管理してくれるツールです。
アプリケーションに関する何かを同時に起動させたい時とかに便利

## やりたかったこと

`Procfile`内で環境変数を展開したい。
公式を確認すると、`.env`ファイルから読み込まれるとありました。
なかなか具体的な方法についてあがっている記事がなく若干詰まったので、いかに書いておきます。

## 方法

以下のような`.env`ファイルを作成

```
MESSAGE=hello
```

`.env`ファイルから`Procfile`内で変数を展開するには、`$変数名`とすればおkです。
なので、`Procfile`を以下のようにしましょう

```yaml
echo: echo $MESSAGE
```

以上を行なったら、実行してみましょう。

```
$ foreman start
```

以下のように変数が展開され、helloが返ってきてるかと思います。

![スクリーンショット 2019-05-13 22.52.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19716/2c01a046-2727-3315-7e82-b37a5329295a.png)
Leetcode #7: Reverse Integer

```swift
func reverse(_ x: Int) -> Int {
    let isMinus = (x < 0)
    var x = abs(x)
    var reversedNumber = 0
    while x > 0 {
        reversedNumber = reversedNumber * 10 + x % 10
        x /= 10
    }
    if isMinus {
        reversedNumber = -reversedNumber
    }
    if reversedNumber < Int(Int32.min) || reversedNumber > Int(Int32.max) {
        return 0
    } else {
        return reversedNumber
    }
}
```
Leetcode #9: Palindrome Number

Solution 1: Convert to string 

```swift
func isPalindrome(_ x: Int) -> Bool {
    if x < 0 {
        return false
    }
    if x < 10 {
        return true
    }
    var str = String(x)
    var start = 0
    var end = str.count - 1
    while start < end {
        if str[start] != str[end] {
            return false
        } else {
            start+=1
            end-=1
        }
    }
    return true
}
```

Solution 2: Revert half of the number

```swift
func isPalindrome(_ x: Int) -> Bool {
    if x < 0 || (x%10 == 0 && x != 0) {
        return false
    }
    var revertedNumber = 0
    var x = x
    while revertedNumber < x {
        revertedNumber = revertedNumber * 10 + x % 10
        x /= 10
    }
    return x == revertedNumber || x == revertedNumber / 10
}
```
CSSで作るテキスト装飾デザイン（サンプル付き）

CSSでよく使うテキスト装飾デザインをコピペで使えるようにいくつか作ってみました。

##概要
・コピー＆ペーストで使い回せるように、テキスト装飾デザインを複数個作る

##タイトル装飾
###サンプル（デモ画面）
<p class="codepen" data-height="480" data-theme-id="0" data-default-tab="result" data-user="yamaki0405" data-slug-hash="zVqqKO" style="height: 480px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="text decoration3">
  <span>See the Pen <a href="https://codepen.io/yamaki0405/pen/zVqqKO/">
  text decoration3</a> by yamaki (<a href="https://codepen.io/yamaki0405">@yamaki0405</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>



##テキスト装飾
###サンプル（デモ画面）
<p class="codepen" data-height="480" data-theme-id="0" data-default-tab="result" data-user="yamaki0405" data-slug-hash="MdaJVK" style="height: 480px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="text decoration1">
  <span>See the Pen <a href="https://codepen.io/yamaki0405/pen/MdaJVK/">
  text decoration1</a> by yamaki (<a href="https://codepen.io/yamaki0405">@yamaki0405</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>



##吹き出し
###サンプル（デモ画面）
<p class="codepen" data-height="480" data-theme-id="0" data-default-tab="result" data-user="yamaki0405" data-slug-hash="dEYzKL" style="height: 480px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="text decoration2">
  <span>See the Pen <a href="https://codepen.io/yamaki0405/pen/dEYzKL/">
  text decoration2</a> by yamaki (<a href="https://codepen.io/yamaki0405">@yamaki0405</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

###ジュエネレーター
今回吹き出しのデザインを作成する時に調べていたら、吹き出しを作るジェネレーターがあることを知りました。
手軽に吹き出しを作りたい方は、こちらで作ったあとで微調整というのでも良さそうですね。

・[cssarrowplease](http://www.cssarrowplease.com/)
・[Bubbly](https://leaverou.github.io/bubbly/)
・[Bubbler](http://ilikepixels.co.uk/drop/bubbler/)


以上です。
最後までお読みいただき、ありがとうございました。
discord.py でボイスチャンネルの入退出をテキストチャンネルに通知するコード

```python
import discord
from datetime import datetime, timedelta

client = discord.Client()

@client.event
async def on_voice_state_update(member, before, after): 
    if member.guild.id == 監視するサーバーid and (before.channel != after.channel):
        now = datetime.utcnow() + timedelta(hours=9)
        alert_channel = client.get_channel(通知させたいテキストチャンネルid)
        if before.channel is None: 
            msg = f'{now:%m/%d-%H:%M} に {member.name} が {after.channel.name} に参加しました。'
            await alert_channel.send(msg)
        elif after.channel is None: 
            msg = f'{now:%m/%d-%H:%M} に {member.name} が {before.channel.name} から退出しました。'
            await alert_channel.send(msg)

client.run("あなたのトークン")
```

## このエントリを書いた理由
[随分前に書かれたコード](https://gugutasuujimasa.blogspot.com/2018/10/discord.html)が最新版のdiscord.pyで動かないって困っている初心者の方がいたので、彼のためにその古いコードを最新版の discord.py (記事執筆時点でv1.1.1) 向けに書き直しました。
せっかくなので公開します。
awkでevalしたい...

[awkでparsec風パーサ](https://github.com/opiliones/parser.awk)を実装した際に作成したeval風関数。

### 使用例
コードを読み込んでeval関数を生成する。

```bash:sample
awk "`./geneval << EOF
  function hoge(arg1, arg2) {
    print arg1" "arg2
    return 1
  }

  function fuga(fun) {
    return eval(fun)
  }

  BEGIN {
    fuga("hoge hello eval!")
  }
EOF
`"
```

```
$ ./sample
hello eval!
```

引数の文字列が関数から始まると仮定して、最初に現れた関数名に使用できない文字を引数間の区切り文字だと判断する。awkだと文字列と数値をよきに変換してくれるのでそれなりに動くが、配列オブジェクトを渡す手段はない…

### コード
```awk:geneval
#!/usr/bin/awk -f

BEGIN{
  if (ENVIRON["CALLER"]) CALLER=ENVIRON["CALLER"]
  else CALLER="eval"

  if (skip) REG="#[     ]*"skip
  f=1

  print "  function " CALLER "(args,   ret, arg) {"
  print "    if (match(args, /[^_a-zA-Z0-9]/))"
  print "      split(args, arg, substr(args, RSTART, 1))"
  print "    else"
  print "      arg[1]=args"
}

{buffer[NR]=$0}
REG && $0~REG {if (f) f=0; else f=1}
f && /\<function[   ]+/ {
  gsub(/.*\<function[   ]*|\(  .*|,  .*|\).*/, "")
  gsub(/[(,]/, " ")
  n=split($0, funarg)

  if (n>1) {
    args="("
    for (i=2; i<=n; i++) args=args "arg[" i "], "
    sub(/, $/, ")", args)
  } else args="()"

  if (! c++)
    print "    if (arg[1]==\""funarg[1]"\") {"
  else
    print "    } else if (arg[1]==\""funarg[1]"\") {"

  print "      ret=" funarg[1] args
}

END{
  print "    } else {"
  print "      print \""CALLER": \"arg[1]\" is not found!\" > \"/dev/stderr\""
  print "      exit 1"
  print "    }"
  print "    return ret"
  print "  }"

  for (i=0; i<=NR; i++) print buffer[i]
}
```
Leetcode #11: Container With Most Water

```swift
func maxArea(_ height: [Int]) -> Int {
    var area = 0
    var start = 0
    var end = height.count-1
    while start < end {
        area = max(area, min(height[start], height[end]) * (end - start))
        if height[start] >= height[end] {
            end -= 1
        } else {
            start += 1
        }
    }
    return area
}
```
Prism入門(3)

以前に勉強してから時間が経ったので、もう一度MVVMを勉強し直す。

環境：Visual Studio Professional 2019 + Prism7.1

# 1.環境構築

## 1-1.Prismインストール
Visual Studioを起動し、[拡張機能]-[拡張機能の管理]から『Prism Tempkate Pack』(バージョンは2019/5/13時点では2.1.6)をインストールする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187121/02c2323b-a365-1c52-ede3-4941cc1046ee.png)

## 1-2. .NETポータブルライブラリ対象パック
公式サンプルのファイルを開こうとしたらインストールする必要があった。

## 1-3.プロジェクト作成
新しいプロジェクトの作成で「Prism Blank App(WPF)」を選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187121/805e110c-c79b-7008-2879-76ad61d83932.png)

# 2.学習

## 2-1.公式サンプル
https://github.com/PrismLibrary/Prism-Samples-Wpf

# 3.方針

## 3-1.MVVMの方針

Viewのコードビハインド側には基本的に何も書かない。
ViewのXAMLとViewModelで対応する。

# 4.データバインド

## 4-1.ラベルのバインド

```xml:XAML
<Label Content="{Binding SystemDateLabel}" />
```

```cs:ViewModel
        private string _systemDateLabel = System.DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");
        public string SystemDateLabel
        {
            get { return _systemDateLabel; }
            set { SetProperty(ref _systemDateLabel, value); }
        }
```

## 4-2.ボタンのバインド
```xml:XAML
            <Button Content="{Binding BtnName}" Command="{Binding SystemDateUpdateButton}" />
```

```cs:ViewModel
 public MainWindowViewModel()
        {
            SystemDateUpdateButton = new DelegateCommand(SystemDateUpdateExecute);
        }

        //
        private string _systemDateLabel = System.DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");
        public string SystemDateLabel
        {
            get { return _systemDateLabel; }
            set { SetProperty(ref _systemDateLabel, value); }
        }

        //

        private string _btnName = "時刻更新";
        public string BtnName
        {
            get { return _btnName; }
            set { SetProperty(ref _btnName, value); }
        }

        public DelegateCommand SystemDateUpdateButton { get; }

        private void SystemDateUpdateExecute()
        {
            SystemDateLabel = System.DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");
        }
```
・ボタンのCommandにBindingで名前を付ける。
・ViewModelで付けた名前のDelegateCommandをプロパティで宣言する。
・コンストラクタでNewする。
・実行したいメソッドをPrivateで作成する。

# 5.画面遷移

## 5-1.ナビゲーション方式

1. 「Views」フォルダを選択し、右クリックで[追加]-[新しい項目]で、「Prism User COntrol(WPF)」を追加する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187121/be23db55-792e-fa73-e087-54d08216294c.png)

2. ViewとViewModelが自動で作成される。
3. 




# 9.TIPS

## 9-1.画面表示

## 9-1-1.画面の表示位置を中央に
XAMLファイルに「WindowStartupLocation="CenterScreen"」を記載する。
[Python] 可変長引数と引数の展開

## 可変長引数とは
可変長引数は関数の引数の個数を指定せず、引数を渡す方法です。
pythonでは引数名の前に*（アスタリスク）を付与することで可変長引数を指定することができます。

```python
def func1(*val):
    for value in val:
        print('value:', value)

func1(1, 2, 3)
```

結果

```python
value: 1
value: 2
value: 3
```

可変長引数を受け取った側での型を調べてみるとタプルであることがわかります。

```python
def func2(*val):
    print(type(val))
    print('val:', val)

func2(1, 2, 3)
```

結果

```
<class 'tuple'>
val: (1, 2, 3)
```

それでは次のように可変長引数を受け取った関数(func4)から、別の可変引数を持つ関数(func3)を呼び出した場合はどうなるのでしょうか

```python
def func3(*val):
    print(type(val))
    print('val:', val)
    for value in val:
        print('value:', value)

def func4(*val):
    func3(val)

func4(1, 2, 3)
```

結果

```
<class 'tuple'>
val: ((1, 2, 3),)
value: (1, 2, 3)
```

func4が受け取った可変引数（タプル）をそのまま引き渡したため、func3ではタプルの入れ子になってしまっています。func3でも入れ子になっていない変数で受け取るにはどうすればよいのでしょうか。

これを解決するしてくれるのが__引数の展開__です。以下の様に受け取った可変引数に*（アスタリスク）を付与すると、可変引数を展開してくれるので
func3では単一のタプルの引数で受け取ることができます。

```python
def func3(*val):
    print(type(val))
    print('val:', val)
    for value in val:
        print('value:', value)

def func4(*val):
    func3(*val)

func4(1, 2, 3)
```

結果

```python
<class 'tuple'>
val: (1, 2, 3)
value: 1
value: 2
value: 3
```

## 引数の展開
引数の展開では、リストやタプルの変数の中身をばらしてくれます。変数の先頭に*（アスタリスク）を付与することで引数の展開が行われます。(ディクショナリではキー項目のみ展開されます。)

```python
li = [1, 2, 3]
tp = (4, 5, 6)
dic = {'a': 7, 'b': 8, 'c': 9}
print(*li)
print(*tp)
print(*dic)
```

結果

```python
1 2 3
4 5 6
a b c
```

またアスタリスクを二つ付与するとキーワード可変引数に対して展開を行います。
こちらは、キーワード可変引数を受け取った関数から、別のキーワード可変引数を持つ関数を呼び出す際に重宝します。

```python
def func5(**kwargs):
    for k, v in kwargs.items():
        print('key:', k, ', value:', v)

def func6(**kwargs):
    func5(**kwargs)

func6(a=1, b=2, c=3)
```

結果

```python
key: a , value: 1
key: b , value: 2
key: c , value: 3
```
Python3 初心者　名前とエラー

# 名前の中の＿＿と＿
よく名前で\_\_name\_\_とかいう名前がある。これはpythonが使う変数として予約されている。例を示してみよう

```py
def amazing():
    '''This is  Function'''
    print('This name is', amazing.__name__)
    print('This comment is', amazing.__doc__)

amazing()
This name is amazing
This comment is This is Function
```


# エラー処理とtry,except
では例をみていこう。今回もオライリージャパンさんのPython3入門のコードをみてみます。

```py
short_list=[1, 2, 3]
position=5
short_list[position]
Traceback (most recent call last):
 File "<studin>", line 1, in <module>
IndexError: list index out of range

short_list=[1, 2, 3]
position=5
try:
    short_list[position]
except:
    print('Need a position between 0 and', len(short_list)-1, ' but got', position)

Need a position between 0 and 2 but got 5
```

これはtryの処理に対してexceptはエラーが出た時になぜその処理がエラーが出たかをわかりやすくするものです。もし複数の例外が起きる場合はそれぞれ別の処理をするために別々の例外ハンドルを作らなくてはいけない。それでは例を見ていこう

```py
short_list=[1, 2, 3]
while True:
    value=input('Position [q to quit]? ')
    if value=='q':
        break
    try:
        position=int(value)
        print(short_list[position])
    except IndexError as err:
        print('Bad index:', position)
    except Exception as other:
        print('Something else broke:', other)

Position [q to quit]? 1
2
Position [q to quit]? 0
1
Position [q to quit]? 3
Bad index: 3
Position [q to quit]? two
something else broke: invalid literal for int() with base 10: 'two'
```
まずIndexErrorはシーケンス今でいうshort_listの無効なものを指定した時に例外が起きる。それがIndexErrorというものでありそれはerrとして名前を出しています。次にExceptionです。これは他のエラーのことをさし、またそれのエラー文がotherに読み込まれ、otherが出てくるという仕組みになっています。
eegeo.jsで遊んでた。

#前振り(いらない子)
3Dとかに興味をもって、以前bingMapAPIを勉強したことをきっかけに、3Dマップで面白いのを探してた、、、、
すると、、eegeo.js!!!
前からゲーム作りたいと思っていたので、ドキュメントのデモがとてもおもしろそうだったので、ちょっと触ってみました。webGLは、ここ直近の自分の楽しみジャンルの上位に食い込みそうな予感！
Google先生、良き出会いを検索させていただきありがとうございましたw

#ポイント
APIを取得する。
ドキュメントを英語の練習とする。


##参考イメージ
![FireShot Capture 008 - eegeo.js：ゲームみたいな3Dマップが作れるAPIの使い方 - WPJ - www.webprofessional.jp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308667/bd38c9a1-6fff-1394-b689-1a8cf79f73e6.png)
SendGrid サポートから得た知見を可能な範囲で公開してみるよ

株式会社オズビジョンのユッコ (@terra_yucco) です。
今日も珍しく仕事の話を書こうと思います。

# SendGrid

ご存知だと思われる SendGrid を、オズビジョンのメインプロダクト「ハピタス」でもメール送信の一部に利用しています。運用を外出しできるメリットはありますが、自前のメールサーバと比べると基本的にブラックボックスなので、サポートを活用するシーンは多いです。
今回、サポートとのやりとりを (機密にあたりそうなところは伏せて) いくつか紹介してみたいと思います。

## サポート問い合わせの前に

オズビジョンは SendGrid を本家ではなく、日本のリセラーパートナーである構造計画研究所経由で利用しています。そのため、対象アカウントを契約しているメールアドレス以外からの問い合わせの場合には、本人確認情報を問い合わせ時に共有する必要があります。
これを忘れると「本人確認情報下さい」と言われて問い合わせ対応が 1 日くらい延びてしまうので、最初から提示するのがベターと思われます。

- [本人確認について](https://support.sendgrid.kke.co.jp/hc/ja/articles/115000021121)

上記には「登録情報や契約内容のご変更時」とありますが、別のメンバが個人アドレスで契約したアカウントについて問い合わせを出すときには、以下の 3 項目が必要となりました。(画像は上記記事よりお借りしています。)

- ユーザ名
- 登録メールアドレス
- 登録姓名

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95030/d0818885-1c28-eb32-a817-7ccf5ff16b92.png)


## Essential プランから Pro プランに上げるときに IP ウォームアップは必要なの？

元々 SendGrid の利用は Essential プランから始まりましたが、流量が増えてきたので Pro プランを検討したときに投げた質問。

### 必要

Essential プランは共有 IP を使っているが、Pro プランはそれとは違う専用 IP を払い出すので、別途 IP ウォームアップが必要とのこと。

- [IPウォームアップをどのように進めればよいですか？](https://support.sendgrid.kke.co.jp/hc/ja/articles/207602316)
- [SendGrid が推奨するウォームアップスケジュール](https://sendgrid.com/docs/assets/IPWarmupSchedule.pdf)

なお、送信予定通数が Daily 500 件とかであれば、上記の表の「IP Warmup Schedule」の中の Day 3 までを徐々に上げていけばよく、それ以上のウォームアップは不要です。

## Pro 100k から Pro 1.5M などへアップグレードする場合、別途ウォームアップは必要なの？

最終的にもっと多くのメールを移行する予定だったので、念のためにした質問。

### 別途は不要、ただし予定通数に応じた追加ウォームアップは必要

Pro プランの中でアップグレードする場合には、割り当ての IP アドレスの変更は発生しないので、最初から改めてウォームアップする必要はありません。しかし、ウォームアップ済みの範囲を超える場合には追加のウォームアップは必要になります。その場合も前述の推奨スケジュールが使えます。

また別の観点として、急激にメール通数が増えると宛先サーバで制限される可能性がある。また、一時的にアカウントが SendGrid によって凍結されることもあるそうです。

- [スロットリングへの対処方法](https://sendgrid.kke.co.jp/blog/?p=10380)
- [アカウント凍結のフローとその解除方法について教えてください。](https://support.sendgrid.kke.co.jp/hc/ja/articles/203392245)

## メールのダウンタイムを発生させず、Daily 500 件程度のメールを Essential から Pro に移行する方法はない？

既に Daily 500 件程度のメールを Essential プランから送っており、これを止めるわけにはいかなかったけど、将来を見据えて Pro に移行したくてした質問。

### 先に Pro にして流量制御して流すか、複数アカウントを並行契約

#### 重要事項

- Pro にした場合に払い出される IP を事前に知ることはできない (プラン変更時に割り当て)
- そのため Essential 状態でウォームアップは不可能

#### 方法 (1)

既存のプランを Pro にアップグレードし、少量ずつ送信する。
ただし、ダッシュボードでメトリクスを見て、ステータス変更に時間がかかっていたり、遅延が発生している場合は一度止めて様子を見る必要がある。

以下は具体的な見方なので、頂いた回答を引用します。

>ActivityにてProcessed発生からDelivered発生までに時間がかかったり、
Deferred(遅延)イベントが発生したりしている場合は、
SendGridによるアカウント凍結や宛先側でのスロットリングが発生していることが考えられますので、
少し時間を置いて、次の100件のメールを配信してください。

#### 方法 (2)

別のアカウントをもう一つ契約し、そちらでウォームアップを行ったあと、元の Daily 600 件を送信するのに使うアカウントを切り替える。

※以前、Essential を契約する際、テスト用にもう一つアカウントを作ろうとしたらダメだと言われたのですが。Pro (要するに有料) アカウントであれば、経緯を伝えれば同じ法人名義でも複数作成できるようです。

#### SendGrid 的選択基準

止められない Daily 600 件のメールの種別次第。

- マーケティング系メールで送信タイミングを制御できるなら (1)
- トランザクション系メールで送信タイミングを制御できないなら (2)

## これらを踏まえ

オズビジョンでは Pro アカウントをもう 1 つ契約し、そちらをウォームアップしてから使う方針を決めました。
ウォームアップをどのように行ったかなどはまた別の記事で共有できればと思います :smiley:
BigQueryで年度別に集計するときのスニペット

事業年度別にデータを集計する時に使ったスニペットを備忘録として
やっていることは単純で月ごとに所属年度を指定するようにかき分けています。例は年度を4月始まりで分けた時


## スニペット

```
CONCAT(
  CAST(
    if(EXTRACT(MONTH FROM date) >= 4
       , EXTRACT(YEAR FROM date)
       , EXTRACT(YEAR FROM date)-1
    ) as STRING)
  , '年度'
) as FY

-- 改行なし
-- CONCAT(CAST(if(EXTRACT(MONTH FROM date) >= 4, EXTRACT(YEAR FROM date), EXTRACT(YEAR FROM date)-1) as STRING), '年度') as FY
```

## 例（年度別ユーザー登録数

```
SELECT 
  CONCAT(CAST(if(EXTRACT(MONTH FROM date) >= 4, EXTRACT(YEAR FROM date), EXTRACT(YEAR FROM date)-1) as STRING), '年度') as FY,
  count(1) as cnt
FROM users
GROUP BY FY
ORDER BY FY
;
```
はじめてのコマンドラインまとめ

プログラミングでの、コマンドラインとは「コマンド」と呼ばれる命令文を入力して、コンピュータに命令を実行させる方法のことです。コマンドラインを扱うツールとして、Macを使っている方は、「ターミナル」を使います。



最初に知っておきたいコマンド。

フォルダ（ディレクトリ）を作成
・　$mkdir ファイル名

ファイルを作成
・　$touch ファイル名

ファイルの中を確認
・　$cat


コンピューターのディレクトリは枝分かれしていて、ツリーのような構成になっています。
最初にいる位置をホームディレクトリと呼び、そこから移動している場所をカレントディレクトリと呼ぶ。


ファイルを作りたい場合、作りたいディレクトリに移動しなければならない
移動の仕方
・　$cd
1個前に戻る
・　$cd ..
指定のディレクトリに移動する
・　$cd ディレクトリ名

今いる位置を確認する
・　$pwd

ディレクトリの中身を確認
・　$ls

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

ファイル、ディレクトリの操作
移動、名前の変更、コピー、削除。

ファイルの移動
ファイル
・　$mv 移動させたいファイル名　移動先のディレクトリ名
ディレクトリ
・　$mv　移動させたいディレクトリ名　移動先のディレクトリ名

ファイル名の変更
・　$mv 現在のファイル名（ディレクトリ名）　新しいファイル名（ディレクトリ名）

ファイルのコピー
・　$cp コピーするファイル名　新しいファイル名
ディレクトリのコピー
・　$cd -r コピーするディレクトリ名　新しいディレクトリ名

ファイルの削除
・　$rm 削除するファイル名
ディレクトリの削除
・　$rm -r 削除するディレクトリ名

-rを入れ忘れるとエラーが起こるので気をつけよう。
ステガノグラフィーについて簡単に調べてみた

##ステガノグラフィーとは？

データの隠蔽技術の一つ。

本来のデータ形式とは別の形式でデータを保存することをいう(ステガノグラフィーの語源であるギリシャ語の"steganos"は「隠された」という意味)。

暗号化のように完全に内容を読めなくするわけではなく、「それが読める人だけが読める」ようにデータを変更する。

裏を返せばそれがステガノグラフィーによって操作されたデータだということを知らなければ読むことができない(変換されたデータとしか認識できない)。

## 例えばどんなものがあるの？

代表的なものとしてはマルウェアがあり、画像にJSを埋め込んでユーザの意図しない動作をしたりする。

日本語での実例では折句がある(平成を生きたあなたであれば、「えるしつているかりんごしかたべないしにがみは」と言えば分かるだろうか)。
xUnitの[MemberData]での間違った型を、事前に防ぐ！

#0.はじめに
みんな、一度はxUnitの[MemberData]で変な型をつけちゃうことあるよね？
ない？僕はあるんだよ！！！（キレ気味）
![MissObj.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/250243/d3344d76-1607-7791-1a1c-bc96a6da843c.png)

でも、**ToObjectCaster**さえあれば、この通り！
自動で**型の不整合をチェック**してくれるんだ！
![Miss.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/250243/e5fc4df5-1808-d311-a253-68ca30033bd3.png)

ほかにも、たとえばこんなのや
![Miss2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/250243/04a38d1b-5ea7-46f2-4975-7e81fc1d9127.png)

こんなのだって！
![Miss3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/250243/3c0f45ac-34b4-f216-8666-dd1950731ad4.png)

**ToObjectCasterを使えば、テストケースの型の間違いを事前に防ぐことができるんだ！**

#1.xUnitについて
そもそも、xUnitについては知らないよって人は、↓の記事がとてもわかりやすいので読んでね！（けして説明がめんどうだからではない）
[xUnit.net でユニットテストを始める](https://qiita.com/takutoy/items/84fa6498f0726418825d#memberdata)
[.NET Coreで単体テストを行う](https://www.buildinsider.net/language/dotnetcore/07)

##テストケースの型を間違っちゃう問題
xUnitの[InlineData], [MemberData], [ClassData]を利用するとき、**IEnumerable\<object[]\>**を返すプロパティ・メソッド・クラスを作成します。しかし、値が全て**object[]**であるため、**間違った型の値を入力しても実行までエラーが出ません。**
なので、**コンパイル段階でエラーとするために、先に型のチェックをしてからobjectに変換する**ということを考えます。
ToObjectCasterクラスのMakeCastメソッドによって生成された**ToObjは、引数をobject[]に変換する関数です。**

#2.実装
バーン！！！！！！
![ToObjectCaster.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/250243/eec5a1ce-d3a4-a08e-de89-89660a46ee01.png)

（引数の数だけ型があるので当然っちゃ当然だけど......）
（xUnitがValueTupleに対応してさえいれば......（でも、0と1のタプルどうするの？））
（リポジトリは、ないです......）

#3.さいごに
実はこの記事には**元ネタがあります。**

[Creating strongly typed xUnit theory test data with TheoryData](https://andrewlock.net/creating-strongly-typed-xunit-theory-test-data-with-theorydata/)
(TheoryDataで強く型付けられたxUnitのTheoryテストデータを作る)

↑の記事の方法は、非ジェネリックなTheoryDataクラスでIEnumerable\<object[]\>を実装し、それを継承したジェネリックなTheoryDataクラスで型チェック用のAddメソッドを実装している、といった感じです。

本記事の方法は、筆者がEnumratorに慣れていなかったので、IEnumerable\<object[]\>の実装はList<object[]>を使い、それを初期化する際に型をチェックしてobject[]にキャストする関数を用意する、ということを考えてみました。

**元ネタの方がコレクション初期化子を使ってキレイに書けるので、そっちの方がいいかもしれない**

**最後まで読んでくれてありがとう！**
Flutter Webでマテリアルアイコンが表示されないとき

# やったこと
- `web/assets/FontManifest.json` を追加して、下記内容を記載する

```json:FontManifest.json
[
  {
    "family": "MaterialIcons",
    "fonts": [
      {
        "asset": "https://fonts.gstatic.com/s/materialicons/v42/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.woff2"
      }
    ]
  }
]

```

# はじめに
Flutter Webが発表されましたね! :rocket:
早速スマホ向けに作っていたアプリをWeb向けに対応させてみました。  

# こうなった
<img width="1458" alt="スクリーンショット 2019-05-11 14.07.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148385/0a1a2846-09ce-0bdd-e3a5-1409301423b6.png">
アイコンが`П`に... :sob: :sob: :sob: 
ちなみに元々スマホ向けで動かしていたときは、こんな感じでした。
<img width="507" alt="スクリーンショット 2019-05-13 21.09.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148385/13876d65-7450-ee02-76a6-60534cec1021.png">

# 理由
大体のことは、[Material icons not rendering #32245](https://github.com/flutter/flutter/issues/32245) に書いてあります。

# 対処方法

[やったこと](#やったこと) に記載したとおりです。 
Web向けの場合は、フォントの読み先を指定する必要があります。
フォントの読み先は、[flutter_web/examples/gallery/web/assets/FontManifest.json](https://github.com/flutter/flutter_web/blob/master/examples/gallery/web/assets/FontManifest.json) を参考にしました。

一応、フォルダ構成をスクリーンショットで載せておきます。
<img width="1440" alt="スクリーンショット 2019-05-13 21.19.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148385/b69ce0dd-f324-7a4f-0dcc-c2ea4adb0b96.png">  

# おわりに
Flutter Web広まるといいですね〜:blush:
また気づいたことがあれば随時書きます。

# 参考
Flutter Web導入にあたって参考にさせて頂きました :bow:
ありがとうございました!!    

- [Flutter Webを動かしたときにつまづいたこと](https://qiita.com/Nkzn/items/402a29fe9bb517ce78aa)
Terraformのuser_dataが動いていない時

`user_data`で書いたスクリプトはrootユーザーとして実行されます。

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/user-data.html

何かおかしいと思ったら実行ユーザーに注意してみましょう。また、ログファイルは `/var/log/cloud-init-output.log` にあるのでこちらも見てみましょう。
Splunk Free ライセンス

SplunkはFree版でも毎日500MBまで使える(データを取り込める)ので便利。
※取り込んだデータが合計500MBを超えても問題なし
https://www.splunk.com/ja_jp/download.html

だけど、500MBを超える日が30日以内に3回以上あると、データの取り込みはできるが検索ができなくなる。
こうなると、3回の制限が下がるのを待つ(30日に2回になるまで)か、再インストールするしかなさそう。
商用版であれば営業からリセットライセンスなるものを発行してもらえるらしいが、Free版やTrial版には効かないようなのでご注意。
https://docs.splunk.com/Documentation/Splunk/7.2.6/Admin/Aboutlicenseviolations
GitHub の特定のラベルが付いた issue の登録時に Slack に通知するツールを作ってみた

## 概要

Slack には GitHub 連携用のアプリケーションがあって、リポジトリについて通知する仕組みがありますが、 issue 作成だけではなく、編集・削除など余計な情報も流れてきます。

今回、情報が埋もれないように **バグレポート** など特定のラベルがついている issue の登録時に Slack に通知する仕組みを作りました。

## 使用技術

### [GitHub Webhooks](https://developer.github.com/webhooks/)

GitHub で issue を追加した時に通知が飛ぶように GitHub の Webhooks を利用しました。

### [Slack Incoming Webhooks](https://api.slack.com/incoming-webhooks)

最後に Slack に通知するために、Incoming Webhooks を利用しました。

### [Google Cloud Functions](https://cloud.google.com/functions/)

今回のメインの部分です。 GitHub の通知を受け取って、特定のラベルが付いた issue 登録のみフィルタして Slack に通知する部分に Google Cloud Functions を採用しました。実装には Node.js を利用しています。

## 実装

コードは GitHub にあげています。 index.js が実装部分です。 50 行ほどで実装できました。他の用途にも使えるような汎用的な作りにはしていないので、以下にカスタマイズ方法を案内しておきます。

```JavaScript
const request = require('request');
const secret = require('./config.json');

/**
 * HTTP Cloud Function.
 *
 * @param {Object} req Cloud Function request context.
 * @param {Object} res Cloud Function response context.
 */
exports.noticeGithubIssueToSlack = (req, res) => {

  const body = req.body;

  if (
    body.action !== secret.validation.action ||
    body.issue.labels[0].name !== secret.validation.labelName
  ) return res.send(200);

  const message = makeMessage(body);

  request.post({
    uri: secret.webhook_url,
    headers: {
      'Content-type': 'application/json',
    },
    json: {
      'text': message
    }
  }, function(err, res, body) {
    res.send(200);
    console.log(err, res, body);
  });
};

function makeMessage(body) {
  return [
    body.issue.user.login + ' さんから新しい調査依頼がありました。',
    '```',
    '# ' + body.issue.title,
    body.issue.body,
    '```',
    body.issue.html_url,
  ].join('\n');
}
```

## カスタマイズ方法

以下の部分をいじれば他の用途に使ったり、メッセージのカスタマイズをすることが可能です。

### フィルタ部分

14-17 行目の if 文で特定のラベルの issue 投稿しか受け付けないようにフィルタリングしています。ここをいじれば、複数のラベルに対応したり、編集・削除も通知するなどカスタマイズ可能です。そもそも issue ではなくて pullreq など、他の webhooks に対応するなども可能です。

```JavaScript
  if (
    body.action !== secret.validation.action ||
    body.issue.labels[0].name !== secret.validation.labelName
  ) return res.send(200);
```

### Slack 通知メッセージ

35-44 行目で Slack に送信するメッセージを作成している。

```JavaScript
function makeMessage(body) {
  return [
    body.issue.user.login + ' さんから新しい調査依頼がありました。',
    '```',
    '# ' + body.issue.title,
    body.issue.body,
    '```',
    body.issue.html_url,
  ].join('\n');
}
```


## 導入方法

導入方法は GitHub にまとめています。

https://github.com/tanabee/github-issue-slack-notification/blob/master/README.ja.md

## まとめ

Cloud Functions を使うと Webhoooks を少しカスタマイズして通知するなど、サクッと実装できて良いですね。他にも [PivotalTracker の更新情報を Slack に通知するツール](https://github.com/tanabee/pivotaltracker-diff-notification) などを以前実装しましたが、ツール間連携のかゆいところに手が届かない時に使うと便利です。

気になる方は触ってみてください！

## 関連記事

- [Slack の特定のチャネルのメッセージ一覧をスプレッドシートにエクスポートするツールを作ってみた](https://qiita.com/tanabee/items/0d17d58ac6008329fdaa)
- [社内メンバーの Qiita 新着投稿を Slack で共有するスクリプトを GAS で作った話](https://qiita.com/tanabee/items/665917d9ab976661115c)
- [Google Cloud Functions の HTTP トリガーで matplotlib を使って生成した画像を返す
](https://qiita.com/tanabee/items/2bfee85f9659be097750)
Google Colaboratory が デフォルトで PyTorch を import できるようになってる件

なんかよくわからない魔法のキーワードを書いて、`!pip install ~` で install して・・・、長いインストール時間が終わってようやく使える・・・
![pytorch.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392934/e293bd5b-331f-4b60-0102-1dae553430ba.png)
から
![new_pytorch.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392934/8e882c84-337b-b57b-4f50-54918dca7907.png)

で、使えるようになってるやん。

まじかよ・・・神対応かよ・・・

か、どうかはよく使ってる人が感じることかもしれないが、 Google だから TensorFlow 以外使っちゃダメ的な（勝手な妄想）からの脱却はすごく良いと思います。どんどんメジャーなモジュールはデフォルトで import できるようになって欲しいっす。

※ダウングレードの方法はわかりません。たぶん `!pip install` になるのかな？
Chromeで動画停止時にAirPodsなどBluetoothイヤホンが誤作動する場合の対処法

AirPods にはイヤホンを耳から外すと自動的に音楽/動画の再生が停止するという機能があります。
iPhone や iTunes で使う場合は問題なかったのですが YouTube で使うと、動画を手動で一時停止した後 AirPods を片耳だけ外すと再生が再開されてしまうなどの問題が発生したので、この機能を無効にする方法を紹介します。
[Brave](https://brave.com/) など他の Chrome 系ブラウザも同様です。

# 原因

Chrome 74 から Media Key という機能がサポートされ、MacBook 上部にあるファンクションバーの再生/一時停止ボタンや、AirPods のダブルタップなどで動画/音楽の再生/一時停止ができるようになりました。これと YouTube の相性が良くなく、上記のようなトラブルが発生する状況になってしまいました。また iTunes や Spotify を同時使用していても問題が発生するようです。

# 対処法

1. **`chrome://flags/#hardware-media-key-handling`** をアドレスバーにコピーして開く
2. **Hardware Media Key Handling** を **Disabled** にする
3. Chrome を再起動する
<img width="1328" alt="SS 2019-05-13 at 20.47.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155587/2de3acf5-0673-e1d9-6235-14d45efd2ea9.png">

# 参考
- 
https://www.reddit.com/r/apple/comments/bne5wq/airpods_on_macos_and_chrome_producing_a_terrible/
- https://www.ghacks.net/2019/04/17/fix-chrome-blocking-keyboard-multimedia-keys-from-working/
- https://www.ghacks.net/2019/02/08/google-chrome-73-to-support-multimedia-keys-on-the-keyboard/
clocで *.spec.ts と */node_modules/* を除いたプログラム規模算出

# 動機

Angular CLIで作成したプロジェクトの開発規模・ステップ数を計測したくて、やってみました。

# 前提

以下の環境を前提とします。
LinuxやMacでも大丈夫だと思います。

* Windows 10 Pro 64bit
* [@angular/cli](https://cli.angular.io/)で作成したプロジェクト
* [cloc](http://cloc.sourceforge.net/)

# 除外対象

以下フォルダ・ファイルを除外します。

* */node_modules
* * /**/ *.spec.ts

# 例

以下でとりあえずは絞り込めました。
もう少しアレンジしてもいいかもしれませんね。

```
cloc angular-project --exclude-dir=node_modules --not-match-f=^.+\.spec\.ts$ --by-file
```
CircleCIでChromeDriverを立ち上げる

# なにこれ
CircleCIでGoogoleChromeをheadlessモードで動かす際に、エラーが出たので対応方法を残す。


# どんなエラー？
LaravelをPHPUnitでテストしたときにテストコードで以下エラー発生

```
There was 1 error:

1) Tests\Unit\HogeTest::testGetUrl
Facebook\WebDriver\Exception\WebDriverCurlException: Curl error thrown for http POST to /session with params: {"desiredCapabilities":{"browserName":"chrome","platform":"ANY","chromeOptions":{"binary":"","args":["--headless","--no-sandbox","--disable-gpu","--window-size=1280,960","--user-agent=\"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/27.0.1453.116 Safari\/537.36\""]}}}

Failed to connect to 127.0.0.1 port 9515: Connection refused
```

WebDriverでChromeDriverにアクセスするときに、ChromeDriverが立ち上がっていなくて9515ポートにアクセスできていないようだった。

# 対応方法
1. CircleCIのconfig.ymlを編集してGoogleChromeとChromeDriverをインストールする
2. ChromeDriverをバックグラウンド起動する


# GoogleChromeとChromeDriverのインストール
`apt install`を使っても良かったのですが、CircleCIのイメージで最初からGoogleChromeとChromeDriver（とFirefoxとGeckodriver）をインストールするイメージが提供されているので、そちらを利用する。イメージ名のあとに`-browsers`と追記するだけ。

```config.yml
# 一部抜粋しています
version: 2
jobs:
  build:
    docker:
      # イメージ名の後に-browsersを追記するだけ
      - image: circleci/php:5.6-node-browsers
      - image: circleci/mysql:5.7
```

詳しい方法はこちらから
https://circleci.com/docs/2.0/browser-testing/

これだけでGoogleChromeとChromeDriverをインストールした状態を作れるのでありがたいですね。

# ChromeDriverをバックグラウンド起動する
ちょいハマりした箇所。
普通に`- run: chromedriver &`とか記述してもバックグラウンド起動ができませんでした。
[CircleCIのドキュメント](https://circleci.com/docs/2.0/configuration-reference/)を確認すると`run`のオプションには`background`というオプションが存在していて、これを使う必要があるらしい。
`background` オプションを指定したら、正しくバックグラウンドでChromeDriverが起動するようになった。

```config.yml
version: 2
  jobs:
    build:
      docker:
        # specify the version you desire here
        - image: circleci/php:5.6-node-browsers
        - image: circleci/mysql:5.7

      working_directory: ~/repo

      steps:
        # chromedriverをバックグラウンドで起動する
        - run:
            command: chromedriver
            background: true

        - checkout
        - run: sudo apt update
        - run: sudo apt upgrade

        # 以下略
```

これでOK。

# おわりに
seleniumでの記事だったらたくさん見つかったけど、ChromeDriver単体での記事が少なかったので書きました。
GitHub【超入門】


この記事を参考にしました
https://guides.github.com/activities/hello-world/

## GitHubって何

こんな風に書かれています。
`GitHub is a code hosting platform for version control and collaboration.`
コードを改良させたり組み合わせたりするためにみんながコードを貼るプラットフォーム（？）って感じの理解です。

`WebベースのGitリポジトリを提供しているサービスです。インターネット上でコードのバージョン管理や開発者同士でコラボレーションできるコード管理プラットフォームを提供しています。`(http://tmnj.hatenablog.com/entry/2016/12/01/144122)


### Repositoryを作る
1つのプロジェクトを組織するものがRepositoryです。
ファイルや写真、ビデオ、データセット、スプレッドシートなど何でもプロジェクトに必要なものを入れることができます。

アカウント作りました！ヒヒ！
https://github.com/kwnbmk

1. 自分のアバターのとなりのプラスをクリック！そしてNew repositoryを選択！
2. repositoryの名前をhello-worldにする。
3. short discriptionを書く。
4. Initalize this repository with a READMEにチェックを付ける(READMEはプロジェクトの説明）
5. Create repositoryをクリック！


作れました！

### ブランチを作る

ブランチとは同じレポジトリ上で、同時に複数の異なるバージョンを管理するための仕組みです。デフォルトではmasterという名前のブランチが一つあり、最後にはこのmasterブランチにすべての変更がマージされます。
masterからブランチを作成するとその時点でのmasterのスナップショットが作成されます。ブランチで作業中に他の誰かがmasterに変更をマージした場合は、その変更を自分が作業中のブランチに取り込む(pull)こともできます。
開発者は、バグフィックスをしたり新機能を追加する際にmasterからブランチを作成します。開発が完了したら、そのブランチの変更をmasterブランチににマージします。

作成します！

1. 先ほど作成したhello-worldリポジトリに移動します！
2. 真ん中左端の"Branch:master"ドロップダウンをクリックして、"readme-edits"と入力して、Create branchをクリックします。

完成です。

### 変更してコミットしてみる
READ-ME.mdファイルをクリックして編集モードにします。
内容を書いたらCommit Changeボタンを押します。
（これは、masterブランチにはマージされていないので二つのレポジトリは違う内容）

### PullリクエストをOpenにする
readme-editsブランチは、masterブランチと異なる内容なりましたので、Pullリクエストをオープンすることができます。Pullリクエストは、Githubでのチーム開発を行う際の重要な機能になります。
Pullリクエストをオープンすると、変更内容が他のメンバーに提示され、その内容を他のメンバーが作業中のブランチにマージするようリクエストします。Pullリクエストは両方のブランチからの内容の差異を示し、変更した内容、追加した内容、削除した内容が緑と赤で表示され差分を確認することができます。リクエストを受けたメンバーは、その内容を吟味し必要に応じてリクエスト送信者とコミュニケーションし、最終的にブランチにマージするか判断します。
今回は自分専用のリポジトリでPullリクエストをオープンしてmasterブランチにマージしてみることで、GitHubの重要なフローを理解しましょう。

この後PullをしてMargeしました……!
おしまい！
Nuxt-i18nで簡単に多言語対応！


## 自己紹介

tanshio(@_tanshio)


フロントエンドエンジニア、ウェブデザイナー
好きなものはVue・Nuxt、TypeScript、WebGLです
いま挑戦中のものはGatsbyとGoです

---

## 多言語対応

つらい

---

- どこで何が呼ばれているかわからない
- いろいろとつらい

---
 
## Nuxtだと簡単だった

---


## Nuxti-18nで簡単に多言語対応


https://github.com/nuxt-community/nuxt-i18n


---

## 基本的に使うもの

- `{{ $t('文字列') }}`
    - 文字列部分は変数が使える
- `<n-link :to="localePath('リンク先')">index</n-link>`
    - localpathで現在の言語でのリンク
- `<nuxt-link :to="switchLocalePath('en')">en</nuxt-link>`
    - switchLocalePath('言語')で言語切替

---

## デモ

---

## Nuxtで世界に発信しよう！

---

デモのURLです
https://github.com/tanshio/nuxt-ts-starter
RubyでSuumoの情報をスクレイプしてみました。



##はじめに
Suumo情報をRubyでスクレイプしたので書いた内容をメモしておきます。
まだまだ修行中のため、もっとこうしたらいいなど、コメントありましたらぜひ、アドバイスいただけると嬉しいです！


## 内容
* 特定のSuumoのサイトを指定して、物件名と価格取得する
* 取得した内容をCSVデータとして出力する


## それでは下記にコード

今回は`Mechanize`を利用しました。


```ruby

require 'mechanize'
require 'CSV'

def get_stock_data(url)
  agent = Mechanize.new
  page = agent.get("#{url}")

  names = get_name(page)
  prices = get_price(page)
  create_data(names, prices)
end


def get_name(page)　## 物件名を取得する
  names = []
  stock_names = page.search('#js-bukkenList').search('.cassette_header').search('h2 a').children
  stock_names.each do |name|
    names << name.inner_text
  end
  return names
end


def get_price(page)　## 物件価格を取得する
  stock_prices = []
  prices = page.search('#js-bukkenList').search('.cassette_price').search('div').search('.cassette_price-accent').children
  prices.each do |price|
    stock_prices << price.inner_text.strip ## 改行コードなどが入るのでstripしました
  end
  return stock_prices
end


## 物件名と価格の配列を加工する
## 一番理解が薄いまま書いたので後で見直ししようと思っているところです
def create_data(names, prices)
 arr = names.zip(prices)
end



## CSVを作成する
## 引数の”w”が何かしっくりきていないです、というか意味はわかっていません。

def create_csv(stock_data)
  headers = ["物件名","販売価格"]
  rows = stock_data
  csv_data = CSV.open('stock_data.csv', 'w') do |csv|
    csv << headers
    rows.each do |row|
    csv << row
   end
  end
end


## 取得したいSuumoページのURLを入力する
url = "https://suumo.jp/jj/bukken/ichiran/JJ010FJ001/?ar=030&bs=010&ta=12&firstFlg=0&urlFlg=0&jspIdFlg=1&sc=12203&kb=1&kt=9999999&km=1&mb=0&mt=9999999&ekTjCd=&ekTjNm=&tj=0&srch_navi=1"

stock_data = get_stock_data(url)
create_csv(stock_data)

```
【Unity】スワイプ時のベクトルの取得方法

# 概要
スワイプ時に指が画面上を移動した距離と方向(スワイプベクトルとここで呼ぶことにする)を取得する方法を書きました。

# 環境
Unity 2019 1.1f1
UniRx 6.2.2

# コード

```C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UniRx;
using UniRx.Triggers;

namespace Test
{
    public class MeasureSwipeVector : MonoBehaviour
    {
        //指が画面に触れた位置
        private Vector2 fingerDownPos;
        //指が画面から離れた位置
        private Vector2 fingerUpPos;
        //スワイプベクトル
        private Vector2 swipeVector;

        private void Start() {
            //マルチタッチを無効化
            Input.multiTouchEnabled = false;

            //指と画面が触れた位置を記録
            this.UpdateAsObservable()
                .Where(_ => Input.GetMouseButtonDown(0))
                .Subscribe(_ => fingerDownPos = Input.mousePosition);

            //指を離した位置を記録し、AmountOfMovementを計算
            this.UpdateAsObservable()
                .Where(_ => Input.GetMouseButtonUp(0))
                .Subscribe(_ => {
                    fingerUpPos = Input.mousePosition;
                    swipeVector = (fingerUpPos - fingerDownPos) / Screen.dpi;
                });
        }
    }
}
```

### 説明
`Screen.dpi`は1 PPI(1インチに含まれるピクセル数)を表します。
単位が`pixel`である`fingerUpPos - fingerDownPos`を`Screen.dpi`で割ることによって、単位が`inch`のスワイプベクトル`swipeVector`を取得しています。


# 参考
- [Unity : モバイルでのスワイプ、ドラッグ入力量を補正する](https://indie-du.com/entry/2016/08/15/142051)
- [UniRxを使ったフリック検出](http://unity-study.hatenablog.com/entry/2016/08/18/155431)
Ruby on Rails Tutorial 5章

演習
リスト 5.10を参考にして、5.1.1.1で使ったネコ画像をコメントアウトしてみてください。また、ブラウザのHTMLインスペクタ機能を使って、コメントアウトするとHTMLのソースからも消えていることを確認してみてください。

リスト 5.11のコードをcustom.scssに追加し、すべての画像を非表示にしてみてください。うまくいけば、Railsのロゴ画像がHomeページから消えるはずです。先ほどと同様にインスペクタ機能を使って、今度はHTMLのソースコードは残ったままで、画像だけが表示されなくなっていることを確認してみてください。

１
確認

２
確認


演習

1.Railsがデフォルトで生成するheadタグの部分を、リスト 5.18のようにrenderに置き換えてみてください。ヒント: 単純に削除してしまうと後でパーシャルを１から書き直す必要が出てくるので、削除する前にどこかに退避しておきましょう。

2.リスト 5.18のようなパーシャルはまだ作っていないので、現時点ではテストは redになっているはずです。実際にテストを実行して確認してみましょう。

3.layoutsディレクトリにheadタグ用のパーシャルを作成し、先ほど退避しておいたコードを書き込み、最後にテストが green に戻ることを確認しましょう。

```_rails_default.html.erb
<%= csrf_meta_tags %>
<%= stylesheet_link_tag 'application', media: 'all',
'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>

```

2.3
確認


演習
5.2.2で提案したように、footerのCSSを手作業で変換してみましょう。具体的には、リスト 5.17の内容を１つずつ変換していき、リスト 5.20のようにしてみてください。

省略

演習

リスト 5.29のようにhelfルーティングを作成し、レイアウトのリンクを更新してみてください。
前回の演習と同様に、エディタのUndo機能を使ってこの演習で行った変更を元に戻してみてください。

動作確認省略

5.3.4
演習
1. footerパーシャルのabout_pathをcontact_pathに変更してみて、テストが正しくエラーを捕まえてくれるかどうか確認してみてください。
2. リスト 5.35で示すように、Applicationヘルパーで使っているfull_titleヘルパーを、test環境でも使えるようにすると便利です。こうしておくと、リスト 5.36のようなコードを使って、正しいタイトルをテストすることができます。ただし、これは完璧なテストではありません。例えばベースタイトルに「Ruby on Rails Tutoial」といった誤字があったとしても、このテストでは発見することができないでしょう。この問題を解決するためには、full_titleヘルパーに対するテストを書く必要があります。そこで、Applicationヘルパーをテストするファイルを作成し、リスト 5.37のFILL_INの部分を適切なコードに置き換えてみてください。ヒント: リスト 5.37ではassert_equal <期待される値>, <実際の値>といった形で使っていましたが、内部では==演算子で期待される値と実際の値を比較し、正しいかどうかのテストをしています。


```
require 'test_helper'

class ApplicationHelperTest < ActionView::TestCase
  test "full title helper" do
    assert_equal full_title,        "Ruby on Rails Tutorial Sample App"
    assert_equal full_title("Help"),"Help | Ruby on Rails Tutorial Sample App"
  end
end
```


5.4.1
演習
表 5.1を参考にしながらリスト 5.41を変更し、users_new_urlではなくsignup_pathを使えるようにしてみてください。
先ほどの変更を加えたことにより、テストが redになったことを確認してください。なお、この演習はテスト駆動開発 (コラム 3.3) で説明した red/green のリズムを作ることを目的としています。このテストは次の5.4.2で greenになるよう修正します。

get users_new_url
を
get signup_path
に変える
２確認


5.4.2

演習
もしまだ5.4.1.1の演習に取り掛かっていなければ、まずはリスト 5.41のように変更し、名前付きルートsignup_pathを使えるようにしてください。また、リスト 5.43で名前付きルートが使えるようになったので、現時点でテストが greenになっていることを確認してください。
先ほどのテストが正しく動いていることを確認するため、signupルートの部分をコメントアウトし、テスト redになることを確認してください。確認できたら、コメントアウトを解除して greenの状態に戻してください。
リスト 5.32の統合テストにsignupページにアクセスするコードを追加してください (getメソッドを使います)。コードを追加したら実際にテストを実行し、結果が正しいことを確認してください。ヒント: リスト 5.36で紹介したfull_titleヘルパーを使ってみてください。
1
確認
2
確認
３

```site_layout_test.rb
get signup_path
assert_select "title", full_title("Sign up")
```
コールバックの種類


## コールバックの種類


```ruby


before_validation ##検証前の正規化
after_validation  ##検証結果(エラーメッセージ)の加工


 # ひとまとまり⬇︎
before_save
before_create    ## saveのために裏側で行いたいデータ準備を行う(ある属性の値に従ってある関連(後述を作成するなど) 検証エラーを出してもユーザーにはどうすることもできない状態異常を防ぐために例外を出す
before_update 


# ひとまとまり　⬇︎

after_save
after_create      ## そのモデルの状態に応じて他のモデルの状態を変えるなど、連動した挙動を実現する。 検証エラーを出してもユーザーにはどうすることもできない状態以上を防ぐために例外を出す
after_update


before_destroy  ## 削除してOKかをチェックし、ダメなら例外を出すなどして防ぐ

after_destroy  ## そのモデルの削除に応じて他のモデルの状態を変えるといった連動した挙動を実現する







```
覚えておくと便利なGitコマンド



#概要
覚えておくと超便利～のGitコマンドをメモしておきます！
φ(..)メモメモ

#一旦他のブランチに切り替えたい
作業中に他の人のプルリクをレビューするなど、ブランチ切替が必要な際に使っています。

###現在の作業を一旦退避
``` git
git stash
```
現在の作業を一端addしてから、上記のコマンドを打つようにしてください。
addしないと、作業した内容が消えてしまったはず。コワイなーコワイなー。

###ブランチ名を変更したい
ブランチ名スペルミスしてる！ダサ！push前に何とかバレずに修正したい

``` git
git branch -m [新しいブランチ名]
```
現在作業しているブランチ名を修正したい場合です。

``` git
git branch -m [古いブランチ名] [新しいブランチ名]
```
ローカルにあるブランチ名を修正できます。

###退避した作業の復元
``` git
git stash pop
```
作業していたブランチに戻ってから、上記のコマンドを打つとstashした際の変更内容が蘇ります。ホッと一安心する瞬間です。

#空コミットしたい
``` git
git commit --allow-empty -m "empty commit"
```
`"empty commit"`はコミットメッセージなので、なんでもOKです。
空コミットは、複数の人数で開発を進める際に使っています。

空コミット → push → プルリク

作業前にプルリクを出すことで、『自分がこれからこの作業をするよ！』とメンバーにアナウンスします。作業のバッティングを防ぐこと、自分の作業報告を目的としています。
ちなみに、作業中のプルリクにはタイトルで [WIP] を頭につけるのが、私達チームのルールです。「Work In Progress」の略で、『まだレビューしないでね！！』というメッセージが含まれています。

#コミット履歴の確認
``` git
git log --oneline
```
リポジトリのコミット履歴を簡易確認できます。Enterを押し続けると、より古いコミット履歴が出力し続けます。「q」を入力すると、一覧から抜け出すことができます。

#昔のコミットに戻るとき
``` git
git checkout [ログID]
```
ログIDを指定（上記のコミット履歴の確認 参照）することで、指定したコミット状態に蘇ることができます。

#直前のコミットに戻るとき
``` git
git reset --soft HEAD^ 
git reset --hard HEAD^
```
--soft：内容はそのままでコミットだけを取り消す
--hard：内容とコミット両方を取り消す

#Gitの管理ファイルリスト生成
``` git
git ls-files > list.txt
```
ルート直下に、list.txt のテキストファイルが作成されます。
納品ファイルをリスト化して報告する際に、役立ちます。

#すでにコミット＆pushしてしまったファイルを削除したいとき
普通にGUIで削除しても、復活してしまいます。（多分他の人のリポジトリに残ってるから？）git rm を使います。

``` git
git rm [削除したいファイル]
```
ファイルをgitの管理対象から削除

``` git
git rm -r [削除したいディレクトリ]
```
ディレクトリをgitの管理対象から削除

``` git
git mv [移動したいファイルやディレクトリ] [移動先のパス] 
```
ディレクトリやファイルの移動・リネーム

``` git
git rm --cached [ファイル名]
```
Gitの管理対象からは外すけれど、手元には残しておきたい場合

#おわりに
GitHub導入当時、真っ黒な画面が怖くて怖くて仕方なかった私をそっと抱きしめて「大丈夫だよ。そう簡単にはデータ壊れないよ。ちょっとしたら慣れてお茶の子さいさいだよ。」って伝えてあげたい。

もうGit管理ができない世界なんて考えられない！くらいに、寝返っているのだから。

「SourceTree使うとコンフリクトエラーのときに対処しきれなくなるから、黒い画面使って、ちゃんとコマンド書いてほしいな～」と圧かけてくれた上司に今は心より感謝なのです！
VSCodeを利用してGit管理することでも、かなりとっつきやすくなりました。
DNS書き換え時のnslookup利用シーン

# はじめに
DNSを書き換えた場合に、正しく設定できたか確認する方法として、ブラウザでアクセスして確認されている方もいるかと思います。

ただブラウザだと一生懸命リロードしても実はキャッシュだったり、ブラウザ変えたりシークレットモードで閲覧すると挙動が異なったりし、混乱してしまい、設定を変更し続けること状況に陥ることがあります。


**※ブラウザで確認した際に疑われる点**

1. ブラウザのキャッシュ
1. PCのキャッシュ
1. セキュリティソフト
1. プロキシサーバー
1. ルーター
1. プロバイダ、その他DNSサービス
1. NSレコードに記載されているネームサーバー  

→ 経由地が多く、キャッシュかもと疑う点が多い


# 解決方法
上記の問題を解決する手堅く＆手っ取り早い確認方法として、ブラウザではなくnslookupを利用し、ネームサーバーに直接問い合わせする方法があります。

**※nslookupで確認した際に疑われる点**

1. NSレコードに記載されているネームサーバー

→ 疑う点が少ない！
→ ネームサーバーに直接問い合わせしているので信頼できる（nslookupがどうなのかは別で）



# 利用シーンごとの使い方
## 利用シーン1：DNSが正しく設定されたか調べるとき
#### 実行
```shell:shell
// ターミナルでnslookupを起動
$ nslookup

// 問い合わせするネームサーバーを切り替える（例：さくらのNS）
> server ns1.dns.ne.jp

// 問い合わせ（例：example.com）
> example.com
```

#### 結果
```shell:shell
Server:		ns1.dns.ne.jp
Address:	61.211.236.1#53

Name:	example.com
Address: xxx.xxx.xxx.xxx
```

※結果の読み方
`ネームサーバー（ns1.dns.ne.jp）に、「example.com」はどこですか？と問い合わせたらIPアドレス「xxx.xxx.xxx.xxx」のサーバーに設定されています。と返ってきた`


※`「server ns1.dns.ne.jp」`を設定していない場合は、デフォルトのネームサーバーに問い合わせになります。

```
Server:		192.168.11.1
Address:	192.168.11.1#53
// ルーターのIPが返ってきます。
```



## 利用シーン2： NS（ネームサーバー）はどこか調べる
#### 実行
```shell:shell
// ターミナルでnslookupを起動
$ nslookup

// クエリータイプをNSレコードに変更
> set q=ns

// 問い合わせ（例：example.com）
> example.com
```
#### 結果
```shell:shell
Server:		192.168.11.1
Address:	192.168.11.1#53

Non-authoritative answer:
masking-tape.jp	nameserver = ns-999.awsdns-99.com.
masking-tape.jp	nameserver = ns-999.awsdns-99.co.uk.
masking-tape.jp	nameserver = ns-999.awsdns-99.org.
masking-tape.jp	nameserver = ns-999.awsdns-99.net.

Authoritative answers can be found from:
ns-999.awsdns-99.com	internet address = xxx.xxx.xxx.xxx
ns-999.awsdns-99.net	internet address = xxx.xxx.xxx.xxx
ns-999.awsdns-99.org	internet address = xxx.xxx.xxx.xxx
```
上記のような結果が帰ってくるので、その中から`Authoritative answers can be found from:`に記載されている内容を確認する。

#### 例
バリュードメインの場合

```
example.com	nameserver = ns2.value-domain.com.
example.com	nameserver = ns1.value-domain.com.
```

さくらの場合

```
example.com	nameserver = ns2.dns.ne.jp.
example.com	nameserver = ns1.dns.ne.jp.
```

ムームーの場合

```
example.com	nameserver = dns02.muumuu-domain.com.
example.com	nameserver = dns01.muumuu-domain.com.
```

AWS Route53の場合

```
example.com	nameserver = ns-135.awsdns-16.com.
example.com	nameserver = ns-1655.awsdns-14.co.uk.
```



## 利用シーン3： TXTレコードにSPFが設定されているか
#### 実行
```shell:shell
// ターミナルでnslookupを起動
$ nslookup

// クエリータイプをTXTレコードに変更
> set q=txt

// 問い合わせ（例：example.com）
> example.com
```

#### 結果
```shell:shell
Server:		192.168.11.1
Address:	192.168.11.1#53

Non-authoritative answer:
example.com	text = "v=spf1 +a:example.com +ip4:xxx.xxx.xxx.xxx ~all"

Authoritative answers can be found from:
・・・
```
上記のような結果が帰ってくるので、その中より`example.com	text = "v=spf1・・・・`のような記載を確認する
    

## 参考サイト
- [Windowsコマンド - nslookup](https://docs.microsoft.com/ja-jp/windows-server/administration/windows-commands/nslookup)  
    - [Queryタイプの一覧](https://docs.microsoft.com/ja-jp/windows-server/administration/windows-commands/nslookup-set-querytype)
プログラミング学習記録86〜Progateからメッセージ〜

##今日やったこと
- Progate JavaScript2そのまま復習

今日もイマイチやる気になれなかったので、Progateをやりました。

やる気がなくても進めていけるのがいいですね。

個人的にはドットインストールよりもやる気がなくてもできる教材かなと思います。

JavaScriptの繰り返し処理を復習しました。
ドットインストールで実際にミニアプリ、ゲームを作ってみる限り、while文による繰り返しはほとんど使われていません。

なので、繰り返しに関してはfor文を覚えておけばよさそうですね。

久しぶりにProgateを開いたらメッセージが届いていました。
https://prog-8.com/message

初心者向けの教材とはいえ、やはり挫折者が多いのでしょうか。

プログラミング学習で心が折れそうな人、折れてしまった人に向けて書かれたような文章です。
折れる気持ちはめちゃくちゃわかります。

僕も正直何度も心は折れています笑

ですが、ちょっとずつ理解できるようになってきています。

プログラミングにもセンスはあるのかもしれないですが、やはりある程度のところまでは努力でいけるのは間違いなさそうです。

折れながらもちょっとずつ学習を進めていこうと思いました。

おわり
Azure DNS障害を耐えられたであろう環境を作ってみた

## 作ってみたきっかけ
2019年5月3日 AM5:00ごろから、Azureの各種サービスのホスト名を解決するDNSサーバーで設定ミスがあって、BLOBストレージや、SQLなど各種サービスのエンドポイントが名前解決できないという問題が発生した。

発生したことは公式のサービスステータス履歴にも上がっているし、いくつかのメディアでも取り上げられている。
https://www.publickey1.jp/blog/19/microsoft_azuredns.html
https://www.itmedia.co.jp/news/articles/1905/09/news084.html

幸いにして日本は10連休の真っ只中かつ、早朝に発生したことから、起きたことのわりにビジネス的なインパクトは小さかったようで、そこまでの大問題として扱われていないようだ。

## DNSをサービスディスカバリとして使うことの問題点
分散DBとしてのDNSは、メールやWebなどIPアドレスの変更が極めて稀な安定したユースケースにおいて、長めのTTLを前提として運用されてきた。
このためDNSサーバーの設定変更、ゾーンファイルの編集によって誤ったIPアドレスをAレコードに登録してしまったようなミスがあると、どこかでキャッシュされてしまい丸一日は反映されないようなことも（たまに）発生してしまっていた。

このDNSによるホスト名解決の仕組みが、インターネットで提供されるAPIエンドポイントのホスト名としての利用されるようになると、DNSの仕組みが持つ鷹揚さが逆にシステム全体の安定稼働にとって問題となる。

最近では、解決するIPアドレスを変えることによってHAが実現されているためDNSのTTLには短い時間が設定されるケースが多いが、ネガティブキャッシュの設定はまた別だったりするので、今回のようにクラウドプロバイダや、アプリをホストしている環境の上位DNSがやらかすと、自分のサービス全体が機能停止に至るようなこともあり得るのである。

SREの観点では、こういう事態においてもシステムが稼働し続けなければならず、システムの内部にDNSの名前解決が必要となるアプリケーションでは、名前解決の仕組み自体に何らかの対策が求められる。

## 方式1: dnsmasqでローカルキャッシュを構築する
ローカルで動かすことができるDNSのキャッシュサーバーとして、[dnsmasq](http://www.thekelleys.org.uk/dnsmasq/doc.html)というものがある。一度解決したホスト名をローカルにキャッシュしておくことで、今回のようなトラブル時にもローカルで動くアプリケーションは稼働しつづけるシステムを構築することができる。

この方式には問題があり、dnsmasqでTTLを無視した独自のキャッシュを導入すると、HAの切り替わりのようなIPアドレスが変更になるDNSの変更がいつまでたっても反映されなくなってしまう。

我々が使っているような Azure MySQL for Database を運用していると、わりと頻繁に（数ヶ月に一度程度）IPアドレスの変更が起きるのでこれでは解決にならない。

また、なるべくメンテナンスする対象を少なくしたい観点からもこの方式は避けたい。

## 方式2: getaddrinfo(3)にキャッシュの仕組みを導入する
サーバープロセスのように長時間稼働しつづけるサービスの場合、DNS名の解決に失敗したとき、前回に成功したIPアドレスを使ってそのまま接続してみるという挙動をしてほしい。

そして、glibc/Linuxの環境では、動作時にglibcで提供されるgetaddrinfo(3)を、自分の実装で横取りする仕掛けを作ることができる。

これをつかってDNS解決に失敗しても前回の結果を返すように実装した getaddrinfo(3) が、[libsaferesolv.so](https://github.com/nebosuke/libsaferesolv) (https://git.io/fjWaX) である。

Dockerのようなコンテナの中で動かすことを想定しており、どのようなインフラの構成であってもコンテナ内で動くアプリをDNS障害からガードすることができる。

getaddrinfo(3)を置き換えることで対応しているため、あらゆる言語・ライブラリに対応しているのが肝である。

## 例: libsaferesolv.so を用いたJavaアプリをガードしてみる
glibc/Linux環境において、libsaferesolv.so をビルドしてそのバイナリが、lib/libsaferesolv.so として存在するとき、以下のようにコンテナをビルドするとコンテナ内で起動するJVM環境のホスト名解決はすべてガードされた状態となる。

```Dockerfile
FROM openjdk:8-jre-slim
EXPOSE 8080

# 省略

ADD lib/libsaferesolv.so /usr/local/lib/libsaferesolv.so
ENV LD_PRELOAD /usr/local/lib/libsaferesolv.so

# 省略

ADD target/app.jar /app.jar

ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-Dnetworkaddress.cache.ttl=0", "-Dnetworkaddress.cache.negative.ttl=0", "-jar", "/app.jar"]
```

LD_PRELOADは、glibcの仕組みなので、Alpine Linuxのような軽量なイメージで使うことができないのが残念なところ。

## 今後について
この仕組み。glibcを弄るというアプリ屋からするとかなり心理的障壁が高い方式のため、実は我々の本番環境にはまだ投入できていない。検証してうまくいきそうだという雰囲気を得ただけである。

真のSRE(Site Reliability Engineer)によるクリティカルな批評がもらえて自信が持てれば投入したい。