OmniAICreator/Qiita-1.07M huggingface dataset:
djangoアプリのリレーション〜多数対多数編

今回のお題
-
今回はdjangoアプリに多数対多数のリレーションを実装していきます。

１対多数のリレーションについては以下をご参照ください。

https://qiita.com/keishi04hrikzira/items/5857104fc947cef0ea90

目次
-

- models.py
- views.py, テンプレート
- おまけ〜中間テーブル
- 終わりに

models.py
-
１対多数の場合と同じく、models.pyにリレーションを記述していきます。

なお今回は、メンバーを何人か選択してチャットルームを作成するアプリを想定します。

チャットルームには複数のメンバーが参加していますし、逆に同一のメンバーが複数のチャットルームに参加することもあり得るので、多数対多数の結びつきになります。

```python:models.py
class Member(models.Model):
  name = models.CharField(verbose_name="名前", max_length=30)

class Room(models.Model):
  name = models.CharField(verbose_name="ルーム名", max_length=20)
  members = models.ManyToManyField(Member)
```

基本的には

```python
"フィールド名" = models.ManyToManyField(対象のモデル)
```
と記述するだけでOKです。

views.py,テンプレート
-
リレーション先の取得方法は基本的に１対多数の時と同じです。

多数対多数であっても親子の区別はあることに注意してください。

今回は`members`というフィールドを設定したRoomモデルが子供側になります。

```python:views.py
# 親側はxxx_set.allで取得
rooms = member.room_set.all

# 子供側には_setは不要
members = room.members.all
```

おまけ〜中間テーブル
-
他の言語のフレームワークと同じように、djangoでも多数対多数のリレーションは中間テーブルで管理されています。

ただし自分で定義するのではなく、上記の`ManyToManyField`を定義してマイグレーションした時点で自動で生成されるようです。

なので例えば上記のRoomモデルのテーブルであればmembersというカラムがDBに存在するわけではなく、実際には以下のようなテーブルで両者のリレーションが管理されているようです（たまたま手元にあったコードのコピペなので、上記とはモデル設定が異なります。少しややこしいですが、`author`を`room`、`book`を`member`と読み替えると整合性が取れるようになります）。

```shell
sqlite> .schema main_author
CREATE TABLE IF NOT EXISTS "main_author" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(20) NOT NULL, "address" varchar(100) NOT NULL);

sqlite> .schema main_author_books
CREATE TABLE IF NOT EXISTS "main_author_books" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "author_id" bigint NOT NULL REFERENCES "main_author" ("id") DEFERRABLE INITIALLY DEFERRED, "book_id" bigint NOT NULL REFERENCES "main_book" ("id") DEFERRABLE INITIALLY DEFERRED);

CREATE UNIQUE INDEX "main_author_books_author_id_book_id_6fa9303d_uniq" ON "main_author_books" ("author_id", "book_id");
CREATE INDEX "main_author_books_author_id_fe7fb621" ON "main_author_books" ("author_id");
CREATE INDEX "main_author_books_book_id_e205b261" ON "main_author_books" ("book_id");
```
後半のINDEXの部分に関する説明は省略しますが、
- 子供側のテーブルにも親側を参照するカラムは作られない
- その代わりに中間テーブルが作られ、多数対多数のリレーションが管理される。

ということをご認識いただければ大丈夫かと思います。

終わりに
-
以上でdjangoアプリに多数対多数のリレーションが実装できました。

中間テーブルが勝手に作られるので、便利と言えば便利ですね。

ただ、その分内部でどのような処理になっているのかがブラックボックスになりやすいので、そこはしっかりと押さえていきたいと思います。
[GAS]二元配列から一部の二元配列を取り出す

どこかしらに落ちてそうな内容なのに全然見つからなかったのでメモとして
やってること自体は簡単な組み合わせなので言及するほどでもないってことかな……

使っているpush,sliceについては他のサイトを参考にしてください

例としてA1:C3に以下の表が入ってるとします。

|a  |b  |c  |
|---|---|---|
|1  |2  |3  |
|4  |5  |6  |


<b></b>
<b></b>
<b></b>

コード

```aiueoooo.gas
function etractArray(){
　const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getActiveSheet();
  const range = sheet.getRange('A1:C3');
  const values = range.getValues();

  //空の配列を用意
  array = []


  //for+pushで空配列"array"にvaluesから1行ずつ押し込んでいく
  //sliceで抜き出した行の要素を削る
  for(i=0;i<=1;i++){
    array.push(values[i].slice(0,2))
  }


  Logger.log(values);
  Logger.log(array);
}
```

<b></b>
<b></b>


ログの出力結果は

values

|a  |b  |c  |
|---|---|---|
|1  |2  |3  |
|4  |5  |6  |


array

|a  |b  |
|---|---|
|1  |2  |


こんな感じになるはず
iとsliceの値の決め方を応用すれば色々できそう。
【Django】独自テンプレートフィルターを作る

## 独自フィルターが必要になった理由
allauthのsocialaccountで、プロバイダ（twitter）から取得する画像の処理をviews.pyに書くのが面倒だったので独自フィルターを作りました。

twitterから取得できる`profile_image_url_https`は、小さいサイズ（_normal）なので、独自フィルターを作成してこれを通常のサイズに変更していきます。

::: note warn
Django-allauthの仕様で書いてありますが、allauthが無くても基本は同じです。
:::

https://docs.djangoproject.com/en/3.2/howto/custom-template-tags/#howto-writing-custom-template-tags

## twitterの画像の仕組み
twitter APIで取得できるURL

```python
# デフォルト
profile_image_url_http = "https://pbs.twimg.com/profile_images/12341234/hoge_normal.png"
```

https://developer.twitter.com/en/docs/twitter-api/v1/accounts-and-users/user-profile-images-and-banners

ファイル名の後ろに付く`_normal`が画像を小さくしてしまっているのでこれを加工する。

|指定|サイズ|
|---|---|
_mini|24 × 24
_normal|48 × 48
_bigger|73 × 73
無し|オリジナル

もしviews.py内で処理したい場合は

```python:views.py
# userのtwitter情報を取得
twitter_accunt = user.socialaccount_set.filter(provider='twitter')
# プロフ画像のURLを取得
t_image = twitter_accunt.values("extra_data")[0]["extra_data"]["profile_image_url_https"]
# _normalをreplaceで削除（置換）
t_image.replace("_normal", "")
```
これでオリジナルサイズの画像のURLが取得できる。

プロフ画像を取得するコードがちょっとナンセンスな気がしますが・・・w

もっとスマートにできる気も？

## 独自テンプレートフィルターを作る
前置きが長くなりましたが早速作ってみる。

1. <b>アプリケーション</b>直下に`templatetags`のディレクトリを作成
1. `templatetags`内に、空の`__init__.py`ファイルを作成
1. `templatetags`内に、`hoge.py`ファイルを作成

```html:
project dir
  |- appname dir
    |- templatetags
      |- __init__.py
      |- hoge.py
```

:::note info
hoge.pyは{% load hoge %}と.htmlで呼び出す名前になります。
:::

ここまで出来たら`hoge.py`ファイルにフィルターの中身を書いていく。

今回は画像のURLの`_normal`を削除したいので、そのフィルターを作る。

```python:hoge.py
# この２つはコピペでOK
from django import template
register = template.Library() 

# twitter_replaceというフィルターを登録
@register.filter
def twitter_replace(value):
    # replaceで書き換える
    return value.replace("_normal","")
```

これで`twitter_replace`をテンプレートフィルターとして使えば、置換されるようになります。

## テンプレートに反映させる

```html:.html
<!-- allauthのsocialaccount用 -->
{% load socialaccount %}
<!-- 先程作ったファイルを読み込む -->
{% load hoge %}

<!-- userはviews.pyの変数 -->
{% get_social_accounts user as accounts %}
<img src="{{ accounts.twitter.0.extra_data.profile_image_url_https | twitter_replace }}">
```

これでオリジナルサイズの画像が表示できるようになります

表示するページが１ページならviews.pyに書いても良いかと思いますが、複数ページに表示したりfor文で回す時などフィルターを作った方が使い回せるので便利だと感じました。

今回の記事とは関係ありませんが、いい感じに`{% include %}`で呼び出すのもありなのかな？


## 補足
* `INSTALLED_APPS`にあるアプリにしか独自テンプレートフィルターは作れない。
* 独自テンプレートフィルターを作成した後は、仮想サーバーを再起動しないと反映されない。
render problem エラーでレイアウトが表示されなくなった話


2021/11/3 初版
2021/12/2 レイアウト微修正
# 事象
AndroidStudioのautofill機能でレイアウトを作っている途中で一回落として再起動したら画像のようにレイアウトが表示されなくなる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1700794/16d90885-47ff-aab7-e8b7-b2c1d7684d38.png)

# 試したこと(もしかしたらこっちで解決する人がいるかも)
- 下記URLに従ってキャッシュを無効化して再起動
    - https://blog.mktia.com/how-to-solve-render-problems-on-android-preview/
    
