OmniAICreator/Qiita-1.07M huggingface dataset:
スクラムプロセスに慣れてきた人向けのディスカッション資料

# はじめに
本記事は、スクラムプロセスに慣れてきた社内メンバー向けの簡単なディスカッション資料です。

**Agenda**

- あなたは今「アジャイル」な状態なのか？
- 困ってそうなコトと個人的アイデア
    - 振り返りのマンネリ化
    - スクラムマスターチェックリスト
- みんなでディスカッション

# 今「アジャイル」な状態なのか？

- 「スクラム」は目的ではない。あくまで、「手段」。
- なんの手段だったのか？「アジャイル」を実現する手段だったはず。
- なぜ「アジャイル」を実現したいのか？そこに「課題」があったから。

今も「課題」がどんどん解消されている状態ですか？

参考：[結果的にスクラムになってる！なのがいいと思う！ #RSGT2017](https://speakerdeck.com/bufferings/jie-guo-de-nisukuramuninatuteru-nafalsegaiitosi-u-number-rsgt2017)
参考：[スクラムとは何か？〜Certified ScrumMaster 研修を受けて〜](https://qiita.com/nh321/items/19818f04841474587644)

# 困ってそうなコトと個人的アイデア

- 振り返りについて：アジャイルレトロスペクティブ
- スクラムマスターチェックリストってのがあるよ

## 振り返りについて：アジャイルレトロスペクティブ
[アジャイルレ・トロスペクティブ](https://www.amazon.co.jp/dp/4274066983/)という本がある。
各プロセスでどのようなアクティビティを行なうかについては、いろんなアイデアが乗ってるのでお薦めです。
紹介も兼ねて、ちょっとだけ紹介します。

アジャイルレトロスペクティブでは、具体的に以下プロセスで行なうと良いよ！って書いてあります。

1. 場を設定する
2. データを収集する
3. アイデアを出す
4. 何をスべきか決定する
5. 終了する

**場を設定する**

- アイスブレイク
    - 誰もが話しやすい空気を出す
- タイムボックス・目標を説明
    - 何について振り返るのかを決める：例えば、「このスプリントは不具合が多かったので、開発プロセスついて振り返る」など。
- チームの約束を確認する
    - 心理的安全に関する約束が多いが、心理的安全に関連する必要はない

**データを収集する**

「意見・気づき」を支える「事実」を捉えるために、データを収集する。
「意見・気づき」を元にアクションを決めると、本質的な問題が解決しない。

**アイデアを出す**

- データを元にアイデアを出す
- 思いつきのアイデアはだいたいダメなので、どんなに「イケてる！」と思っても、分析的に考える。（事実と照らしてみる）

**何をスべきか決定する**

SMARTなアクションであること

- Specific：何をするかが具体的であること
- Measurable：完了条件が測定可能であること
- Achivable：達成可能であること
- Relevant：目標達成に関係があること（を説明できること）
- Time-boxed：「時間」で見積もりが行われていること。「日」レベルでは大きい。

実行に移すアクションは選別する（全部はやらない）

**終了する**

- 議事を残す
- レトロスペクティブ自体を振り返る
- 圧倒的感謝！

## スクラムマスターチェックリスト
本来は、スクラムマスターが開発チームの状態をチェックしたりするものですが、開発チーム自身が使っても良いと思います。
参考：[スクラムマスターチェックリスト](http://scrummasterchecklist.org/pdf/ScrumMaster_Checklist_jp.pdf)
（私が翻訳しました！褒めて！）

チェックリストから「開発チーム向けのチェック項目」を抜粋してみました。確認してみてください。

- ☐ スプリントプランニングのタスクに集中できてますか？（チームは”フロー状態”にありますか？）
- ☐ チームメンバーはお互いが好きで、一緒にバカができて、お互いの成功を祝っていますか？
- ☐ チームメンバーはお互いに、高いレベルで責任を持ち、成長を目指して挑戦していますか？
- ☐ 議論するのを極端に不快に思うあまり、議論を避けているような問題はありますか？
- ☐ スプリントレトロスペクティブにおいて、いろんな場所ややり方を試しましたか？
- ☐ チームはスプリントゴールをずっと大切にしてきましたか？ もしかしたら、このスプリントでコミットされたPBIの受け入れ基準の見直しとして、スプリント内点検を実施しても良いかもしれません。
- ☐ スプリントのタスクボードはチームが実際に行っていることを反映していますか？ 一日では終わらないタスクや隠されたタスクの「ダークマター」に注意してください。 スプリントゴールに関連しないタスクは、スプリントゴールに対する障害です。
- ☐ あなたのチームは、出荷可能なプロダクトインクリメントを構築するのに十分なスキルを備えた3～9人のメンバーで構成されていますか？
- ☐ あなたのチームのタスクボードは最新の状態になっていますか？
- ☐ チームが自己管理してる成果物は、チームから見えるようになっていますか？チームにとって使いやすい状態ですか？
- ☐ これらの成果物は、チーム外のお節介焼き達から保護されていますか？ チーム外の人による過度なチェックは、チーム内部の透明性と自己管理を妨げる可能性があります。
- ☐ チームメンバーは自主的にタスクを行なっていますか？
- ☐ 技術的負債を返済する必要性が”Done”の定義に明示的に示されており、徐々にコードをより楽しい場所にできていますか？
- ☐ チームメンバーは、合意された作業（テスト、ユーザードキュメントなど）のすべての側面を包括的に担当するように、チームルームのドアにチームの役割を張り出してますか？

チェックリストには、「プロダクトオーナー」「開発プロセス」「所属する組織」などを対象にしたチェック項目もあるので、確認してみてください。


# 最後に

気づきのインプットになりそうな情報提供はここらへんにします。
後はみんなでディスカッションしましょう。


以上です。
CentOS7のコンテナでsystemctlを使うための方法

# 概要

dockerからCnetOS7のコンテナを起動し、 `systemctl` コマンドからサービスを制御しようとしたところ以下のエラーに遭遇しました。

```
# systemctl
Failed to get D-Bus connection: Operation not permitted
```

ここでは上記のエラーを解消するための方法について記載します。

# はじめに

そもそもこの `D-Bus` とは何か。

> D-Bus (Desktop Bus) はメッセージバスと呼ばれる、アプリケーション間でやりとりを行うための、プロセス間通信(IPC)実装のひとつ。加えて、プロセスの生成期間を調節し、それらのサービスが必要なときに簡単に呼び出すことが出来るようにするものである。軽量さ、低依存度を保って開発されている。

[Wikipedia](https://ja.wikipedia.org/wiki/D-Bus) からの引用となりますが、 `D-Bus` はプロセス間通信の実装を表しているようです。
はじめて目にしましたが、要は何らかの原因でプロセス間通信の制御が許可されていないようです。

# エラー解消までに試したこと

## 1. CentOS7イメージのpull

まずはCentOS7のイメージを pull してきてコンテナを起動できるようにします。

```
# docker pull centos:7
```

## 2. コンテナの起動 (失敗)

CentOS7のイメージをベースにコンテナを起動してみます。
まずは何も考えずにそのまま `run` します。

```
# docker images
REPOSITORY                 TAG                 IMAGE ID            CREATED             SIZE
centos                     7                   1e1148e4cc2c        4 days ago          202MB

# docker run -it 1e1 /bin/bash
```

## 3. systemctlコマンドの実行 (失敗)

`systemctl` コマンドを実行したところ、例のエラーメッセージが表示されました。

```
# systemctl
Failed to get D-Bus connection: Operation not permitted
```

## 4. コンテナ起動時に --privileged オプションを利用 (失敗)

先ほどのコンテナは exit で終了し、改めてコンテナ起動時に `--privileged` オプションを付けて試してみます。

```
# docker run -it --privileged 1e1 /bin/bash
# systemctl
Failed to get D-Bus connection: Operation not permitted
```

結果、エラーメッセージは表示されてしまいます。

## 5. コンテナをdetach起動して/sbin/initを実行 (成功)

どうやら `systemctl` コマンドを使うためにはコンテナを detach したうえで `/sbin/init` を実行する必要があるようです。
detch したコンテナにはあとから `exec` でattachするようにします。

```
# docker run -d --privileged 1e1 /sbin/init
8badab2733bd54d514f597dcad8e642851a144da5cc62f6686d329aae34309b8

# docker exec -it 8ba /bin/bash
# systemctl
  UNIT                                   LOAD   ACTIVE     SUB       DESCRIPTION
  dev-sda1.device                        loaded activating tentative /dev/sda1
  -.mount                                loaded active     mounted   /
  dev-hugepages.mount                    loaded active     mounted   Huge Pages File System
  ...(略)...
```

無事にCentOS7のコンテナで `systemctl` が使えるようになりました。
【WordPress】はじめよう！Shifter！【Serverless】

## 概要
先日[ブログ](https://hisa-tech.site/2018/12/453)で同じような内容を書いたのですが反響がよかったのと、Qiitaでは意外なことにあまり記事がなかったので書こうと思いました。

## Shifterとは
動的サイトのWordPressをCloud上で構築して、公開するときには静的WebサイトにしてくれるステキService。
WordPressのときに抱えていた脆弱性は公開せず、見せたい所だけ公開することが出来ます。

つまり、WordPress運用において**サーバ管理とDB管理、脆弱性対策**をする必要がなくなります。
　
## プラン
![Kobito.715lFV.png](https://qiita-image-store.s3.amazonaws.com/0/33165/ef6ebedc-96b7-b177-62c6-5c5e3c442578.png "Kobito.715lFV.png")

プランごとで変わるのがサイト数、Storage、転送データ量、Customドメイン。
**Free Trial**で構築まではできるので、まず試してみるのであれば**Free Trial**で十分です。

## 準備
### アカウント作成
![Kobito.Xa18vF.png](https://qiita-image-store.s3.amazonaws.com/0/33165/917c19b8-b0a6-cb5c-95b8-37d39a57b75d.png "Kobito.Xa18vF.png")


- ユーザ名、メールアドレス、パスワードのみのシンプル登録です

### ダッシュボード
![Kobito.wvkTbi.png](https://qiita-image-store.s3.amazonaws.com/0/33165/5d07076a-b293-13b7-ce7a-2884a12f6dbc.png "Kobito.wvkTbi.png")

> Verify your account
>
> Before creating your site, we need to verify credit card information. This ensures that you're a real person and helps prevent fraud and abuse. You card will not be billed for our free trial.

- 本人確認のためにクレジットカードを登録と言われるので、クレジットカードの登録画面に移動するため**Verify**をクリックします。

![Kobito.WyJE7y.png](https://qiita-image-store.s3.amazonaws.com/0/33165/15d69219-2451-d891-9ffd-4c3b6dc82b15.png "Kobito.WyJE7y.png")

- クレジットカード情報入力して**Submit**、最初のダッシュボードに戻ります。

![Kobito.RiuQ2z.png](https://qiita-image-store.s3.amazonaws.com/0/33165/875ec6eb-a857-bc49-e33d-585231f534e8.png "Kobito.RiuQ2z.png")

- 本人確認のMessageが消えているので、サイト名を入力して**Create Site﻿**

![Kobito.dubker.png](https://qiita-image-store.s3.amazonaws.com/0/33165/191694fe-f99c-59d5-500a-4cc526879492.png "Kobito.dubker.png")

- SetUPが始まり、少し待つと右上に**StartWordPress**のボタンが表示されます。

### Start WordPress
![Kobito.hiqupn.png](https://qiita-image-store.s3.amazonaws.com/0/33165/c3b62e2f-b9ab-1871-c4cd-b96740a59b9c.png "Kobito.hiqupn.png")

- ボタンを押すとIDとパスワードが発行されて、セットアップが始まります。
- すこし時間が経つと、Close、Visit Site、Dashbordのボタンが出てきます。

![Kobito.UIIuCz.png](https://qiita-image-store.s3.amazonaws.com/0/33165/c497a3a6-a8d0-320c-7d95-c5eeadf58aab.png "Kobito.UIIuCz.png")

- **Dashbord**ボタンを押すと、WordPressの初期設定が始まります。
- 先程発行されたIDとパスワードを入力してログインします。
- 開始は英字ですが、WordPress側設定で日本語に変更できます。

## 静的Wenサイト化
![Kobito.yJuQzd.png](https://qiita-image-store.s3.amazonaws.com/0/33165/51645b50-717e-b1b0-e31d-59dcc72929c6.png "Kobito.yJuQzd.png")

- WordPressのセッティングが終わったら、こちらの画面に戻ります。
- 更新をすると**Generate**ボタンが押せるようになります。

![Kobito.f3pAcw.png](https://qiita-image-store.s3.amazonaws.com/0/33165/e048f5ca-a809-2249-63cc-b45501a52636.png "Kobito.f3pAcw.png")

- ジェネレート中はWordPressに入れないですよというお達しです。

![Kobito.XLnPxv.png](https://qiita-image-store.s3.amazonaws.com/0/33165/014382a3-1467-38c4-0a9e-c09b02176832.png "Kobito.XLnPxv.png")

- 完了するとこのような画面になります。Artifacts側が静的Wenサイトで隠してますが、URLも発行されます。

## まとめ
1時間かからないくらいで、WordPressを立てつつ静的Webサイト化できました。

注意点としては、Customドメインを使う場合は課金はやむを得ないです。
あとは、WordPressを動的サイトとして運用したい場合には使えないということです。

あくまでブログサイトなどの静的サイト利用向けですが、Webサーバー、DBサーバー、CDN、SSLまで揃えてくれて、運用もやってくれて年間契約なら1500円くらいでカスタムドメインも付けられるようになります。

既存のWordPressからの移行はまだやってないですが、ぜひともお試しください
gem squasher 実行時にdatabase.yml内に環境変数ENVでDBユーザ名/パスワードを読み込んでいるとエラーになる

[squasher](https://github.com/jalkoby/squasher) を実行しようとしたらDB接続のエラーが出てしまう。

```shell-session
$ bundle exec squasher 2019 -m 5.0
Squasher is creating a tmp database
Access denied for user 'root'@'localhost' (using password: NO)
Couldn't drop database 'squasher'
rake aborted!
Mysql2::Error: Access denied for user 'root'@'localhost' (using password: NO)
・
・
・
（以下略）
```

どうやらdotenvなど含めて、環境変数をdatabase.yml内で使ってると、squasherがそれを読み込めていないよう。
一旦、パスワードを直接書き込めば実行しましたが、issueも上がってたので、PRチャンスってやつですね。
https://github.com/jalkoby/squasher/issues/30

具体的にはこういうやつです。

```
# database.yml
development: &default
  adapter: mysql2
  encoding: utf8
  reconnect: false
  database: <%= ENV['DB_NAME'] %>
  pool: 5
  username: <%= ENV['DB_USER'] %>
  password: <%= ENV['DB_PASSWORD'] %>
```

ちなみに実行時のファイルを眺めてたら、実行中だけdatabase.ymlの中身書き換えて、ｔｍｐデータベース接続してるんですね。（なかなか豪快。

```rb
# database.yml
---
development:
  adapter: mysql2
  encoding: utf8
  reconnect: false
  database: squasher
  pool: 5
  username: ****
  password: ****

```
ActiveRecordを見ていたら吐き気を催した時

https://qiita.com/ak-ymst/items/5bc73eba8d2f6b9e29b8
https://qiita.com/haruharuharuby/items/fbca14582a22f413f1b9
https://qiita.com/CostlierRain464/items/5be3c1860bb5137db3d1


https://postd.cc/rails-doctrine/
Mac で絵文字を Slack 形式で補完入力できるアプリ "Rocket" がすごい！ emojiが見つからない対策。

# Rocket

🚀[こちらです](https://matthewpalmer.net/rocket/)

# ダウンロード

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89618/5c37eb92-949c-b58a-18ea-9997f415aa1c.png)

# アプリケーションフォルダにアプリを入れる

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89618/c79cc97b-5ff4-c717-9e4d-965a88271b9b.png)

# 起動する

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89618/f0d66ea0-2270-b565-8bc6-f4cfe87fd000.png)

# 警告が出るのがそのまま開く

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89618/aff81655-8a92-d770-7ed1-20ea207a583c.png)

# Macのアクセシビリティ設定でRocketを許可する

キーボード入力をハックする強力な動作なので許可が必要。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89618/6222c1f2-22f2-a59f-8e33-d25a9c588feb.png)

# デフォルトではいろいろなアプリで入力が無効化されているので、使いたいものを「Disable」の項目からマイナスする

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89618/92b4c8db-1144-ed13-88ac-0789b4ce636c.png)

# SublimeTextで使えるようになった例

`:ice` みたいに入力すると絵文字補完できるようになる

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89618/dddd9dd7-40cf-c223-459f-3f26dcddcfd1.png)




[絵文字yumainaura - Google Search](https://www.google.co.jp/search?q=%E7%B5%B5%E6%96%87%E5%AD%97yumainaura&oq=%E7%B5%B5%E6%96%87%E5%AD%97yumainaura&aqs=chrome..69i57.4204j1j7&sourceid=chrome&ie=UTF-8)








<!-- Update From Qiita API -->

# チャットメンバー募集


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

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





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
PySparkで書き込むファイル数をいい感じにする方法

# はじめに

この記事は[Mobingi Advent Calendar 2018](https://qiita.com/advent-calendar/2018/mobingi)の12日目の記事です。

# やりたかったこと

csvをparquetに変換する処理をAWS GlueのPython（ほぼPySpark）で実現していたのですが、出力されるファイル数が細かくなりすぎるという問題に悩まされていました。

```python:この時細かすぎるファイルが作られる場合がある
output_df.write.save(path=output_path, format=output_format,
                        mode='overwrite', compression=output_compression)
```


細かすぎるファイルはパフォーマンス的によろしく無いですし、Athenaでのクエリ実行時などで`too many open files`といったエラーが出やすくなってしまいます。

そこで出力するファイルサイズをもとに書き込むファイル数をいい感じにコントロールするオプションを探しました。しかしそんな方法はなさそうでした。。。
代わりに書き込むファイル数（厳密にはデータフレームの並列数？）を指定する[repartition](http://spark.apache.org/docs/2.1.0/api/python/pyspark.sql.html?highlight=repartition#pyspark.sql.DataFrame.repartition)というメソッドがありました。

このメソッドを使えば出力されるファイル数は指定できるけど、データサイズに応じて数を調整できないと、データ量の増加に応じていちいちジョブをチューニングしなければいけなくなります。

# 解決策

ということで、以下のようなs3上のデータサイズを取得する関数と適切なファイル数を計算する関数を作って適切なpartition数を事前計算するようにしました。

```python
def fetch_total_object_size(bucket, path):
    b = s3.Bucket(bucket)
    total_size = 0
    objects = b.objects.filter(Prefix=path)
    for o in objects:
        total_size += o.size    
    return total_size

def calculate_repartition_num(previous_total_size, tatget_size, default_num=3):
    # roundup
    num = -(-previous_total_size // tatget_size)
    if num == 0:
        return default_num
    return num
```

```python:GlueScript抜粋
KB = 1024
MB = KB * 1024
TARGET_FILE_SIZE = 32 * MB

previous_size = fetch_total_object_size(bucket, path)
num = calculate_repartition_num(previous_size, TARGET_FILE_SIZE)
output_df.repartition(num).write.save(path=output_path, format=output_format,
                        mode='overwrite', compression=output_compression)
```

これにより、毎日上書き更新する系のデータの場合は書き込み先のs3パスを参考に、時系列データであれば前日のデータなどを参考にサイズを決定できるようになりました。上の例ではs3をストレージとしていますがHDFSでも似たようなことは容易かと思います。
SoundCloud投稿できない問題の解決(JPN and ENG)

# solution by english
plz see following page
https://community.soundcloud.com/upload-manage-230060/workaround-for-stacked-processing-7424449

# 解決方法
解決策だけ見せろやって人向け (Chromeのみ）

* [Google WebStore](https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo?hl=ja) からTamperMonkeyをインストールする
* 拡張機能バーからDashboardを選択
   <img width="253" alt="Screen Shot 2018-12-10 at 17.25.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/137384/f1b6c416-d6a4-8cdd-f1f8-83e53867b7a2.png">

* **+** を選択してスクリプト編集ページに移動
   <img width="155" alt="Screen Shot 2018-12-10 at 17.26.51.png" src="https://qiita-image-store.s3.amazonaws.com/0/137384/39588178-4ffb-af51-9ca9-8a699e0b53cd.png">

* 以下を貼り付け

   ```js
// ==UserScript==
// @name         Workaround for SoundCloud
// @namespace    http://soundcloud.com/
// @version      0.1
// @description  公式で修正されたら削除してね
// @author       Angeart
// @match        https://soundcloud.com/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';
    window.ga = () => {}
})();
   ```
* Saveで保存
   <img width="192" alt="Screen Shot 2018-12-10 at 17.28.56.png" src="https://qiita-image-store.s3.amazonaws.com/0/137384/25904f14-437c-8bee-69a0-4b208c2e9210.png">

* 完了〜〜〜

# なんかアップロードできなくなった
先日日曜日、意気揚々とブートレグをアップロードしようとしたら"Processing.."のところから進まなくなった

# なんでやねーーん
調べたら音雲の設定でGoogle AnalyticsをOFFにしているとモジュールの読み込みが失敗している様

# SoundCloudへ
早よ直せ

# その他
細かいやり取りは一番上に貼ったリンク先でやってるのでみたい人はどうぞ
Zxingで雑誌コードを読み込めるのか

タイトル通りなのですが、Zxingでバーコード読み取り機能を作成しようと考えているのですが、詰まっています。

```fileprivate let kKTCommonBarcodeFormats: [ZXBarcodeFormat] = [
　　　kBarcodeFormatUPCA,
　　　kBarcodeFormatUPCE,
　　　kBarcodeFormatEan13,
　　　kBarcodeFormatEan8,
　　　kBarcodeFormatCode128,
　　　kBarcodeFormatCodabar,
　　　kBarcodeFormatPDF417
]```

現ざし設定しているのはこのフォーマットたちです。
そもそも雑誌コードがZxingで読めるのかがわかっていません。

ご教授お願いします。
Site24x7の無料ツールが意外と優秀な件

はじめまして、mezguinと申します。

表題の通り、本日は、[Site24x7](https://www.site24x7.jp/)のメイン機能でない部分について書こうと思います。

あまり注目されていないかもしれませんが、Site24x7には、ユーザー登録して使用できるメインの監視機能のほかに、ユーザー登録不要で使えてしまう部分があります。

そこが個人的にヒットしたので、スポンサーカレンダーなのに登録不要の無料機能を紹介してしまいます。（すみません）

# Site24x7とは？
アドベントカレンダーが始まって結構経過しているので必要ないかとも思ったのですが、まずはサービスの紹介から。
![2020-02-26_11h48_59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320280/52dda1e8-e658-825a-2eda-1e6190c31b21.png)

> サーバー監視、APM、Web監視もクラウドから

と書いてあります。その言葉通り、SaaS型の監視サービスで、Webアプリの監視やパフォーマンス分析を得意としているサービスです。

が、登録して中身をよくよく見てみると、どうも、Webだけでなく、ネットワーク装置やオンプレのサーバー等、下のレイヤーもいけそうな気配。

『統合監視ソフトウェア』とか『システム一元管理ツール』とか言われているものと、実は似ているようです。

本日は、そんな[Site24x7](https://www.site24x7.jp/)の中身を詳しく見て…………いかず、トップページのここ↓↓
![2020-02-26_11h50_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320280/fe166b84-a0bb-c36c-b077-f7892f1082db.png)
『ツール』を見ていきます。

# 『Web開発支援ツール』

## 何がある？

この投稿を書こうと思いついた当初予想していたよりだいぶ多めでした。その数50個以上。
![2018-12-10_17h14_56.png](https://qiita-image-store.s3.amazonaws.com/0/320280/46afaefb-21af-1427-8ea0-85cec7df31a3.png)
中は「運用管理者向けツール」「検証ツール」「コンテンツチェックツール」「開発者向けツール」のカテゴリーにわかれています。


## Site24x7の『Web開発支援ツール』を使うメリット

これらのツールは、ここにしかないわけではありません。Google検索すればいくらでも出てくるかと思います。

が、

・いちいちググってツールを探す --> めんどくさい

・ググって出てきたツールをブックマークする --> （普通は）別のPCや別ブラウザから使えない

という問題点があると思っているので、Site24x7にこれだけツールが集められているのは、どこからでもアクセス可能なブックマークみたいな便利さを感じました。


## 勝手におすすめ紹介

一つ一つ解説はできないので（というかよくわからないのもある）、その中でも、個人的に使えそうだなと思ったものをメモ代わりに羅列。

## Web管理者におすすめ

### フォーマットチェック系

JSON、XML、SQLをずらずらっと書いていても、改行やインデントを適度に入れてくれ、可読性を高めてくれます。

書いている途中でだんだん崩れていって、あとから調整が大変…という場合に重宝します。

JSON用：
https://www.site24x7.com/tools/json-formatter.html

XML用：
https://www.site24x7.com/tools/xml-formatter.html

SQL用：
https://www.site24x7.com/tools/sql-formatter.html


### リンクチェック系

リンクをツリーにして表示できます：
https://www.site24x7.com/link-explorer.html

リンク切れの一覧を作成できます：
https://www.site24x7.com/link-checker.html

### パフォーマンス比較
2つのサイトの応答時間を、アメリカ、カナダ、シンガポール、インド、オーストラリアからのアクセス時間で比較できます。

競合サービス等とのサイト速度比較だったり、海外からのアクセスを見込んでいるサイトであれば、海外アクセスの様子等も確認できます。

https://www.site24x7.com/tools/website-comparison.html


## サーバー管理者におすすめ

私はサーバー管理者ではないのですが、それと似たようなことを過去に仕事でやっていました。

そこであって嬉しかったものをご紹介。

### タイムスタンプ変換

ログ解析とかで地味ーに使うような。
https://www.site24x7.com/tools/time-stamp-converter.html

## 個人にもおすすめ

普段から使えそうなものをピックアップ。

### ランダムパスワード

強めのパスワードが簡単に作れます。
https://www.site24x7.com/tools/random-password-generator.html

## AWSユーザーにおすすめ

AWSの構成をお絵かきできるツールが最近登場したようです。作成した図に公開用URLを発行してシェアすることも可能。

![2019-12-16_13h19_54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320280/9d288100-ecc4-aed2-c1ad-dbd6e94a4a70.png)

https://www.site24x7.com/tools/aws-designer.html

## 注意点

ものによっては、チェックした履歴が、アクセスした人全員が見られる状態で表示されるものがあります。

こんな感じ。念のためモザイクしました。
![2018-12-10_16h49_08.png](https://qiita-image-store.s3.amazonaws.com/0/320280/4c257844-b0e5-8696-fefa-97a97073d838.png)
公開したくないページだったり、不特定多数からのアクセスを見込んでいないサービスの場合は、Site24x7のWebツールの利用は控えたほうがよさそうです。

# まとめ

「お手軽に色々な監視が始められる」と紹介されているのをおみかけしましたが、もはや登録しなくても色々使えてしまうという。

唯一無二の超絶便利ツール！というわけではないですが、ここにこれだけ集まっているということがわかると、地味に便利さが効いてくる気がしました。

メインのWebページ監視と併せたら、もっと便利感が増すかもしれません。
【GoogleAppsScript】GASでGoogleドライブ内のファイル名とURLを一括で取得してCSV出力する

とある業務で大量の画像ファイルが入ったGoogleドライブの特定フォルダから、ファイル名とURLを取得してCSVで出力する必要があったので、さくっとGASでできるようにした。

使う機会はそこまで無いかもしれないけど、備忘のために残しておきます。


# 下準備
コード内のGOOGLE_DRIVE_IDは以下を参考に取得してください。

![Alt text](https://i.gyazo.com/99858c77e488f3cca8edcd922724be8c.png)


# コード

```JavaScript:
function getList() {
  //ファイルを入れるフォルダを取得
  var folder = DriveApp.getFolderById('GOOGLE_DRIVE_ID');
  //csvファイルの保存先を指定
  var save_drive = DriveApp.getFolderById('GOOGLE_DRIVE_ID');
  
  var fileName = 'path_name.csv';  // 保存ファイル名
  var contentType = 'text/csv'; // コンテンツタイプ
  var charset = 'utf-8';        // 保存文字コード
  var delimiter = ',';          // 区切り文字
  var nl = '\n';
  var csvStr = '';

  //フォルダ内のファイルを一括取得
  var files = folder.getFiles();

  //配列を宣言
  var contents = new Array();

  //ここから、配列に「名前」「説明」「URL」を入れていく
  for(var i = 0; files.hasNext(); i = i + 3) {
    //一括取得したファイルの中から順に一つ取り出す
    var file = files.next();
    //「名前」「URL」をCSV形式で格納
    csvStr += file.getName() + delimiter + file.getUrl() + nl
  }
  
    // 新しい Blob を作成する
  var blob = Utilities.newBlob('', contentType, fileName).setDataFromString(csvStr, charset);
  // ファイル保存
  save_drive.createFile(blob);
}

```
RISC-Vs and Cortex-Ms on VEGAboard

VEGAという新しいRISC-Vボードが出ました(for Free)。
Arm Cortex-Mも搭載するヘテロ構成チップ搭載です。
時間を見つけて試したいところです。
![DSC_1300.JPG](https://qiita-image-store.s3.amazonaws.com/0/324827/cc4865d4-6a79-dc05-09e5-af8fa92d00d4.jpeg)
![DSC_1303.JPG](https://qiita-image-store.s3.amazonaws.com/0/324827/69ce20a9-ac63-aff6-ca36-181a8ddb57ec.jpeg)

#[RV32M1](https://github.com/open-isa-org/open-isa.org/blob/master/Reference%20Manual%20and%20Data%20Sheet/RV32M1DS_Rev.1.1.pdf)
- CPU: 48-72MHz Arm Cortex-M4/Cortex-M0+, RISC-V RI5CY/ZERO-RISCY
- ROM: 1.25MB
- RAM: 384KB
- Package: 176 VFBGA 9x9x0.86mm
- NXP manufactured


http://www.open-isa.org
juliaでPlot.jl tilte等に英語以外は駄目 BoundsError

`Julia: ver.1.0.2`
`GR: ver0.6, ver1.0`
# GRでtitleや軸ラベルの設定
```
hoge = [1,2,3]; foo = [1.5,2.5,3.5]
data = [hoge, foo]
labels = ["hoge", "foo"]
using Plots
Plots.gr()
plot(data, 
     xaxis = "x axis",
     yaxis = "y axis",
     label = labels,
     title = "aa")
```
<img width="604" alt="gr1.png" src="https://qiita-image-store.s3.amazonaws.com/0/164411/d4688ece-e311-b0a5-a475-37b341d34bb2.png">


# `GR: ver0.6 & ver1.0`の場合
title等に日本語やギリシャ文字を使うと，
BoundsErrorを吐く (なんでBoundsError ??)

```
hoge = [1,2,3]; foo = [1.5,2.5,3.5]
data = [hoge, foo]
labels = ["hoge", "foo"]
using Plots
Plots.gr()
plot(data, 
     xaxis = "x axis",
     yaxis = "y axis",
     label = labels,
     title = "あ")
```

```
BoundsError: attempt to access 2-element Array{UInt8,1} at index [3]

Stacktrace:
 [1] setindex!(::Array{UInt8,1}, ::Int64, ::Int64) at ./array.jl:583
 [2] latin1(::String) at /Users/Asahi/.julia/v0.6/GR/src/GR.jl:522
 [3] text at /Users/Asahi/.julia/v0.6/GR/src/GR.jl:554 [inlined]
 [4] gr_text(::Float64, ::Float64, ::String) at /Users/Asahi/.julia/v0.6/Plots/src/backends/gr.jl:214
 [5] gr_display(::Plots.Subplot{Plots.GRBackend}, ::Measures.Length{:mm,Float64}, ::Measures.Length{:mm,Float64}, ::Array{Float64,1}) at /Users/Asahi/.julia/v0.6/Plots/src/backends/gr.jl:943
 [6] gr_display(::Plots.Plot{Plots.GRBackend}, ::String) at /Users/Asahi/.julia/v0.6/Plots/src/backends/gr.jl:583
 [7] _show(::Base.AbstractIOBuffer{Array{UInt8,1}}, ::MIME{Symbol("image/svg+xml")}, ::Plots.Plot{Plots.GRBackend}) at /Users/Asahi/.julia/v0.6/Plots/src/backends/gr.jl:1380
 [8] show(::Base.AbstractIOBuffer{Array{UInt8,1}}, ::MIME{Symbol("image/svg+xml")}, ::Plots.Plot{Plots.GRBackend}) at /Users/Asahi/.julia/v0.6/Plots/src/output.jl:202
 [9] #sprint#228(::Void, ::Function, ::Int64, ::Function, ::MIME{Symbol("image/svg+xml")}, ::Vararg{Any,N} where N) at ./strings/io.jl:66
 [10] display_dict(::Plots.Plot{Plots.GRBackend}) at /Users/Asahi/.julia/v0.6/Plots/src/output.jl:295
 [11] (::Compat.#inner#6{Array{Any,1},IJulia.#display_dict,Tuple{Plots.Plot{Plots.GRBackend}}})() at /Users/Asahi/.julia/v0.6/Compat/src/Compat.jl:189
 [12] execute_request(::ZMQ.Socket, ::IJulia.Msg) at /Users/Asahi/.julia/v0.6/IJulia/src/execute_request.jl:223
 [13] (::Compat.#inner#6{Array{Any,1},IJulia.#execute_request,Tuple{ZMQ.Socket,IJulia.Msg}})() at /Users/Asahi/.julia/v0.6/Compat/src/Compat.jl:189
 [14] eventloop(::ZMQ.Socket) at /Users/Asahi/.julia/v0.6/IJulia/src/eventloop.jl:8
 [15] (::IJulia.##13#16)() at ./task.jl:335
```
複数のDockerイメージを単一リポジトリで管理する


この記事は[Docker Advent Calendar 2018](https://qiita.com/advent-calendar/2018/docker)の10日目の記事です。

# はじめに

インフラチームとして提供する共通利用のDockerfileはDockerfileごとにリポジトリを作ってると沢山リポジトリが増えて結構大変です。しかし単一のリポジトリに複数のDockerfileを纏めると今度はCI/CDでDockerイメージをビルドするのが難しくなります。

この記事では複数のDockerfileを単一のリポジトリにまとめた時に、差分のあったDockerfileだけをビルドする構成について紹介します。

# ディレクトリ構成

今回のサンプルの構成はgithubに上げてます。
https://github.com/kanga333/dockerfiles-monolepo

プロジェクトのディレクトリ構成は以下のような感じです。

```
dockerfiles-monolepo
├── Makefile
├── README.md
├── dockerfiles
│   ├── proxy-nginx
│   │   ├── Dockerfile
│   │   ├── Makefile
│   │   └── files
│   │       ├── nginx.conf
│   │       └── service.conf
│   └── python-lambda-builder
│       ├── Dockerfile
│       ├── Makefile
│       └── README.md
└── scripts
    └── git-diff-make.sh
```

`dockerfiles`の下にDockerfileごとのディレクトリを切っていくような構造になります。

# 構成のポイント

## DockerfileのビルドをMakefileによって抽象化する

Dockerfile用のディレクトリにMakefileを用意して`make release`コマンドを実行すれば`docker build & push`してくれるようにします。これによってリリース操作を抽象化します。

```make:Makefileサンプル
NAME         := python-lambda-builder
REVISION     := $(shell git rev-parse --short HEAD)
ORIGIN       := $(shell git remote get-url origin | sed -e 's/^.*@//g')
RELEASE_TAGS := 1.0.0 $(REVISION)
TAGS         := $(REVISION)
REGISTRY     := index.docker.io
USER         := kanga333

.PHONY: build
build:
	@docker build \
		--build-arg GIT_REVISION=$(REVISION) \
		--build-arg GIT_ORIGIN=$(ORIGIN) \
		--build-arg IMAGE_NAME=$(REGISTRY)/$(USER)/$(NAME) \
		$(addprefix -t $(REGISTRY)/$(USER)/$(NAME):,$(TAGS)) .

.PHONY: push
push:
	@for TAG in $(TAGS); do\
		docker push $(REGISTRY)/$(USER)/$(NAME):$$TAG; \
	done

.PHONY: release
release:
	@make build TAGS="$(RELEASE_TAGS)"
	@make push TAGS="$(RELEASE_TAGS)"
```

ちなみに以前dockerをビルドする際のMakefileについて記事を書いたのでこちらも合わせて参照いただければと思います。
https://qiita.com/kanga/items/aba6928996cb57daa460

## 差分のあったディレクトリを検知するShellスクリプト

このshellスクリプトは前回のコミットとの差分を比較して更新があったディレクトリでのみmakeを実行するshellスクリプトです。

```shell
#!/bin/bash

set -eu

if [ $# -ne 1 ]; then
    echo "Please specify the argument of make." 1>&2
    exit 1
fi

TARGETS=`find dockerfiles -maxdepth 1 -mindepth 1 -type d`
for TARGET in $TARGETS
do
    HAS_DIFF=`git diff --diff-filter=ACMR --name-only HEAD\^ HEAD --relative=$TARGET | head -1`
    if [ ! -z $HAS_DIFF ]; then
        ( cd ${TARGET} && make $1 )
    fi
done
```

`git diff --diff-filter=ACMR --name-only HEAD\^ HEAD --relative=$TARGET | head -1`によって対象ディレクトリで差分があるか無いかを判断するフィルターを実現しています。

あとはCIでマスターにマージされた際にこのshellスクリプトを呼ぶことで差分のあったディレクトリのみでビルドが走るようになります。

```bash
sh scripts/git-diff-make.sh release
```

### 注釈
ただしこの方法だと前回のコミットとの比較なのでマージが動いた事が差分検知の前提になります。
PRごとにビルドをしたい場合はMasterにマージした後に`sh scripts/git-diff-make.sh`を動かすようにCIを工夫する必要があります。
【PHP】抽象クラスで地味につまづいた

# はじめに

PHPの抽象クラスを使っていて地味につまづいたのでログとして残しておく

# 内容

```php5

abstract class BaseBar
{
    protected $model;

    public function __construct()
    {
        $this->model = new Model();
    }

    protected function foo(int $id)
    {
        var_dump($this->model);//null
    }
}

class Bar extends BaseBar
{
    public function __construct()
    {
    }

    public function index($id)
    {
        $this->foo($id);
    }
}

```

こんな感じで抽象クラス内で別クラスをインスタンス化したところ、nullに。

```php5

abstract class BaseBar
{
    public function __construct()
    {
    }

    protected function foo(int $id, $model)
    {
        var_dump($model);//object
    }
}

class Bar extends BaseBar
{
    public function __construct()
    {
    }

    public function index($id)
    {
        $model = new Model();
        $this->foo($id, $model);
    }
}

```
や

```php5

abstract class BaseBar
{
    public function __construct()
    {
    }

    protected function foo(int $id)
    {
        $model = new Model();
        var_dump($model);//object
    }
}

class Bar extends BaseBar
{
    public function __construct()
    {
    }

    public function index($id)
    {
        $this->foo($id);
    }
}

```

これはOKみたいでした。
なんでnull?

# 少しググり進めたらすぐに解決した

```php5

abstract class BaseBar
{
    protected $model;

    public function __construct()
    {
        $this->model = new Model();
    }

    protected function foo(int $id)
    {
        var_dump($this->model);//object
    }
}

class Bar extends BaseBar
{
    public function __construct()
    {
        parent::__construct();
    }

    public function index($id)
    {
        $this->foo($id);
    }
}

```

子クラスにコンストラクタがある場合宣言しないと親クラスのコンストラクタはコールされないらしい
GTK+3でWebページを表示する

せしまるです。

GTK+3で作った画面にWebページを表示する方法を試してみたので記事にしました。

# webkit2gtkのインストール
ターミナルで以下コマンドを実行。

```terminal
$ sudo apt install webkit2gtk-4.0
```

# 実装

```c++:webkit_test.cpp
#include <gtk/gtk.h>
#include <glib.h>
#include <webkit2/webkit2.h>

// class WebKitTest.

int main(int argc, int argv[]){
    gtk_init(&argc, &argv);

    ～～画面作成～～
   
    // Webページを表示するウィジェットを生成.
    WebKitWebView webview = WEVKIT_WEB_VIEW(webkit_web_view_new());
    // 初期ページ設定.
    webkit_web_view_load_uri(webview, "https://google.com/");
    // GtkBoxに入れる.
    gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(webview), TRUE, TRUE, 0);

    // 表示.
    gtk_widget_show_all(window);
    
    gtk_main();

    gtk_widget_destroy(window);
    
    return 0;
}

```

ビルドして実行するとWebページが表示されます。

# 問題点
この状態だと問題がいくつかあります。
1. back/forwardボタンがない
2. reloadボタンがない
3. URL入力して直接飛べない
4. 表示できないページがある

# 解決＆今のところ解決できなかったこと
順番にご説明しますm(_)m

### 解決できたこと
1.のback/forwardボタンはそれぞれ関数が用意されています。それをボタンのコールバックで実行することで解決できました。ただ~~見た目がボタンボタンしている~~ボタンだと見栄えが悪いので、イベントボックス＋イメージウィジェットを使用して、アイコンボタン化するといい感じになります。
以下back/forwardの実装部分

```c++:back_foward.cpp
// ボタン用.

static void OnBackButtonClicked(GtkWidget* button, GtkWidget* webview){
    // back.
    webkit_web_view_go_back(WEBKIT_WEB_VIEW(webview));
}

static void OnForwardButtonClicked(GtkWidget* button, GtkWidget* webview){
    // forward
    webkit_web_view_go_forward(WEBKIT_WEB_VIEW(webview));
}

// イベントボックス用.

static void OnBackButtonPress(GtkWidget* button, GdkEvent* event, GtkWidget* webview){
    // back.
    webkit_web_view_go_back(WEBKIT_WEB_VIEW(webview));
}

static void OnForwardButtonPress(GtkWidget* button, GdkEvent* event, GtkWidget* webview){
    // forward
    webkit_web_view_go_forward(WEBKIT_WEB_VIEW(webview));
}
```

2.のreloadボタンも1.と同じように関数が用意されているので、コールバックで実行する感じです。

```c++:reload.cpp
// ボタン用.

static void OnReloadButtonClicked(GtkWidget* widget, GtkWidget* webview){
    // reload.
    webkit_web_view_reload(WEBKIT_WEB_VIEW(webview));
}

// イベントボックス用.

static void OnReloadButtonPress(GtkWidget* widget, GdkEvent* event, GtkWidget* webview){
    // reload.
    webkit_web_view_reload(WEBKIT_WEB_VIEW(webview));
}
```

3.のURL直叩きについては、入力ボックスを配置して、開くボタンorEnterキー入力で指定のURLに飛ぶようにしました。
また、entryウィジェットとwebviewウィジェットはprivateなグローバル変数で持つようにしてます。

```c++:url_load.cpp
void OpenURL(){
    std::string str(gtk_entry_get_text(GTK_ENTRY(entry));
    webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview), str.c_str());
}

static void OnOpenButtonClicked(GtkWidget* widget, WebKitTest* wkt){
    ((WebKitTest*)wkt)->OpenURL();
}

static void OnKeyRelease(GtkWidget* widget, GdkEventKey *event, WebKitTest* wkt){
    // enterキーのみ.
    if( event->keyval == 65293 ){
        ((WebKitTest*)wkt)->OpenURL();
    }
}
```

### 解決できなかったこと
4.の開けないページは…現時点ではわかりませんでした。
見れないページがあると不便すぎるので、今後も調査はしていく予定です。
（わかり次第更新します）

開けないページの例としては、YoutubeやGoogleの画像検索など（環境によってかわるかもしれません）。


# 最後に
今回はGTKでWebページを表示してみました。
ブラウザっぽいことが簡単にできるかなーと思ってましたが、割と時間がかかりました。
上記コードだけだと、他にも問題があるかもしれません（4.とかね）
AWSを使ってほぼ無料で自動更新されるサイトを構築する方法

AWSの各種サービスを駆使して、ほぼ無料で自動更新なサイトを構築する方法をざっくりと解説。
S3のホスティングではなくCloudFrontを盛り込んだパターン。
※実際には、Route53のHostedZoneに月50円くらいかかる。

# 構成イメージ
![自動更新なサイトの構成図.jpg](https://qiita-image-store.s3.amazonaws.com/0/263737/4485f07b-2c14-f640-8908-363a0c7f8d27.jpeg)

# 利用するサービス
- Route53
  - DNS。ドメインを設定して、CloudFrontへルーティングする。
- CloudFront
  - CDN。S3をオリジンにして、静的コンテンツを配信する。
- CertificateManager
  - SSL/TLS証明書を無料でもらう。
- S3
  - ストレージ。
- Lambda
  - S3に置くhtmlなどの静的コンテンツを更新する。
- CloudWatch
  - スケジュールイベントでLambdaを定期実行する。 

# ざっくり手順

## 1. S3にBucketを作って、コンテンツを置く
好きな名前でBucketを作る。
※この時、__Static website hosting__は無効のままで良い。

## 2. コンテンツを更新するLambda関数を実装する
以下のコードは、Lambda関数の実行時刻をhtmlに書き込んでいるだけ。
実際には、スクレイピングするなどして、サイトの情報を更新する感じ。

```javascript
'use strict';

const AWS = require('aws-sdk');
const s3 = new AWS.S3();
const hbs = require('handlebars');

exports.handler = (event, context) => {
  const template = hbs.compile(`
  <!DOCTYPE html>
  <html>
  <head>
    <meta charset="UTF-8">
    <title>サンプル</title>
  </head>
  <body>
    <p>{{date}}に更新されました。</p>
  </body>
  </html>`);

  const html = template({ date: new Date() });

  const params = {
    Bucket: 'your-bucket-name',
    Key: 'index.html',
    ContentType: 'text/html',
    Body: html
  };

  s3.putObject(params, (err, data) => {
    if (!err) {
      context.succeed('Finished');
    } else {
      context.fail('Failed!');
    }
  });
};
```

## 3. CloudWatchイベントでLambdaを定期実行する
CloudWatch > イベント > ルールからルールを作成する。
`イベントソース` でスケジュールを選んで、お好みの間隔を設定する。
`ターゲット` には、先ほど作ったLambda関数を指定する。

## 4. CloudFrontにS3がオリジンなDistributionを作る
設定のポイントは主に次。
- `Restrict Bucket Access`を`Yes`にする
- `Origin Access Identity`でCloudFrontがBucketにアクセス可能にしておく
- `Alternate Domain Names`に使うドメインを設定しておく

CloudFrontはDeployedステータスになるまで時間がかかる。
完了したら、CloudFrontによって自動で作られるドメイン（例：`xyzxyzxyzxyz.cloudfront.net`）にアクセスして、サイトが表示されることを確認する。

### Origin Settings
![cloudfront-1.jpg](https://qiita-image-store.s3.amazonaws.com/0/263737/d693389e-0285-1cae-371e-9343b7900afe.jpeg)

### Distribution Settings
![cloudfront-2.jpg](https://qiita-image-store.s3.amazonaws.com/0/263737/455fc69f-5915-76f6-dcb3-dc5ee414e2b2.jpeg)

## 5. Route53にドメインを設定して、CloudFrontにルーティングする
AWSでドメインを取る場合、`.com`だと12$/年。
無料のドメインを別サービスで取って、Route53で管理すれば安く上がる。
ドメインを取るか委譲する際に作ったHostedZoneにAレコードを追加して、先ほどのCloudFrontを紐づける。

![route53.jpg](https://qiita-image-store.s3.amazonaws.com/0/263737/be7e25cc-36c8-b658-dd59-f9818d617c35.jpeg)


## 6. CertificateManagerで証明書を作る
証明書をCloudFrontで使いたいので、バージニア北部 `us-east-1` リージョンで作る。
検証方法の選択では__DNSの検証__を選ぶ。
Route53で管理しているドメインなら、`Route53でのレコード作成`ボタンが現れるので、それを押すだけで良い。
すると、先ほど作ったHostedZoneに`CNAME`のレコードが追加される。

![acm.jpg](https://qiita-image-store.s3.amazonaws.com/0/263737/161ef087-2d2d-cd34-be8c-4de69c6c8e51.jpeg)

## 7. CloudFrontに証明書を設定する
先ほど作った証明書をCloudFrontのDistributionに紐づける。

![cloudfront-3.jpg](https://qiita-image-store.s3.amazonaws.com/0/263737/78e82fc8-c587-53ed-dd61-39b9185f5631.jpeg)


# まとめ
以上で、ほぼ無料で自動更新されるサイトが構築できる。
"23:59:59"を使わないSQL期間表現

以前「[日付で期間指定するときに「23:59:59.999」を使わない](https://qiita.com/yuba/items/d7109e684761936e94e8)」なる記事をAPI設計の視点で書いたことがありますが、これはRDBのスキーマ設計・クエリ設計に関しても同じことが言えますので `OVERLAPS` 述語の紹介も加えて改めて。

- 終了日時を表すカラムに「23:59:59.99...」を格納する形式にせず、翌日の「00:00:00」を格納する設計にする
- 日時範囲を指定して問い合わせるクエリで、範囲末を「23:59:59.99...」で指定する形式にせず、翌日の「00:00:00」を指定する形式にする

です。

その理由は前掲のリンク先の内容ともまったく共通するのですが以下の2点です。

- 「23:59:59」のような記述の精度がDBの日時型の精度と一致していなければ、**データの取りこぼしや二重取得を発生させる**
- DBの日時型の精度と一致していたとしても、**精度は何桁かという処理系知識に強く依存**したコードになり読み手に無用な負担をかける

「終了日時を翌日の00:00:00で表す」というのはもう少し一般化した表現をすると **期間は左閉右開の半開区間（＝期間頭以上・期間末未満の組）で表現する** ことだと言えます。
これはAPI設計・RDB設計にとどまらない普遍的な原則となるわけですが、RDBにおいては、次のような注意点が加わります。

- 日付時刻の範囲判定に `BETWEEN` 述語を使わない

BETWEEN述語を使う場合の弊害
---

SQLで `x BETWEEN a AND b` は `a <= x AND x <= b` と等価です。
終了日時を含む判定をしてしまうため、

```sql
:some_datetime BETWEEN start_time AND end_time
```

という判定式は終了日翌日の00:00:00も引っかけてしまいます。
先週分、先々週分、と期間を分けながらレコードを取得するなどしたときにわずかながら二重取得されるレコードが出てくるわけです。
よって、見た目のスマートさで劣るのですが以下の形で記述するのが漏れのない問い合わせとなります。

```sql
(start_time <= :some_datetime AND :some_datetime < end_time)
```

OVERLAPS述語
----

上記の正しい書き方では `:some_datetime` というプレースホルダを2回書くことになりました。
1 wordで書けるものなら2回書くことも特にためらわれるものではないのですが、これがもう少し複雑な計算式だった場合にはどうしましょう。
可読性は悪くなりますし、後に片方を修正したときにもう片方の修正を忘れる、ミスるといったリスクも抱えることになります。

今回紹介しますSQL標準の `OVERLAPS` 述語を使うと2重記述が避けられます。
Oracle, PostgreSQL, DB2以外は採用していないマイナーな述語なのが残念ですが。

```sql
(start_time, end_time) OVERLAPS (:some_datetime, INTERVAL'0'DAY)
```

`OVERLAPS` 述語は本来、二つの日時範囲（もちろん、左閉右開の半開区間）が重なっているかを判定するものです。
ただし、長さがゼロの範囲を渡すことである単一の日時が範囲に含まれるかの判定にも使えるというもの。

詳細な仕様を述べますと、 `(S1, Ｔ１) OVERLAPS (S2, T2)` とは

```sql
( S1 > S2 AND NOT ( S1 >= T2 AND T1 >= T2 ) )
OR
( S2 > S1 AND NOT ( S2 >= T1 AND T2 >= T1 ) )
OR
( S1 = S2 AND ( T1 <> T2 OR T1 = T2 ) )
```
であると定義されています（S>T だったり S IS NULL だったときには SとTを交換して読みます）。

`( T1 <> T2 OR T1 = T2 )` などという一見無意味な項が含まれていますが、これが無意味でないのは各オペランドがNULLである可能性があるからです。
ところが実際 NULL を与えてみるとRDB製品によって異なる結果が出る場合があります。
例えばOracleは本来NULL判定されるべき次の式をFALSEと判定します。

```sql
(DATE'2018-01-02', NULL) OVERLAPS (DATE'2018-01-03', DATE'2018-01-04')
```

NULLが渡る可能性のある式ではRDBの非標準動作に注意する必要があるという但し書きが付きますが、期間に含まれるかの判定・期間が重なるかの判定には`OVERLAPS`の使用もご検討くださいませ。
コード意図を明確にしつつ、左閉右開という良い期間定義方法を強制してくれます。
reCAPTCHAv3を使ってみた

#reCAPTCHAv3とは

簡単にまとめると数々のサイトで使用されている「私はロボットではありません」をチェックさせるアレの最新版です。
reCAPTCHAv2ではユーザがチェックを入れる必要がありましたが **今回のv3ではユーザの操作は一切必要ありません。**
詳細は割愛させていただきます。以下参考にどうぞ。
https://developers.google.com/recaptcha/docs/v3

#導入方法

とても簡単です。1分もかからないです。

1.以下で登録を行う(Googleアカウントが必要となります)
https://www.google.com/recaptcha/intro/v3.html

v3をチェックしてRegister→ドメインなどの入力事項を埋める

2.フロント側に処理を追加する
登録を済ませるとわかりますが、登録完了後の管理画面に
Keys
Step1
Step2
と表示してくれているので、コピーして導入したいコードの部分に貼り付け。ね！簡単でしょ。

actionに関しては公式を参考に↓

| アクション       |       説明 |
|:-----------------|------------------|
| homepage             |              See a cohesive view of your traffic on the admin console while filtering scrapers. |
| login           |            With low scores, require 2-factor-authentication or email verification to prevent credential stuffing attacks. |
| social             |              Limit unanswered friend requests from abusive users and send risky comments to moderation. |
| e-commerce               |                Put your real sales ahead of bots and identify risky transactions. |


※アクションによって動作が変わるというより、どういう用途で使うか？と捉えた方がいいかもしれません。
(管理画面での確認しやすさのためにあると思っております)

3.サーバ側に処理を追加する
**※サーバ側もやらないとreCAPTCHAの意味がないです**

以下の情報を基にapiをたたきます。

```
URL:https://www.google.com/recaptcha/api.js?render=<サイトキー>
secret:シークレットキー
responce: Step1で取得できるtoken
```
apiのレスポンスとしては

```
success: true/false
challenge_ts: タイムスタンプ
hostname: ホスト名
score: 0~1 人間がやると0.9らしい。実際には0.90000000000000002が返ってきた
action: step1で選択したアクション
```

が返ってきます。
reCAPTCHAv3はこの帰ってきたscoreを基にどのような処理を行わせるかを自分で決めることができます。

例えばログイン画面にreCAPTCHAを導入した場合、スコアが低かったらエラーメッセージを表示してセッションを削除するとかロックするとか…
それぞれのサイトに合わせた動きをさせることができます。

#まとめ
・reCAPTCHAv3は非常に簡単に導入できる
・どういった判定基準なのかさっぱりわからないので心配
・管理画面でスコアやアクセス数、どのreCAPTCHAを通ったか(アクションの設定が必要)がわかりやすい

以上、ありがとうございました。
発表資料とスライドを見ながら思ういくつかのこと

# 思うことをつらつらと書きます
発表が多くなるシーズンを前に，ちょっと思うところがいろいろあったのでメモ書きしておきます．
なお，本記事はeeic （東京大学工学部電気電子・電子情報工学科）その2 Advent Calendar（リンクは[こちら](https://qiita.com/advent-calendar/2018/eeic2)）の記事として登録しました．
投稿時点では登録してなかったのですが，まだ空きがあるようだったので1枠もらいます．

# はじめに，一番大事なこと
私達は，なんで体裁にこだわるのか．
私の場合，**「見やすいスライド」「見やすい資料」**は発表内容をきちんと相手に伝えるのに絶対必要な要素だと思っているから，です．逆に，**「見にくいスライド」「見にくい資料」**は，内容がぜんぜん頭に入ってきません．
そういう人が自分以外にも存在するのを知っているから，体裁にこだわってしっかり作り込むようにしています．

相手に話を聞いてもらうときに礼儀を見せるのと同じです．
自分がこんなにしっかりしてるんだぞと見せるところから，コミュニケーションだと思っています．
あまり長く語りすぎないうちに，細かいポイントの列挙に入ります．

# スライドについて，いろいろ
偉大な先人のスライド論は[こちら](http://pst-ic.hatenadiary.jp/entry/2017/12/12/000038)．

## スライドサイズ
僕は**「スクリーン等に合わせるべき，わからないときは4:3」**派です．
スクリーンはフルに使っていくほうが有利ですから．
あと，まだまだ世の中4:3のスクリーンが多いと思います．

## フォントを統一しよう
スライドは原則としてゴシック系でいいんじゃないでしょうか．ヒラギノ角ゴばかり使っています．
英語ならHelveticaを主に使っています．
細い線は基本的に「見づらい」ですから，あまり明朝系は使われないと思います．
参考：[フォントの選び方（伝わるデザイン）](http://tsutawarudesign.com/yomiyasuku2.html)

### モリサワの無料UDフォント（2018年12月11日追記）
[MORISAWA BIZ+](https://www.morisawa.co.jp/products/fonts/bizplus/)の存在をイショティハドゥスくんに教えてもらいました．モリサワのユニバーサルデザイン日本語フォントです．無料で3種類使えます．
リンク先の一番下の方に「無償版」というリンクがあります．最新のWindowsには標準で入っているそうです．
**ティラノサウルスを走らせている暇があったらこのフォント使いましょう．**

## フォントサイズを考えよう
スクリーンのサイズにも依存するので，何pt，と提案する気はありませんが，あんまり小さい字でビッシリ書いてあっても読めません．

## 文字，多くない？（wow wow）
これは僕自身全然できていないのですが，スライドは「見せる」が基本です．
もちろん場合によります．ｱｶﾃﾞﾐｯｸな場所だと文章マシ（当社比）を求められることもあります．

## 階層構造を使おう
なんでもかんでも箇条書きにするのは良くないとされていますが，全部べた書きにされるよりマシです．
同列に配したい内容を同レベルのインデントで揃えて書くなどすると，わかりやすくなります．
「その文章，箇条書きにしたほうがわかりやすくない？」というケースも時々見かけます．
ついでながら，インデントの長さもガタガタだと「見にくい」ですね．

## 改行に注意
単語の途中で改行が入るのは単純に「見にくい」
うまいこと調整したほうがいいと思います．

## その装飾は必要ですか？
スライドのテンプレートとかを使って，上の方とか左の方とかが謎の緑のうねうねに支配されているスライド，それ本当に必要ですか？その部分も使ったほうが良くないですか？
尊敬する先輩曰く「余白は美しい」ですが，これは余白というか……．

## 発表中にページを戻ったら負け
質問されたり止められたりしたケースを除いて，ですが，これは，自分の説明に必要な要素をうまく配置できませんでした，ということになります．
スライドを前後する時間も無駄ですし，右往左往するのはあんまりかっこよくないです．

## 図表の解像度
**輪講で論文の図のスクショを貼っているそこのお前．**
解像度が低いと，軸の文字や細かい変化が読めません．読めない図はいらない図です．
論文誌によってはwebページで図を取得できる場合もあるし，ビューワーでPDFから図を引っこ抜くこともできます．なにか工夫しましょう．
あと，表ぐらい自分でつくろう．

## 図，貼っただけ問題
強調したい部分とか，矢印なり色なりつけたほうがいいです．
何を見たらいいかわからない場合もあります．

## パラパラ漫画のすゝめ
ページ送りを使って，進展する現象を説明するアニメーションもどきポンチ絵的なのを使うと，結構便利なこともあります．
僕はよくやります．

## 発表練習をしよう
しよう，というか，気持ちとしては「しなさーい！」です．
読めば読むほどなめらかに発表できます．
0回ではぶっちゃけ聞いててもなんだかよくわかりません．
ついでに，原稿的なものですが，僕は作ったほうがいいと思っています．
マジでスライドと聴衆だけ見て発表できるくらい練習をやりこんでいるのならいらないかもしれませんが．

# 資料について
自分でも模索しているところがありますが，いろいろ書いてみます．
偉大な先人の資料論は[こちら](https://qiita.com/suigin/items/10960e516f2d44f6b6de)．
尊敬する友人の資料論は[こちら](https://qiita.com/Ishotihadus/items/bbbb85f54e6a4e7aaac0)．

## フォント
こちらも変わらず，細い文字は基本的に見づらいです．

## 行間
ガバガバでも「見にくい」し，ギチギチでも「見にくい」ですね．

## インライン数式
特に分数を使う時．これいっつも悩むんですけど，僕は行内数式の分数は2段にせず，スラッシュ区切りで1段に書くようにしています．行間に干渉したくないので．

## 半角数字を使ったほうがいい
原則は「統一が取れていること」です．僕は昔は「1桁の数字は全角，複数桁の数字は半角」という流派でしたが，改宗しました．理系の文書はだいたい全部半角数字にしておけば間違いないです．
無秩序に異なる表記が混在しているのが一番「見にくい」です．

## 表のスクショを貼るな
表のスクショを貼るな．自分でつくろう．理由はスライドと同じ．

# おわりに
**Qiitaに書く内容じゃなかったかもな！**
なんかあれだったらどっかに移転させます．

急いで作ったので内容がガバですみません．
それでは良いアカデミックライフを．
＊C言語初心者＊#include<stdio.h>/main()ってなに？

#`#include <stdio.h>` ってなに？
プログラミングの授業で欠かせない`#include <stdio.h>`
何気なく最初に付けるものとしての認識しかないこの文はいったい何を表しているのか？
それでは早速。
>- includeの部分はインクルード部と言われるらしい。
>- Cは極めて小さな言語であり、**外部ライブラリ**を使わないと何もできない。
>- 関連するヘッダファイルをインクルードすることで、使用する外部コードをコンパイラに通知する。
>- 最もよく見かけるヘッダはstdio.h。
>- stdioライブラリには、ターミナルに対して読み書きするためのコードが含まれている。

外部ライブラリが何なのかよくわからないので調べてみる。

>ITの分野では、ある特定の機能を持ったコンピュータプログラムを他のプログラムから呼び出して利用できるように部品化し、そのようなプログラム部品を複数集めて一つのファイルに収納したものをライブラリという。

>一般的にライブラリにはオブジェクトコード(機械語などで記述されたプログラム)が格納されているが、それ単体で起動して実行することはできず、他の実行可能ファイルに連結されて利用される。ソースコードの集合をライブラリという場合もある。

>様々なプログラムが共通して利用する汎用性の高い機能などがライブラリとして開発・提供されることが多く、標準的なライブラリはOSやソフトウェア開発環境の一部として添付されることもある。特定のソフトウェアやハードウェアを利用したプログラムを開発するために必要な機能がライブラリの形でまとめられている場合もあり、当該システムの開発キットなどの一部として開発者に提供される。

引用先：[ライブラリとは](http://e-words.jp/w/%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA.html)

stdio.hを理解するためには更に分割コンパイルなどに踏み込む必要がある。
今の段階では、printfなどをするためのおまじない　という理解に過ぎない。

#int main()ってなに？

>- すべてのCコードは関数内で動作する。
>- Cプログラムで最も重要な関数はmain()関数である。
>- main()関数はプログラムの全コードの開始点になる。

つまり、main関数がないとC言語のプログラムは実行できない（？）
main()の前にあるintはいったいどういうことなのか…

>- コンピュータがプログラムを実行するときには、正常に動作したかどうかを判断する手段が必要である。
>- これをmain関数の戻り値を調べて判断する。

だからmain関数の最後には`return 0`を書くのか（？）（！）
何気なく書いてた文章の意味が分かって少しすっきりします。
よし！演習やってバイトに行こ！
Ubuntu 18.04 で Arduino IDE 1.8.8の文字化けを直す

#文字化けった
なぜかArduino IDEをレポジトリじゃなくて、tar落として最新版インストールしたら文字化けった。
解消法はここを参考にした。
http://powder4u.hatenablog.com/entry/2018/06/24/145120
Cicaを入れるのは面倒なので、デフォルトで入っているnotoを使った。つまり以下のようにpreference.txtに書く。
editor.font=noto,plain,12

2018/12/30追記：
OSがぶっ壊れたので再インストールしたら、この方法では治らず、完全豆腐状態であった。正直、日本語である必要がほぼないので、editor.languages.current=enとすることで英語化して使うことにした。
Scalaを使った通信型オセロゲームを作った話。

#はじめに
Scala独学で学んで1ヶ月くらい経ったので、実践ということで、ソケット通信を使ったオセロゲームを作って見ました。以下、学んだ点などつらつらまとめています。実装期間は、2週間程度です。(Scala単体の学習は除く)

<img width="1247" alt="スクリーンショット 2018-12-10 16.17.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/153882/15ccdbc9-5935-31e5-40fc-32384638ba9f.png">


[ソースコード]https://github.com/yuto226/Oselo

#What is Scala
Scalaは、Javaの親戚みたいなもんという認識です。
Scalaでできることは基本的にJavaでも出来ます。

Javaと最も違うと感じたところは、とにかくコード量が少ない、ガチガチのオブジェクト指向ではなく関数型のプログラミングも出来るというところでしょうか。

traitという機能が便利そうですが、今回キャパオーバーで使うに至れなかったので、今後改良したいと思います。

#環境
Mac OS X Sierra 10.12.6
InteliJ IDEA
Scala 2.12.7 
jdk-9

*環境構築的な話は省きます。

#何を作ったか
最近、技術怠けしていたのでとにかく手を動かすという意味を込めてゲームでも作ろうかなと思いオセロを作りました。ついでに、ネットワーク処理関係の復習も兼ねてソケット通信も実装しています。
Scala　を使ったのは、今後仕事でJavaを使う可能性が高かったので、何かないかと調べていたら近しいものがでてきたので、興味本位で手を出しました。
そんなモチベーションでやったのでScalaの良さ100%活かした実装までは至っていないかと思います。(とにかく動くことを目標にしてました)
ただ、Scala自体は結構使っていて書きやすく面白かったので、今後がっつり勉強していこうかと思います。

##簡単な設計(流れ)
ソケット通信ということで、クライアントサーバー形式です。
サーバー側がオセロの黒を担当し、クライアントが接続してきて白です。
ソケットを通して、どこに駒を置いたかの座標をメッセージでやりとりして、ゲームを進めていきます。
設計段階でGUI描画処理がきっと面倒なことになりそうだと思っていましたが、やはり後々面倒臭かったです(笑)

#実装
ソケット通信のプログラミング自体が久々だったので、ソケットをつないでメッセージのやりとりをするのが第一関門でした。さらに今回は、ゲームなのでGUIのための画面描画処理が入ります。スレッド一つでプログラムを走らせていると、どうしても限界がくるのでマルチスレッドを導入しました。サブのスレッドで、メッセージ受信を無限ループで待たせて、勝利判定や、画面描画は本スレッドでやらせる感じです。
こういういつ来るかわからないI/O処理を無限待ちさせるときは、マルチスレッド必須ですね。(初め、本スレッドで無限待ちさせていて当然ですが全く処理が進まなくなりました。。)

```scala
 override def run(): Unit ={
     createServer
     receiveMsg
   }
```

receiveMsg関数が無限待ち担当です。createServer関数は、初期設定でBufferedReaderなどを初期化しています。
JavaのThreadクラスを継承させて、本スレッドからstartメソッドで呼び出します。
基本的にこれをクライアントとサーバーで同じように待たせて、順番制御、勝利判定、メッセージ送信などを交互にやっていけばゲームとして成り立ちます。

画面描画自体は、scalafx(javafx)でやったのですが、scalafxはScene Builderというツールを使ってGUIでGUIの設計ができます。(X CodeでiPhoneアプリの画面作る時のような)

swingにはそういったものが無く、UIコードとデータ処理コードが入り混じった実装になってしまうそうなので、scalafx(javafx)の利点かなとは思います。

##ブロッキング・ノンブロッキング
最終的には、実装途中で、マルチスレッドにすれば、メッセージ受信やら画面描画は解決できる！と分かったのですが、調べて迷走している途中でブロッキング・ノンブロッキングという言葉も出てきて結構迷いました。（大学の講義で言葉を聞いた記憶はあった）

結論から言うと、ブロッキング・ノンブロッキングを考えるのは、サーバーに対してクライアントが複数アクセスする恐れがあるときは、ノンブロッキングを使った方が良い。とのことです。(違ったら教えてください・・)
コンピューターリソース的な観点から、複数来るクライアントに対して、いちいちスレッド・プロセスを割り当てていたら枯渇するのは目に見えているので、「監視」する処理を入れておいて、新規接続なら繋いで、メッセージが飛んできたら処理をして、といった風に実装するのが理想なようですね。ここら辺も落ち着いたらまた勉強しようかと思います。

#学びとまとめ
以下箇条書きでまとめます。
・無限待ちのI/O処理は、マルチスレッドを使う。
・マルチスレッドにおいて、画面描画処理をサブのスレッドで行う場合は、注意が必要。
・今回のように1対１の通信は、ブロッキング処理で大丈夫。複数クライアントが来るときは、ノンブロッキングで監視する処理を入れる。
・オセロの反転アルゴリズムめっちゃ大変。(ここのクラスのコード500行超えました。)
・Scala使い増えたらいいな。

マルチスレッドで画面描画を行う際のコードは、迷いそうなので残しておきます。
Platform#runLaterに対象関数を渡すことで解決しました。

```
Platform.runLater(() -> hogehoge())
```

今後、Scala勉強していきたいと思ったので、コード読んでくださった方は、ここはこうした方がいいよ！っていうのをコメントいただけると勉強の糧となります。宜しくお願いします。
GolangでAWSのコストを通知するツールを作った話

この記事は <a href="https://qiita.com/advent-calendar/2018/gamewith">GameWith Advent Calendar 2018</a> の10日目です

## 前段

所属会社のAdventCalendarなんて初めて書くのでどうしたものかなとひたすら悩んでいた @sys_cat です。
今日は弊社の中で地味に利用しているGolangにまつわるお話をしてみたいと思います。

既にいろんな方が書かれているように弊社ではPHPをメインの技術として利用しています。
その為Golangはどちらかというとサブ、ツール系の作成として使っています。

そんな私が作ったツールの中でも楽しかったものをご紹介してみようと思います。

## インフラコストの見える化

クラウドサービスを利用する会社の共通命題といいましょうか、インフラコストは頭痛のたねになりやすい問題です。
今までConsoleにログインしてから確認するものを定期的に周知出来るようにしてみようというところからスタートしてみました。

利用するパッケージはこんな感じ

```go
package costviewer

import (
	"fmt"
	"strconv"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/costexplorer"
)
```
※詳しいパッケージの解説は [この辺り](https://docs.aws.amazon.com/sdk-for-go/#lang/ja_jp) を読みながら進めることをおすすめします。

### 実装

基本的にはこのような実装になりました。

```go
func New() Client {
	cv := Client{Session: session.Must(session.NewSession())}
	cv.Cost = costexplorer.New(cv.Session, aws.NewConfig().WithRegion("us-east-2"))
	return cv
}

/* CostPerMonthly(month) : get cost explorer per monthly
* month int
 */
func (c *Client) CostPerMonthly(month int) error {
  var err error
	input := _buildParameters(_getMonthlyVariable(month))
	c.Monthly, err = c.Cost.GetCostAndUsage(input)
	if err != nil {
		return err
	}
	c.Month = fmt.Sprintf("%d", month)
	return nil
}

/* CostPerDaily(date) : get cost explorer per daily
* date time
*/
func (c *Client) CostPerDaily(date time.Time) error {
  var err error
	input := _buildParameters(_getDailyVariable(date))
	c.Daily, err = c.Cost.GetCostAndUsage(input)
	if err != nil {
		return err
	}
	c.Date = date.Format("2006-01-02")
	return nil
}
```

　`New()` を宣言してから　`CostPerMonthly()` ならびに `CostPerDaily()` を実行することになります。

```go
cost := costviewer.New()
now := time.Now()
month := int(now.Month())
if err := cost.CostPerMonthly(month); err != nil {
　　　　　panic(err)
}
if err := cost.CostPerDaily(now); err != nil {
　　　　　panic(err)
}
```

最近色々と言われがちなGolangですが個人的にはスッキリ書けるしエラーハンドリングも理解し始めるとすこぶる楽しめています。
内容としては `APIをリクエストして返すスクリプト`　ですが呼び出しがここまで簡単になるとは正直思っていなかったのでやはり使いやすいなぁという印象です。
MacBook + マルチディスプレイ(縦連結)環境で地味に響いたハック

この記事は [ACCESS Advent Calendar 2018](https://qiita.com/advent-calendar/2018/access)、10日目の記事です。

こんにちは！ @diescake です。

突然ですが、私は MacBook + 1〜2 つのサブディスプレイを利用して開発することが多いです。

各々皆様こだわりあるかと思いますが、私の場合は手元の MacBook にはエディタ(VSCode)を `Zen Mode`(フルスクリーン)で表示して、
その他ディスプレイに、ブラウザ、ドキュメント(Preview)、Slack、などなど、開発に必要なツールを表示しています。

そんな環境で、ちょっとストレスに感じていたことがありました。

# TL;DR

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">凄い地味な hack だけど、MacBook とモニタを上下配置で利用している場合、境界を微妙にズラしておくことで、<br>フルスクリーンでコードを書いているときに、右上をタスクバーを表示するためのホットコーナーとして扱えるので割と便利である。 <a href="https://t.co/MS1ldbqMjT">pic.twitter.com/MS1ldbqMjT</a></p>&mdash; diescake (@phocaenidae) <a href="https://twitter.com/phocaenidae/status/1067649766887063552?ref_src=twsrc%5Etfw">2018年11月28日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


# 私の現場

さて…、TL;DR で既に完結してしまっているのですが、
これでは寂しいので水増ししていきますね。（╹◡╹）

<img src="https://qiita-image-store.s3.amazonaws.com/0/38837/d6b8c42e-c99f-cd1f-140d-36dbfc73e782.jpeg" />

実際に、会社ではこんな感じでディスプレイを配置しています。
(自宅の場合は、3枚ありますが位置関係は大体同じです)

MacBook をサブディスプレイと組み合わせて利用している人は、
物理的な制約上、これに近い前後型の配置を取る人は多いのではないでしょうか？

ともすると、直感的には下記のように MacBook のディスプレイとサブディスプレイを上下(vertical)に連結している人も多いものと推測します。
<img width="780" alt="スクリーンショット 2018-12-10 15.05.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/38837/bdcf29ef-b782-997f-5642-cc946186c6ab.png">

# 何が不便なのか？

コーディングをしているときに、
稀によくメニューバーや、システムトレイにアクセスしたくなると思います。

`Zen Mode` の状態ではメニューバーは通常隠れている状態となりますが、
確認するだけ(例えば時間やネットワークとか)であれば、マルチディスプレイのメニューバーに視線をやれば十分です。

しかし、操作が必要な場合は、アナログにポインティングする必要があり、[^1]
ディスプレイを上下で連結している場合は、ポインタが境界を通り過ぎてしまうため、
境界ギリギリの狭い領域をポインティングしないと、メニューバーがオープンになってくれないのです。

コードに集中している際に、突然繊細なアナログな操作を求められるというのは割と大きなストレスでした。

# どう解決したか？

<img width="736" alt="スクリーンショット 2018-12-10 15.05.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/38837/2f5e32c2-7a32-f31c-a89c-ab6fe2029c75.png">

__ディスプレイ境界をほんの少しずらして設定します。__
わかりづらいと思いますが、右側の境界がほんの少しずれています。

こうすることで、 __MacBook 側ディスプレイの右上隅をメニューバーを表示するためのホットコーナー__ のように扱えるようになります。
SS の通りほんの数px だけで十分なので、元々端を揃えている人にとっては、ほぼデメリットなく設定できると思われます。

また、左側をずらしても構いませんが、
メニューバーが表示された状態を維持しながらポインタを反対側へ移動するには、
決死の鉄骨渡りを成し遂げる必要がありますので、メニューの各種アイテム(左上)と、システムトレイ(右上)の利用頻度を考慮して決めると良いかもしれません。

# 終わりに

というわけで、ハックと呼ぶのもおこがましいくらいの 1 tip ですが、
身の回りで評判が良かった(気がする)ので紹介してみました。

追加インストールするツールや複雑な設定は一切ありませんので、
私と同様にちょっと煩わしく思った経験があれば、ぜひ試してみてください！

それでは、明日は @sylph01 さんです。お楽しみに！

# 参考文献

* [wikipedia - 賭博黙示録カイジ(鉄骨渡り)](https://ja.wikipedia.org/wiki/%E8%B3%AD%E5%8D%9A%E9%BB%99%E7%A4%BA%E9%8C%B2%E3%82%AB%E3%82%A4%E3%82%B8#%E9%89%84%E9%AA%A8%E6%B8%A1%E3%82%8A)

# 動作検証環境

* MacBook Pro (15-inch, 2016)
  * macOS Mojave 10.14
  * Visual Studio Code 1.29.1
* VX3276-2K-MHD-7 (31.5 inch)

[^1]: キー操作だとメニューバーは操作しづらい(要出典)ので、ポインタでの操作が快適になれば嬉しいな…、と。