OmniAICreator/Qiita-1.07M huggingface dataset:
【Looking Glass】複数カメラに対応してみる

しばらくLookingGlassから離れていたら、僅か数ヶ月というのに随分とテックデモが充実していますね。
GWを使って遅ればせながら[#るきはく](https://twitter.com/hashtag/%E3%82%8B%E3%81%8D%E3%81%AF%E3%81%8F)や[#るきみと](https://twitter.com/hashtag/%E3%82%8B%E3%81%8D%E3%81%BF%E3%81%A8)を辿って情報収集をしています。

その中でも[@koichi3さん](https://twitter.com/koichi3)の「ディスプレイ複数視点映像の未来」が素晴らしかったので、まずはLookingGlass＋複数カメラで何かゲームが作れないかを考えつつ自分でも試してみました。

あと、LookingGlass以外ではハサミ型の力触覚デバイスも気になりました！

#はじめに

やっていることは「ディスプレイ複数視点映像の未来」と全く同じです。
実装方法についてもほぼ同じ内容なので、まずは以下の資料を読むことをお勧めします。

https://www.slideshare.net/KuraokaKouichirou/ss-141469833

検証環境はUnity2018.3.13f1＋<b>HoloPlaySDK-0.1.4</b> です。
（HoloPlaySDK-1.0.0だとLookingGlassが認識されないんです…）

#結果

まずは結果から。

https://twitter.com/aodama/status/1123308964530180096

LookingGlassの左半分が現実空間、右半分が霊的空間で、それぞれの空間で出来ることをやってクリアしていく～みたいな内容を考えていたんですが、ネタ切れでゲーム自体は没に。

というか<b>「別に切り替えはボタン操作でいいんじゃないの？」</b>の一言で撃沈…

ちなみにQuilt画像はこんな感じになっています。
中央の黒部分は左右の画面が直接混ざらないようにするための緩衝領域です。
![190501_ゲームのQuilt.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227733/3dfab3fe-fb99-9613-e49b-84c8fa639f26.jpeg)


#実装

没ったゲームは結構面倒な処理になっているのでシンプルなシーンで説明することにします。
LookingGlass上で実行するとこんな感じです。
分かりやすいようにカメラ毎に背景色を変えています。

https://twitter.com/aodama/status/1123322847198232576

シーン上のカメラ（Capture）はこんな感じでユニティちゃんの正面と左右の合計3個配置しています。
![190501_カメラ（Capture）を複数配置.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227733/12fb6be0-a43d-43f9-3854-6b2352fe564a.jpeg)

カメラ（Capture）の追加はQuiltのInspectorのボタンで出来ます。
![190501_Captureの追加.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227733/51e62056-48c5-a2fa-b75d-d502737aa405.jpeg)

Quilt内で各CaptureをレンダリングしQuilt画像上に配置します。
この配置を制御することで、LookingGlassを見る角度にあわせた表示を行えます。

この辺は公式資料の説明が分かりやすいです（いつのまにか日本語に！）
https://docs.lookingglassfactory.com/ja/Appendix/how-it-works/

もしカメラの切り替わり境界が気になる場合は黒画面等を入れることで緩和できます（3枚ぐらいあれば十分）
![190501_Quiltレイアウト.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227733/c20bd4f8-ce89-1db8-acba-dd9af00f422f.jpeg)

複数のCaptureをレンダリングする部分はQuilt.csのOnRenderImageメソッド内です。
やっていることは簡単で、出力するQuilt画像上の位置にあわせてif分でCaptureを切り替えているだけです。
<b>今回はあくまでテストなので出力は45枚・Capture3個決め打ちのコードになっています</b>


```
...

// render views
for (int i = 0; i < tiling.numViews; i++)
{
    // broadcast the onViewRender action
    if (onViewRender != null && Application.isPlaying)
        onViewRender(i, tiling.numViews);
    
    // タイル位置に合わせてCaptureを切り替える
    var capture = captures[0];
    
    if ( i >= 0 && i < 12)
        // 左
    else if (i >= 12 && i < 15)
        continue;               // 黒
    else if ( i >= 12 && i < 30)
        capture = captures[1]; // 中央
    else if (i >= 30 && i < 33)
        continue;              // 黒
    else if ( i >= 33)
        capture = captures[2]; // 右

    if (!capture || !capture.isActiveAndEnabled)
        continue;

    ...
```

これだけで複数Capture対応のレンダリングが出来ました。
汎用的に使うのであれば、出力タイル枚数依存しない処理や設定するパラメータはInspectorに出した方がいいですね。


#まとめ

なかなかLookingGlassを活かしたゲームを考えるのは難しいです。
まだHoloPlaySDK-1.0.0は使っていませんが、もしかしたらもっと簡単に複数カメラ対応出来るかもしれません。

---
© Unity Technologies Japan/UCL
http://unity-chan.com/contents/guideline/
Tinker BoardへPython3.7をインストール

やり方は**raspberry pi**にインストールする方法とおんなじです。
[**python.org**](https://www.python.org/)からソースを取得します。
`$ wget https://www.python.org/ftp/python/3.7.3/Python-3.7.3.tgz`

ソースファイルを展開します。
`$ tar xvf Python-3.7.3.tgz`

**Python-3.7.3**ディレクトリが作成されているので移動します。
`$ cd ./Python-3.7.3`

**README.rst**を確認すると**Build Instructions**に書いてあったのでその通りに。
`$ ./configure`
`$ make`
`$ make test`
`$ sudo make install`

**make install**でこんなエラーが出ました。

```
File "/home/******/Python-3.7.3/Lib/ctypes/__init__.py", line 7, in <module>
    from _ctypes import Union, Structure, Array
ModuleNotFoundError: No module named '_ctypes'
Makefile:1130: ターゲット 'install' のレシピで失敗しました
make: *** [install] エラー 1
```

apt-getでもpipでもなんでもインストールしてしまえば良いのだろうけれどモジュール名が分からないのでgoogleで検索。
**libffi-dev**のインストールで解決するとありました。

**libffi-dev**をインストール
`sudo apt install libffi-dev`

もう一度`sudo make install`でインストールし直しました。

バージョンの確認をします。

```
$ python3 --version
Python 3.7.3
```
アルゴリズムメモ

AtCorderを始めて、色々とアルゴリズムをメモしときたくなったので投稿。増えたら追記していきます。

# 2*nの全探索
[ABC 002 D 派閥](https://atcoder.jp/contests/abc002/tasks/abc002_4)

```py:ABC002D
N,M = map(int,input().split())
bond_list = []
for i in range(M):
    bond_list.append(list(map(int,input().split())))

ori_list = list(range(1,N+1))
all_list = []
ans = 0
for i in range(2**N):
    num = i
    each_list = []
    for j in range(N): 
        if num % 2 == 1:
            each_list = [ori_list[N-1-j]] + each_list
        num = num//2

    if len(each_list)*(len(each_list)-1)/2 > M:
        continue
    is_ok = True
    for e_i in range(len(each_list)):
        for e_j in range(e_i+1,len(each_list)):

            if not [each_list[e_i],each_list[e_j]] in bond_list:
                is_ok = False

    if is_ok:
        ans = max(ans,len(each_list))
print(ans)
```
関数だけ切り出し

```py
#　2のｎ乗でリストの中身を選ぶor選ばないで作成できるリストを全列挙する
def Combinations(N,ori_list):
    all_list = []
    for i in range(2**N):
        num = i
        each_list = []
        for j in range(N): 
            if num % 2 == 1:
                each_list = [ori_list[N-1-j]] + each_list
            num = num//2
        all_list.append(each_list)
    return all_list
```

# 深さ優先探索
[ATC 001 A 深さ優先探索](https://atc001.contest.atcoder.jp/tasks/dfs_a)

```py:ATC_A
H,W = map(int,input().split())
maze = []
for i in range(H):
    maze.append(input())
reached = [[False]*W]
for i in range(H-1):
    reached.append([False]*W)

#デフォルトでは1000回再帰するとエラーする
import sys
sys.setrecursionlimit(10000000)

def dfs(x,y):
    if x<0 or x>=W or y<0 or y>=H or maze[y][x] == '#':
        return
    if reached[y][x]:
        return
    reached[y][x] = True

    dfs(x+1,y)
    dfs(x-1,y)
    dfs(x,y+1)
    dfs(x,y-1)

for h in range(H):
    for w in range(W):
        if maze[h][w] == 's':
            start_x,start_y = w,h
        if maze[h][w] == 'g':
            goal_x,goal_y = w,h
dfs(start_x,start_y)
if reached[goal_y][goal_x]:
    print("Yes")
else:
    print('No')       
```

再帰難しい...理解深めてたくさん書いて慣れたい。
iOSエンジニアがはじめてのReactで技術書レビューサイトを作った話

## 技術書レビューサイト
早速だが、作った技術書レビューサイト「Compile Books（コンパイルブックス）」を貼る。
良かったら使ってみて欲しい。

https://compilebook.com/


<img width="439" alt="スクリーンショット 2019-05-01 2.41.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295440/6d219829-a82e-a418-551e-6d7c5c182f16.png">

## 主な機能
### レビューを見る
レビューを見たい本をタイトルで検索して、書籍詳細ページでレビューを見ることが出来る。
レビュー項目は技術書に特化した項目を設定しているため、一般的な本のレビューサイトやECサイトのレビューサイトと異なり、技術書として有用かどうか？を知ることが出る。
まだまだレビュー自体が少ないが、これからどんどん増やせるように努力したい。

### レビューする
もちろんレビューを投稿することができる。
選択性の4項目は必須、フリーワードの項目は任意項目としている。
<img width="610" alt="スクリーンショット 2019-05-01 2.50.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295440/2ae2c64a-5561-a7fe-289a-527bf9e376b9.png">


### お気に入り
書籍詳細のページの「気になる」ボタンを押すことで、特定の本を自分のお気に入りリストに追加することが出来る。
レビュー、気になるの履歴はマイページから確認することが出来る。
レビューを見る、投稿するだけでなく、技術書の管理サービスとしても使ってもらえる。


# 技術的なお話
ここからは「Compile Books」で使用した技術スタックについてまとめて、感想や解説を書いていく。

### React、Redux、ReduxSaga
ここで私が説明するまでも無いフロントエンドにおける組み合わせの主流の1つです。
Reactのライフサイクルという概念は普段iOSの開発を行っている私にとって、理解しやすかったです。
逆にStoreで全てのStateを管理するという概念には馴染みがありませんでしたが、面白いと思いました。


### GoogleBooksAPI
「Compile Books」を作るにあたって一番のハードルは、書籍情報をどのように取得するか。
今回は「GoogleBooksAPI」を使用することで、書籍情報を取得している。
実際の使い方についてはQiitaでもいくつか記事が上がっているのでそちらを参照して欲しい。
注意点としては、

- 一部の書籍でサムネイル画像のURLが無い
- 電子書籍もレスポンスに含まれるためISBNが無い書籍も存在する
- 独自のidが書籍ごとに振ってあり、そのidで検索することも可能

がある。
レスポンスをしっかりハンドリングして表示する必要があった。
「GoogleBooksAPI」を使用する場合は注意して欲しい。

### AWS(lambda, dynamodb, cognito, s3. cloudfront, route53, amplify, ACM)
バックエンドや認証はすべてAWSに任せている。
特に今回はドメインを取得してサイトを公開する必要があったが、そこまで全てAWSで出来てしまうのは非常に助かった。
また、普段Realmを使用している私にとっては「dynamodb」の存在は心強かった。



# 最後に
「技術書に特化したレビューサイト欲しいな、よし作ろう！」と思って作った「Compile Books」であるが、まだまだ不完全な箇所が多いのは見てもらうと分かる。

こんなバグあったよ、とかこんな機能欲しい！という要望があればお知らせ頂けると嬉しい。
発表者ツールで動画が流れない　【PowerPoint】

発表当日のリハで，用意していたスライド内の動画が流れなくて大焦りしたので自分用にメモ．

##今回直面した問題
PowerPointの発表者ツールで埋め込んだ動画が流れない
・動画はmp4形式，10MB弱
・リンクではなく埋め込んだ

##環境
1. Microsoft Office 365 ProPlusのPowerPointを使用
2. OS : Windows10 Pro (1803) | RAM : 16.0GB

##問題分析
・動画プレイヤーで動画を再生すると普通に流れるので動画は壊れていない
・HDMIをつないでスライドショーをするとつながらない
（スライドショーでなくアニメーションウィンドウから流してやると流れる）
・PCも投影先もディスプレイとして認識はされている

##解決法
1. 詳細設定の「ハードウェアアクセサれーたを無効にする」「スライドショー実行中にハードウェアグラフィックアクセサレータを無効にする」をONにした
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278022/274a2f53-49a8-6ff7-4db6-23d7fdb44c83.png)

2. 動画の形式をasfにした

２つのことを実行したがどうもasfにしたことが決定だったっぽいです
今まではこんな問題にあったことが無かったのでとても焦りました><
ところでasf形式って何？
https://ja.wikipedia.org/wiki/Advanced_Systems_Format
Dart x VSCode を Docker 上に構築 (1)

Dart の開発環境も Docker で整えてしまうと楽です。今回の記事では、VSCodeもDockerに含めてみました。開発環境をまるごとDockerで管理できるので、管理がしやすいのでオススメです。

# 登場人物
### Dockerとは
Linux上でコンテナーでアプリを動作させる環境です。アプリケーションとライブラリーを同一のコンテナーで固めて、使い回すことができます。
https://ja.wikipedia.org/wiki/Docker

### VSCode
https://ja.wikipedia.org/wiki/Visual_Studio_Code
Microsoft製のEditorです。Dart Pluginを入れると、補間機能などが使えて便利です。

### Code-Server
VSCodeをWebサービスとして動作させることができる凄いやつです。
https://github.com/cdr/code-server


# 環境を作ってみる

https://github.com/kyorohiro/dart-code-server

### (1) dockerfile を書く

```dockerfile
FROM ubuntu:18.04

RUN apt-get update
RUN apt-get install -y curl wget gnupg less lsof net-tools git apt-utils -y


# WORKDIR
RUN mkdir /works
WORKDIR /works

# DART
RUN apt-get install apt-transport-https
RUN sh -c 'curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -'
RUN sh -c 'curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list'
RUN apt-get update
RUN apt-get install dart -y
ENV PATH="${PATH}:/usr/lib/dart/bin/"
ENV PATH="${PATH}:/root/.pub-cache/bin"

RUN pub global activate webdev
RUN pub global activate stagehand

#
# CODE-SERVER
RUN wget https://github.com/cdr/code-server/releases/download/1.939-vsc1.33.1/code-server1.939-vsc1.33.1-linux-x64.tar.gz
RUN tar xzf code-server1.939-vsc1.33.1-linux-x64.tar.gz -C ./ --strip-components 1

```

### (2) docker image を走らせる
 
```
docker build -t dart_vscode .
docker run -p 8443:8443 -p 8080:8080 -it dart_vscode bash
# docker の中で
mkdir /works/w
/works/code-server /works/w --allow-http --no-auth
```

### (3) and 'http://127.0.0.1:8443/' を ブラウザーで開く

![root_page.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54192/8aefed41-e82e-ef99-6fa6-70ce03dc957e.jpeg)


# 試しに何か作ってみる

### (1) Terminal -> New Terminal on VSCODE

### (2) Terminal 上で以下を入力

```
root@8e5699b9caa4:/works/w# stagehand web-simple
root@8e5699b9caa4:/works/w# pub get
root@8e5699b9caa4:/works/w# webdev serve --hostname=0.0.0.0
```

### (3) 'http://127.0.0.1:8080/' を ブラウザーで開く

![sample_web.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54192/2735f126-0915-bdd4-b830-667bca78ca85.jpeg)



以上です。

Code-Serverがとても便利でしたね。
https://github.com/cdr/code-server

終わり。

今回のコードは以下にまとめました。
https://github.com/kyorohiro/dart-code-server
CloudBuildを利用してGAEへのデプロイを自動化


普段、GitLabを利用してソースの管理をすることが多いので、今まではGitLabCIを利用して色々CI/CD周りを作ることが多かったのですが、最近、GCPをメインで使っているので、CloudBuildで出来ないかなと言う事で実験して見ました。
今回、作成した構成は、以下の通りです。自分の為のメモ書きです。
# 構成図
![スクリーンショット 2019-05-01 2.08.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16794/bd72aceb-1c30-3f62-1098-b197fb33d6b2.png)

## GitLab->CloudSourceRepositories間の連携
下記記事を参考に設定しました。
https://qiita.com/tarosaiba/items/850042d6383ac5b7ef47

## CloudBuildの設定
ここに関しては、UIに表示された通りに選択する事で基本的に詰まる事はありませんでした。
リポジトリの直下に専用のフォルダ(hogehoge)を作成してあったので、各コマンド実行時にcd してから実行しています。
gaeの古いバージョンを定期的にけさいないと上限までいってしまうので、一つ前のバージョン以外は削除するようにしました。

```sh
steps:
- name: 'gcr.io/cloud-builders/yarn'
  entrypoint: '/bin/bash'
  args: [ '-c',
          'cd hogehoge/ && yarn install'
        ]
- name: 'gcr.io/cloud-builders/yarn'
  entrypoint: '/bin/bash'
  args: [ '-c',
          'cd hogehoge/ && yarn run build'
        ]
- name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: '/bin/bash'
  args: [
    '-c',
    "cd hogehoge && gcloud app versions list --service=default | grep default | sort -rk 4,4 | awk '{print $2}' | tail -n +2 | xargs -I {} gcloud app versions delete {}",
  ]
- name: 'gcr.io/cloud-builders/gcloud'
  entrypoint: '/bin/bash'
  args: [
    '-c',
    "cd hogehoge && yes | gcloud app deploy",
    ]                                                                                                                                                                                         
```

## CloudBuildからGAEへデプロイ
CloudBuildのサービスアカウントにGAEのデプロイ担当、サービス担当を追加しないとデプロイが出来ずCloudBuildでエラーとなるので、必要な役割はデプロイ先に応じて変更が必要なようです。

## まとめ
実際、設定して見るとそこまで難しくはなかったのですが、GitLabとCloudSourceRepositoriesの連携でかなり手間取りました(^.^)
Twitch APIを利用してみよう

# はじめに
Twitchには[便利なAPI](https://dev.twitch.tv/docs/api/reference/)が提供されています。
そんなAPIの存在を知らない人、知っててもなんとなくめんどくさくて使ってない人は割と多いと思います。というわけでTwitch APIを使ってみるまでの解説記事となります。
なお、Twitch APIは頻繁に更新されており、この記事執筆時点のバージョンは`New Twitch API`となっています。前バージョンの[v5](https://dev.twitch.tv/docs/v5/)はdeprecatedとなっており、実際の廃止時期は未定です。
~~バージョン名がNewってなんなの~~

# 対象読者
- [公式の手順](https://dev.twitch.tv/docs/api/)読むのがめんどくさい人

# 利用手順
## 1. 利用登録

- [Twitch Developers](https://dev.twitch.tv/login)にアクセスします。
- `Twitchアカウントでログイン`をクリック。
 
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399407/afcf67d2-a4f3-75f8-6b62-a11e5c71b1e7.png" width=50%>

- `許可`をクリック

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399407/3e13d598-0f5d-3e1c-3441-55e419c868e2.png" width=30%>

- `アプリケーションを登録`をクリック

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399407/d05c793d-1728-4a03-66d9-3c45f68e14be.png" width=50%>

- アプリケーションの情報を入力し、`作成`をクリック

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399407/02d282aa-4278-59b7-db35-f507d9bedfe1.png" width=50%>

- `管理`をクリック

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399407/61ffcc1c-98b8-feb0-6a69-9fa9d614b405.png" width=50%>

- クライアントIDを確認します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399407/58e60169-5d0d-a85d-afe2-7f743a988763.png" width=50%>

## 2. APIを利用してみる

公式のサンプルコードは以下の通り。指定したゲーム(ここではFortnite)について、配信中のリストを取得するAPIとなります。

### New Twitch API
何のAPIを叩くにしてもOAuth認証が必要になりました。[Twitch APIに必要なOAuth認証のアクセストークンを取得しよう](https://qiita.com/pasta04/items/2ff86692d20891b65905) を参照してください。

```shell
curl -H 'Client-ID: ↑で確認したクライアントID' \
-H 'Authorization: Bearer OAuthで取得したトークン' \
-X GET 'https://api.twitch.tv/helix/streams?game_id=33214'
```

### v5まで
```shell
curl -H 'Client-ID: p0gch4mp101fy451do9uod1s1x9i4a' \
-X GET 'https://api.twitch.tv/helix/streams?game_id=33214'
```

要はヘッダーに `Client-ID: hogefugahage`を含んでアクセスすればよいということです。

「俺はWindowsだよcurlなんて知るか」という人は、適当なRESTクライアントで試してみましょう。
Chrome拡張の[Postman](https://chrome.google.com/webstore/detail/postman/fhbjgbiflinjbdggehcddcbncdddomop?hl=ja)での利用例を以下に記載します。

URLの欄にAPI、ParamsのKeyにgame_id、HeadersにClient-IDを入力し、Sendをクリックします。
画像のように、レスポンスが帰ってきます。ちなみに以下はデレステの配信中リストを取得したものです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399407/e6252b14-3eb2-7914-906a-3c7b5abae542.png)

# さいごに
サンプルで検索したアイドルマスターシンデレラガールズですが、現在総選挙を開催中です。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399407/e7fdbd27-ba60-bc25-189e-a611dca2bf49.png" width=50%>

諸星きらりちゃんって可愛いですよね。
![2019-05-01_01-54-04_855.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399407/2f3070c5-f059-533b-976d-0165069be5ca.png)

**諸星きらりちゃんへの清き1票お待ちしております！**
![2019-05-01_01-52-52_382.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399407/3f08031b-1ce3-b5db-1f6b-7daa8eb1d0e0.png)

★おわり★
request spec で session 値を設定する

## 検索すると……
https://github.com/rails/rails/issues/23386#issuecomment-273602172 のような感じでリクエストするときにCookieヘッダーでセッションクッキーを送るというものが引っかかります。
なお、このコメントで示されているコードは Rails 5.2.3 / Rspec 3.8.0 ではうまく動きませんでした。
// `ENV.fetch('SECRET_KEY_BASE')` を `Rails.application.credentials.secret_key_base` としたり、もろもろ変えてもだめでした。
// もっと変える必要がありそうではあるけど、私にはわからなかった。

ちなみにDHHは上記のissueのコメントで、セッションを作るURLに `post` なりするのがいいと述べています。

## よくよく考えると…
セッションクッキーがリクエストに乗ってきて、それをどうこうする部分をテストしたいわけではないので前述の方法は不要で、セッションから取れる値をスタブできればいいのです。

### コード例
```rb
describe 'セッションをスタブする', type: :request do
  context do
    let(:user) { create(:user) }
    before 'ユーザーIDをセッションから取り出せるようにする' do
      allow_any_instance_of(ActionDispatch::Request)
        .to receive(:session).and_return(user_id: user.id)
    end

    it '/hoge が成功してユーザー情報が○○する' do
      get '/hoge'

      expect(response).to be_successful
      expect(User.find user).to have_attributes(
        hoge: 'fuga'
      )
    end
  end
end
```

`and_return` に渡すHashオブジェクトを好きなものにすればOKです。
Gitのバージョンをhomebrewで管理（Mac環境）

# Gitのバージョンをhomebrewで管理

今までは、xcodeをインストールした時に一緒にインストールしたgitを
利用してきたのですが、homebrewで管理したくなったので、その時の
手順をメモ。

## homebrewのインストール確認
homebrewがインストールされていることが前提に記事を作成します。
以下のコマンドで、homebrewがインストールされていることを確認

```ruby:
which brew
```
もしくは

```ruby:
brew doctor
```
など。

万が一、homebrewがインストールされていない場合は、以下のコマンドを実行
[公式サイト](https://brew.sh/index_ja)より抜粋。


```ruby:
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```
## Gitのバージョンとパスを確認
現在どのgitバージョンのものを使用しているかを確認

```ruby:
git --version
git version 2.20.0 (Apple Git-117)
```

xcodeをインストールした時に一緒にインストールしたgitを参照しているようです。
念のため、pathも確認

```ruby:
which git
/usr/bin/git
```

## homebrewでgitをインストール

homebrewのパッケージにgitがないことを確認

```ruby:
brew list | grep git
```
また、gitの安定板を確認

```ruby:
brew info git | grep stable
git version 2.21.0
```

gitのインストール

```ruby:
brew install git
```

インストール完了まで少し待つ。

## インストール後の確認
インストール完了したら、本当にインストールできているよね確認。

```ruby:
brew list | grep git
git
```
インストールできているようです！

gitバージョンについても確認

```ruby:
git --version
git version 2.20.0 (Apple Git-117)
```
パスが切り替わっていないようです。。。

~/.bash_profileを編集して、今回インストールしたgitを参照するように変更しましょう。

```ruby:
sudo vi ~/.bash_profile
```
bash_profileの末尾に以下の二行を追加して、保存

　　　PATH=/usr/local/bin/git:$PATH
　　　export PATH

bash_profileの変更を反映するために、bash_profileファイルの再読み込み

```ruby:
source ~/.bash_profile
```

再度、gitバージョンを確認

```ruby:
git --version
git version 2.21.0
```

今回インストールしたバージョンになっていればOK！
パスも確認

```ruby:
which git
/usr/local/bin/git
```

gitのパスも変わっていることを確認。

念のため、git configも変わっていないことを確認

```ruby:
sudo view ~/.gitconfig
```
自分で設定しているユーザ名やe-mailが変わっていないことを確認

homebrewでの管理に移行することができた！


## 雑記
gitをhomebrewでの管理へ移行するに当たって、ハマったポイントはbrew install gitを
行なった後にpathが変更されていない点です。
そのため、新しくインストールした方のgitを参照してくれませんでした。
なんでだろう？って悩んでいたんですけど、pathを通すという初歩的なことを
見落としていました。お恥ずかしい。。



大変参考になったページ
---
・[MacのGitのバージョンをアップデート！Homebrewでの管理に切り替える](http://memories.zal.jp/WP/blog/20150215_2494.html)

・[macOSのgitをXcode Command Line Tools版からHomebrew版に乗り換えてみた](https://qiita.com/306_san/items/3cab1882e3035c646a65)
【Tips】Ubuntuでohgamiさん作フルスクラッチUEFIベアメタルプログラミングの環境構築メモ

## TL;DR;
UbuntuにはOVMFがない(?)ので別途いれておかないといけない

## ことの始まり
ohgamiさんが書かれている[フルスクラッチ本](http://yuma.ohgami.jp/)を読みたいと思い、
適当にUbuntuのVM立てて書いてあるとおり環境を作ってみたもののうまく動かなかったので、
調べた結果OVMFがなかったり、微妙に本来の手順とずれていたのできちんとまとめたくなった。


## ovmfをダウンロード
UbuntuにはどうもOVMFというファームウェアのVMが入ってないっぽいのでバイナリからダウンロードする

```sh
wget https://sourceforge.net/projects/edk2/files/OVMF/OVMF-X64-r15214.zip
unzip OVMF-X64-r15214.zip
```

## OVMF.fdを移動
解凍したzip内にOVMF.fdがあるので、これを/usr/share/ovmfに配置

```sh
mv OVMF.fd /usr/share/ovmd
```
これでOVMF側の設定は完了

## efiファイルを所定の位置に配置
次に、作成したコードファイルをefiに変換し、fs/EFI/BOOT/に配置。その際、ファイル名をBOOTX64.EFIに変換

```sh
x86_64-w64-mingw32-gcc -Wall -Wextra -e efi_main -nostdinc -nostdlib \
        -fno-builtin -Wl,--subsystem,10 -o main.efi main.c

mkdir -p fs/EFI/BOOT
cp main.cfi fs/EFI/BOOT
mv fs/EFI/BOOT/main.cfi fs/EFI/BOOT/BOOTX64.CFI
//結果はこんな感じ
tree -a
.
├── fs
│   └── EFI
│       └── BOOT
│           └── BOOTX64.EFI
├── main.c
└── main.efi

```

## QEMUを実行
fs配下をフォーマットしてUEFIをUbuntu上で表示させます。

```sh
qemu-system-x86_64 -bios /usr/share/ovmf/OVMF.fd -hda fat:fs
```

<img width="504" alt="スクリーンショット 2019-05-01 1.28.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121758/96e72bbc-02bb-9c1a-a7ec-b6d273855584.png">

問題なく表示されました。
Hello Worldを頼まれたら

## 前置き

つい先日、**仕事の受け方**を考える時間がありました。
簡単ゆえに実践が難しいので、定着させるためにもQiitaに残そうと思った次第です。
基本の考え方は`5W1H`です。

## 5W1H

中学生〜高校生の頃によく使ったと思います。
> Who（誰が、どのチームが）
> When（いつ）
> Where（どこで）
> What（なにを）
> Why（なぜ）
> How（どのような方法で、どのように）

エンジニアに限らず、仕事の受け方を考える上で上記は重要です。
では、【Hello Worldを頼まれたら】どう考えるべきでしょうか。

## ストーリー

ある日、非エンジニアの友人Aから「Hello Worldのプログラム？作って！」と頼まれました。
一緒に飲みに行く仲の友人Aの頼みだったので、引き受けることにしました。

## 友人Aに聞くべきこと

5W1Hに当てはめてみましょう。

### Who

* 友人Aが使うのか
* 発注元は友人Aなのか
* 著作権は誰に属するのか

著作権まで行くと過剰です。ただ、プログラムも保護対象ですし、質問の1例としてあげておきます。

### When

* いつまでに必要か
* いつ使う予定か

期日に当たる部分です。締め切りと実際に使用する日のそれぞれをはっきりさせます。

### Where

* どこで使うか（友人Aの自宅、会社、学校など）

プログラムの場合はあまり意識する必要がありません。
ここではプログラムを使用する現実の場所のみを質問します。

### What

* どの言語で実装してほしいのか
* OSは何を使用するのか
* Hello Worldは`Hello World!`でいいのか
* それとも標準入力のほうがいいのか

C言語なのかPythonなのか、それともPHPなのか、ついでにOSも聞いておきます。
また、Hello World!のプログラムとはいえ、**何**を表示するのか聞いておきます。
もしかすると、友人Aは入力した値を表示したいと思っているかもしれません。

Where同様にHowと分別しにくいです。ここでは、具体性のある質問をWhatで聞いておきます。

### Why

* なぜ必要なのか
* なぜ私なのか

今までの質問で**なぜ**がはっきりしていない場合は聞きましょう。
下の質問に関しては、他の人に頼むことを判断する基準を得ることになります。個人ではなく部署単位に依頼が来た時などは、積極的に聞くといいでしょう。

### How

* どのようにプログラムを渡せばいいのか
* どのような方法で実装すればいいか
* どのようにHello Worldを画面に表示すればいいのか
* (お金はどれくらい支払うのか)

渡す方法、実装方法、表示方法といった物事を質問します。
友人なので割愛しますが、場合によってはお金周りを聞きます。

What, Whereと分別しにくい質問もありますが、悩んだらHowで聞くのがいいと思います。


## 結果

以上の質問をした結果、友人Aの依頼をまとめると以下のようになりました。

>Who: 友人Aが使用し、友人Aが発注。著作権は作成者の私に帰属
>When: 6日後の土曜日まで。使用予定は１週間後の日曜日
>Where: 友人Aの自宅で使用。
>What: PHPで実装。Mac OSを使う予定。PHPへ入力された値を表示。
>Why: プログラミングの勉強をするため。頼める人が私しかいない。
>How: USBで受け渡し。実装方法は私の好きにしていい。ブラウザで入力した値を見たい。

Hello Worldのプログラムを作成するのに必要な情報は上記くらいなはずです。
## 結論

Hello Worldを頼まれただけでも、考えなければいけないことがたくさんあります。
殆どの場合は、依頼者が最初に説明してくれると思います。しかし、少しでも依頼者との齟齬をなくすために、エンジニア目線で不足している部分を質問する力が必要となります。その力の基礎となるのが、今回使用した`5W1H`です。

結果で上げた情報を知っていた場合と知らなかった場合のそれぞれで、どのようなプログラムを作成していたか想像すれば、質問する重要性がわかると思います。
実際にHello Worldを頼まれたら、参考にして下さい。

## 補足
あくまで最初に依頼を受けた時の行動です。進めながら考えることではないので、気をつけてください。
とあるRailsエンジニアが再就職活動を共有したがっているようだ 2019-04-30 on Twitter

# とあるRailsエンジニアが再就職活動を共有したがっているようだ 2019-04-29 on Twitter


<a href="https://twitter.com/YumaInaura/status/1122880309626920960">2019-04-29 15:08:22 UTC</a>
# 仕事獲得も出会い系アプリみたいにメッセージのやり取りが肝。


プロフィールは入り口に過ぎない。

そうですよね。

>最近改めて思う事としては、実績があるから仕事をお願いされるわけでもなければ、ポートフォリオが良いから仕事をお願いされるわけではないということ。確かに取れた案件の中ではその要素が大きいものもあるかもしれませんが「この人にお願いしよう」と一番の決めてになる部分はメッセージのやりとり

<a href="https://twitter.com/YumaInaura/status/1123070990139809792">2019-04-30 03:46:04 UTC</a>
# エンジニアは永遠にたどり着かない蜃気楼。


プログラマも。

>エンジニアって単語名乗るの厚かましい気がして使わないんだけど、プログラマもLinuxとかC言語に通じてないと名乗っちゃいけない気がしてきて萎縮している

<a href="https://twitter.com/YumaInaura/status/1123082339012055040">2019-04-30 04:31:10 UTC</a>
# 技術にこだわらないエンジニアとは、フルピッキングにこだわらないギタリストみたいな。


>Twitter見てると
>
>「技術力をつけまくれ！死ぬまで勉強じゃ！」
>「単価100万円！もっとー！」
>
>みたいなのが多いので私は、
>
>「技術や収入に拘らずに楽しく生きて行こうぜ」
>ってスタイルで推していこうと思います😙

<a href="https://twitter.com/YumaInaura/status/1123117281532235777">2019-04-30 06:50:01 UTC</a>
# プログラミングが面白くなるのは開始から15%目安。


実感当たってる気がする。

>ゲームでもプログラミングでも、うまくなるまでは（理解できるまでは）面白さがわからず辛いですが、ある一定を超え始めると、ググッ！っと面白くなる。
>
>小説も同じで読み始めはきついけど、１５％ぐらい超えてくるとどんどんと進んでいく。
>
>とりあえず最初は頭使いながらも、無心で頑張るの重要！

<a href="https://twitter.com/YumaInaura/status/1123141013499854848">2019-04-30 08:24:19 UTC</a>
# "我々は工芸家ではないので、工芸的な要素の為に書いているコードは一つもありません。
プロダクトを成功させるためにコードを書いています。"

「設計なんて不要でしょ」について  Qiita


<a href="https://twitter.com/YumaInaura/status/1123172797734240256">2019-04-30 10:30:37 UTC</a>
# "前は10年やってもよくわからなかった設計が今なら数ヶ月で大分わかるようになりますし、1年学習しながら実践も繰り返せば戦術から戦略レベルまでかなり詳しくなれるでしょう。
"

「設計なんて不要でしょ」について  Qiita


<a href="https://twitter.com/YumaInaura/status/1123173616995028992">2019-04-30 10:33:52 UTC</a>
# 整合性は仕事の起爆剤。


>理念経営を大切にしてるのは、感情論や精神論が伝えたいわけじゃない。経営に対するスタンスの問題。
>
>何のために仕事すんのか？ただ単に食うためだけならなんだっていい。
>
>前向くためには「理由」が必要で、その理由と個人の理想がリンクした時にパフォーマンスは最高潮に達する。

<a href="https://twitter.com/YumaInaura/status/1123180022355775489">2019-04-30 10:59:19 UTC</a>
# 整合性は仕事の起爆剤。
  2019-04-29 on Twitter


<a href="https://twitter.com/YumaInaura/status/1123225556617768960">2019-04-30 14:00:15 UTC</a>



# Original by Github issue

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








<!-- Update From Qiita API -->

# チャットメンバー募集


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

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





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
virt-manager起動時にGtk-WARNING **: cannot open display と警告が出た場合の対処法

### 背景
Vagrant内の CentOS7にKVM環境を構築した。ゲストOSの管理をGUIでするため、`virt-manager`を起動しようとした。しかし、以下の警告が表示されて起動できなかった。

```sh
[vagrant@localhost ~]$ sudo XAUTHORITY=~/.Xauthority virt-manager
[vagrant@localhost ~]$
(virt-manager:28496): Gtk-WARNING **: 15:31:29.497: cannot open display:
```

### 前提条件
* ホストOS
    * macOS mojave
* ゲストOS
    * Vagrant上の`CentOS Linux release 7.6.1810 (Core)`

### 原因
ローカル環境側で `export DISPLAY=:0.0` を実行していなかったのが原因だった。

Xアプリケーションは、クライアントが出した要求をサーバーが受けてモニターに出力をする方式となっている。今回ローカル側でXQuartzを起動していたが、モニターとして利用するホスト側のIPアドレス・ウィンドウ・スクリーン情報を**DISPLAY環境変数**として伝える必要があったが、それが未設定だったのが原因だった。

### 参考
* [Manpage of X](http://xjman.dsl.gr.jp/man/man3/X.3x.html)
DjangoでPython DictionaryをTextFieldに突っ込んだ後でliteral_evalを使えば戻せてハッピー

1. DjangoでTextFieldにdictを突っ込む。
2. 読み出す
3. dictじゃなくてStringが返ってきて困る。
4. ast.literal_eval()でオブジェクトに変換できる。
5. 飯が美味い
6. わざわざjson使わなくていい
7. literal_eval() という単語が覚えにくいからメモ。

```python
from ast import literal_eval

def some_handle(self):
    result = SomeAPIExecute()
    model = SomeModel.objects.get(id=1)

    model.column = result
    model.save() 


def some_view(self):
    model = SomeModel.objects.get(id=1)
    saved_result = model.column # 文字列になってしまう。
    response = literal_eval(saved_result) #  めでたしめでたし

    return response
```
「Cache-Control: no-cache = キャッシュしない」は間違い

一切キャッシュしない設定はno-cacheではなくno-store。

```
//リクエストやレスポンスを一切キャッシュしない
Cache-Control: no-store

//no-cache = キャッシュしない　ではない・・・
Cache-Control: no-cache
```

以下、Cache-Control: no-storeについての説明
(意訳)
・キャッシュしない　
いかなるリクエスト/レスポンスについての情報をキャッシュしない。リクエストはサーバに送られ、完全なレスポンスが毎回ダウンロードされる
>No caching
The cache should not store anything about the client request or server response. A request is sent to the server and a full response is downloaded each and every time.

以下、Cache-Control: no-cacheについての説明
（意訳）
・キャッシュするがrevalidateする
キャッシュはするけど、そのキャッシュを使う前にオリジンサーバにvalidationリクエストを送る
>Cache but revalidate
A cache will send the request to the origin server for validation before releasing a cached copy.

no-cacheはオリジンサーバに「このキャッシュ使っても大丈夫？」って確認してからキャッシュを使うということですね。

## 参考
https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching
（日本語版ではno-cacheの説明のタイトルが「キャッシュしない」になっていますが間違いだと思われます。2019/05/01）
Inversion of Control (IoC) 仕組み分かりやすいPHPサンプル

```php

class IoC {
    protected static $registry = [];
    public static function bind($name, Callable $resolver)
    {
        static::$registry[$name] = $resolver;
    }
    public static function make($name)
    {
        if (isset(static::$registry[$name]))
        {
            $resolver = static::$registry[$name];
            return $resolver();
        }
        throw new Exception('Alias does not exist in the IoC registry.');
    }
}


class Foo {}

class IoCTest extends PHPUnit_Framework_TestCase {
    public function test_can_resolve_out_of_the_ioc_container()
    {
        IoC::bind('foo', function()
        {
            return new Foo;
        });
        $this->assertInstanceOf('Foo', IoC::make('foo'));
    }
}
prismic事始め 〜 contentfulでもGraphCMSでもないHeadlessCMS〜

# 概要
現在、HeadlessCMSが、注目されてきています。

現在 Headless CMSとして、一番有名なのは、contentful です。
GraphQLのAPIが利用可能な、GraphCMS もあります。

しかし、contentful も、GraphCMSも、無料で利用する場合には、
Record数に制限があります。

そこで今回は、prismic という Headless CMS をご紹介します。
(prismic も海外ではすでに有名ですが、まだ日本では知名度がなさそうです)

# Headless CMS とは

通常のCMSでは、WEBページの作成を行いました。
HeadlessCMSでは、データの登録のみを行い、登録したデータはAPIで参照することができます。 (View部分がないからHeadless)

CMSから登録したデータをAPIで取得し、PCやスマホあるいはスマートウォッチなど端末に合わせて表示することができます。

# prismic の使い方

### アカウント作成
FirstName、LastName、EmailAddress、Passwordを入力しアカウントを作成します
![スクリーンショット 2019-04-30 23.48.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283051/e8e08b5b-0fd9-c9e9-0f08-63b22cd3ed0a.png)

### リポジトリの作成
![スクリーンショット 2019-04-30 22.42.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283051/1612adf3-c87f-972a-c50e-70d69ecf69c6.png)
![スクリーンショット 2019-04-30 22.44.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283051/708a3434-e539-ff01-1734-5ea8ebd26d46.png)

### カスタムタイプの作成

カスタムタイプというデータフォーマットを作成します。
![スクリーンショット 2019-04-30 23.59.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283051/64e09050-1035-d9d9-ad3c-b9ff3f1b2151.png)

ドラッグ＆ドロップで項目を追加し、フィールド名を定義します。
![スクリーンショット 2019-05-01 0.06.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283051/047f3a84-eba4-5828-72c2-d4f246ffe8a7.png)

### ドキュメントを登録します
カスタムタイプで定義したデータ項目を登録し、Publishします。
![スクリーンショット 2019-05-01 0.09.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283051/43ac68d4-9bab-0d4d-efd5-a680d0a639e3.png)

### APIを確認

以下のようなURLで、ドキュメントを取得できます。
http://your-repository-name.prismic.io/api/v2/documents/search

詳しいAPI仕様は、以下をご確認ください。
https://prismic.io/docs/rest-api/basics/introduction-to-the-content-query-api
Slickを使って画面スライドを作成してみました！

#jQueryプラグインのSlickを使ってみました。



まずはjQueryのgemをbundle installします。

```ruby
gem 'jquery-rails'
```

app/assets/javascript/application.jsに下記を追加

```javascript

//= require jquery
//= require jquery_ujs
```

views/layout/application.html.hamlに下記のように記述しました。


```haml
 %link{href: "//cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick.css", rel: "stylesheet", type: "text/css"}/
 %script{src: "https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"}
 %script{src: "//cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick.min.js", type: "text/javascript"}

views/layout/application.html.hamlに記述

```


CDNは下記サイトを参考にしております。
http://kenwheeler.github.io/slick/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/383398/fa49b30e-7aa2-b937-faea-5e98cebb92b7.png)

次にHTML（hamlで記述しています)ファイルを用意してスライドさせたい写真を用意します。
（用意する写真の枚数は任意でOKです）

```haml

.slick-container
  %ul.slider
    %li
      = link_to 'https://www.mercari.com/jp/featured/newlife/' do
        = image_tag 'mer.jpeg'
    %li
      = link_to 'https://www.mercari.com/jp/promotion/201812_bokurano_heisei/' do
        = image_tag 'ounen.jpeg'

```


次にjsファイルを作成し、編集していきます。
（ファイル名は任意で大丈夫です）

```javascript
$(function() {
  $('.slider').slick({
    autoplay:true,
    autoplaySpeed:5000,
    arrows: false
  });
});

```

jsは記述少ないですが、いろんなオプションがあり、調べると参考できるサイトがたくさんありました。
下記参考したサイトになります！

http://kenwheeler.github.io/slick/
https://mchinta.hatenablog.com/entry/2018/12/27/020555
https://qiita.com/katsunory/items/25b385aae0f07b41e611


色々調べてプラグインも使いこなせるようになっていければなと思い、残してみました！

以上です。
LDAPで快適Linux環境 #2 LDAPサーバーの設定

[前回](https://qiita.com/uuu_n/items/2620ab239de8481e7323)の続きで、LDAPを使った環境を実際に構築していきます。

まず、OpenLDAPをインストールします。パッケージは「slapd」と「ldap-utils」です。

```bash
root@deb:~# apt install slapd ldap-utils
```

インストール中、管理者パスワードの設定を求められるので任意のものを入力します。

次に、設定を確認します。

```bash
root@deb:~# slapcat

dn: dc=example,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
o: example.com
dc: example
structuralObjectClass: organization
entryUUID: 06569610-ee78-1036-9f61-215a0bc0a3ab
creatorsName: cn=admin,dc=exapmle,dc=com
createTimestamp: 20190426045948Z
entryCSN: 20190426045948.719889Z#000000#000#000000
modifiersName: cn=admin,dc=example,dc=com
modifyTimestamp: 20190426045948Z

dn: cn=admin,dc=example,dc=com
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
userPassword:: e1NTSEF9d1ZKejV4RXZSZDF4aWtNOHJteitNdTBZWmlZM2Z0K0E=
structuralObjectClass: organizationalRole
entryUUID: 065cb18a-ee78-1036-9f62-215a0bc0a3ab
creatorsName: cn=admin,dc=example,dc=com
createTimestamp: 20190426045948Z
entryCSN: 20190426045948.759960Z#000000#000#000000
modifiersName: cn=admin,dc=example,dc=exapmle
modifyTimestamp: 20190426045948Z
```

環境に応じて、dnなどが変わるはずです。もし設定に間違いがあったら、

```bash
root@deb:~# dpkg-reconfigure slapd
```

で再設定できます。

次にユーザーとグループ用の組織単位を登録しておきます。

```bash
root@deb:~# vi base.ldif


dn: ou=people,dc=example,dc=com
objectClass: organizationalUnit
ou: people

dn: ou=groups,dc=exapmle,dc=com
objectClass: organizationalUnit
ou: groups 

root@deb:~# ldapadd -x -D cn=admin,dc=example,dc=com -W -f base.ldif

Enter LDAP Password:

adding new entry "ou=people,dc=example,dc=com"

adding new entry "ou=groups,dc=example,dc=com"
```

途中、パスワードを求められるのでインストール時に設定したものを入力します。dnは適宜置き換えてください。
ここでもう一手間加えます。部活で使う環境なので、学年ごとに分けて登録できるようにします。

```bash
root@deb:~# vi 1th.ldif


dn: ou=1th,ou=people,dc=example,dc=com
objectClass: organizationalUnit
ou: 1th

dn: ou=1th,ou=groups,dc=example,dc=com
objectClass: organizationalUnit
ou: 1th 

root@deb:~# ldapadd -x -D cn=admin,dc=example,dc=com -W -f 1th.ldif

Enter LDAP Password:

adding new entry "ou=1th,ou=people,dc=example,dc=com"

adding new entry "ou=1th,ou=groups,dc=exapmle,dc=com"
```

他の学年も数字を変えて同様にします。

続きはまた[次回](https://qiita.com/uuu_n/items/9a0ba8823180de3b3ab6)。
令和になってLinuxがもっとメジャーになってほしいものです。
Pythonで年齢認証などのクッションページを回避してスクレイピングしたい

# はじめに
[私が運営しているWebアプリケーション](https://hmd.site/app/d3comp/)のジャンル的に、
スクレイピングで[こんなページ](https://www.amazon.co.jp/%E5%A4%A7%E4%BA%BA%E3%81%AE%E3%81%8A%E3%82%82%E3%81%A1%E3%82%83-%E3%82%A2%E3%83%80%E3%83%AB%E3%83%88%E3%82%B0%E3%83%83%E3%82%BA-%E3%82%AA%E3%83%8A%E3%83%9B%E3%83%BC%E3%83%AB-%E3%82%B3%E3%83%B3%E3%83%89%E3%83%BC%E3%83%A0-%E9%80%9A%E8%B2%A9/b?ie=UTF8&node=171288011)によく出くわします。

<img width="459" alt="スクリーンショット 2019-05-01 0.04.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395743/067b5d69-4213-cd88-2d83-6a094dc60761.png">

アダルトサイトとかでよく出くわしますが、通常のサイトでも（ログインまではいかないが）強制的にクッションサイトに飛ばされることがあるかと思います。

この**強制的にクッションサイトに飛ばされる**ことは、**指定したURLではなく、クッションページをスクレイピングすることになってしまう**ため、大きな問題となります。

こういったページを回避して、目的のページをスクレイピングする方法を忘記録として残しておきます。

# クッションページを回避してスクレイピング
それぞれ独立しているわけではありませんが、以下の３通りで概ね解決できるかと。

1. seleniumを使う
2. requests.session()を使う
3. クッキーを渡す

なお、本記事で解説するのは「2」と「3」です。

## 1. seleniumを使う
一番手っ取り早いのはseleniumでchromeやfirefoxのdriverを使うことです。

seleniumの利点は、GUI的なWebブラウザの操作ができる点。
「あるページにアクセス」→「そのページのある要素をクリック」なんてことが、Python上だけで実現できます。

seleniumの詳しい解説は結構転がっているので、本記事では割愛。

ただ、問題なのは**ChromeやFirefoxが無い環境では動かせない**という点。
sudo権限のないCUIのレンタルサーバーとかでChromeをインストールするのは（できなくはないと思いますが）非常に厳しいです。

## 2. requests.session()を使う

seleniumを使わなくても、クッションページの回避程度ならrequestsモジュールのsessionで十分な場合が多いです。

```python

import requests
from bs4 import BeautifulSoup

url_certification = 'クッションページの「はい」のURL'
url_target = 'スクレイピングしたいURL'

session = requests.session()
session.get(url_certification)

soup = BeautifulSoup(session.get(url_target).content, 'lxml')
```
よく使用されるrequests.getはワンタイムのアクセスですが、
上記のようにsessionを使用することで、連続したアクセスを実現が実現できます。
あと、seleniumよりも圧倒的に速いのも利点。


## 3. クッキーを渡す
クッションページ内の「はい」のURLが、「クッキーを生成するJavaScriptへのアクセス」だと、requests.session()だけではうまくいきません。
このような場合は「はい」をクリックしたときに生成されるクッキーをrequests.getに渡してやることで解決します。

```python

cookie = {'abc': '1'}  # 予め調べておく。

soup = BeautifulSoup(requests.get(url, cookies=cookie).content, 'lxml')
```

今回はパスワードやメールアドレスなどのセキュアな情報を扱うわけではないので、セキュリティ面などはあまり気にせずに書いています。

cookieの調べ方は、他の方の記事を参照してください。ある要素をクリックしたときに生成されるクッキーの値を取得するといったことは、Chromeなどの実際のブラウザや、前述のselemiumなどから調べることができます。

なお、requests.getにわたすクッキーのvalueは、str型でなければならない点に注意してください。

# まとめ
seleniumは色々と高機能で楽ですが、requestsモジュールだけでも色々と実現できます。
機能・速さ・セキュリティなどを考慮して、適材適所を心がけたいですね。
Linuxをコンソールモードで起動する

CentOS7をServerモードでセットアップすると、GUI(X Window System)で起動します。サーバでは不要なためコンソールモード(CLI)へ切り替えます。

CentOS7のデフォルト ディスプレイマネージャーはGNOME標準である ``GDM`` のようです。

<br>まずはサービスの状況を確認。有効です。

```console:
# systemctl list-unit-files | grep gdm
gdm.service                                   enabled
```

<br>gdmサービスをdisableにします。

```console:
# systemctl disable gdm.service
Removed symlink /etc/systemd/system/display-manager.service.
```

<br>サービスのdisableを確認し、再起動します。

```console:
# systemctl list-unit-files | grep gdm
gdm.service                                   disabled

# reboot
```
Kerasで1チャネル画像をCNNするときに詰まった話

> これはKerasを全く知らない人にはちんぷんかんぷんな記事となっています.

# はじめに

Pythonの機械学習フレームワーク「Keras」を使って, 
NNの練習をしていた時のこと.

これは, 1チャネル画像のCNNの実装で詰まった時の備忘録である.
ちなみに, ことの発端は次のようなエラーだった.

```terminal:error_1
ValueError: Input 0 is incompatible with layer conv2d_1: expected ndim=4, found ndim=3
```

# 環境 🖥
- python 3.6.5
- keras 2.2.4

```python:今回の役者たち
from keras.layer import(
    Input, Conv2D, Reshape
)
```

なお、modelはSequential()ではなくFunctionalAPIを使ってます.

# 詰まったところ 😓
エラーを見る限り、Conv2D()への入力層_inputに問題がある.
「入力層の次元は3次元じゃなくて, 4次元でお願い！」とのことなので, 以下のように改善した.

```python:modification_1
# === 変更前 ===
input = Input(shape = (28,28,))
hidden = Conv2D( /*some args*/ )(_input)


# === 変更後 ===
input = Input(shape = (28,28,1)) # <-- ここを変えた！
hidden = Conv2D( /*some args*/ )(_input)

```

しかし, またエラー.

```terminal:error_2
ValueError: Error when checking input: expected input_1 to have 4 dimensions, but got array with shape (/*画像の枚数*/, 28, 28)
```

modelの期待する入力と入力データのshapeが合わない, と言われた.

...

当たり前だ.さっき自分で変えたではないか.

|modelの期待する入力|実データのshape|
|:-:|:-:|
|(28,28,1)|(28,28)|

ここで詰まったわけです.
答えは公式ドキュメントにありました.

# これで解決 😆
```python:justice!!
input = Input(shape = (28,28))
hidden = Reshape((28, 28, 1), input_shape = (28, 28))(input) # <-- ここを加えた！
Conv2D( /*some args*/ )(hidden)
```

modelで受け取るときは (28,28)で, その後 (28, 28, 1) にreshapeして畳み込み層に渡せばオッケー.

# 感想 ♨️
エラーで調べても似て非なるものばっかりで, 
かと言って「keras 1チャネル画像 cnn」とかで検索しても解決せず, 詰まってしまったのは反省.
公式ドキュメントは全体をバーっと1読しておくべきでした.

# 参考 🙇‍♂️
[Coreレイヤー - Keras Documentation](https://keras.io/ja/layers/core/)
令和の始まりにHello, Reiwa!と叫ぶ

# はじめに
 
Hello, World! をもじった、ただのネタ記事です。

# プログラム

## C

```c:HelloReiwa.c
#include <stdio.h>
int main() {
    printf("Hello, Reiwa!\n");
    return 0;
}
```

## Java

```java:HelloReiwa.java
public class HelloReiwa {
    public static void main(String[] args) {
        System.out.println("Hello, Reiwa!");
    }
}
```

## Perl

```perl:HelloReiwa.pl
print "Hello, Reiwa!\n";
```

## PHP

```php:HelloReiwa.php
<?php
echo "Hello, Reiwa!\n";
?>
```

## Python

```python:HelloReiwa.py
print("Hello, Reiwa!")
```

## Ruby

```ruby:HelloReiwa.rb
puts "Hello, Reiwa!"
```

# まとめ

ありがとう平成。こんにちは令和。
令和の時代が、幸多き時代になりますように。
０から始めるSQL　

投稿目的
今後のための独学SQLの私的利用目的のメモ程度の内容で、やったことを忘れないでおきたいな、程度なのであまり参考にはならないと思います。

本日のお題
触れようSQLの世界　－環境構築編－

SQL環境
Oracle　SQL
https://apex.oracle.com/ja/
ここから必要なものをDLしてきて

良しなに環境を作成

環境作成後、サンプルデータをDLしておく
＊サンプルをDLしないとおそらく何にもデータがないので？？？？？になる

使用PC　
Surface Pro4　
Windows 10 Pro 64bit 
CPU Intel(R) Core i5-6300U 
RAM 8.00GB

やったこと
１．DB上にあるテーブル一覧を取得
SQL
　SELECT　＊
　FROM　USER_TABLES

Result
　サンプルでDLしたテーブルのリストとカラム？が表示されました。

２．適当なテーブルの中身を確認
SQL
　SELECT　＊
　FROM　DEPT

Result
　テーブルDEPT内のデータが表示された
MetaMaskの有力な代替アプリ、Dapperの導入方法

## MetaMaskの有力な代替アプリ、Dapperの導入方法
クリプトキティーズのチームがMetaMaskに変わるブラウザウォレットプラグインのDapperをリリースしています。

導入はChromeで以下のリンクを開き、エクステンションをインストールすることで導入できます。

https://chrome.google.com/webstore/detail/dapper/pghmmgdinmfblodenlenkcnmndlnffeo?hl=en

国内のDappsだと、マイクリプトヒーローズが対応しているそうです。
## 終わりに
私は現在、Web3のサービスの開発をしています。詳しくはこちらの記事をご覧下さい。
        [無料でイーサリアムが当たる、Web3時代の寄付サイトを作った話](https://note.com/kenroda/n/n814347fbdcd7)
[iOS]StoryBoardのMissing Constraintsについて

# Missing Constraintsとは
StoryboardでViewのConstraintsを設定している時に表示される赤いやつ(下図)。
Constraintsが足りていませんという警告。
無視するとStoryBoard上の配置と端末上の表示が一致しない原因になりえる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196890/aae3bc4d-1e52-7804-478f-f32b78908bc4.png)


# Missing Constraintsになる原因
設定されているConstraintsだけでは、Viewの端末上の表示領域(x, y, width, height)を決められないから。

たとえば上図のケースでは、Viewのleading(左)とtop(上)方向のConstraintだけ設定している。
trailing(右)とbottom(下)方向のConstraintや、widthとheightのConstraintは設定していない。
なので、表示領域の内、xとyは決まるが、widthとheightは決まらない状態。
だから、Missing Constarintsという警告が出る。

# Missing Constarintsへの対処
Viewの端末上の表示領域が決まるようにConstraintを追加する。
上図のように、Viewのleading(左)とtop(上)方向のConstraintだけ設定している状態なのであれば、widthとheightのConstarintを追加したり、trailingとbottomのConstarintを追加すればOK。
(ちなみに、widthとbottom, heightとtrailingのConstarint追加でもOK)

# 備考
Missing Constarintsはあくまで警告。無視しても問題ないこともしばしばある。
多分、Missing ConstraintsになっているViewを基準に、他のViewのConstarintを設定しなければ問題ないのかと。
【gdb】コマンドライン引数つきでgdbを起動  

# コマンドライン引数つきでgdbを起動

通常、プログラムをコマンドライン引数付きで GDB上で実行したい場合、
以下のように実行します。

```bash
$ gdb program
$ (gdb) run --foo --bar
```

--args オプションを用いると、次のように実行できます。
この方がシェルの履歴を再利用できるので便利です。

```bash
$ gdb --args program --foo --bar
$ (gdb) run
```
【gdb】コマンドラインの履歴をファイルに保存する  

# gdbのコマンドラインの履歴をファイルに保存する

ホームディレクトリに .gdbinit を置いておくと、gdb を起動する際に読み込まれます。  
以下の通り記述しておくとgdb のコマンドラインの履歴を覚えておいてくれるようになります。  

```bash
set history save on
set history size 1000
set history filename ~/.gdb_history
```

## 各行の説明

1. gdb のコマンドラインの履歴をファイルに保存する
2. 保存する行を最大 1000 行にする
3. 保存するファイル名を指定。この例であれば ```~/.gdb_history```
CSVファイルを丸ごと挿れたい（間違わないLOAD DATA INFILE)

## はじめに
CSVファイルを１件１件取り出して、加工してSQLを生成……
なんてことを、これまでしてきました。
もちろんすごく遅いです。

LOAD DATA INFILEを使うことでファイルインポートができます。
とはいえ、ざっくり調べても「あまり使えなさそう？」と思っていた私がいます。
ですが理解してみると一転して、様々なCSV案件で大活躍です。
未来の私のために今日もメモします。

> LOAD DATA INFILEとは
> LOAD DATA INFILE ステートメントは、非常に高速にテキストファイルからテーブルに行を読み取ります。

## 参考URL
- [LOAD DATA INFILE 構文](https://dev.mysql.com/doc/refman/5.6/ja/load-data.html)

## 理解のポイント（下記構文を見ながら）
* CSVファイルを読み込み、INSERTを行うイメージです。
* CSVの１列目(例:A1,B1など)が、`users.id`カラムに入ります。
* CSVの２列目(例:A2,B2など)が、`users.name`カラムに入ります。
  * つまりカラムとCSVの順番は、バラバラでも対応が可能ということです
* SET以降は「CSVにはないけれどカラムに入れたい値」をセットすることができます。
  * もはやCSVデータとはほぼ関係なく、SQL側のための機能です

### 構文
```sql
LOAD DATA INFILE 'nzn.csv'
  INTO TABLE `users`
  FIELDS TERMINATED BY ','
  ENCLOSED BY '"'
  LINES TERMINATED BY '\r\n'
  IGNORE 1 LINES
  (
     `id`
      , `name`
      , `price`
  ) SET
     `created_at` = TIMESTAMP
```

### 各行の理解
* `FIELDS TERMINATED` : CSVの区切り文字を指します。ほぼ必須です。
* `ENCLOSED BY '"'` : 文字列などはダブルクォーテーションで囲われていますが、良きように消してINSERTをしてくれます。ほぼ必須です。
* `LINES TERMINATED BY '\r\n'` : 改行コードの認識を定義します。
  * csvファイルがCRLFなのに`\n`と指定すると、１行しか入らないなど不都合が起きます。
* `IGNORE 1 LINES` : CSVには見出しがつきもの。プログラム側で削除するより高速なのでLOAD DATA側で除外すると少し幸せになります。

### ではbashから呼び出してみよう
```bash
readonly ENC='\"'; #エスケープ
$code="
LOAD DATA INFILE 'nzn.csv'
  INTO TABLE users
  FIELDS TERMINATED BY ','
  ENCLOSED BY '${ENC}'
  LINES TERMINATED BY '\r\n'
  IGNORE 1 LINES
  (
     id
      , name
      , price
  ) SET
     created_at = TIMESTAMP
     updated_at = ${TIME_STAMP}
";
```

ちなみにbashで実行の場合、バッククォーツ自体に意味があるので、誤認されるみたいです。
テーブルやカラムにも、バッククォーツは付けずに記述しましゅ。

### 最後に
他にも変数の指定ができますが、これが初めて使うときに理解を遠ざける要因の１つでした。結局、私の案件の場合は変数は不要でしたので、上記のようなLOAD DATAで落ち着きました。
PHPの基本文法 -変数について-

# PHPの基本文法 - 変数について -
PHPの変数について、整理してみました。

## PHPの変数
変数は、値を格納しておくことのできる場所です。
下記は変数のイメージ図です。

![20150128001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263738/d0bb27a2-2ebb-52db-d40d-44113108a261.jpeg)

PHPの変数は、ドル記号「＄」の後ろに「変数名」が続く形式で表します。
上記の図をPHPで表現すると以下のようになります。

```php5
$a = 10;  //aという名前の入れ物に１０という値を入れる

```
ここで使用される=は「等しい」という意味ではなく、「代入する」という意味になります。
上記の場合、「$aに１０を代入する」という意味になります。

## 代入
代入には、２種類あります。

- 代入
- 参照による代入

一つ目の代入は、先ほど上で説明したものになります。
二つ目の参照による代入について、
参照による代入を行うには、代入する変数の前に「＆」をつけます。
この場合、２つの変数は同じ内容を指します。

```php5

$foo = 'Bob';   //Bobを変数fooに代入する
$bar = &$foo;   //変数fooを変数barにより参照する
$bar = 'My name is ' . $bar; //変数barを変更すると変数fooも変更される

//結果、以下は同じ内容「My name is Bob」が表示される
echo $bar, '<br>';
echo $foo, '<br>';
```

[PHPの基本文法 -関数の引数について-](https://qiita.com/rspmharada7645/items/58fb834c61436569ad9e)
【Linux】シェルスクリプトにおいてShebang に bash を明示する

# Shebang に bash を明示する

Bash でしか使えない機能のことを俗に **Bashism** と言います。
Bashism はもちろん Bash 以外のシェルでは動きません。

# #!/bin/sh の罠
これに関するありがちな罠は、以下のように発生します。
* Bash が ```/bin/sh``` として使われている環境でシェルスクリプトを書く。
うっかり Bashism がシェルスクリプトに含まれていても、 ```/bin/sh``` は何も文句を言わないので、Bashism に気付かない。
* /bin/sh が Bash でない環境でそのシェルスクリプトを実行すると動かない。

※ Debianがまさにこのパターンです。 ```/bin/sh``` はdebianの場合 Dash

# 解決策

この解決策は、どの環境でも必ず **Bash** でシェルスクリプトが実行されるようにすることです。
シェルスクリプトの先頭行には ```#!/bin/sh``` ではなく ```#!/bin/bash``` と書きましょう。
PHPの基本文法  -型について- 

# PHPの基本文法 -型について-
PHPの基本文法について整理してみました。

## PHPがサポートする型について
PHPは合計８種類の型をサポートします。

- 4種類のスカラー型
- 2種類の複合型
- 2種類の特別な型

### スカラー型について
スカラー型は、常に１つの値を保持している変数です。
スカラー型には、以下の４種類があります。

- 理論値
- 整数
- 浮動小数点数
- 文字列

```php5
//理論値(Boolean) 真偽の値を表す。値はtrueかfalseの２つ。
//例)
$flag = true;
$flag = false;

//整数(integer)は、１０進数、１６進数、８進数、２進数表記で使用可能。
//８進数表記は「０」を、１６進数表記は「0x」を、２進数表記は「０b」を数の前につける。
//例）
$num = 1234; //１０進整数
$num = -123; //負の数
$num = 0123; //８進数(１０進数だと83)
$num = 0x1A; //16進数(10進数だと26)

//浮動小数点(float)は、小数点以下の値を持つ数値。
//例)
$num = 1.234;
$num = 1.2e3; //1200
$num = 7E-10; //0.0000000007

//文字列(string)は、「'」（シングルクォーテーション）、または「”」（ダブルクォーテーション）で囲んで表現する
//例）
$str = 'Hello World';
$str = "Hello World";
```

### 複合型について
複合型は、複数の値を格納することができる変数です。
複合型には、以下の２種類があります。

- 配列
- オブジェクト

```php5
//配列は、array関数で作成する。
//例）
$array = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
$array = array("太郎", "二郎", "三郎");
$array = array(
  "A" => "windows",
  "B" =>  "Mac",
  "C" =>  "Linux"
);

//オブジェクトは、クラスをインスタンス化して作成する。
//例）
class Hello{
    public function reply($str)
    {
        echo 'こんにちは' . $str;
    }
}

//Helloクラスのオブジェクトを生成する。
$hello = new Hello();
```

### 特別な型について
特別な型には、以下の２種類があります。

- リソース
- NULL

```php5
//リソースは、外部リソースへのリファレンスを保持している特別な変数です。
//リソースは特別な関数によって作成され、使用されます。
//例)
$fp = fopen("test.txt", "r"); // 外部ファイルオープン
var_dump($fp);                // $fpはリソース型
fclose($fp);                  // ファイルクローズ

//ある変数が値を持たないことを表すのがNULLです。
//例）
$num = NULL;
```

## 型の変換について
PHPでは、変数の型はその変数が使用される文により定義される。
オペランドのどれかが「float」の場合、全てのオペランドは「float」として評価され、結果は「float」になる。
その他の場合は、オペランドは「int」として解釈され、結果も「int」になる。

```php5
$foo = 2;            //fooは整数
$foo = $foo + 1.3;   //結果はfloatの3.3 
$foo = 5 + '10 age'; //結果は整数の15になる
```

### キャストについて
ある変数を強制的にある特定の型として評価させたい場合には、型キャストを行う。
PHPの型キャストは、変換しようとする型をカッコで囲み、キャストする変数の前におきます。

```php5
$foo = 10;
$bar = (bool)$foo; //bar はbool
```

使用可能なキャストは、以下の通り。

| キャスト　                  |       説明　　　 　 | 
|:-------------------------|------------------:|
| (int),(integer)          | 変数にキャスト        | 
| (bool),(boolean)         | 理論値にキャスト      |
| (float),(double),(real)  | floatにキャスト      |
| (string)                 | 文字列にキャスト      |
| (array)                  | 配列にキャスト        |
| (object)                 | オブジェクトにキャスト      |
| (unset)                  | NULLにキャスト       | 
| (binary)                 | バイナリ文字列にキャスト | 



[PHPの基本文法  -変数について- ](https://qiita.com/rspmharada7645/items/58fb834c61436569ad9e)
Firebase: Firebase App named '[DEFAULT]' already exists (app/duplicate-app).というエラーに悩まされたときに

Nuxt.jsで開発している際に以下のようなエラーがでたのでその解決方法

```
Firebase: Firebase App named '[DEFAULT]' already exists (app/duplicate-app).
```

# 解決方法
1. キャッシュを消す
2. 開発サーバを再起動する
3. ページリロード
Alexaスキル AWS Lambdaのログ出力場所

エラーが発生したときに、どこにログを出力するか探したのでメモ。

## 結論
CloudWatchログに出力される

以下が参考になった。
[AWS Lambdaのデバッグ方法](https://qiita.com/keitakn/items/02fcee5bbb037bbd2e41)
>CloudWatchの管理画面から、ログ → /aws/lambda/{lambda関数名}/{ログストリーム} とページ遷移していくとログが確認出来る。

私の場合、CodeStarからAlexaスキルを作成したため、{lambda関数名}が以下のような名前になっていた
awscodestar-{CodeStarプロジェクト名}-lambd〜
docker-compose volumeマウント


#概要
docker-composeでマウントをするが、コンテナ側から出力するファイルがホスト側のフォルダに書き込まれないエラーになりハマったので備忘録として残しておく。

#パーミッションになるエラー
コンテナ内で作成したファイルの書き込みができない。

```
version: '3'
services:
  app:
    build: ./docker/php
    volumes:
      - ./www:/var/www/html
```

#対処
yamlのトップレベルにvolumes:を置いてボリュームを定義する。

```
services:
  app:
    build: ./docker/php
    volumes:
      - www:/var/www/html

volumes:
  www:
    driver_opts:
      type: none
      # 絶対パスで指定する
      device: /home/user/www
      o: bind
```
数学定義ノート（１）　－束（lattice）

# 目的
数学理論の構築時に、まぁまぁ忘れがちな定義をノートしておく。

# 定義

## 半順序集合 (partially ordered set)
$P$：集合
$\le \in P \times P$：$P$上の二項関係

$$
\begin{array}
~\langle P, \le \rangle : poset \\\
~~ \overset{def}{\Leftrightarrow} \\\
(i) ~~~ \forall a \in P, a \le a & 反射律 \\\
(ii) ~~ \forall a, b, c \in P, a \le b~\\&~b \le c \Rightarrow a \le c & 推移律 \\\
(iii) ~ \forall a, b \in P, a \le b~\\&~b \le a \Rightarrow a = b & 反対称律
\end{array}
$$

## 束（lattice）
$$
\begin{array}
~\langle P, \le \rangle : lattice \\\
~~ \overset{def}{\Leftrightarrow} \\\
(i) ~ \langle P, \le \rangle : poset \\\
(ii) ~~ \forall a, b \in P, \exists a \land b=inf\\{a, b\\} & meet の存在 \\\
(ii) ~~ \forall a, b \in P, \exists a \lor b = sup\\{a, b\\} & join の存在 \\\
\end{array}
$$

ここで、
$\land$ を meet、$\lor$ を join と呼ぶ。