OmniAICreator/Qiita-1.07M huggingface dataset:
OrangePi5(debian)でPWMを使えるようにするメモ

# はじめに

OrangePi5でPWMを使えるようにするためのメモ

# 参考文献

こちらに書いてある内容を参考にしました。

https://booth.pm/ja/items/4506270

また、PWMの取り扱いについては公式ドキュメントでも記載されている。
PDFをダウンロードして`PWM`で検索をかければ、sudo実行しているコマンドに当たるはず。

https://drive.google.com/drive/folders/1Bre2q0bGgXQuQlYaYDMvwstpvtHLmcgX

# 環境

- OrangePi5
- debian (Orange Pi 1.1.4 Bullseye with Linux 5.10.110-rockchip-rk3588)

# 設定

今回行うことは2点ある。

- orangepi-configでのPWM許可
- rules追記

## orangepi-configでのPWM許可

まず事前知識として、orangepi5ではPWMを実行するためのアドレスを別々のピンで共有しているものがあることを覚えておく。例えば、16ピンと26ピン、15ピンと23ピンは同じアドレスを使っていることから、どちらか片方を許可する必要がある。
(OrangePi_5_RK3588S_User Manual_v0.7.pdfのp203参照)

| アドレス(pwmchip) | 物理ピン | PWM名称 |
|:-:|:-:|:-:|
| fd8b0000|18|pwm0-m1|
| fd8b0010|16|pwm1-m1|
| fd8b0010|26|pwm1-m2|
| fd8b0030|15|pwm3-m0|
| fd8b0030|23|pwm3-m2|
| febf0010|3|pwm13-m2|
| febf0030|7|pwm15-m2|
| febf0020|11|pwm14-m1|

上記を踏まえた上で、orangepi-configを開く。

```shell
sudo orangepi-config
```

`System`→`HardWare`と選択する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271381/b2aa9286-f687-e220-584e-ff05ef038f80.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271381/b2de9fa6-dc28-b45f-3be4-69a2d147d661.png)


使用するpwmにカーソルをあわせてSpaceキーを押して選択する。
選択すると、該当の項目に`*`が表示される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271381/034f092c-0170-635a-3259-9107b5ce1aa6.png)

`Save`を選択すると同じ画面に戻るため、先程設定した項目に`*`でチェックが入っていることを確認したら`Back`に選択を移して戻る。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271381/31c371d9-c985-bfa0-837f-5f562a6a8ccb.png)

再起動を促されるため、そのまま`Reboot`を選択して再起動する。

## rules追記

sudo無しでPWMを扱えるようにするための設定をここで実施する。
ターミナルで下記コマンドを実行する。

```shell
$ sudo groupadd pwm
$ sudo usermod -aG pwm $USER
```

60-pwm.rulesを開いて下記に書き換え。
新規作成は未記入であればそのままコピペでOK。

```shell
SUBSYSTEM=="pwm", PROGRAM="/bin/sh -c '\
  chown -R root:pwm /sys/class/pwm && chmod -R 770 /sys/class/pwm; \
  chown -R root:pwm /sys/devices/platform/*.pwm/pwm/pwmchip* && chmod -R 770 /sys/devices/platform/*.pwm/pwm/pwmc>
'"
```

ファイルを保存したら再起動する。
再起動が完了したら下記コマンドを実行する。ここで表示されるpwmchipの数はorangepi-configで許可したPWMによって変動するかも。

```shell
$ ls -l /sys/class/pwm/
total 0
lrwxrwxrwx 1 root pwm 0 May  3 00:17 pwmchip0 -> ../../devices/platform/fd8b0000.pwm/pwm/pwmchip0
lrwxrwxrwx 1 root pwm 0 May  3 00:17 pwmchip1 -> ../../devices/platform/fd8b0020.pwm/pwm/pwmchip1
lrwxrwxrwx 1 root pwm 0 May  3 00:17 pwmchip2 -> ../../devices/platform/fd8b0030.pwm/pwm/pwmchip2
lrwxrwxrwx 1 root pwm 0 May  3 00:17 pwmchip3 -> ../../devices/platform/febd0020.pwm/pwm/pwmchip3
lrwxrwxrwx 1 root pwm 0 May  3 00:17 pwmchip4 -> ../../devices/platform/febf0010.pwm/pwm/pwmchip4
lrwxrwxrwx 1 root pwm 0 May  3 00:17 pwmchip5 -> ../../devices/platform/febf0030.pwm/pwm/pwmchip5
```

一旦これでPWMは使用可能となる。pwmchipとアドレスの対応を見ながらgpioコマンドを叩けばPWMが発生するはず。

# 確認

下記は公式ドキュメントのpp.204-205に記載されていたサンプルをsudo無し実行した者です。pwmchipNが何に対応しているのかは`ls -l /sys/class/pwm/`で要確認。

```shell
$ echo 0 > /sys/class/pwm/pwmchip2/export
$ echo 20000000 > /sys/class/pwm/pwmchip2/pwm0/period
$ echo 1000000 > /sys/class/pwm/pwmchip2/pwm0/duty_cycle
$ echo 1 > /sys/class/pwm/pwmchip2/pwm0/enable
```
Vue.jsで作られたアプリをAzure Static Web Appsにデプロイする

## 目的
Vue.jsを学習しており、その成果物を公開するため
## 実施環境
- Windows 11
- node.js v18.16.0
## 事前準備
- Azureアカウント
- GitHub
- node.js (※1)
## 手順
### 1. Vueのアプリを作成
① 任意のディレクトリへ移動 (わたしの場合はC:\Users\ユーザ名\projにしています)
```
cd C:\Users\ユーザ名\proj
```
② Vueのアプリの雛形を作成
```
npm init vite@latest sample20230503 -- --template vue
```
③ Vueアプリをビルド
```
cd sample20230503
npm install
```
④ Vueアプリを実行
```
npm run dev
```
以下のような画面が表示されればOKです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333416/26e5f811-d3c3-9513-4366-94796ecfdd97.png)
### 2. GitHubに任意のリポジトリ作成
リポジトリ名はVueのアプリを作った際に設定した名前にしました
README.mdは作らない
https://docs.github.com/ja/get-started/quickstart/create-a-repo
### 3. 1で作成したアプリのディレクトリへ移動
```
cd sample20230503
```
### 4. リポジトリを初期化
```
git init
```
### 4. リモートリポジトリを追加
```
git remote add origin https://github.com/xxxxxxxxx/sample20230503.git
```
### 5. リモートリポジトリから最新の状態をローカルリポジトリに反映する
```
git pull origin master
```
### 6. プッシュする
```
git add .
git commit -m "feat: 最初のコミット"
git push origin master
```
### 7. リソースグループを作成
① Azure ポータルにログイン
② リソースグループに遷移
③ 任意の名前でリソースグループを作成
ソースグループ名はVueのアプリを作った際に設定した名前にしました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333416/dd2aade8-6562-e6eb-3936-bbc056e65da1.png)
### 8.Azure Static Web Appsを作成及びデプロイ
① 全てのサービスから静的 Web アプリを検索
② webを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333416/b0f875f0-d9a7-1fe8-2bf0-5882e1e86801.png)
③ 静的 Web アプリを選択する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333416/382730b4-0dac-8379-6646-b556be0bada9.png)
④ 静的 Web アプリの作成を選択
⑤ 以下のような構成でアプリを作成
- リソースグループ：sample20230503
- 静的 Web アプリの名前：sample20230503
- ホスティング プラン：Free
- リージョン：East Asia
- デプロイ：GitHub
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333416/6042005f-95bf-629f-31f3-0fc10162324f.png)

※GitHubを選択するとGitHubと連携用の画面が表示されます(スクリーンショット取り忘れました:sweat_smile:)

- GitHub組織：GitHubのユーザ名
- GitHubリポジトリ：sample20230503
- GitHub分岐：master
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333416/8794de0d-acf1-41d3-eaa8-0f2caa89df01.png)

- ビルドのプリセット：Vue.js
- アプリの場所：/
- APIの場所：未入力
- 出力先：dist
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333416/3b726ef5-c42c-51d0-2917-57512157dd4f.png)

⑥ 静的 Web アプリが作成されるとgithub actionのファイルが追加されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333416/dce53087-5595-a0c9-755f-18ec2028f0b2.png)

⑦ GitHubActuionが実行され、画像のような状態であれば成功しています
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333416/5b9e7fdb-c824-d0bc-dc2b-0055b687cbc1.png)

