OmniAICreator/Qiita-1.07M huggingface dataset:
インフラエンジニアってなに？料理店に例えてみた

# はじめに
新卒から約4年間インフラエンジニアとしてのキャリアを築き続けてきた筆者なりに、インフラエンジニアのイメージを**料理店**でざっくり例えてみました。
インフラエンジニアになりたい！と思っている就活生や転職活動をされている方々の目に届けばいいなと思います。

# 目次
- [1. インフラエンジニアとは](#インフラエンジニアとは)
- [2. サーバは「コンロ」](#サーバは「コンロ」)
- [3. ストレージは「冷蔵庫」](#ストレージは「冷蔵庫」)

# インフラエンジニアとは
インフラエンジニアを料理店に例えて表すと、**コンロや冷蔵庫を設置する人**です。
料理店に勤めているシェフがお客様に料理を提供できるように、**料理を作るうえで必要不可欠なもの**を提供するようなお仕事です。
ここでシェフは「システム提供者」、お客様は「システム利用者」と捉えていただければよいかと思います。
※SI企業の立場だと、「シェフ＝お客様」になります。

# サーバは「コンロ」
システムを動かすためには「サーバ」というものが必要です。
サーバを料理店に例えると、**コンロ**です。
コンロがないと火を使って炒めたりすることができず、料理が提供できなくなりますよね。

もう少し掘り下げた話をしてみます。
サーバについて調べていくと以下のような用語が出てくるかと思います。
 - スケールアップ（ダウン）
 - スケールアウト（イン）

簡単に説明すると、スケールアップはサーバの性能を上げること、スケールアウトはサーバの台数を増やすことなのですが、これをコンロに例えてみます。
 - スケールアップ ＝ **コンロの火力を上げる**
 - スケールアウト ＝ **使用するコンロの数を増やす**

チャーハンなど強火で調理しなければならない時はコンロの火力を上げますよね？
このように、**コンロの火力を上げる**ことによって**コンロ単体で調理可能な料理の幅を増やす**ことができるようになります。（スケールアップ）

では次に、大盛りチャーハンを2人前作らなければならない場合を考えます。この時、1つのコンロで1つの大盛りチャーハンしか作れない制約があった場合はどうしますか？2つのコンロで同時に作れば同じタイミングで提供できますよね。
このように、**使用するコンロの数を増やす**ことによって、**同じ料理を分担して調理できる**ようになります。（スケールアウト）

# ストレージは「冷蔵庫」
システムを動かすためには何らかのデータを保存する必要があり、その保存先が「ストレージ」となります。
ストレージを料理店に例えると、**冷蔵庫**です。
データを「具材」とするなら、ストレージは「具材を保存する冷蔵庫」になります。

ここでも、もう少し掘り下げた話をしてみます。
    Microsoft社のクラウドであるAzureのストレージには、**ホット層**と**アーカイブ層**なるものがあります。ホット層にあるデータには即時アクセスが可能なのですが、アーカイブ層にあるデータはすぐにアクセスすることができません。
...なんのこっちゃって感じですよね。これらを冷蔵庫に例えてみます。
 - ホット層 = **冷蔵室**
 - アーカイブ層 = **冷凍室**

**冷蔵室**にある具材であれば、それを利用して**すぐに調理**に取り掛かることができますよね。
**冷凍室**にある具材は、**電子レンジなどで解凍**しないといけないため、すぐに利用できませんね。

# おわりに
今回は就活生や転職活動中の方々がインフラエンジニアのイメージを掴んでいただくために、**超ざっくり**とした解説をしてみました！
エンジニアの方々からしたら解釈不一致な内容もあるかと思いますが、あくまでイメージですのでご承知おきください...
【Rails】SprocketsによってコンパイルされたCSSを文字列として取得する方法

Railsでは通常、layoutファイルで`stylesheet_link_tag`メソッドを使ってSprocketsによってコンパイルされたCSS（元々`app/assets/stylesheets/application.css`等に書いていたCSS）を参照します。

```erb:app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <!-- 略 -->
    <%= stylesheet_link_tag "application" %>
  </head>
```

背景を説明すると長くなるので省略しますが、とある事情でこのコンパイルされたCSSを文字列として取得する必要が出てきました。（簡単にいうと、`<link href="..." >`でcssファイルにリンクするのではなく、HTMLに直接スタイルシートのコードを埋め込む必要があった）

いろいろ調べた結果、以下のようなコードで取得できることがわかりました。

```ruby 
Sprockets::Railtie
  .build_environment(Rails.application, true)['application.css']
  .to_s
#=> "html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0} ..."
```

以下はその使用例です。

```erb
<!DOCTYPE html>
<html>
  <head>
    <style>
      <%# SprocketsによってコンパイルされたCSSをHTMLに直接埋め込む %>
      <%= Sprockets::Railtie.build_environment(Rails.application, true)['application.css'].to_s %>
    </style>
  </head>
```

こうしたテクニックを使う場面は滅多にないと思いますが、もし同じような状況に遭遇したら参考にしてみてください。
JavaScriptの配列とオブジェクトの置換

# はじめに
何度も忘れて調べるので自分用メモ。
ググるのも説明するのも難しいから、解を得るまでが地味にめんどくさいやつ。

JSONで定義されているものを、使いやすいように変換したいときに出くわします。idというキーに入っている値をキーにして、nameというキーに入っている値を値にした、オブジェクトを作りたい。（伝われ！）

# 課題
```JavaScript
// この配列を
const ary1 = [{id:11, name:"aa"}, {id:22, name:"bb"}];
// この形に変換したい
const map1 = {11:"aa", 22:"bb"};
```
コードでかけばすぐ伝わる。

この変換があれば
```JavaScript
console.log(map1[11]);  // aa
```
ができる。

# もったいぶらずに解
```JavaScript
const map1 = ary1.reduce((m, v) => (
  {...m, [v.id]:v.name}
), {});
```
`reduce`で解体しながら作り上げていく感じです。

`[v.id]`のところは、わかっていないです。なぜ`[]`で括ると使えるようになるのか・・・。ちなみに括らないと、`Uncaught SyntaxError: Unexpected token '.'`と怒られます。解を知らないと、どないせえっちゅうねん！ってなります。

丸カッコの辺りが分かりづらい人は、下記でもいいかも。`return`を省略した形が上です。
```JavaScript
const map1 = ary1.reduce((m, v) => {
  return {...m, [v.id]:v.name};
}, {});
```


## 別解
こちらの方が、実はよいかもしれない。単純で誰にとってもわかりやすい。（コードを数年後に新人が読むかもしれない前提。）
```JavaScript
const map1 = {};
ary1.forEach(v => {
    map1[v.id] = v.name;
});
```
`const map1`で定義しているけど、再代入はしていなくて値の変更なので、このコードはOK。

# ちなみに逆(オブジェクト→配列)
逆も置いておこう。
```JavaScript
const map1 = {11:"aa", 22:"bb"};
const ary1 = Object.keys(map1).map(k => ({
    id: Number(k),
    name: map1[k]
}));
```

# まとめ
`reduce`を使って、配列をオブジェクトへ変換する方法を紹介しました。

あーまた出たーと２度目の再開をして、また若干躓いたので、メモです。でも別解が優秀だな。それを覚えようか・・・。`reduce`も好きだけど。
【kintone】フィールドの値まわり(初心者/入門)

# はじめに
kintoneのフィールドの値は`record[フィールドコード].value`で基本取り出せます。
例えば文字列フィールドに`テキスト`というフィールドコードを設定し、`こんにちは`と入れていた場合、
`record["テキスト”].value`としてあげれば`こんにちは`が取り出せます
少し異なるフィールドだけ羅列します。

## テスト環境の画面
今回こんな感じの環境で見ていきます。

![スクリーンショット 2024-02-24 16.27.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3719638/3b53eab6-c948-ccae-45c0-8b225b6adea6.png)


## ユーザー選択(組織選択、グループ選択）
`record["ユーザー選択"].value`で取得するとvalueの中に配列で各ユーザーの情報`{code:ユーザーのコード, name:ユーザーの名前}`が入っています。
例えば、一人目の名前だけ取得したければ`record["ユーザー選択"].value[0].name`

ユーザー選択のメンバー全員の名前だけ取得してカンマ区切りの文字としたい時は、
`const userNames = record["ユーザー選択"].value.map(user=>user.name).join(",")`
mapでnameだけの配列を作ってjoinしてあげれば、ですね。組織とグループ選択も同じです。

![スクリーンショット 2024-02-24 16.29.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3719638/cc1b553c-6ddc-1c86-5165-7ada2a2a5766.png)

## チェックボックス
これも配列で返ってきます。値が入っているだけですのでこれもまた`record["チェックボックス"].value[0]`と書いたら１番目の値が取得できます。ちなみにチェックが入っている値のみが配列に入ってきます。チェックしてない値は配列には入ってこないです。

![スクリーンショット 2024-02-24 16.31.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3719638/b7825374-4170-80b7-be92-f687754fcb4f.png)

## サブテーブル
kintoneで開発デビューした際に一番躓くポイントだと思います。恐らく。
このテーブルの値を見ていきましょう

![スクリーンショット 2024-02-24 16.35.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3719638/e9a5f0b7-08c6-b06d-d496-128c54fbc700.png)

例の如く`record["テーブル"].value`とした時を見ると、
![スクリーンショット 2024-02-24 16.36.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3719638/bb847f2e-ae00-8520-2fbb-17a7a2c696c1.png)

配列で各行のデータがオブジェクトで入っています。`{id: 各行に自動で振られたid, value: 各行のフィールドデータ}`となっています。さらに各行のvalue:フィールドデータを掘り下げると、

![スクリーンショット 2024-02-24 16.41.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3719638/69ed937d-7ff8-d646-ff10-95ccec576358.png)

なっており、テーブル以外の普段使っている**フィールドの情報**が入っている形になります。

例えば、2行目のコメントを取り出したい場合は、`record['テーブル'].value[1].value["コメント"].value`で取り出せます。
![スクリーンショット 2024-02-24 16.44.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3719638/483d4ef3-b6ac-4e40-3236-659b36c70cb9.png)

### テーブルのデータ全部をどうにかしたい
そんな場合はまたfor文やmapで行数分確認していきます。
例として、レコードの詳細画面で`テーブル`というサブフィールドと、サブテーブルに`金額`という数値フィールドを設置しテストします。

```test.js
(() => {
  'use strict';
  // レコードの詳細画面で実行していきます
  kintone.events.on('app.record.detail.show', (event) => {
    const record = event.record;
    let total = 0;
    // テーブルの回し方
    record['テーブル'].value.map((row) => {
      total += Number(row.value['金額'].value);
    });
    alert(total);
  });
})();

```

## おわりに
少し異なるフィールドの扱いをざっと書いてみました。
テーブルは慣れてくると楽しくなってくると思います。

それでは
### 楽しいkintoneライフを:relaxed:

## 参考

https://cybozu.dev/ja/kintone/docs/overview/field-types/
SharePointサイトの下側のコメントを消したい

## 結論
消すことはできます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524942/597ce5e4-aab1-c33c-a0d6-21d20a28d955.png)


## 方法
Microsoft365管理センター＞SharePoint管理センター＞設定＞「クラシック設定ページ」へ移動します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524942/cc2a6fd4-de5b-f8a9-0072-3b47e3d60651.png)


「サイトページのコメント」にて **”サイトのページのコメントを無効にする”** を選択して右下の「OK」をクリックすると設定完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524942/ed5c8ebf-3fa3-ada1-3d36-c1d1b2f91f4d.png)

