OmniAICreator/Qiita-1.07M huggingface dataset:
SwiftでL-System

## はじめに

[こちら](https://qiita.com/yukiny/items/7b5692b503fc7db921d4)の記事で紹介しました[SwiftyCreatives](https://github.com/yukiny0811/swifty-creatives)というSwift製のクリエイティブコーディングフレームワークを用いてL-Systemを実装していきます。

## L-Systemとは
L-Systemはフラクタル図形を描画するためのアルゴリズムです。プログラムの再帰性を用いて簡単にフラクタルが描画できるようになっています。

## 実装結果
![QuickTime Player - 画面収録 2023-02-10 1.53.14.mov 2023年-02月-10日 2.55.14.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567236/99b4c224-2631-e532-d6bd-dc60749c7f86.gif)

## 実装
コードはとてもシンプルです。
実装方法についてはたくさん記事が出ているのでそちらをみていただけると助かります。
この記事ではSwiftyCreativesを用いた実装を紹介します。
Processingライクに書くことができます。


```.swift
import SwiftyCreatives
import CoreGraphics
import AppKit

final class TreeSketch: Sketch {
    // これを用いて描画する
    var tree = "F"
    override func setupCamera(camera: some MainCameraBase) {
        // カメラの初期位置を設定
        camera.setTranslate(0, -20, -40)
    }
    override func update(camera: some MainCameraBase) {
        // 毎フレーム0.01radカメラを回転させる
        camera.rotateAroundY(0.01)
    }
    override func draw(encoder: SCEncoder) {
        for t in tree {
            compile(char: t)
        }
    }
    // 何かキー入力がされたら枝を増やす
    override func keyDown(with event: NSEvent, camera: some MainCameraBase, viewFrame: CGRect) {
        var currentTree = ""
        for t in tree {
            if t == "F" {
                currentTree += "FyF+[+FyF-yB]-y[-yF+YP]"
            } else {
                currentTree += String(t)
            }
        }
        tree = currentTree
    }
    func compile(char: Character) {
        switch char {
        case "B":
            color(0.5, 0.5, 1.0, 1.0)
            boldline(0, 0, 0, 0, 1, 0, width: 0.1)
            translate(0, 1, 0)
        case "P":
            color(1.0, 0.3, 1.0, 1.0)
            boldline(0, 0, 0, 0, 1, 0, width: 0.1)
            translate(0, 1, 0)
        case "F":
            color(0.9, 1.0, 1.0, 0.8)
            boldline(0, 0, 0, 0, 1, 0, width: 0.1)
            translate(0, 1, 0)
        case "+":
            rotateZ(0.3)
        case "-":
            rotateZ(-0.3)
        case "[":
            pushMatrix()
        case "]":
            popMatrix()
        case "y":
            rotateY(0.15)
        case "Y":
            rotateY(-0.15)
        default:
            break
        }
    }
}
```


## MacOSアプリへの導入
SwiftUIのViewとして使えます。

```.swift
ZStack {
    SketchView<MainCameraConfig, MainDrawConfig>(TreeSketch())
}
.background(.black)
```

## iOSアプリへの導入
同じくSwiftUIのViewとして使えます。
ただ、keyDown()がiOSでは使えないので、touchesBegin()などで代用してください。
FlutterでFirebaseStorageに保存している音声ファイルを再生する


## この記事を書こうと思ったきっかけ
Flutterの自己学習でポケモン図鑑を作成してみようと思った際、
鳴き声を再生させる機能が欲しかったため自分なりに実装してみました!

## 前提条件
たくさんの方がFlutterでFirebaseの連携方法をわかりやすく書いてくださっているので
本記事では省略させて頂きます。
別途FirebaseStorageにどのようなフォルダ構造で自分が保存しているかは記載致します。
また音声ファイルを再生するためjust_audioもインポートします。
バージョンは下記になります。

``` 
  firebase_core: ^2.5.0
  cloud_firestore: ^4.3.2
  firebase_storage: ^11.0.11
  just_audio: ^0.9.31
``` 
## 1.FirebaseStorageに音声ファイルを保存
FirebaseのプロジェクトからStorageを選択しプロジェクトを開始します。
その後DLというフォルダを作成しDLフォルダの中に
再生したい音声データをアップロードします。
下記キャプチャは音声データをアップロードしている状態です。
![スクリーンショット 2023-02-10 1.36.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2265372/9c5021d9-8b38-a71e-b7e6-8b9890a4f0d9.png)

## 2.main.dartでFirebaseStorageに保存している音声のURL取得メソッドを作る
Future<void> _download()というメソッドを作成し
FirebaseStorageのDLフォルダ内にある音声ファイルのURLを取得する処理を記載します。
コード毎の処理も下記に記載しております。
``` 
class _MyHomePageState extends State<MyHomePage> {

  Future<void> _download() async {
    FirebaseStorage storage = FirebaseStorage.instance;
    //firebase_storageのDLフォルダ内の001.wav音声をitemRefに入れる
    Reference itemRef = storage.ref().child("DL").child("001.wav");
    //itemRefからURLを取得しitemUrlに入れる
    String itemUrl = await itemRef.getDownloadURL();
  }
``` 

## 3. 2で作成したメソッドに音声フォルダを再生する処理を追加 

``` 
class _MyHomePageState extends State<MyHomePage> {
  //3で追加
　final player = AudioPlayer();

  Future<void> _download() async {
    FirebaseStorage storage = FirebaseStorage.instance;
    //firebase_storageのDLフォルダ内の001.wav音声をitemRefに入れる
    Reference itemRef = storage.ref().child("DL").child("001.wav");
    //itemRefからURLを取得しitemUrlに入れる
    String itemUrl = await itemRef.getDownloadURL();
　　//ここから下の処理が3で追加
　　//もしitemUrlが空じゃなければplayerにURLをセット
    if( itemUrl != "") {
      await player.setUrl(itemUrl);
    } else {
      print('失敗');
    }
    //音声を鳴らす
    player.play();
  }
``` 

あとは上記のメソッドをボタン押下時の処理(onPressed等)に入れて頂ければと思います。


## まとめ
メソッドをもう少し処理毎に分けた方がいいかと思いましたが
ひとまず音声ファイルの再生は可能だと思います。
他にも図鑑に入れたい機能があるので実現できたら記事書いてみようと思います。
ポケモンのゲームの鳴き声ってアニメと全く違うのでギャップにびっくりします、、
BitriseのmacOSスタックにGoogle Cloud SDKをインストールして使う

普段Bitriseを使ってiOSアプリのCIをしていて、ビルド成果物をGoogle Cloud Storageにアップロードしたりしています。

Google Cloud Storageとやり取りするには`gcloud`や`gsutil`といったコマンド群を含むGoogle Cloud SDKが必要なのですが、残念ながらmacOSスタックにはインストールされていません。

Xcode14.2 macOS Venturaのスタック情報はこちら。
https://github.com/bitrise-io/bitrise.io/blob/master/system_reports/MACOS/M1/osx-xcode-14.2.x-ventura.log

本記事では、macOSスタックにGoogle Cloud SDKをインストール＆キャッシュして、次回以降のビルドですぐにコマンドを使えるようにする方法をご紹介します。

# Google Cloud SDKのインストール＆キャッシュ
ワークフローにScriptステップを追加し、以下のスクリプトを入れておきます。

```bash
#!/usr/bin/env bash
# fail if any commands fails
set -e
# make pipelines' return status equal the last command to exit with a non-zero status, or zero if all commands exit successfully
set -o pipefail
# debug log
set -x

# write your script here
if [ ! -d $HOME/google-cloud-sdk ]; then
  curl https://sdk.cloud.google.com | bash 
fi
source $HOME/google-cloud-sdk/path.bash.inc
gcloud components update
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81715/aa4e88c3-2c33-353c-2a04-26343de3fb88.png)


次に、ワークフローにCache:Pushステップを追加し、以下のパスを入力します。

```
$HOME/google-cloud-sdk
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81715/3b9fa67d-070c-581e-8773-85565f60164a.png)

これらのステップの追加により、以下の処理が行われます。

- `$HOME/google-cloud-sdk`ディレクトリがなければSDKをインストールする
- SDKを最新にアップデートする
- `$HOME/google-cloud-sdk`ディレクトリをキャッシュする

私は上記ステップを加えたワークフローを毎晩ビルドするようにして、常に最新のSDKがキャッシュされた状態にしています。

こうすることで、他のワークフローではSDKをインストールする必要がなく、すぐに`gsutil`等のコマンドを使用することができます。
エックスサーバー ｘ Thunderbird でアカウント内のごみ箱フォルダなどが表示されなかった

## 環境と経緯

- OS: Windows 10 Pro
- Software: Thunderbird 102.7.2 (32 bit)
- サーバー: エックスサーバー スタンダード
- 受信サーバーの種類: IMAP

とあるサーバーからエックスサーバーへサーバー移行する機会があり、上記構成でThunderbirdにアカウントを設定した。  
※ Thunderbirdには移行元サーバーのアカウントもエックスサーバーのアカウントも登録されている状態。

メールの移行は単純に全選択でD&Dで移動して完了したのだが。。。エックスサーバーのアカウントには「受信トレイ」と「送信済みトレイ」しか表示されていない。数日経っても変わらず。丁度迷惑メール来たので【削除】実行 → ゴミ箱現れず！！どこ行ったん！？  
削除でゴミ箱表示されなかったら、後で戻せないやん、確認すらできないし。とりあえずは、Ctrl+Z で元に戻した。

