OmniAICreator/Qiita-1.07M huggingface dataset:
ブラウザでPDFダウンロードが失敗する原因は、Chromiumの仕様だった

# 背景
ChromeやEdgeブラウザでいくつかのサイトを利用している際、PDFのダウンロードボタンをクリック時のエラーとなる事象に遭遇した。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124955/3179b660-1363-ef4f-8b9a-51990bc25a20.png)

↓日本語設定だと”インターネット接続をご確認ください”と表示されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124955/9d3bd116-6b34-fd65-18ec-021e805a7618.png)

Chromeのdevtoolでダウンロードボタン押下後の通信について、PDFダウンロードが成功するサイト、失敗するサイトの比較してみましたが、いずれも外部通信がボタン押下をトリガーとして実施されていなかったため、ブラウザの内部的な原因を疑い、[Chromium Issue Tracker](https://crbug.com/)にissue登録をしてみた。

# 結論
私が切ったissueはこれ。
https://issues.chromium.org/issues/336965824

コメントの中で教えてもらったものは↓これ。
https://issues.chromium.org/issues/40293042

結論、本事象はChromiumの既知のissueでした。（10年前からのまだ検討中の様です。）

そのため、現時点での対応は下記ワークアラウンドを選択し、ブラウザ側で実施いただくorWEBサーバ管理側にcash設定を見直してもらう。となる。

# 本事象の再現条件

## ブラウザの設定
ブラウザのPDFドキュメントデフォルトの動作がPDFビュワーで表示する設定になっている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124955/63e35d17-0aae-118a-b5c7-67141fcabc1e.png)

日本語設定だと、”ChroniumuでPDFを開く"となっているラジオボタンが選択されている状態。

## WEBサーバ側の設定
PDFデータを返却するHTTPレスポンスヘッダにおいて、
* Cache-Control: no-store
* Content-Disposition: inline
が返却されていること。

https://issues.chromium.org/issues/336965824
私が上記issueに添付した、sample.zipで本事象が再現できる環境を用意しました。
Dockerさえあれば、ローカルで動作すると思うので、この記事の読者の方で自分がはまっている状態と一致しているかは確認いただけると思います。

# 原因
以下の2つの仕様によりダウンロードが失敗している。

* PDFビュワーのダウンロードボタン押下時は、ブラウザ内部で保有しているキャッシュをソースとして、ユーザ所定のローカルディレクトリへPDFファイルをエクスポートすることでダウンロードを実現している
* WEBサーバ側からは、no-store(一切の保存を許さない)設定でPDFファイルがブラウザに到達しているため、PDFビュワーに表示後、キャッシュを破棄している

これら2点により、ダウンロード時に参照すべきキャッシュが存在しないため、エラーが発生している。

# ワークアラウンドについて
## ブラウザ側
* PDFビュワーのダウンロードボタンではなく、印刷ボタンでPDF保存を選択する
* ブラウザの設定をPDFダウンロードする設定に変える

## WEBサーバ側
* Cache-Controlヘッダを`no-store`から`no-cache` 等に変更する※
[MDN Cache-Control](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Cache-Control)

※ WEBサーバ側の変更の際は、キャッシュへの影響があるので、影響確認を実施した後に変更することを推奨いたします

# Chromium側の対応方針について

https://issues.chromium.org/issues/40293042
上記のコメントを追っていくと、2012年から議論されているが
* ダウンロードボタン押下した際に、再度通信を行う
* 一時的にキャッシュを行う
の2案があるように見える。

私としては、とりあえず、ネットワークエラーと表示される点の是正や、
ダウンロードボタン自体押下できないようにグレーアウトするなどのをしたらどうか？と下記コメントを自分のissueに残してみたが、今日時点で反応はない。（自分でコード書ければいいのだがスキル不足）

https://issues.chromium.org/issues/336965824#comment18

# まとめ

Chromiumのissueを自分で初めて起票したけど、みんな優しく教えていただき感謝。
Dockerで再現環境も作成し提示できたのは議論を加速することができたと感じている。
[MuleSoft]自己署名証明書One-Way TLSを設定する方法

MuleSoftで自己署名証明書One-Way TLS（Transport Layer Security）を設定する方法について説明します。

## One-Way TLSとは

One-Way TLSは、クライアントとサーバー間の通信を暗号化し、サーバーの正当性をクライアントに証明するためのセキュリティプロトコルです。クライアントがサーバーの証明書を検証するだけで、クライアントの証明書は検証されません。

## 設定

### 1.　自己署名証明書の生成

自己署名証明書の生成には、keytoolを使用します。
```sh
keytool -v -genkeypair \
-keyalg RSA \
-alias mule-server \
-keystore "super-tickets-papi.p12" \
-keysize 2048 \
-storetype pkcs12 \
-storepass "password"
```

* ***keytool -v -genkeypair***
    * keytoolはJavaキーストアと証明書を管理するためのツールです。
    * -vオプションは詳細な出力を表示するためのものです。
    * -genkeypairオプションは新しいキーペアを生成することを指定します。
* ***-keyalg RSA*** : 生成する鍵ペアのアルゴリズムとしてRSAを指定します。RSAは広く使われる公開鍵暗号方式です。
* ***alias mule-serverv*** : キーストア内で鍵ペアを識別するためのエイリアスをmule-serverに設定します。このエイリアスを使用して後で鍵ペアを参照できます。
* ***-keystore "super-tickets-papi.p12"*** : 鍵ペアを保存するキーストアのファイル名をsuper-tickets-papi.p12に設定します。
* ***-keysize 2048*** : 生成するRSA鍵のサイズを2048ビットに設定します。2048ビットは一般的に安全とされる鍵長です。
* ***-storetype pkcs12*** : キーストアの形式をPKCS#12に指定します。PKCS#12はパスワードで保護されたキーストア形式で、広く使われています。
* ***-storepass "password"*** : キーストアのパスワードをpasswordに設定します。このパスワードを使用してキーストアにアクセスします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260307/3cc678ee-bf69-61d3-df38-e2b45a70a8d8.png)

### 2. Muleアプリケーションの設定

1. TLS Contextを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260307/5408bfa6-75a0-a04f-36ff-96df22b9808e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260307/634231cb-73da-5b8e-f3ad-495f1185db77.png)
1. HTTP Listenerを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260307/4f28696c-a071-f090-f635-ada36776f07b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260307/446ab7d7-1bd2-4996-b0ac-ea3956d8b984.png)

## 設定の効果

1. Anypoint Studioで実行します。
1. https://localhost:8082 でアクセスできます。
View Transitions API を使用している場合、Intersection Observer API で監視している対象はどんな扱いになるのか

## この記事の概要

[View Transitions API](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API) によって、JavaScript なしでもリッチなページ遷移が行えるようになりました。

View Transitions そのものの使い方については以下の記事が分かりやすかったのでご覧ください。

https://qiita.com/access3151fq/items/a057c9b6398afae43670

https://ics.media/entry/230510/

これらの内容を見ていて、ふと気になったことがありました。

共通の要素が画面内でアニメーションしている間、Intersection Observer は要素が画面内に入った・画面外から出たという判定はどのように行うのでしょう。

ということで簡単にですが調べてみて、記事にしました。

## 結論

`View Transitions API` を使用していないときと何も変わらない。

すみません。なにも面白くない結果になりました。

せめて少しでも役に立つ記事にするため、調べていて確かめられたことを書きます。

- トランジション完了をトリガーにして何かの処理を追加するのは、できない
    - 当初は「トランジション完了したら他の要素がアニメーションする」ようなことがしたかった
    - [isIntersecting](https://developer.mozilla.org/ja/docs/Web/API/IntersectionObserverEntry/isIntersecting) が`true`となるのは、トランジション完了時ではない
- トランジション中のどこかをトリガーにして`isIntersecting`が`false`になったのを検出するのは、できない
    - 当初は「消えかける要素をトリガーにして別の場所をアニメーションさせる」ようなことがしたかった
    - `isIntersecting`が`false`にすらならない
- あくまで前のページと新しいページをアニメーションで繋いでいるに過ぎないので、アニメーションが無かった場合に`true`と`false`とが変わるタイミング自体は同じ

## 実験していた内容

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/7c8fdf49-8b5f-27aa-791d-6bf44a7a8060.gif)

下記の条件で`View Transitions API`を使用した際、していない際で挙動を比べていました。

- `view-transition`のアニメーション時間を長くする
- `entry.isIntersecting`が`true`のときに`描画されました`とメッセージを表示する
- `entry.isIntersecting`が`false`のときに`見えなくなりました`とメッセージを表示する
- `DOMContentLoaded`と`load`のときにメッセージを表示する

### 補足：`view-transition`のアニメーション時間を長くすること

アニメーション時間を意図的に長くしておいた方が、console にメッセージが表示されるタイミングと、見た目上の処理が完了したタイミングを見比べやすかったので、実施していました。

```css
::view-transition-group(*) {
  animation-duration: 1s;
}
```
hooks_riverpod関連Widgetざっくり使い分け　

