OmniAICreator/Qiita-1.07M huggingface dataset:
不要な@ModelAttributeに四苦八苦した備忘録

Spring Bootでフォームデータを扱う際の注意点

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327267/6b1efeff-a2b3-e368-2d46-140cfd6907d1.png)

Spring Bootを使用して、コンボデータを管理するシンプルなフォームを作成していました。当初、コンボの追加機能を別ページで実装していたものを、同一ページ内で完結させようとした際に問題が発生しました。具体的には、フォームに入力したデータを保存しても、データが反映されずに空のレコードが作成されるという不具合がありました。

状況
不具合発生時のHibernateログ:
```
Hibernate: insert into jp_combos (damage, `explain`, input, name, startup, usagedg, usagesa) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: select j1_0.id,j1_0.damage,j1_0.`explain`,j1_0.input,j1_0.name,j1_0.startup,j1_0.usagedg,j1_0.usagesa from jp_combos j1_0
```

このログから、データベースへの挿入は行われているものの、具体的な値がバインドされていないことがわかります。

リクエストペイロードには正しい値が含まれていましたが、それが反映されていませんでした。

解決策
問題の原因は、@PostMappingアノテーションを使用したコントローラーのメソッドaddComboのシグネチャにありました。具体的には、@ModelAttributeと@RequestBodyが同時に使用されていた点にありました。

問題のあったコード:

java
Copy code
@Transactional
@PostMapping("/combos/add")
public ResponseEntity<?> addCombo(@ModelAttribute @RequestBody JP_combosEntity newCombo) {
    ...
}
修正後のコード:

java
Copy code
@Transactional
@PostMapping("/combos/add")
public ResponseEntity<?> addCombo(@RequestBody JP_combosEntity newCombo) {
    try {
        jp_combosService.saveJP_combo(newCombo); // 新しいコンボを保存する
        return ResponseEntity.ok().build(); // 成功時は200 OKを返す
    } catch (Exception e) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("エラーメッセージ");
    }
}
@ModelAttributeアノテーションの削除により問題が解決しました。@ModelAttributeは主にフォームデータのバインディングに使用されるため、JSON形式のペイロードを扱う場合には@RequestBodyのみを使用するのが適切です。
You cannot modify this Transit Gateway as there exists at least one active attachment that uses the current ASN.

# 概要

Transit Gateway の設定を変更しようとした際に、以下のエラーに遭遇しましたので記録しておきます。

`You cannot modify this Transit Gateway as there exists at least one active attachment that uses the current ASN.`


# 操作

コンソールから、「Transit Gateway　を変更」から、「共有アタッチメントを自動承認」にチェックし変更。
![スクリーンショット 2024-03-23 1.34.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/c3d18854-269f-6011-0b89-3e77e5577435.png)

ASN は変更していないのに現在の ASN を使用するアクティブなアタッチメントが少なくとも 1 つ存在するため変更できない？


# 先に回避策

CLI ならできるようです。

```
aws ec2 modify-transit-gateway --transit-gateway-id tgw-0ae40b8357228da95 --options AutoAcceptSharedAttachments=enable

{
    "TransitGateway": {
        "TransitGatewayId": "tgw-XXX",
        "TransitGatewayArn": "64512",
        "State": "modifying",
        "OwnerId": "123456789012",
        "Description": "",
        "CreationTime": "2024-03-22T15:04:55+00:00",
        "Options": {
            "AmazonSideAsn": 64512,
            "AutoAcceptSharedAttachments": "enable",
            "DefaultRouteTableAssociation": "disable",
            "DefaultRouteTablePropagation": "disable",
            "VpnEcmpSupport": "enable",
            "DnsSupport": "enable"
        }
```


# 推測

とは言っても参考になりそうな記事は以下しかない。

https://repost-aws.translate.goog/questions/QUiESVUCeYSdaE6R-5IFY-kA/modificar-asn-direct-connet-gateway?_x_tr_sl=en&_x_tr_tl=ja&_x_tr_hl=ja&_x_tr_pto=sc&_x_tr_hist=true

「ASN の変更操作は、アクティブな BGP セッションを持つ Transit Gateway では許可されていません。Transit Gateway　で ASN を変更する前に、まず BGP が設定されている Transit Gateway　のアタッチメントをすべて削除する必要があります。」

下記の通り、VPN と接続しており、Transit Gateway とアタッチメントしている。（ただし、VPN の静的と動的は CGW とのルーティングの設定なので関係はないかとは思う。）

![スクリーンショット 2024-03-23 1.44.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/15900c0d-bc6d-ccea-a78d-c0c021c8315e.png)
![スクリーンショット 2024-03-23 1.45.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/09df8ba4-ca16-c1e4-5952-c240d152f014.png)

まあ、おそらくコンソールからやるとまるっと変更しようとしてして、CLI は変更しようとする箇所のみ行うのだろう。。。
だれも解説しないけど、NginxをWindowsで起動し、Flask APPを動作させてみた

### 目的
Nginx Windows版があるのにも関わらず、なぜかWSL2やUbuntuなどの記事が目立つ、筆者はインドの方のビデオを見てひらめき、そして試してみたらできた。

