OmniAICreator/Qiita-1.07M huggingface dataset:
【Swift】配列の並び替えをSPY×FAMILYを例にして学ぶ

少しでも楽しいものに置き換えて考えてみよう！ということで、SPY×FAMILYを例にすることにしました。

# 配列を"逆順"に並び替える
配列を逆順に並び替えるときには`reverse()`を使用する。
```swift
var characters: [String] = ["ロイド", "ヨル", "アーニャ", "ボンド", "ダミアン"]
characters.reverse()
print(characters) //["ダミアン", "ボンド", "アーニャ", "ヨル", "ロイド"]
```
配列を逆順に回したいとき`reversed()`を使用する。
```swift
var characters: [String] = ["ロイド", "ヨル", "アーニャ", "ボンド", "ダミアン"]
for characters in characters.reversed() {
    print(characters)
}

//  ダミアン
//  ボンド
//  アーニャ
//  ヨル
//  ロイド
```

# 配列を"昇順"に並び替える
昇順にソートする場合は`sort()`を使用する。
文字列の場合は英語だったらアルファベット順、日本語だったらあいうえお順になります。
```swift
var characters: [String] = ["ロイド", "ヨル", "アーニャ", "ボンド", "ダミアン"]
characters.sort()
print(characters) //["アーニャ", "ダミアン", "ボンド", "ヨル", "ロイド"]

// 数値の場合
var numbers: [Int] = [100, -100, 9, 1, 0, -1, 40]
numbers.sort()
print(numbers) //[-100, -1, 0, 1, 9, 40, 100]
```
# 配列を"降順"に並び替える
降順にソートするときは`sort(by: >)`を使用する。
文字列も数値も昇順の逆になります。
```swift
var characters: [String] = ["ロイド", "ヨル", "ボンド", "ダミアン", "アーニャ"]
characters.sort(by: >)
print(characters) //["ロイド", "ヨル", "ボンド", "ダミアン", "アーニャ"]

# 数値の場合
var numbers: [Int] = [100, -100, 9, 1, 0, -1, 40]
numbers.sort(by: >)
print(numbers) //[100, 40, 9, 1, 0, -1, -100]
```

# 配列を"ランダム"に並び替える
配列をランダムに並び替えるときは`shuffle`を使用する。
```swift
var characters: [String] = ["ロイド", "ヨル", "ボンド", "ダミアン", "アーニャ"]
characters.shuffle()
print(characters) //["ダミアン", "アーニャ", "ボンド", "ロイド", "ヨル"]
```

# 配列の"指定の位置の中身"を交換して並び替える
指定の位置にある要素同士を入れ替える場合は`swapAt(_:_:)`を使用する。
入れ替えたい配列の位置のindex番号を指定する。
```swift
var characters: [String] = ["ロイド", "ヨル", "ボンド", "ダミアン", "アーニャ"]
characters.swapAt(0, 4)
print(characters) //["アーニャ", "ヨル", "ボンド", "ダミアン", "ロイド"]

// 数値の場合
var numbers: [Int] = [1, 2, 3, 4, 5,]
numbers.swapAt(0, 4)
print(numbers) //[5, 2, 3, 4, 1]
```
【Swift】Any型ってなに？

# Any型
Any型とは**任意の型を表す型**のことです。
Any型の**変数や定数にはどんな型の値も代入することができる**ので、代入する値が決まっていない場合に使用する。
```swift:例
let str: Any = "あいうえお"
type(of: str) //String.Type

let int: Any = 12345
type(of: int) //Int.Type
```

# Any型の欠点
Any型は変数や定数に代入すると、元の型の情報が失われてしまう。
Int型では四則演算は可能なるが、Any型ではできない。
```swift:例
let a: Any = 1
let b: Int = 2
a + b // コンパイルエラー
```
なので、可能な限りAny型への代入は避けて、型の情報を保つ方が良い。
現場で活きる！Java Gold SE11 

 
最近、わさびと山椒にはまっているアラサーです:metal_tone1:
今回はSE歴3年目の私が **Java Gold** を取得した経緯と現場で活かせた点について伝えたいと思います。

資格取得は、SE経験年数が浅い人ほど大切だと思っています。
その理由は主に３つ！
:apple:自身が理解できてない範囲を芋づる式に具体的に把握できるから
:apple:実践に必要な知識を体系的に取得できるから
:apple:現場の生産性がぐっと上がるから

これから**Java Gold**の取得を考えている人は、
既にJava Silver を取得しているため、製造の中で進行の妨げになるような困難にぶつかることは少ないと思います。

ただ、バグの少ないシステムを製造するにあたり、**Java Gold**の内容を取得しておくことは
実務で頻繁に利用する機能や技術もあれば、フレームワーク等が代わりにやってくれるために直接利用することがない機能、さらにそれを支える基盤的技術に至るまでの多様な知識を習得することになります。

全てを理解してこその製造であり、
バグのでないプログラムになると思います。
（なんとなく製造している人は、バグの発見に気づくのが遅いです）

これからもJavaを現場で使うならば、
取得しておいて損はない資格です。

私が実際に、現場で活きた**Java Gold**の知識と経験の一部を残します！

***
#### :star: ストリームAPI
　今までコレクションをfor文で行っていた処理をより簡潔かつ正確に処理してくれる強力な概念です。
　これを知っていると知らないとでは、処理の速さが段違いです。
　コーディングのステップ数も少なくて済みます。
　知っておくと自身の武器になる知識です。
　ちょっとでも気になった方はネットでストリームの世界を検索してみてください。

　※ただしこれは、ストリームAPIを実際に先輩SEが使用しているかに左右されます。
　　Java Goldを勉強していない人はストリームAPIを使用しない人が多いです。
　　現場で使われていないコーディングはCDIしにくいので、
　　現場にあったコーディングを第一に心がけた方が無難です。



#### :star: アノテーション
フレームワークを使用していると、メソッド宣言や定数の上に
　　 ``@Entity``
　　 ``@NotNull``
　　 ``@Autowired``
　　とかみたことないですか？
　　これ、なんとなく「自動でクラスをnewしてくれるんだろうな」
　　「nullチェックをしてくれるんだろうな」
　　とか製造しているなかで使い方が分かってきます。
　　でも実際にどういう仕組みでnewされるのかとか、値のチェックするのかとか知っていますか？
　　たまに現場では注釈パラメータを渡すタイプの独自アノテーションを使ってる場合もあります。
　　どうやって独自アノテーションを作るのか、アノテーションが付与されることでその付与されたフィールドがどのような動きをするのか、知っていないと製造できないですよね？
　　「先輩に聞けばいいじゃん」と思うかもしれません。
　　　質問自体は悪ではありませんが、現場によっては毎度質問していてはチームの生産性が下がることもあります。アノテーションの定義の仕方など最低限のことはプログラマーとして押さえておきたいところです:nerd:
　　アノテーションの世界を知っておくと、フレームワークをより効果的に使いこなすことが出来るようになりました。何より、バグの発見がかなり早くなりました。
　　
#### :star: Java SEアプリケーションにおけるセキュアコーディング
　　今まで私はセキュリティについて、恥ずかしながらそこまで深く考えてコーディングしていませんでした。（なぜならば、何をどこで勉強すればよいか分からなかったから...）
　　しかし、Javaのセキュアコーディングの規則を知ることで、今現場が扱っているシステムがどのような防衛策をとっていてコーディングでどこに気を付けなければならないのかが分かるようになります。
　セキュリティは必ず意識しなければなりませんが、今回で現場のシステムでセキュリティ規範に外れそうな部位はリーダーに確認をとる癖がつきました！
　
***

ここまで読んでくださった貴方、
少しでも **Java Gold** の知識に興味をもってくださったら嬉しいです！
先輩に聞く、ネットで調べることも良きことですが、
自分で体系的に理解した上でそれでも分からないことを現場の先輩に聞くことはもっと良きです!!


私のおすすめは黒本です！
<img width="180" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3081837/4b4f4596-8a3a-df62-75ba-a9eb767023a3.png">

資格を取得してもしなくても、手元に置いておきたい一冊です。
解説が深くJavaの歴史的背景も理解しながら新しいJavaの世界が知れる最強の教本なので、読むだけでも今のスキルに貢献してくれるのではと思います:ok_woman_tone1:

最後に....
**Java Gold**は現場で活きます！
学んだことをこれからも現場でアウトプットしていきたいと思います！
【Xcode】アプリをiPhoneにインストールすると"信頼されていないデベロッパ"のダイアログが出る

# 環境
- Mac M1 OS Monterey12.6
- Xcode 14.0.1
- iPhone13Pro iOS 16.1.2


# Xcodeでbuildしたアプリが開けない
buildしたアプリを開こうとすると、下記のようなダイアログが表示されアプリが開けませんでした。
![IMG_5067.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2604036/a7af62a8-96c7-f2a6-cf79-34411269798b.jpeg)

# 解決方法
ダイアログにも記載されているように、端末側で許可する設定が必要になってきます。
端末の`設定`→`一般`→`VPNとデバイス管理`→`デベロッパAPP`の設定を開き、`"Apple Development: デベロッパ名"を信頼`を押下して`信頼`を選択する。
これでアプリを開く許可を端末側で設定することができました。

# 補足
会社ではEnterpriseのデベロッパでアプリを作成しているのですが、同じようにダイアログが出てくるので上記と同じ方法でアプリを開ける許可をして上げることで解決できます。
【Xcode】iOS16以上の端末で、OTA配信しているipaが開けないエラー

# 環境
- Mac M1 OS Monterey12.6
- Xcode 14.0.1
- iPhone13Pro iOS 16.1.2

# OTA配信しているipaが開けない
iOS16の端末でOTA配信しているipaをインストールしたが、`"アプリ名"をインストールできません。あとでやり直してください。`とダイアログが出続けてしまう。
iOS12や13では正常にインストールすることができている。

