OmniAICreator/Qiita-1.07M huggingface dataset:
CircleCIでDocker Hubの制限を回避するための設定

# 問題

Docker Hubは、無料アカウントと認証なしユーザーで、[11月からpull数に制限がかかります](https://www.docker.com/pricing/resource-consumption-updates)。CircleCI上で認証無しで運用しているとIPアドレスベースの制限がかかり、CircleCIのIPアドレスはユーザーと比較して多くないので影響が懸念されます。

CircleCIチームはDocker社と会話してる模様なので、今後もしかしたらユーザーの対応は不要となるかも知れません。しかしCI/CD環境が止まれば影響は大きいので回避策を押さえておきましょう。


# 解決策
ひとまずDocker Hubのユーザー認証を噛ませれば、IPアドレスでは判断されなくなるので無料アカウントでも`200 pulls/6h`までは利用できます。これ以上になるならDocker Hubへの課金が必要ですが、どのみちCircleCI上でユーザー認証を行う必要があるので同様の作業が発生します。

# 作業手順
以下の作業でCircleCI上でのDocker Hubのユーザー認証を行います。
`config.yaml`の全体は↓こちら。

- https://github.com/AlisProject/serverless-application/blob/master/.circleci/config.yml
    - [今回の修正分はこちら](https://github.com/AlisProject/serverless-application/pull/430/files)

## CircleCIのContextにDocker Hubのユーザー名とパスワードを設定
Contextへの登録手順はすぐ出てくるので割愛します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50056/4ad409f8-93ff-b269-7ace-a7441f3cbd10.png)

## Dockerを利用するJobにContextを追加
※[2020/09/15から複数のContextがサポートされた模様!](https://ideas.circleci.com/cloud-feature-requests/p/multiple-contexts-in-a-workflow) これは嬉しい。

```yaml
  staging_steps: &staging_steps
    <<: *only_master
    context:
      - serverless_staging
      - docker-hub-credencials
  production_steps: &production_steps
    <<: *only_master
    context:
      - serverless_production
      - docker-hub-credencials
```


## Dockerを利用している箇所に認証を加える
[Docker executor](https://go.circleci.com/VKM40002u60H200ZG7bCkk0)や、Machine executor内でDockerをpullしている箇所に設定した認証情報を加えてゆきます。
以下はDocker executorの例。

### 参照用の項目を作成

```yaml
references:
  docker_hub_authentication: &docker_hub_authentication
    auth:
      username: $DOCKERHUB_USER
      password: $DOCKERHUB_PASSWORD
```

### imageをpullしている箇所全てに適用
以下は`executors`にまとめられている箇所に適用している例。

```yaml
executors:
  python3_6_1:
    working_directory: ~/repo
    docker:
      - image: circleci/python:3.6.1
        <<: *docker_hub_authentication
  test:
    working_directory: ~/repo
    docker:
      - image: circleci/python:3.6.1
        <<: *docker_hub_authentication
      - image: bluszcz/bflocalstack-dynamodb-s3
        <<: *docker_hub_authentication
      - image: alismedia/dynamodb-local
        <<: *docker_hub_authentication
        environment:
          MAX_HEAP_SIZE: 4096m
          HEAP_NEWSIZE: 3072m
      # Docker Hubではないので認証情報不要
      - image: docker.elastic.co/elasticsearch/elasticsearch:6.2.0
        environment:
          discovery.type: single-node
```

以上の設定を行って、変更前と同じようにビルドできれば完了です。


# エラー
Docker Hubではない箇所に誤って認証情報を追加すると以下のようなエラーが出ます。

```bash
Error response from daemon: Get https://docker.elastic.co/v2/elasticsearch/elasticsearch/manifests/6.2.0: unauthorized: authentication required
```

以下は謎のエラー。今回初めて見たもの。

```bash
Allocating a remote Docker Engine
Requesting version: 18.09.3

Got error while creating host: failed to create host: rpc error: code = Unknown desc = failed to create VM: Put "https://vm-service.infra.circleci.com/tasks/5f7ffcbaa7b0aa6a8ec29c79-0-build%2F59C7C9D1": EOF
We had an unexpected error preparing a VM for this build, potentially due to our infrastructure or cloud provider.  Please retry the build in a few minutes
```

指示通りにRerunしたら解決しました。
【Python】foliumで中野区の0歳人口を可視化(＋geoJSONの整形)

<p>保育園の立地ミスマッチが気になったので、子どもが多いエリアを可視化しようとしたところ、Excelでは可視化できなかったのでPythonに挑戦してみました。境界データの整形が一番苦労しました。非エンジニア(Word、Excel、Powerpointしか使ったことがない)の初心者です。</p>

![中野区_0歳児の数.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/777340/9f8c5cb6-34a3-3100-7d33-65f116cd4ab8.jpeg)

<h1>Pythonのコード</h1>
<p>まず、最終的に記述したコードです。初心者なので間違いもあるかと思いますがご容赦ください。</p>
![tizu_code.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/777340/a70256b4-1264-1d64-be56-2494363cdc53.jpeg)







<p>※作業環境はWindows7です。<br>※Anacondaをインストールして、Jyupter Notebook上で作業しました。<br>※geoJSONはget(URL)でGitHubから読み込みたかったのですが、URLが分からず、自分のパソコンから読みこむかたちになっています。</p>



<h1>コードで記述した内容のイメージ</h1>
![cholo_setumei.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/777340/2e90ef75-af2e-b461-8b4c-f73764692a8a.jpeg)


<h1>境界データのJSONデータ</h1>
中野区町丁別の境界データのファイルはGitHubで公開しましたので、そちらを参照ください。(データ出典元のe-StatにはGitHubに載せる旨問い合わせ済)
https://github.com/RefletsDansLeau/Geojson

<h2>JSONデータの整形の体験談</h2>
<p>JSONファイルが完成するまで長い道のりでした。ご興味がある方はお読みください。</P>

<h3>①「地図で見る統計（統計GIS）」でShapeファイルをダウンロード</h3>
まず、中野区町丁別の境界データのjsonファイルを「地図で見る統計（統計GIS）」サイトで探しましたが、Shapeファイルしか見つかりませんでした。
Shapeファイルは4つに分かれており、そのままだとPythonでコロプレス図が書けなかったので、自分で整形することにしました。
<h3>②phtyonのPyShpライブラリで4つのファイルを一つに統合</h3>
PythonのPyShpライブラリでShapeファイルを読み込むことができ、jsonデータ風の文字列が表示されたので、この文字列を保存しました。

<h3>③細かい整形</h3>
しかし、上記の状態ではPythonで読み込めなかったので、知人に相談したところ「文法エラー」とのことでした。そして、括弧の種類を（）→[]へ、また余分な,(カンマ)を修正してくださりました。「Code for 中野」の皆様、アドバイスありがとうございました。

<br>この段階でPythonで読み込もうとしたところ、エラー(UnicodeDecodeError)が出てきてしまいました。余分なデータが含まれているのかもしれないと思い「geojson.io」のサイトで不要な列をガンガン削除し、「Right Hand Rule GeoJSON Fixer」というサイトで修正し、Geojson ファイルチェッカーにかけたところ、無事に境界線が描写されました。
<br>しかし、まだPythonでコロプレス図が書けません。そこで「Visual Studio Code」を使って「JSONで保存」としてみたり、町丁名を日本語→英語表記に変えたところ、ついにPythonでコロプレス図が描写できるようになりました。

最後に、描写したコロプレス図ですが、なぜか、色が塗れている区画と灰色の区画が混じっていました。そこで、Visual Studio Codeを開いて色が塗れる区画と塗れない区画を比較したところ、行政コードの数字をダブルクオテーションで囲うか囲わないかの違いがあることに気づき、ダブルクオテーション無しで統一しました。すると、すべての区画で無事に色が塗れるようになりました。かくして悲願のJSONファイルが完成しました。

<h1>プログラミング初心者の私がつまづいた点</h1>
<h2>①Anacondaの閉じ方</h2>
Anacondaの使い方については色々なサイトで説明をしておりますが、検索してもなかなか分からなかったのが「Anacondaの閉じ方」です。「Ctrl＋Cでターミナルを閉じる。」と説明があるのですが、そもそも「ターミナル」が分かりませんでした。

→「ターミナル」とは、どうやら「Anaconda Prompt」と書いてある画面だと気づくまでかなり時間がかかりました…。


<h2>②Pythonライブラリのインストール</h2>
始めは、Jupyter Notebookのセルに「import folium」と記述しても何も起こりませんでした。
色々検索すると、ライブラリを使う時に、まずはじめに「pip install folium」などと記述する必要がある、と分かりましたが、どこに記述するのか分かりませんでした。
色々いじってみて「Anaconda Prompt」なるものを発見！ここに記述すると上手くいくことが分かりました。

<h1>感想</h1>
時間はかかりましたが、念願のコロプレス図を作成することができました。保育園の立地ミスマッチを防ぐ等活用していただきたいです。
子育て中の親としては児童館も残してほしいです！今後も色々なオープンデータを可視化したいと思います。
Pythonからはじめる数学入門 プログラミングチャレンジ自分的メモ - 問題1-1

## 概要
オライリージャパンの「Pythonからはじめる数学入門」の演習をやってみたメモ。

あくまでも個人的な学習メモです。

## 最初の回答
```python
def print_num(number):
#     print([number + 2 for i in range(2, 11) if number % 2 == 0])
    print('偶数です' if number % 2 == 0 else '奇数です')
    
    for item in range(2, 11):
        number += 2
        print(int(number), end=" ")

if __name__ == '__main__':
    number = float(input('what your number: '))
    if number.is_integer():
        print_num(number)
    else:
        print('整数を入れてください。')
```

## 改良
改良ポイント
整数や小数が入力されたときは良いが、アルファベットなどが入ってきたときには異常終了してします。
そこでtry..except を入れた。

```python

def print_num(number):
    print('偶数です' if number % 2 == 0 else '奇数です')
    
    for item in range(2, 11):
        number += 2
        print(int(number), end=" ")

if __name__ == '__main__':
    try:
        number = float(input('what your number: '))
        if number.is_integer():
            print_num(number)
        else:
            print('整数を入れてください。')
    except ValueError:
        print('整数を入れてください。')
```

## まとめ
改良は回答を参考に行った。
if文の書き方など、回答とは異なる部分もあるものの、これはこれでOK。
今後、例えばパフォーマンスの観点からどうすると良いとかは検証していきたい。
【2D OD】RetinaNet : 簡単に検出出来る物体の重みを減らす(Focal Loss)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/8756bf81-e5d0-1fad-21af-2ed25b105626.png)

2017年1月にSOTAだったRetinaNetで使われていた、Focal Lossについて、見ていきたいと思う。

Focal Lossを簡単に言うと、データの不均衡の問題をなくす為、データ量の少ない物体にfocusを置くためのLossの定義。

<h1>Focal Loss</h1>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/f6ff3791-b4b9-54a1-a8d3-0a36f7faf0d9.png)

多クラス分類で使われるCrossEntropyLossの定義は上記のようになっていて、labelが1の時とlabelが0の時の2つの条件に分かれています。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/3868bd79-6b20-3944-1d9a-9da591b9b617.png)