- APIレベルが高すぎると発生するらしいという記事を見つけたのでレベルを下げる
    - https://teratail.com/questions/24420  

※よくよく読んでみるとAPIレベル23で当時不具合が発生していたという内容っぽかったです
※記事が少し古いので現在同現象が起きるかは未検証

# 原因と解決方法
 - 画像の「android:autofillHints=""」が自動で追加されていたのが原因
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1700794/6a5b8675-ffd7-bf0c-2fff-0ec695d9884b.png)
 - 画像の赤枠部分を削除すると治りました（下は削除後の画像）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1700794/ac70976c-54f6-6ccd-eca4-d3e8371527eb.png)

## 出ているwarningを解決するためには
消すのではなく下記を追加する
``android:autofillHints="no"
``
# 解決時の参考
- https://stackoverflow.com/questions/67419323/how-can-i-solve-android-studio-4-2-rendering-problem
Basic 認証まとめ

Basic 認証の設定方法と自分なりの注意点を
## 開発環境
ruby 2.6.5
Ruby on Rails 5.2.5
MacOS

## 設定方法

大きく２種類のメソッドがありそう

####  １, authenticate_or_request_with_http_basic メソッド

```

 class HogeController < ApplicationController
   before_action :basic_authenticate
  
   def basic_authenticate
     authenticate_or_request_with_http_basic do |name, password|
      name == ENV['BASIC_AUTH_NAME'] && password == ENV['BASIC_AUTH_PASSWORD']
     end
   end
 end

```
#### 2. http_basic_authenticate_with メソッド
```
class ApplicationController < ActionController::Base
  http_basic_authenticate_with name: ENV['BASIC_AUTH_NAME'], password: ENV['BASIC_AUTH_PASSWORD']
end
```
<br>
  
両方とも環境変数を使ったコード

全体に認証をかけたかったら application.controller 内に記入する

以下参考にした記事

https://takagi.blog/adding-basic-authentication-to-a-Rails-application-running-on-heroku/

http://tec-shi.com/rails/628/

## 環境変数の設定方法

### heroku の場合


```:herokuにあげているアプリのカレントディレクトリで

heroku config:set BASIC_AUTH_NAME="（各自で入力）"
heroku config:set BASIC_AUTH_PASSWORD="（各自で入力）"
heroku config で確認
```


以下参考にした記事

https://sitest.jp/blog/?p=9238

### local の場合

#### １, 'dotenv-rails' を使って設定する
https://pikawaka.com/rails/dotenv-rails

上記のテキストの通り

#### 2, ターミナルからマシンに直接設定する(Mac)
```:ターミナル上のどこかで

export BASIC_AUTH_NAME= ”（各自で入力）”
export BASIC_AUTH_PASSWORD=”（各自で入力）”
```

`printenv` をすると自分設定した環境変数を確認出来る

## 注意点

##### Basic 認証はキャッシュが残っていると効かないので、２回目以降の確認の際にはキャッシュの削除が必要


##### ブラウザのキャッシュを消しても heroku のキャッシュは消えない
この点は何回かやってみたのですが、
何回やっても heroku 上での２回目以降の認証ができませんでした。

##### マシン上に環境変数を追加しても時間が立つと消える
本来は ~/.zshrc (もしくは  ~/.bash_profile)に書き込むようです。

##### マシン上に環境変数を設定するときには下手に上書きしないように気をつける
dotenv でやるほうがいいとおもいます
[docker]fatal: unable to access 'https://github.com/oxequa/realize/': Could not resolve host: github.com の解決例

## 何があった？
多人数開発の場面で他の人はうまくいく`docker-compose build`が、下記のエラーで自分だけうまく行かなかった

```:ターミナルの様子
$docker-compose build
Building app
=== 中略 === 
cd .; git clone -- https://github.com/oxequa/realize /go/src/github.com/oxequa/realize
Cloning into '/go/src/github.com/oxequa/realize'...
fatal: unable to access 'https://github.com/oxequa/realize/': Could not resolve host: github.com
package github.com/oxequa/realize: exit status 128
ERROR: Service 'app' failed to build : The command '/bin/sh -c GO111MODULE=off go get github.com/oxequa/realize' returned a non-zero code: 1
```

## 原因
dockerのバージョンが足りていなかった（version2.6だとこのエラーが出た）

## 解決策
dockerのバージョンを上げた（version3.6にした）

## その他のパターン
解決策を探す中で下記の画面の[proxiesを修正すると直るという記事(stackOverflowの記事)](https://stackoverflow.com/questions/20370294/git-could-not-resolve-host-github-com-error-while-cloning-remote-repository-in)もあったので、筆者のもので直らなければこちらも参考にしてみてください。

![スクリーンショット 2021-11-03 14.19.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555157/fce09f9c-5329-77fc-a4b1-c7eb3cb6704a.png)
エントロピーモデル　国沢清典先生　日科技連

```{r}

#p.39 1因子情報路

#Broyden Quasi-Newton Algorithm p.213

f=function(XX){
p=XX[1];q=XX[2];lam=XX[3]
l=2*p+q
H=-p*log(p)-q*log(q)
f1=-log(p)-1-2*H/l+lam*l 
f2=-log(q)-1-H/l+lam*l 
f3=p+q-1
return(c(f1,f2,f3))
}

X=c(1,1,1)

ite=3*10^3
H=diag(f(X))
eta=10^(-2)

for(l in 1:ite){
X_pre=X  
X=X-eta*H%*%f(X)  
X[1:2]=abs(X[1:2])/sum(abs(X[1:2]))
s=X-X_pre
y=f(X)-f(X_pre)
H=H+((s-H%*%y)/as.numeric(t(s)%*%H%*%y))%*%t(s)%*%H
#print(sum(abs(f(X))))
HI=(-X[1]*log(X[1])-X[2]*log(X[2]))/(2*X[1]+X[2])
print(HI)
}



```

```{r}

#p.39 多因子情報路(出力は書籍と一致)

#Broyden Quasi-Newton Algorithm p.213

a=c(1000,2000,3000,4000)/1000

f=function(XX){
p=XX[-length(XX)]
lam=XX[length(XX)]
l=sum(a*p)
H=sum(-p*log(p))
val=-log(p)-1-a*H/l+lam*l
return(c(val,sum(p)-1))
}

X=rep(10,length(a)+1)

ite=2*10^3
H=diag(f(X))
eta=10^(-2)

for(l in 1:ite){
X_pre=X  
X=X-eta*H%*%f(X)  
X[-length(X)]=abs(X[-length(X)])/sum(abs(X[-length(X)]))
s=X-X_pre
y=f(X)-f(X_pre)
H=H+((s-H%*%y)/as.numeric(t(s)%*%H%*%y))%*%t(s)%*%H
#print(sum(abs(f(X))))
HI=sum(-X[-length(X)]*log(X[-length(X)]))/sum(a*X[-length(X)])
print(HI)
}



```

```{r}

#p.79　Darroch and Ratchiff

s=2
n=5
bs=matrix(sample(1:9,s*n,replace=T),ncol=n)
ks=sample(1:9,s,replace=T)

q=sample(seq(0,1,0.01),n)

ts=0.01

asi=ts*bs
hs=ts*ks
if(sum(apply(asi,2,sum)<1)>0){
asi=rbind(asi,1-apply(asi,2,sum))  
hs=c(hs,1-sum(hs))  

}

#等確率はエントロピー最大なので、制約条件により降下する
#制約条件を満たす中でのエントロピーの最大値を求める
p=rep(1/n,n)

ite=10000

for(l in 1:ite){
hsp=asi%*%p
for(i in 1:n){
p[i]=p[i]*prod((hs/hsp)^(asi[,i]))
}    
p=p/sum(p)
H=sum(-p*log(p))
print(H)
}   


```
【Rails6】Ajax学習メモ

#はじめに
Ajaxについて勉強したメモになります
また、Rails及びAjax初学者のため、間違っている可能性もありますので
参考にされる際はご注意ください

##環境
Rails 6.1.4
ruby 2.7.3

#目次
- Ajaxとは
 - 非同期通信とは
 - 同期通信とは
- RailsでAjax処理を実装
 - 環境
 - コントローラ、ビュー作成
 - jqueryインストール
 - jquery設定
 - routes修正
 - HTML修正
 - JS修正
- 参考にさせていただいたサイト

#Ajaxとは
Asynchronous Javascript XMLの略
JavascriptとXMLを使用して、非同期通信を行うこと

##非同期通信とは
ページを更新することなく、一部の変更箇所を反映する
反映するまで他の処理ができる

##同期通信とは
ページ全体を更新し、一部の変更箇所を反映する
反映するまで他の処理ができない

#RailsでAjax処理を実装
![ajax.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1599988/b4f7fbf2-2f80-f5d9-2f0e-299144431159.gif)

![ajax図解.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1599988/1ce05c92-8495-c2d2-1c2d-7ca6ef71e812.jpeg)

##コントローラ、ビュー作成
```erb:ターミナル
% bundle exec rails g controller Practice index
```
##jqueryインストール
```erb:ターミナル
% yarn add jquery
```
##jquery設定
```js:app/config/webpack/environment.js
const { environment } = require('@rails/webpacker')

// ↓追加
const webpack = require('webpack')
environment.plugins.prepend('Provide',
    new webpack.ProvidePlugin({
        $: 'jquery/src/jquery',
        jQuery: 'jquery/src/jquery'
    })
)
// ↑追加

module.exports = environment
```

##routes修正
```erb:config/routes.rb
Rails.application.routes.draw do
  get 'practice/index', to: 'practice#index'
  post 'practice/index', to: 'practice#index'
end
```

##コントローラ修正
```erb:app/controllers/practice_controller.rb
<h1>Ajax</h1>
<%= form_with local: false do |form| %> 
  <%= form.text_field :title %>  
  <%= form.submit "文字列変更" %>  
<% end %>
```

##HTML修正
```erb:app/views/practice/index.html.erb
<h1>Ajax</h1>
<%= form_with local: false do |form| %> 
  <%= form.text_field :title %>  
  <%= form.submit "文字列変更" %>  
<% end %>
```

##JS修正
```js:app/views/practice/index.js.erb
$('h1').html("<%= @title %>")
```

#参考にさせていただいたサイト
https://mebee.info/2021/01/31/post-28411/
https://www.sejuku.net/blog/28967
https://qiita.com/jonakp/items/39fecc0f31335328b34e
https://qiita.com/naberina/items/c6b5c8d7756cb882fb20
https://qiita.com/hisamura333/items/e3ea6ae549eb09b7efb9
MiniMagick での画像のリサイズとサムネイル　


アップロード時に画像のリサイズとサムネイルの作成をする

参考にした記事は以下

https://twinbird-htn.hatenablog.com/entry/2018/05/25/231550


## 開発環境
ruby 2.6.5
Ruby on Rails 5.2.5

## 前提
minimagic がインストールされている
carrierwave を導入している




## リサイズ


```:uploadrs/image_uploader.rb 
  # include RMagick or MiniMagick support:
  # include CarrierWave::RMagick
  # include CarrierWave::MiniMagick
```
コメントにされている上記の

```
include CarrierWave::MiniMagick
```
をコメント解除
その後

```:uploadrs/image_uploader.rb 
 process resize_to_fit: [200, 200]
```

このワンラインをいれることでアップロード時に自動的にリサイズされるようになる
（縦横比そのままの 200*200）

## サムネイル

```:uploadrs/image_uploader.rb 
version :thumb do
    process resize_to_fit: [50, 50]
end
```

これをいれることで、好きなview ファイル内で

```:好きなView
 <%= image_tag(@user.user_image_url(:thumb)) %>
```

とするとサムネイルとして表示出来る
これの意味は

```
[モデル名][画像パス保存の属性名]_urlのメソッドには引数にversionのシンボルが渡せます.
(引用元参照)
```

また、サムネイルで画像を丸くするときには CSS で border-radius をあてる
リムーバブルドライブに System Volume Information フォルダを作らせない設定

Windows の検索バーに `gpedit.msc` または `グループポリシーの編集` と入力して、「グループポリシーの編集」を開く。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1188794/e1e44e6d-6ca6-b5c2-7fd4-c11077f9a902.png)

