OmniAICreator/Qiita-1.07M huggingface dataset:
gpsの研究　その56

#概要

gpsを理解したかった。
nmeaから、緯度経度と時間と衛星の仰角、方位角を求めて、
2行軌道要素から、緯度経度、高さ、時間の時の衛星の仰角、方位角を求めてみた。

#成果物

nmeaから、緯度経度と時間と衛星の仰角、方位角

https://embed.plnkr.co/x4gFDqBRmlriP1GAC0pa/

```
緯度経度: 34.33, 132.24
高さ: 92.3
日本時間: 2018/12/29 05:26:45
仰角、方位角: 76, 164
```

#成果物

2行軌道要素から、緯度経度、高さ、時間の時の衛星の仰角、方位角

https://embed.plnkr.co/d7WERWSDfGyHg8qzBGxT/

```
仰角、方位角: 61.87, 203.84
```

以上。
phalcon 3.4 centos7 install


##phalcon パッケージのリポジトリ情報登録
phalconの最新パッケージは、ここにあります。
https://packagecloud.io/phalcon/stable

ここから
####まずは、yumリポジトリを登録します。

CentOSなので[RPM]を選択します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84965/1ffaedbf-5620-0c69-b421-9d2087066d8c.png)


[RPM]をクリックするとcurlコマンドが出てきますのでコピーしてLinux上で実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84965/415054cb-27f2-280d-b79c-06fad286204f.png)


リポジトリのインストールが終わったらphalconがインストールできるか検索してみます。

```bash
yum search phalcon

php55u-phalcon-debuginfo.x86_64 : Debug information for package php55u-phalcon
php56u-phalcon-debuginfo.x86_64 : Debug information for package php56u-phalcon
php70u-phalcon-debuginfo.x86_64 : Debug information for package php70u-phalcon
php71u-phalcon-debuginfo.x86_64 : Debug information for package php71u-phalcon
php72u-phalcon-debuginfo.x86_64 : Debug information for package php72u-phalcon
php73u-phalcon-debuginfo.x86_64 : Debug information for package php73u-phalcon
php55u-phalcon.x86_64 : High performance PHP framework
php56u-phalcon.x86_64 : High performance PHP framework
php70u-phalcon.x86_64 : High performance PHP framework
php71u-phalcon.x86_64 : High performance PHP framework
php72u-phalcon.x86_64 : High performance PHP framework
php73u-phalcon.x86_64 : High performance PHP framework

```

## phalconのインストール
php7.2の場合は、
php7２u-phalcon.x86_64

ｐｈｐ7.3の場合は、
php73u-phalcon.x86_64

今回は、php7.2の環境にいれるので、
php7２u-phalcon.x86_64

```
yum install php72u-phalcon.x86_64
```

インストールは２箇所にあります。
/usr/lib64/php/modules/phalcon.so
/usr/lib64/php-zts/modules/phalcon.so (スレッドセーフ版)


```
php --info | grep phalcon

/etc/php.d/50-phalcon.ini
phalcon
phalcon => enabled
```

phalcon => enabledと表示されていれば、OKです。
【Swift】基本事項の意味確認

・クラス メソッドやプロパティの集合体で一つの塊
・メソッド  関数のこと
・プロパティ  定数や変数のこと
・インスタンス  何らかの値が入った変数や定数のこと
・インスタンス化  実際に使えるようにすること

例えるとクラスは洋式の部屋、メソッドやプロパティは家具(概念として)、インスタンスは実際に部屋に置いてある家具、インスタンス化は実際に家具を使用すること。
【Windows & Mac】Boostnoteのショートカットまとめ

Boostnoteが好みで公私ともに利用しているのですが、自宅PCはWindows、会社はMacという状態で、
しかも微妙にショートカットが直感的に対応していない部分があり結構混乱します。
あと[公式に一覧でまとめている所の情報](https://github.com/BoostIO/Boostnote/wiki/Keyboard-Shortcuts)があまり網羅的でなかったり、
調べて出てくる情報が古かったりしたので一覧でまとめました。

---

# 基本操作系
|         Windows          |    Mac    | 機能                                  |
|:------------------------:|:---------:|:------------------------------------- |
|         Ctrl + N         |   ⌘ + N   | 新規ノート作成                        |
| Ctrl + Shift + Backspace | ⇧ + ⌘ + ⌫ | ノートの削除                          |
|         Ctrl + D         |   ⌘ + D   | ノートの複製                          |
|         Ctrl + E         |   ⌘ + E   | ノートを編集                          |
|         Ctrl + W         |   ⌃ + W   | ノートを閲覧                          |
|         Ctrl + M         | ⌘ + ⌥ + M | エディタモードの切替（編集時のみ）    |
|         Ctrl + P         |   ⌘ + P   | ノートを印刷                          |
|         Ctrl + Shift + T         |   ⌘ + ⇧ + T   | タグを追加                          |
|           Alt            |     -     | メニューバーの表示/非表示切替         |
|        Ctrl + `,`        |  ⌘ + `,`  | 個人設定の表示                        |
|         Ctrl + B         |   ⌘ + B   | サイドバーの表示/非表示切替           |
|         Ctrl + [         |   ⌘ + [   | サイドバーのノート参照を↑に移動       |
|         Ctrl + ]         |   ⌘ + ]   | サイドバーのノート参照を↓に移動       |
|     Super + Alt + E      | ⌘ + ⌥ + L | Boostnoteの表示/非表示                |
|           F11            | ⌘ + ⌃ + F | Boostnoteを全画面表示                 |
|        Super + M         |   ⌘ + M   | Boostnoteを最小化                     |
|         Ctrl + R         |   ⌘ + R   | Boostnoteをリロード                   |
|         Alt + Q          |   ⌘ + W   | Boostnoteを閉じる                     |
|     Ctrl + Shift + I     | ⌘ + ⌥ + I | デベロッパーツールの表示/非表示       |
|     Ctrl + Shift + L     | ⌘ + ⇧ + L | 検索フォームにフォーカス (閲覧時のみ) |


# ノート編集画面の操作系

|   Windows   |   Mac   | 機能                         |
|:-----------:|:-------:|:---------------------------- |
|Ctrl + Z|⌘ + Z|Undo|
|Ctrl+U|⌘ + ⇧ + Z|Redo|
| Ctrl + Home |  ⌘ + ↑  | 画面最上部へ移動             |
| Ctrl + End  |  ⌘ + ↓  | 画面最下部へ移動             |
| Ctrl + `;`  | ⌘ + `=` | 画面の拡大                   |
| Ctrl + `-`  | ⌘ + `-` | 画面の縮小                   |
| Ctrl + `0`  | ⌘ + `0` | 画面をデフォルトサイズに戻す |


# Markdown系

|        Windows         |        Mac         | 機能                     |
|:----------------------:|:------------------:|:------------------------ |
|    Shift + Ctrl + T    |     ⇧ + ⌃ + T      | 目次（TOC）追加          |
|        Ctrl + /        |       ⌘ + /        | 日付挿入                 |
|    Shift + Ctrl + /    |     ⌘ + ⌥ + /      | 日付+時間挿入            |
| Shift + 範囲選択 + `{` | ⇧ + 範囲選択 + `{` | 選択した範囲を`{}`で囲む |
| Shift + 範囲選択 + `[` | ⇧ + 範囲選択 + `[` | 選択した範囲を`[]`で囲む |
C言語の復習（scanfを使ってみようか)

#scanfって
僕のイメージのscanfは自由に数字や文字を入れてくださいというものでしょうかね。
scanfを使うときは(数字,&宣言した名前)となっています。
&はアドレスを参照してる感じですね。
あなたが作った箱の中身は？って感じですね。

しかし、文字の場合は&使いません。
事前にchar[100]と書いてるのはcharは一文字ずつ読み込むので1文字１バイトとして１００バイト使えるんですね。