と定義すると

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/b5899a9e-a14e-1b4c-9abd-3493e5017b33.png)

CrossEntropyをこのように書くことが出来る。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/7f8d395d-8c87-0a9c-a6b8-443ad3b09a57.png)

データの不均衡を解決する方法として係数αを掛ける方法があるらしい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/dce91177-9279-1d65-8cd7-f13d645f2823.png)

をCE lossにかけてみると

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/c821edfa-ff26-aef9-a2ea-ad80e6625272.png)

となる。ページトップのグラフを見ると。rを増やすことで、well-classified-exampleに対するlossが殆んど0になっている。相対的にProbabilityの推定が難しいもののLossの割合が大きくなる事になる。
すなわち、あまり学習されていないclass、または学習が難しいclassをより効率的に学習する事が出来る。


<h1>結論</h1>
データの偏りなどがあってもFocal Lossを用いる事でバランスよく学習出来る。
背景は画像に締める割合が多く、データ量が豊富なので、簡単にclass分類出来るから、Focal Lossを用いる事で背景の分類の重みを減らす事で、データとしてバランスが取れるっていうロジックなんだと思う。

簡単に実装出来て精度が上がるんで、自分の物体認識のアルゴリズムのLossをFocal Lossにしてみたいと思う。


<h1>参考文献</h1>
Focal Loss for Dense Object Detection
https://arxiv.org/pdf/1708.02002v2.pdf
表（table）の空のセルにCSSのみで斜線を引く　

##空のセルに対して、斜線を引く
例えば下記のような表を作った。
営業日:月、火
お休み:水曜日
っていう感じで、
水曜日のセルに斜線を入れたい時。
（初心者のため表のイメージの貼り付けができなくてごめんなさいね）

一番下の水曜日のセルには何も書かない。
空にしておく。

```index.html
<table border="1">
            <tr>
              <th>診療時間</th>
              <td>月</td>
              <td>火</td>
              <td>水</td>
            </tr>
            <tr>
              <th>9:00~15:00</th>
              <td>●</td>
              <td>●</td>
              <td></td>
            </tr>
          </table>
```

CSSで空のセルに対して。

```style.css
/* 空のセルに斜線を引く 透明ー黒黒ー透明 */
table td:empty {
  background-image: linear-gradient(to top left,
  transparent, transparent 49%,
     black 49%,
     black 51%,   /* 線の太さ */
    transparent 51%, transparent);
}
```

## 解説
・`table td:empty`：空のセルに対して。
・グラデーション`linear-gradient`を利用します。
グラデーションの仕組みは、なんとなくの理解だけど、
「透明〜黒〜黒〜透明の順番でグラデーションしろ。」ってイメージでいいかと。
→→ちょうど中間で黒い線が引かれる。＝斜線　
線の太さは％を変更すれば良い。（ちなみにこれは最小）
47%〜53%とかいい感じじゃないかな。

★この時に、`to top left,`て指定しているのがポイント。
「（右下から）左上に向かってグラデーション」となるので、右上りの斜線になる。

逆に右下がりの斜線ならrightに変更すれば良い。

他のやり方だと４５度傾けたりする方法もあるけど、正方形のセルに対してじゃないとうまくいかないよう。。これならどんな形でもバッチリ斜めの線になる。はず。


