OmniAICreator/Qiita-1.07M huggingface dataset:
Oculus Go 開発のUnity 設定

備忘録としてOculus 公式のUnity 設定をまとめます。
参照したのはこちら。Oculus Go とGear VR 用のプロジェクト設定が説明されています。

[Building Mobile Applications](https://developer.oculus.com/documentation/unity/latest/concepts/unity-build-android/) (Oculus 公式)


Oculus Go 開発の最低限の設定は以下に分かりやすくまとまっています。この記事は+α の設定となります。

[Windows上のUnityでOculus Goアプリ開発するまでの最短手順](https://qiita.com/TyounanMOTI/items/fc11cb0c15f62ec88817)


## 環境
* Unity 2017.4.4f1
* Oculus Integration 1.25

## Build Settings
File > Bulid Settings

* Texture Compression をASTCに設定する

![03-build-settings.png](https://qiita-image-store.s3.amazonaws.com/0/241491/7c9eb5ab-01ed-c742-28d1-bddc20e68d0d.png)

パフォーマンスへの影響が大なので、最終的なビルドではDevelopment Build はチェックを外しましょう。


## Player Settings
Edit > Project Settings > Player

* Multithreaded Rendering にチェックを入れる

![03-player-settings.png](https://qiita-image-store.s3.amazonaws.com/0/241491/e7015321-bbf0-6190-cb05-6070ad08ae4e.png)


## Quality Settings
Edit > Project Settings > Quality

項目が多いので表にします。


|項目 | 設定 |
|:----|:----|
|Pixel Light Count |1 |
|Texture Quality |Full Res |
|Anisotropic Textures |Per Texture |
|Anti Aliasing |2x 余裕があれば 4x Multi Sampling (8xは非推奨) |
|Soft Particles |チェックを外す |
|Realtime Reflections Probes |チェックを入れる |
|Billboards Face Camera Position |チェックを入れる |

![03-quality-settings.png](https://qiita-image-store.s3.amazonaws.com/0/241491/5eefa509-d4e4-2d59-6d5b-84b06bad8dee.png)


## まとめ

Oculus 公式の推奨設定をまとめてみました。
【Java】LocalDateを使って年齢を計算する方法

java.time.LocalDateを使って誕生日から現在の年齢を計算する方法。

```java:BirthdayService.java

public int getAge(int year, int month, int day) {

    // 計算対象の誕生日
    LocalDate birthday = LocalDate.of(year, month, day);

    // 現在の年月日
    LocalDate today = LocalDate.now();

    long duration = ChronoUnit.YEARS.between(birthday, today);

    return (int)duration;
}
```

[LocalDate (Java Platform SE 8)](https://docs.oracle.com/javase/jp/8/docs/api/java/time/LocalDate.html)
tarコマンドでの並列圧縮onSSD

##概要
###趣旨
tarで並列圧縮ができるというので、SSDでの効果を試してみる。
tarでシングル圧縮では遅くて使いものにならない。
並列圧縮にはpigzを使う。

###環境
Virtualbox上のRACDB環境を流用。DB#1をNFSクライアント、DB#2をNFSサーバとし、DB#1からDB#2のACFS上にtarで圧縮ファイルを作成。
仮想DISKは全て同一のSSD上に配置しているので競合する。
DB#1を8vCPUに設定。

##設定
###pigzパッケージダウンロード
ゲストはInternetに接続していないので、PCにダウンロードしてからrpmでインストールする。
Oracle Linux7だと[yum server](http://yum.oracle.com/oracle-linux-7.html)のEPELフォルダにあるが、Oracle Linux6にはないので下記から落とす。大抵のLinuxで動くらしい。すばらしい。
https://dl.fedoraproject.org/pub/epel/6/x86_64/Packages/p/pigz-2.3.4-1.el6.x86_64.rpm

###インストール
```shell-session
# rpm -ivh pigz-2.3.4-1.el6.x86_64.rpm
警告: pigz-2.3.4-1.el6.x86_64.rpm: ヘッダ V3 RSA/SHA256 Signature, key ID 0608b895: NOKEY
準備中...                ########################################### [100%]
   1:pigz                   ########################################### [100%]
# which pigz
/usr/bin/pigz
```

###DB#2(NFSサーバ)設定
```shell
# cat /etc/exports
/u01/app/oracle/fast_recovery_area/datastore/bkup *(rw,no_root_squash)
# /usr/sbin/exportfs -r
# chkconfig nfs on
# service nfs start
# showmount -e
Export list for odax6ha2.vbox.localdomain:
/u01/app/oracle/fast_recovery_area/datastore/bkup *
```

###DB#1(NFSクライアント)設定
omkdir /bkup
mount -t nfs odax6ha2:/u01/app/oracle/fast_recovery_area/datastore/bkup /bkup

###スクリプト作成
```shell
# cat bkup.sh
echo 1 > /proc/sys/vm/drop_caches
date
tar cvf /bkup/bkup.tar /usr > /bkup/bkup.tar.log 2>&1
date
echo 1 > /proc/sys/vm/drop_caches
date
tar cvf /bkup/bkup.tgz --use-compress-prog=pigz /usr > /bkup/bkup.tgz.log 2>&1
date
ls -l /bkup
```

##計測

###キャッシュクリア
```shell
# sh bkup.sh
2018年  5月 15日 火曜日 14:19:13 JST
2018年  5月 15日 火曜日 14:20:21 JST
2018年  5月 15日 火曜日 14:20:21 JST
2018年  5月 15日 火曜日 14:21:20 JST
合計 2454236
-rw-r--r-- 1 root root 1805312000  5月 15 14:20 2018 bkup.tar
-rw-r--r-- 1 root root    5358099  5月 15 14:20 2018 bkup.tar.log
-rw-r--r-- 1 root root  693236067  5月 15 14:21 2018 bkup.tgz
-rw-r--r-- 1 root root    5358099  5月 15 14:21 2018 bkup.tgz.log
```
圧縮した方が若干高速。圧縮の方がCPUを使っているがIO量の差か。

###キャッシュクリアをコメント化
```shell
sh bkup.sh
2018年  5月 15日 火曜日 14:27:00 JST
2018年  5月 15日 火曜日 14:27:19 JST
2018年  5月 15日 火曜日 14:27:19 JST
2018年  5月 15日 火曜日 14:27:46 JST
合計 2459560
-rw-r--r-- 1 root root 1805312000  5月 15 14:27 2018 bkup.tar
-rw-r--r-- 1 root root    5358099  5月 15 14:27 2018 bkup.tar.log
-rw-r--r-- 1 root root  693236067  5月 15 14:27 2018 bkup.tgz
-rw-r--r-- 1 root root    5358099  5月 15 14:27 2018 bkup.tgz.log
```
キャッシュクリアに比較して1/3程度になっていることから、読込の負荷が高い。
逆に圧縮しない方が高速。読込量が減少した分IOが高速となり、圧縮負荷割合が高くなった。
現実的には事前に全体がキャッシュされている場合はまれなので、

###結論
+ SSD利用時はIOが高速な分、圧縮による時間的メリットは少ない。
+ 時間より、DISK容量を節約したい場合に利用。
FlutterでWebViewを表示する

# 概要

FlutterでWebViewを利用してWebサイトを表示する方法を調べたのでメモ。

# インストール

[flutter_webview_plugin](https://pub.dartlang.org/packages/flutter_webview_plugin#-readme-tab-)を使用する。バージョンは`0.1.6`。

pubspec.yamlに以下を追加

```yaml

dependencies:
  flutter_webview_plugin: "^0.1.6"
```

コマンドラインで以下を実行しpackageをインストール

```bash

$ flutter packages get
```

Dartコードからは以下のようにimportして使用する

```dart

import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
```

# 実装

以下のコードでWebViewを表示する。

```dart

import 'package:flutter/material.dart';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
 
void main() => runApp(new MyApp());
 
class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(routes: {
      "/": (_) => new WebviewScaffold(
            url: "https://www.google.com",
            appBar: new AppBar(
              title: new Text("Widget webview"),
            ), // AppBar
          ) // WebviewScaffold
    }); // MaterialApp
  }
}
```

# 実行

iOS、Android共表示できた。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/43438/9489bce9-2dd5-4ac3-bfb5-68c5b0adca4f.png)
rex0220 ルックアップコピー項目編集プラスプラグイン

[rex0220 ルックアップコピー項目編集プラグイン（無償版）](https://qiita.com/rex0220/items/7fd6279c04346952221f)の機能拡張・有償版です。

- ルックアップコピー項目を編集可能にする
- PC、スマホ対応
- 項目数の多いアプリ対応（プラグイン設定時のデータ容量オーバー対応）

※ Ver.7
・プラグイン設定画面のデザイン変更対応
・プラグイン設定に、「説明」設定機能を追加

[rex0220 stores](https://rex0220.stores.jp)で、販売中です。


# プラグイン設定前後の編集画面

ルックアップコピー項目が編集可能になります。

<img width="1467" alt="2018-06-19_15h11_37.png" src="https://qiita-image-store.s3.amazonaws.com/0/100572/3898bd17-fc93-0c30-7495-b36c40d2e1a2.png">

# スマホ編集画面例


<img width="282" alt="2018-06-19_15h21_25.png" src="https://qiita-image-store.s3.amazonaws.com/0/100572/d95077e4-987d-0cc5-e019-0fed3eb78927.png">



# プラグインの追加

- 「kintone システム管理 > プラグイン」で追加します。
- 「アプリの設定 > プラグイン」で、アプリに追加します。

<img width="1274" alt="2018-06-19_15h28_52.png" src="https://qiita-image-store.s3.amazonaws.com/0/100572/4df5283e-3021-843f-51a0-772c823718b7.png">


# プラグインの設定

編集可能にする項目をチェックして、「保存する」をクリックします。


<img width="832" alt="2018-06-19_15h31_21.png" src="https://qiita-image-store.s3.amazonaws.com/0/100572/1d5e0518-dcad-f5dc-f27c-7b6a2d60ce84.png">


# プラグイン設定のダウンロード

- プラグイン設定をダウンロードできます。
- 設定内容を変更している場合は、変更後の設定が対象です。
- ブラウザ IE については、プラグイン設定のダウンロードの動作対象外です。

<img width="842" alt="2018-06-19_15h32_18.png" src="https://qiita-image-store.s3.amazonaws.com/0/100572/ffd494d5-5a85-c1f3-e33d-5742059ef5e7.png">


# プラグイン設定のアップロード

- プラグイン設定をアップロードできます。
- フィールドコードをキーにして、設定ファイルから設定します。
- ブラウザ IE については、プラグイン設定のアップロードの動作対象外です。


<img width="836" alt="2018-06-19_15h34_21.png" src="https://qiita-image-store.s3.amazonaws.com/0/100572/5db2eea9-c0f6-fd54-85df-41b592542487.png">


- プラグイン設定ファイル情報を確認して、設定します。


<img width="833" alt="2018-06-19_15h35_18.png" src="https://qiita-image-store.s3.amazonaws.com/0/100572/bfa9e2c5-1bf1-15b2-bb1e-aa52f2a262cc.png">



# 注意事項
- 既に、JavaScript によるカスタマイズを行っているアプリの場合、処理が競合して、エラーになる場合があります。その場合は、該当するアプリでプラグインの使用を中止してください。
- [kintoneルックアップコピー項目編集プラグイン](https://qiita.com/rex0220/items/7fd6279c04346952221f)をインストール済みのkintone 環境では、ルックアップコピー項目編集プラスプラグインをインストール後に各アプリでプラグインを再設定してください。
準同型暗号の最前線3（理論編）

# 初めに
この記事は[準同型暗号の最前線1（入門編）](https://qiita.com/herumi/items/d8645efe2cc5be2e7ee3)、[準同型暗号の最前線2（原理編）](https://qiita.com/herumi/items/7d0e4a001ed64364642a)の続きです。
このページでは提案したL2準同型暗号の安全性の根拠の話をします。やや難しめです。

# DDH仮定
[電子投票](https://qiita.com/herumi/items/d8645efe2cc5be2e7ee3#%E9%9B%BB%E5%AD%90%E6%8A%95%E7%A5%A8)のところで、各自の1票（0か1）を暗号化して集計する話をしました。
もちろん暗号文$Enc(0)$や$Enc(1)$を見て、それが0や1を暗号化したものであると見破られてしまっては困ります。どういう条件が成り立てば見破られないと考えられるでしょうか。

暗号化の方法を復習しながら考えてみましょう。
まず、楕円曲線の点（歯車の一つ）$P$を固定しました。これは皆が知っている公開パラメータです。
次にランダムに整数$s$をとり、$Q=sP$を公開しました（$s$が秘密鍵で$Q$が公開鍵です）。
暗号化は$m$を0か1として、乱数$r$をとり、
$Enc(m) = (mP + rQ, rP)$
としました。

$m = 0$を暗号化したときは$(rsP, rP)$で、$m = 1$を暗号化したときは$(P + rsP, rP)$です。

暗号文から$m$を推測しようとする人は、公開情報$P$, $sP$を知っていて、$(rsP, rP)$か$(P + rsP, rP)$かを見破ろうとするわけです。

つまり$P$, $sP$, $rP$（暗号文の第2成分）が与えられたときに、残り（暗号文の第1成分）が$rsP$か$P + rsP$のどちらの形をしているか区別できたら勝ちとなります。

定式化すると次の問題になります（$r$, $s$を$a$, $b$に置き換えた）：

「$P$, $aP$, $bP$と$cP$が与えられたとき$c=ab$かそうでないかを判定せよ」

もし$c=ab$と判定できたら暗号文が0を暗号化したもの、そうでなければそれ以外と分かります。
この問題をDDH問題（decision Diffie-Hellman）問題、DDH問題が困難なとき「DDH仮定を満たす」という言い方をします。
今回は楕円曲線（Elliptic Curve）の話なのでEC-DDHということもあります。

# DHとDDH
最近のHTTPSでは「ECDHが使われている」ということを聞いたことがあるかもしれません。
ECDHとは楕円曲線のDiffie-Hellman鍵共有を指します。「$P$, $aP$, $bP$が与えられたときに$abP$を求めよ」という問題（DH問題）が難しいことを根拠に鍵交換します。具体的に$abP$を求めるのでCDH（computational DH）ということもあります。

$P$, $aP$, $bP$から$abP$を求められたら、残りの$cP$が$abP$に等しいかはみれば分かるので、DH問題が解ければDDH問題は解けます。
対偶をとると、DDH仮定を満たす（=DDH問題が解けない）なら、DH仮定を満たします（=DH問題が解けない）。

安全性の証明ではDDH仮定の方が使いやすいのでこちらよく使われます。ElGamal暗号はDDH仮定の下で安全である（今安全性の定義をしていないのでなんですが）と証明できます。

# SXDH
今回提案方式のL2準同型暗号では2個の楕円曲線とそのペアリングを使っています。提案方式の安全性証明には、ペアリングに使われる2個の楕円曲線のDDH問題を利用しました。すなわち$P$が一つ目の楕円曲線の点、$Q$が二つ目の楕円曲線の点としたとき、

「$P$, $aP$, $bP$と$cP$が与えられたとき$c=ab$かそうでないか、または
「$Q$, $sQ$, $tQ$と$uQ$が与えられたとき$u=st$かそうでないか判定せよ。」

という問題です。
この問題はSXDH(Symmetric eXternal DH)問題と呼ばれます。この問題が困難であるというSXDH仮定は比較的新しい仮定（2005年～）です。今のところこの問題は難しいだろうと思われています。

なお、「$P$, $aP$, $bP$, $cP$, $Q$, $aQ$, $bQ$, $cQ$が与えられたときに$c=ab$かそうでないかを判定せよ」ではないことに注意してください。
なぜならペアリングの性質から
$e(aP, bQ) = ab e(P, Q)$
$e(P, cQ) = c e(P, Q)$
なので（注意：右辺は加法表記してます）、両者を比較すると$c = ab$かどうかはすぐ判定できてしまうからです。

提案方式はSXDH仮定の下で安全であると示されます。

# 回路プライバシー
最後に、準同型暗号特有の性質である回路プライバシー（circuit privacy）という概念を紹介しましょう。

準同型暗号は、Aが暗号化してBに暗号文を渡し、Bが何か演算をして結果をAに返す使われ方が多いです。
そのとき、AがBに対して平文を秘匿したいだけでなく、BがAに対してどのような計算をしたか秘匿したい場面があります。
たとえばAが暗号文$c_1$, $c_2$, ...を作ってBに渡し、Bが計算して$d$を返したときに、Aが「$d$は$c_5$と$c_{20}$を足したものである」と分かっては困る場合です（もちろん暗号文を復号して自明に分かる場合を除きます）。

すなわち直接作られた暗号文と、暗号文から何か処理をして得られた暗号文の区別ができて欲しくないのです。この性質を回路プライバシーといいます。ある暗号文がどういう回路で計算されたかが隠されているという意味です。

今回提案したL2準同型暗号は一度掛け算すると暗号文の大きさが変わってしまうので掛け算したという情報は隠せないのですが、それ以外の演算の回路プライバシーを満たすようにできます。
実際にはSXDH仮定の下で、$Enc(0)$を足したり$Enc(1)$を掛けたりすると元の暗号文と同じか判別できなくなります。

$c = Enc(x)$に対して$c' := c + Enc(0) = Enc(x + 0) = Enc(x)$を作ると$c$と同じ平文の暗号文だが$c$と$c'$を見て、平文が同じだと判別できないだけでなく$c$から$c'$を作ったかも分からないということです。

# まとめ
従来のElGamal暗号の安全性の根拠となるDDHを紹介しました。
私たちが提案したL2準同型暗号はDDHを2個くっつけたようなSXDH仮定を根拠に安全性を示しています。
また暗号文の計算に使われた計算式の情報を隠す回路プライバシーという概念を紹介しました。
Amazon LinuxでPPP接続時にルーティングを追加する


## 条件

* L2TP/IPsecでVPNに接続している
* PPP(VPN)接続時に自動的にルーティングを追加したい

```
$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.1.5  netmask 255.255.255.0  broadcast 192.168.1.255


lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0


ppp0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST>  mtu 1400
        inet 192.168.30.201  netmask 255.255.255.255  destination 1.0.0.1
        ppp  txqueuelen 3  (Point-to-Point Protocol)

```

## PPP接続時の起動スクリプトを作成する


`/etc/ppp/ip-up`は編集せずに新規で`ip-up.local`を作成する


```
$ sudo vi /etc/ppp/ip-up.local
```

ルーティングを追加するスクリプトを記述する

``` ip-up.local
#!/bin/sh
ip route add [宛先のIPアドレス] via 192.168.30.201 dev ppp0
exit 0
```

実行権限を追加する

```
$ sudo chmod 755 /etc/ppp/ip-up.local
```

PPPを再接続してルーティングが追加されていることを確認する

```
$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.1.1     0.0.0.0         UG    0      0        0 eth0
1.0.0.1         0.0.0.0         255.255.255.255 UH    0      0        0 ppp0
[宛先のIPアドレス]   192.168.30.201  255.255.255.255 UGH   0      0        0 ppp0
192.168.1.0     0.0.0.0         255.255.255.0   U     0      0        0 eth0
```
CircleCIからAWS S3にアップロードする

よくある、静的ファイルをGitHubにpushしてマスターブランチだったらS3にアップロードする動き。
簡単にできるはずなのにやたらハマったのでメモ。

# IAMの準備

S3にアクセスする用の権限を作成します。
ListBucketがないと怒られます。
また、`aws s3 sync`に`--delete`オプションを付ける場合はDeleteObjectも必要です。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:ListBucket",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::your-s3-bucket-name",
                "arn:aws:s3:::your-s3-bucket-name/*"
            ]
        }
    ]
}
```

# config.ymlを作成する

aws-cliがインストール済みのDocker imageを探していたところ、[Innovator Japanさん](https://tech.innovator.jp.net/entry/2018/04/16/105836)が見つかったので利用させてもらいます。
CodeDeploy？　すみませんまだ勉強中なもので…。

```yml:config.yml
version: 2
jobs:
  build:
    working_directory: ~/repo
    environment:
      - AWS_S3_BUCKET_NAME: your-s3-bucket-name
    docker:
      - image: innovatorjapan/awscli:latest
    steps:
      - checkout
      - run:
          name: Deploy to S3 if branch is Master.
          command: |
            if [ "${CIRCLE_BRANCH}" == "master" ]; then
              aws s3 sync ~/repo s3://${AWS_S3_BUCKET_NAME}/ --exact-timestamps --delete
            fi

```

リポジトリのルートに`.circleci`ディレクトリを作成し、その中に`config.yml`を置きます。

# SECRET_KEYはどこに登録するの問題

あとはIAMで作成したSECRET_KEYを設定し、プロジェクトをビルドすれば動きます。
ではこのSECRET_KEYはどこで設定すればいいのか。

「環境変数でええやん」と思い、当初はこうしていました。

```yaml:config.yml
version: 2
jobs:
  build:
    working_directory: ~/repo
    environment:
      - AWS_DEFAULT_REGION: ap-northeast-1
      - AWS_SECRET_ACCESS_KEY: your-secret-access-key
      - AWS_ACCESS_KEY_ID: your-access-key-id
      - AWS_S3_BUCKET_NAME: your-s3-bucket-name
    docker:
      - image: innovatorjapan/awscli:latest
    steps:
      - checkout
      - run:
          name: Deploy to S3 if branch is Master.
          command: |
            if [ "${CIRCLE_BRANCH}" == "master" ]; then
              aws s3 sync ~/repo s3://${AWS_S3_BUCKET_NAME}/ --exact-timestamps --delete
            fi
```

結果はこう。

```text
#!/bin/sh -eo pipefail
if [ "${CIRCLE_BRANCH}" == "master" ]; then
  aws s3 sync ~/repo s3://${AWS_S3_BUCKET_NAME}/ --exact-timestamps --delete
fi
fatal error: An error occurred (AuthorizationHeaderMalformed) when calling the ListObjects operation: The authorization header is malformed; the Credential is mal-formed; expecting "<YOUR-AKID>/YYYYMMDD/REGION/SERVICE/aws4_request".
Exited with code 1
```

色々探したところ、[プロジェクトのEnvironment Variablesに設定しろ](https://discuss.circleci.com/t/aws-credentials-in-machine-executor/10058/8)という書き込みを見つけたのでその通りにしたところ、結果は全く同じ。

仕方ないのでプロジェクトのAWS Permissionsに設定したところ、バッチリ動きました。
<img width="1045" alt="スクリーンショット 2018-06-19 15.08.42.png" src="https://qiita-image-store.s3.amazonaws.com/0/221538/0719ca56-3895-422b-6d3b-5cda78ca64e4.png">


画面上に燦然と輝く**「2018年8月31日に使えなくなるから2.0に更新してちょ」**の文字を見る限り、正しい設定ではないようです。
どないせーと。

参考：
[nisevi/config.yml](https://gist.github.com/nisevi/42ca8a53ad376d7b5bba6f0dec9845ef)
RailsでES6の機能を使うとプリコンパイルが通らない（Uglifierがエラーを吐く）問題

## TL;DR
+ `uglifier`（Railsデフォルト搭載のJS軽量化gem）はES5までしか対応していない。
+ そのため、ES6の機能（テンプレートリテラルとか）を使うと怒られる。
+ `production.rb`の設定変更で対応可能。

## 変更箇所

+ 変更前

```ruby:config/environments/production.rb
config.assets.js_compressor = :uglifier
```

+ 変更後

```ruby:config/environments/production.rb
config.assets.js_compressor = Uglifier.new(harmony: true)
```

## 参考情報
https://hackbaka.hatenablog.com/entry/2018/02/14/175948
https://github.com/lautis/uglifier#es6--es2015--harmony-mode

## 備考
本来はBabelとか使ったほうがいいのかと思いますが、初学者なのでひとまずの対応です。
Firebase Cloud Storage へのデータアップロードと同時に Cloud Functions 経由でメタデータをセット

# はじめに
Firebase console から Cloud Storageへ画像等をアップロードする際、アップロードと同時にcacheなどのメタデータなども付与したいと思うことがありました。
Cloud Functions から簡単にできるだろうと思ってたけど、若干躓いてしまったのでメモしておきます。

# 問題点
通常、Web(クライアントサイド)からCloud Storageのデータにメタデータを付与する場合、ドキュメントにあるように、下記のようにすればよいと思います。

```javascript
// Create a reference to the file whose metadata we want to change
var forestRef = storageRef.child('images/forest.jpg');

// Create file metadata to update
var newMetadata = {
  cacheControl: 'public,max-age=300',
  contentType: 'image/jpeg'
}

// Update metadata properties
forestRef.updateMetadata(newMetadata).then(function(metadata) {
  // Updated metadata for 'images/forest.jpg' is returned in the Promise
}).catch(function(error) {
  // Uh-oh, an error occurred!
});
```

しかし、Cloud Functionsから同じようなことをやろうとしてもできませんでした。

# 解決策
結論から先に記述すると以下のように実装しました。

```javascript
const functions = require('firebase-functions');
const admin = require('firebase-admin');

admin.initializeApp(functions.config().firebase);

exports.setMetadata = functions.storage.object().onFinalize((object) => {
  const filePath = object.name;
  const { contentType } = object;
  const storage = admin.storage();
  const fileRef = storage.bucket().file(filePath);
  const newMetadata = {
    cacheControl: 'public,max-age=3600',
  };

  // ここでcontentTypeに応じてメタデータを変えてみたりとか
  if (contentType.startsWith('image/')) {
    fileRef.setMetadata(newMetadata).then(() => {
      console.log('Set Metadata'); // eslint-disable-line
    }).catch((err) => {
      console.log(err); // eslint-disable-line
    });
  }
});
```

## 参照の作成
まず、Cloud FunctionsではCloud Storage内のファイルへの参照を作成する場合、

```javascript
const fileRef = admin.storage().ref().child(filePath);
```

としても、Cloud Functionsは通常のWeb用のAPIを使えないので動きません。なので、

```javascript
const fileRef = storage.bucket().file(filePath);
```

こうです。

## メタデータのセット
参照の作成にはドキュメントにも書いてあるので特に問題はなかったのですが、問題はメタデータのセット部分です。

```javascript
fileRef.updateMetadata(newMetadata);
```

上記のようにしてもメタデータをセットできませんでした。
正しくは下記の通りです。

```javascript
fileRef.setMetadata(newMetadata);
```

この方法はドキュメントを探しても見つけられませんでした（探し方が足りないのか...）。

取り合えずこれでCloud Functions経由でデータアップロードと同時にメタデータをセットすることができました。

# 追記
@rubytomato@github さんからコメントを頂いたので追記します。

サーバーサイドの処理ではFirebase Admin SDKを使用し、クライアントサイドの処理ではFirebase SDKを使用します。
今回のようなCloud Functionsを用いたサーバーサイドの処理はこのあたりのドキュメントを読めばよさそうです。
[APIs & Libraries  |  Node.js  |  Google Cloud](https://cloud.google.com/nodejs/docs/reference/)
メタデータに関しては、指摘していただいたように下記リンク先にドキュメントがありました。
[@google-cloud/storage 1.7.0 » Class: File  |  Node.js  |  Google Cloud](https://cloud.google.com/nodejs/docs/reference/storage/1.7.x/File#setMetadata)
[swift].showで画面遷移を横スライドにする

.showの画面遷移方法を変えるというよりはViewをNavigationControllerにしてしまおうというような記事です。
自分も初心者なのでフィードバックなどいただけたらありがたいです。
##ViewをnavigationControllerにする
通常showで遷移する場合は下から画面が出てくるようなアニメーションになりますがnavigationController上でshowをすると右から画面が出てくるようなアニメーションになります

プロジェクトのAppDelegate.swiftのApplicationの中に以下のコードを記入すると最初の画面がNavigationControllerになります。

```AppDelefate.swift
func application(_ application: ~~~Bool {

    let navigationController = UINavigationController(rootViewController: UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "initView"))
    self.window?.rootViewVontroller = navigationController

    return true
}
```

Identifierが"initView"なViewを最初に画面として呼び出しています。
ではVIewControllerに遷移のコードを記入していきます。

```InitViewController.swift
@IBAction func nextButton(_ sender: Any) {
    
    let nextView = self.storyboard!.instantiateViewController(withIdentifier: "nextView"
    self.show(nextView, sender: nil)
}
```
エミュレータを立ち上げて実行すると遷移のアニメーションが横スライドになってると思います。
favicon設定 Rails

`Rails`プロジェクトに`favicon`を簡易設定する際のメモ

# 準備
`favicon`用の画像ファイルを用意しとく。
>[icons8 | アイコン無料ダウンロード](https://icons8.jp/icon/set/favicon/all)
[ファビコン favicon.icoを作ろう!](https://ao-system.net/favicon/index.php)


# 作業
:one: `assets/assets/images`配下に`favicon.ico`ファイルを設置

```
assets/assets/images/favicon.ico
```


:two: 読み込むコードを書く

```erb:app/views/layouts/application.html.erb
<html>
  <head>
<!--(省略) -->

    <%= favicon_link_tag('favicon.ico') %>

<!--(省略) -->
  </head>

```
:three: ローカルサーバー起動して確認

```zsh
bundle exec rails s
```

# 参考
>
[Railsでfaviconを設定する](https://qiita.com/yimajo/items/981c71ca4b2048f96270)
[ Railsでfaviconを設定する - かずおの開発ブログ(主にRuby)](http://kazuooooo.hatenablog.com/entry/2016/01/06/004146)
[MacOSXシェルスクリプトだけでファビコン（Favicon）の全サイズを生成しicoファイルも出力する](https://qiita.com/hibara/items/c5d509298e29c0ff4738)
[favicon大解剖 〜必要サイズから検証時の注意点まで〜 | WebNAUT](https://webnaut.jp/design/1178.html)
Oculus RiftでGoのデバッグをする方法

# Oculus GoをUnity Editor上でデバッグしたい

Oculus Goを買って早速Unityで開発するぞ！と思って始めたのですが、ビルドして実機でプレイしないとHMDやコントローラーの動きの確認ができずとても面倒です。Unity Editor上で動作できればいいのに、と思っていたのですが、ちょうど~~VRカノジョを遊ぶための~~Oculus Riftを持っていたので、それを使って開発できないかと思いました。

## HMDの向き

RiftをPCに接続し、OVRCameraRigをHierarchyに配置すると、Riftの動きがそのままUnity Editor上で確認できます。ただ、Goは3DoF（HMD自体の位置は取れない）のに対して、Riftは6DoFでHMDの位置自体も動いてしまうので、Goの場合とのずれが発生します。なので、微調整は実機で行う必要があります。

## コントローラー

Oculus Touchは位置は認識されるものの、コントローラーが表示されません。なので,
OVRTrackedRemoteを少し修正し、無理やり表示させるようにしました。

```
void Update()
{
		bool controllerConnected = OVRInput.IsControllerConnected(m_controller);

        // 下記ifブロック追加
        if (!controllerConnected)
        {
            controllerConnected = OVRInput.IsControllerConnected(OVRInput.Controller.RTouch);
            m_isOculusGo = true;
        }
（略）
}

```

m_cotrollerにはGo向けプロジェクトの場合はR Tracked Remoteをインスペクタから指定するのが一般的ですので、Editor上でOculus Touchが接続されているときの処理を加えています。（簡易版なので左コントローラーは無視しています）

<img width="521" alt="キャプチャ.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/31032/41e445ca-050a-565d-778a-92eb11c4e104.png">

コントローラーについてもHMD同様、3DoFと6DoFの違いがありますので、Goでのコントローラーの位置がどこになるかは実機で確認が必要です。

## おわりに
もっと簡単な方法があるよ、という場合にはぜひお知らせください。
また、そこそこいいグラボを積んだPCでないとRiftは動作しませんのでご注意ください。
Pythonでファイルを一行ずつ読んで処理する

Python で別ファイルに記録したリストを読み込ませて処理しようとしたときに改行まで入ってきて面倒だったので備忘録。

## 特に何も考えずに書いたコード

```py
f = open('listfile.txt', 'r')
line = f.readline()

while line:
    print(line)
    line = f.readline()
f.close()
```

listfile.txt の中身は ↓ みたいな感じ。

```
1111
2222
3333
4444
```

### 出力結果の期待値
そのまま ↓ みたいな感じ。

```
1111
2222
3333
4444
```


実際には ↓ のような感じ。

```
1111

2222

3333

4444
```

どうやら line には行末の改行コードまで含まれてる。

## 改行を削除する
printするだけなら read とかで良いかもしれないが、数万行の ID のリストを読み込ませて一行ごとに処理するとかだと不便。

ID の末尾の改行コードは処理に不要なので除去して処理したい、

って時には単純に、`line.strip()` で良いらしい。

```py
f = open('listfile.txt', 'r')
line = f.readline()

while line:
    print(line.strip())
    line = f.readline()
f.close()
```

こうすると期待通り処理される。

```
1111
2222
3333
4444
```

write の時は改行はつかないのに readline は改行を含めて処理するらしい。

普段使ってないとなかなか覚えられない。
Railsチュートリアル３章のテストでリスト3.14（テスト）でエラーになる

## Railsチュートリアル３章のテストでリスト3.14でエラーになる
Railsチュートリアル３章のリスト3.14で、出力結果が

```
$ rails test
2 tests, 2 assertions, 0 failures, 0 errors, 0 skips
```

とならず、ハマりました。

結局、
英語版のRailsチュートリアルから、Gemfileを引っ張ってきて解決できました。

minitestのバージョンが5.10.3に固定になってるところが、日本語版と違うみたい。

minitestが何かはしらないが、これをGemfile貼り付けたら先に進めました。

Listing 3.2: A Gemfile for the sample app.

```

source 'https://rubygems.org'

gem 'rails',        '5.1.4'
gem 'puma',         '3.9.1'
gem 'sass-rails',   '5.0.6'
gem 'uglifier',     '3.2.0'
gem 'coffee-rails', '4.2.2'
gem 'jquery-rails', '4.3.1'
gem 'turbolinks',   '5.0.1'
gem 'jbuilder',     '2.7.0'

group :development, :test do
  gem 'sqlite3', '1.3.13'
  gem 'byebug',  '9.0.6', platform: :mri
end

group :development do
  gem 'web-console',           '3.5.1'
  gem 'listen',                '3.1.5'
  gem 'spring',                '2.0.2'
  gem 'spring-watcher-listen', '2.0.1'
end

group :test do
  gem 'rails-controller-testing', '1.0.2'
  gem 'minitest',                 '5.10.3'
  gem 'minitest-reporters',       '1.1.14'
  gem 'guard',                    '2.13.0'
  gem 'guard-minitest',           '2.4.4'
end

group :production do
  gem 'pg', '0.18.4'
end

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

```

引用＜https://www.railstutorial.org/book/static_pages＞
mapstatetopropsの偉大さを知った話

# reduxを使っているときにstoreの中身を見てみるとstateがjson形式で並んでるだけでなくそれを管理する新たなキーが作られていて謎だった

調べてみるとmapstatetopropsの時に指定していたものであった。

```javascript
const mapStateToProps = (state) => {
    const { imageUrl, text } =  state.employeeForm;
    return { imageUrl, text };
}
```
みたいな感じで。

こうするとemployeeFormというキーに対するヴァリューの中にimageUrlとtextの ハッシュが格納される様になる。
Phoenix APIのDBアクセッサ／バリデータのコード解析

（この記事は、「サーバーサイドプログラミング Advent Calendar 2017」の3日目です）

---

[fukuoka.ex](https://fukuokaex.fun/)代表の[piacere](https://twitter.com/piacere_ex)です
ご覧いただいて、ありがとうございます :bow:

今回は、[前回](https://qiita.com/piacere_ex/items/3e8d2dd3a0a8d4c3ba0c)の続きで、Phoenixで自動生成したAPIの、DBアクセッサ／バリデータについて、コード解析します
<br>
:stars::stars::stars::stars::stars:<b>　お知らせ：Elixir MeetUpを6月末に開催します　</b>:stars::stars::stars::stars::stars:

[<b>「fukuoka.ex#11：DB／データサイエンスにコネクトするElixir」</b>](https://fukuokaex.connpass.com/event/87241)を6/22（金）19時に開催します

[![image.png](https://connpass-tokyo.s3.amazonaws.com/thumbs/cb/13/cb130a03343bc310b07244c308b940db.png)](https://fukuokaex.connpass.com/event/87241)

fukuoka.exの発足から、ちょうど1周年となる、記念的なイベントでもあるため、このコラムを気に入っていただいた方と、ぜひ一緒に盛り上がりたいです

福岡近辺にお住まいの方であれば、遊びに来てください

<font color="red"><b>大人気により、一度は満席となりましたが、増枠しましたので、下記URLよりご参加ください</b></font>
https://fukuokaex.connpass.com/event/87241

特別ゲストは、Erlang／Elixirの両面で世界的に有名な「力武 健次さん」と、北九州の飯塚市で「e-ZUKA Tech Night」を6年間主催し続けるハウインターナショナルの「谷口 耕平さん」のお二人と、実に豪華なイベントです

私は、今回のシリーズを踏まえた、「1家に1台、パーソナルなデータ分析AIを全員が持つ2020年を作る」というタイトルで、Elixirによる、ブラウザUI上からサクっとデータ分析プラットフォームを披露するLTをお届けします

# DBアクセッサとバリデータ

APIのリクエスト／レスポンスの解析／改造は、[前回までの内容](https://qiita.com/piacere_ex/items/3e8d2dd3a0a8d4c3ba0c)だけで充分やっていけるのですが、ついでに、DBアクセッサとバリデータについても把握しておいた方が、Phoenixの理解は進むので、ついでに解説しておきます

DBアクセッサは、下記モジュール（≒mix phx.gen.jsonで第1引数に指定した名前で作られる）に集約されています

list_sample()がコントローラのindex()から呼ばれ、create_sample()がコントローラのcreate()から呼ばれます

このモジュール内容は、APIだけで無く、「mix phx.gen.html～」で自動生成するWebのときも、同じ内容で生成されます

```elixir:lib/sample_analytics/api/api.ex
defmodule SampleAnalytics.Api do
…
  def list_sample do
    Repo.all(Sample)
  end
　…
  def create_sample(attrs \\ %{}) do
    %Sample{}
    |> Sample.changeset(attrs)
    |> Repo.insert()
  end
…
```

バリデータは、下記モジュールのchangeset()として生成されます

changeset()は、上記DBアクセッサモジュールのcreate_sample()やupdate_sample()から、DBデータ更新（≒Repo.insert()やRepo.update()）直前に呼ばれます

このモジュール内容も、「mix phx.gen.html～」で自動生成するWebのときと同じですし、DBアクセッサにてDBデータ更新直前にchangeset()が呼ばれる点も同じです

```elixir:lib/sample_analytics/api/sample.ex
defmodule SampleAnalytics.Api.Sample do
  use Ecto.Schema
  import Ecto.Changeset

  schema "sample" do
    field :body, :string
    field :title, :string

    timestamps()
  end

  @doc false
  def changeset(sample, attrs) do
    sample
    |> cast(attrs, [:title, :body])
    |> validate_required([:title, :body])
  end
end
```

なお、changeset()内で呼べるバリデーション処理については、[「elixir on phoenix changesetでのValidates」](https://qiita.com/su_mi/items/feb97e62aa24c73b3eb0)をご覧いただくと参考になると思います

# 終わり

今回は、Phoenix APIのDBアクセッサ／バリデータのコードの流れを解析しました

DBアクセッサをいじる機会は、そこまでは無いと思いますが、一方でバリデータは、比較的カスタマイズする機会がありますので、キャッチアップしておくと、Phoenix API開発がスムースになるかと思います

# p.s.「いいね」よろしくお願いします

よろしければ、ページ左上の ![image.png](https://qiita-image-store.s3.amazonaws.com/0/155423/4d515047-cc48-382e-c2b1-3ad0cc50dbbf.png) や ![image.png](https://qiita-image-store.s3.amazonaws.com/0/155423/a4e3da58-70a3-4197-95a2-6a6906650d01.png) のクリックをお願いしますー:bow:
MediaWikiにて新しいページを作成する

いろいろ面倒だったので備忘録も兼ねて。
まず、記事を作るスペースを用意するところがわかりづらい。
#ページを作成する
まず、ページがなきゃ始まらないのでページを作成する。
とてもわかりにくいのだが、書きたいページのタイトルをページ右上にある検索窓に突っ込む。
すると、このような画面になるので、矢印の部分をクリックすると新規作成画面に飛ぶ

<img width="781" alt="新しいページ.png" src="https://qiita-image-store.s3.amazonaws.com/0/204497/a76a3f3a-a895-8b31-3259-7e09e65132e6.png">



ここでは、MediaWiki markupという記法を用いて書き込んでいくのだが、、、

・・・MediaWiki markup、書きにくくない？

#Pandocを使って変換しよう
正直な話、MediaWiki markup覚えるくらいなら個人的にはMarkdownかTeXの勉強したさあるし、世の中そう思っている人も多そうなので、変換してくれる[Pandoc](http://pandoc.org/index.html)を活用してMarkdownとかTeXでページを作成しよう！
MarkdownとかTeXとかライブ変換してくれるツールも充実してるから書きやすいし

[日本Pandocユーザー会](http://sky-y.github.io/site-pandoc-jp/)が日本語で書かれていて便利です。


#インストール
[この記事にまとめられています](https://qiita.com/sky_y/items/3c5c46ebd319490907e8)
**Mac**
Homebrewを使って
```brew install pandoc```

**Linux**
apt-getやyumを使って
```sudo apt-get install pandoc```
```sudo yum install pandoc```

でインストールできそうです。
Windowsの人は上の記事から頑張ってください


#変換
上の日本Pandocユーザー会に説明が書いてあります。[Pandoc ユーザーズガイド 日本語版](http://sky-y.github.io/site-pandoc-jp/users-guide/)
何かしらをMarkdownやTeXで書いて変換していきます。
拡張子からのフォーマットの推測機能がついているようなので*.tex*ファイルとかの入出力は省略が可能みたいです。また、*.txt*ファイルとかの入力は明示されていない限りMarkdownとして扱い、出力はHTMLとして扱われるらしいです。なのでMarkdownからMediaWikiに変換したいときは後述する-fの部分のみ省略ができます。

基本的に使用するオプションは3つ
```-o``` 標準出力ではなく別ファイルに書き出します
```-f``` ```-r``` 入力形式を指定します
```-t``` ```-w``` 出力形式を指定します

例えば、Markdown形式で書かれた*markdown.txt*をMediaWiki markup形式で書かれた*mediawiki.txt*に書き出したい時は

```
pandoc -f markdown -t mediawiki -o mediawiki.txt markdown.txt
```

と書けば変換されます。
上でも書いた通り、この場合だと```-f markdown```は省略可能です。
また、拡張子から推測してくれる機能を使えばLaTeXで書かれた*latex.tex*をMediaWiki markup形式で書かれた*mediawiki.txt*に書き出したい時は

```
pandoc -t mediawiki -o mediawiki.txt latex.tex
```

で変換が可能です。

**ということで、出てきた文章を先ほど作ったページの編集画面に貼り付ければ完成です！**
iftop のインストール

iftop なるコマンド（ツール）があることを知ったので入れてみたメモ

# 手順
手順は単純にパッケージをインストールするだけで使える

1. apt-get コマンドでインストール

    ```
    $ sudo apt-get -y install iftop
    ```
### 確認
```
$ sudo iftop
```
![iftop画面.png](https://qiita-image-store.s3.amazonaws.com/0/34297/66e399ca-dabe-defa-50e8-8df17a46a0bc.png)

# 参考
- [iftop: display bandwidth usage on an interface](http://www.ex-parrot.com/pdw/iftop/)
Ethereumクライアント geth起動時のオプションの意味

- 色々資料を見ていても「geth立ち上げ時にはこのコマンド」程度にしか記載がなかったので、自分用にメモ。


### __入力例__
---
```bash:console
$ geth --networkid "15" --nodiscover --datadir "~/Desktop/eth_path" --rpc --rpcaddr "localhost" --rpcport "8545" --rpccorsdomain "*" --rpcapi "eth,net,web3,personal" --targetgaslimit "20000000" console 2>> ~/Desktop/eth_path/geth_err.log
```

- テストネットの起動を想定
- `~/Desktop/eth_path`にgenesis.json, gethディレクトリ等を配置


### __各オプションの意味__

---

| オプション | 説明 |
|:-------------------------|:-----|
|`--networkid `|テストネット用のIDを指定（ライブネット（本番環境）では不要）。genesis.jsonに記述したnetworkIdと同一にする。|
|`--nodiscover`|gethでは同じネットワーク内のノードへの接続を常に試みる仕様となっており、この自動Peer探索機能を使用しないオプション。|
|`--datadir`|各種データの出力先指定。genesisブロックで初期化したディレクトリと同一の場所を指定する。|
|`--rpc`|RPCサーバのAPIを有効にするオプション。※RPC(Remote Procedure Call)：遠隔手続呼び出し、ネットワーク上にあるマシンで動いているプログラムと自マシン内で動いているプログラム同士が通信するためのプログラム|
|`--rpcaddr`|自分のgethノードのアドレスを指定。ローカル環境なら"127.0.0.1"か"localhost"を使用。|
|`--rpcport`|RPCAPIのポート番号を指定。特に指定がなければデフォルトの"8545"が設定される。|
|`--rpccorsdomain`        |クロスアクセスドメインを許可するドメイン。アスタリスクは任意のドメインを許可。|
|`--rpcapi`|gethで利用できる（利用したい）apiを指定。|
|`--targetgaslimit`|利用できるGasリミット上限を指定。|
|`console `             |対話型コンソールの立ち上げ。`console`オプション使用なし+末尾に"&"を付与するとバックグラウンドでgethが立ち上がる。|


### __出力__
---
```bash:console
Welcome to the Geth JavaScript console!...（省略）
```
間違い等あればご指摘ください。
ansible-playbook で epel レポジトリを有効にする ( jq コマンドをインストールする例 )

- いったん epel-release を `yum install` する
- 次に `enablerepo: epel` でレポジトリを有効化して必要なライブラリをインストールする

```yaml:roles/some_role/tasks/main.yml
- name: install epel-release
  yum:
    name: epel-release
    state: present
  sudo: yes

- name: install jq
  yum:
    name: jq
    state: present
    enablerepo: epel
  sudo: yes
```

# 環境

- ansible 1.9.6
- CentOS release 6.9 (Final)
- Docker version 18.03.1-ce, build 9ee9f40








<!-- Update From Qiita API -->

# チャットメンバー募集


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

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





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
Vimで特定のファイルだけシンタックスハイライトが効かなくなる

# はじめに

Vimで、ある特定のファイルだけシンタックスハイライトが効かなくなることがあるが、これは~/.vim/view以下に保存されている、バッファの表示情報がおかしくなっているから。

# 現象

いま、`~/temp/test.cpp`をvimで開いたとする。いつもなら`filetype=cpp`となり、勝手にシンタックスハイライトされるはずだが、なぜか以下のようにハイライトされなくなってしまった。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/79744/5d80d471-b67d-99c7-cb38-c17b68faeedd.png)

`:set filetype?`と聞いてみても「filetype=」とつれない返事。

しかし、名前をつけて保存(`:w test2.cpp`)して、それを開く(`:o test2.cpp`)するとちゃんとシンタックスハイライトされる。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/79744/f7885d20-0fda-0d09-682d-35ae6943b8f2.png)

ファイルを移動しても同様。すなわち`~/temp.test.cpp`を開いたときだけファイルタイプが認識されず、シンタックスハイライトがされない。

# 原因

これは、バッファの表示情報を保存しているファイルがおかしくなっているから。表示がおかしくなったファイルを開いた状態で、

```vim
:verbose :setlocal filetype?
```

を実行してみる。すると、

```shell-session
  filetype=
        Last set from ~/.vim/view/~=+temp=+test.cpp=
```

と表示される。これは、現在ファイルタイプは設定されておらず(`filetype=`)、その設定は`~/.vim/view/~=+temp=+test.cpp=`というファイルによって行われたことを示す。この`~/.vim/view`以下のファイルは、バッファの表示状態(カーソル位置やフォルディング状態等)を保存するファイルだが、たまにそれがおかしくなるようだ。

さっそくこのファイル`~/.vim/view/~=+temp=+test.cpp=`を開いてみると、

```vim
if &filetype != ''
setlocal filetype=
endif
(snip)
if &syntax != ''
setlocal syntax=
endif
```

という記述がある。つまり、ファイルタイプやシンタックス情報をわざわざ上書きしている。これらの行を消してから再度先ほどのファイルを開いて見る(この表示情報保存ファイルを消してしまっても良い)。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/79744/87ced6e5-0389-ea1f-3d52-efedeeab06dd.png)

正しくシンタックスハイライトされた。もちろん真面目に`:set filetype=cpp`とかしても良い。

また、稀なケースとして、ファイルタイプは正しく認識されているのに、シンタックスハイライトだけされない、ということがあるかもしれない。つまり`:set filetype?`が`cpp`を返すのに、シンタックスハイライトされない場合がある。これは表示情報ファイルが

```vim
if &filetype != 'cpp'
setlocal filetype=cpp
endif
(snip)
if &syntax != ''
setlocal syntax=
endif
```

と、ファイルタイプだけ正しく設定され、シンタックスが設定されていない場合に起きる。この場合もこのファイルを修正するか、当該バッファで`:set filetype=cpp`すれば治る。

# まとめ

Vimで、ある特定のファイルだけ表示がおかしくなったら、それは`~/.vim/view`以下に保存されている表示情報がおかしくなっているから。Vim側でも治せるが、おそらく当該ファイルを消してしまうのが手っ取り早い。ちなみにこの現象、Macのターミナル上のVimでたまに起きるんだけど、未だ原因不明。あまり他に同様なことが起きている人がいないので、僕の`.vimrc`が悪いのかも。
[Android] Activity Transition 


#いち
style で追加

```xml
<item name="android:windowActivityTransitions" tools:targetApi="lollipop">true</item>
```
や

```xml
<item name="android:windowActivityTransitions" >true</item>
```

まず、このStyleで

```xml

<style name="NoActionBar2">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
        <item name="android:windowActivityTransitions">true</item>
</style>
```

#に

layout　view xmlで 

```xml
android:transitionName="your string name"
```

#さん

```java

imageView.setOnClickListener(v -> {

Intent sharedIntent = new Intent(FisrtActivity.this, SecondActivity.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(FisrtActivity.this,
    Pair.create(v,"one"),
    Pair.create(textView, "second_text"));
    startActivity(sharedIntent, options.toBundle());
 }else {
    startActivity(sharedIntent);
 }

});

```

#終了
GitHubにSSH接続してるのに毎回パスワードを要求される（Windows）

自分のWin10 + GitBashでGitHubにPUSHとかすると、SSH接続なのに毎回パスワード聞かれて面倒くさい。

**回避方法**
1. ~/.bash_profileを開く
2. ファイルの最後に以下の2行を追加
```
eval `ssh-agent`
ssh-add
```
3. GitBashを起動。この時にパスワード入力が要求される。以降はパスワード入力不要となる。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/249926/b73c3b9b-cc88-3db0-1590-eb98c0e87827.png)

参考にさせて頂きました。
https://takanosho.wordpress.com/2013/01/11/input-ssh-key-passphrase-only-once-on-git-bash/

ありがとうございます。
一つ賢くなりました。
GPSの研究　その17

#概要
GPSを理解したかった。
Ntripを調べてみた。

#Ntripとは。

GNSSの観測データや補正データの送受信をインターネット経由で実現するための仕組み。
NtripはHTTPをベースとしたTCPプロトコルであり，スマートフォンなどWebにアクセスできる端末からであれば，Ntripが配信するデータにもアクセスすることができます。
TCPサーバであるNtrip Casterにアクセスする基準局もローバー局も，どちらもTCPクライアントになります。
Ntripのネーミングでは，ローバー局のみをNtirp Clientと呼び，基準局はNtrip Serverと呼びます。

一般に，Ntrip Casterによるデータ配信サービスは，データを受信するNtrip Clientとしてアクセスすることはできても、自分の基準局データを送信するためにNtrip Serverとしてアクセスすることはできません。

Ntrip Serverとしても自由にアクセスできるオープンなNtrip Casterのサービスがいくつかあります。

YouCORS: NTRIP caster as a Service
RTK2GO: Hassle Free RTK Station

Ntrip ServerからNtrip Casterに送られるHTTPデータはストリーム（stream）と呼ばれ，それぞれにMount Pointという識別用の名前が割り振られます。
Ntrip CasterにアクセスするNtrip Clientは，このMount Pointを指定して，自分が受信したいデータを選択します。
つまり，Mount Pointは基準局の名前ではなく，あくまでもストリームの名前です。
そのため，ひとつの基準局からRTCMとBINEXなどの複数のストリームが配信されることもあります。

ポート番号は、2101が、データ形式は、RTCM3かu-bloxが使われる。
基準局からおよそ10kmが有効範囲となります。
Ntirp Clientとしては、RTKLIBとu-centerか。



以上。
今さらながらPWDコマンドの由来を調べた

15年以上UNIX系のOS触っていて放っておいていた疑問…

**PWDってコマンド、なんか違和感ある…**
（パスワードをごにょごにょするコマンドみたい）

いろんなコマンドの由来をまとめてくれた人がいました。
[Linuxコマンドは単語の意味を理解するとグッと身近なものになる](https://qiita.com/tetsuya/items/46888bb4dfc8a6bfef02
)

由来は・・・
**Print Working Directory**
だそうです。そのまんまですね。

一つ賢くなりました。
STM32CubeMX:DACとADCを同期する(2)

　[前回](https://qiita.com/amutou/items/e15c427d92535dd84c18)はDACの開始と同時にADCも開始する方法を紹介しました。この方法は気軽な半面、ADCを遅れて開始させることができません。
　電線に通す電気信号のような、非常に高速に伝搬する信号であれば問題ありませんが、例えば超音波距離計のような、伝搬速度がある程度遅い経路を通す場合等、ADCを遅れて動作させたほうが良い時があります。
　ということで、今回はDACから遅れてADCを動作させます。

## CubeMXの設定

　DAC(マスタ)はTIM4で駆動し、ADC(スレーブ)はTIM3で動作させています。つまり、TIM4をマスタにしつつ、TIM3をスレーブにできるTIMxを間に挟むことにより、任意時間のディレイを実現できます。
　この条件に一致するTIMはTIM2とTIM5のどちらかです。幸運なことにTIM2/TIM5はどちらも32bitカウンタを持っているので、柔軟な運用ができます。どちらもTIM3/TIM4と連番なのでどちらを使ってもあまり違和感はありませんが、とりあえず今回はTIM5を使用することにします。

### Pinoutタブ

　TIM5のSlave ModeをTrigger Modeに、Trigger SourceをITR2に、そしてInternal ClockとOne Pulse Modeにチェックを入れます。
　TIM3のTrigger SourceをITR2にします。

### Configurationタブ

　TIM5をクリックし、TIM5 Configurationウインドウを開きます。
　Trigger Event SelectionをUpdate Eventにします。

　これでCubeMXの設定は終了です。コードを書き出してソフトウェアの変更に移ります。

## ソースコード

```c++
constexpr size_t DAC_len(1000);
constexpr size_t ADC_len(1000);
static uint8_t DAC1_buff[DAC_len];
static uint8_t DAC2_buff[DAC_len];
static uint16_t ADC_buff[ADC_len];

for (size_t i(0); i < DAC_len; ++i)
{
    const float s(sinf((float)i / DAC_len * pi * 2));
    DAC1_buff[i] = (uint8_t)(+s * 110 + 128);
    DAC2_buff[i] = (uint8_t)(-s * 110 + 128);
}

memset(ADC_buff, 0, sizeof(ADC_buff));

htim5.Instance->ARR = 84 * 1000 * 250 - 1;

HAL_TIM_GenerateEvent(&htim4, TIM_EVENTSOURCE_UPDATE);
HAL_TIM_Base_Stop(&htim5);
HAL_TIM_GenerateEvent(&htim5, TIM_EVENTSOURCE_UPDATE);
HAL_TIM_Base_Stop(&htim3);
HAL_TIM_GenerateEvent(&htim3, TIM_EVENTSOURCE_UPDATE);

HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *)DAC1_buff, DAC_len, DAC_ALIGN_8B_R);
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_2, (uint32_t *)DAC2_buff, DAC_len, DAC_ALIGN_8B_R);
HAL_ADC_Start_DMA(&hadc1, (uint32_t *)ADC_buff, ADC_len);

HAL_TIM_Base_Start(&htim4);

while (__HAL_DMA_GET_COUNTER(hdac.DMA_Handle1) > 0 ||
        __HAL_DMA_GET_COUNTER(hdac.DMA_Handle2) > 0 ||
        __HAL_DMA_GET_COUNTER(hadc1.DMA_Handle) > 0)
{
    osDelay(1);
}

HAL_TIM_Base_Stop(&htim4);
HAL_TIM_Base_Stop(&htim3);
HAL_TIM_Base_Stop(&htim5);

HAL_DAC_Stop_DMA(&hdac, DAC_CHANNEL_1);
HAL_DAC_Stop_DMA(&hdac, DAC_CHANNEL_2);
HAL_ADC_Stop_DMA(&hadc1);

for (size_t i(0); i < ADC_len; ++i)
{
    printf("%u %hu\n", i, ADC_buff[i]);
}
```

　ソースコードは前回のものとほぼ同様です。
　TIM5のARR設定/クリア/Start/Stopが増えたのが違いです。

　この設定によりDACから250msec遅れてADCが開始されます。

　今回は250msecですが、コアクロック168MHzの場合、プリスケーラ無しで最大50秒程度、プリスケーラも併用する場合は最大約6千年分のディレイができます。
　例えばプリスケーラを`84-1`に設定した場合、1マイクロ秒の分解能で1時間程度までディレイできるので、大抵の場合はこの設定で問題ないはずです。
　深宇宙の探査機と通信したい、みたいな場合はもうちょっとディレイ時間が長いほうが嬉しいかもしれないですね。そのような場合は各自調整してください。

## 結果

![2018-06-19_12-49.png](https://qiita-image-store.s3.amazonaws.com/0/264452/9d2ed630-ee28-6a67-28ef-b82b1b4d48f0.png)

　前回のグラフと比べて、ADCが250msec遅れて(波形が250msec進んで)計測されていることがわかります。

## 履歴

2018-06-19

* 転送終了待ちwhileの条件を修正
STM32CubeMX:DACとADCを同期する

　[前回(ADC編)](https://qiita.com/amutou/items/b7e6ffc42d2ce2b7f260)と[前々回(DAC編)](https://qiita.com/amutou/items/5e7c9e2ffb1c28812b07)で、決まった周期でDACあるいはADCを駆動する方法を紹介しました。また、ADC編の最後にはDACで出力した正弦波をADCで測定したグラフも紹介しました。ただ、その時はDACとADCの同期が取れていないため、ADCの結果は位相ずれが発生していました。
　ということで、今回はDACとADCの同期を行いたいと思います。

## CubeMXの設定

　ADCに使っているTIM(今回はTIM3)のSlave ModeをTrigger Modeにします。
　Trigger Sourceを適切な値に設定します。今回はマスタがTIM4でスレーブがTIM3なので、ITR3を選択します。詳しくは各MCUのリファレンスマニュアル(STM32F4:RM0090, STM32F1:RM0008 等)の"汎用タイマ→レジスタ→スレーブモード制御レジスタ(SMCR)"を参照してください。

　CubeMXの設定はこれだけです。コードを生成してソースコードの変更に移ります。

## ソースコード

```c++
constexpr size_t DAC_len(1000);
constexpr size_t ADC_len(1000);
static uint8_t DAC1_buff[DAC_len];
static uint8_t DAC2_buff[DAC_len];
static uint16_t ADC_buff[ADC_len];

for (size_t i(0); i < DAC_len; ++i)
{
    const float s(sinf((float)i / DAC_len * pi * 2));
    DAC1_buff[i] = (uint8_t)(+s * 110 + 128);
    DAC2_buff[i] = (uint8_t)(-s * 110 + 128);
}

memset(ADC_buff, 0, sizeof(ADC_buff));

HAL_TIM_GenerateEvent(&htim4, TIM_EVENTSOURCE_UPDATE);
HAL_TIM_Base_Stop(&htim3);
HAL_TIM_GenerateEvent(&htim3, TIM_EVENTSOURCE_UPDATE);

HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *)DAC1_buff, DAC_len, DAC_ALIGN_8B_R);
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_2, (uint32_t *)DAC2_buff, DAC_len, DAC_ALIGN_8B_R);
HAL_ADC_Start_DMA(&hadc1, (uint32_t *)ADC_buff, ADC_len);

HAL_TIM_Base_Start(&htim4);

while (__HAL_DMA_GET_COUNTER(hdac.DMA_Handle1) > 0 ||
       __HAL_DMA_GET_COUNTER(hdac.DMA_Handle2) > 0 ||
       __HAL_DMA_GET_COUNTER(hadc1.DMA_Handle) > 0)
{
    osDelay(1);
}

HAL_TIM_Base_Stop(&htim4);
HAL_TIM_Base_Stop(&htim3);

HAL_DAC_Stop_DMA(&hdac, DAC_CHANNEL_1);
HAL_DAC_Stop_DMA(&hdac, DAC_CHANNEL_2);
HAL_ADC_Stop_DMA(&hadc1);

for (size_t i(0); i < ADC_len; ++i)
{
    printf("%u %hu\n", i, ADC_buff[i]);
}
```

　DACのバッファ初期化やADCのバッファ出力等が近い場所にあるため、少し複雑です。が、処理としてはDAC単体、ADC単体のときとほとんど同じです。
　唯一違うのは、TIM3(ADCトリガ)をソフトウェアで開始しない点と、TIM4/TIM3のカウンタクリアの順番に注意する必要がある点です。
　TIM3はTIM4のアップデートで開始しますが、TIM4をクリアするためにソフトウェアでアップデートイベントを発生させます。この際にTIM3が開始してしまうので、先にTIM3をクリアしてしまっても意味がありません。そのため、先にマスタ側をクリアし、またスレーブ側をクリアする前にスレーブを停止させる必要があります。

## 結果

![2018-06-19_12-00.png](https://qiita-image-store.s3.amazonaws.com/0/264452/d3a2c65a-6fc0-a219-4a72-3451578fec67.png)

　前回のグラフと比べて、確かに位相ずれが減っているのがわかります。厳密に位相ずれがゼロになるわけではありませんが、ジッターを大幅に減らすことが可能になります。

## 履歴

2018-06-19

* 転送終了待ちwhileの条件を修正
STM32CubeMX:ADCをTIMで駆動する

　TIM3でタイミングを生成し、ADC1_IN6(PA6)で受信する。

## CubeMXの設定

### Pinoutタブ

　ADC1のIN6にチェックを入れる。

　TIM3のClock SourceをInternal Clockにする。

### Configurationタブ

　AnalogのADC1ボタンをクリック、ADC1 Configurationウインドウを開く。

　Parameter Settingsタブを開く。

　External Trigger Conversion SourceをTimer 3 Trigger Out eventにする。

　DMA Settingsタブを開く。

　Addをクリックし、DMA RequestをADC1にする。

***

　ControlのTIM3ボタンをクリック、TIM3 Configurationウインドウを開く。

　Parameter Settingsタブを開く。

　Prescalerに`84-1`、Counter Periodに`1000-1`を設定する。
　Trigger Event SelectionでUpdate Eventを選択する。

***

　コードを書き出す。

## ソースコード

```c++
constexpr size_t len(1000);
static uint16_t ADC_buff[len];

memset(ADC_buff, 0, sizeof(ADC_buff));

HAL_TIM_GenerateEvent(&htim3, TIM_EVENTSOURCE_UPDATE);

HAL_ADC_Start_DMA(&hadc1, (uint32_t *)ADC_buff, len);

HAL_TIM_Base_Start(&htim3);

while (__HAL_DMA_GET_COUNTER(hadc1.DMA_Handle) > 0)
{
    osDelay(1);
}

HAL_TIM_Base_Stop(&htim3);

HAL_ADC_Stop_DMA(&hadc1);

for (size_t i(0); i < len; ++i)
{
    printf("%u %hu\n", i, ADC_buff[i]);
}
```

## 結果

![2018-06-19_10-50.png](https://qiita-image-store.s3.amazonaws.com/0/264452/4ec7f898-3a40-1086-9b85-db7895133586.png)

　信号源には[前回](https://qiita.com/amutou/items/5e7c9e2ffb1c28812b07)紹介したDACを使用している。ただし、DACはCircularで連続した正弦波を出力している。
　ADC1kSPS/1kポイントなので1秒分の期間を見ている。DACからは1Hzの正弦波が出力されているので、狙い通りの周期でサンプリングできていることが分かる。
　DACとADCのタイミングは合わせていないから、位相ずれが発生している。

## その他

　DACの場合、DMAをCircularにすれば延々と出力されるが、ADCはもう少し面倒な処理が必要よなる。またADCは得られたデータを解析するまでが仕事だから、Circularにするなら割り込みでリアルタイムにデータを解析する必要もある。
STM32CubeMX:DACをTIMで駆動する

## 目標

　STM32F4のDACから2chの正弦波をTIMのタイミングで出す。

## CubeMXの設定

### Pinoutタブ

　DACからOUT1 ConfigurationとOUT2 Configurationのチェックを入れる。

　TIM4のInternal Clockにチェックを入れる。

### Configurationタブ

　AnalogのDACボタンをクリック、DAC Configurationウインドウを開く。

　Parameter SettingsタブでDAC Out1 SettingsとDAC Out2 SettingsのTriggerをTimer 4 Trigger Out eventにする。
　DMA SettingsタブでAddをクリックしDMA RequestをDAC1にする。同じ手順でDAC2のDMAも作る。

　OkでDAC Configurationウインドウを閉じる。

***

　ControlのTIM4ボタンをクリック、TIM4 Configurationウインドウを開く。

　Prescalerに`84-1`、Counter Periodに`1000-1`にする。
　Trigger Event SelectionでUpdate Eventを選択する。

　OkでTIM4 Configurationウインドウを閉じる。

***

　コードを書き出す。

## ソースコード

```c++
constexpr size_t len(1000);
static int16_t DAC1_buff[len];
static int16_t DAC2_buff[len];

for (size_t i(0); i < len; ++i)
{
    const float s(sinf((float)i / len * pi * 2));
    DAC1_buff[i] = (int16_t)(+s * 1800 + 2048);
    DAC2_buff[i] = (int16_t)(-s * 1800 + 2048);
}

HAL_TIM_GenerateEvent(&htim4, TIM_EVENTSOURCE_UPDATE);

HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *)DAC1_buff, len, DAC_ALIGN_12B_R);
HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_2, (uint32_t *)DAC2_buff, len, DAC_ALIGN_12B_R);

