OmniAICreator/Qiita-1.07M huggingface dataset:
GitHub Pagesで任意の階層をドキュメントルートにした

リポジトリ上に静的ファイルをアップするだけでwebホスティングできるGitHub Pageでのデプロイをよく利用しています。
公開ソースとなるのは指定ブランチのリポジトリ `/(root)` またはソースブランチの `/docs` フォルダのいずれかになりますが、
今回webpackプロジェクトで開発を行い、`(project)/dist/` の配下のファイルのみをデプロイ対象としたかったので、対応したことを書きます。

#  大雑把なまとめ
1. gh-pages をインストール
2. package.jsonにdeploy実行時の処理を、専用ブランチを指定して追記
3. `npm run deploy` を実行 
4. GitHub Pagesの公開ファイル設定にて専用ブランチを指定してpublish

# やったこと詳細

## gh-pages をインストール
`npm install gh-pages --save-dev` 
GitHub Pagesにデプロイを実行するためのnpmパッケージをインストール。

## package.jsonにdeploy実行時の処理を追記
scriptsにdeploy時の処理を記載。

```
"deploy": "npm run build && gh-pages -d {公開したいディレクトリ} -b {新規ブランチ名}"
```
公開に使うブランチ名を指定する。ここでは`deploy-yymmdd` と命名しました。

```package.json
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack --mode=production --node-env=production",
    "build:dev": "webpack --mode=development",
    "build:prod": "webpack --mode=production --node-env=production",
    "watch": "webpack --watch",
    "serve": "webpack serve",
    "deploy": "npm run build && gh-pages -d dist -b deploy-230307",  // 追記
  },
```


## `npm run deploy` を実行 
実行すると `dist/` 下のファイルが新しいブランチ `deploy-yymmdd` にpushされる

## GitHub Pagesの公開ファイル設定にて専用ブランチを指定してpublish
リポジトリの Settings -> Pages にて、 Sourceを`Deploy from a branch`、Branchを先で指定したブランチの `/(root)` に設定 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1974587/0efba23b-4f29-2230-0bf4-fd9df5c90b3a.png)

この状態でパブリッシュすると、`dist/` 配下でpushされたファイルがルートディレクトリとなるため、webpackでビルドした本番用リソースが公開できました。


※ごく小規模な個人開発においては意図した形でのリリースができましたが、本来適切な手法なのかは分かりません。

参考：

https://docs.github.com/ja/pages/getting-started-with-github-pages/about-github-pages
Cisco Packet Tracer 8.2.0をArch Linuxにインストールする

# 概要
Cisco Packet Tracer 8.2.0をArch Linuxにインストールしようとしたときに少々手こずったのでメモ

# 必要なパッケージ
- https://skillsforall.com/resources/lab-downloads?userLang=en-US
にアクセスしてUbutu版(debファイル)をダウンロード
多くの解説記事では.tar.gzをダウンロードするように書かれているが、**PacketTracer8.2.0では削除されている**ため、debファイルをダウンロードする
- https://aur.archlinux.org/packages/packettracer
にアクセスして 
`git clone https://aur.archlinux.org/packettracer.git` 
をしてパッケージをダウンロードする

# インストール
- cloneしたpackettracerファイル配下にdebファイルを配置

```shell:$ tree packettracer
packettracer
├── CiscoPacketTracer_820_Ubuntu_64bit.deb
├── PKGBUILD
└── packettracer.sh
```

- packettracerディレクトリ内で 
`makepkg -si`
する

- ビルドされインストールが完了している
Office VBA RGBをColor番号へ変換する ヘキサクロス方式関数

# 遅いです
今回は見た目でわかりやすい関数をという事になっています。
早くしたいならByteをIntegerにしたほうがいいですが、エラーを事前にはねるようにByte型を使っています。
したがってマイナス、255より大きい整数はエラーで処理が止まります。
また、VBAに実際にコードを貼ってみるとレイアウトが崩れますが仕様です。

# 原理
## 十進数を16進数にするHexの返り値はString型
一桁の場合、`F`-> `0F`とすることがポイントです。
この方法はRight関数を使うことで解決しました。

## Color番号は16進数では青緑赤の順で並んでいる
ということは
```text
赤　　　緑    青
       X
青　　 緑     赤
```

とすればいいということになります。16進（Hex）にしてクロス（RGB -＞ BGR）するのでヘキサクロス関数です。

## 16進数を10進数に変換するのは`Val("&H")`
`"&H"`は`&H`として良い場合もありますが、今回は連結させるので使います。

# コード
入るときに縦にRGBと並んでいるのが返るときには、縦にBGRのと赤（R）と青（B）がひっくり返っています。
また、難しい計算は必要ありません。単純に並べ替えるだけで結果を得ることができるのです。
遅いと言っても167百万回計算するような状況ですから、1回計算する程度では差はありません。
そうであれば可読性の高い、原理のわかりやすいコードを使うほうがいいでしょう。

```vb
' **** Detail About RGBtoColornumberByHexCrossL ********
' For Microsoft Office VBA
' Hex Cross Method Function
' VBA Hex Function Return String
' Usage    RGBtoColornumberByHexCrossL(255,0,12)
' Caution R and G and B is Byte Data Type,  Unsigned 0 to 255
' By Eacn R G B, 2 Digit Hex - > Cross!! 
'                             - B G R ->
'                               Combine!!
'                             -> Val(&H B G R) -> Hex To Decimal(Long)
' *****************************************************
Function RGBtoColornumberByHexCrossL(R As Byte, _
                                     G As Byte, _
                                     B As Byte) As Long
RGBtoColornumberByHexCrossL = _
         Val("&H" & Right("00" & Hex(B), 2) & _
                    Right("00" & Hex(G), 2) & _
                    Right("00" & Hex(R), 2))
End Function
```

## Advance
もちろん16進数（文字列）のまま返してもいいわけです

```vb
Function RGBtoColornumberByHexCrossH(R As Byte, _
                                     G As Byte, _
                                     B As Byte) As String
RGBtoColornumberByHexCrossH = _
             "&H" & Right("00" & Hex(B), 2) & _
                    Right("00" & Hex(G), 2) & _
                    Right("00" & Hex(R), 2)
End Function
```
### Adverse
逆に6桁の16進数をR、G、Bの10進数の配列（Integer）で返すのがこちら

```vb
Function ColorNumberToRGBbyHexCross(Hex6String As String)
Dim ar(0 To 2) As Integer
Dim sbuf As String * 6
  sbuf = Replace(Hex6String, "&h", "", 1, -1, vbTextCompare)
  ar(0) = Val("&h" & Mid(sbuf, 5, 2)) ' 56 Red
  ar(1) = Val("&h" & Mid(sbuf, 3, 2)) ' 34 Green
  ar(2) = Val("&h" & Mid(sbuf, 1, 2)) ' 12 Blue
  ColorNumberToRGBbyHexCross = ar
End Function
```

# 関数なのに計算式があまりない
256とかMODとか一切出てきていません。16進数に変換するだけでこんなに簡単になるのです。
typescriptであるパターンに従った型定義をしたい

typescriptの型定義であるパターン（たとえばメールアドレスや郵便番号）を型として表現したいと思ったことはないですか？
限界はあると思いますが、下記のように表現可能です。

```typescript
type GMail = `${string}@gmail.com`;

const mail1: GMail = 'hogehoge@gmail.com';
const mail2: GMail = 'hogehoge@yahoo.co.jp'; // ERROR. Type '"hogehoge@yahoo.co.jp"' is not assignable to type '`${string}@gmail.com`'.

type PostCode = `${number}-${number}`;

const postCode1: PostCode = '123-1234';
const postCode2: PostCode = 'aaa-aaaa'; // ERROR. Type '"aaa-aaaa"' is not assignable to type '`${number}-${number}`'.
const postCode3: PostCode = '12345678'; // ERROR. Type '"12345678"' is not assignable to type '`${number}-${number}`'.
```

正規表現ほど柔軟にできませんが、個人的には十分だなと感じました。
TypeScriptすごい。。。ちなみに、正規表現を使用して型判定したい場合ユーザ定義タイプガードを使って実装するというアイデアも使いどころはありますね。

```typescript
declare const postCodeSymbol: unique symbol;
type PostCode = string & { [postCodeSymbol]: never };

// 正規表現にマッチした場合、vをPostCode型として型付けする
const isPostCode = (v: string): v is PostCode => {
  return /^\d{3}-\d{4}/.test(v);
}

const postCode = "123-1234";

// PostCode型を引数に取る
const setPostCode = (postCode: PostCode) => {
  console.log(postCode);
}

// isPostCodeによってPostCode型であると認識される
if (isPostCode(postCode)) {
  // ここではエラーでない
  setPostCode(postCode);
} else {
  // PostCode型として認識されてないのでエラー
  setPostCode(postCode); // ERROR. Argument of type 'string' is not assignable to parameter of type 'PostCode'.
}
```
Jetpack Compose テーマカラー(背景色)の設定