scanfだと特に制限なしで読み込んじゃいます。
%sを使っているのですがこちらは文字列で受け取る。(ちなみに%Cは１文字受け取るですね。）という形にしないと文字出力できませんね。

もし、%10sにすると10バイトだけ読み込むことになるのかな。
ひらがなだと１文字２バイトなので%10sだと５文字受け取ることになるでしょうね。

ぐだぐだ言ってないでプログラムを書いていきましょうか。

```
#include<stdio.h>

int main(void){
	int aa, bb, cc, dd, ee, ff, gg;
	char moji[100]; 

puts("君が好きな数字を１つ書て改行してもう一つ数字をかいて、そのあとに改行して好きな言葉いれてね。");
	scanf("%d", &aa);
	scanf("%d", &bb);
	scanf("%10s",moji);

	cc = aa + bb;
	dd = aa - bb;
	ee = aa * bb;
	ff = aa / bb;
	gg = aa % bb;

	puts("");
	puts("じゃあそれを使って計算するよ");

	printf("aa + bb の値は%dですね \n", cc);
	printf("aa - bb の値は%dですね \n", dd);
	printf("aa * bb の値は%dですね \n", ee);
	printf("aa / bb の値は%dですね \n", ff);
	printf("aa %% bbの値は%dですね \n", gg);
	puts("最後に言い残す言葉は");
	printf(moji);

return 0;

}
```
これをコンパイルしてみましょう。
<img width="606" alt="ccl.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292512/27aa4b90-0909-e70f-8d3b-183c7c16c3fb.jpeg">
ってな出力が出てきました！

文字や数字を格納する方法や容量の制限などいろいろできるので触ってみると勉強になりそうですね。

ちなみに%は余りって意味です。%%二つ使ってるのは出力にも%という記号を出したくてなっています。

自分なりのscanfを使った復習でした＾＾
読んだ本の紹介02「伝える力 2 もっと役立つ！ 「話す」「書く」「聞く」技術 (PHPビジネス新書)」

[伝える力 2 もっと役立つ！ 「話す」「書く」「聞く」技術](https://www.amazon.co.jp/dp/B0081BLREI)
おすすめ度★★☆☆☆

## なぜこの本を読んだのか
人に伝える力を身につけたくて検索したら上に出てきた
タイトルに目をひかれた
テレビにも出ている池上さんの本だったため興味がわいた
（なぜか１を飛ばして２を読みました）

## まとめ
- 伝える姿勢や態度によって、相手が受ける印象は大きく異なる
- `質問を想定してそれに対する回答を用意していくことが大事`
    - シミュレーションをする
- 業界用語は業界内だけで使う
    - 伝わらない、聞く側がさらにわからなくなる
- Twitterの140字で「伝える力」を磨く
    - 文字数の制約があるので必要なことを過不足なく盛り込む必要があり力を蓄えられる
- `話し相手との信頼関係を築くことが大事`
- 話が好きな「おばちゃん」気質を持つことでコミュニケーション能力は向上する
    - 変なプライドは捨てて人と話す
- 「伝える力」で大事なのは `謙虚であること`
- `好奇心` を大切にすること
    - 好奇心に駆られて詳しく調べておけばいざという時、相手にわかりやすく説明できる


## 感想
体験談多め9：1ぐらい

案外Twitterでいいんだなーって思った
Twitterで伝える力が鍛えられるということでもっと日常生活をツイートしていこうと思った
kubectlコマンドをタブ補完しようとすると「(eval):1: _kubectl: function definition file not found」と出る



# メッセージ内容
以下のようなメッセージが出て、オプションのタブ補完ができなくなる

```
(eval):1: _kubectl: function definition file not found
```

## 環境
- Mac
- zsh

## 対処方法
キャッシュ的なものが残っているのかな？
それを削除して、zshを再起動

```
rm ~/.zcompdump
exec zsh
```

## 参考

https://kaworu.jpn.org/freebsd/zsh_%E3%81%AEfunction_definition_file_not_found%E3%81%A8%E3%81%84%E3%81%86%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%AE%E5%AF%BE%E5%87%A6%E6%B3%95
gitで直近のコミットした行数をカウントする

# 背景
今日一日の作業実績を確認したり、自分のモチベーションアップのためにサクッとgitでcommitした行数を確認したかった！


# 方法
以下コマンド実行

```sh
git log --numstat --pretty="%H" -1 --no-merges | awk 'NF==3 {plus+=$1; minus+=$2} END {printf("%d (+%d, -%d)\n", plus+minus, plus, minus)}'
```

-1は行数チェックの対象コミット数を示しています。
なので直近の３つのコミットを対象としたい場合は-3としてください。

# 結果
上記コマンドを実行すると以下のような出力が得られる。
左から、合計行数と+追加行数、-削除行数が表示される。

```console
$ git log --numstat --pretty="%H" -1 --no-merges | awk 'NF==3 {plus+=$1; minus+=$2} END {printf("%d (+%d, -%d)\n", plus+minus, plus, minus)}'
675 (+507, -168)
```

# その他
ライブラリなど除外したいファイルがある場合は以下のようにすると良さそう。

方法としては以下

```sh
git log --numstat  --pretty="%H" -1 --format=%s -- . ":(exclude)postgres"
```
上記は例で「postgres」のディレクトリが除外設定されている。

```sh
--format=%s -- . ":(exclude)postgres"
```
上記の部分でpostgresのディレクトリを除外している

<br>

複数のディレクトリを指定する場合はつなげて以下のようにすると良さげ

```sh
git log --numstat  --pretty="%H" -1 --format=%s -- . ":(exclude)postgres" --format=%s -- . ":(exclude)golang/github.com"
```

# 参考にしたURL
- [gitで自分のコミットしたコードの行数を数える](https://qiita.com/Night___/items/359ff81f358968567a45)
- [‘git log’を特定のパスの変更を無視するようにする](https://codeday.me/jp/qa/20181208/58972.html)

# Thanks!
altさん、タグ修正ありがとうございます…！
Redmine(bitnami) > ガントチャートで日本語



環境：
bitnami版Redmine
redmine v3.4


以下を参考にした

[ガントチャートをPNG形式の画像に出力すると文字化けする — Redmine.JP](http://redmine.jp/faq/gantt/gantt-png-mojibake/)



## font 

日本語fontのインストール    

```
apt-get install fonts-ipafont
```

以下のパスにインストールされた
/usr/share/fonts/truetype

インストールされたフォントは以下の２つ

* fonts-japanese-gothic.ttf
* fonts-japanese-mincho.ttf



## config
config/configuration.yml 内の rmagick_font_pathにフォントを設定する。
/home/*user*/apps/redmine/htdocs/config/configuration.yml


```yml:config/configuration.yml
rmagick_font_path: /usr/share/fonts/truetype/fonts-japanese-gothic.ttf
```


## 再起動
redmine 再起動

```
sudo /opt/bitnami/ctlscript.sh restart
```
ローカルIPとグローバルIPを取得するコマンドを自作する

ローカルIPやグローバルIPをたまに確認するのですが、macOSなのに`ip a`しようとしたり、`ifconfig en0 `するのがめんどくさくなってきたので、ほしいIPアドレスだけ取得するコマンドを作ってみました。

```shell
#!/bin/zsh

# If your connection is true, return your global and local IP.

global=$(curl -s inet-ip.info)
local=$(ifconfig en0|grep inet|awk '{print $2}'|sed -n 2P)

if [ -z "$global" ]; then
  echo "\033[31mERROR: No connection\033[m"
  exit 1
fi

echo "\033[34mGlobal IP\033[m: $global"
echo "\033[35mLocal IP\033[m: $local"

exit 0
```

globalは自分のIPを確認できるhttp://inet-ip.info/ からとってきて、localは`ifconfig`から無理やり取ります。

パスを通して実行権限を与えればコマンドとして使えます。
ファイル名は好きなもので、拡張子なしで大丈夫です。

```terminal
$ PATH="/your/directory:$PATH"

$ chmod 755 /your/shell/path

$ command_name
Global IP: xxx.xxx.xxx.xxx
Local IP: 192.168.40.162
```

はじめてコマンドを自作してみたのですが、とても簡単だったので今後も必要に応じてやってみたいと思いました。

**追記**

コピーする手間が面倒になってきたので、以下のようにcommandを編集しました。

```shell

#!/bin/zsh

- # If your connection is true, return your global and local IP.
+ # If your connection is true, return your global and local IP, and copy local IP.

global=$(curl -s inet-ip.info)
local=$(ifconfig en0|grep inet|awk '{print $2}'|sed -n 2P)

if [ -z "$global" ]; then
  echo "\033[31mERROR: No connection\033[m"
  exit 1
fi

echo "\033[34mGlobal IP\033[m: $global"
echo "\033[35mLocal IP\033[m: $local"
+ echo $local | pbcopy

exit 0
```

ローカルIPをpbcopyにパイプで渡せば、そのままクリップボードにコピーしてくれます。
RubyでNokogiriを使ってスクレイピングを行う

Nokogiriを使って、スクレイピングしてcsvに吐き出す方法

##cssを使って指定

```
row.css('#normalResultsBox')　　　　　　　 #ID
row.css('.normalResultsBox')　　　　　　　 #クラス
row.css('h4>a').text,   　　　　　　　　　#階層
row.css('p')[1].text　　 　　　　　　　　　#2番目要素


row.css('a').attribute('href').value    #タグ内の要素を取得
row.css('a').gsub('aaaa','')　　　　　　 #置換する
row.css('a').split(".")[0]　　　　　　 　#区切って1番目を取得


```

###Rubyプログラミング

```test.rb
#住所という文字列が存在するかどうか
if row.css('p')[0].text.include?("住所")
 #存在する
else
 #存在しない
end
```

##urlからスクレイピング
```noko.rb
require 'nokogiri'
require 'open-uri'
require 'csv'

#ヘッダーの書き込み
CSV.open('noko.csv', 'w') do |csv|
  csv << ["title","url"] 
end


#スクレイピングするurlを列挙する
urls = [
    'url1',
    'url2'
    ]
  
#urlをループ処理  
urls.each {
  |url|
  charset = nil

  html = open(url) do |f|
      f.read
  end

  doc = Nokogiri::HTML.parse(html, nil, "CP932")

  #2時配列を宣言する
  arr = Array.new
  
  doc.css('.normalResultsBox').each do |row|
      arr << [
        row.css('h4>a').text,                 #タイトル
        row.css("a").attribute('href').value  #url　
      ]
  end

  # csvファイル形式で生成
  string_csv_format = CSV.generate do |data|
    arr.each do |line|
      data << line
    end
  end

  # csvファイル書き出し方法1
  File.open("noko.csv", "a") do |f| 
    f.puts string_csv_format
  end
}
```

##textファイルを読み込んで、取り出す

```noko2.rb
require 'nokogiri'
require 'csv'

#ヘッダーの書き込み
CSV.open('itown.csv', 'w') do |csv|
  csv << ["url","comment"] 
end


html = File.open("test1.txt") do |f|
    f.read
end

doc = Nokogiri::HTML.parse(html, nil, "CP932")

#2時配列を宣言する
arr = Array.new

 doc.css('.normalResultsBox').each do |row|
    arr << [
      row.css('h4>a').text,                                                       #社名
      row.css('p')[1].text.gsub('住所 ','').gsub('〒','').split("　")[0],         #郵便番号
      row.css('p')[1].text.gsub(' 地図・ナビ','').split("　")[1],                 #住所
      row.css('p')[2].css('b').text                                               #電話
    ]
end

# csvファイル形式で生成
string_csv_format = CSV.generate do |data|
  arr.each do |line|
    data << line
  end
end

# csvファイル書き出し方法1
File.open("itown.csv", "a") do |f| 
  f.puts string_csv_format
end
```

##実行する

```
$ruby noko.rb
```
Rails6 のちょい足しな新機能を試す87（Time#advance編）

# はじめに

Rails 6 に追加された新機能を試す第87段。 今回は、 `Time#advance` 編です。
Rails 6 では、 1001/03/07 以前の `Time#advance` の計算が正確になりました。

Ruby 2.6.4, Rails 6.0.0 Rails 5.2.3 で確認しました。

```shell
$ rails --version
Rails 6.0.0
```

今回は、ちょっとわざとらしいですが、2009年4月1日の1200年前に即位した天皇を検索してみましょう。

# プロジェクトを作る

```shell
rails new rails_sandbox
cd rails_sandbox
```

# Emperor モデルを作る

`name` と `enthroned_at` (即位した年) をもつ `Emperor` モデルを作ります。

```shell
bin/rails g model Emperor name enthroned_at:datetime
```

# seed データを作る

`seed` データを作ります。

```ruby:db/seeds.rb
Emperor.create(
  [
    { name: '桓武天皇', enthroned_at: Time.utc(781, 4, 3) },
    { name: '平城天皇', enthroned_at: Time.utc(806, 3, 17) },
    { name: '嵯峨天皇', enthroned_at: Time.utc(809, 4, 1) },
    { name: '淳和天皇', enthroned_at: Time.utc(823, 4, 16) },
    { name: '仁明天皇', enthroned_at: Time.utc(833, 2, 28) }
  ]
)
```

# マイグレーションを行い seed データを登録する

```shell
$ bin/rails db:create db:migrate db:seed
```

# rails console で確認する

`enthroned_at` が 2009年4月1日の 1200年前に即位した天皇を検索してみます。

「2009年4月1日の 1200年前」は、 `Time.utc(2009, 4, 1).advance(years: 1200)` で求めることができます。


```irb
irb(main):001:0> Emperor.where(enthroned_at: Time.utc(2009, 4, 1).advance(years: -1200))
  Emperor Load (0.3ms)  SELECT "emperors".* FROM "emperors" WHERE "emperors"."enthroned_at" = $1 LIMIT $2  [["enthroned_at", "0809-04-01 00:00:00"], ["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<Emperor id: 3, name: "嵯峨天皇", enthroned_at: "0809-04-01 00:00:00", created_at: "2019-09-21 21:49:24", updated_at: "2019-09-21 21:49:24">]>
```

嵯峨天皇が検索できました。

# Rails 5.2.3 では

「2009年4月1日の 1200年前」が 809年4月5日になってしまうため、期待した結果が得られません

```irb
irb(main):001:0> Emperor.where(enthroned_at: Time.utc(2009, 4, 1).advance(years: -1200))
  Emperor Load (0.5ms)  SELECT  "emperors".* FROM "emperors" WHERE "emperors"."enthroned_at" = $1 LIMIT $2  [["enthroned_at", "0809-04-05 00:00:00"], ["LIMIT", 11]]
=> #<ActiveRecord::Relation []>
```

# 試したソース

試したソースは以下にあります。
https://github.com/suketa/rails_sandbox/tree/try087_time_advance

# 参考情報

* [What is new in Rails 6.0](https://bogdanvlviv.com/posts/ruby/rails/what-is-new-in-rails-6_0.html)
* [Fix Time#advance to work with dates before 1001-03-07](https://github.com/rails/rails/pull/35659)
* [天皇の一覧](https://ja.wikipedia.org/wiki/%E5%A4%A9%E7%9A%87%E3%81%AE%E4%B8%80%E8%A6%A7)
エクセル CSVファイルを読み込む VBA マクロ

#はじめに
エクセルでCSV・テキストファイルを開けるのはいいのだが、
いちいち手作業で出力設定するのが面倒なのでマクロを書きました

```VB
Option Explicit

Sub getcsv()
    Dim st As String
    st = Application.GetOpenFilename()
    If st = "False" Then Exit Sub 'キャンセルなら処理終了

    Dim idx As Long
    idx = 1
    Dim Cnt As Long
    Dim Vst() As String
    
    Open st For Input As #1
    Do Until EOF(1)
        Line Input #1, st
        Vst = Split(st, ",")
        For Cnt = 0 To UBound(Vst)
            Range("A" & idx).Offset(0, Cnt).Value = Replace(Vst(Cnt), """", "")
        Next
        idx = idx + 1
    Loop
    Close #1
    
End Sub

```


読み込むだけなのでFSOを使うまでもないと思いましたので簡潔に書きました。

#おわりに
VBAネタあれば対応できます笑
gulpのビルド環境の設定

会社のフロントが使用しているgulp環境を利用してドメイン等のbuild環境の設定を行いました。
以下の目標で実装を行いました。

- 出来ればモジュールを追加しない
- 切り替えが簡単

## 使用モジュール
Laravelを使っているので当初はenvファイルを読み込む方法を考えてみましたが、そうなると「dotenv」、「node-env-file」、「gulp-env」等をインストールしないと行けなく、会社では別にDeploerなものでデプロイ等しなくて良いので、別の分ける必要がないかと考えました。

それで使用するのは「minimist」のみにしておきました。

### 環境変数の定義
発想としてはdotenvと同じくnpmで利用している環境Objectがあるのでそこで追加したらどうかと思いました。

```
import minimist from 'minimist';

const options = minimist(process.argv.slice(2), {
    string: 'env',
    default: {
        env: 'dev'
    }
});

if (options.env === 'pro') {
    // 本番環境
    process.env = Object.assign(process.env, {
        domain: 'https://pro-example.com'
    });
} else if (options.env === 'stg') {
    // テスト環境
    process.env = Object.assign(process.env, {
        domain: 'https://stg-example.com'
    });
} else {
    // ローカル環境
    process.env = Object.assign(process.env, {
        domain: 'http://dev-example.com'
    });
}
```

「minimist」はgulpの実装Optionの取得・ディフォルトの設定に使いました。「process.env」へ情報を追加する方法は「Object.assign」メソードを利用しました。

### 読み取り方法
```
import gulp from 'gulp'
import pug from 'gulp-pug'
import plumber from 'gulp-plumber'
・・・・
const pugOption = {
	verString: new Date().getTime(),
	domainUrl: process.env.domain // pug内部で直接書いても認識できる
}
・・・・
gulp.task('pug', ['・・・・'], () => {
	return gulp.src([paths.pug_src, paths.pug_exclude])
		.pipe(plumber())
		.pipe(gulpif(global.isWatching, cached('pug')))
		.pipe(filter(function(file) {
			return !/\/_/.test(file.path) && !/^_/.test(file.relative);
		}))
		.pipe(pug({
			pretty: true,
			locals: pugOption
		}))
		.on('error', (err) => {
			console.log(err.message);
		})
		.pipe(gulp.dest('dist'))
		.pipe(browserSync.stream());
});
・・・・
```
pugのタスクのソースの一部です。「process.env.domain」のように直接に使えます。実際のpugファイルへ使っても出来ますが、このファイルではpugのオプションで渡す感じでやってみました。

```sample.pug
・・・・
img(src=domainUrl+"/img/logo_commufa.png?ver="+verString)
・・・・
```
もちろん以下のように直接でも可能です。

```
img(src=process.env.domain+"/img/logo_commufa.png?ver="+verString)
```

### 使い方
```
# gulp pug --env dev  // process.env.domain : http://dev-example.com
# gulp pug --env stg  // process.env.domain : https://stg-example.com
# gulp                // process.env.domain : http://dev-example.com
```
Linux基礎(SUID/SGID/Sticky Bit)

#SUID

Linuxでは、ユーザはUIDと呼ばれるID番号で管理されている。一時的に別のUIDのユーザに変更できる機能のことをSUID(Set User ID)という。SUIDで一般ユーザがroot権限でファイルを実行できる。
※通常の実行ファイルは実行者の権限で動作するが、SUIDが設定されていると実行ファイルの所有者権限で動作させられる。

SUIDの使用例をみる。例えばパスワード変更は、/etc/shadowファイルを編集する必要があるが、このファイルの変更権限は一般ユーザにはない。しかし、パスワード変更コマンド(passwd)にはSUIDが設定されているため、一般ユーザがpasswdコマンドを実行した場合においても、passwdコマンドの所有者であるroot権限で実行できる。なおSUIDが設定されているファイル（プログラム）においては所有者の実行権限が「s」と表記される。

```shell
$ ls -l /usr/bin/passwd
-rwsr-xr-x. 1 root root 25980 Feb 22 2012 /usr/bin/passwd
```

上のコマンド結果では所有者（root）のアクセス権は「rws」となっており、実行権が「s」であることがわかる。つまり、このコマンドを実行可能なアクセス権を有する一般ユーザーによりプログラムが実行された場合はこのファイルの所有者(root)の権限で実行できることを意味する。

アクセス権を決定するchmodコマンドでSUIDを設定する場合は、アクセス権表記に「4000」を加算する。つまり元が755(rwx r-x r-x)のファイルの場合は「4755」と設定する。すると 「rws r-x r-x」となる。
chmodによるアクセス権の設定は数値で定義する方法と、3つの記号（u+s)を用いた方法の2種類ある。

```shell
# 実行例 ： test.txt ファイルのアクセス権を「 rws r-x r-x 」にする設定
$ chmod 4755 test.txt |
```

```shell
# 実行例 ： test.txt ファイルのアクセス権が変更前「 755 」である値を、変更後に「 4755 」とする設定 (SUID)
$ chmod u+s test.txt |
```

#SGID
SGIDはグループ権限で動作する。SUIDの場合は、所有者権限の実行権限が「s」となるが、SGIDではグループの実行権限が「s」となる。chmodコマンドでSGIDを設定する場合、アクセス権表記に「2000」を加算する。文字列の場合には(g+s)を定義

```shell
# 実行例 ： test.txt ファイルのアクセス権を「 rwx r-s r-x 」にする設定
$ chmod 2755 test.txt |
```

```shell
# 実行例 ： test.txt ファイルのアクセス権が変更前「 755 」である値を、変更後に「 2755 」とする設定 (SUID)
$ chmod g+s test.txt |
```

#スティッキービット(Sticky Bit)
Sticky Bitが設定されたディレクトリ以下のファイルとディレクトリは、実際に設定したアクセス権に関係なくて、所有者とrootユーザのみが名前の変更と削除を行える。このスティッキービットが使用されるケースは「全ユーザがファイルを作成できるが作成したファイルを他人がファイル名の変更や削除できないようにしたい」場合に利用する。例えば/tmpディレクトリにはスティッキービットが設定済み。
スティッキービットでは他のユーザの実行権限が「t」となる。chomodコマンドでスティッキービットを設定する場合、アクセス権表記に1000を加算する。文字列の場合は3つの記号（o+t）を定義

```shell
# 実行例 ： testディレクトリのアクセス権を「 rwx rwx rwt 」にする設定
$ chmod 1777 test|
```

```shell
# 実行例 ： testディレクトリのアクセス権が変更前「 777 」である値を、変更後に「 1777 」とする設定 (SUID)
$ chmod o+t test|
```

#SUID/SGID/StickyBitの違い

|比較項目|実行権限の設定対象|加算するアクセス権の表記|加算するアクセス権の表記(3つの記号)|
|---|---|---|---|
|SUID|所有者|4000|u+s|
|SGID|グループ|2000|g+s|
|StickyBit|その他のユーザ|1000|o+t|

#umaskコマンド
umaskコマンドは、umask値の確認とumask値の設定を行うコマンド。新規作成したファイルやディレクトリのアクセス権はファイルの場合「666」からumask値を引いた値、ディレクトリの場合「777」からumask値を引いた値となる。rootユーザのumask値のデフォルト値は「0022」。従い、新規に作成されるファイルのアクセス権は644(666-022=644)となり、新規作成のディレクトリのアクセス権は755(777-022=755)

```shell
# umack値の確認
$ umask

#umask値を0022から、0027に変更する設定
$ umask 0027
#このumask値が適用されるユーザが作成した新規ファイルのアクセス権は（-rw r-- ---）となる。
```

#chown/chgrpコマンド
chownコマンドはファイルやディレクトリの所有者を変更するコマンド。root権限のユーザのみ実行できる。
chgrpコマンドはファイルやディレクトリの所属するグループを変更するコマンド。

|オプション|説明|
|---|---|
|-R|指定したディレクトリ以下の全てのファイルの所有者の変更|


```shell
# test.txtファイルの所有者を「tom」に変更
$ chown tom test.txt

# test.txtファイルの所有者を「tom」に変更、グループを「group1」に変更
$ chown tom:group1 test.txt

# test.txtファイルのグループを「tom」に変更
$ chgrp group1 test.txt

```
EC2がvCPUベースのオンデマンドインスタンス起動数の制限に対応した

[Amazon EC2 で vCPU ベースのオンデマンドインスタンス制限が利用可能に](https://aws.amazon.com/jp/about-aws/whats-new/2019/09/vcpu-based-on-demand-instance-limits-are-now-available-in-amazon-ec2/)

[EC2 オンデマンドインスタンス制限](https://aws.amazon.com/jp/ec2/faqs/#EC2_On-Demand_Instance_limits)

---
vCPUベースのオンデマンドインスタンス起動数の制限に対応したらしいので、確認してみました。
これにより、オンデマンドインスタンスの起動数制限から、vCPUベースになった事で**シンプルな管理が可能**となりました。

従来は、**インスタンスタイプ毎の上限数(Current limit)**が設定されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/68228767-23b5-02aa-6b83-21804e4c9b31.png)

「Opt in」と入力。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/0e893b81-1714-8ea3-82d8-bc8cccc8f0bd.png)

15分間待と、vCPU毎になる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/c7909ef0-7dfe-88f8-1ed7-9f019f4766cd.png)

vCPUの計算は、[簡易 vCPU 計算ツール](https://console.aws.amazon.com/ec2/home?#LimitsCalculator)を使えば簡単に確認することができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/eb37bda9-631d-9796-a53e-e1ffa288b315.png)

*引き上げについてはどうなるのか？*

**Q: これらの制限は時間経過とともに変わりますか ?**
はい。制限は時間の経過とともに変わる可能性があります。
Amazon EC2 は各リージョン内で使用状況を継続的に監視しており、EC2の使用に基づいて制限が自動的に引き上げられます。

**Q: 制限の引き上げをリクエストするにはどのようにすればよいですか?**
EC2 によって使用状況に基づきオンデマンドインスタント制限は自動的に引き上げられますが、必要に応じてAmazon EC2 コンソールの制限ページ、Service Quotas consoleの Amazon EC2 サービスページ、またはサービスクォータ API/CLI から制限引き上げをリクセストできます。
pandasのdataframeでreplaceのinplace機能がうまく働かないとき

例えばdataframeが'A', 'B'というカラム名を持っているとします。
'A' に 'tokyo'と書いてある行で'B'列で1という値を持っているところを2に置換したいとします。

最初は
df[df['A'] == 'tokyo']['B'].replace(1, 2, inplace=True)`
と書いていたんですが、
`A value is trying to be set on a copy of a slice from a DataFrame`
のようなエラーメッセージが出ました。

最終的に、
`df.loc[df.A == 'tokyo', 'B'] = df.loc[df.A == 'tokyo', 'B'].replace(1.0, 0.0)`
のようにしたら元のdataframeにも反映されてくれました。
正直Gitわからなかったけどとりあえずこれできればいいだろっていうメモ

正直Gitって自分はあんまり触らないだろうと思ってたのに、がっつり触るようになってしまったのでとりあえずこれだけ覚えればいけるっていう自分用のメモ

※Github利用を想定

###最初にやること
まずは初期設定をしなければいけないっぽい。主にgithubのアカウントとか。
ただここで登録してもcloneするとき再度認証を求められたりするのでよくわからない。
まあやっとけば間違いない。

```git:
git config --global user.name XXXXXXX
git config --global user.email XXXXXXX
```


###Clone
なにはともあれクローン。githubにすでにプロジェクトができてれば

```git:
git clone http://github.com/user/project
```

###コミットからプッシュまで
クローンしたものを編集したからgithubにプッシュしたいとき。

```git:
git add .
git commit -m "commit message"
git push origin master
```

一番最初にやったときにはまったこととしては、「git add」はちゃんとプロジェクトのディレクトリで実行すること。
例えば「test」というプロジェクトをデスクトップにクローンしたときは

```git:
C:\Users\user\Desktop> git clone http://github.com/user/test
C:\Users\user\Desktop> cd test
C:\Users\user\Desktop\test>==ここでいろいろ編集==
C:\Users\user\Desktop\test> git add .
C:\Users\user\Desktop\test> git commit -m "commit message"
C:\Users\user\Desktop\test> git push origin master
```

###ローカルにあるものをリモートにプッシュする
あんまりやらないがローカルで新規で作ってリモートにプッシュしたいとき。
（自分はリモートで空のプロジェクトつくってそれをクローン⇒編集してプッシュしてる）

```git:
プッシュしたいファイル内で
git init
git remote add origin http://github.com/user/
これでoriginにプッシュ先が登録される
git add .
git commit -m "commit message"
git push origin master
```

###ブランチを指定してプッシュ
なんかいろいろやり方があるみたいだが自分は以下の方法で

```git:
git push origin master:branch
```

###ブランチを指定してクローン

```git:
git clone -b branch http://github.com/user/project
```

2019/10/02現在
ほかにもよく使うものがあれば追記していきたい
mediapipe hand trackingお試し

# mediapipeお試し
Hnad Trackingがヌルヌル動くニュース記事を見てちょっとお試し。基本スマホで動作させてる人が多かったけど、Mac環境で試している人はあまりいなかったので手順を記載。

![](https://1.bp.blogspot.com/-H71UdvAObkQ/XVrSxUc2rFI/AAAAAAAAEhU/h7NuEZ23Pu4XAdwCcaKNxakGbN4nJUc2wCLcBGAs/s1600/image2.gif)
(参照: https://ai.googleblog.com/2019/08/on-device-real-time-hand-tracking-with.html)

## 環境
* PC: Mac Book Pro
* OS: macOS Mojave 10.14.6

## インストール
* 公式(2019/10/02時点)
 - https://github.com/google/mediapipe/blob/master/mediapipe/docs/install.md#installing-on-macos

* gitからdl

```
$ git clone https://github.com/google/mediapipe.git
$ cd mediapipe
```

* bazelをinstall (手動でinstallでも可)

```
$ brew install bazel
```

* opencv/ffmpegをinstall (依存があるようなので注意)

```
$ brew install opencv@3
```

* hello world実行 (Hello Worldが出力されたOK)

```
$ export GLOG_logtostderr=1
$ bazel run --define MEDIAPIPE_DISABLE_GPU=1 \
    mediapipe/examples/desktop/hello_world:hello_world
```

## Hand Trackingお試し
* Hello World出来たら環境のインストール出来ているので次はHnad Trackingを動作させる
 
```
$ bazel build -c opt --define MEDIAPIPE_DISABLE_GPU=1 \
    mediapipe/examples/desktop/hand_tracking:hand_tracking_cpu

$ export GLOG_logtostderr=1
$ bazel-bin/mediapipe/examples/desktop/hand_tracking/hand_tracking_cpu \
    --calculator_graph_config_file=mediapipe/graphs/hand_tracking/hand_tracking_desktop_live.pbtxt
```

うまく実行したらカメラが起動するので手をかざすだけで反応する。かなり精度良い。ただ同時に認識するのは1つだけのよう。

<img width="1277" alt="スクリーンショット 2019-10-02 11.47.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36291/271e58f6-a28c-c1cc-4e7f-7b6fe845b552.png">
<img width="1277" alt="スクリーンショット 2019-10-02 11.47.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36291/663de4c7-769e-ff87-6455-46678101da05.png">
<img width="1277" alt="スクリーンショット 2019-10-02 11.48.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36291/7f2dc898-41a6-0d6e-0670-941754d521e7.png">
brewで入れているruby-buildをgitのHEADに更新する

## はじめに
久々のQiitaです。
Rubyの2.4以降のバージョンに対してセキュリティリリースが出たそうで。
https://www.ruby-lang.org/ja/news/2019/10/01/ruby-2-6-5-released/

使っているrubyのバージョンを更新しようとしたところ、`brew upgrade ruby-build`したのに2.6.5がない。

```
$ brew update && brew upgrade ruby-build
$ rbenv install --list

...（中略）...
  2.6.3
  2.6.4
  2.7.0-dev
  2.7.0-preview1
...（中略）...

```

どうやら `brew upgrade ruby-build` でインストールできるのは `2019/08/28` リリースのバージョンまでらしい（2019/10/02現在）。
https://formulae.brew.sh/formula/ruby-build

というわけで、gitのHEADから拾ってきて`ruby-build`を更新します。

## やり方
インストールコマンドにオプションを付けるだけ

```
$ brew install ruby-build --HEAD
```

が、既に `ruby-build` が入った状態でこれをやると怒られます。

```
Error: ruby-build 20190828 is already installed
To install HEAD, first run `brew unlink ruby-build`.
Warning: Skipping (old) /usr/local/Cellar/ruby-build/20190828 due to it being linked
```

まあそりゃそうだ、ということで、一旦 `unlink` して外してあげてから再インストールします。

```
$ brew unlink ruby-build
$ brew install ruby-build --HEAD
```

Rubyのインストールをしたらバージョン切り替えて確認

```
$ rbenv install 2.6.5
$ rbenv local 2.6.5
$ ruby -v
ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-darwin18]
```

大丈夫そうっすね。
というわけで以上です〜〜

## 参考
https://qiita.com/chezou/items/658a058ae22eb5bf6c5e
[メモ]FormDataオブジェクトにあるデータを全て削除する方法

# 概要
FormDataにあるすべてのデータ（エントリー）を削除する

### ポイント
formData.keys()やformData.entries()のイテレーター内で削除せず、イテレーターの外側で削除する。

```js:FormDataオブジェクトのデータを全て削除する
function deleteAllFormData(formData) {
    const keys = [];
    for (const key of formData.keys()) {
        keys.push(key);
    }
    for (const idx in keys) {
        formData.delete(keys[idx]);
    }
}
```

### サンプルコード(html)

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Delete all formdata</title>
</head>
<body>

<form action="#" method="post" id="myForm" enctype="multipart/form-data">
    <input type="hidden" name="myKey01" value="myValue01">
</form>
<script>

    function deleteAllFormData(formData) {
        const keys = [];
        for (const key of formData.keys()) {
            keys.push(key);
        }
        for (const idx in keys) {
            formData.delete(keys[idx]);
        }
    }

    const formData = new FormData(document.querySelector("#myForm"));
    formData.append("myKey02", "myValue02");
    formData.append("myKey03", "myValue03");

    console.log("Show form entries");
    for (const [key, value] of formData.entries()) {
        console.log(`key:${key} value:${value}`);
    }

    console.log("Delete!");
    deleteAllFormData(formData);

    console.log("Show form again");
    for (const [key, value] of formData.entries()) {
        console.log(`key:${key} value:${value}`);
    }


</script>

</body>
</html>
```

```shell:実行結果(ログ)
Show form entries
key:myKey01 value:myValue01
key:myKey02 value:myValue02
key:myKey03 value:myValue03
Delete!
Show form again
```

### アンチパターン

<font color=red>反復中に自身を変更する以下のようなコードはアンチパターン</font>

```js
for (const key of formData.keys()) {
    formData.delete(key);
}
```

（Javaでも、同期リストのIteratorで反復中に自身を変更（削除も含む）するとConcurrentModificationExceptionが発生するパターン）
githubのNetworkGraphはブランチごとのタイムラインを図で表示されるので便利

githubはとても便利ですが、ブランチが煩雑になってくるとタイムラインとブランチの変遷が分かりづらくなる時ありませんでしょうか。
そんな時はgithubの**NetWorkGraph**を見るとブランチ毎の変遷がグラフで可視化されるので見やすいです。

「``Insights``」タブ→「``Network``」→Network graph

<img width="1094" alt="スクリーンショット 2019-10-02 10.57.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452135/4532f888-16db-e997-ee23-f9d874ffc19b.png">
これでIMEの有効・無効を間違えない！Google IMEのキー設定カスタマイズ方法

WindowsユーザーであればIMEを切り替えたつもりで「こんにちは」が「konnnitiha」になったことありませんか。（筆者はよくある。）

これはひとえに、~~Windowsのせい~~ IMEの切り替えが「半角/全角 漢字キーによるトグル方式」だからだとおもってます。

[【朗報】Windowsも変換/無変換キーで日本語入力がオン/オフに PCまなぶ](https://pcmanabu.com/windows10-ime/)によると、2019年秋のアップデートで無変換キーでIMEオフ、変換キーでIMEオンになるようです :+1: 

アップデートも目前ですが（2019/10現在）、Google IMEのキー設定をマニュアルで変更する方法を紹介します。（MS-IMEの設定方法は上記記事で紹介されています）

## Google IMEでの設定方法

1. **キー設定 > キー設定の選択 > 編集…** をひらきます

> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883/363a991d-1afd-8645-2930-6cdd0a848f28.png)

2. 日本語入力 キー設定を変更します。

* 入力文字なし, Muhenkan, IMEを無効化
* 入力文字なし, Henkan, IMEを有効化

> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883/d4b081a6-2211-d0c0-05b3-8a0ddf897059.png)

これでコードを書くときに「ｐりゔぁて（private）」みたいにならず、コメントをかくときに「syutokusimasu（取得します）」にならずに済むのでよいですね！早くやっておけばよかった… :joy:
BindJSONとShouldBindJSONの違い（gin）

golang で gin を利用している際に、BindJSON と ShouldBindJSON があって名前が似ててどう違うのか気になったので記事にしてみます。間違ってたらご指摘していただけると嬉しいです。

# ginについて
>Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance -- up to 40 times faster. If you need smashing performance, get yourself some Gin.
引用：https://github.com/gin-gonic/gin

Goで扱われている、HTTPのウェブフレームワークです。同じお酒の名前のフレームワーク、Martini（https://github.com/go-martini/martini ) よりもパフォーマンスが良いと評判みたいです。

# BindJSON vs. ShoulBindJSON

以下にGoDocに基づく比較を書きます（ https://godoc.org/github.com/gin-gonic/gin )

|BindJSON |ShouldBindJSON |
|---|---|
|原型：MustBindWith|原型：ShouldBindWith|
|指定されたバインディングエンジンを使用して、渡された構造体ポインターをバインドする。エラーが発生した場合、HTTP 400でリクエストを中止します。|指定されたバインディングエンジンを使用して、渡された構造体ポインターをバインドする。|

つまりはこういうこと↓

### ソースコード

```context.go

//MustBindWith(BindJSON)
func (c *Context) MustBindWith(obj interface{}, b binding.Binding) error {
	if err := c.ShouldBindWith(obj, b); err != nil {
		c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) // nolint: errcheck
		return err
	}
	return nil
}

//ShouldBindWith(ShouldBindJSON)
func (c *Context) ShouldBindWith(obj interface{}, b binding.Binding) error {
	return b.Bind(c.Request, obj)
}
```

ShouldBindJSONに、400番でエラーを返す機能を含んでるのがBindJSONなんですね！

# BindJSON と ShouldBindJSON のまとめ

今回学んだ違いは

|BindJSON |ShouldBindJSON |
|---|---|
|エラー処理の際に400を返してくれる|エラー処理が内部では施されていない|
|独自エラーハンドリング不要|独自エラーハンドリング必要|

エラーハンドリングを独自にやりたい場合は ShouldBindJSONを使うのが良さそうですね！
学びました。

# 参考
gin（GoDoc）：https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBindJSON
障害振り返りの記載項目を考えてみた話

# 前置き
- もともとQA(品質保証部)やってた時によく振り返りさせられてた
- エンジニア転進＋業界変えたら振り返りの粒度の違いに驚いた
- とはいえかなり細かくするとやらなくなるので、悩みながら粒度は調整
- 何を書かないといけないかが明確に区分けされたことで、導入前よりはマシになった
- ゲーム業界での話
- さらすことで、対外の方に反応ワンチャンいただいて、自分にとっても今後良い振り返りができるようになればいいなという思い

# 考えてみた振り返り項目
## 共通項目
### No
- 管理用。

### 状況
- 管理用。以下のステータスを定義
    - 振り返り待ち
    - 振り返り中
    - 再発防止対応中
    - 完了

### 記載日
- 管理用。

### 案件名
- 管理用。

### 担当者
- 振り返り時の責任者。振り返り内容の記載と、振り返りMTG時に説明してもらう人。

## 事象項目
### 重篤度（S/A/B/C）
- 大きい障害〜小さい障害までめっちゃ多く発生し、ある程度小さい障害は振り返らない選択を取った。そのための指標。


### 事象サマリ
- パッとみて、「あ〜あの件ね〜」と分かる記載レベルで記載。


### 事象詳細（事象についてスクショ撮れる場合はスクショ必須）
- 事象が振り返り時に理解できるレベルで記載。


### 発生期間
- YYYY/MM/DD HH:mm 〜 YYYY/MM/DD HH:mm
- ユーザの影響度にも関わるので、明確にしておく。


### 発見経路
- ユーザ報告なのか、開発チーム内で気づけたことなのかを情報として知っておきたいため記載。


### 対応内容（PR、スクショなど、修正の前後が分かる物）
- どういった修正を行ったかを記載。
- 念のため修正内容の妥当性を確認したかったので書いてもらうようにした。

## 開発チーム側項目
### 直接的な原因（作り込み原因）
- 誰がいつ何をして障害の原因を作り込んだかを記載。

### 作り込み根本原因（なんでそうしたか？）
- 直接的な原因に記載ある事に対し、なぜそうしたのか、なぜ直接的原因が発生したかを記載。
- **なぜ？**を最低2回追求するようにした。


### 見逃し原因
- 確認フェーズで見つからなかった原因を記載。
- 実機確認をそもそもしなかったなど
- 仕様書の記載が分かりづらいなどの話であれば、仕様書のURLを貼る。


### どのフェーズで見つけるべきだったか？
- どの確認フェーズで誰が見つけるべきだったかを記載。


### 見逃し根本原因（なんでそうしたか？）
- 見逃し原因、どのフェーズでみつけるべきだったかに記載ある事に対し、なぜそうしたのか、なぜ見逃し原因が発生したかを記載。
- **なぜ？**を最低2回追求するようにした。


### 再発防止策
- 上記までの記載内容から、人に依存しない形で再発防止策を記載。
- 気をつけます、頑張りますとか根性論はNG。


### 再発防止期限
- nextやることを決めたら、それをいつまでにやるかを記載


### リーダー確認欄
- 上記までの内容を担保する人のサイン欄。


## QA(品質保証部)側項目
### 検出可能かどうか
- QA側だとどうしても検出が難しいケースがあるので、そもそも検出できるものかどうかを記載。

### 見逃し原因
- 開発チーム側項目同様

### どのフェーズで見つけるべきだったか？
- 開発チーム側項目同様

### 見逃し根本原因（なんでそうしたか？）
- 開発チーム側項目同様

### 再発防止策
- 開発チーム側項目同様

### 再発防止期限
- 開発チーム側項目同様

# 感想
- 個人的には振り返りMTG時に聞きたいことが前よか聞きやすくなり、MTG中にはだいたい根本原因と再発防止策が明確になった。
- 再発防止を推進する人のやる気がないと、良い再発防止策が出ても意味がなかった（愚痴）

# 参考
- 改めて誰か項目を公開してないかな？と思い調べていたら良い記事あったので参考文献として……  
[エンジニアなら知っておきたい障害報告&再発防止策の考え方](https://qiita.com/hirokidaichi/items/f9f4549c88aaf8b38bda)
AWS EC2 Amazon Linux2でDocker, Docker Composeをインストールする(忘備)

2019年10月現在で有効だった為、忘備録として残しておく

### EC2 への Docker インストール

```
[root@ip-172-31-46-207 ~]# sudo yum install -y docker
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
Resolving Dependencies
--> Running transaction check
Installed:
  docker.x86_64 0:18.06.1ce-10.amzn2

Dependency Installed:
  libcgroup.x86_64 0:0.41-15.amzn2  libtool-ltdl.x86_64 0:2.4.2-22.2.amzn2.0.2
  pigz.x86_64 0:2.3.4-1.amzn2.0.1

Complete!
[root@ip-172-31-46-207 ~]# sudo service docker start
Redirecting to /bin/systemctl start docker.service
[root@ip-172-31-46-207 ~]#
```


### ec2-user を docker グループに追加する

```
$ sudo usermod -a -G docker ec2-user
```


### EC2 への Docker Compose インストール(スーパーユーザー)

```
[root@ip-172-31-46-207 ~]# sudo -i
[root@ip-172-31-46-207 ~]# curl -L "https://github.com/docker/compose/releases/download/1.11.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   617    0   617    0     0   2346      0 --:--:-- --:--:-- --:--:--  2346
100 8066k  100 8066k    0     0  2894k      0  0:00:02  0:00:02 --:--:-- 3416k
[root@ip-172-31-46-207 ~]# chmod +x /usr/local/bin/docker-compose
[root@ip-172-31-46-207 ~]# exit
logout
[root@ip-172-31-46-207 ~]# docker-compose --version
docker-compose version 1.11.2, build dfed245
[root@ip-172-31-46-207 ~]#
```

###aliasを付与

```
[root@ip-172-31-46-207 ~]# alias d='docker'
[root@ip-172-31-46-207 ~]# alias dc='docker-compose'
```

参考サイト
https://qiita.com/shinespark/items/a8019b7ca99e4a30d286
direnvを使ってプロダクト毎に公開したくない環境変数を設定する

# direnvとは

> direnv is an extension for your shell. It augments existing shells with a new feature that can load and unload environment variables depending on the current directory.

シェルの拡張機能ということで、.envrcというファイルを生成し、そこに環境変数を記述すると、**このファイルがあるディレクトリ上でのみ記述した環境変数が有効になる**という代物です。

## インストール
homebrewで簡単にインストールできます。

```
$ brew install direnv
```

zshにパスを通します。

```.zshrc
## direnv
export EDITOR="vi"
eval "$(direnv hook zsh)"
```

読ませます。

```
source ~/.zshrc
```

環境変数を設定したいプロダクトのディレクトリに移動して以下のコマンドを打つとviが起動するので、設定したい環境変数を設定します。

```
$ direnv editor .
```

```.envrc
export GOOGLE_CLIENT_ID=******************
export GOOGLE_CLIENT_SECRET=*****************
```

このようにしてみてから、ディレクトリ内と外でechoを使って環境変数が適応されているのとされていないのを確認してみてください。
Laravel6でtymon/jwt-auth

# パッケージインストールでエラー
``composer require tymon/jwt-auth``で以下のようにエラーが発生しました。

```
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Installation request for tymon/jwt-auth ^0.5.12 -> satisfiable by tymon/jwt-auth[0.5.12].
    - Conclusion: remove laravel/framework v6.1.0
    - Conclusion: don't install laravel/framework v6.1.0
    - tymon/jwt-auth 0.5.12 requires illuminate/http ~5.0 -> satisfiable by illuminate/http[5.0.x-dev, 5.1.x-dev, 5.2.x-dev, 5.3.x-dev, 5.4.x-dev, 5.5.x-dev, 5.6.x-dev, 5.7.17, 5.7.18, 5.7.19, 5.7.x-dev, 5.8.x-dev, v5.0.0, v5.0.22, v5.0.25, v5.0.26, v5.0.28, v5.0.33, v5.0.4, v5.1.1, v5.1.13, v5.1.16, v5.1.2, v5.1.20, v5.1.22, v5.1.25, v5.1.28, v5.1.30, v5.1.31, v5.1.41, v5.1.6, v5.1.8, v5.2.0, v5.2.19, v5.2.21, v5.2.24, v5.2.25, v5.2.26, v5.2.27, v5.2.28, v5.2.31, v5.2.32, v5.2.37, v5.2.43, v5.2.45, v5.2.6, v5.2.7, v5.3.0, v5.3.16, v5.3.23, v5.3.4, v5.4.0, v5.4.13, v5.4.17, v5.4.19, v5.4.27, v5.4.36, v5.4.9, v5.5.0, v5.5.16, v5.5.17, v5.5.2, v5.5.28, v5.5.33, v5.5.34, v5.5.35, v5.5.36, v5.5.37, v5.5.39, v5.5.40, v5.5.41, v5.5.43, v5.5.44, v5.6.0, v5.6.1, v5.6.10, v5.6.11, v5.6.12, v5.6.13, v5.6.14, v5.6.15, v5.6.16, v5.6.17, v5.6.19, v5.6.2, v5.6.20, v5.6.21, v5.6.22, v5.6.23, v5.6.24, v5.6.25, v5.6.26, v5.6.27, v5.6.28, v5.6.29, v5.6.3, v5.6.30, v5.6.31, v5.6.32, v5.6.33, v5.6.34, v5.6.35, v5.6.36, v5.6.37, v5.6.38, v5.6.39, v5.6.4, v5.6.5, v5.6.6, v5.6.7, v5.6.8, v5.6.9, v5.7.0, v5.7.1, v5.7.10, v5.7.11, v5.7.15, v5.7.2, v5.7.20, v5.7.21, v5.7.22, v5.7.23, v5.7.26, v5.7.27, v5.7.28, v5.7.3, v5.7.4, v5.7.5, v5.7.6, v5.7.7, v5.7.8, v5.7.9, v5.8.0, v5.8.11, v5.8.12, v5.8.14, v5.8.15, v5.8.17, v5.8.18, v5.8.19, v5.8.2, v5.8.20, v5.8.22, v5.8.24, v5.8.27, v5.8.28, v5.8.29, v5.8.3, v5.8.30, v5.8.31, v5.8.32, v5.8.33, v5.8.34, v5.8.35, v5.8.4, v5.8.8, v5.8.9].
    - don't install illuminate/http 5.0.x-dev|don't install laravel/framework v6.1.0
    - don't install illuminate/http 5.1.x-dev|don't install laravel/framework v6.1.0
    - don't install illuminate/http 5.2.x-dev|don't install laravel/framework v6.1.0
    - don't install illuminate/http 5.3.x-dev|don't install laravel/framework v6.1.0
    - don't install illuminate/http 5.4.x-dev|don't install laravel/framework v6.1.0
    - don't install illuminate/http 5.5.x-dev|don't install laravel/framework v6.1.0
    - don't install illuminate/http 5.6.x-dev|don't install laravel/framework v6.1.0
    - don't install illuminate/http 5.7.17|don't install laravel/framework v6.1.0
    - don't install illuminate/http 5.7.18|don't install laravel/framework v6.1.0
..........
```

# 解決
``composer require tymon/jwt-auth ^1.0.0``

# 参考
[https://github.com/tymondesigns/jwt-auth/issues/1869](https://github.com/tymondesigns/jwt-auth/issues/1869)
Bashが人気だが、大規模システムにおけるBashと同等に求められるプログラム言語の話をしよう

Bashとは
---------------------------------------
「シェル」の一つのことであり、「シェル」とはLinuxやUNIXやMac等のOSに対して命令を実行する為のプログラムのこと。
特にBashスクリプトとは主にバックエンドにおける様々な処理の「自動化」を目的として使用される。
近年ではDevOps、AWS、GCP、オンプレでの実サーバー管理などにおいて一連の作業を自動化することに使われています。
Pythonなど他のスクリプト言語もあるのですがLinuxはBashが標準でインストールされているためLinuxやMacであれば初期設定なしで使えるという大きなメリットがあります。

Bashと同等に求められるプログラム言語とは
---------------------------------------
現場の経験的にBashと同等に求められるプログラム言語を紹介します。

<b>①バッチファイル（Batch File）<b>

MS-DOS、OS/2、Windowsでのコマンドプロンプト（シェル）に行わせたい命令列をテキストファイルに記述したもの。
これらはマイクロソフトが開発したシェルであり、大手SIerの中には認証用のサーバーとしてマイクロソフト製品を利用していることが多く（自分の経験的には認証としてはほぼこれ）
インフラや運用管理系の案件では開発用の作業端末もWindowsのPCであることが多いです。
WindowsOS環境があると各作業を`自動化＆効率化`できてめちゃめちゃ`人材として重宝`されます。

<b>②teratermマクロ<b>

フロントエンド系のエンジニアの方は無縁だと思われるのが意外とこのteratermマクロ。
OS側の環境変更やCLIにて運用管理業務を自動化します。こちらはLinux、WindowsやMacOSにも対応しており（その為の環境変更は必要だが）管理系業務を自動化したい場合は最高に使えます。
ちなみにことらのプログラムは管理業務を自動化したい効率性の高い企業は積極的に採用しています。
オンプレ側では`優秀なサーバーエンジニアとネットワークエンジニア`が積極採用しているイメージです。

<b>③VBA<b>

定型業務の自動化、省力化。
例えば、毎日更新されるデータを出社してからいちいち手入力し、手順を入力して計算させていた業務を、夜の間に自動でソフトウェアを起動し、データを読み込ませ、朝までに処理させておける。
またOfficeアプリケーションではマクロ記録/再生という操作手順の記録/再生機能を使って、プログラムに関する知識が少ないユーザーでも、ある程度の定型業務の自動化を行なえる。マクロはVBAコードの自動生成により実現されている。
ちなみにWebブラウザとも連携できるしOS系の運用管理業務も自動化できます。ExelVBAができるとエンジニア以外の業務の定例作業も自動化できるので現場で重宝されます。

最後に
---------------------------------------
フロントエンド系エンジニアの方にとっては触る機会が少ないと思われるのでキャリア形成において費用対効果が低いと思われますが、
DevOps系、バックエンド系やインフラエンジニア(サーバー、ネットワーク)においては近年自動化は注目されているので、上記キャリアを形成する可能性がある方はこの手の言語を習得する為に時間を費やす費用対効果はめちゃめちゃ高いです。
是非気になる方は習得してみましょう。
※近日中に__実際の使われ方やコードを公開__しますね！！
Macの「写真」(Photos)でサムネイルがうまく表示されない場合の対処法

Mac の「写真」(Photos) アプリで写真のサムネイル(プレビュー)が表示されなかったり、違う写真のサムネイルが表示されるなどの現象の対処法です。
環境：macOS Mojave 10.14.6, Photos.app 4.0
**追記あり 2020/01/14** macOS Catalina 10.15.2

この手順を試す前にこちらの Apple 公式の記事もお読みください。

**Mac の写真 App に問題がある場合 - Apple サポート**
https://support.apple.com/ja-jp/HT204967

**写真ライブラリの修復ツールの使い方 - Apple サポート**
https://support.apple.com/ja-jp/HT204967

# 手順

※ 写真アプリが作業中にバックグラウンドで動作することを防ぐため、空の新規ライブラリを作成してシステムライブラリに設定し、空のライブラリを最後に使用したライブラリとしておく方が安全かもしれません。

※ 画像を回転→逆回転させることによってもサムネイルが再生成されます。枚数が少ない場合(数枚〜数十枚)にはこちらの方がリスクが低く早いと思います。

> :warning: **作業前に必ず写真ライブラリの完全なバックアップを取り、自己責任で実行してください。**

1. 写真アプリを閉じる
2. Finder から写真ライブラリのファイル (`〜.photoslibrary`) を右クリックし「パッケージの内容を表示」をクリック
3. `Resources` フォルダ内の `media`, `proxies`, `segments` フォルダを移動または名前を変更 (末尾に `_old` をつけるなど)
  > **追記 2020/01/14**
  Catalina では `Resources` フォルダ内の `derivatives`("派生物") に変わったようです。
  いずれの場合にしても必ず完全なバックアップを取ってから行ってください。

4. 完了

この作業を行うと、以前に手動で回転させた写真の向きが元に戻る可能性がありますが、手動で修正してください。

うまくいけば写真アプリを開くとすべての写真のサムネイルが消え、再生成が始まります。再生成にはライブラリのサイズにより数十分〜数時間かかることがあります。
galliumos備忘録

初期設定だと有線でつながらなかった

以下のフォルダが空だったのでconfig.yamlを作成
/etc/netplan/

```yaml:config.yaml
network:
  version: 2
  renderer: NetworkManager
```

反映させる

```
netplan apply
```

この状態でNetworkMangerを再起動

```bash
systemctl restart NetworkManger
```

netplanのconnectionが自動作成されない場合は手動で作る

ifupdownのinterfaceに対象のインターフェース(enp1s0など)が書かれていると、netplanでそのインターフェースが使えないことも分かった。
その場合は削除


#DNS無効化
```bash

sudo bash
systemctl stop unattended-upgrades.service avahi-daemon.socket avahi-daemon.service systemd-resolved.service
systemctl disable unattended-upgrades.service avahi-daemon.socket avahi-daemon.service systemd-resolved.service
```
git initして git add * しようとしたら下位に既にgitがあったので、統合したい。


-----
ex) ~/myprojects/<新しく作ったgitのルート>/   でgit init して　git add * したら、~/myprojects/<新しく作ったgitのルート>/AAA/ に既にgitがありますよと言われた。
これを、「AAA」のgitをなくして「新しく作ったgitのルート」のgitに統合したい。

-----

##戦略
git subtree addを使えば他のgitをサブディレクトリにくっつけられるのでこれを使う。ただ、今回は既にサブディレクトリがある状態なので、そのままだと怒られる。
なので、一旦隣にリネームまたはどこかに移動してから行う。



###ここから下の前提
既にあったフォルダをAAAとする。新しくgit initしたルート直下にあるとする。
<新しく作ったgitのルート>にいるものとする。#cd <新しく作ったgitのルート>へのパス



### git add でステージしてしまったものを綺麗にする 
git addしていなければもうちょっと下からで良い。

```sh
git rm -rf --cached * 
```

ステータスを見ると

```sh
 git status
```

```sh

On branch master

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	AAA/
```	

###一旦コミットする。

```sh
git commit --allow-empty --allow-empty-message -m ""
```
など

--------

*既に戦略どうりにするつもりでgit add などでステージしてない場合はここからでよい。*

###とりあえず名前を変える
```sh
mv AAA AAA_
```

###リモートに登録(XXX は作業用の適当な名前)

```sh
git remote add XXX  AAA_/
```

確認

```sh
git remote 
```

```sh
XXX 
```
###履歴ごと統合
```sh
git subtree add --prefix AAA XXX master
```

### 掃除

いろいろチェックして安心したら AAA_を消しましょう。（心配ならどこかに移動させておく）

```sh
rm -rf AAA_
```

リモートも消します

```sh
git remote remove XXX
```

これであとは普通にできまっせ。


例えば

git add *

など

何か素敵なことがしたい人は、git subtree add --helpなど読む。



---------

今回
git merge
git fetch
git read-tree
git subtree merge
は使わなかった。
【IE】selectboxをaタグで囲うとEnterで選択できない


![スクリーンショット 2019-10-02 10.57.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457046/d9d5e200-bf7b-c0b0-832f-c6be9127eea2.png)
Enterで決定できない！！

## 解決方法は？

1. aタグで囲うのをやめる。
2. そもそもIEだけだし致命的ではないので無視。

とはいえ、IEユーザーの利用が多い箇所では少し不便です。
selectboxをaタグで囲うパターンはあまり無いですが、心当たりがある場合は直しときましょう！

【追記】
@rryu さんに教えてもらい、そもそもaタグの中にselect要素を入れることは不適切だということが分かりました。不適切な構造且つバグも発生するので今後は見つけ次第修正します！
参考：https://developer.mozilla.org/ja/docs/Web/HTML/Element/a#Properties
【AWS】ユーザーアカウントに対して多重認証を行う

#概要
AWSは多重認証を推奨していまして、ルートユーザーアカウントに多重認証を行いました。
「ルートユーザーアカウント」で操作していますが、IAMユーザーアカウントに対しても、操作は同じですので、参考にしてください。


#多重認証の設定
- マネジメントコンソールでログイン
- 右上のアカウント名をクリック、[マイセキュリティ資格情報]をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235774/039869ab-19cb-f45b-b59c-6d13412b23b6.png)

- ルートユーザーアカウントの場合、以下の注意メッセージが表示されます。「セキュリティ保護の観点からIAMユーザーで操作しなさい。」と
いう注意喚起ですね。
- [Continue to Security Credentials]を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235774/53aefb6e-92a8-b93d-2aa8-7b05b020a94c.png)


- セキュリティ認証画面が表示されるので[多要素認証]を選択し、[MFAの有効化]ボタンをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235774/5dc68a5c-1775-fd85-2ed8-d545cb71bfe7.png)

- IAMユーザーの場合、ルートユーザーと画面レイアウトが若干、異なっているので、以下提示しておきます。
＜IAMユーザーの場合＞
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235774/471edcc0-5669-8289-14c2-efd8215abfe2.png)


- 今回はYubicoを使用しますので、U2Fセキュリティキーを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235774/e036a020-4507-54b8-91fb-80afa9f15d2b.png)

- YubicoのセキュリティキーをPCに差し込んで、セキュリティキーにタッチし、処理を続行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235774/42de8b0d-e5a5-93bb-04e4-8d3713de0f8c.png)

