OmniAICreator/Qiita-1.07M huggingface dataset:
[kubernetes]masterノードにpodを配置できるようにする

##概要
kubernetesでは、デフォルト設定でmasterノードにはpodを配置できないようになっているようです。


手元の検証用環境のためリソースが十分に無く、masterノードでもpodを作成できるようにしてリソースを節約したいことがありました。
そこで、以下の作業を実施したので、記録として残しておきます。

##現在の状況
・バージョン

```
vagrant@master:~$ kubectl version
Client Version: version.Info{Major:"1", Minor:"14", GitVersion:"v1.14.1", GitCommit:"b7394102d6ef778017f2ca4046abbaa23b88c290", GitTreeState:"clean", BuildDate:"2019-04-08T17:11:31Z", GoVersion:"go1.12.1", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"14", GitVersion:"v1.14.2", GitCommit:"66049e3b21efe110454d67df4fa62b08ea79a19b", GitTreeState:"clean", BuildDate:"2019-05-16T16:14:56Z", GoVersion:"go1.12.5", Compiler:"gc", Platform:"linux/amd64"}
```
・masterノードの確認

```
vagrant@master:~$ kubectl describe node master
︙
Taints:             node-role.kubernetes.io/master:NoSchedule
︙
```

##コマンド実行
masterノードにpodを配置できるようにする。
**コマンドの最後の「-」を忘れないようにします。**

```
vagrant@master:~$ kubectl taint nodes master node-role.kubernetes.io/master:NoSchedule-
node/master untainted
```

##結果確認
Taintsがnoneになっていれば成功です。

```
vagrant@master:~$ kubectl describe node master
︙
Taints:             <none>
︙
```

##補足
逆にmasterノードへpodを配置できないようにする場合は以下を実行します。

```
vagrant@master:~$ kubectl taint nodes master node-role.kubernetes.io/master=:NoSchedule
node/master untainted
```
`NoSchedule`部分はeffectと呼ばれており、全3種類から選択が可能です。

[Taints and Tolerations](https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/)から引用(2020/05/07)
>・if there is at least one un-ignored taint with effect **NoSchedule** then Kubernetes will not schedule the pod onto that node
・if there is no un-ignored taint with effect **NoSchedule** but there is at least one un-ignored taint with effect **PreferNoSchedule** then Kubernetes will try to not schedule the pod onto the node
・if there is at least one un-ignored taint with effect **NoExecute** then the pod will be evicted from the node (if it is already running on the node), and will not be scheduled onto the node (if it is not yet running on the node).

また、今回は実施していませんが、PodSpecに`tolerations`行を追加することで、podごとに各ノードへの配置可能不可能を設定できます。(上記のリンクを参照)

