OmniAICreator/Qiita-1.07M huggingface dataset:
VuexでStoreの値をモックするときに躓いたメモ

# はじめに

最近コンポーネントテストに力を入れていきたいと思い始めてVueのテストを書くようになったのですが、躓いた箇所があったので個人用にまとめます

# 問題

コード上で以下のように`store`の値を参考にしている箇所がありました

```
$route.getters.isAdmin
```

ここで、`amind`を`true`にテストでする必要があったので以下のようなコードをかきました

```ts:test.spec.ts
import { createLocalVue, mount, shallowMount } from '@vue/test-utils'
import Vuex from 'vuex'

describe('NewsSearch', () => {
  test.only('てすと', () => {
    const wrapper = shallowMount(NewsSearch, {
      localVue,
      store: new Vuex.Store({
        getters: {
            isAdmin: () => {
                return true
            }
        }
      })
    })

    テストのコード
  })
})
```

しかし、うまくテストが通らず、state周りがモックで来ていないようでした

# 解決方法

`state`をよく確認したところい可能構造になっていました

```ts:mainStore.ts
state = new Vuex.Store({
    modules: {
        groups: {
            user,
            hoge,
            fuga
        }
    }
}

```

```ts:user.ts
const getters = {
    isAdmin: (state) => state.isAdmin
}

export defautl {
    hoge,
    getters
}
```



```ts:test.spec.ts
import { createLocalVue, mount, shallowMount } from '@vue/test-utils'
import Vuex from 'vuex'

const localVue = createLocalVue()
localVue.use(Vuex)

describe('NewsSearch', () => {
  test.only('てすと', () => {
    const wrapper = shallowMount(NewsSearch, {
      localVue,
      store: new Vuex.Store({
        modules: {
          user: {
            getters: {
              isEarlyAccess: () => {
                return true
              }
            }
          }
        }
      })
    })

    テストコード
  })
})
```

Vuexがモジュールになっていたのでモジュールを正しく指定しました
そして`localValue`も必要とのことだったので追加をしたところうまく動きました

# おわりに

Vuexがテストするの難しくてあまり私の周りではコンポーネントテストが書かれていないのかなと思いました
ですが、慣れたら普通にテスト書く速さまで持っていけそうなのでがんばりたいです
wslでelixir その49

# 概要
wsl(wsl2じゃない)で、elixirやってみた。
練習問題、やってみた。

# 練習問題
Phoenixで、FIZZBUZZ表示せよ。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/bd0c8bc5-fea1-782d-522d-08427e038dc8.png)

# サンプルコード

```
defmodule FizzBuzz do
	defp buzz(i) do
		cond do
		rem(i, 15) == 0 ->
			"FizzBuzz"
		rem(i, 5) == 0 ->
			"Buzz"
		rem(i, 3) == 0 ->
			"Fizz"
		:else ->
			Integer.to_string(i)
		end
	end
	def say do
		1..100
		|> Enum.map(fn x ->
			x
			|> buzz
		end)
		|> Enum.reduce("", fn v, s ->
			s = s <> v <> " "
		end)
	end
end

```

# 手順
- hello2/lib/hello2_web/templates/page/index.html.heexを修正。

```
<section class="phx-hero">
  <h1><%= gettext "Welcome to %{name}!", name: "Phoenix" %></h1>
  <h3><%= FizzBuzz.say %></h3>
  <p>Peace of mind from prototype to production</p>
</section>


```


以上。
【SecconBeginner2023】Half/reversing【writeup】


### 解法

とりあえず解凍するために

```
 tar -zxvf ファイル名.tar.gz
```

解凍したらHalf/half が出てきたのでfileコマンドでhalfの中身を見てみる。

ELFファイルだったから(Windowsの.exeファイル)実行ファイルと分かった。

halfを試しに実行ファイルとして動作させてみる

flagを入力して正しかったらConnect!! 間違えてたらInvited Flagと表示されるようだ。

中身を見るためにstrings を実行するとプログラムの概要がめっちゃ出てくる。

Flag部分が生書きであったためコピペで確認。

```
ctf4b{ge4_t0_kn0w_the_bin4ry_fi1e_with_s4ring3}
```

とのことでフラグで突っ込んだらどうやらダメだった。

もしかしてひっかけか？と思ったら半角スペースが入ってたらしく消したら通った。

Flagが通らなくてもしかしてIDA freeで見ないと分からないやつかと思ったけど助かった。

___

### 解答できた感想

実はSECCONに参加するのはBeginnerとノーマルを合わせて3回目でした。
実際今回初めて解けたので結構うれしかったです。

学校の授業で使ってたセキュコンの本と類似内容だったので割と早めに解けました。
ELF関連で役立ったので良ければ参考程度にどうぞ。

https://gihyo.jp/book/2022/978-4-297-13180-7
【たぶん】初心者でもできるCUIでNAS作り

※当記事はラズパイ zero・4 の市場が枯渇した時期に制作したものです。ラズパイが手に入る場合はそちらをおすすめします。

専門2年の頃、SBCで何か作れないかと考え、簡単なNASを試してみることにしました。

ただ、その当時（2021年）はラズパイが品切れ状態でしたので、代替品を探していたところ、なんとラズパイ3（無印）と同じ性能のSBCを見つけました。

すでに先駆者の方がいらっしゃったので、その方の情報を参考にすると良いかもしれません。

詳細はこちらのブログをご覧ください。

https://frdrc-droid.fc2.net/blog-entry-106.html

さて、そんなわけで、秋月電子さんの通販サイトで PINE A64+ 1GBモデルを購入しました。

価格は送料別で当時の価格で 2,980円でした。

他のSBCと比べても破格の値段です。

私自身、CUIのみのOS実機に触った経験がなかったため、ちょうど良い機会となりました。

ただ、ラズパイとは異なり無線LANが搭載されていないため、使い勝手は少々悪いですが、有線LANは1Gbpsの速度を実現しており、十分なパフォーマンスがあります。

まずはテスト用に32GBのSDカードを使ってOSストレージを、USB2.0の128GBを使って倉庫ストレージとして準備しました。

OSイメージは、Armbian公式サイトから PINE A64 専用のISOイメージをダウンロードしました。

（ダウンロード方法は地味にわかりにくいので注意が必要です）

また、ダウンロードには時間がかかることがありますので、アジアサーバーからのダウンロードにご注意ください。

ダウンロードが完了したら、balenaEtcherを使用して、SDカードにOSイメージを書き込んでください。

https://etcher.balena.io/

書き込みが完了したら、PINE A64にSDカード、USBキーボード、HDMIケーブル、そして電源用のMicro USB Type-Bを接続してください。

電源が接続されると、システムが起動します。

起動中には、コンソール上にたくらく文字が表示されますが、セットアップの進行状況ですので、コーヒーを飲みながらお待ちください。

初期設定には大きく分けて2つの項目があります。

初期設定

管理者の名前
管理者パスワード
A64の名前（他のPCやスマホから接続する際に識別する名前）
ユーザーの名前
ユーザーパスワード
自宅内で接続するために必要な情報
（これを設定すれば、PCから直接接続して編集することができます）

A64の固定IPアドレス
A64のサブネットマスク
ホームゲートウェイまたはONUに接続されているルーターのIPアドレス（例: 192.168.1.0）
DNSサーバーのアドレス
設定コマンド：

上記の設定が完了したら、「reboot」と入力して再起動してください。

同時に、PCにTeraTermをインストールしてください。

https://ja.osdn.net/projects/ttssh2/

インストールが完了したら、PCからA64に接続し、編集を行うことができます。

ログインする際は、初期設定で登録した名前とパスワードを入力してください。

あとは仕上げです。

A64にOpenMediaVaultをインストールします。

インストールが完了したら、PCのブラウザで以下のアドレスにアクセスし、A64の固定IPアドレスを入力して接続してください。これでNASの設定の段階まで進めました。

ここから先は、OpenMediaVaultの公式ドキュメントを参考にしながらセットアップを進めてください。

※なお、セットアップはUSBメモリのフォーマットとOSへのマウントのみです。

私自身は約1年間この方法を使ってきましたが、適切な使い方さえすれば快適に使用することができました。

今後、USB-HDDの増設を考えていますので、進展があれば再度報告します。

それでは、また。
ffmpegでm4aをYouTubeにアップロードできるmp4に変換する方法

## 背景

iPhoneで録音したm4aの音声ファイルをYoutubeに非公開でアップロードしておくためにffmpegを用いてmp4に変換を試みました。

しかし、公式に書かれているシンプルな例

```
$ ffmpeg -i input.m4a output.mp4
```

で変換したmp4ではYouTubeへのアップロードに失敗してしまいました。

## 結論