コンピュータの構成/管理用テンプレート/Windows コンポーネント/検索 フォルダーを開く。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1188794/7343701a-4a0d-8537-d50f-e458472cb27e.png)

「リムーバブルドライブ上の場所のライブラリへの追加を許可しない」をダブルクリックし、編集ダイアログを開く。「無効」にチェックを入れる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1188794/d7b868cc-d7f1-c0b3-a535-4e222e88245e.png)
ブラウザでmozJPEGを使って画像を圧縮するサンプル

## ソースコード

https://github.com/deguchi/mozjpeg-on-browser

## 動作デモ

https://deguchi.github.io/mozjpeg-on-browser/

## 動機

写真を扱うスマホアプリをCordovaで作っていて、写真のアップロードに時間がかかる問題を解決したかった。
サーバーに送ってから処理するのではなく、ブラウザ側で処理したい。

画像のリサイズはすでにcanvasを使って行っている。
画像のファイルサイズをmozJPEGで最適化することで、より軽量にして、アップロードの高速化、表示の高速化したい。

## 開発

viteを使っています。  
https://vitejs.dev/


```
npm install
npm start
```


## 使ったライブラリ

@wasm-codecs/mozjpeg  
https://github.com/cyrilwanner/wasm-codecs/tree/master/packages/mozjpeg

このWebAssemblyを使う。  
サンプルはnode。このままではブラウザ上では動かない。

WebAssemblyに入力するimageは、raw image。
CanvasのgetImageDataで得ることができる。

```
const image = ctx.getImageData(0, 0, img.width, img.height)
const encodedImage = await encode(image.data.buffer, {
              width: image.width,
              height: image.height,
              channels: 4
            }, {
              quality: 80,
              colorSpace: 3
            });
```

## トラブルシューティング

encodeを実行すると

```
Uncaught ReferenceError: buffer is not defined
```

というエラーが出るので、

```
<script src="https://bundle.run/buffer"></script>
```

公開されているbufferライブラリをindex.htmlに追加した。


## ポイント

publicディレクトリに、wasmファイルを置いて、url直下でアクセスできるようにした。
mozjpegのwasmファイルは、node_modulesの@wasm-codecs/mozjpegの中からコピー。

```
/public
    mozjpeg.wasm
```

## 結論

結論的には、

```
ctx.canvas.toDataURL('image/jpeg', 0.8)
```

canvasからJPEG画像に変換するときに圧縮率を指定できるので、小さい画像ならmozJPEGで最適化しても大きな差は出ない。  
数MBの画像をアップロードする場合は効果ありあそう。
PythonでOutlookの予定表をキーワード検索してテキストで抽出（メールなどにコピペできる）


## 困ってたこと
顧客とのアポなどので、Outlookの予定表に候補の予定を登録してから、
メールなどにチマチマと候補日程を書くという単純作業があまりに面倒だった。

## 解決策
Pythonのプログラムを作り、コマンドプロンプトからキーワードを入力して、
テキストでコピペできるようにした。
ちなみに、今日以降という条件も入れている。

## 環境
・Windows10

## 事前準備 
・Pythonのインストール（当たり前ですが）
・win32comのインストール
　コマンドプロンプトで次のコマンドを実行

```
pip install -U pypiwin32
``` 

## 動かすプログラム

```python:schedule.py
import win32com.client, sys, datetime

outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
calender = outlook.GetDefaultFolder(9).items
items = sorted(calender, key=lambda calendar:calendar.start)
now = datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=9)))
weekday_liset = ['月', '火', '水', '木', '金', '土', '日']
keyword = sys.argv[1]
extract_items = []

for item in items:
    if keyword in item.subject and item.start >= now:
	        extract_items.append(item)

for extract_item in extract_items:
    print(extract_item.subject + "：" + extract_item.start.strftime("%Y/%m/%d(") + weekday_liset[extract_item.start.weekday()] + extract_item.start.strftime(") %H:%M") + "～" + extract_item.end.strftime("%H:%M"))

```

## コマンドと結果の例
・schedule.pyはC:\Users\hoge-userに格納
・コマンドプロンプトで実行

```
C:\Users\hoge-user>python schedule.py hoge
hoge（調整中）：2021/11/17(水) 14:00～14:30
hoge（調整中）：2021/11/18(木) 14:30～15:30
hoge（調整中）：2021/11/19(金) 10:30～11:30
```
・微妙にレスポンスが遅い気もする（仕方ないけど）。
・登録してから検索に引っかかるまで、若干タイムラグがあることも。

## 結果をコピーするための設定
・コマンドプロンプトのプロパティ
　簡易編集モードをチェック、行の折り返し選択を有効にするをチェックしない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223350/013932ff-9ff3-d088-261e-776bde149d9e.png)

## コピペで完了
こんな感じで、矩形で選択してEnterでコピーできる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223350/706c5d02-7dc5-f880-6213-1d2772412f77.png)

ペーストして完了。
2021/11/17(水) 14:00～14:30
2021/11/18(木) 14:30～15:30
2021/11/19(金) 10:30～11:30

他により良い手段がありましたら、ぜひご教示ください。
【Swift】AVPlayerの再生と一時停止を切り替える

Swiftで導入したAVPlayerの再生と一時停止を切り替える方法。

今回はUIButtonで再生と一時停止を切り替える方法を書きます。

## 実装コード

### モジュールを導入

```swift
import UIKit
import AVFoundation
```

### 変数・定数の定義

```swift
var videoPlayer: AVPlayer!

enum AVStatus {
    case playing
    case stoped
}
var av_status : AVStatus = .stoped

let switchbutton = UIButton()
```

### AVPlayerの設定