##参考
・Qiita記事
[KubernetesのTaintsとTolerationsについて](https://qiita.com/sheepland/items/8fedae15e157c102757f)
[KubernetesのTaint / Tolerationの使い方](https://qiita.com/Esfahan/items/843845bdbfefd8ea46d2)
・公式ドキュメント
[Taints and Tolerations](https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/)
[Control plane node isolation](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/#control-plane-node-isolation)
MDB-SQLite のインストールと変換メモ

# はじめに

MDB-SQLiteはMS Access（mdb）をSQLiteにコンバートするソフトウェアです。
Java製のオープンソース・ソフトウェア（New BSD License）です。
インストールするにはJava以外にAntが必要です。
ビルドに際してトラブったので備忘を兼ねて記載します。

## インストール手順

###1. [Java]
(https://www.oracle.com/technetwork/jp/java/javase/downloads/index.html)をインストールします。

###2. [Apache Ant](http://ant.apache.org/bindownload.cgi)をダウンロードします。  

 2020年5月7日時点の最新はapache-ant-1.10.7でした。
 適当な位置にコピーします。（私はD:\apache-ant-1.10.7に）
 ここで環境変数 "ANT_HOME" にapache-ant-1.10.7のパスを設定します。
 ついでに "PATH" 環境変数に %ANT_HOME%\bin を設定しておきます。

###3. [mdb-sqlite](https://code.google.com/archive/p/mdb-sqlite/downloads)をダウンロードします。

 適当な位置にコピーします。（私はD:\mdb-sqlite-1.0.2に）

###4. mdb-sqliteをビルドします。  

~~~
> cd D:\mdb-sqlite-1.0.2  
> ant dist
~~~
<font color="Red">**とここでエラーが！！！**</font>

~~~

Buildfile: D:\mdb-sqlite-1.0.2\build.xml

prepare:

compile:
    [javac] D:\mdb-sqlite-1.0.2\build.xml:45: warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds

BUILD FAILED
D:\mdb-sqlite-1.0.2\build.xml:45: Unable to find a javac compiler;
com.sun.tools.javac.Main is not on the classpath.
Perhaps JAVA_HOME does not point to the JDK.
It is currently set to "C:\Program Files\Java\jre1.8.0_211"

Total time: 0 seconds
~~~
ここでは２つのエラーがあって、
前半の `[javac] D:\mdb-sqlite-1.0.2\build.xml:45: warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds`の部分はMDB-SQLiteのAnt1.8以降に発生する問題で、build.xmlを修正すれば解決します。

~~~xml
<target name="compile" depends="prepare">
    <javac srcdir="${src.dir.java}" destdir="${classes.dir}" source="1.5" target="1.5" includeantruntime="false">
        <classpath>
            <path refid="classpath"/>
        </classpath>
    </javac>
</target>
~~~
`includeantruntime="false"`の部分を追加します。
クラスパスにAntのランタイムライブラリを追加するかどうかの設定らしく、デフォルトでTrueとのこと。Ant1.8以降でこいつをFalseにしないと警告が出るらしい。ググったらいろんなサイトで言ってるけどデフォルトをFalseにしてほしい。

根本的なビルドエラーは`BUILD FAILED`以降の部分でエラー内容を見ると環境変数 "JAVA_HOME" がJDKを指していないじゃないかとのこと。
環境変数 "JAVA_HOME" を設定して、ついでに "PATH" 環境変数に %JAVA_HOME%\bin を設定して解決です。
（ただし、%ANT_HOME%\binより後にあるとエラーとなるような記事を見たので注意です。）

~~~
Buildfile: D:\mdb-sqlite-1.0.2\build.xml

prepare:

compile:
    [javac] D:\mdb-sqlite-1.0.2\build.xml:45: warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds

dist:
  [one-jar] main.jar fs=main.jar
  [one-jar] Building jar: D:\mdb-sqlite-1.0.2\dist\mdb-sqlite.jar
  [one-jar] No 'manifest' attribute was specified for the <one-jar> task, a default manifest will be generated.

BUILD SUCCESSFUL
Total time: 0 seconds
~~~

# 変換
参考までにサンプルでついているMDBファイルをSQLiteに変換してみます。

~~~

> java -jar dist\mdb-sqlite.jar example\test-database.mdb test-database.sqlite
~~~
test-database.sqlite が作成されています。
![MDB-SQLite1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390406/9d256659-e7cc-af9a-c396-f2899578946a.png)

データも無事変換されてます。
![MDB-SQLite2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390406/92a6f09e-160c-5bd5-a962-6f93f3caa718.png)
データローダでオブジェクト権限一括設定

#はじめに
変更セットで新しいプロファイルをリリースする時、オブジェクト権限は自動で反映されますか？
いいえ、新しいプロファイルをリリースするだけでオブジェクト権限は反映されません。
権限を設定したオブジェクトも一緒に変更セットに含める必要があります。

では新しいプロファイルだけ変更セットでリリースした場合はどうなるのか？
オブジェクト権限は全て空になってしまうのか？
いいえ、空になるのではなく、「対象組織のライセンス種別に対応する標準プロファイルで定義されている、現在のオブジェクトレベルアクセスを継承」されます。
要するに、勝手に設定されます。
詳しくは[コチラ
](https://help.salesforce.com/articleView?id=000332644&language=ja&mode=1&type=1)

でも、「Sandboxと本番環境に差分があるから、オブジェクトは変更セットに入れたくない！」
なんてことありますよね？

そんな時に役立つのが、データローダでオブジェクト権限一括設定です。
変更セットで新しいプロファイルリリースした後、
この作業を行えばオブジェクトをリリースすることなく権限を設定出来ます。

# 材料調達
1. 開発者コンソールでSandboxのプロファイルIdを取得

    権限セットオブジェクトからプロファイルIdを取得します。
    なぜ権限セットオブジェクトかというと、オブジェクト権限オブジェクトの親が権限セットオブジェクトだからです。
    詳しいデータモデルが気になる方は[コチラ](https://developer.salesforce.com/docs/atlas.ja-jp.api.meta/api/sforce_api_erd_profile_permissions.htm)

    ```
    SELECT Id FROM PermissionSet WHERE Profile.Name = 'プロファイル名'
    ```
2. 開発者コンソールで本番環境のプロファイルIdを取得

    ```
    SELECT Id FROM PermissionSet WHERE Profile.Name = 'プロファイル名'
    ```
3. データローダで取得したプロファイルIdをキーにSandboxからObjectPermissionを取得

    ```csv:extract_sandbox_objectPermission.csv
    SELECT Id, Name, ... FROM ObjectPermission WHERE ParentId = 'SandboxプロファイルId'
    ```
4. データローダで取得したプロファイルIdをキーに本番環境からObjectPermissionを取得

    ```csv:extract_prod_objectPermission.csv
    SELECT Id, Name, ... FROM ObjectPermission WHERE ParentId = '本番プロファイルId'
    ```

# 下準備
1. データ整形する用のエクセルファイルを新規作成
2. 材料3.4を1の整形用エクセルファイルにぶちこむ
3. 材料3シートを開く
4. すべてのParentIdを本番環境プロファイルIdに変更する
5. IdをSOBJECTTYPEをキーに本番環境のIdに置き換える

    本番環境にIdがない場合はInsertするので空欄にしておきます。
    オブジェクト権限が何も設定されていない場合、通常ObjectPermissionのレコードは作成されていません。
    （例：Accountのオブジェクト権限何もなしの場合、SObjectType=Accountのレコードは存在しない）

    ```
    =IFERROR(VLOOKUP(J2,extract_prod_objectPermission!C:D,2,FALSE),"")
    ```

6. 材料4シートを開く
7. 本番環境のみに存在するレコードを探す
    Sandboxではオブジェクト権限を設定していないのに、勝手にオブジェクト権限を設定されているレコードを探します。
    列を一つ追加して以下の関数をぶちこんで判定します。

    ```
    =COUNTIF(extract_sandbox_objectPermission!N:N,extract_prod_objectPermission!O5)
    ```
8. 7の関数で値が０のレコードの以下の項目を全てFALSEにする
    余計な権限が付いている状態なので、全ての権限をなくす
    - PERMISSIONSCREATE
    - PERMISSIONSDELETE
    - PERMISSIONSEDIT
    - PERMISSIONSMODIFYALLRECORDS
    - PERMISSIONSREAD
    - PERMISSIONSVIEWALLRECORDS
9. 材料３シートに8のレコードを全てくっつける
10. 最終的にこんな感じになる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588573/e64fb7eb-5a22-27b2-b2ce-494e112f876c.png)
11. 材料３シートをコピーしてUpsert用CSVを作成


# 調理
1. データローダでUpsertを選択
2. オブジェクト権限（ObjectPermissions）を選択
3. Upsert用CSVを選択
4. キー項目はIdを選択
5. Upsertを実行
6. 完成！

# 補足
今回はオブジェクト権限の一括設定を解説しましたが、項目レベルセキュリティも同じような手順で設定出来ます。
【Pythonista3を使ったみた】自作モジュールのインポート

#モジュールって？
モジュールとは、Pythonの定義や文が入ったファイルのことです。
（ファイル名の接尾語に`.py`がついたものです）
以下のファイルもモジュールとして扱えます。

```python:HelloWorld.py
print( “HelloWorld” )
```
#インポートって？
例として標準ライブラリの`os`モジュールをインポートする。

```python:import_test.py
import os
print( type( os ) )
# <class ‘module’>
print( os.getcwd() )
# /private/var/mobile/Library/Mobile Documents/iCloud~com~omz-software~Pythonista3/Documents/Test

```
以上のように`import <モジュール名>`とするとインポートできます。
モジュールは`module型`のオブジェクトとしてインポートされます。

#自作モジュールのインポート
**ディレクトリ**
>- iCould
    - Test
        - MyFunc
            - MyCalc.py
       - MyCalcTest.py

以上のようなディレクトリで進めていきます。
`MyCalcTest.py`で`MyCalc.py`モジュールをインポートして
`MyCalc.py`モジュールの関数を使ってみます。

```python:MyCalc.py
'''
自作計算モジュール
'''
def sum ( v1, v2 ) :
	'''
	加算
	'''
	return v1 + v2
	
def sub ( v1, v2 ) :
	'''
	減算
	'''
	return v1 - v2
```

```python:MyCalcTest.py
import MyFunc.MyCalc

v1 = 10
v2 = 5

res1 = MyFunc.MyCalc.add( v1, v2 )
print( "%d + %d = %d" %( v1, v2, res1 ) )
#>> 10 + 5 = 15

res2 = MyFunc.MyCalc.sub( v1, v2 )
print( "%d - %d = %d" %( v1, v2, res2 ) )
# 10 - 5 = 5
```

こんな感じで`MyCalc.py`モジュールの関数が使えました。

#自作モジュール内に関数の簡易アクセス
`MyFunc.MyCalc.add`とか毎回書くの面倒ですよねー。

##オブジェクトをインポート
###オブジェクト指定
`from <モジュール名> import <オブジェクト名>`でオブジェクトをインポートできます。

```python:import_test.py
from MyFunc.MyCalc import add, sub

v1 = 10
v2 = 5

res1 = add( v1, v2 )
print( "%d + %d = %d" %( v1, v2, res1 ) )

res2 = sub( v1, v2 )
print( "%d - %d = %d" %( v1, v2, res2 ) )
```
###すべてのオブジェクト
ワイルドカード`*`を使うことですべてのオブジェクトがインポートできます。

```python:import_test.py
from MyFunc.MyCalc import *

v1 = 10
v2 = 5

res1 = add( v1, v2 )
print( "%d + %d = %d" %( v1, v2, res1 ) )

res2 = sub( v1, v2 )
print( "%d - %d = %d" %( v1, v2, res2 ) )
```

#結論
ディレクトリ階層によってはインポートするパス名が長くなるので
そのまま使うのではなく、オブジェクト指定する方が良い。
ワイルドカードはとても楽に使えるのが名前空間に存在しているか
不明なため控えるようがいいかも。
let'sプレゼンテーション【備忘録】

##前書き
Webディレクターを目指しているので人の前で説明する機会もあるでしょう。ということでプレゼンについて少し勉強してみました。
ちなみにもちろん人見知りのあがり症なので学生時代からプレゼンにいい思い出はありません意図的に記憶から葬り去りました。はい。。

##準備が大事
準備を制すものがプレゼンを制すというのはゴリも仰っていましたが、その通りだと思いました。
プレゼンも面接も飲み会のあいさつだって練習しとけば怖くないんですよね。
練習と言ってもただあらかじめ発表内容を覚える（もちろんこれも大事）だけではなく、トークの**テーマについて深い理解を持っておくことが大切です**。

##眠くならないプレゼンを
まず大体のプレゼンは眠くなりますねはい。聴衆がそうなってしまってはそのプレゼンは失敗です。
眠眠打破のポイント下記にまとめました。
**①シンプルに詰め込みすぎない**
**②デザインはモダンで**
**③自然さ**
**④質問の余地を与える（規模にもよる）**

まず①シンプルにということですが、スライドもトークも情報量が多すぎると眠くなりますねそういうことです。④の質問の余地を与えるにつながってくるのですが、必要最低限の重要項目だけで伝えてあとは質問してきたら対応という程度でも問題ないですね。準備ができていれば質問には答えられるでしょう。

②のデザインはモダンでも一番ではないですが大事なポイントですね。視覚からの情報量は大事です。まずは興味を持たせましょう。

③これが一番難しそうだと思いました。特に私のようなあがり症には、、
ただこれが最も重要なことのようにも思いました。スライドやデータは完全なものを用意しますが**トークは完璧じゃなくてよい**のです。日常に近い形でコミュニケーションを取ることが聴衆とプレゼンターの境をなくし発表に入り込むきっかけとなります。これには準備が必要で、趣味を友人と語る時のようにテーマについて深い理解を持つことが大事となるでしょう。

④質問の余地を与えるというのはなかなか高等技術なのではないでしょうか。聴衆は疑問を持つことで脳が活性化しますし興味を持ち、後のコミュニケーションの機会にもなります。まただらだらとしてかつ難しい説明を省けるのでこれは①と合わせて有効に使っていきたいテクニックですね。

##まとめ
いろんなプレゼン方法があるとは思いますが、私が今後意識していきたいなということを一言でまとめると、**テーマについて事前に深い理解をした上でシンプルにまとめて話す**です。
プレゼン苦手人達、人間は慣れる生き物なのでこれから一緒に慣れていきましょう！
routesに関してうろ覚えだったので復習

# routesで定義できること
受け取ったurlを認識して、適切なcontrollerアクションにつなげる。

## 複数のルーティング間で共通の動作として定義
concern :exanple do
  resources :rei
end

resources :aaa, concerns: :example

⇨
resources :aaa do
  resources :rei
end

### ネストされてるrouteで同時にコントローラーにパスを送る書き方

<%= link_to 'title', a_b_path(@a, @b) %>
<%= link_to 'title', url_for([@a, @b]) %>

また調べたら追記していきます。
AWSのALBでヘルスチェックで詰まった話

#はじめに
　今回はALBのヘルスチェックが通らず、ルーティングに苦戦した時の対処を備忘録として記事にします。結論から言うと、インスタンス側の設定が原因でした。途中までチームメンバーが担当して用意していたものを引き継いで問題解消したので、前提となる環境からメモしておきます。

#環境
- ALBはパブリックサブネットに配置
- ターゲットのインスタンスはプライベートサブネットに配置
- ターゲットインスタンスはRHEL8のEC2
- EC2はインスタンスを立ち上げたあと特に操作なし
- 後々アプリをデプロイするための環境を整える作業中

#確認したこと
 - ALBやEC2インスタンスのSG（セキュリティグループ）の設定
 - リスナーの設定
 - ヘルスチェックの設定
 - SELinuxの設定
 - httpdのステータス
 - index.htmlの存在

　ヘルスチェックを正常化するために上記の6点を確認しました。そのうち原因は下3つ、つまるところEC2インスタンス側の設定が悪さをしていたので説明をします。
　上3つの観点はAWS公式のユーザーガイドを中心に調べればすぐわかると思うのでここでは割愛します。

#SELinuxの設定
　「SELinux、完璧に理解した」といえるほど自分自身これについて理解しているわけではないのですが、一言でいうと「ファイアウォールのような役割」をしているものです。AWSのRHEL8イメージでは初期設定でSELinuxが有効化されています。これが原因でALBのヘルスチェックに403エラーが返されていたと推測しました。
##対処
　今回はAWS側でトラフィックの制御もしていることから、SELinuxは無効化しました。エディタで`/etc/selinux/config`を編集します。

```
<前略>
SELINUX=disabled
<後略>
```

編集がすんだらAWSのコンソールを開いてインスタンスを再起動します。念のため再起動後に`getenforce`コマンドで無効化されていることを確認してください。

```
# getenforce
Disabled
```

#httpdのステータス
　要はサーバーが立っているか、ヘルスチェックをしたいポートがListenしているかということです。ヘルスチェックでpingを送ってもインスタンス側で受け取れなかったらそりゃunhealthyになります。
##対処
まずはApacheが起動しているか`systemctl status httpd`あたりを入力して確かめます。deadとか書かれていれば起動していません。その場合は`systemctl start httpd`と入力して起動しておきましょう。
　続けてポートでListenしているか確認します。RHEL8インスタンスは立ち上げたてでは`lsof`コマンドは使えません。なのでインストールします。今回は80番ポートを使うのでこれを例に一連のコマンドを記載します。

```
# dnf install lsof -y
# lsof -i:80
COMMAND  PID   USER  FD  TYPE  DEVICE  SIZE/OFF  NODE  NAME
httpd   1234   root  4u  IPv6   12345       0t0   TCP  *:http (LISTEN) 
httpd   1245 apache  4u  IPv6   12345       0t0   TCP  *:http (LISTEN)
httpd   1256 apache  4u  IPv6   12345       0t0   TCP  *:http (LISTEN)
httpd   1267 apache  4u  IPv6   12345       0t0   TCP  *:http (LISTEN)
```

　このような表示になればApacheが起動して80ポートをListenしていることになります。

#index.htmlの存在
　地味に忘れがちです。今回は特段アプリをデプロイしているわけでもなく、とりあえずWebサーバーをたててルーティングしておくのが目的だったので、コンテンツは何も置いていなかったようです。普段のブラウザでの挙動をイメージしてもらえればわかりやすいと思います。アクセス先になにもコンテンツがなければ帰ってくるのは「404 Not found」のメッセージです笑
##対処
　Apacheのドキュメントルート（デフォルトなら`/var/www/html`）にindex.htmlを置くだけです。中身はHelloWorldでもなんでも良いです。

#まとめ
　今回はEC2インスタンスに対するALBのヘルスチェックが通らない場合の原因とその対処を、EC2側の設定に焦点を当ててまとめました。単純ゆえに見落としやすいものかもしれません。
mac+vscodeで新規ウィンドウがタブ表示にならない時に試すこと

```settings.json
{
  "window.titleBarStyle": "native",
  "window.nativeTabs": true
}
```

これが設定されているのに、なぜかタブ表示にならない人向けです

## 手順

### macOS 11(Big Sur)以降

- システム環境設定から一般をクリック
![スクリーンショット 2020-12-30 21.45.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137148/f08bb883-b7ed-362c-ffab-7b571749658d.png)

- 「書類を開くときはタブで開く」項目を「常に」にする
![スクリーンショット 2020-12-30 21.45.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137148/fa6f16c6-5ba0-2617-0c37-88128e925c62.png)


### macOS 10.15 (Catalina) 以下

- システム環境設定からDockをクリック

<img width="671" alt="スクリーンショット 2020-05-07 18.22.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137148/8f7d893e-005d-3c67-bc0f-24c1b4061b1c.png">

- 「書類を開くときはタブで開く」項目を「常に」にする

<img width="669" alt="スクリーンショット 2020-05-07 18.23.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137148/4f1e3948-1330-a0eb-56b0-f053d3234bbc.png">

これ、いつも忘れるんだよな〜😰
Ruby公式Dockerイメージにjemallocを導入する方法

## 経緯
- Ruby公式Dockerイメージで立てたサーバで、メモリ消費量が増加してpumaが勝手に再起動してサービスが瞬断することが発生するようになった
- その対策として、メモリ領域の断片化を減らしてくれる[jemalloc](http://jemalloc.net/)を導入した

## 導入方法
以下を追記

```dockerfile:Dockerfile
FROM ruby:2.4.2

RUN apt-get update && apt-get install -y libjemalloc-dev libjemalloc2
ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2
```

※ 以前はパッケージの名前`libjemalloc1`だったが、今は`libjemalloc2`に変更になっていた

## 参考
- [Ruby with jemalloc · Issue #182 · docker-library/ruby](https://github.com/docker-library/ruby/issues/182)
- [quick branch docker build 'Unable to locate package libjemalloc1' · Issue #1422 · nghttp2/nghttp2](https://github.com/nghttp2/nghttp2/issues/1422)
本ブログへの記事移行

技術的な発信はずっと、はてなブログで行っていたのですが、、、、

やはり無料プランだと閲覧してもらう機会が少ないのでしょうかね、発信している感じがしませんでした。

ということで、過去はてなブログで投稿した記事はこちらに移していこうと思います
APP IDの取り方Parse Server Certified by Bitnamia(Swift)

今までFirebaseでしか利用してこなかったのですが、
AWSデビューしてみました😏✨

勉強でただ利用しているため、無料枠を使用したいと考え、
今回は```『Parse Server Certified by Bitnami』```
を使ってみました！！！☀️


しかし、applicationIdとclientKeyの取り方がネットで探し、やってみても
結果は

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407730/d27edb63-cbb7-488e-e471-ddfaaab4b336.png)

のように
"appId"は "myappID"と中々コードらしいものが出てきませんでした……。

結構困ったので
私のように、困っている人がもしかしたらいるかもしれないと思い、今回は記事を書いておきます。



## 1. 旧バージョンをダウンロード

1. AWS ログイン
2. インスタンスの作成
3. 『Parse Server Certified by Bitnami』を検索し、星マークの横にある【以前のバージョン】
をクリック

 <img width="1420" alt="スクリーンショット 2020-05-07 17.09.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407730/364b30f3-375d-40c1-4490-c0d9c4657dbb.png">

4.『Continue to Configuration』をクリック
5.『Software Version』選択で一番最新の　『Ubuntu』って書いてあるものを選択
<img width="816" alt="スクリーンショット 2020-05-07 17.12.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407730/5d7ee46e-1bc8-8ef4-e688-9e86069e8dc1.png">
6.『Continue to Launch』　
7.『Choose Action』で　『EC2』を選択
8.『無料枠選択』→『確認と作成』→『起動』
9.『新しいキーペアーの作成』で作成

## 2. ターミナル

（追）　```pod 'Parse'```

1.ターミナルひらいて、先ほどダウンロードしたpemを保存したところを開く。
（デスクトップなら、```cd Desktop/```)


2.サイトに戻って『接続』をクリック
<img width="275" alt="スクリーンショット 2020-05-07 17.20.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407730/423a12b2-2bca-0fcf-4698-bdfc00ba0b23.png">

3.『①と②をターミナルにコピペ』
<img width="671" alt="スクリーンショット 2020-05-07 17.25.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407730/8a654e9f-3c23-bfbb-1317-07d6e9be4c27.png">
『yes no　質問でたら（yes）を選択』

4.```cd apps/parse/htdocs/```
5.```vi server.js```
6.『appId』と『masterKey』をこれでゲット✨
<img width="389" alt="スクリーンショット 2020-05-07 17.37.43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407730/c0e70ded-0459-548c-344c-4f485d8f6c0c.png">

## 3. Xcode

ここからは　↓
https://docs.parseplatform.org/parse-server/guide/#getting-started

をみた方が分かりやすいかもです😴

<img width="702" alt="スクリーンショット 2020-05-07 17.41.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407730/22b30068-ed3f-296a-aae3-57c3843a75c8.png">

【applicationId】に先ほどの【appId】を
【clientKey】に【masterKey】
【server】に　【http://『上の２の３の❷の＠から後ろ』.amazonaws.com/parse】

## 4. Info.plist

```
<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <false/>
    <key>NSExceptionDomains</key>
    <dict>
        <key>【3のserverに書いたもの（httpsとparse省いたもの）】</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
            <key>NSExceptionMinimumTLSVersion</key>
            <string>TLSv1.1</string>
            <key>NSIncludesSubdomains</key>
            <true/>
        </dict>
    </dict>
</dict>

 ```



## 5. 成功確認

https://docs.parseplatform.org/ios/guide/

<img width="702" alt="スクリーンショット 2020-05-07 17.57.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407730/7fe7aa47-e016-f6c3-b414-b6893323b738.png">


#以上☀️
Gradleでdotenvを利用する

npmでよく利用されているdotenvをGradleでも使えないか試してみたよ。

## build.gradleに下記の記述を追加する

```
buildscript {
  repositories {
    maven {
      url "https://plugins.gradle.org/m2/"
    }
  }
  dependencies {
    classpath "co.uzzu.dotenv:gradle:1.1.0"
  }
}

apply plugin: "co.uzzu.dotenv.gradle"
```

## プロジェクトルートに.envファイルを作成する
中身は適当にこんなかんじで。

```
FOO=foo
```

## 値を取得するには
環境変数名を指定するとOptional<String>型が返ってくるので準じた方法で値を取得する。
環境変数が定義されていない場合ビルドエラーになるケースがあるので、fetchOrNull()を利用するのが良さげ。

```
env.FOO.value                     // => foo
env.fetch('FOO')                  // => foo
env.HOGE.value                    // => ビルドエラー
env.fetch('HOGE')                 // => ビルドエラー
env.fetchOrNull('FOO')            // => foo
env.fetchOrNull('HOGE')           // => null
env.fetch('HOGE', 'defaultValue') // => defaultValue
```

全ての環境変数をMapで取得するメソッド等もあります。
そのへんの詳細はプラグインのGithubを参照してください。

## 利用しているプラグイン
https://github.com/uzzu/dotenv-gradle
AWS Lambdaでネイティブライブラリを含む場合の環境

## はじめに
Pythonの依存ライブラリにおいてネイティブライブラリを使う場合は、
ビルド（pipする）する環境と、AWS Lambda側の環境を揃えておくという話は昔から聞いていました。

ただ、実際に何がどう影響してダメなのか？全然調べたこともなかったので、
ハマったついでに`pip install`で取得したライブラリを確認してみたメモです。


## Lambda実行時に発生したエラー
### エラー内容
`pyproj`という距離計算を行うモジュールを使用した場合に発生しました。  
（このエラーだけ見ても、最初は何が悪いか全然分かりませんでしたが。。。）

```python
[ERROR] Runtime.ImportModuleError: Unable to import module 'lambda_handler': cannot import name '_datadir' from partially initialized module 'pyproj' (most likely due to a circular import) (/var/task/pyproj/__init__.py)
```

### エラー発生時の環境
* ビルド側：Python3.7のDockerImage（https://hub.docker.com/_/python）
* Lambda側：Python3.8のランタイム

### エラー解消時の環境
* ビルド側：Python3.8のDockerImage（https://hub.docker.com/_/python）
* Lambda側：Python3.8のランタイム

## pyprojライブラリの中身（一部抜粋）
細かいインストールの仕組みは理解できていませんが、環境を自動的に把握して、
依存するネイティブライブラリをダウンロードしているようでした。

### ビルド環境がDockerImage Python3.7
```
pyproj
- _crs.cpython-37m-x86_64-linux-gnu.so
- _datadir.cpython-37m-x86_64-linux-gnu.so
- proj.py
```

### ビルド環境がDockerImage Python3.8
```
pyproj
- _crs.cpython-38m-x86_64-linux-gnu.so
- _datadir.cpython-38m-x86_64-linux-gnu.so
- proj.py
```

### ビルド環境がWindows Python3.7インストール（おまけ）
```
pyproj
- _crs.cp37-win32.pyd
- _datadir.cp37-win32.pyd
- proj.py
```

## さいごに
少しだけ理解というか自身の納得感が深まりました。
ただ、amazonlinuxの公式DockerImageが配布されているので、ビルド環境はそちらにすべきなのかもです。
Next.jsのローカル環境でのみ画像が表示されない

#概要

Next.js公式GitHubの[firebase Hostingのサンプル](https://github.com/zeit/next.js/tree/canary/examples/with-firebase-hosting)を使ってプロジェクトをつくったところ、publicフォルダに画像を入れてもローカル環境(npm run dev)でのみ表示されない。

#原因

フォルダ構成は以下

```
$tree -L 1 -a

/
├── .firebaserc
├── .gitignore
├── .next
├── README.md
├── firebase.json
├── firebaseFunctions.js
├── node_modules
├── package-lock.json
├── package.json
├── public
└── src

```

package.jsonをみてみると、以下のようになっていました。

```package.json
#略
  "scripts": {
    "dev": "next src/",
    "build": "next build src/",
    "start": "next start src/",
    "serve": "npm run build && firebase emulators:start --only functions,hosting",
    "shell": "npm run build && firebase functions:shell",
    "deploy": "firebase deploy --only functions,hosting",
    "logs": "firebase functions:log"
  },
#略
```

つまり、npm run devをするとsrcディレクトリ以下しか対象にしていないと言うこと。

#解決

package.jsonを以下のように変更

```package.json
#略
    "dev": "next",
#略
```

これでプロジェクトルート丸ごとローカルサーバーの対象となる。


あとは通常通りimgタグにパスを指定してあげればOK！

```
<img src="/sample_image.png" />
```
#Python基礎（#matplotlib）

環境は以前の記事で作った環境を使用しています。 → [Windows10でAnaconda python環境構築](https://qiita.com/hiwasawa/items/2d802b3471d4be1da341)
numpyの使い方に関しては以前の記事を参考にしてください。　
→ [#Python基礎（#Numpy 1/2）](https://qiita.com/hiwasawa/items/8907980293acc90c82ca) 
→ [#Python基礎（#Numpy 2/2）](https://qiita.com/hiwasawa/items/9950f7882ca67407b805)

#1.Matplotlibインポート

グラフ描画 : `pyplot`モジュールを使用
jupyter lab上で描画 : `%matplotlib inline`

```python
%matplotlib inline

import numpy as np
import matplotlib.pyplot as plt
```

```python
import numpy as np

x = np.linspace(-5, 5, num=10)  # -5から5まで10に区切る
# x = np.linspace(-5, 5) # デフォルトは50分割

print(x)
print(len(x))  # xの要素数
```
```:実行結果
[-5.         -3.88888889 -2.77777778 -1.66666667 -0.55555556  0.55555556
  1.66666667  2.77777778  3.88888889  5.        ]
10
```


#2.グラフ描画

```python
import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(-5, 5)  # -5から5まで
y = 2 * x  # xに2をかけてy座標とする

plt.plot(x, y)
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631693/a992f67d-b741-bd58-97f1-5f0edac3ccd1.png)

#3.タイトル、凡例、線のスタイル
```python
import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(-100, 100, num=1000)
y_1 = x * x.T # x.T : 1行1000列　→　1000行1列に転置
y_2 = 10 * x

# 軸のラベル
plt.xlabel("x val")
plt.ylabel("y val")

# グラフのタイトル
plt.title("Graph Name")

# プロット 凡例と線のスタイルを指定
plt.plot(x, y_1, label="y1")
plt.plot(x, y_2, label="y2", linestyle="dashed")
plt.legend() # 凡例を表示

plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631693/0a73b287-fb7d-fa64-ee58-362142642329.png)

#4.散布図

```python
import numpy as np
import matplotlib.pyplot as plt

x = np.array([1.2, 2.4, 0.0, 1.4, 1.5])
y = np.array([2.4, 1.4, 1.0, 0.1, 1.7])

plt.scatter(x, y)  # 散布図のプロット
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631693/f852d4c2-8e9e-3dee-80fa-2be1457de79b.png)


#5.画像の表示
```python
import numpy as np
import matplotlib.pyplot as plt

img = np.linspace(0, 100,num=100)  # 0から100までを100等分
print(img)
img = img.reshape(10,10) # 10 * 10　行列に変形
plt.imshow(img, "gray")  # グレースケールで表示
plt.colorbar()   # カラーバーの表示
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631693/b265af80-4c9a-ec7b-fd6f-b84d08546513.png)
[awk] 複数列の最大値、最小値


Excelで、ざーーっとドラッグして求めるのが簡単だけど、`awk`でやりたくなったのでメモ。

`shell`のforを使うのが簡単っぽそう。

# 最大値

## C-shell

```C-shell
set nf = `cat Filename | awk '{print NF}'`
foreach i (`seq $nf`)
cut -f$i Filename | \
awk '{if(max<$1) max=$1} END {printf("%f ", max)}'
end
```

これで、一応ずらっと最大値が並ぶ。
`Filename`は、ファイルの名前。

# 最小値

先ほどの`awk`の行を

```
awk '{BEGIN {min=$1} if(min>$1) min=$1} END {printf("%f ",min)}'
```

に変えるとよい。
（`BEGIN{}`は、最小値を求めるための初期値。）

つまり、

## C-shell

```C-shell
set nf = `cat Filename | awk '{print NF}'`
foreach i (`seq $nf`)
cut -f$i Filename | \
awk '{BEGIN {min=$1} if(min>$1) min=$1} END {printf("%f ",min)}'
end
```
と、なる。


他に、合計、平均などもこの方法で求められる。
awkの中身を変えれば良い。

んー、ワンライナーにならない。。
java学習（条件式）

## 関係演算子（文字列の比較）
```java
if (str == "本")　{
```
```java
if (str equals ("本"))　{
```
**上が間違い　下が正しい。**
上（ == ）でもコンパイルエラ〜は起きず、`実行できるけど時々変な動きをする`という不具合が起きる。

##論理演算子
```java
if (age >= 18 && month == 5)　{
```
年齢が１８以上、`かつ`５月生まれ

```java
if (name.equals("斎藤") || name.equals("斉藤"))　{
```
名前が斎藤、`または`斉藤

##否定演算子
```java
if(!(age >= 18)) {
```
年齢が18以上で`ない`ならば
Ubuntu20.04LTSとRancherでkubernetesを構築

Rancherでkubernetesを構築したのでその備忘録です。

## ハードウェア

 - 4X4 BOX-V1000M (¥71,017)
 - Jumper EZbox i3 (¥34,850)
 - TP-Link 5ポート スイッチングハブ (¥1,800)

## ソフトウェア

 OS: Ubuntu 20.04 LTS 
 Docker: version 19.03.8
 Rancher: Docker版 2.4.2

## 構成

マスタノード1台、ワーカー1台の構成となっています。クラスタ構成ではありません。
(本来、マスター、ワーカ共に3台以上がクラスタ構成の条件となっています）

<img width="600" alt="構成図" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105394/bb27b31a-2f25-c26e-b49c-028d92ab116c.png">


## 作成手順

### USBにUbuntu20.04 LTSのイメージを作成してインストール
ASRockの方は順調にインストールできましたが、Jumpberの方はSDカードが認識できないエラーが出続けていました。

```
mmc0: Timeout waiting for hardware cmd interrupt.
```

モジュールをメモリから落とすことで対応した。ただしPCを再起動するともとに戻ります。

```shell
sudo modprobe -r sdhci
sudo modprobe -r sdhci_acpi
```

### Dockerのインストール

```sh
sudo apt install docker.io
sudo usermod -aG docker <<アカウントID>>
```

### Rancherの導入

```sh
sudo docker run -d --restart=unless-stopped -p 80:80 -p 443:443 rancher/rancher
```

公式：（https://rancher.com/docs/rancher/v2.x/en/quick-start-guide/deployment/quickstart-manual-setup/）

### Rancherのクラスター作成

クラスターを作っていきます。オンプレ構成なのでCustomを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105394/969bec4c-05e5-d624-4e6e-17900357be6a.png)

詳細は名前以外デフォルトで決めました。

### kubernetesマスターとワーカーの作成

Clusterの作成・編集でノードの追加ができます。
etcd | Control Plane | Worker をチェックして下に表示されるコマンドをそれぞれのPCで実行するだけです。
Jumperにetcd、Control Plane。ASRockにWorkerを設定します。

![スクリーンショット 2020-05-07 17.22.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105394/22f8fd5a-9032-1d14-fee9-b1a3edb61445.png)

しばらくすると（体感10分弱？）ノードがActiveになりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105394/7ca6abb2-1440-cb2a-ef92-952dbbff7286.png)

### まとめ

めっちゃ簡単にできてしまう。
しばらくはこれでkubernetesの勉強進めようと思う。
pipenv shellでalready activated と出た時の対応

時々やっちゃうもんで、対応を備忘のためにメモ。

### 事象

ちゃんと`exit` で抜けずにpipenvを終了すると、
`pipenv shell` で下のエラーが出力されてしまう。
(pipenvを起動した状態で`source ~/.bashrc` を実行したりとか)

```
Shell for (venvのパス) already activated.
```

### 対応

この場合、 Ctrl + d を実行してシェルセッションを終了すると、
`pipenv shell`でpipenvを起動できるようになる。

### 参考

https://github.com/pypa/pipenv/issues/84
GitHubの使い方-リポジトリを削除する方法-備忘録

プログラミング初心者のGitHub使い方備忘録です。

#リポジトリを削除する方法
1．リポジトリのページで1番右端の「Setting」を選択。
![GitHub1.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615830/4aeb4820-64c3-3a82-85ff-3515cf27b99f.jpeg)


2．左側の「Options」が選択されていることを確認。
![GitHub3.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615830/dcdfecb0-5269-6a8a-af07-cb66bc823a66.jpeg)


3．Optionsの下の方へスクロールし、「Delete this repository」を選択。
![GitHub2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615830/ff03a280-66a7-eaf5-4299-27410fd17716.jpeg)

4．削除するリポジトリ名を入れて「I understand the consequences, delete this repository」を選択。
![GitHub4.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615830/28593a97-61c1-a6a9-0a9e-c1af84b729aa.jpeg)

5．GitHubのパスワードを聞かれたら入力すると削除完了。
![GitHub5.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615830/415bf5b5-a001-c778-857d-2a0c745dc6b5.jpeg)
Gitの使い方-fatal:remote origin already exists.と表示された場合-備忘録

プログラミング初心者の備忘録です。

#Gitで「git remote」を実施したらエラーが出た
Gitで「git remote」コマンドを使用してリモートリポジトリに追加する際に発生したエラー。
既に別のリモートリポジトリを追加している可能性があるため、一旦「origin」を削除する。その後、再び「git remote」を実施する。


１．一旦、「origin」を削除する。

```
$git remote rm origin
```

2．「git remote」の実施
再び、「git remote」を実施する。

```
$git remote add origin git@github.com:ユーザー名/リポジトリ名.git
```
【GitHub Actions】実用例まとめ

## GitHub Actions とは
ワールドクラスのCI / CDですべてのソフトウェアワークフローを簡単に自動化できます。 GitHubから直接コードをビルド、テスト、デプロイでき、コードレビュー、ブランチ管理、問題のトリアージを希望どおりに機能させます。

## 環境変数
```yaml:env(Global)
on:
  push:
    branches:
      - master

env:
  AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
  AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
  AWS_DEFAULT_REGION: ap-northeast-1
```
```yaml:env(Step)
jobs:
  Build:
    runs-on: ubuntu-latest

    steps:
      - name: install
        run: yarn install
        env:
          ENVIRONMENT: dev
```

## 複数コマンド簡略化
```yaml:run
jobs:
  Build:
    runs-on: ubuntu-latest

    steps:
      - name: install and build
        run: |
          yarn install
          yarn build
```

## サブフォルダの指定
```yaml:working-directory
jobs:
  Build:
    runs-on: ubuntu-latest

    steps:
      - name: deploy
        working-directory: build
        run: |
          yarn deploy
```

## アクションのトリガー条件
### 指定フォルダ
```yaml:paths
on:
  push:
    branches:
      - master
    paths:
      - docker/**
```

### 指定フォルダ以外
```yaml:paths-ignore
on:
  push:
    branches:
      - master
    paths-ignore:
      - docker/**
```

## 複数ジョブの実行順番
```yaml:needs
jobs:
  Build:
    runs-on: ubuntu-latest

    steps:
      - run: xxxxxx

  Deploy:
    needs:
      - Build
    runs-on: ubuntu-latest

    steps:
      - run: xxxxxx
```

## リポジトリ間のワークフロー実行
```yaml:repository-dispatch(From)
jobs:
  Backend:
    runs-on: ubuntu-latest

    steps:
      - name: Repository Dispatch
        uses: peter-evans/repository-dispatch@v1.1.0
        with:
          token: ${{ secrets.REPO_ACCESS_TOKEN }}
          repository: owner/repository
          event-type: next
```

```yaml:repository-dispatch(To)
on:
  repository_dispatch:
    types: next
```

## Slack への結果通知
```
jobs:
  Slack:
    runs-on: ubuntu-latest

    steps:
      - name: Slack Notify
        uses: rtCamp/action-slack-notify@v2.0.1
        env:
          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
          SLACK_CHANNEL: build
          SLACK_TITLE: Build Success
          SLACK_COLOR: '#43a047'
          SLACK_MESSAGE: ${{ github.repository }} Build Success
          SLACK_USERNAME: ${{ github.repository }}
```

## 設定用ツール
**[VSCode](https://azure.microsoft.com/ja-jp/products/visual-studio-code/)** で Plugin を追加すれば、より効率的に設定できます。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160072/223d324e-0dfa-1a8c-cdc1-8d39afd5c235.png)
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160072/b035f092-2d16-962a-c70b-25beacae11c5.png)
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160072/5dcd2ad0-3832-3ab2-8dab-4beb171be29b.png)
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160072/75eb5b1a-25ee-be54-b64a-de5f5bf7e720.png)
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160072/a3fa99c4-0c49-3920-0d75-90eae00afd2a.png)
Gitの使い方-既存フォルダをgit管理下に置きpushする-備忘録

プログラミング初心者の備忘録

#既存フォルダをgit管理下に置く方法
1．既存のフォルダの場所を指定する。

```
$cd /c/Users/...
```

2．git管理する。

```
$git init
```

3．リモートリポジトリの設定
※GitHubでリポジトリを作成しておく必要あり。
git管理したフォルダにリモートリポジトリを設定する。

```
$git remote add origin https://github.com/ユーザー名/リポジトリ名/git
```

4．gitにファイルを追加
フォルダ内のファイルを「git add」でgit管理する。

```
$git add ファイル名
$git commit -m "コメント"
```

5．リモートリポジトリにプッシュする
「git push」でリモートリポジトリにプッシュする。

```
$git push origin master
```

以上
Python初心者がFlaskでLINEbotを作ることになった（Flaskざっくり解説編）

#なんでそんなことになっちゃったの？
フリーで独立直後、仕事でLINEbotを作ることになりました。
せっかく作るなら人工知能や自然言語処理が得意といわれるPythonで実装して、拡張性を持たせてみたいなと思い、独学をはじめました。
筆者、Python初心者です。

#この記事について
細かいbotの仕様が決まる前に、自学のため以下を学習しました。
https://www.udemy.com/course/python-flask-python-api-line-bot/

しかし、PythonはドットインストールやProgateで学習したのみで、フレームワークの知識がなかったため、「Flask？」となったわけです。
この記事ではFlaskについて自分用にまとめてみようと思いました。
筆者ほんとに初心者なので、なんか違うということがあればご指摘ください。。

#FlaskはPythonのwebフレームワーク
要は、ゴリゴリ手作業でPython書いてwebページを作ろうとすると大変だから、共通化できる枠組みを使って楽に開発進めようよ、ということらしいです。

参考：https://dividable.net/python/flask-python/

「マイクロウェブアプリケーションフレームワーク」を謳っており、必要最低限の機能しかないそうな。


同じwebフレームワークであるDjangoとのざっくり比較↓

|| Flask       | Django      | 
|:-----------------|:-----------------|:-----------------|
|重さ|軽め|重め|
|カスタマイズ性|高い|細かなカスタマイズには不向き|
|初期セットアップ|早い|諸々準備が必要|
|学習コスト|機能が少ないので低め|いろいろできるけど結構大変そう|
|向いている業務|単機能のWebアプリケーション・業務用の管理画面|企業向けの大規模なサービス|


こんな感じなので、botを作るときにはFlaskのほうが向いているということらしいです。
スピーディーに返答を返してほしいですからね！

#Flaskのざっくり使い方
インストールや環境構築等々は[公式](https://a2c.bitbucket.io/flask/installation.html#installation)をご参照ください。

インストール後、以下を書くだけで、もうWebサービスとして動いちゃうって話。
とても簡単ですね！
筆者はJavaをゴリゴリ書く研修を受けた経験があるので、めまいがするほど楽だなと感動しました。

##おなじみHello Worldの作り方

```hello.py:
from flask import Flask      #Flaskクラスをインポート
app = Flask(__name__)        #Flaskアプリケーションの名前を宣言

@app.route('/')              #ファンクションを起動するURLを設定
def hello_world():           #ファンクションの定義
    return "Hello World!"    #今回はブラウザに"Hello World!"を表示する

if __name__ == '__main__':   #アプリケーションとして起動した場合
    app.run()                #ローカルサーバーでアプリケーションを実行
```

特徴的なのは、`app = Flask(__name__)`と`__name__ == '__main__'`でしょうか。
私はここの理解になかなか時間がかかりました。

###`__name__`ってなに？
>まず、このアプリケーションのモジュール名について述べます。 もしあなたが使うモジュールが一つだけなら、 `__name__` を使わなければなりません。 それがアプリケーションとして起動したときとモジュールとしてインポートされたときで名前が異なるからです (アプリケーションとして起動したときは `'__main__'` 、インポートされたときはそのインポート名)。

>`if __name__ == '__main__':` は、そのスクリプトがPyrhonインタープリタから直接実行されたときだけに そのサーバで走り、モジュールとしてインポートされたときには走らないことを保証します。

公式では上記のように記載があります。ほう、なるほど？

`__name__` というのは、自動的に定義される変数で、現在のファイルのモジュール名が入るのだそうです。

Flaskのアプリケーションを３つ（名前をOne, Two, Threeとしましょう）作ったとして、
OneとTwoを、Threeがインポートしている状態の場合を考えてみます。

３つそれぞれに、`if __name__ == '__main__':app.run() `の記載があったとします。

例えばThreeをサーバで実行したとき、`__name__`が適切な名前に置き換わることで、
One,TwoはサーバでRUNしないという設計ということのようです。
（この時のモジュール名は、Threeは`__main__`、 Oneは`One`、Twoは`Two`として扱われるってことかな。）


##ローカルサーバでRUN
さて、作成したhello.pyを実行してみましょう。

```
$ python hello.py
```


Flaskにはローカル開発サーバが内蔵されているので、
上記をコマンドラインから実行すると、ローカルホストの5000番ポート（`http://127.0.0.1:5000/`）でアクセスできます。

Webブラウザを開いてURLにアクセスしてみましょう。
「Hello World」と、か細く左上に表示されればOKです。
これであなたはFlaskを使えるようになりました。やったね！

Dockerなどの仮想環境を利用している場合は、対応したアドレス・ポートにアクセスしてください。
（そのうち別記事書くかも…。。）

サーバを止めるには、control-Cを押せばOK。


###Hello Worldはできた。次は？
筆者はここまでできた後、オウム返しのbotを試しに作ってみて、それから仕事用の開発に進みました。
オウム返しbotの作り方は、いろんな方が記事にしているのでそちらを見ていただければ難なく進められるかと思います。

次回は仕事用開発のときにめちゃくちゃ詰まった、データベース関連の記事から書こうかなと思います。
ご興味あれば覗いてみてください。。


###参考
https://a2c.bitbucket.io/flask/installation.html#installation　（公式）
https://www.udemy.com/course/python-flask-python-api-line-bot/
https://methane.github.io/flask-handson/start.html
[マニュアル]コミット ~コミット時に気をつけること~

#マニュアル
##コミット
ソースコードを修正してコミットする際のポイントです。

- [ ] コミットメッセージは修正理由を説明した適切なものにする
- [ ] コミット時に修正点を確認すること
- [ ] 修正点にPHPStorm上で警告が出ていないか
- [ ] typoがないか
- [ ] var_dump/print_fなどのデバッグ用コードがないか
- [ ] コードカバレッジが回るか
- [ ] 大文字小文字が正しいか
- [ ] ソースをコピペしていないか
- [ ] コメントが正しいか
- [ ] 不要なコメントが残っていないか
- [ ] コードフォーマットが正しいか

###[補足]コミットメッセージは修正理由を説明した適切なものにする
今後のソースコード保守時、なぜその修正がなされたのかが明確でないと、
それを修正して良いかどうか判断ができないことがあります。
また、ソースコードを見ればわかる内容は不要です。

NG例：

- ○○機能修正
- レビュー対応
- ○○Controllerに○○変数を追加

OK例：

- ○○機能を新規追加
- ○○のバグの修正
- typoの修正
- アノテーションを正しい表記に修正
- ○○が正しくなかったため修正

###[補足]修正点にPHPStorm上で警告が出ていないか
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3130333835332f35656564353636342d626637622d306466332d326531612d3863663537623739373437662e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103853/17834932-461f-d3ff-f881-f0dc079efc51.png)
警告はソースコード右側に黄色で表示され、コード中も背景が黄色くなります。
コードレビュー時には警告が無い前提で見ることで単純なバグが無いことを確認します。

###[補足]大文字小文字が正しいか
基本的に以下のルールで命名してください

変数名：キャメルケース 例)groGro
クラス名：パスカルケース 例)GroGro
メソッド名：キャメルケース 例)groGro
テーブル名：スネークケース 例）gro_gro
URL：ケバブケース 例）gro-gro

###[補足]ソースをコピペしていないか
コピペが悪いわけでは無いですが、自分で考えもせずにコピペしていると、
正しくないコメントが残ったり、変数名が変わっていなかったりします。

###[補足]不要なコメントが残っていないか
仮実装をコメントアウトしてそのままにしているところはお掃除してください。
見るべきコメントなのか、そうじゃないのか、混在しているとソースコードが荒れます。
また、変数名に意味を持たせていれば、冗長なコメントは不要です。

###[補足]コードフォーマットが正しいか
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103853/c8f4ffd8-f7e8-1217-1a1a-bc9b0256c984.png)
PHPStormの設定で、右側の[Set from...]から[Laravel]をセットしておいてください。
コード編集中に `command + option + L` or `ctrl + alt + L` でコードを常にフォーマットしてください。
範囲を選択してコードフォーマットをかけることもできますので、一部の修正の際には活用してください。
Rspec導入方法