### 必要なもの
1. Flask APP
1. Nginx For Windows
1. Waitress(pip install済）

### やり方
1. Nginx for Windowsをダウンロードして、解凍しておく
1. pip install waitressでwaitressをインストール
1. waitressのポートを5000に振っておく
1. nginx.confを開き、以下のようにしておく

```config

#user  nobody;
worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;
    keepalive_timeout  65;

    server {
       listen       3000;

       location / {
            proxy_pass http://localhost:5000;
  
       }
    }
}
```
5.Flaskは以下のようにしておく
```py
from waitress import serve

# APP本体は省略

if __name__ == "__main__":
    serve(app, host='0.0.0.0', port=5000)
```

6.python app.pyを実行

7.Nginxを起動

8.ブラウザからlocalhost:3000でFlaskアプリが見えたら成功

以上、検討を祈る
SvelteKit を使ったサイトで静的な OGP 画像を設定しようとしたら思ったより苦労した話

## この記事の概要

個人開発でサイトを作った[^1]のですが、その際 OGP 画像を設定するのに思ったより苦労しました。

[^1]: 文字数カウントやルーレットなど、ちょっとしたツールをまとめたサイトです。記事の本筋にはまったく関係ありませんが、触ってみてもらえたら嬉しいです。

以下のリンクカードに出ている画像が実際に設定したものです。

https://kodowg.pages.dev/

最終的に解消した方法と、試したけどダメだった方法を備忘録がてら記事にします。

## 環境

[SvelteKit](https://kit.svelte.jp/) (v2.0.0) を使い、[Cloudflare Pages](https://pages.cloudflare.com/) で公開しています。

## 作った内容

1 種類の画像をサイトのどのページでも使う、静的な OGP 画像の設定。

## 作らなかった内容

ページタイトルごとにテキストが変わるなどの、動的な OGP 画像の設定。

## 最終的に解消した方法

- `static` ディレクトリに画像を配置する
    - ここに置かれたファイルは `https://{ホスト名}/{ファイル名}` で配信される
- `$app/stores` からページデータを読み取れる `page` を import する
- `page.url.origin` で、サイトのオリジンを取得する
- 文字列を結合させて OGP 画像の完全な URL を生成する
- `routes` 直下の `+layout.svelte` の中の `<svelte:head>` の中で OGP 画像を設定する

上記をコードにすると次のようになります（[コメント](https://qiita.com/xrxoxcxox/items/db6260e7fefe92a85d8e#comment-e9246ab0067f9b33477c)でいただいた内容を反映しました）。

```svelte:src/routes/+layout.svelte
<script>
  import { page } from '$app/stores';
</script>

<svelte:head>
  <meta property="og:image" content="{$page.url.origin}/og-image.jpg" />
</svelte:head>
```

参考情報:

- [Modules - $app/stores | SvelteKit](https://kit.svelte.jp/docs/modules#$app-stores)
- [Types - Public types - Page | SvelteKit](https://kit.svelte.jp/docs/types#public-types-page)
- [備忘録:SvelteKitで今いるURLを取得する | Qiita](https://qiita.com/Usuyuki/items/96e6c8527b35981533cf)

## 試したけどダメだった方法

### `%sveltekit.assets%` を使う

`create svelte` のコマンドで生成された `app.html` では、ファビコンが次のようにして呼ばれていました。

```html:src/app.html
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
```

`%sveltekit.assets%` というのはアセットディレクトリへのパスです。
そのため、これを使って次のようにコードを書いてみましたが、失敗しました。

```html:src/app.html
<meta property="og:image" content="%sveltekit.assets%/og-image.jpg" />
```

`%sveltekit.assets%` が展開された後のコードとして、ファビコンと OGP 画像とでは以下のような違いが生まれました。

```html:src/app.html
<link rel="icon" href="http://localhost:5173/favicon.png" />
<meta property="og:image" content="./og-image.jpg" />
```

OGP 画像は相対パスではなく、ちゃんとした URL で指定しないといけません。
そのためこの方法は諦めました。

参考情報:

- [Project structure - Project files - src | SvelteKit](https://kit.svelte.dev/docs/project-structure#project-files-src)

### URL コンストラクタと `import.meta.url` を組み合わせて使う

その後、次のようなコードを書きました。

```svelte:src/routes/+layout.svelte
<script>
  import { base } from '$app/paths';
  const imgUrl = new URL(`${base}/og-image.jpg`, import.meta.url).href;
</script>

<svelte:head>
  <meta property="og:image" content={imgUrl} />
</svelte:head>
```

これは開発環境では上手く動いたのですが、デプロイしたら 500 エラーを吐いてしまいました。
デプロイ先が Cloudflare Pages（というか静的なホスティング環境）だったからだと思われます。

参考情報:

- [Where to put images with SvelteKit | Stack Overflow](https://stackoverflow.com/a/72989049)
- [URL - Web API | MDN](https://developer.mozilla.org/ja/docs/Web/API/URL)
- [import.meta - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/import.meta)
- [Modules - $app/paths | SvelteKit](https://kit.svelte.jp/docs/modules#$app-paths)

## 最後に

こんな具合で紆余曲折あった後、最初に書いた `$app/stores` を用いる方法で期待通りに動きました。
まったく難しいことでは無いはずで、10 分もあれば完成するかと思っていたのに、やたらと時間をかけてしまいました。

これがベストなやり方なのか正直自信はありませんが、ひとまずちゃんと動いているので記事にしています。
調べても全然出てこなかったので、どなたかのお役に立てれば幸いです。
Invoke-Sqlcmd コマンドで WID に接続する

WSUS などでおなじみの Windows Internal Database へアクセスするときに、下記のようなコマンドを実行します。
``` PowerShell
Invoke-Sqlcmd -ServerInstance "\\.\pipe\microsoft##WID\tsql\query" -Query "Select @@version"
```

が、下記のようなエラーが発生するようになってしまいました。
![Invoke-Sqlcmd : The instance of SQL Server you attempted to connect to does not support encryption.](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667945/a1e2ab36-e2a4-f0bf-1ceb-eb3d167f1e23.png)

```
Invoke-Sqlcmd : The instance of SQL Server you attempted to connect to does not support encryption.
発生場所 行:1 文字:1
+ Invoke-Sqlcmd -ServerInstance "\\.\pipe\microsoft##WID\tsql\query" -Q ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [Invoke-Sqlcmd]、SqlException
    + FullyQualifiedErrorId : SqlExceptionError,Microsoft.SqlServer.Management.PowerShell.GetScriptCommand

Invoke-Sqlcmd : '' の解析中に無効な構文が見つかりました。
発生場所 行:1 文字:1
+ Invoke-Sqlcmd -ServerInstance "\\.\pipe\microsoft##WID\tsql\query" -Q ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ParserError: (:) [Invoke-Sqlcmd], BatchParserException
    + FullyQualifiedErrorId : ExecutionFailureException,Microsoft.SqlServer.Management.PowerShell.GetScriptCommand
```

エラーを読むと、暗号化をサポートしていないことが原因のようです。
暗号化が既定で必要になったことが要因と思われます。
https://learn.microsoft.com/ja-jp/sql/connect/oledb/major-version-differences?view=sql-server-ver16

` -Encrypt Optional ` を追加することにより解決するようです。
``` PowerShell
Invoke-Sqlcmd -ServerInstance "\\.\pipe\microsoft##WID\tsql\query" -Query "Select @@version" -Encrypt Optional
```

![Microsoft SQL Server 2014 (SP2-GDR) (KB4057120) - 12.0.5214.6 (X64)
        Jan  9 2018 15:03:12
        Copyright (c) Microsoft Corporation
        Windows Internal Database (64-bit) on Windows NT 6.3 <X64> (Build 20348: )](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667945/806f9c31-71c3-bc40-da9c-6640e8b4bc13.png)
無料のONLYOFFICE DocBuilderを使用して、スクリプトからdocx、xlsx、pptx、およびpdfファイルを生成する方法

みなさん、素晴らしいニュースです！

[ONLYOFFICE Document Builder](https://www.onlyoffice.com/ja/document-builder.aspx?utm_source=qiita&utm_medium=social&utm_campaign=docbuilder)の新バージョン、ドキュメントを生成するための当社のライブラリが、AGPLv3ライセンスの条件でGitHubで利用可能になりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655664/28d393db-b4dc-2d71-da57-d52e58ba96aa.png)

## DocBuilderとは？

ONLYOFFICE Document Builderは、JavaScriptコードからドキュメントを生成するためのツールです。以下にその特長をご紹介します。

* 任意の複雑さのdocx、xlsx、pptxファイルを生成および変更できます。
* ドキュメントをプリンタに送信したり、PDFとして保存したりすることができます。
* どんな言語で書かれたアプリにも統合できます。
* アプリでOfficeドキュメントとやり取りするたびに実際のエディタを実行する必要はありません。

ソースコードは[GitHub](https://github.com/ONLYOFFICE/DocumentBuilder)で入手できます。

DocBuilderの使用方法の詳細情報は、当社の[APIドキュメント](https://api.onlyoffice.com/docbuilder/basic)に記載されています。

## ライセンス

AGPLv3ライセンスを遵守する限り、ONLYOFFICE Doc Builderを無料で使用することができます。

[**今すぐ入手**](https://www.onlyoffice.com/ja/document-builder.aspx?utm_source=qiita&utm_medium=button&utm_campaign=docbuilder)

独自の製品で使用したい場合は、sales@onlyoffice.com まで当社のセールスチームにお問い合わせください。
AWS勉強備忘録20 - EC2, S3, RDSとHerokuを使ったPostgreSQLの管理

AWSのEC2、S3、RDSを使用している場合、PostgreSQLデータベースの運用方法にはいくつかの選択肢があります。また、Herokuを使用している場合のPostgreSQLのセットアップについても考察します。この記事では、それぞれのシナリオでのPostgreSQLの利用方法と、そのメリットとデメリットを掘り下げていきます。

## AWSでのPostgreSQL運用

### EC2での自己管理

EC2インスタンス上にPostgreSQLを直接インストールし、自分で管理することができます。この方法のメリットは、データベースの設定や管理に対して完全なコントロールを持てる点です。しかし、データベースのセットアップ、セキュリティ、バックアップ、スケーリングなど、すべて自分で行う必要があります。

### RDSを使用する場合

AWS RDSはマネージドリレーショナルデータベースサービスで、PostgreSQLを含む複数のデータベースエンジンをサポートしています。RDSを使用すると、AWSがデータベースの運用を担ってくれるため、バックアップ、パッチ適用、スケーリングが容易になります。

### S3の利用

S3はオブジェクトストレージサービスで、直接データベースとしては機能しませんが、PostgreSQLのバックアップデータの保管場所として使用できます。

## HerokuでのPostgreSQL運用

Heroku上でPostgreSQLを使用する（例えば、Rails + PostgreSQLアプリケーションをデプロイしている）場合、大抵は`Heroku Postgres`サービスを使用しています。`Heroku Postgres`は、サーバー管理やデータベース運用の手間を省くマネージドサービスです。

### Heroku Postgresの確認方法

Herokuダッシュボードの`Resources`タブから、アプリケーションに紐づけられたアドオンを確認することができます。また、Heroku CLIを使用して`heroku addons`コマンドを実行することで、利用しているアドオンの一覧を確認できます。

## 結論

AWSのサービスを使用している場合、PostgreSQLの運用には柔軟な選択肢があります。自己管理が求められるEC2、運用の手間を省けるRDS、そしてバックアップストレージとしてのS3など、ニーズに応じて選択できます。Herokuを使用している場合は、Heroku Postgresを使用することで、開発の効率化を図ることができます。
便利なPendoブックマークレット

Pendo使っていると頻繁に使うコマンドがあります

`pendo.enableDebugger()`
ガイドのテストやAgentの状態を調べるためのデバッガー

`pendo.designerv2.launchInAppDesigner()`
ガイド作成やタグ付けをアプリから直接できるVDS


いちいちコマンドコンソール開いて上記コマンド打つのもめんどくさい

そこでbookmarkletにして保存しておけば便利なんじゃないかと

任意の機能がいつでも起動できるようにしてみた。

元ソース
https://gist.github.com/Band-Aid/bc094291621120c214095209cdc69ee4

![CleanShotcX6CAhMm@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227518/b096d30f-2bce-4447-b699-9847f4d6ad9f.png)


```javascript
javascript:(function()%7B(function()%7B%0A    function removeDialog() %7B%0A        document.body.removeChild(document.getElementById('customDialog'))%3B%0A    %7D%0A%0A    function functionDebugger() %7B%0A        try %7B%0A            pendo.enableDebugging()%3B%0A        %7D catch (e) %7B%0A            console.log('Pendo VDS is not available.')%3B%0A        %7D%0A        removeDialog()%3B%0A    %7D%0A%0A    function functionVDS() %7B%0A        try %7B%0A            pendo.designerv2.launchInAppDesigner()%3B%0A        %7D catch (e) %7B%0A            console.log('Pendo VDS is not available.')%3B%0A        %7D%0A        removeDialog()%3B%0A    %7D%0A%0A    function functionCloseDebugger()%7B%0A        try %7B%0A            pendo.disableDebugging()%3B%0A        %7D catch (e) %7B%0A            console.log('Something went wrong disbaling the debugger.')%3B%0A        %7D%0A        removeDialog()%3B%0A    %7D%0A%0A    if (document.getElementById('customDialog')) %7B%0A       %0A        return%3B%0A    %7D%0A    %2F%2F Create the dialog container%0A    var dialog %3D document.createElement('div')%3B%0A    dialog.id %3D 'customDialog'%3B%0A    dialog.style.position %3D 'fixed'%3B%0A    dialog.style.top %3D '20%25'%3B%0A    dialog.style.left %3D '50%25'%3B%0A    dialog.style.transform %3D 'translate(-50%25%2C -50%25)'%3B%0A    dialog.style.backgroundColor %3D 'white'%3B%0A    dialog.style.padding %3D '20px'%3B%0A    dialog.style.zIndex %3D 1000%3B%0A    dialog.style.borderRadius %3D '8px'%3B%0A    dialog.style.boxShadow %3D '0 4px 6px rgba(0%2C0%2C0%2C0.1)'%3B%0A    dialog.style.zIndex %3D 100000000%3B%0A    %2F%2F Add buttons to the dialog%0A    var buttonOne %3D document.createElement('button')%3B%0A    buttonOne.innerText %3D 'Pendo Debugger'%3B%0A    buttonOne.onclick %3D functionDebugger%3B%0A%0A    var buttonTwo %3D document.createElement('button')%3B%0A    buttonTwo.innerText %3D 'Pendo VDS'%3B%0A    buttonTwo.onclick %3D functionVDS%3B%0A%0A    var buttonThree %3D document.createElement('button')%3B%0A    buttonThree.innerText %3D 'Disable Debugger'%3B%0A    buttonThree.onclick %3D functionCloseDebugger%3B%0A%0A    %2F%2F Append buttons to dialog%0A    dialog.appendChild(buttonOne)%3B%0A    dialog.appendChild(document.createTextNode(' '))%3B %2F%2F Spacer%0A    dialog.appendChild(buttonTwo)%3B%0A    dialog.appendChild(document.createTextNode(' '))%3B %2F%2F Spacer%0A    dialog.appendChild(buttonThree)%3B%0A%0A    %2F%2F Append dialog to body%0A    document.body.appendChild(dialog)%3B%0A%7D)()%3B%7D)()%3B

```
vagrant boxを更新する手順（備忘録）

## vagrant boxを更新する方法
vagrant upすると以下のように「アップデートあるよ」って言ってくるのちょっとうざいので消したかった。（黄色いところ）
結構いろんな記事をみてbox updateのやり方はあったけど、その先までの情報（ダウンロードしてからどうするの？）があまりなかったので備忘録として残しておきます。

:::note warn
注意事項
・添付画像はbento/amazonlinux-2を使用しています。
・Vagrantfileがあるカレントディレクトリで行ってください。
・実行する場合は自己責任で行いましょう。当方は一切の責任を持ちません。
　※といってもvagrantなんで壊れても大丈夫。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56318/7582d585-d62d-8e3a-0f4f-8f61e11f0fa7.png)



### 簡易手順

1. vagrant box update --force
1. vagrant box list
1. vagrant box remove 消したいbox --box-version 消したいバージョン

おしまい。
ね、簡単でしょ。

ではエビデンス付きで残しておきます。

### ConEmu画面

①まず、はupdateコマンドを入れます。1

```shell:terminal
vagrant box update --force
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56318/dd28a316-2dae-014f-f64c-7e7b8fe50a93.png)

:::note info
これでアップデートOK
:::

②続いてダウンロードできたら既存のboxとダブっていることを確認します。

```shell:terminal
vagrant box list
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56318/7e344dad-8b29-e1c9-268a-41ac85b848f3.png)

:::note info
はい、2ついますね。
:::

③ここで古いboxを削除します。(↓のコマンドは例です。)

```shell:terminal
vagrant box remove bento/amazonlinux-2 --box-version 202305.26.0
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56318/b2595729-ffb3-6873-63cd-2cba7a956b0c.png)

:::note info
はい、消えました。では念のためlistを確認してみましょう。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56318/fd495ba3-8503-7318-7ef2-aed9c2e8727c.png)

:::note info
1つだけになりましたので、これで心置きなくvagrant upができます。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56318/092ab831-6572-13d5-6a77-be09ca5eac13.png)

:::note info
updateの警告文が出なくなり、最新バージョンで起動してくれました。
:::

## 参考記事

https://qiita.com/pyon_kiti_jp/items/02cec156e7bac0a138a1

https://qiita.com/one-kelvin/items/4b4fe9ffdd619fe0da6e

https://blog.amedama.jp/entry/2017/09/18/000114#google_vignette
ZXingをJetpack Composeで利用する

AndroidのXMLレイアウトをJetpack Composeに移行していて、QRコードリーダーのライブラリである`zxing-android-embedded`を使っている部分を移行することがありました。
しかしJetpack Composeで使っている情報が少なかったので備忘として簡単に残しておきます。
# 実装
```Zxing.kt
@Composable
fun AdminClubMembershipScanScreen(navController: NavHostController) {
    val context = LocalContext.current
    val lifecycleOwner = LocalLifecycleOwner.current

    val compoundBarcodeView = remember {
        CompoundBarcodeView(context).apply {
            val capture = CaptureManager(context as Activity, this)
            capture.initializeFromIntent(context.intent, null)
            this.setStatusText("")
            capture.decode()
            // 読み取り枠部分のサイズ設定
            barcodeView.fromingRectSize = Size(300, 300)
            // 中央に表示される赤線を消す
            this.viewFinder.setLaserVisibility(false)
            // 枠外の背景の色を変更
            this.viewFinder.setMaskColor(color.zxing_viewfinder_mask)
            barcodeView.decodeContinuous(
                object : BarcodeCallback {
                    override fun barcodeResult(result: BarcodeResult?) {
                        // 読み取り成功した時の処理などを書く
                    }
                }
            )
        }
    }

    DisposableEffect(lifecycleOwner) {
        compoundView.resume()
        onDispose {
            // 読み取りストップ
            compoundBarcodeView.pause()
            compoundBarcodeView.barcodeView.stopDecoding()
        }
    }

    AndroidView(
        modifier = Modifier,
        factory = {
            compoundBarcodeView 
        },
    )
}
```
何かしらカスタムしたい場合は、とりあえずCompoundBarcodeViewを作ってそこから内部構造を追っていけば見つかると思います。
まあ今は[Google Code Scanner API](https://developers.google.com/ml-kit/vision/barcode-scanning/code-scanner?hl=ja)や[ML Kit](https://firebase.google.com/docs/ml-kit/android/read-barcodes?hl=ja)を使う方が主流なのでしょうかねー

### 参考
[Stack Overflow](https://stackoverflow.com/questions/68139363/using-zxing-library-with-jetpack-compose)
Python で QR コードを簡単に作成する

# やりたいこと
外部向けの発表資料を作成している際、聞いてもらう方にリンクを QR コードで読み込めるようにしたいなと思い、QR コードを作成してくれるサービスを検索してみたものの変な広告とか挟まるのが多くてちょっとなぁ…と。さくっと作れないものかと調べてさくっと作れたので記事にしてみます。

※ QR コードは (株) デンソーウェーブの登録商標です。

# 結論
- Python でさくっと作成できる
    - 他の言語でもできると思うが、Python でしか試していない

# 詳細
極めて単純。

## requirements.txt
```
qrcode==7.4.2
```

## main
実行の度に URL を書き換えたくなかったので実行オプションで URL を指定するようにしているが、そうしない場合は、`main` の２行だけで OK。

```
import argparse
import qrcode


def main(url: str):
    img = qrcode.make(url)
    img.save('qr.png')

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--url', type=str, required=True)
    args = parser.parse_args()
    main(args.url)
```

# ということで
QR コードの作成を Python でやってみました。ここまで簡単だとは思っていなかったです笑
モジュール開発者の方には頭が上がりません。


以上です。
【Shell】特定の文字列を含むファイルのパスを出力する方法

以下のように記述することで特定の文字列を含むファイルのパスを出力できます。

```terminal
grep -l "検索対象の文字列" ファイルパス
```

```terminal
$ cat text.txt
sample
test
example

$ grep -l "sample" test.txt
test.txt
```
Docker 学習記録#3

バインドマウントとは
------------------------
* ホストマシンのファイルシステムへをコンテナ上からアクセスできるようにする

※ホストマシンにリソースがあることを前提とする

```
# イメージをpullする
$ docker pull httpd:2.4

# イメージ確認
$ docker images httpd:2.4
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
httpd        2.4       ac45b24b92cc   2 months ago   167MB

# 起動したコンテナにホストのリソースをバインドマウントする
$ docker run -d --rm --name my-apache-app -p 80:80 -v //c/tmp:/usr/local/apache2/htdocs/ httpd:2.4

# run イメージからコンテナを作成し、起動する
# --rm コンテナ終了後、コンテナのファイルシステムを削除する
# -d バックグラウンドで実行
# --name tag名指定,イメージ指定
#-v バインドマウントするパスを指定

#ステータス確認
$ docker ps
CONTAINER ID   IMAGE       COMMAND              CREATED          STATUS          PORTS                NAMES
7b2e12f9f4bd   httpd:2.4   "httpd-foreground"   13 minutes ago   Up 12 minutes   0.0.0.0:80->80/tcp   my-apache-app

# コンテンツの確認
$ curl http://localhost/
StatusCode        : 200
StatusDescription : OK
Content           : hip, hip array!
RawContent        : HTTP/1.1 200 OK
--snip--

# バインドマウントされているか確認
$ docker inspect -f '{{ json .Mounts }}' my-apache-app
```



https://docs.docker.jp/engine/reference/commandline/run.html
テストとは何か

:::note warn
この記事は筆者の学習のアウトプットです。
:::

## はじめに

テストをより適切に実施するために、書籍でテストを学ぶことにしました。
今回は「はじめて学ぶ　ソフトウェアのテスト技法（日経BP社）」を読みすすめて行きたいと思います。

## テストとは何か

IEEE 標準規格では、テストは以下のように定義されているそうです。

> ある特定の条件下でシステムまたはコンポーネントを操作するプロセスであり、その結果を観察まはた記録して、システムまたはコンポーネントのある側面を評価すること

## テストの成熟度

テストはその成熟度によって５つのレベルに分類されるそうです。

### レベル0

> テストとデバッグには何の差もない。デバッグ以外にはテストには特別な目的はない。

バグを検出するための努力はない、という状態

### レベル１

> テストの目的は、ソフトウェアが動くことを示すことである。

動くことを示すためのテストなので、失敗するであろうテストケースは作成しない。

### レベル２

> テストの目的は、ソフトウェアが動かないということを示すことである。

レベル１とは反対の姿勢。積極的に欠陥を探す。
担当者は重箱の角をつつくような厳しいテストケースを作成する。

### レベル３

> テストの目的は、何かを証明することではなく、プログラムが動かないことによって発生する危険性をある許容範囲まで減らすことである。

システムが完璧であることの証明はほぼ不可能であることを認識した上で、テストを実施することでどれだけシステムが不完全であるかを提供し、それによる損害を測定する。

### レベル4

> テストは行動ではない。大げさなテストをすることなく品質の高いソフトウェアを作るための精神的な規律である。

このレベルでは、テスト容易性の高いソフトウェア開発に重点が置かれる。テスト担当者が検出しなくとも、自らエラーレポートを行うようなコードを書くことまで意味する。

## すべてをテストすることはできない

C言語で一つのint型の整数を引数に受け取るシンプルな関数を作成したとして、intが4バイトの場合、引数の取りうる値は`-2147483648 ~ 2147483647`となってしまう。

上記のシンプルな関数だけでも、すべて試すには大きなコストがかかってしまうので、テストは少ないコストで最大限エラーの検出率を高められるような設計をしなくてはならない。

## まとめ

この本を読むまでは、テストはエラーを見つけるためのものだと思っていたので、私のテスト成熟度はレベル２だったようです。
しかし、先人の方々の教えで、まずもってのテストの考え方を修正することが出来ました。
今後は更にテスト技法に親しんで、効果的かつ効率的なテストを実施できるようにしていきたいです。

## 参考書籍

https://bookplus.nikkei.com/atcl/catalog/05/P82510/
チャットだけじゃない生成AIのインターフェース（IBM watsonx.ai）

# はじめに
生成AIのインターフェースといえば、ChatGPTのようなチャットUIか、API呼び出しがメインかなと思いますが、他にもユースケースに合わせたインターフェースがどんどん出てきてる気がします。
例えば、IBMの生成AIプラットフォームのwatsonx.aiでは、チャットインターフェースも含めて3つのインターフェースがあります。ここでは、簡単にその3つを紹介したいと思います。

# チャットインターフェース
チャットインターフェースはこんな感じです。ChatGPT等、よくあるインターフェースです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184221/4d874bf1-4b76-52ba-07b8-ab5fa9d46163.png)

# 構造化インターフェース
構造化された指示を出すときは、こんなインターフェースもあります。
「命令」と「例」の「入力」・「出力」と「試行」の「入力」を記入して結果を取得します。
いわゆるfew-shotとして、例を渡すことで精度が上がります。
また、複数の入力を入れることで、並列に結果を取得することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184221/c2ca37da-84a1-e19e-8aa5-b1655748f3ae.png)

# フリー・フォーム
最後は、フリーフォームということで、エディタのような画面で、プロンプトを記載し、プロンプトに続けて結果が記載されます。生成後、生成結果が編集可能な状態になって、さらに「生成」することも可能です。自由度が高いです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184221/f5a075c2-55f1-d45d-f866-d9b7bc9cdf8e.png)

# おわりに
あっさりですが、チャットインターフェースを含む3つのインターフェースを紹介しました。
生成AIといえばチャットインターフェースではありますが、状況に応じて違うインターフェースを選択することで、より生成AIを活用できると思います。
【SATySFi】SATySFiで色を変えるコマンドを自作してみる

# 概要
最近SATySFi(TeXなどの組版ソフトの1種)を使う練習を始めたのでその一環としてコマンド定義をしていたが，色とテキストを指定できるコマンド `\color` を作るときに躓いたため記録しておきます．

# 実際のソース(例)

```test.saty
@require: stdjareport

% ここが本質 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
let-inline ctx \color newcolor it =
	let ctx-color = ctx |> set-text-color newcolor in 
	read-inline ctx-color it
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


let mycolor = Color.blue in

document
(|
	title = {};
	author = {};
|)
'<
	+p
	{
		ここはテキストです．
		ここは\color(Color.red){赤色テキスト}です．
		ここは\color(mycolor){私の色(今は青)テキスト}です．
	}
>
```

コンパイルするとこんな感じに↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3559085/84143143-31c1-f5b0-8ad4-106fbdcf66c8.png)

# 躓いたところ
### 引数の渡し方(型への理解不足)
コマンドを呼び出す際に，SATySFiでは`{テキスト}`は文字列(コマンドにするには+pのようにする？)となり，例えば`Color.red`も単なる"Color.red"という文字列になって渡されるようです(リファレンスを読めばちゃんと書いてあると思います)．
そして，変数を変数として渡すためには`(へんすう)`という形で渡す必要があるみたいです．
```
\color{Color.red}{赤色テキスト} %これだと引数は [inline-text ; inline-text] となってエラー
\color(Color.red){赤色テキスト} %これなら引数は [color ; inline-text] となっていいかんじ
```

### 引数の順番
(そのときの書き方が悪かったのかもしれませんが、)
```
let-inline ctx \color newcolor it
```

ここの引数`newcolor`と`it`の順番を入れ替えて
```
let-inline ctx \color it newcolor
```

にし，呼び出し側は
```
\color{赤色テキスト}(Color.red)
```

というようにしたところ，なぜだかうまく動作してくれませんでした(´･ω･`)

# 補足
### 筆者の環境
WLSのUbuntuをVSCodeから開いてコンパイルしています．
(参考: [SATySFi を windows 10 で VSCode 上で使ってみる](https://qiita.com/nhancoromochi/items/274a02601bb0ba06c45b))
基本情報処理　データベース３　データの正規化

https://www.youtube.com/watch?v=dDJ9rAfXgds
## 本日の内容
本日はデータベース基本情報処理について触れていきます。データベースの第3回では、データの正規化に焦点を当てています。まずは、第1世紀化、第2世紀化、第3世紀化の基礎について触れます。これからデータベースの基本情報処理を学ぶ人を対象にしています。
## なぜデータを正規化するの？
まず、なぜデータの正規化を行うのかを考えてみましょう。例えば、受伝票が来たとします。伝票には番号や日付、顧客名などがあります。それぞれの項目に対して、カメラやパソコンの注文が含まれている受注伝票があったとします。これらをデータ化する際、表を作成すると、データの長さが不均一になりがちです。このため、データの正規化が必要になります。
## 第1正規化
データの正規化を行う際には、繰り返しの部分を切り離して繋げていく作業が行われます。例えば、カメラとパソコンの部分を分けて、重複する部分を削除して表を整えます。これにより、表の形を綺麗に保ちながらデータを整理することができます。この作業を第1正規化と呼びます。これにより、表のレコードの長さを一定に保つことができます。
## 第2正規化

第1正規化だけではまだ見づらい部分が残っています。そこで、第2世紀化が行われます。第2世紀化では、式を構成している部分を別の表に移します。これにより、受注ナンバーや商品コードから他の情報が推測できるようになります。
## 第3正規化
第3世紀化では、主以外の項目によって決定される部分を別の表に分割します。これにより、より効率的にデータを管理することができます。このように、データの正規化を行うことで、データベースの管理や処理をより効率的に行うことができます。
YouTube解説のマスターを作るベースを作ってみた。

作ってみた。解説画面の元になるパターンとscript。

mp4の動画はサンプル動画。動画に重ねてイメージと、textを出せるかが、今回の試み。

なお、重ね枚数、textのJavascriptはこれには、組み込まれていません。

![Animation_kaisetu.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3625232/89b717a5-377c-9245-b34c-325d53babbaf.gif)

![スクリーンショット 2024-03-22 222550.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3625232/15f5bd08-702f-6af8-ef64-a5f8c3e49106.png)

```html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<LINK rel="SHORTCUT ICON" href="img/name.ico">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <meta name="description" content="たっちゃん,studio。">
<title>my_test</title>
<link rel="stylesheet" href="my_test.css" type="text/css">
</head>
<body>
<!-- stato -->


<span id="box01">
<table><tr><td id="my1td1"></td><td></td><td>0000</td></tr>
<tr><td></td><td id="my1td4"><figure><figcaption>Go Go Unatyan!!</figcaption>
<video controls src="imge/una00.mp4" width="640" autoplay muted="false">
</video></figure></td><td></td><tr></table></span>

<span id="box02">
<table><tr><td id="my2td1"></td><td></td></tr>
<tr><td></td><td><span id="myt2_1"><img src="imge/gall.png" width="128" height="128"></span></td></tr></table>
</span>

<span id="box03">
<table><tr><td id="my3td1"></td><td></td></tr>
<tr><td></td><td><span id="myt3_1"><img src="imge/man1.png" width="128" height="128"></span></td></tr></table>
</span>

<span id="box04">
<table><tr><td id="my4td1"></td><td></td></tr><tr><td></td><td>
<span id="myt4_1"><font size="6"><b>テキスト</b>を<font color="#f00"><b>変</b>え</font>られる。</font></span>
</td></tr></table></span>  


<div id="test_my0">test0</div>
<br><br><br><br><br>
<br><br><br><br><br>
<br><br><br><br><br>
<br><br><br><br><br>
<br><br><br><br><br>
<br><br><br><br><br>
<div id="test_my1">test1</div>

<!-- end -->
</body>
</html>
```

CSS

```css
@charset "UTF-8";
/* ver. 1_00(test) */

body { 
  margin: 1cm;
  background:#00bbff;
}

#test_my0 {
	color: red;
}


#box01 { 
  background-color: #1995ee; 
  position: fixed; 
  top: 0;/* タグによる位置の既定の位置に配置無視 */
  left: 0;/* 無視 */
  /*width: 64px; 
  height: 64px;*/ 
} 

#my1td1 {
	width: 128;
	height: 128;
}

#box02 { 
  /*background-color: #ff6a00;*/ 
  position: fixed;
  top: 0;/* タグによる位置の 相対位置に配置既定の位置 */
  left: 0;/* 既定の位置 */
  /*width: 64px; 
  height: 64px;*/ 
} 

#my2td1 {
	width: 60px;
	height: 280px;
}

#box03 { 
 /* background-color: #ffd800; */
  position: absolute;
  top: 0;/* タグによる位置の 絶対座標の位置 スクロール*/
  left: 0;/* スクロール */
  /*width: 64px; 
  height: 64px; */
} 

#my3td1 {
	width: 550px;
	height: 280px;
}

#box04 { 
 /* background-color: #26b138;*/ 
  position: fixed ;
  top: 0;/* タグによる位置の 絶対座標の位置 同じ位置*/
  left: 0;/* 同じ位置 */
 /* width: 58px; 
  height: 58px; */
} 
 #my4td1 {
	width: 200px;
	height: 350px;
}

#test_my1 {
	 color: red;
}

```
手抜きや。機能試験言うやつ。自由にお使いください。
kotomamba-2.8B-v1.0は『雪国』の続きをどう生成するのか

transformers 4.39.0が[mambaをサポートした](https://github.com/huggingface/transformers/issues/28086)ので、[kotomamba-2.8B-v1.0](https://huggingface.co/kotoba-tech/kotomamba-2.8B-v1.0)をtransformersで動かしてみた。

```
#! /usr/bin/python3
from transformers import LlamaTokenizerFast,MambaConfig,MambaForCausalLM,TextGenerationPipeline
from transformers.utils import cached_file
tkz=LlamaTokenizerFast(vocab_file=cached_file("kotoba-tech/kotomamba-2.8B-v1.0","tokenizer.model"),add_bos_token=False,pad_token="<pad>")
cfg=MambaConfig.from_pretrained("kotoba-tech/kotomamba-2.8B-v1.0",hidden_size=2560,intermediate_size=5120,num_hidden_layers=64,time_step_rank=160,vocab_size=96872,bos_token_id=1,eos_token_id=2,pad_token_id=4)
mdl=MambaForCausalLM.from_pretrained("kotoba-tech/kotomamba-2.8B-v1.0",config=cfg)
mdl.resize_token_embeddings(len(tkz))
tgn=TextGenerationPipeline(model=mdl,tokenizer=tkz,max_new_tokens=128)
nlp=lambda txt:tgn(txt)[0]["generated_text"]
print(nlp("国境の長いトンネルを抜けると雪国であった。夜の底が白くなった。"))
```

MambaConfigの値に無理矢理感がある上に、LlamaTokenizerFastを借りていたりするし、その結果、トークナイザの単語数とモデルのtoken_embeddingsが合わなくなってしまって、resize_token_embeddingsとか恐ろしいことをしている。何とか『雪国』冒頭部の続きを生成させてみたところ、私(安岡孝一)の手元では以下の結果が出力された。

> 国境の長いトンネルを抜けると雪国であった。夜の底が白くなった。信号所に汽車が止まった。
> \- 1945年8月15日、終戦の日。
> \- 1945年8月15日、終戦の日。
> \- 1945年8月15日、終戦の日。
> \- 1945年8月15日、終戦の日。
> \- 1945年8月15日、終戦の日。
> \- 1945年8月15日、終戦の日。
> \- 19

「信号所に汽車が止まった。」が生成されているので、kotomamba-2.8B-v1.0は、この一節を知っているらしい。どうしてそれが「終戦の日」に繫がるのかは謎だが、そういうものなのだろう。さて、どういう形で継続学習させたらいいかな。
RaspberryPiにWifiAPとEthernetを設定 nmcli無し

参考
https://www.mikan-tech.net/entry/raspi-wifi-ap
https://raspida.com/rpi-wifi-ap
### wlan0用DHCPServerを追加
```
sudo apt -y install dnsmasq
```
wlan0のDHCP割り振りアドレス範囲を設定
```
$ sudo vi /etc/dnsmasq.conf
長いので省略
以下を末尾に追加
interface=wlan0
dhcp-range=192.168.249.50,192.168.249.150,255.255.255.0,12h
$ sudo systemctl restart dnsmasq
```
### wlan0用アクセスポイントを追加
```
sudo apt -y install hostapd
```
dhcpcdが稼働しないのでdhcpcd.confを使わない
```
$ sudo vi /etc/dhcpcd.conf
新規作成
# denyinterfaces wlan0
# interface wlan0
# static ip_address=192.168.249.1/24
# nohook wpa_supplicant
```
アクセスポイントの条件を設定
```
$ sudo vi /etc/hostapd/hostapd.conf
新規作成
interface=wlan0
driver=nl80211
hw_mode=g
country_code=JP
# channel=3
wpa=2
wpa_key_mgmt=WPA-PSK
rsn_pairwise=CCMP
ssid=RPiAP
wpa_passphrase=1234567890123456
```
参考 https://qiita.com/JhonnyBravo/items/5df2d9b2fcb142b6a67c
アクセスポイント設定を有効に
```
$ sudo vi /etc/default/hostapd
以下を有効に
#DAEMON_CONF=""
DAEMON_CONF="/etc/hostapd/hostapd.conf"
```
これは無変更みたい wpa_supplicant.conf
```
$ sudo vi /etc/wpa_supplicant/wpa_supplicant.conf
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
以下を末尾に追加
# country=JP
```
wlan0のIPアドレスを設定
```
$ sudo vi /etc/network/interfaces
# interfaces(5) file used by ifup(8) and ifdown(8)
# Include files from /etc/network/interfaces.d:
source /etc/network/interfaces.d/*
以下を末尾に追加
allow-hotplug wlan0
iface wlan0 inet static
address 192.168.249.1
netmask 255.255.255.0
```
```
sudo systemctl unmask hostapd
sudo systemctl enable hostapd
sudo systemctl start hostapd
```
### Ethernetの静的アドレスを設定
ぐぐると/etc/dhcpcd.confで設定とあるが駄目で、 /etc/network/interfacesを使用
「DHCPCD is not installed on bookworm」https://www.reddit.com/r/raspberry_pi/comments/17l10wr/how_to_set_static_ip_on_raspberry_pi_4b_64bit_lite/
```
$ sudo vi /etc/network/interfaces
以下を末尾に追加
auto eth0
iface eth0 inet static
address 192.168.213.80
netmask 255.255.255.0
auto eth1
iface eth1 inet static
address 192.168.13.80
netmask 255.255.255.0
```
dhcpcdが稼働しないのでdhcpcd.confを使わない
```
$ sudo vi /etc/dhcpcd.conf
以下を末尾に追加
# interface eth0
# static ip_address=192.168.213.80/24
# interface eth1
# static ip_address=192.168.13.80/24
```
### 備忘録
ブリッジ化
https://kassyjp.ninja-web.net/ras/jessie/bridge.htm
hostapd_cliコマンド
https://www.macnica.co.jp/business/semiconductor/articles/qualcomm/142745/
robocopy にUTF-8のログを出力させる

結論から書くとこうです。

以下のファイルを作成し、このバッチファイル自体も文字コードを`UTF-8`で保存します。

```backup.bat
chcp 65001 > NUL
rem "実行します"
pause
robocopy "C:\Users\user1\Desktop\moge" "D:\hoge\moge" /copy:DAT /DCOPY:DAT /NP /MIR /FFT /R:3 /W:3 /UNILOG:NUL /TEE >> C:\Users\user1\Desktop\bk%time:~3,2%.txt
```

・バッチファイル自体を保存する時の UTF-8 はBOMは、有り・無しどちらでも行けそう

・ユーザー名:`user1`のデスクトップに`bk00.txt` が生成されます(数字は、現在時刻の"分"が2桁で入る)

・オプションはお好みで変えてください。このオプションでは、バックアップ処理を想定しており、コピー元を基準として、コピー先にミラーリングされます (ミラーリングなのでコピー先にしか無いファイルは削除される)。また、出来るだけファイル属性を維持します。

・robocopy 自身はcp65001で動くので、英語出力になる。またログファイル内でのログ出力先表記も`Log File : \\.\NUL`になってしまうのであしからず。

・バッチファイル自体を ShiftJIS で保存すると、 rem 行から既に文字化けします。`chcp 65001`をした直後から、バッチファイルの読み込み自体もUTF-8になるようです。`chcp 65001`自体はASCIIコードなので文字コード依存が無く、そのまま読める。

・こちらの方がまとめられているように、 robocopy のUTF出力回りはカオスなようで、回避可能なコマンド`/UNILOG:NUL /TEE >`を使っています (`/UNILOG`は機能するけど`/UNILOG+`はダメってどうなってるのよ・・・。しかもNULなら+付けても良いって何それ・・・。なお、このサイトによると、UTF-16も工夫すれば行けそうです。)

https://n-archives.net/software/robosync/articles/robocopy-unicode-unilog-log/#google_vignette

・`chcp 65001 > NUL`は単に画面出力を捨てているだけです。`chcp 65001`だけでも動作はOK
Windows11Home(Ver.23H2)で日本語配列と英語配列のキーボードを共存させる設定

# 最初に
　作業用に日本語配列、ゲーム用に英語配列のキーボード使用した際の切り替えに不便さを感じ、共存させることはできないかと調べ実施した結果を共有します。
　実施の際は、自己責任でお願いいたします。

# 環境
・Windows11Home(Ver.23H2)
・キーボードレイアウトは日本語キーボード(日本語配列)に設定している状態
・Logicoolの日本語配列キーボード(有線)
・Duckyの英語配列キーボード(有線)

# 変更対象
・レジストリ　**※変更する前にバックアップをとる**

# 手順
### １．英語配列に設定するキーボードのデバイスインスタンスパスを調べる
##### ①スタートメニューの検索等から、デバイスマネージャーを開く
![デバイス マネージャー 2024_03_22 21_14_52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3753378/0c24a1b6-6789-5aee-83a9-f7a6aa7d97e6.png)
##### ②キーボードを開く
![デバイス マネージャー 2024_03_22 21_18_14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3753378/aebb4ce1-fec6-2b62-e320-d2e928714185.png)
##### ③複数ある「HIDキーボードデバイス」の中から、英語配列に設定するキーボードを探す
　キーボードのコードを抜き差しすることで、増減する「HIDキーボードデバイス」があるので、そこから特定します。
##### ④該当する「HIDキーボードデバイス」のプロパティを開き、詳細タブのプロパティで「デバイスインスタンスパス」を選択し、表示されたパスをコピーしておく
![フォト 2024_03_22 21_33_13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3753378/8b72478d-5b46-292f-3ea6-9a71b3b9f5cb.png)

### ２．レジストリを変更する
##### ①スタートメニューの検索等から、レジストリエディターを開く
![レジストリ エディター 2024_03_22 21_40_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3753378/9bf4c99e-78cb-4aa5-9f38-108c7bfed913.png)
##### ②デフォルト設定を削除する
　以下パスのレジストリを開くと、キーボードのデフォルト設定を確認できます。
 **ｺﾝﾋﾟｭｰﾀｰ¥HKEY_LOCAL_MACHINE¥SYSTEM¥CurrentControlSet¥Services¥i8042prt¥Parameters**
 
 このレジストリの以下のキーを削除します。
 ・OverrideKeyboardSubtype
 ・OverrideKeyboardType
 ![レジストリ エディター 2024_03_22 21_55_23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3753378/6790c217-2603-4ca9-1515-adbe51597dfb.png)
　※心配な方は、ここで一度再起動をして日本語配列でキーボードが使えるか確認してもよいかもしれません。
##### ③英語配列の設定を追加する
　以下パスのレジストリを開くと、英語配列に設定するキーボードの設定を確認できます。
 　ｺﾝﾋﾟｭｰﾀｰ¥HKEY_LOCAL_MACHINE¥SYSTEM¥CurrentControlSet¥Enum
  　　　　¥**１でコピーしたデバイスインスタンスパス**¥Device Parameters

　 (例)ｺﾝﾋﾟｭｰﾀｰ¥HKEY_LOCAL_MACHINE¥SYSTEM¥CurrentControlSet¥Enum
  　　　　¥HID¥VID_046D&PID_C53A&MI00¥7&271F0B7A&0&0000¥Device Parameters
 
　このレジストリに以下２つのDWORDを追加します。
 　・名前：KeyboardSubtypeOverride
  　　種類：REG_DWORD
    　　データ：0
      　・名前：KeyboardTypeOverride
       　　種類：REG_DWORD
         　　データ：4
![レジストリ エディター 2024_03_22 22_11_54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3753378/1e91333d-b482-90e3-644b-a444dcb08be2.png)
### ３．再起動して動作確認する
　再起動後、日本語配列、英語配列それぞれのキーボードが動作するか確認して完了です。
 
　ちなみに、追加したDWORDの「データ」を以下の値に変更すると日本語配列にすることができます。
　 ・名前：KeyboardSubtypeOverride
　 　種類：REG_DWORD
　  　**データ：2**
　・名前：KeyboardTypeOverride
　　種類：REG_DWORD
　 　**データ：7**
  
# 最後に
　日本語配列のキーボードがフルサイズのためゲームではかなり使いにくく、英語配列の60%サイズのキーボードが使えるようになって快適度が増しました。
　無線では使用していないため、設定内容がもしかしたら少し変わるかもしれません。
その際は、以下参考サイトも確認していただければと思います。


# 参考サイト
「Windows 11 で 2 つのキーボード配列を使う」
[https://zenn.dev/microsoft/articles/two-keylayout-windows11](https://zenn.dev/microsoft/articles/two-keylayout-windows11)

「Windows10 21H2で英語配列のBluetoothキーボードを追加して日本語キーボードと共存させる設定」
[https://qiita.com/e4rfx/items/3f9a5b884209aced37b5](https://qiita.com/e4rfx/items/3f9a5b884209aced37b5)
rex0220 算式自動採番プラグイン 枝番セット

[算式自動採番プラグイン](https://qiita.com/rex0220/items/2e40a57d2d08023affde)と[計算式プラグイン](https://qiita.com/rex0220/items/ae83c6d5ce50ff7a9a73)で、枝番処理を行います。

# 概要

レコード複製時に、枝番をセットします。
[算式自動採番プラグイン](https://qiita.com/rex0220/items/2e40a57d2d08023affde)と[計算式プラグイン](https://qiita.com/rex0220/items/ae83c6d5ce50ff7a9a73)で、枝番処理を行います。

![2024-03-22_22h33_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/79debc3b-5a85-6561-b17b-6259a03784f9.png)


![2024-03-22_22h41_30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/948f3508-b57d-899d-c836-290c4fc716e7.png)

# アプリ構成

枝番制御用に、元案件管理番号を追加します。

![2024-03-22_22h37_10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/a6c860c4-164a-9bcd-6066-7bb4bf29bb8a.png)

# 算式自動採番プラグイン設定

元案件管理番号がセットされている場合、枝番を採番します。

![2024-03-22_22h40_26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/86af293c-a26d-ba93-91dc-694bce071589.png)

```.js
IF(元案件管理番号,
  元案件管理番号&"-@@",
  "AB"&年&"@@@@"
)
```

# 計算式プラグイン設定

案件管理番号がある場合、元案件管理番号にセット
レコード複製時は、元案件管理番号をそのまま保持します。

![2024-03-22_22h39_06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/19e4b302-596d-a704-afcc-6dadfce8012e.png)

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

// 元案件管理番号 SINGLE_LINE_TEXT
IFS(元案件管理番号,元案件管理番号,
  AND(更新日時,連番),案件管理番号
)
```
Reactでsupabaseのデータを引用する際に画面が真っ白に...

# 初めに
今回はReactでsupabase上のデータを引用する際に、意図せず画面が真っ白になってしまいました...
その原因と解決方法を自分なりに結論づけることができたので報告します！

# 問題のコード
```react
const [todos, setTodos] = useState<any>([]);
```

# 解決した際のコード
```react
const [todos, setTodos] = useState([]);
```

# anyとは？
今回はsupabaseを初めて利用したため、参考としていた動画のコードをそのまま記述していました。
そのため`<any>`もそのまま記述していたのですが、これはTypescriptでしか使用できないそうです。
`<any>`についてchatGPTに聞いてみました。

>`useState<any>()`は、ReactのuseStateフックを使う際にTypeScriptのジェネリクス構文を使用している例です。ここでの`<any>`は、このステートがどのような型の値も保持できることを示しています。TypeScriptのany型は、あらゆる型の値を許容する特別な型であり、型チェックを事実上無効にします。
>`useState<any>()`とすることで、そのステートにどのような型の値もセットできるようになります。これは柔軟性が高い反面、型安全性が低下するため、必要な場合にのみany型を使用し、可能な限り具体的な型を指定するように心がけると良いでしょう。

つまりTypescriptでしか使えないことに加えて、安全性も下がってしまうため、赤る限り使わない方が良さそうです！

# 終わりに
初めてsupabaseデータを引用してみましたが、早速沼にハマってしまいました...
まだまだこれからも沼にハマると思うので、chatGPTや先輩に頼るなどして乗り越えていきます！！
Build Tools for Visual Studio 2022 導入

## ビルドツールとは
ビルドツールとは、ソフトウェア開発で実行ファイルや配布パッケージを作成するビルド工程を自動化、効率化するソフトウェア。
ビルド時に必要になるコンパイラやリンカなどの開発ツールの機能の呼び出し、OSコマンドの実行などの手順をスクリプトファイルや設定ファイルの形で記述することで、ビルドツールがそれを読み込み、自動的に実施することができる。

## Visual Studio とは
Visual Studio とは、統合開発環境である。
コードの記述や編集、デバッグ、ビルドやデプロイなどの、アプリケーション開発に必要な必要なさまざまな機能を一つにまとめたソフトウェアを、統合開発環境と呼ぶ。

## Build Tools for Visual Studio 2022 インストール手順
### インストーラをダウンロードする
下記の URL にアクセス

https://visualstudio.microsoft.com/ja/vs/community/


ダウンロードをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3749137/fbe0a803-0302-c5ec-3c89-c467f8ea2b1a.png)


### インストーラを実行してインストールする
ダウンロードしたインストーラを実行する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3749137/f5232688-2c2a-1f65-e2cd-83b4cf9a79cd.png)

続行をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3749137/f9e2eeb9-2dbf-cf6f-5a33-0e539d97ba3d.png)

C++ によるデスクトップ開発 にチェックを入れた後、
ATL と MFC にチェックを入れてインストールをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3749137/74587f01-3330-083f-d864-26fff8a360cd.png)

OK をクリックしてインストール完了
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3749137/5d8e8aee-a075-9b22-b85b-8731af556e85.png)

## x64 Native Tools Command Prompt for VS 2022 の動作確認
スタートメニューから x64 Native Tools Command Prompt for VS 2022 を起動する
(検索すれば出る)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3749137/faf9f62e-4133-77d7-c08e-acecffaa2d98.png)

以下のコマンドラインを実行し、cl にパスが通っていることを確認する
```
where cl
```
エラーメッセージが出なければ OK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3749137/1a785832-0a4c-d021-15c2-0ad5d887fae7.png)

## C プログラムをコンパイルする
x64 Native Tools Command Prompt for VS 2022 を起動する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3749137/faf9f62e-4133-77d7-c08e-acecffaa2d98.png)

以下のソースコードを、任意のディレクトリに HelloWorld.c として保存する
```
#include <stdio.h>
int main( void ){
    printf( "Hello World!\n" );
    return 0;
}
```

x64 Native Tools Command Prompt for VS 2022 上で、以下のコマンドラインを実行する
```
c:
cd [HelloWorld.c を保存したディレクトリパス]
cl HelloWorld.c
.\HelloWorld.exe
```

"Hello World!" と表示されれば OK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3749137/109c6900-6a3c-ce0f-f80f-2f9a2bef80dc.png)
【初心者】fillメソッドの使い方

## fillメソッドとは

### fill()メソッドがわからなかったので使い方の備忘録。

以下のように、```new Array(9)```とすると、空の値が９つ入った配列が作成される。

```
  const arr = [1,2,3,4,4,5,6,6,7];
  const a = new Array(9);
```

それにfill()メソッドで数字を入れることができる。

```  
  a.fill(1);
  console.log(a);//出力結果→ (9) [1, 1, 1, 1, 1, 1, 1, 1, 1]
```  

第一引数に入れたい数字、第二引数に開始位置、第三引数に終了位置をかく更新方法もある。

```  
  a.fill(2, 3, 6);
  console.log(a);//出力結果→ (9) [1, 1, 1, 2, 2, 2, 1, 1, 1]  

  ```
これからはJavaScript勉強しよう 2回目 3回目

お題はここから

https://fadotech.com/quiz-javascript/


```html
<!DOCTYPE html>
<html lang="ja">
<script>


zzz = [100,500,"aiueo",1000,"JavaScript",3000,"プログラミング"]

for ( i = 0; i < zzz.length; i++) {

    if(isNaN(zzz[i])) {

        console.log(zzz[i]);

    } else {

    }   

}

    


</script>
</html>
```



```html
<!DOCTYPE html>
<html lang="ja">

  <button id="btn">変化</button>

<script>
   const btn = document.getElementById('btn');
   btn.addEventListener('click', () => {btn.textContent = '押されました';})
</script>
</html>
```

mouseoverした版

```html
<!DOCTYPE html>
<html lang="ja">

  <button id="btn">変化</button>

<script>

const btn = document.getElementById('btn');
  btn.addEventListener('mouseover', () => {btn.textContent = '押されました';})

</script>
</html>
```
Docker



# Dockerのコンテナとは

Linuxのコンテナ技術を使ったもの

もともとサーバーは手動でインストールしていたし、同じサーバーを構築するのが難しかった
できることは実行したコマンドをメモしておくくらいだった

**Dockerがあることでサーバーの情報をコード化することができた**

メリット
・サーバーの情報がわかる
・誰でも同じサーバーが立ち上がる
・誰でもサーバーが立てられる
・テキストファイルなので共有しやすい

ホストマシンのカーネル（OSの中核部分でハードウェアとアプリケーションソフトうケアの間で仲介する役割）を利用し、プロセスやユーザなどを隔離することで、あたかも別のマシンが動いているかのように動かすことができる	

ミドルウェアのインストールや各種環境設定をコード化して管理	

# コンテナってどんなもの	

コンテナ型には仮想マシンやゲストＯＳはない
その代わりにコンテナがある
仮想化ソフトウェアとしてコンテナエンジンをインストールして、コンテナという容器を作る

# Dockerでできること
1台のサーバー上に複数のアプリケーション実行環境（Dockerコンテナ）を作成・利用できる

アプリケーション実行環境（Dockerコンテナ）の他サーバーなどへの移転、他ユーザーとの共有※Dockerコンテナの移転や共有は複雑で手間のかかる操作を必要とせず、簡単に実行可能
Dockerコンテナでアプリケーションの開発環境を作成し、インターネット上で他エンジニアと簡単に共有できる
従来の仮想化では仮想マシンごとに1つのゲストOSをインストールして、あたかも1台の独立したサーバーのように利用していた

DockerではホストOSのカーネルを共有して利用することで、従来の仮想化と違いゲストOSを必要としない
その分だけDockerの動作は軽くなる

従来の仮想化では、仮想マシンはOSを起動する必要があった
→仮想マシンの作成から起動まで数分程度の時間がかかった
Dockerのコンテナ型仮想環境は、数秒で起動できる

# DockerImageとは
Dockerコンテナの実行に必要なすべてのコンポーネント、ソフトウェア、ライブラリ、設定などを含むパッケージ
→複数の環境で同じ状態のコンテナを再現するために使用


# Docker Fileとは	
Dockerコンテナをビルドするためのテキストファイル
→コンテナをビルドするための設計書
　Docker Imageをコード化したもの
読めばインフラ構造がわかる
自分の用途に合わせてカスタマイズもできる
同じDocker Fileからは必ず同じコンテナが起動する

# Docker Composeとは
yamlファイルという設計図で複数のコンテナをまとめて管理できるツール
コマンド一つで複数の環境を立ち上げることができる

相対パスで書くことが多い
絶対パスで書くと、ユーザー名を変更したりする必要が出てくるからできるだけ相対パスで書く
Flake8でファイルの最大行を統制する方法がなかったのでプラグインを作ってみた

ESLintにはファイルの最大行を設定することができる。

https://eslint.org/docs/latest/rules/max-lines

Flake8にはない！！！
頑張って探してもなかった。だから作った。
Pythonは何もしないとコード肥大化しがち。こういうの使って減らしていかないと。

https://github.com/misogihagi/flake8-max-lines

## 使い方

他のFlake8プラグインのように使える。

```console
pip install flake8 flake8_max_lines
flake8 {任意のpythonファイル}
```

`--max-lines`で最大行を変えることができる。
デフォルトはESLintにあわせて300。

```
flake8 --max-lines 500 {任意のpythonファイル}
```


import ast
from typing import Generator, List, Tuple

MSG = "MXL001 File has too many lines ({actual}). Maximum allowed is {max}."
DEFAULT_MAX_LINES = 300


## 作ってみて感じたこと

Flake8のプラグインを作るにはクラスを作ってsetup.pyに渡してあげればいい。

そのクラスに色々実装してあげるだけで良さそう。
`__init__`と`run`メソッドは必須で、`--max-lines`みたいな引数を渡してあげたいときは`add_options`や`parse_options`をクラスメソッドとして実装すれば良さそう。
オプションのところはここを見れば良さそう。

https://flake8.pycqa.org/en/latest/internal/option_handling.html

情報が少なすぎるので[あちこちの取り組みを参考](https://github.com/DmytroLitvinov/awesome-flake8-extensions)。

```python:flake8_max_lines.py
class MaxLinesPlugin:
    name = "flake8_max_lines"
    version = "0.0.2"


    @classmethod
    def add_options(cls, option_manager):
        option_manager.add_option(
            "--max-lines",
            type=int,
            metavar="n",
            default=DEFAULT_MAX_LINES,
            parse_from_config=True,
            help="enforces a maximum number of lines in a file"
            "For example, ``--max-lines=500``. (Default: %(DEFAULT_MAX_LINES))"
        )

    @classmethod
    def parse_options(cls, options):
        cls.max_lines = options.max_lines

    def __init__(self, lines: List[str], total_lines: int, tree: ast.AST):
        self.lines = lines
        self.total_lines = total_lines

    def get_file_length(self) -> int:
        # [this logic to check newline at end of file](./test_plugin.py#L27)

        physical_line = self.lines[-1]
        stripped_last_line = physical_line.rstrip("\r\n")
        return (
            self.total_lines
            if stripped_last_line == physical_line
            else self.total_lines + 1
        )

    def run(self) -> Generator[Tuple[int, int, str, None], None, None]:
        actual_lines = self.get_file_length()
        max_lines = self.max_lines
        if actual_lines > max_lines:
            message = MSG.format(actual=actual_lines, max=max_lines)
            yield actual_lines, 0, message, None
```

setup.pyでentry_pointsに作ったクラスをを指定しないと認識してもらえない。

```python:setup.py
...
    entry_points={
        'flake8.extension': [
            'MXL = flake8_max_lines:MaxLinesPlugin',
        ],
    },
...
```
@testing-library/react-hooksから@testing-library/reactに移行したときにやったこと

# はじめに
先日、業務においてReactのバージョンをv17からv18にアップグレードしました。
このアップグレードに伴い、使用していた@testing-library/react-hooksライブラリも@testing-library/reactに移植する必要が生じました。

@testing-library/react-hooksは、React v17以前のバージョンでコンポーネントをテストするためのライブラリでしたが、React v18では新しいRoot APIが導入されたことで、@testing-library/react-hooksは非推奨となり、@testing-library/reactに統合されました。

今回は、業務において@testing-library/react-hooksを@testing-library/reactに移植した時やったことについて解説します。

# 扱うテスト関数
今回はuseSetTimeoutというカスタムフックのテストを例に説明していきます。
useSetTimeoutはReactの`setTimeout`と`clearTimeout`を抽象化したカスタムフックで、タイムアウトの設定とキャンセルを簡単に扱えるようにしています。返り値は[SetTimeout, ClearTimeout, boolean]型です。



# RenderResult→RenderHookResult
@testing-library/react-hooksの`renderHook`関数は、`RenderResult`型を返していましたが、@testing-library/reactでは`RenderHookResult`型に変更されました。この変更に対応するため、以下のようにコードを修正しました。setTimeoutのテストの一部分のみを抽出しております。

```ts:@testing-library/react-hooks
import type { RenderResult } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react-hooks';
import useSetTimeout from './useSetTimeout';

class CurrentResult {
  constructor(
    private renderResult: RenderResult<ReturnType<typeof useSetTimeout>>
  ) {}

  get setTimeout() {
    return this.renderResult.current[0];
  }
}

describe('useSetTimeout', () => {
  let currentResult: CurrentResult;
  beforeEach(() => {
    const { result } = renderHook(() => useSetTimeout());
    currentResult = new CurrentResult(result);
  });
```

```ts:@testing-library/react
import type { RenderHookResult } from '@testing-library/react';
import { renderHook } from '@testing-library/react';
import useSetTimeout from './useSetTimeout';

class CurrentResult {
  constructor(
    private renderResult: RenderHookResult<
      ReturnType<typeof useSetTimeout>,
      unknown
    >
  ) {}

  get setTimeout() {
    return this.renderResult.result.current[0];
  }
}

describe('useSetTimeout', () => {
  let currentResult: CurrentResult;
  beforeEach(() => {
    const renderHookResult = renderHook(() => useSetTimeout());
    currentResult = new CurrentResult(renderHookResult);
  });
```

# 終わりに
@testing-library/react-hooksから@testing-library/reactへの移植は、React v18へのアップグレードの際には必須となる作業です。
本記事では、その際に業務においてやったことをuseSetTimeoutフックを例に解説しました。
内容としては型定義を見ればすぐに行えるものですが、少々苦戦したので備忘録として残したいと思いました。