OmniAICreator/Qiita-1.07M huggingface dataset:
An error occurred (InsufficientCapabilitiesException) when calling the CreateChangeSet operation: Requires capabilities : [CAPABILITY_IAM] のエラーが発生した時


先日CloudFormation をAWS CLI を使って実行していたところ、
以下のエラーが発生しました。

```text
An error occurred (InsufficientCapabilitiesException) when calling the CreateChangeSet operation: Requires capabilities : [CAPABILITY_IAM]
```

めちゃめちゃざっくりというと、IAM のパワーが足りませんよ！って言ってます。Role の話ではなく、このIAM を作成するけど了承してないよって言ってます！

その時に打ったコマンド

```yaml
aws cloudformation deploy \
--template-file alb-ecs.yml \
--stack-name ecs-test
```


# 解決方法

AWS CLI で一文を足してあげるだけで解決します。
コンソール上では同意を求められるのですが、コマンド上ではそういうインタラクティブな機能ないらしく、明示的に指定してあげる必要があります。
```yaml
aws cloudformation deploy \
--template-file alb-ecs.yml \
--capabilities CAPABILITY_NAMED_IAM \
--stack-name ecs-test
```


補足:

上のコマンドはデプロイするときのコマンドですが、dry run したいなと思ったら、もう一行足してあげる必要があります。--no-execute-changeset をつけることによって、ドライランにすることができます。

```yaml
aws cloudformation deploy \
--template-file alb-ecs.yml \
--capabilities CAPABILITY_NAMED_IAM \
--stack-name ecs-test --no-execute-changeset
```

# まとめ
Cloudformation は最近仕事でも使用することはたまにあるのですが、いつもコンソールで操作していたため、今回はAWS CLI に挑戦してみました。ローカルから実行した時はかなり操作も便利だなと思ったので、どんどん使っていきたいと思います。
CLI の便利さが際立った場面でした。

# 参考資料
https://dev.classmethod.jp/articles/read-aws-cli-cfn-options/

https://www.nullpo.io/2021/04/29/aws-iam-capabilities-named-iam/
【cron】Pythonスクリプト(selenium)を定期実行したい...のに動かない？？

# 目次

