OmniAICreator/Qiita-1.07M huggingface dataset:
会社で少し盛り上がった Project Euler をやってみる 018

# Problem 018
```
以下の三角形の頂点から下まで移動するとき, その数値の和の最大値は23になる.

   3
  7 4
 2 4 6
8 5 9 3
この例では 3 + 7 + 4 + 9 = 23.

以下の三角形を頂点から下まで移動するとき, その最大の和を求めよ.

              75
             95 64
            17 47 82
           18 35 87 10
          20 04 82 47 65
         19 01 23 75 03 34
        88 02 77 73 07 63 67
       99 65 04 28 06 16 70 92
      41 41 26 56 83 40 80 70 33
     41 48 72 33 47 32 37 16 94 29
    53 71 44 65 25 43 91 52 97 51 14
   70 11 33 28 77 73 17 78 39 68 17 57
  91 71 52 38 17 14 91 43 58 50 27 29 48
 63 66 04 68 89 53 67 30 73 16 69 87 40 31
04 62 98 27 23 09 70 98 73 93 38 53 60 04 23

```
---

# Answer 018 (Python)

```python3
class Problem18:

    DATA = [
        [75],
        [95,64],
        [17,47,82],
        [18,35,87,10],
        [20 ,4,82,47,65],
        [19 ,1,23,75 ,3,34],
        [88 ,2,77,73 ,7,63,67],
        [99,65 ,4,28 ,6,16,70,92],
        [41,41,26,56,83,40,80,70,33],
        [41,48,72,33,47,32,37,16,94,29],
        [53,71,44,65,25,43,91,52,97,51,14],
        [70,11,33,28,77,73,17,78,39,68,17,57],
        [91,71,52,38,17,14,91,43,58,50,27,29,48],
        [63,66 ,4,68,89,53,67,30,73,16,69,87,40,31],
        [ 4,62,98,27,23 ,9,70,98,73,93,38,53,60 ,4,23],
    ]

    def main(self):
        while(len(self.DATA) > 1):
            self.reduceOne()
        return self.DATA

    def reduceOne(self):
        lastLine = self.triangleMaxSumList(self.DATA.pop(), self.DATA.pop())
        self.DATA.append(lastLine)

    def triangleMaxSumList(self, l1, l2):
        return [max(l2[i] + l1[i], l2[i] + l1[i+1]) for i in range(len(l2))]

if __name__ == '__main__':
    p = Problem18()
    print(p.main()[0][0])
```
---

# (参考) Project Euler とは