こちらの[記事](
https://www.bannerbear.com/blog/how-to-convert-audio-to-video-for-youtube-upload-using-ffmpeg/#convert-mp3-to-mp4-with-an-image)を参考に下記でYouTubeにアップロード可能なmp4へ変換することができました。

```
$ ffmpeg -loop 1 -i image.png -i input.m4a -shortest output.mp4
```

単に-iで画像を指定するだけではだめで、ループ回数を指定してあげる必要がありました。
また、-shortestをつけると変換処理が早くなったので、つけています。

なお、このオプションは音質にはこだわっておらず、YouTubeにアップロード可能なmp4を素早く生成することに主眼を置いています。

同じ問題で困っている人の助けになれば幸いです。

## 参考

https://github.com/FFmpeg/FFmpeg

https://ffmpeg.org/ffmpeg-all.html

https://www.bannerbear.com/blog/how-to-convert-audio-to-video-for-youtube-upload-using-ffmpeg/#convert-mp3-to-mp4-with-an-image
2025年までに運用保守で達成するための目標

# はじめに
現状40歳になったため、求められるスキルが高くなっていると思われます。
そのため、運用保守メインで9年目ですが、3年後にはスキルアップするための目標をこの記事にをまとめました。

**2年後にはお客さんとの調整が出来て運用改善とコードを学び自動化が出来るエンジニアになる**

**スキル不足で焦りはありますが、日々一つづつ実務経験積んで積み上げていくしかないです。**


## 仕事の目標
### 現職で運用保守の同じ案件に3年ほど長く経験を積む
今までは派遣社員でしたが現職はSierで働いております。
一つのシステムに深くなることで他の案件に行ったときに障害対応スキル、長く携わった案件のシステムと比較出来て良い運用改善が出来るのではと期待しています。

私は今まで一つの案件で一番長くて一年半の期間はお仕事を覚えて一人称で対応出来るレベルになった後に案件を離れているため、レベルアップ出来ませんでした。
よりシステムに詳しくなるには3年同じシステムに携わり受け身ではなく深くかかわることが大事だと個人的に思いました。

### 運用改善を積極的に行う
運用改善の経験がよく転職する際に求められます。
今の私は運用改善経験が少なくどちらかといえばメンバー層の運用作業メインになっているため、
運用改善の経験を積む事が大事
**運用を改善するにはお客さんの承諾が必要です。簡単に見えますが実際はコミュニケーション能力が必要になります。**

### お客さんとの会話の仕方を習得する
お客さんとコミュニケーション能力が必要になります。
ある提案があればお客さんが納得がいくように提案したり、誘導したりするコミュニケーション能力は必要です。

**コミュニケーション能力にもスキルがあるらしく　コミュニケーション能力が高い方の会話の仕方を学ぶのもありです。**

### お仕事を人に割り振る能力を付ける
新人や後輩に作業依頼を出して対応する能力が必要です。
新人と後輩の方が対応した業務内容の品質の担保は自分がとる必要があります。
仕事量が多くなったら同じメンバーに自分の仕事をお願いする

### 一つのプロジェクトをリードする経験を積む
40代になると案件のリード経験が求められます。
そのため、一つのプロジェクトでも良いですが案件をリードして納期内に収める経験を積めるようにしたいです。
上記は組織によって体制が決まっていたらなかなか経験積めないですが可能な限り積みたいです。

## 技術のスキルアップ
### ITILの知識を付ける
運用改善にはITILの知識が必要です。
運用改善の本を読んで知識を身に着けて実践していきたいです。

### Ansibleの勉強をする
Ansibleは良くlinuxコマンドを自動的に実行する際に使われます。
例えばサーバー構築の時もAnsibleで作成する時もよくあります。

運用保守の私はあまり構築には縁がないですが運用改善でAnsibleの知識が必要なため、
日頃からAnsibleを学んだ方が良いです。


### AWS cloudformationの勉強をする
AWSは手動で作成するよりはcloudformationでコードでサーバ構築する場合があります。
運用保守するにもcloudformationで構築されたシステムにも即戦力として対応出来る様になりたいです。
日頃からcloudformationを学ぶ必要があります。

### VBAの勉強をする
VBAの資格があるため手順書の自動化が出来るためVBAを日頃から学習していた方が良いです
VBAの入門試験を数年前に取りましたが現職でも手順書の自動化は大変役に立っています。

### AWSの基本知識を付ける
UdemyなどでハンズをンしてAWSの資格試験のみではなくハンズオンを通してAWSの各サービスの仕組みを理解することが出大事です。
**最低でもSAAレベルのハンズオン理解と提案できるSAPの知識レベルは維持したいです**

### linuxの基本知識は付ける
linuxの基本知識は障害対応するうえで重要です。
**lpicの資格レベル1とレベル2を再度認定するように学習します。**
**自宅でlinuxサーバー立ててハンズオンをしてコマンドを覚えた方が良いです**

お客さんにも正しい知識でlinuxシステムの説明できるようになる

### wordpressのサーバーを立てて自宅で運用してみる
よくスキルを付けるにはwordpressのサーバー立てて自宅で運用するとスキルが付くと言われています。
そのため、やり方は調べてやってみるのも良いかもしれないです。


## 個人としての改善
### プラスな面に目を向ける
**出来ないことばかりではなく現在出来ていることと出来ていないことを客観的に把握して
プラスな部分に目を向ける習慣を付ける**

志望度の高い企業であっさり落ちたり、うまくいかないことはよくあります。
そのため失敗経験や評価されなかった経験をバネにして継続して頑張るようにする

優秀な人が職場で多いと比較してしまいますが日頃から今できている部分に目を向ける様にする。

### 失敗や指摘されたことは改善する
人から怒られたことや注意されたことなどメモを取り次回から改善するようにする。

同じ失敗やミスを繰り返して年を取りたくないため、日々改善を繰り返えします。


### 日々慣れないことに挑戦する
お仕事でも難しい仕事は断らずに挑戦してみるのも大事です。
**日々昨日の自分を超えていけるように慣れないことを積極的にしていくことは大事です。**

### 実務の技術に興味を持つ
なんとなく解決したベテラン社員が解決してくれたから大丈夫ではなく

**実務でかかわった技術は疑問点を解決して自分のものにする
その積み重ねが知識が積み上がっていきます**
データエクスプローラはカタログエクスプローラに名称変更されました

こちらのアップデートです。

**Data Explorer is now Catalog Explorer**

https://docs.gcp.databricks.com/release-notes/product/2023/september.html#data-explorer-is-now-catalog-explorer

これは、これまではデータ(カタログ、データベース、テーブル)しか表示されませんでしたが、関数、機械学習モデル、ボリュームなどのセキュリティ保護可能オブジェクトも管理できるようになったためです。

まず、サイドメニューの**データ**が**カタログ**に名称変更されています。
![Screenshot 2023-09-08 at 7.27.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/ae8b188d-8c5e-7940-b984-fd3505ff3b5d.png)

アクセスすると、タイトルも**カタログエクスプローラー**に変更されています。
![Screenshot 2023-09-08 at 7.28.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/a083cca1-b492-da54-2112-47424dacfaf9.png)

このようにAI、データ分析で活用するさまざまなオブジェクトを管理できるようになっています。
![Screenshot 2023-09-08 at 7.29.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/d227f1b6-e48a-2741-a99c-88dd599de2e9.png)

### Databricksクイックスタートガイド

[Databricksクイックスタートガイド](https://www.amazon.co.jp/dp/B09V1YXFVQ/)


### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
react で smooth scroll 実装

## reactでスムースにスクロールさせた時のメモ

```sample.tsx
import { memo, useRef } from "react";

const sample = () => {
    const ref = useRef<HTMLDivElement>(null);
    
    const scrollToTarget = () => {
        // scrollIntoViewのbehaviorオプションで"smooth"を追加
        ref?.current?.scrollIntoView({ behavior: "smooth" });
    };
    
    return (
        <>
            <button　onClick={scrollToTarget}>
              目的地までスムーズにスクロールします
            </button>
            
            // （省略）
            
            // スクロールする要素へref追加
            <div ref={ref}>Target</div>
        </>
    )
}
```
Javaで「デフォルトコンストラクタ」の動作を確認してみた

# 概要
Javaで「デフォルトコンストラクタ」の動作を確認してみました。以下のページを参考にしました。

https://www.javadrive.jp/start/constructor/index4.html

# 実装
以下のファイルを作成しました。
```CTest11.java
class CTest11{
  public static void main(String args[]){
    Test test = new Test();
  }
}

class Test{
  Test(){
  }

  Test(int num){
  }
}
```
以下のコマンドを実行しました。
```
$ javac CTest11.java 
$ java CTest11 
```

# まとめ
なにかの役に立てばと。
46 共通鍵　公開鍵暗号方式の仕組み

### データを暗号化してやり取りする暗号通信の基本
盗聴に対する対策は暗号化である。
暗号通信　送信者と受信者しかわからない暗号文でやり取りを行う。
送信者は、平文を”鍵１”を使って暗号化した暗号文を送る。
受信者は、”鍵２”を使って元の平文に復号する。
### 暗号化と復号で同じ鍵を使う共通鍵暗号方式
共通鍵暗号方式　”鍵１”と”鍵２”に同じ鍵をつかう、暗号化と復号に同じ鍵（共通鍵）（対称鍵暗号方式、秘密鍵暗号方式）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3293109/569fada7-ee9f-2ec9-8109-7ab32f7d9d69.png)
鍵を通信相手に安全に届けるために、鍵自体を暗号化して送信、配送が難しい。そして、通信相手が多くなればなるほど鍵の管理が困難。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3293109/49b241b7-f598-4239-a2ac-305856b67b41.png)
鍵数　＝　N*（N-1）/2
共通鍵暗号方式　DES　2⁵⁶パターン
　　　　　　　　AES　2²⁵⁶パターン　⇒　盗聴リスクが少ない
### 公開鍵と秘密鍵のペア鍵を使う公開鍵暗号方式
暗号化と復号に異なる鍵をつかう、公開鍵と秘密鍵で一組となるペア鍵を使い、暗号化と復号を行う暗号方式を公開鍵暗号方式という。
　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3293109/f1afcf56-ff3e-bfe4-bea3-162dded93c4d.png)
　送信者が公開鍵を入手して、その公開鍵を使って平文を暗号化して送信する。受信者は、暗号文を自分だけが持つ秘密鍵で復号する。
　公開鍵暗号方式　鍵個数　2*N
　公開鍵暗号方式は共通鍵暗号方式より、鍵の管理が容易。
　代表的な暗号方式は　
　RSA　桁数が大きな合成数の分解計算が困難である。
　楕円曲線暗号　楕円曲線の演算
　エルガマル暗号　離散対数
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3293109/b7d0b92f-b84c-b8c3-c413-ca7a35026e6e.png)
### 両方の方式の組み合わせ　ハイブリッド方式
速度と強度が両立

