OmniAICreator/Qiita-1.07M huggingface dataset:
gitlab で長年何もActivityがないレポジトリが最近updated と表示される件について

## 概要

gitlab で例えば

`my_awsome_rust` というレポジトリを持っていたとして

![Screenshot 2023-12-12 at 12.13.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519792/313a076f-a032-ba67-6596-69114363b38a.png)

このレポジトリ、２日前にアップデートされたという表記になっていますが、
Activity を見てみると最後にコミットや何かしらのアクティビティがあったのは数年前でした。

なぜ数年このレポジトリは触っていないのに、２日前にアップデートがあったかのように表示されてしまっているのか、

少し調査したのでこちらに備忘録としてまとめておきます。



## 結論

gitlab のバグ（というより仕様）であり、最近イシューとして議論されていました。
現在解決するために運営が動いているようです。

>  “last_activity_at”, “last_repository_updated_at”, and “updated_at”. Whichever one of these is most recent will be displayed. 

この３つの表記のうち、一番新しいものが自動的に表示されるような機構になっており、
最後の`updated_at` はgitlab のバージョンアップデートや、内部システムのキャッシュに関わるdatetime が入るとのことで、
この`updated_at`がレポジトリの`updated`を更新するのはシステム上ふさわしくないので、改修が入りそうです。


## ソース

https://forum.gitlab.com/t/weird-updated-at-time/93664/9

こちらにまとめられています。

詳細を知りたい人は

https://forum.gitlab.com/t/why-does-a-project-show-updated-4-days-ago-when-it-hasnt-been-updated-for-three-months/49903/7

こちらから。




今回はこの辺で。


@kenmaro
Macでパスワード付きZIPファイルを作成する方法

## アジェンダ
Macでは、セキュリティを強化するために、重要なファイルや文書をパスワード付きのZIPファイルとして圧縮することができます。ここでは、ターミナルを使用してこの操作を行う簡単な方法をご紹介します。

## 必要なツール

- Macコンピュータ
- ターミナルアプリケーション（Macに標準でインストールされています）

## 手順

### ステップ1: ターミナルを開く

1. 「Finder」を開きます。
2. 「アプリケーション」フォルダに移動し、「ユーティリティ」を開きます。
3. 「ターミナル」アプリケーションを見つけて開きます。

### ステップ2: ZIPファイルを作成

ターミナルで、圧縮したいファイルがあるディレクトリに移動します。例えば、デスクトップにある「test.txt」というファイルを圧縮する場合は、以下のように入力します。

```bash
cd ~/Desktop
```

次に、以下のコマンドを使用してパスワード付きのZIPファイルを作成します。

```bash
zip -e test.zip test.txt
```

このコマンドを実行すると、パスワードの入力を求められます。パスワードを入力し、確認のために再度入力します。

### ステップ3: ZIPファイルの確認

コマンドの実行が完了すると、指定したディレクトリに「test.zip」という名前のパスワード付きZIPファイルが作成されます。このファイルを開く際には、設定したパスワードの入力が求められます。

## 注意点

- パスワードは忘れないようにしてください。パスワードを忘れると、ZIPファイルの内容にアクセスできなくなります。
- パスワードは強固なものにすることをお勧めします。短いまたは簡単なパスワードは、セキュリティ上のリスクとなります。

## まとめ

Macのターミナルを使用してパスワード付きのZIPファイルを作成する方法は、簡単で効率的です。この方法を使えば、重要なファイルを安全に保管し、共有することができます。
無名関数で🌸花を描いてみる

・　自分で関数（式）を作る
・　極座標と直交座標
・　ベルヌーイのスケート曲線

# ベルヌーイのスケート曲線

スケート曲線の式は、こんな感じです　どんな風かはすぐには想像できないですが、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333980/67149953-b353-fb66-4a14-3e42f4e04a9e.png)

下のwikipediaのサイトにある動画では、こんな風に双曲線を元に図式化してあります 

双曲線の接線（青い太い線）に、原点から接線（赤い太い線）をおろしていき、交差した点がスケート曲線（細い赤い線）になるようです　原点と青い太い線の距離が最も短くなる点ということですね
<br>
<img src = "https://upload.wikimedia.org/wikipedia/commons/f/f1/Lemniscate_of_Bernoulli.gif">


<a href "https://ja.wikipedia.org/wiki/%E3%83%AC%E3%83%A0%E3%83%8B%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%88">ベルヌーイのスケート曲線について</a>はリンクの説明をお読みください

<a href "https://ja.wikipedia.org/wiki/%E3%83%AC%E3%83%A0%E3%83%8B%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%88">・　ベルヌーイのスケート曲線（日本語）</a>

<a href "https://en.wikipedia.org/wiki/Lemniscate_of_Bernoulli">・　Lemniscate_of_Bernoulli (English) </a>
<br>


# 名前の由来
数学者のヤコブ・ベルヌーイさんの名前がついています　ヤコブ・ベルヌーイさんとヨハン・ベルヌーイさんは、兄弟で有名な数学者だそうですが、ベルヌーイさんの家系は、ベルヌーイ試行とベルヌーイ数、ベルヌーイの法則など、たくさんあって何かの時に聞いたことがありますね
<br>

# 描画
さあ、描いてみましょう　手元にMATLABがあるので、それを使ってプロットしています　コードは図の後に付けてます  角度（theta）なので t を使って作ります

<img width = 480 src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333980/fc896cc0-f3f9-53f8-3380-cd8377a3d606.png">

```MATLAB:bernoulli

clear;

t = 0:.0001:pi * 2;

r = @(t) sqrt(cos(2*t) ) ;

figure;
plot(r(t).*cos(t), r(t).*sin(t), '.');
axis equal;
axis off;
```

少し変形して花のバリエーションを作ってみました　

「スケート曲線」なので、ほんとは角度を狭めて　∞　（無限のマーク）のとこだけ描くものなのかもしれませんが、360° ( 2 × π )にしたら四葉のクローバー型になりました

<br>

<img width = 480 src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333980/e89bf4e6-0da9-e980-4156-d74b7b56bb7e.png">



```MATLAB:original

clear;

t = 0:.0001:pi * 2;

func = @(t) sqrt(cos(2*t) ) ;

rsqared = func(t);

r = sqrt(rsqared);

figure;
plot(r.*cos(t), r.*sin(t), '.');
axis equal;
axis off;
```

abs（absolute）をひとつ入れると花弁が同じ大きさに
なお、デフォルトで、sqrtから先の計算には複素数の変数が使われてます

<img width = 480 src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333980/069f615e-4b42-860e-976e-3d0989a9502d.png">


```MATLAB:version2

clear;

t = 0:.0001:pi * 2;

func = @(t) sqrt(cos(2*t) ) ;

rsqared = func(t);

r = sqrt(abs(rsqared));

figure;
plot(r.*cos(t), r.*sin(t), '.');
axis equal;
axis off;
```

45° 回転した場合 cos => sin　に変えるとこんな風に回転します

<img width = 480 src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333980/cf3d50c1-591b-6705-c613-e2eeabb9c414.png">


```MATLAB:rotated

clear;

t = 0:.0001:pi * 2;

func = @(t) sqrt(sin(2*t) ) ;

rsqared = func(t);

r = sqrt(rsqared);

figure;
plot(r.*cos(t), r.*sin(t), '.');
axis equal;
axis off;
```

originalをもとに、菊の花にしてみました（季節柄）

<img width = 480 src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333980/6a243423-df77-dfe1-6a30-d652785ec8ad.png">


```MATLAB:chrysanthemum
clear;

t = 0:.0001:pi * 8;

func = @(t) sqrt(cos(2*t) ) ;

rsqared = func(t);

r = sqrt(rsqared);

figure;
plot(r.*cos(t/4), r.*sin(t/4), '.');
axis equal;
axis off;
```

<br>
<br>
クリスマスまでには、これを利用して立体のモミの木を作ってみる予定です

<br>
<br>

https://qiita.com/emikosh/items/6fee5c6291a5d0f264cf

<br>
<br>
重複したタブを一度に閉じる拡張機能を作成

## はじめに
自分はブラウジングをしている際、気づけば多くのタブを開いたままにしてしまい、数が物凄いことになってしまう場面がよくあります。
その状況を少しずつ緩和するために、Chrome の拡張機能の勉強もしながら自分でタブ整理を行う機能を作ってみることにしました。

## ２つ以上同じ URL のページを開いているタブを閉じる
自分の場合、よく閲覧するページを既に他のタブで開いているのに、新たに別のタブで開き直してしまい、結果的に同じ URL のタブが複数できてしまうことがよくあります。
なので、同じ URL のタブが２つ以上ある場合、１つ以外は閉じてしまう機能を作ってみたいと思います。

## 拡張機能を作成していく
### ファイル構成
```
manifest.json
popup.html
popup.js
```

#### manifest.json
```json
{
  "name": "Tab duplicate resolution",
  "description": "Tab duplicate resolution",
  "version": "1.0",
  "manifest_version": 3,
  "action": {
    "default_popup": "popup.html"
  },
  "permissions": [
    "tabs"
  ]
}
```

今回は、誤ってアイコンをクリックしてしまった際にそのままタブが閉じられるのを防ぐため、
ツールバーに表示された拡張機能のアイコンをクリックし、
表示されたポップアップの中身を更にクリックすることで重複しているタブが閉じられるようにします。

そのため、
```json
  "action": {
    "default_popup": "popup.html"
  }
```
でポップアップする html の指定を行っています。

また、今回はタブの情報が必要となるため、
```json
  "permissions": [
    "tabs"
  ]
```
上記のように tabs の許可を行っています。