```swift
guard let path = Bundle.main.path(forResource: "sample", ofType: "mp4") else {
    fatalError("動画が見つかりませんでした")
}
let fileURL = URL(fileURLWithPath: path)
let avAsset = AVURLAsset(url: fileURL)
let playerItem: AVPlayerItem = AVPlayerItem(asset: avAsset)

// AVPlayerの作成
videoPlayer = AVPlayer(playerItem: playerItem)

// AVPlayerを追加
let layer = AVPlayerLayer()
layer.videoGravity = AVLayerVideoGravity.resizeAspect
layer.player = videoPlayer
layer.frame = view.bounds
view.layer.addSublayer(layer)
```

### 再生・一時停止ボタンの設置

```swift
switchbutton.backgroundColor = UIColor.black
switchbutton.setTitle("再生する", for: UIControl.State.normal)
switchbutton.addTarget(self, action: #selector(onButtonTapped), for: UIControl.Event.touchUpInside)
view.addSubview(switchbutton)
```
＊位置やサイズはお好みで設定してください。

### ボタンタップの処理

```swift
@objc func onButtonTapped(){
    
    if av_status == .playing{
        switchbutton.setTitle("一時停止", for: UIControl.State.normal)
        videoPlayer.pause()
        av_status = .stoped
    }
    else{
        switchbutton.setTitle("再生中", for: UIControl.State.normal)
        videoPlayer.play()
        av_status = .playing
    }
}
```

## 参考
https://swiswiswift.com/2020-02-21/

## Swiftのお役立ち情報

https://wagtechblog.com/programing/swift-iphone-application-school

https://wagtechblog.com/programing/swift-textbook.html
【資格合格記】AWS DVAに合格したので振り返る

2021/10/30（土）にAWS認定資格の一つであるDVAに合格しました。

![キャプチャ1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185028/a29f745f-119e-f45e-eddd-564071acbfa7.png)

振り返りとして、学習期間や使った教材などをまとめておこうと思います。


# 筆者情報

主にweb系のエンジニア。
AWS歴は１年くらいです。
EC2,S3,RDSを使って会社ではwebシステム作ってます。
IAMロールとかの権限系はインフラチームに作ってもらってました。。

# 学習期間

大体、一か月程度です。
10月にちょっと時間が取れそうだったので、その月に学習を始めて受験しました。
10月末に予約を入れて、ダラダラ学習期間を伸ばさないようにしていました。

# 購入した教材

実際に買って使った教材を、長所・短所分けて書いていきます。

## [ポケットスタディ AWS認定デベロッパーアソシエイト](https://www.amazon.co.jp/dp/B099MFXYYL/ref=dp_kinw_strp_1)

DVA特化の参考書といえばこれしかなかったので購入しました。

### 長所
 - 出題されるカテゴリ毎にサービスの解説がされており、読みやすかった
 - 問題も付いており理解度のチェックもできる

### 短所
 - 各章末の問題の答えには、解説がない問題もある

## [Udemy AWS 認定デベロッパー アソシエイト模擬試験問題集](https://www.udemy.com/course/aws-31955/)

参考書を終えた後に購入

### 長所
 - 問題量が多い割に、値段が安い。セール時ならかなりお得
 - 一つひとつの解説が丁寧で参考書にはなかった知識も得られる

### 短所
 - めちゃくちゃ難しい。半分くらいしか取れなかった

## [AWS問題集で学習しよう](https://aws.koiwaclub.com/)

Udemyのが難しすぎていまいち自信が付かなかったのでこちらにもお金を払いました。

### 長所
 - 解説が丁寧で、間違いの選択肢がどうしてダメなのかも書いてくれている
 - 難易度が本番試験とかなり近い
 - 似たような問題も本番で出題されたため、本番前の実力チェックには最適と感じた

### 短所
 - Udemyと比べるとかかる料金が高いです。その分SAAやSOAの問題にも挑戦できるのですが、利用期間も決まっているのでダラダラやるのはやめた方がいいでしょう。

# 無料の教材
下記の教材は無料で使うことができます。
私は、問題集の解説での不明点を解消するために使用しました。
公式の情報なので活用しない手はないと思います。

