OmniAICreator/Qiita-1.07M huggingface dataset:
Macにcomposerをinstall

```
$ curl -sS https://getcomposer.org/installer | php
All settings correct for using Composer
Downloading...
Composer (version 1.8.4) successfully installed to: /Users/{user}/Documents/src/composer.phar
Use it: php composer.phar

$ sudo mv composer.phar /usr/local/bin/composer
$ composer -V
Composer version 1.8.4 2019-02-11 10:52:10

$ which composer
/usr/local/bin/composer


```
[Vue.js/Nuxt.js] $refsの命名をする際はキャメルケース、もしくはケバブケースで書かないと動かない

## 環境

`Nuxt.js: ^2.0.0`

## 概要

DOMにrefを指定することで、子コンポーネントのプロパティやメソッドに触ることができる。

今回はrefを指定してあるメソッドを実行したかったのだが、なぜかうまく動かなかった。

原因は、refをスネークケース記法で書いていたことだった。(しょうもない）

このデバッグに時間がかかりすぎたのでここに知見を残しておく。

## 悪い例

### スネークケース

```vue
<template>
 <div>
   <ComponentSpecial ref="component_special" />
 </div>
</template>
```

```javascript
// undefined
console.log(this.$refs.component_special);
```

### パスカルケース

```vue
<template>
 <div>
   <ComponentSpecial ref="ComponentSpecial" />
 </div>
</template>
```

```javascript
// undefined
console.log(this.$refs.ComponentSpecial);
```


## 動く例

### キャメルケース

キャメルケースで書くとドット記法でいけるのでおすすめです。

```vue
<template>
 <div>
   <ComponentSpecial ref="componentSpecial" />
 </div>
</template>
```

```javascript
// undefined
console.log(this.$refs.componentSpecial);
```

### ケバブケース

ケバブケースの場合はブラケット記法で書くと参照できます。

```vue
<template>
 <div>
   <ComponentSpecial ref="component-special" />
 </div>
</template>
```

```javascript
// undefined
console.log(this.$refs['component-special']);
```


## 参考リンク

探してもあまり見つかりませんでした。

[vue.js – Vue $refs和烤肉串案 - 代码日志](https://codeday.me/bug/20190303/756080.html)
Azure Database for MySQL で稀によく遭遇する DBエラー

弊社のシステムはAzure Database for MySQLを使っています。
アプリケーションログを監視しているとたまにDBエラーがでているのが確認できます。

エラーのタイミングとして、いっつも出ているわけじゃないけど一度発生すると短時間に大量に出るという、まさに「稀によくある」状態です。

ググってヒットするエラーもあれば、全く他で見たことがないエラーもあるため、Qiitaの皆さんのなかに「それ原因知っているぜ！！」という方がいれば知見をいただきたく、もしくは困っている開発者同士の情報交換の場になればというのがこの記事の趣旨となります。
*※並行してAzure調査チームにサービスリクエストを出しているので、そちらで原因がわかったものは追記する予定です。*
**2019/03/25 Azure調査チームとのやり取りで判明したことなどを追記**

## SQLSTATE[HY000] [2006] MySQL server has gone away
このエラー自体はググっても見かけるやつです。
ただ、困ったことに数秒でエラーで返ってくることもあれば、数分、数時間後にやっとエラーが返ってくることもあるようです。
（実績があるログなので大丈夫だとは思いますが、たまに数日後にエラーが返ってくるものもあり、ちゃんとログ取れているのかは不安）

一般的には接続中のコネクションが切れた場合などに出るらしいですが、殆どが初期化処理の一番最初の接続時に出ているのでイマイチ原因がわかっていません。
PHPのシステムなので処理終了時に明示的なdisconnectをしていないのだけど、それが原因なのか？というのがありますが、まだ検証しきれていない状況です。

### 2019/03/25追記
Azure調査チームの見解としては、「**MySQLとの接続が確立されたものの使用可能になる前に、何らかの原因で接続が切断された場合に発生するエラー**」とのことでした。
とはいえサーバの設定値としてタイムアウトが短いわけでもなく（むしろデフォルトより伸ばしてる）、またアプリケーション側でコネクションプールの設定がされているわけでもありませんでした。
アプリケーション側で単純なリトライ処理を追加してしばらく様子を見たところ、フェイルオーバーで瞬断していると思われるケースは復旧できるようになりました。（割合としては30%）
とはいえ依然駄目なケースも多く、その違いがよくわかりません。
Azureに他社から同様のエラーレポートが来たことはないらしく、再現条件がわからない限りこれ以上の調査は困難とのこと。

## SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known
ググってみると単純な設定ミスらしいのですが、稼働中のシステムでぽつんと1件だけ発生したことがありました。
とはいえ過去1度しか見てないので今後起きない可能性もあります。

## SQLSTATE[HY000] [9002] The server name you tried cannot be found. Please use the correct name and retry. Please check your server name [DBサーバ名].
こちらも1つ前と同じく過去1度しか見てないので今後起きない可能性もあります。

## SQLSTATE[HY000] [9002] An error occurred when accessing your server. Please retry or report your issues.
ググってもよくわからず、現状お手上げ。（サービスリクエスト中）
### 2019/03/25追記
フェイルオーバーのタイミングで出るエラーメッセージということがAzure調査チームから確認が取れました。（同時間帯で実際にフェイルオーバーの記録が残っているとの裏付けもあり）
アプリケーション側で単純なリトライ処理を追加したので、次回発生待ち。

## SQLSTATE[HY000] [9002] Some errors occured.
ググってもよくわからず、現状お手上げ。
最近は起きておらず、次回発生したときに原因がわからなければサービスリクエストする予定です。

## SQLSTATE[HY000] [9002] Server is not ready for incoming connections.
ググってもよくわからず、現状お手上げ。
こちらも最近は起きておらず、次回発生したときに原因がわからなければサービスリクエストする予定です。

## SQLSTATE[HY000] [9999] An internal error has occurred. Please retry or report your issues.
これは以前発生したときにサービスリクエストを出したんですが、Azure側のログが流れてしまって原因究明には至りませんでした。
ただ、同時刻帯で内部サーバのメンテナンスが発生していたそうなので、その切替の間に発生していた可能性が今のところ濃厚。
今さら聞けないPlaceholder

## 問題

golangの標準パッケージ "database/sql"を使って、以下のようにPlaceholder付のクエリ書いたら、Syntax errorが発生してしまう、なぜか。

参考
- https://golang.org/pkg/database/sql/#example_DB_Query_multipleResultSets
- https://play.golang.org/p/D-5ZVSzhcXx

```
func main() {
	age := 27
	q := `
create temp table uid (id bigint); -- Create temp table for queries.
insert into uid
select id from users where age < ?; -- Populate temp table.

-- First result set.
select
	users.id, name
from
	users
	join uid on users.id = uid.id
;

-- Second result set.
select 
	ur.user, ur.role
from
	user_roles as ur
	join uid on uid.id = ur.user
;
	`
	rows, err := db.Query(q, age)
	if err != nil {
		log.Fatal(err) // Syntax error
	}
```


## 原因

PostgresDB使ってたため、?を$1に修正すればエラーは解消できる。

プレースホルダ付きのSQLをDBにあらかじめ送信しているため、DBごとに記法が異なる。

<img width="756" alt="スクリーンショット 2019-03-07 17.45.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/30623/212db80b-8882-f406-4af1-5c827ebe004c.png">

引用: http://go-database-sql.org/prepared.html
[GCEインスタンス]ファイルのアップロード/ダウンロードコマンド

# はじめに
```
WARNING: `gcloud compute copy-files` is deprecated.
Please use `gcloud compute scp` instead.
Note that `gcloud compute scp` does not have recursive copy on by default.
To turn on recursion, use the `--recurse` flag.
```

なるほど、gcloud compute copy-filesコマンドは非推奨だそうです。
以下、備忘録

# 推奨のgcloud compute scpコマンドを使う
（アップロード/ダウンロードともにホスト機で実行）

## GCEへのアップロード

```text:ERRORが出るコマンド
$ gcloud compute scp <GCEのインスタンス名>:<GCEのアップロード先パス> <ローカルのファイル格納パス
```
（GCEのインスタンス名: 「GCPのコンソール＞ナビゲーションメニュー＞Compute Engine＞VM インスタンス」の「名前」列に表示されているアップロード先のインスタンス名）
↓

```
ERROR: (gcloud.compute.scp) Could not fetch resource:
 - The resource 'projects/test-vegetation-map/zones/us-central1-f/instances/test-vegetation-map-deeplabv3plus-2-vm' was not found
```

↓
プロジェクト名、ゾーン（リージョン）を明記し、--recurseオプションを使用すると上手くいきました。

```
$ gcloud compute scp --project "<GCPのプロジェクト名>" --zone "<GCEインスタンスのゾーン(リージョン)>" --recurse <ホスト機のアップロード対象ファイルへのパス> <GCEのインスタンス名>:<アップロード先パス>
```
参考：https://cloud.google.com/sdk/gcloud/reference/compute/scp

## GCEからのダウンロード

1. 参考1の手順でGCEインスタンスに対するsshキーを作成・登録
2. 参考2の「Linux ワークステーションまたは macOS ワークステーションの SCP を使用したファイルの転送」の手順を参考にダウンロードする。（参考2のsshキーとして指定するのは参考1で作成したsshキー）

[参考1]
https://sleepless-se.net/2018/09/15/gcp-ssh/
[参考2]
https://cloud.google.com/compute/docs/instances/transfer-files?hl=ja#transfergcloud

```text:例1
# scp -i ./.ssh/id_rsa user1@<GCEのIP>:<DLしたいファイルパス> <DL先パス>
```

or

```text:例2
$ gcloud compute scp --recurse <GCEのインスタンス名>:<インスタンス内のダウンロード対象パス> <ホスト機のダウンロードファイル格納先パス> --zone '<zone(region)名>'
```

## エラー解決

### CASE1
```text:ERROR内容
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.
Please contact your system administrator.
Add correct host key in /Users/XXXX/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /Users/XXXX/.ssh/known_hosts:19
ECDSA host key for XX.XXX.XXX.XXX has changed and you have requested strict checking.
Host key verification failed.
```

[参考]
https://qiita.com/wnoguchi/items/690f3f4651f8f11e4ed3

### CASE2

その他```Permission denied (publickey).```など、繋がらない場合。

##### 対処法1
インスタンスを再起動してみる。

##### 対処法2
1. ```$ gcloud list```コマンドで現在のCloudSDKの情報を確認する。
2. 通信したいインスタンスと1. の結果が異なる部分を```$ gcloud compute scp```コマンドのオプションで指定する。

[参考 - オプション関連]
https://cloud.google.com/sdk/gcloud/reference/compute/scp#--ssh-key-file
Jupyter notebook/lab メニューの Terminal を非表示にするお話


Jupyter notebook/lab メニューの Terminal を非表示にするお話

Anacondaインストールフォルダ配下にある
`Lib/site-packages/notebook/notebookapp.py`を編集します。

開発環境やバージョンによるかと思いますが、
1200～1300行目あたりにある下記コードを False に変更します。
<b>
terminals_enabled = Bool(<font color="MediumVioletRed">False</font>, config=True,
</b>

```python:notebookapp.py
    terminals_enabled = Bool(False, config=True,
    #terminals_enabled = Bool(True, config=True,
         help=_("""Set to False to disable terminals.

         This does *not* make the notebook server more secure by itself.
         Anything the user can in a terminal, they can also do in a notebook.

         Terminals may also be automatically disabled if the terminado package
         is not available.
         """))
```

これで jupyter notebook / lab のメニューから Terminal が消えます。
Zipkin: AutocompleteTags機能の紹介

# はじめに

ZipkinにおいてAnnotationやTagを条件にトレース検索したい場合、AnnotationQueryを使うのが唯一の方法でした。
しかしAnnotationQueryは以下の点でユーザに負担を強いるため、初心者にとってはいささかハードルの高いものでした。

* ユーザがクエリのフォーマットを覚えなければならない
* ユーザがAnnotation名やTagのキーやバリュー値を覚えなければならない

そうした問題を解決するため、Zipkin-2.11.x 〜 2.12.xでAutocompleteTagsという機能が追加されました。
この機能を用いればTagのキーとバリューが補完されるようになり、Tag情報を用いたトレースの検索が比較的簡単になること請け合いです。

# 使い方

Zipkinの実行時に`AUTOCOMPLETE_KEYS`という環境変数に補完したいタグのキー文字列をカンマ区切りで指定するだけです。

```sh
AUTOCOMPLETE_KEYS=key1,key2,...,keyN java -jar zipkin.jar
```

# 具体例

例として[このトレース情報](https://github.com/openzipkin/zipkin/blob/336c28417e197e8a2a9230c80f91d9676e7eab73/zipkin-ui/testdata/netflix.json)を使ってみます。
このトレース内のスパンは`service_asg_name`と`service_cluster_name`という名前のキーのタグを持っているので、これらを補完してみることにします。

### 起動

上述したように起動時には環境変数`AUTOCOMPLETE_KEYS`に補完したいキー名を指定します。

```sh
AUTOCOMPLETE_KEYS=service_asg_name,service_cluster_name java -jar zipkin.jar
```

### データのPOST

JSONファイルへのパスは適宜変更してください。

```sh
curl -XPOST -H "Content-Type: application/json" http://localhost:9411/api/v2/spans -d @netflix.json
```

### 動作の確認

`localhost:9411`にブラウザでアクセスして…。

![zipkin-autocompletetags.gif](https://qiita-image-store.s3.amazonaws.com/0/149652/d220d7f6-bcd1-148c-d45b-e199738519ce.gif)

`service_asg_name`と`service_cluster_name`というキーと、それぞれに対応するバリューが補完されていることと、それらを用いて検索ができてることが確認できると思います。
Excel 全シート名取得・一覧表示 自分用メモ

※自分用メモ

# Excel 全シート名取得・一覧表示 VBA
- Excel開く
- `Alt`+`F11`で、Visual Basic Editorを起動
- `Ctrl`+`G`で、イミディエイトウィンドウを開く
- 以下ソースをコピペして、`Enter`

```vba
For Each i In ThisWorkbook.Sheets: debug.print i.name : next i
```

- シート一覧がウィンドウ内に表示されるので、後はよしなに

![image.png](https://qiita-image-store.s3.amazonaws.com/0/149342/ccbaa406-0352-0f21-da09-b8a6e4bf1037.png)
【python Flask】Xサーバーでflaskのアプリを公開したい。

flaskのクイックアプリケーションをｘサーバーで立ち上げようとしているのですが、５００エラーが出てしまい上手くいきません。参考サイト通りに進めています。
https://gakutaku.com/technology/xserver-python-flask-env/
参考サイトの手順通りでは何か足りないものがありますでしょうか。
よろしくお願いします。

目的として：
今後、開発したWebアプリをxサーバーで立ち上げたいと考えています。
CoordinatorLayoutに表示したSnackBarをスワイプで消せないようにする方法

知らなかったんですが、CoordinatorLayoutにSnackBarを表示すると、左から右へスワイプで消せるんですね。
でも、消したくない！ってこともあるので、消さないようにする方法を調べて実際に消せないようにした

# まずは消している実装を調べた
Snackbarが継承している BaseTransientBottomBar で以下のようなコードがあります。

``` java
    final void showView() {
        if (mView.getParent() == null) {
            final ViewGroup.LayoutParams lp = mView.getLayoutParams();

            if (lp instanceof CoordinatorLayout.LayoutParams) {
                // If our LayoutParams are from a CoordinatorLayout, we'll setup our Behavior
                final CoordinatorLayout.LayoutParams clp = (CoordinatorLayout.LayoutParams) lp;

                final Behavior behavior = new Behavior();
                behavior.setStartAlphaSwipeDistance(0.1f);
                behavior.setEndAlphaSwipeDistance(0.6f);
                behavior.setSwipeDirection(SwipeDismissBehavior.SWIPE_DIRECTION_START_TO_END);
                // 略
                clp.setBehavior(behavior);
                // Also set the inset edge so that views can dodge the bar correctly
                clp.insetEdge = Gravity.BOTTOM;
            }

            mTargetParent.addView(mView);
        }
```

Snackbarが使ってるViewのLayoutParamsがCoordinatorLayoutだったときだけ特別にBehaviorなるものを設定して、スワイプで消せるようにしてました。

# 消さないようにする方法
CoordinatorLayoutを使いながらも、スワイプで消さないようにするために、Behaviorを上書きするようにしました。

``` kotlin
val snackBar = Snackbar.make(binding.coordinatorLayout, message.text, length).apply {
    addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
        override fun onShown(transientBottomBar: Snackbar) {
            super.onShown(transientBottomBar)
            val lp = transientBottomBar.view.layoutParams
            if (lp is CoordinatorLayout.LayoutParams) {
                lp.behavior = null
            }
        }
    })
}
snackBar.show()
```

addCallbackで、snackBarが表示出来た後にBehaviorを上書きしてます。 `snackBar.show()` の直後だと、 `BaseTransientBottomBar.showViw()` でBehaviorが上書きされてしまうのでスワイプで消えてしまいます。
Perlのソースコード調査用のチートシート

#◆概要
調査やデバッグの際によく使う関数をメモしないで毎回記述しているため、
今回を機に、コピペ用のシートを作成。

###◆チートシート
```
#変数の表示
use Data::Dumper;
warn Dumper($self);

#呼び出し元の調査
my ($package, $file, $line) = caller;
warn 'PACKAGE:'.$package;
warn 'FILE:'.$file;
warn 'LINE:'.$line;
```

###◆関数の補足と参考にしたサイト
・Dumper
warn Dumper($xxx);を使うことで、変数でも配列でもハッシュでもデータを出力できるのでおすすめ。
http://www.omakase.org/perl/datadumper.html

・caller
callerを使うことで、そのサブルーチンがどのファイルのどの行数から参照されているか確認ができるのでおすすめ。
http://perldoc.jp/func/caller
https://qiita.com/colorrabbit/items/865f523fb606242b16f5
Nuxt.jsで高機能スライダーSwiperを使ってみた

Nuxt.jsにSwiperを入れてスライダーを使いたかったので、そのやり方を共有

## 環境

- [Nuxt.js v2.4.5](https://ja.nuxtjs.org/guide/)
- [vue-awesome-swiper v3.1.3](https://github.com/surmon-china/vue-awesome-swiper)
  
## インストール

Nuxt.jsのプロジェクト下で

```bash
yarn add vue-awesome-swiper
```

## pluginsの設定

pluginsのディレクトリにswiperを読み込み

```js:plugins/swiper.js
import Vue from 'vue'
import VueAwesomeSwiper from 'vue-awesome-swiper/dist/ssr'

Vue.use(VueAwesomeSwiper)
```

## nuxt.config.jsでの読み込み

```js:nuxt.config.js
plugins: [
    { src: '~/plugins/swiper.js', ssr: false }
],
```

これで使う準備が整いました。

## Swiperの設定

```html:pages/index.vue
<div
    v-swiper:mySwiper="swiperOption"
    class="swiper-container"
>
    <ul class="swiper-wrapper">
        <li class="swiper-slide">slide1</li>
        <li class="swiper-slide">slide2</li>
        <li class="swiper-slide">slide3</li>
        <li class="swiper-slide">slide4</li>
        <li class="swiper-slide">slide5</li>
        <li class="swiper-slide">slide6</li>
    </ul>
    <button
        class="swiper-button-prev"
        type="button"
    >
        前へ
    </button>
    <button
        class="swiper-button-next"
        type="button"
    >
        次へ
    </button>
</div>
```

```js:index.vue
export default {
    data () {
        return {
            swiperOption: {
                slidesPerView: 'auto',
                centeredSlides: true,
                spaceBetween: 50,
                loop: true,
                navigation: {
                    nextEl: '.swiper-button-next',
                    prevEl: '.swiper-button-prev'
                }
            }
        }
    }
}
```

dataプロパティにSwiperのオプションを設定。

Swiper標準のCSSを読み込む際には下記をコンポーネントで読み込んでください。  
@iwathi さんのアドバイスで追記しました！

```js
// require styles
import 'swiper/dist/css/swiper.css'
```

これでSwiperがつかえます。

## まとめ

Swiper便利ですね。このモジュール作ってくれた方に感謝
MeCabとNEologd辞書を使って「Wi-Fi」を形態素解析する

形態素解析エンジン[MeCab](http://taku910.github.io/mecab/)用の辞書[mecab-ipadic-NEologd](https://github.com/neologd/mecab-ipadic-neologd)(以下neologd)を使って、"Wi-Fi"という言葉の形態素解析を行う。
neologd は今日時点の最新版を用いている。

```
# default dictionary 
mecab
Wi-fi
Wi	名詞,固有名詞,組織,*,*,*,*
-	名詞,サ変接続,*,*,*,*,*
fi	名詞,固有名詞,組織,*,*,*,*
EOS
Wi-Fi
Wi	名詞,固有名詞,組織,*,*,*,*
-	名詞,サ変接続,*,*,*,*,*
Fi	名詞,固有名詞,組織,*,*,*,*
EOS
Wifi
Wifi	名詞,固有名詞,組織,*,*,*,*
EOS
WiFi
WiFi	名詞,固有名詞,組織,*,*,*,*
EOS
wifi
wifi	名詞,固有名詞,組織,*,*,*,*
EOS
wi-fi
wi	名詞,固有名詞,組織,*,*,*,*
-	名詞,サ変接続,*,*,*,*,*
fi	名詞,固有名詞,組織,*,*,*,*
EOS

# NEologd dictionary https://github.com/neologd/mecab-ipadic-neologd
mecab -d /usr/local/lib/mecab/dic/mecab-ipadic-neologd
Wi-fi
Wi	名詞,固有名詞,組織,*,*,*,*
-	記号,一般,*,*,*,*,*
fi	名詞,固有名詞,組織,*,*,*,*
EOS
Wi-Fi
Wi-Fi	名詞,固有名詞,一般,*,*,*,Wi-Fi,ワィファイ,ワィファイ
EOS
Wifi
Wifi	名詞,固有名詞,組織,*,*,*,*
EOS
WiFi
WiFi	名詞,固有名詞,一般,*,*,*,WiFi,ワイファイ,ワイファイ
EOS
wifi
wifi	名詞,固有名詞,一般,*,*,*,WiFi,ワイファイ,ワイファイ
EOS
wi-fi
wi-fi	名詞,固有名詞,一般,*,*,*,Wi-Fi,ワィファイ,ワィファイ
EOS
```

# 結果
- デフォルトでは"Wi-Fi"の正しい形態素解析ができない。
- neologd を使った場合、 "Wi-Fi", "WiFi", "wi-fi", "wifi"　の形態素解析は正しく行うことができるが、"Wi-fi", "Wifi" は正しく形態素解析できていない。
人生初の実装作業で詰みまくった時のメモ（Visual Studio編）

##自己紹介
・テストばかりやってたらついに実装業務を任されてしまった人
・お先は真っ暗だが最近給料が入ることで趣味に金をかけれるようになった

##経緯
前回の記事「未経験SEが突然C#をふられた時のメモ」の続きです。

案件に入ってみたら実装を任されました。
実装といっても改修だから大元はあるので一部分変更する程度。
PMからどんな改修内容なのか丁寧に説明してもらい無事理解できたところでいざ作業開始！

**まったくわからない**

まずそもそも**Visual Studioの使い方がわからん。**
ファイルあけると次から次へとファイルが出てくる。（マトリョシカなみ）
mainどこ？mainってものがそもそもあるのか？？

、、、ということで改修作業を始める前に詰んでしまいました。

##Visual Studioの超基本を調査
にっちもさっちもいかないので、とにかく調べました。

**【調べたい単語が他にどこで使われているのか見たい時】**
検索したい単語にカーソル当てて　**Ctrl + Shift + F**

**【そもそも調べたい単語が見つからない時】**
[Ctrl + Shift + F]して検索ワード内に**適当に思いつく単語を打ち込んでみる。**
例えば画像を検索したいときは[image]とか[png]とかいれると、
見つけたいものじゃなくても、**関係してそうなものは探し出せる。**

**【定義が知りたい時】**
こいつはどこで定義されてんだ？？ってときは
**F12キー**を押す。

**【どこで呼ばれてるのかを知りたい時】**
処理の内容はわかったけどこいつはどこで呼ばれてるんだろう？？ってときは
①
　**[○個の参照|名前、△日前|□人の作成者、×件の変更]**と書かれてるところの
　**○個の参照**をクリックするとそいつを参照している箇所が全部表示される。
　そこから見たいところを選ぶと飛ぶことができる。
　（Git管理してないと表示でてこないかも）

②
　探したい箇所を右クリックして**すべての参照を検索**で探すこともできる。
　（Shift + F12でもできるっぽい）


上記内容を使うことでなんとかVisual Studioで改修内容を調査することができました。
たぶんもっといい方法あるんでしょうが、私にはこれが精一杯でした...
グーグル先生といろいろ助けて下さった上司には大感謝です。

##しかしまたしても詰んでしまう
Visual Stduioの超初歩の使い方を学んだし、改修作業に取り掛かるぞ！

**コードが読めない&かけない**

またしても詰んでしまいました...

大元のコードが読めません。大問題です。
改修しなくちゃいけない箇所は上記方法で見つけられたけど、どうやって修正したらいいの？？

かなり悩みました。
そこへJava神（上司）がある言葉をかけてくださいました。

**「デバッグを何十回、何百回もやればだいたいの流れはわかるようになる」**

よっしゃ、ようわからんがデバッグを繰り返すんだな！
ってことでまたまたデバッグについて調査しました。

##デバッグってすごいんだなぁ
**【デバッグしたい時】**
ブレークポイントを付けるために**デバッグで見たい部分の左横あたりをクリックする。**
**赤い丸**が付いたらそれがブレークポイント。
あとは**F5キー**を押すか、画面上部の**再生ボタン（緑のやつ）**を押すとデバッグスタート。

ブレークポイントで止まって先の処理を見るためには**F11キー**をポチポチ押していく。
変数に何が入ったのか確かめたい時は画面下に出てくるデバッグ表示を見る、
もしくはカーソルを変数に合わせると見れる。


やり方が分かったところで、デバッグを繰り返しました。
すると、元のコードが何をやっているのかが少しずつ理解できるようになったのです！
やはりJava神はすごいなぁ。

結果的に何度も何度もデバッグしていくうちに段々と修正方法もわかり、自分なりに修正をすることもできました。
ですが、それでも技術力がなさすぎたため改修作業の大半は上司の方々の手厚いサポートのもと完成させました。

##まとめ
・Visual Studioは使っていくうちになんとなく理解できるようになる
・デバッグはすごい

ちょっと長くなったので、次回の記事でCDの部分のメモを残したいと思います。
CSSの変数で50％を扱う時の注意点

#CSSの変数ってなんや
cssの変数って便利ですよね、僕は大好きすぎて変数を沢山使って簡単にデザインをカスタマイズ出来るコードを書きます。
まぁ、そんなカスタマイズする機会が無いんだけど…。

そんなcssの変数で気になったことがあったので検証してみました。
気になることとは

**変数って結局なに？**

ってことです。
僕の語彙力が無さすぎて哲学的になってしまいましたが

例えばjavascriptで変数を扱うと

```javascript
let hennsuu_ichi=123;
let hennsuu_ni="123";
```

こんな感じで書きますよね。
`hennsuu_ichi`は数値としての123。
そして`hennsuu_ichi`は文字列としての123。
当たり前体操です。


じゃぁCSSで変数を扱ってみましょう。

```css
--nagasa_ichi:1000px;
--nagasa_ni:50%;
```

こんな感じで書きますよね。
`--nagasa_ichi`は絶対的に1000px。
どの要素にこの変数を与えても、どこでも1000pxです。

では`--nagasa_ni`はどうでしょう？
この変数に入っているのは

- 変数を与えられた要素からみた50%なのか
- 変数を書いた要素の50%なのか

僕はわからなかったので検証して確かめてみます。

#検証するか

```html
<!DOCTYPE html>
<html lang="ja">
	<head>
		<meta charset="utf-8">
		<link rel="stylesheet" href="style.css">
		<title>TEST</title>
	</head>
	<body>

		<div id="max_box">
			<div id="inner_box">
				<div id="inner_inner_box">
				</div>
			</div>
		</div>

	</body>
</html>
```

```css:style.css
#max_box{
	--max_box_width:1000px;
	--max_box_height:500px;

	--inner_box_width:50%;
	--inner_box_height:50%;

	margin:0;
	padding:0;

	width:var(--max_box_width);
	height:var(--max_box_height);

	background:#FF0000;
}
	#inner_box{
		margin:0;
		padding:0;

		width:var(--inner_box_width);
		height:var(--inner_box_height);

		background:#00FF00;
	}
		#inner_inner_box{
			margin:0;
			padding:0;

			width:var(--inner_box_width);
			height:var(--inner_box_height);

			background:#0000FF;
		}
```

`#max_box`要素が一番上の親です。
その子が`#inner_box`
更にその子が`#inner_inner_box`
になります

`#max_box`は`width:1000px`、`height:500px`です。
そして`#max_box`の要素の時点で`--inner_box_width:50%`、`--inner_box_height:50%`を書いています。

もし

- 変数を与えられた要素からみた50%である

ならば
`#inner_box`は`#max_box`の半分のサイズ。
`#inner_inner_box`は`#inner_box`の半分のサイズ
になるはずです。


逆に

- 変数を書いた要素の50%である

ならば
`inner_box`は`#max_box`の半分のサイズ。
`inner_inner_box`も`#max_box`の半分のサイズ
になるはずです。

#結果は…
![kekka.png](https://qiita-image-store.s3.amazonaws.com/0/330542/5ced66ac-a96a-6e78-ba12-968282fec7b1.png)
`#inner_box`は`#max_box`の半分のサイズ。
`#inner_inner_box`は`#inner_box`の半分のサイズ
だったので

- 変数を与えられた要素からみた50%である

とわかりました。

#まとめ
cssの変数は書いた時点でpxに変換されることなく
書いたまんまのテキストが要素に与えられる
とわかりました。
相対的なデザインをしている場合は変数がどのように影響を与えるのか理解しておくと良いですね。
JavaScriptの文字列から配列、オブジェクトから配列、配列の再構築のあれこれ

個人的によく使うのでメモがてら公開。

## 2次配列を1次配列に統合

```js
const array = [
    1, [2, 3, 4], 5
]
const flattened = array.reduce(
    (accumulator, currentValue) => accumulator.concat(currentValue),
    []
)
```

```bash:console
[ 1, 2, 3, 4, 5 ]
```

## 文字列から配列

```js
let array2 = "テキスト１,テキスト２,テキスト３,テキスト４"
array2 = array2.split(',')
```

```bash:console
[ 'テキスト１', 'テキスト２', 'テキスト３', 'テキスト４' ]
```

## 配列の中にあるオブジェクトの値の文字列を配列化

```js
const array3 = [
    { names: "テキスト１,テキスト２,テキスト３,テキスト４" },
    { names: "テキスト１,テキスト２,テキスト３" },
    { names: "" }
]
const values = array3.map((contact, index) => {
    return contact.names.split(',')
})
```

```bash:console
[
  [ 'テキスト１', 'テキスト２', 'テキスト３', 'テキスト４' ],
  [ 'テキスト１', 'テキスト２', 'テキスト３' ],
  [ '' ]
]
```

## 2次配列を1次配列にして空白の配列を削除

```js
const array3 = [
    { names: "テキスト１,テキスト２,テキスト３,テキスト４" },
    { names: "テキスト１,テキスト２,テキスト３" },
    { names: "" }
]
const values = array3.map((contact, index) => {
    return contact.names.split(',')
})
// 2次配列を1次配列に
let flattened2 = values.reduce(
    (accumulator, currentValue) => accumulator.concat(currentValue),
    []
)
// 空の要素を消す
flattened2 = flattened2.filter(function (x) {
    return !(x === null || x === undefined || x === "")
})
```

```bash:console
[ 'テキスト１', 'テキスト２', 'テキスト３', 'テキスト４', 'テキスト１', 'テキスト２', 'テキスト３' ]
```

## 同じ文字列を数えて一つに絞りオブジェクトに変換

```js
const array3 = [
    { names: "テキスト１,テキスト２,テキスト３,テキスト４" },
    { names: "テキスト１,テキスト２,テキスト３" },
    { names: "" }
]
const values = array3.map((contact, index) => {
    return contact.names.split(',')
})
let flattened2 = values.reduce(
    (accumulator, currentValue) => accumulator.concat(currentValue),
    []
)
flattened2 = flattened2.filter(function (x) {
    return !(x === null || x === undefined || x === "")
})
// ここから
let counts = {}
for (var i = 0; i < flattened2.filter(v => v).length; i++) {
    var key = flattened2[i]
    counts[key] = (counts[key]) ? counts[key] + 1 : 1;
}
const local = Object.keys(counts).map((contact, i) => {
    return { id: i, value: contact, count: counts[contact] }
}, counts)
```

```bash:console
[
  { id: 0, value: 'テキスト１', count: 2 },
  { id: 1, value: 'テキスト２', count: 2 },
  { id: 2, value: 'テキスト３', count: 2 },
  { id: 3, value: 'テキスト４', count: 1 }
]
```

## まとめ

ES2019のflat(),flatMap()早く使いたい。
オンラインカードゲームのサーバーサイドを作った④

[前回はこちら](https://qiita.com/Kakky/items/1f260b4061bde6e0a0b9)

# Deckクラスを作る
はい、今回はやっとデッキを作っていきます。
前回、折角作った紙束インターフェースをしっかり使っていきましょう。

# まずはClassを作る

```java
public class Deck{
    private Stack<Card> deck = new Stack();
}
```

はい、デッキができました。

というのは流石に冗談ですが、カードを[Stack](https://ufcpp.net/study/algorithm/col_stack.html)として持つDeckクラスができました。
ちなみにJavaのStackはListのサブクラスです。

デッキは基本的にはトップから取り出す操作しか行わないため、配列や線形リストではなくスタックを利用しました。

# CardSheafを実装する。

```java
public class Deck implements CardSheaf {

    private Stack<Card> deck = new Stack<>();

    public Deck(List<Card> deck) {
        this.deck.addAll(deck);
    }

    public Deck(Card... deck) {
        this.deck.addAll(Arrays.asList(deck));
    }

    @Override
    public int indexOf(Card card) {
        return CardSheaf.indexOf(deck, card);
    }

    //CardSheafクラスではcardSizeの標準実装を提供していないため、実装した。
    //要素数を取り出すだけ。
    @Override
    public int cardSize() {
        return deck.size();
    }

    @Override
    public void addCard(Card card) {
        CardSheaf.addCard(deck, card);
    }

    @Override
    public void removeCard(Card card) {
        CardSheaf.removeCard(deck, card);
    }

    @Override
    public void removeCard(int index) {
        CardSheaf.removeCard(deck, index);
    }

    @Override
    public Card find(int number, Card.Mark mark) {
        return CardSheaf.find(deck, number, mark);
    }

    @Override
    public int indexOf(int number, Card.Mark mark) {
        return CardSheaf.indexOf(deck, number, mark);
    }

    @Override
    public Card getCard(int index) {
        return CardSheaf.getCard(deck, index);
    }

    @Override
    public Card takeCard(int index) {
        return CardSheaf.takeCard(deck, index).getValue();
    }
}

```

Deckクラスでは、カードをListで扱うため、CardSheafのstaticメソッドをそのまま利用した。

# Deckに必要なメソッドを定義する

```java
import java.util.*;

public class Deck implements CardSheaf {

    private Stack<Card> deck = new Stack<>();

    /**
     * リスト内のカードでデッキを初期化する。
     * @param deck 初めにデッキ内に置きたいカードすべてのリスト
     */
    public Deck(List<Card> deck) {
        this.deck.addAll(deck);
    }

    /**
     * 配列内のカードでデッキを初期化する。
     * @param deck 初めにデッキ内に置きたいカードすべての配列
     */
    public Deck(Card... deck) {
        this.deck.addAll(Arrays.asList(deck));
    }

    //略
    /**
     * デッキの一番上のカードを取り出す。
     */
    public Card take_top() {
        return deck.pop();
    }

    /**
     * ゲーム開始時の先攻判定に用いる。
     * @return デッキの一番上のカード
     */
    public Card first_step() {
        return this.take_top();
    }

    /**
     * カードをドローする。
     * @return デッキの一番上のカード
     */
    public Card draw() {
        return this.take_top();
    }

    /**
     * ダメージを受けたときに呼ばれる。
     * @return デッキの一番上のカード
     */
    public Card damage() {
        return this.take_top();
    }

    /**
     * デッキをシャッフルする。
     */
    public void shuffle() {
        Collections.shuffle(deck);
    }

    /**
     * デッキ内にカードが存在するかどうかを判定する。
     * @return デッキ内にカードがあるならtrue、ないならfalse
     */
    public boolean hasCard() {
        return cardSize() > 0;
    }
}

```

では、今回はここまで。

次回は手札を実装予定です。

[次回はこちら](https://qiita.com/Kakky/items/19937f419a7699ff024e)
8bit PICマイコン開発環境構築(Windows)

最終的に量産したい（かもしれない）機器を開発する場合、簡単な機能で良く処理速度も高速じゃなくてよいなら、安価な8bitマイコンで開発するのが良いと思います。
フリーで開発環境が揃い、手が出しやすいPICマイコンですが歴史が長い分、古い情報も多い感じですので割と最新の情報で整理したいと思います。

なおUSB非対応で200円ぐらいのマイコンをバラで買ってきてハンダ付けする・・という、組み込み開発のお話ですので、開発ボード買う場合は読み飛ばせるところがチラホラあるかと思います。

# 用意するもの
1. 開発用PC
2. PICマイコンと基板（ピッチ変換基板とユニバーサル基板でもOK）
3. 発振子（セラロックと抵抗）
4. 電源（5V）
4. PICkit3（その後、PICkit4に乗り換え。ちょっと速くなりました）
5. ソフト：「MPLAB-X-IDE」と8bit-PIC用コンパイラ「XC8」。どちらもフリー。

## ソフトウェア環境の準備
Microchip社からダウンロードしておきます。
 MPLAB-X-IDE: https://www.microchip.com/mplab/mplab-x-ide
 XC8: https://www.microchip.com/mplab/compilers

### MPLAB-X-IDE
　セットアップ手順は省きます。

　MPLAB-X-IDEインストール完了時の画面で、HermonyとMCCとコンパイラが紹介されていますが、HermonyはPIC32用なので不要です。MCCもダウンロードするの？となりますが不要です（下記参照）。コンパイラはPIC18の場合次項のXC8を入れます。

　MPLAB-X-IDEが起動出来たら、メニューの[Tools] - [Plugins] から、「MCC (MPLAB Code Configurator)」というプラグインを入れます。
　ドライバのソースコードを生成してくれますので、マイコン乗り換えもラクチンになります。

こんな画面です。”MPLAB Code Configurator"にチェックを入れてInstall
![MCC.png](https://qiita-image-store.s3.amazonaws.com/0/243968/781880c4-4e85-0d62-f1b7-55dc611650c3.png)

### XC8
　セットアップ手順は省きます。

　なお、XC8 v2.00からC99対応になったようなのですが、sprintf()を使うとROMを使い切ったりしてくれるので、C90設定にしておくのが無難なようです。
(「8bit PIC の XC8 v2.* ビルドは C90で」 https://qiita.com/yukilab/items/9d6d3257c1e9b7329bab も参照)

## ハードウェアの準備
今回選んだマイコンはPIC18F46K40（その後、PIC18F46K42というのも使いました。ADCが10bitから12bitにアップしてて、いい感じです）。

まずは電源端子を接続。それから発振子を接続します。
そのまま動いてくれればよかったのですが、直結ではダメで33Ωを入れたら動きました。

肝心のデバッガとの接続は、これを見ます。（PICKitに紙が同梱されてますけどね）
http://ww1.microchip.com/downloads/jp/DeviceDoc/50002721A_JP.pdf

## ソフトの準備
　MPLAB-X-IDEで、新規プロジェクトを作成します。これも手順は省きます。

MCCを起動します。メニューの[Tools] - [Embedded] - [MPLAB Code Generator v3: Open/Close] としても良いのですが、ツールバーに「MCC」ボタンがあります。
![MCC_Start.png](https://qiita-image-store.s3.amazonaws.com/0/243968/6c1726b5-e086-75fa-c169-7ab887ff0e3b.png)
これを押すと、裏でJavaが起動するようで、時間がかかりますがじっと待ちます。

MCCが起動したら、まずは発振子の設定をします。
下記は、16MHzの発振子を接続して64MHzで動作させるときの設定例です。赤枠が設定変更箇所です。
設定したら「Generate」ボタンを押します。
![MCC_Setting.png](https://qiita-image-store.s3.amazonaws.com/0/243968/9b7a5d41-9d09-dda3-dd62-3a96d8c3cbdc.png)
間違っていると、初期化処理で発振待ちっぽいルーチンで止まります。。

動作確認が出来たら、使いたいデバイスをMCCで追加してみてください。
なお、割り込みを使う場合、main()の中に生成されてコメントアウトされている、割り込み有効化関数を有効化する必要があります。

ひとまず、これにて。
オフライン環境下にあるPCにAnaconda仮想環境を構築するお話 

<dl>
<dt>目的</dt>
<dd>オープンなネットワークへのアクセスを許容していない社内ネットワーク環境のような、クローズドな環境下にある社内サーバ・PCに対して、Anaconda仮想環境を構築するお話です。オンライン環境下であれば単純なインストールコマンドやyamlファイルからのcreateで構築可能ですが、オフライン環境下にある場合においても使い慣れたAnacondaを使って仮想環境を構築したい場合のtipsになります。</dd>
<br>
<dt>環境前提</dt>
<dd>・対象のサーバ・PCにはAnacondaが導入されている<br>
・USBメモリ・DVD等メディアや社内ネットワーク経由でサーバ・PCへのファイル転送はできる<br>
・外部インターネットに接続可能なPCが別途ある</dd>
<br>
<dt>試したオフラインPCのスペック</dt>
<dd>・Windows 10 Pro 1709<br>
・conda 4.5.0</dd>
</dl>

## 事前準備
オフライン環境下で仮想環境を構築するにあたり、インストールしたいパッケージファイルが必要になります。まずはオンライン環境下にあるPCで、同様の仮想環境を構築し、依存関係も考慮した必要なパッケージのリストやパッケージファイルそのものを入手します。

```
conda create -n [新しい仮想環境の名前] py=3.X.X
conda install [必要なパッケージを指定]
conda list でインストールされたパッケージのリストが確認できます
```

anacondaフォルダの pkgs フォルダ内にインストールしたパッケージ（tar.bz2などで圧縮されたもの）が格納されています。他の仮想環境構築時に取得されたパッケージファイルもあるので、作成日時やリストと照らし合わせて必要なパッケージをピックアップします。

それらパッケージをオフライン環境下にあるPCに、USBメモリやネットワーク経由で転送できれば、
事前準備は完了です。


## オフライン環境下での仮想環境の構築
##### 1. 仮想環境の作成

```
conda create -n new_env --offline
```

ここでは new_env という名前で作成しました。既存する仮想環境を複製しパッケージを追加する手法もできないかと思い clone を試したものの、オンライン環境が必要なのか通信エラーで上手くいきませんでした。
`※ 実行エラーとなったコマンド例
conda create -n new_env --clone [既存環境の指定]
conda create -n new_env --clone [既存環境の指定] --offline
`


##### 2. 仮想環境が作成されたことを確認

```
conda env list
```
新たに作成した new_env がリストにあれば◎
##### 3. 仮想環境 new_envをアクティブに

```
activate new_env
```
アクティブのやり方は環境に合わせて実施ください
`source activate new_env
conda activate new_env`

##### 4. new_env環境にあるインストール済みパッケージの確認

```
conda list
```
と、やってみるとこの段階ではパッケージが1つもない空の状態でした。
試しに 「python」とコマンドを叩いてみると起動しますが、これは「base」環境のpythonが呼び出されているだけのようです。

##### 5. Pythonのインストール
ここから事前に準備したパッケージファイルを使い、インストールしていきます。
まずは Python をインストール

```
cd [パッケージファイルを集めたフォルダ]
conda install python-3.X.X-XXXXXX.tar.bz2
```

##### 6. その他パッケージのインストール
以降、ものぐさな私は下記コマンドでとりあえず一括インストールしています。
このやり方で特に問題は発生していませんが、厳密に検証したこともないので
ここは各々のご判断で。jupyter notebookとかはこの一括インストールで問題なく動いてくれています。

```
for /f %i in ('dir /A-d /B *.tar.bz2') do conda install %i
```
↑ dirコマンドで取得した .tar.bz2 のファイル一覧 を1行ずつ conda install の引数に指定するwindowsのコマンドです。Linuxでいう xargs みたいなものです
##### 7. インストールされたパッケージの確認
conda list で確認してみると、インストールされたパッケージがずらっと表示されるはずです。
必要なパッケージが正しくインストールされていることを確認したら、
オフライン環境での仮想環境構築はこれにて完了です。
kubectl コマンド集

# 良く使うコマンドたち
#### リスト表示
##### Pod
`kubectl get pods`
##### Service
`kubectl get svc`

#### ポートフォワード
`kubectl port-forward svc/サービス名 ポート番号:ポート番号`

#### 作成
##### Pod
`kubectl apply -f ファイルパス`
##### Namespace
`kubectl create namespace 名前空間名`

#### 消去
##### Pod
`kubectl delete pod Pod名`
##### Pod完全消去
`kubectl delete pods Pod名 --grace-period=0 --force`
[ dockerコンテナ内 ] にいるか判別してプロンプトをわかりやすく 【Ubuntu】

# 結論
.bashrcと.bashrc_profileファイルに以下を追加すればOK.

```:.bashrc
if [ -f /.dockerenv ]; then
    PS1='[${debian_chroot:+($debion_chroot)}\u@\h:\w]\$'
fi
```
```:.bash_profile
source ~/.bashrc
```
# 補足
dockerコンテナを立ち上げると自動的にコンテナ内に.dockerenvというファイルが作られるので、そのファイルがあるかどうか判別して、あるときだけプロンプトに[　]を追加.

```:dockerコンテナ内
[user@hostname:/]$cd /
[user@hostname:/]$ls -la
total 96
drwxr-xr-x   1 root root 4096 Mar  4 11:08 .
drwxr-xr-x   1 root root 4096 Mar  4 11:08 ..
-rwxr-xr-x   1 root root    0 Mar  4 11:07 .dockerenv
drwxr-xr-x   1 root root 4096 Feb  3 16:39 bazel
drwxr-xr-x   2 root root 4096 Oct 18 21:03 bin
drwxr-xr-x   2 root root 4096 Apr 24  2018 boot
drwxr-xr-x   5 root root  460 Mar  7 07:05 dev
drwxr-xr-x   1 root root 4096 Mar  7 07:05 etc
drwxr-xr-x   1 root root 4096 Mar  4 11:08 home
-rw-r--r--   1 root root  782 Sep 13 18:12 intelpython3-2019.0-047_amd64.deb
drwxr-xr-x   1 root root 4096 Nov 13 00:13 lib
drwxr-xr-x   2 root root 4096 Oct 18 21:02 lib64
drwxr-xr-x   2 root root 4096 Oct 18 21:02 media
drwxr-xr-x   2 root root 4096 Oct 18 21:02 mnt
drwxr-xr-x   1 root root 4096 Feb  3 18:04 opt
dr-xr-xr-x 411 root root    0 Mar  7 07:05 proc
drwx------   1 root root 4096 Feb  3 18:03 root
drwxr-xr-x   1 root root 4096 Mar  4 11:08 run
-rwxr-xr-x   1 root root  733 Jan  9 08:00 run_jupyter.sh
drwxr-xr-x   1 root root 4096 Jan  9 08:00 sbin
drwxr-xr-x   2 root root 4096 Oct 18 21:02 srv
dr-xr-xr-x  13 root root    0 Feb  2 13:11 sys
drwxrwxrwt   1 root root 4096 Mar  4 11:08 tmp
drwxr-xr-x   1 root root 4096 Oct 18 21:02 usr
drwxr-xr-x   1 root root 4096 Feb  3 16:40 var
drwxr-xr-x   1 root root 4096 Feb  3 18:04 workspace
```
Windows Server RDS/VDI ドメインなしでのRemoteAPP資料など

##RDS/VDI概要
・MSのパワポ資料　Windows Server 2012 RDS/VDI 機能紹介　※直リンク
http://download.microsoft.com/download/F/6/B/F6B373D4-B116-4136-AF11-20B64ABD09B0/ws12_rds_vdi.pptx

・情報処理学会PDF資料　Windows Server 2012 R2 完全解説　※直リンク
http://itlib1.sakura.ne.jp/test380/pdfichuran/0275/001-remote.pdf


##導入ガイド
・Windows Server2012　
https://download.microsoft.com/download/0/7/B/07BE7A3C-07B9-4173-B251-6865ADA98E5D/WS2012_RDSVDI_EvalGuide.pdf

・Windows Server2012 R2　※直リンク
https://download.microsoft.com/download/B/2/0/B20A660F-787F-4C17-8CE6-35E9789E2CB1/Windows-Server-2012-R2-Evaluation-Guide.pdf


##その他
・簡易リモート
http://www.vwnet.jp/Windows/w10/2016072001/RemoteApp.htm

・非ドメイン環境で RemoteApp を使う
http://kendik.hatenablog.com/entry/2014/09/03/002908

・ADS（Active Directory）サーバー に RDS を構成する方法
https://www.projectgroup.info/tips/Windows/WindowsSvr2012_0016.html

・Windows Server 2012 リモート デスクトップ環境の構成について
https://docs.microsoft.com/ja-jp/archive/blogs/askcorejp/windows-server-2012

・Windows 2016 非ドメイン環境（WORKGROUP）でRDWebサービス構築をしたい
https://teratail.com/questions/159674

・Microsoft RemoteAppで業務アプリを仮想化して使う
https://devlog.grapecity.co.jp/entry/2018/6/29/support-microsoft-remoteapp

・リモートデスクトップサービス : RemoteApp を公開する
https://www.server-world.info/query?os=Windows_Server_2016&p=remotedesktop&f=5

・https://eit.systems/remoteapp%E3%81%AE%E6%A7%8B%E7%AF%89%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6/
https://eit.systems/remoteapp%E3%81%AE%E6%A7%8B%E7%AF%89%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6/

・Windows 10時代のアプリ互換性問題は、RemoteAppが救世主になるかも
https://www.atmarkit.co.jp/ait/articles/1602/05/news036.html
インドネシアで SORACOM + LoRa を使いました。

# ジャカルタに行ってきました
ジャカルタは大都会です。ホテルから見ると立ち並ぶビルを見ることが出来ます。そして、世界一悪い道路事情（交通渋滞）。歩いているとのどが痛くなります。日曜日はすいているのでタクシーで移動です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/99921/da263261-3889-854d-260c-3fda650a83b6.png)

# SORACOM でつなぐ
SORACOM にはワールドワイドでつながる SIM というのがあって、それを使いました。ぶっつけ本番だったのですがうまくいきました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/99921/28a31519-588b-3f41-b6c3-ada65615bcff.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/99921/c0dadf0e-39c3-ee60-8fb4-fdf5d92e7768.png)

Linux + USB ドングルです。wvdial をつかいました。ほとんど、日本の設定でいけます。電話番号くらいかな？変えたのは。wvdial.conf を修正しました。

ついでに現地の SIM も試しました。こちらも問題なく動作。

# 現地ファームも視察
モチベーションとしては、作物などをつくるときのデータ収集です。現地のファームというのも見てきました。
![firm.jpg](https://qiita-image-store.s3.amazonaws.com/0/99921/5a21594e-dd33-c436-ed3d-9c7833c8087b.jpeg)

# LoRa もついでに
LoRa -> Linux -> SORACOM -> Azure -> iPAD できるでしょうか？日本で作ったアプリを動かしてみます。見える化には grafana を Azure(Ubuntu) で動かしています。Docker とかつかってます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/99921/d1e71954-fae6-3501-bd1e-e77b782b67e7.png)

うまくいきました！！！

# 今後はビジネス展開！？
なにか進捗があったらまた情報を展開しましょう。
NLTKを使えるようにする

nltk.download('punkt')
でやろうとして、

[nltk_data] Error loading punkt: <urlopen error [Errno 11001]
[nltk_data]     getaddrinfo failed>

というエラーが出たので、色々調べた。

会社のプロキシをAnaconda promptで通した後、

python -m nltk.downloader -u https://raw.githubusercontent.com/glowskir/nltk_data/7b505ff1f858a489e5b2d879573bdaaa8ef06732/index.xml punkt

を入力したら、動くようになった。
GCPのDeep Learning VMインスタンスを立ち上げる

DeepLearningVMのインスタンスの立ち上げに一部手間取ったのでメモ。

# はじめに
下記のページに沿ってインスタンスを立ち上げようとしましたが、「Create a new instance」の「7.Click Deploy.」を実行した時点でエラーが発生しました。

[手順の参考ページ]
https://cloud.google.com/deep-learning-vm/docs/quickstart-marketplace

```text:エラー内容1
deeplabv3plus-1-vm: {"ResourceType":"compute.v1.instance",
"ResourceErrorCode":"403",
"ResourceErrorMessage":{"code":403,"errors":[{"domain":"usageLimits",
"message":"Quota 'GPUS_ALL_REGIONS' exceeded. Limit: 0.0 globally.",
"reason":"quotaExceeded"}],
"message":"Quota 'GPUS_ALL_REGIONS' exceeded. Limit: 0.0 globally.",
"statusMessage":"Forbidden",
"requestPath":"https://www.googleapis.com/compute/v1/projects/test-vegetation-map/zones/us-central1-a/instances",
"httpMethod":"POST"}}
```

```text:エラー内容2
{"ResourceType":"compute.v1.instance",
"ResourceErrorCode":"403",
"ResourceErrorMessage":{"code":403,"errors":[{"domain":"usageLimits",
"message":"Quota 'GPUS_ALL_REGIONS' exceeded. Limit: 0.0 globally.",
"reason":"quotaExceeded"}],
"message":"Quota 'GPUS_ALL_REGIONS' exceeded. Limit: 0.0 globally.",
"statusMessage":"Forbidden",
"requestPath":"https://www.googleapis.com/compute/v1/projects/test-vegetation-map/zones/us-central1-a/instances",
"httpMethod":"POST"}}
```

# 原因
GPUの割り当て上限数の設定は2種類あります。
（語弊のある表現ですが、ここまで読んで「GPUの上限数の設定はしたんだよ！」とこの記事を閉じてしまわないために、まずは敢えてこう書きました。）

正確には、「各リージョンで作成するGPUモデルに対する割り当て」に加え、「すべてのゾーンにおけるすべてのタイプのGPUの総数に対するグローバル割り当て」もリクエストする必要がありました。
[参考]
https://cloud.google.com/compute/quotas#gpus

# 解決策
#### 1. 各リージョンで作成するGPUモデルに対する割り当て
こちらの設定は、この記事を読んでいる皆さんは既に完了しているかもしれません。

1. 先ほどのページ[(https://cloud.google.com/compute/quotas#gpus)](https://cloud.google.com/compute/quotas#gpus)の「[割り当て] ページ」のリンク先へ飛ぶ。（※もしくは「GCPの左上のハンバーガーメニュー（横三本線のマーク）＞IAM と管理＞割り当て」と進む。）
2. 「指標」のプルダウンボタンをクリックし、使用したいGPUの名前にチェックを入れる。
3. 「場所」のプルダウンボタンをクリックし、使用したいリージョンの名前にチェックを入れる。
4. 使用したいリージョンの、使用したいGPUの上限数が使用予定数を上回っていることを確認する。
5. 上限数が足りていなかった場合は「割り当てを編集」よりリクエストを投げましょう。早いと1時間程度でリクエストした条件が反映されます。

<img width="1014" alt="スクリーンショット 2019-03-07 16.08.08.png" src="https://qiita-image-store.s3.amazonaws.com/0/205347/6085d608-b8cf-1812-1500-dc034418fcf8.png">





#### 2. すべてのゾーンにおけるすべてのタイプのGPUの総数に対するグローバル割り当て
こちらを見落としていました。

1. 上記1.と同様、「割り当て」ページへ移動する。
2. 「指標」プルダウンボタンをクリックし、「GPUs (all regions)」という選択肢にチェックを入れる。
3. 「場所」のプルダウンボタンをクリックし、「グローバル」にチェックを入れる。
4. 上限数を確認しましょう。デフォルトでは0になっているはずです。
5. 上限数が「すべてのリージョンにおけるすべてのタイプのGPUの総数」を下回っている場合、「割り当てを編集」よりリクエストを投げましょう。早いと1時間程度でリクエストした条件が反映されます。

<img width="1043" alt="スクリーンショット 2019-03-07 16.08.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/205347/0b7768cb-7ca5-a843-9c7e-dd3d8c6fb5ea.png">

以上。
hostsファイルを変更しても反映されない

#hostsファイルを変更しても反映されない。
##事象
社内システムのサーバー変更に伴いhosts変更したが、反映されない。
以下のコマンドを打って反映状況を確認したが旧アドレス

* ping <ipアドレス>　・・・新旧どちらも接続可能
* ping <ホスト名>　・・・旧アドレスにpingしている
* ipconfig flushdns　・・・クリア。正常終了する。
* ping <ホスト名>　・・・旧アドレスにpingしている

##原因
hostsファイルのエンコード、改行コードがCRになっていた。
本来はCRLFであるべき。

* CRLF　：　↵　☆
* CR　　：　←　★
* LF　　：　↓

##対処
秀丸エディタからファイル→エンコードの種類で確認。CRLFを選択。
また、不要な改行が大量に入った状態となっていたため、改行詰めを行った。
その後、以下を確認。
問題なく新アドレスにpingできた。

* ipconfig flushdns　・・・クリア。正常終了する。
* ping <ホスト名>　・・・新アドレスにpingしている。


##埋込原因
不明。どっかで変なふうに開いたのかな。
Azure Functions (Java) でデプロイメントスロットを使ってスワップする

Functions(Java)は ```mvn azure-functions:deploy``` コマンドでデプロイします。
本番用のFunctionsにいきなりデプロイされちゃうので、一度ステージング用のスロットにデプロイして、問題ないか確認して、スワップ（リリース）というやり方ができないか検討しました。

現時点では、azure-maven-pluginsがデプロイメントスロットに対応していないため、mvnコマンドで他のスロットにデプロイすることはできませんでした。
代替策として、zipファイルをazコマンドでアップロードするやり方でうまくいったので手順を残しておきます。

ちなみに、FunctionsのJavaはGAされましたが、デプロイメントスロットはプレビュー機能です。

# Functionsを準備する

* [Java と Eclipse を使用して初めての関数を作成する ](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-create-maven-eclipse) あたりを参考に、サンプルアプリをデプロイします。

* 動作確認しておきます。```https://[Function App Name]/api/HttpTrigger-Java?name=java``` にアクセスして、```Hello, java``` と表示されたらOKです。

# デプロイメントスロットを準備する

* 該当のFunctionsを選択して、スロットの＋ボタンを選択します。  
![image.png](https://qiita-image-store.s3.amazonaws.com/0/180335/3dadd212-cb69-1913-046d-e7502c712b0f.png)

* 任意のスロット名を入力して作成します。  
![image.png](https://qiita-image-store.s3.amazonaws.com/0/180335/29ab2865-98b3-6dad-d58a-37e4f75aed81.png)

* スロットが追加されます。これで準備OKです。  
![image.png](https://qiita-image-store.s3.amazonaws.com/0/180335/7f0fc78b-385f-2257-61a1-7c32f2903869.png)

# コードを修正してzipファイルを準備する  

* サンプルプログラムを修正します。今回は ```Hello, Java``` と表示されるところを、 ```Staging, Java``` と表示されるように変更しました。  
* ```mvn clean package``` コマンドを実行します。  
* ```target/azure-functions/[Function App Name]/``` フォルダに移動すると、jarファイルやjsonファイルがあるので、local.settings.json以外の全てのフォルダやファイルを選択して、zipファイルにします。  
 ここもうちょっといいやり方があれば教えてください・・・

# AZコマンドでZipファイルをデプロイする

* 以下のコマンドを実行してZipファイルをデプロイします。

```
az webapp deployment source config-zip -g [リソースグループ名] -n [Functionアプリ名] --slot [Slot名] --src [zipファイル名]
```

* 動作確認しておきます。 それぞれアクセスすると以下のような結果になります。
    * 本番環境 ```https://[Function App Name]/api/HttpTrigger-Java?name=java```
        * 出力結果  ```Hello, java``` 
    * ステージング環境 ```https://[Function App Name]-stg.azurewebsites.net/api/HttpTrigger-Java?name=java```
        * 出力結果  ```Staging, java```

# 本番とステージングをスワップする

* stgスロットの[スワップ]を選択します。  
![image.png](https://qiita-image-store.s3.amazonaws.com/0/180335/9341b666-aabf-34cd-e018-8b0ec1e940e9.png)

* ソースがstg、ターゲットが本番用になっていることを確認して[スワップ]ボタンを押します。  
![image.png](https://qiita-image-store.s3.amazonaws.com/0/180335/e8b99292-9cb6-1c22-5fab-417d5f76eb0e.png)

* 動作確認します。 先程の結果とは逆になっていれば問題なくスワップできています。
    * 本番環境 ```https://[Function App Name]/api/HttpTrigger-Java?name=java```
        * 出力結果  ```Staging, java```
    * ステージング環境 ```https://[Function App Name]-stg.azurewebsites.net/api/HttpTrigger-Java?name=java```
        * 出力結果  ```Hello, java``` 

# まとめ

手動でやるのはめんどくさいですね。
CIにのせたりして自動化させないと厳しそうです。
今後mavenプラグインでスロットにデプロイできるようになることに期待します。
【C#】フォーマット出力を使ってコードをすっきりさせる



ある文字列を出力したいときに、こんな感じで書いてみました。
(Visual Studio 2017・C#)

```test.cs
string alert  = "これは間違いなので確認してください(列番号 : ";
int    number = 1;

System.Console.WriteLine(alert + number.ToString() + ")");

// 実行結果
// これは間違いなので確認してください(列番号 : 1)

```

これでも意図した実行結果にはなるものの、
`System.Console.WriteLine(alert + number.ToString() + ")");`
の部分がちょっと読みにくいですよね。

なので、フォーマット出力に変換します。

```test.cs
string alert  = "これは間違いなので確認してください(列番号 : ";
int    number = 1;

System.Console.WriteLine("{0}{1})", alert, number);

// こんな方法もあります1(by @albireo さん)
System.Console.WriteLine($"{alert}{number})");

// こんな方法もあります2(by @shoe0227 さん)
ちょっと変数を変えて
var    number = 1;
string alert  = "これは間違いなので確認してください(列番号 : {0})";
System.Console.WriteLine(alert, number);

// 実行結果
// これは間違いなので確認してください(列番号 : 1)

```

比べてみると

`System.Console.WriteLine(alert + number.ToString() + ")");`
↓
`System.Console.WriteLine("{0}{1})", alert, number);`
`System.Console.WriteLine($"{alert}{number})");`
`System.Console.WriteLine(alert, number);`


不要な情報が減って見やすくなりました！

- 文字列が長い
- 変数が長い
- 型変換が必要

といったときにはフォーマット出力がおすすめです。
RAD Studio/Delphi/C++Builder 10.3 Rio の手動アンインストール 

この記事は、以前書いた [RAD Studio/Delphi/C++Builder 10.3 Rio の手動アンインストール] (http://support.embarcadero.com/article/44786) の記事が見れなくなったため転記したものです

原因不明な事象が発生した際、インストールした製品をアンインストールし、クリアする手順です

##### 1. コントロールパネルの[プログラムと機能]で、以下のプログラムをアンインストールします

- Embarcadero RAD Studio 10.3
- RAD Studio 10.3 バージョン 20.0
 
「Embarcadero InterBase 2017」のアンインストールは任意です
InterBase 2017をアンインストールしない場合は、再インストール時にインストールされる機能から InterBase 2017 を外し、上書き/別インスタンスでのインストールが行われないようにします

##### 2. 以下のフォルダ、ファイル、レジストリキーが存在している場合は削除します

 - C:\Users\Public\Documents\Embarcadero\Studio\20.0\CatalogRepository フォルダを削除
 - Windows 32-bit の場合 C:\Program Files\Embarcadero\Studio\20.0 フォルダを削除
 - Windows 64-bit の場合 C:\Program Files (x86)\Embarcadero\Studio\20.0 フォルダを削除
 - C:\Users\Public\Documents\Embarcadero\Studio\20.0 フォルダを削除
 - C:\ProgramData\Embarcadero\Studio\20.0 フォルダを削除
 - %APPDATA%\Embarcadero\BDS\20.0 フォルダを削除
 - C:\ProgramData\ 内の GUID 名が付けられた次のフォルダがあれば削除
    {426A3606-6CB8-4CF8-87A8-44388377C47D} (メインインストーラ)
 - HKEY_CURRENT_USER\SOFTWARE\Embarcadero\BDS\20.0 レジストリキーを削除
 - HKEY_CURRENT_USER\SOFTWARE\Embarcadero\ProductIDs 内の 8220 のキーを削除

 - Windows 32-bit OS の場合
    - HKEY_LOCAL_MACHINE\SOFTWARE\Embarcadero\BDS\20.0 レジストリキーを削除
    - HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{BC75D23E-8A89-4FEF-AFD1-AE110ED83630} レジストリキーを削除
    - HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{DB8A20E2-A030-4B16-B69B-16E67DFFA8C5}_is1 レジストリキーを削除
    - HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Embarcadero RAD Studio 10.3 レジストリキーを削除
    - C:\Windows\System32\ フォルダ内の次のファイルを削除 BDEAdmin.*

 - Windows 64-bit OS の場合
    - HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Embarcadero\BDS\20.0 レジストリキーを削除
    - HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{BC75D23E-8A89-4FEF-AFD1-AE110ED83630} レジストリキーを削除
    - HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{DB8A20E2-A030-4B16-B69B-16E67DFFA8C5}_is1 レジストリキーを削除
    - HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Embarcadero RAD Studio 10.3 レジストリキーを削除
    - C:\Windows\SysWOW64\ フォルダ内の次のファイルを削除します。BDEAdmin.*

##### 3. フィールドテストを行ったマシンに製品版をインストールする場合は、以下も実施します ( フィールドテスト以外の場合でも実施されることをお勧めします )

 - %PUBLIC%\Public Documents\Embarcadero\Studio\20.0 からサンプルファイルを削除
 - %PUBLIC%\Public Documents\Embarcadero\Studio\dbExpress\20.0 からDBExpress の接続設定ファイルを削除
 - アンインストールの前、又は RAD Studio 10.3 のインストールの際に、ライセンスマネージャを使用し、Carnival のライセンスを削除
 - もし、最初の手順（コントロールパネルからのアンインストール）で問題が発生した場合は、マイクロソフトから提供されている [Fix it](https://support.microsoft.com/ja-jp/help/17588/fix-problems-that-block-programs-from-being-installed-or-removed) を利用します

##### トライアル版から製品版に切り替える際は、1. の手順の前に <インストールフォルダ>\bin\licenseManager.exe を起動して、トライアルのライセンスを削除する
Git初歩の初歩

まさか「[みんなで逮捕されようプロジェクト](https://github.com/hamukazu/lets-get-arrested)」でGitを覚える羽目になろうとは。

リポジトリをローカルに複製すること（clone）と、ローカルリポジトリの変更をリモートリポジトリへ反映すること（push）以外はSubversionとだいたい一緒。

# リポジトリの複製

```bash:
$ git clone https://github.com/cress-cc/lets-get-arrested.git
```

ローカルに`lets-get-arrested` というディレクトリが作成される。以降の作業はここで行う。

```bash:
$ cd lets-get-arrested
```

# ブランチ作成

## 既にあるブランチの確認

```bash:
$ git branch -a
```

## 作業ブランチ切り替え

masterをもとにブランチを作成するので、masterに切り替える。

ちなみに、GitHubで`gh-pages`というブランチを作成すると、 https\://cress-cc.github.io/lets-get-arrested [^1]のような形式のURLでアクセスできるようになる。

```bash:
$ git checkout master
```

## 新規ブランチ作成

```bash:
$ git checkout -b gh-pages
```

## リモートリポジトリへ反映

```bash:
$ git push -u origin gh-pages
```

# ローカル変更の反映

## アカウント設定

いきなりコミットしようとしたら「誰だオメー」って怒られてしまったので、氏名とメールアドレスを設定。

```bash:
$ git config --global user.email "*****@cress.cc"
$ git config --global user.name "Cress"
```

## ローカルリポジトリへのコミット

```bash:
$ git commit -m "First commit."
```

## リモートリポジトリへ反映

```bash:
$ git push -u origin gh-pages
```

[^1]: 中身は昨今問題となっている無限ループのJavaScriptなので、うっかり開いてしまっても警察に通報したりしないでくださいね。
fitbit API の利用フロー整理

# はじめに
apiを利用するにあたり認証フローとエンドユーザの情報管理がよくわからなかったので整理しました。

# やりたいこと
- fitbitデータを扱うwebアプリケーションの開発
- ユーザのfitbitデータ（心拍数含む）を、定期的に取得

# 制約
- [OAuth2.0](https://dev.fitbit.com/build/reference/web-api/oauth2/)
    - サポートされているのはAuthorization Code GrantとImplicit Grantの2種類
    - web applicationはAuthorization Code Grantを推奨
    - Implicitが使えるのはApplication TypeがClientのみ
    - Authorization Code Grantはaccess tokenの有効期限が8時間
- [Heart Rate](https://dev.fitbit.com/build/reference/web-api/heart-rate/)
    - Intraday Time SeriesはApplication TypeがPersonalのみ

# API利用フロー
- 上記制約により以下の2つに従うことにします。
    - Application TypeはPersonalでかつAuthorization Code Grantを利用
    - 8時間に1度ユーザにaccess tokenを再発行させるのは困難なため、refresh tokenを使って定期的にデータを取得
![img1.png](https://qiita-image-store.s3.amazonaws.com/0/271751/f3c47606-f275-8840-ba88-9be96f719b8c.png)
![img2.png](https://qiita-image-store.s3.amazonaws.com/0/271751/182ae785-e32f-a051-e239-831b08249ecc.png)
※図は一部パラメータを省略しています。

- コメント
    - client idとclient secretをセキュアに管理しないといけないです。
macOS+homebrew : C++でopencv4

ビルドできなくてえらい苦労したのでメモ

## 導入
    brew install opencv

```
> brew info opencv
opencv: stable 4.0.1 (bottled)
Open source computer vision library
https://opencv.org/
/usr/local/Cellar/opencv/4.0.1 (679 files, 226MB) *
  Poured from bottle on 2019-03-07 at 12:11:25
From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/opencv.rb
==> Dependencies
Build: cmake ✔, pkg-config ✔
Required: eigen ✔, ffmpeg ✔, jpeg ✔, libpng ✔, libtiff ✔, numpy ✔, openexr ✔, python ✔, python@2 ✔, tbb ✔
==> Analytics
install: 13,231 (30 days), 53,429 (90 days), 231,530 (365 days)
install_on_request: 12,353 (30 days), 48,865 (90 days), 212,007 (365 days)
build_error: 0 (30 days)
```

## ソース
```sample1.cc
#include <opencv2/opencv.hpp>

int main(int argc, char* argv[])
{
  //cv::Mat image = cv::Mat::zeros(100, 100, CV_8UC3);
  cv::Mat image = cv::imread("sample.jpg");
  cv::imshow("sample1", image);
  cv::waitKey(0);
  return 0;
}
```

ビルドオプションに `-std=c++11`を付けること。

```Makefile
CXX=g++
CXXFLAGS= -Wall -std=c++11 `pkg-config opencv4 --cflags`
OPENCV_LIBS= `pkg-config opencv4 --libs`

all: sample1

sample1: sample1.o
	$(CXX) -g -o $@ $^ $(OPENCV_LIBS)

clean:
	rm -f sample1 *.o *~

.PHONY: all clean
```

cmakeで書くならこう

```CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
find_package(PkgConfig)

project(SampleProject)

pkg_check_modules(OPENCV4 REQUIRED opencv4)

#
# sample1
#

add_executable(sample1
  sample1.cc)

target_include_directories(sample1
  PUBLIC
  ${OPENCV4_INCLUDE_DIRS})

target_link_libraries(sample1
  PUBLIC
  ${OPENCV4_LDFLAGS}
)

target_compile_features(sample1
  PUBLIC
  cxx_std_11)

target_compile_options(sample1
  PUBLIC
  -Wall
  )
```
Expo で OTAアップデートのタイミングをアプリの再起動だけでなく、foregroundになった時にする

# やること
OTAアップデートが、アプリの再起動だけだとアプリを閉じる習慣のない人だと全然更新されなかったりするので、アプリがforegroundになった時にもアップデートさせるようにする

# やりかた
https://forums.expo.io/t/ota-updates-download-event-not-fired/9835/6

`Updates.checkForUpdateAsync()`でアップデートを確認し、`Updates.fetchUpdateAsync()`してreload