OmniAICreator/Qiita-1.07M huggingface dataset:
KISS の原則とは？

# 目次

1. [はじめに](#はじめに)
2. [KISS の原則](#kiss-の原則)
3. [感想](#感想)
4. [参考URL](#参考url)

## はじめに

実装していく中で、フロントエンドとバックエンドのどちらにコードを書くべきか迷うことがありました。
そこで学んだことに、KISS の原則というものがあることを知りました。
初めて聞いたので、調べてみました。

## KISS の原則

KISS の原則 (英: KISS principle) とは、
**「Keep it simple, stupid.」 （シンプルにしておけ！この間抜け）**
または
**「Keep it short and simple」 （簡潔に単純にしておけ）**
という内容の、1960年代の米国海軍において言われた、経験的な原理・原則の略語。
その意味するところは、
**設計の単純性（簡潔性）は成功への鍵であり、不必要な複雑性は避けるべき**
ということ。

## まとめ

- コードを如何に「単純に」「簡潔に」保つかという視点を最優先に考えることが重要
- 「読みやすく・理解しやすく・修正が容易」なコードを書くことが重要
- 今回の問題（フロントエンドとバックエンドのどちらにコードを書くべきか）は、下記2点の理由でバックエンド側に実装（他にも色々な観点のもとで考えてはいますのでご了承下さい）
  - フロントエンド側に実装すると、フロントエンド側のコードが複雑になる
    - 既にネストが多く複雑であるため、これ以上複雑化したくない
  - 初見では分かりずらい処理になってしまう。保守性が担保できない
  - 役割としても、バックエンドで実装して問題ない
  - パフォーマンス的にも、バックエンドで実装して問題ない

## 参考URL

https://ja.wikipedia.org/wiki/KISS%E3%81%AE%E5%8E%9F%E5%89%87

https://qiita.com/pinebookplus/items/4c1af10095780f9d1fd3

https://tracks.run/agilehr/column2017052501/
[Android]Jetpack ComposeのComposableのModifierを条件によって切り替えたい

例えば
```kotlin
val modifier = 
if (isMax) {
         Modifier.fillMaxWidth()
                 .fillMaxHeight()
} else {
         Modifier.fillMaxWidth()
                 .wrapContentHeight()
}

AnyComposable(modifier = modifier)
```
というようにheightの部分だけ条件によって変更したい時
以下のコードだと.applyの中身はmodifierとして適用されない
```kotlin
AnyComposable(modifier = 
         Modifier.fillMaxWidth()
                 .apply {
                     if (isMax) {
                          fillMaxHeight()
                     } else {
                          wrapContentHeight()
                     }
                 }
)
```
`then`を使う
以下が正解

```kotlin
AnyComposable(modifier = 
         Modifier.fillMaxWidth()
                 .then (
                     if (isMax) {
                          Modifier.fillMaxHeight()
                     } else {
                          Modofier.wrapContentHeight()
                     }
                 )
)
```
testディレクトリに配置したprotoファイルがコンパイルされない

ユニットテスト用にテスト用のprotoファイルを用意してJavaファイルを自動生成したかったのですが、いくつかハマリポイントがあったのでここにまとめておきます。

# テスト用protoファイルの配置場所
テスト用のprotoファイルは以下に配置します。
以下に配置すればbuild.gradleでsourceSetsなどを記述しなくても自動で読み取ってくれるようになります。
```
src/test/proto
```
# テスト用protoからJavaコードの生成
src/main/protoに配置されたprotoファイルの場合は./gradlew buildや./gradlew generateProtoで自動生成することができますが、test配下のprotoからはこれらタスクでは生成できません。
代わりに
```
./gradlew generateTestProto
```
を実行することでtestディレクトリのprotoから自動生成することができます。
生成されたJavaファイルは以下のように/build/generated/source/proto/test配下に出力されます。
![スクリーンショット 2023-01-31 19.17.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287959/222d6632-8770-446c-c728-475074b82303.png)
C#（.Net6）でクライアント証明書を作成してみる

C#でクライアント証明書を作成するサンプルを探しても見つからなかったので、備忘録として記事にしました。

```
using System.Text;
using System.Security.Cryptography.X509Certificates;
            
// ルート証明書ファイルの読み込み
var rootCertificate = X509Certificate2.CreateFromPemFile("ca.crt", "ca.key");

// 2048bit長でキーペア（公開鍵・秘密鍵）を生成
using (System.Security.Cryptography.RSACryptoServiceProvider rsa =
    new System.Security.Cryptography.RSACryptoServiceProvider(2048))
{
    // 公開鍵を取得
    byte[] bytesPublicKey = rsa.ExportRSAPublicKey();
    // 秘密鍵を取得
    byte[] bytesPrivateKey = rsa.ExportRSAPrivateKey();

    // クライアント証明書に使用するサブジェクトを生成
    X500DistinguishedName subjectName = new X500DistinguishedName("C=JP\nST=XXX\nL=YYY\nO=ZZZ\nCN=hogehoge", X500DistinguishedNameFlags.UseNewLines);

    // CSR（Certificate Signing Request）を生成
    var certificateRequest = new CertificateRequest
        (
            subjectName,
            rsa,
            System.Security.Cryptography.HashAlgorithmName.SHA256,
            // System.Security.Cryptography.RSASignaturePadding.Pss
            System.Security.Cryptography.RSASignaturePadding.Pkcs1
        );

    // CSRからルート証明書の秘密鍵で署名されたクライアント証明書を作成（この証明書に秘密鍵は含まれていない）
    var serialNumber = new byte[] { 0x01 }; // クライアント証明書に使用するシリアル番号を指定する
    X509Certificate2 clientCertificateNotHasPrivateKey = certificateRequest.Create
        (
            rootCertificate,
            DateTimeOffset.Now.AddDays(-1), // この証明書が有効と見なされる最も古い日時。
            DateTimeOffset.Now.AddDays(1),  // この証明書が有効と見なされなくなった日時。
            serialNumber                    // クライアント証明書に使用するシリアル番号。
        );

    // 証明書をPem（Base64）形式の文字列で取得
    StringBuilder clientCertificateNotHasPrivateKeyPem = new StringBuilder();
    clientCertificateNotHasPrivateKeyPem.AppendLine("-----BEGIN CERTIFICATE-----");
    clientCertificateNotHasPrivateKeyPem.AppendLine(Convert.ToBase64String(clientCertificateNotHasPrivateKey.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks));
    clientCertificateNotHasPrivateKeyPem.AppendLine("-----END CERTIFICATE-----");

    // 秘密鍵をPem（Base64）形式の文字列で取得
    StringBuilder privateKeyPem = new StringBuilder();
    privateKeyPem.AppendLine("-----BEGIN RSA PRIVATE KEY-----");
    privateKeyPem.AppendLine(Convert.ToBase64String(bytesPrivateKey, Base64FormattingOptions.InsertLineBreaks));
    privateKeyPem.AppendLine("-----END RSA PRIVATE KEY-----");

    // Pem形式の証明書と秘密鍵からPfxファイルを作成
    var clientCertificate = X509Certificate2.CreateFromPem(clientCertificateNotHasPrivateKeyPem.ToString().ToCharArray(), privateKeyPem.ToString().ToCharArray());
    var clientCertificatePfx = clientCertificate.Export(X509ContentType.Pfx, "password");
    File.WriteAllBytes("clientCertificate.pfx", clientCertificatePfx);
}
```
Python実践してみての感想

# 概要

5年間ぐらいJavaでお仕事をしていて、現在はサーバーサイド言語としてPythonを使ってお仕事をしています。
まだ3ヶ月間なので全然慣れていませんが、そんなときにどういうことを思っていたのかということを備忘録として残しておきます。

## self, clsを書く違和感

インスタンスメソッド, クラスメソッドを定義する際に、必ず第一引数に`self`, `cls`（名前はなんでもいいが慣例としてself, clsを使用）を書く必要があるという仕様について。
今まで書いていなかったのでやっぱり違和感ありますね～。

自分自身のインスタンスを表すという意味で、これはJavaで言うなら`this`にあたると理解しています。

言語仕様として絶対に`self`, `cls`を書かなきゃいけないのであるなら、最初から`this`みたいに用意しておけばいいのに...って感覚ですね。
[The Zen of Python](https://peps.python.org/pep-0020/#the-zen-of-python)の`Explicit is better than implicit.`の思想的に、自身を表す単語も明示的に書きましょう！っていう意図で言語設計されているんですかね:thinking:

## `__init__.py`?

各パッケージにある`__init__.py`ってなんだ？ってなりました。しかも基本的に中身空っぽだし。
調べてみてパッケージ化に必要なんだなぁとざっくり理解しました。
でも中身空っぽでもいいなら最初からなくても良くね？って思いました。
~~それに対する答えとして、[Python3.3 以降なら空のものは不要ということ](https://docs.python.org/ja/dev/whatsnew/3.3.html#pep-420-implicit-namespace-packages)が書かれていました。~~
~~古いバージョンのPythonでの開発の際は気をつける必要ありと、心に留めておきます。~~

[\_\_init__.pyを省略してはいけない](https://qiita.com/methane/items/ed1e5b74747f3ffe9324)
↑先輩社員から教えてもらいました！
[名前空間パッケージ](https://docs.python.org/ja/3.9/reference/import.html#namespace-packages)と[通常のパッケージ](https://docs.python.org/ja/3.9/reference/import.html#regular-packages)は別物ということ。
通常のパッケージをディレクトリとして使う場合、目印として`__init__.py`は必要だということを知りました。

> \_\_init__.py を置かなくても良いケースは複数の異なるパッケージとして配布しているものを一つの名前空間に紐付ける形で利用したい場合に使う機能


## isの勘違い

`a is b`といったようにPythonでは`is`で比較できるということで、「より英文っぽくなってかっこいい！」と思いましたし、可読性も良いので基本はこの書き方でいいのかと思って書いていて、見事に落とし穴にハマりました。

あるとき`is`を使った比較でTrueになると想定していたのにFalseが返り「？？？」となる事態が発生してプチハマり。
[python is] で検索するとすぐにisと==の違いといった内容の記事がヒットしました。

`is`は同一性を比較していて、具体的にはオブジェクトが持つidを比較検証しているということでした。
一方で`==`は値のみを比較検証しているということ。
`a is b`は`aのid == bのid`ということだったんですね:bulb:

初心者がやりがちなミスでした。

## pass文、意外に使う

何も実行しない`pass文`。
こんなの使うタイミング滅多にないだろって思っていましたが、意外に書いちゃいますね。

とりあえずクラスとかメソッドとかを定義して中身どうするかを考える際に、エディタの静的コードチェックツールで怒られているのがなんとなく気になっちゃうので、一旦pass文を書くみたいな感じで使いがちです。
すぐ消すんですけどね。

## アクセス修飾子ほしい

アクセス制限できたほうが大規模開発のときにより安全だからいいのになぁと思っています。
いくらアンダースコアがついているものはprivateだと言っても口約束ですからね。
ついつい例外的にここではOKとかにやっちゃいそう。

書き方についても違和感があります。
アンダースコアでプライベートかどうかを示すっていうのもやっぱり慣れません。
明示的にする思想っていうなら`class`とか`def`とかの前に`private`とか`public`って書けたほうが明示的じゃね？って思っちゃいますね。
まあ注釈的な意味しか持たないし、他言語でもアンダースコアが使われているからそれでいいのか...

## 型は注釈にとどまるということに慣れない

Pythonは動的型付け言語ですが、型注釈の機能があり型を指定できます。
ただし注釈なのでコメントみたいなもの。
この感覚に最初は慣れませんでした。

特に`Optional`ですね。
最初は`Optional`なら`ifPresent`みたいなのがあって、かっこよく書けるだろって思ったのですが、実際はNoneかもしれないってことだけしか表現しないってところにちょっぴりがっかりしました:sweat:
注釈なのでそりゃ当たり前だろって感じですよね。
結局if文でNoneチェックしないといけないって感じなんですね。

ただこれは`typing`の`Optional`の話であって、それ以外でJavaのOptionalに似たモジュールはありました。
https://pypi.org/project/optional.py/
https://pypi.org/project/pyOptional/

## 型に自身のクラスを指定できない？

Factoryメソッドの戻り値の型注釈として自身のクラスを指定しようとしたら、未定義だと怒られました。
なにこれ？と思って調べてみたらそういう仕様だったということを知りました。
Python 3.7以降であれば`from __future__ import annotations`を書くことによって自身の型を指定でき、それより前のバージョンであるなら文字列でクラス名を記述することで指定できるとのこと。
Python 3.11からは`typing`で`Self`が使用できるのでそれも使える。
どっちにしろimportの必要なく自身のクラスを指定できたほうが直感的でわかりやすい気がしました。
https://stackoverflow.com/questions/33533148/how-do-i-type-hint-a-method-with-the-type-of-the-enclosing-class

# いったんこのぐらい

現時点までのお仕事で思ったことを書き連ねました。
今後もバリバリPython書いていって、とりあえずPythonに慣れ親しんでいくことにします。
この備忘録を1年後に読んでみて、自分がどんなことを思うのかもちょっと楽しみです。
Google Apps ScriptとGitHubを連携してpullするとエラーが出る [github assistant]  undefined

# GAS - GitHub連携でpullするとエラーが出た

スプレッドシートにスクリプトを入れる場合などApps Scriptを使うが、
そのスクリプトをGitHubで管理したくなった。

Google Chromeに拡張機能「Google Apps Script GitHub アシスタント」を入れるとGitHubと連携できる。

https://chrome.google.com/webstore/detail/google-apps-script-github/lfjcgcmkmjjlieihflfhjopckgpelofo/related

GitHubでAccess Tokenを発行して拡張機能に設定することでソースコードをpushできるようになった。

![名称未設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224453/0734a73a-f5b4-c77b-317a-2a53d335323a.png)

しかし、GitHub側でソースコード変更した内容をpullするとエラーが発生した。

> [github assistant]  undefined

![215725338-9f44e0b5-4f7e-4dcd-b2af-8b1184469815.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224453/8b3a3b1e-c839-90ae-4b72-795096a1981f.png)

# 解決方法

Google Apps Scriptの設定画面で「Google Apps Script API」をオンにすると解決できた。

https://script.google.com/u/0/home/usersettings

![215725477-a0509c99-f1e5-493e-9943-e775eaf43206.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224453/0689b5a2-2a3c-8cc3-21c9-922fc7b6a296.png)

![215725522-967bb11e-17ce-43a9-8f15-20c17721f0f1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224453/651a49df-32f9-d75f-b389-e6f497eb808b.png)

![215725678-32878918-758c-485a-8972-00c23079baab.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224453/b31c5473-fb26-ecef-d5c7-e7b664e05dc1.png)
DockerでLaravelが重すぎたのでvendorとstorageをマウントしないことで解決した気がする

## 経緯
今までリモート勤務だったけど来月から出社する用事がちらほらできそう。
自宅のデスクトップで開発してたけど会社に持っていけるのはMacしかない。
いい機会なのでXAMPP/MAMP開発とはおさらばしてDockerを使おう。

Nuxt + Laravel + Mysqlの環境構築が諸々苦戦しながら完成
さあ動いてくれメンス！

ログイン　XAMPP数秒　→ Docker1分
こりゃあかんｗ

## 原因
Qiitaにも100万記事くらい投稿されているけど、Laravelのアプリフォルダ全部Dockerにマウントさせると
vendorとかstorageみたいな子達が激重でこういうことになるらしい。

こちらの記事を参考にさせていただきました。
[Docker for MacのLaravel アプリケーションのが遅い？それ、ファイルをいっぱいマウントしてるからかもです。](https://qiita.com/tyamahori/items/f627f85c7316e096a061)
こちらの手順で全て解決しました。

何をやっているのかとか行き詰ったところがあったので備忘録として

## 作業の流れ
とりあえずdocker-compose.ymlを直してみる

```docker-compose.yml
version: "3.7"

services:
  frontend:

    #省略

  backend:
    build: ./service
    tty: true
    volumes:
        - ./service:/var/www/laravel
    ports:
      - '8000:8000'
    env_file:
      - ./.env
  
    #省略
```
これに参考記事通り追加
```docker-compose.yml
version: "3.7"

services:
  frontend:

    #省略

  backend:
    build: ./service
    tty: true
    volumes:
        - ./service:/var/www/laravel
        - vendor-volume:/var/www/laravel/vendor 
        - storage-volume:/var/www/laravel/storage 
    ports:
      - '8000:8000'
    env_file:
      - ./.env
  
    #省略

volumes: 
  storage-volume:
    driver: local
  vendor-volume:
    driver: local
```

なるほどつまり、マウントしたくないディレクトリに対して、
一番下のカラvolumeで上書きしてるみたいな感じかな

で起動
```
docker-compose up -d
```
でエラー
```
Warning: require(/var/www/laravel/vendor/autoload.php):
 Failed to open stream: No such file or directory in /var/www/laravel/artisan on line 18
```

vendorがいないらしい。そりゃそうだ。
記事の下の方を読むと注意点としてしっかりこの件についても記載されている。ちゃんと読もうねぼく。

ホストにあるvendorとstorageフォルダをコンテナにコピーしちゃえば良いってことだ
コンテナのIDを取ってこよう
```
docker ps -a
>CONTAINER ID   IMAGE                 COMMAND                  CREATED          STATUS
PORTS                                NAMES
0f42d9ca809e   backend            "docker-php-entrypoi…"   25 minutes ago   Up 24 minutes
0.0.0.0:8000->8000/tcp, 9000/tcp     backend-1
```

このIDを使ってcpコマンド
```
# laravelフォルダに移動
cd service

# コピー
docker cp .\vendor\ 0f42d9ca809e:/var/www/laravel
docker cp .\storage\ 0f42d9ca809e:/var/www/laravel
```

再度docker-compose up -dで起動
実行速度は…計測してないけどめちゃくちゃ早くなった、解決！

これwindowsの話だけど、Macが早くならないと何も解決していない。
多分同じ方法で早くなってくれるだろうと信じて。。
Pythonチートシート - Dict型の使い方一覧

## Pythonのディクショナリーについて¶
dict型のデータは、一意のキーと値のペアを使って管理される型です。 
自然言語処理を行う際や、言語を翻訳したいときに役立ちます。 

言語によってはディクショナリーはハッシュ・連想配列と呼ばれます。 dict型のデータ構造は、ハッシュ表という数値型のテーブルをキー・値と対応させるという 内部構造となっています。そのためdict型のデータはハッシュアブルな型を用いなければならりません。 

Pythonではint, str, bytes, tuple, frozenset等がハッシュアブルな型となっていて、通常、dict型のキーはintかstr型とします。

### ディクショナリーの内容を参照する

```python
d = {"apple":"りんご", "orange":"みかん", "melon":"メロン"}

d["apple"] = "アップル"
d["strawberry"] = "いちご"

#setdefaultメソッドはキーが存在しない場合のみ値を設定するのに用いる
d.setdefault("apple","Good!!")
d.setdefault("watermelon","Good!!")

print(d)
```
```python
{'apple': 'アップル', 'orange': 'みかん', 'melon': 'メロン', 'strawberry': 'いちご', 'watermelon': 'Good!!'}
```
### ディクショナリーから値を取得する(get, pop, popitem)
getは値を取得、popは値を取得して削除（取り出し）する
popitem()は値をLIFOで取り出す（※Python3.7以降のみ）
getする際にはKeyErrorがおこらないよう、規定値（"×"）を指定する
```python
print(d.get("apple", "×"))
print(d.get("pear", "×"))
print(d.pop("melon", "×"))
print(d.popitem())
```
```python
りんご
×
メロン
('orange', 'みかん')
```
### ディクショナリーのキーを判定(in)
特定のキーが含まれるかを判定したい時は、in演算子を使う
```python
d = {"apple":"りんご", "orange":"みかん", "melon":"メロン"}
print("orange" in d)
print("pear" in d)
```
```python
True
False
```

### ディクショナリーのキーを削除(del, clear)
delで特定キーの削除、clearで全てのキーの削除を行う
```python
d = {"apple":"りんご", "orange":"みかん", "melon":"メロン"}

del d["orange"]
print(d)

d.clear()
print(d)
```
```python
{'apple': 'りんご', 'melon': 'メロン'}
{}
```
### ディクショナリーの内容を列挙する(for...in...)
items, keys, valuesの戻り値は列挙可能な型となっている

```python
d = {"Apple":"リンゴ","Orange":"ミカン","Melon":"メロン"}

#項目を列挙
for item in d.items():
    print(item)
#キーと値を抽出して列挙
for key, value in d.items():
    print(key, " : ", value)

#キーを列挙
for key in d.keys():
    print(key)
#値を列挙
for value in d.values():
    print(value)
```
```python
('Apple', 'リンゴ')
('Orange', 'ミカン')
('Melon', 'メロン')
Apple  :  リンゴ
Orange  :  ミカン
Melon  :  メロン
Apple
Orange
Melon
リンゴ
ミカン
メロン
```
### ディクショナリーのキーを比較する(&, |)
&, |等の演算子を使えば異なる辞書のkeysの積集合・和集合を求めることができる

```python
d1 = {"Apple":"リンゴ","Orange":"ミカン","Melon":"メロン"}
d2 = {"Grape":"ブドウ","Orange":"ミカン","Pear":"なし","Apple":"リンゴ"}

print(d1.keys() & d2.keys())
```
```python
{'Orange', 'Apple'}
```

### ディクショナリーの初期化判定をする(defaultdict)
collectionsモジュール、defaultdictを使うことで初期値を管理する

```python
import collections

#リストに何個同じキーが含まれているかを判定し、キーと対応する値をdict型に格納する
data = ["01","02","02","03","03"]
result = collections.defaultdict(int)

for key in data:
    result[key] += 1

print(result)
```
```python
defaultdict(<class 'int'>, {'01': 1, '02': 2, '03': 2})
```
### ディクショナリーの内包表記(for...in...)
リスト・セットの内包表記と同様、ディクショナリーも内包表記にすることができる。他のディクショナリー型を別のディクショナリーにコピーする、等の用途で使える。リスト型やセット型の内容をディクショナリー型にコピーする事もできる

```python
d = {"Apple":"リンゴ","Orange":"ミカン","Melon":"メロン"}
result = {value: key for key, value in d.items()}
print(result)
```
```python
'リンゴ': 'Apple', 'ミカン': 'Orange', 'メロン': 'Melon'}1
```

次回はtuple型の使い方をまとめてチートシートを作ろうと思います。この調子で頑張りますね。
プリザンターでボタンを追加し、データを別Windowで表示する

 # はじめに
今回は鬼門でした(基本的に鬼門ばかりですが・・・)。ボタンを押したら新規でWidowを立ち上げ、あらかじめ指定した項目のテキストを表示するというもの。その画面を印刷したいというものでした。

 # ソースコード
```javascript

//編集画面を開いたときに実行するメソッド
$p.events.on_editor_load = function () {
    //数値Kの隣に「台紙」ボタンを設置し、ボタンクリック後multiTascメソッドが呼び出される
    $('#' + $p.getField('NumK')[0].id).after('<button type="button" style="float: left;" onclick="multiTasc()">台紙</button>');
};
//「台紙」ボタンクリック後の処理
function multiTasc () {
    //クラスAを指定
    let elementClassA = document.getElementById('Issues_ClassA_ms');
    //クラスAの値を取得
    var spanClassA = elementClassA.textContent;
    //クラスBを指定
    let elementClassB = document.getElementById('Issues_ClassB_ms');
    //クラスBの値を取得
    var spanClassB = elementClassB.textContent;
    
    //新規ウィンドウを立ち上げる
    subWin = window.open("","_blank",'left = 10');
    //「資格：」を表示
    subWin.document.write("資格：");
    //クラスBの値を出力
    subWin.document.write(spanClassB);
    //「更新者：」を表示
    subWin.document.write("更新者：");
    //クラスAの値を出力
    subWin.document.write(spanClassA);
    //ウィンドウを閉じる
    subWin.document.close();
};

```

 # おわりに
ソースコードを見てみるとわかりますが、ソース自体はシンプルです。特に変に入り組んだプログラムでもないため、あっさりしている印象です。今回のコーディングで苦労したところは値の取得でした。先輩にセレクタの調べ方を教わったため、そこからの作業ははかどったのですが、それまでの道のりが長かったです。セレクタを指定して値を取得したと思い、画面上に表示しようと試みるも値は取得できず・・・ローカルのHTMLを開こうとしましたが、そもそもローカルのHTMLをブラウザ上から操作できないとのこと・・・try&errorを繰り返し何とか値を表示したかと思えば、お客様の環境では表示されず・・・長い道のりでしたが、少しコツをつかんだように思えます。今後の業務にこの知識や経験を活かしたいです。
GPU がなくても動く Whisper.cpp を試した

2022年は Stable Diffusion や ChatGPT などの AI 技術が話題になりましたが、個人的には 文字起こし AI である Whisper に注目していました。

https://openai.com/blog/whisper/

日本語にも高精度で対応しており、環境されあれば使用も簡単。個人的用途で動画の文字起こしをすることはあるのですが、YouTube の自動字幕や既存の[CLOVA Note](https://clovanote.line.me/)などと比べても精度が高く、実用性は十分にあると考えています。

ただ、個人的な手持ちの環境（ThinkPad X230）は[魔改造](https://osmaniax.1banzaka.com/parts/thinkpad-x230%E3%81%ABegpu%E3%82%92%E4%BA%8C%E5%9F%BA%E8%BF%BD%E5%8A%A0%E3%81%97%E3%81%A6gpu%E3%83%9E%E3%82%A4%E3%83%8B%E3%83%B3%E3%82%B0%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B/3756)でもしない限り些か非力。Google Colabなどの別環境を借りて使用していました。

そんな時、GPU が要らずで Whisper が動作する「Whisper.cpp」があることを知り、試してみました。

https://github.com/ggerganov/whisper.cpp

# 導入

基本的には [README](https://github.com/ggerganov/whisper.cpp#quick-start) に従えば事足ります。例では `base.en` のように言語が指定されていますが、 `*.ja` ファイルはなかったので `tiny`/`base`/`small`/`medium`/`large-v1`/`large` から選びました。個人的には `medium` 以上であれば手直しする頻度が減るのでおすすめです。

# 気になった点

本家 Whisper は MP3 などの音声ファイルに対応していましたが、Whisper.cpp は WAV ファイル（16kHz）にしか対応していないようです。ffmpeg などで変換する必要があります。

また、本家 Whisper はデフォルトで VTT ファイル等が出力されましたが、 Whisper.cpp はオプションで指定する必要がありそうです。

文字起こしの結果は本家同等のものでした。ただマシンスペックのせいだとは思いますが、Colab で試した時よりも長く時間がかかりました。長い音声ファイルを変換するより、15分程度に小分けにした方が精度が上がる（句読点など）ようですが、これは本家でも同じだと思われます。

この Whisper.cpp を知った際は、うちの[初代ラズパイB](https://qiita.com/aRyoKuroda/items/f9fcbd41b2c91d96c040)でも動作するかなと期待したのですが、それなりに[メモリは食う](https://github.com/ggerganov/whisper.cpp#memory-usage)ようなので断念。

ただ、GPU がない環境でも動くことが確認できたので、これからも色々試してみたいと思います。
GAME言語とC言語で、エラトステネスの篩により素数を求める


エラトステネスのふるいで素数を求めるCのプログラムとGAME言語スクリプトです。
アルゴリズムは、「［改訂新版］C言語による標準アルゴリズム事典」奥村晴彦著によります。

# GAME言語

```sieve.gm
#!/usr/bin/gamelinux
1*** sieve.gm エラトステネスの篩により素数を求めるプログラム
2*** アルゴリズムは、「C言語による標準アルゴリズム事典」奥村晴彦著によります。
6*** 
10  "Primes up to " M=? N=(M-3)/2
20  F=0
100  C=1
110  "2 "
120  J=0,N F:J)=1 @=J+1
150  J=0,N
160     ;=#F:J) #=200
170         P=J*2+3
175         ?=P " "
180         ;=J+P<=N K=J+P,N F:K)=0 @=K+P
190         C=C+1
200  @=J+1
210 / ?=C " PRIMES"/
220 #=-1

```

# C言語バージョン

```sieve.c
#include  <stdio.h>
#include  <stdlib.h>

int primes(int n) {
    char f[n];
    int c=1;
    printf("2 ");
    for (int j=0;j<=n;j++) f[j]=1;
    for (int j=0;j<=n;j++)
       if (f[j]) {
           int p=j*2+3;
           printf("%d ",p);
           for (int k=j+p;k<=n;k+=p) f[k]=0;
           c++;
           }
    return(c);
}

int main(int argc,char *argv[]) {
    int m=atoi(argv[1]),c;
    c = primes((m-3)/2);
    printf("\n%d Primes\n",c);
}
```
【オブジェクト指向設計】デメテルの法則って何ですか？

## はじめに

本記事は、プログラミング経験の浅い筆者がつまずき、理解に時間がかかったオブジェクト指向の考え方である「デメテルの法則」について解説したものです。

わかりにくい点、誤り等があれば教えていただけますと幸いです。

## ダメなんですか！？

ToDoリストを作りたい筆者。
わたし「ToDoCollectionにToDoCollectionItemを追加する処理を書きたいな」

```c#

// ToDoを集約するクラス
public ToDoCollection 
{
    public IList<ToDoCollectionItem> ToDoList{get;set;}
    ...

    // アイテムを追加
    public void AddToDo (ToDoCollectionItem item)
    {
        ...
    }
    ...
}
```
わたし「あれ、ToDoCollectionクラスにAddメソッドあるけど、よく見たらプロパティでToDoListが公開されてるじゃん。IList型ならAddメソッドあるよね……」
わたし「**じゃあ、ToDoList.Add()でよくない？**」

こうして筆者はToDoList.Add()で処理を書き、レビューで指摘をもらってしまいました。

## どうしてダメなのか

やりたいことは「ToDoCollection」への要素の追加です。
IList型のAddメソッドでも、ToDoCollectionクラスのAddToDoメソッドのどちらでも、実現できるように思えるでしょう。

しかし、ToDoCollectionに、以下のようなルールがあった場合はどうでしょうか。

**「ToDoCollectionの最大の要素数は10個とする」**

実は、ToDoCollectionクラスのAddToDoメソッドの中には、以下のように、ToDoCollectionが10個を超えないようにする処理が書かれていました。

```c#

// ToDoを集約するクラス
public ToDoCollection 
{
    public IList<ToDoCollectionItem> ToDoList{get;set;}
    ...

    // アイテムを追加
    public void AddToDo (ToDoCollectionItem item)
    {
        // ToDoが既に10個以上の場合
        if(ToDoList.Count() >= 10)
        {
            // 古いToDoを消して新しいToDoを追加する
            ...
        }
        ... 
    }

    ...
}

```

「**じゃあ、ToDoList.Add()でよくない？**」
と、IListのAddメソッドを利用してしまった場合はどうなるでしょうか。

わたし「ToDoCollectionは10個までしか入れちゃダメだからガードしなきゃ……」
```c#
public ProgramA()
{
    ...
    if(ToDoCollection.ToDoList >= 10)
    {
        ToDoCollection.ToDoList.Add(targetToDo);
    }
    
}

```
わたし「あ、こっちでもガード処理書かなきゃ……」
```c#
public ProgramB()
{
    ...
    if(ToDoCollection.ToDoList >= 10)
    {
        ToDoCollection.ToDoList.Add(targetToDo);
    }
    
}

```

**「ToDoCollectionの最大の要素数は10個とする」** というルールを守るための処理を、ToDoCollectionのアイテム追加処理を行う場所すべてで行わなければならなくなります。

ToDoCollectionのルールなのに、ToDoCollectionの外でルールを検証している状態で、**責務がクラスの外に漏れ出しています。**

それに、自分がルールを忘れずに守れてるならまだ良いですが、たとえば他の開発者がこのToDoListの設計を引き継いだ時、
**「ToDoCollectionの最大の要素数は10個とする」という、あちこちに散らばった、不文律的なルールは、果たして守られるでしょうか？**

上記のAddToDoメソッドのように、オブジェクトの保持するオブジェクトを直接外から操作せず、保持しているオブジェクトに操作を依頼するようにすることで、変更が限られた範囲で済み、オブジェクトのメンテナンス性が上がります。
これを**デメテルの法則**といいます。

## デメテルの法則

デメテルの法則では、メソッドを呼び出していいオブジェクトが以下の4つに限られています。
1. オブジェクト自身
1. オブジェクトに引数として渡されたオブジェクト
1. オブジェクトの持つインスタンス変数(フィールド)
1. オブジェクトが直接インスタンス化したオブジェクト

前章の例のAddToDoメソッドは、オブジェクト(ToDoCollection)自身が呼び出すメソッドなので、デメテルの法則に則っています。
逆に、ToDoListプロパティの持つIList型のAddメソッドを利用するのは、オブジェクト(ToDoCollection)の持つフィールド(ToDoList)のメソッドをオブジェクト外から呼び出すことになり、こちらはデメテルの法則に違反しています。

## おわりに

DDDの勉強中にデメテルの法則が出てきて **「これ指摘された奴や！」** と思いましたし、それ以来設計ノウハウとして気を付けるようにしていました。れっきとした法則なのは知りませんでしたが……。
XXX.YYY.ZZZ.....みたいな感じでカンマが数珠つなぎになっているコードがあったら、「変な呼び出し方してない！？」と一度振り返ってみてもいいかもしれないな、と思いました。

## 参考文献

『ドメイン駆動設計入門(成瀬 允宣 著)』
リレーションとアソシエーションの違いをアリでもわかるようにまとめておく

## はじめに
リレーションとアソシエーションの違いについて簡単にまとめておく。
だれかの役に立てば幸いです。

## リレーションとアソシエーションの違い
### リレーション
リレーションはテーブル同士の関係のこと。
例えば、1対多とか多対多とか、そういうこと。

### アソシエーション
アソシエーションは、クラス同士の関係のこと。
ユーザーは複数の投稿を持っているとか、こんな風に表現すること。
Railsで言えば、Userモデルはhas_many :postのアソシエーションみたいな感じで使うはず。多分。

## リレーションとアソシエーションの違いに関するまとめ
- リレーション
これは、テーブル間の関係についてのことを言う。
- アソシエーション
これは、クラス同士の関係を表す概念。オブジェクト指向プログラミングにおいての概念らしい。
PHPとJavaScriptを連携する

# １．はじめに
　個人環境でジュークボックスサーバーを動かしていて、サーバー(Linux)上のSAMBA領域にあるmp3ファイルをブラウザ(Chrome)で連続再生させるといったことをやっています。ブラウザ上ではChromeのMusicオブジェクトを使い、再生するのと同時に楽曲情報のテキストを表示させています。
　HTMLのFORM文を使うといちいち操作介入が必要になりますが、それだと煩わしいので１曲再生終了したら自動的に次のリクエストをサーバーへ送り、同時に楽曲情報を取得したいところです。再生の方はmusicオブジェクトにURLを渡して後はお任せなのですが、楽曲情報については、別途リクエストしなければなりません。
　これを実現するためブラウザ側ではJavaScriptでサーバー側に用意したAPIからXMLHttpRequestを使い、JSON形式の楽曲データを取得させました（下図）。取得したデータは動的HTMLでブラウザの表示に反映させます。
![PHPAPI(XMLHttpRequest).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2696131/a09af617-dc5f-4faa-24c8-40e6f0e8dbb3.png)

# ２．サーバー側のコード（API）
　いわゆるAPIになりますが、PHPで実装しています。シンプルにアーティスト名、アルバム名、楽曲名を返しています。可能であれば再生時間も返したかったのですが、mp3の提供系によってID3タグに埋め込んであったりなかったりなのでそこはあきらめました。
```
<?php
//addInformation.php
  $postedId = $_GET["id"];
  $arrLine = getMP3Info($postedId);
  $responce = "{\"artist\":\"".$arrLine[2]."\",\"album\":\"".$arrLine[3]."\",\"title\":\"".$arrLine[4]."\"}\n";

  header( "Server: JukeBox");
  echo $responce;
?>
```
　エラー処理などは省いています。getMP3Info()はリクエストされたidから楽曲情報を配列で返す関数で、本稿ではそちらの実体定義は省略します。getMP3Info()が返す配列情報をJSON形式に（強引に）整形しています。大抵はjson_encode()を使うところですね。
　header()はブラウザ側でのデバッグ用に入れ込んだ意味合いが強く、無くても大丈夫なはずです。本体は`echo $responce;`で、ここでJSONコードを返しています。適当なidを指定してブラウザで直接このURLにアクセスすると、ブラウザにはただJSON形式の文字列が表示されます。

# ３．クライアント側のコード（JavaScript)
　クライアント側はJavaScriptで先のAPIにアクセスします。アクセスにはXMLHttpRequestを使い、利用者の操作介入は必要しない作りとしました。どちらかというとサーバーよりもクライアント側のコードの方が分量があり、煩雑になるため当該のリクエストを実行する関数だけを抜粋します。
```
 function getMP3Info(idx){
   var xmlHttp = new XMLHttpRequest();

   console.log("xmlHttp: " + xmlHttp.readyState);
   xmlHttp.onreadystatechange = function (){
     console.log('get Information'+ " idx: " + idx);
     if (xmlHttp.readyState == 4) {
       if (xmlHttp.status == 200) {
         var dataJson = xmlHttp.responseText;
         var data = JSON.parse(dataJson);
         document.getElementById("controlArtistName").innerText = data.artist;
         document.getElementById("controlAlbumName").innerText =  data.album;
         document.getElementById("controlTitleName").innerText =  data.title;
       }
     }
   }
   xmlHttp.open("GET", "https://jukebox/addInformation.php?id="+idx);
   xmlHttp.send();
  }
```
　getMP3Info関数は単純です。id(idx)を与えるとサーバーのAPIにGETメソッドでアクセスし、得られたJSONデータを個別のパラメータに展開して動的にHTMLを更新しています。この関数はイベント（任意の曲がクリックされた、楽曲の再生が終わった、等）が発生したタイミングで呼ばれる作りになります。

# ４．おわりに
　今回紹介したAPIは完全にプライベート空間で使っているためシンプルな作りになっていますが、一般的なものとして外部公開することを前提にするのであれば、利用者の認証処理や、不正なリクエストへの対応処理などが必須となってきます。むしろ、難しくAPI作製のキモになるのはそちらではないかと思いますが、PHP⇔Javascript間のデータ連携の参考例になれば幸いです。
Vue.js 2系で簡単にタブ切り替えを実装する

### はじめに
仕事でVue.js(2系)でタブ切り替えを実装することになったので、アウトプットも兼ねて記事で解説してみようと思いました。
※ [注意]サンプルはVue.js(2系)でしか動きません。

まずはHTMLから記述します。

### HTML
```HTML:
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>

<div id="app">
  <div class="tabGroup">
    <ul class="tabNav">
      <li @click="select(1)" :class="{'active': show == 1}">
        タブAのボタン
      </li>
      <li @click="select(2)" :class="{'active': show == 2}">
        タブBボタン
      </li>
    </ul>
    <div class="tabContent">
      <div v-if="show == 1">タブAの内容を表示</div>
      <div v-else-if="show == 2">タブBの内容を表示</div>
    </div>
  </div>
</div>
```
上記の`<li @click="select(1)" :class="{'active': show == 1}">`
は`li`にクリックイベントを設定し、クリックされたらselectメソッドを呼び出しています。

また`:class="{'active': show == 1}"`はshowの値が１だったらactiveのclassを付与しています。

タブの内容を表示するところは
`v-if="show == 1"`だったらタブAの内容を表示し
`v-else-if="show == 2"`だったらタブBの内容を表示するようにしています。

次はJavaScriptを記述します。
### JavaScript
```JavaScript:
new Vue({
	el: '#app',
  data: {
    show: 1
  },
  methods: {
    select (number) {
      this.show = number;
    }
  }
})
```
上記の
`
data: {
    show: 1
}
`
でshowの値の初期値を１に設定しています。

HTMLの`li`のクリックイベントで紐付けたselectメソッドでは渡ってきたパラメータをshowの値にセットしています。
`this.show = number;`

これでタブのボタンのクリックイベントに紐づいているパラメーターとshowの値が同じ場合のみ、タブのボタンにactiveクラスが付与されて、タブの中身のコンテンツも１つだけ表示されるようになりました。
簡単にタブ切り替えが実装できました。
二値分類で使えそうなkfold~等しい割合でsplit~

二値分類で0,1を等しい割合でsplitしたい！！

そんなときはコレ！！！！！

```
kf = StratifiedKFold(n_splits=7, shuffle=True)
for train_index, test_index in kf.split(x, y):
```
親子の参照関係の画面のリフレッシュ


ちょっとしたコンポーネントを作成して入力を便利にしたいと思います。
商談の代わりに使う予定の案件管理オブジェクト(青色の枠)と売上予定月を複数入力できるように別のオブジェクト(緑色の枠)を作って親子の関係にしました。（実際には合計を簡単に出したかったので積み上げ集計項目を使うために主従関係にしています）


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/136d63ed-b266-f3a5-38cb-9fc2e8951779.png)

本当だったら、赤色の枠のような入力画面ですが... 年月度は自動で受注日の２年先を表示したいのでauraコンポーネントで作ってみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/6b5699f8-2d9d-c9dd-e8bf-8789ffee040b.png)

まぁ、簡単にできたのですがカスタムコンポーネントで子オブジェクトを登録しても積み上げ集計項目が変わりません。
あああ、F5を押して再ロードするとちゃんと合計が変わっています。ということは子オブジェクトを登録/修正したらリフレッシュさせればいいんだな。

ということで、保存処理の中に $A.get('e.force:refreshView').fire();を追加。
うまく機能しました。ただし、このカスタムコンポーネントは再描画しませんね。
仕方ないのでちゃんとlightning:tableにApexから最新のデータを渡します。
$A.get('e.force:refreshView').fire();は標準画面にしか適用されないのだろうか？

```
    saveTable: function(component, event, helper) {
        var editedRecords =  component.find("myDataTable").get("v.draftValues");
        //alert(JSON.stringify(editedRecords));
        var recordId = component.get("v.recordId");
        var action = component.get("c.editProspect");
        action.setParams({
            "editedRecords" : editedRecords,
            "recordId":recordId
        });action.setCallback(this,function(response) {
            var ResponseDto = response.getReturnValue();
            //alert(action.getState());
            //alert(ResponseDto.isSuccess);
            if (action.getState() == "SUCCESS" && ResponseDto.isSuccess) { 
                //if update is successful
                helper.showToast({
                    "title": "Record Update",
                    "type": "success",
                    "message": ResponseDto.values.Msg
                });
                helper.getRecord(component, event);//このコンポーネントの再描画
                $A.get('e.force:refreshView').fire();//親画面の再描画

            }  else if (action.getState() == "ERROR" || !ResponseDto.isSuccess) { 
                helper.showToast({
                    "title": "Error!!",
                    "type": "error",
                    "message": "Error in update"
                });                
            }
        });
        $A.enqueueAction(action);
    },
```
Laravelのあいまい検索が自分の中であいまいになっていた

## はじめに
Laravelではクエリビルダという機能があり、DBからレコードなどを取得する際にSQLに問い合わせると思うが、それを簡単にすることができる。
`where句`だったり`select句`などSQLでよく見るものもたくさんあり、Laravelでは非常によく使われる。

そんな中あいまい検索というwhere句を使った部分検索できる機能があり、
そこで少し手間取ってしまったのでまとめてみる。

## あいまい検索とは
基本的な使い方としては、ビュー画面などでキーワードを検索したときにコントローラでパラメータとして受け取り、対応するレコードを抽出してビューに返す。といった感じで使う。
あいまい検索なので、完全一致だけでなく、条件に応じて前後の文字が一致した場合などに対応させることができる。

## あいまい検索の種類
先程条件に応じてと記載したが、あいまい検索にはいくつかの種類がある。
`前方一致`、`後方一致`、`部分一致`がある。
```
$users = クラス::where("該当するカラム名", "LIKE", "条件");
```
- クラスを指定したのちwhere句の記載をする
- 第一引数に該当するカラム名、第二引数には今回あいまい検索なのでLIKEと記載する。第三引数にはどの一致なのかを記載してあげる。

それぞれクエリビルダでの書き方は以下のような感じ。

#### 前方一致
```
$users = User::where("name", "LIKE", "%Bob")->get();
```
- 前方一致の場合は一番前に`%`を書いてあげる。こうすることで前方一致判定とすることができる。

#### 後方一致
```
$users = User::where("name", "LIKE", "Bob%")->get();
```
- 後方一致の場合は一番最後に`%`を書いてあげる。こうすることで後方一致判定とすることができる。

#### 部分一致
```
$users = User::where("name", "LIKE", "%Bob%")->get();
```
- 部分一致の場合は一番前と最後に`%`を書いてあげる。こうすることで部分一致判定とすることができる。

## 送られてきたパラメータを判定したい場合
上記のようにBob決め打ちではなく、検索などパラメータとして渡ってきたものを判定したい場合は以下のような感じで書いてあげる。

例えば、`search=Bob`というような感じでパラメータが渡ってきたとする。
```
$hoge = $request->input('search');

$users = User::where("name", "LIKE", "%${search}%")->get();
```
のような感じで書いてあげる。
この際メソッドの引数には`($request Request)`と書いてあげるのも忘れずに。

## 完全一致の場合はどう書くか?
自分が詰まってしまったのはこの部分。完全一致の場合どのように書けばよいか。
最初いろいろ調べたところ下記のような感じでかけそうだったので書いてみた。
```
$users = User::where("name", "LIKE", "Bob")->get();
```

うまくいかない。
どうするか。
よくよく考えてみたらあいまい検索言うくらいだから、完全一致はそもそもあいまいじゃなくない??という結論に至った。

だったら下記のような感じで書けば良さそう。

```
$users = User::where("name", "=", "Bob")->get();
```
うまくいった。普通にこれで良かった。
真ん中の第二引数はなくても大丈夫。

ちなみに先程もあった受け取ったパラメータを使って書く場合はこんな感じ。
```
$hoge = $request->input('search');

$users = User::where("name", "=", $search)->get();
```

多分この考えでいいのではないでしょうか。
間違った考えだったり、指摘あればよろしくおねがいしますmm
Laravel学習記録①

**PHPフレームワーク「Laravel」について**
**学習した内容を自分の復習用として記録します。**
**エラーや個人的に疑問に思った点なども随時記載していきます**

使用OS：Windows11 バージョン21H2
PHP使用バージョン：PHP8.1.12
Laravel使用バージョン：Laravel Framework 9.48.0

使用書籍：PHPフレームワーク Laravel入門 第2版
&emsp;&emsp;&emsp;&emsp;&ensp;&ensp;(著：掌田津耶乃氏)

## 1.Laravelを導入する利点とは？

___①最低限のセキュリティが確保される___
___②自己流で書いたコードと比較してメンテナンスが容易である___
___③拡張性が確保されている___

__```自分のような初心者であればセキュリティを考慮した構築や、後々のメンテナンスを考慮した構築は難しい。```__


## 2.Laravel開発の手順
```mermaid
graph TD;
    1.プロジェクトの作成-->2.プログラムの作成;
    2.プログラムの作成-->3.サーバーを使った動作確認;
    3.サーバーを使った動作確認-->4.デプロイの実施;
```
___1.プロジェクトの作成___
プロジェクト(アプリケーションで必要となるファイルやフォルダ一式をまとめたもの)を作成する。
Laravelにおけるアプリケーション開発の土台となる。

___2.プログラムの作成___
自身が作成したいアプリケーションの機能となる部分を作成する。
(例:PHPのスクリプトファイル,画面表示のためのテンプレート,その他各種の設定ファイルなど)

__3.サーバーを使った動作確認__
Laravelに内蔵されているWebサーバー機能を使って動作に不具合がないか確認を行う

__4.デプロイの実施__
動作確認後、プログラムをWebサイトにアップロードし動かせる状態にする。
この一連の流れをデプロイと呼ぶ。

___
### 覚えておきたい単語
___・プロジェクト___
<font color="Red">__→アプリケーションで必要となるファイルやフォルダ一式をまとめたもの__</font>

___・デプロイ___
<font color="Red">__→動作確認後、プログラムをWebサイトにアップロードし動かせる状態にすること__</font>

___
LWCのJS内でクラス(っぽいもの)を用意したい

# はじめに
完璧には出来なかったので、もっと良い案をご存じの方おられましたら教えてください。

# やりたかったこと
画面に表示するデータを、同じデータ構造で複数種類保つ必要があったため、クラスに定義して保存するようにしたかった。

# だめだったこと
クラスの定義は出来なかった。  
シンプルなクラス定義と、匿名クラス定義とやらも試してみたけど上手くいかず。  

コードに書いたJavaScriptがそのまま画面に埋め込まれるわけではなく、そこからさらにLWC流に解釈されて  
色々動かされてるため、調べた結果がそのまま使えない感じでした。

# できたこと
色々な値や関数を定義したオブジェクトを作る関数を用意して、それを擬似的にクラスのような形で扱う。
```JavaScript
import getPersons from '@salesforce/apex/TestLWCController.getPersons';

export default class TestLWC extends LightningElement {

    // データを取得してくる
    async doGetPersons() {
    
        const result = await getPersons();
        const persons = this.buildPersons(result);
    }
    
    // 取得したデータを、変換後のデータに詰め替える
    buildPersons(result) {
        
        let persons = [];
        for (personMap of result) {
            persons.push(this.buildPerson(personMap));
        }
    }
    
    // apexから受け取ったデータを、objectに変換する
    buildPerson(personMap) {
        const person = {
            /**
             * 名前
             * JavaDoc形式にも対応している
             */
            name: personMap.name,
            age: personMap.age,
            height: personMap.height,
            weight: personMap.weight,
            selfIntroduction: function() {
                return '私の名前は' + this.name + '。\r\n' 
                     + '年齢は' + this.age + '歳だよ。';
            }
        };
        
        // もし、プロパティの追加や削除、設定された値の変更をしたくない場合はfreezeを使う
        // Object.freeze(person);
        return person;
    }
}
```

## 良い点
見るべきところを纏められる。  
基本的にはクラスを作ったときの良い点と概ね同じ。  

個人的に意外と出来てた点としては、JavaDocを書いたときのようにカーソルホバーをしたら、きちんとそのプロパティのdocが表示されたところ。
※ただし、カンマが手前に来てたらダメだった。
```javascript
const person = {
    /**
     * 名前 これは表示される
     */
     name : personMap.name,
    /**
     * 年齢 ←これも表示される
     */
     age : personMap.age
    /**
     * 身長 ←これは表示されない
     */
     ,height : personMap.height
};
```

## 悪い点
freezeをすると値の変更もできなくなってしまう。  
しかし、freezeをしなかった場合は以降利用しようとした際にプロパティ名を間違えて書いたとしても、その点に気づけない。(エラーは出ないため)
それと、LWCのhtmlから関数を呼ぶことは出来ないため、間に挟まるgetterが必要になる。
<details><summary>コード例</summary>

```html:testLWC.html
<template>
    <lightning-input>
        type="text"
        label="自己紹介文"
        value={person.selfIntroduction()} <!-- ← エラーになる -->
    ></lightning-input>
    <lightning-input>
        type="text"
        label="自己紹介文"
        value={person.selfIntroduction} <!-- ← 取得出来ないため、空になる -->
    ></lightning-input>
    <lightning-input>
        type="text"
        label="自己紹介文"
        value={selfIntroduction} <!-- ← 表示できる -->
    ></lightning-input>
</template>
```

```JavaScript:testLWC.js
export default class TestLWC extends LightningElement {

    person = this.buildPerson();
    
    buildPerson() {
        const person = {
            name: 'ゆうた',
            age: 13,
            height: 150,
            weight: 45,
            selfIntroduction: function() {
                return '私の名前は' + this.name + '。\r\n' 
                     + '年齢は' + this.age + '歳だよ。';
            }
        };
        
        return person;
    }

    get selfIntroduction() {
        return this.person.selfIntroduction();
    }

}
```
</details>
Testlinkのプラグインを試す

Testlink Version 1.9.15 から Plugin が使えるようになりました。

* Plugin フォルダにサンプルプラグインがある「TLTest」
* 言語、画面、主ルーチンのセットが入っている
* これを参考に(Copy して) Plugin を作成する
(外部のWebアプリでTestlinkの進捗グラフを表示させるもの）
* プラグインは外部 URL に飛ぶだけのものです

1. Testlink 管理者から Plugin アイコンをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114660/a4ef3c7b-c736-3174-6763-88845cf5811b.png)

2. アクション欄から [install] をクリックする
TLMetrics がメトリクスのメニューを追加するプラグイン
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114660/0402ac03-b392-3b39-d769-db2f0d001715.png)

3. 質問に「Yes」
下記の画面になる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114660/cd9a7aea-e3a6-95dc-e302-1e146f41d975.png)

4. メインに戻ると右下 Plugin セクションに「メトリクスツール」メニューが現れる

![picture484-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114660/5e0083d1-b4ed-fbdf-a82f-7da11ec79482.png)

5. Testlink 進捗グラフの例

![chart.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3114660/9db0f52f-3ad3-9924-d5e8-6aff079f4165.png)


グラフについてはいずれまた。

# Pluginのコード

<details><summary>サンプルコード</summary>

```TLMetrics.php
<?php
/**
 * TestLink Open Source Project - http://testlink.sourceforge.net/
 * This script is distributed under the GNU General Public License 2 or later.
 *
 * @filesource  TLTest.php
 * @copyright   2005-2016, TestLink community
 * @link        http://www.testlink.org/
 *
 */

require_once(TL_ABS_PATH . '/lib/functions/tlPlugin.class.php');

/**
 * Sample Testlink Plugin class that registers itself with the system and provides 
 * UI hooks for 
 * Left Top, Left Bottom, Right Top and Right Bottom screens.
 * 
 * This also listens to testsuite creation and echoes out for example. 
 * 
 * Class TLTestPlugin
 */
class TLMetricsPlugin extends TestlinkPlugin
{
  function _construct()
  {

  }

  function register()
  {
    $this->name = 'TLMetrics';
    $this->description = 'Testlink Metrics Menu';

    $this->version = '1.0';

    $this->author = 'Testlink';
    $this->contact = 'shinji.hanzawa@xxxxx.co.jp';
    $this->url = 'http://www.collab.net';
  }

  function config()
  {
    return array(
      'config1' => '',
      'config2' => 0
    );
  }

  function hooks()
  {
    $hooks = array(
      'EVENT_RIGHTMENU_BOTTOM' => 'right_bottom_link',
      'EVENT_TESTRUN_DISPLAY' => 'testrun_display_block'
    );
    return $hooks;
  }

  function testrun_display_block() {
    $args = func_get_args();
    // $args details: $arg[1] -> Testplan Id, $arg[2] -> Build Id, $arg[3] ->TestCase Id, $arg[4] -> TestCase Version Id
    return '<img src="http://www.testingexcellence.com/wp-content/uploads/2010/01/testlink-open-source-test-management-tool.jpg" />';
  }

  function right_bottom_link()
  {
    return "<a href='http://localhost/tlMenu/index.php' target='_blank' >".plugin_lang_get('config')."</a>";
//	<a href='" . plugin_page('config.php') . "'>".plugin_lang_get('config')."</a>";
  }

}

```

</details>
Gihtub Actions から実行する JavaScript 内で後続に渡す Output を設定する

# 概要
Github Actions で実行したステップの出力結果を後続に連携したい場合、決められた様式で出力することで対応できます。

https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-output-parameter

```yaml:例
      - name: Set color
        id: random-color-generator
        run: echo "SELECTED_COLOR=green" >> $GITHUB_OUTPUT
      - name: Get color
        run: echo "The selected color is ${{ steps.random-color-generator.outputs.SELECTED_COLOR }}"
```

Actions から実行する JavaScript 内で、出力結果をセットする手順をメモに残す。

# 手順
1. @actions/core パッケージをインストール
    - `npm install @actions/core`
1. JavaScript 内で `core.setOutput` を実行する
    ```javascript
    const core = require('@actions/core');

    core.setOutput('outputKey', 'outputVal');
    ```
1. 後続のワークフローで参照する
    ```yaml
      - name: echo
        run: |
          echo ${{steps.step_id.outputs.outputKey}}
      - name: if test
        if: steps.step_id.outputs.outputKey != 'SAMPLE_VALUE'
        run: |
          echo "trueの処理"
    ```



## 参考情報
https://github.com/actions/toolkit#packages
https://github.com/actions/toolkit/tree/main/packages/core
【Django】datetime型のフォーマットを変更（0埋めしない方法も）

毎回調べているので備忘録

## Django側で変更

~~~python
from datetime import datetime

time = datetime.datetime.now() # 2023-01-31 16:11:23.849831

print(time.strftime('%Y年%m月%d日 %H時%M分%S秒')) # 2023年01月31日 16時11分23秒

# mやdの前に「-」を入れると0埋めされないようになる
print(time.strftime('%Y年%-m月%-d日')) # 2023年1月31日
~~~

### strftime()の詳しい使い方
https://docs.python.org/ja/3/library/datetime.html#strftime-and-strptime-format-codes

## テンプレート側で変更

~~~python
{{ time|date:"Y/n/j" }}
{{ time|date:"Y/m/d" }}
~~~

表示
~~~
2023/1/31
2023/01/31
~~~

### 詳しくはここ
https://office54.net/python/django/template-date-filter
プロジェクト参画時にgit cloneから始める時(ローカルにリモートリポジトリクローン)

備忘録

環境
MAC
php
mysql
ローカル内で動けば良いので、一旦MAMP


~~git hub のssh接続を有効にする。~~
→ssh非推奨なう。httpsでクローン推奨とのこと。

### 1,MAMPのhtdocsファイル内にてgit clone (githubクローン元のhttpsコピペ貼る)
この時にhtdocs内にファイルも作成される。
※階層気をつける。階層ミスると、ファイル内にファイルできて、大変
該当ファイルに移動 cd

~~git init~~
→これはgitを初期化して作るものなので、クローンした後にこれをしてしまうと、リモートリポジトリが　なくなりpush先がないと認識され、push できない。

既存コードや、インポートしたものがあれば、そのファイルへコピペする。
### 2,git aad .
### 3,git commit -m"コミットコメント追記"
### 4,git push origin main(push先のブランチ名入れる)

その後は、作業ブランチ(dev,stg,prd)作るなりして開発に入る。
FESS で Redmine ナレッジベースと用語集をクロール

# FESSでナレッジと用語集をクロールする設定

[ナレッジベース　プラグイン](https://github.com/alexbevi/redmine_knowledgebase "knowledgebase")
[用語集　プラグイン](https://www.r-labs.org/projects/rp-glossary/wiki/Glossary "Glossary")

* どちらもデータストアでクロールします
* ナレッジと用語集は同じ一つのプロジェクトで管理しています(Project ID:index)
* url はRedmineサーバー環境にあわせてください

## ナレッジベース

SQL文
```SQL
sql=SELECT id,title,summary,content, DATE_FORMAT(updated_at,'%Y-%m-%dT%H:%i:%s.00Z') AS last_modified_dt FROM kb_articles
```

スクリプト
```script
url="https://xx.xx.xx.xx/redmine/projects/index/knowledgebase/articles/" + id
host="https://xxx.xx.xx.xx/"
site="https://xx.xx.xx.xx/redmine/projects/index/knowledgebase/"
title="【Redmine - ナレッジベース】" + title
content=content
cache=content
digest=summary
anchor=
content_length=content.length()
last_modified=last_modified_dt
timestamp=last_modified_dt
```

## 用語集

SQL文
```SQL
sql=SELECT id,name,description, DATE_FORMAT(updated_at,'%Y-%m-%dT%H:%i:%s.00Z') AS last_modified_dt FROM glossary_terms
```

スクリプト
```script
url="https://xxx.xx.xx.xx/redmine/projects/index/glossary_terms/" + id
host="https://xxx.xx.xx.xx/"
site="https://xxx.xx.xx.xx/redmine/projects/index/glossary_terms/"
title="【Redmine - 用語集】" + name
content=description
cache=description
digest=name
anchor=
content_length=content.length()
last_modified=last_modified_dt
timestamp=last_modified_dt
```
VSCodeにChatGPTを入れてコードレビューやバグを発見してもらう

こちらの記事を参考にやってみた。
https://qiita.com/tak001/items/c3000b3ce9b6e72b2ae5

# つまずきポイント
## ChatGPTのアカウント登録とOpenAIのアカウント登録は別物！
Api Keyの設定をする手順が以下のように紹介されていた。
>入力欄の上にある「Documentation」をクリック
ブラウザが開くので、「Create new secret key」をクリック
API key が作成されたらコピーして、VSCode の Settings の「Api Kye」へ貼り付ける

だが、[ChatGPTの画面](https://chat.openai.com/chat)で探せど探せど入力欄の上に「Documentation」がない！
そこで、ChatGPTに聞いてみた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526938/bf51eea9-227c-8b68-bf67-ea7c329ed55e.png)

神。ということで[OpenAIのサイト](https://openai.com/)に行き、OpenAIのアカウントを登録する。
![スクリーンショット 2023-01-31 15.51.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526938/4c878a39-bc3f-bf8a-5bf1-5ee5c565d904.png)

## 入力欄の上にある「Documentation」をクリックしてもAPI Keysが出てこない
「Documentation」ではなく、右上にある「Personal」の「View API keys」を押そう。
![スクリーンショット 2023-01-31 16.01.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526938/302d3af4-eb15-a882-dbc9-8d419bf6fc2b.png)

## 設定が終わったので使ってみると・・
無事に使えた〜！！こりゃスゴイ。
<img width=500 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526938/f3990513-9b81-57f0-558d-fb80a365b82a.png"/>)

# 勉強になったポイント
## ChatGPTの便利な使い方
「〇〇のサンプルコードを教えて」と質問した場合、文章が長すぎて途中でChatGPTの返答が止まってしまうことがあった。
そんな場合は、「続き」と入力すると再開してくれる！
UE5で筒状オブジェクトの穴に入る方法

# はじめに
ゲームを作りたいなと思って、UE5を入れてみたものの何から何までわからん。
ネットで調べたくても調べ方もわからん。
今回はそのうちの一つで筒状オブジェクトを置くときのメモです。
# こんなオブジェクトを配置したい
こんな筒状オブジェクトをBlenderで作ってfbxでエクスポートする
<img width="700" alt="オブジェクト" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2970350/2a3788de-df4d-11fd-d539-37d0f546a52a.png">

# そのまま配置しただけだと
BlenderからエクスポートしたデータをUE5で読み込み、そのままマップに配置すると穴の上に乗ってしまう。
<img width="300" alt="UE5_fail" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2970350/a1df3da8-0743-17d8-d712-ec0608c174e0.gif">

# コリジョンの設定を変える
先ほど読み込んだオブジェクトをダブルクリックしマテリアル編集画面(?)で右の詳細設定からコリジョンを探す。
コリジョンの中の「Collision Complexity」の値を「Use Complex Collision As Simple」にする。
<img width="500" alt="UE5_setting" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2970350/8625231a-bc14-82f5-9f35-97560b866d28.png">

# 戻って試してみると
変更を保存して、再びシミュレーションを実行してみると. . .
<img width="300" alt="UE5_success" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2970350/612038cf-03b2-4d17-9678-82c7401d3485.gif">
できた！

# 原因
UE5のコリジョンには「単純なコリジョン」と「複雑なコリジョン」の２種類が存在しているようで初期設定だと足場には単純なコリジョンが読み込まれているっぽい。
基本的には、プレイヤーやモンスターみたいな動くものは単純なコリジョンで、設置物は複雑なコリジョンにすればよいのかな。

詳しくは：https://docs.unrealengine.com/5.1/ja/simple-versus-complex-collision-in-unreal-engine/


ほかにもいろいろ方法があると思います。
2022年版Googleでログイン(gsi)で、prompt が表示されない？！

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

この記載通りに実施すると、ウマク動作しましたが、一度認証せずにキャンセル、プロンプトを閉じると、以降プロンプトが表示されなくなります。

ちょっと例示のスクリプトに追加して原因調査します。

```
    google.accounts.id.prompt((notification) => {
      if (notification.isNotDisplayed() || notification.isSkippedMoment()) {
        // notification.getNotDisplayedReason() が suppresed_by_user になってしまって、
        // 2度目以降がウマク動作してくれない
      }
    });

```

https://developers.google.com/identity/gsi/web/guides/features?hl=ja#exponential_cooldown

この記載によると、何度かキャンセルをすると、抑制ユーザとして、プロンプトを一定期間表示しなんだとか。。。。
4回行うと 4週間使えないとか、厳しすぎません？

別の仕組みでログインできれば、元に戻るとのこと。。。

もうちょっと検証が必要ですね。
JANOG51 NETCON Level4-1問題解説

# はじめに
2023年1月24日～26日（JANOG51の会期は1/25～1/27）に行われたJANOG51 NETCONで出題されたLevel4-1の問題解説です。

# 問題
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133769/b83e7ccc-058e-8686-df09-02d9d238b73c.png)

新しく買ったスイッチ。
ファイバで接続しようとするもどうも様子がオカシイ・・・。リンクが上がったり、切れたり・・・。
設定には問題ないし・・・。

先輩「それ、つなぐときにちゃんとファイバの確認した？」
私「適当にその辺にあったファイバ使いました。」
先輩「そのファイバって先端にキャップついてた？」
私「なんもついてなかったですよ」
先輩「うーーーん、、、」

さて、問題はどこにあったでしょうか？

　＊端面検査機とファイバークリーナを用意しています。ご自由にお使いください

# 解説
- 通信速度が遅い場合はそんなに問題になりませんが、通信速度が速くなるにつれて接続に使用する光ファイバの性能が重要になってきます。
- 特に接続面（ファイバの端面）に汚れが付着していると、そこで信号の減衰が大きくなり物理リンクが上がらなくなったりします。
- 光ファイバを接続する時は、端面検査機を使って端面状態を確認し、汚れがある場合はクリーナで清掃してから使用しましょう。新品のケーブルでもたまに端面が汚れていることがあります。
- 端面が汚れたファイバを使ってJJやインターフェイスに挿すと、対向側の端面に汚れが付着することもあるので注意しましょう。

端面検査機に接続して、端面の状態を確認します
今回はEXFO社のFIP-415BとVIAVI社の端面検査機を用意しました。
端面検査機にLCコネクタを差し込みます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133769/01dc0675-57cf-d41f-2033-64c4c35bc523.png)

汚れているがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133769/52aa85f5-6298-023c-4b5e-bc8c46f6fc39.png)

クリーナに差し込みカチッと音がするまで押し込みます。
今回は、精工技研社のスティック型クリーナを用意しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133769/d718ab35-3291-ed2e-f8b1-e6153330f1f8.png)

クリーニング後に再度端面検査機で見ると、綺麗になっています。
中心に見える白い部分がコア、その周りの薄い灰色部分がクラッド、黒い部分が保護材となります。
今回はマルチモードファイバなので、コアが太目です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133769/deef24a6-7046-2025-c4e1-b3dfa429e48b.png)

# 終わりに
今回の問題は、端面の汚れを検査してクリーニングする問題でした。
レーザは結構強いので、短距離かつ帯域があまり大きくなければ問題になることはあまりありません。
ただ、10G、40G、100G、400Gbpsと帯域が広くなるにつれ、距離が長くなるにつれ汚れ等の影響が大きくなります。
実際に端面の汚れによってリンクアップ・ダウンを繰り返すこともあります。
光ファイバを接続する時は新品でもクリーニングしてから使うようにしましょう。
端面部以外については、OTDRといった測定器を使用して減衰がどこで大きくなっているのかを測定して原因を調査します。
[Flutter]Colorコードのあれこれ

![flutter-logo-sharing (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672609/a267c231-0cc9-fd5f-7dee-09bcb409076c.png)

こんにちわ。いせきです。最近寒いですね。ほんとに寒くて家に出るのが億劫になってしまいます。でも外に出て散歩して健康づくりをやっています。おじさんみたいな生活を送っています。

今回は、カラーコードが色々な記載方法があることを知ったので共有していこうと思います。
色の設定でできることをまとめてみました。



# カラーコードの設定例


```dart
Container(
  width: 100,
  height: 100,
  color: Colors.black,
),
```

```dart
Container(
  width: 100,
  height: 100,
  color: const Color(0xff000000),
),
```

```dart
Container(
  width: 100,
  height: 100,
  color: const Color(4278190080),
),
```

```dart
Container(
  width: 100,
  height: 100,
  color: Color(int.parse('ff000000', radix: 16)),
),
```

色々と書き方があることを知りました。しかし、`Color(4278190080),`だとWarningが出るのでconst Color(0xff000000),`Color(0xff000000),`の方が良さそうです。

warning文を見てみると

```
Prefer an 8-digit hexadecimal integer(0xFFFFFFFF) to instantiate Color
```
と記載されています。念のための共有です。

Materialの色で問題ない場合は、`Colors`を使用して、指定がある場合は、`Color(4278190080)を使用した方が良さそうですね。




# 最後に
ColorCodeは、Widgetでたくさん使うことがあるので、色々な表現方法があるだけでも知っておくととても便利になると思います。まあ、最低でも１つ以上使いこなせれば問題はないと思います。


# 参考文献

https://pryogram.com/flutter/color-code-int-string/