## 注意点
こちらはテナントにあるSharePointサイトすべてに適応されます。
指定ページだけコメントを非表示にすることはできません。

## まとめ
画面の下がすっきりしましたね。

ただ、コメント機能は**間違った情報などを掲載していた際は閲覧者がコメントで知らせる**ことができます。
その結果**即対応**することができますので、個人的には好きな機能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524942/15322816-f6c8-5f2f-524a-8826156f3224.png)
Raspberry Pi 5でGStreamerを使用したRTSPサーバー

# 1. 概要
Raspberry Pi 5が手に入ったので、3Bや4Bで動いていたGStreamerやRTSPサーバーが使えるのか確認する。Pi 4Bのときの作業をベースに進める。

以下は以前の記事。

https://qiita.com/tetsuoMikami/items/96f96b0f1117ae2c114b

https://qiita.com/tetsuoMikami/items/7ebaa42d798fd801f37b

# 2. 使用機器
* Raspberry Pi 5 (8GB)
* OSはBookworm 64bit(Debian 12)
* UVCカメラ: Buffalo BSW500M
* 再生アプリケーション: VLC Player on Windows11

# 3. OSのインストール
　まずは、前回から条件をあまり変更せずに試した見たかったので、Bullseye 64bit Lite（raspios_lite_arm64-2023-05-03）をインストールしてみた。残念ながら、電源をいれてもファンがうるさいだけで起動しているそぶりがなかった。LANのLEDも点灯しないので、多分起動できない。Pi5はBullseyeに対応していないという記述をどっかで読んだので動かないということだろうか。

 　仕方がないので、Bookwormをインストールした。起動の様子を一度もみたことないと何が起きるかわからないので、最初はDesktop版（GUI）ありとした。
のちにBookworm 64bit Liteで試して同じ結果を得ました。

# 4. アプリケーションやライブラリのインストール
とりあえず定番のアップデート。これしないと一部のapt installで失敗するみたい。
```
$ sudo apt update
$ sudo apt upgrade
```

Gstreamerと関連のインストール
```
sudo apt -y install cmake m4
sudo apt -y install libssl-dev libcurl4-openssl-dev　liblog4cplus-dev
sudo apt -y install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-bad1.0-dev 
sudo apt -y install gstreamer1.0-plugins-bad gstreamer1.0-plugins-good gstreamer1.0-plugins-ugly gstreamer1.0-tools 
```

Lite版で追加インストールしたもの
```
sudo apt -y install git python3 python3-pip
sudo apt -y install meson
```


GStreamerのバージョン確認。1.22.0だった。
```
user@raspberrypi:~ $ gst-launch-1.0 --version
gst-launch-1.0 version 1.22.0
GStreamer 1.22.0
http://packages.qa.debian.org/gstreamer1.0
```

## 4.1 ハードウェアエンコーダはない
Pi5のスペックにはハードウェアエンコーダが記載されていない。ということで、v4l2hの確認をしてみる。
```
$ gst-inspect-1.0 | grep v4l2h
```
何も出てこない。なんで無くしたんだろうか。

# 5. RTSPサーバーのインストール
　Pi 4Bで使ったのと同じ方法で試そうかと思ったのだが、mesonの前に「git checkout 1.22.0」をしたら失敗した。GitHubを見るとブランチは1.18まで、Tagは1.19.2までで、1.22については何もされていないようだった。
今後は使うべきでないかもしれない。

```
$ git clone git://anongit.freedesktop.org/gstreamer/gst-rtsp-server
$ cd gst-rtsp-server
$ meson build/
$ cd build/
$ ninja
```

# 6. 確認（RTSP）
## 6.1. カラーバー
出力は確認できた。
再生はVLC Playerでメディアを開くのネットワークに「rtsp://192.168.1.128:8554/test」のように入力する。192.168.1.128はRaspberry Piに割り当てたIPアドレス。
```
./test-launch '( videotestsrc ! x264enc ! rtph264pay name=pay0 pt=96 )'
```

## 6.2. カメラの映像をRTSP
出力は確認できた。再生方法はカラーバーと同様。
遅延が妙に大きい。数秒ありそう。
```
./test-launch '( v4l2src device=/dev/video0 ! videoconvert ! video/x-raw,format=I420,width=320,height=240,framerate=30/1 ! videoconvert ! x264enc ! rtph264pay name=pay0 pt=96 )'
```

# 7. 今後
gst-rtsp-serverは未来がないかもしれないので、別の方法で確認したい。
ハードウェアエンコーダがないことで、遅延などのパフォーマンスへの影響がどの程度あるのか調べたい。
ACID特性とその覚え方

## はじめに
データベースの勉強をしていると、
「ACID特性」や「トランザクション」などという言葉をよく聞きます。

私は何回聞いても何が何なのか覚えられなかったので、
アウトプットして覚えようということで記事を書きます。

（この覚え方はあくまで個人的に考えたものです。）

## トランザクションとは
トランザクションは一言でいうと、

**複数の利用者が同時にデータベースにアクセスしても矛盾を発生させないための
SQL処理の最小単位**

です。

以下は例なので、トランザクションが何者かわかっている方は読み飛ばしてください。

例えば、AさんとBさんがスーパーの商品テーブルにアクセスしています。
以下のように同時にデータベースにアクセスすると、矛盾が発生してしまいます。

1. Aさんがりんごを１つ100円で登録する
2. Bさんがりんごを１つ120円で登録する
3. Aさんがりんご10個の合計の値段を計算し、りんごをテーブルから削除する
4. Bさんがりんご10個の合計の値段を計算する

このとき、3でAさんは本来であれば ```100*10 = ¥1,000``` と出力されてほしいですが、
Bさんがりんごの値段を上書きしてしまっているので
予想とは違う ```120*10 = ¥1,200``` が出力されてしまいます。

また、4でBさんはりんご10個の合計の値段を計算したいですが、
Aさんによってりんごの情報がデータベースから消されてしまったので、
エラーが発生します。

トランザクションがないとこのように矛盾が生じます。

**データベースの矛盾を発生させない仕組みをトランザクション管理**といいます。

## ACID特性とその覚え方

トランザクション処理は、ACID特性と呼ばれる4つの特性を備えている必要があります。

### ACID特性の４つ
- Atomicity 原子性
- Consistency 一貫性
- Isolation 隔離性/独立性
- Durability 耐久性


### ACID特性の説明と覚え方
| 特性 | 一言でいうと | 覚え方 |
|:-:|:-|:-|
| 原子性 | 処理が全て完了しているか、全く実行されていないかのどちらかである | 原子はあるかないかのどちらかなので、白黒はっきりさせるのが原子性。 |
| 一貫性 | データに矛盾が生じない | 矛盾がないので一貫性 |
| 隔離性 | 複数のトランザクションを同時または並行のどちらで実行しても結果が一致する | 処理の順番に依存しないので隔離性 |
| 耐久性 | 正常終了した後、障害が発生しても結果が消失しない | 障害があっても結果を保持するので耐久性 |

