OmniAICreator/Qiita-1.07M huggingface dataset:
FlutterのiOSのmicrophoneによるマイク入力を有効化する環境設定

Flutterはまだ慣れておらず特にUIや関数でない部分、iOSやAndroidフォルダ側の独自の設定で戸惑うことがあるためメモ的に残しておきます。

## info.plistにタグを追加
ios/Runnerフォルダにある環境設定ファイルであるinfo.plistにXMLを追加します。

```info.plist
<dict>
    ...省略
	<key>NSMicrophoneUsageDescription</key>
	<string>Used to capture audio for image picker plugin</string>
    ...省略
</dict>
```
をdictタグ内の適当な場所に追加。

## Podfileの編集
iOS,macOSのライブラリ管理ツールCocoaPodsの設定ファイルであるPodfileを書き換えてmicrophoneの設定を追記します。

```Pofile
post_install do |installer|
  installer.pods_project.targets.each do |target|
    flutter_additional_ios_build_settings(target)
  end
end

```

を下に置き換え

```
post_install do |installer|
  installer.pods_project.targets.each do |target|
    flutter_additional_ios_build_settings(target)

    target.build_configurations.each do |config|
      # You can remove unused permissions here
      # for more information: https://github.com/BaseflowIT/flutter-permission-handler/blob/master/permission_handler/ios/Classes/PermissionHandlerEnums.h
      # e.g. when you don't need camera permission, just add 'PERMISSION_CAMERA=0'
      config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
        '$(inherited)',

        ## dart: PermissionGroup.calendar
        # 'PERMISSION_EVENTS=1',

        ## dart: PermissionGroup.reminders
        # 'PERMISSION_REMINDERS=1',

        ## dart: PermissionGroup.contacts
        # 'PERMISSION_CONTACTS=1',

        ## dart: PermissionGroup.camera
        # 'PERMISSION_CAMERA=1',

        ## dart: PermissionGroup.microphone
        'PERMISSION_MICROPHONE=1',

        ## dart: PermissionGroup.speech
        # 'PERMISSION_SPEECH_RECOGNIZER=1',

        ## dart: PermissionGroup.photos
        # 'PERMISSION_PHOTOS=1',

        ## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse]
        # 'PERMISSION_LOCATION=1',

        ## dart: PermissionGroup.notification
        # 'PERMISSION_NOTIFICATIONS=1',

        ## dart: PermissionGroup.mediaLibrary
        # 'PERMISSION_MEDIA_LIBRARY=1',

        ## dart: PermissionGroup.sensors
        # 'PERMISSION_SENSORS=1',

        ## dart: PermissionGroup.bluetooth
        # 'PERMISSION_BLUETOOTH=1',

        ## dart: PermissionGroup.appTrackingTransparency
        # 'PERMISSION_APP_TRACKING_TRANSPARENCY=1',

        ## dart: PermissionGroup.criticalAlerts
        # 'PERMISSION_CRITICAL_ALERTS=1',
      ]

    end
  end
end

```
'PERMISSION_MICROPHONE=1'のみコメントをインさせています。他に必要なパーミッションがあれば任意で設定。

その後

```prompt
pod upgrade
pod install
```

で設定完了
ChatGPTによる構造化データの音声入力インターフェースが賢すぎる

子どもの勉強時間の記録アプリを少し探したのですが、シンプルで毎日使っても負担のない、しっくりくるものがありませんでした。

自作しようかな？ でも業務日報システムみたいにチクチク入力するのは使ってもらえないな。そうだ音声入力にしよう！ ChatGPTでいい感じにできるのでは？ と思ってやってみたメモです。

# コンセプトの確認

音声を入力し、それを元にプロンプトを組んでJSONデータを得るというのをやってみます。

:::note info
命令形なのは横柄だからでなく、トークン短縮や意味の揺らぎを少しでも減らすためです^^;
:::

```
次の仕様に基づき入力文を解釈し、結果を出力しろ。

# 仕様

- 日付の指定がない場合は、今日の日付(2023年3月21日)を用いる。
- 年の指定がない場合は、今年(2023年)を用いる。
- 月の指定がない場合は、今月(2023年3月)を用いる。
- 教科の指定がない場合は、「不明」を用いる。

# 入力文
「(ここに音声入力した文字列)」

# 出力
- 日付(プロパティ名date、フォーマットは年-月-日)、教科(プロパティ名subject)、勉強時間(プロパティ名minutes、単位は分)のレコードをJSON配列で返せ。
- JSONのソースコードだけを返せ。
```

ちょっと意地悪な入力文を試してみましたが、おいおい、完璧じゃないか…

![勉強時間の記録.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35178/ad99a937-cc5d-2738-6423-68c8543c0251.png)

**数学がやっぱり60分とか英語は追加で15分やった、みたいな訂正まで拾っています。賢すぎる。**

思った以上にうまくいきそうなので、動くものを雑に実装してみます。

# 実装

こんなユースケースを想定します。これなら毎日の入力もイヤにならないはず！

1. ボタンを押して音声を入力する。
1. 自動で文字起こしする。
1. ChatGPTでJSONデータに構造化する。
1. 入力インターフェースに反映し、修正があれば手作業で直す。

実際に動かした動画がこちら。**ChatGPTのAPIがなんだか遅くて解釈に10秒くらいかかります。** 止まったように見えますが、じっくり待ってください。

GUI上だとレスポンスは一瞬なので、そこはAPIの都合っぽいですが、ひとまず期待したものができました。


<iframe width="560" height="560" src="https://www.youtube.com/embed/4c4U_4sjdvA" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

# ソースコード

ソースコードと動かし方をこちらにあげておきました。

https://github.com/miyanaga/demo-study-log-voice-input

このファイルに主要な処理が記述されているので参考にしてください。

https://github.com/miyanaga/demo-study-log-voice-input/blob/main/src/views/Main.vue

# 感想

スマートスピーカーのアプリ開発ってもっと大変そうな印象でしたが、それ以上に賢いものが、すぐにできてしまいました。思いついてからこの記事をここまで書くのに3時間くらいです。

筋トレやお薬などの習慣化トラッカーはもちろん、券売機などにも応用できるでしょう。

AIに触れるたびに、「今の仕事どんどんなくなるな」と痛感しますね…
Pythonのスクリプト作成を支援するGUIアプリ ver0.2

この記事で紹介したスクリプトの更新版です

https://qiita.com/nakmura/items/3b518051e113a9ba24b0

:::note
業務外の個人的な検討活動です。
:::

:::note alert
警告
作者はいかなる責任も負いません。
:::

https://github.com/nakanomuramoto/chatWorkBench

#### 準備
githubに記載しているモジュールをインストールしてください。
今回は追加でdeepLのAPI-keyが必要です。

#### 実行手順
1. 日本語で質問を入力します。
入力が終わったらTranslation to ENのボタンを押してください。
テンプレートになるスクリプトがある場合は、左下の欄に分けて入力してください。
次の手順でdeepLさんへ英訳をお願いするときは左下の欄は送信されません。

![230321_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/588e89f0-3104-2c1b-4b5f-e49e8eafd7aa.png)

1. deepLさんの翻訳結果を確認して、必要だったら訂正してください。
このときは「変更して」の部分が後に続きそうだと判断されたようなので削除しました。
訂正が終わったら左上のAsk openAIのボタンを押してください。
chatGPTさんへ質問が飛び、回答が返ってきます。

![230321_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/239ee609-dbc5-a813-a97b-b11ad336075d.png)

だいたいの場合、スクリプト部分は右下に分かれて表示されます。
copy Code belowを押すと右下の内容がクリップボードにコピーされます。
![230321_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/7c3a7483-65ca-156d-531b-189fca6bdc39.png)

1. deepLさんの英語で日本語に翻訳したいときはマウスで選択してコピーし、右上のTranslation Clipboard to JAを押すとdeepLさんに和訳を依頼します。

![230321_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/c7d6b0eb-637c-1029-e687-4e497d49382e.png)

deepLさんの翻訳結果が新しいウィンドウに表示されます。

![230321_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/fef8c4bc-caa7-3982-40ad-aae87b2907fc.png)

#### 相談相手の設定変更
1. 左上のFileにあるSettingのSystem Contentを選ぶと、相談相手の設定を変更できます。

![230321_6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/413f41fc-cd79-0467-cd06-c1841991f27f.png)

Comboのなかから選択したらChange and resetを押してください。
![230321_7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/087ce229-593e-f87b-5fd0-97001a234aaa.png)

相談相手の設定が変わったようです。
![230321_8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/85ede013-d543-ecc7-b16f-630a77bfa769.png)
MMdetection trainの環境構築

mmdetectionでtrainしようとしたが、どハマりしたので備忘録