HAL_TIM_Base_Start(&htim4);

while (__HAL_DMA_GET_COUNTER(hdac.DMA_Handle1) > 0 &&
       __HAL_DMA_GET_COUNTER(hdac.DMA_Handle2) > 0)
{
    osDelay(1);
}

HAL_TIM_Base_Stop(&htim4);

HAL_DAC_Stop_DMA(&hdac, DAC_CHANNEL_1);
HAL_DAC_Stop_DMA(&hdac, DAC_CHANNEL_2);
```

## 結果

![2018-06-19_10-39.png](https://qiita-image-store.s3.amazonaws.com/0/264452/efba2d7a-92c2-c0dd-46a4-255819819dc7.png)

　DAC1とDAC2をオシロで見てみた。
　1000ポイントで正弦波1周期を1kSPSで出力しているので、1secで1周期の正弦波となるが、正しくそのように出力されている。

## その他

　今回はNormalモードだが、CircularにすればDACバッファを延々と送信し続けることができる。今回の例をCircularにすると1Hzの正弦波が延々と送信されることになる。
　また、今回は12bitモードだが、8bitモードにすることもできる。その場合、使用するメモリが半分で済むので、電圧分解能がそれほど高くなくていいなら8bitモードは良い選択肢になる。また、バス使用率が半分になるのも利点。
Lets Encrypt + certbot + nginx + CentOS7 + GCE

# TL;DL;
CentOS 7 + nginx の環境で Let's Encrypt を使うために certbot を動作させようとすると、バグのようなものを踏むので注意

# 環境

- GCE: f1-micro, `https-server`タグをつけて 443ポートが通るように設定済
- CentOS 7 (7.5.1804)
- nginx は yum で導入
- ドメイン取得済み/DNS登録済み

# 大まかな手順
certbot のページに行って、プラットフォーム(nginx, centos7)を選ぶとやり方が出てくるのでその手順通りに進めればよい（要シェル、root権限）。Let's Encryptのページに行く必要すらない。以下その内容を記載

- プラグイン導入:  `yum install python2-certbot-nginx`
- certbot起動 ★はまりどころ `sudo certbot --nginx`
    - 解決策: https://github.com/certbot/certbot/issues/5104#issuecomment-355020248
- 対話シェルで答えて終わり
- 自動更新できるかチェック: `sudo certbot renew --dry-run`
- cron で自動更新(0時前後と12時前後に renew)

```
0 0,12 * * * python -c 'import random; import time; time.sleep(random.random() * 3600)' && certbot renew
```

# あれこれ疑問

**nginx.conf 書き換えなくていいの？**
certbot が勝手に書き換えてくれる。一通り手順が終わったら、`/etc/nginx.conf` の内容を見てみよう。

**なんかつながらない**
GCEやAWSでは、明示的にhttpsのポート443をあける必要がある。忘れてない？

**はまりポイントって？**
よくわかんない(というか調べようとすらしてない）けど、certbot が依存するpythonライブラリが、pipとディストリ（RPM）で多重管理されてうまく動かない、と解釈。このパターンが多すぎるのでCentOS/RHELはクソ。

https://github.com/certbot/certbot/issues/5104#issuecomment-355020248 で提示されたコマンドはこちら。**certbotとは別に動作している自分のpythonプログラムが、OS標準の python を使ってると影響出るかもしれないので注意。**

```
pip uninstall requests
pip uninstall urllib3
yum remove python-urllib3
yum remove python-requests
yum install python-urllib3
yum install python-requests
yum install certbot
```

**Let's Encrypt と certbot の関係は？**

Let's Encryptが証明書を発行してくれる機関のようなもの。certbot は Let's Encrypt を使うためのツールのようなイメージ。ACME protocol あたりがキーワードかな。
IBM Cloud Private付属のPrometheusが突然死を繰り返す場合の対処

# 経緯

IBM Cloud Private(ICP)には標準でPrometheusが導入されますが、導入して間もなく、Prometheusのコンテナが突然死して再起動を繰り返していることに気づきました。コンテナログを見ると普通にサービスが起動しているのですが、しばらくするとコンテナ自体がクラッシュして再起動がかかっていました。

結論ですが、ノードのOS側でOOM Killerが動いていました。

```
# dmesg | grep prometheus
[287787.255395] prometheus invoked oom-killer: gfp_mask=0xd0, order=0, oom_score_adj=984
[287787.255401] prometheus cpuset=2a3fd55af7e6b229ba978ee840e193c473c1b65a45ca9afbb5aba61073115f2f mems_allowed=0
[287787.255405] CPU: 0 PID: 24987 Comm: prometheus Kdump: loaded Not tainted 3.10.0-862.3.2.el7.x86_64 #1
[287787.255661] [24933]     0 24933   212094   129001     302        0           984 prometheus
[287787.255664] Memory cgroup out of memory: Kill process 25005 (prometheus) score 1969 or sacrifice child
[287787.258035] Killed process 24933 (prometheus) total-vm:848376kB, anon-rss:516004kB, file-rss:0kB, shmem-rss:0kB
```

PromethuesのPodの定義を見ると、メモリリミットが512MiBでした。これを広げてあげましょう。

```
$ kubectl get deployment monitoring-prometheus -n kube-system -o yaml
(略)
        resources:
          limits:
            cpu: 500m
            memory: 512Mi
```

## 手順

```
$ kubectl edit deployment monitoring-prometheus -n kube-system
-> 先ほどの512Miを1Gi等に変えて保存
```

これで自動的にデプロイメントが破棄されて新しいメモリリミットで起動します。楽ですね。

以上です。