視覚的にまとめてみると意外とスッキリして覚えられそうな気がします。
ACIDがどの英単語の頭文字なのかを覚えておいて、
あとはそこからこの覚え方を使って導くのが良さそうです。

## 参考文献

- [令和６年応用情報技術者合格教本](https://amzn.asia/d/3G04cLg)
標準提供クラス

標準提供クラスはJava言語が提供しているクラスです。
importをせずとも変数の宣言など様々な機能を使用できるのは標準提供クラスがあらかじめ実装されている為です。
ただし、java.langパッケージもimport無しで利用する事が出来ます。

# 参考文献

https://eng-entrance.com/java-basic-string-standardclass
⚠️Non-ASCII characters に静かになってもらう方法


OS： macOS
IDE： IntelliJ IDEA (Ultimate Edition)

---

# 発生状況
Kotlinで実装を書く前にテストを書いていたときのことです。

Problems > File を見ると

⚠️Non-ASCII characters
⚠️Non-ASCII symbols in ASCII word
⚠️Non-ASCII characters
⚠️Non-ASCII symbols in ASCII word
⚠️Non-ASCII characters
⚠️Non-ASCII symbols in ASCII word
⚠️Non-ASCII characters
⚠️Non-ASCII symbols in ASCII word
⚠️Non-ASCII characters
⚠️Non-ASCII symbols in ASCII word
⚠️Non-ASCII characters
⚠️Non-ASCII symbols in ASCII word
・
・
・

同じ警告多すぎん？？


# 発生要因
Kotlinで書いていたテストのタイトルに、日本語を使っていたことに起因していました。

え・・・。日本人だもん。。。

# 解決方法
解決方法として、テストのタイトルを英語で書くって方法もあるのだが・・・
今すぐ対応するのは私のスペック上しんどいので・・・。

⚠️Non-ASCII characters にカーソルを合わせて、右クリック。
Show Quick-Fixes > Inspection 'Non-ASCII characters' options > Edit inspection profile setting


![Non-ASCII-characters.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3695365/b8901b3c-ef8b-537f-2db0-7119f378ebac.png)

Non-ASCII characters のチェックを外し、OK


![uncheck-Non-ASCII-characters.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3695365/2232e634-3537-50bd-5743-f0d5027eaea6.png)

![no-problems.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3695365/29c85519-b725-e6eb-608e-2907a829a0cf.png)

お〜。静かになった🙌
settings からたどっても設定はできるんだけど、探すの大変だったからこっちのがおすすめです。
Ubuntu上のDockerでPleasanter(SQLServer)環境を作成

# 環境
・OS : Ubuntu 22.04.4 LTS
・Docker: version 20.10.12, build e91ed57

# きっかけ
[以前投稿したPleasanterの環境](https://qiita.com/M_S/items/a864ea5ea69296bcab3b/)を再度作りたいと思い、Ubuntu上で環境を作成しましたが動きませんでした
調べたところ当時使っていたPleasanterのURLが無効になったり、ベースとしていたDockerイメージのバージョンが変わっている（バージョン指定をしていなかったため）ようでした
またPleasanterのGithubページにて、Docker上で動かす手順が公開されていたので[そちら](https://github.com/Implem/Implem.Pleasanter)を試してみましたが、起動するもののなぜかアクセスできませんでした
なので以前の自分の投稿を見直し、環境を作成しました

# 作成方法
以下の内容でDockerfileを作って

```Dockerfile.pleasanter-dotnet-sqlserver
#
# pleasanter -dotnet - sqlserver
#
FROM mcr.microsoft.com/mssql/server:2022-CU11-ubuntu-22.04

ENV ACCEPT_EULA=Y
ENV MSSQL_PID=Express
ENV SA_PASSWORD=Password1!

USER root

RUN apt-get update && apt-get install -y curl

RUN curl https://packages.microsoft.com/config/ubuntu/22.04/mssql-server-2022.list | tee /etc/apt/sources.list.d/mssql-server.list
RUN apt-get update && \
    apt-get install -y  \
    unzip \
    dotnet-sdk-8.0 \
    mssql-server-fts

RUN wget https://github.com/Implem/Implem.Pleasanter/releases/download/Pleasanter_1.4.1.1/Pleasanter_1.4.1.1.zip
RUN unzip Pleasanter_1.4.1.1.zip

WORKDIR /pleasanter/Implem.Pleasanter
RUN  sed -i -e 's/PostgreSQL/SQLServer/g' App_Data/Parameters/Rds.json
RUN  sed -i -e 's/Database=postgres/Database=master/g' App_Data/Parameters/Rds.json
RUN  sed -i -e 's/UID=postgres/UID=sa/g' App_Data/Parameters/Rds.json
RUN  sed -i -e 's/SetSaPWD/'${SA_PASSWORD}'/g' App_Data/Parameters/Rds.json

WORKDIR /pleasanter/Implem.Pleasanter
RUN touch run.sh
RUN echo "/opt/mssql/bin/sqlservr & \n sleep 10 \n  dotnet /pleasanter/Implem.CodeDefiner/Implem.CodeDefiner.dll _rds \n dotnet Implem.Pleasanter.dll --urls=http://0.0.0.0:5000" >> run.sh
RUN chmod 755 run.sh
```

次のコマンドを実行します
```
docker build -t pleasanter-dotnet-sqlserver -f Dockerfile.pleasanter-dotnet-sqlserver .
docker run --name pleasanter-dotnet-sqlserver -p 5000:5000 -d --restart=always pleasanter-dotnet-sqlserver /bin/bash -c "/pleasanter/Implem.Pleasanter/run.sh"
```

これでhttp://{localhost or 起動したUbuntuのIPアドレス}:5000/ にアクセスすればPleasanterのログイン画面が表示されます

# 参考
https://github.com/Implem/Implem.Pleasanter
レゴの歯車を自作する手順

# はじめに
3次元CADを使用し、レゴと組み合わせることができる歯車の自作に挑戦してみました。平歯車に限らず、純正では存在しないやまば歯車やはすば歯車も簡単に作ることができました。基本的な作り方は重複する部分もあるため、本記事ではやまば歯車を中心に解説します。
![assy.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951963/1d3b301a-d709-1dea-9918-900a1cbc996e.jpeg)
# 環境
* Windows 11 Home 22H2
* Autodesk Fusion 2.0.18441
# 手順
まず、平歯車を作成するため、アドインの`SpurGear`を実行します。ここではPythonのロゴが付いている方を選択してください。
![screenshot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951963/4c70ef71-ff01-f2f7-5c13-7147a8ced1e1.png)
実行すると別画面が開き、歯車に関するパラメータを指定できます。特に重要なパラメータはモジュールと歯数です。モジュールが等しい歯車なら噛み合います。レゴの場合、モジュールは1です。つまり、モジュールを$m$、ピッチ円の直径を$d$、歯数を$z$とおくと次式のような関係が成り立つため、ピッチ円の直径と歯数は等しくなります。また、穴の間隔は8mmなので歯数が8の倍数なら何かと都合は良さそうです。今回は24と指定しました。故にピッチ円の直径は24mmと算出されます。
```math
m=\frac{d}{z}
```
その他のパラメータに関しても解説していきます。単位はメートル系、圧力角は初期値の20度です。バックラッシュは少し付けてみました。歯の根元に付けるフィレットの半径は過剰に大きい値だと警告が出るはずです。上限値がヒントとして表示されるため、その値よりも小さい値に修正する必要はありますが、なるべく大きい値を指定した方が歯の強度は高くなります。歯車の形状を使うだけなので歯幅は適当な値で構いません。また、穴の直径も後で編集するため、適当に小さい値を指定しました。最終的に入力したパラメータは下表の通りです。
| 項目 | 値 |
|:-:|:-:|
| Standard | Metric |
| Pressure Angle | 20deg |
| Module | 1 |
| Number of Teeth | 24 |
| Backlash | 0.1mm |
| Root Fillet Radius | 0.5mm |
| Gear Thickness | 12mm |
| Hole Diameter | 1mm |

ここまで進めると下図のように平歯車が出力されるはずです。注意としてアドインを実行した後からパラメータは編集できないため、もし修正したい場合は全て削除し、最初から作り直すしかありません。
![process-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951963/6c5ac047-5711-09db-1a12-edbb186d99f2.png)
次に歯車の形状をスケッチに写し取ります。これ以降、本体の方は不要なので非表示にしました。
![process-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951963/b6df5365-ec7d-8aa8-2eb0-2c1d4755e663.png)
このスケッチを作成した平面に対して垂直な平面に新しくスケッチを作成し、線分を描画します。この線分の長さが歯幅となります。ここでは6mmと指定しました。
![process-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951963/cfec895a-e615-572e-f870-6c329a7481b5.png)
この線分をパスとして歯車の形状をスイープします。ねじれ角度は20度です。なお、正面から見て歯筋が右肩上がりの場合は右ねじれ、左肩上がりの場合は左ねじれと呼びます。どちらのねじれ方向でも構いません。ただし、はすば歯車の場合はねじれ方向を区別し、両方を作成する必要があります。
![process-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951963/e6a0c284-4bdd-6735-cb26-875f7170e913.png)
これを反転させて結合します。
![process-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951963/fb384d39-ce08-e5d0-30c9-a6babc7128d1.png)
最後に全体的な幅を調整するため、両側に円柱を追加します。ここでは15.8mmとなるように合わせました。また、穴は下図のように設計しました。僅かにフィレットを付けてレゴの軸が嵌め合いやすいように工夫しています。
![sketch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951963/5e169490-4157-934c-4f81-d03234c2a6d6.png)
これで完成です。
![process-6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951963/fb884df7-575d-e059-6b20-d435a030306e.png)
# 発注
今回は[**JLCPCB**](https://jlcpcb.com/)に発注しました。素材としては9000Rという白色レジンを選んでみましたが、そこそこ精度も良くて意外と滑らかに噛み合いました。また、レゴの軸も適度に嵌まりました。ただし、歯車のサイズや素材が異なる場合は同じ寸法でも嵌合が悪くなる可能性はあるため、その場合は微調整してください。
![picture.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951963/5babbd55-8a7f-9d6f-0ba0-8727754957a6.jpeg)
# おわりに
簡単にレゴのパーツを作ってみましたが、嵌め合い具合の調整は奥が深そうです。そこまで今回は詳しく触れていませんが、本来なら印刷時に生じる歪みや反りも考慮して設計する必要があると思います。
# 参考文献
* http://bdml.stanford.edu/Main/CrawlerNotes
JavaでOptionalを使用してみる

# 1. はじめに
* JavaでOptionalの使い方を理解したい

# 2. 開発環境
* Java 21

# 3. Optionalの生成
* 3つのファクトリメソッドのいずれかから生成する

| メソッド | 備考 |
| :--- | :---: |
| of(T value) | Optionalを生成。値がnullの場合はNullPointException。 |
| ofNullable(T value)) | Optionalを生成。値がnullの場合は空のOptional。 |
| empty() | 常に空のOptional。 |

* NullPointExceptionにならないからといって何も考えずにofNullable()を利用してはいけない
* 本来NULLになっては行けない場合にof()を使っておけばnullチェックになる
* 自然にNULLが考えられる場合はofNullable()を使用する

# 4. Optionalのメソッド
* Optionalで値を取り出すときは、次の4つのメソッドを使用する
* 値が存在しなかった場合の振る舞いが違うので、利用する時に注意する

| メソッド | 値が存在する場合 | 値が存在しない場合 |
| :--- | :--- | :--- |
| get() | 値を返却する | NoSucheElementException |
| orElse(T other)| 値を返却する  | 指定された値を返却する |
| ofElseGet(Supper<? extends T> other) | 値を返却する | 指定されたsupplierから生成した値を返却する |
| ofElseThrow(Supper<? extends X> exceptionSupplier) | 値を返却する | 指定されたsupplierから生成した例外をThrow |

* get()は値がなかった場合はNoSuchElementExceptionが発生し、NullPointExceptionではない
* orElse()とorElseGet()は似ているが違っていて、orElseGet()はSupplierから値を生成するため遅延実行にある

# ５. Optionalのアンチパターン
* NGのパターン
```java:
Person person = null;
if (optional.isPresent()) {
    person = optional.get();
}
```
 * OKのパターン
     *  orElse(), orElseThrow()等の使用を検討する
 ```java:
 Person person = optional.ofElse(null);
 ```
Reactのアクセシビリティ改善に役立つユニークIDの生成


React 18に追加された新しいフック `useId` を活用することで、重複やハイドレーションエラーを起こさずにユニークなIDを生成する方法を解説します。

(React 19を使用しています)

:::note warn

※ これは2022/12/4に[個人ブログ](https://bicstone.me)で公開した記事を移植し、[CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/deed.ja)で提供しています。情報は古い可能性があります。

:::

## ユニーク ID の必要性

アクセシビリティを改善するためにHTML AttributeへIDを指定することがよくあります。

- 固定値を設定した場合、同じコンポーネントが複数レンダリングされた場合に、IDが重複してしまいます。
- 乱数にした場合、生成されたHTMLとハイドレーション時のIDが異なることにより整合性が取れないためパフォーマンスの問題が発生してしまいます。

## useId について

これらの問題を解決するために、React 18で新しいフック `useId` が登場しました。

https://ja.reactjs.org/docs/hooks-reference.html#useid

> useId はハイドレーション時の不整合を防ぎつつサーバとクライアント間で安定な一意 ID を作成するためのフックです。

## 使用方法

公式ドキュメントによると、1つのコンポーネントで複数のIDを使う場合、接尾辞を付けるよう記載がありました。

- labelタグのforでinputを指定する
- バリデーションエラーをWAI-ARIAで指定する

場合次のようになります。

```jsx
import { useId } from "react";

const PasswordInput = () => {
  const id = useId();
  const inputId = id + "_input";
  const errorMessageId = id + "_errorMessage";

  return (
    <>
      <label htmlFor={inputId}>パスワード</label>
      <input
        id={inputId}
        type="password"
        autoComplete="current-password"
        value={props.value}
        onChange={props.onChange}
        aria-invalid={props.hasError}
        aria-errormessage={props.errorMessageId}
      />
      {props.errorMessage !== undefined && (
        <span id={errorMessageId}>{errorMessage}</span>
      )}
    </>
  );
};
```

## 単体テストの書き方

恥ずかしながら今まで1つしかレンダリングされない前提で、IDを定数で実装していました。テストもその形で作っていたので動的なIDの場合に取得する方法がわからず、しばらくtesting-libraryのドキュメントを探し回っていました。

結果として、 [@testing-library/jest-dom](https://github.com/testing-library/jest-dom) の便利マッチャーを使うとシンプルで宣言的にテストを書くことが出来ました。

(jest 29, jest-dom 5を使用しています)

```js
describe("Password", () => {
  // ...
  describe("has error", () => {
    // ...
    test("has error message", () => {
      // ...
      expect(passwordInput).toBeInvalid();
      expect(passwordInput).toHaveErrorMessage(
        "ID またはパスワードが誤っています",
      );
    });
  });
});
```

## まとめ

- ID系のHTML Attributeを追加したい場合は `useId` を使ってみよう
- `@testing-library/jest-dom` 便利
【Next.js】create-next-appの古いバージョンを入れる

## はじめに

`create-next-app`の古いバージョンを入れたかったのですが、[公式サイト](https://nextjs.org/docs/pages/api-reference/create-next-app)にも情報がありません。検索してみると「古いバージョンは入れられない」と言っている方もいました。

サンプルコードのバージョンが12なので、何とか古いバージョンを入れたいです。

## 結論

以下のコマンドでできました。

```bash
$ npx create-next-app@12 <app-name> && cd <app-name> && npm i next@12
```

:::note warn
単に`$ npx create-next-app@12`だけだと最新バージョンになってしまいます。
:::

## サンプル

筆者が試した例を記載しておきます。

- バージョンは12.2.2
- TypeScriptも入れたいので`--ts`を追加
- アプリ名は`next-sample`とする

```bash
npx create-next-app@12.2.2 --ts next-sample && cd next-sample && npm i next@12.2.2
```

インストール後、バージョンを確認したところ、確かに`12.2.2`になっています。

![スクリーンショット 2024-02-24 16.44.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911578/cc269f24-2a24-6652-5142-e27c65182c5a.png)

`package.json`も`12.2.2`です。

```json
{
  "name": "next-sample",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "next": "^12.2.2",
    "react": "18.2.0",
    "react-dom": "18.2.0"
  },
  "devDependencies": {
    "@types/node": "20.11.20",
    "@types/react": "18.2.58",
    "@types/react-dom": "18.2.19",
    "eslint": "8.57.0",
    "eslint-config-next": "14.1.0",
    "typescript": "5.3.3"
  }
}
```

`$ npm run dev`で起動したところ、問題なく起動しました。

<p align="center">
    <img width="300" alt="create-react-app-start" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911578/c142bb04-6219-59bb-f6e4-49ff925c8c4d.png" />
</p>


## 終わりに

何とか解決してよかったです。

## 参考

https://stackoverflow.com/questions/75470624/how-to-create-next-app-using-version-12-instead-of-version-13
【Java】プログラム作成練習問題 4

# 問題
int型の変数nが0まで1ずつ増減するプログラムを作成せよ。
nが正の場合は減り、負の場合は増えていくこと
## 解答
```java
public class java01 {

	public static void main(String[] args) {
		int n  = -5;
		
		if (n > 0) {
			for(int i = n; i >= 0; i--) {
				System.out.println(n);
				n -= 1;
			}
		} else {
			for (int i = n; i < 0; i++) {
				n += 1;
				System.out.println(n);
			}
		}
	}
}
```

## 模範解答
```java
public class Exercise_004 {
    public static void main(String[] args) {
        int n = -5;

        if (n > 0) {
            for (int i = n; i >= 0; i--) {
                System.out.println(i);
            }
        } else {
            for (int i = n; i <= 0; i++) {
                System.out.println(i);
            }
        }
    }
}
```

## 問題点
1.for文のiの条件式に統一性がない。
2.nをprintlnするよりiをprintlnするべき
## 感想
nを軸に問題を解いたせいで余計な下記の2行が増えてしまった。
```java
n += 1
n -= 1
```
今回はコードの量が少ないので問題はないがコード量が多くなるとこういう無駄な処理は
バグの元なので極力シンプルにコーディングするようにしていきたい。
PowerPlatformのバックアップにはどんな種類があるか

## 結論
2種類あります。
その種類は自動と手動の2種類です。

## 自動バックアップ
正式には「システムバックアップ」といいます

こちらは自動でバックアップをしてくれています。
サンドボックスまたは実稼働環境を立ち上げた時点でシステムが勝手にバックアップを始めてくれます。

バックアップの頻度についてはこちらの記事を参照ください

https://qiita.com/Pawappu/items/62bb4b3bddcbb7308d5a


## 手動バックアップ
こちらはその名の通り手動で現時点でのバックアップを作れます。
PowerPlatform管理センター＞環境＞対象の環境＞バックアップと復元
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524942/4fa16e62-6cd9-2dc5-e280-943d47d9a8b8.png)


画面右側にバックアップの名前を入れて作成です
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524942/83967f8f-2b7c-7086-6155-2256a94ae51d.png)


## まとめ
障害が起きた時は障害発生の時間を確認して、戻したい時間のバックアップを適応しましょう
PowerPlatformの自動バックアップ頻度は1日ごと？？

Power PlatformやDynamics365にはバックアップ機能があります。
そちらについて説明します。

## 回答
30分に自動でバックアップがとられています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524942/3065b259-f772-f7a1-a34c-3221ed15c99e.png)

## どこで確認できるか？
Power Platfomr管理センター→環境→対象の環境を開く
ごめん上部のメニューに「バックアップと復元」から「復元と管理」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524942/7d8de1a1-8493-0cd0-6c78-b622838db976.png)


先に進むと

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524942/8f8197e1-caa5-3230-8388-71ae5192061b.png)

ここで選択できる時間として**30分ごとに選択できます。**


## そもそも「バックアップと復元」が表示されない方
環境の種類が違います。
現状確認できているのは **「サンドボックス」と「実稼働」** 環境の2種類です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524942/73e3e4d4-64b5-d8ad-1ad6-7c8a8a23ffd0.png)
pandasの基本と概要