Railsでモデルに設定されたバリデーションの動作などをRspecを用いてテストすることが出来るので、その導入方法をまとめました。

##### インストール

web_console：
テスト環境で動かすと不具合が起きる可能性ありのため、development環境のみ


```ruby:Gemfile

group :development do
  # Access an interactive console on exception pages or by calling 'console' anywhere in the code.
  gem 'web-console', '>= 3.3.0'  #追記

...

group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
  gem 'rspec-rails' #追記
end
```

```console:terimnal
$ bundle install
```

##### Rspec設定

```console:terminal
$ rails g rspec:install
Running via Spring preloader in process 5275
      create  .rspec
      create  spec
      create  spec/spec_helper.rb
      create  spec/rails_helper.rb
```

##### spec_helper.rb
RailsなしでRspec用の共通の設定を記述するファイル。

##### rails_helper.rb
RailsでRspecを利用する際に、各テスト用ファイルから読み込まれる共通の設定を記述するファイル。


以下を追記する。

```rails:.rspec
--format documentation
```

rspecを実行し、正常に完了するメッセージが出ることを確認する。

```terminal:terminal
$ bundle exec rspec
No examples found.

Finished in 0.00033 seconds (files took 0.12782 seconds to load)
0 examples, 0 failures
```


##### テスト対象

