OmniAICreator/Qiita-1.07M huggingface dataset:
Jupyter を Docker で使った時のメモ

久しぶりに更新。
お仕事変わりました。

# はじめに
今月から、機械学習も学ぶ必要があり、
JupyterをDockerで使おうとした時のメモです。
ちょっと、ん？となってので、備忘録的に。

基本的には[こちら](https://qiita.com/kshigeru/items/2cd504e927869163b4c8) を参考にさせてもらいました。

#　環境
PC：Macbook Pro
OS:Mac OS High Sierra
Docker:17.12

# Jupyterのインストール
リンクの記事の通りにコマンドを入力していきます。
ここでは、とくにつまるところもありませんでした。
ちょっと時間がかかります。



```sh
$ docker pull jupyter/datascience-notebook
Using default tag: latest
latest: Pulling from jupyter/datascience-notebook
e0a742c2abfd: Downloading   22.9MB/47.15MB
486cb8339a27: Download complete
dc6f0d824617: Download complete
4f7a5649a30e: Download complete
672363445ad2: Download complete
ecdd51c923e7: Download complete
42885501cf6c: Download complete
a91169574a99: Downloading  3.595kB/8.349kB
4d0f6517ea26: Download complete
665f40dab9d2: Download complete
545196d05ed6: Download complete
4c4f04ecf7e4: Waiting
c4a89ed29043: Waiting
b4c0a15e4c3c: Waiting
4d43858c7566: Waiting
8db425ef5cd8: Waiting
e9c73c3c71e3: Waiting
e83e98458044: Waiting
6071e4b0c1bc: Waiting
ec7741f34b85: Waiting
9e4a532179fd: Waiting
1b2949962cfe: Waiting
f7650f130532: Waiting
8fee9f5dc92a: Waiting
7cd51a2466d5: Waiting
0ba443fcae06: Waiting
151d0e55b16e: Waiting
3194c17312b3: Waiting
ed7b343f1a4b: Waiting
:
:
$ docker images jupyter/datascience-notebook
REPOSITORY                     TAG                 IMAGE ID            CREATED             SIZE
jupyter/datascience-notebook   latest              ce345ce27afc        3 weeks ago         6.18GB
```

6.2GB！？でかいw

# Dockerで起動する

すこし時間がかかりましたが、インストールできました。
さっそく、以下のコマンドで起動しましょう。

```sh
$ docker run -d --name notebook -p 8888:8888 jupyter/datascience-notebook
cb0f75df7bae39d9a3ea3a8912fd5059acfc36afdc63132768c396f0958cd88e
```

# ブラウザでアクセスする
ブラウザをひらき`http://localhost:8888/`にアクセスします。
そうするとトークンが聞かれます。ここで、ん？となりました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/63125/46803398-3217-d018-784f-df1687b83201.png)

docker起動時に出力されてた`cb0f75df7bae39d9a3ea3a8912fd5059acfc36afdc63132768c396f0958cd88e`を入力しても、
Invalid passwordが表示されるだけだったのです。
まぁ、dockerん中入ってコマンド打てばわかるんですけどね。

# dockerに接続する
Jupyterを使用するためのtokenをするため、dockerに接続してみます。

```
$ docker ps -a
CONTAINER ID        IMAGE                          COMMAND                  CREATED             STATUS                      PORTS                    NAMES
cb0f75df7bae        jupyter/datascience-notebook   "tini -- start-noteb…"   6 minutes ago       Up 6 minutes                0.0.0.0:8888->8888/tcp   notebook
$ docker exec -it notebook /bin/bash
jovyan@cb0f75df7bae:~$ jupyter notebook list
Currently running servers:
http://localhost:8888/?token=86c312f14e234dedfeab6e4f02e044c35616ff575fcebff8 :: /home/jovyan
```

ということで、
`http://localhost:8888/?token=86c312f14e234dedfeab6e4f02e044c35616ff575fcebff8`
へアクセスします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/63125/d8e1c853-c234-9856-48b2-6eaddb15f117.png)

アクセスできました！
Pipenvでnpm-scriptsみたいにPipfileへコマンドを書く

## 概要
- pipenvの~~隠し~~機能で、npm-scriptsみたいな機能が実装されていた。
- Pipfileに`[scripts]`セクションを追加すると、~~`npm run <コマンド名>`~~`pipenv run <コマンド名>`で実行できる！
- npm-scriptsでできることすべてができるわけではない~~し、なぜ隠したのかは知らない~~。

★追記★
ドキュメントにも追記されました。
https://pipenv-ja.readthedocs.io/ja/translate-ja/advanced.html#custom-script-shortcuts

