OmniAICreator/Qiita-1.07M huggingface dataset:
Google Domainsでのドメイン取得・購入方法

#はじめに
今までお名前COMでしかドメインを取得したことなかったので、GCPなどの利用も見越してGoogle Domainsでドメインを取得・購入してみました

#Google Domainsについて
公式 
https://domains.google/intl/ja_jp/

## できること
- ドメインの取得
- ネームサーバはCloud DNSが利用可能
- Whois代理
- DNSSEC対応
- G Suite や Blogger などのGoogleサービスとの連携が簡単
など、基本的なレジストラの機能からGoogleをメイン使うのであれば連携が簡単なところもメリットです。

## 用意しておくもの
- 候補のドメイン
- クレジットカード
- Googleアカウント

Gsuiteと同時申し込みもできるようですが、今回はドメインのみを取得します。


# ドメインを取得・購入してみる
##### ・公式サイトにアクセスし、右上の「マイドメイン」をクリック。

https://domains.google/intl/ja_jp/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541506/52a51403-b5c8-59ff-ffbb-6f24df7ceda9.png)

##### ・ドメイン検索の画面になるので、候補のドメイン名を検索。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541506/b0356237-9611-653a-eaca-16603be7d433.png)

##### ・完全一致のほか、候補も多数出てきます。購入したいもののカートボタンをクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541506/9a194ba6-3170-51ea-3857-6947d69a86f1.png)

右上のカートボタンに追加されるので、カートボタンをクリックすると支払い画面に遷移します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541506/01d40da3-f447-8035-b2ab-bae35b4704d3.png)

##### ・カートの内容の確認です。
**プライバシーの保護が有効です。**
ドメインのwhois情報を代理公開の有無です、有効にしておきます。
**自動更新オン**
ドメインは1年の期間制のため、永続的に利用を検討もしくは忘れっぽい方は有効にしておきましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541506/55abc07a-4cd5-0140-e764-aecfee87ec5f.png)
**清算**をクリックします。

##### ・購入手続き
お客様の情報はGoogleへの情報ではなく、ドメインを管理するICANNへの登録情報です。
個人の名前でもOK。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541506/015ac558-0c5b-4127-4b28-5e40cd1ce485.png)

支払い方法を入力します。カード払いです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541506/785f7aaf-811a-c8f4-b713-0f67f5843a40.png)

**「請求先の住所」**の欄は郵便番号のみの入力でした。

**購入**をクリック。

##### ・最終確認
購入の最終確認です。日本の税金10%が加算され、合計1,540円でした。
内容に問題なければ**購入**をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541506/b6c62ab4-8a70-bfde-6b86-5100063036b7.png)

##### ・購入確認
Google Domainsの管理画面に遷移します。
しかし、まだドメインのメールアドレス確認（承諾）ができていません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541506/61dd791d-270d-6770-525b-13ce92bc76be.png)

メールを見てみると3通きていました。承諾に必要な情報は
**「重要なお知らせyourdomain.comのメールアドレスをご確認ください」**
のメールです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541506/2032276c-5c24-3a9d-6295-31a119dfe2af.png)
**メールアドレスを確認**をクリックして承諾します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541506/ed9f5c62-ae09-7495-2570-0fa814c88012.png)

メールアドレスの確認が実施され、これで作業は完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541506/1c2c8660-662e-6d11-9439-0a1a06650b1c.png)

# whoisはどうなっているか
whoisはどのように公開されているか気になったのでさくらさんのwhois検索にて確認。
https://domain.sakura.ad.jp/whois/

レジストラが「Google LLC」で登録されていました。
**状態**はドメインの種類によって変わりますが、comの場合基本は移管禁止のロックがついているようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541506/5b1312f6-f101-d24f-a00e-5d5335555703.png)

# まとめ
- UIが簡単でスムーズ
- ドメイン移管、DNSサービス、Webサービスもあるので簡単なWebサイトであればGoogleで一括で作成できます
- メールについては転送という機能がありますが、G Suiteの利用がいいでしょう。
Angularのtranslateでの$filterの使い方

Angular1での多言語対応における自分用メモです。
#$filterを使いたい
テンプレートでfilterを使用したいときは以下のように使います。
この$filterによって、「2000」を「2,000」とします。

```
<span>{{price | number}}</span>
```


#翻訳をしてみる
JSONをまずは用意。日本語はja.json、英語はen.jsonなどとします。

```
{
	"TEST": "It will be {{amount}} yen"
}
```

テンプレ側を用意。

```
<div ng-bind-html="'TEST' | translate"></div>
```

ちなみにこの結果はこのようになります。

`It will be yen`

変数を適用したい場合には、テンプレ側に記述します。他にやり方はありますが、ここではこの場合での$filterを適用したいと思います。

```
<div ng-bind-html="'TEST' | translate:'{amount: "price"}'"></div>
```

`It will be 2000 yen`

ここに$filterのnumberを適用したい。となった時、テンプレ側に記述してもやり方が悪いのか適用されません。
調べていてもよくわからなかったのですが、なんか閃きました。JSON側です。

```
{
	"TEST": "It will be {{amount | number}} yen"
}
```

`It will be 2,000 yen`

これで色んなfilterを適用できるぞー！

#参考URL
https://ryotah.hatenablog.com/entry/2017/03/06/210555
Imgur APIを使って画像を匿名アップロードする（Python使用）

## ユーザ登録する
https://imgur.com/register

## アプリケーションを作成
https://api.imgur.com/oauth2/addclient
<img width="695" alt="スクリーンショット 2019-12-08 0.16.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215784/bf819b45-75b3-e16c-4b93-b7ec8acc0202.png">

- Application name: アプリケーション名
- Application name: 匿名アップロードだけできれば良い場合は`Anonymous usage without user authorization`を選択
- Authorization callback URL: 匿名アップロードの場合は関係ない。適当なURLを入力しておく。
- Application website (optional): 省略可
- Email: 適当なメールアドレス
- Description: 省略可

Submitすると`Client ID`と`Client secret`が払い出される。が、匿名アップロードでは`Client ID`さえあれば良い。

## 投稿
### ローカルにある画像をアップロード

```python
client_id = 'YOUR CLIENT ID'
image_path = 'path/to/your/image'

import requests
headers = {
    'authorization': f'Client-ID {client_id}',
}
files = {
    'image': (open(image_path, 'rb')),
}

r = requests.post('https://api.imgur.com/3/upload', headers=headers, files=files)

import json
print(json.loads(r.text)['data']['link'])
```

### 既にWEB上にある画像をアップロード 

```python
image_url = 'YOUR IMAGE URL'
client_id = 'YOUR CLIENT ID'

import requests
headers = {
    'authorization': f'Client-ID {client_id}',
}
files = {
    'image' : requests.get(image_url).content
    }
r = requests.post('https://api.imgur.com/3/upload', headers=headers, files=files)

import json
print(json.loads(r.text)['data']['link'])
```
「"A"..."Z"」でアルファベットの配列を取得する

#経緯

勉強のコードを動かしてると理解が合ってるか確認するためにA~Zの文字をループで回して試したくなることがあって

```swift
func hoge(_ v:String){
 //ここで書いた処理が合ってるか試したい
}

let test = "ABCDEFGHIJKLMNOPQRSTUVWXWZ" // <- なんかめんどい
for c in test{
  hoge(c)
}
```

```swift
for c in "A"..."Z"{ // <- こうしたい
  hoge(c)
}
```

C言語の時ならchar型に++でループさせてたなあ...


#やってみた

```Stirng+extension.swift
infix operator ...
extension String{
    static func ...(left: String, right: String) ->Array<Character> {
        return ((left.unicodeScalars.first!.value) ... (right.unicodeScalars.first!.value)).map { Character(UnicodeScalar($0)!) }
    }
}
```

```test.swift
let alphabets = ("a"..."z") + ("A"..."Z")
print(alphabets)
/*
["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", 
"k", "l", "m", "n", "o", "p", "q", "r", "s", "t", 
"u", "v", "w", "x", "y", "z",
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", 
"K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", 
"U", "V", "W", "X", "Y", "Z"]
*/
```

`1...10`と違ってClosedRange型じゃないけど...

#結論
`unicodeScalars`って初めて知ったよ
いつもプログラミングするときに考えること

# はじめに
後輩とかに、「どんなこと考えてプログラミングしてるんですか？」みたいなことを聞かれたりすることが出始めたので、現状での考え方を書いておく。
あくまで、独学なので実際はもっといい方法があるかもしれない。
(その時は、ぜひともコメントで教えてもらいたい！！)

# 基本的な手順
先に、以下に手順だけ載せておく。

1. 使用用途の決定
2. 使用するものの決定(サーバの数とか)
3. ログの取得方法
4. 使用するAPIの決定
5. プログラムの構想決定
6. プログラム作成
7. 動作テスト

# プログラミングをする前に
まずプログラミングをする前に、全体的な構想や設計をしたりする必要がある。
これは、かなり重要だと個人的に思う。

なぜなら、構想や設計の時点で破綻していた場合、実装時には手遅れになっている場合が多いからだ。

確かに、具体的な構想を練ったり、設計書を書いたりするのはとても手間がかかり、時間もかかる。

しかし、それを抜きにしていきなり実装ができるのは、熟練のエンジニアか天才くらいだと(自分は)思う。
特に、あまり開発経験がない人に関しては、絶対的に構想や設計をちゃんとしたほうが良いと思う。
なぜなら、実体験を踏まえると、あまり開発経験がない人の場合、まず「**なにをしたらよいかがわからない**」という問題にぶつかる。

