OmniAICreator/Qiita-1.07M huggingface dataset:
https対応したLaravelプロジェクトでassetを使う時の注意点

Laravel5.5製のWebアプリケーションをhttps化させた時に遭遇した問題とその解決方法について書きます。

# 読み込みファイルのパスのプロトコルが変わらない問題
Laravelにはviewでcssやjsを読み込む際にフルパスを記述するためのメソッドが用意されています。

たとえばcssを読み込みたい時は

```html
<link href="{{ asset('css/your_app.css') }}" rel="stylesheet">
```

jsを読み込みたい時は

```html
<script src="{{ asset('js/your_app.js') }}"></script>
```

と書くことができます。
これらは実際にローカルでページにアクセスすると

```
# css
http://localhost/css/your_app.css
# js
http://localhost/js/your_app.js
```

のように展開されます。
headerの情報を元に参照hostを判断して動的に生成してくれます。

しかし、なぜかプロトコルのところはアクセス元の情報に沿わずにhttpとして展開されてしまいます。

`https://your_domain` にアクセスしたら

```
# css
http://your_domain/css/your_app.css
# js
http://your_domain/js/your_app.js
```

と展開されます。
これだとcssとjsのロードエラーがフロントで発生するため、何かしら回避策が必要です。

# 回避方法
そこで、https通信のときだけassetで返されるURLをhttpsにすることにしました。

まずhttpsかどうかの判定にはリクエストオブジェクトから呼び出せる`isSecure`というメソッドを使って判定しました。
これは単純にアクセス元のプロトコルだけでなく、headerの`X_FORWARDED_PROTO`も見てくれるので、AWSでロードバランサーを介してhttps化している場合でも対応が可能です。

ただし、ロードバランサー経由の場合は追加で

```php:TrustProxies.php
protected $proxies = '**';
```

と記述する必要があります。
Laravelはデフォルトではプロキシー経由のリクエストにおけるhttpsを許容していないらしく、TrustProxies.phpに追記する必要があります。AWSのロードバランサーはipアドレスが動的に変わるためワイルドカードを指定します。
参考: https://readouble.com/laravel/5.5/ja/requests.html#configuring-trusted-proxies

そして、URL生成でhttpsを強制するための方法として`forceScheme`というメソッドが用意されているので、これを使いました。
https://laravel.com/api/5.5/Illuminate/Routing/UrlGenerator.html#method_forceScheme

AppServiceProviderのboot()の中に下記の記述をすることで対応できます。

```php:AppServiceProvide.php
    public function boot()
    {
        if (request()->isSecure()) {
            \URL::forceScheme('https');
        }
    }
```

これでhttpでもhttpsでも大丈夫になりました。

# 最後に
調べていると本番環境は常にhttpsにするって方法がちらほら出てきましたが、ステージング環境とか必要箇所が増えるたびに環境変数の対応箇所が増えてきてしまうので、単純に通信のプロトコルをみて判断できる実装のほうが良いのではないかなと思いました。

また、こういうエラーはローカルでは検証しづらく、httpsな環境にあげたときにしか気づけ無いので、httpsなステージング環境は必要ですね。
使いやすいUIAlertControllerのExtensionを考えたので載せてみる


# 実装
```swift
extension UIAlertController {
    static func noButtonAlert(title: String?, message: String?) -> UIAlertController {
        return UIAlertController(title: title, message: message, preferredStyle: .alert)
    }
    static func okAlert(title: String?,
                        message: String?,
                        okHandler: ((UIAlertAction) -> Void)? = nil) -> UIAlertController {
        let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
        alert.addAction(.init(title: "OK", style: .default, handler: okHandler))
        return alert
    }

    static func errorAlert(title: String? = "⚠️",
                           error: Error,
                           okHandler: ((UIAlertAction) -> Void)? = nil) -> UIAlertController {
        let alert = UIAlertController(title: title, message: "\(error)", preferredStyle: .alert)
        alert.addAction(.init(title: "OK", style: .default, handler: okHandler))
        return alert
    }

    static func fieldAlert(title: String?,
                           message: String?,
                           placeholder: String?,
                           handler: ((String?) -> Void)? = nil) -> UIAlertController {
        let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
        alert.addTextField {
            $0.placeholder = placeholder
        }
        alert.addAction(.init(title: "OK", style: .default, handler: { (action: UIAlertAction) in
            handler?(alert.textFields?.first?.text)
        }))
        alert.addAction(.init(title: "Cancel", style: .cancel, handler: { (action) in
            handler?(nil)
        }))
        return alert
    }
}

extension UIViewController {
    func present(_ alert: UIAlertController, completion: (() -> Void)? = nil) {
        present(alert, animated: true, completion: completion)
    }

    func present(_ alert: UIAlertController, _ autoDismissInterval: TimeInterval, completion: (() -> Void)? = nil) {
        present(alert, animated: true, completion: { [weak self] in
            DispatchQueue.main.asyncAfter(deadline: .now() + autoDismissInterval) {
                self?.dismiss(animated: true, completion: completion)
            }
        })
    }
}

```

# 使い方

```swift
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        // OKボタンのみのAlertを表示
        present(.okAlert(title: nil, message: "グループを作成しました"))

        // OKボタンのついたErrorを表示するAlertを表示
        present(.errorAlert(error:　NSError(domain: "hoge", code: 0, userInfo: nil)) { _ in
        // ユーザが閉じたあとに行う処理を記述
        })

        // UITextFieldつきのAlertを表示
        present(.fieldAlert(
            title: "グループの作成", message: "グループ名を入力してください", placeholder: "グループ名",
            handler: { [weak self] (inputText) in
                // 入力されたテキストを使う処理を記述
        }))

        // 0.3秒後に自動で閉じる
        present(.noButtonAlert(title: "✅", message: "保存しました"), 0.3) { [weak self] in
            // ユーザが閉じたあとに行う処理を記述
        }
    }
}
```
#python の findall で #正規表現 マッチをおこなうと、戻り値には割と癖があるので注意

# グルーピングなしの場合

マッチした全体が配列で返ってくる

```
>>> re.findall(r'lic', 'AliceAliceAlice')
['lic', 'lic', 'lic']
```

# カッコでグルーピングした場合

グルーピングした部分のマッチ結果が配列が返ってくる
```
>>> re.findall(r'l(i)c', 'AliceAliceAlice',)
['i', 'i', 'i']
```
# カッコで複数グルーピングした場合

tuple の配列が返ってくる
```
>>> re.findall(r'A(li)(ce)', 'AliceAliceAlice')
[('li', 'ce'), ('li', 'ce'), ('li', 'ce')]
```

# グルーピングしつつキャプチャしない書き方

```
>>> re.findall(r'l(?:i)c', 'AliceAliceAlice')
['lic', 'lic', 'lic']
```

# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/1653








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
Jenkinsのどのワークスペースが容量を大きく占有しているか確認する

Jenkinsで古いワークスペースを削除しないようにするとどんどんと溜まっていき、サーバ容量を圧迫する。

どのワークスペースが容量を占めているかを以下のコマンドで確認する。必要に応じて該当のワークスペースを削除するのに使える。

`du -sh /var/lib/jenkins/workspace/* | sort -nr`
Wordpressのちょっとした書き換えで常時SSLを行なう - .htaccessで常時SSLをするのに都合が悪い方に

#はじめに
通常の常時SSLの設定では、事情によりサーバー業者の仕様で、SSLの更新ができなくなることがあり、それがサブドメインにまで影響をすることがあります。

```.htaccess
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
</IfModule>
```

この記述を.htaccessに記載すると、エックスサーバーでは最短3ヵ月に1回、SSLの更新に関するエラーがでます。

#これを記載すればいいのですが

```index.php
if($_SERVER['HTTPS'] != 'on') {
        $url="https://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
        header( "HTTP/1.1 301 Moved Permanently" ); 
        header('Location: ' . $url);
        exit;
}
```

##・・・・いや待て、大問題です！
Wordpressの更新がかかったり、再インストールされると、この記述が消えてしまいます。

#結論
wp-config.php に以下の記述をしましょう。場所はどこでも構いません。

```wp-config.php
if($_SERVER['HTTPS'] != 'on') {
        $url="https://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
        header( "HTTP/1.1 301 Moved Permanently" ); 
        header('Location: ' . $url);
        exit;
}
```

#さいごに
この記事、似たような記事はあるものの、以外とぐぐっても出てこなかったのです。
【PHP】【Laravel】League of Legendsの公式からAPIキーを取得する。

#きっかけ
プログラミングを学ぶことも楽しいが、ゲームもやはり楽しい。（特にlol）
最近プラチナに昇格して、ほくほくである。
プログラミングもようやく色々とできるようになったので、いっちょここらで自作のwebサイトを作ろうかと意気込んでいた。

###そうだlolのデータを取得して分析サイト（個人趣味）を作ろう！

