OmniAICreator/Qiita-1.07M huggingface dataset:
ABC339回答メモ

# 0.はじめに
　今回のコンテストは問題のレベルがちぐはぐな気がしました。
　Bが難しく、Cが簡単でD,EよりFが簡単な気がしました。
　Fが簡単だったのは、Pythonの言語的特性のせいかもしれません。
　サッカー見ながらやってたら、A正解でフィニッシュになりそうだったので
　消して集中しました。
　そんなこんなで、ABCF正解で1798thと近年まれに見る高順位。
　レートも936と初の900台に届きました。


# 1.A - TLD
　最後のドット以降の文字列を表示という問題。
　答えを格納するリストansを用意しておいて
　Sを先頭から見ていきながらansに1文字ずつ格納。
　”.”がきたらansを空にする。
　といったロジックで最後にansをjoinして出力。
　いろいろやり方ありそうですが自分なりにすっきりした方法を取りました。

　https://atcoder.jp/contests/abc339/submissions/49916205


# 2.B - Langton's Takahashi
　大ブレーキを起こした問題。
　Dでもよいのでは・・・という印象。
　配点的には250点と高目でした。
　方向転換や、端に行った場合の挙動等、類似問題の
　ロジックを使いまわせばまぁ、スムーズに行けそうではあります。

　私の嵌りポイントとしては、2次元表の添え字の前後とX軸とY軸を
　表す値がどっちがどっちかわからなくなるところです。
　今回もそこでてこずり、WAを繰り返しました・・・。

　実装としては、問題文の内容を素直に実装しました。
　後に回答を見ると、方向を表す表や、回答用の2次元表の端に行った処理を
　modを取ることで対応可能と見てなるほどと思いました。
 
　https://atcoder.jp/contests/abc339/submissions/49950751


# 3.C - Perfect Bus
　問題を読んで、直感的に、以下の実装を思いつきました。
　【考え方】
 　　1.ansに0を格納。
 　　2.Aを先頭から見ていき、ansにA[i]を加算していく
   　3.ansが0より小さくなったらansを0にリセット
   　4.最後にansを出力して終了。

　乗客の変動の中で、一番乗客が少なくなったタイミングを
　単純に0人とすればそのあとの変動が条件を満たさないことはないなと
　考えた結果で、そのままAC頂けました。

　https://atcoder.jp/contests/abc339/submissions/49938574


# 4.F - Product Equality
　D・Eは、断念し、Fに向かいました。
　最初、i=j=kとかが許されるのかが条件にないな‥と思いましたが
　例題や、i≠j≠kが条件にないことからOKなんだなと分かりました。
　とりあえず、1000×1000を単純に取りまわすのは無駄かなと思い
　まずは以下を実装

　【実装】
　　1)辞書DにKEYを値、値を個数として、リストAを詰め込む。
　　2)D.keys()をリストLに格納し、昇順にソート
　　3)2重for文で、Lからi・jを取り出す
  　4)i*jをkとし、D内にkがあるかを検索
  　5)あった場合は、D[i]*D[j]*D[k]を、変数ansに加算
  　6)最後にansを出力して終了

   1000*1000位ならいけるかなーと思いましたが
   桁数が大きいせいか、TLEが5個。
   5個位なら、何とかなるかと思いとりあえず
   Kが、Lの最大値を超えた時に、2重ループのjのループを、ブレイクするように
   したところ、ACとなりました。

   解説をみたら、難しいことが書いてあって理解できませんでしたが
   c++とかだと難しいのかなーと思いました。

　https://atcoder.jp/contests/abc339/submissions/49964000

以上
Mindで倍精度整数を使ってみる（倍精度表示）

# はじめに
諸般の流れから日本語プログラミング言語Mindで固定小数点計算機能を書いてみようかなと思い立ち、Mind開発者の@killyさんからMind8に倍精度整数があると伺ったのだけを手掛かりにほぼ手探りで使ってみましたの続報です。

# お題のソースコード
```mind:decimal.src
int32は　変数。
int64は　倍精度変数。

メインとは
	int32に　2147483647を　入れ
	int32を　数値表示し　改行し
	int32を　NOTし　数値表示し　改行し
	int32を　1だけ　左シフトし　数値表示し　改行し
	int32を　1だけ　右シフトし　数値表示し　改行し
	改行し
	07fffffffHHと　00000FFFFHを　無処理し　文字列情報合成し　int64に　入れ
	int64を　＄＄倍精度表示し　改行し
	int64を　NOTし　＄＄倍精度表示し　改行し
	int64を　1だけ　左シフトし　＄＄倍精度表示し　改行し
	int64を　1だけ　右シフトし　＄＄倍精度表示し　改行し
	改行し
	int32を　ダブル表示し　改行し
	int32を　NOTし　ダブル表示し　改行し
	int32を　1だけ　左シフトし　ダブル表示し　改行し
	int32を　1だけ　右シフトし　ダブル表示し　改行し
	改行し
	int64を　＄＄クアド表示し　改行し
	int64を　NOTし　＄＄クアド表示し　改行し
	int64を　1だけ　左シフトし　＄＄クアド表示し　改行し
	int64を　1だけ　右シフトし　＄＄クアド表示し　改行。
```
今回は「＄＄倍精度表示」という単語を発見したので使ってみました。なるべく正の大きい数字（15桁）となるよう入力値を調整しました。32bit整数をダブルワード表示する単語も発見したので、併せて比較表示しています。

# 実行結果
では実行してみましょう。
```
C:\pmind\sample>decimal2.exe
2147483647
-2147483648
-2
1073741823

281472829227007
281472829227008
281474976710654
281471755485183

7FFFFFFF
80000000
FFFFFFFE
3FFFFFFF

7FFFFFFF|0000FFFF
80000000|0000FFFF
FFFFFFFE|0000FFFF
3FFFFFFF|0000FFFF

C:\pmind\sample>
```
おおっ15桁の32bit超の整数が表示されました。40bitは使っている感じ。
シフト処理単語は、推定「倍精度右シフト」とかあるのかないのか、Mindのインストールフォルダを「シフト」でgrepしてみましたがなさそうでした。

実装目的は10進数の固定小数点で小数部4桁10000倍なので、シフトはなくてもなんとかなるのかもしれません。

### 追記
少し固定小数点ライブラリのイメージを具体化してみると、インターフェースは小数点付き数字文字列なので、ピリオド位置が4桁未満なら右側に4桁まで0埋めしてからピリオド除去し、それをクァッドワード文字列に置換して倍精度整数にして、倍精度整数で演算して、元の小数点形式の文字列に復元して返すという感じになりそうなので10000倍自体もいらなさそうですね。

# つづく
しばらくつづきます:sweat_smile:


## この記事内容の作業環境
Windows11 Pro 22H2
CPU Intel(R) Core(TM) i3-5005U 2.00 GHz
Mind Version 8.0.08 for Windows
命題と論理

# 命題

　命題とは、1つの判断や主張を記号や文章で表したものであり、それが正しい（真：true）、正しくない（偽：false)ではっきりと区別できるもののこと。

　例えば、美味しいレストランという命題であった場合、美味しいのであればtrue、美味しくなければfalseとなるが、美味しいかどうかは主観に大きく依存する。そのため、美味しいレストランを命題とは呼べない。

　「3は数字である」、「Aは数字である」であれば、定義がはっきりとしているため、「3は数字である」=「true」、「Aは数字である」=「false」とはっきりと区別できる。このように文章で表したものを命題と呼ぶことができる。


 # 条件命題
 
　条件や状況によって真偽が異なる命題のこと。
　例えば、基準値を2とした場合、「3は基準値より大きい」=「true」となる。しかし、基準値が2から4に変わった場合、「3は基準値より大きい」=「false」となる。このように、命題に前提条件が存在し、その前提条件によって真偽が分かれるものを条件命題（命題関数）と呼ぶ。


# 複合命題（合成命題）

　複数の命題を「かつ」、「もしくは」などで結んで1つの命題としたもののことを、複合命題（合成命題）と呼ぶ。
 
　例えば、「基準値以上の数であること」かつ「上限値以下の数値であること」のように、2つの命題を複合（合成）し、1つの命題としたものである。
 
　この例えの場合、「基準値を3」、「上限値を10」と仮定すると、「4」であれば2つの命題に合致するためtrueとなるが、「13」であれば、基準値以上の数値であるが、上限値以下の数値ではないためfalseとなる。


# 複合命題の種類（記号）

・「A∧B」
　Aもture、Bもtrueであればtrueであるもの。AかつBの状態

・「A∨B」
　AかBのいずれかがtrueであればtureであるもの。AまたはBの状態

・「￢A」
　Aでなければture、Aであればfalseとなるもの。命題に反するものを真とするもの。

・「A→B」
　AがtrueでBがfalseの場合はfalse、それ以外はtrue
　※AがfalseでBがtrueでもtrue、AとBがfalseでもtrue

・「A↔B」
　AとBがtrueならtrue、AとBがfalseでもtrue、AがtrueでBがfalseはfalse
　AとBの真偽値が同じならばtrueとなる。

・ド・モルガンの法則
　￢(A∧￢B) = ￢A∨B = A→B
文字コードの変換と確認など


過去に作ったものを1つにしたものです。

入力されたテキストを変換したり、文字コードの確認ができます。

- 正規化：NFC,NFD,NFKC,NFKD の各種で正規化します
  - 変換された文字は背景の色が変化します
- コードポイント：文字ごとに文字コードをルビとして表示します
- innerHTML：出力タグの innerHTML に代入します
  - 入力されたテキスト次第では正常動作しなくなるので注意してください
- 文字化け : UTF-8 / シフトJIS / EUC-JP 間の「正しくない変換」を行います
- 英数字(他)変換：ASCIIの英数文字をボールドやイタリックなどの文字コードに変換します（できない場合もあります）
  - "Sample" → "𝐒𝐚𝐦𝐩𝐥𝐞", "𝑆𝑎𝑚𝑝𝑙𝑒", "𝕊𝕒𝕞𝕡𝕝𝕖" など