#### popup.html
```html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>popup</title>
    <style>
      body{
        width: 230px;
      }
      button{
	    background-color: transparent;
	    border: none;
	    cursor: pointer;
      }
    </style>
  </head>
  <body>
    <button id="tabCountMessage"></button>
    <script src="popup.js"></script>
  </body>
</html>
```

拡張機能のアイコンをクリックした際に表示する、ポップアップの中身を記載します。
今回は、`tabCountMessage` を指定している箇所に重複しているタブの数を記載し、それをクリックすることでタブが閉じられるようにします。
また、最低限の style を指定して見た目を整えています。

#### popup.js
```js
let duplicateTabs = []

chrome.tabs.query({}, tabs => {
  tabUrls = tabs.map((tab) => tab.url)

  duplicateTabs = tabs.filter((tab, index) => {
    return tabUrls.indexOf(tab.url) !== tabUrls.lastIndexOf(tab.url) && tabUrls.indexOf(tab.url) < index
  })

  document.getElementById("tabCountMessage").innerHTML = "重複している"+ duplicateTabs.length+"個のタブを閉じる"
})

document.getElementById("tabCountMessage").addEventListener("click", async () => {
  duplicateTabs.forEach((tab) => {
    chrome.tabs.remove(tab.id)
  })

  window.close()
})
```

ポップアップで動作するスクリプトです。

```js
chrome.tabs.query({}, tabs => {
  tabUrls = tabs.map((tab) => tab.url)

  duplicateTabs = tabs.filter((tab, index) => {
    return tabUrls.indexOf(tab.url) !== tabUrls.lastIndexOf(tab.url) && tabUrls.indexOf(tab.url) < index
  })

  document.getElementById("tabCountMessage").innerHTML = "重複している"+ duplicateTabs.length+"個のタブを閉じる"
})
```

上記の部分で、ポップアップが表示された際に閉じられる予定のタブの数を数え、`tabCountMessage`を指定した要素に表示するようにしています。


```js
document.getElementById("tabCountMessage").addEventListener("click", async () => {
  duplicateTabs.forEach((tab) => {
    chrome.tabs.remove(tab.id)
  })

  window.close()
})
```
そして、`tabCountMessage`を指定した要素がクリックされた際に
重複したタブの削除を行い、そのままポップアップを閉じるようにしています。

## 動かしてみる


![tab.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247154/6310da85-b61c-17ba-367f-b362bb3b0f0b.gif)

無事、重複したタブを閉じてくれました！
monitを使ってサーバー監視

# monitとは

本記事では簡易監視ツールのmonitについてご紹介します。monitはオープンソースのツールで一定周期で監視し、設定したイベント検知すると自動でコマンドを実行してくれる便利なツールです。

 **関連リンク** 
 [ モニト](https://mmonit.com/monit/) 

#monit設定

 **インストール** 

まずmonitをインストールしましょう。epelリポジトリからyumで簡単にインストールすることができます。

```
yum install epel-release
```

```
 yum install monit
```
#監視基本設定
インストールが無事に成功したら以下の設定ファイルからmonitの設定を行っていきます。※バージョンやディストリビューションによって設定ファイル名は異なるのでご注意ください。


```
# vi /etc/monitrc
```
監視の周期を確認します。秒単位で設定が可能です。あまり周期が短いと負荷がかかるためデフォルトの30秒で設定しています。

```
 set daemon  30              # check services at 30 seconds intervals
```
monitはsyslogでの出力が可能です。特定のログファイルに出力したい場合は、ここにフルパスを記載します。後ほど記載しますが、デフォルトで/var/log/monit.logにもログは出力されます。

```
set log syslog
```
#監視内容設定
Apacheを監視するように設定する

```
# vi /etc/monit.d/httpd

check process httpd

with pidfile "/var/run/httpd/httpd.pid"          #監視対象プロセスを指定

start program "/bin/systemctl start httpd"    #プロセス起動のコマンド指定

stop program "/bin/systemctl stop httpd"    #プロセス終了のコマンド指定

if failed port 80 with timeout 10 seconds then restart   #80番ポートが10秒タイムアウトしたら再起動する

if failed port 443 with timeout 10 seconds then restart  #443番ポートが10秒タイムアウトしたら再起動する

if 10 restarts within 10 cycles then unmonitor  #10回中10回再起動したら監視を止める
```
#設定確認
以下コマンドで設定の文法チェックを行ってくれます。

```
# monit -t
> Control file syntax OK と出ることを確認
```
monitを起動し、自動起動設定を行います。

```
# systemctl start monit

# systemctl enable monit
```

monitが起動したことと、自動起動されるようになったことを確認する

```
# systemctl status monit

# systemctl is-enabled monit
```
これにてmonitのインストールは完了です。
Vive Tracker {2018, 3.0} 対応のドングルを Logicool Unifying Receiver から生成する

# はじめに

- メモです
- 動作の保証は勿論できません

# 概要

- ViveTracker のドングルは単品で買うと高い
    - 純正品は [iFixit で $49.99](https://www.ifixit.com/products/htc-vive-tracker-dongle-3-0) 
    - Amazon で変える互換性のあるものも 5000円程度
    - [IntoFree](https://market.intofree.world/products/steamvr-dongle)では 2750円だった
    - ドングル如きにこの値段払いたくない
- [watchman dongleを自作するブログ](https://ugokutennp.hatenablog.com/entry/2021/12/13/230401)を発見
    - 同じチップを積んでるもののファームウェア書き換えでどうにかなりそう
    - Logitech Unifying Receiver も同じチップを積んでいるが、ファームウェア書き込みガードにより難しい
    - Receiver 自体は中古で 500~1000円で入手できるので嬉しい
- ガードを搔い潜ってファームウェア書き換えればいけるのでは？
- [それをやっている人がいた](https://steamcommunity.com/app/507090/discussions/0/5174040687100682988/)
- 同様の手順でやればできた

# 作業メモ

##### 1.  Logicool の Unifying Receiver 購入

logicool は logitech の日本法人なので、チップも同じ？という推測の元、メルカリで買いました。500円。

注意点

- オレンジマークがあるもの
- 型番は C-U0007 
    - 型番が異なる場合チップが異なることがある
- プラスチック部分にくぼみがあるもの
    - ないものはファームウェアのバージョンが新しいため

##### 2. 以下のページに従いファームウェア書き換え実行

コードをコピペするのも無駄なので参照してください。

[Programming the watchman dongle firmware to alternative nRF24LU1+ USB devices](https://steamcommunity.com/app/507090/discussions/0/5174040687100682988/?ctp=2)

Win/Linux での方法が提示されていますが、私は Linux の方でやりました。

##### 3. 動作確認

通常の Tracker 接続の要領で接続可能でした。

写真そのうち張ります。

# 終わりに

最悪自分でファームウェア書き換えればいいかと思っていたが、ラクにできた。

先人に感謝。
【Udemy】基本情報技術者試験対策おすすめ講座

# はじめに
内定をいただいた会社が入社前学習でUdemy使い放題だったので
**基本情報技術者試験**対策に役立った講座をまとめておく

## 講座
1. ～始めから効率よく学ぶ～基本情報技術者試験最速 合格講座
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627466/f91eb572-4ee4-adbe-cafb-42448100a7cd.png)
独学での習得が難しい部分だけを集中して学習できる
<br>

2.令和5年版:現役講師が教える【基本情報技術者試験　科目A】
　基礎理論から経営戦略までの全範囲を網羅
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627466/79a003da-51a5-bb79-04cd-d741670e16ee.png)
科目Aを徹底して学習でき、しっかり理解することができる
<br>

3.令和5年版:現役講師が教える【基本情報技術者試験　科目B】
　Javaプログラミング言語を使った、科目B対策専門コース
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627466/c9d772f1-4deb-81ae-0da2-ac0012c0e64e.png)
科目Bを徹底して学習でき、しっかりと理解することができる
画像投稿のプレビュー表示してみた

# やること
Flaskで画像を投稿するときに、実際に投稿する前にプレビューでどんな画像が選択されているか表示する機能を作ります
Flaskでやってますが、実際の機能はHTMLだけで完結します
### 完成版
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2586059/8450f216-0ce8-ffc1-5dbe-b4436fd75dd1.png)
投稿する前にどんな画像が選択されているかを表示します

### Github
https://github.com/naoya25/flask-img-preview

# 実装
```html
<h1 class="text-3xl font-bold mb-4">Image Upload and Preview</h1>

<form
  action="{{ url_for('upload') }}"
  method="post"
  enctype="multipart/form-data"
  id="upload-form"
  class="max-w-sm mx-auto bg-white p-6 rounded shadow-md"
>
  <input
    type="file"
    name="file"
    id="file-input"
    accept="image/*"
    onchange="previewImage()"
    class="mb-4 p-2 border border-gray-300 w-full"
  /><br />
  <img
    id="image-preview"
    src="#"
    alt="Image Preview"
    class="mb-4 w-full"
    hidden
  /><br />
  <button type="submit" class="bg-blue-500 text-white p-2 rounded">
    Upload
  </button>
</form>

<script>
  // プレビュー表示
  const previewImage = () => {
    const fileInput = document.getElementById("file-input");
    const imagePreview = document.getElementById("image-preview");

    if (fileInput.files && fileInput.files[0]) {
      const reader = new FileReader();
      reader.onload = (e) => (imagePreview.src = e.target.result);
      reader.readAsDataURL(fileInput.files[0]);
      imagePreview.hidden = false;
    }
  };
</script>
```
大事なのは`script`タグだけです
FileReaderで画像を受け取って用意しておいた`img`タグにsrc設定して終わりです！

バイバイ〜〜〜
OpenAI（ChatGPT）でAzure AI Searchでベクター化したデータを利用する

本記事は [OpenAI活用法 Advent Calendar 2023 by ナレコム](https://qiita.com/advent-calendar/2023/openai-knowledgecommunication) の9日目の記事です。

OpenAI活用法 Advent Calendar 2023 by ナレコム ではGPTsを含めた最新のOpenAIの活用法について紹介します。

### はじめに

前回の記事「Azure OpenAI Studioを活用した効率的なチャットアシスタント構築」では、Azure OpenAI Studioを使ってデータソースを追加し、チャットアシスタントをセットアップする方法を解説しました。今回の記事では、その続きとして、ベクター化した大量データの実用性と注意点に焦点を当てます。特に、文章の引用と検索性能の最適化、Azure AI Searchでのチューニングの難易度、およびキーワード検索の挙動に関して詳しく掘り下げていきます。この情報を活用し、より精度の高いAIベースのアシスタントを構築しましょう。

### 準備

前回の記事を参考にお願いします

https://qiita.com/akiraokusawa/items/68cc2c6a5912ebe09013

### OpenAIでベクター化したデータを利用する

1. [Azure OpenAI Studio](https://oai.azure.com/) にアクセスし、左メニュー「チャット」を選び、 **アシスタントのセットアップ** の「データの追加（プレビュー）」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61189/cf988ce9-2733-3260-d29a-2663e10ba833.png)
1. 「データソースの追加」をクリックし、データ追加ウィンドウを立ち上げます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61189/7f62d890-33bb-845e-e978-1b0c3122e03d.png)
1. 以下のように選択します。
データ ソースを選択する⇒**Azure AI Search**
サブスクリプション⇒**前記事でベクター化を実行したサブスクリプション**
Azure AI Search Service⇒**前記事でベクター化を実行したAzure AI Search**
Azure AI Search インデックス⇒**前記事でベクター化したインデックス**
ベクトル検索をこの検索リソースに追加します。⇒**チェック**
埋め込みモデルを選択する⇒**前記事で準備したOpenAIの埋め込み(embedding)モデル**
Azure AI Searchアカウントに接続すると、アカウントが使用されるようになることに同意します。⇒**チェック**
1. 「インデックス データ フィールドのマッピング」では以下のように選択します。
コンテンツデータ⇒**chunk**にチェック
1. 「データ管理」では以下のように選択します。
検索の種類⇒**ハイブリッド＋セマンティック**（ベクトル、ハイブリッド(ベクトル＋ハイブリッド)でも可だが、性能が異なる）
既存のセマンティック検索の構成を追加する⇒**前記事でベクターに自動的に下図のようなものが追加されているので選択**
両方の項目にチェック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61189/99e87ae7-dc74-5b02-d06a-4eb3fe3f5c6a.png)
1. 確認画面が表示されるので「保存して閉じる」

完了すると以下のようにアシスタントにデータソースに選択したソースが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61189/b47cf1b9-267d-8012-a602-7bb49e51348f.png)

実行すると以下のようにAI Searchに登録したデータを参照した回答を返してくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61189/1fbaae54-4b45-d655-5c71-d690d86e003e.png)


