OmniAICreator/Qiita-1.07M huggingface dataset:
GTO Wizardの特定のプリフロップシチュエーションを素早く開きたい

## 概要
- GTO Wizardにおいて、特定のプリフロップスポットを開くまでのボタンクリック回数が多く、復習が困難であるためにLaunchヘルパーを作成した
- 実装容易性を優先し、gemとして[glimmer-dsl-libui](https://github.com/AndyObtiva/glimmer-dsl-libui)を用いた

## 完成物
![スクリーンショット 2022-03-09 12.58.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21406/a0f251cb-da19-6588-a81c-ef0682ada810.png)


## 課題

GTO Wizardにおいて復習をする際
「bb数は20bbを選択して... UTG fold... UTG+1 fold... LJ Raise... HJ fold... BU fold... のレンジは?」
という具合に、ボタン操作をするのが大変億劫であるため、復習機会を逃してしまう

## アプローチ

```
https://app.gtowizard.com/solutions?gametype=MTTGeneral&depth=17.125&soltab=strategy_ev&history_spot=6&preflop_actions=F-R2-RAI-C-F-F
```

GTO WizardにおけるURLのクエリパラメータは以下のようになっている
```
depth = bb数 + .125 (.125は謎)
history_spot = UTGから数えたアクションの順番のindex
preflop_actions = F-R2-RAI-C-F-F というような、アクションの履歴
```

このクエリパラメータを作るツールが作れればよい

今回の場合

- Raiseアクション (R2など)は、レイズサイズをツール側が把握していなければならず、マスタの作成が必要になる
- 主に20bb以下のトーナメントポーカーにおけるPreflopの復習が目的であったため、知りたいシチュエーションがAll-in or Fold であることが多い

という2点から、「AnyポジションにおけるAll-in、またそれに対するAnyポジションからのCallが入っている状況での各ポジションの振る舞いを復習するための簡易的なツール」 として作成するのが作業に対するコスパが良いと判断しました。

以下のように、特に難しいことはやっておらず単純な分岐のみのツールとなります。

```ruby
# preflop_actionsのクエリパラメータの作成
# F-F-RAI-C-Fみたいな文字列を作る
def action_text(data)
  action_text = ''
  data.each_with_index do |d, index|
    break if d.has_key?(:target)
    if index > 0
      action_text += '-' # アクションの連結文字
    end
    if d[:call]
      action_text += 'C' # Call
    elsif d[:allin]
      action_text += 'RAI' # Raise All In
#   elsif d[:raise] # Raiseを管理する場合、ポジションごとのRaise額をこのツール側が知っている必要があるので作業時間が必要
    else
      action_text += 'F' # Fold
    end
  end
  action_text
end
```

また、glimmer-dsl-libuiではtable形式のUIの中にcheckboxを表示するオプションもありましたが、Mac OSでは表示専用 (チェックしているかどうかの値を動的に変更して、データとして取得することは出来ない)という制約があるため、今回は **ボタンの上にチェックマークを表示すること** で代用しました。

```ruby
positions = ['UTG', 'UTG+1', 'LJ', 'HJ', 'CO', 'BU', 'SB', 'BB']
actions = { 'All-in': 1, 'Call': 2 }
settings = positions.map { |position| [position, '', '', "#{position} Open"] }
check_mark = "✓"

window('GTOWizard Opener', 500, 500) {
  text_column('Position')
  table {
    actions.each do |k, v|
      button_column(k.to_s)  {
        on_clicked do |row|
          settings[row][v] = (settings[row][v] == '') ? check_mark : ''
        end
      }
    end
    cell_rows settings
  }
}
```


## 使用感

**シチュエーション:**
14bbがeffのときに
UTG+1からのオールインが入っており、そこにHJとCOがコールしている状態でのSBのアクションを確認したい

![スクリーンショット 2022-03-09 14.21.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21406/90e84eb5-d4ae-28cb-466b-d479cebf95b2.png)


![スクリーンショット 2022-03-09 14.21.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21406/add5474f-911c-1146-511d-1206a7847207.png)


いい感じ :thumbsup:
マクロの自動実行処理

## バッチファイルでマクロを実行する（Outlook）
VBAを用いた自動化、業務効率化シーリズのOutlook版です。
バッチファイルをタスクスケジューラで起動し、マクロを自動実行させる

---
### バッチファイルの作成
---
1. バッチファイルの作成
ファイル名は任意で命名し拡張子を.batで保存

2. 下記のコードを記述し、上書き保存しファイルを閉じる
※下記バッチ処理は、Outlookを起動し、マクロが動作している時間（SleepTime）を90sec入れて
処理が終わったらoutlookを終了する流れです
（使用になるマクロにより処理時間は変わると思うのでSleepTimeは調整が必要）

```
start outlook.exe /autorun <マクロ名>
timeout /nobreak 90
taskkill /F /IM OUTLOOK.EXE
```

---
### 作成したバッチファイルをタスクスケジューラで実行する
Outlookを起動していなくても、処理を実行する

---

【つまずいた事】
タスクスケジューラの登録を行ったところ、セキュリティの関係のエラーが発生。
（実行権限の変更により解決）

参考記事の紹介

【ユーザガイド】（学習向け）
https://www.qualeed.com/ja/qbackup/userguide/scheduling/

【bat自動実行のタイムスケジューラ設定】
https://qiita.com/Richard_Roe/items/44e16841f16ee40c6113

上記記事（bat自動実行のタイムスケジューラ設定）の2-5でパスワード入力後、エラー発生。

---
#### やったこと
---

【エラーに関する情報】

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/866385/426ec88a-623a-ceec-0e8b-e568218c5ab3.png)

---

管理者権限でタイムスケジューラ起動し設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/866385/83cf35ce-52e3-c80b-24a0-76ee7f6ba31e.png)

エラー情報が変りました。

#### "バッチジョブとしてログオン"の権利が必要

参考記事
https://se-abeaver.com/logon-as-a-batchjob/

---

【試したこと】

下記記事の「 3. タスクスケジューラをSYSTEM権限で起動する方法 」の1-3を実行。
https://datyotosanpo.blog.fc2.com/blog-entry-159.html

下記記事の 「 1. 実行権限の変更 」
https://se-abeaver.com/logon-as-a-batchjob/

SYSTEM 権限に変更することで、タイムスケジューラからバッチファイル実行ができました。

以下参考

2. 実行権限の付与
実行権限を付与するは、管理者権限でも変更不可（ロックされていた）

3. レジストポリシーの変更
リスクがあると判断したため、試しておりません。
（制御に関する設定なようなので、変更する場合はIT部門に相談が必要と思いました。）

---
#### 動作確認
---

上記の1（実行権限）で設定を終え、Outlook、タイムスケジューラを閉じた状態で、設定時刻まで待機。

無事Outlookが起動し、マクロも実行されたことが確認できました。

※このバッチ処理は、Outlookが起動 > マクロの実行なのでOutlook起動した状態ですと
重複してOutlookが起動され、マクロは実行されなかった。

例）スリープモードで帰宅し朝出社したら既にOutlookが起動しマクロも実行されている。
出社時にPCの電源を入れログインし、設定時刻なったら実行される

---
#### Outlook起動している状態でのマクロ実行
---

予定表のアラームをトリガーとして、マクロを実行する（アラームが発生したらマクロが実行される）

※予定表の追加など操作方法などはご自身で調べてください。

1. 予定表にマクロを実行したい時間、期間などを設定する。

2. 開発タブからVBEを起動する

3. Microsoft Outlook Objects 直下にある "ThisOutlookSession" をW Clickする

4. 下記コードをコピペし編集してください。

```
Private Sub Application_Reminder(ByVal objItem As Object)
    'マクロの自動実行プロシージャ

    Dim strItemSubject As String

    '予定アイテムの件名を指定します。
    strItemSubject = "<予定アイテム>"
　　
    '新しい予定を表す AppointmentItem オブジェクト(26)を指定
    If objItem.Subject = strItemSubject And objItem.Class = "26" Then

    'マクロの呼び出し
    Call <マクロ名>
    End If
    
End Sub
```

※strItemSubject = "<予定アイテム>" （設定した予定アイテム名を入力する）
※Call <マクロ名>　（マクロ名を入力）

---

#### olAppointment	26	AppointmentItem オブジェクト

https://docs.microsoft.com/ja-jp/office/vba/api/outlook.olobjectclass

---

【補足】

以上、上記の流れでOutlookマクロの自動化を実装することができました。
この記事を読んで気付き指摘事項などありましたら、ご教授頂けると助かります。

PCの設定に関する点に置きましては、自己責任でお願いします。
【Rails】Deviseでログイン機能の実装

# Deviseとは
ログイン機能の実装を簡単にしてくれるRubyのgemの1つ。
今回Railsの学習中に使用したので自分用のメモとしてまとめてみました。

# Devise導入
Gemfileに以下を追記します。

```ruby:Gemfile
gem 'devise'
```

次にbundle installを実行します。

```
$ bundle install
```

以下のコマンドでRailsアプリケーションにDeviseを導入します(プロジェクトディレクトリ)。

```
$ rails g devise:install
```

# userモデルを作成
Deviseを用いてuserモデルを作成します（プロジェクトディレクトリ）。

```
$ rails g devise user
```
マイグレーションファイル（db/migrate/YYYYMMDDhhmmss_devise_create_users.rb）が生成されるので、
他に追加したいカラムがあればここに追記。

追記が完了しましたらマイグレーションを実行します。