[目的](#目的)
[結論](#結論)
[crontabって？](#crontabって？)
[設定してみると...](#設定してみると...)

# 目的

先日、cronでseleniumを用いたPythonのスクリプトを定期実行したかったのですが、なかなか沼にハマったため手順を少しまとめておきます。

# 結論

DISPLAYを記述してあげましょう。

# crontabって？

簡単にいうとUNIX系のOSで使える、定期実行のための便利なコマンドです。

`crontab -e` コマンドで設定できます。
  ```bash
  $ crontab -e
  ```
この辺の操作は調べたらいくらでも出てくると思うので割愛します。

# 設定してみると...

適当にPythonのスクリプトを書いて設定してみます。

  ```python
import datetime
now = datetime.datetime.now()
date_string = now.strftime("%Y-%m-%d %H:%M:%S")
print(date_string)
  ```

  ```bash
* * * * * /usr/bin/python /home/test/Desktop/test.py >> /home/test/cron.log 2>&1
  ```
動くかと思いきや、、、動きません。
どうやらcrontabにはパスをちゃんと書いてあげる必要があるようです。

```bash
$ echo $PATH
/usr/local/sbin:...
```

これを書いてあげます。
```bash
PATH=/usr/local/sbin:...
* * * * * /usr/bin/python /home/test/Desktop/test.py >> /home/test/cron.log 2>&1
```

するとちゃんと動きました！
必要そうな環境変数はちゃんと渡してあげたほうがいいですね。

# seleniumを用いたスクリプトを設定してみる

ではseleniumを用いたスクリプトを指定してみましょう。
適当にテスト用のスクリプトを用意してみます。

```python
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager

driver = webdriver.Chrome(ChromeDriverManager().install())
driver.get("https://www.google.com")
driver.quit()
```

すると、、、、動かない。

うんともすんとも言いません。

色々調べてみると、DISPLAYも書いてあげる必要があるようです。
というのも、環境変数のDISPLAYがブラウザの表示に必要なようです。全然知らなかったです。

調べてみます。

```bash
$ env | grep DISPLAY

DISPLAY=:0
```

ちゃんと書いてみます。

```bash
PATH=/usr/local/sbin:...
DISPLAY=:0
* * * * * /usr/bin/python /home/test/Desktop/test.py >> /home/test/cron.log 2>&1
```

ようやく動きました！！！！！！

というわけで、cronでselenium(に限った話ではないですが)を定期実行したいときはちゃんと環境変数を渡しましょうというお話でした。
独自プレイヤー(video)でHLS.JS配信とかで再生が詰まった(?)時のゴニョゴニョのやつ

こういうやつ。再生中によく出るやつ。
![スクリーンショット 2024-02-03 0.06.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3691016/e15c3855-bb19-727d-333f-86609100d5fc.png)

HLSとかプレイヤーを自分でゴニョゴニョ実装してた時、個人的にすげぇ困ったのでメモる。
HLSのやり方は https://stream.77lab.cloud のソースを開発者ツールで見てくれたらいいよ。
今回はこの「ロード中だお少し待て」の探知方法を書くので。

こんなVIDEOタグを使っている前提だお:
```
<video id="VIDEO" class="h-full w-full" ....></video>
```
したが再生が詰まった時の

```
VIDEO_EL = document.getElementById("VIDEO"); //VIDEOタグを取得するお

VIDEO_EL.addEventListener('waiting', function() { //イベントを監視するお。この場合はwaitingに監視してるお。
    //ロード中な時の処理をここに書いてね。例えば例のクルクルを出すとか。
});
VIDEO_EL.addEventListener('stalled', function() {
    //ロード中
});

VIDEO_EL.addEventListener('playing', function() {
    //再生中だお。ロード中の時の処理を終わらせようね。永遠にロード中みたいになるお^^;;
});

VIDEO_EL.addEventListener('canplaythrough', function() {
    //再生中
});
```
Docker Desktopでコンテナが自動的にstartされるのを防ぎたい！

## はじめに
Docker Desktopを起動するとコンテナが自動起動されて
いちいち停止するのめんどくさいなと思ったので調べてまとめてみました。
## 原因
ymlファイルでよく見るrestartの部分が原因らしい
```docker-compose.yml
restart: always
```
## 解決法
#### restartの部分をnoに書き換える
```docker-compose.yml
restart: no
```
このように書き換えることでコンテナが自動生成されることを防ぐことができました。

ドキュメントによるとDockerには再起動ポリシー（restart policy）という物があり
`restart`に`no(デフォルト)`、`on-failure`、`always`、`unless-stopped`の４種類がある。
コンテナを自動的に再起動しないのは`no`だけらしい。
[Docker日本語ドキュメント](https://docs.docker.jp/config/container/start-containers-automatically.html)

:::note warn
今回は「Docker Desktopを起動するとコンテナが自動起動される」ということを
防ぐ目的です。
:::

## わざわざコンテナ作り直すの嫌な時
そんな時はコマンドで解決できるらしい！

step1: alwaysになっているコンテナを取得します。
```bash:step1
docker inspect -f "{{.Name}} {{.HostConfig.RestartPolicy.Name}}" $(docker ps -aq) | grep always
```
```bash:step1-出力結果
/hoge-db always
/hoge-minio always
/hoge-firebase always
```
こんな感じで出力されると思います。

step2:その中からnoにして自動起動してほしくないコンテナに以下のコマンドを使う
```bash:step2
docker update --restart=no /hoge-db
```
このようにして特定のコンテナを自動起動しないようにできます。
参考記事：https://www.pressmantech.com/tech/6522#comment-97436

## なんなら全部のコンテナ自動起動にしなくていいよーって時
以下のコマンドを行うことで、すべてのコンテナを`no`にできます。
```bash
 docker ps -aq | xargs -I {} docker update --restart=no {}
```

## まとめ
・restart（再起動ポリシー）をnoにすることで、Docker Desktopでコンテナが自動的に
startされるのを防ぐ事ができる。

## 終わりに
今回初めて記事を書かせてもらいました。
「ここ違うよ～」とか「こうできるんじゃない？」とかあったら色々教えてください。
よろしくお願いします。🙇

最後まで読んでいただきありがとうございました。
AWS SAM CLIで「Unable to upload artifact HelloWorldFunction referenced by CodeUri parameter of HelloWorldFunction resource.」エラーを解決する方法


# はじめに

AWS SAM CLI を使用して`sam deploy`コマンドを実行した際に「Unable to upload artifact HelloWorldFunction referenced by CodeUri parameter of HelloWorldFunction resource.」というエラーメッセージが表示され、デプロイが行えない問題の解決策を紹介します。
この方法は根本的な解決にはなりませんが、すぐにデプロイを進めたい場合に役立ちます。

## 動作環境と対象者

- AWS SAM CLI を Homebrew を通じてインストールしている方
- 使用バージョン：
  - SAM CLI: version 1.108.0
  - AWS CLI: 2.15.16, Python/3.11.7, Darwin/23.3.0, source/arm64

```bash
sam --version
SAM CLI, version 1.108.0
```

```bash
aws --version
aws-cli/2.15.16 Python/3.11.7 Darwin/23.3.0 source/arm64 prompt/off
```

## エラーの再現

- `sam build`は成功しますが、`sam deploy`でエラーが発生します。

  ```bash
  sam build
  ...(snip)...
  Build Succeeded

  sam deploy
  ...(snip)...
  Error: Unable to upload artifact HelloWorldFunction referenced by CodeUri parameter of HelloWorldFunction resource.
  An HTTP Client raised an unhandled exception: sequence item 0: expected str instance, bytes found
  ```

## 解決方法

- Homebrew を使用してインストールした AWS SAM CLI を一度アンインストールし、公式のパッケージインストーラから再インストールします

1. **AWS SAM CLI のアンインストール手順**

   - Homebrew を使用して AWS SAM CLI をアンインストール：

     ```bash
     brew uninstall aws-sam-cli
     which sam
     #sam not found
     ```

   - AWS 管理のリポジトリを untap し、キャッシュをクリア：

     ```bash
     brew untap aws/tap
     brew cleanup aws/tap
     ```

   - Homebrew およびフォーミュラを更新：

     ```bash
     brew update
     ```

2. **AWS SAM CLI のインストールパッケージを使用したダウンロード**
   - アンインストール後、[AWS 公式サイト](https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/install-sam-cli.html)の指示に従い、インストールパッケージを使用して AWS SAM CLI をダウンロードしてください

https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/install-sam-cli.html

## 補足

- 下記のように Homebrew インストーラーのメンテナンスを公式では行わなくなったので、このタイミングでインストールパッケージを使用したダウンロードに切り替えても良いかもですね。
  > 2023 年 9 月以降、AWS では AWS で管理される AWS SAM CLI (aws/tap/aws-sam-cli) 用 Homebrew インストーラーのメンテナンスを行いません。

https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/install-sam-cli.html#install-sam-cli-instructions

- 2024 年 2 月 2 日時点で、AWS SAM CLI の GitHub Issue にこの問題に似たような報告があります。([参照リンク](https://github.com/aws/aws-sam-cli/issues/6629))

https://github.com/aws/aws-sam-cli/issues/6629
【JavaScript】オブジェクトをマージする方法

## スプレッド構文

```js
const obj1 = { a: 1, b: 2, c: 3 };
const obj2 = { d: 4, e: 5, f: 6 };
const result = { ...obj1, ...obj2 };

console.log(result);
// => { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6 }
```

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Spread_syntax

## Object.assign()

```js
const obj1 = { a: 1, b: 2, c: 3 };
const obj2 = { d: 4, e: 5, f: 6 };
Object.assign(obj1, obj2);

console.log(obj1);
// => { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6 }
```


https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
【備忘】APIとは

## APIとは

API＝Application Programming Interface
要は、「 **アプリ同士をつなぐための取り決め** 」である

### APIの重要性
・効率向上
APIを利用することで、開発者は特定の機能やデータを自分のアプリケーションに組み込むことができ、複雑な機能をゼロから構築する手間を省くことが可能

・データの共有:
異なるサービスやアプリケーションがAPIを介してデータを共有することで、ユーザーエクスペリエンスが向上し、ユーザーはシームレスな体験を享受できる

・イノベーションの促進
APIは開発者にとって新しいアイデアや機能を生み出すための土壌となり、新しいサービスやプロダクトの創造を促進できる

### APIを使用するメリットデメリット
#### メリット
・サービスの利便性が向上する
⇒APIを利用することでサービスの価値・利便性が向上する
・データを活用できる
⇒APIを利用しデータを取得し、取得したデータを有効活用可能
・開発の効率化
⇒API連携可能な他のツール等を組み合わせ開発なども可能
・セキュリティの向上
⇒API活用することでログイン機能（セキュリティ対策）を代替可能


#### デメリット
 ・API提供サービスに依存してしまう
⇒機能が外部サービス起因で使用できるなる可能性あり


### 

### APIの種類
◆ウェブ API
・RESTful API: HTTPプロトコルを使用し、リソースを表現し、操作するアーキテクチャ。
・SOAP API: XMLを用いた通信プロトコルを利用するもの。

◆ライブラリ API
ソフトウェア開発のための関数やクラスを提供する。

◆オペレーティングシステム API
オペレーティングシステムが提供する機能にアクセスするためのAPI。

◆データベース API
データベースとの対話に使用されるAPI。

◆クラウド API
クラウドサービスとの連携や操作のためのAPI。

### 実際の活用事例
・Google Maps API: 多くのアプリケーションが地図機能を組み込む際に、Google Maps APIを利用しています。これにより、開発者は簡単に地図データを統合可能

・Twitter API: 多くのソーシャルメディアツールは、Twitter APIを使用してリアルタイムのツイートやトレンドを取得し、ユーザーに提供している。

・OpenWeatherMap API: 天気情報を取得するために使用されるAPIで、多くの天気アプリがこれを利用してリアルタイムの天気予報を表示している。

### まとめ
APIは現代のソフトウェア開発において欠かせない要素であり、異なるシステムやサービスがシームレスに連携できる基盤を提供している。
開発者や企業がAPIを理解し、効果的に利用することで、柔軟で拡張可能なアプリケーションを構築することが可能となる。


参考情報
https://www.udemy.com/course/digital_api/
https://mintaku-blog.net/api-difference/
[CAIレシピ] プロセス実行環境の切り替え(Secure Agent環境での実行)

## はじめに

[プロセスの作成と実行(匿名認証と基本認証)](https://qiita.com/shunsuzu/items/e122c0bbd9d45ee504db)ではクラウドサーバー上で動作するCAIプロセスの作成手順を確認しました。この記事では次のポイントを確認します。

- CAIプロセスをSecure Agentで実行するための実装手順
- CAIプロセスの実行(http/https)

なお、この記事は次の記事の内容を理解していることを前提としています。

- [はじめてCAIを使う際に](https://qiita.com/shunsuzu/private/12b8dbd08a30efa0003a)
- [プロセスの作成と実行(匿名認証と基本認証)](https://qiita.com/shunsuzu/private/01d91caedb92bd7781ea)


## CAIプロセスをSecure Agentで実行するための設定手順

### CAIプロセスの作成

1. [匿名認証のCAIプロセスの作成手順](https://qiita.com/shunsuzu/items/01d91caedb92bd7781ea#CAIプロセス作成手順) と同じ手順で新規にCAIプロセスを作成します。
(名前を __recipe-psa-HelloWorld__ として保存、パブリッシュをする前の手順まで進める)
1. __開始タブ__ に切り替えて、__匿名アクセス__ を有効化、 __ランタイム環境__ プロパティにCAIプロセスをデプロイするSecure Agentを指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074553/85202c80-e78f-a4e6-7ebf-a29873eefd77.png)

1. __保存__ / __パブリッシュ__ を実行して、 __サービスURL__ を確認します。
1. サービスURLのホスト名の部分が __localhost:7443__ となっていることを確認します。
(必要に応じてlocalhostの部分を変更して実行します)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074553/397207e9-6795-a2b2-8c71-902b11d81072.png)


### CAIプロセスの実行(HTTP)

HTTPにてCAIを実行する場合、確認したサービスURLを次のように変更します。

- プロトコルをhttpsから __http__ に変更
- ポート部(7443)を __7080__ に変更

```:HTTPとしてCAIプロセスを実行
// curl コマンド
curl http://localhost:7080/process-engine/public/rt/recipe-psa-HelloWorld

// 実行結果
{"out":"Hello World"}
``` 


:::note info
HTTPポートを無効化できないの？
残念ながら現状ではHTTP呼び出しを無効化することはできない様です。
HTTPを無効化する要望はFeature RequestとしてICAI-16978が登録されています。
[ICAI-16978 : Ability to block incoming HTTP request to the IPD process deployed on the agent.](https://network.informatica.com/s/ideadetail?id=0876S000000K0JrQAK)
:::

### CAIプロセスの実行(HTTPS)
HTTPSとして実行する場合、curlコマンドの-kオプションを指定します。
```:HTTPSとしてCAIプロセスを実行
// curl コマンド
curl -k  https://localhost:7443/process-engine/public/rt/recipe-psa-HelloWorld

// 実行結果
{"out":"Hello World"}
``` 

-kオプションを指定しない場合、次のように証明書の検証エラーが発生します。
```
curl: (60) Issuer certificate is invalid.
More details here: http://curl.haxx.se/docs/sslcerts.html

curl performs SSL certificate verification by default, using a "bundle"
 of Certificate Authority (CA) public keys (CA certs). If the default
 bundle file isn't adequate, you can specify an alternate file
 using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
 the bundle, the certificate verification probably failed due to a
 problem with the certificate (it might be expired, or the name might
 not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use
 the -k (or --insecure) option.
```

プロジェクトの方針で証明書の検証を必要とする場合、次の記事で紹介している手順で証明書を再作成します。
- [Secure Agent環境の証明書入れ替え](https://qiita.com/shunsuzu/private/c7c520fba50e7934375e)

## 参照

- [Qiita - IICS CAIの実装レシピ - マスターページ](https://qiita.com/shunsuzu/items/3d1971ef6e3b993516aa)
SuPar-UniDicで日本語係り受け解析

日本語係り受け解析モジュール[SuPar-UniDic](https://pypi.org/project/suparunidic/)は、[単語間係り受け](http://kanji.zinbun.kyoto-u.ac.jp/~yasuoka/publications/kakariuke.html#3)と[二文節間係り受け](http://kanji.zinbun.kyoto-u.ac.jp/~yasuoka/publications/kakariuke.html#2)の両方をサポートしている。Google Colaboratoryで動かしてみよう。

```
!pip install suparunidic
import suparunidic
nlp=suparunidic.load()
doc=nlp("吾輩はここで始めて人間というものを見た")
import deplacy
deplacy.serve(doc,port=None)
from suparunidic import bunsetu_span,bunsetu_spans
from deplacy.deprelja import deprelja
d=bunsetu_spans(doc)
g="digraph{"+";".join([f'x{b.start}[label="{b.text}"]' for b in d]+[f'x{bunsetu_span(t).start}->x{b.start}[label="{deprelja[t.dep_]}",fontsize=9]' for b in d for t in b.lefts])+"}"
import graphviz
graphviz.Source(g)
```

「吾輩はここで始めて人間というものを見た」を係り受け解析してみたところ、私(安岡孝一)の手元では以下の結果が得られた。

```
1	吾輩	我が輩	PRON	代名詞	_	12	nsubj	_	SpaceAfter=No|Translit=ワガハイ
2	は	は	ADP	助詞-係助詞	_	1	case	_	SpaceAfter=No|Translit=ワ
3	ここ	此処	PRON	代名詞	_	5	obl	_	SpaceAfter=No|Translit=ココ
4	で	で	ADP	助詞-格助詞	_	3	case	_	SpaceAfter=No|Translit=デ
5	始め	始める	VERB	動詞-非自立可能	_	12	advcl	_	SpaceAfter=No|Translit=ハジメ
6	て	て	SCONJ	助詞-接続助詞	_	5	mark	_	SpaceAfter=No|Translit=テ
7	人間	人間	NOUN	名詞-普通名詞-一般	_	9	obl	_	SpaceAfter=No|Translit=ニンゲン
8	と	と	ADP	助詞-格助詞	_	7	case	_	SpaceAfter=No|Translit=ト
9	いう	言う	VERB	動詞-一般	_	10	acl	_	SpaceAfter=No|Translit=ユー
10	もの	物	NOUN	名詞-普通名詞-サ変可能	_	12	obj	_	SpaceAfter=No|Translit=モノ
11	を	を	ADP	助詞-格助詞	_	10	case	_	SpaceAfter=No|Translit=オ
12	見	見る	VERB	動詞-非自立可能	_	0	ROOT	_	SpaceAfter=No|Translit=ミ
13	た	た	AUX	助動詞	_	12	aux	_	SpaceAfter=No|Translit=タ
```

![SuPar-UniDic1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/428317/706af81f-0f93-3c62-6352-9a3dd9bd6351.png)
![SuPar-UniDic2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/428317/aa552e1a-66d0-6ffc-7224-63b911db2888.png)

[ja-ginza-bert-largeと較べた場合](https://qiita.com/KoichiYasuoka/items/71b1044f2389c7b604d9)、「人間という」の部分の解析結果が異なっており、二文節間係り受けについては[jdepp-pythonの解析結果](https://qiita.com/KoichiYasuoka/items/c2a44f683a9fd678bb33)に近い。このあたりを、ぜひ色々な文で較べてみてほしい。
C++ 文字列を区切る

# 初めに
これで二つ目の記事となります。TETTSUNです。
この記事は、ライブラリ紹介となっています。

ライブラリはgithubに公開しています。以下がそのリンクです。
<a href=https://github.com/GAS-projects/MyLibraries>Click on this.</a>

このリンクから、`Libraries/c++/Split関数`を見つけて、ヘッダファイルとcppファイルを入れてください。

# 簡単に紹介
このc++ライブラリは、特定の文字列を指定した文字で区切り、それをリスト(vector)に入れるというものです。

たとえば、`"Hello, my name is Kenta."`の文字列を`' '`で区切ると、リストの中身は、

- `"Hello,"`
- `"my"`
- `"name"`
- `"is"`
- `"Kenta."`

となります。文字列を`' '`で分けていることが分かるでしょうか？

文字列を区切るためには、`Split()`を呼び出します。

# 使い方
文字列を区切るためには、`Split.h`をインクルードし、`Split()`を実行しましょう。

・main.cpp

```
#include <iostream>
#include <vector>
#include "Split.h"

using namespace std;

int main() {
#include <iostream>
#include <vector>
#include "Split.h"

using namespace std;

int main() {
  string str = "Hello, that is the real person. That's so cool and beautiful!";
  vector<string> strArray;

  strArray = Split(str, ' '); //これが区切るための関数。
  for(int i = 0; i < strArray.size(); i++) cout << strArray[i] << endl;
  
  return 0;
}
```

以上のコードを実行すると、出力は、

```
Hello,
that
is
the
real
person.
That's
so
cool
and
beautiful!
```

となります。strArrayリストに、区切られた文字列たちが格納されて、それが出力されています。

では、関数の詳しい使い方を説明します。

まず、`Split()`には三つの引数があります。

- 第一引数(`const std::string str&`)・・・区切られる文字列を格納。

- 第二引数(`char splitChar`)・・・区切る文字。

上記のサンプルコードだと、`str`を`' '`で区切り、`strArray`に、それらを格納するという形になります。

関数の戻り値を、リストに代入する形になります。[^1]

なお、区切る文字(このサンプルコードだと`' '`)は、区切られた文字列には含まれずに無視されます。[^2]

[^1]:なお、もともとリストに何かしらの要素が入っていた場合、それらはすべてリセットされ、区切られた文字が入ってくることになります。
[^2]:もし区切り文字が複数並んでいた場合、それらに関してもすべて無視されます。

# 最後に
正直、文字列を区切る方法はほかにもたくさんあるので、わざわざ利便性の低いこのライブラリを使う必要はないかなと思います。

あくまでもこのライブラリは趣味程度の気持ちで作ったものです(笑)
助けて！名付けは難しい，suspended_atはやめとけ．

あなたが，Userモデル（またはUserテーブル）に，**アカウント停止機能**を追加するとして，その状態をもつフィールド名はどれにしますか？

1. **suspended_at** (datetime型)
1. **is_suspended** (bool型)
1. **is_active** (bool型)
1. **suspended_from** (datetime型)

要件によって，変わるだろうというのはそうなんですけど，実務の場合は，要件は**アカウント停止機能**としか決まってないことはざらにありますし，じゃあ，関係者をわざわざあつめて要件定義を行う機能サイズでもない．
そうなると，フィールド名をどうするかというのは，そのときコードを書く人に一任されてしまうんですよね．

## suspended_at
代表的なORM（例えばRailsのActiveRecord）の場合，created_atとupdated_atが，モデル標準のフィールドとして自動定義されているので，そこからの横並びだと，素朴に名づけるフィールド名．
アカウントが停止から復帰した場合，このフィールドの値はどうなるのだろうという疑問がわいてくる．
システム運用上，停止日時を知りたいということはそんなに多くない気がする．

## is_suspended
非常に素直なフィールド名，停止しているならTrue，停止していないならFalse．

## is_active
なんて天邪鬼なんだろうかと思っちゃう．値がnullだったら，停止しているのだろうか．

## suspended_from
アカウントにはライセンス期限があったりするので，運用上使いやすい．でも**アカウント停止機能**というキーワードだけですぐ思いつくかというと微妙．

# 名付けは関連の実装に影響を与える
先にモデルをつくったときに，同僚がフィールド名をみて何を考えるのかというのが変わってくる．
**is_suspended**や**is_active**ならUIは自然とスイッチになるだろうし，**suspended_from**ならカレンダーになると思う．
そう思うと**suspended_at**は同僚に対してどのような実装をすればいいか悩ませてしまう余地があるのでいい実装じゃないかも．
【Swift】浮動小数点型のものを整数部分と小数部分に分ける

# はじめに
整数部分を小数部分を別で取得したい場面があったとします。
パッと思いつくのは、Stringにして小数点で分割するみたいな感じです。
しかし、数値を扱っているのに文字列にするのは予期せぬバグが生まれそうです。

そこで、`modf`です。
`modf`を使用すると、整数部分と小数部分でしっかり分けてくれます。

# 実装
```swift
import Foundation

// Float型
let float: Float = 3.5
// Double型
let double: Double = 3.5

print(modf(float)) // (3.0, 0.5)
print(modf(double)) // (3.0, 0.5)
```

# おわり
知らなかったので勉強になりました。

# 参考記事
https://www.alphacodingskills.com/swift/notes/swift-math-modf.php
【Python】累計学習時間と今日の学習時間を合計するプログラムを作った

## はじめに

私が在籍しているHappiness Chainというプログラミングスクールでは、学習した日に日報を提出します。日報には今日の学習時間と、**入会してからの累計学習時間**を記入します。

<img width="300" alt="46be4c69-bd21-3e89-12b7-7db98a2a22e3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911578/46be4c69-bd21-3e89-12b7-7db98a2a22e3.png">

この累計学習時間を毎回計算するのが面倒だったので、先日、計算用のシェルスクリプトを作りました。

https://qiita.com/wsigma21/items/3b9c788270e56532fbd9

このシェルスクリプトでは、最新の累計学習時間をテキストファイルにリダイレクトして上書きしています。

これを見た他の受講生の方に「学習時間の積み上げが可視化できるように、上書きではなく**テキストファイルに追記していく**形式が良いのでは」というアイディアをもらいました。

個人的には、最新の累計学習時間がトップにある方が見やすいので、以下のように出力されるようにしたいと思います。

```log.txt
773h42m
771h42m
770h40m
760h38m
...
```

また、シェルスクリプトよりもPythonの方が絶対に簡単に書けると思ったので、今回はPythonで作成してみました。

## 完成したコード

ファイルの先頭に追記するのに`textfile`パッケージを使用しているため、インストールが必要です。

```bash
$ pip install textfile
```

コードに関する説明はコメントに記載しています。

```python:calc_times.py
import sys
import textfile

def main(todays_time):
    # 記録用ファイルのパスを指定
    log_file = 'log.txt'
    # 最新の累計時間をファイルから取得
    f = open(log_file, 'r')
    current_total = f.readline()
    # ファイルが空なら0h0m扱い
    if not current_total:
      current_total = "0h0m"
    f.close()

    # 時刻補正
    hours1, minutes1 = time_correction(current_total)
    hours2, minutes2 = time_correction(todays_time)

    # 学習時間を足す
    total_hours = hours1 + hours2
    total_minutes = minutes1 + minutes2

    # 60分以上なら時間に補正
    if total_minutes >= 60:
        total_hours += total_minutes // 60
        total_minutes %= 60

    # 結果を表示
    result = f"{total_hours:02d}h{total_minutes:02d}m"
    print(result)

    # 結果をファイルの先頭に書き出し
    textfile.insert(log_file, result+'\n', line=0)

def time_correction(time_entered):
    """
    時刻補正用関数

    :param time_entered : "1h02m"のような時刻を表す文字列
    :type time_entered: string
    :returns 時間数と分数
    :rtype: tuple
    """
    # hがなければ0hを追加
    if not "h" in time_entered:
        time_entered = '0h' + time_entered
    # mがなければ0mを追加
    elif not "m" in time_entered:
        time_entered = time_entered + '0m'
    hours = int(time_entered.split('h')[0])
    minutes = int(time_entered.split('h')[1].split('m')[0])
    return hours, minutes

if __name__ == '__main__':
    # 引数チェック
    args = sys.argv
    if len(args) <= 1:
        print("Enter today's study time in a format such as '1h02m'.")
    elif len(args) > 2:
        print("Too many arguments")
    else:
        main(args[1])
```

## 利用例

`log.txt`を作成し、累計学習時間を記入しておきます[^1]。

```log.txt
773h42m
```

引数に今日の学習時間を指定して実行すると、累計学習時間を計算し、ターミナルに表示し`log.txt`の先頭に記入します。

```bash
$ python calc_times.py 1h02m
774h44m
```

```log.txt
774h44m
773h42m
```

### 補足

以下のように、時間か分どちらかのみだけでも計算できます。

```bash
$ python calc_times.py 1h
```

```bash
$ python calc_times.py 45m
```

分を0埋めしていなくても問題ありません。

```bash
$ python calc_times.py 1h2m
```

## 終わりに

簡単なプログラムでも自分の役に立つものを作ることができるのは嬉しいですね！

そしてやはり、Pythonの方がシェルスクリプトより圧倒的に書きやすかったですw

## 参考

https://qiita.com/m_mizutani/items/c48f67f871d1d41ff4b9

https://qiita.com/taashi/items/07bf75201a074e208ae5

https://jimaru.blog/programming/python/insert-text-to-file/

https://note.nkmk.me/python-split-rsplit-splitlines-re/

https://qiita.com/flcn-x/items/393c6f1f1e1e5abec906

[^1]:空の場合は0h0mと見做されます。
研究の振り返り

研究を終え，事前に確認すべきだった...と後になって思ったことを書きおきます

# 実験にあたって
## データセットは正しいか？
- 　SMILESには溶媒が入っていないか？
- 　データセット内での重複・テストデータセットとの重複はないか？
- 　分子量の分布はおかしくないか？

## その条件で実験して比較できるか？
- 　データ・アーキテクチャ等々，比較したいところ以外は揃っているか？


## 学習時のログは残るようになっているか？
- 　手元の環境で実験する際も，ログをファイルに出力する癖をつけておく
- 　よほどメモリを圧迫するようでなければ，研究が終わるまで不用意に消さない
- 　損失の推移のログに関しては，wandbに登録しておくのがお手軽


# 執筆にあたって
## 章立てで必要な部分
- 計算環境
    - CPU・GPU・メモリ・OSあたりまで書いておくと無難

## 図表を入れる時の注意
- 表のキャプションは上部，図のキャプションは下部
- Texで図表に引用を入れる際は，`\caption{hoge}[hoge\cite{fuga}]`として，図表の目次には引用を出さないようにする
- グラフや図に文字が含まれる場合は，読めるサイズにするか削除する
- グラフの枠線・目盛りは見えるように太くし，0始まりにする

## 言い回しの部分
- 漢字変換をしっかり
    - 「および」→「及び」，「〜したのちに」→「〜した後に」
- 回りくどくしない
    - 「学習を行った」→「学習した」
- 数値＋単位の間にはスペースを入れる
    - 「5Å」→「5 Å」，「10nm」→「10 nm」
- 堅い言い回し
    - 「〜年に登場した**（研究）によって」→「〜年に報告された**（研究）によって」
- 略称を初めて使う際は書き下す
    - 「ECFP」→「ECFP（Extended Connectivity Fingerprint）」

## 必ず先生や先輩に見てもらう
- ギリギリになって見せても時間がなくなる．余裕を持ってお願いする
    - どの学生も通ってきた道だから，申し訳ないと思わず研究室の人々にお願いしてOK
    - 堅い文章の読み書きに慣れている人に指摘してもらうのが一番良い
透明度を考慮して Texture2D 画像を合成する【Unity】

### 概要

2つの画像を透明度を考慮して加算合成します。

### 使用例

![SynthesisTexture2D.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865650/67c44537-c0a0-5c47-500a-0ae7d33334ca.png)


### コード
```SynthesisTexture2D.cs
// 2つのTexture2Dを合成して、1枚のTexture2Dを返す関数
private async UniTask<Texture2D> GetSynthesisTexture2D(Texture2D baseTexture, Texture2D blendTexture)
{
    // 出力用Texture2D
    Texture2D synthesisTexture = new Texture2D(baseTexture.width, baseTexture.height, TextureFormat.ARGB32, false);

    // RenderTextureを作成して書き込む
    var renderTextureA = RenderTexture.GetTemporary(synthesisTexture.width, synthesisTexture.height);
    Graphics.Blit(baseTexture, renderTextureA);
    var renderTextureB = RenderTexture.GetTemporary(synthesisTexture.width, synthesisTexture.height);
    Graphics.Blit(blendTexture, renderTextureB);

    // Texture2Dを作成してRenderTextureから書き込む
    //現在のRenderTextureをキャッシュする
    var preRT = RenderTexture.active;

    RenderTexture.active = renderTextureA;
    var TextureA = new Texture2D(synthesisTexture.width, synthesisTexture.height);
    TextureA.ReadPixels(new Rect(0, 0, synthesisTexture.width, synthesisTexture.height), 0, 0);
    TextureA.Apply();

    RenderTexture.active = renderTextureB;
    var TextureB = new Texture2D(synthesisTexture.width, synthesisTexture.height);
    TextureB.ReadPixels(new Rect(0, 0, synthesisTexture.width, synthesisTexture.height), 0, 0);
    TextureB.Apply();

    // キャッシュしたRenderTextureを元に戻す
    RenderTexture.active = preRT;

    // RenderTextureの解除
    RenderTexture.ReleaseTemporary(renderTextureA);
    RenderTexture.ReleaseTemporary(renderTextureB);

    // 2枚の画像を合成する
    var pixels = TextureA.GetPixels();
    var blendPixels = TextureB.GetPixels();

    for (int i = 0; i < pixels.Length; i++)
    {
        var basePixel = pixels[i];
        var blendPixel = blendPixels[i];

        var baseAlpha = basePixel.a - blendPixel.a;
        var blendAlpha = blendPixel.a;

        var r = basePixel.r * baseAlpha + blendPixel.r * blendAlpha;
        var g = basePixel.g * baseAlpha + blendPixel.g * blendAlpha;
        var b = basePixel.b * baseAlpha + blendPixel.b * blendAlpha;

        // alpha値 加算合成
        var a = MathF.Min(1.0f, baseAlpha + blendAlpha);

        // どちらも透明度が0の時は、alpha値に0を指定する
        if (basePixel.a == 0 && blendPixel.a == 0) a = 0.0f;

        // 合成後のピクセルの設定
        pixels[i] = new Color(r, g, b, a);
    }
    synthesisTexture.SetPixels(pixels);
    synthesisTexture.Apply();

    return synthesisTexture;
}
```

### 備考
自分の場合は、ノベルゲームを制作する過程でデータ容量削減のため、キャラクターの顔の表情パーツを体の下地と合成する処理を記述する必要がありました。

Unityにおける画像合成って何か良いライブラリとかあるのでしょうか？
知っていれば情報ください！

### 参考記事

https://bluebirdofoz.hatenablog.com/entry/2023/06/09/085054

https://qiita.com/kerupani129/items/4bf75d9f44a5b926df58
ブラウザで遊べるトランプゲームを作りたいのですが 

ブラウザで遊べるトランプゲームを作りたいのですが、
言語はどんなのがいいでしょうか？

初歩的なﾌﾟﾛｸﾞﾗﾐﾝｸﾞなので、VBやC#であればつくることができるのですが、
ダウンロード不要なブラウザで遊ぶには向いていないように思います。

むかしはJAVAアプレットというのがあったようですが今はないみたいですね。

UNITYのプログラミングしてブラウザでプレイするという選択肢もあるようです。
（UNITYまだよくわかってないんで、使いこなせるかどうかわかりません）

アドバイスお願いいたします。
The Future Of Remote Work And Its Innovations And Challenges In 2024

The Future Of Remote Work And Its Innovations And Challenges In 2024

The year 2020 witnessed a massive shift in the way we work, with remote work becoming the new norm for numerous individuals and associations worldwide. As we look ahead to the future, it’s apparent that remote work is then to stay and will continue to evolve in 2024 and further. In this article, we will explore the future of remote work, the inventions that will shape it, and the challenges that come with it. 

https://lifesnipet.com/business/the-future-of-remote-work-and-its-innovations-and-challenges-in-2024/
エンジニアの恋愛は好き避けになる傾向が高い

エンジニアは一般に、論理的思考を重視し、細部にこだわる職業群です。この性質が、恋愛においても影響を与える場合があります。

■論理的思考と感情の抑制
エンジニアは問題解決を論理的に行う傾向があり、感情よりも理性を優先することが多いです。恋愛感情が芽生えた際にも、感情をオープンにすることに慣れていないため、好き避けという形で無意識に感情を抑制してしまうことがあります。

■内向的な性格
エンジニアリングの仕事は集中力と緻密さを要求されるため、職業的に内向的な性格を持つ人が多いです。内向的な人は、自分の感情を表に出すことに消極的であることが多く、これが好き避けの行動に繋がる可能性があります。

■コミュニケーションのスタイル
エンジニアはしばしば、明確で直接的なコミュニケーションを好みます。しかし、恋愛においては、感情を直接的に表現することが難しいため、相手に対して好意を持ちながらも、それをうまく表現できずに避ける行動を取ることがあります。

■社交性の発展
エンジニアの仕事は時に孤立した環境で行われることが多く、社交的なスキルが発達しにくい場合があります。その結果、好意を持つ相手に対してどのように接近していいのか分からず、好き避けという行動に出ることがあります。

■結論
エンジニアにおける好き避けの傾向は、彼らの職業的特性、性格、コミュニケーションスタイル、社交性の発展の過程など、さまざまな要因によって生じる可能性があります。この理解を深めることで、エンジニアの恋愛観をより深く理解することができるでしょう。また、エンジニア自身も自らの感情表現やコミュニケーションスタイルに対する自己認識を高めることが重要です。

■参考サイト
好き避け男子研究所
https://sukizake.com/
【Rails】アプリケーションを作成したときに抜けがちな作業(初心者編)

こんにちは。
今回は初心者が忘れがちでも、当たり前すぎて記事にあまり載っていない作業を載せていきます！

## プラグイン導入
```terminal:
$ yarn add @babel/plugin-proposal-private-methods @babel/plugin-proposal-private-property-in-object
```
これをしないとRailsアプリケーションが動作しません。アプリケーション作成後忘れないうちに！
(私は忘れてしまってdelete機能をきちんとメソッド指定しているのにPOSTで処理されてしまっていることがありました。)

## ホストの許可
```ruby: config/environment/development.rb
  config.hosts.clear
end
```
スクロールして一番下に元々あったconfig.hostsの記述がありますが、それを消して書き換えましょう。
これを忘れてしまうとBlock host:∼以下略というエラーが発生します。

## $ rails db:migrate
 ```terminal
 $ rails db:migrate
 ```
  モデル作成のコマンド(rails g model テーブル名 カラム名:データ型)のあとに忘れがちです。
  
  また、もし間違えてカラムを作成してしまったり、カラムを追加したいときは、まず最初に作成されたマイグレーションファイルを書き換えます。その後、ターミナルでステータスを確認して、修正したいもののIDを確認します。その後、redoを打ち込むとupだったものがdown→upを経て修正した内容がアプリ上に反映されるようになります。カラムの追加や削除をターミナル上で出来るコマンドもありますが、後々面倒なことになった経験があるので、最初の段階ではこちらがおすすめかなと思います。
```terminal
$ rails db:migrate:status #ステータスを確認してIDをコピー
$ rails db:migrate:redo VERSION:ID #IDの場所にペースト
```

以上です。
少しでもお役に立てたらうれしいです。
（実は私が忘れないようにするためのメモ書き的な役割もあります:sweat_smile:）
2024年版　reCAPTCHAの突破（2captcha）



## はじめに
reCAPTCHAの突破（2captcha）に関しての備忘録です。
初心者です😅
間違えてる部分が多々あると思います。
もし見つけた場合、ツッコミいただけると助かります🙇
<br>
# 🦁<INS>**結論**</INS>🦁
**reCAPTCHAを突破するために「2captcha」を使って回避します。**

## <INS>**前提**</INS>🙊
「2captcha」のアカウント作成して「APIKEY」を取得
「2captcha」にチャージ
https://2captcha.com/

【流れ】
サイトにアクセス
→「reCAPTCHA」が出現
→「reCAPTCHA」が出現したサイトの「data-sitekey」を取得（reCAPTCHA近くにある）
→「サイトURL」「data-sitekey」「2captchaのAPIKEY」この3つを「2captcha」にリクエスト。
→「2captcha」が「reCAPTCHA」を代理で解除
→「reCAPTCHA」を解除することで「トークン」が発行
→「2captcha」からのレスポンスで「トークン」を取得
→サイトの特定のtextareaに「トークン」を貼り付けて「ログインボタン」を押下して終了。
※textareaはdisplay:noneを解除しないと入力はできない
※ログインボタンが条件下で無効化されてる場合は有効化する

***


:::note info
押さえておくべき点
*  「2captcha」は有料です。
* reCAPTCHA V2で  15円/回程度（詳細はこちら）
:::  
***


:::note warn
利用シーン
* スクレイピングによる自動ログイン
:::  
***


:::note alert
注意点
* 有料
* セキュリティの難易度が高ければ課金要素は高くなる
* まれにセキュリティの解除に失敗することがある。
:::  
***

## 詳細内容
### reCAPTCHAについて
こういうやつです。（写真）
botなどで自動ログインができないようにしてる。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3522630/aff2665c-7a8b-5abb-41ba-c21457f50363.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3522630/6d6da4c4-9f84-addf-3482-6eec238b7494.png)

***  

### 2captcha
有力でreCAPTCHAを代理でオンライン上で処理してくれてクリアしたデータをもらうことで自動ログインなどを可能にしてくれるAPI。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3522630/f6e62a6e-4b63-7626-eea1-ccfd2b16821d.png)


***  
### data-sitekey
reCAPTCHAのサイトに必ずあるIDみたいなもの。
そのサイト固有のIDが付与されてる。

***
### solveRecaptcha関数
サイトのURL、data-sitekeyを2captchaにデータを渡すことで「解除key（トークン）」をくれる。

```python:sample.py
from twocaptcha import TwoCaptcha

def solveRecaptcha(api_key, sitekey, url):
    solver = TwoCaptcha(YourAPIKey)

    try:
        result = solver.recaptcha(
            sitekey=sitekey,
            url=url)
        return result
    except Exception:
        return "Captcha solving failed"
```
***  

### handle_recaptcha関数
textareaはdisplay:noneを解除しない
→data-sitekeyを検索
→data-sitekeyの値を解析
→2captchaからレスポンスがあったトークンをdata-sitekeyのtextareaに入力

```python:sample.py
def handle_recaptcha(browser, current_url):
    # display:noneを[""](空欄)に書き換え
    chrome.execute_script('var element=document.getElementById("g-recaptcha-response"); element.style.display="";')

    # data-sitekeyを検索
    recaptcha_element = browser.find_element_by_css_selector('[data-sitekey]')

    # sitekeyの値を抽出
    data_sitekey_value = recaptcha_element.get_attribute('data-sitekey')

    result = solveRecaptcha(data_sitekey_value, current_url)

    # トークンをtextareaに入力
    code = result['code']
    textarea = browser.find_element_by_id('g-recaptcha-response')
    chrome.execute_script(f'arguments[0].value = "{code}";', textarea)
```
このあとログインなどのボタン押下などで進む。
※ログインボタンが押せないなどの状態はjsで解除。
***  

## まとめ😺
テストサイトではなく、実際のサイトでやってみると、障害があり、なかなか上手くいきませんでしたが、できた時の快感は今でも忘れられません🤭

***

## 参考にしたサイト📗
reCaptcha v2.0を突破するための2captchaサービス (python版)
Google『reCAPTCHA』を突破！『2Captcha』でブラウザ操作の完全自動化に挑む
XcodeからVSCodeをワンアクションで開く！

**Xcodeで開いてるプロジェクトをVSCodeで開く**とき、Finderを開いてプロジェクトを探してVSCodeにドラッグ&ドロップするという操作を毎回やっていると、開くまでにそこそこ時間がかかって面倒です。
そこで、Xcodeから**ショートカット一発**でVSCodeを開けるようにする方法について解説します！

# そもそもなぜVSCodeを開きたいのか
私は **Git/GitHub操作のツール** としてVSCodeを愛用しています。

- SourceTreeのように**視覚的にブランチの流れを見る**ことができます。([Git Graph](https://marketplace.visualstudio.com/items?itemName=mhutchie.git-graph)という拡張機能)
- ターミナルもあるので、**CUI操作**/**GUI操作**が両方可能！併用すると強いです。
- [GitHub公式の拡張機能](https://marketplace.visualstudio.com/items?itemName=GitHub.vscode-pull-request-github)があるので、**プルリクの作成やレビュー、Issueの管理**もできます。

![VSCodeのスクリーンショット画像](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3566752/73d7e53f-436f-52ca-987c-b309cb91acd5.jpeg)

他にも**コンフリクトの対処**や、**READMEや.gitignoreの編集**などにも使えます。
プレビューを見ながらMarkdownファイルを編集できるのも良いところです。

そんな便利なVSCodeを、Xcodeから一発で開くショートカットの設定方法をお伝えします！

# Step1 - ショートカットの実行ファイルを用意
まずは、`open_vscode.sh`というファイルを作成し、以下の内容を記述します。
パスが変わらないような適当な場所に作成しましょう。ファイル名は別の名前でもOKです。

```shell
#!/bin/bash
open -a "Visual Studio Code" "$(dirname $XcodeProjectPath)"
```

作成したら、その場所でターミナルを開いて以下のコマンドを実行します。

```zsh
chmod 755 open_vscode.sh
```

これは`open_vscode.sh`を実行可能ファイルにするためのコマンドです。

# Step2 - Xcodeでショートカットを登録する
Xcode上で `command`+`,` を押して設定画面を開き、Behaviorsを選択します。
![Xcode設定画面の操作手順説明画像](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3566752/502e301f-15ca-b7df-f1e3-935dc09cd85b.jpeg)
左下の「＋」をクリックして`OpenVSCode`と入力します。
右側を1番下までスクロールして`Run`にチェックを入れ、`Choose Script...`を2回クリックするとファイル選択画面が現れるので先ほど作成した`open_vscode.sh`を選択します。

最後に、OpenVSCodeの隣に表示されている**⌘をダブルクリック**して、割り当てたいショートカットキーを押します。私は `control`+`command`+`V` に割り当てています。元々あるショートカットキーと被っている場合はアラートが出るので分かります。
![Xcode設定画面のスクリーンショット](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3566752/2a10c1be-3113-13a4-5c0e-5ef9e60c879c.png)
これで完了です！
設定画面を閉じて、割り当てたショートカットでVSCodeが開くか確認してみてください。

# 逆に、VSCodeからXcodeを開くには？
こっちは特に設定しなくても簡単に起動できます。
Xcodeは`xed`というコマンドで起動できるので、VSCodeのターミナル上で
```zsh
xed .
```
と打ってEnterすれば開けます。

# 参考にしたもの
https://ios-docs.dev/open-terminal/
PHP 型を知る

phpで変数の型を比較したい時などあると思います。

## gettype関数を使う
gettype関数は引数の型を文字列として返してくれます。
```php
$number = 5;
$numberType = gettype($number);

var_dump($numberType);
```
```
string(7) "integer"
```

if文とかで活躍しそうですね。
CVEMapを使ってみた

# はじめに
2024年1月にリリースされたオープンソースツールであるCVEMapを触ってみた。
自分自身のためのメモとして、分かったことをまとめてみる。


# CVEMapとは
ProjectDiscovery( https://projectdiscovery.io/ )が無償で提供する、CVE(共通脆弱性識別子)を簡単に検索可能にするツール。

https://github.com/projectdiscovery/cvemap

## 主な特徴
+ Go言語で書かれている。
+ データ処理はクラウド上で行われている模様。
+ 無償（ProjectDiscovery Cloud Platformのサインアップが必要）
+ CVEの検索（文字列、ベンダー名、製品名など）
+ CVEをEPSS,KEVなどのデータと連結
+ CSVやJSONでの出力に対応
+ CVEデータの更新は6時間ごと


# インストール

Goのインストールから始める場合は、環境変数の設定が必要となる

参考（macOSの場合):


https://qiita.com/koji0705/items/ec262da03eaa7df6ad8b

インストールに必要なコマンド

    $ go install github.com/projectdiscovery/cvemap/cmd/cvemap@latest

ProjectDiscovery Cloud Platformのサインアップをして、API Keyを取得する必要があるが、Googleアカウントなどがあれば簡単にできる。

API Keyのインポートに必要なコマンド

    $ cvemap -auth


# 使い方
こちらにまとめられている。


https://docs.projectdiscovery.io/tools/cvemap/running


CVSSやEPSSなどの数値データは、数値でフィルタリングできる。記述方法の例は以下の通り。


    $ cvemap -cs '> 7' -es '> 0.3' -f poc,kev,vendor
    
    
![スクリーンショット 2024-02-02 9.32.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155751/7ad95e04-88f2-a7e6-81d4-cc70b5ff2c9d.png)


公開されてからの日数(AGE)でフィルタリングした例
   

    $ cvemap -age '< 10'


![スクリーンショット 2024-02-02 9.30.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155751/12714aa0-5e06-53c2-4a44-85cd9de56245.png)

    

# 使えそうなケース、使えなさそうなケース

特定のベンダーのソフトウェアや特定の製品に注目した脆弱性管理を始める際には、ちょうど良い気がする。

CVE,EPSS,KEVをそれぞれバラバラに参照している場合には、メリットを感じるだろう。

一方で、脆弱性管理のサービスを利用していたり、既にCVEやEPSS、その他の関連情報の生データを定期的に収集して、データをマージするようなシステムを独自に構築している場合は、そちらで十分だと思う。既存の処理の一部をCVEMapに置き換えることで簡素化できるかもしれない。


# 最近公開された脆弱性を用いたケーススタディ

2024年2月1日に報じられたESET製品の脆弱性、"CVE-2023-7043"について、ベンダー名、製品名を使った検索で正しくキャッチできるか試してみる。（2024年2月2日に実施）

https://forest.watch.impress.co.jp/docs/news/1565642.html

ベンダー名で検索してみたが、該当するCVEはヒットしない。

:::note warn
ベンダー名、製品名の検索は、全て小文字で！！
:::

    $ cvemap -vendor eset -f kev,poc,vendor


![スクリーンショット 2024-02-02 19.02.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155751/7dbf6f36-c8ad-c95d-ef84-525fb5072eb1.png)

"-q"オプションを使って、ベンダー名を文字列検索する。

    $ cvemap -q '"ESET"' -f kev,poc,vendor

![スクリーンショット 2024-02-02 19.01.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155751/99a404f2-00f5-8e97-b2ca-81b40da23af4.png)

ヒットしたが、製品名、ベンダー名が空欄だった・・・。公開された直後のCVEを製品名、ベンダー名で検索するとヒットしないケースがある模様。見落としを防ぐには、"-q"オプションを使った文字列検索と併用した方が良さそう。

# ProjectDiscovery Cloud Platformでできること

"テンプレート"と呼ばれる特定の脆弱性などを定義したルールを用いたスキャン。
公開されているテンプレート、自分で作ったテンプレートが使える。
まだ十分なレビューができていないので、詳細は不明。

![スクリーンショット 2024-02-02 19.23.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155751/d984e6c2-6fae-6d86-7796-ce5f982f66cb.png)



# 関連情報
## CVE(Common Vulnerabilities and Exposures)

https://cve.mitre.org/

生データ：

https://github.com/CVEProject/cvelistV5/archive/refs/heads/main.zip


## EPSS(Exploit Prediction Scoring System)

https://www.first.org/epss/

生データ：

https://epss.cyentia.com/epss_scores-current.csv.gz

## KEV(Known Exploited Vulnerabilities)

https://www.cisa.gov/known-exploited-vulnerabilities-catalog

生データ：

https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json
富岳のspack0.19版python3.10でjdepp-pythonを動かすには

[昨日の記事](https://qiita.com/KoichiYasuoka/items/c2a44f683a9fd678bb33)で書いたjdepp-python 0.17の(二文節間)係り受け解析プログラムを、スーパーコンピュータ「富岳」のspack0.19版python3.10に移植してみた。

```
#! /bin/bash
#PJM -L rscgrp=small
#PJM -L elapse=1:00:00
#PJM -L node=1
#PJM -j
#PJM -S

. /vol0004/apps/oss/spack/share/spack/setup-env.sh
spack load py-cython@0.29.32/wmhf2on
G=`id | sed 's/^.*gid=[0-9]*(\([^)]*\)).*$/\1/'`
set `ls -d /vol*/$G /vol*/data/$G` $HOME
export PYTHONUSERBASE=$1/J.DepP
export TMPDIR=$PYTHONUSERBASE/tmp
mkdir -p $TMPDIR
cd $TMPDIR
pip3 install -U jagger jdepp --user
test -d model/kwdlc || curl -L https://github.com/lighttransport/jagger-python/releases/download/v0.1.0/model_kwdlc.tar.gz | tar xzf -
test -d model/knbc || curl -L https://github.com/lighttransport/jdepp-python/releases/download/v0.1.0/knbc-mecab-jumandic-2ndpoly.tar.gz | tar xzf -

P=$PJM_JOBID.$$.py
cat << 'EOF' > $P
import jagger,jdepp
tagger=jagger.Jagger()
tagger.load_model("model/kwdlc/patterns")
parser=jdepp.Jdepp()
parser.load_model("model/knbc")
nlp=lambda x:parser.parse_from_postagged("\n".join(t.surface()+"\t"+t.feature() for t in tagger.tokenize(x))+"\nEOS\n")
doc=nlp("吾輩はここで始めて人間というものを見た")
print(doc,jdepp.to_tree(str(doc)),sep="\n")
EOF
python3 $P
```

富岳のログインノードから`pjsub`してみたところ、ジョブ待ち・ダウンロード等も含め、15分ほどで以下の結果が得られた。

```
# S-ID: 1; J.DepP
* 0 6D
吾輩	名詞,普通名詞,*,*,吾輩,わがはい,代表表記:我が輩/わがはい カテゴリ:人
は	助詞,副助詞,*,*,は,は,*
* 1 2D
ここ	指示詞,名詞形態指示詞,*,*,ここ,ここ,*
で	助詞,格助詞,*,*,で,で,*
* 2 6D
始めて	動詞,*,母音動詞,タ系連用テ形,始める,はじめて,*
* 3 4D
人間	名詞,普通名詞,*,*,人間,にんげん,*
と	助詞,格助詞,*,*,と,と,*
* 4 5D
いう	動詞,*,子音動詞ワ行,基本形,いう,いう,*
* 5 6D
もの	名詞,形式名詞,*,*,もの,もの,*
を	助詞,格助詞,*,*,を,を,*
* 6 -1D
見た	動詞,*,母音動詞,タ形,見る,みた,*
EOS

# S-ID: 1; J.DepP
  0:　　　　　　　　吾輩は━━┓
  1:　　　　　ここで━━┓　　┃
  2:　　　　　　　　始めて━━┫
  3:　　人間と━━┓　　　　　┃
  4:　　　　　　いう━━┓　　┃
  5:　　　　　　　　ものを━━┫
  6:　　　　　　　　　　　　見たEOS
  ```

`jdepp.to_tree()`が少しズレていて、EOSが妙なところにくっついているものの、ちゃんと解析できているようだ。ただ、このやり方だと、manylinux2014_aarch64のバイナリをそのまま使ってしまうため、富岳のa64fxがイマイチ生かせていない。さて、どうしたら、もう少し高速になるかな。
PHP 変数の型変換

変数の型変換方法です。
```php
$number = "580";
var_dump($number);

$number = (int)$number;
var_dump($number);
```
```
string(3) "580" 
int(580)
```
以下のようにすることで入力される値に対しても型の指定が可能です。
```php
$number = (int) trim(fgets(STDIN));
```

簡単でしたね。
react-hook-formで `FieldPathByValue` とコンポーネント・デリゲーションの組み合わせ



デリゲートすることで、ロジックを共有しつつ型を特化させる。

StringFormとNumberFormはそれぞれ文字列型／数値型のフィールドのみしか受け入れない入力フォームのコンポーネントになる。

```ts
import {
  Control,
  FieldPathByValue,
  FieldValues,
  PathValue,
  useController,
  useForm,
} from "react-hook-form";

const SubchildForm = <
  T extends FieldValues,
  P extends Path<T>,
  V extends PathValue<T, P>,
>(props: {
  control: Control<T>;
  name: P;
  defaultValue: V;
}) => {
  const { field } = useController({
    control: props.control,
    name: props.name,
    defaultValue: props.defaultValue,
  });

  return <input {...field}>hello</input>;
};

const StringForm = <
  T extends FieldValues,
  P extends FieldPathByValue<T, string | null | undefined>,
  V extends PathValue<T, P>,
>(props: {
  control: Control<T>;
  name: P;
  defaultValue: V;
}) => {
  return (
    <SubchildForm
      control={props.control}
      name={props.name}
      defaultValue={props.defaultValue}
    />
  );
};

const NumberForm = <
  T extends FieldValues,
  P extends FieldPathByValue<T, number | null | undefined>,
  V extends PathValue<T, P>,
>(props: {
  control: Control<T>;
  name: P;
  defaultValue: V;
}) => {
  return (
    <SubchildForm
      control={props.control}
      name={props.name}
      defaultValue={props.defaultValue}
    />
  );
};

type Schema = {
  name: string;
  job?: string | null;
  age: number;
};

const Page = () => {
  const form = useForm<Schema>({
    defaultValues: {
      age: 10,
    },
  });

  return (
    <div>
      <StringForm control={form.control} name="job" defaultValue={""} />
      <NumberForm control={form.control} name="age" defaultValue={0} />
    </div>
  );
};
```
【ST言語ことはじめ】カウントを利用したランプの点灯制御

## はじめに

プログラマブルロジックコントローラー（PLC）でランプの点灯制御を行う際に、カウンターを活用することは一般的です。この記事では、カウントを利用してランプの点灯を制御する方法について解説します。

## 使用機材

|   |機種など   |
|:---:|------|
|PLC  |Q02CPU, QX41, QY41P, Q62P, Q38B    |
|アプリ  |GX Works 2    |

I/O割り付けはこちらを[参照](https://qiita.com/so2/items/0f0cab2e324179718b89 "I/O割り付け表")

## サンプルプログラム

電源投入時にランプ３が点灯しています。その後ボタン１を3回押すとランプ３が消灯してランプ２が点灯します。さらにボタン１を2回押すとランプ２が消灯してランプ１が点灯します。さらにボタン１を1回押すとランプ３のみが点灯する初期状態になるプログラムです。

### ラダー図

```batch:ラダー図
(+)                                               (-)
|    X1        C2                         C3 K1     |
+----|↑|---+---| |------------------------(    )----+
|          |   C1                         C2 K2     |
|          +---| |------------------------(    )----+
|          |                              C1 K3     |
|          +------------------------------(    )----+
|                                                   |
|    C3                                   RST C1    |
+----| |---+------------------------------(    )----+
|          |                              RST C2    |
|          +------------------------------(    )----+
|          |                              RST C3    |
|          +------------------------------(    )----+
|                                                   |
|    C2                                    Y71      |
+----| |----------------------------------(    )----+
|                                                   |
|    C1     C2                             Y72      |
+----| |----|/|---------------------------(    )----+
|                                                   |
|    C1                                    Y73      |
+----|/|----------------------------------(    )----+
|                                                   |
```

### ST言語 1

カウンタ命令を利用したプログラムです。

```st
PLS(X1, M0);

IF M0 THEN
    M1 := TRUE;
END_IF;

OUT_C(CS2, CC3, 1);
OUT_C(CS1, CC2, 2);
OUT_C(M1, CC1, 3);

RST(CS3, C1);
RST(CS3, C2);
RST(CS3, C3);

Y71 := M1 AND NOT CS1;
Y72 := CS1 AND NOT CS2;
Y73 := CS2;
```

### ST言語 ２

比較演算などを用いて、ランプの点灯状態を制御しています。

```st
PLS(X1, M0);

IF M0 THEN
    INC(K1, CN1);
END_IF;

IF CN1 >= 6 THEN
    CN1 := 0;
END_IF;

M1 := CN1 >= 5;
M2 := CN1 >= 3 AND CN1 < 5;
M3 := CN1 < 3;

Y71 := M1;
Y72 := M2;
Y73 := M3;
```

### コードの解説
- ボタン1の入力信号をカウンターCN1に割り当てます。
- ボタン1が押されるたびに、カウンターがインクリメントされます。
- カウンターが6以上になった場合、カウンターを0にリセットします。
- カウンターの値に応じて、M1、M2、M3の各ランプの点灯を制御します。

### 注意: ワードデバイスの比較演算に関するエラー

上記のプログラムではコンパイル時に以下のエラーメッセージが出力されました。

:::note warn
Warning MAIN    プログラムのコンパイル     ワードデバイスは、ワード[符号付き]型として比較演算をおこないます。ワード比較を行う場合は、ワード[符号なし]/ビット列[16ビット]型グローバルラベル、もしくはINT_TO_WORD関数を使用してください。        C9215
:::

この警告は、ワードデバイスの比較演算が符号付きワード型として行われていることを示しています。この警告は、データ型の不一致による予期しない動作を回避するために重要ですが、定数の型を揃える方法がわからなかったため、この状態で紹介しています。

## まとめ
この記事では、カウントを利用してランプの点灯を制御する方法を紹介しました。カウンターを使うことで、複雑な制御を簡潔に表現することができます。是非、実際のプロジェクトで活用してみてください。
PHP連想配列操作まとめ

便利だなと思った連想配列の関数をまとめてみました。
自分の備忘録的な感じで残しておきます。
良かったら参考にしてください。

## array_column
連想配列から特定の要素のみを取り出します。

第1引数に配列、第2引数に取り出したいキー名を指定します。

```php
<?php
$row = [
    ['id' => 1, 'name' => '久保', 'hobby' => 'サッカー'],
    ['id' => 2, 'name' => '佐藤', 'hobby' => '野球'],
    ['id' => 3, 'name' => '山田', 'hobby' => '料理'],
];


var_dump(array_column($row, 'name'));
// array(3) {
//   [0]=>
//   string(6) "久保"
//   [1]=>
//   string(6) "佐藤"
//   [2]=>
//   string(6) "山田"
// }

?>
```

加えて第3引数を指定すると、あるフィールドをキー、あるフィールドを値にした連想配列を作成することができます。

```php
<?php
$row = [
    ['id' => 1, 'name' => '久保', 'hobby' => 'サッカー'],
    ['id' => 2, 'name' => '佐藤', 'hobby' => '野球'],
    ['id' => 3, 'name' => '山田', 'hobby' => '料理'],
];


var_dump(array_column($row, 'name', 'hobby'));
// array(3) {
//   ["サッカー"]=>
//   string(6) "久保"
//   ["野球"]=>
//   string(6) "佐藤"
//   ["料理"]=>
//   string(6) "山田"
// }

?>


```



## array_keys
連想配列からキー要素のみ取り出します。

```php
<?php
$row = [
    ['id' => 1, 'name' => '久保', 'hobby' => 'サッカー']
];


var_dump(array_keys($row));

// array(3) {
//   [0]=>
//   string(2) "id"
//   [1]=>
//   string(4) "name"
//   [2]=>
//   string(5) "hobby"
// }

?>
```


## array_search
値からキーを取得します。

```php
<?php
$row = [
    '001' => '久保',
    '002' => '佐藤',
    '003' => '山田'
];


var_dump(array_search('久保', $row));


// string(3) "001"
?>

```


## array_combine
2つの配列の結合して連想配列を作成します。
第1引数の配列の値がキーになり、第2引数の配列の値がバリュー（値）になります。

```php
<?php
$ids = ['001', '002', '003'];

$names = ['久保', '佐藤', '山田'];


var_dump(array_combine($ids, $names));

// array(3) {
//   ["001"]=>
//   string(6) "久保"
//   ["002"]=>
//   string(6) "佐藤"
//   ["003"]=>
//   string(6) "山田"
// }
?>

```

## array_intersect_key
複数の配列の中の共通のキー名を取得します。
返り値の配列は第1引数に指定した配列の要素で構成されています。

```php
<?php
$row1 = [
    'id' => 1, 'name' => '久保', 'hobby' => 'サッカー', 'birthday' => '2021-06-04'
];



$row2 = [
    'id' => 1, 'name' => '加藤', 'hobby' => 'テニス', 'birthplace' => '日本'
];


var_dump(array_intersect_key($row1, $row2));


// array(3) {
//   ["id"]=>
//   int(1)
//   ["name"]=>
//   string(6) "久保"
//   ["hobby"]=>
//   string(12) "サッカー"
// }

?>

```
【Laravel9対応】LaravelのSMTPサーバを動的に設定する

# 何がやりたいのか
- ユーザーが設定したメールアドレスから自動送信を行うシステムを作っている。
- .envで設定したメール設定ではなくて、データベースに登録された各ユーザーのメールサーバー情報を使い動的に設定を変えて送信する。

Laravel9ではSwiftMailerが使えなくなったため、[こちらの方法](https://qiita.com/nakahara-d/items/9a4c870839741dde8f93)で実装できなりました。
そのため別のやり方を解説します。

# 代替案Symfony Mailerを使う。

``` ruby:DynamicMailService.php

<?php

namespace App\Mail;

use Symfony\Component\Mailer\Transport;
use Symfony\Component\Mailer\Mailer;
use Symfony\Component\Mime\Email;
use Illuminate\Support\Facades\Log;
use Exception;

class DynamicMail
{
    public function send()
    {   
        $username = 'hoge';
        $password = 'password';
        $port = 587;
        $host = 'sample.ne.jp';
        $host = trim($host);
        $transport = Transport::fromDsn("smtp://{$username}:{$password}@{$host}:{$port}");
        $mailer = new Mailer($transport);

        try {
            $email = (new Email())
            ->from($from)
            ->to($to)
            ->subject($subject)
            ->text('Sending emails is fun again!')
            ->html('<p>テスト送信</p>');
            $mailer->send($email);
        }
        //送信失敗時
        catch (Exception $e) {
            Log::error($e);
        }
    }
}


```

# bladeのテンプレートを使う場合

Bladeテンプレートをレンダリングする。
例：`resources/views/emails/test.blade.php`を使う場合

``` ruby:sample.php
<?php

    public function send()
    {   
      // Bladeテンプレートをレンダリング
        $htmlContent = View::make('emails.test', ['variable' => '山田太郎'])->render();

        $username = 'hoge';
        $password = 'password';
        $port = 587;
        $host = 'sample.ne.jp';
        $host = trim($host);
        $transport = Transport::fromDsn("smtp://{$username}:{$password}@{$host}:{$port}");
        $mailer = new Mailer($transport);

        try {
            $email = (new Email())
            ->from($from)
            ->to($to)
            ->subject($subject)
            ->html($htmlContent);
            $mailer->send($email);
        }
        //送信失敗時
        catch (Exception $e) {
            Log::error($e);
        }
    }
```

``` ruby:test.blade.php
<p>こんにちは: {{ $variable }}</p>
```
特定フォルダ内の複数ファイルを一括削除しよう

不要ファイルとかを一括削除したい時ってありますよね。
MACでは「.DS_Store」、Windowsでは「.bak」など、それでも使えますし、応用でいろんなファイルが消せます。

特定フォルダ内の複数を一括削除する方法です。
サブフォルダ内のファイルもちゃんと削除されます。

# Mac&Linux版
ターミナルで、フォルダに移動→削除コマンド実行
```text:terminal
cd  ディレクトリパス
```
```text:terminal
find ./ -name "*.DS_Store" -exec rm {} \;
```
`xargs rm`はファイルを削除するコマンドです。

# Windows版
コマンドプロンプトで、フォルダに移動→削除コマンド実行
```text:command prompt
cd ディレクトリパス
```
```text:command prompt
del /s *.bak
```
`del` はファイルを削除するコマンドです。
オプションの`/s`は「指定したファイルを全てのサブディレクトリから削除し、削除したファイル名を表示する」ことを意味します。
サブディレクトリのファイルも対象にしたくない場合は`/s`オプションは、外してください。
`*`は0文字以上の任意の文字列です。`*.bak`は拡張子が「`.bak`」のファイルすべてという意味です。