## 背景
[pypa/pipenv](https://github.com/pypa/pipenv)に、npm-scriptsのような機能がほしいというissueは以前(2017/10/4)からあった。
[Scripts section in Pipfile #826](https://github.com/pypa/pipenv/issues/826)

ないならしかたないし、自分で作ることも考えていたところ、
[pypa/pipenv](https://github.com/pypa/pipenv)のWikiが更新され、**Ideas**から**Hidden Features**に変わっていた！

## 試してみた

### 環境

|項目|内容|
|---|---|
|OS|macOS High Sierra|
|python|3.6.4|
|pipenv|11.6.3|


### 初期化
まずは、Pipfileを作る。

```
> pipenv install --three
```

PipfileとPipfile.lockが作られた。

```text:Pipfile
[[source]]

url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"


[packages]



[dev-packages]

```

もし、この状態で`pipenv run start`と実行しても、`start`コマンドは存在しないため、当然エラーとなる。

```
> pipenv run start
Error: the command start could not be found within PATH or Pipfile's [scripts].
```


### `[scripts]`セクションを追加する

```text:Pipfile
[[source]]

url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"


[packages]



[dev-packages]

[scripts]

start = "echo aa"

```

そして、再実行すると、`echo aa`が実行される。

```
> pipenv run start
aa
```

## いつ頃実装されてたのだろう？

該当のソースを追ってみたところ、[2018/2/16の修正っぽい](https://github.com/pypa/pipenv/commit/a42d85b1517d6029245a507313868630a72d7426)。

なので、v9.1.0~なら使える。

いいね！
Angular2でGCSのSignedURLのファイル(Blob)を取得する


# Angular2でGCSのSignedURLのファイル(Blob)を取得する

* SignedUrlは正しいし、CORSは＊。


```typescript
  private fetchUrlAsBlob = (url: string): Observable<Blob> => {
    const options = {
      responseType: ResponseContentType.Blob,
      // headers: new Headers({'Content-Type': 'application/x-www-form-urlencoded'}),
    };
    return this.http.get(url, options).map((res) => {
      return res.blob();
    });
  }
```

## Content-Typeをつけると403で`SignatureDoesNotMatch`というエラーが帰って来て困った

```xml:response
<?xml version='1.0' encoding='UTF-8'?><Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Message><StringToSign>GET

application/x-www-form-urlencoded
1521814129
/my-bucket/foo%2Fbar%2Fimages%2Fapple.jpg</StringToSign></Error>
```

StringToSignのタグの中身を見ると、文字列にContent-typeで指定したヘッダー値が含まれている。
署名時に指定したものと異なるので当然シグネチャが違うんでしょうね。
Headerも含めた文字列が署名対象ということかな。
まあ、妥当といえば妥当なきもする。

* エラー解決の決め手になったのはこちら  
  https://github.com/GoogleCloudPlatform/google-cloud-node/issues/1312

ありがとう
Go の、型のない定数の精度

Go の定数には型のないものがあり
> 型のない定数を基本型の値よりも遥かに高い数値精度で表現します
( 『プログラミング言語Go』 p88 )

ということになっている。
じゃあどんだけなんだ、ということで、試してみた。

```ruby:ruby
S=%Q!package main

import (
	"fmt"
)

const(
  a = 1
  b = 0.%s
  c=(a-b)*1%s
)

func main() {
  fmt.Printf( "%%.18f", c )
}!

def test(n)
  code = S % [ "9"*n, "0"*n ]
  File.open( "hoge.go", "w" ){ |f| f.puts(code) }
  %x( go run hoge.go )
end

(1..1000).each do |n|
  p [ n, r=test(n) ]
  break if r.to_f.round!=1
end
```

こんなコードを実行してみたら：

```
[1, "1.000000000000000000"]
[2, "1.000000000000000000"]
[3, "1.000000000000000000"]
«中略»
[138, "1.000000000000000000"]
[139, "1.000000000000000222"]
[140, "1.000000000000000222"]
[141, "1.000000000000029976"]
[142, "0.999999999999806266"]
[143, "0.999999999996822986"]
[144, "1.000000000004281242"]
[145, "1.000000000004281242"]
[146, "0.999999997766779058"]
[147, "1.000000005225119892"]
[148, "1.000000154391934348"]
[149, "0.999999408557861291"]
[150, "1.000014325239323654"]
[151, "1.000163492053947722"]
[152, "0.999417657980827712"]
[153, "0.969584295056026835"]
[154, "0.745834073120020702"]
# command-line-arguments
./hoge.go:10:11: constant too large: 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
```

こんな結果になった。

上記の例だと、10進数で 138桁 ≒ 2進数で458桁 ぐらいまで誤差がみえない。
458 + 53(float64の仮数部) = 511。

で、10進数で 154桁≒2進数で514桁 で死んだ。
たぶん内部表現は 512bit なんだと思う。

ちなみに go は、「go version go1.10 darwin/amd64」です。
bashからfishにaliasを同期するスクリプトを作った

https://qiita.com/doriven/items/0df0154e884621eddd99 の終わりに下記のように記載していたが、それが一応は形になったので公開。
> 環境変数はこの方法で共有できるけど、エイリアスなどは bash/zsh <=> fish の記法の差分でシンプルには行かない。

## Bash2FishAliasesSync

https://github.com/d0riven/Bash2FishAliasesSync
Bashのみ対応の雰囲気を出しているが、読み込み先のファイルを `.zshrc` に変えてあげれば行ける気はする（試してはいない）

### 出来ること

* fish起動時に `.bashrc` に定義されているaliasをfishの文法に変換して吐き出す
* alias定義元ファイルパス、出力ファイルパスは変更可能

### 利点

* bashで使用していたaliasを `config.fish` や `functions/*` に定義せず利用可能
* bash, fishそれぞれでaliasを管理する必要がなくなる(二重管理の手間がなくなる)
  - bashに戻りたくなった or bashのみしか使えない環境でfishだけに定義されたaliasを追記するような手間がなくなる
  - bashのみ、fishのみにしか存在しないaliasがあるという事をなくせる

### 使い方

show https://github.com/d0riven/Bash2FishAliasesSync#usage

## 開発のお話

### 経緯

利点にも書いたとおりでbashの設定ファイルとfishの設定ファイルを二重で管理する必要が出てきそうで、それが非常にだるくなりそうなので作った

### 考慮点

* perl, bash, Makefileなど標準で入っているツールを使用
  - やりたいことが `bash => fish` への記法変換、ファイルの出力のみだった
  - わざわざシェルのために色々なツール導入したくないよね
* 置換ツールはperlを使用
  - sedのGNU, BSDの差で悩みたくなかった & perlはだいたい標準で入っている
* alias定義元が変更された時だけ実行されるようにMakefileを使った
  - ファイルの更新時間を見て更新する実装を省きたかったのでMakefileを使用
  - ただ `.bashrc` などから更にimportしているような場合は反映されないという弱点もあるので都度更新の方が良いかもしれない（要望があれば修正）

### やったこと

`bash <=> fish` の[文法の差異](https://github.com/fish-shell/fish-shell/wiki/Shell-Translation-Dictionary)を参考に正規表現で置換できるように書いただけ。
ただ途中で~面倒~完全対応しなくてもaliasに使っていなさそうなのだったり、正規表現じゃ辛いものは対応していない。

## aliasを定義した後でfuncsaveすれば良くないですか？

それをやり始めると設定ファイルに記述されていない（消した）にも関わらず、設定が残っているものが出て来る。
他に環境を移行するときにそういった前提で死ぬことになるので個人的には状態を持つfunc saveを使うのは避けたいところ。

## 疑問

私が定義しているaliasでは以下のようなbashのaliasがある。

```bash
alias docker-rm='docker ps -a | awk '\''{print $1}'\'' | xargs docker rm'
```

これを今回の変換・同期スクリプトを通すと以下のようになるのだが、何故かaliasが作成されずにfishの関数として定義されてしまう。
aliasで`$argv` を何故か最後につけようとしているのが気になる所。

```fish
⟩ cat ~/.config/fish/b2f_aliases.fish | grep docker-rm
alias docker-rm='docker ps -a | awk \'{print $1}\' | xargs docker rm'

⟩ functions docker-rm
# Defined in - @ line 0
function docker-rm --description alias\ docker-rm=docker\ ps\ -a\ \|\ awk\ \'\{print\ \$1\}\'\ \|\ xargs\ docker\ rm
        docker ps -a | awk '{print $1}' | xargs docker rm $argv;
end
```

他でもそのようなaliasに出ないパターンがあり、どうやら共通しているのは最後にパイプで受けてxargsで処理しようとしていること。
これの理由は分からないが、引数がなければ動作は一緒なのでまぁあまり気にしていない。

## 終わりに

このツールで少しでもaliasのコピペ作業が減ることを祈る。
ツールを作る過程でfishの文法を理解するのにいい勉強になったのは収穫。
ssh keyの紛失等でアクセスできないEC2インスタンスのデータにアクセスする方法

全部[ここ](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/TroubleshootingInstancesConnecting.html)に書いてありますが、要するにアクセス不可能なインスタンスのEBSを一旦デタッチし、他のEC2インスタンスにアタッチすればよいです。

---

## 1. アクセスできなくなったインスタンスを停止

![image.png](https://qiita-image-store.s3.amazonaws.com/0/29000/d56e87da-0f69-0cca-9e1c-03cdf03928a5.png)

## 2. インスタンスのボリュームをデタッチ

- EC2ダッシュボードのナビゲーションペインから「ボリューム」を選択
- 該当のボリュームを右クリック => 「ボリュームをデタッチ」

![image.png](https://qiita-image-store.s3.amazonaws.com/0/29000/726a5207-b039-a71c-36b4-5ce418a8e15b.png)

## 3. __元のインスタンスと同じAZ__に新しいインスタンスを立てる
- インスタンスを立てる際、「ステップ4: ストレージの追加」で先程デタッチしたEBSを新しいインスタンスに追加します。
- [スナップショット]欄でEBSのIDを入力すると出てくるはずです。
- __同じAZでなければアタッチできません！__
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29000/d54f6fff-57ac-4516-5530-ae750a3f11ca.png)

## 4. 新しいEC2インスタンスにssh接続し、ディスクの状態を見る

```sh

[ec2-user@ip-000-00-00-000 ~]$ sudo fdisk -l
WARNING: fdisk GPT support is currently new, and therefore in an experimental phase. Use at your own discretion.

Disk /dev/xvda: 8589 MB, 8589934592 bytes, 16777216 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: gpt


#         Start          End    Size  Type            Name
 1         4096     16777182      8G  Linux filesyste Linux
128         2048         4095      1M  BIOS boot parti BIOS Boot Partition

Disk /dev/xvdb: 8589 MB, 8589934592 bytes, 16777216 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x00000000

    Device Boot      Start         End      Blocks   Id  System
/dev/xvdb1   *       16065    16777182     8380559   83  Linux
```

この場合、`/dev/xvdb1` が手動で追加したEBSになります。

## 5. ディスクをマウントする

```sh
# 適当にマウントポイントを作成
[ec2-user@ip-000-00-00-000 ~]$ mkdir ebs
# マウント
[ec2-user@ip-000-00-00-000 ~]$ sudo mount /dev/xvdb1 ebs
```

## 6. 中身を見てみる

```sh
[ec2-user@ip-000-00-00-000 ~]$ ls ebs
bin  boot  dev  etc  home  initrd.img  initrd.img.old  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var  vmlinuz  vmlinuz.old
```

無事データが見えています。
あとは煮るなり焼くなりお好きにどうぞ。
Simplenote のショートカットキー

Simplenote便利ですよね。テキストオンリーですが、マークダウン記法をサポートしていて、思いついたことをさっとメモ書きできるのは重宝します。テキストしか対応していないので、できるだけキーボードから手を離したくない。そのためにはショートカットを使いこなすしかないじゃないですか。ということで調べてみました。
[Simplenoteのヘルプページ](https://simplenote.com/help/)にすべてのショートカットが書かれていないのは謎……

- Ctrl + `n` : 新しいファイル
- Ctrl + `+`: 文字サイズの拡大
- Ctrl + `-`:文字サイズの縮小
- Ctrl + `0`: 文字サイズをデフォルトに戻す
- Ctrl + `p` : プリント
- Ctrl + `t` : タグエリアとテキストエリアの遷移
- Ctrl + Shift + `j` / `k` : ノートを選択
- Ctrl + Shift + `t` : タグメニューを開く
- Ctrl + Shift + `f` : 検索
- Ctrl + Shift + p : マークダウンのプレビューの切り替え
Heroku x Django x Cloud9

# cloud9でDjangoのWebアプリを作って、それをHerokuにデプロイするためのメモ

# CLOUD9
##create a new project

  confilm your workspace name
  choose a template -> djnago

##create workspace

  remove all (include .gitignore .env etc...)

# CHANGE PYTHON VERSION
```
  $ sudo unlink /usr/bin/python
  $ sudo ln -s /usr/bin/python3 /usr/bin/python
```

#Install djnago for python3
```
 $ sudo pip install django-toolbelt
```

#Create your django project
```
  $ django-admin startproject <project_name>
```

#Edit <project_name>/<project_name>/settings.py
```
  ALLOWED_HOSTS = ["*"]
  <japanese>
```
#Make new project
```
   $ cd <project_name>
   $ python manage.py startapp <app-name>
```


#RUN YOUR SERVICE
```
  $ python manage.py migrate
  $ python manage.py runserver $IP:$PORT

remoteserver
  $ python manage.py runserver 0.0.0.0:8000
```

##WARNING DIRECTORY!!

#MAKE FILE <project_name>/.gitignore
```
  *.pyc
  staticfiles
  db.sqlite3
```

#git 初期化
```
  $ git init
  $ git add .
  $ git commit -m "Djangoアプリを作成した"
```
#heroku用設定
```
  $ echo "web: gunicorn <project_name>.wsgi --log-file -" > Procfile

  $ echo "python-3.6.4" > runtime.txt

  $ pip freeze > requirements.txt
MINIMUM
  dj-database-url==0.5.0
  Django==2.0.3
  gunicorn==19.7.1
  psycopg2==2.7.1
  pytz==2017.2
```


##Add <project_name>/<project_name>/settings.py
```
  # Parse database configuration from $DATABASE_URL
  import dj_database_url
  db_from_env = dj_database_url.config()
  DATABASES['default'].update(db_from_env)

  # Honor the 'X-Forwarded-Proto' header for request.is_secure()
  SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

  # Allow all host headers
  ALLOWED_HOSTS = ['*']

  # Static asset configuration
  import os
  BASE_DIR = os.path.dirname(os.path.abspath(__file__))
  STATIC_ROOT = 'staticfiles'
  STATIC_URL = '/static/'

  STATICFILES_DIRS = (
      os.path.join(BASE_DIR, 'static'),
  )
```

##LOGIN TO HEROKU
```
  heroku login
  heroku create
  heroku config:set DISABLE_COLLECTSTATIC=1
```

##PUSH to HEROKU
```
  $ git add .
  $ git commit -m "Herokuで動くようにした"
  $ git push heroku master
```

##migration
```
  $ heroku run python manage.py migrate
```

## run server
```
  $ heroku run python manage.py runserver
```
テスト等でのreflect.DeepEqualの問題点とその解決策

#等価性
Go言語では==は等値でなく等価ですが、もちろんpointerの参照先まで見てくれるわけではないので、
sliceやmap、pointerまたはそれらを含む構造体などの等価性を比較したい場合
通常、reflect.DeepEqualを使用するものだと思います。

ただ、テスト用途としてはいくつか問題があります。

###reflect.DeepEqual
まずreflect.DeepEqualはunexportの値まで参照します。
基本的に内部表現にまで影響を受けるべきではありませんし
unexportの値を取得するためにunsafeな部分を扱う必要もあるので気持ち悪いです。

また、内部表現が異なっていても等価を表現したいこともあります。
良い例がGo言語1.9で追加されたMonotonic clockの影響を受けたTime型です。
うるう秒の巻き戻しに対応するために導入された経過時間を保持するとかいう生意気なあれです。
2つあるTime型変数がnano秒にいたるまで両方ともぴったり同時刻だったとしてもMonotonicのなんたらがうんたらしていると
DeepEqualの結果はfalseとなり、我々がちんたらしてしまうわけです。おそろしいですね・・・

もちろんTime型だけを比較したいだけであればEqual関数が用意されているのでそれを使えばいいわけですが
Time型が入った構造体などをDeepEqualすると問題になることは極めて稀ですが少しややこしくなってしまいます。

Equal(T)bool関数があればそれを使っていただきたいものですね。
Time型以外にもnet.IPやregexp/syntax.RegexpもEqual関数を持ってますしね。

##go-cmp
というわけで強力安全シンプルな比較ライブラリgo-cmpです。
https : //github.com/google/go-cmp
Equal関数が存在すればそれを考慮してくれますし、
カスタム等価関数を使用してfloatで誤差を許容することもできます。
unexportを扱うか否かも決められます。
何が違うかの文字列も出力してくれます。便利ですね。
しかもFunctional Option Patternも使ってます、おしゃれです。

自分は結局使いませんでしたが、
レポジトリはgoogleでも公式ではありませんが、
まだバグもTODOもあるようですが、
image.RectangleとかEqualじゃなくてEqだったりする標準ライブラリ構造体もありますが、
みなさん。

go-cmp、使いましょう。
RDBのインデックス構造と、インデックス自体の持ち方について

# この記事は
インデックス自体の構造について、そしてインデックスをどのようなデータ構造で保有していくかについてまとめていこうと思う。
図を描くスキルがなかったのでテキストオンリーです。

# インデックス自体の構造体
後述するが、本章は一般的なB+Treeを用いているとする。

### クラスター化インデックス
プライマリキーによるB+Treeのリーフノードに実データが含まれる。
データは「タプル単位でまるごと+メタ情報」というのが多そう。
プライマリキー値によるソートが掛かった状態で検索が行われるので、検索が高速であることが利点。
加えてリーフノードには実データが収められていることから、一次検索でデータのフェッチまで完了するのが魅力。
innoDBやSQL-Server等多くのRDBで採用されているインデックス構造。

### 非クラスター化インデックス
セカンダリインデックスとも呼ばれる。
任意のインデックスキーのリーフノードに二次検索用のハンドラが収められている。
このハンドラには下記のようなパターンがある。

 - プライマリキー値
 - レコード場所情報（ファイルid、ページ番号、ページ内行番号）
 - ヒープに対するポインター

### 複合インデックス
非クラスター化インデックスと同様の概念。
複数のインデックスキー値によるB+Treeであることが差異である。
リーフノードには同様に二次検索用のハンドラが収まる。

B+Tree自体は最初のインデックスキーに基づいて構築されるので、複合インデックスを使った検索を行うためには最初のインデックスキーを検索条件に含める必要がある。

### カバリングインデックス
複合インデックスの亜種にあたる。
複数のインデックスキー値によるB+Treeであることは同様だが、リーフノードに収まるのは（対象カラムの）実データである。
実際に利用するのが一部のカラムだけなら、あらかじめインデックスに実値として持たせることで、二次検索を発生させないというアイデア。

# じゃあどうやって上記のようなインデックスを保有するの？
基本的にインデックスについてググると上記のような情報が真っ先に出てくるわけだが、ほとんどの説明がB+Treeを前提としている。主要なRDBがB+Treeを採用しているからであろうが。
しかし実際にはB+Tree以外の構造を利用しているRDBも存在しているわけで、そこら辺も調べてみた。

### B+Tree
大人気B+Tree。
リーフノードが1レコードに対応しているものもあれば、複数のレコードを含むページに対応しているものも有る。ここらへんは各プロダクトによりまちまちっぽいが、大半はページを返して、線形サーチしていくのが一般的かと。
等値検索・シーケンシャル検索にも対応しており、性能も悪くないので人気っぽい。

### ハッシュテーブル
大規模データに対応できる質の高いhasherがあれば一次検索で実データにたどり着ける。
あくまでhasherに依存するが、データ量が増えても理論上性能劣化しない。
ただし等値検索にしか対応できないため、あまり採用されない。
はずだが、RDBのバックエンドにKVストアを使ってるやつとかも有るので、何か進化があるのかもしれない。

### 範囲表
実表をチャンクという単位で区切り、各チャンクを更にセグメントという単位で区切っていく。
インデックスされる実データをソートして、各セグメントに割り振り、各セグメントは各チャンクに割り振られることになる。
チャンクとセグメントはメタ情報としてインデックスされる実データの最小値と最大値を保有する。
一次検索ではチャンクを舐めて、該当するチャンク内のセグメントを舐めて、その後実表の対応箇所を舐めるというアイデア。
シーケンシャル検索には向きそうだが、B+Treeでいい気もする。
性能がどれくらい変わるのか調べてみたい。

# 感想
基本的に計算量の話でしか無いことが実感できてよかった。
計算量の最適化が図られていればデータ構造はなんでもいいっぽいので、上記例が絶対というわけではなさそう。
今更$.Deferredの使い方

# はじめに

IE11に対応することになったら`Promise`が使えず、今更`$.Deferred`を学習したので記録

* 参考記事

https://qiita.com/varmil/items/269496d3be071a297d76

# 定義側

```javascript
function post(url, data) {
  const defer = new $.Deferred;
  $.ajax({
    url: url,
    data: data,
    type: 'json',
    method: 'POST',
    success: function(res) { defer.resolve(res); },
    error: function(err) { defer.reject(err); }
  });
  return defer.promise();
}
```

# 利用側

## 単発

``` javascript
post('/zun', { doko: 'kiyoshi!' })
  .done(function(res) {
    console.log(res);
  })
  .fail(function(err) {
    console.error(err);
  });
```

## 順々に処理したい場合

```javascript
post('/zun', { zun: 'zun' })
  .then(function(res) {
    console.log(res);
    return post('doko', { doko: 'doko' });
  })
  .done(function() {
    console.log('kiyoshi!');
  })
  .fail(function(err) {
    console.error(err);
  });
```

## 複数並列に処理したい場合

```javascript
$.when(
    post('/zun', { zun: 'zun' }),
    post('/doko', { doko: 'doko' })
  )
  .done(function() {
    console.log('kiyoshi!')
  })
  .fail(function(err) {
    console.error(err);
  });
```
Dockerfileが技術的負債になる前にラベルを付けよう

# そのベースイメージはどのリポジトリで管理されてるの？

Dockerfileを分割管理したまでは良かったけれど、久々にベースのimageを更新しようとしたら、リポジトリどれだっけ？となり、時間を浪費したので解決策を共有します。

# リポジトリのURLをLABELとして明示的に記載しよう

LABELはmaintainerだけ書くとこじゃないですよ。せっかくkey-value形式で何でも書けるので、後悔しないためにもここに運用上必要な情報を記載しておくことをオススメします。

[公式のドキュメント](https://docs.docker.com/config/labels-custom-metadata/)によると、キーが被らないようにドメイン名をひっくり返した値をプレフィックスとして使うよう推奨されています。Javaのパッケージ名と同じですね。

例として、プロジェクト内でベースイメージとして使っている``java-base``と、アプリ用のイメージ``app``のDockerfileがあるとします。ドメイン名が``takitake.tech``だとしたら、``tech.takitake``がプレフィックスとなります。

## ベースイメージ

```dockerfile:Dockerfile.base
FROM openjdk:9-jre
LABEL tech.takitake.base.image.source=http://takitake.tech/base-image.git
```

```bash
$ docker build -t takitake/java-base -f Dockerfile.base .
```

すると、ベースイメージのラベルは以下のようになります。

```bash
$ docker inspect takitake/java-base:latest | jq '.[0].Config.Labels'
{
  "tech.takitake.base.image.source": "http://takitake.tech/base-image.git"
}
```

## アプリイメージ

```dockerfile:Dockerfile.app
FROM takitake/java-base
LABEL tech.takitake.app.image.source=http://takitake.tech/app-image.git
```

```bash
$ docker build -t takitake/app -f Dockerfile.app .
```

そして、最終的なラベルは以下のようになります。

```bash
$ docker inspect takitake/app:latest | jq '.[0].Config.Labels'
{
  "tech.takitake.app.image.source": "http://takitake.tech/app-image.git",
  "tech.takitake.base.image.source": "http://takitake.tech/base-image.git"
}
```

これで、アプリイメージのラベルを確認するだけで、ベースとアプリそれぞれのリポジトリが簡単に確認することができるようになりました。この調子で、ビルドジョブのURL等もラベルとして記載して辛くない運用ライフを送りましょう。
IE11にはファイルをローカルに保存するJavaScriptのAPIが2種類用意されている。

ダウンロード処理をJavaScriptで実装する場合、言い換えればBlobオブジェクトをローカルストレージに保存する処理をJavaScriptで制御する場合、IE11では`window.navigator.msSaveBlob`と`window.navigator.msSaveOrOpenBlob`というふたつのAPIが用意されています。このふたつのAPIの違いですが、呼び出した際に表示されるポップアップが異なります。たとえば以下のようなhtmlファイルを用意します。

```html
<!DOCTYPE html>
<html>
  <body>
    <input type='button' value='msSaveBlob' id='msSaveBlob' />
    <input type='button' value='msSaveOrOpenBlob' id='msSaveOrOpenBlob' />
  </body>

  <script>
    window.onload = function() {
      var blob = new Blob([JSON.stringify({hello : 'world'})], {type : 'application/json'});

      document.getElementById('msSaveBlob').addEventListener('click', function(e){
        window.navigator.msSaveBlob(blob, 'msSaveBlob.json')
      });

      document.getElementById('msSaveOrOpenBlob').addEventListener('click', function(e){
        window.navigator.msSaveOrOpenBlob(blob, 'msSaveOrOpenBlob.json')
      });
    }
  </script>
</html>

```

これをファイルに保存したのち、IE11で開いてみると以下のような画面が表示されるはずです。なお一部にローカルパスが表示されているので黒塗りにしています。見えても特に害はないはずですが、なんとなく恥ずかしいので隠しました(´・ω・｀)

![キャプチャ - コピー.PNG](https://qiita-image-store.s3.amazonaws.com/0/105859/b79a6cd5-1b66-df10-7d01-fc07f54d3931.png)

このうちmsSaveBlobボタンを押下する、すなわち`msSaveBlob`を呼び出すと以下のようなポップアップが表示されるはずです。

![キャプチャ1 - コピー.PNG](https://qiita-image-store.s3.amazonaws.com/0/105859/c742787d-db3f-c965-6daf-fae37da874e8.png)

次にmsSaveOrOpenBlobボタンを押下して、`msSaveOrOpenBlob`を呼び出した場合は次のようなポップアップが表示されると思います。

![キャプチャ3 - コピー.PNG](https://qiita-image-store.s3.amazonaws.com/0/105859/2d302795-a2c1-6db9-6d16-bc630ea8fe35.png)

つまり`msSaveBlob`の場合はダウンロードファイルをローカルに保存するだけ、一方`msSaveOrOpenBlob`の場合は保存せずにファイルを開くことが可能になります。__ふたつのAPIがある理由はいろいろ調べたもののよくわからなったのですが、現代的なIE11プログラミング(?)では特別な理由がない限り、基本的には`msSaveOrOpenBlob`を利用するのがよさそうです。__
WindowsでDNSキャッシュをクリアする方法

### 方法

コマンドプロンプトで下記を実行

```
ipconfig /flushdns
```

下記で現在の状態も確認出来る。

```
ipconfig /displaydns
```

### 雑記

普段あまり使うことは無いと思うけど、開発向け等に自前管理しているドメインで不意にアクセス出来なくなったりした場合にキャッシュクリアすると解決したりする事もある。
[Ruby]DiscordにWebhookでメッセージを投稿する

# Webhook URLを取得

1. `サーバー設定`の`Webhooks`タブを開く
	![スクリーンショット 2018-03-13 22.15.56.png](https://qiita-image-store.s3.amazonaws.com/0/222294/2be85325-82cf-a415-6801-fe25849065c0.png)

2. `Webhookを作成`をクリックする
	![スクリーンショット 2018-03-13 22.15.56.png](https://qiita-image-store.s3.amazonaws.com/0/222294/d425f973-cf58-6b1d-1ece-b09788ce8cb5.png)

3. オプション設定をおこなう
	* `チャンネル`：メッセージを投稿するチャンネルの選択
	* `名前`：メッセージを投稿する際のユーザ名
	* `WEBHOOK　ICON`：メッセージを投稿する際のユーザのアバターの編集

4. `WEBHOOK URL`をコピーする
	後ほど使います。

# WebhookにPOSTするプログラムの作成

投稿したいメッセージを先ほど取得した`WEBHOOK URL`に対してPOSTするだけです。
[Faraday](https://github.com/lostisland/faraday)を使ってPOSTしてみました。

```ruby:discord_webhook.rb
require 'faraday'

conn = Faraday.new
conn.post do |req|
  req.url '取得したWEBHOOK URL'
  req.headers['Content-Type'] = 'application/json'
  req.body = '{ "content" : "投稿したいメッセージ" }'
end
```

`投稿したいメッセージ`のところに`test`と`aaaaaaaa`を入れて動かしてみたら、こんな感じで投稿できました。

![スクリーンショット 2018-03-13 22.35.05.png](https://qiita-image-store.s3.amazonaws.com/0/222294/0ac8257b-64dd-10e7-2e3b-2ed12e01f2e7.png)

その他、[指定のフォーマット](https://discordapp.com/developers/docs/resources/webhook#execute-webhook)に沿って`body`をいじれば、ユーザ名を変えたりttsでメッセージを読み上げさせたりできそうです。
WARNING ITMS-90076: "Potential Loss of Keychain Access. が出たとき

##警告
アプリを配信しようと、いつも通り「Upload To App Store」を押したら、最後にこんな警告が出た。
<img width="742" alt="Screen Shot 2018-03-13 at 20.13.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/203954/cb788558-90af-d1ac-d69a-b20829e11412.png">

##対処法
google翻訳にかけてみると、「アップロードはうまくいったけど、アプリケーションIDが今までと違うくない？Keychainデータにアクセスできなくなるけど大丈夫？」という内容らしい。

もっと調べてみると、どうやらCSRファイルが一致しない時に起こるのだとか。さらに、一度アプリを提出すると２回目以降は警告が出なくなるらしい。

だから問題なければ無視すればいいと思う。

##考えられる原因
最近、アカウントを変更したためアプリ譲渡を行なった。証明書が前のアカウントに紐づいてるから、このエラーが起こった可能性が高い。

##参考
[stack-overflow : Will warning “Potential loss of keychain access” automatically go away in the next update I push to app store?](https://stackoverflow.com/questions/41374988/will-warning-potential-loss-of-keychain-access-automatically-go-away-in-the-ne)

##コメント
間違ってたらコメントください。
sublime + docker +pylsで入力補完

# はじめに
前回は、sublime + venv + pylsで入力補完できるようにしました。
https://qiita.com/lisp719/items/5a47e3e8342c11fb90b9

今回はdocker環境でのやり方を記事にします。

# dockerでpythonの開発環境を立てる
${PWD}でホストとゲストのパスを揃えます。
あとは、pipのpackageをキャッシュしたり適当に。

```docker-compose.yml
version: "3"

services:
  app: &app
    image: python:3.7
    volumes:
      - .:${PWD}
      - bin-data:/usr/local/bin
      - pip-data:/usr/local/lib/python3.7/site-packages
    working_dir: ${PWD}

volumes:
  bin-data:
  pip-data:
```

# pylsをインストール
pipでpylsをインストールします。
[all]を指定するとlintとかもインストールされます。

```shell
docker-compose run app pip install python-language-server[all]
```

入力補完のテスト用にbottleもインストール。

```shell
docker-compose run app pip install bottle
```

# sublimeの設定
LSPのインストールまでは前回と同じです。
docker-composeでpylsを立ち上げるようにcommandを指定します。

```LSP.sublime-settings
{
	"clients":
	{
		"pyls":
		{
			"command": ["docker-compose", "run", "--rm", "app", "pyls"],
			"enabled": true
		}
	}
}
```

# 動作確認
設定が終わったので適当なpythonファイルを開いてみます。
何故かファイルを開いた直後は補完が効きません。
1度改行をして入力すると補完が効くようになります。
かなり謎な動作なのですが、一度補完が効くようになれば1行目でも動作するようになります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/93971/93f46329-1d5c-17c2-f5e9-ddfa9ec55103.png)

入力補完が効いていますね。

# おわりに
pyls自体はpython版lsp(language-server-protocol)実装なので、lspプラグインなどがあるエディタなら同じような感じで行けると思います。
また、色んな言語のlspがあるようなので他の言語でも入力補完などが可能っぽいです。

lsp良いですね。
TWE-Lite で無線タグアプリのIDを変更する

## TWE-Lite の開発環境の入手
TWE-Lite で<a href="https://qiita.com/jagarl/items/a0363eeac22c2caeec0b">温湿度センサーHDC1000</a>の制御と、同じく<a href="https://qiita.com/jagarl/items/3f0bda846aba62eef801">温湿度センサーSHT31</a>の制御を I2C 経由でできるようになったが、デフォルトの超簡単！TWELITE標準アプリでは常時電源がONになっているので、特にボタン電池ではすぐに電気を使い切ってしまう。無線タグアプリを使えば数秒に一回だけ起動して測定、および無線経由でのデータ送信を行うようになるので、電力消費をかなり減らすことができる。一方、無線タグアプリは限られた種類のセンサーしかサポートしていないため、SHT31 も HDC1000 も使うことができない。使いたければ、自分でソフトウェアを書き換える必要がある。

ソフト開発の環境は、今回は TWELITE-BLUE を使うので、2014/8月号 SDK というものになる。<a href="https://mono-wireless.com/jp/products/TWE-NET/TWESDK.html">ここ</a>からダウンロードして c:\ に展開、c:\TWESDK\eclipse.cmd を実行すればeclipse が立ち上がる。

## 無線タグアプリのソースの取りだしとプロジェクトのビルド
ソフトウェアのほうは、<a href="https://mono-wireless.com/jp/products/TWE-APPS/App_Tag/download.html">ここ</a>から無線タグアプリのソースファイルをダウンロードし、c:\TWESDK\Wks_ToCoNet にコピーする（ワークスペースはどれを選んでもいい）。次に、eclipse からファイル→インポート→既存プロジェクトをワークスペースへでインポート。コピーしたフォルダを選べばインポートできる。

eclipse でのコンパイルは プロジェクト→プロジェクトのビルド。また、無線タグアプリには無線タグの子機、親機、中継機などのソースがすべて含まれており、プロジェクト→構成のビルド→アクティブにする、のメニューでビルドするアプリを切り替えて各バイナリを作成する。

## ソースを書き換えてアプリがデフォルトで使用する ID を変更する 
さて、TWE-LITE では各プログラムに ID と無線通信用のチャネルが割り振られており、同じ ID、チャネル のプログラム同士（親機と子機）がやりとりをするようにしている。もしも近くに無線タグアプリを使っている人がいた場合、混信してしまうので、できれば自分の親機・子機のネットワークに固有のIDを使うほうが望ましい。ソフトウェア上では Common\Source_User\config.h に ID 等の設定があり、たとえば以下のようになっている。

````cpp:Common\Source_User\config.h
/* Specify the PAN ID and CHANNEL to be used by tags, readers and gateway */
#define APP_TWELITE_ID		0x67720102
#define APP_ID				0x67726305

#define APP_NAME            "App_Tag"
#define APP_TWELITE_CHANNEL	18
#define CHANNEL				15

// リモート設定用
#define APP_ID_OTA       0x67726405
#define CHANNEL_OTA		25
````

無線タグアプリは、設定によってデフォルトの超簡単！TWELITE標準アプリにデータを送信したり、無線ごしに設定の更新を行う OTA を行うことがある。そのため、自分自身の ID である APP_ID 以外にこれらのアプリ用の ID もソースに書きこまれている。これらを変更する必要はないので、アプリのデフォルトのIDを変更したければ、上記の APP_ID と CHANNEL だけを書きかえれば良い。また、親機ならシリアル通信で +++ と打つ、子機なら MODE2 ピンを GND に落としてリセットすると、設定画面に入ることができる。設定画面でIDとチャネルを書きかえれば、EEPROM に書きこまれて次回の起動時からは新しいID,チャネルを使うようにできる。

それでは実際にテストしてみよう。ソースのAPP_IDを変更して親機、子機用のバイナリをビルドする。つぎに、それぞれのバイナリを TWE-LITE に書きこんでみよう。設定画面で APP_ID が変更されたか見てみると・・・IDは変更されていなかった？？？

## ソースの APP_ID を書き換えることで TWE-Lite 子機の ID を変更する
いろいろやってみると、一旦、超簡単！TWELITE標準アプリを書きこんでリセットしてから +++ と打って設定画面に入り、S を打って設定をセーブしてから、新しい無線タグアプリのバイナリを書きこむと、新しい APP_ID に設定された。

これは EEPROM 上に書きこまれた ID, チャネル等とソースに書かれた（デフォルトの）ID,チャネルが競合するために起きるらしい。無線タグアプリなどのアプリにはそれぞれ、versionとデフォルトのIDがある。EEPROMのバージョンとプログラムのバージョンが合わない(今回で言えば、無線タグアプリだったチップに超簡単！TWELITE標準アプリを書き込んだ）場合、EEPROM の内容は無視してデフォルトのIDやチャネルなどを使用する。一方、もともと無線タグアプリがTWE-LITE に書きこまれていた場合、新しいバイナリが書きこまれても同じソフトウェアと認識されるので、ソースに書きこんだ APP_ID ではなく、EEPROM に設定された ID が使われるようだ。
I2S DAC で作るアンプ付きBluetoothAudioReceiver

# 概要

aptX, aptX Low Latency, SBC and AAC 対応のちょっと音にこだわった、15w+15wパワーアンプ付きBluetooth Audio Receiver を作る。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/187531/49a57608-b23d-99e5-52df-2af9141094f3.png)

※内部配線を雑にしたせいで、残念な感じになっています。。。

# BOM (Bill Of Materials)

パーツ例。
写真の例では以下を使用しています。

|パーツ名|値段|入手先|備考|
|:--|--:|:--|:--|
|BluetoothAudioModule|700～1700円程度|eBay [CSRA64215](https://www.ebay.com/itm/Bluetooth-I2S-Converter-Board-Support-4-2-I2S-output/272758209072?ssPageName=STRK%3AMEBIDX%3AIT&_trksid=p2057872.m2749.l2649)||
|I2S DAC|1000円程度|eBay [PCM5102](https://www.ebay.com/itm/ASSEMBLED-PCM5102-DAC-decoder-I2S-player-32bit-384K-beyond-ES9023-or-PCM1794/311704263039?hash=item489305997f:g:3F4AAOSwLnBX48-r) or [ES9023](https://www.ebay.com/itm/Audiophonics-DAC-Sabre-ES9023-I2S-vers-Analogique-24bit-192KHZ-ll/301441579838?epid=1131149443&hash=item462f517b3e:g:YccAAOSwD0lUj2EL)|MCLK入力不要なI2S-DAC|
|パワーアンプ|300円程度|eBay [TDA7297](https://www.ebay.com/itm/AC-DC-12V-TDA7297-2x15W-Digital-Audio-Amplifier-DIY-Kit-Dual-Channel-Module/201891167411?hash=item2f01a6bcb3:g:y5MAAOSwc49Y8JJL)|15w+15w 激安パワーアンプ|
|ケース|108円|Seriaで購入|8cm四方くらいのもの|
|SP端子|約408円|https://www.amazon.co.jp/gp/product/B06X9517QV/ref=oh_aui_detailpage_o07_s00?ie=UTF8&psc=1||
|DCジャック|120円|http://akizukidenshi.com/catalog/g/gC-06569/|内側から取り付けるタイプじゃないと工作が難しくなる|
|各種配線材|||適宜|

## Bluetooth Audio Receiver

CSRA64215系のものを使用。I2S出力が使える！

基板の有無などによって、以下の種類かあるので好きなものを使う。
モジュール単体は、1mmピッチなので配線はちょっと大変。

|値段|概要|
|--:|:--|
|600円程度|[eBay モジュール単体](https://www.ebay.com/itm/2-8-4-2V-Bluetooth-Audio-Module-Bluetooth-Receiver-Universal-Module-CSRA64215/112659656941?hash=item1a3b09f0ed:g:R08AAOSwevlaG-x~)|
|1000円程度|[eBay 基板付き](https://www.ebay.com/itm/CSRA64215-Bluetooth-V4-2-Audio-Module-I2S-Call-USB-Sound-Card-APTX-LL-TWS/232208330639?epid=839364860&hash=item3610b1ef8f:g:hTsAAOSwq1NZhVwr)|
|1700円程度|[eBay 電源回路&ペアリングスイッチ付き](https://www.ebay.com/itm/Bluetooth-I2S-Converter-Board-Support-4-2-I2S-output/272758209072?ssPageName=STRK%3AMEBIDX%3AIT&_trksid=p2057872.m2749.l2649)|

工作例では一番下の物を使用。ペアリングスイッチは便利。
モジュール単体or基板付きで工作するなら、スイッチ付ければ 次の曲、前の曲もできる模様。

このモジュールの配線図は以下が参考になります。(ロシア語)

http://lampcore.ru/diy-%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D1%8B/%D1%82%D0%B5%D1%81%D1%82-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B9-bluetooth-bt625/

## I2S DAC

MCLKが不要なもの、かつ、I2S Format対応のものを使用する。
RightJustFitとかはNG.

|ジャンル|例|
|:--|:--|
|王道|PCM5102, ES9023|
|NOS DAC|該当なし?|
|ダークホース|AK449x 系|

※AK449x系は、本来MCLK入力が必要ですが、MCLK=BCLK ででも音出るようです。
ただし、音は本来の音よりも悪くなると思われます。興味ある方は自己責任でやってみてください。

## パワーアンプ

2回目の登場となる 290円アンプです。
[NanoPi-NEOとMPDとLCDとI2S-DACとTDA7297で音楽再生サーバ(完全体)](https://qiita.com/blue-7/items/07ad5661607799053d44)と同じように、改造して使います。

電源電圧は Bluetooth,I2S DAC がありますので、今回も5vでの使用です。

# 組み立て

頑張って組付けます。

# 結果

- Windows機から音出せた
- Android機から音出せた
- iPhoneから音出せた

# おまけ

## CSRA64215 の BCLK波形

![image.png](https://qiita-image-store.s3.amazonaws.com/0/187531/210ac381-c70a-4720-9049-37103155ebd7.png)

ジッターがひどいです。
RaspberryPiと同じように周波数優先なのだと思われます。
【Swift】タプル

# 実行環境
- Swift4
- Xcode9.2

# タプルとは
順序付けされた値の集合体のこと。
異なる型の値をひとつの変数、または定数で扱えるようになる
ただし、値の追加、削除、また繰り返し処理などはできない。

# メリット 
- 構造体やクラスを使わずに型の違う値の詰め合わせを簡単に作ることができる
- 関数呼び出しの戻り値に複数の値を戻すコードが簡単に書くことができる

# 定義
var 変数名 = (値1, 値2, 値3, ・・・)
let 定数名 = (値1, 値2, 値3, ・・・)

# 使い方
## 宣言と値の取得
```swift:値のみの宣言の場合
// タプルの宣言
let tpl = (123, "ABC", true)

// 値の取得（インデックス番号）
print(tpl.0) // 結果: 123
print(tpl.1) // 結果: ABC
print(tpl.2) // 結果: true
```
```swift:型付き宣言の場合
// タプルの宣言
let tpl: (Int, String, Bool) = (123, "ABC", true)

// 値の取得（インデックス番号）
print(tpl.0) // 結果: 123
print(tpl.1) // 結果: ABC
print(tpl.2) // 結果: true
```
```swift:ラベル付き宣言の場合
// タプルの宣言
let tpl = (count: 123, alpha: "ABC", isFlag: true)

// 値の取得（ラベル指定）
print(tpl.count) // 結果: 123
print(tpl.alpha) // 結果: ABC
print(tpl.isFlag) // 結果: true

// 値の取得（インデックス番号）
print(tpl.0) // 結果: 123
print(tpl.1) // 結果: ABC 
print(tpl.2) // 結果: true
```
```swift:型付き／ラベル付き宣言の場合
// タプルの宣言
let tpl: (count: Int, alpha: String, isFlag: Bool) = (count: 123, alpha: "ABC", isFlag: true)

// 値の取得（ラベル指定）
print(tpl.count) // 結果: 123
print(tpl.alpha) // 結果: ABC
print(tpl.isFlag) // 結果: true

// 値の取得（インデックス番号）
print(tpl.0) // 結果: 123
print(tpl.1) // 結果: ABC
print(tpl.2) // 結果: true
```

## 値の代入
```swift:タプルと変数の個数が同じ場合
// タプルの宣言
let (count, alpha, isFlag) = (123, "ABC", true)

// 値の取得
print(count) // 結果: 123
print(alpha) // 結果: ABC
print(isFlag) // 結果: true
```
```swift:タプルと変数の個数が違う場合（エラー発生）
// タプルの宣言
// コンパイルエラー発生
let (count, alpha) = (123, "ABC", true)
```
```swift:タプルと変数の個数が違う場合（エラー回避）
// タプルの宣言
// アンダースコアで数合わせすることにより、エラー回避
let (count, alpha, _) = (123, "ABC", true)

// 値の取得
print(count) // 結果: 123
print(alpha) // 結果: ABC 
```
## 値の更新
```swift
// タプルの宣言
var tpl = (count: 123, alpha: "ABC", isFlag: true)

// 値の更新
tpl.count = 456
tpl.alpha = "DEF"
tpl.isFlag = false

// 値の取得（ラベル指定）
print(tpl.count) // 結果: 456
print(tpl.alpha) // 結果: DEF
print(tpl.isFlag) // 結果: false
```
## 値の入れ替え
```swift
var num1 = 1
var num2 = 2

// 値の入れ替え
(num1, num2) = (num2, num1)

// 値の取得
print(num1) // 結果: 2
print(num2) // 結果: 1
```
# タプルは価渡しである
```swift
var tpl1 = (1, "ABC")
var tpl2 = tpl1

tpl1.0 = 10

print(tpl1) // 結果: (10, "ABC")
print(tpl2) // 結果: (1, "ABC")
```
ちょっと8946を触ってみる

こんにちわ

[グローバルセンス株式会社](https://gb-sense.com)のskanehiraです。

偶々8946ってサイトを見つけたので
触ってみたいと思います。

# **8946とは？**
[8946](http://www.hackerschool.jp/hack/)とはハッキングを通して
セキュリティを学ぶことができるサイトです。

ハッキングと言っても
実際ハッキングをするわけではなく
用意された問題を解くだけの様です。

# **実際解いてみる**
[Take#1](http://www.hackerschool.jp/hack/take1.php)が一番簡単らしい
ということで解いてみます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/66178/df64fd31-fd58-9971-a397-1636173adb69.png)

なんのヒントもなくいきなりログインIDとパスワード入力画面が表示されましたね。
ログイン出来たら正解らしいので
htmlを見たり、実際適当に入力して動きを見ました。

そして、あっさり正解しました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/66178/a1d0411e-7539-8820-4710-83e25bb4a029.png)

答えは書けないのでヒントだけになりますが
htmlを見れば一発です。
本当に簡単だった…

# **最後に**
そういえば
[ハッカーズバー](https://hackers.bar/)ってとこが前々から気になっていたので
近々行ってこようと思います。

行ってきた感想をそのうち書くかもしれません。
SHT31 を TWELITE で制御する

## 温湿度センサー SHT31 と TWE-Lite を購入する
<a href="https://qiita.com/jagarl/items/a0363eeac22c2caeec0b">
TWE-Lite で温湿度センサ HDC1000 を取り付け、</a>I2Cデバイスを本格的に制御できることがわかったので、部屋のいくつかの場所や外気温度を調べるために複数のチップを購入することにした。HDC1000 は湿度表示があきらかに変だし、すでに秋月電子に売っていないので、他のものを検討する。TWE-LITE の無線タグアプリは温湿度計としてはSHT21 に対応しており、気圧までオプションがついた BME280 というのにも対応している。

値段をみるとSHT21は１チップ（基板配線済み） 1500円、チップだけだと600円程度、BME280 は秋月で1080円、あと秋月では SHT31 という SHT21 の上位バージョンが950円で売っていた。ただし、SHT31とSHT21はi2cコマンドの互換性はない。また、同様の試みをしている人のページをみてみると、SHT31 は温度・湿度の精度が割と良くて広く使われているらしい。そこで、秋月電子で TWE-LITE の DIP 版と SHT31 、それに CR2032 のボタン電池とそのソケットをセットで４つずつ購入した。

## SHT31 と TWE-Lite を接続する
SHT31 は５本ピンがあり、ADR ピンをGNDにするかVccにする（プルアップされている)かでi2cアドレスを44,45で選択できる。消費電力を小さくする必要もあるので、ADR 端子はオープンにして  i2c アドレス 45 で運用しよう。あとはVcc, GND, SCL, SDA の各端子を TWE-LITE にはんだ付けした。

![DSC_0264.JPG](https://qiita-image-store.s3.amazonaws.com/0/241288/6effd527-9db9-3be3-9f3a-adfd51d76df5.jpeg)
(基板の裏側)
![DSC_0265.JPG](https://qiita-image-store.s3.amazonaws.com/0/241288/63b4da82-f77e-c174-7160-82e8121b503a.jpeg)
(基板の表側)
GND とVccはちょうどTWE-LITE のVcc,GNDの位置に一致するので、ピンコネクタをさしてそのままはんだ付け。SCL,SDA は細いワイヤではんだ付けしてつないだ。

![DSC_0267.JPG](https://qiita-image-store.s3.amazonaws.com/0/241288/04276eff-fc5d-8178-1a9c-d322a0d0b8fa.jpeg)
また、電池ソケットのピンがピンコネクタの穴にちょうどはまるので、電池をGND端子上のピンコネクタにぬきさしすることで電源のON/OFFとした。Vcc の方は適当な長さの細いワイヤではんだ付けする。なお、今回は DIP の足は必要ないのでつけていないが、必要であえば付けられるように、DIPの足と干渉しないように作成した。
![DSC_0268.JPG](https://qiita-image-store.s3.amazonaws.com/0/241288/8fffc014-71a7-f2df-91a3-8ee39972b909.jpeg)
後ろのピンコネクタは UART 信号を TWILITE-Rに送るためのコネクタ。TWILITE-R につなぐとプログラムを書き込んだり、UARTに出力されるメッセージをパソコンから確認したりできる。

## 無線経由で TWE-Lite 親機から子機の SHT31 の I2C 通信を行う
ここまでできて電源をONにすると、デフォルトの超簡単！TWELITE標準アプリで無線通信できりるようになった。あとは、前にやった HDC1000 と同じように無線経由で I2C 通信すれば良い。SHT31はいくつか測定のモードがあり、一定時間ごとに自動的に測定してデータを送ってくれたりする。また、測定精度を三段階で変えられる。ここでは HDC1000 と同じように、測定ごとにコマンドを送り、測定精度は中とした。(No clock stretch, repeatability medium)。そうすると、まずは 0x24 0x0b というコマンドを書き込む。その後、6ms 以上
待ってから I2C バスを読み込むと、測定が終わっていればデータが帰ってくる。前に書いたように ID は 45 番なので、コマンドは以下のようになる。
:788800014524010BX
 (88:cmd)(01:W) (45:i2cアドレス) (24:コマンド1)(01:書き込みバイト数)(0B:コマンド2)
として温度読み込み開始。次に
:78880002450006X
 (88:cmd)(02:R) (45:i2cアドレス) (06:読み込みバイト数)
と打ち込んだら
:7889000201066D6D63561D33
         01:成功 06:読み込みバイト 6D6D(63): 温度(CRC) 561D(33): 湿度(CRC)
なお、3バイト目と 6 バイト目は CRC チェックサムだが、とりあえずは気にしなくてもよい。計算してみると、
温度 = 0x6D6D × 175.00 / 65536 - 45.00 = 25.528 ℃
湿度 = 0x561D × 100.0 / 65536 = 33.638 %
成功。温度、湿度の読み込みができた。温度・湿度ともに、他の温湿度計の表示とだいたい合っているので正しそうだ。これで、前のHDC1000用のスクリプトを少し書き換えるだけで一定の時間ごとの温度計読み込みができるようになった。
書籍「低レベルプログラミング」アセンブリ実行 Docker 環境の構築

# はじめに

* [書籍「低レベルプログラミング」](https://www.amazon.co.jp/dp/4798155039/)では VMWare イメージで実行環境が提供されているが Docker を使いたかったので構築したメモ。
* 書籍内ではアセンブリの後に C もやるが、まだ最初なのでとりあえずアセンブラが動くところまで。

# 環境構築

* Dockerfile の作成

```Dockerfile
FROM debian:9

RUN apt-get update
RUN apt-get install -y binutils nasm gdb
RUN apt-get install -y vim
```

* Docker イメージの作成

```sh
docker build -t low-level-programming .
```

# 実行

* [公式リポジトリ](https://github.com/Apress/low-level-programming)のクローン

```
git clone https://github.com/Apress/low-level-programming
```

* コードをマウントして Docker イメージの実行

```
cd /path/to/low-level-programming
docker run -it -v $(pwd)/listings:/listings low-level-programming bash
```

* hello.asm のコンパイルと実行

```
cd /tmp
nasm -felf64 /listings/chap2/hello/hello.asm -o hello.o
ld -o hello hello.o
./hello
```

# デバッガの実行

* Docker コンテナ内でデバッガを有効にするために実行オプションを追加する
  * [参考URL](http://www.cyamax.com/entry/2018/02/09/070000)

```
docker run -it --cap-add=SYS_PTRACE --security-opt="seccomp=unconfined" -v $(pwd)/listings:/listings low-level-programming bash
```

* gdb コマンドでデバッガを起動する

```
# コンパイルとデバッガの実行
nasm -felf64 /listings/chap2/hello/hello.asm -o hello.o
ld -o hello hello.o
gdb hello

# アセンブリ向けレイアウトの表示
(gdb) layout asm

# レジスタを表示するレイアウト
(gdb) layout regs

# ブレークポイントを設定する
(gdb) b _start

# 実行
(gdb) run

# 一ステップ実行
(gdb) si

# print $"レジスタ名" でレジスタの値を表示
(gdb) p $cl

# 終了
(gdb) quit
```
Elm pipe vs Elixir pipe

　へぇー、ElixirってElmと同じpipeオペレータ( |> )が使えるんだ。便利だねー、って思っていたら、よく見ると違う。まるっきり違うのならともかく、表記法も同じで使い方もほぼ同じ、ちょっとだけ違うっていうのは勘違いしがちなので、心に刻んでおくためのメモです。

　Elmの場合、6 |> f 3　は f(3,6) と解釈されます。curryが考慮されている？

```sh:elm
$ elm-repl
> f a b = a / b
<function> : Float -> Float -> Float
> 6 |> f 3
0.5 : Float
```

　Elixirの場合、6 |> f.(3)　は f(6,3) と解釈されます。

```sh:elixir
$iex
iex(1)> f = fn x, y -> x / y end
#Function<12.99386804/2 in :erl_eval.expr/5>
iex(2)> 6 |> f.(3)
2.0
```

　以上
Mac の Composer で SSL エラーでうまく動かなくなった時の対処法 (OS アップグレード後)


Mac OS X Sierra から High Sierra にアップグレードした後に Composer (PHP パッケージ) の調子がおかしく composer install しても

```
Downloading (failed)       
Downloading (failed)    Failed to download xxxx/xxxx from dist: The "https://api.github.com/repos/xxxx/xxxx" file could not be downloaded: SSL operation failed with code 1. OpenSSL Error messages:
ror messages:
error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version
Failed to enable crypto
failed to open stream: operation failed

```

と OpenSSL のエラーでちゃんとレポジトリからダウンロードできなかったというエラーが起こって四苦八苦していましたが、Mac OS のアップグレードをした後に、X Code のコマンドラインツールの設定がおかしくなっていたのが原因でした。

# OpenSSL のパス確認方法

```
xcode-select -p
```

```
/Applications/Xcode.app/Contents/Developer
```

と表示されるとおかしいので、修正する。

```
sudo xcode-select -switch /Library/Developer/CommandLineTools
```

再度

```
xcode-select -p
```

で、`/Library/Developer/CommandLineTools` であると修正完了。

参考
MacのhomebrewでOpenSSLがビルドエラーになる場合の対処方法
https://techracho.bpsinc.jp/hachi8833/2016_09_09/25454
Windows Subsystem for Linux の日本語化

日本語化とユーザー環境のカスタマイズの備忘録

1.日本語化等の実施

```bash:
# --- Linuxモジュールの最新化 -------------------------------------------------
  sudo apt-get update
  sudo apt-get -y upgrade
  sudo apt-get -y dist-upgrade
# --- 追加モジュールのインストール --------------------------------------------
  sudo apt-get -y install task-japanese ssh curl
# --- 日本語環境の設定 --------------------------------------------------------
  sudo dpkg-reconfigure locales
  sudo update-locale --reset
  sudo update-locale LANG=ja_JP.UTF-8 LANGUAGE=ja_JP.UTF-8
# --- Windows共有フォルダのマウント先の作成 -----------------------------------
  sudo mkdir /mnt/share
```
2.ユーザー環境のカスタマイズ

```bash:
echo -e "set number\nset tabstop=4\nset list\nset listchars=tab:>_" > ~/.vimrc
echo -e "location\nprogress-bar\nremote-time\nshow-error" > ~/.curlrc
```
3.SSHの起動

```bash:
sudo /etc/init.d/ssh start
```
4.Windows共有フォルダのマウント例

```bash:
sudo mount -t drvfs '\\server\share' /mnt/share
```
IDCFクラウドのUbuntu16.04サーバーでサブドメインを使えるようにするまで

# 作業環境
OS：Windows 10 Pro Build 16299.248
コンソール：Tera Term v.4.98 64bit

# サーバー
OS：Ubuntu 16.04
Apache：2.4.18
DNS：お名前.com
サーバーへの接続：ssh

# 前置き
私は今回初めてUbuntuサーバーに触れてます。というかLinuxサーバー自体初心者です。ですのでここに書いてある内容で間違いや説明不足な部分もあると思いますがご容赦下さい。

# 作業の流れ
Apache2のインストールまでの作業と初期設定、お名前.comでのドメイン登録についてはここでは省略します。

## ポート開放
いくら下に書かれた作業をこなしても80番ポート、空いてなきゃ何の意味もないです。(HTTPSなら443番ポート)
IDCFクラウドのコントロールパネルから80番ポートを開放してください。

## Apache等の情報を非表示にする

```shell:ターミナル
sudo vim /etc/apache2/conf-available/security.conf
```
25行目あたりにServerTokensがあるのでこれをProdにする
続いて35行目辺りのServerSignatureもOffにする

## sites-available内にconfファイル作成

ここではファイル名はhoge.confとします。

```shell:ターミナル
sudo cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/hoge.conf
sudo vim /etc/apache2/sites-available/hoge.conf
```
```apache:hoge.conf
<VirtualHost *:80>
	ServerNmae (サブドメインの名前)
	ServerAdmin (管理者の連絡先)
	DocumentRoot (コンテンツの場所)
	ErrorLog (エラーログのファイルの場所)
	CustomLog (アクセスログのファイルの場所)
</VirtualHost>
<Directory (コンテンツの場所)>
	Options Indexes
	Options FollowSymLinks
	AllowOverride none
	Require all granted
	Order allow,deny
	Allow from all
</Directory>
```
一応最低限こんな感じですね。たぶん…。
それぞれのタグの意味はググればどこにでも書いてあるのでここではその辺の説明は省略します。

## 設定の反映

```shell:ターミナル
sudo a2ensite /etc/apache2/sites-available/hoge.conf
sudo service apache2 reload
```

これでOS側の作業はおしまいです。
ちなみにconfファイルに問題があると、apache2でエラーが起きます。
実は今回hoge.confのDirectoryのOptionsなんですが、いろんなページで見てたら１行で書いていたんですね。でもその通りやったらapache2のリロードの際にエラー起こしちゃって、それで２行にしたら正常に行ったのでこうしました。

## Aレコードの登録

お名前.comの人は[ここ](https://www.onamae.com/guide/details.php?g=18&_ga=2.185049004.461434390.1520933436-1749458428.1519897795)見てやって下さい。下手な説明よりよっぽどいいです

# トラブルシューティング
私が遭ったトラブルです。
まず上に書いてあること最低限やったかを確認し、それでもダメだった場合ここ見てください。

## ページが開かない
DocumentRootで指定したフォルダにindex.htmlを適当に作ってください。なくても普通は404が出てくれると思うけど…。あと、もしAレコード登録直後でしたら、すぐには開けないので時間置いてアクセスしてみてください。

## apache2が起動しない

```shell:ターミナル
sudo service apache2 status
```
ここのログ読んでみてください。confファイルの内容に問題があるとここに出ます。

# 最後に
私もLinuxでサーバーやったの初めてなので詳しい人からすると「なんで！？」みたいな部分も多々あると思います。
でも、私と同じ初心者の皆さんがこの記事見てサブドメインに挑戦してくれたらなと思います

# 参考
- [1台のApache Web Serverに複数のドメインを設定する(@terrymさん)](https://qiita.com/terrym/items/ba988394fbe6099b4485)
- [CentOS設定記録3 apacheサーバー設定編(@ka_iwashitaさん)](https://qiita.com/ka_iwashita/items/de33d59721a7f349224f)
- [Apache2@Debianでのバーチャルホスト設定まとめ(@ninnekoさん)](https://qiita.com/ninneko/items/87a76f0f1dc6d82500fb)
- [Apache2.4ではconfの書き方が変わりました。(@tukiyo3さん)](https://qiita.com/tukiyo3/items/61202fdec60af854b3fe)
- [VirtualHost Examples - Apache HTTP Server Version 2.4](https://httpd.apache.org/docs/2.4/en/vhosts/examples.html)
intellijでSpring Bootプロジェクトを作成、起動してもすぐに終了する

IntteliJでSpring Bootを始めようと思って、
プロジェクトを作成、実行した時につまづいたときのことです。

# 症状

IntelliJでSpring Inirializerを使ってプロジェクトを作ってmainからRun Applicationを実行したところ、すぐにアプリケーションが終了してしまいました。


```console
2018-03-13 20:45:42.270  INFO 7595 --- [      Thread-12] o.s.j.e.a.AnnotationMBeanExporter        : Unregistering JMX-exposed beans on shutdown

Process finished with exit code 0
```

eclipseからの実行ではうまくいくし、gradleからの実行もうまくいく。。。
なぜかIntelliJからのRun Applicationからは起動しない。。。

# 解決方法

build.gradleのdependenciesにあるspring-boot-starter-tomcatの依存構成をprovidedRuntimeからcompileにすれば起動しました。

```gradle:build.gradle
dependencies {
	compile('org.springframework.boot:spring-boot-starter-web')
	// providedRuntime('org.springframework.boot:spring-boot-starter-tomcat')
	compile('org.springframework.boot:spring-boot-starter-tomcat')
	testCompile('org.springframework.boot:spring-boot-starter-test')
}
```

# 感想

同じようなことでハマった人がいるんですね。
[Spring Boot app shuts down automatically](https://intellij-support.jetbrains.com/hc/en-us/community/posts/206670989-Spring-Boot-app-shuts-down-automatically)

ただ、実際の運用を考えるとspring-boot-starter-tomcatの依存構成は変更しないほうがよさそうですね。
IntelliJからgradleでbootRunを実行して開発を進めます。
デバッグもできるし。
XCTContext.runActivity(named:)を使ってユニットテストを構造化する

# XCTContext.runActivity(named:) について

 - Xcode9から追加された機能
 - https://developer.apple.com/documentation/xctest/xctcontext/2923506-runactivity

 これを使うとテストが構造化できるようになります🙆


# XCTestの弱点

XCTestはテストの構造化に弱かったため、１つのテストメソッドにいろんなテストを詰め込んでしまい、
「これは何をしているテストなんだ？」と頭を抱える羽目になったり、
頑張ってテストメソッドの命名ルールを作ったりしてテストパターンを切り分ける工夫をしていました。

それを嫌って、Spec記法が使える Quick を導入しているプロダクトも多いのではないかと思います

しかし、Xcode9から追加された　XCTContext.runActivity(named:) 　を使うことでXCTest単体でもテストの構造化ができるようになりました



# 書き方

```swift
class VersionTests: XCTestCase {
    
    override func setUp() {
        super.setUp()
        print("setUp")
    }
    
    override func tearDown() {
        print("tearDown")
        super.tearDown()
    }
    
    func testCompareVersion() {
        XCTContext.runActivity(named: "バージョン比較") { _ in
            XCTContext.runActivity(named: " < ") { _ in
                var resultFalse = Version(rawString: "1.2.0") < Version(rawString: "1.1.0")
                XCTAssertFalse(resultFalse)
                resultFalse = Version(rawString: "1.2.10") < Version(rawString: "1.2.9")
                XCTAssertFalse(resultFalse)
                resultFalse = Version(rawString: "2.0.0") < Version(rawString: "1.9.99")
                XCTAssertFalse(resultFalse)
                resultFalse = Version(rawString: "2.0.1") < Version(rawString: "2.0.1")
                XCTAssertFalse(resultFalse)
            }
            
            XCTContext.runActivity(named: " > ") { _ in
                var resultTrue = Version(rawString: "2.1.0") > Version(rawString: "2.0.0")
                XCTAssertTrue(resultTrue)
                resultTrue = Version(rawString: "3.0.0") > Version(rawString: "2.0.0")
                XCTAssertTrue(resultTrue)
                resultTrue = Version(rawString: "3.0.1") > Version(rawString: "3.0.0")
                XCTAssertTrue(resultTrue)
            }
        }
    }
}
```

テストを実行しテスト結果を見てみると…
![image.png](https://qiita-image-store.s3.amazonaws.com/0/48695/4acb4e15-fcfc-5f23-2878-d16ad57a030c.png)

このように、テスト結果も構造化された状態で見ることができます


setUp() や tearDown() については今までどおり、各テストメソッドの開始前後に呼び出されます

ブロック単位で前後に処理をはさみたい場合は自力で実装するしかないようです。。もしくは他に手段があったら教えてください:bow:


お手軽に使えるので、QuickなどOSSを導入することに躊躇しているならば、こちらを使ってみると良さそうです。
　　
　　
　　
※テスト対象の Version は以下の記事を参考に作らせていただいてます。
SwiftではバージョンはStructにして演算子オーバーロードで比較したらどうでしょう - Qiita
https://qiita.com/yimajo/items/ed496545962c83e3f9bf
destroy_allとdelete_all

## 概要

`ActiveRecord::Relation` の `destroy_all` と `delete_all` のメソッドの違いを検証

## destroy_all

- `records` の要素1つ1つに対して `destroy` と `reset`  を実行
- レコード数の多い条件に対して実行する際は要注意

```ruby
    def destroy_all
      records.each(&:destroy).tap { reset }
    end
```

https://github.com/rails/rails/blob/fe6adf43e124f4c9132e5a88a80ebba3f10fd2cb/activerecord/lib/active_record/relation.rb#L378

## delete_all

- 直接SQLを実行し、対象のレコード全てに対して `DELETE` を実行する
- レコード数が多い場合は `destroy_all` よりも早く実行できるが、 `destroy` は呼ばれないので、 削除時のバリデーションや `callback` 等が呼ばれないことに要注意
- `INVALID_METHODS_FOR_DELETE_ALL` ( = `distinct` `group` `having` )等の集計関数を含んでいる場合は `raise` される

```ruby
    def delete_all
      invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select do |method|
        value = get_value(method)
        SINGLE_VALUE_METHODS.include?(method) ? value : value.any?
      end
      if invalid_methods.any?
        raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
      end

      if eager_loading?
        relation = apply_join_dependency
        return relation.delete_all
      end

      stmt = Arel::DeleteManager.new
      stmt.from(table)

      if has_join_values? || has_limit_or_offset?
        @klass.connection.join_to_delete(stmt, arel, arel_attribute(primary_key))
      else
        stmt.wheres = arel.constraints
      end

      affected = @klass.connection.delete(stmt, "#{@klass} Destroy")

      reset
      affected
    end
```

https://github.com/rails/rails/blob/fe6adf43e124f4c9132e5a88a80ebba3f10fd2cb/activerecord/lib/active_record/relation.rb#L400