OmniAICreator/Qiita-1.07M huggingface dataset:
assert_empty cookies[:remember_token]がうまくいかない件

Rails Tutorialで詰まり、原因究明のためにコードを遡りました。

```ruby:test/integration/users_login_test.rb
test "login without remembering" do
   log_in_as(@user, remember_me: '1')
   delete logout_path
    
   log_in_as(@user, remember_me: '0')
   assert_empty cookies[:remember_token]
end
```
テストコードの```assert_empty cookies[:remember_token]```でFalseになってました。
関数を遡っていきます。

```ruby:test/test_helper.rb
def log_in_as(user, password: 'password', remember_me: '1')
   post login_path, params: { session: { email: user.email,
                                         password: password,
                                         remember_me: remember_me } }
end
```

```ruby:config/routes.rb
   post '/login', to: 'sessions#create'
```

```ruby:app/controllers/sessions_controller.rb
def create
   user = User.find_by(email: params[:session][:email].downcase)
   if user && user.authenticate(params[:session][:password])
      log_in user
      params[:session][:remember_me] == '1' ? remember(user) : forget(user)
      remember user
      redirect_to user
   else
      flash.now[:danger] = 'invalid email/password combination'
      render 'new'
   end
end
```

```ruby:app/helpers/sessions_helper.rb
def forget(user)
   user.forget
   cookies.delete(:user_id)
   cookies.delete(:remember_token)
end
```
ここまで遡ってみて、特に問題ないなと思いました。
　
```ruby:app/controllers/sessions_controller.rb
      params[:session][:remember_me] == '1' ? remember(user) : forget(user)
      remember user
```
よくみると、一度```forget```した後に、```remember```してます。これでは常にremember onをオンにしたのと変わりません。```remember user```を削除すると、テストにクリアしました。
RP2040でジョイスティックを作ってみる

RP2040を使用したジョイスティックを作成する。

# 環境
* XIAO RP2040
* Windows 11 
* Arduino IDE 1.8.19
# 1.今回使用するボード

### Seeed XIAO RP2040

Raspberry pi picoと同じチップを使用したボード  
1000円位で安い

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482400/698aac05-052b-081e-21db-8e88f066598f.jpeg width=90%>

# 2.ArduinoIDEの下準備
### ボードデータの追加  

ファイル -> 環境設定 -> 追加のボードマネージャのURLにRP2040を追加

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482400/7041a57d-57ce-cb4c-ca9b-3c69930747fa.png width=90%>

```
https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
```
ボードマネージャからボードのインストール
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482400/af3a741b-1766-c70d-6afb-df7f81839271.png width=90%>


### ライブラリの追加  
今回使用するライブラリは下記
RP2040のボードを追加したときに自動的に入る

入っていなければ、下記のGitからzip ファイルをDLしてArduinoIDEに読み込ませる

https://github.com/adafruit/Adafruit_TinyUSB_Arduino


# 2.配線  
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482400/d836802a-6dcc-efe9-eac5-ebfe76867f73.png width=90%>


# 3.ジョイスティックとして認識させる  

### コードの実装


ヘッダファイルとピンの設定
```
#include "Adafruit_TinyUSB.h"

#define BTN D4
#define ANALOG_X A0
#define ANALOG_Y A1

uint8_t const desc_hid_report[] =
{
  TUD_HID_REPORT_DESC_GAMEPAD()
};
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_NONE, 2, false);
hid_gamepad_report_t    gp;

```

初期設定 
```
void setup() 
{
  TinyUSB_Device_Init(0);
  usb_hid.begin();
  // wait until device mounted
  while( !TinyUSBDevice.mounted() ) delay(1);
  
  pinMode(BTN, INPUT_PULLUP);
  pinMode(ANALOG_X, INPUT);
  pinMode(ANALOG_Y, INPUT);
  if ( !usb_hid.ready() ) return;
  gp.x       = 0;
  gp.y       = 0;
  gp.z       = 0;
  gp.rz      = 0;
  gp.rx      = 0;
  gp.ry      = 0;
  gp.hat     = 0;
  gp.buttons = 0;
  usb_hid.sendReport(0, &gp, sizeof(gp));
}
```
analogRead,digitalReadで読み取った内容をhid_gamepad_report_t構造体に入れ  
usb_hid.sendReportでPCに送信をしています。
```
void loop() 
{ 
  gp.x = (int8_t)map(analogRead(ANALOG_X), 0, 1023, -127, 127);
  gp.y = (int8_t)map(analogRead(ANALOG_Y), 0, 1023, -127, 127);
  gp.buttons = (!digitalRead(BTN) << 0);
  usb_hid.sendReport(0, &gp, sizeof(gp));
}
```

### Windowsで認識するか確認

書き込んでWindowsにさしJoystickとして認識することを確認する 

コントロール パネル\ハードウェアとサウンド\デバイスとプリンターからXIAO RP2040名のデバイスを確認  
ゲームコントローラの設定

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482400/e4aa6db6-7280-f1cc-70e9-7737df0a65e4.png" width=40%>  


なぜか x,y,z軸　回転軸　ボタンが32個　表示されるが、今回使用しているのは一部のみ
ジョイスティックを動かすとXY軸が動くことが確認できた。

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482400/b2cded19-11d3-142c-dfe0-3fad6775cb71.png width=40%>


# 4.まとめ  
RP2040を使用してジョイスティックとして認識させ動作をPCに取り込むことができた。
【Python】大量のlogファイルをJSON整形されたJSONファイルに一瞬で変換する方法

# 概要
- `001_output.log`から`100_output.log`までのログファイルをそれぞれ`001_output.json`から`100_output.json`と言うファイル名のJSON形式に変更する方法を紹介します。JSONは整形された状態で出力されるようにしています。
    - ログファイルは元からJSON形式のログという前提です（`.log`なので整形はされていない）

# サンプルコード解説
```py
import os
import json

for i in range(1, 101):
    # ログファイルとJSONファイルのパスを指定
    log_file_path = f"./output_files/{str(i).zfill(3)}_output.log"
    json_file_path = f"./output_files/{str(i).zfill(3)}_output.json"

    try:
        with open(log_file_path, "r", encoding="utf-8") as log_file:
            log_content = log_file.read()

            # JSON形式に変換
            log_data = json.loads(log_content)

        with open(json_file_path, "w", encoding="utf-8") as json_file:
            # JSON形式に整形して書き込み
            json.dump(log_data, json_file, ensure_ascii=False, indent=4)

        # 元のログファイルを削除したい場合
        # os.remove(log_file_path)

    except (FileNotFoundError, json.JSONDecodeError) as e:
        print(f"変換エラー: {log_file_path} - {e}")
```

### ざっくり解説
- 読み込むログファイルのパスと書き込むJSONファイルのパスをはじめに定義します。
- `with`文は、ファイルの操作が終了したら自動的にファイルを閉じるための構文です。`"r"`は読み込みモードでファイルを開くことを指定しています。
- 次に、ログファイルの内容を文字列として読み込み、変数`log_content`に格納し、これをJSON形式に変換して`log_data`という変数に代入。
- `with`文の`"w"`書き込みモードのところで、`json.dump`を使って`log_data`の内容をJSON形式で書き込みます。

### ゼロパディングについて
- 今回、`1`ではなく、`001`というように、桁数に満たない部分をゼロで埋めています。必要ない場合は、`zfill`のところを変更して下さい。ちなみに以下の記法もあります。

```py
{i:03}_output.log
```

### 日本語のエンコードエラーが起きた場合
- 日本語のエンコードエラーが発生した場合は、以下の対応をします。
    - ログファイルの読み込みと書き込み時に`encoding="utf-8"`を指定。また、JSONファイルへの書き込み時には`ensure_ascii=False`を指定して、Unicode文字をエスケープせずに書き込むようにする。

### JSONフォーマットへの整形とエラー処理
- `json.dump`関数の`indent=4`を追加することで、JSONデータが整形され、可読性のある形式で書き込まれます。この`indent`を忘れると読みづらいJSONファイルができてしまいますので要注意。
    - インデントの数やスペースの量など、整形の詳細はカスタマイズ可能
- もしJSON形式になっていないログファイルがある場合、`json.JSONDecodeError`が発生しますので`except`で捕捉。

### `os.remove`について
- サンプルコードではコメントアウトしていますが、`os.remove(log_file_path)`は、指定されたパスにあるファイルを削除するためのコードです。
- `os.remove()`は、osモジュールの関数であり、指定されたファイルを削除するために使用されます。削除したい場合はこちらを実行させます。
webアクセシビリティを知ってる？

<h1>Webアクセシビリティとは何か、なぜそれが重要なのか<h1>

最近、webアクセシビリティに関するイベントに出席し、その重要性と実装方法について学ぶ機会がありました。
今日は、その学びを皆さんと共有したいと思います!

<h3>1. Webアクセシビリティとは？<h3>

Webアクセシビリティとは、<font color="red" >**ウェブコンテンツがすべての人々にとって使いやすくアクセス可能であること**</font>を意味します。これには、視覚や聴覚の障害を持つ人、運動障害を持つ人、高齢者、色覚異常を持つ人など、さまざまな特性や能力を持つ人々が含まれます。また、異なるデバイス（パソコン、スマートフォン、タブレットなど）やブラウザを使用する人々のことも考慮に入れるべきです。

