OmniAICreator/Qiita-1.07M huggingface dataset:
HerokuのReview AppでStaging AppのDBをコピーする

# はじめに
* GithubのPull RequestをフックにHerokuのReview appsを自動Deployするパイプラインを構築した際に悩んだ事を備忘としてまとめています。

# （My）環境
* DjangoアプリをHerokuでホストしており、DBとしてHeroku Postgresを利用

# デリバリー
* Gitのブランチ運用(戦略)はGitHub Flowを採用。
* Herokuパイプラインを構築しており、Review AppのParent AppはStating Appを指定、
* Staging AppがGithubのmasterと同期しており、Production AppはPromote to productionの手動実行によりDeploy
    * ソースコードはGithubでホストしており、Githubのmasterに対するプルリクエストをトリガーにReview AppがDeployされる。
    * Review Appで動作を確認後、Pull Requestをmasterへmerge。
    * masterへmergeされると、masterブランチの更新をフックにHerokuのStating AppがDeployされる。
    * Staging Appで動作を確認後、HerokuパイプラインのPromote to productionボタンにより、Production AppがDeployされる。

# 悩んだ事
* Review Appにも当然AddonとしてPostgresを利用しており、**工夫せず**ビルドすると、DBが空の状態でDeployされ、manage.py migrateが必要だったり、CreateSuperUserしたりと一手間必要となる。
* またPull Requestの内容によっては、テストデータが合った方が良い場合、無い方が良い場合が存在する（と考えられる）

# アプローチ
* Reviewの都度、手動実行する事は現実的ではなく、HerokuではReview Appの振る舞いを決めるapp.jsonによってDeploy後に発生する手動作業を軽減出来る。
* app.jsonによりテストデータ有りの場合、無しの場合の振る舞いを再現する。

# やってみた

## テストデータ無し（migrateのみ実行する）
* env(Config Vars)は意識せず、scriptsのみで完結。
* この場合、テストデータが存在しない状態になる。

```app.json
(略)
"scripts": {
    "postdeploy": "python manage.py migrate"
  },
(略)
```
* https://devcenter.heroku.com/articles/github-integration-review-apps
* 上記の通りHeroku公式によると、test dataをreview appにloadする際にもpostdeployを利用せよとの事なので以下を

## テストデータ有り（stating appのデータをreview appにリストアする）
* staging appのConfig varsにはpostgresのデフォルトKey名として「DATABASE_URL」が採用されている。
* app.jsonではConfig varsの値をscripts内で参照し、コマンド実行する事が可能。
* Config Vars(env)の値にはStringしか設定できないため、単純にStaging AppのDABATASE_URLをReview AppのDATABASE_URLに設定という記述をenvに閉じて実行する事は出来ない。（っぽい）
* よって、scripts内でParent App(Statging App)のDATABASE_URLをReview AppのDATABASE_URLに設定する為に以下のようにする。

1. Staging AppのDATABASE_URLの値をコピーし、STG_DATABASE_URLとして設定
    * Review appのDATABASE接続先にDATABASE_URL(というKEY名)を利用する場合、Staging AppのDATABASE接続先に別名を付与する必要があるため
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473617/48567354-e610-cc5f-119d-189ed3f1d39a.png)

2.　app.jsonのenv及びpostdeployで以下のように指定

```app.json
（略）
"env": {
    "STG_DATABASE_URL": {
      "required": true
    },
    "HEROKU_APP_NAME": {
      "required": true
    }
  },
  "formation": {
    "web": {
      "quantity": 1
    }
  },
  "scripts": {
    "postdeploy": "pg_dump $STG_DATABASE_URL | psql $DATABASE_URL"
  },
(略)
```

# まとめ
* app.jsonをブランチにPushする際にテスト内容に応じ都度変更していく事は手間であるため、テストデータ有りを前提としつつテストデータが不要な場合は、Reset Databaseを実行する。
【Android】Floating Action Button（FAB）のアイコンを書き出す時の注意点

#はじめに

今回はマテリアルデザインのフローティングボタンについて学んだことをメモしたいと思います。

#フローティングボタンとは？
![floatong_btn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486362/240d2368-a6c7-c042-a320-d65834937497.png)

>**1ページあたり1つまで**

FABは基本的に1ページにつき1個だけ使うことが推奨されており、最重要な操作を行うためのボタンである。

※ フローティング操作ボタンはFAB（Floating Action Button）と略される

>**ボタンは基本円形**

マテリアルデザインでは、ユーザーが重要なボタンだと直感的に判断できるように円形にすることが決められており、勝手にオリジナルの形に変更することは許されていない。（Extended FABは別）

>**Extended FAB**

2018年に**Extended FAB**というスタイルがガイドラインに追加され、ボタン内にアイコンだけでなくテキストを含めることができるようになった。

マテリアルデザイン公式↓
https://material.io/components/buttons-floating-action-button/#types-of-transitions


#アイコンの書出し設定時の注意点
アイコンのサイズはマテリアルデザイン推奨の余白ありの**24dp**で用意すること。

ここで注意したいのは、マテリアルデザインの標準アイコンを使うのなら問題はないが、自作のアイコンの場合は**アイコンの周りに必ず余白を設ける**こと。

余白がないアイコンを設定してしまうと24dpいっぱいにアイコンが拡大されてしまい、アイコンがでかく見えてしまうという罠が…。　標準のアイコンはすべて余白込みの24dpなのでそのまま使用すればOK。

マテリアルデザインの標準アイコン↓
https://material.io/resources/icons/?style=baseline

##失敗談
今回初めてフローティングボタンをデザインした訳ですが、何も分からずに作ったため背景の丸まで込みの画像素材を書出し設定してしまい、「ちがうやーん！」ってなりました。
ボタン一つでもきちんと概念を理解しなければきれいに作成できないので、とても勉強になりました。

--以上
新入社員でIT系の企業で仕事を始めた頃の自分を振り返る

## 〜宣伝〜

:::note info
個人開発でエンジニア専門マッチングサービスを開発しましたので、是非未経験からエンジニア目指している人！現役エンジニアで教えたい人！使ってみてください！

β版リリース記念キャンペーン中です！

10名様限定、抽選でお好きな技術本1冊プレゼント！
🎉当選者にはメッセージ差し上げます(送付の際に住所はお聞きしません)
詳しくはこちらから↓

https://x.com/dokupro01/status/1796837336145436846
:::
https://dokupro.dev/

# 目的

- 新卒でIT系の会社に入ってから1年ちょい経過したため、新人のことを振り返る。
- 現在の新人さんがどんなことに困っているか書く。
- 自分が困ったことを整理し、現在の新人さんへの教育を見直す。
- あまりIT系特有の困り事に偏ってまとめない

# この記事のターゲット

- 新人さんを教育している先輩社員の方
- 新卒の新人の方
- IT系企業に就職機能・内定が出ている学生の方

# 苦労したこと

- 現場に配属されても先輩社員が忙しくどうしても放置される時間があった。  
しょうがないことだが、放置される時間が一番つらかった記憶がある。自分なりに何か生み出そうとしても、プロジェクトに対して一切知識がないので何もできない。
- 新しい知識が1日の間に100個くらいインプットされるので整理が追い付かない。  
完全に脳の記憶容量がパンクする。性格というか癖なのかわからないがそこまで覚えがいいほうではなかったので教えてもらった作業自体もちゃんとできているか不安だった。
- 職場の雰囲気に慣れようとして自身の置かれる環境に疑問を抱かない。  
ほんとにこの作業は効率がいいのか、本当にこのやり方で問題がないのか、そもそもこれは何の作業なのか、知識の引き出しがなく判断できない。
- ショートカットがないのでオンプレサーバへのファイルパスが分からない。  
本来聞けばいい話。ちょっとこれは自分だけかもしれない。
- 技術知識がなかったので会話についていけない。  
プロジェクトの独特な用語や、人によって同じものに対し違う名詞を使うことがあって困った。「その作業は～時間かかります」も「その作業は～Hかかります」のように簡単なこともわからなかった。
- ストレスの逃がし方を知らない、人の便り方を知らない。  
行き詰ったときにどうしていいかわからないことがあった。先輩へのうまい便り方もわからず、わかっていないことの説明もうまくできない。
- すべての作業に大きな責任を感じる。  
「社会=多額なお金が動いている」とビジネス研修で教わっていたため、ミスをしたら本当に大変なことになると思いずっと気を張っていた。本来ずっと気を張っていないといけないとは思うが気を張るレベルが分かってないので常に100%で気を張っている。
- 職場にある技術書が自分に合わない。  
なぜか汎用てきな入門書は自分には合わないことが多かった。おそらく本が悪いわけではない。ターミナルなどを知らなかったので、Linuxコマンド集よりどこでその本に載ってるコマンドを実行したらいいのかを教えてほしい。
- 今教えてもらっている作業はどんな作業なのかが分かっていない。  
俯瞰して物事を見ることができていなかったため、ミクロな作業としてはできるが、今自分がどんな作業をしているかがマクロでわかっていない。