次のようにモデル設定されたバリデーションが正しく動作するか、などをテストすることができる。

```rails:app/models/user.rb
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
  has_many :tweets
  has_many :comments

  validates :nickname, presence: true, length: { maximum: 6 }
end
```
wkhtmltopdfをECSで動かす

## 背景

wkhtmltopdfを使ってPDF出力をさせたときにローカルで出力できても、実稼働環境でうまく動かず500エラーが出る事があった。
ローカルと実稼働環境の違いはnginxの有無とECSのOSで、nginxの方は別途検証し問題なさそうだった。

結論を言うとGemのバージョンの問題だったが、特定に少し時間かかったのでメモ。

## 実稼働環境
- ECS
- amzn-ami-2017.09.g-amazon-ecs-optimized(ami-872c4ae1)

## 問題の特定

実稼働環境のログを確認すると下記のようになっていた。

```
Command Error: /usr/local/bundle/gems/wkhtmltopdf-binary-0.12.5/bin/wkhtmltopdf:40:in `<main>': Invalid platform, must be running on Ubuntu 14.04/16.04/18.04 CentOS 6/7, Debian 8/9, or intel-based macOS (missing binary: /usr/local/bundle/gems/wkhtmltopdf-binary-0.12.5/bin/wkhtmltopdf_debian_10_amd64). (RuntimeError)
Error: PDF could not be generated!
```

実稼働環境で使用しているOSに対応してないよ！というエラーのよう…
debian_10_amd64とエラーにあるのでDebian 10に対応していないかを調べたところ、
同じようなことで悩んでいる人がいて、修正済みなのがわかった。
[Please add support for debian 10 (buster)](https://github.com/zakird/wkhtmltopdf_binary_gem/issues/58)

wkhtmltopdf-binaryのバージョンが0.12.5.1以上であれば対応しているとのことなので早速反映。

## 修正

```:Gemfile
gem 'wkhtmltopdf-binary', '~>0.12.5.1'
gem 'wicked_pdf'
```

```/config/initializers/wicked_pdf.rb
WickedPdf.config = {
 exe_path: "#{Gem.loaded_specs['wkhtmltopdf-binary'].full_gem_path}/bin/wkhtmltopdf"
}
```

上記の設定に変更後、無事に実稼働環境でもPDF出力ができた。
Color#argbのAPI Levelでの使い分け

Color#argbでRequireLevelでの警告が出て対処したので備忘録


Call Requires API Level 26

```
Color.argb(alpha: Float, red: Float, green: Float, blue: Float)
```

それ以下

```
Color.argb(alpha: Int, red: Int, green: Int, blue: Int)
```

`Float`か`Int`かの違いですね
壁を永遠にバウンスするボールのアニメーション

#リクエスト
youtubeの視聴者さんから初めてのリクエストボックスを頂きました！
ありがとうございます！
ちなみにリクエストボックスはこちらから
https://docs.google.com/forms/d/e/1FAIpQLSfYolQjv1u9wn_8jztOTWO7Qc_F2RBYxiZKY0KYL0igW3Cogg/viewform?usp=sf_link

#リクエストの内容はこちら
http://koyamatch.com/post/javascript/oojs/2017/06/06/bouncing-ball.html

Q）上記のようなことはAEで可能なのか
positionがボックスサイズと等しいときの時間を求めてその時間以降はベクトルを反転させたい

A）答えとしては出来るはず

#ちょっとやってみたけど
結構難しい。
物理とか数学とか苦手だったので・・・
しかし今日空いた時間を使って少し考えてみたらそれっぽいものは出来てきたけど、全然完成には程遠い。
もう少し時間がかかりそうですが、ちょっと面白いチャレンジなので引き続き研究。

#とりあえず今日やった分はこちらから視聴可能
https://www.youtube.com/watch?v=PLAVSLveyis

#現時点の問題点
動画を見ていただいた通り、ボールが片道しか行かない状態です。
跳ねて返ってきたときに逆側が跳ね返らない・・・
このままでは上下の設定も出来ない。
すごい初歩的なミスな気がする。
これだと最初の一回だけしか読み込まないから、跳ねた時にまた跳ねないかと思って
whileで毎回やってみたけど、出来なかった。
要点としてはvalueを常に置き換えないといけないってとこが原因だと思う。

#Expression
```jsx
defPos = [div(thisComp.width,2),div(thisComp.height,2)];
boxSize = [thisComp.width,thisComp.height];
myRadius = div(content("楕円形パス 1").size,2);
seedRandom(index,true)
speedControl = time*random(300,500);
direction = random()*Math.PI*2;
x = Math.cos(direction)*speedControl+defPos[0];
y = Math.sin(direction)*speedControl+defPos[1];