### 9. 出来上がった静的 Web アプリを確認する
① 作成された静的 Web アプリを選択する
② URLを選択する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333416/855cad7b-81be-4fb4-ba52-b3ee2aa502eb.png)
③ 以下のような画面が表示されればOKです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333416/96a1be40-96dd-8f6a-a969-74d207eff73e.png)
## 参考サイト
※1 nvm-windowsのインストール手順については下記

https://learn.microsoft.com/ja-jp/windows/dev-environment/javascript/nodejs-on-windows
DockerでGit+Rubyの環境を構築する

# 概要
今回はDockerを利用してGit＋Rubyの開発環境を構築します。
DockerfileにエイリアスやLinuxを日本語化する設定も一緒に記載しました。

## 前提
GitとGitHubとDockerとLinuxのコマンド操作の基本を理解している方を対象としています。

## 用意する物
カレントディレクトリにDockerfileとsrc/を作成します。src/の中にコンテナにコピーしたいファイルを格納します。今回はGemfileです。
### Dockerfile
```
FROM ruby:3.2.2

WORKDIR /home/work

COPY ./src /home

RUN git config --global user.email "あなたのメールアドレス" && \
    git config --global user.name "あなたの名前" && \
    # vendor/bundleに依存関係をインストールするよう設定する
    bundle config set --local path 'vendor/bundle' && \
    bundle install && \
    echo 'alias g="git"' >> ~/.bashrc && \
    echo 'alias b="bundle exec"' >> ~/.bashrc && \
    echo 'alias r="ruby"' >> ~/.bashrc && \
    git config --global alias.c commit && \
    git config --global alias.s status && \
    git config --global alias.a add && \
    git config --global alias.sw switch && \
    git config --global alias.st stash && \
    git config --global alias.b branch && \
	# Linuxを日本語化する
    apt update && \
    apt install -y locales locales-all && \
    rm -rf /var/lib/apt/lists/*

    ENV LANG ja_JP.UTF-8
    ENV LANGUAGE ja_JP:ja
    
# コンテナを起動した際に設定ファイルを再読み込みさせます。
CMD ["/bin/bash", "-c", "source ~/.bashrc && exec /bin/bash"]
```
### Gemfileの例です。
```
# frozen_string_literal: true

source "https://rubygems.org"

gem "solargraph"
gem 'rubocop'
gem 'pry'
gem 'pry-byebug'
gem 'pry-doc'
```
### 手順
1.Dockerfileがあるディレクトリでイメージを作成します。「.」はカレントディレクトリにあるDockerfaileを参照するという意味です。
```
docker image build -t ruby:3.2.2 .
```
2.コンテナを作成します。その際にローカルのGitの管理下にあるディレクトにマウントします。
```
docker run --name apprentice_ruby -it -v /Gitの管理下のディレクトリ:/home/work ruby:3.2.2
```
3.SSHキーを作成します。
```
ssh-keygen -t ed25519 -C "メールアドレス"
```
4.SSHキーをGitHubの設定のSSH and GPG keysをクリックして New SSH keyにコピペします。※SSHキーが作成されたディレクトリは人によって違うと思います。
```
cat /root/.ssh/id_ed25519.pub
```