# 楽しかったこと

- 学生のときの研究室とは全く違った規模間だったこと
- なんでもいいから先輩から褒められると幸せだった
- 作業を自動化して作業時間の短縮をしたこと
- 新しい知識がどんどんインプットされて、バラバラの知識の歯車がかみ合ったこと

# あの頃の自分にアドバイス

- わからないことはしつこいと怒られてもいいから聞こう。
- 今自分ができることとできないことをまとめよう。
- できないことに関して素直になろう。
- 社外のエンジニアコミュニティにも参加してみよう。
- 不明点を先輩に聞くときに、何をどう調べてここまでは分かったが、そこから先がわからなかったため教えてほしいと伝えよう。

# これから(新人を育てる立場として)

- 新人たちが手すきになる時間を作らないようにする。
- 詳細な作業をレクチャするときには大枠の作業名を伝える。(例えばレクチャ前に「今日はソフトウェアのローカルビルド作業のソースコードの取得をレクチャしようと思っているよ」と先に伝える)
- こまめな1 on 1を継続実施する。
- 機会を見つけて社外のエンジニアイベントに誘ってみる。
Sublime Text 3でPackage Controlをインストールできない時に試す事

#前提として

Sublime Textにプラグインを入れるなら、まず「Package Control」と言うのを入れないといけない。

https://packagecontrol.io/installation#Simple
:point_up:パッケージコントロールのインストールページ

やり方は2つ。
①sublimeのコンソール画面からコードを入れる
②自分で直接ファイルを入れる