- [Black Belt](https://aws.amazon.com/jp/aws-jp-introduction/aws-jp-webinar-service-cut/)
- [AWS公式ドキュメント](https://docs.aws.amazon.com/ja_jp/)
Oracle Linux 7.9にDockerをインストールした際の備忘録

# 結論
「[Install Docker on Oracle Linux 7](https://blogs.oracle.com/virtualization/post/install-docker-on-oracle-linux-7)」に従えば、インストールできます。

# はまったポイント
私は初めに「[Oracle Linux — Docker-docs-ja 1.13.RC ドキュメント](https://docs.docker.jp/engine/installation/linux/oracle.html)」に従ってDockerをインストールしようとしました。

初めにyumリポジトリを手動で追加します

```
$ sudo tee /etc/yum.repos.d/docker.repo <<-EOF
[dockerrepo]
name=Docker Repository
baseurl=https://yum.dockerproject.org/repo/main/oraclelinux/7
enabled=1
gpgcheck=1
gpgkey=https://yum.dockerproject.org/gpg
EOF
```

しかし、`baseurl`に指定した`yum.dockerproject.org`は現在（2021/11/03）存在していないようです。そのため、手動でリポジトリを追加した後に、`yum install xxx`や`yum update`をすると、以下のエラーとなります。

```
"Could not resolve host: yum.dockerproject.org; Unknown error"
```

解決策は、`/etc/yum.repos.d/docker.repo`を削除してから、「[Install Docker on Oracle Linux 7](https://blogs.oracle.com/virtualization/post/install-docker-on-oracle-linux-7)」に従って正しいリポジトリを作成することです。

```
# cd /etc/yum.repos.d/
# wget http://yum.oracle.com/public-yum-ol7.repo
# vi public-yum-ol7.repo

[ol7_latest]
name=Oracle Linux $releasever Latest ($basearch)
baseurl=http://yum.oracle.com/repo/OracleLinux/OL7/latest/$basearch/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-oracle
gpgcheck=1
enabled=1

[ol7_UEKR4]
name=Latest Unbreakable Enterprise Kernel Release 4 for Oracle Linux $releasever ($basearch)
baseurl=http://yum.oracle.com/repo/OracleLinux/OL7/UEKR4/$basearch/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-oracle
gpgcheck=1
enabled=1

[ol7_addons]
name=Oracle Linux $releasever Add ons ($basearch)
baseurl=http://yum.oracle.com/repo/OracleLinux/OL7/addons/$basearch/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-oracle
gpgcheck=1
enabled=1
```

# 参考
- [Install Docker on Oracle Linux 7](https://blogs.oracle.com/virtualization/post/install-docker-on-oracle-linux-7)
- [Oracle Linux — Docker-docs-ja 1.13.RC ドキュメント](https://docs.docker.jp/engine/installation/linux/oracle.html)
cutコマンド備忘録(ちょっとだけawk)

#はじめに
Linuxのcutコマンドのオプションを度々忘れてしまうので復習&備忘録。。


<サンプルコード>

```
$ cat list_fruit
01:apple,りんご:120円 aomori
02:orange,オレンジ:100円 ehime
03:banana,バナナ:95円 miyazaki
```

## 文字数を指定して切り取りたい

#### 1〜2文字目までを切り取る。

```
$ cut -c 1,2 list_fruit
01
02
03
```

#### 1〜12文字目までを切り取る。

```
$ cut -c 1-12 list_fruit
01:apple,りんご
02:orange,オレ
03:banana,バナ
```

#### 12文字目以降を切り取る。

```
$ cut -c 12- list_fruit
ご:120円 aomori
レンジ:100円 ehime
ナナ:95円 miyazaki
```

## ある特定の文字で区切りたいとき
```
$ cut -d <区切り文字> -f <項目数> ファイル名
```
注) -dと-f はセットで使う必要がある。


#### カンマで区切られた1番目のフィールドを切り出す。

```
$ cut -d ',' -f 1 list_fruit
01:apple
02:orange
03:banana
```

#### スペースで区切られた1番目のフィールドを切り出す。

```
$ cut -d ' ' -f 1 list_fruit
01:apple,りんご:120円
02:orange,オレンジ:100円
03:banana,バナナ:95円
```

#### スペースで区切られた2番目のフィールドを切り出す。

```
$ cut -d ' ' -f 2 list_fruit
aomori
ehime
miyazaki
```


###番外編

ふと思ったのだが、複数の区切り文字を使いたい時は、どうするんだ。。
例えば、apple, orange, bananaの部分だけを取り出したい時。
もちろん文字数が違うから`-c`では指定できない。
`-d`と`-f`を使って、`:`と`,`の間を`複数の区切り文字を使って`指定したい。。

調査した結果、<b>cutコマンドでは複数の区切り文字は使えない！</b>
→awkコマンドを使えば可能!

```
awk -F'[区切り文字]' '{print $表示したい項目}'
```

↓これでapple達が取れる。

```
$ awk -F'[:,]' '{print $2}' list_fruit
apple
orange
banana
```

ちなみに`print $1`をやってみるとこんな感じ

```
$ awk -F'[:,]' '{print $1}' list_fruit
01
02
03
```
ElasticBeanstalk with ALBを簡単に(雑に？)https対応する

## 目的
ElasticBeanstalkが設定してくれるドメイン (*.ap-northeast-1.elasticbeanstalk.com)　を、簡単にhttps対応にしたい。

## 結論
自己署名証明書、ACM(AWS certificate manager)を使う

## 手順

### openssl インストール

```
# Macデフォルトのopensslと、AWSドキュメントで使用されているopenssl差異があるためインストール
brew install openssl
```

```
% /usr/local/opt/openssl/bin/openssl version
OpenSSL 3.0.0 7 sep 2021 (Library: OpenSSL 3.0.0 7 sep 2021)
```

### 自己証明書とプライベートキー生成

```
# 東京リージョンの場合
# rsa:4096にすると、ALBに載せたときにエラーが起こるので rsa:2048
# 
sudo /usr/local/opt/openssl/bin/openssl req -x509 -days 365 -nodes -newkey rsa:2048 -keyout test.key >test.crt <<-EOT                                                                                                                    
JP
Tokyo-to
Nakano-ku
Example Incorporation
Example Devision
*.ap-northeast-1.elasticbeanstalk.com
contact@example.com
EOT
```

### ACM上、インポート作業

Certificate Manager -> Import
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83488/cb7a2aaa-43ea-3e8e-4ed7-102920781e5d.png)

`test.crt` の 

```
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
```

をCertificate bodyに、

`test.key` の

```
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
```

をCertificate private keyにコピペし、Import

`test.crt` の中身を見る場合

```
openssl x509 -in test.crt -text
```

`test.key` の中身を見る場合

```
cat test.key
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83488/8aea5c58-6879-034e-f8b2-5037b832f5e0.png)

### ElasticBeanstalkコンソール上、作業

```
Configuration -> Load Balancer -> Edit

Listeners -> Add Listener
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83488/20a597c0-d700-c30c-b670-a86be204a885.png)

作業後、apply。環境が立ち上がるまで待ち、立ち上がったら https://~のドメインでアクセスする。

## その他

Macのchromeだと、 `ERR_INVALID_CRT` のようなエラーが出るため、エラーページを表示した状態で `thisisunsafe` とタイプする

## 参考
https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/configuring-https-ssl.html

https://qiita.com/TakahikoKawasaki/items/4c35ac38c52978805c69
update メソッドはクラスメソッドとインスタンスメソッドがある

## 開発環境
ruby 2.6.5
Ruby on Rails 5.2.5


<br>

編集機能の実装の際に
update アクションで

```
 def update
    Blog.update(para_permission)
    redirect_to blogs_path
 end
 private
 def para_permission
    params.require(:blog).permit(:title, :content, :id)
 end

```

として更新をしたところ

```
タイトル	内容
123	1233	一覧表示	編集	削除
123	1233	一覧表示	編集	削除
123	1233	一覧表示	編集	削除
123	1233	一覧表示	編集	削除
123	1233	一覧表示	編集	削除
123	1233	一覧表示	編集	削除
123	1233	一覧表示	編集	削除
```

要素が全て更新された。

原因は update メソッドをクラスに対して使ったため。


正しくは

```
  def update
    @blog = Blog.find_by(id: params[:id])
    @blog.update(para_permission)
    redirect_to blogs_path
  end
  private
  def para_permission
    params.require(:blog).permit(:title, :content)
  end
```

こう

updateメソッドはクラスメソッドとインスタンスメソッドがあるっぽい
きちんと使いわけないと

また

```
  def update
    Blog.update(para_permission)
    redirect_to blogs_path
  end
  private
  def para_permission
    params.require(:blog).permit(:title, :content, :id) ← 追記
  end
```

としても特定のレコードは更新できなかった。
MattermostをWSL2でビルドする

#概要
Mattermostは，Slack風のチャットツールですが，オープンソースで一般公開されています．

https://github.com/mattermost

本記事では，WSL2でMattermostをビルドするための手順を紹介します．

#前提とする環境
* OS
  * Windows10 Home or Pro
  * WSL2
* Docker
  * Docker for Desktop
    * docker および docker-compose がインストールされている必要あります
* 標準ツール類
  * make
  * git

#ビルドする上で必要なツール類のインストール手順
Mattermostをビルドするために，以下をインストールする必要があります．

* GO(v1.16.0)
* nvm(v10.20.1)

## GO のインストール
WSL2の ${HOME} 上で，goenv をインストールします．

```
$ git clone https://github.com/syndbg/goenv.git ~/.goenv
$ echo 'export GOENV_ROOT="$HOME/.goenv"' >> ~/.bashrc
$ echo 'export PATH="$GOENV_ROOT/bin:$PATH"' >> ~/.bashrc
$ echo 'eval "$(goenv init -)"' >> ~/.bashrc
$ echo 'export PATH="$GOROOT/bin:$PATH"' >> ~/.bashrc
$ echo 'export PATH="$PATH:$GOPATH/bin"' >> ~/.bashrc 
$ source .bashrc
```

次に，go を以下の手順でインストールします

```
$ goenv install 1.16.0
$ goenv global 1.16.0
$ goenv rehash
```

## nvm のインストール
WSL2の ${HOME} 上で，nvm をインストールします．

```
$ curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash
$ source .bashrc
$ nvm install v10.20.1
```

#Mattermostのビルド手順
2021/11/03 時点で，[参考記事](https://qiita.com/microwavePC/items/db2f33dfb5aeb18376ec)の Mattermostバージョンのソースを取得してビルドすると，docker image が存在せずエラーとなりましたので，ここでは v6.0.0 を使用します．

mattermostのソースは，任意のディレクトリ上に`mattermost`というディレクトリ作って，そこで以下のように clone します．

```
$ cd mattermost/
$ git clone https://github.com/mattermost/mattermost-server.git -b v6.0.0 --depth 1
$ git clone https://github.com/mattermost/mattermost-webapp.git -b v6.0.0 --depth 1
```

あとはビルドするだけ．

##webapp 側のビルド手順

```
$ cd mattermost-webapp/
$ make clean
$ make -j4 build
```

##server 側のビルド手順

server 側のビルドが終わると，Webサーバーが起動されます．

```
$ cd ../mattermost-server/
$ ln -nfs ../mattermost-webapp/dist client
$ make run-server
```

#サーバーアクセス方法

まずは，WSL2のIPアドレスを確認しましょう．

```
$ $ ifconfig | grep -A1 eth0 | grep inet | awk '{print $2}'
172.24.36.25
```

Webブラウザ使って，``http://<WSL2のIPアドレス>:8065/``でアクセスします．
成功すると，以下のように，Mattermostの初期画面が見えます．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244147/ccb31def-374b-c518-ece9-5da45ec83540.png)


なお，サーバーを停止するには，``mattermost-server``ディレクトリ直下で，以下のコマンドを叩くことで停止します．

```
$ make stop-server
```

#参考記事

https://qiita.com/microwavePC/items/db2f33dfb5aeb18376ec
長い処理でコマンドプロンプトやPowerShellの出力が止まってしまうときの対処方法

# 問題
長い処理だとコマンドプロンプトやPowerShellの出力が止まってしまう。

# 解決法
## 結論
簡易編集モードを解除すればいい。

## 簡易編集モードの解除方法

1. コマンドプロンプトまたはPowerShellを開く
2. コマンドプロンプトまたはPowerShellのウィンドウの左上に**コマンドプロンプト**または**PowerShell**という文字があるので、それを右クリックする
3. **プロパティ**をクリックする
4. **オプション**タブをクリックする
5. 編集オプションの中の**簡易編集モード(Q)**のチェックを外す（下図を参照）
6. 現在開いているコマンドプロンプトまたはPowerShellを一度閉じて、再び開く
 
![powershell_長時間.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2014686/e996ef68-7494-f6ae-a338-4e6b0803bba4.png)

# 注意
簡易編集モードのチェックを外すと、コマンドプロンプトまたはPowerShellに表示されている文字列をドラッグで選択できなくなります。

文字列をクリップボードにコピーする場合など、表示されている文字列をドラッグで選択したいときは、その都度、簡易編集モードにチャックを入れる必要があります。
Oracle Master bronze DBA 2019(Bronze DBA Oracle Database Fundamentals)に合格した話

2020年から始まった新体系の資格のようで、あまり記事がなかったので書いてみます。

<table>
<tr>
<td>試験名</td>
<td>資格名</td>
</tr>
<tr>
<td>1Z0-085-JPN / Bronze DBA Oracle Database Fundamentals</td>
<td>ORACLE MASTER Bronze DBA 2019</td>
</tr>
</table>

試験の申し込みは、1Z0-085-JPN / Bronze DBA Oracle Database Fundamentals
履歴書に書く資格名は、ORACLE MASTER Bronze DBA 2019
ちょっとややこしいですね。

## 受験のきっかけ

会社で旧体系の資格取得に向けた勉強会がありましたが、自分で勉強した方が早いと思ったからです。ちなみに勉強会はSQLをやっていました。
この時は旧体系のこともいまいちわかっておらず、[このサイト](https://xn--w8j8bac3czf5bl7e.com/2020/03/16/2020%E5%B9%B41%E6%9C%88%E3%81%8B%E3%82%89%E5%B0%8E%E5%85%A5%E3%81%95%E3%82%8C%E3%81%9Foracle-master%E6%96%B0%E8%B3%87%E6%A0%BC%E4%BD%93%E7%B3%BB%E3%81%A3%E3%81%A6%E3%81%A9%E3%82%93%E3%81%AA%E3%82%82/)を見ると旧体系は２つだけど、新体系は１つで合格みたいだし、なら新体系受けた方が楽じゃんと思ってました。
黒本を買って読んでみるとDBAの内容だったので、もう少し詳しく調べるとSQLとDBAが独立した資格になったことがわかりました。
興味があるのはSQLでDBAは全く興味がなかったんですが、折角黒本買ったんだから受けてみることにしました。

## 教材

- オラクルマスター教科書 Bronze DBA Oracle Database Fundamentals

(通称：黒本)

## 勉強期間
- 二週間

## 勉強方法

1. 黒本を1周読みながら章の問題を解く
1. 巻末の模擬問題を解く
1. 黒本を1周読みながら章の問題を解く。わからないところは、黒本の読み直し。
1. 巻末の模擬問題を解く。わからないところは、黒本の読み直し。
1. 章の問題と模擬問題を選択肢を見て、それが正解・不正解になる理由も答える。
1. 章の問題と模擬問題を選択肢を見て、それが正解・不正解になる理由も答える。

多分２〜４周くらいを目安に勉強すればいいと思います。
初見問題っぽいものや、消去法で迷ったものとかもあり、落ちたかなーと思いましたが正解率80%でした。
しっかり勉強して自信を持って試験に臨むなら、他の書籍やDBA 12c(黒本)で勉強するといいかもしれません。
資格だけ取るなら黒本で十分だと思います。

次のステップはSQL Silverかなーと思ってるので、そのうち受けるかもしれません。

## その他

- 申し込みがわかりにくい

Oracleの試験は、２つのサイトに登録する必要があります。
自分はJava Silverの試験の時に登録はしていたので、Bronze DBA Oracle Database Fundamentalsの申し込みは楽でした。
しかし、Bronze DBA Oracle Database Fundamentalsが初めてのOracle試験の場合は手間取ると思います。

- 試験前の写真撮影

Java Silverの時に撮影したし、ないやろーと思ったらありました。テストごとに撮影するっぽいです。
受付の流れで写真撮影するので、レポートを会社に提出するから等の理由で身だしなみを気にする方は受付前にトイレなどで整えるのが吉です。
【Swift】忘れがちな static,public,private 変数 の共有範囲について

# 目的
static,public,private 変数の共有範囲を知ること。筆者のメモ用。

# サンプルコード
```SampleClass.swift

//すべてのクラスから参照可能
let global_let = "global"  //グローバル変数

class SampleClass: NSObject {

    static let str_static = "static"   //クラス変数、他クラスからSampleClass.dddで参照可能
    public let str_public = "public"   //インスタンス変数(クラス内の共通変数)、インスタンス化すると他クラスから参照可能
    private let str_private = "private"   //インスタンス変数(クラス内の共通変数)、他クラスから参照不可

    let str_global = "global"   //インスタンス変数(クラス内の共通変数)、インスタンス化すると他クラスから参照可能
    
    // クラス内メソッド
    func method1(){
        
        let str_local = "local"        //ローカル変数
        print("str_local=",str_local)    //メソッド内でのみ有効
    }

}
```

# ① : static

クラス変数、他クラスから **SampleClass.str_static** で参照可能

```
static let str_static = "static"
```

# ② : public

インスタンス変数(クラス内の共通変数)、インスタンス化すると他クラスから参照可能

```
public let str_public = "public"
```

# ③ : private
インスタンス変数(クラス内の共通変数)、**他クラスから参照不可**

```
private let str_private = "private"
```


# 参考文献
https://cccookie.hatenablog.com/entry/2017/02/18/233914
heroku にデプロイできない


かなり長いこと herokuにデプロイできなくて苦しんだ。

## 開発環境

ruby 2.6.5
Ruby on Rails 5.2.5
bundler 2.2.16



## エラー内容　
heroku にデプロイする際に下記のエラーが発生

```
remote: -----> Compiling Ruby/Rails
remote: -----> Using Ruby version: ruby-2.6.6
remote: -----> Installing dependencies using bundler 2.2.16
remote:        Running: BUNDLE_WITHOUT='development:test' BUNDLE_PATH=vendor/bundle BUNDLE_BIN=vendor/bundle/bin BUNDLE_DEPLOYMENT=1 bundle install -j4
remote:        Your bundle only supports platforms ["x86_64-darwin-19"] but your local platform
remote:        is x86_64-linux. Add the current platform to the lockfile with `bundle lock
remote:        --add-platform x86_64-linux` and try again.
remote:        Bundler Output: Your bundle only supports platforms ["x86_64-darwin-19"] but your local platform
remote:        is x86_64-linux. Add the current platform to the lockfile with `bundle lock
remote:        --add-platform x86_64-linux` and try again.
remote: 
remote:  !
remote:  !     Failed to install gems via Bundler.
remote:  !
remote:  !     Push rejected, failed to compile Ruby app.
remote: 
remote:  !     Push failed
remote: Verifying deploy...
remote: 
remote: !	Push rejected to infinite-bayou-54822.
remote: 
To https://git.heroku.com/infinite-bayou-54822.git
 ! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'https://git.heroku.com/infinite-bayou-54822.git'
```

## 解決策
　push 前にターミナル上で以下のコマンドを入力

```$ bundle lock --add-platform x86_64-linux
$ git add -A
$ git commit -m 'Add platform'
$ git push heroku master
```

これだけいけた

最初はいろいろと調査していくなかで

```
remote:  !     Failed to install gems via Bundler.
```
ここが悪いと思い bundler の様々なバージョンをためしたが、


どうやら僕の場合は

```
remote:        Your bundle only supports platforms ["x86_64-darwin-19"] but your local platform
remote:        is x86_64-linux. Add the current platform to the lockfile with `bundle lock
```

ここが悪かったよう。

ちなみに heroku-20 です。

参考にさせていただいた記事は以下

https://yumishin.com/heroku-push-error/#i-4
tableタグ・Cannot set properties of null (setting 'textContent')

```
      <tr>
        <td id="first">おはよう</td>
        <td id="second">こんにちは</td>
        <td id="third">こんばんわ</td>
      </tr>
```
このようにtableタグで囲み忘れてしまうと、テキスト意外認識してもらえない。なのでcss、javascriptが効かなくなってしまう。
![スクリーンショット 2021-11-03 11.56.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2241999/f0be59bf-411b-d131-d9f9-31152002d1d2.png)
![スクリーンショット 2021-11-03 11.58.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2241999/9764467d-969b-44e5-7738-1420ad9f0597.png)
![スクリーンショット 2021-11-03 11.58.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2241999/e7685bde-b200-7f5a-c7aa-4e2397451ed8.png)
djangoアプリのリレーション〜1対多編

今回のお題
-
今回のお題はdjangoアプリにおけるリレーションの実装です。

リレーションと一口にいってもいくつかのバリエーションがありますが、今回はその中でも`1対多`のリレーションについてまとめます。

目次
-

- models.py
- テンプレート
- おまけ〜select_related
- 終わりに

models.py
-

まずはモデルを用意して、その中に両者の関係性を記述します。

今回は例として書籍のレビューサイトを想定します。

一つの書籍に対して複数のレビューが紐づく可能性があります。

```python:models.py
class Book(models.Model):
  title = models.CharField(maxlangth=30)

class Review(models.Model):
  book = models.ForeignKey(Book, on_delete=models.CASCADE)
  text = models.TextField(max_length=200)
```

注目すべきは、Reviewモデルの以下の部分ですね。

```python
book = models.ForeignKey(Book, on_delete=CASCADE)
```
関連するbookインスタンスの情報を保存するために`book`というフィールドを定義しています。

フィールドの型はForeignKeyで、第一引数は対象となるモデル、`on_deleteオプション`はbookインスタンス削除時の挙動です。

今回は`on_delete=CASCADE`としているので、あるBookインスタンスが削除されるとそこに紐づくReviewインスタンスも全て削除されます。

以下、その他のon_deleteオプションについて載せておきます。

【PROTECT】
関連するレコードが存在する間は削除ができなくなります。

```python
book = models.ForeignKey(Book, on_delete=models.PROTECT)
# レビューが一つでもある書籍は、先にレビューをレビューを消してからでないと削除できない
```

【SET_NULL】
関連するレコードが削除されると`NULL`が削除される。

`null=True`を設定しておく必要がある。

```python
book = models.ForeignKey(Book, on_delete=models.SET_NULL, null=True)
# 関連先の書籍が削除されるとreview.book = nullが自動的に設定される。
```

【SET_DEFAULT】
関連先のレコード削除時に、あらかじめ決められたデフォルト値を設定する。

`defaultオプション`の設定が必須。

```python
book = models.ForeignKey(Book, on_delete=models.SET_DEFAULT, default=xxx)
```

【SET()】
関連先削除時には、引数として与えた値をセットする。

```python
book = models.ForeignKey(Book, on_delete=models.SET(xxx))
```

テンプレート
=
関連先のレコードを取得する際には以下のように記述します。

```django
{# 親モデルから子モデルを取得 #}
{{ book.review_set.all }}

{# 子モデルから親モデルを取得 #}
{{ rev.book }}
```
親から子を取得する際には`xxx_set.all`とする必要があります。

また、上記のコードはveiwsで用いることも可能です。

おまけ〜select_related
-
いわゆる`N+1問題`を解決するためには、`select_related`メソッドを用いるのが便利です。

以下のようにレコード取得の途中で`select_related`メソッドを挟むことで、引数として与えた外部キーの情報を同時に取得することができます。

```python
rev = Review.objects.select_related("book").get(id=pk)
book = rev.book
```

終わりに
-
以上が１対多のリレーションの基本になります。

気が向けば多数対多数についてもまとめます。
DFINITYで遊んでみる ~環境構築~【ICP】

#はじめに
みなさんはDFINITYとは何かご存じでしょうか？
DFINITYとは、ブロックチェーン技術を用いて分散型のクラウドプラットフォームを提供するプロジェクトです。簡単に言えばAWSやGCPのようなものを非中央集権的に使えるようにしよう！ってことです。(たぶん…)
仮想通貨バブルの真っただ中ですが私は乗り遅れたので、DFINITYで遊びたいと思います。
なお、この記事では公式のチュートリアル(https://smartcontracts.org/docs/quickstart/local-quickstart.html )に書かれていることをやるだけです。めちゃくちゃ易しく書かれているので、英語に抵抗がない方は**公式を見ることを強くお勧めします**。

#実行環境
- Ubuntu 18.04 LTS(WSLで実行)
 → Ubuntu 20.04 LTSに変更

現在、DFINITY Canister SDKはmacOSまたはLinuxにしか対応していません。

#環境構築
## Node.jsのインストール
Node.jsが後で必要になるそうなのでインストールします。
Node.jsのパッケージ管理システムであるnpmもインストールします。

```terminal:terminal
$ sudo apt install nodejs 
$ sudo apt install npm 
```

##DFINITY Canister SDKの導入
DFINITY Canister SDKをダウンロードし、インストールします。

```terminal:terminal
$ sh -ci "$(curl -fsSL https://sdk.dfinity.org/install.sh)"
```

パスを通して

```bash:.profile
export PATH=$PATH:/home/user/bin
```

ちゃんと動くか確かめます。

```terminal:terminal
$ dfx --version
```

これでdfxのバージョンが表示されれば良かったのですが、エラーが発生。

```terminal:terminal
dfx: /lib/x86_64-linux-gnu/libm.so.6: version `GLIBC_2.29' not found (required by dfx) 
```

GLIBCのバージョンが古いよ！って怒られてしまいました。一応今使っているバージョンが何か見てみます。

```terminal:terminal
$ /lib/x86_64-linux-gnu/libc.so.6
GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1.4) stable release version 2.27.
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. 
Compiled by GNU CC version 7.5.0. 
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
```

バージョンは2.27を使っていることが分かります。しかしGLIBCをアップデートするのは避けるべきとのことです。

### Ubuntu 20.04に変更
色々と変にいじるよりもUbuntuのバージョンを上げてしまうのが一番お手軽です。
さくっとUbuntu 20.04 LTSをMicroSoftStoreからダウンロード&インストールします。
では、GLIBCのバージョンを確認します。

```terminal:terminal
$ /lib/x86_64-linux-gnu/libc.so.6
GNU C Library (Ubuntu GLIBC 2.31-0ubuntu9.2) stable release version 2.31. 
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 9.3.0.
libc ABIs: UNIQUE IFUNC ABSOLUTE
For bug reporting instructions, please see:
<https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
```
バージョンが2.31になり要件は満たせてそうです。
再び最初からDFINITY Canister SDKのインストールとパスの設定等を行い、今度はちゃんと動くか確認します。

```terminal:terminal
$ dfx --version
dfx 0.8.3
```

しっかりとバージョンを表示することができました。:raised_hands:

#終わりに
とりあえずSDKが使用できる状態にはなりました。
次回は簡単なプロジェクトを作成し動かしてみたいと思います。
続き→ https://qiita.com/YakitoriBoyz/items/2bc3d15c069f5617d4db

#参考
https://smartcontracts.org/docs/quickstart/local-quickstart.html
https://smartcontracts.org/docs/quickstart/newcomers.html
cargo-editのインストール時にopensslのビルドに失敗した

## 環境

MacOS Big Sur 11.6

```zsh
$ rustc -V
rustc 1.56.0 (09c42c458 2021-10-18)
$ cargo -V
cargo 1.56.0 (4ed5d137b 2021-10-04)
```

## 事象

以下コマンドを叩いたら失敗
`cargo install cargo-edit`

エラーログは以下。

```
error: failed to run custom build command for `openssl-sys v0.9.70`

Caused by:
  process didn't exit successfully: `/var/folders/9x/g2ywd3js5qzcpsp8py24hphc0000gn/T/cargo-installqsxcgc/release/build/openssl-sys-7dcc680373887c03/build-script-main` (exit status: 101)

(中略)

error: failed to compile `cargo-edit v0.8.0`, intermediate artifacts can be found at `/var/folders/9x/g2ywd3js5qzcpsp8py24hphc0000gn/T/cargo-installqsxcgc`

Caused by:
  build failed
```

macデフォルトの`openssl`は入っている

```
$ openssl
OpenSSL>
```

## 解決法

homebrewでopensslをインストールしたらできました。

```zsh
$ brew install openssl
$ cargo install cargo-edit
```

opensslのバージョンが古かった・・・？のかな・・・
AWS Day1対応

#はじめに
最近UdemyでAWSの学習を始め、AWSアカウントを作成したのでDay1対応を実施しました。
備忘録として、以下に概要をまとめます。

#Day1対応とは
AWSアカウントを作ったらまずやったほうがいいと推奨されている設定
AWSに足を踏み込んだ者のはじめの一歩

基本的には"セキュリティ"と"請求"についての設定を実施していきます。

#やること
やることは以下の5つ

- MFA(他要素認証)の設定
- パスワードポリシーの設定
- IAMユーザの作成
- CloudTrailの有効化
- 請求アラームの有効化

##MFAの設定
まずは、MFAの設定を実施します。
※MFA = Multi Factor Authentication(他要素認証)

MFAとは、ログイン時にユーザ名・パスワード+αで認証を行う方式のことです。
詳細は割愛します。

AWSではユーザ名・パスワード+ワンタイムパスワードで認証を行います。
ワンタイムパスワードを発行するトークンとしていくつか選択肢がありますが、
Google Authenticatorというアプリを利用できます。
スマホから利用できるため、こちらを利用するのが一番手間が少ないです。


##パスワードポリシーの変更
AWSでは一つのアカウントの中に、IAMユーザというユーザを複数作成することができます。

IAMユーザ作成時のパスワードルールを設定します。

PCなどのパスワードルールと同様に、事前に用意されている条件の中から、
好きな条件を組み合わせてルールを作成できます。

##IAMユーザの作成
AWSアカウントを作成した直後は、ルートユーザという何でもできる権限を持ったユーザのみ存在しています。

ルートユーザは権限が強すぎて、意図しない重大な変更なども行えてしまうという危険性をはらんでいます。
そこで、IAMユーザを作成し適切な権限を割り当てることで、誤って重大な変更ができないように保険をかけます。

また、同じ権限を持ったユーザをたくさん作成する場合、それぞれに設定を加えるのは面倒なため、
グループというものを作成し、ユーザをグループに所属させます。
なお、グループはAWS側で用意してくれているものもあります。

Day1対応としては、管理者権限を持ったユーザを作成するため、
事前に用意されているAdministratorグループへIAMユーザを追加します。

##CloudTrailの有効化
CloudTrailとはログ管理サービスです。
各ユーザのログイン履歴や、自身の構築したAPIの利用履歴などが自動で監視・ログ取得されています。

初期設定では、ログは90日間で削除されてしまいます。
しかし、何かあったときに過去のログを参照することは多いと思います。

ログを長期保存したい場合、
保存先として、S3というストレージサービスかRDSというデータベースサービスを指定できます。

なお、CloudTrailは無料で使うことができます。

##請求アラームの有効化
AWSでは一定の請求額を超えた際にメール等で通知を飛ばす設定ができます。
「気づいたら高額な請求がされていた...」といったことを防ぐためにもこの設定は重要です。

請求アラームの有効化は"請求ダッシュボード"から行います。
また、IAMユーザでこの設定を実施する場合は、前もってIAMユーザによる請求情報へのアクセスを有効化しておく必要があります。(この設定はルートユーザで実施します。)

請求アラームの有効化は東京リージョンでは利用できません。
そこで、画面右上のリージョンをバージニア北部のなどに変更する必要があります。
【Kotlin】toString() 関数

## `Any.toString()`

すべてのクラスのスーパークラスである `Any` には次のようにメンバ関数 `toString()` が定義されている。

```Kotlin
open fun toString(): String
```

→[`Any.toString()` の API ドキュメント](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-any/to-string.html)

これが適切にオーバーライドされたクラスであれば、
そのインスタンスに対してこの関数を呼び出すことで
適切な文字列を得ることができる。

```Kotlin
println(
    listOf("I", "love", "Kotlin", ".")
        .toString()
) // > [I, love, Kotlin, .]
```

## `Any?.toString()`

`null` はオブジェクトではないのでメンバ関数を持たない。

しかし `null` に対してメンバ関数 `toString()` を呼び出しても
コンパイルエラーにならないし、
実行時には `"null"` という文字列が返る。

```Kotlin
println(
    null.toString()
) // > null
```

これは言語仕様でそうなっているという訳ではない。

標準ライブラリーで次の拡張関数が定義されているからこのように動作するのである。

```Kotlin
fun Any?.toString(): String
```

→[`Any?.toString()` の API ドキュメント](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/to-string.html)

`null` に対して文字列 `"null"` を返すことについても API ドキュメントに次のように明記されている。

> Can be called with a null receiver, in which case it returns the string "null".

なお実装は、先述の API ドキュメントからリンクされているが、次のようにシンプルなものである。

```Kotlin
public inline fun Any?.toString() = this?.toString() ?: "null"
```

／以上
TexLive 2021のfancyhdrをバージョンダウンする

# 経緯

ドキュメント作成にLatexを使用することが多いのですが、Windowsで作成するときに使用しているツールは Texlive 2020です。

* TexLiveのダウンロードはこちら

https://www.tug.org/texlive/

\pagestyle{fancy}を使用することが多いのですが、ヘッダーのアルファベットがすべて大文字になってしまうのを防ぐために、かうぱーとさんのブログ記事を参考にさせてもらっています。

http://miyahn.blog80.fc2.com/blog-entry-55.html

こんな感じのtexファイルになります。

```tex
\documentclass[11pt,a4paper]{jsbook}
\usepackage{fancyhdr}
\begin{document}

\makeatletter
\def\ps@fancy{%
\def\chaptermark##1{\markboth{\ifnum \c@secnumdepth>\z@ \thechapter\hskip 0.5em\relax \fi ##1}{}}%
\def\sectionmark##1{\markright {\ifnum \c@secnumdepth >\@ne \thesection\hskip 0.5em\relax \fi ##1}}%
\ps@@fancy
\gdef\ps@fancy{\@fancyplainfalse\ps@@fancy}%
\ifdim\headwidth<0sp
\global\advance\headwidth123456789sp\global\advance\headwidth\textwidth
\fi
}
\makeatother

\pagestyle{fancy}

\chapter{fancyのテスト}

\section{はじめに}

fancyのpagestyleをテストします。

\clearpage

2ページ目

\end{document}
```

#TexLive 2021でのエラー

上記のtexファイルですが、TexLive 2021でタイプセット実行すると以下のエラーが出力されます。

```:エラー表示
This is ptex2pdf[.lua] version 20200520.0.
Processing untitled-2.tex
This is e-pTeX, Version 3.141592653-p3.9.0-210218-2.6 (utf8.sjis) (TeX Live 2021/W32TeX) (preloaded format=platex)
 restricted \write18 enabled.
entering extended mode
(./untitled-2.tex
pLaTeX2e <2020-10-01>+2 (based on LaTeX2e <2020-10-01> patch level 4)
L3 programming layer <2021-02-18>
(c:/texlive/2021/texmf-dist/tex/platex/jsclasses/jsbook.cls
Document Class: jsbook 2020/10/09 jsclasses (okumura, texjporg)
(c:/texlive/2021/texmf-dist/tex/platex/jsclasses/jslogo.sty))
(c:/texlive/2021/texmf-dist/tex/latex/fancyhdr/fancyhdr.sty)
(c:/texlive/2021/texmf-dist/tex/latex/l3backend/l3backend-dvips.def)
(./untitled-2.aux)
! Undefined control sequence.
\ps@fancy ...skip 0.5em\relax \fi ##1}}\ps@@fancy 
                                                  \gdef \ps@fancy {\@fancypl...
l.17 \pagestyle{fancy}
                      
? 
```

どうもps@fancyのところがエラーになっているようですが、詳しいことはよくわかりません。^^;;

## fancyhdrのバージョン比較

fancyhdr.styを比較するとtexlive2020にインストールされているfancyhdrはバージョン3.10、texlive2021のはバージョン4.0.1であることがわかりました。
そこで、fancyhdrをバージョンダウンさせてみます。

# fancyhdrのバージョンダウン

- githubからfancyhdrのリポジトリをクローンします。

```console
git clone https://github.com/pietvo/fancyhdr
cd fancyhdr
```

- バージョン3.10をチェックアウトします。

```console
git checkout V3.10
```

- スタイルファイルを生成します。

```console
tex fancyhdr.ins
```

:::note
リポジトリには元からスタイルファイルが入っていて、上記のコマンドを実行しても変化なしなのでこの手順はいらないのかもしれません。
:::

- 出来上がったファイルを、texliveがインストールされているフォルダにコピーします。

```console
md C:\texlive\texmf-local\tex\latex\local\fancyhdr
copy *.sty C:\texlive\texmf-local\tex\latex\local\fancyhdr
```

- texlive2021のls-Rファイルを更新します。

```console
mktexlsr
```

# 結果

fancyhdrのバージョンダウン後、再度タイプセットを実行するとエラーなくPDF化できました。ヘッダーのアルファベットもちゃんと小文字で出力されています。

![untitled-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570192/162e142a-14ce-e5e0-e35a-3ee04cfb7954.png)

## Texliveのパッケージ参照について

今回の件では、Texlive 2021のdistに入っているfancyhdr V4.0.1を削除してはいません。
localフォルダにfancyhdr V3.10をインストールしてls-Rを更新すると、localのほうが優先されるようです。

もとはといえば、ブログの内容をべた貼りしていることが問題なのかもしれませんが、latexの書式設定って難しくて。。。
何かの参考になれば。
プログラミング初心者のためのQiita記事投稿テンプレート

## はじめに
勉強したことをQiita記事として残す習慣をつけたいと思い、Qiita投稿を始めました。
せっかく書くのだから、わかりやすい記事にしたいですよね？
...でも、毎回構成を考えるのは面倒。
そこで、「とりあえずこれをコピペしてから書き始めればOK！」というQiita記事投稿テンプレートを作成しました。

## 対象者
この記事は下記のような人を対象にしています。

- 駆け出しエンジニア
- プログラミング初学者
- 文章の構成を考えるのが面倒な人
- 初歩的な内容の記事を書きたい人

## 結論
このQiita記事投稿用テンプレートをコピペして記事を書き始めるだけでOK！

## Qiita記事投稿用テンプレート全内容
<pre>## はじめに

## 対象者
この記事は下記のような人を対象にしています。

- 駆け出しエンジニア
- プログラミング初学者

## 結論

## 段落

### 詳細

## おわりに
についてまとめました。

## 参考記事
[リンクタイトル](url)

## その他部品
```php:example.php
コード
```

| No |    内容     |    備考    |
|---:|-------------|------------|
| 1  |             |            |
| 2  |             |            |
</pre>

## Qiita記事投稿用テンプレート各項目解説
### はじめに
「なぜこの記事を書いたのか」を端的に書きましょう。
**「あ、この人も同じことで悩んでたのね、そしてそれを解決したのね！」**ということが分かると安心して読み進められるため、出来るだけ書くようにしています。
### 対象者
「はじめに」とおなじで、**「これは自分向けの内容だな」**と思えることが大事なので、書くようにしています。
### 結論
プログラマーは上から順番に文章を読む人が多いような気がします。
そのため、結論はできるだけ前半に書くようにしています。
### 段落・詳細
ここまで読み進められた人は具体的な内容を知りたいはずです。
実際のコードなども提示しつつ、わかりやすい説明を心がけましょう。
### おわりに
これはなくてもいいかと思いますが、記事のまとまり的に所感みたいなものがあってもいいかと思います。
### 参考記事
参考にした記事は感謝の意味も込めて、きちんと掲載するようにしましょう。
自分の記事が参考にされることもあるかもしれませんね！
### 今回記載しなかった項目
下記の項目はもっと上級者向けの記事の場合には必要になると思います。

- 開発環境
- セットアップ
- 使い方
- デモ

...が、私のような初心者が調べてまとめるような記事には不必要なので省略しました。

## おわりに
駆け出しプログラマー向けのQiita記事投稿用テンプレートについてまとめました。
**「自分のためにまとめたテンプレ、もったいないから公開しよ！」**という軽い気持ちで書き始めましたが、記事になるとそれなりに達成感がありますね。
今後もこのテンプレートを使ってどんどん投稿していこうと思います！



## 参考記事
[はじめてのMarkdownの書き方。まずはこれだけは覚えよう！](https://tonaise.hatenablog.jp/entry/2017/05/04/154334)