練習問題
暗号化と復号に同じ鍵を利用する暗号方式を共通鍵暗号方式。
公開鍵と秘密鍵のペア鍵を使う暗号方式を公開鍵暗号方式。
AESはNISTが公募した共通鍵暗号方式。
RSAは素因数分解の計算の困難さを利用した公開鍵暗号方式。
通信の開始時に共通鍵を公開鍵暗号方式で暗号化して相手に送り、データの暗号化を共通鍵暗号方式で行う方式をハイブリッド方式。
【積読】コードを書くときは、意図が読み手に伝わるように

:::note info
コードを書くときには、詩やエッセイやメールで要件を伝えるように、意図を明確に表現することが重要。
:::

今回はプリンシプルオブプログラミングを読んだ中で、自分が参考にしている章について整理しています。

---

### コードが唯一の手がかり
ソフトウェア開発では、様々なドキュメントが作成される。ですが、ドキュメンントでは「ソフトウェアがどのように動くのか」について正確に知ることは実は難しいです。

|ドキュメント|内容|
|:------------|:--|
|要件定義書 |どのようなものが欲しいか書かれている|
|基本設計書|どのようなソフトウェア要件を実現するか|
|詳細設計書|どのような構造でソフトウェアを作るのか予定が書かれている|

:::note info
上記のように様々なドキュメントを作成する中で、「ソフトウェアがどう動くか」について正確に知ることは難しい。結局ソフトウェアの動作を把握するには、コードを読むしかない。
:::


### コードは読みやすさが最優先
重要なのは、コードは「書かれること」より「読まれること」の方がずっと多いということ。書くのは1回ですが、その後たくさんの人が、たくさんの回数読むことになります。結果、「**コードを書く時間**」よりも「**コードを読む時間**」のほうがはるかに多くなるのです。

よって、コードは「書く効率」よりも「読む効率」の方が優先されます。**書く時の効率が多少落ちても、読む時の効率が上がれば、十分見合う価値があります**。コードは思いがけず長く生き続けることがあるので、コードが読んで分かりやすいものになっていれば、その価値は累積的に膨れ上がっていく。

:::note info
コードを読んでいる中で、すぐに何を言っているのか理解できない場合は、直ちに分かりやすく書き直すようにしましょう。
:::

### モグラ叩き開発を避ける
有名なゲームであるモグラ叩きは、子供たちは大喜びですが、ソフトウェア開発においては望ましいことではありません。
ランダムに壊れたコードが顔を覗かせるような厄介なソフトウェアの修正は少しも楽しいものではない。読みやすく、障害のない、品質の高いコードを書くのは、時間はかかります。短期的には損失に見えますが、「モグラ叩き」にならないので、長期的には必ず利益をもたらします。


### コメントは書く
コメントがなくても読めるような、分かりやすいコードを書くのが理想。
ただし、コードはどこまで行っても「What」と「How」までしか表現できません。「Why」、つまり「なぜそれをしているのか」を表現するには、コメントを使用する必要がある。

:::note info
コードは、**読む人とのコミュニケーションに使用する**もの。コミュニケーションを円滑にするために役立つのであれば、コメントは進んで使用するべき。
:::

---

参考文献
*プリンシプル オブ プログラミング3年目までに身につけたい一生役立つ101の原理原則*
https://www.amazon.co.jp/dp/4798046140?ref_=cm_sw_r_cp_ud_dp_0C637KV2ZJAP5TECFEK4_2
TypeScriptのジェネリック型とは


ジェネリック型（Generics）は、TypeScriptや他のいくつかのプログラム言語で見られる機能で、コードの再利用性を高めるための非常に強力なツールです。

# ジェネリック型とは 
ジェネリック型を簡単に説明すると、型を「パラメータ」として関数やクラスに渡すことができる仕組みです。この「型のパラメータ」によって、一般的な関数やクラスを作成することができ、それを様々な型で再利用することができます。

### 例: ジェネリックを使用しない場合
```typescript
function echoString(value: string): string {
    return value;
}

function echoNumber(value: number): number {
    return value;
}
```
上記のように、文字列や数字を返すための別々の関数を作成する必要があります。

### 例: ジェネリックを使用する場合
```typescript
function echo<T>(value: T): T {
    return value;
}

let str: string = echo<string>("hello");
let num: number = echo<number>(12345);
```
上記のecho関数は、<T>という部分で型のパラメータを受け取ることができます。これにより、どんな型でもこの関数を使用することができるようになりました。

> <> の中の T は、単に一つの「型変数」または「型パラメータ」として使用される文字です。T は>「Type」の略としてよく使用される名前ですが、必ずしも T である必要はありません。実際には、任意の名前を使って型変数を定義することができます。

# ジェネリックの利点
- __再利用性__: 一つのジェネリック関数やクラスを多くの型で再利用することができます。
- __型の安全性__: 型の情報を保持しながら、動的に型を操作することができます。
- __柔軟性__: 様々な型で動作するコードを書くことができますが、型の安全性も確保されます。

# 他のジェネリックの例
ジェネリックを持つ配列


```typescript
let numbers: Array<number> = [1, 2, 3];
let strings: Array<string> = ["a", "b", "c"];
```
ジェネリッククラス
クラスでもジェネリック型を使用することができます。

```typescript
class Box<T> {
    private content: T;

    constructor(content: T) {
        this.content = content;
    }

    getContent(): T {
        return this.content;
    }
}

let numberBox: Box<number> = new Box(123);
let stringBox: Box<string> = new Box("hello");
```
このように、ジェネリック型はコードの再利用性を高めるための非常に強力なツールです。特に大きなプロジェクトやライブラリを作成する際には、この機能は非常に役立ちます。
SQL serverでユーザーをつくろうとしてハマった話(ログインとユーザーの違い、マッピングについて)



# やりたかったこと
自動化でDBから必要な情報をselectしてSQL内で加工するだけなので、
①Power Automate用のユーザ作成
②db_datareader、db_denydatawriterの付与(読み取り専用を明示的に)

~~こんなん5分で終わるやろ、て思ったら午前中を丸々つぶしたのは内緒です~~

# 最初に参考にしたもの
この後ドツボにはまりますが、自分が無知なだけでこちらの記事を批判とかそういう意図は無いです。
https://www.kwbtblog.com/entry/2019/10/11/030233

もしストアドプロシージャやファンクションの実行が必要な人は
こちらの記事をお読みください。
https://qiita.com/kazumatsukazu/items/9935d524f53c347b0e3c

# 新しく作ったユーザでログインしようとするとエラーが出る
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/485045/b010aaaa-ffba-5b1e-33e5-efbadac33d41.png)


## SQL Serverの２種類のユーザー
https://sql-oracle.com/sqlserver/?p=143
なるほど、SQL serverとDBでそれぞれ設定が必要だった模様
下記のスクショには確かにServer側に使いたいログインが無い(DB側にはユーザーとしてある)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/485045/2f95a613-36d4-a892-ae85-7a1d8766f396.png)

## Server側のログインも作成したが。。。
ServerログインとDBユーザーが紐づいてないもんね、そりゃそうだ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/485045/3e12c055-4bce-e1ad-2a8b-1d0af6c92293.png)

#### マッピングしたいのに、みんなが出てくるUIウィンドウの代わりにT-SQLの画面出るのなぁぜなぁぜ？
顧客がほしいもの
https://blog.itparadise.jp/?p=575
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/485045/3cf90c26-27e2-1032-8e04-77e7f0789251.png)
提案されたもの
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/485045/f049ebde-1048-0104-00dd-80359e47601d.png)
くそぅ

### ひたすらググる
https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-change-users-login-transact-sql?view=sql-server-ver16#b-mapping-a-database-user-to-a-new-sql-server-login

ちなみに調べてると出てくる

```sql
EXEC sp_change_users_login
```
ですが、将来削除予定で今は非推奨のようです(自分の環境ではエラー出ました。そんなSP無いぞ、と)。

```sql
--Map database user MB-Sales to login MaryB.  
USE <db_name>;  
GO  
ALTER USER <USERNAME> WITH LOGIN = <LOGINNAME>; 
GO  
```
### でもエラー
```
The user cannot be remapped to a login. Remapping can only be done for users that were mapped to Windows or SQL logins.
```

なんかユーザー作成の地雷全部踏み抜いてないか？

### 今度こそ
ユーザー作るときにfor でログインを指定しないといけなかったみたい。
```sql
create user <user-name> for login <login-name>
```
てなわけで既存のユーザー削除して新規作成。

それでもエラーが出たのでユーザが存在するDB名を指定するようにしたらログイン出来ました！！！！！！！
https://azureops.org/articles/the-server-principal-is-not-able-to-access-the-database-master-under-the-current-security-context/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/485045/6105c5f4-7b52-eb51-0d5d-b696fccffa6c.png)

# 教訓
きちんと基礎から学ぼうな
【Flet】シンプルなカレンダーを作る