if ( x-myRadius[0] < 0){
	x = myRadius[0];
	direction = Math.atan2(Math.sin(direction),Math.cos(direction)*-1);
	x = Math.cos(direction)*speedControl-(defPos[0]-x-myRadius[0]);
	[x,y]
}else if(x + myRadius[0] > boxSize[0]){
	x =  boxSize[0]-myRadius[0];
	direction = Math.atan2(Math.sin(direction),Math.cos(direction)*-1);
	x = Math.cos(direction)*speedControl+(defPos[0]+boxSize[0]-(myRadius[0]*2));
	[x,y]
}else{
	[x,y]
}
```
#2020/5/8翌日の追記
あら？？これもっと単純に出来るんじゃない！？と思って頭を柔らかくしてやってみたら、すぐに出来た(笑)
物理がわからなくて、いろいろ調べすぎて頭でっかちになってました。。。

答えはyoutubeにて公開いたします！
https://youtu.be/wQYP0Bd6dg4
ArrayListで独自に作成したクラスを扱うメモ

#ArrayListで独自に作成したオブジェクトを扱う
はじめまして。はねうまです。
自作のクラスのリストを扱うときのメモを書いてみます。
**例：自作クラス「Food」のリストを扱う**
addメソッドの引数の中でFoodをインスタンス化し、リストに追加する。

```java
List<Food> foodList = new ArrayList<>();
foodList.add(new Food("バナナ","果物")); 
foodList.add(new Food("キャベツ","野菜"));
foodList.add(new Food("カレー","料理"));
```

要素にアクセスするには・・・
(1)Foodクラスの変数を用意して、そこにリストからgetして代入する
(2)その変数を使って自作クラスの処理をする
(3)拡張for文の利用

```java
Food fd = foodList.get(0);  // (1)
fd.printFood();  // (2)
fd.setFoodName("りんご");  // (2)

