OmniAICreator/Qiita-1.07M huggingface dataset:
ROM（Ruby Object Mapper）4.0でcross-database associationを設定する

# 概要
[ROM（Ruby Object Mapper）](http://rom-rb.org/)というORM（Object Relational Mapper）があります。
Railsだとデフォルトで `ActiveRecord` が組み込まれているので基本的に使うことはないと思いますが、HanamiではROMをラップした `Hanami::Model` がデフォルトのORMになっています。
ROM自体はデータソースがRDB以外でも使うことのできる汎用的なORMで、単なるHashやArrayでも扱うことができます。

今回はROM 4.0のassociationでcross-database associationを設定する書き方をメモっておきます。

# 想定用途
- 複数のデータベースを運用しており、データベース間でassociationを設定したいとき
    - アカウント情報を保存するDBと、個別のデータを保存するDBが別々の場合等

例えば以下のスキーマを定義して `users` テーブルと `posts` テーブルを別々のDBで管理していた場合、SQLでJOINすることができません。

```schema.sql
CREATE DATABASE `db1`;
USE `db1`;
CREATE TABLE `users`(
  `id` INTEGER UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  `uuid` VARCHAR(36) NOT NULL,
  `name` VARCHAR(20) NOT NULL
);

CREATE DATABASE `db2`;
USE `db2`;
CREATE TABLE `posts`(
  `id` INTEGER UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  `user_uuid` VARCHAR(36) UNSIGNED NOT NULL,
  `title` VARCHAR(20) NOT NULL
);
```

この場合ActiveRecordではassociationを設定できず、 `User` と `Post` のインスタンスを別々に作成するしかありません。
一方ROMのassociationでは、別々のDBからのデータを内部で結合することができ、JOINした場合と同じ結果を得ることができます。

```rb
# ActiveRecordでの例
# SwitchPoint等のgemを使って複数DBへの接続を管理している前提です
user = User.find_by(id: 1) #=> #<User id=1 uuid="uuid" name="name">
post = Post.find_by(user_uuid: user.uuid) #=> #<Post id=1 user_uuid="uuid" title="title">
```

# ROMで書く
## データベース接続の設定
初期設定としてデータベースの接続先を指定します。
ROMでは接続情報を内包した `Container` を作成し、これを `Repository` のコンストラクタに渡すことでRepositoryに接続先を教えます。

`ROM::Configuration` のコンストラクタには、接続先が一つの場合はそのURLを、複数の場合は `{ db_alias: 'db_url' }` の形式のHashを渡します。

```container.rb
container = ROM.container(
  ROM::Configuration.new(
    default: 'mysql2://root@localhost/db1',
    db2: 'mysql2://root@localhost/db2'
  )
)
```

## Relation, Repositoryの定義
ROMを使うにあたって、Relation（RDBでいうテーブル定義）とRepository（データソースとやり取りするためのロジックをまとめた層）を定義する必要があります。

```relations.rb
class Users < ROM::Relation[:sql]
  schema(infer: true) do
    # :view, :override, :combine_keys を指定するのがポイントです
    has_many :posts, foreign_key: :uuid, view: :for_user, override: true, combine_keys: { uuid: :user_uuid }
  end
end

class Posts < ROM::Relation[:sql]
  gateway :db2 # gateway :alias の書式でどの接続先を使うか指定します。省略すると :default につながります
  
  schema(infer: true)

  def for_user(_assoc, user) # データを結合するときの条件をviewとして指定します
    where(user_uuid: user.pluck(:uuid))
  end
end
```

```user_repo.rb
class UserRepo < ROM::Repository[:users]
  def find_with_posts_by(uuid:)
    users.combine(:posts).where(uuid: uuid).one # usersメソッドで Relation のインスタンスが取れます
  end
end
```

## 使う
定義は済んでいるので、あとは使うだけです

```rb
user_repo = UserRepo.new(container)
user = user_repo.find_with_posts_by(uuid: 'uuid')
#=> #<ROM::Struct::User id=1 uuid="uuid" name="name" posts=[#<ROM::Struct::Post id=1 user_uuid="uuid" title="title">]>
```

という感じで、複数DBにまたがるテーブル間でもちゃんとassociationを定義した状態でレコードを取得することができました。
railsのユーザー管理を劇的に便利に！FBログインで入手した情報+αを入力させてformrunで管理

#やりたいこと
[以前こちらの記事](https://qiita.com/RYOSUKE310/items/2f9ec73aaecd4d80f997)でrailsでのFBログインの実装方法を紹介しました。

今回はFBログインで入手したユーザー情報を劇的に便利にする方法の一つとしてformrunを使った方法を紹介します。

#formrunとは
[formrun](https://form.run/ja)とはフォーム作成とその管理を簡単にするサービスで特にチームで管理する際には絶大な威力だと思います。

こんな感じ。

![スクリーンショット 2018-03-01 17.53.58.png](https://qiita-image-store.s3.amazonaws.com/0/240838/7ebbaf5f-99dd-6045-713f-d10a0400000b.png)

ステータスや担当者等を決めて全員で管理できる上にフォームから取得した情報も大変見やすいです。

#実装方法

とても簡単です。フォーム作成後HTMLタグを入手できるところがあります。それをフォームを作りたいページにコピペ。FBログインで取得できる項目、例えばemailなどだったら、

```ruby
<% current_user.email %>
```

と値を入れてあげればformrunに飛ばすことができます。表示させる必要がないときは

```html
<input type="hidden"></input>
```
で隠しておきましょう。

#感想

めちゃくちゃ便利です。
au世界サービスがつながらなくてやったこと

Qiitaに書くようなことじゃないんだろうけど、割と困ったので情報共有。

# ベトナム ホーチミンでau世界サービスが使えない

何度かホーチミンが来てるんだけど、今回初めてiphoneの「au世界サービス」でのデータ通信ができなくなった。
正確にいうと1分くらいだけしかつながらなくなった。
通話は問題なし。

過去に、知人も同じくなぜかau世界サービスにつながらない状態になっていたので（KDDIに問い合わせて色々やったが結局解決できず）、こっちにもその順番が回ってきたかと思った。

# つないだ直後だけ1分くらいだけ使える

再起動、もしくは機内モードからの復帰で、回線につながった直後1分間だけは使える。画面上部のアンテナは3本経っているし、回線業者には「VinaPhone」の表示、そしてその横に「**3G**」の文字。

そして1分経つと「**3G**」の文字が消え、つながらなくなる。その後どれだけ待ってもどこに行ってもつながらない。

youtubeなどの動画を見てて通信がずっと発生しているような場合は、4分くらい持った。

なので、しばしの間、通信が発生するタイミングで機内モードON→OFFをやる、という運用対処しててすごい面倒だった。

# KDDIに問い合わせ

初めて電話で「+」を入力して、国際電話でKDDIに問い合わせ（もちろん通話料無料）。
言われた対処方法は、以下の3つ。

1. Safariとかの履歴を消す
2. 端末リセット
3. SIM抜き差し

1は、関係なさそうだから無視。
2は、流石にKDDIの人も「最終手段でデータをすべて消してでも試してみたいなら」、と言っていた。

ということで**3. SIM抜き差し**をやってみたところ・・・

つながりました！

回線業者が「Viettel 4G」に変わり、ずっとつながるようになりました。
「VinaPhone」の問題だったのだろうか・・・。

# 結論

au世界サービスがつながらなくなったら、一回SIM抜き差ししてみて。
gitbookでドキュメントを書く

#0. gitbookのインストール

```sh
$ npm install -g gitbook-cli
```

#1. gitbookプロジェクトの作成

```sh
$ gitbook init
warn: no summary file in this book
info: create README.md
info: create SUMMARY.md
info: initialization is finished
```

README.md (required: Preface/Introduction for this book)
必須：ルートのドキュメント

SUMMARY.md (optional: Table of Contents)
オプション：目次

#2. 日本語化設定をする

book.jsonを作成

```sh
$ touch book.json
```

内容を下記に変更

```md
{
    "language": "ja"
}
```

#3. ビルトインサーバー

```sh
$ gitbook serve
Live reload server started on port: 35729
Press CTRL+C to quit ...

info: 7 plugins are installed
info: loading plugin "livereload"... OK
info: loading plugin "highlight"... OK
info: loading plugin "search"... OK
info: loading plugin "lunr"... OK
info: loading plugin "sharing"... OK
info: loading plugin "fontsettings"... OK
info: loading plugin "theme-default"... OK
info: found 1 pages
info: found 0 asset files
info: >> generation finished with success in 0.4s !

Starting server ...
Serving book on http://localhost:4000
```

#4. HTML出力

```sh
$ gitbook build
info: 7 plugins are installed
info: 6 explicitly listed
info: loading plugin "highlight"... OK
info: loading plugin "search"... OK
info: loading plugin "lunr"... OK
info: loading plugin "sharing"... OK
info: loading plugin "fontsettings"... OK
info: loading plugin "theme-default"... OK
info: found 1 pages
info: found 0 asset files
info: >> generation finished with success in 0.4s !
```

#5. 書き方

ドキュメントを入れるディレクトリを作成

```sh
$ mkdir docs
```

##5.1 ページを作成

```sh
$ touch docs/first.md
```
あとはMarkdownで編集して、README.mdやSUMMARY.mdからリンクを貼る

```md
# Summary

* [Introduction](README.md)
* [最初のドキュメント](docs/first.md)
    * [最初の子ドキュメント](docs/child.md)
```

##5.2 画像を添付
画像を入れるディレクトリを作成

```sh
$ mkdir images
$ open images
```

あとはMarkdownで編集して、README.mdやSUMMARY.mdからリンクを貼る

```md
![サンプルイメージ](./images/sample.png)
```

## 5.3 先にsummaryを作成する場合

先にSUMMARY.mdを修正

```md
# Summary

* [README](README.md)

## 環境構築

* [バックエンド](docs/env-backend.md)
* [フロントエンド](docs/env-frontend.md)

```

ファイルができる

```sh
$ gitbook init
info: create docs/env-backend.md
info: create docs/env-frontend.md
info: create SUMMARY.md
info: initialization is finished
```

#6. gitignore
```
# Logs
logs
*.log

# Runtime data
pids
*.pid
*.seed

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directory
# Deployed apps should consider commenting this line out:
# see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git
node_modules

_book/
book.pdf
book.epub
book.mobi
```
キーの押下判定

いつも使っている任意のキーを押した瞬間を判定するコードを備忘録として書いておきます。

```cpp:pushkey.cpp
BOOL keyflg;

if(GetAsyncKeyState(`判定したいキー`) & 0x8000){
  if(!keyflg){
    //キーを押した瞬間の処理
    keyflg=true;
  }
  //キーを押している間の処理
}
else{
  //キーを離している間の処理
  keyflg=false;
}
```
JavaScriptで、ある要素をクリップボードにコピーする

私は、今までjavascriptに関してはノータッチでした。
しかし、急にインターン先でjavascriptの仕事がきてやらざるを得なくなりました(笑)
javascriptの何もかもが初めてでとても戸惑いましたが、周囲の方々の協力もあってそのお仕事は解決できました…。
せっかくなので学んだことを備忘録としてここに書いておきたいと思います。

## 課題
やったこと、それは、
『ボタンをクリックしたときに、ある要素がクリップボードにコピーされるようにする』
ことでした。

jQueryではなく純javascriptで、という注文つきです。


これを実装するためには、いくつかの段階を踏まなくてはなりません。
1. ボタンがクリックされたことを検知する
2. ある要素を取得する
3. 取得したものをクリップボードに入れる
4. 出力されるようにする

順々に整理していきます。

## 対応
### ボタンがクリックされたことを検知する

ここでは、次の関数を使います。

```javascript
document.getElementById("<id要素>").onclick = function() {
  // ここに#buttonをクリックしたら発生させる処理を記述する
};
```
document.getElementById()で文書内のid要素を指定して、その要素をクリックした時の処理をfunction( ){ }内に記述します。


### ある要素を取得する

ここでは、次の関数を使います。

```javascript
var <変数> = document.getElementById("<id要素>");
```
先ほどと同様、id要素を取得したら、それをある変数に代入します。

### 新しい要素の取得

```javascript

var element = document.createElement("textarea")
```
これは新しく要素を作成する関数です。
作成したい要素のタグ名を引数に指定してください。
ここではtextareaとしています。

### 取得したものをクリップボードに入れる

```javascript

element.value = <id要素>.dataset.copy_clipboard;
```
セットされたelementに対して、読み取り専用のプロパティを提供します。

### 出力する

```javascript
document.body.appendChild(element)  #要素に値を追加
element.select();  #値を選択する
document.execCommand("copy");  #選択範囲をクリップボードにコピー
document.body.removeChild(element)  #要素から値を削除
```
初心者なので少し曖昧ですが、これはDOM(Document Object Model)操作というもので、HTML文書をアプリケーションから利用するためのAPIらしいです。




### おまけ：ポップアップメッセージ

```javascript

alert('クリップボードにコピーしました。')
```
このように書いておくと、これまで述べてきたfunction{}の操作がが実行されたときに、「クリップボードにコピーしました」とポップアップメッセージを表示することができます。

### まとめると...

id要素：user_email として、

```javascript

javascript:
  document.getElementById("user_email").onclick = function(){
    var email = document.getElementById("user_email");
    var text = document.createElement("textarea");
    text.value = email.dataset.copy_clipboard;
    document.body.appendChild(text);
    text.select();
    document.execCommand("copy");
    alert('クリップボードにコピーしました。');
  }
```
となりました！
PatchとPutの違いについて

今までなんとなく使っていて、ちゃんと調べていなかったpatchメソッドとputメソッドの違いについて調べてみた。

調べる前はどっちもリソースを更新する時に使うものだよね？程度の認識。

>
Abstract
>
   Several applications extending the Hypertext Transfer Protocol (HTTP)
   require a feature to do partial resource modification.  The existing
   HTTP PUT method only allows a complete replacement of a document.
   This proposal adds a new HTTP method, PATCH, to modify an existing
   HTTP resource.

[PATCH Method for HTTP](http://www.rfc-editor.org/rfc/rfc5789.txt)

- Putメソッドは更新というよりは置換
- Patchメソッドは既存のリソースを更新・変更・修正


>
The HTTP method PUT means resource creation or replacement at some given URL.
>
Think files, for example. If you upload a file to S3 at some URL, you want either to create the file at that URL or replace an existing file if there’s one. That is PUT.

[Edge Rails: PATCH is the new primary HTTP method for updates](http://weblog.rubyonrails.org/2012/2/26/edge-rails-patch-is-the-new-primary-http-method-for-updates/)

PutはS3のあるURLにファイルをアップロードするイメージ。そのURLにファイルが無ければ新規でアップされるし、あれば置き換える。よく冪等というキーワードが出てくるが、何度やってもそのURLにはそのファイルがアップされている状態になる。こういう処理にPutを利用する。

>
Now let’s think about ordinary edit forms in typical Ruby on Rails applications. How many times are we sending a complete representation for replacement? Not always, perhaps we could say that it is even rare in practice that you do so. For example, the conventional created_at and updated_at timestamps normally can’t be set by end-users, though they are often considered to belong to the representation of resources that map to records.

>
中略

>
Because of that, the PATCH method was defined in 1995 and standarized later. PATCH is a method that is not safe, nor idempotent, and allows full and partial updates and side-effects on other resources.

[Edge Rails: PATCH is the new primary HTTP method for updates](http://weblog.rubyonrails.org/2012/2/26/edge-rails-patch-is-the-new-primary-http-method-for-updates/)


Railsでは、ユーザーが情報をまるごと置換えたと思っても`created_at`と`updated_at`があるし、Putのような処理になることは少ないから、"PATCH is the new primary HTTP method for updates"にしたよとのこと。


まとめ

- Railsで開発している時に"更新"でイメージするような、リソースの一部を更新する処理はPatch
- ファイルアップロードのような、指定したURLにあるリソースをまるごと置換えるような処理はPut
pythonでiGraphを使用すると日本語が表示されない問題を解決する[Mac]

なぜiGraphを使用したかというと読んでいた参考書で使っていたから。

iGraphをpythonで使うにするのがそもそもやや煩雑だった。

- iGraphは内部でcario使っているからcarioインストールする必要ある
- iGraphをpythonから使うためのインターフェイスであるpython-igraphも必要
- pythonでcario使うにはpycairo（anacondaはcondaコマンドで楽できる）、cairocffiあたりも必要

以下コマンドを叩けば環境は用意できるはず。

```
brew install igraph
brew install cairo --use-clang
pip install python-igraph
conda install -c conda-forge pycairo
pip install cairocffi
```

で、試しにグラフ描画する。

```
from igraph import *
vertices = ["山田", "Tanaka", "Suzuki", "Sato", "Ito", "Obokata"]
edges = [(0,1),(1,3),(1,4),(1,5),(2,5),(3,5),(4,3),(0,5)]
g = Graph(vertex_attrs={"label": vertices}, edges=edges, directed=True)
plot(g, vertex_size=30, bbox=(800, 800),vertex_color='white')
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/41759/78b93983-6674-44ff-51d5-5efebbcf1485.png)

しかし、日本語が表示されない。↑のケースだと山田が存在しない。

原因はライブラリである`igraph/drawing/graph.py`の`DefaultGraphDrawer`クラスに以下のようにフォントがハードコードされているためだった。

```
        context.select_font_face("sans-serif", cairo.FONT_SLANT_NORMAL, \
            cairo.FONT_WEIGHT_NORMAL)
```

これを以下のように修正した。

```
        context.select_font_face("Hiragino Sans", cairo.FONT_SLANT_NORMAL, \
            cairo.FONT_WEIGHT_NORMAL)
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/41759/dc4fe173-5897-ca8a-fde1-d80d5a1e8188.png)


これで日本語（山田）が表示されるようになった。
ubuntuにre:dashを構築する手順

# はじめに

dockerを利用しますのでまずはDockerを利用できるようにします。
[UbuntuにDockerとdocker-composeを動かすための手順](https://qiita.com/sea_ship/items/e71638458ef5f88e4a9c)

# re:dashインストール手順

[公式:Setting up a Redash instance
](https://redash.io/help-onpremise/setup/setting-up-redash-instance.html)のDocker Composeも参考にしてください。

## redash on docker

```shell:docker-compose実行手順
$ git clone https://github.com/getredash/redash.git
$ cd redash

# docker-compose.ymlを編集しておきます。詳細は下に記載しています。

# Dockerコンテナーイメージ作成
$ docker-compose build
# re:dash setup database
$ docker-compose run --rm server create_db
# re:dash起動
$ docker-compose up -d
```

docker-compose.production.ymlをベースに作業を進めますが、そのままだと毎回`docker-compose -f docker-compose.production.yml`を打たないと行けないのでdocker-compose.ymlにファイル名を変更しましょう。

#### docker-compose.yml作成
```
$ cp docker-compose.production.yml docker-compose.yml
```

#### docker-compose.ymlの編集
```diff:docker-compose.yml
# volumeのコメントをはずす。
postgres:
 image: postgres:9.5.6-alpine
-   # volumes:
-   #  - /opt/postgres-data:/var/lib/postgresql/data
+   volumes:
+     - /opt/postgres-data:/var/lib/postgresql/data
```

redashの画面が表示されればOKですね。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/30329/5398f7d2-6aad-3994-ad79-d875340246f1.png)
[Linux] ブロックデバイスのモデル名を表示する

# はじめに
ハードディスクや光学ディスクなどのブロックデバイスの一覧を表示するには**lsblk(list block devices)**コマンドを利用します。`lsblk`コマンドは**util-linuxパッケージ**に含まれています。
&nbsp;
`lsblk`コマンドのオプションを利用することで、デバイスのモデル名などを表示することができます。表示項目を追加するには、<strong>-o</strong>オプションを利用します。
オプションに<strong>＋</strong>を付けて表示項目を指定することとで、デフォルトの表示項目に追加して表示することができます。<strong>+</strong>を付けない場合、追加項目のみ表示されます。
モデル名の場合、'MODEL'を追加します。

```shell:
lsblk -o +MODEL
```

他に表示できる項目は<strong>-h</strong>オプションで調べることができます。バージョンによって利用できる表示項目が異なるので、事前に<strong>-h</strong>オプションで確認しておくことを勧めます。
# 実行例
それでは、実際に<strong>lsblk</strong>コマンドの表示項目を増やして表示してみます。
※以降の例では、文字化けを防ぐために出力をASCII文字に限定する<strong>-i</strong>オプションも指定しています。
## デフォルトの表示
```shell-session
$ lsblk -i
NAME                  MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda                     8:0    0   16G  0 disk
|-sda1                  8:1    0  487M  0 part /boot
|-sda2                  8:2    0    1K  0 part
`-sda5                  8:5    0 15.5G  0 part
  |-ubuntu--vg-root   253:0    0 13.5G  0 lvm  /
  `-ubuntu--vg-swap_1 253:1    0    2G  0 lvm  [SWAP]
sr0                    11:0    1 1024M  0 rom
```
## モデルを追加で表示
```shell-session
$ lsblk -io +MODEL
NAME                  MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT MODEL
sda                     8:0    0   16G  0 disk            VBOX HARDDISK
|-sda1                  8:1    0  487M  0 part /boot
|-sda2                  8:2    0    1K  0 part
`-sda5                  8:5    0 15.5G  0 part
  |-ubuntu--vg-root   253:0    0 13.5G  0 lvm  /
  `-ubuntu--vg-swap_1 253:1    0    2G  0 lvm  [SWAP]
sr0                    11:0    1 1024M  0 rom             CD-ROM                    11:0    1 1024M  0 rom             VBOX
```
sdaのモデル名はVBOX HARDDISK(VirtualBoxの仮想ハードディスク)と表示されました。
## モデルとシリアル番号を追加で表示
カンマ区切りで複数の項目を追加することができます。

```shell-session
$ lsblk -io +MODEL,SERIAL
NAME    MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT MODEL            SERIAL
sda       8:0    0   16G  0 disk            VBOX HARDDISK    VBxxxxxxxx-xxxxxxxx
|-sda1    8:1    0  487M  0 part /boot
|-sda2    8:2    0    1K  0 part
`-sda5    8:5    0 15.5G  0 part
  |-ubuntu--vg-root
  |     253:0    0 13.5G  0 lvm  /
  `-ubuntu--vg-swap_1
        253:1    0    2G  0 lvm  [SWAP]
sr0      11:0    1 1024M  0 rom             CD-ROM           VB2-xxxxxxxx
```
## Google Compute Engine (GCE)での実行例
```shell-session
$ lsblk -io +VENDOR,MODEL
NAME   MAJ:MIN RM SIZE RO TYPE MOUNTPOINT VENDOR   MODEL
sda      8:0    0  20G  0 disk            Google   PersistentDisk
`-sda1   8:1    0  20G  0 part /
```
GCEのブロックストレージのモデル名はPersistentDiskと表示されました。

以上、ブロックデバイスのモデル名を表示する方法の紹介でした。
TomcatのManager画面にログインできない

## tomcat-users.xml の設定

```tomcat-users.xml
<tomcat-users>
  <role rolename="manager-gui"/>
  <role rolename="admin-gui"/>
  <user username="tomcat" password="p@ssw0rd" roles="manager-gui,admin-gui"/>
</tomcat-users>
```

## 401 Unauthorized　となってしまう！
tomcat-users.xml に role, user 記載したのにログインできない！!

![無題.jpg](https://qiita-image-store.s3.amazonaws.com/0/241360/7615bf7a-48d0-b896-0f91-dd9635092a0d.jpeg)

## server.xml も設定が必要！

server.xmlの、GlobalNamingResources で tomcat-users.xmlファイル を参照する設定も必要！

```server.xml
...
  <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />           
  </GlobalNamingResources>
...
```
- デフォルトでコメントアウトされているので、コメントアウトを外しましょう
- Tomcatの再起動も忘れずに...

無事ログインできました。
![OK.jpg](https://qiita-image-store.s3.amazonaws.com/0/241360/c98134df-e6de-8cbf-0d12-7c2b42165bf7.jpeg)


## 参考
[Tomcatの管理者権限アカウント設定の方法](http://takigawa401.hatenablog.com/entry/20101119/1290092862)
[TOMCATで設定するBASIC認証の失敗する原因](https://qa.atmarkit.co.jp/q/3425)
dyld: Library not loaded: /usr/local/opt/icu4c/lib/libicui18n.60.dylib

```
 > node                                                                 16:22:41
dyld: Library not loaded: /usr/local/opt/icu4c/lib/libicui18n.60.dylib
  Referenced from: /usr/local/bin/node
  Reason: image not found
fish: 'node' terminated by signal SIGABRT (Abort)
```
これの解決法。

```
brew uninstall --ignore-dependencies node icu4c
brew install node
```
Laravelでオブザーバを試す

Laravelのモデルでライフサイクル（新規作成した際や削除した際）に、合わせて処理を行うことができます。

`$dispatchesEvents`にイベントを登録する方法もありますが、今回は`Observer`を利用してみます。

Laravel:v5.6.5

## 試してみる

### オブザーバの用意

Groupモデルに対応するオブザーバを用意する。

```php:app/Observers/GroupObserver.php
<?php

namespace App\Observers;

use App\Group;

class GroupObserver
{
    public function saved(Group $group)
    {
        \Log::debug("Hoge");
    }
}
```

### オブザーバの登録

`Group::observe`に`GroupObserver`を登録します。

```php:app/Providers/AppServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

use App\Group;
use App\Observers\GroupObserver;
    
class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        Group::observe(GroupObserver::class);
    }
}
```

### 実行

`$ php artisan tinker`

```console
>>> $group = factory(App\Group::class)->make()
=> App\Group {...}
>>> $group->save();
=> true
```

※ `factory`使ってますが、用意してない方は、`new App\Group()`でよいと思います。

```text:storage/logs/laravel.log
[2018-03-01 10:16:22] local.DEBUG: Hoge
```

## オブザーバの順序

ついでに実行順序も気になったので確認してみます。

```php:app/Observers/GroupObserver.php
<?php

namespace App\Observers;

use App\Group;

class GroupObserver
{
    public function creating(Group $group)
    {
        \Log::debug("GroupObserver: creating");
    }

    public function created(Group $group)
    {
        \Log::debug("GroupObserver: created");
    }

    public function saving(Group $group)                                                                                                  
    {
        \Log::debug("GroupObserver: saving");
    }

    public function saved(Group $group)
    {
        \Log::debug("GroupObserver: saved");
    }
}
```

```php:app/Group.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Group extends Model
{
    public function save(array $options = [])
    {
        \Log::debug("Group: before save");
        $saved = parent::save($options);
        \Log::debug("Group: after save");                                                                                                
        return $saved;
    }
}
```

先ほどと同じ様に`tinker`で実行

```text:storage/logs/laravel.log
[2018-03-01 16:57:28] local.DEBUG: Group: before save  
[2018-03-01 16:57:28] local.DEBUG: GroupObserver: saving  
[2018-03-01 16:57:28] local.DEBUG: GroupObserver: creating  
[2018-03-01 16:57:28] local.DEBUG: GroupObserver: created  
[2018-03-01 16:57:28] local.DEBUG: GroupObserver: saved  
[2018-03-01 16:57:28] local.DEBUG: Group: after save
```

ふむ、わからん。
`creating`と`created`の間で実際の`save`が行われてそうな気がしますね。
TeamCity上でrbenvでrubyバージョンを変えられない問題

# 症状
- rbenvで使いたいrubyバージョンを入れたけど、なぜかTeamCity上ではそのバージョンに切り替えられない。
- `rbenv versions` を見ると、なぜか `system` しか表示されない。

# 調査

`rbenv --debug version` の結果を比較してみる：

作業用のbash session：

```
+ [rbenv:23] enable -f /usr/local/Cellar/rbenv/1.1.1/libexec/rbenv-realpath.dylib realpath
+ [rbenv:53] '[' -z '' ']'
+ [rbenv:54] RBENV_ROOT=/Users/*****/.rbenv
...
```

TeamCity：

```
[15:38:16][Step 2/3] + rbenv --debug versions
[15:38:16][Step 2/3] + [rbenv:23] enable -f /usr/local/Cellar/rbenv/1.1.1/libexec/rbenv-realpath.dylib realpath
[15:38:16][Step 2/3] + [rbenv:53] '[' -z /usr/local/Cellar/rbenv/1.1.1 ']'
[15:38:16][Step 2/3] + [rbenv:56] RBENV_ROOT=/usr/local/Cellar/rbenv/1.1.1
...
```

`$RBENV_ROOT` がなぜか違う。どうやら、TeamCityでは `$HOME/.rbenv` を認識していないようなので、TeamCityのスクリプトで下記を追加：

```bash
export RBENV=/Users/*****/.rbenv
```

これにより解決。
Cognos レポートでドリルスルーのボタンを簡単に実装する

#概要
最近プチネタばっかりですいません。

こんな感じに、別のレポートに遷移するボタンを置いて欲しいといわれた時の簡単な実装方法です。
![007.JPG](https://qiita-image-store.s3.amazonaws.com/0/147246/1999d7ec-32aa-5f1a-11a3-5d3c217bd7d9.jpeg)

#実装
ボタンと言われると、「プロンプト・ボタン」が使えるかと思いますが、以下のようにプロパティを見ても「ドリルスルー」がありません。
![001.JPG](https://qiita-image-store.s3.amazonaws.com/0/147246/7d427cd8-7ff8-4b9c-cbba-dca53ecf6c2b.jpeg)

「テキスト・アイテム」であれば、「ドリルスルー」の定義は可能です。
でも、テキスト・アイテムではボタンっぽく無いですね。
![002.JPG](https://qiita-image-store.s3.amazonaws.com/0/147246/a90c6c3d-f5ee-276d-3567-b09dd0d7dafc.jpeg)

そんな時は「テキスト・アイテム」のプロパティから「クラス」を選び。
![003.JPG](https://qiita-image-store.s3.amazonaws.com/0/147246/9774d901-aa22-4c8a-8904-9a43352e0e9f.jpeg)

「ボタン」を選択したクラスに入れてしまいます。
![004.JPG](https://qiita-image-store.s3.amazonaws.com/0/147246/d91ebe8f-553e-9509-2f37-a110ce7e84dc.jpeg)

この状態でもドリルスルー定義は可能なので設定します。
![005.JPG](https://qiita-image-store.s3.amazonaws.com/0/147246/3b25412d-70d4-be8f-fd96-2847c9d0111e.jpeg)

枠線とか背景色とか、色々と整えます。
![006.JPG](https://qiita-image-store.s3.amazonaws.com/0/147246/ecbaacdb-acb4-0594-9ad7-6aa17289cde5.jpeg)

これでOK。クリックするとドリルスルー遷移します。
![007.JPG](https://qiita-image-store.s3.amazonaws.com/0/147246/77a92128-adb9-cc47-d362-de22150b9bf9.jpeg)

以上です。ご活用下さい。
vscodeのgolangのdebugで詰まった話

# 要約
vscodeでgolangデバッグしようと思ったら、localhostが`not such host`と言われ詰んでたら、hostファイルにlocalhostがなかったというアホすぎるお話。

# vscode
jetbrain社のintelliJ使ってるからgoもkotlinもdebugモードで実行できるけど、学生終えて有料になった時の事を考えてvscode使いになろうと思った。

# delve
vscodeでgolangデバッグするには、vscodeの拡張機能とgoのパッケージdelveを`go get`する必要がある。割愛。

# debugモード
ブレークポイント作ってそこでプログラムを止めて変数の中身を見れる。最強。

# エラー内容
なんかエラー吐いてた

```
couldn't launch process: listen tcp: localhost :not such host
```
的な感じだった。スクショ撮り忘れてうろ覚え。

# 解決策
まさかのhostファイルが真っ白だった
`vim /private/etc/hosts`に127.0.0.1 localhost を追記
無事解決。
Macで移行アシスタント使ったらファイルが開けなくなった話

# 要約
Macで移行アシスタントを使って別のMacにデータを移行したら「ファイルが壊れています。ゴミ箱に入れる必要があります」とかなんとか出てきて、画像も何も開けなくなった。が、コマンド一つで解決した。自分への備忘

# バグ？
`システム環境設定`の`セキュリティとプライバシー`のアプリの開く許可のところを変更しても、戻ると変更されていない。これは何しても治らなかった。。。

# 解決策
コマンド一つ

```
sudo spctl --master-disable
```
以上。
なんのバグやねん
Cocoa Podsでライブラリを公開するときにpodspec設定で躓いたところ

# 導入
ライブラリを公開するときにpod lib lint 【podspecファイル名】でチェックすると思います。
そのときにデフォルトのままだと大量のエラーが出たのでその時に対処したことを記述していきます。

今回サンプルに使うライブラリ
https://github.com/HideakiTouhara/TinderCard
(スターも押して頂けると嬉しいです)

# 対処したこと一覧
一つずつ挙げていきます。

## - ERROR | attributes: Missing required attribute \`summary`.

podspecのファイルの中のsummaryはデフォルトでは設定されていませんが、必須項目です。
podspecファイルを開いてs.summaryにライブラリの概要を記入しましょう。
例

```
  s.summary      = "Use tinde like UI instantly."
```

## - WARN  | description: The description is equal to the summary. もしくは - ERROR | description: The description is empty.

先ほどと同じ要領でdescriptionにも文言を設定していきましょう。
summaryと文言は違ったもので設定しましょう。

```
  s.description  = <<-DESC
		   - You can implement tinder UI like tableView.
                   DESC
```

##     - ERROR | license: Sample license type.
Licenseのタイプとファイルを指定しましょう。
github上でレポジトリを作成する際にライセンスを作成しておくのが良いと思います。
MITなら以下でいけます。

```
s.license      = { :type => "MIT", :file => "LICENSE" }
```

##     - ERROR | file patterns: The \`source_files` pattern did not match any file.
ライブラリに使うソースのパスを正しく指定します。
サンプルの場合はこんな感じです。

```
  s.source_files  = "TinderCard/**/*.swift"
```

##     - WARN  | swift_version: The validator for Swift projects uses Swift 3.0 by default, if you are using a different version of swift you can use a \`.swift-version` file to set the version for your Pod. For example to use Swift 2.3, run:

使用するSwiftのバージョンをechoしてほしいと言っています。
コマンド上から実行します。
自分は以下のようにしました。

```
echo "4.0" > .swift-version
```

## platform
エラー内容は忘れましたが、platformも指定します。

```
  s.platform     = :ios, "10.0"
```
# 完成

以上であとはpod trunk push 【podspecファイル名】で公開完了です！

もしかしたら他にも指定しなければならない項目があるかもしれませんが、そのときは[https://github.com/HideakiTouhara/TinderCard](https://github.com/HideakiTouhara/TinderCard)に[TinderCard.podspec](https://github.com/HideakiTouhara/TinderCard/blob/master/TinderCard.podspec)があるので参考にして頂ければと思います。

# Cocoa Podsで公開するための資料
https://qiita.com/s0hno/items/d1600457dce94ec635be
https://qiita.com/taji-taji/items/e23373f9b8124de728a2
QiitaでCodePenの埋め込みコードが見れない

# 現象

[Qiitaで記事にCodePenが埋め込めるようになりました - Qiita](https://qiita.com/Qiita/items/edae7417214c8e957f54)

>![image.png](https://qiita-image-store.s3.amazonaws.com/0/62354/db1dac8c-704a-1779-c6bf-530163d51f38.png)

見れない><


>CodePen requires a referrer to render this. Your browser isn't sending one.  If you have questions, contact support@codepen.io.

と常に出て見れない。

# 解消方法

[歌うキツネ : 各種ブラウザでリファラー(Referrer)を送らない](http://utaukitune.ldblog.jp/archives/65696343.html)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/62354/ae48f669-b24e-c6d1-0e58-90e72465f973.png)

記憶にないけれどガチガチにしているせいかリファラーを送らないようにしていたので、値を2にして送るようにすると表示できた。
1ではダメだった…

# 参考

* [Security/Referrer - MozillaWiki](https://wiki.mozilla.org/Security/Referrer)

***

* [「Firefox 59」でプライバシー保護機能を強化する「リファラの削減機能」の内容をMozillaが発表 - GIGAZINE](http://gigazine.net/news/20180205-firefox-referrer-trimming/)

プライベートブラウジングモード限定らしいが、自動で削除されるようになるらしい。
ビットコインエクスプローラー(ウォレットコマンド:fetch-header)

# ビットコインエクスプローラー(ウォレットコマンド:fetch-header)

原文(https://github.com/libbitcoin/libbitcoin-explorer/wiki/)

## bx fetch header

指定したhashまたは、heightからブロックヘッダを取得する。
heightは、両方指定された場合、無視される。

```
Usage: bx fetch-header [-h] [--config value] [--format value] [--hash
value] [--height value]

情報:指定したhashまたは、heightからブロックヘッダを取得する。heightは、両方指定された場合、無視される。
libbitcoin serverと接続する必要がある。

Options (named):

-c [--config]        コンフィギュレーションファイルを指定        
-h [--help]          コマンドの説明を表示
-f [--format]        The output format. Options are 'info', 'json', and  
                     'xml', defaults to 'info'. 
                     アウトプットのフォーマットを指定。オプションは、'info','json',と’xml'。
                     デフォルトは、'info'           
-s [--hash]          Base16ハッシュ
-t [--height]        ブロックの高さ

```

このコマンドは、設定をサポートをしている。

#### Example 1

ブロックHeight 0

```
bx fetch-header
```
```
header
{
    bits 486604799
    hash 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
    merkle_tree_hash 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b
    nonce 2083236893
    previous_block_hash 0000000000000000000000000000000000000000000000000000000000000000
    time_stamp 1231006505
    version 1
}
```

#### Example 2

ブロックHeight 1

```
header
{
    bits 486604799
    hash 00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048
    merkle_tree_hash 0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098
    nonce 2573394689
    previous_block_hash 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
    time_stamp 1231469665
    version 1
}
```

#### Example 3

ハッシュ　ジェネシスブロック

```
header
{
    bits 486604799
    hash 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
    merkle_tree_hash 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b
    nonce 2083236893
    previous_block_hash 0000000000000000000000000000000000000000000000000000000000000000
    time_stamp 1231006505
    version 1
}
```
enchant.js 継承を利用した衝突判定

[昨日の記事](https://qiita.com/takako_sudou/items/bc9a5eba827df539037e)の続きです。

昨日は連射した弾丸と次々現れる敵の衝突判定をするのに、functionではなくてクラスを使うとプログラムをシンプルにできるという記事を書きました。

今回は少し応用編として、継承を利用した方法について。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/234600/0c99c5ca-068b-c7db-aec9-81b0dfb5c369.png)

白くまからサッカーボール(Ballクラス）を連射し、男の子のクマ（T_Boyクラス）か女の子のクマ（T_Girlクラス)に当たったかどうかを判定するとします。

この場合も、衝突判定は前回と全く書き換えていません。

```js
            // BallクラスとTargetクラスの衝突判定
            Ball.intersect(Target).forEach(function(pair)
            {
                //pair[0]: Ballのインスタンス
                //pair[1]: Targetのインスタンス
                game.rootScene.removeChild(pair[0]);
                game.rootScene.removeChild(pair[1]);
            });
```


BallクラスとTargetクラスが当たっているかを判定しているだけです。

なぜこのようなことができたかというと、ポイントは、男の子のクマ（T_Boyクラス）と女の子のクマ（T_Girlクラス)は、Targetクラスの子孫として記述したことです。

```js
    // ターゲットクラス
    var T_Boy = Class.create(Target, {initialize:function(){
        Target.call(this);
        this.frame = 1;
    }});
    
    var T_Girl = Class.create(Target, {initialize:function(){
        Target.call(this);
        this.frame = 11;
        this.speed = 3;
    }});
```

Targetクラスが親、T_BoyクラスとT_Girlクラスが子孫なので、この３つをまとめて親の名前を取ってTargetクラス一族と呼ぶことにしましょう。

つまりBallクラスとTargetクラス一族が当たっているかを判定していることになるのです。

Targetクラスが親、T_BoyクラスとT_Girlクラスが子孫のような関係を、オブジェクト指向プログラミングでは継承といいます。

Targetクラスがスーパークラス、T_BoyクラスとT_Girlクラスがサブクラスです。

特にT_BoyクラスとT_Girlクラスに派生させなくてもTargetクラスだけあれば同様の処理はできなくはないです。なぜあえて派生をつかうのでしょう。

それは、衝突判定はもちろんその後の処理の記述効率がとても良いからです。

例えばTBoyとT_Girlにボールがヒットしたときに得点が加算されるとします。さらにT_BoyとT_Girlでは加算されるポイントが異なるともします。

もし派生を使わない場合、衝突を感知するたびに「当たったのは男の子なのか女の子なのか」をメンバ変数などを使って条件分岐する処理を書いておく必要があります。

しかし同じ親から派生した別々のクラス、まるで兄弟のようなクラスにしておけば、共通の部分は親クラスに、異なる部分は子クラスそれぞれに記述できます。

少しまだ雑な説明ですが、クラスと継承が分かるとオブジェクト指向プログラミングがとても面白くなります。

もう少し追記かリライト、または別記事で、もう少し丁寧に説明できるといいですね。。。がんばります。

全てのサンプルはこちらにあります。
http://code.9leap.net/codes/show/143744
ビットコインエクスプローラー(ウォレットコマンド:tx-decode)

# ビットコインエクスプローラー(ウォレットコマンド:tx-decode)

原文(https://github.com/libbitcoin/libbitcoin-explorer/wiki/)


## bx tx decode

Base16トランザクションをデコードする。

```
bx tx-decode --help
```
```
Usage: bx tx-decode [-h] [--config VALUE] [--format VALUE] [TRANSACTION] 

情報：Base16トランザクションをデコードする。                     

オプション (named):

-c [--config]        コンフィギュレーションファイルを指定        
-h [--help]          コマンドの説明を表示    
-f [--format]        フォーマットを指定。'info'、'json'、'xml'のいずれかで
                     デフォルトは、'info'
                     
引数 (positional):

TRANSACTION          BASE16トランザクション。指定がなければSTDINから読み込む
```

3.1バージョン移行、アドレスプロパティは、望ましくない支払いアドレスバージョンの依存を避けるために、アドレスハッシュに変わっている。

## Example 1


署名なしの、input、支払いアドレスアウトプット

```
bx tx-decode 0100000001b3807042c92f449bbf79b33ca59d7dfec7f4cc71096704a9c526dddf496ee0970000000000ffffffff01c8af0000000000001976a91458b7a60f11a904feef35a639b6048de8dd4d9f1c88ac00000000
```
```
transaction
{
    hash f9be6abf60342de5606421c7deaaf2d3f7133490db5242e8507e05926b16d090
    inputs
    {
        input
        {
            previous_output
            {
                hash 97e06e49dfdd26c5a904670971ccf4c7fe7d9da53cb379bf9b442fc9427080b3
                index 0
            }
            script ""
            sequence 4294967295
        }
    }
    lock_time 0
    outputs
    {
        output
        {
            address 1966U1pjj15tLxPXZ19U48c99EJDkdXeqb
            script "dup hash160 [58b7a60f11a904feef35a639b6048de8dd4d9f1c] equalverify checksig"
            value 45000
        }
    }
    version 1
}
```

#### Example 2

署名されたトランザクション

```
bx tx-decode 01000000017d01943c40b7f3d8a00a2d62fa1d560bf739a2368c180615b0a7937c0e883e7c000000006b4830450221008f66d188c664a8088893ea4ddd9689024ea5593877753ecc1e9051ed58c15168022037109f0d06e6068b7447966f751de8474641ad2b15ec37f4a9d159b02af68174012103e208f5403383c77d5832a268c9f71480f6e7bfbdfa44904becacfad66163ea31ffffffff01c8af0000000000001976a91458b7a60f11a904feef35a639b6048de8dd4d9f1c88ac00000000
```

```
transaction
{
    hash 37c9c4ee0e84c7c7924f74d92cf0779ec6e8fc4c57ebab2593562d52c61c5eb8
    inputs
    {
        input
        {
            address 1JziqzXeBPyHPeAHrG4DCDW4ASXeGGF6p6
            previous_output
            {
                hash 7c3e880e7c93a7b01506188c36a239f70b561dfa622d0aa0d8f3b7403c94017d
                index 0
            }
            script "[30450221008f66d188c664a8088893ea4ddd9689024ea5593877753ecc1e9051ed58c15168022037109f0d06e6068b7447966f751de8474641ad2b15ec37f4a9d159b02af6817401] [03e208f5403383c77d5832a268c9f71480f6e7bfbdfa44904becacfad66163ea31]"
            sequence 4294967295
        }
    }
    lock_time 0
    outputs
    {
        output
        {
            address 1966U1pjj15tLxPXZ19U48c99EJDkdXeqb
            script "dup hash160 [58b7a60f11a904feef35a639b6048de8dd4d9f1c] equalverify checksig"
            value 45000
        }
    }
    version 1
}
```
ビットコインエクスプローラー(ウォレットコマンド:tx-encode)

# ビットコインエクスプローラー(ウォレットコマンド:tx-encode)

原文(https://github.com/libbitcoin/libbitcoin-explorer/wiki/)


## bx tx encode

Base16トランザクションをデコードする。

Encode an unsigned transaction as Base16.

未署名トランザクションをBase16でエンコードする。

```
bx tx-encode --help
```
```
Usage: bx tx-encode [-h] [--config VALUE] [--input VALUE] [--lock_time   
VALUE] [--output VALUE] [--script_version VALUE] [--version VALUE]       

情報：未署名トランザクションをBase16でエンコードする。

オプション (named):

-c [--config]        コンフィギュレーションファイルを指定        
-h [--help]          コマンドの説明を表示    
-i [--input]         TXHASH:INDEX:SEQUENCEフォーマットで、トランザクションのinputを指定する。
                     TXHASHは、BASE16を指定(transaction hash)。
                     インデックスは、32ビット。シーケンスは、任意の32ビットのインプットシーケンス、デフォルトは最大値。 
-l [--lock_time]     トランザクションロックタイムを指定。
                     
-o [--output]        TARGET:SATOSHI:SEEDでエンコードされた、トランザクションアウトプットのセット。
                     TARGETは、アドレス(stealthやpay-to-script-hashを含む)、または、Base16スクリプト。
                     SATOSHIは、64bitの消費量を指定。
                     SEEDは、stealthアウトプットのために必要とされ、他には使われない。
                     同じシードは、複数アウトプットではつかわれない。

-s [--script_version] pay-to-script-hashアドレスのバージョン。デフォルトは5。
                      アウトプットのアドレスを識別するために使われる。

-v [--version]       .トランザクションのバージョン、デフォルトは1.
```

#### Example 1

1インプット、アドレスアウトプット

```
bx tx-encode -i 97e06e49dfdd26c5a904670971ccf4c7fe7d9da53cb379bf9b442fc9427080b3:0 -o 1966U1pjj15tLxPXZ19U48c99EJDkdXeqb:45000
```
```
0100000001b3807042c92f449bbf79b33ca59d7dfec7f4cc71096704a9c526dddf496ee0970000000000ffffffff01c8af0000000000001976a91458b7a60f11a904feef35a639b6048de8dd4d9f1c88ac00000000
```
zplug の自動インストールを高速化してみた

いつも使ってる [zplug](https://github.com/zplug/zplug) が遅いと感じ始めたのでちょっと工夫してみました!
**`$ZPLUG_LOADFILE` を設定して、キャッシュを使用してることが前提条件です.**

## tl;dr
```diff:.zshrc
 source $ZPLUG_HOME/init.zsh

+if [[ $ZPLUG_LOADFILE -nt $ZPLUG_CACHE_DIR/interface || ! -f $ZPLUG_CACHE_DIR/interface ]]; then
 	zplug check || zplug install
+fi

 zplug load
```
条件を追加するだけです!

## 詳しく
`[[ $ZPLUG_LOADFILE -nt $ZPLUG_CACHE_DIR/interface ]]` は キャッシュ(`$ZPLUG_CACHE_DIR/interface`) と 設定ファイル(`$ZPLUG_LOADFILE`) の更新日時を比較します.
また, `[[ -f $ZPLUG_CACHE_DIR/interface ]]` はキャッシュが生成されてない場合は新しく zplug 自体をイントールなどを行ってる可能性があるので確認してます.

zplug はインストール済みで更新があったときのみ確認したいので `[[ $ZPLUG_LOADFILE -nt $ZPLUG_CACHE_DIR/interface ]]` を先に書いてます

補足: `$ZPLUG_CACHE_DIR` は zplug を読み込むと設定されるので設定しなくても使えます.

## ちなみに
<img width="560" alt="image.png" src="https://qiita-image-store.s3.amazonaws.com/0/96420/c0333339-c65d-4b63-43f5-30acb1ddef00.png">

`zplug check` を計測してみましたが結構時間がかかってる処理だったので起動が早くなると思います!
もうググらない、サイトの引っ越し、転送のためのリダイレクトいろいろまとめ


# ここリダイレクトさせてくれる？

## はじめに

たまにリダイレクトするページ作ってとか言われると、いちいちソース覚えてないし、
サーバーとか意味わからんし、
毎回ググるのも面倒なのでまとめときます
:smirk:



## 書いてみよう
### ■ リダイレクトタグ
meta、1行書くだけです。
例えば、外部に飛ぶアンカーに計測タグかましたいときとか、
これ書いてタグだけ入れたページを作って読ませたりします。

```html:html
<meta http-equiv="refresh" content="0; URL=http://XXXXXXX">
```
ただgoogleではあまり推奨されていない書き方のようです。下記の301か302でのリダイレクトを推奨しています。
なお、yahooでは、content="0;を指定した場合は301と同じ扱いになると回答しているようです。

参考：[301リダイレクトが使えないときの転送方法 | 海外SEO情報ブログ](https://www.suzukikenichi.com/blog/alternative-to-301-redirect/)

### ■ 301リダイレクト https化
google推奨はこちらです、サーバーのお引越しのときとかは基本こっちでいいと思います。
放り込んだら、移送先が同じディレクトリ構造だったら同じページに飛ばしてくれますね。

素敵！


```html:.htaccess
RewriteEngine on
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ http://XXXXXXX/$1 [R=301,L]
```
しかし便利な.htaccessにもデメリットがあります。
サーバー自体がリダイレクトに対応してないことがあります。
この場合は正直どうにもならないので、別の手段をとるしかないです。

※他にもPHPとかJSでリダイレクトする方法もあるようですが、そもそもそのやり方を選ぶ必要性を感じないので省略します。

#### 301リダイレクトってなんですか?
>301リダイレクトは、URLが恒久的に変更された場合に用いられる転送処理のステータスコードです。転送のステータスコードとして他に302リダ>イレクトがありますが、302リダイレクトは「一時的な転送」を表すものであり、その意味が異なります。
>引用：[301リダイレクトとは | SEO用語集：意味/解説/SEO効果など [SEO HACKS]](https://www.seohacks.net/basic/terms/301_redirect/)

恒久とか一時的とかよくわかりません！日本語でお願いします！！！！
となりそうですが、こういうとこはどうして難しく書くのかわかりませんが、
サーバーお引越しは恒久的で大丈夫だと思います。

基本301で大丈夫だと思います:wink:


## もっと.htacessを知る
ここが一番わかりやすかったです。
コピペで色々使えるのでここブクマ推奨。

参考 :[よく使う.htaccessの書き方まとめ 301リダイレクト - Minimal Green](http://blog.minimal-green.com/entry/htaccess)


## 他、参考にしたサイト
[.htaccessなど、サーバー側でリダイレクトが利用できない場合どのように対処すれば良いですか？ | SEO対策Q&A [SEO HACKS] ](https://www.seohacks.net/basic/qa/inner_qa/cannot_use_htaccess/)
Unix タイムスタンプを渡しDateTimeは作れる。が比較はUnix タイムスタンプ同士がよくないか

ひとまず現在時刻との話。

# まとめ

* Unix タイムスタンプをそのまま`DateTime`の`__construct`に渡してもエラーとなる。
* `new DateTime('@' . time())`と頭に`@`を付けると書式が認められDateTimeインスタンスが得られる。
* ただし、`new DateTime('@' . time())`ではマシンのタイムゾーンが反映されず、第二引数にタイムゾーンを指定しても効かない。
 * インスタンスに対してタイムゾーンを指定する一手間が必要。
* `new DateTime()`ではタイムゾーンは適応されている(ex:`Asia/Tokyo`)ので、タイムゾーンを意識しないと9時間ずれる。
* PHPで時刻を取る関数の返り値はUnix タイムスタンプが多い[^1]
* 忘れやすいタイムゾーンを考慮するぐらいならば、もうUnix タイムスタンプを扱う必要が出た時点で無理に`DateTime`に変換しなくてもいいのではないか

[^1]: 印象です

(PHPマニュアルの表記に倣いWikiでのUnix時間をUnix タイムスタンプと呼んでいます)

***

Unix タイムスタンプで`DateTime`を作れなくていつも困るので見つけた記念にメモしようと思ったら、そもそもあまりよくなさそうという話。

# 参考

* [DateTimeオブジェクトにUNIXタイムスタンプとタイムゾーンを指定した時の挙動に関する備忘録 - Qiita](https://qiita.com/fivestar/items/f3c9d9fb40333a9f0987)
* [DateTimeクラスで日付文字列とUNIX時間(タイムスタンプ)を相互変換するときのまとめ - Qiita](https://qiita.com/sounisi5011/items/d6df76798d2e23c83e14#unix%E6%99%82%E9%96%93%E3%82%BF%E3%82%A4%E3%83%A0%E3%82%B9%E3%82%BF%E3%83%B3%E3%83%97%E3%81%8B%E3%82%89%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E3%82%92%E4%BD%9C%E6%88%90)

話としては参考記事で終わりだが、ではどうするのがいいのかと悩む。



# 検証環境

* PHP 5.4


```php
<?php

$tz = new DateTimeZone('Asia/Tokyo');

echo ((new DateTime())->format('Y-m-d H:i:s')) . "\n";
echo ((new DateTime('@' . time()))->format('Y-m-d H:i:s')) . "\n";
echo ((new DateTime('@' . time(), $tz))->format('Y-m-d H:i:s')) . "\n";
echo ((new DateTime('@' . time()))->setTimeZone($tz)->format('Y-m-d H:i:s')) . "\n";
```

```出力
2018-03-01 14:48:18
2018-03-01 05:48:18
2018-03-01 05:48:18
2018-03-01 14:48:18
```


`file(a,m,c)time()`はすべてUnix タイムスタンプで返すので、
ファイルがどれぐらい古いか=現在時刻との比較・差秒算出なら`new DateTime()`より`time()`で計算したほうが心配がない。のでは。

`(new DateTime('@' . time()))->setTimeZone(new DateTimeZone())`
では理由がコードから読み取れず、似たことをするときに

1. `setTimeZone()`をつけわすれる
2. タイムゾーンは自動で合わせられるはずと勘違いして取り除くリファクタリング
3. 第二引数でタイムゾーン指定できるのでこの書き方は冗長とリファクタリング

のどれかを自分なら踏み抜きそう。[^2]


ただなんでもUnix タイムスタンプで処理しろというわけではなく、
文字列で日付が来たら`strtotime()`より`DateTime`の方がいいと思っている。
あくまでどれか一つ、Unix タイムスタンプでしかとれない時刻が出てきたら、そっちに合わせたほうがいいんじゃないかなーという所感。

***

この経緯自体覚えることが難しそう…

[^2]: ~~自動テストしているなら大丈夫じゃないか~~
JDBCドライバをビルド後にダウンロードする

複数のデータベースをサポートするプロダクトは、ふつうはMavenのプロファイルを使って、dependenciesを切り替えると思いますが、プロファイルごとのMavenビルドが必要になって面倒です。

そこで、アプリケーションのJarは1つにしておいて、あとからランタイムで必要なJDBCドライバを足すことを考えます。

以下のようなシェルを用意します。

```bash:fetch_jdbc_driver.sh
#!/bin/bash -u

## requires: curl xmllint

declare -A drivers
drivers["h2"]="com.h2database:h2:RELEASE"
drivers["mysql"]="mysql:mysql-connector-java:RELEASE"
drivers["postgres"]="org.postgresql:postgresql:42.2.1"
drivers["sqlserver"]="com.microsoft.sqlserver:mssql-jdbc:6.4.0.jre8"

remote_repository=https://repo.maven.apache.org/maven2

function resolve_version () {
    local version_alias=$1
    local metadata_url=${remote_repository}/$2/maven-metadata.xml
    local xpath="/metadata/versioning/$(echo ${version_alias} | tr 'A-Z' 'a-z')/text()|/metadata/version/text()"

    curl -s ${metadata_url} | xmllint --xpath "$xpath" -
}

function fetch_driver () {
    local dbtype=$1
    local version=$2
    local deps=(`echo ${drivers[$dbtype]} | tr -s ':' ' '`)

    if [ ${#deps[@]} -eq 0 ]; then
        echo "Unknown database type: $dbtype"
        exit 1
    fi

    local group_path=$(echo ${deps[0]} | tr -s '.' '/')
    local artifact_path=${deps[1]}
    if [ -z "${version}" ]; then
        version=${deps[2]}
    fi

    if [ $version = "RELEASE" -o $version = "LATEST" ]; then
        version=$(resolve_version $version "${group_path}/${artifact_path}")
    fi

    local jarfile=${deps[1]}-${version}.jar
    curl -sL -o $dest_dir/$jarfile -w '%{http_code}' \
         ${remote_repository}/${group_path}/${deps[1]}/$version/$jarfile
}

dest_dir=runtime

if [ ! -e "$dest_dir" ]; then
    mkdir -p $dest_dir
fi

for arg in "$@"
do
    dbtypes=(`echo $arg | tr ':' ' '`)
    ret=$(fetch_driver ${dbtypes[0]} ${dbtypes[1]:-""})

    if [ $ret -eq 200 ]; then
        echo "Install driver: ${dbtypes[0]}"
    else
        echo "Not found: ${dbtypes[0]}"
    fi
done
```

```shell_session
% ./fetch_jdbc_driver mysql
```

のような感じで、最新のJDBCドライバをダウンロードします。特定のバージョンを指定することも可能です。

```shell-session
% ./fetch_jdbc_driver mysql:8.0.9-rc
```

Dockerfileでいうとこんな感じで使えます。

```dockerfile:Dockerfile
FROM alpine AS build

ARG RASCALOID_VERSION=0.1.0-SNAPSHOT
ARG dbtype=h2
RUN apk --no-cache add curl jq libxml2-utils bash

RUN mkdir /rascaloid
WORKDIR /rascaloid
RUN curl 'https://circleci.com/api/v1.1/project/github/kawasima/rascaloid/latest/artifacts?branch=develop&filter=successful' \
    | jq "map(select(.[\"path\"] == \"home/circleci/repo/target/rascaloid-${RASCALOID_VERSION}.jar\"))" \
    | jq '.[0]["url"]' \
    | xargs curl -o rascaloid.jar

ADD fetch_jdbc_driver.sh /usr/local/bin
RUN fetch_jdbc_driver.sh $dbtype

RUN apk del --purge curl jq libxml2-utils

FROM openjdk:8-alpine
COPY --from=build /rascaloid/ /rascaloid/
WORKDIR rascaloid
ENTRYPOINT ["java", "-cp", "rascaloid.jar:runtime/*", "net.unit8.rascaloid.Main"]
```
Swift：Terminalで実行するときコマンドライン引数でファイル指定して開く

#はじめに
SwiftをTerminalで実行できることを今更知った私です。
そこで、ふとシェルスクリプトのように使いたいぞと思い至りました。
コマンドライン引数でテキストファイルを指定して、その中身を開くというのを軽く実装できたのでまとめておきます。

#ソースコード
開きたいテキストファイル

```text:gomi.txt
aaa
bbb
ccc
```

実行するSwiftファイル

```swift:args.swift
import Cocoa

if CommandLine.arguments.count == 2 {
	let fileName: String = "./" + CommandLine.arguments[1]
	if let text = try? String(contentsOfFile: fileName, encoding: String.Encoding.utf8) {
		Swift.print(text)
	}
}
```

#実行
```text:terminal
$ swift args.swift gomi.txt
aaa
bbb
ccc

$
```
こんな感じでファイルを読み込んで`print`できます。
これでシェル感覚でちょっとしたCUI処理を行うことができますね。
rdsをslaveにするときに躓く点

# dump時

```
```

--master-data=2にする

# パラメータグループ

```
You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
```

log_bin_trust_function_creatorsを1にする

# dumpデータ編集

```
ERROR 1227 (42000) at line 60: Access denied; you need (at least one of) the SUPER privilege(s) for this operation
```

DEFINE=を消す
Swift, iOS：ナビゲーションバーにビューを重ねる方法

#背景
iOSでUINavigationBar(ナビゲーションバー)を使ったユーティリティアプリを作っている時、モーダルを表示する時に画面全体に半透明グレーのビューを重ねたくなるときがありました．
ナビゲーションバーにビューを重ねる方法で調べると、何やら結構厄介なことをしてそうだったので、簡単にできる方法はないかと模索した結果を備忘録的に書き記しておきます．
（ついでに、ビューをフェードで重ねる方法も書いておきます．）

#ソースコード（説明入り）
```swift:ExampleViewController
class ExampleViewController: UIViewController {
	let naviFadeView = UIView() //ナビゲーションバーの上にだけ重ねるビュー
	let mainFadeView = UIView() //メインコンテンツの上に重ねるビュー

	override func viewDidLoad() {
		super.viewDidLoad()

		//★★★ナビゲーションバーの上に重ねるビューの初期設定★★★
		//ナビゲーションバーの高さを取得
		let naviH: CGFloat = UIApplication.shared.statusBarFrame.height + self.navigationController!.navigationBar.frame.height
		//ビューのframeを設定
		naviFadeView.frame = CGRect(origin: CGPoint.zero, size: CGSize(width: self.view.frame.width, height: naviH))
		//ナビゲーションバーにビューを追加
		self.navigationController!.view.addSubview(naviFadeView)
		//ビューを隠しておく
		naviFadeView.isHidden = true
		//ビューの色設定（ここでは半透明の黒）
		naviFadeView.backgroundColor = UIColor(hex: "000000", alpha: 0.5)
		//フェードアニメーションのためにalphaも設定
		naviFadeView.alpha = 0.0

		//★★★メインコンテンツの上に重ねるビューの初期設定★★★
		//ビューのframeを設定
		mainFadeView.frame = CGRect(origin: CGPoint.zero, size: self.view.frame.size)
		//メインビューにビューを追加
		self.view.addSubview(mainFadeView)
		//ビューを最前面にする
		self.view.bringSubview(toFront: mainFadeView)
		//ビューを隠しておく
		mainFadeView.isHidden = true
		//ビューの色設定（ここでは半透明の黒）
		mainFadeView.backgroundColor = UIColor(hex: "000000", alpha: 0.5)
		//フェードアニメーションのためにalphaも設定
		mainFadeView.alpha = 0.0
	}

	//ビューをフェードイン
	func fadeIn() {
		mainFadeView.isHidden = false
		naviFadeView.isHidden = false
		//タイマーでアニメーション（UIView.animateでも可）
		Timer.scheduledTimer(withTimeInterval: 0.02, repeats: true, block: { (t) in
			if self.mainFadeView.alpha < 1.0 {
				self.mainFadeView.alpha += 0.05
				self.naviFadeView.alpha += 0.05
			} else {
				t.invalidate()
			}
		})
	}

	//ビューをフェードアウト
	func fadeOut() {
		//タイマーでアニメーション（UIView.animateではうまくいかなかった）
		Timer.scheduledTimer(withTimeInterval: 0.02, repeats: true, block: { (t) in
			if self.mainFadeView.alpha > 0.0 {
				self.mainFadeView.alpha -= 0.05
				self.naviFadeView.alpha -= 0.05
			} else {
				t.invalidate()
				self.mainFadeView.isHidden = true
				self.naviFadeView.isHidden = true
			}
		})
	}
}
```

#解説
ナビゲーションバーはメインビューよりも上層（手前）のレイヤーに存在するようで、単純にビューを最前面に持ってくるだけでは覆いかぶせることができません。
`AppDelegate`経由で`UIWindow`にビューを追加する方法とか、ナビゲーションバーの`layer.zPosition`を`-1`にしちゃうとか色々やりようがあるみたいですが、ViewControllerに処理が収まらないのは嫌だし、`zPosition`をマイナスにするとナビゲーションバーそのものが消えてしまいます。
そこで、一枚のビューに見せかければ良いのでは？というひらめきで実装してみました。
やっていることは簡単でナビゲーションバーに被せる用のビューとメインビューに被せる用のビューを用意してそれぞれの上に被せるだけです．色や透明度を同じにしたら、2つのビューの境目は全くわかりませんし、ユーザに気づかれることはないでしょう。
googleアカウントのプロフィール画像が変更できない時の対処法（「@gmail.com」ではなく企業アドレスでアカウントを管理している場合）

#問題の整理
gmailやdriveを開いた時に右上にプロフィールアイコンが表示されているが、変更しようとしてアップロードした画像を選択すると、「プロフィール写真を保存できませんでした。しばらくしてからもう一度試してください」（設定を英語にしている人は「Sorry!  We could not save your profile photo.  Please try again later.」）と表示される
※G suitesで企業アカウント管理下の場合のみ起こる。「@gmail.com」の個人アカウントでは起こらない

#解決法
・"管理者"が[G suites管理画面にログイン](https://admin.google.com/AdminHome?fral=1)
・ダッシュボードの「アプリ」をクリック
・「G Suites」をクリック
・「ディレクトリ」をクリック
・「プロフィールの編集」をクリック
・「写真」のチェックボックスにチェックをいれる
→これで企業に属しているすべてのメンバーが写真をアップデートすることができるようになる。

#メモ
・企業アカウントの場合は、デフォで写真が変更できないようになっているらしい
・forumの日本語版で同じ問題を質問している人がいたがベストアンサーが「googleに問い合わせしてみるのがいい」という解決になってない回答があったので今回書いてみた
・forumの英語版を見てみたら解決法が書いてあったので[それ](https://productforums.google.com/forum/#!topic/apps/LNybo9z56xw)を参考にした。