OmniAICreator/Qiita-1.07M huggingface dataset:
自動リロードするOpenAPIモックサーバ




- `openapi.json`が更新されたらリロード
- zero configuration
- 軽い（docker imageのサイズが18MBくらい）


## 必要ファイル

```sh
.
├── docker-compose.yml
└── openapi.json
```

## `openapi.json`

- OpenAPIのv3のスペックにのみ対応
    - https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md
    - Swaggerのスペックには未対応

```sh
# gistから適当にサンプルを拾ってくる
 wget https://gist.githubusercontent.com/adfinlay/e797691536644f72d8b6e4668074e8ac/raw/27e43ad20c7ff7a1c728d8017d644b591cfbe3ea/swagger.json -O openapi.json
```


## `docker-compose.yml`

```yml
version: '3'

services:
  apiMock:
    image: danielgtaylor/apisprout:latest
    container_name: "apiMock"
    ports:
      - "8000:8000"
    volumes:
      - ./openapi.json:/openapi.json
    entrypoint: /usr/local/bin/apisprout /openapi.json --watch
```

- https://git.io/fjEJo

## 起動

```sh
# 起動
docker-compose up -d
# モックサーバログ
docker-compose logs -f apiMock
```

### `🌙 Reloading /openapi.json...`

`openapi.json` が更新されると更新される

```sh
Attaching to apiMock
apiMock    | 🌱 Sprouting バックエンドapi on port 8000
apiMock    | 🌙 Reloading /openapi.json
apiMock    | 2019/05/18 05:56:15 GET /v1/hello (Accept text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3) (hello) => 200 (application/json)
apiMock    | 2019/05/18 05:56:16 ERROR: GET /favicon.ico => Path was not found
apiMock    | 🌙 Reloading /openapi.json
apiMock    | 2019/05/18 06:03:58 ERROR: GET / => Path was not found
apiMock    | 2019/05/18 06:04:04 GET /pets/11 (Accept text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3) (showPetById) => 200 (application/json)
```

## apisproutの起動設定

```sh

Usage:
  apisprout [flags] FILE

Examples:
  # Basic usage
  apisprout openapi.yaml

  # Validate server name and use base path
  apisprout --validate-server openapi.yaml

  # Fetch API via HTTP with custom auth header
  apisprout -H 'Authorization: abc123' http://example.com/openapi.yaml

Flags:
      --add-server string   Add a new valid server URL, use with --validate-server
      --disable-cors        Disable CORS headers
  -H, --header string       Add a custom header when fetching API
  -h, --help                help for apisprout
  -p, --port int            HTTP port (default 8000)
      --validate-request    Check request data structure
  -s, --validate-server     Check scheme/hostname/basepath against configured servers
      --version             version for apisprout
  -w, --watch               Reload when input file changes
```

## openapi.jsonを削除すると、変更監視は停止する

- 削除後に同名のファイルを作成しても変更監視は復活しない
    - ディレクトリの監視ができずファイルレベルでしか監視できないため
    - タスクランナーの設定でよくある `rm -fr ...` してから同名ファイル生成という方法は失敗する
- 監視ファイルで `DELETE_SELF` イベントが発生したら、監視が終了
- 監視が切れた場合は再起動が必要
    -  `docker-compose restart apiMock`
Jestでデフォルト値設定済みのaxiosインスタンスに対するMockテスト

# TL;DR

axiosそのものではなく、`adapter`でMockすると良さそう

# 背景
axiosを使ったコードのテストをJestで書くときにMock化したい。
よくあるサンプルにはaxiosモジュールそのものをMockにしている例がある。
ただし、下記のように`axios.create()`や`axios.defaults`を使って共通設定している場合、

```javascript
import axios from 'axios'
const api = axios.create({
  ...
})
export const getFoo = req => api.post('/foo', req)
```

axiosモジュールそのものをMockにすると、create関数の戻り値でさらにMockを返すなどの実装がテストコード側で必要になりかなり面倒。
さらに、interceptorsやtransformersなんかを設定している場合には、最終的にサーバーにどんなリクエストが飛ぶかをテストしたい場合も出てくる。

# 解決策

