OmniAICreator/Qiita-1.07M huggingface dataset:
【2024年02月版】ターミナル閉じてもタスクを実行し続ける方法しってますか？　あとから。【切断対策】

# はじめに

Linux上で、長時間実行するタスクを切断されても大丈夫なようにする方法として、

- screen 上で実行しておく　→　切断されても大丈夫
- nohup をつけて実行しておく →　切断されても、exitしても大丈夫

というのがありますが、

- screen するの忘れた。。。
- nohup つけて実行するの忘れた。。。

という時に使う方法です。

# 結論

一旦バックグラウンドジョブにして、`disown` でセッションから切り離す。

```terminal
$ ./long_task.sh           # やらかし、screen上でもないし、nohupもついていない
ctrl + z
[1]+  停止                  ./long_task.sh
$ bg
[1]+ ./long_task.sh &
$ disown %1
```

すでにバックグランドで実行している場合も、`disown` でセッションから切り離す。

```terminal
$ ./long_task.sh &        # やらかし、screen上でもないし、nohupもついていない
[1] 1013632
$ jobs
[1]+  実行中               ./long_task.sh &
$ disown %1
```

# 参考

ターミナル閉じてもタスクを実行し続ける方法

- `screen` セッション上で、バックグラウンドで、タスクを実行する
- `nohup` をコマンドの先頭に付けて、タスクを実行する

# さいごに

忘れますよね
UIFlow 2.0 でシンプルな MQTT の送受信（パブリッシュ／サブスクライブ）

2/27 に行われたイベント　IoTLT で LT登壇した際、その登壇ネタにしていた以下の話にも関連する内容です。

<script defer class="speakerdeck-embed" data-id="8e9a585d1f194a529350f4e95e729c78" data-ratio="1.7761332099907492" src="//speakerdeck.com/assets/embed.js"></script>

M5Stack社のデバイスをビジュアルプログラミングで扱える「UIFlow」の新バージョン 2.0 で、IoT でよく使われる MQTT を扱う話です。

## UIFlow（バージョン 1系）での MQTT
今回の記事の本題は、今月正式版になった新しいバージョンの UIFlow（UIFlow 2.0）で MQTT という話ですが、バージョン 1系では過去に既に何度も利用していたものでした。

直近では、以下の記事に書いたものがあります。

●【小ネタ】shiftr.io Desktop と UIFlow1.0 の MQTT を組み合わせて軽く動作確認（ローカルネットワーク内） - Qiita
　https://qiita.com/youtoy/items/69dc3c4a5dde16600092

またかなり前の記事になりますが、以下は MQTT の通信の仲介役（MQTTブローカー）にクラウドサービスを使った話です（上で掲載したものは、宅内ローカルでプライベートIP を用いた通信をやっていました）。

●Beebotte のダッシュボードで M5StickC から送った数値をグラフ化する（UIFlow ＋ MQTT でデータ送信） - Qiita
　https://qiita.com/youtoy/items/b65ddfc89a03117a0ee3

MQTT による送受信（パブリッシュ／サブスクライブ）は、複数台をつなぐのを手軽に実現できたり、また宅内にあるデバイスに対してインターネット側からの通信をやりやすかったり、便利に使えると感じています。

## UIFlow 2.0 でシンプルな MQTT
それでは本題の UIFlow 2.0 でのシンプルな MQTT です。

今回は、UIFlow 2.0 を使うためのセットアップや、細かな使い方の話は省き、シンプルにどのようなブロックを利用するか、という部分をサクッと紹介する感じにします。

### サブスクライブ
先にデータを受信する側、MQTT のサブスクライブの話です。
以下の動画に出てくる、手前の小さなデバイス（ATOMS3）の実装に用いたものについてです。

（※ 以下では、送り側は JavaScript を用いて 0-255 の数値を送っているのですが、その部分は UIFlow の話からズレるのと、[過去に JavaScript＋MQTT の話を複数記事に書いている](https://qiita.com/search?q=mqtt%20mqtt.js%20user%3Ayoutoy&sort=created)ので、今回は省略します）

<iframe width="560" height="315" src="https://www.youtube.com/embed/3K2ErWSVTZg?si=aS830BNVpkyQrmuT" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

用いたブロックのプログラムは以下のとおりです。
基本的に青色のブロック（convert to int のブロックを除く）が、MQTT関連のブロックです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/c565eda6-c423-ffb5-cb8d-c648e968f5c5.png)

Setup の中で初期設定と通信開始の処理を行い、サブスクライブのブロックで MQTT で使う「トピック」を設定しています（さらに、その中の「get msg (return bytes)」で、受信したメッセージを取り出している形）。
それと、ループの処理の部分で、「MQTT apply for messaging」を使う構成となります。

上記の構成は、キーワード検索して結果に出てきていた以下を参考にしました。
※ なお、自分の用いたものは「MQTT で送られてくるものが数値」という前提になっています

●m5tough UIFlow2.0 Alpha 24. mqtt. first-timer needs some guidance | M5Stack Community
　https://community.m5stack.com/topic/5634/m5tough-uiflow2-0-alpha-24-mqtt-first-timer-needs-some-guidance

### パブリッシュ
今度は送信（パブリッシュ）です。

ループする処理の中で、カウントアップする数字を用意していて、それを送信しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/03ad83c6-5304-31f4-9574-730a92147414.png)

基本的には、Setup の中は受信（サブスクライブ）の場合と同じような構成です。それと、送信（パブリッシュ）の場合は、「MQTT apply for messaging」を使う必要はなさそうで、メッセージを送りたいところで「トピック」とメッセージを指定してやれば良さそうでした（なお、MQTT の msg で送るのは文字列となり、上記では数値を送ろうとしたため、文字列変換の処理をする「convert to str」を用いています）。

## おわりに
とりえあず、UIFlow 2.0 でシンプルな MQTT の送受信（パブリッシュ／サブスクライブ）を実現するための、ブロックを使ったプログラムを紹介してみました。
RailsアプリケーションとPostgreSQLの接続問題を解決する

Railsアプリケーションを開発している際、PostgreSQLデータベースへの接続でつまずくことがあります。この記事では、そのような時に役立つ解決策を共有します。

## 前提

RailsアプリケーションからPostgreSQLデータベースへの接続時に次のようなエラーが発生しました。

```plaintext
ActiveRecord::ConnectionNotEstablished (could not connect to server: No such file or directory
        Is the server running locally and accepting
        connections on Unix domain socket "/tmp/.s.PGSQL.5432"?):
```

このエラーは、RailsがPostgreSQLサーバーへの接続を試みるも、指定されたUnixドメインソケットが見つからないために発生します。

## 解決策

### 1. PostgreSQLサーバーの状態確認

まず、PostgreSQLサーバーが実際に稼働しているかを確認します。ターミナルで次のコマンドを実行してください。

```shell
sudo systemctl status postgresql
```
または、PostgreSQLのインストール方法に応じて、適切なコマンドを使用します。

### 2. ソケットファイルの場所の確認

PostgreSQLサーバーが稼働していることを確認したら、次にソケットファイルの場所を確認します。デフォルトの場所は通常`/var/run/postgresql`ですが、エラーメッセージでは`/tmp`を参照しています。

### 3. Railsのデータベース設定の修正

`config/database.yml`内の設定を、実際のPostgreSQLのソケットファイルの場所に合わせて修正します。例えば、デフォルトのソケットファイルの場所を使用している場合は以下のようになります。

```yaml
default: &default
  adapter: postgresql
  encoding: unicode
  # その他の設定...

development:
  <<: *default
  database: myapp_development
  username: myapp
  password: <%= ENV['MYAPP_DATABASE_PASSWORD'] %>
  host: /var/run/postgresql
```

これで、Railsアプリケーションは正しい場所でPostgreSQLサーバーに接続しようとするはずです。
【React】useIdの使い方

`useId`を使用すると以下のように一意のIDを設定できます。
同一画面に同じコンポーネントを複数回使用してもIDが重複することはありません。

```js
import { useId } from 'react';

export default function Form() {
  const id = useId();
  return (
    <form>
      <label htmlFor={`${id}-firstName`}>First Name:</label>
      <input id={`${id}-firstName`} type="text" />
      <hr />
      <label htmlFor={`${id}-lastName`}>Last Name:</label>
      <input id={`${id}-lastName`} type="text" />
    </form>
  );
}
```
【Deno Deploy】md5sum api【md5】

javascriptでmd5するの結構めんどいのでAPI作った


# 使い方

```javascript
const md5 = text => fetch('https://md5sum.deno.dev/' + text).then(r=>r.text())

console.log(await md5('abc'))
```

# ソースコード

```typescript
import { Md5 } from "https://deno.land/std@0.119.0/hash/md5.ts"

const headers = { 'Access-Control-Allow-Origin': '*' }
Deno.serve((req: Request) => new Response(new Md5().update(req.url.slice(24)).toString(), { headers }));
```
【SwiftUI】左右の要素がちょっと見えているバナーを実装する（iOS17）