<h2>2. Webアクセシビリティが重要な理由<h2>

<h4>2.1 ウェブの普遍性<h4>

インターネットは、情報の源泉であり、私たちが日々利用するツールの一部です。情報検索、ショッピング、学習、コミュニケーションなど、私たちの生活の多くの側面がウェブ上で行われています。しかし、これらの活動が可能であるためには、ウェブが万人に利用できる状態でなければなりません。そのため、ウェブアクセシビリティは重要な社会的課題となっています。

<h4>2.2 多様なデバイスへの対応<h4>

また、ウェブサイトやアプリケーションは、さまざまなデバイスやブラウザで利用できるべきです。ユーザーは自分にとって最も便利なデバイスやブラウザを選び、利用するため、それら全てに対応したウェブアクセシビリティは重要となります。

<h4>2.3 法的義務<h4>

さらに、多くの国や地域では、ウェブアクセシビリティは法的な義務となっています。例えば、日本では2016年に障害者差別解消法が施行され、公共機関や大規模な企業は、ウェブサイトがアクセシブルであることを求められています。これは音声読み上げ、点字ディスプレイ、色覚異常対応など、多様な形での情報提供を含みます。

<h4>3. Webアクセシビリティのガイドライン：WCAG<h4>

Webアクセシビリティの標準として最も広く知られているのは、W3C（World Wide Web Consortium）が開発したWCAG（Web Content Accessibility Guidelines）です。これは、視覚、聴覚、運動、認知の各種障害を持つ人々がウェブコンテンツをアクセスしやすくするための指導原則と基準を提供します。WCAGは、ウェブコンテンツのアクセシビリティを確保するための具体的な基準とテクニックを提供し、四つの原則（知覚可能、操作可能、理解可能、堅牢）に基づいています。

<h2>4. Webアクセシビリティのためのツール<h2>

Webアクセシビリティを確保するためのツールも多数存在します。例えば、Google Chromeの開発者ツール（DevTools）やLighthouseといったツールは、ウェブサイトのアクセシビリティをチェックし、改善点を指摘してくれます。これらのツールを使用することで、自分のウェブサイトがWCAGの基準を満たしているか、どの部分が改善されるべきかを確認することができます。

<h3>終わりに

Webアクセシビリティはすべてのユーザーが等しくウェブコンテンツを利用できるようにするための重要な要素です。ウェブ開発者は、最初からアクセシビリティを考慮して設計することで、全ての人がウェブサービスを十分に活用できるようにする責任があります。以上が、私が最近出席したイベントで学んだWebアクセシビリティの基本的な概念とその重要性です。
Linuxでいきなりcdやlsなどのコマンドが使えなくなった

# はじめに

Fultterの環境構築をしているときに`.bashrc`のスワップファイルがあるという忠告を受けたので編集して適応したらいきなりコマンドが使えなくなって困ったのでまとめます

# 問題

`ls`コマンドをしたところ以下のエラーが出るようになりました

```
$ ls
コマンド 'ls' は以下の場所で利用できます
 * /bin/ls
 * /usr/bin/ls
'/usr/bin:/bin'がPATH環境変数に含まれていないためコマンドを特定できませんでした。
ls: コマンドが見つかりません
```

# 解決方法

以下のコマンドで解決しました

```
echo 'export PATH=$PATH:/bin:/usr/bin' >> ~/.bashrc
source ~/.bashrc
```

何かのタイミングでパスが変わってしまったようでした
治ってよかった、、

# おわりに

Linuxコマンドが使えなくなって焦りました
また調べてもすぐに記事がみつからなかったのも意外でした
Ct.jsの日本語翻訳を更新する方法

# はじめに
:::note
この内容は2023年7月1日時点の情報です。現在この問題は解決しています。
:::
JavascriptまたはCoffescriptで簡単にゲームを作れるCt.jsですが、公式サイトにある最新版だと翻訳データが古く翻訳漏れがあります。

↓ 言語を「日本語」に設定しているのに英語の部分が残っている例
![スクリーンショット 2023-07-01 174940.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1751564/a9d09946-50f8-6e36-78c1-b84a865b2246.png)
今回はこのデータを更新する方法を紹介します。

## 1.新しい翻訳ファイルをダウンロード
ct.jsはオープンソースソフトウェアなので、Githubでソースが公開されています。
Githubにある新しい翻訳ファイルをダウンロードして従来のものと取り替えることで、エラーを解消しましょう。