```
$ rake db:migrate
```
ローカルサーバーを立ち上げてブラウザから http://localhost:3000/users/sign_up/ を開くと新規登録画面が表示されます。

しかしこのままだとViewの装飾などができないので以下のコマンドでViewファイルを生成します（プロジェクトディレクトリ）。

```
$ rails g devise:views
```

これにより app/views/devise 傘下にDeviseで使用するビューが作成されます。 

|ディレクトリ名|画面|
|---|---|
|sessions|ログイン画面|
|registrations|ユーザ登録画面とアカウント編集画面|
|confirmations|認証メール再送信するための画面|
|passwords|パスワードを変更するための画面|
|unlocks|アカウント凍結画面|
|shared|Deviseの画面に遷移させるためのリンク|

# Deviseのルーティング確認

|URL|HTTPメソッド|動作|
|---|---|---|
|/users/sign_up|GET|ユーザ登録|
|/users/sign_in|GET|ログイン|
|/users/edit|GET|ユーザ編集|
|/users/sign_out|DELETE|ログアウト|

# その他
以下Deviseが用意している便利なメソッドです。

`current_user`
現在ログインしているユーザを取得することができます。 

`user_signed_in?`
ログイン状態かどうかを判定するメソッドです。ログインしていればtrue、していなければfalseを返します。
本日のRuby基礎練習問題(22/3/9)

# 本日のRuby基礎練習問題(22/3/9)
**問題**
以下の仕様を満たすメソッドnumを作成しよう。

メソッドの実引数として「1以上の正の整数」を3つ用意し、それぞれを仮引数a,b,c としてnumメソッド内で使用する
第一引数と第二引数は足し算をし、変数abに代入する
第三引数が3以下の場合は変数abを第三引数の値で割り、結果を出力する
第三引数が4以上の場合は変数abを第三引数の値で掛け、結果を出力する
※小数点以下の出力は考慮しなくてよい


```ruby:qiita.rb
def num(a, b, c)
  # ここに条件式を実装する
end

# 呼び出し例
num(1,5,3) 
num(1,5,5)
```

出力例
num(1,5,3) → 2
num(1,5,5) → 30

# 私の回答
```ruby:qiita.rb
def num(a, b, c)
  ab = a + b
  if c <= 3
   puts ab / c
  else
   puts ab * c
  end
end

# 呼び出し例
num(1,5,3) 
num(1,5,5)
```
**自分なりの解説**
まず2行目で変数abにa+Bの値を代入
その後cの値が3以下の場合はab/cを実行
それ以外(4以上)の場合はab*cを実行
end忘れなどがないようにチェック

# 模範解答
```ruby:qiita.rb
def num(a, b, c)
  ab = a + b
  if c <= 3
   puts ab / c
  else
   puts ab * c
  end
end

# 呼び出し例
num(1,5,3) 
num(1,5,5)
```

**模範解説**
ab = a + bで第一引数aと第二引数bを足し合わせています。
そして、第三引数cが3以下なのか否かをc <= 3として比較し、trueの場合は変数acをcで割る処理をしています。

一方、第三引数cが4以上の場合はc <= 3がfalseの場合であると一意に決まるため、elseの場合は変数abにcをかける処理をしています。


# 感じたこと

今回のレベルは基礎の基礎だと思うのですぐに解答することができた。
このような練習問題は毎日行うことで身につくことですので明日からも継続して取り組みたい。
kintoneにメールワイズを導入する

# 既存のkintoneでメールを送信したい
kintoneで顧客管理をしていると、「この人にメール送りたいなあ」と思う時がよくある。
レコードにメアドは載っているのに、一旦それをコピーして...というのはとても面倒で仕方ない。

## メールワイズの導入
kintoneでメールを送信する方法は色々なアプローチがあるが、安価に簡単にメールを送る方法の一つに「メールワイズ」がある。
メールワイズはkintone開発のサイボウズ社が提供するメールアプリで、kintoneと親和性が非常に高い。
ユーザー1人500円で始められるので、料金体系等は以下から確認してほしい。