- 設定が完了しました。
- これで、次回のログイン時から、アカウント情報入力後、セキュリティーキーを求められるようになります。
- 多重認証成功しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235774/76ae0010-89f1-ab9d-69ff-9b77afe6a5db.png)


#多重認証の設定解除

- 認証設定と同様に、右上のアカウント名をクリック、[マイセキュリティ資格情報]をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235774/6a653739-9aab-a70a-6190-18f465fd9389.png)

- セキュリティ認証情報画面で設定したデバイスの[管理]リンクをクリック
- 以下は、ルートユーザーの場合の見た目です。ISMユーザーアカウントは若干異なっています。[多重認証の設定]の画面レイアウトを参照ください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235774/02cea307-cc7a-fd2c-caae-e0395ca31fa3.png)

- [削除]を選択し、[削除]を実行します。以上です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235774/c09d4d02-16db-6465-8a72-60b189c6c7d3.png)
C言語の復習（計算）

#ゆっくり復習するために自分で考えてアウトプットしていくよ。
リハビリに適当に足し算引き算してみてるか。

```c:b.c

#include <stdio.h>

int main(void)
{
	int aa, bb, cc, dd, ee, ff;

	aa=50;
	bb=5;

	cc = aa + bb;
	dd = aa - bb;
	ee = aa * bb;
	ff = aa / bb;

	printf("aaの値は%dですね～ \n", aa);
	printf("bbの値は%dですね～ \n", bb);
	printf("aa + bb の値は%dですね \n", cc);
	printf("aa - bb の値は%dですね \n", dd);
	printf("aa * bb の値は%dですね \n", ee);
	printf("aa / bb の値は%dですね \n", ff);
	return 0;
} 
```
これをコンパイルすると
<img width="430" alt="tasi.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292512/59807722-b20b-afb0-8368-7f2afd15af4a.png">
ですね～はい予想通り。
【Swift】WKWebViewでピンチによるズームを無効にする