# はじめに
キャンペーンのバナーとかでよくみる、左右の要素がちょっと見えているカルーセルUIをSwiftUIで実装してみたいと思います。

# サンプルアプリ
![Simulator Screen Recording - iPhone 15 Pro - 2024-02-28 at 23.44.16.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/1bb50179-81ea-b625-77bb-91b69dd25855.gif)

# 実装
```swift
import SwiftUI

struct ContentView: View {
    private let carouselRange = 0..<10
    
    var body: some View {
        ScrollView(.horizontal, showsIndicators: false) {
            HStack {
                ForEach(carouselRange) { index in
                    Text(index.description)
                        .containerRelativeFrame(.horizontal)
                        .frame(height: 60)
                        .background(
                            Color(hue: Double(index) / 10, saturation: 1, brightness: 1),
                            in: .rect(cornerRadius: 10)
                        )
                }
            }
            .scrollTargetLayout()
        }
        .scrollTargetBehavior(.viewAligned)
        .safeAreaPadding(.horizontal, 25)
    }
}
```

# 自動スクロール機能を追加実装してみる
```swift
import SwiftUI

struct ContentView: View {
    /// スクロール位置
    @State private var scrollPosition: Int? = 0

    private let carouselRange = 0..<10
    
    private let timer = Timer.publish(every: 3.0, on: .main, in: .default).autoconnect()
    
    var body: some View {
        ScrollView(.horizontal, showsIndicators: false) {
            LazyHStack {
                ForEach(carouselRange) { index in
                    Text(index.description)
                        .containerRelativeFrame(.horizontal)
                        .frame(height: 60)
                        .background(
                            Color(hue: Double(index) / 10, saturation: 1, brightness: 1),
                            in: .rect(cornerRadius: 10)
                        )
                        .id(index)
                }
            }
            .scrollTargetLayout()
            .onReceive(timer) { _ in
                guard let scrollPosition else { return }
                let carouselCount = carouselRange.upperBound
                let carouselMaxIndex = carouselCount - 1
                withAnimation {
                    if carouselMaxIndex <= scrollPosition {
                        self.scrollPosition = 0
                    } else {
                        self.scrollPosition = scrollPosition + 1
                    }
                }
            }
        }
        .scrollPosition(id: $scrollPosition)
        .scrollTargetBehavior(.viewAligned)
        .safeAreaPadding(.horizontal, 25)
    }
}
```

# おわり
このUI割と見ますよね
iOS17で追加された機能をいっぱい使ってます。

`scrollPosition`初めて使ったのですが、`Lazy◯Stack`じゃないと動かない？気がする
この辺は別記事で調査してみます。
RedisをDockerで動かす

業務でRedisを使う機会があったので、備忘録としてRedisをDockerコンテナで動かす手順を書き起こします。

### 環境

* Windows11
* WSL2 Ubuntu20.04
* Docker 20.10.22

### redisコンテナを起動する

#### redisイメージを取得する

```bash
$ docker pull redis:7.2.4-alpine
```

※ 2024年2月時点で最新かつ軽量の`7.2.4-alpine`を利用しています。

#### redisコンテナを起動する

```bash
$ docker run -d --name redis -it redis:7.2.4-alpine
```

* `-d` : コンテナをバックグラウンドで起動する
* `--name` : コンテナ名

### redisの基本操作

#### redisコンテナにログインする

```
$ docker exec -it redis sh
```

#### redisを操作する

`redis-cli`コマンドを使って操作します。redis-cliコマンドを最初に実行して対話モードに切り替えても良いですし、redis-cli [command] でコマンドライン上で操作しても良いです。

ここでは対話モードを使います。

```
/data # redic-cli
127.0.0.1:6379>
```

##### 疎通確認

```
127.0.0.1:6379> ping
PONG
```
##### 文字列データ

```
# set <key> <value> でデータを登録
127.0.0.1:6379> set hoge fuga
OK

# get <key> でデータを取得
127.0.0.1:6379> get hoge
"fuga"

# キーが存在しない場合nilが返る
127.0.0.1:6379> get bar
(nil)

# 数値も文字列データとして扱われる
127.0.0.1:6379> set fizz 1
OK
127.0.0.1:6379> get fizz
"1"
```

##### ハッシュデータ

```
# hset <key> <field1> <value1> <field2> <value2> ... <fieldX> <valueX>
127.0.0.1:6379> hset shoes1 brand On model CloudMonster size 26cm
(integer) 3

# hget <key> <field>
127.0.0.1:6379> hget shoes1 model
"CloudMonster"

# hgetall <key>
127.0.0.1:6379> hgetall shoes1
1) "brand"
2) "On"
3) "model"
4) "CloudMonster"
5) "size"
6) "26cm"
```

##### データ全削除

```
127.0.0.1:6379> flushall
OK

127.0.0.1:6379> hget hoge
(nil)
```

### 参考資料