>2023/11/22　公式からDatePickerが提供されていることを確認しました。特に理由がなければそちらを使用することをお勧めします。

https://flet.dev/docs/controls/datepicker/

pythonに標準で入っているcalendarモジュールとfletを組み合わせて簡単なカレンダーを作るコードです。

完成形はこちら
![スクリーンショット 2023-09-08 013328.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2960906/2232dcc9-1b9a-274a-8eaf-0ecfcb6bcc27.png)

## コード
```py
import flet as ft
import calendar

class DateMapping:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day

    def generate_days(self):
        # 2次元配列形式の日付を生成。firstweekdayで始まりの曜日を設定できる。0が月曜、6が日曜
        c = calendar.Calendar(firstweekday=self.day)
        dates = c.monthdayscalendar(self.year, self.month)
        return dates

    def ymd_mapping(self):
        # 年月をキーとして二次元配列の日付を辞書に格納
        calendar_dict = {}
        calendar_dict[(self.year, self.month)] = self.generate_days()
        return calendar_dict

class FletMonthCalendar(ft.UserControl):
    def __init__(self, year, month, day):
        super().__init__()
        self.year = year
        self.month = month
        self.day = day

    def build(self):
        # グリッドの作成
        item_width = 50
        self.calendar_grid = ft.GridView(
            width=item_width*7,
            max_extent=item_width,
            child_aspect_ratio=1.0,
            spacing=1,
            run_spacing=1,
        )

        # 日付のリストと年月の組み合わせの辞書を取得
        self.dates_dict = DateMapping(self.year, self.month, self.day).ymd_mapping()

        # 日付をグリッドに格納
        for ym, date in self.dates_dict.items():
            for week in date:
                for day in week:
                    if day != 0:  # 日付が0以外なら数字を表示
                        self.calendar_grid.controls.append(
                            ft.Container(
                                content=ft.Text(value=day),
                                alignment=ft.alignment.center,
                            )
                        )
                    else:  # 日付が0なら空白を表示
                        self.calendar_grid.controls.append(
                            ft.Container(
                                content=ft.Text(value=""),
                                alignment=ft.alignment.center,
                            )
                        )

        return self.calendar_grid

def main(page: ft.Page):
    content = FletMonthCalendar(2023, 9, 6)
    page.add(content)

if __name__ == "__main__":
    ft.app(target=main)
```
`item_width`で一つ一つのアイテムの大きさを決定し、`width=item_width*7,`にすることで一行ごとのアイテム数を7にしています。
`ft.Text`を他のものに変えれば日付選択のコンポーネントなども作れると思います。
【Python】dict型/list型でgetとset 

# dict型をget
getを使用すると存在しないキー「グループ名」を指定した場合にエラーが出ない
```python
student_dict = {'所属ID': 102, '学年ID': '01', 'クラスID': 4, '名前': '星宮いちご'}
school_year = student_dict.get("学年ID")
print(school_year)
# 01
```
存在しないキーをカラムで指定するとエラーが出る
```python
student_dict = {'所属ID': 102, '学年ID': '01', 'クラスID': 4, '名前': '星宮いちご'}
school_year = student_dict['グループID']
print(school_year)
# KeyError: 'グループID'
```

# dict型をset
```python
student_dict = {'所属ID': 102, '学年ID': '01', 'クラスID': 4, '名前': '星宮いちご'}
school_year = set([student_dict.get("学年ID")])
print(school_year)
# {'01'}
```
setの中身が文字列のとき`[]`で囲む
囲まないときは、文字列が分解される
```python
student_dict = {'所属ID': 102, '学年ID': '01', 'クラスID': 4, '名前': '星宮いちご'}
year_list = set(student_dict.get("学年ID"))
print(year_list)
# {'0', '1'}
```

# list型をget
```python
student_list = [
    {'所属ID': 100, '学年ID': '01', 'クラスID': 1, '名前': '星宮いちご'},
    {'所属ID': 100, '学年ID': '01', 'クラスID': 2, '名前': '霧矢あおい'},
    {'所属ID': 100, '学年ID': '01', 'クラスID': 4, '名前': '紫吹蘭'},
    {'所属ID': 100, '学年ID': '01', 'クラスID': 4, '名前': '栗栖川おとめ'},
    {'所属ID': 100, '学年ID': '02', 'クラスID': 1, '名前': '藤堂ユリカ'},
    {'所属ID': 100, '学年ID': '02', 'クラスID': 3, '名前': '北大路さくら'},
    {'所属ID': 101, '学年ID': '04', 'クラスID': 1, '名前': '一ノ瀬かえで'},
]
for l in student_list:
    year = l.get("学年ID")
    print(year,end=" ")
# 01 01 01 01 02 02 04
```
# list型をset
```python
student_list = [
    {'所属ID': 100, '学年ID': '01', 'クラスID': 1, '名前': '星宮いちご'},
    {'所属ID': 100, '学年ID': '01', 'クラスID': 2, '名前': '霧矢あおい'},
    {'所属ID': 100, '学年ID': '01', 'クラスID': 4, '名前': '紫吹蘭'},
    {'所属ID': 100, '学年ID': '01', 'クラスID': 4, '名前': '栗栖川おとめ'},
    {'所属ID': 100, '学年ID': '02', 'クラスID': 1, '名前': '藤堂ユリカ'},
    {'所属ID': 100, '学年ID': '02', 'クラスID': 3, '名前': '北大路さくら'},
    {'所属ID': 101, '学年ID': '04', 'クラスID': 1, '名前': '一ノ瀬かえで'},
]
year = set(l.get("学年ID") for l in student_list)
print(year)
# {'04', '01', '02'}
```
for内部表記を使用してdict扱いにする
# 応用
```python
student_list = [
    {'所属ID': 100, '学年ID': '01', 'クラスID': 1, '名前': '星宮いちご'},
    {'所属ID': 100, '学年ID': '01', 'クラスID': 2, '名前': '霧矢あおい'},
    {'所属ID': 100, '学年ID': '01', 'クラスID': 4, '名前': '紫吹蘭'},
    {'所属ID': 100, '学年ID': '01', 'クラスID': 4, '名前': '栗栖川おとめ'},
    {'所属ID': 100, '学年ID': '02', 'クラスID': 1, '名前': '藤堂ユリカ'},
    {'所属ID': 100, '学年ID': '02', 'クラスID': 3, '名前': '北大路さくら'},
    {'所属ID': 101, '学年ID': '04', 'クラスID': 1, '名前': '一ノ瀬かえで'},
]
# 所属IDのlistを作成
affiliation_list = set(l.get("所属ID") for l in student_list)
for affi in affiliation_list:
    # 所属IDのlistと所属IDの値が同値のlistを取得
    affi_same = list(filter(lambda x : affi == x["所属ID"],student_list))
    print(affi_same,end="\n")
# [{'所属ID': 100, '学年ID': '01', 'クラスID': 1, '名前': '星宮いちご'}, {'所属ID': 100, '学年ID': '01', 'クラスID': 2, '名前': '霧矢あおい'}, {'所属ID': 100, '学年ID': '01', 'クラスID': 4, '名前': '紫吹蘭'}, {'所属ID': 100, '学年ID': '01', 'クラスID': 4, '名前': '栗栖川おとめ'}, {'所属ID': 100, '学年ID': '02', 'クラスID': 1, '名前': '藤堂ユリカ'}, {'所属ID': 100, '学年ID': '02','クラスID': 3, '名前': '北大路さくら'}]
# [{'所属ID': 101, '学年ID': '04', 'クラスID': 1, '名前': '一ノ瀬かえで'}]
```
AWS認定 AWS Certified Database - Specialty(DBS-C01) 合格記録

AWS認定 AWS Certified Database - Specialty(DBS-C01) に合格しました！

# 事前知識

AWSの資格は、ソリューションアーキテクト2つを保持しています。

AWSのデータベースサービスは、仕事でちょくちょく触っている程度です。

https://qiita.com/marchin_1989/items/32199930a219778337bb

https://qiita.com/marchin_1989/items/e5239de6bc05df3f4957

# 学習方法

