OmniAICreator/Qiita-1.07M huggingface dataset:
[C/C++ポインタ] int *p; と宣言したとき。

#はじめに
以下のように変数宣言しました。

```C++:main.cpp
int data1 = 8; /* data1の宣言、初期化 */
int *p; /* ポインタpの宣言 */
p = &data1; /* ポインタpの初期化 */
```
このとき、`&p`、`*p`、`p`の違いは何でしょうか。

#環境

- OS : Ubuntu 18.04 LTS
- コンパイラ : g++ 7.4.0

#`&p`
ポインタ`p`自身のアドレス

#`*p`
ポインタ`p`が指す`data1`

#`p`
ポインタ`p`が指す`data1`のアドレス

#上記のように結論付けた理由

###ソース
```C++:main.cpp
#include <iostream>

using namespace std;

int main(void){

	int data1 = 9;
	int *p;
	p = &data1;

	int **pp = &p;

	cout << "  data1 : " << data1 << endl;
	cout << "     *p : " << *p << endl;

	cout << " &data1 : " << &data1 << endl;
	cout << "      p : " << p << endl;

	cout << "     &p : " << &p << endl;
	cout << "    　pp : " << pp << endl;

return 0;
}
```

###実行結果
```
  data1 : 9
     *p : 9
 &data1 : 0x7ffe3d5cc094
      p : 0x7ffe3d5cc094
     &p : 0x7ffe3d5cc098
    *pp : 0x7ffe3d5cc098
```

#終わりに
何かご指摘があれば遠慮なくコメントしてください。
CounterFactual Machine Learning勉強会 #4 聴講メモ

# 概要

