OmniAICreator/Qiita-1.07M huggingface dataset:
SwiftでplistをCodableで読み込む

# SwiftでplistをCodableで読み込む
昨日の記事[Swiftでplistを読み込む](https://qiita.com/drafts/40e8f92308e062644a43)に「NSDictionary使いたくない」って書いたら心優しい[masakihori](https://qiita.com/masakihori)さんが　Whisper words of wisdom　「Codeableで書けばええ」をくださった、、、ので早速トライした。

実行環境は前回と同じ（2018年6月20日現在　xcode 9.4.1, swift 4, ios 11.4）

## 結論
Codable　のほうが絶対いいよね。かっこいいし。
## コード
Codable　protocolをもつApiURL構造体をつくりました。
classでも使えるんか？って思って試しましたが使えません。
いや、正確には使えるかもしれませんがおそらく使い物になりません。

```swift:ApiCodable.swift
struct ApiURL: Codable {
    let BaseURL: String
    let Paths: ApiPaths
}

struct ApiPaths: Codable {
    let user: Dictionary<String, String>
    let staff: Dictionary<String, String>
}
```

そして以下のコードで　plist　をデコードします。propは構造体なので.（ドットシンタックス）でメンバにアクセスできます。　
すごく便利です。

```swift:AppDeligate.swiftとか
var prop: ApiURL?
if let urls = Bundle.main.path(forResource: "ApiURL", ofType:"plist" ) {
  do {
    let data  = try Data(contentsOf: URL(fileURLWithPath: urls))
    self.prop = try PropertyListDecoder().decode(ApiURL.self, from: data)
  } catch let e {
    print("Failed to getting properties from plist.")
    print("Reason: \(e)")
  }
}
prop?.BaseURL // -> "https://api.example.com"
```

##一言メモ
Codableはswift4で追加されましたが、かなりの発明品だと思う。
Nuxt.jsを使い始める前に考えること

## Nuxt.jsとは

ユニバーサルな Vue.js アプリケーションを構築するためのフレームワーク
https://ja.nuxtjs.org/guide

---

## SPA

![server-side-mvc.png](https://qiita-image-store.s3.amazonaws.com/0/20045/b621b3d8-cbb4-0a6d-2367-20ef8f9f347a.png)
https://medium.com/airbnb-engineering/isomorphic-javascript-the-future-of-web-apps-10882b7a2ebc

---

## SPAの問題点

##### SEO

GoogleのBotはクライアント側でDOMを書き換えていくようなページを正しく評価できる保証がない

---

## SPAの問題点

##### Performance

ブラウザは初期表示用のJSをダウンロードして実行するまで待つ必要がある

###### ※クライアントサイドJSがHTMLをレンダリングするまで待つ必要があるため

---

## SPAの問題点

##### Maintainability

アプリケーションロジックやビューロジックがクライアントとサーバー間で重複する

###### 特にルーティングやバリデーション（フォームとリクエストパラメータ）が重複しやすい

---

## Isomorphic JavaScript

![client-server-mvc.png](https://qiita-image-store.s3.amazonaws.com/0/20045/a08322ef-d80a-557e-f4f6-6deeb42d7026.png)
https://medium.com/airbnb-engineering/isomorphic-javascript-the-future-of-web-apps-10882b7a2ebc

---

## Isomorphic JavaScript

* クライアント側とサーバー側両方で実行できるJavaScriptアプリケーション
* ユニバーサルJavaScriptとも呼ばれる

---

## Isomorphic JavaScript

* Nuxt.jsはクライアント側、サーバー側でVue.jsを使ってこれを実現している
* Nuxt.jsのドキュメントではUniversal Vue.js Applicationと呼んでいる
https://nuxtjs.org/guide

---

## Nuxt.jsが解決するSPAの課題

---
## SEO

* Botがページを評価するときは必ずダイレクトアクセス
  * ![スクリーンショット 2018-06-11 23.50.58.png](https://qiita-image-store.s3.amazonaws.com/0/20045/c0ca3dc9-e9a1-b9e5-8aca-6675d72449d8.png)
    * https://twitter.com/JohnMu/status/895648997741875200

---

## SEO

ダイレクトアクセスのときはサーバー側で描画したコンテンツを返す（SSR）ため正しく評価される

---
## Performance

初期表示の際はサーバーサイドでHTMLが描画される（SSR）のでのJSをダウンロードして実行を待つ時間がかからない

---

### Maintainability

クライアントとサーバーのJavaScriptの記述をNuxt.jsが共通化してくれる

---

## 使ってみてわかったつらみ

---

## ルーティングの融通がききづらい

---

#### 動的なルーティング

```
/:make/:model  // --> showing model content.

/:section/:slug  // --> showing some other article
```

こういうのはNuxtのディレクトリ構造だけではルーティングを分けられない。
nuxt.config.jsに設定を追加するなど工夫する必要がある。

###### https://github.com/nuxt/nuxt.js/issues/2256

---

#### クライアントサイドからAPIへのアクセス

---

#### APIへのアクセス制限

個人情報等も扱うような基幹APIなどにクライアントサイドからのアクセス許可すなわち全世界からのアクセスを許可するのはつらい

---

#### APIへのアクセス制限

サーバーサイドへのリクエストをひとつはさむことで回避

→ クライアントからはNuxtのエンドポイントにしているExpressに一度リクエストしてそこからAPIにアクセスする

---

#### 枯れていない

issue, PR, マージ済みのCommitなど欲しい機能がなかなかリリースされない

----

#### 枯れていない

<img width="789" alt="Screen Shot 2018-06-13 at 16.38.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/20045/02f66d2e-fec6-e1d2-456e-dd36b0c7fb36.png">
https://github.com/nuxt/nuxt.js/issues/3018
はやくマージされてほしい。。
Unity-Androidアプリから明示的インテントで他のアプリを起動する

#Unity-Androidアプリから他のアプリを起動する

unityで作ったandroidアプリから
他のアプリを起動したかったから調べたら
URLスキーマを使うものしか見つからなかったので
明示的インテントで起動できるようにした。

##概要
1.Unityクラスの取得
2.アプリのアクティビティ取得
3.インテントに明示的にアプリパッケージ名とアクティビティの指定
4.起動
**※manifest.xmlの編集が必要かもしれない。確認中。**

```c#:startActivity.cs
string PackageName = com.campany.example;//パッケージ名
string MainActivity = ".MainActivity";//スタートアクティビティ(ドット必要)

AndroidJavaClass UnityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject Activity = UnityPlayer.GetStatic<AndroidJavaObject>("currentActivity");

Intent = new AndroidJavaObject("android.content.Intent");
Intent.Call<AndroidJavaObject>("setAction", "android.intent.action.VIEW");
Intent.Call<AndroidJavaObject>("setClassName", PackageName, PackageName + MainActivity);

Activity.Call("startActivity", Intent);
```
Elixirで大きな変数をファイルに書き出す

こんにちは．[fukuoka.ex](https://fukuokaex.connpass.com/)という技術コミュティにて活動しております、twibeeことenpedasiと申します。


今回は、変数の状態をファイルに書き出す方法をご紹介します。
私自信が開発中に巨大なMapをデバッグするのに困っていたので、ここでご紹介致します。

# 結論
忙しい時に見ると思うので、結論から先に書きます。

```elixir
File.write! "debug.txt", inspect(val, [pretty: true, limit: :infinity, printable_limit: :infinity])
```

valが変数とした場合に、内容を`debug.txt`に書き込む例です。

下記のようにモジュール化してLib直下などに配置しておくと良いでしょう。(一桁の数字のリストが化けないような設定も追加してあります)

```elixir:deb.ex
defmodule Deb do
  def put(val, file_path \\ "debug.txt") do
   File.write! file_path, 
       inspect(val, [pretty: true, 
                     charlists: :as_lists,
                     limit: :infinity, 
                     printable_limit: :infinity])
  end
end
```

こんな感じで使用します。

```
iex> Deb.put 1..1000 |> Enum.chunk_every(10) 
```

---

# リストの見えない部分にバグある⇒こまる

以下のようなリストを`IO.inspect`で出力した場合

```elixir
iex(1)> IO.inspect 1..1000 |> Enum.chunk_every(10)
```

次のような表示になってしまい、全部出力できません。
このような表示の後ろにバグの原因があった場合、困ってしまいますよね？

```elixir
  [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
  [11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
  [21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
  [31, 32, 33, 34, 35, 36, 37, 38, 39, 40],
  ')*+,-./012',
  '3456789:;<',
  '=>?@ABCDEF',
  'GHIJKLMNOP',
  'QRSTUVWXYZ',
  '[\\]^_`abcd',
  'efghijklmn',
  'opqrstuvwx',
  #
  # 中略
  #
  [391, 392, 393, 394, 395, 396, 397, 398, 399, 400],
  [401, 402, 403, 404, 405, 406, 407, 408, 409, ...],
  [411, 412, 413, 414, 415, 416, 417, 418, ...],
  [421, 422, 423, 424, 425, 426, 427, ...],
  [431, 432, 433, 434, 435, 436, ...],
  [441, 442, 443, 444, 445, ...],
  [451, 452, 453, 454, ...],
  [461, 462, 463, ...],
  [471, 472, ...],
  [481, ...],
  [...],
  ...
]
```

# IO.inspectとinspect

[IO.inspect公式](https://hexdocs.pm/elixir/Inspect.Opts.html)

通常であれば、IO.ipspectのオプションの指定でなんとかなりそうなものなのですが、`limit:`を指定しても表示は変わってくれません。

詳しくは@melpon さんの[「inspect について調べてみた」](https://qiita.com/melpon/items/dede48ad3bbc8c4ff443)の記事にもある通り、inspect関数を使用する必要があります。

IO.inspecとinspect、似た者同士なのですが、少し違うから厄介なのです。

頻繁に使うはずなのに、正当ルートで調べても徒労に終わる残念なケースです。ここに書いた結論もスマートなものではないのですが、知っているに越したことはありません。

効率よく行きましょう！
GKEの認証問題

# Authorization

## 問題

$ kubectl get pod --server https://{{cluster_endpoint}} --client-certificate=client.pem --client-key=key.rsa --certificate-authority=ca.pem

を実行して、以下のエラーが出ました。

Error from server (Forbidden): pods is forbidden: User "client" cannot list pods in the namespace "default": Unknown user "client"

## 原因

This is because, for GKE clusters, by default Legacy Authorization is disabled. So, we need to create role-based access to grant permissions to user. So, we grant current user the ability to create authorization roles.

## 解決方法

* 下記のコマンドでクラスターの認証を通す
```
$ gcloud container clusters get-credentials {{clustername}} --project {{projectname}} --zone {{zone}} 
```
* clusterrolebinding作成
 * rbak.yml ファイル作成、コマンド　`kubectl apply -f rbak.yml` を実行する
 
```
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: client-admin-crb
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: admin
subjects:
- kind: User
  name: client
  apiGroup: ""
```
フォトショップで文字化けならぬ画像化けしちゃう件の解決策

## フォトショップで文字化けならぬ画像化けしちゃう。

### 画像化けの原因
不明

### フォトショップ画像化けの解決策
フォトショップをアップデートしたら普通に治りました。アップデートしないと治らないのかなこれ。なんだろう。
ウェブからダウンロードした画像はよく画像化けしました。

![Adobe_Photoshop_CC_2018.jpg](https://qiita-image-store.s3.amazonaws.com/0/265198/006b6d27-5cc6-0640-39b3-c193fea89e32.jpeg)


## なにかおかしいなと思ったらやること

- パソコンの再起動
- ソフトの再起動
- アップデートチェック
- 環境設定をさらっと見てみる


今日もお仕事がんばるぞいっ
長さ 0 のスライスとしての nil (Go)

# 長さ 0 のスライスとしての nil (Go)

長さ 0 のスライスは`make([]T, 0)`でも作れますが、基本的には`nil`を使えば良いようです.

## 確認コード

```go
package main

import (
	"fmt"
)

func testNil(p []byte) {
	fmt.Printf("p: %v\n", p)
	fmt.Printf("len(p): %d\n", len(p))
	fmt.Printf("cap(p): %d\n", cap(p))
	for i := range p {
		fmt.Printf("NG: %d\n", i)
	}
	fmt.Printf("p[:]: %v\n", p[:])
	fmt.Printf("append(p, 0): %v\n", append(p, 0))
}

func main() {
	testNil(nil)
}
```

## 確認結果

```
p: []
len(p): 0
cap(p): 0
p[:]: []
append(p, 0): [0]
```

## 追記

2019/11/13 現在最新の Go 1.13.4 で動作が変わっていないことを確認
TensorFlowアルゴリズムの一般的な流れ③

一連の流れ[引用元(1)]
①デ―タセットをインポートまたは生成
②データを変換/正規化:fist_tone4:
③データセットをトレーニングセット、テストセット、検証セットに分割する
④アルゴリズムのパラメータを設定:taco:
⑤変数とプレースホルダーを初期化
⑥モデル構造を定義:flag_ag:
⑦損失関数を設定
⑧モデルの初期化とトレーニング
⑨モデルを評価:sunny:
⑩ハイパーパラメーターをチューニング
⑪デプロイと新しい成果指標の予測


##⑤からやってく。
まずプレースホルダと変数の違い。
プレースホルダ:実際の内容を後から挿入するためにとりあえず用意した場所。計算した結果の値とかを入れたい
変数:ある範囲内の数のこと。調べてたらtf.Variablesとかtf.assignとか出てきたからこいつらなんだろう。わかんないから飛ばす。



##⑥モデル構造を定義
難しいこと言っているけど計算グラフを作るために足したり掛けたりすること。この定義されたモデルってやつにさっきの変数とかプレースホルダーを入れてこねくりまわす。

##⑦損失関数を設定
損失関数は機械学習させた結果が実際に予測させたかった値にどれだけ近いかを示す関数。さまざまな種類の損失関数がある。

##⑧モデルの初期化とトレーニング
変数の作成や損失関数など必要な材料がそろったらあとは実行。初期化してリセットしてからやる。計算グラフとかの初期化も行う。トレーニングの所で機械学習が行われる

##⑨モデルを評価
ようやく実行させた。その結果がどれだけ精度が良かったか確認する。それがうまくいってなかったらどうしてうまくいかなかったのかを考え、次のステップに移る。

##⑩ハイパーパラメーターをチューニング
設定した値④に何か変更点があったかを検証する。そしてまた異なる値に設定したのち再度モデルを評価⑩させる

##⑪デプロイと新しい成果指標の予測
全てが終わった後それから読み取れたデータ、結果をもとに次の予測を考えていく。①に戻る

(1):「Pythonベースの活用レシピ60+ TensorFlow 機械学習クックブック　2017年」p3-5
GitHub as a storage

# はじめに
なんか良いストレージサービス無いかなーなんて探したりとかしたことありませんか?
でもあるじゃないですか。すぐそこに。

# :thinking:
## 普通に置く
GitHubには1ファイル当たり100MBの制限があるのでそのままではできないことがあります。
自分は大きなファイルの保存を試みようとしたので当然です。

## じゃあ分割すれば良いじゃない!
ファイル名もバレたくないしテキストファイルでファイル名とか管理するのもなぁ

# じゃあどうしたか
じゃあ分割したついでに暗号化すればいいじゃない! ついでにファイル名変更の対応表も自動生成しちゃえ!

という訳でつくったのが[これ](https://github.com/nao20010128nao/Cryptorage)

ドキュメントの類全く書いてないですが使い方は難しくない方だと思います。JitPackで入れましょう。

# 下準備
gitリポジトリを作りましょう

```bash
cd locked/
git init
git remote add origin https://github.com/nao20010128nao/somewhere-secret.git
```

# ベースファイルシステムを読み込む
全部Kotlinで書きます。importは`com.nao20010128nao.Cryptorage.*`にして下さいね

```kotlin
// ローカルから開く
val fs = File("secure/").asFileSource()

// GitHubのリポジトリから開く
val fs = URL("https://github.com/nao20010128nao/somewhere-secret/raw/inexistent/").asFileSource()

// メモリ上に展開する
val fs = newMemoryFileSource()
```

これで`FileSource`というCryptorage専用のファイルシステムを取得することができます。

# 暗号化ストレージを開く
暗号化はAES-128を用いています。
暗号鍵はパスワードから決定的に導かれます。

```kotlin
// シンプルな暗号ストレージ(V1)
val cryptorageV1 = fs.withV1Encryption("パスワード")

// 対応表の在り処すら特定困難にしたストレージ(V2)
val cryptorageV2 = fs.withV2Encryption("パスワード")
```

簡素化のためにパスワードだけの例を示しましたが、V1に限り`Pair<ByteArray, ByteArray>`をAES鍵として指定できたりします。

# 書き込む
CryptorageのAPIはGuavaのByteSink/ByteSourceを使っています。

```kotlin
// ByteSinkのAPIを活用
cryptorage.put("filename").write("This is a secret string!!!".toByteArray())

// OutputStreamで扱う
val os = cryptorage.put("filename").openStream()
// 書き込み操作
os.close()
```

# 読み込む

```kotlin
// 最初から
val is = cryptorage.open("filename").openStream()
// 途中から (分割をしているので途中からでもコストは低い)
val is = cryptorage.open("filename", offset).openStream()

// isはInputStreamなので好きに扱いやすいと思われる
```

# ファイル一覧を確認

```kotlin
cryptorage.list()// Array<String>
```

# 消す

```kotlin
cryptorage.delete("filename")
```

# 変更を保存

```kotlin
cryptorage.commit()
```

# 後始末
Cryptorageは`Closeable`なのでCloser系ユーティリティーが使えます。

```kotlin
cryptorage.close()
```

# アップロード

```bash
git add .
git commit -mChanged
git push
```

# などなど
こんな感じでファイルを分割しつつ暗号化してGitHubに保管できます。
ちなみにGitHubのブランチ当たりのサイズには限界があるようなので、ブランチを適宜切ったりして超えないように注意して下さい。
Hedera Hashgraphのセキュリティについて考えてみる：その１

*※2018年6月27日公開*
*※2018年6月27日編集*

N−Village CTOの林田です。
　[前回の記事](https://qiita.com/rinrin0108/items/d7401c6eac70084c77bc)では、Hedera Hashgraphの仮想投票について考察しました。今回は、Hedera Hashgraphのコンセンサスアルゴリズムにおける、セキュリティ耐性について考えてみたいと思います。

# 想定される攻撃パターン
　Hashgraphに対する攻撃パターンは、次のようなものが想定されると思います。

* 嘘のイベント（トランザクション）を作って送る
* 送られてきたイベントを改ざんして他のメンバーに送る
* 送られてきたイベントを無視して他のメンバーに送らない
* 適当なメッセージを大量に作って送る（DoS/DDoS攻撃）

　これがすべてではありませんが、今回の記事ではこれらについて考えます。それでは、攻撃パターン別に見ていきましょう。

# 嘘のイベント（トランザクション）を作って送る
　次のような攻撃を想定します。

**メンバーBが悪意を持っていたとき、Bが勝手に「AからBに100万円送った」というイベントをねつ造してCに送る**

![06.png](https://qiita-image-store.s3.amazonaws.com/0/16023/76ff84a7-cafb-4f5d-8189-7d80b5db889a.png)

　この時、Cは送られてきたイベントの内容をチェックします。
　Bが生成した嘘のイベントの中には「AからBに100万円送った」というトランザクションが記録されています。しかし、本来このトランザクションにはA本人による電子署名がされているべきですが、送られてきたトランザクションにはそれがありません。したがって、Cはこのイベントが嘘の内容であると判断することができます。

# 送られてきたイベントを改ざんして他のメンバーに送る
　次のような攻撃を想定します。

**メンバーBが悪意を持っていたとき、Aから送られてきたイベントのトランザクション内容を書き換えてCに送る**

![08.png](https://qiita-image-store.s3.amazonaws.com/0/16023/4e1643dd-10be-0588-9952-3fc3b71e6483.png)

　この時、Cは送られてきたイベントの内容をチェックします。
　Bが生成した嘘のイベントの中には「AからBに200万円送った」というトランザクションが記録されています。しかし、トランザクションの内容とAの電子署名から生成されるハッシュ値が異なります。したがって、Cはこのイベントが嘘の内容であると判断することができます。
　Bが完璧な改ざんをするには、Aの電子署名を偽造する必要があるため、不可能です。

# 送られてきたイベントを無視して他のメンバーに送らない
 次のような攻撃を想定します。

**メンバーBが悪意を持っていたとき、Aから送られてきたイベントを無視して他のメンバーに送らない**

![09.png](https://qiita-image-store.s3.amazonaws.com/0/16023/7c076e73-3ba0-2b3e-34b5-20d2a351c947.png)

　AはBだけに限らず、当該イベントの仮想投票が行われるまで、CやDなどに対してランダムにゴシップを続けます。そのため、Bだけが無視したとしても正しく仮想投票が行われます。

# 適当なメッセージを大量に作って送る（DoS/DDoS攻撃）
　次のような攻撃を想定します。

**メンバーBが悪意を持っていたとき、Bが適当なメッセージを大量に作成して他のメンバーに送りつけ、コンセンサスが確立されにくくする**

![07.png](https://qiita-image-store.s3.amazonaws.com/0/16023/636f91d7-b87d-37f5-cd92-42c0e4eccd88.png)

　通常、他のブロックチェーンにおけるDoS/DDoS攻撃では、コミュニティ全体の機能を効率的に低下させるために、コミュニティ内のコンセンサスの確立に大きく貢献しているメンバーに対してのみDDoS攻撃を仕掛けます。具体的には、ラウンドロビンで採択されたリーダーや、マイニングパワーに優れたメンバーなどが対象となります。
　ところが、Hashgraphではメンバー全員がコンセンサスの確立に対して平等に権限を有しています。そのため、DDoS攻撃を成功させるためにはコミュニティ全体の大部分のメンバーを機能不全にしてしまう程に大量のメッセージを送る必要があります。これは経済合理性から考えて現実的ではありません。したがって、Hashgraphはブロックチェーンと比較して強力なDoS/DDoS攻撃耐性を備えているといえます。

# セキュリティについての所感
　改ざんへの対処として電子証明書やハッシュを活用する部分はブロックチェーンと大きく違いませんが、DoS/DDoS攻撃耐性はHashgraphが優れている印象です。今後執筆する「その２」記事では、以下の攻撃パターンについても考えてみたいと思います。

* コミュニティ全体の1/3以上のメンバーをコントロール下に置く
* ネットワークが一時的に隔離された複数メンバーに対してイベントを送る

---
内容に間違いがあればご指摘いただけますと幸いです。よろしくお願いいたします。
自分用メモ：Linuxコマンド①

**先頭の空白を削除するコマンド例**
`$ sed -e 's/^[ ]*//g' hoge.txt`或いは
`$ sed 's/^[ \t]*//' hoge.txt`

**行末の空白を削除するコマンド例**
`$ sed -e 's/[ \t]*$//' hoge.txt`

**ファイル全体から目的の行を抜き出す例**
class="paging-number"属性のある行をgrepコマンドでフィルタリングする場合
`$ cat index.html | grep -E 'class="paging-number"'
<li class="paging-number">1</li>
<li class="paging-number">1 - 20 / 2000</li>`
更に下側を抜き出したい場合
`$ cat index.html | grep -E 'class="paging-number".*-'`[^1]
`<li class="paging-number">1 - 20 / 2000</li>`

**行から目的の文字列を抜き出す例**
`$ cat gihyo.jp/dp/index.html | grep -E 'class="paging-number".*-'
 | sed -E 's@.*/ ([0-9]+).*@\1@'`[^2]
`2000`
正規表現にマッチした箇所を取り除き残った箇所を抜き出す場合
`$ echo '<li class="paging-number">1 - 20 / 2000</li>' | sed -E 's/[^>]*>//g'`[^3]
`1 - 20 / 2000`
特定の文字で区切られた文字列からn番目を抜き出す場合
`$ echo '1,foo,bar' | cut -d , -f 2`
`foo`
スペースで桁揃えされた文字列からn番目を抜き出す場合[^4]
`$ echo 'PID  COMMAND   %CPU TIME     #TH   #WQ  #PORT MEM' | awk '{print $4}'`
`TIME`

[^1]: 「.*」は「>1 」を指すことになるから`'class="paging-number">1 -'`でもいいってこと
[^2]: sedコマンド区切り文字は改行とバックスラッシュを除く任意の文字に変更できる。正規表現中に/（スラッシュ）が登場する場合、バックスラッシュでエスケープしなくていいので可読性が向上する。
[^3]: 「0回以上の\>ではない文字列に文字\>が付く文字列」を空文字に変換
[^4]: cutコマンドは区切り文字1文字しか指定できないので、スペースで桁揃えされた文字列のように区切り文字が連続する場合は向いていない。このような場合はスペース限定でawkが使える。
[Laravel] ユーザーのアイコン画像を投稿、表示させる機能の実装したのでメモ（画像の保存場所は？シンボリックリンクって？）

#やりたいこと

Laravel で勉強のために簡単な CRUD アプリを作成中です。
ユーザーが自分のアイコン画像を投稿できる機能を実装しました。
ためになった知識や注意点などを自分用に備忘録としてメモします。

![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/238891/07198f3a-c3b1-88cd-d264-ec39cabf9143.png)
こんな感じのイメージです。

#画像はどのディレクトリに保存すればいいの？

コントローラーで受け取った画像などのファイルですが、基本的に `storage/app/public` 内に保存するようです。
（ただし、public ディレクトリに入っているファイルは誰でもアクセスできてしまうため、公開したくないファイルの場合は別途処理が必要みたいです。）

```UserController.php
public function image(Request $request, User $user) {

  // バリデーション省略
  $originalImg = $request->user_image;

    if($originalImg->isValid()) {
      $filePath = $originalImg->store('public');
      $user->image = str_replace('public/', '', $filePath);
      $user->save();
      return redirect("/user/{$user->id}")->with('user', $user);

}
```

上記コントローラーでは `<input type="file" name="user_image">` で送った画像ファイル `$request->user_image` を `store('public')` とすることで public ディレクトリに保存してます。

config 内の `filesystems.php` を確認するとディスクの設定が確認できます。初期設定では `storage/app` ディレクトリに保存されるようになっているので、public ディレクトリに保存するために store メソッドの引数にディレクトリ名 public を指定します。

また、どの画像がどのユーザーのアイコンなのかを識別するために、ファイル名をユーザーテーブルに保存しています。store メソッドの戻り値としてファイルのパスが渡されるため、そのパスをユーザーテーブルの image カラムに保存します。その際、パス名が `public/xxxxxxxxxx.jpg` となるので不要な `public/` の部分を削除しています。

#シンボリックリンクって？

Laravel で作ったアプリケーションが公開されるとき、公開されるのは一番上の階層にある public ディレクトリのみです。public ディレクトリにファイルや処理のすべてが集約されています。なので、保存した画像も public ディレクトリ内に存在しないとアクセスすることができません。そこで**シンボリックリンク**を利用して storage ディレクトリにアクセスできるようにします。

![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/238891/832cc32f-ca30-295e-1fba-1e918554d889.png)


今回初めてシンボリックリンクとうい単語を知りました。
といっても特に難しいものではなく、UNIX 系で使われるいわゆるショートカットのようなもののようです（厳密には違いがあるのかもしれませんが...）。

シンボリックリンクは Artisan コマンドで作成できます。

```
php artisan storage:link
```

![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/238891/6690f88f-3c39-9e0a-3dc4-c87397b935d6.png)

これで storage へのリンクができたので画像データへアクセスできます！
右側にちょこんとくっついてる矢印がリンクのマークかと思われます（画像はVSCode）。

#画像が表示されるか試してみる

作成したシンボリックリンクの中を見てみると、当然ですが `storage/app/public` の中身がこんにちわしてます。以下のようにビューを編集すれば画像が表示させるはず！

```html
@if($user->image == null)
  <img src="/storage/noimage.png">
@else
  <img src="/storage/{{$user->image}}">
@endif
```

ユーザーアイコンがなければ `noimage.png` を表示、アイコンが登録されていればユーザーテーブルの image カラムからファイル名を引っ張ってきます。

`<img>` タグの `src=` につづくパス名は、一番上の階層の public ディレクトリがルートディレクトリになりますので、`"/storage/xxxxxxxxx.jpg"` などとすることで画像へアクセスすることができます。この `storage` はシンボリックリンクのことですね。

![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/238891/37327db2-3031-f263-ec9a-46bde7db9d3d.png)

よし！成功～

今回は以上です。
pythonとraspberry piでマイクを用いた録音

なんとかpyaudioを使っての録音までこぎつけたのでメモ
メモ書き程度かつ画像なしなので分かりづらいかも
#Raspberry Piにマイクを接続
今回使用したマイクがこれ[サンワサプライ-MM-MCU01BK](https://www.amazon.co.jp/サンワサプライ-MM-MCU01BK-USBマイクロホン/dp/B013SYV6P2/ref=sr_1_1?ie=UTF8&qid=1529483654&sr=8-1&keywords=sanwa+マイク)
Raspberry Piへの接続はUSBを挿すだけで認識された。

優先順位の変更等は無視で
#ターミナルで録音、再生
これは簡単でターミナルに

```
$ arecord -D plughw:1,0 test.wav
```
を入力するだけで録音が開始される。止めるときはctl+cで終了。
再生するときは

```
$ aplay test.wav
```
で再生される。
#python(pyaudio)を使った録音
とりあえずpipでpyaudioをインストール
その後公式サイトの録音プログラムを試してみるも

```python:hoge_audio.py
import pyaudio
import wave

CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 2
RATE = 44100
RECORD_SECONDS = 5
WAVE_OUTPUT_FILENAME = "output.wav"

p = pyaudio.PyAudio()

stream = p.open(format=FORMAT,
                channels=CHANNELS,
                rate=RATE,
                input=True,
                frames_per_buffer=CHUNK)

print("* recording")

frames = []

for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
    data = stream.read(CHUNK)
    frames.append(data)

print("* done recording")

stream.stop_stream()
stream.close()
p.terminate()

wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
wf.setnchannels(CHANNELS)
wf.setsampwidth(p.get_sample_size(FORMAT))
wf.setframerate(RATE)
wf.writeframes(b''.join(frames))
wf.close()
```

しかしエラーを吐いてしまう

```Error
  File "hoge_audio.py", line 22, in <module>
    frames_per_buffer=CHUNK)
```

見たかんじ冒頭の設定が悪そうだったので、バッファを増やし、チャンネルもモノラルにしてみる

```
CHUNK = 1024*2
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
RECORD_SECONDS = 5
WAVE_OUTPUT_FILENAME = "output.wav"
```
すると今度は、Input: Overflowとのエラーが出たので

```
CHUNK = 512
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
RECORD_SECONDS = 5
WAVE_OUTPUT_FILENAME = "output.wav"
```

このように変更
これで録音できて、録音されたファイルはソースコードと同じディレクトリに保存されていた。

#参照
[194円(送料込み)のマイクと Raspberry Pi でボイスレコーダーを作る話し](https://qiita.com/UedaTakeyuki/items/e2bda3a0b1d6e367e637)
[RaspberryPiでマイク録音してみる【ヒミツのクマちゃん その２】](http://uepon.hatenadiary.com/entry/2016/12/15/095114)
c libcurl http client

```c
  /*
   * HTTP初期化
   */
int httpInitialize (void)
{
  m_curl = curl_easy_init();
}
/**
 * callback register
 */
void httpConnect (void)
{
  curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, httpMsgarrvd);
}
/**
 * HTTP受信
 *
 */
static int httpMsgarrvd( void* buffer, size_t length, size_t size, void* data ) {
  json_error_t error;

　json_t *root = json_loads((char*)buffer, 0, &error);
  char* out = json_dumps(root, JSON_ENCODE_ANY);
　/*受信処理*/

  json_decref(root);
  return 0;
}

static void httpSetHeaders(const char* api)
{
	CURLcode res;
	// ヘッダの追加
	struct curl_slist *headers = NULL;
	headers = curl_slist_append(headers, "Accept: application/json");
	headers = curl_slist_append(headers, "Content-Type: application/json");
	headers = curl_slist_append(headers, "charsets: utf-8");
 	headers = curl_slist_append(headers, "Content-Encoding: gzip");
  　　　curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, headers);	
	//API設定
	res = curl_easy_setopt(m_curl, CURLOPT_URL, api);
}

static json_t* httpSetCommonRequest(void)
{
	json_t *root = json_object();
	json_t *item = json_object();
	json_object_set_new(item, "itemName", json_string(itemValue));
	json_object_set_new(root,"RequestName",item);
	return root;
}
初心者に贈る エラー文の出ないバグを潰す方法

> プログラマーとは調査分析力が群を抜いたツワモノどものことである
> 〜 プログラマーについて　コレ=ナン=ノバグ (1936~1965)

#迷える羊たちへ
プログラミングをはじめたばかりの初心者やプログラミングを苦手と感じている情報学徒たちに、**テストコード**を作ってくださいとか**ブレークポイント**を活用してくださいという様な**高度なテクニックは要求しません**。デバッグというワードも知らないかもしれないですしね...
本記事では初心者プログラマーにぜひやってほしいバグ潰しの方法をまとめます。

#下ごしらえ
バグ潰しをする前に、確認すべきことがあります。

- 参考資料ちゃんと読めていますか？
- 課題の意味ちゃんと理解できていますか？
- 要件をちゃんと把握できていますか？

実はプログラミングが下手な人って高確率でそもそも日本語が読めないんです！まずは日本語の勉強をしっかりしましょう。ボキャブラリーを増やしましょう。意味のわからない単語との遭遇は貴重です。確実に調べて覚えていきましょう。次に英語の勉強をしましょう。参考資料の行き着くところはだいたい英語です。プラットフォームの公式リファレンスとかも英語です。
そして、実装に使用するプログラミング言語の勉強をしましょう。何か参考書を持っている場合は、とやかく言わずにまず最初のページから最後のページまで舐めるように読んでください。一冊くらい読破したと言える参考書を持っておきましょう。

#バグ発見編

1. 実装要件を明確にする
何をしなければならないのか正確に把握してください。

2. 処理の流れ(ストーリー)を全て追ってみる
イベントの発火から最終結果出力までの全てを追ってみてください。プログラムは処理の順序が何より重要なので、そこを意識しながら行なってください。

3. バグ箇所を絞る
どこでダメになっているのかを特定します。printデバッグを上手に使いましょう。おススメは**挟み撃ちprintデバッグ**です。`2`で押さえた処理の流れの最初と最後にprintデバッグを仕掛け、徐々にその間隔を狭めていきます。自ずとバグ箇所が追い詰められて炙り出せるという戦法ですね。この時printデバッグで出力する内容はその処理に関わっている変数の中身にしましょう。nullなのか負の値なのかなどとにかく吐き出すことで原因を見つけやすくなります。

断言できますが、どこら辺にバグの原因があるのか、この手法で範囲を狭められないことはありません。解決できるかどうかは別ですが...

#バグ解決編

最近のIDEで開発をしている場合、エラー文が出力されない/コンパイルが通ってしまうバグというのは基本的にロジックのミスしかありえません。なにかの処理が不足しているか、処理の順番を間違えているか、計算が間違っているか、そもそも理論が間違っているか以外考えられません。そうでないなら、もしかしたら使用しているライブラリやフレームワークのメソッドは期待する処理を行わないものかもしれません。

1. 何ができていないのかを明確に言語化する
例えば「うまく動かない」のではなく「クリックしても反応しない」とか「クリックができない」とか「図形が動かない」とか「図形が表示されない」とかより具体的な表現にしましょう。

2. 本当にそうなのかチェックする
例えば「キャンバスになにも表示されない」とバグを言語化したとします。本当にそうでしょうか？もしかしたらキャンバスの見えている範囲外に描画されているかもしれないし、見えない色で描画されているかもしれません。常に疑問を抱き、バグの可能性の芽を見捨てないでください。

3. 要件達成の原理に立ち返る
原理を考えて、何がなければいけないのか、どの順番で行わなければならないのかなどを理詰めで確認してください。理詰めが苦手という人はプログラマーに向いていないので諦めてください。大丈夫、きっと他にもっと向いていることがありますよ(知らんけど
>例:当たり判定の実装
>当たり判定をするためには、矩形と点あるいは矩形同士の領域を比較する必要があります。つまり比較するための領域が設定されており、最新状態に更新されていなければなりません。状態の更新処理がなく、当たり判定がうまく行かないということがあります。
>
>例 図形描画の実装
>オリジナルの図形インスタンスを作って満足しているパターン結構あります。概念的・内部処理的には良いのですが、キャンバスに描画されなければ意味がありません。インスタンスをキャンバスに追加する処理、再描画をかける処理が抜けているということもあります。

4. 図を描いてみる
頭を整理するためにも、人に説明するためにも図を描いてください。(上手な絵をかけとは言ってません。)図が描けないなら実装要件や状態遷移を完璧に把握できていないのと同義です。

5. 同じ症状に陥った人が過去にいないかググる
自分の理解を超える様な、「ぜってぇそんなの気づかねぇよ💢」という様なバグというのもあります。そんなバグは自力で見つけることはできません。先人に頼りましょう。
mysql5.7にしたら「SELECT list is not in GROUP BY clause」エラーが発生した

環境
---

```sh
$ mysql -V
mysql  Ver 14.14 Distrib 5.7.20, for osx10.12 (x86_64) using  EditLine wrapper
```

対応
---

mysql 5.6 -> 5.7にした際にsql_modeの初期設定が変更されていたのが原因でした。
localにはhomebrewでmysqlをインストールしていたので、my.cnfの変更と再起動で対応します。

### mysqlのSQLモードを確認

```sql
SELECT @@sql_mode;
=> ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
```

なんかいろいろいますね・・・ :thinking: 
（mysql5.7から7個のSQLモードが初期設定されているそうです）

### my.cnfのSQLモードを変更

my.cnfの場所を確認します。

```sh
$ mysql --help | grep my.cnf
                      order of preference, my.cnf, $MYSQL_TCP_PORT,
/etc/my.cnf /etc/mysql/my.cnf /usr/local/etc/my.cnf ~/.my.cnf
```

SQLモードはとりあえず空っぽにしときます。
（今回のエラーの原因の`ONLY_FULL_GROUP_BY`を取り除くだけでもいいです）

```diff:/usr/local/etc/my.cnf
  # Default Homebrew MySQL server config
  [mysqld]
  # Only allow connections from localhost
  bind-address = 127.0.0.1
+ sql_mode = ""
```

### mysqlサーバを再起動
```sh
$ mysql.server restart
```

Done. :clap: 

参考
---

- [脱！ゆるふわMySQL - Qiita](https://qiita.com/bboobbaa/items/9fdca834076cb4c3389e)
- [Hemebrewで入れたMySQLのmy.cnfを設定 - ほげほげ（仮）](https://starzero.hatenablog.com/entry/2012/11/10/103047)
- [MySQL :: MySQL 5.6 リファレンスマニュアル :: 5.1.7 サーバー SQL モード](https://dev.mysql.com/doc/refman/5.6/ja/sql-mode.html#sql-mode-setting)
Springで直接Responseデータを書き込むには

HttpServletResponseに直接書き込みたい、という要望があったので、その方法を調べました。

# やり方
Controllerの引数にHttpServletResponseを定義し、そこに書き込むだけです。

```java:HelloController.java
@Controller
public class HelloController {

  @RequestMapping(value="/", method=RequestMethod.GET)
  public void hello(HttpServletResponse response) throws Exception {
    response.getWriter().write("hogehoge");
  }
}
```

# レスポンスを書き込むパターンとView名を返却するパターンを分岐したい
戻り値をStringにします。
レスポンスに直接書き込んだ場合はnullを返却します。

```java:HelloController.java
@Controller
public class HelloController {

  @RequestMapping(value="/{param}", method=RequestMethod.GET)
  public String hello(HttpServletResponse response, @PathVariable String param) throws Exception {
    if(Objects.equals("param", param)){
      response.getWriter().write("hogehoge");
      return null;
    }
    return "hello";
  }
}
```

# nullを返却したらエラーが出たと文句を言われた
nullを返却したらエラーログが出たんだけど、と報告がありました。
ログを確認すると、JSPを探しに行ったけど見つからない、みたいな内容でした。

ということでソースコードを確認してみると以下のような感じになっていました。

```java:HelloController.java
@Controller
public class HelloController {

  @Inject
  HttpServletResponse response

  @RequestMapping(value="/{param}", method=RequestMethod.GET)
  public String hello(@PathVariable String param) throws Exception {
    if(Objects.equals("param", param)){
      response.getWriter().write("hogehoge");
      return null;
    }
    return "hello";
  }
}
```
確かにこのように実装するとJSPを探してエラーになるみたいでした。つまり、Viewのrender処理が実行されている。
ちなみに、HttpServletResponseってInjectできるんだー、と思いましたが話の本筋ではないのでスルー。

## フレームワークの中身を確認してみる
### render処理が実行されないための条件は？
DispatcherServletを確認すると、HandlerAdapterを実行してModelAndViewを取得しています。
このとき、戻り値がnullであればViewによるrender処理は実行されません。Responseを直接書き込んでいる場合は、この挙動になることを想定しています。
（doDispatchやprocessDispatchResultなど）

### では、HandlerAdapterの戻り値がnullになる条件は？
RequestMappingHandlerAdapterの処理を見てみると、ModelAndViewContainerのisRequestHandledがtrueになった場合にnullを返却しています。
（getModelAndViewなど）

### では、これがtrueになるための条件は？
いろんな条件があるのですが、今回のケースに関して言うと、Controllerメソッドの引数にHttpServletResponseがあること、Controllerからの戻り値がnullであることが条件となります。
エラーが発生していたソースでは、フィールドに定義されたHttpServletResponseを利用しているため、HandlerAdapterの戻り値がnullにならなかった、ということです。

### 参考までに、View名がnullのときの動作
DispatcherServletのapplyDefaultViewNameからの処理を追えば、リクエストされたURLをView名として適用していることがわかります。

## 解決方法
引数にHttpServletResponseを追加しましょう。
そんなことできないよ～、という方は以下のようにControllerの戻り値の型をModelAndViewにしましょう。

```java:HelloController.java
@Controller
public class HelloController {

  @Inject
  HttpServletResponse response

  @RequestMapping(value="/{param}", method=RequestMethod.GET)
  public ModelAndView hello(@PathVariable String param) throws Exception {
    if(Objects.equals("param", param)){
      response.getWriter().write("hogehoge");
      return null;
    }
    return new ModelAndView("hello");
  }
}
```

なぜこれで上手くいくのかは、ModelAndViewMethodReturnValueHandlerを読めばきっとわかります。
C　gzip圧縮　httpサーバー送信

```c

#include <stdio.h>
#include <string.h>
#include <zlib.h>

int compress_gzfile_puts(const char* filename, char* source)
{
    gzFile zp;

    zp = gzopen(filename, "w9");
    if(zp == NULL){
        fprintf(stderr, "gzopen error\n");
        return -1;
    }
	
    gzwrite(zp, source, strlen(source));
	
    gzclose(zp);

    return 0;
}

static bool httpUploadGzipFile(const char* filename, char* source)
{
	CURLcode res;
    long statusCode= -1;
	struct stat file_info;
	FILE *fd;
	
	//gzip圧縮
	compress_gzfile_puts(filename, source);
	
	//open file to upload
  fd = fopen(filename, "rb");
	//can't continue
	if(!fd) {
    return false;
	}
  //to get the file size
  if(fstat(fileno(fd), &file_info) != 0) {
    return false;
	}
	
	//Post
	curl_easy_setopt(m_curl, CURLOPT_CUSTOMREQUEST, "POST");
	curl_easy_setopt(m_curl, CURLOPT_POST, 1);
	
	/*圧縮じゃない方法でデータをサーバー送る
	curl_easy_setopt(m_curl, CURLOPT_POSTFIELDS, postthis);
	curl_easy_setopt(m_curl, CURLOPT_POSTFIELDSIZE, strlen(postthis));
	*/
	
	//tell it to "upload" to the URL
  curl_easy_setopt(m_curl, CURLOPT_UPLOAD, 1L);
 
  //set where to read from (on Windows you need to use READFUNCTION too)
  curl_easy_setopt(m_curl, CURLOPT_READDATA, fd);
 
  //and give the size of the upload (optional)
  curl_easy_setopt(m_curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size);
	
	//Set the default value: strict certificate check please
	curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, 0L);

	//実行
	curl_easy_perform(m_curl);
	
  res = curl_easy_getinfo( m_curl, CURLINFO_RESPONSE_CODE, &statusCode);
	if(res != CURLE_OK) {
   	return false;
  }
	
	return true;
}
Slack で n 週間ごとに当番を通知する

たとえば 3 チームあって週ごとに交代制をとりたい場合。
先に `@groupA`, `@groupB`, `@groupC` を作っておいて、次のようにやる

```
/remind #channel "@groupA message" every 3 weeks on Monday 6/25
/remind #channel "@groupB message" every 3 weeks on Monday 7/2
/remind #channel "@groupC message" every 3 weeks on Monday 7/9
```

see also: https://get.slack.help/hc/ja/articles/208423427-%E3%83%AA%E3%83%9E%E3%82%A4%E3%83%B3%E3%83%80%E3%83%BC%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B
【Laravel】Homesteadで「php artisan migrate」が動かない


# TL;DR

- Artisanコマンドを実行している場所を確認しましょうというお話

# `php artisan migrate`でエラーが発生

テーブル作ろうと思い、`php artisan migrate`コマンドを叩くと以下のエラーが発生

```
$ php artisan migrate

In Connection.php line 664:


   (SQL: select * from information_schema.tables where table_schema = homestead and table_name = migrations)


In Connector.php line 67:
```

調べても何も出てこない

# 解決方法

- まずもって**Homestead内でコマンドを実行していなかった**

ただひたすら**プロジェクトのディレクトリ内でコマンドを叩いていただけ**でした。
`vagrant ssh`で中に入った後、artisanファイルがある場所でArtisanコマンドを実行したら普通に実行できました。

```
$ vagrant ssh

～～～～～～～～～～

vagrant@project:~/code$ php artisan migrate
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table
```

# 番外編　DBのポート番号を変更する

`.env`ファイルの`DB_PORT`をデフォルトの「**3306**」から「**33060**」に変更すると、
Homestead外からでもArtisanコマンドを実行することができます。

https://readouble.com/laravel/5.5/ja/homestead.html#ports

> 以下のポートが、Homestead環境へポートフォワードされています。  
SSH: 2222 → フォワード先 22
ngrok UI: 4040 → フォワード先 4040
HTTP: 8000 → フォワード先 80
HTTPS: 44300 → フォワード先 443
MySQL: 33060 → フォワード先 3306
PostgreSQL: 54320 → フォワード先 5432
Mailhog: 8025 → フォワード先 8025



# おわり
- とてもくだらないことで3時間くらい悩んでしまったのでした



# 参考

- [Laravel4のhomesteadでmigrateしようとしたら「SQLSTATE[HY000] [2002] 対象のコンピュータによって拒否されたため、接続できませんでした。」でハマった件 - 終電23時15分って早くね？](http://blue-goheimochi.hatenablog.com/?page=1413683320)
Android端末の最新Chrome 67でストリーミング配信動画が閲覧できないときに確認すること

Androidスマホで Chromeブラウザを2018/06/20現在の最新バージョン（67.0.3396.87） にアップデートすると、videojsのプレイヤーで動画を再生するときに下記のようなエラーが出力されるようになる場合があります。

>The media playback was aborted due to a corruption problem or because the media used features your browser did not support."

そんなときは、Chromeの設定より、「キャッシュされた画像とファイル」のデータを削除することでこれまで通りに動画を再生できるようになります。

　設定 ▶ プライバシー ▶ 閲覧履歴データを消去する 

と辿っていくとよいです。

もしかしたら、キャッシュクリア後にスマホを再起動も必要かもしれません。
Qiita投稿で画像アップロードがエラーになる

Qiitaに投稿するとき、画像をアップロードすると

```
![Payload Too Large]()
```

ってなる。。
なんか初回は月間2MBまでしか画像アップできないみたい。
投稿すると100MBまでふえるみたい。

実はこの記事自体が画像アップロードさせるための投稿です。。。
実際エラーがなくなりました:clap:
Neo4jをCentOSにインストールする


# はじめに
最近仕事でよくグラフデータベースの話が出てくる。RDBはともかくのことMongoやElasticsearchくらいしか触ってなくて「グラフデータベースってなんだろ」と思い触ってみることにしました。インストール自体は簡単でしたがメモしておきます。

# 環境
CentOS7　（Vagrant）
Neo4j 3.4.1 (当時)

# 手順
手順は以下です

## 前準備
JDKを入れておきます.とりあえずあれば動くとのことっぽいので適当に入れておきます

```bash:
yum install java-1.8.0-openjdk
```

## Neo4j のインストール
メディアを落としていれるのが定番ぽかったですが今回はyum を使って入れます。
ここらへんを参考にしました
　[How to List and Install Neo4j Versions using yum](https://neo4j.com/developer/kb/how-to-list-and-install-neo4j-versions-using-yum/)
レファレンスは[ここ](http://yum.neo4j.org/)を参照

```bash:
# Key の取得
cd /tmp
wget http://debian.neo4j.org/neotechnology.gpg.key
rpm --import neotechnology.gpg.key

# リポジトリ追加
cat <<EOF>  /etc/yum.repos.d/neo4j.repo
[neo4j]
name=Neo4j Yum Repo
baseurl=http://yum.neo4j.org/stable
enabled=1
gpgcheck=1
EOF

# インストール
yum install neo4j
```

無事に入ったらバージョンを確認しておきます

```bash:
[vagrant@neo ~]$ neo4j --version
OpenJDK 64-Bit Server VM warning: If the number of processors is expected to increase from one, then you should configure the number of parallel GC threads appropriately using -XX:ParallelGCThreads=N
neo4j 3.4.1

```


## Neo4j の設定
ここの設定で少しはまった

### limits.conf の編集
一度起動させてみる
```bash:
sudo neo4j start
```

すると下記のようなエラーが出る

```bash:
WARNING: Max 1024 open files allowed, minimum of 40 000 recommended. See the Neo4j manual.
```

開けるファイル数のリミットを増やせてきな警告が出るので設定を編集

```bash:/etc/security/limits.conf
neo4j   soft    nofile  40000
neo4j   hard    nofile  40000
root    soft    nofile  40000
root    hard    nofile  40000
```

### 起動の方法の変更
もう一度、さっきの neo4j start でエラーっぽいのが出る

```bash:
[vagrant@neo bin]$ sudo neo4j start
Active database: graph.db
Directories in use:
  home:         /var/lib/neo4j
  config:       /etc/neo4j
  logs:         /var/log/neo4j
  plugins:      /var/lib/neo4j/plugins
  import:       /var/lib/neo4j/import
  data:         /var/lib/neo4j/data
  certificates: /var/lib/neo4j/certificates
  run:          /var/run/neo4j
Starting Neo4j.
/usr/share/neo4j/bin/neo4j: line 418: /var/run/neo4j/neo4j.pid: No such file or directory
```

また調べてみると、neo4j コマンドからではなくservce か systemctl で立ち上げろ、とのこと
参考 : [Neo4j Start Error](https://stackoverflow.com/questions/44988218/neo4j-start-error-var-run-neo4j-neo4j-pid-no-such-file-or-directory)

### リモートアクセスの許可
ここが一番ハマった。本来であればここまでやって http://localhost:7474 でコンソールでつながるのだが、リモート接続する場合はNeo4jの設定を変更するようです

ということで設定ファイルであるneo4j.confファイルの設定を変更します

```bash:/etc/neo4j/neo4j.conf
## １か所め
# HTTP Connector. There must be exactly one HTTP connector.
dbms.connector.http.enabled=true
dbms.connector.http.listen_address=XXX.XXX.XXX.XXX:7474 ##サーバーのIP

## ２か所め
# Bolt connector
dbms.connector.bolt.listen_address=0.0.0.0:7687
```

参考 [公式](https://neo4j.com/developer/kb/how-do-i-enable-remote-https-access-with-neo4j-30x/)

### Neo4jの再起動
ここで起動している場合は再起動します。もちろんservice やsystemctl からやります

## 接続確認
ここでもう一度 http://{IP Adress}:7474 でアクセスします

![image.png](https://qiita-image-store.s3.amazonaws.com/0/95824/f401d5f7-df85-f4d3-f8b0-03008a166a08.png)

やった！！！これでコンソールに繋がりました

# おわりに
やっとこれから触ることができます。もうちょっと日本語のドキュメントが増えてるとおもったのにあんまりなくて残念です。
<C#>標準入力について

最近、C#に入門しましたが、練習問題で標準入力に躓くことがあったので、メモします。

半角空白（スペース）区切りの標準入力を普通にJavaの感覚で取ろうとすると、エラーが出たので調べたところ、ちょっと違ってたみたい。


・入力値：「12　5」


```csharp
    public static void Main(){

        var a = 0;
        var b = 0;
        
        string[] str = Console.ReadLine().Split(' '); //ここで半角スペース区切りで取る
        a = int.Parse(str[0]);
        b = int.Parse(str[1]);
        
        Console.WriteLine(a + ":" + b);
    }
```

⇒　出力結果：「12：5」


これからどんどん使うかもしれないので、覚える。
SQLServer ストアドプロシージャ　ANSI_NULLをONにしなければならない理由

ストアドプロシージャを変更するに当たり
ANSI_NULLをON
QUOTED_IDENTIFIER OFF
と宣言しなければならない理由には何かわけがあるのでしょうか？

加えてGoにはメモリ解放というイメージがありますが
一つの宣言ごとにGOされてる理由についても知りたいです。

USE [hogehogedb_10]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GO
ALTER PROCEDURE [dbo].[hoge_list] 

SELECT ~~~
Gmailに来るConnpass通知をいい感じにSlackに通知する

# はじめに
Connpassの通知、いい加減メール以外にも対応してほしい...。
Slackとまでは言わないからせめてLINEも選択肢としてとれるようにしてほしい...

そんな欲求、ありますよね？

はい、例によって例のごとくGASで作りました。

このスクリプトでは、
こんな感じのボタンが含まれているメールを
<img width="499" alt="スクリーンショット 2018-06-20 15.53.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/76726/f8525a1b-43a1-1502-7d4f-b7e1a0bcbf1c.png">

こんな感じでSlackに通知します。
<img width="637" alt="スクリーンショット 2018-06-20 15.52.11.png" src="https://qiita-image-store.s3.amazonaws.com/0/76726/c327a167-03f8-e954-520e-4aca069e1313.png">

逆に言うと例のボタンが含まれてないやつは対象外になるので注意してください。
(そんなのは嫌だ！って人はスクリプトをいじってください)

# Gmailの設定をしよう
といってもやることは２つだけ

- connpassのラベルを作る
- フィルタ機能でconnpassから来たメールは受信トレイをスキップしてconnpassのラベルつけて既読にする

フィルタ具体的な設定は↓のような感じ

<img width="588" alt="スクリーンショット 2018-06-20 15.20.42.png" src="https://qiita-image-store.s3.amazonaws.com/0/76726/bc1274a0-4153-dcb0-5c42-1deb3f5651a3.png">

<img width="585" alt="スクリーンショット 2018-06-20 15.21.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/76726/19344af2-b6c1-3f25-e665-d74260c7c5ab.png">

これでGmail側は準備完了

# SlackのIncoming Webhooks設定をする
「Slack Incoming Webhook」でググれば情報出て来るので詳細は割愛。
ここで通知したいチャンネル、BOTの名前、アイコンを適当に設定する。
ちなみにアイコンは公式がAPIの一部として公開してるので使うといいかも。
https://connpass.com/about/api/

発行されたWebhookのURLはあとで使うのでコピーしておくなり、タブを開いておくなりする。

# GASを使って定期チェックのスクリプトを作る

## GoogleDriveにGASプロジェクトを作る
そのまんま。名前は任意に。
次にここにスクリプトがあるので`main.gs`をコピーして貼り付ける
https://github.com/kiuchikeisuke/ConnpassNotifier

### Constの定義を書く
データ格納用のスプレッドシートを１つ作る。シート名を`data`にする
スプレッドシートのURLのId(↓のXXXの部分)をコピーして、`Const`の`spreadSheetId`にセットする
`https://docs.google.com/spreadsheets/d/XXXXXXXXXXXXXXXXXX/edit#gid=0`


Incoming Webhookで発行したurlを`Const`の`webhookurl`に貼り付ける

## スクリプトの定期実行を設定する
「GAS　定期実行」でググれば出て来るので詳細は割愛。
定期実行に指定する関数は`timer()`。だいたい1時間おきくらいでいいかも。

# 技術的なお話
と言ってもGmailのアクセスはGASがデフォルトでできてしまうので、ほぼソースを読めば（多分）わかるレベル。
ボタンの部分を判定してる処理はメールのBodyから正規表現で該当するテキスト部分を抽出してる感じ。具体的には以下の部分

```javascript
      var messages = thread.getMessages();
      var message = messages[0];
      var subject = message.getSubject();
      var body = message.getBody();
     
      var url = body.match(/<a href="https:\/\/.+\.connpass\.com\/event\/.+\/.+utm_content=detail_btn"/);
      if(url != null) {
        url = url[0].substring('<a href="'.length, url[0].lastIndexOf('/') + 1);
         
        var msg = "*" + subject + "* \n" + url;
        postToSlack(msg);
      }

```

また、全部のメールを判定対象にすると重くなることが予想されたので、**前回チェックから今回チェックの間に受信したメール20件**を対象にしている。

# 終わりに
全て設定が終われば、イベントが発生するとこんな感じで通知が来る。

<img width="637" alt="スクリーンショット 2018-06-20 15.52.11.png" src="https://qiita-image-store.s3.amazonaws.com/0/76726/c327a167-03f8-e954-520e-4aca069e1313.png">
CentOS 7 cmake 3.11.4のソースファイルからのインストール

# 動作確認環境
事情によりバージョンをダウングレードしました。新しいバージョンでも動作するはずです。

- 仮想環境 VMware Workstation Player 12.5.9
- OS Windows 10 Pro 64bit

# 仮想環境
- OS CentOS 7.4 (1708) minimalインストール
- メモリ 2GB
- HDD 250GB

# ダウンロード・展開
最新バージョンの確認
[Download | CMake](https://cmake.org/download/)

`/usr/local/src`ディレクトリに移動する。

````
cd /usr/local/src
````
ソースファイルをダウンロードする。

````
wget https://cmake.org/files/v3.11/cmake-3.11.4.tar.gz
````

ダウンロードしたファイルを展開する。

````
tar zxvf cmake-3.11.4.tar.gz
````
# コンパイル・インストール
展開したディレクトリに移動する。

````
cd cmake-3.11.4
````

コンパイル・インストール

````
./bootstrap --prefix=/opt/cmake --no-system-libs
make
make install
````
./bootstrapが成功すると最後に以下のような表示をする。

````
---------------------------------------------
CMake has bootstrapped.  Now run gmake.
````

# エラー対策
`./bootstrap`で`lib64`関連のエラーが発生した場合、共有ライブラリへの対策。
エラー内容。

````
/usr/local/src/cmake-3.11.1/Bootstrap.cmk/cmake: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by /usr/local/src/cmake-3.11.1/Bootstrap.cmk/cmake)
/usr/local/src/cmake-3.11.1/Bootstrap.cmk/cmake: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by /usr/local/src/cmake-3.11.1/Bootstrap.cmk/cmake)
---------------------------------------------
Error when bootstrapping CMake:
Problem while running initial CMake
---------------------------------------------
````

`/etc/ld.so.conf`の編集

````
vi /etc/ld.so.conf
````
`/usr/local/lib64/`を追加し、更新コマンド`ldconfig`を実行する。

````
/usr/local/lib64/
````

この時点で`ldconfig`するとエラーが表示される。

````
ldconfig: /usr/local/lib64/libstdc++.so.6.0.25-gdb.py は ELF ファイルではありま せん - 先頭に誤ったマジックバイトを持っています。
````

対策を行う。（参照しないようにする）

````
mv /usr/local/lib64/libstdc++.so.6.0.25-gdb.py /usr/local/lib64/back.libstdc++.so.6.0.25-gdb.py
````

以上で`./bootstrap`が実行できる。

# 環境変数 PATH の設定
インストールしただけではcmakeが実行できないので、`/etc/bashrc`環境変数を設定する。

````
vi /etc/bashrc
````

`PATH=$PATH:/opt/cmake/bin`を追加し、コマンドを実行する。

````
PATH=$PATH:/opt/cmake/bin
source /etc/bashrc
````
# バージョン確認

````
cmake -version
````
以下のような内容が、表示される。

````
cmake version 3.11.4

CMake suite maintained and supported by Kitware (kitware.com/cmake).
````
# 参考
[MySQLのビルドに欠かせないCMakeを準備する：仕事で使える魔法のLAMP（45） - ＠IT](http://www.atmarkit.co.jp/ait/articles/1203/02/news117.html)
[CMakeインストールメモ(Hishidama's CMake install Memo)](http://www.ne.jp/asahi/hishidama/home/tech/cmake/install.html)
(

---
[目次](https://qiita.com/knutpb1205/items/3ece0cab588afdb13f02)
RubyのSequelライブラリを使ってjoin,where,update

Sequelは、[jeremyevansさんが開発したRubyのライブラリ（gem)です](https://github.com/jeremyevans/sequel)

```hoge.rb
DB[:table1].join_table(:inner, :table2, table1_id: :table2_id)
           .where(Sequel[:table1][:table1_id] >= 10000)
           .update(status: 1)
```
とか、（require 'sequel'）はやっといてね。

sequelを使ってwhere句内で比較とかの記事が薄めだったのでメモ代わりに残しておきます。

.join_tableの引数はこんな感じ↓
join_table(type, table, expr = nil, options = OPTS, &block)
参考（https://www.rubydoc.info/github/jeremyevans/sequel/Sequel%2FDataset:join_table）

外部キーにもなっているキーで比較しようとすると、
Mysql2::Error: Column 'tweet_id' in where clause is ambiguous
みたいに、どっちのテーブルのidやねん！って怒られるので、Sequel使ってテーブルから指定してあげましょう。


ちなむと、
ハッシュ値で比較する場合は、

```hash_compare.rb
.where(:id => 3,
       :id_source => 1..8)
```
とかで比較すればいいんですけど、これだと◯◯以上とかの比較ができない。
1..8　 で１以上８以下
1...8　で１以上８未満

　>とか<=とか使いたい場合はSequelを用いましょう。

【メモ】
.update_sqlで実際の発行sql文見れるので、デバックに便利です。
Laradock の使い方

LaraDock の簡単な使い方です。

1) プロジェクトの作成
>空のフォルダーで作業を始めて下さい。

```bash
composer create-project laravel/laravel project_1
```

2) 書き込み権限をつける

```bash
chmod -R 0777 project_1/storage
```

3) Laradock のクローン

```bash
git clone https://github.com/Laradock/laradock.git
```

>フォルダーの構成

```text
$ tree -L 1
.
├── laradock
└── project_1
```

4) .env を作成する

```bash
cd laradock
cp env-example .env
```

.env は、次の２ヶ所を修正します。

```text
APP_CODE_PATH_HOST=../project_1
NGINX_HOST_HTTP_PORT=8888
```

5) サーバーの起動
>laradock フォルダーで起動します。

```bash
sudo docker-compose up -d nginx
```

6) ブラウザーで http://localhost:8888/ にアクセス
![laradock_jun2001.png](https://qiita-image-store.s3.amazonaws.com/0/179446/69996e58-bf2f-d129-8361-76d9b234d725.png)

7) ログインするには、

一般ユーザー

```bash
sudo docker-compose exec --user=laradock workspace bash
```

ルート

```bash
sudo docker-compose exec workspace bash
```

8) サーバーの操作
停止

>```bash
sudo docker-compose stop
```

>```text
$ sudo docker-compose stop
Stopping laradock_nginx_1     ... done
Stopping laradock_php-fpm_1   ... done
Stopping laradock_workspace_1 ... done
```

状態のモニター

>```bash
sudo docker-compose ps
```

再スタート

>```bash
sudo docker-compose restart
```

削除

>```bash
sudo docker-compose rm
```
PHPとRuby間のソケット通信

PHPプログラムとRubyプログラム間でソケット疎通しデータを受け渡す作業がありましたのでメモ。____〆(._.)
※基本動作のみ行うシンプルなコードになっています。ruby 1.8.7、PHP 5.4.29です。

★PHP側（ソケット通信でRubyにデータを送信）

```PHP:send.php
<?php
	$socket = null;
	//ソケット生成。localhostに40001番ポートで接続。タイムアウトは5秒とする。
	$socket = fsockopen("localhost",40001,$errno, $errstr,5);

	//ソケット接続結果
	if(!$socket){
		echo("ソケット接続失敗\n");
	}else{
		echo("ソケット接続成功\n");
	}

	//メッセージ送信
	$fwrite = fwrite($socket, "Hello, World!");

	//ソケット書き込み結果
	if(!$fwrite){
		echo("ソケット書き込み失敗\n");
	}else{
		echo("ソケット書き込み成功\n");
	}
	//ソケットクローズ
	fclose($socket);
?>

```

★Ruby側（ソケット通信でデータを受信）

```Ruby:receive.rb
#!/usr/bin/ruby -Ku
# encoding: utf-8

require 'socket'

begin
	# TCPサーバOPEN。PHPと疎通。
	socket=TCPServer.open("localhost",40001)
	print "TCPサーバ起動\n"
rescue => e
	# エラー処理
	print "TCPサーバ起動エラー\n"
else
	@socks=[socket]
	#ソケットの書き込みを常時待ち受ける
	while true
		sleep 1

		# 入力待ちSocket収集
		read_sock = select(@socks, nil, nil, 0.1)

		# 読み取り可能なソケットはあるか？
		unless read_sock == nil
			read_sock[0].each{|rs|
				# 新規接続か？
				if rs == socket then
					cs=rs.accept
					#接続を許可し、そのオブジェクトをソケット配列に入れる
					@socks.push(cs)
					# 接続情報出力
					print "接続しました " + cs.peeraddr[3].to_s + "[" + cs.peeraddr[1].to_s + "]\n"
				else
					#メッセージ受け取り実行
					msg=rs.recv(8192)
					#何も受信してるものがなければソケット情報配列からacceptしたソケット情報を削除し、ソケットをクローズ
					if msg.empty? then
						@socks.delete(rs)
						rs.close
					else
						print "受信メッセージ： " + msg + "\n"

						#受信したらソケットをクローズ
						@socks.delete(rs)
						rs.close
					end
				end
			}
		end

	end
end

```
receive.rbを起動し、TCPサーバをOPENした状態にしてからPHPを実行してみます。

★PHP側の標準出力
![PHP.PNG](https://qiita-image-store.s3.amazonaws.com/0/78305/a26a7608-fdb9-3df1-5b89-b220c214705b.png)

★Ruby側の標準出力
![RUBY.PNG](https://qiita-image-store.s3.amazonaws.com/0/78305/e326ae31-e9db-1a0e-759f-464386d735ae.png)

ちなみにreceive.rbを起動していないとソケット接続の確立ができないのでPHP側の結果は以下のようになります。
![PHP2.PNG](https://qiita-image-store.s3.amazonaws.com/0/78305/61a1de8d-1e5c-c17e-882a-e8393b5bdea0.png)

まぁ、そのまんまなんですが・・・。（・ω・）

初めての方でもコピペで実装できちゃうくらいシンプルにまとめてみました。（・o・）
Azure Web Apps (Windows, Linux, Container) の分類

#はじめに
　現在 Azure Web Apps は、下記に示す３種類の WEB サービスを提供しています。この内 [Web App on Linux](https://azure.microsoft.com/ja-jp/services/app-service/web/) と [Web App for Container](https://azure.microsoft.com/ja-jp/services/app-service/containers/) については、いずれも Linux OS ベースの Docker イメージとして動作しています。[Web App on Windows](https://azure.microsoft.com/ja-jp/services/app-service/web/) は最も歴史の長い Web App サービスでもあり、Windows/IIS ベースのホスト基盤上で動作しています。

- Web App on Windows
- Web App on Linux
- Web App for Container

![image.png](https://qiita-image-store.s3.amazonaws.com/0/166732/c8879a01-c90b-69ef-4f6f-f649c76f54f0.png)
#利用者視点での分類
　Web App on Windows と Web App on Linux は、OS, WEB サーバーといったアプリケーションの実行基盤は異なりますが、その部分は PaaS サービスとして隠蔽化されているため、サイト管理者（サービス利用者）は、どちらの Web App も同じような使用感で利用出来ます。例えば、どちらのサービスも GitHub や Bitbucket からコンテンツデプロイを実行したり、ポータルから Java, PHP, Python といった組み込みランタイムのバージョン管理を同じ操作感で行えます。

#アーキテクチャ視点の分類
　他方アーキテクチャ的な観点から見ると、冒頭で触れたように Web App on Linux と Web App for Container はどちらも同じコンテナ技術を利用しています。Web App on Linux は組み込みランタイム毎に[マイクロソフト側でベースとなる Docker イメージ](https://hub.docker.com/u/appsvc/)を用意しており、それが裏でデプロイされています。このためランタイムのバージョンを変えると 下記の通り Docker イメージが再デプロイされる事となります。

#####SSH コンソールで Web App on Linux のディストリビューションとランタイムを確認

- PHP 7.0 を選択した場合、Debian Linux 8
![image.png](https://qiita-image-store.s3.amazonaws.com/0/166732/1b588e1c-c648-81a1-5c75-07331883289f.png)
- PHP 7.2 を選択した場合、Debian Linux 9
![image.png](https://qiita-image-store.s3.amazonaws.com/0/166732/1dc9e65e-077a-362e-a3b4-6ec2800db748.png)
- Tomacat 9.0 (JRE 8) を選択した場合、Alpine Linux 3.7
![image.png](https://qiita-image-store.s3.amazonaws.com/0/166732/057211cc-4475-4f2c-cf48-f9a59abd5b76.png)

　簡潔に述べると上記のような [Web App on Linux の組み込みランタイム一覧](https://docs.microsoft.com/ja-jp/azure/app-service/containers/app-service-linux-intro)にない WEB サーバー環境 (Linux) を作るときには、Web App for Container でカスタムの Docker イメージを利用する必要が出てきます。
react native "this.setState is not a function"

# react native で"this.setState is not a function"と怒られる

APIのレスポンスを扱おうとした時にコールバック関数内でthis.setStateを使おうとしたらthis.setState is not a functionとエラーがでた。

ググると
https://stackoverflow.com/questions/31045716/react-this-setstate-is-not-a-function/31045750#31045750

こちらにたどり着いた。

どうやらcallback関数内のthisはグローバルのwindowオブジェクトを示してしまうらしいのでes6 のbind(this)をcallback関数につけることで本来参照したいthisを参照できる様になるらしい。
CSSでメニュー右上に矢印をつける方法メモ

<img width="375" alt="スクリーンショット 2018-06-20 15.00.39.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/265255/cdc7ab6a-60b8-5b18-0d9c-e834a5589f7a.jpeg">

↑こういうのを作りたい時


#① pのプロパティにbackground: urlを入れる
擬似要素っぽく扱うけどcontentがなくても使える

```css

    p{
        padding: 12px 20px 14px;
        height: 46px;
        color: #fff;
        font-size: 14px;
        background: url("../images/ico_arrow_head.gif") no-repeat 97% 50% #0099cc;
        background-size: 14px 8px;
    }
```

#② ::afterを利用する
widthとheightで画像の大きさを決めて、background-size: coutain;でぴったりサイズの矢印を表示させる。topとrightで位置を決める。

```css
        .header_bar{
            position: relative;
        }

        p{
            padding: 12px 20px 14px;
            height: 46px;
            color: #fff;
            font-size: 14px;
            background-color: #0099cc;
        }

        p::after{
            position: absolute;
            width: 14px;
            height: 8px;
            top: 44%;
            right: 15px;
            background-image: url('../images/ico_arrow_head.gif');
            background-size: contain;
            content: '';
        }
```

#③ imgタグを使う
imgタグにclass="arrow"をつけて矢印を出す。この場合はwidthのみ、heightは必要ない。②と同様にtopとrightで位置を決める。

```css

        .header_bar{
            position: relative;
        }

        .arrow{
            position: absolute;
            width: 14px;
            top: 18px;
            right: 20px;
        }

        p{
            padding: 12px 20px 14px;
            height: 46px;
            color: #fff;
            font-size: 14px;
            background-color: #0099cc;
        }
```