[メールワイズ公式HP](https://mailwise.cybozu.co.jp/)

## 既存kintoneにメールワイズを導入する手順
### 共通管理者権限があるか確認する
kintoneにメールワイズを導入するためには、cybozu.com共通管理者のアカウントが必要になる。
![スクリーンショット 2022-03-09 14.02.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1005334/0636ce13-2893-8424-9c33-81a1563a4751.png)
kintone右上の上記歯車からcybozu.com共通管理が表示されていれば、使用しているアカウントは共通管理者である。
共通管理者であることを確認したら、cybozu.com共通管理をクリックして、管理画面に遷移する。


### 契約状況からメールワイズを選択する
![スクリーンショット 2022-03-09 14.10.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1005334/c1e60353-6c61-0ae1-30bf-001609441339.png)

現時点(22/03/09)ではデフォルトで契約情報の画面に遷移する。

契約情報を確認してみると
![スクリーンショット 2022-03-09 14.14.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1005334/e7b3c2dc-3e71-39f8-d80a-ec3f940d6aaa.png)
※画像は既に契約済みの画面

上記のような形で契約状況が表にまとまっている。
この表の中から、メールワイズを選択する。

あとは、画面の流れに沿って必要となるアドレス情報を打ち込むだけです。

## 注意点
どうやらkintone単体を既に契約している状態で、メールワイズ単体で新規申し込みを行うと、異なるドメインでメールワイズが立ち上がってしまい、紐付けがうまくできない様子。
自分は引っかかりました。。。

## まとめ
新規契約をせずに、同じドメインで手軽にkintoneとメールワイズを繋げられます。
ARKitでカメラと平面との距離を測る

![Mar-09-2022 14-18-06.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/9e86dcb3-971a-aa7c-435f-5b21b8cee950.gif)


# 対象平面との距離を測りたい

# ARKitでヒットテストを行う
ARKitでヒットテストを行い、検知した平面の座標と、カメラの距離を計算することができます。

```Swift
let hitTestResults = sceneView.hitTest(sceneView.center,types:[.existingPlaneUsingGeometry])
guard let result = hitTestResults.first else { return nil }
let hitCoordinates = simd_float3(x: result.worldTransform.columns.3.x, y: result.worldTransform.columns.3.y, z: result.worldTransform.columns.3.z)

let distance = distance(cameraCoordinates,hitCoordinates)
```

カメラの座標の取得方法はこちら。

https://qiita.com/john-rocky/items/873b170621b3c3d43994

🐣
****
フリーランスエンジニアです。
お仕事のご相談こちらまで
rockyshikoku@gmail.com

Core MLやARKitを使ったアプリを作っています。
機械学習／AR関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)
[GitHub](https://github.com/john-rocky)
GCP ACE合格記(2022/3/9投稿)

# はじめに
この度GCP認定のAssociate Cloud Engineerを受験してきましたので、勉強した内容と受験した感想を書いておきます。
これから受験される方の参考になれば幸いです。

# 前提
* Google Cloudはほぼ触ったことなし
* AWSの実務経験あり
* AWS認定は全て取っています(詳細は[こちら](https://qiita.com/handy-dd18/items/d21d914bf1c475d777f2))

# 学習内容
今回は以下の順番で勉強を進めました。
スタンスとしてはAWS試験の場合とあまり変わらず、書籍などで知識の勉強をした上で問題を繰り返し解いて問題に慣れるようにしました。

* ①書籍([GCPの教科書](https://www.amazon.co.jp/dp/B07S1LG1Y1/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1))
* ②[公式模擬問題](https://cloud.google.com/certification/practice-exam/cloud-engineer?hl=ja)
* ③練習問題([koiwaclub](https://aws.koiwaclub.com/))

## 書籍
最初は[GCPの教科書](https://www.amazon.co.jp/dp/B07S1LG1Y1/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)でGoogle Cloudの全体的なサービスについてざっくりと学習しました。
上記の本で勉強して特に良かった点として、AWSサービスとGCPサービスとのマッピング表が書籍内に記載されているので、サービスの理解がとてもスムーズにできました。

## 公式模擬問題
書籍でサービスについてある程度理解したら、公式の[模擬問題](https://cloud.google.com/certification/practice-exam/cloud-engineer?hl=ja)を解いてどのような問題が出題されるのかを把握しました。

AWSで出題される問題とはまたちょっと観点が異なるので、問題傾向を理解しておくのは重要でした。

## 練習問題
こちらはいつも通りですが、最後は[koiwaclub](https://aws.koiwaclub.com/)を利用して練習問題を繰り返し解きました。
1セクション7問×19セクション=133問を100%正解するまで解いています。

# 受験した感想
公式の模擬問題やkoiwaclubの模擬問題よりは若干難しいかなと思うぐらいの試験が多かったですが、アソシエイトレベルということもあって入門以上の難しさはありませんでした。

個人的にはAWS資格で学んだ知識だけで5割ぐらいは取れそうだったので、根本となる知識はさほど違わないんだなという学びがありました。

# 受験結果
無事に合格することができました。
![20220309_124924.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440403/8a9daa4f-2524-3d08-8ce8-69b5f238ef68.png)

これは知らなかったのですが、合格は当日にわかっても正式な合格ではなく、後日正式な合格通知が来るようです。
自分は受験の翌日に通知がきました。

# おわりに
今までAWSだけを勉強してきたので、違うクラウドを勉強するとその仕組みや強み弱みが見えてきて面白かったです。
Azureについても知りたくなったので、時間があればそっちも勉強してみようかなと思いました。
AWSで最初にやるべきことの中に課金要素がある件について

# はじめに
ある日、次のメールがAWSから届きました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2520632/0fdff69e-ddc2-8c9e-3306-7a027ea4ce9b.png)

内容を見ると、AWSの無料利用枠の85%を超過してしまっているとのこと。
AWS Consoleにログインして、実際に状況を調べてみました。

# 原因はAWS CloudTrailだった！
今回AWSで最初にやるべきことをネットで検索して、書いてある内容をそのまま実践しました。
その中にAWS上の操作履歴をログとして保存するCloudTrailというサービスがあります。
結論から言うと、このCloudTrailが課金の原因でした。

# 課金対象のサービス
請求ダッシュボードからいくら課金されたのか実際に見てみることにしました。
内訳としては次の通り。34円程度と少額なのが不幸中の幸いでした。

* Key Management Service
    * $1 per customer managed KMS key version in Asia Pacific(Tokyo)　　**$0.25**
* Simple Storage Service
    * $0.00 per request - PUT, COPY, POST, or LIST requests under the monthly global free tier　　**$0.00**
    * $0.0047 per 1,000 PUT, COPY, POST, or LIST requests　　**$0.01**

CloudTrail自体に課金が発生しているのではなくて、S3にログを保存する際の暗号化に使うKMSやS3へのリクエストに対して課金が発生しているようでした。

# 対処法
このまま放置していると、少額ですが課金が発生し続けるため、大きく分けて次の3つの対応を実施しました。
※ログを完全に削除するので、ご注意ください。

* CloudTrailによる証跡の停止・削除
* カスタマー管理型のKMSキーの削除
* S3上にあるログの削除

### 対処手順

1. CloudTrailのダッシュボードから対象の証跡情報に対して「ログ記録の停止」を実行する（これでS3へのリクエストはなくなります）
1. 同じ画面で「削除」を実行する
1. S3の画面に移動し、ログが保存されているバケットを選択して、「空にする」を実行する
1. 同じ画面で「削除」を実行する
1. KMSの画面に移動し、「カスタマー管理型のキー」の画面を表示する
1. 「キーのアクション」から「無効」を実行する
1. 同じ画面で「キーのアクション」から「キーの削除をスケジュール」を実行する
1. キーは即日削除はできないため、最短の待機期間の「7日」に設定する

以上で、CloudTrailを設定する前の状態に戻すことができました。

ちなみにS3には次のように全リージョンに対して、ログが取られていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2520632/52967e19-110d-1e3c-4181-4ed6f89ae1f6.png)


こんなにログをはいて、暗号化もしていればそりゃ課金されますよね・・・
S3へのリクエスト回数が大量になっていたのもうなずけます。
今後は定期的にAWS Consoleにログインして、課金されていないかチェックしようと思います。
ちなみに、AWSのアプリもあり、スマホでも課金状況をチェックできるようです。
Railsで環境構築

今回Railsの学習中に使用したので自分用のメモとしてまとめてみました。
homebrewやrbenvの設定は終わっている想定です。

# Railsのインストール
以下のコマンドを実行します。
バージョンはプロジェクトに合わせて変更してください。

```
$ gem install rails -v "5.2.3"
```

インストールが完了したら以下のコマンドでバージョンを確認してみましょう。

```
$ rails -v
```

指定したバージョンが表示されればOKです。

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

Railsアプリケーションを新規作成していきます。
アプリケーションの新規作成には以下のコマンドを使用します。
アプリ名は仮に「sample」とします。

```
$ rails new sample -d mysql
```
上記のコマンドは `sample` という名前のRailsアプリケーションを作ります、データベース管理システムは `MySQL` で作ります、ということを意味しています。

# Railsアプリケーションへの移動・立ち上げ

先程作成したsampleフォルダに以下のコマンドを使用して移動しましょう。

```
$ cd sample
```

そして

```
$ rails s
```

テストサーバーを立ち上げてみます。

その状態で `http://localhost:3000/` にブラウザでアクセスできればOKです。

# Railsアプリケーションの構成

## appディレクトリ
|ディレクトリ名|なにが入っているか|役割|
|---|---|---|
|assets|CSSファイル、JSファイル、画像|デザインに関すること|
|controllers|コントローラ|モデルに命令を出し、ビューにデータを渡す|
|helper|ヘルパー|ビューで使う自作メソッドを定義|
|models|モデル|データベースとのやりとり|
|views|ビュー|見た目の部分（HTMLの素）|

## configディレクトリ
|ディレクトリ/ファイル名|役割|
|---|---|
|environments|環境ごとの設定|
|initializers|Gemやクッキー、セッションの設定|
|helper|ヘルパー|ビューで使う自作メソッドを定義|
|models|モデル|データベースとのやりとり|
|views|ビュー|見た目の部分（HTMLの素）|

## dbディレクトリ

|ディレクトリ/ファイル名|役割|
|---|---|
|migrate|マイグレーションファイル|
|schema.rb|DB内のテーブルの状況|
|seeds.rb|初期データを作成するファイル|

# Gemfile
Gemfileはインストールしたいgemを書くためのファイルです。 Gemfileのすぐ下に Gemfile.lock というファイルがあり、実際にインストールしたgemやバージョンが書かれています。
gemは以下のコマンドでインストールできます。 

```
$ bundle install
```

# bundle
bundleはbundlerというgemのバージョンを管理してくれる機能です。

# rails g (generate)
`rails g` コマンドは、`rails new` コマンド で作ったRailsアプリケーションの土台に中身を盛り込んでいくためのコマンドです。

```
$ rails d scaffold tweet title:string content:text
```

|コマンド|コントローラ|ビュー|モデル|マイグレーションファイル|ルーティング|
|---|---|---|---|---|---|
|controller|○|○|×|×|○|
|model|×|×|○|○|×|
|migration|×|×|×|○|×|
|scaffold|○|○|○|○|○|

# DBの作成
Railsでは `config/database.yml` というファイルを編集することで、データベースの設定を
運用環境ごとに変更できる仕組みになっています。
encodingがutf8mb4となっていればutf8に変更します。

```ruby:config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: password
  socket: /tmp/mysql.sock
```
最後に以下のコマンドでDBを作成します。

```
rails db:create
```
ros python 時間差取得

ros pythonノード内pythonのtimeライブラリを使用した時間取得が行えません。rosノード内でそのような処理を行う場合は以下のようなプログラムになります。

```python
import rospy

def now():
    return rospy.get_time()

rospy.init_node("time")

start = now()

while not rospy.is_shutdown():
    print( now() - start)

```

出力(単位:s)

```
0.3100881576538086
0.31009507179260254
0.3101022243499756
0.31010913848876953
0.3101155757904053
0.3101224899291992
```
http://wiki.ros.org/rospy/Overview/Time
xlwingsでExcelのセルの書式設定の表示形式の分類を文字列に変更したい

PythonでExcelを操作もしくはExcelからPythonを呼び出すときにxlwingsさんを使っています。

https://www.xlwings.org/

xlwingsでセルの書式設定の分類を変更したい！ってなりました。




# 例

右クリックで出てくる
![2022-03-09_13h06_50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217361/95b83352-86d4-35c2-7751-5de56df7b1ad.png)

ここのこれです

![2022-03-09_13h07_41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217361/49c19836-270c-8783-c50d-02fe9c465cd8.png)


よくあるのが住所データが入ったCSVをExcelにインポートした時に、番地だけが入っていると○月○日となってしまうやつです。


![2022-03-09_13h11_31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217361/5598cb95-0fd6-b346-9bf3-89f879d0c7d3.png)

これをセルの書式設定の分類を文字列にして回避します。

# コード

``` Python:csv_paste.py
    import xlwings as xw
    import pandas as pd

    df = pd.read_csv('csv.csv', dtype = str)

    wb = xw.Book()
    sh = wb.sheets.active

    sh.range('A:XFD').number_format = '@' # 全てのセル(A列～XFD列)のセルの書式設定の分類を 文字列 に変更

    sh.range('A1').options(index = False, header = True, dtype = str).value = df # dfをA1セルからヘッダーありで貼り付け
```

VBAのnumber_format的に使えるということです_(┐「ε:)_

「xlwings 書式設定 変更」で検索していて以下の記事を見つけました。
表示形式を取得できるとうことは、逆に変更もできるんじゃね？って試してみたところできました、ありがとうございます！


https://www.relief.jp/docs/xlwings-range-nuber-format.html

> number_formatはNumberFormatLocalに相当

とのこと🙌

なので文字列以外にも標準なら'G/標準'、数値なら'0_'としてあげることで自由に変更することができそうです。 

これで住所が日付・時間に自動変換されたり、=や+、-から始まる値も数式に自動変換されることがなくなりました👍


よかったらTwitterもフォローお願いします＼(^o^)／
https://twitter.com/tbshiki
python 時間差取得

開始から3s後にループを抜けるプログラム

```python
import time

def current_milli_time():
    return round(time.time() * 1000)

print(current_milli_time())

start = current_milli_time()

while True:
    d = current_milli_time() - start

    print(d)

    if d > 3000:
        break

print("finish")
```
FigmaとSlackの連携が再びアップデートされたから試してみた

## この記事の概要

2021年半ばのアップデートにより、Slackの個別のチャンネルにFigmaの通知を送ることができなくなってしまっていました。
しかし2022年3月8日のアップデートで再び個別チャンネルへの通知ができるようになったようです。

変更の内容を簡単にまとめてみました。

## 公式ドキュメント

https://help.figma.com/hc/en-us/articles/360039829154-Receive-comment-notifications-in-Slack

何はともあれ公式を読むのが1番です。

要点だけかいつまんで知りたい方はこの記事の続きをご覧ください。

## 既にSlackにFigmaのAppを入れていた方

Slackにおいて、Figma appのapprove and re-authorizeを実施してください。

https://slack.figma.com/slack/slack_authorize

## まだSlackにFigma appを入れていない方

以下からインストールをしてください。

https://slack.com/apps/A01N2QYSA81-figma-and-figjam?tab=more_info

インストール後、アクセスの許可を求められます。
`Allow Access`をしてください。

また、Figmaアカウントと接続する必要があります。
Slack上でFigma appを開いて`Connect your account`のリンクを践み、指示に従って接続してください。

## 以前のように、チャンネルごとに通知をする方法

- 通知を飛ばしたいチャンネルで`/invite @figma`と入力、エンター
- `/figma subscribe`と入力、エンター
- ウィンドウが開くので、条件を入力してsubscribe
    - ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/285aa3a9-9971-ba2a-cdc4-886e053a4d8d.png)
    - What do you want updates for?
        - File, Project, Teamから、アップデート通知を送りたい単位を選べます
    - What's it called?
        - File名, Project名, Team名を入力して選択します
        - テキストを入力すれば良い感じに絞り込んで候補を出してくれるみたいですが、関係なさそうな候補も出てきました
            - 細かな仕様は分かりませんが、お目当てのFile名, Project名, Team名が先に分かっていれば問題ないと思います
    - How often do you want updates?
        - 即時, 1時間に1回, 1日に1回を選べます
    - If daily, at what time?
        - 1日に1回の場合、何時にするかを選べます

## 通知を削除したい場合

- `/figma list`と入力、エンター
    - 現状の通知一覧と、`Delete subscription`というボタンが一緒に表れるので、DeleteすればOKです
    - ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/a1507355-3e67-9327-0831-a01e0d158d2f.png)

## 今までに無かった機能

ここまでだと「以前できたことがもう一度できるようになっただけか」と思われるかもしれません。
新規にできるようになったこととして「Branch操作の通知」があります。

- merges
- requests
- approvals
- archives

こちらの4つが通知されるようになりました。
Branch機能はOrganizationプラン限定ですが、かなり便利な気がします。

ちなみに過去にBranchについての記事も書いたので、良かったらご覧ください。

https://qiita.com/xrxoxcxox/items/48ebfcc7055bd51e3e9f

---

最後まで読んでくださってありがとうございます！
Twitterでも情報を発信しているので、良かったらフォローお願いします！

https://twitter.com/xrxoxcxox
Rubyで文字列の時間表記を秒数に変換

## やりたいこと
`06:23.19`みたいなものを`383.19`秒のようにする。
２つの地点の通過タイムから区間タイムを計算する。
丸め誤差がでないように浮動小数点はできるだけ使わないようにする。

## 環境

macOS 10.15.7
Ruby 3.1.0

## 使用したメソッド

- String#partition
  - 指定した文字を中心に、文字列を３分割して配列に収めるメソッド
  - https://docs.ruby-lang.org/ja/latest/method/String/i/partition.html
- String#delete
  - 文字列から指定した文字を削除するメソッド
  - https://docs.ruby-lang.org/ja/latest/method/String/i/delete.html
- Numeric#modulo
  - 除算の余りを返すメソッド
  - https://docs.ruby-lang.org/ja/latest/class/Numeric.html#I_--25
- その他
  - to_i
  - to_f
  - 有理数リテラルのr

## [分] : [秒] . [コンマ秒]形式の文字列を秒に変換してみる

- "06:23.19"を秒に変換する
- 丸め誤差対策
  - 文字列の段階で小数点を削除する
  - ケタを戻すときは有理数を使う

### code

```ruby
str = "06:23.19"
strs = str.partition(":")
#=> ["06", ":", "23.19"]

#分のケタを秒にする
#整数にするため、100倍して２ケタ上げておく
min = strs[0].to_i * 60 * 100
#=> 36000

#秒の部分から小数点を削除して整数にする
sec = strs[2].delete('.').to_i
#=> 2319

sum_sec = min + sec
#=> 38319

#有理数を使って２ケタ戻す
puts "#{str}は#{(sum_sec * 0.01r).to_f}秒"
#=> 06:23.19は383.19秒
```

## 区間タイムを計算するメソッドをつくる

A地点の通過タイムが01:30.24。
B地点の通過タイムが03:12.14。
A-B間の区間タイムを計算する

### メソッド

```ruby
def to_interval(here, pre)
	#分の単位を変換
	min_here = here.partition(":")[0].to_i * 60 * 100
	min_pre  =  pre.partition(":")[0].to_i * 60 * 100

	#秒の単位を変換
	sec_here = here.partition(":")[2].delete('.').to_i
	sec_pre  =  pre.partition(":")[2].delete('.').to_i

	#差を求める
	interval_sec = (min_here + sec_here) - (min_pre + sec_pre)

	#計算結果を[分]:[秒].[コンマ秒]形式に戻す
	#秒を分に戻す
	min = interval_sec / 6000
	#秒の単位の桁を戻す
	sec = interval_sec.modulo(6000) * 0.01r
	
	interval_str = "#{sprintf("%02d", min)}:#{sprintf("%2.2f", sec)}"
	return interval_str
end
```

### つくったメソッドを実行してみる

```ruby:run_to_interval.rb
here = "03:12.14"
pre  = "01:30.24"
puts "A-B間のタイムは#{to_interval(here, pre)}です。"
```

ターミナル

```
$ ruby run_to_interval.rb
#=> A-B間のタイムは01:41.90です。
```

意図通りに動いた。

## 追記 [2022-03-10]
コメントで@scivolaさんからアドバイスをいただいたのでメソッドを書き換えました。

主な変更点

- `to_r`を使って文字列から有理数に変換
- `map(&:[メソッド])`を使って配列の要素を一気に変換
- 番号指定パラメータ`_1, _2`を使ってブロック内で要素を各々処理

[2022-03-11]
@scivolaさんからご指摘いただき、変更を更に修正しました。
詳しい内容はコメント欄参照。

修正点

- `/60`, `modulo(60)`を`divmod(60)`へ
- `sprintf`を`String#%`へ


 **メソッド（改）と実行の結果** 

```ruby:run_to_interval.rb
def to_interval(here_str, pre_str)
	here_sec_r = here_str.split(":").map(&:to_r).then{ _1 * 60 + _2 }
	pre_sec_r 　　=  pre_str.split(":").map(&:to_r).then{ _1 * 60 + _2 }
	#差を求める
	interval_sec_r = here_sec_r - pre_sec_r

	#秒から分の単位を取得
#	min = interval_sec_r / 60 (下記に修正)
	#余りの秒を取得
#	sec = interval_sec_r.modulo(60) (下記に修正)

#	interval_str = "#{sprintf("%02d", min)}:#{sprintf("%2.2f", sec)}" (下記に修正)

# =====文字列に戻す部分の修正========
	# Rationalから整商と剰余を配列で返すNumeric#divmodを使用
	min, sec = interval_sec_r.divmod(60)
	# String#%を使って成形
	interval_str = "#{"%02d" % min}:#{"%05.2f" % sec}"
# =====//文字列に戻す部分の修正========

	return interval_str
end

interval_str = to_interval("03:12.14", "01:30.24")
puts "A-B間のタイムは#{interval_str}です。"
#=> A-B間のタイムは01:41.90です。

```

秒をもとめるところが随分とスッキリしました。
cronとdocker execコマンドを組み合わせたlaravelスケジューラの挙動メモ

# 環境
サーバ: AWS EC2
PHP7.1
laravel5.1

# 状況
コンテナを利用したlaravelプロジェクトのスケジューラをホスト側のcronを使って動かしていた

```
* * * * * docker exec --user www-data php-fpm_container sh -c "php artisan schedule:run" > /dev/null 2>&1
```

スケジューラ内で1日1回実行されるコマンドが3時間ほどかかるのだが、このコマンド実行中にホスト内のメモリ使用量がどんどん増えていき使用量90%を超える事態に
また、コマンド実行中にphp-fpmのヘルスチェックが失敗するようになっていた

```
  php-fpm:
    healthcheck:
      test: ["CMD-SHELL","cgi-fcgi -bind -connect localhost:9000 2>&1 || exit 1"]
      interval: 1m
      timeout: 10s
      retries: 3
```


# 調査結果
コンテナ内にschedule:runプロセスは残っていないにもかかわらず、ホスト側でcronのプロセスが大量に残っている状態だった(3/1時点で2/28以前の実行プロセスが残っていた
コマンド実行中は、その後に実行されたcronプロセスが全て残り続けるようだった
このcronプロセスが平均0.5%ほどメモリを消費することにより、メモリ使用量が肥大化していた

```
root  14003  0.0  0.0 183160  2912 ?        S    Feb28   0:00  \_ /usr/sbin/CROND -n -m off
hoge  14004  0.0  0.0 119852   884 ?        Ss   Feb28   0:00  |   \_ /bin/sh -c docker exec --user www-data php-fpm_container sh -c "php artisan schedule:run" > /d
hoge  14005  0.0  0.4 609184 34388 ?        Sl   Feb28   0:11  |       \_ docker exec --user www-data php-fpm_container sh -c php artisan schedule:run
```

また、docker eventsコマンドを監視したところ、exec_dieイベント発行が行われずに詰まっている？ようだった

```
◆ スケジューラ1回目開始 (αコマンド実行)
2022-03-01T15:15:01 container exec_create: sh -c php artisan schedule:run (省略, execID=ff762a994cf8bd1b68b106c85e6fffece2ed9d2c3e626db842ba25dfe38a1393)
2022-03-01T15:15:01 container exec_start: sh -c php artisan schedule:run (省略, execID=ff762a994cf8bd1b68b106c85e6fffece2ed9d2c3e626db842ba25dfe38a1393)

◆ スケジューラ2回目開始
2022-03-01T15:16:01 container exec_create: sh -c php artisan schedule:run (省略, execID=6b6a678463cad21dc30300e6059bc93db27575f4428871b833b4f1a2b4ab3399)
2022-03-01T15:16:01 container exec_start: sh -c php artisan schedule:run (省略, execID=6b6a678463cad21dc30300e6059bc93db27575f4428871b833b4f1a2b4ab3399)

~ スケジューラ2回目の終了が来ない ~

◆ スケジューラ1回目終了
2022-03-01T18:15:01 container exec_die (省略, execID=ff762a994cf8bd1b68b106c85e6fffece2ed9d2c3e626db842ba25dfe38a1393)
◆ すぐにスケジューラ2回目も終了
2022-03-01T18:15:01 container exec_die (省略, execID=6b6a678463cad21dc30300e6059bc93db27575f4428871b833b4f1a2b4ab3399)
```

# 解決方法
cronプロセスが残り続ける問題については、デタッチモードで実行することにより結果出力を受け取らずにcronプロセス自体は終了するように変更

```
* * * * * docker exec -d --user www-data php-fpm_container sh -c "php artisan schedule:run" > /dev/null 2>&1
```

exec_dieイベント発行の詰まりについては分からずじまいで、php-fpmコンテナのヘルスチェックをnginxコンテナのヘルスチェックに内包することでとりあえずの解決とした
[AppStoreConnect] In-App-Purchase商品の審査用スクリーンショットがアップロードできない場合

先日、AppStoreConnectに商品を登録する機会があったのですが、審査用スクリーンショットがうまく登録できなかったので備忘録としてまとめておきます。

# TL;DR

下記のような点に気をつけて画像を作成する。

- **画像の解像度は 幅750px, 高さ1334px, 75dpi の画像を用意する**
- ブラウザはSafariを使う（念の為）
- 拡張子はpngにし、透過は削除する
- 多分画像は軽量な方がよい
- ファイル名は "screenshot.png" のようなシンプルなものにする（スペースや全角文字などを使用しない）

この画像はアップロードできるはずです（2022/03/09現在）↓

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95499/26b40454-5282-6614-19f4-05e425ea6a35.png" width="320">

# 問題について

AppStoreConnectで、自動更新サブスクリプションの登録時には、審査用のスクリーンショットを提出する必要があります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95499/24a5faa3-706c-b660-a4a8-9062437f082e.png" width="320">

ここに添付すべき画像は、公式のヘルプにこのように記載されています。

> 販売されるアイテムを表す App 内課金のスクリーンショット。たとえば、ブックのイメージや購入ページをスクリーンショットにして提出してください。このスクリーンショットは、Apple の審査のみに使用され、App Store には表示されません。
>
> スクリーンショットの要件は以下の通りです。
> 
> iOS では、少なくとも 640 x 920 ピクセルが必要です。
> tvOS では、1920 x 1080 ピクセルが必要です。
> macOS では、1280 x 800 ピクセルが必要です。
> App Review 用イメージをアップロードした後は、それを差し替えることはできますが、削除することはできません。App 内課金の審査中は、スクリーンショットをアップデートできません。

https://help.apple.com/app-store-connect/#/dev84b80958f

要件として最低解像度が指定されているので、このサイズ以上の画像を添付すればよいのだろう... と思ったのですが、実際には色々な制約があるようです。


# 遭遇したエラー一覧

遭遇したエラーを以下に記載しておきます。

### 画像の解像度エラー？

エラー

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95499/9071c888-7bf6-73a9-7a49-fb8e28271abc.png" width="200">

アップロードした画像

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95499/30deb518-c97b-a410-8f47-8001251ef92d.png" width="320">

- 画像の解像度が　`750 × 1624` （iPhone XRのスクショサイズ）の場合などに発生
- 解像度を `1334 × 750` に無理やり修正するとちゃんとアップロードできる（ファイルサイズが4.6MBくらいあっても問題なくアップロードできていた）


### 画像が透過png

エラー

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95499/3855d4d9-2bb0-187d-4212-e8c2432cd0f7.png" width="200">

アップロードした画像

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95499/d41b26f0-5c24-c48e-c293-2300426d42ce.png" width="200">

- PNGの場合、アルファチャンネルは削除しておく必要がある

### アップロードはできるけど謎エラー

エラー

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95499/4346b7fd-a7c8-d466-f26e-6bbc9ff30dfc.png" width="320">

アップロードした画像

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95499/26b40454-5282-6614-19f4-05e425ea6a35.png" width="320">

- アップロードした後、保存を押したときにエラーが発生する
- 解像度が `1920 x 1080` の場合に発生

# アップロードできた画像

↓の画像はエラーなしでアップロードできた（1334 × 750、75dpi、アルファなし）

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95499/325b63ed-ed08-587e-01d0-50855c6ffcee.png" width="320">

# 思ったこと

制限があるならちゃんと書いて欲しいですね...


# 参考にさせていただいたサイト

[Impossible to upload screenshot fo… | Apple Developer Forums](https://developer.apple.com/forums/thread/62615)
Appgyverで予約アプリを本気で開発してみた話

ノーコード開発やローコード開発が盛り上がりを見せていますが、いろんなツールが出てきており、どれを選ぶかを考えるだけでも1日が過ぎてしまいます。「ノーコードツールを試してみた」という記事は増えてきたものの、本気で開発に使えるのかどうかというところまではいまいちわからないところも事実です。

そこで今回は、実際にAppgyverという去年SAPに買収されたノーコードツールを使ってガチで予約アプリを開発してみたので、ノーコードツールでどこまで開発できるのか？そしてどんな課題があるのかということについて分かったことをまとめてみました！

ノーコードツールで開発しようかどうか迷っている人の判断材料になればうれしいです。

結論としては、ノーコードツールを使っていいかどうかの基準はアプリの画面数とロジックの複雑度合によって決まるので、個人で行う小規模開発であれば問題なく使えるものである、になります。

# 今回作ったアプリの仕様
- 飲食店のテイクアウトの予約ができるアプリ
- ユーザー登録が必要
- 各商品の1日の販売個数に上限があり予約時にチェックが必要（★難しいポイント①）
- 自分の予約履歴をマイページから確認できる
- ユーザーは翌日以降の注文をマイページからキャンセルすることができる（★難しいポイント②）
- デザインは最低限見やすいものであること
- お店側のページは別途あり、メニューの登録編集や予約の管理が可能
- メニューにはセットなどのオプションを追加することができる（★難しいポイント③）

# ノーコードツールを使って感じたメリット
- 環境用意などの前準備が不要！
- Excelの関数を書く感じでロジックを書くことができる！
- 変更がすぐに画面イメージとして反映される
- プレビューツールが充実していてすぐにテスト可能！
- 1日でかなり本格的なプロトタイプができる！

# ノーコードツールを使って感じたデメリット
- 使えるコンポーネント（UI・ロジック）が限られているために出来ることも限られる
- ロジックが複雑になると一気に難しくなる
- データ構造が複雑になるとロジックも複雑になる
- 複雑なロジックを実現するためにテクニックが必要
- firebaseを使う場合にはRestAPIの使い方をマスターする必要がある
- コードのテキスト検索ができないので、画面数が増えてくると修正工数が膨らむ（ドキュメントの重要性UP）
- 画面を機能を増やすと開発画面が重くなる（ブラウザベースのため）
- 同時共同開発機能がまだ整備されていない
- 変更履歴がGitのように追えない

# ノーコードツールを使って開発してもいいアプリ
- プロトタイプ用である
- 個人開発で10画面以内で、データ構造がシンプルである（ネストがない）
- 更新系のデータ操作が少なく、作成・削除がメインである（firebaseを使う場合）
- 複雑なチェックロジックがない
- 一度構築したら機能追加や改修が少ない

# ノーコードツールを使って開発してはダメなアプリ
- 10画面以上ある
- チームで開発する、または、開発する予定がある
- 機能追加や改修が頻繁に入る
- データの更新処理が多い場合（firebaseを使う場合）
- データ構造が複雑である
- 複雑なチェックロジックがある
- 複数のデータソースがある場合

# ノーコードツールを使って開発してみた所感
今流行りのノーコードですが、よくも悪くも癖のあるツールです。もともとコーディングできる人の場合は、複雑な画面や処理を開発しようとしたときに「コーディング出来たら簡単に書けるのに…」と思う場面も多いように感じました。

ノーコードツールを使う場合は、開発に着手する前の設計がより重要になります。行き当たりばったりで作り始ると、おそらくどんどんと複雑さが増していき、ある段階で開発できないという状況に陥る可能性が高いです。それを回避するために事前に設計を検討して、複雑になりすぎる部分はないか、それをサーバ側に寄せることはできないかということを決めておいたほうがうまくいきやすいです。逆説出来ですが、すぐに作れるからこそ、慎重に考えて作らないといけないということです。

# ノーコードツールとを使うときに注意しないといけないこと
ノーコードツールを使ってアプリ開発経験のない人が”ちゃんとした”アプリを開発して維持していくことはかなり難易度が高いと思うので、設計とコーディングができるエンジニアが開発工数を下げるためにシンプルなアプリを開発するためのツールとして使う、というのが現実的なラインなのではないかなと思いました。ただ、もしかしたら他のノーコードツールでは事情が異なるかもしれないので、それはツールごとの特性を確認していく必要がありそうです。

データベース設計については、ノーコードツールを使うかどうかにかかわらず必要になるものなので、特に最初はしっかりと作るべきですね。

サービスとして拡大していく予定がある場合は、最初は小規模だったとしてもノーコードツールは検証用にとどめておいたほうがいいですね。「ある程度まではノーコードツールで」という考え方もあると思いますが、作り直しの工数がかなりかかってしまうと思うので初めからコーディングしておいたほうがいいですね。

個人開発で、更新頻度も少なめ、さらにいろんなアプリをリリースしていきたいということであればノーコードツールは非常に役に立つので、そういった場面では活用できると思います。
C#に於いてinterfaceがinterfaceを継承した場合について私が知っている二、三の事柄

# `interface` が `interface` を継承するって？

正直言って、これは行儀の良い作法ではない。アンチパターン一歩手前である。しかし、C#の文法的に許されていることだし、利点も十分あるので議論の価値はあるだろう。

即ち、以下の様なコードである。

```cs
public interface IFoo
{
    int DoSomething();
}

public interface IBar : IFoo
{
    double DoOtherThing();
}

public class SomeClass : IBar
{
    /// <summary>
    /// IFooのメソッド実装。IBarには書かれていないが、継承しているため実装が必要。
    /// </summary>
    public int DoSomething()
    {
        return 530000;
    }

    /// <summary>
    /// IBarのメソッド実装。
    /// </summary>
    public double DoOtherThing()
    {
        return 5.55;
    }
}
```

## 長所

- `IFoo`が必要となるメソッドに`IBar`のインスタンスを入れることができる。
- `SomeClass`には`IFoo`を明示的に実装しなくても`IFoo`に変換可能。

`interface`から`interface`を派生させたいということは割とある（例えばモジュールの`interface`を結合した`interface`を作るなど）ので、それなりに需要はあると思う。

## 短所

- `IFoo`を見るだけでは`IFoo`がどのメソッドを要求しているかが分からない。
- `SomeClass`が`IFoo`インターフェイスを実装していることがコードだけでは分からない。

一応、どのメソッドを実装すべきかはVisual StudioなどのIDEが教えてくれるだろうが、分かりづらいことは確かである。

# `interface`でメンバが被った場合

当然ながら`interface`は多重継承できる。その場合に発生するのがメンバ被りだ。例えば次の場合を考える。

``` cs
public interface IHoge
{
    int Something { get; set; }
    // その他メンバ省略
}

public interface IPiyo
{
    int Something { get; set; }
    // その他メンバ省略
}

public interface IFuga : IHoge, IPiyo
{
    // その他メンバ省略
}

public class Fuga : IFuga
{
    public int Something { get; set; }
    // その他実装は省略
}

public void main()
{
    IFuga fuga = new Fuga();
    fuga.Something; // ここで警告が出る！
}
```

`IFuga`はコードのどこかで`IHoge`、`IPiyo`として使われることを期待している。
しかし、`IFuga`経由で両方で定義されているメンバを読み出すと、警告が走る。この場合は型が同じなので警告に留まるが、型が違えばそれぞれを明示的に実装しなければならないし、`fuga.Something`という書き方はできない。

## この場合の解法：new宣言の使用

ここで`fuga.Something`としたいのであれば、IFugaを以下のコードを追加すれば良い。

``` cs
public interface IFuga : IHoge, IPiyo
{
    // ...
    new int Something { get; set; }
}
```

`new`と銘打ったことで`IFuga.Something`は上位クラスとのつながりが切れた。しかし、今回の場合は型が同じため、`IHoge`、`IPiyo`いずれからでも`Something`を読み出すことができる。
WordPress ogタグ function.php

```function.php
/**********************
OGP設定
 *********************/
function my_meta_ogp()
{
  if (is_front_page() || is_home() || is_singular()) {

    /*初期設定*/

    // 画像 （アイキャッチ画像が無い時に使用する代替画像URL）
    $ogp_image = '画像URL';
    // Twitterのアカウント名 (@xxx)
    $twitter_site = '@Twitterアカウント名';
    // Twitterカードの種類（summary_large_image または summary を指定）
    $twitter_card = 'summary_large_image';
    // Facebook APP ID
    $facebook_app_id = '';

    /*初期設定 ここまで*/

    global $post;
    $ogp_title = '';
    $ogp_description = '';
    $ogp_url = '';
    $html = '';
    if (is_singular()) {
      // 記事＆固定ページ
      setup_postdata($post);
      $ogp_title = $post->post_title;
      $ogp_description = mb_substr(get_the_excerpt(), 0, 100);
      $ogp_url = get_permalink();
      wp_reset_postdata();
    } elseif (is_front_page() || is_home()) {
      // トップページ
      $ogp_title = get_bloginfo('name');
      $ogp_description = get_bloginfo('description');
      $ogp_url = home_url();
    }

    // og:type
    $ogp_type = (is_front_page() || is_home()) ? 'website' : 'article';

    // og:image
    if (is_singular() && has_post_thumbnail()) {
      $ps_thumb = wp_get_attachment_image_src(get_post_thumbnail_id(), 'full');
      $ogp_image = $ps_thumb[0];
    }

    // 出力するOGPタグをまとめる
    $html = "\n";
    $html .= '<meta property="og:title" content="' . esc_attr($ogp_title) . '">' . "\n";
    $html .= '<meta property="og:description" content="' . esc_attr($ogp_description) . '">' . "\n";
    $html .= '<meta property="og:type" content="' . $ogp_type . '">' . "\n";
    $html .= '<meta property="og:url" content="' . esc_url($ogp_url) . '">' . "\n";
    $html .= '<meta property="og:image" content="' . esc_url($ogp_image) . '">' . "\n";
    $html .= '<meta property="og:site_name" content="' . esc_attr(get_bloginfo('name')) . '">' . "\n";
    $html .= '<meta name="twitter:card" content="' . $twitter_card . '">' . "\n";
    $html .= '<meta name="twitter:site" content="' . $twitter_site . '">' . "\n";
    $html .= '<meta property="og:locale" content="ja_JP">' . "\n";

    if ($facebook_app_id != "") {
      $html .= '<meta property="fb:app_id" content="' . $facebook_app_id . '">' . "\n";
    }

    echo $html;
  }
}
// headタグ内にOGPを出力する
add_action('wp_head', 'my_meta_ogp');
```

function.phpにこれ追記するだけ
WMIを使用したWindowsUpdateListの一覧出力

# Wmicコマンドとは
WMI(Windows Management Instrumentation)コマンドはシステム管理に関する様々なハードウェア情報やソフトウェアといったシステム情報から、CPU稼働率などの動的な情報を取得、管理するためのコマンドです。
Windows2000以降では標準機能としてWindowsに実装されているようですが、近年ではWindowsPowerShellへ置き換わられており、非推奨となっています。

# InstallされたWindows Update FileのExport
Windows Update Fileの一覧をExportする必要があり、やり方を調べました。

## コマンド
以下はhtml形式でInstallされたWindows updateの一覧を出力できます。
```text
html形式
wmic qfe /format:htable > File名.html
csv形式
wmic qfe /format:csv > File名.csv 
```
Command Lineは非推奨とのことで、PowerShellでも出力できるか確認しました。
```text
html形式
get-hotfix | convertto-html -Property 列名 | out-file File名.html  
csv形式
get-hotfix | export-csv File名.csv
```
Property数は異なりますが、同じようなデータを取得できました。
（Slackアプリを作ってみて）Viewをsubmit → 即、別のViewをopenするのは無謀っぽい（追記：回避方法あり）

[Bolt For Javascript](https://slack.dev/bolt-js/concepts)を使用しました。

ざっくり言うと、以下のようなアプリを作りたかったのです。
①スラッシュコマンドやショートカットから登録画面を表示
②入力してもらって登録ボタンをぽち
③登録結果をユーザーに返す

登録画面で登録ボタンぽちっとするのだから、登録結果もViewで返した方がいいと思ったのです。
でも無理だったのでMessageで返しました。
なにが無理だったのか。

※無理と思っていたのですが、コメントでできる方法を教えていただきました！！

### Viewをsubmit → 続けて別のViewをopenするのは無謀っぽい
まずは素直に「登録画面でサブミット → 登録処理 → 登録結果画面表示」を考えました。
でもViewオープンには3秒ルールがあり、登録処理には3秒以上かかることが見込まれていたので、

①登録画面で登録ボタンを押す
②サーバでview_submissionを受け取り、処理中画面をview.openする。登録処理を実行する。
③登録処理が終わったら、処理中画面を登録結果返却画面にview.updateしてユーザーに結果を通知する。

としました。
これは一見うまくいったように見えました。

##### ですが
ですが処理中画面が表示されなかったり、登録結果画面への更新が失敗することがあります。サイレントで失敗する時と、Slackからエラー画面（なんか亀さんがいるエラー画面）を出された時がありました。
でも毎回じゃないし、view.openやview.updateのAPIレスポンスは正常となっているのに「なぜ？？」と唸っていました。


##### 結果
同じように困っている人はいないのかな？とネット検索してみたのですが同志は見つからず、「Viewサブミットの結果をユーザーに返したいのであれば、Messageで返す」のサンプルは見つかりました。思えば公式でもこの方法で紹介してたな、この方法が無難なんだな…という結果になりました。

###### 多分
「Viewサブミット→即Viewオープン」は想定されていなくて、Slack側で描画が追いついてないとかそういうことなのかなあ、と想像しています
年々のレポート任意の月を選択してスタートさせる方法は？


[Year over Year Report Question how to choose which month is first?](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000FU6WX)

Caseを使って数式フィールドで並び替えたようです。

```
CASE( Month__c ,  1, "11 -Jan",  2, "12 -Feb", 3, "01 -Mar", 4, "02 -Apr", 5, "03 -May", 6, "04 -Jun", 7, "05 -Jul", 8, "06 -Aug", 9, "07 -Sep", 10, "08 -Oct", 11, "09 -Nov", 12, "10 -Dec" ,NULL)
```
環境設定に依存しているエラーメッセージ

[まとめページに戻る](https://qiita.com/Keiji_otsubo/items/60afc2a8d211b6f7d89f)
[まとめA～M](https://qiita.com/Keiji_otsubo/items/f3ddedee6793bf1576f8)


+ [DEBUG|output[{"message":"Access from current IP address is not allowed","errorCode":"INSUFFICIENT_ACCESS"}]](https://qiita.com/Keiji_otsubo/items/34f88fe0d82dd2d04a1c)
composerがウクライナを応援しているのを見つけてみた #StandWithUkraine

ふとcomposer updateしてみたら違和感が・・・。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/250158/0433f512-947c-0875-9cb2-33addc96397e.png)

#StandWith Ukraine
「ウクライナと共に立ち上げれ」的なメッセージが！！

どうやら、こちらのIssueでメッセージが表示されるようになったようです。
https://github.com/composer/composer/issues/10582

追従するプロダクト出てきそうですね。

# 追記

コミットを見てみたら意外と賛否両論
https://github.com/composer/packagist/commit/86244a3695fcaaac9c5ba4257a4314eae1c6d981#/

気軽に手を出してはいけなそうです。
ドメインを介したエクスペリエンスサイトアクセス（オーディエンス）の指定


最後まで理解できない内容ですが、そのうち役に立つかもしれない

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/7b54ad16-6252-c2b6-32eb-524029562a5a.png)


[Specify Experience Site Access (Audience) via Domain](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000FuEnZ)


オーディエンスは、アクセス要素ではなく、パーソナライゼーション要素として考え、実装するのが最適です。あなたのユースケースは、物事のパーソナライゼーション側ではなく、物事のアクセス側にあるようです. したがって、アクセスに関する限り、次のオプションがあります。

1.認証されたサイト。企業の要件に応じてアクセスできるようにプロビジョニングされたユーザーがいます。

2. IP ログイン範囲が定義された認証されていないサイト。サイトへのアクセスを、定義した IP 範囲のみに制限します (これらの IP 範囲のメンテナンスが必要になり、ユーザーが最初から一貫した IP アドレスを持っていない可能性があるため、理想的ではありません)。

3. すべてのユーザーがサイトにアクセスできる認証されていないサイト (パブリック) (Web 上の誰もがサイトにアクセスできるようにしたくない場合はお勧めしません)

 

私の意見: あなたのユースケースは、認証されたサイト (上記の #1) と、要件に従って適切なユーザーに適切なアクセスを許可するユーザー プロビジョニング プロセスで最もよく機能します。
AWS lambda pythonでライブラリを読み込むまで

### AWS lambdaとは？
AWS環境下においてサーバーレス（EC2などを起動しない）でプログラムを実行できるサービス


### lambdaを使う利点

EC2と違って、サーバーレスなのでサービスを実行する時のみ課金される。
（コストを抑える利点がある）

### lambdaの使い方

AWSコンソールにてlambdaへ移動。

![lambda説明資料1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1928016/e502c9dd-f276-2464-a76b-6eb03afcf351.png)

右上の関数を作成ボタンをクリックして、関数を作成する画面へ飛ぶ。

関数の作成画面へ移行すると、関数の作成方法を求めてきます。

今回はユースケースなど使わず、一から作成を選択。

![lambda説明資料2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1928016/6c27e496-909c-9b00-53a1-373d97088506.png)


ランタイムにpython 3.9を選択し、関数を作成。

関数の作成が終われば、ここからはコーディング。

### 外部ライブラリの使い方

lambdaにはライブラリが搭載されていないので何も設定されていない場合だと、ライブラリが使えない。

lambdaでライブラリを使うにはレイヤーの設定が必要となる。

![lambda説明資料3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1928016/ae8fc5dc-1425-6f80-b9a0-82960fe04229.png)

レイヤーを設定し、関数に紐づけることでライブラリが使用できるようになる。

レイヤーの設定方法について、今回は.zipをアップロードする形で設定していきます。

```windows.コマンドプロンプト
pip install -t ./python requests
```

pythonフォルダにrequestsをinstallします。

```windows.コマンドプロンプト
powershell compress-archive ./python zip
```

上のコマンドでpythonディレクトリをzipファイルに圧縮。

zipファイルをレイヤーの作成画面からアップロード。

レイヤーの作成が完了したら、lambda関数のレイヤーの追加からアップロードしたものを紐づけることでライブラリが読み込まれるようになる。
django開発メモ admin.py

### Django公式ドキュメントより

> Djangoのパワフルな特徴の1つは、自動的に生成されるadminインタフェースです。
> あなたのモデルクラスからメタデータを読み取り、モデル中心のインタフェースを提供します。
> このインタフェースのおかげで、ユーザはあなたのサイトのコンテンツを操作することができます。
[Djangoドキュメント|Djangoのadminサイト](https://docs.djangoproject.com/ja/3.2/ref/contrib/admin/)

つまり、自分で管理サイト用のテンプレートを作らなくてもオッケー！
モデルを作成して読み込ませれば管理サイトができちゃう！すごい！頭いい！！

### モデルの読み込み
```python:admin.py
from django.contrib import admin
from myapp.models import Author

admin.site.register(Author)
```
ここでは、`form myapp.models import Author`で、
myappというアプリケーションからAuthorというモデルを読み込むことを可能にしている。

`admin.site.register(Author)`でadminページに指定のアプリケーションの項目（ここではmyapp）が表示されるようになる。

あとは、
```:command
python manage.py createsuperuser
```
で管理者ユーザーを登録、adminページにログインしてエラーがないか確認してみる。
これは最低限の設定で、全部デフォルトのとりあえず表示させてる状態って感じ。

adminページの見た目を変えたいとか、いろいろカスタマイズしたい場合は、上とはちょっと違う書き方をする。
```python:admin.py
from django.contrib import admin
from myapp.models import Author

class AuthorAdmin(admin.ModelAdmin):
    pass
admin.site.register(Author, AuthorAdmin)
```
ModelAdminクラスってのを作成して、その中にカスタマイズする内容を記述していく（らしい）。

さらに、デコレータってのがあって、
```python:admin.py
from django.contrib import admin
from .models import Author

@admin.register(Author)
class AuthorAdmin(admin.ModelAdmin):
    pass
```
この書き方でも大丈夫らしい。
違いは何ぞやと思い調べてみても難しくてわからなかった。
たぶん、`@admin.register()`を使えば、管理者権限を持つユーザーしかログインできないか、
アプリケーションの項目が表示されないようになるっぽい。

### カスタマイズ

***
### あとがき
pythonとDjangoの勉強をはじめて、まだまだわかないことだらけです。
備忘録としてと理解を深めるために、メモを残していきます。
調べたことや学んだことを言葉にして説明することの難しさを実感しています。
また、用語の正しい使い方に全く自信がありません。コメントで**優しく**指摘していただけると嬉しいです
中途半端な状態になっているかもしれませんが、追々更新していく予定です。
Dockerいろいろ

#### Dockerコマンドの覚書
```sh
# docker開始
docker start <docker_name>
# docker停止
docker stop <docker_name>
# docker プロセス確認
docker ps
# docker 実行例
docker -itd -p <port_num>:<port_num> <docker_name> <docker_image> <shell> -v <mount_vlume>
# docker 再構築
docker container prune
# dockerイメージ 完全削除
docker image prune
```
#### その他
```sh
# ポート確認
netstat -tupln
# ディスク容量割り当て確認
df -h
UnitTestにて、verifyでの比較が失敗する時の解決策

# 初めに
今回、自分が仕事でUnit testを書いていたときに起こったエラーに大きくつまづいたので備忘録として書かせていただきます。
早速ですがエラー内容としては下記の様なものでした
```
Verification failed: call 1 of 1: 受け取った比較対象. Only one matching call to 用意した比較対象 happened, but arguments are not matching:
[0]: argument: 受け取った比較対象のインスタンスなど詳細情報, matcher: 用意した比較対象のインスタンスなど詳細情報, result: -
```
では、なぜこの様なエラーが起きてしまうのか。
引数のクラスがdataクラスではないため、equlsが実装されていなくて、引数の比較が失敗するからです

### 解決策
では、どの様に解決すべきなのかです。
実はものすごく単純なもので比較をこちらが作って仕舞えばいいのです。
実装方法は下記になります

```kotlin:
verify {
           match {
                // ここに比較を自分で作成、意図した物が帰ってこなかった場合はfalseにするように実装
           }
       }
```

### 最後に
エラーログだけ見ると何がなんだかわかりづらいとは思いますが、解決策を見ると確かになぁと納得できる物だと思います。
備忘録程度なので、わかりづらい部分もあるかと思いますが何かのお役に立てれば幸いです
IBMCloud Netscalerにおけるサポートされるsyslog設定箇所

##サポートされる設定方法
NetscalerVPXでは、VPXを動作させるOSとしてFreeBSDが利用されている。
FreeBSD側にもsyslog設定が可能だが、<font color=red>基本VPX本体側のみサポートされる</font>

<b>FreeBSDファイルへの設定/カスタマイズはCitrixによってサポートされていません</b>


##サポートされていないが、設定する事はできる
必要に応じてFreeBSD側に設定変更してsyslogを利用できる。
しかし、トラブルが発生してもsyslog関連はサポートされない

下記のCitrixBlogにて、VPXとFreeBSDのSyslog設定について説明されていた
[Citrix ADC syslog configuration – The missing pieces](https://www.citrix.com/blogs/2020/08/25/citrix-adc-syslog-configuration-the-missing-pieces/)
メールを印刷しようとすると２ページ目が重なる

Outlook365を利用していて
なんかRICOHプリンタで印刷しようとすると
１ページ目に２ページ目が重なる……

MSが悪いのかリコーが悪いのか……
多分MSが悪い気がしています……(T_T)
【SAP】サンプルレポート - ExcelでSAPのレポートを作る

[Sharperlight](https://sharperlight.jp/)を使用すると、SAP Business One から必要なデータをExcelシート上に簡単に抽出できます。
![2022-03-09 Figure 01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/6639e11d-1b7c-408d-ecbe-634541b10a47.png)
:bow_tone1:英語を基本に開発されているので、ところどころ英語表記なのはご勘弁を。:pray:
しかし、[Sharperlight](https://sharperlight.jp/)は、ディクショナリ機能を有しているので、日本語への対応は可能です。
:postbox:[Sharperlight](https://sharperlight.jp/)
python3 thread



```python
import time
import threading

def proc():
    for i in range(0,5):
        time.sleep(1)
        print("count", i)

if __name__ == '__main__':
    th1 = threading.Thread(target=proc)
    th2 = threading.Thread(target=proc)
    th1.start()
    th2.start()
    while True:
      print("main loop")
      time.sleep(1)

```

https://corgi-lab.com/programming/python/python3-multi-thread/
githubで戻る方法

# コミットの取り消し
- 直前のコミットをなかったことにする
```
git reset --soft HEAD^
```
- 直前のコミットを取り消し
```
git reset --hard HEAD^
```
- コミット後の変更を全部消したい
```
git reset --hard HEAD
```
- addを取り消したい
```
git reset --mixed HEAD
```
- git resetをなかったことにする
```
git reset --hard ORIG_HEAD
```
# reflog 
- reflog（参照ログ）とは HEAD やブランチ先端の動きの履歴
各個人のローカルリポジトリに存在
- ブランチの切り替え、新たに加えられた変更のプル、履歴の書き換え、あるいは単なる新規コミットの実行などを記録
git reflog で HEAD の移動履歴を、git reflog <ブランチ名> でそのブランチ先端が指していたコミットの一覧を確認可能
- HEAD@{5}: HEAD の五つ前の状態を示す
```
$ git reflog
d22bfa0 HEAD@{0}: commit (amend): Add the contens of poem-c
8c9300c HEAD@{1}: commit: Add the contens of poem-c
6a67f31 HEAD@{2}: commit: Add empty poem-c
f7c3605 HEAD@{3}: reset: moving to @^
...
```
- 間違えて意図と異なるコミットへ git reset --hard して、必要なコミットを失った場合
`git reflog` か `git log -g` で `reflog` を見る
- 失ったコミットがあれば、`git reset --hard HEAD@{<n>} `でそのコミットへ HEAD を移動できる
- `git branch recover-branch HEAD@{<n>}` すれば、そのコミットが先端のブランチを作成できる
LatexIt で表示される数式のフォントを変更する

LatexItで表示される数式のフォントは、デフォルトではプレゼンなどで使うには若干細めになっている。たとえば、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28792/72b750ca-c91a-96c7-cb32-75acc08089c7.png)

これをもう少し見やすくするために別のフォントを使いたい。たとえば、Concrete ＋ Eulerフォントを使うと同じ式は次のように見える。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28792/20bbe032-f8be-53d0-c456-1cfaaee46805.png)

この設定をするためには、latexitの環境設定を開き、「Templates」タブでPreambleを編集して以下の１行を追加する。その後、"Apply to open documents"をクリックすると現在開いている数式に設定が反映される。

```latex
\usepackage{ccfonts,eulervm}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28792/ce7b8d69-b15d-bfbd-0a26-f0d98d0ff600.png)

参考: https://text.baldanders.info/remark/2017/10/math-fonts/
jQuery動的タグとjavaのDateについて

# jQuery動的タグ
aタグはjQueryコードを介して動的に作成されます（実際にはありません）
```javascript
 var tdObj6 =  $("<td><a id='"+n.id+"' class='deleteCategory' href='javascript:'>消す</a>|<a href='#'>改訂</a><td>");
```
通常のクリックイベント（jQueryによって作成された動的タグでは機能しません） 
```javascript
$(".deleteCategory").click(function(){
     alert("クリックされました")
}
```
動的タグのクリックイベント：
```javascript
$("#table").on("click",".deleteCategory",function(){
    alert("クリックされました")
}
```


# レビュー：Dateについて
Javaで現在の時刻を使用する場合は、Dateクラスを使用できます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524339/11b11952-b4f0-5ac2-a3dd-ee38a78f5fc8.png)
Javaでの時間形式の調整
```java
        Date date = new Date();//現在の時刻を取得できますが、形式がきれいではありません
		SimpleDateFormat time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		//カスタム編集時間形式
		String format = time.format(date);//dateをこの形式に変換する
		System.out.println(format);
```
githubdesktop ブランチを切って作業していたけど、反映させないでマスターブランチに戻りたとき

### githubdesktop
[![Image from Gyazo](https://i.gyazo.com/2ffc78b3390c2bd95ffadabdc85c577c.png)](https://gyazo.com/2ffc78b3390c2bd95ffadabdc85c577c)
### 日本語訳
[![Image from Gyazo](https://i.gyazo.com/8e8bd48b0a67681088ba7559d56d89e4.png)](https://gyazo.com/8e8bd48b0a67681088ba7559d56d89e4)
Django　ブログ記事に画像を表示する

# はじめに
Pythonの学習を始めようと思い、Djangoを用いてブログサイトの作ってみました。今回はその中で、ブログに画像を保存する方法を通して学習していきたいと思います。

# 開発環境
Python 3.8.12
Django 4.0.2
### バージョンの確認方法
Pythonのバージョン確認

```ターミナル.
python --version
```
Djangoのバージョン確認

```ターミナル.
python
>>>import django
>>>django VERSION
```


# 画像を使用するための設定

mediaファイルの設定の記述を追加します。

```config/settings.
MEDIA_ROOT = BASE_DIR / "media"
MEDIA_URL = "/media/"
```
アップロードされた画像をmediaディレクトリに保存するようにする設定です。
- mediaファイルはユーザーがアップロードしたファイルなどが保存されるディレクトリのことです。
- MEDIA_ROOTは、アップロードファイルなどを読み込む際のディレクトリの場所を記述する。
- MEDIA_URLは、mediaディレクトリのURLパスを設定する。


# URLの設定をする

```config/urls.py.
~
from django.conf import settings 
from django.conf.urls.static import static　　

urlpatterns = [
    ~
]

if settings.DEBUG:
    urlpatterns += static(
        settings.MEDIA_URL, document_root=settings.MEDIA_ROOT
    )
```
if settingsは開発環境のときのみ使用します。本番環境はDEBUG=FlaseとするためURL設定は反映されません。

# モデルを編集して画像カラムを追加する

```blog/models.py.
from django.db import models

class Post(models.Model):
  ~
  image = models.ImageField(upload_to="uploads/", null=True, blank=True)
  ~
  
```
ImageFieldについて
- upload_to = "uploads/" は、画像ファイルのアップ先を指定します。(media/uploads/に保存されます。)
- null=Trueは、データベースの中身が空かどうか判定する。
- blank=Trueは、Djangoのフォームから空かどうかを判定する。		

このままサーバーを起動するとエラーが出るので、Pillowをインストールします。

```ターミナル.
pip install pillow
```
- Pillow(PIL)とは画像処理ライブラリで、簡単な画像処理を行うことができます。

マイグレーションを実行してimageカラムを追加する

```ターミナル.
python manage.py makemigrations
python manage.py migrate
```

# 画像を表示する

```list.html.
    ~
    {% if post.image %}
      <img src="{{ post.image.url }}" class="card-img-top" alt="{{ post.title }}">
    {% endif %}
    ~
```
	
# おわりに
初めてのDjangoを用いての開発ということでわからない部分は多いですが、開発を通して学んでいければと思います。

# 参考
[Just Python staticとmedia](https://just-python.com/document/django/project-setting/static-media)
[DjangoBrothers BLOG](https://djangobrothers.com/blogs/django_null_blank/)