[axiosを乗りこなす機能についての知見集 - Qiita](https://qiita.com/terrierscript/items/ccb56b6fc05aa7821c42) を見て知ったのだけど、`adapter`プロパティを使うとRequest, ResponseがMockできて良い感じだった。

使い方や詳細については下記も参照。
[axios/lib/adapters at master · axios/axios](https://github.com/axios/axios/tree/master/lib/adapters)

# 実装サンプル

GitHubにもあります。
[clomie/sample\-axios\-jest\-mock\-test](https://github.com/clomie/sample-axios-jest-mock-test)

プロダクトコード側はMockをインポートして`adapter`に渡す実装にしておく。

```typescript:index.ts
import axios from 'axios'
import { stringify } from 'querystring'
import mockAdapter from './mock'

const api = axios.create({
  baseURL: 'https://api.example.com/v2/',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  adapter: mockAdapter
})

export const createFoo = async (req: any) => {
  const { data } = await api.post('/foo', stringify(req))
  return data
}
```

プロダクトコード側のMockの中身は`undefined`にしておけば良い。

```typescript:mock/index.ts
import { AxiosAdapter } from 'axios'
export = (undefined as unknown) as AxiosAdapter 
```

テストコード側でJestのMockに差し替えてテストを書いていく。

```typescript:index.test.ts
import { AxiosAdapter } from 'axios'

jest.mock('./mock', () => jest.fn())

import mock from './mock'
const axiosMockAdapter = (mock as unknown) as jest.Mock<
  ReturnType<AxiosAdapter>,
  Parameters<AxiosAdapter>
>

import { createFoo } from './index'

describe('createFoo test', () => {
  beforeEach(() => {
    axiosMockAdapter.mockClear()
  })

  it('send form request and receive response', async () => {
    const request = {
      name: 'hogefuga'
    }
    const response = {
      status: 200,
      statusText: 'OK',
      headers: {},
      config: {},
      data: {
        id: 1,
        name: 'hogefuga'
      }
    }

    axiosMockAdapter.mockResolvedValueOnce(response)

    const result = await createFoo(request)
    const callArgs = axiosMockAdapter.mock.calls[0]

    expect(callArgs[0].url).toBe('https://api.example.com/v2/foo')
    expect(callArgs[0].headers).toHaveProperty(
      'Content-Type',
      'application/x-www-form-urlencoded'
    )
    expect(callArgs[0].data).toBe('name=hogefuga')

    expect(result).toStrictEqual({ id: 1, name: 'hogefuga' })
  })
})
```
javaのバージョン確認方法

##cmdでjavaのバージョンを表示させる方法

javaというコマンドを入力すると1.8.0_201というバージョンのjavaを使用している事がわかる。

```bash:
> java -version
java version "1.8.0_201"
Java(TM) SE Runtime Environment (build 1.8.0_201-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.201-b09, mixed mode)
```

javaコマンドの実体ファイルのパスを調べるためには以下のコマンドを実行する。

```bash:
> where java
C:\Program Files (x86)\Common Files\Oracle\Java\javapath\java.exe
C:\ProgramData\Oracle\Java\javapath\java.exe
C:\Program Files\Java\jre1.8.0_201\bin\java.exe
```

環境変数JAVA_HOMEに設定されているパスを表示する。

```bash:
> echo %JAVA_HOME%
C:\Program Files\Java\jre1.8.0_201
```
SIerに入って８年ぐらい経ったのでいろいろ棚卸しをしてみる。【vol.006 SubversionとGit】

## 出会い

2011年に入社以来、2017年に今の案件をやるまでSubversion一筋、現在、Git（GitHub）を使用している。
Subversionについては、最初から当たり前にあったものなので出会いの感想も特にないが、
Gitについては、リモートリポジトリとローカルリポジトリの仕組みが自分にとっては新しく印象的だったように思う。

## Subversionとは
>Subversion（Apache Subversion）は、さまざまなソフトウェアの開発現場において広く使われているソースコード管理システムです。
>...中略...
>Subversionではソースコードやそこに加えられた変更点などの履歴はすべて中央リポジトリに記録され、各開発者はネットワーク経由で中央リポジトリにアクセスすることでソースコードを取り出したり、変更点を記録するという中央集権型のバージョン管理機能を備えています。
>[Subversion（svn）によるソフトウェア開発を始めよう](https://ja.osdn.net/svn/)

中央リポジトリなので開発者にとっては、ソースコードは以下の３つの状態が存在する。

- 自分のPCにあってまだコミットされておらず、バージョン管理もされていないソースコード。
- バージョン管理はされているが、自分のPCにあってまだ変更内容がコミットされていないソースコード。 
- コミット済みでリポジトリ上にもあるバージョン管理されているソースコード。

コミットされていないソースコードは、万が一HDDやSSDが壊れたりすれば、PC内にあるその他のデータと一緒に消える。
なので、こまめにコミットすることが多かったし、PJとしても推奨していたように思う。

ただ、たまにビルドの通らない状態でコミットするメンバーが（自分も含め）いて、それを取り込むとPJ全体がザワザワすることになる。
気軽にコミットしていると弊害もあるが、とはいえ、コミットしていないと他のメンバーと盛大にコンフリクトする範囲や可能性も広がっていく。

ここらへん技術的にどうするかというよりは、開発する機能やクラスの単位を予め、計画してコントロールしていた。


## Gitとは
>Git は、元々 Linus Torvalds によって 2005 年に作られた、無料でオープンソースのバージョン管理システムです。他の SVN や CVSといった中央バージョン管理システムと違って、Git は分散型で、すべての開発者がローカル環境で彼らのコードのリポジトリの完全な履歴を持っています。
>[Git を学ぶ - Git のチュートリアル、ワークフローおよびコマンド | アトラシアン](https://ja.atlassian.com/git)

分散リポジトリなので開発者にとっては、ソースコードは以下の４つの状態が存在する。

- 自分のPCにあってまだコミットされておらず、バージョン管理もされていないソースコード。
- バージョン管理はされているが、自分のPCにあってまだ変更内容がコミットされていないソースコード。
- コミット済みでローカルリポジトリ上にだけあるバージョン管理されているソースコード。
- コミット済みでローカルリポジトリだけでなく、リモートリポジトリにもあるバージョン管理されているソースコード。

結局、万が一HDDやSSDが壊れたりすれば、PC内にあるその他のデータとローカルリポジトリ共々、一緒に消えるのは変わらない。
ただ、Subversionに比べれば、ローカルリポジトリの存在があるので、気軽にコミットしやすい。

どんなコードを書くかまだ定まってない試行錯誤の段階では、書いて、コミットして、リファクタして、コミットしての繰り返しに心理的な抵抗がSubversionと比較してかなり低い。

うっかりビルドの通らない状態でコミットしても、他のメンバーにご迷惑をかける前に気づける可能性が高い。

リモートリポジトリにコミットしていないと他のメンバーと盛大にコンフリクトする範囲や可能性も広がっていくのは、
Subversionと同じでここらへん技術的にどうするかというよりは、やっぱり開発する機能やクラスの単位を予め、計画してコントロールすることになる。

## 振り返ってみて

Gitの方がSubversionより後発だから良いし、メリットも感じられるはずだ。
そう思っているかというと個人的にはそうではない。

中央リポジトリと分散リポジトリという考え方の違いは、開発のスタイルによってよりメリットを感じられる場合もあるし、
逆に「SubversionからGitに移行したけど、あんまりメリットを感じられない。。」というケースもある。

実際、身近な範囲でもそんな話は聞く。

どちらかというとSIだと

 - ウォーターフォール（要件定義、設計、実装、テスト）のフェーズを切って開発する。
 - 長期間かけて、複数の機能からなる１つのシステムを参画メンバー全員で開発する。
 - リリースは、複数の機能を束ねた大きな塊でまとめてやる。

ことが多いので、設計段階でクラス設計してしまって、影響範囲に応じてメンバーに対してタスク割当てを行うと、
中央リポジトリでもデメリットをあんまり感じなかったりする。

気軽にコミットしていても、担当タスクが他のメンバーとの影響が考慮済みであれば、
問題にならなかったりする。

PM（Project Manager）からすると分割リリースでもしない限り、今のPJメンバーで作っているものは一緒のタイミングでリリースするので、
中央リポジトリにどんどんコミットされている方が進捗も分かるし、状況が把握しやすい面もある。

逆にサービス開発だと

 - アジャイルにウォーターフォールほど明確なフェーズ分けはなく開発する。
 - 短期間で、個別の要件、機能単位で個人、チームやユニットごとに参画メンバーが開発する。
 - リリースは、個別の機能ごとに小さな単位でやる。

ことが今の案件もそうだが多いかと思う。

これだと設計段階でクラス設計してしまって、影響範囲に応じてメンバーに対してタスク割当てを行うのは、開発スタイルに合わない。
個々のメンバーやチームの担当タスクの影響は、コントロールされるべきだと思うけど、
リリースタイミングも状況によって前後するし、より柔軟性がある仕組みにしないとそこがボトルネックになると思っている。

その点、分散リポジトリでやる方が向いているし、メリットもより感じられるのだと思う。
ReadyNAS 102 上で RAID1 で構成したディスク1枚からデータを復旧する

# Long story short
## 手順
- ReadyNAS から抜き取ったHDDをPCに接続します。
私はSATA-USB変換ケーブル経由でラズパイにUSBで接続しました。

- カーネルのメッセージを読み、直近に接続されたデバイスの名前を確認します。

```
pi@raspberrypi:~$ dmesg | tail
[5455709.414861] usb-storage 1-1.5:1.0: USB Mass Storage device detected
[5455709.415172] scsi host0: usb-storage 1-1.5:1.0
[5455710.493139] scsi 0:0:0:0: Direct-Access     ASMT     2115             0    PQ: 0 ANSI: 6
[5455710.495554] sd 0:0:0:0: [sda] 3907029168 512-byte logical blocks: (2.00 TB/1.82 TiB)
[5455710.496061] sd 0:0:0:0: [sda] Write Protect is off
[5455710.496071] sd 0:0:0:0: [sda] Mode Sense: 43 00 00 00
[5455710.496495] sd 0:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[5455710.535257]  sda: sda1 sda2 sda3
[5455710.535547] sd 0:0:0:0: Attached scsi generic sg0 type 0
[5455710.537887] sd 0:0:0:0: [sda] Attached SCSI disk
```

- **/dev/sda** として認識されていることが分かりました。目的のパーティションを探します。

```
pi@raspberrypi:~$ sudo fdisk -l /dev/sda
Disk /dev/sda: 1.8 TiB, 2000398934016 bytes, 3907029168 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX

Device       Start        End    Sectors  Size Type
/dev/sda1       64    8388671    8388608    4G Linux RAID
/dev/sda2  8388672    9437247    1048576  512M Linux RAID
/dev/sda3  9437248 3907025071 3897587824  1.8T Linux RAID
```
最大容量の **/dev/sda3** が目的のパーティションですね。

- リードオンリーで強制再構成し、マウントします。

```
pi@raspberrypi:~$ sudo mdadm --assemble /dev/md0 --readonly --force --run /dev/sda3
mdadm: /dev/md0 has been started with 1 device (out of 2).
pi@raspberrypi:~$ sudo mount /dev/md0 /mnt/raid
mount: /dev/md0 is write-protected, mounting read-only
```
以上です。

## 問題が起こった場合
一旦 RAID を停止してやり直します。

```
sudo mdadm --stop --scan
```


# Short story long
随分前に買った NAS の容量が不足したので、2TB から 4TB に換装しました。
せっかくなので NAS が故障した場合に備え、単体の HDD から情報を取り出す方法を確立しておこうと思い、抜き出した 2TB の HDD を使って実験しました。
たまたまネイティブの Linux デバイスがラズパイしかなかったのでラズパイで試しましたが、十分動きましたね。
これでこの古い NAS を安心して使い続けられます。
CentOS7系環境でsupervisorを使ってphpをデーモン化してみた

## supervisorとは
supervisorとは、プロセスの死活監視などできるデーモン化ツールの1つです。

- プロセスの死活監視し、プロセスが寝たら再起動させる
- stdout/stderrを出力させる
- ステータス確認もできる

## 導入手順

まずは、supervisorをインストールします。
今回はEPELリポジトリからを前提に書いています。
（EPELリポジトリ経由で無い場合、「$ mkdir /etc/supervisor.d」など少し作業が増える）

```bash
$ yum install supervisor
```

initスクリプトはredhat-init-equeffelecを利用します。

```bash
$ curl -o /etc/rc.d/init.d/supervisord https://raw.githubusercontent.com/Supervisor/initscripts/master/redhat-init-equeffelec
$ chmod 755 /etc/rc.d/init.d/supervisord
```

log rotationを作成します。


```bash
$ sh -c "echo '/var/log/supervisor/*.log {
       missingok
       weekly
       notifempty
       nocompress
}' > /etc/logrotate.d/supervisor"
 
```

supervisord.confに動かしたいプログラムを追記します。
（細かい詳細はググってください。）

```bash
$ vi /etc/supervisord.conf

 1| [program:Execute001]
 2| command=/usr/bin/php /var/www/html/batch/Execute001.php
 3| ;priority=999                ; the relative start priority (default 999)
 4| autostart=true              ; start at supervisord start (default: true)
 5| autorestart=true            ; retstart at unexpected quit (default: true)
 6| ;startsecs=10                ; number of secs prog must stay running (def. 10)
 7| ;startretries=3              ; max # of serial start failures (default 3)
 8| ;exitcodes=0,2               ; expected exit codes for process (default 0,2)
 9| ;stopsignal=QUIT             ; signal used to kill process (default TERM)
10| ;stopwaitsecs=10             ; max num secs to wait before SIGKILL (default 10)
11| ;user=chrism                 ; setuid to this UNIX account to run the program
12| log_stdout=true             ; if true, log program stdout (default true)
13| log_stderr=true             ; if true, log program stderr (def false)
14| logfile=/var/log/supervisor/sampledeamon.log
15| logfile_maxbytes=1MB        ; max # logfile bytes b4 rotation (default 50MB)
16| logfile_backups=10          ; # of logfile backups (default 10)

```

サービスを実行し、状態を確認します。

```bash
$ service supervisord start
$ service supervisord status
```

サービスを止めたいときは、以下を実行します。

```bash
$ service supervisord stop
```
Cypher QLでリレーションの存在するノードを削除するための方法

##Cypher QLとは？
Neo4jというグラフデータベースを扱うための、SQLライクな言語です。
>Cypher QL（Cypher：サイファーと読む）は、Neo4jでグラフ構造のデータ処理を行うために開発した宣言型のグラフクエリ言語です。簡単に言うと、あらかじめ決まった機能を遂行する文やひな形のような構文の書式が存在し、それを組み合わせてクエリを作成し、データ処理を実行します。
（CREATIONLINE Inc.ホームページより）https://www.creationline.com/lab/7577

##参照整合性問題
RDBと同様に、リレーションが存在するノード同士は、先に整合性を削除しないとノードを削除できない仕組みになっています。
Neo4jでは、全てのリレーションには始点と終点のノードが存在するということを規約としているようです。
>Within the Neo4j graph database, there’s a guarantee that each relationship will always have a starting and ending node. This guarantee of referential integrity is core to the principles of reliability in which Neo4j concentrates its write architecture. To achieve this, ever time a relationship is being created or modified, Neo4j locks the nodes on both sides of the relationship.
https://www.graphgrid.com/understanding-detach-delete-in-cypher/


##リレーションの存在するノードを削除するには
DETACH DELETEを使用します。

・リレーションをもつノードを作成

```
CREATE(p:Person{name:"Kento Yamazaki"})-[:ACTED_IN]->(m:Movie{title:"Kingdom"})
RETURN p,m
```
<img width="1440" alt="スクリーンショット 2019-05-18 14.32.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248756/c9611180-eb62-6c14-f9a6-479969aa6383.png">

・削除しようとすると…エラー！

```
MATCH(p:Person{name:"Kento Yamazaki"})-[:ACTED_IN]->(m:Movie{title:"Kingdom"})
DELETE p,m
```
<img width="1440" alt="スクリーンショット 2019-05-18 14.37.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248756/0b0e614c-c1b0-697c-38a3-2bf0fa4ffb6a.png">


・DETACH DELETEを使用する

```
MATCH(p:Person{name:"Kento Yamazaki"})-[:ACTED_IN]->(m:Movie{title:"Kingdom"})
DETACH DELETE p,m
```

<img width="1440" alt="スクリーンショット 2019-05-18 14.38.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248756/45bad0c8-eb93-66f7-9bad-ca15f313ba8c.png">

無事削除されました。

##最後に
まだNeo4jに触り始めたばかりなので、間違いなどありましたら、どんどんコメントしていただけると幸いです。
【RSS】記事引っ張ってニュースアプリ作ってみた②一覧表示

前回の続き。
RSSで取得した記事を一覧で表示してみる。
記事タイトルを押した時に記事のリンク先に飛びたいので、Ajaxを使用しました。

config/routに以下を記述

```
resources :feeds do
  member do
   resources :entries, only: [:index]
  end
end
```
app/views/entries/index.html.erbに記述

```
<% @entries.each do |entry| %>
    <span class="record-history pick" href="<%= entry.url%>"><%= entry.title %></span>
    <br> - <i class="published"> published <%= entry.published.strftime("%Y-%m-%d-%R") %></i>
<% end %>
```

(spanタグにpickというクラスをつけていますが、記事の閲覧履歴を残したかったため、jsで使うクラス名としてつけています。これについては後ほど別の記事でまとめます)

```
$(document).ready(function() {
	$('.pick').on('click',function(event){
	   // event.preventDefault();
	   var linkUrl = $(this).attr('href');
	   console.log(linkUrl)

	   // Ajaxリクエストを送ってRSSから自分のところに情報入れる
	    $.ajax({
	      url: '/browsing_histories', //どこに遷移したいか(ルーティング)
	      type: 'POST',
	      data: {url: linkUrl},  //書き方変更
	      dataType: 'json'
	    })
	    window.location.href = linkUrl;
 });
});
```
GKEとSpinnakerでCD環境構築

# やりたいこと
- 簡単にSpinnakerをGKEにインストールしたい
- 新しいやつを入れたい

GCPの公式のSpinnakerのドキュメントを見て、GKEにインストールしてみたくなったが、最新(19/5/18)のSpinnaker(v1.12.5)ではなく、0.31というめっちゃ古いやつやって、そのままではインストールできなかった！

GCP公式のドキュメント
https://cloud.google.com/solutions/continuous-delivery-spinnaker-kubernetes-engine?hl=ja#start_a_cloud_shell_instance

MACにHalyardをインストールして構築したことはあるが、全部Kubernetesでやりたかった。

# Spinnakerの必要条件
- Kubernetesクラスタ
- DockerRegistoryの権限

# やることリスト
- サービスアカウント作成
- アクセス権限付与
- サービスアカウントのSecretリソース作成

## サービスアカウント作成
```
SERVICE_ACCOUNT_NAME=spinnaker-account

gcloud iam service-accounts create $SERVICE_ACCOUNT_NAME \
    --display-name $SERVICE_ACCOUNT_NAME
```

#### 変数整理
```
export SA_EMAIL=$(gcloud iam service-accounts list \
    --filter="displayName:$SERVICE_ACCOUNT_NAME" \
    --format='value(email)')

export PROJECT=$(gcloud info --format='value(config.project)')
```

## アクセス権限付与
```
gcloud projects add-iam-policy-binding $PROJECT \
    --member serviceAccount:$SA_EMAIL \
    --role roles/storage.admin 

gcloud projects add-iam-policy-binding $PROJECT \
    --member serviceAccount:$SA_EMAIL \
    --role roles/browser
gcloud iam service-accounts keys create spinnaker-sa.json --iam-account $SA_EMAIL
```

## values.yamlファイル作成
詳しくは[こちら](https://github.com/helm/charts/tree/master/stable/spinnaker)を参考にしてください。

```
halyard:
  spinnakerVersion: 1.12.5
  image:
    repository: gcr.io/spinnaker-marketplace/halyard
    tag: 1.16.0
dockerRegistries:
- name: gcr
  address: asia.gcr.io
  username: _json_key
  # パスワードは先ほど作ったspinnaker-sa.jsonをコピペ
  password: |
    {
      "type": "service_account",
      ...
    }
spinnakerFeatureFlags:
  - artifacts
  - jobs
minio:
  enabled: true
  imageTag: RELEASE.2018-06-09T02-18-09Z
  serviceType: ClusterIP
  accessKey: spinnakeradmin
  secretKey: spinnakeradmin
  bucket: "spinnaker"
rbac:
  create: true # ここはkubeconfigをsecretでやる方法とRBACでやる方法の２種類があります、こちらの方が簡単かと
```

## Helmからインストール
```
helm install -n cd -f values.yaml stable/spinnaker --timeout 600
```

### ログの確認
こちらで、どこでつまづいたのか確認できます。先ほどのvalues.yamlの `rbac.create` を `true` にするのを忘れると、インストーラ(`cd-install-using-hal`)がデプロイできなかったりするので注意が必要です。他にも、認証が通ってないとかって問題も発生しやすそうです。

```
k logs jobs/cd-install-using-hal -f

# stern をお使いの場合は
stern cd-i
```

## Spinnakerにアクセス
ちなみに、ポッドが立ち上がるまで若干かかります。

```
export DECK_POD=$(kubectl get pods --namespace spinnaker -l "cluster=spin-deck" -o jsonpath="{.items[0].metadata.name}")

kubectl port-forward --namespace spinnaker $DECK_POD 9000

export GATE_POD=$(kubectl get pods --namespace spinnaker -l "cluster=spin-gate" -o jsonpath="{.items[0].metadata.name}")

kubectl port-forward --namespace spinnaker $GATE_POD 8084
```
ローカル環境のPostfix構築

CentOS7で実施。Postfix、Dovecotを使ってローカルネットワーク向けの
メール送受信環境を構築。メール配信の仕組み理解のため。

### Postfix

インストール

```
sudo yum -y install postfix
```

起動

```
systemctl restart postfix
```
 
postfixのバージョン確認

```
postconf | grep mail_version
```
 
自動起動

```
systemctl enable postfix
```
 
main.cf

```
cp -p /etc/postfix/main.cf /etc/postfix/main.cf.org
vi /etc/postfix/main.cf

# 自身のドメイン設定
mydomain = mail-server.test
myorigin = $mydomain
 
# ローカルホスト以外からも受け付ける
inet_interfaces = all
 
# ipv4しか使用しないため
inet_protocols = ipv4
 
# 宛先ドメインに自身のドメインを追加
mydestination = $myhostname, localhost.$mydomain, localhost, mail-server.test
 
# 初めはローカルホストで動かすため
mynetworks = localhost
 
# メールボックスの形式設定
home_mailbox = Maildir/
```
 
再起動

```
systemctl restart postfix
```
 
user1というアカウントを作成する。

```
useradd user1 -s /sbin/nologin
任意のパスワード入力
passwd user1
```

server1というアカウントを作成する。

```
useradd server1 -s /sbin/nologin
任意のパスワード入力
passwd server1
```
 
ディレクトリの書き込み権限

```
chmod 777 /var/spool/mail
```

telnetインストール

```
yum -y install telnet
```

テスト

```
ローカルホストの25番ポートに接続
telnet localhost 25
 
出力
220 localhost.localdomain ESMTP Postfix
 
入力
helo localhost
 
出力
250 localhost.localdomain
 
入力:送信元アドレス
mail from: user1@mail-server.test
 
出力
250 2.1.0 Ok
 
入力:宛先アドレス
rcpt to: user1@mail-server.test
 
出力
250 2.1.5 Ok
 
入力:メールの本文かきますコマンド
data
 
出力
354 End data with <CR><LF>.<CR><LF>
 
入力:メール本文
helo postfix

入力:本文書き終えましたコマンド
.
 
出力
250 2.0.0 Ok: queued as ・・・
 
入力:telnet終了
quit
 
出力
221 2.0.0 Bye
 
以下ディレクトリ存在すること
ll /home/user1/Maildir
```
 
### Dovecot

インストール

```

yum -y install dovecot
```

起動

```
systemctl start dovecot
```

自動起動

```
systemctl enable dovecot
```
 
設定

```
vi /etc/dovecot/dovecot.conf
 
# 使用するプロトコル列挙
protocols = imap pop3 lmtp
 
# IPv4のみ使用。v6へのバインドを行わない
listen = *
```

vi /etc/dovecot/conf.d/10-mail.conf

``` 
# ファイルの場所を指定
mail_location = maildir:~/Maildir
```

vi /etc/dovecot/conf.d/10-auth.conf

``` 
# 平文認証の許可
disable_plaintext_auth = no
 
auth_mechanisms = plain login
```

vi /etc/dovecot/conf.d/10-ssl.conf

``` 
ssl = no
```
 
再起動

```
systemctl restart dovecot
```
 
テスト

```
telnet localhost 143
 
出力
Connected to localhost.
 
入力:user1でログイン
1 login user1 パスワード
 
出力
Logged in
 
入力:ホームディレクトリの一覧を見る
2 list "" *
 
出力
* List () "." "INBOX"
2 OK List completed.
 
入力:INBOXの中身を見る
3 select INBOX
 
出力
1 EXISTS　　←１通のメールがある
1 RECENT　　←最新のメールは１通
3 OK Select completed.
 
入力:1通目のメールを見る。送信時のテストのものが見れる。
4 fetch 1 body[]
 
出力
From: user1@mail-server.test
To: undisclosed-recipients:;
 
helo postfix
)
4 OK Fetch completed.
 
入力:終了
5 logout
 
出力
5 OK logout completed.
```
 
ネットワーク設定

```
vi /etc/postfix/main.cf

# 割り当てているネットワークを追記
mynetworks = localhost, 192.168.2.0/24
```

再起動

```
systemctl restart postfix
```

設定

```
vi /etc/dovecot/dovecot.conf
 
# ネットワークを記述
login_trusted_networks = xxx.xxx.xxx.xxx/xx (プライベートネットワークのCider)
```

再起動

```
systemctl restart dovecot
```
Leetcode #37: Sudoku Solver

```swift
var grids = [(Int, Int)]()

func solveSudoku(_ board: inout [[Character]])  {
    for i in 0..<9 {
        for j in 0..<9 {
            if board[i][j] == "." {
                grids.append((i,j))
            }
        }
    }
    helper(&board, 0)
}

private func helper(_ board: inout [[Character]], _ index: Int) -> Bool {
    if index == grids.count {
        return true
    }
    let ar = possibleNumber(board, grids[index].0, grids[index].1)
    if ar.isEmpty {
        return false
    } else {
        for num in ar {
            board[grids[index].0][grids[index].1] = num
            if helper(&board, index+1) {
                return true
            } else {
                board[grids[index].0][grids[index].1] = "."
            }
        }
        return false
    }
}

private func possibleNumber(_ board: [[Character]], _ i: Int, _ j: Int) -> [Character] {
    var set = Set<Character>()
    for x in 0..<9 {
        if board[x][j] != "." {
            set.insert(board[x][j])
        }
    }
    for y in 0..<9 {
        if board[i][y] != "." {
            set.insert(board[i][y])
        }
    }
    for x in 0..<3 {
        for y in 0..<3 {
            if board[i/3*3+x][j/3*3+y] != "." {
                set.insert(board[i/3*3+x][j/3*3+y])
            }
        }
    }
    var answer: Set<Character> = Set(["1","2","3","4","5","6","7","8","9"])
    answer.subtract(set)
    return Array(answer)
}
```
EC2（AmazonLinux）にDocker Composeをインストールする

## 環境
EC2(Amazon Linux 2 AMI)

## docker composeのインストール
docker-composeのインストールは、[Install Docker Compose \| Docker Documentation](https://docs.docker.com/compose/install/) からバイナリファイルをダウンロードする方法になる。

参考までに手順を載せるが、最新版のコマンドは[Install Docker Compose \| Docker Documentation](https://docs.docker.com/compose/install/)の、「Install Compose」章にある「Linux」タブを参照する方が良い。

### 1. 現在の安定版のバイナリファイルをダウンロード

```
sudo curl -L "https://github.com/docker/compose/releases/download/1.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
```

### 2. ダウンロードしたバイナリファイルに実行権限を許可

```
sudo chmod +x /usr/local/bin/docker-compose
```

### 3. インストールされたことを確認
バージョンが表示されればOK。

```
docker-compose -v
```

### 4. docker-composeコマンドが失敗する場合
シンボリックリンクを作成する。

```
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
```
Laravel Mix4でSassを使う

# 背景とか

- 公式ドキュメント読めば済みますが備忘録として

## 前提(環境)条件

- macOS Mojave
- Node.js 8.15
- Laravel-mix4をインストール済み

## その他モジュールをインストール

- node-sassをインストール（公式ドキュメントに書いてある）

```
npm install node-sass
```

- resolve-url-loaderをインストール
- これがないとSassコンパイル時に怒られる(ログに出る)

```
npm install resolve-url-loader
```

- webpack.mix.jsを編集（公式ドキュメントに書いてある）

```js
mix.sass('resources/sass/app.sass', 'public/css', {
    implementation: require('node-sass')
});
```

## コンパイル

```
npm run dev
```

## その他

- 例としてpackage.jsonの構成とか(最低限の構成ではなく色々入ってます)

```json
{
    "private": true,
    "scripts": {
        "dev": "npm run development",
        "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
        "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
        "watch-poll": "npm run watch -- --watch-poll",
        "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
        "prod": "npm run production",
        "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
    },
    "devDependencies": {
        "axios": "^0.17",
        "cross-env": "^5.1",
        "laravel-mix": "^4.0",
        "lodash": "^4.17.4",
        "vue": "^2.6.8",
        "vue-template-compiler": "^2.6.8",
        "imagemin-pngquant": "5.0.1"
    },
    "dependencies": {
        "node-sass": "^4.12.0",
        "resolve-url-loader": "^3.1.0",
        "sass-loader": "^7.1.0",
        "vue-analytics": "^5.16.4",
        "vue-loader": "^14.2.3",
        "vue-router": "^3.0.2"
    }
}

```

## 参考

[公式ドキュメント](https://laravel-mix.com/docs/4.0/upgrade)
DjangoCongressJP 2019 公開資料まとめ

参加申込開始からあっという間に定員に達した、[DjangoCongressJP 2019](https://djangocongress.jp/)に参加してきました。

会場スポンサーであるサイボウズさんのオフィスは、きれいでfantastic!
![DjangoCongress2019_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280437/24f7d636-b8fe-43f5-09b0-e0529a87592f.jpeg)

以下のプログラムの発表者が、スライドを公開されています。
どれも実践的で、分かりやすくポイントがまとめられています。

5/31追記：connpassサイト上で資料がまとめて公開されましたので、こちらの参照が確実です。
https://django.connpass.com/event/124059/presentation/


- Djangoで静的ファイルとうまくやる
ttps://tell-k.github.io/djangocongressjp2019/#1

- 現場で使える Django のセキュリティ対策
ttps://speakerdeck.com/akiyoko/django-security-measures-for-business-djangocon-jp-2019

- DjangoではじめるGraphQLとフロントエンド開発の協業
ttps://speakerdeck.com/nasum/djangodehazimerugraphqltohurontoendokai-fa-falsexie-ye

- Djangoでのメール送信 - 設定からテストまで
ttps://speakerdeck.com/thinkami/djangocongress-jp-2019-talk

- 自社サービスのDjango1.3サーバを1.11(LTS)にアップグレードするまでの道のり
ttps://speakerdeck.com/lighttiger2505/zi-she-sabisufalsedjangowo-1-dot-3kara1-dot-11-lts-ni-atupuguredosurumadefalsedao-falseri

- Authorization in Django
ttps://gitpitch.com/hirokiky/gitpitch?p=2019djangocongres#/

- どうなってるの？Djangoのトランザクション
ttps://speakerdeck.com/denzow/dounatuterufalse-djangofalsetoranzakusiyon


他にも様々な情報が#djangocongressで発信されています。
https://twitter.com/hashtag/djangocongress?src=hash

私は諸事情により限られた時間の参加になりましたが、Djangoに関わる多方面の分野の方と接する事ができて、とても刺激になりました。運営者や発表者、スポンサーの方々のご尽力に感謝いたします。
EC2（AmazonLinux）にDockerをインストールする

## 環境
AWS EC2（Amazon Linux 2 AMI）


## yumを使うと
`yum`で`docker`インストールしようとすると、毎回下記のようなエラーが出て困っていた。

```
Error: Package: 3:docker-ce-18.09.6-3.el7.x86_64 (docker-ce-stable)
           Requires: container-selinux >= 2.9
 You could try using --skip-broken to work around the problem
 You could try running: rpm -Va --nofiles --nodigest
```

## amazon-linux-extrasを使おう
下記コマンドで一発で`docker`を入れられる。
公式（[Amazon Linux \- Amazon Elastic Compute Cloud](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/amazon-linux-ami-basics.html)）

```
sudo amazon-linux-extras install docker -y
```

## アンインストール
`amazon-linux-extras`にはアンインストール用のコマンドがないため
`yum`でアンインストールするしかなさそう。

```
sudo yum remove docker
```

ちなみに、`yum`でアンインストールして、再度`amazon-linux-extras`でインストールしてみたが、エラーもなくインストールできた。


##### 続いて、docker composeもインストールする方は[こちら](https://qiita.com/maruuuuu/items/7d99cd1230b649591b4f)
flyweight pattern

# flyweight pattern
## ケース
小さくて多いオブジェクトを共有する

## 結果
### pros 
メモリ空間を節約できる

## 実装対象

FlyweightFactory
Flyweight

## example
intrinsic, extrinsicを区別する。
前者はflyweight内部に格納する状態、後者は状況に応じて外部から受け取る情報

```
class CharFactory {
    private var charStringMap: [String: Char]

    func char(code: String) -> Char {
        if let c = charStringMap[code] { return c }
        return Char(code)
    }
}

class Char {
    private let code: String

    init(_ code: String) {
        self.code = code
    }
}
```
Nuxt.jsプロジェクトへStorybook導入手順

##この記事について

AmazonLinux2で稼働しているNuxt.jsプロジェクトにStorybookを導入し、ブラウザから画面を表示するまでの手順です。
AmazonLinux2へNuxt.jsプロジェクトを導入する手順は以下のURLを参照してください。
https://qiita.com/deehii/items/58e6da680f322fce10ff

- - -
##Nuxt.jsプロジェクトにStorybookをインストールします
```sh
$ pwd
/home/ec2-user/my-project
$ npx -p @storybook/cli sb init
```

- - -
##nginxにStorybookが稼働するローカルサーバーを追加します

```sh
$ sudo vi /etc/nginx/conf.d/storybook.conf
```

- - -


```diff
+server {
+   listen       80;
+   server_name  storybook;
+
+   location /storybook {
+       proxy_pass http://localhost:6006;
+       proxy_http_version 1.1;
+       proxy_set_header Upgrade $http_upgrade;
+       proxy_set_header Connection 'upgrade';
+       proxy_set_header Host $host;
+       proxy_cache_bypass $http_upgrade;
+   }

+   error_page 404 /404.html;
+       location = /40x.html {
+   }

+   error_page 500 502 503 504 /50x.html;
+       location = /50x.html {
+   }
+}
```

- - -
##nginxを再起動します

```sh
$ sudo systemctl restart nginx
```

- - -
##Storybookを起動します
```sh
$ pwd
/home/ec2-user/my-project
$ npm run storybook 
```

<img width="380" alt="Screen Shot 2019-05-18 at 11.43.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418795/7eab747b-e0d1-80d8-017d-7a17e325651b.png">

- - -
##ブラウザからアクセス
ブラウザからEC2のパブリックIP(ポート6006)にアクセスします

<img width="1432" alt="Screen Shot 2019-05-18 at 11.44.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418795/d6259c8a-3747-0ce5-893d-f32003c845ed.png">

Storybookのページが表示されました。

- - -
以上
シェルスクリプトって??

#目的
業務を効率化するためにシェルスクリプトについて理解します!!
djangoでWEBアプリケーションを作成している中でDBの管理の際にシェルスクリプトを利用することでより便利にDBの設定が行えたのでアウトプットしていきたいと思います!!

#シェルって??
シェルはOSと対話する為に存在します。
ユーザーがターミナルからコマンドを入力し、シェルがOSが解釈できるように変換し実行してくれます。
Linuxにおいてこのシェルはbashと呼ばれます。


#シェルスクリプトって??
シェルスクリプトはシェルが実行する内容が書かれたスクリプトです。
テキストで記述されますが実際にコマンドに打つ内容をそのまま記述することで記述内容を実行してくれます。
つまり、コマンドに何回も入力しなくてはならないことをシェルスクリプトに記述することで一度に実行してくれる便利屋さんということですね!!

#具体例!!
今回、Djangoのデータベースを初期化する工程をシェルスクリプトにしたので以下に示します!!

```bash:dbreset.sh
#!/bin/sh
cd app1
rm -d -r migrations/
cd ..
rm -d -r db.sqlite3
python manage.py makemigrations app1
python manage.py migrate
python manage.py createsuperuser
```
このようなファイルを用意した後に、このファイルを実行することでこのファイルに記述した内容が上から順に実装されます。
ちなみに実行は以下のようにします!!

＞＞bash dbreset.sh

#まとめ
今回シェルスクリプトについてアウトプットしていきました!!
とても便利ですよね、たくさん使用して業務を効率化していきたいと思います!!
Leetcode #34: Find First and Last Position of element in Sorted Array

```swift
func searchRange(_ nums: [Int], _ target: Int) -> [Int] {
    let index = binarySearch(nums, target)
    if index == -1 {
        return [-1,-1]
    } else {
        var startIndex = index
        var endIndex = index
        while startIndex >= 0 {
            let tmp = binarySearch(Array(nums[0..<startIndex]), target)
            if tmp == -1 {
                break
            } else {
                startIndex = tmp
            }
        }
        while endIndex < nums.count {
            let tmp = binarySearch(Array(nums[(endIndex+1)...]), target)
            if tmp == -1 {
                break
            } else {
                endIndex = endIndex + tmp + 1
            }
        }
        return [startIndex, endIndex]
    }
}

private func binarySearch(_ nums: [Int], _ target: Int) -> Int {
    var start = 0
    var end = nums.count-1
    while start <= end {
        let middle = (start + end)/2
        if nums[middle] == target {
            return middle
        } else if nums[middle] < target {
            start = middle + 1
        } else {
            end = middle - 1
        }
    }
    return -1
}
```
AWSでFluentdを導入してS3にログアップロード

AWSで運用されている方がよくやるfluentdを使ったログのS3アップロードです。
手順ではApacheが動いているサーバと仮定して、以下ログをアップロードします。
/var/log/httpd/access_log
/var/log/httpd/error_log
/var/log/messages

### 前提条件
OS:AmazonLinux 2017-09
IAM Role設定済みであること。IAM Roleはインスタンスに割り当てるといいです。
バケット名:logs

### IAM Role設定例
S3の特定バケット（ログ保管）へアクセスする為のポリシー。
※ バケット名は適宜書き換えのこと。
※ Sidも適当な文字列へ書き換えること。（日時などへ）

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Stmt201803121612",
            "Effect": "Allow",
            "Action": [
                "s3:*"
            ],
            "Resource": [
                "arn:aws:s3:::logs/*",
                "arn:aws:s3:::logs"
            ]
        }
    ]
}
```

### td-agentインストール・設定手順
インストール

```
wget https://td-agent-package-browser.herokuapp.com/3/redhat/6/x86_64/td-agent-3.1.1-0.el6.x86_64.rpm
その都度最新のものをダウンロード。
 
rpm -Uvh td-agent-3.1.1-0.el6.x86_64.rpm
```

設定ファイルバックアップ

```
cd /etc/td-agent/
cp td-agent.conf td-agent.conf.org
```
 
td-agent プラグインのインストール

```
/usr/sbin/td-agent-gem install fluent-plugin-s3
/usr/sbin/td-agent-gem install fluent-plugin-forest
/usr/sbin/td-agent-gem install fluent-plugin-ec2-metadata
```

ログディレクトリ権限変更

```
cd /var/log/
chmod 750 httpd/
chown  root.td-agent  httpd/
ls -ld httpd/
 
chmod  640 messages
chown  root.td-agent  messages
ls -ld messages
```
 
td-agent 設定ファイルの編集

```
vim /etc/td-agent/td-agent.conf
※本記事、最下部の設定を記載。バケット名やバケットのパスは都度変更すること。
```

td-agent起動

```
/etc/init.d/td-agent start
```
 
ログテスト

```
logger test
※コンソール上でバケットを確認し、ログが転送されていることを確認する。
```

### 設定ファイル (/etc/td-agent/td-agent.conf)
```
<source>
  @type tail
  path /var/log/httpd/access_log
  tag httpd-access
  format apache2
  pos_file /tmp/td-agent/httpd-access.pos
</source>
 
<source>
  @type tail
  path /var/log/httpd/error_log
  tag httpd-error
  format apache_error
  pos_file /tmp/td-agent/httpd-error.pos
</source>
 
<source>
  @type tail
  path /var/log/messages
  tag syslog
  format syslog
  pos_file /tmp/td-agent/syslog.pos
</source>
 
 
<match {httpd-access,httpd-error,syslog}.**>
  @type ec2_metadata
   
  output_tag ${tagset_system}.${tagset_name}.${tag}
  <record>
    System       ${tagset_system}
    Name           ${tagset_name}
  </record>
</match>
 
<match **.{httpd-access,httpd-error,syslog}>
  @type forest
  subtype s3
   <template>
     s3_bucket logs
     s3_region ap-northeast-1
     path ec2-Logs
     buffer_path /var/log/td-agent/buffer/${tag}
     time_slice_format ${tag_parts[0]}/${hostname}/%Y/%m/%d/${tag_parts[-1]}-%Y-%m-%d-%H
     jst
     flush_interval 600s
     flush_at_shutdown true
   </template>
</match>
```
bridge pattern

# bridge pattern
## ケース

抽象と実装を分離する。
抽象のみで組み立てて、実装は置き換え可能にする。

## 実装対象

Client
Abstraction
RefinedAbstraction
Implementor
ConcreteImplementorA

## example
```
class WindowAbstraction {
    private let figureImplementor: FigureImplementorProtocol

    init(figureImplementor: FigureImplementorProtocol) {
        self.figureImplementor = figureImplementor
    }

    func drawRect() {
        figureImplementor.drawLine()
        figureImplementor.drawLine()
        figureImplementor.drawLine()
        figureImplementor.drawLine()
    }
}

class IconWindow: WindowAbstraction {
    func drawBorder() {
        // some process
        drawRect()
        // some process
    }
}

protocol FigureImplementorProtocol {
    func drawLine()
}

class : AndroidFigureImplementor {
    func drawLine() {
        // some exact process
    }
}
```
#Qiita でトレンド取得する #API がないのでスクレイピングもせずオンライン解析サービスでデータ取得してみる

# import.io を利用

 https://www.import.io/

詳しい操作方法は割愛

# Instant Access を選んで色々登録

![image](https://user-images.githubusercontent.com/13635059/57963328-99288600-795d-11e9-96ca-b710145599d8.png)

# Extraction -> New Extract を選んでURLを入力する

![image](https://user-images.githubusercontent.com/13635059/57963347-e73d8980-795d-11e9-9bec-d1036eaf06c0.png)

# トレンド表示されているトップページを非ログイン状態で解析

![image](https://user-images.githubusercontent.com/13635059/57963300-4949bf00-795d-11e9-8286-b80f15fb94d5.png)

# 解析された

![image](https://user-images.githubusercontent.com/13635059/57963301-4c44af80-795d-11e9-9843-a206ebd2c6c9.png)

# CSV とか落とせるらしい

![image](https://user-images.githubusercontent.com/13635059/57963306-4f3fa000-795d-11e9-8093-85296dfb1cd7.png)



# Original by Github issue

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








<!-- Update From Qiita API -->

# チャットメンバー募集


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

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





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
nginx 設定標準化

nginx設定のサンプルを記載します。

設定ファイル配置場所

```
/etc/nginx/sites-enabled/xxxxxx.conf
※　xxxxxxはドメイン名とする。
```

LB配下にnginxサーバを配置する場合

```
アクセスログがすべてLBのIPになるため、下記を設定ファイル内に記載する。
　set_real_ip_from xx.xx.xx.xx/xx;　←　LBのIP
　real_ip_header X-Forwarded-For;
```

アクセスログ

```
/var/log/nginx/xxxxx/access.log ltsv
※　xxxxxxはドメイン名とする。
※　ltsv形式にする。

ログフォーマットは下記とする。
---
log_format ltsv "time:$time_local"                                  : アクセス日時
　　　　　　"\thost:$remote_addr"                                    : クライアントのIPアドレス
           "\tforwardedfor:$http_x_forwarded_for"                   : アクセス元のIP
           "\treq:$request"                                         :  httpの要求URI
           "\tstatus:$status"                                       :  httpの要求URI
           "\tsize:$body_bytes_sent"                                 : 送信バイト数
           "\treferer:$http_referer"                                 : リファラーURL（遷移元URL）
           "\tua:$http_user_agent"                                   : ユーザエージェント情報（ブラウザ名・バージョン等）
           "\treqtime:$request_time"                                 : 要求処理時間（ミリ秒）最後のバイトがクライアントに送信された後、                       　　　　　　"\tcache:$upstream_http_x_cache"　　　　　　　　　　　　　　最初のバイトの間の経過時間がクライアントから読み取られ、ログの書き込み
           "\truntime:$upstream_http_x_runtime"
           "\tvhost:$host";
---
```

ログローテート設定

```
vi /etc/logrotate.d/nginx
---
# LB用のアクセスログ
/var/log/nginx/*.log {
daily
missingok
rotate 30
ifempty
compress
delaycompress
create 0640 www-data adm
dateext
sharedscripts
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 `cat /var/run/nginx.pid`
fi
endscript
}
 
#各サービス用のアクセスログ
/var/log/nginx/*/*.log {
daily
missingok
rotate 30
ifempty
compress
delaycompress
create 0640 www-data adm
dateext
sharedscripts
prerotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 `cat /var/run/nginx.pid`
fi
endscript
}
---
```

ドキュメントルート

```
/var/www/xxxxx/current/zzzzzz/public/
※　xxxxxxはドメイン名とする。zzzzzzはサービス名など。
```

レスポンスヘッダーにバージョン番号を表示させない。

```
/etc/nginx/nginx.conf
server_tokens off;　　←　#を外す
```

LBのヘルスチェックは下記を利用。

```
LBからのヘルスチェックは、各案件ログとは別に記録されるように設定を行う。
ドキュメントルート直下にヘルスチェック用のファイル「healthcheck.php」を準備し、LBのヘルスチェックは、/healthcheck.phpに対して行う。
nginxの設定ファイルに下記を記載して、LBからのヘルスチェックのアクセスログは、/var/log/nginx/access.logに記載されるようにする。

location = /healthcheck.php {
empty_gif;
access_log /var/log/nginx/access.log;
break;
}

phpが停止したときに、LBから切り離しされるようにhealthcheck.phpのファイルの中身は下記を記載する。
<?php {print 'healthcheck';}?>
```
Kaggle カーネルでPixieDustを使う

Kaggle Kernel上で、PixieDustを使ってみました。

いきなり`import pixiedust`を入れても動きませんでした。(*2019年5月)
まずはインストールが必要なようなので、カーネル画面右のSettings➡InternetをONにします。

![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191446/24632aed-d30e-b063-ca16-897f23c460c0.jpeg)



これで`pip install`などが使えるようになります。


```
!pip install pixiedust
```

でpixiedustをインストールし、

```
import pixiedust 
```
で使用準備完了です。

使用するときは

```
pixiedust .display(データ名)
```
です。

#実際に使ってみる


試しに、[タイタニックコンペ](https://www.kaggle.com/c/titanic/kernels)で新カーネル(Note Bookを選択)を作り、PixieDustでtrain.csvを見てみます。
画面右のSettings➡InternetをONにし、以下を追記し実行します。


```
train = pd.read_csv("../input/train.csv")
!pip install pixiedust
import pixiedust as px
px.display(train)
```
PixieDustが起動しました。
最初はテーブルが表示されます。
![table.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191446/bc183bd5-7a25-ba56-ce94-80e1aa2cc0cc.jpeg)

左上のこのアイコンを押す見たいとグラフの種類を選択できます。
今回はBar Chartを選択してみます。
![gura.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191446/645ec399-8ace-8834-4e0c-d9822354f7e0.jpeg)

左側にすべてのカラムが表示されます。Survived(生存率)とPclass(客室グレード)を縦軸、横軸にドラッグ。
OKを押します。
![kjh.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191446/3389a668-a4ed-3639-b00a-95aa7abb1059.jpeg)

Bar Chartが表示されました。
![ggg.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191446/b5513e9e-c704-ee1e-3675-ee707e4e68bf.jpeg)

詳細な使い方などはこちらのリンクにあるようです。

[・PixieDust Hello World Lab](https://github.com/pixiedust/pixiedust/wiki/Tutorial:-Using-Notebooks-with-PixieDust-for-Fast,-Flexible,-and-Easier-Data-Analysis-and-Experimentation)
【初心者向け】AtcoderA問題レベルのコードの書き方(Ruby)

自作問題をときながら、競技プログラミング(AtCoderのA問題レベル)での「こんな書き方もできるよ〜」ってパターンを紹介していく。

## 得ることができるもの
- AtCoderA問題レベルでのコードの書き方について。今回はデータの取得の仕方と最大最小、三項演算子についてのみ。

## 対象者
- AtCoderでAの問題を解き始めた！
- 競技プログラミングに触れてみたい！

## 問題
masa08君はX円のりんごとY円のみかんとZ円のバナナのうち、最も値段が高い果物を購入しようとしている。現在の所持金はN円で、所持金Nが最も値段が高い果物に満たない場合は何も買わずに帰るとする。

【入力】
X Y Z N

【出力】
'GET' or 'NO'(何も買わなかった場合)

【例】
入力: 100 200 300 500
出力: GET

入力: 100 200 300 100
出力: NO

## 入力
```ruby
x, y, z, n = gets.split.map(&:to_i)
```
一つ一つ取得するのではなくて、一気に値を取得する。splitで各入力を文字列として取得、map(&:to_i)で型をinteger型に変更する。


## 最大最小
```ruby
[x, y, z].max
```
配列に対して、maxで最大値、minで最小値を取得することができる。最大最小はいろんな場面で使うと思う。

## 三項演算子
```ruby
puts [x, y, z].max <= n ? 'GET' : 'NO'
```
if文を書かなくても、三項演算子を用いれば条件分岐文を短く書くことができる。?の前までが条件、その次は条件がtrueの場合、最後が条件がfalseの場合。

## 全文
```ruby
x, y, z, n = gets.split.map(&:to_i)
puts [x, y, z].max <= n ? 'GET' : 'NO'
```

## まとめ
競技プログラミングのテクニックは本当に色々とありそうなので一つ一つ知っていきたい。
Go Conference 2019 Spring ゆるゆるまとめ

# はじめに
2019年5月18日に東京で開催される Go Conference 2019 Spring に参加してきました．
https://gocon.jp/
気になった Session に関して，ゆるゆるメモったので，本記事でまとめたいと思います．
~~間違っている箇所があれば優しくご指摘下さい．~~

# エラー設計について/Designing Errors
https://gocon.jp/2019-spring-sessions#b2-s-%E3%82%A8%E3%83%A9%E3%83%BC%E8%A8%AD%E8%A8%88%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6designing-errors

Go におけるエラーハンドリングのベストプラクティス紹介

Speaker: morikuni さん
Twitter: inukirom

## エラーについて
エラーには **既知のエラー** と **未知のエラー** が存在する
未知のエラーを既知のエラーにするのが **エラーハンドリング**

## エラーに求められること
エラーに求められるのは **関係者に処理が失敗した原因を伝える** こと
関係者によってエラーに求める情報は異なるので， **関係者ごとに適切な情報を渡そう**

- アプリケーション：エラーの識別情報
- エンドユーザ：人間が理解可能なメッセージ
- 運用者：コールスタックやコンテキスト

## Go でエラーを扱うベストプラクティス
- アプリケーション固有のエラーコードを定義しよう
- 既知の外部のエラーは定義したエラーコードに変換しよう
- 定義したエラーコードのみを想定してエラーハンドリングをしよう
- エンドユーザがエラーを解決できる場合はメッセージを追加しよう
- 必要に応じてコールスタックや引数の情報を追加しよう
- 未知のエラーが見つかったらハンドリングして既知にしよう

## failure について
上記のエラーハンドリングを適切に行うために failure というものを作ったよ 
failure を使ったエラーハンドリング方法紹介

## failure と xerrors の違い
failure はエラーを **拡張** するイメージ
xerrors はエラーを **変換** していくイメージ

## どちらを使うとよいか
- アプリケーション： failure
- ライブラリ： xerrors

# まとめ
Go Conference 2019 Spring に参加して気になった Session についてまとめました．
まだまだ Go Conference は開催中なので，引き続き気になる Session があれば記事化していきたいと思います．

Qiita には私が聞いた内容をまとめていますが，
会社のブログには，同僚が書いた記事も載っているのでそちらも合わせてご覧下さい．
http://nekojarashi.hatenablog.jp/
MySQLのメモリ関連確認コマンド (都度追記)

パラメータチューニングなどメモリ関連のパラメータ設定する際に使用できるかも。

#### トータルメモリサイズを導出するSQL(メモリ設定変更後など確認用)
```
SELECT
  @GLOBAL_BUFFER := (@@GLOBAL.KEY_BUFFER_SIZE + @@GLOBAL.INNODB_BUFFER_POOL_SIZE + @@GLOBAL.INNODB_LOG_BUFFER_SIZE) as GLOBAL_BUFFER_SIZE,
  @THREAD_BUFFER := (@@GLOBAL.NET_BUFFER_LENGTH + @@GLOBAL.SORT_BUFFER_SIZE + @@GLOBAL.READ_BUFFER_SIZE + @@GLOBAL.JOIN_BUFFER_SIZE + @@GLOBAL.READ_RND_BUFFER_SIZE) as THREAD_BUFFER_SIZE,
  @TOTAL_MEMORY  := (@GLOBAL_BUFFER + (@THREAD_BUFFER * @@GLOBAL.MAX_CONNECTIONS)) as TOTAL_MEMORY_SIZE,
  @TOTAL_MEMORY / 1024 / 1024 / 1024 as TOTAL_MEMORY_SIZE_gb;
```

#### innodb_buffer_pool_sizeとinnodb_log_file_sizeをさくっと確認したい時
```
read -sr MYSQL_PWD_INPUT
※root@localhostのパスワードを入力
 
MYSQL_PWD="$MYSQL_PWD_INPUT" mysql -e "SHOW GLOBAL VARIABLES LIKE 'innodb_%_size';"|grep "pool_s\|log_f
```
oh-my-zshで入力履歴を表示して、補完する

# tl;dr

```
oh-my-zshで直近のコマンドをサジェストしたい
```
　　
　　
オワコンと言われている？ `zsh`、`oh-my-zsh`ではありますが

使用しているので、書いてみます。


# まずは移動

```
cd ./.oh-my-zsh
```
　　

各自、移動。

<img width="981" alt="スクリーンショット 2019-05-18 11.25.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268339/97f0ba40-5db0-6862-3424-d3d947269039.png">

いた。

# pluginsへ移動

```
cd plugins
```

# zsh-autosuggestionsをクローン

[zsh-autosuggestions](https://github.com/zsh-users/zsh-autosuggestions)をクローン。

```
git clone https://github.com/zsh-users/zsh-autosuggestions $ZSH_CUSTOM/plugins/zsh-autosuggestions
```

# .zshrcに記載

`.zshrc` で `plugins`をgrepして  
`zsh-autosuggestions`を追加。  

```
plugins=(
    git
    zsh-autosuggestions
)
```
　　

誤って、カンマ入れるとこうなるよ。

```
[oh-my-zsh] plugin 'git,' not found
```
　　
 
設定更新。

```
source ~/.zshrc
```

# やったー

<img width="231" alt="スクリーンショット 2019-05-18 11.44.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268339/ef6d5536-a866-2bf8-3d99-3dc54779d4b0.png">

補完を確定するには　`→` か `ctrl + f` か　`ctrl + e`


# なんか薄くてみにくい

補完の文字がデフォだとみにくい。。

と思ったら、設定変更できるみたい。


```
ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=your_color_code'
```

# fg=your_color_code ってなんすか？

って思って調べたら、[ここ](https://magenest.com/en/power-up-and-beautify-your-terminal-by-zsh/)にあった。

![image01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268339/1e212910-41ce-9dbf-2f23-b1c1af46387e.png)


`１３` を選択！

`.zshrc` に追加！

```
ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=13'
```

設定更新！

```
source ~/.zshrc
```

# やったー！

<img width="192" alt="スクリーンショット 2019-05-18 12.32.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268339/f8f303bc-c0df-dafa-5782-020f9587c861.png">
Leetcode #32: Longest Valid Parentheses

```swift
func longestValidParentheses(_ s: String) -> Int {
    var answer = 0
    var stack = [Int]()
    stack.append(-1)
    for (index, char) in s.enumerated() {
        if char == "(" {
            stack.append(index)
        } else {
            stack.removeLast()
            if stack.isEmpty {
                stack.append(index)
            } else {
                answer = max(answer, index-stack.last!)
            }
        }
    }
    return answer
}
```
ECサイトで配布するであろうクーポンの機能をまとめてみた

こんにちわわわわわのわ。

とある世界の執行役員 (@azulmod5)です。

## この記事を読む人の対象
このタイトルに釣られた人は、恐らく思いやりのあるマーケターやECサイトを作っているエンジニア諸君である

そう、
ECサイトを作ってる人ならわかるはず
クーポンの機能を作るのは、エンジニアからしたら大変なのである

クーポンは、色々なクーポンが世の中にある。
ビジネスによって本来ありえないようなクーポンが、作られるからだ

要件定義では、賄いきれないありえないクーポンがある

しかし、これから言うことは抽象度をあげればどんなクーポンでも発行できてしまう
素晴らしいメソッドを用意しよう（うーん。。本当かな。。）

## 要件定義
恐らく考えれるのは、このクーポンたち

- ○％OFFクーポン
- ○％円引きクーポン
- 全額無料クーポン

大枠は、こう言うクーポンを想像するだろう
今度は、誰にだ！
ここのケースは、かなり重要だと思うしっかり定義していこう

- 特定のユーザーに配布するクーポン
- みんなに配るクーポン
- みんなに使って欲しいけどn回までしか使えないクーポン
- 特定のユーザーにn回までしか使えないクーポン

もう、お分りいただけただろうか
ケースが多すぎるのだ
優秀なプログラマーならこんなもんかと思ってしまうかもしれないけど、初めてクーポン機能を作る人は考えることが多すぎると思うかもしれない

## 色々要件のケースを考えてみたよ
- 特定のユーザーに配布するクーポン○％OFFクーポン
- 特定のユーザーに配布するクーポン○％円引きクーポン
- 特定のユーザーに配布するクーポン全額無料クーポン
- みんなに配るクーポン○％OFFクーポン
- みんなに配るクーポン○％円引きクーポン
- みんなに配るクーポン全額無料クーポン
- みんなに使って欲しいけどn回までしか使えないクーポン○％OFFクーポン
- みんなに使って欲しいけどn回までしか使えない○％円引きクーポン
- みんなに使って欲しいけどn回までしか使えない全額無料クーポン
- 特定のユーザーにn回までしか使えないクーポン○％OFFクーポン
- 特定のユーザーにn回までしか使えないクーポン○％円引きクーポン
- 特定のユーザーにn回までしか使えないクーポン全額無料クーポン

__１２通り__もあるんですよ。
もうこれは

もう多すぎる
多すぎるよ大変だよ。。。

数えると１２機能ほどあります、何日かかるんでしょうね。。。

これは、エンジニア的には大変なんです。

ふぅー疲れた。。。

次からは、そのクーポンを実際にテーブル設計をしてみたいと思います

## ここまで読んでくれた方へ

ここまで読んでくださりありがとうございます。

次からは、そのクーポンを実際にテーブル設計をしてみたいと思います

いいねやコメント、SNSでの共有等をしてくださると、今後の励みになります。よろしくお願いします。

良かったらツイッター(@azulmod5)もフォローしてね