基本的には、[要点整理から攻略する『AWS認定 データベース-専門知識』](https://amzn.asia/d/dcKE166)で学習を進めました。
ソリューションアーキテクトプロフェッショナルの試験勉強時に、問題以外は1周読んでおり、今回は、問題含め、まず1周しました。
その後、問題を解いて間違えた部分、自信がない部分などを公式のドキュメントや、FAQ、ブラックベルトなどで補完し、試験に臨みました。

1ヶ月前に試験予約をして、10日ほど2, 3時間勉強していたので、合計の学習時間は30時間ほどだったかと思います。

# 受験

慣れないことをして、脳に負荷をかけたくなかったので、いつも受験している（行きつけのw）テストセンターで受験しました。

ほぼほぼ予想通りの試験内容でした。時間も1時間以上余って、結構手応えありました。

# 結果

受験者スコア: 816 で合格でした。手応えがあった割にですが、まぁよしとします。

# 振り返り

AWSのデータベースに関するサービスを体系的に学べたのは良かったかと思います。

要件をもとに、データベースを含めたシステム構成を考える際に、大いに役立ちそうです。

# まとめ

とろうとろう思って半年以上経ってしまったんですが、やはり試験で一番大事だったのは、**まず試験日決めて予約すること**でした。次のAWS試験もまずは予約してやろうと思います！
ffmpegでfilter_complexを使った処理がうまくできない場合の解決

# 結論
ffmpegで29.97fpsの動画を取り扱うとき、うまく使えない場合があるので30fpsにするとうまく処理できる

# 経緯
29.97fpsの動画2つを横に並べて比較したいということがありました。  
そこで、下記のコマンドを使って横に結合した動画を作ろうとしたところ、何時間経ってもエンコードできないバグを踏みました。

```
ffmpeg -i input1.mp4 -i input2.mp4 -filter_complex "hstack" output.mp4
```

#　解決方法
動画自体を30fpsとして解釈できるようにして、上記のコマンドで結合するとうまくできました。

```
ffmpeg -i input.mp4 -r 30 -c:v copy output.mp4
```
# 原因？
フレームレートが29.97なのは日本のNTSC方式なので、あまりバグとして認知されてないのかもれしれませんね。
【Laravel】フロント(JavaScript)へ渡した配列のソートがリセットされる件について

## 概要
`コレクション配列`をソートして、フロント(JavaScript)へ渡した際にソートは正しく実行されているはずが、データを受け取るとソートがリセットされてしまう問題に直面しました。

## 原因
`コレクション配列`は値をキーと共に保持し、通常は0から始まる連続した数値インデックスを持ちます。

しかし、ソートした場合インデックスはリセットされないので、正しくソートされていたとしてもJavaScriptでデータを受け取るときには、そのインデックスで再度並び替えられてしまいソートがリセットされてしまいます。

## 解決策
この問題を解決するために、`valuesメソッド`を使用します。

このメソッドは、コレクション内のすべての値を新しい0から始まる連続した数値インデックスで`再構築`し、ソートを保持します。

以下のようなコレクションがあるとします。

```php
$collection = collect([
    ['name' => 'E. Haaland', 'score' => 85],
    ['name' => 'Messhi', 'score' => 92],
    ['name' => 'Neymar', 'score' => 78],
]);
```

このコレクションをスコアの降順でソートした場合

```php
$sortedCollection = $collection->sortByDesc('score');
```

$sortedCollectionは次のようになります。

```php
Illuminate\Support\Collection 
[items:protected] => Array
        (
            [1] => Array
                (
                    [name] => Messhi
                    [score] => 92
                )

            [0] => Array
                (
                    [name] => E. Haaland
                    [score] => 85
                )

            [2] => Array
                (
                    [name] => Neymar
                    [score] => 78
                )

        )
```

ソートされたコレクションを見てみると、キー（インデックス）がリセットされていません。

そこで、`valuesメソッド`を使用して次のようにインデックスを再構築することができます。

```php
$sortedCollection->values();
```

$sortedCollectionは次のようになり、キーが再構築されたデータが格納されています。

```php
Illuminate\Support\Collection 
[items:protected] => Array
        (
            [0] => Array
                (
                    [name] => Messhi
                    [score] => 92
                )

            [1] => Array
                (
                    [name] => E. Haaland
                    [score] => 85
                )

            [2] => Array
                (
                    [name] => Neymar
                    [score] => 78
                )

        )
```
`valuesメソッド`をソートされたコレクションに使用することで、インデックスが再構築されフロントでソートを維持したまま受け取ることができるようになります。

## 参考
https://readouble.com/laravel/8.x/ja/collections.html#method-values
【Git】エディタ設定の優先順位

## 設定の優先順位

Gitのエディタ設定の優先順位は次のとおりです。

1. `GIT_EDITOR`環境変数 
2. `core.editor`設定
    - `/etc/gitconfig` 
    - `~/.gitconfig`または`~/.config/git/config`
    - `.git/config`
3. `VISUAL`環境変数
4. `EDITOR`環境変数 
5. vi（Debian、Ubuntu の場合は editor）
@Controllerと@RestControllerの違い

# 序文
<details><summary>編集履歴</summary>
無し
</details>
備忘録兼JavaDocを参考文献として提示しているものがなかったため文章を作成。
間違い・補足可能な情報があり次第追記する。

# 結論
@RestControllerが@Controllerの拡張版。
@ResponceBodyが@Controllerと合併している。

# 補足
昔は@RestControllerは存在せず、
@ResponceBodyと@Controllerを両方付与する必要があった模様。

HTMLを返す際には@Controllerをまだ用いれるが、
統一して@RestControllerを使用して問題なさそう。

## テスト：JSON形式を返す想定（@Controller）
```SampleAPI.java
@Controller
public class SampleAPI{

  @GetMapping("/")
	public Text main() {
		return new Text("Hello");
	}

}
record Text(String message){};
```
![スクリーンショット 2023-09-07 23.50.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622672/545eeb05-856f-e53d-e08f-f9411379ad54.png)

```error.log
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Circular view path []: would dispatch back to the current handler URL [/] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)] with root cause

jakarta.servlet.ServletException: Circular view path []: would dispatch back to the current handler URL [/] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
```
## テスト：JSON形式を返す想定（@RestController）
```SampleAPI.java
@RestController
public class SampleAPI{

  @GetMapping("/")
	public Text main() {
		return new Text("Hello");
	}

}
record Text(String message){};
```
![スクリーンショット 2023-09-07 23.49.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622672/2970d967-02cc-77c6-5fb2-d56dd48c3902.png)

RestControllerのみJSON形式のデータを返すことができていることが確認できた。
@Controllerの方はビューリゾルバを提供しろとエラーを吐いていることも確認できた。

# 参考サイト
https://spring.pleiades.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Controller.html


https://spring.pleiades.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html


https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/ResponseBody.html

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html

https://note.com/yota7/n/n2ee5c62957f5
名前付けのコツ「現実見ろよ法(仮)」

最近卒業制作に追われる中でとてもいい命名法を編み出したので、広大なネットの海から意見をもらいたい。

# 忙しい人のための「現実見ろよ法(仮)」 
- 機能を現実に存在するものに置き換えて命名しろ
- この命名法で命名できない場合それはたぶん設計が間違っている


```
【 Unityでプレイヤーキャラを作る場合の例 】

■ → ゲームオブジェクト
● → コンポーネント


■ Player
　● Head  (入力やゲームからのフィードバックから各コンポーネントを制御)
　● Body  (体力やスタミナの管理を担当)
　● Arm   (攻撃を担当)
　● Leg   (移動を担当)
　● Bag   (持ち物管理を担当)
　● Armor (防御力を管理)
```
要するに「CharacterMove」とか「InputManager」みたいなコンポーネントを作るなって話

# 暇人のための詳説
現実のものに即した命名をしようという考え方である。
虚ろを覗いてばかりいるプログラマーたちはイキって抽象的な名前を付けたがる。
「Manager」とか「Update」とか。
そういうのはやめて現実にあるもので命名しよう。

## なぜ CharacterMove がダメなのか
機能の分割, 追加, 変更 etc. するときに困るから。
CharacterMove は「キャラクターが動く」という処理を表した名前と思われる。
しかし「処理」を名前にするのはよろしくない。
人間の頭は非可算なものを効率よく分割できるように設計されていない。

### リスト等で複数個まとめて管理するとき変数名に困る
- CharacterMoves にはしたくない
- じゃあ CharacterMoveManager にするか！(地獄の始まり)

オブジェクト指向って「モノ」をいっぱい集めてデカいもの作ろうぜ！って思想なので、
そもそも不可算な名前を付けてる時点でだめだと思う。
    
### 機能を分割すると名前が長くなる
 - CharacterMoveGroundNormalChecker って何？
 - 概念を分割しても所詮は概念なのでさらに機能分割するとどんどん悲惨なことになる

概念は分割したところで所詮は概念なので、実態を持つ「オブジェクト」に昇格することはない。
よくエンジニアはろくろを回しているが、コード上でもろくろを回している余裕はあるのだろうか。


### 新機能を追加する時に困る
- キャラクターが走る機能を追加しよう ← まだなんとかなる
- 走るときスタミナを消費させよう ← スタミナコンポーネントのメソッドを呼び出して共依存に...
- ローリングできるようにしよう ← 無敵時間管理コンポーネントにも依存

「上位階層に移譲すればいいじゃん」と気づいたアナタ、大正解。
でも人間はアホなのでコード書いてるときに気づけないんや(n敗)
脳死で機能追加の場所を特定できる命名は重要。

## CharacterMove を「現実見ろよ法(仮)」で解決する
「現実見ろよ法(仮)」を使うとこの問題をスマートに解決できる(できてほしい)。
ここでは「CharacterMove」を「Leg」に置き換えてみる。


### リスト等で複数纏める場合
- Legs でいい
- もっとも、脚をいっぱい集めるなんて吉良吉影の脚版みたいなこと誰がするんやって話だが

### 機能を分割する場合
- Leg (他の機能から入力を受けて足全体を制御する)
    - Bone (足の長さを保持して登れる坂や段差を判定する)
    - Muscle (移動速度やジャンプ力を制御)
    - Foot (接地判定や地面の法線を取得する機能)

なんかきもいな。
たぶん分割しすぎだと思う。
自分なら Foot と Leg に分割するにとどめるかなぁ。
(一応こういう風に分けられるという例)
ただ、Foot 基準で分割しておくと「足のすべての指に指輪を付けられる」という狂気じみた仕様にも簡単に対応できそうなので間違っていないと思う。

### 機能を追加する場合
Leg は脚なので「脚にその機能をつけていいのか？」を考えるだけでいい。
付けられないなら他のコンポーネントを作って機能の合成は上位階層に移譲する。
- 走る機能を追加しよう ← 足に機能を追加するだけでOK
- 走るときにスタミナを消費させよう ← 移動部分のみ Leg に実装, スタミナ処理等は上位階層に移譲
- ローリングできるようにしよう ← 移動部分のみ Leg に実装, 他は上位階層に移譲

Leg の親が Player なら、Player にスタミナとローリングのコンポーネントをぶら下げて
Player オブジェクト内でローリングの移動/無敵/スタミナ消費の処理をしかるべきコンポーネントにぶん投げると良いと思う。

## 現実見ろよ！
いい夢見るなよ！
ポートフォリオ作成時に知っておきたかったdockerの用語

# 概要

未経験で入社して初日にdockerを動かすことになったのでもろもろイメージできていないものがあり、結構苦労したので復習できる範囲で用語を書き連ねていく

# 用語

- Docker
コンテナ型の仮想環境を構築できるもの

- コンテナ化すると何がいいのか
いろんなバージョンを統一できるので考えることが少なくて済む

- dockerfile
説明書の設計書みたいなもの。imageを作る際に必要。環境とかはこっちに書く

- docker image
後述するコンテナの設計書みたいなもの。dockerhubとか見るといい

- docker container
イメージを元にした実際のコンテナ

# 大体使うコマンド
- build
初回作成時によく使うかんじ。２回目以降はrun,stop,downでいいかも

- up,down
コンテナ起動のコマンド。

- prune
コンテナファイルを削除する。ポートフォリオで中途半端に作ったやつで自分は10G使ってたので一番便利だと思ったコマンド

# まとめ

もっと色々あるけど随時更新する。
Windows Insider Programに登録する

マイクロソフトの渡部です☺

本記事では、Windows Insider Programへの登録の仕方をご紹介します。

**Windows Insider Programとは？**
-Windows Insider Program は、マイクロソフトが公式に運営する、一般提供前の Windows をいち早くお試しいただけるプログラムです。

※本記事は公式記事を参考に執筆しております。
[Microsoft Learn](https://learn.microsoft.com/ja-jp/windows-insider/get-started "Microsoft Learn")

# 手順
1\. **物理PC** もしくは **クラウドPC**を起動し、[設定] > [Windows Update] > [Windows Insider Program] ページに移動します。
[使用を開始する] を選択して、登録プロセスを開始します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529374/6509ce19-e4f3-054b-f2d8-f7b18e088384.png)


2\. アカウントを紐づけます。
職場アカウントの場合は [職場または学校アカウント] 、個人アカウントの場合は [Microsoft アカウント] でサインインします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529374/bd21eb04-a1ec-395e-5a2d-abd3d7913eb7.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529374/9ee58776-ca7f-bd6e-0773-91094429de59.png)