## はじめに
pandasの基本と概要に関しての備忘録です。
初心者です😅
間違えてる部分が多々あると思います。
もし見つけた場合、ツッコミいただけると助かります🙇
<br>
## 🦁<INS>**結論**</INS>🦁
どういうものです。

:::note info
押さえておくべき点
* 標準ライブラリではないのでインストールが必要。
* Pythonでは表を使う場合にはほぼ「pandas」を用いる。
* いろんなファイルの読み込みが可能（HTMLも可能）
:::  
***


:::note alert
注意点
* 大規模なデータセットを扱う場合、パフォーマンスとメモリ使用量に注意し、適切なデータ型を選択することが重要。
* Pandasは頻繁に更新されるため、新しいバージョンで非推奨になった機能や新機能をチェックが必要。
:::  

***
# Installが必要なライブラリ。
```py
pip install pandas
# もしくは　pip3 install pandas
```
***  



## <INS>**pd.DataFrame()**</INS>
いつも使う表のイメージ。
indexがあり、columnがある。
書き方は辞書の中にcolumn書いてリスト書くイメージ。
Int、float以外はコーテーション（ダブルも可）を入れる。

```py
import pandas as pd

# 辞書からDataFrameを作成
df = pd.DataFrame({
    'A': [1, 2, 3],
    'B': ['a', 'b', 'c']
})
print(df)
```
***

