OmniAICreator/Qiita-1.07M huggingface dataset:
Laravel 5.8でオリジナルのイベントを定義してみた話

# はじめに

`こちらの記事は、社内knowledgeからの移行記事になります。`

Laravelで自作イベントを定義するまでの一連の流れ。

【参考にした公式】

- [公式(英語)](https://laravel.com/docs/5.8/events)

- [ReaDouble](https://readouble.com/laravel/5.8/ja/events.html)

【参考記事】
- [Laravel5.7でEventを利用してみる - qiita](https://qiita.com/zaburo/items/3a712bae293f3f222f17)
  

【ソース】
- [GitHub](https://github.com/suupoo/illuminate-laravel-study/commit/6ba7e6f0b9f9a1a763d19099787924237007159c)

# 環境

- Laravel 5.8.23

# 本編

### 1.イベントとリスナをサービスプロバイダに定義

```php:application/app/Providers/EventServiceProvider.php
protected $listen = [
    'App\Events\TaxIncreased' => [
        'App\Listeners\TaxIncreasedNotification'
    ],
];
```

  

### 2.Artisanコマンドでイベントとリスナを作成

```sh
# php artisan event:generate
Events and listeners generated successfully!
```
### 3.リスナにイベント処理を定義
今回は発生したイベントのオブジェクトを返すだけ。
  
```php:application/app/Listeners/TaxIncreasedNotification.php
public function handle(TaxIncreased $event)
{
    return $event;
}

```


### 4.イベントを定義

```php:application/app/Events/TaxIncreased.php
public $name;
public $price;
public $taxRate;
public $taxIncludingPrice;

/**
 * TaxIncreased constructor.
 *
 * @param string $name
 * @param int $price
 * @param bool $isReduceTax
 */
public function __construct(string $name, int $price, bool $isReduceTax){
    $this->name  = $name;
    $this->price = $price;
    $this->taxRate = ($isReduceTax) ? 0.08 : 0.10;
    // 税込み価格計算
    $this->taxIncludingPrice = (int) $this->price * ( 1 + $this->taxRate);
}
```



### 5.イベントを呼び出す

今回はコントローラのアクションからイベントを呼び出す。

```php:application/app/Http/Controllers/HomeController.php
 public function index()
 {
     $eatIn   = event(new TaxIncreased('タピオカ',1000,false))[0];
     $takeOut = event(new TaxIncreased('タピオカ',1000,true ))[0];

     return view('home',compact(['eatIn','takeOut']));
 }
```

## 結果

軽減税率イベントが発火した。

![image01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/338551/168bfdfb-10b7-baa0-cd53-f1f04f330b13.png)
Macショートカットキー

※自分用にまとめ中


##スリープ
| キー操作 |目的 |
|:--|--:|
|Ctrl + Shift + 電源ボタン | ディスプレイのみスリープ|
|Cmd + Opt  +  電源ボタン	| スリープ|
|Ctrl + Cmd + Q | スクリーンロック |

##再起動
| キー操作 |目的 |
|:--|--:|
|Cmd + 電源ボタン | 再起動 | 
|Cmd + Ctrl + 電源ボタン | 強制再起動 | 

##ログアウト
| キー操作 |目的 |
|:--|--:|
|Cmd + Shift +  Q	|ログアウト（確認あり）|
|Cmd + Opt + Shift +  Q	| ログアウト（確認なし）|


##強制終了
| キー操作 |目的 |
|:--|--:|
|Cmd + Opt + Shift + Esc（長押し）|最前面のアプリケーションを強制終了|
|Ctrl + Opt + Dockアイコンをクリック | 強制終了のコンテキストメニューを表示 |


##ウィンドウの操作
| キー操作 |目的 |
|:--|--:|
| Cmd + W | ウィンドウを閉じる |
| Cmd + M |ウィンドウを Dock にしまう | 
| Cmd + Ctrl + F | ウィンドウの最大化・元に戻す |
| Cmd + H |アクティブウィンドウを隠す | 
| Ctrl + F3 | Dock上のアプリケーションを起動|
| Cmd + Tab (+ Shift で逆順）| アプリケーションの切替え|
| Cmd + Q |アプリケーションの終了|


##Finder の操作
| キー操作 |目的 |
|:--|--:|
|Cmd + ↓ |子フォルダ移動/選択アイテムを開く/アプリケーションを開く| 
|Cmd + ↑|親フォルダ移動|
|Cmd + I | 選択したアイテムの情報を見る|
|Cmd + O | ファイル/フォルダを開く|	
|Ctrl + Cmd + G|フォルダの場所を入力|

##スクリーンショット
| キー操作 |目的 |
|:--|--:|
| Cmd + Shift + 4 | スクリーンショット |

##カーソル移動
ホームポジションに手を置いたままカーソル移動が可能。
※Eclipse上で使えない・・・

| キー操作 |目的 |
|:--|--:|
|Ctrl + F | カーソルを右へ |
|Ctrl + B | カーソルを左へ |
|Ctrl + P | カーソルを上へ |
|Ctrl + N | カーソルを下へ |
|Ctrl + A | 行頭に移動    |
|Ctrl + E | 行末に移動    |
ESPの書き込みができなくてハマった


# 現象

ESP32にファームウェアの書き込みはできるが、シリアルモニタでログを見ようとすると動かない。

- ESPの`make monitor`コマンドが失敗する
- miniterm.py / arduinoIDEでシリアルに接続すると、ESPが固まる
- シリアル接続しない場合はESPは正常に動く


### ESPの`make monitor`の失敗例１

```
$ make monitor ESPPORT=/dev/tty.usbserial-DQ0007XM
MONITOR
--- WARNING: Serial ports accessed as /dev/tty.* will hang gdb if launched.
--- Using /dev/cu.usbserial-DQ0007XM instead...
--- idf_monitor on /dev/cu.usbserial-DQ0007XM 115200 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
Exception in thread Thread-2:
Traceback (most recent call last):
  File "/Users/kido/.pyenv/versions/2.7.10/lib/python2.7/threading.py", line 810, in __bootstrap_inner
    self.run()
  File "/Users/kido/.pyenv/versions/2.7.10/lib/python2.7/threading.py", line 763, in run
    self.__target(*self.__args, **self.__kwargs)
  File "/Users/kido/Documents/extra/obniz/obniz-firmware/esp-idf/tools/idf_monitor.py", line 120, in _run_outer
    self.run()
  File "/Users/kido/Documents/extra/obniz/obniz-firmware/esp-idf/tools/idf_monitor.py", line 200, in run
    data = self.serial.read(self.serial.in_waiting or 1)
  File "/Users/kido/.pyenv/versions/2.7.10/lib/python2.7/site-packages/serial/serialposix.py", line 509, in read
    raise SerialException('read failed: {}'.format(e))
SerialException: read failed: [Errno 6] Device not configured
```


###  ESPの`make monitor`の失敗例2
ログが一部しか保存してなかった

```
.../site-packages/serial/tools/miniterm.py, line 63, in write_bytes self.byte_output.write(byte_string) 
TypeError: a bytes-like object is required, not 'int'
```

# 原因


Serialの設定がうまくできていなかった模様



# 解決法

SerialのFlashModeを正しいものにする（デバイス依存）。

仕様書はこちら
https://github.com/espressif/esptool/wiki/SPI-Flash-Modes


設定方法がわからなかったので、arduino IDEをつかってFlashModeをDIOにした
<img width="567" alt="スクリーンショット 2019-11-26 13.32.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227015/832cf8a8-c890-e566-ccef-a8231ef4b6d5.png">

一度設定すればずっと有効みたいなので、抜いて刺しても問題なく動いた


### (参考)上の解決に行くまでにやってみたこと

- FDTI社のUSB-Serialドライバーの再インストール
- miniterm.py / ArduinoIDE / screen 等のシリアルモニタでの接続

`make monitor`の失敗例２ → `make monitor`の失敗例1　に行くまでに、上記を色々やってたので、
そこら編の影響もがあるかも・・・？



#追記

失敗例２が再発して、なかなか直せなかったので、暫定対処として下記コマンドで対応中

make monitorが失敗するなら別コマンドでminiterm動かしちゃえばいいじゃない

```
 make flash ESPPORT=/dev/tty.usbserial-00004314  ESPBAUD=1500000 && miniterm.py /dev/tty.usbserial-00004314 115200
```
Primitives vs Objects

#What is the difference between primitives and objects?###

Variables holding primitives actually holds the value of the primitive inside the variable.

Variables associated to an object doesn't hold the object but holds a reference to where the object is stored. It points to the object.

```JavaScript
// Primitives
var a = 23;
var b = a;
a = 46;
console.log(a); // 46
console.log(b); // 23

// Objects
var obj1 = {
  name: 'John',
  age: 26
};

// New object is not created but rather a new reference to the same object is created
var obj2 = obj1;
obj1.age = 30;
console.log(obj1); // 30 
console.log(obj2); // 30

// Functions
var age = 27;
var obj = {
  name: 'Jonas',
  city: 'Lisbon'
};

function change(a,b){
  a = 30;
  b.city = 'San Francisco';
}

change(age,obj);
console.log(age); // 27
console.log(obj.city); // San Francisco

```

***When a primitive is passed to a function as an argument, rather than the actual variable, a copy will be passed. This means that the variable passed will not be affected.***

***When an object is passed, it's actually the reference to the object that is being passed and that is why the change is made to the object.***
processingで原子のモデルを動かしたい　立体の重なり方がおかしい

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197731/d176d4c5-215d-89b0-7b44-13677e3982fc.jpeg" width=50%>

↑
こんな感じのを電子を動かして見せたいなと思った。

```java

float t =0;
void setup() {
size(500,500,P3D);
noStroke();
lights();
}

void draw() {
  fill(255,50);
  rect(0,0,width,height);//backgroundではなく不透明のrectでリフレッシュすることで残像をつける
  fill(153);
translate(width/2,height/2,0);
sphere(25);//原子核
fill(255,0,0,10);//k殻原子領域の色
sphere(100);//原子領域を示す透明

fill(0,255,0,10);//l殻の領域の色
//sphere(150);


fill(0,0,255,255);//電子を示す色



pushMatrix();//電子の回転用

pushMatrix();
rotateZ(t+5);//z軸で回す
translate(100,0,0);//z軸で回す
sphere(10);//電子
popMatrix();

pushMatrix();
rotateX(t+4);//x軸で回す
translate(0,0,100);//x軸で回す
sphere(10);//電子
popMatrix();

pushMatrix();
rotateY(t+2);//y軸で回す
translate(100,0,0);
sphere(10);//電子
popMatrix();



pushMatrix();
rotateX(TWO_PI/8);
rotateY(t);//斜め軸で回す
translate(100,0,0);
sphere(10);//電子
popMatrix();


popMatrix();//電子の回転終わり
  



  t=t+TWO_PI/(60*3);
}
```

これで実行してみると
![8f8wk-dxkjm.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197731/e9b3a7c9-4e91-92a2-cb3f-7d56cd2174d6.gif)


電子が後ろに回ったときに、なぜか消えている。
原子の部分は赤色で透明度を設定しているのにおかしい。

http://tercel-sakuragaoka.blogspot.com/2011/11/p3d.html
調べてみると上のサイトに
processing : P3D モードのヘンなクセ
ということで記述されていた。　P3Dだと仕方ないことらしい

setup()の部分に

```
  hint(ENABLE_DEPTH_SORT); // ←追加 
```
を追加するといいらしい

描画方式をデフォルトのZ バッファリングから画家のアルゴリズムに変更する　ことができているらしい


そうしたら
![xqese-wp7eb.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197731/fe47c66a-02b1-7b93-6f95-dd1ac6b816cc.gif)


うまくいった。
obnizのサーバレスイベントでのはまりポイント＆Tips

obnizを使っているとサーバレスイベントを活用するタイミングがあると思います。

特に12月発売予定のobniz board 1Yではスリープが使えるようになるのでサーバレスイベントを使うと他になにも用意せずにセンシングするようなIoTのサービスをつくれます。

https://blog.obniz.io/ja/news/obniz-board-1y-2/

![obniz board 1Y](https://blog.obniz.io/wp-content/uploads/2019/11/IMG_00172.jpg)


今回は私がサーバレスイベントを作るにあたってはまったポイントやTipsをまとめます。

# サーバレスイベントとは

公式ドキュメント：https://obniz.io/ja/doc/obniz_cloud/about_event

> obnizを使うには外部にobnizを使うためのプログラムが必要ですが、obnizクラウドのイベント機能を使えばサーバーレスでプログラムを動作させられます。

> obniz Eventはあらかじめ設定したトリガーが発生したときに登録しておいたプログラムを自動的にクラウド上で実行するサービスです。
これによりあなたは自分でプログラムを動かして無くてもトリガーとプログラムだけ設定しておくことで、何かが起きた時にクラウド内で自動的に処理を行えます。

上記公式から引用しましたが私なりの言葉でまとめると、**サーバを用意しなくても各自で作成したプログラムを、後述するトリガーをきっかけに実行してくるツール**といった感じでしょうか？

## トリガー

- Webhook（APIが生成される）
- 決められたある時間(11:11など)
- 決められた時間の間隔(1時間毎など)
- obnizがオンラインになったら
- obnizのボタンが押されたら

現在5つのトリガーがあります。
指定されたobnizIDで指定されたトリガーがあったときに、各自のプログラムが実行されます。

## 制約事項
11/27現在

- 実行できる時間は30秒以内、それ以上は終了される
- 1日に実行可能な回数は120回

すこし制約はありますが例えばセンサーの値を取得するプログラムであれば12分に1回はデータを貯められます。

# はまりポイント

## APIを使用したとき

次のようにAPIを使用するときエラーが発生することがあります。

```js
await fetch('https://maker.ifttt.com/trigger/obniz_temp/with/key/', {
  method: 'POST',
  mode: "no-cors",
  body: formData
}).then(()=>console.log("success")).catch((error) => console.log(error));
```

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/97208/c2f154d5-b27c-5a89-285b-3e9e2091d0c3.png)

このときにAPIの呼出し後に```await obniz.wait(1000)```をいれるとエラーが発生しなくなります。

# Tips

## 絶対にスリープさせる

センサーの値読み取りなど予期しないところでプログラムが停止してしまうなど可能性があります。

電池稼働しているデバイスではこの問題はクリティカルなので、サーバレスイベントが終了する前にスリープをするようにします。

（obniz board 1Yでのみ使用可能です。）

```js
 //Timeout 25s
let tid = setTimeout(()=>{
  let dt = new Date();
  dt.setMinutes(Math.floor(dt.getMinutes()/10)*10+10,0,0);
  obniz.sleep(dt);
  obniz.close();
},25000);
```

こんな感じでスリープするプログラムをobniz.onconnectの外でも呼び出せば問題ないかと思います。

他にTipsがあれば追記していこうと思います。

# まとめ

obnizの便利機能であるサーバレスイベント、そのはまりポイントとTipsを簡単にまとめました。

定期的にセンシングしてみたいなと思ったら、ぜひ一度さわってみるとよいでしょう！
Tableauでレーダーチャートを作った日

#参考
http://blog.livedoor.jp/tab_hiro/archives/cat_365998.html?p=2

https://ksugii.tumblr.com/post/168495305379/%E3%83%AC%E3%83%BC%E3%83%80%E3%83%BC%E3%83%81%E3%83%A3%E3%83%BC%E3%83%88%E3%83%9E%E3%83%8B%E3%82%A2%E5%90%91%E3%81%91
#注意
・座標軸の値を合わせる
・0の値に微小な数値を当てはめることでチャートの崩れを無理やり防ぐ
ssh接続方法

#SSH接続ができるようになるまで
パスワード認証を聞かれたくない人用です

まずは公開鍵と秘密鍵を作成

```
ssh-keygen
```
これで
id_rsa.pub　公開鍵
id_rsa　秘密鍵
ができます。

公開鍵をサーバーにアップロードしてそれをauthorized_keysとして登録

```
ssh-copy-id -i ~/.ssh/id_rsa.pub user@xxx.xxx.xx.xx
```

サーバー側の設定を書き換える

```
sudo vim /etc/sshsshd_congig
```
`PublickeyAuthentication yes`のところ＃をとってコメントアウトを外し、sshdを再起動する

```
service ssh restart
```

最終的にこれで接続すればパスワード聞かれない

```
ssh -i ~/.ssh/id_rsa.pub user@xxx.xxx.xx.xx
```
要素を右下に配置 ❏CSS❏

・親要素に
`position: relative;`

・子要素に
`position: absolute`
`right: 0;`
`bottom: 0;`

をあててあげましょう。

```xxx.css
.contents {
  position: relative;
}

.content {
  position: absolute;
  right: 0;
  bottom: 0;
}
```

<br>
ではまた！
[php] switchで比較演算を使うときの注意

これに似たコードをレビューしていて

```php

$age = 10;
 
switch ($age) {
 
  //年齢が20歳以上、50歳以下
  case $age > 20 && $age < 49:
    echo '21~49歳です。';
    break;
 
  //年齢が50歳以上
  case $age > 50:
    echo '50歳以上です。';
    break;
 
  default:
    echo "該当しません。";
    break;
}
```

### 出力: 該当しません。

で、気になったので、

```php

$age = 0;
 
switch ($age) {
 
  //年齢が20歳以上、50歳以下
  case $age > 20 && $age < 49:
    echo '21~49歳です。';
    break;
 
  //年齢が50歳以上
  case $age > 50:
    echo '50歳以上です。';
    break;
 
  default:
    echo "該当しません。";
    break;
}
```

### 出力: 21~49歳です。

# ん？

該当しませんじゃないの？
(ていうか私はswitchに比較条件入れようとそもそも思わないですが）

1以上は 「該当しません」が出力されます。
0のときだけ先頭が評価されます。

教えてえろいひと。
Railsチュートリアル 第10章  - 「div.paginationが無い」と言われてテストが失敗する場合

# 何が起こったか

Railsチュートリアルも第10章まで進み、[ユーザー一覧のテスト](https://railstutorial.jp/chapters/updating_and_deleting_users?version=5.1#sec-users_index_test)を一通り書き終えました。しかし、以下のように「`div.pagination`が無い」と言われてテストが通りません。

```
# rails test test/integration/users_index_test.rb
Running via Spring preloader in process 12045
Started with run options --seed 11902

 FAIL["test_index_including_pagination", UsersIndexTest, 2.137264299992239]
 test_index_including_pagination#UsersIndexTest (2.14s)
        Expected at least 1 element matching "div.pagination", found 0..
        Expected 0 to be >= 1.
        test/integration/users_index_test.rb:12:in `block in <class:UsersIndexTest>'

  1/1: [===================================] 100% Time: 00:00:02, Time: 00:00:02

Finished in 2.14716s
1 tests, 2 assertions, 1 failures, 0 errors, 0 skips
```

# 解決

`app/views/users/index.html.erb`や`app/controllers/users_controller.rb`の記述に間違いがないのにテストが通らない場合、fixtureの記述を間違えているのが原因かもしれません。

私の場合は、fixtureにおける以下の記述間違いが原因でした。

```diff:test/fixtures/users.yml（抜粋）
  ...
  <% 30.times do |n| %>
- user_<% n %>:
+ user_<%= n %>:
    name:  <%= "User #{n}" %>
    email: <%= "user-#{n}@example.com" %>
    password_digest: <%= User.digest('password') %>
  <% end %>
```

これは気が付きにくい。
[UE4]エディタの解像度

絵作りを詰めていく際、
最終的なクォリティアップの為にレンダリング解像度を引き上げることはよくあるかと思うのですが、
エディタでも高解像度で見たい…！ということ、ありますよね。
<img width="943" alt="2019-11-27_18h31_47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/2698ee0d-acf7-bf7a-a5c6-d915bb96b292.png">
ここの項目でエディタの解像度を調整することが可能です。
<img width="944" alt="2019-11-27_18h32_03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/0b2c3182-3b69-89a5-ea93-3d72c29e0974.png">
チェック時は200にして高精細に、普段の作業は軽快に行いたいので50で荒く、とできて便利です。
![res1000.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/6e9cc408-e5dc-e104-384f-19168f2275bc.gif)

ちなみに50-200の幅は、SceneView.hで決められちゃってるのでこの範囲で我慢して下さい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463796/5617f4a3-25fd-174d-ef06-656eac9b6056.png)
SumologicでGCP Loggingを解析する

# 背景
AWS向けはマニュアルや第三者の投稿がたくさん見つかりますが、GCP向けはあまり見つからなかったのでQiitaに落としておきます。
一応、Sumologicの公式サイトでかなり丁寧なマニュアル(＊1)が用意されているのですが、ところどころつまづいたので備忘も兼ねて。

# 構成
こんなことを実現します。
![Sumologic GCP.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51320/af0b959a-0e9d-9cd4-e8c3-194a3aa43604.png)


# 手順
## ①GCEのVMインスタンスのログをStackdriver Loggingにストリーミングする
GCPではエージェントもマニュアル(＊2)も用意されていて、デフォルトのままで基本的な動作はするので、簡単！
捕捉することもないので、ここでの解説は割愛します。

## ②Pub/Subにエクスポートする
Stackdriver Loggingでは、今回のようにPub/Subを介したサードパーティとのつなぎ込みや、BigQueryで利用するために、ログデータをエクスポートする機能が用意されています。詳細は公式ドキュメント(＊3)を。

エクスポート先やフィルタを、「シンク」にて定義することでエクスポートが開始されます。
GCPコンソールのログビューアで、エクスポートしたい情報を表示している状態（GCE VMインスタンスのログを表示中とか）で、「エクスポートを作成」することで、表示中のログ群でフィルタしたシンクを定義することができます。

予め作成しておいたPub/Subを指定することもできますが、初回であればシンク作成時にPub/Subトピックを新規に作成する方が、必要なロールも自動生成してくれるため、おすすめです。

ここまでで、Pub/Subトピックにログがエクスポートされるようになっているはずです。
<img width="967" alt="Sub – cloudpack-invoice – Google Cloud Platform 2019-11-27 17-45-06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51320/4d8db731-116b-c312-d433-08ea96d81986.png">

## ③Sumologicでコレクターを追加する
ここからが、本題。Sumologicのマニュアル（以降、「Sumologicマニュアル」と記載）(*1)を片手に進めます。
先に書いた通り、Sumologicマニュアルがかなり丁寧なため、ここでは詳細には書かずに、留意点を捕捉する形で記載します。

まずは、Sumologicコンソールでの作業になります。
手順6.のFieldは省略可能。
手順7.で最初は「Copy URL」でなく「Create URL」ボタンが表示されていると思います。
一度、「Create URL」ボタンを押下することで、マニュアルどおり「Copy URL」が表示されます。


「Steps to add the Source's URL as an allowed domain in GCP:」と記載されているところから、しばし、GCPコンソールの作業に移ります。
手順d.で、「Domain」という表記で僕は混乱しましたが、ドキュメント記載どおり、手順7.でコピーしたURLを貼り付けでOKです。
手順g.でHTMLファイルをダウンロードします。ファイルに記載された文字列（google-site-verification: 〜）を確認します。

ここで、Sumologicコンソールでの作業に戻ります。
手順g.で確認した情報を入力します。ファイル名はそのままファイル名です。フルパスでなくてOKです。
必要に応じて、オプション設定をし、Saveします（〜手順11.）。

GCPコンソール（ウェブマスターセントラル）に戻り、Verifyします。
ウェブマスターセントラルの「3. Confirm」は無視して大丈夫なようです。（ここで僕は結構迷いました）

## ④Pub/Subサブスクリプションの設定
若干、GCPコンソールのUIは変わっていますが、ほぼSumologicマニュアルのとおりに進められます。
サブスクリプションIDは任意のもので大丈夫です。

## 動作確認
以上にてSumologicでGCPのログを解析できるようになりました。

こんな感じでログを参照できるかと思います。

```
_sourceCategory="gcp" and _collector="GCP"
```

<img width="1430" alt="SourceCategory - gc1 | Log Search | Sumo Logic 2019-11-27 18-37-44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51320/3b92f60d-605d-3c22-7770-1b7f7369ad5a.png">


# まとめ
個人的にはAWS向けのマニュアルの方がわかりやすかったです。
ただ、これは今後改善されそうに思います。
１回やっちゃえば後は流用できるので大きな問題ではないかと。
機会があれば、Azureでも試してみます。

## 参照
(＊1) https://help.sumologic.com/07Sumo-Logic-Apps/06Google/Google_Cloud_Functions/Collect_Logs_for_the_Google_Cloud_Functions_App
(＊2) https://cloud.google.com/logging/docs/agent/installation
(＊3) https://cloud.google.com/logging/docs/export
【Django】Modelを作成後makemigrationsを実行してもNo changes detectedになる

# 現象
新規にmodelを作成後、makemigrationsを実行しても下記のような出力となり、マイグレーションファイルが作成されない現象に遭遇したので、その対応策をメモ。

```sh
# modelを新規作成後下記コマンドを実行
$ python manage.py makemigrations
No changes detected
```

# フォルダの構造

※詳細は割愛

```
app
├─migrations
├─models
│  ├─__init__.py
│  ├─accounts.py
│  └─users.py　　　　# 今回新しく追加したmodel
└─views
   ├─__init__.py
   └─account.py
```

# 原因

どうやらmodelsフォルダに分割してmodelを作成している場合は\__init__.pyに新規で作成したmodelをインポートしないと認識してくれないらしい。

## もともとの\__init__.pyの中身

```python:app/models/__init__.py
from accounts.py import AccountsModel
```

ここに新しく追加したusers.pyを追加する。

```python:app/models/__init__.py
from accounts.py import AccountsModel
from users.py import UsersModel # 新規に追加
```

## 再度実行

```
$ python manage.py makemigrations
Migrations for 'app':
  app\migrations\0002_users.py
    - Create model UsersModel
```

無事に作成できました！
【Laravel】Carbonで今が上期下期を判断する

Laravelを用いてますが、`Carbon`は`composer`から入れれるので同じです。

上期は基本的に4月から9月末、下期は10月から3月末のようなので、そのように定義します。

今回は`web.php`にコールバックに書いていきます

```php:web.php

Route::get('/',function(){
    $start = today()->month(4)->firstOfMonth();
    $end = today()->month(9)->endOfMonth();
});

```
上期の開始と終了を定義しました。
`today()`はLaravelに用意されているヘルパです。
`new Carbon('today')`と同等になります。

```php:web.php

Route::get('/',function(){
    $start = today()->month(4)->firstOfMonth();
    $end = today()->month(9)->endOfMonth();
    echo today()->between($start , $end ) ? '上' : '下');
});

```

あとは、今日が上期の範囲内か判断しているだけです。
SQLServer 2017インストール

#Win2016 + SQL Server 2017のスクショ

##1.左のインストール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/3522525b-48fb-ef18-2b55-20aba239bfef.png)

##2.一番上のSQC Serverの新規…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/cfbfd24d-5916-ae66-cdcb-73b1ee443779.png)

##3.プロダクトキー入力（とりあえずtrial版で）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/001b9893-eb8e-e6de-ea12-fbb7a387a4ad.png)


##4.ライセンスに同意
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/319382b3-bfb7-70d7-a1e5-1ca5a9d19e18.png)

##5.次へ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/4472a433-a9f8-321a-803a-9571f7787342.png)

##6.とりあえず、データベースエンジンサービスだけチェックして次へ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/07fe437c-5f33-e344-a365-a6334e4f310d.png)



##7.次へ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/1ea2f4f3-1477-de6f-53c5-eedc4980c83e.png)


##8.次へ
サービスアカウント
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/2dc568e9-2d84-1e2b-dc89-07be33a50399.png)


照合順序
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/24d1ba33-7192-8a93-4b5b-635d8d43402a.png)


##9.次へ
サーバーの構成（現在のユーザーの追加を押す＝今administratorで操作中）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/9f159ceb-2264-a2eb-c7f6-67b97e847cb5.png)


データディレクトリ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/a4941f7e-2b86-8aaf-b8f6-b62dd8589f84.png)


TempDB
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/6dc40fab-6879-432c-17f3-e9352a2d204a.png)


FILESTREAM
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/d91b6904-8303-16bc-123a-2a5dd8a04294.png)


##10.インストール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/b87915f1-dcd7-ea53-ad4e-ab477ee9494a.png)


##11.OK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/82174fc7-3778-4f7e-a109-b4810aa8e91b.png)


##12.閉じる（reboot)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/19c48c2a-703a-f481-101e-899b301500fe.png)




#Win2016 + SMSSのスクショ
##1.インストール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/624ec161-4fea-187b-b053-9d5e6c79fe99.png)

##2.閉じる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/e13fa610-f541-517f-cd44-c0b0308dcd4b.png)
話を聞く人の「伝える」技術

# コミュニケーションは「送受信」の繰り返し

コミュニケーションスキルというと、何を思い出しますか？
主に、**伝える技術**ではないでしょうか？
**正しく伝える、わかりやすく伝える、相手に慮って伝える・・・**

最近、1on1をはじめとする、**メンバーのモチベートに寄与するコミュニケーション**
が強く求められてくる中、この必要性はとても大きくなってきました。

そもそも、コミュニケーションとは、その目的に応じ、**「何かを伝える人」**と**「それを聞く人」**に分かれ、
会話の中で、立場が都度都度変わっていきます。

伝える人の「伝えるスキル」が足りないと、相手は誤認してしまったり、全然違うアクションをとってしまう事となります。
また、どちらかが上司・先輩のように、権力が入ってしまう事で、「伝え方」が高圧的になってしまうなどの、
バイアスがかかってしまったりします。

こういったとき、

聞く人は、**「あの人は、伝え方が下手くそだ」**
伝える人は、**「あの人は、理解力が無い」**

となりがちです。この不幸なすれ違いへの対処法は、

**伝える側の伝えるスキルだけではなく、聞いている側の「伝えるスキル」にも依存する。**

という趣旨で書いていきます。

# 「聞く側」が頑張る、二つの事

聞く側が伝える側に頑張って伝える、二つの事。それは、

- **相手がなぜ「今の話をしているか」の背景を意識する**
- **伝えてくれたことを、自分が正しく理解しているか、相手に確認する**

## 相手がなぜ「今の話をしているか」の背景を意識する

これを語りだすと、またそれはそれで長いのですが、いわゆる「傾聴」＋αです。
今回書きたい事ではないので、またの機会に。

## 伝えてくれたことを、自分が正しく理解しているか、相手に確認する

そして今回のお話。
このプロセスを踏む人は、意外と少ないが、とても大切なプロセスで、意外とハードルが高いものです。

### 何をしたらいいのか

やることは凄く簡単です。

- **自分の言葉で**
- **相手の伝えてくれた内容をまとめて**
- **相手に伝え**
- **確認しあう**

の4つをするだけで、今までのコミュニケーションロスはかなり少なくなります。
少し細かく見ていきましょう


### 1. 自分の言葉で伝える

自分の言葉にすることで、自分の理解度を計ります。
理解できていないときは、相手の言葉をそのままなぞっていたり、どこかのサイトで読んだ表現を
そのまま使っていたりします。

> ■ 酷い例
> 「心理的安全性とは、メンバーの心理的安全を担保することだから、とても大切なんだ」」
> とかですね。なんで大切なのか、とかまったく理解できていない感じです。

稚拙でも酷くても良いから、自分の言葉で伝えましょう。
こういった努力をしないと、**わからない事がわからなくなる。**という、とても不幸な事が起きます

### 2. 相手の伝えてくれた内容をまとめる

内容をまとめる時、自然と、**重要だと感じている事**を残します。
これがとても大切で、「相手が重要だと思っていること」と「自分が重要だと思っていること」が、
正しく一致しているか。誤解は無いか。その判断をする材料となります。

自分の言葉で伝える理由にもなるのですが、ここでまとめた内容は、
**「誰かに伝える時」にも自然と使われることになります。**

### 3. 相手に伝える

当たり前だろ。と思った方いませんか？
実は、これやってない人すごく多いんです。

仕様誤認でプログラムを間違えて記述する事例として、一番多いのではないでしょうか。
何を伝えるのか、どこまで伝えるのか、いつ伝えるのか、などなど。。。

聞く側のセンスが一番出る所です。

但し、本当に伝えるべきことは、先述した通り、**自分の理解が正しいかどうか、自分の言葉で伝える。**という事です。

これは、「会議進行が書かれた議事録」が読まれない理由にも近く、
全部読んでも、会議を思い出す。しかないので、自分も相手も得るものが無い。
大切なのは、結論に対する意識があっているかどうか。です。

### 4. 確認しあう

理解してもらおう。で終わってはいけません。
なぜなら、このフェーズに入った瞬間に「伝える側」と「聞く側」が逆転したからです。

次に返ってくる言葉を正しく理解できるように、相手の表情観察や、傾聴に入ります。

# 簡潔に言うと、「フィードバックループ」

コミュニケーションをとる二人が、お互いにこの4つのプロセスを踏みあう事で、
お互いの考えに理解が深まり、より建設的なコミュニケーションが取れるようになります。

普段の議論も、1on1も、なぜ「一人で考える」のではなく、対話するのか。
成長に行き詰まりを感じた時、ペアプロするとよかったりするのか。
それは、

**相手の脳内で、自分の意見や知見が熟成され、返ってくる。**

からです。これを双方でポジティブにやることで、その効果は更に跳ね上がります。

このフィードバックループは、「相手」が始める事を期待していても始まりません。
是非、自分から始めていきましょう。

# そうそう世の中甘くない

フィードバックは、常に「良い」フィードバックだけではありません。
辛い現実、合わない考え、すれ違う心。。。色んな事が起きます。

これを、いかにポジティブに変換していくか。本当はそういう「聞き手のスキル」も
無茶苦茶大切です。これはまたの機会に書いていきたいなと。

# まとめ

- 話す側のスキルだけに依存したコミュニケーションでは、破綻しますよ
- 聞く側の伝えるスキルが、コミュニケーションを更に良いモノに変換してくれます

という事でした。

コミュニケーションは、常に送受信。どちらが欠けても意味が無いということを心において、
日々のコミュニケーションを、実りあるものにしていきましょう。
Rubyで長い文字列を書く時の備忘録

Rubyで複数行に渡る長い文字列を作成する際の備忘録です。

文字列を作成する際、シングル（or ダブル）クオーテーションで囲う書き方が一般的です。

```ruby:ダブルクオーテーション
a = "長い文字列です。
     複数行にわたる文字列は
     読みにくいですね。"
```

こう書けばもっと読みやすいよ。

```ruby:ヒアドキュメント
a = <<TEXT
長い文字列です。
複数行にわたる文字列は
読みにくいですね。
TEXT
```

TEXTはただの識別子なので、TEXTでなくても良いです。
識別子を指定できるので、文字列について何かわかりやすい文言を指定できるというのも
メリットの1つです！

以上、備忘録でした！

### 参考文献
[プロを目指す人のためのRuby入門](https://gihyo.jp/book/2017/978-4-7741-9397-7)
= ヌジョレーボーボー in haskell


# 元記事

[ヌジョレーボーボー @mattn](https://qiita.com/mattn/items/ae764601862b0073071e)

> mattnさん
>
>> ```
>> [
>>   ["ボ", ""],
>>   ["ジョ", ""],
>>   ["レ", "ー"],
>>   ["ヌ", "ー"],
>>   ["ボ", "ー"]
>> ]
>> ```
>> この 1 element 目だけを shuffle して全体 flatten みたいなのが綺麗に書ける言語は強そうですね。

---

これについて自分なりに書いてみた
Haskell初心者なのでこれ以上綺麗にできなかった...

```haskell
module BeaujolaisNouveau where

import Control.Arrow
import System.Random
import Control.Monad

main :: IO ()
main = do
    let beaujolaisNouveau = [ ["ボ", ""]
                            , ["ジョ", ""]
                            , ["レ", "ー"]
                            , ["ヌ", "ー"]
                            , ["ボ", "ー"]
                            ]
    res <- (liftM concat $ liftM concat $ shuffle1st beaujolaisNouveau)
    putStrLn res

shuffle1st :: [[a]] -> IO [[a]]
shuffle1st xs = do
    xs' <- shuffle $ fstL xs
    return $ zipWith (\x y -> [x, y]) xs' (sndL xs)


shuffle :: [a] -> IO [a]
shuffle (x:[])= return [x]
shuffle xs = do
        pickedIndex <- randomRIO (0, (length xs) - 1)
        let picked = xs !! pickedIndex

        rest <- shuffle $ restOf (pickedIndex + 1) xs
        return $ picked : rest

restOf :: Int -> [a] -> [a]
restOf _ (x:[]) = []
restOf n xs     = take (n - 1) xs ++ (drop n xs)

fstL :: [[a]] -> [a]
fstL []     = []
fstL (x:xs) = head x : fstL xs

sndL :: [[a]] -> [a]
sndL []     = []
sndL (x:xs) = head (tail x) : sndL xs
```

# 結果

![スクリーンショット 2019-11-27 17.50.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222594/35d50a45-95b4-15f0-6226-aa6dba0d3b75.png)

[2019-11-27 17:43]
GAS 今のところできるもの～スプレッドシート編

function s(){
  
 var sheet = SpreadsheetApp.getActiveSpreadsheet(); //アクティブシートを取得
 var a =sheet.getActiveRange().getValue(); //アクティブな範囲の値を取得
  Browser.msgBox(a);//値をポップアップ表示

}

function henkan() { //オブジェクトに割り当てて使用
  var targetSheet = SpreadsheetApp.getActiveRange(); // ①変換したい文字のある列や行をクリックしてアクティブにする
  var finder = targetSheet.createTextFinder("あ"); // ②あを検索する
  var cnt = finder.replaceAllWith("い"); // ③いに変換する
  SpreadsheetApp.getUi().alert(cnt + "件置換しました。"); //④終了を伝える。
} （編集済み） 

↑範囲指定したセルにある「あ」を「い」に置換するgas
変換したいセルとしたくないセルがある場合に使用するために作成
【Python】数字が入ったListを文字列結合して出力ファイルへ書き出す

`pickle` とかありましたが、数字が入っているとバグるようなので原始的にやります。

```python

data = [[1,2,3,4,5,6], [1,2,3,4,5,6]]

def c(data):
    outputfile = open("./output.txt", "w")
    for d in data:
        if(len(d) == 6):
            str_list = map(str, d)
            write_data = ",".join(str_list)+"\n"
            outputfile.write(write_data)
    outputfile.close()

c(data)
```

結果

```text:output.txt
1,2,3,4,5,6
1,2,3,4,5,6
```

Point
- 一度使用したファイルのcloseを忘れずに
- mapで要素全てをStringに変換
Vuetifyのv-messagesのmin-heightを0pxにしたい

#背景
- エラー文言とかを入れるdivがvuetify使うとデフォルトでついてくる
- デフォルトはmin-height 12pxだからレイアウトが結構崩れるので0pxにしたい

# 解決
- deep selectorで解決

```html
<style>
>>>.v-messages {
  min-height: 0px !important;
}
</style>
```

# 参考
- https://stackoverflow.com/questions/50985783/vuetify-css-not-working-taking-effect-inside-component
特定パス以下のActionController::RoutingErrorでJSONを返却する

## 環境
Ruby 2.5.7
Rails 5.2 (ActionPack 5.2)

## コード

```lib/middleware/routing_error_response_json.rb
module YourNameSpace::Middleware
  class RoutingErrorResponseJson
    RESPONSE_JSON_PATHS = %w[/api/v1]

    def initialize(app)
      @app = app
    end

    def call(env)
      request = ActionDispatch::Request.new(env)
      status, headers, response = @app.call(env)
      # NOTE: ActionController::RoutingError時に設定されるパラメータ
      # See https://github.com/rails/rails/blob/5-2-stable/actionpack/lib/action_dispatch/journey/router.rb#L64
      if enable?(request) && status == 404 && headers['X-Cascade'] == 'pass'
        status, headers, response = pass_response(status)
      end 

      [status, headers, response]
    rescue Exception => exception # rubocop:disable Lint/RescueException
      raise exception
    end

    private

    def pass_response(status)
      [
        status,
        { "Content-Type" => "application/json" },
        [
          JSON.generate(
            {
              title: 'Routing Error',
              detail: 'No route matches',
              invalid_params: []
            }
          )
        ]
      ]
    end

    def enable?(request)
      RESPONSE_JSON_PATHS.any? { |path| request.path.to_s.start_with?(path) }
    end
  end
end
```

```config/initializers/middleware.rb
require_relative "../../lib/middleware/routing_error_response_json"
::Rails.application.config.middleware.use YourNameSpace::Middleware::RoutingErrorResponseJson
```

## 実現できる事

↑の例であれば `/api/v1` 以下へのリクエストでRoutingErrorとなった場合にJSONを返却する事ができる。
WebとApiが同居しているアプリケーションなどで利用価値があるかもしれない。

## 最後に

もっと良い方法があれば教えて欲しいです。
Rubyのreturn備忘録

Rubyでメソッドを定義する際、他の言語経験者だと戻り値を返すためにreturnを使うことが多いかと思うのですが、
Rubyの場合はreturnを使わない書き方の方が主流です。

```ruby:メソッド定義（return版）
def add(a, b)
  return a + b
end

add(1, 2)
```

```ruby:メソッド定義（主流版）
def add(a, b)
  a + b
end

add(1, 2)
```

returnはメソッドを途中で脱出する場合に使われることが多い。
以下の例は、引数がnilの場合はgreetingメソッドを抜けるようreturnを使っています。

```ruby:returnの書き方
def greeting(country)
  return 'countryを入力してください' if country.nil?

  if country == 'japan'
    ・・・  
end
```

以上、備忘録でした！

### 参考文献
[プロを目指す人のためのRuby入門](https://gihyo.jp/book/2017/978-4-7741-9397-7)
クイズ：なぜバリデーションエラーになるでしょう

### 要約
- railsのcallbackで中間テーブルを生成する方法をミスるとvalidationエラーになるアンチパターン

### 詳細
- モデル構成

```ruby
class User < ApplicationRecord
  has_many :notification_settings, dependent: :destroy
  has_many :notifications, through: :notification_settings, dependent: :destroy
  after_create :create_default_notifications
end

class NotificationSetting < ApplicationRecord
  belongs_to :user
  belongs_to :notification

  validates :user_id,  uniqueness: { scope: [:notification_id] }
end

class Notification < ApplicationRecord
  has_many :notification_settings, dependent: :destroy
  has_many :users, through: :notification_settings, dependent: :destroy
end
```
とかで、ユーザに通知設定が複数ひもづいている状態で、ユーザが作成されたタイミングでデフォルトの通知設定を作りたくて`create_default_notifications`の中で

```ruby
def create_default_notifications
  self.notifications = Notification.all
end
```
てやっていると一見OKっぽいんだけど、`validates :user_id,  uniqueness: { scope: [:notification_id] } `で引っかかってvalildationエラーになる。

### 理由

```ruby

self.notifications = Notification.all
```
が評価されたタイミングでNotificationSettingにinsertが発行されてしまって、
その後autosaveも動くので、結果2回createされてしまってuniqueじゃなくなってエラーになる。
has_manyにassignすると即insertされるというのがわかりにくかったという問題。
=はsaveされないという思い込みでした。

### 修正
丁寧に1件1件buildする

```ruby

Notification.all.each do |notification|
  self.notification_settings.build(notification: notification)
end
アドテク単語～学んだ分のまとめ

DSP
広告打つ側のサービス

SSP
広告枠持ち側のサービス

ビッドリクエスト
SSPからDSPへ送られるユーザー情報等

Cookie
syncして広告配信タゲに使う。
safariはITP2.3で即消しされるが、他は問題なし

MAID
iOS・Androidの識別ID デバイスID、端末IDとも言う
railsをheroku にデプロイする際に注意すること

# railsをherkuにデプロイする手順

```terminal:ターミナル
$ git add .
$ git commit -m "release to heroku"
$ heroku create アプリ名
$ git push heroku master
```
 
# 注意１　herokuはsqlite3でビルドできない。production環境はpostgresにする

```rb:gemfile
gem ' sqlite3' #コメントアウト

#以下を追加する
gem 'sqlite3', group: [:development, :test]
gem 'pg', group: :production
``` 
上記の設定を忘れると

```terminal:ターミナル
remote:  !     Failed to install gems via Bundler.
remote:  !     Detected sqlite3 gem which is not supported on Heroku:
remote:  !     https://devcenter.heroku.com/articles/sqlite3
```
というエラーがでて怒られる。

# 注意2 herokuにデプロイしたら、heroku上のデータベースに反映させる必要がある

```terminal:ターミナル
heroku run rails db:migrate
```
これを忘れるとブラウザを開いても以下のようなエラーが出る

```
We're sorry, but something went wrong.
If you are the application owner check the logs for more information.
```
grepでタブ文字をマッチさせる時

英数字＋Tab+数字　で構成されるレコードから、
英数字＋Tab+0.0の行を抽出したかった。


先頭の英数字には0.0がくる可能性があったので、
『0\.0$』と指定してその前にタブ文字を付けて

```
'\t'0\.0$
```
としてもマッチしなかった。


正解は、

```
$'\t'0\.0$
```
で、タブの部分は『 $'\t' 』でした。
python sqlalchemyでoracleに接続しようとするとUnicodeDecodeErrorが出る

Python3.7 sqlalchemyでoracleに接続しようとしたら下記エラーが出てしまった。
cx_Oracle単体ではoracleに接続できているようなので何が原因がよくわからなかった。

なかなか情報にたどり着けず、
encodingとかcharsetとかずいぶん遠回りしたので記載しておきます。

参考）
http://blog.kzfmix.com/entry/1361525164

```出たエラー
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x98 in position 11: invalid start byte
```

下記をpyのソースに埋め込んでエラーが解決した。

```
import  os
os.environ["NLS_LANG"] = "JAPANESE_JAPAN.AL32UTF8"
```
Pythonで数字to漢数字の変換

# きっかけ
テストケースで1郎2郎3郎...みたいなのを作ってたんですが、
名前にアラビア数字というのもいかがなものかと思いまして、変換してやるようにしました。

# int2kanint
`python3.7.5`で動いてます

```python:int2kanint
# -*- coding: utf-8 -*-

import csv

def int2kanint(num) :
	suji   = ["","一","二","三","四","五","六","七","八","九"]
	kugiri = ["","十","百","千"]
	tani   = ["","万","億","兆","京","垓","𥝱","穣","溝","澗","正","載","極","恒河沙","阿僧祇","那由他","不可思議","無量大数"]

	num  = list(map(int,list(str(num))))
	kansuji = []

	for k, v in zip(range(len(num)), reversed(num)) :
		keta = []
		keta.append(suji[v if v>2 else 0 if k%4 else v])
		keta.append(kugiri[k%4 if v>0 else 0])
		keta.append((tani[0 if k%4 else int(k/4) if any(list(reversed(num))[k:(k+4 if len(num)>=(k+4) else len(num))]) else 0]))
		kansuji.append("".join(keta))

	kansuji = "".join(reversed(kansuji))

	return kansuji if kansuji else "零"
```

以下に説明を連ねていきます。

## 変数
説明が怪しい日本語になってますが、何となく察していただけると幸いです。

| 変数名 | 意味 | 型 |
| :-: | :-- | :-: |
| suji | 一から九までの漢数字です | string[] |
| kugiri | 十,百,千といった区切りです | string[] |
| tani | 四桁区切りの単位です | string[] |
| num | 変換前のアラビア数字です | int → int[] |
| keta | 四桁区切り毎の漢数字です | string[] |
| kansuji | 変換後の漢数字です | string[] → string |

# 変換方法
`suji`,`kugiri`,`tani`でそれぞれ分けて、最後に結合する形をとっています。
私が習った漢数字のルールを基に、それぞれ変換を行っていきます。
地域差、業界差あるとは思いますがそこは一旦置いておきましょう。

## suji
それぞれの桁の値を表す一から九の漢数字には以下のルールがあります。

* 値が0でない限り、`零`は省略する
    * 例：4203 → 四千二百三
    * `〇`とする場合がありますが今回は含めません
* `十`,`百`,`千`の前にくる`一`は省略する
    * 例：11111 → 一万千百十一

よって
**値が`２以下`かつ`一の位ではない`のであれば省略、それ以外は出力**
と考えれば良いでしょう。
そのため、`suji`を出す為の処理は以下のようになります。

```python:suji
suji[0 if v<2 and k%4 else v]
```

`suji`はインデックスと漢数字が連動してるリストです。
上記の条件を満たしていれば空文字を、それ以外の場合は漢数字を返す形になります。
（関数でもないのに返すというのも変ですが）

## kugiri
漢数字では四桁毎に数を区切りますが、その中で十,百,千とさらに桁を区切ります。
その際には以下のようなルールがあります。

* 桁に該当する値がなければ、省略する
    * 例：2035070 → 二百三万五千七十

これだけですね。

```python:kugiri
kugiri[k%4 if v>0 else 0]
```
内容もシンプルです。

## tani
漢数字では四桁毎に数を区切りる際には以下のルールがあります。

* 四桁の中身がなければ、単位を表す漢数字は省略する
    * 例：123400005678 → 千二百三十四億五千六百七十八

ここだけ見ればシンプルなんですが、私のアルゴリズムではかなりややこしくなってしまいました。
というのも、与えられた値を漢数字に変換する際に、以下のようなfor文で各桁を参照しています。

```python3:for文
for k, v in zip(range(len(num)), reversed(num)) :
```
`k`にはインデックス、`v`には各桁の値が入るわけですが、`reversed(num)`としてるように一桁目から見てるわけです。
処理としては **四桁毎に単位を出力する** と考えるのですが、四桁の中身がない場合、単位を省略しなければなりません。
そうすると必然的に四桁先を見ればいいだけなんですが、値が四桁もない場合を考慮しなければならないわけです。

解決策としては以下のとおりです。

```python3:tani
tani[0 if k%4 or not any(list(reversed(num))[k:(k+4 if len(num)>=(k+4) else len(num))]) else int(k/4)]
```
**値が`十,百,千の桁である`または`四桁の中身が１つもない`のであれば省略、それ以外は出力**という形に落ち着きました。
`any`で四桁分の値を参照しに行くのですが、四桁先がリストの末尾を超えた場合、末尾まで参照する、といった感じです。

# 終わりに
競技プログラミングとも言えなくもない、アルゴリズムを考える課題は大好きなので、ついつい熱中して作ってしまいました。
数字to漢数字はいくらでもやりようがあると思うのですが、リストを使ったやり方は今回初めて思いついたので、とても楽しかったです。
高速化・簡易化できる書き方がありましたら、ぜひともご教授ください！
PySpark で when をチェーンしたときの処理順序

PySpark で `when` をチェーンするコードを書いていたときに

「これって SQL と同じように先に書いた `when` が優先される？」
「メソッドチェーンだから後ろに書いた `when` で上書きされる？」

と不安になったので、実際に検証コードを書いて調べた。

## ダミーデータ
``` python
df = spark.createDataFrame([(1,),(2,),(3,)], schema=('val',))
display(df)
```

|val|
|---|
|1|
|2|
|3|

## Spark SQL の場合
``` python
# Spark SQL から触れるように一時テーブルとして登録
df.registerTempTable('tmp')
```

``` sql
SELECT
  val,
  CASE
    WHEN val <= 1 THEN 'label_1'
    WHEN val <= 2 THEN 'label_2'
    ELSE 'label_3'
  END AS label
FROM tmp
```

|val|label|
|---|---|
|1|label_1|
|2|label_2|
|3|label_3|

SQL の場合は当然、先に書いた `WHEN` の条件が優先される。

## PySpark の場合
``` python
from pyspark.sql import functions as F

df_label = df.withColumn('label',
    F.when(F.col('val') <= 1, 'label_1')
     .when(F.col('val') <= 2, 'label_2')
     .otherwise('label_3')
)
display(df_label)
```

|val|label|
|---|---|
|1|label_1|
|2|label_2|
|3|label_3|

PySpark で `when` をチェーンした場合でも、Spark SQL と同様に先に書いた `when` の条件が優先されるらしい。
Kubernetes(AKS)導入奮闘記〜その４〜

# 目次

 - **既存環境の置き換え**
 - **環境リプレース時の問題**
 - **Azureで実装待ちの要素技術**
 - **その後**

# ◆既存環境の置き換え

 - 十分テストしてから置き換えるべきで、そのテスト環境をどうするか？
 - CIとの連携で詰まる。

## 置き換え前の事前テスト環境
 - MySQLを含めてた既存環境のシミュレートは非常に困難で断念。
 - 仕方なく既存AzureマネージドMySQLを利用してテスト環境を構築する。
 - Redis Cacheも既存のものを利用しようとしたが管理情報が混ざってしまうようで、PHPのセッションタグなどで環境ごとに分ける必要があることが判明。
 - やむなくRedis Cacheは移行テスト期間中だけAKSクラスタ内の使い捨てRedis Podで運用することに。


## CIとの連携
 - リポジトリのソースコードを修正。
 - docker buildしてコンテナレジストリにpush。
 - CI環境でコンテナをロードして各種(セキュリティなど)チェック。
 - CI環境にデプロイメント。
 - CIのことはあまり考えていなかったので、ここが一番苦労しました。

ほとんど開発に関わっていなくてCIの仕組みを全然理解していなかった自分が悪いのですが。このリプレース作業を機にだいたい理解することができました。
インフラとかSREとか呼ばれるエンジニアはきついですね。ネットワーク/ストレージ/OS/ミドルウェアは当然のスキルとして、コンテナ運用では更にアプリの知識もなくてはならない。インフラのコード化を高度に追求している会社では更にCIの経験もなくていけない。更に運用や監視やプロジェクトマネジメントなどなど、、、そんなスーパーエンジニアはいない！！！と叫びたい気分です。


# ◆環境リプレース時の問題
 - 環境置き換えた後、旧Virtual Machine上のdocker-composeが起動しているとバッティグして動作しなくなる機能あり！想定してなかったので焦りました。
 - しばらくCIを回していたら、 `db migrate` していないことが判明！
 - かなり後になってから、 `docker-compose up` 毎に機能を実行していたことに気づく。kubernetes jobで機能作って必要な時に呼ばなくてはいけない。これは今現在もまだ対処していません。

失敗ばかりでしたね、とほほ。急いでkubenrtesの機能を使って対処した記憶があります。


# ◆Azureで実装待ちの要素技術
 - Cluster Autoscaler -> preview段階
 - Azure Kubernetes Service Ingress Controller -> k8s IngressとAzure Application Gatewayが統合されるはず

付記：
 - Cluster AutoscalerはAKSに仮想ノード(AWS Fargateみたいなもの)というものができて、どちらか検討中。ノードを意識しないでクラウド業者に任せられるので仮想ノードが優勢かな。
 - AKSのIngress Controllerは2019年中には完全に統合しないようなので、来年の課題とします。

# その後
半年以上前に既存Virtual Machine運用からほとんど無理やりKubernetes環境に移行したのですが、結果的に良かったと思います。
内容を振り返ると結構無茶苦茶なことしているのですが、スタートアップなのでいくらでもチャレンジを許してくれる雰囲気に救われました。
その後優秀な同僚がいろいろと仕組みを整えてくれて、今では見違えるようなシステムに仕上がっています。
本番環境にkubernetes導入を不安に思って二の足を踏んでいる会社がたくさんあると思いますが、苦手なストレージやDBやバッチ処理をクラウドマネージドにすることで十分運用可能だと思います。
その後のトピックはいつか記事にしたいと思います。
Kubernetes(AKS)導入奮闘記〜その３〜

# 目次

 - **コンポーネント分割への道**
 - **導入前の検証環境**
 - **AzureでのkubernetesであるAKSの特徴**
 - **Azureアプリケーションゲートウェイをどうするか？**
 - **SSL証明書をどうするか？**


# ◆コンポーネント分割への道
 - 当初docker-composeに乗っている全種類のコンテナをまとめて１つのPodとしてスケールアウトしようとしていたが、ヒアリングミスで勘違い。
 - 目的はコンテナの種類ごとにコンポーネント毎に分離して、各コンポーネント毎にスケールアウトしたいという要望だった。
 - このような事情によりコンポーネント分割へ。


# ◆導入前の検証環境
 - 当初MySQLもAKSクラスタ内部で検証しようとしていたが断念。
 - 既存リソース(MySQL)のもう１つのフロントエンド的な運用でテスト環境構築に至る。


# ◆AzureでのkubernetesであるAKSの特徴

 - azコマンドCLIとkubectlコマンドが統合されている。要するに、az login認証・権限 = kubeコマンドの権限。
 - コンテナの標準出力/エラー出力を自動的にagentがLog Analyticsに転送してくれる。syslogログドライバの設定などは必要ない。


# ◆Azureアプリケーションゲートウェイをどうするか？
普通に構築するとAzureアプリケーションゲートウェイを通過した通信が、グローバルIPアドレスを通じてバックエンドであるAKSクラスタにアクセスするので、セキュリティ的にかなり問題が残る。
これに対処するために以下の構築方法を採用しました。

 - Internal Loadbalancers with Application Gateway (AKS)  
    https://rinormaloku.com/prohibiting-direct-access-microservices-aks/  

![kouseizu](https://rinormaloku.com/wp-content/uploads/2018/01/Internal-LBAppGateway-1.png)

ちょっとわかりずらい図ですが。  

 - Public IPが露出するのは、Application Gatewayのみ。
 - Application Gatewayのバックエンド指定はAKS(kubernetes)内のサービス(大抵はnginx)のPrivate IP。

ただ、これを実現するためには、AKSクラスタ構築時に面倒な作業が必要です。

 - AKSクラスタを作成(デプロイ)すると自動で「MC_xxx_japaneast」などのリソースグループが勝手に作成される。
 - AKSクラスタのネットワークはカスタムで、 `172.xx.0.0/24` と作成したら、ゲートウェイ用のサブネットを `172.xx.1.0/26` などのように手動で用意してあげないといけない。
 - このMC_xxx_japaneastのリソースグループを指定して、さらに用意したサブネット `172.xx.1.0/26` を指定してアプリケーションゲートウェイを新規作成しないといけない。
 - あとは、ゲートウェイのバックエンドにAKSクラスタ内のService(大抵nginx)のExternal IPを指定すると通信が到達するようになります。

なんのことかさっぱり分からない人はネットワークを勉強してくださいね。


# ◆SSL証明書をどうするか？
 - 元々docker-composeでcertbotを利用して自動更新していた。  
 - 今回の移行作業を機にワイルドカード証明書にしようとしたが、Lets EncriptのDNS-01チャレンジでないとだめみたいで困る。  
 - しかもDNS-01チャレンジはAPI連携必須。お〇〇.comでDNSレコード管理していたので無理！将来Azure DNSでドメイン管理に移行しないと無理。  
 - AKS側もingressを使用しているわけではなくアプリケーションゲートウェイを利用しているのでnginx-ingressなどには頼れなく非常につらい。  
 - このようなわけで七転八倒したあげくに今回の移行ではあきらめました。  

付記：
半年以上経過した2019年末現在、いまだに完全に自動化は実現しておらず、、、まあDNSドメインが増えたりといろいろ環境の激変があったわけで。一生懸命格闘していた頃が懐かしいです。

# ◆次回
次回はいよいよ既存システムのリプレーズ作業なのですが、地獄をみることになります。。。
【非テストエンジニア向け】即効バグ出し技法集

こんにちは、@illypon です。
趣味でソフトウェアテストをやっている者だ。 

さて、[ACCESS Advent Calendar 2019](https://qiita.com/advent-calendar/2019/access) 8日目は、ソフトウェアテストが本業でない方にもできる、**早く・簡単に・重大なバグがポコポコ見つかる**汎用的なテストの技法を紹介します。

ラインナップは以下の通り。ぜひお試しください。

1. 画面遷移図A3印刷技法 (難易度★☆☆☆☆)
2. ぶん殴り技法 (難易度★★☆☆☆)
3. 椅子引き技法 (難易度★★★☆☆)
4. 間違い探し技法 (難易度★★★★★)

# 画面遷移図A3印刷技法

- **難易度:** ★☆☆☆☆
- **用法:** 1秒で見つかるような恥ずかしいバグを撲滅したいときに。

### やりかた

1. 画面遷移図をA3用紙などなるべく大きい紙に印刷します。
2. 印刷した画面遷移図を見ながら、テスト環境で同じ画面を遷移図の通りに順番に操作します。
3. 操作が済んだ画面遷移は紙上で大きく×を書き込んでわかるようにしてください。
4. すべての遷移をもれなく触れたら完了です。

### ここがポイント

紙に印刷することでページスクロールする必要がなくなるので、
スクロールのし過ぎでドキュメントを読み飛ばしてしまうということがなくなりますし、
視認性が良いので作業効率が全然違います。紙は偉大。
また、確認済みのところに×を書き込むという行為によって、確認もれを防止できます。
シンプルな技法ですが、これをやるだけでも1秒で見つかるようなバグはなくなりますよ。


# ぶん殴り技法

- **難易度:** ★★☆☆☆
- **用法:** 手っ取り早くバグを見つけて、設計からやり直した方がよさそうな雰囲気を作りたいときに。

### やりかた

|テスト内容|起こりがちな現象|効果|
|:----|:----|:----|
|長すぎる文字列を入力|●豪快にレイアウトが崩れる<br>●数値の見た目が指数表示になる|●文字列の折り返しや...による省略表現など、長すぎる文字列への対処漏れに気付く<br>●バリデーションの漏れや誤りに気付く|
|押せるものは何でも連打|●重複したデータが大量登録される<br>●APIが弱音を吐きだす<br>●非同期処理のキューが絶望的にたまる|連打への対処漏れに気付く|
|大量にデータを登録する|●データを1件も表示できなくなる<br>●画面が表示されるのに何秒もかかるようになる<br>●登録したデータを一括削除するすべがないことに気付き、絶望的な気持ちになる<br>●検索窓やページャーが必要だと気付く|大量データを想定することは大事だと気付く|
|でかすぎるデータを入力|●システムがだんまりになる<br>●そもそもPOSTできない<br>●登録したデータが生焼けになる|●バリデーションの漏れに気付く<br>●Webサーバーの設定誤りに気付く<br>●トランザクションによるデータの整合性が担保されないケースがあることに気付く|

### ここがポイント

この技法のコツは、**システムを破壊してやろうという悪意を持って一切の手加減をせずに悪い行儀をする**ことです。
連打するときは1秒間に10回は打てるように鍛え、理解できないほど長ったらしいCSVファイルを作り、
4GBを超える画像やPDFを作り、偽装したファイルを食わせ、大量の一括更新をさせたり、
やたら途中でキャンセルをしたり、いきなり電源を抜いたり、HDDをサーバーからぶっこ抜いたりしましょう。
ぶん殴り技法に弱いシステムは設計時の考慮がいろいろと足りていない可能性が高いので、
設計レビューからやり直すことをおすすめします。

# 椅子引き技法

- **難易度:** ★★★☆☆
- **用法:** エラーケースの考慮漏れがいつも多いんだよなぁってときに。

### やりかた

|テスト対象|テスト内容|起こりがちな現象|対策の例|
|:----|:----|:----|:----|
|ユーザー名を都度取得して表示に使っている画面 (たとえばチャットルームやテンプレートでのスニペット、データのプロパティなど)|よく使いこんだユーザーを削除|●ユーザー名の部分がundefinedになる<br>●ユーザに紐づくデータが見えなくなる|●ユーザー削除は論理削除にとどめておき、「ユーザー名(退会済)」のように表示できるようにする<br>●物理削除した場合、ユーザー名は「退会済ユーザー」のような表記に置換する|
|フロントエンドの画面全般|別ウィンドウで更新・削除されたデータを操作|●データ更新の競合が発生する<br>●APIからエラーコードが返るが適したエラーメッセージを表示しない|●データを操作できない旨や、リロードを促すメッセージを表示する<br>●APIのエラーコードに応じて意味の通じるメッセージをユーザーに表示する|
|外部サービス(他社APIなど)に依存した機能|●だんまりをエミュレート<br>●メンテナンスモード応答をエミュレート<br>●異常応答をエミュレート|●エラーログが大量発生する<br>●APIのエラーメッセージをそのまま表示してしまう<br>●よくわからないが失敗した処理がある|●事前にメンテナンスなどで外部サービスが停止することが分かっている場合は、その時間帯は外部サービスに依存した定期処理を停止する<br>●エラーレスポンスが返ってきたときのことを考慮した設計にする<br>●エラー時にユーザーはどうすればいいのか説明する|


### ここがポイント

いつまでもあると思うな参照先と外部API。初めからエラーケースのときの外部仕様を考えておきましょう。
画面や機能ごとにあまりにも担当者が違いすぎると、データがなかった場合の考慮漏れが起きやすくなります。
メッセージ一覧を確認するのも汎用的におすすめできます。正常系のメッセージしか定義していなかったらあやしいですね。
バックエンドAPIのエラーがフロントのどのシーンで起きうるのかが整理できているといっそうGoodです。

# 間違い探し技法

- **難易度:** ★★★★★
- **用法:** 万能にして最強

### やりかた

1. 理想通りに完璧にできあがったシステムであればこのように動くだろうというイメージを脳内に投影します。
1. 目の前にある現実と向き合ってください。テスト環境を触ります。
1. 理想と現実を比較して違うところ、違和感を感じるところがあれば、それは改善したほうがよい仕様であるか、もしくはプログラムの欠陥です。

### ここがポイント

この技法の素晴らしいところは、テスト設計をしなくてもほぼ網羅的にインシデントを検出できる上に、
同時に探索的テストまで実行できてしまうという点です。
そしてこれが難なくできるあなたはテストエンジニアが適職です。QAチームにようこそ！

# 終わりに

ぶん殴り技法と椅子引き技法については、わざわざテストをしなくても、
こういうテストをされても問題が起きないような設計をしよう！と注意するだけでも十分だったりします。
ぜひチェックリスト的に参考にしてみてください。

明日は @diescake が何かIndexdDBネタを書いてくれるみたいです。
あと、12/12も私がソフトウェアテストのネタを投稿する予定です。お楽しみに！
和暦の環境で西暦の日付の文字列をパースする/DateTime変数を西暦の文字列に変換する

#問題
Windowsのカレンダーを和暦にした状態で`yyyy/MM/dd HH:mm:ss`形式の**西暦の**文字列を`DateTime.Parse()`でパースすると、`yyyy`の部分が元号の年として認識されてしまいます。
また、`DateTime`型の変数を単純に`ToString()`すると、和暦の文字列が得られてしまいます。

```c#
 var date = "2019/11/21 01:23:45";
 Console.WriteLine(DateTime.Parse(date)); //令和2019/11/21 1:23:45

 var date2 = DateTime.Parse("令和1/11/21 01:23:45");
 Console.WriteLine(date2.ToString("yyyy/MM/dd HH:mm:ss")); //01/11/21 01:23:45
```

#解決方法
`DateTime.Parse()`および`ToString()`に特定のカルチャに依存しないカルチャ情報(`CultureInfo.InvariantCulture`)を指定してあげると、`yyyy`の部分を西暦として認識してくれます。

```c#
 var date = "2019/11/21 01:23:45";
 Console.WriteLine(
   DateTime.Parse(date, CultureInfo.InvariantCulture)
 ); //令和1/11/21 1:23:45

 var date2 = DateTime.Parse("令和1/11/21 01:23:45");
 Console.WriteLine(
   date2.ToString("yyyy/MM/dd HH:mm:ss", CultureInfo.InvariantCulture)
 ); //2019/11/21 01:23:45
```
vue-stripe-elements-plusで複数の<card>を使うとエラーになる問題の解決方法

## 背景

1. vueでstripeのカード入力UIを表示するために、[vue-stripe-elements-plus](https://github.com/fromatob/vue-stripe-elements) を使っていた。
2. 一つの画面で複数のカード入力UIを表示するとエラーになるので治したい

## 結論

https://github.com/fromatob/vue-stripe-elements
の代わりに
https://github.com/Cl3MM/vue-stripe-better-elements
を使うと良い。

## 注意

### ```<card>```タグの代わりに```<stripe-element type="card">```タグを使う必要がある。

オリジナルでは以下のように```<card>```タグが定義されている。vue-stripe-better-elementsではこれが無いので、```<stripe-element type="card">```と書く必要がある。

https://github.com/fromAtoB/vue-stripe-elements/blob/master/src/Card.vue

### createTokenの代わりに(stripe-elementのvueインスタンス).elements.createTokenを使う必要がある

stripe-elementのvueインスタンスは以下のようになっている。
elements配下にcreateToken関数があるらしい。

>Each component looks like this:
{
  type: 'card',         // element type (card, iban...)
  key: 'pk_test_xxxx',  // the stripe key used for this component,
  element: {/*..*/},    // the stripe element created by the Stripe library,
  elements: {/*..*/},   // the stripe elements created by the Stripe library,
  createToken: fn,      // the element's createToken function
  createSource: fn,     // the element's createSource function
  retrieveSource: fn    // the element's retrieveSource function
}
https://github.com/Cl3MM/vue-stripe-better-elements#what-you-get-for-free

## 解説

>Moreover vue-stripe-elements, prevents you from using multiple <stripe-elements/> components on the same page, as there is only one instance of the createToken and createSource methods needed to further process payment.
https://github.com/Cl3MM/vue-stripe-better-elements#why
Rubyの丸め誤差備忘録

小数点での計算の際、思わぬバグが生じたりする。

例えば0.1かける3が0.3にならない。

```ruby:丸め誤差発生
0.1 * 3.0

 => 0.30000000000000004
```

これはPCが10進数ではなく2進数で計算していることが原因なのですが、
上記コードから、以下のような場合が発生します。

```ruby:思わぬバグ
0.1 * 3.0 == 0.3 #-> false
0.1 * 3.0 <= 0.3 #-> false
```

そのため、Rubyで小数点の計算を行うときは、Rationalクラスを使う！
数字の後ろに『r』をつけることで利用できる！

```ruby:Rationalクラス利用
0.1r * 3.0r #->3/10

# 上記を利用すると・・・
0.1r * 3.0r == 0.3 #-> true
0.1r * 3.0r <= 0.3 #-> true
```

変数に小数点が入っている場合は、rationalizeメソッドを呼び出すことでRationalクラスの数値に変換することができる！

```ruby:rationalizeメソッド
a = 0.1
b = 3.0
a.rationalize * b.rationalize #-> 3/10
```

『分数になってるやないか！』というツッコミが聞こえてくる・・・
その場合はto_fメソッドを使って、分数を少数にしてくださいませ！

```ruby:to_fメソッド
(0.1r * 3.0r).to_f #-> 0.3

以上、備忘録でした！
```
### 参考文献
[プロを目指す人のためのRuby入門](https://gihyo.jp/book/2017/978-4-7741-9397-7)
AWS Solutions Architect Professional 合格記録


## どしたん
先日、**AWS Solutions Architect Professional**に合格したので
今回も取り組んだことを残します。

因みに、以前情報収集したメモは残しているので
そちらと被る内容は省略します。

## まず試験概要

[AWS 認定ソリューションアーキテクト – プロフェッショナル](https://aws.amazon.com/jp/certification/certified-solutions-architect-professional/)

**必要な知識など**
AWS２年以上相当の実務経験
主にAWSクラウドのアーキテクチャ設計/提案やデプロイに関する分野
エンタープライズ規模のスケーラブルな運用設計、デプロイ
AWS Well-Architected フレームワークの適用
Linuxなどのある程度の知識
など

## 前回からやったこと

※前回はこちら
[AWS ソリューションアーキテクトプロフェッショナル受けた記録 - Qiita](https://qiita.com/shinon_uk/items/ba839ba048ba439cc3ff)

改めて以前の敗因を記載すると主に
・少々特殊な日本語の読解力不足
・知識が明らかに足りないAWSサービスがあった
・コストを考えたアーキテクチャの設計ができなかった
・DBの知識が足りなすぎて時間をかけてしまった
です。

なので、以下に取り組みました。
①問題演習を繰り返して「試験問題」になれる
  こちら
  [AWS WEB問題集で学習しよう \| 赤本ではなく黒本の問題集から学習する方向け](https://aws.koiwaclub.com/)
　★いくつかに分けて**何周か**します。
　私は集中力がそんなにもたなかったので、5~10(x7問)で一区切りしてもう一回。

②想定試験範囲や問題集の中で、ほとんど知らないor使った経験がないサービスの学習/検証

```
私の場合はこちら
  ・AWS EMR(各種)
  ・Kinesis系(重要)
  ・Rekognitionなど
  ・Application Discovery Service
  ・Storage Gateway(種類が大事)
  ・AWS Batch
```
　検証する場合は、AWS公式のチュートリアル、またはQwiklabsがおすすめです。(以前の記事参照)

③複雑なアーキテクチャを設計する際や、移行の問題にてよく比較するサービスの料金体系や**連携方法**を学習

```
取り組んだ主な対象サービス
 ・S3
 ・DynamoDB
 ・DirectConnect,VPN
 ・Snowball,Snowmobile系
```
ちなみに試験概要見ればわかりますが、移行計画の問題だけでも15%出ます。
これは私の大きな弱点で前回致命的だったのでしっかり補完。
対象のAWSドキュメントを読むだけで十分なことも結構あります。

試験概要：下記AWSサイト内「試験ガイド」PDFファイルを参照。(2019/11/27)
https://aws.amazon.com/jp/certification/certified-solutions-architect-professional/

## 結果

時間余りませんでしたが、**合格**。

```
組織の複雑さに対応する設計：十分な知識を有する
新しいソリューションの設計：十分な知識を有する
移行の計画：十分な知識を有する
コスト管理：十分な知識を有する
既存のソリューションの継続的改善：再学習の必要あり
```

分野別でもこんな風に結果出ます。
前回まではSAでもコストがだめでしたが、初めて克服した・・・！

前日に受けた模擬試験はなんと50%
多分、疲れ果てた状態で流し見して解いたから・・・？
心が折れる手前もちろん総復習しました（正解がわからないから超大変だったが）

当日試験問題に解答していく毎に、自信5割/不安3割/**カオス2割**が増えていき、
最後の方は目が霞んでいましたが、結果を見て安心しました。

SAPを受ける方は、以前にSAAなどの試験を受けているかと思います。
できれば、**慣れているテストセンターで**受けられることをお勧めします。
私はずっと同じ会場で受けていますが、大正解でした。

あとは試験前に(飲む人は)**コーヒー**。
相当な集中力を要します。
試験中にトイレくらいはOKなはずなので大丈夫。

## まとめ

あくまで試験です。
AWS SAP試験用の対策を、努力して取り組めばちゃんと取れます。

今後は、実際にサービスを検証したり、実務で役立てたりしていこうと思います。
また、Dev系の資格やネットワーキングのSpecialistもタイミングを見て取得します。

今回改めて、会社で既に取得している方々の偉大さを感じました(笑)