- 円内文字への変換：円の中に該当文字があれば変換します
  - "SAMPLE 10" → "ⓈⒶⓂⓅⓁⒺ ⑩", "🅢🅐🅜🅟🅛🅔 ❿" など
- 丸括弧付き文字への変換：丸括弧で括られた文字との対応があれば変換します
  - "(祝) (A)(B)(C) (a)(b)(c) (10)" → "㈷ 🄐🄑🄒 ⒜⒝⒞ ⑽"
- 異字体設定 : 各文字に VS𝒏 コードを追加します
  - 該当文字があれば字形(フォント)が変化します

https://github.com/ikiuo/dhtml-charcode-tool

<p class="codepen" data-height="525" data-default-tab="result" data-slug-hash="rNRvrXN" data-user="ikiuo" style="height: 525px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/ikiuo/pen/rNRvrXN">
  文字コード ツール</a> by Ikiuo (<a href="https://codepen.io/ikiuo">@ikiuo</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
ギター マルチエフェクター MOD Dwarf を無料で使ってみよう(3) -Ver 0.0.7-

MOD Desktop をよく知らないという人は過去の記事[『ギター マルチエフェクター MOD Dwarf を無料で使ってみよう(1) 』](https://qiita.com/Inqb8tr_jp/items/eee71a8c5453574cf11b)を読んでみてください。すぐに使いたいという人は[ダウンロード](#ダウンロード)からダウンロードしてインストールしてください。

![Screenshot from 2024-02-04 08-37-42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129361/611a2e60-48bd-7310-de11-1d9dac62dcb1.png)


## 変更点

またまた名前が変わりました。

~~MOD Desktop App~~ から MOD Desktop へ

それに伴い、ユーザーデータの保存場所もまたまた変わりました。

~~Documents -> MOD Desktop App~~ から Documents -> MOD Desktop へ

以前のユーザーデータを使いたい人はフォルダ名を~~MOD Desktop App~~からMOD Desktopに変更してください。

その他にもRelease Noteには変更点が書かれているのですが、Linux関係が中心で、Windowsではそれほど多くの変更点はないようです。

## ダウンロード

https://github.com/moddevices/mod-desktop/releases/tag/0.0.7

## 過去の記事

[ギター マルチエフェクター MOD Dwarf を無料で使ってみよう(1) -Ver 0.0.5-](https://qiita.com/Inqb8tr_jp/items/eee71a8c5453574cf11b)
[ギター マルチエフェクター MOD Dwarf を無料で使ってみよう(2) -Ver 0.0.6-](https://qiita.com/Inqb8tr_jp/items/cf61fffbb48ae361cfaa)
[MOD Dwarfを無料で使ってみよう(1)](https://qiita.com/Inqb8tr_jp/items/ee3a30838e90c3ee9589) (mod-live-usbの作り方と使い方）
[MOD Dwarfを無料で使ってみよう(2)](https://qiita.com/Inqb8tr_jp/items/897432306eb404bd9a6b)
[MOD Dwarfを無料で使ってみよう(3)](https://qiita.com/Inqb8tr_jp/items/461625cf450c01ddb74d)
プログラミングスクールへ通うことを検討している人へ

:::note alert
特定の個人や団体に対する誹謗中傷はご遠慮ください。
一個人の意見なので鵜呑みにせず、自身で見極めてください。
また、この記事は趣味でプログラミングをやっている人向けに書いています。
:::

# 結論
人によりけりです。ただ、たまにあるむやみに独学をこき下ろすスクールの広告は信用しないほうがいいです。

# 理由
私は、いままで独学で勉強してきました。人に教えてもらったこともありますが、最終的には独学でやったほうが早かったです。
理由としては、

①単純に意欲が高かったから。
②自分で調べたほうが頭に残りやすいから

これだけです。しかし、これが非常に重要なのです。

まず、①から説明していきましょう。
プログラミングが好きで好きでしょうがなく、依存症と呼ばれるくらい熱中するような人であれば、人に教えをこうより自分でいろいろと調べたほうが遥かに効率がいいと思います。その理由は人によって様々ですが、私の場合は誰かに教えをこうと、その人のペースになってしまい思うように勉強できなかったです。

つぎに、②です。
人に教えを請うと、もしかしたら自分の興味ない分野に進むかもしれません。面白そうではないプロジェクトをやらないといけないかもしれません。そういうものは、勉強しても頭に残りづらいです。それに対して、自分の好きな分野・プロジェクトを自由にできる独学は、意欲さえあれば非常に頭に残りやすいです。

# まとめ
意欲があるなら、独学でやろう。スクールの広告に惑わされてはいけない。
意欲がない・少ない人なら、スクールも視野に入れてもいいと思う。
【コピペ用】HTMLのコードスニペット（後で追記していく）

## 最初期状態

```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    
</body>
</html>
```

## デバイスの画面幅に応じて表示されるようにする

```HTML
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
```

## キャッシュを保持しないようにする

```HTML
    <meta http-equiv="Pragma" content="no-cache">
    <meta http-equiv="Cache-Control" content="no-cache">
    <meta http-equiv="Expires" content="0">
```

## 数字が電話番号としてレンダリングされないようにする

```HTML
    <meta name="format-detection" content="telephone=no">
```
django-allauth - 認証関連ページへのリンクの設定方法（URLの逆引き・逆検索名）

django-allauth では認証周りのページがごそっと作成されます。

では、逆引きするときの名前は？と疑問に思ったので調べてみました。

つまり、テンプレート HTML から `"{% url 'ここに入る文字列は何？' %}"` の形でリンクを作る方法です。

## 逆検索時の名前
以下のように指定すると、django-allauth で定義された各ページへのリンクを作成できます。

```python
<nav>
  <ul>
    <li><a href="{% url 'account_login' %}">Login</a></li>
    <li><a href="{% url 'account_logout' %}">Logout</a></li>
    <li><a href="{% url 'account_signup' %}">Sign Up</a></li>
    <li><a href="{% url 'account_change_password' %}">Change Password</a></li>
    <li><a href="{% url 'account_reset_password' %}">Reset Password</a></li>
    <li><a href="{% url 'account_email' %}">Email Addresses</a></li>
  </ul>
</nav>
```

## django-allauth で作成されるページの一覧
urls.py に include('allauth.urls') を追加することと、以下が自動的に組み込まれます。

- 基本認証ページ
    - ログイン (account_login)
        - ユーザーがログインするためのページ
    - ログアウト (account_logout)
        - ユーザーがログアウトするためのページ
    - サインアップ (account_signup)
        - 新規ユーザーがアカウントを作成するためのページ
    - パスワード変更 (account_change_password)
        - ログイン済みのユーザーがパスワードを変更するためのページ
    - パスワードリセット (account_reset_password)
        - ユーザーがパスワードを忘れた場合にパスワードを再設定するページ
- メールアドレス管理
    - メールアドレスの追加/削除 (account_email)
        - ユーザーが自分のメールアドレスを管理（追加、削除、変更）するためのページ
- アカウント確認とセキュリティ
    - メールアドレス確認 (account_confirm_email)
        - ユーザーがメールアドレスを確認するためのリンクをクリックした後にアクセスするページ
    - パスワードリセット確認 (account_reset_password_from_key)
        - ユーザーがパスワードリセットリンクをクリックした後、パスワードを再設定するページ
- ソーシャルアカウント
    - ソーシャルアカウントの接続/管理 (socialaccount_connections)
        - ユーザーがソーシャルアカウント（Facebook、Googleなど）を自分のアカウントに接続、または管理するためのページ
SendToフォルダを活用しよう！

今更ですが、意外と知らない人も多いみたいなので。。。

［Win］＋［R］キーで〔ファイル名を指定して実行〕ダイアログを開き、

shell:sendto

と入力して［OK］ボタンを押すと［SendTo］フォルダ（%APPDATA%\Microsoft\Windows\SendTo）が開く。

この［SendTo］フォルダ内に登録されているプログラム（のショートカット）は、エクスプローラ上で選択したファイルを右クリックしたときの［送る］メニューに表示され、選択されているファイルのパスを［送る］メニューで指定したプログラムにコマンドライン引数として渡すことができる。

例えば、以下のスクリプトを 文字コード Shift-JIS で［SendTo］フォルダに保存し、エクスプローラで選択したCSVファイルを右クリックして［送る］メニューからこのスクリプトを指定すると、選択したCSVファイルの全レコード件数がメッセージボックスに表示される。

エクスプローラ上のスクリプトファイルにCSVファイルをドラッグアンドドロップしても同じ効果が得られるが、［送る］メニューで行ったほうがやりやすい。

```vb:複数のCSVファイルを選択してレコード件数集計.vbs

Option Explicit

Dim arg, rowsCnt, totalRowsCnt, x

x = 2   '// カウント開始行
With CreateObject("Scripting.FileSystemObject")
    For Each arg In WScript.Arguments
        '// 追記モードで開き、最終行を（.Line）を取得する
        With .OpenTextFile(arg, 8)
            rowsCnt = .Line - x
            .Close
        End With
        totalRowsCnt = totalRowsCnt + rowsCnt
    Next
End With

MsgBox "総レコード数：" & totalRowsCnt
```

![sendto.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146265/f367e748-a920-6ffa-c72f-91285ba7ae51.png)
---
＜参照サイト＞
[テキストファイルの行数を調べる](http://officetanaka.net/excel/vba/filesystemobject/sample09.htm)
【Flutter】ProcessException Process exited abnormally with exit code 3のエラー

### ???
こんな感じの新規登録画面を作成。
アイコンを設定するためのプラスを押し、ファイルにアクセスしようとするとエラーが発生。
問答無用でシュミレータが落ちる。

![スクリーンショット 2024-02-04 7.24.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669888/96227d5b-56f4-5ff2-bf66-44ec70a93bcd.png)

### やったこと
- シュミレータの再起動
- `flutter clean`してから`flutter run`
どちらも解決ならず…

### なんてことはない、ただの設定漏れ…

udemyで同じようなことをやってたときのプロジェクトとまじまじと見比べてみると、`Info.plist`の設定が漏れていた。

```
ios/Runner/Info.plist

// 以下の設定を追加
<key>NSPhotoLibraryUsageDescription</key>  
<string>写真フォルダへのアクセスが必要です</string>  
<key>NSCameraUsageDescription</key>  
<string>カメラのアクセスを許可しますか</string>  
<key>NSMicrophoneUsageDescription</key>  
<string>マイクを許可しますか</string>
```
### 解決 

アクセスできた！
![スクリーンショット 2024-02-04 7.27.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669888/8c52caad-5a92-3f28-000f-198782b5bf14.png)
Elasticsearchが Unexpected http method: PRIと吐いた件について

# はじめに

みなさんこんにちは。

突然ですが、みなさんはElasticsearchをFargateでデプロイしたことありますか？意外にサイトが少なく、情報が少ないまま私はデプロイしたわけですが。まぁAmazon OpenSearch Serviceがありますから、それ使えばいいじゃんという話ですよねすいません....存在に気づいた時にはすでにFargate使ってたもんですから......

それはそうとして、せっかくならとFargateにHTTPS通信つけてみたんですよね。そしたらElasticsearchから
```
"java.lang.IllegalArgumentException: Unexpected http method: PRI"
```
と吐かれまして.....そんでこの原因がめちゃくちゃしょうもなかったので共有したいと思い記事にしました。

# TL;DR

ってことでどのようにして解決したのかって話ですよね。

EC2 > ロードバランサー > Fargateと紐付けてあるNLBを選択 > リスナーの編集 > ALPNポリシー

この部分を「None」にすることで解決しました。

![スクリーンショット 2024-02-04 7.00.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/462621/1d0be05f-ec52-1e07-ce2b-0660d95873ce.png)

というのも、私何を血迷ったのかここの項目「HTTP2Preferred」にしてたんですよね。

![スクリーンショット 2024-02-04 7.02.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/462621/3852a1f5-ec9b-acb9-ee0a-8c56927e0465.png)

それが原因でElasticsearchがエラーを吐いたようです。

# なぜエラーを吐いたのか

エラーコードを見る限り、「PRIとかいうHTTPメソッドは知りませんよ」と言ってるようです。

ではこのPRIとは何者なのか、調べてみると以下の記事が気になるようなことを書いてありました。

> クライアントが、接続先サーバーが HTTP/2 対応済みであることを知ってる場合は事前知識(Prior Knowledge)があると言う。
> [HTTP/2: ちょっと詳細: プロトコルネゴシエーション編](https://qiita.com/nozmiz/items/3bf03533895251c93af2)

はい、そうです。PRIは*Prior Knowledge*の先頭3文字を取った単語だったのです。

さらにちょっと深掘りすると、HTTPS/2にサーバーが対応していることがわかった後、**HTTP/2コネクションプリフェイス**という定められた文字列を接続先サーバーに送信するようです。そういえば、上の「HTTP2Preferred」も、「プリフェイス」と読めそうな言葉......

要は、上の設定にすると、接続先のサーバーはHTTP/2でリクエストを受ける必要があり、その挨拶がわりとして決められた文字列が送られるわけですね。
それを「HTTP/2ってHTTP/1より強いんだ！じゃあよくわからんけどこれにしよ！」という感覚でよくわからない項目を選んだがゆえにこんなエラーに悩まされました......

# 反省点

まず、**よくわからない項目は下手にいじらない**。これをとても実感しました。

そして、HTTP/1とHTTP/2の大まかな通信の仕組みもしっかりと把握する必要がありますね。


P.S. Elasticsearchのバージョン載せ忘れました......Dockerを使って動かしてます。

```
FROM elasticsearch:7.17.6
```
SVGのプレビューをWindowsのファイルエクスプローラーで確認

# 環境
* OS: Microsoft Windows 11 Pro
* SVG: MicroSoft配布リソース

https://learn.microsoft.com/ja-jp/microsoft-365/solutions/architecture-icons-templates?view=o365-worldwide


# 課題
SVG はエクスプローラーで表示しようとすると、Edge アイコンになっています。

![svg_icon](https://github.com/pea-sys/Til/assets/49807271/adc2a737-94d4-460f-9749-946053fede16)

プレビューを他の画像ファイル(png, jpg, gif)のように表示できるツールを導入します。

# 解決方法

- プログラムを以下からダウンロードします

https://github.com/tibold/svg-explorer-extension/releases

![icon_tool](https://github.com/pea-sys/Til/assets/49807271/4add4aa5-4892-4e43-b8de-ad80bbf15da2)

- ダウンロードしたインストーラを実行し、インストールします

- プレビューが表示されるようになりました

![svg_icon](https://github.com/pea-sys/Til/assets/49807271/88c4350f-925b-4d09-93fc-1a8fc91971dd)

※ 小アイコン/一覧/詳細だとプレビューが表示されません。

以上
BackWpupのデータ復元手順、データベース接続エラーとなる場合

# バックアップファイルをダウンロードする
![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3518353/d0d89c58-ca89-3a42-d87c-c7ce58ea1abc.png)

BackWPup > バックアップ
ダウンロードしてください

### 解凍できない場合
BackWPup > ジョブ > 編集 > アーカイブ形式
![スクリーンショット 2024-02-04 6.58.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3518353/97158fe6-4c59-44a0-c2f9-9b098ec6e5a2.png)

以下に設定する必要があります。
Windows: ZIP
Mac: Tar GZip

# WPを復元する
1. バックアップファイルを解凍します
1. FTPソフトを使用してSQLファイル以外を上書き転送します

※SQLファイルとは、『xxxxx.sql.zip』, 『xxxxx.sql.gz』などのこと
※転送には時間がかかると思います

# DBを復元する
1. サーバーのphpAdminにアクセスします
1. 対象のDBを選択します
1. インポートを選択します
1. 先ほど転送しなかったSQLファイルを選択します
1. 他はそのままで実行を選択します

![スクリーンショット 2024-02-04 7.03.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3518353/b90bf059-7038-6d38-e981-32fb9e2b1f15.png)




### データベース接続確立エラーの場合
![スクリーンショット 2024-02-04 6.44.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3518353/3b6796ef-e7c9-ecf6-14b8-7dde6afc68ab.png)

データベース自体のパスワード等が変更されているとこうなる。
wp-config.phpの以下部分を確認する。

```php
// ** Database settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define( 'DB_NAME', 'xxxxx' );

/** Database username */
define( 'DB_USER', 'xxxxx' );

/** Database password */
define( 'DB_PASSWORD', 'xxxxx' );

/** Database hostname */
define( 'DB_HOST', 'xxxxx' );

/** Database charset to use in creating database tables. */
define( 'DB_CHARSET', 'utf8' );

/** The database collate type. Don't change this if in doubt. */
define( 'DB_COLLATE', '' );
```

# 終わり
復元できていれば終わりです。
他にもトラブルシューティングがあれば追加します。
laravelで値を暗号化

laravelで値を暗号化し、それをデコードできる関数を紹介します。

## encrypt関数
値を暗号化する関数です。
以下のように使用します。
```php:
$value = 123

$encrypted = encrypt($value);

print($encrypted)
//結果
//eyJpdiI6Ik9mY3B2WkxJeWdKam90a2FFNTlrMHc9PSIsInZhbHVlIjoiMVVvYno1R0VlL2ZXZ09RL005SUUzZz09IiwibWFjIjoiMDY2MDVkOGJlOTM1Yzg1Njk4ZjdkNDdlYTI4Nzc4ZTA2M2U3MGRiODRhZGUzY2Y2MTljNDMxNDUwN2NjNDk2ZiIsInRhZyI6IiJ9

```
元の値をランダムな文字列に暗号化できます。

## decrypt関数
暗号化された値を元の値に戻すことも可能です。
```php:
$encrypted ='eyJpdiI6Ik9mY3B2WkxJeWdKam90a2FFNTlrMHc9PSIsInZhbHVlIjoiMVVvYno1R0VlL2ZXZ09RL005SUUzZz09IiwibWFjIjoiMDY2MDVkOGJlOTM1Yzg1Njk4ZjdkNDdlYTI4Nzc4ZTA2M2U3MGRiODRhZGUzY2Y2MTljNDMxNDUwN2NjNDk2ZiIsInRhZyI6IiJ9';

$decrypted = decrypt($encrypted);

print($decrypted);
//結果
//123
```
STM32C011(SOP8)のI2Cで遊ぶ(準備編)(STM32C011J4M7)(そしてI2Cは、動いた)


x 時間がなくて忙しい人は、一番下へ


目的
I2Cで遊ぶ準備をする


ピンの機能　(i2c SCK SDA)
ハードウェアマニュアル(英文)より

```


1 - 20 PC14 I2C1_SDA
8 - 1  PC15 
2   2  VDD
3 - 3  VSS
4 - 4  PF2
4 - 5  PA0
4 - 6  PA1 
4 - 7  PA2 
  - 8  PA3
  - 9  PA4

  - 10 PA5
  - 11 PA6
  - 12 PA7
5 - 13 PA8 
       PA9   I2C1_SCL
       PA10  I2C1_SDA
5 - 14 PA11 
6 - 15 PA12
7 - 16 PA13
8 - 17 PA14

8 - 18 PB6 I2C1_SCL
1 - 19 PB7 I2C1_SDA I2C1_SCL


```


いろいろ1
えーーー　1ピンと8ピンのみ
標準的なPB6、PB7だね
8ピンは、SWDと被るから
「ターゲットリセット」が必須だね。


1ピン　PB7のLチカ


![o_cop922.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/561051ac-ed00-ade4-f5a5-8a5d2db03719.jpeg)



```c++



//GPIO_PB7_C011_2


//初期化
void setup() {

  delay(3000);//マッポの手先、消したら、いかんぜょ(斎藤由紀風)

  //ピンの初期化 PB7
  pinMode(PB7, OUTPUT);

} //setup


//メインループ
void loop() {

  //PB7をオン
  digitalWrite(PB7, HIGH);

  delay(1000); //1秒待つ

  //PB7をオフ
  digitalWrite(PB7, LOW);

  delay(1000); //1秒待つ

} //loop


```





必ず読んでください。

↓ここをクリック↓

https://qiita.com/caa45040/items/62917ae9fe9dd134edbd

↑ここをクリック↑

x 以降は、自己責任の意味がわかる人だけ読んでください。

x ターゲットリセット信号の出る書き込み器を必ず用意してください。
x 必ず、全体のはじめの先頭に3秒のウエートを入れてください。
x 3秒ルールは、絶対に消さないでください


PB6は、なぜか動かない


```c++

//GPIO_PB6_C011_1


//初期化
void setup() {

  delay(3000);//マッポの手先、消したら、いかんぜょ(斎藤由紀風)

  //ピンの初期化 PB6
  pinMode(PB6, OUTPUT);

} //setup


//メインループ
void loop() {

  //PB6をオン
  digitalWrite(PB6, HIGH);

  delay(1000); //1秒待つ

  //PB6をオフ
  digitalWrite(PB6, LOW);

  delay(1000); //1秒待つ

} //loop

```

PB6が動かない
PC14が動かない

PA9が動いた
PA10が動いた

STM32C011F6Uの時

```

//*** I2C ***

#ifdef HAL_I2C_MODULE_ENABLED
WEAK const PinMap PinMap_I2C_SDA[] = {
  {PA_10_R, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF6_I2C1)},
  {PB_7,    I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF6_I2C1)},
  {PC_14,   I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF14_I2C1)},
  {NC,      NP,   0}
};
#endif

#ifdef HAL_I2C_MODULE_ENABLED
WEAK const PinMap PinMap_I2C_SCL[] = {
  {PA_9_R, I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF6_I2C1)},
  {PB_6,   I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF6_I2C1)},
  {PB_7,   I2C1, STM_PIN_DATA(STM_MODE_AF_OD, GPIO_NOPULL, GPIO_AF14_I2C1)},
  {NC,     NP,   0}
};
#endif



```

-----------------------------------------

PA10,PA9で遊ぶ そして、動いた


へんな液晶は、オリジナルハードで0x80に送ると文字を表示する


![o_cop923.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/bf1ba1d8-e5cd-ad59-3e6c-40e1a23c1c86.jpeg)



```c++


//GPIO_I2C_A_C011_1


//インクルド
#include <Arduino.h>
#include <Wire.h>


//初期化
void setup() {

  delay(3000);//マッポの手先、消したら、いかんぜょ(斎藤由紀風)

  //ピンの初期化 PB6
  pinMode(PB7, OUTPUT);

  //i2cの初期化
  Wire.setSDA(19); //PA10
  Wire.setSCL(18); //PA9
  Wire.begin(); //pa12 pa11

} //setup


//メインループ
void loop() {

  //一文字転送
  Wire.beginTransmission( (0x80)>>1 );
  Wire.write('A');
  Wire.endTransmission();
  delay(1);

  //PB6をオン
  digitalWrite(PB7, HIGH);

  delay(1000); //1秒待つ

  //PB6をオフ
  digitalWrite(PB7, LOW);

  delay(1000); //1秒待つ

} //loop


```
絵文字があるか判定する

絵文字が含まれているかどうかを判別します。
入力された文章から絵文字を除去するコードはいくつか合ったけど、真偽で返すのは無かったので残します。
絵文字を判定しているサイトをいくつか比べたのですが、完璧に判定するのは難しいのですね...
```js
const emoji = new RegExp(/[\u2700-\u27BF]|[\uE000-\uF8FF]|\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDFFF]|[\u2011-\u26FF]|\uD83E[\uDD10-\uDDFF]/, 'g');

const judgeEmoji = input => {
  return input.match(emoji) ? true : false
}

judgeEmoji('おはよー😇');   // true
judgeEmoji('こんに👨‍🍳ちは'); // true
judgeEmoji('こんばんは！'); // false

```

https://teratail.com/questions/157253

https://corycory.hateblo.jp/entry/javascript/javascrip-reg-emoji/
【bat】01 と 1 はイコールか否か


```bat
@echo off

echo 01 == 1
if 01 == 1 (
	echo true
) else (
	echo false
)

echo 01 equ 1
if 01 equ 1 (
	echo true
) else (
	echo false
)
pause>nul
```

```bat:result
01 == 1
false
01 equ 1
true
```

`equ`の時は数値として処理する？
【SQL】条件付きソート/SQLマスターへの道「CASE・WHEN」

## 導入
SQL文で並び替えをカスタマイズしたい場合、一般的には`ORDER BY`でソートする事が多いですよね。
今回は``ORDER BY``を使って、より複雑なソート条件に対応するテクニックについて紹介をします。
**キーワードは「when」「case」です。**

## ORDER BY について
（※ 初学者向けです。``ORDER BY``くらい知ってるよって方はスキップしてください。）
通常の``ORDER BY``について簡単に説明をします。
具体例を出したほうが早いですかね。

データベース内のポケモンテーブルで`図鑑No.`でのソートを例に出すと...
```sql
SELECT `pokemon_data`.`id`, `pokemon_data`.`name`
FROM `pokemon_data`
ORDER BY `pokemon_data`.`id` ASC
```
結果はこんな感じです。
```md
| id | name       |
|----|------------|
| 1  | フシギダネ  |
| 2  | フシギソウ  |
| 3  | フシギバナ  |
| 4  | ヒトカゲ    |
| 5  | リザード    |

（To Be Continued...）
```

## 要件
今回の要件はこちら！

:::note warn
- ポケモンの一覧で通常は図鑑順
- タイプが「ドラゴン・ひこう」・地方が「ホウエン」の場合、上に表示させる
:::
（もう結果はわかりますか？あの三体ですね。）

## 実装
### コード
```sql
SELECT `pokemon_data`.`id`, `pokemon_data`.`name`, `pokemon_data`.`type`
FROM `pokemon_data`
ORDER BY CASE
  WHEN `pokemon_data`.`type` = 'ドラゴン・ひこう'
    AND `pokemon_data`.`region` = 'ホウエン' THEN 0
  ELSE 1
  END,
  `pokemon_data`.`id` ASC;
```

## 解説
### 今回のポイント
- タイプが「ドラゴン・ひこう」かつ地方が「ホウエン」である場合には**ソートキーを「0」**
それ以外の場合には**ソートキーを「1」**
- 通常はサイズ順に並び替えられる

今回のポイントは、**CASE句**。
CASE句を利用することでソートキーのような形で重み付けをすることができます。

### SQL結果
```md
| id  | name       | type            |
|----|------------|-----------------|
| 334  | チルタリス   | ドラゴン・ひこう |
| 373 | ボーマンダ   | ドラゴン・ひこう   |
| 384 | レックウザ   | ドラゴン・ひこう     |
| 1  | フシギダネ   | くさ・どく       |
| 2  | フシギソウ   | くさ・どく       |
| 3  | フシギバナ   | くさ・どく       |
| 4  | ヒトカゲ     | ほのお           |
```
はい。答えは「チルタリス」・「ボーマンダ」・「レックウザ」でした〜。

### まとめ
今回は、`ORDER BY`と`CASE`を組み合わせて複雑なソート条件への対応方法について解説しました。
【bat】全角スペースのアレを回避【追記：外部batで処理】

新しい記事書きました

https://qiita.com/noenture/items/d67050a7c155b492a317




# 追記
外部batにしました
使い方
`%*`を渡すと、変数`__ARGS`に格納されます
```bat
call fullspace_loader.bat %*

for %%i in (%__ARGS%) do echo %%~dpnxtzi
pause

```

```bat:fullspace_loader.bat
@echo off
setlocal

for %%i in (%*) do if not exist %%i goto :__ARRANGE_MODE
set __ARGS=%*
goto :__END

:__ARRANGE_MODE
for %%i in (%*) do call :__MERGE_ALL %%i
set __ARGS=%__ARGS:~1%
set __ARGS="%__ARGS:?=" "%"
goto :__END

:__MERGE_ALL
set __V=%~1
if "%__V::\=%" == "%__V%" (
	set __ARGS=%__ARGS%　%__V%
) else (
	set __ARGS=%__ARGS%?%__V%
)
exit /b

:__END
endlocal & set __ARGS=%__ARGS%
exit /b


```

# 追記おわり


タイトルを下記から変更しました
【bat】全角スペースが含まれるファイルをそのまま扱う




そんなファイル有りませんと言われてイラッとしたので作りました
有る物投げてるのに何なのって

# 全体

```bat:fullspacefile_loader.bat
@echo off

for %%i in (%*) do if not exist %%i goto :_ARRANGE_MODE
for %%i in (%*) do call :_MAIN_LOOP %%i
goto :_NEXT

:_ARRANGE_MODE
for %%i in (%*) do call :_MERGE_ALL %%i
set _ARGS=%_ARGS:~1%
call :_DIVIDE_ARGS "%_ARGS:?=" "%"
goto :_NEXT

:_MERGE_ALL
set _V=%~1
if %_V::\=% == %_V% (
	set _ARGS=%_ARGS%　%_V%
) else (
	set _ARGS=%_ARGS%?%_V%
)
exit /b

:_DIVIDE_ARGS
for %%i in (%*) do (
	if exist %%i (
		call :_MAIN_LOOP %%i
	) else (
		call :MESSAGE "not exist :  %%~i"
	)
)
exit /b

:MESSAGE
echo #
for %%i in (%*) do echo # %%~i
echo #
exit /b

:_MAIN_LOOP
echo %~dpnx1
exit /b

:_NEXT
call :MESSAGE "finish : %~nx0"
pause

```

ごちゃごちゃしちゃったけど私にはこれが限界

# 全体解説

読み込んだファイルを一度すべて連結し、ちゃんとした場所で分割する
callを使い、引数として渡すことで問題解消


# 個別解説

```bat
for %%i in (%*) do if not exist %%i goto :_ARRANGE_MODE
for %%i in (%*) do call :_MAIN_LOOP %%i
goto :_NEXT
```
存在しないファイルがないかチェック、あった場合　ラベル`:_ARRANGE_MODE`へ移動
全て存在していたらそのまま通常処理し下記処理をジャンプして次の処理へ

```bat
:_ARRANGE_MODE
for %%i in (%*) do call :_MERGE_ALL %%i
set _ARGS=%_ARGS:~1%
call :_DIVIDE_ARGS "%_ARGS:?=" "%"
goto :_NEXT
```
引数を順次ラベル`:_MERGE_ALL`へ投げて変数`_ARGS`に結合させる
さらに`_ARGS`を加工し、区切り文字 **?** でファイルごとに分割しラベル`:_DIVIDE_ARGS`へ投げる

```bat
:_MERGE_ALL
set _V=%~1
if %_V::\=% == %_V% (
	set _ARGS=%_ARGS%　%_V%
) else (
	set _ARGS=%_ARGS%?%_V%
)
exit /b
```

渡された引数が
ドライブレターを含む場合、**?** を頭に付与し追加
ない場合、**全角スペース**を頭に付与し追加

```bat
:_DIVIDE_ARGS
for %%i in (%*) do (
	if exist %%i (
		call :_MAIN_LOOP %%i
	) else (
		call :MESSAGE "not exist :  %%~i"
	)
)
exit /b
```
気にしすぎかもしれないけど、ここでも存在確認

```bat
:MESSAGE
echo #
for %%i in (%*) do echo # %%~i
echo #
exit /b

:_MAIN_LOOP
echo %~dpnx1
exit /b

:_NEXT
call :MESSAGE "finish : %~nx0"
pause
```

ラベル`:_MAIN_LOOP`
ここで本来させたかった処理を記述

ラベル`:_NEXT`
続く処理を記述


# あとがき

もっと簡単に回避する方法ないのかなorz
StarTech HDD ケース(HSB4SATSASBA)の静音化(ファン交換)

# 作業メモ＆備忘録

# 動機
1. True NAS の外付けバックアップディスクを mini-SAS で接続している
    - 今 32T (striped-mirror (16Tx4)) で、そろそろ不足したので 16Tx8 にする予定
    - => USB 接続だとさすがに邪魔くさい。10台入るケースだとフルバックアップの時間が不安
2. ケースは QNAP TL-D800S にしようかと思ったが高い
2. HSB4SATSASBA を使ったが、付属ファンがうるさすぎる



# 機材構成
1. 母艦　*TrueNaS Core*
1. SAS カード　*LSI SAS 9200-8e*
1. SAS-SATA 変換　適当に mini-SAS <-> SATA ファンアウトケーブル (SFF-8088 <-> SATAx4)
1. 外付け HDD ケース　*StarTech HSB4SATSASBA*
1. 静音ファン　*Noctua NF-A8 ULN*



# 作業内容
1. HSB4SATSASBA の裏のファンが収まってるケースを外す
    - ネジの正確なサイズは不明。自分は PH1 で作業した。
2. 元のファン規格確認
    - `Xj12b8020h` らしい
        - https://szdcfan.en.made-in-china.com/product/yKCxdEwGwsVe/China-Xj12b8020h-Sleeve-Bearing-Economic-Cooler-Fan-12V-DC-Car-Radiator-Fan.html
        - **80mm角、20mm厚**
1. ファン置換
    - 元ファンは 20mm 厚だが、25mm 厚ファンも使用可能
        - ケース側のネジ受けが出っ張っているため、ネジ長が 25mm 厚ファンでも足りる
    - 作業後の図 ![20240203_080958873_iOS.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278058/c72234fb-d6fa-eafb-4538-44b6693fe491.jpeg)
2. 電源繋いで起動
    - **元ファンは 3-pin だが、通常の 3-pin ではない** ため、交換したファンの電源は HSB4SATSASBA のピン経由で引っ張れない
    - 比較　![20240203_080948556_iOS.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278058/5f384732-f36b-4ff3-59bd-8901791ee0a0.jpeg)
        - 白いのが元ファン `Xj12b8020h`
        - 黒いのが `Noctua NF-A8 ULN`
3. 静かになった


# 以上、終わり
OCI Cacheについて基礎からまとめてみた

## はじめに
Oracle Cloud Infrastructure（OCI）で、データの読み取りと書き込みが高速化するマネージドインメモリデータベースの提供が開始されました(2023/10/17より)。

【アップデート】
Redisのライセンス変更に伴い、OCI Cache with RedisからOCI Cacheに名称が変更されています。
Redisのバージョンが7.4以降はValkeyとしての提供になりますが、旧バージョンには影響しないため、現在のOCI Cacheユーザーには影響しません。

https://docs.oracle.com/en-us/iaas/releasenotes/changes/43d86a10-11b1-4918-b009-5977d26dfbc9/

https://blogs.oracle.com/oracle4engineer/post/ja-oracle-supports-valkey

◆OCI Cacheについての参考リンク

https://www.oracle.com/jp/cloud/cache/

## そもそもRedisとは
:::note info
Redis (**RE**mote **DI**ctionary **S**erver)
* オープンソースかつインメモリのキーバリュー型データストア
* 開発者はVMware所属のエンジニアSalvatore Sanfilippo (2010/3)
* [DB-Engines Rabking](https://db-engines.com/en/ranking)で全体6位、キーバリューデータベースとして1位 (2024/1 現在)
:::
そんなRedisの機能として、
**①アプリケーションの応答性向上**、**②データ永続機能化**、③**データの高可用性**が特徴として挙げられます。
### ①アプリケーションの応答性向上
インメモリデータベースなので、時間のかかるDisk I/Oがなくなり、応答が早くなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3072173/46b48adb-c410-5132-2daf-4b4b0c4149f1.png)

### ②データの永続性
2種類の永続化設定によりデータ保持が可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3072173/cf2afcd9-3693-37dc-a932-9534a1e9da29.png)
Redisのデータ永続性はRDBとAOFの2つの方法で実現しています。

### ③データの高可用性
クラスタ構成によってデータの高可用性を実現しています。
プライマリノード(1つ)とレプリカノード(複数)によって構成されているため、プライマリノードのダウンタイムを最小限に抑えられようになっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3072173/a90dd63d-932e-8c5f-4df1-85846808fa31.png)

## OCI Cacheの特徴
特徴としては主に3点挙げられます。

:::note info
特徴としては下記の3点です。
* 設定が容易
* 自動的な高可用性構成
* シンプルな価格設定
:::
### 設定が容易
メモリ量とノード数のみ指定のシンプルなプロビジョニングが可能です。
1クラスタあたり5ノードまで、1ノード当たり2 GBから500 GBまで調整できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3072173/24c1e7a4-79a9-0ea2-01a0-d8c197b26401.png)
これらにより、最低限の操作でRedisをデプロイしユーザーの負担を軽減することができます。

### 自動的な高可用性構成
2つ以上のノードをデプロイするとOCIが自動的にノードをADまたはFDへ分散してくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3072173/cc250842-a4e3-8708-3459-f338160f1d8d.png)
システム障害に備え、自動的に可用性を向上させることが可能です。

### シンプルな価格設定
従量課金制であり、使用するメモリの総量のみに基づいています。
**<最初の10 GBまで>**
1 GBメモリ利用1時間ごとに¥3.007
**<11 GBを超える場合>**
それ以降の1 GBメモリ利用は1時間ごとに¥2.108

これにより、価格が予想しやすくニーズや予算に合わせた利用が可能になります。

* 具体例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3072173/18604bdb-7910-1fdf-d538-3db22bf66aba.png)

* [OCI価格リスト](https://www.oracle.com/jp/cloud/price-list/#pricing-open-source)からの引用
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3072173/1ad5e337-514d-1f82-a0a8-28363221a88a.png)
## 実際にOCI Cacheを試してみる
OCIで実際にOCI Cacheを利用してみるときは、以下の記事が非常に参考になりました。
この記事では、パブリックサブネットに作成したCompute（Oracle Linux）から、プライベートサブネットに立てたRedisにアクセスするような構成となっております。

https://qiita.com/atwits/items/cf79609e8a229bddbf4c

## おわりに
今回はOCI Cacheというサービスについて紹介いたしました。
日本企業におけるデータ活用の種類として、POSやEコマース、センサデータなどのリアルタイムデータを活用している企業が急増しているので、今後OCI Cache需要は拡大していくことでしょう。
複数のデータストアとマイクロサービスの仲介役をOCI Cacheが担うことで、DBの負荷軽減やマイクロサービスのパフォーマンス向上に寄与することができます。
【Swift】#if DEBUGによるデバッグ処理とConditional Compilation Blockについて

## はじめに
[iOS App Dev Tutorials / UIKit](https://developer.apple.com/tutorials/app-dev-training#uikit-essentials)に取り組んだ際、`#if DEBUG`フラグを活用した処理の実装に遭遇しました。チュートリアルによると、このフラグで囲まれたコードがコンパイルされなくなるようです。しかし、このコードが具体的に何を意味しているのか、また、同様のフラグが他に存在するのかについて疑問が残ったため調べてみました。
## #if DEBUGフラグについて
デバッグビルドの際に特定のコードを実行するため、Swiftでは`#if DEBUG`を使用し下記のようにブロックを作成します。
```swift:Swift
#if DEBUG
    // デバッグモードでのみ実行されるコード
    print("Debugging Only")
#endif
```
これにより、ブロック内のコードはリリースビルドでは無視されるようになります。
### 活用法
* ログ出力を制御し、デバッグ時のみ詳細なログを出力させる
* デバッグ時のみ実行されるコードブロックを作成して、テストケースを追加する
## Conditional Compilation Blockについて
`#if`,`#endif`というディレクションに囲まれたこのようなブロックをConditional Compilation Block（条件付きコンパイルブロック）と呼び、下記の形式で記述されます。
``` swift:Swift
#if <条件>
    <コンパイル制御したい内容>
#endif
```
通常のif文と異なり、コンパイル条件はコンパイル時に評価され、Trueの場合にブロックが実行されます。
また、`#elseif`,`#else`を使用することで分岐処理も可能です。

条件としては、下記の項目が使用可能です。
DEBUGは-D command line flagに該当するようです。
* Bool値
* -D command line flag （例: DEBUG）
* プラットフォーム条件 （例: os(macOS)、arch(x86_64)）


また、XcodeのBuild Settings -> Swift Compiler - Custom Flagsを設定することで、リリースビルドのみの処理を行うためのフラグなどを設定することもできるようです。

![スクリーンショット 2024-02-04 0.43.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613152/85bbfb17-e152-6bcf-a667-47755cfe3a99.png)
## <参考>
https://docs.swift.org/swift-book/documentation/the-swift-programming-language/statements/#Conditional-Compilation-Block
【java+spring boot】ローカルでファイル添付処理を実装してみた：読み解き（１）

## こちらの続き 
[【java+spring boot】ローカルでファイル添付処理を実装してみた](https://qiita.com/macha_7/items/4f9d613e913b6bd95a30)

### 【読み解き】実装を調べてみた
主には参考にしたページで解説されているがちょっと難しい。
実装みながら自分なりにまとめてみる。

## 実装箇所の概要
#### メイン
- Controller
- StorageService（interface）
- FileSystemStorageService (implements StorageService)
- StorageProperties
- MainApplication

#### 例外
- StorageException extends RuntimeException
- StorageFileNotFoundException extends StorageException

#### その他
- html(template)
- application.properties

→ それぞれの役割と処理についてざっと書き出して最後にまとめる。
　書き出し順は適当。

## 役割と処理を書き出す

 #### StorageProperties
まず[最初の記事](https://qiita.com/macha_7/items/4f9d613e913b6bd95a30)にも記載したように、ここでは**ファイルデータを保管するロケーションのパスを指定**している。今回は`"upload-dir"`を設定。
これをBean登録することで、**パスを処理するときに簡単に呼び出して使うことができる**。

```java
@Component // ConfigurationPropertiesを付けたクラスに付けることでBeanに登録する
@ConfigurationProperties("storage") //DIコンテナに登録されたBeanに対してプロパティを設定するためのアノテーション
public class StorageProperties {
    /**
     * Folder location for storing files
     */
    private String location = "upload-dir";

}
```

:grey_question: **`@ConfigurationProperties("storage")`** を詳しく...
参考：[Spring Bootの@ ConfigurationPropertiesで型安全なプロパティ設定](https://ik.am/entries/376)
> **@ConfigurationPropertiesアノテーション**をつけることで、**プロパティ値が各フィールドにインジェクションされます**。 prefix属性をつけることで、プロパティ値のプリフィクスを設定することもできます。

>**@ConfigurationProperties**は正確に言うと、プロパティクラスを定義するアノテーションではなく、 **DIコンテナに登録されたBeanに対してプロパティを設定するためのアノテーション**です。 この例だと、@ComponentをつけてDIコンテナに登録されたtargetPropertiesというBeanの hostプロパティに対してプロパティファイル中のtarget.hostの値を設定し、 portプロパティに対してプロパティファイル中のtarget.portの値を設定しています。 インジェクション対象のBeanにSetter/Getterが必要なのはこのためです。

ふむ、本記事にそって言い換えると、
`@Component`をつけてDIコンテナに登録された`StorageProperties`というBeanの `storage`プロパティに対してプロパティファイル中の`storage.location`の値を設定している。初期値は`upload-dir`。
また、インジェクション対象のBeanにSetter/Getterが必要（今回はLombokでアノテーション追加しているのでOK）。

#### StorageService(interface)
　サービスは主にController で呼び出す基本的な処理を切り分けて実装する。こちらはインターフェースなので、実際の処理は`implements`して`FileSystemStorageService`に実装されている。敢えてインターフェースにしているということは、ファイル処理に最低限必要な処理を定義しているということ、か。
 
それぞれの役割を簡潔にコメントで記載。
```java
public interface StorageService {

	void init(); // 保管先の親ディレクトリを作成、アプリ実行度に実行（※）

	void store(MultipartFile file); // ファイル保存 ※storeの動詞は「保管する」の意味

	Stream<Path> loadAll(); // 保管しているファイルパスを走査（画面表示に利用）

	Path load(String filename); // 「保存場所のパス+ファイル名」のパスを返す

	Resource loadAsResource(String filename); // 引数のfilenameが保管先に存在し、リソースとして読み取り可能かチェックする

	void deleteAll(); // 保管用の親ディレクトリごと削除、アプリ実行度に実行（※）

}
```
これらを用いてあれやこれやして、ファイルの保管や取得を行う。
ファイル操作の流れ別に処理を見ていく...は長くなるので次の投稿で


### 引用リスト
1. [【Spring】＠Autowiredはコンストラクタインジェクションで使おう！](https://qiita.com/yuto-hatano/items/69d01343f710117e4243)
1. [ファイルのアップロード](https://spring.pleiades.io/guides/gs/uploading-files/)
1. [【Spring】インターフェース MultipartFile](https://spring.pleiades.io/spring-framework/docs/current/javadoc-api/org/springframework/web/multipart/MultipartFile.html)
1. [Spring Bootの@ ConfigurationPropertiesで型安全なプロパティ設定](https://ik.am/entries/376)
【Kotlin】リストに追加 / リストの結合

## 1. add() : 単一の値を追加する
※Mutable(可変)なリストでないと`add()`は使用不可であることに注意！
```kotlin:
fun main(){
    val list1 = mutableListOf(1, 2, 3)

    list1.add(4)

    println("結合結果 : $list1")
}
```

### Output：
```
結合結果 : [1, 2, 3, 4]
```


## 2. addAll() : 2つのリストを結合
※Mutable(可変)なリストでないと`addAll()`は使用不可であることに注意！
```kotlin:
fun main(){
    val list1 = listOf(1, 2, 3)
    val list2 = listOf(1, 4, 5, 6)

    val joinedList = mutableListOf()
    joinedList.addAll(list1)
    joinedList.addAll(list2)

    println("結合結果 : $joinedList")
}
```

### Output：
```
結合結果 : [1, 2, 3, 1, 4, 5, 6]
```

## 3. Plus演算子 : ２つのリストを結合
```kotlin:Plus演算子を用いた結合
fun main(){
    val list1 = listOf(1, 2, 3)
    val list2 = listOf(1, 4, 5, 6)

    val joinedList = list1 + list2

    println("結合結果 : $joinedList")
}
```

#### Output：
```
結合結果 : [1, 2, 3, 1, 4, 5, 6]
```

## 4. plus() : ２つのリストを結合
```kotlin:Plus演算子を用いた結合
fun main(){
    val list1 = listOf(1, 2, 3)
    val list2 = listOf(1, 4, 5, 6)

    val joinedList = list1.plus(list2)

    println("結合結果 : $joinedList")
}
```

### Output：
```
結合結果 : [1, 2, 3, 1, 4, 5, 6]
```

## 5. union() : 重複削除かつリストの結合
```kotlin:
fun main(){
    val list1 = listOf(1, 2, 3)
    val list2 = listOf(1, 2, 4, 5, 6)

    val joinedList = list1.union(list2)

    println("結合結果 : $joinedList")
}
```
### Output：
重複した値`1`を削除したうえで結合した結果が返却される
```
結合結果 : [1, 2, 3, 4, 5, 6]
```
完全コンストラクタ（「良いコード悪いコードで学ぶ設計入門」復習）

# 背景
「良いコード悪いコードで学ぶ設計入門」の復習の為です。TypeScriptで記述します。
今回は「完全コンストラクタ」についてです。

# インスタンス変数が未初期化状態（生焼けオブジェクト）
```ts
class Car {
  name: string | undefined;
}

const car = new Car();
car.name;
//undefined
```
このようなインスタンス変数の未初期化状態が発生しうるクラスを```生焼けオブジェクト```といいます。

# 不整値の混入

```ts
class Person {
    age:number;

    constructer(age:number){
        this.age = age;
    }
}

const p = new Person(-1);
```
Personクラスは人間の年齢を表すage変数を持ちます。
ここに負の値を設定できてしまいます。

これだと後続処理で年齢が正の値かどうかを毎回判定しないといけないです。

# 完全コンストラクタ
完全コンストラクタとは以下を満たすコンストラクタのことを言います。
- インスタンス変数を全て初期化する
- 不正な値をインスタンス変数に設定できない

以下が完全コンストラクタの例です。

```ts
class Person {
    age:number;
    
    constructor(age:number){
        if(!number)throw new Error('年齢は1以上を指定してください。');
        this.age = age;
    }
}
```

このようにすると生成されたインスタンスが後続の処理で安全に使用されます。

また、以下のようにインスタンス変数をprivateにし、外部に公開しないこと（[カプセル化](https://webpia.jp/encapsulation/)）でさらに不正に強いクラスになります。
```ts
class Person {
    private age:number;
    
    constructor(age:number){
        if(!number)throw new Error('年齢は1以上を指定してください。');
        this.age = age;
    }

    getAge(){
        return this.age;
    }
}
```

# 最後に
不正値のバリデーションは実装したことがなかったので、気をつけたいと思いました。

# 参考
- [良いコード悪いコードで学ぶ設計入門](https://gihyo.jp/book/2022/978-4-297-12783-1)
- [カプセル化](https://webpia.jp/encapsulation/)
p5.js でカメラ画像のアスペクト比は保ちつつキャンバスにピッタリ合うように表示位置・サイズを調整する

記事の内容はタイトルの通りです。

p5.js でカメラ画像を使った作品をよく使うのですが、例えば以下のようなシェーダーを絡めた処理や、その他 AI・機械学習を組み合わせた処理を行った場合に、解像度の高い画像を使うと処理が重たくなることがあります。

https://twitter.com/youtoy/status/1752373799339823116

その場合に、処理する画像の解像度をあまり高くしないで処理するということがありました。
一方で、展示イベントなどに出した際に、カメラ映像は 640x480 などの解像度を使ったとしても表示上は画面いっぱいか、それに近いサイズで表示させたいという場合があります（※ カメラ画像のアスペクト比は変えないようにしつつ）。

このような場合に、処理する画像は画面いっぱいのサイズより小さいものを使っていても、表示では画面いっぱいに表示する、ということを行うプログラムをメモとして残してみます。

## パターン1： キャンバスサイズが固定
まずはキャンバスサイズが固定の場合の例です。

まずはプログラムを示します。こちらは、キャンバスのサイズは 700x800（や、900x500）で、それに対してカメラ画像は 640x480 のサイズにしたものです。

```javascript
let capture;

function setup() {
  createCanvas(700, 800);
  // createCanvas(900, 500);

  capture = createCapture(VIDEO);
  capture.size(640, 480);
  capture.hide();
}

function draw() {
  background(220);

  // キャンバスとカメラ映像のアスペクト比に基づくスケーリング比を計算
  let scaleX = width / capture.width;
  let scaleY = height / capture.height;
  let scale = min(scaleX, scaleY); // 幅と高さの比率のうち、小さい方を選択

  // スケーリングされた映像のサイズを計算
  let scaledWidth = capture.width * scale;
  let scaledHeight = capture.height * scale;
  // スケーリングされた映像を中央に配置するためのもの
  let offsetX = (width - scaledWidth) / 2;
  let offsetY = (height - scaledHeight) / 2;

  image(capture, offsetX, offsetY, scaledWidth, scaledHeight);
}
```

内容的には、以下のようなことをやっています。

1. カメラ画像のアスペクト比を保ってキャンバスサイズの縦・横のそれぞれに合わせてスケーリングした場合の、比率の値が小さい方を選択
1. 上記の比率を使ってカメラ画像をスケーリング
1. スケーリングしたカメラ画像を画面中央に表示するような、画像描画の基準点からのオフセットを計算
1. 上で求めたパラメータを使ってカメラ画像を表示

これを実行すると、以下のようにカメラ映像をスケーリングした後キャンバス上で余った部分が、カメラ画像の上下か左右のどちらかに均等に割りふられる形になっているのが分かります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/a77b7b8e-2c75-6124-450b-32d5ff857e62.png)

これで、スケーリングした後のカメラ画像が、キャンバスの中央に表示されました。

## パターン2： キャンバスサイズがウィンドウサイズに合わせて変わる場合（リサイズも考慮）
次は、キャンバスサイズがウィンドウサイズに合わせたものになる場合です。
そして、リサイズが行われた場合の対処も考慮します。

メインの処理部分は、上で提示したものとあまり変わらないのですが、プログラムは以下のようになります。

```javascript
let capture;
let scale;
let offsetX, offsetY;

function setup() {
  createCanvas(windowWidth, windowHeight);

  capture = createCapture(VIDEO);
  capture.size(640, 480);
  capture.hide();

  calculateLayout();
}

function draw() {
  background(220);

  image(
    capture,
    offsetX,
    offsetY,
    capture.width * scale,
    capture.height * scale
  );
}

function windowResized() {
  resizeCanvas(windowWidth, windowHeight);
  calculateLayout();
}

function calculateLayout() {
  // キャンバスとカメラ映像のアスペクト比に基づくスケーリング比を計算
  scale = min(width / capture.width, height / capture.height);

  // スケーリングされた映像のサイズを計算
  let scaledWidth = capture.width * scale;
  let scaledHeight = capture.height * scale;

  // スケーリングされた映像を中央に配置するためのオフセットを計算
  offsetX = (width - scaledWidth) / 2;
  offsetY = (height - scaledHeight) / 2;
}
```

windowResized() の処理の際にも、スケーリングの比率・オフセットの再計算をする、というのを忘れず行う必要があります。

こちらの実行結果は省略しますが、ウィンドウサイズを変更しても、カメラ画像のアスペクト比は維持されつつキャンバスに合わせてスケーリングされる、という結果を確認できます。
代表的なSAPサービスの違い～SAPonAWS勉強法～

SAPonAWS受験に向け、代表的なSAPサービスの違いについて初心者向けに簡単にまとめました。  

## SAP HANA
High-Performance Analytic Appliance
インメモリ（処理が爆速）で列志向（分析が得意）の**データベース**。
普通のDBより処理が早く（数100倍）、分析が得意。
インメモリデータベースのデメリットは、ストレージを利用するDBよりコストが高く、耐久性も低いこと。
SAP HANAではスナップショットやトランザクションログ等の工夫により、障害対策が行われている。

## SAP S/4 HANA 
SAP Business Suite for SAP HANA

SAP HANA を用いた[ **ERP(Enterprise Resource Planning)** ](https://e-words.jp/w/ERP.html)**製品**。
経営のため、購買、製造、物流、在庫管理、販売、給与、財務・会計などを一元管理する。
SAP HANAという高性能なデータベースを用いている。

## SAP Commerce (SAP hybris)
hybris社を買収して作った**顧客管理製品**
販売チャネルや・顧客に関することを一元管理できる。

## SAP BW 4 HANA
SAP Business Warehouse for HANA
大規模な業務データの分析を行うための**データウェアハウス**

## SAP Business Suite
ERP製品やCRM（顧客管理）製品など、**SAPの様々な製品をまとめた製品**
HANAは使っていない？？

## SAP Buisiness One
**中小企業向けに**SAPの様々な製品をまとめた製品

## SAP BusinessObjects
SAP BusinessObjects Business Intelligence
SAPの**BI製品**
データのレポーティング、ビジュアル化、共有機能が一元化されたスイート。
ERPは**経営のために**データを一元化したもの。
BIはデータをビジュアライズするためのもの。経営目的だけでない。
CDデッキにTelnet 〜 TASCAM SS-CDR250N を、QLab5で動かす

# いまどきtelnet?!
2017年に発売された業務用CDレコーダー・ソリッドステートレコーダー TASCAM SS-CDR250Nにはethernet端子が装備され、ネットワークにつながるデッキとなりました。
FTPでのデータ転送ができるなど、常設機器としての保守性が高まった機種ですが、
アプリケーションからのリモート制御が可能になり、現場での操作性が格段に向上しました。

そして、なんとtelnetリモートができるというんです。
ネットワークに詳しいと、いまどきtelnet? SSHじゃないの?とか思ってしまうのですが、
まあ、そんなセキュリティリスクの高いような環境に置かれることはほぼないでしょうし、なんなら平文のまま送受信されるtelnetは都合がいいというところでしょうか。

TASCAMといえば、むかしからRS-232C制御が可能な機種も数多く、過去にはPCからRS-232CでCDデッキのリモートや、情報表示などを試したこともあります。
直接接続可能な環境でしたら、RS-232Cのほうがより安定した制御が可能です。

# QLabでtelnet
QLab といえば、ここ数年で一気に音響のポン出し（再生）アプリとして定着した感じがするソフトですが、
ネットワーク経由での制御コマンドを送信できる、「ネットワークキュー」の機能があります。
おもに、OSC (Open Sound Control)が主で、QLab4まではUDP Messageのみが対応していましたが、
QLab5ではTCP Messageまで対応の幅が広がり、一気に制御の対象が増えました。

https://qiita.com/hiro_esaki/items/df00cb4b9e0373be7a4e

# 実際の設定
実際のセッティングを紹介します。

## ネットワーク設定
TASCAM SS-CDR250NとQLabの立ち上がったMacを同一ネットワーク内に設定します。

DHCPでもstaticでも良いですが、SS-CDRのIPアドレスを確認しておきます。
[MENU] > [NETWORK] > [IP ADDRESS]

QLabのネットワークパッチを作ります。
![スクリーンショット 2024-02-04 0.11.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601755/b78e328b-6742-5af4-54d2-f4917f663664.png)

192.168.0.196のSS-CDR250Nへのパッチの例。
telnetのポートナンバーは23です。

これで、telnet接続する下地ができました。

## 実際のキュー
```:QLab5から再生させるキュー
\r\nSS-CDR250N\r\n012\r\n
```

telnetで接続すると、何かメッセージが送られるまで待機状態となります。
まずは、改行(\r\n)だけ送ります。
本来、ここで、「Enter Password」とメッセージが返ってくるのですが、QLabでそれを確認する方法はありません。

`EnterPassword`と聞かれているはずなので、`SS-CDR250N`（SS-CDR上で設定されているIP PASSWORD）を送信し、`login successful`となったであろうところで、
`012\r\n` （再生）を送ります。

このキューを走らせると、SS-CDR上で再生されているはずです。

## キューの紹介（一部）
``` : STOP
\r\nSS-CDR250N\r\n010\r\n
```
0 : machine ID （通常0）
10 : 停止コマンド

``` : Track 12を選択
\r\nSS-CDR250N\r\n01401\r\n0231200\r\n
```
0 : machine ID（通常0）
1401 : pause

0 : machine ID
23 : ダイレクトトラックサーチ
1200 : トラック12

ちなみに、トラックナンバーの指定は少し癖があり、左から十の位、一の位、千の位、百の位、となっています。
つまり、（実際にはありえませんが）トラック1234を指定する場合、3412となります。

``` : Next
\r\nSS-CDR250N\r\n01A00\r\n
```

QLabでtelnetが行けたよ、という記録でした。
これが実際の現場にどう活かせるかは未知数ですが、例えば、QLabのバックアップでもとのCDを再生する、特定のトラックを再生したあとでauto readyを切り替える、なんかは便利に使えるかもしれません。

でも、それすべて**QLabのほうが得意**なんですけどね。笑

どうしてもCDを取り込んではいけないとか、絶対にデッキを使用しないといけない、みたいな状況のときにお試しください。
周期的な数パターンループの綺麗な実装

本日は軽いネタを紹介しようと思います．

周期的な数パターンをループさせたい時ってありませんか？
具体的には **[0,1,2,3,0,1,2,3,0,1...]**, **[3,2,1,0,3,2,1,0,3,2...]** というような形で変数を周期的に変化させたいケースです．

最近，私はキャラクターを上下左右に時計回りと反時計回りで回転させたかった時にこの実装と出会いました．

この時の実装方法でちょっと綺麗な実装を思いついたのでご紹介します．

## 周期的なインクリメント
キャラクターを上下左右に回転させる場合について考えていきます．
上=0, 右=1, 下=2, 左=3と数を割り振ると，キャラクターの時計回りの回転操作は，周期的なインクリメントと言えます．
この場合ループする変数はキャラクターの方向となります．
ループの際のパターン数は上下左右なので4通りとなります．

ここで，**周期的なインクリメントは，ループ対象の変数をインクリメントした後，パターン数で割って余りを計算する**のがおすすめです．
これはほとんどの方がすぐに想像できると思います．

以下にキャラクターを上下左右に時計回りで回転させる場合のGoの実装例を示します．
`rotate_clockwise()`メソッドにご注目ください．

```Go
const (
	UP    = 0
	RIGHT = 1
	DOWN  = 2
	LEFT  = 3
)

type character struct {
	direction int
}

func (c *character) rotate_clockwise() { // 時計回り
	c.direction = (c.direction + 1) % 4
}

func main() {
	c := character{direction: UP} // 初期方向をUPに設定
	fmt.Printf("Initial direction: %d\n", c.direction)

	for i := 0; i < 8; i++ {
		c.rotate_clockwise()
		fmt.Printf("Direction after rotate %d: %d\n", i+1, c.direction)
	}
}
```

```text
Initial direction: 0
Direction after rotate 1: 1
Direction after rotate 2: 2
Direction after rotate 3: 3
Direction after rotate 4: 0
Direction after rotate 5: 1
Direction after rotate 6: 2
Direction after rotate 7: 3
Direction after rotate 8: 0
```

## 周期的なデクリメント
キャラクターを上下左右に回転させる場合について考えていきます．
上=0, 右=1, 下=2, 左=3と数を割り振ると，キャラクターの反時計回りの回転操作は，周期的なデクリメントと言えます．
先ほどと同じく，ループする変数はキャラクターの方向，ループの際のパターン数は上下左右なので4通りとなります．

ここで**周期的なデクリメントは，ループ対象の変数にパターン数を足してデクリメントした後，パターン数で割って余りを計算する**のがおすすめです．
これはやや直感的でないので思いつかない人も多いかもしれません．

注意点として，言語によってはパターン数を足さないと動作しない場合があります．
パターン数を足さない実装をする人は，`c.direction = (c.direction - 1) % 4`のように書きます．
これは，`-1 % 4 = 3, なぜならば -1 = 4 * (-1) + 3 `という考え方です．
これは少なくともGoでは動作しません．(`-1 % 4 = -1` となります．)
このようにプログラミング言語によっては余りの計算方法が数学的な考えと異なる場合もあるので，今回紹介する実装のほうが好ましいでしょう．


以下にキャラクターを上下左右に反時計回りで回転させる場合のGoの実装例を示します．
`rotate_counterclockwise()`メソッドにご注目ください．

```Go
const (
	UP    = 0
	RIGHT = 1
	DOWN  = 2
	LEFT  = 3
)

type character struct {
	direction int
}

func (c *character) rotate_counterclockwise() { // 反時計回り
	c.direction = (c.direction + 4 - 1) % 4
}

func main() {
	c := character{direction: UP} // 初期方向をUPに設定
	fmt.Printf("Initial direction: %d\n", c.direction)

	for i := 0; i < 8; i++ {
		c.rotate_counterclockwise()
		fmt.Printf("Direction after rotate %d: %d\n", i+1, c.direction)
	}
}
```

```Text
Initial direction: 0
Direction after rotate 1: 3
Direction after rotate 2: 2
Direction after rotate 3: 1
Direction after rotate 4: 0
Direction after rotate 5: 3
Direction after rotate 6: 2
Direction after rotate 7: 1
Direction after rotate 8: 0
```

rotate_counterclockwise()メソッドの実装は，剰余演算子%を使うことで，以下のような実装よりもすっきりしています．
```Go
func (c *character) rotate_counterclockwise() { // 反時計回り
	c.direction--
    if c.direction < 0 {
        c.direction = 3
    }
}
```

いかがでしたでしょうか？
今後このパターンは,綺麗に書けるようにしたいですね．
単体テストの考え方/使い方-第一章学んだことまとめ

# 読んだ本

[Amazon\.co\.jp: 単体テストの考え方/使い方 eBook : Vladimir Khorikov, 須田智之: 本](https://amzn.asia/d/4PLqvOy)

# 第1章　なぜ、単体(unit)テストを行うのか
- 単体テストの現状について知ってもらうことが目標
- 単体テストをする目標とは？
- 良い単体テストが持つ主な特徴

開発者は単体テストに費やした時間と見合った結果を最大限に引き出せるように努力をしなくてはならない。
⇒テストにかける労力をできるだけ抑え、テストから最大限の価値を引き出さなくてはならない。

このバランスが取れているプロジェクトは
- 成長すること(つまりはプロジェクトが大きくなること？)に対してあまり労力を必要としない
- 保守に対する負担もそれほど大きくはない
- 顧客の要求に速やかに対応できる

## 1.1 単体テストの現状
作成した単体テストが機能しないとむしろ開発の足を引っ張る形になってしまう。
単体テストを作成するだけではなく、`費やした労力に見合った結果を引き出せる単体テストを作成できるようになることが基本を学んだ次の段階になる`

## 1.2 なぜ、単体テストを行うのか？
単体テストの目標は何か？
よく言われるのが「設計がより優れたものになる」というもの。
しかしこれは単なる副産物であり第一目標ではない。

:::note info
- 単体テストが作成しずらい⇒テスト対象コードが何らかの改善を必要としている
- 単体テストを作成しやすい⇒プロジェクト・コードの質が良いという判断を下すことはできない
:::
単体テストで何を成し遂げるか？
⇒ソフトウェア開発プロジェクトの成長を「 **持続可能** 」なものにすること
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/472955/c6cd400e-5577-da45-3c9f-a5b05eb96eaf.png)

テストを用意しておくことで変更によって生じる退行を検出するセーフティネットがプロジェクトに備わることになる。

テストの質が悪いとテストを全くしない場合と同じ結果になる。
長い目で見ると単体テストの質が悪ければ、テストが全くない場合と実質的に変わらない。

[^KEY]テスト・スイートに含まれているケースの質が悪いとテストが間違った理由で失敗することが頻繁に起こり退行をきちんと検出できなかったり、てテストに時間がかかりすぎて簡単に保守できなくなってしまう。

:::note info
テストケースが多いほど良いと思っている開発者が多く存在するが、その考えは間違いである。
**なぜならコードは資産ではなく負債だからです。**
コードが増えるということはバグが持ち込まれる可能性が上がる。
コードは最小限にするべきである。
:::


## 1.3 網羅性とテスト・スイートの質との関係
網羅性(テスト。スイートに含まれているテストケースが実行するプロジェクトコードの割合のこと)
に依存してテスト・スイートの質を評価することは間違いである。
網羅性はテスト・スイートの質が悪いことを示せても、質が良いことを証明することはできないから。
※コード網羅性についてはまとめててつまらなかったので省略


## 1.4 何がテスト・スイートの質をよくするのか？
テスト・スイートの質をどのように評価すべきか？
結局のところテスト・スイートの評価に関して信頼できる方法は各テスト・ケースを1つずつ評価することしかない。
優れたテストケースには次の特徴がある。
- テストすることが開発サイクルの中に組み込まれている
    
- コートベースの特に重要な部分のみがテスト対象となっている
    
- 最小限の保守コストで最大限の価値を生み出すようになっている

### テストすることが開発サイクルの中に組み込まれている
- 理想はコード変更を加えるたびにテストが実施されること

### コートベースの特に重要な部分のみがテスト対象となっている
- 重要なことは**単体テストにかける労力をシステムにとって非常に重要な部分に向けるということ**
- ほとんどのアプリケーションでテストに時間を費やして価値のある所はビジネスロジックを含む部分(ドメイン・モデル)の部分になる
- ドメイン・モデルではないコードは以下
    - インフラに関するコード
    - 外部サービスや依存関係にあるもの
    - 構成要素同士を結び付けるコード

ドメインモデルを意識するためにもそれ以外の部分は隔離しておかなかればならない

### 最小限の保守コストで最大限の価値を生み出すようになっている
単体テストにおいて最も難しい部分は、最小限の保守コストで最大限の価値を生み出すこと。
このことを実現するためには次の2つのことを行えなくてはいけない。
- 価値のあるテスト・ケースを認識できること
- 価値のあるテスト・ケースを作成できること

## 1.5 本書から学べること
- テスト・スイートに含まれるテスト・ケースを分析する際の基準となる枠組みについて学び、その枠組をつかってどのようにテストケースを分析するのかを見ていく
- 多くのテストケースを新しい視点から評価できるようになる
- より価値をもたらすテストコードとなるようなリファクタリングを行えること

[^KEY]: 目的や対象ごとにテスト・ケースを集めたもの