ベクター化した大量データを利用することは魅力ですが、現時点での注意事項としては、
1. 主に文章の引用に依存し、複雑な文章の再構成や要約には限界があります。例えば、全体の文章からいい感じに必要な情報をまとめて欲しい、などは出来ないと思ったほうが良い
1. 検索性能は主にAzure AI Searchに依存し、望む回答を得るためには高度なチューニングが必要です
1. 『「〇〇」と検索して』など特定のキーワードでの検索を指示しない限り、AIがどのようなキーワードで検索するか予測するのは困難です
1. キーワードに複数の回答が存在する場合、回答は検索のヒットスコア順で表示され、文脈に適した部分を特定するのは難しい場合があります。対応策としては人間の問い合わせ文章を変える必要がある

### まとめ

本記事では、Azure OpenAI Studioを利用してチャットアシスタントにデータソースを追加し、ベクター化したデータを活用する方法を探求しました。重要な点として、文章の引用の限界、検索性能に関するAzure AI Searchの依存性、およびキーワード検索の挙動について説明しました。これらの知見は、AIアシスタントの構築と最適化において役立つでしょう。

---

また、ナレッジコミュニケーションでは  **「[Musubite](https://recruiting.musubite-job.com/features/company/knowledge-communication)」** というエンジニア同士のカジュアルトークサービスを利用しています！この記事にあるような生成AI 技術を使ったプロジェクトに携わるメンバーと直接話せるサービスですので興味がある方は是非利用を検討してください！

https://recruiting.musubite-job.com/features/company/knowledge-communication
【ChatGPT無】にコロナについて尋ねた。

  
　どうも、カーブミラーです。

　今回は、コロナについて、尋ねました。

:::note info
本記事は、ChatGPT（無料版）で
行なっております。GPT4での確認
はできておりません。あしからず。
:::
　本題の前に、まずは、
　　昨日の記事について、です。

　今朝（2023/12/12）、
　　@yyoshino1様から
　　　コメントをいただきました。

　@yyoshino1様も
　　試された模様。
　　　その際のログを
　　　　載せてくださいました。
　　　　　詳しくは、そちらを
　　　　　　ごらんください。

　見ると、Gemini PROかを
　　尋ねています。

　Bardは、
　　そうだ、と返しています。

　この点は、
　　私と同じですね。

　さらに続けての問いに、
　　Bardは、URLを出してきますが、
　　　リンクがとおっていません。

　それを問うと、
　　“ウソっぱちでした”と白状。

　やはり、Bardの言うことは
　　信じちゃいけない、
　　　ということのようですね。

　コメントくださった
　　@yyoshino1様、
　　　ありがとうございました。

　（なお、この部分は、
　　　昨日の記事の最後に
　　　　追記してあります）
***
　本題に入ります。

　なぜ、コロナ？と
　　思った方もおいでかと思います。

　実は、
　　先週木曜日（2023/12/07）から
　　　体調を崩しておりました。

　身体が震える寒さのため、
　　家から出られずじまい。

　空咳のために
　　ノドも痛くなり、
　　　食事もノドを
　　　　うまく通りませんでした。

　月曜日（2023/12/11）、
　　動けるようになったので、
　　　病院で診てもらおうと
　　　　行ったところ、
　　　　　風邪症状のある人は
　　　　　　中に入れず、
　　　　　　　予約しろ、と
　　　　　　　　言われました。

　まぁ、入り口付近には、
　　たくさんの方々が
　　　たむろっていましたので、
　　　　自分と同等なのだろう、と
　　　　　判断して、予約を取り、
　　　　　　近場の図書館へ。
　　　　　　　予約は１時間後。

　で、予約時間に行ったら、
　　鼻に棒を突っ込まれて。
　　　そこから２時間、
　　　　外で待たされて、
　　　　　ようやく中で診察、
　　　　　　という名の結果発表。

　インフルエンザの反応はなく、
　　コロナである、との診断。

　はい、コロナ認定受けましたw
***
　まぁ、そういう理由です。

　そして、現在、
　　引きこもりニート中w

　でも、こういうときって、
　　頭が働かないのよねぇ……。

　なので、
　　とりあえず、
　　　聞いてみたわけですw
***
***User***
コロナになりました。
すでに山を越え、快方に向かっています。
でも自宅療養を言い渡されています。

どうしてですか？

***ChatGPT***
お大事にしてください。自宅療養は、他の人への感染リスクを最小限に抑えるための一般的な措置です。自宅での療養が終われば、周囲の安全を確保しつつ元の日常に戻れるでしょう。家で十分な休息をとり、医師の指示に従うことが重要です。
***

　まぁ、体調を整えなさい、
　　という話と思って、
　　　養生します。

　今回は、ここまで。
LPIC/Linux学習記録#7

〇自戒のための自己への宣誓
1. お前に足りないのはインプットだ！！！インプットしろ！！！インプットの奴隷になれ！！！
2. 記事の書き方とか今はどうでもいいから書け！！！インプットをアウトプットしろ！！！やる前からこだわりとか持つな！！！
3. 見られることとか評価されることとか気にするな！！！MECEとか構造化されてるかどうかとか気にするな！！！構造化はアウトプットの整地であって、インプットが足りないお前が手を出す領域ではない！！！ていうかお前頭良いんだからインプットに注力しろ！！歴史を刻め！！！歴史をまとめようとするな！！！未来を描け！！過去を清算するな若者め！！！！
4. 疑問を持つことを恥じるな！！！お前は頭はいいがインプットが足りない未熟者だ！！！インプットの奴隷になれ（再掲）！！！

〇学習記録
カーネルっていうOSの中核があるらしい。カーネルを操作するのがシェルであり、他のOS構成要素はブートローダーやデーモンなどがあるらしい。

カーネルの機能には、
①プロセス管理
②メモリ管理
③ファイルシステム管理
の３つがあるらしい。

①プロセス管理
プロセスの生成、割り当て、実行、停止、スケジューリングなどを管理するらしい。
プロセス＝処理＝アプリケーションが実行される単位。
プロセスを管理して、システムのリソースを適切に割り当てるらしい。

②メモリ管理
メモリの割り当て、解放、スワップなどを管理するらしい。→スワップて何？→仮想メモリのことらしい。
→仮想メモリってことは、仮想化したPCに割り当てるものとかのことなのかな？
→物理メモリがいっぱいになったときに、使っていないメモリ部分をSSDなどのハードディスクに一時的に移す（スワップする）機能に関連するっぽい。

③ファイルシステム管理
ファイルシステムのマウント、アンマウント、ディレクトリ操作、ファイルの読み書きなどを管理するらしい。
アプリケーションがファイルを読み書きできるようになり、システムのストレージリソースを最適化できるらしい。

カーネルにはバージョンがあるらしい。
AA.BB.CC-xxxx
AA:メジャーバージョン。大きな変更。
BB:マイナーバージョン。機能追加や改善。
CC:パッチレベル。セキュリティやバグ修正。
Edge120とプロキシ環境でHTTPS接続エラー発生になった話

## プロキシフィルタリング有り環境下で、Edge120に更新されたらHTTPのみでサービスされているサイトが表示できなくなった
直近ハマった話から記事をつくってみました。

- 現象
フィルタリング有りのプロキシ環境でEdge120に更新された。
HTTPのみでサービスしているサイトに検索結果から飛ぶ。
このときブラウザがHTTPS接続試行してしまう。
プロキシが代行復号していて、正常なHTTPS接続エラー画面を出してとまってしまう。
なお、HTTPサイト直入力は問題無く表示できてる。


- 対策
Edgeのリファレンスに載ってないように見えるけど、ポリシーには存在する「HttpsUpgradesEnabled」をfalseに設定して対応。
これで勝手にHTTPSに接続試行しなくなった。
プロキシ無しの直アクセス環境であれば、https試行→失敗がブラウザで判断出来るんだろうけどプロキシ環境だとデータ返ってくるからダメだったんだろうと。
AutomaticHttpsDefaultは関係無かった。  
- レジストリ追加コマンド（管理者権限）
`reg.exe add "HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Edge\Recommended" /v HttpsUpgradesEnabled /t REG_DWORD /d 0 /f`　　




- あと
ChromeにはFlagsに設定値[HTTPS Upgrades]がちゃんとあるのに、Edgeにはない。
YouTubeに5.1chオーディオの動画を上げる

AppleTVやChromeCastなどをアンプなどにつないでいると
Youtubeでも5.1ch再生ができそうなのだが、どうやってあげると再生されるのか気になったので調べてみた

# まず、5.1ch素材を用意する。
マルチチャンネルで、6chwavを作る
チャンネル内訳は（L,R,C,LFE,sL,sR)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96808/fb82f9d3-f52c-3c27-ad41-fbb8b5dc922a.png)
NuendoでなんとなくAtomsミックスしつつ
ADMではなくマルチチャンネルミックスとして出力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96808/6e801ed7-cd2f-380d-3d00-b462a32505ec.png)