ちなみに、WEBメールで確認すると削除マークがついた状態、受信トレイにはある状態だったようだ。

## 解決策

先に解決した設定を。

解決となったのは、「アカウント設定－該当アカウント－サーバー設定－サーバー設定－詳細設定（ボタン）－購読しているフォルダーのみ表示する」のチェックを外すこと。（いや、え？って思ったけど。大事なフォルダは初期で同期でいいんじゃないの？）

設定後に受信動作をしてもフォルダは出てこなかったが、Thunderbirdを再起動することで、起動時にバラバラって表示された。「alias」と「mailfilter」も追加されたけど、そちらは「アカウント設定－該当アカウント－サーバー設定－同期とディスク領域－メッセージの同期－詳細（ボタン）」からチェックを外して、同期しない設定にすれば、消えた。

## 調査したこと・試したこと

1. 「アカウント設定－該当アカウント－サーバー設定－サーバー設定（メッセージを削除するとき：）」「次のフォルダに移動する」になっているが、未設定の状態だったので、ゴミ箱を選択しようとしたが、選択肢にはなかった。 
1. 「Trash」フォルダを「受信トレイ」内に作成 → 表示されない
1. 「アカウント設定－該当アカウント－サーバー設定－サーバー設定－詳細設定（ボタン）－IMAPサーバーディレクトリー」にInboxを設定。→ 何も変わらず
1. 「アカウント設定－該当アカウント－サーバー設定－同期とディスク領域－メッセージの同期－詳細（ボタン）」の同期が外れてるのではないかと、確認 → ゴミ箱フォルダ達は選択肢としてない

上記では解決できなかった。

未来の自分はもちろん、この情報が誰かの役に立ったのならうれしい。
【UE4】ScrollViewで自動スクロールを実装する

# 0. 最初
こんにちは、皆さんはペペロンチーノ食べていらっしゃいますか？
私は最近残業続きでなかなか食べられておりません....

今回はScrollViewの自動スクロールについて書いて行きます。

# 1. 問題
通常UEでScrollViewを実装すると以下のような形になると思います。

通常のScrollView
![無題の動画-‐-Clipchampで作成-_1_ (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1918199/59760333-11c3-637a-f67c-ed89ea672df6.gif)



上記実装のBP
![最初のせっとあっぷ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1918199/39063243-42a5-141b-434a-398c397e3df7.png)


全然この実装でもいいのですが、追加されるたびにスクロールが大きくなっていき
最後に追加されたアイテムを見るためには手動でスクロールしなければいけません

YoutubeやTwitchのコメント欄を参考にするとわかりやすいのですが新しいコメントが追加される
度に自動的に下に下にスクロールされると思います

# 2. 実装
実装は以下のBPの通りです

![zennhann.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1918199/d838731c-bf60-ef20-b13e-87903669c817.png)
![kouhann.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1918199/7c9a6cb7-812c-380c-050e-92c11df5991b.png)




上記の実装すると以下のような動作になります
![無題の動画-‐-Clipchampで作成-_2_.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1918199/69876a2a-72a6-cd23-5d50-a7275654d50f.gif)


追加されたアイテムが上に上に表示されています


# 3. 注意点
BPのコメントにも記載していますが「Add　Child」を行った後に必ず1フレーム待機してください。
追加した直後だとScrollViewの末尾情報は更新されないので想定の動きになりません
（このことがわからず3時間悩み先輩プログラマーに教えていただきました....）

DelayのDulationに0.0を入力すると1フレーム待機してくれます

Scroll Offsetにスクロール速度を足し判定
Scroll Offset Of Endを超えるまで（スクロールが末尾に到着するまで）処理を回し続ける


# 4. 最後に
実装してしまえば考え方は単純ですがこれがなかなか難しいです
（先輩プログラマーには足を向けて寝られないですがね。今度、炭酸水でも差し入れします）

UEは日本語の記事が少ないのでこの記事が少しでもお役に立てればいいなと思います。
Paizaの「レベルアップ問題集」の私の解答集repositoryを作った話

# Paiza のレベルアップ問題集とは
プログラミングスキルを伸ばしたい方向けの「問題セット」と「メニュー」
* 「問題セット」は共通テーマの問題集
* 「メニュー」はランクアップしていく問題集
> なお、このコーナー内の問題については、ユーザー同士で解答を教え合ったり、コードを公開したりするのは自由としています。
授業や研修にもご利用いただけますので、ぜひ教材などにもお使いください。
（[レベルアップ問題集](https://paiza.jp/works/mondai)より抜粋）


Paizaには自分のプログラミング技能の腕試しができる[スキルチェック](https://paiza.jp/challenges)もありますが、こちらは解答の共有などは禁止となっております。

## 私のgithub 解答集repositoryの紹介
最近こちらの[二分探索メニュー応用編](https://paiza.jp/works/mondai/binary_search_advanced/problem_index?language_uid=c-plus-plus) を C++で取り組んでいます。

しかし、解答を提出した後はその解答したコードが残らないので、githubにrepositoryをつくりました。

https://github.com/KaoriKoba/PracticePaiza

解答の解説などはまた別の投稿で書きたいと思います。

## ついでに他の公開repositoryの紹介
### GASのサンプルrepositoryも作っています

私が働いている自治体ではICT支援員としてGASをサポートするのは禁止されています。
しかし、先生からの問い合わせが時々あります。
先生が書いたコードをデバッグしたり検証したりを私のお昼休みを費やして見ることがありました。

特殊な事案だったので、その経験を元に休日に私が作成したGASサンプルなどを公開しています。

https://github.com/KaoriKoba/GAS-samples-for-school

こちらの解説もまた別の投稿で書きたいと思っています。
ファイル名やフォルダ名の先頭に右クリックで日付文字列を追加する

# 操作方法
- 日付文字列を追加したいファイルやフォルダを選択した後、右クリック ＞ `AddDateFilename.bat` を実行します。
- 複数選択には対応していません。

![メディア1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2534581/8c584134-e576-65b3-64ab-80e28852b9f5.gif)

# 準備
## バッチファイルの記述
- メモ帳やVSCodeなどに下記コードをコピーあるいは記述します。
```bat
@echo off
title ファイル名やフォルダ名の先頭に、更新日時文字列を追加
rem ファイル名やフォルダ名の先頭に、更新日時文字列を追加します。

set N1_DATE_TIME=%~t1
set N1_DATE_TIME=%N1_DATE_TIME:/=%
set N1_DATE_TIME=%N1_DATE_TIME:(=%
set N1_DATE_TIME=%N1_DATE_TIME:)=%
set N1_DATE_TIME=%N1_DATE_TIME: =%
set N1_DATE=%N1_DATE_TIME:~0,8%

ren ""%1"" "%N1_DATE%_%~nx1"
```

## 右クリックメニューへの登録
- Windowsのスタートメニューから「ファイル名を指定して実行」を選択して `shell:sendto` と入力し、 `%USERPROFILE%\AppData\Roaming\Microsoft\Windows\SendTo` フォルダを開きます。
- そこに先ほどのファイルを保存します。ここでは、ファイル名を `AddDateFilename.bat` とします。
ぼっち演算子とnil?、blank?を組み合わせるとnilのときに結果が逆になる罠

考えてみればそのとおりだけども、ちょっとハマったのでメモがてら。

ぼっち演算子については[safe navigation operator (ぼっち演算子)](https://docs.ruby-lang.org/ja/latest/doc/news=2f2_3_0.html)を参照。

rubyのぼっち演算子が便利なのでよく使うのですが、
条件分岐させるときに注意が必要です。

```ruby
# hogeはnameというインスタンス変数を持つオブジェクトとします
hoge.name.blank? ? '空です' : '空じゃないです'
```

みたいな判定のときに

```ruby
hoge.name = '値あり'
hoge.name&.blank?  ? '空です' : '空じゃないです'
#=> '空じゃないです'

hoge.name = ''
hoge.name&.blank?  ? '空です' : '空じゃないです'
#=> '空です'

hoge.name = nil
hoge.name&.blank?  ? '空です' : '空じゃないです'
#=> '空じゃないです'　# 思ってたのと違う!!
```

のように`name`がnilのときに期待と逆の結果になります。
ぼっち演算子は「オブジェクトがnilじゃないときにメソッドを呼び出す」という動きなので、
nilのときは`blank?`を呼び出さないためnilが返り、nilはfalsyなのでfalseのときの結果を返します。

そもそも`nil?`も`blank?`もnilが使えるメソッドなので素直に

```ruby
hoge.name.blank? ? '空です' : '空じゃないです'
```

と書けばOKです。

`empty?`はnilが持ってないので、ぼっち演算子が必須ですが、

```ruby
hoge.name&.empty? ? '空です' : '空じゃないです'
```

だと、hoge.nameがnilのときは「空じゃないです」が返って、ブランクのときは「空です」が返るという直感的じゃない動きをします。
`empty?`使うときってnilチェックしているかと思うのでこの罠には引っかからないかと思いますが。

ちなみに`present?`だと、結果オーライな感じになります。

```ruby
hoge.name = '値あり'
hoge.name&.present? ? '空じゃないです' : '空です'
#=> '空じゃないです'

hoge.name = ''
hoge.name&.present? ? '空じゃないです' : '空です'
#=> '空です'

hoge.name = nil
hoge.name&.present? ? '空じゃないです' : '空です'
#=> '空です'
```

`&`ひとつだけの違いだし、パッと見で気づきにくいのでレビューで見落としがちだったりします。
あらためてrspecとか大事だなと思いました。
0x80072F8F エラーで Windows 10 にアップグレードできない



かなり以前の Windows 7 マシンを Windows10 にアップグレードしようとしたらエラー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/2bbb0ccc-d174-d779-c98d-c2b374847bbf.png)

メディアクリエーションツールを実行しようとしたときのエラーです。。

# 環境

- Windows7 Pro SP1
- x64 版
- WinCDEmu 4.1
- 作業用別PC (Windows 10 Pro)
- Windows10 ISOファイル (2023年2月8日作成)




# 試したけど効果なし

Windows7 SP1 リリース後、SHA-2 署名の対応を有効にしないと Windows Update などが同様のエラーとなるようです。

対応するには、 KB3138612  と KB4490628 のインストールかな? と以下のようにしたのですが、どうやら KB の選定を間違ったようです。

Windowsカタログ

https://www.catalog.update.microsoft.com 

で KB番号を検索します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/9a91c076-a792-eda2-a7a4-1dd030e80575.png)
KB4490628
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/a4e8ef76-81a4-4564-e334-3bef646116d0.png)
KB3138612

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/8bc8425a-e380-d751-54cb-392341e2ad06.png)

ダウンロードしたKBパッケージをインストールして、再起動します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/9895603e-d318-5910-aa17-d0ae7c97bd36.png)

