OmniAICreator/Qiita-1.07M huggingface dataset:
brewからmongodbがなくなったのでmongodb-communityをインストールする

# はじめに

MongoDBが必要だからインストールしようと思って

```shell
$ brew install mongodb

Error: No available formula with the name "mongodb"
==> Searching for a previously deleted formula (in the last month)...
Warning: homebrew/core is shallow clone. To get complete history run:
  git -C "$(brew --repo homebrew/core)" fetch --unshallow

Error: No previously deleted formula found.
==> Searching for similarly named formulae...
Error: No similarly named formulae found.
==> Searching taps...
==> Searching taps on GitHub...
Error: No formulae found in taps.
```

と怒られたのでインストール方法を残す

# 方法

ちなみに`brew search mongodb`すると

```shell
$ brew search mongodb

==> Casks
gcollazo-mongodb                                            mongodb-compass-community                                   mongodb-compass-readonly                                    nosqlbooster-for-mongodb
mongodb-compass                                             mongodb-compass-isolated-edition                            mongodbpreferencepane                                       homebrew/cask-versions/mongodb-compass-beta

```

なくなってる。。

どうやら、MongoDBがOSSじゃなくなったらしいので以下を実行

```shell
$ brew tap mongodb/brew

==> Tapping mongodb/brew
Cloning into '/usr/local/Homebrew/Library/Taps/mongodb/homebrew-brew'...
remote: Enumerating objects: 13, done.
remote: Counting objects: 100% (13/13), done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 13 (delta 4), reused 5 (delta 1), pack-reused 0
Unpacking objects: 100% (13/13), done.
Tapped 6 formulae (46 files, 60.1KB).

$ brew install mongodb-community

==> Installing mongodb-community from mongodb/brew
==> Downloading https://fastdl.mongodb.org/osx/mongodb-macos-x86_64-4.2.1.tgz
######################################################################## 100.0%
==> Caveats
To have launchd start mongodb/brew/mongodb-community now and restart at login:
  brew services start mongodb/brew/mongodb-community
Or, if you don\'t want/need a background service you can just run:
  mongod --config /usr/local/etc/mongod.conf
==> Summary
🍺  /usr/local/Cellar/mongodb-community/4.2.1: 21 files, 273.5MB, built in 26 seconds

$ brew services start mongodb-community

==> Successfully started `mongodb-community` (label: homebrew.mxcl.mongodb-community)
```

これで使えるようになる

ちなみに`brew tap`なるものを初めて使ったが、
> brew tapとは公式以外のリポジトリをフォーミュラとしてHomebrewに追加するもので、brewのもとでinstall,uninstall,updateなどが行えます。もちろん自分が公開しているものも簡単に追加できます。