# 6chのWavができる　（SoundForgeで開いたところ）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96808/ac4505bb-3a24-dbb9-cb78-76b6c0234e94.png)

サウンドの構成で設定しておくと
wavファイルはWindowsのエクスプローラーでもマルチチャンネル再生できるようだ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96808/d99e5aac-9ebf-91af-2cec-0d08340f1a62.png)

# Vegasでも5.1ch再生は可能だったが
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96808/a6c17e4b-0f73-d419-bb35-3351c04564c9.png)
出力したファイルではステレオにダウンミックスされてしまうようだった
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96808/91a7a3f3-871f-ada0-5f9d-80e74b38dc7b.png)

# ffmpegでaacトラックを追加したらどうだろうか

## まずaacに変換

``` 音が悪い.bat
>ffmpeg -i Test51.wav -c:a aac -b:a 160k TestAAC.m4a
```

下の方が音質が良い

128k*6chということで768kにしてみた

``` 音が良い.bat
>ffmpeg -i Test51.wav -b:a 768k -aac_coder twoloop Test2.m4a
```

``` 最初のやり方でビットレートだけあげてみる.bat
>ffmpeg -i Test51.wav -c:a aac -b:a 768k TestAAC2.m4a
```

## 動画にくっつける
```
>ffmpeg -i Test2.mp4 -i TestAAC.m4a -c:a copy Encoded.mp4

```

さて
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96808/52c347ab-717c-7d99-8e3e-e76d2232f246.png)
オーディオは6chになったようだ

# Youtubeにあげてみる
aac 128k

https://youtu.be/MMK5EvJhyDo

-aac_coder twoloop 768k

https://youtu.be/4c3cIttrBd0

aac 768k

https://youtu.be/7rT90nd5Qis

残念なことに、ブラウザではステレオでしか鳴らないはず

AppleTVのYoutubeアプリで再生し、対応アンプを通してみると
MultiChannelの動画として認識されて、マルチチャンネルの動画になっていた。

ただ、音量が小さい？
めっちゃ音量小さい・・　うーむ

他のYoutubeの5.1ch動画も小さい感じがする
・・・アンプ側の設定とかもあるのだろうか・・・

波形レベルが小さかったようなので、を大きくすることで解決

どうも[aacのエンコード](https://trac.ffmpeg.org/wiki/Encode/AAC)で音が悪くなるみたいなのが書かれているので
要調査な感じだが、aacの別コーデックを入れるのにffmpegのコンパイルが必要と敷居が高く試せていない。
(BizRobo!)Webページの表を正規化してみよう！

## はじめに
この記事はRPA（ロボティック・プロセス・オートメーション） Advent Calendar 2023 12月14日担当分の記事です。

https://qiita.com/advent-calendar/2023/robotic_process_automation

Webページの表の正規化ってなんのこっちゃって方がほとんどなのではないかと思うので例を出します。

例えば、こんな表があったとして、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2736479/4a59cc81-232e-1c9e-5c5c-1638ff8f8998.png)

こんな感じに直すってことです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2736479/9d80de88-a6ab-8fd3-a81f-fea40182482a.png)

Excelなんかでよく話題になるセル結合みたいなことがWebページでも行われていて、そのせいでRPAで表から値を抽出する際のタグの設定がややこしくなったりします。
これを解決する方法がBizRobo!の機能にあります。
※以下、v11.4でのBizRobo!内蔵ブラウザ(Webkit)での動作です。
　v10.x系でも存在する機能なので過去バージョンお使いの方もご安心ください。

## 正規化前の動作
まず、正規化前に各行毎にループを回して最高気温を抽出しようとしたときの動作です。
オレンジ色で囲われた場所がロボットが抽出先として見ている場所です。
1行目は最高気温の場所になっているのが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2736479/77cf3ddf-b3bd-bd23-78dc-db621b98838f.png)
ちなみに抽出先の設定は、左から4番目のtdタグを見に行くことになっています。
年、月、日、最高気温、と4番目になるので正しいですね。

しかし、2行目を抽出しようとすると、平均気温を取りに行ってしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2736479/d2115ea0-9c17-7b98-f7b3-820e76b72f58.png)
これは、先ほどの1行目は
年、月、日、最高気温、となっていたのに対し、
2行目以降は
セル結合が行われているせいで、2行目以降は年と月の分のtdタグが存在しないことから、
日、最高気温、最低気温、平均気温、と4番目が平均気温になってしまっています。
このままでは、1行目は4番目から抽出し、他の行は2番目から抽出するように設定しなくてはならなくなります。

これはまだマシな例で、途中で結合されている場所が現れたり、現れなかったり、
後にページが更新されてそういう箇所が増えたり減ったりと、その度に設定を見直して複雑なつくりにしなくてはならなくなる可能性があります。

以前、ループ処理にせずに1セルずつ数十個の変数に1つ1つ場所を設定して抽出しているロボットを見たことがあります。
大変な力作でしたが、今回の正規化機能を知っていればそんな苦労もせず保守性の悪くないロボットが作れたでしょう…。

## 正規化の方法とその場合の動作
正規化の方法とその場合の動作です。

正規化の方法は非常に簡単。
普通にLoad PageでWebページを読み込んでいる状態から、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2736479/ca92b116-9a39-7824-7f79-d7658496decd.png)

HTMLタグの欄から対象のテーブルを選び、
右クリックメニュー⇒修正⇒セル結合解除
と選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2736479/3950e71e-300b-a1b0-c5e9-b22b79154101.png)

すると、Normalize Table(セル結合解除)ステップが追加され、
このように結合されていた行すべてが解除され、データが挿入されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2736479/56ee60d7-51e8-4d27-d8c1-f4e195490a92.png)

この状態で抽出処理すると、2行目以降でも最高気温が記載されている順番が変わらないため、最後まで同じ設定で抽出可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2736479/dc77c8c0-32e7-9301-aca2-afa48d5c80d6.png)

## まとめ
今回は少々ニッチな機能だったかもしれませんが、知っているのと知らないのでは、同じ状況にハマったときの対処にかなりの差が出る機能だと思います。

現在、内蔵のWebkitブラウザのみの機能で、デザインモードも最小実行モードにしか対応していないため、DA機能との併用はできません。
したがって内蔵Chromiumブラウザで開いたページやDA機能でデスクトップに起動したブラウザに対してはそのままでは使えない機能ですが、まだ使う方法はあります。
同じロボット内では使えませんが、一旦ChromiumやDAで開いたページからHTMLを抽出して保存しておけば、それをWebkitブラウザで読み込むことで今回のようなことが可能です。

使いにくいとかクセがあるとか色々言われることもあるBizRobo!ですが、今回のように内蔵ブラウザ内でHTMLやJavaScriptを改変したり、色々な機能を組み合わせることで便利になることもあります。
特徴をうまく使いこなして楽しく開発・運用していきましょう。
スマートロックの解錠方法

# はじめに
今回は3パターンのスマートロックの解錠方法を紹介します。スマートロックとは、スマホやタブレットなどの専用アプリを使って、ドアの解錠や施錠を管理できるシステムのことです。

いくつかのメーカーがありますが、今回は KEYVOX のスマートロックを例にします。

https://www.keyvox.co/

# 1. Bluetooth経由での解錠
最も簡単な方法がBluetoot経由での解錠です。スマートロックのデバイスを用意して、Lockin Link という専用アプリを使って、Buletoothで接続します。そうすると、下図のような画面になるので、後は「長押しで解錠」のボタンを長押しするだけです。簡単ですね。

