OmniAICreator/Qiita-1.07M huggingface dataset:
Raspberry Pi サーボモータ制御用クラス

# はじめに
Raspberry Piを使用して複数のサーボモータを制御するためのクラスを作成しました。
初期設定は下記サイトが参考になります。
自分も参考にさせていただきました。

https://sozorablog.com/servo/

# ソースコード

クラスを使用することで複数のサーボモータを独立して制御できます。
また、インスタンスが現在の角度情報を保持しているので値を参照できます。

```python:ServoMotor.py
import pigpio
import time


class ServoMotor:
    """
    サーボモータを制御するクラス

    Attributes:
        pin: GPIOのピン番号
        max_angle: 最大移動角度
        min_angle: 最小移動角度
        angle: 現在の角度
        ini_angle: 初期設定角度
        pi: gpio制御
    """
    def __init__(self, pin=17, min_angle=0, max_angle=180, ini_angle=90) -> None:
        """
        サーボモータを制御するクラス
        """
        self.pin = pin
        self.max_angle = max_angle
        self.min_angle = min_angle
        self.angle = 0
        self.ini_angle = ini_angle
        self.pi = None

    def start(self) -> None:
        """
        GPIOの開始処理
        """
        self.pi = pigpio.pi()
        self.pi.set_mode(self.pin, pigpio.OUTPUT)

    def stop(self) -> None:
        """
        GPIOの終了処理
        """
        self.pi.set_mode(self.pin, pigpio.INPUT)
        self.pi.stop()

    def set_angle(self, target_angle: int) -> None:
        """
        サーボモータを指定角度に移動する

        Args:
            target_angle (int): 動作させる角度
        """
        if target_angle < self.min_angle or target_angle > self.max_angle:
            print(f"角度は{self.min_angle}から{self.max_angle}度の間で指定してください。")
            return

        # 角度を500から2500のパルス幅にマッピングする
        pulse_width = (target_angle / 180) * (2500 - 500) + 500
        self.angle = target_angle
        # パルス幅を設定してサーボを回転させる
        self.pi.set_servo_pulsewidth(self.pin, pulse_width)
        time.sleep(0.2)  # サーボモータが移動するのを待つために少し待つ

    def set_ini_angle(self) -> None:
        """
        サーボモータを初期設定の角度に移動する
        """
        self.set_angle(self.ini_angle)

if __name__ == "__main__":
    # 動作サンプル

    """
    動作サンプルではサーボモータを2台接続
    サーボそれぞれの信号ピンを17番、18番に接続
    """
    
    """
    ServoMotorクラスのインスタンス化
    pin: サーボモータ信号端子の接続先ピン番号(設定しない場合 17番)
    max_angle: 最大角度(設定しない場合 180度)
    min_angle: 最小角度(設定しない場合 0度)
    ini_angle: 初期設定角度(設定しない場合 90度)
    """
    servo_motor_horizontal = ServoMotor(pin=17, max_angle=160, min_angle=0, ini_angle=90)
    servo_motor_vertical = ServoMotor(pin=18, max_angle=130, min_angle=0, ini_angle=40)

    # サーボ動作開始
    servo_motor_horizontal.start()
    servo_motor_vertical.start()

    # サンプル動作 
    servo_motor_vertical.set_angle(20)
    for angle in range(0, 181, 10):
        servo_motor_horizontal.set_angle(angle)

    servo_motor_vertical.set_angle(40)
    for angle in range(180, -1, -10):
        servo_motor_horizontal.set_angle(angle)

    servo_motor_vertical.set_angle(60)
    for angle in range(0, 181, 10):
        servo_motor_horizontal.set_angle(angle)

    # 初期位置(ini_angle)に移動
    servo_motor_vertical.set_ini_angle()
    servo_motor_horizontal.set_ini_angle()

    # 現在の角度を表示
    print(servo_motor_vertical.angle)
    print(servo_motor_horizontal.angle)

    # サーボ動作停止
    servo_motor_horizontal.stop()
    servo_motor_vertical.stop()
```

# 制作物
少し変更を加えていますが、下記制作で使用しています。

https://qiita.com/Marusankaku_E/items/85ec76877f2c33189ea7
Aiven、PostgreSQL®とApache Kafka®のKubernetes Operatorサポートを開始