## <INS>**pd.Series()**</INS>
シリーズ
columnを持たない、indexと値のみの構造。
シリーズはデータフレームの単一の列と見なすこともできる。

```py
import pandas as pd

data = pd.Series([10, 20, 30, 40], index=['a', 'b', 'c', 'd'])
```
※indexは指定する場合のみ。通常は0.1.2...



# <INS>**利用シーン**</INS>

## <INS>**DataFrameにて特定の行（列）を全選択する。**</INS>
```py
# カラムAを選択し、シリーズとして取得
series_a = df['A']
```

## <INS>**シリーズではなくcolumn名を指定して列の全選択**</INS>
```py
# データフレームの定義
df = pd.DataFrame({
    'Name': ['Alice', 'Bob', 'Charlie'],
    'Age': [25, 30, 35],
    'City': ['New York', 'Paris', 'London']
})

# 'Name'列を選択
df['Name']
```

## <INS>**シリーズではなく.locや.ilocを使った行の全選択**</INS>
```py
# 0番目の行を選択（ラベルベース）
row_series_by_label = df.loc[0]

# 0番目の行を選択（位置ベース）
row_series_by_position = df.iloc[0]
```

***

## <INS>**DataFrameに新しい列を追加する**</INS>
```py
# 新しい列Cをデータフレームに追加
df['C'] = pd.Series([100, 200, 300, 400])
```
***

## <INS>**DataFrameの特定のcolumnのある条件の値を選択する**</INS>
```py
# カラムAの値が2より大きい行を選択
filtered_df = df[df['A'] > 2]
```
***

## <INS>**DataFrameの特定のcolumnの合計を出したい。**</INS>
```py
# カラムAの合計を計算
sum_a = df['A'].sum()
```
***


## 読込ができるファイル形式
* CSV: pd.read_csv()
* Excel: pd.read_excel()
* JSON: pd.read_json()
* HTML: pd.read_html()（ウェブページのテーブルを読み込む）
* SQL: pd.read_sql()（SQLデータベースからのデータ読み込み）
* Parquet: pd.read_parquet()
* HDF5: pd.read_hdf()
* Feather: pd.read_feather()


## 書き込み可能なファイル形式
* CSV: df.to_csv()
* Excel: df.to_excel()
* JSON: df.to_json()
* HTML: df.to_html()（データフレームをHTMLテーブルとして書き出す）
* SQL: df.to_sql()（データフレームをSQLデータベースに書き込む）
* Parquet: df.to_parquet()
* HDF5: df.to_hdf()
* Feather: df.to_feather()



## まとめ😺
触りだけだけど、かなりすごいライブラリだなと感じる。
Pythonを扱ってる上では必須のライブラリ。
HTMLにはびっくりした。
これからもさらに深掘りしていきたい。
tarの--strip-components 1でうまく最上位のディレクトリを取り除けなくて悩んだ

アーカイブ内にディレクトリが1つある形でアーカイブしたときに`--strip-components 1`でそのディレクトリ配下を展開することがあると思います。

その際にディレクトリそのものが展開されてしまい悩んだのでその時の原因と解決法のメモ。

## 原因

アーカイブされたディレクトリのパスが `./`で始まっていた。

↓testディレクトリを取り除いてhogeが展開されてほしい。
```shell
$ tar -tf test.tar
./test/
./test/hoge
$ mkdir a
$ tar -C a -xf test.tar --strip-components 1
$ ls a
test
```

## 解決法

`--strip-components 2`とする

```shell
$ mkdir b
$ tar -C b -xf test.tar --strip-components 2
$ ls b
hoge
```
or 

`./`を含まない形でアーカイブする

```shell
$ tar cf test2.tar test
$ tar -tf test2.tar
test/
test/hoge
$ mkdir c
$ tar -C c -xf test2.tar --strip-components 1
$ ls c
hoge
```

---

それはそうという感じの内容だけどこれで数十分悩んだ:innocent:
VSCodeでGitHub Copilot Chatを利用できない

# はじめに