![Screenshot_20231212-104453.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2065133/aa9c7d99-6d7f-ffa8-5b01-42cf49d6da4f.png)

![PXL_20231212_014512613.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2065133/36a0fccd-b078-1ae7-0e3e-e28322be27bf.jpeg)

![PXL_20231212_014602257.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2065133/f686a873-1f4c-0405-8cf0-d64da53908f8.jpeg)

自分だけが解錠するのであれば、この方法を事足りるでしょう。しかし、施設予約システムにスマートロックを組み込んで、不特定多数が使用するとなれば、この方法を使うことはできません。

# 2. オンライン方式での解錠
そこで、次に取ることができる方法がオンライン方式での解錠です。KEYVOXが提供しているAPIを利用して、このデバイスを解錠できる暗証番号を取得します。暗証番号はインターネットを通じて、ネットワークに繋がっているデバイスに配信されます。

![スクリーンショット 2023-12-12 11.25.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2065133/b27b7a20-96c6-d2a5-4552-285f2e507af6.png)

![1000004557.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2065133/ef95e5e4-31a0-785d-eee7-f167f9f9590e.jpeg)

![1000004556.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2065133/16ebe9d1-9cfd-eb68-bd21-729788c66fbb.jpeg)

しかし、この方法にも１つの問題があります。それはネットワークに繋がっている機器しか解錠できないことです。例えば、屋外の野球場など、スマートロックを設置する場所にwi-fiが存在しない可能性も大いにあります。

# 3. オフライン方式で解錠
そこで、取りうる最終手段がオフライン方式での解錠です。オフライン方式を利用すると、解錠可能期間とデバイス情報を組み合わせて、10桁のパスワードを発行してくれます。このパスワードを利用すると、インターネットに繋がっていないデバイスでも解錠することができます。

詳しくはKEYVOXのサポート記事まで。

https://support.keyvox.co/support/solutions/articles/63000277077-lockin-%E3%82%AA%E3%83%95%E3%83%A9%E3%82%A4%E3%83%B3%E6%9A%97%E8%A8%BC%E7%95%AA%E5%8F%B7%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9F%E4%BA%88%E7%B4%84%E7%AE%A1%E7%90%86%E3%83%BB%E9%81%8B%E7%94%A8%E3%81%AE%E6%B3%A8%E6%84%8F%E7%82%B9

# まとめ
一口にスマートロックと言っても、複数の解錠方法が存在しています。利用する場所の特性に合わせて、適切なデバイスと解錠方法を選択するところから始める必要があることを学びました。
Android14の変更点を簡単にまとめる

## はじめに
Android14の変更点の主な点をざっくりまとめていきたいと思います。
## 主な変更点
### ・正確なアラームのスケジュールがデフォルトで拒否される
・ここ最近バージョンが上がるごとに厳しくなっている権限関係の変更のようです。
　・SCHEDULE_EXACT_ALARM 権限がデフォルトで付与されなくなる。
　ダイアログを出して許可を取らないといけなったっぽい。
影響を受けるのは、
　・Android 13（API レベル 33）以降をターゲットとしている。
　・マニフェストで SCHEDULE_EXACT_ALARM 権限を宣言している。
アプリケーションになります。

### ・アプリは自身のバックグラウンドプロセスのみを強制終了できる
・killBackgroundProcesses()　を呼び出すことで自身のバックグラウンドプロセスを強制終了できるようになります。ただし、範囲はあくまで自身のみで他のアプリのパッケージ名を渡しても意味はありません。
### ・インストール可能な最小APIレベルが23に
・これはそのままです。Android14の端末では、targetSDKVersionが23未満のアプリはインストールできなくなります。セキュリティ強化の一環のようです。
### ・閉じることができない通知のユーザー エクスペリエンスに関する変更
・アプリで閉じることのできない通知がある場合、ユーザーがそれらの通知を閉じられるように変更されるようです。
具体的には、
・Notification.Builder#setOngoing(true)
・NotificationCompat.Builder#setOngoing(true) で Notification.FLAG_ONGOING_EVENTを設定しているアプリケーションに対し、FLAG_ONGOING_EVENT の動作が変更され、通知を閉じられるようになるそうです。
一部の例外もあるっぽい？
### 写真と動画への部分的なアクセス権を付与する
・Android13からメディアファイルのアクセスに、
　・READ_MEDIA_IMAGES
　・READ_MEDIA_VIDEO
といった、メディアファイルの種類に合わせた権限が必要になりました。
これついて、Android14では、権限確認のダイアロクに、
　・写真と動画を選択
 という、新しい選択肢が追加されます。
 この選択肢を選ぶと、そのアプリケーションに使用できる写真、動画などを個別で指定できるようになります。
 ## まとめ
 以上がざっくりとしたAndroid14の変更点のまとめです。
 印象としては、ここ最近のセキュリティ関係がまたさらに厳しくなったという印象ですが、そこまで大きな変更はなさそうでした。

 今回まとめた内容は、
 ここ　https://developer.android.com/about/versions/14/behavior-changes-all?hl=ja
 にまとまっていますので、ぜひご覧ください。
動かして試す、git restoreの動き

## 環境
Ubuntu 20.4
Git 2.25

## 内容
コミットを行った直後で、ワーキングディレクトリでは、何のファイルの修正も行っていない状態が以下です。
```
$git status
nothing to commit, working tree clean
```

test.txtを修正しました。ワーキングディレクトリで何らかの修正が入ると、ステータスのメッセージ内容が変わります。下記のメッセージは「ワーキングディレクトリで何らかの修正が行われたが、ステージングエリアにはまだ上がっていません。ワーキングディレクトリで、これ以上、修正が行われないようであれば、変更内容をステージングエリアに上げて、コミットへ向いましょう。」といった内容です。ステージングエリアに上げないのであれば、ワーキングディレクトリの変更内容を破棄することもできます。
```
$git status
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   test.txt

no changes added to commit (use "git add" and/or "git commit -a")
```

ワーキングディレクトリの変更内容を破棄します。すると、test.txtの内容が、直前にコミットをした直後の状態に戻ります。
```
$git restore test.txt
```

ワーキングディレクトリの変更内容を破棄する方法は、ファイル単位で１個つづ行う方法以外に、複数のファイルを一括で破棄する方法もあります。
```
$git restore test1.txt test2.txt
$git restore .
$git restore ./
$git restore              # これはエラーになります
```

破棄した後状態を表示すると、ワーキングディレクトリでは、何のファイルの修正も行われていない状態に戻っています。
```
$git status
nothing to commit, working tree clean
```

もう一度、test.txtを修正しました。次は破棄をしないで、修正内容をステージングエリアに上げます。
```
$git add test.txt
```

ステージングエリアに上げました。後はコミットをするだけです。折角、ステージングエリアに上げたが、そこから取り下げることもできます。
```
$ git status
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   test.txt
```

ステージングエリアから取り下げました。
```
$git restore --staged test.txt
```

ステージングエリアから取り下げれば、ワーキングディレクトリの変更内容を破棄できるようになります。ステージングエリアに上がっている状態で、ワーキングディレクトリの変更内容を破棄することはできません。ここが重要なポイントです。
```
$git restore test.txt
```

もう一度、test.txtを修正して、ステージングエリアに上げました。
```
$git add test.txt
```

次は破棄しないで、コミットをします。
```
$git commit -m "test.txtに行を追加"
 1 file changed, 1 insertion(+), 1 deletion(-)
```

コミットをした直後のステータスの内容です。ワーキングディレクトリには何も修正がかかっていませんというメッセージが表示されます。
```
$git status
nothing to commit, working tree clean
```

コミットをした直後にリストアをしても、何も起こりません。ワーキングディレクトリでは何の修正を行っていないため、当然、何も起こりません。
```
$git restore test.txt
```

コミットをした直後に、ステージングエリアから取り下げるコマンドを実行しても、これまた、何も起こりません。コミットをすると、ステージングエリアの中身は何も上がっていない状態になるため当然です。
```
$git restore --staged test.txt
```

## 複数のファイルを指定する
複数のファイルをステージングエリアに上げて、ファイルを指定して、ステージングエリアから削除することができます。test1.txtとtest2.txtの２つのファイルを修正して、２つともステージングエリアに上げます。
```
$git add .
$git add test1.txt test2.txt
```

ステージングエリアに上げた、全てのファイルを取り消す場合です。
```
$git restore --staged .
$git restore --staged ./			       # これでもOK
$git restore --staged				       # これだとエラーになります
$git restore --staged test1.txt test2.txt  # 複数のファイルを指定してもOK
```

test1.txtを取り消すと、test2.txtだけがステージングエリアに残ります。
```
$git restore --staged test1.txt
```

ステータスを確認すると、test2.txtだけがステージングエリアに上がっており、test1.txtはステージングエリアに上がっていないことが確認できます。
```
$git status
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   test2.txt
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   test1.txt
```

test1.txtを再び、ステージングエリアに上げます。
```
$git add test1.txt
```

test1.txt、test2.txt共に、ステージングエリアに上がっていることが確認できました。
```
$git status
  (use "git restore --staged <file>..." to unstage)
        modified:   test1.txt
        modified:   test2.txt
```
i 番目の出力 4 Python3編

https://paiza.jp/works/mondai/array_primer/array_primer__string_i-thinput_step4

```py
N,M,L = map(int,input().split())
A = input().split()
Ans = A[N-1]
print(Ans[L-1])

```

でも答えを見ると上の最後の二行はもっと短くできて

```py
print(A[N-1][L-1])
```
P4勉強録

# P4勉強録
金沢工業大学のAdvent Calendar 2023 12日目の内容です。

## P4とは
オープンソースのプログラミング言語です。ネットワーク機器のデータプレーン部分をプログラミングすることができます。