再起動後、メディアクリエーションツールを再実行しましたが改善しませんでした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/267b96ed-bff3-d336-7eaa-11503a04feee.png)


# Windows 10 ISO ファイルからインストール

メディアクリエーションツールを使って、オンラインでアップグレードしようとしましたがうまくいきませんでした。なので別PCを使い、ISOファイルを作成し、それでインストールを行うことにしました。

別PCで作ったISOファイルをUSBメモリを使い、ターゲットPCにコピーします。
Windows7 の標準の機能だと ISO ファイルが読めないので、WinCDEmu を使い iso ファイルをマウントしました。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/7689e6e6-48be-fae1-1052-82019ee312b6.png)


setup を実行し、インストールを始めます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/f02bf28b-9033-3030-c580-d78d035f99be.png)

今回はダウンロード方法を変更し、更新プログラムなどを「今は実行しない」としました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/96967e30-e7f2-f977-b93a-48a9e6db115b.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/410a61e1-1439-4f73-48fb-dc5e5d81f0df.png)

これでインストール作業が進み、無事インストールできました。
SwiftUIのMap()で地図表示

# Map（）で地図を表示する　




![Map.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3127198/01d58db2-e1cc-783a-ea4a-22ec625a1f26.gif)
swiftUIに対応したMapKiyフレームワークを使って地図を表示する方法を解説してみます。MapKitを使って地図を表示するMap()がSwiftUIに追加され、手軽に地図表示ができるようになりました。それではMap()を使ってのやり方を見てみましょう。　

### Map()を使って地図を表示　
```swift:qiita.rb
import SwiftUI
import MapKit

struct ContentView: View {
    // 座標と領域を指定する
    @State var region = MKCoordinateRegion(
        center: CLLocationCoordinate2D(
            latitude: 35.6805702,   // 緯度
            longitude: 139.7676359  // 経度
        ),
        latitudinalMeters: 1000.0,
        longitudinalMeters: 1000.0
    )
    
    var body: some View {
        // 地図を表示する
        Map(coordinateRegion: $region)
            .edgesIgnoringSafeArea(.bottom)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
``` 

地図を表示するコードでは、MapKitフレームワークを利用します。そこまず、`import MapKid`を追加します。bodyには地図を表示するためのメソッドを描きます。引数で指定する$regionは地図で表示する領域を指しています。　


## 地図を表示する　
先にも書いたように、地図は`MapKid`を使って表示します。Mapkidは標準で組み込まれているので、利用するには`Import MapKid`を実行する必要があります。　

```swift:qiita.rb 
import MapKit 
``` 

地図を表示するには`Map()`を実行します。Map()はSwiftUIで定義してあるビューの一つです。　
```swift:qiita.rd  
var body: some View {
        // 地図を表示する
        Map(coordinateRegion: $region)
            .edgesIgnoringSafeArea(.bottom)
    } 
``` 
以上、swiftUIに対応したMApkidフレームワークを使って地図を表示する方法でした。　
この記事は以下の文献を参考にして書かせていただきました。　
- [SwiftUI Iphoneアプリ開発入門ノート](http://www.sotechsha.co.jp/sp/1279/)
nvm 使用方法

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3076318/23aa843b-d389-00cb-fb3a-494deb419e1f.png)

# 概念説明

## nvm

node Version Manager、省略してnvmと呼びます。nodeのバージュン管理ツールです。

nvmを利用する事で、任意バージュンのnodeを簡単にインストール、削除、切り替わって使用や設定ができます。

例えば、Aにnode12を使わせて、Bにnode14を使います。

## node

node.js、省略してnodeとも言います。

Chrome の V8 エンジンで動作する JavaScript 環境です。オープンソースかつ高性能で JavaScript 環境 中の TOP です。

## npm

node Package Manager、またはnpmとも言います。nodeのパッケージ管理システムです。

簡単に説明すると、App Storeみたいなものです。他の人が開発したnode.jsのツールやパッケージをインストールしたり管理ができます。

npmはnode.jsと梱包されています。node.jsをインストールしたら、対応するバージュンのnpmも一緒にインストールされます。

## まとめ

- nvm は node.js のバージュン管理ツールです。
- npm は node.js のパッケージ管理ツールです。

# インストール

## Homebrew

macOS では homebrew を利用して一行のコマンドだけでインストールできます。

```
brew install nvm	
```

# 使用方法

- node.js の最新LTSバージュンをインストール

```
nvm install stable
```
![image-20230210001927107.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3076318/b69c0cce-9d87-d616-b412-253801825f31.png)

![image-20230210001927107](./image-20230210001927107.png)

- node.js の指定バージュンをインストール

```
nvm install version
```
![image-20230210003516932.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3076318/7178b183-c4a6-2a6f-e9ca-0e35bd79e49b.png)

- node.js の指定バージュンを削除

```
nvm uninstall version
```



- node.js のデフォルトバージュンをセット

```
nvm alias defualt version
```
![image-20230210003941353.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3076318/bb30cd9c-c69e-db92-1c6c-463304157ca9.png)


- node.js の指定バージュンを使用

```
nvm use version
```
![image-20230210003818228.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3076318/2aabcaf1-714d-6471-9bda-8466351bdca9.png)


- インストールした node.js を確認

```
nvm list
```
![image-20230210003706473.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3076318/0f601d92-b9af-093d-c5db-7c7824174dce.png)


- 今使っている node.js のバージュンを確認

```
nvm current
```
![image-20230210004140815.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3076318/87d0b107-b2da-51f4-4097-6dcb782bdba0.png)
リーダブルコード読書エントリ[Part1]

リーダブルコードを読んでみたので、定着させるためにもこの記事を書いてみることにしました！
今回はPart1ということで、全4部のうちの1部を紹介します。

# そもそもリーダブルコードってどんな本？
簡潔に言うならば「コードの可読性」に焦点を当てた本です。「具体的な～について紹介する」という技術書は多いですが、この本はどの言語にでも汎用的に適応できるノウハウが書かれています。例えば、命名規則についてだったり、コメントについてだったり、「素通りしがちだけど本当は大事だよね！」ということを全231ページにわたって解説しています。

# 本の内容
この記事では、本の内容をすべて書こうとは思っていません。重要そうだと思ったり、参考になった部分だけ、かいつまんで書いていきます。

## 名前に情報を詰め込む
変数や関数の名前についてです。命名について注意すべき主な二点について書いていきます。
### 明確で具体的な変数名にすること
意味が絞り切れない変数名や、処理内容を表現しきれていない変数名にすべきではありません。
例として、円周率を計算して返す`getPi()`という関数を考えてみます。関数名だけを見ると円周率を返すのだろうとはわかりますが、計算しているという情報は読み取れません。
```
    const pi = getPi();// 計算してるの？ただとってきてるだけ？
```

つまり、明確ではありません。
「円周率を返す」と「円周率を計算する」では、計算するのほうが大切な情報（計算してその結果を「返す」のは示さずとも予想できるため）なので、この場合は`calculatePi()`とすべきです。
```
    const pi = calculatePi();// 計算してるんだね！代入してるってことは戻り値は円周率かな？
```
### スコープの長さに応じて変数の長さを決めること
スクロールが必要なくらいスコープの長い変数は、変数を見ただけでも何が入っているかわかる名前にすべきです。逆に、数行のスコープで済む場合は、冗長になるので変数名を長くするべきではありません。
例えば、APIレスポンスとして、ゲーム大会の優勝者名を返す場合を考えます。このとき、返す値の変数名は優勝者の名前なので、`winnerName`と表現できます。しかし、これだと、“何に”勝った人の名前なのかわかりません。したがって、変数名は`videoGameCompetionWinnerName`とすべきです。

## コメントについて