VSCodeで利用可能なAIアシスタント「GitHub Copilot」は、開発者の作業を効率化する強力なツールです。
「GitHub Copilot」は2022年6月から個人向けサブスクリプションが開始され、私も2022年8月から契約して日々活用しています。
[GitHub Copilot の概要](https://docs.github.com/ja/copilot/using-github-copilot/getting-started-with-github-copilot)
2023年12月には、自然言語を使って、コードの生成、脆弱性の検出、単体テストの作成などを依頼できる「GitHub Copilot Chat」も一般提供が開始され、開発者がより簡単かつ迅速にコードを書くことができるようになっています。
[GitHub Copilot Chat について](https://docs.github.com/ja/copilot/github-copilot-chat/about-github-copilot-chat)

ここでは、VSCodeで「GitHub Copilot」や「GitHub Copilot Chat」を活用する人が増えている一方で、上手く使えなかった事例と解決策を紹介していきます。

## Visual Studio Codeで「GitHub Copilot Chat」が有効にならない

私はIndividualsプランで「GitHub Copilot」を利用しています。
`GitHub Copilot Individual サブスクリプションを持つすべてのユーザーは、VSCode および Visual Studio の GitHub Copilot Chat にアクセスできます。`と公式で案内されていますので、VSCodeで以下2つの拡張機能をインストールすると良いです。
- GitHub Copilot
- GitHub Copilot Chat

拡張機能をインストールして、Individualsプランを契約しているGitHubアカウントでログインすると、ChatタブでGitHub Copilot Chat が使えるはず・・・なのですが、使えませんでした。
状況としては、「Get started withGitHub Copilot」というテキストの下に、「Start 30-day Free Trial」というボタンが表示されていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631893/7cbdf194-8562-3142-31dc-3f75f365bc4d.png)

指示に従って「Start 30-day Free Trial」というボタンをクリックすると、[GitHub Copilot}(https://github.com/settings/copilot)ページに遷移して、`You have an active Copilot subscription.`と書いているのですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631893/10f4e8f6-e30a-0f27-9615-fe01388046aa.png)
アクティブなサブスクリプションを持っているのに、フリートライアル？？？はい、訳がわかりません。

## 原因と解決策

私の場合、VSCodeでGitHubの複数アカウントにログインしていて、片方は「GitHub Copilot」を利用できないアカウントでした。
- アカウント1: GitHub Copilot Individual サブスクリプションありの個人アカウント
- アカウント2: GitHub Copilot Individual サブスクリプションなしの組織アカウント

VSCodeには、[ユーザーが複数のアカウントでサインインしている場合、間違った GitHub アカウントが選択される](https://github.com/microsoft/vscode-copilot-release/issues/836)場合がある不具合があるらしく、これが原因でした。
Github Copilot拡張機能で使用されているのと同じアカウント1だけでサインインするようにすると、無事GitHub Copilot Chatを使うことができるようになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631893/334b4a1b-b70a-5dcd-4785-84050b7e7c97.png)
やったぜ🥳

他にも、VSCodeとVSCode Insidersでアカウントを使い分けるようにするなど、解決策は色々あるようです。
根本的にGitHubとVSCodeのアカウント管理の連携がうまくいっていないらしく、今後、改善されるなど状況変わるかもしれません。

## 最後に

今回、[vscode copilot](https://github.com/microsoft/vscode-copilot-release)のリポジトリで質問して、同じ悩みを持つ人がヒントをくれたり、親切な人が関連する[issue](https://github.com/microsoft/vscode/issues/127967)を教えてくれて、解決に至りました。
AIに表題の質問を投げかけると、いくつかの表面的な回答と`GitHub Copilot Chatのコミュニティに参加することで、他のユーザーと情報交換したり、問題解決のヒントを得ることができます。`という提案を出力しました。
わからないときはAIに聞くだけではなく、思い切って人に聞く力や勇気も必要だなと改めて感じた次第です。
Temperature MCP9701 の関数化(改)(浮動小数点)(Arduino UNO)(リッチプログラミング)


x MCP9701-E/TO 販売コード 103199

Temperature MCP9701 の関数化(改)(浮動小数点)(Arduino UNO)(リッチプログラミング)


Arduino 電子工作 ArduinoUno 温度センサー MCP9701

目的
温度センサーMCP9701のテスト
隠匿(20240224)


いろいろ

ほかのを見ていると「カプセル化と隠匿」しているので
まねてみた。
たぶん、UNO R3だと成り立つ
AIと小学生用
他は、専用ハードが固定ポートについているのでたぶん、問題が出ない。


ex


```


a=Temperature_MCP9701_A0();
b=Temperature_MCP9701_A1();
c=Temperature_MCP9701_A2();
d=Temperature_MCP9701_A3();
e=Temperature_MCP9701_A4();
f=Temperature_MCP9701_A5();


```

結果

![o_cop972.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/60034dfd-b966-5c8e-3bc5-53335074792a.jpeg)


プログラム


```c++


//SER_Temperature_MCP9701_UNO_2


//インクルド
#include <Arduino.h>
#include "Temperature_MCP9701.h"


//初期化処理
void setup()
{

  //シリアルの初期化
  Serial.begin(9600);

} //setup


//メインループ
void loop()
{

  //センサーの値を読み込む
  //int Sensor = analogRead(A0); // センサーの読み取り値
  //温度の表示
  //float Voltage = Sensor * ( 5.0 / 1024.0 );
  //float Temperature = Temperature_MCP9701(Voltage);
  //Serial.println(Temperature);

  //温度の表示
  Serial.println(Temperature_MCP9701_A0());

  //1秒の待ち
  delay(1000);

} //loop


```

Temperature_MCP9701.h


```c++


// Temperature_MCP9701.h 
//
// ex 3.3V analogReadResolution(12);
//         float Sensor = analogRead(A2);
//         float Voltage = Sensor * ( 3.3 / 4096.0 );
//         float Temperature = Temperature_MCP9701(Voltage);
//
float Temperature_MCP9701(float Voltage){

  return((Voltage - 0.4) * (1.0 / 0.0195));

}//Temperature_MCP9701

float Temperature_MCP9701_A0(void){return Temperature_MCP9701(analogRead(A0)*(5.0/1024.0));}
float Temperature_MCP9701_A1(void){return Temperature_MCP9701(analogRead(A1)*(5.0/1024.0));}
float Temperature_MCP9701_A2(void){return Temperature_MCP9701(analogRead(A2)*(5.0/1024.0));}
float Temperature_MCP9701_A3(void){return Temperature_MCP9701(analogRead(A3)*(5.0/1024.0));}
float Temperature_MCP9701_A4(void){return Temperature_MCP9701(analogRead(A4)*(5.0/1024.0));}
float Temperature_MCP9701_A5(void){return Temperature_MCP9701(analogRead(A5)*(5.0/1024.0));}



```
Gitで既にコミットしたファイルをバージョン管理から外す方法

# はじめに
開発を進める中で「既にコミットしたファイルを後からバージョン管理の対象から外したい」という状況に直面することがあります。
たとえば、機密情報を含むファイルを誤ってコミットした場合や、ビルド生成物をリポジトリに含めたくなくなった場合などです。
こうした場合、.gitignoreファイルを使っても、すでに追跡されているファイルはその対象外となりますので、別のアプローチが必要になります。
この記事では、その方法をステップバイステップで説明します。

# 手順1 .gitignoreにファイルを追加
最初のステップは、バージョン管理から外したいファイルやディレクトリを.gitignoreファイルに追加することです。
これにより、これらのファイルが今後のコミットで無視されるようになります。

```.txt:.gitignore
sample.py
app/
```

# 手順2 キャッシュからファイルを削除
既にコミットされているファイルをGitの追跡から外すために、キャッシュから該当ファイルを削除します。
この操作はファイルを作業ディレクトリに残した状態で行います。
ファイルの場合は次のコマンドを使用します。
```shell
git rm --cached ファイル名
# git rm --cached sample.py
```

```shell
git rm -r --cached ディレクトリ名
# git rm -r --cached app
```

# 手順3 変更をコミット
キャッシュからの削除をリポジトリに適用するためには、この変更をコミットする必要があります。
適切なコミットメッセージを付けて、変更をコミットしましょう。
```shell
git commit -m "特定のファイル/ディレクトリをバージョン管理から除外"
```

# 手順4 変更をプッシュ
最後に、変更をリモートリポジトリにプッシュします。
これにより、他の開発者もこの変更を取り込むことができるようになります。
```shell
git push origin ブランチ名
```
AG-Gridでヘッダーの下にアクションエリアを表示する方法


AG-Gridでテーブルのヘッダー行の下にアクションができる固定行を表示する方法を解説します。

(React版v28を使用しています。)

:::note warn

※ これは2022/12/13に[個人ブログ](https://bicstone.me)で公開した記事を移植し、[CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/deed.ja)で提供しています。情報は古い可能性があります。

:::

## ヘッダー行の下にアクションができる行とは？

正式な名称がわからないので説明的ですが、次のようなUIです。 (もし名前ご存知でしたら教えてください)

![Gmail のスクリーンショット。メールを選択すると、テーブル内の最上部に「このメッセージ内のメッセージ50件すべてが選択されています。」という行(セル)が増える](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684999/0c5a490d-38b2-9f65-d3cd-d4a029270312.png)

AG-Gridではこの機能は搭載されていませんでした。そこで、AG-Gridの様々な機能を活用して無理やり実装してみました。

https://www.ag-grid.com/react-data-grid/full-width-rows/#understanding-full-width

https://www.ag-grid.com/react-data-grid/row-pinning/

https://www.ag-grid.com/react-data-grid/row-selection/

## サンプル

どれか行を選択すると、上から件数と選択されたIDを表示するセルが表示されます。

(個人的には選択するとすべての行が動いてしまうので避けたい実装ではありますが、Gmailと挙動を合わせてみました)

https://codesandbox.io/embed/ag-grid-action-row-mmssuf?&theme=light&view=preview

```tsx
import { AgGridReact } from "ag-grid-react";
import { useCallback, useMemo } from "react";

import type {
  ColDef,
  IsFullWidthRowParams,
  RowHeightParams,
  RowSelectedEvent,
} from "ag-grid-community";

type Data = { id: number; name: string };

// 表示するコンポーネント
const FullWidthCell = ({ api }: IsFullWidthRowParams) => {
  const length = useMemo(() => api.getSelectedRows().length, [api]);
  const selectedIds = useMemo(
    () => api.getSelectedRows().map((v) => v.id),
    [api],
  );

  return (
    <div
      style={{
        borderBottom: `1px solid #eee`,
        width: "100%",
        height: "100%",
        paddingLeft: 24,
      }}
    >
      {length}件を選択中。 {selectedIds.join(",")}
    </div>
  );
};