その場合、イメージが大雑把であることが大半であると思う。
そのため、構想を練り、設計をしっかりと可能な限り細かく行うことで、どのような手順を踏めばよいのかが、なんとなくわかるようになる(はず)。

なので、「**なにをしたらよいかがわからない**」という人は、可能な限り細かい設計をしてみるといいと思う。

# 補足
ちなみに、構想(個人的にはアイデアだしに近い)についてだが、これはかなり大雑把でもいいと思っている。
どういうことかというと、「**アイデアは質よりも量**」だからだ。
より良いアイデアを出そうといくら考えても、でないことのほうが大半だ。

なのであれば、ありふれた簡単なものであっても、ひたすら可能ならノンストップでノートに書き続けたほうがいい。
出たアイデアは、その時点では使い物にならなくても、別の機会に利用できるかもしれないし、組み合わせてみたらとても素晴らしいものになるかもしれない。
なので、パッと思いついたものは迷わずメモしたりするのがいいと思う。

あと、個人的に構想を練ったり、仮の設計をする際(草案を作成する際とか)にはノートや紙に書くといいと個人的には思う。
自分だけかもしれないが、どうしてもスプレッドシートやWordに書こうとすると、きれいに書こうとしてなかなか作業が進まないことがあり、それに比べて捨てる予定の紙の裏に書くとかなりのスピードで作業が進むのだ。

# おわりに
こうした、ちょっとしたテクニック(?)は、かなり個人差があったり、我流の方法があったりするので一概にいいとはいえないが、役に立つのであれば幸いです。

また、最初にも述べた通り、基本的に独学でこうしたことを学んでいるので、「こういう方法もあるんだよー」って人がいましたら、コメントで教えてくれると、片っ端から試しますのでよろしくお願いします。
VSCodeにvenv環境を認識させる方法とそのメリット

# 環境
* macOS
* VSCode 1.40.1
* Python3.6.0

# VSCodeにvenv環境を認識させる
```.vscode/settings.json``` に下記を追加（下記は```python -m venv .venv```で仮想環境を作成した場合）

```.vscode/settings.json
    "python.venvFolders": [
        ".venv"
    ]
```

VSCodeで```Command+Shift+P```で「Python: インタープリターを選択」を選択し、表示された一覧から上記で設定した```.venv```のPython（./venv/bin/pythonなど）を選択する

# メリット
Linterが仮想環境にインストール済みのライブラリを認識してくれるため、「インストール済みなのにNot found警告が出る！」なんてことにならない。
#Windows10でAnaconda使用時にpip installでエラーが出るときの解決方法


環境
Anaconda 3.74
windows10

コマンドプロンプトからpip install [パッケージ名]としても

WARNING: pip is configured with locations that require TLS/SSL, however the ssl module in Python is not available.

と出てインストールができず困ってしまった時の解決方法になります。

#解決手法
Anaconda Promptを開き、
conda install openssl
を入力します。これでpipによるインストールが可能になります。

dllが壊れているなどの情報もありましたが、ネットに転がっているそちらの情報は私のケースの場合は適用できませんでした。
Rails 新規アプリケーションの作成①


##書かれていること
- アプリケーションの作成とRailsの動き
1.Rails newコマンド
2.DB作成
3.ルーティングの設定
4.コントローラーの作成
５.ビューの表示

- 備考
 - Gemとは？
 - バージョン確認
 - リクエストとは？
 - 全体流れ
- 終わりに

##アプリケーションの作成とRailsの動き
####1.Rails newコマンド

- ```cdでアプリを作成したいディレクトリへ移動```し以下を入力


```rails:ターミナル
rails new 作りたいディレクトリ名 -d　mysql
```
 -d mysqlはデータベースに作成するときの種類をmy sqlにするという指示 

#####エラーが出た時


- ```VSC```で作成したディレクトリを開く
- Gemfileの編集(mysql２と書いてある右側のバージョンを変更する)

```rails:Gemfile
gem 'mysql2','0.5.3'  #エラー
↓
gem 'mysql2','0.5.2'　#バージョンを下げてみる
```
- Gemlockファイルを削除し、ターミナルで```bundle```する
- Gem再インストール完了(gemlockファイルが新たに作られる)

####2.DB作成
```rails:ターミナル
rake db:create
```
####3.ルーティングの設定
```rails:routes.rb
get 'tweets' => 'tweets#index'
```
- リクエストを記述

####4.コントローラーの作成
```rails:ターミナル
rails g controller コントローラー名
```
- 関連ファイルも同時に作られます

#####コントローラーに記述
```rails:コントローラー名_controller.rb
###省略###
def index
end
```
- ビューにあるコントローラー名と同名のディレクトリにあるindex.html.erbを呼んでねの意味

####５.ビューの表示
```rails:index.html.erb
（表示したいものを書く。例えば）
こんにちは！
```

##備考
######Gemとは？
- GemとはRubyで様々なことができるように書かれたプログラムのまとまり
- GemとはRubyのバージョンごとに管理をされている

######バージョン確認
- 今使っているRubyのバージョン確認（$ruby -v）
- 自分のPCで使えるRubyのバージョン確認（$rbenv install --list）
- mysqlのバージョン確認（＄mysql --version）

######リクエストとは？
- HTTPメソッドとパス（URL）の組み合わせのこと

GET "tweets"=>"tweets#index"
(HTTPメソッドGETの”tweetsパス”で＝＞”tweetsコントローラの＃indexアクションが動くよ”)という意味。

#####全体流れ
リクエスト → ルーティング → コントローラー → ビュー