思い立ったが吉日。早速設計することにした。（頭の中で）
lolというゲームにおいて、忘れてはならないのが、OP.GGというサイトである。
このサイトで自分のゲームの中の名前を入れるやいなやものすごい量の戦績データなどを振り返ることのできる
神サイトである。
また、チャンピオンの勝率や、そのチャンピオンの使用武器ごとの勝率などとにかくすごい。
僕自身かなりお世話になったサイトである。~~僕をあおってきたやつの名前を検索してランクをあざ笑ったりした~~

なので、最初はそのサイトをスクレイピングして～（いいのかわからんが）と考えていたのだが、検索したところ。。。

###Riotから既にAPIが公開されているではないかあああああ！！！！

まさにS8途中にADCがADCでないメタが流行ったばりに衝撃を受けた。
lolネタがわかるひとならきっと伝わっていると思う。

#参考
[Riot Games APIでLeague of Legendsの試合データを取得しよう](https://qiita.com/himrox/items/8e99ee4a8451add5f332)
[RiotAPIを使ってLP変動を調べてみる](https://qiita.com/sasuke-287/items/8cd9cef4cb3c23cfafa0)

[公式サイト](Riot Games API)

幸運にも偉大なる先人たちがやってくださっていた。ありがとうございます。ちょっと記事が古いけども

#実践
今回の流れとしては、公式から発行されているAPIキーを使って自身に紐づくサモナーIDを取得して画面に表示しちゃおうというもの
まずはrouteから
###route
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402399/744c6b5b-5cc2-665f-6cdb-9cb12feb678d.png)

シンプルなルーティング。indexControllerのgetIDapiメソッドを使う。

###controller
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402399/28bdde97-2b40-1cb8-a8c7-d90c2458e404.png)

変数api_keyには、公式から発行されるAPIキーを入力する。
変数summoner_nameには、自分のサモナーネームを入れる。
変数regionには、自分のやっているサーバーを入れる。日本ならjp、NAならna

上記の変数は別に作成せずとも変数urlの中にべた書きで問題ない。変数urlさえ正しく作れていればOK

その後は、curlを使ってサーバーへリクエストを送り、サモナーIDを手に入れるという形。
この辺は参考サイト2番目のほうで詳しくやっていただいている。

セッションの項目は僕が勝手に作ってるだけなので気にしないでください。

取得し終えたら、api.blade.phpへ変数resultを返す。
この変数resultは配列になっているので注意。

###view
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402399/0cf166f5-9895-f6cd-86dc-25639c240bbf.png)

自分好みでわんわんおやらふざけているが最悪、11行目がかけていれば大丈夫。
ボタンの部分は今後自分が作る予定のために書いているので気にしないでください。
~~ソースがふざけすぎててわらった~~

#実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402399/85971f16-0b05-b9a9-b2d6-42540c38fa87.png)

なんかこんな感じでidやらサモナーレベルやら出たら合格！
nameには自分のサモナーネームが入っているよ。
（一応怖いので一部マスクしました。）

#注意点

ハマってしまった箇所が一点だけ。。。
参考サイトをみていてずっとうまくいかなかったのですが、Controllerのurlには注意してください。

https://jp1.api.riotgames.com/lol/summoner/v4/summoners/by-name/summoner_name.?api_key=[key]

この部分が参考サイトだと古いので必ず公式サイトを参照してください。（当時クローズドベータだったからだと予想）

#あとがき
僕自身APIを利用すること自体が初めてなので、HTTPリクエストとかも完全に理解してないと思います。。。（勉強します）
なので、文章自体が少しおかしかったり、なんならviewはたぶんインデントとかひどいと思うので
もしそういうことがあればコメントいただけたらと思います。。。

champion.gg?そんなサイトはもう知らんなぁ！
Qiita 表テンプレート


```
|  |  |
|:--|:--|
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
```

表示結果

|  |  |
|:--|:--|
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
|  |  |
WWWクラスが非推奨になっていた件

# 前置き

- 標準ブラウザに簡単にアクセスできるApplication.OpenURLとよくセット使っていたWWWが気づいたら非推奨になっていた。

```
Application.OpenURL("https://ja.wikipedia.org/wiki/" + WWW.EscapeURL(string.Format("hoge{0}", param)));
```

- Unity 2018 .3.11.f1

# 修正
警告メッセージ通りだけど
WWW → UnityEngine.Networking.UnityWebRequest

```
Application.OpenURL("https://ja.wikipedia.org/wiki/" + UnityEngine.Networking.UnityWebRequest.EscapeURL(string.Format("hoge{0}", param)));
```