3\. チャネルを選択して [続行] します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529374/eb87d635-0860-372c-ba9d-e5b1a83c31e9.png)

4\. 規約を読み、同意して[続行] します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529374/2b98f1e9-55d1-eb65-1d51-39d22196f049.png)

5\. デバイスを再起動して登録します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529374/e528fd24-437b-9e7d-2534-333bf2d53037.png)


6\. 再起動後、[設定] > [Windows Update] > [Windows Insider Program] ページに移動し、登録が完了したことを確認します。
[Windows Updateを開く] を押して Windows Update のページに遷移します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529374/860bab7c-d4ee-e543-a0ca-ad3deaeb8b45.png)
Insider Preview のダウンロードとインストールが開始されたのを確認します。
※更新が開始しない場合は [更新プログラムのチェック] を押して更新を開始してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529374/51b54553-17da-60de-d977-caf668143ffe.png)

6\. 更新が完了したら再起動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529374/f09c155c-37c8-066e-5f18-4678a82e911d.png)

再起動が完了したら、PCへの Windows Insider Program の登録は完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529374/08352def-526c-0244-46c3-8cd235d4f859.png)

# 諸注意

設定>Windows Update 画面にてWindows Insider Programが表示されないケースがあります。
以下の点ご確認ください。

### ① 管理者権限の有無の確認
物理PC もしくは クラウドPC自体に管理者権限がないと表示されない模様です。
（※Windows 365 Businessで展開したクラウドPCは自動的に管理者権限が外れた状態で展開されていることを確認）
もし、ご自身で設定が変更可能なPCをお持ちの場合、Windows Insider Programが表示されないPCにて以下手順を行い管理者権限に変更して下さい。
1\. タスク バーの検索ボックスに「コントロール パネル」と入力して、[コントロール パネル] を選びます。
2\. [コントロール パネル] ウィンドウで、[ユーザー アカウント]、[アカウントの種類の変更] の順に選択します。
3\. [アカウントの種類の変更] を選択します。
4\. [管理者] を選択して [アカウントの種類の変更] を選択します。
5\. PCを再起動します。