### ひどい名前にはコメントをつけるのではなく名前を変える
先ほどの例で出した円周率を計算して返す`getPi()`を考えてみましょう。この関数名では「計算している」という情報が抜けています。「関数を説明するコメントをつければよいのでは？」と思った方もいるかと思います。しかし、先の例で説明したように、関数名を`calculatePi()`とすれば、コメントは必要なくなります。
```
//  円周率を計算して返す
    const pi = getPi();
```
より
```
    const pi = calculatePi();
```
のほうが簡潔で分かりやすい。
### 自分の考えをコメントする
「どうしてこの処理を書いたのか」、「別の処理ではいけなかったのか」をコメントで残しておくとプログラム修正時に役立つことがあります。
例えば、
```
//  精度より速度が必要なので、計算量の小さい方法で許容できる精度の答えを求めている
```
と書いておけば、後に自分以外の人が「遅いが最適な答えが求まるコード」に置き換えてしまうことがなくなります。

また、定数にコメントをつけておくのも良いです。例えば、
```
//  一秒間のリクエスト数は100で見積もっておけば十分
    MAX_RWQUESTS_PER_SEC = 100
```
と書いておけば、勝手な書き換えを防ぐだけでなく、リクエスト数が上限を超えそうになったときに書き換えることも可能です。

### 要約コメント
一行のコードにだけではなく、複数行にわたるコードに対してコメントをするのも良いです。
```
//  バリデーション
    （処理）
//  DBからデータを取得
    （処理）
//  レスポンスを整形
    （処理）
```
細かい処理を読まずに処理の概要を把握できるため、プログラム全体の見通しが良くなります。

# Part1　まとめと感想
以上でPart1は終了です！
振り返ってみると、当たり前なことばかりですが、意識していないと実践するのは難しいと思います。特に、コメントについては自分の視点だけでは書けないので、いったん自分で書いたプログラムを客観視することが必要そうです。

次回のPart2は、今回のような表面的な改善だけではなく、ループなどの処理の内容に突っ込んだ改善を紹介することになりそうです。
InfluxDBは、時間枠中に発生した一定量のイベントを集約するのに適していますか?

eコマース分析に TSDB を使用することもできますが、特にデータ量が急速に増加する場合は、代わりにデータ ウェアハウスを使用することをお勧めします。

TSDBは、時系列データと時系列分析を組み合わせて使用​​するのが最適です。たとえば、ショッピング カートがいついっぱいになって空になるかは気にするが、ショッピング カートの中身はあまり気にしない場合などです。

ユースケースはOLAPに似ており、ClickHouseをチェックできます。
Windows PowerShell と InfluxDB: バケットにデータを書き込めません

401 は、認証ヘッダーに問題があることを示します。詳細を表示するには、次のようにデバッグ ログを有効にしてみてください。

client = influxdb_client.InfluxDBClient(url=url, token=token, org=org, debug=True) // see that **debug=True** will enable verbose logging of HTTP requests

HTTP 要求ヘッダーと本文の両方が標準出力に記録されます。また、HTTP ヘッダーをチェックして、次のような「Authorization: Token」ヘッダーがあるかどうかを確認してください。

Authorization: 7mexfXXXXXXXXXXXXX
「Windows印刷鯖で、クライアントだけはドライバレスで印刷できる」ようにする rev2