* [redis - Official Image | Docker Hub](https://hub.docker.com/_/redis)
  * Docker HubのRedisイメージのページ
* [Redis](https://redis.io/)
  * Redisの公式ページ
  * [Docs](https://redis.io/docs/)
CpawCTF Q22.[Web]Baby's SQLi - Stage 1-

# CpawCTF Q22.[Web]Baby's SQLi - Stage 1-
問題にあるurlにアクセスする。![スクリーンショット 2024-02-16 171258.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3685661/20dfdb94-86bd-b075-a4c6-848f3d053ff6.png)
select * from palloc_homeと入力してflagをゲット
答えはcpaw{palloc_escape_from_stage1;(}
select * from -> SQLでテーブルからすべての列を選択するために使用されます。

```sql:usage.sql
SELECT * FROM テーブル名;
```
DockerのRedisに初期データを登録する

# 背景
背景というほどのこともないんですが、タイトルままでDockerのRedisに初期データを登録したくて、その方法が検索しても出てこず試行錯誤してできたので備忘録的な感じです。

MySQLなんかは `/docker-entrypoint-initdb.d` にSQL書いたファイルをマウントすればコンテナ起動時にSQL実行されるのでテーブル作って初期データ作ったりできますね。
Redisの場合は、同じ要領ではできないので、初期データ登録するだけですぐ落ちるコンテナを作ることで対応しました。

# やり方
```yaml:compose.yaml
version: "3.9"

services:
  redis:
    image: redis:latest

  redis-client:
    image: redis:latest
    volumes:
      - ./redis/redis-init-data.txt:/tmp/redis-init-data.txt
    command: >
      /bin/bash -c '
      cat /tmp/redis-init-data.txt | redis-cli -h redis -p 6379 --pipe
      '
    depends_on:
      - redis
```

```text:redis/redis-init-data.txt
SET test-key test-value
```

`redis`コンテナは、アプリやら何やらが接続して実際に使うコンテナです。
`redis-client`コンテナは、`redis`コンテナに初期データを登録したらお役御免のコンテナです。

`redis-init-data.txt`ファイルに登録したい初期データ(redisコマンド)を書いておいて、それを初期データ登録用の`redis-client`コンテナにマウントします。

`redis-client`コンテナは `redis-cli`コマンドで、マウントされたファイルの内容を`redis`コンテナに対して実行します。
これで`redis`コンテナに初期データが登録されます。

こんな感じで。
```terminal:ターミナル
$ docker compose exec redis bash
root@4a5eb2d1a95d:/data# redis-cli get test-key
"test-value"
```

`redis-client`コンテナはこのコマンドを実行した後、落ちます。

```bash
cat /tmp/redis-init-data.txt | redis-cli -h redis -p 6379 --pipe
```

## ただの苦労話
元々1つのredisコンテナでなんとかできないか色々試してたんですが、docker-composeファイルのcommandの中で`redis-cli`コマンドを使うと、コンテナが`exited(0)`で正常終了してしまってお手上げ状態でした。
調べても出てこないし、ChatGPTもGeminiも、これといった回答が出ず、諦めて全く関係ない件の環境構築の方法を調べてる中で、クライアント用のコンテナを立てるという手法を見て、「このやり方ならもしかしてRedisもいけるんじゃないか？」と試してみたところ、ようやくうまくいったのでした。
そして勢いそのままにこの記事を書いているのでした。
【SwiftUI】getNotificationSettingsの非同期代替関数

## Before
async関数以外だと以下のコードのように通知許可状態を取得していました。
```swift
UNUserNotificationCenter.current().getNotificationSettings { settings in
    DispatchQueue.main.async {
        switch settings.authorizationStatus {
        case .authorized:
            self.statusLabel.text = "Status: Authorized"
        case .denied:
            self.statusLabel.text = "Status: Denied"
        case .notDetermined:
            self.statusLabel.text = "Status: NotDetermined"
        case .provisional:
            self.statusLabel.text = "Status: Provisional"
        case .ephemeral:
            self.statusLabel.text = "Status: Ephemeral"
        @unknown default:
            fatalError("Unknown authorization status")
        }
    }
}
```
async関数内で使用した場合、警告が出ます。
```
Consider using asynchronous alternative function
```

## After
```swift
// こちらに代替された
let settings = await UNUserNotificationCenter.current().notificationSettings()
switch settings.authorizationStatus {
case .authorized:
    self.statusLabel.text = "Status: Authorized"
case .denied:
    self.statusLabel.text = "Status: Denied"
case .notDetermined:
    self.statusLabel.text = "Status: NotDetermined"
case .provisional:
    self.statusLabel.text = "Status: Provisional"
case .ephemeral:
    self.statusLabel.text = "Status: Ephemeral"
@unknown default:
    fatalError("Unknown authorization status")
}
```

## 参考文献

https://developer.apple.com/documentation/usernotifications/asking-permission-to-use-notifications

ドキュメントにめちゃめちゃ載っていましたね…
【Drupal】APIへの外部からのアクセスを許可する

# 結論
services.ymlを次のように編集する
```services.yml
# Configure Cross-Site HTTP requests (CORS).
# Read https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
# for more information about the topic in general.
# Note: By default the configuration is disabled.
cors.config:
    # enabled: false # --- 修正前
    enabled: true # --- 修正後 
    # Specify allowed headers, like 'x-allowed-header'.
    allowedHeaders: []
    # Specify allowed request methods, specify ['*'] to allow all possible ones.
    allowedMethods: []
    # Configure requests allowed from specific origins. Do not include trailing
    # slashes with URLs.
    allowedOrigins: ['*']
    # Configure requests allowed from origins, matching against regex patterns.
    allowedOriginsPatterns: []
    # Sets the Access-Control-Expose-Headers header.
    exposedHeaders: false
    # Sets the Access-Control-Max-Age header.
    maxAge: false
    # Sets the Access-Control-Allow-Credentials header.
    supportsCredentials: false
```

# 環境
Drupal10.2.3

# 概要
Reactからaxiosを使って、Drupalで作成したViewsRESTからデータを取ろうとしたところ以下のエラーが出ました。
```
blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource
```
ざっくりいうと、CORSポリシーに反してるよっていう趣旨のメッセージです。

## CORSとは
異なるサーバー間でのリクエストのやり取りをできるようにするための仕組みです。

https://developer.mozilla.org/ja/docs/Web/HTTP/CORS

間違ってたらごめんなさい。

# やったこと
DrupalではデフォルトでCORSが許可されていないのでこれを許可するように設定しました。
その設定が冒頭に紹介した修正です。

```allowHeaders```以降の設定も要件に応じて変えてください。私は特に変更しませんでした。
コメントを翻訳すると次のようです。

>x-allowed-header'のように、許可するヘッダを指定します。
>許可するリクエストメソッドを指定します.
>特定のオリジンからのリクエストを許可するように設定する。
>URLの末尾にスラッシュを含めないでください。
>正規表現パターンにマッチするオリジンから許可されるリクエストを設定します。
>Access-Control-Expose-Headersヘッダーを設定します。
>Access-Control-Max-Ageヘッダーを設定します。
>Access-Control-Allow-Credentialsヘッダーを設定します。

なおservices.ymlは最初から存在するファイルではないので、
初めて触る場合は前もって以下を実施してください。
```bash
cp sites/default/default.services.yml sites/default/services.yml
```

:::note warn
私の場合はsites/defaultに書き込み権限がなかったのでchmodしましたが、
その辺は環境によっても異なるので適宜実施してください。
:::

# 参考

https://www.drupal.org/project/simple_instagram_feed/issues/3201098
リモート追跡ブランチを知り、Gitへの理解が深まった話

開発に入って数ヶ月後、origin/mainってなんやねんと気になって調べ、リモート追跡ブランチを認識しgitが完璧になった気がしました。
リモート追跡ブランチを理解することで、git fetch, git mergeなど他のものの解像度も上がりました。


githubでのコード管理を想定しています。


## リモート追跡ブランチとは？

origin/mainはリモートリポジトリoriginのmainブランチを追っている追跡ブランチ。
普段作業しているローカルブランチとは別のもの。

（githubを使っている場合、リモートリポジトリはgithubのリポジトリになります）

https://qiita.com/uasi/items/69368c17c79e99aaddbf

上記の記事を読んで、リモート追跡ブランチを認識しました。

その後、git fetch, git mergeが何をしているのかわかるようになりました。


## git fetch

```jsx
git fetch
```

上記で更新がかかるのはリモート追跡ブランチ

```jsx
git fetch -p
```

上記を実行することで、リモート追跡ブランチの更新に加え、リモートリポジトリで削除されたブランチをリモート追跡ブランチ上で削除する。（git fetch -pを実行しないと、リモート追跡ブランチは増え続ける）

## git merge

```jsx
git merge origin/main
```

現在のブランチにリモート追跡ブランチのorigin/mainをマージ

## リモート追跡ブランチをローカルに作成

```jsx
git checkout -t origin/xxxxx
```

リモート追跡ブランチorigin/xxxxxをローカルに作成してそのブランチが現在のブランチになります。（git branchを打つと現在のブランチがxxxxx）

他のメンバーがaaaaaブランチをpushした際、そのブランチをローカルに持ってきたいとき、git fetchでリモート追跡ブランチを更新してから、git checkout -t origin/aaaaaを実行してローカルの作業中のブランチをaaaaaブランチに変更できます。

## まとめ
リモート追跡ブランチについて理解したことで、fetch, merge chekcout -t などのコマンドに関する理解が深まりました。
日本国内のノートPCでのブラウザシェア率を見る

# 1. 背景

https://ics.media/entry/231120/

こちらの本を読んだ際に [Statcounter Global tats](https://gs.statcounter.com/) を知った為です。

日本におけるノートPCでブラウザのシェア率を知りたくこの記事で調査しました。

:::note
後続で調査結果を載せますがデスクトップPCのシェア率も含まれています。
:::


# 2. Statcounter Global Stats とは
世界で使われている検索エンジン、ブラウザ、モバイルを含むオペレーティング・システムなどの統計を見ることができるサイトです。

https://x.com/statcountergs?s=21

# 3. 日本国内のノートPCでのブラウザシェア率を見る
## 3.1 「Edit Chart Data」をクリック 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405182/12603e48-4373-c900-154b-625662725256.png)

## 3.2 Desktopを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405182/d006c324-c8cc-0a24-60e8-17e92dbea69e.png)

:::note
https://gs.statcounter.com/faq#desktop-laptop

>Are laptops included in the desktop platform?
Yes. Laptops and desktop machines are included in the desktop platform together. We use the browser useragent to determine the platform and there is not enough information contained in the useragent to distinguish between laptops and desktops. That is why we do not have a separate laptop platform.

laptop(ノートPC)はDesktopに含まれるとのことです。
ブラウザのユーザーエージェントを使ってプラットフォームを判断していて、ユーザーエージェントにはラップトップとデスクトップを区別するのに十分な情報が含まれていないからだそうです。
:::

## 3.3 regionで日本を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405182/a84e2b41-071d-3e99-10af-39a41589c0ca.png)

## 3.4 「2024年2月21日~2024年2月28日」を指定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405182/c5b1b65d-57a8-3e94-945e-ec2dcb1bfb5c.png)

## 3.5 「View Chart」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405182/db6d7f69-3a91-b4eb-fbbe-5875dfcf9790.png)

## 3.6 シェア率を見る
https://gs.statcounter.com/browser-market-share/desktop/japan/#daily-20240221-20240228

![StatCounter-browser-JP-daily-20240221-20240227.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405182/807225ae-2502-6300-22fd-434f60f32bb7.png)

# 4. can i use との関係
can i use で表示されているブラウザのシェア率はStatcounter Global Statsに基づいています。

https://caniuse.com/?search=grid

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405182/0ec54e7b-06b8-c444-0c92-84f94570d155.png)

# 5.最後に
Statcounter Global Statsはブラウザのシェア率以外にも豊富な統計情報があります。
今後参考情報として積極的に使っていきたいです。
laravel Featureテスト時にファイルpostするときに画像用意するのが面倒だったのでトレイト作ってみた

## 概要

タイトルの通りだが、マルチパートエンコードされた画像を受け取るAPIのFeatureテスト時にテスト画像をローカルストレージから用意したりするのが面倒だった。なのでそれっぽいトレイトを作って必要なFeatureテストクラスでuseして使ってみた。

## 作ったトレイト

多分、説明するよりコード見てもらったほうが早いと思うので書いておく。

```tests/Traits/MakeFileTestFileTrait.php
<?php

declare(strict_types=1);

namespace Tests\Traits;

use Illuminate\Http\UploadedFile;

trait MakeFakeTestFileTrait
{
    /**
     * リクエストで使うテストファイルを作成
     *
     * 注意！MIMEとファイル名の拡張子は必ず合わせること！
     *
     * @param string|null $name
     * @param string $mimeType
     * @param int $kilobytes
     * @return UploadedFile
     */
    private function makeFakeTestFile(
        string $name = null,
        string $mimeType = 'image/png',
        int $kilobytes = 1024
    ): UploadedFile {
        $name = $name ?? config('test.test_file.file_name');

        $file = UploadedFile::fake()->create(
            name: $name,
            kilobytes: $kilobytes,
            mimeType: $mimeType,
        );

        return $file;
    }
}

```

## 使い方

任意のディレクトリにMakeFakeTestFileTrait.phpを作っていただき、namespaceを設定いただき、下記のように任意のFeatureテストでuseして、それぞれのパラメーターを設定して`makeFakeTest()`を呼び出してあげるだけである。

```php
use Tests\Traits\MakeFakeTestFileTrait;

$hogeFileName = 'hogeFile.png';
$hogeFileKilobytes = 2048;
$hogeFileMimeType = 'image/png';
$hogeFile = $this->makeFakeTestFile(
    name: $hogeFileName,
    mimeType: $hogeFileMimeType,
    kilobytes: $hogeFileKilobytes,
);
```

あとはそのまま`$hogeFile`をリクエストボディに突っ込んでpostするだけで良いはず。
Java ~論理演算子~

## :pushpin:前回の記事はこちら
https://qiita.com/nukoxo/items/a733d0eac169bd737640
## :ledger:論理演算子
前回の記事で紹介した関係演算子は「AはBより大きい」など
２つの値の比較を行うことが出来ました。

本日の論理演算子は複数の条件を組み合わせてより
複雑な条件式を組み立てることができます。

<table>
    <tbody>
      <tr>
    <th>演算子</th>
    <th>例</th>
    <th>意味</th>
      </tr>
    <tr>
    <td>&&</td>
        <td>A&&B</td>
        <td>AかつB(AとBが共にtrueならtrue)</td>
        </tr>
        <tr>
    <td> || </td>
    <td> A||B </td>
    <td>AまたはB(AとBどちらかがtrueならtrue)</td>
    </tr>
    <tr>
     <td>!</td>
     <td>!A</td>
     <td> Aでない（Aがtrueならfalse)</td>
    </tr>
    </tbody>
</table>

***

### :crayon:補足
①`A && B && C`のように３つの値を連結することもできます。
（この場合は`”AかつBかつC”`という意味です。）


②ド・モルガンの法則
`!(条件A && 条件B)` は `!(条件A) || !(条件B)) `
`!(条件A || 条件B) `は `!(条件A) && !(条件B) `に置き換えできます。

***
GoogleのGemma.cppをMacBook Pro 2023で動かす

Xで流れてきた情報を参考にしてgemma.cppをMacBook Pro 2023で動かしてみた。

# 参考サイト #

- [google/gemma.cpp](https://github.com/google/gemma.cpp)
- [mac で gemma.cpp を試す](https://note.com/npaka/n/n74f80ee86ac2)
- [WSL2でgemma.cppを試してみる](https://note.com/ngc_shj/n/n3f5c02b48a75)

# 手順 #

1. ターミナルを開く。
2. githubからgemma.cppのコードを取得
3. ディレクトリを移動し、ビルドする。
4. モデルをkaggleからダウンロードし、展開する。
4. 実行する。

# gemma.cppのビルド #

## gemma.cppリポジトリのクローン ##

gitコマンドでgithubからgemma.cppのコードをクローンする。コマンドを実行するディレクトリは適当な場所でよい。

``` shell
git clone https://github.com/google/gemma.cpp
```

## gemma.cppのビルド ##

クローンしたコードのディレクトリへ移動し、cmakeコマンドでビルド用ディレクトリbuildの準備とビルドの実行。``cmake``コマンド、C++コンパイラが必要なので``brew``でインストール、``Xcode``のインストールが必要である。

``` shell
cd gemma.cpp
cmake -B build
cmake --build --preset make -j 8
```

``-j 8``は8スレッドでコンパイルすることを指示している。少ない数でもよい。

## モデルのダウンロードと展開 ##

[kaggl](https://www.kaggle.com/models/google/gemma/frameworks/gemmaCpp)にサインインし、モデルをダウンロードする。ここでは``2b-it-sfp``をダウンロードフォルダにダウンロード(``~/Downloads``)している。


ダウンロードされるモデルのファイル名は``archive.tar.gz``となる。

モデルの展開先を作成し、このファイルをtarコマンドでそのディレクトリへ展開する。

``` shell
mkdir 2b-it-sfp
tar xzfv ~/Downloads/archive.tar.gz -C 2b-it-sfp
```

# 実行 #

gemma.cppのビルドに成功したら下記のようにオプションを指定して実行する。

``` shell
./build/gemma \
--tokenizer ./2b-it-sfp/tokenizer.spm \
--compressed_weights ./2b-it-sfp/2b-it-sfp.sbs \
--model 2b-it \
--verbosity 1
```

質問の文章を入力すれば、応答が得られる。

![gemma.cppの実行](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72921/506f9b95-abd8-a292-0daf-d88e0416fb40.png)
SQL Serverで16進数を10進数に変換する方法

# やりたいこと
- 図のように文字列（nvarchar）で格納されている16進数の数値を10進数に変換する方法を備忘がてら投稿しておきます。
- 1レコード目であれば**18001**と変換できればOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/9f79c271-01ad-9ace-fcd4-ea860ed43e9e.png)

https://hogehoge.tk/tool/number.html

# 0xとは
- そもそも0xとは**16進数表記**の目印だそうです。

https://wa3.i-3-i.info/word1613.html

# 16進数から10進数へ変換
- データ型の変換方法として**CAST**と**CONVERT**があるかと思いますので、どちらとも試してみました。
- 結果はこちら↓
```
SELECT 
    [16進数の列], 
    CAST([16進数の列] as VARBINARY), 
    CAST(CAST([16進数の列] as VARBINARY) as int) 
FROM [dbo].[table]
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/19f971e9-9efd-56c2-923a-a1f71389b277.png)

```
SELECT 
    [16進数の列], 
    CONVERT(VARBINARY, [16進数の列], 1), 
    CONVERT(int, CONVERT(VARBINARY, [16進数の列], 1))
FROM [dbo].[table]
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/08622c84-f593-1046-e8c1-bffe448e9f2a.png)
- どちらも**バイナリ型に変換してから整数型に変換**しているのですが、結果としては、CASTだとうまく変換できず、CONVERTを使用すると正しく変換できました。
- docsを確認したところ、バイナリ型への変換の際、0xが付く文字列の場合はCONVERTを使用して*style*を1に設定する必要があるようです。

https://learn.microsoft.com/ja-jp/sql/t-sql/functions/cast-and-convert-transact-sql?view=sql-server-ver15

>**CONVERT ( data_type [ ( length ) ] , expression [ , style ] )**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/f94b10ad-3bf9-71b6-3b54-c66dcc436dae.png)
Rubyの基本（制御構造 Part2 と メソッド）

# for文による条件分岐（続き）
for文の中で処理を中断したり、次のループに移る処理を加えることができる。
```ruby:sample_01.rb
money = 100
for year in 1..30
  money *= 1.05
  # 「money」の値が300を超えたら処理終了
  break if money > 300
  # 「money」の値が200未満の場合は次のループ文にスキップ
  next if money < 200
  puts "Year #{year}: #{money}"
end
```
以下に注意
break：反復処理全体を終了させる命令。
next：次の反復処理に移る命令。

# 三項演算子
Excelにおけるif文と似ており、構文としては、「条件 ? [trueの場合の処理] : [falseの場合の処理]」となる。
```ruby:sample_02.rb
score = gets.to_i
result = score > 80 ? "A" : "B"
puts result
```

# メソッドの実装
Rubyのメソッドでは最後に評価された値が自動的に戻り値となるため、以下の例では「return」は省略できる。
```ruby:sample_03_01.rb
def triple(num) # 仮引数
  return num * 3
end

puts triple(10) # 実引数
```
上の例のような場合は、「return」ではなく「puts」としてメソッドを単に呼び出すだけで戻り値を表示することもできる。
```ruby:sample_03_02.rb
def triple(num)
  puts num * 3
end

triple(10)
```
この場合、値を表示した後に「nil」として評価されるため、それが戻り値となる。
そのため、戻り値を使ってさらに演算することが難しくなる。

# 戻り値として「true」か「false」を返すメソッド
戻り値として「true」か「false」を返すメソッドの場合、慣習上メソッド名に「?」を付ける。
```ruby:sample_04_01.rb
def dividable?(a, b)
  if b != 0 && a % b == 0
    true
  else
    false
  end
end

puts dividable?(10, 2) # true
puts dividable?(10, 3) # false
puts dividable?(10, 0) # false
```
割る値（b）が0の場合にfalseとなるif文を先に書いておく方法もある。
このようなテクニックを「早期リターン」という。
イレギュラーなパターンの条件分岐を先に書いておくことで、それ以外の条件分岐に集中できるという考え方である。
```ruby:sample_04_02.rb
def dividable?(a, b)
  if b == 0
    return false # 早期リターン
  end
  if a % b == 0
    true
  else
    false
  end
end

puts dividable?(10, 2) # true
puts dividable?(10, 3) # false
puts dividable?(10, 0) # false
```
# 仮引数について
仮引数には初期値を設定することができる。
```ruby:sample_05.rb
def get_total(price, amount, rate = 1.1)
  price * amount * rate
end

puts get_total(100, 10)
puts get_total(120, 10, 1.08)
```
NULLと「""」と「" "」の違い

### 初めに

DBテーブルの特定のカラムに値が入っているかどうかを確認しようとした際に、
これらの違いについて気になったので今回まとめてみようと思いました。

### 結論

・「""」は **空** が値として入っている状態
・「" "」は **空白文字** が入っている状態
・NULLはそもそも値が入っていない状態

### まとめ
NULLは「中身が存在しない」場合に使われる用語で、「中身が存在しない」と「空である」ことはプログラムの世界では同じではないようです。
「""」であるということは空が値として入っている状態であり、 NULLはそもそも値が入っていない状態を指すようです。

[参考サイト]
・https://note.com/shift_tech/n/ne2b5bc6af1c3
・https://wa3.i-3-i.info/diff290moji.html
Cursorってどうなんだろう？


この記事は以下のスクラップをまとめた記事です。

https://zenn.dev/gardenia_710/scraps/704e77324af94b

## はじめに

今回は、Cursorエディタについて調べてみました。

簡単にいうとCopilotを内蔵しているエディタです。

百聞は一見にしかず、ということで、実際に使ってみたいと思います。

## 使ってみる

### インストール

まずは、インストールからです。

公式ページからダンロードを進めます。

https://cursor.sh/pricing

画面の通りインストールを進めていきます。

![](https://storage.googleapis.com/zenn-user-upload/6ee3a90ea7e3-20240225.png)

どうやらVSCodeから設定や拡張機能をインポートできる機能もあるようです。

![](https://storage.googleapis.com/zenn-user-upload/8502aa5d80c7-20240225.png)

### いざ起動

最初はWindowsにインストールして使おうと思ってたのですが、WSL2環境を開けなかったので今回はmacで使ってみることにします。

```bash
$ npx create-next-app@latest
Need to install the following packages:
create-next-app@14.1.0
Ok to proceed? (y) y
✔ What is your project named? … cursor-test
✔ Would you like to use TypeScript? … No / Yes
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like to use `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to customize the default import alias (@/*)? … No / Yes
Creating a new Next.js app in /Users/syotaro2122/dev/cursor-test.

Using npm.

Initializing project with template: app-tw


Installing dependencies:
- react
- react-dom
- next

Installing devDependencies:
- typescript
- @types/node
- @types/react
- @types/react-dom
- autoprefixer
- postcss
- tailwindcss
- eslint
- eslint-config-next


added 365 packages, and audited 366 packages in 20s

131 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
Initialized a git repository.

Success! Created cursor-test at /Users/name/syotaro2122/cursor-test
```

なんとなくNext.jsのプロジェクトを作ってみて、コードを書いてみます。

### チャット機能

![](https://storage.googleapis.com/zenn-user-upload/f075d96e5fc6-20240226.png)

まずはCopilot Chat的な機能のChatを試してみました。

この辺の使い勝手はCopilot Chatとそんなに変わらない気がします。

![](https://storage.googleapis.com/zenn-user-upload/862f95c9f15b-20240226.png)

Copilotでも使えるインラインチャットも同じように使えます。

### Docs

これが一番気になって多機能ですが、外部のライブラリのドキュメントを学習してそこから情報を引っ張ってきてくれるというものです。

実際にNext.jsのドキュメントを学習させて聞いてみました。

![](https://storage.googleapis.com/zenn-user-upload/33165571aecc-20240226.png)

どのページを元に情報を取ってきたのかも明示されているのでわかりやすくてとてもいいですね。

### その他

特定のファイルを開いていなくても、プロジェクトフォルダ全体から必要なものを見に行ってChatの返信をしてくれるらしく、適当に聞いても返してくれるのはいいなと思いました。

![](https://storage.googleapis.com/zenn-user-upload/683157cf7684-20240226.png)

## まとめ

正直他にも機能が沢山あるので使いこなせてはいないですが、現状自分が使っているようなライトな使い方ではCursorへ乗り換えるメリットはあまり感じられませんでした。

Cursor独自の機能はもちろんありますが、Copilotの方もアップデートで対応してくるかもしれないので、今後の動向に注目していきたいと思います。

また、Copilot自体も完全に使いこなせているわけではないので、これを使いこなす方法ももう少し検証したいと思います。

## 参考

https://zenn.dev/umi_mori/books/ai-code-editor-cursor

https://cursor.sh/
Mac（apple siricon）にDocker Desktop のインストールと設定やプラグイン

## 概要
DockerDesktopのインストールと快適に動かすための設定を記載します。

## Docker本サイトからダウンロード
 https://www.docker.com/ja-jp/products/docker-desktop/
より「Mac用のダウンロード マック・アップルチップ」を選択

![スクリーンショット 2024-02-28 16.48.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284596/51b3ff87-f4fe-121e-0db2-9ba234fdb242.png)

## Dockerをインストール
ダウンロードしたDocker.dmgファイルをクリックしてインストールを進める
![スクリーンショット 2024-02-28 16.53.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284596/a976f794-3c28-8805-bcd5-54b8de941323.png)

## Dockerのアップデート
- Docker Desktopを開いたら右上の歯車アイコンをクリック
- 「Softare Updates」をクリックして「Softare Updates」画面を開き「Download update」
![スクリーンショット 2024-02-28 16.55.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284596/ea088323-a380-00c7-c696-f293404ec0ad.png)

※Dockerのコンテナが動かないなと思ったら、アップデートが原因のことがあったりしました。

## Dockerの設定方法
下記での設定でやっています。
これでRailsやVueのプロジェクトの環境はさくさく動いています。
筆者のPCのCPUはm1 Proです。

- CPU Limit: 8
最大

- Memorial limit: 8GP 
全メモリの25%

Swap：1GB
根拠なし、なんとなく

Virtual disk limit:　96GB
同時並行のプロジェクトがあるので、このくらい必要になりました。
状況に応じてもっと減らしてもよいかも

![スクリーンショット 2024-02-28 17.09.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284596/f8b2a8f3-ee7e-44a7-429d-b685654308c5.png)

## プラグインのインストール
Docker Desktopにはプラグインが用意されていているのでインストールしてみます。

### 手順（Resource Usageプラグインをインストール）
- 左のサイドメニューの「Extensions」をクリック
- 検索窓に「resource」と入力
- 目的のResource Usageプラグインをインストール
![スクリーンショット 2024-02-28 21.40.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284596/f251dc44-a8bf-3f0d-1b12-a1d6ee850bc5.png)

- こんな画面になります。
![スクリーンショット 2024-02-28 21.41.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284596/14f5d2c8-5983-ae89-b73b-1c340214b91c.png)
UART通信 Raspberry Pi 4のGPIOでループバック編

# 経緯
* UART通信等の勉強にインタフェース2024年3月号を購入
* Raspberry Pi Picoを未所有
* UART-USB変換ICやケーブルも未所有

# やったこと
* とりあえず手元のRaspberry Pi 4でUART通信を試した
* 対向機器を使わないで，GPIOを使ってループバックで通信をした
* pythonプログラムで疎通確認ができた

# 1. Raspberry Pi 4のシリアルポートを有効化する
今回はRaspberry Pi 4のUART2とUART4を用います。[公式ドキュメント](https://www.raspberrypi.com/documentation/computers/configuration.html#serial)を参考にしました。
1. raspi-configを実行
1. 「3 Interface Options」> 「P6 Serial Port」を選択
1. シェルへのログインにシリアル通信を使うか聞かれるので「いいえ」を選択
1. ハードウェアのシリアルポートを有効化するか聞かれるので「はい」を選択
1. 確認画面で内容を確認して「了解」を選択
1. Finishを選択し，reboot実行

# 2. UART2とUART4を有効化する
UART2とUART4を有効化します。[公式ドキュメント](https://www.raspberrypi.com/documentation/computers/configuration.html#configuring-uarts)を確認するとUART0とUART1はそれぞれ既にconsoleとBluetoothに割り当てられているので，今回はUART2とUART4を使います。
[ラズパイのフォーラム](https://forums.raspberrypi.com/viewtopic.php?t=244827)を参考にしました。
1. nanoで/boot/config.txtを開く
```nano /boot/config.txt```
1. [all]の後に以下を追加する
```/boot/config.txt
[all]
dtoverlay=uart2
dtoverlay=uart4
enable_uart=1
```
再起動した後に以下のようにttyAMA1とttyAMA2がデバイスとして認識されていたらOKです。ttyAMA1がUART2,ttyAMA2がUART4のはずです。
```console
> ls /dev/ | grep ttyAMA
ttyAMA0
ttyAMA1
ttyAMA2
```

# 3. pythonプログラムを作成する
[公式ドキュメント](https://pyserial.readthedocs.io/en/latest/shortintro.html)を参考に適当に作りました。
```uart2touart4.py
# -*- coding: utf_8 -*-

import serial

#インスタンス生成
serUart2 = serial.Serial('/dev/ttyAMA1', 9600, timeout = 0.5);
serUart4 = serial.Serial('/dev/ttyAMA2', 9600, timeout = 0.5);

#データ送信
serUart2.write("Hello World")

#データ受信
data = serUart4.readline()

#データ出力
print('uart4 recv data : {0}'.format(data))

# ポートのクローズ
serUart2.close()
serUart4.close()
```
# 4. GPIOを接続する
ジャンパワイヤを使ってPIN21とPIN27，PIN24とPIN28を接続します。

以下のコマンドでUART2(TXD2とRXD2)がGPIO0とGPIO1に，UART4(TXD4とRXD4)がGPIO8とGPIO9に割り当てられていることが確認できます。
```console
> raspi-gpio get
BANK0 (GPIO 0 to 27):
GPIO 0: level=1 fsel=3 alt=4 func=TXD2 pull=NONE
GPIO 1: level=1 fsel=3 alt=4 func=RXD2 pull=UP
GPIO 2: level=1 fsel=4 alt=0 func=SDA1 pull=UP
GPIO 3: level=1 fsel=4 alt=0 func=SCL1 pull=UP
GPIO 4: level=1 fsel=0 func=INPUT pull=UP
GPIO 5: level=1 fsel=0 func=INPUT pull=UP
GPIO 6: level=1 fsel=0 func=INPUT pull=UP
GPIO 7: level=1 fsel=0 func=INPUT pull=UP
GPIO 8: level=1 fsel=3 alt=4 func=TXD4 pull=NONE
GPIO 9: level=1 fsel=3 alt=4 func=RXD4 pull=UP
GPIO 10: level=0 fsel=0 func=INPUT pull=DOWN
===以下略===
```

また，以下のコマンドでGPIOとPINの対応が確認できます。
```console
> pinout
===前略===
J8:
   3V3  (1) (2)  5V    
 GPIO2  (3) (4)  5V    
 GPIO3  (5) (6)  GND   
 GPIO4  (7) (8)  GPIO14
   GND  (9) (10) GPIO15
GPIO17 (11) (12) GPIO18
GPIO27 (13) (14) GND   
GPIO22 (15) (16) GPIO23
   3V3 (17) (18) GPIO24
GPIO10 (19) (20) GND   
 GPIO9 (21) (22) GPIO25
GPIO11 (23) (24) GPIO8 
   GND (25) (26) GPIO7 
 GPIO0 (27) (28) GPIO1 
 GPIO5 (29) (30) GND   
 GPIO6 (31) (32) GPIO12
GPIO13 (33) (34) GND   
GPIO19 (35) (36) GPIO16
GPIO26 (37) (38) GPIO20
   GND (39) (40) GPIO21
===以下略===
```

# 5. 実行
pythonプログラムを実行すると，以下のようにUARTループバック通信の疎通が確認できました。

```console
> python uart2touart4.py 
uart4 recv data : Hello World
```

# まとめ
とりあえずUART通信ができました。「raspi×UART」は何番煎じだよって感じですが，意外とループバックで通信してみた人はあまりいないんじゃないでしょうか。

次はPicoを購入してインタフェース2024年3月号の内容を試したいと思います。
記事にはしません。
【Side Project】SNSアプリに使った技術のまとめ

# SNSアプリ
FacebookやLinkedInのみたいなWebアプリを作っています～

個人のメモとして、開発中によく見ているドキュメントをまとめます～

諸々スキル触りながら遊んでいますが、興味ある方は↓

https://github.com/curlneko/curlneko-sns

# Frontend
・フロント全体のフレームワーク：React

https://ja.legacy.reactjs.org/

・フロント側言語：JavaScript

https://developer.mozilla.org/ja/docs/Web/JavaScript

・CSSフレームワーク：Ant Design

https://ant.design/components/overview/

・フロント側のリソース取得のためのインターフェイス：Fetch API

https://developer.mozilla.org/ja/docs/Web/API/Fetch_API

https://fetch.spec.whatwg.org/#fetch-method

・フロント側データフェッチフレームワーク：TanStack

https://tanstack.com/query/v4/docs/framework/react/overview

・フロント側画面のstate管理：Redux

https://redux.js.org/usage/

・フロント側の画面ルーター：react-router-dom

https://reactrouter.com/en/main/start/tutorial

・chat UI：chat-ui-kit-react

https://chatscope.io/storybook/react/?path=/docs/documentation-introduction--docs



# Backend
・バック全体のフレームワーク：Node.js Express

https://nodejs.org/api/

https://expressjs.com/ja/guide/routing.html

・バック側言語：JavaScript

https://developer.mozilla.org/ja/docs/Web/JavaScript

・バックの認証：jsonwebtoken

https://jwt.io/introduction

https://www.npmjs.com/package/jsonwebtoken

・バックのパスワード暗号化：bcrypt

https://www.npmjs.com/package/bcrypt

・バックのCORS：cors

https://www.npmjs.com/package/cors

・バックのCookie処理：cookie-parser

https://www.npmjs.com/package/cookie-parser

・バックのバリエーションチェック：express-validator

https://express-validator.github.io/docs/guides/getting-started

・ファイルアップロードのミドルウェア：multer

https://www.npmjs.com/package/multer

・バック側のORM：prisma

https://www.prisma.io/docs/orm/prisma-client/queries/crud

・DB：mySQL

https://dev.mysql.com/doc/

# テスト（工事中）

・JavaScriptの単体テスト：jest

https://jestjs.io/ja/docs/getting-started

・フロント側のブラウザ上テスト自動化ツール

https://playwright.dev/docs/intro

# その他ツール
・API管理：Swagger V3

https://swagger.io/docs/specification/about/

・SQLクライアントツール：a5m2

https://a5m2.mmatsubara.com/

・API関連開発工程支援ツール：postman

https://learning.postman.com/

・バージョン管理：github

https://github.com/curlneko/curlneko-sns

・gitのGUIツール：tortoisegit

https://tortoisegit.org/
MSWの準備前にreact-router-domのloaderが動いてしまったことに対応したメモ

## 概要
react-router-domのloaderの通信がMSWが準備される前に始まってしまう問題があった。
[Issue](https://github.com/mswjs/msw/issues/1653#issuecomment-1781867559)に解決法が乗っていたのでメモする。

[コミット](https://github.com/hibohiboo/kartagraph-monorepo/commit/e71defef2e8c46e47d5e181d7a5fa51e5759893e)



## 原因

loaderは`createBrowserRouter`が作成されたときに実行される。
下記のように、MSWを準備する前に`createBrowserRouter`を行っていた

```ts:router/index.tsx
export const router = createBrowserRouter(
```

## 対応

```ts:router/index.tsx
export const createRouter = () =>  createBrowserRouter(
```

```diff:router/RoutesApp.tsx
- import { router } from '.';
+ import { createRouter } from '.';
export function RoutesApp() {
+  const router = useMemo(() => createRouter(), []);
  return <RouterProvider router={router} future={{ v7_startTransition: true }} />;
}
```

```diff:main.tsx
+ await initMSW();

ReactDOM.createRoot(document.getElementById('root')!).render(
  <Provider store={gameCoreStore}>
    <React.StrictMode>
      <RoutesApp />
    </React.StrictMode>{' '}
  </Provider>,
);
```
DjangoとPostgresで構成されたアプリをAzure Web Appsにデプロイする

## まずはチュートリアル

https://learn.microsoft.com/ja-jp/azure/app-service/tutorial-python-postgresql-app?tabs=django%2Cwindows&pivots=azure-portal

まぁそのままやっておけば良いのだが、ローカルで作成したアプリをコマンドでデプロイできるのは便利

## つまずいたところ

### デプロイが進まなかった
Github側で確認したらずっとStatusがIn progressにならなかった
再デプロイしたら進みました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680269/ed898fba-e876-b96f-7bfe-37b6d569e1a9.png)

同期で再デプロイできた

無事完了
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680269/586ab343-caa6-faa5-e6e6-7133d2d1f29d.png)

マイグレーションも完了

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3680269/1d817146-50b8-85eb-3966-b792aa0da46a.png)

## まとめ
Githubのリポジトリをそのまま簡単にデプロイできるのはマジでやべーなって思いました。
今後自分で作成したアプリもデプロイしてみたいと思います。
とりあえず無料の範囲でならある程度お遊び出来そう
[Rider]UnityでRiderを使ってる人がUE5でもRiderを使おうとしてエラーが出た時の話

# 概要
普段Unity用のIDEに使っているRiderをUnrealEngine5でも使いたくて挑戦してみたのですが、エラーが出てしまいました。その時行った解決するための手順をここにまとめます。
# 本文
## 最初に
Rider for UnrealEngineという名前がありますが、Unityで使ってる普通のRiderをそのままUnrealEngineで使うことができます。専用のRiderを追加でインストールする必要はありませんでした。

## エラー発生
UnrealEngineのメニューから
**編集 > エディタの環境設定
ソースコード > ソースコードエディタ**と辿ってRiderを選択します。（再起動を促されますので再起動のボタンを押します）

![スクリーンショット 2024-02-28 193143.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/495a9d91-ae10-8c9a-c1af-2d4f642d3fec.png)

メニューから**ツール > Riderプロジェクトを更新**を押します。

![スクリーンショット 2024-02-28 195148.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/bc1322aa-79d0-ded3-8152-b358199db54b.png)

うちの環境ではここでエラーが発生しました。

![スクリーンショット 2024-02-28 193849.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/a1b8ce36-c879-6a1d-e50f-fd81ef1f6281.png)
 
 ## VisualStudioの設定

 VisualStudioを開いたらメニューから**ツール > ツールと機能を取得**を選びます。
 
![スクリーンショット 2024-02-28 193926.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/6ac120e8-73d3-34d7-2881-e53806b74e78.png)

機能追加のインストーラーがポップアップしますので「C++によるゲーム開発」をインストールします。

![スクリーンショット 2024-02-28 195922.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/fe173779-13ad-034f-b362-cd16235a920e.png)

## 無事成功
UnrealEngineに戻ると、先程エラーが出た**Riderプロジェクトを更新**を押してもエラーが出なくなりました:open_hands_tone1:
その下の**Riderを開く**を押すとRiderが起動して、UnrealEngineのプロジェクトを開くことができました。

![スクリーンショット 2024-02-28 195148.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/597a2d45-c22b-5389-f6a8-caff131b34f5.png)


# 補足
この手順で解決しなかった場合はVisualStudioのインストールの手順の時、UnrealEngineやC++関連の他の機能をインストールすると上手くいくかもしれません。
Webページの全ての「Add」ボタンを一括でクリックするブックマークレット【ICPSwap編】

ICPSwapのAddボタンが面倒なので、Bookmarkletで一気押し。

ってか、どこかにまとめて押すボタンあるのかもだけど、Bookmarkletの勉強がてら。

*   ICPswap<br><https://app.icpswap.com/wallet>

![](https://pbs.twimg.com/media/GHbDzttawAAWunB?format=jpg\&name=small)

***

### Webページの全ての「Add」ボタンを一括でクリックするブックマークレット

Webサイトを使っていて、たくさんの「追加」ボタンを一つ一つ手動でクリックするのは面倒な作業です。特に、一覧から多くの項目を追加する必要がある時、この作業は時間の無駄に感じられます。そんな時に便利なのが、このブックマークレットです。

#### このブックマークレットは何をするのか？

このブックマークレットは、ページ上の全ての「Add」ボタンを自動でクリックします。「Delete」ボタンがある場合はそれを無視するため、既に追加されている項目を誤って削除する心配はありません。

#### 使い方

1.  以下のJavaScriptコードをコピーします。

```javascript
javascript:(function() {
  document.querySelectorAll('button').forEach(function(btn) {
    if (btn.innerHTML.includes('AddIcon') && !btn.disabled) {
      btn.click();
    }
  });
})();
```

2.  ブラウザでブックマークバーを表示させます。
3.  ブックマークバー上で右クリック（またはコントロールクリック）し、「新しいブックマーク」または「ブックマークを追加」を選択します。
4.  名前フィールドに、ブックマークレットにわかりやすい名前を入力します（例: 「全Addボタンをクリック」）。
5.  URLフィールドに、コピーした`javascript:`で始まるコードをペーストします。
6.  保存します。

これで、使用したいページでこのブックマークをクリックするだけで、ページ上の全ての「Add」ボタンが自動的にクリックされます。

#### 注意点

*   このブックマークレットは、HTML構造やクラス名が予期した通りであるページでのみ正しく動作します。
*   セキュリティの観点から、知らないソースからのスクリプトは実行しないようにしてください。
*   特定のサイトでの使用においては、サイトの利用規約に違反しないよう注意してください。

この小さなツールが、日々の作業を少しでも楽にしてくれることを願っています。

***

# Add token

押してから、ちょっと時間かかるかも

*   実行前

![](https://pbs.twimg.com/media/GHbDzttawAAWunB?format=jpg\&name=small)

*   実行後

![](https://pbs.twimg.com/media/GHbEbj7bsAA9Gvv?format=png\&name=900x900)

# Add NFT もできるよ

![](https://pbs.twimg.com/media/GHbErSvbcAAUBHG?format=png\&name=small)
Vue3でdotenvを使う方法.envの環境変数名に `VITE_` という接頭辞をつけ`import.meta.env.{環境変数名}` という指定の方法にする (processでエラーが出る人向け)

## 現象

- Vue3で `npm install dotenv` して使おうとしたが使えなかった
- `process.env.HOGE` という書き方ではprocessでエラーになる
    - 予測変換で設定できるので余計混乱する

## 解決方法

要点は２つ

- .envファイルに設定する環境変数には `VITE_` という接頭辞をつける 例） `VITE_HOGE`
- `import.meta.env.{環境変数名}` という指定の方法にする 例）`import.meta.env.VITE_HOGE`

参考サイト
[VITE公式 環境変数とモード](https://ja.vitejs.dev/guide/env-and-mode.html)

## エラー全文

`process.env.HOGE` という書き方ではprocessでエラーになる
```
Vue: Cannot find name  process . Do you need to install type definitions for node? Try  npm i --save-dev @types/node  and then add  node  to the types field in your tsconfig.
```

## 何が起こっていたのか

- Vue.jsはVue3からビルドにVITEを使っている
- 環境変数の設定はVITEに委ねられている

上記２つの点を理解していないと解決にたどり着けない
エラーメッセージで検索してもたどり着けなかった

参考サイト（再掲）
[VITE公式 環境変数とモード](https://ja.vitejs.dev/guide/env-and-mode.html)

## 混乱の原因

混乱の原因としては大きく２つ原因があると考えている
- Vue3のサイトで環境変数と検索してもヒットしない
- 検索結果に古い設定が書かれた `Vue CLI` のページがHitする 
    - ここで紹介されている方法ではエラーで使用できない `process` を使う方法だ
    - [Vue CLI モードと環境変数]https://cli.vuejs.org/guide/mode-and-env.html
ModuleNotFoundError: No module named 'cv2'が出た

## 今回の内容
2月22日の猫の日にちなんでOpenCVを使用して猫の顔を判別するコードを書いていたのですが、実行しようとしていたところ、```import cv2```で詰まったので備忘メモとして残したいと思います。
今回使用したコードは以下にあります。


https://github.com/yuuka51/learn_opencv


## やりたかったこと
OpenCVを使用して猫の顔を判別するコードを動かしたい

## 結論
原因は異なるバージョンのPythonを複数インストールしていたことが原因で、Visual Studio Codeで設定＆実行したバージョンのPythonにopencv-pythonをインストールしていなかったことが原因でした。


## 動作環境
Windows11
Python==3.12
OpenCV==4.9.0.80

## 出力されたエラー
事前の準備として```pip install opencv-python```は実施していたのですが、cv2がimportできないよと言われてしまいました。

```
$ C:/.../Python/Python312/python.exe c:/.../cat_face.py
Traceback (most recent call last):
  File "c:\...\cat_face.py", line 1, in <module>
    import cv2  
    ^^^^^^^^^^
ModuleNotFoundError: No module named 'cv2'
```

## 確認したこと
```ModuleNotFoundError: No module named 'cv2'```で検索して出てきた解決方法にopencv-pythonをinstallするという方法が多く出てきていたので以下のように確認してみました。

```
$ pip install opencv-python
Requirement already satisfied: opencv-python in c:\...\python\python311\lib\site-packages (4.9.0.80)
Requirement already satisfied: numpy>=1.21.2 in c:\...\python\python311\lib\site-packages (from opencv-python) (1.26.4)
$ pip install --upgrade pip 
Requirement already satisfied: pip in c:\...\python\python311\lib\site-packages (24.0)
$ pip install --upgrade pip --user
Requirement already satisfied: pip in c:\...\python\python311\lib\site-packages (24.0)
$ python
Python 3.11.7 (tags/v3.11.7:fa7a6f2, Dec  4 2023, 19:24:49) [MSC v.1937 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
>>> print(cv2.__version__)
4.9.0
```

既にインストールはできていて、import cv2もできていました。
じゃあopencv-pythonいるじゃんと思ったのですが、よく見るとPythonファイルを実行したときのPythonのバージョンとpip installで場所を確認したときのPythonのバージョンが異なっていました。
その時にPythonを複数インストールしていたことを思い出しました。

## 解決方法
Visual Studio Codeで使用しているPythonのバージョンを指定してopencv-pythonをインストールしました。

```
$ py -3.12 -m pip install opencv-python
Collecting opencv-python
  Downloading opencv_python-4.9.0.80-cp37-abi3-win_amd64.whl.metadata (20 kB)
Collecting numpy>=1.21.2 (from opencv-python)
  Downloading numpy-1.26.4-cp312-cp312-win_amd64.whl.metadata (61 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 61.0/61.0 kB 1.6 MB/s eta 0:00:00
Downloading opencv_python-4.9.0.80-cp37-abi3-win_amd64.whl (38.6 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 38.6/38.6 MB 29.7 MB/s eta 0:00:00
Downloading numpy-1.26.4-cp312-cp312-win_amd64.whl (15.5 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 15.5/15.5 MB 46.7 MB/s eta 0:00:00
Installing collected packages: numpy, opencv-python
Successfully installed numpy-1.26.4 opencv-python-4.9.0.80

$ py -3.12
Python 3.12.0 (tags/v3.12.0:0fb18b0, Oct  2 2023, 13:03:39) [MSC v.1935 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
>>> print(cv2.__version__) 
4.9.0
```
cv2のバージョンを確認するコマンドを実行して確認後、対象のPythonファイルを実行したところ無事動かせました。

## 参考

https://qiita.com/solitude_under_the_blue_sky/items/c49ff2d1970089ae3a1b

https://qiita.com/tatsuya1970/items/2d6b0e061756d9e33473

https://creepfablic.site/2020/04/10/python-opencv-error/#index_id0
【Linux】ifconfig と grep コマンドを使ってプライベートIPアドレスを簡単に見つける方法

## はじめに
この記事では、ifconfigとgrepコマンドを組み合わせることで、特にプライベートIPアドレスを簡単に見つける方法についてご紹介します。

## 環境
- Apple M2 Pro
- macOS Sonoma 14.2.1

## IPアドレスの検索
多くのローカルネットワークでは、プライベートIPアドレスは 192.168.x.x の形式かと思います。

この範囲のIPアドレスを検索するには、次のコマンドを実行します。

```zsh
ifconfig | grep 192
```

このコマンドで行われることは以下の通りです。

- ifconfig コマンドが実行され、そのパソコンのIPネットワークの設定情報が表示されます。
- |（パイプ）は、ifconfig の出力を grep コマンドに渡します。
- grep 192 は、その出力の中から 192 で始まる行のみを抽出し、表示します。

これにより、プライベートIPアドレスなど、192で始まる情報だけを簡単に見つけることができます。

**出力例（例なので適当に書き換えています）**

```zsh
inet 192.168.1.5  netmask 255.255.255.0  broadcast 192.168.1.255
```

この例では、プライベートIPアドレスが 192.168.1.5 であることがわかります。また、netmask と broadcast の情報も表示されています。


## まとめ
ifconfig と grep コマンドを組み合わせることで、プライベートIPアドレスを簡単に見つけることができました。

## 参考

https://qiita.com/mogulla3/items/efb4c9328d82d24d98e6
【生成AI】アプリの仕様をAIに考えてもらった

##### はじめに
ITに転職したもののがっつり開発みたいなことをしたことがないので自分でアプリを作ることにしました。

##### 作りたいもの
よくジムに行くのでトレーニング内容などを記録できるアプリを作ろうと思いました。
いままで個人開発をしたことがないので↓のようなイメージしかまとまらない。
そこで、AIに具体的にしてもらおうと思います。

```
筋トレの記録とジムの滞在時間をカレンダー形式で保存できるフィットネスアプリ

GPS機能を使いあらかじめ登録したジム位置情報とスマホの位置が重なった時にその滞在時間を算出して記録する。

カレンダーをクリックすると詳細画面に遷移し、トレーニング名と重量、レップ数、セット数を記録できる機能。
```
AIとアプリの議論をして最終的にできたのは↓


以下は、追加の要件を含めたフィットネスアプリの要件定義のまとめです：

1. **ユーザー認証とプロフィール管理**:
   - ユーザーはアカウントを作成し、ログインする必要があります。
   - プロフィールページで、ユーザー情報や目標設定を管理できます。

2. **ジム位置情報の登録**:
   - ユーザーはアプリ内でジムの位置情報を登録できます。
   - 登録したジムの位置情報は、後で滞在時間の計測に使用されます。

3. **GPSによる滞在時間の計測**:
   - ユーザーがジムに到着し、スマートフォンの位置情報がジムの位置と重なった場合、滞在時間の計測が開始されます。
   - ユーザーがジムから離れると、滞在時間の計測が停止されます。

4. **カレンダー形式での記録**:
   - カレンダーページで、ユーザーは過去のジム滞在時間を確認できます。
   - カレンダー上の日付をクリックすると、その日の詳細画面に遷移します。

5. **トレーニング記録**:
   - 詳細画面で、ユーザーはトレーニングの詳細を記録できます。
   - トレーニング名、重量、レップ数、セット数などの情報を入力できます。
   - トレーニングの記録はカレンダー上の日付ごとに保存され、後で参照できます。

6. **データの保存と同期**:
   - ユーザーのジム滞在時間とトレーニング記録は、ローカルデータベースまたはオンラインサービスに保存されます。
   - データは複数のデバイス間で同期され、ユーザーがどこからでもアクセスできます。

7. **ユーザーインターフェイスの設計**:
   - ユーザーが使いやすいUI/UXを提供するために、直感的なナビゲーションと視覚的なデザインを採用します。

8. **ジムの滞在時間帯の集計とグラフ化**:
   - ユーザーはジムの滞在時間帯を集計し、グラフ化できる機能があります。
   - グラフは、1日または週ごとのジム滞在時間帯の変化を視覚的に表示します。

9. **トレーニング種目ごとの取り扱い重量、レップ数の変化の集計とグラフ化**:
   - ユーザーは各トレーニング種目ごとの取り扱い重量とレップ数の変化を集計し、グラフ化できる機能があります。
   - グラフは、時間の経過に伴う取り扱い重量やレップ数の変化を表示し、トレーニングの進歩や課題を把握するのに役立ちます。

これらの要件を満たすアプリを開発することで、ユーザーはトレーニングの効果や進捗を効果的に管理し、より効率的なフィットネスルーチンを確立できます。

この仕様に沿って個人開発をのんびり始めてみます。
【AWS】exec format errorはCodebuild Projectの「オペレーションシステム」に原因があった...

# 概要

ビルドプロジェクトを少し編集してからCodebuildを走らせたら以下のエラー。

```
./script.sh: exec format error
```

うむ？ビルドプロジェクトでそんな重要なところいじった記憶はないのに...
と言うことでこちらのエラーの原因がわかったので紹介します。


# 原因：「オペレーションシステム」の選択
今回編集したのは、以下にある環境変数。

```
CodeBuild -> ビルドプロジェクト -> 該当プロジェクト -> 編集 -> 環境
````

そこで一つ思い出す。
以前は出てなかった気がしたのですが、「オペレーションシステム」に何も選ばない状態で更新をしようとすると、「オペレーションシステムを選択する必要があります」と言うエラーが出ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710373/973e282f-5805-e926-5f1f-50ae70cd4004.png)

（適当に）一番上のを選んでいたのですが、ここに原因がありました。

# 解決策

以下のように、ビルド環境をARMアーキテクチャからx86_64アーキテクチャに変更するで解決しました。
`./script.sh`スクリプトがARMアーキテクチャでは実行できない形式だったのです。

### エラーになった設定

```
aws/codebuild/amazonlinux2-aarch64-standard:2.0
```

### エラーが解消された設定

```
aws/codebuild/amazonlinux2-x86_64-standard:5.0-24.02.08
```

このスクリプトには、`nginx`や`gunicorn`、`alembic`などのコマンドやプログラムがあったのですが、ARMアーキテクチャではなくx86_64アーキテクチャで動作するように作られていた可能性が高いです。もしくは、それらに依存しているPythonインタープリタやライブラリが特定のアーキテクチャ向けだった場合もありますね。

どのアーキテクチャで動作するかを確認する場合は、それらのバイナリファイルに対して`file`コマンドを実行するとわかります。

```
file $(which nginx)
/usr/sbin/nginx: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=29eeec75474b0468b8cfc3029beed211a830f23e, for GNU/Linux 3.2.0, stripped
```