for(Food f : foodList) {  // (3)
    f.printFood();
}
```
なぜGit（Hub）なのか？　　メモ、備忘録

特定の誰か1人がバージョン管理してくれねーかなー
面倒そうだから俺はやりたくねーなー


# 別に使わなくていいんじゃないか？
特に大きいシステムでもなく、管理するデータも少ないのであれば
全体の開発者が1人ないし、2人くらいであれば…

# 要は効率化
オンラインゲームをやったことがある人なら分かるかもしれない。
固定メンツ、メンバーを固定してゲームをクリアする手法。
メンバーを固定するから、それぞれで”持ちつ持たれつ”できるし。
メンバーを固定する前に選ぶ作業があるから、一定レベルのプレイヤーを集える。

まぁ、サッカー日本代表みたいなもん。

プログラミングもチーム戦だから求められることは同じ。
統一された認識、統一されたルールに則って早く動くこと。
１つ１つの作業・動作レベルで無駄を省き、皆でスムーズな開発をしよう。ということ。
（なのでスケールメリットが大きいか小さいかみたいな話になる）
（と養護してみたけど、プログラミングの開発手法って、要はスケールメリットの大小だよね）

単一のチームだけの話じゃない。チームは移籍することだってある。
複数チームで”統一され”ていると、他のチームでも能力を発揮しやすいよね。

# ポジティブに捉えよう
Git（Hub）を使いこなせたらサッカー日本代表に一歩近づくというわけだ。
サッカー日本代表も使うくらい有益なことなんだ、**やるっきゃないでしょ！**
HTMLのダイアログ内のスクロールを指定位置に移動する

ページ内で指定位置にスクロールさせたいとき以下のようなアンカーを用いるが

HTML

```
<a href="#sampleId">指定位置へスクロール</a>