(引用)　[brew tapとは](https://qiita.com/saa/items/85ed5e914d424fbf9fd6)
らしいです。
mayaからffmpegを使ってmp4を書き出し

##**準備**

**1. ffmpegをダウンロードします。**
>【windows】FFmpegをインストールする手順
>https://fukatsu.tech/windows-ffmpeg

上記のページを参考にffmpegをダウンロードして環境変数の設定まで行います。

**2. [ffmpeg-python](https://pypi.org/project/ffmpeg-python/)のインストール**

```python
pip install ffmpeg-python
```
pipを使ってpython用のffmpegのライブラリのffmpeg-pythonをインストールします。
>Mayaでのパッケージ管理 - mayapyにpipを入れてみるよ
>https://qiita.com/it_ks/items/664f56d5e203ec005ca4

pipの導入の仕方は上記を見て頂ければ

##**実行**

mayaで下記のコードを実行するとプレイブラストが非圧縮のAVIで書き出され、そのAVIを即mp4に変換します。
AVIのほうはmp4への変換が終わったら自動で削除されます。

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

import maya.cmds as cmds
import ffmpeg
import os

# 書き出し先の指定
mp4 = "D:/test.mp4"
avi = mp4.replace("mp4", "avi")
# プレイブラストの書き出し
cmds.playblast(fp=4, offScreen=1,
               clearCache=1, format='avi', sequenceTime=0,
               showOrnaments=0, percent=100,
               filename=avi, viewer=0,
               compression="None", quality=100, widthHeight=(500, 500),
               fo=1)
# ffmpegを使ってAVIをmp4に変換
stream = ffmpeg.input(avi)
stream = ffmpeg.output(stream, mp4, pix_fmt='yuv420p', vcodec='libx264')
stream = ffmpeg.overwrite_output(stream)
ffmpeg.run(stream)
# AVIを削除
os.remove(avi)

```

##**エラー**
自分の環境だとffmpeg読み込み時に以下のようなエラーが出ました。
![2019-11-08_17h39_29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529842/6932bc1c-54a4-3476-4ed7-c99dd5f2f9a4.png)
どうやらpython27.zipのlib2to3以下にあるファイルが開けない(解凍できない？)のが原因のようです。
[pythonのgithub](https://github.com/python/cpython/tree/2.7/Lib/lib2to3)からlib2to3をダウンロードできるようなので、それをダウンロードして
C:\Program Files\Autodesk\Mayaのバージョン\Python\Lib\site-packages
に移したら動くようになりました。
DockerのGDがjpegに対応してないので対応する

# elfinderのリサイズが動かない（ローカル環境にて）

エラーが出る。

```
Call to undefined function imagecreatefromjpeg() {"exception":"[object] (Symfony\\Component\\Debug\\Exception\\FatalThrowableError(code: 0): Call to undefined function imagecreatefromjpeg() at /var/www/html/public/js/admin/elfinder/php/elFinderVolumeDriver.class.php:5819)
```

GDがうまく動いてない模様。

# 原因

https://qiita.com/takeru56/items/74d3e402660ae4473e88

**JPEGのサポートが有効になっていないため**

# 解決方法

Dockerfileにて

```
RUN apt-get install -y \
        libfreetype6-dev \
        libjpeg62-turbo-dev \
        libpng-dev \
    && docker-php-ext-install -j$(nproc) iconv \
    && docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
    && docker-php-ext-install -j$(nproc) gd
```
PowerShellでCD-ROMドライブのドライブ文字変更ツールを実装してみた

業務でPowerShellを用いてCDドライブのドライブレター(通称：ドライブ文字A~Z)を変更するツールを実装する必要が有ったため調査して実装したスクリプトを備忘録も兼ねてまとめます。

```powershell:CD-ROMドライブのDriveLetterの変更
Param($after_letter)

# Get current drive letter of CD-ROM drive
$before_letter = (Get-Volume | ?{$_.DriveType -match 'CD-ROM'}).driveletter

# Get current drive number of CD-ROM drive
Write-Output "list volume" | DiskPart | ?{$_ -match ("Volume[ ]{1}(?<volume>\d)[ ]*"+ $before_letter)} | Out-Null
$volume = $Matches["volume"]

# Set new drive letter provided by argument
Write-Output ("select volume {0}`nassign letter={1}" -f $volume, $after_letter) | DiskPart | Out-Null
```

実行にはシェルを格納したディレクトリ上でPowerShellウィンドウを開いて以下のコマンドを実行します。(例はDドライブをQドライブに変更する場合)

```
> .\drive_letter_changer.ps1 "Q"
```

* Before

![before](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469079/4757160b-e085-ab86-ab2e-7ef08278d7e2.jpeg)

* After

![after](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469079/60546605-f5a4-ed93-ac69-ce3740ca2d22.jpeg)

実際のソースコードは以下のURLからダウンロード出来ます。
[Drive Letter Changerのソース @ GitHub](https://github.com/y-vectorfield/drive_letter_changer)

# Reference
https://gist.github.com/n-fukuju/8487265
https://blog.shibata.tech/entry/2016/01/11/151201
Heroku で Apache HTTP Server コンテナをそのまま動かそうとすると crash するのを解決したメモ

# 結論から言うと
- Heroku ではコンテナに外部からのアクセスを受け付けるポートを動的に割り振っている
- ので、httpd.conf に Listen するポート番号を固定で記述してしまうと疎通できない
- Heroku が動的に割り振っているポート番号は環境変数 $PORT として取得できる
- Dockerfile 内の ENTRYPOINT 実行タイミングで Listen ディレクティブを $PORT の値に編集するコマンドを実行してやるとなんとかなる

</br>

# コンテナをpushしただけだとエラーになる

例えば Dockerfile はこんな感じ。

```Dockerfile
FROM httpd:alpine
MAINTAINER xsgk

ADD ./index.html /usr/local/apache2/htdocs
```

これのデプロイを行うと、

>State changed from starting to crashed

とか

>(13)Permission denied: AH00072: make_sock: could not bind to address [::]:80
>(13)Permission denied: AH00072: make_sock: could not bind to address 0.0.0.0:80
>no listening sockets available, shutting down

とか、もうエラーの大合唱。bind ができないってことは何かそもそも接続できてないね、と思ってるとこんなのを stackoverflow で見つけた。同じく Apache の httpd を使って接続できないという状況を以下のとおり解決したとのこと。

[Deploy a Dockerized Laravel app using Apache on Heroku](https://stackoverflow.com/questions/54452086/deploy-a-dockerized-laravel-app-using-apache-on-heroku)

>I discovered I could insert a CMD statement at the end of my Dockerfile to sed replace the ports in my apache config files to the magical $PORT environment variable at run time.

（意訳）

>Dockerfile の終わりに CMD ステートメントを挿入するかたちで、sed コマンドで Apache コンフィグファイル中のポート指定を、ランタイムの $PORT 環境変数の値に置換できることを発見したんだ

なるほど、やってみよう。

# $PORT の値に書き換える処理を Dockerfile に追加した

今度の Dockerfile はこんな感じで、ENTRYPOINT が実行されるタイミングで http.conf 中の Listen ディレクティブを置換（`sed`）したのち、本来のコンテナ起動時のコマンド（`httpd-foreground`）を実行するよう記述。

```Dockerfile
FROM httpd:alpine
MAINTAINER xsgk

ADD ./index.html /usr/local/apache2/htdocs

ENTRYPOINT []
CMD sed -i -e "s/Listen 80/Listen $PORT/g" /usr/local/apache2/conf/httpd.conf && httpd-foreground
```

これをデプロイすると
 ![テスト用HTML画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251261/8dc8a814-4f7d-f8d0-555a-4a6b03c1cace.png)
出た。以上。


#参考

[Deploy a Dockerized Laravel app using Apache on Heroku](https://stackoverflow.com/questions/54452086/deploy-a-dockerized-laravel-app-using-apache-on-heroku)
opencv2で画像をぼかしてみる

#目的
先日の記事のせいで、少し画像処理に興味が湧いてきました。
とは言え最後に数学を触ったのは高3の期末テスト...。しかも2点。
理解不能なところもありましたが、まずは触ってみようということでコードを書いてみました。

#まずはインストールと画像の用意
opencv2ってのが画像処理用のモジュールらしい。ということで安直に「pip install opencv2」するも見つからないらしい。どうやらこっちが正しい模様。

```shell
$ pip install opencv-python
```

ぼかす画像は目の保養としてフリー素材の田舎っぽい画像を採用。

![inaka.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/495652/775ab469-a88c-456f-f5a9-360a4b1a2232.jpeg)

こいつをぼかしていきましょう。

#コード
ではコードを書いていきます。

##インポート部分＋画像読み込み
```python:main.py
import cv2

#画像を読み込む
image = cv2.imread("inaka.jpg")
```

##（補足）BGR→RGB変換したい場合
このopencv2は、画像をBGRで表現してくるらしい。
そして、加工後の画像を保存したり、描画するためにするために使えるライブラリであるmatplotlibはRGB形式。matplotlibを使う場合、ここの違いを無視して進めるとこうなります！　笑

![new_image.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/495652/9024c1f0-fc78-da70-9864-a6b315e93fb3.jpeg)

というわけで、BGR→RGB変換する場合はこう。今回は加工後の画像をmatplotlibに渡したりはしないので不要です。

```python:main.py
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
```

##ぼかす
いよいよぼかし作業に入ります。とは言ってもメソッド呼ぶだけ。

```python:main.py
blurr_image = cv2.GaussianBlur(image, (5, 5), 0)
```

このGuassianBlur、引数がよくわかりませんでした。
第一引数は画像オブジェクト、第二引数はカーネルなる数値配列、第三引数は標準偏差らしいですが
私にとってはすべて宇宙語に聞こえます。ちゃんと勉強しとけばよかった。

##画像を書き出す
さて出来上がった画像を書き出します。

```python:main.py
cv2.imwrite("new_image.jpg", blurr_image)
```

##コード最終形態
コード全体はこんな感じになりました。

```python:main.py
import cv2

image = cv2.imread("inaka.jpg")
blurr_image = cv2.GaussianBlur(image, (5, 5), 0)
cv2.imwrite("new_image.jpg", blurr_image)
```

##確認してみる
変わった...のか...？

![new_image.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/495652/4f0cbd61-62ad-d223-306d-827001bc3b6e.jpeg)

GaussianBlurの引数をちょこちょこ弄ってみましたが、法則性が掴めず今日は時間も無いし断念...。

#ゴリ押し突破
余談ですが目が悪すぎるくせにメガネは邪魔で嫌い、コンタクトも怖くて入れられないので
普段からすべてぼけて見えてます。そのせいで本当にぼけてくれたのか全くわかりません。
もしかしたら上の画像もちゃんとぼけてるのかもしれませんが、体感できないので繰り返しで100回ぐらい回してやろうと思いました（絶対使い方間違ってると思います）。

```python:main.py
import cv2
image = cv2.imread("inaka.jpg")

for i in range(1,100):
    image = cv2.GaussianBlur(image, (5, 5), 0)

cv2.imwrite("new_image.jpg", image)
```

ちゃんとぼけてくれたような気がします。
![new_image.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/495652/545566d6-c739-af5b-01bc-d7421de39484.jpeg)

ちなみに、これ以上繰り返し回数を増やしても劇的にボケ度がUPすることはありませんでした。
会社を辞めた後輩に詳しいやつがいたような気がするので、聞いてみようと思います。

#結論
・画像のぼかしはopencv2で実現可能
・GuassianBlurの使い方がよくわからないけど泥臭くぼかし処理を繰り返したらそれっぽくなった
Amplify Consoleでのバックエンド自動構築ユースケース

# AWS Amplifyとは

AWS Amplifyは3つの要素から成る。
ポピュラーなWebサービスに必要な開発・運用ツールを一式揃えた感じ。

- **Amplify CLI**
`amplify` コマンドを使ってバックエンドのAWSリソースを構築する。
例えば `amplify auth add` と打てばCognito用のCloudFormationテンプレートが生成され、
`amplify auth push`  か `amplify push` すれば、それがAWS上に反映される。
https://github.com/aws-amplify/amplify-cli

- **Amplify Framework**
iOS/Android/Web向けのクライアントライブラリでフロントエンドの開発時に利用できる。
AWSバックエンドとの連携が容易になる。
例えば、Vue.jsで `<amplify-authenticator />` と書くと認証/新規登録/リマインダーが実装できる。謎。
https://docs.amplify.aws/

- **Amplify Console**
Amplify Console は `*.amplifyapp.com` ドメイン下にWebアプリケーションをホストする。
Gitリポジトリと連携することでCI/CDパイプラインを使ったビルド/デプロイ/テストを自動実行してくれる。
他にも機能はあるがここでは割愛する。
https://aws.amazon.com/jp/amplify/console/

# Amplify Console によるバックエンドの自動構築

Amplify Console は当たり前のように Amplify CLI と相性がよく、バックエンド設定は自動検知され、再現可能な状態で構築作業が自動化される。
Gitリポジトリを Amplify Console に紐づけておくことで、Gitにコミットするたび自動的に `amplify push` され、差分がバックエンドに反映される。
バックエンドの構築が手軽に行えるので、Amplify Console でありがちなユースケースについてまとめた。

## バックエンドの構築パターン

### Gitブランチごとのバックエンド構築

基本的な機能としてブランチごとに環境を構築できる。
ドメイン、パイプライン、バックエンド等がそれぞれのブランチ毎に作成される。

![amplify_app.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379/84713a68-5ab1-0b43-c7f1-e9b21b804406.png)

AWSコンソールか `aws amplify create-branch` で対象ブランチを追加。
もしくは Branch autodetection をONにすると、自動的にパターンに当てはまるブランチを検出して追加することもできる。この時、毎回バックエンドを構築したり、全てのブランチで特定のバックエンドに向けたりできる。

![branch_autodetection.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379/5c447427-d28d-a627-0988-c8eb2f3363c2.png)

### 開発者ごとのバックエンド構築

Amplify CLI には `env` というものがあり個別の環境を定義できる。
`amplify env add` で環境の追加、 `amplify env checkout` で環境の切り替えを行う。
各自の `env` とGitブランチを紐付けて Amplify Console に登録すれば、開発者ごとにバックエンド環境を用意できる。

### PRのレビューがしたい時のバックエンド構築

https://docs.aws.amazon.com/amplify/latest/userguide/pr-previews.html
現状、GitHubかつプライベートリポジトリじゃないとダメな機能。
PRを出したタイミングで自動的にバックエンドが構築され、マージされると自動的に削除される。

![pr_preview.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379/3cbc5330-6cf4-9a73-dd00-6c954549798d.png)

# 補足

バックエンドを自動構築できても、ストレージの中身は自分で用意してやる必要がある。

# 参考

[AWS Amplify Console 概要](https://aws.amazon.com/jp/amplify/console/)
[AWS Amplify コンソールユーザーガイド](https://docs.aws.amazon.com/ja_jp/amplify/latest/userguide/welcome.html)
[Amplify Framework](https://aws-amplify.github.io/)
plotly に imshow が実装されたので早速触ってみた

# 概要
`plotly`に`imshow`が実装され、画像をプロットできるようになったので早速触ってみた

https://github.com/plotly/plotly.py/pull/1855

`imshow`のベースになっている`plotly.js`の Pull Request
https://github.com/plotly/plotly.js/pull/4289

# コード
```python
import plotly.express as px
import numpy as np
from PIL import Image

img = np.asarray(Image.open('dog.jpg'))
px.imshow(img)
```

# Jupyter 上でプロット

`plotly`に備わっているインタラクティブな機能が画像に対して使える

![demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185448/26ffabca-d241-7b91-6aaa-e932119503d5.gif)

# 気になった点
- ズームした際の遅延
Gitについての学び

#はじめに
こんにちは！プログラミングを学び始めてまもない学生です。
今日はGitについて学んだことを書いていきたいと思います。間違ってることもあると思うので、その場合はご指摘お願いします。

#Gitとは
Gitは簡単にいうと、プログラムなどの変更履歴を管理できるもののことです。Gitを使うことのメリットは編集管理ができるので、何かを変更した際その履歴が残るため、簡単に元に戻したりできます。

さらに、Gitはチームプロジェクトでも重宝されます。ローカルリポジトリで管理したコードをリモートリポジトリに送ることができ、それをチームメイトも管理することができるのです。

#Gitの主な操作
今回は実際にGitでチーム開発をする場面を想定しての操作を説明していきたいと思います。

##clone

```
$ git clone <URL>
```
この操作によってリモートリポジトリにあるコンテントを自分のローカルリポジトリに取り入れることができます。

##branch
Gitにはbranchというものがあり、そのbranchごとに作業を分けることができます。大きな作業になると何個もブランチを分けることになるので、自分のするべき作業のブランチにCheckoutすることになります。

##checkout
```
$ git checkout <ブランチ名>
```
これを行うことによって、作業するブランチの場所を変更することができます。

##commit
コードの追加、修正を行なったらcommitをしなくてはいけません。これは感覚でいうと、上書き保存のようなものです。このコミットをしないとリモートにプッシュすることができません。

```
$ git commit
```

##push

```
$ git push origin <ブランチ名>
```
とすることで変更を行なったブランチをリモートに送ることができます。ここでGit Hubでプルリクエストを行います。プルリクエストとは、この変更で良いかどうかを責任者にレビューしてもらうためのもので、ここで問題なければ責任者がそのプッシュをMergeして変更、追加したコードを取り入れます。
ちなみに、

```
$ git branch
```
と入力することによって、今のブランチの状況を把握することができます。
ブランチの前に*（アスタリスク）がついているものが、今作業しているブランチということです。

##pull
ここで終わりではありません！リモートでマージされたものを自分のローカルに取り込むには、Pullを使います。

```
$ git pull origin master
```
これを実行することで、リモートにある最新のコンテントを自分のローカルの中に取り込むことができます。


#さいごに
今回紹介したものはGit操作のほんの一部でしかありません。Gitで覚えておかないといけないものはまだまだあります！Gitはプログラマーなら絶対に使う場面が来るので勉強して損はありません。これからも一緒に頑張っていきましょう！ありがとうございました！
銀行マスタ検索API作成に関して

# 銀行マスタ検索API作成に関して

## フロントで外部APIを利用する場合：
●銀行 支店 マスタで使えそうなライブラリってあるの？
![スクリーンショット 2019-11-08 16.38.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274686/4c73a1c8-93b3-5bc2-1d28-94b994e27fe9.png)

上記で割りとよさそうな④を利用しようと思ったが、金融機関の候補例が20までが上限だったり色々デメリットもある。
上記で⑥を利用しようと思ったが、上記④のデメリットもカバーできるが個人運営というのが唯一引っかかる。

フロントで外部APIを利用するのは、急に使えなくなるといったことがどれくらいあるのか？
などの懸念もあり結果的にバックエンドで銀行マスタAPIを実装してフロントに渡す結論になった。

## バックエンドでAPIを実装する場合：
下記のサイトからマスタのCSVをダウンロードし、CSVをDBに取込する。
http://ykaku.com/ginkokensaku/index.php
上記サイトの『＜全データダウンロード・zip形式＞リンクよりzipファイルをダウンロード後、解凍しCSVをDBに取込する。
上記のサイトのデータは更新タイミングはルールがなく、
http://ykaku.com/ginkokensaku/ment.html
１ヶ月に３回の時もあれば、更新がない月もあるので、更新周期（月１回）と決めて自動更新を行うようにバッチを実装する。

## 銀行マスタ検索用API実装
●検索画面イメージ
![スクリーンショット 2019-11-08 16.58.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274686/c96a055b-b537-6d85-2837-121714fff4ce.png)


●APIのroot:

    メイン銀行API:
    Route::any('/bank/{keyWord}', 'ApiBankController@getBank');
    銀行API:
    Route::any('/main/bank', 'ApiBankController@getMainBank');
    支店検索API:
    Route::any('/branch/{bankCode}/{keyWord}', 'ApiBankController@getBranch');

●フロントに渡すAPI(例：先頭が「み」の銀行のみ)
検索時はPGで平仮名をカタカタに変換してからDBのカタカタを検索対象にして検索を行う。
①銀行検索用
![スクリーンショット 2019-11-08 17.04.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274686/70d0327d-f8b1-4111-17bc-6bb4815e941c.png)

②支店検索用
![スクリーンショット 2019-11-08 17.06.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274686/774d1057-a141-d37c-e83f-a8e5c54d0f44.png)

## 参考サイト
http://ykaku.com/ginkokensaku/index.php
https://qiita.com/yuki_chrono/items/f03ce8b4036390927d86
https://bankcode-api.appspot.com/
https://bank.teraren.com/
SSLとドメインの期限をプログラムで取得した話

# SSL

## PHPで取得

ソース丸パクリで動きました。
https://qiita.com/hondy12345/items/7d493b8544f9eb2cd747

## わかったこと

- 期限が切れてる場合も取得できる
- 証明書のドメインが正しい場合、自己証明書でも日付は取得できる。証明書のドメインが違う場合は日付は取得できない。
  - 自己証明書の場合は注意が必要
- ドメインが無効の場合は例外が発生する

# ドメイン

## PHPで取得

execでwhoisを叩きました。
`exec('whois ' . $domain, $results);`

## whoisのバージョンに注意

dockerでやるとwhoisのバージョンは5.2.17でしたが、
CentOSでyumでinstallすると5.1.1になります。
5.1.1では新しいドメインに対応しておらず、また.comなどの結果が途中で切れてしまいます。
ですので、新し目のwhoisを入れる必要があります。
dockerと同じ5.2.17を入れる場合はソースからビルドしてください。
※5.2.11を試しましたが、新しいドメインに対応してなかったので5.2.17でいいと思います。

### whoisをソースからビルド

gitから好きなバージョンをwget
https://github.com/rfc1036/whois

解凍して、cdしてmakeするとperlのautodieで怒られるかと思います。
yumでperl-autodie.noarchをinstallすれば大丈夫です。

また、そのままmakeすると日本語ドメインに対応しないため、
`yum install libidn-devel`
の後、設定値を加えてmake
`make all HAVE_LIBIDN=1;`

OKならmake install。

## 連続してwhoisをすると20回で止められるのでsleepで5秒待つ

whoisサーバには連続接続に制限があるようです。
これを回避するにはsleepで5秒待つとイケました。

## 結果の解析

whoisの結果文字列を解析して、ドメインが無効かどうか、有効の場合は期限を取得します。
トップレベルドメインで結果が違うので、分岐します。

- .jp
  - あらかじめサーバでwhoisを試してみて、結果が日本語で出力されるか確認する。以下は日本語の場合です。
  - ドメイン無効の場合「No match!!」がある
  - 有効の場合は[有効期限]の行を探す。無い場合は[状態]の行を見る。
- .com、.net
  - ドメイン無効の場合「No match for domain」がある
  - 有効の場合は[Registrar Registration Expiration Date:]の行を見る。
- .info
  - ドメイン無効の場合「NOT FOUND」がある
  - 有効の場合は[Registry Expiry Date:]の行を見る。
- .biz
  - ドメイン無効の場合「No Data Found」がある
  - 有効の場合は[Registry Expiry Date:]の行を見る。
- .organic
  - ドメイン無効の場合「NOT FOUND」がある
  - 有効の場合は[Registry Expiry Date:]の行を見る。
- .work
  - ドメイン無効の場合「This domain name has not been registered.」がある
  - 有効の場合は[Registry Expiry Date:]の行を見る。

## RDAP

早く使えるようになってほしい。
rails 発展その4 アソシエーション

モデルを跨いだデータの呼び出しができるようになります。

ユーザー情報と商品情報などは別テーブルで保存されてることがあり
簡単なコードで呼び出せるようにするコードのこと

```ruby:app/models/user.rb
  class User < ApplicationRecord 
    has_many :items
  end
  # ユーザーにたいし複数のアイテムがある時などは　has_manyで定義
```

```ruby:app/models/item.rb
  class Item < ApplicationRecord 
    belongs_to :user
  end
  # こちらは逆にアイテムにたいしユーザーは一人だけなのでbelongs_toと定義
```

htmlやコントローラーでの使用の場合は

```ruby:controller
    def show 
      @items = current_user.items
      #これでユーザーからアイテムの情報を全て持ってきます。
      @item = current_user.items[0]
     #上記に続いて特定のidの情報だけ取り出します。
      @user = item.current_user
      #belongs_toと定義されてるのでこれだけでユーザー情報を持ってきます。　
    end
```
GitHubでgit操作するときはhttpsの方が９９９９９９倍楽

# 概要

今まではsshを使用しており、リポジトリを作るたびに~/.sshフォルダに入りssh-keygen -t rsaして鍵を作り、configを書きリポジトリに鍵を登録するところまでやってから開発していました。

ですが、どうやらGithubにおいてはhttpsがいつのまにか主流になっていたようです。

参照: https://help.github.com/ja/github/using-git/which-remote-url-should-i-use

というわけで、https時代のgit操作についてメモしておきたいと思います。

## clone

Githubのcloneボタンからurlをコピペしてclone。

sshならば切り替える必要がありますが、httpsならデフォなのでそのままコピペでおｋです。

基本はこれでOK、pushするときに最初だけパスワード入力が必要だったはず

詳しくは多分ググれば出てくると思います

## git操作ユーザを明示的に切り替えたい場合(会社用、私用などで分けているパターン)

コマンドを打てばユーザを指定できる。

```
git remote set-url origin https://git操作したいユーザ名@github.com/ユーザ名/リポジトリ名.git
```

example

```
git remote set-url origin https://Ancient-Scapes@github.com/Ancient-Scapes/prettier-plugin-svelte.git
```

## 参考

[gitでpushしようとしたら403された話](https://qiita.com/ritukiii/items/0d14df8f0253ca223373)

こちらを参考にさせていただきました！ありがとうございます！
文字列リテラルはその都度オブジェクトが生成される

#  文字列リテラルはその都度オブジェクトが生成される

```ruby
colors = { 'apple' => 'red', 'banana' => 'yellow' }

colors.each do |key, value|
    puts value if key == 'banana'  
end  

=> yellow
```

のような処理を行いたい場合、'banana'オブジェクトが繰り返し処理が行われるたびに生成されてしまい、無駄である。

```ruby
'banana'.object_id
=> 70183968739080
'banana'.object_id
=> 70183956909760
'banana'.object_id
=> 70183956844260

# 全て異なるオブジェクト
```

#シンボルはオブジェクトがその都度生成されない。

```ruby
:banana.object_id
=> 3021148
:banana.object_id
=> 3021148
:banana.object_id
=> 3021148

# 全て同じオブジェクト
```

そのため、ハッシュのキーをシンボルにすればオブジェクトが毎回生成されず、無駄をなくすことができる。

```ruby
colors = { apple: :red, banana: :yellow }

colors.each do |key, value|
    puts value if key == :banana
end  

=> yellow
```
初耳用語に対応する方法  新米エンジニアに向けて

最近はNode.jsばっかり触っている３年目エンジニアの松田です。
３年目にもなり、二ヶ月前から後輩のメンターをしています。

その後輩くんに「WebAPIってなんですか？？？」と聞かれ、、、
そういえば2年前の自分も同じことでかなり悩んでたなぁ...
と思ったので、まとめることにしました。

せっかくなので、ただ内容をまとめるだけでなく、
普段、どのようにキャッチアップ/学習をしているのかも一緒に書きます。
少しでも新米エンジニアの方にキャッチアップ方法が届けば幸いです。

## 日本語にしてみる
本題に入る前に、私が未知の英単語？にあった場合にやっている(いた)こととして、
まず単語を日本語に訳すところから始めています。
いきなり、単語をググるのではなく、日本語にしてどのような機能なのかあたりをつけてから調べています。

最初は、日本語に訳してもなんじゃらほい状態だと思います。特にWebとかAPIとか...。
慣れてくると、抽象的なことを学ぶ際にイメージしやすくなり、理解するまでがかなり近道になるので、是非試してみてください。
(先輩エンジニアの皆さん。そうですよね？？？)

ということで早速、訳していきましょう。

## Q： APIって？

A： API (アプリケーション・プログラミング・インタフェース )のこと

### アプリケーション・プログラミング・インタフェースって？

A： アプリケーション・プログラミング(アプリ)のインタフェース(境界線)
(日本語にしてみようとか言いつつ、日本語化が難しすぎ...)

### インターフェースとは境界である

インタフェースという言葉を日本語に直訳すると、`接点`とか`境界`とか出ると思います。
ちょっとイメージがつきにくいかもしれないので、別の言葉で説明すると
`ユーザインタフェース`とか`オーディオインタフェース`だとイメージが付きやすいですかね。

`ユーザインタフェース`はユーザと機械の接点/境界で、人(ユーザ)がコンピュータに指示を伝える、ものの総称のことで、例えば、リモコン(人の指示をTVに伝えるための接点)やアプリのボタン(人の指示をアプリに伝えるための接点)、キーボード(人の指示をコンピュータに伝えるための接点)です。

`オーディオインタフェース`は言わずもがな、オーディオ機器に対しての接点の総称で、ギターとアンプを繋ぐシールドや、マイクとパソコンを繋いでいるゴツゴツした機器がオーディオインタフェースです。

### 改めて、アプリケーションプログラミングインタフェースとは？？？
アプリケーションプログラミング、要はプログラムがそれ同士と接続する部分の接点/境界のことです。
`Java API ドキュメント`とか聞いたことはありませんか？
それは、自分が書いたプログラムとJavaのSDKが持っている機能、例えば、日付を処理するものとの接点/境界のことです。

プログラムはあくまで人が書いた処理なので、接点/境界も人が定義し、いろんなプログラムがアクセスできるようにしないといけません。
これは`ハードウェアインタフェース`をイメージすると分かりやすいですかね。
USBのインタフェースはUSBの規格に合わせたものでないと使用できませんし、
SDカードのインタフェースはSDカードしか刺さらないし、使用できません。

プログラムも一緒で接点（プログラムの入り口）を定義しないと使う側は使えないのです。
Javaを使う人向けにプログラムの入り口を定義した内容がまとまっているドキュメントが`Java API ドキュメント`です。
上記のような背景があり、`API`は`仕様書`と言った意味を含んで使用する方もいます。

最近はAPIと調べると、後述する`WebAPI`ばかりがヒットすると思いますが、APIの本来保つ意味は上記なんですよ。
（どやってますけど、あってますよね？？？）

日本語で調べると、いきなりググるより本来持つ意味がわかりやすかった気がしませんか？

## Q： Webって？

A：WWW(World Wide Web)のこと  
(これこそ日本語にできない...)

直訳すると、世界に広がるWebなんですが、
じゃあ「Webとは？」と気になると思うのですが、端的にいうと、
「それぞれの文章が網目上に繋がった情報網」という意味です。
いわゆるホームページのような文章が世界中の仮想文献（ホームページ）と繋がっていることをイメージしてもらえればと思います。
また、それを可能にするシステムの仕組みやルールだと思ってもらえれば、ここでは十分です。

※ （私があまり理解できていないこともあり）この辺りの詳細な解説を知りたい方は、Webの生い立ちとか歴史を調べてみると、Webがどういうものとして生まれてきたのか理解できると思います。この周辺の説明はそういった記事や文献にお任せします。。。

### その仕組みやシステムの生い立ち・歴史を調べてみる

今回は記事が冗長になるので書きませんが、昔からある仕組みや概念の勉強する際には、生い立ちや歴史を調べることは結構有効だと思っています。その言葉がどういった`背景`で生まれてきたのかを知ると理解度が深まるのではないかと思います。 

なので、私が何かの概念や調べてもあまり分からないことは、少し文章多めの歴史から学べる記事や、本を読むようにしています。
特にWebやインターネットは私が生まれた時ぐらいからある技術なので、ながーい歴史があり、どういう時代背景があって生まれたものなのか、知ることで理解しやすくなるかなと思います。

ちなみに、私は[Webを支える技術](https://gihyo.jp/magazine/wdpress/plus/978-4-7741-4204-3)という書籍を読んで理解しました。

## Q：WebAPIって？

A； WWWを可能にする仕組みや技術を用いたプログラム同士が接続する部分の接点/境界

と私は思っています。  
これ以上説明するとあまりに長くなるのですが、
Webについて掘り下げなかったため、中途半端な理解になってしまったかもしれません、、、。  

Webとはどう言った仕組みなのか、どのような歴史で出来上がってきたのか、
というのを調べてみるとより理解が深まると思います。

## 最後に

いかがだったでしょうか。  
APIの理解というより、未知の単語との向き合い方や考え方が伝われば私は満足です。
plantuml-encodingを使ってPHPでPlantUmlする

## 概要

[PHP で API クライアントを実装する](http://plantuml.com/ja/code-php) を参考に、[plantuml-encoding](https://packagist.org/packages/jawira/plantuml-encoding)を使用してPlantUMLのコードを圧縮文字列にする変換をPHPで行う。

**最終目的: PlantUMLのコードをテキストとして実データで保持しつつ(git管理しつつ)、図は自動で更新され、かつ閲覧のみならば簡単に行える環境を探す**

## try
### 環境
PHP実行できる環境。
今回はdocker-composeで用意。

```:最初のディレクトリ構造
project/
　├ docker-compose.yml
　├ docker(dockerfileなど入ってる)
　├ public/
　　　└ index.php/
```

### jawira/plantuml-encoding

composerで入れる

```bash=
$ composer require jawira/plantuml-encoding
```

### とりあえず実行してみます

[参考](http://plantuml.com/ja/code-php)のサンプルコードを少し変えてみました。

```php:index.php
<?php
require '../vendor/autoload.php';
use function Jawira\PlantUml\encodep;
$encode = encodep('
    Alice -> Bob: hello
');
$svg = file_get_contents("http://www.plantuml.com/plantuml/svg/{$encode}");

echo $svg
```

`encodep()`関数でエンコードを行います。
生成した圧縮文字を用いてPlantUML Serverからsvgを取得し、それをそのまま画面に出します。

![スクリーンショット 2019-11-07 9.58.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489139/eefd3ceb-5bd4-993c-3a3c-8b32a80fc93c.png)


### PlantUmlを別ファイルに記述する

```:./umls/test.puml
@startuml
Alice -> Bob: hello
@enduml
```

```php:index.php
<?php
require '../vendor/autoload.php';
use function Jawira\PlantUml\encodep;

$uml = file_get_contents('../umls/test.puml');
$uml = str_replace('@startuml', '', $uml);
$uml = str_replace('@enduml', '', $uml);

$encode = encodep($uml);
$svg = file_get_contents("http://www.plantuml.com/plantuml/svg/{$encode}");

echo $svg;
```

別のファイルにUMLを記述して読み込みます。
エディタのパッケージで開発中にプレビューを行うには`@startuml`と`@enduml`の記述が必要なのですが、エンコード時には取り除きます。

## おわり
フレームワークなど使って.pumlファイルを保存する作業ディレクトリ内の内容が、そのまま図として表示が出来るようにしたら便利なんじゃないかなと思いました。
Vue.jsでEditor.jsプラグインを使いたい

# Vue.jsでEditor.jsプラグインを使いたい

## メモ
家に帰ったら正式なやつ書く
取り敢えず導入まで

### インストールする

```
$ npm install @editorjs/editorjs
or
$ yarn add @editorjs/editorjs
```

### 呼び出す

```vuejs
<template>
  <div class="hoge">
    <div id="codex-editor" />
  </div>
</template>

<script>
import EditorJS from '@editorjs/editorjs'

export default {
  data() {
    return {
      editor: {}
    }
  },
  methods: {
    // Editor.js関連
    doEditor() {
      this.editor = new  EditorJS({
        holder: 'codex-editor',
      })
    }  
  },
  mounted() {
    this.doEditor()
  }
}
</script>
```
【UiPath】「アプリケーションを開く」でPowerpointが開けない

#1.事象
UiPath Studioにて、「アプリケーションを開く」アクティビティを使用し、PoworPointを開くワークフローを作成し実行したところ、アプリケーションへのアクセス権が無いというエラーメッセージが出力された。

#2.環境
- Windows 10 Pro 
    - バージョン1809(OSビルド 17763.805)
- Microsoft Office 2016 Home and Business 2016 
    - バージョン1910(ビルド 12130.20272 Microsoft Store)

#3.対応方法
下記の手順を実施したところ無事に起動した

- 「アプリケーションを開く」アクティビティのプロパティ「ファイル名」に、対象アプリケーションのAUMIDを設定
    - PowerPointのAUMID："Microsoft.Office.Desktop.8wekyb3d8bbwe!PowerPoint"  
- セレクターの再設定

#4.調査したこと
- 「アプリケーションを開く」アクティビティのプロパティ「ファイル名」を確認
    - 設定値："C:\Program  Files\WindowsApps\Microsoft.Office.Desktop.PowerPoint_16051.12130.20272.0_x86__8wekyb3d8bbwe\Office16\POWERPNT.EXE"
    - アクセス権を確認したところ、Usersは条件付きで「読み取りと実行」が許可されていた
-  スタートメニュー経由からなら起動できることから、ショートカットに仕掛けがあると考え、ショートカットのリンク先を調査
    - 設定値："Microsoft.Office.Desktop.8wekyb3d8bbwe!PowerPoint"
- 設定されている値がAUMIDであることを確認できた

#5.その他
- MicrosoftStoreアプリ(UWPアプリ)がインストールされているフォルダ配下に対して、Usersは直接アクセスする権限がないため、「アプリケーションを開く」アクティビティを使用する際はプロパティの値に注意が必要
- しかし、OneNoteに関しては最初からAUMIDが設定されていた
- UiPathのバグかもしれません。今後の対応に期待します。
プログラムに書くコメント各種



```java:java
//　一行だけがコメント
/*　この間の文字は
すべてコメント*/

/**　 Javadocコメント
* 　　エンターを押すと
*　 　行とアスタリスが自動で追加される
*　  @author	クラスの作成者情報を記載
*    @param	メソッドの引数の説明
*    @return	メソッドの返り値の説明
*    @throw	発生する例外クラスを指定
*    @see	他のAPIを参照する場合に記載
*    @deprecated	推奨されないAPIであることを示す
*    @serial	直列化されたフィールドの説明
*    @sesrialData	直列化された状態でのデータ型と順序を記載
*    @since	導入されたバージョンを記載
*    @version	バージョンを記載
*/
```


```html:html
<!-- この間の文字がコメント-->
<!-- この間の文字が
すべてコメント-->

//　コメントにはならない
/*　コメントにはならない*/
```
```css:CSS
/*　この間の文字がコメント　*/
```
```Python:python
#一行コメント
'''
シングルクォーテーション
3つでで囲んだ文字がコメント
'''
Azure Synapse Analytics についてまとめてみた

##はじめに
Microsoft Ignite 2019 にて、Azure の新サービスが数多く発表されました。
そのうちの1つ **Azure Synapse Analytics** を紹介元の記事を翻訳しながら概要をまとめていきます。

翻訳元の記事
■[Simply unmatched, truly limitless: Announcing Azure Synapse Analytics](https://azure.microsoft.com/en-us/blog/simply-unmatched-truly-limitless-announcing-azure-synapse-analytics/)


他の Azure 新サービスまとめ
■ [Azure Arc についてまとめてみた](https://qiita.com/Yoshiyuki03/items/99a6c42e5f24085da14b)

## 概要
**Azure Synapse Analytics**は、エンタープライズデータウェアハウスと、ビッグデータ解析をまとめる、制限の無い解析サービスです。ユーザはオンデマンドで実行できるサーバレス環境と、既存のリソース環境のどちらに対しても、**大規模データへのクエリ発行**が可能です。

Azure Synapse Analytics はこれら2つの環境を統合し、機械学習やBIツールでの分析要請に対して、解析データの取り込み、準備、加工、抽出を行うことができるプラットフォームを提供します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321349/4235945f-c1dc-d8ac-ae84-7da47be36b20.png)

Azure Synapse Analytics は **次世代の Azure SQL Data Warehouse** と言えます。データウェアハウスを全く新しいレベルのパフォーマンスと能力に押し上げました。

> 補足:
コンソールを見ていただくとわかるのですが、**SQL Data Warehouse** をすでに使用している場合、名称が Azure Synapse Analytics に変わっています。使用側としては、**新機能が追加され、名称が変わった**、という理解で良いかと思います。

このサービスは**ペタバイト規模**で全ての TPC-H クエリを実行できる環境を持つ唯一の解析システムです。Azure Synapse Analytics を用いることで、既存のデータウェアハウスのワークロードを継続しつつ、新しいキャパシティを持つサービスの恩恵にあずかることができます。

これにより、すべてのデータソース、データウェアハウス、ビックデータ解析システムから、**より早く、生産的に、セキュアに、同時にインサイトを得る**ことができるようになります。

Azure Synapse Analytics は以下のパートナーと豊かで活気のあるエコシステムを構築することで、パートナーとの共同開発を続けることができます。

- Databricks
- Informatica
- Accenture
- Talend
- Panoply
- Attunity
- Pragmatic Works
- Adatis


Azure Synapse Analytics では、あらゆるタイプのデータ専門家が、同じサービス内で最も重要なデータを簡単に共同作業し、構築し、管理し、分析することができます。Azure Synapse Analytics は、強力で信頼できる SQL エンジンをもつ Apache Spark の機構構築から、コード不要機構の構築やマネージメントまで、すべてのデータプロフェッショナル向けに構築されています。これが、Azure Synapse Analytics がユニリーバなどの企業にも選ばれる理由です。

>Nallan Sriraman
ユニリーバ、テクノロジー担当グローバルヘッド

>「Azure Synapse Analytics プラットフォームの採用で、我々のビジネスにinsightsを導入する力は格段に進化した。Azure Synapse Analytics が、我々の解析プロセスをシームレスなインテグレーションによって、より合理的なものになることを期待している。」

<br>
> 補足： TPC-Hクエリは、リレーショナルデータベースのベンチマーク仕様の一つ。正規化されていない複数のテーブルにまたがった集計を行うクエリで、負荷の高いクエリに耐えられるデータベースかをチェックできる

## 特徴

#### Limitless Scale
- データウェアハウスとビッグデータ分析システム全体から**非常に高速に洞察**を得られる
- **ペタバイト規模**でリレーショナル・非リレーショナル両方のデータへ SQL でクエリ発行
- すべてのクエリのパフォーマンスを**簡単に最適化**

#### Powerful Insight
- Power BI と Azure Machine Learning と緊密に統合
- Dynamics 365、Office 365、Open Data InitiativeのSaaSサービスに至るまで**シームレス**に数クリックで**データをシェア**
- インテリジェンスを適用・簡単に共有できることで、**機械学習プロジェクトの開発期間を大幅に削減**

#### Unified Experience
- **統一された使用感**を備えたエンドツーエンドの分析ソリューションを構築 
- Azure Synapse Studioで、データ準備、データ管理、データウェアハウス設計、ビッグデータ、AIタスクのための**統合ワークスペース**を提供
- データエンジニアは、コードなしのビジュアル環境を使用して、データパイプラインを管理
- データベース管理者は、クエリの最適化を自動化
- データサイエンティストは、数分で概念実証を作成
- ビジネスアナリストは、同じ分析サービスを使用しながら、データセットに安全にアクセス、Power BIでダッシュボードを数分で構築

#### Unmatched security
- Azure はマーケットにおいて**最も優れたセキュリティとプライバシー**機能を有する
- **行レベル・列レベル**のセキュリティ
- Dynamic Data Masking でリアルタイムで**重要データを自動的に保護**し、データを安全に利用


##おわりに
Azure Synapse Analytics についての紹介は以上となります。
この他にも様々な新サービスが発表されたので、別途記事にまとめて紹介していきます。
Growiの挙動まとめ

# バージョン

GROWI 3.2.7-RC

# IP制限

## 80番ポート

apacheからリバースプロキシでやっているので、
vhosts.confに追加

```
<VirtualHost *:80>
    ServerName growi.example.com
    ProxyPass / http://growi.example.com:3000/
    ProxyPassReverse / http://growi.example.com:3000/
    <Location />
        Require all denied
        Require ip xxx.xxx.xxx.xxx
        Require ip xxx.xxx.xxx.xxx
    </Location>
</VirtualHost>
```

## 3000番ポート

nodeが動いているのでnodeで制限した。

参考：http://dotnsf.blog.jp/archives/1066182158.html

```
npm install express-ipfilter
```

※インストールするとなぜか他のモジュールが削除された。yarnするとなおった。

src/server/crowi/express-init.js

```
    , Config = crowi.model('Config')
    , User = crowi.model('User')
    , ipfilter = require('express-ipfilter').IpFilter  // 追加
    ;

  var ips = ['127.0.0.1', 'xxx.xxx.xxx.xxx'];  // 追加
  app.use(ipfilter(ips, {mode: 'allow'}));  // 追加

  const lngDetector = new i18nMiddleware.LanguageDetector();
  lngDetector.addDetector(i18nUserSettingDetector);
```

```
systemctl restart growi
```

nodeにapache経由でアクセスするとプロキシなのでIPがサーバのIPになっている。
それを利用して、サーバのIPのみ許可することでapache経由でのみアクセスできるようにした。

http://xxx.xxx.xxx.xxx:3000/
Forbiddenになる。

# ログインしてない人に閲覧のみ許可する設定をした場合

公開範囲がpublicの記事がすべて閲覧可能になる。
※Anyone with the linkの記事はリンクを教えても見れなかった。

# Anyone with the linkの挙動

上記にも書いたが、

- ログインしてない人
  - 見れない
- ログインしている人
  - トップページの一覧には無いが、直リンから見れる
【Python中級者への道】__call__でクラスインスタンスを関数のように呼び出す 


# まとめへのリンク

https://qiita.com/ganariya/items/fb3f38c2f4a35d1ee2e8

# はじめに

Pythonの勉強をするために、[acopy](https://github.com/rhgrant10/acopy)という群知能ライブラリを写経していました。

acopyでは、多くのPythonの面白い文法・イディオムが使われており、その中でも便利だなぁというのをまとめています。


今回は、クラスのインスタンスを関数のように呼び出す`__call__`属性についてみてみます。

# `__call__`属性メソッド

`__call__`属性をクラスに定義すると、
インスタンスを`()`演算子で関数のように呼び出すことができます。

```py
class Person:

    def __init__(self, age, name):
        self.age = age
        self.name = name

    def __repr__(self):
        return f'age = {self.age}, name = {self.name}'

    def __call__(self, *args, **kwargs):
        return self.name


'''
age = 20, name = ron
ron
'''
p = Person(20, 'ron')
print(p)
print(p())
```

以上の例では、Personクラスに`__call__`属性が定義されています。
これによって、関数呼び出しのようにインスタンスが呼び出されると、pの名前を返します。

このように、関数のように呼び出せるようにするのが、`__call__`です。

# 活用例

それでは、この`()`を使うとどう嬉しいことがあるのでしょうか？

## 単純なインターフェース

あまりするべきで無い気がしますが、単純なインターフェースとして
使用できるのかなと思います。

```py
class Add:

    def __init__(self, x):
        self.x = x

    def __call__(self, y):
        return self.x + y


class Sub:

    def __init__(self, x):
        self.x = x

    def __call__(self, y):
        return self.x - y


'''
20
10
50
'''
arr = [Add(10), Sub(20), Add(40)]
for ice in arr:
    print(ice(10))

```

なんか違う気がしますね。

## 関数に状態をもたせる

主にこれの意味があるのかなと思います。
C++では、structに`()`を持たす関数オブジェクトというものが存在します。
それについて触れた自分の記事です。([俺のunordered_mapがこんなにpair型をキーにできないわけがない](https://qiita.com/ganariya/items/df35d253726269bda436))


関数には状態を持たせづらいですが、クラスには状態を簡単に持たすことができます。
すると、`()`演算子の使用回数や、重い処理のDPのような計算結果の取得などが可能になります。

```py
class Count:
    cls_count = 0

    def __init__(self):
        self.count = 0

    def __call__(self, *args, **kwargs):
        self.count += 1
        Count.cls_count += 1
        return self.count, Count.cls_count


c1 = Count()
c2 = Count()

'''
(1, 1)
(1, 2)
(2, 3)
(3, 4)
(2, 5)
'''
print(c1())
print(c2())
print(c1())
print(c1())
print(c2())
```

以上のコードでは、Countクラスを作り、それを関数呼び出ししています。
内部で`cls_count, count`という変数・内部状態を保存しています。

以上は適当な例ですが、`()`という関数呼び出しに内部状態を保存することができます。

また、以下はエラトステネスの篩を関数呼び出ししています。
一回計算したあとは、内部キャッシュした値を返しています。

```py
class Era:

    def __init__(self, N):
        self.N = N
        self.primes = []
        self.ready = False

    def __call__(self, x):
        if self.ready:
            return self.primes[x]
        else:
            self.primes = [True] * (self.N + 1)
            self.primes[0] = self.primes[1] = False

            i = 2
            while i * i <= self.N:
                if self.primes[i]:
                    for j in range(i * 2, N + 1, i):
                        self.primes[j] = False
                i += 1
            return self.primes[x]


N = 100
era = Era(N)

for i in range(0, N + 1):
    print(i, era(i))

```

このように、外部からは`()`で関数のように呼び出したいですが、内部状態をもたせたいときは、`__call__`を使用すると良さそうです。


# 参考文献

- [__call__メソッドについて](http://alexei-karamazov.hatenablog.com/entry/2013/12/31/09595)
- [__call__ と callable がよくわかんなかった話](http://atasatamatara.hatenablog.jp/entry/20120817/1345162948)
XcodeでMarkdownファイルをプレビュー表示する

XcodeでMarkdownファイルをプレビュー表示することができます。

![スクリーンショット 2019-11-08 16.27.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37634/9f41c1ff-0584-6417-0998-72f07023988b.png)

↑このような感じです。

[XcodeでMarkdownを利用する](https://qiita.com/Arime/items/4a1f90b3b5cea4b63327)

↑の記事に詳しいのですが、時々どうするんだっけ？となるので、スクリプトファルを書いてみました。

```bash:Script
#!/bin/sh

array=`find . -name *.xcodeproj -type d`
for dir in $array; do
   echo $"enable markdown preview on "$dir" (y/N): "
   read -n1 -p "" yn; if [[ $yn = [yY] ]]; then touch $dir/.xcodesamplecode.plist; else echo skiped; fi
done

```

カレントディレクトリー以下の `*.xcodeproj` を見つけて、
`enable markdown preview on "$dir" (y/N): `
と聞いてくるので、`y`を入力すれば、
プロジェクト（.xcodeproj）以下に、 `.xcodesamplecode.plist`を作成します。

複数のプロジェクトを含んだ上位のディレクトリーから実行すると、下位に含まれる全てのプロジェクトで`.xcodesamplecode.plist`を作成するかどうかを聞いてきますので、ご注意ください。

Appleのサンプルコードの場合は、下記のような内容になっているようですが、空でも動作するということなので、現状は空のままです。

```xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array/>
</plist>
```
「GoogleDrive」リンク固定でコンテンツ更新をする方法

#きっかけ
web制作をしている中で、クライアントから次のような要望がありました。
『PDFを自分でアップロードして、自社サイトに表示させたい！』
初めはなんだ投稿機能でいいのねと思っていましたが詳しく聞いてみると

・投稿をより簡単に（wp管理画面はむずかしい）
・最新1件を直接表示したい
・自分たちだけの力で

とのことでした。

WordPressを使わず、もちろんサーバー等を触ることもできないとなると、
他に管理する方法として、Googleドライブを思いつきました。

#Google Driveの共有
<img width="1440" alt="スクリーンショット 2019-11-08 15.51.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307320/f2bb50f3-2f2f-a05c-a797-d27c13cbc645.png">

GoogleDrive上でファイルを右クリックし、共有設定を行うと公開範囲と権限が選べるので、
「全員が閲覧可」にすることで、誰もが閲覧のみできる状態になります。

そしてそのリンクをコピーし、aタグに乗せれば一応機能します。

https://drive.google.com/file/d/19s71JQnx19-quttxT21qn56tIrCUaS1n/view?usp=sharing

#本題
GoogleDriveでの共有リンクは簡単でしたが、このままではどれだけフォルダに新しいファイルを入れようとも、aタグのリンク先には最初のファイルしか表示されません。

そこで邪道ではありますが、新たに投稿したいファイル名を旧ファイルと同じにし、新バージョンとして保存しました。

<img width="1440" alt="スクリーンショット 2019-11-08 16.13.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307320/715abb73-5e66-bf80-a801-6be29e02c8f0.png">

これで新しいファイルもtest.pdfとして扱われ、リンクもそのままです！

<img width="1440" alt="スクリーンショット 2019-11-08 16.15.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307320/0c122531-d576-f788-b624-debf9112fdcf.png">

さらにGoogleDriveではバージョン管理も可能なため、間違ってアップロードしたり、過去のファイルが欲しい場合には簡単にダウンロードができます。
<img width="1440" alt="スクリーンショット 2019-11-08 16.19.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307320/e76e2476-f419-f31d-d8d3-81c20ca975b1.png">
#終わりに
同一タイトルでなければならないという制約は少しあるものの、これならクライアントの方もなんとか更新可能かと思います。

このように使う機会はほとんどないかと思いますが、個人的に活用していただけたら嬉しいです、、

GoogleDriveフォルダ内の最新1件のリンクを取得とかしたかったんですが、ファイルIDとやらがなかなか取れず諦めました（泣）
どなたかご存知であればお教えください。
[ Android ] [ localization ]　言語切替4

今回も言語切替について記す。

前回記事でほとんど綴っているので、ポイントのプログラムのみ解説する。
https://qiita.com/QiitaD/items/e26287727e067cd98a1f

##initialize()
以下のようなプログラムを前回のプログラムに加えることで、表示切替ができる。
（変数名は変えているので注意していただきたい）

~~~java
        button.setOnClickListener((View view1)->{
            Context context2 = MyContextWrapper.wrap(newBase2, newLocale);
            //付け加え
            if (isLocaleJp(context2)){
                newLocale = Locale.ENGLISH;
                textView2.setText("こんに");
                button.setText("英語表示");
            } else {
                newLocale = Locale.JAPAN;
                textView2.setText("He");
                button.setText("in Japanese");
            }
        });
~~~

動作としては目標を達成できたが、
私が作りたかったものはOSの言語を切替え、それに伴い表示を切替えるプログラムである。
上記ではvalues-jaフォルダやMyContextWrapperの存在価値が無くなっている。
作りたいプログラムは作れなかったが、試行錯誤の結果を下に記す。

##試したこと

前回のMainActivity.javaを少し弄ったファイルを見て頂きたい。

~~~java
public class MainActivity extends AppCompatActivity {

    static MainActivity mainActivity;
    Context newBase2 = null;
    Locale newLocale = Locale.ENGLISH;
    Locale locale2 = null;

    //ロケール初期化、onCreateより前に一度だけ呼び出せる
    @Override
    protected void attachBaseContext(Context newBase) {
        //省略
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mainActivity = this;
//        newBase2 = MainActivity.mainActivity.getApplicationContext();
        setContentView(R.layout.activity_main);
        initialize();
    }

    //onCreate内から呼び出される
    private void initialize() {
        Button button = findViewById(R.id.button);
        TextView textView2 = findViewById(R.id.textView2);
        button.setOnClickListener((View view1)->{
            Context context2 = MyContextWrapper.wrap(newBase2, newLocale);
            if (isLocaleJp(context2)){
                newLocale = Locale.ENGLISH;
                textView2.setText("こんに");
//                button.setText("英語表示");
            } else {
                newLocale = Locale.JAPAN;
                textView2.setText("He");
//                button.setText("in Japanese");
            }
        });
    }

    //initialize()内から呼び出される、contextが日本語か判定
    static boolean isLocaleJp(Context context){
        //省略
    }
}
~~~

attachBaseContext()はLocaleを英語に初期化する。
私のエミュレータは日本語に設定してあり、このメソッドにより英語の表示に切り替わっている。
このメソッドをコメントアウトすると日本語表示になるので、うまくいっていると言える。
しかし、initialize()でも同様にMyContextWrapperクラスのwrap()を呼び出しても、
表示を切り替えることができなかった。
この対策としてManifestに以下を追加してみたが変わらなかった。

~~~xml
<application
    android:configChanges="locale"/>
~~~
また**onConfigurationChanged(Configuration newConfig)**をオーバーライドして使ってみたが、依然うまくいかなかった。

まだ結論は出ていないが、SharedPreferencesを使った実装ならできるかもしれない。
以下がその参考になりそうだ。
・基本的な使い方
https://qiita.com/YAmi/items/3e5640f365277d70f255
・実装方法例
https://juejin.im/post/5ac8d62c518825557e78a514
SubVersionにリポジトリを作成

# 前提

- VirtualBox
- Debian10
- Bitnami Redmine(With SVN Git Mysql)

# やりたい事

- SubVersionに新規リポジトリを作成

## リポジトリを作成

1./home配下にsvnフォルダを作成して、所有者：グループを設定

```shell:command
cd /home
sudo mkdir svn
sudo chown -R daemon:daemon svn/
```

2.Bitnamiのapacheの実行ユーザー：グループを確認

```shell:command
cat -n /opt/[redmine]/apache2/conf/httpd.conf
# 174 User daemon
# 175 Group daemon
# になっているかを確認
# [redmine]は自分の環境に合わせてください
```

3.リポジトリを作成

```shell:command
cd /opt/[redmine]
sudo ./use_redmine
svnadmin create /home/svn/[myrepo1]
chown -R daemon:daemon /home/svn/[myrepo1]
# [myrepo1]は任意で決めてください
```

4.apacheにSVNのパスを設定する

```shell:command
sudo nano /opt/[redmine]/apache2/conf/httpd.conf
# LoadModule dav_svn_module     modules/mod_dav_svn.so
# LoadModule authz_svn_module   modules/mod_authz_svn.so
# 上記２つはコメントアウトを解除する
# ファイルの最後に下記の１行を追加
# Include "/opt/[redmine]/apache2/conf/extra/httpd-svn.conf"

# /opt/[redmine]/apache2/conf/extraに「httpd-svn.conf」を作成する
sudo nano /opt/[redmine]/apache2/conf/extra/httpd-svn.conf
# 中身は以下を参照
# [redmine]は自分の環境に合わせて変更してください
```

```text:httpd-svn.conf
<Location /svn>
    DAV svn
    # enable view for repositories parent directories
    #SVNPath "/home/svn"
    SVNParentpath "/home/svn"
    #SVNListParentPath On
 
    # read/write accesses force Basic auth
    AuthType Basic
    AuthName "Subversion repository"
    AuthUserFile /opt/[redmine]/apache2/conf/dav_svn.passwd
    Require valid-user
</Location>
```

※SVNListParentPathをOnの場合は「http://localhost/svn」で全レポジトリが見えます
SVNListParentPathがOffの場合は「http://localhost/svn/myrepo1」でmyrepo1が見えます。

5.パスワードファイルを作成してから、apache再起動

- dav_svn.passwdファイルの作成はhtpasswdを使う

```shell:command
sudo htpasswd -c /opt/[redmine]/apache2/conf/dav_svn.passwd [username]
```

apacheを再起動

```shell:command
cd /opt/[redmine]/
sudo ./ctlscript.sh restart apache
```

http://[localhost]/svn/[myrepo1]/にアクセスして
Basic認証が実施された後にRevision表示されればOK
※Basic認証は先ほどパスワードファイルを作成した時のユーザーと入力したパスワード
![subversion.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526027/be84e6bd-76c2-c614-e157-f490c5485f5e.png)
神記事まとめ

神記事の備忘録

## Git
[【GitHub超初心者入門】この前初めてGitHubを使い始めたエンジニア見習いが書くGitHubの使い方と実践～とりあえず一緒に動かしてみようぜ！～](https://qiita.com/nnahito/items/565f8755e70c51532459)
[【永久保存版】Gitのあらゆるトラブルが解決する神ノウハウ集を翻訳した](https://blog.labot.jp/entry/2019/07/01/183204)

## フロントエンド
[【保存版】Webフロントエンド基礎力（初心者向け）](https://qiita.com/teradonburi/items/43c52d7cffc318e9b1e9)

## Ruby
[[初心者向け] RubyやRailsでリファクタリングに使えそうなイディオムとか便利メソッドとか](https://qiita.com/jnchito/items/dedb3b889ab226933ccf)


## Rails
[Railsを支える基本概念の整理（RESTfulやリソースなど）](https://qiita.com/kidach1/items/43e53811c12351915278)
[【初心者向け】丁寧すぎるRails『アソシエーション』チュートリアル【幾ら何でも】【完璧にわかる】](https://qiita.com/kazukimatsumoto/items/14bdff681ec5ddac26d1)
[使えるRSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する」](https://qiita.com/jnchito/items/42193d066bd61c740612)
【Python中級者への道】独自クラスを比較演算を可能にする


# まとめへのリンク

https://qiita.com/ganariya/items/fb3f38c2f4a35d1ee2e8

# はじめに

Pythonの勉強をするために、[acopy](https://github.com/rhgrant10/acopy)という群知能ライブラリを写経していました。

acopyでは、多くのPythonの面白い文法・イディオムが使われており、その中でも便利だなぁというのをまとめています。


今回は、クラスのインスタンスに比較演算が行えるようにします。

# 比較演算

Pythonの組み込みデータ型には、比較演算が定義されています。

例えば、もちろんintクラスのインスタンスの数字は当然ソート・比較が可能です。

```python
'''
[-2, -1, 1, 2, 3, 5]
'''
a = [1, 2, 3, 5, -1, -2]
a.sort()
print(a)
```

以上のように、ソートが行え、当然「`<=`」などの演算子も使えます。

# 独自クラス

しかし、自分で作った独自クラスに関しては比較演算を行えません。
比較演算を行うために必要な特殊属性メソッド

- `__lt__` less than
- `__le__` less or equal
- `__eq__` equal
- `__ne__` not equal
- `__gt__` greater than
- `__ge__` greater or equal

が定義されていないためです。

そこで、これらの属性を自分で定義することで、クラスのインスタンスを比較・ソートすることができます。

# 実装してみる

```py
import functools


@functools.total_ordering
class A:

    def __init__(self, x):
        self.x = x

    def __repr__(self):
        return f"x = {self.x}"

    def __eq__(self, other):
        return self.x == other.x

    def __lt__(self, other):
        return self.x < other.x


'''
[x = 2, x = 3, x = 10, x = 20]
'''
arr = [A(10), A(20), A(3), A(2)]
arr.sort()
print(arr)
```

class Aには、`__repr__`属性が定義されていて、これによって、printを見やすくすることができます。

ここで、`__eq__`と`__lt__`が定義されており、これによって、他のインスタンス`other`との比較関係を表します。
`__lt__`の`self.x < other.x`は、相手より小さければTrueを返し、これ以上交換しなくて良い！というイメージになっています。


実は、`__eq__`と`__lt__`しか上のクラスには定義されていませんが、ちゃんと機能してくれます。
これは、functoolsのtotal_orderingというデコレータを使用することで、その他の比較メソッドを推測してくれるためです。

# まとめ

クラスに直接比較演算が行えるとソート、そしてもちろんif文などで便利です。
`__eq__`, `__lt__`のみ定義するだけで比較できるのは便利だなと感じました。
C++非常に面倒なので...


# 参考文献

- [[Python] 独自クラスで比較演算ができるようにする](https://www.yoheim.net/blog.php?q=20171002)
入れ子集合モデルから木構造を作る

入れ子集合モデルについて、簡単にしか説明しません。詳しくは、ぐぐってください。
すでに詳しく知ってる人は、飛ばして [作ったもの](#作ったもの) までどうぞ。

# 入れ子集合モデル
木構造（階層構造）をデータベースに格納しようと思ったとき、自分のテーブルへのリレーションを作るのが、単純だしわかりやすい。しかし、SQLで木の一部を取得するのが面倒だったりして、使いやすくはない。
そこで、入れ子集合モデルという考え方で木構造を保存する場合がある。階層構造を、入れ子の集合構造と見なして保存するわけである。

##### 自分のテーブルへのリレーションを持った、使いやすくないテーブルの例

|ID|名前|上司ID|
|--:|---|--:|
|1|佐藤|NULL|
|2|鈴木|1|
|3|高橋|2|
|4|田中|2|
|5|伊藤|1|
|6|渡辺|5|

##### 入れ子集合モデルの考え方

作りたい木構造
![2019110815024620.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223441/7fcae740-1d2f-a891-ab84-9e5594b3c6b2.png)

入れ子構造だとみなす
![2019110815080772.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223441/43806de7-6d65-0aad-db10-077de1fddc0a.png)

##### 入れ子集合モデルのテーブルの例

|ID|名前|Left|Right|
|--:|---|--:|--:|
|1|佐藤|1|12|
|2|鈴木|2|7|
|3|高橋|3|4|
|4|田中|5|6|
|5|伊藤|8|11|
|6|渡辺|9|10|

入れ子集合モデルを使うと、木の一部を取り出すのが簡単。
例えば鈴木さんの部下が誰か知りたければ、Leftが2以上、Rightが7以下の行を取り出せば、どれだけ階層が深かろうとごっそり全員取り出せる。逆にLeftが2未満でRightが7を超える行は鈴木さんの上司であり、その中でLeftが最も小さい人が鈴木さんの直属の上司となる。

# 作ったもの

プログラム全体はこちら→ https://github.com/ShTair/TreeBuilder/tree/master/TreeBuilder

プログラムの役割としては、入れ子集合モデルのリストから、木構造を生成すること。
そして、木構造から入れ子集合モデルのLeftとRightを更新すること。

2つのインタフェースがある。

- `ITreeItem`は入れ子集合モデルを表すために、`Left`と`Right`を持つ。
  - データベースに格納するモデルクラスにでも実装してください。
- `ITreeNode`は木構造を表すために、`Parent`と`Children`を持つ。
  - ビューモデルとかに実装したらいいと思います。

もしデータベースのモデルクラスを木のノードとしても使える場合は、一つのクラスに`ITreeItem`と`ITreeNode`を両方実装することもできます。

# 使い方

```C#
// 木構造の構築
// ITreeItem を実装するクラスのリストと、 ITreeItem から ITreeNode を生成するメソッドを渡す。
// 渡す ITreeItem のリストは、Left順にソートしてある必要がある。
// 木構造が構築されて、ルートノードのリストが返ってくる。
var roots = TreeBuilder.Rebuild(items, item => new Node(item));

// 木構造を表示したり、何らかの操作を加える

// Left、Rightの更新
// ルートノードのリストと、ITreeNode から ITreeItem を取得するメソッドを渡す。
// ITreeItem はnodeの中に持っておくと便利。もしくはディクショナリにでもしておく。
TreeBuilder.Update(roots, node => node.Item);
```

テスト用のプロジェクトがリポジトリの中にあるので、そっちも参照のこと。
https://github.com/ShTair/TreeBuilder
Kubernetes上にmattermostを構築する

# 本記事の内容
mattermostをkubernetes上に構築する方法のまとめ。

# 1. githubからmanifestとかを取ってくる
```bash:bash
vagrant@vagrant:~$ git clone https://github.com/mattermost/mattermost-docker.git
```
# 2. PostgreSQLをdeployする
```bash:bash
vagrant@vagrant:~$ kubectl run postgres --image=postgres:9 \
  --env="POSTGRES_PASSWORD=mmuser_password" \
  --env="POSTGRES_DB=mattermost" \
  --env="POSTGRES_USER=mmuser"

vagrant@vagrant:~$ kubectl expose deployment postgres \
   --name=db \
   --port 5432 \
   --target-port 5432
```

# 3. secretをdeployする
```bash:bash
vagrant@vagrant:~/mattermost-docker/contrib/kubernetes$ kubectl apply -f mattermost.secret.yaml
```
# 4. mattermostのdeploymentをdeployする
```bash:bash
### manifestの書き方が古いので最新化する
vagrant@vagrant:~/mattermost-docker/contrib/kubernetes$ git diff
diff --git a/contrib/kubernetes/mattermost.deployment.yaml b/contrib/kubernetes/mattermost.deployment.yaml
index 8c14390..20ea85d 100644
--- a/contrib/kubernetes/mattermost.deployment.yaml
+++ b/contrib/kubernetes/mattermost.deployment.yaml
@@ -1,4 +1,4 @@
-apiVersion: extensions/v1beta1
+apiVersion: apps/v1
 kind: Deployment
 metadata:
   name: mattermost-app
@@ -7,7 +7,12 @@ metadata:
     tier: app
   namespace: default
 spec:
-  replicas: 1
+  selector:
+    matchLabels:
+      app: mattermost
+      tier: app
+  strategy:
+    type: Recreate
   template:
     metadata:
       name: mattermost-app

### deplyする
vagrant@vagrant:~/mattermost-docker/contrib/kubernetes$ kubectl apply -f mattermost.deployment.yaml
deployment.apps/mattermost-app created
```
# 5.mattermostのserviceをdeployする
```bash:bash
vagrant@vagrant:~/mattermost-docker/contrib/kubernetes$ kubectl create -f mattermost.svc.yaml
service/mattermost created
vagrant@vagrant:~/mattermost-docker/contrib/kubernetes$ kubectl get svc mattermost
NAME         TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
mattermost   NodePort   10.99.213.175   <none>        80:32383/TCP   38m
vagrant@vagrant:~/mattermost-docker/contrib/kubernetes$
```

# 6.Webアクセスしてloginする
mail address, username, passwordを入力
<img width="300" alt="ms01" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76498/36669a4e-20cc-6345-43c3-131192ccb247.png">
team nameを入力
<img width="300" alt="ms01" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76498/d17cd3c6-f400-c237-cf70-676984d767e8.png">
login後
<img width="600" alt="ms01" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76498/849e5a78-a918-fc91-e7fe-f9deab428c28.png">


# 参考文献
https://github.com/mattermost/mattermost-docker/tree/master/contrib/kubernetes