# はじめに
こんにちは。OREOです。
本記事ではFlutterの開発でよく使われているパッケージ[hooks_riverpod](https://pub.dev/packages/hooks_riverpod)使用した場合にでてくるConsumerWidgetやHookWidget等の使い分けについてざっくりと整理したいと思います。

# 各Widgetについて
Flutterを触り始めると出会うのがStatelessWidgetとStatefulWidgetかと思います。２つの特徴はざっくりとこんな感じ。

|StatelessWidget|StatefulWidget|
|-|-|
|静的なWidget|動的なWidget|

次にhooks_riverpodを導入した場合にでてくる主なWidgetがこちら
|HookWidget|ConsumerWidget|HookConsumerWidget|StatefulHookConsumerWidget|
|-|-|-|-|
|（ライフサイクルをより簡単に管理することができる）動的なWidget|（プロバイダーを用いて状態を管理する）動的なWidget|Hook+Consumerの性質|全機能つかえる動的なWidget|

# 使い分けフローチャート
```mermaid
flowchart TD
StatelessWidget -- Widgetに閉じた状態を管理したい --> StatefulWidget
StatelessWidget -- プロバイダーを監視して状態を共有したい --> ConsumerWidget
StatelessWidget -- useEffect等を使用してライフサイクルを管理したい --> HookWidget
ConsumerWidget -- ライフサイクルも管理したい(initStateを使いたい) --> StatefulConsumerWidget
HookWidget --全部やりたい！！--> StatefulHookConsumerWidget
StatefulConsumerWidget --全部やりたい！！--> StatefulHookConsumerWidget
```

# さいごに
実際のところ全てのWidgetで`StatefulHookConsumerWidget`を使ってしまえばなんでもできてしまうのですが，それはナンセンスなので用途に応じて最適なWidgetを使用して可読性の高いコードを書いていきたいですね。


# 参考情報
https://riverpod.dev/ja/docs/concepts/reading
質問・相談しやすい環境のために、質問・相談の機会を"先に"つくる

## はじめに

◆この記事は何？
質問・相談しやすい環境づくりの実践的なコツを紹介する記事です

◆対象は？
質問・相談に困っているチームメンバーとリーダーの両方が対象です

◆この記事のねらい
質問・相談しやすいチーム環境の構築に役立てていただくことを目指しています。

## 先に結論
- 「質問・相談の機会」を**先に**つくる
- リーダー側から主導して環境を整備する
- 同期コミュニケーションの例
    - **「質問・相談のためのクイックミーティング」をあらかじめスケジュールに組み込む**
- 非同期コミュニケーションの例
    - **「質問事項一覧」をあらかじめ作成して、質問の方法を定めておく**

## 解きたい課題

多くのチームで、次のような課題があるかと思います。

- メンバー側
    - 「リーダーが忙しそうで、質問・相談がしづらい」
- リーダー側
    - 「メンバーからの質問・相談が少ない」

上記のような状況はチームの生産性に影響を与える可能性があります。

## 先手での環境づくり

質問・相談をしやすくするために、事前に機会を設けるのが効果的です。

同期と非同期の両方のコミュニケーション方法を用意することで、より柔軟な対応が可能になります。

チームの状況によって、効果的なコミュニケーション方法は異なります。何が最適かを事前に予測するのは困難です。そのため、「どちらかの方法がうまくいけばよい」という考えで、同期と非同期の両方を準備します。

◆同期のコミュニケーション
例えば、先に「定例の質問タイム」をスケジュールに組み込みます。

他の議題は持ち込まないのがコツです。

メンバー目線では、質問・相談の機会を得ることができます。
リーダー目線では、定期的にメンバーの障壁を取り除くことができます。

◆非同期のコミュニケーション
例えば、先に下表のような「質問事項一覧のフォーマット」を作成して、チーム全員がアクセスできるようにします。

| # | 質問 | 回答日 | 回答 |ステータス |
|:-:|:-:|:-:|:-:|:-:|
| 1 |   |  |   |  |
| 2 |   ||   |  |

リーダーが忙しいときは、非同期コミュニケーションが有効です。

メンバー目線では、落ち着いて質問を整理できます。
リーダー目線では、効率的に回答できます。

## 「先に」が大事

質問の必要性を感じてから、方法を考えるのではなく、事前に質問の方法を決めておくのが望ましいです。事前に決めることで質問のハードルが下がります。

「質問の仕方のフォーマット」を先に決めておくなども有効です。

メンバーから働きかけを待つのではなく、リーダーから働きかけていく方が質問・相談しやすい環境になっていきます。
結果的に、質問・相談しやすい雰囲気が醸成されます。

## おわりに

この記事では、質問・相談しやすい環境にするためのコツを紹介しました。

質問・相談しやすい環境構築に寄与できれば幸いです。
PHPのエラーハンドリングとデバッグについてまとめてみた

# はじめに
こんにちは、Webエンジニアの岩田史門([@SI_Monxy](https://x.com/SI_Monxy))です！
今回はPHPのエラーハンドリングとデバッグについて記事を書いてみました！
改善点や修正点があれば、コメントにてやさしくご指導いただけると嬉しいです！

# 概要
PHPを使った開発において、エラーハンドリングやデバッグは重要なスキルです。本記事では、PHPでのエラーハンドリング方法やデバッグテクニックについて紹介します。サンプルコードも交えて解説します。

# 基本的なエラーハンドリング
PHPでは、try-catchブロックを使って例外をキャッチし、エラーハンドリングを行います。

```php
<?php
function divide($dividend, $divisor) {
    if($divisor == 0) {
        throw new Exception("Division by zero");
    }
    return $dividend / $divisor;
}

try {
    echo divide(10, 2); // 正常動作
    echo divide(10, 0); // 例外発生
} catch (Exception $e) {
    echo "Caught exception: " . $e->getMessage();
}
?>
```
# カスタム例外クラスの作成
独自の例外クラスを作成することで、より細かいエラーハンドリングが可能です。

```php
<?php
class CustomException extends Exception {}

function test() {
    throw new CustomException("A custom exception has occurred");
}

try {
    test();
} catch (CustomException $e) {
    echo "Caught custom exception: " . $e->getMessage();
}
?>
```

# エラーレベルの設定
PHPでは、エラーレベルを設定して特定のエラーのみを表示させることができます。

``` php
<?php
error_reporting(E_ALL); // すべてのエラーを報告
ini_set('display_errors', 1); // エラーを画面に表示
?>
```

# まとめ
これらの技術を活用することで、PHPでの開発がよりスムーズになるでしょう。エラーハンドリングとデバッグを適切に行うことで、コードの品質を向上させることができます。

# 参考
- [PHP: Error Handling](https://www.php.net/manual/en/language.exceptions.php)
ステータスコード

## はじめに
WEBを支える技術を読んでステータスコードについて改めて学んだので備忘として記載していきます。HTTP1.1のステータスコードになります。

## 1xx 処理中
## 2xx 成功
### 200 OK：リクエスト成功
- GETの場合はボディにリソースの表現が入る
- PUTやPOSTの場合はボディに処理結果が入る
### 201 Created：リソースの作成成功

## 3xx リダイレクト
### 301 Moved Permanentry：リソースの恒久的な移動
- リクエストで指定したリソースが新しいURIに移動したことを示す
- 新しいURIはレスポンスのLocationヘッダに絶対URIとして入る

## 4xx クライアントエラー
### 404 Bad Request：リクエストの間違い
- リクエストの構文やパラメータが間違っていたことを示す
- ほかに適切なクライアントエラーがを示すステータスコードが存在しない場合にも用いる
- 未知の4xx系ステータスコードが返ってきた場合、400 Bad Requestと同じ扱いで処理するように仕様で定められている

### 401 Unauthorized ：アクセス権不正
### 404 Not Found：リソースの不在
- 指定したリソースが見つからないことを示す
- レスポンスボディにはその理由が入る

## 5xx サーバーエラー
### 500 Internal Server Error ：サーバ内部エラー
- サーバ側に何らかの異常が生じていて正しいレスポンスが返せないことを示す
- ほかに適切なサーバエラーを示すステータスコードが存在しない場合にも用いる
- 未知の5xx系ステータスコードが返ってきた場合、500 Internal Server Errorと同じ扱いで処理するように仕様で定められている
### 503 Service Unavailable ：サービス停止
- サービスメンテナンスなどで一時的にアクセスできないことを示す。レスポンスボディにはその理由が入る
おじさんがFlutterで0から開発していく　#0 意気込み

## はじめに
### 自己紹介
今年で39になるのですが、本当にいろんな職を高校卒業から点々としました。

そんな私が数奇な縁で、35になる年齢でITエンジニアとして転職するきっかけをもらいました。
ITエンジニアとしては4年目で大した実績、これをやり切りました！！的なものはありません。

Qiitaでは、私がITエンジニアとしての気づきやと、その中で選んだFlutterという技術について紹介します。Flutterを使って、どのようにしてゼロからアプリケーション開発に挑戦していくのか、その過程で得た学びや気づきをアウトプットできたらいいなと思います。

## なぜFlutterを選んだのか
孫請けSierの現場でPHPやJavaやKotlinなどを使用してきましたが、フラフラといろいろな言語を頭だけ勉強していました。


### Androidアプリを作成したいし、Webサービスも作成したい。


結局なんの言語を勉強すればなにがいいのかって感じでここ何カ月悩んでおり、ニッチ好きの性格とこれまでの自分の経験からReactNativeではなく、Flutterに決めました。
もう一つ理由としてはこれまで主に使用してきた言語がサーバーサイド言語だからです。
~~また即座にビルドできることもせっかちな自分には合っているように感じます。~~
(ReactNativeでもできるんですね:sweat_smile:）

## Flutterの将来性について
そもそもFlutterを開発しているGoogleがFlutterチームを解雇したみたいな[ニュース](https://gigazine.net/news/20240430-google-engineers-lay-off/)を言語を調べていくなかで見ましたが、個人開発で使用するつもりなので、特に気にしてないです。

## とりまゴール
長々と初めから文章だけを書きましたが、とりあえずのゴールを以下とします。
・Flutterを使用してToDoアプリを作成する
ABC359をPythonで（A～E）

ユニークビジョンプログラミングコンテスト2024 夏（AtCoder Beginner Contest 359）の解答等のまとめ

https://atcoder.jp/contests/abc359



# A問題
https://atcoder.jp/contests/abc359/tasks/abc359_a

全部調べる。
```python:A
cnt = 0
for a_i in open(0).read().split():
    if "T" in a_i:
        cnt += 1
print(cnt)
```

# B問題
https://atcoder.jp/contests/abc359/tasks/abc359_b

dictにメモを残して調べる。
```python:B
n = int(input())
a = list(map(int, input().split()))

d = dict()
ans = 0
for i, a_i in enumerate(a):
    if a_i in d:
        if d[a_i] + 2 == i:
            ans += 1
    else:
        d[a_i] = i

print(ans)
```

# C問題
https://atcoder.jp/contests/abc359/tasks/abc359_c

パターンを減らすために$sx<tx$となるように変える。
縦移動は確定で1かかる。
横移動は縦へ1つ移動するときにコスト0で移動できる。
そうでないときは$x$==0を基準に考える。
```python:C
sx, sy = map(int, input().split())
tx, ty = map(int, input().split())

if sx > tx:
    sx, sy, tx, ty = tx, ty, sx, sy

if abs(sx - tx) < abs(sy - ty):
    print(abs(sy - ty))
else:
    ans = abs(sy - ty)
    tx -= ans
    ans += abs((tx + sy % 2) // 2 - (sx + sy % 2) // 2)
    print(ans)
```

# D問題
https://atcoder.jp/contests/abc359/tasks/abc359_d

dictで確認すべきパターンを全通り調べる。
```python:D
n, k = map(int, input().split())
s = input()
mod = 998244353

d = {"": 1}
for s_i in s:
    new_d = dict()
    for key, val in d.items():
        for a in ["A", "B"]:
            if s_i == a or s_i == "?":
                new_key = "{0}{1}".format(key, a)
                if len(new_key) > k:
                    new_key = new_key[-k:]
                if len(new_key) < k or new_key != new_key[::-1]:
                    if new_key not in new_d:
                        new_d[new_key] = 0
                    new_d[new_key] += val
                    new_d[new_key] %= mod
    d = new_d

ans = 0
for val in d.values():
    ans = (ans + val) % mod

print(ans)
```
# E問題
https://atcoder.jp/contests/abc359/tasks/abc359_e

スタックを利用してそれより左にいくら溜めないといけないか計算する。
似たような問題をどこかでやったことがあるので出来た。
```python:E
n = int(input())
h = list(map(int, input().split()))

stack = [[float("inf"), 0]]
ans = []
t = 0
for i, h_i in enumerate(h, 1):
    height = 1 if i > 1 else 0
    while stack[-1][0] <= h_i:
        x, j = stack.pop()
        t += (x - height) * (i - j)
        height = x
    t += (h_i - height) * (i - stack[-1][1]) + 1
    stack.append([h_i, i])
    ans.append(t)

print(*ans)
```
【Github】リポジトリの設定でプルリクエスト上から rebase とか出来るようにする

これ便利よねー

リポジトリの settings から General の Pull Requests に `Always suggest updating pull request branches` ってチェックボックスあるからそれにチェック入れるだけ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531606/d105823e-067d-84c2-55d8-68c3e1114bd7.png)

PR 上から rebase 出来るようになりやす

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531606/095d2838-dd3a-3ea6-5173-1334df30c046.png)
git fetchとは何か

# この記事を書いたきっかけ
Gitの勉強をしているときに、git fecthというコマンドを初めて知りました。一人でWebアプリケーションを作成する時には使用したことがなかったので、このコマンドが何をするものなのかよく知りませんでした。

git fetchを必要な場面で使えるようにするために、記事にしました。

# git fetchとは
### git fetchとは何か
`git fetch` とは、Gitのコマンドの一つです。

`git fetch` コマンドを使うことで、リモートリポジトリの最新情報をローカルに取得することができます。取得した情報はローカルリポジトリのリモート追跡ブランチに格納されるので、現在作業しているローカルブランチの状態を変更することはありません。

fetchは英語で、ある場所から<物や人>を取ってくる(呼んでくる)という意味があります。bringみたいな意味を持ちます。

### git fetch の役割
`git fetch` はリモートリポジトリの全ての最新のコミットやブランチ情報を取得します。フェッチした情報はローカルのリモート追跡ブランチ（例：origin/master）に格納されますが、チェックアウトしている現在のローカルブランチには影響を与えません。作業中のブランチには影響を与えたくないときに、安心して実行できます。

### git fetchを使用するシナリオ
- 他の開発者がリモートリポジトリに変更をプッシュした場合、その変更をローカルで確認する必要がある時。
- リモートに新しいブランチが作成された時に、そのブランチ情報をローカルで取得したい時。
- リモートリポジトリとローカルリポジトリの状態を同期させ、最新の情報を基に作業を進めたい時。

### git fetch の使用方法
**基本コマンド**
`git fetch <リモート名>`


例えば、リモート名がoriginの場合
`git fetch origin`

これにより、リモートoriginの最新の状態を取得します。

***
フェッチ後、ローカルブランチをリモートの最新状態に更新するには、
`git merge` や `git pull` コマンドを使用します。

**git fetchしたファイルを統合(マージ)したいとき**
masterに切り替える
`git checkout master`

統合(マージ)する
`git merge origin/master`


**git pull コマンドを使用してフェッチとマージを一度に行うとき**
`git pull origin master`


### git fetch と git pull の違い
`git fetch`は、リモートの最新情報を取得しますが、ローカルブランチの状態は変更しません。
`git pull`は、`git fetch`と`git merge`を組み合わせたコマンドであり、リモートの最新情報を取得し、ローカルブランチにマージするところまでを実行します。
マージとは、枝分かれしたブランチの変更をmasterブランチに統合する操作です。

https://qiita.com/eric50905/items/fa0fe0d8430b5191688e

# まとめ
リモートリポジトリの情報をちょっとローカルで見てみたい！でも、ローカルには何も影響を与えたくない！というときには`git fetch` を使うとよい。
ZIOのZLayerを使ってみる

# TL;DR

ZLayerを使用すると、次のようなイメージで簡潔にDIすることができます。

```scala:擬似コード
ZIO.serviceWith[使用したいサービスクラス].provide(
  ZLayer.derive[サービスクラスの依存1],
  ZLayer.derive[サービスクラスの依存2],
  ZLayer.derive[サービスクラスの依存1の依存],
  ZLayer.derive[サービスクラスの依存1の依存の依存]
  ...
)
```

## はじめに

Scala ZIOには、ZLayerという強力な機能があります。
ZLayerは、DIをシンプルかつ型安全に実現するための仕組みです。
本記事では、ZLayerを用いたDIについて説明します。

# ZIOのZLayerとは？

ZLayerは、ZIOにおけるDIの中核を担う機能です。
ZLayerは、依存関係を解決するためのレシピのようなもので、必要な依存関係をどのように生成し、組み合わせるかを定義します。
ZIOは、これらのZLayerを組み合わせて、最終的に必要なオブジェクトのインスタンスを生成します。

# ZLayerによるDIの例

以下のコードでは、`Service`クラスが`DependencyA`と`DependencyB`に依存しており、さらに`DependencyA`が`DependencyAA`に依存しています。
各クラスに対応するZLayerを定義し、provide関数でこれらのZLayerを組み合わせています。これにより、`Service`のインスタンスが生成され、fooメソッドが実行されます。

```scala
import zio.{Scope, ZIO, ZIOAppArgs, ZIOAppDefault, ZLayer}

object Main extends ZIOAppDefault {
  class Service(dependencyA: DependencyA, dependencyB: DependencyB) {
    def foo(): Unit = println("foo")
  }

  class DependencyA(dependencyAA: DependencyAA)
  class DependencyAA
  class DependencyB

  // 各モジュール
  val dependencyA = ZLayer.derive[DependencyA]
  val dependencyAA = ZLayer.derive[DependencyAA]
  val dependencyB = ZLayer.derive[DependencyB]
  val service = ZLayer.derive[Service]

  override def run: ZIO[ZIOAppArgs, Any, Unit] =
    ZIO.serviceWith[Service](_.foo()).provide(
      service,
      dependencyA,
      dependencyAA,
      dependencyB
    ) // 実行結果: 「foo」という文字列が標準出力される
}
```

# もし依存関係の定義に誤りがあったら、コンパイルエラーに

`Service`が依存する対象は`DependencyA`, `DependencyAA`, `DependencyB`の3つです。
ここでもし仮に`DependencyAA`をDIし忘れたらどうなるでしょうか？

```
  override def run: ZIO[ZIOAppArgs, Any, Unit] =
    ZIO.serviceWith[Service](_.foo()).provide(
      service,
      dependencyA,
      dependencyB
    )
```

結果、以下のようにコンパイルの段階でエラーが検知されます。

```txt:コンパイルエラー内容
/Users/tobita/work/ScalaPlayground/src/main/scala/Main.scala:19:46


──── ZLAYER ERROR ────────────────────────────────────────────────────

 Please provide a layer for the following type:

   Required by dependencyA
   1. Main.DependencyAA
      
──────────────────────────────────────────────────────────────────────


    ZIO.serviceWith[Service](_.foo()).provide(
```

型安全で凄いですね👍

# おわりに

この記事では、ScalaのZIOライブラリにおけるZLayerの基本的な使い方と、その型安全性について触れました。
ZLayerを利用することで、依存関係を明示的かつ安全に管理できるため、複雑なアプリケーションの開発が容易になりそうですね！
ZIO Schema: 1つのスキーマ定義でJSONとAvro形式を切り替える

# はじめに

ZIO Schemaを使用すると、一度データ構造をSchemaとして定義するだけで、
JSONやバイナリ形式など、データを様々な形式へ変換することができます。

本記事では、ZIO Schemaを用いて、ケースクラスをJSONとAvroバイナリ形式に変換する例を紹介します。

### サンプルコード解説

```scala
import zio.{Console, ZIO, ZIOAppArgs, ZIOAppDefault}
import zio.json.*
import zio.schema.*
import zio.schema.codec.{AvroCodec, BinaryCodec, JsonCodec}

object Main extends ZIOAppDefault {
  case class Person(name: String, age: Int)

  implicit val schema: Schema[Person] = DeriveSchema.gen[Person] // (1)
  implicit val jsonCodec: JsonCodec[Person] = JsonCodec.jsonCodec(schema) // (2)
  implicit val binaryCodec: BinaryCodec[Person] = AvroCodec.schemaBasedBinaryCodec(schema) // (3)

  val person = Person("John Doe", 30)
  override def run: ZIO[ZIOAppArgs, Any, Unit] = Console.printLine(
    (
      person.toJson, // (4)
      binaryCodec.encode(person) // (5)
    )
  )
}
```

1. `DeriveSchema.gen[Person]`で、ケースクラス`Person`のスキーマを自動生成します。
2. `JsonCodec.jsonCodec(schema)`で、スキーマからJSONコーデックを自動生成します。
3. `AvroCodec.schemaBasedBinaryCodec(schema)`で、スキーマからAvroバイナリコーデックを自動生成します。
4. `toJson`メソッドで、`Person`オブジェクトをJSON文字列に変換します。
5. `binaryCodec.encode`メソッドで、`Person`オブジェクトをAvroバイナリ形式に変換します。

### 実行結果

このコードを実行すると、以下のような結果が得られます。

```
({"name":"John Doe","age":30},Chunk(16,74,111,104,110,32,68,111,101,60))
```

1つ目の要素はJSON形式、2つ目の要素はAvroバイナリ形式で表現された`Person`オブジェクトです。

### まとめ

ZIO Schemaを使用することで、一度スキーマを定義するだけで、JSONやAvroバイナリ形式など、様々な形式へのデータ変換を簡単に行うことができます。
異なるデータ形式への変換が必要な場面で、ZIO Schemaが活用できそうですね。
HHKB Professional HYBRID Type-S（PD-KB820WS）のキートップを外して掃除した

## はじめに
3年ほど使っているHHKBの隙間汚れが気になってきたため、キートップを外して掃除をしました。
同じキーボードを使っている方の参考になるかと思い、まとめます。

### 掃除をしたキーボード
- HHKB Professional HYBRID Type-S 日本語配列／白
（PD-KB820WS）

https://www.pfu.ricoh.com/direct/hhkb/detail_pd-kb820ws.html

![2024-06-23_17-06-21_992.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818066/d1aaba28-2ec6-67a8-3a53-3bc30822979b.jpeg)


### 掃除に必要なもの
- キートップ引き抜き工具
  - わたしは下記工具を使用しました
    - FILCO キートップ引抜工具 FILCO KeyPuller プロ仕様 ブラック Keycap Remover キーボードメンテナンス用工具 FKP01
https://amzn.asia/d/03oTJBK3
- 綿棒
- キッチンペーパー
- エアダスター
- ボウル（キートップをお湯でつけ置きするための容器）
- ザル（キートップの水切りする際に使用）
- 重曹
- キートップを乾かす場所

## 掃除内容
### キートップをキートップ引き抜き工具で引き抜く
キートップを1つずつ工具で引き抜きます。
工具の針金を指で広げてキートップを左右に挟んだ状態で、工具を斜めにし、真上に引き抜く を繰り返しました。

![キートップ引き抜き工具でキーを引き抜いている様子](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818066/2707f781-702f-8fe2-3fba-fd3af4be854d.jpeg)

参考にしたサイトではSpaceキーにバネが入っているとの事でしたが、今回わたしが掃除をしたPD-KB820WSではバネはありませんでした。
### キートップを重曹入りのお湯でつけ置き
重曹を入れたお湯にキートップを入れ、キーボード本体の掃除が終わるまで放置します。

![重曹を入れたお湯にキートップを入れている様子](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818066/647ef709-1429-e84f-bb3d-d705ae510678.jpeg)


### エアダスターでキーボードの髪の毛やホコリなどのゴミを取り除く
目立つゴミをエアダスターで取り除きます。
エアダスターがない場合はキッチンペーパーや綿棒で取り除くのでも問題ありません。

### 綿棒でキーボードの細かい部分の汚れを取り除く
綿棒でキーとキーの間の汚れを擦り取ります。
気が済むまで汚れを取りましょう。
![キーボードの汚れを取った後の様子](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818066/464d48bf-fe3e-602c-b335-cc7465555c54.jpeg)

### キートップを水洗い
キートップをお湯からザルに移し、水洗いをします。
重曹が残らないよう流水でよく洗います。

### キートップの水をふき取る
ザルでキートップの水を切り、キッチンペーパーで残った水滴をふき取ります。
キートップの軸の部分に水が残っている場合は、綿棒を軸に入れることで水を取り除けます。

### キートップを乾燥
平らな場所にキートップを重ならないように置き、乾くまで置いておきます。

![平らな場所にキートップを置いている様子](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818066/51a8beba-6be2-e46f-127e-b4ee65e199ba.jpeg)

### キートップをキーボードに付け直す
乾いたキートップをキーボードの元の位置に付け直します。

![キートップをキーボードに付け直した後の様子](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3818066/033ff50f-6cd6-cdea-f8a5-56b03313e131.jpeg)

これで掃除完了です。

## おわりに
キートップの取り外しが手間なのですが、隅々まで汚れを落とせたので良かったです。
また汚れが気になってきたら掃除しようと思います。

## 参考記事
https://blog.yucchiy.com/2022/01/keyboard-osouji-2022/
【図解】scpコマンドの書き方が毎回混乱するので図解する

お疲れ様です。秋並です。

scpコマンドでリモートマシンとファイルのやり取りをすることがたまにあるのですが、たまにしか使わないので、**どっちの書き方が「ローカル→リモート」で「リモート→ローカル」なのか毎回一瞬分からなくなります**。

そこで、本記事では図解で説明することでどっちかどっちであるかをぱっと見で分かるようにしたいと思います。

# 「リモートのファイル」をローカルにコピーする
「リモートのファイル」をローカルにコピーするのは以下コマンドになります。

なお、ディレクトリごとコピーしたい場合は`-r`オプションをつける必要があります。

```bash
scp remote@192.168.OOO.OOO:~/hoge2/hoge.txt ~/hoge1
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2030125/34a6546d-1c91-435d-8220-5c6ccfc9dbc8.png)


# 「ローカルのファイル」をリモートにコピーする

「ローカルのファイル」をリモートにコピーするのは以下コマンドになります。

なお、ディレクトリごとコピーしたい場合は`-r`オプションをつける必要があります。

```bash
scp ~/hoge1/hoge.txt remote@192.168.OOO.OOO:~/hoge2/
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2030125/df63e6f0-3f44-d621-011c-53f197c4344c.png)

# 参考サイト
- [scpコマンド](https://qiita.com/chihiro/items/142ebe6980a498b5d4a7)
[Gitコマンド]git stashについて

こんにちは！
開発現場でよく利用するGitコマンドを今後暫くは投稿していこうと思います。
まず手始めにgit stashについて纏めます。

# git stashとは？
そもそもgit stashとは何か？
git stashは現在のブランチで開発中の作業を一時的に別の場所に保存をし、作業ディレクトリを綺麗な状態にします。

開発中のタスクで別のブランチでレビューがあった際、現在のブランチの作業内容に変更があった時には、ブランチの移動をすぐすることができません。
その際に役立つのがこのgit stahsです。これを一時的に別の場所に保存することで、ブランチの移動が可能になります。

# git stashを実際にやってみよう。
##### 現在の作業ディレクトリの変更を一時的に保存
```
git stash
```
##### メッセージ付きで変更を保存
```
git stash push -m "message"
```
##### 保存されたすべてのスタッシュの一覧を表示
```
git stash list
```
##### 最新のスタッシュを適用し、作業ディレクトリに戻す
```
git stash apply 
```
##### 特定のスタッシュ（stash@{n}）を適用
```
git stash apply stash@{n}
```
##### 最新のスタッシュを適用し、その後スタッシュリストから削除
```
git stash pop
```
##### 特定のスタッシュを適用し、その後スタッシュリストから削除
```
git stash pop stash@{n}
```
##### 最新のスタッシュを削除
```
git stash drop
```
##### 特定のスタッシュを削除
```
git stash drop stash@{n}
```
##### すべてのスタッシュを削除
```
git stash clear
```

# まとめ
今日はgit stashについてまとめてみました。
基本的な操作ですが、実際の開発では結構便利で私自身利用頻度も多いです。

今後はこのような覚えていたら便利なGitコマンド操作をまとめていこうと思います。
【R】統計処理と作図に関する情報のまとめ

# はじめに

これまでに`R`に関する記事を幾つも書いてきましたが、どこに何を書いたのか分からなくなってきたので、そのまとめページを作ってみました。
要は個人的な備忘録のページですが、どこかで何かの役に立つかもしれないと思い記事として公開することにしました。

# 基本操作

* [【R】作業フォルダの移動と確認](https://qiita.com/nkojima/items/d5963eadf9efd1928184)
  * カレントフォルダを移動＆確認する方法
* [【R】データの読み込み](https://qiita.com/nkojima/items/131fdce3a22ccc1760b4)
  * ベクトル、行列、データフレームの作成方法
* [【R】複数行のコメントを実現する](https://qiita.com/nkojima/items/5bda23c22ce0bd75443b)

# 統計処理

* [【R】基本統計量を求める](https://qiita.com/nkojima/items/b49048f971352a36fefd)
* [【R】平均値の差を比較する方法（t検定）](https://qiita.com/nkojima/items/92afdadf772a1b6c82bc)
* [【R】平均値の差を比較する方法（一元配置分散分析）](https://qiita.com/nkojima/items/690906dd0beb2d4e32e5)
* [【R】相関係数を求める方法](https://qiita.com/nkojima/items/4f0bd1db623e4f036080)
* [【R】ロジスティック回帰を行う](https://qiita.com/nkojima/items/c4848877cae5261c8595)

# 作図

## 散布図

* [【R】散布図を描く方法](https://qiita.com/nkojima/items/c008adec58c7834edfc1)
* [【R】散布図に相関係数を埋め込んで描画する方法](https://qiita.com/nkojima/items/cb4cb4d3db15c60cbdfc)
* [【R】複数のデータを散布図としてまとめて描画する方法](https://qiita.com/nkojima/items/d6e22a244e2d84d36abc)
  * A, B, Cという3つのデータから、`A vs B`, `A vs C`, `B vs C`という散布図をまとめて描画する方法
* [【R】散布図にグリッド線を入れる](https://qiita.com/nkojima/items/577b8790a7c8400916c3) 
  * プロットエリアにグリッド線（罫線的なもの）を入れる方法

## その他の図

* [【R】ヒストグラムを作る](https://qiita.com/nkojima/items/681f7131bc97a52df447)
* [【R】箱ひげ図を描く方法](https://qiita.com/nkojima/items/016bb9ace336e88bc9ad)
* [【R】グラフの目盛りを任意の文字に変える](https://qiita.com/nkojima/items/581e1141c64e5145e1f2)
  * グラフの横軸を数値ではなく、「4/1」などの任意の日付に変える方法

## 作図処理全般

* [【R】作成した図にフォントを埋め込む](https://qiita.com/nkojima/items/4375f1ed297999e133aa)

  
# その他

* [【R】MeCabで形態素解析](https://qiita.com/nkojima/items/54ca56ac819e5e085b0a)
* [【R】引用情報を表示する](https://qiita.com/nkojima/items/324de37fc6c8d0cf8964)
【電卓・ファイル検索 詳細解説】いまから始めるRaycast vol.3 【生産性向上】

# はじめに
今回の記事はシリーズ３回目の記事となります
Raycastがそもそも何なのかわからない、という方はぜひ第一回の記事をご覧になってください！

https://qiita.com/hikagami/items/d4b88d8e99d40dbf7287

## 今回紹介する内容
- Calculator (電卓)
- Search File & Search Screenshots (ファイル検索、スクリーンショット検索)

今回は、この3つの機能について詳しく紹介していこうと思います。
これらの機能はRaycastにデフォルトで入っているため、拡張機能をインストールする必要はありません！

## Calculator (電卓)

ふとした瞬間に簡単な計算を行いたい時、ありますよね？
単位の変換や暗算するには少し大変な計算をするとき、Raycastなら一瞬でできてしまいます！

![demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778030/47d158be-ed7d-11f6-37bd-22ad4805dcc7.gif)

### 機能概要
Raycastを起動して、そのまま計算式を打ち込みます。

![スクリーンショット 2024-06-23 21.40.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778030/5ee7b44e-c731-4557-13e9-ff7e42f15fab.png)

また、履歴を見ることもできます。
`Calculator History`コマンドを実行することで、時系列順で履歴を確認できます。

### 仕様
計算には一般にプログラミングで用いられる演算子を使うことができます。
`+`、`-`、`*(かける)`,`/(割る)`、`**(二乗)`、`%(剰余)`、`pi(円周率)`などなど...
また、単位の変換ができます。
`1$ in Yen`などの通貨の換算や`3week in min`で時間の計算をしたりすることも可能です。

### アクション
`⌘+K`でその項目に対してさまざまなアクションをすることができます。
便利なものを抜粋して紹介します。

- `Copy answer`
計算の結果をクリップボードにコピーすることができます。

- `Put Answer in Search Bar`
計算の結果をRaycastのSearchbarに貼り付けしてくれます。続けて計算をしたい時に便利です。

- `Show History`
履歴一覧画面に飛ぶことができます。
前述の`Calculator History`と同じ動作になります。

## Search File & Search Screenshots (ファイル検索、スクリーンショット検索)
続いてはファイル検索、スクリーンショット検索機能の紹介です。
大きな力を持つわけではないのですが、知っているとかなり時間短縮になることが多いです。

`Search File`は`file`、`Search Screenshots`は`screen`と検索すれば1番上に出てきてくれます。

### 機能概要
どちらも似たような機能を有しており、それぞれ最近保存したファイルとスクリーンショットを時系列順で確認することができます。
`Search Screenshots`は画像だけでなく、画面録画のファイルも表示してくれます

### 仕様
どちらのコマンドもほぼ同じようなことができますが、表示が大きく違います。
`Search File`はリスト表示、`Search Screenshots`はグリッド表示となり、個人的には見やすさの観点から`Search Screenshots`の方を使用しています。

![スクリーンショット 2024-06-23 22.14.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778030/59b6f07b-75d7-e0b9-8700-37faf4a10e55.png)

`Search File`を使用する場面としては、ファイルのサイズや保存場所を即座に確認したい時が多いです。
![スクリーンショット 2024-06-23 22.14.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778030/144d2369-4841-67d6-4f1f-212aeb781810.png)

どちらにも共通して一番便利なのが、Raycastからそのままドラッグ&ドロップができる点です。
いちいちFinderを開かなくとも良いのです...

![画面収録 2024-06-23 22.18.49.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778030/a4b5bc1f-2b47-883a-4ae3-f51e2d0b47cb.gif)

### アクション
`⌘+K`でその項目に対してさまざまなアクションをすることができます。
便利なものを抜粋して紹介します。

- `Show in Finder`
選択したファイルをFinderで開くことができます。
なんだかんだFInderで開きたいことは多々あるのでとても便利です。

- `Copy to Clipboard`
選択したファイルをクリップボードに追加してくれます。
あとは貼り付けを行えば良いだけの状態になるので、画像の共有時などに時短になります。

## おわりに
最後まで見ていただきありがとうございました！
RSS Hackathon 2024 に参加した話

## 初めに
ハッカソンイベントに行ってきたので覚書として記事を書いてます

今回参加してきたのはレイスシステムソリューションズ株式会社様が主催する「RSS Hackathon2024」です
https://race-ss.co.jp/hackathon

最初は賞金総額75万円のインパクトにつられて書類選考ありとのことだったので通ればいいな～くらいの軽い気持ちで応募したのですがめちゃくちゃ楽しかったです．

## イベントの概要
イベントは金，土，日の３日間で1日目がアイデアソン，2日目から3日目の午前までが開発で，三日目の午後に発表というかなり忙しいスケジュールでした．
参加チーム数はオフライン参加4チーム，オンライン参加2チームの計6チームの参加でした．
参加形式はチーム，個人から選ぶことができ，個人でエントリーした場合でも運営側にチームアップを行ってもらうこともできます．


## ハッカソンのテーマ

今回のハッカソンのテーマは「"あたりまえ"の，その先へ」ということで運営が用意した４種類のあたりまえ，あるいは自身が考えたあたりまえを解決するというものでした

うちのチームでは「適材適所は難しくて"あたりまえ"」と「悩みを解決するのは難しくて"あたりまえ"」という二つの問題に取り組みました

## 作成したプロダクト

最終プレゼンの内容は[こちら](https://www.docswell.com/s/minarin0179/ZJL2WQ-2024-06-25-204840)で閲覧できます
今回うちのチームが作成したのは利活用可能な社内SNSサービス「SeeReal.」です

Slackのtimesチャンネルなど，自由につぶやける社内SNSを運用している会社は少なくないと思いますが，そこに投稿される情報が利活用されていないことに着目しました．

SeeReal.は大きく３つの機能からなります
1. 投稿しないと見られない & 翌日になると見られないタイムライン
2. 投稿によるスキルシートの自動更新
3. 投稿による悩みの迅速な解決 

順番に解説していきます

### 投稿しないと見られない & 翌日になると見られないタイムライン
社内SNSを運用するにあたって障壁となるのは，利用者が投稿するモチベーションです．せっかくシステムとして導入されても誰も利用しなくなってしまっては意味がありません．
そこで「SeeReal.」では既存サービスであるBeReal.と似た仕組みを採用しています．
その日に一回でも投稿を行っていないと他の人の投稿を見ることが出来ません．これにより他の人の投稿を見るために更新したいという意欲が生まれます．また，見られる投稿をその日に投稿されたものに限定し，過去の投稿を見られなくすることで今日この瞬間に更新することに意味が生まれます．

### 投稿によるスキルシートの自動更新
社内SNSとして運用することを想定しているため，投稿内容には現在取り組んでいる作業などを投稿することになります．このような投稿には往々にしてその人物のスキルを反映する内容が含まれています．
　例を挙げると「Reactのステート管理について勉強中」といった投稿からは，この人が現在Reactについて学習に取り組んでいるという情報が汲み取れます．このような情報を元にスキルシートを更新することが出来れば常に社員の最新のスキルセットを自動で更新することができます．

 ### 投稿による悩みの迅速な解決
 現在のタスクで息づまっており，誰かに助けを求めたいが誰に聞いていいか分からない．そのような際に，悩みを含んだ内容を投稿することによって該当の技術に対して知識を持ったユーザーを自動的にメンションします．
 多くの人が見られる場所に置くことで一人でも知っている人がいれば迅速な解決が出来る & スキルを見て適切な人にのみメンションを行うことでメンションの乱立を防ぐことを実現しています．


以上を踏まえたシステムの全体の流れは以下の図のようになっています．
![RSS_Hackathon-08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589575/190cee4b-5acf-be4c-e5d9-4406d98a76f8.png)


使用した技術スタックは以下の通りです．
![RSS_Hackathon-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589575/b801530e-882a-fbe7-d808-6cafef827a91.png)


投稿された内容GPT-4oに入力してスキルシートの更新と悩みの抽出を行っています．
各社員のスキル内容はMongoDBによって管理することでRDBよりも柔軟に社員のスキルを表現できるようにしています．

### RSSハッカソンのここがよかった
1. 賞金の大きさ
やはり最優秀賞50万円，優秀賞20万円という額は学生にとって魅力的です．
ここまで賞金が大きいハッカソンイベントもなかなか他に類を見ないのではないでしょうか．

2. フィードバックの鋭さ
審査員としてRSSの社長クラスの方々が講評してくれます．
学生相手にも忖度なく鋭い意見をぶつけてくれるので非常に参考になります．

3. 参加者のレベルの高さ
ハッカソンイベントにしては珍しく，参加にあたって書類審査があります．
そのため全体のレベルが非常に高く，個人でエントリーして集められたチームにも関わらず問題なく開発を進めることが出来ました．
一緒に参加する人がいないけどチーム開発をやってみたいという人にはとても良い機会になるのではないでしょうか．

### 最後に
はじめましてから始まって3日間一緒に走り切ってくれた焼きSwiftの皆さん，ありがとうございました．RSS初めてのハッカソンイベントとのことで来年以降も開催されるかは分かりませんが，非常に魅力的なイベントだと思います．もし来年の開催があれば腕に自信のある人はぜひ参加してみてはいかがでしょうか．
【Xcode】Simulatorで位置情報を任意で指定する方法

こんにちは！
今回はXcodeのSimulatorで、位置情報を任意で指定する方法を纏めます。
実際の開発現場で利用したので、やり方は至ってシンプルですが忘れないように備忘録として残します。


## 手順紹介
### ①Simulatorで位置をカスタム指定できる「Custom Location」を選択
XcodeのSimulatorを起動します。
起動したら「Simulator」の上部メニューから「Features」→「Location」→「Custom Location」を順に選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1789173/ea9807a7-d147-2450-3b61-dc34baf7b2ce.png)



### ②Simulatorで位置の指定を行う
緯度と経度を指定。それぞれ「Latitude(緯度)」「Longitude(経度)」を入力します。
![スクリーンショット 2024-04-19 16.33.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1789173/ede10567-c152-ce12-6d69-9d5910e33ef2.png)


これで完了です。

## まとめ
今回は簡単に実装できる方法を纏めました。
デフォルトのSimulatorで用意されている設定は米Apple本社になり、日本の特定の場所を指定しないといけません。

 今日は以上です。
DTOクラスはアホにしよう

# DTOクラスはアホにした方がいい
- DTOクラスはただの入れ物であり、中身のデータが何かは知らない
つまり、getterやsetterは(中身は何か知らんけど)ただ来たものを、受け渡すだけ
- DTOクラスは、賢くしない方がいい(処理とかを入れない方がいい)
  - 末端であるDTOクラスで色々やろうとすると、メンテナンス性が悪くなる
  →・末端が広大化していく
  　・要件が増えた時にif文が増えたりしてカオスになる
   
**どこで頭を使うかにもよるが、基本は末端がアホな方がいい**

# カプセル化の意味
- カプセル化とは、他のオブジェクトに「使っていいよ」と公開するフィールドとメソッドを最小限に抑え、さらには、公開するなら操作できる範囲を必要最小限に抑えること。(アクセス制御　access control)
↓
**いちいち色々と処理をするためのメソッドとかをDTOクラスに作っていたらキリがない！！**

# 備考
- Androidの場合、DTOクラスはアホにしてView Modelは頭をよくするようにすればいいハズ。。。
- kotlinのdata class(DTOクラス)はプロパティを定義するだけで、自動的に setter/getter が生成される

# 参考サイト
https://kotlin-study.com/getter-setter/#toc8

https://maku77.github.io/kotlin/basic/setter-getter.html
jetpack composeでcameraxとmlkitをつかってバーコード読み取り画面を実装するPart3

#  はじめに
今回も前回に引き続きJetpackComposeでのバーコード読み取り機能を実装していきます。
### 本文
下記のコードをViewModelに追加することで実際にコードを読み取った時にやりたい処理をすることができます
```kotlin
private val qrCodeFlow = MutableSharedFlow<Barcode>()

    val qrCodeAnalyzeUseCase: ImageAnalysis = ImageAnalysis.Builder()
        .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
        .build()
        .apply {
            setAnalyzer(
                Executors.newSingleThreadExecutor(),
                BarCodeScanner { barcode ->
                    viewModelScope.launch {
                        qrCodeFlow.emit(barcode)
                    }
                },
            )
        }

    init {
        intentRepeatOnSubscription { scope ->
            qrCodeFlow
                .debounce(100.milliseconds)
                .filter { state.isAnalysing }
                .mapNotNull { barcode -> barcode.rawValue }
                .onEach {
                    // やりたい処理を呼び出し
                }
                .launchIn(scope)
        }
    }
```
### 
画像解析部分の公式は下記にあります
https://developer.android.com/media/camera/camerax/analyze?hl=ja&authuser=1&_gl=1*1xafqf3*_up*MQ..*_ga*MTgzMjE2NzQ5Ni4xNzE2MTk1Mjc5*_ga_6HH9YJMN9M*MTcxNjE5NTI3OS4xLjAuMTcxNjE5NTI3OS4wLjAuMA..

次で最後になります
https://qiita.com/ryuji_sato/items/bdc34b7671d034543440
ITパスポート システム構成

・デュプレックスシステム
通常業務で使用している本番系（主系）と、その本番系の故障に備える待機系（従系）の二組のシステムで構成される方式
コールドスタンバイ
待機系を本番系へ切り替えるのに時間を要する
ホットスタンバイ
待機系を本番系へ直ちに切り替えることができる

・デュアルシステム
二組のシステムで構成され、常に同じ処理を行わせて結果を相互に照合することで、高い信頼性を得ることができる方式

・サーバの仮想化
１台の物理サーバ上で、あたかも複数のサーバが稼働しているかのように見せかける技術
・スケールアップ
CPUやメモリなどサーバ内部の部品を高性能なものに交換したり拡張したりする
・スケールアウト
サーバの台数を増やす
・ライブマイグレーション
仮想サーバで稼働しているOSやアプリケーションを停止することなく、他の物理サーバへ移し替える技術
・仮想化の形態
ホスト型、ハイパバイザ型、コンテナ型

・クラスタリング
複数のサーバを連携させて、全体として一つのサーバであるかのように動作させる技術

・グリッドコンピューティング
インターネット上に存在する複数のコンピュータを連携し、仮想的に１台の巨大で高性能なコンピュータを作る技術

・バックアップサイト
ホットサイト
ネットワークを介して常にソフトウェアやデータを更新
ウォームサイト
定期的にソフトウェアやバックアップデータなどを搬入して保管
コールドサイト
あらかじめ予備のサイトのみを確保

・BCP（事業継続計画）
災害やシステム障害などの予期せぬ事態が発生したとしても、重要な業務が継続できるように事前に策定される行動計画
・BCM（事業継続管理）
PDCAサイクルで継続的に維持・向上を図る
【JavaScript】文字列を変数名として認識させてみる

# はじめに
Blazor で、ExcelライクなグリッドJSライブラリの`Handsontable`を使用しています。

https://qiita.com/yaju/items/bcca337af393f15a6795

Blazor では JavaScript から C# を呼ぶことができます。一般的には Windowsオブジェクトに`DotNet`が予め定義されているため、「DotNet.invokeMethodAsync(C#に定義したメソッド)」のように呼びます。
この方法では、複数台で操作した時に問題が発生しました。

https://qiita.com/yaju/items/44b207477d1cb1c81bfb

その際に Windowsオブジェクトに`DotNet`の代わりとして、`ComponentReference`を定義した上で、「ComponentReference.invokeMethodAsync(C#に定義したメソッド)」としました。

```js
export class SpreadSheet {
  constructor(reference) {
    window.ComponentReference = reference;
  }

  // インスタンス作るためのメソッド
  static create(reference) {
    return new SpreadSheet(reference);
  }
```

# 問題
画面上に、このコンポーネントを利用した履歴一覧表示とチェックシート一覧表示が両方表示される状態になった場合、履歴一覧で全選択チェック処理(C#メソッドを呼ぶ)を呼ぶと JavaScriptエラーが発生していることが分かりました。

原因として、`window.ComponentReference`の変数が被っているため、チェックシート一覧表示がされた段階で変数内容が上書きされてしまい、履歴一覧表示側の全選択チェック処理が呼べない状態となっていました。

## 対応
`window.ComponentReference`の変数が被らないように、
履歴一覧表示は、`window.HisotryListReference`、
チェックシート一覧表示は`window.CheckSheetListReference`
と分けました。

# 本題
コンポーネントに変数用の文字列を引数として渡して変数名にできるのなら、より汎用的なコンポーネントに出来る。
そもそも、文字列を変数名として認識できるんだっけ？

## Chat GPTに聞いてみた
>JavaScriptで文字列を変数名として認識できますか

JavaScriptでは文字列を変数名として動的に扱うことができます。ただし、通常の変数名としてではなく、オブジェクトのプロパティとして扱う方法を使います。

以下に、いくつかの方法を紹介します。

### 1. オブジェクトのプロパティとして使用
JavaScriptでは、オブジェクトのプロパティに文字列を使うことができます。オブジェクトのプロパティにアクセスする際に、ドット記法 (object.property) のほかに、ブラケット記法 (object['property']) を使用することで、文字列をプロパティ名として扱えます。

```javascript
let variableName = "dynamicVariable";
let obj = {};

obj[variableName] = "This is a dynamically named variable";

console.log(obj.dynamicVariable);  // "This is a dynamically named variable"
console.log(obj[variableName]);    // "This is a dynamically named variable"
```

### 2. eval 関数を使う方法
eval 関数を使うと、文字列をJavaScriptコードとして評価し実行できますが、この方法はセキュリティやパフォーマンスの観点から推奨されません。

```javascript
let variableName = "dynamicVariable";
eval('var ' + variableName + ' = "This is a dynamically named variable"');

console.log(dynamicVariable);  // "This is a dynamically named variable"
```

### 3. window オブジェクトを使う方法 (ブラウザ環境の場合)
ブラウザのグローバルスコープでは、window オブジェクトを使用して動的に変数を作成することもできます。

```javascript
let variableName = "dynamicVariable";
window[variableName] = "This is a dynamically named variable";

console.log(window.dynamicVariable);  // "This is a dynamically named variable"
console.log(window[variableName]);    // "This is a dynamically named variable"
```

### まとめ
オブジェクトのプロパティとして文字列を使う方法が最も一般的で安全です。eval 関数の使用は避けた方が良いでしょう。ブラウザ環境では、window オブジェクトを使うこともできますが、これはグローバル変数を操作するため、注意が必要です。

# 最後に
採用するかは別として、出来ることは把握しました。

```js
export class SpreadSheet {
  constructor(variable, reference) {
    window[variable] = reference;
  }

  // インスタンス作るためのメソッド
  static create(variable, reference) {
    return new SpreadSheet(variable, reference);
  }
```
GitbashでDocker Desktopを起動し、volumeで親ディレクトリ..を指定する方法について

## TL;DR

`realpath ..`で親ディレクトリの絶対パスを指定する．

Windowsのgit bashでもLinuxのbashでも動く-vオプションの親ディレクトリ指定方法
```bash
#!/usr/bin/env bash
MSYS_NO_PATHCONV=1　docker run -it --rm -v $(realpath ..):/input alpine ls /input
```

Windowsのmingw makeでもLinuxのmakeでも動く-vオプションの親ディレクトリ指定方法
```makefile
.PHONY: all
all:
	MSYS_NO_PATHCONV=1 docker run -it --rm -v $$(realpath ..):/input alpine ls /input
```
>TL;DR= Too long; dont'read 長すぎるので読まない

## 背景

単純に`-v ..:/input`と指定するとエラーになる

```shell_session
$ MSYS_NO_PATHCONV=1 docker run -it --rm -v ..:/input alpine ls /input
docker: Error response from daemon: create ..: ".." includes invalid characters for a local volume name, only "[a-zA-Z0-9][a-zA-Z0-9_.-]" are allowed. If you intended to pass a host directory, use absolute path.
See 'docker run --help'.
```

use absolute pathとあるので親ディレクトリ`..`を`realpath ..`で絶対パスに変換するとGitBashのDocker Desktop for WindowsやRancher Desktop for WindowsでもLinuxでも正しく動作する

```shell_session
$ realpath ..
/c/Users/
$ MSYS_NO_PATHCONV=1 docker run --rm -v $(realpath ..):/input alpine ls /input # Docker Desktop
All Users
Default
Default User
Public
desktop.ini
lzpel
$ MSYS_NO_PATHCONV=1 docker run --rm -v $(realpath ..):/input alpine ls /input # Rancher Desktop
All Users
Default
Default User
Public
desktop.ini
lzpel
```

```shell-session
$ MSYS_NO_PATHCONV=1 docker run --rm -v $(realpath ..):/input alpine ls /input #CentOS
lost+found
misumi3104
```

Makefileでかくなら
```makefile
.PHONY: all
all:
	MSYS_NO_PATHCONV=1 docker run --rm -v $$(realpath ..):/input alpine ls /input
```
チームメンバーのバランスを考慮したタスクの公平な分配方法

#### 1. チームメンバーのスキルセットを把握する

まず最初に、チームメンバーそれぞれのスキルセットをしっかりと把握することが重要です。これにより、各メンバーがどのタスクに最適かを判断する基礎ができます。例えば、あるメンバーがAWSのサービスに精通している場合、そのメンバーにはクラウドインフラの設定や管理を担当してもらうと良いでしょう。

#### 2. タスクの難易度と優先度を明確にする

次に、各タスクの難易度と優先度を明確にします。これにより、タスクの分配がより公平かつ効率的になります。難易度が高いタスクは経験豊富なメンバーに、比較的簡単なタスクは新人や経験の浅いメンバーに割り当てると良いでしょう。また、優先度の高いタスクは早めに着手できるように計画します。

#### 3. タスクの見積もりをチーム全体で行う

タスクの見積もりは、チーム全体で行うことが推奨されます。これにより、各メンバーがタスクの内容や難易度を理解し、適切なフィードバックを提供できます。スクラムのプランニングポーカーなどの手法を用いると、見積もりがより正確になります。

#### 4. タスクの分配は透明性を持って行う

タスクの分配は透明性を持って行うことが重要です。チーム全体がどのようにタスクが分配されているかを理解し、納得できるようにします。これにより、不公平感が生じることを防ぎ、チームのモチベーションを維持できます。

#### 5. 定期的なフィードバックと調整

タスクの分配が適切に行われているかどうかを定期的に確認し、必要に応じて調整を行います。スクラムのスプリントレビューやレトロスペクティブを活用して、チームメンバーからのフィードバックを収集し、改善点を見つけましょう。

#### 6. クラウドサービスの活用

クラウドベンダーの提供する様々なサービスを活用することで、タスクの効率化が図れます。例えば、AWSのCodePipelineを使ってCI/CDを自動化することで、デプロイ作業の負担を軽減できます。また、AzureのDevOpsツールを使ってタスク管理を一元化することも有効です。

#### まとめ

チームメンバーのバランスを考慮し、タスクを公平に分配することは、スクラム開発において非常に重要です。スキルセットの把握、タスクの難易度と優先度の明確化、チーム全体での見積もり、透明性のある分配、定期的なフィードバックと調整、そしてクラウドサービスの活用を通じて、より効率的で公平なタスク分配を実現しましょう。

これらのポイントを押さえることで、チーム全体のパフォーマンスが向上し、プロジェクトの成功に繋がることを願っています。皆さんのスクラム開発がより良いものになることを期待しています！
ALBで複数のSSL証明書を使う際にハマったこと

# 目的
ALBのSNIサポートによって複数の証明書を選択した際に、クライアントからのHTTPSリクエストが失敗する問題が発生しました。そのためALBのSNIに関する注意点を備忘録としてまとめます。

# ALBのSNIサポートについて
ALBで複数のドメインを捌きたい際に、これまでは複数のALBを用意する必要がありました。しかしアップデートにより、同一のロードバランサで複数の証明書を使えるようになりました。
[Application Load BalancerがSNIを利用した複数のTLS証明書のスマートセレクションをサポートしました](https://aws.amazon.com/jp/blogs/news/new-application-load-balancer-sni/)

# HTTPSリクエスト失敗に至った経緯

エラー発生に陥ったイベントを時系列にまとめます。
(1) これまでサードパーティからACMへImportしたEVSSL(`prod.exaple.com`)が近日中に失効する。
(2) 応急処置として、ACM側で発行した証明書(`*.exaple.com`)をALBに追加。この時は2つのSSL証明書がアタッチされている。
(4) (1)でImportした証明書の期限が切れた後、クライアントからのHTTPSリクエストが失敗していることが発覚。


### 原因
#### ALBが選択する証明書の優先順位ロジックによるもの。
この問題が引き起こされるまでは複数の証明書がALBにアタッチされていたとしても、有効な証明書が自動で選択されると思っていましたが、ちょっと違いました。

↓↓↓↓↓以下公式Docより↓↓↓↓↓↓↓↓↓↓↓
ALBは以下の優先順位によって、複数存在する証明書から最適な証明書を動的に判断。
>ロードバランサーは、SNIをサポートするスマート証明書の選択アルゴリズムを使用します。クライアントから提供されたホスト名が証明書リスト内の単一の証明書と一致する場合、ロードバランサーはこの証明書を選択します。

[Application Load Balancer 用の HTTPS リスナーを作成する](https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/create-https-listener.html#https-listener-certificates)


つまり、今回の場合はサードパーティからImportしたEVSSL(`prod.exaple.com`)が、ACM側で発行した証明書(`*.exaple.com`)よりも優先順位が高く判断されたため、有効期限を迎えたEVSSLが引き続き使用されたことでHTTPS通信が失敗する問題が発生しました。


一応、ALBの証明書の選択アルゴリズムは下記の優先順位で判定されます。
・パブリックキーアルゴリズム (ECDSA よりも RSA を優先）
・ハッシュアルゴリズム (SHA よりも MD5 を優先）
・キーの長さ (最大が優先)
・有効期間

今回の場合はこのアルゴリズムの前にクライアントからのホスト名が、EVSSL(`prod.exaple.com`)に一致すると判断されて、有効期限を迎えても引き続き使われていました。（ALBログから確認）


# まとめ
今回はALBのSNIサポートによって複数の証明書を選択する機能でハマったところを共有しました。
有効期限を迎えた証明書は不必要にALBに残さないようにします。
GitHub ActionsでPythonを実行する

個人的「質はともかく継続する」１6日目です

# GitHub Actionsで言語を実行する

最近まで知らなかったのですが、GitHub ActionsでPython等の言語を実行することができるんだそう。よく考えれば、大体はUbuntuを仮想で動かしてるんだから当然の話しですよね。
早速、Pythonを動かすymlを書いてみました。

## Pythonを動かす

以下のように書けばpythonを動かせます。

```sh
jobs:

  build:
    runs-on: ubuntu-latest

    steps:
     
    - name: Checkout repository
      uses: actions/checkout@v4

    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: '3.x'

    - name: Run Script
      run: |
            python <<EOF
            import os
            print("Python動かせます")
            for f in os.listdir():
                print(f)
            EOF
```

結果。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45303/b2bc09c9-1106-983d-5ded-490537ace245.png)

Javaとか、.NET SDKもあるようなので色々と使えそうですね。
普段業務で使うことが少ないので、ちょっとずつ学習していこうかな。
【リハビリJS学習】瞑想アプリを作る②

JS学習のため、瞑想アプリ作成をする第二回。

↓前回はこちら
https://qiita.com/sakuc47/items/252a7d21bf658fcc61ee

---
### 8. `<svg class="moving-outline"〜> </svg> `の下に時間表示を追加する
```html
<h3 class="time-display">0:00</h3>
```

### 9. `<div class="sound-picker">`にボタンをマークアップする
雨とビーチの音・画像を選択できるようなボタン。
追加するボタンにはdataプロパティ　`data-sounds`と`data-video`を追加する。
```html
<div class="sound-picker">
    <button data-sound="./sounds/rain.mp3" data-video="./video/rain.mp4">
      <img src="./svg/rain.svg" alt="rain">
    </button>
    <button data-sound="./sounds/beach.mp3" data-video="./video/beach.mp4">
      <img src="./svg/beach.svg" alt="beach">
    </button>
</div>
```

:::note info
データ属性
jsではデータ属性にアクセスして、属性を取得したり書き換えたりできる。
CSSでも利用できる。
:::

https://developer.mozilla.org/ja/docs/Learn/HTML/Howto/Use_data_attributes

https://zero-plus.io/media/html-data/


### 10. バックグラウンドで再生するデフォルトのビデオを追加する
` <div class="app"> `直下にコンテナを追加

``` html
<div class="vid-container">
    <video Loop>
        <source src="./video/rain.mp4" type="video/mp4">
    </video>
</div>
```
- ムービーをループ再生したければ`<video Loop>`とする

現在の表示↓

![FireShot Capture 005 - Meditation App_瞑想アプリ - 127.0.0.1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524465/c1f1ab84-ebfc-7e72-dab7-e9bbb77d5604.png)

## 11. CSSを調整する
``` scss
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.app {
  height: 100vh;
  display: flex;
  justify-content: space-evenly;
  align-items: center;
}
.time-select,
.sound-picker,
.player-container {
  height: 80%;
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: space-evenly;
  align-items: center;
}
.player-container {
  position: relative;
  svg {
    position: absolute;
    height: 50%;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    pointer-events: none; // SVGが邪魔して再生ボタンを押せないため
  }
}

.time-display {
  position: absolute;
  bottom: 10%;
  color: #fff;
  font-size: 50px;
}

video {
  position: fixed;
  top: 0%;
  left: 0%;
  width: 100%;
  z-index: -1;
}
 ```

現在の表示↓
![スクリーンショット 2024-06-23 21.34.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524465/96268952-669c-16f7-e314-d54f8fe7ba32.png)


今回はここまで！
（なかなかjsまでたどりつかない）
VSCode キーボードショートカット チートシート (macOS版)

## はじめに
この記事で紹介するチートシートは、公式が出しているPDFファイルを日本語訳したものです。

https://code.visualstudio.com/shortcuts/keyboard-shortcuts-macos.pdf

macOS以外のOSや、他のショートカットについて知りたい方は以下の公式ガイドも参照してください。

https://code.visualstudio.com/docs/getstarted/keybindings

## チートシート
![keyboard-shortcuts-macos.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3362317/ea157c38-f6e0-48d8-fd6f-c34d54290f1d.png "keyboard-shortcuts-macos")

## 補足
同じ機能を持ったショートカットキーや、ここに記載されていない中で私がよく使うものについて少しですが紹介します。
| 項目 | キーバインド | 機能 | 補足 |
| --- | --- | --- | --- |
| Basic editing | Home / End | 行頭/行末へカーソル移動 | ⌘← / →でも同様 |
| Multi-cursor and selection | ⌃⇧⌘→ / ← | 選択範囲を拡張/縮小 | ⌃⇧→ / ← (⌘なし) でも同様 |
| Integrated terminal | ⌃` | 統合ターミナルを表示 | ⌘Jでも同様 |
| 記載なし | ⌘Backspace | カーソル位置の左側を全削除 | よく使う！ |
| 記載なし | ⌘Delete | カーソル位置の右側を全削除 | よく使う！ |
| 記載なし | ⌘ + double-click | ファイルを別グループで開く | たまに使う |

## おわりに
`⌘K ⌘S`で表示されるキーボードショートカット一覧からもわかるように、
VSCodeにはここに記載されている以外にもたくさんのショートカットが存在し、
自分でカスタマイズすることもできます。
私自身まだまだ知らない機能が多いので、まずはこのチートシートから使いこなせるものを増やしていきたいと思います。
【Pybulletサンプル解説】シミュレーションを保存し、再生する【commandLogAndPlayback.py】

お疲れ様です。秋並です。

Pybullet公式gitリポジトリのサンプルコードを解説するシリーズです（一覧は[こちら](https://qiita.com/akinami/items/7b433b60aeb5115ba4d7)）。

<br>

今回は、commandLogAndPlayback.pyを解説します。（コードのリンクは[こちら](https://github.com/bulletphysics/bullet3/blob/master/examples/pybullet/examples/commandLogAndPlayback.py)）

本コードを実行すると、シミュレーションをログファイルに保存されます。その後、保存したログファイルを読み込むことでシミュレーションが再度実行されます。

![commandLogAndPlayback.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2030125/1bd3718b-a003-3a09-0391-5da792929a1f.gif)


# 使用している機能
本コードは、以下の機能を使用して「シミュレーションをログに保存したのち、ログから再度シミュレーションを実行」しています。

- シミュレーションのログの保存
- シミュレーションのログの読み込み

## シミュレーションのログの保存

pybulletでは、`startStateLogging`関数を使用することで「シミュレーションのログ記録の開始」することができます。
```
logId = pybullet.startStateLogging(logMode, logFile)
```
- `logMode`：モードを指定
    - `pybullet.STATE_LOGGING_ALL_COMMANDS`：すべてのコマンドを記録するモード
    - `logFile`：保存するログのファイル名


<br>

次に、`stopStateLogging`関数を使用することで「シミュレーションのログ記録の停止」をすることができます。
```
pybullet.stopStateLogging(logId)
```
- `logId`：ログのID

## シミュレーションのログの読み込み
`startStateLogging`関数を使用することで「ログを読み込み、シミュレーションを実行」することができます（ログの記録の時と同じ関数を使用します）。
```
logId = pybullet.startStateLogging(logMode, logFile)
```
- `logMode`：モードを指定
    - `pybullet.STATE_REPLAY_ALL_COMMANDS`：すべてのコマンドを再生するモード
    - `logFile`：保存するログのファイル名
    
# コメントをつけたサンプルコード
サンプルコードにコメントをつけたものが以下になります（もともとあった不要と思われるコメント等については削除しています）

```python
import pybullet as p
import time
import pybullet_data

# PybulletをGUIモードで接続
p.connect(p.GUI)

# Pybulletに関するデータのパスを取得
p.setAdditionalSearchPath(pybullet_data.getDataPath())

# ログの記録を開始する
logId = p.startStateLogging(p.STATE_LOGGING_ALL_COMMANDS, "commandLog.bin")

# 床とr2d2を生成
p.loadURDF("plane.urdf")
p.loadURDF("r2d2.urdf", [0, 0, 1])

# ログの記録を停止
p.stopStateLogging(logId)

# シミュレーション空間をリセット
p.resetSimulation()

# ログを読み込みシミュレーションを実行
logId = p.startStateLogging(p.STATE_REPLAY_ALL_COMMANDS, "commandLog.bin")

# Pybulletに接続されている間ループを継続
while (p.isConnected()):
  time.sleep(1. / 240.)
```