OmniAICreator/Qiita-1.07M huggingface dataset:
ターミナルによるDjangoアプリケーション作成まで（開発環境）

#■環境
　Windows10home
　Python3.7
　Pycharm

#■手順

##①仮想環境の作成（コマンドプロンプト）

###1)作成したいディレクトリへ移動
　例：C:\python_project　へ移動

```
　C:\Users>cd C:\python_project
```


###2)仮想環境作成（python -m venv(仮想環境名)）
　例：venv_python_dev　という仮想環境作成

```
　C:\python_project>python -m venv venv_python_dev
```

###3)仮想環境に入る（仮想内Scriptsの「activate.bat」実行）

```
　C:\python_project>cd venv_python_dev\Scripts
　C:\python_project\venv_python_dev\Scripts>activate.bat
　(venv_python_dev) C:\python_project\venv_python_dev\Scripts>
```

###4)抜ける時は、「deactivate」


##②Djangoのインストール（ターミナル）
 pip install Django

```
 　(venv_python_dev) C:\python_project\venv_python_dev\Scripts>pip install Django
```

　Successfully ・・・・・・installed Django・・・・
　出たらOK
　
 Djangoバージョン確認

```
　python -m django --version
  3.0.3
```

##③Djnagoプロジェクト作成

###1)作成したいディレクトリ（ここでは仮想環境）に移動

```
　(venv_python_dev) C:\python_project\venv_python_dev\Scripts>cd 　
　(venv_python_dev) 　C:\python_project\venv_python_dev>C:\python_project\venv_python_dev
```

###2)プロジェクト作成（ここではPrivate_Diary_project）

```
　(venv_python_dev) C:\python_project\venv_python_dev>django-admin startproject Private_Diary_project
```

##④Djangoアプリケーションの作成

### 1)ここでは、プロジェクトフォルダに作りたいのでディレクトリ移動

```
　(venv_python_dev) C:\python_project\venv_python_dev>cd C:\python_project\venv_python_dev\Private_Diary_project
(venv_python_dev) C:\python_project\venv_python_dev\Private_Diary_project>
```

### 2)アプリケーション作成
　例：app_private_diary

```
(venv_python_dev) C:\python_project\venv_python_dev\Private_Diary_project>python C:\python_project\venv_python_dev\Private_Diary_project\manage.py startapp app_private_diary
```

##⑤pycharmでフォルダ確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547159/594f3bb5-c93e-0e76-40b8-6b4e31f7d80d.png)
　
###　【ファイル構成】
　プロジェクト名
　　　　-プロジェクト名
　　　　　__init__.py
　　　　　setting.py
　　　　　urls.py
　　　　　wsgi.py
　　　　-manage.py
　　　　-アプリケーション名
　　　　　migrations
　　　　　__int__.py
　　　　　admin.py
　　　　　apps.py
　　　　　models.py
　　　　　tests.py
　　　　　views.py

##以上　出来上がり。
Rails + heroku 無料でアプリケーションを公開

