OmniAICreator/Qiita-1.07M huggingface dataset:
[Next.js 13] ビルド時に特定のカスタムデータ属性を表示させない方法

## はじめに
テスト用に設定しているdata-testidを本番環境で表示させない方法を調査した結果、便利な設定を見つけました。

## TL;DR
Next.js Config内のcompiler.reactRemovePropertiesを設定することで、
data-testidのようなカスタムデータ属性を削除することができます。

```typescript
// next.config.js
const nextConfig = {
// ...その他の設定
    compiler: {
      reactRemoveProperties: {
        properties: ['^data-testid$'],
      },
    },
}
```

## 本番環境でのみ有効化する場合
compilerの設定が開発環境に作用してしまっていたので、
compilerごと条件分岐での有効化をさせています。

```typescript
// next.config.js
const nextConfig = {
// ...その他の設定
...(process.env.NODE_ENV === 'production' && {
    compiler: {
      reactRemoveProperties: {
        properties: ['^data-testid$'],
      },
    },
  }),
```

## 参考文献
https://www.reddit.com/r/nextjs/comments/xqidvy/configure_nextjs_to_remove_datatest_attributes/

https://nextjs.org/docs/advanced-features/compiler#remove-react-properties
ファイル系アプリを作る際の指南書

## アプリのホームディレクトリを取得

/var/mobile/Containers/Data/Application/XXXX/Documents/は、アプリケーションのドキュメントディレクトリのパスであり、XXXXはアプリケーションのランダムな識別子です。

このパスを取得するには、FileManagerのurl(for:in:appropriateFor:create:)メソッドを使用します。具体的には、以下のように書くことができます。

```swift
let fileManager = FileManager.default
if let documentsDirectory = try? fileManager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) {
    // documentsDirectoryは"/var/mobile/Containers/Data/Application/XXXX/Documents/"になります
} else {
    // ドキュメントディレクトリが見つからなかった場合の処理
}
```





上記のコードでは、FileManagerのurl(for:in:appropriateFor:create:)メソッドを使用して、アプリケーションのドキュメントディレクトリのURLを取得しています。in:パラメーターに.userDomainMaskを指定することで、ユーザーディレクトリ内のアプリケーションディレクトリを検索します。appropriateFor:パラメーターにnilを指定することで、アプリケーションディレクトリのURLを取得することができます。create:パラメーターにfalseを指定することで、ディレクトリが存在しない場合は作成しないようにしています。

このコードを実行すると、documentsDirectoryに"/var/mobile/Containers/Data/Application/XXXX/Documents/"のようなURLが格納されます。




## ファイル一覧を取得する際に、ドキュメントディレクトリからの相対パスで取得



.producesRelativePathURLsオプションを指定すると、contentsOfDirectory(at:includingPropertiesForKeys:options:)メソッドが返すファイルのURLが、相対パスで表現された形式で返されます。

具体的には、指定されたディレクトリからの相対パスでファイルのURLが生成されます。例えば、Documentsフォルダー内のMyAppフォルダー内のDataフォルダー内のFile1.txtファイルのURLを、相対パスで生成した場合、以下のような形式になります。

```swift
file:///MyApp/Data/File1.txt
```

一方、.producesRelativePathURLsオプションを指定しなかった場合、ファイルのURLは絶対パスで表現された形式で返されます。例えば、Documentsフォルダー内のMyAppフォルダー内のDataフォルダー内のFile1.txtファイルのURLを、絶対パスで生成した場合、以下のような形式になります。

```swift
file:///var/mobile/Containers/Data/Application/XXXX/Documents/MyApp/Data/File1.txt
```

ここで、XXXXはアプリケーションのランダムな識別子です。.producesRelativePathURLsオプションを指定することで、ファイルのURLがよりシンプルで簡潔な形式で取得できるため、アプリケーション開発において便利なオプションの1つとなっています。
【Swift】「〇日前」の表示を作成する

# はじめに
SNSなどでよくみる「〇日前」のような表示をSwiftで作成してみようと思います。

# 実装
```swift
extension Date {
    static let dateFormatter: DateFormatter = {
        let dateFormatter = DateFormatter()
        dateFormatter.dateStyle = .short
        dateFormatter.timeStyle = .none
        dateFormatter.locale = Locale(identifier: "ja_JP")
        return dateFormatter
    }()

    var elapsedTimeText: String {
        let components = Calendar.current.dateComponents([.year, .month, .weekOfYear, .day, .hour, .minute, .second], from: self, to: Date())

        if let year = components.year, year > 0 {
            return Date.dateFormatter.string(from: self)
        } else if let month = components.month, month > 0 {
            return "\(month)ヶ月前"
        } else if let week = components.weekOfYear, week > 0 {
            return "\(week)週間前"
        } else if let day = components.day, day > 0 {
            return "\(day)日前"
        } else if let hour = components.hour, hour > 0 {
            return "\(hour)時間前"
        } else if let minute = components.minute, minute > 0 {
            return "\(minute)分前"
        } else if let second = components.second, second > 0 {
            return "\(second)秒前"
        } else {
            return "たった今"
        }
    }
}
```

# テストコード
```swift
    func testElapsedTimeText() {
        let now = Date()

        // 1年以上前の場合
        let oneYearAgo = Calendar.current.date(byAdding: .year, value: -1, to: now)!
        XCTAssertEqual(oneYearAgo.elapsedTimeText, Date.dateFormatter.string(from: oneYearAgo))

        // 11ヶ月前の場合
        let elevenMonthsAgo = Calendar.current.date(byAdding: .month, value: -11, to: now)!
        XCTAssertEqual(elevenMonthsAgo.elapsedTimeText, "11ヶ月前")

        // 1ヶ月前の場合
        let oneMonthAgo = Calendar.current.date(byAdding: .month, value: -1, to: now)!
        XCTAssertEqual(oneMonthAgo.elapsedTimeText, "1ヶ月前")

        // 2週間前の場合
        let twoWeeksAgo = Calendar.current.date(byAdding: .day, value: -14, to: now)!
        XCTAssertEqual(twoWeeksAgo.elapsedTimeText, "2週間前")

        // 1日前の場合
        let oneDayAgo = Calendar.current.date(byAdding: .day, value: -1, to: now)!
        XCTAssertEqual(oneDayAgo.elapsedTimeText, "1日前")

        // 2時間前の場合
        let twoHoursAgo = Calendar.current.date(byAdding: .hour, value: -2, to: now)!
        XCTAssertEqual(twoHoursAgo.elapsedTimeText, "2時間前")

        // 30分前の場合
        let thirtyMinutesAgo = Calendar.current.date(byAdding: .minute, value: -30, to: now)!
        XCTAssertEqual(thirtyMinutesAgo.elapsedTimeText, "30分前")

        // 10秒前の場合
        let tenSecondsAgo = Calendar.current.date(byAdding: .second, value: -10, to: now)!
        XCTAssertEqual(tenSecondsAgo.elapsedTimeText, "10秒前")

        // たった今の場合
        XCTAssertEqual(now.elapsedTimeText, "たった今")
    }
```

# おわり
Dateの扱いは難しいです。
もっとこうしたほうがいいとかありましたらコメントください。。

# 参考記事

https://qiita.com/rinov/items/bff12e9ea1251e895306

https://yamatooo.blog/entry/2021/02/16/083000
Terraform – AWS RDS で使う  engine_version の文字列を得る

# 問題


```terraform
resource "aws_rds_cluster" "default" {
  engine_version  = "xxx"
}
```
新規作成フォームはセレクトボックス形式で具体的な文字列が分からない

<img width="950" alt="image" src="https://user-images.githubusercontent.com/13635059/227528542-cdcec5f3-3bf0-46db-bfa7-9b54622e89d9.png">

この設定の文字列を知りたい


# 解決

いちどDBを作成すると、Webのコンソールから確認できるようだ

