OmniAICreator/Qiita-1.07M huggingface dataset:
expo製アプリをgoogle playに公開するには、privacy policy必須

![alt](https://user-images.githubusercontent.com/26253721/39765058-e8d0eae4-531b-11e8-9305-4c852f269517.png)

expoで作ったアプリをgoogle playに公開したら、削除された。
？？？

結論から言うと、expo（version 32）製アプリをgoogle playに公開するにはprivacy policyが全てのアプリで必須らしい。

私に以下のメールが届いた。

```
Android 広告 ID の収集及び転送を行うことが確認されましたので、プライバシーポリシーを掲載して頂く必要があります。
```

Hey google play! 広告なんて使ってないぞ！！
ところが

## expoで作られたアプリは、通常android Advertise IDをリクエストするらしい。
expo公式がこの問題に回答していた。
質問　広告IDの収集を行なっているとgoogle playに怒られ、アプリが削除されました。　どうしたらいいですか？
回答　expoで作られたどんなアプリもprivacy policyが必要です。privacy policyを掲載してください。
…

早く言ってや。

必要ないと思い、privacy policyを提出しなかったのが原因らしい。

## 仕方ないので、以下のサービスで、privacy policyを自動生成しホスティングした。
https://app-privacy-policy-generator.firebaseapp.com/

作成したprivacy policyが以下。
おしゃれな感じに仕上がっている。
https://til.flycricket.io/privacy.html

作ったprivacy policyをgoogle playにアップしたら、3時間後にアプリの削除が取り消された

完
Firebase Analyticsの調査（画面の自動追跡）


## Firebase Analyticsへの移行に向けて
[iOS/Androidアプリ向けGAの終了](https://support.google.com/analytics/answer/9167112?hl=ja)の通知があり、```お早めに Firebase SDK でアプリをトラッキングするように移行していただけますようお願いいたします。```とアナウンスがあったころから、携わっているiOSアプリのプロジェクトでもFirebase Analyticsへの移行に向けての調査を進めており、調査でわかったことをまとめていきたいと思います。

## 画面の自動追跡
Firebase Analytics（以下「FA」）が、GAと大きく違う点に自動の画面追跡機能があります。
GAではviewDidAppearなどのタイミングで、専用のメソッドをコールして手動でスクリーン名を送信していましが、FAでは画面追跡のイベント（screen_viewイベント）が自動で送信されます。
※FAでは、現在フォーカスされているUIViewControllerのクラス名など、アプリケーション内の画面に関する一部の情報を自動的に追跡しています。

なお、送信されたscreen_viewイベントの値はFirebase ConsoleのAnalyticsのEventsで
確認できます。（※以下の画像をご参照ください。）

__＜自動送信された画面のUIViewControllerクラス名＞__
<img width="491" alt="FAスクリーンクラス.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361214/2af3dabb-d36a-ee4c-918e-0503c6a70121.png">

ちょっと表示が切れていますが、上記の画像を見ると、ViewControllerのクラス名が自動的に送信され、**スクリーンクラス**に表示されているのがわかります。

## 画面自動追跡の設定手順

参照：[Get Started with Google Analytics for Firebase for iOS](https://firebase.google.com/docs/analytics/ios/start)

上記を参照し、進めていけばOKです。手順の大まかな方法は、以下の通りです。（2019/5/20時点）

１．'Firebase/Analytics'をpodでインストールする

```
pod 'Firebase/Analytics'
```

２．```application:didFinishLaunchingWithOptions:```でFirebaseライブラリの設定を行う

```swift
import Firebase

// (途中省略)

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    FirebaseApp.configure()
    // (途中省略)
    return true
}

```

## 注意： 既存のプロジェクトでスクリーンクラスが(not set)になる
新規プロジェクトでFAを導入する場合は、上記の設定手順で問題なく画面が自動追跡され、スクリーンクラスがfirebase consoleでも表示されたのですが、既存プロジェクトにFAを導入したところ、firebase consoleで表示されるスクリーンクラスが(not set)になる現象が発生しましたので、対応方法をまとめます。

<img width="490" alt="FA_not_set.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361214/92d980b5-2c0b-2bef-829a-58a7a7efa237.png">


原因がわからずいろいろ設定を見直したところ、以下のInfo.plistの項目が原因でした。

```xml
<key>FirebaseAutomaticScreenReportingEnabled</key>
<false/>
```
既存のプロジェクトでFirebase Analyticsは利用していなかったのですが、Firebaseの別のサービスFirebase Cloud Messagingを利用していました。

どの過程でFirebaseAutomaticScreenReportingEnabledの項目がInfo.plistに設定されたのか、なかなか追えなかったのですが、FirebaseAutomaticScreenReportingEnabledの項目を除去するかtrueを設定すると、画面の自動追跡が有効になりFirebase consoleでスクリーンクラスが表示されるようになります。
（新規プロジェクトにFAを導入した際は、Info.plistのFirebaseAutomaticScreenReportingEnabledの設定が無かったので、画面の自動追跡を行う場合は不要かと思います。）

今回はFirebase Analyticsの画面自動追跡の内容でしたが、引き続き調査した内容を今後もQiitaにまとめていく予定です。
Azure Portalからストレージにファイルがアップロードできなくなった！

# 事件は唐突に発生した

AzureStorageのFileサービスを利用して、VMからは`cifs`マウントすることでVM間のファイルを共有をしています。
検証用環境としてゆる～く使っており、ファイル操作はAzure Portal画面から気軽に行っていたのですが
突然ファイルが**アップロード出来なくなる現象に遭遇しました**。

# 何が起きた？

アップロードボタンを押すと即座にエラーメッセージが表示されるようになってしまいました。

![無慈悲なエラーメッセージが出たところ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/11411/edc3b034-3b9b-9012-284d-a39cf14cfdbe.jpeg)

メッセージには下記の通りに書かれています。

> Azure FileService ファイルの作成 が失敗しました。 詳細: BLOB ストアのSAS URI が有効であり、アクセス許可が期限切れになっていないことを確認してください。また、BLOB ストアの CORS ポリシーが正しく設定されていることを確認してください。StatusCode = 0、StatusText = undefined。

心当たりが無いメッセージにやっぱり焦ります:fearful:
ただ、エラーメッセージにはBLOBストアに関連した確認事項だけがヒントとして書かれていて
Fileサービスのみを利用している今回の事象とは無関係そうです。

# 試してみたこと

- 削除の操作
  Azure Portalからはファイルの削除もできます。
  試したところ、既に置いてあるファイルの削除はできました。

- フォルダの作成
  新規フォルダの作成オプションもあるので、作成したところできてしまいました。
  ファイルと同様、削除もできました。

- ファイルの上書き
  既存ファイルに同名のファイルをアップロードしようとしましたが、
  ファイルは消えるだけでアップロードは失敗しました。
  削除 → 追加、をもって上書きとしてるんでしょう。
  やっぱり追加段階でエラーになったんでしょうね。

- ストレージ自体の空き容量を増やした
  そもそも容量が足りないのでは？:thinking:
  確認したところ5GiBだけ割り当てていて4GiB以上は埋まっているので
  ディスクフルなんでしょう、と思いましたがだめでした。
  要らないファイルを消してもアップロードは出来ませんでした。

# 最後の手段だ！

別のストレージを作成して載せ替えちゃいましょう。
こういうことがサクッとクラウドの良いところですね。

### やっぱりだめだった
同じ現象が発生しました:innocent:

# 分からん、もう。

### サポートに連絡

結局はマイクロソフトのAzureサポートに依頼しました。

### 応急処置

回答によると現象自体の根本解消はできていないものの、応急処置として
Azure Portal画面の基本言語を**英語に**変更することでアップロードはできるようになると。

#### 提示された手順
半信半疑で英語に設定変更します。下記で変更できました。
1. Azure Portal (https://portal.azure.com) にアクセスします。
2. 画面右上にある [歯車のマーク] をクリックします。
3. [言語 (更新が必要)] のドロップダウン メニューより [English] を選択します。
4. 最下部の [更新] をクリックします。
5. 自動的に画面全体が更新され、ポータルの言語が英語になったことを確認いたします。

# 治った

確かに、英語表記にしただけであっさり治ってアップロードできました。
まあ、根治していませんが。

![あっさり治った様子](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/11411/8f3033ee-a294-95bd-a325-768ecbda74a3.jpeg)


# 今回学んだこと

Azure Portalで意味不明なエラーに遭遇した場合は、一旦英語表記に設定変更するだけで解消するかも知れません。
根治についてはMS様から続報があれば記載しようと思います。

# 【追記】Microsoft様からの回答

何度かMS様のAzureサポートから調査が難航している旨のメールを受信した後に、下記のご連絡をいただきました。

> 本日、確認いたしました状況によりますと、弊社データセンター側の事象発生
> 対象の環境に対し、すべての修正対応が完了した旨の報告を獲得しましたので
> 取り急ぎその旨をご報告いたします。
> 現時点におきまして Azure ポータル画面よりファイルのアップロードが正常に
> 行えていることを改めて確認いたしております。

詳細に書かれていませんが、修正したそうです。よかった。
2進数を分かりやすく解説したYouTube動画を３つ作成しました

2進数（2進法）に関しては、持論で「一度は理解しておくべき、だけどそこまで実用性はないので最小限の労力で学ぶのが良し」ぐらいに落ち着きました。
実際、ハードウェアに近いシステムプログラミングとかドライバーを開発したりとかしない限り2進数の理解は必要ない、と思うんですがどうでしょう？
もちろん、プロフェッショナルとして必要な状況は多々あると思うんですが得に「プログラミング教育」などではさほど重要ではない、と思うのです。ただ、16進数は実用的で使うシーンが多いと思いますし、16進数の理解の道筋には間違いなく2進数が出て来ると思うので、結局は通る道なんでしょうか。
ということで、2進数をまだ学んだことがない人が、出来るだけ簡単に、数学やプログラミングの雰囲気を抑えめで、教えるとしたらどういうのがいいかな、っとずっと模索していて、自分なりの解を動画としてまとめました。

[2進数が分からない？大丈夫！5進数だって3進数だって簡単に理解できます【コンピューターサイエンス】](https://youtu.be/TBiUh8tLh14)
[2進数パート２。12進数も16進数も実は簡単【レイジーな人のためのコンピューターサイエンス】](https://youtu.be/CBYsw8HpOLE)
[2進数パート３。指で数えて楽しく学ぼう【レイジーな人のためのコンピューターサイエンス】](https://youtu.be/52NaprUGEr0)
Neo4jをJupyter notebookで実行する

##はじめに

グラフネットワーク分析用ツール[Neo4j](https://neo4j.com/)をJupyterから実行し、
結果をJupyter notebook上に可視化させる。

実行には、[Neo4jboltドライバー](https://neo4j.com/docs/api/python-driver/current/#)を利用する。


本内容のNotebookは[こちら](https://github.com/miotakei/utils/blob/master/notebooks/Neo4j_jupyter.ipynb)。

---
##実行環境
CentOS
openJDK 8
python 3.6.6
Jupyter notebook 4.3.0

Neo4j CommunityEdition 3.5.5
[Neo4jboltドライバー](https://neo4j.com/docs/api/python-driver/current/#)


---
##準備

### インストール

- Neo4j
Neo4j をインストール
DLとインストール方法は[こちら](https://neo4j.com/download-thanks/?edition=community&release=3.5.5&flavour=unix&_ga=2.18496377.1397323080.1557018502-1719355477.1551781509)

- Python ライブラリ
Neo4jboltドライバー をインストール

```
$ pip install neo4j
```

---

### Neo4j パラメータ変更
 
- ホストOSからアクセス可能にするため、以下のパラメータをコメントアウト

```
$ vi $NEO4J_HOME/conf/neo4j.conf
# With default configuration Neo4j only accepts local connections.
# To accept non-local connections, uncomment this line:
dbms.connectors.default_listen_address=0.0.0.0
```

- bolt ドライバーを利用可能にするために、以下のパラメータをコメントアウト

```
$ vi $NEO4J_HOME/conf/neo4j.conf
# Bolt connector
dbms.connector.bolt.enabled=true
dbms.connector.bolt.tls_level=OPTIONAL
dbms.connector.bolt.listen_address=:7687
```

### Neo4jを起動

```
$ $NEO4J_HOME/bin/neo4j start
```

*初回起動後、以下にアクセスし必要に応じてパスワードを変更
http://localhost:7474

---

##データ

データはmovieのデータを利用

---
##実行

Jupyter notebookから以下の内容を実行

### ライブラリのインポート、ドライバーに接続
```python
import pandas as pd
from neo4j  import GraphDatabase, basic_auth
import matplotlib.pyplot as plt
%matplotlib inline

driver = GraphDatabase.driver("bolt://localhost:7687", auth=basic_auth("neo4j", "Welcome1"))
```
---

### グラフデータの分析、取得
```python
Query = '''CALL algo.betweenness.stream('','',{direction:'both'})
YIELD nodeId, centrality
MATCH (person:Person) WHERE id(person) = nodeId
RETURN person.name, centrality
ORDER BY centrality DESC LIMIT 10'''

session = driver.session()
res = session.run(Query)
    
col = ['name', 'centrality']
df = pd.DataFrame([r.values() for r in res], columns=col)
    
session.close()

del session

```
---

### 棒グラフの作成
```python
plt.figure(figsize=(15, 6))
plt.bar(list(range(len(df))), df['centrality'])
plt.xticks(list(range(len(df))), df['name'])
```
---

###結果
<img width="934" alt="スクリーンショット 2019-05-21 11.07.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113406/95dde0da-4358-2931-74e9-00a967f08113.png">


---
Safariのinput type="file"で問題が繰り返し起きるときの対応

# はじめに

ファイルアップロードは、かなり鉄板機能なので実装することが多いのですが、ハマりかけたのでログに残しておきます。

# エラーまでの経緯

ファイルアップロードのソースは、雰囲気こんな感じです。

inputタグをそのまま使うとダサいので、style="display: none"にして、その代わりにボタンやフォームのクリックイベントでinputタグのクリックイベントを発火します。

```vue
<template>
  <!-- 上は省略 -->
  <div class="text-xs-center">
    <img :src="imageUrl" height="200" v-if="imageUrl"/>
    <v-text-field color="primary" label="Select Image" @click='pickFile' v-model='imageName' prepend-icon='attach_file'></v-text-field>
    <input
     type="file"
     style="display: none"
     ref="image"
     accept="image/*"
     @change="onFilePicked"
    >
  </div>
  <!-- 下も省略 -->
</template>

<script>
export default {
  data () {
    return {
      imageName: '',
      contentType: '',
      imageUrl: '',
      imageFile: ''
    }
  },
  methods : {
    pickFile () {
      this.$refs.image.click ()
    },
    onFilePicked (e) {
      const files = e.target.files

      if(files[0] !== undefined) {
        this.imageName = files[0].name
        this.contentType = files[0].type  // contentType: image/jpegとか
        if(this.imageName.lastIndexOf('.') <= 0) { return }
	
        const fr = new FileReader ()
        fr.readAsDataURL(files[0])
        fr.addEventListener('load', () => {
          this.imageUrl = fr.result
          this.imageFile = files[0] // this is an image file that can be sent to server...
        })

      } else {
        this.imageName = ''
        this.imageFile = ''
        this.imageUrl = ''
      }
    }
  },
  /** いろいろ省略 **/
}

</script>

```

開発が一段落し、自分のiPhoneでぽちぽちやっていると、こんな現象に遭遇しました。


*問題が起きたため、このWebページが再読込されました。*
*XXXXXXXXで問題が繰り返し起きました。*

# 調べた

Safariでは、display:noneに問題があるらしいです。なので、**『inputタグはdisplay:noneではなく、divで囲んでheightとwidthを0にせよ』**とのことでした。

```vue
<template>
  <!-- 上は省略 -->
  <div class="text-xs-center">
    <img :src="imageUrl" height="200" v-if="imageUrl"/>
    <v-text-field color="primary" label="Select Image" @click='pickFile' v-model='imageName' prepend-icon='attach_file'></v-text-field>
    <div class="hiddenfile"> <!-- ←これで囲む -->
      <input
       type="file"
       ref="image"
       accept="image/*"
       @change="onFilePicked"
      >
    </div>
  </div>
  <!-- 下も省略 -->
</template>

<script>
/** 変更なし **/

</script>
<style scoped>
.hiddenfile {
  width: 0px;
  height: 0px;
  overflow: hidden;
}
</style>
```

う〜ん何故だろう、、、
むかしからdisplay:noneが常識かつ定石だと思っていましたら、Safariさんは違ったようです。

めでたし。

# 参考記事
[Safari input='file' doesn't work](https://stackoverflow.com/questions/24980459/safari-input-file-doesnt-work)
MW WP Formでphpファイルから自由に選択項目を設定する

MW WP Form便利ですよね。
確認画面も付いてるし
デザインも柔軟に変更できるし
カスタマイズも容易だし
日本人開発のため日本語情報多いし（重要）

ただWordpressって管理画面に入ってなにか作業するのってダルいので、極力phpファイルで出来るようにしています。

なので今回は投稿画面でなくphpファイル内(functions.php)でセレクトボックスやチェック、ラジオの項目を設定する方法を書きたいと思います。

## mwform_choices_mw-wp-form-xxx を使う

[https://plugins.2inc.org/mw-wp-form/filter-hook/mwform_choices/](https://plugins.2inc.org/mw-wp-form/filter-hook/mwform_choices/)
これ利用すると管理画面外から色々設定できます。
例ではカスタム投稿タイプ「products」の投稿を選択肢として表示してますが、もっと単純に静的な項目でも簡単に設定できます。

```php:functions.php
function add_discount( $children, $atts ) {
    $discounts = ['割引A','割引B','割引C'];
    if ( $atts['name'] == 'discount' ) {
        foreach ( $discounts as $discount ) {
            $children[$discount] = $discount;
        }
    }
    return $children;
}
add_filter( 'mwform_choices_mw-wp-form-xxx', 'add_discount', 10, 2 );
```

管理画面上では空で設定しておけばよいです。":--"にしておくと最初の項目が"--"で`value=""`の状態になります。

```
[mwform_select name="discount" children=":--" post_raw="true"]
```

## 複数項目あってもmw_form_choice一つで設定できる
```php:functions.php
function custom_form_contents( $children, $atts ) {
    $discounts = [...];//配列で設定。以下同文
    $options1 = [...];
    $options2 = [...];
    switch ($atts['name']) {
        case 'discount':
            foreach ( $discounts as $discount ) {
                $children[$discount] = $discount;
            }
            break;
        case 'option1':
            foreach ( $options1 as $option1 ) {
                $children[$option1] = $option1;
            }
            break;
        case 'option2':
            foreach ( $options2 as $option2 ) {
                $children[$option2] = $option2;
            }
            break;
        default:
            break;
    }
    return $children;
}
add_filter( 'mwform_choices_mw-wp-form-xxx', 'custom_form_contents', 10, 2 );

```
switchで条件分岐させれば複数あっても適用できます。`$discounts`の配列部分も`require`とか`include`使えば別ファイルからも渡せるのでconfig.phpのような管理用ファイルで設定するっていうのもできます。


マニュアルの例より簡単なことしてるけど、意外とこっちの方が使う機会多いんだよな。。

もっといい方法あればぜひ教えてください！
EC-CUBE4で支払方法ごとに注文受付メールの文言を切り替える

支払い方法に応じて、注文受付メールの文言を切り替える方法を解説します。
例えば、銀行振込の場合にのみ銀行口座を表示したい、のようなケースで使用できます。

## 支払方法のIDを確認

管理画面から、設定＞店舗設定＞支払方法設定を表示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72858/f3dffefd-8c1b-8320-4202-c8828227b35f.png)

銀行振込の場合は、初期状態ではIDは「3」になります。

## メール設定から、メールのテンプレートを編集

設定＞店舗設定＞メールテンプレート設定を表示します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72858/8f49a96b-eb7b-d5a8-474d-383b07d1b9a6.png)

## テキストメールの編集

「注文受付メール」を選択し、「本文」に以下のテキストを追加します。

```twig

{% if Order.Payment.id == 3 %}
************************************************
お支払いにつきまして
************************************************

お振込先の口座は以下をご指定ください。

さんぷる銀行

支店：難波支店
口座番号：(普) xxxxxxx
振込先：カ）イーシーキューブ
{% endif %}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72858/8655bc7b-b968-8832-cd52-f351b98d958e.png)

## HTMLメールの編集

「HTML」のタブを選択し、HTMLメールの編集モードに切り替えます。
「本文」に、以下のテキストを追加します。

```twig
{% if Order.Payment.id == 3 %}
<hr style="border-top: 3px double #8c8b8b;">
　お支払いにつきまして<br/>
<hr style="border-top: 3px double #8c8b8b;">
お振込先の口座は以下をご指定ください。<br/>
<br/>
さんぷる銀行<br/>
<br/>
支店：難波支店<br/>
口座番号：(普) xxxxxxx<br/>
振込先：カ）イーシーキューブ<br/>
<br/>
{% endif %}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72858/e55d4158-d85a-89cd-5c5b-2d62be6e36a6.png)

以上で設定は完了です。
ショップ画面からテスト購入を行い、メールに修正が反映されているか確認してみてください。
Android エミュレーターでネットワークに繋がらない時



### 1. SDKの場所を確認する

 - Android Studioを開き、右下のConfigerを押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88533/2135dc2c-c6e4-1a1c-49e8-8c03ad9edfdd.png)


 - Project Defaults → Project Structureを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88533/425f1c23-9398-b63d-73dd-3996728b4f2a.png)


 - Android SDK LocationにSDKのパスがあることを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88533/de843d17-9eb6-1da6-84f6-81e36e8f05a7.png)

### emulatorのDNSを変更させる

 - ターミナルでSDKのパスに移動

```
cd /Users/xxx/Library/Android/sdk
```

 - さらにemulatorフォルダに移動

```
cd emulator
```

 - emulatorの一覧を確認

```
./emulator -list-avds
```
と打つと、私の場合はこれ↓が返ってきました

```
Nexus_5X_API_19
Nexus_6_API_22
Pixel_2_XL_API_23
Pixel_XL_API_19
```

 - デバイスを一個ずつ起動させる（Nexus_5X_API_19の箇所は自由に変えてください）

```
./emulator -avd Nexus_5X_API_19 -dns-server 8.8.8.8
```




この手順でネットワークにつながりました！
【jQuery】異なるバージョンを共存させる

ひとつのリソースに複数のコーダーが関わってるとたまにあるやつ。
これを導入したら既存のギミックが動作しなくなった・・・みたいな。

<h4>解決方法</h4>
`$.noConflict()`を使う

```html

<script type="text/javascript" src="https://code.jquery.com/jquery-1.8.2.min.js"></script>
<script type="text/javascript">
    $182 = $.noConflict(true);
</script>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
```

これで、<b>$182</b>はバージョン1.8.2、<b>$</b>はバージョン3.3.1のjQueryとして使い分けることが可能。 

参考.
[1画面内でバージョンの異なるjQueryを共存させるには](https://rei19.hatenablog.com/entry/2013/03/25/000818)
Linux初心者向け基本コマンド一覧

#覚えておきたい基礎中の基本コマンド
ホームディレクトリ直下にシェルスクリプト用のディレクトリを作成して、自分の名前を表示するシェルスクリプトの作成から実行まで行いたい。

//すべてホームディレクトリから実行します。

####ディレクトリを作成して新規シェルスクリプトファイル作成

mkdir makeDirectory
vi エディター実行と新規ファイル作成

```
mkdir ~/sample
vi sample/sample.sh
```

####シェルスクリプトを作成
[変数の宣言＝ / echoで出力 / セミコロンの使い方]

```Linux
#!/bin/bash #シバンまたはシェバン 必ず入れる

userName=Kenny!
echo $userName

#または

userName=Kenny!; echo $userName
#セミコロンで区切ると行を短縮できる
```

####実行権限を付与する
change mod

```
chmod 770 sample/sample.sh
```
####シェルスクリプトを実行する
```

./sample/sample.sh
```
グーグルドライブ

グーグルドライブをうまくいれることができない場合

グーグルドライブ
https://www.google.com/intl/ja_ALL/drive/
ダウンロードページ
https://www.google.com/drive/download/


ダウンロード→インストール
したものの起動しない場合
すべてのプログラムリストから「Backup and Sync」を探す←こっちで解決
起動すると、右下タスクトレイに新規「雲」アイコンがあれば、クリック

ネット検索で解説されているページでは「Backup and Sync」を自動翻訳されているのか、
「バックアップと同期を起動する」と表現されていて、
詰まってしまうことがある。
AWS WAFの概要

# このページについて
先日、業務でDoS攻撃をくらったため、AWS WAFを導入することになりました。
導入に伴っていろいろ勉強したこと、DoS攻撃を防ぐAWSサービスであるAWS Shield standardで防げるもの、AWS WAFで防げるものについて記載していこうと思います。

# 構成
![AWS WAFなしの構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413372/3ba689ab-4bf8-e337-4257-cef58a040148.png)
![AWS WAFありの構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413372/185e29d9-0647-d1a3-2c6a-a288855f459d.png)

# AWS Shield standardについて
- AWS Shield standardは、OSI参照モデルのレイヤー3および4のDoS攻撃を防いでくれる機能です。
- AWS Shield standardは、AWSサービスであるELBやCLoudFrontを使用すると自動的に有効化されます。

## AWS Shield standardで防げるレイヤー3および4のDoS攻撃
### SYN / ACK / FINフラッド攻撃
レイヤー4で使用するTCP接続を確立するために使用する3ウェイハンドシェークで、最初に投げる制御ビット（SYNやACK、FIN)を大量に送りつけることでサーバ側のキャパシティオーバーを引き起こす方法
### UDPフラッド攻撃
UDPパケットを大量に送りつけることでサーバ側のキャパシティオーバーを引き起こす方法

# AWS WAFとは
- AWS WAFは、OSI参照モデルのレイヤー7のDoS攻撃を防いでくれる機能です。
- HTTPのGET/POSTメソッドを使用した攻撃に対して有効です（例えば、GETリクエストを大量に送りつけることでサーバ側のキャパシティオーバーを引き起こす方法）。
- AWS WAFの導入には、ALBもしくはCloudFrontを使用する必要があります（CLBでは不可です）。

# 参考とさせていただいたURL一覧
* https://dev.classmethod.jp/cloud/aws/aws-waf-alb-support/
* https://recipe.kc-cloud.jp/archives/9095
* https://www.shadan-kun.com/blog/measure/1426/
Rails5.2 migrationファイルの作成とやり直し方



###migrationファイルの作成とやり直し方(初学者向け)

migrationファイルとは、一言で言うと、
**DBの設計図です。**
マイグレーションファイルに必要なカラムを書き込み、実行することでDBにテーブルを作成できます。アプリケーションとデーターベースの間には構造的なギャップがありまして、インピーダンスミスマッチと言うそうですが、Rails ではO/RマッパーであるActiveRecordが提供されていて、SQLで書かずとも、データを取得できることになってます。
###modelを作成するとmigrationファイルも作成されます
modelと併せて作成できます:blush:

```
$ rails g model モデル名　
```

### カラムを追加したい時migrationファイルも作成されます:blush:

```
$ rails g migration AddXxxxxToテーブル名
```
###作成したいカラムを記述します
changeメソッドで作成するカラムを指定します。
この例はnameとbookとimageカラムを作成します。
書き込んだ後、保存してください。

```ruby:db/migrate/201xxxxxx_creat_books.rb
class CreateTweets < ActiveRecord::Migration[5.2]
  def change
    create_table :books do |t|
      t.string   :name
      t.text     :book
      t.text     :image
      t.timestamps null:true
   end
  end
end
```

####主な利用できるデータ型

| 型 | 説明 | 用途 |
| :---         |     :---:      |          ---: |
| integer   | 数字     | ユーザid    |
| string     | テキスト      | パスワード,ユーザー名      |
|text |文字|テキスト|
|boolean  |真か偽か|真偽フラグ|
|datatime |日付と時刻|作成日時
|float|浮動小数点数|

###実行コマンド
現時点で未実行のmigrationファイルを実行します。

~~~
rake db:migrate
~~~
###schema_migrationsファイルにバージョンが記録される

~~~ruby:db/migrate/schema.rb
ActiveRecord::Schema.define(version: 2019_05_20_151430) do

  create_table "books", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
    t.string "name"
    t.text "text"
    t.text "image"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

end

~~~

**schema_migrations**ファイルはmigrationファイルの実行履歴のようなもので、複数のmigrationファイルにおいても、記録されているテーブルです。最新のスキーマ情報をrubyスクリプトとして表現しています。

###テーブルを確認する(phpMyadmin(Mysql))
**versionが一致しているmigrationファイルであることがわかります。**
***
<img width="672" alt="mysql-pic.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328651/2b29b9d4-bacf-e4e5-54b8-d056a3dad817.png">
***
##dbを元に戻したい時
### どこまでmigrateされているか確認する
migrationファイルを削除する前に確認しておきましょう。

```terminal
rake db:version
```

意図しないカラムができた場合や、何かしらの更新の変更の時など。

~~~
$ rake db:rollback
~~~

### migrateされていないファイルを確認する
```terminal
rake db:abort_if_pending_migrations
```
ロールバックしたことによりdbからは削除されていますが、ファイルとしては`db/migrate`に残っています。ぱっと見では確認出来ませんがこのコマンドにより、migrateされていないファイルを特定出来ます。


`rake db:rollback`は最新の更新履歴の一つ前の状態に戻すコマンドです。意図しないカラムなどを削除して書き換えて、今一度、`rake db:migrate`で実行しても、更新はされません。新たなカラムを追加したい場合は、常にmigrationファイルを作成してください。

###ActiveRecord::Base.connection.tables
DBが元に戻ったかターミナルで確認

~~~
#コンソールで確認
$ rails c

#booksがない場合は、成功してます
$ ActiveRecord::Base.connection.tables
=> ["schema_migrations",]

＄ exit
~~~

###これまでmigrateした履歴を表示
~~~
$ rake db:migrate:status
~~~

**結果**

~~~
database: book_development

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20190520151430  Create books
~~~

up で表示されるのはDBに反映されているファイルのこと。
down で表示されるのは、反映されていないファイルのこと。

###migrationファイルを複数から選んでrollbackしたい時
特定のファイルを指定できます。

~~~
rails db:migrate:down Version=migrationID
~~~




###まとめ
####migrationファイルで出来ること(初学者向け)
migrationファイルはDB設計図であります。
今回はchangeメソッドとdbを使うときの扱い方法でした。
指定した時間にメールする

# はじめに

定時報告ではないが、ある時間にメールしたい事がビジネス上あると思う。

私が所属している脆弱性診断業務の場合は、顧客と事前合意した開始時間(のちょっと前)に「開始メール」や、終了時間(のちょっと前、または直後)に「終了メール」を、大体だけど時間指定でメールするんだけど、そのタイミングで会議とか、急な呼び出しが掛かったりとかで、忘れてしまったりする場合もあるんで、そういう場合の Microsoft-Outlook の Tips です。

まぁ、普通はこの手のシステム(サーバ作って、クライアント-サーバ型システムですかね!?)を構築して、万全を期するかもしれないけど、パソコン一つでどうにかなるので、システム作るほどの話でもないとは思うけど、それは会社それぞれ。

# 指定した時間にメールする

送信メール・メッセージのプロパティに「指定日時以降に配信」というオプションがあるので、それを設定するだけ。

こんな感じ

![o04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182822/9dbc0812-c851-5129-b202-a0a839c7b23c.png)

1～2分はズレるかもしれない。

当然だけど、以下の場合は、指定した時間にメールが送信されない。

- パソコンの電源が落ちていた
- Outlookが起動していない
- パソコンがネットワークに参加していない
- 経路上のメールサーバが落ちている

# 蛇足

プロパティを見ると、投票するとか、指定した日時に削除(昔のスパイ映画で「なおこのメッセージは5分後に消滅する」みたいな!?)とか、できるかもしれない・・・

# 以上
API Gateway で作成したAPIを独自に用意したCloudFrontディストリビューションで公開する


## 背景

* API を API Gateway + Lambda で作成している
* 1つの Cloudfront ディストリビューションで API など動的なレスポンスと画像などの静的なレスポンスを供給する構成としている
* API Gateway のエンドポイントタイプは「リージョン」を選択している

※以下の設定内容は本番環境で十分に検証されたものでは無いことに注意。

## CloudFront の設定

いろいろハマったりしたが、以下のような設定に落ち着いた。

* API Gateway に対応する Origin を作成
    * Origin ID は "API Gateway / {API名}" みたいにわかり易いものにする
    * Minimum Origin SSL Protocol は "TLSv1.2" を選択
    * Origin Protocol Policy は "HTTPS Only" を選択
* API の path (`api/*` など) に対して API Gateway に転送するための Behavior 設定を追加
    * Viewer Protocol Policy は HTTPS Only
    * Cache Based on Selected Request Headers で Whitelist を選択
        * API で必要なヘッダを明示的に Whitelist に追加する
    * Object Caching は Customize を選択
        * Minimum TTL, Maximum TTL, Default TTL を 0 にする
    * Forward Cookies は必要に応じて設定
        * 自分のケースでは `_session_id` を Whitelist に追加してオリジン側（Lambda関数）に渡すように設定した
    * Query String Forwarding and Caching は Forward all, cache based on all を選択


## ハマった点

### CloudFront の Origin 設定で Origin Protocol Policy が HTTP Only になっていた

* API Gateway は HTTPS のみサポートなので HTTPS Only とするのが正しい

### Cache Based on Selected Request Headers の設定が All になっていた

* `All` とした場合 `Host` ヘッダもそのまま（Cloudfrontに割当てられたドメイン名そのまま）オリジン（API Gateway）に転送される
* そうした場合、API Gateway のSSL証明書とホスト名の不一致で Forbidden が返される
    * curlで再現してみる
    
    ```terminal
    $ curl https://xxxxxx.execute-api.ap-northeast-1.amazonaws.com/test -v -H 'Host:hoge.example.com'
    * Connection state changed (MAX_CONCURRENT_STREAMS updated)!
< HTTP/2 403
< date: Mon, 20 May 2019 06:53:31 GMT
< content-type: application/json
< content-length: 23
< x-amzn-requestid: fad71491-7acb-11e9-a176-0bf199e4dfca
< x-amzn-errortype: ForbiddenException
< x-amz-apigw-id: Z-FE0G7htjMFaGw=
<
* Connection #0 to host xxxxxx.execute-api.ap-northeast-1.amazonaws.com left intact
{"message":"Forbidden"}
    ```

* 上記の理由により、 API が必要なヘッダを明示的に指定する必要あり
    * たとえば、自分のケースだと API Gateway 経由で Lambda 関数を実行するには以下のヘッダが必要だった
        * `Accept`
        * `Accept-Encoding`
        * `Accept-Language`
    * Cache Based on Selected Request Headers で、 Whitelist を選択し、上記のヘッダを Whitelist に追加


#### じゃあキャッシュを禁止するには？

* もともと、CloudFrontでのAPIのキャッシュを無効化するつもりで「All」の設定を行っていた
* 「All」の指定ができないとしたら、どうやってキャッシュを無効化するか？
* とりあえず、Behaviour の 各TTL設定(Minimum, Maximum, Default)を `0` とした


## 参考

* [Cloudfront-Origin間のHTTPS通信エラー原因と対策（502:Bad Gateway） - Qiita](https://qiita.com/kaojiri/items/4e2d2f112acfca14970e)
* [【小ネタ】カスタム認証を使うAPI GatewayをCloudFrontの後ろに置いたらAPIを叩けなくなった ｜ DevelopersIO](https://dev.classmethod.jp/cloud/how-to-put-api-gateway-with-custom-authorization-bihind-cloudfront/)
* [AWS SAMにてサーバーレスアプリケーションを実装するときに気をつけたこと - Qiita](https://qiita.com/elyunim26/items/c1ad35b5188c9b70b864#%E9%80%9A%E9%81%8E%E3%81%95%E3%81%9B%E3%82%8Bheader%E3%82%92%E6%98%8E%E7%A4%BA%E7%9A%84%E3%81%AB%E6%8C%87%E5%AE%9A%E3%81%99%E3%82%8B)
ソフト開発 > セカンドシステム症候群 | 第一..第三のシステム

### セカンドシステム症候群

- [フロントエンドでとても大切な3つのプラクティス](https://qiita.com/kahirokunn/items/3151bc35adf16ac720c0)

セカンドシステム症候群について記載がある。

セカンドシステム症候群については「Coders at Work by Peter Seibel」に以下の記述がある。

> p19
我々のやっていた仕事や我々の成功をすべて無視し、セカンドシステム症候群に向かってまっしぐらに突き進み、会社を沈没させたのです。

...

> p106　セカンドシステム症候群
何か成功を収めた人たちが白紙状態から何でもしていいと言われたときに陥る。...それはあまりに野心的になって、限界を理解しないためです。...強い統制力をもって言う必要があるのです。「これは白紙状態ではない。すでにあるものの再実装だ。我々に分かっていることをやるのだ」


## 第一..第三のシステム

関連して思い出したのが、第三のシステム。

UNIXという考え方 by Mike Gancarz 2015-07-03読了

### 第一のシステム

> p34 第一のシステムは、一人か、またはせいぜい数人からなる小さなグループで創られる
p35 第一のシステムは無駄がなく俊敏な計算機だ
p36 第一のシステムのコンセプトは人間の想像力を刺激する 

### 第二のシステム

> p37
しかし、皮肉なことに第二のシステムは、３つのうちで最悪のシステムでもある。

>p37「専門家」が、第一のシステムで証明されたアイデアを用いて第二のシステムを作る
p38 第二のシステムは、委員会が設計する
p39 第二のシステムはぜい肉がつき、遅い

### 第三のシステム

> p40 第三のシステムは第二のシステムで「火傷」した人が作る
p42 第三のシステムは、第一のシステムと第二のシステムの最良の特徴を組み合わせる 

### 所感

第三のシステムまで作る例はどれほどあるだろうか。

第二のシステムで失敗した会社が第三のシステムを作るだろうか。

注意が必要。
WBSとは？今更ながら説明

## はじめに

"WBS"というものは実際の現場では良く使われるものです。
でも現場によって意味が違っていたり、惰性で作っていてなぜ作っているのかよくわからなかったりもします。
ということで「WBSって何？何のために作るの？」を説明してみます。

> Twitterでちょっと話があがったのでちゃんと説明したら焼肉くらいおごってもらえるかも？と思ったので投稿してみます。

## WBSとは？

Wikipediaよりの抜粋

**WBS : Work Breakdown Structure**
*プロジェクトを理解し管理する上で、プロジェクトの各工程を各担当者の作業レベルまで展開し木構造にまとめたものである。どのレベルまで展開するかはプロジェクトの全メンバーが作業内容を「具体的に〇〇をする」と理解出来るレベルまでに分解するのが理想であるが、最低でも作業担当者とプロジェクト管理者の理解が得られるレベルまでは必要である*

簡単に図示するとこう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33095/459a9ff5-ecaf-1b76-6aa8-c45b6760d661.png)

つまり大きなカタマリのままでは理解しづらい最終ゴールを分解することでわかりやすくする手法です。
当たり前すぎて手法と言うほど大げさなものではないですがこれをWBSと言っています。

> あれ？WBSってガントチャートのことじゃないの？と思った方もいるかもですがそれは後述。

### WBSの W=WORK(ワーク) とは？

ここでちょっとだけ考えておかないといけないのはWBSのWである「WORK(ワーク)」とは何か？です。

ワークは別に日本語で言うところの「**作業**」**だけ**を指しているのではなく「**成果物**」も指しています。

例えば上の例は「ECサイト → ログイン機能 → ID/PW入力」までは成果物の視点で分解した流れです。書いてませんが「設計書」とかそういうのがでてくることもあります。その後の「設計」「実装」「テスト」は作業よりで分解しています。

WBSの基本的な考え方は「すべての作業を積み上げると最終的な成果物が出来上がる」というものです。なので個人的なおすすめとしては「成果物」で分解できるところまで分解して最後にその最も細かく分解された成果物を作るための「作業」を付けるというのをおすすめします。

## WBSとガントチャートの違いは？（ついでにOBSも）

WBSと言った時に担当者付きのスケジュールを思い浮かべる人も多いと思います。

実際現場ではそう使われることが多いですがこれはどういうことかというと、

- WBSは成果物を分解して作業レベルにまで分解したもの
- OBSはWBSの作業に対して担当者名を付与したもの
- ガントチャートはWBSの作業を横棒でスケジュールや進捗を可視化したもの

図にしてみるとこんな感じです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33095/31bbf380-7398-006b-c22a-6e3708183ca0.png)

WBSを作れば担当者を割り振るでしょうしスケジュールも加えるでしょうし、これらは一括りにして「ガントチャート」と呼ばれていたり「WBS」と呼ばれていたりします。

## メリットとかデメリットとか

メリットは何といってもわかりやすいところです。

老若男女とわず業界問わずほぼ誰でも意味を理解してくれます。
ツールも特別選びません。Excelでも何でも作ることができます。
これだけでもものすごいメリットです。

デメリットは真面目にやろうとするととても大変ということです。
ツリー構造というのは原則１つのルートからすべてが木構造につながります。それを末端まで全作業を分解していくのはとても時間がかかります。

最初から完璧にクリアなプロジェクトなら良いですが、そうでもないなら使い捨てになることがわかっているのに最初からWBSを完璧に作り上げるのは無駄です。

## まとめ

WBSは複雑なゴール（要件）を見通しが良くなるように分解して扱いやすい形にしましょう！ついでに可視化もしてみんなで共有できるようにしましょう！というものです。

使い方次第では自身の理解のためのツールとしてもチーム内外の共有のツールとしても有効なツールなので毛嫌いせず積極的に有効活用してみましょう。

---

## Appendix. アジャイルとの相性とか

一般的には相性があまり良くないと言われます。

上のデメリットでも書きましたが、原則的にWBSというものはゴールを分解して全ての作業を見えるようになるまで細かく分解していく手法です。

現代のソフトウェア開発においてプロジェクトのスタート時点で最終的なゴールの姿が確定していて、変化なく最後まで行くことは極めてまれです（というかあり得ないです）。ついでに言うとソフトウェアのような複雑なものを正確に日単位で見積もってスケジュール化することも無理です。作業者のスキルもバラバラですのでやってみないと分からないことが多い分野です。

そう考えると、最初にWBSをきっちり作って、担当者をわりふって、ガントチャートを書く作業は無駄です。すぐに使い捨てになってしまうからです。考える時間も無駄ならそれを図にする時間も無駄です。

**だがしかし!!**

その相性の悪さの裏返しで、要件が確実に決まっていて見積もり可能な作業であればWBSほど有効な手段はありません。

それはつまり何かと言うとアジャイル（Scrum）で言うところのSprint Backlogが近いです。Sprint Backlogの作業は要件は絶対に変更されないしスケジュールもSprint内でやることが絶対です。

スケジュールはSprintしばりなので考える必要はない。OBSも自律型チームであれば気にする必要はない。けどSprint Backlogをしっかり達成するためには実作業レベルまでSprint Planningで落としこむ必要はあります。その時にはWBSのテクニックは絶対的に有効なものです。

ということでWBS！？ガントチャート！？と毛嫌いせず積極的に学んで使えるところは使ってみましょう！というメッセージでした。
Excelで文字数（size）チェックするための文字を生成

### セルを指定して文字数（size）生成
セル"C3"の部分が数字（例.256）のようなデータになっている想定
`=REPT("あ",E1)`
`=REPT("A",E1)`

### セルを相対指定して文字数（size）生成
先ほどの C3 を以下に変えると、常に左隣のセルを参照できる。
`OFFSET(INDIRECT(ADDRESS(ROW(),COLUMN())), 0, -1)`


### 全角/半角表記パターン
セル"C3"の部分が以下のようなデータになっている想定

- 全角256
- 半角256

`=IF(COUNTIF(C3,"全角*"),REPT("あ",RIGHT(C3,LEN(C3)-2)),REPT("A",RIGHT(C3,LEN(C3)-2)))`


左隣のセルが以下のようなデータになっている想定

- 全角256
- 半角256

```
=IF(COUNTIF(OFFSET(INDIRECT(ADDRESS(ROW(),COLUMN())), 0, -1),"全角*"),REPT("あ",RIGHT(OFFSET(INDIRECT(ADDRESS(ROW(),COLUMN())), 0, -1),LEN(OFFSET(INDIRECT(ADDRESS(ROW(),COLUMN())), 0, -1))-2)),REPT("A",RIGHT(OFFSET(INDIRECT(ADDRESS(ROW(),COLUMN())), 0, -1),LEN(OFFSET(INDIRECT(ADDRESS(ROW(),COLUMN())), 0, -1))-2)))
```






~~こんなことせずに、全部seleniumでやりたい。。。~~
AWS構築の見積もりについて


AWSでシステムを動かしたい。費用は？という点からオンデマンドセミナーを見ての備忘録。

「料金設定のベストプラクティス・見積もり作成ハンズオン オンデマンドセミナー」から
※2017年12月9日時点の料金体系
https://aws.amazon.com/jp/blogs/news/on-demand-quotation-handson/

## AWSおさらい
* 初期投資が不要
* 低額な利用料金
* 従量課金（実際の使用分のみ支払い）
* セルフサービス（使いたいときに使いたい分だけ）
* リソース増強も自由度がある
見積もりで大変な部分は、従量課金部分で事前予測が難しいという声が多い。その声を解消するためのセッション

## 見積の考え方

* 基本的にAWS利用平均値は、9割が EC2 or RDS。この２つを軸に見積を考える
* 商用環境は、365日24時間で見積ことが大多数。これは、月額固定費として扱うことができる。
* EBS＝確保した容量分の料金がかかる。アタッチされたEC2の起動・停止に関係なく費用が掛かる。
* S3 = EBSとことなり、利用している容量にのみ費用がかかる（事前に容量を確保しない）。
* リージョンごとに料金が異なります。
* ユーザーアクセスに対してレイテンシーが関係ない場合は、アメリカリージョンのほうが若干安くなる。
* AZ間の通信は、1ms程度
* データ転送 ＝ 一番計算しずらい・・・が全体の10％ないに収まってる統計となってる。
* 動画配信等は、ちょっと違うのでアマゾン担当者にご相談くださいとのこと。
* インスタンスを停止している分は、料金は発生しない。
* スペック、ライセンスによって時間単価が変わる
* 料金ツールは、最大24時間のずれが生じている
* 料金の閾値をウォッチしてアラート送信が可能
* Amazon Linux に限っては、1秒単位での課金になっている。
* RDSのMulti-AZ は、２インスタンス分の料金がかかります。


## データ転送

* 基本的にAWS利用の10％内で収まるコスト
* リージョンに対する下り通信にのみ料金がかかる。リージョンに対する上り通信は、料金がかからない。
* リージョン内の通信（AZ間の通信も微細な費用がかかるが、見積もりに含めないのが一般的）。
* 通信先リージョンで料金が異なる。


## サポート料金
* 24時間365日（メール・電話・チャットでの日本語サポートを提供）
* デベロッパー（開発者向け、開発環境向け）
* ビジネス（商用環境向け）AWS利用料金の10％がかかる
* エンタープライズ（専用テクニカルアカウントマネージャがアサインされる）

## 概算算出時のポイント

* 物理環境とおなじ間隔でサイジングしない
  * 検証環境やスタンバイ機を常に用意しておく必要はない
* AWS内部ネットワーク構成は費用にほぼ影響しない
* 割引オプションやボリュームディスカウントを見積環境後に比較考慮
* EC2 = 70%、RDS = 20%。商用環境は、24時間稼働なので月額費用として見積もる。
  * この2サービスの見積もり精度を高めることが最初のミッション
* マネージドサービスの積極利用
  * エンジニアのオペレーションなどの費用削減効果

## お支払い方法について

* 原則クレジットカード払い
* 価格は、ドル表記
* Visa, MasterCard ならカード会社へ円請求への変更が可能
* クレジットカード払いから海外送金払いに切り替えが可能（請求書払い）
* 月2000ドルを超える支払いが継続して確実に見込める場合＞営業に問合せ
* 請求代行会社によるお支払い
* AWSのパートナーが実施している代行サービス

## 概算見積もりの注意点

* 見積ツール利用
  * https://aws.amazon.com/jp/how-to-understand-pricing/
  * 簡易見積もりツール
* 注意点
  * 日本語が表示されていない場合は、画面右上の言語選択で「日本語を選択」
  * 無料利用枠のチェックを外す
  * どのリージョンで見積もりするのかを選択（リージョンで料金差異がある為）
C++ Builder > Vim > Borland C++5.5対応のコードがあったようだ | 過去の実装の除去 | Neovim

### VimにかつてあったBorland C++対応コード

- [最近Vimに取り込まれた大規模パッチに関する備忘録](https://qiita.com/k-takata/items/71fbdea3a8481a4597ad)

> 現在のWindows版Vimは、Visual C++とMinGWでビルドできるようになっていますが、かつてはBorland C++ 5.5でもできるようになっていました。しかし、Borlandを使う人がいなくなってしまい、いつの間にかビルドできなくなってしまっていました。Borland C++の後継としては、Embarcadero C++も公開されていますが、これに対応させようという人もいませんでした。そのため、Borland向けのコードをすべて削除することになりました。


- patch 8.1.1306: Borland support is outdated and doesn't work 
    - https://github.com/vim/vim/commit/eae1b91fea74842000fc055afc74fe2e7934c6ee

### 過去の実装の除去

壊れた実装は不要なものである。正しい。

一方で、過去に誰かがした仕事を足掛かりとして、将来別の誰かが何かをすることもある。

Git上で消えた`#ifdef`は、その存在自体を最新版では気づかないことが多い。
Embarcadero C++で実装をしようとする人が現れた時は「ゼロ」からのスタートになる。
(今はC++ BuilderでClang（古いバージョン）も使えるようになっているので、そういう人が現れるか不明ではあるが）

Borland C++の実装（壊れているが）が残っていた場合、その情報を読み解き、「この部分を変更すればいいだろう」と作業が短縮されることもあるかもしれない。一方で、残ることでそれを使わない人にとっては「ソース可読性へ悪影響」でしかない。

難しいところ。

### Neovim

上記のように、長い歴史を持つVimのコードの可読性や変更困難性を検討した結果生まれたプロジェクトがNeovimだと認識している。

https://neovim.io/

https://neovim.io/charter/
> Neovim is a refactor, and sometimes redactor, in the tradition of Vim (which itself derives from Stevie). It is not a rewrite but a continuation and extension of Vim.

neovimはスクラッチからコードを実装する?(あるいは大規模なリファクタをする?)ことで、長い歴史を持つVimの複雑なコードをシンプルなものへと変えようとしている、と認識している。

neovimが今後どれくらい支持されるか不明であるが、そういう動きもある。
Rails6 のちょい足しな新機能を試す20（ActiveStorage::FileNotFoundError編）

# はじめに

Rails 6 に追加されそうな新機能を試す第20段。 今回のちょい足し機能は、 `ActiveStorage::FileNotFoundError` 編です。
Rails 6.0 では、 `ActiveStorage::Blob#open` などで対応するファイルが見つからなかったときに `ActiveStorage::FileNotFoundError` が発生するようになりました。

記載時点では、Rails は 6.0.0.rc1 で確認しました。Rails 6.0.0.rc1 は `gem install rails --prerelease` でインストールできます。

```shell
$  rails --version
Rails 6.0.0.rc1
```

# わざと動作しないコードを書く

今回は、 `ActiveStorage::FileNotFoundError` が発生するようにわざと動作しないコードを作成します。

[Rails6 のちょい足しな新機能を試す16（UploadedFile#to_path編）](https://qiita.com/suketa/items/c06068518ae0ba283b2b) で使ったコードを修正して動作しないようにします。
`User` モデルの `avatar_file_format` メソッドを動作しないように修正します。

```ruby:app/models/user.rb
class User < ApplicationRecord
  ...
  private

  def avatar_file_format
    avatar.blob.open do |file|
      header = File.read file, 8
      if header != PNG_FORMAT_HEADER
        errors.add(:avatar, 'is not png format file')
      end
    end
  end
end
```

# 試してみる

Rails サーバーを立ち上げて http://localhost:3000/users/new にアクセスしてユーザー登録してみます。
アップロードする画像ファイルも指定します。
`Create User` ボタンを押すと `ActiveStorage::FileNotFoundError` が発生します。
![2019-05-18-210935_790x291_scrot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209941/bfb0f3d5-11c8-d77e-9ef1-4d8703c41883.png)


ファイルのアップロード先に限らず、ファイルが見つからないときは、`ActiveStorage::FileNotFoundError` が発生するようになっています。 ファイルが見つからない場合のエラーを `rescue` したいときには、何も考えずに `ActiveStorage::FileNotFoundError` を指定しておけば良いので、便利ですね。

# ソースコード

試したソースは以下にあります。
https://github.com/suketa/rails6_0_0rc1/tree/try020_active_storage_missing_file

# 参考情報

* [What is new in Rails 6.0](https://bogdanvlviv.com/posts/ruby/rails/what-is-new-in-rails-6_0.html)
* [Fail more gracefully from ActiveStorage missing file exceptions](https://github.com/rails/rails/pull/33666)
素因数分解をPHPでやってみた

#はじめに
私は、現在大学４回生です。
未来電子テクノロジーのインターンでプログラミング開発コースに所属しています。
今回は、アルゴリズムの勉強中にひっかかった素因数分解についてお話しします。

プログラミング初心者であるため、内容に誤りがあるかもしれません。
もし、誤りがあれば修正するのでどんどん指摘してください。

#素因数分解とは
素因数分解は、自然数を素数で表すことを示します。
（素数は、１とその数でしか割れない数字のことを言います）

例）
　２０　＝　２　×　２　×　５
　６３　＝　３　×　３　×　７
　３２　＝　２　×　２　×　２　×　２

このように素数が並びます。

#PHPで実装
PHPでのコードは、以下のものです。

```php
function pf($n){
 $result = array();
 if($n===1){
     return [1];
 } 
  $init = 2;
 while($n! == 1){
  $i = $init;
   while($i < 0 *FFFFFF){
     if($n%$i == 0){
        $result[] = $i;
     break;
 }
 $i++;
}
 $init =$i;
}
return $result;
}
```

#まとめ
今回は、素因数分解についてお話ししました。
whileが2回入ってくるあたりや、変数がどこからくるのかが初め理解できませんでした。
コードは、理解してこそ自分のものになると思います。

#参考文献
http://sevendays-study.com/algorithm/pr-day7.html
「一週間で身につくアルゴリズムとデータ構造」
Genymotionのemulatorがネットワークに繋がらない 

# はじめに
最近、expoを用いてクロスプラットフォームにアプリ開発を行っています。
その中でandroidで動作確認を行うのにGenymotionを使っているのですが、emulatorが全然ネットワークにつながってくれなかったのでその解決方法について書きます。

# Genymotionとは
ここでは詳しく説明しませんが、Android StudioのAVDよりも高速に動くemulatorです。Virtual Box上で動きます。
個人利用であれば無料でで使えます。
詳細は[こちら](https://www.genymotion.com)

# 問題
全然ネットワークにつながってくれない。

GenymotionもしくはVirtual Boxのネットワークの設定が間違っているのでしょうが、どこをどういじればいいかわからず、とりあえずググッて出てきた解決策を試してみました。
実際にこれらを試してみましたが、だめでした。
https://stackoverflow.com/questions/33075796/genymotion-emulator-no-internet-connection
https://qiita.com/shymst/items/1bb60ca0c8a020ce6bc2

# 解決策
Virtual Boxの設定でNATネットワークを作成するとネットワークに繋がりました。

- Virtual Boxの設定 >> ネットワーク
- NATネットワークの追加（設定はデフォルトのまま）
- emulator起動
- wifiつながった

参考： https://stackoverflow.com/a/36151812

# さいごに
たったこれだけのことでしたが、仮想環境でのネットワークについての理解がまったくないのでめちゃくちゃ時間がかかりました。
これを期に仮想環境、ネットワーク周りの勉強をしようと思います。
git rebase i コミットを編集する

最近 `git rebase -i`がの便利な機能を知ったのでメモとして残します。

## 今の `git log`の状態
```
commit cd8a4309b4e196d3fc169f10b708197c48898346
Date:   Tue May 21 09:01:15 2019 +0900

    file modified

commit f9d702a3c0f6188c780609270da917aa174d858a
Date:   Tue May 21 08:59:14 2019 +0900

    modified file

commit 321f711dc4a590fd27721523d53a69353e9daf76
Date:   Tue May 21 08:58:42 2019 +0900

    created file
```

## 1つ目と2つ目のコミットをまとめたい。
```
git rebase -i HEAD~2
```

すると以下のようなvimが立ち上がります。

```
pick f9d702a modified file
pick cd8a430 file modified
```

ここで以下のようにすると

```
pick f9d702a modified file
s cd8a430 file modified
```

こんな感じでコミットメッセージを編集する画面が表示されます。

```
# This is a combination of 2 commits.
# This is the 1st commit message:

modified file

# This is the commit message #2:

file modified
```

しかし、こんな感じにすると

```
pick 0f1e189 modified file
f b470369 third commit
```

`pick`されたコミットのメッセージが残ります。
少しだけ時短
AndroidのFragmentでOverlayViewを表示する

# Solution

```res/layout/partial_overlay.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/overlay_screen_bg">

    <!-- クリックイベントをセットするためのView -->
    <View
        android:id="@+id/view_bg"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent" />
   
...
</androidx.constraintlayout.widget.ConstraintLayout>
```

```HogeFragment.kt
class HogeFragment : Fragment() {

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        showOverlayView()
    }

    private fun showOverlayView() {
        // activityのrootを取得
        val rootLayout = requireActivity().findViewById(android.R.id.content) as FrameLayout
        // overlayViewを表示
        val overlayView = View.inflate(requireActivity(), R.layout.partial_overlay, rootLayout)

        // view_bgをタップしたら非表示にする
        overlayView.view_bg.setOnClickListener {
            rootLayout.removeViewAt(rootLayout.childCount - 1)
        }
    }
}
```

# 参考

https://stackoverflow.com/questions/14194967/android-addview-adding-a-new-view-on-top-of-activity
Surgeを使ってページを公開してみる

## Surgeとは
コマンドを打つだけで簡単に自分のHTMLを公開できるツール
[Surge](https://surge.sh/)

## Surgeを使うために必要なもの
* Homebrew
* Node.js

## 導入手順
### 1. Homebrewインストール
SurgeのインストールにはNode.jsというものが必要だが、Node.jsのインストールにはHomebrewを使うのが手っ取り早いので、インストールする
PC画面の右上にある虫眼鏡を押す
<img width="38" alt="スクリーンショット 2019-05-20 16.34.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18699/90a491bd-85e5-ae85-dbd6-00c494313d87.png">
検索フォームが出てくるので`ter`と打つとターミナルアプリが出てくるので、選択して起動
<img width="1033" alt="スクリーンショット 2019-05-20 16.37.01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18699/fcb3b995-03d0-5cbe-f825-4b45052a25f4.png">

Homebrewの[公式ページ](https://brew.sh/index_ja)通り、以下コマンドをコピペしてターミナルに貼り付けて、エンターキーで実行

```bash
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```

### 2. Node.jsインストール
以下コマンドを実行

```bash
brew install node
```

### 3. Surgeインストール
[Surge公式ページ](https://surge.sh/)に書いてあるとおり、以下コマンドを実行

```bash
npm install --global surge
```

以下コマンドを打って何かしら数字が出てきたらインストール完了

```bash
surge -V
例）0.19.0
```

### 公開
公開したいHTMLがあるフォルダに移動して
`surge`コマンドを実行

（初回はもしかしたらアカウント登録の画面が出てくるかも）

```bash
surge
例）
    Surge - surge.sh

              email: 自分のメールアドレス@gmail.com
              token: *****************
       project path: フォルダ位置
               size: 1 files, 76 bytes
             domain: wealthy-teaching.surge.sh ←勝手にドメインが設定される
             upload: [====================] 100%, eta: 0.0s
   propagate on CDN: [====================] 100%
               plan: Free
         IP Address: 45.55.110.124

    Success! Project is published and running at wealthy-teaching.surge.sh
```
上記の場合、`https://wealthy-teaching.surge.sh/`にアクセスすると自分のサイトを見られる
Picassoで画像キャッシュを無効にする

案件でPicassoのキャッシュを無効にする事になり、ちょっと調べた情報をまとめる。

## Picassoのデフォルトの動作
Picassoのデフォルトの動作は以下
- メモリキャッシュはアプリケーションRAMの15%
- ディスクキャッシュはストレージサイズの2%で最大50MB
  - 注：これはAPI 14+で、またはOkHttpのようなすべてのAPIレベルでディスクキャッシュを提供するスタンドアロンライブラリを使用している場合にのみ利用可能
- ディスクおよびネットワークアクセス用の3つのダウンロードスレッド。

Picassoは常に最初にメモリキャッシュから画像をロードしようとする。
メモリキャッシュになければ、ディスクキャッシュをチェックする。
ディスクキャッシュもなければネットワーク処理をリクエストする。

つまり、`メモリ -> ディスク -> ネットワーク` の順にチェックする。

また、Picassoで表示する画像はメモリ/ディスクキャッシュの両方に保管される。

## キャッシュ無効
メモリキャッシュ、ディスクキャッシュを両方とも無効にする必要がある。
```java
Picasso.get()
        .load(url)
        .memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE)
        .networkPolicy(NetworkPolicy.NO_CACHE)
        .into(imageView);
```

## 参考リンク
- Picasso — Influencing Image Caching https://futurestud.io/tutorials/picasso-influencing-image-caching
- Picassoでキャッシュの簡単設定 - Qiita https://qiita.com/hoonokonoko/items/fc4a16bf187faf39979a
Go言語の環境を作ってみた（GinでHTTPサーバー構築）

最近、Go言語の話題をちょこちょこ見かけるので、環境を作ってみました。

# 環境
- Windows＋VirtualBOX＋Vagrant
- ゲストOS：CentOS7

# 環境構築
## Windows側作業
- 以下のVagrantfileを作成し、`vagrant up`を実行

```Vagrantfile
Vagrant.configure("2") do |config|
  config.vm.box = "centos/7"
  config.vm.network "private_network", ip: "192.168.33.20"
end
```
- 立ち上がったら`vagrant ssh`でVMにSSH接続

## ゲストOS（CentOS）側作業
※Vagrantfileでまとめればよかった。。。

- `yum update`
- `sudo yum install git`（後述のGinのインストールに必要）
- Goのインストール（[参考](https://golang.org/doc/install#tarball)）

```
$ curl -OL https://dl.google.com/go/go1.12.5.linux-amd64.tar.gz
$ sudo tar -C /usr/local -xzf go1.12.5.linux-amd64.tar.gz
$ export PATH=$PATH:/usr/local/go/bin
```

- Hello Worldしてみる([参考](https://golang.org/doc/install#testing))

```
$ mkdir hello-world
$ cd hello-world/
$ sudo vi main.go
$ go build
$ ./hello-world
```

```main.go
package main

import "fmt"

func main() {
	fmt.Printf("hello, world\n")
}
```

↓↓↓結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/b666bbb9-afbb-e5b1-df6e-ddb798935082.png)


# HTTPサーバーとして起動してみる

- [Gin](https://github.com/gin-gonic/gin)のインストール
 
```
$ go get -u github.com/gin-gonic/gin 
```

- Ginの[QuickStart](https://github.com/gin-gonic/gin#quick-start)に従ってmain.goを改修

```main.go
package main

import "github.com/gin-gonic/gin"

func main() {
	r := gin.Default()
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})
	r.Run() // listen and serve on 0.0.0.0:8080
}
```

- 再ビルド


```
$ go build
$ ./hello-world
```

↓↓↓サーバー起動
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/207a70d4-1af6-e1f8-01c3-0aeb4284db86.png)


- Windows側でブラウザから「[http://192.168.33.20:8080/ping](http://192.168.33.20:8080/ping)」にアクセス

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/0e5b6485-2036-cfb7-9342-d53897a880f9.png)
→ちゃんとアクセスできてる


↓サーバーサイドのログ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325108/a631ec55-cec1-8359-e266-7fb63a84fff9.png)
ログがμ秒単位なのがいかにも処理速度に自信がある感じがして良いですね(笑)
(Ruby)ハッシュについて(備忘録)

#ハッシュ#
<p>・連想配列と言われ、キーワードで取り出すデータをもとめる仕組み<br>・<strong>Webサイトのユーザー管理</strong>などに使われる</p>

<P>型）</p>

```ruby:qiita.rb
{key1 =>value1 , key2 => value2 ・・・・・ }
```
<p>例）</p>

```ruby:qiita.rb
money = {"tom" => 400 , "ken" => 500 , ・・・・・}
user = {"name" => "tom" , "age" => "16" , "birthday" => "12/2" ,　・・・・・・}
```

<p>ハッシュのデータの取り出し方</p>

```ruby:qiita.rb
money["tom"]
=> 400
user["name"]
=>"tom"
```
#シンボル#
<p>""や''と同じように扱える文字列オブジェクトのこと<br>
シンボルは<strong>keyにのみ</strong>使う</p>

<p>型）</p>
```ruby:qiita.rb
:シンボル名
```
<p>例）</p>
 ``````ruby:qiita.rb
:tom
```
<p>注意・・・文字列と全く同じではないため、基本的に英文字のみで作り、_（アンダーバー）などは使用しない</p>

##シンボルを使ったハッシュの作り方##

```ruby:qiita.rb
user = {:name => "tom" , :age => "16" , :birthday => "12/2" ,　・・・・・・}

user = {name: "tom" , age: "16" , birthday: "12/2" ,　・・・・・・}
```
<p>データの取り出し方</p>

```ruby:qiita.rb
user[:name]
=> "tom"
```
<p>注意・・・name:となっていても、取り出すときは:nameにしなければ取り出せない</p>

#ハッシュの繰り返し処理#
<p>型）</p>
```ruby:qiita.rb
ハッシュ.each do |変数１,変数２|
　　繰り返したい処理
end
```
<p>メモ）<br>
変数１はkey、変数２はvalueのこと<br>
ハッシュはkey用とvalue用の２つの変数が必要</p>

<p>例）</p>

```ruby:qiita.rb
pet = {tom: "dog" , ken: "cat" , gai: "tiger"}

pet.each do |key , value|
puts "#{key} は #{value} を飼っています"
end

=>
tom は dog を飼っています
ken は cat を飼っています
gai は tiger を飼っています
```
<p>補足）変数は型と比較するためkeyとvalueにしましたが、実際はわかりやすい変数（nameやanimal）にする</p>

#まとめ#
##ハッシュの書き方##
```ruby:qiita.rb
{"one" => "1" , "two" => "2" ,・・・・・ }

{:one => "1" , :two => "2" ,・・・・・ }

{one: "1" , two: "2" ,・・・・・ }
```
###ハッシュの繰り返し処理#
```ruby:qiita.rb
ハッシュ.each do |変数１,変数２|
　　繰り返したい処理
end

pet.each do |key , value|
puts "#{key} は #{value} です"
end
```

<p>参考</P>
[【七海有里佳とRubyの基礎】Lesson10 配列と似て非なるもの－ハッシュ](https://www.youtube.com/watch?v=6-aUJl6vveo&t=606s)
Goで使うべきでない文法 - from:GothamGo 2018 - Things in Go I Never Use by Mat Ryer -

# 概要

この記事は、2018年のGothamGoのMat Ryerさんのtalkの動画のサマリーになります
[GothamGo 2018 - Things in Go I Never Use by Mat Ryer](https://www.youtube.com/watch?v=5DVV36uqQ4E&t=914s)

この動画では、主に、「Goで可読性の高いコードを書く上で使わない文法」について具体的なポイントを挙げて話しているので、それらのまとめとなります。

# まとめ

### elseはできるだけ使わない
Goでは、Happy Path(正常系)は左端に寄せて（関数内でインデントをしない）で書いて、エラーハンドリングなどのその他のケースのみインデントするという書き方が好ましいとされている。
なので、異常系のみ都度`if`節で処理して、正常系はネストの中には入れないようにする。
そうすると、必然的にelseを使わないといけないケースは限られてくる。
動画内でも紹介されているリンク: [Code: Align the happy path to the left edge](https://medium.com/@matryer/line-of-sight-in-code-186dd7cdea88)

```go
// bad 
if ok {
  err := something()
  if err != nil {
    return errors.Wrap(err, "something")
  }
  // do more great things
} else {
  return errors.New("not ok")
}

// good
if !ok {
  return errors.New("not ok")
}
err := something()
if err != nil {
  return errors.Wrap(err, "something")
}
// do more great things
```

### labelは使わない
処理の流れが把握しづらくなるため。

### gotoは使わない
処理の流れが把握しづらくなるため。

### arrayは使わない
`slice` を使えばメモリの細かい挙動を考えずに複数のarrayを内部で作ってくれるので、厳密なメモリ最適化をしたい場合でもなければ、`slice` で事足りる。

### newは使わない
`&type{}`みたいに直接オブジェクトを初期化すれば事足りる。

### panicはそのままでは使わない
`error`を使う。

ただし、下記のように、既存のpanicをカスタマイズして使う場合は有意義なものとなる。

```go

func (t *Greeter) Greet1(name string) {
        // Speakerがnilの場合に、下記の既存のpanicが起きる
        // "invalid memory address or nil pointer dereference"
	return t.Speaker.Speak("hello" + name)
}

func (t *Greeter) Greet2(name string) {
	if t.Speaker == nil {
		panic("greeter: cannot call Greet with nil Speaker")
	}
	return t.Speaker.Speak("hello" + name)
}

```

### Structを初期化するときはfield名も明示する
それぞれの値がなにを表すのかわかりづらいため。

```go
// bad
// どっちが緯度でどっちが経度かわからない
pos := &Position{40.712772, -74.006058}

// good
pos := &Position{
	latitude:  40.712772,
	longitude: -74.006058,
}
```

### 冗長なレシーバ付き関数の呼び出しはしない


```go
type Greeter struct {
	Format string
}

func (g Greeter) Greet(name string) { fmt.Println("hello", name) }

func main() {
	g := Greeter{}
	Greeter.Greet(g, "Mat") // bad

	g.Greet("Mat") // good

}
```

# 最後に
さっと振り返れる用にまとめとして書いたもののこの動画自体そこまで長くなく、また前半では「そもそもGoにおける良いコードとは」という話もしており、冗談も交えつつで話も面白いので、もし英語に抵抗がなければ動画を全部実際に見てみることをおすすめします。