[CounterFactual Machine Learning勉強会 #4](https://cfml.connpass.com/event/155167/)

> 近年因果推論の知識を機械学習に応用したり、逆に因果推論の為に機械学習を応用するといった方法論が提案されています。 この勉強会はCounterfactual Machine Learningと呼ばれるこれらの手法に関する研究や実例の紹介を行う事を目的としたものです。


[以前(CFML勉強会 #1)の聴講メモ](https://qiita.com/calderarie/items/894f10652fd5a3f86a90)

# 各発表とそのメモ

各発表について、気になったところのメモを掲載します。
後日資料が追加されていたら、リンクも追記します。

なお、本勉強会では、Off Policy learningの研究最前線についての発表もありましたが、事前知識がなくあまりまとまっていないので、ここで公開は控えます。

## Delayed Feedback meets CFML

- RTBと機械学習
    - アクセスが発生した瞬間に、広告枠にどの広告主の広告を出すか、効果測定して決定
    - クリックされる確率(CTR)と売り上げが発生する確率(CVR)から最適化する

    - 予測モデルは、ログデータを基にモデルを学習する
    - 運用上、一定期間ごと(例えば1日)にモデルを学習して差し替える

- Delayed Feedback
    - CTしてからCVまでは時間がかかる場合がある
        - 特に高額商品の購買などは検討時間があり、時間がかかる傾向
    - そのため、学習時に、ログ上にCVが発生していない可能性があり、学習データで得られるCVと真に予測したいCVに乖離がある

- CFMLなアプローチの解説
    - 予測モデルの真のCVに対する損失を最小化したい
    - 過去のDelayed Feedbackの傾向(S)を基に、IWを算出するし、バイアスを除く
    - オフライン・オンライン共に、既存手法より良い性能

## Unbiased Recommender Learning from Biased Implicit Feedback

- Implicit Feedbackを用いた推薦システムの定式化
    - 推薦システム「ユーザに対して関連性がある商品を推薦したい」
        - Pointwiseアプローチ：ユーザ・アイテム間の関連性(Relevance)に基づく損失から最適化
        - Pairwiseアプローチ：アイテム間の関連性の順序関係を最適化
    - ClickをRelevanceで代替するには
        - 損失関数を計算する際、関連性(Relevance)を必要だが、コストがかかる
        - Click情報のようなImplicit Feedbaskは容易に手に入るので使いたい
        - しかし、必ずしもClickとRelevanceは一致しない
        - Exposure Modelによって、Clickの発生プロセスをおく
            - Clickの有無 = Exposure(曝露)の有無 * Relevanceの有無
    - Click情報のみで、Relevanceを導く最適化問題
        - Positive-Unlabeled / Missing-Not-At-Randomの問題
        - 真にRelevanceだが、Click情報がないケースがある

- 基本的な手法の紹介と整理
    - Weighted Matrix Factorization(WMF)
        - Positive-Unlabeledを取り扱えない
    - Bayesian Personalized Ranking(BPR)
        - Positive-Unlabeledを取り扱えない
    - Relevance Matrix Factorization
        - Pointwise Lossに対して、Exposure確率の逆数で重み付けする
    - Unbiased Bayesian Personalized Ranking
        - Pairwise Lossに対して、Exposure確率の逆数で重み付けする
    - 真のExposure確率の推定は、情報検索周りで手法が色々ある
        - Item popularityで代用するのがナイーブ
11. タブをスペースに置換

## 11. タブをスペースに置換
タブ1文字につきスペース1文字に置換せよ．確認にはsedコマンド，trコマンド，もしくはexpandコマンドを用いよ．

###Go
```go
package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
)

func main() {
	//	読み込みファイルを指定
	name := "../hightemp.txt"

	//	読み込むファイルを開く
	f, err := os.Open(name)
	if err != nil {
		fmt.Printf("os.Open: %#v\n",err)
		return
	}
	defer f.Close() //	終了時にクリーズ

	//	スキャナライブラリを作成
	scanner := bufio.NewScanner(f)

	//	データを１行読み込み
	for scanner.Scan() {
		//	TAB を 空白へ置換
		fmt.Println(strings.Replace(scanner.Text(),"\t"," ",-1))
	}

	//	エラーが有ったかチェック
	if err = scanner.Err(); err != nil {
		fmt.Printf("scanner.Err: %#v\n",err)
		return
	}
}
```


###python
```python
# ファイルを開く
with open("../hightemp.txt", "r") as f:
    # 一行ずつ読み込む
    for data in f:
        # TAB を 空白へ置換（strip で white space を除去）
        print(data.strip().replace("\t"," "))
```


###Javascript
```Javascript
// モジュールの読み込み
var fs = require("fs");
var readline = require("readline");

//  ストリームを作成
var stream = fs.createReadStream("../hightemp.txt", "utf8");

//  readlineにStreamを渡す
var reader = readline.createInterface({ input: stream });

//  行読み込みコールバック
reader.on("line", (data) => {
    //  TAB を 空白へ変換（文字列 "\t" 指定ではうまく動作しないため正規表現で指定）
    console.log(data.replace(/\t/g," "))
});
```

## まとめ

Javascirpt で置換元文字列に "\t" が指定出来ないのか？。
Python コード数の少なさに改めて驚く。

[トップ](https://qiita.com/naoshin1984/items/3d7814e2f8eb01eea8dd)
Raspberry Piをできるだけ楽にシャットダウンする方法まとめ

# はじめに
Raspberry Piの電源を切るとき、電源をいきなり引っこ抜いてはいけない、ということはよく知られています。SDカードへの書き込みが行われている最中だと、カードが破損し、起動できなくなってしまう恐れがあります。

一方で、毎回シャットダウンコマンドを実行するのは手間ですよね。

ラズパイのシャットダウン手順（4ステップ）

1. PCを起動する
1. PCとRaspberry Piが同じLANに接続されていることを確認する
1. SSHクライアントを起動し、Raspberry PiにSSH接続する
1. `sudo shutdown -h now` を実行する

そこで、もっと楽にシャットダウンする方法をまとめてみました。

# 物理シャットダウンボタン
この方法に関しては多くの先人が記事を書いてくれているので、それを紹介するにとどめます。

* [RaspberryPiにshutdownボタンを付けよう](http://jellyware.jp/kurage/raspi/shutdown_button.html)
* [ラズパイでシャットダウンボタンを付ける(ついでに起動ボタン)](https://qiita.com/clses/items/e701c1cb6490751a6040)
* [Raspberry Pi 3 にシャットダウン/リブート/再開ボタンを追加する](http://hammmm.hatenablog.com/entry/2016/11/14/231337)
* [OnOff SHIM](https://www.switch-science.com/catalog/3295/)

物理ボタンによるシャットダウンの強みは、ラズパイがWebに接続していなくても使えるところですね。
この中で最もおすすめしたいのは4つめの「OnOff SHIM」です。セットアップが簡単で、1コマンド実行すれば使えるようになります。また、ラズパイのピンに直接マウントできるので、ブレットボードにジャンパワイヤを挿したまま持ち歩く必要もありません。ネックになるのは、はんだ付けが必要なことでしょうか。

# Web経由でシャットダウン
ラズパイがWebに繋がっている状態なら、遠隔でシャットダウンができる方法がいくつかあります。

## IIJ Legsを使う
IIJが2019年7月にリリースした新しいサービスです。
IIJ Legsを利用すると、Webコンソールを利用して世界中どこからでも任意のコマンドを安全に実行できます。すなわち、IIJ LegsのWebコンソールを開き、`sudo shutdown -h now`を実行すればミッション完了です。

[![Image from Gyazo](https://i.gyazo.com/bdc67c3fe466652f08fb916871f9d627.gif)](https://gyazo.com/bdc67c3fe466652f08fb916871f9d627)

導入が非常に簡単なのも嬉しいところです。[チュートリアル](https://dev.smf.jp/legs/tutorial/)に従い数コマンドで導入が完了します。
加えて、起動時に `./legsc start` が自動で実行されるよう設定し、常に使える状態にしておきましょう。
> [Raspberry Piでプログラムを自動起動する5種類の方法を比較・解説](https://qiita.com/karaage0703/items/ed18f318a1775b28eab4)


IIJ Legsはシャットダウン以外にも様々な用途で使える、非常に便利なサービスですが、まだ使っている人は少ないようです。ぜひ広めてください。

IIJ LegsにはURLフォワーディング機能があり、グローバルなURLをラズパイのlocalhostにフォワーディングできます。
しかし、この機能には不具合があるようです。例えば、localhost:8080へのフォワーディングを設定すると、このフォワーディング自体はうまくいきますが、localhost:8080/style.cssなどへのフォワーディングがうまく行かず、表示がおかしくなることがあります。
まだβ版とのことなので、今後のアップデートに期待しましょう。

## Blynkを使う
Blynkは、スマホアプリからRaspberry Piなどのハードウェアを制御できるサービスです。
スマホアプリのUIはカスタマイズ可能です。ボタンやスライダーを好きな場所に設置し、それらへの入力をトリガーにRaspberry Pi上で処理を実行することができます。
すなわち、Blynkアプリ上に設置したボタンをタップしたときに、シャットダウンコマンドが実行されるように設定すればいいですね。

私が試してみたものを紹介します。安全装置として設置したスライダーが100％のときにシャットダウンボタンを押すと、ラズパイがシャットダウンされます。
[![Image from Gyazo](https://i.gyazo.com/ab1753297096e2f91e1125a4db5438d5.gif)](https://gyazo.com/ab1753297096e2f91e1125a4db5438d5)

スマホアプリを立ち上げてさっとシャットダウンができるので、IIJ Legs以上にお手軽に使えます。
一方でセットアップはそこそこ手間がかかります。以下のサイトで紹介している手順に従いセットアップしたら、私はうまくシャットダウンできましたよ。

> [Rasberry Pi 3B + Blynkで実現、スマホからラズベリーパイを遠隔操作してシャットダウンする無料で簡単な方法](https://iot-plus.net/make/raspi/rpi3-blynk-shutdown/)

# 終わりに
これ以外にも良い方法があったら、ぜひコメント欄で教えていただけるとありがたいです。
それでは、良きラズパイライフを。
ESP32-CAMとRTSPを組み合わせて簡易ネットワークカメラを作ってみた。

ESP32-CAMとRTSPを使って簡易ネットワークカメラを作ってみました。

#RTSPを利用した理由
ESP32-CAMはESP32と同じくArduino IDEを使って開発をすることができます。
サンプルとして「CameraServer」というスケットが用意されていてそれをESP32-CAMに書き込めば簡単にネットワークカメラとして利用することができます。

書き込み後、ESP32-CAMに割り当てられたIPアドレスにブラウザからアクセスすれば映像をみることができます。
さらに画質の調整や顔検出などがブラウザ上から操作可能になっており簡易的なネットワークカメラとしては十分な機能があります。

今回はそれを使わずにRTSPを用いてネットワークカメラを作成しました。
その一番大きな理由は「映像をPythonのプログラムで取得/利用できるようにする」ことを目標をしていたからです。

#ESP32-CAMを使う上での注意事項
ESP32-CAMにはWiFiとBluetoothの機能があります。
この機能を日本国内で利用するには総務省より「技適」を取得している必要があります。
技適未取得の製品を使用することは罰則の対象となる場合があります。

詳しくはこちらを参照 
[wikipedia: 技適マーク](https://ja.wikipedia.org/wiki/%E6%8A%80%E9%81%A9%E3%83%9E%E3%83%BC%E3%82%AF#%E6%A6%82%E8%A6%81)
[無線基準認証制度](https://www.tele.soumu.go.jp/j/equ/index.htm)
[端末機器に関する基準認証制度について](https://www.soumu.go.jp/main_sosiki/joho_tsusin/tanmatu/index.html)


2019/11/20より技適未取得の機器を実験用として利用することができる制度がスタートしました。
[技適未取得機器を用いた実験等の特例制度](https://www.tele.soumu.go.jp/j/sys/others/exp-sp/index.htm)

この制度は所定の届出を行うことで技適未取得を実験目的で使用することができるようになります。
ただし期間や利用できる無線の規格、周波数帯など一定の制限が設けられています。

今回はこちらの届出をおこないESP32-CAMを使用しています。

#ESP32-CAMのスケッチ
今回ESP32-CAMでRTSPを利用するにあたり下記のリポジトリを参考にしました
[Micro-RTSP](https://github.com/geeksville/Micro-RTSP)

### オリジナルスケッチからの変更点
オリジナルのスケッチではESP32-CAMをSoftAPモード(アクセスポイントモード)で使用していました。それを変更し固定IPアドレスを設定しました。

```arduino:wsp32-cam.ino

WiFi.config(ip, gatway, subnet);
while (WiFi.status() != WL_CONNECTED)
  {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    WiFi.begin(ssid, password);

    delay(10000);
  }
```

またオリジナルのスケッチではRTSPの他にWebServerも設定されていましたがスケッチの簡略化のため削除しました。


#Python側での処理
PythonではOpenCVでESP32-CAMからの映像を受け取り表示しています。

```python:view.py
esp_ip = ''
esp32cam_camera = cv2.VideoCapture(f"rtsp://{esp_ip}:8554/mjpeg/1")
```

Python側では単に画像データとして扱えるので顔認識や物体認識などいろいろ活用することができます。

作成したソースはgitにアップしています。
[ESP32CAM_RTSP](https://github.com/tkinjo1985/ESP32CAM_RTSP)
railsにてcreated_at の曜日も日本語で表示する方法（ lメソッド）

- 目標①：railsにて、DBからcreated_at の日時を表示（取得）したい。



```変数.html.erb　
<%= link_to(変数.created_at.strftime('%Y年/%m月/%d日(%a)%H:%M')," リンク先を記入") %>
```
- まず試したコード
(今回は、更にlink_toを使いたい）

 - 「 XXXX年　XX月XX日（mon)　XX:XX 」とまで成功。
 - <%= 変数.created_at.strftime('%Y/%m/%d(%a)%H:%M') %> を実行し、曜日が英語標記のままのため苦戦。
 - #{%w(日 月 火 水 木 金 土…　系も試したが、上手くいかない。
 - config/initiallzers/time_formats.rb等も作成し定義を試したが、上手くいかない。


 
ーーーーーーーーーーーーーーーーーーーーー

＜備忘録＞
***目標②　（mon）ではなく、曜日も日本語で表示する簡単な方法***


①gem 'i18n_generators'　をbundleインストール

②en.ymlと同じ階層ディレクトリにconfig/locales/ja.yml　を作成。以下のコマンド実行すると内容が書き換わり大変便利。


```
rails g i18n_locale ja
```

③ja.yml　内の

```ruby
time:
   
      default: "%Y年%m月%d日(%a) %H時%M分" ←ここを取得したいように自分で変更する
```
④表示したいhtml.erb内へ　lメソッドにて記入。

```ruby
<%= link_to(l(テーブル名.created_at),"リンク先") %>
```

リンクではない場合、↓

```ruby
<%= l テーブル名.created_at %> 
```

念のため、サーバーを立ち上げ直し、
曜日も (mon)→（月）　日本語になりました。



##最終参考##

[Railsで日時をフォーマットするときはstrftimeよりも、lメソッドを使おう @Junichi Ito](https://qiita.com/jnchito/items/831654253fb8a958ec25)

＊個人勉強用サイト作成のため、
曜日を表示しないで妥協するか迷いましたが、諦めないで試行錯誤することが大切だと感じています。
[git]強制的にpullする

###はじめに
gitで、リモートをローカルにpullしたらコンフリクトした。
でもローカルのソースは保存する必要はなくて、とにかくリモートがローカルに来ればいいんだ！！強制的にpullしたい！！

ってことがままあります。
いっつもコマンド忘れちゃってググる行為から始まるのでここにメモします。


###コマンド
リモートの「develop」のソースをローカルの「mylocal」にpullしたいとき

```git
$ git fetch origin develop
$ git reset --hard origin/mylocal
```


これでいけました〜。
gitのコマンドとかそもそものところが、未だに理解で来ていない部分もあり
やりながら勉強中です・・・・。なかなか難しい・・・・。
cURLを利用して、MovableTypeのアクセストークンを取得する

MovableTypeのData APIを利用する際に必要となるアクセストークンは以下の方法で取得することが出来ます。
パスワードは、「Webサービスパスワード」を指定します。（管理画面ログイン時のパスワードではないので注意）
クライアントIDは、決まったものは無く、任意のIDを指定可能です。
```
curl -X POST https://<サイトURL>/mt/mt-data-api.cgi/v4/authentication \
-F username=<ユーザー名> \
-F password=<パスワード> \
-F clientId=<クライアントID> \
-F remember=1 \
| jq -r .accessToken
```
便利な使い方として、結果（アクセストークンを）ファイルへ出力することで（例えば、cronで一定時間ごとに実行して、結果をファイルへ出力することで）、curlやスクリプト等からData APIを、認証や有効期限を意識することなく手軽に利用することが出来ます。（もちろんセキュリティが確保された環境で行うことが前提です）
nodenvで指定したバージョンを使ってくれない時

現象
----

nodenv をインストールしてプロジェクトのディレクトリに .node_version を作成したところ、指定したバージョンを使ってくれませんでした。

```
$ nodenv local
x.x.x
```

```
$ node -v
y.y.y
```

```
$ which node 
/usr/local/bin
```


解決
---

nodenv をインストールした時に指定したパスが間違っていました。

`node` コマンド実行時に PATH に指定された順(`export -p`で左から順)に実行ファイルを探します。 
間違っていた PATH は `/usr/local/bin` -> `.nodenv/shims` の順に設定していたので `/usr/local/bin` にヒットして実行されていたようです。

`.nodenv/shims` -> `/usr/local/bin` の順にしたところ期待通りの動きになりました。

```
$ which node
/Users/myaccount/.nodenv/shims/node
```

最後に 
----

マニュアルにしっかり書いてありました。日本語のインストールブログだけではなくまず公式ドキュメントを読みましょうという話でした。

https://github.com/nodenv/nodenv#understanding-shims
SONiCとZTP

# ZTP?

Zero Touch Provisioning 略してZTP。

通常、PCやサーバ、あるいはネットワーク機器は、ケーブルをつないで電源を入れただけで定常運用状態にならず、人間の手による初期設定処理が必要です。たとえば、WindowsがプリインストールされているPCの場合、起動するとライセンスの確認やタイムゾーンの指定、キーボードレイアウトの確認、アカウント情報の入力などが求められ、キーボードやマウスを使って操作することで初めてWindowsを使えるようセットアップが完了するという流れになります。

こういった手動設定をなくすための手法はいくつかあります。たとえば顧客を特定し出荷前に顧客ごとの設定をあらかじめ書き込んで出荷することで、受け取った顧客は電源投入するだけでよい、といった手法があります。

上記の手法は出荷側に多大な負担がかかるのですが、別のやり方として、機器を接続するネットワーク上に仕掛けを用意しておくことで、CLIやGUIの操作を全く介さずに自動的に設定を完了させるという手法があります。この自動設定の一連の処理やフレームワークをZTPと呼びます。

# ホワイトボックススイッチにおけるZTP

ホワイトボックススイッチにおけるZTPはおおよそ下記の2段階に分けられます。

- ONIEによる自動OSインストール
- OSのZTP機能による自動初期設定

ホワイトボックススイッチは「OSがインストールされてないネットワークスイッチ製品」であるため、完全なZTPを実現するにはOSインストール部分から自動化できている必要があり、すでにそのための仕組みは用意されているのです。

## ONIEによる自動OSインストール

ONIEとは、Open Network Install Environmentの頭文字をとったもので、「オープンネットワーキング」対応のホワイトボックススイッチにおいて事実上標準と言えるOSインストーラーです。事実上標準というのは、たいていの製品で出荷時にプリインストールされているということを意味します。

ONIEの正体は、ホワイトボックススイッチに用意されているシリアルコンソールやマネジメントポートといった独自ハードウェアに対応し、IP通信によってOSインストールイメージを読み込み内蔵ストレージに展開できる機能を持つ、ごく小さなLinuxディストリビューションです。

ONIE自体の話を書き出すとそれはそれで長くなるのでかいつまんで説明すると、IA-32/AMD64のプロセッサで制御されるホワイトボックススイッチにおける自動OSインストールは下記のような流れで実行されます。

1. 機器が起動する
2. ONIEが`OS Install`モードで起動する
3. DHCPでマネジメントポートのIPアドレスを取得する
4. DHCPの追加情報あるいは特定URLにてOSインストールイメージの存在場所を特定する
5. OSインストールイメージを取得する
6. インストールを実行する(ストレージ上にOSのファイルシステムイメージを書き込む)
7. インストールが成功するとGRUBメニューを書き換え次回起動をインストールしたOSに変更する
8. 自動的に再起動する
9. インストールされたOSが起動する

つまり、インストール対象機器本体以外にも必要なものがあり、それは

- OSインストールイメージを配置・配信できるサーバ
- DHCPサーバ
- インストール対象機器との間のネットワークリーチャビリティ

です。

## OSのZTP機能による自動初期設定

ONIEによってOSが無事インストールされたとして、OSの設定はどのようにやればZTPが実願できるでしょうか? ここについてはOSの種類やバージョンにより詳細な実現手段は異なるといっていいでしょう。基本的には、DHCPでIPアドレスを取得する際に同時に受け取る追加情報を元に設定情報を取得する、といった手段をとるOSが多いようです。

# SONiCにおけるZTP

本稿執筆時点では、SONiCのZTP対応は完了していません。つまり、ONIEによって自動的にSONiCをインストールすることができても、その先の設定については人間が手動で実行する必要があります。

以上で解説はおしまい、というわけではなく、ZTPについては[HLD(High Level Design)](https://github.com/Azure/SONiC/blob/master/doc/ztp/ztp.md)に基づき実装が進められていて、現在レビュー中というステータスです。2020年の早い時期にmasterにmergeされるだろうと思います。ここではHLDでどのようにZTPを実現する設計としているかをかいつまんで説明します。細かい説明はHLDをご参照ください。

## ZTP JSON

あらかじめ、DHCP option 67にURLを載せるようにDHCPサーバに設定しておき、SONiCのZTPサービスはそれを認識するとURLで指定されたファイルを読み込みます。このファイルはZTP JSONと呼ばれ、ZTP関連の設定を記述することになっています。記述内容はユーザ定義が可能、pluginを使って拡張できる、とあり、かなり自由度が高くなっています。また、すでに提供されているpluginである`configdb-json`を使うことにより、外部から設定を取得して初期コンフィグとして適用することができます。下記はHLDに掲載されていた`configdb-json`の例です。

```json
"configdb-json": {
    "url": {
      "source": "http://192.168.1.1:8080/spine01_config_db.json",
      "destination": "/etc/sonic/config_db.json"
    }
  }
```

## どうやってそれぞれの機器の設定をわけるのか

これはZTP HLDに書かれている話でなく自分の勝手な考えですが、いくらかやり方が考えられます。

- DHCPで付与されたIPアドレスの値に基づいてさまざまな設定値を決定する (たとえばx.x.x.4が付与されたらASN番号もxxx04にする、など)
- DHCPサーバ側で適宜JSONの参照先を切り替える (あらかじめ機器のMACアドレスを把握するなどしてサーバ側で役割を決めておく)
- 同一DHCPサーバから取得した機器は同一設定(たとえばIP CLOSのspine)で動作するようにし、管理ネットワーク側を対象に応じて分離する

いずれにせよ、ZTPの利点を生かせるのは大量の機器を扱い交換等の手間も軽減させる場合であり、1台や2台導入して試験するだけであれば無理して構築する必要性は薄いと言えるでしょう。

# 参考リンク

- [ONIE](http://onie.org/)
- [ZTP HLD](https://github.com/Azure/SONiC/blob/master/doc/ztp/ztp.md)
cURLを利用して、Movable TypeのData API経由でファイルをアップロードする

以下の方法で、cURLを利用してMovableTypeへファイルをアップロードすることができます。
```
curl -X POST \
https://<サイトのURL>/mt/mt-data-api.cgi/v4/assets/upload \
-H "X-MT-Authorization:MTAuth accessToken=<アクセストークン>" \
-F site_id=<サイトID> \
-F path=<アップロード先のパス> \
-F "file=@<アップロードするファイルのパス>"
```
Webシステム構築（超基礎）①：Webサーバ構築と基本動作

#目的
Webシステム構築を目的として、まずは超基礎的なWebサーバの構築と動作を確認する。

#環境条件
- Webサーバ
    - EC2：t2.micro
    - OS：Red Hat Enterprise Linux 8 (HVM), SSD Volume Type
    - Disk：汎用SSD（GP2） 10GB

セキュリティグループの設定等はいい感じに。

#構築手順
```
ec2-userでログイン

rootユーザにスイッチ
$ sudo su - 

httpパッケージの存在確認
# yum info httpd

httpパッケージのインストール
# yum install -y httpd
Complete!の出力を確認する。

httpdサービスの停止を確認
# service httpd status
   Active: inactive (dead)の出力を確認する。

httpdサービスを起動する
# service httpd start
Redirecting to /bin/systemctl start httpd.service

再度httpdサービスのステータスを確認する
# service httpd status
   Active: active (running)の出力を確認する。 

ブラウザからWebサーバの「パブリックDNS:80」に接続し、
Red Hat Enterprise Linux Test Pageが表示されることを確認する。
```

#Webサーバの基本動作
以下２点ほど確認しておく。
1. DocumentRootとコンテンツの配置
2. 別ポートでのWebサーバ起動

##1. DocumentRootとコンテンツの配置

###DocumentRoot
DocumentRootとはざっくりいうと、自分で作ったコンテンツを
Apache HTTP ServerでWebサービスとして提供するための置き場所。
デフォルトは、以下となっている。
```
/var/www/html
```

DocumentRootの変更や設定の確認については、
以下ファイルによって可能。
```
/etc/httpd/conf/httpd.conf
```


```httpd.conf
（:set numberを実行の上、一部抜粋）
    117 #
    118 # DocumentRoot: The directory out of which you will serve your
    119 # documents. By default, all requests are taken from this directory, but
    120 # symbolic links and aliases may be used to point to other locations.
    121 #
    122 DocumentRoot "/var/www/html" #←ここを変更することでDocumentRootが変更可能
```

###コンテンツの配置
まずは、DocumentRootにindex.htmlファイルを配置してみる。

```index.html
（中身はなんでもいい。）
index.html
```
この状態で、ブラウザからWebサーバの「パブリックDNS:80」に接続すると、
Red Hat Enterprise Linux Test Pageが表示されなくなり、
index.htmlの中に記載した内容が表示される。
DocumentRootにindex.<xxx>が存在しない場合、
Testページを表示するが、存在する場合、index.<xxx>を表示する。

次に、DocumentRootにtest.htmlファイルを配置してみる。

```test.html
（中身はなんでもいい。）
test.html
```

この状態で、ブラウザからWebサーバの「パブリックDNS:80/test.html」に接続すると、
test.htmlを表示することができる。

##2. 別ポートでのWebサーバ起動

80番ポート以外でのWebサーバの起動が必要な場合に、DocumentRootと同じく、
以下ファイルを変更することで対応することが可能。

```httpd.conf
（:set numberを実行の上、一部抜粋）
     37 # Listen: Allows you to bind Apache to specific IP addresses and/or
     38 # ports, instead of the default. See also the <VirtualHost>
     39 # directive.
     40 #
     41 # Change this to Listen on specific IP addresses as shown below to
     42 # prevent Apache from glomming onto all bound IP addresses.
     43 #
     44 #Listen 12.34.56.78:80
     45 Listen 80
```

45行目のListen 80を Listen 10000等に変更し、プロセスを再起動することで、
10000ポートでのWebサーバの起動が可能になる。

次回は、
[Webシステム構築（超基礎）②：APサーバ構築と基本動作](https://qiita.com/ts6190ms/items/f685b4ea7cbfe4033839)
です。
「ファルコン・パンチ」が「フパ・ルァチンコン」にwwwワロタwwwわろた、、、

どうも今年もやってきました[クソアプリアドベントカレンダー](https://qiita.com/advent-calendar/2019/kuso-app)
24日を担当させていただきます@nabettuです。今年で四年目かな？


# 作ったもの

今年作ったのはこちら！

↓↓↓↓↓↓↓↓↓↓↓↓↓
https://challenge-maker.bubbleapps.io/
↑↑↑↑↑↑↑↑↑↑↑↑↑

チャレンジメーカーというネタWebサービスです。

![Screenshot_20191224-131905.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40154/e2d10f82-6fbc-a820-1515-a7ec298363d2.png)

# どうやって遊ぶか

タイトルの通り、任意の文字列のチャレンジを作ったら、それがちゃんとした順番で出てくるかをチャレンジするゲームのようなものです。

ランダムなアナグラムによって変な言葉が産まれたら、ぜひシェアしてみてください！

遊び方は以上です。

# どうやって作ったか

今回、webサービスとは言ってますが、実はコードを一行も書いていません。JavaScriptどころかHTMLすらゼロです。

最近流行りのNOCODEサービスであるbubbleを使って、GUIでボタンをポチポチ置いたりして、全ての機能を作っています。

- 各ページ
- チャレンジ投稿→DBへの保存
- トップページへの投稿の一覧表示
- チャレンジページでのランダムアナグラム生成
- 結果のシェア
- 404ページ

などなど、全ての機能をbubbleで完結し開発→公開まで行いました。

bubbleでのサイト制作について学びたい方はこちらのYouTubeチャンネルがオススメですのでぜひどうぞ。

- NOCODEスクール

https://www.youtube.com/channel/UCa3cFggd3BrJ6qq5lw8P_9w

（本当はチャレンジ投稿はtwitterログインした人だけにしようとしてたんですが、プラグインが上手く動かず。。。）


# bubbleはヤバイ

このサービスを作るまで、公式レッスンを一通りやった後実際に手を動かしたのは2〜3時間くらい試行錯誤しながら進めました。慣れてきたので次やるなら30分くらいでもっとマシなデザインでいけると思います笑

静的サイトだけ、とか結局ちょっとコード書くとかのサービスはありましたが、bubbleは今までで一番、本当に簡単にちゃんとしたサービスの機能を作ることが出来ます。思ったより学習コストは高くありません。

NOCODEの波は確実に来ます。bubble以外にもこういったサービスはたくさん出てきており、今後のサービス開発の常識が変わる可能性を秘めていると思います。

（まあガラッと変わるというよりかは、小規模なプロトタイプから徐々にデカいプロダクトでも使えるように進化していく感じ。でも見逃していたらいつの間にかやべー事になるので今のうちに波に乗っとくといいかなー！）


以上。クソアプリアドベントカレンダー、チャレンジメーカーでした！

明日はついにトリ！@munieru_jpさんとんでもないクソアプリをよろしくお願いします！
（ハードルを上げるけどクソアプリだからどんなのでも良いハードルの低さで相殺笑）
[Rust] argsort

Rust の `Vec<T>` (正確には `Deref<Target = [T]>`) は `sort` や `sort_unstable` といったメソッドを持ちますが, 配列そのものは変更せずソートした順のインデックスの配列が欲しいことがあります. そんなときはこちら:

```rust
fn argsort<T: Ord>(v: &[T]) -> Vec<usize> {
    let mut idx = (0..v.len()).collect::<Vec<_>>();
    idx.sort_unstable_by(|&i, &j| v[i].cmp(&v[j]));
    idx
}
```

最も効率的か若干自信がないですが... 安定ソートが欲しい場合は unstable を外してください. 

使用例: 

```rust
fn main() {
    let mut v = [-5, 4, 1, -3, 2];

    let idx = argsort(&v);

    for i in idx.into_iter() {
        println!("v[{}] = {}", i, v[i]);
    }
}
```
AmplifyでCognitoユーザプールの認証を行いトークン（ID、アクセス）取得後、トークンの有効期限を取得する

## 概要

AmplifyでCognitoユーザプールの認証を行いトークン（ID、アクセス）取得後、トークンの有効期限を取得する。

## 実装

下記実行でUNIX秒が返ってくる。
※ `new Date()` に渡すときは、1000をかける（ミリ秒にして渡す）こと。

```javascript
  (await Auth.currentSession()).getIdToken().getExpiration()
```

## 参考

* https://github.com/aws-amplify/amplify-js/blob/867412030de57fd74078b609252de6f7f81ad331/packages/amazon-cognito-identity-js/src/CognitoJwtToken.js#L42
AWS re:invent2019に行った感想(次行く人のためにメモ)

# はじめに
12/1~12/6に開催されるAWS re:invent2019に会社名義で参加してきました。
雰囲気や今後行く人のために参考になればと残しておきます。
画像とか追加であげます。

# AWSの認定資格を取得する
### 懇親会の際に知識共有がしやすい
AWSの社員経由でre:inventに参加したので、日本企業で行く人たちが集まる事前懇親会がAWS目黒本社に招待されました。多くのAWSを使用した企業と交流するにあたり幅広く知識を持っていると、自分が担当しているサービス以外でも吸収できる部分が多くなります。
(現地で首に下げるIDバッジに認定者シールが貼られるので、胸を張れる部分もあります)

### 認定者限定のスペース・ノベルティがある
イベント会場でも認定者資格を持っている人は休憩スペースに入れたり、
特別なノベルティがもらえます。2019年はスポーツウェア・靴下・バッジでした。
正直、休憩スペースは狭くて席が埋まっているのでそんなにうまみは感じませんでした。
ドリンクとか軽食がもらえますとre:invent関連の記事にありますが、ドリンクと軽食は認定者ラウンジ以外でももらえます。

取るならSAA(ソリューションアーキテクト)が全体的なことを知れて良いかなと思いました。

# セッションの種類について
re:inventでは5日間で4000以上のセッションがあり、それぞれ形式が異なるセッションが行われています。
自分が参加したものだけ参考に書いていきます。

### 現地でしかできないことをやる
まず事前懇親会でも言われたのが「現地でしかできないことをやる」です。
講義形式のセッションは後に動画配信されるので、見逃してしまっても興味があれば後からでも見ることができます。
とはいえ現場の温度感などしっかり味わえるし、セッション取ってもいいと思います。

### 予約時はSessionは後回しでもいい
セッションはよっぽど人気でない限り、当日でも余裕で入れると思います。
当日から20分前くらいに並べば入れるので、予約の際はセッション以外を優先的に取るようにするといいです。
→10分前には待機列が解放されるので、予約をしていても早めに来ていないと受けられなくなる可能性もあります。

### Workshopをたくさん取るようにするといい
手を動かす方が英語を使わないので英語ができない人はWorkshopオススメです。
→でもわからないことがあると聞く必要はある(画面見せれば色々喋りながらサポートしてくれます)
ワークショップは人気なので後からはなかなか取れない。予約の際にとっておくといいと思います。

また、予約枠以外で当日並ぶ場合、開始1時間前に並べばほぼ入れる(30~45分だと入れたり入れなかったり、30分)
→当日ノベルティがもらえるワークショップは2~3時間前くらいから並ばないと取れないです(去年ならdeepcomposer/一昨年ならdeepracer)

### Chalk Talk
20分程度のセッションから残り40分は質疑応答になります。
自分が参加したものはボード一切使いませんでした。
スライドなどがないので、英語のリスニングがある程度できる前提で取った方がいいと思います。
→ただ話さなくてもいいので、話すことが苦手でも大丈夫です。
スピーキングができるとより価値があるセッションだと思います。

### SpotLight Lab
ハンズオンのトレーニングを現場でできます。
無料で提供されているハンズオンではないものなど実践できるし、
実際に手を動かすのでインプットが多いと思います。

### 基調講演は一度は必ず参加すると良い
フェスのようなどでかい会場で講演があります。前座でバンドとかDJが演奏しているし、
先着1000名にはノベルティのTシャツがもらえます。(1時間前くらいに会場入りすればもらえる)
日本語訳が同時通訳にあるので理解しやすいです。

温度感だけでも1度は必ず現場で体験してみて、そのあとは中継でもどちらでも良いかなと思いました。

# その他イベントについて
### 朝食&昼食&軽食&ドリンク
全て会場内で無料なので有効活用すると良いです。
缶ジュースとか持って帰ってホテルとかで飲むのも良いです。

### re:play
木曜日にバスでどこだかわからないところに連れて行かれます。
フェスみたいな会場、いろんなことに力が入っていて楽しいです。

### EXPO
AWSのスポンサーがブースを開いており、小規模なセッションをやっていたりサービスを試せたりする。
英会話の練習でこのサービスは何なのかとか色々聞いてみるといいかも。
ノベルティをたくさん配っており、プリーズって言えばとりあえず貰える。Tシャツとか頑張れば10着くらい貰える。
曜日によりスポンサーが異なっており、毎日空き時間にいくといいと思う。
シャツやパーカーのサイズはいつも自分が来ている1サイズ小さめのものをお願いすると良い。

# 英語について
スピーキングよりリスニングが重要な印象を受けました。
行く前はリスニングに注力して勉強するといいと思います。
海外の人はみんなフランクで昼食バイキング中やセッションの待ち時間に普通に声をかけてきます。
・どこから来たの？
・fargateを自社サービスに導入していますか？課題はありますか？
・その背中の大きい荷物は何ですか？
とか聞かれたりしました。
話せると自分から列の待ち時間で周りの人にヒアリングできてより充実してイベントに参加できると思います。
@ngrx/dataで別ドメインのAPIサーバにアクセスしてみる


AngularのAdvent Calendarで@ngrx/dataが紹介されました。

[Angularから@ngrx/dataとActiveRecordを使ってRDBにアクセスする（追記あり）](https://qiita.com/FumioYoshida/items/e9b1eaa36b0a94467d1b#513%E5%AF%BE%E8%B1%A1%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%AE%E8%A8%AD%E5%AE%9A)

この記事で詳細に説明されているのですが、別ドメインのAPIにもアクセスできないかと思い試してみました。

#別ドメインのAPIにアクセスするには

上記の記事の中でも紹介されていますが、デフォルトのAPIへのpathを変更するにはDefaultDataServiceConfigを使うだけです。

```typescript:dataservice-config.ts
const defaultDataServiceConfig: DefaultDataServiceConfig = {
  root: 'https://api-server/user',
  timeout: 5000
};
```

rootの部分にAPIサーバのURLを設定してproviderに登録するだけです。

機会があれば複数のAPIサーバにアクセスさせる設計も考えます。
GoF デザインパターン チートシート

![25B81B6A-B091-46A7-9090-A7A41A644F6E.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/11525/c314ccc8-4911-2b42-1eb3-bb6ca9691571.png)

ここまで読んでくださった皆さんに、ちょっとしたクリスマスプレゼント。マンガでわかる GoF デザインパターン 23 種チートシートです。これでもうデザインパターンは完全にマスターしましたよ。やったね!

- - -
(注: ここからはあとがきポエムです)

ところでみなさん、せっかくデザインパターンを学んだので、これを使ってプログラムを書こう、チートシートがあるからなんでも書けそうだぞ、なんて思っていませんか。ダメですよ。そんなことしたら 2000 年前後に起きた失敗を繰り返してしまいます。

実は GoF のデザインパターンは、ビジネス的には成功したけど、教育には失敗しました。最初に出版された本に「オブジェクト指向における再利用のための」という肩書が付いていましたが、これが本当に良くなかった。

あの頃 (ポール・グレアムが LISP と Ruby を褒めるまで) は、「オブジェクト指向様こそが良い設計のすべて教」が信仰されていました。みんな、オブジェクト指向とは何かって意識がピンキリで、キリのみなさんは、これでコードを書くスキルを身につけて再利用できると考えてしまいました。

その結果何が起きたかというと、無目的なデザインパターンの乱用です。目的はわからないけど、デザインパターンを盛り込んだ方がソフトウェアが高級になるらしい、なんてとんでもない迷信がはびこったのです。目的のないパターンはただの難読化です。

いま日本では DDD (ドメイン駆動設計) が再燃していますが、そんな中、コードと業務を一致させる組織論を諦めたグループが、軽量 DDD と称して DDD のデザインパターンだけを利用しようとしています。たいへん危険な思想です。

DDD のデザインパターンは、ユビキタス言語を形成するための道具です。わかっていてやる最初の人はいいですが、そうとは知らない人がパターンだけを真似させられたらどうなるでしょう。疎結合にした先をビジネスの本質に一致させようとする意識がないまま、どうだクールなアーキテクチャだぜ、でいくと「依存方向を逆転してるのか何だか知らないけど、結局いつも全部修正させられるんだから、Repository で Entity に転送するより、愚直に ActiveRecord のままやって BDD した方がよっぽど簡単だった」「なんで開発そんなに遅いの」なんて言われかねません。(←本題じゃないので反論は別の機会に)

GoF の失敗の原因は、そんな、ドメインを失ったドメイン駆動パターンのように、そもそもの目的を見失っていたことです。本の題名に含まれていた「オブジェクト指向」が指していること、良い設計って何だったんでしょう??

- 継承よりコンポジションを好む方が柔軟になる (これは主張されてた)
- 操作から生成の関心を分離して条件分岐を減らす
- 状態の変更を最小限に → イミュータブルこそ最高
- 後で決めたいことから先に決めたいことに単方向依存させよ
- (↑つまり SOLID 原則を手段としたパッケージ原則が目的)

これらを、経験ある人にとっては本能でわかることと思いますが、なんて文脈ひどない? 「C++ と Java を使って書くことがオブジェクト指向」と思っている初心者が、デザインパターン本とサンプルコードを突然目にして、これがナウいらしいと言われたらどう思うか...

なので、このマンガでわかるシリーズでは、プログラムの書き方にはいっさい言及しませんでした。大事なのは、かっこいいプログラムを書ききることではなくて、必要があって露出した設計 (安定度のムラと依存方向の問題など) 判断に対して、どれだけみんなへの説明を省けるかなのです。

再利用というのは、これさえ学べば何度でもプログラムを書くことができる、という意味ではなくて、「みんなの共通ボキャブラリにしていこうね」「もし自分の考えた設計がデザインパターンの形になるなら、ちょうどいいメタファーがあるんだから、そう呼べばみんなにわかりやすいよ」という意味だったんです。物を書くときの再利用ではなく、読むときのメンタルモデルの再利用が目的だった。

そのためには、あんな分厚い偉そうな本ではダメです。どこが要点かわからないぐらいに豊富すぎる Java のサンプルコードが載った本でもダメ。ぱっと見でそのパターンが「何であって」「何でないのか」がわかるコンテンツでなきゃという思いがありました。

HTTP ミドルウェアは Proxy パターンですね。CQRS とかいうアレの C はまさに Command です。たいていのフレームワークは Template Method パターンを利用しています。最重要パターン、Abstract Factory は、オブジェクト指向の醍醐味、操作と生成の分離の概念が難しかったのを、一言で表せるようにしてくれています。

流行りに乗ったけどうまく行かなかった人たちを尻目に、うまくやっていた一部の人々は、20 年の間にいろいろなソフトウェアを残してくれました。OSS にこれだけアクセスしやすくなったいま、パターンで読める知識がさまざまな所に見て取れます。初心者にとってのデザインパターンは、いまや本当に、書くものではなく、読み取るものになったと思います。

実は、マンガを描くためにウェブで調べているうちに、どのような有様を指すかではなく、どのように **書くこと** がデザインパターンなのかを説明する記事があまりにも多くて、とても残念な気持ちになりました。時代だったからしょうがないですね。けどもう GoF は良い意味でオワコンなので安心してください!!

このシリーズを読んでくださった皆さんが、「なんだ、結局これじゃプログラムを書くのに使えないや」と思いながらも、パターンに関係するマンガのシチュエーションが記憶に残っていて、「あれ?なんかイメージと違う」と感じられるようになったなら、それこそ大成功だと思っています。パターンを組み合わせてプログラムを書くぞ、なんて思ってた時代より、よっぽど深く理解できたスタートラインに立ったことになるので。

繰り返します。デザインパターンを組み合わせてコードを書こうとしないでください。がんばって自分の設計センス (= いろいろ見てきた経験) に従って書いているうちに、あるいは他人のコードを読んでいるうちに、そこにパターンを見出せるようになってください。それをコミュニケーションに活かしてください。

見出したパターンの名前を借りて、チームに共通の語彙を形成しいくのです。プロジェクトで使える語彙だけ使えばいいんです。でも、使わないなら知らなくていい、じゃないです。知らなきゃ使える状況ですぐ出てこない。ことわざと同じです。学習コスト? マンガ読むのに学習コストかかります? 意味を知らない人がいても、マンガを読ませて「このイメージ」って教えればすぐですよね。

ちょうぜつアドベントカレンダーは **再利用可能な <del>オブジェクト指向</del> <ins>いい感じの設計</ins> のための** ブログ記事です。

(はい、技術的内容にポエムをぶら下げる戦略でした)
WARNING: POSSIBLE DNS SPOOFING DETECTED

```
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@       WARNING: POSSIBLE DNS SPOOFING DETECTED!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
The ECDSA host key for yourdomain.com has changed,
and the key for the corresponding IP address 777.77.777.77
is unknown. This could either mean that
DNS SPOOFING is happening or the IP address for the host
and its host key have changed at the same time.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
```
ドメイン設定をしたサーバーを作ったり壊したりすると`ssh`接続で上記のメッセージがでる。

**対策**: `~/.ssh/known_hosts` を開いて該当のドメインを削除する。
VSCodeでタブが1つしか開かなくなったときの対処法

以下のように
複数タブが開いてくれないことがあったので。

![スクリーンショット 2019-12-23 17.40.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168023/6f5153d5-37a0-638b-328b-0d8c2408fc16.png)

### 環境

* macOS mojave(10.14.6)
* Visual Studio Code(1.41.1)

#### 原因

Macの画面ロックするときのコマンド (`Command + Control + q`) が誤爆して、
VSCodeのタブ切り替えのショートカットが起動してしまった模様。


### 方法1

VSCode上で以下のショートカットを入力する

```
Command + Control + w
```

### 方法２

Settings.json を開き

```
workbench.editor.showTabs: true
```

に設定する


### 参考

https://stackoverflow.com/questions/48589785/vscode-showing-only-one-file-in-the-tab-bar-cant-open-multiple-files/51731593
Elasticsearch によるログ収集と可視化

Elasticsearch によるログ収集と可視化について、全三回に渡って記事を掲載しています。
第一回から第三回まで順を追ってご覧頂ければ幸いです。

・[Elasticsearch によるログ収集と可視化（第一回）](https://qiita.com/wooheehan/items/39f59a5a1da61286e86b)
　　Elasticsearch の概要とデータ構造について

・[Elasticsearch によるログ収集と可視化（第二回）](https://qiita.com/wooheehan/items/938aafd05b2d54708efb)
　　データの流れと AWS 上での環境構築について

・[Elasticsearch によるログ収集と可視化（第三回）](https://qiita.com/wooheehan/items/a955e3671d49eb411043)
　　各ツールの設定内容と可視化について
django-rest-framework 動的にserializerのフィールドを変更する

# はじめに

`django-rest-framework`の`serializer`を利用してクライアントからのリクエストに応じて動的にフィールドを変更する場合、
公式ガイドにあるクラスを利用し返すことが出来ます。

ビューセットからの呼び出しサンプルです。
ここではフィールドの動的変更のみを行いますが、他のパラメータと組み合わせることで返却するフィールドを柔軟に変更できるようになります。

## Dynamic クラスの定義

公式ガイドにあるクラスを利用します。
https://www.django-rest-framework.org/api-guide/serializers/#dynamically-modifying-fields

```python
from rest_framework import serializers


class DynamicFieldsModelSerializer(serializers.ModelSerializer):
    """
    A ModelSerializer that takes an additional `fields` argument that
    controls which fields should be displayed.
    """

    def __init__(self, *args, **kwargs):
        # Don't pass the 'fields' arg up to the superclass
        fields = kwargs.pop('fields', None)

        # Instantiate the superclass normally
        super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)

        if fields is not None:
            # Drop any fields that are not specified in the `fields` argument.
            allowed = set(fields)
            existing = set(self.fields)
            for field_name in existing - allowed:
                self.fields.pop(field_name)
```

## モデルの作成

シンプルなコード、名称を持つモデルです。

```python
from uuid import uuid4
from django.db import models


class Customer(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid4, editable=False)
    code = models.CharField(verbose_name='コード', help_text='コード', max_length=10)
    name = models.CharField(verbose_name='名称', help_text='名称', max_length=50)
```

## シリアライザの作成

```python
class CustomerSerializer(DynamicFieldsModelSerializer):
    class Meta:
        model = Customer

        fields = (
            'id',
            'code',
            'name',
        )
```

## ビューセットの作成

`get_serializer`をオーバーライドし、`GET`リクエスト時のみクエリ文字列に設定されたフィールド値で
取得する列を動的に変更します。

```
from rest_framework import viewsets


class CustomerViewSet(viewsets.ModelViewSet):
    queryset = Customer.objects.all()
    serializer_class = CustomerSerializer

    def get_serializer(self, *args, **kwargs):
        if self.action == 'list':
            if 'fields[]' in self.request.query_params:
                kwargs['fields'] = self.request.query_params.getlist('fields[]')

        return super().get_serializer(*args, **kwargs)
```

## 動作確認

### フィールドを指定しない場合

```bash
curl -s -X GET "http://localhost:18000/api/customers/" -H "accept: application/json" | jq .
[
  {
    "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx1",
    "code": "001",
    "name": "test1"
  },
  {
    "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx2",
    "code": "002",
    "name": "test2"
  }
]
```

### フィールドに`code`, `name`を指定した場合

```bash
curl -s -X GET "http://localhost:18000/api/customers/?fields[]=code&fields[]=name" --globoff -H "accept: application/json" | jq .
[
  {
    "code": "001",
    "name": "test"
  },
  {
    "code": "002",
    "name": "test2"
  }
]
```
Ruby数字出力 ０埋め

#Rubyでの計算結果を0埋めで表示(3→003)

今回、例として、入力された数値の倍の数を三桁の0埋めで考える。
1→002
2→004
6→012

##1.まず普通の表示
1→2
2→4
6→12
をまず、できるようにする

~~~Ruby
puts "数字を入れてください"
number = gets.to_i
number2=number*2
print number2
~~~

↑これで、完了。

##2.0埋めを考えていく

~~~Ruby
sprintf("%03d",number)
~~~

や

~~~Ruby
"%03d" % number
~~~

が、numberの0埋め3桁表示となる。

##実行するプログラム

~~~Ruby
puts "数字を入れてください"
number = gets.to_i
number2=number*2
number3=sprintf("%03d", number2)
print number3
~~~


1→002
2→004
6→012


が確認できた

##参考文献

http://osishow3.hateblo.jp/entry/2017/04/24/235500

https://www.setoya-blog.com/entry/2013/12/06/171143
Ubuntu18.04 proxy関連設定メモ

# Proxy関連の設定

```/etc/environment.
http_proxy=http://proxy:port/
https_proxy=http://proxy:port/
```

# pipができない場合
.pipフォルダとpip.confファイルを作成

```~/.pip/pip.conf
[global]
trusted-host = pypi.python.org
               pypi.org
               files.pythonhosted.org
```

# Docker関連

```/etc/default/docker.
export http_proxy="http://proxy:port/"
export https_proxy="http://proxy:port/"
```
sudo service docker restart
docker info で確認


# Zscaler関連の設定
Zscalerをコピー

```
sudo cp ZscalerRootCertificate.crt /usr/share/ca-certificates
```

```/etc/ca-certificates.conf
ZscalerRootCertificate.crt
```

以下のコマンドを実行

```
sudo update-ca-certificates
```

CURLが使えなければ、下記を追加するのも一興

```
export CURL_CA_BUNDLE=/usr/share/ca-certificates/ZscalerRootCertificate.crt
export REQUESTS_CA_BUNDLE=/usr/share/ca-certificates/ZscalerRootCertificate.crt
export SSL_CERT_FILE=/usr/share/ca-certificates/ZscalerRootCertificate.crt
```
next.jsで画像圧縮のblueimp-load-imageしてみる

画像圧縮してFirebaseアップしたかったのでメモ

### パッケージインストール

``` Bash
npm install --save blueimp-load-image
```

### canvas->blob変換
blobに変換してFirebaseへ送るようにするとできた

``` js
  const dataUri = canvas.toDataURL(type);
  var bin = atob(dataUri.split(',')[1]);
  var buffer = new Uint8Array(bin.length);
  for (var i = 0; i < bin.length; i++) {
    buffer[i] = bin.charCodeAt(i);
  }
  var blob = new Blob([buffer.buffer], { type: type });
```

### 画像圧縮してblob変換してストレージへ保存
``` js
loadImage.parseMetaData(file, (data) => {
  const options = {
    maxHeight: 300,
    maxWidth: 300,
    canvas: true,
  };
  if (data.exif) {
    options.orientation = data.exif.get('Orientation');
  }
  //画像圧縮
  loadImage(file, (canvas) => {
    //変換
    var type = 'image/jpeg';
    const dataUri = canvas.toDataURL(type);
    var bin = atob(dataUri.split(',')[1]);
    var buffer = new Uint8Array(bin.length);
    for (var i = 0; i < bin.length; i++) {
      buffer[i] = bin.charCodeAt(i);
    }
    var blob = new Blob([buffer.buffer], { type: type });
    //ストレージへ保存
    query.put(blob, { contentType: file.type })
      .then(function (snapshot) {
        
      }).catch(function (error) {
        console.error("Error getting document:", error);
      });
  }, options);
});
```


### 参考サイト

Canvas に描いた画像を png などの形式の Blob に変換する方法: Tender Surrender
https://blog.agektmr.com/2013/09/canvas-png-blob.html

blueimp/JavaScript-Load-Image
https://github.com/blueimp/JavaScript-Load-Image

JavaScript(ES2015&React)で画像を扱う：リサイズとプレビュー表示
https://blog.agektmr.com/2013/09/canvas-png-blob.html
Catapult版のアポスティーユをざっくりとかいてみる

# はじめに

この記事、nem advent calendar #2の20日目に投稿する予定でしたが、体調を崩してしまい投稿が遅くなってしまったことお詫び申し上げます。

さて、アポスティーユですがNEMのユースケースの1つですが、Catapultの機能を活用して強化されます。
詳細は[NIP-0004](https://github.com/nemtech/NIP/blob/master/NIPs/nip-0004.md)に書いてありますが、ここではざっくりどんな風に変わるのかを説明します。

# ポイント1: パブリックアポスティーユの廃止

現行NEMのアポスティーユはパブリックとプライベートの2種類がありました。
パブリックのアポスティーユの場合、共通の公証アカウントを持ち、ファイルのハッシュ値を平文で持っています。
一方、プライベートのアポスティーユは、独自の公証アカウントを持ち、ファイルのハッシュ値は所有者の秘密鍵で署名されます。
プライベートのアポスティーユは、独自の公証アカウントを持つため、この公証アカウントをマルチシグ化することで、権利の分割・譲渡を可能にしています。

パブリックのアポスティーユは実装が簡単な反面、拡張性がなくプライベートのアポスティーユに置き換えようとした場合、ほぼ作り直しみたいな感じになるため、プライベートのアポスティーユに一本化されています。

# ポイント2: アポスティーユ作成時に所有者割り当ても同時にできるようになった

先ほども述べたようにプライベートのアポスティーユでは独自の公証アカウントが作成されます。これは、管理しないといけない秘密鍵の数が増えることを意味し、利用者の負担が増えることに繋がりかねません。

Catapult版のアポスティーユでは、アグリゲートトランザクションで、公証アカウントのマルチシグアカウント化を行うことにより、アポスティーユの作成と、所有者の割り当てを同時に行えるようになりました。

マルチシグアカウント化すると公証アカウントの秘密鍵では、アカウントの操作も行えなくなるので、鍵の扱いの負担も軽減されます。

# ポイント3: アポスティーユにメタデータを入れる事ができるようになった

アポスティーユでは、実際のファイルはブロックチェーン上に保存せず、ファイルのハッシュ値の署名値がブロックチェーンに保存されます。
これは、ネットワークの負担、手数料、プライバシーの観点からしてもよいことなのですが、一方でどんなアポスティーユだったかなど、ちょっとしたデータを追加しておきたいケースもあります。

Catapult版のアポスティーユでは、Catapultに追加されたメタデータを活用し、公証アカウントにメタデータを付与することでこのアポスティーユがどんなものかなどを書き占めることができました。

## 現行のNEM Walletのタグは??

デスクトップ版のNEM Walletを使ってアポスティーユをしたことがある人は、タグはなんなんだと思うかもしれません。
確かに、アポスティーユ作成する際にタグの入力を求められますが、あれは**ブロックチェーン上に書き込まれることはなく**、アポスティーユの管理用ファイルの中だけで存在します。

# まとめ

非常に簡単にですが、Catapultによってアポスティーユがより使いやすくなるポイントを解説しました。
(コードも、図もなく読みづらいかもしれませんが、おいおい追記・修正します)
トークルームの roomId を調べる方法

LINEWORKS のトークルームにはすべて roomId が与えられているらしいのですが、UI からは確認できません( ﾟДﾟ)

確認する方法を公式コミュニティで検索してみると、現在 3つある模様。

1. トークルームに Bot を招待して、Callback URL でメッセージを受信する際に含まれる roomId を確認する
2. 「Bot を含むトークルーム作成 API」にてトークルームを作成した際のレスポンスに含まれる roomId を確認する
3. Chrome のデベロッパーツールを使って調べる（ブラウザ版のみ）

1.の方法は前に記事を書いたので、こちらをご参考ください。
[「トークルームの roomId を取得する bot」](https://qiita.com/kunihiros/items/16bd30676c8f17480646)

2.の方法は既存のトークルームには使えません。
あくまで Bot が新規にトークルームを作る場合のみですね。
[Bot を含むトークルーム作成 API](https://developers.worksmobile.com/jp/document/1005022?lang=ja)

3.の方法は下記ページで解説されています。
[既存トークルームのルームIDを確認する](http://help.receptionist.jp/?p=12028#roomid1)

しかし！今日！たまたま見つけてしまいましたよ！(*´Д｀)ﾄﾞﾔｧ

## 画像送信時、temp フォルダに roomId のフォルダが作られる

PC 版アプリをインストールすると、デフォルトで以下のフォルダが作られます。
C:\Users\ユーザ名\AppData\Roaming\WorksMobile\WorksMobileOneW\temp

このフォルダ、何に使うのかと言うとトークにある画面キャプチャ機能で使用されています。
画面キャプチャ機能は便利なので、私は記事を作るときによく使っています。
![1576736473.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363367/eb710821-0660-f3ce-32d0-84e85f905321.png)

キャプチャするとトークに送信されるのですが、「フォルダを開く」ボタンを押すとさっきの temp フォルダが開かれます。
![1576734909.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363367/f2534fbb-c085-e135-cd85-b4e0bd9ab520.png)

![1576735020.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363367/98392f65-7f54-5154-74c2-7bfeccacff46.png)

んで、いつも Qiita にアップロードするためにキャプチャ画像をガスガス入れていくわけなのですが、それとは別に 8ケタの数字のフォルダが作られているんですよね。

「何かなー？('ω')」と思って中身を見てみると `small_thumbnail_17892807...` といった名前がついた画像データがいっぱい！
しかも、消しても消してもしばらくすると復活するというゾンビのような輩です。こわわ( ﾟДﾟ)

でも、何かこの数字見覚えあるなー・・・？と、思っていたら。

![1576734532.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363367/deff40f3-2657-25be-7098-93650f593c8d.png)

そうだよ！ roomId だよ！
つまり、画像を送信して更新日時で検索かければファイル名が出てくるから roomId が判明する、と！(ﾟДﾟ)ﾉ
![1576741941.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363367/1dfc75a6-2925-96d2-712d-a1f3f0a49b47.png)

いえーい(/・ω・)/

これで簡単に（？）roomId を調べられるぞ！
・・・・簡単・・・・に？(ﾟДﾟ)

#おわりに
ここまでお付き合いいただきありがとうございました。

Bot をいちいち設定するのも面倒だし、PC版アプリではこの方法、ブラウザ版だと Chrome のデベロッパーツールを使うのが良さげですね。
何かトークの端っこに roomId 表示しといてくれればいいのにね。

「ほんと、マニアックな記事ばっかりだね」とかの応援、ありがとうございます！（謎）

ではまた！(^^)/

#参考にさせていただきましたm(_ _)m
[LINEWORKS Developers](https://developers.worksmobile.com/jp/document?lang=ja)
ReactJS react-routerのサンプルアプリ

非常にシンプルな実装例のメモ！
github: https://github.com/Kohei-Sato-1221/SugarReactRouter

![スクリーンショット 2019-12-24 12.24.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/454171/6ca3aa96-8cb5-e068-7b93-602fd5f7b1eb.png)



# react-routerとは？
Reactでルーティングを実現するためのライブラリ

# 前提条件
1. npmコマンド使えるようにしておく
2. create-react-appを使えるようにしておく

# 実装方法
サンプルのReactプロジェクトを用意

```
create-react-app router-sample
```

ライブラリをインストール

```
cd router-sample
npm install react-router-dom
```

App.jsを以下の通り書き換える

```javascript:App.js
import React from 'react';
import {Route, BrowserRouter, Link} from 'react-router-dom'

const App = () => (
  <BrowserRouter>
    <div>
      <div><Link to='/page1'>Go to Page1</Link></div>
      <div><Link to='/page2'>Go to Page2</Link></div>

      <br/>

      <Route path='/page1' component={Page1} />
      <Route path='/page2' component={Page2} />
    </div>
  </BrowserRouter>
)

const Page1 = () => (
  <div>This is Page1</div>
)

const Page2 = () => (
  <div>This is Page2</div>
)

export default App;
```

以下のコマンドで起動

```
npm start
```
【Laravel】routeメソッドで生成されるURLを相対パスにする



Laravel 6.0


`route`メソッドの第３引数に`false`を渡すと相対パスを返してくれるらしい。（デフォルトはtrue）

[ヘルパ 6.x Laravel](https://readouble.com/laravel/6.x/ja/helpers.html#method-route)

>route関数はデフォルトとして絶対URLを生成します。相対URLを生成したい場合は、第３引数にfalseを渡してください。
$url = route('routeName', ['id' => 1], false);

```php:helpers.php
if (! function_exists('route')) {
    /**
     * Generate the URL to a named route.
     *
     * @param  array|string  $name
     * @param  mixed  $parameters
     * @param  bool  $absolute
     * @return string
     */
    function route($name, $parameters = [], $absolute = true)
    {
        return app('url')->route($name, $parameters, $absolute);
    }
}
```

```php:index.blade.php
<form action="{{route('foo/bar', [], false)}}" method="post">
 ...
</form>
```

# おまけ

そもそも相対パスにしようと思ったのは、
サーバーの事情で生成されるURLのドメインが期待するものになっていなかったので、
絶対パスではなく、相対パスでURLを生成したかったから。

でもよく考えたらrouteメソッドで生成されるURLは相対パスにできても
リダイレクトは絶対パスが生成されていたのでドメインが違えば正しくリダイレクトできない。

どのみちURLのドメインを明示的に指定する必要があった。


↓リダイレクトも含めて生成されるURLを固定する方法
[【Laravel】routeメソッドやリダイレクトで生成されるURLのホスト名を指定する - Qiita](https://qiita.com/tkek321/items/19465ed85e8cb42af53c)
【Laravel】routeメソッドやリダイレクトで生成されるURLのホスト名を指定する


# 経緯
Laravel6.0

・Laravelはルートを指定していない場合`$_SERVER`から取得する。

・`$_SERVER`の値はサーバーの設定により決まる。
[PHP: $_SERVER - Manual](https://www.php.net/manual/ja/reserved.variables.server.php)

・サーバーの設定が複雑で期待する値が取得できなかった。

・リダイレクトやrouteメソッドで生成されるURLに影響がでて正しく遷移できない。

# 結論

UrlGeneratorにルートURLを設定することで、生成されるURLを固定できる

```php:app/Privider/AppServiceProvider.php

    public function boot()
    {
        // ルートURLを設定
        Illuminate\Support\Facades\URL::forceRootUrl(\config('app.url'));

        // 必要に応じてsslを強制する
        if (\config('app.env') !== 'local') {
            Illuminate\Support\Facades\URL::forceScheme('https');
        }
    }
```

```:.env
APP_URL=https://foo.com
```

# ソースコード（ざっくり）


`Illuminate/Routing/UrlGenerator.php`に`forcedRoot`を指定することで生成されるURLを変更できる。

```php:Illuminate/Routing/UrlGenerator.php


    public function formatRoot($scheme, $root = null)
    {
        if (is_null($root)) {
            if (is_null($this->cachedRoot)) {
                // forcedRootが設定されている場合は優先されるみたい。
                $this->cachedRoot = $this->forcedRoot ?: $this->request->root();
            }

            $root = $this->cachedRoot;
        }

        $start = Str::startsWith($root, 'http://') ? 'http://' : 'https://';

        return preg_replace('~'.$start.'~', $scheme, $root, 1);
    }

    // forcedRootを設定するためのメソッドがある
    public function forceRootUrl($root)
    {
        $this->forcedRoot = rtrim($root, '/');

        $this->cachedRoot = null;
    }
```

`forcedRoot`が指定されていない場合は`$_SERVER`から値を取得しているみたい。

```php:symfony/http-foundation/Request.php
 public function getHost()
    {
        // ここの処理がいまいちわかってない
        // プロキシを指定したときなどに関係ありそう
        if ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_X_FORWARDED_HOST)) {
            $host = $host[0];

        // $_SERVERから取得している
        } elseif (!$host = $this->headers->get('HOST')) {
            if (!$host = $this->server->get('SERVER_NAME')) {
                $host = $this->server->get('SERVER_ADDR', '');
            }
        }
```

[Symfony2のコントローラについてまとめた(後半) - OTOBANK Engineering Blog](https://engineering.otobank.co.jp/entry/2016/12/14/215350)

>    // $_SERVER['DOCUMENT_ROOT']
    $request->server->get('DOCUMENT_ROOT');

>    // \$\_SERVERのインデックスのうち、命名がHTTP_*に該当するもの
    // \$_SERVER['HTTP_USER_AGENT']
    $request->header->get('user-agent');


優先順位的には

1. $this->forcedRoot
2. $\_SERVER['HTTP_HOST']
3. $\_SERVER['SERVER_NAME']
4. $\_SERVER['SERVER_ADDR']

になりそう。多分。

# テスト（追記）

PHPUnitでテストを行う場合は`phpunit.xml`で`APP_URL`を空にしておく。

```php:FooTest.php
$response= $this->get('foo/bar');
$response->assertStatus(200);
```

```xml:phpunit.xml
<php>
        <server name="APP_URL" value=""/>
</php>
```

この記述がない場合、404がかえってきてテストが失敗してしまいました。


# 参考

[LaravelのURLジェネレーターで.envに設定したホスト名を使用する。 - Qiita](https://qiita.com/niiyz/items/f0b63e7afeb540a8b4b1)
共通化ではなく抽象化でいこう！

[Fringe81 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/fringe81)の24日目、本日はクリスマスイブですね！
1年間を通して気にしていたことを若干ポエム的な感じで書きます。

2019年は意識的に注意していたワードがあります。それは __共通化__ です。
意識しすぎたせいで、人の話を聞く時に __共通化__ というワードが出てくると、話の内容よりもどんなコンテキストで共通化を使っているのかが気になる感じになりました。

「こことここは似ているんで共通化します！」
「(その共通化はどういう意味だ？)」

みたいな感じですね。

ソフトウェアの世界、特にオブジェクト指向の世界では __抽象化__ というワードがあります。
最近は意識的に抽象化というワードを使っています。

僕が考える共通化・抽象化を定義したいと思います。といっても以下の影響が多分にあります。

[共通化という考え方はアンチパターンを生み出すだけ説](https://hachibeechan.hateblo.jp/entry/dont-think-just-make-it-abstract)

# 共通化
AとBから同じモノ・コトを見つけて、異なるモノ・コトを引くこと。
例えば関数だと、関数自体が同じモノ・コトになり、異なるモノ・コトが引数として現れます。

# 抽象化
AとBから同じモノ・コトを見つけて、異なるモノ・コトを引き、__概念を導き出し命名すること。__
最初は共通化と同じですが、最後が違いますね。
__概念を導き出し命名すること__が本当に重要だと思っています。
この行為ができていれば、その行為に対する名称を共通化と呼ぼうが抽象化と呼ぼうがどちらでも良いとも思っています。

ただ共通化から導き出されたアウトプットは、重複を排除するために同じ処理を関数に切り出しすことが大半になるのではと思います。
なので、共通化とはちょっと違うぞってことを意識付けできるように、敢えて抽象化という言葉を使うように僕はしています。
抽象化できれば、クラスに格上げできる余地も出てくるので。
概念が導き出せない場合は、所謂Helperみたない便利な箱を作るしか手はなくなると思います。

# 重複排除
最近は概念を導き出せない場合は別に纏めなくてもよいとさえ思ってきています。
ソースコード上重複しているから・似ているから纏めるのではなくて、意味として同じだから纏める、みたいな感じですね。
まぁただ、僕も共通部分をprivateな関数に纏めたりします。その時に関数の命名に苦労することがあります。
そういう場合は概念が導き出せていないのでしょうね。

同じことを何回もしたくないっていうのがエンジニアだと思うので、どうしても重複排除をしたくなる欲求は湧くと思います。
その時に概念を導き出せれば良いのですが、導き出せない場合は本当にその重複排除は必要かを自分に問いただすキッカケになります。

# 最後に
共通化と抽象化って似ているけどちょっと違いますね。
ちなみに、今回僕が定義した意味と辞書的な意味はもしかしたら違うかもしれません。調べてないけど。

ある言葉の意味を全ての人の中で同じ理解にすることは不可能だと思っています。
ただ、同じ理解に近づけることは可能だと思っているので、言葉に敏感になっていきましょう！
プログラミングってある事象をソースコードに再定義する行為なので、言葉の理解を近づけるのは大切です！

では良いクリスマスイブを！！
【初心者向け】SEが言う「アプリ」とは？


## はじめに
未経験からアプリエンジニアになると大体聞かれるのがこの質問。

「アプリエンジニアって何作ってるの？　インスタとかそういう？」

こういう質問をされる場合、たいてい相手の頭の中にあるのはモバイルデバイス上の「ネイティブアプリ」のアイコンです。

<img width="300" alt="smartphone.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469936/7102b45a-22a5-f484-387c-c3a9406b5645.png">

そもそも、エンジニア界隈での「アプリ（＝Webアプリ）」と、一般的な用法としての「アプリ（＝スマホアプリ、ネイティブアプリ）」は基本的に別物なのですよね……（もちろん重なってはいるものの）
なんで同じ名詞を採用してしまったのか……命名って大事ですね……

エンジニアと非エンジニア同士の会話では、「アプリ」の認識合わせを行わないまま話が進むことが多々あり、そういう現場を目にすると非常に歯がゆい思いになります。
それだけでなく、ビジネス上の会話で、ここの認識がずれていると、ちょっと悲惨な手戻りが発生する可能性もあります。

今回は、

- エンジニア的「アプリ（＝Webアプリ）」とは何なのか？
- スマホアプリと何が違うのか？

という2点について、ざっくりご説明いたします！

## Webアプリって何？
そもそもWebアプリとは何なのでしょうか？

[プロになるためのWeb技術入門](https://gihyo.jp/book/2010/978-4-7741-4235-7)によるとWebアプリとは以下のように説明できます。

> 主な処理はサーバー上で行われ、
> HTMLで表現されWebブラウザー上で表示される、
> ダウンロード不要のアプリケーション

サーバー上にサービスを提供するアプリケーションが存在して、手元のPCやスマホは主にサーバー上のアプリケーションが一生懸命考えて処理した結果を表示しています。

Amazonや楽天で買い物をし、YouTubeやNetflixで動画を見る……というように、ユーザーが、Google Chrome、Safari、Internet ExplorerなどのWebブラウザーを介して、能動的に検索をしたりフォームを入力して利用するサービスは「Webアプリ」です。
![スライド2コピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469936/5a0591a6-3ed5-7ca5-8298-c80bbdf03b16.png)


### WebアプリとWebサイトの違いは？
Webアプリはユーザーが**能動的に**利用する、対話型サービスであり、Webサイトは情報提供を目的としているサービスのことを指します（[Web サイトから Web アプリケーションへの変換：第 1 回 Web サイトと Web アプリケーションの違い](https://www.ibm.com/developerworks/jp/web/library/wa-websiteapp/index.html)より）。
たとえば[Wikipedia](https://ja.wikipedia.org/wiki/)は、サービス内で主にリンクを飛んで情報を閲覧するサービスなので、Webサイトです。

一方、[Amazon](https://www.amazon.co.jp)は、もちろん商品情報閲覧もできますが、商品を購入する過程でフォームに住所を入力したり、ポイントを使用するかしないか選べたり……と、対話が発生しているので、Webアプリです。

## スマホアプリとの違いは？
Webアプリがインストール不要である一方、利用する前にアプリケーション（ソフトウェア）をインストールする必要があるものは、PC用なら「デスクトップアプリ（ソフトウェア）」（Microsoft WordやOutlookなど）、
スマートフォン用なら[App Store](https://www.apple.com/jp/ios/app-store/)や[Google Play](https://play.google.com/store)などからダウンロードする「スマホアプリ（ネイティブアプリ）」といいます。

エンジニアの中では、「アプリエンジニア」というと前述のWebアプリを開発するエンジニアを指していて、スマホアプリを開発するエンジニアは「ネイティブアプリエンジニア」と呼ぶことがあります。

スマホアプリの場合、処理がデバイス本体で行われるため、いちいちサーバーとのやり取りが必要なWebアプリと比べて、処理が高速であることが特徴です。多くのゲームアプリがWebブラウザーを介さず、デバイスに直接インストールするタイプのアプリであるのも、この理由からです。
<img width="300" alt="game_friends_smartphone_boy.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469936/239a5c0b-08b3-a16d-46e3-54237090deac.png">

ちなみに…ややこしいですが、Webブラウザーそのものは「デスクトップアプリ」あるいは「スマホアプリ」です（Webブラウザーはデバイスにインストールしていますよね！）。

## おわりに
エンジニアとビジネス上で関わる機会のある方は、「エンジニアの言う『アプリ』は、ひょっとしたらスマホアプリのことじゃないかもしれない」という可能性を知っておいていただけると嬉しいです。

逆にエンジニア志望の学生などと話す機会のあるエンジニアは「『アプリエンジニア』と言うと、学生はネイティブアプリ開発のイメージを持ってしまうかもしれないから、補足しておこう」などと想像して話をすると、誤解のない会話ができるかと思います！
EPSONスマートグラスMOVERIOにアプリをビルドしてみた

Unityのアセットを使ってMOVERIOにAPPビルドしてみたメモ
MOVERIOはAndroid5.1のようなのでSDKも同じバージョンを用意するようにしました

## BT-350を体験してみた感想
BT-350を使ってみた感じは、中身はAndoridタブレットのUIでした
トラックパッドなコントローラーあるですが使いづらい感じでした。。
表示は輝度も高く見やすいですが、歩きながらだと、注視点が画面になるので、ぶつかりそうで危ない感じですた
映画に出てくるような、スマートグラス感は無いです

## Android5.1のビルド環境を準備

### Unity HubなどでAndroid書き出し環境のモジュールをインストール
![NoName_2019-12-24_11-48-56_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48015/50aae678-dc3d-629f-3e25-640e7a9e5252.png)

### AndroidStudioでSDKをインストール
Tools > SDK Manager > AndroidSDK でAndroid 5.1 (Lollipop)をインストール
![NoName_2019-12-24_11-50-33_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48015/7bb284bd-246a-4909-eb2e-a7cef108ee40.png)


## Unityでサンプルプロジェクトをビルド
![NoName_2019-12-24_11-53-9_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48015/731d3ba6-d101-bd15-d94d-e4afac2c0074.png)

## 参考サイト

スマートグラス・スマートヘッドセット
https://www.epson.jp/products/smartglasses/

Moverio BT-300 Unity Plugin
https://assetstore.unity.com/packages/tools/integration/moverio-bt-300-unity-plugin-83627