公式ドキュメントの通りにやるとハマった。

環境　
ubuntu20.04
RTX3060 Laptop
CUDA 11.6 ←ここ大事　あとからインストールするMMCVのバージョンに関わる

```
conda create --name openmmlab python=3.8 -y
conda activate openmmlab 
#仮想環境を作る
```
```
conda install pytorch==1.12.0 torchvision -c pytorch 
#pytorchを仮想環境にインストール 1.12が大事
```
```
pip install -U openmim 
#mmlabのパッケージ管理モジュールmimを入れる
```
```
mim install mmcv-full==1.6.0 
#バージョン指定しないと最新版1.7.1が入る
```


mmdetの中のなんちゃらpyファイルがバージョンを指定していてそれが1.6.0までのはず…詳しくは忘れたfaq.mdにも書いてある
1.7.0だとtrain.pyの20行〜22行をimportできなかった
https://mmcv.readthedocs.io/en/latest/get_started/installation.html#install-mmcv-full ここで1.6.0を入れられる条件確認
```
git clone https://github.com/open-mmlab/mmdetection.git

cd mmdetection

git log

#2.25.0のハッシュ値をコピー

git checkout "ハッシュ値"

# mmdetectionのバージョンを2.25.0に切り替える
```
https://qiita.com/sister_DB/items/3d931f713681d8ba5c4a こんな記事を見つけたのでそのままやるのが嫌だから
```
pip install -v -e .

python
#インタラクティブモード
import torch
torch.cuda.is_available()

true #環境構築完了

false #torchのホイールをpip install
```
ProxmoxVEでPCI Passthroughした際のゲームベンチまとめ

# 動機
Steam Link用のゲーミングサーバーとしてWindows10のゲストをProxmoxVEで運用中。ProxmoxVEのゲームベンチ結果について公開している例があまりないので記事にしてみた。

# ホストハードウェア
CPU：Ryzen 5600G (常時稼働なので65Wの省電な点、PCI Passthroughした状態でコンソールを操作したかったので内蔵グラフィックがある点で選んだ)
GPU：Nvidia Geforce 3060Ti (メルカリでマイニング落ちを購入)
RAM：32GB
マザー:ASRock AB350M

# ゲストのリソース割り当て
CPU：10vCPU
RAM：20GB

# その他設定
* FF15のベンチ結果を見てCPUのタイプは「host」から「EPIC」に変更(フラグの方が優先？)
* CPUはPinning
* RAMは20GBすべてHugePage
* 解像度はすべて「1920×1080」

以下、フラグ類

```
args: -cpu 'host,+pdpe1gb,hv_vendor_id=whatever,kvm=off,hv_relaxed,hv_spinlocks=0x1fff,hv_vapic,hv_time,hv-runtime,hv-crash,hv-synic,hv-vpindex,hv-ipi,hv-tlbflush,hv-frequencies,hv-reenlightenment,hv-stimer,hv-stimer-direct,hv-no-nonarch-coresharing=auto,+kvm_asyncpf,+kvm_steal_time,+kvm_pv_eoi,+kvm_pv_unhalt,topoext=on,invtsc=on,smep=off'
```

# 備考
* Windows10の他にUbuntu Serverが2台稼働している状態で測定。CPU使用率はほぼ0の状態
* 12スレッドすべてを割り当てなかったのは、他にもゲストがあることとホストの分も必要と考えたため

# 測定結果

## ファイナルファンタジーXV
<img width="666px" alt="ff15-final" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65278/bbfcc522-b6c5-21c9-c610-f38e7506aaa0.png">

## ファイナルファンタジーXIV
<img width="772px" alt="ff14-final" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65278/297c4cb0-5f0e-9248-0bdc-ffefd463b43a.png">

## ドラゴンクエストX オンライン
<img width="570px" alt="dqx-final" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65278/6b9e8607-bc28-6716-639e-72585fff0a7d.png">

## BLUE PROTOCOL
<img width="1022px" alt="bp-final" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65278/24a44fd6-14c4-2eba-f46c-0bc28fa6b905.png">

## ストリートファイターV
<img width="1022px" alt="stv-final" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65278/e4494427-a6b5-eea2-6f61-4eceb9e8edfa.png">

## ちはやローリング
<img width="1022px" alt="tiha-final" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65278/3b7b7b28-bd72-9f22-318c-041f9b377d5e.png">

## FINAL FANTASY XI
<img width="1022px" alt="tiha-final" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65278/7d3a7bd7-8baa-cdd8-619e-339f290ee0b9.png">

# 感想
* FF15、BLUE PROTOCOLについては一般に出回る3060Tiのスコアに近い
* DQX、FF14のスコアがやたら低い。なんだろう
* FF15はCPUを100%の使用率だったので、コア数の多いCPUに変更すればもう少しスコアが上がったかもしれない
cscの作法 その294

# 概要
cscの作法、調べてみた。
udpを叩いてみた。
ipアドレス、192.168.0.104のポート49153番に、helloを送信して、返事を受け取る。


# サンプルコード

```
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace ConsoleTest
{
	class Program {
		static void Main(string[] args) {
			UdpClient udpClient = new UdpClient(50000);
			udpClient.Connect("192.168.0.104", 49152);
			while (true)
			{
				Byte[] sendBytes = Encoding.ASCII.GetBytes(Console.ReadLine());
				udpClient.Send(sendBytes, sendBytes.Length);
				Console.WriteLine(Encoding.ASCII.GetString(sendBytes));
				IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
				Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
				string returnData = Encoding.ASCII.GetString(receiveBytes);
				Console.WriteLine(returnData.ToString());
			}
		}
	}
}
```

# 実行結果

```
>utu0
hello
hello
^C
```


以上。
youtube に API 経由で動画をアップロードする

## 環境

* Ubuntu 20.04 LTS
* Python 3.8

## 手順

* Youtube API を有効化する
* Python スクリプトを実行する

## Youtube API を有効化する

下記動画を参考に、 API をセットアップし、認証情報をダウンロードする