![image](https://user-images.githubusercontent.com/13635059/227528339-12d8a2b9-d76c-4397-90a7-6f0e896454e7.png)

この中の「エンジンバージョン」に書かれているのがそれ

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ


# Twitter

https://twitter.com/YumaInaura
ラベルを自動的に付けたり外したりするGoogle Apps Script

Gmailのインボックスにメールがたまりすぎて、どうにも整理がつかなくなってきたので、Google Apps Scriptを作って自動的にラベルをつけることにした。

私宛に来たと思われるメールを"美山様" OR "美山さん" OR "Dear Toru" OR "Dear Dr. Miyama" OR "美山先生" OR "Prof. Miyama"で検索して、"Miyama"というラベルをつける。"to:my@email.adress"のように検索すると、メーリングリストなども該当するので、そうはしない。これだけなら、Gmailの機能のフィルターでもできるのだが、インボックスから外した(アーカイブした)メールからは、ラベルを取ってくれるのがミソ。これを一定期間(1時間間隔など)にトリガーして自動的にラベルを整理する。

以下がスクリプト。queryやonLabelを変えれば別のラベルもつけることが出来る。
例えば
query='"締め切り" OR "締切" OR "deadline"'
onLabel="Deadline"
など。
プロトタイプはChatGPTに作ってもらったのですぐに出来た。

```
function labelmail() {  
  query='"美山様" OR "美山さん" OR "Dear Toru" OR "Dear Dr. Miyama" OR "美山先生" OR "Prof. Miyama"'
  onLabel="Miyama"
  label(query,onLabel);
}

function label() {
  // ラベルを取得する。なければ作成する。
  var label = GmailApp.getUserLabelByName(onLabel);
  if (!label) {
    label = GmailApp.createLabel(onLabel);
  }

  // query 条件、及びinboxにあり、及びlabelがついていないメールのスレッドを取得する。
  var threads = GmailApp.search(`label:inbox ${query} -label:${onLabel}`);

  // 各スレッドにラベルを付ける。
  for (var i = 0; i < threads.length; i++) {
    label.addToThread(threads[i]);
  } 
　// inboxに無い場合はlabelを外す
  unlabel(onLabel)
}

function unlabel(onLabel) {
  // ラベルを取得する。
  var label = GmailApp.getUserLabelByName(onLabel);

  // ラベルがついているがinboxに無いメールのスレッドを取得する。
  var threads = label.getThreads(0, 100).filter(function(thread) {
    return !thread.isInInbox();
  });

  // 各スレッドからラベルを外す。
  for (var i = 0; i < threads.length; i++) {
    label.removeFromThread(threads[i]);
  } 
}
```
【JavaScript】UTC形式の時刻をJST形式(日本時間)に変換する。

## 使用するAPI
今回は、GitHub APIからJSONを取得します。

## APIのエンドポイント
以下のエンドポイントで、リポジトリ内のプルリクエストの履歴が取得できます。
```
https://api.github.com/repos/GitHubのユーザー名/リポジトリ名/pulls
```

取得結果の一部がこちらです。
```
"created_at": "2023-03-23T08:05:05Z",
```
"created_at"はプルリクエストを作成した時刻で、UTC形式になっています。
こちらのUTC形式のJST形式(日本時間)にしていきます。

## サンプルコード
以下が、形式を変換するコードになります。
```
const url = "https://api.github.com/repos/GitHubのユーザー名/リポジトリ名/pulls"
fetch(url)
  .then(response => response.json())
  .then(data => {
   console.log(data[0].created_at)
   const dataTime = data[0].created_at;
   const dt = new Date(dataTime);
   cosnole.log(dt.toLocaleString());
}
```

5行目で取得できるデータはこちらです。
```
2023-03-23T08:05:05Z
```

6~8行目で変換するとこうなります。
```
2023/3/23 17:05:05
```
このように、JST形式(日本時間)に変換することができました。
簡単にはなりましたが以上になります。
【Rails】Enumで複数選択(multiple: true)を使う時の備忘録

## 概要
Enumで複数選択を初めて使ったときにすぐにやり方がわからなかったので、
今回は記事(Article)モデルに複数選択可のタグ(tags)カラムを追加する例でメモしました。


## 対応
### マイグレーション
Articleモデルにtagsカラムを追加。
`array: true`で配列対応しておくのがポイント。
(通常の文字列カラムだとrailsのコンソールでAticle.first.tagsとか入力して値を参照しようとするとデータがなぜか消えて困った)
```ruby:../db/migrate/add_tags_to_articles.rb
class AddTagsToArticles < ActiveRecord::Migration[6.1]
  def change
    add_column :articles, :tags, :integer, array: true, default: []
  end
end
```

### モデル
Articleモデルにtagsのenumを設定する。
```ruby:../app/models/article.rb
class Article < ApplicationRecord
  extend Enumerize
  # (中略)
  enumerize :tags, in:{
	hobby: 1,
	cooking: 2,
	travel: 3,
  }, multiple: true
  # (中略)
end
```


### ビュー(Slim)
#### 入力フォームでf.selectを使用する場合
tagsを複数選択できるようにselectタグで表示する。
```ruby:../app/views/articles/_form.html.slim
h3.label 記事のタグ
= f.select :tags, Article.tags.options, { include_blank: false }, multiple: true
```

#### 一覧表示などでカンマ区切りを表示する場合
`.texts`で選択内容の配列が取得できるので`.join`を使ってカンマ区切りで結合する。
```ruby:../app/views/articles/_index.html.slim
h3 記事一覧
table
  thead
    tr
      th = タイトル
      th = タグ
  tbody
    - @articles.each do |article|
      tr
        td = article.title
        td = article.tags.texts.join(",")
```
Terraform で プリントでバッグしたい ( Object とか値の中身を確認したい )

こんな風に .tf ファイルで outputすれば良いようだ

```terraform
output "yyy" {
  value = module.mysql_sg
}

output "xxx" {
  value = module.vpc.private_subnets
}
```

そして terraform apply または terraform plan を実行する



# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ


# Twitter

https://twitter.com/YumaInaura
ヤマハのルーターRTX810で設定を外部メモリにコピー・外部メモリから設定をコピーする

## はじめに

私は自宅でヤマハのRTX810というルーターを使っています。以前、RTX1200などを業務で使ったことがあり、ルーター専用機を買うなら今度はヤマハにしようと思い、中古で購入しました。

ヤマハのルーターでは、内部フラッシュROMの設定を外部メモリにコピーする、その逆に外部メモリにある設定を内部フラッシュROMにコピーすることができます。

ルーターが壊れてしまって代替のルーターを買った場合や、初期化をした後に設定の復元をなるべく簡単に行えるようにしておきたいと思ったので、動作確認も兼ねて実施してみました。

## 対応機種、ファームウェア

対応機種は以下の通りで、ファームウェアはすべてのリビジョンが対象です。

RTX1300
RTX1220
RTX830
NVR510
NVR700W
RTX1210
RTX5000
RTX3500
FWX120
RTX810
NVR500
RTX1200
SRT100
RT58i
YSL-V810

## USBホスト機能を有効にする

工場出荷時にはONになっているそうですが、私のRTX810はOFFになっていましたので、ONにしました。

```
# usbhost use on
# show config | grep usb
Searching ...
usbhost use on
```

## USBメモリを接続後、USBホストの状態確認

USBメモリを接続したところ、認識されていることが確認できました。

```
# show status usbhost
Host controller:           Running

usb1
Bus power feed:            ON
Attached device
  Device name:             0x0111 <USB Flash Disk>
  Vendor name:             0x0411 <BUFFALO>
  Maximum transfer rate:   480Mbps(High speed)
  Memory capacity:         1955840 KB
MASS Storage Class Transmit statistics
  Timeout:                 0
  Stalled:                 0
  Canceled:                0
  I/O error:               0
  Unknown:                 0
```

## 内部フラッシュROMの設定ファイル0をUSBメモリにコピーする

```
# copy config 0 usb1:config.txt
```

* 内部フラッシュの設定ファイル0が「config 0」
* USBメモリおよびコピー先のファイル名が「usb1:config.txt」

## USBメモリの取り外し方

外部メモリボタンを2秒間押し続けます。

## 外部メモリの設定ファイルを内部フラッシュROMにコピーする

USBメモリを接続して、外部メモリボタンとダウンロードボタンを同時に3秒間押し続けると、外部メモリに保存されているファームウェアファイル、設定ファイルをルーターの内部フラッシュROMにコピーします。

コピーに成功するとアラームが鳴り、自動的に再起動します。

## 参考

http://www.rtpro.yamaha.co.jp/RT/docs/external-memory/
テキストファイル読み込みのすゝめ 

textファイルはリスト化して読み込み、リストを編集して、リストを書き出し
複数ファイルを扱うなら多次元リスト化する

```python
# textファイルを読み込んでリスト化
file = "import.txt"
with open(file,mode="r",encoding="utf8") as f:
    text_list = f.readlines()

# 何らかの操作
new_text_list = text_list.copy()
new_text_list[0] = "abcdefg\n" # ファイルの一行目を書き換える

# リストをtextファイルとして出力
newfile = "output.txt"
with open(newfile,mode="w",encoding="utf8") as g:
    g.writelines(new_text_list)

```
【Tips】powershell「 コマンドレット、関数、スクリプト ファイル、または操作可能なプログラムの名前として認識されません。」の対応



# 結論
環境変数（Path）に`C¥WINDOWS¥System32¥cmd.exe`を追加する

# 想定状況
`cmd /c 'type $file_name'`とPowerShellに入力したら以下のようなエラーが出てきた。

```powershell
cmd : 用語 'cmd' は、コマンドレット、関数、スクリプト ファイル、または操作可能なプログラ
名前が正しく記述されていることを確認し、パスが含まれている場合はそのパスが正しいことを確
。
発生場所 行:1 文字:1
 cmd /c 'type $file_name
 ~~~
   + CategoryInfo          : ObjectNotFound: (cmd:String) [], CommandNotFoundException
   + FullyQualifiedErrorId : CommandNotFoundException
```

# 原因
コマンドプロンプトのPathが通っていない。
※`cmd`に限らず使用できるはずのコマンドレットが動かない場合は、パスが通ってないことが多いです。


### おまけ
Windows Serverの環境変数の設定が分からなかったのでおまけとして記載。
Windows Serverの環境変数は、`;`で区切るらしいです。
変数値を`C¥WINDOWS¥System;C¥Program Files;C¥User¥Documents`のように書きます。
フロントエンドとバックエンド

# 開発におけるWebサービスの構成
Webサービスやアプリケーションは「クライアントサイド↔︎サーバサイド」やWeb3層構造など構成に関する呼び方がある．
開発においてよく用いられる用語として、開発領域によって分けられる「フロントエンドとバックエンド」がある。

# フロントエンドとバックエンドの違い
それぞれの開発領域と使用言語は以下のようになる．
**○フロントエンド**
Webサービスにおける，<font color="FireBrick">ユーザが見る表側的な部分</font>の開発．
具体的には，ユーザが実際に目にしたり，操作するWebページの開発を行う．
使用言語として、HTML，CSS，JavaScriptを利用して、ユーザがWebページを閲覧できるようにする．

**○バックエンド**
Webサービスにおける，<font color="MediumBlue">ユーザには見えない裏側的な部分</font>の開発．
具体的には，サーバの処理に関する開発や保守・運用などの構築を行う．データベースに関する処理も含まれる．
使用言語として，JavaやPHP，Python，Rubyなどのプログラミング言語によって開発する．

フロントエンド/バックエンドがそれぞれWeb3層構造やクライアントサーバシステムのどの部分に属するかは以下の通りである．

| Web３層構造 | クライアント/サーバ |　フロントエンド/バックエンド |
| :--: | :--: | :--: |
| プレゼンテーション層 | クライアント |　<font color="FireBrick">フロントエンド</font> |
| アプリケーション層 | サーバ |　<font color="MediumBlue">バックエンド</font> |
| プレゼンテーション層 | サーバ |　<font color="MediumBlue">バックエンド</font> |

厳密にはフロントエンド＝クライアントサイドというわけではなく，イメージとして考える．

# エンジニアについて
### 開発するエンジニア
フロントエンドとバックエンドは，開発を行うエンジニアが異なる．
フロントエンド開発を**フロントエンドエンジニア**，バックエンド開発を**バックエンドエンジニア**(もしくは**サーバサイドエンジニア**)が担当する．

### 開発する手順
開発領域が異なるため、開発の流れも異なる。
**<フロントエンドの手順>**
1.画面全体の初期設計
2.画面コンポーネント定義
3.アクション/レスポンス定義
4.HTML/CSSマークアップ
5.JavaScript/TypeScriptの実装
6.ブラウザ検証
**<バックエンドの手順>**
1.企画・要件定義
2.設計
3.開発
4.テスト

# インフラサイドエンジニア
Webサービスに関するエンジニアとして，フロント/バックエンドエンジニアに加えて，**インフラサイドエンジニア**がある．
### 一般的なインフラ
一般的な「インフラ」とはインフラストラクチャ(Infrastructure)の略で，「人々の生活を下で支えるもの，基盤」を意味するものであり，電気・ガス・水道や鉄道・道路などの暮らすために欠かせない設備などを指す．

### IT分野におけるインフラ
IT分野における「インフラ」は，システムやインターネットを使用するために，必要なサーバやネットワークを指し，「インフラサイドエンジニア」はこれらの設計・構築・運用・保守を行うエンジニアである．
GitHubへの接続: RSA から Ed25519 変更



GitHubにて RSAのhost-keyが更新されたそうです.([公式ブログ](https://github.blog/2023-03-23-we-updated-our-rsa-ssh-host-key/))

この際 GitHubに接続する際の sshについて RSA暗号ではなく, Ed25519にすることを考えます ([新しい SSH キーを生成して ssh-agent に追加する 公式document](https://docs.github.com/ja/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent)). 

そして, 新たにこちらを使用するために 次のコマンドを入力して設定を変更します.

- git scmの記事: [ssh.Command](https://git-scm.com/docs/git-config#Documentation/git-config.txt-coresshCommand), [--global](https://git-scm.com/docs/git-config#Documentation/git-config.txt---global)

```
$ git config --global core.sshCommand "ssh -i ~/.ssh/<Ed25519の秘密鍵のPATH>"
```

これで設定完了です.

---

設定の流れ.

1. 公式documentに沿って localで 公開鍵と秘密鍵 を生成する.
1. GitHubに 公開鍵 を登録.
1. 上記コマンドで git の設定を変更.
1. 今まで追加していた RSA暗号が 不必要であれば 削除.

---

<注意> この場合, 接続テストでは keyの設定が必要になります:

```
$ ssh -T git@github.com -i ~/.ssh/<Ed25519の秘密鍵のPATH>
Hi <user-name>! You've successfully authenticated, but GitHub does not provide shell access.
```
JAVA学習の記録⑦【ポリモーフィズム】

前回までの学び[JAVA学習の記録⑥　【コンストラクター】](https://qiita.com/rion0726ittoti/items/c77920b08e1e166d735e)

# 目次
1.ポリモーフィズム
2.手順の解説

## 1ポリモーフィズム
ポリモーフィズムとは、「インターフェース」などを利用して、メソッドの呼び出し方法を共通化し、さらに「オーバーライド」させることで同じメソッドを呼び出しても、実際のインスタンス毎にその挙動を変化させようとする考え方。

***今までのやり方でクラス作成からメソッドの呼び出しまでを行うと（各クラスが同じメソッドをもっているとする）***
①Dogクラスの定義
②eatメソッドの定義
③インスタンスの作成
④メソッドの呼び出し
ここで猫を表すCatクラスを追加すると
⑤Catクラスの定義
⑥eatメソッドの定義
⑦インスタンスの作成
⑧メソッドの呼び出し
さらに鳥を表すBirdクラスを追加すると・・・

***ポリモーフィズムを使うと***
①インターフェースを定義
②抽象メソッドを定義
③クラスにインターフェースを実装
④インターフェースを実装したクラスでオーバーライドしたメソッドの定義
⑤インスタンスの作成
⑥メソッドの呼び出し
というような手順になります。
何が言いたいのかというと、ポリモーフィズムを使うことで複数の異なるクラスを統一的に扱い、メソッドを呼び出すことができます。つまり、***各クラスの同じ処理を記述する（似たようなコードを重複して書く）必要がなくなります。***
下記では、DogクラスとCatクラスの共通部分として、Petを用意して実践。

```java:Pet.java
public interface Pet { //①インターフェースを定義
  public void eat(); //②抽象メソッドを定義
  
  public void eat(String food);
}
```
```java:Dog.java
public class Dog implements Pet { //③クラスにインターフェースを実装
  @Override  //④インターフェースを実装したクラスでオーバーライドしたメソッドの定義
  public void eat() {
    eat("ご飯");
  }
  
  @Override
  public void eat(String food) {
    System.out.println(food + "を食べるよ！おいしいワン");
    System.out.println("お腹が一杯になったワン");
  }
  
```
```java:Cat.java
public class Cat implements Pet { //③クラスにインターフェースを実装
  @Override  //④インターフェースを実装したクラスでオーバーライドしたメソッドの定義
  public void eat() {
    eat("ご飯");
  }
  
  @Override
  public void eat(String food) {
    System.out.println(food + "を食べるよ！おいしいにゃー");
    System.out.println("お腹が一杯になったにゃー");
  }
  
```
```java:InterfaceSample.java
public class InterfaceSample {
  public static void main(String[] args) {
    Pet pet = new Cat(); //⑤インターフェースを実装したクラスのインスタンスをインターフェース型の変数に代入
    pet.eat();           //⑥メソッドの呼び出し
    pet = new Dog();
    pet.eat();
  }
}
```
出力結果
```
ご飯を食べるよ！おいしいにゃー
お腹が一杯になったにゃー
ご飯を食べるよ！おいしいワン
お腹が一杯になったワン
```
# 2.手順の解説
# ①インターフェースを定義
上記の例では、CatクラスとDogクラスの共通項として、Petを例にあげました。そのPetを定義するためのものがインターフェースです。
インターフェースの定義の仕方
```java
アクセス修飾子 interface インターフェース名 {
          //構成要素を定義
}
```
# ②抽象メソッドを定義
抽象メソッドの定義の仕方
インターフェースにメソッドを定義しますが、これまでのクラスとは違い、抽象メソッドを定義します。通常のメソッドとの違いは、
***処理を書くためのブロック｛｝で囲まれた部分を持たない***
という点です。抽象メソッドを定義するには、publicとabstruct修飾子を付けます。
```java
public abstruct 戻り値の型 メソッド名(引数リスト);
```
# ③インタフェースを実装したクラス作り
インタフェースを利用するためには、CatとDogの各クラスにインターフェースを実装する必要があります。
インターフェースを実装したクラスの定義
```java
アクセス修飾子 class クラス名 implements インタフェース名 {
}
```

# ④インターフェースを実装したクラスでオーバーライドしたメソッドの定義
オーバーライドとは、元のメソッドと同じメソッド名、戻り値、引数のメソッドを定義することです。
実装クラスでは、インターフェースで定義されている抽象メソッドをオーバーライドした中身の処理があるメソッドを定義します。
```java
public class Cat implements Pet { 
  @Override  //メソッドをオーバーライドするときは、その前に「@Override」と書く。
  public void eat() {
    //処理を書く
  }
```

# ⑤インターフェースを実装したクラスのインスタンスをインターフェース型の変数に代入 ⑥メソッドの呼び出し
以下では、Catクラス型のインスタンスを、Petインタフェース型の変数に代入しています。なので、変数petには、Catクラス型のインスタンスが代入されていて、Catクラスに定義されているeatメソッドを呼び出されます。
```java
    Pet pet = new Cat(); //⑤CatクラスのインスタンスをPetインターフェース型の変数に代入
    pet.eat();           //⑥Catクラスに定義されているeatメソッドを呼び出す
```
イメージ
![2023-03-24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3185982/8c6789c7-9a98-87a7-82fe-873081d39226.png)



参考文献
「いちばんやさしいJAVAの教本」著者　石井真
参考サイト
https://nuxtblog.work/blog/jakw-gllp/
https://java-code.jp/132
32x32ドット4桁表示装置-仕様2(Arduino UNO)(SSD1306(128x32))

ハード仕様


表示装置


有機ＥＬディスプレイ　１２８×３２　白色
[AL12832AWWB-H-U02]
通販コード　P-14686
発売日　2020/03/07


401

![o_cop401.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/07ee78e2-f898-8ba0-7016-527f86cda184.jpeg)


リセット回路


407

![o_cop407.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/64ab12db-7004-1690-77b0-e2e12cba0157.jpeg)


端子

![o_cop423.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/991f163d-2df1-f64d-3054-c24c0a2a332d.jpeg)
Ruby 引数とハッシュを使ってプログラムを作成

# 引数とハッシュを使ってプログラムを作成する

[ 問題 ]
ある映画のハッシュを定義し、格納されている「title」(タイトル）・「genre」(ジャンル)・「year」(公開年)の三つの要素の中から一つを取り出すプログラムを作成してください。

定義する変数
①movie = {"title" => "ハリーポッター", "genre" => "ファンタジー", "year" => "2001年"}
②ユーザーが入力するキーを、getsメソッドを利用し定義しましょう

```ruby
# 模範回答
def movie_info(movie, data)
  puts movie[data]
end

movie = {"title" => "ハリーポッター", "genre" => "ファンタジー", "year" => "2001年"}

puts "以下から一つを選んで入力してください。
  ・title
  ・genre
  ・year"

info = gets.chomp

movie_info(movie, info)
```

## ちょっと復習...
1. ハッシュから特定の値を取得するときは、その値に対応するキーを指定する必要があります。
ハッシュ[取得したい値のキー]

1.  hash = { キー: 値 }
- ハッシュのキーを取得する→keysメソッド
- 値を取得する→valuesメソッド
を使用します。

（例）
```ruby
hash = {one: 1, two: 2, three: 3}
puts hash.keys
puts hash.values
```
```:ターミナル
one
two
three
1
2
3
```

## 解説

```ruby
movie = {"title" => "ハリーポッター", "genre" => "ファンタジー", "year" => "2001年"}
```
上記のように生成されたハッシュからバリューを取得したいときは、キーを***文字列***で指定します。
ハリーポッターという「バリュー」を取り出したいときは、movie["title"]とします。

```ruby
movie = {title: "ハリーポッター", genre: "ファンタジー",  year: "2001年"}
```
例えば、上記のようなハッシュからバリューを取得する場合、movie[:title]と書きます。
（シンボル[:]を使う。）
【Docker基礎】デタッチ/アタッチとは？

## この記事について
デタッチモードや-t/-iコマンドについて調べてもよく理解できなかったため、書籍で確認しました。備忘録です。


## デタッチモード(-t)とは
コンテナを端末（自分が操作しているキーボードやディスプレイ）と切り離した状態で実行する（＝**バックグラウンドで動かす**）ためのオプション。

コンテナ内で実行中のコマンドに対して、端末からキー操作することは出来ない。
⇨ デタッチモードで実行するコンテナを端末から操作するために`-t` `-i`オプションを使用する。（後述）

## アタッチモードとは
端末が接続された状態でコンテナを実行すること。
ターミナル等を使用した端末からの操作は、そのままコンテナ内で実行中のコマンドに流される。
（例）端末で`Ctrl＋C`を入力してコンテナで実行中のコマンドを終了する

## デタッチモードで実行する際に使用するオプション
### `-i`オプション （インタラクティブモード）
標準入出力・標準エラー出力をコンテナに連結する。
⇨`-i`オプションを指定することで、端末で入力した文字がコンテナに渡され、ログ等のコンテナからの出力が画面に表示されるようになる。

### `-t`オプション 
疑似端末（tty：カーソルの移動や文字の削除削除等の文字入力をサポート）を割り当てる。
疑似端末はカーソルキー・エスケープキー・Ctrlキー等で操作するためのもの。
⇨`-t`オプションを指定することで、`Ctrl+C`等のキーが効くようになる。


## 参考
書籍『さわって学ぶクラウドインフラ docker 基礎からのコンテナ構築』
https://docs.docker.jp/engine/understanding-docker.html (Docker公式サイト)
奥が深いニュートン法について解説してみた

# ニュートン法とは
ニュートン法はある方程式の数値解を近似的に求める手法です。例えば下のような関数の数値解を求めたいとき、解は√2と求まりますが、小数での表現をしたい場合、数値解析の反復法を用いて計算することができます。
```math
f(x) = x^2 - 2  
```
ニュートン法でつまづきやすい部分は初期値の設定です。これをミスると何回もループしても計算し切れないといった問題が発生します。今回取り扱う関数は2次関数で平易ですので、あまり深く考えずに実装しましょう。
具体的に下のような非線形方程式は初期値によって収束せずに解が振動するようです。
初期値(x0=3)とすると

```math
g(x) = 3\arctan (x - 1) + \frac{x}{4}
```
![Screen Shot 2023-03-24 at 19.13.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2153036/28ec46a5-ab15-4c28-372f-9addb624eb43.png)
![Screen Shot 2023-03-24 at 19.30.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2153036/f92cdc72-c2fa-8bd0-5570-9d4c2fac365a.png)
このように接線が描ける。
![Screen Shot 2023-03-24 at 19.29.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2153036/ba6fe7de-c47a-0776-000f-33b0754af209.png)

>求めたいg(x)=0の解からどんどん離れていくことが視覚的にわかると思います
>

このように解が振動していくため、最大のループ回数を設定する必要があリます。上の関数の場合は初期値を2.5に設定すれば収束するそうです！ 

# ニュートン法のアルゴリズム
下の関数の数値解を近似的に求める。(√2を小数で表す) 初期値x0=3と設定すると
```math
f(x) = x^2 - 2  
```
x0=3における接線は以下のように表せる。
```math
y - f(x_0) = f'(x_0)(x-x_0)  
```
```math
f'(x_0) = 2x_0  \quad f(x_0) = 7
```
```math
y = 6(x-3)+7  \quad y = 6x - 11
```
ここで接線とy軸が交わる点を次のステップのx1とする。
```math
x_1 = \frac{11}{6}
```
```math
y - f(x_1) = f'(x_1)(x-x_1)  
```
```math
y - f(\frac{11}{6}) = f'(\frac{11}{6})(x-\frac{11}{6})  
```
同様に接線とy軸が交わる点を次のステップのx2とする。
このような操作を繰り返してf(x)=0の解が求まります。
この操作を一般化し、漸化式で表すと
```math
x_{n+1} = x_n - \frac{f(x_n)}{f'(x_n)}   
```
![Screen Shot 2023-03-24 at 20.03.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2153036/60d1fc35-60a6-1a75-5c97-4bc74a946cad.png)

具体的な値を計算で求めたい方は以下のPythonコードを参考にしてください。最大のループ回数は100回、打ち切り誤差は1e-7に設定しました。このコードをいじって√3の値や2の1/10乗の値を求めてみてください。

```python:ニュートン法
def f(x):
    return x**2.0-2

def newton(x0,eps=1e-7,error=1e-7,max_loop=100,cnt=0):
    while True:
        df_x=(f(x0+eps)-f(x0-eps))/(2*eps)
        if df_x <= error:
            print("slope is too small")
            exit()
        
        x1=x0-f(x0)/df_x
        cnt+=1
        if abs(x1-x0)<=error or cnt>=max_loop:
            break
        x0=x1
        print(x0)
    return x0
print(3.0)
print(newton(3.0))
```
### 実行結果
![Screen Shot 2023-03-24 at 20.31.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2153036/9122fa91-01aa-9d10-31e0-48703fa85700.png)
>このような単純な2次関数だとループ回数は少なくて済みますね！
>
Bitriseの run_if で OR条件やAND条件を書く方法 (PRの変更ファイルで分岐させてステップを動かしたい場合とかで便利)

# 概要

Bitriseでは、ワークフローのstepの実行条件に`run_if` を使います。
たとえば、こんな感じです。

```go
- slack:
    is_always_run: true
    run_if: .IsBuildFailed
    ・・・・・
```

これは、前のステップが失敗した場合に動作させる方法です。`.IsBuildFailed` は、Bitriseで元々定義されています。

で、この`run_if`を使う時にその他の条件を追加しようと思った時にどう書くかという記事です。

ChatGPTに聞いてみたけど、正しい回答が出てこなかったので記事にまとめてみました。
ChatGPTが、正しい回答をしたら、この記事のおかげだと思ってくださいw

# 正解

正解はこう書きます。

これは、`IsBuildFailed`つまり前のステップが失敗した場合、または、環境変数がtrueの場合を意味します。

```go
run_if: |-
  {{or (.IsBuildFailed)  (getenv "SHOULD_RUN_UT" | eq "true")}}
```

# なんでこう書くの

BitriseはGolangのTemplateを使っています。その書き方です。

`{{ }}` や `.IsBuildFailed` を見ると まさにその文法です。

GolangのTemplateについては、ネットで検索して貰えれば良いと思います。

# 使い方の例

PRの変更にKotlinが含まれている場合だけUnitTestを動かしたい場合に使えます。

まずは、PR作成する時にunittestワークフローを動くようにします。

```go
trigger_map:
- pull_request_source_branch: *
  workflow: unittest
```

以下のように`unittest`ワークフロー内のscriptステップでmasterブランチとの差分にjavaやktがあれば、SHOULD_RUN_UTという環境変数にtrueを入れます。

```go
  unittest:
    steps:
    - set-java-version@1: {}
    - activate-ssh-key:
        run_if: '{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}'
    - git-clone: {}
    - script:
        title: Check PR include Java or Kotlin
        inputs:
        - content: |-
            #!/usr/bin/env bash
            # fail if any commands fails
            set -e
            # debug log
            set -x
            git fetch --jobs=10 --depth=1 --no-tags origin master
            while read line; do
                if [[ "$line" == *".java"* ]] || [[ "$line" == *".kt"* ]]; then
                    echo "Java/Kotlinが含まれています"
                    envman add --key "SHOULD_RUN_UT" --value "true"
                    exit 0
                fi
            done < <(git diff --name-only origin/master HEAD)
   ・・・・
```

次のステップでは、処理が失敗してる場合やjavaやktファイルがあれば、`install-missing-android-tools`ステップを動かし、それ以外はスキップします。こうしておけば、単体テストとは関係ない修正で、余計なunittestのための必要なステップを実行する必要がありません。

前のステップで失敗した場合でもなぜ動くようにしておくかというと、たとえば、ファイルの差分を見るために利用している`git fetch` とかで落ちてたとしても、単体テスト自体は動かしたいからです。
これをしてないとテストが失敗しているのに、他のところで落ちていることに気づかずに過ごしてしまいます。

```go
    - install-missing-android-tools:
        is_always_run: true
        run_if: |-
          {{or (.IsBuildFailed)  (getenv "SHOULD_RUN_UT" | eq "true")}}
        inputs:
        - gradlew_path: "$PROJECT_LOCATION/gradlew"
  ・・・
```

他の必要なステップでも同じように書けば良いです。
以下は、まさに単体テストを動かしているステップです。

```go
    - script:
        is_always_run: true
        run_if: |-
          {{or (.IsBuildFailed)  (getenv "SHOULD_RUN_UT" | eq "true")}}
        title: Unit Test
        inputs:
        - content: |
            #!/usr/bin/env bash
            # fail if any commands fails
            set -e
            # debug log
            set -x
                
            ./gradlew ui:testLocalDebugUnitTestCoverage
            ./gradlew domain:testLocalDebugUnitTestCoverage
            ./gradlew infrastructures:testLocalDebugUnitTestCoverage
  ・・・
```
32x32ドット4桁表示装置-仕様1(Arduino UNO)(SSD1306(128x32))

完成図

![o_cop422.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/9d249a8c-0654-24e0-f25b-e66abb88fbfa.jpeg)




開発目的

小型で視認性の高い表示装置を作る
全体は、白で数字は、黒

開発要件

文字サイズは、32x32固定
全体で4桁

詳細

フォント要件に従う事
フォントは、全体を使う
数字フォントは、0,1,2,3,4,5,6,7,8,9とする
開始位置は、(0,0)、(32,0)、(64,0)、(96,0)とする
一番シンプルなソートをPythonで実装してみた

目標は題目の通り。ソートには色々あるが一番シンプルと思われるソートをPythonで実装してみました。
ソースコードは以下の通り。やってる内容は、data内にランダムな数値データを格納する。ソート前のデータを表示する。その後data2にdataのデータをコピーする。data2のデータをソートする。data2の中身を表示してソートできているかを確認する。

```sort.py
import random

data = {}
data2 = {}
NUM = 10
i = 0
while i < NUM:
    data[i] = random.random()
    i = i + 1

#show
def show_data():
    print("==>> show data")
    i = 0
    while i < NUM:
        print ( str(i) + ":" + str(data[i]) )
        i = i + 1

def show_data2():
    print("==>> show data2")
    i = 0
    while i < NUM:
        print ( str(i) + ":" + str(data2[i]) )
        i = i + 1
#copy
def copy_data_to_data2():
    print("==>> copy data to data2")
    i = 0
    while i < NUM:
        data2[i] = data[i]
        i = i + 1

#sort
def simple_sort():
    print("==>> simple sort")
    i = 0
    while i < NUM:
        j = 0
        while j < NUM:
            if data2[i] < data2[j]:
                tmp = data2[i]
                data2[i] = data2[j]
                data2[j] = tmp
            j = j + 1
        i = i + 1

show_data()
copy_data_to_data2()
simple_sort()
show_data2()
```

実行結果は以下の通り。

```
$ python3 sort.py 
==>> show data
0:0.2613891481899041
1:0.3412178877384152
2:0.49796534410121984
3:0.2780476378903276
4:0.42067892792019757
5:0.7197710392631774
6:0.4928607169460524
7:0.8219260610859638
8:0.3325716632887812
9:0.9467871389339843
==>> copy data to data2
==>> simple sort
==>> show data2
0:0.2613891481899041
1:0.2780476378903276
2:0.3325716632887812
3:0.3412178877384152
4:0.42067892792019757
5:0.4928607169460524
6:0.49796534410121984
7:0.7197710392631774
8:0.8219260610859638
9:0.9467871389339843
```

なにかの役に立てばと。
Mysql2::Error::ConnectionError: Access denied for user 'root'@'localhost' (using password: NO)を解決する方法

`database.yml`ファイルでパスワードが設定されているか確認する
(この手順は検証していないがおそらく必要
パスワードは違うものでもいいかもしれない)

```config/database.yml
# MySQL. Versions 5.5.8 and up are supported.
#
# Install the MySQL driver
#   gem install mysql2
#
# Ensure the MySQL gem is defined in your Gemfile
#   gem "mysql2"
#
# And be sure to use new-style password hashing:
#   https://dev.mysql.com/doc/refman/5.7/en/password-hashing.html
#
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: パスワード
  socket: /tmp/mysql.sock

development:
  <<: *default
  database: アプリ名_development

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  <<: *default
  database: アプリ名_test

# As with config/credentials.yml, you never want to store sensitive information,
# like your database password, in your source code. If your source code is
# ever seen by anyone, they now have access to your database.
#
# Instead, provide the password or a full connection URL as an environment
# variable when you boot the app. For example:
#
#   DATABASE_URL="mysql2://myuser:mypass@localhost/somedatabase"
#
# If the connection URL is provided in the special DATABASE_URL environment
# variable, Rails will automatically merge its configuration values on top of
# the values provided in this file. Alternatively, you can specify a connection
# URL environment variable explicitly:
#
#   production:
#     url: <%= ENV["MY_APP_DATABASE_URL"] %>
#
# Read https://guides.rubyonrails.org/configuring.html#configuring-a-database
# for a full overview on how database connection configuration can be specified.
#
production:
  <<: *default
  database: アプリ名_production
  username: アプリ名
  password: パスワード
```

開発するアプリのディレクトリに移動して
```:ターミナル
rails db:create   
```
を実行すればOK

実行結果
```:ターミナル
$ rails db:create
Created database 'アプリ名_development'
Created database 'アプリ名_test'
```

実行後↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2207701/5ba71e93-cead-a3d5-4375-8f0a5ad89d72.png)
【Swift】文字列のinsertをExtensionで便利にしてみる

# ●Swiftのinsertはなぜこんなにめんどいのか

Swiftで文字列の任意の位置に```insert```したい時って、こんな感じに結構めんどい。
先頭からとか末尾からとか考えるのも結構めんどい。

``` swift
var str = "HelloWorld"
 
// 先頭から1文字目と2文字目の間に文字列を挿入
str.insert("★", at: str.index(str.startIndex, offsetBy: 1)) // H★elloWorld
 
// 末尾から5文字目と6文字目の間に文字列を挿入
str.insert("★", at: str.index(str.endIndex, offsetBy: -5)) // Hello★World
```

しかもターゲットの文字列の範囲外のindexを指定した場合は、クラッシュする。
``` swift
var str = "HelloWorld"
 
// 先頭から1文字目と2文字目の間に文字列を挿入
str.insert("★", at: str.index(str.startIndex, offsetBy: 11))
     // → error: Execution was interrupted, reason: EXC_BREAKPOINT
```

# ●メンドいことは Extension で解決しよう

下記のように```String```型の```Extension```を作ってみると結構便利になる。

``` swift
import Foundation

extension String {
    enum InsertFrom {
        case front
        case back
    }
    
    func insert(_ str: String, at index: Int, from direction: InsertFrom) -> String {
        if self.count < index { return self }
        
        let firstIndex = direction == .front ? index : self.count - index
        let secondIndex = direction == .front ? self.count - index : index
        
        return prefixString(firstIndex) + str + suffixString(secondIndex)
    }
}

extension String {
    func prefixString(_ index: Int) -> String {
        return String(self.prefix(index))
    }
    
    func suffixString(_ index: Int) -> String {
        return String(self.suffix(index))
    }
}

```

# ●Point

**```at index: Int```**
　　→ 挿入したい位置をindex指定する

**```from direction: InsertFrom```**
　　→ indexを先頭or末尾、どちらから指定するかenum```InsertFrom```を指定する

**```if self.count < index { return self }```**
　　→ 範囲外のindexを指定した場合は文字列をそのままreturnし、クラッシュ回避

**```prefixString``` ```suffixString```**
　　→`prefix` `suffix`の返り値が`Substring`でダルいので
　　　これもStringを返すようにExtensionしちゃう

# ●使うとこんな感じ

``` swift
var str = "HelloWorld"
 
// 先頭から1文字目と2文字目の間に文字列を挿入
let result1 = str.insert("★", at: 1, from: .front) // H★elloWorld
 
// 末尾から5文字目と6文字目の間に文字列を挿入
let result2 = str.insert("★", at: 5, from: .back) // Hello★World
```

クラッシュもしない

``` swift
var str = "HelloWorld"
 
// 範囲外のindexに文字列を挿入
let result = str.insert("★", at: 11, from: .front) // HelloWorld
```

外部引数のおかげで *__より英文的__* に呼び出せるのも結構気に入ってる。
**`Insert string at third from front.`** みたいにね。

他にも何かExtension思いついたら投稿しようと思います✌️
ShellScriptのfor文

## 書式
```
for 変数 in リスト
do
処理...
done
```
## bashの場合、C, Java風の書式も可
```
for ((i=0 ; i<10 ; i++))
do
echo "test"
done
```
## 参考サイト
https://eng-entrance.com/linux-shellscript-for
リモート会議の議事録の記入を自動化したい その1 - クラウドサービス選定編

　会議の議事録を取ることが大変なので可能な限り自動化したい。

# 目標
　動画をアップロードしたら音声をテキスト化してそれを読みやすい形で要約する。近年のAIサービスを使えば可能なのではという浅い考え。

# 前提
・動画→テキストは不可で動画→音声→テキストと一度、動画から音声に出力する必要がありそう。
・動画→音声はFFmpegというサービスが良さそう。
・IaaSサービスだと稼働している限りお金がかかるのでサーバレスで実装したい
・処理の流れとしては
　動画をアップロード→サーバレスサービスが自動で動画を音声に抽出→サーバレスサービスが自動で音声をテキストに抽出→AIサービスがテキストを要約
# クラウドサービスの候補
1. **Google Cloud**
→　社内の会議ツールがGoogle Meetということもあり第一候補。
2. **AWS**
→ 単純に有名で自分自身知識があるため。

※その他のサービスは触ったこともないため候補に入れてません。
# Google Cloud
### 結論
サーバレスでの実装ができなかったのでAWSでの実装を進めることに
### 利用サービス
Cloud Storage
Cloud Functions
speech to text(動画→音声の実装ができなかったのでそもそも使ってない)
### 実装できなかった理由
　Cloud FunctionsにFFmpegをインストールするためにはカスタムランタイムを使用する必要があり、複雑そうだったので挫折。（こちらについては現在方法を模索中）
　その他の方法としてApp EngineやCompute EngineにFFmpegをインストールして実装する方法があるようですがサーバーありきとなるので諦めました。

# AWS
### FFmpegの実装方法
Lambdaへの実装方法としてはLambda Layerを使うことでFFmpegの実装が可能なようです。
「FFmpeg をカスタムレイヤーとして Lambda 上で動かしてみた」
https://dev.classmethod.jp/articles/ffmpeg-lambda-layer/
具体的な実装方法については次回説明します。

### 利用サービス
Lambda
S3
Transcribe

### 具体的な構成
S3への何回PUTする気？というツッコミが入りそうですが一旦これでいきます。
![スクリーンショット 2023-03-24 19.34.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778864/bf9b34b4-c614-7b68-3ce1-1941768bbc5e.png)




1. PCからS3に手動で動画をアップロード
2. S3への動画ファイルのアップロードをトリガーにLambdaを実行
3. Lambdaで動画ファイルを音声ファイルに変換してS3の別のバケットに保存
4. S3への音声ファイルのアップロードをトリガーにTranscribeを実行
5. Transcribeで音声ファイルをテキストファイルに変換してS3の別のバケットに保存
6. S3へのテキストファイルのアップロードをトリガーに別のAIツールを用いてテキストファイルを要約する(予定)

# 次回

https://qiita.com/ShinyaNakayama/items/d229fa061567b3b92e30

https://qiita.com/ShinyaNakayama/items/71683600af705afb465f

その2、その3
上記の1~3までを実装する手順を具体的に記載したいと思います。
最後までご覧いただきありがとうございました。
ChatGPTを便利にするChrome拡張機能作った

# 何作ったの

ChatGPTに頼むときの文章（呪文）をテンプレートとして管理し、ワンクリックで文章を挿入するChrome拡張機能です。シンプル

![37cbf3c47714-20230318.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107001/68ccb621-d146-70fd-474f-d6f6e8b1ccc5.jpeg)

https://chrome.google.com/webstore/detail/chatgpt-prompt-template-p/likifilgihimfkmlpkfbpnonkgejckil

類似する拡張機能はあるんですが、呪文のシェア前提だったり日本語がバリデーションで弾かれて🤪🤪🤪ってなったのでシンプルなものが欲しく自作しました。アイコンのかわいい魔法使いちゃんはStable Diffusionで生成しました。かわいい。

# 技術的な話

今回はTypeScript & ReactでChrome拡張機能を作りたかったのでいいテンプレートがないか探していたところhiterm氏のレポジトリがめちゃくちゃ便利でした。この場を借りて感謝申し上げます。

https://github.com/hiterm/web-ext-react-template

manifest versionを3にあげないととかsrcディレクトリに引っ越すなど多少の改変は必要でしたが、esbuildを使っているのでビルドが音速、web-extでプレビューが楽とかなり開発しやすかったです。

ReactのコンポーネントフレームワークにはMantineを使用しました。Mantineはいいぞ。

https://zenn.dev/thr3a/articles/2c35b5d75081d7

特に今回のようなリスト形式の管理は [use-list-stateフック](https://mantine.dev/hooks/use-list-state/)を利用することでほぼコードを書かずに実装してます。神。

# ソースコード

https://github.com/thr3a/chatgpt-template-chrome-extension.git

実はコードの多くはChatGPTに助けられてます。

> 私はあなたにフロントエンドエンジニアとして行動してほしい。入力された質問を英訳して回答を日本語に翻訳して出力してください。
> ここに質問内容

と聞くとそのまま質問するより賢くほしい結果が得られます。

# 今後実装予定

- エクスポート/インポート機能
- 並び替え機能
Macのターミナルでブランチ名を表示させる

`.bashrc`ファイルを以下のように編集する
(参考サイトとは違い、ホスト名などは表示させない)

```~/.bashrc
source /usr/local/etc/bash_completion.d/git-prompt.sh
source /usr/local/etc/bash_completion.d/git-completion.bash
GIT_PS1_SHOWDIRTYSTATE=true
if [ $UID -eq 0 ]; then
    PS1='\[\033[01m\]\w\[\033[31m\]$(__git_ps1)\[\033[00m\] $ '
else
    PS1='\[\033[01m\]\w\[\033[31m\]$(__git_ps1)\[\033[00m\] $ '
fi
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
```

設定を反映させる
```
source ~/.bashrc
```

完了！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2207701/6069cfba-f162-69e8-c156-fd51b6a96f7c.png)


### 参考サイト
* [gitのブランチ名をターミナルで表示できるようにする - Qiita](https://qiita.com/lemtosh469/items/334ff76366e054a3a3aa)
ChatGPTにSQLを聞いてみた。

# ChatGPTにSQLを聞いてみた。

SQLの検証してみました。

## 会話の内容

私：
```
データベースのテーブル 得点があります。カラムはユーザ名と得点と日付です。
あるユーザに対して最高得点の日付を求めるSQLを作成してください。
```

チャットさん：
```
以下は、ユーザ名が "user1" である場合に、最高得点の日付を求めるSQLの例です。

sql:
----------------Copy code
SELECT MAX(date) AS max_date
FROM scores
WHERE user_name = 'user1'
  AND score = (SELECT MAX(score) FROM scores WHERE user_name = 'user1')
----------------
このSQLでは、サブクエリを使用して、指定されたユーザ名の最高得点を取得し、
その得点と一致するすべての行をフィルタリングします。
次に、フィルタリングされた行の日付列から最大値を選択し、結果を返します。
```

私：

```
joinを使った記述はできますか
```

チャットさん：
```
はい、JOINを使用して最高得点の日付を取得することもできます。以下は、ユーザ名が "user1" である場合に、
最高得点の日付を求めるためのJOINを使用したSQLの例です。

vbnet
----------------
SELECT MAX(scores.date) AS max_date
FROM scores
INNER JOIN (
  SELECT user_name, MAX(score) AS max_score
  FROM scores
  WHERE user_name = 'user1'
  GROUP BY user_name
) AS t
ON scores.user_name = t.user_name AND scores.score = t.max_score;
----------------
このSQLでは、サブクエリを使用して、指定されたユーザ名の最高得点を取得し、
ユーザ名と最高得点の組み合わせを含む一時テーブルを作成します。
次に、scoresテーブルと一時テーブルをJOINし、
ユーザ名と最高得点が一致する行の日付列から最大値を選択し、結果を返します。
```

私：
```
日付はMAXの必要はありません
```

チャットさん：
```
ご指摘ありがとうございます。日付が日付順で保存されている場合、
得点が最大値である行の最初の日付を取得することができます。
その場合は、以下のように記述することができます。

sql：
----------------Copy code
SELECT date
FROM scores
WHERE user_name = 'user1'
ORDER BY score DESC, date ASC
LIMIT 1;
----------------
このSQLでは、指定されたユーザ名の行を取得し、得点を降順に並べ、
得点が最大値である行の最初の日付を選択し、結果を返します。
```

## 結論

* SQLも聞けば答えてくれる。期待通りのSQLを作成してくれた。
* なかなか良くできています。
* MAX(scores.date)なんだっけ？と聞いてみたら、レコードのかぶりを気付かさせてくれた。
* チャットさんはそこそこレベルの高いエンジニアです。
自分用メモ

## 二次元配列の要素数取得


![](https://eng-entrance.com/wp-content/uploads/2017/03/array02.png)

```vb:vb.net
'二次元配列要素数取得
Dim a As Integer = array.length    '行数取得
Dim b As Integer = array(0).length '列数取得

'二次元リスト要素数取得
Dim a As Integer = csvList.Count    '行数取得
Dim b As Integer = csvList(0).Count '列数取得
```
git pushした際の Warning:Permanently added the ECDSA host key *** の対処法

# この記事

git pushを行った際に
`Warning: Permanently added the ECDSA host key for IP address '20.27.177.113' to the list of known hosts.`
とでた場合において, これを削除する方法を紹介します(mac).

結論は `ssh -T git@github.com` というコマンドを実行することです.

# はじめに

githubにて RSAのhost-keyが更新されたそうです.
その関係で, RSA SSH でgithubに接続していた場合 `.ssh`等の中身をいじる必要があります.

[公式ブログ](https://github.blog/2023-03-23-we-updated-our-rsa-ssh-host-key/)を参考に更新しましょう.

しかし,更新した後に 以下のようなWarningが出るかもしれません.

```
$ git push
Warning: Permanently added the ECDSA host key for IP address '20.27.177.113' to the list of known hosts.
```

こちらは`github`のaddressであることがわかりました.

```
$ host github.com
github.com has address 20.27.177.113
```

危険ではないですが, 毎回Warning が出ると鬱陶しいため, 解消を行います.


### 試したこと 1. `ssh-keygen -R 20.27.177.113`
`.ssh/known_hosts`の内容について 

```
$ssh-keygen -R 20.27.177.113
```

として該当箇所を削除を続けても `git push`等をするたびに,引き続き Warningが出て 追加されてしまいました.


### 試したこと 2. 公式documentに従い 接続テスト

[SSH 接続をテストする by GitHub](https://docs.github.com/ja/authentication/connecting-to-github-with-ssh/testing-your-ssh-connection)

こちらについて,実行すると Warningが消えました.

```
$ ssh -T git@github.com
Hi <user-name>! You've successfully authenticated, but GitHub does not provide shell access.
```

butの後ろでGitHubについて少し説明していますが,しっかり権限が付与されたことが確認できました.

なぜかは不明ですが, この後の操作で `git push` を行ってもWarningは出ませんでした.

# 余談

`git push`をした際に `man-in-the-middle attack`を受けたよ!(could be attacked)
とWarningをくらったときはびっくりしましたが, 公式の変更があったことや 今後も引き続き使っていけるようで安心しました.

- 参考: [「SSHホスト鍵が変わってるよ！」と怒られたときの対処](https://qiita.com/hnw/items/0eeee62ce403b8d6a23c) でWarningの内容を見れます.


---

# 追記

また, この際に githubで 全てのsshについて RSA暗号ではなく, Ed25519にすることを考えました: [別の記事 『GitHubへの接続: RSA から Ed25519 変更』](https://qiita.com/making111/items/474bed55252146e528e2)
Azure SQL Databaseで意図的にtempdbとtempdb logの使用率を上げる方法

# はじめに
Azure SQL Databaseを扱う業務の中で、意図的にtempdbとtempdb logの使用率を上げて挙動を確かめたいということがあり、苦労した末に実現できたので、その方法を備忘録として残したいと思います。

# 概要
簡単にこの記事に出てくるものを説明します。

#### tempdb とは
Microsoft SQL Serverの一時データベースで、一時的なデータストレージや処理のために使用されます。

#### tempdb logとは
tempdbデータベースに関するトランザクションのログファイルです。

#### Azure SQL Databaseにおけるtempdb
Azure SQL Databaseはマネージド型のサービスであり、tempdbはAzureによって管理されています。
そのため、tempdbを直接操作して使用率を上げることはできませんが、一時テーブルを作成し、大量のトランザクションを処理させることで使用率を上げることが可能です。

https://learn.microsoft.com/ja-jp/sql/relational-databases/databases/tempdb-database?view=sql-server-ver16#tempdb-in-azure-sql

# 方法
以下にそのSQLの例を記載します。


```SQL:tempdb.sql
CREATE TABLE #t1(c1 CHAR(8000) NOT NULL);

BEGIN TRANSACTION
DECLARE @i INT = 1
WHILE @i <= 2000000
BEGIN
	INSERT INTO #t1 VALUES (REPLICATE('a', 8000))
	SET @i = @i + 1
END
COMMIT TRANSACTION

```

以上になります。

# 最後に
参考になれば嬉しいです！！
Power BI DesktopからMicrosoft TeamsのExcelデータを取得する方法(2023/03/24現在)

PL-900勉強中のPower Platform初心者の李と申します。:slight_smile:
Power BI研究中得た知識を皆さんに共有しようとしています。
この記事を投稿する理由は、Microsoft Teamsのアップデート(2023/03/09)後、Power BI DesktopからMicrosoft TeamsのExcelデータを取得する方法が少し変わったからです。:open_mouth:
(今後も、同じく、パラメーターが新しく追加されるか取得の方法が変わる可能性があることを念頭に置いてくださいませ。その意味合いで記事のタイトルに現在の日付を記入します。)

それでは、Power BI DesktopからMicrosoft TeamsのExcelデータを取得する方法について教えたいと思います。:mortar_board::writing_hand_tone1:

１．取り込みしたいファイルのURLをMicrosoft Teamsから取得する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114135/fa4ea1e4-879f-289e-2f57-be412cfcc034.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114135/07e40638-0930-5261-f4fc-72a301047228.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114135/ae9893ce-71f5-3291-2466-59562f6c3e0e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114135/4d6bcd22-ca47-77e7-0c82-826bb3fd99e0.png)
２．Power BI Desktopを開き、１で取得したファイルを取り込む。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114135/d1518a93-0f31-4cd3-bd1f-d4b88c81afdb.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114135/6763c353-5d1a-e52d-e76c-3ef300752abd.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114135/37c6aaed-69a5-e4b5-98a5-21f27e6dca17.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114135/2c67ff08-ad82-c3b1-cffd-4a403ba629fe.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114135/fd5a7b4a-59fe-8f1c-5a99-914f9a420bc3.png)

これで、Power BI DesktopからMicrosoft TeamsのExcelデータが取得できました。:v_tone1:
StroyBook v6.5.16 & TypeScript v5.0.2で発生したTypeErrorの解決

## 概要
Next.jsのプロジェクトにStorybookを導入し、起動したら以下のエラーが発生した。 

```
TypeError: typescript_1.default.createIdentifier is not a function 
```

1ヶ月、２ヶ月ほど前は発生しなかったので最近発生したみたいで、以下の情報が見つかった。

- https://qiita.com/rikuto125/items/5f54c1dd95085c3276a4
- https://github.com/storybookjs/storybook/issues/21642

ただ、私の場合は解決せず、上記のイシューから辿ったreact-docgen-typescript-plugin自体のイシューでコメントされている方法で解決した。

- https://github.com/hipstersmoothie/react-docgen-typescript-plugin/issues/78#issuecomment-1409224863

## 環境
- Node.js v18.15.0
- NPM v9.5.0
- Next.js v13.2.4
- TypeScript v5.0.2
- StroyBook v6.5.16


## 対応方法
react-docgen-typescript-pluginをインストールする。

```
npm i --save-dev react-docgen-typescript-plugin
```

.storybook/main.jsに以下を追加する。
```javascript
  "typescript": {
    "reactDocgen": "react-docgen-typescript-plugin"
  },
```

.storybook/main.jsの最終形は以下の通り。  
導入しての起動でエラーなので、デフォルトの状態に上記を追加した形となる。

```javascript
module.exports = {
  "typescript": {
    "reactDocgen": "react-docgen-typescript-plugin"
  },
  "stories": [
    "../src/**/*.stories.mdx",
    "../src/**/*.stories.@(js|jsx|ts|tsx)"
  ],
  "addons": [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/addon-interactions"
  ],
  "framework": "@storybook/react",
  "core": {
    "builder": "@storybook/builder-webpack5"
  }
}

```
CIQRCodeGeneratorを使ってQRコードを作成する

# 概要
iOSではiOS 13から、`CIQRCodeGenerator` というAPIが用意されており、これを用いることでQRコードの画像を簡単に生成することが可能になりました。
公式のドキュメントは以下になります。

https://developer.apple.com/documentation/coreimage/ciqrcodegenerator

この、CIQRCodeGeneratorを使ってのQRコード画像を生成してみたいと思います。


# CIQRCodeGeneratorを生成する
CIQRCodeGeneratorはprotocolであり、実際はCIQRCodeGeneratorに適合したCIFilterを作成する形になります。
CIFilterには `QRCodeGenerator` というそのものズバリのクラスメソッドが用意されているので、そちらを使ってCIFilterを生成し、`message`にQRコード化したいデータ、`correctionLevel`にはドキュメントにも記載のある通り、L, M, Q, Hから誤り訂正レベルを文字列で指定することになります。

以下はQITQrCodeGeneratorというクラスに生成処理を設けたコード例です。

```objc:QITQrCodeGenerator.h
#import <Foundation/Foundation.h>
#import <CoreImage/CIFilterBuiltins.h>


NS_ASSUME_NONNULL_BEGIN

@interface QITQrCodeGenerator : NSObject

+ (CIFilter<CIQRCodeGenerator>*)generator:(NSData* )data
                          correctionLevel:(NSString* )correctionLevel;

@end

NS_ASSUME_NONNULL_END
```


```objc:QITQrCodeGenerator.m
#import "QITQrCodeGenerator.h"

@implementation QITQrCodeGenerator

+ (CIFilter<CIQRCodeGenerator>*)generator:(NSData* )data
                          correctionLevel:(NSString* )correctionLevel
{
    CIFilter<CIQRCodeGenerator>* filter = [CIFilter QRCodeGenerator];
    filter.message = data;
    filter.correctionLevel = correctionLevel;
    return filter;
}
@end

```

# Swiftから使う

上記のコード例からわかる通り、iOS 13から追加されたCIQRCodeGeneratorは、**Objective-Cでしか使えません。**

なので上記クラスをブリッジしてSwiftで使うことになります。
サンプルとしてSwiftUIからQRコードを表示するためのコードを例示します。

ポイントとして、CIQRCodeGeneratorから生成されるCIImageは、そのままUIImageにあるinitで変換しようとしてもSwiftUI上で表示されないのと、SwiftUIはマルチプラットフォームなのでSwiftUI.Imageに変換するのが望ましいと考えたので、CIImage→CGImage→Imageの変換を行なっています。

```swift
struct ContentView: View {
    @StateObject private var model = DataModel()

    var body: some View {
        VStack {
            if let qrImage = model.qrImage {
                qrImage
            } else {
                Image(systemName: "globe")
                    .imageScale(.large)
                    .foregroundColor(.accentColor)
            }
            Text("Hello, world!")
        }
        .task {
            model.showQr(text: "適当な文字列")
        }
        .padding()
    }
}

final class DataModel: ObservableObject {
    @Published var qrImage: Image?
        
    func showQr(text: String) {
        let urlData: Data = text.data(using: .utf8)!
        let qrFilter = OADQrCodeGenerator.generator(urlData, correctionLevel: "H")
        
        // QRコードの拡大処理
        let qrOutputImage = qrFilter.outputImage!.transformed(by: .init(scaleX: 5, y: 5))
        let context = CIContext()
        let qrCgImage: CGImage = context.createCGImage(qrOutputImage, from: qrOutputImage.extent)!
        qrImage = .init(qrCgImage, scale: 1.0, label: Text(text))
    }
}
```

![Simulator Screen Shot - iPhone 14 Pro - 2023-03-24 at 18.21.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687960/ed031b54-1a7b-506c-8bc3-3d9c1e7d37b4.png)