<div id="sampleId">内容</div>
```

ダイアログ内で指定位置にスクロールさせるにはscrollTopを用いて指定位置に移動させる。

HTML

```
<!--ダイアログ-->
<div id="dialog">
  <!--指定位置へ移動するボタン-->
  <button onclick="jump()">指定位置へスクロール</button>
  <!--スクロール領域-->
  <div id="contents" style="overflow-y:auto;height:520px">
    <!--移動したい内容-->
    <div id="sampleId">内容</div>
  </div>
</div>
```

Javascript

```
function jump() {
  //スクロール領域の位置を取得
  var offsetTop = $("#contents").offset().top;
  //移動したい内容の位置を取得
  var top = $("#sampleId").offset().top;
  //スクロールを移動する
  $("#contents").scrollTop(top - offsetTop);
}
```
npm install時にENOENT: no such file or directoryが出た場合の対処

# はじめに
ある日突然`npm install`ができなくなった。（正しくは実行時にエラーになる。）

```bash
$ npm install -g @aws-amplify/cli
npm ERR! code ENOENT
npm ERR! syscall open
npm ERR! path /home/vagrant/.npm/_cacache/tmp/823188c5
npm ERR! errno -2
npm ERR! enoent ENOENT: no such file or directory, open '/home/vagrant/.npm/_cacache/tmp/823188c5'
npm ERR! enoent This is related to npm not being able to find a file.
npm ERR! enoent 
```

本記事はこのerrno -2でキャッシュフォルダが参照できない場合の対処について記載。

# 対処（結論）

```bash
$ unlink /home/vagrant/.npm
```

※指定するパスはご自身の環境で出力されているエラー文見て、合わせてください。

# 原因
対処コマンド見れば説明いらない気もするけど一応。
エラー時に出力されていたnpmのキャッシュ先パスがシンボリックリンクになっていた。
どのタイミングでシンボリックリンクが作られたのか記憶にない。。。
Android 11 Labs Day 2 メモ書き

少し時間が空いちゃったけど、[Android 11 Labs](https://developersonair.withgoogle.com/events/android11labsjp) の Day 2 で気になったところだけメモ。
（Day 1 は[こちら](https://qiita.com/koichi-ozaki/items/77313a8c49c0b2c76367)）

- ストレージのスコープ化についての最新技術情報
    - Android 10 でストレージのスコープは導入されている
    - Android 10 より前
        - 外部ストレージへのアクセスはストレージのパーミッションがあれば OK だった
        - 他のアプリの領域も読み書きできた
    - Android 10 から
        - セキュリティの観点から、他のアプリの領域は参照できなくなった
        - ファイルの所有者がちゃんとわかるようになっている
        - 強制ではなく、manifest になんか書けばこの機能をオフにできてた
    - Android 11 から
        - 強制になった
        - `Storage` から `Files & Media`
        - メディアストレージの操作が便利になった
            - 複数の写真をお気に入りにしたり削除したり
            - 操作したいデータの URI をリストで渡してユーザーに許可してもらう感じ
    - Media Store API を使ったほうがいい
        - パフォーマンスとかバッテリーの面でそっちのほうがいいらしい
    - ストレージへの全権限が必要なアプリ（ファイルマネージャーとかバックアップするようなアプリ）のために、特別なパーミッションが追加される予定
        - ただし厳し目のガイドラインが設定されるはず

- 非公開 API の利用制限について
    - 非公開 API は予告なく変更したり消えたりするからできるだけ使わないでね
    - でも案外使ってるアプリはある
    - White、Light grey、Dark grey、Black の４段階にわけている
    - @UnsupportedAppUsage: Light grey
    - @UnsupportedAppUsage(maxTargetSdk = 0): Black
    - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.X): Dark grey
    - 2000件 Light grey にした
    - 800件 Dark grey にした
    - 900件 Black にした
    - 非公開 API を利用しているか確認する方法
        - debug アプリでログで確認する
        - Google Play Console で検知
        - Android Studio の lint tool
        - StrictMode API を利用する？？すべての非公開APIが使えなくなるらしい

- その他の新規機能
    - IME の表示/非表示 をコントロールできるようになった
        - コールバックを実装する
    - フレームレートの設定
    - プロセスが終了の細かい情報を取得できるようになった
        - 次起動したときに取得できる
        - 終了した理由、stack trace

- Q&A
    - ファイルマネージャ的なアプリは作ることができなくなる？
        - できます
        - 全体を管理する権限が追加されるのでそれを取得すればできる
        - ただしガイドライン厳しいよ
    - なぜ外部ストレージ全体を制限したの？
        - 所有権をハッキリさせるため（個人的な意見ですが）
    - 非公開 API を利用しているアプリを公開後、そのあとその API がブラックになったらリジェクトされる？
        - API level によってそれぞれリストがちがうから targetSdk 変えたりしたときにビルドできなくなる
    - 非推奨 API はどういう立ち位置？
        - 推奨している方法があるんでできるだけそっちの実装の仕方がいい
    - android 11 の動作確認は targetSdkVersion を R にした方がいい？
        - いずれ R 対応が必須になるんで早めにやるにこしたtことはない
        - R にすることで動きが変わる部分もある
    - ポリシー変更も情報共有してほしい
        - 今後検討します
    - scoped storage の best practice はありますか？
        - 複数のアプリでストレージを共有しているなら移行してね
        - アプリによってストレージの使い方や解決方法はバラバラだろうからベストプラクティスはむずかしい
    - 同じ開発者が作ったアプリ間でファイルを共有する方法はありますか？前作のゲームのセーブデータを引き継いで続編で読み込む、みたいな
        - Google 検討中
    - ユーザーが USB 経由で document、download、メディア以外にファイルを転送したら、そのファイルはアプリから扱えなくなる？
        - そうです
        - ファイルマネージャ的なアプリ以外でそういう用途おもいつかないなあ
    - アプリが終了した情報を保持するやつは firebase を最新にすれば収集できる？
        - firebase 関係ない
        - OS の機能です
    - ACTION_OPEN_DOCUMENT_TREE で初期表示されるフォルダを指定したい
        - なぜ指定したいのか教えてくれると助かります
    - メディアファイルとその他のファイルでアクセスする仕組みを分けるのに理由はあるんですか？
        - 使われ方が違うと思うから分けてるんじゃ
        - ファイルの性質がちがう気がするから
    - アプリ終了したときの情報はクラッシュだけ？どこに保存される？
        - クラッシュ以外も取れるっぽい
        - この API 経由でしかアクセスできないです