### 以上となります。
参考
[仕組みと使い方がわかる Docker&Kubernetesのきほんのきほん ](
https://www.amazon.co.jp/%E4%BB%95%E7%B5%84%E3%81%BF%E3%81%A8%E4%BD%BF%E3%81%84%E6%96%B9%E3%81%8C%E3%82%8F%E3%81%8B%E3%82%8B-Docker-Kubernetes%E3%81%AE%E3%81%8D%E3%81%BB%E3%82%93%E3%81%AE%E3%81%8D%E3%81%BB%E3%82%93-%E5%B0%8F%E7%AC%A0%E5%8E%9F%E7%A8%AE%E9%AB%98/dp/4839972745)
[Docker超入門講座 合併版 | ゼロから実践する4時間のフルコース](https://www.youtube.com/watch?v=lZD1MIHwMBY)
(リンクだけです)EXCELの「罫線」と Googleスプレッドシートの「枠線」を調べた。

教えて下さい。
表の中の罫線の本数を数えるvba,GoogleAppsScriptを探しています。
本数と罫線の始点、終点座標も知りたいです。
おすすめを、よろしくお願いします。

# 呼び方(日本語版)

＞Googleスプレッドシートの枠線～ちょっと便利な方法～
＞EXCELで「罫線」とよんでいるものを、Googleスプレッドシートでは「枠線」とよびます。
＞EXCELで「枠線」とよんでいるものを、Googleスプレッドシートでは「グリッド線」とよびます。

http://www.terakoya-tawaramoto.com/google%E3%82%B9%E3%83%97%E3%83%AC%E3%83%83%E3%83%89%E3%82%B7%E3%83%BC%E3%83%88%E3%81%AE%E6%9E%A0%E7%B7%9A%EF%BD%9E%E3%81%A1%E3%82%87%E3%81%A3%E3%81%A8%E4%BE%BF%E5%88%A9%E3%81%AA%E6%96%B9%E6%B3%95

# 呼び方(英語版)
勉強中

# EXCELで

https://www.google.com/search?q=VBA+%E7%BD%AB%E7%B7%9A+%E6%9C%89%E7%84%A1+%E5%88%A4%E5%AE%9A&client=ms-android-huawei&biw=816&bih=454&sxsrf=APwXEdfp7zeHOjUtHipiVxjdGP6hvJ21dA%3A1683063119962&ei=T4FRZOyvOpmW2roPg62N6AE&oq=VBA+%E7%BD%AB%E7%B7%9A%E3%81%AE%E7%AF%84%E5%9B%B2%E3%82%92%E5%8F%96%E5%BE%97&gs_lcp=ChNtb2JpbGUtZ3dzLXdpei1zZXJwEAEYADIKCAAQRxDWBBCwAzIKCAAQRxDWBBCwAzIKCAAQRxDWBBCwAzIKCAAQRxDWBBCwAzIKCAAQRxDWBBCwAzIKCAAQRxDWBBCwAzIKCAAQRxDWBBCwAzIKCAAQRxDWBBCwAzIKCAAQRxDWBBCwAzIKCAAQRxDWBBCwA0oECEEYAFAAWABguStoAXAAeACAAQCIAQCSAQCYAQDIAQrAAQE&sclient=mobile-gws-wiz-serp

https://www.tipsfound.com/vba/07009

# 【GAS】スプレッドシートで

https://pineplanter.moo.jp/non-it-salaryman/2022/01/12/gas-getcellinfo/
[自分用]vercelについて

## vercelについて
vercelとはフロントエンド開発のプラットフォーム（開発者と利用者を繋ぐようなもの）。
→商用目的でなければ無料で使える！

Next.jsを開発した会社が運営していることもあり、Next.jsとvercelの相性は抜群！！

## デプロイする方法
①githubでリポジトリの作成
②ファイルとリポジトリを連携
③vercel.comを開き、対象のリポジトリを選んでデプロイ
④ビルドされて、デプロイ完了

### 2回目以降
2回目以降は、プッシュすると自動的にビルドされる
データクラスとデータクラスでないクラスのクラス変数をまとめて参照すると、mypyでエラーが発生した

# 環境
* Python 3.11.2
* mypy 1.2.0

# やりたいこと
dataclassの`Cat`と、通常のクラス`Bird`のクラス変数`animal_name`を出力したいです。

```python:sample.py
from dataclasses import dataclass
from typing import ClassVar


class Animal:
    animal_name: ClassVar[str]


@dataclass
class Cat(Animal):
    cat_id: str
    animal_name: ClassVar[str] = "cat"

    def only_cat_method(self) -> None:
        print("only cat method")


class Bird(Animal):
    """Not dataclass"""

    animal_name: ClassVar[str] = "bird"

    def only_bird_method(self) -> None:
        print("only bird method")


for cls in [Cat, Bird]:
    print(cls.animal_name)
```


```
$ python sample.py 
cat
bird
```

# 起きたこと
上記のコードをmypyでチェックすると、エラーが発生しました。

```
$ mypy sample.py
sample.py:28: error: "type" has no attribute "animal_name"  [attr-defined]
Found 1 error in 1 file (checked 1 source file)
```

親クラスにも`Animal`にも`animal_name`はクラス変数として宣言しているので、問題ないようにみえます。

# 原因と解決策
`Cat`と`Bird`でコンストラクタ引数が合っていないから、エラーが出ているようです。

`Bird`に引数が1個の`__init__`メソッドを宣言したら、mypyでエラーは出なくなりました。

```python
class Bird(Animal):
    """Not dataclass"""
    animal_name: ClassVar[str] = "bird"

    def only_bird_method(self) -> None:
        print("only bird method")

    def __init__(self, foo) -> None:
        pass
```

mypyのドキュメントに記載されている通り、特殊メソッドもチェックしているようです。

>Mypy will detect special methods (such as __lt__) depending on the flags used to define dataclasses. [^1]

ただし、エラーメッセージが正しくない気がします。[^2]

[^1]: https://mypy.readthedocs.io/en/stable/additional_features.html#dataclasses
[^2]: [issue](https://github.com/python/mypy/issues/15173)で報告しました。
docker-composeのrunではポートは作成されない。（ホストからコンテナに接続できない）

# １．ホストからコンテナに接続できず、ERR_CONNECTION_REFUSEDがブラウザに表示

久しぶりにdocker-compose.ymlを作り、Webサーバのコンテナを起動し、ブラウザ（Chrome）でアクセスすると、サーバにアクセスできず、以下のメッセージが表示される。


```txt
このサイトにアクセスできません

localhost で接続が拒否されました。
次をお試しください

接続を確認する
プロキシとファイアウォールを確認する

ERR_CONNECTION_REFUSED
```

コンテナにログインをして、以下のようにcurlでアクセスするとindexファイルが取得できる。

```sh
curl http://127.0.0.1
```

つまり、コンテナ内でWebサーバーは稼働しており、ホストからコンテナへのアクセスができていない。


# ２．コンテナとホストのポート転送を確認

ポートの転送ができているのかをdockerコマンドで確認。
PORTSにIPアドレスがないので、転送できていない。

```sh:docker ps
CONTAINER ID   IMAGE          COMMAND                   CREATED         STATUS         PORTS     NAMES
ded69e07b4fc   nginx:latest   "/docker-entrypoint.…"   9 seconds ago   Up 8 seconds   80/tcp    121nginx-nginx-run-7badcf62fd8b
```

念のため、コンテナのIPアドレスを確認してみたが、空文字。


```sh:docker inspect
docker inspect --format '{{.NetworkSettings.IPAddress}}' ded69e07b4fc
''
```

docker-compose.ymlは以下のような簡単なものだが、ポート転送の記述はしてある。
ちなみに、docker-composeを使ったのは、このあといくつか入れたい処理があったため。


```yml:docker-compose.yml
version: '3.4'

services:
  nginx:
    image: nginx:latest
    ports:
      - "3000:80"
```

# ３．エラー原因：docker-compose upではなく、runをつかっていた

表層的な原因としては、ホストとコンテナの間の通信ができていないことなのは分かった。
それをどうやって解消するのか？

いろいろ探して、いろいろ調べ、試したけどだめ。
どうも自分のケースと他のケースは原因が違うようだ。

とりあえず、過去に使っていたプロジェクトのコンテナを起動して成功したものと、失敗したものの状況を比較することにした。
過去に使っていたプロジェクトのコンテナは、ブラウザにWebサーバからのレスポンスが表示された。

そのとき、あることに気づいた。
過去のプロジェクトは、特にコンテナに入るつもりはないので、**<font color=red>upで起動</font>** していた。
一方、今問題となっているコンテナは、早くコンテナ内でコマンドが打ちたかったので、**<font color=red>upせずにrunでコンテナを起動</font>** していた。

```sh:docker-compose run
docker-compose run nginx sh
```

実は、これが接続できない原因だった。ドキュメントに下記の通り記載がある。


:::note info
docker-compose run コマンドはサービス設定ファイルで指定したポートを作成しません。
:::


https://docs.docker.jp/compose/reference/run.html


ということで、以下のようにupをして、ブラウザでアクセスするとindexページが表示された。

```sh:docker-compose up
docker-compose up
```

dockerコマンドでポートを確認すると、マッピング（0.0.0.0:3000->80/tcp）も確認できた。

```sh:docker ps
CONTAINER ID   IMAGE     COMMAND                   CREATED          STATUS          PORTS                  NAMES
1fee115d6b0f   nginx     "/docker-entrypoint.…"   56 seconds ago   Up 55 seconds   0.0.0.0:3000->80/tcp   quirky_moser
```

久しぶりに触ると色々忘れるんだなと思いました。
もし、自分のようなオッチョコチョイの人がいてハマっている人の助けになれば幸いです。
ひずみエネルギとそれを使った材料力学 基本例題8.29 P287 「材料力学演習(20221021)」をsympyでやってみた。

# オリジナル
基本例題8.29 P287
http://zairikiweb.starfree.jp/zai_enshuh/zai_enshuh_ver.3.3.pdf#page=292

「材料力学演習(20221021)一括(ver.3.3)」を勉強したい。＞sympy
https://qiita.com/mrrclb48z/items/c3274daf5f7a99cfe027#%E4%BD%9C%E6%A5%AD%E4%B8%AD%E7%A7%81%E3%81%AE%E8%A7%A3%E7%AD%94sympy

# sympyで
```python
from sympy import *
from sympy.simplify.fu import TR11
NAC,NBC=symbols('NAC NBC',real=True)
t1 ,t2 =symbols('t1  t2' ,real=True)
P      =symbols('P'      ,real=True)
A  ,EE=symbols('A    EE' ,real=True)
l1 ,l2=symbols('l1   l2' ,real=True)
mAC,mBC=symbols('mAC mBC',real=True)
#
myH=Eq(NAC*sin(t1)-NBC*sin(t2)  ,0)
myV=Eq(NAC*cos(t1)+NBC*cos(t2)-P,0)
ans=solve([myH,myV],[NAC,NBC])
NAC=ans[NAC]
NBC=ans[NBC]
nAC=NAC/P
nBC=NBC/P
dCV=(1/(A*EE)*NAC*nAC*l1+1/(A*EE)*NBC*nBC*l2).simplify()
print("#",dCV)
#
myH=Eq(mAC*sin(t1)-mBC*sin(t2)-1,0)
myV=Eq(mAC*cos(t1)+mBC*cos(t2)  ,0)
ans=solve([myH,myV],[mAC,mBC])
mAC=ans[mAC]
mBC=ans[mBC]
dCH=TR11( (1/(A*EE)*NAC*mAC*l1+1/(A*EE)*NBC*mBC*l2).simplify() )
print("#",dCH)
# P*(l1*sin(t2)**2 + l2*sin(t1)**2)/(A*EE*sin(t1 + t2)**2)
# P*(2*l1*sin(t2)*cos(t2) - 2*l2*sin(t1)*cos(t1))/(2*A*EE*sin(t1 + t2)**2)
```

①私の環境は,pycharmです。
②よく聞くのは、Jupyterです。
③web上で、上記のソースを「SymPy Live shell」に、コピー貼り付けでもできました。
黒背景の右上に、マウスを移動すると、コピーマークが発生します。
???　タブレット環境で、コピー貼り付けが実行できませんでした。???

https://live.sympy.org/


# (追加)sympyで(角度を入力してみた。)
以下は、単独では、実行できません。連結して下さい。
t1=30°、t2=60°で実行してみました。
```python
l=symbols('l',real=True)
mySubs={l1:l        ,t1:30*pi/180,
        l2:sqrt(3)*l,t2:60*pi/180
       }
print("#",dCV.subs(mySubs).simplify() )
print("#",dCH.subs(mySubs).simplify() )
# P*l*(sqrt(3) + 3)/(4*A*EE)
# P*l*(-3 + sqrt(3))/(4*A*EE)
```

# Mathematicaで
勉強中

# 作図
勉強中

# 参考
sympy.simplify.fu.TR11(rv, base=None)
Function of double angle to product.

https://docs.sympy.org/latest/modules/simplify/fu.html#sympy.simplify.fu.TR11
`abc.ABC`を継承するかしないかで、インスタンス生成時の挙動をpythonとmypyで確認した

# 環境
* Python 3.11.2

# 概要
`abc.ABC`を継承し忘れて、抽象基底クラスとして書いてしまうときがたまにあります。
ただその場合でも、問題なく動いていたりします。
`abc.ABC`を継承するとどうなるのか、なぜ`abc.ABC`を継承する必要があるのかが分かっていなかったので、`abc.ABC`を継承する/しないによって挙動がどのように変わるかを調べました。

https://docs.python.org/ja/3/library/abc.html#abc.ABC


# 理想の状態
`Dog`クラスは具象クラスですが、`cry`メソッドの実装が漏れている状態です。


```python:sample.py
import abc


class Animal(abc.ABC):
    @abc.abstractmethod
    def cry(self) -> None:
        pass


class Dog(Animal):
    # def cry(self) -> None:
    #     print("bowwow")

    def only_dog_method(self) -> None:
        print("only dog method")


dog = Dog()
```

```
$ python sample.py
Traceback (most recent call last):
  File "/home/vagrant/Documents/study/20230503/sample.py", line 18, in <module>
    dog = Dog()
          ^^^^^
TypeError: Can't instantiate abstract class Dog with abstract method cry

$ mypy sample.py
sample.py:18: error: Cannot instantiate abstract class "Dog" with abstract attribute "cry"  [abstract]
Found 1 error in 1 file (checked 1 source file)
```

python、mypy[^1]でエラーが発生しました。



[^1]: mypyはインスタンス化しないと、抽象メソッドの実装漏れのエラーは発生しません。https://qiita.com/yuji38kwmt/items/1000adfadc7faea7d0ea



# 抽象メソッドは宣言しているが、`abc.ABC`を継承していない

```python:sample1.py
import abc


class Animal:
    @abc.abstractmethod
    def cry(self) -> None:
        pass


class Dog(Animal):
    # def cry(self) -> None:
    #     print("bowwow")

    def only_dog_method(self) -> None:
        print("only dog method")


dog = Dog()
```


```
$ python sample1.py 

$ mypy sample1.py 
sample1.py:18: error: Cannot instantiate abstract class "Dog" with abstract attribute "cry"  [abstract]
Found 1 error in 1 file (checked 1 source file)
```

python実行時にはエラーは発生しませんでした。
公式ドキュメントには、`abc.abstractmethod`について以下のように記載されています。

>このデコレータを使うには、クラスのメタクラスが ABCMeta かそれを継承したものである必要があります。 ABCMeta の派生クラスをメタクラスに持つクラスは、全ての抽象メソッドとプロパティをオーバーライドしない限りインスタンス化することができません。[^2]

`abc.ABC`を継承していないクラスは`abc.abstractmethod`デコレータを使う条件を満たしていないため、Python実行時にエラーは発生しなかったようです。
mypyは、`abc.abstractmethod`を利用していれば抽象基底クラスだとみなして、エラーを出力しているのかもしれません。

[^2]: https://docs.python.org/ja/3.11/library/abc.html#abc.abstractmethod

# 抽象メソッドがないクラスで`abc.ABC`を継承する
`Animal`クラスをmixinクラスとして扱いたいです。`Animal`クラスはインスタンス化させたくありません。`Animal`は抽象クラスではありません（抽象メソッドが存在しない）が、`abc.ABC`を継承してみました。

```python:sample2.py
import abc


class Animal(abc.ABC):
    def cry(self) -> None:
        print("cry, cry")


class Dog(Animal):
    def only_dog_method(self) -> None:
        print("only dog method")


animal = Animal()  # インスタンス化を禁止させたい
dog = Dog()
```


```
$ python sample2.py

$ mypy sample2.py
Success: no issues found in 1 source file
```

python, mypyでエラーは発生しませんでした。
そもそも`Dog`も`abc.ABC`のサブクラスなので、`abc.ABC`を継承したらインスタンス生成を禁止できる訳がないですね。。。

```python 
issubclass(Dog, abc.ABC) # => True
issubclass(Animal, abc.ABC) # => True
```
AlmaLinux wkhtmltox インストール

## wkhtmltoxとは？
wkhtmltox は、HTMLをPDF、画像、またはその他の形式に変換するためのツールで、C++で書かれたコマンドラインプログラムです。これは、QtとWebKitのオープンソースバージョンであるQt WebKitを使用して、HTMLをレンダリングしてPDF、画像、SVGなどのファイル形式に変換します。

Pythonからwkhtmltoxを利用するためには、Pythonのラッパーライブラリである pdfkit や weasyprint が使用されることがあります。これらのライブラリは、PythonからHTMLをPDFに変換するためのシンプルな方法を提供します。

python-highcharts などからHTMLやPDFを生成する時に必要です。

## インストール

```
wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox-0.12.6-1.centos8.x86_64.rpm
du -sh wkhtmltox-0.12.6-1.centos8.x86_64.rpm
 dnf install ./wkhtmltox-0.12.6-1.centos8.x86_64.rpm
```
【javascript】濁音を清音に変換する

# ひらがなの清音部分を取り出します

[String.prototype.normalize()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/normalize)
のNFDを使って、濁音を分解し、一文字目を取り出します。


```javascript:
// 濁音を清音に変換する
function dakuten(str){
    let _str = '';
    for (let i = 0; i < str.length; ++i) {
       _str += str[i].normalize('NFD')[0];
    }
    return _str;
}

const dakuten_arrow = (str: string) => {
    let _str: string = '';
    for (let i = 0; i < str.length; ++i) {
       _str += str[i].normalize('NFD')[0];
    }
    return _str;
}

const str_dakuten: string = Deno.args[0];  // <- "がぎぐげご"
const str_seion = dakuten_arrow(str_dakuten); // もしくは dakuten(str_dakuten);
console.log(str_seion);  // -> "かきくけこ"
```

関数が２つあるのは同じものです。
下のアロー関数のは、Typescript用に型つけしてあるだけです。
Hadoopとは？

# はじめに
毎週1本様々な技術に関する記事を投稿しています。
もし興味のある方は下のリンクから他の記事も見ていただければ幸いです。
 [@7_inai_](https://qiixta.com/7_inai_)

# Hadoopとは
Hadoopとは、膨大なデータ([ビッグデータ](https://qiita.com/7_inai_/items/0bbce95823ca7ae9ae2e))を、複数のマシンに分散して処理する(分散処理)ためのオープンソースのプラットフォームです。

# 分散処理はなんのため？
分散処理とは、処理速度の向上とサーバー負荷軽減のために、1つの処理を分散して行うことです。
ビッグデータをリアルタイム処理するにあたり、処理速度の向上は必須です。分散処理を行うことで、処理速度を向上させて、リアルタイムのデータを解析することができます。

また、分散処理の方法は、主に以下の2つに分けられます。
①1台のPCに多数のプロセッサを搭載して処理する方法
②複数のサーバーにデータを分散させて処理する方法

# MapReduce と HDFS
Hadoopは分散処理を実現するためにMapReduceとHDFSといったの2つのコンポーネントを使用しています。
### ■MapReduce
MapReduceはHadoopで動作するプログラミングモデルです。大量のデータを複数のタスクに分類し、並列処理することができます。
### ■HDFS
HDFS(Hadoop Distributed File System)は、大量のデータを複数のマシンに分散させて保存するためのファイルシステムです。

# 終わりに
IoTの普及により、大量のデータ(ビッグデータ)を処理することの重要性が高まってきている昨今、Hadoopを使用した分散処理は必要不可欠な技術となっています。
IoTのみならず、AI、インダストリー4.0、5G等新しい技術や思想が生まれるにつれ、処理しなければならないデータ量は指数関数的に増加していますので、発生したデータを処理するための技術にも注目していきたいです、


最後までお付き合いくださりありがとうございました。
Tailwind CSSでよく使うもの

Tailwind CSS(テイルウィンドシーエスエス)で個人的に使う頻度が高いものを抜粋

・p-シリーズ(padding)

|tail|css          |
|---|--------------|
|p-8| padding:32px;|
|pt-8| padding-top:32px;|
|pl-8|padding-left:32px;|
|pr-8|padding-right:32px;|
|pb-8| padding-bottom:32px;|

・m-シリーズ(margin)

|tail|css|
|-----|-----------|
|m-8 |margin:32px;|
|mt-8 |margint-top:32px;|
|ml-8| margin-left:32px;|
|mr-8 |margin-right:32px;|
|mb-8| margin-bottom:32px;|

・roundedシリーズ(border-radius)


|tail|css|
|-----|-----------|
|rounded-tl-2xl| border-top-left-radius: 16px;|
|rounded-tr-2xl| border-top-right-radius: 16px;|
|rounded-bl-2xl| border-bottom-left-radius: 16px;|
|rounded-br-2xl |border-bottom-right-radius: 16px;|

・shadowシリーズ(box-shadow)


|tail|css|
|-----|-----------|
|shadow-2xl|	box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25);|

・w-シリーズ(width)

|tail|css|
|-----|-----------|
|w-8| width:32px;|

・h-シリーズ(height)

|tail|css|
|-----|-----------|
|h-8 |height:32px;|

・bg-color-シリーズ(background-color)

|tail|css|
|-----|-----------|
|bg-red-600| background-color: rgb(220 38 38);|

・opacityシリーズ(opacity)

|tail|css|
|-----|-----------|
| opacity-40| opacity: 0.4;|

・displayシリーズ(display)


|tail|css|
|-----|-----------|
|flex |display:flex;|
|inline-block |display:inline-block;|

・positionシリーズ(position)


|tail|css|
|-----|-----------|
|relative| position:relative;|
|absolute| position:absolute;|
|fixed |position:fixed;|

・fontシリーズ(font)


|tail|css|
|-----|-----------|
|text-sm |font-size: 14px;line-height:20px;|
|font-semibold|	font-weight: 600;|
【SwiftUI】@Bindingを初期化する時の注意点

# はじめに
[前回](https://qiita.com/mogeko6347/items/45236f0212d420bab660)、`private`な変数・定数が含まれるclassやstructをMemberwise Initializerで初期化しようとするとエラーが起きることを知りました。今回は、自分で`init`を作成する際に`@Binding`変数がある場合の注意点です。

# 結論
@Binding変数を初期化する際はアンダースコア(_)を付ける

# Cannot assign value of type 'Binding<String>' to type 'String'
通常は`@Binding`変数を定義しても、Memberwise Initializerが自動で初期化してくれるので自分でinitializeを定義する必要はありません。しかし、`private`変数を使うなど自分で`init`を書く必要がある場合、以下のような書き方をするとエラーが発生します。
```swift
struct ContentView: View {
    @State var text = "Hello"
    var body: some View {
        VStack {
            SecondView(text: $text)
        }
        .padding()
    }
}
struct SecondView: View {
    @Binding var text: String
    private var count = 0
    init(text: Binding<String>) {
        self.text = text // Cannot assign value of type 'Binding<String>' to type 'String'
    }
    var body: some View {
        VStack {
            Text(text)
        }
    }
}
```
エラーの内容は、「最初に定義した`self.text`は`String`型なのに引数の`text`は`Binding<String>`型だからアクセスできません」といったものです。
https://qiita.com/crea/items/0b59722ab21e8c6cbb30
この記事ですごく分かりやすく解説されているのですが、
```swift
@Binding var text: String
```
は、実際は以下のような宣言として定義されています。
```swift
 var _text: Binding<String>
 var text: String {
     get {
         _text.wrappedValue
     }
     set {
         _text.wrappedValue = newValue
     }
 }
```
それぞれのクラスは表のようになります。
|名前                |型 |
|---                |---|
|_text              |Binding\<String>|
|_text.wrappedValue |String|
|text               |String|

`text`自体は値を持たず、`String`型の`_text.wrappedValu`を`get`メソッドで返すだけであり、`Binding<String>`型を表してるのは`_text`だと分かります。


# 解決策
`self.text`を`self._text`もしくはただの`_text`と直します。
```swift
struct ContentView: View {
    @State var text = "Hello"
    var body: some View {
        VStack {
            SecondView(text: $text)
        }
        .padding()
    }
}
struct SecondView: View {
    @Binding var text: String
    private var count = 0
    init(text: Binding<String>) {
        self._text = text
    }
    var body: some View {
        VStack {
            Text(text)
        }
    }
}
```

# 終わりに
`@Binding`と`Binding<String>`の関係がごっちゃになってました...

参考：
https://ja.stackoverflow.com/questions/63300/swiftの初期化処理でエラーが発生する/63305#63305
https://inon29.hateblo.jp/entry/2020/05/02/134257
OrangePi5(debian)でGPIOを使えるようにするための設定

# はじめに

- orangepi5でGPIOを使うために必要な設定をメモ

# 参考文献

こちらに書いてある内容を書き換えているだけです。

https://www.technicalife.net/orangepi5-led-on/

https://booth.pm/ja/items/4506270

また、GPIOの取り扱いについては公式ドキュメントでも記載されている。
PDFをダウンロードして`GPIO`で検索をかければ、sudo実行しているコマンドに当たるはず。

https://drive.google.com/drive/folders/1Bre2q0bGgXQuQlYaYDMvwstpvtHLmcgX

# 環境

- OrangePi5
- debian (Orange Pi 1.1.4 Bullseye with Linux 5.10.110-rockchip-rk3588)

# 設定

su権限なしでgpioを使えるようにするため、下記のコマンドを実行する。
sudo無しでnode-redやwiringPiなど別のサービス・ライブラリ等からgpioを操作する際には必須となる。

ちなみに初期パスワードは`orangepi`なはず。

```shell
$ sudo groupadd gpio
$ sudo usermod -aG gpio $USER
```

また、デバイスファイルに設定を加えるため。好きなエディタで`60-gpio.rules`を開く。

```shell
$ sudo nano /etc/udev/rules.d/60-gpio.rules
```

下記の内容に書き換える。
（何も書いていなければそのまま追記）

```
SUBSYSTEM=="gpio", KERNEL=="gpiochip[0-5]", GROUP="gpio", MODE="0660"
```

ファイルを保存して、再起動すれば設定が反映されるはず。

# 確認

再起動後、GPIOが使えるようになっていることを確認する。
下記のように、ファイルの所有グループのgpioに対して`rw`の権限が付与されている(権限に関する表示の5~7文字目に`rw`と出力されている)ことが確認できればOK。

```shell
$ ls -l /dev/gpiochip*
crw-rw---- 1 root gpio 254, 0 May  3 00:17 /dev/gpiochip0
crw-rw---- 1 root gpio 254, 1 May  3 00:17 /dev/gpiochip1
crw-rw---- 1 root gpio 254, 2 May  3 00:17 /dev/gpiochip2
crw-rw---- 1 root gpio 254, 3 May  3 00:17 /dev/gpiochip3
crw-rw---- 1 root gpio 254, 4 May  3 00:17 /dev/gpiochip4
crw-rw---- 1 root gpio 254, 5 May  3 00:17 /dev/gpiochip5
```

# 注意

参考文献のブログや書籍にも書いてあるとおり、一部のピンを除いてGPIOが出力する電流が小さすぎてLチカができない事象がある。

下記の物理ピン**以外**を使う際にはドライバ回路が別途必要になるかも。

- 8(wPi:3)
- 10(wPi:4)
- 11(wPi:5)
- 13(wPi:7)
「フロントエンド開発のためのテスト入門」感想

# はじめに

[フロントエンド開発のためのテスト入門](https://www.shoeisha.co.jp/book/detail/9784798178639)を読了したので感想と個人的な所感を記載します。
結論から述べると私はこの本を読んで非常に満足しております！！本記事を読んで少しでも多くの方にこの本を手に取ってもらえたらと思います。本書は、「テストってなぜ書くのだろうか？」「単体/結合/E2Eテスト等、各レベルのテストをどのように構成するべきか？」といったような示唆に富んだ内容になっているかと思います。

# なぜこの書籍を読んだのか

Javascript/TypeScriptのテスティングフレームワークの一つであるJestの学習をしたく2023/5現時点で新しい書籍であることと、他にあまりJestの学習ができそうな書籍があまりなく、半分好奇心で読んでみた。

## 目的に対する満足度

60% 

### 理由

本書はJestのみの書籍では当然なく、確かにJestの大枠はつかめたが、1つ1つの書き方や、APIが細かく説明されているといった類の書籍でもなく、今後実装時にリファレンスレベルでおいておけるレベルの書籍ではなかったため。60%としている。

## 総合満足度

80%

### 理由

一通り書籍を読んだが、本書のピークは1-2章だと思いました。
1章：「テストの目的と障壁」、2章：「テスト手法と戦略」となっており、3章からは各単体レベル/結合レベルなどのテストの実装方法について記載されています。3章からは前述の通り、個人的に求めるレベル(リファレンスレベルなのでかなり細かいレベルですが・・・)に達していなかったのですが、そこそこの満足度でした。

　実は私が所属しているプロジェクトは2章にあるようなE2Eテストがかなり重い「[アイスクリームコーン型テスト](https://zenn.dev/zundaneer/articles/84f6415220d5b6#%E3%82%A2%E3%82%A4%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%A0%E3%82%B3%E3%83%BC%E3%83%B3%E5%9E%8B%E3%83%86%E3%82%B9%E3%83%88)」になっており
毎日のテストに相当数のコストがかかってしまっているのが現状です。
そういった現状をある意味この書籍でズバッと指摘された気がしており、かなり心に響きました。

# 感想

　Seleniumなどを使ったE2Eテストは確かに動く画面で動かすためとっつきやすく、考えやすいのかなと思います。実際私のプロジェクトもそうなっています。最近はE2Eテストは開発者がブラウザを操作したものがそのまま記憶されて～といった形で簡単テスト作成できるものもありますが、だからと言って安易にE2Eテストを増やして良いといったものではないのだと思いました。
　ここで一度立ち止まってプロジェクトの他チームメンバーへの説明や関係者への説明を今すぐにでもしてテスト戦略練りたくなりました。
iOSでキーボードがUITextFieldを隠さないようにする方法

# iOSでキーボードがUITextFieldを隠さないようにする方法

### :warning:この記事はchatGPT-4に解説してもらった内容なので、間違っている可能性があります。

この記事では、iOSアプリでキーボードがUITextFieldを隠さないようにする方法について説明します。具体的には、Swiftで書かれた以下のコードを解析していきます。

```swift
import UIKit

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    // Define the input field
    private let field: UITextField = {
        let textField = UITextField()
        textField.placeholder = "Type here..."
        textField.translatesAutoresizingMaskIntoConstraints = false
        textField.backgroundColor = .red
        return textField
    }()
    
    // Define the table view
    private let table: UITableView = {
        let table = UITableView()
        table.translatesAutoresizingMaskIntoConstraints = false
        table.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        return table
    }()
    
    // This is called when the view is loaded
    override func viewDidLoad() {
        super.viewDidLoad()

        // Add the field and table to the view
        view.addSubview(field)
        view.addSubview(table)

        // Set the delegate and data source for the table
        table.delegate = self
        table.dataSource = self

        // Set up constraints
        NSLayoutConstraint.activate([
            field.heightAnchor.constraint(equalToConstant: 50),
            field.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor, constant: 10),
            field.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor, constant: -10),
            field.bottomAnchor.constraint(equalTo: view.keyboardLayoutGuide.topAnchor),
            
            table.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor),
            table.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor),
            table.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            table.bottomAnchor.constraint(equalTo: field.topAnchor),
        ])
    }
}
```

## AutoLayoutの制約

このコードでは、キーボードが表示された際にUITextFieldが隠れないようにするために、AutoLayoutの制約を適用しています。具体的には、以下の行が重要な役割を果たしています：

```swift
field.bottomAnchor.constraint(equalTo: view.keyboardLayoutGuide.topAnchor)
```

この行は、UITextFieldの下端（bottomAnchor）を画面のキーボードの上端（keyboardLayoutGuide.topAnchor）に固定する制約を作成します。これにより、キーボードが表示されると、その上端にUITextFieldが自動的に移動します。その結果、キーボードがUITextFieldを隠すことはありません。

## テーブルビューの制約

また、テーブルビューの下端もUITextFieldの上端に固定しています：

```swift
table.bottomAnchor.constraint(equalTo: field.topAnchor),
```

これにより、キーボードが表示されたときには、テーブルビューが適切にサイズ調整され、全体のレイアウトが保たれます。

## まとめ

このように、AutoLayoutの制約を利用することで、iOSのキーボードが表示された際に他のUI要素を隠す問題を解決することができます。



参考コード
[Build An AI ChatBot with OpenAI (Swift, Xcode 14, 2023) | iOS Academy](https://youtu.be/9DjbQpbQVFo)

https://youtu.be/9DjbQpbQVFo
dashアプリのコンテナ化

サマリ
　①dashサンプルアプリ作成
→②コンテナ化
　③AWSデプロイ

---

# dashアプリのコンテナ化

## gunicorn化

### gunicornインストール

```
pip install gunicorn
```

### requirements.txt更新

```
pip freeze > requirements.txt
```

### main.py修正

```python
server = Flask(__name__)
app = Dash(name=__name__ , server=server)
#修正前
#app = Dash(__name__)
```

## Dockerfile作成

```Dockerfile
FROM python:3.10

ENV DEBIAN_FRONTEND noninteractive
ENV PROJECT_ROOTDIR /work/
WORKDIR $PROJECT_ROOTDIR

COPY ./requirements.txt $PROJECT_ROOTDIR
COPY ./main.py $PROJECT_ROOTDIR

RUN pip install -U pip && \
    pip install -r requirements.txt
```

## docker-compose.yml作成

```docker-compose.yml
FROM python:3.10

ENV DEBIAN_FRONTEND noninteractive
ENV PROJECT_ROOTDIR /work/
WORKDIR $PROJECT_ROOTDIR

COPY ./requirements.txt $PROJECT_ROOTDIR
COPY ./main.py $PROJECT_ROOTDIR

RUN pip install -U pip && \
    pip install -r requirements.txt

EXPOSE 8050
```

## 試しに実行

```bash
docker-compose up -d
```
【Swift】URLを開く処理と無効なURLの場合のエラーハンドリング

# はじめに
URLを開く処理は実装したことがあるが、エラーハンドリングに関しては`fatorError()`, `print("URLが開けない")`といったデバッグ用のものしか記述していないことが多い。

アラートを使って、無効なURLであることをユーザーに通知する実装を備忘録として記録。

以下の処理を実装した。
①URLが開けるかどうか判断するバリデーションを実装
②`UIApplication`を使って、URLを開く処理を実装

# 実装
①URLが開けるかどうか判断するバリデーションを実装
「日本語が%表記に変換できるかどうか」、「URLに無効な文字列が含まれているか」を判断するバリデーションを実装

``` swift:Validator.swift
enum Validator {
    case isUnavailableURL, includedJapaneseURL
    
    init?(urlStr: String) {
        let encurl = urlStr.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed) ?? ""
        guard let url = NSURL(string: encurl) else {
            self = .includedJapaneseURL
            return
        }
        
        if UIApplication.shared.canOpenURL(url as URL) == false {
            self = .isUnavailableURL
            return
        }
        
        guard let fixedURL = URL(string: urlStr) else {
            self = .isUnavailableURL
            return
        }
        
        return nil
    }
    
    var alertMessage: String {
        switch self {
        case .isUnavailableURL:
            return "URLに無効な文字が含まれています。"
        case .includedJapaneseURL:
            return "URLに含まれている日本語を変換できません。"
        }
    }
}
```

②`UIApplication`を使って、URLを開く処理を実装
`UIApplication.shared.open`の前に、強制アンラップをしているが、Validatorの方で「URLに無効な文字列が含まれているか」判断しているため、問題はない。

``` swift:ViewController.swift
@objc private extension ViewController {
    func tapOpenURL() {
        if let validationAlertMessage = Validator(urlStr: String.URL)?.alertMessage {
            self.showErrorAlert(title: String.cannotOpenURLTitle, message: validationAlertMessage)
            return
        }
        
        let appURL = URL(string: String.URL)!
        UIApplication.shared.open(appURL, options: [:], completionHandler: nil)
    }
}
```

# プレビュー
<img width="200" src="https://gyazo.com/e5311382ba25d3009c52f2e5ba39ccac/raw">

# 終わりに
原因不明でアプリがクラッシュするよりも、エラー内容をアラートでユーザーに通知した方がよい

# 参考リンク
[UIApplication | Apple Developer Documentation](https://developer.apple.com/documentation/uikit/uiapplication)
[【SwiftUI】入力されたURLの有効性を識別する方法！](https://tech.amefure.com/swift-url-validation)
Dockerでnginx環境を構築

+ ゴール
Windowsのdocker環境に基本コマンドを実行できるnginx環境を構築

+ Dockerの導入
[WindowsでDocker
](https://qiita.com/tyakosuke/items/6c77c057913453820fa4)

+ nginxのイメージを検索
~~~
docker search nginx
~~~
結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22836/9e0ba684-fa78-2f4a-c408-4d83395b670a.png)
+ nginxのイメージを取得
~~~
docker pull nginx
~~~
+ 取得したイメージの確認
~~~
docker images
~~~
+ 取得したイメージからnginxコンテナの起動
~~~
docker run -dp 80:80 nginx 
~~~
localhost:80にアクセスすると下記ページが表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22836/e9d2d3f8-69bb-a301-ba7b-e49b56f2b427.png)


+ 起動したコンテナへログイン
~~~
docker exec -it nginx /bin/bash
~~~
参考：[docker exec](https://docs.docker.jp/engine/reference/commandline/exec.html)
このままだと、様々なコマンドが使用できないのでインストール
+ パッケージ情報取得
~~~
apt update
~~~
+ Vimインストール
~~~
apt install vim
~~~
+ 監視コマンドインストール（ps,top,kill等）
~~~
apt install procps
~~~
+ ネットワーク制御系コマンドインストール（netstat,arp等）
~~~
apt install net-tools
~~~
nginxのインストールディレクトリは下記
~~~
ls /etc/nginx
~~~
confファイルは下記
~~~
ls /etc/nginx/conf/nginx.conf
ls /etc/nginx/conf/conf.d/default.conf
~~~
アクセスした際に表示されるページ
~~~
ls /usr/share/nginx/html/index.html
~~~
抽象メソッドの実装が漏れているクラスを定義しただけでは、mypyはエラーを出力しない

# 環境
* Python 3.11.2
* mypy 1.2.0


# 起きたこと
抽象基底クラス`Animal`を継承している`Cat`クラスでは、`cry`メソッドの実装が漏れていました。

```python:sample.py
import abc


class Animal(abc.ABC):
    @abc.abstractmethod
    def cry(self) -> None:
        pass


class Dog(Animal):
    def cry(self) -> None:
        print("bowwow")

    def only_dog_method(self) -> None:
        print("only dog method")


class Cat(Animal):
    # cryメソッドの実装漏れ

    def only_cat_method(self) -> None:
        print("only cat method")
```

この状態でmypyを実行してもエラーは発生しません。なぜでしょうか？

```
$ mypy sample.py 
Success: no issues found in 1 source file
```


# 原因
コードを書いている私は、`Cat`クラスを具象クラスとして扱っていましたが、mypyは`Cat`が抽象基底クラスか具象クラスか判断できません。mypyは`Cat`クラスを抽象基底クラスとして扱っているため、エラーは発生しませんでした。


>There is one important peculiarity about how ABCs work in Python – whether a particular class is abstract or not is somewhat implicit. In the example below, Derived is treated as an abstract base class since Derived inherits an abstract f method from Base and doesn’t explicitly implement it. The definition of Derived generates no errors from mypy, since it’s a valid ABC:

https://mypy.readthedocs.io/en/stable/class_basics.html#abstract-base-classes-and-multiple-inheritance 引用



# 解決策
インスタンスを生成すれば、mypyはエラーを出力します。


```python:sample.py
...

dog = Dog()
cat = Cat()
```

```
$ mypy sample.py 
sample.py:26: error: Cannot instantiate abstract class "Cat" with abstract attribute "cry"  [abstract]
Found 1 error in 1 file (checked 1 source file)
```

もちろん、Python実行時にエラーも発生します。

```
$ python sample.py
Traceback (most recent call last):
  File "/home/vagrant/Documents/study/20230503/sample.py", line 26, in <module>
    cat = Cat()
          ^^^^^
TypeError: Can't instantiate abstract class Cat with abstract method cry
```
【AWS】特定の環境変数を持つLambda関数をAWS CLIで検索する方法

最近、複数のLambda関数のとある環境変数を更新しなければならなくなったのですが、関数が100個くらいあり、マネジメントコンソールから環境変数の値を含むLambda関数を検索する機能も見当たらず、手動で探しきれませんでした。

そこで調査を進めると、AWS CLIやBoto3（Python SDK）を利用すれば、該当の環境変数を含む関数をフィルタリングすることができることが可能だとわかりました。

似たような記事がたくさんありそうなのですが、駆け出しエンジニア向けに調査内容をあらためてまとめました。

# AWS CLIをつかう方法
jqコマンドでフィルタリングして、特定の環境変数を含む関数を抽出します。

```bash
aws lambda list-functions --query 'Functions[].[FunctionName,Environment]' --output json | jq '.[] | select(.[1].Variables.YOUR_VARIABLE_NAME == "your-value")'
```
こんな感じで出力されます。

```
{
    "Reservations": [
        {
            "Groups": [],
            "Instances": [
                {
                    "AmiLaunchIndex": 0,
                    "ImageId": "<ami>",
                    "InstanceId": "<instance-id>",
                    "InstanceType": "t2.micro",
                    "KeyName": "<key-name>",
                    "LaunchTime": "2022-01-17T15:07:53+00:00",
                    "Monitoring": {
                        "State": "disabled"
                    },
                    "Placement": {
                        "AvailabilityZone": "ap-northeast-1a",
                        "GroupName": "",
                        "Tenancy": "default"
                    },
    ...
}
```


# Boto3をつかう方法
Boto3で特定の環境変数の値を持つLambda関数を検索する場合、以下のPythonコードを使用できます。
Lambda関数の一覧を取得し、指定された環境変数名（YOUR_VARIABLE_NAME）と値（your-value）を持つ関数をフィルタリングします。

```python
import boto3

def find_lambda_functions_with_env_var(variable_name, variable_value):
    lambda_client = boto3.client('lambda')
    functions = lambda_client.list_functions()['Functions']
    matched_functions = []

    for function in functions:
        env_variables = function.get('Environment', {}).get('Variables', {})
        if variable_name in env_variables and env_variables[variable_name] == variable_value:
            matched_functions.append(function['FunctionName'])

    return matched_functions

if __name__ == "__main__":
    your_variable_name = "YOUR_VARIABLE_NAME"
    your_value = "your-value"
    matched_functions = find_lambda_functions_with_env_var(your_variable_name, your_value)
    print(matched_functions)
```

※Google Colaboratoryで実行する際は、Boto3のインストールとAWSクレデンシャルの設定を忘れずに行いましょう。

```python
!pip install boto3
```

```python
import os

os.environ['AWS_ACCESS_KEY_ID'] = 'your-access-key'
os.environ['AWS_SECRET_ACCESS_KEY'] = 'your-secret-key'
os.environ['AWS_DEFAULT_REGION'] = 'your-default-region'
```
【Jetpack Compose】Previewで実行されているかを判定する

## ComposeでPreviewで実行されているかをコードで判定する
結論、以下のコードでComposable関数がPreviewで実行中かを判定することができます。


```kotlin
import androidx.compose.ui.tooling.PreviewActivity

val isInPreview: Boolean
  @Composable
  get() = LocalInspectionMode.current || LocalLifecycleOwner.current is PreviewActivity
```
| API | 説明 |
|:-----------|:------------|
| `LocalInspectionMode.current`       |     Android StudioのCompose Preview上でComposable関数のPreviewが実行されているかどうか。trueでPreview上で実行中。<br>(実機やエミュレータ上で実行中の場合だとfalse) |

`LocalInspectionMode.current`だけをみて判定すると実機やエミュレータでPreviewを実行した時に判定できなくなってしまいます。
そこで実機やエミュレータでは`compose.ui.tooling.PreviewActivity`というActivityの上で実行されるという仕組みを利用してPreviewかどうかを判定することができます。
(Composeのアップデートによって将来的に変更される可能性もあります。本記事はCompose v1.4系の情報です。)

無闇にPreviewかどうかを判定するコードをComposable関数に入れるのはやめた方が良いですが、
稀に本当に稀にPreviewの時だけ何かをやりたい、やらせたくないなどのケースがあるので知っておくと役に立つ時が来るかもしれないです。
التحديات والصعوبات عند استخدام Tencent Cloud  

# مقدمة  
(سأحكي لكم عن حادثة وقعت خلال مشاركتي في مشروع عالمي قديمٍ). وكان من الضروري آنذاك نشر النظام في بلد معين، لذا قمنا بإنشاء بيئة على خدمة **Tencent Cloud** السحابية في تلك المنطقة. كانت الخدمة تواجه بعض التحديات من حيث الموثوقية والكفاءة مقارنة بالخدمات السحابية الكبرى، وكانت بعض وظائفها غير مكتملة، مما تسبب في عدة صعوبات. في هذه المقالة، سأتحدث عن الحدث الأكثر إثارة للاهتمام.

---

# الشروط  
- يتم إدارة البنية التحتية التي تم إنشاؤها على **Tencent Cloud** بشكل أساسي باستخدام **Terraform**.

---

# مشكلة إعادة إنشاء موارد إدارة المستخدم تلقائيًا  

## المنبع  
- قمت بإضافة رمز **Terraform** لتحديث مورد البنية التحتية ونفذت خطة terraform.  

## الظاهرة  
- حدث خطأ في تطبيق SDK أثناء تنفيذ الخطة. محتوى الخطأ كان يشير إلى أن بعض الموارد لم تكن موجودة على الجهاز الفعلي.  
- الموارد المعنية لم تكن ذات صلة بالموارد التي تم تحديثها، ولم تواجه مشكلة من قبل عند إدارتها باستخدام Terraform.  

## السبب  
- بعد البحث، تم اكتشاف أن معرّف UUID (المعرف الفريد للمورد) على حالة الحفظ **tfstate** لم يعد يتطابق مع القيمة الفعلية.  
- لم يتم تحديث المستخدم للمورد المعني، وتم التواصل مع دعم خدمة **Tencent Cloud**. 
- كانت الموارد التي حدثت فيها المشكلة هي **موارد المراقبة**.  
وهي خدمة تشبه تنبيهات **CloudWatch** في AWS.  

https://cloud.tencent.com/document/product/877/18758


## نتيجة الاستفسار  
- اكتشفنا أن **خدمة المراقبة** المزودة من قِبل **Tencent Cloud** قامت بإعادة إنشاء موارد إدارة المستخدم بسبب ترقية تم تطبيقها على هذه الخدمة.  
- نتيجةً لإعادة إنشاء الموارد، اختلف معرّف UUID على حالة الحفظ **tfstate**، مما أدى إلى فشل عملية التنفيذ.  

## التعامل مع المشكلة  
- تم ترتيب قائمة بالموارد المُعاد إنشاؤها، ثم تنفيذ **state rm** للموارد القديمة و**state import** للموارد الجديدة (كتبنا بعض النصوص البرمجية البسيطة، لكن بسبب العدد الكبير للموارد، استغرق الأمر وقتًا طويلًا).  
- نظرًا لأن خدمة **Tencent Cloud** لم توفر عملية تلقائية لهذه المشكلة، كان على المستخدم تنفيذها يدويًا.  

## السبب الجذري الذي اعتقدته  
1. **تحديث مفاجئ بدون إشعار مسبق**  
    - لم يتم إرسال إشعار مسبق من **Tencent Cloud** حول هذا التغيير.  
2. **عدم كفاية التحقيق في التأثير الناتج عن التحديث**  
    - لم تجرِ **Tencent Cloud** تحقيقًا كافيًا لتحديد التأثيرات المحتملة للتحديث.  
3. **تصميم الخدمة غير المثالي**  
    - لا يوجد توضيح منطقي لسبب إعادة إنشاء الموارد بعد التحديث.  

---

# خاتمة  
للأشخاص الذين يعتمدون على خدمات سحابية مثل **Tencent Cloud**، أردت توثيق هذه التجربة لتجنب مشاكل مماثلة في المستقبل. آمل أن تكونوا قد استفدتم من هذه المقالة.  

---

# روابط ذات صلة  
- [صفحة دعم Tencent Cloud](https://cloud.tencent.com/document/product)  
- [وثائق Terraform الرسمية](https://developer.hashicorp.com/terraform/language/state)
Developing a Proactive Security Strategy for your organization

Cyber dangers continue to emerge at an alarming rate in today’s dynamic digital environment, endangering businesses of every size and in all sectors. Every day, there are more than 4,50,000 new malware samples alone, but researchers are also always finding new social engineering scams and zero-day vulnerabilities. It is no longer sufficient to respond to cyber threats reactively by patching vulnerabilities after attackers have exposed them to safeguard important digital assets. Instead, by implementing a proactive security policy, organizations must foresee dangers and respond to them before they materialize.

What Is a Proactive Security Strategy?

A proactive security strategy is an all-encompassing cybersecurity approach with the objective of identifying, foreseeing, and mitigating threats before they materialize into incidents. Due to their high profile and the extreme sensitivity of their data, large corporations and significant government organizations were the main practitioners of proactive security for a very long period. Smaller businesses could afford to take their time with cybersecurity because attackers didn’t give a damn about them.

Cyberattacks are no longer only directed at the most visible targets, though, as times have evolved. In 2021, 18% of SMBs faced six or more cyberattacks, while 60% of SMBs experienced one, according to the report The State of IT Security for SMBs in 2022-2023. Virtually every organization with internet-accessible IT infrastructure can anticipate being inundated with increasingly sophisticated attacks as a result of the rise of automated cyberattacks powered by artificial intelligence, and preventative measures won’t be able to offer a sufficient defense. Building a strong proactive security plan that is intended to stop both present and future cyber threats from generating data breaches and other mishaps is the best course of action.

The Primary Building Blocks of a Proactive Cybersecurity Strategy

An organization’s digital assets can be protected from cyber-attacks by using a proactive security strategy, which can be broken down into smaller building blocks.

Understanding of the Evolving Threat Landscape

It’s essential to stay up to date on new threats, attack techniques, and vulnerabilities if you want to be able to predict and be ready for attacks. Unfortunately, not all businesses employ or contract with the cybersecurity experts required to stay current with the constantly evolving threat landscape. They are therefore forced to resort to more expensive and ineffective reactive procedures because they are unable to change their security measures in a proactive manner.

source: https://www.esds.co.in/blog/developing-a-proactive-security-strategy-for-your-organization/
AutoHotKey を使って、Windows Terminal の Emacs に C-SPC、M-RET を送る

# はじめに

Windows Terminal などのターミナルエミュレータはキー入力をアスキーコードとして受け取る。その場合、１部の特殊キーは認識されない。

Emacs で良く利用するキー、コマンドとして C-SPC を使った set-mark-command があるが、C-SPC が Windows Terminal 上では使えないため、Windows Terminal から ssh 接続した先で Emacs を利用する際、set-mark-command が使えない。

一方で Emacs には event-apply-*-modifiers という関数があり、後続のキーの前にモディファイアキーが押されているとしてキー入力を受け付けることができ、C-x @ [hsmaSc] に割当られている。例えば C-x @ c SPC と入力すれば C-SPC に割当られたコマンドを呼び出すことができる。

そこで、AutoHotKey で Windows Terminal を利用しているときに C-SPC が押されたら、
C-x @ c SPC を送信するように設定する。

# Emacs 設定
event-apply-*-modifers にはコントロールキーとメタキーの同時利用のための関数は用意されていない。そのための関数を定義する(StackOverflow より)

```elisp
; https://superuser.com/questions/83166/using-c-m-to-do-a-query-replace-regexp-in-emacs-running-in-mac-terminal                                               
; cargo cult adaptation of event-apply-control-modifier
(defun event-apply-control-meta-modifiers (ignore-prompt)
  (vector
   (event-apply-modifier
    (event-apply-modifier (read-event)
                          'control 26 "C-")
    'meta 27 "M-")))
(define-key function-key-map (kbd "C-x @ %") 'event-apply-control-meta-modifiers)
```

# AutoHotKey 設定

※ sleep は気持ち、無くても動くはず

```
#IfWinActive, ahk_exe WindowsTerminal.exe
{
^Space::
{
    Send, ^x
    Sleep, 50
    Send, @
    Sleep, 50
    Send, c
    Sleep, 50
    Send, {Space}
    Return
}
}

#IfWinActive, ahk_exe WindowsTerminal.exe
{
^!Space::
{
    Send, ^x
    Sleep, 50
    Send, @
    Sleep, 50
    Send, `%
    Sleep, 50
    Send, {Space}
    Return
}
}

#IfWinActive, ahk_exe WindowsTerminal.exe
{
!Enter::
{
    Send, ^x
    Sleep, 50
    Send, @
    Sleep, 50
    Send, m
    Sleep, 50
    Send, {Enter}
    Return
}
}

```

# 参考 (WezTerm バージョン)

```
config.keys = {
  {
    key = 'Enter',
    mods = 'META|SHIFT',
    -- action = wezterm.action.SendString 'Test'
    action =  wezterm.action_callback(function(win, pane)
      win:perform_action(wezterm.action.SendKey{ key = 'x', mods = 'CTRL' }, pane)
      win:perform_action(wezterm.action.SendKey{ key = '@', mods = '' }, pane)
      win:perform_action(wezterm.action.SendKey{ key = '%', mods = '' }, pane)
      win:perform_action(wezterm.action.SendKey{ key = 'Enter', mods = '' }, pane)
    end),
  },
}
```
python maya delete all keys

```python
import maya.cmds as cmds

# Get all joint nodes
joints = cmds.ls(type="joint")

# Filter out joints that do not have any keys
keyed_joints = [joint for joint in joints if cmds.keyframe(joint, q=True, keyframeCount=True) > 0]

# Print the names of all the keyed joints
for joint in keyed_joints:
    print(joint)
    
mySel = keyed_joints

test = []
try:
	test += cmds.listConnections(mySel,s=True, type="animCurveTU")
except:
	pass
try:
	test += cmds.listConnections(mySel,s=True, type="animCurveTL")
except:
	pass
try:
	test += cmds.listConnections(mySel,s=True, type="animCurveTA")
except:
	pass

cmds.delete(test)
```
python maya rename joints

```python
import maya.cmds as cmds

# Get a list of all nodes that end with '_M'
nodes_to_rename = cmds.ls("*:*_M")

# Rename each node to end with '_Mocap_M'
for node in nodes_to_rename:
    new_name = node.replace("_M", "_Mocap_M")
    cmds.rename(node, new_name)

nodes_to_rename = cmds.ls("*:*_L")

for node in nodes_to_rename:
    new_name = node.replace("_L", "_Mocap_L")
    cmds.rename(node, new_name)

nodes_to_rename = cmds.ls("*:*_R")

for node in nodes_to_rename:
    new_name = node.replace("_R", "_Mocap_R")
    cmds.rename(node, new_name)
```