# 参考
- [WWW.EscapeURL](https://docs.unity3d.com/jp/460/ScriptReference/WWW.EscapeURL.html)
- [UnityWebRequest.EscapeURL](https://docs.unity3d.com/ja/2017.4/ScriptReference/Networking.UnityWebRequest.EscapeURL.html)
APIサーバのレスポンスがスキーマ上のレスポンス定義と一致するかのテスト

[committee](https://github.com/interagent/committee)や[committee-rails](https://github.com/willnet/committee-rails)が(わからなかった|動かなかった)ので、[WEB+DB PRESS Vol.108](https://www.amazon.co.jp/WEB-DB-PRESS-Vol-108-%E4%B8%AD%E9%87%8E/dp/4297103249/)に記載されている方法でやってみた。

# ざっくり言うと

`oas_parser`でswagger.jsonをパースして、`json_schema`でバリデーションを行う


## gem

```ruby

gem 'oas_parser'
gem 'json_schema'
```

## swagger.json

```json
{
  "swagger": "2.0",
  "info": {
    "title": "API V1",
    "version": "v1"
  },
  "servers": [
    {
      "url": "http://localhost:3000/api-docs",
      "description": "development server"
    }
  ],
  "basePath": "/api/v1",
  "paths": {
    "/areas/{id}": {
      "get": {
        "summary": "Retrieves a area",
        "tags": [
          "Areas"
        ],
        "description": "Retrieves a specific area by id",
        "operationId": "getArea",
        "security": [
          {
            "apiKey": [

            ]
          }
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name":        "id",
            "in":          "path",
            "type":        "integer",
            "description": "エリアID",
            "required":    true
          }
        ],
        "responses": {
          "200": {
            "description": "success",
            "schema": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "integer"
                },
                "name": {
                  "type": "string"
                }
              },
              "required": [
                "id",
                "name"
              ]
            }
          }
        }
      }
    },
    "securityDefinitions": {
    "apiKey": {
      "type": "apiKey",
      "name": "Authorization",
      "in": "header"
    }
  }
}
```

## SchemaオブジェクトとJSON Schemaライブラリを用いてJSONのバリデーションを行う

+ spec/rails_helper.rb

```rb
RSpec.configure do |config|
  config.include ControllerSpecsHelper

  config.before :example, type: :controller do
    spec        = OasParser::Definition.resolve(Rails.root.join('swagger', 'v1', 'swagger.json'))
    schema_data = spec.path_by_path(schema_path).endpoint_by_method(schema_method).response_by_code(code.to_s).raw["schema"]
    @schema     = JsonSchema.parse!(schema_data) if schema_data
  end
```

+ spec/support/controller_specs_helper.rb

```rb
module ControllerSpecsHelper
  def expect_to_conform_schema(response)
    expect {
      @schema.validate!(JSON.parse(response.body))
    }.not_to raise_error
  end
end
```

## テスト

```rb
require 'rails_helper'

RSpec.describe Api::V1::AreasController, type: :controller do
  render_views

  describe 'GET #show' do
    let(:schema_path)   { '/areas/{id}' }
    let(:schema_method) { 'get' }
    let(:code)          { 200 }

    it 'conform json schema' do
      expect_to_conform_schema response
    end
    
  end
end
```
#python で｢改行を含んだ複数行｣の文字列を #正規表現 で置換する例

第四引数に `flags=re.DOTALL` を指定する。
```
>>> re.sub(r'A.+', 'SALADA', 'Alice\nBob\nCarol')
'SALADA\nBob\nCarol'
>>> re.sub(r'A.+', 'SALADA', 'Alice\nBob\nCarol', flags=re.DOTALL)
'SALADA'
```

# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/1652








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
#python で｢改行を含んだ複数行｣にマッチする正規表現を書く例

`re.DOTALL` をオプションで指定する
```
>>> re.findall(r'A.+', 'Alice\nBob\nCarol')
['Alice']
>>> re.findall(r'A.+', 'Alice\nBob\nCarol', re.DOTALL)
['Alice\nBob\nCarol']
```

# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/1651








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
EC2サーバが重いのでインスタンスストアボリュームを初期化した

# はじめに
EC2インスタンスでインスタンスストアのボリュームを使う際は、最初に初期化をしなければなりません。
このことを知らず、初期化をしないで使い続けた結果、サーバに負荷をかけてしまったことと、初期化によって解決したことの記録です。

## 起きたこと
・Webアプリの画面に、2時間ほど接続できなくなった
・Webアプリのバッチが、通常2分ほどで終わるものが30分かかった
・これらのことが不定期に起こった

## 調査
sarコマンドで調べたところ、iowaitとロードアベレージの負荷が高いことはわかりました。
しかし、根本的な原因がわからないため、AWSサポートへ質問したところ、

・インスタンスストアがボトルネックになった可能性がある
・インスタンスストアが高いディスクパフォーマンスを必要とする場合には一度初期化が必要だが、実施しているか
との回答をいただきました。


**インスタンスストアとは**
インスタンスに刺さっているストレージです。高速に読み書きができる一方、サーバを再起動するとデータが消えてしまうという特徴があります。
本件では一時ファイルの置き場として利用しています。

詳しくは公式ドキュメントを参照してください。
[AWSドキュメント - インスタンスストア](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/InstanceStorage.html)

**初期化とは**
インスタンスストアボリュームへの最初の書き込みは、速度が遅いという特性があります。
先にすべての場所に書き込みを行うことで、パフォーマンスを上げることを「初期化」と呼ぶようです。

数年前までは、EBSも同じように「プレウォーミング」と呼ばれる初期化を必要としていましたが、現在は不要になっています。


## 対応
インスタンスストアボリュームの初期化を実行しました。
方法は、 `dd` コマンドでインスタンスストアボリュームに書き込みをします。一度書き込むことで、そのあとの読み書きがスムーズになるという寸法です。

**！！！注意！！！**
インスタンスを作成した直後に行うこと。
既に運用が始まっている場合は、バッチやCGIに影響を与えないよう、一時ファイル置き場の参照先を変更するなどの対策が必要です。


```
$ dd if=/dev/zero of=/dev/sdb bs=1M          
$ dd if=/dev/zero of=/dev/sdc bs=1M          
$ dd if=/dev/zero of=/dev/sdd bs=1M          
$ dd if=/dev/zero of=/dev/sde bs=1M
```

## 結果
不定期に起きていたサーバの高負荷が起きなくなくなりました。

## 注意点
インスタンスストアボリュームの初期化は、インスタンスを停止/起動（再起動）したときに都度行う必要があります。
起動スクリプトを組んでおくとよいでしょう。

## 参考
[AWSドキュメント - インスタンスストアボリュームのディスクパフォーマンスの最適化](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/disk-performance.html)

### 2019/5/24 追記
先日、Amazon Linux の c3.xlarge から c3.2xlarge へスケールアップし、
またインスタンスストアの初期化をしたので時間を計測してみました。

c3.2xlargeのインスタンスストレージは 80GB が2つ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/408585/4aac9d0e-794c-2a6e-16cc-a3bb556f0c01.png)

2つのボリュームに対し初期化を実行。
計測結果は、片方は45分、もう片方は35分でした。

```
$ dd if=/dev/zero of=/dev/sdb bs=1M  # 約45分で終了
$ dd if=/dev/zero of=/dev/sdc bs=1M  # 約35分で終了
```

80GB のインスタンスストアボリュームを初期化するのに、40分くらいかかると想定しておくと良さそうです。
Pythonの配列の初期化で[['-']*3]*4のように書くと各要素がコピーされてしまうので代入操作で罠にはまる

# 覚書
配列操作でサイレントエラーになりハマった。
２次元配列で掛け算記号```*```を使って初期化すると、ある要素に対する操作がすべての要素に反映されてしまう。


```python
# 初期化
m = [['-']*3]*4

# mの中身
# [['-','-','-'],
#  ['-','-','-'],
#  ['-','-','-'],
#  ['-','-','-']]

# 代入操作をする
m[0][1] = '%'
# すべての要素に代入が反映されてしまう。
# [['-','%','-'],
#  ['-','%','-'],
#  ['-','%','-'],
#  ['-','%','-']]

# 本当はこうなってほしい
# [['-','%','-'],
#  ['-','-','-'],
#  ['-','-','-'],
#  ['-','-','-']]

```

# 対処法
初期化の記述を変更する

```python
m = [['-']*3 for _ in range(4)]
```

以上
「docker-compose up」をしようとしたところ「OCI runtime create failed」

## DockerでPHPの開発環境を構築していたところエラーが発生
***環境***

- macOS mojava（バージョン10.14.4）
- Docker version 18.09.2

## エラーの内容

```
docker-compose up -d
``` 
でコンテナを一斉に立ち上げた際に以下のエラーが発生

```
Creating php_mysql_nginx_db_1 ... error

ERROR: for php_mysql_nginx_db_1  Cannot start service db: OCI runtime create failed: container_linux.go:344: starting container process caused "process_linux.go:424: container init caused \"rootfs_linux.go:58: mounting \\\"/Users/UserName/WorkSpace/php_mysql_nginx/mysql/data\\\" to rootfs \\\"/var/lib/docker/overlay2/51d8c0970ffca60b031d04ce28ec8224c6d81ec33635095cc3e2bb6b78cc1a53/merged\\\" at \\\"/var/lib/docker/overlay2/51d8c0970ffca60b031d04ce28ec8224c6d81ec33635095cc3e2bb6b78cc1a53/merged/var/lib/mysql\\\" caused \\\"not a directory\\\"\"": unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type

ERROR: for db  Cannot start service db: OCI runtime create failed: container_linux.go:344: starting container process caused "process_linux.go:424: container init caused \"rootfs_linux.go:58: mounting \\\"/Users/UserUserName/WorkSpace/php_mysql_nginx/mysql/data\\\" to rootfs \\\"/var/lib/docker/overlay2/51d8c0970ffca60b031d04ce28ec8224c6d81ec33635095cc3e2bb6b78cc1a53/merged\\\" at \\\"/var/lib/docker/overlay2/51d8c0970ffca60b031d04ce28ec8224c6d81ec33635095cc3e2bb6b78cc1a53/merged/var/lib/mysql\\\" caused \\\"not a directory\\\"\"": unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type
ERROR: Encountered errors while bringing up the project.
```
<br>

## 試したこと
### 1. docker volumeの削除

未使用のvolumeを一括削除

```
docker volume rm $(docker volume ls -qf dangling=true)
```
それでもって再度```docker-compose up -d```を試みるも同じエラー

<br>

### 2. エラーが起きている箇所`docker-compose.yml`ファイルのdb箇所のvolume部分だからその部分のパスを変える

```
db:
    image: mysql:5.7
    ports:
      - 13306:3306
    volumes:
      - ./mysql/data:/var/lib/mysql
```

こうなっていたのを以下のようにしたところ上手くいった！

```
db:
    image: mysql:5.7
    ports:
      - 13306:3306
    volumes:
      - ./mysql:/var/lib/mysql
```
SATySFiでもSI単位を使いたい！


[SATySFi](https://github.com/gfngfn/SATySFi)で化学系のレポートや、物理系のレポートを書く時に、"kg"などの単位を書かなければいけないときが来ると思います。

この時に、適当に`${5kg}`などと書くと、"kg"が斜体になってしまいますし、一々`${5\text!{kg}}`などと書くのはなかなかに面倒です。そこで、これらを補助するパッケージを作りました。

SI単位と一部の非SI単位をサポートする、[siunitxパッケージ](https://github.com/puripuri2100/SATySFi-siunitx)です。

# 導入方法

SATySFiのパッケージマネージャである[satyrographos](https://github.com/na4zagin3/satyrographos)に登録してありますので、これを導入している人は

```
$ opam install satysfi-siunitx
$ satyrographos install
```

とするだけで使えるようになります。


satyrographosを導入していない人はcloneしてからsiunitx.satyhというファイルをSATySFiが見つけられる場所（例えば`~/.satysfi/dist/packages`や`~/.satysfi/local/packages`など）に置いてください。

# 使い方

全てのコマンドは引数のない`math`型ですので、数式環境内で用いてください。

例：

```
${5\kilogram}
${5\peta\gram}
```

使えるコマンドについては、docフォルダ内にあるsiunitx-ja.satyをコンパイルして読んでみてください（あとでここにも書くかも）。

**結構便利なのでぜひ使ってみてください**（リポジトリにstarを押していただけると嬉しいです……。）

# 改善したい点

- スペーシングがおかしいところがあるのでそこの改良
- 英語版ドキュメントの作成
@Nekonecode  FOF(First, One File)。仮説（45）

@Nekonecode 良いプログラムを書くために心がけたい、たった１つの事「FOF」
https://qiita.com/Nekonecode/items/a0d9e7eea90bdcf5e3a2

>「まず１ファイル」

記事拝見しました。そう。これなんです。個人でも、複数人でも。

# 班活動(group work)
班活動(group work)をする前に、個人作業した結果を持ち寄るようにしています。
FOFの原則のGroup版です。

当方では班活動はGitlabにあげたソースコードか、Wiki、Issueの記事を使っています。
設計審査(Code Review)にしろ、週報にしろ、全員がGitlabに上げてから始めます。

## 量の少ないものから議論(little thing first)
量の少ないものから議論すれば、すべてを議論できたり、みんなが主人公になれたりします。
量の多いものから議論すると、時間ぎれになったり、他の内容をそこに含んでいて、議論しないものができてしまう。
すべての人を主人公にした議論ができることが班活動では大事です。

# 具体例(example)
私は、主に試験担当です。
ソースコードをあげる時は試験プログラム
試験結果から直すとよい変更提案
分析結果
を上げます。

対象の設計が決まっていなくても、最終顧客を想定した、受け入れ試験案を書きます。

# 過去のいやな思いで(Past bad cases)
過去の否定的なことを書くのは、今日はやめておきます。
とにかく、自分で書いたものを持ち寄るのが基本。

自分の手を動かさないで、人の批判や足をひっぱる人はいらない。
それぞれが書いたものを持ち寄れば、他人を批判する時間が無駄だとわかる。

# 参考資料
@kazuo_reve 私が効果を確認した「小川メソッド」
https://qiita.com/kazuo_reve/items/a3ea1d9171deeccc04da

@kazuo_reve 新人の方によく展開している有益な情報
https://qiita.com/kazuo_reve/items/d1a3f0ee48e24bba38f1

@kazuo_reve ワークショップ「ソフトウェア開発におけるHAZOP入門」の結果
https://qiita.com/kazuo_reve/items/c1c1d32baed5d60d55c7

## 自己参照
効率的なHAZOPの進め方。仮説（187）
https://qiita.com/kaizen_nagoya/items/2b8eae196945b7976446

「@kazuo_reve ワークショップ「ソフトウェア開発におけるHAZOP入門」の結果」の分類
https://qiita.com/kaizen_nagoya/items/e62e91cb019c6275d6c1

公開算譜は機敏だ(An Open Source Project is Agile)GitHub with Docker。仮説（51）
https://qiita.com/kaizen_nagoya/items/5dd49a046b5991af3a5e

「会議は30分未満」小耳にはさんだ話。臨機応変。
https://qiita.com/kaizen_nagoya/items/55ab43e7f50434156ff4

### 文書履歴(document history)
ver. 0.01 初稿 20190506 
ver. 0.02 かきかけの文を書き終わる。 20190507
ver. 0.03 参考資料追記　20220307
### 最後までおよみいただきありがとうございました。
いいね　💚、フォローをお願いします。
#### Thank you very much for reading to the last sentence.
Please press the like icon 💚　and follow me for your happy life.
Scratch3.0でmicro:bitを使う

# 概要
Scratch3.0になりmicro:bitと連動するようになったので、使ってみた。とても、簡単に連動させることができた。

# 準備
- 準備条件、Winあるいはmac,Bluetooth4.0。
- 流れ。scratch linkというソフトのインストール、micro:bitの準備、Scrathサイトに行く、scratch上で拡張機能を導入する
- [Scratch Linkというソフトをインストールする。OSはWin10とMac（双方バージョンの指定がある）](https://scratch.mit.edu/microbit)
- インストールのOSは自動判定されるので指示にしたがって、インストール。
- 以下はmacでインストールが完了したときに現れたアイコン
- <img width="226" alt="スクリーンショット 2019-05-06 7.40.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237044/86d76a96-c69d-bf63-f807-12f450ab4f6f.png">
- [micro:bitには専用のhexファイルを書き込む必要あり](https://scratch.mit.edu/microbit)
- 上のサイトからHEXファイルをダウンロードして書き込む。
- [Scratch3.0はWebベースなのでインストールの必要なし](https://scratch.mit.edu)
- プログラムを作る画面の左下の青いフォルダーボタンをクリックする。
- <img width="1161" alt="スクリーンショット 2019-05-06 7.28.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237044/389c22be-8da2-9328-8c25-63f72e99a176.png">
- クリックすると拡張メニューが表示されるのでmicro:bitを選んで、クリック。
- <img width="977" alt="スクリーンショット 2019-05-06 7.32.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237044/d96498fe-c6a7-0770-b9bf-6a88566d4a88.png">
- ここでscratch3.0とmicro:bitが接続される。
- <img width="549" alt="スクリーンショット 2019-05-06 7.49.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237044/d47399f8-5e48-2b03-cffa-8194e3713823.png">

- これでmicro:bitのブロックが表示されるので、準備完了！。ここで緑の丸チェックマークが出ていることが必要。
- <img width="318" alt="スクリーンショット 2019-05-06 7.59.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237044/22d56096-fd96-e25c-7bd6-6d8a9b0fb806.png">
- 下のように、オレンジのビックリマークがでていたらmicro:bit側の準備ができていません。オレンジのマークをクリックするとmicro:bit探索の画面が表示される。見つからない場合は、Scratch Linkの導入確認、micro:bitのHexファイル導入確認、場合によっては、micro:bitのファームウェアのバージョン、OSのバージョン確認が必要と思う。

- <img width="684" alt="スクリーンショット 2019-05-06 7.43.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237044/06d49da9-3a5b-ccd7-b300-161eff8bfd89.png">

# サンプル

- micro:bitのAボタンを押すと「左に10歩」、「Bボタンを押すと「右に10歩」、A＋Bボタンで「ジャンプ」
- <img width="684" alt="スクリーンショット 2019-05-06 7.43.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237044/b239297e-b01c-05e3-25f6-6fe7d12635cd.png">

# 参考
- [micro:bitのファームウェアを最新版](https://sanuki-tech.net/micro-bit/appendix/update-firmware/)にする必要があると思う。
- micro:bit用のソフトは2019.5.5時点では、でした。導入時期に併せて最新版を確認してください。
Day004 webエンジニアへの道 - rails tutorialを始める -

こんにちは。
webエンジニアを目指すtomoです。

エンジニアの勉強をしている日々の学びを記録しています。

私自身の頭の整理と今後迷った時のリファレンスも兼ねて書き連ねていきますが、同じようにエンジニア転職を考えている方の参考にもなればと考えています。
また、「ここ間違ってる！こっちが正しい！」といったご指摘もあれば頂けると嬉しいです🙏

---

##[1.3.2 rails server]のブラウザ表示でつまづく

[railsチュートリアル](https://railstutorial.jp/chapters/beginning?version=5.1#fig-share_workspace)の文章に「クラウドIDEの場合は、[Share] を開いて、開きたいアプリケーションのアドレスをクリックします(図 1.11)。]と記載があり、文章に従って進めていたのですがうまく表示されませんでした。

調べた結果、文章ではなく図1.11と図1.12に従うことでブラウザを正しく表示することができました。

正しくは「クラウドIDEの場合は、[Preview]から[Preview running application]を開いて、アドレスバーの右横にあるブラウザ展開アイコンをクリックする。」のようです。
*[Share]から開く方法があれば教えてください！

[参考]
[Cloud9上でのRuby on rails サーバ起動/ページ表示方法(Ruby on rails Tutorial 1.3.2)](https://qiita.com/iwato/items/c70eeb87f944043ba356)

##★メモ

######*後日調べること & 気づいたこと

- チュートリアルとWikipediaでMVCモデルの概念図が異なるので、他のサイトではどのように説明されているか調べる。

##さいごに

5月5,6日は勉強外の予定があり進捗少ないかもしれませんが、毎日少しでもコードを書いて進めたいと思います。

---

twitterもやっているので、宜しければフォローお願いします！
[@tomo_tech_](https://twitter.com/tomo_tech_)
メモ PHP docker xdebug

# 何がしたい
dockerコンテナとしてnginxとphp-fpm動作させて、PhpStormを使ったxdebugによるリモートデバッグできるまでをやる


# Overview
* mac
* dockerはdocker-for-mac
* dockerコンテナ上でnginxが動作
* dockerコンテナ上でphp-fpmが動作
  * with Xdebug
* PhpStormでXdebugリモートデバッグをする


# Source

https://github.com/tttreal/local-php-debug


# HTTPリクエストの処理概要
* nginxにport:80でリクエストが飛ぶ
* nginxからphp-fpmにport:9000でリクエストが飛ぶ（９０００はphp-fpmのデフォルト設定）
* php-fpmはphpを動作させてレスポンスする
  * php上でxdebugが動作する (`xdebug.remote_autostart=1` なので、勝手に動作)
  * php上のxdebugが、phpの処理中に、`xdebug.remote_host`に対してDBGp接続（これなに？）を試みる
    * 公式の説明gif: https://xdebug.org/images/docs/dbgp-setup.gif
  * PhpStormがDBGpをうまくやっている・・・んだと思う（曖昧・・・💧）
* nginxがphp-fpmのレスポンスをクライアントに返す

（URLに`?XDEBUG_SESSION_START=xxx`とかつける必要はないよ）

# docker
* nginx用のコンテナ、php-fpm用のコンテナ　を作成する
* docker-for-macだと、"dockerのホストマシン"というのはmacではなく、mac上で動いている仮想環境
  * アクセスする方法は、https://gist.github.com/BretFisher/5e1a0c7bcca4c735e716abf62afad389
* コンテナから見たmacは、docker.for.mac.host.internal
  * （ちなみにホストマシンはhost.docker.internal）
* せっかくなので、docker-composeを使う


# Xdebug
* なんでかXdebugがデフォルトで使うport:9000と、php-fpmがデフォルトで使うport:9000とが、被っているので、どちらかを変える必要がある
  * なんでやねん
* 設定例

```ini
xdebug.idekey="PHPSTORM"
xdebug.remote_enable=1
xdebug.remote_host=docker.for.mac.host.internal
xdebug.remote_port=9001
xdebug.remote_autostart=1
; xdebug.remote_connect_back=1
```

* 設定を参考にしたページ・・・は色々あったけど、どれもしっくりこなかった。公式は https://xdebug.org/docs/all_settings


# PhpStorm

よくわかんなかったんで適当にやった・・・

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31118/0aed9a56-2fb0-ad71-305a-a149b495a755.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31118/e7d20a9a-4c00-2acf-00e5-4166ba2ac64c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31118/43d9301d-6aa0-d7b0-62ea-a4fa3dc28227.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31118/671008ed-0417-1623-3a02-fba1816b4bae.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31118/33c7bfca-dc76-ea47-250b-1427ba6957c4.png)
DMD 2.086.0リリースによせて？個人的な活動記録

## はじめに

リリースの中身のちゃんとしたやつは @lempiji さんが [書かれた](https://qiita.com/lempiji/items/0336fc2497588083dc77) のでそっちをみてください。自分の記事はチラシの裏みたいなものです…

迂闊に記事書くかーとか言っちゃったせいで言及されてしまったので書くことになってしまいました、、イキるのはだめですね。
考えてみると大した修正でもないので書くことないんだよな。まあどういうふうに修正したかとかを併せて書いてみます。

あとちょこっとざっくりしたトピックも追記しました。

## なおしたバグの解説

チケット番号の並びが順番になっていないんですが、覚えているやつは修正した順に時系列で並べています。

ほんとは他のBugも解説したほうがいいかと思ったんですが(とくにBugzilla 17684とか)、これPRを6個にわけて修正されてて追うのが面倒なんですよね。なので宿題です(？)

### Bugzilla 19804

[対応したPR](https://github.com/dlang/dmd/pull/9623)

これは関数の引数の型で、float型の要素をもつ構造体の静的配列でサイズが1であるときだけコンパイラがエラー `tym=x27` を吐いて異常終了するというregressionでした。(あと再現条件がネストした関数をつかっているか `-g` オプションをつける必要がある、というのがあったので他の人が再現できなかったっぽい)

これはBugzillaで見つける前に、[なんかこういう意味不明なエラーが出るんだけどー、というブログ記事](https://sobaya007.github.io/2019/04/11/dmd2.085.0%E3%81%A7%E8%AC%8E%E3%81%AE%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%8C%E5%87%BA%E3%81%A6%E3%83%93%E3%83%AB%E3%83%89%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%8F%E3%81%AA%E3%82%8B%E4%BB%B6%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6/) を見かけてなおした感じです。

エラーをすでにassertで拾えてたので `xmmstore` という関数で型のチェックに失敗してることがわかり `x27` が `Tysarray` (内部的に静的配列を表す型情報)なので、再現条件からfloatを要素に持つ構造体のサイズが1の静的配列をXMMレジスタに割り付けるような最適化をしているんだなというあたりはすぐにつきました。実際に `src/dmd/backend/cod1.d` 内の `FuncParamRegs_alloc` 関数にそういった最適化の処理が書かれていました。この関数は最適化するぞ！という情報しかもたせてないので、あとは実際にcodegenするところに同じような修正を入れてやればいいだけです。

というかこの最適化を足した後でテストしなかったってことですねこれ。

### Bugzilla 19806

そういえばphobosも一個バグ修正していたのだった、URLにs足しただけなんだけど、まあこういう貢献もありです。

### Bugzilla 19519

[対応したPR](https://github.com/dlang/dmd/pull/9634)

静的配列の長さがコンパイル時に決定しない、というバグです。

これ `s.e` のようなドットでアクセスされるような変数を普通の変数と別に内部で扱っているんですが、そこの条件を足してなかったために長さ情報を決定する処理に到達してなかったというわりとしょうもないバグです。でもこれきづくのわりと無理ゲーだよな。このPRだけNice!ってコメントもらいました。
GDBで泥臭く頑張った感じでとくにおもしろい話はないです。

これいつからのregressionなのか調べてないな。

### Bugzilla 19540

[対応したPR](https://github.com/dlang/dmd/pull/9695)

テンプレート実体化の処理をするときに `typeof` の中で無名クラスをnewするときだけ発生する珍しい、別の言い方をするとこんなん普通に書いてたら遭遇せんだろというバグです。
単なる初期化漏れだったのですが、コンパイラがSEGVで落ちるというのはいかんなあ、というのでえいやっって感じでなおしました。

### Bugzilla 19833

[対応したPR](https://github.com/dlang/dmd/pull/9723)

`getMember` で `template` を取得しようとするとその型だとできないよ、というregressionです。もくもく会のときにshooさんに報告してもらったバグです。typesem(型に関する意味論が定義されているコード)をリファクタリングしたときに誤って混入してしまったバグで、元々の処理と同じようにtemplateが渡されたときにちゃんと評価されるように修正しました。

### その他の修正

- バグじゃないけどdubの `list-installed` コマンドを消しました。これ2013年からdeprecatedになってたんですがなぜか残ってたのでした。
- たぶんDWARFのDW_AT_producerのコンパイラ情報を修正したのもこのバージョンからだったはず…

## その他トピック的なもの

- `lowmem` オプションを渡すとコンパイル時にGCが動くのでピーク時のメモリ消費量がぐっとへるらしいです。あと実行時間がちょっと遅くなるらしい。
- GC parallel-markingはきっと次に入るので待ちです。rainers先生はすごいのですごい。

## あとがき

やってみたら意外とすんなりpatch書けたので続けて出してみた(いやまだむずかしいやつはできてないんだけど)、ってくらいの感じなのでみなさんも挑戦してみてはいかがでしょうか。自分は去年の７月くらいからときどきpatch投げてるくらいでそんなにたいしたことはできませんが、なにかしら手伝えることがあればするので気軽に尋ねてください。
Windows Server 2012 R2 EssentialsへSystem Center Endpoint Protectionをインストールする方法

# はじめに
Windows Server 2012 R2 Essentials環境へSystem Center Endpoint Protection (SCEP) をインストールしようとすると（scepinstall.exeを実行すると）、以下のようなメッセージが表示され、インストールすることができません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64876/5095e554-c222-4db1-56a3-ae0da1ec2cd0.png)

# 対応方法
scepinstall.exe 実行時に ```/disableoslimit``` オプションを付加することで、インストールが行えるようになります。

```
scepinstall.exe /disableoslimit
```

上記コマンドを実行すると、次の画面が表示され、インストールを継続することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64876/45ebe507-71cf-4305-8cba-2b7a85505297.png)


# System Center Endpoint Protectionの入手先

System Center Endpoint Protection は以下のURLより評価版が入手可能です。 

https://www.microsoft.com/ja-jp/evalcenter/evaluate-system-center-configuration-manager-and-endpoint-protection-technical-preview

なお、上記リンクよりダウンロード可能なファイルは、あくまでも評価版として提供されているものとなります。その点予め理解のうえ、ご利用（お試し）ください。
OneDrive上に保存したエクセルファイルの「数値」形式が勝手に「標準」に変る

皆さんの中であまりエクセルファイルをPowerAppsのソースデータに使っている人は多くないかも知れませんが、今回ハマったので備忘録として書いときます。

エクセル上である列を「数値」形式でOneDrive上に保存したにも関わらず、その列をアプリからSubmitFormやPatch、Collect関数で値を更新した時に「文字列ではだめ」みたいなエラーが出てハマりました。PowerApps内のコードを全て確認しても問題が見つからず、OneDrive上のエクセルファイルを見たら対象の列の形式が勝手に「標準」に変ってました。それをまた「数値」に変更してもしばらくしたらアプリ上でまた同じエラーが出始めて、エクセルファイルを開けて確認するとまた「標準」に変ってるのです。

そこで下記のページで解決の糸口がみつかりました。

[PowerApps公式フォーラム（英語）](https://powerusers.microsoft.com/t5/General-Discussion/Submitting-forms-Expected-String-Error/td-p/48587)


そのページでは一旦そのエクセルファイルをローカルの自分のＨＤに保存して、数値形式にして改めてOneDriveに上書き保存すると良いと書いてありますが、それだけでは不十分でした。

もし、エクセルの「ホーム」メニューのドロップダウンで「数値」形式を選択するだけでは問題が解決せず、「セルの書式設定」ダイアログで「数値」形式に変え、もう少し細かい設定をしてから保存すると問題が解決しました。

<blockquote class="twitter-tweet" data-lang="en"><p lang="ja" dir="ltr">マイクロソフトのPowerAppsの動画を集めたプレイリストを作りました。<a href="https://t.co/JELJZcOUHb">https://t.co/JELJZcOUHb</a></p>&mdash; Mike Negami (@Econoshift) <a href="https://twitter.com/Econoshift/status/1126992363983900672?ref_src=twsrc%5Etfw">May 10, 2019</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
JMeterでSpring SecurityのCSRF対策を使用したAPIを呼び出す際の設定

## やりたいこと
長いタイトルの通りです。
Vue.jsのアプリケーションから呼び出すAPIをSpring Bootで作ってまして、
そのAPIの負荷試験を行うことになったと。
JMeterを使用してシナリオを作成するのですが、Spring Securityの`CookieCsrfTokenRepository`を使用したCSRF対策を使っているので

* CSRFトークンとして`XSRF-TOKEN` Cookieの値を取得して
* `POST`を使用したAPIをコールする際の`X-XSRF-TOKEN`ヘッダとして設定する

ということをシナリオ中で行う必要が生じたわけです。

## 試験対象APIのざっくり仕様
イメージだけ、こんな感じです。

|url|HTTPメソッド|概要|
|-----------------|---------|---|
|/login|POST|ID/Passwordを送信してログインする<br>ログイン成功時に`XSRF-TOKEN`Cookieが付与される<br>CSRFチェック対象外|
|/orders|POST|受注登録を行う<br>CSRFチェック対象|

## 環境
### アプリケーション
* Spring Boot 2.1.4

### ツール
* Apache JMeter 5.1.1
  * 設定はGUI起動で実施します。

## JMeterの設定
### XSRF-TOKENの値を取得する
`/login`のレスポンスに`XSRF-TOKEN`のCookieが含まれることになるので、それを抽出することになります。
一応、DevToolsで`/login`のレスポンスを見てみると、こんな感じです。

![XSRF-TOKEN.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51995/4d8b3db4-47c3-ff72-cd4b-d78386a260f6.jpeg)

#### 設定
`/login`の呼び出しは`HTTP Request`サンプラーで定義します。(詳細は割愛）
このサンプラーの実行後に、`正規表現抽出`を使用して、CSRFトークンを取得します。

##### 手順
1. `/login`の`HTTP Request`サンプラーを選択して右クリック
2. `ADD` → `Post Processors` → `Regular Expression Extractor` を選択
3. 以下の通り設定する(NameとCommentsは適当です）
![csrfトークン取得.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51995/cd6ce5da-1561-c636-aab5-9c0669e97289.jpeg)

* Response Headersから抽出する
* ヘッダからの抽出になるので、先程DevToolsで確認した形式、要は「Set-Cookie:」を含んだ形式で正規表現を書く必要がある

というあたりがポイントでしょうか。
これ以降のシナリオでは、`${xsrf_token}`を指定することで、抽出した値を変数から解決することができるようになります。

### X-XSRF-TOKENヘッダを設定する
`/orders`はCSRFチェック対象となるため、コール時に`X-XSRF-TOKEN`ヘッダを設定する必要があります。

#### 設定
`/orders`の呼び出しは`HTTP Request`サンプラーで定義します。(詳細は割愛）
このサンプラーの実行時に、`HTTP Header Manager`を使用して、`X-XSRF-TOKEN`ヘッダを設定します。

##### 手順
1. `/orders`の`HTTP Request`サンプラーを選択して右クリック
2. `ADD` → `Config Element` → `HTTP Header Manager` を選択
3. 以下の通り設定する(NameとCommentsは適当、content-typeは今回のAPI固有の仕様で必要なため設定しています）

![X-XSRF-TOKEN付与.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51995/2d112776-f26a-ac44-6910-3bed4a3ac982.jpeg)

先程取得した`${xsrf_token}`を、`X-XSRF-TOKEN`ヘッダとして設定しています。

## まとめ
以上の設定で、CSRF対策を通過させることができます。
JMeterに不慣れだと、こういうちょっとした応用ってすぐに思いつかなくて
意外と悩むかなと思った(不慣れな私の実体験です）ので書き留めておきました。

## 参考ページ
以下を参考にさせていただきました。
ありがとうございました。

https://www.blazemeter.com/blog/how-load-test-csrf-protected-web-sites
VirtualBoxを使ってUbuntu Live USBを作った話

以前使っていたPCにUbuntuを入れていたのですが、HDDで起動がもっさりしているのと、ラップトップを壊して数年経って、そろそろ中古でもいいからほしいなと思って、せっかくなのでUbuntuも使えるようにしておこうと思ったのがきっかけです。
Live USBなので、設定の保存もできますし。

ほんと簡単な手順ですが。

1. UbuntuのISOをダウンロード。（最新版をダウンロードしました）
2. VirtualBoxで仮想マシンを作成。
3. 光学ドライブにダウンロードしたISOを指定。
4. USBドライブをWindowsに認識させ、とりあえずフォーマット。VMのUSBフィルターに追加。
5. 仮想マシンを起動。「Try Ubuntu」でOSを起動。
6. 「Install Ubuntu」でUSBにUbuntuインストール。
7. 別PCのBIOS設定で、Boot PriorityをUSBに変更。
8. インストールしたUSBドライブをPCに挿して起動。

手順的には以下のサイトの応用です。

- [【Ubuntu】USBメモリでコンピュータを持ち歩く？！](https://www.milkmemo.com/entry/usbmemory_os_install_ubuntu)

サイトによってはUSBドライブを2つ用意するというようなことを書かれていますが、一つだけでも大丈夫でした。
USBドライブは以下のようなものを用意すればOKかと。

- [SanDisk Cruzer Fit USBフラッシュメモリー 64GB (5年間保証)【正規代理店品】 SDCZ33-064G-J57](https://www.amazon.co.jp/dp/B00IUF56T2)

VirtualBoxにUSB 2.0/3.0用のドライバーを入れてなかったので、USB 1.0でインストールしました。
なので時間がかかったのですが、入れてれば早くなったかも。

- [VirtualBox - 拡張パック（Extension Pack）のダウンロード・インストール](https://pc-karuma.net/virtualbox-extension-pack-install/)

所感ですが、元々のUbuntu PCがHDDで動きがもっさりしていたのですが、USB 2.0しか搭載していないにもかかわらず結構快適に動きました。

使えると思いますが、モニタとかキーボードとかマウスとか解決する問題も多そうなのと、他のPCで試してない、キーボードの使用感をWindowsと合わせたいなど、自分的に解決しないといけない課題は多いかなと。

あと、VirtualBoxでUSBブートとか試してみましたが、うまくいきませんでした。

以上。
自分のツイートの文章のみを取得する

#背景
機械学習したいなーって思って自分のツイート履歴を取得してみた
ハッシュタグやメンションは除外するようにしたかったのでregexを使いました
本当はツイッターの公式が自分のツイート履歴はデータをくれるのでわざわざAPI叩く必要はないです
https://qiita.com/nya3_neko2/items/50d8ba2228f22fac9d3d
##除外対象　
ツイート自体
・RT
部分的に除外
・メンション　idを除外
・ハッシュタグ　ハッシュタグのみを除外


#コード

```python
import json, re, time
from requests_oauthlib import OAuth1Session

CONSUMER_KEY = ''
CONSUMER_SECRET = ''
ACCESS_TOKEN = ''
ACCESS_TOKEN_SECRET = ''

CK = config.CONSUMER_KEY
CS = config.CONSUMER_SECRET
AT = config.ACCESS_TOKEN
ATS = config.ACCESS_TOKEN_SECRET
twitter = OAuth1Session(CK, CS, AT, ATS)

url = "https://api.twitter.com/1.1/statuses/user_timeline.json"

params = {'count': 200}
req = twitter.get(url, params=params)

txt_file = open('learn_text.txt','a')

if req.status_code == 200:
    timeline = json.loads(req.text)
    for tweet in timeline:
        tw_txt = tweet['text']
        regex_at = re.compile('@\S+ ?')
        regex_http = re.compile('https://\S+')
        regex_tag = re.compile('#\S+ ?')
        regex_end = re.compile('\n$')
        if len(re.findall('^RT', tw_txt)) == 0:
            tw_txt=regex_at.sub('',tw_txt)
            tw_txt = regex_http.sub('', tw_txt)
            tw_txt = regex_tag.sub('', tw_txt)
            if regex_end.search(tw_txt) == None:
                tw_txt = tw_txt + '\n'
            txt_file.write(tw_txt)

else:
    print("ERROR: %d" % req.status_code)

txt_file.close()

txt_file = open('learn_text.txt')
content=txt_file.read()
txt_file.close()
print(content)

```

#参考
https://cre8cre8.com/python/twitter-api.htm
setcapコマンド

# 使い方

```
setcap {capabilities|-r} filename
```

-rオプションは、file capability setを削除する。

> The special capability string, '-r', is used to remove a capability set from a file. Note, setting an empty capability set is not the same as removing it.  An empty set can be used to guarantee a file is not executed with privilege in spite of the fact that the prevailing ambient+inheritable sets would otherwise bestow capabilities on executed binaries.

setcapコマンドでのcapabilitiesの指定方法は、以下の構文に従う。詳しくは、cap_from_text(3)参照。

|name|syntax|
|:--|:--|
|\$action|=+-{p&#124;i&#124;e}...&#124;=|
|\$clause|\<cap name\>[,\<cap name\>]...[\$action]...|
|\$caps|\$clause[ $clause]...|

# 例

```shell
touch hoge
setcap "cap_kill+p" hoge
setcap "cap_net_raw,cap_kill+i cap_net_raw-i+p" hoge
getcap hoge
# hoge = cap_kill+i cap_net_raw+p
```

`hoge = cap_kill+ip cap_net_raw+p`でないことに注意。+-は同一のcapabilities指定内でのみ効力を持つ。
Vagrant for macOS

## Vagrantとは
Vagrantとは、VirtualBoxなどの仮想環境にOSのインストールなどの環境構築を数コマンドで実現してくれる便利なもの。という認識です。
通常、環境構築（OSのインストールなどなど）は、結構手間がかかります。Linuxだと便利なコマンドはあとでyumとかで入れないといけないですし。仕事先の環境では、インストールされているコマンドも、まっさらに構築した環境では「そんなコマンドありません。」地獄でイライラします。

macOSでのVagrantでの環境構築した際の手順を残しておきます。

## 環境

* macOS 10.14
* VirtualBox 6.0.6
* Vagrant 2.2.4

### VirtualBox Vagrant導入

homebrew-caskで導入します。[この記事](https://qiita.com/tsunemiso/items/9d8cd616ae72572c77d9)を参照。

```bash:terminal
$ brew cask install virtualbox
$ brew cask install vagrant
```

### 作業用ディレクトリを作成

```bash:terminal
$ mkdir vagrant
$ cd vagrant
```

### box作成
[ここ](https://app.vagrantup.com/boxes/search)で、VMの元になるboxファイルを作成(インストール)します。

インストールは、作業用ディレクトリに移動したのち、対象のboxのNewタブのコマンドを実行します。
例では、[bento/centos](https://app.vagrantup.com/bento/boxes/centos-7.6/versions/201812.27.0)のboxを紹介します。

![スクリーンショット 2019-05-06 1.48.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75277/7de0cff2-5410-60e6-4e8c-00573f4c8ac9.png)

### boxの確認

```bash:terminal
$ vagrant box list
bento/centos-7.6 (virtualbox, 201812.27.0)
```

上記例通りにすると、vagrant box listでboxの確認ができます。

### Vagrantfileの確認

作業用ディレクトリには、Vagrantfileも生成されているので確認します。

### 仮想マシンの起動

作業用ディレクトリでvagrant upで仮想マシンが***使える状態で***起動します。

```bash:terminal
$ vagrant up
```

### 仮想マシンの起動の確認

```bash:terminal
$ vagrant status
running(virtualbox)
```

となっていれば、正常に起動しています。

### SSH接続

Linuxでは、SSHで作業するのが一般的だと思いますので、SSHの接続方法

```bash:terminal
$ vagrant ssh
```

### 仮想マシンの停止

停止もワンコマンド

```bash:terminal
$ vagrant halt
```

### 仮想マシンの削除

いらなくなった仮想マシンを削除します。

```bash:terminal
$ vagrant destory
```

### boxの削除

もはや、元となるboxも使わなくなった場合

```bash:terminal
$ vagrant box remove [box名]
```

で削除することができます。

## さいごに

Vagrantは一瞬で環境構築できるので便利ですね!
vueでWebComponentを作ったとき、Vue.use({theme})が適用されないからまだ使えない？

Vueファイルに対して`vue-cli-service build --target wc ./src/App.vue`を実行し、作成されたhtmlを開くとコンポーネントの再現が出来ていない箇所がある。

ファイルの概要は以下の通り。

```json:package.jsonの一部
  "dependencies": {
    "vue": "^2.6.10",
    "vue-class-component": "^7.0.2",
    "vue-cool-select": "^2.10.2",
    "vue-property-decorator": "^8.1.0",
    "vuejs-datepicker": "^1.5.4"
  },
  "devDependencies": {
    "@vue/cli-plugin-typescript": "^3.7.0",
    "@vue/cli-service": "^3.7.0",
    "node-sass": "^4.12.0",
    "sass-loader": "^7.1.0",
    "typescript": "^3.4.5",
    "vue-template-compiler": "^2.6.10"
  }
```

```vue
<template>
  <div style>
    <cool-select v-bind:items="privateFieldArray" disable-search>
      <template #item="{item}">
        <div style="display:flex;align-items: center;flex: 1 1 0;">
          <b>{{ item }}</b>
        </div>
      </template>
      <template #selection="{item}">
        <div style="display:flex;align-items: center;flex: 1 1 0;">
          <b>{{ item }}</b>
        </div>
      </template>
    </cool-select>
  </div>
</template>
<script lang="ts">
import VueSelect, { CoolSelect } from 'vue-cool-select';
import { Prop, Vue, Component } from "vue-property-decorator";
Vue.use(VueSelect, {
  theme: 'material-design' // or 'material-design'
});
@Component({
  components: { CoolSelect }
})
export default class TestVue extends Vue {
  async mounted(): Promise<void> {
    console.log(this.privateFieldClass.classFunction())
  }
}
</script>

```

vue-cool-select というモジュールはhtmlのselect要素の様なリストボックスのUI。
このモジュールの為、vueファイルで

```js

Vue.use(VueSelect, {
  theme: 'material-design' // or 'material-design'
});
```

という指定をしているが、これがweb componentの外に設置されてしまう。
コンポーネントの外に指定されたcssは、当然コンポーネントの中に適用されない。

web component大好き人間だからこっちに統一しようと思ったけど、これはつらい。何か方法があれば知りたい。

説明用の図を書こうと思ったけど、いいツールが見つからなかったのでパス。
clasp login で TypeError が出る

Google Apps Script(GAS)をローカルで開発をしたくて、
[google/clasp](https://github.com/google/clasp)をインストールしました。

最初のステップとして、ログイン(clasp login)をするのですが、
コマンドを実行すると[Error retrieving access token: TypeError: URL is not a constructor]が出て開発環境すら作れない。

```
% clasp login
Logging in globally...
🔑 Authorize clasp by visiting this url:
https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&・・・・


Error retrieving access token: TypeError: URL is not a constructor
```

当然、~/.clasprc.json は作成されません。
  
原因は node のバージョンが古かったからです。
因みに私のバージョンは v6.4.0 でした。

```
% node -v
v6.4.0
```

node のバージョンを上げました。  
上げる方法は色々とあると思うのですが、私は nodebrew を使っています。
いや、使っているのを忘れていて

```
brew install node
```

なんのでやっても、 node のバージョンが上がらなくてハマりました。
更に nodebrew が壊れていて無限にインストールできなくてまたハマりました。

以下を参考にして nodebrew を入れ直しました。
[nodebrewでinstallが失敗するようになった](https://qiita.com/shimitei/items/7975bc1b60cfb477817e)

今回は最新の安定バージョンの node を入れたかったので
以下の nodebrew コマンドでインストールしました。

```
nodebrew install-binary stable
```
その後に

```
nodebrew use stable
use v12.1.0
```
2019年05月06日現在です。

```
clasp login
Logging in globally...
(node:952) [DEP0066] DeprecationWarning: OutgoingMessage.prototype._headers is deprecated
🔑 Authorize clasp by visiting this url:
https://accounts.google.com/o/oauth2/v2/auth?access_type=offline・・・・

Authorization successful.

Default credentials saved to: ~/.clasprc.json 
```

[Error retrieving access token: TypeError: URL is not a constructor]が
でなくなりました。
ここ何年もnodeのバージョンを上げてなかったので、こんなに上がっているのって
びっくりしました。
男性用３Dアバター（３Dモデル）を探してみた＜随時更新＞

boothで３Dアバター（男性向け）を探すのに苦労したので、まとめておこうと思います。

「男性アバター」タグを皆さんつけてくれてたらありがたいんですが、boothがそこまで整備されていないみたいで、「３Dモデル」の検索結果を頑張って３，０００件ほど目を通してみました

漏れや勘違いあったらすみません！

＜更新：2019/5/6＞


- [VRChatアバター用3Dモデル「タチバナ」](https://booth.pm/ja/items/1264356)
- [Oldman Cornelius](https://booth.pm/ja/items/1001515)
- [【ｵﾘｼﾞﾅﾙ3Dﾓﾃﾞﾙ】成-naru-](https://booth.pm/ja/items/1339247)
- [【VRChatアバター】yu](https://booth.pm/ja/items/1291494)
- [シンプル男性モデル（無料版）](https://booth.pm/ja/items/953338)
- [オリジナル和風男性アバター「さんかく」](https://booth.pm/ja/items/1259033)
- [【スキニング済み】ミリタリー系男素体](https://booth.pm/ja/items/1034662)
- [Humanoid対応3Dモデル　悪魔のルル　ver1.0](https://booth.pm/ja/items/1264571)
- [【3Dモデル】坪倉輝明](https://booth.pm/ja/items/943414)
- [VRchat用AVATAR「AEF-00 CRADLE」](https://booth.pm/ja/items/1264211)
- [オリジナルアバター「たにぐち」](https://booth.pm/ja/items/1288901)
- [オリジナル3Dモデル「かなで」くん](https://booth.pm/ja/items/1230264)
- [オリジナル男性アバター「ヨウ」](https://booth.pm/ja/items/1335313)
- [【３Ｄモデル２体セット】灯夜＆灯花【1.0→1.1UPDATE】](https://booth.pm/ja/items/1264774)
- [竹流式オリジナル3Dモデル「ジョンスミス」](https://booth.pm/ja/items/926517)
- [【オリジナル3Dモデル】「冬樹」【VRC対応】](https://booth.pm/ja/items/1101592)
- [VRC/MMD向け3Dモデル「漆瀬　零」](https://booth.pm/ja/items/1089153)
- [オリジナル3Dモデル『ウーフラン(Woflang)』](https://booth.pm/ja/items/1284586)
- [O-Zi-san（VRChat想定オリジナル3Dモデル）](https://booth.pm/ja/items/1272506)
- [VRChat対応3Dモデル「鬼人霧雨」Ver1.2](https://booth.pm/ja/items/1018062)
- [エリク](https://booth.pm/ja/items/1128294)
- [オリジナル3Dモデル「Constantan / コンスタンタン」](https://booth.pm/ja/items/1281896)
ElasticSearchに複数データを投入

複数データを投入する場合はBulkAPIを使う

[BulkAPI](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html)

## APIのEndpoint

```
POST /_bulk
POST /{index}/_bulk
POST /{index}/{type}/_bulk
```

## API実行

### コマンド
```console
$ curl -s -H "Content-Type: application/x-ndjson" -XPOST localhost:9200/_bulk --data-binary "@insert_data.js"
```
※`insert_data.js`は投入データを定義したファイル

### 注意点
・`-H "Content-Type: application/x-ndjson"`でheaderを指定する
・`-d`ではなく、`--data-binary`を使う
・`insert_data.js`はndjson形式で記述する

## insert_data.jsのサンプル
リファレンスがちょっと分かりづらかったのでうまく行ったサンプルを掲載します。


```json
{"create":{ "_index" : "test_es" , "_id" : "1"}}
{"text":"あああああああ","text_id":291}
{"create":{ "_index" : "test_es" , "_id" : "2"}}
{"text":"えええええええ","text_id":338}
{"create":{ "_index" : "test_es" , "_id" : "3"}}
{"text":"たかたかたかか","text_id":941}
```

・１行目：実行するaction(`create`)とmetadata(`_index`, `_id`)
・２行目：投入するデータ(`text`, `tesxt_id`)
※１行目と2行目のフォーマットで投入するデータ分記述する
※create以外にもindex、delete、updateがあり、それぞれフォーマットが異なる
※createとindexのみ２行目が必要
Dockerとは？Dockerと仮想マシンの違い

今回はDockerとは何か、Dockerと仮想マシンの違いについてを簡単に紹介します。
プログラミング初心者であるため、内容に誤りがあるかもしれません。
もし、誤りがあれば修正するのでどんどん指摘してください。

## Docerって何？
開発者やシステム管理者 がコンテナを使用してアプリケーションを開発、デプロイ(いつでも使える状態にする)、および実行するためのプラットフォームのことです。
ここで、コンテナとは、Dockerイメージ(コンテナを作成するためのファイルシステムや設定をまとめたもの)を起動し、その内部でアプリケーションが稼動している状態のことです。
Dockerの特徴は、アプリケーションとその実行環境、展開／操作方法（スクリプト）などをまとめて1つのパッケージにし、保存／配布しているDockerイメージのダウンロードや起動が非常に軽量なことです。

## Dockerと仮想マシンの違い
仮想マシンは、ホストOS上でハイパーバイザと呼ばれるソフトウェアを利用し仮想マシンを作成後、ゲストOSを動かし、その上でミドルウェアなどを動かします。
一方、Dockerでは、各コンテナはホストOSのカーネルは共有しつつも、各コンテナ内のアプリケーションは分離された場所で実行されます。
このように、プロセスやユーザなどを隔離することで、あたかも別のマシンが動いているかのように動かすことができ、軽量で高速に起動、停止などが可能です。

![docker_vs_hv.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/380428/9fd814bf-f0e2-26c7-4204-3e40b7a2cbcc.png)
CloudRunを試してるけど、GCPはまだまだAppEngineが最強の話

# 概要

2019/5/13追記
CloudRunからSQLデータベースへ接続できるようになりました。

Serverlessでシステム作るときにだいたい必要になってくる秘匿情報管理、VPCリソースへのアクセス、非同期処理をCloudRunで利用可能か見てみました。
また、CloudRunだけでなくAppEngine、CloudFunctionsでもどうか調べてみたら、結局まだまだAppEngineが最強だったってお話です。

# 秘匿情報の管理

berglasを使えば、AppEngine、CloudFuntions、CloudRunどれでも管理が可能です。

https://qiita.com/yamaneko-yosistamp/items/9e5291404daccd0656ad

# VPC内へのアクセス

GCPではマネージドサービスからVPC内へのルーティングとしてServerless VPC Accessというサービスがあります。

## アーキテクチャ

Serverless VPC Access Connectorを作成し、AppEngine、CloudFunctionsからはConnectorにアクセスします。VPCへはConnectorからアクセスします。

<img width="685" alt="スクリーンショット 2019-05-03 19.02.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306826/5366b313-e558-507e-7215-e7ce49e888f1.png">

ただ、この図を見ても分かる通り、現状AppEngineとCloudFunctionsしか対応していません。
SQLデータベースやMemoryStore(Redis)へのアクセスが必要なケースではまだCloudRunでの運用は難しそうです。

また、このServlerless VPC Access自体us-central1にしかないので、早く他のリージョンへ展開してほしいところです。（AppEngineを東京リージョンに作っても一度us-central1経由になると思われる）

# 非同期処理

マイクロサービス間を非同期につなぐキューイングのサービスとしてCloudTasksがあります。（AWSでいうところのSQS）

# ドキュメント

https://cloud.google.com/tasks/

## キューの作成

```
gcloud beta tasks queues create <キュー名>
```

キューが作成されると、ブラウザから確認できるようになる。

<img width="1053" alt="スクリーンショット 2019-05-03 19.29.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306826/5909d11a-37e1-efd4-fdf9-471998900b78.png">

#### 思いっきり、AppEngineキューって書いてます。。。

## キューへのデータ登録

### APIのドキュメント

https://googleapis.github.io/google-cloud-python/latest/tasks/gapic/v2/api.html


### 必要ライブラリ（python）

```
google-cloud-tasks==1.0.0
```

### キューへのデータ登録はCloudRunからでもできます。

```
    data = 'hoge'
    client = tasks_v2.CloudTasksClient()
    parent = client.queue_path('<プロジェクト名>', '<リージョン>', '<キュー名>')
    task = {
            'app_engine_http_request': {  # Specify the type of request.
                'http_method': 'POST',
                'relative_uri': '/example_task_handler'
            }
    }
    task['app_engine_http_request']['body'] = data.encode()
    response = client.create_task(parent, task)
```

### タスクのフォーマット

https://googleapis.github.io/google-cloud-python/latest/tasks/gapic/v2/types.html

ただ、タスクのフォーマットを見ても分かる通り、AppEngine向けの仕様になっており、キューに登録されたデータの自動ディスパッチはAppEngineになります。
（キューへの登録や手動で取り出す分にはCloudRunからでも可能ですが）

## まとめ

Serverlessでアーキテクチャを考えるときにだいたい出てくる秘匿情報管理、VPCアクセス、非同期処理と見てきましたが、全てに対応できているのはAppEngineのみでした。
CloudRunは期待しているんですが、まだ機能が少ないのと、us-central1にしかないので、早く機能追加＆東京リージョンへきてほしいですね。
git revertでpush済みのcommitの内容を取り消す

git revertで該当のMergeCommitのみを取り消す

```
$ git revert -m 1 [取り消したい該当commit id]
```
-> これで該当のコミットのみを取り消すcommitが作られる(戻されるわけではなく、ソース上で消す変更が行われる)

後はpushしてマージするだけ。