[How to Upload Videos with the YouTube API (using Python) - YouTube](https://www.youtube.com/watch?v=aFwZgth790Q)

## Python スクリプトを実行する

単体のファイルをアップロードする場合は、以下のような形で。

```
import os.path

from simple_youtube_api.Channel import Channel
from simple_youtube_api.LocalVideo import LocalVideo

# loggin into the channel
channel = Channel()
channel.login("client_secret.json", "credentials.storage")

# setting up the video that is going to be uploaded
file_path = "/home/taro/.Videos/video.mp4"
video = LocalVideo(file_path=file_path)

# setting snippet
video.set_title(os.path.basename(file_path))

# setting status
video.set_privacy_status("private")
video.set_public_stats_viewable(True)

# uploading video and printing the results
video = channel.upload_video(video)
print(video.id)
print(video)

# liking video
```

ディレクトリ以下のファイルをすべてアップロードする場合は、以下のような形で。

```
import os.path

from simple_youtube_api.Channel import Channel
from simple_youtube_api.LocalVideo import LocalVideo


def upload_local_file(file_path):
    video = LocalVideo(file_path=file_path)
    # setting snippet
    video.set_title(os.path.basename(file_path))
    # setting status
    video.set_privacy_status("private")
    video.set_public_stats_viewable(True)
    # uploading video and printing the results
    video = channel.upload_video(video)
    print(video.id)
    print(video)
    # liking video


# loggin into the channel
channel = Channel()
channel.login("client_secret.json", "credentials.storage")

# setting up the video that is going to be uploaded
dir_path = "/home/taro/.Videos/PS4/SHARE/Video Clips/Bloodborne®"

for file_path in os.scandir(dir_path):
    upload_local_file(file_path)

```

OAuth 認証が行われるため、アクセス許可のリクエストを承認する。

OAuth 認証を行うと「credentials.storage」にキャッシュファイルが作成され、以降はその情報が利用されるようになる。

なお、環境は「testing」のまま利用している。用途において必要十分であるため。

## 結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124948/6c799a72-5608-6c79-3118-f0f813f58f74.png)

Youtube Studio で、動画がアップロードされていることを確認できる。

## 経緯

Ubuntu 端末を初期化しようと思い、端末に保管していた PS4 のビデオクリップを Youtube に移動しようとした。

管理画面から一度にアップロードできる動画数は 15 であり、一括でアップロードするには API を利用する必要があったため、 API で動画をアップロードできる方法を探した。

## 余談

よくわからなかったのだが、 Bulk Upload する方法は API 以外にももう一つあるらしい。

* [Choose an upload method - YouTube Help](https://support.google.com/youtube/answer/3070500?hl=en)

## 追記

複数ファイルのアップロードを行っていると、 Quota 制限に引っかかった。

[YouTube Data APIとクォータ（割り当て、quotas）について（2022年2月） | masaki-blog](https://masaki-blog.net/youtube-data-api-quotas)

特にアップロードは Quota を大きく消費するようで、 Quota の上限を引き上げる申請を行う必要がある。

結局、本来の目的である動画ファイルのバックアップには Cloud Strage を利用し、この方法は利用しないことにした。

## Ref

* [Upload Videos with the YouTube API (using Python)](https://morioh.com/p/c3ecc243221c)
* [Upload a YouTube Video — Simple YouTube API 0.2.2 documentation](https://simple-youtube-api.readthedocs.io/examples/youtube_upload.html)
wemosでalexaデバイス その2

# 概要
wemos d1で、alexaデバイスを作ってみる。
練習問題、やってみた。

# 練習問題
udpで、オウム返し、エコーバックを作れ。

# 方針
- ルーターに、入る。
- シリアルは、115200。
- ポートは、49152番。

# サンプルコード

```
#include <ESP8266WiFi.h>
#include <WiFiUDP.h>

const char * ssid = "****";
const char * password = "****";
static WiFiUDP udp;
#define LOCAL_PORT	0xC000
#define REMOTE_PORT 0xC001
IPAddress localIP;
IPAddress remoteIP;

void setup() {
	Serial.begin(115200);
	delay(100);
	boolean state = true;
	int i = 0;
	WiFi.mode(WIFI_STA);
	WiFi.begin(ssid, password);
	Serial.println("");
	Serial.println("Connecting to WiFi");
	Serial.print("Connecting ...");
	while (WiFi.status() != WL_CONNECTED)
	{
		delay(500);
		Serial.print(".");
		if (i > 10)
		{
			state = false;
			break;
		}
		i++;
	}
	if (state)
	{
		Serial.println("");
		Serial.print("Connected to ");
		Serial.println(ssid);
		Serial.print("IP address: ");
		Serial.println(WiFi.localIP());
	}
	else
	{
		Serial.println("");
		Serial.println("Connection failed.");
	}
	udp.begin(LOCAL_PORT);
}
void loop() {
	char packetBuffer[256];
	int packetSize = udp.parsePacket();
	if (packetSize)
	{
		int len = udp.read(packetBuffer, packetSize);
		if (len > 0)
			packetBuffer[len] = '\0';
		remoteIP = udp.remoteIP();
		Serial.print(remoteIP);
		Serial.print(" / ");
		Serial.println(packetBuffer);
		udp.beginPacket(remoteIP, REMOTE_PORT);
		udp.write(packetBuffer);
		udp.endPacket();
	}
}
```

# 実行結果

```
Connecting to WiFi
Connecting ..........
Connected to ****
IP address: 192.168.0.104
192.168.0.102 / hello
```
以上。
React開発Part2～Props編～

# はじめに
　おはようございます、Tunです。
今回も前回の続きでReactの基礎編を復習がてらに記載していきます。

# Props
　`Props`(プロパティの意)とは、コンポーネントに渡す引数のようなのもで、コンポーネントは受け取った`Props`に応じて表示するスタイルや内容を変化させます。
※`component`・・・UIにより独立した再利用できる部品に分解したもののこと。
概念的には、コンポーネントはJavaScriptの関数に似ています。`props`と呼ばれる任意の入力を受け取り、画面上に表示すべきものを記述するReact要素を返します。[公式参照](https://ja.reactjs.org/docs/components-and-props.html#gatsby-focus-wrapper)

　今回は、React公式に倣って学んでいきたいと思います。
### 関数コンポーネントとクラスコンポーネント
```react:関数コンポーネント
function Welcome(props){
  return <h1>Hello, {props.name}</h1>;
}
```
　この関数は、データの入った'props'というオブジェクトを引数として受け取りReact要素を返しています。

```react:クラスコンポーネント
class Welcome extends React.Component{
 render(){
   return <h1>Hello, {this.props.name}</h1> ;
 }
}
```
 これも、引数として'props'を受け取っていますので、上記の関数コンポーネント同様、クラスコンポーネントと言えます。
### コンポーネントのレンダー
```react:DOMのタグのReact要素
const element = <div />;
```
　これはDOMのタグを表すReact要素になります。この`div`はHTMLに存在するタグですのでそのまま`div`タグとして機能します。
```react:ユーザ定義にコンポーネント
const element = <Welcome name="Tun" />;
```
　これに関して、DOMのタグには存在せず、ユーザが定義したコンポーネントになります。Reactがこのユーザ定義コンポーネントを見つけた場合、JSXに書かれている属性と子要素を、単一のオブジェクトとしてこのコンポーネントに返します。このオブジェクトのことを`"Props"`と呼びます。
```react:Example
function Welcome(props) {
 return <h1>Hello, {props.name}.</h1>;
//consple.log(props); ⇒{name: 'Tun'}
}
//const Welcome = (props) => {...}
const root = 
ReactDOM.createRoot(document.getElementById('root'));
const element = <Welcome name="Tun" />;
root.render(element); //Hello, Tun.
```
1. `<Welcome name="Tun" />`という要素を引数として`root.render()`を呼び出す
2. ReactはWelcomeコンポーネントを呼び出し、その時に`props`として`{name: 'Tun'}`(object)を渡します。
3. Welcomeコンポーネントは出力として`<h1>Hello, Tun.</h1>`を要素として返します。
4. ReactDOMは`<h1>Hello, Tun.</h1>`に一致するように、DOMを効率的に更新します。

　この例からわかるように、コンポーネントに渡す引数がある場合は、そのコンポーネントに`props`で渡して、その`props`自体は`object`形式で受け取っています。

:::note warn
**補足：コンポーネント名は常に大文字で！**
Reactでは小文字で始まるコンポーネントをDOMタグとして扱います。上記にも記載していますが、`<div />`はHTMLのdivタグを表しますが、`<Welcome />`はユーザ定義のコンポーネントとして扱われますので、必ず最初の文字は**大文字**にしましょう。

※この規約策定の背景が気になる方は[こちら](https://ja.reactjs.org/docs/jsx-in-depth.html#user-defined-components-must-be-capitalized)へ
:::

### Propsは読みとり専用
　コンポーネントを**関数で宣言するかクラス宣言するか**に関わらず、自分自身のpropsは決して変更してはいけません。すなわち、受け取ったオブジェクトは加工せず、そのまま使うほかはないということです。
```react:Example2
const sum (a, b) => {
 return a + b;
}
```
このような関数は入力されたものを変更しようとせず、同じ入力に対して同じ結果を返すので`"pure"`であると言われます。

対照的に以下の関数は自身への入力を変更しているため純関数とは言えません。
```react:Example3
const withdraw (account, amount) => {
 account.total -= amount;
}
```

　**すべてのReactコンポーネントは、自己のpropsに対して純関数の様に振舞わなければならない**という厳格なルールがあるみたいですね...

今日はここまでです、次回は`State`について学んでいきたいと思います。
## 参照
- [React公式](https://ja.reactjs.org/docs/components-and-props.html#gatsby-focus-wrapper)
Googleデジタルマーケティング＆Eコマース：プロモーション・メール

# はじめに

”Googleデジタルマーケティング＆Eコマース プロフェッショナル認定証"　の受講が完了しました(2022/3/3)。私がこのコースから得られた素晴らしい体験を、テーマごとに分割して、わかりやすくご紹介しています。興味を持たれた方は、是非下記を受講してみてください。

https://jp.coursera.org/professional-certificates/google-digital-marketing-ecommerce

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/bc50df6f-2af4-4c58-96fb-829e0752d0af.png" width="800">

# プロモーション・メールとは

プロモーション・メールとは、購読者に新製品や既存製品の情報を伝えるために配信されるメールです。

プロモーション・メールを配信する理由は様々です。

- サイト全体でセールを行う場合
- お客様の誕生日を祝って10％オフの注文を受け付ける場合
- 創業5周年を祝う場合
- 新製品やコンテスト、景品を発表する場合
- 祝日に無料ダウンロードできるコンテンツを提供する場合

などです。

どのような理由であれ、プロモーションメールの目的は、購買プロセスを加速させること、購読者に何らかの行動を促すこと、新規顧客やリピーターを作ることにあります。これらの目標から、メールはマーケティングファネルの

- 検討
- ロイヤリティ

のバケットに分類される傾向があります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/ca71fe54-971f-6b84-640d-643fc78e9686.png" width="600">

プロモーションは、購読者や顧客が何度も足を運ぶ理由、そして購買につながる理由を提供します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/31cbc691-10ea-4ead-237d-4402897b14ba.png" width="600">

# プロモーション・メールを作成する際のヒント

プロモーション・メールは、様々な方法でパッケージ化されるため、必ずしも厳密なルールがあるわけではありません。しかし、ここではプロモーション・メールを作成する際のヒントをいくつかご紹介します。

- プロモーションの内容に焦点を当て、簡潔な文章にし、件名でプロモーションを告知する。
- 製品の特徴や詳細よりも、プロモーションそのものに焦点を当てる必要があります。
- 製品の特徴や詳細がある場合は、リンクを貼り、読者がランディングページをクリックし、さらに詳しく読むことができるようにします。
- メール本文は簡潔かつ要点を押さえたものにしましょう。読者は、あなたのプロモーション・メールをほんの2、3分で読み終えることができるはずです。
- 読者はすでにあなたのブランドの製品に興味を持っているので、あなたの会社や製品・サービスに関する1,000字を読む必要はありませんし、考慮すべきは本文のコピーだけではありません。マーケティング調査によると、メールの47％は件名だけで開封されることが分かっています。つまり、件名の作成にかなりの時間をかける必要があります。件名には、必ずプロモーションの告知をしましょう。ただし、何か特別なものが入っていることを示唆し、プロモーションとの関連性を持たせることが必要です。件名にプロモーションを含めることで、読者は何を期待すればよいかを知ることができます。このように、件名にプロモーションの内容を盛り込むことで、読者の期待感を高め、最終的にはより効果的なキャンペーンを行うことができます。

# プロモーション・メールの例

#### 例１

この食品宅配アプリの例は、一般的なルールに沿っているため、優れたプロモーション・メールと言えます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/b459d041-4d2c-b594-0338-207bb7ada1cd.png" width="600">

- 商品やブランドに関する余計な情報はありません。このメールの焦点は上部のバナーで、食料品店のベーカリーから焼きたてのスコーンを注文すると送料が無料になるコードが記載されています。
- このオファーに従うと、Order Nowと書かれたボタンをクリックすれば、購入に進むことができるのです。
- 件名に「Free delivery on something sweet」とあることから、このメールに何らかのプロモーションがあることは明らかです。

#### 例２

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/56b7d409-7560-d88f-d0cf-364a6cc577bc.png" width="600">
【SwiftUI】簡単なおみくじアプリを作る

# １，はじめに
SwiftUIの学習のために購入した、
「[SwiftUI対応 たった2日でマスターできる iPhoneアプリ開発集中講座](https://amzn.asia/d/cEHJac4)」
を学習している過程で、アウトプットとして簡単なおみくじアプリを作成。

# ２，簡単に構成をイメージ
- 画面構成図（上：結果を出力、真ん中：おみくじのイラスト、下：おみくじを引くボタン）
- おみくじを引くボタンを押すとおみくじの結果が出力される。
- おみくじとアプリアイコンのイラスト（同じイラストをフリーサイトから持ってきた）

# ３，コードを書く

### おみくじの結果を格納する状態変数
```swift
@State var answerNumber = 0
```
変数に@Stateを付けることで、
値が更新されたらViewがリロード(再描画)され、tructの中で値を変更することができる。



### if文でおみくじの結果を判別

```swift
// おみくじの数字が0だったら
if answerNumber == 0 {
    // 初期画面のテキストを表示
    Text("今日の運勢は？")
        .font(.title)
    Spacer()
} else if answerNumber == 1 {
    // おみくじの数字が1だったら「大吉」
    Text("大吉")
        .font(.title)
    Spacer()
} else if answerNumber == 2 {
    // おみくじの数字が2だったら「吉」
    Text("吉")
        .font(.title)
    Spacer()
} else if answerNumber == 3 {
    // おみくじの数字が3だったら「中吉」
    Text("中吉")
        .font(.title)
    Spacer()
} else if answerNumber == 4 {
    // おみくじの数字が4だったら「小吉」
    Text("小吉")
        .font(.title)
    Spacer()
} else if answerNumber == 5 {
    // おみくじの数字が5だったら「末吉」
    Text("末吉")
        .font(.title)
    Spacer()
} else if answerNumber == 6 {
    // おみくじの数字が6だったら「凶」
    Text("凶")
        .font(.title)
    Spacer()
} else {
    // おみくじの数字が1~6以外だったら「大凶」
    Text("大凶")
        .font(.title)
    Spacer()
}
```





### おみくじのイラストを配置

イラストはフリー素材。
```swift
// おみくじの画像
    Image("おみくじイラスト")
        .resizable()
        .scaledToFit()
        .padding()
```


### おみくじボタンを配置

Int.random(in: 1...6)で、１〜６までのランダムな値を出力する

```swift
// おみくじボタン
Button {
    // ボタンがタップされたときの動き（ランダム）
    answerNumber = Int.random(in: 1...6)
    print("タップした！")
} label: {
    // ボタンに表示する文字
    Text("おみくじを引く！")
        .frame(maxWidth: .infinity)
        .frame(height: 70)
        .font(.title)
        .background(Color.pink)
        .foregroundColor(Color.white)
}
```


# ４，終わり

参考書籍：「[SwiftUI対応 たった2日でマスターできる iPhoneアプリ開発集中講座](https://amzn.asia/d/cEHJac4)」
コード：https://github.com/Yuchi-SaitoYuya/Omikuji.git
CSSグリットレイアウトを学び直す

格子状のマス目でWebサイトのレイアウトを作るのがグリッドレイアウト。授業で習ってよくわからなかった思い出。。
Gridコンテナー（親要素）とGridアイテム（小要素）で構成される。また間の隙間をGridギャップという。

↓基本的な書き方
```html
<style>
.container{
    display:grid;
    grid-template-columns: 100px 200px 100px;
    gap:15px
}

</style>
```

・grid-template-columns
ー　横並び用
ー　↑のコードである、100px 200px 100pxは三つのブロックの列を作れる。もしもう一つ200pxを足すと４つ目の列が。
ー　さらにもし、100px 100px autoにしたら、autoの部分は残りの幅を取る
ー　fr=fraction（分数）
ー　さらにさらに。1fr fr 1frにしたら。。ページの伸び縮みに関わらず均等な３つのブロック列ができる。１：１：１
ーもし2fr 1fr 1frにしたら。。2frは1fr二つ分の幅を取る。ページの伸び縮みしても割合は保持される。２：１：１
ー　また300px 1fr 1frなど、他の単位で組み合わせ可能。この場合300pxは固定される。300px：１：１

・grid-template-rows
ー　縦並び用

・gap
ー　余白の指定
ー　column-gapは横の余白、row-gapは縦の余白
ー　gap:20px 15px;みたいに一括指定できる

・repeat
ー　繰り返しの指定ができる
ー　grid-template-columns:1fr 1fr 1fr;みたいなのを、grid-template-columns:repeat(3, 1fr);というふうに簡略化

・minmax
ー　最小値と最大値が指定できる
ー　ページ幅を狭めるときのこれ以上は凝縮すんな！っていう設定
ー　minmax(最小値,最大値)→grid-template-columns:repeat(3, minmax(200px, 1fr));
ー　これは２00px以上は凝縮させないぜってゆー

・auto-fill
ー　グリッドコンテナー（親要素）の大きさに合わせて繰り返す。repeat関数と一緒に使う
ー　repeat(auto-fill,　値)
ー　グリッドコンテナーにスペースが余る時に空のグリッドが作られる。

・auto-fit
ー　グリッドコンテナー（親要素）の大きさに合わせて繰り返す。repeat関数と一緒に使う
ー　repeat(auto-fit,　値)
ー　グリッドコンテナーにスペースが余る時にそこは余白に。1frだとどこまでも。
【Swift】配列同士の引き算

## 実装
配列を比較して、重複する要素を削除する方法です。
平たく言うと、配列同士の引き算をして差分を求める方法です。

```swift:例1
let intArray: [Int] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] //引かれる
let evenArray: [Int] = [0, 2, 4, 6, 8] //引く

let oddArray: [Int] = intArray.filter{ !evenArray.contains($0) }

print(oddArray)
// -> [1, 3, 5, 7, 9]
```

```swift:例2
let words: [String] = ["しりとり", "りんご", "ごりら", "ラッパ", "パンダ"] //引かれる
let animals: [String] = ["ごりら", "パンダ"] //引く

let nonAnimals: [String] = words.filter{ !animals.contains($0) }

print(nonAnimals)
// -> ["しりとり", "りんご", "ラッパ"]
```

## 参考
https://qiita.com/atsuo1203/items/766ebbb9a35b73a98902
2023/3/21主にITとかセキュリティの記事

広島銀行を偽るフィッシング確認、注意を(3/19)
https://news.mynavi.jp/techplus/article/20230319-2629681/

誰もが直面しているオンライン詐欺のリスク、見破る5つの兆候と対処法とは(3/18)
https://gunosy.com/articles/ajzal

北朝鮮、２２００億円窃取 仮想通貨、サイバー攻撃で(3/18)
https://www.fukuishimbun.co.jp/articles/-/1746943

北朝鮮、2200億円窃取　仮想通貨、サイバー攻撃で(3/18)
https://nordot.app/1009728618929094656?c=220450040231249399

Microsoft セキュリティ更新プログラムリリース情報 - 2023 年 3 月(3/17)
https://qiita.com/niimim/items/849b32bd5fcdef70c0ce

Microsoftが2023年3月セキュリティ更新プログラムを公開／「Google Workspace」にジェネレーティブAI導入でビジネス文書の自動生成を支援(3/19)
https://news.yahoo.co.jp/articles/f937097c9d71306c46527326b9603c9f3fcdc63d?source=rss

Google Pixel、マークアップツールで編集前の画像が復元できる脆弱性(3/19)
https://www.zaikei.co.jp/article/20230319/714144.html

セキュリティ維持にはDNS Query Logsの可視化が必要です(3/18)
https://qiita.com/kimuni-i/items/6c7b467e6a01fd1bbda6

ChatGPTを支える技術が“複製”され、会話型AIの能力が解き放たれる時代がやってくる(3/19)
https://wired.jp/article/get-ready-to-meet-the-chatgpt-clones/

亡くなった後に見つかったら大騒動？ デジタル遺産はどう管理するべき？(3/19)
https://news.yahoo.co.jp/articles/cabc1af01e262ee5c6d08cd8f7ac8628bbc35aa2?source=rss

盗難警報発令中!　2022年は中部と近畿で自動車ドロが20～30％も増加!　ワーストは愛知だった(3/19)
https://news.yahoo.co.jp/articles/5eb74353a4efb842d5aa68172fb9c01e1ffddcbe

ビットコイン巡る前金融庁長官の「伝説のスピーチ」、2年半後に答え合わせをしてみる(3/20)
https://xtech.nikkei.com/atcl/nxt/column/18/02132/031600012/

IT運用からDXのガイダンスへ、生まれ変わった「ITIL 4」の魅力(3/20)
https://xtech.nikkei.com/atcl/nxt/column/18/01687/00348/
【WPF】GroupBoxのHeaderを安直に太字にすると全部太字になる

# 勝手に太字にしないで
`GroupBoxコントロール`のヘッダー文字列を太字にしたいとき、次のように記述してしまうと、`GroupBoxコントロール`で括られた**すべてのコントロールに太字が適用**されてしまいます。

```xml
<GroupBox Header="グループボックス見本"
          FontWeight="Bold">
    <StackPanel>
        <Label Content="ラベル見本1"/>
        <Label Content="ラベル見本2"/>
    </StackPanel>
</GroupBox>
```

↑のように記述すると、

「**グループボックス見本**」

のみを太字にしたいはずが、

「**ラベル見本1**」
「**ラベル見本2**」

も太字になってしまいます。

# どうすれば
以下のように記述すると、これを解決できます。

```xml
<GroupBox>
    <GroupBox.Header>
        <TextBlock FontWeight="Bold"
                   Text="グループボックス見本"/>
    </GroupBox.Header>
    <StackPanel>
        <Label Content="ラベル見本1"/>
        <Label Content="ラベル見本2"/>
    </StackPanel>
</GroupBox>
```
Gitクライアント Fork 購入記

# 前置き
小ネタになります:pushpin:
[こちら](https://qiita.com/nkk777dev/items/a85541852a7eacb20f63)の記事にもありますようにGitクライアントは有料です。評価を無料でできるだけの理解でいます。最近円安ですがお値段以上だと思いますので購入しました。その手順だけの記事です。日本時間で2023/1/3時点の購入方法です。

# 購入手順
1. https://git-fork.com/buy へアクセスして`Buy Fork`をクリックする
  ![buy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240974/0f38e780-fd82-2c99-50b2-1c792fc360d5.png)
1. 数量とメールアドレスを入力して`次へ進む`をクリックする
  ![pay1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240974/c96d39e4-8791-5078-5651-afc220794c29.png)
1. `PayPal`をクリックする
  筆者の事情でPayPalにしました。
  ![pay2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240974/0b9538f5-1aa2-7388-a472-9f2064d59638.png)
1. PayPalで決済する
  ![payment.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240974/12d7de28-b3a9-f51c-99df-358c7eec1f6f.png)
  ![pay3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240974/8b3e6ac2-fc3a-3691-4a0a-07b76ed30f84.png)
1. ForkのWebサイトに購入完了が表示される
  ![complete.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240974/8de907ae-aa01-347d-816a-072e95446695.png)
1. メールでライセンスキーを受け取る
  ![license.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240974/416707af-6130-483c-8493-a9634478bf4a.png)
1. Forkのメニューから`Help`->`Fork Activation...`を開いてメールアドレス/ライセンスキーを入力する
![activate.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240974/dfb2bac6-d68b-3317-c8e3-4a94d1ee38cb.png)
1. アクティベートが完了する
  ![activated.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240974/34eac424-5f60-67b2-17c8-d9d98ef46648.png)

# 終わりに
筆者がソフトウェアライセンスや著作権を熟知しているとは思いません。ただ、誰もが気軽に情報発信ができるようになった結果、PV数稼ぎばかりが先行しがちな気がしてなりません。特にForkは評価期間が無料であることからか、有料であることすら伝えない動画も観ました。そんなことからこの記事を執筆してみました。少しポエムになりかけましたが、筆者は業務で評価検証して会社の費用で購入して頂き、この度個人で購入するに至っています。買い切りだと「今期から予算が取れません」とか無いので精神衛生上良かったりしますね。
【Mac】Homebrew でインストール中に Command Line Tools のエラーが出て中断された話

## 概要
Homebrew を使ってインストール中に Command Line Tools のエラーが発生したので、その時の解消方法の備忘録。

## 事象
brew コマンドでツールインストールした時に以下のエラーが発生してインストールを中断された。

```
Error: Your Command Line Tools are too outdated.
Update them from Software Update in System Settings.

If that doesn't show you any updates, run:
  sudo rm -rf /Library/Developer/CommandLineTools
  sudo xcode-select --install

Alternatively, manually download them from:
  https://developer.apple.com/download/all/.
You should download the Command Line Tools for Xcode 14.1.
```

## 原因
注目すべきは `Error: Your Command Line Tools are too outdated.`
👉「Command Line Tools が古すぎる。」とのこと。

## 解決策
出力メッセージを読むと、解決方法は「macOS のソフトウェアアップデートを行い最新状態にしろ」「それでもダメなら、以下のコマンドで Command Line Tools を入れ直せ」とのお告げでした。

ソフトウェアは最新だったので、単純にコマンドラインツールを削除して最新を入れ直します（そこそこ時間がかかります）。

```zsh
# 管理者権限でコマンドラインツールを削除
sudo rm -rf /Library/Developer/CommandLineTools

# 管理者権限でコマンドラインツールをインストール
sudo xcode-select --install
```

無事、ツールインストールできるようになり解決👏✨
EC2 スナップショットを削除後に課金されたため問い合わせてみた

# はじめに
EC2のAMIとスナップショットを削除したのになぜかコストレポートを見ると
EBSの課金され続けていることが判明しました。

AWSにお問い合わせしたところ、原因はボリュームの消し忘れでした。
EC2を終了した際にEBSを一緒に削除する設定になっていなかったため、EC2を終了後ボリュームが残ってしまいました。

EC2といえばAMIとスナップショットのみに意識がいってしまいボリュームの確認が失念していました。
今後、この体験が他の方にもお役に立てばと思い記事にさせていただきました。


# 課金され続けた際に調査したこと
## コストを確認しました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/0734e596-99cb-415f-af7c-11ee8cd82841.png)

左ペインのCost explorerをクリックする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/b96e4b11-d5f6-140e-9db5-f8faf3a735a2.png)

「Cost Explorerを起動」をクリックする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/95b9c959-859f-a958-c45e-f43ccea7f223.png)

EC2のグラフが「EC2 その他」で表示されているため、課金の詳細を確認するため、
以下のサイトから手順を参考にさせていただきました。
https://blog.serverworks.co.jp/cost-explorer-ec2-others

コストレポートにて右ペインでグループ化の条件「使用タイプ」を選択して、サービスは「EC2-other」を選択しました
3/4にEC2 1台を構築した後、EC2終了し取得したAMIとスナップショット削除しました
3/5～3/17 0.02ドル課金が発生し続けていることを確認しました。グラフから東京リージョンのgp3のEBSであることが分かりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/99c96595-0caf-2fab-e477-5a87943c7002.png)


## AMIとスナップショットを確認しました
自己所有は何も残っていませんでした。

パブリックイメージにはAMIがいくつかありましたが、他人が所有しているAMIのため課金対象外です。

以下のサイトが参考になりました。
https://awsjp.com/AWS/hikaku/Owned-by-me_Public-Images_Private-images.html

**AMI**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/946d9b4d-8bc7-3cd0-1c86-4dcfb9eb0c12.png)

**スナップショット**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/6eb59068-645b-002f-44df-0fd8ae35a858.png)

AWSにお問い合わせした後にボリュームであることが分かりました
## 後日ボリュームを確認しました。
ボリュームが残っていたため、削除しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/904f7f12-6339-89dd-a301-dfbccaf2b4b4.png)

## まとめ
**EC2のEBS削除は左ペインのAMIとスナップショットとボリュームの削除漏れがないか確認が必要です。**
EC2のイメージを取得することの方が多いため、ボリュームについては忘れてしまい削除漏れが起きやすくなります。

「インスタンスの起動」のデフォルト設定ではEBSボリュームは「終了時に削除」が「はい」のため、
インスタンスが終了されるとアタッチされているEBSボリュームも同時に削除されますが、
「終了時の削除」が「いいえ」の場合はボリュームに残ります。
検証環境にEC2を構築する方はEBSの消し忘れに注意してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/00be03c8-f769-fbd7-c686-4c5e5296418d.png)

**今後の対策**
有識者にご教示いただき「aws-nuke」ツールでリソースを一括で削除出来ることを学びました。
消し忘れて想定外の課金が発生することを防ぐために検証完了後、ツールで一括で削除をお勧めします。
以下のサイトが分かりやすく「aws-nuke」ツールの使い方が書かれているため引用させていただきました。
https://qiita.com/yu-yama-sra/items/cca952150356c15ec496
Go言語の runコマンドが凄く遅かった話

# Go言語の `run`コマンドが凄く遅かった話
- はじめましてGoのド初心者です。
Goをつかいはじめて早一か月。別環境でGoの学習を行い始めた時の話です。
`run`だけでなく、`build`も遅かったのでおそらくコンパイラあたりの話でしょう。


## 結論:Goはウイルス対策ソフトと相性が悪い!?
- 私の使用しているウイルス対策ソフトはGoと相性が悪かったため、実行にものすごい時間がかかっていました。
この記事にたどり着いたとき、本当にうれしかったです。
とある海外のレディットにウイルス対策ソフトが関係している...!?ってあったのに気づけて本当に感謝しています。

### 感想
同じ被害者が増えないことを祈ります。これが原因で萎えてGoをいじらなくなりそうでしたが、また明日からGoと仲良くやっていきたいと思います。
TypeScript5でパワーアップしたEnum

TypeScriptでは数値型の`enum`を以下のように定義されます。
```ts
enum Mammal {
  Human,
  Monkey,
  Lion,
  Bear,
};
```

TypeScript5以前で、`enum`の型を持つ値は`number`側のように振る舞っていました。
```ts
let mammal: Mammal = Mammal.Human
mammal = 1000;
```
実際にMammalが取る数値は`0`、`1`、`2`、`3`ですが、任意の数値を代入することが可能になっていました。

TypeScript5ではこれが改善されてエラーが出るようになりました。
```ts
let mammal: Mammal = Mammal.Human
// エラー発生！
mammal = 1000;
```
これまでは`enum`を用いた型を使っても大した制約を課せませんでしたが、今回の変更で`enum`に基づいた型、例をもとにすると`Mammal.Human | Mammal.Monkey | Mammal.Lion | Mammal.Bear`のようなある程度の制約を持つ型として扱えるようになりました。

他にもデメリットはいくつか残っているのでこれによって`enum`を積極的に使いたいとはなりませんが、徐々に期待する動作に近づいているので数年後にはどのような変化が訪れているか楽しみです。

この記事は[このPR](https://github.com/microsoft/TypeScript/pull/50528)を参考に作成しました。
プロンプト攻略サイトリンク集

お疲れ様です。素晴らしい唐揚げです。

ChatGPTを利用するにあたり、「どんなふうに聞いたらいいの？」という疑問を持たれる方のために、各サイトの先人の知恵をここにまとめていきます。

これらの先人の知恵を参考に、ChatGPTを利用して色々便利にこなしていきましょう。

・「プロンプトエンジニアリングガイド」
https://www.promptingguide.ai/jp
→最近日本語訳されました、ありがたい……

・「深津式プロンプト・システム」
https://chatgpt-lab.com/n/ne1643b7f10e6

・「ChatGPT使い方総まとめ」
https://qiita.com/sakasegawa/items/82069c97a1ee011c2d1e

ざっくりこのあたりを呼んでおけば、ブラウザ版利用で当面の使い方に困ることはなさそうです。
ACMのDNS検証で使用するCNAMEレコードは、特殊な使い方をしている

## CNAMEレコードとは？
> CNAMEレコードとは、DNSで定義されるそのドメインについての情報の種類の一つで、あるドメイン名やホスト名の別名を定義するもの。別名は「エイリアス」（alias）と呼ばれる。
https://e-words.jp/w/CNAME%E3%83%AC%E3%82%B3%E3%83%BC%E3%83%89.html より

例えば、hoge.example.comにアクセスした場合、ドメインのDNS設定でCNAMEレコードにexample.comが設定されている場合、クライアントに対してexample.comを返却する。

この時、通常はhoge.example.comのホストゾーンにはAレコードが存在しない。
なぜなら、Aレコードが示すIPアドレスを返却すべきか、CNAMEレコードが指しているドメイン(example.com)を返却すべきか、わからなくなるからだ。

## ACMのDNS検証
ところが、ACMのDNS検証ではhoge.example.comに対してAレコードもCNAMEレコードもどちらも設定する。
ただし、この場合通常のクライアントに対してはAレコードが示すIPアドレスが返却される。
CNAMEはいつ使われるのかというと、AWSが所有権検証を行う際に使用されるのである。

## 検証方法
ACMでDNS検証を選択した場合、AWSから当該のドメインのCNAMEレコードに対して、設定すべきCNAME NAMEとCNAME VALUEが送られる。
これを当該のドメインで設定することでAWSはドメインの所有権を検証し、ACMを発行することになる。
CNAMEレコードにマッピングされているCNAME NAMEとCNAME VALUEの組み合わせが、想定されているものかどうかを判断する、という方法で検証を行う。
IDとパスワードの関係に近い気がする。（というかそれそのもの？）
これがきちんと設定されていないと、ACMの自動更新が行えない。

## 感想
DNSもちゃんと理解できてないのに、特殊なCNAMEの使いかたをしていて混乱した。
DNS難しいからもっとちゃんと理解したい。
GitHubのCompare changes機能について：ブランチ比較する場合とコミット比較する場合のdiff確認方法

# 概要
* GitHubのCompare changes機能は異なるブランチの差分を見れる機能ですが、コミットの差分を比較する場合とブランチの差分を比較する場合があるので、整理してみました。

# 前提
* この機能は、コミット間の差分を比較する機能です。指定された2つのブランチ（あるいはタグ）のコミット間の差分を比較するために使用されます。

# 使い方
### ブランチ・タグの比較
* URLに以下の形で指定すれば、Compare Changes機能を使用することができます。
    * 比較元（古い方）から順に設定

```
https://github.com/{ユーザー名}/{リポジトリ名}/compare/{比較元のブランチ・タグ}...{比較先のブランチ・タグ}
```

* GitHubのブラウザ（ウェブインターフェース）からの操作で比較も可能です。その場合は以下記事をご参考ください。
    * [GitHub – コミット間・ブランチ間の差分(Diff)の確認方法・見方](https://howpon.com/8540)
* ブランチを比較する場合、一方を`「base」`として、もう一方を`「compare」`として指定します。このとき、`「base」`ブランチにあるコミットから`「compare」`ブランチにあるコミットまでの差分が表示されます。`「base」`と`「compare」`を逆にしてしまうと、全く異なる比較結果になってしまうので、要注意です汗
* `「Split」`を選択すると、左側に比較元のコード、右側に比較先のコードが表示されます。`「Unified」`とどちらがいいかは好みですかね。

### コミットの比較
* 特定のコミット間の差分を確認する場合は、以下のURLになります。
    * コミットのところには、SHA-1ハッシュを持つコミット番号（短縮された7文字orフル）を入れます
    * 比較元（古い方）から順に設定

```
https://github.com/{ユーザー名}/{リポジトリ名}/compare/{比較元のコミット}...{比較先のコミット}
```

* コミットの差分の確認方法がURLしかありません。
TwitterとMisskey、同時投稿したくない?

もちろんしたいですよね!

というわけで作りました

https://greasyfork.org/ja/scripts/463292-twiskey

# 何これ

普通のTwitterの投稿画面に...

![twitter.com_home.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677057/595a5f52-bfb3-c836-bcbe-05b52838b47c.png)

ボタンが生えます!

![twitter.com_home (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677057/5c4d16d8-1238-5086-2a9d-6eaf31492882.png)

押すと光ります! 嬉しい!

光らせた状態で「ツイートする」を押すと、気づかないうちにMisskeyにも投稿されています

# 使い方

まずはTempermonkeyをインストール(普通のChrome拡張です)

https://www.tampermonkey.net/

で、このページを開いて、「スクリプトをインストール」

https://greasyfork.org/ja/scripts/463292-twiskey

Misskeyを開いて、設定→「API」→「アクセストークンの発行」からアクセストークンを作る

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677057/3ebc4351-83c2-1789-e12b-73725eb69cde.png" width=50%>

権限は多分ノート作成だけでOKです

次にTwitterを開くとなんかボタンがあるのでクリック
あとは指示に従ってURL(misskey.ioなど)と今もらったトークンを入れてください

最初の投稿時に許可みたいなのが出るかもしれませんが、許可してもらってOKです。また、その時点ですでにTwitterへの投稿は完了しています

# 技術面

まずTwitter APIが消えてしまったので、「送信ボタンを押したらTwitterに投稿する」アプリは作れません
ですが、Twitterのサイトからの送信はできるので、これに手を加えようというわけです

やってることは簡単で、Twitter本来のツイートボタンにonclickリスナーをつけ、押されたらMisskeyに対してHTTPリクエストを送ってるだけです

詳しくはコード見た方が早いです

https://github.com/ZOI-dayo/Twiskey/blob/main/src/twiskey.user.js

# できないこと

Tweet欄の文字読んでMisskeyに送ってるだけなので、Misskeyの絵文字を使うとか、画像ごと転送するとか、そういうのはできません
試してみよう！Oracle23c-free 

# ポイントは？

- 起動が早い(20秒程度)
- container-registry.oracle.comにDockerイメージがある

# 早速試してみよう

## docker composeの場合

```compose.yml
# https://github.com/compose-spec/compose-spec/blob/master/schema/compose-spec.json
services:
  oracle:
    image: container-registry.oracle.com/database/free:23.2.0.0
    ports:
      - target: 1521
        published: 1521
    environment:
      ORACLE_CHARACTERSET: AL32UTF8
      ORACLE_PWD: OracleV23!
    volumes:
      - type: volume
        source: oradata23
        target: /opt/oracle/oradata

volumes:
  oradata23:
```

## GtiLabの場合

```.gitlab-ci.yml
variables:
  ORACLE_PWDS: "OracleV23!"

test:
  needs: []
  services:
    - name: container-registry.oracle.com/database/free:23.2.0.0
      alias: free23c
      pull_policy: if-not-present
      variables:
        ORACLE_CHARACTERSET: AL32UTF8
        ORACLE_PWD: $ORACLE_PWDS
  image: 
    name: container-registry.oracle.com/database/sqlcl:23.1.0
    entrypoint: [""]
    pull_policy: if-not-present
  script:
    # 少し待たないと起動が間に合わない(Error Message = ORA-01033: ORACLE initialization or shutdown in progress)
    - sleep 20
    - cat ./silent.sql
    - sql system/$ORACLE_PWDS@free23c:1521/FREE @silent.sql
```

### 出力

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161516/084de7f8-9900-cc3b-f193-614bdb08398e.png)
覚えておくと良いNavigation barの作り方　tailwind & react


# 今回実現させたいNavigationBar
ブラウザの幅が一定値以上超えても、Navbarのコンテイナは一定の幅以上超えない。
（つまり、NavbarのコンテイナにMax幅を入れたい。）
ブラウザサイズに合わせて無限に広くなると、UI/UX的に良くないですね。

### 参考映像
![NavBarGif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3321296/2a9ff37a-9bd3-563a-f8bb-56d2af5da575.gif)

### 事前に用意しておくこと
・ tailwind install 
・ React library
(もちろん just JavaScript, HTML/CSSでも構いません)

### コード

```react Navbar.jsx
import React from 'react';
import { Link } from 'react-router-dom';
import {BsFillPencilFill} from 'react-icons/bs';


export default function Navbar() {
  return (
    <header className='flex justify-between border-b border-gray-300 p-2'>
        <Link to ='/' className='flex items-center text-4xl text-brand'>            
            <h1>Navbar</h1>
        </Link>
        <nav className='flex items-center gap-4 font-semibold'>
            <Link to='/products'>Products</Link>
            <Link to='/carts'>Carts</Link>
            <Link to='/products/new' className='text-2xl'>
                <BsFillPencilFill/>
            </Link>
            <button>Login</button>
        </nav>
    </header>
  )
}

```


```index.css
@tailwind base;
@tailwind components;
@tailwind utilities;

body{
    ...
    @apply flex flex-col items-center; 
    /*flex : cssでの　display: flex */
    /*flex-col : Flexboxのコンテナーの方向を垂直方向にするように、親要素に flex-direction: column を追加 */
    /*items-center : Flexboxのコンテナーのアイテムを中央に配置するように、親要素に align-items: center を追加 */
  

}
#root {
    @apply w-full max-w-screen-xl;
    /* root要素が100％の幅を占有し、最大幅がスクリーンの横幅の最大値に制限*/ 
}
```

ポイントは  ```<div id="root"></div>```のroot属性に ```max-w-screen-xl```を入れることで、
root DOMの幅は```xl```サイズ以上にはならないのです。

### Tailwind公式ドキュメント
https://tailwindcss.com/docs/max-width
![Screenshot 2023-04-09 at 23.41.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3321296/903b59fc-a060-7045-00ce-d0b00ab98363.png)
【Linux】sedコマンドで改行を置換する方法

## 改行を置き換える方法

`z`オプションを使用することで改行を置き換えられます。

`z`オプションを使用しない場合には次のようになります。

```terminal
$ cat sample.txt                            
sample
example
test

$ sed 's/sample//' sample.txt

example
test
```
`sample`が削除されますが改行が残っているため空白行が出力されます。

`z`オプションを使用すると次のようになります。

```terminal
$ cat sample.txt                            
sample
example
test

$ sed -z 's/sample\n//' sample.txt
example
test
```

改行も含めて置き換えされたため空白行が削除されています。


## 上書きする

上書きする場合には`i`オプションを使用して次のように実行します。

```terminal
sed -i -z 's/sample\n//' sample.txt
```
[HireRoo] コーディングテストの入出力問題に対応する方法

# 概要　
転職活動や就職活動の中で、コーディングテストを受ける機会があるかと思います。
特に **HireRoo** でのコーディングテストでは、必ず**入出力問題**が出題されます。
しかし、初めてHireRooのテストを受けると、
「**どうやって構築したコードの結果を出力すればいいのか？**」
と迷うことがあるかもしれません。

私自身もこの問題に直面し、解決するまでに時間がかかりました。
そこで、本記事では HireRoo のコーディングテストで入出力を適切に処理する方法を解説します。

# 結論
出力系のメソッドを使用しないで、`return`で値を返せば出力されます。

# 出力方法

:::note alert
2023年4月時点で、私が使用しているプログラミング言語を用いて、チュートリアルの問題を題材にした解答例をご紹介します。
:::

## 問題(チュートリアルで出題されている問題)

問題の説明(内容)
`solution` 関数には引数として `int` 型の配列 `arr` が与えられています。
`arr` に含まれるすべての要素を2倍した結果を `int` 型の配列で返すプログラムを作成してください。

**解答例**
```
例1:

入力: arr = [1,2,3]
出力: [2,4,6]
説明: 1*2=2, 2*2=4, 3*2=6 なので [2,4,6] が答えとなる。
```

```
例2:

入力: arr = [0,-1,1]
出力: [0,-2,2]
説明: 0*2=0, (-1)*2=-2, 1*2=2 なので [0,-2,2] が答えとなる。
```

前提
```
2 ≦ len(arr) ≦ 10000
```
## `go`での解答例

```golang
package main

func solution(arr []int) []int {
    // TODO: Implement me!

    // makeの引数： make([型/type], [長さ/len], [容量/cap])
    // len()：組み込み関数　 / 返り値は、「バイト長」で行われる

    result := make([]int, len(arr))
    for i, v := range arr {
        result[i] = v * 2 
    }

    return result
}
```

## `PHP`での解答例

```php
<?php
    function solution($arr) {
        // TODO: Implement me!
        if (!$arr) {
            return [];
        }

        foreach ($arr as $key => $row) {
            $output[$key] = $row * 2;
        }

        return $output;
    }
?>
```

# 参考資料
- [Go言語(golang) スライスと配列の使い方](https://golang.hateblo.jp/entry/golang-slice-array)

# 感想
もし今回の記事の内容が、どなたかのお役に立てれば幸いです。
表題とは関係ありませんが、現在、著者は`Go`を勉強中です。これまで静的型付け言語を扱った経験がなかったため、シンプルな問題でも書き方に悩み、思った以上に時間を要する事が多々あります。まだまだ`Go`言語について学ぶべきことが多いと実感しています。精進あるのみですね！
AZ-104に合格した話

こんにちは。yuzu_juiceです。
先日、AZ-104に合格したので記録しておきます。

# AZ-104とは
これ。Azureの管理者向けの試験。
https://learn.microsoft.com/ja-jp/certifications/exams/az-104/

# 私のクラウドの知識レベル
- AWS SAA所持
- Azureはほぼ触ったことがない
- ADはほぼ知らないし、触ったこともない

# どれだけ勉強をしたか
## 勉強時間
50時間くらい

## 基礎の勉強
- https://learn.microsoft.com/ja-jp/training/paths/az-104-administrator-prerequisites/
- https://learn.microsoft.com/ja-jp/training/paths/az-104-manage-identities-governance/
- https://learn.microsoft.com/ja-jp/training/paths/az-104-manage-storage/
- https://learn.microsoft.com/ja-jp/training/paths/az-104-manage-compute-resources/
- https://learn.microsoft.com/ja-jp/training/paths/az-104-manage-compute-resources/
- https://learn.microsoft.com/ja-jp/training/paths/az-104-monitor-backup-resources/
上記コンテンツを各1周

## 模擬試験
- Microsoft公式の練習問題 50問×10回
- Udemyの問題集 50問×4回

# 結果
740点で合格した。(合格点は700/1000点)
Microsoftが用意してくれている教材と練習問題だけでもかなり試験対策としては役立った。
AD周りはいまだにわからんことが多いので、今後も勉強していく。
Railsで使用するテーブルの型の種類について


#### Railsで使用するテーブルの型の種類について

- テーブルの作り方

```
作る例
$ rails g model User name:string
```
$ rails g model モデル名 カラム名:型

```
消す例
$ rails d model User
```
$ rails g model モデル名

### 指定できる型の種類


- string : 文字列
- text : 長い文字列
- integer : 整数
- float : 浮動小数
- decimal : 精度の高い小数
- datetime : 日時
- timestamp : タイムスタンプ
- time : 時間
- date : 日付
- binary : バイナリデータ
- boolean : Boolean

### マイグレーション実行方法

このままだと、実際のDBには反映されないので、db:migrateコマンドを実行しないといけない

```
$ rails db:migrate
```
変数や list の値をコピーする方法（copy()メソッド、deepcopy()関数）

変数や list の値をコピーするには、
実現したい内容によっていくつかの方法があります。
私はそれを知らないまま1時間近く悩んでしまったことがあるので、
ここにまとめておきます。

ここでは、以下の3パターンに分けて説明します。
1. 変数の値を代入
1. list の浅いコピー（`copy()`メソッド）
1. list の深いコピー（`deepcopy()`関数）


**1. 変数の値を代入**
===

変数の値を代入した場合のコードを例に説明します。

```python
s = 1

# 変数の値を代入
d = s

# 代入元変数の値を変更し、その値を出力
s += 100
print("s -> ", s)

# 代入先変数の値を出力
print("d -> ", d)
```

実行結果は以下の通り。

```python
s ->  101
d ->  1
```

実行結果を見てもわかるように、
代入元と代入先の変数は別々の変数として管理されているため、
片一方を変更しても、もう片方に影響はありません。





**2. list の浅いコピー（`copy()`メソッド）**
===

続いて list のコピーを行いますが、
まずは**イケてない**コピー方法の例を挙げます。

```python
s_list = [0, 1, 2]

# list を代入
d_list = s_list

# 代入元 list の値を変更し、その値を出力
s_list[0] += 100
print("s_list -> ", s_list)

# 代入先 list の値を出力
print("d_list -> ", d_list)
```

実行結果は以下の通り。

```python
s_list ->  [100, 1, 2]
d_list ->  [100, 1, 2]
```

実行結果を見てもわかるように、
代入元の list を変更しただけなのに、
代入先の list の値も変更してしまっています。
つまり同一のオブジェクトを参照してしまっています。

これを回避する（別のオブジェクトを参照する）には、
`d_list = s_list`という指定ではなく、
`copy()`メソッドを使い、
`d_list = s_list.copy()`と指定します。

具体的なコードを使って説明します。

```python
s_list = [0, 1, 2]

# list を copy()メソッドでコピー
d_list = s_list.copy()

# 代入元 list の値を変更し、その値を出力
s_list[0] += 100
print("s_list -> ", s_list)

# 代入先 list の値を出力
print("d_list -> ", d_list)
```

実行結果は以下の通り。

```python
s_list ->  [100, 1, 2]
d_list ->  [0, 1, 2]
```

今回はちゃんと別々の結果になっています。
つまり別々のオブジェクトを参照してます。



**3. list の深いコピー（`deepcopy()`関数）**
===

最後に、2次元 list のコピーを行いますが、
まずは直前に説明した`copy()`メソッドを使った**イケてない**例を挙げます。

```python
s_list = [0, 1, [20, 21, 22]]

# list を copy()メソッドでコピー
d_list = s_list.copy()

# 代入元 list の値を変更し、その値を出力
s_list[0] += 100
s_list[2][0] += 100
print("s_list -> ", s_list)

# 代入先 list の値を出力
print("d_list -> ", d_list)
```

実行結果は以下の通り。

```python
s_list ->  [100, 1, [120, 21, 22]]
d_list ->  [0, 1, [120, 21, 22]]
```

実行結果を見てもわかるように、
入れ子（2次元配列）になっていない部分（0番目）の値は別オブジェクトを参照していますが、
入れ子（2次元配列）になってる部分（2番目）の値は同じオブジェクトを参照しているため、
同じ値になっています。

これを回避する（別のオブジェクトを参照する）には、
copy モジュールの deepcopy() 関数を使います。

具体的なコードを使って説明します。

```python
# copy モジュールを import
import copy

s_list = [0, 1, [20, 21, 22]]

# list を copy.deepcopy() 関数でコピー
d_list = copy.deepcopy(s_list)

# 代入元 list の値を変更し、その値を出力
s_list[0] += 100
s_list[2][0] += 100
print("s_list -> ", s_list)

# 代入先 list の値を出力
print("d_list -> ", d_list)
```

実行結果は以下の通り。

```python
s_list ->  [100, 1, [120, 21, 22]]
d_list ->  [0, 1, [20, 21, 22]]
```

今回は入れ子（2次元配列）になってる部分（2番目）も含めて
別々の結果になっています。

知らないとかなりハマってしまう内容ですが（私はハマりました）、
整理して理解しておけば、難しくはない内容だと思います。
どなたかの参考になればと思います。
"ワークロード画面の出し方" or "visual studio 2022にVB.NETなどをインストールする画面の出し方"（VB.NET）

# 結論
1. visual studio上のタブから、"ツール"＞"ツールと機能を取得"を選択する。
![無題２.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3079289/277bab81-677c-1a7a-aa14-00f6b8b55091.png)
2. ここから必要に応じて、プログラムツールをインストールする。
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3079289/251618c4-5614-fc1d-afc6-fb6c52d18471.png)

# 背景
- GitHubからVB.NETのソースコードをクローンし、開発をしようとした。
- しかし、デバックをしようとし、実行したところ、エラーとなってしまった。
エラー内容：To run this application, you must install .NET. Would you lik to download it now?
- Visual Studioを2019から2022にバージョンアップしたこともあり、VB.NETがまだインストールされていなかったことが原因と思われた。
![無題3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3079289/86ee9ba7-e5f5-2a68-43a3-bce506c758a6.png)
**※私の場合だけなのか、なぜか、"はい(Y)"を選択しても、インストールが開始しませんでした。**
- ワークロードをどのように出力するかわからず、少し時間がかかってしまったため、この記事に記録を残しました。

# この記事は誰向けの記事か？
- ワークロード（C#,VB.NET,Unityなどをインストールする画面）を出力するまでの方法がわからない人
- VB.NETなどのソフトパッケージをダウンロードしたい人

# 環境
- OS：Windows10
- 開発プラットフォーム：[visual studio 2022](https://visualstudio.microsoft.com/ja/vs/)

# 本記事における注意事項
- 本記事は、備忘録としてまとめたものになります。
- 他の方の参考になる可能性も踏まえて、一般公開も行なっております。
- また記載内容はすべて、正しい内容が記載されているとは限りません。
- 誤った内容を見つけた場合は、ご指摘をお願いいたします。