OmniAICreator/Qiita-1.07M huggingface dataset:
iPhoneXのViewでの位置の取得方法まとめ

# 取得するタイミングに注意
詳しくは[こちらの記事](https://qiita.com/hituziando/items/e5873b5bfa42247071e6)に書いてあったが、viewWillLayoutSubviews()以降に呼ばれるメソッドの中でしかSafeAreaの値は取得できないので注意。
上の記事にはviewDidLoad()などが呼ばれる順番も書いてあった。

# SafeAreaの座標の取得方法
SafeAreaは上下に被らない長方形の所の話
![image.png](https://qiita-image-store.s3.amazonaws.com/0/211192/c6c3cca8-339d-c37e-aed3-ae729c140edf.png)

```swift
            //safeAreaFrameが上の青い部分のCGRect.
            let safeAreaFrame = self.view.safeAreaLayoutGuide.layoutFrame
            let safeAreaTop = safeAreaFrame.origin.y
            let safeAreaBottom = safeAreaFrame.origin.y + safeAreaFrame.height
            let safeAreaRight = safeAreaFrame.origin.x
            let safeAreaLeft = safeAreaFrame.origin.x + safeAreaFrame.width
```

# SafeArea外の画面を覆う四角の座標取得方法
iPhoneXはいびつな画面の形をしているが、それを覆うような長方形viewをうまく配置すると考えると話は楽になる

```swift
            //overViewFrameが上からかぶせる長方形のCGRect
            let overViewFrame = self.view.safeAreaLayoutGuide.owningView!.frame
            let overViewTop = overViewFrame.origin.y
            let overViewBottom = overViewFrame.origin.y + overViewFrame.height
            let overViewRight = overViewFrame.origin.x
            let overViewLeft = overViewFrame.origin.x + overViewFrame.width
```

# あとはうまく使おう
ここさえ取れればいくらでも自作でnavigationBarやらを作れる気がしたのでやってみよう。
あとでまたnavigationBarを作ったら記事書いてここに載せます。

追記: かけたー
[iPhoneXでも他でも使える"上に表示するバー"(NavigationBar)を作ろう]
(https://qiita.com/nasutaro211/items/89a00768ef95ee800537)
Trelloで運用する際のルールとかのメモ

こういうのはちゃんとルールとか決めないとカオスになる(なった)のでメモとして。

## ボードについて
- ボード作成単位はプロジェクト単位で作成する
- 完了したプロジェクトのボードはアーカイブする

## リスト作成について
- リストは進行状況が分かるものを用意。基本は以下固定でいいかも。この辺りはいっぱい記事あったのでそれを参考に。
 - To Do, Waiting, Doing, Done, Pending  などなど
- To Doはリストを分けてカテゴライズする。ただし細かく分けすぎるのはNG
 - To Do(All),To Do(バグ),To Do(仕様変更)・・・

## カード作成について
- 最初はある程度大きめの単位で作成する
- 詳細はコメントに
- 細かい作業タスクはチェックリストに追加する
- 期限は暫定でも設定する
- チェックリストから期限を切って作業する場合はカード化
- カード作成時に出来る限りアサインする
- カードに優先度を設定する必要があればラベルを設定する
- ラベルはあまり多く用意しないで「緊急即時」「優先度高」「調整中」くらいに

　※優先度低のカードを作らないように。カードにした時点で優先度が中以上のものが見える状態が望ましい。
　　そもそも優先度低いものはチェックリストで充分かと。いずれやらなきゃ的なものはやると決めた段階で優先度を上げるとよろしい

# 運用する上での注意点
- 何か動きがあればコメントに
- カードの削除はよほどの理由がない限りはやらない。Doneに移動して理由をコメントに書いておくようにする
- 週1くらいで進行状況を確認してみる。きつそうな作業はフォロー・相談できそうな人を追加アサインしておくとよい
- コメントにはなるべく経緯や背景的な内容を入れると見返した際に納得しやすい（はず）

# まとめ
やる事と現在の状況が一目見て分かる・共有できるような状況を維持することが重要。
変なカード作る人いるかもしれないので、テンプレート的なものを初めに用意しておくのもアリかなと思います。
OpenRestyのDockerイメージを使って重いバックエンドをシミュレートする

EnvoyなどのCircuit Breakerの検証のために、重いバックエンドをシミュレートしようと思ってます。nginx系のOpenRestyのコンテナイメージを使えば容易に実現できそうです。

### 起動

[nginxでnon-blocking sleep - Qiita](https://qiita.com/cubicdaiya/items/7a4065443e6943f55852) の記載を参考に、下記のような `docker-compose.yml` ファイルを用意、 `docker-compose up` する。

```bash
$ docker-compose up
```

```yaml:docker-compose.yml 
version: '3'
services:
  frontend:
    image: openresty/openresty:alpine
    command:
    - /bin/sh
    - -c
    - >
      echo '
      server {
        listen       8080;
        location / {
          proxy_pass http://heavy_backend:8081;
        }
      }
      '
      > /etc/nginx/conf.d/default.conf
      && /usr/local/openresty/bin/openresty -g 'daemon off;'
    ports:
    - "8080:8080"
  heavy_backend:
    image: openresty/openresty:alpine
    command:
    - /bin/sh
    - -c
    - >
      echo '
      server {
        listen       8081;
        location / {
          content_by_lua_block {
            ngx.sleep(1.234)
            ngx.say("Heavy")
          }
        }
      }
      '
      > /etc/nginx/conf.d/default.conf
      && /usr/local/openresty/bin/openresty -g 'daemon off;'
```

### 確認

```bash
$ time curl -i http://localhost:8080/
HTTP/1.1 200 OK
Server: openresty/1.13.6.2
Date: Thu, 23 Aug 2018 01:43:18 GMT
Content-Type: application/octet-stream
Content-Length: 6
Connection: keep-alive

Heavy

real	0m1.262s
user	0m0.007s
sys	0m0.007s
```

約1.234秒かかっていることが確認できた。
AWS ElasticIPのインスタンスを変更してssh接続できなくなったのを解消したときの備忘録

ElasticIPに設定されているインスタンスを別のものに変更してssh接続しようとすると、接続を拒否されてしまった。

接続できるようにするために公開鍵のリセットが必要になるようだ。

以下やったこと

1,確認して

```
$ ssh-keygen -F xxx.xxx.xxx.xxx
```

2,リセットして

```
$ ssh-keygen -R xxx.xxx.xxx.xxx
```

3,再接続

```
$ ssh -i hogehoge_ap-northeast-1.pem -l root xxx.xxx.xxx.xxx
```

無事接続できました。




参考：https://cloudpack.media/1362
物体検出（ssd）で顔のきりとりを自動化したい。自分が用意した画像と自分の決めたCLASSで学習する

顔の識別、検索をしたいがデータを集めて切り取りする作業があまりにも鬼畜な作業なので自動化したくて頑張ってみる。
open cv では傾いた顔を認識しない、顔じゃないものを顔と認識するなどなどイマイチ。

#物体検出というものがあるらしい
ここ
https://github.com/pierluigiferrari/ssd_keras
にあるコードが自分の環境（TensorFlow 1.x、Keras 2.x）で動きそうだったので試してみた。


ssd300_inference.ipynbかssd512_inference.ipynbに従ってポチポチコピペして実行してみる
とくに何の問題もなく実行できる。
ssd512_inference.ipynbの方が精度は高いみたい。

残念ながら顔は認識しなかった。
精度がすごく高い。えげつない。
こんなところに人がいたんだ！！！って物も見つけてくる。


#VOCを学習させてみる
教師データ「To train the original SSD300 model on Pascal VOC:」をダウンロードしてssd300_training.ipynbに従ってポチポチと実行する。
特に問題なく学習が始まる。

終わらない。
（環境はWindows,CPU i5 7500,GPU GTX-1070ti,メモリ 24G）

GPUのLOADがあまり上がらない。CPUは全コア100%を指している。
画像のジェネレータが重いのかも？。

複数GPUにしてみたが、そもそもCPUが限界だから速度はあがらないしmodelの保存で失敗（エポック毎に保存）するし、なかなか厳しい
ジェネレータ周辺のソースをcythonにしてみたが変わらない。

単騎で戦うしかない(´・ω・`)

Ryzen Threadripper 2990WXが欲しいよ・・

ssd512のほうはやってみたが失敗する。
ipynbにはSSD300と変わんねーから説明しない！と書いてある。
細かいパラメータを合わせてもepoch-01でエラー。
動かない。

ファインチューンのやり方も書いてあるけど、いまいちピンとこなかった。
もともとのClass idを生かして学習しろ～って書いてあるけど、元のclassは使いたくない。
最初から学習だ。最初はVGG16の重みを読み込むってあるので、まっさらな状態でもないみたい。

#顔認識教師データをつくる
画像のどこの部分（四角で指示）が顔だよって教師データを用意してあげればいい。
VOCのデータをみてみるとXMLでダーーーーっとかいてある。
これと同じものを作ればいい。
これをアノテーションと言うみたい。

あれ？また鬼畜作業？
(´・ω・`)



#VoTTで鬼畜作業
Visual Object Tagging Toolというツールを使ってアノテーションを作るのが一番らくだった。
人の画像を集めてVoTTで四角を手で書きまくる。

(´,,･ω･,,`)どうせ書くなら
ファッションにつながる物を抽出しちゃおう！
トップ、スカート、アウター、シューズみたいな感じでアノテーションを作って行く

20枚も書くと飽きてくる。
100枚も書くと吐き気がするよ。
↓鬼畜なアノテーション作成作業
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/185049/0779203e-5436-79d1-eb02-6fd1e0c42739.png)
ぱくたそをまた使いました。

一万枚くらいやればええですか・・・(´・ω・`)

アノテーションをやり始めた頃と数百枚作業したあとではBOXの書きっぷりが違うので・・・
最初に戻って微調整する。これがまた鬼畜。やりたくない。


#途中結果

４００程度枚の画像をepoch-19まで学習した結果
![78.jpg](https://qiita-image-store.s3.amazonaws.com/0/185049/48f7f71a-2d0c-fe61-e3d6-9a37914e33eb.jpeg)
ぱくたそ　です

やってみてわかったことは
・画像収集がやっぱりめんどくさい
・最初は100毎程度でちゃんと動いてるか？途中で確認したほうがいい。
・当たり前だけど間違った教師データや、抜けデータがあると精度が悪くなる。とくに顔があるのに、顔の指示が無い場合とか多くなりがち。
・教師データを何度も確認。

そのた注意点
・background　classは最初にちゃんといれよう。（LISTの一番最初をbackgroundと認識する）
・n_classes = は自分のクラス数に合わせて書き換える
・VOCのフォーマットとVoTTのフォーマットが微妙に違うので修正する
・trainval.txt＞トレーニングのデータみたい。こいつを作る必要がある
・test.txt＞確認のデータみたい。こいつを作る必要がある。
・VoTTはファイル名でソートされた順番で記録されているのでファイルを消したり足したりするとズレる（補正する機能がない）
・SSDが\*.jpg以外は変だったので全部\*.jpgにする（フォーマットもファイル名も\*.jpg）
・VoTTがjpegだとexportで変だったので全部\*.jpgにする（フォーマットもファイル名も\*.jpg）


VGG16を学習させるのと違ってすごくめんどくさい


#今後
1万枚くらい学習させたいので
学習＞推定＞VoTTのフォーマットで結果を保存＞人間が修正
を繰り返して教師データを増やしていく

(´,,･ω･,,`)忍耐

つづき
https://qiita.com/mokoenator/items/3268ec162658efe82fb6
WSL（Windows Subsystem for Linux）の導入とUbuntuの初期設定

## Windows Subsystem for Linux とは

Linux の（ELFフォーマット形式の）バイナリ実行ファイルを、Windows 10 および Windows Server 上でネイティブに実行するための互換レイヤーとのこと
（https://ja.wikipedia.org/wiki/Windows_Subsystem_for_Linux より引用）
Linux の実行ファイルを Windows でそのまま利用できるよってやつです

## インストール手順

1. 設定→アプリと機能→プログラムと機能→Windowsの機能の有効化または無効化で、「Windows Subsystem for Linux」を有効化して再起動する
1. ストアで「Ubuntu」を導入する。（Ubuntu以外もあり）
1. 起動した「bash」で任意のユーザ名とパスワードを入力する

> PowerShellを管理者権限で起動し、下記コマンドを実行することでも有効化できる（要再起動 & ストアからのインストールは別途必要）

```powershell
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
```

## TIPS

- いろいろあってWSLの環境をリセットしたい場合

  - Windows 10 の 設定 - アプリ から、対象ディストリビューションを選択

  - 詳細オプション の リセット をクリックする。

- bash起動時に.profile が実行されない場合

  - bashのショートカットのコマンドライン引数に「--login」を追加する

- 日本語が文字化けする場合

  - コンソールのフォントをラスターフォント以外にする

  - "ＭＳ ゴシック"で良いですね

# Ubuntuの初期設定

- Ubuntuのバージョンを確認する

```bash
$ cat /etc/os-release
# バージョンのみ
$ lsb_release -d
```

- 必要であれば、/etcの設定ファイルをバックアップしておく

```bash
$ cd ~
$ pwd
$ mkdir etc.org
$ sudo cp -p .* /etc/* etc.org/
```

* aptコマンドのリポジトリをubuntu.comからjpに切り替える

```bash
$ sudo sed -i -e 's%http://.*.ubuntu.com%http://ftp.jaist.ac.jp/pub/Linux%g' /etc/apt/sources.list
```

* aptコマンドでパッケージをアップデートする

```bash
$ sudo apt update
$ sudo apt upgrade
```

* 必要であれば、導入されているパッケージの一覧を保存しておく

```bash
$ cd ~
$ pwd
$ mkdir backup
$ dpkg --get-selections > backup/pkg-selections
```

* よく利用するコマンドのエイリアスを設定する（全ユーザに適用）

```bash
$ sudo vi /etc/profile
```

```bash
# 最終行に追加したいエイリアスを追記
alias ll='ls $LS_OPTIONS -l'
alias l='ls $LS_OPTIONS -lA'
alias cp='cp -i'
alias mv='mv -i'
alias rm='rm -i'
```

```bash
$ sudo source /etc/profile
# もしくは
$ sudo -s
# source /etc/profile
# exit
```

* .bashrc にヒストリ無視パターンを追加する

```bash
$ echo "export HISTIGNORE='?:??:???:exit:h *'" >> .bashrc
```

* さまざまな設定や環境を確認してみる

```bash
# ユーザの情報を確認
$ id
# ホスト名を確認
$ hostname
# システム情報を確認
$ uname -a
# bashのバージョンを確認
$ bash --version
# マウント状態を確認
$ ls /mnt -la
# プロセスの動作状況を確認
$ ps aux
# プロセスの動作状況をリアルタイムに確認
$ top
# ネットワークを確認
$ ifconfig
# ネットワークの接続状況を確認（すべての接続・名前解決なし・プロセスを表示）
$ netstat -anp
# メモリを確認
$ cat /proc/meminfo
# CPUを確認
$ cat /proc/cpuinfo
```

* Vimのインストール

```bash
$ sudo apt install vim-nox
```

```bash
$ sudo vi /etc/profile
```

```bash
# 最終行にエイリアスを追記
alias vi='vim'
```

```bash
$ sudo source /etc/profile
# もしくは
$ sudo -s
# source /etc/profile
# exit
```

- GCCのインストール

```bash
#!/bin/bash
$ sudo apt install build-essential
```

- パッケージ管理

```bash
#!/bin/bash
# パッケージ情報の更新
$ sudo apt update
# パッケージの更新
$ sudo apt upgrade
# パッケージの検索
$ apt search 検索対象文字列
```

- パッケージが保留された場合

```bash
#!/bin/bash
# 保留状態の確認
$ sudo apt -s dist-upgrade
# 不要なパッケージの自動削除
$ sudo apt autoremove
```

## 最後に

Windows 10 Fall Creators Update から正式版となったはずなので、いまさらながら WSL の導入を投稿しました。
安定して利用できるようになってきたので、ちょっとしたLinux環境としてコマンドの確認や調査を行うのに重宝しています。
Windowsのコマンドも実行できるのが何気に便利ですね。
【Unity】～SIerからゲーム業界へ～ 第1回 概要

##概要
IT業界で勤めていましたが
小さいころからのゲームに関わる夢を捨てきれず、33歳にて転職をチャレンジします。

同じような方の参考になればと
勉強の軌跡を残していきます。

##経歴
今までの経歴は
SIerにて設計、開発、テスト、保守、プログラマ管理者を担当。

##スキル
主にMicrosoft製品を扱っており

- 開発環境
VisualStudio(10年)

- 言語,フレームワーク
ASP.NET(10年)
C#(10年)
JavaScript(5年)
HTML/CSS(5年)
JQuery(5年)

- DB
SQLServer(10年)

- ソース管理
Microsoft Team Foundation Server(7年)
Microsoft Visual SourceSafe(3年)

##今後の内容
Unityでは使い慣れたVisualStudioとC#で開発ができるという事で
簡易的なゲームを作りながらUnityの使い方に慣れていければと考えてます。
2018-08-23 C++ > デフォルト引数 > 使わない理由(ソースリーディングの観点から)

```txt:動作環境
C++ Builder XE4
```

### デフォルト引数

- [デフォルト引数 @ C++入門](http://wisdom.sakura.ne.jp/programming/cpp/cpp18.html)
- [デフォルトパラメータ @ Delphi, C++ Builder](http://docwiki.embarcadero.com/RADStudio/Tokyo/ja/%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF%EF%BC%88Delphi%EF%BC%89)

自分が使うC++ Builderなどで「デフォルト引数」「デフォルトパラメータ」という機能があります (以下、デフォルト引数と呼びます）。

関数の引数の初期値を関数宣言部で指定しておくことで、関数コール部分で指定する必要がない機能と認識しています。

デフォルト引数を使った実装を読むなかで、自分が「読むのに手間がかかる」と感じた経験から、デフォルト引数を使わないようにしています。

## 例

例として、様々なセンサーを初期化する処理を上げてみます。
様々なセンサーに対して、通信速度(bps)をそれぞれ自由に設定できる場合とします。
そのコードに対して***「それぞれのセンサーの通信速度は何か？」***を確認するソースリーディングを考えてみます。

### デフォルト引数を使わない場合

```cpp
void initDevices()
{
    // 初期化(通信速度bps)
    initDHT22(1200);
    initRHT03(2400);
    initSi7021(1200);
    initTMP104(2400);
    ...
}
```

上記のコードの場合、initDevices()を見た時点で「それぞれのセンサーの通信速度は何か?」を確認できます。
2-3秒で全てのセンサーの設定を確認できるでしょう。

### デフォルト引数を(一部)使った場合

```cpp
void initDevices()
{
    // 初期化(通信速度bps)
    initDHT22();
    initRHT03();
    initSi7021(1200);
    initTMP104(2400);
    ...
}
```

上記の場合、「DHT22とRHT03のデフォルト引数の値は何か？」という疑問を持ちます。
それらを知るためにはヘッダーの宣言をgrepで検索するか、IDEの関数引数ポップアップ機能などを使います。

ヘッダーを確認する場合でも、ポップアップで確認する場合でも、それぞれ「一つの関数ごと」にしか確認できません。
１０個のセンサーを初期化する処理をinitDevices()で行う場合、一つの確認に２秒かかるとする(*1)と最大２０秒の時間を通信速度を見るために使うことになります。
この作業を自分は「ソースリーディングを中断する」と考えています。

*1) F1などのキー入力、ポップアップの表示、ポップアップの消失時間の合計

### 短期記憶の容量 (mental juggling, mental baggage)

人の短期記憶の容量は7±2と言われることがあります。

10個の通信速度デフォルト引数の値を短期記憶に格納するのは7+2を超えます。また、短期記憶の項目が増えることは、Code Completeの「mental juggling」（やThe Art of Redable codeの「mental baggage」)になります。

### ソースは書くよりも読まれる方が多い

@ プログラマが知るべき97のこと by Kevlin Henney 
コードレイアウトの重要性 by Steve Freeman

> プログラマは仕事の時間を、実際にコードをタイプすることよりも、コードを探すことと読むことに費やしている、そんな調査結果もあるようです。

僕自身、実際にソフトウェアをメンテナンスする中で、読む方が多いと経験しています。

読む方が多いコードに対して、「デフォルト引数を使うことは有効なのだろうか？」と疑問を持ちつづけました。そして、上記の理由から、2018年8月現在の自分の考えでは「使わない方がコードを読みやすい」という考えです。

### 備考

記事執筆者の記憶力はあまりよくありません。短期記憶は5かもしれません。
そういう人でも読みやすいソースコードは何か、を日々考えています。

C++のtemplateやoverloadをうまく使うことで「それぞれのセンサーの通信速度は何か？」を複数台(例:10台)に対して2-3秒で一覧する方法があれば、知りたいと思います。

また、デフォルト引数を使うことで、ソースリーディングはこのように効率化する、ということがあれば知りたいと考えています。

注記: 記事執筆時点の考えなので、もっと良い方法があれば、考え方を反転することもあります。
AWS-UG 初心者支部#13　「AWS Night school」 メモ

# AWS Night School

Twitterのハッシュタグは \#jawsug_bgnr

## AWS Night school 第1回（AWSJ 亀田さん）

### ビルディングブロック
ブロックを組み合わせるようにサービスを組み合わせて利用するという思想

### AWS利用料の一般的な内訳
EC2・RDSが利用料金の9割
→EC2・RDSから学習すると良い

### AWSの利用額が怖い
Billing Alertを活用しよう
一定金額を超えたらアラート（メール）を飛ばす

### AWSのグローバルインフラストラクチャ
大阪リージョンは単独で利用できないので、東京リージョンとセットで利用する
※リージョン＝国・地域

東京は4つのアベイラビリティゾーンで構成されている
※アベイラビリティゾーン＝データセンター

### リージョンとアベイラビリティゾーン
アベイラビリティゾーンをまたがないとSLA適用外
1台構成は要件を満たしているか要確認

アベイラビリティゾーンを跨ぐ場合、1ms程度の時間が掛かる

マルチアベイラビリティゾーンでデータセンターレベルで単一障害点を失くす

### EC2・EBS
コンピューティング処理能力を変更可能
Linuxの場合、1分単位で課金

インスタンスのCPU・メモリを変更する場合、再起動が必要

前払い機能で割引あり（リザーブドインスタンス）

東京リージョンは高い（アメリカより）
データ分析など、データの転送速度よりCPUが必要な場合はアメリカのリージョンを使うと良い

### インスタンスタイプとは？
C3.8xlarge のように表記する

C：インスタンスファミリー
3：世代数（より大きいものが良い）
8xlarge：スペック（より大きいほうが性能が良く料金が高い）

初めて触る場合、M5がオススメ

### インスタンスのユーザーデータ
インスタンス起動後にスクリプトを実行することができる

### ストレージ
* EBS 永続的に保存できる

* インスタンスストア シャットダウンするとデータが消える

AWSは障害が起きない×
障害は発生しているが即時に別ハードウェアで起動するなどして瞬断で復旧している○

EC2が不安定なときは停止・起動で安定する場合あり
何故か？ 可能な限り別ハードウェアで起動するため、不安定なハードウェアから脱出できる

EC2とストレージはネットワークで繋がっているため、ここがボトルネックになるケースがある
「EC2最適化」でEC2を起動すると良い（ネットワークとストレージ用ネットワークが別で提供される）

10万IPOSを超えるようなアクセスの場合、EC2に直付けのインスタンスストアを使用すると良い
シャットダウンでデータが消えるため定期的にEBSやS3に退避すること

### EBS
アベイラビリティゾーン内で自動的にレプリケートしている

* 1GiB〜1TiBのEBSマグネティックボリューム
* 最大16TiBのSSDボリュームを提供
基本的にSSDを利用すると良い

複数のEC2から一つのEBSへのアクセスはできない
NASのように利用する場合はEFSを利用すると良い

ストレージパフォーマンスが必要ならプロビジョンドIOPSを利用すること

EBSスナップショットは差分バックアップで取得される
取得したバックアップは自動的に圧縮される
そのため、見積もりがしにくい点に注意

### インスタンスメタデータ
169.254.169.254にアクセスすることで取得可能

### GitHubにAWSのシークレットキーをアップロードしないこと
クロールしているユーザーがいて、仮想通貨のマイニングに使用される

AWSでもGitHubにシークレットキーがアップロードされていないかクロールしているが、
AWSではお客様のアカウントを操作しないというポリシーになっているため連絡のみ
基本的には自己防衛


第2回ではS3・RDSを予定

## Auroraの凄さを振り返る（クラスメソッド株式会社 大栗 宗さん）

Auroraの凄さを振り返る
https://speakerdeck.com/maroon1st/aurorafalseqi-sawozhen-rifan-ru

JAWS-UG 初心者支部#12 AWS Night schoolでAuroraの凄さを話してきた \#jawsug \#jawsug_bgnr
https://dev.classmethod.jp/cloud/aws/jaws-ug-bgnr-13-aurora-session/

### Auroraの特徴
クラウド自体にAmazonが再設計したRDBMS
MySQLとPostgreSQL互換

MySQLの最大5倍
99.999999999%の堅牢性 （S3と同じ）

移行サポートが豊富
低コスト（実際に利用した分だけ料金が発生）
→将来のデータサイズを見越した設計をしなくて良い

AZを跨いだ統一的なストレージボリュームがある

既存のAWSサービスを組み合わせてAuroraが実現されている
ユーザーからは隠蔽されており、ユーザーは意識せずに利用できる

### Well-Architected Framework

#### 信頼性の柱
6重化された分散ストレージ
1つのAZに2個、3AZでデータを保存

１つぐらいデータセンターがなくなっても運用可能

なぜ6重化？
クォーラムモデルによる多数決のため
本来なら3重化でも良いが、AZ停止のような大規模障害にも耐えるため6重化

ストレージが独立している
フェイルオーバーが速い（データリカバリが殆ど無い）

#### パフォーマンス効率の柱
レプリケーションによるスレーブへの書き込み負荷がない
スレーブにはログの位置情報のみを伝える（ストレージが共用なので可能）
（通常のRDSはスレーブにもマスターと同じ書き込みを行っているため負荷がある）

レスポンスタイムが安定している

MySQL限定だが、特定のJoinが高速化されている
Joinの種類やスキャン方法を追加している

MySQLが苦手なフルスキャンが高速化されている

#### コスト最適化の柱
Multi-AZの予備機をリードレプリカとして利用できる
（予備機も含めてすべて利用可能）

負荷に合わせてリードレプリカをオートスケーリングできる

Aurora Serverlessで待機コストを極小化
停止後の起動に25秒ほどかかることに注意

#### 運用上の優秀性
コネクションを切断せずにパッチ適用可能（例外あり）

高速フェイルオーバー（数秒）
通常はDNSで切り替えるが、
マスターフラグ・スレーブフラグがあり、そこをクライアントで判定して切り替えることで高速化可能

backtrack：DBデータを任意の時点に戻すことができる
drop tableのオペミスにも活用できる

Database clone：即座にDBデータを複製

Performance insights搭載：パフォーマンス分析・トラブルシューティングが可能
DBの待ち時間の可視化
クエリ単位でも状況確認可能

IAM認証でログインできる

カラム追加も高速

AuroraからLambdaを実行可能
Macの環境設定

MacのOSを初期化したついでに環境構築をまとめてみる。

os は High Sierra

## Xcode
App Store から入手。

## Homebrew
https://brew.sh/index_ja

インストール

```terminal
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```

## emacs
brew で管理

インストール

```terminal
$ brew install emacs
```

## anyenv
rbenv と nodenv を管理
https://github.com/riywo/anyenv

ダウンロード

```terminal
$ git clone https://github.com/riywo/anyenv ~/.anyenv
```

~/.bash_profile に追加

```text:.bash_profile
export PATH="$HOME/.anyenv/bin:$PATH"
eval "$(anyenv init -)"
```

.bash_profile を反映

```terminal
$ exec $SHELL -l
```

rbenv と nodenv をインストール

```terminal
$ anyenv install rbenv
$ exec $SHELL -l
$ anyenv install nodenv
$ exec $SHELL -l
```

## ruby
rbenv で管理

デフォルトと同じバージョンをインストール

```terminal
$ rbenv install 2.3.7
$ rbenv global 2.3.7
$ exec $SHELL -l
```

## node.js
nodenv で管理

バージョンはなんとなくでインストール

```terminal
$ nodenv install 7.10.1
$ nodenv global 7.10.1
$ exec $SHELL -l
```
Javascriptで配列をマージする

Javascriptで２つの配列をマージしたいことがあると思います。

配列Aと配列Bを、どちらの配列の値も残したまま連結する場合は以下のように記述できます。

```js
let array_base = ['blue', 'green', 'yellow'];
let array_add = ['red', 'white'];
let result_concat = array_base.concat(array_add);
console.log(result_concat);
```
上記の結果は以下となります。

```json
["blue", "green", "yellow", "red", "white"]
0:"blue"
1:"green"
2:"yellow"
3:"red"
4:"white"
```
<br>

`Object.assign`を使った場合、思い通りにならないかもしれません。

```js
let array_base = ['blue', 'green', 'yellow'];
let array_add = ['red', 'white'];
let result_assign = Object.assign(array_base, array_add);
console.log(result_assign);
```
上記の結果は以下となります。
キーが重複する部分は第二引数の配列の値で上書きされてしまいます。

```json
["red", "white", "yellow"]
0:"red"
1:"white"
2:"yellow"
```


<br>
`push`を使った場合は配列の最後に配列が追加されます。

```js
let array_base = ['blue', 'green', 'yellow'];
let array_add = ['red', 'white'];
array_base.push(array_add);
console.log(array_base);
```
上記の結果は以下となります。

```js
["blue", "green", "yellow", Array(2)]
0:"blue"
1:"green"
2:"yellow"
3:(2) ["red", "white"]
```
The server quit without updating PID file　mysqlエラー解決方法

#The server quit without updating PID file　mysqlエラー解決
```The server quit without updating PID file```
こちらのmysqlエラーに結構な期間悩まされました。。。

今回は解決方法をまとめたいと思います。

##エラー出現理由に対する考察
こちらのエラーの出現理由ですが、mysqlのバージョン切り替え時に出現すると思われます。
私はmysqlを使っていたので、brewのupdateを行った際にmysqlがアップデートされてしまいました。

mysqlのバージョンを切り替え　→　前のmysqlバージョンで使用したデータを使って起動した時に出るようです。

参考リンク
[MacでHomebrewを使ってinstallしたMySQL5.6とMySQL5.7を切り替えて使う](https://qiita.com/t_oginogin/items/76ca2b6ce18d53988dc3)

＊解決手順実行前に
そのまま解決手順を実行してしまうと、mysqlのデータが削除されてしまいます。
***以下の手順を実行し、バックアップを行ってください。***

```
$ brew services stop mysql 
でmysqlを一旦停止
$ cp -pr /usr/local/Cellar/mysql /適当な場所/mysql_backup
により、mysqlのデータバックアップを行ってください。
```

##解決手順

####1.まずlocal配下のmysqlを全て削除する
```
$ rm -rf /usr/local/mysql
$ rm -rf /Library/StartupItems/MYSQL
$ rm -rf /Library/PreferencePanes/MySQL.prefPane
$ rm -rf /Library/Receipts/mysql-.pkg
$ rm -rf /usr/local/Cellar/mysql*
$ rm -rf /usr/local/bin/mysql*
$ rm -rf /usr/local/var/mysql*
$ rm -rf /usr/local/etc/my.cnf
$ rm -rf /usr/local/share/mysql*
$ rm -rf /usr/local/opt/mysql
```
brew uninstall mysql　では削除できないファイル群を削除します。

####2.次にmysqlをインストールします
```brew install mysql@5.6(使いたいmysqlバージョンを指定してください)```

####3.最後にパスを通してからサーバーを立ち上げる
```$ echo 'export PATH="/usr/local/opt/mysql@5.6/bin:$PATH"' >> ~/.bash_profile
$ mysql.server start```

```
Starting MySQL
. SUCCESS! 
```

mysqlの立ち上げが完了しました！:laughing:
（備忘録）RubyOnRailsの超超超ざっくりした開発のながれ

今までで僕が学んだことを、ざっくりと骨格のみをつかむ形でまとめてみた。
**個人的な備忘録として書いたついでの投稿**なので、詳細は他をあたっていただきたい。
　
##Railsプロジェクト開始コマンド作成 
```
rails _バージョン名_ new プロジェクト名
```
→プロジェクト名とは、つまりアプリ名。
 
##データベースの作成
```
rails db:create
```
→.ymlファイルの記述にのっとり作成される。
　
##Modelの作成
```
rails g model モデル名 その他
```
→マイグレーションファイルとモデルファイルの作成が行われる。
　
##マイグレーションファイルの実行
```
rails db:migrate
```
→先ほど作成したデータベースにテーブルがモデル名の小文字かつ複数形で作成される。
　
##ルーターの作成
→*config/routes.rb*に書いていく。
　
##コントローラーの作成
```
rails g controller コントローラー名
```
→これにより、コントローラーファイルとビューフォルダが作成される。
なお、コントローラー名はモデル名の複数形！（ぼくが決めたことじゃない）
___
（ひとりごと）ActiveRecordは、Railsとデータベースをつなぐ役割をしているんだね。また、これによって、SQLを書かずに（$ rails c　から入って）Rails側でレコード操作ができるんだね。
最新バージョンのTensorBoardをGoogle App Engineで使えるようにしてみた

## 概要

前回はGCPから提供されているDockerイメージを利用してデプロイしてみたけど、TensorBoardが最新バージョンじゃなかったので、自前でDockerイメージを用意してApp Engineにデプロイしてみました。

TensorBoardをGoogle App Engineで使えるようにしてみた
https://qiita.com/kai_kou/items/3be6d840fafb0623e664


## 前提

Dockerアプリはインストール済みの前提です。


## 手順

### Dockerfileの作成

```sh
> mkdir 任意のディレクトリ
> cd 任意のディレクトリ
> touch Dockerfile
> vi Dockerfile
> docker build . -t tensorboard
```

参考)DockerのイメージをGAE/FEにデプロイする
https://qiita.com/wasnot/items/b8691bb4940e6f4a9c24


```txt:Dockerfile
FROM python:3.5
RUN pip install tensorflow
ENTRYPOINT ["tensorboard", "--logdir", "gs://任意のバケット/output", "--port", "8080"]
```
ポイントはtensorboardのパラメータオプションで```--port``` で8080指定することでしょうか。


### app.yamlの作成

```sh
> gcloud app gen-config
> vi app.yaml
```


もし既存のGCPプロジェクトにデプロイする場合、```service``` 指定しないと、```default``` にデプロイされてしまうので、ご注意ください。
今回は```automatic_scaling``` でインスタンスが1台のみ起動するように指定しています。

```yaml:app.yaml
env: flex
runtime: custom
service: サービス名

automatic_scaling:
  min_num_instances: 1
  max_num_instances: 1
```

### 参照データのコピーとデプロイ

今回は```--logdir``` の参照先をCloud Storageにするので、
TensorFlowの結果をCloud Storageのバケットへコピーしておきましょう。

```sh
> gsutil cp -r TensorFlowの結果フォルダ  gs://任意のバケット/output/
```

App Engineへデプロイします。

```sh
 > gcloud app deploy
(略)
Deployed service [サービス名] to [https://サービス名-dot-プロジェクトID.appspot.com]

You can stream logs from the command line by running:
  $ gcloud app logs tail -s サービス名

To view your application in the web browser run:
```

### アクセスしてみる

では、App Engineにデプロイできたので、URLへアクセスしてみましょう。

```sh
> open https://サービス名-dot-プロジェクトID.appspot.com
```

<img width="1389" alt="TensorBoard-3.png" src="https://qiita-image-store.s3.amazonaws.com/0/48549/1db5b771-53d0-ff4d-0299-d47eae3cf8ee.png">

やったぜ。

[前回](https://qiita.com/kai_kou/items/3be6d840fafb0623e664)とは違って認証機能はありませんので、ケースバイケースでの利用になりそうです。


## 参考

雑に TensorBoard を起動する Docker イメージの作り方
https://qiita.com/hoto17296/items/c0d214ca6e34c2d72a52

DockerのイメージをGAE/FEにデプロイする
https://qiita.com/wasnot/items/b8691bb4940e6f4a9c24
sudo apt updateできない

#きっかけ
過去の投稿にコメントでアドバイス頂き、アドバイスを試そうと約半年ぶりにubuntuを起動。
まずOSを更新でもするかとコマンドを打つと次のようなエラー発生。

#環境
ubuntu 16.04

#エラー内容

```
$sudo apt update

W: ターゲット DEP-11-icons (main/dep11/icons-64x64.tar) は /etc/apt/sources.list.d/google-chrome.list:3 と /etc/apt/sources.list.d/google.list:2 で複数回設定されています
```

#対策
色々調べ、次の記事を参考に対策。
https://qiita.com/on-vegetable/items/8f821be0641d0dbb7631


```
cd /etc/apt/sources.list.d/
sudo gedit google.list
```

google.listの中身は、次のような感じ。
同じ内容が2行存在。

```
deb http://dl.google.com/linux/chrome/deb/ stable main
deb http://dl.google.com/linux/chrome/deb/ stable main
```

###失敗
これがエラーの原因かと思い、次のように修正。

```
#deb http://dl.google.com/linux/chrome/deb/ stable main
deb http://dl.google.com/linux/chrome/deb/ stable main
```
しかし、改めてupdateを実行しても、エラーは解消されない。

###成功

失敗を受けて、次のように修正。

```
#deb http://dl.google.com/linux/chrome/deb/ stable main
#deb http://dl.google.com/linux/chrome/deb/ stable main
```

これでエラーが解消し、update無事完了。
その後、upgradeも無事完了。

#最後に
今回使ったコマンド。

```
$sudo apt update
$sudo apt upgrade
```
Vim — 最初からインサートモードでファイルを開く

```
vim some_file -c 'startinsert'
```

## `-c` オプションって何？

ファイルをロードした後に実行するコマンドを決められる。

```
$ vim --help | grep '\-c '
   -c <command>		Execute <command> after loading the first file
```

( `first file` ってなんだろう )

## Ref

- [How do I start vim in insert mode? - Stack Overflow](https://stackoverflow.com/questions/11464088/how-do-i-start-vim-in-insert-mode)

## Versios

- VIM - Vi IMproved 8.1 (2018 May 18, compiled Aug  7 2018 21:58:18)
- Mac OS X High sierra








<!-- Update From Qiita API -->

# チャットメンバー募集


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

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





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
nginx1.12.2でもhttp/2 Server Pushに対応していたという事実

#http/2 Server Pushの導入

　[技術系情報掲載システム](https://croud.jp/ttis/)のレスポンスを少しでも上げようと、http/2 Server Pushを導入してみた。CentOS7の場合、無設定のyumだとnginxの1.12.2が入る。Web上の情報を参照すると対応は1.13.9以降なので、リポジトリ設定を変更し最新版をインストールした。結果、バージョンは1.15.2となった

　その後、Server Pushのためのプログラムの追加作業を行う。コンテンツ中に含まれる画像リンクを元に、linkヘッダを吐き出すようにした

#結果

　システムはSPA(Single Page Application)で、データはAjaxを利用して送信している
　最初にあるttisが画像のリンクを含んだテキストデータを送信しており、linkヘッダの添付もここで行っている
　結果だけ見るとAjaxでのやりとりでもServer Pushは正常に動作するようだ

###linkヘッダを付けない場合
![image.png](https://qiita-image-store.s3.amazonaws.com/0/267629/ae4b0c14-83b6-2def-3c5b-3053487a14ad.png)

###linkヘッダを追加した場合
![image.png](https://qiita-image-store.s3.amazonaws.com/0/267629/2eb845f8-ca99-3dce-3ff9-3bd9e089b539.png)

　linkヘッダ付けない場合は画像のアドレスをブラウザが受け取り、再度サーバに要求する形になる。そのためttisがデータを受け渡した後、ラグが発生する。linkヘッダを付けた場合は、ttisのテキストコンテンツ送信終了直後に画像の送信が始まっている。30ms程度ではあるが、確実に総合的な時間が短くなっている


#本番サーバに適用
　テストがうまくいったので、本番サーバにデプロイする。gitでpullするだけの簡単な作業だ。本番サーバのnginxのバージョンは1.12.2なので、こちらもアップデートをかけなければならない・・・と思っていた

　とりあえずアップデート前にデプロイの状態を確認するため、普通に動かしてみた。するとnginx1.12.2の状態でも、テストサーバでlinkヘッダを追加した場合と同じ動きをしている

　**ちょっ、これって前から対応してた？**

　試しに本番サーバのlinkヘッダ出力をいじって、存在しない画像のIDを設定してみる

![image.png](https://qiita-image-store.s3.amazonaws.com/0/267629/0b18c6d9-e772-6534-9f56-a9da53940d68.png)

　明らかにlinkヘッダに反応している。つまりnginxのバージョンを上げなくても、Server Pushは使えるということだ

　しかし[ぐぐ](https://www.google.co.jp/search?q=http%2F2+Server+Push+&oq=http%2F2+Server+Push+nginx)ってみても、1.13.9で対応したという話ばかりだ


#まとめ

　バージョン・・・いや、別にいいんだけど、なんか釈然としない

　実際にシステムを操作してみると、画像表示までの一瞬のラグが消え、たかが30msでも意外に体感できるものなのだという結果だった
ちょっと複雑なSQLをEloquentに落とし込むためのメモ

# はじめに
　最近CTFのscoreboardとかを制作している際に複雑なSQL文を書き集計やグラフ化、データ取得をしないと行けないことがあり、「SQLで書けば一発！」と高をくくっていたが最後...Eloquentにとっつかまりました...
　完成はしていないのでまだまだいっぱいこんな事案が出てくるとは思いますが何かしらの足しになればと思い投稿します。

# WHERE (col1='a' OR col1='b') AND (col2='b' OR col2='a')
```sql:sample.sql
SELECT *
FROM   table_a
WHERE  (col1='a' OR col1='b') 
AND    (col2='b' OR col2='a');
```
```php:demoService.php
$val_a = 'a';
$val_b = 'b';
$query = Sample::where( function ($query) use ($val_a, $val_b) {

             $query->orWhere('col1', =, $val_a)
                   ->orWhere('col1', =, $val_b);

         } )->where( function ($query) use ($val_a, $val_b) {

             $query->orWhere('col2', =, $val_a)
                   ->orWhere('col2', =, $val_b) ;

         } )
```
Where自体がANDと同じ役割を持っているのでWhereの内部でorWhereを利用することにより( or )AND( or )を実現している。

# LEFT JOIN (副文)
```sql:sql.sql
SELECT    *
FROM      table_a
LEFT JOIN ( SELECT * FROM table_2 WHERE id < 9 ) AS JOIN_Table 
ON        JOIN_Table.col1 = table_a.col2;
```
```php:demoService.php
$sub_query = SampleA::where('id', '<', 9);
$query     = SampleB::leftJoin(
                 \DB::raw(
                     "( { $sub_query->toSql() } ) AS JOIN_Table"
                 ),
                 JOIN_Table.col1, =, table_a.col2
             );
return $query->mergeBindings($sub_query->getQuery())->get();
```
# SELECT in CASE
```sql:sql.sql
SELECT (
    CASE 
        WHEN table_a.name IS NOT NULL 
        THEN 1 
        ELSE 0 
    END
) AS isExist 
FROM table_a;
```
```php:demoService.php
$query = Sample::selectRaw::('( 
             CASE 
                 WHEN userSolve.problem_id IS NOT NULL T
                 HEN 1 
                 ELSE 0 
             END 
         ) AS isSolve');
```
シェルでコマンドがBSD版かGNU版かを見分けるお手軽な方法

man を grep する手があるんじゃないだろうか。

## BSD

Macでのコマンド類はデフォルトで BSD版なので、その例。

```
man man sed | grep -e BSD -e GNU | head -n 1
SED(1)                    BSD General Commands Manual                   SED(1)
```

### GNU

Macでは GNU版のコマンドを brew で入れられる。その例。

```
man man gsed | grep -e BSD -e GNU | head -n 1
              disable all GNU extensions.
```

## 他のコマンドで試した例

```
bash-4.4$ man sed | grep -e BSD -e GNU | head -n 1
SED(1)                    BSD General Commands Manual
```

```
bash-4.4$ man gsed | grep -e BSD -e GNU | head -n 1
              disable all GNU extensions.
```

```
bash-4.4$ man cut | grep -e BSD -e GNU | head -n 1
CUT(1)                    BSD General Commands Manual
```

```
bash-4.4$ man gcut | grep -e BSD -e GNU | head -n 1
       GNU coreutils online help: <https://www.gnu.org/software/coreutils/>
```

```
bash-4.4$ man stat | grep -e BSD -e GNU | head -n 1
STAT(1)                   BSD General Commands Manual                  STAT(1)
```

```
bash-4.4$ man gstat | grep -e BSD -e GNU | head -n 1
       GNU coreutils online help: <https://www.gnu.org/software/coreutils/>
```

## Versions

- Mac OS X High sierra


## Links

- [Gist](https://gist.github.com/YumaInaura/5c717da2184e5efecd303b8bc4eadd51)








<!-- Update From Qiita API -->

# チャットメンバー募集


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

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





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
GitHubでブログを公開する

> GitHub PagesとHexoについて新しい記事を書きました、こちらの方がわかりやすくなっています。
> [コマンドラインでブログを運用する](https://qiita.com/sakkuntyo/items/3763eb8e39c267542776)

もう何番煎じだよって感じですが、気になっていたのでやってみました。
WordPressで公開しているブログも動的コンテンツは使ってないし、デザインも気にしていないので、もうこれでいいかなと思っています。

- Github Pagesとは
    - 静的Webページを公開できるホスティングサービス
    - ApacheやNginxがやってくれるルーティングも含めてこのサービスがやってくれます。

# GitHub PagesでWebページを公開する手順
ここ（公式）を参考に手順を進めるだけでWebページの公開が出来てしまいます。おしまい。
> https://pages.github.com/

・・・ここまでがあまりに簡単すぎたのでブログの様にしていく手順を追加したいと思います。

# 静的サイトジェネレータ「Hexo」でページを作成する手順
- 静的サイトジェネレータとは
  - HTMLとCSSとJavaScriptで構築さページを簡単に生成出来るツール

```
面倒なHTMLやCSSを書く必要がなくなります。
```

- Hexoとは
  - Nodejs製の静的サイトジェネレータ
  - 他のジェネレータよりデザインがイカしてるブログデザインなページを作成できる

```
似ているツールの一つに「Hugo」があります。
こちらは特に人気が出ている様です。
それぞれの出来るデザインの違いは記事最後にある参考ページを確認してみてください。
```

### 1. Hexoをインストール
```shell-session
$ npm install -g hexo
```

### 2. Hexoでプロジェクトを作成
```shell-session
$ hexo init sakkuntyoLab
```

### 3. Hexoで起動して、ページを確認してみる
```shell-session
$ cd sakkuntyoLab
$ hexo server
INFO  Start processing
INFO  Hexo is running at http://localhost:4000. Press Ctrl+C to stop.
```
このままブラウザで接続してみると以下の様なページが表示されます。
指定するアドレスは「http://localhost:4000」です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/266455/784b2542-cd99-c520-f5ca-e1f23f12119a.png)
確認が済んだら起動したHexoをCtrl+Cで停止しておきましょう。

### 4. Hexoで記事を追加してみる
```shell-session
$ hexo new "新しい記事のタイトル"
$ hexo server
```
またブラウザで確認してみます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/266455/4c7f07e3-9cba-7070-2579-9bb9d6e9eb3f.png)
本文のない記事が追加されている事がわかります。

### 5. ブログの設定を編集する
_config.ymlを以下の様に編集します。
行頭の - は変更された行で、 + は 新しく追加された行となります。
-と+で並んでいる場合は、 - の行が + の様に変更された、と解釈してください。

```diff
-title: Hexo
-subtitle:
+title: さっくんちょ実験室
+subtitle: いろいろやります
+author: sakkuntyo
+language: jagit 
+timezone: Asia/Tokyo
-url: http://yoursite.com
+url: https://githubユーザー名.github.io
```
変更後、またブラウザで確認してみます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/266455/fdc5663c-c5d8-f21a-cb55-4a6540000306.png)
タイトルやサブタイトルなどが変更されているのがわかりますね。

### 6. githubにアップロードする
```shell-session
$ mkdir ../repo
$ cd ../repo
$ git clone https://github.com/githubユーザー名/githubユーザー名.io
$ cd githubユーザー名.io
$ mv ../sakkuntyoLab/* ./
$ rm .gitignore
$ git add *
$ git rm index.html
$ git commit -a -m "Hexo generated"
$ git push origin master
githubのユーザー名とパスワードを聞かれた場合は、入力してエンターを押します。
```
githubで公開されたページを確認してみましょう！
尚、ページが反映されるには少し時間がかかるようで、反映されない場合は時間を置くと良いそうです。

# 参考
今回はこちらのサイトにお世話になりました。
> Node.js製の静的サイトジェネレータ「Hexo」で無料ブログ開発 vol.1
> https://dotstud.io/blog/hexo-static-site-vol1/

> デザイナーの僕がHugoを使ってポートフォリオサイトを作ってみる #1【準備編】
> https://dotstud.io/blog/hugo-for-designers-vol1/
ubuntuへの環境構築

半年以上前に書いた記事がずっと「下書き」に入った状態だったので、投稿。

備忘録。
目的：ubuntu 16.04への自然言語処理環境の構築。

1.miniconda インストール
（参考）https://qiita.com/icoxfog417/items/e8f97a6acad07903b5b0

●ここからダウンロード
https://conda.io/miniconda.html

●「ダウンロード」フォルダに次のファイルをダウンロード
・Miniconda3-latest-Linux-x86_64.sh

```
$ cd ダウンロード
```

```
$ bash Miniconda3-latest-Linux-x86_64.sh
```

・Enterやyesを押して終了。


●パスを通す
・geditで開く。

```
$ gedit ~/.bashrc
```

・以下を追記して保存。

```
export PATH="/home/ユーザ名/miniconda3/bin:$PATH"
```

・変更をシステムに反映。

```
$ source ~/.bashrc
```

・パス完了。

2.


2.仮想環境構築
2-1. condaで仮想環境を構築する場合
（参考）https://qiita.com/icoxfog417/items/02a80b93b5f1e95f2795

```
# 仮想環境に追加でインストール(バージョンを指定する場合conda install scipy=0.12.0など)
conda install scikit-learn

# condaで取得できないものについて、pipでインストール(仮想環境にpipを入れて対応)
conda install pip
pip install Flask

# condaでインストールしたライブラリを書き出し
conda list --export > conda_requirements.txt

# インストールしたパッケージのアップデート(conda自身はconda update conda)
conda update numpy

# 仮想環境無効化
deactivate # Windows
source deactivate # Max/Linux

# ファイルから仮想環境を作成
conda create -n my_new_env --file conda_requirements.txt

# 最近はconda env exportを使い方が良いよう
conda env export > environment.yml
conda env create -f environment.yml
```

●「my_env」として生成と同時に、アクティブ化して、「numpy scipy scikit-learn matplotlib jupyter」をインストール。

```
$ conda create -n my_env numpy scipy scikit-learn matplotlib jupyter
activate my_env
```

●もし、「my_ebv」という仮想環境だけ作成するなら。

```
$ conda create -n my_env
```


●構築した仮想環境の確認

```
$ conda info -e
```

●アクティブ化
（参考）https://conda.io/docs/user-guide/tasks/manage-environments.html

```
$ source activate my_env
```

●非アクティブ化

```
$ source deactivate my_env
```

●削除
・「my_ebv」という仮想環境を削除する場合。

```
$ conda remove --name my_emv --all
```

2-2.virtualenvで仮想環境を構築する場合。

●まず、virtualenvのインストール

```
pip install virtualenv
```

```
# プロジェクトのフォルダを作成
mkdir myproject 
cd myproject

# 1.仮想環境の作成 venvはフォルダ名でここにプロジェクト用の環境が用意される
virtualenv venv 

# 2.仮想環境を有効化し、pipで必要なモジュールをインストール
# Windowsの場合、venv/Scripts/activate.bat なお、Gitのシェルを利用すると同じようにsourceでできる
# 仮想環境のactivateを行わないと、グローバルにインストールされるので注意 なお、無効化はdeactivate

source venv/bin/activate

pip install xxxx
# pip freezeで作成した一覧(requirements.txt)からインストールする場合は以下
pip install -r requirements.txt

# 3.実行する
python xxx.py
```



３．ライブラリのインストール（mecab, gensim, pandas）
●mecabインストール

```
$ sudo apt install mecab libmecab-dev mecab-ipadic-utf8
```

●mecabのPython用バインダをインストール

```
$ pip install mecab-python3
```

●mecab-pythonの動作確認

```
$ mecab
すもももももももものうち
すもも  名詞,一般,*,*,*,*,すもも,スモモ,スモモ
も      助詞,係助詞,*,*,*,*,も,モ,モ
もも    名詞,一般,*,*,*,*,もも,モモ,モモ
も      助詞,係助詞,*,*,*,*,も,モ,モ
もも    名詞,一般,*,*,*,*,もも,モモ,モモ
の      助詞,連体化,*,*,*,*,の,ノ,ノ
うち    名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ
```

●パッケージ（gensim）の検索(見つからないパッケージは、my-env内でpipインストール)


```
$ conda search "gensim"
```

●パッケージ（gensim）のインストール

```
$ conda install gensim
```

●パッケージ（pandas）のインストール

```
$ conda install pandas
```

●インストール済みパッケージの確認

```
$ conda list
```
vagrantで構築した環境でDNS解決できていないかもな時

## どうしたの
yumでインストールしようとしたらエラーでた

```
curl#6 - "Could not resolve host: mirrorlist.centos.org;
```

## 確認
参考：[yum installが失敗するときにやったこと。DNS解決 | 屋根裏の部屋](http://www.s-runoa.com/457)

## 対応方法

#### ifcfg-eth0に追記

`/etc/sysconfig/network-scripts/ifcfg-eth0`にDNSサーバ追記

```bash
sudo sh -c "echo -e 'DNS1=8.8.8.8\nDNS2=8.8.4.4' >> /etc/sysconfig/network-scripts/ifcfg-eth0"
```

中身こんなん

```bash:ifcfg-eth0
DEVICE="eth0"
BOOTPROTO="dhcp"
ONBOOT="yes"
TYPE="Ethernet"
PERSISTENT_DHCLIENT="yes"
DNS1=8.8.8.8  #追加
DNS2=8.8.4.4  #追加
```

#### network再起動

```bash
sudo service network restart
```

#### 確認
ping通ってればOK

```bash
ping www.yahoo.co.jp
```

#### おわり
参考：[Vagrantのネットワークで躓いた](https://qiita.com/yoshiya64/items/62d85f645499bf5b7eb6)

## memo
* `ifcfg-eth0` と `ifcfg-eth1` の違い：[自分用のVirutalBoxで仮想マシン設定メモ](https://qiita.com/digdagdag/items/32569809fcd97676e95d)

> eth0 はNATなので外部のネットワークにつながる用のアダプター
> eth1 はホストコンピュータとsshさせる用のアダプター
Excelセルの判定方法（数値、文字列、日付、時刻、論理値）

# はじめに

*こんにちは、のんびりエンジニアのたっつーです。*
*[ブログ](https://www.fast-system.jp/)を運営しているのでよろしければ見てください。*

各種のAPIを用いた結果を以下の画像に記載します。
![18d125d31d80f14dc9c96a97eec4780c.png](https://qiita-image-store.s3.amazonaws.com/0/91697/e8924579-2eb0-ae48-8d3a-54051aab9001.png)

# 使い方

**セルの種別**
判断するセルの種類（数値／文字列／日付／時刻／論理値）

**概要**
各種判定メソッドを用いてセルの形を判断する。
ただし、時刻「23:59:59」などは数値セルの判定となり、数値と時刻の区別が付かないためcell(“format”, 対象セル)の戻り値でD6/D7/D8/D9になる場合は時刻表示として判断する必要がある。

※時刻は、セルの値で0～0.9999999999999で保持され表示書式として「hh:mm:ss」などを指定すると時刻として表示されるためこのような仕様となる。

**判断の順序**
１．VBAでIsDateで日付形式かどうか判定　→　日付確定
２．IsTextで文字列かどうか判定　→　文字列確定
３．IsLogicで論理値かどうか判定　→　論理値確定
４．IsNumberで数値かどうか判定　→　Cell（”format”, 対象セル）の戻り値がD6～D9の場合は時刻確定、それ以外は数値確定
※１と２の順序は逆でも大丈夫です、文字列形式の日付を日付として扱うか文字列として扱うかにより順序を変えてください。

**補足情報（VBAソースコード）**
![b7b799c6e93b537bf53a4c05cb902ec1.png](https://qiita-image-store.s3.amazonaws.com/0/91697/783cc2c5-d268-491c-ce94-dd87cc0f43e5.png)

# 終わりに

*よければ ブログ「[初心者向けUnity情報サイト](https://www.fast-system.jp/)」の方にも色々記載しているのでぜひご参照いただければと思います。*
jupyter notebookで豆腐問題を解決するときになかなかうまくいかなかったのでその解決録



以下の手順でやると色々トラブりはしたが無事日本語設定にすることができた

- フォントのダウンロード(IPAexGothic)
- 設定ファイルのコピー・追記（毎回fontfamilyを設定するのならこれは不要）
- キャッシュを削除
- fontList.jsonを削除！！
- ここら辺でmacごと再起動


現在設定されているフォントの確認

```python
import matplotlib
matplotlib.rcParams.get('font.family')
```

どこのmatplotlibの設定ファイルを見ているのかの確認

```python
import matplotlib as mpl
print(mpl.matplotlib_fname())
```

今使えるフォントの表示

```python
import matplotlib.font_manager as fm
fm.findSystemFonts()
```


```python
plt.rcParams['font.family'] = 'IPAexGothic'
```
Linux / Bash — 2個のキーワードの間で grep する


## 例

- grep の結果に対して grep を実行 (計二回)
- `-A` ( After という意味 ) オプションに適当な大きな数字を渡す ( e.g 10000 )
- `-B` ( Bfter という意味 ) オプションに適当な大きな数字を渡す ( e.g 10000 )

```
echo "V\nW\nX\nY\nZ" | grep -A 10000 W | grep -B 10000 Y
```

```
W
X
Y
```

## Versions

- GNU bash, version 4.4.23(1)-release (x86_64-apple-darwin17.5.0)

## Links

- [Gist](https://gist.github.com/YumaInaura/2ebac8269aafdf1c2615e21ae07a30b9)
- [Medium—imported](https://medium.com/supersonic-generation/bash-grep-between-two-keywords-fe0d91112b9d)








<!-- Update From Qiita API -->

# チャットメンバー募集


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

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





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
[MySQL] field 'カラム名' doesn't have a default valueのエラーの対処法

環境
[Mysql ver5.7.22]
[PHP ver7.1.7]
[Laravel ver5.5.42]

# 1.症状
Mysqlにデータをinsertしようとした際

```
SQLSTATE[HY000]: General error: 1364 Field 'カラム名'
doesn't have a default value (SQL: insert into `〇〇` (`updated_at`, `created_at`)
values...(以下略)
```

との表示が。。
今まで見たことないし、今までとinsertの際異なることと言ったら、別管理で使うgroup_idを持たせたくらい？？

```
+----+----------+-----------------------+---------------------+---------------------+
| id | group_id | name                  | created_at          | updated_at          |
+----+----------+-----------------------+---------------------+---------------------+
|  1 |        0 | name1                 | 2018-01-05 23:59:59 | 2018-01-09 23:59:59 |
|  2 |        0 | name2                 | 2018-02-07 00:00:00 | 2018-02-09 00:00:00 |
|  3 |        0 | name3                 | 2018-08-21 21:26:04 | 2018-08-21 21:26:04 |
|  4 |        0 | name4                 | 2018-08-21 21:26:08 | 2018-08-21 21:26:08 |
+----+----------+-----------------------+---------------------+---------------------+
```

# 2.原因・対策
原因はStrictModeでした。
このモードがtrueであるとInsertやUpdate時に不正な値が入らないよう制限をかけてくれるようです。
こちらは簡単にfalseにできて

```
/config/database.php
'mysql' => [
            'strict' => false
           ]
```
これで完結です。
私の場合Request内にgroup_idの値が入っていなかったため、
値入ってないカラムがあるから処理できないでー😅
ということでエラーが出たようです。
古いパージョンのMySQLではデフォルト設定でないようなのでバージョンを上げたことにStrictModeが原因でうまく動作しなくなってしまうケースもあるようです。💦

私はこれで改善したのですが、一応改善しない場合のためもう一パターン載せておきます。

# 3.SQLモード
MｙSQLにおいて無効な値が入力された場合エラーをだすか、有効な値にして入力するかの設定をになっているのがSQLモード
です。
ONLY_FULL_GROUP_BYや
STRICT_TRANS_TABLESなど
デフォルトで設定が為されています。
詳しい仕様はググっていただけると😀

SQLモードに関してはMySQL内で

```
SET GLOBAL sql_mode="〇〇";
```

で設定可能であるので
ここの値をいじって改善する場合もあるそうなので是非確認していただけるとよいかもです。
obnizのサンプルプログラムを試してみた3（DCモーター）

#概要
- [obnizのサンプルプログラムを試してみた](https://qiita.com/getapojim/items/045441c4ef71ba9efa86)のDCモーター編．
- [「Parts Library for obniz」](https://obniz.io/sdk/parts)に掲載されているものを組み合わせてやってみただけ．
- 「forward」ボタンを押したらモータを回転する．「reverse」ボタンを押したらモーターを逆回転する．
- モータードライバ不要．モーターそのまま挿すだけ．（ここ大事！）

#試したパーツ
- DCモーター

#DCモーター
みのむしクリップで挟んだだけ．
ArduinoやRaspberryPiでDCモーターを使おうとすると「モータードライバ」なる謎のパーツが出てきて一気に難易度が上がり電子工作素人の私にはギブアップ気味だが、これならすんなり受け入れられる．
<img width="225" alt="obnizでDCモーター" src="https://qiita-image-store.s3.amazonaws.com/0/85506/a5edf61a-452b-771d-b363-044b89138647.jpeg">

画面にはボタンを２つ配置．
「forward」ボタンを押したら1秒回転する．
「reverse」ボタンを押したら1秒逆回転する．
<img width="225" alt="obnizでDCモーター" src="https://qiita-image-store.s3.amazonaws.com/0/85506/e0f256cc-1916-fdac-5b65-819474aa98da.png">

```html:private_DCMotor.html
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="https://obniz.io/js/jquery-3.2.1.min.js"></script>
  <script src="https://unpkg.com/obniz@1.9.4/obniz.js" crossorigin="anonymous"></script>
</head>
<body>

<div id="obniz-debug"></div>
<h1>obniz instant html</h1>
<button id="forward">forward</button>
<button id="reverse">reverse</button>
<div id="print"></div>

<script>
var obniz = new Obniz("OBNIZ_ID_HERE");
obniz.onconnect = async function () {

var motor = obniz.wired("DCMotor", {forward:1, back:0});

//モーターを回転する
$('#forward').click(function () {
  motor.forward();
  setTimeout(function(){
    motor.stop();
  }, 1000);
});

//モーターを逆回転する
$('#reverse').click(function () {
  motor.reverse();
  setTimeout(function(){
    motor.stop();
  }, 1000);
});

}

</script>
</body>
</html>
```

動画
画面を映してないので分かりづらいが、最初に「forward」ボタンを押す．
するとモーターが1秒回転して止まる．
続いて、「reverse」ボタンを押す．
今度はモーターが1秒逆回転して止まる．
モーターの先にピニオンギアしか付けていないので回っているのかどうか分かりづらいが、回転する際にモーター自体が横倒しになるのでなんとか見て取れるかと．
「forward」ボタンを押したときと「reverse」ボタンを押したときとでは、のたうち回り方が逆方向なのも見て取れる．

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">obnizでDCモーターを動かす<a href="https://t.co/7Dloj3eMA1">https://t.co/7Dloj3eMA1</a><a href="https://twitter.com/hashtag/obniz?src=hash&amp;ref_src=twsrc%5Etfw">#obniz</a> <a href="https://twitter.com/hashtag/IoT?src=hash&amp;ref_src=twsrc%5Etfw">#IoT</a> <a href="https://twitter.com/hashtag/%E9%9B%BB%E5%AD%90%E5%B7%A5%E4%BD%9C?src=hash&amp;ref_src=twsrc%5Etfw">#電子工作</a> <a href="https://twitter.com/hashtag/JavaScript?src=hash&amp;ref_src=twsrc%5Etfw">#JavaScript</a> <a href="https://twitter.com/hashtag/DC%E3%83%A2%E3%83%BC%E3%82%BF%E3%83%BC?src=hash&amp;ref_src=twsrc%5Etfw">#DCモーター</a></p>&mdash; m (@getapojim) <a href="https://twitter.com/getapojim/status/1032365878258483201?ref_src=twsrc%5Etfw">2018年8月22日</a></blockquote>

#参考
obniz
https://obniz.io/

ArduinoでDCモーターを使う場合
https://trac.switch-science.com/wiki/DCMotorDriver
Python スクリプトで if __name__ == '__main__': を使うとどうなるか

## 使わなかった場合
### ファイル
```module.py
def greet():
    print('hello')

greet()
```

```main.py
import module

module.greet()
print('world')
```

### 実行結果
直接 module.py を実行した場合:

```terminal
$ python module.py
hello
```
module.py で定義されている greet() を main.py で呼び出して利用した場合:

```terminal
$ python main.py
hello
hello
world
```

main.py でモジュールをインポートしただけで `greet()` が実行されるので， hello が 2 回出力されてしまう．

### イメージ
```main+module.py
####### import module #######
def greet():
    print('hello')

greet() # これも展開される
# >hello
#############################

greet()
# >hello（2回目）
print('world')
# >world
```

## 使った場合
### ファイル
```module.py
def greet():
    print('hello')

if __name__ == '__main__':
    greet()
```

```main.py
import module

module.greet()
print('world')
```

### 実行結果
```terminal
$ python module.py
hello
```
```terminal
$ python main.py
hello
world
```

main.py でモジュールをインポートしたときには `greet()` が実行されず，呼び出して初めて実行される．つまり， `if __name__ == '__main__':` 下の処理は，コンソールから直接実行されたときのみ実行され，メソッドとして参照された際には実行されない．

### イメージ
```main+module.py
####### import module #######
def greet():
    print('hello')

''' これは展開されない
if __name__ == '__main__':
    greet()
'''
#############################

greet()
# >hello
print('world')
# >world
```
「ゼロから作るDeep Learning ❷」の環境を、Docker+Jupyter Notebook+PyCharmでさくっとつくる

# はじめに

以下のことをやります。

- 最低限動作するコンテナを作成
- docker-composeでコンテナ内のボリュームをマウント
- Jupyter Notebookで実行できるように
- ブラウザで上記の環境が動作するように
- PyCharmで上記の環境が動作するように

## 補足

### Jupyter Notebookって?
http://jupyter.org/
ブラウザ経由で動作して、対話的にコマンドを実行できるツール。
実行したコマンドや実行結果を保存することができる。

### PyCharmって?
https://www.jetbrains.com/pycharm/
JetBrains社が提供するPython用のIDE。

[最強のPython開発環境 PyCharmのすゝめ](https://qiita.com/pashango2/items/de342abc10722ed7a569)を見れば、何ができるかはだいたい理解できる。Emacs派だが、利用する言語が増えるにつれ設定が面倒になってきたので、試しに利用中。

## なぜPyCharm上で操作したいのか
- オートサジェストの機能が優秀
- デバッガが優秀
- Jupyter Notebookと連携できる

# 実行レポジトリ
- ブラウザ用ブランチ
  - https://github.com/tomoyamachi/deep-learning-from-scratch-2/tree/master
- PyCharm用ブランチ
  - https://github.com/tomoyamachi/deep-learning-from-scratch-2/tree/for_pycharm

2つのブランチの違いとしては、PyCharmは絶対パスで読み込むのに対し、ブラウザ利用は相対パスでimportします。そのため、PyCharmバージョンは↓のシェルスクリプトを利用して、各ファイルのimport部分を変えています。
https://github.com/tomoyamachi/deep-learning-from-scratch-2/blob/for_pycharm/sed_path_to_pycharm.sh

# 起動方法

すでにdocker, docker-composeの環境がある前提で話をすすめると、

```
$ docker build -t deeplearning .
```

で、deeplearningという名前のイメージをビルドして、そのイメージをdocker-compose内で呼んでます。あとはボリュームマウントした、りポートフォワードしたり程度。

# PyCharmでの利用手順

## Interpreterの設定
オートサジェストを賢く使うために、Interpreterを指定します。
ここで指定したいのは先程作成した、deeplearningというコンテナのruntimeです。

Preference > Project: python > Project Interpreterから設定できます。
<img width="767" alt="スクリーンショット 2018-08-23 5.22.15.png" src="https://qiita-image-store.s3.amazonaws.com/0/14275/786f513b-555f-f663-5634-247eac35e0c8.png">
歯車のマーク > Add... > Docker と選んでいくと先程作成したdeeplearningというのが出ていると思いますので、それを選びましょう。

## JupyterNotebookプロセスへの接続

```
$ docker-compose up
deeplearning_1  |     Copy/paste this URL into your browser when you connect for the first time,
deeplearning_1  |     to login with a token:
deeplearning_1  |         http://(コンテナID or 127.0.0.1):8888/?token=トークン
```

PyCharmで新しくJupyterNotebookファイルを作成して、処理を実行しようとするとJupyterNotebookのプロセスが表示されるので、`localhost:8888?token=<トークン>` と入力されればdocker内で走っているプロセスに繋がります。
<img width="881" alt="スクリーンショット 2018-08-23 5.10.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/14275/d748abf6-7f9e-6ccf-cb12-0ad1e313168f.png">


## 注意点
PyCharmでの注意点として、どのフォルダ内にいても実行元パスがルートディレクトリになります。 ※設定次第でどうにかできそうですが、設定方法がわかりませんでした。

そのため、importするときはルートディレクトリからの階層でimportします。/python/ch01/train.pyを利用したい場合は `import ch01.train` です。

読み込むと計算結果とグラフが出てくるのが分かります。
<img width="958" alt="スクリーンショット 2018-08-23 5.26.42.png" src="https://qiita-image-store.s3.amazonaws.com/0/14275/c556fdf2-eb99-3584-0eb9-94af72109c68.png">
https://github.com/tomoyamachi/deep-learning-from-scratch-2/blob/for_pycharm/python/ch01/sample.ipynb

# 最後に
2ヶ月ほど前からPythonを触り始めていて、Word2Vecの概念や、ライブラリの利用方法はわかっていたけど、内部で何をやっているかわかっていないというレベルでした。
そのレベルの自分にとっては、丁寧に、誤解が起こらないように書いてある本だと感じました。
mysql 重複するデータの取得・1件をのぞいた重複データ削除方法

重複するデータの取得および1件をのぞいたデータ削除は以下の形式のクエリが有効です。
## 取得
```sql
select *
from {table}
inner join (
  select {column}
  from {table}
  group by {table}.{group_column}
  having count(*) > 1
) as tmp
on {table}.{group_column} = tmp.{group_column}
```

## 削除
```sql
delete 
from {table}
where {table}.id not in (
  select id 
  from (
    select {max|min|etc}(tmp.id) as id 
    from {table} as tmp
    group by tmp.{group_column}
  ) as tmp2
)
```

以下、実データ例を交えて

# 前提
ブログシステムを想定して 
記事 および 記事に対する コメント、 コメントしたユーザが存在するとします。
データモデルは以下のような形です。
![model (1).png](https://qiita-image-store.s3.amazonaws.com/0/71387/237392ac-5a9b-3254-e4ba-0ce9719634a4.png)

# 主題
「記事に対してユーザは何回でもコメントできること」 という仕様から、
「記事に対してユーザは1回しかコメントできないこと」 という仕様に変わったとします。

# usecase1: 重複しているコメント一覧が欲しい
以下のようなクエリで取得できます。

```sql
select *
from comments
inner join (
  select article_id, user_id, count(*)
  from comments
  group by comments.article_id, comments.user_id
  having count(*) > 1
) as tmp
on comments.article_id = tmp.article_id and comments.user_id = tmp.user_id
```

# usecase2: 最新一件だけ残して重複したデータを削除したい
以下のようなクエリで削除できます。

```sql
delete 
from comments
where comments.id not in (
  select max_id 
  from (
    select max(tmp.id) as max_id 
    from comments as tmp
    group by tmp.article_id, tmp.user_id
  ) as tmp2
)
```