#####参考ページ
[おさえておきたいRubyのバージョンごとの違い・切り替え方法まとめ](https://www.sejuku.net/blog/12327)
[MySQLのバージョン確認方法](https://qiita.com/haxpig/items/b270acb9550efddd5fe5)


##終わりに
３〜５は流れを見るために書いた記述なので（例）を載せていると思って見てください。
```resources```などを使っていった方が複雑なルーティングはスッキリまとまるかと思います。


プログラミング始めて２ヶ月半、何も身になっていないような・・・
アウトプットのために（学習記憶を喪失しないため）qiitaへ投稿始めます。
プログラミングはど素人なため、記述内容で誤りなどございましたら、ご指摘いただけると幸いです。
今後、HTML,HAML,CSS,Rails,JS（Jquery）などまとめる予定です。
（こんなにできるかな・・・）
pythonのAI,swiftでiosアプリ制作なんかもできたら。
Linux標準教科書その4

## Linuxのユーザアカウント
Linuxを使用するときユーザアカウントが必要となります。ユーザによってLinuxというシステムの利用権限を与えることでファイルやディレクトリ、任意のプログラムやシェルスクリプトなどの参照・編集する権限や実行権限を管理することができます。

## ユーザ
メモリやファイルなどのリソースを操作権限の最小単位。

## グループ
複数のユーザの権限をまとめて扱うためのもの。ユーザは必ず一つ以上のグループに属していて、所属するグループのことをプライマリグループと呼ぶ。

## rootユーザ
利用に制限がない特別なユーザ。システムの変更やプログラムのインストールや削除、ユーザを作成、削除ができる。アクセス権に関係なく全てのユーザのディレクトリへのアクセス、コンテンツの読み書きが行えるので管理を厳格にする必要がある。

## suコマンド
ログイン中のユーザが一時的に別ユーザになるためのコマンド。ユーザを指定しないで実行するとrootユーザになる。rootユーザに複数人で使用すると履歴にrootユーザの履歴しか残らないため誰がどんな作業したかわからなくなる。一般ユーザからrootユーザに切り替えるとrootユーザとして作業を開始した時刻が残る。

## sudoコマンド
スーパーユーザ(root)権限でコマンドを実行できる。suコマンドでユーザを切り替えることなく、root権限で設定やプログラムを実行できる。
[RSpec][model] RSpecモデルテストの書き方例

# はじめに

Rspecの中で、自分がよく使うmodelのテストの例をまとめます。


## 有効かどうかのテスト

```ruby
it "メール、フルネーム、ユーザーネーム、パスワードがあれば有効な状態であること" do
        user = User.new(email: "example@test.com",
                        user_name: "test_user_name",
                        password: "test_password",
                        password_confirmation: "test_password")
        expect(user).to be_valid
end

```

`expect(user).to be_valid`を使う

## validation presence:trueのテスト

```ruby
 it "ユーザーネームがない場合、ユーザー登録に失敗すること" do
        user.user_name = ""
        user.valid?
        expect(user.errors.full_messages).to include "ユーザーネームを入力してください"
 end

```
一度`valid?`かどうか確認し、エラーを表示させてそのエラー文の確認しております。



## validation  uniqueness: true のテスト

```ruby
it "ユーザーネームが重複した場合、ユーザー登録に失敗すること" do
        create(:user)
        existing_user = build(:another_user, user_name: "test_user_name")
        existing_user.valid?
        expect(existing_user.errors.full_messages).to include "ユーザーネームはすでに存在します"
end

```
FactoryBot.createの「Factory」は省略できるようにしております！
（方法について、また記事を書こうと思います）
userを先に作り、そのあとで同じ名前のuserを作り、エラーが出ることを確認しています。

## emailの　format: { with: VALID_EMAIL_REGEX }のテスト

```ruby
it "メールアドレスのフォーマットが正しくない場合、ユーザー登録に失敗すること" do
        user.email = "exampletestcom"
        user.valid?
        expect(user.errors.full_messages).to include "メールアドレスは不正な値です"
end

```

正しくないemalを書き、エラー文を確認します。

## パスワード更新時のエラー

パスワードと確認用パスワードが一致しない時のテスト

```ruby
 let(:user) { create(:user) }
 let(:current_password) { user.password }

      context "パスワードと確認用パスワードが一致していない場合" do
        it "Validationエラーが発生すること" do
          expect do
            user.update_password(current_password, "password", "buzzword")
          end.to raise_error(ActiveRecord::RecordInvalid)
          expect(!!user.reload.authenticate("password")).to be false
          expect(user.errors.full_messages).to include "再入力パスワードとパスワードの入力が一致しません"
        end
      end

```

expectの部分が複雑なのですが、パスワードを暗号化しているためこの書き方にしています。

入力したパスワードと現在のパスワードが正しくない場合

```ruby
    context "現在のパスワードが正しくない場合" do
      it "NoCurrentPasswordErrorが発生すること" do
        new_password = "updated_password"
        expect do
          user.update_password("buzzword", new_password, new_password)
        end.to raise_error(Exceptions::NoCurrentPasswordError)

        expect(!!user.reload.authenticate(new_password)).to be false
      end
    end

```
こちらはflashでエラーが出るようにしているのですが、その確認の仕方が分からなかったので、
エラーが出ることと、更新されていないことを確認しています。

以上です！
間違っている部分やもっとこうしたほうがいいよ！という場所あればぜひ教えてください！！^^
vim-lsp の pyls が重いのをなんとかする

# vim-lsp と pyls

Vim の Python 入力補完を jedi-vim から vim-lsp に乗り換えてみたが、動作が重い。
しかも Python ファイルを編集し始めてしばらくすると、編集しているファイルとは全然関係のない、OneDrive に置いてある.py ファイルの自動ダウンロードが頻発する。

プロセスをみると pyls.exe のサブプロセスで pylint がCPU全開でメモリをバカ喰いして走っていた。
こいつがいろんな場所の .py ファイルを触りまくるらしい。何してくれているの・・・。

どうやら pyls のプラグインの pylint が自動起動して意図しない動作をしているようだ。
こういうのがデフォルトになっているのは何だかなぁ。(自分の設定・環境のせいかな？)

プラグインは```enabled```(enable じゃなくて enable<font color="red">d</font>) を設定すれば無効化できるようなので、補完用の jedi だけ残して停止させることにした。
これでなんとか使えそうだ。

```vim:.vimrc
if executable('pyls')
    call lsp#register_server({
        \ 'name': 'pyls',
        \ 'cmd': { server_info -> ['pyls'] },
        \ 'whitelist': ['python'],
        \ 'workspace_config': {'pyls': {'plugins': {
        \     'mccabe'              : { 'enabled': v:false },
        \     'preload'             : { 'enabled': v:false },
        \     'pycodestyle'         : { 'enabled': v:false },
        \     'pydocstyle'          : { 'enabled': v:false },
        \     'pyflakes'            : { 'enabled': v:false },
        \     'pylint'              : { 'enabled': v:false },
        \     'rope_completion'     : { 'enabled': v:false },
        \     'yapf'                : { 'enabled': v:false },
        \
        \     'jedi' : {'extra_paths' : [] },
        \     'jedi_completion'     : { 'enabled': v:true, 'include_params': v:true },
        \     'jedi_definition'     : { 'enabled': v:true, 'follow_imports': v:true, 'follow_builtin_imports': v:true },
        \     'jedi_hover'          : { 'enabled': v:true },
        \     'jedi_references'     : { 'enabled': v:true },
        \     'jedi_signature_help' : { 'enabled': v:true },
        \     'jedi_symbols'        : { 'enabled': v:true },
        \ }}},
        \ })
    autocmd FileType python setlocal omnifunc=lsp#complete
endif
```

余談だけど、vim-lsp も補完は jedi なんだね。
自作言語HexBfについて

# はじめに
今回は、1年前にBrainf*ck言語にはまったときに、自作したBrainf*ck言語の亜種についてや、自作した経緯について書きます。
仕様については、[HexBFのリポジトリ](https://github.com/shouta02jp/HexBF-from-PHP)のREADMEに記載しています。
(一部確定ではない部分があるため、気分が乗ればC言語で実装してみようと思っています。)

# HexBFについて
まずは、とにかく自作した言語について書いておくのがいいと思ったので書きます。
まず、自作した言語名ですが、**HexBF**です！
Hexは16進数から、BFはBrainf*ck言語からとりました。
(某FPSゲーではないです笑)
仕様については、先ほども述べた通り、[HexBFのリポジトリ](https://github.com/shouta02jp/HexBF-from-PHP)のREADMEに記載しています。
なので、ここでは軽く本家との違いを軸に書いていきたいと思います。

まず、本家Brainf*ck言語の仕様は、[このサイト](http://www.muppetlabs.com/~breadbox/bf/)で解説されていますが、ざっくりまとめると以下の通りです。

|入力|説明|
|:-:|:-:|
|+|ポインタが指す値を1byteインクリメント|
|-|ポインタが指す値を1byteデクリメント|
|<|ポインタのインクリメント|
|>|ポインタのデクリメント|
|.|ポインタが指す値をASCIIコードに従って出力|
|,|入力した値をASCIIコードに従って変換しポインタが指す値に代入する|
|[|ポインタが指す値が1以上(true)であるうちは`]`で囲った範囲を繰り返す|
|]|`[`に戻る|

そして、自作したHexBF言語の仕様は以下の通りです。
([GitHubのREADMEから引用](https://github.com/shouta02jp/HexBF-from-PHP/blob/master/README.md))

|入力|説明|
|:-:|:-:|
|+|指定アドレス値をインクリメント|
|-|指定アドレス値をデクリメント|
|<|指定アドレスを一桁左にずらす|
|>|指定アドレスを一桁右にずらす|
|.|全体の値をASCIIコードで文字列に変換し、出力|
|[|指定アドレス値が0出ない場合、]まで実行|
|]|指定アドレス値が0だった場合、]に戻る|

* <,>をしたとき、指定アドレスはループするようになっています。

例）```<<+```の値は、0x01
　　```>+```の値は、0x10となります。

はい、基本的にはいっしょですね笑
では、違う部分はどこかといいますと、例と書いてある部分ですね。
ここがHexBFの最大の特徴です！
Brainf*ck言語ではメモリは無制限(たしか本来は無制限なはず)なのに対し、HexBFでは2桁の16進数で行うといったものです。

正直に言います。
この言語、チューリング完全ではないかもしれません。
(ちゃんと確認してないので、断定できませんが)

# HexBFができた経緯
というのも、この言語はチューリング完全を目的として作られてはいないからです。
これは、HexBFができた経緯に大きく関係します。

このHexBFですが、思い付きでBrainf*ck言語のインタープリタを作成しようとして失敗した際にできたものなのです。
具体的には、Brainf*ck言語のメモリの認識を16進数の桁ごとであると勘違いしてしまったまま、実装してしまったのです。

今思うと、まったく訳の分からない勘違いの仕方をしていますが、Brainf*ck言語を触り始めた当初はこんな感じのイメージがあったようです。

そして、実装途中なって「あれ？これ違くね？」ってなり、調べて気が付きました。
ですが、「これはこれで、面白いからいいか！」や「むしろ16進数で値を扱った方がASCIIコードで見たときわかりやすくね！」となり、この言語が完成しました。

# おわりに
この言語は、個人的にはちょっと気に入っています。
なぜかというと、かなり実装が簡単だからです。(もちろん自分自身が実装をしたということもありますが)

この言語は、あまりコンパイラを作成するための知識がなくても実装できるので、「面白いかもしれない」と思ったひとは試しに実装してみるのもよいと思います。

また、実際に(偶然ではありますが)自作言語を作ってみたところ、このような簡単な言語であれば、気楽に言語の開発ができることを知れたので、色んな人にも自作言語を作ってもらいたいと思ったり、思わなかったり笑

そんなわけで、以上が自作言語のHexBFの紹介でした。
teratermマクロで複数サーバ作業を自動化

# はじめに

大量のサーバで同じような作業をするのは病みますよね・・・
その時のために、teratermで使えるツールを作りました

たまにしかteratermマクロを触らないので、コピペ用に置いておければなと思い投稿しました

# 環境

|環境||
|:-----------|------------:|
| Windows 10 home   | |
| teraterm | v.4.104 |
| MS-DOS||

# 検証

バッチからマクロを呼び出し、複数サーバに対して処理を実行します。

## マクロ呼び出し元バッチ

```bat:teratermExec.bat
@echo off
REM ======================================
REM teratermマクロ呼び出し
REM ======================================
setlocal
    cd /d %~dp0
    set chdir=%~dp0

    REM 変数定義
    set ttMacroExe="ttpmacro.exeのパス"
    set ttMacroPath=%chdir%teratermMacro.ttl
    set logDir=%chdir%ttlLog

    REM ログ出力ディレクトリ作成
    if not exist %logDir% (
        md %logDir%
    )

    REM マクロ実行ラベルの呼び出し
    call :doMacro 192.168.0.1 root password
    call :doMacro 192.168.0.2 root password

endlocal
exit /b

REM -------------
REM マクロ呼び出し
REM -------------
:doMacro
    set ipaddr=%1
    set username=%2
    set password=%3
    set logFile=%logDir%¥%ipaddr%_%date:/=%_%time::=%.log

    echo %date% %time% [INFO] %ipaddr% ログ保存先：%logFile%

    REM teratermマクロ呼び出し
    call "%ttMacroExe%" %ttMacroPath% %ipaddr% %username% %password% %logFile%
exit /b
```

## テラタームマクロ

```ttl:teratermMacro.ttl
; ======================================
; 引数１：実行マクロ名
; 引数２：IPアドレス
; 引数３：ログインユーザ名
; 引数４：ログインパスワード
; 引数５：ログファイル名
; ======================================

; タイムアウトを設定
timeout=15

; 引数チェック
if paramcnt !=5 then
    messagebox '引数は５つ必要です'
    end
endif

; 引数代入
TTLNAME = param1
HOSTADDR = param2
USERNAME = param3
PASSWORD = param4
LOGNAME = param5

; コマンオプション組み立て
msg = HOSTADDR
strconcat msg ' :22 /ssh /auth=password /user='
strconcat msg USERNAME
strconcat msg ' /passwd='
strconcat msg PASSWORD

; 接続
connect msg
if result <> 2 then
    messagebox '接続失敗' 'connection err'
    end
endif

; ログ出力指定
Loginfo NOW_LOGIFLE
if result <> -1 then
    logclose
    filecopy NOW_LOGIFLE LOGNAME
    filedelete NOW_LOGIFLE
endif
logopen LOGNAME 0 1 1 1

; コマンド実行
wait '#'
sendln 'date'

wait '#'
sendln 'set -o vi;alias ll="ls -lFa"'

wait '#'
sendln 'df -m'

wait '#'
sendln 'w'

wait '#'
sendln 'who'

; テストコマンド実行

; ・・・・・実行したいコマンドを列挙

; teraterm終了
wait '#'
sendln 'exit'
end
```

# まとめ

クライアントソフトを大量のサーバにインストールしたり、それのパラメータ確認用資料を収集してきたり、動作確認したりといろんな場面で使えるかなと思います。
JavaScriptでボタンの表示を変更


```
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">

  <style>
    #text-button {
      display:block;
      cursor:pointer;
      width: 160px;
      text-align:center;
      border: 1px solid #232323;
    }
  </style>
  <title>Document</title>
</head>
<body>
  <div id="text-button"><p id="text">あなたのことが好きです。結婚してください。</p></div>
  <script>
    document.getElementById("text-button").onclick = function() {
      document.getElementById("text").innerHTML = "すみません。私はあんまり。";
    };
  </script>
</body>
</html>
```
Lumen 6.2 でセッションを使う

`Lumen 6.2` には `illuminate/session` が含まれていますが、デフォルトで無効になっているので有効化させたときの手順メモ

**※Lumen 8.2.1 でも同じ手順でセッションが有効になることを確認しました**

# 動作環境

```sh
Windows10 Home Edition
XAMPP 7.2.17

$ php --version
PHP 7.2.17 (cli) (built: Apr  2 2019 20:11:25) ( ZTS MSVC15 (Visual C++ 2017) x64 )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.2.17, Copyright (c) 1999-2018, by Zend Technologies
    with Xdebug v2.6.1, Copyright (c) 2002-2018, by Derick Rethans

$ php artisan --version
Laravel Framework Lumen (6.2.0) (Laravel Components ^6.0)
```

# 設定

## セッション関連クラスの登録

`bootstrap/app.php` に下記を追加

```php:bootstrap/app.php
$app->singleton(Illuminate\Session\SessionManager::class, function ($app) {
    return $app->loadComponent('session', Illuminate\Session\SessionServiceProvider::class, 'session');
});

$app->singleton('session.store', function ($app) {
    return $app->loadComponent('session', Illuminate\Session\SessionServiceProvider::class, 'session.store');
});


$app->middleware([
     \Illuminate\Session\Middleware\StartSession::class,
]);
```

## `config/session.php` の追加

プロジェクトのルートに `config` フォルダを作成。その中に `session.php` を配置  
`session.php` の内容は `Laravel` の `config/session.php` と同じ  

[laravel/session.php at master - laravel/laravel](https://github.com/laravel/laravel/blob/master/config/session.php)

## セッションの保存フォルダの作成

`storage/framework` の下に `sessions` フォルダを作成する

```
$ mkdir storage\framework\sessions
```

# 動作確認

## テストコード

```php:routes/web.php
// Test Session
$router->get('/test', function (\Illuminate\Http\Request $request) {

    $counter = $request->session()->get('counter') ?: 0;
    $request->session()->put('counter', ++$counter);

    return response()->json([
        'session.counter' => $request->session()->get('counter')
    ]);
});
```

## テストサーバー起動

```sh
$ php -S localhost:8000 -t public
```

## アクセス

WEBブラウザで `http://localhost:8000/test` を開くと以下のように表示される

```json
{"session.counter":1}
```

セッションが正常に機能していれば、リロードする度に数値がインクリメントされる

# 参考

- [lumen 5.2 でもSession使う - Qiita](https://qiita.com/mikakane/items/faa8becc85631be13156)
- [laravel - Enabling session in lumen framework - Stack Overflow](https://stackoverflow.com/questions/47050984/enabling-session-in-lumen-framework)
達人に学ぶSQL徹底指南書第2版を読んで

自分なりに所感とまとめ。

## 構成

- 1部がSQLのサンプルケースと使い方について
- 2部が歴史や背景・概念などについて
- 3部が1部の演習問題の解答、参考文献

と言った形になっています。
お忙しい人は1部のサンプルケースをつまみ食いして読むのも良いかも。

## 個人的に参考になったところ

再認識させられたところやなるほどな～となったところを抜粋。

- CASE式はELSEを必ず書こう
- MySQLでSELECT句とGROUP BY句に同じCASE式を書かなければいけない場合、SELECT句のCASE式部分に別名を付けて別名をGROUP BY句で指定する
- CASE式はどこにでも書ける
- ウィンドウ関数のフレーム句で異なる行のデータを1つの行に持ってこれる＝行間比較が容易になる
- NULLは値でも変数でもない
- NOT INのサブクエリで使用されるテーブルの選択列にNULLが存在＝SQL全体の結果は常に空
- テーブルはファイルではない。行も順序を持たない。そのためSQLでは"原則"ソートを記述しない。
- ソートを回避する
- 余計な中間テーブルを減らす
- レコード数を絞れる条件は早い段階で記述する
- 読みにくいコードは何物も、誰も解決してくれない
- NULLの撲滅、NULLを入れず、値で代用して設計できないか考慮する

## 所感

- 著者のCASE式とEXISTS句推しにとても熱意を感じた
- 1-6のHAVING句の章では連番の歯抜けを探すなど遡及の対象となるようなレコードの探し方が細かく紹介されており、とても参考になると思う
- ウィンドウ関数は業務でも使用してみたいけど、業務で使用してる現行システムのMySQLのバージョンは8.0じゃないよ～；；って人結構居そう
- EXISTS句を速いと紹介しているが、相関サブクエリを用いるので一概にそうとは言えないと思うと感じた
    - 相関サブクエリ：サブクエリ内でメインのクエリを参照しているクエリのこと
    - EXISTS句で「メインクエリで参照するレコードの数」×「サブクエリで参照するレコードの数」だけ比較するわけなので、テーブルによっては膨大な時間が掛かることになる
- 詰まったときのヒントとして手元に置いておく、繰り返し読み返して心掛けるなどすると大いに活用できると思う
BigQueryのプレフィックス文字を理解する

ある日のこと。
後輩くんからこんな質問をされた。

<b>後輩「先輩、この正規表現関数に出てくる`r`ってどういう意味ですか？」
　私「(やっべぇ、わかんねぇ…)」
　私「あれじゃね？正規表現を表す的な。」
後輩「なるほどー！」</b>


…すまない、後輩くん。
私は君に嘘をついてしまった。


日頃、何も気にせず`r`をつけて正規表現関数を使っていたので、今回の質問をきっかけに調べてみた。


## rのプレフィックス文字について

BigQueryには、下記正規表現関数が用意されている。

```
REGEXP_CONTAINS(email, r"@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+") 
REGEXP_EXTRACT(email, r"^[a-zA-Z0-9_.+-]+")
REGEXP_REPLACE(heading, r"^# ([a-zA-Z0-9\s]+$)", "<h1>\\1</h1>")
```



第二引数の正規表現処理が走る文字列の先頭に、もれなく`r`がついている。
公式の説明によると、

>生の文字列のリテラル プレフィックス（r または R）を持つ、引用符または三重引用符付きのリテラルは、生のあるいは正規表現の文字列と解釈されます。
>バックスラッシュ文字（\）はエスケープ文字としては機能しません。文字列リテラルの内部にバックスラッシュとそれに続く別の文字がある場合は、両方の文字が保持されます。
>生の文字列は、奇数のバックスラッシュで終えることはできません。
>生の文字列は正規表現を作成するのに便利です。
>https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical?hl=ja

とのこと。
どうも理解しづらいため、もう少し噛み砕いてみる。

- `r`を文字列の先頭につけた場合、対象の文字列は<b>生文字列もしくは正規表現文字列として処理される</b>よ。
- 文字列内では、<b>\(バックスラッシュ)によるエスケープ処理は走らない</b>よ。
- 文字列の最後を<b>奇数個の\(バックスラッシュ)で終えるとエラーになる</b>よ。

ってこと。

ちなみに`r`は、raw string(生文字列)の頭文字からきている。
(正規表現のregexpの`r`じゃなかったんだ…)


さて、`r`のプレフィックス文字の仕様を理解したところで確認テストです。
下記のSQLをBigQueryで実行したら何が返ってくるでしょーか？

```sql
SELECT 
  REGEXP_CONTAINS('\\', r'\\') AS q1
  , REGEXP_CONTAINS('\\', r'\\\\') AS q2
  , REGEXP_CONTAINS(r'\\', r'\\\\') AS q3
```

<details>
<summary>答え</summary>
<div>

| q1 | q2 | q3 |
| :-: | :-: | :-: |
| true  | false  | true  |

## q1の解説

第一引数の`\\`はエスケープ処理が走り、`\`になる。
第二引数の`\\`はエスケープ処理が走らないが、正規表現により`\`になる。
よって、trueが返ってくる。

## q2の解説

第一引数の`\\`はエスケープ処理が走り、`\`になる。
第二引数の`\\`はエスケープ処理が走らないが、正規表現により`\\`になる。
よって、falseが返ってくる。

## q3の解説

第一引数の`\\`はエスケープ処理が走らないため、`\\`になる。
第二引数の`\\`はエスケープ処理が走らないが、正規表現により`\\`になる。
よって、trueが返ってくる。
</div>
</details>

## 最後に

今まで理解せずに毎回つけてSQLを実行していたが、もしかしたら意図しない処理になっていたかもしれない。
皆さんも、仕様を理解せずに利用しているものがあれば、ミスを犯す前に一度調べてみましょー。


# 私たちのチームで働きませんか？
![alt](https://brides.a-tm.co.jp/wp-content/uploads/2019/11/ATEAM_BRIDES.jpg)
[エイチーム](https://www.a-tm.co.jp/)は、インターネットを使った多様な事業を展開する**名古屋の総合IT企業**です。
そのグループ会社である**株式会社エイチームブライズ**では、一緒に働く仲間を募集しています！

- [ハナユメ サイト開発グループ](https://jobs.qiita.com/employers/brides-a-tm/development_teams/138)
- [HIMARI開発チーム](https://jobs.qiita.com/employers/brides-a-tm/development_teams/147)
- [技術開発部](https://jobs.qiita.com/employers/brides-a-tm/development_teams/148)

上記求人をご覧いただき、少しでも興味を持っていただけた方は、まずは**チャットでざっくばらんに話**をしましょう。
技術的な話だけでなく、私たちが大切にしていることや、お任せしたいお仕事についてなどを詳しくお伝えいたします！

[Qiita Jobs](https://jobs.qiita.com/)よりメッセージお待ちしております！
ジャンケンが弱い僕はタブレットと合体した

[クソアプリ Advent Calendar 2019](https://qiita.com/advent-calendar/2019/kuso-app) 7日目の記事です。

## はじめに
僕はジャンケンが弱い。1対1の心理戦では尚更だ。

しかし悲しいことに、世の中ジャンケンで決めることは多い。

テレビのチャンネル権、給食で余ったデザート、どちらが風呂掃除をするか・・・
人生においてここぞという決め事はいつもジャンケンで負けてきた。

このままでは負けっぱなしの人生だ。

次にこの手を出そうと頭で考えると負けてしまう・・・
自動でジャンケンしてくれるロボットアームがあったらいいのに・・・

そこで僕は自動で手を出してくれるアプリを作ることにした。

※ AIとか機械学習で勝率をあげるとかそういう技術レベルの高いことはやっていません。あらかじめご了承ください。

## 作ったもの
![animation.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49696/5ee62cca-906b-0c54-4d59-2ded523afe45.gif)
[**振ってジャンケン！**](https://okmr-d.github.io/shake-janken/)
https://okmr-d.github.io/shake-janken/

スマホやタブレットを振ることで、ジャンケンの手をランダムで出してくれるWebアプリです。

これでもう次にどの手を出すか迷う必要はありません。

手の上にタブレットを置けばまるで自分の手のよう。相手にも違和感を与えることなく真剣勝負ができます。

ジャンケンする友達がいなくても大丈夫。スマホ片手に一人でもジャンケンができます。暇つぶしにはもってこいです。

端末の加速度センサーを利用するため、対応しているスマホやタブレットでご覧ください。ホーム画面に追加することで全画面で遊べます。

【注意事項】 
・端末を振る際は落として壊さないよう十分ご注意ください。壊れても責任は負いかねます。
・本当に大事な場面でこのアプリを使うことは推奨しません。使って負けても責任は負いかねます。

## 工夫したこと
### 背景を透過した
この画像を背景に使うことで、人によっては端末が透けて見えます。
<img width="300" alt="透過画像.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49696/0d3b5b14-f253-dd10-ec06-5bb9ad7bcc7b.png">

### 振ったことをわかりやすくした
振った時に同じ手が連続で出た場合、画面に変化がないとうまく振れなかったように感じてしまうため、振ったタイミングに一瞬だけ背景色を変えるようにしています。
![画像.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49696/d1525945-4ac8-c0ef-21d3-e0396c9009f9.jpeg)

## 技術解説
### デバイスが振られたことを検知する
Webブラウザでシェイクジェスチャーを検知するには、 [DeviceMotionEvent](https://developer.mozilla.org/ja/docs/Web/API/DeviceMotionEvent) を利用してデバイスの加速度情報を取得し、計算して判定します。

```js:シェイク判定の例
const threshold = 5 // 判定のしきい値
const last = { x: null, y: null, z: null } // 前の時点のデータ

const deviceMotionHandler = (event) => {
  // X、Y、Z 上のデバイスの加速度を重力度込みで与えるオブジェクト(m/s2)
  const current = event.accelerationIncludingGravity

  // 初回だけ
  if (last.x === null && last.y === null && last.z === null) {
    last.x = current.x
    last.y = current.y
    last.z = current.z
    return
  }

  // 現時点の座標と前の時点の座標の差分
  const deltaX = Math.abs(last.x - current.x)
  const deltaY = Math.abs(last.y - current.y)
  const deltaZ = Math.abs(last.z - current.z)

  // シェイク判定（差分がしきい値を超えた）
  if (deltaX > threshold || deltaY > threshold || deltaZ > threshold) {
    // シェイクされた！！！
  }

  // 現時点の座標を更新する
  last.x = current.x
  last.y = current.y
  last.z = current.z
}

window.addEventListener('devicemotion', deviceMotionHandler, false)
```

iOS 12 だとユーザーの設定変更が必要だったり、 iOS 13 からはパーミションの取得が必要だったりするので、別記事にまとめてあります。
→ [iOS13+のSafariでdevicemotionやdeviceorientationイベントの許可を取得する方法](https://qiita.com/okumura_daiki/items/16a09c9c0d0b2509d261)

# クソースコード
https://github.com/okmr-d/shake-janken

# おわりに
世の役に立たないクソアプリを作るはずが、ジャンケン弱者を救う役立つアプリを生み出してしまいました。

クソアプリ Advent Calendar 今年も大人気ですね。明日も楽しみです。

よろしければ去年の作品もご覧ください。
→ [「通知止まらんwww」を体験できるアプリを作った](https://qiita.com/okumura_daiki/items/ed6398c06c1b40d10c6c)
自動テストでSimulatorの位置情報を偽装したいときはidbをお忘れなく

Simulatorで位置情報を偽装したく、driver.set_locationで位置情報を偽装してテストを実行したのですがiOSのときだけ下記のエラーが出ました。

```
An unknown server-side error occurred while processing the command. Original error: Could not complete operation. Make sure Simulator UI is running and the parent Appium application (e. g. Appium.app or Terminal.app) is present in System Preferences > Security & Privacy > Privacy > Accessibility list. If the operation is still unsuccessful then it is not supported by this Simulator. Original error: Command 'osascript -e ' ...
```

調べてみると fbsimctlが必要とのことで(https://github.com/appium/appium/issues/12575 を参照) 入れてみようとしたところビルドエラーになりました。ビルドエラーを解決しようとしてもエラーは解決できなかったためhttps://seleniumjp.slack.com で聞いてみたところ「今のappium-doctorではfbsimctlがidbにリネームされた」という話を聞きました。appium-doctorを叩いてみたところご丁寧に

```
Why idb is needed and how to install it: https://github.com/appium/appium-idb
```
と教えてくれたのでをインストールしテスト実行するとSimulatorの位置情報を偽装できることができました。
HTML classの書き方　どっちの方がいいのか

① <h3 class="section-title">学べるレッスン</h3>

② <div class="section-title">            
        <h3>学べるレッスン</h3>            
 </div>


section-titleというクラスをh3要素につけなさいと言われたので最初②のやり方で書いたら怒られました。
答えをみると①の記述があったのですが、なぜ②の書き方じゃいけないのですか？
Azureの基礎　その５

#コアクラウドサービス -Azure portalを使用してサービスを管理する

出展：https://docs.microsoft.com/ja-jp/learn/modules/tour-azure-portal/index

##Azureの管理オプション

###Azure Portal
・あらゆるWebブラウザーでアクセスできるパブリックWebサイト
・Azureアカウントでサインインすると、利用できるあらゆるAzureサービスを作成、管理、監視できる
・探しているサービスを識別したり、トピックに関するヘルプのリンクを取得したり、リソースのデプロイ、管理、削除を行ったりすることができる
・ウィザードやヒントを使って、複雑な管理タスクにも対応できる
・ダッシュボード ビューには使用しているAzure環境についての詳細が表示される
・ポータルには反復的なタスクを自動化する方法は用意されていない

###Azure PowerShell
・Windows、Linux またはmacOSで実行するクロスプラットフォームバージョンのPowerShellである、Windows PowerShellまたはPowerShell Core 用にインストールできるモジュール
・Azureサブスクリプションに接続し、リソースを管理することができる
・管理スクリプトを作成し自動化ツールを使用することは、ワークフローを最適化する強力な方法となる
・反復的なタスクを自動化することも可能

###Azure CLI（Azure コマンドラインインターフェイス）
・Azureに接続してAzureリソース上で管理コマンドを実行することができるクロスプラットフォームのコマンドラインプログラム

###Azure Cloud Shell
・Azureリソースを管理するために認証されたブラウザーからアクセスできる対話型シェル
・BashまたはPowerShellのうち作業に最適なシェルエクスペリエンスを選択できる
・ブラウザーベースの環境から直接、アプリを作成、構築、デプロイできる

###Azure mobile app
・iOSまたはAndroidを搭載したスマートフォンやタブレットからAzureのすべてのアカウントとリソースにアクセスし、管理し、監視することができる
・インストール後に可能となる主な操作
　　・サービスの現在の状態や重要なメトリックを確認する
　　・最新の情報を受け取り、正常性に関する重要な問題があれば警告を受ける
　　・時間と場所を問わず、問題をすばやく診断し、修正する
　　・最新のAzureアラートを確認する
　　・仮想マシンやWebアプリを開始、停止、再開する
　　・仮想マシンに接続する
　　・ロールベースのアクセス制御 (RBAC) の権限を管理する
　　・Azure Cloud Shell を使用し、保存したスクリプトの実行や臨時の管理タスクを行う
next_combinationを実装してみた

# 前置き

next_permutationがあるならnext_combinationがあってもいいじゃないか、というわけでnext_combinationです。

next_combinationでググると、実装されたものもたくさん見つかるのですが、どれもなかなか理解するのが大変で、そんな中でも比較的私の頭でも理解できそうだったものを参考に、勉強のために改めて自分で実装し直してみました。

なお、参考にさせていただいた記事はこちらです。[C++でnCkやnPkを全列挙する関数](http://ysugiyama.hatenablog.com/entry/2018/10/31/233418)
ありがとうございます。

# 実装

```c++:next_combination
template <typename T> bool next_combination(const T first, const T last, int k) {
    const T subset = first + k;
    // empty container | k = 0 | k == n 
    if (first == last || first == subset || last == subset) {
        return false;
    }
    T src = subset;
    while (first != src) {
        src--;
        if (*src < *(last - 1)) {
            T dest = subset;
            while (*src >= *dest) {
                dest++;
            }
            iter_swap(src, dest);
            rotate(src + 1, dest + 1, last);
            rotate(subset, subset + (last - dest) - 1, last);
            return true;
        }
    }
    // restore
    rotate(first, subset, last);
    return false;
}
```

## 概要

「次の組み合わせ」が先頭k個に、その組み合わせに使われていない数はソートされた状態で後ろに繋がるようになっています。次の組み合わせがなければfalseが返ります。
後ろがソートされていることにより、次の数が容易に取り出せるような実装になっています。多分。

# 使い方

まずソートされた列を用意します。（前述の通り、列の後半部分はソートされていることが前提なので、next_permutationとは違ってソート済みでない列を最初に渡してしまうと動作しません）
引数には、next_permutationのようにイテレータを渡すとともに、`nCk`のkも渡します。
組み合わせとして見るべき要素は、先頭のk要素となります。

```c++
vector<int> v{1, 2, 3, 4, 5, 6, 7};
do {
    for (int i = 0; i < k; i++) {
        cout << v[i] << " ";
    }
    cout << "| ";
    for (int i = k; i < v.size(); i++) {
        cout << v[i] << " ";
    }
    cout << endl;
} while(next_combination(v.begin(), v.end(), k));

/*
1 2 3 | 4 5 6 7 
1 2 4 | 3 5 6 7 
1 2 5 | 3 4 6 7 
1 2 6 | 3 4 5 7 
1 2 7 | 3 4 5 6 
1 3 4 | 2 5 6 7 
1 3 5 | 2 4 6 7 
1 3 6 | 2 4 5 7 
1 3 7 | 2 4 5 6 
1 4 5 | 2 3 6 7
...
*/
```

# 使ってみた

実戦投入したものがこちらです。
https://atcoder.jp/contests/cpsco2019-s1/submissions/8827591

作っておいてこんなことをいうのも何ですが、next_permutationほど頻繁に使う機会があるものではないですね。
M5CameraでLineに通知を送る最小限のサンプル

M5Cameraをルータに繋いだときのカメラのIPアドレスを知りたいときなど、
画面がないので何らかの方法で通知する必要があります。
シリアルコンソールにつないでいれば Serial.print 等で出力して確認できますが、
モバイルバッテリーにつないで動作させている場合はそれもできません。
そういった場合に Line に通知するとわかりやすいので、実現のためのプログラムを以下に示します。

Lineに通知するにはインターネットにつなげる必要があるので、
ソース中のSSID、PASSWORDを書き換えるのと、
LINE_TOKENに Line Notify から取得したトークンに書き換えてください。

Line Notify のトークンは
https://notify-bot.line.me/ja/
にログインしてマイページから発行できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/d7e93619-e2f6-fc8c-be44-2b106da17944.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/e266ce22-47dc-24c6-8293-9ffcd1c6039a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82535/2463ec39-a2c0-48a5-840e-97b7cf0e9f2c.png)

プログラムソースは以下のとおりです。

```
#include <HTTPClient.h>
#include <WiFi.h>

//インターネットアクセスポイントのSSID、パスワード
#define SSID "(お使いのルータのSSID)"
#define PASSWORD "（お使いのルータのパスワード）"
//LINE Notify トークン
#define LINE_TOKEN "（Line Notifyで取得したトークン）"

// URLエンコード(URLに任意の文字を設定するときに使用)
String urlencode(const String &sourse) {
    static const char lookup[] = "0123456789abcdef";
    String result;
    for (const char* c = sourse.begin(); c != sourse.end(); c++) {
        if('0' <= *c && *c <= '9'
        || 'a' <= *c && *c <= 'z'
        || 'A' <= *c && *c <= 'Z'
        || *c=='-' || *c=='_' || *c=='.' || *c=='~') {
            result += *c;
        } else {
            result += '%';
            result += lookup[(*c >> 4) & 0xf];
            result += lookup[*c & 0xf];
        }
    }
    return result;
}

void setup() {
    // シリアル通信開始
    Serial.begin(115200);
    Serial.setDebugOutput(true);
    Serial.println("power on");

    // WiFi接続
    WiFi.mode(WIFI_STA);
    WiFi.begin(SSID, PASSWORD);
    for (int i = 0; WiFi.status() != WL_CONNECTED; i++) { // 接続できるまで最大30秒間試行
        if (i >= 30) esp_restart(); // 接続できない場合はリセット
        delay(1000);
        Serial.print(".");
    }
    Serial.println("\nconnected: " SSID);

    // Line Notify にメッセージ送信
    HTTPClient http;
    http.begin("https://notify-api.line.me/api/notify");
    http.addHeader("Authorization", "Bearer " LINE_TOKEN);
    http.addHeader("Content-Type", "application/x-www-form-urlencoded");
    http.POST("message=" + urlencode("M5Cameraからの通知"));
    http.end();
    Serial.println("posted");
}

void loop() {
}
```
Lookerで始める機械学習

Looker Advent Calendar 2019 Day 8の投稿になります。

Lookerで始める機械学習ということで、Lookerを使って機械学習をする手順とそのメリットについてまとめていきたいなと思っています。

##機械学習に必要なステップ
例えば、機械学習や統計解析などを使ってデータサイエンス的ななにかを行う場合、多くの場合以下のような手順で行います。

    1. ローデータの収集
    2. データのクレンジング
    3. 検証したい仮説の実績データを取得
    4. 統計/機械学習アルゴリズムを使用して予測の実施
    5. 可視化やアラートなどを利用し、結果を共有
 
この手順にツールを追加すると・・・

    1. ローデータの収集 → ETLツール
    2. データのクレンジング　→ ETLツール/SQL
    3. 検証したい仮説の実績データを取得 → SQL
    4. 統計/機械学習アルゴリズムを使用して予測の実施 → R/Python/各種機械学習サービス
    5. 可視化やアラートなどを利用し、結果を共有　→ BIツール

データ活用を検討されている企業の場合、その多くはすでに1,2については安定した運用が行われているケースが多いですが、3以降ではそれぞれの手順で異なるツールやテクノロジーが必要とされるため、利用にあたり高いスキルが必要とされたり、運用管理が複雑になってしまいます。

しかし、Lookerではこの手順で必要とされるものをシンプルにして実行することを可能にします。

##Lookerで実施する場合の手順
前述の通り、1,2に関してはすでに構築済みだと思いますので3からの手順に焦点を当てていきます。

###3. 検証したい仮説の実績データを取得
機械学習を利用して様々な状況の予測を実施するためには、仮説を立て、仮説が正しいかデータをクエリし確認します。
通常、この手順では立てた仮説のもと実態の確認のためにデータを探索します。この際、多くのパターンの仮説検証を繰り返すために何度もSQLを書きます。これが地味に手間なのですが、LookerではExploreの画面から簡単にデータセットの中に自由にクエリをかけることができるため、思いつく限りの多くのパターンの仮説の検証が可能になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96820/1a7ddfd5-9b76-b925-1b7a-6ada5de64d54.png)


###4. 統計/機械学習アルゴリズムを使用して予測の実施
3で検証したデータを元に予測をしていきます。
Lookerではこれをいくつかの方法で実施することが可能です。

> Action Hubを使った連携

LookerにはAction Hubという、Exploreで探索した結果を他のソリューションへ定期配信することができる機能があります。これを使うとこでAmazon Sagemakerで機械学習を開始させたり、DataRobotにデータを送りプロジェクトを作成したりすることが可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96820/1beff9ac-5669-1b31-06d8-4807f291ca42.png)

> LookMLからクエリを作成

Google BigqueryML(BQML)の場合、Standard SQLを使用してモデル構築が可能となっています。LookerではこのBQMLの操作をLookMLを通して実現することが可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96820/c5d65c87-d2cf-562d-e0aa-3922929c0954.png)
ここでは、3で取得した結果を元に一時テーブルを作成し、それを元にモデル作成用のクエリを実行するようなLookMLを記述しています。

> APIを使用してデータを取得

Looker内で定義したデータをAPIで取得することが可能になっています。Python SDKもあるため、APIを通してJupyter Notebookにデータを取得して利用することも可能です。

###5. 可視化やアラートなどを利用し、結果を共有
4でモデルを構築/予測し、それを使用した結果はみなさんがお持ちのDWHにあると思うので、その可視化やアラート設定はLookerで簡単に実施ができます。

######モデル精度の検証
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96820/12d3a11e-ed4d-e2f1-11c4-b595eefa5a28.png)


######予測結果を現場オペレーションへ展開
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96820/135f3a7b-9031-f335-b495-abcf217424a6.png)


##まとめ
従来ではステップ毎に異なるテクノロジーを利用しているためにデータの受け渡しなど煩雑な管理が必要となっていたところを、Lookerでは簡単にシームレスに繋ぐことが可能になるので、みなさんのデータ分析業務を簡単にステップアップさせることが可能です。
初心者がRailsプロジェクト作った時の話

## はじめに
Rails、Dockerなど、初めての事だらけの状態でプロジェクトを作った際に苦労したことや、反省点、私がやっていた手順などを紹介したいと思います。

## はじめてのDocker
Dockerは今回のプロジェクトで初めて利用しました。Dockerの知識が全くないので下記のような手順で、練習してから本番のプロジェクトを動かしました。

1. ローカル環境でDockerをホストして、nginxでHTMLを表示
2. ローカルではなくherokuで1と同じことをする
3. 2と同じことをGitHubとherokuを連携させてデプロイ
4. heorkuでrailsをホストする

### HerokuのGitHub連携
HerokuとGithubを連携すると、Githubでpushした際にそのコミットがherokuに自動的に反映されます。
とても便利で、簡単に設定できるのでぜひやってみてください:bangbang:
[参考記事](https://qiita.com/sho7650/items/ebd87c5dc2c4c7abb8f0)

### Dockerの注意点
`docker-compose run web `を使ってコマンドを実行していましたが、それだとコンテナがその都度作られて、コンテナが増える原因になってしまうので、`docker-compose exec web `とすると今使われているコンテナ内で、そのコマンドが実行されるので、コンテナが増えずに済みます。

## テストコードのありがたみを知った
私は、テストコードを書くことがあまりできませんでしたが、今回のプロジェクト制作を通して、テストコードが自分的には書けるように成長したなと感じました。また、テストコードを書くことによって、手軽に動作や機能の確認をすることができるので、見えないエラーの修正などもできました。今回の件で、テストコードって大切なんだなって感じました。

## HTMLとCSSの奥深さを知った
Railsのテストコードを使う際に、CSSセレクタを使って要素の検索などをしたのでCSSセレクタは、難しいと感じました。
一見、簡単そうに見えますがHTML、CSSは適切なタグ付け、クラス分けをするのは難しいんだなと感じました。
もっと勉強していかなければならない点だなと感じました。

## 「まずは思ったように書いてみる」が大事
「頭の中で考えているだけでなく、それをコードに起こしてみる」が大切だと感じました。考えているだけでは時間の無駄になってしまうので、ある程度頭の中で構成図が組めたら、コードを書いてみるというサイクルが大事だなって思いました。書くことにより、どこが間違えているのかが明確になるので、より短い時間で開発ができている気がしました。



## さいごに
今回のRailsのプロジェクトを通して、学ぶことが多かったです。また、これからしなければならないことがはっきりわかってきた気がします。アウトプットとして、皆さんも何かを作ってみるとたくさん学びが得られるので、新しいことに前向きに挑戦してみてください！
Node.jsのasync/awaitとPromiseを超ざっくり_中編

※[Node.jsのasync/awaitとPromiseを超ざっくり_前編](https://qiita.com/masa_miyazaki/items/fb137d8b7d3aeb6967b1)の続きです。後でまとめるかも。
※arrow関数は使わないといったな、あれは嘘だ。


##  目次  
~~1. Node.jsの非同期処理について~~  
~~2. 非同期処理の書き方~~  
~~2.1 コールバック（callback）関数~~  
~~2.2 Promise~~  
2.3 asycn/await  <font color="Red">←この記事はココから！</font>    
~~3. Promiseとasycn/awaitが一緒だと思ったらハマった件~~
4. 参考


##  2.3.asycn/await
asycn/awaitとはPromiseのシンタックスシュガー。
（同じような内容のことをもっと簡単な書き方でできるよ、というもの。）

###async
Promiseの場合は

```javascript
function hoge() {
    return new Promise((resolve, reject)=>{
        //処理
        resolve('success')
        //or
        reject('error')
    })
}
```
というように明示的にPromiseをリターンしていたが、asyncを使って書くと以下のように書ける。

```javascript

async function() hoge{
    //処理
    return 'success'
    //or
    throw new Error('error')
}
```
asyncで宣言した関数内は
・Promiseを返す。
・値をreturnするとPromiseをresolveする
・エラーをthrowするとPromiseをrejectする

###await
・async functionの中でしか使えない
・Promiseが `resolve` or `reject`されるまでasync functionの処理を待つ
使用例）

```javascript

//プロミスを返す非同期function
function addNum_promise(num1, num2) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(num1 + num2);
        }, 1000);
    })
}

async function example(num1, num2) {
    //[2]
    const res = await addNum_promise(num1, num2) //Promsieがresolveされるまで待つ
    return res + 10
}

(async()=>{
    console.log('start')
　　//[1]
    console.log(await example(1,2))
    console.log('end')
})()
```

```console:console
//結果
start
13
end
```
Promiseを返すfunctionにawaitをつけて呼び出すことで処理の順番が同期的になっていることがわかります。
ちなみに[1]、[2]のawaitを外してみた場合はそれぞれこのようになります


```javascript
//*******************[1]
async function example(num1, num2) {
    const res = await addNum_promise(num1, num2) //Promsieがresolveされるまで待つ
    return res + 10
}

(async()=>{
    console.log('start')
　　//[1]await外す
    //console.log(await example(1,2))
    console.log( example(1,2))
    console.log('end')
})()

//*******************[2]
async function example(num1, num2) {
    //[2]await外す
    //const res = await addNum_promise(num1, num2) //Promsieがresolveされるまで待つ
    const res =  addNum_promise(num1, num2) 
    return res + 10
}

(async()=>{
    console.log('start')
　　console.log(await example(1,2))
    console.log('end')
})()
```

```console:console
[1]のawaitを外した場合
start
Promise { pending }
end

[2]のawaitを外した場合
start
[object Promise]10
end
```
[1]の場合はfunction「example」が返すPromiseがまだ準備中だよ(未resolve)～って意味
[2]の場合はfunction「addNum_promise」のPromise(res)がresolveされていない状態でres+10をreturn(==resolve)しているので上のような結果になる。`[object Promise]`の中身は`Promise { pending }`である。

上の2つをまとめると
[1]`function「example」が未解決`という結果が返された
[2]`function「example」が解決済(function「addNum_promise」が未解決+10)`という結果が返された

書いててよくわからなくなったので続きはまた後日...(薄く延ばす戦法)


##  4.参考
[Node.js 非同期処理・超入門 -- Promiseとasync/await](https://qiita.com/ef81sp/items/29b7b91a3f3e77cf2233)
Node.jsデザインパターン
[async/await 入門（JavaScript）](https://qiita.com/soarflat/items/1a9613e023200bbebcb3)
社会人１年目の反省や学びや気付きの振り返り（04/01-09/30）

2017/04/01~2017/09/30

社会人１年目にほぼ毎日書いていた日報を振り返り、
反省や学びや気付きをまとめていきます。箇条書きで少々読みづらいかもしれませんが
ご了承ください。

■日報取りまとめ
・言葉の使い方
　・内容の論理構成がまるでなっていない
　・軽率な発言が多い
　・頼み事をされたときにとりあえず返事をしてしまう（要件確認不足）

・ほうれんそう
　・誰に何をどのような粒度で伝えればいいのかわからない
　・相手が欲している情報はなにかを考えること。
　　・報告する相手は時間がない。端的に正確に。
　・伝えるのが下手な人は、どう伝えればいいのかがわからないのではなく、
　　伝えたいことがそもそも足りていないことが多い。

・タスク管理
　・言われてからやることが多い
　・言われたことをただやることが多い
　・作業の背景を知ること。そのほうが結果スムーズに行く。
　・新人だからといって気張らずどこかに余白を残しておいたほうが良い
　　・突発的に入ってくるタスクを処理しきれなくなる
　・段取り力
　　・段取り八割、ただ残りの二割で最も集中して取り組むこと。
　　　・最後にミスをすればすべてが水の泡となる。
　・優先順位付けとさくさく終わらせること。ボールを持ちすぎない。

・フットワーク
　・若手の頃に慎重さはいらないし期待されていない

・問題解決
　・大雑把に物事の全体構造を捉える→図示
　・物事を分解する→図示されたパーツを階層型の論理構造に切りなおす
　・精密に洗い出す→表形式でリストアップ

・コミュニケーション
　・赤色と言われても、りんごの赤なのか血の赤なのか。
　　・人によって認識は様々。
　　・そこをなんとなくのままにしておかない。
　・自分の考えなしの質問はただその人の時間を奪っているに過ぎない。
　・基本的にジャッジを仰ぐまでは自分でできるだけ思考する。
　・最悪どうしても何もわからなければごめんなさいして聞く。
　・上記をいかに早く回すか。

・その他仕事全般
　・物事を複数の視点から捉えること
　・目的と目標を常に頭においておくこと
　・PDCAのサイクルを早く回すこと
　・仕事における当たり前の基準値が圧倒的に異なる
　・普通のことを普通に、当たり前に確実に収めていくこと。
　　・そういった人が信頼される。
　・自分の好きがなにかを知ること。
　　・好きこそものの上手なれという言葉がありますが、そのとおり。
　　・自分の強みを知り、強みが活かせるフィールドで戦うこと。
　・自分の役割を自分の中で狭めないこと。
　　・任されたことをやり通すことは最低限必要
　　・その外に目を向けていき、周りのサポートを積極的に。
　・すごいと思う人は共通してエネルギーの総量が半端ない。常に元気。
　・先輩に飲みに誘われたら基本的には行くように
　・メモを取ること
　・元気以外に求められていることはあまりない。
　　（元気さだけは絶やさないように）
　・分け与える人になること
　　・地獄と極楽に住む人の話
　　・地獄に住む人も極楽に住む人も同じく長い箸を使ってご飯を食べる
　　・ただ地獄にいる人は長く食べづらい箸で頑張って自分で食べようと
　　　するが、極楽に住む人はその箸で他の人に食べさせるという。
　　・自分が自分がとならず、分け与える人になりなさいという教訓
　・仕事のスピード感
　　・作業スピード、ほうれんそうのスピード、取り掛かるスピード

■あと読んだ本の気づきや学びなんかも以下に少し記載
・69　
　・楽しんで生きないのは罪。暗いやつは周りからエネルギーを奪う。
　・人生楽しんで周りにエネルギーを与えられる人間に。
　
・論語と算盤と私
　・誰に対してもいい人であろうとすることは誰に対しても薄情であることにほかならない
　・やったことに対して糾弾されることはあっても、やらなかったことに対して
　　糾弾されることはない
　・開き直るとは覚悟を腹に落とすこと、無責任とは覚悟を他に委ねること

・桜の樹の下には瓦礫が埋まっている
　・本当に伝えなければいけないことはなにか、華やかなことばかりではなく
　　厳しい現実にも目を向けなければいけない。
　・必要なのは期待でも頑張りでもなくただ実現することのみ。

・１８時に帰る仕事術
　・時間を決めて段取り決めて実行するのみ

・ほうれんそう禁止で１日〜
　・仕事もプライベートも関係なくどうすれば人を幸せにできるのか、
　　感動させることができるのかを常に考えることによって、
　　仕事中もプライベートでもいい結果を残すことができる
　　（遊んだほうがいいというか、遊んでる人は１日の大半を人のために考える
　　　ことになるので、そりゃ強いよねと言う感じ。）

・鏡の法則
　・自分の力で解決できない問題にぶつかることは無い。その問題にぶつかった時点で、
　　ある程度そこに対してやってきているし、やれるだけの力はある。
　・やれないと思っているのは自分だけ。

・無敵の思考
　・最悪の状態を性格に理解すること。そこを理解した上で、それでも生きていけると
　　判断できればどんなチャレンジも恐れることはない。
　　　
・論理的思考力を鍛える〜
　・消極的義務が割と人こころに根付いている。よくあるのはトロッコ問題。
　・レバーを切り替えれば先の人は助かるが切り替えた先の人は死ぬという問題。
　・色々パターンはあれど基本的には何もしない選択が多い。
　・あと直接手を下すパターンだとなおのこと何もしない。
　　　

・２０代にしておきたい１７のこと
　・幸せな人は自分がどういう人かをよくわかっている人。
　・２０代のうちに自分は社会と何をもって繋がるかということを見つけられた人。
　・自分が社会に貢献したことはそのまま自分の人生に帰ってくるということ。
　・だから自分が社会に何を与えるかがとても重要になってくる。
　・そのためには何をしなければいけないのか。
　　・まず自分深く知ること。
　　・自分のルーツを知ること。
　　・幸せ、楽しいと思うことを追求することに全力を注ぐこと。

・自分を捨てる仕事術
　・自分には何もないということを自覚して心を空にし、
　　目指している人を真似することにより取り込む。
　・真似をしているうちに自分には合わないと思うところが出てきて、
　　本当の自分がおのずと見えてくる。
　・そこから自分は本来どういった人物で、どういったことに向いていて、
　　何をするべきなのかが見えてくる。

■あとがき
色々学んで、考えも揺れて、自分が何者か悩んで、
その中でもがいて転がって、それでも前に進んで。
今わかってることは答えはないということ。
とにかく前に進むしか無い。間違っててもいいから動くこと。
まだ１年の前半しかまとめられてないので、
後半戦をいつかまとめたいと思います。

つづく
WebGL?よくわからないけどブラウザで3DCGやるやつでしょ

タイトルぐらいの理解をしていたので、実際に手を出す前に概念を整理しておく。

# WebGL?OpenGL?わからん！

## GLSL(OpenGL Shade Language) 
OpenGLのプログラマブルシェーダーを記述するシェーディング言語

### そもそもOpenGLって？
クロスプラットフォームな2D/3D CGライブラリ、またはそれを元とするオープン標準規格
macOSで非推奨に
→代替はMetal

## HLSL(High Lebel Shading Language)
Direct3Dのプログラマブルシェーダーを記述するシェーディング言語

### Direct3Dって？
MicrosoftがWindows向けに開発した3DグラフィックAPI(DirectXの一部)。Xboxでも使われている

### プログラマブルシェーダー？
昔はシェーダーの各機能はハードウェア依存だったが、
(スーファミのグラフィックチップによる拡張とかの話か？)
ソフトウェアによりプログラマブルになったシェーダーのこと。

## WebGL
Webブラウザ上で2D/3D CGを扱うための、
Open GL ES2.0(組み込み向け規格)の派生規格。
HTML5のcanvas要素にGLSLを用いて記述する。
GKEでクラスタを削除してもDBのデータを保持したい

## はじめに
GKEでクラスタを作成してDBを起動していましたが、クラスタを削除するとDBのデータも消えてしまうので困っていました。

クラスタ外にデータを置いておけば解決するだろうと考えて調べたところ、パッと見つけた方法で解決したのでそのメモです。

他にもいろいろとやり方はあるかと思いますが、ここでは一例を扱います。

## どうやって対処したか
[永続ディスクを使用した永続ボリューム](https://cloud.google.com/kubernetes-engine/docs/concepts/persistent-volumes?hl=ja) には以下のように記述があり、

>ほとんどの場合、PersistentVolume オブジェクトを直接構成したり Compute Engine 永続ディスクを作成したりする必要はありません。PersistentVolumeClaim を作成すると、Kubernetes が自動的に永続ディスクをプロビジョニングします。
~省略~
>この要求を削除すると、対応する PersistentVolume オブジェクトとプロビジョニングされた Compute Engine の永続ディスクも削除されます。

GKEではPersistentVolumeClaimを使用して動的にPersistentVolumeが用意された場合、
クラスタを削除したタイミングでDBデータも削除されるようです。

DBデータを保持したい場合には、[既存の永続ディスクを PersistentVolume として使用する](https://cloud.google.com/kubernetes-engine/docs/how-to/persistent-volumes/preexisting-pd?hl=ja)で記述されている通りにCompute Engineに永続ディスクを用意してPersistentVolumeで使用します。


まずは、クラスタのゾーンを確認します。
>注: 永続ディスクは、クラスタノードと同じゾーンに存在する必要があります。

```bash
$ gcloud container clusters list
NAME       LOCATION       MASTER_VERSION  MASTER_IP      MACHINE_TYPE  NODE_VERSION    NUM_NODES  STATUS
```

次に永続ディスクをクラスタノードと同じゾーンに用意します。
sizeやtypeは適宜置き換えます。

```bash
$ LOCATION=xxx #上記で確認したLOCATIONを設定する
$ gcloud compute disks create pd-name --type pd-standard --zone $LOCATION --size 10GB --quiet
```

あとは、[既存の永続ディスクを PersistentVolume として使用する](https://cloud.google.com/kubernetes-engine/docs/how-to/persistent-volumes/preexisting-pd?hl=ja)で記載されている通り、`PersistentVolume `と`PersistentVolumeClaim `のマニフェストファイルをapplyしてPodでマウントしてあげればOKです。

これでクラスタを削除しても永続ディスクは消えないのでデータが保持されました :tada: 

## 追記
上記の方法だと複数nodeから書き込みできませんでした。

https://cloud.google.com/kubernetes-engine/docs/concepts/persistent-volumes#deployments_vs_statefulsets
>注: 複数のノードから永続ディスクに書き込みモードで同時接続することはできません。

しかし、対応方法は用意されています。

https://medium.com/asl19-developers/create-readwritemany-persistentvolumeclaims-on-your-kubernetes-cluster-3a8db51f98e3
>The steps you need to take for this installation are:
- Create a Google Disk instance with your desired capacity.
- Create the nfs-server deployment and service.
- Create your PV and the corresponding PVC with special specs.

こちらを参考にしました。

クラスタ内にnfs-serverを用意して永続ディスクとつなぎ、DBをnfs-serverとつなぐという感じです。

Cloud Filestore をつかう方法もあるようですが、容量が1TBからとなっているので費用が高くなるので選択肢としては厳しいなと思いました。