<font color="Grey">*[Aiven launches Kubernetes Operator support for PostgreSQL® and Apache Kafka®](https://aiven.io/blog/aiven-launches-kubernetes-operator-support-for-postgresql-and-apache-kafka)の翻訳です。*</font>

2021年9月13日

# Aiven、PostgreSQL®とApache Kafka®のKubernetes Operatorサポートを開始

Aivenは現在、一部のAivenサービス向けにKubernetes Operatorを提供しています。サービススタック全体の管理にご利用ください。

AivenのサービスをKubernetesで管理できないかとお考えでしたら、もうご心配いりません - そのためのKubernetes Operatorを提供開始しました！


[Kubernetes](https://kubernetes.io)は、コンテナベースのアプリケーションを管理およびオーケストレーションするための一般的なオープンソースツールです。プラットフォームとアプリケーションのデプロイ、スケーリング、管理を自動化するために使用できます。


Kubernetesを使用する場合、システムの望ましい状態を定義し、その状態に到達し維持するのをKubernetesに任せる。Kubernetesには、システムの自動化機能を拡張して新しいサービスやアプリケーションを含める機能もある。そのような拡張機能を作成する1つの方法として、[Kubernetes Operators](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/)という形があります。


その強固な歴史と比類のない柔軟性により、Kubernetesはサービスオーケストレーションツールとして広く普及しており、すべての主要なクラウドプロバイダーによってサポートされ、活発なコミュニティによって開発されている。


## Aivenサービスを管理する新しい方法


では、Kubernetes上の[Aiven for PostgreSQL](https://aiven.io/postgresql)や[Aiven for Apache Kafka](https://aiven.io/kafka)サービスで何ができるのでしょうか？Aiven Operator for Kubernetesは、私たちのパブリックREST APIと同じすべての操作へのアクセスを提供します。同時に、Kubernetesツールを使用してAivenインフラストラクチャを管理できます。また、Aiven ProjectsやAiven VPCなどのAivenネイティブリソースもサポートしています。


Aiven Operator for Kubernetesにより、最新のソフトウェアアプリケーションの迅速かつ効率的な構築とデプロイをサポートします。当社のマネージドサービスは、日々のデータ運用のシームレスな一部となり、使い慣れた標準ツールで利用できます。


## Aiven Kubernetes Operatorを使い始める


Aiven Kubernetes Operatorは[GitHubのプロジェクトページ](https://aiven.github.io/aiven-operator/)から入手できます。指示に従ってインストールし、使い始めてください。


## まとめ


Aiven Operator for Kubernetesが提供する一元化されたアクセスは、あなたのデータベース管理業務にさらなるフォーカスをもたらします。今すぐチェックしてみてください！


まだAivenのサービスをご利用になっていませんか？<https://console.aiven.io/signup>から今すぐ無料トライアルにお申し込みください！


また、[changelog](https://aiven.io/changelog)や[blog](https://aiven.io/blog)のRSSフィード、または[LinkedIn](https://www.linkedin.com/company/aiven/)や[Twitter](https://twitter.com/aiven_io)のアカウントをフォローし、製品や機能関連の最新情報をご確認ください。
Zhejiang Zhongbang Decorative Material Co.,Ltd

Zhejiang Zhongbang Decorative Material Co.,Ltd

https://www.zjzbpvc.com

+86 15158963370

Nancy@zjzbdeco.com

Marble Design HOT Stamping Foil For Wall Panel Furniture, Wood Grain Hot Stamping Foil, Solid Color PP Decorative Film For Door

Zhejiang Zhongbang Decorative Material Co.,Ltd was established as a professional manufacturer of decorative film in 2009 and has been developed rapidly since then. Main products include PVC film, PETG film and hot stamping foil. Our 35000㎡Production line covers the whole production process of decorative films including printing, laminating and embossing. We have over 10,00 different styles for choice and keep developing innovative and trendy colors or patterns every year, meanwhile we carry out a full range of customized services to meet worldwide customers’ needs. Product series include wood grain series, marble series, metal series, skin feel film series, embossing series, art lacquer series and so on. Our products are mainly exported to Asia, Africa, Europe and also Chinese domestic market and are widely used in many fields such as Particle Board, MDF, Plywood, furniture, wall panels, decoration lines and Door. With fashionable design, stable quality and superior cost performance. we enjoy a high reputation in the industry and establish long-term business relationships with customers all around the world.

NO.1 ZHONGBANG ROAD, ANHUA TOWN, ZHUJI CITY, ZHEJIANG PROVINCE, CHINA
SQLServer UPSERT

「DBにないデータだけ登録して」と言われたときに使う(-ω-)/

## UPSERT
SQL ServerでUPSERT操作を行う一般的な方法は、MERGEステートメントを使用することです。UPSERTは、データが既に存在する場合は更新（UPDATE）し、存在しない場合は挿入（INSERT）する操作を指します。

## MERGE
`users`テーブルへのUPSERT操作例
ここでは、usersテーブルに対してidをキーとして使用し、該当するidがテーブルに存在する場合はnameを更新し、存在しない場合は新しいレコードを挿入します。

```SQL
MERGE INTO users AS target
USING (VALUES (@id, @name)) AS source (id, name)
ON (target.id = source.id)
WHEN MATCHED THEN 
    UPDATE SET name = source.name
WHEN NOT MATCHED BY TARGET THEN 
    INSERT (id, name) VALUES (source.id, source.name);
```

まず`USING`句でソースとして使用する値を指定します。
ここでは、変数`@id`と`@name`から成る1行のデータをソースとしています。

`ON`句で`users`テーブルの`id`とソースの`id`を比較し、
一致するかどうかに基づいて次の操作を決定します。

`WHEN MATCHED`句は、一致するレコードが見つかった場合に実行され、`name`を更新します。

`WHEN NOT MATCHED BY TARGET`句は、一致するレコードがターゲットテーブルに存在しない場合に新しいレコードを挿入します。

## Reference
- [MERGE (Transact-SQL)](https://learn.microsoft.com/ja-jp/sql/t-sql/statements/merge-transact-sql?view=sql-server-ver16)
Spring　transactionメモ

~~~Java
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.io.IOException;

@Service
public class CsvImportService {

    private final JdbcTemplate jdbcTemplate;
    private final PlatformTransactionManager transactionManager;

    @Autowired
    public CsvImportService(JdbcTemplate jdbcTemplate, PlatformTransactionManager transactionManager) {
        this.jdbcTemplate = jdbcTemplate;
        this.transactionManager = transactionManager;
    }

    @Transactional
    public int importCsvData(String tableName, String csvFilePath) {
        try {
            // トランザクションを開始
            TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());

            try {
                // CSVファイルからデータを読み込み、データベースに一括挿入
                String copySql = "COPY " + tableName + " FROM '" + csvFilePath + "' WITH CSV HEADER";
                jdbcTemplate.execute(copySql);

                // トランザクションをコミット
                transactionManager.commit(status);

                return 0; // 正常終了
            } catch (Exception e) {
                // エラーが発生した場合、トランザクションをロールバック
                transactionManager.rollback(status);
                e.printStackTrace();
                return 1; // 異常終了

                // SQLExceptionに変換してスローし、トランザクションをロールバック
                //throw new RuntimeException("データベースエラー", e);
            }
        } catch (IOException e) {
            e.printStackTrace();
            return 1; // 異常終了
        }
    }
}
systemd-sysv-generator コマンドと chkconfig の比較

## systemd-sysv-generator コマンドと chkconfig の比較

**systemd-sysv-generator** と **chkconfig** は、どちらも Linux システムでサービスを管理するためのコマンドです。どちらもサービスの起動・停止・設定を可能にする強力なツールですが、それぞれ異なる利点と欠点があります。

**初心者にとってどちらが使いやすいのか** は、それぞれの知識レベルや使用目的によって異なります。

### 1. systemd-sysv-generator とは？

**systemd-sysv-generator** は、**systemd** という新しいサービス管理システムで利用できるコマンドです。**systemd** は、従来の SysVinit システムよりもシンプルで柔軟なサービス管理を提供します。

**systemd-sysv-generator** は、SysVinit の init スクリプトを systemd サービスファイルに変換するために使用します。つまり、**systemd** を使いながら、従来の SysVinit スクリプトを継続して使用することができます。

### 2. chkconfig とは？

**chkconfig** は、**SysVinit** という従来のサービス管理システムで利用できるコマンドです。**SysVinit** は、長年多くの Linux ディストリビューションで使用されてきたサービス管理システムです。

**chkconfig** は、サービスの起動レベルを設定したり、サービスの起動・停止を制御したりするために使用します。

### 3. systemd-sysv-generator と chkconfig の比較

| 項目 | systemd-sysv-generator | chkconfig |
|---|---|---|
| 使用するサービス管理システム | systemd | SysVinit |
| コマンドの役割 | SysVinit スクリプトを systemd サービスファイルに変換 | サービスの起動レベル設定、起動・停止制御 |
| 設定ファイル | /etc/systemd/system/<サービス名>.service | /etc/init.d/<サービス名> |
| 複雑性 | 比較的シンプル | 比較的複雑 |
| 初心者向け | 慣れれば使いやすい | 最初は使いにくい |
| 利点 | - systemd の利点を活かせる<br>- SysVinit スクリプトを使い続けられる | - 多くのディストリビューションで利用可能<br>- 設定ファイルの構造が単純 |
| 欠点 | - systemd に慣れていないと使いにくい | - systemd ほど柔軟ではない |

### 4. どちらを使うべき？

**どちらのコマンドを使うべきかは、以下の状況によって異なります。**

* **すでに systemd を使っている場合:** systemd-sysv-generator を使うのがおすすめです。
* **SysVinit を使い続けている場合:** chkconfig を使い続けることもできますが、将来的には systemd に移行することを検討すると良いでしょう。
* **初心者でどちらを選ぶべきかわからない場合:** systemd-sysv-generator の方がシンプルで使いやすいので、まずは systemd-sysv-generator を試してみることをおすすめします。

### 5. まとめ

**systemd-sysv-generator** と **chkconfig** は、どちらも Linux システムでサービスを管理するためのコマンドです。それぞれ異なる利点と欠点がありますが、どちらを使うべきかは状況によって異なります。

**初心者にとってどちらが使いやすいのか** は、それぞれの知識レベルや使用目的によって異なります。

**この比較が、どちらのコマンドを使うべきか判断する助けになれば幸いです。**

**参考**

https://qiita.com/nl-naoki/items/b6bd30fcc4714d70f4c0

https://qiita.com/nl-naoki/items/171f04e8d3904425b9e6
RHEL初心者向け！リポジトリとインターネットのURLの違いを徹底解説します


## RHELにおけるリポジトリとインターネットのURLの違い

RHELを使い始めたばかりの方向けに、リポジトリとインターネットのURLの違いをわかりやすく解説します。
実際の現場で、エラー文を読み解いたり、リポジトリの有効化・無効化で、インストールに躓いた経験から、理解しておいた方が良いと思い、記事にしております。

### インターネットのURL

インターネットのURLは、Webサイトやファイルを特定するためのものです。例えば、GoogleのURLは `https://www.google.com/` です。URLを入力すると、ブラウザはその場所にあるWebサイトやファイルを表示します。

### RHELにおけるリポジトリ

一方、RHELにおけるリポジトリは、ソフトウェアパッケージを格納するための場所です。RHELは、さまざまなソフトウェアパッケージをあらかじめリポジトリに用意しており、ユーザーはそこから必要なパッケージをインストールすることができます。

### それぞれの役割と違い

**役割**

-   インターネットのURL: Webサイトやファイルへのアクセス
-   RHELのリポジトリ: ソフトウェアパッケージのインストール

**違い**
## インターネットとRHELリポジトリの違い

| 項目 | インターネット | RHELのリポジトリ |
|---|---|---|
| 役割 |   Webサイトやファイルへのアクセス<br> ソフトウェアパッケージのインストール |  ソフトウェアパッケージのインストール |
| 内容 |   Webサイト、画像、動画、テキストファイルなど<br> ソフトウェアパッケージ（RPMファイル） |  ソフトウェアパッケージ（RPMファイル） |
| アクセス方法 |   ブラウザ、wgetなど |   yum、dnfなど |
| インターネットのURL |  [https://www.example.com/](https://www.example.com/) |   [https://example.repo.com/](https://example.repo.com/) |

**例**

-   Google Chromeをインストールしたい場合:
    -   インターネットのURL: [https://www.google.com/chrome/](https://www.google.com/chrome/) からChromeのインストーラーをダウンロード
    -   RHELのリポジトリ: `yum install google-chrome-stable` コマンドを実行

### RHELに書かれているリポジトリの意味

RHELの設定ファイルやマニュアルには、さまざまなリポジトリが記載されています。それぞれのリポジトリには、以下のような情報が含まれています。

-   リポジトリ名: リポジトリを識別するための名前
-   リポジトリのURL: リポジトリの場所
-   リポジトリに含まれるソフトウェアパッケージ: リポジトリからインストール可能なソフトウェアパッケージの一覧
-   有効期限: リポジトリの有効期限（古いリポジトリは無効になる場合があります）

**例**

```
[base]
name=Red Hat Enterprise Linux 9
baseurl=https://mirror.centos.org/centos/9/base/os/x86_64/
gpgcheck=1
enabled=1

[appstream]
name=Red Hat Enterprise Linux 9 AppStream
baseurl=https://mirror.centos.org/centos/9/appstream/os/x86_64/
gpgcheck=1
enabled=1

```

上記の例では、`base` と `appstream` という2つのリポジトリが設定されています。

-   `base` リポジトリには、RHELの基本的なソフトウェアパッケージが含まれています。
-   `appstream` リポジトリには、追加のソフトウェアパッケージが含まれています。

## まとめ

RHELのリポジトリは、インターネットのURLとは異なり、ソフトウェアパッケージをインストールするための専用の場所です。RHELをインストールすると、さまざまなリポジトリが設定されており、ユーザーはそこから必要なソフトウェアパッケージを簡単にインストールすることができます。

## 実務経験

実際に、インフラエンジニアとして勤務していた際、RHELのリポジトリを利用して、金融システムの検証用サーバー構築を行ってました。
具体的には、dnfコマンドを用いて、Apache HTTP ServerとtomcatとHinemosなど各種ミドルウェアをインストールしておりました。


**関連記事**

https://qiita.com/nl-naoki/items/b6bd30fcc4714d70f4c0

https://qiita.com/nl-naoki/items/e027d86103ab5ce47b9e
GoogleMapの「住所をコピーする」で取得した住所から郵便番号を外すPython3コード（Pythonista3対応）

# はじめに
本コードはPython3およびiOS版アプリPythonista3を用いて、iPhone版GoogleMapAppの住所の部分をコピペしたものから、郵便番号を抜き取るものです。

1. GoogleMapの住所部分をクリップボードにコピー
1. iOSの場合はPythonista3を起動
1. 本コードを実行
1. クリップボードに「住所」のみコピー
1. Pythonista3のコンソールに「郵便番号[改行]住所」を出力

という趣旨です。

# 用途
例えばiOSアプリ「乗換案内」の住所検索では郵便番号が入っている場合に、正常に検索してくれません。そのためGoogleMapアプリの目的地（あるいは出発地）から住所をコピペした後で、本コードを実行し、その後「乗換案内」にペーストして、住所タブを選択することで、郵便番号を削除する手間を省くといった利用方法があります。
（というか、そのためだけに作りました……）

# 前準備
Pythonista3は有料です。iOSでお使いの場合は別途お買い求めください。

# ソースコード
```python:google_address_V2.py
import sys

# クリップボードモジュール振り分け
try:
    import clipboard #Pythonista3用
    def copy_text_to_clipboard(text):
        clipboard.set(text)
    def paste_text_from_clipboard():
        return clipboard.get()
except ImportError:
    import pyperclip #Python3用
    def copy_text_to_clipboard(text):
        pyperclip.copy(text)
    def paste_text_from_clipboard():
        return pyperclip.paste()

# GoogleMap住所変換機能の本体
class ImportURL:  # クリップボードを取得するクラス
    def __init__(self):
        self.in_text = paste_text_from_clipboard()

class CaseAddress:  # 住所判定クラス
    def __init__(self, in_text):
        self.in_text = in_text
    
    def process(self):
        if '〒' in self.in_text[:2]:
            url = self.in_text[:9]
            text = self.in_text.replace(url, '')
            address = text.translate(str.maketrans({chr(0xFF01 + i): chr(0x21 + i) for i in range(94)}))
            address = address.replace('−','-')
            address = address.lstrip()
            url = url.replace('〒','')
            copy_text_to_clipboard(address)  # クリップボードに住所を設定
            address = address.replace(' ','\n')
            print(url)
            print(address)

# 実行部分
if __name__ == '__main__':
    importURL = ImportURL()
    in_text = importURL.in_text  # クリップボードからテキストを取得
    caseAddress = CaseAddress(in_text)
    caseAddress.process()  # 住所処理を実行
```

# 終わりに
クリップボードに貼付後、変換後の文章がコンソールに表示されます。
Next.jsを使用したAPIテストで発生した404エラーについて

問題

Next.jsにてAPIテストを行っていたところ用意したページが404エラーとなってしまった。



原因

単純なタイプミス。
「page」ファイルの名前が「pages」となってしまっていた。


恥ずかしすぎる内容だが戒めとして書き残す。
【Heroku】 error:0308010C デプロイ失敗

# はじめに
以下の環境でRailsアプリを作成し、Herokuにデプロイしようとしたところ、error:0308010C:digital envelope routines::unsupportedが発生。
原因はNode.jsとOpenSSLの互換性だったので、解決法を備忘録としてシェアします。

# 環境
Ruby 3系
Ruby on Rails 6.1系

# 解決手順
1. Heroku側で NODE_OPTIONS=--openssl-legacy-provider を設定。

    - 該当アプリケーション選択
    - Settingsへ
    - Config VarsでReveal Config Varsを押す
    - NOTE_OPTIONS, --openssl-legacy-provider を追加
    　
    ![Heroku setting](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/942638/3200b76d-d9e5-f2ad-f386-6d19947fe2fa.png)
    　
    ![スクリーンショット 2024-02-08 2.31.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/942638/853dfd86-c596-931a-1621-1386c23471d7.png)

　
2. production.rbに環境変数を追加
```ruby:config/environments/production.rb
ENV['NODE_OPTIONS'] = '--openssl-legacy-provider'
```
　
以上
# 参考
以下の記事を参考にエラーの解決ができました。感謝申し上げます:bow_tone1:

[Rubyと筋肉とギターとわたし](https://smot93516.hatenablog.jp/entry/2023/11/13/121530)
[【Heroku】 error:0308010C が発生してデプロイに失敗する場合の解決策](https://zenn.dev/yutonishi/articles/04d617d67eed73)
【忘備録】startActivity(intent)で画面遷移できずアプリが落ちる（なんで？）

### startActivity(intent)で画面遷移できず沼りまくったのでメモ

:::note info
Android 超初心者が画面遷移で沼ったので忘備録
:::


<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3694057/84fff2d1-4dd2-983f-c42a-d6d0af9bc37f.png">

<br>
<br>

#### MainActivity.kt のコードはちゃんと書いていた


```kotlin:MainActivity.kt
    // ボタンクリックで画面遷移
    val mBtn = findViewById<Button>(R.id.btn_1)
    mainBtn.setOnClickListener{
            val intent = Intent(this, MainActivity2::class.java)
            startActivity(intent)
    }
```

idも一致させていて、アラートとか一切出ていなかった。（デバッグも）
もちろん`import android.content.Intent`もちゃんと書いてた。
ただボタンを押すとアプリが強制終了する、なぜ？

<br>
<br>

#### <font color="red">Bottom Navigation Views Activity</font> の初期コードのせいだった

**MainActivity（遷移元）** は [Empty Views Activity] で作ってたが、**MainActivity<font color="red">2</font>（遷移先）** は [Bottom Navigation Views Activity] で作っていた。

<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3694057/effc5411-a67c-1a07-9574-5a9cfb5c882a.png">

<br>
<br>

#### MainActivity2 を生成した際、初期から入っているコードが干渉してたぽい

以下ソースの`// ここから`～`// ここまで`部分をコメントアウトすることで無事に画面遷移できた。

```kotlin:MainActivity2.kt
package com.example.gominohi

import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.TextView
import android.content.Intent

import com.google.android.material.bottomnavigation.BottomNavigationView
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import com.example.gominohi.databinding.ActivityMain2Binding

class MainActivity2 : AppCompatActivity() {

    private lateinit var binding: ActivityMain2Binding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main2)

        // ここから
        binding = ActivityMain2Binding.inflate(layoutInflater)
        setContentView(binding.root)

        val navView: BottomNavigationView = binding.navView

        val navController = findNavController(R.id.nav_host_fragment_activity_main2)
        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        val appBarConfiguration = AppBarConfiguration(
            setOf(
                R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications
            )
        )
        setupActionBarWithNavController(navController, appBarConfiguration)
        navView.setupWithNavController(navController)

        // ここまで
    }
}
```
<br>


初期で書いてくれてるコードを強引にコメントアウトしたけど、結局ナビゲーションビューの設定組むときに画面遷移できなくなりそう😢
<br>
初心者はまず [Empty Views Activity] で勉強してから他のActivityを使うようにしたほうがいいんだと大変勉強になりました。
Release-DrafterにUnityのProjectSettingsのバージョンを流し込みたい


# 結論

```
name: Release Drafter

on:
  push:
    branches:
      - stage

permissions:
  contents: read

jobs:
  update_release_draft:
    permissions:
      contents: write
      pull-requests: write
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: setup bundleVersion
        run: |
          BUNDLE_VERSION=$(cat Unityのプロジェクト名/ProjectSettings/ProjectSettings.asset | grep bundleVersion: | tr -d "bundleVersion: ")
          echo $BUNDLE_VERSION
          echo "BUNDLE_VERSION=$BUNDLE_VERSION" >> $GITHUB_ENV
      - uses: release-drafter/release-drafter@v5
        with:
          name: ${{ env.BUNDLE_VERSION }}
          tag: ${{ env.BUNDLE_VERSION }}
          version: ${{ env.BUNDLE_VERSION }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

# 何をやっているか

```
    steps:
      - uses: actions/checkout@v4
```
プロジェクト情報を得るため、チェックアウトする

```
      - name: setup bundleVersion
        run: |
          BUNDLE_VERSION=$(cat Unityのプロジェクト名/ProjectSettings/ProjectSettings.asset | grep bundleVersion: | tr -d "bundleVersion: ")
          echo $BUNDLE_VERSION
          echo "BUNDLE_VERSION=$BUNDLE_VERSION" >> $GITHUB_ENV
```
ProjectSettingsから`bundleVersion`を引っこ抜く

```
      - uses: release-drafter/release-drafter@v5
        with:
          name: ${{ env.BUNDLE_VERSION }}
          tag: ${{ env.BUNDLE_VERSION }}
          version: ${{ env.BUNDLE_VERSION }}
```
release-drafterの[Action Inputs](https://github.com/release-drafter/release-drafter?tab=readme-ov-file#action-inputs)を用いて、BUNDLE_VERSIONを流し込む


# 生成例
Unityの`bundleVersion`をタイトルに、リリースノート作ってくれる
![スクリーンショット 2024-02-08 1.50.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178486/d0509d06-c361-5477-75e1-241a21297421.png)
FTPサーバ作成備忘録・雑まとめ

## 概要
- 急にftpサーバを立ててみたいと思い立った
- 普段EC2にsshでWinSCPを用いてファイルをあげるのとほぼ変わらないうえに、SFTPやFTPSを利用しているわけでもないため、セキュリティがむしろ低下し、虚無っている( ᐛ👐)パァ

## やり方
https://go.dx.business/dev/aws/23874

↑の人のサイトにすべてまとまっている

唯一の注意点として、

```sh
 sudo systemctl restart vsftpd
```
をすべて設定したあとに実行しないと設定が反映されないため、設定が終了した場合に設定しなおす必要がある。

また、固定IPを吐き出さない場合は、　
```sh
 sudo vi /etc/vsftpd/vsftpd.conf
```
の中のＩＰに関する設定を毎回変更する必要があるので、普段使いをする場合は、必ず固定ＩＰを吐く必要があるだろう

## まとめ
比較的細かい設定まで記述しているサイトがあったため、簡単に作成することができた。
使い道に関してはおいおい考えていこうと思う、、
Cordova iOSでSafeAreaの有無判定で悩んだ件

CordovaでiPhoneアプリでも作ってみようかと、ちょっと手を出してみましたが、意外なところで、つまづいたのでメモ。

iPhone X以降、画面に切り込みが入り、「ノッチ」と呼ばれる部分が存在するようになりました。それで、iPhone SEやX以前には無かった画面上部の部分を、SafeAreaと呼ぶようです。

そして、この**SafeAreaの有無が簡単に取れないんです**！どうして？！

そして、散々調べて解決方法を見つけたので、ここにメモっておきます。

### 手順(1) CSSの準備

まず、以下のCSSを作成します。

```css:root.css
:root {
    --sat: env(safe-area-inset-top);
    --sar: env(safe-area-inset-right);
    --sab: env(safe-area-inset-bottom);
    --sal: env(safe-area-inset-left);
}
```

下記の通り取り込むようにしておきます。

```html:index.html
<link rel="stylesheet" href="css/root.css">
```

### 手順(2) JSで読み込む

以下のようなコードで、SafeAreaのサイズを得られます。「0px」とか「34px」とか得られます。整数で欲しければ`parseInt(getSafeAreaSize())`を実行します。

```js:get_safe_area_size.js
function getSafeAreaSize() {
    return getComputedStyle(document.documentElement).getPropertyValue("--sab");
}
```


### 参考

- (上記の解決作の元ネタ) https://stackoverflow.com/questions/47112393/getting-the-iphone-x-safe-area-using-javascript
- (端末と値の一覧) https://qiita.com/MJeeeey/items/a640922da33dacc0fc30
- (div作って設定して取得するようなJS関数を紹介している) https://tenderfeel.xsrv.jp/javascript/4775/
SAS Tips

SASに関する個人的Tips
個人の備忘録です。
誤りの指摘、アドバイス等歓迎します。



## SAS日付値の指定
### 様々な書き方

以下は同じ日付2024/01/01を表す。

```sas
input("01JAN2024", date9.)
input("20240101", yymmdd10.)
"01JAN2024"d
mdy(1,01,2024)
```

### YYYYMMDDTHHMMSSの形の変換

ISO8601形式の日時値の変換は
```sas
input(2024-01-01T00:00:00, e8601dt.)
```


00:00:00を代入する方法
```sas
dhms( input( 2024-01-01T12:34:56, e8601da. ) ,0,0,0) ;
```


### Excelの日付値を読んでしまった場合の対応
```sas
sasdate = XlsWinDate + 21915;
```

### データセットを縦結合するとき、文字切れさせない方法

```sas
proc sql;
   create table datax as
   select * from data1
      union
   select * from data2;
quit;
```

## 参考にさせていただいたページ

https://how-to-business.com/%E3%80%90sas%E3%80%91sas%E3%81%A7%E6%97%A5%E4%BB%98%E3%82%92%E6%89%B1%E3%81%86%EF%BC%88%E5%B9%B4%E6%9C%88%E6%97%A5%EF%BC%89%E3%80%90d%E3%80%91-%E3%80%90year%E3%80%91%E3%80%90month%E3%80%91/

https://wikiwiki.jp/cattail/SAS%E3%81%AE%E6%99%82%E9%96%93%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E6%A6%82%E5%BF%B5

https://sas-boubi.blogspot.com/2017/10/cdisc-dtc-adtm-adt-atm_5.html

https://sas-boubi.blogspot.com/2015/01/sql14union.html
Blueskyのフィードを作ってみた

## Bluesky
Blueskyが招待コードなしで始められるようになったので、フィードを作ってみたいと思います。
### 手順
1. Blueskyのアカウントを作成
1. アプリパスワードを作成
1. SkyFeedと連携
1. フィードを作成・公開

## アプリパスワードを作成する
Blueskyにログイン

https://bsky.app/

「設定」→「アプリパスワード」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684438/a3af69e6-6a77-5620-da83-51b65583aef6.png)

「アプリパスワードを追加」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684438/8908ef28-4382-c687-42b4-8a10c4384439.png)

好きな名前を入力し「アプリパスワードを作成」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684438/90911230-7ac8-c7aa-db35-adaf616326eb.png)

アプリパスワードを保存し「完了」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684438/62489584-12b4-4794-cb4c-7c00fff117f7.png)

## SkyFeedと連携する

SkyFeedにアクセス

https://skyfeed.app

ユーザー名とアプリパスワードを入力し「Continue」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684438/838dad2b-58d9-b3c1-df6b-072396cd6af6.png)

## フィードを作成する

「Feed Builder」→「Create your first feed」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684438/80882df2-b5e3-924d-f332-00ffcb385301.png)

フィードの条件を決めたら「Publish Feed」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684438/95157289-3bd0-d862-8d58-f2fe9fc5fd68.png)

フィードの概要を入力し「Publish」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684438/7ad1f5b6-84b2-ea9a-199c-909c0cf5a75c.png)

フィードの作成と公開が完了し、URLが表示されました。
（ブックマークアイコンを押すと、マイフィードに登録できました）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684438/b9f27aae-bbe8-30b4-f549-76dbed52c311.png)

## 終わりに
フィードで検索条件を共有できるので、リストと違った使い方ができそうだと感じました。
もっと使いこなせるように少しずつ触っていこうと思います。
~~（SkyFeedでTweetDeckみたいな事したいな…）~~

## 参考
- [モデレーションとカスタムフィード](https://blueskyweb.zendesk.com/hc/en-us/articles/19002427251981-Moderation-and-Custom-Feeds)
- [SkyFeedのFeed Builderを使ってカスタムフィードをつくる](https://scrapbox.io/Bluesky/SkyFeed%E3%81%AEFeed_Builder%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0%E3%83%95%E3%82%A3%E3%83%BC%E3%83%89%E3%82%92%E3%81%A4%E3%81%8F%E3%82%8B)
- [blueskyのカスタムフィードの作り方](https://immature.01kawa.com/sns/bluesky/customfeed/)
GETとPOSTの違いを安全と冪等を踏まえて説明

お疲れ様です。翔太です。
今回は、GETとPOSTの違いについて、まとめていきたいと思います。

# GETとは

指定したリソースの表現を転送するようにリクエストするメソッドです。
何が情報を検索したり取得するために使います。

例えば、ブラウザでURLを入力し検索するときには、GETメソッドを使っています。

また、仕様で**安全かつ冪等(べきとう)** であると定義されているため、基本的に読み取り専用な機能に対して使うべきメソッドになる。

GETを使うとどのような処理をしていたとしてもクライアントには安全なAPIだと
見なされます。

これは、クライアントからはサーバがどのような処理をやっているかを知ることはできないためです。

# POSTとは

POSTは指定したリソースを実装した機能に従って処理をする機能になります。

主に**登録処理や更新処理などの書き込みがあり、リソースが更新される可能性のある処理に対して使うメソッド**になります。

例えば、以下のような例があります。

- HTMLの `<form></form>`に入力された内容をDBへ登録する
- ブログの記事を投稿する
- 新しいユーザを登録する
- 既存のデータに新しい情報を付加する

また、GETとは反対に**冪等でないかつ安全でない**と定義されています。

# HTTPメソッドにおける冪等、安全、副作用とは何か
ここまでの話で、冪等と安全って何？って思いませんでしたでしょうか？
私は無茶苦茶思いました。POSTは安全じゃねーの？、冪等ってそもそも何？ってね
なので、ここでは、冪等と安全、そして、それを説明するのに必要な副作用について説明していきたいと思います。

### 副作用とは
    
安全と冪等を語る上で重要な表現であるため、ここで解説します。

クライアントにより意図されたものを「主たる作用」と言います。
逆に、**クライアントにより意図されていないものを副作用**とする。

つまり、クライアントによって意図されていない動作や状態の変化、データの揺らぎなどが起こってしまうこと全般を副作用が生じると言います。
    

### 安全とは
    
HTTPリクエストメソッドにおける「安全」とは、「リソースの状態を変化させない読み取り専用であること」を言います。

それ以外の作用は副作用であり、制限もかけられず、責任も負えないものとされてる。

そして、「安全」を定義する目的は、クローラーや、キャッシュ機構のパフォーマンスを正常に機能させることや、クライアントに「リソースの状態の変化」を伴う作用と伴わない作用の区別を事前に知らせることができるようにするためとされています。

つまり、「安全」とは、「**リソースの状態に変化が生じることのない**」メソッドです。
例えば、GETはリンクにリソースを含み、ブラウザに設定することでリクエストを送ると、受け取ったサーバはその**リクエストに応じたデータを何のデータの変更もせずにレスポンスで返却**する。

これは結果として、サーバ側でデータをいじることがないため、サーバ側に何の危害も与えることのない安全なメソッドであると言えます。

リソースの状態の変化って何だよと感じる方もいらっしゃると思うので説明しておくと、
**サーバー側が用意したデータに対してリクエストの内容によって、変更を加えてレスポンスとして返すこと** を**リソースの状態の変化** と言います。

逆にPOSTなどの処理は、サーバー側でデータの状態の変更(データを追加、更新、削除)される可能性があるため、安全とは言えません。

**安全メソッド：**

- HEAD
- GET
- OPTIONS
- TRACE
    
### 冪等とは
    
HTTPリクエストメソッドにおける「冪等」とは、「**同一パラメータで1回以上リクエストしても、リソースの状態が同じであること**」をいいます。

それ以外の作用は副作用であり、副作用も実装可能とされます。

もしクライアントがサーバーからのリクエスト成功の応答を受信する前に通信障害が発生した場合、クライアントはリクエストを再度送り、そのリクエストの目的を達成する必要があります。
サーバーはそのリトライによるリソースの不整合から保護しなければなりません。
さらに、クライアントは、同じリクエストを再度送るとリソースの整合性が破壊されるとなれば、リトライはできなくなるでしょうし、そのリトライによりリソースの整合性が保護されるのか、破壊されるのかを知らなければ無闇にリトライもできなくなるでしょう。

したがって、サーバーはこのような堅牢性を確保するとともに、クライアントにリトライ可否の区別を知らせなければなりません。

つまり、クライアント側からリクエストを再送した際にデータが変わる場合、得たいデータが取得できなくなってしまう。
また、もしリクエストを再送することで、データが変更されてしまう可能性があるとなれば、リクエストの再送ができなくなってしまうと言うことです。
    
**冪等メソッド：**

- PUT
- DELETE

### HTTPメソッドにおける安全かつ冪等であるとは何を指すのか？
    
簡単に言うと、同一のパラメータで1回以上リクエストを送った場合に、**リクエストに応じたデータを何のデータの変更もせずにレスポンスとして返却する。**

そして、**その返却したリソースの状態が前回と同じ結果であること**が安全かつ冪等といえます。

## 結論(GETとPOSTの違い)
上記の話でわかったと思いますが、GETは冪等かつ安全、POSTは逆に、冪等ではないし安全ではありません。

つまり、簡単に言えば、クライアントがリクエストを送信する際に、
「**同一のパラメータで1回以上リクエストを送った場合に、リクエストに応じたデータを何のデータの変更もせずにレスポンスとして返却する。**」と言う条件に合うならば、GETメソッドを使う。そうでないならば、POST(PUTやDELETEなどもあります)を使ったらいいと言うことになります。


上記の理由から、GETメソッドは検索などで使われますし、POSTメソッドは、データベースの更新処理などに使われるわけですね。

また、HTTPメソッドには、キャッシャブル(キャッシュ可能)かどうかがメソッドごとに定義されています。
GETはキャッシュできますが、POSTはキャッシュできないこともあるため、そう言う点においてもGETの方が適しているとしてGETメソッドを用いる場合もあります。


## 参考サイト
https://qiita.com/kanataxa/items/522efb74421255f0e0a1
https://qiita.com/KyojiOsada/items/9c8db9714a0c9c72823c
【日記？考察？】pluckメソッドとfind_byメソッドはどこで使うのか

こんばんは！
今まであまり使う機会がなかったメソッドをこの機に理解しよう！とおもったのですが、
pluckメソッドの使いどころがいまいちピンとこず、
今回は**pluckメソッド**と**find_byメソッド**について考えてみるというふわっとした感じです:cactus:
(現在DM機能がうまく実装できず煮詰まり中。。。)

## pluckメソッドはどんな時に使う？
> pluck メソッドは、指定されたカラムの値を直接データベースから取得し、ActiveRecord オブジェクトのインスタンス化をせずに値の配列として返します。これは特に、カラムの値を素早く配列として取得したい場合に便利です。

↑引用元は[こちら](https://zenn.dev/kumasaka/articles/d17ddda0c9476b)

初心者(私)はこれでもすぐ理解できなかったので、自分の言葉に直して使った状況も踏まえながら説明してみたいと思います。

ということで、私がどういうタイミングでpluckを使う流れになったのか考えてみました。

まさに絶賛煮詰まり中のDM機能実装の際、
ログイン中のユーザーがもっているチャットルームのidをpluckメソッドを用い
すべて参照した後、相互フォローしている相手とのチャットルームのid(バリデーションで2つ以上作れないようにしてある)をfind_byメソッドを使って引っ張り出し、そのチャットルームのidがpluckメソッドで参照したすべてのチャットルームのidの中に一致するものはあるか確認し、一致するものがなければnilが返ってくるというものでした。(あればそのチャットルームに入り、なければチャットルームを新規作成の流れ)
ここから分かったことは、pluckで探す値というのは引用にあるように指定されたカラムの内容の配列(値のみ)なので、そのあと何かと比較するという用途に使う際は処理が素早くなるため便利ということでした。
うーん、分かったような分からないような、、、いつか理解できる時が来たらまとめます:sob:

## find_byメソッドはどんな時使う？
先ほど登場したfind_byメソッド、こちらは理解できたのでまとめてみます。
普段よく使うfindメソッドでは.find(params[:id])のように用いて、idとそのidが持つ他のカラムの情報もすべて参照できます。一方、find_byメソッドはfindが含まれているので探すことには間違いありませんが、値の出し方が違います。
find_byメソッドでは、find_by(:id)やfind_by(:email)などメソッドの後ろにカラムを指定し、その指定したカラムの最初に見つかった値のみ参照できます。
すごく簡単に言い換えると、あるか無いか確認したいときに使用します。
こんな時に使えます。↓

>一件しかヒットしないレコードに対して使用
unique制約がかかっているカラムに対して使用
完全一致以外での検索に使用(あいまい検索等、完全一致よりも使用頻度は少ない)

引用させていただいたリンクを貼ります。多分世界一わかりやすいです。

https://pikawaka.com/rails/find_by

### 最後に
今日はDM機能をうまく実装できず、悩んでばかりの1日でしたが明日から気持ちを切り替えて頑張っていきたいと思います！悩んでいたら日付を超えてしまった、、！みなさんおやすみなさい！

追記：
DM機能解決しました:blush:
Git リポジトリを作ったときに大体実行するコマンドたち

## 概要

リポジトリを作ったときに大体実行するコマンドたちを簡単にまとめます。（筆者の場合です。）

## 詳細

実行する順番に羅列しておく。

```shell
git init
git config --local user.name '自分の名前'
git config --local user.email '自分のメールアドレス'
git branch -M main
git commit --allow-empty -m "first commit"
git remote add origin リモートリポジトリアドレス
git push -u origin main
touch README.md
git add README.md
git commit -m "READMEの追加"
git push origin main
```

このあとはREDMEを記入してコミットしたり、その他のファイルをコミットしたりする。
自宅のIPアドレスがコロコロ変わって、都度IPを更新するのがめんどくさい

## 想定読者
- 自宅のIPアドレスが頻繁に変わってAPIリクエストの制限に引っかかり、都度IP許可していてめんどくさいという方
- sshサーバー・socksproxy経由でリモートサーバーにアクセスしようとしたが、[グローバルIPアドレス](https://www.cman.jp/network/support/go_access.cgi) が変わらずアクセスできないよという方


## ConoHa VPSでIPアドレスを固定し、ssh接続・socks proxy経由でリモートサーバー(APIサーバー)にアクセスする手順
### 1. [ConoHa VPS](https://www.ConoHa.jp/vps/?btn_id=login--commonHeader_vps-top)を契約、固定のIPアドレスを取得
### 2. .ssh/configにConoHa VPSの情報を追加
configファイルがなければ作る
```.ssh/config
Host conoha
  HostName XXX.XXX.XXX.XXX // ConoHa VPSのIPアドレス
  Port 22
  User root
  IdentityFile ~/.ssh/some.pem
```
### 3. .ssh/にConoHaVPS契約時に取得した秘密鍵ファイル(some.pem)を置く
ssh接続時にエラーが発生することがあるため、秘密鍵ファイルのパーミッションが適切に設定されていることを確認する。
不適切な場合は次を実行。
```chmod 400 ~/.ssh/some.pem```
### 4. ssh接続
```ssh -D 10080 conoha```を実行
### 5. socks proxy経由でアクセスする
システム設定 > Wi-Fi > 接続中のWi-Fiの詳細 > プロキシ > SOCKSプロキシをONしてポートを10080に設定 > OK

これで[IPアドレスを確認](https://www.cman.jp/network/support/go_access.cgi)すると、ConoHaVPSのIPアドレスに**変わるはずだった**。:dizzy_face:
けど変わらなかった。


## グローバルIPアドレスが変わらなかった原因
- 起きていたこと
Chromeで[IPアドレスを確認](https://www.cman.jp/network/support/go_access.cgi)すると、ConoHaVPSのIPアドレスではなく自宅のIPアドレスのままだった。しかし、safariでアクセスするとConoHaVPSのIPアドレスになっていた。
- 何が原因だったか
おそらく、Chromeブラウザがsocksプロキシを使用してアクセスしない設定になっていたこと。
[Chromeのプロファイルを作り直す](https://atmarkit.itmedia.co.jp/ait/articles/1906/05/news019.html#create)ことで解決した。

解決まで導いてくださった大先輩に感謝🙏🙏🙏



## 試したけどダメだったことも一応載せておく
- socks proxyの設定をコマンドから
```
sudo networksetup -setsocksfirewallproxy Wi-fi localhost 10080
sudo networksetup -setsocksfirewallproxystate Wi-fi on
```

- chromeのキャッシュ削除
[chrome://net-internals/#dns](chrome://net-internals/#dns)にアクセスして、
  - DNSのClear host Cacheを押す
  - ProxyのClear Bad proxiesを押す



## なぜsshサーバーを踏み台・socks proxy経由で接続する必要があるのか
sshはリモートコンピューターに安全に接続するため。ネットワーク上でデータを暗号化することにより、セキュリティを確保しながらリモートマシンへのログインやファイル転送を可能にする。
SOCKSプロキシ経由で接続すると次のメリットがある。
1. セキュリティ強化: SOCKSプロキシを使用すると、クライアントとサーバー間の通信がプロキシサーバーを経由するため、直接的な接続が行われず他者から攻撃されにくくなる。
2. ファイアウォールやNATの回避: 企業や学校などのネットワークでは、ファイアウォールやNATによってインターネットへのアクセスが制限されている場合がある。これらの制約を回避して接続することができる。
3. 匿名性の向上: SOCKSプロキシを介して通信することで、実際のIPアドレスを隠し、匿名性を高めることが可能。



## 参考にさせていただいた記事🙏
https://qiita.com/YumaInaura/items/7e4c9335e0f07b64319d
https://qiita.com/YumaInaura/items/7e1fcf9c23e7ba15e25b
Reactにおける状態管理と日付操作の落とし穴

# Reactにおける状態管理と日付操作の落とし穴
Reactで状態（state）として管理されている日付オブジェクトの操作は慎重に行う必要があります。特に、moment.jsを使用して日付の状態を更新する場合、不用意な操作が予期せぬ副作用を引き起こす可能性があります。

## 問題の発生
例えば、ライブ配信アプリケーションにおいて、配信の終了時刻を管理する`endDate`という状態があるとします。配信が現在進行中か終了したかを判定するために、次のようなコードが書かれているかもしれません：

```javascript
setIsLiveEnded(moment().isAfter(endDate.endOf('day')));
```
このコードは、現在時刻がendDateが指す日の最終時刻（23:59:59.999）を過ぎているかどうかを判断します。問題は、`endDate.endOf('day')`の呼び出しによって`endDate`自体が変更され、その結果がReactの状態に永続される点にあります。

## 解決策
この問題の解決策は、endDateのクローンを作成し、そのクローンに対して操作を行うことです。これにより、元の状態オブジェクトは変更されずに済みます：

```javascript
setIsLiveEnded(moment().isAfter(moment(endDate).clone().endOf('day')));
```
このアプローチにより、endDateの値を直接変更することなく、目的の日付の最終時刻と現在時刻を安全に比較することができます。

## 結論
Reactやその他のフロントエンドフレームワークにおいて、状態として管理されているオブジェクト（特に日付オブジェクト）に対する操作は、副作用を避けるために慎重に行う必要があります。moment.jsのようなライブラリを使用する場合は、オブジェクトのクローンを作成して操作することで、状態の不意な変更を防ぐことができます。これにより、アプリケーションの予測可能性と信頼性が向上します。
HTML + jsでバリデーションチェックをしてみた

## 概要

出落ち感すごいんですがタイトル通りです。「HTMLに適当にstyleタグでCSSを、scriptタグでjsを記載してsubmitボタン起点で入力内容をチェックする。内容がイケてなかったらエラーを出す。」というものを作ってみました。

## 詳細

コードはGithubに上げました。README.mdをお読みいただき実際に簡単に体験いただく事ができます。

https://github.com/miriwo0104/html_css_javascript_validation
svnやgitをシェルスクリプトで使う

# 1
このスクリプトは、指定されたSubversion (SVN) リポジトリからzipファイルをエクスポートし、そのzipファイルを解凍して、特定のスクリプト（スクリプトA）を実行した後、ダウンロードしたzipファイルと解凍したファイルを削除します。スクリプトAの実際の名前と、エクスポートするzipファイルのSVNパスを適宜置き換えてください。

```bash
#!/bin/bash

# SVNからzipファイルをエクスポートするためのURL
SVN_URL="your_svn_repository_url_here"
# エクスポートするファイル名
ZIP_FILE_NAME="exported_file.zip"
# スクリプトAのパス（ここを適宜書き換えてください）
SCRIPT_A_PATH="./scriptA.sh"

# SVNからzipファイルをエクスポート
svn export $SVN_URL $ZIP_FILE_NAME

# zipファイルを解凍
unzip $ZIP_FILE_NAME

# スクリプトAを実行
bash $SCRIPT_A_PATH

# エクスポートしたzipファイルと解凍したファイルを削除
rm $ZIP_FILE_NAME
rm -r $(basename $ZIP_FILE_NAME .zip)

```

このスクリプトを使用する前に、いくつかの点を確認してください：

1. `svn` コマンドがシステムにインストールされている必要があります。
2. `unzip` コマンドも同様にインストールされている必要があります。
3. スクリプトAが存在し、実行可能であることを確認してください。
4. SVNのURL (`SVN_URL`) とzipファイルの名前 (`ZIP_FILE_NAME`)、スクリプトAのパス (`SCRIPT_A_PATH`) を実際のものに置き換えてください。

このスクリプトを保存し、実行可能にするためには、ファイルに実行権限を付与する必要があります。これは、ターミナルで以下のコマンドを使用して行います：

```bash
chmod +x your_script_name.sh
```

その後、スクリプトを以下のコマンドで実行できます：

```bash
./your_script_name.sh
```
# 2
スクリプト実行時に引数を受け取り、その引数に基づいてエクスポートするURLを切り替えるようにスクリプトを修正します。以下のスクリプトでは、最初の引数（`$1`）をエクスポートするURLとして使用します。引数が提供されない場合は、スクリプトはエラーメッセージを表示して終了します。

```bash
#!/bin/bash

# 引数の確認
if [ "$#" -ne 1 ]; then
    echo "使用法: $0 <svn_repository_url>"
    exit 1
fi

# 引数からSVN URLを取得
SVN_URL=$1

# エクスポートするファイル名
ZIP_FILE_NAME="exported_file.zip"
# スクリプトAのパス（ここを適宜書き換えてください）
SCRIPT_A_PATH="./scriptA.sh"

# SVNからzipファイルをエクスポート
svn export $SVN_URL $ZIP_FILE_NAME

# zipファイルを解凍
unzip $ZIP_FILE_NAME

# スクリプトAを実行
bash $SCRIPT_A_PATH

# エクスポートしたzipファイルと解凍したファイルを削除
rm $ZIP_FILE_NAME
rm -r $(basename $ZIP_FILE_NAME .zip)
```

この修正により、スクリプトはコマンドライン引数として指定されたURLからzipファイルをエクスポートします。スクリプトを実行するには、次のようにターミナルでコマンドを入力します：

```bash
./your_script_name.sh your_svn_repository_url_here
```

ここで、`your_script_name.sh` はスクリプトファイルの名前、`your_svn_repository_url_here` はエクスポートしたいSVNリポジトリのURLです。引数を変えることで異なるリポジトリからファイルをエクスポートできます。

# 3
このスクリプトは、gitリポジトリから特定のタグに基づいてソースコードをクローンし、ソースコード内で定義されている`#define HOGE`の値を検索して表示し、その後取得したソースコードを削除します。

```bash
#!/bin/bash

# 引数の確認
if [ "$#" -ne 2 ]; then
    echo "使用法: $0 <git_repository_url> <tag_name>"
    exit 1
fi

# 引数からリポジトリURLとタグ名を取得
GIT_REPO_URL=$1
TAG_NAME=$2

# 一時ディレクトリを作成し、そこにクローン
TEMP_DIR=$(mktemp -d)
git clone --depth 1 --branch $TAG_NAME $GIT_REPO_URL $TEMP_DIR

# ソースコードの中から#define HOGEを探して表示
grep -R '#define HOGE' $TEMP_DIR | awk '{print $3}'

# 取得したソースコードを削除
rm -rf $TEMP_DIR
```

このスクリプトは、`<git_repository_url>`と`<tag_name>`の2つの引数を必要とします。`git_repository_url`はクローンしたいGitリポジトリのURLで、`tag_name`はソースコードを取得するタグ名です。

スクリプトを保存し、実行可能にするには、ファイルに実行権限を付与します。これは、ターミナルで以下のコマンドを使用して行います：

```bash
chmod +x your_script_name.sh
```

その後、スクリプトを以下のコマンドで実行できます：

```bash
./your_script_name.sh git_repository_url tag_name
```

ここで、`your_script_name.sh`はスクリプトファイルの名前、`git_repository_url`はGitリポジトリのURL、`tag_name`はソースコードを取得したいタグ名です。`#define HOGE`の右側にある文字列は、スクリプトが見つけたすべての場所から表示されます。
Laravel アクセさについて

## Laravelのアクセさについて
データベースからデータを取得したときに動く処理、ざっくり書くとモデルのプロパティの値を加工する処理のこと

[Laravel公式サイト アクセサ／ミューテタ](https://readouble.com/laravel/10.x/ja/eloquent-mutators.html)


## アクセサの使い方
```
Foodモデル

protected $fillable = [
・・・
    'info',
・・・
];

DBから取得したinfoの値の後ろに「最高」と追加
public function getDisplayInfoAttribute(): string
{
    return $this->info . '最高';
}

----------
bladeファイル
<body>
    @foreach ($foods as $food)
        <div>{{ $food->info }}</div>
        <div>{{ $food->displayInfo }}</div>
    @endforeach
</body>

----------
infoの値がお肉とハンバーグがある場合、表示は以下のようになります
お肉
お肉最高
ハンバーグ
ハンバーグ最高

```
AppleからMLXが発表された

# 概要
MLXはNumpyのような使い心地で設計されており、トランスフォーマー言語モデルのトレーニング、大規模なテキスト生成、テキストのファインチューニング、画像生成、音声認識などをAppleシリコン上で実行することができます。

MLXを使用することでApple siliconを最大限に活かすことができるとされている。

# 動作環境
MLXを使用するにはApple siliconを搭載したMacが必要になります。

MacOSは13.3以上  いわゆるVenturaです。Sonomaにしてあれば間違い無いです。公式文書ではSonomaでの使用を強く勧めています。

Pythonは3.8以上で動作するようです。
# インストール
MLXのインストールにはターミナルで以下のコマンドを実行します。(Python3の場合)
```:Python
pip3 install mlx
```

# 活用方法
こちらのGitHubに機械学習のモデルがいくつかあります。
https://github.com/ml-explore/mlx-examples/tree/main
「なぜchatgptを使わなければならないか」

#  「なぜchatgptを使わなければならないか」

これを別の言葉に言い換えたい
##  「なぜ新しいこと・ものに飛びつかなければならないか」
理由は世界は後戻りせず変わり続けているから。
俗な例えを引用すると、
### 「googleで検索できるなら、暗記しなくていいじゃん」
この言葉を全面的に支持する。
すべて記憶してなくても、検索エンジンで検索すればいいし、
計算の達人にならなくても、計算機を使えばいい。
単純作業ならプログラムを書いて、自動にしたらいい。
そういうと、
### 「計算力や記憶力がなければ、頭が悪くなる」
### 「そういった我慢、反復の経験がなければ人として成長できない」
といった反論がありそう。
ほんとにそうだろうか？
頭のいい人間の例として数学者を挙げるなら、彼らはどのように
仕事を行っているか？彼らは紙とペンと使い数式を解いている。
それも同じことではないだろうか？
それを見て反論する人たちは、同じように現代の数学者を批判しなければならない。
### 「現代の数学者は紙に書かないと自分の考えを記憶も計算もできない大馬鹿である」
### 「ましては、コンピュータを使わなけれ複雑な計算ができないぼんくらである」
この批判に対して多くの人は喜んで賛同できないはず。
人間はこれまで、単純な機能を外部に受け渡し、自分の思考の範囲を広げていった。
工学、物理、化学などによって人間は多くのことが出来るようになった。
頭の良さだけではない。肉体的なことでも同じで、
ウサイン・ボルトが本気で走ろうが、新幹線と比較にならないほど遅く、
どれだけの力自慢の巨漢も大型トラックに引かれてしまえば簡単に死ぬように。
つまり、何が言いたいかというと個体の修練よりはるかに外部を機能として利用する方が生産性も結果も圧倒的に大きい。
ならば、新しいものは試そうという話。
また、競争の観点から話そう。先ほど、「個体の修練よりはるかに外部を機能として利用する方が生産性も結果も圧倒的に大きい」といった。そうなると、ある新しい技術が出てきたとき、その中の集団であなた一人ががその技術を活用するなら他者を圧倒出来る。熟練の職人を一日で抜きさることが出来る。新しいものを100回試して1回でも成功すれば、周りを圧倒出来る。99回の失敗も初期段階では致命傷にならない。取り残された人間が出来る選択は二択。自分も技術を取り入れ２匹目のどじょうを狙うか、自分の今やっている範囲内だけで死ぬまで威張り散らすか。私はどちらも悲惨に見える。
ChatGptを使ってみよう。
バージョン管理の命名規則　セマンティックバージョニング

初歩的な話だが、
セマンティックバージョニングという言葉を聞いて今まで流していたが。
ふと考えてみるとセマンティックバージョニングって何なんだろう？と思った。

今まではバージョン管理方式ぐらいの軽い認識しかなかったので、
これを期に調べてみた


## セマンティックバージョニングとは？
一般的によく目にする
「v1.23.45」
のようなバージョニング方式(バージョン管理の命名規則)のことを指して呼ぶ。

メジャーバージョン.マイナーバージョン.パッチバージョンの3つのセグメントから構成される。

そして、それぞれ変更内容によって、
「どのセグメントのバージョンの数をインクリメントするか？」
決まっているらしい。


- メジャーバージョン：互換性のない場合に上げる
- マイナーバージョン：後方互換性がある機能追加した場合マイナーバージョンを上げる
- パッチバージョン：後方互換性のあるバグ修正、パッチバージョンを上げる


仕様書を書いたのは、Gravatarの考案者であり、GitHubの共同創設者である
Tom Preston-Werner氏だそうだ。



https://semver.org/


## なぜ使用するのか？
仕様書を読んでみた。

>なぜセマンティック バージョニングを使用するのか？
>　このアイデアは新しいものでもなければ、革新的なものでもありません。実際、みなさんも似たよう>な取り組みを既におこなっているかもしれません。問題は「似ている」のでは不十分だということです。正式な仕様書による取り決めがなければ、バージョンナンバーは依存性の管理において基本的には無意味です。上記のアイデアに対して名前と正確な定義を与えることよって、あなたの開発するソフトウェアにおいて、あなたの意図がユーザーに対して伝わりやすくなることでしょう。一度、これらの意図を正確にしてしまえば、柔軟な（しかし、柔軟すぎてはいけない）依存性の仕様を作ることができます。

それまで、明確なルールがあるとは知らなかった。
というより、気にしていなかった。



## 感想

>**問題は「似ている」のでは不十分だということです。正式な仕様書による取り決めがなければ、バージョンナンバーは依存性の管理において基本的には無意味です。**

読んでいて、すごくドキッとした。
今後は、ちゃんと仕様書に従った管理をしたい
【JavaScript】フォームを送信する方法

## `submit()`

以下のように記述すると`submit()`を使用してフォームを送信できます。

```html
<form action="/changename">
  <label for="name">名前</label>
  <input type="text" id="name">
</form>

<button>Change name</button>
```

```js
const btn = document.querySelector('button')
const form = document.querySelector('form')

btn.addEventListener('click', () => {
  form.submit()
})
```

ただし、`submit()`でフォームを送信した場合には、

- submit イベントは発生しません
- 制約検証は行われません

https://developer.mozilla.org/ja/docs/Web/API/HTMLFormElement/submit

## `requestSubmit()`

`requestSubmit()`を使用してもフォームを送信できます。


```html
<form action="/changename">
  <label for="name">名前</label>
  <input type="text" id="name" required>
</form>

<button>Change name</button>
```

```js
const btn = document.querySelector('button')
const form = document.querySelector('form')

btn.addEventListener('click', () => {
  form.requestSubmit()
})
```

`requestSubmit()`でフォームを送信した場合には、
- submitイベントが発生します
- 制約検証は行われます

https://developer.mozilla.org/ja/docs/Web/API/HTMLFormElement/requestSubmit
Hugoで久しぶりにbuildしたらERROR render of "page" failedになった

# はじめに

年に1、2回の頻度でしか更新しないものの、そこそこ複雑な構成のHugoプロジェクトがあります。

これは同じ頻度で更新されるCSVデータに強く依存していて他のプロジェクトと統合することが難しく、メンテナンスは頻繁には行っていません。

データを更新したのでコンテンツを生成したところ、Hugoのバージョンが上がっているためエラーになってしまいました。

エラーメッセージで検索すると主な原因はGoのテンプレートライブラリが変更されたことのようだとは分かったのですが、根本原因は複数あるようですぐに解決できなかったのでまとめておきます。

# 原因が異なるGo Templateに関連した類似の障害情報

* https://stackoverflow.com/questions/73675601/go-1-19-error-executing-template-range-branches-end-in-different-contexts
* https://groups.google.com/g/golang-nuts/c/0HJoROz2TMo
* https://qiita.com/matopenKW/items/015b171624b0b5882a51

# エラー#1. js.Build

```text:エラーの内容
Start building sites … 
hugo v0.122.0+extended linux/amd64 BuildDate=unknown

ERROR render of "page" failed: ".../layouts/_default/baseof.html:4:7": execute of template failed: \
  template: _default/single.html:4:7: executing "_default/single.html" at <partial "head.html" .>: \
  error calling partial: ".../layouts/partials/head.html:23:54": execute of \
  template failed: template: partials/head.html:23:54: \
  executing "partials/head.html" at <js.Build>: error calling Build: no Resource provided in transformation
...
```

## 対応

HugoでJavaScriptのコードをminifyした後の処理で問題が発生しています。
この場合の原因は元のHTMLコードにありました。

最後の**no Resource provided in transformation**のメッセージが示しているように変換対象のファイルにアクセスできなくなっていることが原因です。

元のコードは次のようになっています。

```html:
{{- $jsdefault := resources.Get "js/default.js" | js.Build (dict "minify" "true") }}
<script type="text/javascript" src="{{ $jsdefault }}"></script>
```

これは"js/default.js"がassetsディレクトリに存在しないことが原因でした。static/jsディレクトリから必要なファイルをassets/jsディレクトリに移動し、js.Buildが無事に動作しました。

# エラー#2. 空のHTMLコメント

また似たようなエラーですが、少し内容の違うメッセージが出現しました。

```text:別のエラーメッセージ
Start building sites … 
hugo v0.122.0+extended linux/amd64 BuildDate=unknown

ERROR render of "page" failed: ".../layouts/_default/baseof.html:4:6": execute of template failed: \
template: summary/single.html:4:6: executing " summary/single.html" at <partial "head.html" .>: error calling partial: \
execute of template failed: html/template:partials/head.html: \
ends in a non-text context: {stateJS delimNone urlPartNone jsCtxRegexp attrNone elementScript <nil>}
Total in 35 ms
```

この時は次のようなHTMLコードに問題がありました。

```diff
--- a/.../hugo/layouts/partials/head.html
+++ b/.../hugo/layouts/partials/head.html
@@ -26,7 +26,7 @@
 {{ $style := resources.Get "sass/default.scss" | toCSS | minify | fingerprint }}
 <link rel="stylesheet" type="text/css" href="{{ $style.RelPermalink }}" />
 {{ $jsdefault := resources.Get "js/default.js" | js.Build (dict "minify" "true") }}
-<script type="text/javascript" src="{{ $jsdefault.RelPermalink }}" ></script>
+<script type="text/javascript" src="{{ $jsdefault.RelPermalink }}" ><!-- --></script>
 
 <!-- print specific settings -->
 {{ $style := resources.Get "sass/print.scss" | toCSS | fingerprint }}
```

なぜかscriptタグの中に空のHTMLコメントが残っていて、この部分が原因でエラーになっていました。

# まとめ

こんな事でもエラーになるのかと分っていれば対応も難しくないと思いますが、Hugoをいろいろ使っていても始めて遭遇したエラーだったので少し時間がかかりました。

参考になれば幸いです。

以上
Open MPIにデフォルトで論理コア数だけプロセスを立ち上げてもらう

Open MPIではデフォルトで物理コア数だけしかプロセスが立ち上がらない。
それだけならまだいいが、ハードウェアスレッドを活用しようと論理コアの数だけプロセスを立ち上げようとするとエラーになるのが良くない。

例えば2コア4スレッド（ハードウェアスレッド、SMT）のマシンでは2プロセスを超えているとエラーになる:
```console
$ mpiexec -n 4 hostname
--------------------------------------------------------------------------
There are not enough slots available in the system to satisfy the 4
slots that were requested by the application:

  hostname

Either request fewer procs for your application, or make more slots
available for use.

A "slot" is the PRRTE term for an allocatable unit where we can
launch a process.  The number of slots available are defined by the
environment in which PRRTE processes are run:

  1. Hostfile, via "slots=N" clauses (N defaults to number of
     processor cores if not provided)
  2. The --host command line parameter, via a ":N" suffix on the
     hostname (N defaults to 1 if not provided)
  3. Resource manager (e.g., SLURM, PBS/Torque, LSF, etc.)
  4. If none of a hostfile, the --host command line parameter, or an
     RM is present, PRRTE defaults to the number of processor cores

In all the above cases, if you want PRRTE to default to the number
of hardware threads instead of the number of processor cores, use the
--use-hwthread-cpus option.

Alternatively, you can use the --map-by :OVERSUBSCRIBE option to ignore the
number of available slots when deciding the number of processes to
launch.
```

素直にこれに従って`--use-hwthread-cpus`オプションを`mpiexec`に毎回指定してあげてもいいのだが、できる限り`mpiexec`のオプション周りはMPI実装非依存な形で保っておきたい。

上記のエラーメッセージに書かれていないが、MCAパラメタを設定することでデフォルトで`--use-hwthread-cpus`をonにすることが可能。

Open MPIのMCAパラメタの一覧を確認するには:
```sh
ompi_info --param all all --level 9 
```

ちなみにOpen MPI v5系ではランタイムがORTEというものからPRRTEに変わっており、そのPRRTEのMCAパラメタは以下に移動している:
```sh
prte_info --param all
```

v5系では`prte_set_default_slots`というパラメタが見つかると思うので、以下のように環境変数を設定する:
```sh
export OMPI_MCA_prte_set_default_slots=hwthreads
```

v4以前ではPRRTEではなくORTEなので`orte_set_default_slots`の名前である:
```sh
export OMPI_MCA_orte_set_default_slots=hwthreads
```

こういうデフォルトのMCAパラメタは`~/.openmpi/mca-params.conf`に置いておいてもいいらしい。
詳しくは: https://docs.open-mpi.org/en/v5.0.x/mca.html#configuration-files

結果、2コア4スレッドの環境でも以下のように4プロセス立ち上げられる:
```console
$ mpiexec -n 4 hostname
fv-az1385-855
fv-az1385-855
fv-az1385-855
fv-az1385-855
```