P4.org(https://p4.org/)

## コントロールプレーンとデータプレーン
ネットワークの「プレーン」は、特定の処理が行われる場所に関する抽象的なものになります。

### コントロールプレーン
コントロールプレーンは、パケットをどの経路で送受信するのかを制御します。ルーティングテーブルなどはコントロールプレーンの一部です。

### データプレーン
データプレーンは、実際にパケットの転送処理を行います。

## P4サンドボックス
P4.orgにブラウザ上でP4を動かすことができる、P4サンドボックスというものがあります。
今回はそのサンドボックスに例として書かれているプログラムの挙動を見たいと思います。

P4サンドボックス：https://p4.org/sandbox-page/

### プログラムの全体像
``` POPL-2021-talk.p4
#include <core.p4>
#include <v1model.p4>

const int MAX_HOPS = 10;
const int STANDARD = 0x00;
const int HOPS = 0x01;

typedef standard_metadata_t std_meta_t;

header type_t {
  bit<8> tag;
}

header hop_t {
  bit<8> port;
  bit<8> bos;
}

header standard_t {
  bit<8> src;
  bit<8> dst;
}

struct headers_t {
  type_t type;
  hop_t[MAX_HOPS] hops;
  standard_t standard;
}

struct meta_t { }

parser MyParser(packet_in pkt, out headers_t hdr, inout meta_t meta, inout std_meta_t std_meta) {
    state start {
        pkt.extract(hdr.type);
        transition select(hdr.type.tag) {
            HOPS: parse_hops;
            STANDARD: parse_standard;
            default: accept;
        }
    }
    state parse_hops {
        pkt.extract(hdr.hops.next);
        transition select(hdr.hops.last.bos) {
            1: parse_standard;
            default: parse_hops;
        }
    }
    
    state parse_standard {
        pkt.extract(hdr.standard);
        transition accept;
    }
}

control MyVerifyChecksum(inout headers_t hdr, inout meta_t meta) {
    apply { }
}

control MyComputeChecksum(inout headers_t hdr, inout meta_t meta) {
    apply { }
}

control MyIngress(inout headers_t hdr, inout meta_t meta, inout std_meta_t std_meta) {
  action allow() { }
  action deny() { std_meta.egress_spec = 9w511; }

  table acl {
    key = { hdr.standard.src : exact; hdr.standard.dst : exact; }
    actions = { allow; deny; }
    const entries = { (0xCC, 0xDD) : deny(); }
    default_action = allow();
  }
  apply {
    std_meta.egress_spec = (bit<9>) hdr.hops[0].port;
    hdr.hops.pop_front(1);
    if (!hdr.hops[0].isValid()) {
        hdr.type.tag = 0x00;
    }
    acl.apply();
  }
}

control MyEgress(inout headers_t hdr, inout meta_t meta, inout std_meta_t std_meta) {
    apply { }
}

control MyDeparser(packet_out pkt, in headers_t hdr) {
    apply {
        pkt.emit(hdr.type);
        pkt.emit(hdr.hops);
        pkt.emit(hdr.standard);
    }
}

V1Switch(MyParser(), MyVerifyChecksum(), MyIngress(), MyEgress(), MyComputeChecksum(), MyDeparser()) main;
	
```

### 入力パケット
先程のP4プログラムに対する入力は以下のものとします。
```
01
0200 0300 0401
AA BB
4f 48 20 4d 59 59 20 49 20 4b 4e 4f 57 20 57 48 59
```

### 出力パケット
上記の入力を行った場合の出力パケットは以下になります。
```
01 03 00 04 01 AA BB 4F 48 20 4D 59 59 20 49 20 4B 4E 4F 57 20 57 48 59  port: 2
```

### プログラムの挙動
入力の最初の8ビットである「01」はtagフィールドとして認識されます。
「AA」はsrc, 「BB」はdstとなります。
そして、ペイロードが「4F 48 20 4D 59 59 20 49 20 4B 4E 4F 57 20 57 48 59」となります。
[Swift]TableViewスクロール時のパフォーマンスを高めて滑らかなUIを実現する

# 投稿の経緯
TableViewスクロール時にセルの高さが低くなったり、高くなったりする不具合に遭遇しました。
AutoLayoutの制約は問題なさそうで、heightForRowAtでも固定値を返していたので改めて調査しました。

調査の中で、TableViewへの理解が高まり、スクロール時のパフォーマンスを高めて滑らかなUIを実現する方法に辿り着いたので記事にします。


# 対処法
結論、`tableView(_:estimatedHeightForRowAt:)`を実装して、推定値を返すと改善できました。

```.swift
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return 100 // 推定値を設定する
}
```

`heightForRowAt`と`estimatedHeightForRowAt`を組み合わせて使用することで、TableViewのパフォーマンスを高めて滑らかなUIを実現することができます。

# heightForRowAtとestimatedHeightForRowAtの違い
似たようなメソッドの`tableView(_:heightForRowAt:)`との違いを説明します。

## tableView(_:estimatedHeightForRowAt:)
セルの高さの**推定値**を返します。

このメソッドは、セルの実際の高さを計算する前に、推定値を用いてセルのスペースを確保し、スクロールの滑らかさを向上させることができます。

大量のセルが表示される場合やセルの高さが動的に変化する場合に使用するといいと思います。

## tableView(_:heightForRowAt:)
セルの**実際の高さ**を返します。

このメソッドをは、セルが表示されるたびに実際の高さを計算します。
`estimatedHeightForRowAt`が実装されている場合でも、`heightForRowAt`が優先され、実際の高さはこのメソッドで返される値に基づいて確定されます。
【備忘録】BEM記法について


# はじめに
BEM記法でマークアップする機会があった。
BEMの備忘録。

# BEMとは
BEMはCSSの設計手法のひとつ。
もともとロシアのYandex社が開発した「BEM Tools」のこと指すらしい。

いいCSSは、**予測がしやすくて**、**拡張性があり**、**保守性がある**ことが重要だと言われていて、比較的大規模なプロジェクトだと、複数人で作業することが多く、その際に作業の効率化や品質を担保が出来る。

BEMは、webサイトの各要素をブロック（Block）として考える。
各ブロックの中にはタイトルやテキスト、ボタンなどさまざまな要素（Element）があり、Elementの組み合わせでブロックを構成する。
ブロックやElementは装飾や動作のパターンをModifierというルールで設定する。

CSSの設計手法にはBEM以外にも
- OOCSS　　
- SMACSS
- FLOCSS
などがある。

# BEMの書き方（ルール）
先述の通り、BEMはブロックと要素（エレメント）と装飾を組み合わせて下記のようにクラスを定義する。

```
Block__Element--Modifier
```

例えばヘッダー（.header）をブロックとして定義して、その中にメニュー(.menu)があるとすると。

```
header__menu(Block__Element)
```
というように書く。

menuはヘッダーを構成するelementにもなるが、menu自体がブロックであると定義もできる。
例えば、下記のようなHTML構造の場合。
```
<header class="header">
    <div class="menu">
        <ul class="list">
            <li class="listitem"><a href="menu1">メニュー</a></li>
            <li class="listitem"><a href="menu2">メニュー</a></li>
            <li class="listitem"><a href="menu3">メニュー</a></li>
        </ul>
    </div>
</header>
```
BEMだとこう書く。
```
<header class="header">
    <div class="header__menu">
        <ul class="header__list">
            <li class="header__listitem"><a href="menu1">メニュー</a></li>
            <li class="header__listitem"><a href="menu2">メニュー</a></li>
            <li class="header__listitem"><a href="menu3">メニュー</a></li>
        </ul>
    </div>
</header>
```

ただ、「header__listitem」の中にさらに要素があったり、メニュー以外に色々なパーツが入ってくると、elementとして定義すると読みづらくなる。（個人的に）

なのでmenuをブロックと定義して、
```
<header class="header">
    <div class="header__menu menu">
        <ul class="menu__list">
            <li class="menu__listitem"><a href="menu1">メニュー</a></li>
            <li class="menu__listitem"><a href="menu2">メニュー</a></li>
            <li class="menu__listitem"><a href="menu3">メニュー</a></li>
        </ul>
    </div>
</header>
```
と書くこともできる。

この設計を考えながらマークアップしていく。

# 結局、正解はあるけどない
BEM記法はどこをブロックにしてどこをエレメントにするかは実装者やプロジェクトによっても様々。
ブロックにした理由や考え方を説明できるようにしてマークアップをすることが大切！
CAN通信ログ(MF4)の中身を見る(その２)

# Jupyterで使いそうな操作をメモ
## 前提
```python
import asammdf

# MDFファイルを読み込む
mdf = asammdf.MDF('path/to/mdf/file')
```

# シグナル名を部分一致検索
```python
[c for c in mdf.channels_db if "xxx" in c.lower()]
```

# 特定のシグナル名のメッセージ名を調べる

```python
[mdf.groups[gi].channel_group.acq_name for gi, _ in mdf.channels_db['xxx']]
```

# 特定のシグナルのソースを調べる
どのCAN から取得したとか。取得方法によっては格納されてないこともありそう。
その場合、sourceが Noneになるので、エラー処理が必要

```python
[mdf.groups[gi].channels[ci].source.path for gi, ci in mdf.channels_db['xxx']]
```

# 特定のシグナルから全部調べる（おまけ）

```python
[(mdf.groups[gi].channel_group.acq_name, mdf.groups[gi].channels[ci].name, mdf.groups[gi].channels[ci].source.path) for gi, ci in mdf.channels_db['xxx']]
```

# シグナルの値(Signal class)を取得する
## シグナル名が重複しない場合
```python
mdf.select(['xxx'])
```

## シグナル名が重複する場合
```python
mdf.select([(None, gi, ci) for gi, ci in mdf.channels_db['xxx']])
```

# シグナルの値(pandas)を取得する
## シグナル名が重複しない場合
```python
mdf.to_dataframe(['xxx'])
```

## シグナル名が重複する場合

取得はできるが、カラム名が `xxx, xxx_1, xxx_2, ...` となるので、いけてない。

```python
mdf.to_dataframe([(None, gi, ci) for gi, ci in mdf.channels_db['xxx']])
```
# シグナルの値を取得する際の便利そうなオプション

<dl>
  <dt>use_interpolation=False</dt>
  <dd>欠損値を補完しない</dd>
  <dt>ignore_value2text_conversions=True</dt>
  <dd>テキストへの変換をせず、数字のままにしてくれる</dd>
  <dt>raster=0.5</dt>
  <dd>0.5秒ごとにリサンプリングする</dd>
</dl>
APIキーを.envファイルに格納する

# はじめに
APIキーをどこに書けばいいか悩んだときに調べた結果のメモ

# 問題
下のようにAPIキー(テキトー)を直接ソースコードに書くのは多分だめだろうけど、じゃあどうすればいいの？
```
useEffect(() => {
        const access_weather = async () => {
            const response = await fetch(
                'https://api.openweathermap.org/APIKEY=129ahdfa8p3917ga8891d'
            )
            const body = await response.json()
            console.log(body)
        }
        return () => {
            access_weather()
        }
    }, [])

```
# 解決方法
ルートディレクトリ直下に`.env`ファイルを作成する
「.gitignore」などと同じ階層

# ViteでReactプロジェクトを作成した場合
頭にVITE_をつけないとだめらしい
```
VITE_WEATHER_API_KEY=129ahdfa8p3917ga8891d
```
以下のコードでアクセスできる
```
console.log(import.meta.env.VITE_WEATHER_API_KEY)
```
# create-react-appでReactプロジェクトを作成した場合
頭にREACT_APP_をつけないとだめらしい
```
REACT_APP_WEATHER_API_KEY=129ahdfa8p3917ga8891d
```
以下のコードでアクセスできる
```
console.log(process.env.REACT_APP_WEATHER_API_KEY)
```
# 注意
もし、このコードをGitHubにあげる場合は.envファイルを.gitignoreに記述する
```
*.env
```
# おわりに
開発環境の時のみアクセスできる.env.development
本番環境の時のみアクセスできる.env.production
というのもあるらしい。使い分けはよくわからん。

.envはおそらく.environmentの略で、環境変数という意味なのだろう。
# 参考
https://ralacode.com/blog/post/use-env-variables-in-react/
「羊男ゲーム」でエンジニアとしてのコミュニケーション能力を高める！(建前)

:::note info
先日社内で忘年会したときに実施した「羊男ゲーム」というワードウルフをベースにしたゲームについてご紹介します。
:::

最近社内で「エンジニアにとってコミュニケーション能力は重要だ」的な建前で、AmongUsなどの対話形式で進めるゲームをみんなでやりたいという意見が上がっていました。

そうしたなかで今年の忘年会の幹事を私が務めることとなり、できればベテランから若手までが共通の話題を通じて盛り上がれるアクテビティを取り入れたいと考え、企画したのが「羊男ゲーム」になります！

# 既存の対話形式のゲームの難点

もともとは人狼ゲームやワードウルフなどの手軽にできそうな対話形式のゲームを実施しようと考えていたのですが、以下の都合からゲームを自作する必要があると判断しました。

- ゲームに使える時間には限りがある
- ゲームに景品を用意する都合上、人狼などの特殊な役割があると、プレイヤー間の公平性が損なわれる

# コンセプト

羊男ゲームは、ワードウルフにチーム戦形式でプレイできるような修正を加え、プレイヤーの役割の公平性を保ちながらプレイできるゲームになっています。

※ワードウルフのルールをご存じないかたは、こちらをご参照ください。

https://g.co/bard/share/cc5ca35e395a

:::note
ゲーム名の「羊男」は、私が最近読んだ村上春樹の羊をめぐる冒険に出てくる同名のキャラクターから取っています。人狼の対になる言葉で真っ先に思い浮かんだ言葉だったのでこの名前にしました。
:::

# ルール

- ワードウルフの要領でゲームマスターがゲームのお題とそのお題に沿ったワード、ゲームの制限時間を伝えてゲームをスタートします
    - 今回の忘年会では、ワード1種類につきプレイヤーの数が2人1組になるように割り振りました
        
        例）お題が「焼き鳥」で、プレイヤーが4人の場合
        - ワードを2種類にし、それぞれにプレイヤーを2人ずつ割り振る
            
        ![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1995005/b65da36e-9d77-2ab8-06d6-1cb1193d0bcb.png)

            
- プレイヤーは自分と同じワードのプレイヤーを探したり、他のプレイヤーの仲間のふりをしながらゲームを進めていきます
:::note alert
割り振られたワードをカミングアウトする行為はNGです
:::
- 制限時間を過ぎたら、プレイヤーはゲームマスター宛てに同じワードが割り振られていると思う人物の名前を投票（DM）し、ゲームマスターは以下の配点に従って点数を計算します
    - 同じ単語が割り振られた人物に投票したプレイヤーには5点
    - 投票を受けたプレイヤーは投票者の数×3点
        例）
        4人プレイで同じワードの人物に投票し、他の2人の人物から投票をされたプレイヤーの得点   
        → 5点 + 6点(3点×2人) = 合計11点
            
- 計算した点数をもとに順位付けをして、上位入賞者には景品を贈呈します
    - 今回は上位3人に景品を贈呈しました

# 実際にプレイした環境

- 参加人数：17人（うちゲームマスター1人）
- 割り振り：
テーブルが大体4人ずつで区切られていたので、4人1組でテーブルごとにお題を割り振って実施
## テーブルA

| お題 | ワード① | ワード② |
|:-:|:-:|:-:|
| 今年の紅白出場歌手 | MISIA | 椎名林檎 |

## テーブルB

| お題 | ワード① | ワード② |
|:-:|:-:|:-:|
| スポーツブランド | ニューバランス | アンダーアーマー |

## テーブルC

| お題 | ワード① | ワード② |
|:-:|:-:|:-:|
| 人気ゲームシリーズ | ドラゴンクエスト | モンスターハンター |

## テーブルD

| お題 | ワード① | ワード② |
|:-:|:-:|:-:|
| 国民的アニメ | ちびまる子ちゃん | サザエさん |

## 採点結果（上位3人の点数）
- 1位：14点（テーブルAのプレイヤー）
- 2位タイ：11点（テーブルBとCから1人ずつ）

成績上位は普段から多くの方々とコミュニケーションをとる機会の多いキャリア10年以上のベテランエンジニアに独占されました。

# 感想
- どのテーブルでも若手からベテランまでゲームをしながらコミュニケーションを取れていたので、企画としては成功だったと捉えています
- ワードウルフに比べて他のワードが何かを予想する場面が多いことから、お題に沿ったワードの組み合わせにより繊細さが求められるように感じました

もしこちらのゲームに興味を持っていただけた方がいらっしゃったら、このページの内容をもとに自分なりのアレンジなどをして楽しんでもらえれば幸いです！
開発時のあるあるを格言っぽくまとめてみた

こんにちは。静岡市でフリーランスでWeb開発しているkazuomatzです。

開発してると、開発ならではのあるあるがいろいろとあります。これらを格言っぽくまとめてみました。


# 灯台もと暗し的な

> どんなにググっても、GitHubやStack OverflowにもQiitaにも解決策が見つからない場合、それは凡ミスである。足下をみよ。

技術的な問題にぶち当たって、解決策をGitHubやStack OverflowにもQiitaなど、一生懸命探しまくっても、解決策が見つからないことがあります。
そんな時は、単なる凡ミスであることが多いです。


# コピペあるある その１

> 君が今コピペしたコードには先人の知恵と工夫が詰まってる。後から何かあって後悔することは、よく味見せず食べてお腹痛くなるのと同じだ。

そもそもその用途のためのコードぢゃないとか、ちゃんと動かないじゃないか、クソコードがっ!! と怒るのはお門違いです。
最近では、GitHub Copilotが提案してきたコードをそのまま使っちゃうというのも当てはまりますね。

# コピペあるある その２

> 君が今コピペしたコード、ついさっきもどこかにコピペしてたよね。このまま進んでもきっと正しく動作するよ。でもね、昔の人は急がば回れって言ってた。遠回りしてみないかい？

同じコードが各所にペタペタ貼られてる。一工夫して共通化するとかそういうこと。

# あとから気づいちゃう系

> 君には今二つの選択肢がある。タイポしてしまった変数名をすべて直してプルリクを出すか、このままやり過ごすか。どちらを選ぶかは君次第だ。Hare we go.

変数名なら修正すればよいですが、S3のバケット名を 「xxxx-backet」ってつけて運用されちゃってから気づくとか、割とありがちで恥ずかしい。


# jQueryってさぁ

> jQuery使ったっていいじゃない。楽なんだもの。

みつをっぽいですが、、まぁいいんじゃないかと。


# 昔の自分を褒める系

> 長いことソースメンテしてると、昔の自分が書いたコードにイラッとすることが多いけど、たまーに、よく考えて作ってあるじゃんって場合もあるよね。

なんでこんなコード書いたんだろうってがっかりすることもあるけど、何も考えて作ってないだろうなと思って、コードを見ていくと、すごくいろいろ考えて作ってあって、そのまま流用できるじゃんってコトもある。そんな時は本当によくやったと褒めてあげたい。
Laravel .htaccessのRewriteBaseの記述で画面表示に失敗する

# 経緯
Laravelアプリをclone後にdockerで起動し、ローカル環境でTOP画面の表示には成功するが相対パスで他の画面を表示しようとした時にInternal Server Errorになっていました。

今回はその対応策の記事になります。

# cloneしてきたプロジェクトの起動後にInternal Server Error

![スクリーンショット 2023-11-08 18.26.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/574173/7bba7817-0269-49cd-c81e-1cd838a101b1.png)

# .htaccessを確認すると

以下のような記述になっていました。
```
RewriteEngine On
RewriteBase /プロジェクト名/
```

この場合はサーバ側の都合で
`ホストドメイン/プロジェクトドメイン/`のようなURLの構成をベースにしたいという意図があることから来ています。
本来はこのようなことはREADMEに書いておくのが親切ですね。

# RewriteBaseの記述を修正

下記に修正します。

```
RewriteEngine On
RewriteBase /
```

# 注意点
この修正はGitには反映せずローカル内でのみの修正にします。
これを反映してしまうと本来そのサーバでやりたかったリライトルールから外れてしまうためです。

.htaccess内でif文を組み込めるのでその方法で切り抜けても大丈夫かと思います。

```
RewriteEngine On
RewriteBase /
<If "req('Host') = 'サーバホストドメイン'">
    RewriteBase /プロジェクト名/
</If>
```
Findy Team+を活用し開発リードタイムを80%削減した取り組み

この記事は[ツクリンクアドベントカレンダー2023](https://qiita.com/advent-calendar/2023/tsukulink)の12日目の記事になります！

## はじめに
現在、弊社では[DevOps Research and Assessment（DORA）](https://dora.dev/)が提唱しているFour Keysを元に開発生産性の向上を目指し取り組んでいます。

Four Keysの各指標としては下記になります。

|デプロイの頻度  |組織による正常な本番環境へのリリースの頻度 |
|---|---|
|**変更のリードタイム**  |**commit から本番環境稼働までの所要時間**|
|**変更障害率**  |**デプロイが原因となり、本番環境で障害が発生する割合（%）**|
|**サービス復元時間**  |**組織が本番環境での障害から回復するのにかかる時間**|

本記事では、**変更のリードタイム**を短くする為に行ってきた取り組みを紹介させていただきます。

先にどのような状態からどこまでの変化があったのかをFindy Team+のキャプチャを添付します。

**2023年5月の変更のリードタイムの状態**
![スクリーンショット 2023-12-12 11.10.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/459450/d83ced02-35b8-a2d4-5890-f6054e2bdb76.png)

**2023年10月の変更のリードタイムの状態**
![スクリーンショット 2023-12-12 11.10.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/459450/b79d966a-0ed1-e626-cacc-b4a884c0f178.png)

変更のリードタイムが約半年で80%削減できるまでに取り組んできた内容を紹介させていただければと思います。

## 現状把握
実施前に過去の下記4項目の数値を抜き出し、チーム全体で定量的に可視化する事によって現状を把握するところから始めました。

- **First CommitからPull Request作成までの時間**
- **Pull Request作成からレビュー実施までの時間**
- **レビュー実施からApproveまでの時間**
- **Approveからマージまでの時間**

弊社としては、「Approveからマージまでの時間」に関しては課題として見える部分がなかったのですが、それ以外の3項目についてはリードタイムが長く課題を感じる状態にありました。

こちらを実施する事でチームとしての課題の意識の共有ができ、方向性の一致が取れるので最初に実施しておいて良かったと感じるポイントです。

## Pull Request粒度の分割
こちらはレビュー実施からApproveまでの時間に着目し削減する為の改善策となります。
今までですと、変更行数が多くPull Requestのレビューへの負担が大きい事があり、レビューへのハードルが高い状態にありました。
そのレビューを容易にする為に、実装単位を機能単位の粒度ではなく、意図単位の粒度へと変更し粒度を小さくする取り組みを実施しております。

例えば、**データを取得し画面へ描画する機能A**が存在していたとすると、機能Aとして1つのPull Requestにするのではなく、**データを取得**と**画面への描画**の2つのPull Requestに分けるように実施しております。

この策の結果、レビュワーへの負担が減り、レビュー時間の削減ができていることが結果として出ています。
さらにまだ数値として定量的には見れてないですが、レビュー範囲が狭まりレビューの質が上がっているように感じております。

Findy Team+で見るとPull Request作成数も約2倍の数字になっている事がわかります。
**2023年5月のPull Request作成数**
![スクリーンショット 2023-12-12 11.35.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/459450/1d97a299-bb0d-78f6-4d1a-a772107baee5.png)

**2023年10月のPull Request作成数**
![スクリーンショット 2023-12-12 11.35.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/459450/baed597a-a737-ad96-ff7d-f2f5feb2a811.png)


## レビューを後回しにしない
Pull Requestのレビューが放置される状態が続いている事が数値として明らかになっていたので改善していく必要がありました。

こちらは意識的な部分から取り組み、まずは実装よりもレビューを行うことの方が優先タスクだという意識をチーム全体で統一していくことから始め、さらに、毎日の朝会で現状のレビュー段階のタスクを洗い出し担当者が決まっていないものはその場で担当者を決めレビューの抜けを無くす取り組みを実施しています。

また、Pull Requestを作成したらチーム全員にメンションし、レビューをお願いするという動きを徹底することも実施しています。
![image (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/459450/457b52f0-42b0-32ff-5f06-9f0c4d881847.png)


ここについては、GitHub Actionsなどを使用し少し自動化にも取り組んでいきたいと考えております。


## 毎週のふりかえり
弊社ではスクラム開発を取り入れているので、スプリント・レトロスペクティブにて、スプリント内で実施した内容のリードタイムを全て振り返る時間を設けております。
[Findy Team+](https://findy-team.io/) を取り入れているので、そちらで可視化したデータを確認し課題点の抽出 → 次週改善案を出すまでを毎週実施しています。

## これから
今は、変更のリードタイムにフォーカスして追っている部分がありますが、今後はデプロイ頻度や変更障害率についても深ぼっていこうと考えております。
また、取り組んでいく上でこの数値は本質的な改善を行う事を目的として使用し、数値を上げることが目的とならないようには気をつけながら取り組んでいく必要があります。
Azureにサーバーを立ててリモートデスクトップでアクセスする①（アカウント作成）

最近Azureを勉強しています。
AWSとの違いになれるためにも、勉強した構築手順などをQiita記事にまとめていこうと思います。
Azure上にNWを構築し、仮想サーバーを立ててリモートデスクトップを行う手順についてまとめて行こうと思います。


# 作業の流れ
サーバー構築については、下記流れで行っていきます。
今回は準備編として、Azureアカウントの新規取得手順についてご紹介します。

 1.Azureアカウント新規取得（マイクロソフトアカウント情報が必要です）←今ここ
 [2.リソースグループの作成](https://qiita.com/tonkatsu_oishi/items/8d3b708da4e98174d947)
 [3.仮想ネットワーク/ネットワークセキュリティグループの作成](https://qiita.com/tonkatsu_oishi/items/8d3b708da4e98174d947)
 [4.NSGの編集](https://qiita.com/tonkatsu_oishi/items/8d3b708da4e98174d947)
 [5.AzureVM（仮想サーバー）の作成](https://qiita.com/tonkatsu_oishi/items/8d3b708da4e98174d947)

# Azureアカウント新規取得手順
### AzureのURLへアクセスする
まずは[AzureのURL](https://azure.microsoft.com/ja-jp/)にアクセスします。
Azureのトップページが表示されたら、「無料で始める」のボタンを押下します。
※画像は2023年9月時点の物です。実際の表示が画像と異なる場合があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2237429/a3a7f8a0-0e3d-0f3a-d9bc-03fbe47b15aa.png)

### Microsoftアカウントへログインする
「無料で始める」を押下すると、microsoftアカウントへのログイン画面が表示されます。
ログイン情報を入力し「サインイン」を押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2237429/0fe6198a-2719-329d-7a17-0a7751207f23.png)

### Azureアカウントの作成
Azureアカウントの作成画面が表示されます。
「国/地域」のプルダウンメニューから「日本」を選択します。
名前・姓を入力し、下へスクロールします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2237429/1fe9c754-5df0-37b2-7e54-32d3d9adb22c.png)

「顧客契約に同意します」のチェックボックスにチェックをいれ、「サインアップ」を押下します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2237429/2f42412c-ef87-4492-dd04-7467efd8403a.png)

アカウント作成が完了するまでしばらく待機します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2237429/00c66d83-c8a2-d88b-879a-9550b0c2d42b.png)

### Azureポータルの表示

アカウント作成が完了するとAzureportalへのリンクが表示されます。
「Azureportalに移動する」を押下し、Azureのトップページへ移動します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2237429/174923e3-e634-86bf-47da-3d5a12356cfc.png)

アカウントのトップページの状態です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2237429/88c4aff4-03ac-373c-28ed-b4936bc69e31.png)

### Azureの無料クレジットについて

Azureの新規アカウント作成が完了すると、マイクロソフトアカウントへ登録しているアドレス宛に画像のようなメールが届きます。
Azureでは、利用開始後1ヵ月間は200ドル分の無料クレジットを利用できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2237429/26e3908a-4a86-8b13-3272-bb8e9792e39a.png)

また、AzureVM・Azure SQL Databaseなどのサービスを12か月の間無料で利用できます。
※12か月間無料で利用できるサービスについては、[こちら](https://azure.microsoft.com/ja-jp/pricing/free-services)をご確認ください。

ここまでお読みいただきありがとうございました。
[次回](https://qiita.com/tonkatsu_oishi/items/8d3b708da4e98174d947)はAzure上に仮想ネットワークを作成し、仮想サーバーの構築を行います。