メモ：背景色の設定

※デフォルトはWhite

①色を設定する
■color.kt　ファイル

val Purple200 = Color(0xFFBB86FC)
val Purple500 = Color(0xFF6200EE)
val Purple700 = Color(0xFF3700B3)
val Teal200 = Color(0xFF03DAC5)
val black = Color(0xFF000000) //追加　

②テーマに反映する
■Theme.kt ファイル

private val DarkColorPalette = darkColors(
    primary = Purple200,
    primaryVariant = Purple700,
    secondary = Teal200,
    background = black 　//追加
)

private val LightColorPalette = lightColors(
    primary = Purple500,
    primaryVariant = Purple700,
    secondary = Teal200,
    background = black 　//追加
）


参考(ありがとうございました！)
https://engawapg.net/jetpack-compose/1457/theme/
https://android.benigumo.com/20220711/default-theme-color/
Jetpack Composeを学ぶ⓪

## はじめに
Android歴1.5年の初級〜中級者が、JetpackComposeが浸透していくことを踏まえて学んでいきます

今回は実際のコードや仕組みというより概要やメリットの部分を知っていくといった内容になります

## JetpackComposeとは
[developer](https://developer.android.com/jetpack/compose?gclid=CjwKCAiA3pugBhAwEiwAWFzwdRoIPY1c7pr30jYVG5b5Z-XyQffD0ckcXkYBYBcxNUZaX3ZCuJ0R8BoCj7sQAvD_BwE&gclsrc=aw.ds&hl=ja)によると、**ネイティブ UI をビルドする際に推奨される Android の最新ツールキット**とのこと

以下のメリットがあるそう
- コードを削減
- 直感的
- 開発を加速させる
- パワフル

すごく魅力的なUIに使えるツール？の印象
![スクリーンショット 2023-03-07 23.01.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2044482/cf727fc6-bd04-3805-e1f0-b43a1aac8345.png)
ぱっと見スタイリッシュでカッコ良さそう

[メリット](https://developer.android.com/jetpack/compose/why-adopt?hl=ja#less-code)についてそれぞれ見ていきます

## コードを削減
以下のような意見がある
- 「同じ Button クラスで、コードのサイズが 1/10 になりました。」（Twitter）
- 「画面の大部分を占める、RecyclerView で構築された画面でもコードが大幅に削減されています。」（Monzo）
- 「アプリでリストやアニメーションを作成するのに必要な行がとても少なくって喜んでいます。機能ごとに記述するコード行がわずかで済むので、顧客に価値を提供することにより集中できるようになりました。」（Cuvva）

見る限りRecyclerViewやアニメーションが必要な場合に効果が発揮しそう
また、xmlが不要になってコードを読むのに行ったり来たりがなくなるのが良い点のよう

## 直感的
以下のような良い点があるとのこと
- 宣言型APIが直感的で、UIを記述さえすれば残りの処理はComposeがやってくれる
- テーマの設定を単一のkotlinファイルで行える
- ステートレスコンポーネントで保守が容易になり実装/拡張/カスタマイズが直感的にできる
- 唯一の情報源が状態についてを発信しコンポーザブルが受け取る形で状態がカプセル化できる

わかるようで深くは理解できない。。
宣言的APIとステートレスコンポーネントとコンポーザブルを理解しないといけなさそう

## 開発を加速させる
以下のようなことが書かれていた
- Compose↔︎Viewで相互に呼び出すことができることや、NavigationやViewModelなどのよくあるライブラリやCoroutineが機能するため導入の際の互換性が良い
- ライトモードとダークモードなど考えなくてよくなる
- 複数作成できるプレビューを使って時間の節約につながる

導入する際の障壁が少ないのと、複雑なUIに関する考えなきゃいけないことが少なくなりそう

## パワフル
以下のようなことが書かれていた
- マテリアルデザイン、ダークテーマ、アニメーションなどを組み込んだ美しいアプリが作れる
- 「Compose ではアニメーションを簡単に追加できるので、色やサイズや高度の変化をアニメーション化しない理由が見当たりません。」（Monzo）
- 「何も特別なことをしなくても、静止画面を表示するのと同じようにアニメーションを作成できます。」（Square）

めちゃめちゃ画期的なUIの実装する手段が生まれた？という印象
ここだけ見るとやらない手はないのではと思ってしまうが実際問題どうなのか


## まとめ

- JetpackComposeは今後ネイティブUIを作っていく上で推奨されていくであろうツールキット
- xmlが不要になってUIでアニメーションみたいなものが簡単に実装できる
- 直感的に実装が行え、プレビューを使って実装を加速してくれる

#### 感想
JetpackComposeを学んでいく上てメリットやうまみの部分をざっくり知れて良かった。
良い部分を知ると学ぶモチベーションにも繋がるので今後も良い部分を見つけるようにしたい。

次回は
[Composeコース](https://developer.android.com/courses/jetpack-compose/course?hl=ja)について見ていきたい
別環境テーブルが使えるようになった

Power Appsのアプリ作成時に別の環境テーブルを使用することができるようになりました。

# 手順
### 1.データの追加からテーブルの横の三点リーダーを開き、環境の変更をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404009/1ec3a5ed-e34d-e561-658a-9c6413c76fa7.png)
### 2.接続したい環境を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404009/ee10cde5-fe7f-0676-e0a9-0f2dc87b959d.png)
### 3.接続したいテーブルを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404009/1f975787-03ec-1cb5-d65d-6c261262b4de.png)
### 4.テーブルが追加される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404009/da78352a-6b02-656e-ab63-245f8e5e767c.png)
## おまけ
データテーブルに取引先企業テーブルを追加したら、取引先担当者が自動で入ってくれた。
データテーブルに取引先責任者があるからだと思うけど、知らなかっただけかな～
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404009/b092928f-235a-8774-3f6d-cfbc04f42189.png)
SwiftでSymbolの送信トランザクション

# SwiftでSymbolの送信トランザクションを書いてみた

参考記事はこちら


https://qiita.com/nem_takanobu/items/09b6b687f3cbe10af945


日曜プログラマなので稚拙なのはご容赦ください。
なんならいい書き方を教えてください。


## 構成(XYMのみを送信の場合)
数値は基本リトルエンディアン

```
TransferTransaction
    Transaction
        totalSize(4Byte):このバイト数も含めた総バイト数
        padding(4Byte):穴埋め用。全て0。
        signature(64Byte):versionからmessageまでのペイロードの頭にgenerationHashをくっつけ、それを秘密鍵によってed25519のアルゴリズムで署名する
        signerPublickey(32Byte):送信者の公開鍵(リトルエンディアン)
        padding(4Byte):穴埋め用。全て0。
        ・version(1Byte):1固定
        ・networkType(1Byte):testNetは152固定
        ・transactionType(2Byte):転送トランザクションは16724固定
        ・fee(16Byte):最大払ってもいい手数料
    TransferTransactionBody
        ・recipientAddress(24Byte):Symbolアドレスの最後に"A"をつけてBase32デコードし、末尾の1Byteを消す
        ・messageSize(2Byte):messageのバイト数
        ・mosaicCount(1Byte):モザイクの種類の数
        ・padding(5Byte):穴埋め用。全て0。
        ・mosaicID:モザイクID、リトルエンディアンで示す
        ・amount(8Byte):10000000で1XYM
        ・message(xByte):メッセージをUTF8エンコードしたもの。そこから頭に00をつけないといけない。　

```

メッセージをUTF8エンコードするやつ
```swift
    func utf8DecodeForPayload(val:String)->String{
        var resultStr:String = ""
        for code in val.utf8 {
            resultStr += String(code,radix: 16)
        }
        return "00" + resultStr
    }

```

base32デコードするやつ（こいつ…動くぞ！）
```swift

    private let base32Table = [
        "0":"A",
        "1":"B",
        "2":"C",
        "3":"D",
        "4":"E",
        "5":"F",
        "6":"G",
        "7":"H",
        "8":"I",
        "9":"J",
        "10":"K",
        "11":"L",
        "12":"M",
        "13":"N",
        "14":"O",
        "15":"P",
        "16":"Q",
        "17":"R",
        "18":"S",
        "19":"T",
        "20":"U",
        "21":"V",
        "22":"W",
        "23":"X",
        "24":"Y",
        "25":"Z",
        "26":"2",
        "27":"3",
        "28":"4",
        "29":"5",
        "30":"6",
        "31":"7"
    ]

    private func getKey(val:String)->Int{
        let key = base32Table.first(where: { $1 == val })?.key
        return Int(key!)!
    }
    
    private func getKey2(val: String)->String{
        var resultStr:String = ""
        let val = val.uppercased()
        for s in val{
            var a = String(getKey(val: String(s)),radix: 2)
            while a.utf8.count < 5 {
                a = "0" + a
            }
            resultStr += a
        }
        return resultStr
    }
    
    private func base32Decode(val:String)->String{
        var resultStr:String = ""
        let val = getKey2(val: val)
        var tmpStr:String = ""
        for s in val {
            tmpStr += String(s)
            if tmpStr.utf8.count == 8 {
                let i:Int = Int(tmpStr,radix: 2)!
                let h :String = String(i,radix: 16)
                if h.utf8.count == 1 { resultStr += "0" }
                resultStr += h
                tmpStr = ""
            }
        }
        return resultStr
    }

```
レスポンシブ（responsive）

# レスポンシブとは
画面サイズが異なる様々なデバイス（パソコン、スマホ、タブレット）でも、ユーザーが使いやすく見やすく対応させること。
# メディアクエリの基本
メディアクエリとは、指定した画面のサイズの時にのみ使われるCSSの要素などを決めるもの。
`@media　screen and (min-width:780px) { }`
画面の横幅（width）が780pxまでは、以下のCSSを適応するという意味です。よって上記のコードでは、「画面の横幅が780px以上の時はfont-sizeが300px、それ以外の場合は30pxということになります。
# モバイルファースト / デスクトップファースト
`@media　screen and (min-width:780px) { }`の場合、デフォルトでは、フォントの大きさは30pxで、画面が780pxより大きい場合は300pxという条件を付けた書き方になっています。 これは、基本が小さい画面に合わせた書き方になっていると言えます。 このように、小さい画面を基本にした指定の仕方をモバイルファーストと言います。 
逆に大きい画面を基本にした書き方はデスクトップファーストと言います。以下のようにminではなく、max-wdithと書いて指定します。`@media　screen and (max-width:780px) { }`
# やってみた
## Live　780px以上（デスクトップ画面）
![スクリーンショット 2023-03-07 23.48.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193952/a8dead9d-9c76-1377-75fe-ae707479b972.png)
## Live　７８０px以下（スマホ画面）
![スクリーンショット 2023-03-07 23.48.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193952/dd206e91-3723-7bd5-8de7-b1887c6ad358.png)
## html
![スクリーンショット 2023-03-07 23.48.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193952/7f071c94-f738-394e-2d78-ca87095090c9.png)
## css
![スクリーンショット 2023-03-07 23.48.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193952/0fbe6cd1-2a89-400a-c25e-9f0eec5c1dcf.png)
YAMAHA ルータの ICMP too large 対処

自宅 YAMAHA ルータの「不正アクセス検知」機能を有効にしてみたら「ICMP too large」なる内容で大量に検知されてしまって、対処に割と苦戦した。

## まとめ
- (今回の) ICMP too large の原因は iOS デバイスらしく、ググるとよくあることらしい
- コマンドで有効にした不正アクセス検知設定を GUI で無効にしたところ、対象範囲が違っていたようで無効にできておらずハマった
- それはそうと ICMP の検知設定をすべて無効にする対応はちょっと雑すぎるので、より良い方法があるなら知りたい

## 自宅環境
- YAMAHA NVR700W (Rev.15.00.23)
- IPoE で IPv6 インターネットに接続
- MAP-E トンネルくぐって IPv4 インターネットに接続

## やったことログ
(ルータの Web GUI をポチポチしているとき)
「不正アクセス検知」機能使ったことなかったな、有効にしてみるか

http://www.rtpro.yamaha.co.jp/RT/manual/rt-common/ip/ip_interface_intrusion_detection.html

``` config
ip lan1 intrusion detection in on reject=on
ip lan1 intrusion detection out on reject=on

tunnel select 1
ip tunnel intrusion detection in on reject=on
ip tunnel intrusion detection out on reject=on
```

(※ MAP-E トンネル使ってるのでインタフェースが tunnel になっている)

→ 数分後、ルータがピーピー鳴り出す

ダッシュボードみると「ICMP too large」なる不正アクセス検知履歴が大量に

送信元 IP (ローカル IP) を調べる
→ iPhone っぽい

送信先 IP を調べる
→ Apple の IP っぽい

「ICMP too large」 でググる
→ iOS ではよくあることらしいが、有効な対処方法を見つけられず

MAP-E インタフェースで検出されているから MAP-E の ICMP 検出を止めれば良いんじゃろ？ (GUI で無効化)
→ 止まらない

ダッシュボードには「不正アクセス検知」とエラーが出てピーピー鳴っているが、各インタフェースの検出履歴を見てもどこにも検出履歴がない
→ ？？？

めんどくさいので、GUI の「不正アクセス検知」設定画面から全 ICMP の検知止めてやろ
→ 止まらない

サポートに泣きつく
→ **「OUT 方向も止めるんやで」**

なるほど〜 (それはそう)

``` config
ip lan1 intrusion detection out icmp off

tunnel select 1
ip tunnel intrusion detection in icmp off
```

→ 止まった〜〜〜

## ハマりポイント
**「GUI だと検知対象のプロトコルごとに IN/OUT が決まっておりいずれかの設定しか操作できないが、コマンドだと両方設定できる」**

例えば ICMP の不正アクセス検知は GUI から設定できるのは「IN 方向」と決まっており、GUI からだと IN 方向の設定しか操作できないが、コマンドからだと OUT 方向の設定もできる。

今回は、最初にコマンドで type を指定せずに (= 全種類の) IN/OUT の検出を有効にして、さらに GUI から無効化を試みたため、ICMP OUT 方向は有効化されたままになった。
→ GUI ですべて無効化したつもりが無効化できておらず、検出され続けるという事態に

まぁ確かに、インタフェースの IN/OUT どちらかで検出できればいいもんな...

## コマンドでの設定例
コマンドで GUI と同様に設定するには、下記のようにひとつひとつ有効化していくしかなさそう。

``` config
ip lan1 intrusion detection in on
ip lan1 intrusion detection in ip on reject=on
ip lan1 intrusion detection in ip-option on reject=on
ip lan1 intrusion detection in fragment on reject=on
#ip lan1 intrusion detection in icmp on reject=on
ip lan1 intrusion detection in udp on reject=on
ip lan1 intrusion detection in tcp on reject=on
ip lan1 intrusion detection in default off
```
GASを用いてGmailの未読メールを１分おきにチェックしてスプレッドシートに記録する方法

# はじめに

GAS を用いて、１分おきにメールをチェックして、ある条件を満たしたメールから必要な情報を抽出してスプレッドシートに書き込む方法について紹介します。

## 簡単な方針解説

言葉にするとかえって難解になるかもしれませんが、大きくは３ステップ程度です。

1. ログを取り専用のスプレッドシートを作成し、機能拡張 --> Apps Script を作成する。必ず、スプレッドシートから GAS を作成すること。それにより、それを呼び出したスプレッドシートに紐づけられたGASが出来上がる。
2. 下記を参考に GAS をコーディングする。ここでのポイントは、最近の未読メールから10件検索し、ある条件を満たした場合にその情報をスプレッドシートに保存し、そのメールを既読にすること。これにより、ダブルカウントを防ぐ。
3. GASの設定で、「イベントソースの選択」で「時間主導型」にして、「時間感覚の設定を1分おき」にする。

以下、具体例で紹介します。

# 簡単な例

ここでは、"Zoom responsecheck" という件名のメールを見つけたらその内容をスプレッドシートに書き出す、という簡単な例を紹介します。

## GASのコーディング

https://tetsuooo.net/gas/512/

https://blog.synnex.co.jp/google/gmail-gas/

など参考にさせていただきました。

``` js:
function myFunction(){
  //件名に、「Zoom connection information」の文字列を検索条件に指定して抽出命令 
  let query = 'is:unread subject:(Zoom responsecheck)'; // is:unread で未読メール限定とする
  let gmail = getGmail(query);

  if (gmail.length > 0){ // 一件以上ヒットした場合のみ実行

  //スプレッドシートに書き出し
  let sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  let lastRow = sheet.getLastRow();
  let row = gmail.length;
  let col = gmail[0].length;

  let range = sheet.getRange(lastRow+1, 1, row, col);

  range.setValues(gmail);
  }
}

function getGmail(query){

  //新着メール情報を格納する配列を宣言
  let array = [];

   //Gmailの履歴からマッチするメールをスレッド化、最新の10通を取得
  let threads = GmailApp.search(query,0,10);

  //一覧化したメールの件数分繰り返し 
  threads.forEach(function(thread) {

    // スレッド内のメール一覧を取得
    let messages = thread.getMessages();

    // メールを一つずつ取り出す
    messages.forEach(function(message) {

      //メール受信日の取得
      let date = message.getDate();
      date = Utilities.formatDate(date, 'Asia/Tokyo', 'yyyy/MM/dd HH:mm:ss');

      // メール本文の取得
      let plainBody = message.getPlainBody();
      array.push([date, plainBody]); //受信日と本文の組を配列に追加
      })

    thread.markRead() // 未読を既読に変更。これで次に is:read で検索されない。
  })
  return array;
}
```

検索部分は、
let query = 'is:unread subject:(Zoom responsecheck)'
で、is:unread で未読メール限定とした上で、subject: で、件名に限定し、(Zoom responsecheck) という文字列が続いているものを検索します。丸括弧()がないと意味が変わってしまうので注意です。丸括弧があることで、連続した文字列という意味になり、丸括弧がないと and の検索条件になります。

## トリガーの設定

トリガーの設定で、１分おき、を選びます。

![スクリーンショット 2023-03-07 23.41.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179652/cdb269dc-78d6-c8d2-6abc-9b40e75b6a05.png)


## 実行例

Zoom responsecheck というタイトルで、本文が テスト1, テスト2 というメールを送ると、

![スクリーンショット 2023-03-07 23.42.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179652/3611a368-d8dc-43d1-05df-ae94b6a86505.png)

のように追記されます。

## 注意点

未読メールに対して検索をかけて、ヒットしたら既読にする、ことでダブルカウントを防いでいます。もし、未読のままにしたい場合は、スプレッドシートの中身と照合するなど別の方法でダブルカウントを防ぐ方が良いです。

## 関連記事

GASの使い方などは割愛しています。他のページを参照ください。

https://qiita.com/yamadasuzaku/items/fdec0813c704a6a2784a
【React初心者】JSXのルール

# 概要
JSXはHTMLそのものではなく、独自のルールを持っている。
今回は基本的なルールを以下にまとめる。
# 最上位の要素は1つにする
React要素はASTの形で扱われているが、Reactではその最上位が1つであることを要求する。
以下の記述では最上位にh1要素とp要素の2つが存在することになるため、エラーとなる。
```
export default function Home() {
  return <h1>Test</h1> <p>testtesttest.....</p>
}
```
そのため、たとえば`<div></div>`で囲うとエラーが解消される。
```
export default function Home() {
  return (
    <div>
      <h1>Test</h1>
      <p>testtesttest.....</p>
    </div>
  )
}
```
## `<div>`を追加したくない場合は...
`<React.Fragment>`を使うことができる。
```
export default function Home() {
  return (
    <React.Fragment>
      <h1>Test</h1>
      <p>testtesttest.....</p>
    </React.Fragment>
  )
}
```
また、`<React.Fragment>`は`<>`に置き換えることもできる。
```
export default function Home() {
  return (
    <>
      <h1>Test</h1>
      <p>testtesttest.....</p>
    </>
  )
}
```
# 要素は閉じる
HTMLでは閉じる必要がない要素でも、JSXでは必ず閉じなければならない。
たとえば、以下のように`<hr>`を追加すると、エラーとなる。
```
export default function Home() {
  return (
    <div>
      <h1>Test</h1>
      <hr>
      <p>testtesttest.....</p>
    </div>
  )
}
```
`<hr />`に書き換えるとエラーは解消される。
※`<img>`なども同様のため注意
```
export default function Home() {
  return (
    <div>
      <h1>Test</h1>
      <hr />
      <p>testtesttest.....</p>
    </div>
  )
}
```
# classはclassNameと書く
HTMLの感覚で`class`を使うとWarningが表示されるため、`className`と記述する。
※現在のReactでは`class`でも機能するが、Warningの扱いである
多くのコンポーネントでが`className`を使っているため、トラブルの原因になることから`class`の使用は推奨されていない。
```
export default function Home() {
  return (
    <div className="test">
      <h1>Test</h1>
      <p>testtesttest.....</p>
    </div>
  )
}
```
# style属性の値は{{}}の中に書く
`style`属性の値は文字列ではなく、キャメルケース（camelCase）のプロパティを持ったオブジェクトとして指定する必要がある。
```
export default function Home() {
  return (
    <div>
      <h1 style={{ color:'red',fontSize:'48px' }}>Test</h1>
      <p>testtesttest.....</p>
    </div>
  )
}
```
# 式（Expression）は{}の中に書く
JavaScriptの式（Expression）は`{}`で囲うことで、JSXの中でも使える。
変数だけでなく、関数や条件分岐なども使用できる。
```
export default function Home() {
  const sub = 'testtesttest.....'

  return (
    <div>
      <h1>Test</h1>
      <p>{sub}</p>
    </div>
  )
}
```
#　複数行で書く場合は`()`に入れる
要素を複数行に分けて記述する場合には`()`に入れる。
```
export default function Home() {
  return (
    <>
      <h1>Test</h1>
      <p>testtesttest.....</p>
    </>
  )
}
```
# まとめ
書いているコードはあくまでも**JSX**、**JavaScript**のコードだということを意識すれば、問題ないと思う。
Reactの実行開始ファイル「index.tsx」の名前を変更してみる

## はじめに
create-react-appでテンプレートを作成した場合、エントリーポイントは`index.tsx`固定になっています。
ふと、このファイル名を変更するにはどうすればいいか？気になったので実験してみました。

eject('npm run eject')を実行すると、隠されていた設定ファイルとビルドスクリプトが出力されます。

その中に`config\paths.js`というファイルがあり、各種パスが定義されていました。
`appIndexJs`を書き換えれば目的が達成できそうです。

ただ、ejectすると後が大変ですので[react-app-rewired](https://www.npmjs.com/package/react-app-rewired)(設定を書き換えるツール)を使って書き換えてみます。


```js
// config after eject: we're in ./config/
module.exports = {
  dotenv: resolveApp('.env'),
  appPath: resolveApp('.'),
  appBuild: resolveApp(buildPath),
  appPublic: resolveApp('public'),
  appHtml: resolveApp('public/index.html'),
  appIndexJs: resolveModule(resolveApp, 'src/index'),
  appPackageJson: resolveApp('package.json'),
  appSrc: resolveApp('src'),
  appTsConfig: resolveApp('tsconfig.json'),
  appJsConfig: resolveApp('jsconfig.json'),
  yarnLockFile: resolveApp('yarn.lock'),
  testsSetup: resolveModule(resolveApp, 'src/setupTests'),
  proxySetup: resolveApp('src/setupProxy.js'),
  appNodeModules: resolveApp('node_modules'),
  appWebpackCache: resolveApp('node_modules/.cache'),
  appTsBuildInfoFile: resolveApp('node_modules/.cache/tsconfig.tsbuildinfo'),
  swSrc: resolveModule(resolveApp, 'src/service-worker'),
  publicUrlOrPath,
};
```


## 前提

create-react-appで作成したプログラム(--template typescript)

## 手順


① package.jsonの`devDependencies`に`react-app-rewired`を追加

```sh
  npm i -D react-app-rewired
```

② ビルドの設定変更を行うため`config-overrides.js`をルートフォルダに作成

`paths.appIndexJs`の設定を上書きします。

```js
const path = require('path');
module.exports = {
  paths: function (paths, env) {
    paths.appIndexJs = path.resolve(__dirname, 'src/entry-point.tsx');
    return paths;
  },
};
```

③ package.jsonを修正

```json
  "scripts": {
-    "start": "react-scripts start",
-    "build": "react-scripts build",
+    "start": "react-app-rewired start",
+    "build": "react-app-rewired build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  }
```

④ `index.tsx`を`entry-point.tsx`にリネーム

```sh
mv index.tsx entry-point.tsx
```
![img10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276579/03b1b53b-7bbe-7c12-7103-3ccfb8ca0798.png)

⑤ 動作確認

```sh
npm run start
```
いつもの画面が表示されました

![img20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276579/4d8b786d-5e77-97b5-0e58-dbdf10ab48f9.png)


## 参考ページ
[react-app-rewired](https://www.npmjs.com/package/react-app-rewired)には`path`だけではなく、`webpack, jest, devServer`の書き換え方の説明が乗っています。
Prismaの"debian-openssl-3.0.x"エラーに関する忘備録

これは、CI上でPrismaでシードスクリプトを実行した時のエラーに関する忘備録。

Cypressを使ったE2Eのテストを行う際にPrismaのシードスクリプトを実行したところ次のエラーが発生した。

```shell
...
Running seed command `ts-node --require tsconfig-paths/register prisma/seed.ts` ...
PrismaClientInitializationError: 
Invalid `prisma.user.delete()` invocation in
/home/runner/work/example-app/example-app/prisma/seed.ts:22:27

  19 const email = "rachel@remix.run";
  20 
  21 // cleanup the existing database
→ 22 await prisma.user.delete(
Query engine library for current platform "debian-openssl-3.0.x" could not be found.
You incorrectly pinned it to debian-openssl-3.0.x

This probably happens, because you built Prisma Client on a different platform.
(Prisma Client looked in "/home/runner/work/example-app/example-app/node_modules/@prisma/client/runtime/libquery_engine-debian-openssl-3.0.x.so.node")

Searched Locations:

  /home/runner/work/example-app/example-app/node_modules/.prisma/client
  /home/runner/work/example-app/example-app/node_modules/@prisma/client
  /home/runner/work/example-app/example-app/node_modules/@prisma/client
  /home/runner/work/example-app/example-app/node_modules/.prisma/client
  /home/runner/work/example-app/example-app/prisma
  /tmp/prisma-engines
  /home/runner/work/example-app/example-app/node_modules/.prisma/client


To solve this problem, add the platform "debian-openssl-3.0.x" to the "binaryTargets" attribute in the "generator" block in the "schema.prisma" file:
generator client {
  provider      = "prisma-client-js"
  binaryTargets = ["native"]
}

Then run "prisma generate" for your changes to take effect.
Read more about deploying Prisma Client: https://pris.ly/d/client-generator
    at RequestHandler.handleRequestError (/home/runner/work/example-app/example-app/node_modules/@prisma/client/runtime/index.js:34316:13)
    at /home/runner/work/example-app/example-app/node_modules/@prisma/client/runtime/index.js:34737:25
    at async PrismaClient._executeRequest (/home/runner/work/example-app/example-app/node_modules/@prisma/client/runtime/index.js:35301:22)
    at async PrismaClient._request (/home/runner/work/example-app/example-app/node_modules/@prisma/client/runtime/index.js:35273:16)
    at async seed (/home/runner/work/example-app/example-app/prisma/seed.ts:22:3) {
  clientVersion: '4.6.1',
  errorCode: undefined
}

An error occurred while running the seed command:
Error: Command failed with exit code 1: ts-node --require tsconfig-paths/register prisma/seed.ts
```

この時のPrismaのバージョンは次のとおり。

```json
"dependencies": {
  "@prisma/client": "^4.5.0"
},
"devDependencies": {
  "prisma": "^4.10.1"
}
```

エラーログの指摘通り、**schema.prisma**を修正して、`binaryTargets`に`debian-openssl-3.0.x`を追加するという方法も考えた。
しかし、すでにある程度動いているアプリケーションであったため、あまり**schema.prisma**を修正するのは避けたいと考えた。

そこで、Prismaのバージョンを上げてみることにした。

```shell
$ npm install prisma@latest @prisma/client@latest
```

すると、次のようにバージョンが上がった。

```json
"dependencies": {
  "@prisma/client": "^4.11.0"
},
"devDependencies": {
  "prisma": "^4.11.0"
}
```

この状態でコミットを行い、CIを実行したところ、エラーが解消された。
RESTについて。アウトプットしてみた

## RESTとは

アプリケーションの設計方法の一つ
HTTPメソッドを使ってwebのリソースを操作する際の設計方法
（HTTPメソッドとは～ブラウザでWebページを見る際やフォームに入力したデータを送信する際に裏側でブラウザからサーバに送信されている命令の事）

HTTPメソッドの種類と役割
GET　リソースの取得
POST　リソースの作成
PATCH/PUT　リソースの更新
DELETE　リソースの削除
bashスクリプトをオブジェクト指向っぽく書いたらこうなった

```
hoge@penguin:~$ cat Log.class.sh 
```
```sh:Log.class.sh
#!/usr/bin/bash

function Log_print() {
        declare -n this=$1
        local log=$2

        echo `date '+%Y-%m-%d %H:%M:%S.%3N'` $log >> ${this[logfile]}
}

function Log() {
        declare -n this=$1
        local logfile=$2

        this[logfile]=$logfile
        this[print]="Log_print $1"
}

declare -A exelog
Log exelog exe.log

declare -A errlog
Log errlog err.log

${exelog[print]} "start!"
${errlog[print]} "error!"
${exelog[print]} "end!"
```
```
hoge@penguin:~$ ./Log.class.sh 
hoge@penguin:~$ more *.log
::::::::::::::
err.log
::::::::::::::
2023-03-07 22:09:26.863 error!
::::::::::::::
exe.log
::::::::::::::
2023-03-07 22:09:26.857 start!
2023-03-07 22:09:26.875 end!
hoge@penguin:~$ 
```
Pythonコース2周目の世界線2

2周目の2日目：今回も可能な限り突き進んでいくぞい！猪突猛進んんんんん！！！！


◎復習兼メモ◎

引数のとこ間違えすぎぃ！！！！！！！！！
じゃんけんゲームのとこ難しすぎぃ！！！！！

モジュールは別ファイルをモジュールとして読み込むことでスッキリする。呼び出すときは「import　モジュール名」※.pyはつけなくておk


ｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰｰ

今日は会社で作った画像リサイズシステムを一緒に仕事をしている人に披露したら、思ったより好評だった。嬉しい。
こうやって自分で作って便利だなって思ったものが活躍すると達成感が何倍にもなった気がする。
人間だものそりゃそうだ。嬉しいに決まってる。

次回は以前やったPythonコース5が短かったのでコース4とコース5を終わらせて、3周目世界線へと向かうぞい😤
モジュール、コンポーネント、ライブラリ

・モジュール：部品単独でも動作し、他の部品と組み合わせて使うもの
・コンポーネント：部品単独では使用せず、他の部品と組み合わせて使うもの
・ライブラリ：外部提供のプログラム部品（他のプログラムに機能を提供するコードの集まり）
[Unity] RequireComponentAttributeの or 版を作りたかった

# 概要
UIの基盤を実装する時、たまに↓みたいなことをしたくなることがあった
```C#
[RequireComponent( typeof(VerticalLayoutGroup) or typeof(HorizontalLayoutGroup) )]
```
~~そろそろ重い腰を上げて~~調べたところ、割と簡単にできそうだったので備忘録として要点をまとめる
# 実装
```C#
// コンポーネントを追加した時が取れるので、ここで検証を行う
ObjectChangeEvents.changesPublished += (ref ObjectChangeEventStream stream) =>
{
    for (int i = 0; i < stream.length; i++)
    {
        switch (stream.GetEventType(i))
        {
            case ObjectChangeKind.ChangeGameObjectStructure:
                stream.GetChangeGameObjectStructureEvent(i, out ChangeGameObjectStructureEventArgs args);
                var go = EditorUtility.InstanceIDToObject(args.instanceId) as GameObject;
                // 具体的に何が起こったかは分からないので、持ってるComponentを全て洗う
                break;

            // こっちは子に変更が入った時に呼ばれてそう（蛇足）
            case ObjectChangeKind.ChangeGameObjectStructureHierarchy:
                break;
        }
    }
};

```

[実装の全容はここから](https://github.com/riru-ruribe/UnityExtension_RequireComponent)
~~手抜きで~~エラー出すだけだが、個人的には良い感じ
うちのPC紹介-デスクノートCore i7-7700HQ君

これからちょこちょこ家にあるPCのベンチ紹介とかしようと思ったので、
その前にPCごとのスペックとか紹介しようと思った。

# 7700HQ君

・マウスコンピューター m-Book W（2017モデル）
　（紹介記事：https://ascii.jp/elem/000/001/496/1496451/）
・CPU：Core i7-7700HQ
　・第7世代インテルCore i7
　・4コア8スレッド
　・2.8GHz～3.8GHz
　・TDP：45W
　・[詳しくはここ](https://www.intel.co.jp/content/www/jp/ja/products/sku/97185/intel-core-i77700hq-processor-6m-cache-up-to-3-80-ghz/specifications.html)
・メモリ：16GB（増設）
・SSD：500GB（SSD換装）
・GPU：GeForce GTX 1050 4GB (mobile)
・OS：Windows 10 Pro
・ディスプレイ：17.3インチFullHD
・重量：2.8kg
・モットー：でかい、重い、GPUあり
・こいつの良いところ
　・3画面外部出力
　　・HDMI✕1、Mini DisplayPort✕2
　　・フルHD＋4K外部ディスプレイ3枚も可能らしい（試したことない）
・こいつの悪いところ
　・大きくて重くて持ち運びづらい
・感想（2023/2/25）
　　とても良く動いてくれた！！！
　　デスクトップの代わりになってそこそこ3D動けばいいなぁと思って、
　　「でかい・重い」構成で買いました。
　　GPUあり選んだこともあって、
　　割と長い間使わせてもらいました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154954/9a33eadc-c176-a236-42d8-461316349cf1.png)

## ベンチマーク結果
[こちらを参照](https://qiita.com/kit/items/0d57a3433a2e44062d3a)（2023/2/25：数年使って調子悪いときのベンチ）

## 用途
#### 2018年～
・メインPC
　・普段作業
　・開発
#### 2023～（予定）
・趣味検証PC
　・VMware環境
Google One Tap Sign-inでJavaScript APIではlogin_uriが使用できないという話

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/ecf72f0b-86c7-2911-37f1-1bd9a8af3042.png)

https://developers.google.com/identity/gsi/web/reference/js-reference?hl=ja#login_uri

Serverに直接POSTされるためには、HTML APIで`data-login_uri`を使用しましょう、という話

```html
<script src="https://accounts.google.com/gsi/client" async defer></script>
<div id='g_id_onload'
     data-client_id="YOUR_CLIENT_ID.apps.googleusercontent.com"
     data-login_uri="https://example.com/callback.php" ></div>
```
SlackからChatBotを呼び出す。

SlackからChatBotを呼び出します。

最終的にはlambdaを呼び出して、EC2の起動停止をさせたいなと思います。

色々調べたところ、PythonやNodejsで行っている方は割といるのですが、C#がないとなったので今回はC#で書いています。結構.NET使ってる人いますよね？（え？いない？）

まぁそんなわけで第一弾、SlackとChatBotを連携させます。

あらかじめSlackにログインしておいてください。
ではAWSにログインして、ChatBotを開きます。
チャットクライアントをSlackにして、クライアントを設定を押します。

![スクリーンショット 2023-03-07 21.45.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2737143/57698a5f-31a4-d3b9-4c3d-4a9f88d3163f.png)


するとこんな感じで権限のリクエストに飛びますので許可してください。
![スクリーンショット 2023-03-07 21.46.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2737143/6f0a79d7-1a97-c940-10cb-1eab7b01abe5.png)


連携されるとこのような画面に飛びます。
![スクリーンショット 2023-03-07 21.47.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2737143/2e737b7e-adc9-56ea-96ca-5029f159528e.png)

一旦Slackにもどります。今回連携するSlackのトチャンネルはプライベートです。
プライベートの場合はチャンネルIDが必要となるので、あらかじめSlack側から情報を取得しておきます。
チャンネルのタイトルをクリックしましょう。
![スクリーンショット 2023-03-07 21.54.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2737143/decd7481-9a05-320b-66f1-62d0635742e1.png)

出てきた画面の下部にチャンネルIDが記載されています。ここを控えます。
![スクリーンショット 2023-03-07 21.52.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2737143/95d069bb-a4af-51e4-8da1-07820a9b1a83.png)

ではここでAWS側に戻ります。新しいチャンネルを設定を押します。
![スクリーンショット 2023-03-07 21.47.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2737143/20782922-7c7e-d035-c976-1bea2cb27cc6.png)

詳しくは割愛しますが、ここではチャンネルの設定、アクセス許可周りを設定しています。
チャンネルIDは上記のものを記載します。
![スクリーンショット 2023-03-07 22.27.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2737143/1dc2df81-acb2-7e93-2cf7-6b5b861019ee.png)

この記事では書きませんが、lambdaを呼び出すのに以下のポリシーを設定してます。
![スクリーンショット 2023-03-07 22.33.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2737143/e3501851-980f-c474-3ab5-5821221e5899.png)

必要に応じてSNSなどを設定して登録すれば完了です。
次回はlambdaを呼び出します。
が、その前にC#でlambdaを扱いたいのでそのあたりの説明からです。
パイプについて（Linuxコマンド）

# 背景
最近Linuxでパイプを使う機会が多いため、パイプについて簡単な説明を記しておく。
# パイプとは？
Linuxコマンドを使って標準出力された内容を次のコマンドへ橋渡しするために使われるコマンド。
パイプの正式名称は**パイプライン**で、パイプを使った処理のことを**パイプライン処理**と呼ばれる。
この処理を使うことで柔軟で多様なコマンド処理が可能となる。
# パイプの使い方
基本的な記述は以下の通り。
```
$コマンド① | コマンド②
```
また、パイプは3つ以上のコマンドでも実行可能である。
```
$コマンド① | コマンド② | コマンド③ | コマンド④ | コマンド⑤...
```
# パイプの使用例
`grep`コマンドとは、ファイルから**特定の文字列**が存在するかを調べたいときに利用されるLinuxコマンドである。
```
$ps aux | grep xxx
```
`ps`コマンドは、ざっくり言うとサーバー内で動いているプロセスを表示するコマンドである。
しかし、psコマンドで表示されるプロセスは多いため、調べたいプロセス名を`grep`コマンドで表示することがある！
# まとめ
今回は`grep`コマンドを例に挙げたが、パイプは他のコマンドでも応用可能なためぜひ習得しておきたい。
Nuxt3 / Vue3 – 親コンポーネントで定義したdataを子コンポーネントの props として渡して連動させる ( Compotision API )

どうやるんだろうと思ったがとりあえず以下で動いている
computed とか必要なかったようだ

# 呼び出し側

`pages/example.vue`

```vue
<template>
  <Example :name="name"/>
  Parent: Name :{{ name }}
  <button @click="setName()">Chage Name</button>
</template>

<script lang="ts" setup>

function setName(){
  name.value = "Bob"
}
const name = ref('Alice')

</script>
```

# 呼び出され側

`componens/Example.vue`

```vue
<template>
  <h3>Child: Name : {{ name }}</h3>

</template>

<script lang="ts" setup>

interface Props {
  name: string
}

withDefaults(defineProps<Props>(), {
  name: '',
})

// このように定数を定義しなくても使える
// const props = withDefaults(defineProps<Props>(), {
//   name: '',
// })

</script>

```

# 表示例

親のボタンを押すと
親/子で両方の値が変わるのが分かる

![image](https://user-images.githubusercontent.com/13635059/223432759-cafb4e13-0701-4b67-8b91-f6b385f1b2a4.png)
![image](https://user-images.githubusercontent.com/13635059/223432761-1202c26f-4472-4b53-a137-53a39e8f101f.png)


# NOTE

ただしこの書き方では子コンポーネントで値を変えるということが出来なかった


# 環境

- Nuxt 3.2.2

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ


# Twitter

https://twitter.com/YumaInaura
Androidで超簡単にPIP(ピクチャーインピクチャー)実装してみた

## はじめに
業務でPIP（ピクチャーインピクチャー）を実装しそうな予定があるので予習も兼ねて超簡単に実装してみる。

### こんなやつ

<img width="400" alt="pip_sample.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2644766/c7fe64b4-c49f-298f-a434-a504f9b36f65.gif">

## 早速実装
まずはManifest.xmlに記述。
```xml:Manifest.xml
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:label="@string/app_name"
            android:supportsPictureInPicture="true">
```

適当なFragmentにピクチャーインピクチャーを開始するボタンを設置。

```xml:fragment_home.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.home.HomeFragment">

    <com.google.android.material.button.MaterialButton
        android:id="@+id/start_pip_btn"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:text="@string/start_pip_mode"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
```

Fragmentにクリックリスナーを設置
```Kotlin:HomeFragment.kt
    @RequiresApi(Build.VERSION_CODES.O)
    private fun setClick() {
        binding.startPipBtn.setOnClickListener {
            startPIPMode()
        }
    }
```

クリックされたタイミングでピクチャーインピクチャーを開始
```Kotlin:HomeFragment.kt
    @RequiresApi(Build.VERSION_CODES.O)
    private fun startPIPMode() {
        val builder = PictureInPictureParams.Builder()
        // PIPモード中のサイズを指定
        builder.setAspectRatio(Rational(16, 9))
        this.activity?.enterPictureInPictureMode(builder.build())
    }
```

### 気をつけること
ピクチャーインピクチャーは[APIレベル26(Android8)](https://qiita.com/irgaly/items/bd2ffe3725424690b856 "APIレベル26(Android8)")からしか使用できないみたいです。


## 最後に
思ったより簡単にピクチャーインピクチャーを実装できました。
ただ、アプリ内でピクチャーインピクチャーをやる方法がわからないのでわかる方は教えて頂けると幸いです。

サンプルコードはGitHubに載せてあります。

https://github.com/KenshoHanano/PIPSample

ではまたっ！
[GitHub] プルリクエストテンプレートの作成

チーム開発をやっていると、リポジトリを作る毎にテンプレートを用意することがあるので、備忘録的な形で残します。

# 1.ファイルの作成
`.github/pull_request_template.md`

(個人的に非表示のディレクトリに格納したかったので`.github`に入れてます)
その他「ルートに直接ファイルを置く」「docsディレクトリにファイルを置く」方法があるみたいです。
複数テンプレートを作成する方法は割愛します。
 
# 2.テンプレートの作成
状況によって項目を増やしますが、私は基本以下のように作ってます。
```
# 概要
ざっくり説明

# 詳細
コミット毎に細かく説明

# 動作確認
写真貼ったり、確認用のコマンドを貼る

# TODO
- [ ]aaa
- [ ]bbb
```
# 3.コミットする
これでおしまい

### 参考
GitHub公式アカウント
https://docs.github.com/ja/communities/using-templates-to-encourage-useful-issues-and-pull-requests/creating-a-pull-request-template-for-your-repository
RubyからOpenAI APIをたたいてDALL-E!を呼ぶ


RubyからChatGPTを呼ぶ記事はいくつかあるけど、DALL-Eを呼ぶ記事がなさそうなので書いた。
GTK4を利用している。確認していないけれど、WindowsやmacOSでも動くんじゃなかろうか。

動作には、ruby-openai と、gtk4 が必要。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144608/78e987b8-d411-be58-3b70-ef55e29415aa.png" height="50%" width="50%">


```ruby
require 'gtk4'
require 'openai'
require 'open-uri'

client = OpenAI::Client.new(access_token: ENV['OPENAI_ACCESS_TOKEN'])

app = Gtk::Application.new('org.example.myapp', :flags_none)
app.signal_connect 'activate' do |a|
  window = Gtk::ApplicationWindow.new(a)
  window.title = 'DALL-E!'
  window.set_default_size 600, 600
  vbox = Gtk::Box.new(:vertical)
  window.child = vbox
  hbox = Gtk::Box.new(:horizontal)
  vbox.append(hbox)
  entry = Gtk::Entry.new
  entry.hexpand = true
  hbox.append(entry)
  image = Gtk::Image.new
  image.vexpand = true
  button = Gtk::Button.new(label: 'Go')
  button.signal_connect('clicked') do
    loader = GdkPixbuf::PixbufLoader.new
    response = client.images.generate(
      parameters: { prompt: entry.text, size: '512x512' }
    )
    url = response.dig('data', 0, 'url')
    data = URI.open(url).read
    loader.write(data)
    pixbuf = loader.pixbuf
    loader.close
    image.from_pixbuf = pixbuf
  end
  save_button = Gtk::Button.new(label: 'Save')
  save_button.signal_connect('clicked') do
    image.paintable.save_to_png("output.png")
  end
  hbox.append(button)
  hbox.append(save_button)
  vbox.append(image)
  window.show
end

app.run
```

エラー処理とか一切していない。。。
この記事は以上です。
文言を出力する際""で囲まれないようにする方法

## 実行環境と結論
Windows環境、Pythonのwith open関数を使ったテキストファイル出力について。
簡単な処理ログを出力しようとした際、文言に空白があると""で囲まれ見栄えが悪かったので囲まれない方法を調べた。

~~結論としては「 」をセパレータとしてCSV出力する際、**半角スペース「' '」をノンブレーキングスペース「\uA00」で置換する**だけ。~~
csvモジュールを使わずとも「print(_message, sep=' ', file=f)」で簡潔に実現可能。
（コメントありがとうございます！）

## ソースコードと実行例
print_log関数の引数として渡した文言をログに追記していくという処理。
ファイル名や出力先の設定、関数の呼び出し日時も出力文言に含める処理などは割愛。
~~~sample.py
def print_log(_message):
    _log_file_name = 'MM-dd.log'
    with open(_log_file_name, 'a', newline='', encoding='utf-8') as f:
        print(_message, sep=' ', file=f)
~~~

~~~実行例.py
count_now = 1
count_all = 10000
s = f'{count_now:>6} / {count_all:>6} 件完了'

print_log(s)
~~~
出力結果は以下のとおり。期待どおり文字寄せの空白があっても
「""」で囲まれるようなことはなく出力できた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/446953/d520fe4b-7e51-048f-89ed-0788b991e0e0.png)

以上、備忘のため残す。
MP3のデータから文字起こしをする方法

# はじめに
手元にあるmp3の音声データを文字起こしする方法です。
Wordのディクテーション(音声入力)を使用することもありますが、訳あって音声データのmp3のみが手元にあったので、さてどうしようかなと思ってました。

# 手順
1. WEB版Wordを開く
1. 新規で空白の文章を作成する
1. [ホーム] - [ディクテーション] から [トランスクリプト] を選択する
1. 音声をアップロードからファイルを選択する

※トランスクリプトの選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475457/5cd76342-9891-01ee-84b4-6b2001b5385c.png)

※音声データのアップロード
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475457/77c7d989-a12e-85e1-84cd-3f428ee26cee.png)

# 注意事項
自分の環境では、インストール版のWordでは、「トランスクリプト」機能が出てこなかったです。同じように困ったら、WEB版で試してみて下さい。
あとは、データ量が300MB以内の制限があるので、注意して下さい。今回の場合は、約３時間ぐらいのデータがあったので、まずは音声ファイルを分割して、その後にそれぞれのデータごとに文字起こしを行いました。

# 参考
こちらの記事もとても良くまとまっているので、参考になると思います。

https://www.notta.ai/blog/transcription-feature-word-method
GoでJSON文字列を返すAPIを構築する(Gin)

Go公式のチュートリアルを進める
https://go.dev/doc/tutorial/web-service-gin

すでにGoは導入済みなので手順通りに進めてみます

```bash
$ mkdir web-service-gin
$ cd web-service-gin
$ go mod init example/web-service-gin
go: creating new go.mod: module example/web-service-gin
```

この階層にmain.goを作りチュートリアルをコピペする

```go:main.go
package main

import (
	"net/http"
	"github.com/gin-gonic/gin"
)

// album represents data about a record album.
type album struct {
	ID     string  `json:"id"`
	Title  string  `json:"title"`
	Artist string  `json:"artist"`
	Price  float64 `json:"price"`
}

// albums slice to seed record album data.
var albums = []album{
	{ID: "1", Title: "Blue Train", Artist: "John Coltrane", Price: 56.99},
	{ID: "2", Title: "Jeru", Artist: "Gerry Mulligan", Price: 17.99},
	{ID: "3", Title: "Sarah Vaughan and Clifford Brown", Artist: "Sarah Vaughan", Price: 39.99},
}

func main() {
	router := gin.Default()
	router.GET("/albums", getAlbums)
	router.Run("localhost:8080")
}

// getAlbums responds with the list of all albums as JSON.
func getAlbums(c *gin.Context) {
	c.IndentedJSON(http.StatusOK, albums)
}
```

パッケージの取得

```bash
$ go get .
〜
go: downloading github.com/gin-gonic/gin v1.9.0
〜
```

実行

```bash
$ go run .
[GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.
Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.
[GIN-debug] Listening and serving HTTP on localhost:8080
```

リクエストを送付する

```json
$ curl http://localhost:8080/albums
[
    {
        "id": "1",
        "title": "Blue Train",
        "artist": "John Coltrane",
        "price": 56.99
    },
    {
        "id": "2",
        "title": "Jeru",
        "artist": "Gerry Mulligan",
        "price": 17.99
    },
    {
        "id": "3",
        "title": "Sarah Vaughan and Clifford Brown",
        "artist": "Sarah Vaughan",
        "price": 39.99
    }
]
```

getに関しては問題なく動いたのでpostなどを順次試して行きます。
プロペラの回転数と推力と電流

# ドローンを作りたい
ドローンを作りた～い。自分の作った飛行体が謎に空中にういていてほしぃいい～い。

ということで、ドローンを作るためにプロペラとモータを買いました。
ついでにPROXXONのミニルータ買いました。便利ぃイイイ。

![IMG_20230307_210040423.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/7a270982-5427-5aa6-c88e-db5bb98ffd54.jpeg)

では実際、モーターの回転数・電流・発生する浮力（プロペラ方向へ発生する力）の関係はどれくらいなのでしょうか。


## 実験装置
![IMG_20230307_210817442.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/d242807a-12b9-8e92-a2b5-f19cc6df4cce.jpeg)

単純に、秤（0.01g単位）に写真のようにモーターセットを載せて電流を入れてます。

### 注意点
意外と地面効果ってかなり強いです。プロペラの下に指を置くだけで浮力が3gから3.5gに変化します。本体がプロペラの下の流れを遮ると効率が下がりますね。
逆にプロペラの上に手のひらを当てるのもかなり効果があります。浮力が3gから4gぐらい変わります。コレはつまり、天井付近を飛行すると天井に本体が吸引されるということですね。

## 実験結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/66489824-c40c-daab-70a8-5c54b1e8aa7c.png)

浮力と電流には比例関係がある。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/ef8124f4-0c63-1473-3daf-42988cca683c.png)
回転数と電流には2乗関係がある。


## 考察
500mAで5gほどの浮力。モータ＋プロペラで2gなので、実質発生浮力は3g。4モータ式で12g浮かせられる。
本体＋マイコン＋FET＋ジャイロ＋電源を12gで抑えるのはかなり困難。
リポを乗せるのを諦めたほうがいい。


# 浮力と回転数の理論的説明
流体的に、抗力と速度には次の関係がある。

```math
D= \frac{1}{2} \rho V^2 S C_D
```

https://ja.wikipedia.org/wiki/%E6%8A%97%E5%8A%9B

速度の2乗比例するということだ。
モータのトルクは電流に比例するので


```math
T = KI\\
\therefore KI = \frac{1}{2} \rho S C_D  \omega ^2\\
\therefore I = a \omega^2 
```

電流は角速度の2乗に比例すると証明できる。

浮力（揚力）も速度2乗に比例する

```math
L = \frac{1}{2} \rho V^2 S C_L\\
\therefore L = b \omega^2\\
\therefore L = b I/a\\
\therefore L = (b/a) I\\
```
よって、浮力は電流に比例すると言える。

# プロペラの効率について
プロペラの効率はプロペラのサイズが大きいほど高くなる。
ギヤードモータなども売っている。
同じモーター、同じ電流でも50gも推力が出るらしい。
届き次第確認してみる。
【Tips】「ファイルを開く」ダイアログでファイルのフルパスを取得したい【OpenFileDialog】

# 1.概要
`System.Windows.Forms.OpenFileDialog`を使用し、ファイル選択ダイアログから選択したファイルのフルパス情報を取得する方法を記します。

環境
Visual Studio Community 2022
プロジェクトテンプレート:Windows フォーム アプリケーション(.Net Framework)
言語:C#

# 2.フォーム
![2023-03-07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633534/35ab57f1-8e17-b30d-7530-f2e28131c770.png)
サンプルとして上記のようにフォームを構成したとします。
テキストボックスのnameを`textBox1`、
ファイル選択ボタンのnameを`button1`と仮定します。

# 3.コード
先にコードを記します。その後詳細を説明します。
```Form.cs
/// <summary>
/// ファイル選択ボタンクリック時
/// </summary>
private void button1_Click(object sender, EventArgs e)
{
    path = SelectFile();

    if(path != string.Empty)
    {
        textBox1.Text = path;
    }
}

/// <summary>
/// ファイル選択
/// </summary>
/// <returns>string:選択されたファイルのフルパス キャンセル時はEmpty</returns>
private string SelectFile()
{
    string ret = string.Empty;
    
    //OpenFileDialog
    using(OpenFileDialog openFileDialog = new OpenFileDialog())
    {
        openFileDialog.Title = "ファイル選択ダイアログ";
        openFileDialog.Filter = "テキストファイル(*.txt)|*.txt|すべてのファイル(*.*)|*.*";
        openFileDialog.InitialDirectory = @"c:\Study\";
    
        //ファイル選択ダイアログを開く
        if(openFileDialog.ShowDialog() == DialogResult.OK)
        {
            ret = openFileDialog.FileName;
        }
    }
    return ret;
}
```
`button1`をクリックすると`button1_Click()`メソッドが呼び出され、`SelectFile()`を呼び出します。
`SelectFile()`では、`OpenFileDialog`クラスのインスタンスを生成し、いくつかのプロパティ設定を経て`ShowDialog()`を実行することでファイル選択ダイアログを呼び出しています。
![ファイルを開く.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633534/f3696972-4b57-eefc-dc02-891b506aa103.png)
`ShowDialog()`が閉じた際、返り値は`DialogResult`形式で返却されます。
返り値が`DialogResult.OK`だった場合、`FileName`プロパティに選択されたファイルのフルパスが格納されているため、メソッド自体の返り値としてその情報を返却しています。
返却されたフルパス情報を、textBox1の表示プロパティである`textBox.Text`に代入し、表示に反映しています。
![2023-03-07 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633534/75f85233-e4c4-3e05-b767-e07bd7a0a7cf.png)

# 4.OpenFileDialogのプロパティ
今回使用しているプロパティの内容を記します。
<dl>
<dt>Title</dt>
<dd>ファイル選択ダイアログ左上のタイトルに表示する文字列です。</dd>
<dt>Filter</dt>
<dd>拡張子によるフィルタを指定します。|で区切られた2つを1セットとして、[表示]|[フィルタ内容]と記述します。更にそのフィルタを複数設定する場合は、1セット毎に更に|を挟みます。ちょっと見づらい。</dd>
<dt>InitialDirectory</dt>
<dd>ダイアログを開いた時に最初に開かれているディレクトリをフルパスで指定します。記述がある場合、開くたびにこのディレクトリから選択を開始します。このプロパティを設定しない場合は、開き直すと以前開いていたディレクトリから開始するため、設定しないほうがいい場合もあります。</dd>
</dl>

実際はこのフルパス情報からStreamReaderなどを用いてファイルを扱うことになります。
OpenFileDialogは、Formを使ったファイル操作の入り口の入り口と言ったところでしょうか。
実際のファイル操作はまたの機会に。
Gitでローカルでの変更をすべて破棄したい。

# はじめに
SIer2年目の社会人です。

# 環境
Windows 11
Git 2.39.1.windows.1

# 問題
リモートブランチからPullしたかったのですが、ローカル変更が邪魔でマージできませんでした。
エラーメッセージとしては下記のエラーメッセージが出ていました。

```エラーメッセージ
error: The following untracked working tree files would be overwritten by merge:
```

# 解決

下記のコマンドを実行して、うまくいきました。

```コマンド
git clean -d -f .
```

git checkout .やgit clean -fではうまく消せませんでした。
もうちょっと調べて精進したいと思います。

# 参考
https://chico-shikaku.com/2022/01/git-error-the-following-untracked/
https://prograshi.com/general/git/how-to-undo-modifications/
boolvalの値とbool値比較評価備忘メモ

# 前提
```
% php --version
PHP 8.0.18 (cli) (built: Apr 15 2022 09:41:02) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.18, Copyright (c) Zend Technologies
    with Xdebug v3.1.5, Copyright (c) 2002-2022, by Derick Rethans
    with Zend OPcache v8.0.18, Copyright (c), by Zend Technologies
```

# boolvalをくぐらせてのecho結果
文字列の'false'をboolvalにくぐらせるとtrue判定となる。nullはfalse
```
echo '0:' . boolval(0)  . PHP_EOL;
echo '1:' . boolval(1) . PHP_EOL;
echo 'true:' . boolval('true') . PHP_EOL;
echo 'false:' . boolval('false') . PHP_EOL;
echo 'true(bool):' . boolval(true) . PHP_EOL;
echo 'false(bool):' . boolval(false) . PHP_EOL;
echo 'mojiretsu:' . boolval('mojiretsu:') . PHP_EOL;
echo 'null:' . boolval(null) . PHP_EOL;
```
↓
```
0:
1:1
true:1
false:1
true(bool):1
false(bool):
mojiretsu:1
null:
```

# 評価の動作
## vs文字列

bool文字列
```
echo false == 'false'; // 一致しない
echo false === 'false'; // 一致しない
```

数値文字列 ※==と===で動作が変わるのでややこしい😖
```
echo false == '0';　// 一致する
echo false === '0'; // 一致しない
```

## vs数値
==と===で動作が変わるのでややこしい😖
```
echo false == 0; // 一致する
echo false === 0; // 一致しない
```

boolvalをくぐらせた場合はどちらも一致
```
echo false == boolval(0); // 一致する
echo false === boolval(0); // 一致する
```