# 背景
* 事務所のPCがボロくて実用に堪えないので、私物のLinux PCかChromeBookを持ち込んで作業できるようにしたい
* そして、書類を印刷するためのプリンターもWindowsとMacにしか対応してない(Canon MF7455N。AndroidとiOSは専用アプリが必要。そしてアプリの評価は良くない)
* Redmon(http://www.ghostgum.com.au/software/redmon.htm) がWindows10に非対応で別の方法が必要
* PdfScribe(https://github.com/stchan/PdfScribe) だと、オプションでの自動アクションは「既定のプログラムで開く」しか無い
* 最近はpdfで保存できるソフトが増えてる

# 前提条件
:::note alert
BYODのために本設定を行う場合、上長もしくは情シスから許可を得た上で実行してください！
::: 
* 印刷鯖:Windows10以降
* ファイル鯖:印刷鯖と兼用で可[^1]
* クライアント:pdfで保存出来て、smbでファイル鯖にアクセスできれば何でもいい[^2]
 
# やった事
1. 事務所のWindowsPCを印刷サーバに仕立てるため、smb共有内に「印刷用の一時ファイル置き場」フォルダを作る (*\\\\server\share\pdf_printTMP* とか。) 
1. *pdf_printTMP* をフォルダ監視ソフトで監視して、[^3]　[^4]
1. フォルダ内に新しいpdfファイルが置かれたら印刷[^5]するために、以下の自動アクションを設定する[^6]
    * 実行: C:\Program Files\gs\gs10.00.0\bin>gswin64c
    * パラメータ: -sDEVICE=mswinpr2 -dNoCancel -dSAFER -dBATCH -dNOPAUSE -sOutputFile="%printer%*printer_name*　"%fullfile%
1.  ~~タスクスケジューラで *pdf_printTMP* 内を削除する設定をする~~ 事務所のはまだだったので削除(自宅のはやった)


# 今後やるかもしれない事
* 事務所のファイル鯖兼Wi-fiアクセスポイントのらずぱいにcups鯖立てて、cups-pdfで *pdf_printTMP* に出力するよう設定する[^7]

# 未解決の問題点
* 用紙サイズ・拡大縮小・印刷範囲の設定 [^7]
* 印刷部数の設定

[^1]: 既にあるファイルサーバを利用しても良い
[^2]: smbじゃなくても良いし、pdfが出力できるならHaikuでもPuredarwinでも何でもいける筈。試してはいないけどｗ
[^3]: 自動アクションが起こせるなら何でも良い。今回は Directory Monitor (https://directorymonitor.com/) の無償版を使用。
[^4]: 「フォルダ監視(https://www.saberlion.com/tukaeru/soft/ )」の場合、パラメータの最後の引数は %FILENAME% になる。
[^5]: 印刷が終わったら勝手に終了してくれて、しかも扱えるファイル形式が多いのでghostscriptを使用した。
[^6]: 事務所PCを使用中に他の人が印刷掛けたらコマンドプロンプトが出て鬱陶しい。「フォルダ監視ソフトの自動アクションは印刷のみ」「古いファイルは(印刷成否問わず)タスクスケジューラで消す」方法にした。
[^7]: 各々のクライアントから「普通のプリンタ」と全く同じように扱えるようになるので、用紙サイズ・拡大縮小・印刷範囲の設定ができるようになるかもしれない

# 参考:
https://gihyo.jp/admin/serial/01/ubuntu-recipe/0271
Blob　URL.createObjectURLでcsvデータをダウンロードする

１．csvデータを用意する
２．csvデータからBlobオブジェクト(new blob)に変換する。
→ブラウザ内のメモリに格納される
３．URL.createObjectURL()メソッドで２．のBlobオブジェクトに一意のURLを割り当てる(仮想アドレス)
４．downloadLinkで３．を指定するとダウンロードできる。


補足：
メモリ・・・データを一時的に保存できる領域のことを指す。
　　　　　　→RAM：読み取り、書き取りOK
　　　　　　 ROM：読み取り専用
仮想アドレス・・・メモリの住所。
　　　　　　　　→上記では、３．でメモリに一時的に保存されたcsvデータに仮想アドレスを割り当てる処理を行っている。
現代病「集中できない」を知力に変える読む力を読んだ感想

# 概要
現代病「集中できない」を知力に変える読む力を読んだ感想について記載します。
この本は「本の読み方」ではなく「情報の読み方」が書いてある本だと感じました。
スマートフォンを活用した情報収集方法や、やる気をコントロールしてうまく仕事をする方法などが記載されています。

本には様々なことが記載されていますが、
本記事は私が本を読むことで得た気づきなど感想について記載します。
なので最近私が悩んでいた「本が楽しく読めない」や「読まないといけない本がたくさんあってつらい」といった悩みの解決が主な観点です。


# 読む前
- 面白くない本をせっかく買ったからと無理やり読み進めていた。
- 仕事の勉強用に買った本を優先して読むようにしていた。

# 気付き
- 本には相性がある。また、スキルが足りないと読めない本がある。
- 結局は自分のための本なので仕事と趣味で分ける必要はない。


## 本には相性がある。また、スキルが足りないと読めない本がある。
人間は読みやすい文章というか字体というか相性があり、それは生理的なもので決まることが多いそうです。
相性が悪い本を読むのは難しい。
また、スキルがその本を読むレベルに達していない場合も読むのが難しくなります。


## 結局は自分のための本なので仕事と趣味で分ける必要はない。
この本で一番良いと思った考え方です。
勉強をするのは自分が仕事でもっと活躍したいから読む、漫画も面白い話が読みたいので読む。
仕事と趣味を分ける必要はありませんでした。

強要されたり無理をした読書では「知」を得ることはできません。
その時読みたい本を楽しみながら読むことが一番大切だと思いました。


# 読んだ後
今後は以下を行っていこうと思います。
- 読んで楽しい本を読む
- 読んで楽しいと感じたこと/気になったことをメモする。
    - 集中していると読んだことをすぐ忘れてしまう。
    - 思い出そうとしても難しいし、ハイライトを入れても本の文章しか残らない。
    - それを読んで何を感じたかが「知」にとって重要である。
コマンドでブラウザで特定のURLを開く方法

## 方法
以下のように実行すると特定のURLを指定したブラウザで開けます。

```zsh
open -a 'ブラウザ名.app' <URL>
```
- ChoromeでURLを開く場合
```zsh
open -a 'Google Chrome.app' <URL>
```
- SafariでURLを開く場合
```zsh
open -a 'Safari.app' <URL>
```

## 具体例
- Chromeで https://github.com/ を開く
```zsh
open -a 'Google Chrome.app' "https://github.com/"
```

- Safariで https://qiita.com/ を開く
```zsh
open -a 'Safari.app' "https://qiita.com/"
```
Googleドライブフォルダ内のファイル名とURLをGoogle Apps Scriptで一括で取得する

## 概要
特定のGoogleドライブのフォルダ内にあるファイル名とURLをGoogle Apps Scriptで一括取得する。
類似の記事はあるが、数年前のもの・複雑なものが多いため投稿。

## Apps Scrip
1. 一覧をエクスポートするスプレッドシートのIDを記載
```
function getfileinfo() {

  const files = DriveApp.getFolderById("ここにスプレッドシートのIDを記載").getFiles()
```

※スプレッドシートのID取得方法
画像のURLの赤い部分
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011610/fe20cc1e-2708-5056-e969-5ded848041ab.png)

2. 取得する情報の選択とスプレッドシートへのエクスポート
```
 const files = DriveApp.getFolderById("ここにスプレッドシートのIDを記載").getFiles()

  let filinfo = [] 

  while (files.hasNext()) {
    let buf = files.next()
    filinfo.push([

      buf.getName(),
      buf.getLastUpdated(),
      buf.getUrl()

    ])
  }
  console.log(filinfo)
  console.log(filinfo.length)
  console.log(filinfo[0].length)

  const ss = SpreadsheetApp.getActiveSheet()
  ss.getRange(2,2,filinfo.length,filinfo[0].length).setValues(filinfo)
```

## コピペ用
```
function getfileinfo() {

  const files = DriveApp.getFolderById("ここにスプレッドシートのIDを記載").getFiles()

  let filinfo = []  //ファイル情報

  while (files.hasNext()) {
    let buf = files.next()
    filinfo.push([

      buf.getName(),
      buf.getLastUpdated(),
      buf.getUrl()

    ])
  }
  console.log(filinfo)
  console.log(filinfo.length)
  console.log(filinfo[0].length)

  const ss = SpreadsheetApp.getActiveSheet()
  ss.getRange(2,2,filinfo.length,filinfo[0].length).setValues(filinfo)

}
```

## スクリプトの定期実行
Apps Scriptのトリガー設定を使用。
画像を参考に任意の時間を設定する。
![ファイル取得 - プロジェクトのトリガー - Apps Script - Google Chrome 2023_02_09 23_21_49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011610/2d8d3d31-7a84-5a6a-492e-cc1e28ceddd9.png)
【SwiftUI】macOSアプリで保存機能を作成する

# はじめに
最近、Macアプリを作っているのですが、保存機能を作成しようと思った時にやり方がわからなかったので記録しておきます。

# サンプルアプリ
![画面収録_2023-02-09_23_05_34_AdobeExpress.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/20d241f6-bc0e-01de-8af9-be52e8e82f44.gif)

# ファイルへのアクセス権を付与
① プロジェクトを選択します
② ターゲットを選択します
③ 「Signing & Capabilities」を選択します
④ 「File Access Type」の「User Selected File」のピッカーを選択します
![スクリーンショット 2023-02-09 23.14.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/ab79ed0a-800e-3e88-6a72-755a8212addc.png)

⑤ 「Read/Write」を選択します
![スクリーンショット 2023-02-09 23.17.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/9a989743-0147-e35e-4c4f-ed05404494ce.png)

# 実装方法
```swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            Button {
                showSavePanel()
            } label: {
                Text("Download")
            }
        }
        .frame(width: 300, height: 200)
    }

    func showSavePanel() {
        let savePanel = NSSavePanel()
        savePanel.message = "Download"
        savePanel.allowedContentTypes = [.png]
        guard let window = NSApp.windows.first else { return }
        savePanel.beginSheetModal(for: window) { response in
            switch response {
            case .OK:
                guard let path = savePanel.url else { return }
                saveImage(imageName: "sample", path: path)
            default:
                break
            }
        }
    }

    func saveImage(imageName: String, path: URL) {
        guard let image = NSImage(named: imageName),
              let representation = image.tiffRepresentation
        else { return }
        let imageRep = NSBitmapImageRep(data: representation)
        guard let png = imageRep?.representation(using: .png, properties: [:]) else { return }
        try? png.write(to: path)
    }
}
```

![スクリーンショット 2023-02-09 23.19.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/31f508f7-27ef-628f-ec7c-3d416b4d2e90.png)

# おわり
よく見る保存画面を実装することができました！
Pythonでの音声信号処理 (9) 波の解析の一歩の疑問点

## 今回のテーマ
「(8) 波の解析の一歩」を踏まえて、しっくりこない疑問点を整理する。

疑問点
1. sin波が横にズレたような場合に、解析結果が変にならないか
2. そもそも周期が分からないときはどうすればいいか

順番に検証する。

### 「sin波が横にズレる」場合
「sin波が横にズレる」とは、つまり、
![p9_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2850619/289b5f24-4507-fca2-cd8f-d099820f460c.png)
のように、dだけズレたような場合でも、きちんと周波数成分を抽出できるのかということ。

dだけズレたsin波の式を加法定理を使って展開すると、

![p9_2_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2850619/99562e23-b693-9588-7fae-99abeb51798f.png)

という感じになる。つまり、同じ周波数のsinとcosの中で完結するので、他の周波数に影響を与えたりすることは無いということ。

加えて、
![p9_2_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2850619/13ec0061-6097-809d-7311-1f25dbe96c82.png)
となるので、横にいくらズレても、もともとのsin波の大きさRを取り出すこともできるということ。

一応、プログラムで検証

```p9_1.py
# -*- coding: utf-8 -*-
import sys
sys.dont_write_bytecode = True

import Dummy as dmy
import Analyze as ana
from multiprocessing import Process
import time
from Grp import Line
from Grp import Bar
import numpy as np
import math

def main():
    smpl = 44100
    sec  = 2
    r    = 2.0

    # sin(x) 4Hz 2秒分
    sin4x = dmy.makeWave(4, smpl, sec, r, 0, 1)

    # ちょっと横にズラす
    wav = sin4x[1000:]

    # Hz 1～10で、解析
    rng = (1, 10)
    res = ana.ft(wav, smpl, (0, 1), rng)
    res_sin = res[0]
    res_cos = res[1]

    # sinとcosの係数を2乗して加算して平方根をとる
    res_all = list(map(  
        lambda v : math.sqrt(v),
        np.array(res_sin) * np.array(res_sin) + np.array(res_cos) * np.array(res_cos)))


    # 表示
    p_s = []
    p = Process(target=drawLineGraph, args=(wav, smpl))
    p.start()
    p_s.append(p)

    p = Process(target=drawBarGraph, args=(res_all, range(rng[0], rng[1] + 1)))
    p.start()
    p_s.append(p)

    while len(p_s) > 0:
        for p in p_s:
            if not p.is_alive():
                p.join()
                p_s.remove(p)
        time.sleep(0.1)

    return

# 折れ線グラフの表示
def drawLineGraph(data, rate):
    grp = Line()
    grp.setData(data, rate)
    grp.setScale(1)
    grp.display()

# 棒グラフの表示
def drawBarGraph(data, label):
    grp = Bar()
    grp.setDataLabel(data, label)
    grp.display()

if __name__ == '__main__':
    main()
```

4Hzの波が、ちょっとだけ横にズレている。
![p9_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2850619/ab2653ca-3cfd-db57-68b7-13222a6205ab.png)

解析結果は、4Hzのところだけが出ている。
![p9_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2850619/f8824e07-81f9-e107-cebe-426f3c9378ad.png)

## 補足
Grp.pyはここにあります。
https://qiita.com/u1tym/items/b52c466620f65225edf3

Dummy.pyはここにあります。
https://qiita.com/u1tym/items/3e2be5364e83df1b7792

Analyze.py、Integral.pyはここにあります。
https://qiita.com/u1tym/items/6fadd6b2974fc3281137
【C#】×ボタンの無効化(WindowsForm)

　今回はWindowsFormでアプリケーションを作成する際、[×]ボタンの活性/非活性の制御ではまってしまった。解消をすることができたので、今回は備忘録として記録を残そうと思う。(今回が初めての投稿です。私の認識に誤りがあればご指摘いただければと思います。よろしくお願いします。)
処理としては、フォームの右上にある[×]を表示をそのままにボタンのみを無効にする動作の実装をした。
WindowsFormの既定のプロパティなどで活性制御が行えなかったため、Win32 API を使用し実装した。 


**サンプルコード**
　フォームに、[×]ボタンの有効/無効ボタンを設けClickイベントで有効/無効の制御処理を行っている。
```c#:qiita.rb
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace _test {
    public partial class Form1 : Form {
        public Form1() {
            InitializeComponent();
        }

        ///APIのDLL読み込み 外部で実装されるメソッドを宣言
        [DllImport("user32.dll")]
        static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable);
        [DllImport("user32.dll")]
        static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

        ///定数宣言
        ///第二引数で使用する用
        ///×ボタンの設定されている定数
        internal const UInt32 SC_CLOSE = 0x0000F060;
        /// 第三引数で使用する用
        /// 無効の設定されている定数
        internal const UInt32 MF_GRAYED = 0x00000001;
        /// 有効の設定されている定数
        internal const UInt32 MF_ENABLED = 0x00000000;

        /// <summary>
        /// 有効化ボタン
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e) {
            //×ボタンのシステムメニュー（フォームの）ハンドル取得する
            IntPtr hMenu = GetSystemMenu(this.Handle, false);
            if (hMenu != IntPtr.Zero) {
                //閉じるメニュー有効化
                EnableMenuItem(hMenu, SC_CLOSE, MF_ENABLED);
            }
        }

        /// <summary>
        /// 無効化ボタン
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e) {
            IntPtr hMenu = GetSystemMenu(this.Handle, false);
            if (hMenu != IntPtr.Zero) {
                EnableMenuItem(hMenu, SC_CLOSE, MF_GRAYED);
            }
        }
    }
}

```

**関連するリファレンス**
https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-enablemenuitem

**確認環境**
・Windows 10 Home
・開発環境：Visual Studio 2017 
・.Net：5.0.16


**参考サイト**
https://www.pine4.net/Memo/Article/Archives/51
https://learn.microsoft.com/ja-jp/windows/apps/develop/ui-input/retrieve-hwnd
https://qiita.com/kob58im/items/34724e36603351d78596
http://wisdom.sakura.ne.jp/system/winapi/win32/win59.html
https://work-note32.com/c-close-button-invalid
rmdir: failed to remove "xxxx": Directory not emptyエラーが出た場合：正しいコマンドはrm -r ！

# 中身が空ではないディレクトリを消す場合

* ファイルが存在するディレクトリを削除する場合、以下のコマンドを実行します。

```terminal
$ rm -r sample
```

## 間違えて以下のようなコマンドを打つと失敗します

* 以下はディレクトリ削除コマンドではありません
```terminal
$ rm sample
rm: cannot remove 'sample': Is a directory
```

* 以下は中身にファイルがない場合のコマンドです
```terminal
$ rmdir sample
rmdir: failed to remove 'sample': Directory not empty
```

* ちなみに「-rf」オプションを付けると、本当に消していいのか？という警告なしで削除できます
【試験合格記】AWS 認定 SAP on AWS – 専門知識(PAS-C01)

お疲れさまです。
表題の試験に合格したため記録として残したいと思います。

# 結果
合格(791点)

[AWS-Certified-Database-Specialty_Exam-Guide.pdf](https://d1.awsstatic.com/ja_JP/training-and-certification/docs-database-specialty/AWS-Certified-Database-Specialty_Exam-Guide.pdf)

|分野|名称|割合|
|:-----------------|:-------------------|:-------------------|
|1|AWS での SAP ワークロードの設計|30%|
|2|AWS での SAP ワークロードの実装|24%|
|3|SAP ワークロードの AWS への移行|26%|
|4|AWS での SAP ワークロードの運用とメンテナンス|20%|

# 事前知識
SAP何それ美味しいの？

# 所感
練習問題の雰囲気やすでに合格された方の記事を見る限りではオンプレで動いているSAPリソースをAWSに移行する場合の方策や、ハイブリッド接続による運用時のトラブルシューティングが多いと感じました。
加えて、AWS試験に共通するクラウドネイティブな要素があれば比較的合格に至りやすいものと踏んで、7日間詰め込みプランで勉強して挑戦しました。
結果は699点ぐらいで不合格に打ちのめされることとなりました。

この他のAWS試験では、分野が異なっていても「このAWSサービスの組み合わせが最適だろうな…」と推測して回答することができましたが
当該試験では基本的にEC2に閉じた状態でのリフト&シフトが原則となっているため、すでにうろ覚えだったEBSのストレージクラスの特徴などが必要、かつ、動いているSAPリソースのOSや拡張リソースの特徴を殺さないようにAWSの特定リソースで受け入れる必要があるなど、特殊な要件が多く知識のインプットに大変な苦労をしました。。。

# 学習範囲

今回、一から学習するにあたって先人の記事やSAPつよつよマンによるコンテンツに大いに助けられました。
真面目に暗記したい方はNRIさんの記事が参考になるかと思います。
https://tech.nri-net.com/entry/aws_certified_sap_on_aws_specialty

僕個人の学習方法としては、要点を理解して文脈から正しい組み合わせを推測するようなやり方で今に至っているため、こちらの方の記事を参考にしました。
https://qiita.com/Regryp/items/07c112f15b7598002911

あとは基礎知識の定着にこちらのYoutube動画が非常に役立ちましたので、今から挑戦する方はこちらを一通り見てから模擬試験に取りかかったり、技術ブログを漁ると良いかもしれません。
https://www.youtube.com/watch?v=6MsaoLjseCs

# 受験者に向けたアドバイス
- SAPを業務でやってきた方はSolution Architect Professionalに合格できる知識があれば問題ないと思います
- AWSは触っているけどSAPは全然…という方はSecurityとNetworkの資格を取っておいて、後付けでSAPの知識を仕入れると取りこぼしが減るかと思います
- ハイブリッド接続で使用するAWSサービスも頻出したので、Solution Architect Professionalの問題を見て記憶の整理をすると良いです
- あとはひたすらSAPリソースの特徴や組み合わせ可能なパターンを覚えていくしかないと思います


3年後にまた受験するイメージが湧きませんが、クラウド全盛期とも言える現代ではSAPのような大型の社内向けサービスをクラウド移行していく選択肢が取られていくフェイズに入ったのかなとも感じます。
また、コンテナの恩恵に甘んじていた自分としてはVMベースで要求をどのように処理するかという課題に向き合うことができたので、この試験をきっかけにVMによるサービス展開も再学習しようと思えました。

ChatGPTをはじめとしたAI隆盛期に差し掛かっていますが、インフラ屋はクラウドでも泥臭く頑張っていこうと思います。
【最短合格】ITパスポート勉強法

<h1>この記事でわかること</h1>
<ul>
<li>1か月でITパスポートに合格する方法</li>
<li>合格するための勉強法</li>
</ul>

<h1>おすすめ教材</h1>
以下の2点がおすすめです。
<ul>
<li>いちばんやさしいITパスポート絶対合格の教科書</li>
<li>ITパスポート過去問道場</li>
いちばんやさしいITパスポート絶対合格の教科書は試験に出るポイントがうまくまとまっていて、復習にも使いやすいです。また、絵もキャッチーなので、勉強に取り組みやすいデザインになっています。
</ul>

<h1>ITパスポート勉強方法</h1>
<ol>
<li>いちばんやさしいITパスポート絶対合格の教科書をさらっと1周読む</li>
<li>ITパスポート過去問道場を5年分解く</li>
<li>いちばんやさしいITパスポート絶対合格の教科書を理解して、暗記しながら1周読む</li>
<li>ITパスポート過去問道場を3年分解く</li>
</ol>

<h1>1.いちばんやさしいITパスポート絶対合格の教科書をさらっと1周読む</h1>
まずは1周さらっと読みましょう。暗記というよりかは理解をするイメージで読みましょう。過去問を見て、なんとなく聞いたことがある用語があるなという程度で大丈夫です。

<h1>2.ITパスポート過去問道場を5年分解く</h1>
このステップが非常に大切です。ここでは、問題を解きながら、用語などを覚えていきましょう。最初の2、3年は全く解けないと思いますが、問題の出され方や良く出てくる用語を意識して解くようにしましょう。

<h1>3.いちばんやさしいITパスポート絶対合格の教科書を理解して、暗記しながら1周読む</h1>
過去問を5年分やってから教科書を1周すると驚くほど、記憶に定着します。過去問演習では、概要があまりわからず、点で用語を覚えていたと思いますが、教科書を読むことで、点が線になり、理解度が高まります。

<h1>4.ITパスポート過去問道場を3年分解く</h1>
ここまで来たら後は演習を繰り返すのみです。聞いたことない用語は結構少なくなってきているはずなので、間違った単語などをメモなどにまとめて、一気に覚えてもよいでしょう。

<h1>まとめ</h1>
この記事ではITパスポートの勉強方法を紹介しました。勉強を通じて、IT周りのことを幅広く学ぶことができるので、とてもおすすめの資格だと思います。
Rustで変数の中身を出力するんゴ #programming

## なんとなくメモ

javaだと変数を出力するには

```java
import java.util.*;

public static void main (string[] args) {
    int output = "Hi!";
    System.out.println(output);
}
```

ですが

Rustだと

```rust
fn main () {
    let output = "Hi!";
    println!("{}", output);
    // "{}"必須
}

```

となります

{}が何を意味しているのはさっぱりわかりませんが(笑)、さすがに安全性をウリにしているだけはある気がします。

ただVS2022必須なのはどうにかしてほしいです...
初心者がDjangoを勉強したのでざっくりとアウトプットします

# Djangoとは
　Djangoとはウェブアプリケーションを作る手助けをしてくれるフレームワークのことです。Djangoを用いることで、より安全に、より効率的にウェブサイトを作成することができます。
　一般的なウェブサイトではブラウザから表示したいURLをサーバーにリクエストし、サーバーはそれに対応するファイルをブラウザにレスポンスとして返します。
　一方、Djangoではリクエストを受け取ったあとサーバー内で処理を行った後に、レスポンスを返します。これにより、使うデータを指定できたり、見た目を変更したりすることができます。要するに、より便利なサイトを提供することが可能になるということです。

# Djangoの構成
 Djangoは以下の3つから構成されています。

- Controller
`Model`に使うデータを指示したり、`View`に使うテンプレートを指示する。

- Model
`View`にデータを受け渡す。

- View 
テンプレートとデータを組み合わせた情報を`Controller`に渡す。
　
以下、それぞれを実際にどう使うかを説明します。

## Controller
`Controller`は`urls.py`と`view.py`の2つから構成されています。
### urls.py
`urls.py`は文字通り、URL周りの処理が書かれています。言い換えると、ブラウザから受け取ったリクエストを読み取って処理をしています。実際に処理をしている部分を少しだけ見ていきます。
```python:urls.pyの一部
urlpatterns = {
    path('hoge/', hogehoge),
}
```
　ブラウザからのリクエストが`'hoge/'`と一致したら、`view.py`に書かれている`hogehoge`という処理が行われるという流れです。もう少し具体的に書くと、`http://ipアドレス:ポート番号/hoge`というURLをブラウザに入力すると、それに対応した`hogehoge`という処理（後述）が行われるという感じです。

### view.py
`view.py`には入力されたURLに応じた処理が記述されています。
```python:view.pyの一部
from django.http import HttpResponse

def hogehoge(request):
    return HttpResponse('hoge!')
```
`urls.py`に呼び出される処理部分です。引数でリクエストを受けとって、戻り値でレスポンスを返しています。今回の処理は`hoge!`と表示するだけです。

## Model
　`Model`はデータベースを作成する設計図です。データの名前、データの値、データの型を定義するために`model.py`というファイルを用います。
```python:model.pyの一部
from django.db import models

class HogeModel(models.Model):
    name = models.CharField(max_length=100)
    num = models.IntegerField()
```
　データベースの設計図となる記述なので、データベースを触ったことがある方ならぱっと見で何となくわかるかもしれません。`name`という文字データを最大100字、`num`というデータを整数で格納するという意味になっています。

## View
　`View`もその名前通り、見た目に関する処理をしています。`View`では`htmlファイル`を`テンプレート`として所持しています。これは受け取ったリクエストに応じて、表示するhtmlファイルを変えるためです。リクエストに応じて、決められた型のhtmlファイルを返すのでテンプレートです。
　`Model`からデータを受け取り、それをhtmlファイルに反映して`Controller`に渡します。

# まとめ
　Djangoはデータを処理するModelと、見た目を処理するView、それらに指示を出すControllerからなるということをざっくりと説明しました。
　まだまだ初心者なので間違った内容もあるかと思いますが、それは分かった際に訂正しようと思います。それはそれとして、ある程度勉強したらまた投稿しようとも思います。
ReactNavigationのborderを消す方法

## 概要

ReactNavigationを使ってヘッダーを入れているのですが
どうしてもヘッダー下のborderが消せず...
ネットにある解決方法では対応できなかったので、備忘録として投稿します。

## やりたいこと

- ReactNavigationの下線を消したい

![スクリーンショット 2023-02-09 22.41.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/250206/ec069e1a-ce30-8581-606e-f8c48f58c2c7.png)


## 解決方法

`headerShadowVisible: false`を入れるだけ！！
`headerStyle`など、スタイルを入れている場所に追加すればOKでした。

```
<Stack.Navigator initialRouteName="Home" screenOptions={{
    headerStyle: {
      backgroundColor: '#f5f5f5'
    },
    headerTintColor: '#333',
    headerTitleStyle: {
      fontWeight: 'bold'
    },
    headerShadowVisible: false
    }}>
```

消えたー！:relaxed:

![スクリーンショット 2023-02-09 22.29 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/250206/a8662890-63aa-9a93-7f5f-bed3879e12a2.png)


## 解説

- スタイルでどうにかするのかなと思っていましたが、公式でオプションがあったのですね。
- 公式ドキュメントに書いてありました。
    - https://reactnavigation.org/docs/native-stack-navigator/#headershadowvisible 

> headerShadowVisible​
Whether to hide the elevation shadow (Android) or the bottom border (iOS) on the header.
（ヘッダーの標高の影 (Android) または下の境界線 (iOS) を非表示にするかどうか。）

## まとめ

- 公式ドキュメントをまず読もう
NCMBのソーシャルログインを複数サービスに関連付ける

2022年終わりくらいからTwitter界隈が不穏になっています。特にAPIの有料化が発表されたり、クライアントアプリが開発できなくなったりと、開発者向けの施策で締め付けが増えています。

そんな中、認証でTwitterログインを利用しているアプリは多いでしょう。もしTwitter認証に何かあれば、ログインする手段が失われてしまいます。

そこで、現状のTwitter認証に他のソーシャルログインも関連付けておくことで、万一の際の代替手段になり得ます。今回はニフクラ mobile backend（NCMB）のソーシャルログインで、複数のサービス認証を関連付ける方法を解説します。

本記事ではJavaScript SDKを利用しています。

## 最初のソーシャルログイン

まず最初にログインを行います。例えばこれはTwitterでの認証とします。以下の処理で、ユーザーがいなければ作成し、ユーザー情報が返却されます。

```jsx
const twitter = {
	oauth_token: "OAUTH_TOKEN",
	oauth_token_secret: "OAUTH_TOKEN_SECRET",
	oauth_consumer_key: "OAUTH_CONSUMER_KEY",
	consumer_secret: "CONSUMER_SECRET",
	id: "TWITTER_USER_ID",
	screen_name: "TWITTER_SCREEN_NAME"
};

const user = await ncmb.User.loginWith('twitter', twitter);
```

## 関連付けるソーシャルログイン

このログインした状態で、続けてソーシャルログイン情報を紐付けます。この時にも `loginWith` を使います。この時の返却値は特に利用しません。

```jsx
const expire_date = new Date(3000 * 1000 + (new Date()).getTime()).toJSON();
const date = {
	__type: "Date",
	iso:expire_date
};
const facebook = {
	id: "ID",
  access_token: "TOKEN",
  expiration_date: date
};
// 関連付け
await ncmb.User.loginWith('facebook', facebook);
```

このように `loginWith` を使うと、ユーザー情報の `authData` フィールドに、各ソーシャルサービスの認証情報が紐付きます。

```json
{
  "twitter": {
    // Twitterのソーシャルログイン情報
  },
  "facebook": {
    // Facebookのソーシャルログイン情報
  }
}
```

同様に、GoogleやAppleの認証も関連付けられます。

## 注意点

### 同じソーシャルサービスの別アカウントは利用できません

Twitterは複数アカウントを持っている方も多いですが、1つのアカウントに同じソーシャルサービスの別アカウントは紐付けられません。

### 匿名認証は紐付けられません

匿名認証もソーシャル認証と同じように `authData` を使いますが、認証を関連付けることはできません。

### パスワード認証と組み合わせられません

ユーザー名とパスワードで認証した後、ソーシャルログインを行っても別アカウントになってしまいました。組み合わせることはできないようなので注意してください。

## まとめ

複数のソーシャルサービスによる認証を紐付けておけば、いざ1つのサービスが使えなくなっても安心です。逆に言えば、1つのサービスだけ使っていると万一の際にログインできないユーザーが急増してしまうでしょう。

各ソーシャルサービスでのログインは普通に作ると別々なアカウントになってしまうので注意してください。今回の方法を使って、ソーシャルサービス同士を関連付けてください。
Ruby on Rails  マイグレーションファイルの修正方法

本日はRuby on Rilsのマイグレーションファイルの修正方法の紹介を致します。

○マイグレーションファイルとは
データベースの設計図の事。このファイルに記載した内容がデータベースに反映されます。

訂正の順序
①まず初めに修正したマイグレーションファイルが既に実行済みか確認をします。
ターミナルに　rails db:migrate:stautusを入力してマイグレーションファイルがUPになっているか確認

②確認出来たらrails db:rollbackで元に戻します。これで修正可能になります。

③修正したらrails db:migrateを入力すると修正完了となります。

以上で大まかな流れの説明でした！ありがとうございました！
Firebase と Stripe で決済処理を実装する

# はじめに
最近、個人でwebサービスを運営する人が増えてきました。個人運営からはじめたサービスが、ビジネスとして成長していくケースも少なくない状態になっています。
しかし、実際に収益を得るためには決済処理の実装について考える必要があります。そこで、webサービスを個人運営するとき、簡単に決済処理を実装する方法を紹介します。

[Firebase](https://firebase.google.com/?hl=ja) の機能と [Stripe](https://stripe.com/jp) を使用すると、独自のサーバー インフラストラクチャを構築することなく、ウェブアプリで支払い処理を実装できます。

https://stripe.com/jp

## 参考リンク
Firebase による支払い処理
URL　：　https://firebase.google.com/docs/use-cases/payments?hl=ja

## 参考になる本
- [サーバーレス開発プラットフォーム Firebase入門](https://amzn.to/3ZgCj9r)
- [Firebase Authenticationで学ぶ ソーシャルログイン入門 ID管理の原則にそった実装のベストプラクティス](https://amzn.to/3ZgLTt4)
- [良いコード／悪いコードで学ぶ設計入門―保守しやすい　成長し続けるコードの書き方](https://amzn.to/3Xb9HwG)

# Stripe とは
Stripeは、オンライン決済のためのプラットフォームです。開発者には、APIを使用して決済処理を組み込むことができます。Stripeはクレジットカード、デビットカード、Apple Pay、Google Payなど様々な支払い方法をサポートしており、開発者はカスタマイズ可能なチェックアウトページを作成することができます。また、Stripeは、決済処理の自動化、顧客データの管理、決済取引の詳細な分析などの機能も提供しています。

# 事前準備
### Firebase CLI を使用出来るようにする
Firebase CLI を使用することで、拡張機能をインストールして管理することができます。
以下のサイトでセットアップ手順をまとめました。

https://qiita.com/nekoharuyuki/items/b487cbfb167c2ff4f9d9

## Stripe アカウントの作成
https://dashboard.stripe.com/register

ダッシュボードでテスト用の API キー/シークレットを用意する。 

# 実装
1. Firebaseプロジェクトを作成: Firebaseコンソールにアクセスして新しいプロジェクトを作成します。
1. Stripeアカウントを作成: Stripeにアクセスしてアカウントを作成します。
1. Firebase Cloud Functionsを使って決済処理を実装: Firebase Cloud Functionsを使って決済処理のバックエンドを実装します。Stripe APIを使って支払いを受け付け、Firebase Realtime Databaseを使ってトランザクション情報を保存することができます。
1. クライアントアプリを開発: FirebaseとStripeを使って決済処理を実装するためのクライアントアプリを開発します。ここではStripe Checkoutを使って支払いフォームを作成し、Firebase SDKを使ってCloud Functionsにデータを送信することができます。
1. デプロイ: 最後に開発したアプリをデプロイします。これにより、Firebase Cloud Functionsがバックエンドとして動作し、Stripe Checkoutがフロントエンドとして動作するようになります。

https://firebase.google.com/docs/use-cases/payments?hl=ja

# まとめ
参考にしたコードは[こちら](https://github.com/stripe/stripe-react-native)です。
iOSやandroidの決済であれば、[RevenueCat](https://www.revenuecat.com/)で実装するのも良いと思います。
業務でテスト設計を行ったときの備忘録

# はじめに
<!-- 発端や概要を記載 -->
入社2年目から業務で初めて単体テストから結合テストのテスト設計を行ったので次回に向けての振り返りです。振り返ってみて何ができなかったのかを書いていきたいと思います。
業務内容により単体テストから結合テストを行っています。


# 目次
<!-- タイトルとアンカー名を編集 -->
1. [テストとは](#Chapter1)
1. [テストの種類](#Chapter2)
1. [テストケースの考え方](#Chapter3)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# テストとは
(開発)作業が完了しリリースに向けて行う工程。
テストの目的はソフトウェアや作成したシステムの品質を保証する工程である。また、ユーザーが想定通りに機能することを評価、検証する工程でもある。テストのメリットとしてバグ、不具合の防止、開発コストの削減等が挙げられます。リリース後の不具合をなくし、ユーザが安心、安全に運用することができます。
同じソフトで同じテスト仕様書で誰がテストを行っても同じ結果が得られるようなテスト仕様書が完成形になります。

テスト工程では事前にテスト設計書やテスト仕様書を作成し、開発工程(コーディング)で作成した機能に対して複数のテスト項目を確認していく。複数人でテストケースを作成するときはあらかじめテストの観点とケースの上げ方のガイドを作成するほうがいいです。
テスト仕様書を作成すると上司や担当者に「レビュー」も必要になるので、工数の見積もりをするときはレビューの工数も追加するようにする。

<a id="#Chapter2"></a>
# テストの種類
```
単体テスト
結合テスト
システムテスト
ユーザーテスト
```

| 　　No　　　 |  　　　　　　　　　　　　内容  | 　インプット　 | アウトプット　 |
|-----------------:|-----------------------------------|------------------|--------------------------
| 単体テスト　|    画面や機能(コンポーネント)単位でのテストを実施します。 |     外部、内部設計書 | 単体テスト仕様書
| 結合テスト　|    単体テストの次の工程として他の機能(コンポーネント)やモジュール間のデータの受け渡しを行います。 | 外部、内部設計書 | 結合テスト仕様書
|システムテスト | 本運用を想定して、システム全体の動作を確認を行います。 |外部、内部設計書 | 結合テスト仕様書
| ユーザテスト | 単体テストからシステムテストは開発者側が主に検証しますがユーザーテストはシステムを使う人(発注側)が希望した機能ができているか確認を行います。 |テストシナリオ | テスト結果報告書



<a id="#reference"></a>
# テストケースの考え方
**境界値分析** 
　境界値分析はバグが潜む有効値と無効値の境界をテストする方法。
0と1、50と51など、境界に近い2つの数値をテストする。

![スクリーンショット 2023-02-09 220351.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3071732/c329cd0e-0658-0003-46ed-b4cc0c2574a8.png)

**状態遷移テスト**
 　ファイルの保存ウィンドウが開いているときにファイルの変更ができないなど、ユーザーの操作をあえて制限することで、使いやすくする機能があります。システムやソフトウェアは状態によって使える機能が変わります。正しく動作しているかどうかという開発者の視点だけでなく、ユーザーの視点に立って、状態が遷移する過程や、それぞれの状態別にテストを行う。

異常系のテストは異常入力をどれだけ考えられるかがポイントです。

<a id="#reference"></a>
### テストケース例
| No |    内容     |
|---:|-------------|
| 1  |  境界値の確認(最大値や最小値)         |
| 2  |  入力内容(空文字、0(ゼロ)、null |
| 3  | 入力内容2(半角文字、全角文字)   |
| 4  | 状態(DB)  |
| 5  | 状態(ネットワーク)  |
| 6  | 状態(webサーバ)  |
| 7  | 状態(アクセス過多)  |
| 8  | ブラウザの種類(chrome,Edge)  |
| 9  | オフライン時  |
| 10  | オンライン → オフライン  |

### まとめ
結合テストのテストケースにはインプットとアウトプットは何になるのかを知る必要があり、入力されるインプットデータに対してアウトプットはこうなるといった内容をテストケースには書く必要があります。テスト経験は少ないですが今後の役に立てればと思います。
Cloud Shellでstartup scripts 起動スクリプト【$HOME/.customize_environment】

```bash
echo '
sudo apt update
sudo apt install -y google-chrome-stable
sudo /etc/init.d/dbus start' >> $HOME/.customize_environment
```

`.customize_environment`で起動時に自動実行できます

https://cloud.google.com/shell/docs/configuring-cloud-shell?hl=ja
パワポの数式でLatin modern mathがバグる時の対処法

# はじめに
パワポの数式フォント、ダサいですよね。
対処法としてTeX系のアドインを入れる、もういっそのことTexで書いてスクリーンショットを貼るなど色々な方法がありますが、自分は[Latin modern math](https://ctan.org/tex-archive/fonts/lm-math/opentype)というフォントをダウンロードして使用しています。
インポートするだけなのでお手軽だと思ったのですが、このフォントがなかなか曲者で「一度パワポを閉じてから開くと数式の表示が変わる」という摩訶不思議な現象に悩まされてしまいました。

# 観察されたバグ
今回問題になったのは開きかっこ`(`と閉じかっこ`)`です。
- 保存直後
![保存直後](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2649169/2fbcdc4b-76d9-9550-38e7-76fb4f929e5d.png)
- 一度パワポを閉じて、開き直した時
![開き直した時](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2649169/44ec04a4-19c6-ac42-6880-b023f7e98ec4.png)

**なんてこったい**。`(`が`F`に、`)`が`G`になっているではありませんか。

# 原因(?)と対処法
原因は、パワポの数式プルダウンからかっこを選択していることでした。
![スクリーンショット 2023-02-06 14.41.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2649169/d3f7503f-447d-66b4-9689-d3fa8287b9cc.png)
このプルダウンを使うと、`()`の中身にカーソルを合わせると全体が選択されます。
↓
![スクリーンショット 2023-02-09 22.00.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2649169/95ea72fb-6f3c-a83b-2122-7a740a8d5416.png)

どうやらこの`()`がデフォルトのCambria Math専用のフォントのようで、これを無理やりLatin Modern Mathに変換すると(一度は成功するのですが)開き直した時に`F`や`G`となってしまうようです。
また、プルダウンから選択しなくても数式モードにしてから`54−((258−314)−(143−96))`のようにかっこが連続するような数式を書くと先ほどのプルダウンを選択した場合と同じ`()`フォントが使われてしまいます。

解決策としては
1. 数式モードにせず、普通のテキストとして数式を打つ
1. 数式部分を選択して、「数式」モードにする
1. フォントをCambria MathからLatin Modern Mathにする

という手順で数式を書けば良いです。このようにすれば数式モードにしても`()`がただのテキストとして認識されているので、開き直してもバグりませんでした。

# おわりに
というわけで、なんとかバグを直すことができました。ただ、積分などの普通のテキストでは打てない記号を含むような時にはこの方法は使えないので、大人しくアドインを入れるなどした方がいいかもしれませんね・・・・



# 参考
- [闇の Cambria Math に対する防衛術](https://sgya-youtoo.hatenablog.com/entry/2020/12/10/200000)