#### 参考リンク
[CSSで斜線を引く方法](https://allabout.co.jp/gm/gc/457196/3/)
HTML & CSS WEB基礎知識





###FTPとHTTP

FTP    (File Transfer Protocol)
HTTP   (Hyper Text Transfer Protocol)


###タグの種類




```

<p>         「Paragraph」の略で、<p>～</p>で囲まれたテキストは1つの段落であることを示します。 

<H1>～<H6>  「Heading」の略で、見出しを表します。

<div>       「Division」の略で、区分や部分などの意味を持ちます。 
　　　　　　　したがって、その意味から推測できる通り、divタグは複数のタグを１つにまとめる働きを持ちます。

<ul>        「unordered list（順序がないリスト）」の略で、
　　　　　　　その名前の通り順序がない箇条書きのリストを表示する際に使用するタグです。

<ol>        「ordered list（順序のあるリスト）」の略で、
　　　　　　　その名前の通り順序のある番号付きのリストを表示する際に使用するタグです。

<li>        「list item」の略で、リストの項目を表示するために使用するタグです。

<a>         「アンカー(anchor)」の略で、リンクの出発点と到達点を指定するために使われます。 
　　　　　　　様々な属性を持ちますが、リンク先を指定するhref属性、
　　　　　　　対象となるファイルへの関係を指定するrel属性などが比較的よく使用されます。

<em>        「emphasis」の略で、強調を表すタグです。

<br>        「Break」の略で、改行を行うためのタグです。

<hr>        「horizontal rule（水平方向の罫線）」の略で、水平の横線を引くためのタグです。

<tr>        「table row」の略で表の行部分（横方向）を指定するタグです。

<td>        「table data」の略で、テーブルセルの内容を指定します。

<th>        「table header」の略で、表の見出しやタイトルとなるヘッダセルを作成するタグです。 
　　　　　　　セルの内容がデータに対する見出しの場合はこの<th>要素を使用します。


```


###タグ　HTML メモ
```

download="〇〇.pdf" "ダウンロードさせる"

target="_blank" "別タブで開く"
```
社内LANでgitのエラーが出るとき（プロキシ設定）

社内でgitを使おうとしたら繋がらない。

```
fatal: repository '[リポジトリのURL]' not found

fatal: unable to access '[リポジトリのURL]': SSL certificate problem: unable to get local issuer certificate
```

などのエラーが出てしまう。
あれ、おかしい。
URLはあってるし、インターネット設定からプロキシはちゃんと設定しているからネットにはちゃんと繋がっているのに。

と思ったら、**gitにもプロキシを設定しないといけない**んですね。

# 設定、解除および確認の仕方

テレワークをすることも多いのでgitのプロキシの設定と解除をそれなりの頻度で行います。
そのため自分用メモを残します。

## gitのプロキシ設定

```
git config --global http.proxy http://proxy.example.com:8080
git config --global https.proxy https://proxy.example.com:8080
```
httpプロキシの設定は↑、httpsは↓

## gitのプロキシ解除
```
git config --global --unset http.proxy 
git config --global --unset https.proxy 
```
httpプロキシの解除は↑、httpsは↓

## gitのプロキシ確認
```
git config http.proxy 
git config https.proxy 
```
httpプロキシの確認は↑、httpsは↓
新人エンジニアがインフラのコード化（IaC）に３ヶ月取り組んで見えた知見をまとめてみた

# はじめに
約３ヶ月間、それなりにボリュームのある新規開発で AWS周りをガッツリやらせてもらいました。

AWS や新規開発について学ぶことが多かったので何回かに分けてまとめてみたいと思います。
これから AWS をガッツリ使っていこうと思っている方の参考になれば幸いです。

今回はその第１回、 **IaC** (Infrastructure as Code)編です🎉

## AWSで使った技術など
- CloudFormation
- Lambda
- DynamoDB
- API Gateway
- CloudWatch
- CloudFront
- X-Ray
- SNS
- S3

などなんかたくさん。
今回 IaC にはCloudFormationを使ったのですが、Terraform など他のツールでも参考になると思います。

## ある程度の規模になりそうなら SAM はやめておこう
AWS でインフラをコード化するにはいろいろ選択肢がありますが、AWS SAM というものも使えます。
今回使用したのは厳密に言えばこちらの SAM です。

【参考】
https://aws.amazon.com/jp/serverless/sam/

簡単に言うと、Lambdaを中心としたサーバーレスアプリケーションを構築する人向けに、CloudFormationをより簡単に使えるようにラップしたもの、でしょうか。

### 何が問題なのか？
CloudFormationをラップしたものなので、CloudFormationで書けるものは基本的には書けるはずです。
では、何が問題なのでしょうか？

それは、 **CloudFormation なら使える機能の１部が使えない（あるいは使いづらい）** からです。

最初はスピード感を重視して SAM で開発を始めたのですが後々、

- Stack の管理外にあるリソースを CloudFormation の管理下におきたい
- リソースを記載したファイルが煩雑になってきたのでリファクタリングしたい

という時に苦労しました。もしかしたら何か別の方法があったかもしれませんが、必須では無かったのでとりあえず諦めました。

サクッとサーバーレスアプリを立ち上げたい時には素晴らしいのですが、ある程度の規模になることが見込まれるのであれば最初から純粋な CloudFormation で良くない？というのが印象です。

あまりメリットを享受できなかった気がする。。。

## リソースの命名規則は最初にチームでしっかり決めていく
インフラをコード化する時には論理名（下のサンプルで言うと `HelloBucket` ）と、そのリソースの名前（バケット名とか）があると思います。

```yaml
Resources:
  HelloBucket:
    Type: AWS::S3::Bucket
    Properties:
      AccessControl: PublicRead
```

これらの命名規則をしっかり決めておかないと、後で `何が何だかどこで使っているリソースなんだか分からなくなります`。


私の失敗談を共有しておくと、それなりに分かりやすい名前を付けて進めていたつもりなんですが、「環境名の prefix」を付けていなかったんですね。

そして開発が進み、必要になりました。はい。環境名の prefix が。



**うわあああああああああああああ、めんどくせええええええええ！！！！！！！** 

本当に後から名前を変える単純作業は苦痛ですし、工数としてもちょっと無駄です。
せっかく効率化のために IaC ツールを使っているのですから、この辺はスマートにやりたいところ。
是非皆さんには私のような間違いは犯して欲しくないなと思っております😵


命名規則に関しては以下のクラスメソッドさんの記事が非常に参考になります。
https://dev.classmethod.jp/articles/aws-name-rule/


## ワークフローはしっかりチームで決めよう
もちろんインフラをコード化したらチームメンバーにレビューをお願いすると思います。

しかしまだ経験が少ないなら尚更のこと、 **AWS は実際にデプロイしてみないと分からないことが多々あります**。
もしかしたら、合っていたと思っていた設定値が間違っていてデプロイに失敗するかもしれません。


それにレビューする側もプロパティがツラツラ書いているだけのものを見るより、動いてから見せてもらった方が良いと思います。
なので開発用の環境が用意できるのであればそこで試してからレビュー依頼を出す、とか工夫をした方が良いです。

工夫というか、チームで決めるようにできると良いですね！！
他にもワークフローに関してはこんなことを事前に決めておくと良いかもしれません

- 手でデプロイするの？ CI/CD ツールを使ってデプロイするの？
- 環境は何を用意してそれぞれがどんな役割なの？
- コードレビューの着眼点

## IaC ツールは Terraform を使おう
以上です、何も言うことはありません😢

## 手動を排除しよう
最初は良いんです、最初は。
しかし開発は進み、当初は予期していなかったリソースは増えていくものです。

その時、 **チームのワークフローはそれに対応できるものでしょうか？**

確かにコマンド一発でインフラを構築できる威力は凄いですしシンプルですが、それでも環境が増えたりすると手順ミスは当然起こりえます。
AWS ですし、下手にミスると大事なデータを消してしまったりもします。精神衛生上も良くないです（幸い問題にはなりませんでしたが、私も開発中何度かヒヤッとしました）。

めんどくさい気持ちは分かるんです。最初はコマンドラインから普通にデプロイした方が楽ですからね。

しかしこういうのは最初に CI/CD パイプラインを構築するなどして **仕組みに頼る** べきです。
間違っても「自分は間違えない」などと過信してはいけません。どんなに優秀な人でも所詮人間です、普通に間違えます。間違えるのは決して悪いことではありません。それに対して策を講じないのが悪いことです。

気合で頑張るとかはやめて、仕組みに頼りましょう。

【例】
GitHubにpush → CDで検証環境にデプロイ → 動作確認 → レビュー依頼 → 修正対応 → masterにマージ → 本番環境にデプロイ

ほんの一例ですが、手元からデプロイするよりずっと安全です。


## おわりに
まだまだあるのですが、長くなるのでこの辺で切ります。
引き続き、もっと安定して強力なワークフローを考えられるように頑張ります🙂

どなたかの役に立てば幸いです、ありがとうございました。
[備忘録]Githubの使い方

<h1>リポジトリーの作成からファーストコミット</h1>
「README.md」を作成

```sh
echo README.md
```


リポジトリを新規に作成

```sh
git init
```


「README.md」をインデックスに登録

```sh
git add RAEDME.md
```


インデックスをローカルリポジトリにコミット

```sh
git commit -m "my first commit"
```


mainブランチにブランチを設定

```sh
git branch -M main
```

githubのリモートリポジトリを登録

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


コミットされているのを、リモートリポジトリにプッシュ

```sh
git push -u origin main
```


<h1>ブランチ</h1>
現在のブランチ一覧の確認

```sh
git branch
```

ブランチの作成

```sh
git branch [ブランチ名]
```


ブランチの移動

```sh
$ git checkout [ブランチ名]
```


ブランチの作成と移動

````sh
git checkout -b [ブランチ名]
```


<h2>ブランチにプッシュする</h2>

```sh
git add index.html
git commit -m "add file index.html"
```

```sh
git push origin [ブランチ名]
```


<h2>ブランチからプル</h2>

まずは、ブランチからチェックアウト

```sh
git checkout [ブランチ名]
```


リモートブランチ[ブランチ名]のコードを取得する

```sh
git pull
```


<h2>ブランチのマージ</h2>
作業中のブランチをmainに切り替える

```sh
git checkout main
```


[ブランチ名]の作業結果をマージする

```sh
git merge [ブランチ名]
```


Githubにプッシュ

```sh
git push origin main
```


ブランチの削除

```sh
git branch -d [ブランチ名]
```

<h1>その他のGitコマンド</h1>
リポジトリの状態を確認する

```sh
git status
```


ローカルリポジトリのコミット履歴の閲覧
`-n`オプションで履歴の表示数を指定できる

```sh
git log -n 10
```


既存のリモートリポジトリをローカルに落とす

```sh
git clone [url]
```
AWS GlueでRDSにデータを上書き保存する

GlueのジョブでDynamicFrameを使ってデータをRDSに書き込むとき、
追記（Append）で書き込むため、同じジョブを動かすとデータが重複してしまいます。

DynamicFrameをDataFrameに変換すると、上書きモードで書き込むことができます。

自動生成されたジョブのコードに以下を追記します。
JDBCの接続定義が用意されてることが前提です。

```python
#datasink4 = glueContext.write_dynamic_frame.from_jdbc_conf(frame = dropnullfields3, catalog_connection = "MyConnection", connection_options = {"dbtable": "my_table", "database": "my_database"}, transformation_ctx = "datasink4")

# 接続定義からJDBC情報を取得
jdbc_conf = glueContext.extract_jdbc_conf(connection_name='MyConnection')

# DynamicFrameをDataFrameに変換
df = dropnullfields3.toDF()

# DataFrameをテーブルに書き込み（上書きモード）
df.write \
    .format("jdbc") \
    .option("url", jdbc_conf['url']) \
    .option("dbtable", "my_database.my_table") \
    .option("user", jdbc_conf['user']) \
    .option("password", jdbc_conf['password']) \
    .mode("overwrite") \
    .save()

job.commit()
```

例では、S3のデータをAurora Serverless MySQLに書き込んでいますが上書きできました。
Rails書き方

```.rb
# ダメな書き方
@incorrect_questions = session[:incorrect_question_ids].map { |n| Question.find(n.to_i) }

# なぜダメ？
# これだと件数ごとにQuestionを呼び出すクエリが発行されてしまって仮に100件あったら100件クエリが発行されてしまうのでこちらの方が良いかと。

# 良い書き方
@incorrect_questions = Question.where(id: session[:incorrect_question_ids].map(&:to_i))
```

Railsの考え方

・デフォルトに存在しないactionは別のcontrollerにした方が良い、というのがDHHの意見で、僕もそう思います。
・RESTとは?
・オブジェクトが自分自身の状態を持つのがオブジェクト指向の考え方の一つだよ。
・sessionを使うのは危険で、その人の状態をテーブルで用意しておけばいいのでは?
・Test◯◯という名前はrspecのファイルと勘違いされる可能性があるので避ける
・callback系(before_saveなど)は意図せずメソッドが走ったりするから、そこにロジックを書くのはあまり好ましくない。

```.rb
# ダメな書き方
def index
  @questions = Question.all
end

#なぜダメ?
# 今の件数だと問題ないと思いますが、実際のサービスでallを使うとメモリが足りなくて落ちることがあるので気をつけた方が良いです。
基本的には動的に変わるデータ（例えばユーザーが追加するもの）はselect/pluckなどで必要なカラムを制限するように癖付けた方が良いかなと思います。
```

```rb
#ダメな書き方
<%= form_for(@question_similar, url: { controller: 'question_similar', action: 'create' }) do |f| %>

#ダメな理由
url: {〜〜〜} は xxx_path で書けそうですね
```


```rb
#ダメな書き方
 def cancel_save
    question_similars.each do |question_similar|
      if question_similar.similar_word == ""
        question_similar.delete
      end
    end
  end

#.blank使え
#トランザクション大丈夫?
#delete_all の方がパフォーマンスは良いと思います
```


```rb
params[:front_article_search_form][:heart_period]
```
こういうハッシュは2次元ハッシュていうのですが、
params[:front_article_search_form]がそもそもnilだと
undefined method `[]' for nil:NilClass (NoMethodError) みたいなエラーがよく起こる。
なので書き方を十分に気をつけなきゃいけないです。

わたしだったら

```rb
article_search_form = params[:front_article_search_form]
if article_search_form.present?
 @heart_period = article_search_form[:heart_period]
end
```
Zgrab2のインストール方法と簡単な使い方

#1. Zgrab2とは
バナー収集を行うためのツールです。

#2. 環境
Virtual Box 6.1
CentOS Linux release 7.6.1810（最小構成）

#3. 入れ方
基本的には以下を見ながら進めていきます。
https://github.com/zmap/zgrab

## Goを入れる
今回は`epel`リポジトリをインストールして、`yum`でインストールします。

```bash
# epelリポジトリのインストール
yum install epel-release
```
```bash
# golangのインストール
yum install -y golang
```
これでGoインストールは完了。
念のためバージョン確認。

```bash
# Goのversionの確認
go version go1.15.2 linux/amd64
```

## $GOPATHの設定
今回はホームディレクトリ直下にする。（どこでもいい）

## zgrab2のインストール

```bash
cd $GOPATH
go get github.com/zmap/zgrab2
cd $GOPATH/src/github.com/zmap/zgrab2
make
```
make時に`fatal: git fetch-pack: expected shallow list`エラーが出た。
が、再度`make`したらすんなり完了（謎）

#4. 使い方
簡単な使い方は以下の通り

```bash
# 2222/ssh に対するバナー収集
echo 'IPaddress' | ./zgrab2 ssh -p 2222
```

#5. おわり
特につまるところはないかもしれませんが、zgrab2の入れ方を書きました。
もっといろいろな使い方ができます。気が向いたら追々まとめていきます。
［Android］scrcpy でミラーリングすると画面が見切れる問題の対処方法

# はじめに

[scrcpy](https://github.com/Genymobile/scrcpy) は Android 端末をミラーリング、画面操作をUSBまたはTCP/IP経由で行うアプリケーションです。Windows・Linux・Macで利用できるアプリケーションなので全てのAndroid開発環境で利用できます。scrcpy はかなり便利なツールでバグも少ないのですが次の問題があったので解決方法を共有します。

# 問題

解像度が 1920x1200 のを scrcpy でミラーリングすると、なぜか 1920x1080 の解像度でミラーリングされ画面が見切れて表示されてしまう。本来であれば scrcpy ではタップ操作もサポートしているが、この状態になるとタップ操作もできなくなる。

```
$ scrcpy 
2020-10-09 15:40:18.220 scrcpy[7021:244757] INFO: scrcpy 1.10 <https://github.com/Genymobile/scrcpy>
/usr/local/Cellar/scrcpy/1.10/share/scrcpy/scrcpy-server.jar: 1 file pushed. 1.3 MB/s (22662 bytes in 0.017s)
2020-10-09 15:40:19.995 scrcpy[7021:244757] INFO: Initial texture: 1920x1200
2020-10-09 15:40:20.488 scrcpy[7021:244757] INFO: New texture: 1920x1080
```

![Screen Shot 2020-10-09 at 15.47.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79387/834a90ff-10a2-af91-044f-9753d083f0df.png)
※ 画面下部のナビゲーションバーとボタンが切れて表示されてしまっている。

# 解決方法

scrcpy でミラーリングする際に 1280x800 の解像度で小さく表示するようにしてやる。ミラーリングの解像度は -m オプションで設定できるようになっています。なので次のように -m オプションを設定してやると見きれずに表示してくれます。また -m オプションを設定することでタッチ操作も正常に動作するようになります。

```
$ scrcpy -m 1280
2020-10-09 15:52:08.956 scrcpy[7177:254315] INFO: scrcpy 1.10 <https://github.com/Genymobile/scrcpy>
/usr/local/Cellar/scrcpy/1.10/share/sc...shed. 2.0 MB/s (22662 bytes in 0.011s)
2020-10-09 15:52:09.897 scrcpy[7177:254315] INFO: Initial texture: 1280x800

```

![Screen Shot 2020-10-09 at 15.46.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79387/7edb416d-697a-6bf2-1791-902e9d3ee4c9.png)
※ 画面下部のナビゲーションバーとボタンが切れずに表示できている。

# おわりに

scrcpy は便利なツールで殆どの端末で正常に動作するのですが、稀に手く動作しない端末があるみたいです。動作しない端末に遭遇した場合は本記事で紹介した解決方法を試してみると良いかなと思います。

# 参考記事

- [Github | scrcpy](https://github.com/Genymobile/scrcpy)
ぱそこん分からないマンがサーバの勉強をする　2020/10/09

# モチベーション・動機
　ぱそこんが別に好きなわけでもないのに、配属ガチャで外れを引いたばっかりに、
否応なしにぱそこん知識（）が問われるような部署に配属されてしまった。
　技術職（笑）状態で居続けるのも嫌なので、自力救済を目指して盗める知識は盗むことにした。

# なぜOracle VM VirtualBoxなのか
　隣の情シス部門の課長さんからおすすめしてもらったため。
　筆者は実のところこれが何をする何なのかも理解していないレベルであり、かろうじてPowePointでスライドを作成することができる程度の知識しかない。
　ところでサーバって何？等と思っている。

# Oracle VM VirtualBoxを取得する
　[ここ](https://www.oracle.com/jp/virtualization/technologies/vm/downloads/virtualbox-downloads.html)から取得した。どうやって見付けたかと言うと、これはもう端的にぐぐったら出てきた。Googleの検索窓に「Oracle VM VirtualBox」と入力すると、割と上の方に出てくる。

　Windowsインストーラと書かれたボタンがあったので、こいつをクリックしてダウンロードした。「はい」とか「次へ」的なボタンをぽちぽち押していくとどうもインストールできたようである。

　他に参考にしたのは[こちら](https://www.atmarkit.co.jp/ait/articles/1009/30/news122.html)。

# ところでインストールとかダウンロードとか聞くけど何が違うのかよく分からない

ざっと調べた感じだと、
・インストール：インターネットからデータやソフトウェアを取ってくること
・ダウンロード：取ってきたものを自分のパソコンに組み込んで使えるようにすること
というような感じとのこと。なるほど。

　この認識で合っているかどうかは分からないが、以下のようなイメージで理解した。
　近所のスーパーに野菜やお魚さんを買いに行く＝ダウンロード
　　↓
　買ってきた材料を冷蔵庫に直しておいたり下ごしらえしたりして、料理や食事の準備をする＝インストール

　間違ってたらツッコミお願いします。


# 次のタスク・宿題
・結局これって何するやつなん…？
　Oracle VM VirtualBoxが何をするものなのかまず調べる。

・NECのe-Learningに取り組ませてもらっているので、それをまとめる。
　ネットワークに関係する用語が分からないので、用語集でも作ればいいかもしれない。

・「環境」の意味を調べる。
　本当なら、VirtualBoxを入れた環境とかを書くべきなのだろうと思う。
　ただ、「環境」と言われたときに、どこまで詳しく書けばいいのか分からない。
　日本です！とか、パナソニックのパソコンです！は多分「環境」じゃない気がする。
　Windows10であることは分かっている。
　しかし64bit？？？？何が？？となっているし、クロック？とかに至っては謎の極み。
　一般に「環境」と言われるものはここくらいまで書くんやで、というのをまず調べる。
iosでinputタグがボコってみえるのを直す

# 課題
まず１枚目と2枚目を比べてみる。
![IMG_3121.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223280/30c94dec-d2fd-864c-481a-8e380619ff82.jpeg)
![IMG_3122.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223280/cb8bf8da-0287-7c0b-4627-db8606fd2a42.jpeg)

1枚目はデフォルトのinputタグで上の方にshadowみたいな彫りの深さが出ているバージョン
2枚目はそのiosのデフォルトの仕様に対してcssで彫りの深さを消したバージョン

# 解決法
inputタグのcssに `appearance: none;` `-webkit-appearance:none;` を追加する

```:css
input {
  appearance: none;
  -webkit-appearance:none;
}
```
BFE.dev解答記録 #88. JavaScriptでnegative indexをサポートする

> https://bfe.dev/ja はFrontEnd版のLeetCode、GAFAの面接を受けるなら練習した方がいいかなと。
> 以下は自分の練習記録です。

![スクリーンショット 2020-10-09 15.57.52.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699002/4085c8df-37a7-2b8d-e010-bee4fa7ac6a5.jpeg)


[BFE.dev#88. JavaScriptでnegative indexをサポートする](https://bigfrontend.dev/ja/problem/support-negative-Array-index) をみてみよう


## 説明をみよう

```js
const originalArr = [1,2,3]
const arr = wrap(originalArr)

arr[0] // 1
arr[1] // 2
arr[2] // 3
arr[3] // undefined
arr[-1] // 3
arr[-2] // 2
arr[-3] // 1
arr[-4] // undefined
```

新しいobjetを返して、プロパティにいい感じのindexとvalueを設定するのは可能です。例えば `{0:1, 1:2, 2:3, -1:3, -2:2, -3:1}`。

だけど下記のように元々の配列とシンクするのは不可能のようだ。

```js
arr[-1] = 5
arr // [2,3,5]
originalArr // [2,3,5]
```

getter/setterを使えばsyncできそう、このように

```js
Object.defineProperty(arr, '-1', {
  get() {
     return originalArr[2]
  },
  set(value) {
     originalArr[2] = value
  }
})

```

だけの`-1`の他、`-2`... `-originalArr.length`もあるので、全部いちいち変更するのは無理を感じる。

## Proxy は救世主

問題の説明からでは、ある意味の`Proxy`が求められるのはわかりました。

1. 全ての変更は元のarrayにする
2. negative indexのみ、戻り値をいじる

なず基本のproxyを書く

```js
function wrap(arr) {
  return new Proxy(arr, {
    get(target, prop) {
      return target[prop]
    },
    
    set(target, prop, value) {
      target[prop] = value
      return true
    }
  })
}     
```

このproxyはただproxyするだけなので、negative indexはサポートしていない、それ以外のデータはちゃんと返している。

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/hbk3pdrp7e8upnri7gc0.jpg)

## indexをいじる

propはnumberではないことを注意してください、まずnumberに変換しとこう。

```js

get(target, prop) {
  let index = parseInt(prop, 10)
  // negative index
  if (index < 0) {
    index += target.length;
    return target[index]
  }

  return target[prop]
},

set(target, prop, value) {
  let index = parseInt(prop, 10)
  // negative index
  if (index < 0) {
    index += target.length;
    // negative index overflowed, too small
    if (index < 0) {
      throw new Error('not ok')
    }
    target[index] = value
    return true
  }

  target[prop] = value
  // don't forget to return true to indicate success
  return true
}                   
```

## iterableではない！！

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/8gchbu7gljbg74f22yi9.jpg)

 `[...arr]`は動かない。。

`[...arr]` は実は`Symbol.Iterator`を実行している、上記のproxyではdata持っていないから、元の配列のinteratorを実行する必要があるので、`Function.prototype.bind()` はいいかも、このように。

```js
get(target, prop) {
  if (prop === Symbol.iterator) {
    return target[Symbol.iterator].bind(target)
  }
  ...
}
```

## 通った！

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/81tfmgog3soekjw00nvj.gif)

上記のコードはこちらで見れます。https://bigfrontend.dev/ja/problem/support-negative-Array-index/discuss/22

もし興味あれば、 BFE.devでやってみましょう
SQLアンチパターン　ランダムセレクション

# ランダムセレクション

ランダムな結果を返すソートを使用するとパフォーマンスが低下するというアンチパターン。

# 目的：サンプル行をフェッチする

大量のデータセットからランダムに結果を抽出したい。
使用する場面として以下のような場面が想定されます、

* 複数の広告からランダムで数件選択されるニュースの広告
* おみくじやくじ引きのような複数の選択肢からランダムに結果を返す場合

# アンチパターン：データをランダムにソートする

SQLでランダムな行を取得する方法として一般的な方法として、***RAND()***を用いてソートを行い、最初の行を取得する方法があげられる。

```SQL:ランダムソート
SELECT * FROM Users ORDER BY RAND() LIMIT 1;
```

昇順、降順のソートとの違いについて比較する。
昇順、降順のソートでは値の大きさによって行を並び替え、２回以上同じクエリを発行しても結果は同じとなる。

以下の方法であればインデックスのメリットも得ることができる。

```sql:昇順、降順ソート
-- 昇順ソート
SELECT * FROM Users ORDER BY user_id ASC;

-- 降順ソート
SELECT * FROM Users ORDER BY user_id DESC;
```

ランダムにソートをかける場合は値の大小に関わらず行はランダムにソートされ、順番はソートをかけるごとに変わる。
***RAND()***ではインデックスのメリットを受けることができない。

インデックスの活用はソートを高速化する手段の１つ。
インデックスを使用できない場合、***テーブルスキャン***を用いるためパフォーマンスの低下につながる。

稼働期間が長くなった場合など、データが増えるにつれ問題が出てくる場合がある。

# アンチパターンを用いても良い場合

データセットが小さい場合。
47都道府県からランダムに１つ選択する場合など、サイズが大きくなく件数が増えていく可能性が低い場合。

# 解決策：特定の順番に依存しない

ランダムなソートを使用したクエリではテーブルスキャンが発生してインデックスを使えない高コストなソートが行われる。

## １と最大値の間のランダムなキーを選択する

```sql:解決策1
SELECT b1.*
FROM Bugs AS b1
INNER JOIN (
  SELECT CEIL(RAND() * (SELECT MAX(bug_id) FROM Bugs)) AS rand_id
) AS b2 ON b1.bug_id = b2.rand_id;
```
１から主キーの最大値までの間の値をランダムに選択する。

* 主キーが１から開始されていること
* １から最大値までに欠番がないこと
* 全ての値が使用されていることが確実な場合

## 欠番の穴の後にあるキー値を選択する

```sql:解決策2
SELECT b1.*
FROM Bugs AS b1
INNER JOIN (
  SELECT CEIL(RAND() * (SELECT MAX(bug_id) FROM Bugs)) AS bug_id
) AS b2 ON b1.bug_id >= b2.bug_id
ORDER BY b1.bug_id
LIMIT 1;
```

１から主キーの最大値までの間に欠番があり、かつ乱数によって欠番キーが算出されてしまう場合。

* 乱数に一致するキー値がない場合でも算出できる
* 欠番キーの１つ上のキー値が産出される可能性が高い
* 欠番の行が少ない場合やキー値が均等に選ばれることが重要ではない場合

## 全てのキー値のリストを受け取り、ランダムに１つ選択する

アプリケーションからデータセットの主キーを全て取得し、ランダムにキー値を選択。
ランダムで取得した主キーで該当の行全体を再度取得する。

```sql:解決策3
-- アプリ側から以下のようなクエリでキーリストを取得
SELECT user_id FROM Users;

-- アプリケーション側で上記リストから乱数を取得
-- 言語によって処理方法が変わるため処理は省略

-- リストから取得した乱数で行全体を取得するクエリ
SELECT * FROM Users WHERE user_id = 乱数;
```
※言語などによって方法が異なるためクエリのみサンプルを記載。

* テーブル全体のソートを回避でき、テーブルスキャンの必要がない
* 各キー値が均等に選択される
* データベースから全てのキーを取得するとリストが大きくなりすぎる可能性がある
* １回目はリストを取得、２回目は選択したキーで行の取得と２回クエリを実行する必要がある

## オフセットを用いてランダムに行を選択する

データセットの行数をカウントし、０と行数までの間の乱数を返す方法。

```sql:解決策4
-- アプリ側から以下のようなクエリで乱数を取得
SELECT FLOOR(RAND() * (SELECT COUNT(*) FROM Users));

-- 言語によって処理方法が変わるため処理は省略

-- 取得した乱数で行全体を取得するクエリ
SELECT * FROM Users LIMIT 1 OFFSET 乱数;
```
※言語などによって方法が異なるためクエリのみサンプルを記載。

* キー値が連続していることを前提としない場合
* 各行が均等に選択される必要がある場合
* キーリスト全体を取得する必要がない
* 複数件の取得だとクエリの発行回数が増加

# まとめ

クエリには最適化できないものもあります。最適化できない場合は、別のアプローチを考えましょう。

# 参考文献

[SQLアンチパターン](
https://www.amazon.co.jp/SQL%E3%82%A2%E3%83%B3%E3%83%81%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3-Bill-Karwin/dp/4873115892/ref=sr_1_1?adgrpid=104444684056&dchild=1&gclid=CjwKCAjw4_H6BRALEiwAvgfzqy-f83NTsyQkauo7gn6ysgAPmJvKyvuI5FaXFnxFmhVfCzCRRACsaBoCY-oQAvD_BwE&hvadid=447984765572&hvdev=c&hvlocphy=1009332&hvnetw=g&hvqmt=e&hvrand=13417269104929133208&hvtargid=kwd-335484809678&hydadcr=27264_11561110&jp-ad-ap=0&keywords=sql%E3%82%A2%E3%83%B3%E3%83%81%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3&qid=1599934568&sr=8-1&tag=googhydr-22)

![参考文献.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257405/b46d45ab-75ec-a620-eeb2-a422f6b1e659.jpeg)
[Rails] Couldn't find with 'id'=:id　でupdateアクションが実行されない

#解決方法

###@を消すと解消される

修正前

```ruby:controller.rb
  def update
    @gear = find_gear_by_id
    @gear.update(gear_params)
    redirect_to gears_path
    flash[:notice] = "編集が完了しました"
  end
```
⇓
修正後

```ruby:controller.rb
  def update
    gear = find_gear_by_id
    gear.update(gear_params)
    redirect_to gears_path
    flash[:notice] = "編集が完了しました"
  end
```

詳しい理由がわからない。。。
dotnet core(C#言語)で、コンソールの多重起動制御(Mutexを使う方法)をLinuxでも行う

## Mutexクラスを使って多重起動制御を行う

Windowsだと、普通に```new Mutex(false, "hogehoge");```とすれば、多重制御処理を書けてしまいますが、Linuxだと発動したり発動しなかったり。

##多重制御が効く

```
/usr/local/bin/Hoge/Hoge &
/usr/local/bin/Hoge/Hoge &
```

## 多重制御が効かない

```cron
0 0 * * * root /usr/local/bin/Hoge/Hoge
5 0 * * * root /usr/local/bin/Hoge/Hoge
```

## Mutexクラスで多重起動制御できるようにする

```Global\``` 文字列を付けるだけみたいです。

```c#
var mutex = new System.Threading.Mutex(false, @"Global\\Hoge");
try {
    handle = mutex.WaitOne(0, false);
}
catch( System.Threading.AbandonedMutexException) {
    handle = true
}

if( !handle ) {
    // 多重起動
    return;
}

````

cronでもちゃんと制御してくれました！！

* dotnet core 3.1 / centos7, centos8 で確認
新しい Google Play Console では「サービスとAPI」というメニューは別の名前になっていた件

# 概要

<img width="720" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34926/df44bddf-5054-dbe9-a2fd-ca30d4244587.png"/>

今までの GooglePlayConsole は 2020年11月2日 をもってサービスを終了し、新しい GooglePlayConsole になります。

最近は新しい方の GooglePlayConsole に使っていました。

新しいと言ってもまあだいたい雰囲気で問題なく使えていたのですが、従来の GooglePlayConsole でいうところの以下のメニューが行方不明に…

**開発ツール - サービスとAPI**

<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34926/dffcaae8-992e-d0d5-8787-5ce907c61d19.png"/>

どこにいったのかわからず、調べようにも検索ワードが微妙すぎてうまく検索できず、
ドキュメントを見ても従来の GooglePlayConsole のスクリーンショットがはられており困っていたのですが、
さっきたまたまメニューをポチポチしてたら見つけることができました。

めんどくさがらずに、最初から全部のメニューをポチポチしておけばよかった…

ちなみに、一度新しい GooglePlayConsole に切り替えたとしても、サービス終了するまでは
「従来の Play コンソールを使用」というところから今までの GooglePlayConsole を使うことはできます。

しかし従来の GooglePlayConsole が使えなくなったら「どこから設定するのかわからない！」となってしまうのでどうしても見つけたかった次第です。

# 場所

従来の GooglePlayConsole の「サービスとAPI」には以下の４項目がありました。

- ライセンスとアプリ内課金
- リアルタイム デベロッパー通知
- Google Play ゲーム サービス
- Google 検索のインデックスにアプリを登録

それぞれ新しい GooglePlayConsole ではどこにあるのかを書いておきます。

### ライセンスとアプリ内課金、リアルタイム デベロッパー通知

こちらの２つは同じ画面内にあります。

**<font color="red">収益化 - 収益化のセットアップ</font>**

<img width="720" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34926/eccb86ae-0044-18ac-02aa-20dae0a6b13f.png"/>

### Google Play ゲーム サービス

**<font color="red">検索ボックスに「ゲーム」と入力 - Play ゲームサービスの設定</font>**
（メニューから遷移する方法がわかりませんでした…）

<img width="720" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34926/193036ba-1ae7-259c-bfdd-fd92dc501641.png"/>


### Google 検索のインデックスにアプリを登録

**<font color="red">設定 - 詳細設定 - アプリのインデックス登録</font>**

![スクリーンショット 2020-10-09 13.07.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34926/53ed4f5e-a1ce-8758-6fba-1e1c816afbac.png)
dufコマンドでいい感じにディスクの使用量を表示する方法

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7565/51f046e0-f125-34f8-8374-57ac47e34267.png)

## macOSでインストールする方法

```
brew tap muesli/tap && brew install duf
```

## Arch Linuxでインストールする方法

```
sudo pacman -Sy duf
```

## 使い方

```
duf
```


## github

https://github.com/muesli/duf
SELECT文を使用したデータの取得

現在勉強しているオラクルマスターブロンズ（SQL）についてまとめたものです。
自分のアウトプット用なので見やすさなどは期待しないでください。

# SELECT文の基本

SELECT文では、以下の3つの機能を使用してデータを取り出す。

**射影**・・・**特定の列のみ**を取り出す。
**選択**・・・**特定の行のみ**を取り出す。
**結合**・・・**複数の表を関連付けて**取り出す。

SELECT文の基本構文

|  |  |
|:--|:--|
| SELECT | 列名 |
| FROM | 表名; |

複数の列からデータを取り出す場合は、列名を**,（カンマ）で区切って**指定する。
その際、**指定した順番で列が表示される**。

全ての列のデータを取り出したい場合は、**アスタリスク**を指定する。
その際、**表に定義されている列の順番**で表示される。

列名などを確認する際に**DESCRIBEコマンド**を使用すると、表に定義されている列の情報を一覧で確認できる。

#　SELECT句の色々な指定方法

## 算術式の使用

取り出す列の値が数値や日付データの場合は、SELECT句に算術式を指定することで計算結果を取り出すことができる。
算術式には**列名、定数値**（**リテラル**：SELECT文に含まれる文字、数値または日付）、**算術演算子**を指定できる。
なお、**算術式の中に１つでもNULL値が含まれていると、その算術式の結果もNULL値になる**。

## 列別名の使用

SELECT句に列名や算術式を指定してSQL文を実行すると、その実行結果に表示される列見出しには、指定した列名や算術式が**大文字**で表示される。
列名が分かりにくい場合や列見出しの大文字・小文字を区別したい場合、複雑な算術式を列見出しとして表示したくない場合などは**列別名**を指定して列見出しを変更できる。

列別名の設定方法

1.　列名または算術式の後ろに、**1つ以上の空白**を入れる。
2.　列名または算術式の後ろに、**ASキーワード**を指定する。

なお、いずれの方法でも、**列別名にスペースや特殊文字を使用する場合、また大文字・小文字を区別する必要がある場合**は、列別名を**"（二重引用符）で囲む**必要がある。

## 連結演算子の使用

SELECT句に**||（連結演算子）**を指定すると、複数の列値やリテラル、算術式の結果を連結する文字式を記述できる。
なお、文字式の中に**文字リテラル**や**日付リテラル**を指定する場合は、それらを**'（一重引用符）で囲む**必要がある。

また、文字列リテラルの一部に一重引用符を使用したい場合は、**代替引用符(q)演算子**を使う。
この演算子を使用すると、SQL文内で以下の文字を独自の**引用符デミリタ**として指定できる。

- **任意のシングルバイト文字やダブルバイト文字**
- **[]、{}、()、<>の各組合せ**

例　[]を引用符デミリタとして使用：q'['文字リテラル]'

## 重複行の削除

実行結果から重複行を削除する場合は、SELECT句のSELECTキーワードの直後に**DISTINCTキーワード**を指定する（デフォルトではすべての行が表示される**ALLキーワード**になっている）。

DISTINCTキーワードは、複数の列を取り出す際にも指定できる。
この場合は**指定した列の値の組み合わせが一意になる行**のみが取り出される。
なお、DISTINCTキーワードは**SELECTキーワードの直後に1度だけ**記述できる。
標的型メール攻撃「Emotet（エモテット）」マルウェア（ウイルス）の感染対策について

世の中がコロナ禍で悪戦苦闘している最中、ネットの世界でも許しがたい悪行が流行しています。
標的型メール攻撃のEmotet（エモテット）である。

よくある添付ファイル型の攻撃なのですが、なかなか判別が出来ないような巧妙な手口です。
実際の知り合いから「請求書.doc」や「見積書.doc」の様な添付ファイル付きで、よくある自然なビジネス文面で送られてきます。
昨今、機密文書はパスワード付き圧縮ファイルでやり取りする習慣があれは疑いようがあるが、慣習化されていない業界、企業も未だ多くあります。

######【実際に届いたEmotetマルウェア添付のメール文面】
>○○　様
>お世話になっております。
>
>09月度ご請求書をDOCファイルにて添付いたします。
>ご確認の程、よろしくお願い致します。
>
>原本は郵送にて送付致しますのでよろしくお願い致します。
>
>以上、よろしくお願い致します。
>
>---------
> シグニチャ

※添付ファイルの代わりにURLリンク付きメールのケースもあり
※満足度アンケート調査を装うケースもあり

また、実際の知り合いというは、連絡帳や送受信履歴から抽出しているものと思われます。
そしてこの貼付ファイルを開くことで、同じく連絡帳や送受信履歴から知り合いに同様に拡散し、パソコン内部に保存されているパスワードやクレジットカード情報を盗み取られる可能性があります。

現時点では、調べる限り添付されたWORDやEXCELを開かなければ感染しないため、駆除や防御は簡単そうですが、如何せん、実在の知り合いの名前から疑いようのない完全な日本語文面でメールが届くため、疑うことなく開いてしまう方が多く報告されています。

## 現状、Emotetの代表的な以下の流れで感染されます。
1. 添付ファイル付きメールを受信する
<br />　↓
2. メールに添付されたWordファイルなどのOffice文書を開封する
<br />　↓
3. マクロの有効を許可する
<br />　↓
4. マクロ経由でWMI（Windows Management Infrastructure）が実行され、勝手にPowerShell が起動する
<br />　↓
5. PowerShellがEmotetマルウェアのダウンロードと実行を行う
<br />　↓
6. Emotetマルウェアに感染する

##感染の確認方法
一般社団法人JPCERTコーディネーションセンタートレンドから感染チェックツール「EmoCheck（エモチェック）」が無償リリースされており、こちらのツールを利用しEmotetの感染有無をチェックすることが可能です
https://github.com/JPCERTCC/EmoCheck/releases

また、有償のウィルス対策ソフトにて、検出/駆除が可能です。
（検出出来ないケースもあるようです。）
カスペルスキー社のウィルスソフトが本件について優秀とのこと。
※実際に検出/駆除を確認しました。

##感染防止するには

- 怪しいファイルは開かない
- 不用意にリンクURLはクリックしない
- 万が一開いたとしてもマクロの有効化は行わない
- 有償のウィルス対策ソフトをインストールし常駐実行する

##さらに感染防止を強化する場合は、

###Officeマクロ機能の無効化
Excel/Wordを起動する。
画面上部メニューから
【ファイル】→【オプション】→【セキュリティセンター】→【セキュリティセンターの設定】
を選択します。

左メニュー部から、【マクロの設定】を選択し、「警告を表示せずにマクロを無効にする」を選択してください。
 ※設定は、Excel、Wordを使っている場合はそれぞれ必要です。

###Windows PowerShellの無効化
PowerShellはシステム管理者が自動化や構成管理に利用する管理ツールです。
「設定」アプリを開き、「更新とセキュリティ」「開発者向け」の「PowerShell」の部分にチェックをはずし「適用」をクリックします。


上記はあくまで現時点での対処法です。
感染が疑われる場合は、専門家に相談する。もしくは、Windowsの初期化を行うことをおすすめします。

####【参考サイト】
IPA情報処理推進機構
https://www.ipa.go.jp/security/announce/20191202.html
Docker Compose が docker.credentials.errors.InitializationError のエラー表示で起動しない

####TL,DR

Dockerアイコンのメニューの「Troubleshoot」を選択、「Reset to factory defaults」ボタンで初期化すれば直る

####エラーの内容

```
$ docker-compose up -d --build
Building ubuntu
Traceback (most recent call last):
  File "docker-compose", line 3, in <module>
  File "compose/cli/main.py", line 67, in main
  File "compose/cli/main.py", line 126, in perform_command
  File "compose/cli/main.py", line 1070, in up
  File "compose/cli/main.py", line 1066, in up
  File "compose/project.py", line 615, in up
  File "compose/service.py", line 346, in ensure_image_exists
  File "compose/service.py", line 1125, in build
  File "site-packages/docker/api/build.py", line 261, in build
  File "site-packages/docker/api/build.py", line 308, in _set_auth_headers
  File "site-packages/docker/auth.py", line 311, in get_all_credentials
  File "site-packages/docker/auth.py", line 262, in _resolve_authconfig_credstore
  File "site-packages/docker/auth.py", line 287, in _get_store_instance
  File "site-packages/docker/credentials/store.py", line 25, in __init__
docker.credentials.errors.InitializationError: docker-credential-gcloud not installed or not available in PATH
[56567] Failed to execute script docker-compose
```

####手順
ステップ1
![pic1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41095/c64b0a21-adc0-d40e-c590-f275e92cb0d9.png)
ステップ2
![pic2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41095/032f5c5c-7bea-d4c0-c9a1-049a072a46cd.png)
Git メモ

Gitに関する個人用メモ。


#全体の流れ

作業領域（ワーキングツリー）
　↓
ステージング領域（インデックス）
　↓
ローカルリポジトリ
　↓
リモートリポジトリ（GitHub等）


#作業領域→ステージング領域

```
$ git add <ファイル名>
```
指定したファイルをステージング領域に追加。

```
$ git add .
```
変更されたファイルや新規作成されたファイルを、一括でステージング領域に追加。

```
$ git rm <ファイル名>
```
ファイルの削除をステージング領域に記録。


#ステージング領域→ローカルリポジトリ

```
$ git commit
```
ステージング領域のファイルを、ローカルリポジトリに登録（コミット）する。コマンド実行後にコメントの入力を求められる。

```
$ git commit -m "コメント"
```
コミットとコメント入力を同時に行う。


#ローカルリポジトリ→リモートリポジトリ

1. リモートリポジトリ（GitHub等）のURL取得
1. ローカルリポジトリからプッシュ

の流れで行う。

##リモートリポジトリのURL取得

```
$ git remote add origin <リポジトリのURL>
```

originは任意の文字で良い。URLをoriginに格納するイメージ。

##ローカルリポジトリからプッシュ

```
$ git push origin master
```

masterは、リモートリポジトリのブランチ名を表す。
origin(=リポジトリURL)／master(=ブランチ名)　にファイルを格納するイメージ。


#リモートリポジトリ→ローカル にファイルを持ってくる

1. ローカルリポジトリが存在していない場合
2. ローカルリポジトリが既に存在する場合

でやり方が異なる。

##ローカルリポジトリが存在していない場合

```
$ git clone <URL>
```
これにより、ローカルリポジトリが作成される。
URLの後にディレクトリ名を指定すると、指定した名前で作成される。

##ローカルリポジトリが既に存在する場合

```
$ git remote add origin <URL>
$ git pull origin master
```

こちらは、他の人が更新したファイル等、必要なものだけ持ってくるイメージ。
（因みに、空のディレクトリを作成後に`$ git init`して、その後に上のコマンドを実行すると`$ git clone`と同じ結果になる。）


#今の状態を確認する

```
$ git status
```


#Branch

##Branchの作成

```
$ git checkout -b <ブランチ名>
```

この場合、ブランチ作成と同時に移動する。
単に作成する場合は下記。

```
$ git branch <ブランチ名>
```

##Branchの一覧表示

```
$ git branch
```

##Branchの移動

```
$ git checkout <ブランチ名>
```

##Branchの削除

```
$ git branch -d <ブランチ名>
```

##Branchのマージ

```
$ git merge <ブランチ名>
```


#commitの履歴を見る（ローカルリポジトリ）

```
$ git log
```
基本形

```
$ git log --oneline
```
一行で表示する

```
$ git log -n 3
```
数を指定して表示(新しい順)

```
$ git log -p
```
差分を表示する

```
$ git log -p <ファイル名>
```
ファイルの差分を表示する


#差分の確認

##作業領域とステージング領域の差分

```
$ git diff
```

##ステージング領域とローカルリポジトリの差分

```
$ git diff HEAD
```


#リモートリポジトリの確認、変更

##リモートリポジトリの名前とURLを表示

```
$ git remote -v
```

##リモートリポジトリのURLを変更

```
$ git remote set-url origin <URL>
```


#Gitの管理対象からの除外

+ まだGitの管理対象ではない場合
+ 既にGitの管理対象となっている場合
+ 既にGitの管理対象となっており、ファイルの物理削除も行う場合

で、少々手順が異なる。

##まだGitの管理対象ではない場合

`.gitignore`ファイルを作成し、対象外にしたいファイルやディレクトリを記載する。

##既にGitの管理対象となっている場合

`.gitignore`ファイルへの記入＋以下のコマンドを実施

```
$ git rm --cached <ファイル名>
```
`-r`オプションを付けるとディレクトリを対象にできる。

##既にGitの管理対象となっており、ファイルの物理削除も行う場合

```
$ git rm <ファイル名>
```
この場合ファイル自体が無くなるので、`.gitignore`ファイルへの記載は不要。
また、`-r`オプションを付けるとディレクトリを対象にできる。


#変更の取り消し

この方の説明が非常に分かり易い。
https://qiita.com/shuntaro_tamura/items/db1aef9cf9d78db50ffe
wsimportのエラー対応(クラス/インタフェースがすでに使用されています/A class/interface with the same name "xxx" is already in use)

Java用のSoapクライアントコードの自動生成に利用する`wsimport`で発生したエラーメッセージが日本語になっていて、日本語情報だと見つからず、ちょっと遠回りしたので備考。

# エラーメッセージ

## 日本語だと

```bash
[ERROR] 同じ名前"xxxxxx.SampleResponse"のクラス/インタフェースがすでに使用されています。
この競合を解決するには、クラス・カスタマイズを使用してください。
```
## 英語だと

```bash
[ERROR] A class/interface with the same name "xxx" is already in use. 
Use a class customization to resolve this conflict.
```

# 原因と対策

原因は2つ考えられる。

- `-p`オプションを指定してパッケージ名を任意に指定したことにより名称が重複
- wsdl内でname属性の値が重複している・・・サーバ側が.NET(拡張子asmx)だと発生するのかも

前者の場合は`-p`オプションを指定せず(=つまり`wsdl`にしたがって)に`wsimport`を実行すれば解決。

自分の場合は後者だった。具体的には以下の`SampleResponse`のように同じname()を持つ定義があるのが悪い模様。
片方の定義を削除すると重複エラーは消えるが、メソッドから参照されているので結局エラーになる。

```xml:hoge.wsdl
<s:element name="SampleResponse">
  <s:complexType>
    <s:sequence>
      <s:element minOccurs="1" maxOccurs="1" name="Response" nillable="true" type="tns:SampleResponse" />
    </s:sequence>
  </s:complexType>
</s:element>
<s:complexType name="SampleResponse">
  <s:sequence>
    <s:element minOccurs="0" maxOccurs="1" name="Result" type="tns:SampleResponseResult" />
    <s:element minOccurs="0" maxOccurs="1" name="ApplicationResponse" type="tns:SampleResponseApplicationResponse" />
  </s:sequence>
</s:complexType>
```

この場合の対策は、`wsimport`コマンドに以下のオプションを指定すること。-Bの後には空白ないので注意。

```bash
-B-XautoNameResolution
```

なお、この場合は、`SampleResponse`と`SampleResponse2`というクラスが生成されるので適宜修正する。

# 参考

- [Problem generating Java SOAP web services client with JDK tool wsimport from a WSDL generated by a .NET 2.0 application - Stack Overflow](https://stackoverflow.com/questions/785945/problem-generating-java-soap-web-services-client-with-jdk-tool-wsimport-from-a-w)
- [よくあるご質問(サポートFAQ)・詳細: よくあるご質問(サポートFAQ)・検索一覧 | NEC](https://www.support.nec.co.jp/View.aspx?NoClear=on&id=3150106140)
Array(Element)型を理解しよう！

Array(Element)型について学習したので、アウトプットしていきます
※以下の内容は、学習内容のアウトプット用のため、誤りがある場合があります。予めご了承ください

#Array(Element)型とは？
***Array(Element)型を一言でいうと、配列を表す型のことです。***


例えば
Array(Element)型は[1,2,3]のように配列リテラルを用いて表現することができます

```swift:qiita.rbvar 
1.let a = [a,b,c]
2.let b = [1,2,3]

```
Array(Element)型を用いることで、便利なのが
Array(Element)型の値に対して、***要素の更新、追加、結合、削除***を行えることです。

それでは一つずつ深堀りしていきましょう！

#要素の更新

```swift:qiita.rbvar 
               //0 1 2 
1.var numbers = [1,2,3]
2.numbers[1] = [4] // 1番目である２の更新を行っている
numbers// [1,4,3]

```
#要素の追加
***末尾***に要素を追加するには***append(_:)***メソッドを使用します
次の例は、[String]型の"d"を追加していいます

```swift:qiita.rbvar 
1.let strings  = ["a","b","c"]
2.strings append(d)//["a","b","c","d"]
```
また、***任意***の場所に追加することができます。
***任意***の場所に要素を追加するには、***insert(_: at:1)***、メソッドを使用します。

次の例では、nsert(_: at:1)***、メソッドをし使用し、２番目に"b"を追加しています。

```swift:qiita.rbvar 
1.let strings  = ["a","c","d"]
2.strings insert("b",at1)//["a","b","c","d"]
```
#要素の結合
要素の結合は、＋演算子でArray(Element)型の値を結合することができます。

```swift:qiita.rbvar 
1.let strings1 = ["あ","い","う"]//[String型]
2.let c =["え","お"]//[String型]

let result = strings1+let c //["あ","い","う","え","お"]
```
#要素の削除
要素の削除には、任意の場所を削除する***remove(at:)***、最後の要素を削除する***removeLast()***、全ての要素を削除するremoveAll()メソッドの３つが用意されています。

```swift:qiita.rbvar 
var strings = ["あ","い","う","え","お"]

strings.remove(at:2)
strings//["あ","い","え","お"]//"う"が削除

strings.removeLast()
strings//["あ","い","え"]//末尾の"お"が削除

strings.removeAll()
strings//()

```
SQLで今日の予約一覧を取り出す方法



こんにちは。

SQLで「今日公開している映画の一覧」や「今日ホテルに泊まりに来ているユーザー一覧」を
表示させます。

カラムのstartからendで範囲を指定。

| カラム | 型 |
|:-:|:-:|
| start  | date  |
| end  |  date |


今回は「今日ホテルに泊まりに来ているユーザー一覧」を予約としてresevationsテーブルを取り出します。

```
"SELECT * FROM  users JOIN reservations ON users.id = reservations.user_id WHERE current_date BETWEEN reservations.start AND reservations.end"

```

usersテーブルを結合しててわかりにくいので大事なところだけ切り取ります。


```
WHERE current_date BETWEEN reservations.start AND reservations.end
```


これでstartからendの範囲の値を取り出すことができます:sunny:
EclipseLink JPAでの自動トリムを止める方法

# 背景

最近仕事でWebSphere Liberty (Open Liberty)を利用する事になりましたが、JPAでデータベースの項目を取得するときに標準ではCHAR型のスペースが自動トリムされていることが判明しました。CHAR(3)の項目に、"a&nbsp;&nbsp;"(後ろにスペース2つ)や"&nbsp;&nbsp;&nbsp;"(スペース3つ)を意図的に設定しているときに、"a"や""(空文字列)と取得されてしまいます。調べると、これはEclispeLinkの標準仕様だそうで。

#Solution
persistence.xmlかなにかの設定で簡単に変更できると思いきや単純な設定はなさそうでした。はまってしまいましたが、その解決方法としてはSessionCustomizerを作成する必要がありました。

###SessionCustomizerの作成
JavaEE APIでの対応が難しく、EclipseLinkのAPIを利用した制御が必要です。

```
import org.eclipse.persistence.config.SessionCustomizer;
import org.eclipse.persistence.sessions.Session;

public class YOURSessionCustomizer implements SessionCustomizer{
	public void customize(Session session) {
		session.getLogin().setShouldTrimStrings(false);
	}
}
```

###persistence.xmlの設定
```
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<!-- 中略 -->
	<persistence-unit name="ABC" transaction-type="JTA">
<!-- 中略 -->
		<properties>
			<!-- EclipseLink settings -->
			<property name="eclipselink.validate-existence" value="true"/>
			<property name="eclipselink.logging.level" value="ALL" />
			<property name="eclipselink.logging.sql" value="ALL"/>
			<property name="eclipselink.logging.level.sql" value="ALL"/>
			<property name="eclipselink.logging.parameters" value="true"/>
<!-- 追加したところ -->
			<property name="eclipselink.session.customizer" value="package.YOURSessionCustomizer"/>
<!-- 追加したところ -->
		</properties>
	</persistence-unit>
</persistence>
```

###Libertyのserver.xmlの設定変更
```
<server>
<!-- 中略 -->
    <webApplication contextRoot="app" id="webapp" location="webapp.war" name="webapp">
        <classloader apiTypeVisibility="spec, ibm-api, stable, third-party" />
    </webApplication>
</server>
```
参考:Java EE アプリケーションからのサード・パーティー API へのアクセス
https://www.ibm.com/support/knowledgecenter/ja/SSEQTP_liberty/com.ibm.websphere.wlp.doc/ae/twlp_classloader_3p_apis.html

###(option)pox.xmlの修正
EclipseLinkのAPIのが必要ですので、プロジェクトのクラスパスの通し方に応じて設定してください。
EclopseLinkはLibertyに含まれますので`provided`にしてます。

```
        <dependency>
            <groupId>org.eclipse.persistence</groupId>
            <artifactId>eclipselink</artifactId>
            <version>2.6.9</version>
            <scope>provided</scope>
        </dependency>
```
bitnamiにCertbot-auto入れるときのメモ

しょっちゅう忘れるのでメモ

Rootユーザーになる
```sudo su -```

ドメインを環境変数に
```DOMAIN=sample.com```

certbotをインストール
```apt-get -y install letsencrypt python-letsencrypt-apache```

パスが通ってるか確認
```which certbot-auto```

証明書発行（WordPressの場合）
```certbot-auto certonly --webroot -w /opt/bitnami/apps/wordpress/htdocs -d $DOMAIN```

シンボリックリンク
```ln -s /etc/letsencrypt/live/$DOMAIN/privkey.pem /opt/bitnami/apache2/conf/server.key
ln -s /etc/letsencrypt/live/$DOMAIN/fullchain.pem /opt/bitnami/apache2/conf/server.crt```

apache再起動
```/opt/bitnami/ctlscript.sh restart apache```

cron設定
```crontab -e
0 0 * * 1 /usr/bin/certbot-auto renew --deploy-hook "/opt/bitnami/ctlscript.sh restart apache"```