# 解決までに行ったこと
#### ①最新のXcodeでアーカイブを作成する
筆者はXcode13と14両方使用する機会があったため、案件のアプリによって対応するバージョンが異なっていることを忘れていたので、もう一度アーカイブを作成しました。ただそれでもうまくいかず、、

#### ②manifest.plistをもう一度作成する
原因を考えていると、最近`manifest.plist`のファイルを作り直したらしくそれでOTAを配信行っていました。
なので、Xcode14の方でもう一度作り直してインストールするとダウンロードすることができました。

# 参考
`manifest.plist`の作り方や、内容がよく分かっていませんでしたが、こちらの記事がかなり参考になりました。

https://softmoco.com/devenv/how-to-host-ipa-file-for-ad-hoc-distribution.php
【Xcode】ipaファイルの中身のProvisioning Profileの内容を確認する

# Provisioning Profileにある情報
Provisioning Profileには作成したアプリに対してアプリ開発者が署名するために必要なデータがあります。
- アプリのBundle ID
- 開発に使っている実機デバイスの情報(UDID)
- Macで生成した証明書
- アプリの用途（開発or配布）

こちらのサイトがかなり参考になりました。

https://hirokuma.blog/?p=2783

今回はProvisioning Profileの有効期限を確認したかったので、以下の手順で行いました。
# Finderで拡張子を変更する
- 対象のipaファイルの拡張子を.**ipa**から.**zip**に変更し、解凍してください。
- `Payload`というフォルダが展開され、その中にアプリケーションファイルが入っています。

# アプリファイルの中身を表示
- `Payload`というフォルダが展開され、その中にアプリケーションファイルをそのままだと開けないので、右クリックで**パッケージの内容を表示**を選択してください。
- その中にある`embedded.mobileprovision`があるので、**クイックルック**等で確認しましょう。
【Swift】Quick Help機能を使って変数や定数の型の情報を確認する

# 型の情報をポップアップで確認する
型を知りたい変数や定数にカーソルを合わせてからXcodeのメニューの`Help`→`Show Quick Help for Selected Item`を選択すると、変数や定数の型の情報をポップアップで表示することができる。
ショートカットキーだと`control + command + ?`でも確認ができる。
![スクリーンショット 2022-12-25 18.17.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2604036/1253c14a-c723-df09-8759-1641a18eb067.png)

# 型の情報を右ペインで確認する
Xcodeのメニューの`View`→`Inspectors`→`Show Quick Help Inspector`を選択するとQuick Helpが右ペインに表示され、変数や定数にカーソルを合わせるとその変数や定数の方が表示される。
ショートカットキーだと`option + command + 3`でも確認ができる。
![スクリーンショット 2022-12-25 18.19.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2604036/4e756407-258e-d237-dcf6-bd44b104fcf2.png)
【Docker】Docker Compose をデタッチモード（バックグラウンド実行）で起動する方法

# Dockerのデタッチモードとは
バックグラウンドでdockerのコンテナを立ち上げることです。
デタッチモードでない場合だとコンソール上にコンテナのログが出続け、他のコマンドを打つことができないので、
特にコンテナのログを見る必要がない時は`-d`でデタッチドモードのオプションをつけることで、デタッチモードにすることができます。
```docker
$ docker compose up -d  # デタッチモードで起動
```
# オプションをつけたけどログを確認したくなった時
```docker
$ docker compose logs 
```
# Docker Compose で動作しているコンテナの一覧を確認したい時
```docker
$ docker compose ps # コンテナの一覧をコンソールに表示
```
# デタッチモードで起動したコンテナをすべて停止する
```docker
$ docker compose stop  # コンテナを停止
```
# 停止されたコンテナを起動する
```docker
$ docker compose start  # 停止中のコンテナを起動
```
# コンテナやネットワークをすべて削除する
```docker
$ docker compose down  # 停止ではなくて削除
```
`--volumes`オプションをつけてあげることでボリュームまで削除することができます。
```docker
$ docker compose down --volumes  # ボリュームまで削除
```
【Swift】配列の要素を追加・削除する

# 配列の要素を追加
配列の要素を追加したい場合は`append`を使用する。
```
配列.append(値)
```
引数には追加する値を記述する。
```swift
var characters: [String] = ["ロイド", "ヨル", "アーニャ", "ボンド", "ダミアン"]
print(characters) //["ロイド", "ヨル", "アーニャ", "ボンド", "ダミアン"]

characters.append("ベッキー"); // ここで要素を1つ追加
print(characters) //["ロイド", "ヨル", "アーニャ", "ボンド", "ダミアン", "ベッキー"]
```
+=演算子を使用して配列の要素を1つ追加することも可能。
```swift
var characters: [String] = ["ロイド", "ヨル", "アーニャ", "ボンド", "ダミアン"]
print(characters) //["ロイド", "ヨル", "アーニャ", "ボンド", "ダミアン"]

characters += ["フランキー"]; // +=演算子を使用して要素を1つ追加
print(characters) //["ロイド", "ヨル", "アーニャ", "ボンド", "ダミアン", "フランキー"]
```
追加する場所を指定して要素を追加する場合は`insert`を使用する。
```swift
var numbers: [Int] = [1, 2, 3, 4, 5,]
numbers.insert(100, at: 2)
print(numbers) //[1, 2, 100, 3, 4, 5]
```
# 配列の要素を削除
配列の要素を削除するときは`remove`を使用する。
```swift
var characters: [String] = ["ロイド", "ヨル", "アーニャ", "ボンド", "ダミアン"]
characters.remove(at: 3)
print(characters) //["ロイド", "ヨル", "アーニャ", "ダミアン"]
```
全てを削除する場合は`removeAll()`を使用する。
```swift
var couple: [String] = ["デート", "クリスマス", "プレゼント", "サンタクロース", "トナカイ"]
couple.removeAll()
print(couple) //[]
```
メリークリスマス。
【Swift】配列に重複する要素を追加しないようにする

# Set
配列に重複する要素を追加できないようにするには`Set`を使用する。
```例
var a : Set<要素の型> = [・・・]
```
実際にコードにするとこんな感じ。
```swift
var characters: Set<String> = ["ロイド", "ヨル", "アーニャ", "ボンド", "ダミアン"]

characters.insert("アーニャ") //"アーニャ"を追加
print(characters) 
//["ヨル", "ダミアン", "ロイド", "アーニャ", "ボンド"](重複で無効になるため追加されない)

characters.insert("フランキー") //"フランキー"を追加
print(characters) //["ヨル", "フランキー", "ダミアン", "ロイド", "アーニャ", "ボンド"]

characters.insert("フランキー") //"フランキー"を追加(重複で無効)
print(characters) 
//["ヨル", "フランキー", "ダミアン", "ロイド", "アーニャ", "ボンド"](重複で無効になるため追加されない)
```
# 重複する要素を削除する
配列を`Set(array)`のように、Set型に変換した後に、もう1度`Array(Set(array))`のように、配列に変換する。
```例
var number = Array(Set(number))
```
実際にコードにするとこんな感じ。
```swift
var characters: [String] = ["ロイド", "ヨル", "アーニャ", "ロイド", "ヨル"]

var uniqueCharacters = Array(Set(characters))

print(uniqueCharacters) //["アーニャ", "ヨル", "ロイド"]
```
文字列分かりづらいから数字ですればよかった。。
Webアクセシビリティについて