### ② Windows Insider Programへのアカウント登録の確認
Windows Insider Program に登録済みでないと表示されない可能性があります。
以下から、お使いのアカウントを登録して下さい。
[Register for the Windows Insider Program](https://www.microsoft.com/en-us/windowsinsider/register "Windows Insider")
GoでWebアプリケーションを作る（5）ーパッケージ

こんにちは。

今日は「パッケージ」についてです。

パッケージの参照方法と、実際にパッケージの作成を試してもらいます。

# パッケージを使う

実は既に、何度も登場している、`import fmt` が、パッケージ名fmtを使います。という表現です。
`import <パッケージ名>` を増やすことで、他のパッケージを活用できます。
複数のパッケージのimportでは、以下のように`()`でまとめることで、より文字数の少ない書き方もできます。

```go
import (
	"fmt"
	"os"
)
```

## 4章のソースコードを直す

4章で作成したソースコードには、修正すべき問題があります。
それは、エラー時の出力先と、正常時の出力先が同じstdoutであることです。

`fmt`に含まれる、Print関係の関数には、出力先を指定できるものが存在します。
出力先を指定できる関数を用い、エラー出力をstderrに出力するよう修正してもらいます。
実行時は、stdoutを捨てる(`> /dev/null`)すると、差分がわかることでしょう。

なお、Go言語のstderr定数は、osパッケージの、`os.Stderr`として存在するため、追加で、`os`パッケージのインポートください。

```
:# TERMINAL 0

$ cd /../fixFunckyMonkey/
$ <お好きなエディタ> eaters.go
$ go run eaters.go
$ go run eaters.go > /dev/null
```

- `/../fixFunckyMonkey/eaters.go`

```go
package main

import (
	"fmt"
	"os" //追加
)

func Eat(name string) (bool, error) {
	if name == "" {
		return false, fmt.Errorf("name is empty.")
	}
	fmt.Println(name)
	return true, nil
}

func main() {
	var name1 string = "GYUDON"
	if _, err := Eat(name1); err != nil {
		fmt.Fprintf(os.Stderr, "cannot eat: '%s'\n" , err) //更新
	}

	var name2 string = ""
	if _, err := Eat(name2); err != nil {
		fmt.Fprintf(os.Stderr, "cannot eat: '%s'\n" , err) //更新
	}
}
```
### 結果

```
:# TERMINAL 0
:# WORKPATH /../fixFunckyMonkey/

$ go run eaters.go
GYUDON
cannot eat: 'name is empty.'
$ go run eaters.go > /dev/null
cannot eat: 'name is empty.'
```

# パッケージを作る

実は既に、mainパッケージを何度も作成しています。
1行目に書いている`package main` です。
`package <パッケージ名>`と、先頭に書くことで、パッケージ名を定義できます。
`package main`は、それを起点として実行できる決められたパッケージ名です。
今回は、main以外の任意の名前が指定可能な、起点から呼び出されるパッケージを作成してもらいます。

## 関数Eatのshopパッケージ化

```
:# TERMINAL 0
:# COPY /../fixFunckyMonkey/eaters.go /../notKinkyuJi/eaters.go
:# WORKPATH /../notKinkyuJi/

$ cp /../fixFunckyMonkey/eaters.go /../notKinkyuJi/eaters.go
$ cd /../notKinkyuJi/ 
$ <お好きなエディタ> shop/shop.go
$ <お好きなエディタ> eaters.go
$ go run eaters.go
```
- `/../notKinkyuJi/shop/shop.go`

```go
package shop

import (
	"fmt"
)

func Eat(name string) (bool, error) {
	if name == "" {
		return false, fmt.Errorf("name is empty.")
	}
	fmt.Println(name)
	return true, nil
}
```
- /.../notKinkyuJi/eaters.go

```go
package main

import (
	"os"
	"fmt"
	"./shop"
)

func main() {
	var name1 string = "GYUDON"
	if _, err := shop.Eat(name1); err != nil {
		fmt.Fprintf(os.Stderr, "cannot eat: '%s'\n" , err) //更新
	}

	var name2 string = ""
	if _, err := shop.Eat(name2); err != nil {
		fmt.Fprintf(os.Stderr, "cannot eat: '%s'\n" , err) //更新
	}
}
```

### 結果

```
:# TERMINAL 0
:# WORKPATH /../notKinkyuJi/

$ <お好きなエディタ> shop/shop.go
$ <お好きなエディタ> eaters.go
$ go run eaters.go
GYUDON
cannot eat: 'name is empty.'
```

### 真のパッケージ化

本章の課題では、`import "./shop"`のような、相対Pathによるimportを行っています。
相対Pathによるimportは推奨されず、コンパイルエラーとなります。
本講義では、`go mod`の説明を割愛するため、対象エラーを無効化できる環境変数`GO111MODULE=off`を指定しています。
使えるmoduleを作成する場合は、[Module作成方法](https://go.dev/doc/tutorial/create-module)や、その他の[Moduleの呼び方](https://go.dev/doc/tutorial/call-module-code)を参考に、`go mod`に沿ったパッケージ化が推奨されます。

今日は以上です。
ありがとうございました。

次のPart 6は「構造体」です。
よろしくお願いいたします。
fzfでメモを検索

## はじめに

Markdownで書いたメモを、[fzf](https://github.com/junegunn/fzf)を使って見出し単位で検索するコマンド[fcqs](https://github.com/yendo/fcqs) (以前はfcsという名前でした) を書きました。fzfで見出しを検索すると、その見出しから次の見出しまでの内容がプレビューで表示されます。

コマンドラインやショートカットキーなどちょっとしたことについて、繰り返しウェブで検索しさらにページ内から探す手間を省く助けとして使えます。

## インストール

[fzf](https://github.com/junegunn/fzf#installation) をインストールしておきます。

[fcqs](https://github.com/yendo/fcqs/releases)をGitHubからダウンロードして展開します。コマンド本体は`fcqs-cli`というファイルです。

`fcqs-cli`をパスの通ったディレクトリに配置します。例えばLinuxなら以下のようにします。

``` bash
install fcqs-cli ~/.local/bin/
```

Linuxでbashを使う場合、`.bashrc`で設定を行います。メモの内容をコピーする機能を使うためには xclip をインストールしてください。

メモの編集にvimを使う場合は以下を追記します。

``` bash: .bashrc
export VISUAL="vim" # your Unix Editors (Emacs, nano, gedit, etc.)
eval "$(fcqs-cli --bash)"
```

VS Codeを使う場合は以下を追記します。

``` bash: .bashrc
export FCQS_EDITOR="vscode"
eval "$(fcqs-cli --bash)"
```

## メモの仕様

検索対象となるメモファイルは、デフォルトでは`~/fcnotes.md`です。検索対象となるメモファイルは、`FCQS_NOTES_FILE`という環境変数にファイルのパスを設定することで変更できます。

メモの形式として必要なことは、見出しをMarkdown形式で書くだけです。

``` markdown
# title1

contents1

# title2

contens2
```

## 利用方法

コマンドラインで`Ctrol+o`を入力します。

fzfでMarkdownの見出しが表示されますので、検索しつつプレビューで内容を見ることができます。また以下のキーバインドが利用可能です。

- Enterキー: 選択したメモを標準出力に出力します。もしそのメモにコードブロックに囲まれたシェルコマンドが書かれている場合、その最初のブロックのシェルコマンドをコマンドラインにペーストします。
- Ctrl+y: 選択したメモをクリップボードにコピーします。
- Ctrl+o: 選択したメモにURLが含まれる場合、最初のURLをブラウザ等で開きます。
- Ctrl+e: 選択したメモをエディタで開きます。

キーバインドは環境変数でカスタマイズできます。[README](https://github.com/yendo/fcqs/blob/main/README.md)を参照してください。

### その他

- 検索の対象は見出しのみです。
- 見出しの階層やそれに伴う構造は無視します。単純に見出しと見出しの間にある内容を表示します。
- 内容をもたない見出し（次の見出しまでにコンテンツがない）は一覧に表示しません。
- 同じ見出しが複数ある場合は、一つにまとめます。
- 見出しの行末空白は無視します。
- メモの内容に連続する空行があれば1行にまとめます。それ以外の整形は行いません。
- メモの中身が多いと、メモの内容を検索する必要が出てきます。メモの内容は短くしておくのがよいです。
ようつべ体験記8

[前回](https://qiita.com/matsukatsu/items/05a53d2e3352bbeb9ad1)

方針に従って `東南アジア3` を作成し公開しました。
公開したばかりとはいえ、視聴回数が伸びません。
![チャンネルアナリティクス.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423506/ff64c1ff-26b3-0a2a-b214-92fae970e22b.png)
爆死の臭いがします。
やはり `東南アジア1` が比較的視聴回数が伸びたのは何かしらの偶然が作用したからで、安直に東南アジアを投下しても視聴回数が伸びそうにありません。
もう少し `東南アジア1` が視聴された理由を深掘りした上で、方針変更をする必要がありそうです。

`東南アジア1` の視聴回数を振り返ります。
まず、投稿直後の10時間の時点で *37* でした。
まあ、この動画もそもそも大した事は無かったので、`東南アジア3` が伸びないといってもどんぐりの背比べといったところでしょうか。
あまり悲観的にならないようにします。
![コンテンツ-リーチ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423506/89eb43bb-bd01-cae3-3cd2-a0f2384f9f07.png)

投稿後3〜5日目のあたりで *100* 程度急激に伸びています。
ここが特徴的なので、何があったのか調べてみます。
![コンテンツ-リーチ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423506/b61f54fb-4690-bcff-159f-2beeb1f536c2.png)

8/24 - 8/26 の間で *115* のインプレッションからの視聴があり、そのうちの 90.2% が関連動画からの流入です。
![コンテンツ-リーチ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423506/3cd7c947-62b4-7fd0-f9e5-4057bbb60484.png)

関連動画のうち、*65.8%* がたった一つの動画からの流入でした。
![詳細.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423506/15d7ef2b-c065-27e5-b94d-e4a8c04fa08e.png)

この動画を見てみました。
僕のと全く同じテーマの動画が1日先に公開されていました。
この方は `チャンネル登録者数 300人` と、僕より15倍ぐらい多くの登録者数を有し、動画も1.6万回も視聴されていました。

図らずも、他人の人気にあやかるような投稿ができた為、そのチャンネルの視聴者を誘引できていたようです。
「この手法を故意にやり続ければ、他人の顧客を僕の顧客にできるのでは...」
ちょっとそんな考えもよぎりましたが、あまり良い事にはならなさそうです。
視聴回数には貢献してくれそうですが、平均視聴時間があまりに短いです。
![詳細.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423506/5d6ef374-8675-59a5-1615-d0bcdd0ea9cf.png)

この経路で見てくれた方の多くが僕の動画を見て、「うげ、変な動画がはじまった、消そ」と思って離脱しているはずです。
この特徴はリピーターの数にも表れていて、 `東南アジア1` は *19* 人ですが、
![コンテンツ-リーチ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423506/8be714f5-d4bd-3d86-57ff-6c50ea4c335e.png)

視聴回数の合計で次点の `西ヨーロッパ1` は *36* 人のリピーターがついてくれています。
![コンテンツ-リーチ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423506/da7b76ad-de0b-4077-d396-aea47dc35423.png)

`東南アジア1` の強引な客引きでは、リピーターは増やせていない気がします。
せっかく見ていただいても離脱されるようでは最終目標である `チャンネル登録者数 1000人` への貢献は少ないでしょうから、強引な客引きはしないでおこうと思います。
やはり、よそのチャンネルの顧客は、僕のチャンネルの顧客とは違うのでしょう。

とはいえ、視聴回数の合計から、強引な客引きによる視聴回数を引いたとして
```
339 - 79 = 260
```
*260* となり、これは `西ヨーロッパ1` の *254* とかなり近い数です。

`東南アジア1` も `西ヨーロッパ1` も、僕のチャンネルの中ではそこそこ見ていただけている方で、その理由は、強引な客引き以外の何かがありそうです。

[次回](https://qiita.com/matsukatsu/items/4eaa878457fdf71cc59a)
Markdownの文書にPlantUMLを使ってUMLを埋め込む


Markdownの文中にPlantUMLでUMLを埋め込むのに少し苦労したため、備忘として残します。

## PlantUMLを使うための下準備

PlantUMLを使うために、GraphvizとOpenJDKをインストールします。

- [Graphviz](https://www.graphviz.org/download/)
- [OpenJDK](https://jdk.java.net/)

下記を参考にインストールしました。
[Visual Studio CodeでPlantUMLを使うメモ (Windows編)](https://gist.github.com/yoggy/bd68b3f1f55dbd742bea71424ca66564)


## VSCodeの拡張機能のインストール

VSCodeの拡張機能から以下の拡張機能を導入します。

- PlantUML

    VSCodeでPlantUMLを使ってUMLを書くために用います。

- Markdown Preview Enhanced

    Markdownの文書中にPlantUMLのUMLを埋め込むために用います。
    Qiita Markdown Previewと同時に有効化すると、干渉して正しく動作しないようなので注意。

## VSCode上でのUMLの描画

以下のサンプルコードのプレビューがVSCode上で描画できるか確認します。

個人的に、可視性をPlatUMLの独自記号でなく、`+`や`-`で表したいため、`skinparam classAttributeIconSize 0`を指定しています。

### サンプルコード

```:sample.puml
@startuml
skinparam classAttributeIconSize 0

title サンプルクラス

class Encoder{
    + translate()
}
Interface Reader
Reader <|-- CsvReader
Encoder .> Reader
@enduml
```

### プレビュー

プレビューは`Alt + d`で表示できます。

![sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3359852/b3206733-a5e3-3482-cde8-bd216d144737.png)

プレビューが表示できれば動作確認はOK。
クラス図やシーケンス図を単に画像として出力するだけなら、この構成で実現できます。

`Ctrl + Shift + p`でコマンドパレットを開いて、`PlantUML: Export Current Diagram`を実行すると、画像として出力できます。

## （方法1）外部ファイルとして保存したUMLを読み込む

Markdownの文書中に、別ファイルで保存したUMLを表示できるようにします。

画像化して挿入すると、UMLの更新後に再び画像化しないといけないのが手間なので、PlantUMLで書いたまま挿入できるようにします。

### plantuml.jarのインストール

- plantuml.jarファイルをダウンロードします。

https://plantuml.com/ja/download
からplantuml.jarをダウンロードし、任意の場所に配置します。

（公式ページのはずですが）広告が多いので注意。
私はリンク先からgithubのreleaseページに飛んでダウンロードしました。

- VSCodeの設定

`Ctrl + ,`を押してSettingsを開き、`markdown-preview-enhanced.plantumlJarPath`の項目に、先ほどのplantuml.jarファイルのパスを設定します。
plantumlJarPathで検索すると出てきます。

![plantumljar.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3359852/efb548eb-5e8c-80e1-74f8-5e19284534b5.png)


### 本文中へのUMLの挿入

本文中で`@import`文でpumlファイルを読み込むと、UMLを挿入できます。

```markdown
@import "sample.puml"
```

### （方法2）コードブロックとしてUMLを描く

Markdownの文書中に、直接PlantUMLでUMLを記載します。

コードブロック記法で`plantuml`を指定してUMLを描くと、Markdownの文書内でUMLを挿入できます。

~~~markdown:sample.md
```plantuml
@startuml
skinparam classAttributeIconSize 0

title サンプルクラス

class Encoder{
    + translate()
}
Interface Reader
Reader <|-- CsvReader
Encoder .> Reader
@enduml
```
~~~

## 参考

- [Plantuml を VSCode で利用する](https://qiita.com/AyumuSuzuki/items/22e2d7ddfe5e8c485839)

- [Visual Studio Code + Markdown Preview Enhancedはチームでデファクト化したいMarkdown環境だ！、と思う(2017/10月時点)](https://qiita.com/kitfactory/items/2fde799fa092f0d8f0f1)
集計関数とグループ化とUNION

# はじめに
集計関数とグループ化とUNIONについてのメモ

# 参考
https://www.amazon.co.jp/%E3%82%B9%E3%83%83%E3%82%AD%E3%83%AA%E3%82%8F%E3%81%8B%E3%82%8BSQL%E5%85%A5%E9%96%80-%E7%AC%AC3%E7%89%88-%E3%83%89%E3%83%AA%E3%83%AB256%E5%95%8F%E4%BB%98%E3%81%8D-%E3%82%B9%E3%83%83%E3%82%AD%E3%83%AA%E3%82%8F%E3%81%8B%E3%82%8B%E5%85%A5%E9%96%80%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E4%B8%AD%E5%B1%B1/dp/4295013390/ref=sr_1_1_sspa?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=2PEUM5GO6UZ2C&keywords=sql&qid=1694137676&sprefix=s%2Caps%2C202&sr=8-1-spons&sp_csd=d2lkZ2V0TmFtZT1zcF9hdGY&psc=1

# 集計関数
SUM、MAX、MIN、AVG

## 結果表が凸凹になってはいけない
* 日付は複数の日付で行が出力されるが、金額はSUMされているので、1つの行しか出力されないのでエラーになる
* 集計関数を使うと結果は必ず`1行`になる

```sql
select 日付, SUM(金額) From 家計簿
```

# グループ化
* GROUP BY
* テーブルをグループに分割する
* select項目は定数、集約関数、GROUP BY　で指定した列名しか指定できない

## グループ化して集計する際の順番
```sql
SELECT 項目、集計関数
FROM テーブル
(WHERE 絞り込み条件)
GROUP BY 項目
```
検索(WHEREによる絞り込み) -> グループごとに検索結果を分類 -> 各グループを集計

## 複数の列によるグループ化
GROUP BY A、B

* まずAでグループ化して、Aはグループ化しているので、重複のない一意なものになる。
* このときにBはまだグループ化していないので、重複がある。
* 次に、そのグループ化したものに対して、Bでグループ化する。Bも重複のない結果表になり、AとBで一意な結果になる。
* すなわち、結果セットの中で、同じAとBの組み合わせを持つ行は1つだけになります。

元表
| A | B | 値   |
|---|---|------|
| 1 | 1 | 100  |
| 1 | 1 | 200  |
| 1 | 2 | 50   |
| 2 | 1 | 150  |
| 2 | 2 | 300  |
| 2 | 2 | 300  |


```sql
SELECT A, B, SUM(値) as 合計 FROM テスト GROUP BY A, B
```

結果表
AとBで一意な行だけが残る

| A | B | 合計 |
|---|---|------|
| 1 | 1 | 300  |
| 1 | 2 | 50   |
| 2 | 1 | 150  |
| 2 | 2 | 600  |

# UNION
* SELECT文の結果セットをマージする(和集合)
* 各テーブルは列数とデータ型を一致させないといけない
* UNIONはテーブル同士を縦方向に連結。結合は横方向に連結
* 使いどころ
  - １つのテーブルに格納されたデータを複数の異なる条件で抽出したい場合
  - 異なるテーブルでも、列数とデータ型を一致させていれば、1つのSQLで抽出できる

## UNINONとUNION ALLの違い
`UNION` と `UNION ALL` の違いは、UNION が重複行の除去処理を行う点にあります。この重複行の除去処理がオーバーヘッドとなり得ます。一方、UNION ALL はこの処理を行わないため、原則として性能面で有利です。


## SELECT文をネストする（サブクエリを使用する）場合
SELECT文をネストする（サブクエリを使用する）場合、最上位のSELECT文は通常サブクエリの結果セットをさらにフィルタリングや変換するために使用

```sql
-- サブクエリ内でUNIONを使って結果を結合し、その結果から特定の列を選択してフィルタリングする場合
SELECT SUM(columnA) FROM (
    SELECT column1 AS columnA, column2 AS columnB FROM table1
    UNION
    SELECT columnA, columnB FROM table2
) AS subquery_alias;
```
【PowerShell】テキストを整形して出力する

# はじめに

ある時にPowerShellのスクリプトで処理結果を整形して出力したいと思ったのですが、改行コード（CRLF）を入れてテキストを整形して出力するのが面倒だなと感じました。
その時にふと「そういえばRubyだとヒアドキュメントという書き方があった」ということを思い出し、PowerShellでも同様の方法があるのではないかと調べてみたところ、まさにヒアドキュメントそのものがありました。

そこで今回は、ヒアドキュメントについて調べた結果を記事としてまとめてみました。

# 学習環境

今回はWindows PowerShell ISEを使いました。

# ヒアドキュメントの使い方

## ヒアドキュメントの基本

* Microsoftのドキュメントによると、PowerShellのヒアドキュメントは正式には**「ヒア文字列リテラル」**と呼ぶそうです。
  * [2.3.5.2 文字列リテラル - Microsoft Learn](https://learn.microsoft.com/ja-jp/powershell/scripting/lang-spec/chapter-02?view=powershell-7.3#2352-string-literals)
* ヒアドキュメントは「@"～"@」もしくは「@'～'@」の間に記述します。
* 以下の例では改行コード「\`r\`n」を埋め込む書き方と比較していますが、ヒアドキュメントを用いた方が可読性が良くなっていると思います。

```powershell:ヒアドキュメントの基本的な使い方
# 改行コードを埋め込む書き方
$text1 = "複数行`r`nの`r`nテキスト"

# ヒアドキュメントを用いた書き方
$text2 = @"
複数行
の
テキスト
"@

Write-Host ----------
Write-Host $text1
Write-Host ----------
Write-Host $text2
Write-Host ----------
```

```text:出力結果
----------
複数行
の
テキスト
----------
複数行
の
テキスト
----------
```

## ヒアドキュメント内の式展開

* 式展開を使う場合、ヒアドキュメントは「@"～"@」で囲みます。
  * 「@'～'@」と記述した場合は式展開されないので注意が必要です。
  * 正式には「@"～"@」は「展開可能な文字列リテラル」、「@'～'@」は「逐語的ヒア文字列リテラル」と呼ぶそうです。
* 処理結果のレポートのようにほぼ固定的な文言を出力する場合は、式展開付きのヒアドキュメントを用いると便利だと感じました。

```powershell:ヒアドキュメントの式展開
$today = Get-Date -Format "yyyy/MM/dd"
$pcName = $Env:Computername

$text = @"
$today
このPCは${pcName}です。
"@

Write-Host $text
```

```text:出力結果
2023/09/07
このPCはNKOJIMA-DESKTOPです。
```

# 余談

* Microsoftの公式サイトで「ヒアドキュメント」と検索しても全く記事がヒットしませんでしたが、Microsoftでは正式名が「ヒア文字列リテラル」なので、記事もこの呼び名で統一されているようです。
  * 別名として括弧書きで「ヒアドキュメント」と書いてもらえると、より多くの人が所望の記事を探しやすいと思ったのですが、その辺は色々あって難しいのかもしれませんね...

# 参考URL

* [2.3.5.2 文字列リテラル - Microsoft Learn](https://learn.microsoft.com/ja-jp/powershell/scripting/lang-spec/chapter-02?view=powershell-7.3#2352-string-literals)
* [PowerShellでヒアドキュメントの記述方法](https://win.just4fun.biz/?PowerShell/PowerShell%E3%81%A7%E3%83%92%E3%82%A2%E3%83%89%E3%82%AD%E3%83%A5%E3%83%A1%E3%83%B3%E3%83%88%E3%81%AE%E8%A8%98%E8%BF%B0%E6%96%B9%E6%B3%95)
* [【PowerShell】ローカルのホスト名(コンピューター名)を取得する方法](https://buralog.jp/powershell-get-hostname-or-computername/)