OmniAICreator/Qiita-1.07M huggingface dataset:
Power Automate DesktopでGmail送信！

## Gmailの自動配信の様子
https://twitter.com/MitsuhiroM82423/status/1651608420280320000

みなさん、こんにちは。
紙、印鑑、手作業に埋もれて業務をしているX世代の会社員です。

**Power Automate Desktop**でメールの自動化を目指し作成しています。しかし、Outlookでのメール自動送信は、すんなり作成出来ましたが、Gmailだとうまく動きません。業務では、Gmailしか使用していないので、どうしても**Gmailで自動送信**したいです。

[Outlookで自動送信はこちら](https://qiita.com/miyabe-mitsuhiro/items/f69db1dd728696494e5f)

https://qiita.com/miyabe-mitsuhiro/items/f69db1dd728696494e5f

## 参考記事を見つけ、いざ設定！
[参考にした記事はこちら](https://note.com/uipath/n/nb046c0c1dd82)

https://note.com/uipath/n/nb046c0c1dd82

Power Automate Desktopではありませんが、同じ**RPAツール**のUiPathの設定を参考にさせていただきました。
## 使用するもの

・Power Automate Desktop
・Gmail
・Excel

## Excelの準備
Excelシートにデータを貼り付けていきます。
![2023-04-23 (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3288463/2b343e30-862c-8875-39ac-8d49ced031c6.png)


**`注：必ずデータをテーブルで保存してください。`**
![2023-05-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3288463/61e99ce4-2e32-3cc7-5010-1dd0fd42d6a2.png)


## Power Automate Desktopの設定
![2023-04-29 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3288463/749aeea9-755e-23ca-6e12-4bcd6a20304f.png)

**フローのソースコード**

```ruby:Gmail自動送信
Excel.LaunchExcel.LaunchAndOpenUnderExistingProcess Path: $'''C:\\Users\\miyabe.m\\OneDrive\\プロトタイピング2期\\0422_lesson3\\【確定回収用】割り戻し計算確認書回収チェック表_練習.xlsx''' Visible: True ReadOnly: False Instance=> ExcelInstance
Excel.SetActiveWorksheet.ActivateWorksheetByName Instance: ExcelInstance Name: $'''メール送信本文'''
Excel.ReadFromExcel.ReadAllCells Instance: ExcelInstance ReadAsText: False FirstLineIsHeader: True RangeValue=> ExcelData
LOOP FOREACH CurrentItem IN ExcelData
    Email.SendEmail.AuthenticateAndSend SMTPServer: $'''smtp.gmail.com''' Port: 465 EnableSSL: True Username: $'''miyabe.m@ga.mv-tokai.com''' Password: P'AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAZfwg9V/njEmvZ6u7yej+QwQAAAACAAAAAAADZgAAwAAAABAAAAAbgzbpIqI/HWO8YppqEKD3AAAAAASAAACgAAAAEAAAAFHGhS7z0bOlqdKTV//psLgoAAAAB95TsRcdOAtPRMRNEBbCiNSKsECOaAik8cFJBVK/zZFiyUBDK5eQ/RQAAAAMw1g7iLvTiNFlY/bxpPr++8vmRQ==' AcceptUntrustedCertificates: False SendFrom: $'''miyabe.m@gmail.com''' SenderDisplayName: $'''宮部光博''' SendTo: CurrentItem['To'] CC: CurrentItem['Cc'] BCC: CurrentItem['Bcc'] Subject: CurrentItem['件名'] Body: $'''%CurrentItem['本文']%
契約No %CurrentItem['契約No']%
件名 %CurrentItem['件名2']%
期間 %CurrentItem['期間開始']%～%CurrentItem['期間終了']%''' IsBodyHtml: False
END
```
## ポイントは、パスワード設定
[Googleアカウントのセキュリティ](https://myaccount.google.com/security)で「**2段階認証プロセス**」を有効にして、「**アプリ パスワード**」を生成する必要があります。

[Googleアカウントのセキュリティはこちら](https://myaccount.google.com/security)

https://myaccount.google.com/security

## 「メールの送信」アクションの設定
ここの**パスワード設定**が、Gmailの「ログインパスワード」ではなく、「**アプリパスワード**」でした。
![2023-04-29 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3288463/1ab6c6ac-07c9-3474-2c72-5eea3b015f60.png)

ちょっとしたことですが、このパスワード設定が、アプリパスワードだとわかるのに苦労しました。
**パスワード**って色々ありますね～。
【Rails】rails sでエラーが発生する　`initialize': Address already in use - bind(2) for "127.0.0.1" port 3000 (Errno::EADDRINUSE)

## 状況
rails sでサーバーを立ち上げようとしたら以下のエラーが発生しました。
```
$ bin/rails s
=> Booting Puma
=> Rails 6.1.7.3 application starting in development 
=> Run `bin/rails server --help` for more startup options
Puma starting in single mode...
* Puma version: 5.6.5 (ruby 3.2.1-p31) ("Birdie's Version")
*  Min threads: 5
*  Max threads: 5
*  Environment: development
*          PID: 8832
Exiting
/Users/name/app_name/vendor/bundle/ruby/3.2.0/gems/puma-5.6.5/lib/puma/binder.rb:341:in `initialize': Address already in use - bind(2) for "127.0.0.1" port 3000 (Errno::EADDRINUSE)
```
しかしpsコマンドで、実行されているプロセスを確認してもサーバーは表示されませんでした。
また、tmp/pids/server.pidの値を削除してみても直らず。

## 解決法
以下のコマンドでport 3000を使用しているプロセスを表示します。
```
$ lsof -i :3000
ruby    32184 name   13u  IPv4 0xbceeb2e3b353     0t0  TCP localhost:hbci (LISTEN)
ruby    32184 name   15u  IPv6 0xbceeb2e875f5      0t0  TCP localhost:hbci (LISTEN)
```
表示されたプロセスをkillします
```
$ kill 32184
```
これでサーバーを再度起動させることができました。
［JavaScript］オブザーバパターン

## この記事で書くこと
- オブザーバパータンを JavaScript で実装する

## オブザーバパターン
- 状態変化に応じた処理を記述する際に使用
- 観察対象の状態が変化すると、観察者に対して通知する

## コード
```JavaScript:sample.js
class Observer {
    update = (generator) => { };
}

class NumberGenerator {
    #observers = [];
    addObserver = (observer) => {
        this.#observers.push(observer);
    }
    notifyObservers = () => {
        this.#observers.forEach((observer) => {
            observer.update(this);
        });
    }
    getNumber = () => { throw new Error("Line15 Error"); }
    execute = () => { throw new Error("Line16 Error"); }
}

class RandomNumberGenerator extends NumberGenerator {
    #number;
    getNumber = () => this.#number;
    execute = () => {
        let count = 0;
        let notifyFunction = setInterval(() => {
            count++;
            this.#number = Math.round(Math.random() * 20); // 0 から 20 までの乱数（整数）を生成
            this.notifyObservers();
            if (count === 20) { clearInterval(notifyFunction) };
        }, 1000);
    }
}

class DigitalObserver extends Observer {
    update = (generator) => {
        console.log(`DigitalObserver: ${generator.getNumber()}`);
    }
}

class GraphObserver extends Observer {
    update = (generator) => {
        console.log(`GraphObserver: ${"*".repeat(generator.getNumber())}`);
    }
}

const main = () => {
    const generator = new RandomNumberGenerator();
    const observer1 = new DigitalObserver();
    const observer2 = new GraphObserver();
    generator.addObserver(observer1);
    generator.addObserver(observer2);
    generator.execute();
}

main();
```

## 実行結果
- 1秒ごとに乱数（0から20の整数）を発生
- 1秒ごとにその乱数に応じた処理結果をコンソールに出力する

```
GraphObserver: **********
DigitalObserver: 12
GraphObserver: ************
DigitalObserver: 13
GraphObserver: *************
DigitalObserver: 19
GraphObserver: *******************
DigitalObserver: 8
GraphObserver: ********
DigitalObserver: 19
GraphObserver: *******************
DigitalObserver: 11
GraphObserver: ***********
DigitalObserver: 5
GraphObserver: *****
DigitalObserver: 1
GraphObserver: *
DigitalObserver: 18
GraphObserver: ******************
DigitalObserver: 10
GraphObserver: **********
DigitalObserver: 4
GraphObserver: ****
DigitalObserver: 1
GraphObserver: *
DigitalObserver: 4
GraphObserver: ****
DigitalObserver: 8
GraphObserver: ********
DigitalObserver: 20
GraphObserver: ********************
DigitalObserver: 17
GraphObserver: *****************
DigitalObserver: 19
GraphObserver: *******************
DigitalObserver: 12
GraphObserver: ************
DigitalObserver: 2
GraphObserver: **
```
headとtailを組み合わせるのは疲れた

長大なログファイルから特定の行だけを見たい。

そんな時にheadやtailコマンドを組み合わせて特定の行のみを抽出して閲覧することはよくあるだろう。

**でもめんどくさい**。

「長大なログファイルの**12267行目**から**12504行目**まで欲しい」
それをheadとtailで実現すると次のようになる。

```sh
head -n 12504 very_long.log | tail -n 237
```

**すぐに引き算ができただろうか？**

僕にはできなかった...
(暗算は苦手なのだ...)

計算が手間ならexprコマンドを使う技もある。
```sh
head -n 12504 very_long.log | tail -n $(expr 12504 - 12267)
```

**長い！！！**

たかだかログファイルの一部を抽出するのにこんなに長々とコマンドを打つのは辛い...

もっと簡単にログファイルの一部のみを抽出する方法はないものか...
それこそPythonのスライス(slice)構文のように、どの行からどの行までという指定はできないものか...

**はい、ないなら作れば良いですね！**

作りました。

https://github.com/ChanTsune/slice


sliceで「**12267行目**から**12504行目**まで欲しい」を実現すると次のようになる。

```sh
slice 12267:12504 very_long.log
```

**シンプル！！!**

先程のhead,tail,exprの組み合わせと比べるとどうだろう？

```sh
head -n 12504 very_long.log | tail -n $(expr 12504 - 12267)
```
```sh
slice 12267:12504 very_long.log
```

**シンプル！！！圧倒的にシンプル！！！！**
パッと見で何をやりたいかも自明です！

というわけで以下インストール方法

## インストール方法

Rust製なのでcargoでインストール

```sh
cargo install slice-command
```
cargoのインストールは[こちら](https://www.rust-lang.org/ja/tools/install)から

一応、Mac,Linuxユーザーであればhomebrewでもインストールできるようにはしているが、cargoでのインストールを推奨
```sh
brew install chantsune/tap/slice
```

## 使い方

```sh
slice [オプション] <slice> <file...>
```

`<file>`はスライスを適用したいファイルのパス、`<slice>`はファイルに適用したいスライス構文。
`<file>`が指定されていない場合、`slice`は標準入力から読み込む。

スライス構文は、Pythonのスライス構文に似ており、`start:end:step`の形式を取る。
各値はオプションであり、省略された場合は、それぞれファイルの先頭、ファイルの末尾、ステップ1をデフォルト設定として利用する。

### 例

`file.txt`の10行目から20行目までの内容をスライス。
```
slice 10:20 file.txt
```

`file.txt`の先頭から100行目までの内容をスライスし、2行おきにスキップ。
```
slice :100:2 file.txt
```

-cオプションを付けるとスライスの単位を行ではなく文字とすることができる。

```sh
slice -c 10:20 file.txt
```

2023/10/17追記)

文法を少し拡張して便利にしました。

### 開始位置から指定の行数を切り出すパターン
```
slice 100:+50 very_long.log
```
これは以下と等価
```
slice 100:150 very_long.log
```

### 対象行の前後を切り出すパターン
```
slice 100:+-20 very_long.log
```
これは以下と等価
```
slice 80:120 very_long.log
```

### おわりに

不具合等あれば報告してもらえると嬉しいです！

https://github.com/ChanTsune/slice/issues

また、星がもらえると筆者が飛んで喜びます！

以上、拙作のsliceコマンドの紹介でした！
windowsでmac風に入力する

# 目的
windowsでmacbookのようなキーボードの使い心地を実現したい。コマンドの位置や言語切り替えをMac風にしたい。

# 方法
windowsPCで管理者権限がある場合は[PowerToys](https://learn.microsoft.com/ja-jp/windows/powertoys/install) (windows公式のカスタマイズアプリ) を素直にインストールして利用する。

管理者権限がなくて素直にインストールできない場合、PowerToysをscoopを使ってインストールするとうまくいった。

## 1. Powershellでscoopをインストール
まずはWindows画面左下の検索🔎などでPowershellを探して開く。

<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267311/109d08eb-29f5-b271-d1e6-f067459e4fd9.png">

[下記スクリプト](https://qiita.com/rhene/items/d8a0c0c7d637904e14da)をPowershellで実行する。ポリシー変更のために文言が出てくるのでYを押す[1]。
```
Set-ExecutionPolicy RemoteSigned -scope CurrentUser
invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh')
```

これでscoopがインストールできた。

## 2. scoopでPowerToysをインストール
次にscoopを使ってPowerToysをインストールする。[windows公式](https://learn.microsoft.com/ja-jp/windows/powertoys/install#install-with-scoop)にやり方が載っているのでその通りに行う[2]。
下記コマンドをPowershellで実行する。

```
	scoop bucket add extras
	scoop install powertoys
```
これで目的のPowerToysがインストールできた。

## 3. PowerToysを起動し設定を行う
Windows画面左下の検索🔎で探して、PowerToysを起動する。
キーボードマネージャーを探して設定する。
キーの再マップの詳しいやり方は[こちら](https://learn.microsoft.com/ja-jp/windows/powertoys/keyboard-manager)。

<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267311/d0c6e59b-eb7c-f3c1-17c2-b3458fcb83a0.png">

この人の[マッピング](https://qiita.com/ktanoooo/items/ba4b7098ebb4d790cec8#microsoft-powertoys)とかは結構よさそう[3]。

# 参照
[1]https://qiita.com/rhene/items/d8a0c0c7d637904e14da
[2]https://learn.microsoft.com/ja-jp/windows/powertoys/install#install-with-scoop
[3]https://qiita.com/ktanoooo/items/ba4b7098ebb4d790cec8#microsoft-powertoys
【Linux】実行したコマンドを履歴に残さないようにする方法

## はじめに

BashやZshにおいて実行したコマンドを履歴に残さない方法について記載します。  

## Bash

Bashの場合には`~/.bashrc`に以下を追記します。  

```:~/.bashrc
export HISTCONTROL=ignorespace
```

すると先頭にスペースを入力して実行したコマンドの履歴は`.bash_history`に保存されなくなります。  

## Zsh

Zshの場合には以下を`~/.zshrc`に追記します。  

```:~/.zshrc
setopt HIST_IGNORE_SPACE
```

すると先頭にスペースを入力して実行したコマンドの履歴は`.zsh_history`に保存されなくなります。
初学者の私がGitを理解するために、この順番で読めばよかったと思った記事の順番

エンジニア未経験のわたしがGitを学ぶ上で、この流れで記事を読むべきだったと思ったことを記載する。
完全に初学者意見のため、疑いながら読んでください。

私は下記の流れで学習することによって、理解をしやすいように感じた。

①　Gitで何をしているかのイメージを掴む（コマンドなし）
②　Gitのイメージを、コマンドで実現している記事をみる
③　実際にGitのコマンドを打ちながら、出力と、頭の中のイメージのすり合わせ

## 　Gitで何をしているかのイメージを掴む（コマンドなし）

https://qiita.com/noshishi/items/2821c01d590bf9c96038

こちらの記事は、Gitのイメージをコマンドなしで、わかりやすく図で示してくださっています。

記事にも記載されていますが、
・重要なのは 「何」から「何」へ・「どんな作業」を行う のかを追う
・操作前と操作後でどんなことが起こっているのかをイメージする

上記の内容が、すごく同意で、重要だと感じている。いきなりコマンドを打ちながら理解しようとすると、何を目的にこの操作をしているのかがわからなくなります。〇〇の操作を行う事によって、どんなことが起こり、メリットが生まれるのかを考えながら学習することが重要であり、コマンドを打つ準備段階の記事だと感じました。

## Gitのイメージを、コマンドで実現している記事をみる

https://qiita.com/satona-oinuma/items/97205ca0ce04dcae2adb

こちらの記事は丁寧に、ターミナルでの`操作`＋`操作後の結果`を記載してくださっているので、実際にコマンド操作をしたあとにどのような結果が表示されるのかを、見ることができます。実際に手を動かしながら、学習することも良いとは思います。ただ、私にとっては、コマンドを打つ→結果を確認する→コマンドをうつ→結果を確認する→...を繰り返すよりも、コマンドを打った結果がどうなるんだろうな。。ということを想像しながら記事をみる方が学習しやすかった。実際に問題文をみて、答え合わせをする感覚に近い。コマンドを打つ作業を減らして、私の頭の中のイメージと、コマンドを含めた出力結果がそのイメージ通りの結果になっているかどうかを、すり合わせて行く作業が重要だと感じた。

## 実際にGitのコマンドを打ちながら、実際の出力と、頭の中のイメージのすり合わせ

 https://qiita.com/renesisu727/items/248cb9468a402c622003

次にこちらの記事を用いて、実際にコマンドを打ちながら、頭の中のイメージと、出力結果を見ながら進めていく。
したいこと・目的を意識しながら、現在のコミットどこまでしているか`git log `、どこのブランチにいるか`git branch`を適宜確認しながら、進めていくとより理解しやすいように感じた。

以上が私が色んな記事を見て、この順番で学習したほうが良かったと思った記事集でした。


他にも良い記事があれば、コメントいただけると大変うれしいです。
良かったと思ったら、いいねやTwitterのフォローよろしくお願いいたします！

https://sites.google.com/view/muranakar
個人でアプリを作成しているので、良かったら覗いてみてください！
Route53

# Route53とは
フルマネージド型のDNS（ドメインネームシステム）サービス
* 独自ドメインを購入可能。
* ヘルスチェック機能
* ルーティングポリシー機能、様々な種類がある。

# ルーティングポリシー
* フェールオーバールーティング
障害発生時のルーティング、sorryページへのルーティングなどを行う。
* シンプルルーティング
１つのリソースに対してルーティング。
* 加重ルーティング
複数のリソース対してのルーティング
どのリソースに何％の比率で振り分けるか重み付けが可能。
* レイテンシールーティング
複数のリージョンにまたがってサービスを展開している場合に有効
一番応答時間が早いリソースへ通信を流していく。
* 位置情報ルーティング
複数のリージョンにまたがってサービスを展開している場合に有効
リクエストが発生した地域に近いリージョンに向けて通信を発生させる
* 複数値回答ルーティング
１つのDNSの問い合わせに対して複数の値を返却するルーティング。
オプションでヘルスチェックも付与可能。

# レコード
* Aliasレコード
ドメインとAWSサービスの関連付け
* Aレコード
ドメインとIPv4アドレスの関連付け
* AAAAレコード
ドメインとIPv6アドレスの関連付け
* NSレコード
ドメイン情報を管理するサーバ
* SOAレコード
ドメインの管理情報を現したレコード
* CNAMEレコード
ドメインとURLの関連付け
Aliasと比較すると、名前解決が2度手間になってしまう＆追加料金有りとなってしまうため基本的にはAliasレコード使用を推奨
[AWS Q&A 365][SES]AWSのよくある問題の毎日5選 #42

# 1. Amazon SESでは、電子メールの受信制御にどのような方法がありますか？ 
A：Amazon SESは、受信者ベースの制御を使用した受信ルールと、IPアドレスフィルタを使用したIPベースの制御の2つの方法で、電子メールの受信を制御します。 

# 2. Amazon SESでメール受信用のドメインをどのように確認できますか？ 
A：Amazon SESでメール受信用のドメインを確認するには、ユーザーはMXレコードを公開し、Amazon SESが自分たちに代わってメールを受信する権限を与える必要があります。 

# 3. Amazon SESでのメール受信のユースケースと制限事項は何ですか？ 
A：Amazon SESでのメール受信のユースケースには、顧客からのメール受信、受信メールの処理、および受信メールの別のメールアドレスへの転送が含まれます。制限事項には、確認できるメールアドレスとドメインの数に制限があり、1秒あたりに受信できるメールの数に制限があります。 

# 4. Amazon SESでメール受信のイベント通知を設定する方法は？ 
A：Amazon SESでメール受信のイベント通知を設定するには、ユーザーはイベントの宛先を作成し、通知を受け取りたいイベントのタイプを指定する必要があります。 

# 5. Amazon SESのアカウントレベル抑止リストとは何ですか？ どのように有効にできますか？ 
A：Amazon SESのアカウントレベル抑止リストは、ユーザーのアカウントからのメール受信を拒否したメールアドレスのリストです。これを有効にするには、Amazon SESコンソールにアクセスし、「抑止リスト」タブを選択し、「アカウントレベル抑止リスト」タブをクリックします。そこから、ユーザーは個々のメールアドレスを追加するか、メールアドレスのリストを抑止リストにインポートできます。
[AWS Q&A 365][SES]Daily Five Common Questions #42

# 1. What are the different methods for controlling email receiving in Amazon SES? 
A: Amazon SES provides two methods for controlling email receiving - recipient-based control using receipt rules and IP-based control using IP address filters. 

# 2. How can one verify their domain for email receiving in Amazon SES? 
A: To verify their domain for email receiving in Amazon SES, users need to publish an MX record and give permission to Amazon SES to receive emails on their behalf. 

# 3. What are the use cases and restrictions for email receiving in Amazon SES? 
A: The use cases for email receiving in Amazon SES include receiving emails from customers, processing incoming emails, and forwarding incoming emails to another email address. The restrictions include a limit on the number of email addresses and domains that can be verified and a limit on the number of emails that can be received per second. 

# 4. How can one set up event notifications for email receiving in Amazon SES? 
A: To set up event notifications for email receiving in Amazon SES, users need to create an event destination and specify the types of events they want to receive notifications for. 

# 5. What is the account-level suppression list in Amazon SES and how can it be enabled? 
A: The account-level suppression list in Amazon SES is a list of email addresses that have opted out of receiving emails from the user's account. It can be enabled by going to the Amazon SES console, selecting the Suppression Lists tab, and clicking on the Account-level suppression list tab. From there, users can add individual email addresses or import a list of email addresses to the suppression list.
Atcoder Problems に参加してみた

# 0. はじめに
就活が終わった24歳、学生です。
AtCoderの過去問をやっていくにあたって、以下のような素晴らしいサービスがありました:

+ [AtCoder Problems](https://kenkoooo.com/atcoder/)

とりあえずここに載っている問題をやっていきます。
コンテスト形式なので、気軽にコンテストさながらの緊張感で問題を解いていけそう。初参加。備忘録として、詰まった問題や、解けたけど時間がかかり過ぎた問題などを記していこうと思います。コンテストは「まよコン」というものに参加させていただきました。

# 1. 詰まった問題など
## その1 :  [ABC 148 E - Double Factorial](https://atcoder.jp/contests/abc148/tasks/abc148_e) (500 点)

-----
**【問題概要】**
$0$以上の整数$n$に対し、$f(n)$を次のように定義します。
 
+ $f(n)=1$ ($n<2$のとき)
+ $f(n)=nf(n-2)$ ($n\geq2$のとき)

整数$N$が与えられます。$f(N)$を$10$進法で表記した時に末尾に何個の$0$が続くかを求めてください。

**【制約】**

+ $0 \le N \le 10^{18}$
+ $N$ は整数

**【数値例】**
1)
　$N = 12$
　答え: 1

$f(12)=12×10×8×6×4×2=46080$ なので、末尾の$0$の個数は$1$個。

-----
**【考えていたこと】**
+ 問題文の関数を愚直に実装すると、Nが大きすぎる時に計算時間がエグいことになる
+ $f(n)=n!!$であることに気づいた
+ $n$が奇数なら0だし、偶数なら素因数$5$の個数が答えになる？。高校数学かな？

数学的な発想は至ったが、コードにする前にタイムオーバーになってしまった。難しい。

**【ポイント】**
+ あ


**【他の人の提出で通ってたやつ】**
```
n = int(input())

cnt = 0
if n % 2 == 0:
    i = 1
    while n // 5 ** i > 0:
        cnt += (n // 5 ** i)//2
        
        i += 1

print(cnt)
```
$5^1$の倍数, $5^2$の倍数, $5^3$の倍数, ...の数を数えて行って総和を求めている。

# 2. おわりに
初めてのバチャコンでしたが、思いのほか集中できて楽しかったです。他の人も同時に解いているというのは思いの外モチベになりますね。当分は、バチャコンに参加しながら解放パターンを増やしていきたいです。

この記事を書く際、markdownの書き方は以下のリンクを参考にしました。
https://mathlandscape.com/latex-equal/
情報セキュリティに関する資格まとめ

# はじめに
情報セキュリティの仕事をやることになりましたが、どうやって知識をつければよいのかさっぱりわかりません。
そんな時は手っ取り早く資格の勉強で知識をつければ良いんじゃないかと考えまして、情報セキュリティ系の資格を調べてみました。

# 国内系
### 情報処理安全確保支援士試験
情報セキュリティについて高度な知識やスキルを求められる国家試験のようです。
合格した後、登録を行うと「情報処理安全悪保支援士」という国家資格を取得できるようです。登録した場合、維持が必要なようで３年間で14万円程度かかるようです。高いですね:fearful:

https://www.ipa.go.jp/shiken/kubun/sc.html

### 情報セキュリティマネジメント試験
マネジメントよりの国家試験のようです。
こちらは維持費用などはないようです。

https://www.ipa.go.jp/shiken/kubun/sg/index.html

### 情報セキュリティ管理士認定試験
一般財団法人 全日本情報学習振興協会が主催するセキュリティの資格。
出題は範囲をみると、こちらもマネジメント寄りの資格に見えます。
ChatGPTで調べると、質問するたび答えが変わる不思議な資格。他にもあるのかもしれません。

https://www.joho-gakushu.or.jp/isme/

# 海外系
### CISSP（Certified Information Systems Security Professional）
国際的な情報セキュリティ・プロフェッショナル認定資格とのこと。
Twitterを見ていると、取得を目指している方が多いように見えます。
受験料は749米ドルだそうです。高い:open_mouth:

https://japan.isc2.org/cissp_about.html

### CISA（Certified Information Systems Auditor）
情報システム監査に関する資格のようです。取得には実務経験が必要なようで、セキュリティ未経験者がいきなり目指すものではなさそうです。

https://www.isaca.gr.jp/cisa/
### GIAC（Global Information Assurance Certification）
SANS Instituteが主催する、情報セキュリティに関する様々な分野での専門的な知識やスキルを認定する資格とのこと。、GSEC、GCIH、GPENなど様々な試験があるようです。

https://www.sans-japan.jp/giac

### CompTIA Security+
CompTIAが主催する、情報セキュリティの基礎的なスキルと知識を認定する資格のようです。Security+ のほか、PenTest+、Cybersecurity Analystなど様々な試験があるようです。

https://www.comptia.jp/certif/core/comptia_security/

### CEH（Certified Ethical Hacker）
エシカルハッカーとしてのスキルを認定する資格とのこと。受験にはトレーニングを受ける必要があるようです。日本語の公式サイトが見つからず、代行する企業がトレーニングと受験をセットで提供しているようです。
エシカルでないハッカーの資格はあるのでしょうか:rolling_eyes:

https://www.eccouncil.org/train-certify/certified-ethical-hacker-ceh/

### CND（Certified Network Defender）
CEHと同じ、EC-Councilが認定している資格とのこと。防御する側の資格のようです。

https://www.eccouncil.org/train-certify/certified-network-security-course/

# クラウド系
### AWS 認定セキュリティ
AWS上でのセキュリティに関する資格試験とのこと。

https://aws.amazon.com/jp/certification/certified-security-specialty/

### Professional Cloud Security Engineer
GCPに特化したセキュリティ資格試験とのこと。

https://cloud.google.com/certification/cloud-security-engineer?hl=ja

### Microsoft Certified: Azure Security Engineer Associate
Azureに特化したセキュリティ資格試験のこと。
資格の取得には「試験 AZ-500: Microsoft Azure セキュリティ テクノロジ」という試験に合格する必要があるようです。

https://learn.microsoft.com/ja-jp/certifications/azure-security-engineer/

# まとめ
情報セキュリティの資格といってもマネジメント系・監査系・テクニカル系など様々なものがあり、闇雲に取得を目指すと目的とする知識が得られないかもしれないと思いました。また国内よりも海外の方が種類が多いと思いました。
そして一番気になったのはコスト面で、受験料や維持費が高額なので、個人だと厳しい気もしております:sweat_smile:
PEM形式の秘密鍵からJKS形式のキーストアを作成する

Salesforceに証明書をインポートするにはJKS形式のキーストアに変換する必要があります。秘密鍵から自己署名証明書を作成してJKS形式のキーストアを作成したり、PKCS12形式のキーストアをJKS形式に変換してアップロードします。アップロードした証明書はSSOリクエスト署名、APIクライアント、ドメイン証明書として使用できます。

### 1. PEM形式の秘密鍵から証明書署名要求（CSRファイル）を作成する
```console
$ openssl req -new -key server.key -out server.csr
    Country Name (2 letter code) []:JP
    State or Province Name (full name) []:TOKYO
    Locality Name (eg, city) []:Chiyoda
    Organization Name (eg, company) []:CompanyName
    Organizational Unit Name (eg, section) []:UnitName
    Common Name (eg, fully qualified host name) []:Test
    Email Address []:
```

### 2. 自己署名デジタル証明書(CRTファイル)を作成する
```console
$ openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt
```

### 3. PKCS12形式のキーストアを作成する
```console
$ openssl pkcs12 -export -name signedcert -in server.crt -inkey server.key -out keystore.p12
export password:
```

### 4. JKS形式のキーストアを作成する
```console
$ keytool -importkeystore -srckeystore keystore.p12 -srcstoretype pkcs12 -destkeystore keystore.jks -deststoretype jks -alias signedcert
出力先キーストアのパスワードを入力してください:
新規パスワードを再入力してください:
ソース・キーストアのパスワードを入力してください:
```

## Appendix
### 秘密鍵のパスフレーズを解除する
`-----BEGIN ENCRYPTED PRIVATE KEY-----`から始まる秘密鍵のパスフレーズを解除して`-----BEGIN PRIVATE KEY-----`から始まる秘密鍵に変換する。

```
openssl pkcs8 -topk8 -nocrypt -in your_private_key.pem -outform PEM
```

## 参考
- [非公開鍵と自己署名デジタル証明書の作成 | Salesforce DX 開発者ガイド | Salesforce Developers](https://developer.salesforce.com/docs/atlas.ja-jp.242.0.sfdx_dev.meta/sfdx_dev/sfdx_dev_auth_key_and_cert.htm?_ga=2.43114208.439795187.1656333652-1742453021.1655933163)
- [Generate a salesforce compatible JKS from PFX or P12](https://help.salesforce.com/s/articleView?id=000381987&type=1)
Dockerを使用してWireguardサーバーをインストール



### envfile：
```
SERVERURL=外部IPまたはドメイン名
SERVERPORT=51820
PEERS=3
PEERDNS=あなたのDNS
INTERNAL_SUBNET=10.6.0.0/24
ALLOWEDIPS=10.6.0.0/24
```

### 説明：
ALLOWEDIPSは、IPアドレスの範囲を指定するものです。このフィールドを設定すると、wgクライアントはこれらのサブネットをwgインターフェイスにルーティングし、INTERNAL_SUBNETを追加することができます。これにより、ピア同士が通信できるようになります。また、0.0.0.0/0を追加することもできます。これにより、クライアントのすべてのトラフィックがサーバーに転送されます。

PEERDNSは、生成されたクライアント構成のDNSアドレスです。サーバーのアドレスを設定することもできますし、一般的なDNSアドレスを設定することもできます。

### docker-compose.yaml ファイル：
```
version: "3.3"

services:
  wireguard:
    image: linuxserver/wireguard
    restart: always
    env_file:
      - ./conf/wg_config/env
    environment:
      PUID: "1000"
      PGID: "1000"
    volumes:
      - ./conf/wg_config:/config
      - /lib/modules:/lib/modules
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    sysctls:
      - net.ipv4.conf.all.src_valid_mark=1
      - net.ipv4.ip_forward=1
    ports:
      - 51820:51820/udp
 ```

Wireguardは、カーネルモジュールでサポートされているため、cap_addのSYS_MODULEは必須です。

sysctlsの役割は、サーバーをルーターとして動作させ、ピア間のトラフィック転送を実現することです。

### サーバーの起動：

`docker-compose up -d`

docker-composeでサービスを起動すると、./conf/wg_configディレクトリに構成ファイルが自動的に生成されます。以下は、peer1からpeer2まで、クライアントが使用する自動生成された構成ファイルです。peer.confを直接インポートすることができ、peer.pngをスキャンしてクライアントにインポートすることができます。

```
drwxr-xr-x  2 opc  opc  4.0K Feb  3 15:44 coredns
drwxr-xr-x  2 root root 4.0K Feb 28 09:12 custom-cont-init.d
drwxr-xr-x  2 root root 4.0K Feb  3 15:44 custom-services.d
-rw-------  1 opc  opc   193 Feb  3 15:49 .donoteditthisfile
drwx------  2 opc  opc  4.0K Feb  3 15:44 peer1
drwx------  2 opc  opc  4.0K Feb  3 15:44 peer2
drwx------  2 opc  opc  4.0K Feb  3 15:44 peer3
drwxr-xr-x  2 opc  opc  4.0K Feb  3 15:44 server
drwxr-xr-x  2 opc  opc  4.0K Feb  3 14:35 templates
-rw-r--r--  1 opc  opc   677 Feb  3 15:49 wg0.conf
```

custom-cont-init.dには、サーバー起動時に自動的に実行されるシェルスクリプトを配置することができます。通常、追加のルーティングテーブル設定やファイアウォール設定などを配置することができます。
Dockerコンテナ内でFastAPIアプリケーションの起動エラーの解決

## 概要
本稿では、Dockerコンテナ内でFastAPIアプリケーションを起動する際に発生したエラーとその解決方法について論じる。アプリケーションがIPv6アドレスでバインドしようとして失敗した時の対処方法を以下に説明する。

## 本件のエラー
```shell
ssh-python | ERROR:    [Errno 99] error while attempting to bind on address ('::1', 8080, 0, 0): 
```
## IPv6アドレスでのバインドエラー：
エラー内容：FastAPIがIPv6アドレス(::1)でポート8080をバインドしようとしたが、そのアドレスが利用できないことを示していた。

解決策：FastAPIがIPv4アドレス(0.0.0.0)でポートをリッスンするように変更する。main.py（またはFastAPIを実行しているファイル）で、uvicorn.run()関数のhost引数を"0.0.0.0"に設定する。この変更により、FastAPIはすべてのIPv4アドレスでリッスンし、Dockerコンテナ内で正常に起動できる。

```python
from fastapi import FastAPI

app = FastAPI()

# ... その他のルートや設定 ...

if __name__ == "__main__":
    uvicorn.run("main:app", host="0.0.0.0", port=8080, reload=True)
```
DJI Mobile SDK V5 Sample Codeを動かしてみた

# はじめに
DJIのドローンにはMobile SDKを利用してスマホアプリを開発できるものがあります。
今回はサンプルプログラムをビルドして実際にMini3と接続してみました

# 前提条件
* Android Studio Flamingo
* [DJI Mini 3](https://www.dji.com/jp/mini-3)
* [Huawei Mate 20](https://www.gsmarena.com/huawei_mate_20-9367.php)


# APIキーの発行
* Mobile SDKを利用するためにはDJI Developerに登録してAPIキーを発行する必要があります。
0. DJI Developerに登録します
* [DJI Developer](https://developer.dji.com/)に行き、DJIアカウントを持っていなければ作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2584877/07a32556-1e24-d2e4-2905-0f71f1242531.png)

0. APIキーを発行します
* DJI Developerにログインします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2584877/1eda7d11-dda2-1f5c-dff5-00f52ced76dd.png)
* APIキーの作成ボタンを押下します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2584877/6df82645-9813-ceb9-850f-f8e0df581c7a.png)
* 必要な情報を入れて、作成します
:::note warn 
Package Nameは下記と同一のものとしてください(サンプルコードと同一にするため)
:::
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2584877/58e16038-b093-4374-5950-ef6b5e22cfa8.png)
* メールがくるのでAPIキーを有効にします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2584877/21460e0a-f031-2532-f1df-743aff4687a3.png)
* APIキーをメモします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2584877/13066778-de86-611e-e5a3-b6d694e36255.png)

# サンプルソースのビルド
0. [サンプルコード](https://github.com/dji-sdk/Mobile-SDK-Android-V5)をcloneします
0. プロジェクトをOpenします(Mobile-SDK-Android-V5\SampleCode-V5\android-sdk-v5-as)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2584877/a9c128fe-23b3-83d7-8020-ec0b38f0f4c6.png)

0. APIキーを入力します
```Kotlin:Mobile-SDK-Android-V5\SampleCode-V5\android-sdk-v5-as\gradle.properties
#gralde build config
org.gradle.daemon=true
org.gradle.parallel=true
org.gradle.configureondemand=true
org.gradle.jvmargs=-Xmx4608M

#use androidX
android.useAndroidX=true
android.enableJetifier=true

android.disableResourceValidation=true

#build config
ANDROID_MIN_SDK_VERSION=23
ANDROID_TARGET_SDK_VERSION=29
ANDROID_COMPILE_SDK_VERSION=29
KOTLIN_VERSION = 1.6.10
#NDK_VERSION = 21.3.6528147

#msdk api key
AIRCRAFT_API_KEY = ここにAPIキーを入れてね！！！
#map key
```
0. スマホを接続してビルドすると、以下のアイコンが表示されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2584877/f00c8dee-6655-fd61-1e96-0ae4d3dcd9b9.png)
0. アイコンをタッチして以下の画面が表示されれば成功です
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2584877/58bd757a-0ce3-8e3c-1e1a-35dd3caf1ded.png)

# ドローンに接続
0. Mini 3とプロポ(送信機)を起動し、スマホをプロポに接続します
::: note 
以下の画面が表示された場合「ファイルの転送」を選択してください
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2584877/7b4bfb8b-f2bc-3c7b-5fe7-f572acdaeb86.png)
:::

0. Product Nameが更新されれば成功です
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2584877/2c73a0ae-f0e7-352e-df86-34f1f3423767.png)


# 備考
今回使用した機体のほかに2023年8月時点では以下の機体がサポートされています。
* DJI Mini3 Pro
* DJI Mini3
* Mavic 3 Enterprise Series
* M30 Series
* M300 RTK
* Matrice 350 RTK
【Python】Rust版Pandas 'Polars'備忘録

## Polarsとは
Rustで構成されたPandasを強く意識したPythonライブラリ。
Pandasより実行スピードが早いのが特徴。

## API

### Input/output

https://pola-rs.github.io/polars/py-polars/html/reference/io.html

### SeriesのMethod

https://pola-rs.github.io/polars/py-polars/html/reference/series/index.html

### DataFrameのMethod

https://pola-rs.github.io/polars/py-polars/html/reference/dataframe/index.html

### LazyFrameのMethod

https://pola-rs.github.io/polars/py-polars/html/reference/lazyframe/index.html

### Expressions(評価式)

https://pola-rs.github.io/polars/py-polars/html/reference/expressions/index.html

### Function(関数)

https://pola-rs.github.io/polars/py-polars/html/reference/functions.html

### SQL

https://pola-rs.github.io/polars/py-polars/html/reference/sql.html

## 実際のコード

```python
import os
import sys
import time
import glob
import re
import datetime
import csv
import numpy as np
import polars as pl

# 現在時間取得
now = datetime.datetime.now()
today = now.strftime('%Y-%m-%d %H:%M')

# 引数取得
args = sys.argv
print(os.path.abspath(args[1]))
input_path = os.path.abspath(args[1])
basename = os.path.basename(input_path)
basename_wo_ext = os.path.splitext(os.path.basename(input_path))[0]
dirname = os.path.dirname(input_path)

# DataFrame生成1
rng = np.random.default_rng(0)
df = pl.DataFrame(rng.random((2, 3)), schema=["A", "B", "C"])

# DataFrame生成2
df = pl.DataFrame(
    {
        "Integer": [1, 2, 3, 4],
        "Float": np.array([1, 2, 3, 4], dtype=float),
        "Datetime": [datetime.datetime(2022, 4, 1)] * 4,
        "String": ["test", "train", "test", "train"],
    }
)

# ファイル読み込み
files_file = input_path
df = pl.read_csv(files_file, has_header=True, skip_rows=0, columns=[0, 1, 2, 3, 4, 5], dtypes={'ID': str, 'X': float}, separator=',', encoding='utf8')
# サイズ確認
print(df.shape)
print(df.height)
print(df.width)
# NullとNanを置換
df = df.fill_null(0)
df = df.fill_nan(0)
# 行抽出
print(df[0:3])
# 列抽出
print(df.get_column("ID"))
# すべての列をリストで取得
print(df.get_columns())
# 左から何番目の列か
print(df.find_idx_by_name("ID"))
# 列取得
print(df.select("ID"))
# 新しい列を追加
new_seires = (df.get_column("xcenter") * 2).alias("xcenter2")
df = df.with_columns(new_seires)
# 指定した列でソート
df = df.select(pl.col(df.columns).sort_by("ID"))
# 中身確認
print(df.glimpse())
print(df.describe())
print(df.columns)
# 特定の列に特定の文字が存在するか確認
print(df.get_column("ID").is_in(['ea02e0be-b90b-48a6-a90']))
# reset index
df = df.with_row_count()
# フィルター
df = df.filter(((2000 >= pl.col("xcenter")) & (pl.col("xcenter") > 1160)) | ((1000 >= pl.col("ycenter")) & (pl.col("ycenter") > 750)))

# カウント数でフィルター
df_counts = df["ID"].value_counts()
df_counts = df_counts.filter((35 < pl.col("counts")) & (250 > pl.col("counts")))
fill_list = df_counts.get_column("ID")
df = df.filter(df.get_column("ID").is_in(fill_list))

# カウント分布を保存
df_counts = df["ID"].value_counts()
df_counts = df_counts.select(pl.col(df_counts.columns).sort_by("counts"))
df_counts.write_csv("./counts_by_ID.csv")

# 重複を削除
df = df.unique(subset=["ID"], keep="first")

print(df)
Number_of_employees = df["ID"].value_counts().sum().get_column("counts")[0]
print(Number_of_employees)
df.write_csv("./filtered.csv")
```

## まとめ
今回は、Polarsについて紹介した。
【SwiftUI】HStackを下寄せにした時の要素の下辺を揃える

# はじめに
タイトルでは意味がわからないと思うので説明します。

# 今回何をしたいのか
要素を横並びにして`alignment`で`.bottom`を指定しています
```swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        HStack(alignment: .bottom, spacing: 10) {
            Text("タイトル")
                .font(.system(size: 50, weight: .bold))
                .foregroundColor(.primary)
            Text("サブタイトル")
                .font(.system(size: 15, weight: .regular))
                .foregroundColor(.secondary)
        }
        .background(Color.cyan)
    }
}
```

上記のコードだとこのようになります。
![スクリーンショット 2023-04-28 22.19.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/88763594-c18c-4dcb-02be-38c237f654b1.png)

下を揃えたいのに揃っていません。
![スクリーンショット 2023-04-28 22.20.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/491127dd-31e4-1988-febf-00817058f702.png)

これを揃えていきたいと思います。

# 実装
```diff_swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        HStack(alignment: .bottom, spacing: 10) {
            Text("タイトル")
                .font(.system(size: 50, weight: .bold))
                .foregroundColor(.primary)
            Text("サブタイトル")
                .font(.system(size: 15, weight: .regular))
                .foregroundColor(.secondary)
+               .baselineOffset(7)
        }
        .background(Color.cyan)
    }
}
```

ちゃんと揃いました。
![スクリーンショット 2023-04-28 22.25.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/2ada3123-dedb-6bd4-c04c-03e761212ad0.png)

# ドキュメント
https://developer.apple.com/documentation/foundation/nsattributedstring/key/1526427-baselineoffset

# おわり
たまたま見つけましたー
リスコフの置換原則の考えを感覚的に捉える試み

先日、「リスコフの置換原則」について学ぶ機会がありました。自分が聞いた話では、整理術に近いような印象で、システムだけでなく実生活にも適用できる考えなのでは？と熱いものを感じたので、自分なりに言語化してみました。

この記事の対象者
- ある程度のポエムが混じっていても、許容できる方
- リスコフの置換原則を感覚で捉えたい方。
- タイトルに共感できる方

#目次
[1.リスコフの置換原則とは？](#リスコフの置換原則とは)
[2.リスコフの置換原則の考えは現実にも適用できる？](#リスコフの置換原則の考え方は現実にも適用できる)
[3.リスコフの置換原則の考えが使われているシステム？](#リスコフの置換原則の考えが使われているシステム)
[4.まとめ](#まとめ)
[5.参考](#参考)

# リスコフの置換原則とは？

リスコフの置換原則はよく以下のように説明されます。

**S が T の派生型であれば、プログラム内で T 型のオブジェクトが使われている箇所は全て S 型のオブジェクトで置換可能であれ**

もっと短く言うと

**派生型は基本型と置換可能でなければならない**

頭の中にたくさんの「?」が湧き出たと思います。この記事は上記の文章の言っている事を紐解きながら、私たちの生活役に立ちそうな考えを抽出する試みです。

## リスコフの置換原則の考え方は現実にも適用できる？

リスコフの置換原則で大事なのは、基本型から生まれた派生型は、基本型にできない事をすべきではないという所です。

この考えは、会社の組織で例えると仕事の属人化に似ています。

新入社員のAさんと先輩社員のBさん、その他の社員Cで仕事をしていたとします。

ある業務は数年前までは、社員C全員が担当できる、統一されたものでした。しかし、Bさんが「だいたい任されるの、俺だから俺流でいいや」的な発想で「統一業務マニュアル」を無許可で「俺流マニュアル」に書き換えてしまいました。


〜そして、現在へ〜


Bさんが退社してしばらく経ち、新入社員のAさんが入社しました。Bさんはもう居ないので、代わりに社員Cの中の一人がAさんの研修を担当しました。業務がうろ覚えなので、マニュアルを見つつ教える必要がありましたが、マニュアルを開くと超効率化されて訳の分からないことになっている「俺流マニュアル」がありました。これでは研修どころではありません。社内は小さな騒ぎになりましたとさ...。

現実には一つの業務が変わるだけで会社全体がパニックになることは考えにくいかも知れませんが、「部分最適」が「全体最適」の支障になりかねない一つの例として考えていただければと思います。

最初の文章をもう一度見てみましょう。

「派生型は、基本型と置換可能でなければならない」

今回出てきた「統一マニュアル」が基本型にあたり、「俺流マニュアル」が派生型に当たります。

ここで、「置換可能」かというふうに考えるともはや原型は残っていないように思えます。なんせ「全体で統一」から「超部分的で俺」に置き換わってしまっていますからね。

小さなマニュアルであれば、新しく作り替えるのは容易かも知れませんが大きなマニュアルであるほど、どこまでが「俺流」になっているのかを特定する労力は計り知れません。

ここまでの話を整理すると、リスコフの置換原則を適用しない事で以下のような
デメリットがある事が分かります。

- 全体の中で一部が部分的に特化している事で、全体で歪みが生まれる。
- 部分が担当する範囲が大きくなることで、部分の変化に全体が大きく影響を受ける

ここまでは、やや現実寄りで考えてきましたが、もう少しシステム寄りで「リスコフの置換原則」について考えていきましょう。

## リスコフの置換原則の考えが使われているシステム？

例えば、Linuxのファイルシステムは「ファイル」と「ディレクトリ」というとてもシンプルな構成で成り立っていると思います。ルートディレクトリには/binや/dev、/tmpなどのディレクトリがあると思いますが、これらは個々のディレクトリに役割を与えたものであり、極論を言えばどのような名前でもシステムには影響が出ないと思います（多分...）。現実にはないと思いますがLinuxに大きく変更が必要な場合でもLinuxのファイルシステムの考え方には「小さなものを組み合わせて大きくする」というものが根底にあり、個々が統一感を持って独立しているため、「機能を追加することで他のシステムの修正が必要になる」という事がないと思います。

こう考えると「コマンド」という仕組みは完成度が高いですね...。

(Linuxの場合は、「全体最適」の範囲を狭めて、部分の中に全体最適の考えを適用することで、個々の独立性を高めてシステム全体で部分が部分個々を認識しなくてもいいようにしているかもしれないですね。)

ここまでの話を整理すると、リスコフの置換原則を適用する事で以下のような
メリットが得られる事が分かります。

-  全体で統一感を持てる
- 個々が統一感を持つ事で特定の部分だけが特別という事が無くなる

# まとめ

**派生型は基本型と置換可能でなければならない**

この記事では上記の言葉を通じて、置換可能ではないケースとはどんなケースか？というのを現実寄りの視点で見てきました。

「リスコフの置換原則」を知ることで、「部分個々」の暴走を防ぐ事ができ、「統一感を持って全体最適」な考えを持つ事ができる。

「置換可能か？」という考えは「再現可能か？」という考えに置き換えると多くの物事に適用させる事ができそうですね。

他にもシステムで適用されていて、現実でも適用できそうな考えはあると思うので、考え方のひきだしを増やしていきたいです。

# 参考

https://qiita.com/yuki153/items/142d0d7a556cab787fad

https://www.membersedge.co.jp/blog/typescript-solid-liskov-substitution-principle/

https://emb-sw-eng.com/solid_l/

https://youtu.be/ET4iWuRntO4
外部ファイルを読み込む

## 概要
PHPで外部のファイルを読み込む。
## 手順

下記のようなディレクトリを想定。html配下のmain.phpから、template配下のtemplate.phpを読み込む。

    html
    └ main.php
    template
    └ template.php

ターミナルからrootディレクトリにhtmlフォルダを指定し、main.phpを読み込む。
例えば、Localhostであれば、ブラウザで　「http://localhost:8080/main.php」を叩く。

```main.php
<?php
    include __DIR__.'/../template/template.php';
?>
```
`include('ファイル名')`で読み込みたいファイルを指定。`__DIR__`そのファイルがあるディレクトリを示し、`/../`でその一つ上の階層、その階層のtemplateフォルダ以下の「template.php」を読み込んでいる。

例えば、template.phpに下記のようなhtmlを記載。

```template.php
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    "Hi!"
</body>
</html>
```
ブラウザで　「http://localhost:8080/main.php」を叩くと、

![スクリーンショット 2023-04-28 22.20.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185127/d01121b0-cc9d-6d2c-45e9-1a17837da0ea.png)

表示されました。

ちなみに似たようなことができる``require``というのがあるが、違いは下記。

``require`` = エラーが出てもその後の処理を継続
``include`` = エラーが出たら処理を中止

エラー発生時に後続処理に影響するかしないかで使い分けるようです。
Qiita記事をランキング化！技術ブログランキングアプリを開発しました

こんにちは、皆さん！
今回は、Qiitaの記事を検索し、いいね数や閲覧数でランキング化できる技術ブログランキングアプリを開発しましたので、その概要と使い方をご紹介します。

## アプリ概要
このアプリでは、Qiitaの記事を特定のトピックと期間で検索し、いいね数や閲覧数でランキング化することができます。さらに、検索された記事に関連する情報もグラフやリストで表示されます。これにより、あなたが興味を持つトピックに関する人気のある記事や、そのトピックがどの程度話題になっているかを簡単に把握することができます。

## アプリの使い方
まず、[technical_blog_ranking](https://technical-blog-ranking.onrender.com/)のURLにアクセスしてください。
アプリケーションにアクセスすると、検索フォームが表示されます。以下の手順で検索を行ってください。

①トピック欄に検索したいトピックを入力します（例：Python, JavaScript, etc.）。
②期間ドロップダウンメニューから、検索対象の期間を選択します（1日以内、1週間以内、1か月以内、1年以内から選べます）。
③ランキング順ドロップダウンメニューから、いいね数または閲覧数でランキングを表示するか選択します。
④検索ボタンをクリックします。
検索が完了すると、記事のランキングリストが表示されます。また、関連情報（トピック数、記事の筆者、投稿時間）もグラフやリストで表示されます。

### おわりに
技術ブログランキングアプリは、Qiitaの記事を効率的に探索し、人気の記事やトレンドを簡単に把握することができる便利なツールです。ぜひお試しください！
YouTube Data API v3 の Search.List で videoCategoryId を指定すると `googleapi: Error 400: Request contains an invalid argument., badRequest`

# 概要

以下のように Search:List をコールしたが

```go:Golangの例
	search := service.Search.List([]string{"snippet"}).
		Q("foo").
		VideoCategoryId("10").
		RegionCode("JP").
		PageToken(tok)
```

以下エラーが発生してしまう。

```
googleapi: Error 400: Request contains an invalid argument., badRequest
```

# 原因

`Type` パラメータを video と指定したところエラーを抑制できた。

```go
	search := service.Search.List([]string{"snippet"}).
		Q("foo").
        Type("video").
		VideoCategoryId("10").
		RegionCode("JP").
		PageToken(tok)
```

デフォルトでは channel や playlist も検索対象に含まれていることから、VideoCatagoryId 指定がうまくいかなかったのだろうか。

> デフォルト値は video,channel,playlist です。
https://developers.google.com/youtube/v3/docs/search/list?hl=ja#%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF
RubyでAtCoder ABC273(A, B, C)を解いてみた

# はじめに
Webエンジニアを目指して、RubyやRailsをいじってます。
今回は、RubyでAtCoder ABC273のA, B, Cを解きました。備忘録として解き方をまとめていきたいと思います。

# A - A Recursive Function
https://atcoder.jp/contests/abc273/tasks/abc273_a
```diff_ruby:a-273.rb
def f(k)
- f = 1
- f = k * f(k - 1) if k != 0
- f
+ (1..k).inject(1, :*)
end

n = gets.to_i
puts f(n)
```
## 解説
再帰関数を定義することで実装することができます。

# B - Broken Rounding
https://atcoder.jp/contests/abc273/tasks/abc273_b
```ruby:b-273.rb
# 修正前
x, k = gets.split.map(&:to_i)
k.times do |i|
  x = x.round(-i - 1)
end
puts x
```
```ruby:b-273.rb
# 修正後
x, k = gets.split.map(&:to_i)
puts k.times.inject(x){ |result, i| result.round(-i - 1) }
```
## 解説
i(0<=i<=k-1)について順次四捨五入していくことで実装することができます。

# C - (K+1)-th Largest Number
https://atcoder.jp/contests/abc273/tasks/abc273_c
```ruby:c-273.rb
n = gets.to_i
a = gets.split.map(&:to_i)

b = a.sort.uniq
l = b.size
hash = Hash.new(0)
n.times do |i|
  index = b.bsearch_index { |x| x > a[i] } || l
  hash[l - index] += 1
end

n.times do |k|
  puts hash[k]
end
```
他の方の提出結果を参考にしたところtallyメソッドを使って解くこともできるようです。こちらの方が高速で直感的に分かりやすいです。
```diff_ruby:別解
n = gets.to_i
a = gets.split.map(&:to_i)

hash = {}
l = a.uniq.size
- a.sort.uniq.each_with_index do |factor, index|
+ a.uniq.sort.each_with_index do |factor, index|
  hash[l - 1 - index] = factor
end

a = a.tally
n.times do |k|
  puts a[hash[k]] || 0
end
```
## 解説
最初のコードでは、bsearch_indexメソッドを使ってa[i]よりも大きくなるインデックスを取得し連想配列を更新しています。

https://qiita.com/shoya15/items/50fd17e37d7c64f2b166
[SubstancePainter]ノーマルマップをベイクする

# 概要
Blenderでローポリメッシュとハイポリメッシュを用意してSubstancePainterでノーマルマップをベイクします。
その後、作成したノーマルマップをblenderに戻してローポリに適用して確認するまでの手順です。
# 本文
## Blenderでローポリメッシュとハイポリメッシュを用意する
まずはデフォルトのキューブを
![スクリーンショット 2023-04-28 20.34.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/de606867-7f15-8fa0-8530-3e0efd32fe07.png)
複製します。複製した方で編集モードに切り替えて凸凹を描きハイポリを作ります。
![スクリーンショット 2023-04-28 20.34.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/eeb627f4-d40d-8367-7bdf-6ecb81cac1ef.png)
ローポリとハイポリができたら、fbxファイルをエクスポートします。どちらかを選択状態にしてエクスポート。次にもう一方を選択してエクスポートします。（スクショの様に両方が同じ位置に重なった状態にしておきます。合計2つのfbxファイルを作成します）

:::note info
今回の例で使っている「デフォルトで用意されたキューブ」は自動でUV展開されていますが、オリジナルモデルの場合はUV展開をしておく必要があります。（ハイポリの方のUV展開は必要ありません。ローポリのUV展開だけでOKです）
:::

![スクリーンショット 2023-04-28 20.41.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/3513653b-372c-28e7-9fe6-dc2c5cb77649.png)
File > Export > FBX
![スクリーンショット 2023-04-28 20.47.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/5285bd27-740b-548e-ee59-22546de2e64c.png)
## SubstancePainterでノーマルマップをベイクする
SubstancePainterでローポリのfbxを開きます（作業画面にドラッグ&ドロップ）

![スクリーンショット 2023-04-28 20.50.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/5b0f8cb8-d582-cef9-4c81-137bdc957d13.png)
メニューから「モード > メッシュマップをベイク」を選択して、ベイク画面に切り替わったら以下のように設定します
・ 出力サイズ2048以上
・ 高精細メッシュの右側にあるファイルアイコンを押してハイポリのfbxを選択
・ 「最前面の最大距離」と「背面の最大距離」はハイポリの凸凹を読み取る高さ＆深さを指定します。右側のサムネイル表示で確認しながら適度な値に設定します。
例えば以下スクショの様に真っ赤な部分があると高さ設定が足りていないということです。赤い部分が無くなるまで「最前面の最大距離」を大きくします。
![スクリーンショット 2023-04-28 21.04.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/c66bd1a6-8a17-f014-1dc5-99ff604c6fe4.png)

![スクリーンショット 2023-04-28 20.57.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/318b0422-329a-f924-35b0-8ba370a66e97.png)
出来上がったら「テクスチャをベイク」を押します。ベイクが終了したら「ペインティングモードに戻る」を押します。
ノーマルマップが出来上がりました。
![スクリーンショット 2023-04-28 21.11.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/9d6151e2-edf1-b484-d18d-65a06a478112.png)
メッシュマップ - Normalを選択すればノーマルマップ単体を確認することもできます。
![スクリーンショット 2023-04-28 21.33.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/706fcd72-f917-dce1-bc20-012865d75aa0.png)

## Blenderでノーマルマップを確認する
Blenderに戻ったらローポリだけを表示した状態にしてオブジェクトを選択状態にします。

Shadingタブを押して画面が切り替わったらPrincipled BSDFノードだけを選択状態にして「Ctrl」+「Shift」+「T」を押します。SubstancePainterでベイクしたテクスチャファイルを全部選択したら先ほどベイクしたノーマルマップが適用されます。（このショートカットキーを機能させるためにはアドオンNode Wranglerが必要です。）
![スクリーンショット 2023-04-28 8.44.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/ad2a924c-1968-cd13-b7a7-a5a238aec95a.png)

# 補足
blender単体だけでもノーマルマップのベイクは出来ますが、ちょっぴりめんどくさいです。SubstancePainterなら手軽にできます。

# 補足2
ハイポリメッシュの凸凹は角度が急な垂直の高低差は情報がうまく乗らないことがあります。そんな時は少し角度をつけておくと上手くいくと思います。

# リンク
[【SP解説】ゲーム系モデラー絶対必見‼ベイクの設定や仕組みを分かりやすくモノマネ付き解説‼SubstancePainter](https://www.youtube.com/watch?v=--3Daat61K0)
IsADirectoryError: [Errno 21] Is a directory: の解決例

## 何が起きた？
pdfファイル自動ダウンロードのロジックを作ろうとしたときに、保存のファイル名をちゃんと指定しているはずなのに表記のエラーで動かなくなるということが起きました。

## 原因（結論）
下記のようにファイル名で使用するつもりのものをディレクトリ作成で指定してしまっていたからでした。

```python:エラーが出る記述
import urllib
import os

# ファイル名設定
filename = xxx.pdf

# 保存先のディレクトリを自動で用意
os.makedirs('/Users/user/python_test/resources/' + filename)  # ←ここで間違ってファイル名でディレクトリを作成している

# 保存する場所とファイル名の指定
savepath = "/Users/user/python_test/resources/" + filename

# pdfのurl
url = "https://xxx.com/xxx.pdf"

# 取得して保存
urllib.request.urlretrieve(url, savepath)
```

## 解決方法
`os.makedirs`を正しく行うことでエラーが解消できました。

```python:正しい記述
import urllib
import os

# ファイル名設定
filename = xxx.pdf

# 保存先のディレクトリを自動で用意
os.makedirs('/Users/user/python_test/resources/')  # ←正しいディレクトリ名を指定した

# 保存する場所とファイル名の指定
savepath = "/Users/user/python_test/resources/" + filename

# pdfのurl
url = "https://xxx.com/xxx.pdf"

# 取得して保存
urllib.request.urlretrieve(url, savepath)
```
[Git] 動作を試す 実行例7：showでコミット履歴を見る

Gitの動作を理解するために、Gitのコマンドを実際に試して、結果を見てみました。

1つの記事内で一連のGitコマンドが完結しているので、これら一連のコマンドを順に実行させて結果を見ることで、一連のGitの動作を実際に体感でき、一通り独習することが可能です。

※前回記事のリポジトリ状態からの続きになっています。
| [前回記事へ](https://qiita.com/dl_from_scratch/items/cc1e4839815fbccbb23b) | [目次へ：Git関連記事のまとめページ](https://qiita.com/dl_from_scratch/items/597bc28a4787a7901d21) | [次回記事へ](https://qiita.com/dl_from_scratch/items/d495e43edb93ffae57db) |
|:-:|:-:|:-:|

# 実行例

```
git show
↓
結果: 
commit 94996a08c7d417aa01f78359887c7c59b8f3e309 (HEAD -> master)
Author: person1 <person1@abc.def>
Date:   Sun Jan 1 18:10:58 2023 +0900

    message4

diff --git a/test1.txt b/test1.txt
index 2cb4452..bb7eb1a 100644
--- a/test1.txt
+++ b/test1.txt
@@ -1,3 +1,4 @@
 Sample-Added-11
 Sample-Added-12
 Sample-Added-13
+Sample-Added-14
diff --git a/test4.txt b/test4.txt
new file mode 100644
index 0000000..d42c59e
--- /dev/null
+++ b/test4.txt
@@ -0,0 +1 @@
+Sample-Added-41

-----

git show --stat
↓
結果: 
commit 94996a08c7d417aa01f78359887c7c59b8f3e309 (HEAD -> master)
Author: person1 <person1@abc.def>
Date:   Sun Jan 1 18:10:58 2023 +0900

    message4

 test1.txt | 1 +
 test4.txt | 1 +
 2 files changed, 2 insertions(+)

-----

git show --oneline --stat
↓
結果: 
94996a0 (HEAD -> master) message4
 test1.txt | 1 +
 test4.txt | 1 +
 2 files changed, 2 insertions(+)
```

Gitコマンドを実行した時に「More?」と表示される場合の対処法
https://pasomaki.com/git-windows-commandprompt/
↓
引用: 
Windowsコマンドプロンプトでは「^」（キャレット）は エスケープ記号として使われる特別な意味を持った記号なので、ダブルクォーテーション（"）で括ればOKです。
git diff HEAD "HEAD^"

```
git log --oneline
↓
結果: 
94996a0 (HEAD -> master) message4
20bbab7 message3
00cad71 message2
4ace194 message1

※1つ前のコミットを表示する
git show --oneline --stat "HEAD^"
↓
結果: 
20bbab7 message3
 test1.txt | 1 +
 test2.txt | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

※同様
git show --oneline --stat HEAD~
↓
結果: 
20bbab7 message3
 test1.txt | 1 +
 test2.txt | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

-----

※2つ前のコミットを表示する
git show --oneline --stat "HEAD^^"
↓
結果: 
00cad71 message2
 test1.txt | 1 +
 test2.txt | 1 +
 2 files changed, 2 insertions(+)

git show --oneline --stat HEAD~~
↓
結果: 
(応答不可、エラー)

※同様
git show --oneline --stat HEAD~2
↓
結果: 
00cad71 message2
 test1.txt | 1 +
 test2.txt | 1 +
 2 files changed, 2 insertions(+)

-----

※3つ前のコミットを表示する
git show --oneline --stat "HEAD^^^"
↓
結果: 
4ace194 message1
 test1.txt | 1 +
 1 file changed, 1 insertion(+)

※同様
git show --oneline --stat "HEAD^3"
↓
結果: 
4ace194 message1
 test1.txt | 1 +
 1 file changed, 1 insertion(+)

※同様
git show --oneline --stat HEAD~3
↓
結果: 
4ace194 message1
 test1.txt | 1 +
 1 file changed, 1 insertion(+)
```

# 環境

Windows 10、PortableGit-2.40.0-64-bitを使用、全てローカルPC上で実施、GitHub等は不使用。
CloudFormationでEC2ユーザデータを環境別に指定する

`AWS::EC2::Instance`や`AWS::EC2::LaunchTemplate`で指定するプロパティ`UserData`を環境別に指定するにはどう書けばいいか悩み、ググっても出てこなかったのでメモ。
今回は「本番環境」と「それ以外の環境」で分けたい場合について記載する。

```yaml
Parameters:
  env:
    AllowedValues:
      - 'prod'
      - 'stg'
      - 'dev'
    Type: String

Conditions:
  IsProduction: !Equals [!Ref env, 'prod']

Resources:
  EC2:
    Type: AWS::EC2::Instance
    Properties:
      UserData:
        Fn::If:
          - IsProduction
          - Fn::Base64: !Sub |
            {{本番環境用の処理}}
          - Fn::Base64: !Sub |
            {{それ以外の環境用の処理}}
```
［JavaScript］テンプレートメソッドパターン・シングルトンパターン

## この記事の内容
JavaScript でのテンプレートメソッドパターン・シングルトンパターンの実装方法のメモ

## この記事を書くきっかけ
最近、JavaScript でコーディングする機会が増えたため

## デザインパターンに則ってコーディングする理由
拡張性・メンテナンス性を担保する

## デザインパターン
### テンプレートメソッドパターン
スーパークラスに処理の流れを定義し、サブクラスに処理の詳細を定義するデザインパターンのこと

### シングルトンパターン
そのクラスのインスタンスが１つしか生成されないことを保証するデザインパターンのこと

## コード
```JavaScript:sample.js
class Product {
    constructor(name,price){
        this.name = name;
        this.price = price;
    }
    // サブクラスが処理未実装の場合、エラーを投げる
    getInfo = () => { throw new Error("Line3 Error") };
}

// テンプレートメソッドパターン
class Food extends Product {
    constructor(name,price,calorie){
        super(name,price);
        this.calorie = calorie;
    }
    getInfo = () => { console.log(`${this.name} ¥${this.price} ${this.calorie}cal`);};
}

class Drink extends Product {
    constructor(name,price,amount){
        super(name,price);
        this.amount = amount;
    }
    getInfo = () => { console.log(`${this.name} ¥${this.price} ${this.amount}ml`); };
}

class ProductMaster {
    // シングルトンパターン
    static #productMaster = new ProductMaster();
    static getInstance = () => this.#productMaster;

    #products = [];

    constructor(){
        const food1 = new Food("food1",100,123);
        const drink1 = new Drink("drink1",148,500);
        const product1 = new Product("product1",1000);
        this.#products.push(food1);
        this.#products.push(drink1);
        this.#products.push(product1);
    }

    getProducts = () => this.#products;
}

const master = ProductMaster.getInstance();
const master2 = ProductMaster.getInstance();

// 同じインスタンスかどうか確認
console.log(master === master2);
console.log(master.getProducts() === master2.getProducts());

// 具体的な処理をサブクラスに任せる
master.getProducts().forEach( product => {
    product.getInfo();
});
```

## 実行結果
```
true
true
food1 ¥100 123cal
drink1 ¥148 500cal
/Users/XXXXXX/Desktop/JavaScript/sample.js:6
    getInfo = () => { throw new Error("Line3 Error") };
                      ^

Error: Line3 Error
（中略）
```
C#のHttpClientでDigest認証接続を行う。

# はじめに
.Netではhttpアクセスクラスがたくさんあるが、HttpClientクラスが推奨されている。
しかし、HttpClientクラスでDigest認証を扱うサンプルがなかなか見つからなかった。
（HttpWebResponseだとDigest認証サンプルが多いが、筆者環境では不具合が出た。）

# 実行ソース

参考
https://teratail.com/questions/296671

## VB参考元ソース
```VB
    'CredentialCacheの作成
    Dim cache As New System.Net.CredentialCache()
    'Digest認証の情報を追加
    cache.Add(New Uri(url), "Digest", New System.Net.NetworkCredential("user", "password"))

    Dim myClientHandler = New HttpClientHandler()
    myClientHandler.Credentials = cache

```

## C#対応後ソース

```C#
        private HttpClient GetDigestClient()
        {
            //'CredentialCacheの作成
            var cache = new System.Net.CredentialCache();
            //'Digest認証の情報を追加
            cache.Add(new Uri("URL"), "Digest", new System.Net.NetworkCredential("ID", "PW"));

            var myClientHandler = new HttpClientHandler();
            myClientHandler.Credentials = cache;

            var client = new HttpClient(myClientHandler);
            client.Timeout = new TimeSpan(0, 0, 0, 0, 5000);
            return client;
        }

```