##前提
- Mac OS
- Ruby on Rails
- Herokuアカウント作成済
登録がまだの方は[Heroku公式サイト](https://jp.heroku.com/)から登録してください。

[Herokuとは](https://jp.heroku.com/what)、`PaaS（Platform as a Service）`と呼ばれるサービスで、
アプリケーションを実行するためのプラットフォーム。
無料でさくっと公開した方はオススメ。

- 未認証アカウントの場合：無料 dyno 時間は 550 時間/月まで
(クレジットカード登録をした場合：+ 450 時間/月が付与 合計で1,000時間/月 利用可能)
- 必要な RAM は 1 dyno あたり 512 MB
- 30分アクセスがないとスリープしてしまう(スリープ中はdynoを消費しない)
- HerokuPostgreSQLは、10000行までの制限あり

詳しくは下記公式のページ参照してください。
https://jp.heroku.com/what

##1. Heroku CLI インストール
```terminal:terminal
$ brew tap heroku/brew && brew install heroku
```
コマンドで実行するか、下記のリンクからOSを指定してダウンロードもできる。
https://devcenter.heroku.com/articles/heroku-cli
個人的にはターミナルがおすすめ。

##2. Herokuにログイン
```terminal:terminal
$ heroku login
heroku: Press any key to open up the browser to login or q to exit: 
Opening browser to https://cli-auth.heroku.com/************************
Logging in... done
Logged in as (登録したメールアドレス)
```
`$ heroku login`コマンド入力後、リターンキーを押す。
(任意のキーと書いてるのでおそらくどれでも良いかと...)
するとherokuのログイン画面がブラウザーで表示されるため、ログインする。
<img width="591" alt="ss.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531099/77b36d5e-f9cc-59bc-bff3-14cd95306ce7.png">
画像のように表示されればOK。
この時点でターミナル側でも`Logged in as (登録したメールアドレス)`と表示されているはず。

##3. PostgreSQLのインストールと設定
3-1. PostgreSQLのインストール

```terminal:terminal
$ brew install postgresql
```
HerokuではPostgreSQLデータベースを使う為、
インストールされてない方はここでインストール。

3-2. PostgreSQLの設定

```ruby:Gemfile
gem 'sqlite3', '~>1.3.6' # この行を削除しdevelopment内に移動

# 省略
group :development, :test do
  gem 'sqlite3', '~>1.3.6' # 開発環境のみ
end
# 省略
group :production do
  gem 'pg' # 本番環境のみ
end
# 省略
```
HerokuではSQLiteがサポートされていないため、
`sqlite3 gem`を開発環境(development)内に移動させ
本番環境(production)内に`pg gem`をインストールし
RailsがPostgreSQLと通信できるようにする。

```terminal:terminal
$ bundle install --without production
```
Gemfileを更新したので最後にbundle installを忘れずに。
今回は`--without production`を追記してますが、
こうすることで`pg gem`はローカル環境には反映されないようになります。

##4. Herokuにデプロイ
4-1. heroku上にアプリケーションを作成

```terminal:terminal
$ heroku create 任意のアプリ名
```
アプリ名を入力しない場合は自動で割り当てられます。(後で変更可能)

4-2. Gitを使ってHerokuにリポジトリをプッシュ

```terminal:terminal
$ git add .
$ git commit -m "initial commit"
$ git push heroku master
・
・
・
・　# 省略
remote: Verifying deploy... done.　# このように表示されればOK！
To https://git.heroku.com/.git
 * [new branch]   master -> master
```

4-3. migrationの実行

```terminal:terminal
$ heroku run rails db:migrate
```
ローカル環境で行なっていた`rails db:migrate`を本番環境でも同じことをしてあげる。

##5. サイトにアクセス
```terminal:terminal
$ heroku open
```
上記コマンドを実行すると、ブラウザーでWebページを表示してくれます。


以上！！！！！！！！！！パチパチ
【AWS】AWS ソリューションアーキテクトアソシエイトに合格した勉強法

#はじめに
仕事で1年くらい前からAWSの環境のシステム保守運用をするようになりました。
それに伴いAWSの資格の取得を目指すようになりました。
2019年11月ごろから本格的に勉強を始め、2020年1月25日に合格しました。

#試験結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266541/4e41af31-e3f3-be8c-b1f0-a0c464bccd10.png)
ギリギリ合格しました！

#勉強したこと
##これだけでOK！ AWS 認定ソリューションアーキテクト – アソシエイト試験突破講座（初心者向け22時間完全コース） 
https://www.udemy.com/course/aws-associate/

上記のudemyのコースを一通り自分のAWS環境を使って行いました。udemyのコースは頻繁に値下げしており、私は1800円くらいで購入しました。
手を動かしながらやるのでAWSの主要機能の理解が進みました。

##徹底攻略 AWS認定 ソリューションアーキテクト – アソシエイト教科書
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266541/fb934088-1f8f-f7ab-8d14-e68db779a180.png)

udemyのコースが終わった後一通りやりました。間違えた箇所は何度かやり直しました。

##AWSの模擬試験
https://aws.amazon.com/jp/certification/certified-solutions-architect-associate/

AWSの模擬試験を2回受けました。1回2000円でした。
解答は出なく最後にスコアのみ表示されます。1回目が50%くらいで、2回目が84%でした。
問題をスクリーンショット取りながら受験するのが、受験後に問題の見直しができるのでおすすめです。

#最後に
AWSの資格に合格できたのは自信になりました。
次はソリューションアーキテクトプロフェッショナルの合格を目指してがんばります！
全て同じ値の２次元配列を作る時の注意点

# ２次元配列でハマったところ

全ての要素の値が0である２次元配列を作り、それぞれの要素をカウントアップしていく場合に、ある行のある列を指定して値を更新すると全ての行の同一列が更新されてしまったので、今後同じところでハマらないように備忘録として残しておこう。

## ハマった時の２次元配列の作り方

以下のようにすると、4行１０列の２次元配列ができる。

```Python
array2D = [[0] * 10] * 4
```

例えば、以下のように３行５列目の値を更新すると、、、

```Python
array2D[2][4] += 1
```

全ての行の5列目が更新されています。

[[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 1, 0, 0, 0, 0, 0]]

上記のような作り方をすると、各行の配列は同一になるんですね。

## 各行をそれぞれ別の配列として作成する場合の作り方

これでいけます。

```Python
array2D = [[0] * 10, [0] * 10, [0] * 10, [0] * 10]
```

ただ、スマートじゃないのでこんな感じで作るのがいいんじゃないでしょうか。

```Python
array2D = [[0] * 10 for _ in range(4)]
```
IndexedDBをKey Value Storeとして扱う

## はじめに

自分でPWAのアプリケーションを作成した際、データの保存のためIndexedDBを使いました。
ただ機能的にはLocalStorageで十分だったため、Key Value Storeのように簡単に扱えるようなライブラリを作成しました。

[npm](https://www.npmjs.com/package/indexed-kv)
[github](https://github.com/tkdalic/indexed-kv)

本記事はIndexedDBとは何かと、どのようにKey Value Storeのように使うかを説明します。

## IndexedDBとは

[IndexedDB API](https://developer.mozilla.org/ja/docs/Web/API/IndexedDB_API)によると、

> IndexedDB は、ファイルや blob を含む構造化された多くのデータを保存する、クライアントサイドのローレベル API です。

とのことです。
クライアントサイドでデータを保存する仕組みで、以下の特徴があります。

- オブジェクト指向データベース
- データのやり取りが非同期
- ブラウザでもPWAでも使える

特に「ブラウザでもPWAでも使える」のが重要で、WebStorageはPWAにて使えないようになっています。
そのため、IndexedDBでKey Value Storeを構成しようと思いました。

## indexed-kv

今回作ったライブラリのindexed-kvですが、sampleは以下のようになっています。

```typescript
import { IndexedKv } from "indexed-kv";
const inputKey = "test";
const inputValue = "testValue";

const indexedKV = new IndexedKv(); // オブジェクトの作成
indexedKV
  .set(inputKey, inputValue) // keyとvalueのセットを登録
  .then(() =>
    indexedKV.get(inputValue).then(
      value => console.log(value) // "testValue"
    )
  );
```

まず、`new IndexedKv()`にてオブジェクトを生成します。
この際にパラメータとして、`dbName`と`tableName`が与えられるため、必要であれば与えてください。

その後、keyとvalueの組み合わせで`set()`を呼ぶとデータが登録されます。
また、登録したものを取り出す際には`get()`を呼ぶとデータを取得できます。

型定義上、WebStorageと同じように`value`は`string`で定義しています。

あとは使いやすいように使ってみてください。

### browserのsample

以下にブラウザで試せるsampleがあるので、試してください。

[Indexed KV sample](https://tkdalic.github.io/indexed-kv/)
Kotlin入門:型変換

##型変換

型同士が継承・実装の関係にある場合には、相互に型変換が可能です。
入力例:

```Kotlin
open class Person(){}
class MagickPerson():Person(){
    fun sayHello(){
        println("Hello")
    }
}
fun main() {
    val mp:Person = MagickPerson()
    println(mp is Person)
    println(mp is MagickPerson)
①  if(mp is MagickPerson){
②      mp.sayHello()
    }
}
```
上記のコードが実行可能なのは`MagickPerson `が`Person`の派生クラスだからです。
派生クラスのインスタンスは基底クラスのインスタンスとして使用できます。

したがって、派生クラスから基底クラスへの型変換は暗黙的に実施できます。

しかし、基底クラスから派生クラスへの必ずしも可能ではありません。
派生クラスが独自のメンバーを追加している可能性があるからです。

①では型を判定しています。このブロックの配下②であれば
暗黙的にその型として振る舞うことができる点に注意です。

実行結果は以下の通りです。

```Kotlin
true
true
Hello
```

###明示的なキャストをしたい場合
`as`演算子を使用します。
ただし、asによるキャストは失敗する可能性があります。

```Kotlin
open class Person(){}
class MagickPerson():Person(){}
class Student():Person(){}
fun main() {
    val person:Person = MagickPerson()
    val mp1:MagickPerson = person as MagickPerson
    
    val student:Person = Student()
①  val mp2:MagickPerson = student as MagickPerson
}
```

①でエラーが発生します。
変数`student`は`Person`型ですが、実体は`Student`型です。
したがって、`MagickPerson`型に変換することができません。
応用情報技術者試験　合格への道：ネットワーク:ネットワーク管理、ネットワーク応用

今回はネットワークに関しての最終回！

ネットワーク管理、ネットワーク応用に関して攻略していきます！

#■ネットワーク管理

ネットワーク管理に関しては、「SNMP」、「監視用サーバーの検査項目」、「SDN」に関しての問題のみとなっています。
「監視用サーバーの検査項目」の問題も「SNMP」を理解しているかを問うような内容になっています。

「SNMP」と「SDN」は以前の記事で記載していますが、おさらいも含めて採録しておきます。

##・SNMP(Simple Network Management Protocol)
　TCP/IPネットワーク上でネットワーク上の機器の情報を収集して、監視や制御を行うためのプロトコル。アプリケーション層。
　同じアプリケーション層のプロトコルはFTPだけ。

###SNMPトラップ
　SNMPエージェント(サーバA)からSNMPマネージャ(サーバX)に障害発生などのイベントの発生を通知するコマンド。

##・SDNとNFV
　→SDN(Software-Defined Networking)　NFV(Network Functions Virtualisation)
　　SDNは、ネットワーク機器の構成や接続ルートを機器の導入や配線などの作業をせずに、ソフトウェアへの設定だけで実現する技術。
　　SDNは制御部だけをソフトウェア化したが、NFVでは機器ごと仮想化する

##・OpenFlow
　既存のネットワーク機器がもつ制御処理と転送処理を分離したアーキテクチャ。

#■ネットワーク応用

##・ATM(Asynchronous Transfer Mode)

送信するデータを48バイトのペイロード部に5バイトのヘッダ情報を付けた合計53バイトの固定セルに分割してデータをやり取りする交換方式。

パケット交換方式は多種多様なパケットに対応することができます。ATMは固定長にし、交換機での処理をソフトウェアではなくハードウェアによる高速な処理で行うことで、パケット処理時間の短縮を実現している。

##・IMAP4(Internet Message Access Protocol Version 4)

電子メールの受信に使われるプロトコル。メールサーバ内のメールを選択して受信することが可能。
選択したメールだけを利用者端末へ転送する機能。サーバ上のメールを検索する機能。メールのヘッダだけを取り出す機能、がある。

POPはメールをダウンロードする、IMAP4はメールをサーバーに残してキャッシュのみをローカルで管理する。

##・MIME、S/MIME

###MIME(Multipurpose Internet Mail Extension)
　ASCII文字しか使用できないSMTPのメールで、日本語の2バイトコードや画像データを送信するための仕組み。

あて先(To)フィールド中に日本語の文字を用いることができるようになる
本文の日本語はJISコードに符号化することでMIMEの機能がなくても、すべてのバイトを7ビットに収めてやり取りできる。

###S/MIME(Secure MIME)
　MIMEに暗号化とディジタル署名の機能を付け電子メールの機密性と完全性を高めたもの。

##・SAML(Security Assertion Markup Language)

認証情報に加え，属性情報とアクセス制御情報を異なるドメインに伝達するためのWebサービスプロトコルを定めたもの

クッキー方式やリバースプロキシ方式でシングルサインオンを実現した場合、その認証が有効であるのは認証を受けたドメイン内に限られる。SAMLを使用して他のドメインとの間で認証情報を交換することで、同一ドメインに留まらない大規模なサイトにおいてもシングルサインオンの仕組みやセキュアな認証情報管理を実現できる。

##・WiMAX

広帯域無線アクセス技術の一つで，最大半径50kmの広範囲において最大75Mビット/秒の通信が可能であり，周波数帯域幅を1.25～20MHz使用するという特徴をもつ

##・マルチホーミング

インターネット接続において，複数のISPの回線を使用した冗長化構成


#■最後に

ということでネットワークに関しては以上です。

午前問題で1回しか出ていないような問題は、午後に扱われる可能性が低いと予測されます。

そういった用語に関しては、端的に答えが導き出せる部分だけ覚えておくのが効率が良いと思います。

次回はサービスマネージメントを攻略していきます！
herokuでデプロイに失敗しbundle installしてもダメだったときに見ておくべきところ

herokuへのデプロイは簡単だと思っているエンジニアは多いと思いますが、駆け出しエンジニアにとってはそれすらも大仕事。

僕と同じような状況の人は何かの参考になれば幸いです。

#エラー内容

```
Failed to install gems via Bundler
```

git push heroku masterとしたらこのエラーが出てくる時があります。エラーが出たはいいもののこれをどう処理すればいいのか…

まずはググる

#解決方法
ググったら、上のエラー内容が出たらbundle install またはbundle install --without production（production内にインストールしていないものがある場合）をする必要がある。

それをしたけれどエラーが止まらない。

僕の場合はherokuへのログインをしていなかったことが原因でした。

なのでgit push heroku masterとする前にheroku loginとコマンドを打ち、ログインを完了されることでできるようになりました。

heroku loginを忘れている方は今すぐログインしてください。それだけで解決するかもしれないです。

参考になったら幸いです。
線形時不変システムの双一次変換

連続時間のシステムを離散時間に変換する際の近似手法に、双一次変換というものがあります。デジタルフィルタを作る時などに使われたりします。
よく使用される基本的な状態空間表現を使って、双一次変換による離散化の方法を紹介します。

※この記事では双一次変換の**特別な場合**についてお話ししています。詳細や一般的な変形を知りたい方は、[こちら](https://qiita.com/fukuroder/items/e1cd551b7492020da992)などを参考にしてください。

## 変換方法

基本的な連続時間線形時不変システムを、双一次変換を使用して離散時間状態空間に変換します。

変形前がこちら。

```math
\left\{ \begin{eqnarray}
\dot{x} & = & Ax + Bu \\
y & = & Cx
\end{eqnarray} \right.
```

$x$は状態変数、$y$は出力、$u$は入力です。また、$A$、$B$、$C$は時刻に依存しない係数行列です。

これを、次の形式に変換したいとします。

```math
\left\{ \begin{eqnarray}
\hat{x}[k+1] & = & A_d \hat{x}[k] + B_d u[k] \\
y[k] & = & C_d \hat{x}[k] + D_d u[k]
\end{eqnarray} \right.
```

$\hat{x}[k]$は離散時刻$k$の状態変数です。係数行列の添え字$d$は離散時間のものであることを表します。

この時の、離散時間の間隔をTとした場合の変換方法はこちらです。

```math
\begin{eqnarray}
A_d & = & \left( I + \frac{T}{2}A \right) \left( I - \frac{T}{2}A \right)^{-1} \\
B_d & = & T \left( I - \frac{T}{2}A \right)^{-1} B \\
C_d & = & C \left( I - \frac{T}{2}A \right)^{-1} \\
D_d & = & \frac{T}{2} C \left( I - \frac{T}{2}A \right)^{-1} B
\end{eqnarray} 
```

変換方法については以上です。

## 変換例

簡単な回路を使ってデジタルローパスフィルタを設計します。$V_{in}$が入力電圧、$V_{out}$が出力電圧です。抵抗$R$とコンデンサ$C$で構成された部分がローパスフィルタとなり、$V_{in}$の高周波成分（ノイズなど）が減衰され、$V_{out}$に出力されます。

![lowpass_circuit.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563402/e08b24e3-18cc-2d14-be4d-fb13253b7f8b.png)

回路を流れる電荷を$q$とすると、回路方程式は次のようになります。

```math
\left\{ \begin{eqnarray}
V_{in} & = & R\dot{q} + \frac{1}{C}q \\
V_{out} & = & \frac{1}{C}q
\end{eqnarray} \right.
```

状態変数を$q$、入力を$V_{in}$、出力を$V_{out}$としたシステムに変形すると、

```math
\left\{ \begin{eqnarray}
\dot{q} & = & -\frac{1}{RC}q + \frac{1}{R}V_{in} \\
V_{out} & = & \frac{1}{C}q
\end{eqnarray} \right.
```

これは微分方程式で表現されているので、連続時間の状態方程式になります。シミュレーションは離散時間で行うので、双一次変換を使って離散時間状態方程式に変形します。

先にまとめた変換表を参考にシステムの係数を計算すると、次のようになります。離散時間の間隔は$T$とします。

```math
\left\{ \begin{eqnarray}
\hat{q}[k+1] & = & \frac{2RC-T}{2RC+T}\hat{q}[k] + \frac{2CT}{2RC+T}V_{in}[k] \\
V_{out}[k] & = & \frac{2R}{2RC+T}\hat{q}[k] + \frac{T}{2RC+T}V_{in}[k]
\end{eqnarray} \right.
```

これで離散化は完了です。あとは$V_{in}$に適当な信号データを入力し、$V_{out}$を取得すればデジタルローパスフィルタの完成です。

### （おまけ）シミュレーション

上で求めたデジタルローパスフィルタを使ってノイズ除去をやってみました。入力は$$V_{in}=\sin(2\pi t) + 0.3\varepsilon$$ としています。$\varepsilon$は平均0、標準偏差1のガウスノイズです。ノイズが除去されているのがわかりますね。

![lowpass_graph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563402/63e4583b-5968-af52-c9d7-ea89d313488c.png)

以上です。ありがとうございました。
Font Awesomeのアイコンを導入してみる


# 目的
サイトを作成するのに無料アイコンが必要だったので導入しました。
備忘録

# 流れ

## 1.登録:メール
下記のサイトにアクセスし、スタートをクリック
https://fontawesome.com/
<img width="300" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89227/a3315ffa-0ec9-c354-f67a-af4f25ba5eb5.png">

下記に、自分のメールアドレスを入力し、「Send Kit Code」！
<img width="300" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89227/8a284580-52d6-075a-c57a-8556656d8863.png">

こんなメールが来るので「Click to Confirm Your Email Address + Set Things Up」！
<img width="300" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89227/6ea1d54f-e25f-2b49-4d5a-8fc1737756f7.png">

## 2.登録：入力
新しいパスワードを入力
<img width="300" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89227/df2a5328-5ff4-3f18-6184-7ebc7761821a.png">


上から「ファーストネーム」、「ラストネーム」…「最初に使ったのはいつか」
って感じで入力。そのままですね
<img width="300" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89227/825b3c14-4a25-e40e-15e2-f0339aab8a23.png">

## 3.リンク取得
入力が終わると下記のような画面に移動します。
<img width="300" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89227/83f83180-d2ff-63d1-3fcc-6cc46f9153c4.png">
ここで表示されているコードをコピーしてホームページにCOPYすればOK

```haml

<script src="https://kit.fontawesome.com/{serial}.js" crossorigin="anonymous"></script>
```

例もダウンロードできます。

```html

      <!doctype html>
      <html>
        <head>
          <!-- Place your kit's code here -->
          <script src="https://kit.fontawesome.com/{serial}.js" crossorigin="anonymous"></script>
        </head>

        <body>
          <i class="fas fa-thumbs-up fa-5x"></i>
        </body>
      </html>
```

# 詰まったところ
## フォントの最初の文字が異なる場合がある
フォントによって最初に入ってくる文字が異なる場合がります。
これがバージョンによって異なるらしく…注意が必要です。

fa **s**

```html
<i class="fas fa-map-marked-alt fa-3x"></i>
```
fa **b**

```html
<i class="fab fa-linkedin fa-1x"></i> 
```

こちらのサイトにあるような分類になっているようです。
https://fontawesome.com/how-to-use/on-the-web/referencing-icons/basic-use

<img width="800" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89227/0e9909b8-9702-58d3-e050-cdf0841e7d5d.png">


# その他
## ライセンス
ここにあります。
今日（2020年3月1日）現在はGPLライセンスのようです。
https://fontawesome.com/license/free

## 設定変更
設定を変更し、過去のバージョンも利用できるようです。
また、SVGかWebフォントも選択可能です。

kitのホーム画面で「your kit settings.」をクリックすると下記の画面に移動します。

<img width="300" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89227/15f68eca-a517-7077-dbc1-4e28262c7120.png">
リストや辞書をデフォルト引数にする場合の注意点

#リストや辞書は参照渡しなので注意
```py
def test_func(x, l=[]):
    l.append(x)
    return l


r = test_func(100)
print(r)

r = test_func(100)
print(r)
```

デフォルト引数として空のリストにしたはずが・・・

```text
[100]
[100, 100]
```

#改良するには、下記のようにする
```py
def test_func(x, l=None):
    if l is None:
        l = []
    l.append(x)
    return l


r = test_func(100)
print(r)

r = test_func(100)
print(r)
```
出力：

```
[100]
[100]

```
Google Coraboratory上でOpenGYMを利用する準備

#概要
2020/02/29地点にてGoogleCoraboratory上で強化学習の勉強の為Gymを利用しようとした。
その際にとある記事を参考し環境構築しようとした所Coraboratoryにて利用するCudaのバージョンが変わっているため、手順通りに施行出来なかった為、備忘録として実施した内容を記載する。

#参考記事
[【強化学習】OpenAI Gym×Keras-rlで強化学習アルゴリズムを実装していくぞ（準備編）](https://qiita.com/pocokhc/items/a8120b0abd5941dd7a9f)

#手順変更箇所
## 作業実施前にパッケージレポジトリの更新を実施した。
coraboratoryは定期的にUbuntuのパッケージレポジトリの更新はしていないらしくパッケージマネージャを利用する際はレポジトリ情報のアップデートを手動で実施したほうが良い。
レポジトリ情報のアップデートは下記コマンドで実行できる。

```
!apt-get update
```

##[GoogleColaboratory で実行して表示する。]

```
!apt-get -qq -y install libcusparse8.0 libnvrtc8.0 libnvtoolsext1 > /dev/null
!ln -snf /usr/lib/x86_64-linux-gnu/libnvrtc-builtins.so.8.0 /usr/lib/x86_64-linux-gnu/libnvrtc-builtins.so
```

上記工程にて　libcusparse8.0は現地点では　9.1へバージョンが上がっていたため変更し下記の通り実施した。

```
!apt-get -qq install libcusparse* libnvrtc* libnvtoolsext1 > /dev/null
!ln -snf /usr/lib/x86_64-linux-gnu/libnvrtc.so.9.1 /usr/lib/x86_64-linux-gnu/libnvrtc-builtins.so
```

#その他
Coraboratoryで利用しているCudaのバージョンは下記記事を参考にした。
[google colaboratory の cuda version, cudnn version](https://qiita.com/ikeyasu/items/cdae3562fffdca235d69)
C言語のポインタを再学習したのでちょこっとメモ

udemy でC言語の基礎を進めたいたので、少しメモ

# ポインター

ダメなソース

```c
void main(){
    int a = 100;
    int* pointer = NULL;
    // OK：ポインタ変数に 変数a　のアドレスをセット
    pointer = &a;
    printf("%d, %d\n", a, *pointer);
    // OK：ポインタ変数に 変数a の値をセット
    *pointer = 200;
    printf("%d, %d\n", a, *pointer);
    // NG：ポインタ変数に 変数a の値をセットしようとしている
    pointer = a;
    printf("%d, %d\n", a, *pointer);
}
```

# 問題点
* 主要な開発環境では、エラーが表示されている。
* コンパイルはOKが出る。 
* ただし、実行はできる。

# こうなるとやばいことが発生しそう。

```c
    pointer = a;
```
上記、箇所で 変数a の値に「有効なアドレス値」をセットが可能な点。

つまり、他のAPもしくはOSが使用しているアドレスをセットして、操作が可能？ということか？
（もちろん、そうされないようにOSではガードが固くなっていると思われる。ただAPでそのようなガードがされていないと、簡単にクラッシュさせてしまうことが可能ではないだろうか？）

# まとめ
仕事では簡単なPG修正しかしていないけど、改めて基礎を学びなおしていると怖くなってきた。。。
VagrantでWordPressの構築をするまで・・・

#MacにVagrantでCentOS7環境を作成
[MacにVagrantでCentOS7環境を作成](https://qiita.com/sudachi808/items/3614fd90f9025973de4b)
[WindowsにVagrantでCentOS7のセットアップ](https://qiita.com/mekappi/items/df606a3b7ca0b52ecb5b)

```
# 起動
vagrant up
# VagrantインスタンスへSSH接続
vagrant ssh
# 停止
vagrant halt
#　停止→破壊→起動！（環境面で何かおかしくなった時の最終手段）
vagrant halt && vagrant destroy -f && vagrant up
```
[VagrantインスタンスにSSHでログインする](https://qiita.com/y_arakawa/items/7bb292c999873032e6a4)
[vagrant仮想マシンにホスト名でアクセスする方法](http://ktykwsk.com/vagrant%E4%BB%AE%E6%83%B3%E3%83%9E%E3%82%B7%E3%83%B3%E3%81%AB%E3%83%9B%E3%82%B9%E3%83%88%E5%90%8D%E3%81%A7%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/)

#WordPressを動作させるまでにやったこと

・ユーザー作成、SSH鍵認証
[CentOS7でユーザーを作成しSSH接続を行う](https://qiita.com/kkenya/items/bfdce8801614f895e123)
[[Vagrant] vagrant以外のユーザへ公開鍵認証でSSH接続する方法](https://qiita.com/nafuka/items/dc17f00dec14aaf09ce5)
[ssh-keygenコマンドオプション](https://www.atmarkit.co.jp/ait/articles/1503/20/news007.html)

・Nginxインストール
[CentOS7 に nginx導入](https://qiita.com/MuuKojima/items/afc0ad8309ba9c5ed5ee)
[CentOS7 で nginxのインストールと起動](https://qiita.com/MiraGi/items/f87851985ff2c9985935)

・NginxとAppacheの違いについて
[Nginxとは？Apacheとの違いについてエンジニアに聞いてみた](https://academy.gmocloud.com/qa/20160616/2761)

**上記サイトでのポイント**
＜Apache＞
・HTTP（Web）のサービスに特化している。
・Webサービスで必要な機能をどんどん取り込んでいる為、動作が遅い！。
＜Nginx（エンジンエックス）＞
・他サービスにも柔軟に対応できるようになっている。
・同時リクエストを多く処理することに特化している。
・余計な機能はつけていない非常にシンプルなもの。
・クラウドサーバーなどでを使えば、少ないメモリ量でサーバーが立てれるので、コストを抑えられる。
＜まとめ＞
・Apacheはたくさんの機能が最初からついており、Nginxに比べるとどうしてもメモリの使用量が多くなる。

[Nginx（エンジンエックス）をインストールした環境で、WordPressを導入してみた。](https://academy.gmocloud.com/advance/20160721/3203)
mLabを使用してMongoDBの書き込み時に"MongoError: This MongoDB deployment does not support retryable writes"のエラー

## 概要
MongoDBをクラウド上で提供している[mLab MongoDB](https://elements.heroku.com/addons/mongolab)というサービスがあるのですが、データの書き込みを行った時に、`MongoError: This MongoDB deployment does not support retryable writes`のエラーが発生したので、対応方法をメモします。

## 原因
この[Stack Overflowの記事](https://stackoverflow.com/a/60161675)によると、mLabではMongoDBの接続設定`retryWrites`オプションが使用できないので、falseにする必要があるとのこと。
`retryWrites`オプションは書き込みのエラー発生時に、DB側で自動的にretryしてくれる機能で、[公式のマニュアル](https://docs.mongodb.com/manual/core/retryable-writes/)によると、MongoDB4.2のドライバーだとデフォルトでtrueになるみたいです。

## 接続時の設定
以下はRailsのMongoidを使用した際の、`retryWrites`オプションをfalseにする設定です。なお、設定ファイル`mongoid.yml`の詳細については、[mongoid-configuration](https://docs.mongodb.com/mongoid/current/tutorials/mongoid-configuration/)を参照ください。

```mongoid.yml
production:
  clients:
    default:
      database: heroku_test
      hosts:
        - test111111.mlab.com:51180
      options:
        user: "test_user"
        password: "test_password"
        retry_writes: false
  options:
```
パチンコの保留動作を再現する

#パチンコの保留を再現したい。
保留の動作をいざ再現したいと思ったけど、
意外と再現するのに苦戦したので紹介。
以下を再現
![horyu.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591107/ef92c3b4-2ede-8f6f-31c5-4648a16817fd.gif)


#フローチャート
まず、プログラムを考えるときに必要なフローを考えてみた。
アニメーションなどは考えず表示、非表示で保留の動きを考えてみる。
後のことを考えて配列で保留を管理します。

- 例: 保留が０と等しいときは保留がない状態。
- 保留が１のときは白保留。
- 保留が２のときは青保留
- 保留が３のときは赤保留
- etc
![キャプチャ3fffffffffff3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591107/c0456ece-8418-09a7-6a9f-e036d9fc4a3d.png)

これにアニメーションを追加すると完成。
Django 静的ファイルの扱いについて

Djangoの静的ファイルの扱いがいまいち理解出来てなっかたので
調べて自分なりにまとめました。
staticディレクトリの配置する場所が参考にするサイトによって
設計が違ったりするとわからなくなってしまう...
`STATIC_ROOT`、`STATIC_URL `、`STATICFILES_DIRS `
この3つの意味をちゃんと理解できればそんなに難しい話ではなかった...

##STATIC_ROOTについて
```python:settings.py
STATIC_ROOT = os.path.join(BASE_DIR,'static')
```

ローカルのサーバを動かしている段階では、Djangoが勝手に
各アプリディレクトリ直下のstaticディレクトリを自動で探してくれるため、
意識する必要はないみたいです。

しかし本番環境のWebサーバに静的ファイルを管理させる場合に設定が必要になります。
というのも本番環境のWebサーバにそれらの静的ファイルを管理させる場合、
それらのファイルを一箇所に集めることが必要になり、
どこに集めるのかを決めるのがこのSTATIC_ROOTの役割だそうです。

なので`$ python manage.py collectstatic`コマンドを打った際に、
各アプリの静的ファイルを集約する先を設定値として指定します。
こちらはデフォルトで記述がないため、自分で追記する必要があります。

##STATIC_URLについて
```python:settings.py
STATIC_URL = '/static/'
```

静的ファイルをどんなURLで公開するのかを決める設定値。
例：`/static/`とした場合、各静的ファイルは`ドメイン/static/????`のような形で
アクセスできるようになります。

特にこだわりがなければ、デフォルトで記載されている/static/として問題ないみたいです。

##STATICFILES_DIRSについて
```python:settings.py
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, "static"),
)
```
ローカルのサーバを動かしている段階では、Djangoが勝手に
各アプリディレクトリ直下のstaticディレクトリを自動で探してくれますが、
もしそれ以外に静的ファイルディレクトリとして
認識してほしいディレクトリがあればSTATICFILES_DIRSで設定可能。
基本的には必要ないはず。
SeleniumでShiftRightとShiftLeftを使い分ける

# 3行でわかる概要
* JavaのSelenium(4.0.0-alpha-4)の`WebElement::sendKeys`で左右Shiftキーを使い分けようとした際に少し詰まった
* 用意されている`Keys`は`SHIFT`/`LEFT_SHIFT`の中身が同じ
* `Keys`を使わずに文字列で`"ShiftRight"`と指定すると右Shiftとして認識される 

# 問題

JavaでSeleniumを使用してkeyDownさせる場合、下記のようなコードを書く。

```java
public void sendKey(WebDriver webDriver, CharSequence... keys) {
  WebElement element = webDriver.findElement(By.className("hoge"))
  element.sendKeys(keys);
}
```

`WebElement.sendKeys`は引数に`CharSequence...`を取るが、用意されているenum`Keys`を使用することが多い。
ただし、右Shiftキー/左Shiftキーのように同一機能のキーについて左右で使い分けたい場合は注意が必要。

enum`Keys`の実装は下記のようになっている。
`SHIFT`/`LEFT_SHIFT`がそれぞれ定義されているが、残念なことにどちらを送った場合でも左Shiftキーの挙動になってしまう。

```Keys.java
public enum Keys implements CharSequence {
  ...
  SHIFT        ('\uE008'),
  LEFT_SHIFT   (Keys.SHIFT),
  CONTROL      ('\uE009'),
  LEFT_CONTROL (Keys.CONTROL),
  ALT          ('\uE00A'),
  LEFT_ALT     (Keys.ALT),
  LEFT         ('\uE012'),
  ARROW_LEFT   (Keys.LEFT),
  UP           ('\uE013'),
  ARROW_UP     (Keys.UP),
  RIGHT        ('\uE014'),
  ARROW_RIGHT  (Keys.RIGHT),
  DOWN         ('\uE015'),
  ARROW_DOWN   (Keys.DOWN),
  ...
}
```

# 解決策

`Keys`は`CharSequence`を実装しており、コンストラクタおよび`toString()`の実装は下記のようになっている。

```Keys.java
public enum Keys implements CharSequence {
  ...

  private final char keyCode;
  private final int codePoint;

  Keys(Keys key) {
    this(key.charAt(0));
  }

  Keys(char keyCode) {
    this.keyCode = keyCode;
    this.codePoint = String.valueOf(keyCode).codePoints().findFirst().getAsInt();
  }

  ...

  @Override
  public String toString {
    return String.valueOf(keyCode);
  }
}
```

また、`WebElement.sendKeys`は実質与えられたkeycodeを改行区切りで結合してWebDriverに送っているだけ。
そこで、`Keys.SHIFT`で定義されたKeyCodeを使用せずに下記のように文字列で指定することで正常に認識されるようになる。

```java
  WebElement element = webDriver.findElement(By.className("hoge"))
  element.sendKeys("ShiftRight");
```
Railsで綺麗に\nを<br>に変換する方法

## 準備
まず、Stringクラスを拡張します。ファイルの置き場所はお作法です。

```ruby:/lib/ext/string.rb
class String
  def to_br
    ERB::Util.h(self).gsub(/\R/, "<br>")
  end
end
```

先ほどのstring.rbを初期化時に読み込みます

```ruby:/config/initializers/extension.rb
require 'ext/string'
```

これで準備完了です。

## 使い方

あとは任意のhtmlファイルにて、

```erb:hoge.html.erb
<%== hoge_str.to_br %>
```

または、

```slim:hoge.html.slim
== hoge_str.to_br
```
などで綺麗に\<br\>へ変換することができます。
Pipenvを利用した仮想環境上でdjango-admin startprojectコマンドでディレクトリがバグった時の話

##概要
Pipenvを利用した仮想環境上でdjango-admin startprojectコマンドで、
プロジェクトを作成しGitで管理をして開発を進めていたら、
途中でおかしくなった為、ディレクトリ構造を確認すると
Pipfileとmanage.pyが別のディレクトリになってることに違和感を感じた....
ディレクトリが一階層多いので調べたところ解決策があったのでメモ。

##結論
```terminal
$ django-admin startproject 任意のプロジェクト名 .
```
この最後の`ピリオド(.)`をつけることで解決。

##失敗パターン
```terminal
$ django-admin startproject 任意のプロジェクト名

//下記の例の場合
$ django-admin startproject sample
```
```text:DirTree
sample/
　├ sample/ ここでひとつ余分にディレクトリが作成される。
　│　├ sample/
　│　│　├ __init__.py
　│　│　├ settings.py
　│　│　├ urls.py
　│　│　└ wsgi.py
　│　└ manage.py
　├ Pipfile
　└ Pipfile.lock
```

##成功パターン
```terminal
$ django-admin startproject 任意のプロジェクト名 .

//下記の例の場合
$ django-admin startproject sample .
```
```text:DirTree
sample/
　├ sample/
　│　├ __init__.py
　│　├ settings.py
　│　├ urls.py
　│　└ wsgi.py
　├ manage.py
　├ Pipfile
　└ Pipfile.lock
```

Pipenvを利用した仮想環境上でDjangoのプロジェクトを始める時は要注意ですね.....
【Rails】 nil落ちの回避方法

#nil落ちの回避方法

`find`などを使用した時に、レコードが存在しない場合`NoMethodError`が発生する。
そんな時に検索結果を`nil`で返したい時に行う方法を色々。

## `||=`を使う
修正前
`User`の`id`が存在しない場合`NoMethodError`が発生する。

```ruby:
@current_user = User.find(params[:id])
```

修正後
`User`の`id`が存在しない場合`@current_user`は`nil`を返す。

```ruby:
@current_user ||= User.find(params[:id])
```


##`&.`を使う(ぼっち演算子)
レシーバーが nil のとき，NoMethodErrorを投げずにnilを返してくれる機能。

```ruby:
@current_user = User&.find(params[:id])
```

メソッドやスコープにも使えるので、便利

```ruby:user.rb
class User < ApplicationRecord
  scope :find_user, -> { find(10) }
end

```

```ruby:users_controller.rb

def show
   @current_user = User&.find_user
end
```


##`try`を使う
レシーバーが nil のとき、NoMethodErrorを投げずにnilを返してくれる機能。
※定義されていないものを呼び出そうとした時、#try はnilを返すため注意が必要

```ruby:user.rb
class User < ApplicationRecord
  scope :find_user, -> { find(10) }
end

```

```ruby:users_controller.rb

def show
   @current_user = User.try(find_user)
end
```

##まとめ
- `||=` と`&.`を使う事で簡単に`NoMethodError`を回避できる。



## 参考資料
第8章　コラム8.1
https://railstutorial.jp/chapters/log_in_log_out?version=4.2
Google Chromeの拡張機能を整理する方法：Extensions Toolbar Menuの活用法

Google Chromeの拡張機能はとても便利ですが、何も考えずにインストールしていると気付けばブラウザのツールバーがアイコンで溢れてしまいます。私自身も、新しく見つけた便利な拡張機能をインストールするたびに「このアイコンどこに置こう？」と試行錯誤していた時期がありました。

頻繁には使わない拡張機能もあるため、できれば整理したいところです。今回は、Chromeの中にある拡張機能を隠してツールバーを整理する｢Extensions Toolbar Menu｣というオプション機能を紹介します。

## Extensions Toolbar Menuの有効化手順
ブラウザのアドレスバーに「chrome://flags」と入力し、Enterキーを押します。
表示されたExperimentのページの検索ボックスに「Extensions toolbar」と入力します。
表示される「Extensions Toolbar Menu」のドロップダウンメニューで「Enabled」を選択します。
Google Chromeを再起動します。

この機能を有効にすることで、多数の拡張機能アイコンをスマートに整理することができます。

## 拡張機能のピン止め
もちろん、頻繁に使用する拡張機能が隠れてしまうと不便に感じることがあります。その場合は、拡張機能のアイコンの右側にある3つの点をクリックし、「固定」を選ぶことで、特定のアイコンをツールバーにピン止めすることができます。

## 拡張機能の整理の重要性
私自身も拡張機能を入れすぎてChromeが重くなることを何度も経験しました。どんなに便利な拡張機能でも、利用頻度が低いものは思い切って削除することも大切です。
CSSを使って長い文章を三点リーダーで省略する方法

ECサイトを作成している際に、長すぎる商品名が表示されると、2行や3行に改行されてレイアウトが崩れてしまうことがあります。そんなとき、続きの部分を「…」と表示して一列に収める方法をご紹介します。

## 対処方法
CSSを使用して、長いテキストを省略表示にする方法を説明します。以下は、具体的な例です。


```html:HTML
<div class="compact">2019年度〇〇賞受賞。福岡県産！〇〇米10kg</div>
```
```css:CSS
.compact {
    width: 300px; /* 要素の横幅を指定 */
    white-space: nowrap; /* 横幅のMAXに達しても改行しない */
    overflow: hidden; /* 溢れた部分を隠す */
    text-overflow: ellipsis; /* 「…」と省略 */
    -webkit-text-overflow: ellipsis; /* Safari用 */
    -o-text-overflow: ellipsis; /* Opera用 */
}
```
### 解説
width: 要素の横幅を指定します。この例では300pxに設定しています。
white-space: nowrapを設定することで、テキストが横幅の最大値に達しても改行されないようにします。
overflow: hiddenを設定して、要素の範囲外に溢れた部分を非表示にします。
text-overflow: ellipsisを指定することで、溢れたテキストを「…」と省略表示します。
-webkit-text-overflowと**-o-text-overflow**: それぞれSafariとOpera用のベンダープレフィックスです。

## 実際の使用例
例えば、以下のような商品名が長い場合でも、指定した幅内で「…」を使って省略され、レイアウトが崩れるのを防ぐことができます。

```html:HTML
<div class="compact">この商品は非常に人気があり、売り切れ必至のアイテムです。今すぐご購入をお勧めします。</div>

```
```css:CSS
.compact {
    width: 250px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    -webkit-text-overflow: ellipsis;
    -o-text-overflow: ellipsis;
}
```
この設定により、長い商品名や説明文が指定した幅を超えた場合でも、「…」で省略表示され、一列に収まるようになります。これで、ECサイトのレイアウトが整い、見やすさが向上します。
railsをversion指定してアプリ作成する方法

 railsをversion（5.2.4.1）指定してアプリ制作したかったのでその方法をば…



まずは現在のversionを確認



##現在のrailsのversionを確認するコマンド

```ruby:ターミナル
$ rails -v
```




現在のversion

```ruby:
Rails 6.0.2.1
```

##version（5.2.4.1）を指定してインストールするコマンド

```ruby:ターミナル
$ gem install rails:5.2.4.1
```
「/Library/Ruby/Gems/2.6.0ディレクトリに対する書き込み権限がありません。」と言われる

```ruby:
ERROR:  While executing gem ... (Gem::FilePermissionError)
    You don't have write permissions for the /Library/Ruby/Gems/2.6.0 directory.
```

#####`sudo`を付けて再びコマンド入力

```ruby:
$ sudo gem install rails:5.2.4.1
```

#####MacBookのpassを入力
（入力中passはターミナルに表示されないので、入力が終わったらそのままエンターキーでOK）

```ruby:ターミナル
Password:
```
**インストール完了**
（上記の様な"権限がない系のエラー"が出た時は頭に`sudo`を付けたらだいたい解決する説）

```ruby:
Successfully installed rails-5.2.4.1
Parsing documentation for rails-5.2.4.1
Done installing documentation for rails after 0 seconds
1 gem installed
```

####現在のversionを確認する

```ruby:
$ rails -v
```

最新versionのまま…

```ruby:
Rails 6.0.2.1
```

気を取り直して、方法を変えてみる

##versionを指定して新しいアプリを作るコマンド

```ruby:
$ rails _5.2.4.1_new ○○○○（アプリ名）
```
問題なさそう…？

```ruby:
（省略）
*
*
Bundle complete! 14 Gemfile dependencies, 64 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
         run  bundle exec spring binstub --all
* bin/rake: Spring inserted
* bin/rails: Spring inserted
```

再びversion確認

```ruby:
$ rails -v
```

最新のまま…orz

``````ruby:
Rails 6.0.2.1
```

ググったら
どうやら作ったアプリに入ってからversion確認してみると良さげらしい


##作ったアプリに移動するコマンド

```ruby:
$ cd ○○○○（アプリ名）
```

↓ユーザーの後ろにアプリ名がくっついて表示されていればOK

```ruby:
○○○○（アプリ名） ＄
```
version確認

```ruby:
○○○○（アプリ名） ＄ rails -v
```

#成功！！

```ruby:
Rails 5.2.4.1
```
photonnetwork.instantiateでgamepobject型を生成してからステータスや値を参照する方法

主に前回の記事で起きたことの修正です。
前回↓
https://qiita.com/wttk05/items/5f8cef73a5aa5ec3e06a

では本題です。（タイトルがまとまってなくてすいません）

まず前回の**Illegal view ID:0**ですがphotonnetwork.instantiateを使わないと出るエラーらしいです。逃れられないのでphotonnetwork.instantiateを使用した後値を参照することにしました。


```GameManager.cs
    void CreateCardPrehub(Transform transform,int cardID)
    {
        // Prehubを生成
        playerInfo = PhotonNetwork.Instantiate("Cards", new Vector3(100, 100, 1), Quaternion.identity,0);// Photonオブジェクト生成
        playerInfo.transform.SetParent(playerFieldTransform.transform); // 親を設定
        playerInfo.transform.localScale = new Vector3(1.5f, 1.5f, 1.5f); // カードのサイズを設定
        playerInfo.transform.position = new Vector3(510, 270,0);// カードの位置を設定

        //CardControllerを参照してInitを実行
        playerInfo.GetComponentInParent<CardController>().Init(cardID); 
    }
```

![SnapCrab_NoName_2020-3-1_2-4-2_No-00.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542433/b5565d5e-dad3-debf-5310-0d7619699536.jpeg)

CardViewでの値はinstantiaceするオブジェクトに付いているテキストやImage等をアタッチしています。

カードの位置の設定等はもっといい方法があるかもしれませんが今の自分では無理だったので裏で動く脳みそに任せて
成功を祝おうと思います。

```GameManager.cs
CreateCardPrehub(playerPrehab.transform,1);
```
これ１行で幸せになれる。

まだ色々適当なので少しずつソースコードを壊れない程度に整理しつつ、カードゲームをオンライン化していこうと思います。
ちなみにコード一つ一つ解説するより大まかにサンプルを上げたほうが他人から見ても自分から見てもわかりやすいと思いってるので
このスタイルを続けます😏

今回はこの辺で終わります。
アドバイスやコメントくださってる方本当にありがとうございます。
Unityしてる友達がいないのでとても助かってます。 

Twtter@wttk05
Mozilla hubsで世界中の人とお茶しよう！

世界中のどこにいる誰とでも同じ空間を共有できたら面白いと思いませんか？

VRChatみたいなものが最近どんどん話題になっており、VRを使った様々なアプリケーションが登場しています。でもVRChatはスペックの良いPCかVRが必要だし手を出しづらいなあと思っている方に朗報です！

Mozilla主導で開発が進んでいる[Mozilla Hubs](https://hubs.mozilla.com/#/)というオープンソースのアプリケーションをご存知でしょうか？VR空間で人とコミュニケーションを取るためのツールなのですが、これがなかなかにすごいんです。

![service](https://i.imgur.com/CR1ACM4.jpg)

## ブラウザだけで動く！
環境構築が必要ありません！URLを共有するだけで簡単に招待することができます。WebGLなどの技術をフル活用して実装されているみたいです。ユーザー登録も不要で参加できるのでとにかく気軽に共有できます。pcだけでなく、スマートフォンやタブレットのブラウザでも動作します。

さらにオキュラスクエストなどのVR機器をもっている方はそちらを用いることも可能です。


## 様々なコミュニケーションのとり方ができる
ユーザーは自身のアバターを作成してRoomに入場します。アバター同士で会話ができるのはもちろん、Chatやフリーハンドでのお絵かき、カメラ、スタンプのようなリアクションなど様々な方法でコミュニケーションを取ることができます。

さらにsketchfabという3Dモデルの投稿サービスにある3DオブジェクトをSceneに出現させて遊ぶこともできます！ドラえもんの4次元ポケットみたいですね笑。様々なオブジェクトが登録されているので一度見てみると面白いです。

![hub](https://assets-prod.reticulum.io/spoke/assets/images/meeting-ee8cb4d5a0bc4a379c60831eaa2518fd.jpg)

他にも画像、動画、その他リンク、さらには画面共有までできてしまいます。デジタルなコンテンツはほとんど扱えると見て良さそうです。

## カスタマイズもできる
Sceneのカスタマイズだってできちゃいます！それもブラウザだけで。

![custom](https://assets-prod.reticulum.io/spoke/assets/images/environment-editor-efe992a4a7fc17ceec6af45461f4edf8.jpg)

[Spoke](https://hubs.mozilla.com/spoke)という項目があってここからオリジナルのポリゴンや画像を配置してみたり、照明をいじってみたりbgmをかけてみたり...とにかく何でもできます。

デフォルトのSceneがそこそこあるのでそこからカスタマイズしていくと自分好みのSceneが簡単に作成できます。

## 使用例
URLを共有するだけという手軽さから、様々な利用方法が考えられます。例えば普段会えない友達とオンラインでお茶してみたりとか、Twitterなどにおけるコミュニティの共有スペースを作ってみたりとか、海外の人に向けて語学教室を開いて見たり等、とにかく使い方は無限大です！自分は自身の運営する法人の事務所をこれで作ってみました笑。固定資産税とも無縁です笑。

## 最後に
Mozilla Hubsは現在非常に活発に開発が進められており、どんどん機能も追加されています。オープンソースなので興味があれば開発現場を覗いてみるのも良いでしょう。自身でサーバーをたてることもできるようです。

コロナが流行っていて外出がしづらい今、結構活用できるのではないかと思います。興味をもった方は是非！Mozilla Hubsを使ってみて下さい。

[Mozilla Hubs](https://hubs.mozilla.com/#/)
[github](https://github.com/mozilla/hubs)
画像のドミナントカラーをk-meansクラスタリングで抽出

ドミナントカラー（dominant color）とは、配色全体を支配するような色相のことです。 --Google

５色抽出して、割合で円グラフを描きます。
<div align="center">
<img width="400" alt="input.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563906/1430c496-2833-d401-8a24-053af38af748.jpeg">
<img width="400" alt="out.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563906/8ecba1e1-bbcf-c3ef-6e5b-32081cfb7ae4.png">
<img width="400" alt="input.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563906/dc6e4fa9-7a41-801b-b0ab-ca8c556a3041.jpeg">
<img width="400" alt="out.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563906/fc686005-e773-3644-db8c-5bef3f5f85c0.png">
<img width="400" alt="input.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563906/deaacfa4-abe3-4484-6ed1-4a33d17e43fe.jpeg">
<img width="400" alt="out.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563906/569d33cd-f60f-734b-81b5-83be4c5e7840.png">
</div>

### 使うパッケージ
```shell
$ pip install opencv-python
$ pip install scikit-learn
$ pip install matplotlib
```

### 画像を読み込む
画像をk-meansクラスタリングできるデータにするため、RGBのリストにする

```python
import cv2
import itertools

image = cv2.imread('./input.jpg')
rgbs = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
rgb_list = list(itertools.chain(*rgbs.tolist()))
```

## k-means
抽出する色の数=クラスタの数
ここでは5の例:

```python
from sklearn.cluster import KMeans

clusters = KMeans(n_clusters=5).fit(rgb_list)
```

クラスタのセンターがドミナントカラー

```python
colors = clusters.cluster_centers_
print(colors)
[[ 25.29093216 119.84721127 142.13737995]
 [223.23362209 201.96734673 193.59849205]
 [176.3426999  108.01350558 118.93074255]
 [  8.36396613  14.71480369  27.54413049]
 [ 98.95068783  32.240443    48.93265647]]
#rgb
```

各クラスタの割合を計算

```python
import numpy as np

def cluster_percents(labels):
    total = len(labels)
    percents = []
    for i in set(labels):
        percent = (np.count_nonzero(labels == i) / total) * 100
        percents.append(round(percent, 2))
    return percents
```
```python
percents = cluster_percents(clusters.labels_)
print(percents)
[9.16, 9.6, 11.51, 48.37, 21.35]
#%
```

###円グラフを描く
matplotlibのcolorが0~1にスケールされたRGBしか受け付けないためスケールする。

```python
import matplotlib.pyplot as plt

colors = clusters.cluster_centers_ / 255
colors = colors.tolist()
```

円グラフを綺麗に見せるため割合を大から小にソートする。

```python
percents = cluster_percents(clusters.labels_)
tup = zip(colors, percents)
sorted_tup = sorted(tup, key=lambda n: n[1], reverse=True)
sorted_colors = [c for c,p in sorted_tup]
sorted_percents = [p for c,p in sorted_tup]
```
円グラフを描く

```python
plt.pie(sorted_percents, colors=sorted_colors, counterclock=False, startangle=90)
plt.show()
```
同時調音(co-articulation)のメモ

次の音(phoneme)に応じて口, 舌などの動きが変わる

## 参考情報

http://www.dgp.toronto.edu/~elf/JALISIG16.pdf
https://en.wikipedia.org/wiki/International_Phonetic_Alphabet
(日本語 https://ja.wikipedia.org/wiki/%E5%9B%BD%E9%9A%9B%E9%9F%B3%E5%A3%B0%E8%A8%98%E5%8F%B7)


## 主な 4 つの制約要因(from JALI paper)

Bilabials (m b p ) : 両唇音 
Labiodentals (f v) : 唇歯音
Sibilants ( s z J C S Z) : 歯擦音
Non-Nasal : (鼻に関係しない?)
vimで単語検索と置換ができるプラグイン far.vim

# 概要
単語検索と置換が簡単にできる[far.vim](https://github.com/brooth/far.vim)

## 使い方
### 例) usreをuserに置換

1. 下記コマンドを入力

```vimscript
:Far usre user **/*.php
```

1. 置換する場所を撰択
下のような画面が出現するので、
ファイルまたは行数ごとに変換しない場所を`t`で選択する.

![スクリーンショット 2020-02-29 23.18.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68643/10cc55b0-8381-bf9d-bfee-219c19b9eec7.png)


ファイルごとに折りたたみができ、`zo`を開き、`zc`で閉じる

1. 選択した場所を下記コマンドを実行すると一括変換

```
:Fardo
```

## 設定
```vimscript
" 検索する場所の指定
" 例) let g:far#cwd='/var/www/html'
let g:far#cwd='ディレクトリパス'

" 検索するsourceの指定
" 例) let g:far#source='rg'
let g:far#source='vimgrep/rg/rgnvim/ack/acknvim/ag/agnvimのいずれか'

" 検索結果をファイル単位で表示
" 検索結果が多い場合、表示がカクツクため
let g:far#collapse_result=1
```

その他の設定は `:help far.vim` で確認できます。

## その他
- .gitignoreは検索の対象外となる.

## GitHubリポジトリ
[brooth/far.vim](https://github.com/brooth/far.vim)

## 2020/03/10 追記
今開いているファイルに対して実行したい場合は `%` を使う

```vimscript
:Far usre user %
```

### エラーが出る場合

`File in current buffer is not readable`
こんなエラーが出る場合は、bufferのパスの読み込みがうまくできていないので、
`autoload/far.vim` の line.2064を変更する。

```vimscript
" 変更前
if !filereadable(filename)

" 変更後
if !filereadable(a:far_params.cwd . a:far_params.file_mask)
```

ファイルがある場所まで移動してファイルを開いた場合上記のエラーは出ないが、
ファイルパスを指定した場合ファイルの読み込みがうまくできずエラーとなっているみたい...
DELETEME と ARCHIVEME


<link rel="canonical" href="https://wraith13.github.io/writing/?programming%2Fdeleteme.md" />
この記事の転載元URL: <a rel="canonical" href="https://wraith13.github.io/writing/?programming%2Fdeleteme.md">https://wraith13.github.io/writing/?programming%2Fdeleteme.md</a>

# DELETEME

## コンセプト

- 不要になったハズだけど、まだ残しておきたいコードのクラスや関数の名前には `DELETEME` を含めます。
- `DELETEME` と明示される事で、間違えて利用してしまう事を防ぎ、また、いまは気にしなくて良いコードだと示せます。
- 明らかに完全に不要になった際は必ず容赦なく削除します。
- 再度、利用する事になった場合は必ず `DELETEME` の明示を削ります。

## サンプル

```typescript
// before
const renderItem = () =>
{
    ...
}
```

```typescript
// after
const renderItem_DELETEME_at_Feb2020 = () =>
{
    ...
}
```

## 詳細

- ディレクティブが使えるプログラミング言語では `#if DELETEME` 〜 `#endif` のようなディレクティブで囲むのも良いでしょう。
- 対象となるコードがファイル単位やディレクトリ単位になる場合、ファイル名やディレクトリ名に `DELETEME` を付けるのも良いでしょう。
- 特にゼロから書き起こしている最中のコードは試行錯誤を繰り返し方針をコロコロ変える事も珍しくないでしょう。そのような場合に現行の方針上は不要になったコードを `DELETEME` で明示しておく事で、いまは気に掛けなくていいコードだと明示できますし、なにより方針変更でやっぱり必要になった！って場面でも面倒が少なく、もちろん最終的に確実に要らなくなった際も `DELETEME` で検索することでスムーズに削除でき、間違えてコミットしてしまう事も減らせれば、間違えてコミットした際にも間違えてコミットしたコードである事も分かり易くなります。
- 乱用すると使用されないコードによってコード全体が無駄に間延びしてしまいコードの見通しが悪くなるので程々に。
- `DELETEME` と明示するコードにはいつになったら削除してよいのか、できればその期限やその他の条件を明記します。

# ARCHIVEME

- 使用はしないが長期保存したいコードに対しては `DELETEME` ではなく `ARCHIVEME` と明示し、保存期間以外に関しては `DELETEME` と同様の運用を行います。
- 一般的に最適化を行うとコードの可読性やメンテナンス性は著しく悪化する上に、前提の変化により、最適化の意味が無くなったりかえってパフォーマンスが悪くなる事もあるでしょうし、そうでなくとも最適化後のコードにやっかいなバグが存在しどうにも対処できないなんて事もあるでしょう。そういう事態に備えて最適化前のクリアでソリッドなコードを `ARCHIVEME` として残しておくと良いでしょう。
- 「バージョン管理ツールがあればこのような事は不要では？」という言説もあるでしょうが、特に削除してからかなりの期間が経過している場合、削除したコードをバージョン管理ツールを漁って拾ってくるのは存外手間も掛かる上に、なんらかの形でリポジトリを移行する際に移行前の履歴は分断される等して、削除したコードを拾ってくる手間や難易度が著しく上昇する事も珍しい話ではありません。また、最適化後のコードに問題がある場合などに、最適化前のコードを **気軽に** 参照したり動作確認できる事は重宝される事でしょう。
MDの書き方

ここのサイトを参考
https://qiita.com/oreo/items/82183bfbaac69971917f


## コードブロック
```markdown:title

 ```


## リンク
```markdown:リンク
[Wikipedia][1]
文中
[1]:https://ja.wikipedia.org/wiki/%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8
```
例
[Wikipedia][1]
文中
[1]:https://ja.wikipedia.org/wiki/%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8
Adafruit Trinket M0でTinyGo(環境構築&Lチカ編)

#はじめに
Goで組み込み向けプログラミングができるTinyGoが盛り上がってきているようなので試してみた。
今回実行したのはAdafruit Trinket M0の搭載LEDを利用したLチカ。
#動作環境
* OS: macOS 10.15.3
* Go: 1.13.8
* TinyGo: 0.12.0
* マイコン: Adafruit Trinket M0

#セットアップ
###Go
```
$ brew update
$ brew install go
```
###TinyGo
```
$ brew tap tinygo-org/tools
$ brew install tinygo
$ brew tap osx-cross/avr
$ brew install avr-gcc avrdude
$ go get -u tinygo.org/x/drivers
```
###BOSSA
[BOSSA](https://github.com/shumatech/BOSSA/releases)からMAC用パッケージをダウンロードしてインストール
#実行コード
```go:main.go
package main

import (
	"machine"
	"time"
)

func main() {
	led := machine.LED
	led.Configure(machine.PinConfig{Mode: machine.PinOutput})
	for {
		led.Low()
		time.Sleep(time.Millisecond * 500)

		led.High()
		time.Sleep(time.Millisecond * 500)
	}
}
```
#ビルド&書き込み
###パターン1. Macでビルド&書き込み
MacにインストールしたTinyGoを使ってビルドから書き込みまで一気に実行

```
$ tinygo flash -target trinket-m0 ./main.go
```

###パターン2. Dockerでビルド&Macから書き込み
Mac上でDockerを使ってビルドして、書き込みはMacから実行
Trinket M0はUSBマスストレージとして扱えるので、ビルドで生成されたUF2ファイルをドラッグ&ドロップで書き込み

```
$ docker run --rm -v $(pwd):/src -w /src tinygo/tinygo:0.12.0 \
tinygo build -o /src/flash.uf2 -size=short -target trinket-m0 ./main.go
```
#実行結果
![IMG_20200301_004751.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79375/c7524180-831d-6f97-6be3-ad6f2bd05ffd.jpeg)
情绪管理

不能做情绪的主人，就只能做情绪的奴隶。
情绪是能量，流动的能量。驾驭情绪，生命充满能量。
例如；愤怒是捍卫的能量，捍卫自己的尊严，价值。
如果驾驭不了，情绪就两极化发展。
一极是找不到情绪，情绪消失了，没有生命的能量，结局就是忧郁症；
另外一级，情绪成为活火山，随时会爆发，不明就理的爆发。

常见情绪的三大类。
恐惧，愤怒，悲伤。
情绪失控的时候，身体付出代价，人际关系出现问题，伤害家人朋友。
认识情绪，掌控情绪，驾驭情绪，成为情绪的主人，先要把情绪当朋友。
幼时，生气，骂人，大哭 这些情绪被认为不吉利，不能被很好的自然接受，尊重。以至于成长过程中，没有学会处理情绪。

该如何处理情绪？
当你很生气的时候，怎么办？
闭起眼睛，默念四句口诀,我知道你很生气，你可以生气，生气没有关系，我在这里陪你。
慢慢地念，多念几遍。
接纳自己的情绪，不要拒绝你的情绪。
不要再骂自己你很没用，已经发誓再也不要生气，为什么还会再生气。
情绪管理不是消灭情绪，是跟情绪做朋友，接受他，允许他。
情绪的爆发往往就在一瞬间。要表达情绪就要先处理情绪，察觉而不发作。
我知道我在生气，但是不要立马发作。
有情绪的时候要处理情绪，没有情绪的时候才处理问题。
不要在有情绪的时候处理问题。
处理情绪一定要独处。跑去找别人讲话，或者做家务都不是处理情绪的方法。一定要停下来，找个安静的地方，散步，思考。
先跟情绪做朋友，我知道你很生气，你可以生气，生气没有关系，我在这里陪你。自己陪自己。

等情绪稳定下来，跟情绪对话，情绪是在告诉你，你真实的自己是怎么一回事。
了解情绪，跟情绪做探讨。就会越来越了解真实的自己。反而言之，逃避情绪就是逃避做一个真实的自己。
情绪会告诉你是怎样一个人，情绪会告诉你为什么这么生气。你在气什么？这个人为什么这么让你生气。
你的生气只是因为他，还是你的生气跟过去的成长经历有关系,跟小时候的遭遇有关。

一定要知道没有人可以让你生气，除了你自己。
一定不是一个人说了什么话，做了什么事让你生气；同样一个人对别人说了同意的话，做了同样的事，别人就不会生气，因为他不在乎。为什么别人不生气，你就那么生气呢？可能他的言行碰触了你生命的地雷。

可能你的成长历程中有很多未解决的伤痛，在你的生命中埋下地雷。
所以再与人交往中，不小心就会触碰到那颗地雷。就会爆炸。
要问自己，是那个人触碰了你的地雷你会爆炸，还是你自己心里有颗地雷所以才你会爆炸。

举个生活例子，你手指头有个伤口，有杯盐水，你手指头碰到盐水会痛。所以问题是你要处理这杯盐水？还是要处理你手指头的伤口。如果你的手指头没有伤口，有多少盐水都不会痛。
有人说手指头有伤口不要碰盐水就好啊。其实每一个人都是一杯盐水。只是每一个人咸的程度不一样。
你也是一杯盐水，别人碰你，他的伤口就会痛。越亲密的人越容易触碰到对方的伤口。
如果总是很爱生气，要反思是不是自己伤口很多。要先处理自己的问题。

每一个生命个体再诞生的时候是美好的，但是出生的环境造成后来的性格差异。
最主要的就是家庭环境，父母之间的相处，父母对你态度，是我们情绪产生的来源。
每个人心里都住着小孩，他就是你的情绪。他可能就是小时候经历的各种事情，产生了现在的情绪。
情绪管理就是学会照顾内心的小孩子。要有力量保护内心的小孩。

没有一个关系重要到让你失去自己。
有人为了挽留爱情，活得没有了自己。最后还是留不住。

生命的两大支柱，1.要先照顾自己；2.与人友善。
生命力在哪里失去在哪里找回。
高境界地管理情绪，用文字表达情绪。有情绪的时候，设定15分钟，给自己写信，跟自己对话。

学习台湾大学刘仁州先生《學習做自己情緒的主人》的课程学习笔记发表。
JavaScript でライブラリを使わず日時文字列 (yyyyMMddHHmmss) を Date オブジェクトに変換する

## 日時文字列 (yyyyMMddHHmmss) → Date オブジェクト

```javascript
/**
 * yyyyMMddHHmmss な文字列を Date オブジェクトに変換
 * @param {string} strDate
 */
function stringToDate(strDate) {
    const year = parseInt(strDate.substring(0, 4))
    const month = parseInt(strDate.substring(4, 6))
    const date = parseInt(strDate.substring(6, 8))
    const hour = parseInt(strDate.substring(8, 10))
    const min = parseInt(strDate.substring(10, 12))
    const sec = parseInt(strDate.substring(12, 14))
    return new Date(year, month, date, hour, min, sec)
}
```


## Date オブジェクト→ 日時文字列 (yyyyMMddHHmmss)

```javascript
/**
 * Date オブジェクトを yyyyMMddHHmmss 形式の文字列に変換
 * @param {Date} date 変換対象の Date オブジェクト
 */
function dateToString(date) {
    const strYear = String(date.getFullYear()).padStart(4, '0')
    const strMonth = String(date.getMonth()).padStart(2, '0')
    const strDate = String(date.getDate()).padStart(2, '0')
    const strHour = String(date.getHours()).padStart(2, '0')
    const strMin = String(date.getMinutes()).padStart(2, '0')
    const strSec = String(date.getSeconds()).padStart(2, '0')
    return strYear + strMonth + strDate + strHour + strMin + strSec
}
```

**※ padStart() は IE 未対応なので注意**

## 参考ページ

- String.prototype.substring() - JavaScript | MDN
    - https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/string/substring
- String.prototype.padStart() - JavaScript | MDN
    - https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/padStart
- Date - JavaScript | MDN
    - https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date
pypiのlong_descriptionにMarkdownが使えなくてハマった話

# 結論

- 自作ライブラリ([mong](https://github.com/toshihikoyanase/mong)) を [pypi](https://pypi.org/project/mong/) に登録しようとしたらパッケージ説明(README.md)のフォーマットエラーで怒られた
- `long_description_content_type` は指定してあるのにreStructuredTextだと認識されている
- `setup.py` では `distutils.core.setup` ではなく `setuptools.setup` を使えば解決

気づけば解決は一瞬でした。あまりsetup.pyを一から作る機会はないので、今後のために記録しておきます。（３日後の自分は他人）

# 経緯

[mong](https://github.com/toshihikoyanase/mong)のpypiの説明文が崩れているのがずっと気になっていました。Markdownだと認識されておらず、 `setup()`の引数に`long_description_content_type="text/markdown"`は指定してあるのに、タイポかなと思っていました。本家のほうで新しい名前が追加されたので、バージョンアップをすることになり、先送りしていたこの問題にも取り組みました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133233/1e778783-0e4e-dd9c-8f86-e52dc3cfba78.png)

# 調査

## `twine check` を使おう

はじめは test.pypi でテストをしていましたが、途中で `twine check` を使えば手元で検証できることに気づきました。これで検証のサイクルが高速化できました。

twineでのチェック結果は下記のとおりで、やはり `long_description_content_type` が指定されていないと出ます

```console
% twine check dist/mong-0.0.1.tar.gz
Checking dist/mong-0.0.1.tar.gz: FAILED
  `long_description` has syntax errors in markup and would not be rendered on PyPI.
    line 13: Warning: Inline literal start-string without end-string.
  warning: `long_description_content_type` missing.  defaulting to `text/x-rst`.
```

## 調査項目

下記の項目を順次調べていきました。結局全部関係ありませんでしたが、 `PyPI`やパッケージの理解が深まりました。 説明文は `mong-0.0.1/PKG-INFO` を見て生成されているらしい、など。

- typo: [Python公式ドキュメントの例](https://packaging.python.org/tutorials/packaging-projects/#creating-setup-py)をコピペしてもだめだったので違いそう
- [他の項目のフォーマット違反](https://github.com/pypa/twine/issues/454): 入力項目を最小にしても、なお起こる
- [setuptoolsのバージョンが古い](https://medium.com/@chezou/1%E8%A1%8C%E4%BF%AE%E6%AD%A3%E3%81%A7%E6%96%B0%E3%81%97%E3%81%84pypi%E3%81%A7markdown%E3%81%AE%E3%83%89%E3%82%AD%E3%83%A5%E3%83%A1%E3%83%B3%E3%83%88%E3%81%8C%E4%BD%BF%E3%81%88%E3%81%9F-14e40d90ff3f): setuptoolsはv38.6.0からMarkdownに対応とのことだが、 `45.2.0`を使っている

# 原因と対策

で、ふとコードの先頭を見ると、そもそも `setuptools` を使っていませんでした。古い `distutils` を使っていたとは、完全に想定外です（自分のコードなのに）。

https://github.com/toshihikoyanase/mong/blob/v0.0.1/setup.py#L1

```python
from distutils.core import setup
```

`setuptools`に差し替えればよいはず。

https://github.com/toshihikoyanase/mong/blob/v0.0.2/setup.py#L1

```python
from setuptools import setup
```

無事、Markdownで説明文がレンダリングされるようになり、一安心。v0.0.2のリリースもできました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133233/43f5dc51-e6e0-2499-216e-5f3eb101c681.png)