# はじめに
この記事は[Webの基礎をおさらいカレンダー Advent Calendar 2022](https://qiita.com/advent-calendar/2022/basic_review)です。
このカレンダーでは、なんとなくわかった気になっている、Webの知識をおさらいするカレンダーです。
興味をもし持ってくださった方は、購読いただけると嬉しいです！


## Webアクセシビリティとは
一言で言えば、誰でもがWebコンテンツを使えるようにすることです。
障害者に限った話ではありません。
もちろん、聴覚障害者向けにalt属性を付与するというのもアクセシビリティに配慮していると言えますが、
サイト表示が遅くて画像が表示できない人もalt属性の恩恵を受けます。

Webアクセシビリティに配慮するというのは、
すなわち、どんな人・どんな状況でもWebコンテンツの利便性が高い状態を担保することを意識すること
と言えるかと思います。
イメージとしてはユニバーサルデザインの考え方に近いのではと思います。

一つの基準になるガイドラインとしてはW3Cが定めたWCAGというものがあります。
2022年9月に[WCAG 2.2](https://www.w3.org/TR/WCAG22/0)として最新のガイドラインが規定されています。


### 測定ツール
おおよそのアクセシビリティチェックを行うために、ツールを利用するのが良いです。
chromeの開発者ツールを使えば、Lighthouseという項目から、測定することができます。

![スクリーンショット 2022-12-25 21.23.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224825/27421c24-ffdf-1a7d-22c8-46961a53c6ba.png)

ユーザー補助の箇所をチェックしましょう。
治した方が良いポイントも教えてくれます。

![スクリーンショット 2022-12-25 21.24.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224825/b767ec0c-245b-e598-2575-eeb19d70adbc.png)


# おわりに
以上、Webアクセシビリティについてでした！

[Webの基礎をおさらいカレンダー Advent Calendar 2022](https://qiita.com/advent-calendar/2022/basic_review)でした。
興味をもし持ってくださった方は、購読いただけると嬉しいです！

## 参考文献
[ウェブアクセシビリティ導入ガイドブック](https://www.digital.go.jp/assets/contents/node/basic_page/field_ref_resources/08ed88e1-d622-43cb-900b-84957ab87826/377fe31d/20221212_introduction_to_weba11y.pdf)
【Swift】スコープ(名前の有効範囲)とは

# スコープとは
**変数、定数、関数、型の名前の有効範囲**を表すもの。
スコープその範囲に応じて、グローバルスコープとローカルスコープの２種類に分類することができる。
同じスコープ内には同じ名前を複数存在させることはできず、変数、定数、関数、型が異なっていても名前は一意である必要がある。

# ローカルスコープとは
関数や制御構文によって**局所的に定義されるスコープ**をローカルスコープという。
ローカルスコープで宣言された定数や変数は、定義した関数や制御構文からのみアクセスでき、スコープの外部からは参照することができない。
```swift:例
func sampleFunction() {
    let a = "ドラえもん"
    print(a) // ドラえもん
}

print(a) // コンパイルエラー
sampleFunction() // ドラえもん
```

# グローバルスコープ
どの関数にも型宣言にも含まれない**プログラム全体から参照できるスコープ**をグローバルスコープと言う。
```swift:例
let a = "ドラえもん"
func sampleFunction() {
    print(a) // ドラえもん
}

print(a) // ドラえもん
sampleFunction() // ドラえもん
```

# 注意点
グローバルスコープはどこからでも同じ名前で参照できてしまい、影響範囲が大きく、ローカルスコープで宣言された変数や定数よりも説明的な命名が必要になるので、意味をコメントで残しておくのも良い。
【Xcode】ビルド時にCannot find 'xxxxxx' in scopeとエラーが出た時の解決方法

# 突然ビルドできなくなった
いつも通りgitからpullしてからbuildするとコンパイルエラーが発生した。スコープを確認したが問題もない、、

このエラーは何回か出てきましたが、それぞれ解決方法が異なったので紹介していきます。

# 解決方法① 
#### Xcodeを再起動する
調べてみるとやはり同じエラーで悩んでいる方が多くいました。
意外とこれで治っている方が多いです。
ちなみに`command + q`でタスクキルをしてくれます。

# 解決方法②
#### Clean Build Folderでビルドフォルダのクリーンを行う
自分はよくこれで解決することが多いです。
Productタブから`Clean Build Folder`で実行できます。
ショートカットキーだと`command + shift + K`でも実行することができます。

# 解決方法③
#### Xcodeのバージョンを確認する
自分はXcode13と14両方使っていたのですが、修正でXcode14への対応が行われていたためXcode１３ではビルドができずコンパイルエラーになることがありました。
バージョンはXcodeタブの`About Xcode`を押下で確認できます。

# その他解決方法
エラーが発生した時に参考になったサイトです。
上記以外の解決方法もあるみたいなので、できない場合はこちらを確認してみてください。

https://qiita.com/antk/items/5f7f005d29a7fcaeff3d

http://hogeo.blog.jp/archives/1078092228.html
【Swift】配列の要素の数を取得する

# count
配列の要素の数を取得するには`count`を使用する。
```swift
var characters: [String] = ["ロイド", "ヨル", "アーニャ", "ボンド", "ダミアン"]
print(characters.count) // 5
```
# isEmpty
配列の要素が空(nil)かどうかを判定するには`isEmpty`を使用する。
```swift
var characters: [String] = ["ロイド", "ヨル", "アーニャ", "ボンド", "ダミアン"]
print(characters.isEmpty) // false
```
ちなみにこの記事の投稿日は12/25です。
```swift
let myGirlfriend: [String] = []
print(myGirlfriend.isEmpty) // true
```
メリークリスマス。
【Rsepc】実行時間が長いテストを抽出する

# profileオプション
テストケースごとの実行時間がわかり、時間がかかっているテストを抽出することができる。

`$ bundle exec rspec --profile`で実行時間がかかっているテストケースとその実行時間の上位10個が出力される。
デフォルトで10件表示されるようになっているので、
`$ bundle exec rspec --profile 20`と指定して上げると、上位20個が表示される

# ディレクトリごとに分けて実行するのが良い
すべてのテストコードを実行するのだと、大きなアプリケーションだと時間かかるので、ディレクトリごとに確認した方が良い。
```ruby
ex)
bundle exec rspec --profile 20 spec/controllers/
bundle exec rspec --profile 20 spec/models/

# １つのテストケースの時間も確認できる
ex)
bundle exec rspec --profile 10 spec/models/user/user_spec.rb:40
```
Raspberry PiでGStreamerを使ってUVCカメラの映像をファイル保存

# 1. 概要
Raspberry PiでGStreamerを使ってUVCカメラの映像をファイル保存（簡易録画）

# 2. 機材など
* Raspberri Pi 4B
* OS : Raspberry Pi OS (Bullseye 64bit)
* UVCカメラ

# 3. UVCカメラの映像をファイルとして保存する
## 3.1. YUVをそのまま保存
解像度(1280と720)は、カメラの性能に合わせて変更可能。
フレームレート(10/1)は、カメラの性能に合わせて変更可能。30fpsなら30/1にする。
「timeout 10」は、10秒間したら停止。

```
timeout 10 gst-launch-1.0 v4l2src device=/dev/video0 ! video/x-raw,width=1280,height=720,framerate=10/1 ! \
videoconvert ! filesink location=test.yuv
```

Ctrl+Cで停止させたいときは -e をつける。
```
gst-launch-1.0 -e v4l2src device=/dev/video0 ! video/x-raw,width=1280,height=720,framerate=10/1 ! \
videoconvert ! filesink location=test.yuv
```

※これらのファイルはVLC playerとかでは再生できない。画が壊れているわけではない。YUV専用の再生アプリが必要。

## 3.2. MJPEGをそのまま保存
解像度(640と480)は、カメラの性能に合わせて変更可能。
フレームレート(5/1)は、カメラの性能に合わせて変更可能。30fpsなら30/1にする。
「timeout 10」は、10秒間したら停止。
```
timeout 10 gst-launch-1.0 v4l2src device=/dev/video0 ! "image/jpeg,width=640,height=480,framerate=5/1" ! \
filesink location=test.mjpeg
```

Ctrl+Cで停止させたいときは -e をつける。
```
gst-launch-1.0 -e v4l2src device=/dev/video0 ! "image/jpeg,width=640,height=480,framerate=5/1" ! \
filesink location=test.mjpeg
```
※これらのファイルはVLC playerとかでは再生できない。画が壊れているわけではない。MJPEG用の再生アプリが必要。

## 3.3 YUVを変換してH.264(mp4)として保存
解像度(1280と720)は、カメラの性能に合わせて変更可能。但し, H.264のエンコーダに合わない解像度やフレームレートだと期待する結果にならないことがある。
フレームレート(10/1)は、カメラの性能に合わせて変更可能。30fpsなら30/1にする。
「timeout 10」は、10秒間したら停止。

```
timeout 10 gst-launch-1.0 v4l2src device=/dev/video0 ! video/x-raw,width=1280,height=720,framerate=10/1 ! \
videoconvert ! v4l2h264enc ! 'video/x-h264,level=(string)4' ! h264parse ! mp4mux ! filesink location=test.mp4
```

Ctrl+Cで停止させたいときは -e をつける。
```
gst-launch-1.0 -e v4l2src device=/dev/video0 ! video/x-raw,width=1280,height=720,framerate=10/1 ! \
videoconvert ! v4l2h264enc ! 'video/x-h264,level=(string)4' ! h264parse ! mp4mux ! filesink location=test.mp4
```

## 3.4. MJPEGを変換してH.264(mp4)として保存
分からない。何やっても再生できないファイルができてしまう。
以下はその失敗コマンド

```
gst-launch-1.0 -e v4l2src device=/dev/video0 ! image/jpeg,width=1280,height=720,framerate=10/1 ! \
queue ! jpegparse ! v4l2jpegdec ! v4l2h264enc ! 'video/x-h264,level=(string)4.1' ! h264parse ! \
mp4mux ! filesink location=test.mp4
```

## 3.5. MJPEGを変換してH.264(mkv)として保存
mp4の代わりにmkvのエレメントを使ったら再生できるファイルができた。
どう違うんだ・・・

```
gst-launch-1.0 -e v4l2src device=/dev/video0 ! image/jpeg,width=1280,height=720,framerate=10/1 ! \
queue ! jpegparse ! v4l2jpegdec ! v4l2h264enc ! 'video/x-h264,level=(string)4.1' ! h264parse ! \
matroskamux ! filesink location=test.mkv
```

# 4. 補足
入力元としての解像度やフレームレートを間違うと分かりづらいエラーとなって現れる。使用できる解像度やフレームレートを以下のコマンドで確認した方がよい。
```
v4l2-ctl -d /dev/video0 --list-formats-ext
```


以上
catやlsが存在しないときの暫定方法


# 前提：`cat`や`ls`が使えない環境がある

dockerの一部のコンテナイメージ（k8sのetcdなど）では、`cat`や`ls`と言った基本的なコマンドすら存在しないということが起こりえます。

![スクリーンショット 2022-12-24 23.38.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/778f97eb-82ae-61f5-2b2c-a11a1be0a2ec.png)

**`cat`がない…**

![スクリーンショット 2022-12-25 1.03.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/8042810c-68fe-01fd-d699-42c58c2c745c.png)

**`ls`もない…**

# ないなら作れば良いだけ

`sh`(Bourne shell)が起動しているなら絶対に使える **組み込みコマンド** というものが存在します。
今回は`sh`の組み込みコマンドだけを使用し、`ls`と`cat`を作ります。

### `ls`を作る

まずは`ls`ですが、これは簡単で`echo *`をエイリアスにするだけです。

`alias ls="echo *"`

オプションは何もないですが、とりあえずの確認ならこれで十分です。

![スクリーンショット 2022-12-25 1.01.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/7d9d137e-758e-d84b-e414-00fb6ff5a01e.png)

無事に`ls`でルートディレクトリの配下が見れるようになりました。

なお、出力結果を色つきにした時の記事も[こちら](https://qiita.com/minnsou/items/eb90ec4d56920e16e7c7#21-ls%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89)にあるので、参考にどうぞ。

ディレクトリは青、ファイルが白で表示するlsコマンドを以下に記載しておきます。

```.sh
function ls 
{ 
for i in *
do
  if [ -d $i ]
  then 
    echo -ne "\e[34m$i\e[m\t" # ディレクトリは青色
  else
    echo -ne "$i\t" # それ以外は白色
  fi
done
echo # 改行のためのecho
}
```


### 次は`cat`を作る

こちらは関数を使います。

```
function cat 
{
while read val
do
  echo $val
done
} < $1
```

`val`という変数にファイルの中身を1行ずつ入れて、`echo`で表示するだけです。

これを使えば、ファイルの中身を見ることができます。

![スクリーンショット 2022-12-25 1.13.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395943/f12fbbed-8cf1-1de5-7e92-ed530ff2050e.png)

無事にファイルの中身を見ることができました。

オプションとかは全く再現していない最低限のコマンドの機能ですが、shの標準の機能だけで作ることができました。

### まとめ

`ls`とか`cat`はshの機能だけで再現することが可能です。

なお、[別の記事](https://qiita.com/minnsou/items/eb90ec4d56920e16e7c7)で`ps`コマンドも作っているので、こちらも参考にしてください。
350円で作る簡単リフロー機

秋ロボアドベントカレンダー２２日目です。


# 必要な物
1.直流電源 60w出る電源　私は、24V 10A程度まで可変ででるものを使用。
2.抵抗までケーブル(熱を発生するので半田付けでなく圧着を推奨）
3.基板、IC、クリームハンダ
以下はあれば、便利
温度計
アルミテープ

# 今回のお題の350円の抵抗
秋月で売っているメタルクラッド抵抗　
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31412/f30a5167-bfda-3235-dab5-de837437950f.png)
私は５０Ｗ１Ωを使いましたが
、結局、W数で発熱するのでお好きに選んでください。
# 前準備
基板にクリームハンダ適当に塗る。
![IMG_5037.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31412/b024b863-68f2-0b04-1dc4-d1dc05307bf4.jpeg)
アルミテープを張る（きれいに張っておいた方が良い）<font color="Red">コネクターのショートに注意（アルミは電気を流す）</font>
こんな感じで焼く。
![IMG_5047.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31412/5398ea5d-3d36-ad24-3bb2-34821f8f683e.jpeg)
# 焼く
電源を入れます、私は8V 7Aくらいをかけて焼きました。
焼くのは焼けるか見ていれば良いだけです。
クリームハンダがとければ完成ですので、<font color="Red">電源を切り、即　冷やしましょう。</font>
こんな感じで焼けます。
![IMG_5045.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31412/953390e5-71f4-0e26-a8d8-7bf45d770094.jpeg)

以上
やましょうでした。
RakeでECRにdocker imageをpushする

### 概要

docker imageのbuildからAWS Lambdaへのデプロイまでをrakeで実行できるようにしてみました

### 作成した動機

* lambdaでの動作テストのためにdocker imageのpushとlambdaのデプロイが頻繁に発生しており、いくつかのコマンドを何度も実行する必要があった
* 作成しているアプリケーションはrubyで作成されているため、shell scriptやmakeではなくrubyで完結させたい
* CIでもrakeを用いることでCI側の記述がシンプルになりそうだった

### 実装
```ruby
task default: :docker_build

REGISTORY_URI = 'XXXXXXXXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com'
REPO_NAME = 'ECR REPOSITORY NAME'
IMG_NAME = 'IMG NAME'
TAG_NAME = 'TAG NAME'
FUNCTION_NAME = 'LAMBDA FUNCTION NAME'

task :docker_build do
  sh %(docker build -t #{IMG_NAME} -f ./Dockerfile .)
end

task :aws_login do
  sh %(aws ecr get-login-password | docker login --username AWS --password-stdin #{REGISTORY_URI})
end

task docker_push: %i[docker_build aws_login] do
  sh %(docker tag #{IMG_NAME}:latest #{REGISTORY_URI}/#{REPO_NAME}:#{TAG_NAME})
  sh %(aws ecr batch-delete-image --repository-name #{REPO_NAME} --image-ids imageTag=#{TAG_NAME})
  sh %(docker push #{REGISTORY_URI}/#{REPO_NAME}:#{TAG_NAME})
end

task deploy: :docker_push do
  option = "--function-name=#{FUNCTION_NAME} --image-uri=#{REGISTORY_URI}/#{REPO_NAME}:latest"
  sh %(aws lambda update-function-code --no-publish #{option})
  unless ENV['CI']
    sh %(aws lambda wait function-updated --function-name=#{FUNCTION_NAME})
    puts 'deploy DONE.'
  end
end

task docker_run: :docker_build do
  option = '--rm -it --env-file=./.env --mount type=bind,source=$(pwd),target=/app -p 9000:8080'
  sh %(docker run #{option} #{IMG_NAME})
end

task docker_run_bash: :docker_build do
  option = '--rm -it --env-file=./.env --mount type=bind,source=$(pwd),target=/app --entrypoint "bash"'
  sh %(docker run #{option} #{IMG_NAME})
end
```


### 利用方法
```bash
# docker imageをbuildしたい
$ rake
# もしくは
$ rake docker_build

# deployしたい
rake deploy

# docker imageからインスタンスを作成してbashで操作したい
rake docker_run_bash
```
構造化マークアップについて

# はじめに
この記事は[Webの基礎をおさらいカレンダー Advent Calendar 2022](https://qiita.com/advent-calendar/2022/basic_review)です。
このカレンダーでは、なんとなくわかった気になっている、Webの知識をおさらいするカレンダーです。
興味をもし持ってくださった方は、購読いただけると嬉しいです！

今回は構造化マークアップについて説明します！
## 構造化マークアップとは
Googleのクローラーにコンテンツ内容を適切に理解させるための記述方法のことです。

構造化マークアップを行うことで、下記利点が得られます。
通常のマークアップであれば下記のように表現しますが、
`<p>会社名: hogehoge株式会社</p>`

構造化マークアップでは下記のように表現したりします。

```html
  <p itemscope itemtype="http://schema.org/Corporation">
    <span itemprop="name">株式会社hogehoge</span>
  </p>
```

このように構造化マークアップを行うことで得られる利点は下記です。

* 検索エンジンに認識されやすくなる。
    * コンテンツの意図や文脈を伝えることができるため。
* リッチリザルトの表示がされる場合がある。
    * 通常の検索に、加工された表示が行われる

どのようなリッチリザルトがあるかについては[Google検索セントラル](https://developers.google.com/search/docs/appearance/structured-data/search-gallery?hl=ja)を参照するのが良いです。

### 構造化データの記述方法
Googleでは下記2種類の方法をサポートしています。
* microdata: htmlの中で記述する
    * HTMLコードが複雑化し、メンテナンスコストが増えてしまう可能性が高い
* JSON-LD: scriptタグを用いて記述する
    * Googleはこちらを推奨している

先ほどの例で示したmicrodataでの記載をJSON-LDで記載すると下記のようになる。

```json
<script type="application/ld+json">
{
    "@context" : "https://schema.org",
    "@type" : "Organization",
    "name" : "企業名",
}
</script>
```

構造化データを検証する際は、[Googleが提供しているツール](https://developers.google.com/search/docs/appearance/structured-data?hl=ja)があるので、ぜひ使いましょう。


 
# まとめ
以上、構造化マークアップについての説明でした！

[Webの基礎をおさらいカレンダー Advent Calendar 2022](https://qiita.com/advent-calendar/2022/basic_review)でした。
興味をもし持ってくださった方は、購読いただけると嬉しいです！
WordPressをローカル環境に構築してみた　 ～その2、WordPressをダウンロードしてみた～

引き続き、WordPressをローカル環境に構築していきます。
今回は、WordPressをダウンロードしてみます。


1,WordPressの公式サイトを開きます。

https://ja.wordpress.org/


2,右上の「WordPressを入手」ボタンを押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646863/2e6a0bbd-ae82-4f3c-39ce-cfbdf463d1f5.png)

3,ページ真ん中の「WordPress6.1.1をダウンロード」ボタンを押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646863/c260c70e-1e91-22a8-afb4-6354e9bdea71.png)

4,成功しました。とポッポアップが出てきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646863/2b93c684-8ba9-c4b1-876a-44e861bc7d32.png)

5,WordPressがZIPファイルでダウンロードされるので、解凍してからXAMPPをインストールしたディレクトリ直下の「htdocs」内にコピーします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646863/807c3693-7045-309e-75a6-3a67293a2833.png)


6,解凍されたフォルダの名前は「wordpress」となるのでそのまま使います。
  これで、WordPressの設置は完了です。
Splunk: サポートで必須のファイル、diagファイルをSplunkWebから取得する


###### 実施環境： Splunk Free 8.2.2

 Splunk でサポートにエラー調査等を依頼する場合、ほぼ間違いなく求められるのが diag ( diagnosis の略、日本語だと「診断」)ファイルです。
これは Splunk の設定やログ等、 Splunk で発生した事象を調査するのに使用する様々な情報が含まれたファイルです。
今回はその取得方法について紹介します。

まず、「設定」から「インストルメンテーション」を選択します。

![WS000380.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/4c604516-3435-0185-4d53-0d31452e4aa5.jpeg "設定")

すると次のような画面になるので、「新規 Diag 」を押します。

![WS000381.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/f2e0a91e-31d4-1ed1-2a85-e685321306cf.jpeg "インストルメンテーション")

 Diag ファイルを取得したいサーバを選択し、「次へ」を押します。

![WS000382.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/564add03-6180-a6f0-4f8a-ffccbcd5950f.jpeg "サーバ選択")

必要に応じて出力設定を変更し、「作成」を押します。

![WS000383.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/7078579a-0e4d-e216-0b3f-fddd7518584e.jpeg "出力設定")

 Diag ファイルの作成が開始するので、しばらく待ちましょう。

![WS000384.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/0fd16e2f-6010-c5b9-d3ba-fae894998d58.jpeg "作成中")

ステータスが「成功」になったら、「ダウンロード」を押します。

![WS000385.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/692e3a7f-8a23-5502-2324-1a492e7944a2.jpeg "ダウンロード")

これで、 Diag ファイルのダウンロードは完了です。
あとはこれをサポートに送ったりすることになります。

ちなみに Diag ファイル自体は .tar.gz のファイルです。
解凍ツール等を使用することで、以下のように中身を見ることができます。

![WS000386.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/23a8ce17-c654-17c7-bc06-57fc33033bc1.jpeg "Diagの中身")
javascriptの勉強記録

li要素のテキスト取得
```html
<ul id="list">
  <li>aaa</li>
  <li>bbb</li>
  <li>ccc</li>
</ul>

<script>
  var elem = document.getElementById('list');
  console.log(elem.children.item(1).textContent);
  //bbb
</script>
```

CSSの疑似クラス:nth-child()とquerySelector()で取得する方法
（コメントで教えて頂きました）

```html
<ul id="list">
  <li>aaa</li>
  <li>bbb</li>
  <li>ccc</li>
</ul>

<script>
console.log(document.querySelector('#list li:nth-child(2)').textContent);
// bbb

console.log(list.querySelector('li:nth-child(2)').textContent);
// bbb
</script>
```
[Tabular Editor 2 Docs] 目次

# Tabular Editor 2 Docs

こちらはTabular Editor 2 Docs Advent Calendar 2022への投稿記事です。

https://qiita.com/advent-calendar/2022/tabulareditor2docs2022

2022年11月下旬ごろのDocsを日本語訳しています。
最新情報は公式ページ・公式リポジトリをご確認ください。

https://tabulareditor.com/

https://github.com/TabularEditor/TabularEditorDocs

# 目次

## Introduction

[[Tabular Editor 2 Docs] はじめに - Qiita](https://qiita.com/akihiro_suto/items/d9902e3c5619f930f552)

[[Tabular Editor 2 Docs] Power BI Desktopとの連携 - Qiita](https://qiita.com/akihiro_suto/items/f16888c680ee226d6666)

[[Tabular Editor 2 Docs] テーブルのインポート - Qiita](https://qiita.com/akihiro_suto/items/c4f4c1835306142917cd)

[[Tabular Editor 2 Docs] ビデオチュートリアル - Qiita](https://qiita.com/akihiro_suto/items/fc897fd344a516d4557e)

[[Tabular Editor 2 Docs] よくある質問 - Qiita](https://qiita.com/akihiro_suto/items/430dbbff7bb0b94bbb5c)

[[Tabular Editor 2 Docs] キーボードショートカット - Qiita](https://qiita.com/akihiro_suto/items/364cf368a5202ecfeb37)

## Feature Overview

[[Tabular Editor 2 Docs] 機能概要ベーシック - Qiita](https://qiita.com/akihiro_suto/items/1dad90f9a15e83333ed2)

[[Tabular Editor 2 Docs] 機能概要アドバンス - Qiita](https://qiita.com/akihiro_suto/items/79acabc77c2a23ab8549)

## Advanced Topics

[[Tabular Editor 2 Docs] アドバンスト・スクリプティング - Qiita](https://qiita.com/akihiro_suto/items/249263664f4757afbaa7)

[[Tabular Editor 2 Docs] FormatDaxの非推奨 - Qiita](https://qiita.com/akihiro_suto/items/21ab66ddd41c003568ac)

[[Tabular Editor 2 Docs] 便利なスクリプトスニペット - Qiita](https://qiita.com/akihiro_suto/items/befe9b56335b68b4b7fd)

[[Tabular Editor 2 Docs] カスタムアクション - Qiita](https://qiita.com/akihiro_suto/items/997cc7fc1475ba98d8c1)

[[Tabular Editor 2 Docs] コマンドライン - Qiita](https://qiita.com/akihiro_suto/items/3ffae9c59b7ffbe4adbd)

[[Tabular Editor 2 Docs] ベストプラクティス・アナライザー - Qiita](https://qiita.com/akihiro_suto/items/83e89e935f9b0719f242)

[[Tabular Editor 2 Docs] ベストプラクティス・アナライザー 2.0 - Qiita](https://qiita.com/akihiro_suto/items/d1407730cd85cab29f2b)

[[Tabular Editor 2 Docs] エクスプローラツリーの高度なフィルタリング - Qiita](https://qiita.com/akihiro_suto/items/f74960859ea5bfc052dd)

[[Tabular Editor 2 Docs] マスターモデルパターン - Qiita](https://qiita.com/akihiro_suto/items/47bd3e215cbebed3c7be)

[[Tabular Editor 2 Docs] 増分更新 - Qiita](https://qiita.com/akihiro_suto/items/367eaaab7b1e8200771e)

[[Tabular Editor 2 Docs] Excelからテーブルをインポートする - Qiita](https://qiita.com/akihiro_suto/items/4d199b56e8d0c719771c)

## Other

[[Tabular Editor 2 Docs] TabularEditor.TOMWrapper リファレンス - Qiita](https://qiita.com/akihiro_suto/items/d54e6f035a7e61377578)

[[Tabular Editor 2 Docs] SQL Server 2017への対応 - Qiita](https://qiita.com/akihiro_suto/items/96d6c7acd19fb57f49ef)

[[Tabular Editor 2 Docs] ワークスペース・データベースの紹介 - Qiita](https://qiita.com/akihiro_suto/items/0a6d8b2a2f8579df7e0d)

[[Tabular Editor 2 Docs] DAXロジックを一貫した方法で維持する - Qiita](https://qiita.com/akihiro_suto/items/b1bdd6f0e2dc92897292)

[[Tabular Editor 2 Docs] 今後のロードマップ - Qiita](https://qiita.com/akihiro_suto/items/c3ef50f8424e078a7e29)
【Python】GoogleDriveからダウンロードしたファイルの操作時のエラー対策

## どんなエラー？
GoogleDriveAPIを使用し、何らかのファイルのダウンロード後にosライブラリ等でファイルを移動・削除など行うと…

```エラー
PermissionError: [WinError 32] プロセスはファイルにアクセスできません。別のプロセスが使用中です
```

はい、怒られました。
こんな感じでファイルがどこかで開かれたままになっています。

ちなみにコードは下記の通りです。

```python:example.py
# ↑省略
# ########  Googleの認証 ##############
scope = ['https://www.googleapis.com/auth/drive.file']
        
# ↓ここにはサービスアカウントの鍵のJSONファイルの中身をコピペしてください
credential = {
      "type": "",
      "project_id": "",
      "private_key_id": "",
      "private_key": "-----BEGIN PRIVATE KEY-----",
      "client_email": "",
      "client_id": "",
      "auth_uri": "",
      "token_uri": "",
      "auth_provider_x509_cert_url": "",
      "client_x509_cert_url": ""
}
credentials = ServiceAccountCredentials.from_json_keyfile_dict(credential, scopes=scope)
service = build("drive", "v3", credentials=credentials, cache_discovery=False)

# フォルダ内の全てのファイルを取得
results = service.files().list().execute()  
files = results.get('files', [])

for i, file in enumerate(files):
    # ファイルIDから取得ファイルの指定
    request = service.files().get_media(fileId=file['id'])  
    # ファイル名の取得
    fh = io.FileIO(file['name'], mode='wb')  
    # ダウンロード処理
    downloader = MediaIoBaseDownload(fh, request)
    done = False
    while not done:
        _, done = downloader.next_chunk()

    # ↓の様にファイルに対して何らかの操作をするとエラーが発生する
    os.remove(file['name'])
    

# ↓省略 
```

## 原因・解決策
ダウンロードに使用した「io.FileIO」がファイルを開いたままになっているようです。
「.close()」を使って閉じてあげましょう。

```Python:example.py
    #↑省略

    request = service.files().get_media(fileId=file['id'])  
    # ファイル名の取得
    fh = io.FileIO(file['name'], mode='wb')  
    # ダウンロード処理
    downloader = MediaIoBaseDownload(fh, request)
    done = False
    while not done:
        _, done = downloader.next_chunk()
   
    # ########################
    #   ここで閉じる！！！ 
    fh.close()
    # ########################


    os.remove(file['name'])
    #↓省略
```

これでダウンロード後のエラーが無くなります。

初心者なので、間違えている点や冗長な点がある場合があります。
その時は優しくご指導いただけると嬉しいです(‘ ; A ;`)
Core Web Vitalsについて

# はじめに
この記事は[Webの基礎をおさらいカレンダー Advent Calendar 2022](https://qiita.com/advent-calendar/2022/basic_review)です。
このカレンダーでは、なんとなくわかった気になっている、Webの知識をおさらいするカレンダーです。
興味をもし持ってくださった方は、購読いただけると嬉しいです！

今回の記事では、Core Web Vitalsについて説明します！

## Core Web Vitalsとは
ユーザー体験を優れたものにするためにGoogleが提唱している指標(Web Vitals)の中でも、中心となる3指標のことを指します。
[GoogleのSEOの指標として導入](https://support.google.com/webmasters/thread/107597847/core-web-vitals-page-experience-faq-v2-0?hl=ja)されたことで、対策をするサイトが増えている。

* LCP(Largest Contentful Paint): 最大視覚コンテンツの描画までの時間
* FID(First Input Delay): 初回入力までの遅延時間
* CLS(Cumulative Layout Shift): 累積のレイアウトのずれ

### LCP
簡単に言えば、一番メインとなるコンテンツが表示するまでにどれだけ待たされるか？というのを指標にしています。
2.5秒以内であれば、問題ないとしてGoogleは定めています。

|基準|基準値|
|--- |---|
|良好| 2.5秒未満|
|要改善|4秒以下|
|不良|4秒以上|

### FID
ページに訪れてから、ユーザーが操作を行えるようになるまでの時間です。
重たいサイトだと、アクセスしてから画面が真っ白になる時間があると思いますが、
あの真っ白な画面が終わるまでの時間だと思っても大きな相違はないです。

|基準|基準値|
|--- |---|
|良好| 100ミリ秒未満|
|要改善|300ミリ秒以下|
|不良|300ミリ秒以上|

### CLS
ページを表示した後に、予期しないレイアウトのずれの大きさを計測する指標です。
ページをタップしたときに、コンテンツが後から描画されて別の部分を誤タップしてしまったことはないですか？  
ああいった事象を避けるために、このCLSという基準があります。

|基準|基準値|
|--- |---|
|良好| 0.1未満|
|要改善|0.25以下|
|不良|0.25以上|

### 測り方
[PageSpeed Insights](https://pagespeed.web.dev/)で測るのが手軽でおすすめです。
下記のような形で、問題ないかどうかを測定してくれます。
![スクリーンショット 2022-12-25 20.15.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224825/c6466866-e6c0-0c17-28be-777a138c91c9.png)


 
# まとめ
以上、Core Web Vitalsについての説明でした！

[Webの基礎をおさらいカレンダー Advent Calendar 2022](https://qiita.com/advent-calendar/2022/basic_review)でした。
興味をもし持ってくださった方は、購読いただけると嬉しいです！

## 参考文献
[web.dev](https://web.dev/vitals/)
ABC283回答メモ

0.はじめに
　Cは、初見簡単に解けそうに感じたけど
　意外とてこずりました。

1.A - Power
　A、Bをインプットして問題通りに表示するだけの簡単な問題でした。

　https://atcoder.jp/contests/abc283/submissions/37488139

2.B - First Query Problem
　若干ややこしい感じではありましたが
　Aのリストへクエリーごとに更新＆表示するだけの
　簡単な問題でした。

　https://atcoder.jp/contests/abc283/submissions/37494709

3.C - Cash Register
　これも簡単やな！と思って実装したら
　最後が0の時にWAとなってしまいました。
　油断大敵。

　【考え方】
　　Sを頭から見ていく
　　0以外→変数ansに1加算
　　0の時、ジャッジを次の数字に繰り越し
　　　→0の次が0の時ansに1を加算
　　　→0の次が0以外の時ansに2を加算

　https://atcoder.jp/contests/abc283/submissions/37498322

4. 	D - Scope
　テスト時は試行錯誤したけどTLEを解消できずに時間切れでした。
　
　2022/12/27追記
　その後細かい調整をして提出しなおしACをゲット

　考え方
　　変数
　　　・英小文字のボール状態を保持する辞書dictを定義
　　　　-辞書に存在しない場合は箱にボールが入っていない
　　　　-辞書に存在かつ、値が0の時は箱にボールが入っていない
　　　　-辞書に存在かつ、値が1の時は箱にボールが入っている
　　　・現在何番目の”（）”の中にいるかを表す変数LVを定義
　　　・現在までの”（）”の最大多重度を表す変数MLVを定義
　　　・”（）”の多重度ごとに出現したアルファベットを保持する2次元表Lを定義
　　処理
　　　1)文字列Sを1文字目からチェックしていく
　　　　1-1)S[i]が"("の時
　　　　　1-1-1)LVに1加算
　　　　　1-1-2)LV>MLVの時
　　　　　　1-1-2-1)MLVにLVをセット
　　　　　　1-1-2-1)Lに空配列を追加
　　　　1-2)S[i]が")"の時
　　　　　1-2-1)L[LV]配列内のすべてのアルファベットについてdictの値を0にする
　　　　　1-2-2)L[LV]配列を空にする
　　　　　1-2-2)LVを1減算
　　　　1-3)S[i]が"("でも")"でもない時(アルファベットの時)
　　　　　1-3-1)S[i]が辞書に存在し、かつ値が1の時
　　　　　　1-3-1-1)気絶条件を満たすので、”No”を出力しPG終了
　　　　　1-3-2)L[LV]にS[i]を追加
　　　　　1-3-3)dict[S[i]]に1をセット
　　　2)気絶せずに文字列Sのチェックが終わったら、”Yes”を表示
　　NGだった考え方１と大して変わらない気もしましたが、
　　”変数preから当該アドレスまでの文字について辞書の値を0にする”
　　の部分をさかのぼってチェックして消すのと配列に持っておいて消すので
　　だいぶ処理回数に差が出るのだなぁと思いました。

　　あとは、試験時にうまくいかなかったのが、配列内に配列を追加の部分が
　　MAXの場合新規配列を追加というロジックが入っていなかったからでした。
　　他にも応用が利きそうなので覚えておかないと。

　https://atcoder.jp/contests/abc283/submissions/37577568

---
　NGだった時のメモ
　考え方１
　　文字列Sを頭からチェック
　　　→"("の時
　　　　アドレスを変数preに保存
　　　→")"の時
　　　　変数preから当該アドレスまでの文字について
　　　　辞書の値を0にする
　　　→上記以外
　　　　当該文字が辞書にあるかをチェック
　　　　　→あった場合、値をチェック
　　　　　　→値が1の時”No”表示
　　　　　　　PG終了
　　　　上記以外
　　　　　→辞書の当該文字の値に1をセット
　最後までチェックが終わったら”Yes”を表示

　余裕でTLEな上に、おそらく、(a(bc)a)みたいなときにエラーを判断できなさそう。

　考え方２
　　”（”毎にレベル分けし、レベル毎に文字を配列に格納
　　”）”がきたら当該レベルの配列はクリアし1レベルを下に戻す
　　的な感じで実装。
　　→2次元配列の存在チェックがうまくいかずに終了。
　　そして、それでもTLE

　その後回答を見たら、考え方は間違ってなさそうなのですが
　ちょっと実装がうまくいってなさそうなので
　時間が出来たら見直してみよう・・・。

　以上。
JetpackComposeシンプルなSliderの実装方法

今年JetpackComposeを少しづつ勉強していきました。今回もシンプルですがSliderの実装をしてみようと思います。


# リファレンス

https://developer.android.com/reference/kotlin/androidx/compose/material/package-summary#Slider(kotlin.Float,kotlin.Function1,androidx.compose.ui.Modifier,kotlin.Boolean,kotlin.ranges.ClosedFloatingPointRange,kotlin.Int,kotlin.Function0,androidx.compose.foundation.interaction.MutableInteractionSource,androidx.compose.material.SliderColors)

# 実装方法

```SliderSample.kt
@Composable
fun SliderSample() {
    var sliderPosition by remember { mutableStateOf(0f) }
    Text(text = sliderPosition.toString())
    Slider(
        value = sliderPosition,
        onValueChange = { sliderPosition = it },
        modifier = Modifier.padding(40.dp),
        onValueChangeFinished = {
            //スライダーの値が変更（指を離したタイミング）になったときにしたい処理を実装する。
        },
        steps = 9,
        colors = SliderDefaults.colors(
            thumbColor = Color.Blue,
            activeTrackColor = Color.Green
        )
    )
}
```

![Screenshot_20221225_200218.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274615/d389b2c3-2c6d-6260-8dcc-07eed5d4a1b9.png)

`remember`については説明しませんが、値はsliderPositionに保持されてます。
`value`で初期値を設定します。
`steps`メモリの表示個数を指定します。
`colors`SliderDefaultsを作成し、`thumbColor`ボタンの色`activeTrackColor`線の色を指定できます。


普段使用しているものがJetpackComposeだと、どういう実装になるのか試しておくのはよさそうですね。
以上です。
JavaエンジニアがRubyを使ってみて思ったこと

# 前説
- 株式会社SUPER STUDIOの2022年Adventarの記事です。
- 7年ぐらいJava(Spring)を使っていたエンジニアが初めてRuby(Rails)を使ってみた所感のまとめです。
- JavaもRubyもどちらもまだまだ未熟者が書いた記事です。
- Javaの最新のバージョンもキャッチアップできてないのでちょっと知識が古いです。
- Javaの方がいいとか、Rubyの方がいいとか、対立煽りを助長するつもりはありません。
- 自分と同じでJavaばかり使ってきて、Rubyとかどんな感じなんかなあって思ってる人に読んでもらえたら幸いです。

# Ruby(Rails)を使い始めて思ったことまとめ
- 型宣言が必要ない
- メソッドの引数にデフォルト値を設定できる
- メソッドの戻り値の型の定義が必要ない
- 最終行の結果がreturnされる
- 後置ifが使える
- if文の戻り値が設定できる
- ActiveRecordが便利

1個ずつ見ていきます。

## 型宣言が必要ない
これは解説不要かと思いますが、Rubyは動的型付け言語ですので、Javaのような静的型付け言語と違い型宣言が必要ありません。

```Java
// Javaの場合
Integer count = 0;
String text = "";
int i = 1;
TestClass testClass = new TestClass();
```

```Ruby
# Rubyの場合
count = 0
text = ''
i = 1
test_class = TestClass.new
```
のような感じ。
メソッドの戻り値を変数に代入する場合も、Javaの場合は変数の型と戻り値の型が一致している必要がありますが、
Rubyの場合はそれも不要です。
個人的にはこの変数今何入ってるんだっけ？ってなることもありますが、命名とか気をつければ問題ない範疇かなと思いました。

## メソッドの引数にデフォルト値を設定できる
個人的にこれが一番Rubyやってて有用かなと思いました。
開発してて、色んな所から呼び出されているメソッドがあって、そのメソッドに特定の条件のときだけ処理を変えたい、もしくは処理を加えたい、ってことがあると思うんですが（ありますよね？）、
そういうときにメソッド引数に変数を追加して制御しようとしたとき（もっと良い解決策があるかは置いておいて）、
Javaだと呼び出し箇所に引数を追加する必要がある（もしくは他の呼び出し箇所に影響が無いよう別メソッドを定義するなど）のですが、
Rubyの場合はデフォルト値を定義できるので、他の呼び出し箇所に影響を与えることなく引数の追加ができます。
Javaの場合は、

```Java
// 修正前のメソッド
public void example(String hoge) {
  // 何かしらの処理
}
```
上記のようなメソッドがあって
```Java
// 修正後のメソッド
public void example(String hoge, Boolean flag) {
  if (flag) {
    // flag == trueのときだけ実行される処理
  }
  // 何かしらの処理
}
```
このような修正をした場合、メソッドの呼び出し箇所全てに影響があります。
（そもそも設計が〜、とかそういう話は一旦なしでお願いいたします。）

Rubyの場合は、
```Ruby
# 修正前のメソッド
def example(hoge)
  # 何かしらの処理
end
```
上記メソッドに同じようにflagを追加する場合
```Ruby
# 修正前のメソッド
def example(hoge, flag = false)
  if flag
    # flag == trueのときだけ実行される処理
  end
  # 何かしらの処理
end
```
このようにデフォルト値を設定することで、他の呼び出し箇所には影響なく引数の追加ができます。

## メソッドの戻り値の型の定義が必要ない
先程の「メソッドの引数にデフォルト値を設定できる」の項でメソッドの定義のイメージを書きましたが、
動的型付け言語なのでRubyではメソッドの戻り値の型を定義する必要がありません。
Javaの場合は戻り値がない場合はvoid、ある場合はその型を定義する必要があるので、
これはめちゃめちゃ便利だなあと思いました。

## 最終行の結果がreturnされる
Javaの場合は
```Java
public int calc(int a, int b) {
  return a + b;
}
```
のように明示的にreturnが必要ですが、Rubyの場合は
```Ruby
def calc(a, b)
  a + b
end
```
このようにメソッドの最終行がreturnされるので、単純に最終行の結果をreturnしたい場合はreturnが不要です。
もちろんメソッド途中の分岐で明示的にreturnすることも可能です。
これに関しては好みが分かれると言うか、場合によっては予期せぬ値が返ることもあるので、ちょっと注意が必要な印象です。

## 後置ifが使える
Rubyは後置ifが使えます。Javaエンジニアの方には馴染みがないかも知れませんが、
ifの条件を満たしたときのみその行が実行される、みたいなイメージです。
特定に条件を満たしたときだけメソッドを呼び出すような処理の場合、
```Ruby
# 普通のif文
if flag
  hoge.fuga
end

# 後置ifの場合
hoge.fuga if flag
```
のように書くことが出来ます。
1行でスッキリ書けるのでメソッドの見通しが良くなる反面、多用し過ぎは注意が必要かも知れません。
（余談ですが、ifに対してunlessというfalseの場合に実行される制御文もあります。）

## if文の戻り値が設定できる
これは三項演算子みたいなもので
```Ruby
hoge = if flag
         'hoge'
       else
         'fuga'
       end
```
みたいにif~elseブロックの最終結果を戻り値として変数に設定できます。
三項演算子だと行が長くなりすぎたり、ちょっと複雑な処理をする場合に使えるかも知れません。

## ActiveRecordが便利
こちらはRailsの機能になりますが、めちゃめちゃ便利で簡単なCRUD操作するアプリを作るなら、取り敢えずRailsで作ろうかなと思うくらい便利でした。（他の言語やフレームワークへの見識が浅いだけかもですが）
詳細は省きます。

## Rails Consoleも便利
こちらもRailsの機能ですが、ちょっとした実行結果を得たりするのにめちゃめちゃ便利です。
詳細は省きます。

# まとめ
他にも色々Ruby使ってみて思ったことはありますし、今でも結構戸惑うことは多いのですが、今まで業務でJavaしか使ってこなかったので、今回めちゃめちゃ見識が広がった気がします。この記事を書いていて、そういえばRubyの場合はここはどうなるんだっけ？とかRailsのもっと深い部分まで理解できていない事がわかったので、今後はそういったところも勉強していきたいです。
アドベントカレンダーも毎日できない…おしまいだと思わないための計画性の重要性

# 来年アドベントカレンダーを走りたい人に向けてのアドバイス。

https://twitter.com/yuria_cats/status/1604711656155938816?s=20&t=S9z10iMe6lu2mAhEkK-QjA

とのことです。
強いて言うならば、

- 10月から3か月かける仕事としてJilaなどで管理すればかなり現実的なラインで安定的にアドベントカレンダーを走ることが可能である（2か月だと厳しい）
- 一人アドベントカレンダーは本当に準備が99％なのでネタを25個ひねり出せない人は来年に向けて精進しよう。
- 12月はアドベントカレンダーを書く期間ではなく「**アドベントカレンダーをマーケティングしたり人のアドベントカレンダーを読む期間である。**」これを1月から毎日音読して来年のカレンダーに臨もうな
- あと、ほかのカレンダーの参加でViewを稼ぎにくくなっているためQiitaのハートが好きな人は自分でマーケティングすることを忘れないようにしましょう！

---

ここからは筆者個人のつらつらとした懺悔になります。


# 今回かけなかったけどお蔵入りした記事のネタ
- Dockerについてまとめてみた
Dokerについてまとめたかったが、コンテナ・Dockerの解像度の違いについて人に説明できるくらいに落とし込むことができなかった。3月までには出したい。
- Reactについて説明してみた
気が付いたらjQueryの記事になっていた。Reactのメリットやパラダイムについて自分の言葉で説明・説得するという経験は一度やってみたいと考えている。

深堀するうえでEnglishの壁を強く感じることが多く来年上半期は英語を0からやり直そうと思っております[^1]

# アドベントカレンダー駆動開発のすすめ
今年アドベントカレンダーを通して
「Rust」「finch」といった技術に新しく触れることができ「Github」「remark」については改めてしっかり触れることができて楽しかったと同時に学びが大きかったなと思っております。既存の技術をドキュメントベースで再確認する機会は案外少ないためその点の整理としてのアドベントカレンダー駆動開発・アドベントカレンダー駆動学習というのは学習効果も高いのではないかなと思っております。


# 今年の懺悔

やはり、毎日投稿するというアドベントカレンダーらしい投稿形態をとれなかったことに今年はとても悔いがあります。またポエムが多くなってしまったことに。
今年は計画時点で分かっていたことではあったのですが、説明できるだけの技術への深い理解ができていないなということを強く感じた12月となってしまいました。
その反面で、アドベントカレンダーを通して曲がりなりにも1つのことをやり抜くという達成感と技術に面白いと思うめり込み具合を発見できたりして理解が深まったアドベントカレンダーでもあったなと思っています。アドベントカレンダー完走賞がなければここまで走り抜けることはできませんでした。Qiitaさん本当にアドベントカレンダーイベントをしてくださりありがとうございます！来年も楽しみにしています！

# 来年の一人アドベントカレンダーに向けての抱負

来年は1つのテーマでアドベントカレンダーを書けたらと思っております。フロントエンドかコンテナ技術を極めていけたらなという一つの1年の集大成を築いていきたいですね。

[^1]: 余談ですが筆者は、意気揚々と高校生向けの文法本と初心者向けの赤い単語帳を買ったところ本棚を見た父親に鼻で笑われました。学生のうちに勉強しておけば鼻で笑われずに済むので**英語は今のうちに勉強しておきましょう**。社会人は鼻で笑われるのを糧に頑張って英語を読めるようになりましょう。
【Linux】$*と$@の違い

## `$*`と`$@`の違い

クォートしない場合には`$*`と`$@`は同じ挙動になります。  

```test.sh
outputarg() {
  echo "引数の数は $# 個です。"
  echo "第一引数は $1 です。"
  echo "第二引数は ${2:-なし} です。"
}

echo 'クォートなし'
echo '$@'
outputarg $@
echo '--------------------------'
echo '$*'
outputarg $*

```

```terminal
$ bash test.sh 'arg1 arg2' 'arg3 arg4'
$@
引数の数は 4 個です。
第一引数は arg1 です。
第二引数は arg2 です。
--------------------------
$*
引数の数は 4 個です。
第一引数は arg1 です。
第二引数は arg2 です。
```

## `"$*"`と`"$@"`の違い

クォートした場合には`"$*"`は引数が結合され、`"$@"`は引数が渡したとおりに分割されます。

```test.sh
outputarg() {
  echo "引数の数は $# 個です。"
  echo "第一引数は $1 です。"
  echo "第二引数は ${2:-なし} です。"
}

echo '"$@"'
outputarg "$@"
echo '--------------------------'
echo '"$*"'
outputarg "$*"

```

```terminal
$ bash test.sh 'arg1 arg2' 'arg3 arg4'
"$@"
引数の数は 2 個です。
第一引数は arg1 arg2 です。
第二引数は arg3 arg4 です。
--------------------------
"$*"
引数の数は 1 個です。
第一引数は arg1 arg2 arg3 arg4 です。
第二引数は なし です。

```
プログラミング初心者はまず「質問する場」を探そう

一応[LIFULLアドベントカレンダー](https://qiita.com/advent-calendar/2022/lifull)の中にありますが、ほぼプライベートの話です…ｗ

この間、知り合いが次のような「何を調べればいいかわからない」という状況をSNSでコメントしていました。これは、私自身でも、特に初心者の間や、慣れない分野で実装しているときに陥る症状でした。他の人もそうなんじゃないかと思います。

> 〇〇を実装したいとき、どういう設計をするのがいいんだろう。こういう話題は検索できないので、何を手がかりにすればいいかわからない

私がプログラミングを始めたのは大学の研究室で、大学の研究室で先輩が急に「**C言語で数値計算してgnuplotで描画するより、PythonでやるほうがCOOLらしいぜ！**」っていう謎の布教を受けて、いろいろ本を買ったりして一緒に学んでたのがきっかけです。ただ情報科学ではないため、一般的な用語もあまり知らずに就職後にもいろいろ苦労しました。

この状態に陥ったとき、「自分でいい方法を検索する or 考える」ことの他に、今の私なら当時の私（や知り合い）に「**自分が学びたい分野について、質問する場を探そう！**」ということをおすすめします。これはもしかすると何かを独学するときには広く適用できることかもしれません。

## 質問する場の探し方

気軽に質問したいなら、WEB上の質問サイトを使うといいでしょう。もし迷うなら「自分が学びたい分野が一番盛り上がってるとこ」にするといいと思います。

* [質問 - Qiita](https://qiita.com/question-trend)
* [Stack Overflow日本語版](https://ja.stackoverflow.com/)（[英語版](https://stackoverflow.com/)）
* [teratrail](https://teratail.com/)

もう少し深く学びたいなら、プログラミング言語やフレームワークのコミュニティを探すと良いでしょう。

* [Start Python Club](https://startpython.connpass.com/): （けっこう前の話ですが）発表も面白くて親切にしていただいた記憶があります

また、コミュニティによっては、SlackやDiscordなどで質問を受け付けてるところがあります。

## 質問するとき気をつけること

エリック・レイモンドの「[賢い質問のしかた](https://www.ranvis.com/articles/smart-questions.ja.html)」を読もう！…と言いたいのですが、別にハッカー（※超すごいプログラマーの意味）になりたいわけでもないと、この長文に気後れすると思います。

「[新卒1年目に使ったエンジニア質問テンプレート](https://qiita.com/KNR109/items/550b52ff980c0c32bf2a)」をまず参考にすると良いです。

> (1) 実現したいこと
> (2) 実現するために自分が試した内容とその結果
> (3) 調べた内容や資料
> (4) 原因だと思われそうな箇所


このテンプレートはエラーのデバッグの質問なので、最初に挙げた設計の話では違うかもしれません（具体的に言うと(4)はいらないかも）。それでも、多分上記のサイトで、

* 自分の書いた〇〇のコードに重複が多いように感じていて、もっといい設計があるんじゃないかと思っている
* 具体的なコードの例
* Webサイトで検索して、これらのサイトまでは見つけたが、いい方法が思いつかない

みたいなことを聞けば、解決に一気に近づくし、今後の同様な問題のときに、どんなワードで検索すればいいかわかるようになると思います。


## 最後に

プログラミングやエンジニアリングはけっこう楽しいので、うまく活用して楽しんでください。

弊社（LIFULL）の人間へ: GitHub Discussionsの「[エンジニアいつでも相談](https://www.lifull.blog/entry/2022/02/24/100000)」をご活用して頂ければ、弊社の教えたがりのエンジニア達が熱心に**クソ長文**の回答を送ってくれることでしょう。

（追記）
つらいときはNeko Hackerのこの曲を聞いてがんばりましょう[^1]。

https://www.youtube.com/watch?v=0uLwC9uuT6k

> Thank you Qiita, teratail, stack overflow
> Thank you Qiita, teratail, stack overflow

[^1]: 素晴らしい歌詞ですが、現代のソフトウェアエンジニアなら大抵ソースコードをgit管理していて、大事そうなやつ間違って消しちゃった後の実際の行動は「`git rebase`しようとしてコミットログをぶっ壊し、更に別の問題（コミットログ復旧）にぶち当たる」じゃないかと思ってしまいます。その点だけ残念です。あと結婚おめでとうございます
複数メソッドの一つ目しか発火しなかった件 jQuery

# 【同じセレクタ】なぜか最初に書いたメソッドしか発火しなかった
同じ要素内にあるテキストと画像をjQueryで変更するメソッドを書いたが、なぜか最初に書いたテキスト変更のメソッドしか発火しなかった。

```html:HTML
<div id="id">
     テキスト変更前
     <img src="image1.png" alt="">
</div>
```

```html:jQuery
<script>
$("#id").text('テキスト変更後');
$("#id").children('img').attr('src','image2.png');
</script>
```


## 修正：正常に動いたコード

```html:HTML
<div id="id">
    <p>テキスト変更前</p>
    <img src="image1.png" alt="">
</div>
```

```html:jQuery
<script>
$("#id").children('p').text('テキスト変更後');
$("#id").children('img').attr('src','image2.png');
</script>
```
## 原因
#idの要素が全て「テキスト変更後」に上書きされ、imgタグが消滅した模様。
テキストもpタグで囲み、pタグ部分のテキストを変更するようにjQueryで指定したら解決した。
C++でコンパイル時にクリスマスツリーを出力してみた

今日は**クリスマス**ですね！
クリスマスにすることといえば……、

そう、<font color="red">**コンパイル時処理**</font>ですね！！

というわけで、**コンパイル時にクリスマスツリー**を出力します！

# コンパイル時出力

少し前にコンパイル時出力についての記事を書きました。

https://qiita.com/Raclamusi/items/418d08f8e64fa1959850

この記事では文字列を出力しましたが、今回出力したいのはクリスマスツリー、つまり**画像**です。
小さい画像の出力であれば、コンパイル時文字列出力のコードを少しいじるだけで実現できます。

## エスケープシーケンス

例によって[**エスケープシーケンス**](https://en.wikipedia.org/wiki/ANSI_escape_code)を利用します。
GCC の `static_assert` がエスケープシーケンスを出力できることを利用するため、実行環境は GCC に限定されます。

今回利用するエスケープシーケンスはこちらです。

|エスケープシーケンス|効果|
|:-:|:--|
|<code>\x1b[<b><i>n</i></b>;<b><i>m</i></b>H</code>|カーソルを上から <b><i>n</i></b> 行目、左から <b><i>m</i></b> 行目に移動（絶対座標指定）|
|<code>\x1b[48;5;<b><i>n</i></b>m</code>|背景色を事前定義された256色の <b><i>n</i></b> 番目の色に変更|
|<code>\x1b[m</code>|文字スタイルをリセット|
|<code>\x1b[J</code>|カーソルより後ろをすべて削除|

コンパイル時文字列出力では相対座標指定でカーソルを動かしていたので、エラーメッセージの行数によって移動する行数を変えなければならず大変でした。
今回出力するのは画像であり、**出力する位置が事前に決まっている**ので、カーソルの移動を絶対座標で指定します。

画素の出力は、エスケープシーケンスで背景色を変更してスペースを出力することで実現します。
あとは画素の各出力位置について「**全部書く！**」をするだけです。

# コンパイル時乱数

ただクリスマスツリーを出力するだけというのも面白くないので、**コンパイルするたびにオーナメントの位置や色が変わる**ようにします。

乱数生成は適当に Xorshift で実装するとして、問題となるのは**シード値（初期値）の決定**です。

ここで、 C 言語で乱数のシード値を設定するときにどんなことをしているかを思い出してみましょう。
おそらく、 `srand(time(NULL))` などのように、**時刻**をシード値として利用しているのではないでしょうか。

コンパイル時乱数でもこれと同じことをすればよいのです。
そう、**コンパイル時刻**をシード値として利用します。

コンパイル時刻は `__TIME__` マクロで取得できます。
これだけでは別の日の同じ時刻にコンパイルした際に同じ結果が出るので、 `__DATE__` マクロで取得したコンパイル日の情報も利用します。

マクロから取得した値は文字列なので、適当にハッシュでも使って数値に変換します。
と思ったらなぜか標準の `std::hash<T>::operator()` がなぜか constexpr ではなかったので、 [MSVC STL](https://github.com/microsoft/STL/blob/main/stl/inc/type_traits#L2125-L2143) を参考に自分で constexpr なハッシュ関数を実装します。

```c++:コンパイル時乱数
constexpr std::uint64_t constexpr_hash(std::string_view s) {
    std::uint64_t value = 14695981039346656037ULL;
    for (auto&& c : s) {
        value ^= static_cast<std::uint64_t>(c);
        value *= 1099511628211ULL;
    }
    return value;
}

class constexpr_random {
public:
    constexpr constexpr_random()
        : state{ constexpr_hash(std::string_view{ __DATE__ " " __TIME__ }) } {}

    constexpr constexpr_random(std::uint64_t seed)
        : state{ seed } {}

    constexpr std::uint64_t operator()() noexcept {
        state ^= state << 3;
        state ^= state >> 35;
        state ^= state << 14;
        return state;
    }

private:
    std::uint64_t state;
};
```

# コンパイル時クリスマスツリー

出来上がったものがこちらになります。

今回も例によって「全部書く！」をしているので、コードは GitHub Gist に置いておきます。

GitHub Gist: https://gist.github.com/Raclamusi/902cd6cd2065b9e35f85fcfe841da3e5

```shell-session
$ g++ -std=c++20 constexpr_xmas_tree.cpp
```

![result.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643544/be051546-c566-e56b-d247-2c4354f7d73b.gif)

（オーナメントが点滅して見えるのは動画を GIF に変換する際に発生したもので、なんかきれいな感じになっていますが仕込んだわけではありません。）

# 余談

上の実行結果の動画を Twitter に投稿したら、アカウントをロックされました。
なんで？

# 余談2

`#embed` が入ったら /dev/random から乱数を取ってこれたりするんでしょうか？