export const DataGrid = (): JSX.Element => {
  const rowData: Array<Data> = [
    { id: 1, name: "Item 1" },
    { id: 2, name: "Item 2" },
    { id: 3, name: "Item 3" },
    { id: 4, name: "Item 4" },
    { id: 5, name: "Item 5" },
  ];

  const columnDefs: ColDef<Data>[] = [
    {
      field: "check",
      headerCheckboxSelection: true,
      checkboxSelection: true,
    },
    { field: "id" },
    { field: "name" },
  ];

  // 上部に固定
  const isFullWidthRow = useCallback(
    (params: IsFullWidthRowParams) => params.rowNode.rowPinned === "top",
    [],
  );

  // 高さを固定
  const getRowHeight = useCallback(
    (params: RowHeightParams) => (params.node.rowPinned ? 40 : undefined),
    [],
  );

  // 選択時に有効を切り替え
  const onRowSelected = useCallback((event: RowSelectedEvent) => {
    event.api.setPinnedTopRowData(
      event.api.getSelectedRows().length > 0 ? [true] : undefined,
    );
  }, []);

  return (
    <AgGridReact<Data>
      rowData={rowData}
      columnDefs={columnDefs}
      fullWidthCellRenderer={FullWidthCell}
      isFullWidthRow={isFullWidthRow}
      getRowHeight={getRowHeight}
      onRowSelected={onRowSelected}
      domLayout="autoHeight"
      rowSelection="multiple"
      rowMultiSelectWithClick
    />
  );
};
```

## まとめ

AG-Gridでヘッダーの下にアクションエリアを表示できました。なんとなく辛みがあるので、AG-Gridに実装してほしいです。
GoのExcelizeでExcelのセル値読み取り・R1C1形式の変換

[前回の記事](https://qiita.com/te-k/items/cbde3a34577eb6c84f26)の続きで、`.xlsx`に変換したExcelファイルを操作してみます。

ライブラリには、[Excelize](https://github.com/qax-os/excelize)を使います。

```bash
go get github.com/xuri/excelize/v2
```

## Excelの指定セルの値を読み取る
`Excelize`の機能を使って、最初のシート
```go
package main

import (
	"fmt"

	"github.com/xuri/excelize/v2"
)

func main() {
    path := "sample.xlsx"

    // Excelで操作
    f, err := excelize.OpenFile(path)
    if err != nil {
        fmt.Println("error opening excel file: %w", err)
    }
    defer f.Close()
    
    // シート名をインデックスを指定して取得
    sheetName := f.GetSheetName(0)
    
    // 指定したシートの指定したセルの値を取得
    value, err := f.GetCellValue(sheetName, "A1")
    if err != nil {
        fmt.Println(fmt.Errorf("error getting cell value: %w", err))
    }
    
    fmt.Println(value)
}
```

## R1C1形式の変換
`Excelize`でセルの値を取りに行く場合、"A1"などの`string`で指定します。ExcelのR1C1形式で指定したい場合、以下のように変換する必要があります。

```go
func main() {
    // 例として、(1, 1)をA1形式に変換
	cellRef := CoordsToCellRef(1, 1)
	fmt.Println(cellRef) // 出力: A1
}

// rowIndexとcolIndexからA1形式のセルアドレスに変換する関数
func CoordsToCellRef(colIndex, rowIndex int) string {
	col, _ := excelize.ColumnNumberToName(colIndex)
	return fmt.Sprintf("%s%d", col, rowIndex)
}
```
列番号をアルファベットに変換する`ColumnNumberToName`関数が利用できます。
![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482880/086282d6-adab-ec4c-8d05-5e78f9257d55.png)


## Reference
- [Excelize](https://github.com/qax-os/excelize)
- [pkg.go.dev/github.com/xuri/excelize/v2](https://pkg.go.dev/github.com/xuri/excelize/v2)
- [fmt.Sprintf](https://pkg.go.dev/fmt#Sprintf)
Macで使えるハイパーバイザー

VirtualBoxはAppleシリコンのCPUに対応してない。
UTMというHyperVisorでM1チップのMacにRockyやUbuntuがインストールできました。
https://mac.getutm.app

RockyやUbuntuのインストールイメージはarm64を選びましょう。

MacBookAir
Apple M1
Sonoma
[Home Assistant] Virtual Boxのストレージ容量を拡張する

# どんな目的で、何を実現するか
Windows PCにインストールしたVirtual BoxのVM上稼働させたHome Assistantのストレージ容量を増やします。

Home Assistantには様々なログを残す機能もありますし、監視カメラのレコードを残すこともできますが、結果として当初想定していたよりもストレージが必要になってしまうことがあります。

以下の記事の続きです。

https://qiita.com/embcpp/items/c40a8430243d9d03197b


# 前提条件・環境
- ホストPC
    - Minisforum UN100L 16GB/512GB
    - Windows 11 Home 23H2 22631.3155
- Virtual Box 7.0.14
- Home Assistant 11.5



# 手順

# Snapshotの数をゼロにする
仮想ディスクの容量を増やすことで、それにあわせて内部のストレージが自動的に拡張するようになっています。但し、その機能が働くにはスナップショットがゼロの状態としなければなりません。
以下のスクリーンショットでは「2024～」と「最新の状態」の2つが表示されていますが、後者の「最新の状態」だけにしておかないといけません。

　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3084885/66af4ae6-ae70-74e4-86f2-daa20230c495.png)


これを実現するには2つの手段があります。
* Snapshotをすべて削除する
* VMをクローンして新規VMとして立て直す

前者は簡単にできる(ただし、バックアップがなくなるのでお勧めはしない)ので、今回は後者の「VMをクローンして新規VMとして立て直す」を紹介します。前者を選択した方は最新の状態以外のスナップショットを「ストレージ容量を拡張する」の章から始めてください。



## VMをクローンする

### 起動しているVMをシャットダウンする
VMが起動されている状態だとクローン出来ないため、VMをシャットダウンします。VM上でシャットダウン操作を行うか、以下の画像のようにACPIシャットダウンを選択してください。電源オフは強制電源オフ(PCの電源ボタン長押しと同等)ので使用しないでください。
　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3084885/6c24cd26-e376-49fe-9ede-ba629e15e693.png)


### クローンする
最新の状態を選択している状態で「クローン」を押します。
　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3084885/b6b889a5-a0cc-57df-c7c3-ba060855d0f3.png)

エキスパートモードを選択します
　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3084885/aed65a7a-7762-8965-0e5c-4ac719e1a1b6.png)

スナップショットは「現在のマシンの状態」を選択します。ここで「すべて」を選んでしまうとスナップショットも含めてクローンされてしまうので注意してください。
また、MACアドレスのポリシーは「NATネットワークアダプターのMACアドレスのみ含む」を選択し、追加オプションの「ディスク名を保持」と「ハードウェアUUIDを保持」を選択します。※これらは不要かもしれませんが、念のため選択しています。
　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3084885/18abeab2-b508-7eb7-ca8f-facb91d0339e.png)


### 
完了ボタンを押します。以下のような表示がでるのでコピーが終わるまで待ちます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3084885/f2f8899f-e40a-85f0-d73a-ed66bb06f223.png)


## ストレージ容量を拡張する
VMの電源オフ状態でこの作業は行ってください。

ツールの右側の□－からメディアを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3084885/0ac3a0ff-b9e6-6a0d-2365-1e539f323471.png)

利用しているストレージが表示されるので場所の情報を基に、拡張したいハードディスクを選択し、サイズを増やし、適用を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3084885/26780a7b-5afb-3bfc-e4e8-cb8f7081b797.png)


## VMを起動します
起動してしばらくたつとストレージが拡張されているはずです。完成！
Javaにおけるシングルクォートとダブルクォートの違い

シングルクォートで囲まれた文字は1文字のみを表し
ダブルクォートで囲まれた文字は複数の文字であることを示す。
1文字だけ変数に代入したい場合は
```java
char a = 'a';
```
これでOK。

しかし、以下の場合は1文字限定のシングルクォートに対して複数の文字を代入しようとしているため
コンパイルエラーが発動される。
```java
char a = 'aaa'
```

上記のように複数の文字を変数に代入したい場合は
```java
String a = "aaa"
```
とすればOK。
備忘　arduino 割込み


```c
void fun();

void setup(){
  Serial.begin(9600);
  pinMode(2,INPUT);
  attachInterrupt(digitalPinToInterrupt(2),fun,RISING);
}

void loop(){
}

void fun(){
  Serial.println(1);
}