[このリンク](https://github.com/ct-js/ct-js "ct.jsのレポジトリ")を開いてください。![Screenshot_20230625-165040.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1751564/c34e9440-ea3f-65f0-8b73-9d8b0b56e805.png)
「app」→「data」→「i18n」の順にフォルダをクリックすると、jsonファイルが並んだページに行きます。
![Screenshot_20230625-165013.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1751564/b5ef1740-83c2-eac2-7128-f4a7c4bb5f8c.png)
その中から、Japanese.jsonを開き、![スクリーンショット 2023-07-01 175534.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1751564/7c1ff098-3e33-84e9-13dc-f8bd7a1c2b50.png)
「Raw」を右クリックして、リンク先を保存してください。

## 2.エクスプローラーでの操作
エクスプローラーからexeファイルが入ってるフォルダに移動し、
(Windowsの場合はC:\Users\(ユーザー名)\AppData\Local\ct.js)
そこから「data」→「i18n」に移動すると、さっきGithubで見たようなファイルが並んでます。
![スクリーンショット 2023-07-01 180420.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1751564/2e4d0516-f5ec-66fc-0a18-3a14bdd13bb3.png)
ここにさっきダウンロードしたJapanese.jsonをドラッグ＆ドロップして、
![スクリーンショット 2023-07-01 180717.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1751564/decede0c-df23-0e34-8259-5ac67dda8647.png)
ファイルを置き換えれば完了です。

#### Before
![スクリーンショット 2023-07-01 174940.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1751564/ae80cf5d-2173-7a7c-768a-201887cb8520.png)

#### After
![スクリーンショット 2023-07-01 181049.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1751564/0ff003c3-4074-c455-8af7-47a9c3c2811f.png)

やったぜ！
Pythonで書く「アルゴリズムとデータ構造」　13_選択ソート

コーディングテスト対策として、「アルゴリズムとデータ構造」という本を実践してます。
自分自身の備忘のために、pythonコードとメモを載せてます。

# pythonコード
```python
def selectionSort(A, N):
    swich_counter = 0
    for i in range(N):
        mini = i
        for j in range(i, N):
            if A[ j ] < A[ mini ]:
                mini = j
        if A[ i ] != A[ mini ]:
            A[ i ], A[ mini ] = A[ mini ], A[ i ]
            swich_counter = swich_counter + 1
    # いつものやつ（出力）
    print( ' '.join( map( str, A ) ) )
    print(swich_counter)

# いつものやつ（入力）
N_input = int( input() )
A_input = list( map( int, input().split(' ') ) )

selectionSort(A_input, N_input)
```

# 補足
```python
if A[ i ] != A[ mini ]:
```
上記コードがないと```swich_counter```に正確に反映されません。
【2.キーボード操作編】ここから始めようWebアクセシビリティ

## 関連記事
1. [【0.気持ち整理編】](https://qiita.com/shamokit/items/2d490f281a3bd168fdd6)
1. [【1.導入編】](https://qiita.com/shamokit/items/e8c4c2f13cc604f4fb2c)
1. いまここ 【2.キーボード操作】

## 振り返り
気持ち整理編では「なぜやるのか」「何のためにやるのか」を整理しました。
導入編では「どうやって学ぶのか」「やりがちなミス」をみて知識をつけました。

ここからは、スクリーンリーダーを使う前にまずキーボードでサイト内を操作してみよう　というのをやります。
この記事では、キーボードで操作できないコンテンツを見ていきます。次の記事でそれを改善していきましょう。


## キーボードでサイト内を操作してみる
一旦二つだけ覚えてください。

`Tab`
フォーカス可能な「現在フォーカスしている要素の次の要素」にフォーカスを移動します。

`Shift + Tab`
フォーカス可能な「現在フォーカスしている要素の前の要素」にフォーカスを移動します。

今回は特別にメインコンテンツ内に、よく使用される

- リンク
- ボタン
- アコーディオン
- タブ

があるページを用意しました。
__ただし、このページのコンテンツはキーボードで操作できません。__
[https://shamokit.com/examples/a11y/bad](https://shamokit.com/examples/a11y/bad)

:::note warn
__スクリーンリーダーでの読み上げ__
実はこれらのコンテンツはスクリーンリーダーでの読み上げに対してもよくない実装になっています。

こちらの改善については次の次の記事あたりで対応します。
:::

### まずマウスで操作する
まずはマウスだけで以下を確認してみてください。

- TOPページはこちら の「こちら」の部分をクリックしたらTOPページに遷移する
- 「+1」と書いてあるボタンをクリックすると「クリックするとメッセージが表示されます！」というメッセージが、何回クリックしたかを教えてくれるメッセージに変わる
- 「このページについて」と書いてあるテキストをクリックすると「このページ内のコンテンツは、キーボードで操作できないようにわざと悪い実装やマークアップをしているページです。
絶対に真似しないでください。」というメッセージが表示される
- 「哺乳類」「魚類」「鳥類」のタブをクリックするとその下のタブパネルが切り替わる
！！タブの中身は正しい情報ではない可能性があります！！

動いてますね。

### キーボードで操作する
Chromeをお使いの方はブラウザのアドレスバー（URLが入力されているところ）あたりをクリックしてからTabキーを2回くらい押すと「しゃもきっとブログ」のロゴにフォーカスが当たって角丸のアウトライン（ボーダー）が表示されると思います。
（キーボードでサイト内のコンテンツにフォーカスできれば何でもいいです。）

そこからタブを何度か押していってみてください。
そして以下を確認してください。

- TOPページはこちら　のリンク（に見えるもの）にフォーカスできない
- 「+1」と書いてあるボタンにフォーカスできない
- 「このページについて」と書いてあるテキストにフォーカスできない
- 「哺乳類」「魚類」「鳥類」のタブにフォーカスできない

どうでしたか？グローバルメニューの[メールアイコン]Contactの次のフォーカスがフッターのコンテンツになっていて、メインコンテンツ内にアクセスできなかったと思います。

つまり、 __キーボードで操作するユーザーがメインコンテンツにアクセスできていない__ ということです。
これは「Webを誰にでも使えるようにする」という観点で大問題です。
大した問題ではないと思う方はこの記事を読んでいないはずです。

試しに自分が所属している会社のサイトやアプリケーションをキーボードで操作してみましょう。

おそらくほとんどの方が「このコンテンツにアクセスできない」という部分を見つけると思います。
サイトやアプリケーションの品質を高め、より多くのユーザーが利用できるものにするためにアクセシビリティの改善をやっていきましょう！

## 具体的に何が悪かったのか
なぜキーボードで操作できなかったのかみていきましょう。
この記事内では簡単な説明にとどめ、修正しません。

### リンク
みた感じ「こちら」に下線が引いてあるのでリンクに見えます。
検証ツールで見てみると`a`タグでマークアップされています。

あれ、おかしいですね。`a`タグならキーボードでフォーカスできるはずです。
ところが、よくみると`href`属性が設定されていません。
これのせいですね。JSでページ遷移を実現させているようです。

### 「+1」ボタン
`div`でマークアップされているのが原因です。
`button`タグでのマークアップが妥当でしょう。

### アコーディオン
こちらも`div`で実装されているのが原因です。
アコーディオンについては`button`でマークアップするか、`details`タグでの実装が選択肢になると思います。
特に理由がなければ`details`タグでの実装をお勧めします。

`details`タグで実装すれば`Ctrl + F`での検索においてコンテンツ内にヒットした場合自動でアコーディオンが開くメリットがあり、こちらであればJSがなくても実装できます。

### タブ
こちらも`div`で実装されているのが原因です。
タブについても`button`でのマークアップがいいと思います。

タブに関してはキーボードでの操作のためにJSでの実装が必要です。

## まとめ
正しいマークアップがされていないとキーボードで操作できないことがわかりました。

- リンク
- 「+1」ボタン
- アコーディオン

に関してはタグを変更すれば少なくともキーボードでの操作は可能になるので、次回の記事では答え合わせ＋補足にとどめ、タブの実装をメインに解説して修正していきます。

次回でキーボードでの操作はできるようになりますが、この記事の序盤で書いたように、実はそれだけではスクリーンリーダーユーザーへの対応が不十分です。

このシリーズはあと数記事続きます。
できるだけ多くなりすぎないボリュームで進めているので、どんどん先に進みたい人は[前回の記事](https://qiita.com/shamokit/items/e8c4c2f13cc604f4fb2c)で紹介した本やブログなどを読んでどんどんアクセシビリティを改善していってください。

僕もまだ目を通せていませんが、以下の二つのサイトにも実装例が載っているようなのでひとまず共有しておきます。

- https://web.dev/learn/accessibility/
- https://www.w3.org/WAI/ARIA/apg/patterns/

## これから
次回の記事でキーボード操作可能にした後、スクリーンリーダーの紹介と簡単な使い方の説明を行い、その後スクリーンリーダーでの読み上げで問題のあった部分の改善を行います。

できるだけゆっくり進める予定なので、あと3〜４記事くらいかかると思います。
右クリックを禁止にしたり、禁止を回避したり

# 右クリックを禁止する方法
次のように実装する。
```html
<body oncontextmenu="return false;">
```

# 右クリックを禁止を回避する
F12をクリックして「開発者ツール」を開いてコンソールに次のように入力する。

```
document.oncontextmenu = function(){return true;}
```
もしくわ
```
document.body.oncontextmenu = function(){return true;}
document.getElementsByTagName('html')[0].oncontextmenu = function(){return true;}
```
Django Webアプリケーション AWSデプロイ EC2 SSL証明書更新自動化

『動かして学ぶ! Python Django開発入門（第1版）』で学ぶ際、
SSL化で用いるcertbot-autoが使えなくなっている。
これでは本書の意図通り、自動更新の設定が出来ない。

そして、90日間が有効期限となっているSSL証明書を手動で更新しなければならない。
※次のコマンド1行をEC2上で実行。（Windowsの場合PuTTyにて）
```
sudo certbot --nginx
```
参考記事：[【Nginx】Let’sEncryptからのSSL証明書がcertbot-autoで取得できない際の対処](https://zenn.dev/whitecat_22/articles/c353049988b034)

これを本来の目論見通り、自動更新できるようにする。
AWSで使われているOSはLinux。
Linuxに、cronという定期的なプログラムの自動実行用の常駐プログラムが入っている。

cronを設定する為に、次のコマンドを打つ。（cronへのコマンドの登録は下記の通行う。）
```
crontab -e
```

そうすると、vimエディターのような画面になるので、キーボードで'i'のボタンを押して「挿入モード」にして、次のように記載し、'Esc'ボタンを押して、:wqを押して、保存してエディターから退出。
```
30 07 25 */2 * echo 2 | sudo /usr/bin/certbot --nginx -d janken-time.com
```

この登録したコマンドは、
「（3か月に対して余裕を持って）2ヶ月おきに、日付が25日の日、朝7時30分に右側に記述したコマンドを実行してください」
という意味合い。

オリジナルのSSL証明書更新用のコマンドは、
```
sudo certbot --nginx
```



これを、
```
echo 2 | sudo /usr/bin/certbot --nginx -d janken-time.com
```

にしたのは、例に倣ってcertbotをフルパスにした上で、
次の画像の黄色枠のように、
![PuTTY AWS SSL化更新.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448893/33fce8f6-addd-4605-a902-0d661dba9aad.jpeg)


「登録されている何番目のURLのものを更新しますか？」
と聞かれるので、応答で「1：janken-time.com」を自動応答出来るようにし、
（-dの後に、SSL証明書を適用するWebアプリケーションのURLを引数に設定すると良いそうです。chatGPTが教えてくれました。）
また、次の質問、
>What would you like to do?
>- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
>1: Attempt to reinstall this existing certificate
>2: Renew & replace the certificate (may be subject to CA rate limits)
>- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

で、「更新」の意味の「2」を自動応答出来るようにする為。
（SSL証明書の有効期限が切れていないときには、この2つ目の引数も必要になる。）

```
echo 2 | sudo /usr/bin/certbot --nginx -d janken-time.com
```

このコマンドの有効性は次の画像のように実際に実行してみて確認できている。
![EC2_SSL_reissue_PuTTY_AWS_20230401_確認.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448893/4ae6de94-12fc-417c-0e12-229657a061dd.jpeg)

3ヵ月後、
自動更新されていることを確認済！！
以上！！
Python3 日本語版 docset for mac dash

# いきなりですが本題

## 作成したもの
Python3.11.4日本語版docset　（mac用アプリDashで使うアレです）

## 公開先
[Python3 日本語版 docset for mac Dash](https://docset.glmx.work/)

### 作成検証環境
- Macbook Air Mid2013
- Dash for mac v3.3

※注意事項
現在Dashのバージョンは6になっているようなので、もしかしたら動かないかもです。その時は、こちらにコメントをいただけたら対処するかもしれません。


## 後書き
**Python3日本語版docsetが欲しい**
探したけど見つからない・・・

**自分で作るってみるか**
というわけで、Dash(macOS)用のPython3.11.4日本語版docsetを作成開始。

**そして、作り方を投稿する**
つもりだったが紆余曲折の末にできあがったため、手順をまとめきれない・・・

**であれば、せっかくなので、**
できたものを公開するしかないな・・・
そんな感じで今に至る。
Pythonで書く「アルゴリズムとデータ構造」　12_バブルソート

コーディングテスト対策として、「アルゴリズムとデータ構造」という本を実践してます。
自分自身の備忘のために、pythonコードとメモを載せてます。

# pythonコード
~~~python
# バブルソート関数の定義
def bubbleSort(A, N):
    # 交換回数
    swich_counter = 0
    neighbor_exist = True
    while neighbor_exist:
        neighbor_exist = False
        for j in reversed( range( N ) ):
            if A[ j ] < A[ j-1 ] and j-1 >= 0:
                tmp = A[ j ]
                A[ j ] = A[ j-1 ]
                A[ j-1 ] = tmp
                swich_counter = swich_counter + 1
                neighbor_exist = True
    return A, swich_counter


# いつものやつ（入力）
N_input = int( input() )
A_input = list( map( int, input().split(' ') ) )

# バブルソート関数の実行
A_output, swich_counter = bubbleSort(A_input, N_input)

# いつものやつ（出力）
print(' '.join( map( str, A_output) ) )
print(swich_counter)
~~~

# 補足
~~~python
if A[ j ] < A[ j-1 ] and j-1 >= 0:
~~~
上記コードは ``` j-1 >= 0 ``` がないとループします。
理由は、pythonでは```A[-2]```とかが出力できてしまうからです。

~~~python
for j in reversed( range( N ) ):
~~~
上記コードは ```5, 4, 3, 2, 1, 0``` となります。
Ubuntuで空き容量を確認する

Ubuntuのパソコンで空き容量を確認するためには、以下のコマンドを使用することができます。

1. `df`コマンド:

   ```
   df -h
   ```

   `df`は"disk filesystem"の略で、ディスクの使用状況を表示します。`-h`オプションは"human-readable"の略で、結果をキロバイト、メガバイト、ギガバイトなどの読みやすい単位で表示します。

2. `du`コマンド:

   ```
   du -sh /
   ```

`~/hoge`ディレクトリを`/`（ルート）ディレクトリに移動するには、以下のコマンドを使うことができます：

```bash
sudo mv ~/hoge /
```

`sudo`を使ってディレクトリを移動した場合、そのディレクトリの所有者とグループが元のまま（おそらくあなたのユーザーアカウント）であり、パーミッションも元のままなので、`/`ディレクトリに移動した後も引き続きあなたが所有していることになります。

しかし、ディレクトリをルート(`/`)に移動すると、通常、rootユーザーしかそのディレクトリにアクセスできなくなります。これがGUIのファイルエクスプローラで`/hoge`ディレクトリが開けない原因かもしれません。

この問題を解決するためには、`/hoge`ディレクトリのパーミッションを変更する必要があります。以下のコマンドを使用すると、全てのユーザーが`/hoge`ディレクトリを読み取り、実行できるようになります：

```bash
sudo chmod a+rx /hoge
```

これにより、全てのユーザーが`/hoge`ディレクトリの中身を見ることができるようになるはずです。

なお、ファイルの内容を読むためには、同様にそのファイルに対しても読み取りパーミッションを与える必要があります。これを行うには以下のコマンドを実行します：

```bash
sudo chmod -R a+r /hoge
```

このコマンドにより、`/hoge`ディレクトリ内の全てのファイルとディレクトリに対して読み取りパーミッションが与えられます。`-R`オプションは"recursive"の略で、指定したディレクトリとその中にある全てのファイルとディレクトリに対して操作を行うことを意味します。
MicrosoftのOpenAI ChatGPTサンプルを、個人のAzureアカウントで動かす＆Javaとの比較をしてみる

# 概要

 - Microsoftの[Azure Cosmos DB + OpenAI ChatGPT](https://github.com/Azure-Samples/cosmosdb-chatgpt)サンプルを、Azure OpenAIではなく、OpenAI社のサービスを利用するように変更しました。
 - Azure OpenAIは、エンラープライズ契約がないと利用できないため、個人のAzureサブスクリプションで同サンプルを動かすために作成しました。
 - ソースコードとしては、Azure OpenAIへのアクセスを責務とするサービス`OpenAiService.cs`のみ修正しており、他の箇所の修正はありません（プロパティ等変更はあり）。
 - Javaのエンジニアが、個人のAzureサブスクリプションで、ASP.NETのAzure OpenAIのサンプルを動かしたい、という極めてニッチなアレです。

# 成果物

成果物は[【こちら】](https://github.com/katakotoworks/cosmosdb-chatgpt-betalgo)から。

# L&L

作業中に判ったこと：もともとJavaの世界しか知らなかったので、Javaでいうところの何、というのの理解をまとめました。

## アーキテクチャの概要

| # |サンプルの方式|Java系のスタックで相当するもの|
|----|----|----|
|言語|C#|Java||
|フレームワーク|ASP.NET Core Blazor Server|JSF|
|DI|Microsoft.Extensions.DependencyInjection|CDI|
|実行環境|Azure App Service|AWS Elastic Beanstalk|
|DB|Azure Cosmos DB|AWS DocumentDB(MongoDB)|

 - Blazor Serverは、UIを構築するためのフレームワークで、サーバサイドで動作します。
 - 同じBlazorでも、Blazor WebAssemblyを使うと、ブラウザのWebAssemblyランタイムで実行されるコードになります。
（WebAssemblyはブラウザに内蔵されているバイトコード実行環境で、JavaScriptインタプリタの横にあります）

## プロジェクト自体を構成するファイル

|#|サンプルのファイル|Java系のスタックで相当するもの|
|----|----|----|
|プロジェクト定義|cosmoschatgpt.sln|.project|
|ビルド定義|cosmoschatgpt.csproj|pom|
|規定のエントリポイント<br>(FW初期化、DI実行……を実行)|Program.cs|public static void main(String[] args)|
|プロパティファイル|appsettings.json|*.properties|
|IaC<br>(Azure CLI用のDSL)|azuredeploy.bicep|AWS CloudFormationテンプレート|
|IaC<br>(Azure Resource Manager テンプレート)|azuredeploy.json|AWS CloudFormationテンプレート|

## コマンドラインで遊ぶ

 - コマンドラインからビルドする場合は、以下のいずれか。mavenがpomを読むように、MSBuildは(sln経由で)csprojを読みます。dotnet buildは内部的にMSBuildを使うようです。MSBuildの詳細は[こちら](https://learn.microsoft.com/ja-jp/visualstudio/msbuild/walkthrough-using-msbuild)。
```
"C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\MSBuild.exe" cosmoschatgpt.sln
dotnet build cosmoschatgpt.sln
```
 - コマンドラインから実行する場合は、以下のいずれか。画面に表示されるとおり、localhost:8100からアクセスできます。
```
dotnet run --project cosmoschatgpt.csproj
dotnet run cosmoschatgpt.sln
```
 - azuredeploy.jsonはDeploy to Azureボタンのためだけに利用します。azuredeploy.bicepをコンパイルして作ります。コマンドは以下。Bicepの詳細は[こちら](https://learn.microsoft.com/ja-jp/cli/azure/bicep)。
```
az bicep build --file azuredeploy.bicep
```
 - azuredeploy.bicepをAzureにデプロイするコマンドは以下。`resource_group_1`はbicepに書かれたリージョンに作成しておく必要があります。
```
az deployment group create --resource-group resource_group_1 --template-file ./azuredeploy.bicep
```

## ソースコードの種類

|#|サンプルのファイル|Java系のスタックで相当するもの|
|----|----|----|
|画面定義＋ロジック|Pages/*.razor|xhtml + ViewScoped bean|
|サービス(DDDでいう)|Services/*.cs|Singleton bean|
|ドメインモデル|Models/*.cs|Entity bean|
|設定値|Options/*.cs|Singleton bean -> ConfigProperty field|

 - まあここは感覚で。

## Blazorまわりのあれこれ

参考：
<https://learn.microsoft.com/ja-jp/aspnet/core/blazor/project-structure>
<https://learn.microsoft.com/ja-jp/aspnet/core/blazor/components/layouts?view=aspnetcore-7.0>

|#|サンプルのファイル|補足|
|----|----|----|
|ルートページ|Pages/_Host.cshtml||
|規定レイアウト|Pages/_Layout.cshtml|_Host.cshtmlから参照|
|ルータ|App.razor|web.xml, faces-config.xml的なやつ|
|using自動読込|_imports.razor||

# 感想

概ね、JavaEE6+AWSくらいの時代感のエコシステムが判っていれば、読み解き、修正、デプロイは可能だなと思いました。
まったく知らない技術に触れると、やっぱり楽しいですねえ。
【チュートリアル】GoとGinを使ったRESTful API開発のチュートリアルで詰まったところ

Goの勉強を始め、基本的な文法はさらったので**API**の勉強をしてみたいと思い、以下のチュートリアルをしてみました。

https://go.dev/doc/tutorial/web-service-gin

割と簡単にAPIの実装の仕方を学べたのでおすすめ。
本記事ではわからなかった単語や詰まったところについてまとめておきます。
ぜひ参考にしてください。

# "go mod tidy"と"go get ."の違い

- go mod tidyはモジュールの依存関係を更新するため
- go get .は実際モジュールをインストールするため

go mod tidyコマンドは、**モジュールの依存関係**を解決し、go.modファイルとgo.sumファイルを最新の状態に更新します。
go get .コマンドは、現在のディレクトリにあるパッケージとその依存関係を**ダウンロードし、インストール**ます。

# MustBindWith機能
MustBindWithは、指定されたバインディングエンジンを使用して、**渡された構造体ポインタにデータをバインドする機能**です。

**バインドとは、HTTPリクエストからのデータを構造体にマッピングするプロセスのこと**です。構造体にはフィールドが定義されており、それぞれがリクエストデータの特定の部分に対応しています。

<details><summary>フィールドとは</summary>

```go
type Person struct {
    Name  string
    Age   int
    Email string
}
```
上記の例では、Personという構造体が定義されています。この構造体には、Name、Age、Emailという3つのフィールドがあります。それぞれのフィールドは、文字列型 (string)、整数型 (int)、文字列型 (string) のデータを保持します。

</details>

# 関数になんでポインタを渡すん？
```go
if err := c.BindJSON(&newAlbum); err != nil {
		return
	}
```
ポインタを渡すと**元の変数を直接変更**する
そのまま変数を渡すと**変数のコピーが変更**される

# [Write a handler to add a new item] でもとのコマンドじゃ動かん。
以下はサイトに載っているコマンド
```bash
$ curl http://localhost:8080/albums \
    --include \
    --header "Content-Type: application/json" \
    --request "POST" \
    --data '{"id": "4","title": "The Modern Sound of Betty Carter","artist": "Betty Carter","price": 49.99}'
```

動いたコマンド
```bash
curl -X POST -H "Content-Type: application/json" -d '{"id": "4","title": "The Modern Sound of Betty Carter","artist": "Betty Carter","price": "49.99"}' http://localhost:8080/albums
```

## 動いたコマンドの説明
-X：HTTPメソッドを設定。(今回はPOST)
-H：リクエストヘッダーのContent-typeを設定。
-d：リクエストボディとして送信するデータ
<details><summary>リクエストヘッダーって何？</summary>

HTTPリクエスト中のメタデータ情報を含む部分です。クライアントがサーバーに対してリクエストを送信する際に、リクエストヘッダーに必要な情報を含めることで、サーバーに対する要求の詳細や処理方法を伝えることができます。

今回はこの中のコンテンツタイプを指定した。

- HTTPメソッド（GET、POST、PUT、DELETEなど）: リクエストの目的や処理方法を指定します。
- URLやパス: リクエストの対象となるリソースの場所や識別子を指定します。
- ホスト名: リクエストを受けるサーバーのホスト名を指定します。
- ユーザーエージェント: リクエストを行うクライアント（通常はWebブラウザ）の情報を指定します。
- コンテンツタイプ: リクエストボディの形式や種類を示します。例えば、JSONやXMLなどのデータ形式を指定する場合があります。
- 認証情報: リクエストを送信するために認証が必要な場合、認証に関する情報を含めることがあります。
- クッキー: クライアントが保持するセッション情報などを含めることがあります。

</details>

# 今回の学び
- chromeのページ翻訳使ったら結構すらすら進んだ。
- API難しく考えすぎてた。
- ChatGPTに質問しながら進めるの楽しい。

# 課題
- フロント側でどうやって受け取るの？
- データベースとの連携は？
- 英語の原文のまま読んだ方がもっとニュアンス取れそう。

# PS
7月まででバックエンドとかデータベース関係勉強し終わって７月はwebアプリ作ろうと思ってたけど、厳しそう。
早く何かを形にしたい。
夏インターン、１社しか決まってない。(´·ω·`)
長期インターン探し中。
document.getElementById()のメモ

自分用の備忘録です。
## 取得したいHTMLのID
qiita(pタグ)
form(inputタグ)
## 基本的な使い方
~~~javascript:main.js
//取得
qiita = document.getElementById("qiita")
~~~

## テキスト取得＆書き換え
~~~javascript:main.js
//取得
qiita = document.getElementById("qiita")
//コンソールに出力
console.log(qiita.innerText)
//文字をHello Qiita!に書き換え
qiita.innerText = "Hello Qiita!"
~~~
:::note warn
取得の際に.innerTextを指定すると読み出しはできますが<font color="Red">**書き換えができません**</font>
:::


## inputタグを取得
~~~javascript:main.js
//取得
form = document.getElementById("form")
//コンソールに出力
console.log(qiita.value)
//文字をHello Qiita!に書き換え
qiita.value = "Hello Qiita!"
~~~
MyBatisでDBの共通カラムを設定する

## Aspectで値を設定する

Aspectを利用して、Mapperを実行する前にパラメータに値を設定する。
対象となるプロパティを共通仕様にして、これを拡張したものを利用すると良い。
今回は、以下のテーブル共通項目を自動で設定する仕様とする。

- 登録者
- 登録日時
- 更新者
- 更新日時
- バージョン

```Java:MapperAspect

import java.lang.reflect.Method;
import java.util.Date;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;

@Aspect
@Component
public class MapperAspect {

	@Before("execution(* jp.co.test.mapper.*Mapper.insert*(..)) || "
			+ "execution(* jp.co.test.mapper.*Mapper.update*(..))")
	public void setCommonProperty(JoinPoint jp) throws Throwable {

		// Mapperのメソッド名を取得
		MethodSignature signature = (MethodSignature) jp.getSignature();
		Method method = signature.getMethod();
		String methodName = method.getName();

		// ログインID(各フレームワークで保持しているIDを持ってくる)
		String loginId = "123456789";

		// 現在日時の取得
		Date now = new Date();

		// Mapperの第一引数（モデルオブジェクト）を取得
		Object[] args = jp.getArgs();
		Object dto = args[0];

		if (methodName.startsWith("insert")) {
			setInsertedProperty(loginId, now, dto);
			setUpdatedProperty(loginId, now, dto);
		} else if (methodName.startsWith("update")) {
			setUpdatedProperty(loginId, now, dto);
		}
	}

	private void setInsertedProperty(String loginId, Object now, Object dto) throws Throwable {
		Method setTorokushaId = ReflectionUtils.findMethod(dto.getClass(), "setTorokushaId", String.class);
		if (setTorokushaId != null) {
			setTorokushaId.invoke(dto, loginId);
		}
		Method setTorokuDatetime = ReflectionUtils.findMethod(dto.getClass(), "setTorokuDatetime", Date.class);
		if (setTorokuDatetime != null) {
			setTorokuDatetime.invoke(dto, now);
		}
		Method setVersion = ReflectionUtils.findMethod(dto.getClass(), "setVersion", Integer.class);
		if (setVersion != null) {
			setVersion.invoke(dto, 1);
		}
	}

	private void setUpdatedProperty(String loginId, Object now, Object dto) throws Throwable {
		Method setKoshinshaId = ReflectionUtils.findMethod(dto.getClass(), "setKoshinshaId", String.class);
		if (setKoshinshaId != null) {
			setKoshinshaId.invoke(dto, loginId);
		}
		Method setKoshinDatetime = ReflectionUtils.findMethod(dto.getClass(), "setKoshinDatetime", Date.class);
		if (setKoshinDatetime != null) {
			setKoshinDatetime.invoke(dto, now);
		}
	}
}

```
社内勉強会の資料をChatGPTとMarp for VS Codeで作成してみた

## 背景

Docker初心者向けにdockerの勉強会をする機会があり、
良い感じの資料を探す時間も作成する時間もあまりとれそうになかったのでChatGPTに手伝ってもらいました。
というか作ってもらいました。

2023/7/10追記：
python-pptxというライブラリを後から知り、python-pptxを使って資料作成してください、とChatGPTに命令すればパワポを出力してくれるpythonコードを生成してくれるのでそっちのほうがよかったかも。。。


## 概要

ChatGPTにどんな資料を作成したいか説明し、
提案された目次に沿って資料を作成してもらいました。
また、[Marp for VS Code](https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode)で使用できるコードに変換した形式で出力してもらいました。


以下、具体的な作業を説明します。

## ChatGPT

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896507/dedea86c-7b9a-d1d7-69cd-6491506fb3a3.png)

目次はいい感じだなと思ったので、
あとはひたすら依頼し順番にページを作成してもらいます。
(無料版？だと出力に文字数制限があると思ったので分割して命令してます。)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896507/994bbd1d-b566-1aa7-9807-4e4b6d9dc8f0.png)


自分の命令の仕方が悪かったみたいで以下のように余計なやり取りが発生してしまった。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896507/8c5dddf8-6d4d-20c6-65f9-6d71da50a714.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896507/812a9e8b-e617-c195-e6a1-5082eaa4963f.png)

あとはひたすら目次に沿ってページを作成を命令。



以下のように、デモで使えそうな具体例もしっかり作成してくれました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896507/d7fcd813-16b8-927f-70ce-697247d4ec7c.png)



## VS Code
- 以下の拡張機能をインストール
- .mdファイルを作成
- ChatGPTで出力された内容をコピペ
- 資料完成！！


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896507/ac9c192c-5776-bc8e-bf41-9f20f741077c.png)

ちなみに、右上の三角マークをクリックすればパワポやpdfで出力できます。
しかし、出力されたパワポは編集できない。残念。


## 最後に
資料作成の前提条件をもう少し詳細に記載することで、無駄なやり取りを省けたかなと思い反省。
ChatGPTを使いこなす練習や勉強も必要。

プラグインを使用しない限り、テキストの出力のみなので図の作成は以下のような感じになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/896507/8e88b299-0d4c-4402-2ca7-19dbd6cb2b19.png)

(今回は結局VS Codeに[Draw.io](https://marketplace.visualstudio.com/items?itemName=hediet.vscode-drawio)インストールして図を作成しました。)

命令の仕方を工夫すればもっと良い図を作成してくれそうだが、
プラグインを使うことでできることの幅がもっと広がりそう。
日時表記のオフセットの意味

# はじめに

DBなどでよく見かける「**2004-04-01T12:00+09:00**」といった表記の「**+09:00**」の部分が何を意味しているのか、について備忘録を残します。

# 前提

タイムゾーンについてはすでに知識があるとします。

# 本題

結論から言うと、「+09:00」は「UTCからの時間的なずれ」を意味しています。

つまり、「**2004-04-01T12:00+09:00**」を例に取ると

**UTC**(**2004-04-01 3:00**)に9時間プラス(+09:00)すると、**Asia/Tokyo**(**2004-04-01 12:00**)になる

ということなんですね。

# さいごに

オフセットの部分(+09:00)をはぶいた日時がローカルタイム(Asia/Tokyoなど)を表している、と整理しておくとシンプルでよいかもしれません。

# 参考

- [RFC3339#section-4.2](https://datatracker.ietf.org/doc/html/rfc3339#section-4.2)
Pythonで書く「アルゴリズムとデータ構造」　11_挿入ソート

コーディングテスト対策として、「アルゴリズムとデータ構造」という本を実践してます。
自分自身の備忘のために、pythonコードとメモを載せてます。

# pythonコード
~~~python
#数値の個数
N_input = int( input() )

# N個の数値をリストに格納
A_input = list( map( int, input().split(' ') ) )

# 挿入ソート関数の定義
def insertionSort(A,N):
    for i in range(N):
        v = A[i]
        # 対象要素よりも左側にある要素
        j = i - 1
        # 大きな値を抽出する
        while (j >= 0 and v < A[j]):
            # １つずつずらす
            A[ j+1 ] = A[ j ]
            j = j - 1
        A[ j+1 ] = v
        print(' '.join( map( str, A) ) )

insertionSort(A_input, N_input)
~~~

# 補足
入力・出力は決まった形があるので、コピペで対応。
RSpecでモデルオブジェクトが作成されない

## はじめに

RSpecを回した時だけモデルオブジェクトが作成されない問題が発生し、
ただただ凡ミスですがなかなか気づかず時間を溶かしてしまったため自戒の念を込めて・・・

## 概要
- 論理削除のため"discard"を使用
- RSpecでダミーデータを作成するため、FactoryBotを使用
- `let(:user)　{FactoryBot.create(:user)}`のようにテストデータを定義

## 発生した問題
デバッグしuserを確認するとオブジェクトは作られているのに、
User.firstなどで参照した際に空となっているため期待値を得られない。

## 原因
結論、**FactoryBotのdiscarded_atに初期値を入れてしまっていた**ことが原因と思われます。

```ruby
# spec/factories/users.rb

FactoryBot.define do
  factory :user do
    nickname              {"test"}
    email                 {"test@gmail.com"}
    password              {"12345678"}
    password_confirmation {"12345678"}
    discarded_at {"2023-07-01 03:12:01"} # 問題の箇所
  end
end
```

> 修正後

```ruby
# spec/factories/users.rb

FactoryBot.define do
  factory :user do
    nickname              {"test"}
    email                 {"test@gmail.com"}
    password              {"12345678"}
    password_confirmation {"12345678"}
    discarded_at {nil} # nilに修正
  end
end
```

これでモデルオブジェクトが正常に保存され参照できるようになったの、
テストが期待通り通るようになりました。


## 最後に
letで定義する際に`discarded_at`をnilにしても解決すると思いますが、
そもそも`discarded_at`に初期値を持たせること自体普通ではないので、
`nil`にするのが正解だと思います。

めちゃくちゃ凡ミスだった。反省。
githubのソースをeclipseにインポートメモ

毎回Zip落としてからインポートが面倒だったので、直接連携するようにしましたが、特別開発する訳ではないならZipからの方が早いです

### インポート
ファイル → インポート → Git → Gitからプロジェクト
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2713217/007db482-0f8c-025c-a730-f68fcb01da51.png)

クローンURIを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2713217/7e45cd0a-384d-b132-40d1-0358e2f9fcda.png)

githubでプロジェクトを開き、画像の箇所からURLをコピー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2713217/4bdfeb28-4fb7-2aa2-ea12-7a5ee055401b.png)

URI欄に貼り付け
※公式のpublicリポジトリなので認証不要
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2713217/b4d555d6-388e-de5f-b7ce-1d0b708270c6.png)

参照するだけなので、最新のソースだけ選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2713217/1e63214e-0cc8-e0bd-6c1d-219a3bf85898.png)

ディレクトリーの初期設定がユーザーディレクトリになってるので注意
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2713217/8c9b8abe-bc59-dcad-7f14-1e796866e07e.png)

一般的なプロジェクトとしてインポート、完了
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2713217/46e2ca13-14e8-4d15-cf7d-c70ef2c95e0c.png)


---
### インポートしたプロジェクト内の一部プロジェクトをインポート
サンプルだけ動かしたいので、一部だけインポート
※gitコマンドを使うと一発でこれができるそうです

ファイル → ファイル・システムからプロジェクトを開くを選択、先ほどインポートしたプロジェクトを選択、欲しいプロジェクトのみをチェック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2713217/fcc88623-6fd9-b977-685d-e27d929284cc.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2713217/60114b49-a129-682d-9efb-2294743d72a3.png)

~~Zipから抜き取ったほうが早い~~
クロスオリジン間でCookieを共有する


## 概要
構成はNuxt.jsとRailsのAPIモード。

ローカルでは問題なかったのですが、
STGと本番環境にあげた際にクロスオリジン間でCookiesの保存ができなかった経験があり、
色々と設定に苦しんだので備忘録としてまとめます。


### この記事で話すこと
- クロスオリジン間でのCookieを共有するための設定方法

### この記事で話さないこと
- クロスオリジンとは何か
- gem 'rack-cors'によるCORSの設定


## 本題
### 実現したかったこと
ActionCable使って特定のユーザーに配信を行いたく、
以下のようにユーザーの識別のためにランダムな文字列を発行しcookieに保存したかった。

```ruby
# 例　※実際の実装内容とは異なります
def set_code
  # cookieを見て識別子が保存されていなければ発行
  cookies[:user_code] ||= SecureRandom.hex
end
```
が、毎回保存できておらず識別子が生成されてしまっていた。

### 解決方法
バックエンドとフロントエンドの両方で諸々の設定をしました。
まずはバックエンドのRailsから。

#### Cookieを使うための準備
RailsのAPIモードの場合、このままではcookieが使えないので設定をする必要があります。
```application_controller.rb
class ApplicationController < ActionController::API
    include ActionController::Cookies # これを追加する
```

次に、RailsのAPIモードではCookieを処理するミドルウェアがないため、
application.rbに次の設定を追加します。

```application.rb
module App
  class Application < Rails::Application
    # ・・・
    config.middleware.use ActionDispatch::Cookies
    config.action_dispatch.cookies_same_site_protection = :none
    # ・・・
  end
end
```
※cookies_same_site_protectionはRails6.1で追加された設定のようです。
参考：https://qiita.com/SoarTec-lab/items/10280dbea1195bf21b3c

#### CORSの設定
現状の設定ではフロントエンドとバックエンドのオリジンが異なる場合に
ブラウザに保存ができないので、次はCORSの設定をします。

許可したいオリジンを指定するのに加え、
`credentials: true`の設定が必要となります。

これでクロスオリジン間でcookieが使用できます。
```cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins "http://localhost:8080" # ここに許可するオリジンの指定。正規表現も使えるので、可能であればそれで指定する方がベターだと思います。

    resource "*",
      headers: :any,
      credentials: true, # これが必要！！！
      methods: [:get, :post, :options, :delete, :put, :patch]
  end
end
```

#### CookieのSecure属性を追加
SameSite属性がNoneの場合、
Secure属性も付与しなければいけないため次のようにします。
（※開発環境ではなくても動きました）

```diff_ruby
def set_code
  # cookieを見て識別子が保存されていなければ発行
- cookies[:user_code] ||= SecureRandom.hex
+ cookies[:user_code] ||= {value: SecureRandom.hex, http_only: true, secure: true}
end
```

#### Nuxt.jsの設定
フロントエンドはNuxt.jsを使用していたため、
次のように設定を追加しました。

`credentials: true`を追加することで、リクエストヘッダーの`withCredentials`をtrueにします。
参考：https://axios.nuxtjs.org/options/#credentials

ドメインにcookieを設定する際にこちらが必要となるようです。
> 異なるドメインからの XMLHttpRequest のレスポンスは、リクエストを行う前に withCredentials を true に設定しない限り、自身のドメインの Cookie 値を設定することができません。
https://developer.mozilla.org/ja/docs/Web/API/XMLHttpRequest/withCredentials

```nuxt.config.js
// ・・・
axios: {
    // ・・・
    credentials: true
  },
// ・・・
```

## 最後に
これだけ諸々の設定をしてようやく望み通りの動作が実現できました。
CORSやCookieのいい勉強になりました。

もし間違っている点や、
もっとこうした方がいいよなどあればコメント頂けますと幸いです。


## 参考
https://qiita.com/chain792/items/4783d67e5ab02d569517

https://qiita.com/yuki_0920/items/50d4618508463cc24a6f

https://blog.cloud-acct.com/posts/u-rails-nuxt-cross-origin-cookies/
Qiita CLIでQiitaの執筆体験をより便利にするTips


## この記事は何
昨日Qiita CLIをベータ版として公開しました！

https://github.com/increments/qiita-cli

Qiita CLI とは、手元の環境で記事の執筆・プレビュー・投稿ができるツールです。 Qiita CLIを使うことで、エディタなどを使って記事の執筆・投稿がしやすくなります。

この記事は、Qiita CLIを使ってQiitaの記事執筆をするときに便利なTipsを紹介します。

## Copilotを用いて記事を執筆する
Qiita CLIを用いれば、記事の執筆をエディタで行うことができます。また、記事のデータはMarkdown形式で保存されるため、エディタの機能やプラグイン、ライブラリなどを用いて記事の執筆を行うことができます。

Markdownの執筆にも、Copilotは便利に活用できます。
実は、この文章もCopilotを用いて執筆しています。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158501/c3dab224-4c9f-05fe-c449-428a05b22783.gif)

なお、Copilot.vimでMarkdownの補完を行えるようにするTipsも以前Qiitaに投稿しています。

https://qiita.com/getty104/items/f4c1ed9b376825b41779

## markdownlintを用いて記事のLint・フォーマットを行う
Qiita CLIを用いると、編集した記事ファイルは一括でQiitaに投稿・更新することができます。そのため、[markdownlint](https://github.com/igorshubovych/markdownlint-cli)などでファイルのフォーマットをかけても、一括で記事の更新を行うことが可能です。

一括で変更した記事の反映を行う場合は`qiita publish --all`というコマンドか、GitHub Actionsの設定をすることで実現できます。

具体的な利用方法はREADMEの以下の部分にまとまっています。

- [記事の投稿・更新](https://github.com/increments/qiita-cli#%E8%A8%98%E4%BA%8B%E3%81%AE%E6%8A%95%E7%A8%BF%E6%9B%B4%E6%96%B0)
- [GitHub で記事を管理する](https://github.com/increments/qiita-cli#github-%E3%81%A7%E8%A8%98%E4%BA%8B%E3%82%92%E7%AE%A1%E7%90%86%E3%81%99%E3%82%8B)

markdownlintを導入して記事ファイルを修正する方法は、以下の記事が参考になります。

https://qiita.com/fussy113/items/1537dfacfea61d0a2564

## GitHub上でレビューを行う
Qiita CLIとgitを用いれば、記事の執筆をGitHub上でレビューすることができます。
また、GitHub Actionsを用いればレビュー完了後、マージをすることでそのままQiitaに反映することも可能です。
GitHub Actionsの設定方法は前項と同じく以下にまとまっています。

- [GitHub で記事を管理する](https://github.com/increments/qiita-cli#github-%E3%81%A7%E8%A8%98%E4%BA%8B%E3%82%92%E7%AE%A1%E7%90%86%E3%81%99%E3%82%8B)


## 最後に
Qiita CLIはまだベータ版です。不具合や使いにくいところもあると思います。
もし、不具合や改善点などあったら、[Qiita Discussions](https://github.com/increments/qiita-discussions/discussions)でフィードバックをいただけると嬉しいです！

https://github.com/increments/qiita-discussions/discussions
authenticate_user!について(Rails)

ポートフォリオ制作でauthenticate_user!を使用した為、アウトプットします。

authenticate_user!とは？
authenticate_user!の使い方(例)
オプション(補足)

## authenticate_user!とは？
* ユーザーの認証（ログイン）を確認するためのもの。
* deviseのメソッドである。
* コントローラ上で定義するものである。

以下にauthenticate_user!の使用例を記載します。

## authenticate_user!の使用例(その１)

```ruby:XXX_controller.rb
before_action :authenticate_user!
```
基本的にはbefore_actionと合わせて使用します。
controller.rbの最上部に記述することで
全てのアクションの前に、ユーザーがログインしているかどうか確認する。

## authenticate_user!の使用例(その2)

```ruby:XXX_controller.rb
before_action :authenticate_user!, only: [:index, :show]
```
`only:`は特定のアクションにのみ処理を実行したい時に使用します。
その２ではindexとshowにのみ適応させています。
indexとshowのみに適用したい場合は、only: [:index, :show]をつける。
その他にもオプションがあるので適切なものを選んでください。

## オプション(補足)
オプションを使用することで様々な条件下で使用出来る。

|    内容    |      意味      | 
|:-----------:|:---------------:|
|    only     | 実行するアクション  |
|   except    | 実行しないアクション　| 
|     if      | 実行する条件　     |
|   unless    | 実行しない条件    |
iOS + Firebase のAppleAuth で、Testflightだと大丈夫なのに審査でダメだと言われる時の対処法

## 概要

個人開発でモバイルアプリを作成している時、
最後の審査まで辿り着いてから、
たくさんいろんなデバッグが発生するのはもうしょうがないことだと思いますが、
あと少しのところが一番大変なので、できるだけ審査をスパッと通過したいですよね。


今回はたぶん良くあるかと思いますが、
モバイルアプリ(iOS)にApple ID によるAuthを実装し、
それが動かないと審査で言われてしまった時の（一つ考えられる）対処法について備忘録的に書いておきます。


## 症状

TestFlightでは問題なくAppleIDを使用したログインはできていましたが、
審査で不可という結果が通知され、

```
2.1.0 Performance: App Completeness
```

と言われてしました。


## 解決策

ここや
https://firebase.google.com/docs/auth/ios/phone-auth?hl=ja&authuser=0&_gl=1*n8dky1*_ga*NzU3NDA5OTg5LjE2ODgxODg1NTk.*_ga_CW55HF8NVT*MTY4ODE4ODU1OC4xNi4xLjE2ODgxOTA1MDYuMC4wLjA.#start-receiving-silent-notifications

ここにあるように、
https://developer.apple.com/jp/help/account/manage-keys/create-a-private-key/

APN鍵を Apple developer Console から作成し、
Firebase のプロジェクト設定　 --> Clound Messaging --> Apple アプリの構成 --> APN認証鍵
のところから登録しておく必要があります。
VPC Latticeについて今更ながら

# ■概要
気になっていたVPC Latticeについて調べました。
4月にGAとなっていて、かなり今更感ありますが折角なので感じた事を書き残します。

# ■VPC Latticeとは？

公式の中では以下のような説明があります。

> Q: Amazon VPC Lattice とは何ですか?
> Amazon VPC Lattice は、事前のネットワーキングの専門知識がなくても、サービス間の通信を一貫して接続、保護、モニタリングできるようにするアプリケーションレイヤーのネットワーキングサービスです。VPC Lattice を使用すると、基盤となるコンピューティングタイプにかかわらず、ネットワークアクセス、トラフィック管理、およびネットワークモニタリングを設定して、VPC やアカウント全体で一貫したサービス間通信を実現できます。

なるほどよくわからんという事で色々調べてみた所以下のようです。

・VPC向けのリバースプロキシ
・別VPC間でも通信可能（80と443に限る）
・デフォルトで証明書が用意されており、接続の保護とモニタリングも可能。
・EC2インスタンス（VPC:A） → ALB（VPC:B）といった通信が簡易的に設定できる。

Latticeサービスの構成としては、ターゲットグループやリスナーの設定が出来る点などALBの体系イメージに近しいと感じました。

##### EC2インスタンス（VPC:A） → ALB（VPC:B）のイメージ↓ 

![test2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954355/e7ec5574-a168-ba00-8839-50f09913c677.png)

# ■嬉しいこと

・設定がとても簡単。
ALBと同じような工程で設定を完了する事が可能です。
具体的には作成したLatticeサービスのDomain nameを接続先で設定するのみ。
別途証明書を準備する手間がない分、こちらの方が簡単かもしれません。

・VPCのCIDRが重複していても問題ない。
接続の際はドメインネームを指定する為、CIDRの重複問題をクリアできます。
基本的にCIDRが重複する事はないかもしれませんが…。

# ■少しさわってみる

VPCのトップページよりLatticeを確認できます。

![Lattice1_20230630044728.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954355/926f08cd-6d49-66fd-102c-47bfdf93d712.png)

作成に必要な項目としては、サービス、サービスネットワーク、ターゲットグループの3項目です。
構築さわってみたは記事がたくさんあったのでこの辺りは割愛させてください…

![Lattice_TG_20230630050141.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954355/0b2f96b5-1fb6-da06-34a8-e9bf086f871f.png)

ALBのようにターゲットグループも作成する必要があります。
ターゲットにできる項目としては、インスタンス、IP、Lambda、ALBが指定可能です。

# ■最後に

今更ながらでしたが、まださわってない人の知見になれば。

# ■参考
Amazon VPC Lattice のよくある質問
https://aws.amazon.com/jp/vpc/lattice/faqs/
Slackに新機能「canvas」が出現！ ConfluenceやNotionの併用いらずで超便利🎉

なんか最近、Slack使ってたら「canvas」ってのが出現しているのに気付いた方も多いのではないでしょうか？
![スクリーンショット 2023-07-01 14.32.46a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/01415138-ea77-5dd7-560d-c1e916fa97b1.png)

これはSlackの新機能で、先月ごろからワークスペースごとに順次ロールアウトされているようです。かなり便利な機能だったので紹介したいと思います。



# canvasとは？

チーム内での情報共有に便利なSlackの新機能です。

https://slack.com/intl/ja-jp/features/canvas

実は色々な機能があります。
- ドキュメント管理（TeamsでいうWiki機能のようなもの）
- 業務を自動化できるワークフローの作成
- JiraやFigmaなど外部アプリと統合してSlack内で操作を完結

中でも一番手軽に使えて、多くの人がすぐ活用できるのが一番上の「ドキュメント管理」機能だと思うので、サクッと試して画面イメージを紹介します。



# とりあえず使ってみよう！

サイドバーから「canvas」を開き、「canvasを作成する」を押してみます。
![スクリーンショット 2023-07-01 14.38.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/fe97f019-104a-00e7-b6a6-40b09f014aec.png)

するとウィンドウが開き、メモを編集できます。
マークダウン形式で記載できて画像の添付もできます！
![スクリーンショット 2023-07-01 14.44.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/85f6b2a9-ec86-47a8-df6b-5c36b952ddcf.png)

書いたメモは自動保存されているのですが、明示的に権限付与するまでは自分しか見られないようになっています。

右上の「共有」ボタンを押すと権限付与のポップアップが開きます。
![スクリーンショット 2023-07-01 14.48.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/43aaebf7-8e26-3709-aceb-80507f13504a.png)

共有先にチャンネルを指定すると、権限（編集可能 or 閲覧可能）を選んでメッセージとともにチャンネルへ共有することができます。
![スクリーンショット 2023-07-01 14.51.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/20cdbc0c-4570-5656-11f1-fb3b9aad63a3.png)

共有先には特定のメンバーのみを指定することもできます。この場合はチャンネルではなくDMで選んだメンバーへメッセージとともにcanvasを共有できるようです。
![スクリーンショット 2023-07-01 14.53.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/e83b806b-5f0e-b064-00a9-bfc902cbeb15.png)

個人宛て共有を試してみると、こんな感じでDMが自動送信されました！
![スクリーンショット 2023-07-01 14.55.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/b6bba3c5-4df6-8370-dab0-886109f9aabf.png)


# まとめ

これまではSlackのチャンネルでメンバーと「フロー情報」をやり取りしながら、決まったことを「ストック情報」としてConfluenceやNotion等を併用して管理している人も多かったと思いますが、このcanvasを使えばSlackアプリ内である程度の仕事が完結しそうですね！

別途メモツールを使っていると、Slackメンバー間で権限差異があったりして共有が面倒なケースもありそうですが、canvasの場合はその点シンプルに共有しやすくなりそうです。
Railsチュートリアル１章のまとめ

# 前提
GitHubのcodespaceを使用して
Railsチュートリアルの学習を始めました。
codespaceを使用する場合だと、1.3.2 rails serverから進めることができます。
（用意されているcodespaceでgemのインストール等がされているのにインストールの手順をやってしまいエラーが出たりして無駄な時間を食いました、、、）
１章ではcodespaceの準備や
renderへのデプロイで詰まったのでそちらについて共有します！

# 目次
[codespaceの準備で詰まった](#codespaceの準備で詰まった)
[renderへのデプロイで詰まった](#renderへのデプロイで詰まった)
[感想](#感想)

# codespaceの準備で詰まった
・Railsチュートリアルで用意されたcodespaceのURL
https://github.com/yasslab/codespaces-railstutorial

動画ではcodespaceがどこにあるのかが説明されておらず
探すのに時間がかかりました、、、、
どう探したのかというと
1.2.1：開発環境 に載せられている解説動画の概要欄で
📜 note記事で見る → https://note.com/yasslab/n/n427c56266295
と記載されているのでこちらを開きました。
飛んだ先のページに
"Railsチュートリアル用テンプレートが公開され、"
とリンクがあるのでこちらを開くとチュートリアル用のcodespaceが確認できました。

実行方法などは解説動画で説明されており
そちらの通りに進めると問題なく環境構築できました。
一回閉じたcodespaceはcodespaceのページで , を押したら
再実行できます。
・参考サイト
https://docs.github.com/ja/codespaces/developing-in-codespaces/opening-an-existing-codespace

# renderへのデプロイで詰まった
1.5 デプロイするで詰まりました、、、
詰まった箇所としてはrenderのリポジトリ作成で
keyにRAILS_MASTER_KEY、Valueにconfig/master.keyを設定する部分です。
というのもmaster.keyファイルが自分のリポジトリに存在しなかったためです。

○対応方法
master.keyファイルを自分で作成して、
そちらの内容をrenderのValueに記載しました。

○手順
sudo EDITOR="vi" rails credentials:editを実行してmaster.keyファイルを作成します。
※credentials.yml.encも一緒に作り直す必要があるようなので
　credentials.yml.encを削除して実行します。
↓
上のコマンドで作られたmaster.keyの中身を
sudo vi config/master.key　と実行して確認します。
↓
credentials.yml.encも作り直されたので
そちらをgitにコミットします。
そしてmaster.keyの値をrenderのValueに記載したらデプロイできました！

参考サイト
https://qiita.com/naokit-dev/items/5e09b2fb4b64a29712e4

# 感想
Railsチュートリアルの学習を始めましたが
１章でも意外にすんなり進められなかったです。
逐次調べて疑問点は解消して２章からも進めていきたいと思います。
Windowsでストレージから一時ファイル削除（ディスクのクリーンアップなど）

# ディスクのクリーンアップ

この画面でディスク上で右クリック → 『プロパティ』 。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/40a22c7f-8b0d-0822-069c-44a6626ac8c6.png)

ディスクのクリーンアップ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/f4783083-1242-e5ff-3723-190040be9176.png)

消したいファイルにチェック入れて『OK』。
『ごみ箱』の中身を消していいかどうか、などに注意。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/2589c8e2-ac25-543a-b375-2811b093b700.png)


# エクスプローラーで直接一時ファイル格納フォルダーへ

エクスプローラーのバーに下記入力すると一時ファイルのフォルダーにすぐ行ける。

```
%temp%
```

# 参考サイトさん

https://jp.minitool.com/partition-disk/disk-cleanup-wont-open.html

# バージョン

Windows 10 Pro 22H2 19045.3155
コルーチンとは

フレームをまたいで処理を実行したいときに使用する。
→「〇〇するまで待つ」を再現したいときに便利。

たとえば、
・５秒かけて画像をフェードインする
→５秒経過するまで待つ

・Enterキーが押されたら次のゲームステータスに移行する
→Enterキーが押されるまで待つ

〇Unityにおける使用例

    private float seconds = 0.0f;

    void Start()
    {
        StartCoroutine(TimeCount());//コルーチンの開始
    }
 
    private IEnumerator TimeCount()//コルーチンで行う処理の定義
    {
        while (true)//無限ループ
        {
            yield return new WaitForSeconds(5.0f);//５秒経過するまで待つ
            seconds += 5.0f;
            Debug.Log(seconds + "秒経過");
        }
    }

出力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954716/8c419ef9-175b-9876-750a-aaeae419022a.png)


https://docs.unity3d.com/ja/2018.4/Manual/Coroutines.html
【Python】素数の出力Generator使用

今回の記事は素数をGeneratorを使用して出力するプログラムを作成しました。
是非、勉強の参考にしてください。

## コード

```python
from typing import Generator

def primlist(number):
    n_list = {}
    for i in range(2, number + 1):
        is_prime = n_list.get(i)
        if is_prime is False: # Falseの場合は次の処理に行く
            continue
        yield i

        n_list[i] = True
        for j in range(i * 2, number + 1, i):
            n_list[j] = False # 2倍の数はFalseにしていく

n = int(input('数字入力')) # 入力を受け取る。
print(f'素数リスト->{[i for i in primlist(n)]}')
```

実行すると以下のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2759758/5a5d29cd-1b07-ce4e-c8f7-7502a84512aa.png)

for文で書くよりも圧倒的に出力されるスピードは速いです。
是非参考にしてください。

以上になります。
Google Domains売却に伴う値上がりに備えるための移行先料金比較

# はじめに

[Googleドメイン売却!? 良さげな移行先サービスを比較してみた](https://qiita.com/minorun365/items/790635f211a14ad6b4db) という記事でGoogle Domains売却を知りました。

https://qiita.com/minorun365/items/790635f211a14ad6b4db

移行先を料金面からだけ比較してみたいと思います。ここでは自分が使っている .dev と .net ドメインだけです。

# 料金比較サイト

まずはこちらを見てください。

https://tld-list.com/

下の表を書くために調べていて見つけました。まあやっぱり普通に存在しますよね。


# 料金比較

上に書いたサイトで調べば事足りますが、せっかくなので載せておきます。

1USD = 150円で換算しています。

| レジストラ | .dev移管料 | .dev 登録料 | .dev 更新料 | .net 移管料 | .net 登録料 | .net 更新料 |
|:--|:-:|:-:|:-:|:--:|:--:|:--:|
| お名前.com  | 2,718  | 2,718  | 2,718 | 1,012 | (不明)  | 1,628
| AWS Route 53 | -  | -  | - | 1,650   | 1,650  | 1,650  |
| Cloudflare Registrar | - | - | - | (不明) | 1,515 | 1,515 | 
| ムームードメイン | - | - | - | 1,628 | 1,628 | 1,590 |
| GoDaddy | (不明) | 2,919 | 2,919 | (不明) | 3,298 | 3,298 |
| porkbun | 1,630 | 1,630 | 1,630 | 1,772 | 1,772 | 1,772 |
| さくらインターネット | - | - | - | 2,708 | 2,708 | 2,708 |


Cloudflare考えていたんですけれど、.dev がない。
どうしようかなー。


# 料金表リンク

* お名前.com https://www.onamae.com/service/d-price/
* AWS Route 53 https://aws.amazon.com/jp/route53/pricing/
* ムームードメイン https://muumuu-domain.com/domain/price
* porkbun https://porkbun.com/products/domains
* さくらインターネット https://domain.sakura.ad.jp/specification/