①と②共に[公式ページ](https://packagecontrol.io/installation#Simple)を見ればできるだろう。

**この記事はどっちを試してもできない！！！と言う人向けのものである**


#キーワードは「ignored_packages」

ここから私の体験談と共に見ていこう。


私も当然最初は
①sublimeのコンソール画面からコードを入れる
でやってみた。

が、


<img width="1187" alt="スクリーンショット 2019-09-11 21.28.52.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167220/ece885eb-244d-95a2-8fca-f9a1b4d2648c.jpeg">


こんな感じで一向にPackage Controlのインストールが終わらない。

最初は
「あれ？まっとけばいいのか？」

「再起動してみよう！」

「sublimeもう一回入れ直してみよう！！」


とか色々したが、結局Package Controlは現れず。。。。


##犯人は設定にいた。

`Preferences > Settings`

の中に**「ignored_packages」**なるものが存在する。（ignoreは無視するって意味）

ここを確認すると、なんと「Package Control」があるじゃないですか・・・。

<img width="500" alt="スクリーンショット 2019-09-11 21.22.49.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167220/e7c885f0-7288-fe9a-4e79-5ec5fbbba28f.jpeg">


「Package Control」は無視されていた訳だ。。。。

（なぜ？？）

#Package Controlをインストールする手順

①`Preferences > Browse Packages…`で同じ階層にある`Installed Packages`の中を確認

②`Installed Packages`の中の**Package Control.sublime-package**ファイルを削除

③`Preferences > Settings`の中の**ignored_packages**に**Package Control**が無いことを確認

④[公式ページ](https://packagecontrol.io/installation#Simple)のManualの項目から、Package Control.sublime-packageをダウンロード

⑤`Preferences > Browse Packages…`で同じ階層にある`Installed Packages`に、④でダウンロードしたPackage Control.sublime-packageを配置

<img width="487" alt="スクリーンショット 2019-09-11 21.32.20.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167220/57159719-371d-d9e4-6fb9-2e7daaf04b7e.jpeg">




sublimeを再起動。


<img width="486" alt="スクリーンショット 2019-09-11 21.35.24.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167220/6062a799-0fb0-900e-03fa-1da2cc5c0830.jpeg">


Package Controlがある。


##ちなみに

`Preferences > Package Control`を押すと、

<img width="701" alt="スクリーンショット 2019-09-11 22.18.26.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167220/847cf385-f186-2811-5ea9-3d03f37bc94d.jpeg">

こんな感じになる。

この時、**Package Control: Install Pacage**を押してから、目当てのプラグインとかを入力しよう。

（初めて使った時私は、Package Control: Install Pacageを消してからプラグイン名を打ち込んでた。。。。「あっれ〜？また失敗？」とか思ってた。）

##参考
https://github.com/wbond/package_control/issues/1282

https://www.panzee.biz/archives/11903
転職黙示録 (3) JavaScriptのために1ミリもHTMLを書きたくない人のためのNode.js

# HTML書くのめんどくさい

　「よしJavaScriptをやるぞ｜と思ってもいざコードを書くとなるとHTMLが必要です. VSCodeならhtmlと打ち込むとボイラープレートが生成できます. ここにscriptタグを足してやればブラウザのコンソールで入力を確認したりできます.

```html:index.html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <script type="text/javascript" src="./index.js"></script>
    <title>Document</title>
</head>

<body>

</body>

</html>
```

　もちろんできますが面倒です. ブラウザを開く必要もあります. そこでNode.jsの出番です.

# Node.jsって何?

　公式ページによると以下のような説明がされています.

> Node.js はスケーラブルなネットワークアプリケーションを構築するために設計された非同期型のイベント駆動の JavaScript環境です.

　よし分からん. サーバーサイドJavaScriptなどとも言われますが, JavaScriptを普通のプログラミング言語のように動かせる実行環境だと思えばいいです. サーバーというのはつまるところコンピュータのことですから. つまりNode.jsはJavaScriptをコマンド・ラインで実行できるわけです.[^1] ブラウザに閉じ込められていたJavaScriptの真の力が発揮されるわけです. Node.jsの導入の仕方などはネットで検索してください.[^2]

# Node.jsでHello, World!

```javascript:index.js
console.log("Hello, World!");
```

```bash
node index.js
# Hello, World!
```

　簡単ですね? JavaScriptという言語を試したいけど一ミリもDOMとかWindowとか使わんしHTMLのボイラープレート書くのめんどくさい, そんな感じで心が折れているあなたはNode.jsで解決です:point_up:[^3]

# 付録

## コード・サンプル

　とりあえずNoe.js環境を整備して以下を実行してみよう!

```javascript
const pets = ["🐱", "🐶", "🐷"];
const newPets = ["🐮", ...pets];
console.log(newPets);

const hasCat = newPets.includes("🐱");
if (hasCat) {
    console.log(`animals includes ${newPets[0]}`);
}
```

## ブラウザ環境との違い

 windowは存在しないのでglobalというのが代わりになるようです.

```javascript
function noWindow() {
    if (this === global) {
        console.log("windowは存在しません");
    }
}

noWindow();
```

　またconsole.logで関数名だけを渡しても文字列にはならないのでtoStringで文字列に変換する必要があります.

```javascript
function MyFunc() {
    return "定義は見えてますか?";
}
console.log(MyFunc.toString());
```


[^1]: 当然ですがDOMなどはその対象となるHTMLがないので使えません.

[^2]: 私はnodenvを入れています.

[^3]: つまり私のことです.
androidシミュレータのstorage容量の変更

# シミュレータ起動の際にエラー発生

```
com.android.ddmlib.InstallException: INSTALL_FAILED_INSUFFICIENT_STORAGE
```
storage容量が足らないのが原因のため、設定値を変更します。

# storage値の変更

Android Studioから`AVD`ページへ移動します。
下記青囲み線から、該当ページへ行き変更します。
今回は`2048`に変更しました。
![Screen Shot 2019-09-10 at 18.00.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/291139/213cc57c-a55a-b1f7-0749-a943db7cdbf4.png)
![Screen Shot 2019-09-10 at 17.59.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/291139/1b858c19-59c5-8a49-5fdd-fddca7f40ced.png)
![Screen Shot 2019-09-10 at 18.00.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/291139/ce610637-5d55-96f3-8fe6-e4c711ddb79f.png)
PythonによるHTTP/HTTPS通信について【備忘録】

# メモ

PythonによるHTTP/HTTPSは様々な標準モジュールがある。代表的なものであると以下のものがある。

- http
- urllib
- urllib3
- requests

自分はurllib3モジュールとrequestsモジュールを試したが、どうもrequestsモジュールの方が使いやすい（Anaconda/Spyder上ではpipの必要なし）。詳しい使用方法については下記サイトを参考とする。

以下にサンプルコードを示す。参考サイトを見ればわかる通り、requestsモジュールであればGET通信やPOST通信などのHTTP/HTTPSの通信用の関数は別途用意されている。レスポンスデータは「data.text」に格納されている。

```python:example.py
import requests

url = "https://www.google.com/?hl=ja"
data =requests.request("GET", url=url)
print(data)
```

```text:実行結果
<Response [200]>
```

# 参考
- [Requests の使い方 (Python Library)：Qiita](https://qiita.com/sqrtxx/items/49beaa3795925e7de666)
#Ruby 2.7.0 で改行できるようになったコンソール irb を使ってみる

# Try using console irb that can start a new line in Ruby 2.7.0


それだけ。

```
rbenv install 2.7.0-dev
```

```
irb
```

![image](https://user-images.githubusercontent.com/13635059/64682579-afce8c00-d4bc-11e9-80b6-3993f34b3389.png)


入力中であればDELETEキーで戻ることもできるみたいです！


# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/2408








<!-- Update From Qiita API -->

# チャットメンバー募集


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

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





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
httpとhttpsの違い

#はじめに
この記事ではhttpとhttpsの違いについて書こうと思います。

# HTTPとは
HTTPとはクライアント・サーバ間でデータを送受信する際の通信プロトコル。

Webサイト閲覧においてWebブラウザからWebサーバーに対してデータを要求した際は、アプリケーション層では```HTTP```、トランスポート層では```TCP```、インターネット層では```IP```、ネットワークインターフェース層では```イーサネットプロトコル```が利用されている。

#HTTPとHTTPSの違い

Webサイトショッピングやネット予約の普及に伴い、HTTPSが利用されるようになった。

HTTPSとはHTTP over SSL/TLSの略でHTTP通信においてSSLやTLSを用いることでデータを暗号化方式で送受信するもの。

#安全を確保する仕組み

HTTPSで利用されるSSL/TLSでは以下の三つの仕組みにより安全性を確保している。

###盗聴防止（暗号化通信）

**データを暗号化**することで、万が一データを傍受されても解読されない。

###改ざん防止
**メッセージダイジェスト**を利用して送信するデータのハッシュ値を計算し、データと一緒に送ることで、受け取り時のハッシュ値を計算したものと値が異なっていれば改ざんが検知できる。

###なりすまし防止
Webサーバーに**認証局により配布されたSSLサーバ証明書を配置**しておくことで、ブラウザ側はWebサイトの運営元が確認できる。

#HTTPSのデメリット
セキュリティ・信頼性の向上はメリットとして挙げられますが、デメリットもいくつかあったりする。
###運用コストがかかる
SSLサーバー証明書を取得するために初期コストがかかるプラスで、取得後も転送設定やパス修正などサイト改修に手間がかかってしまう。

###ツールや広告が表示されなくなることがある
SSL非対応のツールや広告は表示されなくなる場合がある。設定を変更する手間がいりそう。


#終わりに
今やHTTPS化していないWebサイトには警告表示「保護されていません」が出ます。
またSEOの面でもHTTPS化してる・していないでランキングに影響するようなので必須で利用する必要がありそうですね。
エラー[debug.keystore' not found for signing config](ReactNative)

# androidシミュレータ起動の際にエラー発生

```
Execution failed for task ':app:validateSigningDebug'.
> Keystore file '/android/app/debug.keystore' not found for signing config 'debug'.
```

# 解決法
`android/app`直下に下記URLから`debug.keystore`をダウンロードし格納する。
[Keystore file '/Project-Folder/android/app/debug.keystore' not found for signing config 'debug' in react-native 0.60](https://github.com/facebook/react-native/issues/25629)
秒でaxiosをモックするnpmモジュールの入門サンプル

突然axiosのGET/POST/PUT/DELETEを丸ごとモックしたくなるときってありますよね！
[axios-mock-server - GitHub](https://github.com/m-mitsuhide/axios-mock-server)

## インストール
```bash
$ npm i axios axios-mock-server
```

## APIエンドポイント定義

`/users` のGETとPOSTを `mocks/users.js` に定義する

```javascript:mocks/users.js
const users = [{ id: 0, name: 'taro' }]

export default {
  get: () => [200, users], // 返り値は [status, body?, headers?]

  post: ({ data }) => {
    users.push({
      id: users.length,
      name: data.name
    })

    return [201]
  }
}
```

## npmスクリプト定義
モックAPIルーティングファイルをビルドするnpmスクリプトを定義

```json:package.json
{
  "scripts": {
    "mock:build": "axios-mock-server -b"
  }
}
```

## ルーティングファイルをビルド
npmコマンドで起動。 `mocks/$mock.js` が生成される。

```bash
$ npm run mock:build
```

##axiosのモック化
環境変数を見て開発中だけaxionのモックを有効にするメインの `index.js`

```javascript:index.js
import axios from 'axios'
import mock from './mocks/$mock.js' // ビルドで自動生成されたファイル

if (process.env.NODE_ENV === 'develop') {
  mock() // axiosのモック有効化
}

(async () => {
  await axios.post('/users', { name: 'yoko' })

  const users = await axios.get('/users')
  console.log(users.data) // [{ id: 0, name: 'taro' }, { id: 1, name: 'yoko' }]
})()
```

## もっと詳しく
他にもモックサーバーに必要な機能はだいたい揃ってます。
[RESTfulな「axios-mock-server」の使い方 - Qiita](https://qiita.com/m_mitsuhide/items/b8e073cba0dae5af2359)

メインのJSファイルのビルドはこの記事のスコープ外なので解説しませんでした。
webpack/parcel/browserifyあたりを普段通りに使ってください。
Terraform + AWS環境でIAMポリシーを書いていたら「MalformedPolicyDocument: Has prohibited field Resource」というエラーが出た

全く大した話ではなく、TerraformでEC2にIAMポリシーを割り当てようとコードを書いていたら掲題のエラーが出力されて少し調べたのでメモ。

`Terraform: Error creating IAM Role. MalformedPolicyDocument: Has prohibited field Resource`

使っているTerraformのバージョンは0.12.6

その時のTerraformのコードはこんな感じです。

```
resource "aws_iam_role" "this" {
  name = "iam_role"

  assume_role_policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "eks:UpdateClusterVersion",
                "eks:DescribeCluster",
                "eks:ListClusters"
            ],
            "Resource": "*"
        }
    ]
}
EOF

resource "aws_iam_instance_profile" "this" {
  name = "profile"
  role = aws_iam_role.this.name
}

```

よくよく考えるとassume-roleブロックに直接ポリシーを書いているのはまあ、違和感があるかも。。。
とか考えてました。


## 結論
aws_iam_roleには信頼ポリシーと呼ばれる記法で委譲する対象を指定しなければならない。
元々期待していたポリシーに関する記述はaws_iam_role_policyと言うresourceに書きましょう。

認証、認可やassume-roleの概念について雰囲気でしか理解していなかったため、
うっかりassume-roleに直接ポリシー書いてしまっていたと言うチョンボなお話でした。

下記の様なコードに修正。

```
resource "aws_iam_role" "operation_iam_role" {
  name = "iam_role"

// ここに権限を委譲するポリシーを書く
  assume_role_policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Principal": {
            "Service": "ec2.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
EOF
}

// このresourceを追加してポリシーを記載する
resource "aws_iam_role_policy" "this" {
  name   = "iam_role_policy"
  role   = aws_iam_role.this.id
  policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "eks:UpdateClusterVersion",
                "eks:DescribeCluster",
                "eks:ListClusters"
            ],
            "Resource": "*"
        }
    ]
}
EOF
}

resource "aws_iam_instance_profile" "this" {
  name = "profile"
  role = aws_iam_role.this.name
}
```
無事にapplyし、EC2にIAM-Roleを割り当てる事ができました。

## 参考
[AWS IAMポリシーを理解する](https://dev.classmethod.jp/cloud/aws-iam-policy/)
[Terraformを使ってEC2インスタンスにIAMロールを当ててみる](https://cross-black777.hatenablog.com/entry/2015/12/04/233206)
Excel小技（VBA）特定文字列セルの隣セルにコメントを追加する

```VBA:VBA
ub updateAllSheet()

Application.ScreenUpdating = False 
  Dim シート As Worksheet
      For Each シート In Worksheets
          シート.Select
          Call rowJ
      Next シート
Application.ScreenUpdating = True

MsgBox ("Finished")
End Sub



Sub rowJ()

For i = 1 To 100
 a = "*コメント*"
 If Cells(i, 7).Value Like a Then
  
  Cells(i, 10).Value = Cells(i, 10).Value + " コメントを追加する"
  Cells(i, 10).Interior.ColorIndex = 38
  
 End If
 
 Next i
 
 
End Sub


```
Cloud Functions for Firebaseでスプレッドシートに書き込む

# やりたいこと

Firestoreの特定コレクションにドキュメントが追加されたら
その内容をスプレッドシートに書き込みたい。

# 手順

## 書き込むスプレッドシートに、GAEのサービスアカウントが書き込めるようにする

Firebaseコンソールの「設定」→「サービスアカウント」から
「サービスアカウント権限の管理」リンクから、GCPの「IAMと管理」に飛び
名前が「App Engine default service account」となっている
`＜プロジェクトID＞@appspot.gserviceaccount.com` をメモしておく。

書き込みたい対象のスプレッドシートの「共有」メニューで
上記GAEのデフォルトサービスアカウントに権限を付与する。

## Google Sheets APIを有効にする

GCPのコンソールから「APIとサービス」→「ライブラリ」を開き
「Google Sheets API」を検索し、有効にする

## googleapis ライブラリを追加する

```
$ npm install googleapis
```

## functionを実装して、デプロイする

```javascript
const functions = require('firebase-functions')
const {google} = require('googleapis');

exports.appendSpreadSheet = functions.region(functions.config().region.name).firestore.document('test/{testId}').onCreate((snap, context) => {
    const test = snap.data();

    return google.auth.getClient({
        scopes: ['https://www.googleapis.com/auth/spreadsheets']
    })
    .then(auth => {
        const sheets = google.sheets('v4');
        return sheets.spreadsheets.values.append({
            auth,
            spreadsheetId: "*************", // 書き込みたいスプレッドシートのID
            range: "****", //書き込み先のシート名やセル範囲
            valueInputOption: "RAW",
            insertDataOption: "INSERT_ROWS",
            resource: {
                values: [
                    [
                         context.params.testId, //ドキュメントID 
                         test.foo               //ドキュメントの任意の属性を必要なだけ入れる
                    ]
                ]
            }
        });
    })
})

```

これで、 `test` コレクションに ドキュメントを追加すると、スプレッドシートに書き込める。

# 補足

意外とこの方法がネット上で載ってなく
Googleのドキュメントでも OAuth2使った少々煩雑なサンプルしかなく
サービスアカウント使えばもっとシンプルに実装できるはずだよなぁ、と実験していてたどりついたのがこの方法。

なお、`auth` に 認証情報のjsonを渡している例や、環境変数 `GOOGLE_APPLICATION_CREDENTIALS` を利用する例もあったが、
Cloud Functionsから利用する場合には、これらはなくても動いた。
その理由については以下が詳しい。

https://dev.to/seizans/gcp-api--429k

ADCを得るロジックで、3番目に

> GAE (Google App Engine) 上で実行されていれば、その built-in service account を使う

とあり、Cloud Functionsは、裏の実行環境としてはGAEなのだろう、そのサービスアカウントを
スプレッドシート側で共有に設定していれば認証は通る模様。
雑に紹介するオンラインで学習できるサイト

オンラインで学習できるサイトをまとめたので、雑に紹介する

# udemy
https://www.udemy.com/
コース：幅広くビジネススキル、デザイン、写真、マーケティング、ITとソフトウエアなど
料金：教材単位で買い切り。

# LinkedInラーニング
https://learning.linkedin.com/
linkedinIDでログイン。
コース：udemyに似てるかも。
料金：月額2,990円。期間内無制限

# progate
https://prog-8.com/
プログラミング特化
料金：月額980円。

# qwiklab
https://www.qwiklabs.com/
AWS、GCP重点。実際に作れる模様。
料金：クレジットによる都度購入。または使い放題で月間$55

## AWS セルフスペースラボ
https://aws.amazon.com/jp/training/self-paced-labs/
qwiklabを利用している模様
AWS版
## GCP 無料のハンズオン トレーニング
https://cloud.google.com/training/free-labs/?hl=ja
qwiklabのGCP版
GCPを初めて使う人のための使い始めガイド

# 概要
## GCP とは
GCP (Google Cloud Platform) とは、いわずもがなGoogleが提供しているクラウドサービスです

まずは使ってみよう！

# はじめかた

https://console.cloud.google.com にアクセス
![2019-09-11 17_55_14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136348/5cea33fe-57f0-9f76-00f8-e593478fb91f.png)

**無料トライアルに登録** をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136348/f75b42a0-3f0f-88f9-44af-41c14021bfd0.png)
利用規約をチェックしてから、**続行** をクリック

![2019-09-11 18_01_41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136348/4d93fa6e-7358-7c05-6347-b826bf33429d.png)
![2019-09-11 18_02_42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136348/fb792dd7-78d9-1f30-a09d-a513ed55902c.png)
必要事項を入力して、**無料トライアルを開始** をクリック
![2019-09-11 18_05_17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136348/f68fe5a2-c4cb-f44e-cf3b-61e52c085172.png)
**OK** をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136348/9187f9e4-542a-6160-6141-515f9c0bba5e.png)
**Compute Engine** をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136348/12d5a3bb-1105-56fb-58c7-112854422d9d.png)
準備に数分かかる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136348/25d8ed5e-a4dd-ddd5-bd5e-cdcf3a5d538a.png)
**作成** をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136348/557b6f4a-8766-bff6-fbf2-21a95f99c061.png)
必要事項を記載する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136348/c591185d-650d-dfcc-0a22-10c9fc04b72b.png)
**作成** をクリックする

![2019-09-11 18_22_18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136348/707a2864-9e15-3f41-7942-45b75358af4b.png)

**SSH** をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136348/cfccf8f4-d403-eebc-7e1f-6eb04396cc22.png)

![2019-09-11 18_25_00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136348/244d2986-df47-d636-1905-19de87253c96.png)

デフォルトのユーザ名が自分の本名なのはびっくりする...
【QAメモ】GitHub Enterpriseで実現するDevOps 〜 新機能GitHub Actionsを使ったCI/CDの構築 [セミナー] 参加レポート

今日はMicrosoft社主催のGithubのCI/CD構築セミナーに行ってきました。
　
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">これいってくる<br><br>&gt; GitHub Enterpriseで実現するDevOps 〜 新機能GitHub Actionsを使ったCI/CDの構築 [セミナー] 東京開催</p>&mdash; gkz (@gkzvoice) <a href="https://twitter.com/gkzvoice/status/1171563352121696256?ref_src=twsrc%5Etfw">September 10, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

セミナーの内容としては以下の3本でした。
- Github Actionsでできること
- デモ
- 質問コーナー

#Github Actionsでできること
- Linux、macOS、Windowsなどの任意のプラットフォーム上での開発、テストおよびデプロイのプロセスを簡単に自動化できる
- Node.js、Python、Java、PHP、Ruby、C/C++、.NET、Android、iOSなど、多くの言語とフレームワークに対応済
- ワークフローや処理内容はリポジトリ内のコードとして記述されるので、作成したワークフローを共有したり、再利用するだけでなく、開発プロセスもまるっとforkすることもできる
- 現在はベータ版がリリースされており、パブリックリポジトリでは無料、プライベートリポジトリでは有料

cf. GitHub ActionsにCI/CD機能を搭載〜パブリックリポジトリでは無料で利用可能
https://github.blog/jp/2019-08-21-github-actions-now-supports-ci-cd/


#質問コーナー
Q. commit logが汚くなることに対する対応策はあるか？
A. commitの量が増えるのはやむなし。
1pr = 1 commit objとなるようにcommitをRebaseしてcommitをまとめたりしている企業もいる


Q. 自動脆弱性、互換性チェックについて
A.githubが用意するCVE以外に、機械学習、人力でおこなっている 
cf.脆弱性のある依存関係に対するセキュリティアラートについて
https://help.github.com/ja/articles/about-security-alerts-for-vulnerable-dependencies

Q. GitHub Enterprise Server(オンプレミス環境)へのリリース時期は？
A. 来年を予定
現在リリースされているのは、GitHub Actionsのベータ版。
こちらの正式バージョンのリリース日は11月13日とされている。


Q. Github ActionsってAzure Pipelineをベースに作っている？
A. Azure Pipelineをforkして開発。cacheなど機能の充実はAzure Pipelineに劣っている。


##p.s. 印象に残ったこと
**・Github ActionsはOSSであることを活かしてマーケットプレイスにActionが充実していること**
→Azure Pipelineと比較して。
**・コードのようにアクションとワークフローを記述して再利用可能**
→Stackstormを仕事で使っている身としてはどこまで再利用できるのか気になる。
Stackstormでワークフローを定義してアクションを走らせる場合、かなりスペシフィックに書くことが多く、ファイルの量が膨大になってしまう汗。

P.S. Twitterもやってるのでフォローしていただけると泣いて喜びます！
[@gkzvoice](https://twitter.com/gkzvoice)
jest, rspec経験者向けkotlintest事始め

## build.gradleにkotlintestを追加
```build.gradle
test {
  useJUnitPlatform()
}

dependencies {
  testImplementation 'io.kotlintest:kotlintest-runner-junit5:3.3.2'
}
```

## DescribeSpecを用いてテストを記述
下記のようにrspec, jestのような雰囲気でdescribe, （jestにはないけど）context, itを使ってテストを書いていくことができます。

```DurationUtilsTest.kt
import io.kotlintest.matchers.types.shouldBeTypeOf
import io.kotlintest.shouldThrow
import io.kotlintest.specs.DescribeSpec
import java.lang.IllegalArgumentException
import org.joda.time.Duration

class DurationUtilsTest : DescribeSpec({
    describe("#parseDuration") {
        fun shouldThrowIllegalArgumentException(duration: String) {
            shouldThrow<IllegalArgumentException> { DurationUtils.parseDuration(duration) }
        }

        context("when invalid time suffix") {
            it("throws illegal argument exception") {
                shouldThrowIllegalArgumentException("1")
            }
        }

        context("when value is negative") {
            context("when second") {
                it("throws illegal argument exception") {
                    shouldThrowIllegalArgumentException("-1s")
                }
            }
        }

        context("when value is positive") {
            fun shouldBeTypeOfDuration(duration: String) {
                DurationUtils.parseDuration(duration).shouldBeTypeOf<Duration>()
            }

            context("when second") {
                it("returns duration") {
                    shouldBeTypeOfDuration("1s")
                }
            }

        }
    }
})
```

kotlintestではDescribeSpec以外の書き方もできます。
詳しくは[kotlintest styles](https://github.com/kotlintest/kotlintest/blob/master/doc/styles.md)を見てください。

## 参考
* [kotlintest styles](https://github.com/kotlintest/kotlintest/blob/master/doc/styles.md)
* [kotlintest matchers](https://github.com/kotlintest/kotlintest/blob/master/doc/matchers.md)
Strava heat map の GeoTIFF化

# 動機

[前回記事](https://qiita.com/Tomonobu3110/items/88d3815e463cfdab498d)でHeatmapを手に入れましたが、
これはただのPNGの画像です。

ルート検索に利用するためには、このPNGに位置情報を付与する必要があります。
位置情報が付与された画像フォーマットとして[GeoTIFF](https://ja.wikipedia.org/wiki/GeoTIFF)が定義されています。

よって、今回は PNG to GeoTIFF を試みます。

# レッスン課題

最初の実験として
皇居から江戸川あたりのヒートマップに位置情報を付けて
GeoTIFF化してみましょう

# 材料

- Strava Heat Map (ヒートマップPNG)
https://heatmap-external-b.strava.com/tiles/ride/hot/11/1819/806.png?px=512

- 国土地理院・緊急輸送道路データ・東京 (位置情報付きデータ)
http://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-N10-v1_1.html

# 道具

- [QGIS](https://qgis.org/ja/site/)
- QGIS ジオリファレンサ・プラグイン (QGISにデフォルトで入っている)

# 手順

1. 材料の準備
  1-1. ヒートマップPNGをStravaからダウンロード
  1-2. 国土地理院データ(N10-13_13.zip)を入手し、任意のディレクトリに展開

2. QGISで国土地理院データに含まれる N10-13_13.shp を取り込み
  2-1. レイヤ(L) --> データソースマネージャ(D) --> ベクタ
  2-2. ベクタデータセットに N10-13_13.shp を指定
  2-3. 追加
  2-4. EPSG:6677を選択し、OK

3. QGIS上でヒートマップPNGに位置情報を付ける
    3-1. ラスタ(R) --> ジオリファレンサ...(G)
    3-2. ファイル --> ラスタを開く... で ヒートマップPNGを取り込む。EPSG:6677
    3-3. 編集 --> ポイントの追加 で、ポイントを追加していく
      - ポイント追加については、ココ↓を参照
      - https://sites.google.com/site/qgisnoiriguchi/basic/01/03

    3-4. 設定 → 変換の設定
      - 変換タイプ = 線形
      - リサンプリング方法 = 線形
      - 変換先SRS = EPSG:6677
      - 完了時にQGISにロードする = チェックを入れる

    3-5. ファイル --> ジオリファレンスの開始

4. QGISにヒートマップが表示される

5. 以上

※とにかく全ての場所でEPSG(SRS)は一致させること！
iPad Safari PointerDown調査

iOS12では、PointerDownを拾えないため、タッチとペンの判別がかなり辛い。

iPad OSのSafariでようやくPointerEvent系が実装されるので、動作を確認した。

# pointerdown  touchstart  mousedown のいずれかをセットした場合

pointerdownの中身は event.pointerType


|OS|操作| pointerdown | touchstart | mousedown |
|---|---|---|---|---|
|MAC Chrome|マウス|mouse|-|○|
|iPad iOS 12|タッチ|-|○|○|
|iPad iOS 12|Applie Pencil|-|○|-|
|iPad iPad-OS 13 beta2|タッチ|touch|○|○|
|iPad iPad-OS 13 beta2|Applie Pencil|pen|○|-|


# pointerdown / touchstart / mousedown を全部セットした場合(数値は呼ばれた順番)

|OS|操作| pointerdown | touchstart | mousedown |
|---|---|---|---|---|
|MAC Chrome|マウス|1|-|2|
|iPad iOS 12|タッチ|-|1|2|
|iPad iOS 12|Applie Pencil|-|1|-|
|iPad iPad-OS 13 beta2|タッチ|1|2|3|
|iPad iPad-OS 13 beta2|Applie Pencil|1|2|-|


# その他
## 指でスクロール・apple pencilではスクロールさせない

```

トップ要素(v-on:touchmove.scroll='scrolling')


scrolling(event: TouchEvent) {
  const t = event.touches[0];
  if (t && t.touchType == "stylus") event.preventDefault();
}
バリデーションを指定したアクションにのみかける方法

どうもチャンクノです！！！

今回はバリデーションを指定したアクションにのみかける方法について書いていきます。
昨日個人アプリの編集機能を使ってて変更点が反映されずに困っていました。
ターミナルを見てもエラーはない。むむむ、、、
ここで私の中で一つ仮説が閃きました。(天才！！！)
「もしかしてバリデーションが関係している？」

```
  validates :name, :account, presence: true, uniqueness: true
  validates :tag_list, presence: true,
```
こちらが記述を追加する前のコードです。
まずはこのバリデーションを全て突破する形で編集機能を使ってみた結果、ビンゴ！！！
編集内容がちゃんと反映されていました。(天才！！！)

で、ここからが問題ですね。
どうやってCreateの時のみバリデーションをかけるのか。
「rails バリデーション createのみ実行」で検索、、、
ビンゴ！！！(天才！！！)
validatesの後にon: :アクション名を書けばいいみたいです。
どうするかというと

```
  validates :name, :account, presence: true, uniqueness: true, on: :create
  validates :tag_list, presence: true, on: :create
```
こう！！！
これでCreateアクションの時のみバリデーションがかかるようにできました！！！

いやーバリデーションは必然的にCreateのみにかかるものだと思っていたけど違うんですね。
お勉強になりました。
皆さんもバリデーションには気をつけてください。
それでは皆様の良きプログラミングライフを祈って🙏🙏🙏

参考記事
https://qiita.com/kadoppe/items/061d137e6022fa099872
Cloud Deployment Managerを使ってBigQueryのデータセット及びテーブルを作る

簡単なデータ可視化ツールのサンプルを作るため、BigQueryにデータセットとテーブルをサクッと作る際にCloud Deployment Managerを利用しました。

小さなyamlなのですが、[APIのドキュメント](https://cloud.google.com/bigquery/docs/reference/rest/v2/tables)を読んで対応する設定を書くのに少し手間がかかってしまったので置いておきます。

```yaml
# それぞれ [PROJECT_ID] を置き換えてください
resources:
  - name: test-bq-dataset
    type: bigquery.v2.dataset
    properties:
      datasetReference:
        datasetId: test_bq_dataset
        projectId: [PROJECT_ID]
  - name: test-bq-table
    type: bigquery.v2.table
    properties:
      datasetId: test_bq_dataset
      tableReference:
        datasetId: test_bq_dataset
        projectId: [PROJECT_ID]
        tableId: test_bq_table
      schema:
        fields:
          - name: timestamp
            type: TIMESTAMP
            mode: REQUIRED
          - name: col1
            type: STRING
            mode: REQUIRED
          - name: col2
            type: STRING
            mode: REQUIRED
    metadata:
      dependsOn:
        - test-bq-dataset
```

ちなみに[GCPの公式リポジトリにサンプルはある](https://github.com/GoogleCloudPlatform/deploymentmanager-samples/tree/master/community/cloud-foundation/templates/bigquery)のですが、yamlの中でPythonを呼び出していて、挙動を追うのが少し大変だったので自分で書いてしまいました。
Laravelの/publicをルートに変更する

下記の.htaccessファイルをlaravelのプロジェクトのルートディレクトリに配置する。

[liaotzukai/Php laravel 5.5 project .htaccess file](https://gist.github.com/liaotzukai/8e61a3f6dd82c267e05270b505eb6d5a)
git コマンドラインで操作しよう！

基礎編　

Gitの準備
$ git init

共有したいファイル名選択
$ git add ~

選択したファイルを記録する
$ git commit -m “コミットメッセージ”
コミットメッセージは何を変更したのか具体的に。

リモートに登録
＄ git remote add origin リモートのurl
  originはリモート名

リモートにファイルをアップロード（プッシュ）
＄  git push origin master
originは登録時につけたリモート名

リモートのファイルをダウンロードする(プル)
$ git pull origin master


変更したファイルを把握→変更の中で共有したいとこだけ選択する

変更したファイルを把握→赤色で表示
＄ git status

変更したファイルの内容を把握→緑で表示
$ git diff

コミットメッセージ経歴表示
$ git log

コミットの変更内容確認
$ git log -p
【Unity】突然、音が出なくなった場合

環境メモ
⭐️Mac OS Mojave バージョン10.14.4
⭐️Unity 2019.1.19f1

Unityを実装していて、突然、音が出なくなった。
調べてみるとGameビューの上にある「Mute Audio」をオンにしていたので、音が出なくなったようです。
「Mute Audio」OFFにしたら、音が出ました。


<img width="988" alt="スクリーンショット 2019-09-03 19.24.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93155/0a157a10-9cb3-f20f-ff24-50076559e0bb.png">
<br>
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">【VR】Androidアプリ💕リリース<br>😍VR Diamond Crash Game💎<br>リリースしました✨VRゴーグルで遊びます👯‍♀️<br>とっても✨弾けて💎気持ちいいです🤩<br>↓↓📱Google Play 無料Free<a href="https://t.co/fiqJKtFmo7">https://t.co/fiqJKtFmo7</a><br><br>🖥️パソコンで遊ぶ（UnityRoom）無料Free<a href="https://t.co/CK47FkXiN6">https://t.co/CK47FkXiN6</a><a href="https://twitter.com/hashtag/unity3d?src=hash&amp;ref_src=twsrc%5Etfw">#unity3d</a> <a href="https://twitter.com/hashtag/VR?src=hash&amp;ref_src=twsrc%5Etfw">#VR</a> <a href="https://t.co/jF7FWv4Yjw">pic.twitter.com/jF7FWv4Yjw</a></p>&mdash; non (@nonnonkapibara) <a href="https://twitter.com/nonnonkapibara/status/1171022411581423616?ref_src=twsrc%5Etfw">September 9, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

↓↓Google Play 無料Free
VR ダイアモンド クラッシュゲーム〜VR Diamond Crash Game
[![diamondvr1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93155/a843180b-794a-81ce-c605-5e24a5cd4ddb.png)](https://play.google.com/store/apps/details?id=com.NonCompany.DiamondVR)

↓↓パソコンで遊ぶ（UnityRoom）無料Free
https://unityroom.com/games/diamondpc

<br>
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">💖【VR】Androidアプリ💖リリース<br>😍ピヨくまちゃん💫シューティングVRゲームリリースしました。😊VRゴーグルであそびます。🍩<br>💎とっても💎キレイで🤩楽しいです👍<br>↓↓Google Play 無料Free<a href="https://t.co/DmkV8ltaCD">https://t.co/DmkV8ltaCD</a><a href="https://twitter.com/hashtag/Piyo_Kuma_chan_Shooting_VR_game?src=hash&amp;ref_src=twsrc%5Etfw">#Piyo_Kuma_chan_Shooting_VR_game</a> <a href="https://twitter.com/hashtag/VR?src=hash&amp;ref_src=twsrc%5Etfw">#VR</a> <a href="https://twitter.com/hashtag/Unity3d?src=hash&amp;ref_src=twsrc%5Etfw">#Unity3d</a> <a href="https://t.co/fFVADdAiDV">pic.twitter.com/fFVADdAiDV</a></p>&mdash; non (@nonnonkapibara) <a href="https://twitter.com/nonnonkapibara/status/1127938600501334016?ref_src=twsrc%5Etfw">May 13, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

↓↓Google Play 無料Free
VR ピヨくまちゃんのシューティング〜VR Shooting Piyo-Kuma-Chan
[![vrpiyokumachan.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93155/7407a010-942e-dfa8-879a-11d014353f53.png)](https://play.google.com/store/apps/details?id=com.non.VRPiyokumaChanShooting)
【Laravel】エラー情報を非表示にする

```:.env

APP_DEBUG=false
```

https://readouble.com/laravel/5.8/ja/errors.html

>アプリケーションエラー発生時にユーザーに対し表示する詳細の表示量は、config/app.php設定ファイルのdebug設定オプションで決定します。デフォルト状態でこの設定オプションは、.envファイルで指定されるAPP_DEBUG環境変数の値を反映します。

>local環境ではAPP_DEBUG環境変数をtrueに設定すべきでしょう。実働環境ではこの値をいつもfalseにすべきです。実働環境でこの値をtrueにしてしまうと、アプリケーションのエンドユーザーへ、セキュリティリスクになりえる設定情報を表示するリスクを犯すことになります。

`.env`の値が反映されない場合はキャッシュを削除

```
$ php artisan config:cache
```
cssのみでタブ機能を作成する

例の如くコピペ。jQeryなし

ほとんど引用コピペになってしまうのでリンクで省略
[参考ページ](https://nelog.jp/css-tabs)

タブってradioの応用なのかと初めて知った24進数15歳。


```
/* 選択されているタブのスタイルを変える */
    .tabs input[name="tab-radio"]:checked + .tab-label {
        background-color: rgb(0, 0, 0);
        color: white;　
    }
```

あとはbackground-colorとcolorをデザインに合わせればそれっぽく見えるハズ。
GCM SDKとFCM SDKは、アプリケーション内で共存できないのに、アプリのbuild.gradleに共存してた

GoogleCloudMessagingは使用不可になってます。Firebaseに切り替えましょう。

```app/build.gradle
これがあるから→ implementation "com.google.firebase:firebase-messaging:20.0.0"

これを除去→ implementation "com.google.android.gms:play-services-gcm:17.0.0"
```
Androidバージョン上げたらOneSignal通知が届かなくなった

Androidのバージョン(targetSdkVersion)を25から28に上げたら、
OneSignalで来ていたプッシュ通知が来なくなりました！

AndroidStudioは3.2.4、OneSignalは3.11.3@aaです。



```AndroidManifest.xml
<application
...
tools:node="replace">
```

この「tools:node="replace"」を除去したら来るようになりました！！
Ganache CLIって何なの？マイニングせずに動くけどどうなってるの？

#Ganache CLIとは何か？
Ganache CLIはイーサリアムのエミュレーターです。実際のイーサリアムノードを起動するコスト無しに、イーサリアムのような挙動するものを起動でき、主に開発目的で利用します。

##Ganacheの特徴
Ganacheで起動するイーサリアムは実際のイーサリアムと次の点で異なります。
- トランザクションは即時にマイニングされる
- トランザクションコスト不要
- Etherを所有したアカウントの自動発行
- Gasやマイニングスピードを自由に設定可能

開発で実際にEtherコストやマイニングの時間を消費する訳にはいかないの、Ganacheは必須のライブラリとなるでしょう。
Ubuntuにchromedriverをインストールする

# はじめに
chromedriverは、Mac環境ではbrewコマンドでインストールするが、Ubuntu環境では、Googleのサイトから、curlでzipファイルをダウンロードして、unzipで解凍するといった、少し面倒な手順を踏む事になります。（Windowsでフリーツールをダウンロードする時と同じようなイメージの手順）
chromeは、aptコマンドでインストールするが、chromedriverは、curlコマンドでインストールする事になります。

# 環境
Utuntu16.04.5 LTS
Windows10 + Vagrant

# 手順
自分の環境では、そもそも、unzipが入っていなかったため、インストールする

```aa
sudo apt install unzip
```

折角なので、zipも一緒にインストールしたい場合は、このようにする

```aa
sudo apt install unzip zip
```

unzipとzipが確かに、入った事を確認する（ヘルプが出てくればOK）

```aa
zip -h
unzip -h
```

chromedriverのダウンロード元はここのURL （Googleのような大手企業の割りには、何故このような貧相な印象のサイト作りになっているのかは不明）
https://sites.google.com/a/chromium.org/chromedriver/downloads

ダウンロード元のパスを調べるために、Windows上に最新版をダウンロードしてみる　そして、パスが表示されるのでそれをメモる　（ダウンロードファイルには、mac64,linux64,win32と３種類あるので、間違わないように）
https://chromedriver.storage.googleapis.com/77.0.3865.40/chromedriver_linux64.zip

curlコマンドでダウンロードする
ダウンロードファイルは、tmpにいれておく

```
cd /tmp/
curl -O https://chromedriver.storage.googleapis.com/77.0.3865.40/chromedriver_linux64.zip
```

chromedriver_linux64.zipがダウンロードされた事を確認する

```aa
ls -l
```

zipファイルを解凍して、更に、解凍された事を確認する

```aa
unzip chromedriver_linux64.zip
ls -l
```

ダウンロードファイルは、ここにセットする（パスが通っているフォルダであればどこでもいいらしい）

```aa
sudo mv chromedriver /usr/local/bin/
```

移動された事を確認する

```aa
which chromedriver 
```

インストールが完了したので、ダウンロードした圧縮ファイルは削除する

```aa
rm chromedriver_linux64.zip
```

削除された事を確認

```aa
ls -l
```

# 参考記事
https://www.ytyng.com/blog/ubuntu-%E3%81%AB-chromedriver-%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB/
【SAPUI5】OData経由でCSVエクスポート実装

#はじめに
ODataのデータをCSVファイルでエクスポートできたので、手順を記載します。

今回はテンプレート選択からNew SAPUI5 Applicationを選択して、実施しました。

#1.ODataサービスを設定
プロジェクトを作成し、manifest.jsonの[Description Editor]-[Data Sources]を開き、追加ボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320261/4267e5f4-f85a-bcfa-35f6-80da56edb583.png)

左ペインの[Service URL]を選択後、システムおよびURLを選択し、Nextボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320261/1544142e-feb4-226a-59b2-7791a20c3685.png)

どちらかのラジオボタンを選択し、Nextボタンをクリックします。
今回は、[Create new model]を選択し、exportTestと命名しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320261/8f38c937-bab1-27b6-d1a1-4d61aa9b05d2.png)


#2.コントローラーの実装
以下のコードを入力します。

```javascript
sap.ui.define([
	"sap/ui/core/mvc/Controller",
	"sap/ui/core/util/Export",
	"sap/ui/core/util/ExportTypeCSV"
], function (Controller, Export, ExportTypeCSV) {
	"use strict";

	return Controller.extend("test.test.controller.export", {
		onInit: function () {
			
		},
		onExportCsv: function() {
			var oView = this.getView();
			var oExport = new Export({
				exportType: new ExportTypeCSV({
					separatorChar: ","
				}),
				models: oView.getModel("exportTest"),
				rows: {
					path: "/exportTestSet"  // パスを指定します。今回はEntity Setを指定しました。
				},
				columns: [{
					name: "名前",
					template: {
						content: "{Name}"
					}
				},{
					name: "要素",
					template: {
						content: "{Element}"
					}
				}]
			});
			oExport.saveFile("exportTestCsv");
		}
	});
});
```


#3.ビューの実装
以下のコードを入力します。

```html
<mvc:View 
	controllerName="test.test.controller.exportPage" 
	xmlns:mvc="sap.ui.core.mvc"
	xmlns="sap.m"
	displayBlock="true">
	<Page title="エクスポート処理">
		<Button type="Emphasized" press="onExportCsv" text="エクスポート（CSV）"  />
	</Page>
</mvc:View>
```

#4.エクスポートした結果
今回は以下のような形式のファイルがエクスポートされました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320261/13c7922c-30cd-ca55-bed5-dbc6f38f961f.png)

#5.さいごに
今回はCSV形式でエクスポートしてみましたが、
スプレッドシート形式でのエクスポートも同じような方法でできたので、また記載しようと思います。

#6.参考サイト
下記のSAPリファレンスおよびサンプルを参考にしました。
https://sapui5.hana.ondemand.com/1.68.1/#/api/sap.ui.core.util.Export
https://sapui5.hana.ondemand.com/1.68.1/#/entity/sap.m.Table/sample/sap.m.sample.TableExport
Oracle 主キーを変えつつ、レコードをコピーする方法

例えば、既存のユーザーレコードをもとに、ID（主キーカラム）やその他一部のカラムだけ変えてコピーを作る際の雛形です。

他のテーブルを参照することもできるため、「あるレコードを元に、権限や種別の組み合わせを網羅したデータを用意する」など、大量に作成する場面にも応用がききます。

この方法では無名ブロックを書かないといけませんが、
ID 毎に INSERT 文をベタで書く方法と比べると、変更するカラムが明確になります。

```sql
-- 部署ごとにテストユーザーを作成する方法

set serveroutput on -- debug
begin
  -- バリエーションに応じてループを回す
  for d in (select * from DEPARTMENT order by DEPARTMENT_ID) loop
    dbms_output.put_line(d.DEPARTMENT_ID); -- debug

    -- 雛形レコードを rowtype な変数 u に格納する
    for u in (select * from USERS where USER_ID = 'test-user-templ') loop
      -- 主キーを変更する
      u.ID := 'test-user-' || d.DEPARTMENT_ID;
      -- その他、変更するものを明記する。
      u.DEPARTMENT_ID := d.DEPARTMENT_ID;
      u.NAME2 := d.NAME;
      u.NOTE := 'テスト';

      insert into USERS values u;
    end loop;

  end loop;
end;
/
```
DirectAccessを強制的に利用不可にする方法

マイクロソフトから提供されている[DirectAccess](https://docs.microsoft.com/ja-jp/windows-server/remote/remote-access/directaccess/directaccess)ですが、サポート終了が予告されています。すでにAzure上のVMにはDirectAccessの機能が使えないことも案内されています。（[こちら](https://support.microsoft.com/ja-jp/help/2721672/microsoft-server-software-support-for-microsoft-azure-virtual-machines)）

というわけで代替のVPNを将来に備えて用意する必要があります。
とはいえ、別のVPNとDirectAccessを共存させることができない場合があったりなかったりすることがあります。
そういう場合は正しい手順としてはDirectAccessをいったん無効化したのち、新しいVPNを入れることが望ましいと思われます。
それができない場合などはかなり強制的な方法になりますが、以下の手段でDirectAccessを無効化することで対処します。（しました）

■手順
１．各クライアントPCのローカル管理者でサインインする
２．Powershellを「管理者として起動」して、以下のコマンドを実行して実行許可を付与する。
`#Set-ExecutionPolicy RemoteSigned`
３．以下のコマンドを実行する
`＃Get-Item -Path “HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient\DnsPolicyConfig” | Remove-Item -Confirm:$false`
４．PCを再起動する

これ何をやってるかというと内部と外部の名前解決の基準となるサーバ（NLS: ネットワーク ロケーション サーバー）を強制的に削除しちゃうことをしてます(と理解してます）。NLSに到達可能かどうかでDNSの名前解決するDNSサーバを自動で切り替えるのでNLPに到達できない場合は社外ネットワークにいる状態になるので、内部DNSがいつまでたっても参照できないようなことが起こりえます。
pingやnslookupでの内部DNSの名前解決はできるのにブラウザ経由やエクスプローラからはサーバ名でアクセスできないという不思議現象が起こりまして対処方法を探すのに大変苦労しました。

元ネタは以下のサイトです。（英語）

[Uninstalling and Removing DirectAccess](https://directaccess.richardhicks.com/2017/04/13/uninstalling-and-removing-directaccess/)
[Enabling or disabling the DirectAccess adapters for testing (6to4, Teredo, IP-HTTPS)](https://www.ivonetworks.com/2012/08/enabling-or-disabling-the-directaccess-adapters-for-testing-6to4-teredo-ip-https/)
[Disable DirectAccess](https://www.itprotoday.com/windows-78/disable-directaccess)
練馬区のゴミ分別検索ページが使いにくいのでGASでWebAPIを作った

#目的
数ヶ月前に練馬区に引っ越したものの、ゴミの分別がめちゃくちゃめんどくさい。
それはいいとして、公式ページの「これは何ゴミ？」的なページも使いづらい。
LineでBot作って、聞いたら応えてくれるようにしたらいいんじゃね？ということで、
汎用性を高めるためにとりあえずまずはWebAPIを開発した。

#用意するもの
- Googleアカウント（Google DriveでGASを利用。GASでのWebAPIの作り方は<a href="https://qiita.com/bowtin/items/ee304c178c4acbd913b2">こちら</a>を参照）

#やったこと
##データの用意
以前にダクソ3のフレーバーテキストをランダムに返すAPIを作ったときと同じで、データが無い。いや、あるんだけどそもそも使いづらいから今回の話になってるわけで...。
ちなみに練馬区さんのゴミ検索ページは<a href="https://www.city.nerima.tokyo.jp/kurashi/gomi/wakekata/bunbetsu/index.html">ココ</a>。
あいうえお順のページの飛んでから、気合で探す（ブラウザの検索機能使えば多少はましだけど）しかない...。

スクレイピングすることも考えたけど、そんなに頻繁に変わるものでもないと思うので、
とりあえずスプレッドシートにコピペコピペ＆コピペ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/495652/b0a1c0d7-8c1c-49e3-4552-b2dd9cf6d168.png)

これでデータは揃った...ことにしましょう。

##API仕様の決定
前回のダクソ3のときとは違って、「検索キーワードを入れてもらう→合致したデータを返す」という流れになるはずなので、今回はリクエストパラメータを受け取らなきゃいけない...。

とりあえず、こんな感じでリクエストを投げてもらうことにします。
```
http://hogehoge.com?searchkey=魚の骨
```

##コーディング
まずはGETリクエストが来たときの挙動を定義します。

リクエストパラメータ「searchkey」で検索キーワードを受け取り、あいまい検索でスプレッドシートから該当する情報を抽出する。

```js:endpoint.gs

//GET時の挙動
//getData関数を呼び出して検索キーワードを渡し、戻り値としてゴミ配列を受け取る
//JSONにしてレスポンスとして返す
function doGet(e) {
  var garbages = getData(e.parameter.searchkey);
  
  return ContentService.createTextOutput(JSON.stringify(garbages)).setMimeType(ContentService.MimeType.JSON);
}

//検索キーワードを受け取り、シートA列であいまい検索を行う
//マッチした行をゴミオブジェクトとして登録し、これを全行分繰り返す
//ゴミオブジェクトたちを配列に保存して投げ返す
function getData(searchkey){
  
  var sheet = SpreadsheetApp.openById('1LLJXJeSubmD_Nqtb-wxBrZEmYn9Hiby_AjbpL3gwP2g');
  
  //A列のデータをごっそり読み取り
  var columnAVals = sheet.getRange('A:A').getValues();
  var columnBVals = sheet.getRange('B:B').getValues();
  var columnCVals = sheet.getRange('C:C').getValues();
  
  //このあとの繰り返し条件に使うので、最後の行番号を取得
  var lastRow = columnAVals.filter(String).length;
   
  var garbages = new Array();
  for(var i = 1; i <= lastRow; i++){
    
    
    if(((columnAVals[i].toString()).indexOf(searchkey)) !== -1){
      garbages.push(new GarbageData(columnAVals[i].toString(), columnBVals[i].toString(), columnCVals[i].toString()));
    }
  }
  
  return garbages;
}
```


上でしれっと使ってしまっていますが、今回返すべき情報は単一の情報ではなく、「ゴミの種類」「分別方法」「出し方」の3つが合わさった**「ゴミオブジェクト」**になるので、ここはお得意のオブジェクト指向を活用してゴミクラスを作っておきます。

```js:Garbage.gs
GarbageData = function(itemname, category, notice){
  this.itemname = itemname;
  this.category = category;
  this.notice = notice;
};

GarbageData.prototype.getItemname = function(){
  return this.itemname;
};

GarbageData.prototype.getCategory = function(){
  return this.category;
};

GarbageData.prototype.getCategory = function(){
  return this.notice;
};
```

##動作確認
前回同様、設計もクソも無いですがあとはWebアプリケーションとして公開するだけです。
公開の仕方は前回の記事（<a href="https://qiita.com/bowtin/items/ee304c178c4acbd913b2">こちら</a>）を見ていただくとして、動作確認です。

ブラウザで試してみます。


```
https://script.google.com/macros/s/AKfycbymo1obfb9uD6E8lewUEhUtI1zq9VuAQa4OBAi2iWF1F9ijOR4/exec?searchkey=空き缶
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/495652/3d2e91fd-28a4-fbe6-b6e1-7d7fe67935d3.png)

できたー。
改行コードとか入っちゃってますが、まあそのうち調整すればいいですかね。
そのうちLINE Botと連携しようと思います。
【VB.NET】MariaDBからコンボボックスへの出力(Visual Studio 2019)

## もくじ

1. 開発環境及び前提条件
2. プログラム作成
    1. MariaDBへの接続
    2. コンボボックスへの呼び出し
3. まとめ

## 1.開発環境及び前提条件
OS: Windows10
IDE: Visual Studio 2019
言語: VB.NET(.NET Frameork 4.7.2)
DB: MariaDB 10.4

開発環境作成方法、および参照設定については既知とする。
(もし１件でも要望があれば作成します。)

## 2.プログラム作成


### 1. MariaDBへの接続

参照を追加する。

```VB.NET
Imports MySql.Data.MySqlClient
```

```VB.NET
        Using conn As New MySqlConnection("Database=<DATABASE>;Data Source=localhost;User Id=<USERNAME>;Password=<PASSWORD>; sqlservermode=True;")

            ' データベースコネクション開始
            conn.Open()

            '<<ここへMariaDB接続中の処理を記述する>>

            ' データベースコネクションクローズ
            conn.Close()
        End Using
```

### 2. コンボボックスへの呼び出し方法
コンボボックスコントロール作成(ここでは[DropdownBox1]とする)後、
上記コードの

```VB.NET
    '<<ここへMariaDB接続中の処理を記述する>>
```

の部分へ、
　・データ取得　　
　・コンボボックスのデータソースを設定
するように記述する。

```VB.NET
            ' データ取得
            Dim cmd As MySqlCommand = New MySqlCommand("SELECT * FROM <DATATABLE>", conn)
            Dim da As MySqlDataAdapter = New MySqlDataAdapter(cmd)
            Dim dt As DataTable = New DataTable()
            da.Fill(dt)

            ' コンボボックスに値を設定
            Dim dc As New ArrayList
            dc.Add("")
            For i As Integer = 0 To dt.Rows.Count - 1
                dc.Add(dt.Rows(i).ItemArray(1)) 'ItemArray(1)は設定したい任意のカラム
            Next
            DropdownBox1.DataSource = dc


```

## 3.まとめ
今投稿は、初Qiita記事投稿のテストも兼ねる。
自己のMariaDBにおけるDatabase to Contorolのテンプレートとする。
[Rails6.0] URLに数値のIDではなく(Qiitaみたいに)ハッシュ化したIDを使用する

# はじめに

`show`や`edit`などのアクションにアクセスする場合、`user/1`や`item/6`のようにデフォルトでは数値のIDを使います。
このままだとユーザー数や投稿数が直接見えてしまい、かっこ良くなかったり~~過疎っているのがバレたり~~します。
今回はそんな問題を(Qiitaの記事のURLみたいに)`IDをハッシュ化した文字列`をURLに使用することで解決していきます。

# モデルにカラムを作成

ハッシュ化なので、暗号化できても**複合(元に戻す)ことは出来ません。**
なので、まずはモデルにハッシュ化した文字列を入れるカラムを作成します。
今回はモデル名は`User`、カラム名は`id_digest`とします。

```bash
$ bin/rails g migration add_id_digest_to_users
```

出来上がったmigrationファイルを編集します

```XXXXXXXXXXXXX_add_id_digest_to_users.rb
class AddIdDigestToUsers < ActiveRecord::Migration[6.0]
  def change
    add_column :users, :id_digest, :string
  end
end
```

保存したらmigirate

```bash
$ bin/rails db:migrate
```

# モデルの編集

次に、モデルのファイルを編集していきます。
ここでのポイントは、`IDはsaveが終わった後に値が入る`という点です。
なので`save`メソッドが完了した後に`id_digest`の値を埋めていくように実装します。

```user.rb
class User < ApplicationRecord
  after_save :create_id_digest # saveが完了した後に呼び出されるコールバック

  def to_param
    id_digest
  end

  private

  # after_saveによって呼び出されるメソッド
  def create_id_digest
    if id_digest.nil?
      new_digest = Digest::MD5.hexdigest(id.to_s)
      update_column(:id_digest, new_digest)
    end
  end
end
```

`after_save`コールバックで`create_id_digest`メソッドを呼んています。
このメソッド内の

```ruby
new_digest = Digest::MD5.hexdigest(id.to_s)
```

でIDの値を元に`MD5`でハッシュ化しています。[^1]

あとは`update_column`メソッドで**validationをスキップして**値を保存しています。
こうしておかないと、後々カラムやvalidationを増やした時にここでvalidationエラーが出てしまいます。

また、`to_param`メソッドをオーバライドしてURLに使用する値を変更しています。
これに関しては以下のサイトが参考になるかと思います。
https://ruby-rails.hatenadiary.com/entry/20141223/1419334845
[to_key と to_param で URL や HTML 中のリソースの id を別の文字列にしてしまう](https://qiita.com/tyamagu2/items/36cba2c7ce9e941c37d3)

# ページにアクセス

あとはルーティングを設定して、ページにアクセスするリンクからページに遷移すればOK!

```routes.rb
Rails.application.routes.draw do
  resources :users
  root 'user#index'
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end

```

```index.html.slim
= link_to('テスト', user_path(User.first))
```

成功すれば、URLにハッシュ化された文字列が入った状態で`show`や`edit`のページに遷移できていると思います。

# まとめ

IDをハッシュ化することに関する情報が少なく、中々いい方法にたどり着けず苦戦しました。
まとめると
`ハッシュ用のカラムを追加`→`after_saveで自動的に値が入るよう修正`
なのですが、何か他にいい方法があれば是非コメント等でご教授頂ければ幸いです。

# 参考文献

[Ruby,Railsの暗号化いろいろ](https://qiita.com/sibakenY/items/fa25d984764f4ebe9fdf)
https://railsguides.jp/active_record_callbacks.html

[^1]: MD5は弱点が発見されているハッシュ関数ですが、今回は解析されても問題のないidの値なので使用しました。