```

attachInterrupt(~~digitalRead(pin)~~,fun,condition)は非推奨
attachInterrupt(<font color="red">digitalPinToInterrupt(pin)</font>,fun,condition)とする

回路は、スイッチを入れると、pin(2)に電圧がかかる、というもの。
初めてのCursor

# はじめに
最近CursorというChatGPTを搭載したVScodeライクなエディタが話題になっています。食わず嫌いは良くないということで、VScode歴3年の私が使用してみた感想を書いていこうと思います。

## 料金とリクエスト数
そこまで使っていないので、リクエスト制限に到達すると何が制限になるのかはわかっていません。無料プランだと1ヶ月で以下のリクエスト数です。
- GPT4が50リクエスト
- GPT3.5が200リクエスト
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557291/72ea5450-9651-61a1-25d2-826aff7ea869.png)

ちなみに、モデルの選択ではcursor-fastという謎のモデルがあります。筆者はこのcursor-fastを利用していますが、特に問題はなさそうです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557291/28203539-dc1e-74d0-6b4b-d32c83d9c2d9.png)


## VScodeの拡張機能のインポート
Cursorを開くと、VScodeの拡張機能をインポートしますか？と聞かれます。これに同意すると、VScodeを利用している人は全ての拡張機能をCursorの拡張機能に入れることができます。
拡張機能を１から入れると考えただけでVScodeから離れられないので、拡張機能のインポートによってCursorダウンロードのハードルはかなり下がると思います。

## ＠mention機能
Chatでは、先頭に＠をつけることでファイル、フォルダー、ドキュメントなどを参照してくれます。このメンション機能が一番便利だと思っています。今のところドキュメント参照だけしか使っていないので、ドキュメントの参照について説明します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557291/49d712e2-ff2c-3040-6158-dd527c43ecc2.png)

### ドキュメントの参照
Pythonのグラフ描写ライブラリであるMatplotlibのドキュメントを参照してグラフを描写してみました。拙い英語で指示をしています。(英語だと日本語よりもトークン数が約1/2でよくて、生成速度は約2倍だからです)
指示：@Matplotlib "2つのグラフを上と下に配置してください"

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557291/8cc79ab7-bbe1-67e0-ec6d-cd6351a5ceb6.png)

自動でコードが生成されます。
```graph.py
import matplotlib.pyplot as plt
import numpy as np

# Create some data
x = np.linspace(0, 2 * np.pi, 400)
y = np.sin(x ** 2)

# Create a figure and a set of subplots
fig = plt.figure(constrained_layout=True)
gs = fig.add_gridspec(2, 1, height_ratios=[2, 1])

# Create the first subplot
ax1 = fig.add_subplot(gs[0])
ax1.plot(x, y)
ax1.set_title('Big subplot')

# Create the second subplot
ax2 = fig.add_subplot(gs[1])
ax2.plot(x, -y)
ax2.set_title('Small subplot')

plt.show()
```

グラフ描画
指示通りに描写してくれています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557291/072efd1e-f0f1-ae2f-b043-39aa6ce445b8.png)


従来の方法だと、ChatGPTに移動→指示→コード生成→コピー→エディタに移動→ペーストの6ステップかかります。
しかし、このメンション機能を使うと、指示→コード生成→コピペの3ステップで完結するので、従来の方法よりも約1/2のステップ数です。

エディタの中で全てが完結するのは素晴らしいですね👍



## 最後に
他にも AIDebugでターミナルで発生したエラーの修正やリントエラーの修正、コードの中身を参照などといった機能があります。便利なので使ってみるといいと思います。制限次第ではCursorに移行することも考えています。

https://cursor.sh/features
試験項目表作成時のメモ

## SI：試験項目表作成
### 粒度について
粒度は、具体性と言い換えられる。
つまり、どれくらい具体的に試験条件を指定して、試験実施するかを粒度という。

### バリデーションについて
①全命令網羅　②decision網羅　③condition網羅　④multiple conditionをベースに作成する。
ex)
```java
if(age >= 0 && age < 18) {
return true;
}
```
①のケース：exで記載されている2つの条件が実施されるケース。
入力値が10であるとき、当てはまる。

②のケース；真と偽のケースが実施される。
入力値が10と-5であるとき、当てはまる。

③のケース：それぞれの条件が真と偽になるケース。
入力値が20,-5であるとき、当てはまる。

④のケース：真&偽、真&真、偽&真が実施される。
入力値が20,10,-5であるとき、当てはまる。

## UT：試験項目表作成
### 境界値を設定
境界値とは、ある値を境に処理が変わる場合に使用される値。
ex)
```java
if(age >= 0 && age < 18) {
return true;
}
```
exの境界値は、0,1,17,18
不等号の記入ミスにより、バグが発生しやすいため上記の境界値を設定する

###　繰り返し処理に対する試験項目を設定する
0回、1回、複数回実施されるテストケースを用意する。

## バグ修正時に発生する試験について
バグ修正前に実施されたものと修正後のものとで修正箇所以外で差分がないか確認できる、バグが修正されているテストケースを確認できる2種類のテストケースを用意する。
初期化について

# 問題
1から10までの和を求めるプログラムを作成せよ。
ただし、for文を用いること。

という問題を解いた際、以下のエラーが出ました。
Exception in thread "main" java.lang.Error: Unresolved compilation problems
私が書いた解答コードは以下です↓

```java
public class java01 {

	public static void main(String[] args) {
		int n;
		
		for (int i = 1; i <= 10; i++) {
			n += i;
		}
		
		System.out.println(n);
	}
}
```

原因は変数宣言時にnに値を代入していないことによるコンパイルエラーでした。
変数宣言時に初期化しないで変数を参照するとコンパイルエラーになると今回の問題で
学べることができました。
あざした！！！
PowerShellGet でインストールしたモジュールの保存先

# PowerShellGet でインストールしたモジュールの保存先

## インストール方法によって異なる

ふと調べてみたところ、
インストールを実行する方法によって保存先が異なっていた。

|インストール方法|保存先|
|---|---|
|管理者権限の Windows PowerShell で実行|C:\\Program Files\\WindowsPowerShell\\Modules\\<モジュール名>|
|通常のWindows PowerShell で実行|C:\\Users\\\<ユーザー名\>\\Documents\\WindowsPowerShell\\Modules\\\<モジュール名\>|
|OneDrive同期しているユーザー| C:\\Users\\\<ユーザー名\>\\OneDrive\\ドキュメント\\WindowsPowerShell\\Modules\\\<モジュール名\>|

環境変数の $env:PSModulePath で確認できる。

```ps
PS> $env:PSModulePath
```
rex0220 計算式プラグイン ルックアップ項目を含む不要なテーブル行の削除（旧）

[計算式プラグイン](https://qiita.com/rex0220/items/ae83c6d5ce50ff7a9a73)でルックアップ項目を含む不要なテーブル行の削除を行います。

# 概要

* TABLE_SORT 関数でテーブル行削除ができますので、今後はTABLE_SORT 関数をお使いください
* [rex0220 計算式プラグイン テーブルソート TABLE_SORT関数版](https://qiita.com/rex0220/items/9c79f548200a09e6e61d)


指定した条件で、レコード保存時にルックアップ項目を含む不要なテーブル行の削除を行います。

テーブルの集計用の TLTABLE 関数を使用するため、集計値の数値項目が必要です。
レコード保存後のイベント処理を行うため、制御用項目が必要です。
テーブル内にファイル添付項目がある場合は、対応できません。

※ルックアップ項目が無い場合は、
[rex0220 計算式プラグイン 不要なテーブル行の削除](https://qiita.com/rex0220/items/4b5d6e215d8065108972)

![2024-02-24_14h57_51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/24f093e2-8a53-23b0-2b3e-9272d5edc2a3.png)

# アプリ設定

テーブル行の識別のため、テーブルに数値項目を配置します。
レコード保存後イベント処理用に、文字列項目で制御項目を配置します。

![2024-02-24_15h02_25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/75979ba4-7a37-e2ad-10d4-1f1cb0deee45.png)


# 計算式プラグイン設定

「循環参照を許可」をチェックします。

![2024-02-24_14h59_53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/5654267c-0d92-3ce3-f657-df183e829dea.png)

レコード保存後のイベント時、TLTABLE 関数で不要テーブル行を削除します。
TPFILTER オプションで、必要なテーブル行の条件を指定します。

TPFILTER(OR(ルックアップ,日付1,文字列1,チェックボックス1,数値1))
ルックアップ,日付1,文字列1,チェックボックス1,数値1に値がある

制御用項目に、更新日時を指定することで、レコード保存後のイベント処理を行う。

```.js
OPTION: 循環参照を許可

// テーブル SUBTABLE (editable)
IF(EV_INFO("mode")!="success","",
  TLTABLE(テーブル,
    TPFILTER(OR(ルックアップ,日付1,文字列1,チェックボックス1,数値1)),
    TPKEY(番号,ルックアップ,日付1,チェックボックス1,文字列1),
    TPVAL(数値1),
    TPOUT(番号,ルックアップ,日付1,チェックボックス1,文字列1,数値1)
  )
)

// テーブル.番号 NUMBER
ROWNO(テーブル)+1

// 制御用 SINGLE_LINE_TEXT
更新日時
```
AndroidStudio MD5、SHA-1、SHA-256の簡単な取得方法

MD5、SHA-1、SHA-256が必要になるときは多くないので、必要になった時忘れていたりしました。

忘れた時に簡単に思い出せるように取得方法を残します。

AndroidStudioの右側のところからGradleを開きます。
![スクリーンショット 2024-02-24 14.34.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274615/b0c56489-8921-f046-b2cf-218929157657.png)

そして``Tasks -> signingReport``をクリックすると取得できます。
![スクリーンショット 2024-02-24 14.34.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274615/f8ff8662-572a-629f-0e46-6ed3aecdfa88.png)

以上です！