```swift
import UIKit
import WebKit

class WebViewController: UIViewController {

    @IBOutlet weak var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()
        guard let url: URL = Bundle.main.url(forResource: "index", withExtension: "html") else { return }
        webView.scrollView.delegate = self
        webView.loadFileURL(url, allowingReadAccessTo: url)
//        webView.scrollView.pinchGestureRecognizer?.isEnabled = false
//        ↑↑↑この時点で書いてもpinchGestureRecognizerがnilなので意味ない
    }
}

extension WebViewController: UIScrollViewDelegate {
    func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
        scrollView.pinchGestureRecognizer?.isEnabled = false
//      ↑↑↑delegateの中で書いてやると良い
    }
}
```
Effective Java 項目25 配列よりリストを選ぶ 前半

# 配列よりリストを選ぶ

配列とジェネリック型の違いとして、

- 配列は共変であり、ジェネリック型は不変である
- 配列は具象化（実行時にその要素型を知っていて、強制すること）だが、ジェネリックスはイレイジャ(コンパイル時にのみ型制約を強制し、実行時に型情報を廃棄すること)

E、```List<E>```、そして、```List<String>```は、技術的には具象化不可能型(nonreifiable type)として知られています。
直感的に言えば、具象化不可能型は、その実行時の表現がコンパイル時の表現よりも情報が少ない型です。
具象化可能な唯一のパラメータ化された型は、```List<?>```や```Map<?, ?>```などの非境界ワイルドカード型です。非境界ワイルドカード型の配列の生成は許されていますが、稀にしか有用ではありません。
ジェネリック配列生成の禁止は、煩わしいかもしれません。例えば、一般にジェネリック型は、その要素型の配列を返すことが不可能です。
可変長引数のメソッドをジェネリック型と組み合わせて使用する場合、困惑する警告が出る可能性も意味しています。それは、可変長引数のメソッドを呼び出すと、必ず可変長パラメータを保持するために配列が生成されるからです。
（下記のコードでいうと、argsがそれに該当する）

```
static int sum(int... args) {
    int sum = 0;
    for (int arg : args) {
        sum += arg;
    }
    return sum;
}
```

この配列の要素型が具象化可能でなければ、警告が出ます。その警告を抑制することとAPIでジェネリックスと可変長引数を混在させないようにすること以外に、警告に対してできることはほとんどありません。

ジェネリック配列生成エラーとなる場合には、最善の解決策は、配列型```E[]```よりはコレクション型```List<E>```を大抵は使用することです。
何らかのパフォーマンスや簡潔さを犠牲にするかもしれませんが、代わりに、より良い型安全性と相互運用性を得ます。