[Project Euler](https://projecteuler.net/) はプログラミングで数学の問題を解くサイトです。問題は600問以上あるので、勉強に使うのも良し、楽しむのも良しです。

サイトに登録すれば、解答を submit することができ、その場であっているか判定してくれます。

また、問題だけであれば、日本語に翻訳された Wiki もあるのでそちらを見ながらやると捗ると思います。

[Project Euler(日本語訳)](http://odz.sakura.ne.jp/projecteuler/)
chaining template

### class化するまでもない、けれども、chain出来ると便利
### 使用イメージ
base64データをサイズ変更して且つフィルターを掛ける。

```js
 imgc(e.target.result)
   .fit({w:300,h:200,fa:2})
   .filter('grayscale')
   .filter('_median')
   .filter('sharpen')  
   .then((src)=>{
     let el = fn.ce('img');
     el.src =src;
     fn.g('list').appendChild(el);
  })
  ;
```

### object保持版、bind版ではない。
利点、発火しなければ値を確認できる。bindは格納されると後で値を確認できない。
欠点、発動関数がなければ、実行されない。実行忘れがある。一時期のsuperagent...end()のような。

### 発動関数は return戻り と Promise戻り
awaitやasyncは過剰に処理を止める要因になるため、周知が徹底されるまで避ける。

```js
 o.end=(log)=>{
      if(log) console.log(log);
      return o._done();
    }
 o.then=(caller)=>{return new Promise((sol)=>{
      let ret =o._done();
      sol(caller(ret))
     })      
    }
```
### 全部
entry関数でジェネレートして、thisやproto...を避ける。
end()かthen()が呼ばれるまではo._に値を格納しているだけ。

```js

(function(root){
  'use strict'
  /*lent*/
  let document=root.document
  ,Object =root.Object
  ,Promise =root.Promise
  ,console =root.console
  ;
  function entry(target){
    let o={};
    /*gather*/
    o._={};
    o._['target']=target;
    o._['a']=[];
    o._['oa']={}
    o.a=(obj)=>{o._['a'].push(obj);return o}
    o.oa=(obj)=>{Object.assign(o._['oa'],obj);return o}
    /*main*/
    o._done=()=>{
      let param=o._;
      //something...
      return param;
    }    
    /*emit*/
    o.end=(log)=>{
      if(log) console.log(log);
      return o._done();
    }
    o.then=(caller)=>{return new Promise((sol)=>{
      let ret =o._done();
      sol(caller(ret))
     })      
    }
    return o;
  }
  ;
  root.modname=entry;
})(this);
```
### proto...とか継承とか、まで考えるならclass。
使用イメージの件。dnd＞サイズ変更、フィルター適用＞表示
https://gnjo.github.io/imgc.js.test.html
消えないアイツ。(DELETEしてもレコードが消えない）

さてみなさん。
以下のトリガー関数のバグとその動作を指摘ください。（関数の直後で回答しますが）

環境 | PostgreSQL 9.4

```iketenai.sql
CREATE OR REPLACE FUNCTION update_test_data_changelog() RETURNS trigger AS $BODY$
BEGIN
  IF TG_OP = 'DELETE' THEN
    -- 削除時はIDを削除データに追加する
    INSERT INTO change_log (edit_id, data, deleted) VALUES (OLD.id, OLD.data, TRUE);
  ELSEIF TG_OP = 'UPDATE' THEN
    INSERT INTO change_log (edit_id, data) VALUES (NEW.id, NEW.data);
  ELSE
    INSERT INTO change_log (edit_id, data) VALUES (NEW.id, NEW.data);
  END IF;
  RETURN NEW;
END;
$BODY$ LANGUAGE plpgsql;

```

------

**こたえ**
DELETEしてもデータが消えない。（呪いか）
原因は 最後のRETRUN NEW;
削除したのに、RETURN NEWなんてしてるからおかしな挙動になるわけで。

一通り再現するなら以下のSQLを実行してみるといい。

```iketenai.sql
create table test_data (
    id serial not null primary key
    , data text not null
);

create table change_log (
    id serial not null primary key
    , edit_id int not null
    , data text not null
    , deleted BOOL NOT NULL DEFAULT FALSE
    , edit_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);

CREATE OR REPLACE FUNCTION update_test_data_changelog() RETURNS trigger AS $BODY$
BEGIN
  IF TG_OP = 'DELETE' THEN
    -- 削除時はIDを削除データに追加する
    INSERT INTO change_log (edit_id, data, deleted) VALUES (OLD.id, OLD.data, TRUE);
    -- RETURN OLD;
  ELSEIF TG_OP = 'UPDATE' THEN
    INSERT INTO change_log (edit_id, data) VALUES (NEW.id, NEW.data);
    -- RETURN NEW;
  ELSE
    INSERT INTO change_log (edit_id, data) VALUES (NEW.id, NEW.data);
    -- RETURN NEW;
  END IF;
  RETURN NEW;
END;
$BODY$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS update_test_data_changelog_trigger ON test_data;
CREATE TRIGGER update_test_data_changelog_trigger
BEFORE INSERT OR UPDATE OR DELETE ON test_data
FOR EACH ROW EXECUTE PROCEDURE update_test_data_changelog();

INSERT INTO test_data (data) VALUES ('data1');
INSERT INTO test_data (data) VALUES ('data2');
INSERT INTO test_data (data) VALUES ('data3');
INSERT INTO test_data (data) VALUES ('data4');

UPDATE test_data SET data = 'data1-1' WHERE id = 1;
DELETE FROM test_data WHERE id = 4;
```

data4が消えない。

で、修正は以下の通り、INSERT / UPDATEはRETURN NEW; DELETEは RETURN OLD;
で解決。

```imasara.sql
CREATE OR REPLACE FUNCTION update_test_data_changelog() RETURNS trigger AS $BODY$
BEGIN
  IF TG_OP = 'DELETE' THEN
    -- 削除時はIDを削除データに追加する
    INSERT INTO change_log (edit_id, data, deleted) VALUES (OLD.id, OLD.data, TRUE);
    RETURN OLD;
  ELSEIF TG_OP = 'UPDATE' THEN
    INSERT INTO change_log (edit_id, data) VALUES (NEW.id, NEW.data);
    RETURN NEW;
  ELSE
    INSERT INTO change_log (edit_id, data) VALUES (NEW.id, NEW.data);
    RETURN NEW;
  END IF;
END;
$BODY$ LANGUAGE plpgsql;
```

脱力するほどくだらないミスですが、気づけば一瞬だけど、知らないとハマるので。
テーブルの先頭から不要な行を削除する には

データソースには集計に必要としない情報が含まれていることが多くある。Power BI Desktop や Excel のクエリ エディター でその処理を施すのだけど、さて、どうしようかな:rolling_eyes: と、いうこともあろうかと。クエリ エディターの UI 操作のみで解決することは多いが、そうもいかないときは、Power Query(M言語)を記述しなければならない。難しいことではないですが、[Power Query M function reference](https://msdn.microsoft.com/en-us/library/mt779182.aspx) とにらめっこする時間が必要かも。

先日開催した Power BI 勉強会 でご質問いただいた内容のうちのひとつです。

# 行を削除したい、いくつかのパターン
クエリ エディター - [ホーム] - [行の削除] からの操作で多くの場合で操作ができるはず。
![クエリエディター リボン](https://qiita-image-store.s3.amazonaws.com/0/193509/99afd7c5-e998-2ac0-8eef-386299620eb1.png)

## 上位の行の削除 - 特定の行数
![クエリ1](https://qiita-image-store.s3.amazonaws.com/0/193509/95855f28-1a74-f175-cb7f-1069787b2300.png)
削除対象となる行は明らかであったり特定できる場合は、**不要な行数を指定し削除**することができる。このとき、中の人は [Table.Skip - Table functions][Table.Skip] を使用する。ダイアログで **行数** を投入することで 先頭から行の削除。
 
![ダイアログ 上位の行の削除](https://qiita-image-store.s3.amazonaws.com/0/193509/bb10b124-9b37-398d-4fae-e0d3ad933fef.png)

```text:該当のステップ
    RemovedTopRows = Table.Skip( PreviousStep , 2) // 先頭の2行をスキップ(削除)
```
てっきり、[Table.RemoveFirstN - Table functions][Table.RemoveFirstN] を使っているものと思い込んでいたので確かめていてよかった。同じ結果を得られるはずだけど、中の人が使っているのだからなんらか都合がよいのかもかな。

## 上位の行の削除 - 特定できない行数
csvでデータを入手できるラッキーと思ったら *まれによくある*。サマリ的なものやステータスのようなものがあったりして。
![クエリ2](https://qiita-image-store.s3.amazonaws.com/0/193509/fb1f8613-a413-7a91-aef3-2116a217b352.png)

クエリ エディター上のクエリとして読み込み、[列1] の値に "A"(text) が出現する以前の行を削除対象とするとき以下の通りになる。

```text:該当のステップ
    RemovedTopRows = Table.Skip( PreviousStep , each [列1] <> "A" ) // 列1 が "A"ではないときスキップ(削除)
```
```text:構文：Table.Skip
Table.Skip(table as table, optional countOrCondition as any) as table

Remarks
* Table.Skip is similar to List.Skip but requires a table as input.
* If countOrCondition is a number, that many rows (starting at the top) will be skipped.
* If countOrCondition is a condition, the rows that meet the condition will be skipped until a row does not meet the condition.

```
引数名からも解りますけど、第2引数 countOrCondition が number ではないんですね。

引数:countOrCondition が 

- number(行数) であるとき、該当する行数を先頭からスキップ
- condition(真偽) であるとき、評価が true である限り先頭からスキップ 

### 別の解
何行目までが該当するかカウントする方法も念のため。検証する列を限定してしまうけど。

```text:該当のステップ
    RemovedTopRows = Table.Skip(
        PreviousStep ,
        List.PositionOf( PreviousStep[列1], "A" )
    )
```

# その他
- [Power BI 勉強会 - connpass](https://powerbi.connpass.com/)
- [Power BI Desktop を使い始めるには](http://qiita.com/PowerBIxyz/items/6c4735cb5b5712e70981)
- [Excel で Power Query を使い始めるには](http://qiita.com/PowerBIxyz/items/52e563037b855a099ca9)

[Table.Skip]:https://msdn.microsoft.com/en-us/library/mt260831.aspx
[Table.RemoveFirstN]:https://msdn.microsoft.com/en-us/library/mt260779.aspx
[Table.RemoveLastN]:https://msdn.microsoft.com/en-us/library/mt260773.aspx
[Table.RemoveMatchingRows]:https://msdn.microsoft.com/en-us/library/mt260784.aspx
[Table.RemoveRows]:https://msdn.microsoft.com/en-us/library/mt260783.aspx
[Table.RemoveRowsWithErrors]:https://msdn.microsoft.com/en-us/library/mt260807.aspx
[Table.RemoveMatchingRows]:https://msdn.microsoft.com/en-us/library/mt260784.aspx
@jnchito さんのスクリプトで Kobito から Quiver にドキュメントを移行した

こちらのスクリプトを利用して、移行作業を終えました。
ありがとうございます。

> * [Kobitoのサポートが終了してしまったので、Quiverに移行するスクリプトを書いた - Qiita](https://qiita.com/jnchito/items/3a6861c179e2ab4a28a2)


個人的な環境の違いとタイミングが原因と思われる、手順の変更点がありました。
以下、作業メモです。


## Kobitoのdbファイルをdbディレクトリにコピーする

コピー後に markdown として出力されたファイルと Kobito 上のデータ件数が合いませんでした。

```prettyprinted
$ cp ~/Library/Containers/com.qiita.Kobito/Data/Library/Kobito/Kobito.db ./db
```

状況を調べてみると、Kobito.db が 2018/02/13 15:57 から後は更新されていないよう。
手作業で差分を反映させました。:stuck_out_tongue_closed_eyes:

```prettyprinted
% ls -al ~/Library/Containers/com.qiita.Kobito/Data/Library/Kobito/
total 61400
drwxr-xr-x  19 foo  staff      608  9 14  2016 ./
drwx------  32 foo  staff     1024  4  6  2017 ../
drwxr-xr-x  32 foo  staff     1024  2 19 16:11 Backups/
-rw-r--r--@  1 foo  staff  5038080  2 13 15:57 Kobito.db
-rw-r--r--@  1 foo  staff    32768  2 19 16:36 Kobito.db-shm
-rw-r--r--@  1 foo  staff  3605032  2 19 16:00 Kobito.db-wal
```


## Quiverのqvnotebookディレクトリをコピーする

インストール後、標準のままであればこのディレクトリ配下にファイルが存在します。

```prettyprinted
$ ls -lt ~/Library/Containers/com.happenapps.Quiver/Data/Library/Application\ Support/Quiver/Quiver.qvlibrary/ | grep .qvnotebook
```

自分は、設定を変更していたことを忘れていました。
`Preferences > Sync > Library Location` の設定が反映されているはずです。

下記のようにファイルを Finder 上に表示して、ファイル選択後 `cmd + c` で現在のパスを取得できました。

![quiver.png](https://qiita-image-store.s3.amazonaws.com/0/19223/721a4a2f-ec33-890d-6b69-8f3fc5ccc6d0.png)
iOS ブラウザのスクロールイベント

# 背景
github page で プロフィールサイト作ったのに ios のスクロールイベントがおかしい!


# touchmove イベント

スマホのスクロールは慣性スクロールがあるので `scroll` イベントではとぎれとぎれになる

スマホのタッチイベントは ｢押した時｣ ｢動かした時｣ ｢離した時｣ と段階毎に用意されているらしい

スクロールだけに限定すれば `touchmove` イベントが ｢動かした時｣ なので, 連続してイベントが発生してくれる.

```js
//...
window.addEventListener('scroll', this.handleScroll.bind(this));
window.addEventListener('touchmove', this.handleScroll.bind(this));
//...
```

のように両方用意しておくことでスマホでもPCでも同じようにイベントが発生する.


# window.outerHeight

スクロールとは直接関係無いのだけれど, iOS のブラウザだと `window.outerHeight` と `window.outerWidth` が 0 になってしまうバグ(?) があるらしいので注意すべき
checkIO( The Most Wanted Letter）　

・アルファベットのみを取得
import re
re.findall('[a-z]' ,lower_text)


・辞書から
dic.items()
dic.values()
で取得するとリストに変換することにわすれていた
だからその後はオフセットを使って指定できる。

・iteratorを継承しているモジュールの内の1つがlistやtuple
これから勉強

・フィルターに通して、フォーマットして、値を整形して、解析して、出力
問題を解くポイント
SQSとSESを上手く使って通知を出そう！（後編）

##どういう所に実装したのか
　前回の話から、今回はどこにどのように実装したのかを説明していきます。とは言っても至極かんたんな話です。
###SQS
 SQSはiDen（＝遺伝）と呼ばれる、コンテンツツリーを作り出すためのシステムに実装しました。iDenをもう少し詳しく説明すると、その名の通りコンテンツを遺伝させるための物で、例えばAさんが作ったキャラクターをBさんが借りて継承して創作したいときに、そのキャラクターをBさんはクリエイティブ・コモンズ（以下、CC）に準拠してAさんにお願い通知を出すことが出来る機能です。
 このときに配慮したのが、メッセージのやりとりはさせないこと。あくまで規定された文章にYes、Noだけでやり取りする必要があると考えました。そのため、単純なPushよりもメッセージ機能を優先しSQSを選択しています。
###SES
 SESはRuby on Railsの認証用gemであるdeviseを利用して認証周りを作った際に、ログインアカウントをメールアドレスにしたので、アカウント作成時にメール通知を出す必要がありました。
 その際、通知メールを送信するには、当然メール送信用のSMTPサーバが必要ですし、ネットワークに設定が必要となります。それを簡略化出来るのがSESの良いところです。
 これをSESとRoute53側で実装すれば1時間以内に動かすことも出来ると思います。もちろん、Gmailの法人版でも可能ですが外部のSMTPの場合、SLAの対象となるかは微妙ですし、できれば同一システム内で組んだほうが良いでしょう。
 また、リージョンで分けて使えばリスクも分散されるため、メールシステムに関しては、アーキテクチャを統一したほうが良いと私は考えます。
##実装上の問題
　SQSについては、Railsのgemである[Shoryken](https://github.com/phstc/shoryuken)を使って実装しました。ただ、このsyorykenを実装する時に、以下のように書くと、CircleCIなどのテストツールではエラーがでるため、書き方を修正しています。

```config/initialize/shoryuken.rb
      Shoryuken.configure_client do |config|
  Aws.config[
    access_key_id:  ENV['環境変数_ID'],
    secret_access_key: ENV['環境変数_KEY'],
    region: "ap-northeast-1",
  ]
end

     Shoryuken.configure_server do |config|
  Aws.config[
    access_key_id:  ENV['環境変数_ID'],
    secret_access_key: ENV['環境変数_KEY'],
    region: "ap-northeast-1",
  ]
  Rails.logger = Shoryuken::Logging.logger
  Rails.logger.level = Rails.application.config.log_level
end
```

この、`Aws.config[...`を当初は`config.aws = {`と書いており、これが単体テスト時にエラーとなって先に進みませんでしたが、実装上には問題がありませんでした。書き方の問題らしいので、`Aws.config[`で書くことでSDKを使う場合は統一したほうが良さそうです。

  SESはどうでしょうか？Ruby on Railsに付属するActionMailerを使うことでシステム全体に簡単に実装できます。殆ど設定情報を書き、deviseの認証にもメールアドレスを記述するだけです。特にコード側には問題はありません。

```ruby:application.rb
       config.action_mailer.delivery_method = :smtp
       ActionMailer::Base.smtp_settings = {
        address: 'email-smtp.hoge.amazonaws.com',
        port: 587,
        domain: 'example.com',
        authentication: :login,
        user_name: ENV['環境変数_NAME'],
        password: ENV['環境変数_PASSWORD'],
     }
```

```ruby:application_mailer.rb
class ApplicationMailer < ActionMailer::Base
  default from: 'info@example.com'
  layout 'mailer'
end
```

```ruby:devise.rb
Devise.setup do |config|
   config.mailer_sender = 'info@example.com'
```
  ですが、問題なのは、route53に設定するDKIMやSPFなどの認証に時間がかかり、そのプロセスがマニュアルとは違い一部不明瞭なため、何度か認証行程を踏むこともあり、送信が出来ない理由がそこにあります。

##実際に実装してみてどうだったのか
　実装が簡単で、テストも直ぐにできるため、開発工数は相当に削減できています。基本的な機能やサービスは、なんども実装するものですから、同じパターンで実装できるようにしておくほうが効率は良いです。このように昔からある実装パターンは構築の仕方をある程度モジュール化しておくことが大事ですし、海外の開発者が短時間で組み上げているのはこのような、作らない事を重要視しているからだと思われます。
　私の開発方針は「作るな使え」です。とにかく、素早く作る事が大事です。そのためには便利なツールやインフラ基盤を活用し、車輪の再発明をどんどん減らしていくべきです。その方がずっと楽になると思います。

##まとめ
　今回はSQSとSESを利用して、通知をする機能を実装しました。コード自体はシンプルに出来ていて、ライブラリやサービスがとても良く出来ているし、サーバレスアーキテクチャのため、素人でも実装できる点がとても良かったです。
　次はAWS SNS（Simple notification Service）を利用して、Push通知をアプリ含めて実装してみたいなと思います。
deviseを用いたアカウント編集のupdateを「現在のパスワード」を確認せずにする方法。

deviseを用いたアカウント編集では、編集したあとupdateする際にデフォルトでは「現在のパスワード」を入力しなくてはいけないことになっている。

そのupdateを「現在のパスワード」を確認せずにする方法をまとめる。[ここを参照](https://github.com/plataformatec/devise/wiki/how-to:-allow-users-to-edit-their-account-without-providing-a-password)

1,registrations_controller.rbを新規作成。その中に以下を記載。

```registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController

  protected

  def update_resource(resource, params)
    resource.update_without_password(params)
  end
end

```
2,routes.rbに以下を追加

```routes.rb
devise_for :users, controllers: { registrations: 'registrations' } 
```
3,devise/registrations/edit.html.erbから以下のコードを削除

```devise/registrations/edit.html.erb
   :
   :
<div class="field">
    <%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
    <%= f.password_field :current_password, autocomplete: "off" %>
</div>
   :
   :
   :
```
SQSとSESを上手く使って通知を出そう！（前編）

##現代システムにおける通知の重要性
　さて、現代的なサービスで重要なことは何でしょうか？
唐突な質問で「？？？」となったかもしれませんが、それは知ってもらうことです。実際にサービスを作って運用してみるとわかりますが、インターネットという電子砂漠の中で知ってもらうことが一番大変です。実際にウェブサービスを知ってもらっても、店に入らずすぐに帰る顧客も沢山います。
　また、来店した顧客にメールアドレスを教えてもらったら、昔はメールを送るだけでした。住所を書いてもらったら、DMを送るなどもしていました。
　ですが、これらの方法はだいぶ時代遅れ、というかEC以外のウェブサービスにはあまり効果は薄いです。
　では、最も効果があるのは何でしょうか？それは、言わずと知れたPush通知です。
しかし、通知というものは上手くやることでユーザーはうれしくなりますが、上手くやらないと嬉しくなりません。会社のブランディングにまで影響してくるのです。
　ですので、安売りのような通知はPushで頃合いを見てリアルタイムに出す必要がありますし、読ませるようなものはメールで休日にでも出して上げるなど、ファンづくりの一環として実装すべきものなのです。

##Webサービスにメッセージを送るSQS
 では、通知はどうやれば実装できるのでしょうか？実は、最近のクラウドサービスでは最初からPush用の環境を実装しており、安価に利用することが出来ます。例えばAWSではこの機能のことを、SNS（Simple Notification Service）と呼んでいます。
　このSNSはサーバレスアーキテクチャのため、AWSが用意しているAPI等を経由して、すぐに通知をWebサービスなどに送信できます。この時、モバイルOSへの通知はOS毎のフォーマットに合わせてカスタマイズすることも出来ます。しかし、単純に通知のメッセージを出して、Webサービス上にアラートを出すだけならば、SQSというメッセージキューイングシステムを使います。
　私はRuby on Railsを使って実装していますので、[Shoryukenというオープンソースライブラリ](https://github.com/phstc/shoryuken)を利用して実装しました。

##SDKであっというまにメールが送れるSES
 つづいてはSESです。SESはSimple Email Serviceの略で、その名の通りSMTPサーバを立てずにEmailを外部に送信できるサービスです。迷惑メール問題もDNSサーバであるRoute53にSPFとDKIMを設定すれば問題なく送信できます。ただし、大規模なメールマガジンのようなものを送信する場合は専用業者のシステムを経由したほうが良いです。
 それはメールの負荷もさることながら、迷惑メール対策を行っている各キャリアの設定を回避する方法を知っているからです。
 同様のサービスにはSendGridなどがあります。またメール一斉送信はMailChimpなどのソリューションがあるので、上手く組合せて使うことが大切です。
 無理に一つのソリューションで解決するのは時間の無駄なのでよくありません。

##まとめ
　ここまでは概念と各ソリューションについて説明してきました。サーバレスアーキテクチャとして、他のAWSのサービスとは少し毛色の違った実装がなされている通知系のサービス群。SDK等を活用することで、さっと作れる仕様なのは開発者の工数削減にも繋がりますし、メンテナンスコストも少なくて済みます。
　このように、便利な機能があるのに実装せずに無駄な工数を掛けていたならばもったいないということです。マネジメント側も知識をつけて、無駄な実装をさせていないのか定期的にチェックしましょう。
　さて次回は、私達が実際にどのように実装したのかを解説します。Ruby on Railsを使っておりコード自体は非常にシンプルですが、1行でもコードを減らす努力を行うことで、運用面も楽になっていきます。
deviseでデフォルト以外のカラム(nameなど)を追加したいとき

[devise](https://qiita.com/cigalecigales/items/f4274088f20832252374)を使ってログイン機能作成することはよくあるが、deviseにもともと備わっていない機能、、、例えば「名前(name)を登録したい」「電話番号(phone_number)を追加したい」など、を実現する手順。

とは言っても、「rails g devise User」の段階でUserモデルは完成しているのでまずはUserテーブルにそれぞれのカラムを追加したらいいだけ！

1, 例えば、nameカラムを追加したい時。

```
＄rails g migration AddNameToUser name:string
```
で、string型のnameカラムが追加される。

しかし、カラムには追加されたものの、このままでは「strong parameter」に引っかかってデータを保存できない！

なので、（[ここのstrong parameter](https://github.com/plataformatec/devise#strong-parameters)を参考に）以下を追加。


```application_controller.rb
class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:name])　　←***
  end
end
```
***のところの意味は「sign_upするときに、nameカラムも渡しますよ」ということ。

なので、同様に、アカウント編集で編集(update)したものを反映させたければ「permit(:account_update, keys: [:name])」となる。
（より詳しい他の例は[ここのstrong parameter](https://github.com/plataformatec/devise#strong-parameters)を参考に）

カラムを追加するだけでなく、strong parameterも更新し忘れないように注意！！
AWS RDSを使うときに理解しておくべきこと

##RDSとEC2の運用思想の違い
　私がここ最近RDSを使っていて、EC2のように運用できるだろうと思っていたのですが、それは大きな間違いでした。
　もちろん同じな部分はあるのですが、細かな思想の違いが大きな運用実装に影響をあたえ、あまつさえ課金にまで影響してきたので、気が抜けません。
　それは何かというと、インスタンス停止しても7日後には自動的に再起動してくる、リビングデッド仕様です。つまり、月の頭に停止しても、翌月の請求には21日間の金額が計上されているということです。
　そして、それはマニュアルを調べても明確な答えが載っていません。課金を完全に止めるには、削除するしか無いのです。

##RDSは非常に高度なサービス
　では、何故このような運用になっているのか？というと、そもそもデータベースシステムというのは停止させてはいけません。現代においては、常時オンラインで動かすものです。では、この停止という機能は何故ついているのでしょうか？それは、単純にメンテナンスのためです。
　移行や、インスタンスサイズのアップ／ダウンなどを行うときは一時停止させるべきですし、一般的にはシングル構成のデータベースシステムを作ることはあまりなく、Master／Slave構成にしておくはずです。
　このとき、コールドスタンバイ／ホットスタンバイという選択はあるにせよ、バックアップを用意しておくという概念が必要です。
　そして、自動起動を強制的に行っている理由は、想像ですが立ち上げ忘れを考慮してではないかと思います。
　ただ、こうなると融通の聞かない高度なサービスになってしまうので、RDSを使う前にEC2やLightsailの中にMySQLなどをインストールして運用可能かを十分に検討する必要はあるでしょう。

##RDSはどういうときに使うべきか？
　さて、RDSはどういったときに利用すべきなのでしょうか？一つはスケールするビジネスかどうかにかかるでしょう。大規模な顧客が存在し、その大量の顧客を捌かなければいけないが、インフラの人員がまだ少ないといったときに、メンテナンスコストと構築運用コストを天秤にかける場合です。
　別記事でも任天堂の事例を調べましたが、技術的に出来る人がいる場合はEC2上にMySQLを立てて、独自運用を行うで問題ないと思います。そのほうがチューニングを細かく行えるので、誰も体験したことがない驚異的なトラフィックを捌くなどの場合はEC2による自前の実装が良いでしょう。　

##まとめ
　RDSがだめ、と言っているわけではなく、便利だからと言って、身の丈に合わないサービスを使わないことが重要です。顧客が満足すればそれで良いわけですが、お金も大事です。サービスが上手く継続できるような実装を心がけるべきです。
　すべてはケース・バイ・ケースですが、サーバ単体のコストもさることながら、システム全体の運用も含めた「コスト」を算出し、金銭以外の損が無いかも含めて計算しなければいけません。
　コンピュータサービスは往々にして、コンピュータ利用の金銭的コストに目が行きがちですが、人的コスト、顧客が享受すべき利益まで見据えた上で、すべてをトレードオフした結果を見つめるべきだと渡しは考えます。
　みなさんも今一度、サービスを見直し「コスト」について考え直してみてはいかがでしょうか？
Font > link: JIS X 0213非漢字一覧 > 読み方不明な記号の検索


# ¶という記号

この文字は何を意味するのか。読み方すらわからない。

下記の一覧に掲載されていた。

[JIS_X_0213_非漢字一覧](https://ja.wikipedia.org/wiki/JIS_X_0213%E9%9D%9E%E6%BC%A2%E5%AD%97%E4%B8%80%E8%A6%A7)

> Shift_JIS-2004: 0x81f7
> 段落記号

「文字化け」「縦二重」でgoogle検索したら「[双注](https://ja.wikipedia.org/wiki/%E5%8F%8C%E6%9F%B1)」が見つかり、カテゴリ「釣物」のリンク先に「JIS X 0213非漢字一覧」を見つけた。
現代的なWebサービスをAWSで作るとこうなる（後編）

##他の会社の仕組みを見てみよう（メルカリ編）
　さて、前回は自社サービスのサーバ構成を抜粋して説明しましたが、他社はどうでしょうか？ここでは、メルカリ社の構成を元に説明したいと思います。

![メルカリスピーカーデッキ1.png](https://qiita-image-store.s3.amazonaws.com/0/18072/aa7b69c9-7c52-daa4-1c01-5c6e38f4883c.png)
AWS Dev Day2017のメルカリ社スピーカーデッキより抜粋１

　　これは2017年6月時点の資料ですが、AWS Dev Dayにて登壇したメルカリ社のシステム構成です。USのサーバ構成をAWSで構成しているようです。
　この構成を見てみると、まず、日本のしくみをそのまま移植した後、アメリカ向けのサービスをRDSなどで組んでいるようです。また、特徴的なのはWebサーバNginxを別で切り出しEC2として組んでいる処、日本から移植した所はMySQLもRDSを使わず個別にEC2上で運用している点です。
 その他、memcachedを使って内部キャッシュをもたせ、DBとアプリケーションサーバのトランザクションコントロールをしています。
　典型的なウェブサービスの三層構造をサーバ単位で切り出したというイメージです。

![メルカリスピーカーデッキ2.png](https://qiita-image-store.s3.amazonaws.com/0/18072/38b2ab03-4d8b-494d-7d6d-c32291a11c89.png)

 さらに、グローバルサービスのため、CDNをAkamaiやCloudFrontとして実装し、拡張するサイドサービスをマイクロサービスとして実装しています。また、解析系サービスをGoogleのBigQueryとしているのも最近の流行りですし、グローバルの保存先をS3にしていて、まさにマルチクラウドを地で行っている感じがします。
 そして、DNSがとても特徴的でRoute53に集約しているあたりに、サービスのレイテンシを考慮しているのかもしれませんね。

[メルカリ社AWS Dev day スピーカーデッキ](https://speakerdeck.com/kazeburo/cloud-connect-the-world-as-a-glue-aws-dev-day-2017)

##他の会社の仕組みを見てみよう（任天堂＆DeNA編）
つぎに昨年話題になった、[任天堂のSuperMarioRunの構成](https://aws.amazon.com/jp/solutions/case-studies/nintendo-dena/)です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/18072/244e29cd-cd17-0045-5849-973c259ed5bb.png)
AWS 導入事例任天堂株式会社、株式会社ディー・エヌ・エーより抜粋

　とてもシンプルな構成です。EC2とS3そして、ELBでロードバランスしただけの構成です。これで8000万ダウンロードを耐えていると考えると驚異的だと思いました。
　また、これはモバイルアプリのため、Webサーバの代わりにProxyサーバ、アプリケーションサーバのかわりにAPIサーバですが、ここでもRDSを使わずDBサーバをMaster/Slave構成で立てています。たぶん、細かいチューニングを自分たちで行う必要を感じたからこのような構成にしたのかもしれません。それ以外は殆どメルカリと似たような構成になっています。

　ここには掲載していませんが、[ログや認証周りはGoogleCloudPlatform](https://cloudplatform-jp.googleblog.com/2017/06/nintendo-super-mario-run-google-cloud.html)を使っています。このように、任天堂すらもグローバルベンダーをマルチクラウドで使う時代になっています。

##現代的＝マルチクラウドに進む
　こうやって見てきたとおり、AWSは単一サービスでも十分力を発揮できますが、無理やり実装する前に技術検証をして上手く実装しましょう。でも、わかったと思いますが、メインサーバとしてはAWSが一番こなれていると思います。やはり有名所の大きなサービスはだいたいEC2とRDS、S3をしっかり実装しており、その周辺機能を他の会社のサービスで補うというのが一般的だと思いました。
　このようにマルチクラウドという点が一つのポイントになっており、なんでも１社で賄おうとするのは危険ですし、DNSラウンドロビンなどディザスタリカバリも考慮したシステム構成を検討したほうが良いでしょう。

##まとめ
　こう見てくると、自社サービスのインフラ構成はかなりAPI的な作り方をしています。基本は抑えているもののかなりチャレンジングだなと自分でも思いました。
　ただ、他社との比較をしていく中で、過剰な実装にならないようにしつつ、ポイントを抑えた実装を行い、顧客の体験を最大化出来るようにしたいと思います。
C > !val と val != 0の違い?

組込みで使うライブラリのバージョンアップにおいて、下記のような修正がいくつか見られる。

```previous.c
if (nb) {
...
while (!nb) {
...
```

```current.c
if (nb != 0) {
...
while (nb == 0) {
...
```

読みやすさだけの変更なのか、そのバージョンアップ履歴に記載されているバグ修正と関係があるのかは不明。

https://ideone.com/12umLs

```c
#include <stdio.h>

int main(void) {
	int val;

	val = 0;
	if (!val) printf("!val\n");
	if (val != 0) printf("val != 0\n");

	val = 1;
	if (!val) printf("!val\n");
	if (val != 0) printf("val != 0\n");

	val = 5;	
	if (!val) printf("!val\n");
	if (val != 0) printf("val != 0\n");

	return 0;
}
```

```txt:run
!val
val != 0
val != 0
```
vagrantにnode.jsをインストールしてgulpでsassをコンパイルする

# gulpでsassをコンパイルしたい
vagrant内にnvmでnode.jsをインストールして、gulpコマンドでsassをコンパイルできるようにしたので、そのメモです。
sassをコンパイルするだけであればnvmを使う必要もないのですが、今後のことも考えてnvmを利用することにしました。
*gulpfile.jsを用意してある前提で進めます。

## nvm
[nvmのリポジトリ](https://github.com/creationix/nvm#install-script)を参考に、下記コマンドを実行します。

```
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.32.1/install.sh | bash
```

終わったらpathが通っているかを確認します。

```~/.bashrc
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
```

この2行が追加されていればOKです。
場合によっては`.bashrc`ではなく、`.bash_profile`などに書き込まれることがあるようです。
[nvmのリポジトリ](https://github.com/creationix/nvm#install-script)にも記載があるので、
「追加されてない！？」
と慌てる前に確認しましょう。

pathが通っていることが確認できたら一度vagrantからログアウトし、再度`vagrant ssh`でログインしてください。
ログインできたら改めてnvmのバージョンを確認します。

```
[vagrant@localhost ~]$ nvm --version
0.31.0
```

これでnvmのインストールは完了です。

## node.js
続いてnode.jsをインストールします。

安定版をインストールする場合は

```
nvm install --lts
```

これだけでOKです。
自分でバージョンを選びたい場合は

```
nvm install v*.**.*(バージョン番号)
```

これでインストールできます。
バージョン一覧を見たい場合は

```
nvm ls-remote
```

を叩きましょう。
インストールが終わったら、nodeのバージョンを確認します。

```
[vagrant@localhost ~]$ node -v
v6.11.4
```

同時にnpmのバージョンも確認しておきます。

```
[vagrant@localhost ~]$ npm -v
3.10.10
```

これでnodeのインストールまで完了しました。

### nodeコマンドが使えない時
nvmでnode.jsをインストールした後、デフォルトのバージョンを指定しないとnodeもnpmを使えなくなることがあります。
その場合は

```
nvm alias default v*.**.*(バージョン番号)
```

を実行し、デフォルトのバージョンを指定してください。
インストールされているnode.jsのバージョンは

```
[vagrant@localhost ~]$ nvm ls
->      v6.11.4
default -> v6.11.4
node -> stable (-> v6.11.4) (default)
stable -> 6.11 (-> v6.11.4) (default)
```

これで確認できます。

## gulp
gulpをインストールします。
先にグローバルインストールをしたいので

```
npm install　-g gulp
```

を叩いてインストールします。
その後、gulpをローカルインストールしたいディレクトリに移動してから

```
npm install gulp
```

を実行します。
インストールが終わったら、gulpのバージョンを確認します。

```
gulp -v
```

バージョンが表示されればOKです。
ただ、これだけではsassをコンパイルできないので、`gulp-sass`をインストールします。

```
npm install gulp-sass
```

エラーなくインストールできたら`gulp`コマンドを叩き、cssファイルが生成されれば完了です。

## 参考
- https://qiita.com/sansaisoba/items/242a8ba95bf70ba179d3
- https://original-game.com/gulp-sass-install-and-how-to-use/#gulp-sassgulp-ruby-sass
.NET Core アプリケーションの配置についてのメモ

# .NET Core アプリケーションの配置についてのメモ

[参照元:.NET Core application deployment](https://docs.microsoft.com/en-us/dotnet/core/deploying/)
[参考：主に技術日記 / .NET Coreが動くまで](http://yfakariya.blogspot.jp/2017/03/net-core.html)

## .NET Coreアプリの配置の種類

### Framework-dependent deployment[FDD] (フレームワーク依存型配置)

  配置対象となるシステム(マシン)にインストールされている.NET Coreのバージョンに依存して、モジュール配置を行う方式。

  .NET Coreアプリは、基本的に.NET Coreがインストールされているいずれのマシンでも実行可能です。

　そのため、FDDによる配置では **.NET Coreを除いた** 実行のために必要な自身のモジュールやサードパーティのモジュールのみで構成します。

　FDDに含まれるDLLファイルは、コマンドラインからdotnetユーティリティを使用して起動します。

  dotnetコマンドラインは、アプリのランチャーとして機能し、指定されたパラメータに対応するdllをCorRunにホストして実行します。

  （例：``dotnet app.dll``）

  [CoreRun Host](https://github.com/dotnet/coreclr/tree/master/src/coreclr/hosts/corerun)は、[Hosting API](https://docs.microsoft.com/en-us/dotnet/core/tutorials/netcore-hosting)を使用したマネージコードのJIT, GCといったランタイムやAppDomainの生成、およびマネージコードのエントリーポイントからの起動などを行います。

  [CoreRun Host](https://github.com/dotnet/coreclr/tree/master/src/coreclr/hosts/corerun)では、プラットフォーム毎に用意されており、この機構によりプラットフォーム毎の差異を吸収します。

#### どのような場合にFDDを作成するか

* ターゲットとなるOSを特定しない.NET Coreアプリを作成したい場合。
* 配置用パッケージ全体のサイズを小さくしたい場合。
* 対象システムで、同じ.NET Coreを使用しているアプリがインストールされている場合

### FDDのデメリット

* 特定の.NET Coreのバージョンをターゲットとしたアプリの場合、最新バージョンのインストールなどが行えなくなる
* 可能性は低いが、.NET Coreランタイムやライブラリで使用していた機能が将来バージョンで振る舞いの変更が行われた場合、アプリの振る舞いが変更になる

### Self-contained deployment[SCD] (自己保持型配置)

  FDDとは異なって、対象となるシステム（マシン）のコンポーネントに依存しない方式です。実行に必要となる.NET Coreライブラリや.NET Coreランタイムは保持し、他の.NET Coreアプリケーションと分離します。

  SCDは、プラットフォーム毎の実行ファイル（例：``app``というアプリケーションの場合、Windowsであれば``app.exe``というような形式）が含まれており、``app.dll``がRenameされて含まれる。

#### どのような場合にSCDを作成するか

* 自身のアプリに使用する .NET Core のバージョンを制御したい場合。　SCDで構成すると、必要モジュールがすべて組み込まれるため、環境に依存しないアプリの作成が可能。
* 対象となるシステム（マシン）で .NET Coreアプリが確実に動作する保障が必要な場合。

#### SCDのデメリット

* SCDは自動生成されないため、ビルドの際にターゲットプラットフォームの設定やSCDへの切り替えなどの追加設定を行う必要がある
* .NET Coreのモジュールも含まれるため、配布用パッケージのファイルサイズが多きくなる
* １つのマシンに複数のSCDアプリを配置すると、重複したファイルによってディスクスペースが消費される。
background-imageのみにfilterを掛ける。

### backgroundにフィルターを掛けると、文字にまで影響が及ぶ。
before要素に画像のコピーを作り、z-indexを下げることで回避する。

```css
:before{z-index:-1;background:inherit;filter:....;
content:' ';position:absolute;width:100%;height:100%;
overflow:hidden;}
```
### フィルターの構文
```css
/* .x{filter:yyyy} */
.f-40{filter: brightness(35%);}
```
### パターン
```css
/*pattern
brightness(35%);
brightness(260%);
invert(100%);
sepia(100%);
grayscale(100%);
opacity(20%);
blur(5px);
hue-rotate(100deg);
contrast(300%);
*/
/* mix
brightness(85%) blur(5px) contrast(300%) grayscale(100%);
*/
```
```scss

/*mixin*/
@mixin filter($cls:'filter',$filter:brightness(40%)){
  
  img.#{$cls},canvas.#{$cls}{filter:$filter}
.#{$cls}:not(img):not(canvas){z-index:0;position:relative}
.#{$cls}:not(img):not(canvas):before{z-index:-1;background:inherit;filter:$filter;
content:' ';position:absolute;width:100%;height:100%;
overflow:hidden;}
  
}

$f-40: brightness(40%);
@include filter('f-40',$f-40);/*make class the .f-40*/
```
### 全部 
```scss
@mixin filter($cls:'filter',$filter:brightness(40%)){
  
  img.#{$cls},canvas.#{$cls}{filter:$filter}
.#{$cls}:not(img):not(canvas){z-index:0;position:relative}
.#{$cls}:not(img):not(canvas):before{z-index:-1;background:inherit;filter:$filter;
content:' ';position:absolute;width:100%;height:100%;
overflow:hidden;}
  
}

$f-40: brightness(40%);
@include filter('f-40',$f-40);
/*pattern
brightness(35%);
brightness(260%);
invert(100%);
sepia(100%);
grayscale(100%);
opacity(20%);
blur(5px);
hue-rotate(100deg);
contrast(300%);
*/
/* mix
brightness(85%) blur(5px) contrast(300%) grayscale(100%);
*/

div{color:whitesmoke}
.card{
  width:250px;
  height:200px;
  border:1px solid;
  background-image:url('https://i.imgur.com/1JQ7yss.png');
  background-position:center;
  background-size:cover;
}
```
```html
<div class="card">aaabbbccc</div>
<div class="card f-40">aaabbbccc</div>
<hr>
<img src="https://i.imgur.com/1JQ7yss.png" ></img>
<img src="https://i.imgur.com/1JQ7yss.png" class="f-40"></img>
```
Slackbot用のHubotをサーバーに永続化して配置する

# 概要
サーバーにHubotを導入し、Slackに接続した状態で永続的に起動しておく方法

# Hubotの導入
### npmでHubotをインストール
（npmが入っていない場合は先にnpmを入れる）

```
%  npm install -g yo generator-hubot
```

### Hubot用のディレクトリを作成して移動
（今回はbotというディレクトリを作るが、実際はなんでもいい）

```
$ mkdir bot
$ cd bot/
```

### Hubotを作成

```
$ yo hubot
```
※ 設定を聞かれるのでBot adapterにだけ`slack`と入力する。他はEnter。

### Hubotの起動

```
$ bin/hubot
```
Enterを押して`bot>`となったところに`bot ping`を実行して "PONG"と返ってくればHubotが正常に導入されている。
Ctrl+cでHubotを停止できる。

# HubotをSlackに接続する

### SlackでHubotのアカウントを作成
Slack>bots>hubot>Add Configuration で新しくHubotを登録
![add_hubot.JPG](https://qiita-image-store.s3.amazonaws.com/0/231600/c363464c-0910-143e-206b-d39599ef00dc.jpeg)

![hubot_token.JPG](https://qiita-image-store.s3.amazonaws.com/0/231600/b543ba94-f703-3a85-401f-983f64134a82.jpeg)
上の赤部分のアクセストークンはコピーしておく

その後作成したHubotのアカウントをSlackの対象のチャンネルに追加

### HubotをSlackに接続して起動
作成した`bot/bin` 配下にある`hubot`ファイルをviもしくはテキストエディターなどで開き、下記を<font color="Red">execの行よりも上</font>に追記する

```
export HUBOT_SLACK_TOKEN="SlackでHubotのアカウントを作成した際のアクセストークン"
```


bot配下で下記コマンドを実行するとSlackで作成したHubotに接続してHubotが起動される

```
$ bin/hubot --adapter slack
```


Slackの対象のチャンネルで`bot ping`と送ったらHubotのアカウントが"PONG"と返してくれば成功

# Hubotを永続化する
このままだとサーバーの接続を切るとHubotも終了してしまうので永続化の処理をする。

### Foreverのインストール
```
$ npm install forever --save
```

### PATHの設定
ホームディレクトリ（$ cd で移動）にある `.bash_profile`ファイルをviもしくはテキストエディターなどで開き、最終行に下の一行を書き足す。

```
export PATH=$PATH:/home/vagrant/bot/node_modules/.bin
```
その後下記コマンドで再読込

```
$ source .bash_profile
```

### hubotの起動ファイル書き換え
`bot/bin` 配下にある`hubot`ファイルをviもしくはテキストエディターなどで開き、`exec`から始まる行を下に書き換える。

```
forever start -c coffee node_modules/.bin/hubot --adapter slack
```

### 永続化起動
bot配下で下記コマンドを実行するとSlackに繋がったHubotが起動し、サーバーの接続を切っても起動し続けることができる。

```
$ bin/hubot
```
現代的なWebサービスをAWSで作るとこうなる（前編）

##AWSを使った機能の分散
　当たり前の話をするわけではないですが、クラウドサービスを使うということは如何に一極集中させず、分散管理するかという話になってきます。
　昔はオンプレミスでサーバ管理をするよりも、インターネットのあちら側のクラウドに設置して、仮想化技術で一つのサーバのように見せておくことに価値がありました。
　だが、現代において、それは最低条件であり、より機能が細分化され、単体サービスだった頃の問題点をいかに回避し、顧客へのサービスダウンを回避するのかという点を徹底的に考えられるようになりました。
　今回は、どのように機能の分散配置するのか説明したいと思います。

##各機能の紹介と利用理由
細かい所はオミットしましたが、図のような構成になるのではないかと考えています。
![スライド1.png](https://qiita-image-store.s3.amazonaws.com/0/18072/0405a39f-091e-cc0b-88b8-af46c64d6d44.png)

さて、それぞれの機能とその利用理由ですが、以下の通りです。

###本番系
####Route53
　DNSサーバ。他でドメインを取得していても、AWSでサービスを作るならこちらにDNSを切り替えて使ったほうが良いです。特にALBやSESなどはこちらを使わないとトラブルが起こりえます。
####CloudFront
　コンテンツを配信する仕組みCDNです。最近はfastlyなどもありますので、一概にこちらが正しいわけではありませんが、すべてをAWSで設計するのでこうなりました。
####ALB（ApplicationLoad Balancer）
　仮想上のロードバランサです。負荷分散装置ですが、高度な処理が可能です。EC2で標準設定できるのでシンプルに実装しています。
####EC2
　言わずと知れた静的サーバです。サービスのオートスケールの要だといえるでしょう。これがないと始まりません。
####CloudWatch
　監視システムです。無料でもそこそこ使えますが課金してからが本番です。今回はアラートを上げて、オートスケールするような仕組みを作るため、シェルの代わりに使っていく予定です。
####ElastiCache
　静的なキャッシュサーバです。データベースやS3との間に設置して、EC2との間のI/Oスループットを向上させる予定です。
####RDS
　リレーショナル・データベースサーバです。DBのメンテナンスや拡張は従来ではものすごく面倒でしたが、RDSのおかげで便利になりました。拡張も拡大もほぼ自動でいけます。今回はマスタースレーブ構成を組みます。採用するDBはAurora（MySQL）です。
####S3
　シンプルストレージサービスです。あらゆるデータを保管しておくことができるストレージサービスです。静的なHTMLとCSSもおけるので、サーバレスでホームページを公開できます。
###管理・分析計
####Kinesis firehouse
　ログの収集と適切なフォーマットへ変換する装置です。膨大なログが出る可能性があるので、こちらで処理を予定しています。ですが、GCPの方が良いかなと思っていたりしますが、データの転送量との兼ね合いですね。
####Lambda
　サーバレスアーキテクチャです。Kinesisで処理したrowデータをRedshiftに中継するために使います。
####Redshift
　データウェアハウスです。BIと組み合わせてデータを可視化します。もしかすると、ここはGCPの方が強いのでBigQueryになるかもしれません。
####Quicksight
　AmazonのBIツールです。もし、AWSでBIをやるなら場合はこれを利用します。
####Athene
　S3をSQLの構文で検索できるようにするサービスです。サーバレスアーキテクチャですが、これらを見ると、すべてBigQuery+αで処理できるかもしれないので、コストとの兼ね合いで冷静に考えたほうが良いかもしれません。

##実装上注意した点
　今回のポイントはEnterpriseサービスなのでダウンは絶対に起きないようにするための強固な基盤を作るためにはどうしたら良いのか？という点に着目しました。
　もちろん、システムの接続ポイントが増えると、増えただけ障害が発生するのですが、最近のクラウドサービスはリージョンでディザスタリカバリを作るなどすれば、システムで担保できるのでSLAを設けても十分対応できるでしょう。
　ベンチャーであっても、大企業並みの強固なシステム基盤を構築できるのがAWSの大きな利点だと思いました。

##まとめ
　次回後編では、他社の仕組みを参照しながら、各社ごとの哲学を読み解き、自社との違いを解説していきます。
AWS LambdaとNode.jsを使ったAIソリューション作り方（後編）

##AWS Lambdaの制限事項
　AWS Lambdaは通常のサーバと違い、幾つかの制約条件があります。まず、OSをセットアップできないため細かいコントロールが出来ません。あくまでAmazonが決めたルールに従うのみです。実行環境はそれぞれの言語毎に指定されたバージョンしか使えません。
　そのため最新型で動かしたいなどの要望には答えることが出来ません。メモリは現在最大3GBまで使えますがそれ以上は増設できません。
　基本的にプログラムファイル以外はS3などのLambda以外に保存して置き、トリガーとして利用したりします。
　データベースも当然入っていないので、DynamoDBなどのサービスを呼び出します。これでおわかりだと思いますが、LambdaはあくまでCPUとして使います。あとは外部のストレージサービス、データベースサービス、通知サービス、メッセージサービスなど機能毎にAPIで接続していく、APIエコシステムの中心的なサービスなのです。
　そのため、あえてフル機能を実装していません。そこがいいところでもあり、簡単なプログラムをさくっと動かせるポイントでもあります。

##Lambdaのハマリポイント
 私がLambdaを使っている中でハマったポイントを幾つか説明します。まず、外部のSDKを入れるためにはフルパッケージをPCのローカル環境などでダウンロードしておき、それをまるごとアップロードする必要があります。
 そうした時、問題があってWebUIからは50MB制限が掛かるということです。50MB以上はアップロードできません。50MB以上をアップしたい場合はS3経由でアップするかCLIツールからアップするなど少し面倒になります。
 そのため、SDKを同時にアップロードする場合は、SDKの中身を精査し必要なものだけに制限する必要がありました。そして、デバッグがウェブ上でしかわからないため何が問題なのかが見えづらいというのがあります。
 その他、ハンドラと呼ばれるトリガーネームがありますが、これは実行ファイル名を指すわけですが、ZIPで保存してアップロードするときに、何かフォルダを一つ作ってその下に入れてしまうと、上手く認識できないというディレクトリ構造問題に行き着きます。
 その為、圧縮するときは実行ファイルと、SDKフォルダは同一ディレクトリ上（例えばデスクトップ上など）で、そのまま圧縮すべきです。
 こういう「作法」を理解した上で実行していく必要がありますが、実行ファイルの関数名などに制限は無く、柔軟に書けるのは良いのですが、JavaScriptなどは一般的な書き方とLambdaではほんの少しだけ書き方が違うため、そこでドハマリしていました。
 さらに、短期間で大幅なアップデートがなされる事があり、マニュアル通りにやっても違う減少が発生したりもしたので、常に自分で考えながら動かす癖が必要です。

##実際のコードを見てみる
それでは、実際にLambdaに実装したコードを以下に表してみます。
すべてを書くと、冗長になるので、形態素解析しキャラクターが何を話し、同行動したのかを切り出すためのコードです。

```:node.js
'use strict';

exports.handler = function(event, context, callback) {
  var language = require('@google-cloud/language')({
  	projectId: 'story-analytical-engine',
  	keyFilename: 'config/keygcp.json'
  });
  var document = language.document(event.text);
  document.annotate({verbose: true},
    function(err, annotation) {
      if (err) {
        callback(err);
      } else {
        callback(null, annotation);
      }
  });
}
```

 上記のように、APIを読み出しているだけですが、中継するだけならごくシンプルな実装で、あとはライブラリにおまかせすることが出来ます。
 また、もちろん、この後ろにEC2を実装したRuby on Railsプログラムがあり、判定用のアルゴリズムが動くわけですが、形態素解析と感情算出という膨大な演算を外部サーバに任せるときに、既存のサーバをいじらずサーバレスでサクサクとアドオンを作れるのはとても便利だと思います。

##まとめ
　さて、前編と後編を通して感じたことですが、最近のクラウドサービスは組み合わせ次第でかなり出来ることが増えたなと思いました。また、簡易的に実装したいという場合も、サーバの中からサーバの外という選択肢が増えたことで、自由度が増し、検討時間も実装時間も大幅に短縮することで、ユーザーテストまで持っていくまでのリードタイムが圧倒的に短縮できていると思います。
　このように、道具だと割り切ってうまくLambdaなどのサーバレスアーキテクチャを利用し、マルチクラウドの実装を試してみて下さい。
AWS LambdaとNode.jsを使ったAIソリューション作り方（前編）

##機械学習ではないAIから始まった
　みなさんは日頃AIと言えば、やれ深層学習だとか、やれ機械学習だとかのキーワードが飛び交っていて、AI＝ビッグデータ解析＆ニューラルネットワークが当然だと思っているかもしれません。
　しかし、私はそれにあえてアンチテーゼを唱えたいと思っており、イベントや取材などでも度々言っていますが、スモールデータをAPIを使って検証するところから始めれば良いでしょ？と考えて今回の実装形態に至りました。
　グローバル企業やゲーム企業など膨大なトラフィックを持っている企業ならいざしらず、殆どGoogleの定義するビッグデータを持っておらず、深層学習効果はありません。
　そこで、既にアルゴリズム化され、最終的な戻り値のみとなったAPIにアクセスすることで、もっとライトに作れるのではないかと考えたのです。

##改めてAWS Lambdaとは？
　AWS Lambda（以下、Lambdaと呼称）とは2年ほど前に流行った、サーバレスアーキテクチャと呼ばれる、利用時間課金のソリューションです。使える言語は現在Node.js（JavaScript）、JAVA、Python、C#、Go Langの5種となり、日本人に人気の言語Rubyは現在のところSDKが準備されていません。
　Lambdaはサーバレスコンピューティングを実現するために、EC2やLightsailに代表されるように空っぽのサーバに独自のAMIを用意しデプロイする必要はありません。最初から用意されている基盤に従い、SDKを使って「呼び出し」で動かします。
　これは私が推奨するAPIエコシステムにも通じる概念です。サーバ自体をAPI化しているので、ごく少量のコードを書くだけで動きますが、メモリに限度があるためプログラムの同時実行数に限りがあり重すぎる処理には向いていません。
　あくまで簡易的なバッチ処理などを行う事に向いています。

##なぜ、AWS Lambdaを選んだのか
　なぜ、私はAWS Lambdaを選択したのかというと、EC2に実装していたWebサービスから他社のAIソリューションが持っているAPIを呼び出す必要がありましたが、EC2が既に稼働しており、あまり実装上環境をいじりたくなかったためです。
　そこで、EC2インスタンスを新たに立ち上げるとコストが掛かるというのもあって、前から興味があったLambdaでコストを安く実装できないかと思案しました。また、今回の実装はIBMとGoogleのAI APIを同時に呼び出す必要があったので、そのSDKを本番に仕込ませるのも影響を考えると嫌だったというのもあります。
　影響範囲の検証という、事前調査の時間を取りたくなかったからです。一秒でも早く、AIで解析した結果を見て使えるのかどうかを確認したいと思いました。
　そういう今までならばサンクコストになっていた余剰時間をカットすることで、設計から実装までに1週間も掛からず内部ローンチすることが出来ました。実際に動かすだけなら数時間でしょう。

##まとめ
　ここまでが、AWS Lambdaを使ったAIソリューションのあらましでした。深層学習を行う理由は、可視化出来ていない何かを見つけるための、アルゴリズムを探すための探求です。しかし、私たちのような既に業務で動いている人間からすれば、ある程度の粒度を持って答えが出ているのであれば、そのパラメータを引き出し、独自の「アルゴリズム」で答えを求める方が理にかなっているはずです。
　また、今回行っている処理は自然言語解析と形態素解析であり、ある程度ライブラリがものを言う世界ですし、論文などの演算結果でもそのベクトルや積分の数式からして、すでにあるアセットを使うべきだと私は思っていますし、十分これまでの他の研究と引けを取らない結果が出ていると思います。
　結局、道具なのですから使う側はもっと知恵を絞り効率的に答えを導き出していけばいいのです。では、後編ではもう少し具体的な実装について話をしたいと思います。
InstagramのoEmbedを使用すると表示が崩れる

サイトにてInstagram画像を使用するためにInstagramさんが提供しているoEmbedを使用していたが、ある日を境にInstagram画像表示が崩れるようになってしまった。

某質問サイトや、英語のサイトをあさってみたが原因を発見できなかったため、ここに対応方法を備忘録として残そうと思う。

※apiが既に修正されている可能性もありますので、その時はご了承ください。

# 現象
- 使用するAPIは`https://api.instagram.com/oembed?url=[InstagramのURL]`
- 1ページに複数枚のInstagram画像を使用いていると、表示が崩れて画像が文字と重なったり、画像自体が表示されなくなる。
- リロードすると直ることがある。
- 表示が崩れないページも存在する。
- `"Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings."` とjsエラーが出ている。

# 原因
APIから返ってくるscriptタグの中身がタイミングによって異なるっぽい。下記の２つのどちらか。
1. `<script async defer src="//www.instagram.com/embed.js"></script>`
2. `<script async defer src="//platform.instagram.com/en_US/embeds.js"></script>`

どうやら1.のscriptタグを取得すると表示が崩れるらしい。
※現在は1.のみしか取得しなくなっていた。

`www.instagram.com/embed.js`は圧縮されていて読み解くのが困難なので、根本的な原因は調査していないが、これを使用しないほうが良いらしい。

# 対応
単純に`www.instagram.com/embed.js`を使わないようにする。
下記3つのどれかで解決できるはず。
1.　`www.instagram.com/embed.js`を`//platform.instagram.com/en_US/embeds.js`に置換する。
2.　ページ表示時に毎回apiを叩いている場合は、`omitscript=true`をパラメータに加えることでscriptタグを返さなくなるので、自分自身で上記2.のスクリプトタグを付け加える。
3. 自作jsを使用する。

# 最後に
前述したように根本的な原因はわからず。なぜこのような仕様になっているか。同じような現象で悩んでいる方もいると思うので、少しでも役にたてばと思う。
Sinatraのlayout指定の方法が変わっているっぽい話

# 初めに
先日、sinatraを使っていて、layoutを使わない方法・他のlayoutを使う方法について調べていたところ、ネットの文献のままではエラーが吐かれてしまいうまくいかなかった。

##見た文献
http://d.hatena.ne.jp/kajisuke/20090711/1247311590
少ししようが変わっているようだ。
そのため、ここに現時点で動く書き方を記す。
### レイアウトを使わない方法

	get '/' do
	  #なんか処理等
	  erb :使いたいview, :layout => nil
	end

### レイアウトを指定する方法

	get '/' do
	  #なんか処理等
	  erb :使いたいview, :layout => :指定したいレイアウト
	end
Ruby on Rails Tutorialのメモ

# Rails Tutorial Memo
4章までのRuby on Rails のメモ

## 2章
MVCの挙動

[config/routes.rb]
URLとアクションの組合せを設定する。

＊ code ＊
Rails.application.routes.draw do
  resources :users   ←URLの設定
  root 'application#hello' ←アクションの設定
end

＊ mean ＊
ルートにアクセスするとApplicationコントローラ内のhelloアクションにルーティングされるようになる。

<img width="401" alt="スクリーンショット 2018-02-13 17.27.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/148649/cb6a2f60-ab23-9270-d808-ca39dcc1fcf2.png">

そのアクションひとつひとつに割り当てられてる処理を書く部分が、
[app/controllers/users_controller.rb]
[app/controllers/microposts_controller.rb]

*before_action : ????*
????をほかのアクションより前に作動させる。


<img width="300" alt="スクリーンショット 2018-02-13 16.56.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/148649/62b754b2-ab80-9139-4c4f-d3118ad49014.png">

⑥ @記号で始まる変数をRubyではインスタンス変数と呼び、Railsのコントローラ内で宣言したインスタンス変数はビューでも使えるようになる。


## 3章


<img width="239" alt="スクリーンショット 2018-02-15 14.32.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/148649/4e076e4b-0280-27f4-f4d6-2304169875ea.png">

------

生成したコードを元に戻したいとき

rails generate controller StaticPages home help  ・・自動生成

rails destroy  controller StaticPages home help  ・・取消処理

ちなみに、
home help はそれぞれアクションとなる。

データベースのマイグレートを一つ前に戻すとき

rails db:rollback


データベースのマイグレートを最初の状態に戻したいとき

rails db:migrate VERSION=0

----------------
###HTTPメソッドについて

GET : Web上のデータを読み取る時に使う
POST : ページ上のフォームに入力した値を、ブラウザから送信する時に使う
PATCH : サーバー上の何かを更新
DELETE : サーバー上の何かを削除

上から順によく使用する。

＜プレースホルダーとは＞

点線で囲まれたボックスであり、スライド レイアウト内に配置される。
この中にコンテンツが入り、組み込みスライド レイアウトにはすべて、コンテンツ プレースホルダーが含まれる。

#Test


assert_select "title", "Home | Ruby on Rails Tutorial Sample App"

<title>タグ内に「Home | Ruby on Rails Tutorial Sample App」という文字列があるかどうかをチェック。





##4章

[full_titleヘルパー]
ページタイトルが定義されていない場合は基本タイトルを返し、定義されている場合は基本タイトルに縦棒とページタイトルを追加して返します 

シングルクオート文字列の中では式展開が出来ない。

＊code＊
出力 → '#{foo} bar'     # シングルクォート内の文字列では式展開ができない
入力 → "\#{foo} bar

出力 → '\n'       # 'バックスラッシュ n' をそのまま扱う
入力 → "\\n"

reverseメソッドを使うと、文字列の逆から表示される。

splitを使用すると
＊code＊
入力　→ "foo bar     baz".split     # 文字列を3つの要素を持つ配列に分割する
出力　→ ["foo", "bar", "baz"]
のように分けてくれる。
また、
＊code＊
入力　→ "fooxbarxbaz".split('x')
出力　→ ["foo", "bar", "baz"]
のようにsplitの引数に文字を入れることでその引数の文字で区切ることもできる。

code1のように入力した場合、aの中身は変更しない。
aの中身を変更したい場合は、code2のようにそのmethodに対する破壊メソッドを使用する。
また、code3のようにpushメソッド (または同等の<<演算子) を使って配列に要素を追加することもできる。
＊code1＊
入力　→ a.sort
出力　→ [8, 17, 42]
入力　→ a.reverse
出力　→ [17, 8, 42]
入力　→ a.shuffle
出力　→ [17, 42, 8]
＊code2＊
入力　→ a.sort!
出力　→ [8, 17, 42]
＊code3＊
入力　→ a.push(6)                  # 6を配列に追加する
出力　→ [42, 8, 17, 6]
入力　→ a << 7                     # 7を配列に追加する
出力　→ [42, 8, 17, 6, 7]
入力　→ a << "foo" << "bar"        # 配列に連続して追加する
出力　→ [42, 8, 17, 6, 7, "foo", "bar"]




参考ページ
https://railstutorial.jp
Visual Studio でターゲット.NETバージョンを変更したときのNugetパッケージ更新

#環境
Visual Studio 2017 Community（Professionalも同じ）

#やりたいこと
.NET バージョンを上げる or 下げる
そのときのNugetパッケージが元のターゲットバージョンを指しているので、更新したい

#やってみた
今回は.NET 3.5 → .NET 4.0 にします。

##バージョンを上げる
さっそくメニュ→プロジェクト→[アプリ名]のプロパティ を開いてバージョンをあげます。
![ss20180219_152534.jpg](https://qiita-image-store.s3.amazonaws.com/0/136398/08da545d-593d-59c0-396e-3d4d5422000d.jpeg)
こいつから

するとなんか言われますが、はいはい 言っときましょう。
![ss20180219_152707.jpg](https://qiita-image-store.s3.amazonaws.com/0/136398/ba86e1fc-efbc-721c-0ade-28c92ac3c2ce.jpeg)

↓
![ss20180219_152824.jpg](https://qiita-image-store.s3.amazonaws.com/0/136398/955df490-d2f8-2ee0-150f-83c3e1dd6cb0.jpeg)

↓
![ss20180219_152807.jpg](https://qiita-image-store.s3.amazonaws.com/0/136398/e96e6d08-6ce0-8c1f-fbbf-4198cd88ca83.jpeg)
エラー一覧に変化が！！
どうやらインストールしたNugetパッケージは.NET3.5 基準なので使えないそうです。

でも再インストールするのもGUIからのパッケージマネージャーだとめんどくさいし…

##パッケージマネージャーコンソールを開く
そこでパッケージマネージャーコンソールを開きます。
一括で更新しちゃいましょう。
メニュー → ツール→Nuget パッケージマネージャー → パッケージマネージャーコンソール
 を開きましょう。

そこで
**PM> Update-Package -Reinstall**
と入力するとすべてのパッケージがきれいサッパリアンインストールされ、再インストールされます。

そのときは今の.NETバージョンでやってくれるので、.NET4.0でインストールされます。

Nugetパッケージのたちのバージョンもそのまま再インストールしてくれるので、バッチリ。

以上、備忘録でした。
MavenのJAVA_HOMEで躓いた時に見るメモ

自分用にメモ
##### ●動作環境
- Winodws 10(Pro 64bit)
- jdk-8u161(64bit)
- Maven 3.5.2

##### ●事象
Maven+Spring Bootで「mvn spring-boot:run」を実行したら次のエラーが発生

```
The JAVA_HOME environment variable is not defined correctly
This environment variable is needed to run this program
NB: JAVA_HOME should point to a JDK not a JRE
```
##### ●原因
環境変数「JAVA_HOME」の設定ミス
JDKは、インストーラーに従ってインストールしたものの、環境変数のJAVA_HOMEが未設定のまま

##### ●対応
JAVA_HOMEを次のように設定したら動いた

```
JAVA_HOME=C:\Program Files\Java\jdk1.8.0_161
```
ちなみに、最初binまでパスを通していたが、mvn -vで確認したらまた怒られました
swift初心者:「Class 'ViewController' has no initializers」の対処方法

#はじめに
初歩的なエラーかと思いますが、初心者のため備忘録を含め記録として残したいと思います。

##①Class 'ViewController' has no initializers

```swift:ViewController
import UIkit

class ViewController: UIViewController {

    var sum: Int 
}
```

上記のようなコードを記入した際に発生するエラーです。

nilを許していただけないようです。

以下のどちらか一方の対策を行えば改善されると思われます。

①ViewController内にプロパティの初期値をオプショナル型で定義

```swift:ViewController
import UIkit

class ViewController: UIViewController {

    var sum: Int!
}
```

もしくは

②値を代入。


```swift:ViewController
import UIkit

class ViewController: UIViewController {

    var sum: Int = 0
}
```

以上のように実施することで、エラーが解消されるかと思います。
[覚書]XCodeでユニットテスト時のエラー


## Ambiguous type name 'SomeClass' in 'AnotherClass'

### 原因

Testターゲットの"Build Phases">"Compile Sources"に、テスト対象のソースを含めてしまっていたせいのようだった。

### 解決方法

"Compile Sources"には、テストクラスのみにした。

![スクリーンショット 2018-02-19 15.11.44.png](https://qiita-image-store.s3.amazonaws.com/0/20722/5d92d25d-27a6-c3eb-4d1b-15d68d1e820a.png "スクリーンショット 2018-02-19 15.11.44.png")



### 参考：

[Ambiguous type name in Swift unit test](https://stackoverflow.com/questions/45895186/ambiguous-type-name-in-swift-unit-test?noredirect=1&lq=1)

## Test target X encountered an error (Early unexpected exit, operation never finished bootstrapping - no restart will be attempted

### 解決方法：

"Build Settings">"Linking">"Runpath Search Paths"に ```$(FRAMEWORK_SEARCH_PATHS)``` を追加する。 

![スクリーンショット 2018-02-19 15.02.25.png](https://qiita-image-store.s3.amazonaws.com/0/20722/fc587504-e494-5710-b9e2-c98d53f5563a.png "スクリーンショット 2018-02-19 15.02.25.png")


### 参考：

[https://stackoverflow.com/questions/34990175/test-target-x-encountered-an-error-early-unexpected-exit-operation-never-finis](https://stackoverflow.com/questions/34990175/test-target-x-encountered-an-error-early-unexpected-exit-operation-never-finis)
[onmyway133/TestTarget](https://github.com/onmyway133/TestTarget)
JMeter で独自関数を定義する

# 概要

JMeter で独自関数を定義する方法を記載します。

独自関数の定義方法は JMeter の公式ドキュメントには記載がないです。

WEB検索すれば英語での解説記事は簡単に見つかりますが、日本語での解説記事は見つからなかったので、自分が書いてみることにしました。

英文に抵抗がない人は以下を参照した方がいいです。

* http://www.testautomationguru.com/jmeter-extending-jmeter-creating-custom-functions/
* https://www.javacodegeeks.com/2013/06/jmeter-custom-function-implementation.html

# 手順

大まかな流れは以下です。

1. 関数のソースコードを作成する
2. コンパイルして jar を生成し、JMeter に追加する
3. シナリオから参照する

## ソースコード

以下のサンプルコードを基にして、カスタマイズしてください。
※package 名は functions を含む必要があります。

```java:SampleFunc.java
package jp.proj.jmeter.functions.sample;

import org.apache.jmeter.engine.util.CompoundVariable;
import org.apache.jmeter.functions.AbstractFunction;
import org.apache.jmeter.functions.InvalidVariableException;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.samplers.Sampler;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * JMeter 関数の定義
 * 機能：引数を二つ受け取り、引数を連結した文字列を返す
 */
public class SampleFunc extends AbstractFunction {

    /**
     * 引数の説明
     */
    private static final List<String> desc = new ArrayList<String>();
    /**
     * 関数名
     * prefix として __ を付けること。
     */
    private static final String MyFunctionName = "__SampleFunc";

    static {
        desc.add("引数１");
        desc.add("引数２");
    }

    /**
     * 引数を保持しておくための変数
     */
    private List<String> args;

    public SampleFunc() {
        super();
    }

    @Override
    public List <String> getArgumentDesc() {
        return desc;
    }

    /**
     * 関数本体
     * @param arg0
     * @param arg1
     * @return
     * @throws InvalidVariableException
     */
    @Override
    public String execute(SampleResult arg0, Sampler arg1) throws InvalidVariableException {
        return args.get(0) + args.get(1);
    }

    @Override
    public String getReferenceKey() {
        return MyFunctionName;
    }

    @Override
    public void setParameters(Collection< CompoundVariable > parameters) throws InvalidVariableException {
        args = parameters.stream().map((param) -> param.execute().trim()).collect(Collectors.toList());
    }
}
```

## コンパイル

org.apache.jmeter.ApacheJMeter_core に依存しています。

## JMeter に追加

生成した jar ファイルを \<JMETER_HOME>/lib/ext　に追加して、JMeter をリスタートします。

## シナリオから参照

${__SampleFunc(hoge1, hoge2)} で参照可能です。
G Suite Admin権限が割当られてる俺がSAMLログインチェックするときの注意

俺です。

SAML最高だわっていってたんですが若干G SuiteのSAML設定がうまくいってるかなとおもったら半端に動いてない。
のかなーとおもったら権限の違いっぽい。

# G Suite 一般権限を付与した社員のケース

ok SAML牧場

0.G SuiteのURLへアクセス。
1.自社のユーザー名+ドメインでログイン(hogetaro@andgate.co.jpなど自社ドメイン)
2.G Suite側でJumpCloud Consoleへリダイレクトされる
3.JumpCloudコンソールからログイン
4.JumpCloudコンソール内のG Suiteへログイン


# G Suite 管理者な俺のケース

No SAML牧場

0.G SuiteのURLへアクセス。
1.自社のユーザー名+ドメインでログイン(hogetaro@andgate.co.jpなど自社ドメイン)
2.G Suite側でJumpCloud Consoleへリダイレクト`されずに`G Suiteログイン画面が表示される

どーも管理者権限はSAMLリダイレクトページに飛ばない臭い。
マニュアルにかいてあったような気がするけど記憶失ったのでここに残す。

`死`