OmniAICreator/Qiita-1.07M huggingface dataset:
【QGIS】CS立体図が最新版のQGISでも作れる！CSMap Pluginを作成しました 🎉

![sample_6641.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762063/418a365c-ef9d-f40f-2088-eacf60624799.png)

## はじめに
CS立体図を最新版QGIS LTRで作成できる[CSMap Plugin](https://plugins.qgis.org/plugins/csmap-qgis-plugin/)を作成しました 🎉

CS立体図を作成できるQGISプラグインでは[CSMapMaker](https://plugins.qgis.org/plugins/CSMapMaker/)が長らく使われています。しかし，[QGIS 3.30](https://qgis.org/ja/site/forusers/visualchangelog330/index.html#data-providers)からQGISのインストール時にSAGAが内蔵されなくなったため，SAGAに依存するこのプラグインを使用するには対応のバージョンのQGISを使用する必要がありました。

https://plugins.qgis.org/plugins/CSMapMaker/

SAGAに依存せずCS立体図を作成できるツールとして公開されたのが[csmap-py](https://github.com/MIERUNE/csmap-py)です。
本プラグインは，csmap-pyのrasterioとnumpyによる変換ロジックを利用しています。

https://github.com/MIERUNE/csmap-py

https://qiita.com/Kanahiro/items/744dee4795800570b01b

![icon.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762063/3c3dd7c3-2724-4f30-a13d-4a9743c0f5ce.png)

:::note 
<b>追記</b>：2025/05/26から、プラグインアイコンが変わりました！
@chizutodesign さんに作成いただきました。
:::

## プラグインのインストール
本プラグインは <b>QGIS Python Plugins Repository</b> にて "<b>[CSMap Plugin](https://plugins.qgis.org/plugins/csmap-qgis-plugin/)</b>" という名前で公開しています。

QGISの ```プラグイン``` > ```プラグインの管理とインストール...``` から "CSMap Plugin" と検索してインストールすることができます。

![スクリーンショット 2024-06-17 22.52.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762063/ac69138a-d52f-eb2b-859d-35e85db28a59.png)

:::note warn
Windowsをお使いの方へ
:::
Windows版のQGISでは，<b>プラグインの読み込みエラー</b>が発生する場合があります。
原因は，変換処理に必要な<b>rasterioモジュールがない</b>ことにあります。
＊プラグインのインストール自体は問題なく完了しています。

![スクリーンショット 2024-06-17 233322.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762063/a262f028-3f08-5a81-8e27-373ee775a049.png)

以下の手順でrasterioをインストール/インポートしましょう！
- [ ] 手順1：QGISでPythonコンソールを起動します。
- [ ] 手順2：```!pip install rasterio```を実行します（コピペ推奨）。
- [ ] 手順3：QGISを再起動して，再度Pythonコンソールを起動します。
- [ ] 手順4：```import rasterio``` を実行して，```プラグイン``` > ```プラグインの管理とインストール...``` から本プラグインにチェックを入れます。

手順2を実行時に以下のような ```WARNING``` が赤文字で表示される場合があります。
これは，rasterioが指定されたディレクトリにインストールされていますが，そのディレクトリがシステムのPATH環境変数に含まれていないことを意味しており，コマンドラインやターミナルから ```rio.exe``` を直接実行することができない，ということを教えてくれています。
本プラグインを使用するうえでは全く問題のないことなので，無視していただいて構いません。
```
WARNING: The script rio.exe is installed in. 'C: \Users\<UserName>\AppData|Roaming\Python\Python312\Scripts'.which.is.not.on PATH. Consider・adding・this.directory・to・PATE or,if you.preter・to suppress・this warning,use --no-warn-script-location.
```

## CSMap Pluginを使ってみよう
使用方法は，
 - 入力ファイル：DEM（GDALでサポートされている形式のもの）を選択する
 - 出力ファイル：CS立体図を保存したいディレクトリを選択して，名前をつけて保存する
 - ```高度なオプション``` 及び ```処理終了後，自動でウィンドウを閉じる``` を任意で選択・設定する

以上です！

入力ファイルは1つのファイルのみ選択可能ですが，仮想ラスターに対応しています。
出力ファイルは，```name.tif```として出力されます。
高度なオプションは，その意味がわかる方の使用を想定しています。```max workers```はCPUのスレッド数を最大値の目処として設定してあげると，多少の処理速度向上が見込めます。

![スクリーンショット 2024-06-18 0.23.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762063/73cb8e8c-60f4-bc2f-b307-6ae24830d196.png)

## おわりに
本プラグインに対するご指摘やご要望がありましたら，GitHubの[ issues ](https://github.com/MIERUNE/csmap-qgis-plugin/issues)に投稿いただけますと幸いです。今後の機能改善の参考にさせていただきます。
日本語生成AIの品詞付与「精度」をUD_Japanese-GSDLUWで測る

[昨日の記事](https://qiita.com/KoichiYasuoka/items/09acb9207f1659fe8b10)に続いて、「国語研長単位でのUPOS品詞付与をFew-Shot Promptingでやる」という手法を、[UD_Japanese-GSDLUW](https://github.com/UniversalDependencies/UD_Japanese-GSDLUW)を使ってベンチマークっぽくしてみた。やはり12-shot Promptingである。

```
#! /usr/bin/python3
# pip3 install transformers accelerate spacy-alignments
model="tokyotech-llm/Swallow-MS-7b-v0.1"
ud="https://github.com/UniversalDependencies/UD_Japanese-GSDLUW"
import os
d=os.path.basename(ud)
os.system(f"test -d {d} || git clone --depth=1 {ud}")
os.system("for F in train dev test; do cp "+d+"/*-$F.conllu $F.conllu; done")
with open("train.conllu","r",encoding="utf-8") as r:
  trn=r.read().strip().split("\n\n")
with open("test.conllu","r",encoding="utf-8") as r:
  tst=r.read().strip().split("\n\n")
def ext(x):
  u=v=""
  for s in x.split("\n"):
    if s.startswith("# text ="):
      u=s[8:].strip()
    else:
      t=s.split("\t")
      if t[0].isdigit():
        v+="|"+t[1]+"_"+t[3]
  return (u,v[1:])
from transformers import pipeline
nlp=pipeline("text-generation",model,max_new_tokens=256,device_map="auto")
from spacy_alignments import get_alignments
i,j=0,int(len(trn)/len(tst))
gold=system=correct=0
for t in tst:
  w="\n".join("###text:"+"\n###UPOS:".join(ext(x)) for x in trn[i*j:i*j+j])
  u,v=ext(t)
  w+="\n###text:"+u+"\n###UPOS:"
  g=v.split("|")
  s=nlp(w)[0]["generated_text"].split("\n")[j*2+1][8:].split("|")
  gold+=len(g)
  system+=len(s)
  correct+=sum(1 for t,k in zip(s,get_alignments(g,s)[1]) if len(k)==1 and t==g[k[0]])
  i+=1
print("\n***",model)
print("Precision",correct/system if system else 0.0)
print("Recall   ",correct/gold)
print("F1 Score ",2*correct/(system+gold))
```

3行目の`model`を変えつつ実行した結果、私(安岡孝一)の手元では以下の結果が得られた。

```
*** tokyotech-llm/Swallow-MS-7b-v0.1
Precision 0.6013539282990084
Recall    0.6048139624088991
F1 Score  0.6030789825970548

*** stabilityai/japanese-stablelm-base-gamma-7b
Precision 0.6442735248167287
Recall    0.5140966628308401
F1 Score  0.5718704997599872

*** rinna/llama-3-youko-8b
Precision 0.6153669197147458
Recall    0.513041810510165
F1 Score  0.559564899069135

*** rinna/youri-7b
Precision 0.5705988383737232
Recall    0.5464135021097046
F1 Score  0.5582443421181542

*** Rakuten/RakutenAI-7B
Precision 0.5327243293246994
Recall    0.4417913310318374
F1 Score  0.48301530719228347

*** cyberagent/calm2-7b
Precision 0.4641642228739003
Recall    0.3794591484464902
F1 Score  0.41755922545243496

*** lightblue/suzume-llama-3-8B-japanese
Precision 0.4584841761065047
Recall    0.37648638281549673
F1 Score  0.4134590068980043
```

残念ながらF1値が低く、品詞付与の「精度」としては不十分と言わざるを得ない。一昨年の『[青空文庫DeBERTaモデルによる国語研長単位係り受け解析](http://hdl.handle.net/2433/275409)』でも、「UPOS」のF1値は0.95以上出ていたので、現時点での生成AIによる品詞付与は、まだまだ実用にはほど遠いと考えていいだろう。うーん、残念。
supabaseを触ってみる

# 背景
* 最近はRAG検索を勉強している
* いろいろなベクトルデータベースを勉強したり、触ったりしている
* Firebaseを試したことがある


# Supabaseとは
### ホームページ
* https://supabase.com/
* Supabaseはを使用していて、pgvectorを追加してベクトル検索できる


### 料金
* https://supabase.com/pricing

無料
```
Unlimited API requests
50,000 monthly active users
500 MB database space
2 Core shared CPU • 1 GB RAM
5 GB bandwidth
1 GB file storage
Community support
```

# 試してみる
### DB作成
![スクリーンショット 2024-06-14 14.34.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13451/5b5d22cd-5fea-fc04-8bb4-38901ca87fc5.png)

### vectorプラグインを追加
* ダッシュボード -> 左サイドメニュー -> データベース
* 左サイドメニュー  -> Extensions 
* サーチバーにvectorで検索して、vector0.7.0をオンにする

![スクリーンショット 2024-06-14 15.23.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13451/c8304912-d05c-cb1e-3c48-4b51625c9527.png)


### テーブル作成
![スクリーンショット 2024-06-18 8.26.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13451/c4962e71-31b6-8681-778d-134643c0bd3f.png)


### データinsertと検索
![スクリーンショット 2024-06-18 8.35.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13451/e90be6d4-65f0-a24f-a644-67758a51478c.png)

![スクリーンショット 2024-06-18 8.36.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13451/c9c64a42-0302-f4d8-2f8a-6d54aaec288e.png)



# クライアント側だけでRAG検索できそう
![supabase.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13451/dfe01b32-1e74-6a20-d8af-0ea1f090ad4e.png)

# 感想
* 無料範囲が広く
* 個人勉強と練習のために、お金かからなくてRAG検索サービスを作成できる
[Redux] RootStateの型定義にはReturnTypeを使おうと思った話

# 背景
Reduxを使用したアプリケーション開発時...
動的に`store`の型定義を行う方法があると知り記事化しました :memo:

# 解説

`store` と `ReturnType`を組み合わせることで`RootState`の型を動的に定義することができます。

- `store`: Reduxのグローバル値を管理
- `ReturnType`: 関数の戻り値の型から新たな型を生成

以下の例では、複数のリデューサーを含む`store`を設定し、`store.getState`の戻り値から`RootState` の型を動的に定義しています。

```typescript
// src/stores/index.ts
import { configureStore } from '@reduxjs/toolkit';
import hogeSlice from './hoge';
import fooSlice from './foo';

const store = configureStore({
  reducer: {
    hoge: hogeSlice.reducer,
    foo: fooSlice.reducer,
  },
});

export type RootState = ReturnType<typeof store.getState>;
export default store;
```

### メリット

1. **型安全性の向上：** `ReturnType` を使用することで、ストアの状態に対する型推論が強化され、誤った型の使用や存在しないプロパティへのアクセスをコンパイル時に検出できる
2. **保守性の向上：** ストアの構造が変更された場合に、`RootState` の型定義を手動で更新する必要がなくなる

### デメリット

1. **初学者には理解しにくいかもしれない：** 馴染みがないコードなのでTypeScriptの初学者にとっては少し理解しにくいかも

### まとめ
1つのテクニックとして活用していきましょう :fire:
Summer 24 適用後のUIの変更（バグ？）


今回のバージョンアップで少々UIが変わったように感じます。
情報を収集しておきたいと思います。

# アクションのレイアウト

+ [アクションのレイアウトで１列と２列を混合させる方法](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007epjCZ)

**テスト環境**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/0cada24e-924f-51ec-274f-f5223e4c85d4.png)


**本番環境**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/b3f90952-fa47-ce61-3a4e-33f72a8d7031.png)


私の認識では以下のアイデアにあるようにセクションの追加ができないので１列、２列と変更できないと思っていましたが... 過去はできていたということでしょうか？

https://ideas.salesforce.com/s/idea/a0B8W00000GdVpIUAV/allow-to-create-sections-in-quick-action-layout-editor

:::note
左側に項目を配置して右側に空白スペースを配置すると、項目は１列レイアウトで表示されるとのことです。
:::

# 価格表

+ [Is anyone else experiencing UI changes to Product Option (PriceBook2) after the Summer '24 Major Release?](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007cm99QSAQ)


# 画面フロー Choice Lookup

+ [画面フローにおいてその項目を設定していますが、レコード横の×ボタンを押しても取引先責任者レコード名が出たままになってしまっていてブランクにすることができません。](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007cm9ul)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/1a5c49be-9576-81f6-17a2-b3b9bc3763e8.png)

+ [画面フロー検索コンポーネントが入力されていません。メッセージ「選択リストからオプションを選択するか、検索語句を削除してください。」](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007epWdP)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/094acc6f-114a-0c2b-ee2d-73d072eb24de.png)


# 検索レイアウト

+ [Why is Search Layout not applying to one person after Summer 24 Release?](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007epk1w)

:::note
Update: 20 mins after the forced session removal and forced re-login the search columns started showing up for this user again without any further action. Still not sure what happened or why.
:::

#  Dynamic Form

+ [Error with Add Visibility Rules for Dynamic Pages](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007cmC3wSAE)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/d058f546-310c-f904-2813-2017daf52a70.png)


-----------------------

コントラストが変わった？

+ [フォーカス状態のコントラストの向上の確認](https://help.salesforce.com/s/articleView?id=release-notes.rn_general_focus_states.htm&release=250&type=5)
MySQL 8.4 install to CentOS 7.9

# TL;DR

* use vagrant box bento/centos-7.9
* yum install MySQL 8.4

# prepare for install

## uninstall mariadb

```
yum remove mariadb-libs -y
```

## add repository of mysql

```
yum localinstall -y https://dev.mysql.com/get/mysql84-community-release-el7-1.noarch.rpm
```

## install

```
yum install mysql-community-server
```

## version check

```
mysqld --version
```
=> 8.4.0

## set auto start mysqld

```
systemctl start mysqld.service
systemctl enable mysqld.service
```

## set passwd

```
grep 'temporary password' /var/log/mysqld.log
mysql_secure_installation
```


# thanks for

https://zenn.dev/ymasaoka/articles/install-mysql-8-centos-7
アプリ紹介(2023,11) ~ AI student

# 目的
学習は、人に教えられるよりも教えた場合の方が効果があると考える。そこで、AIがあるお題に対して質問をして、こちら側で答えるアプリの開発を行なった。
# 技術
- フロントエンド　Nextjs
- バックエンド fastapi 
- DB MYSQL

# コード

https://github.com/k-sml/AIstudent


# 内容
## ログイン機能
![スクリーンショット 2024-06-17 20.27.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3751344/feafdc8d-163e-24c7-ab96-8fdbf181e1df.png)

## チャット機能
![スクリーンショット 2024-06-17 20.50.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3751344/7fcb7fa0-bf5e-6213-94c0-7a4ad79f32b0.png)
![スクリーンショット 2024-06-17 20.50.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3751344/ac1a5a94-a728-2679-5466-431d869a2b59.png)
![スクリーンショット 2024-06-17 20.53.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3751344/cf9a9163-6da3-3743-586b-404412854149.png)


## 一覧機能
![スクリーンショット 2024-06-17 20.53.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3751344/5c226eab-7386-8bea-7098-07c214965c75.png)
AI初心者でもわかる！RAGの仕組みと導入ステップ

# はじめに
AI技術の進歩はものすごい勢いで加速していますね。そのため、少しでもAIに関する知見を身につけておくことが重要です。今回、RAGについて調査する機会があったので、まずざっくりと理解したことをまとめてみました。内容に誤りがあれば、ご指摘いただけると幸いです。

# RAGとは
RAGとはRetrieval-Augmented Generationの略で、リトリーバル アグメンテッド ジェネレーションと読みます。また、「ラグ」とも呼ばれます。これはLLM（大規模言語モデル）に外部ソースを渡して回答の精度を高める仕組みです。

イメージ的には、LLMにカンニングさせて回答の精度を上げるような感じです。

![Group 5 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3486510/2659677b-f727-00be-d1af-6053cd5e072c.png)


# RAGにできること・できないこと
回答の精度を上げる具体例として、以下の「できること」があります。また、RAGの限界を理解して使うことが重要です。「できないこと」についても知っておきましょう。

### できること
- LLMが時々いい加減な回答をする現象（ハルシネーション）を減らすことができる
- LLMの回答の精度を高めることができる
- LLMに専門的な回答をさせることができる


### できないこと
- 100%の精度で回答すること
- 参照するデータ以外の情報に基づいた回答をすること


# RAGを活用事例
RAGの活用例はさまざまですが、主に以下のような用途で利用されています。

### 社内ヘルプデスク
社内データを参照させることで、「〇〇会議資料をちょうだい」や「社内ルールを教えて」といった質問に対して資料を提供したり、社内ルールについて教えることができます。

### 市場調査
社内で調査した情報とネット検索を組み合わせて、精度の高いレポートを迅速に作成することができます。

### お問い合わせチャットボット
過去の問い合わせ情報を参照させることで、類似する問い合わせに対して自動で回答させることができます。

# 構築方法
「こんな感じで作るんだ！やってみたい！」と思った記事を3つピックアップしました。ぜひ参考にしてみてください。

1.  [RAGを使った社内情報を回答できる生成AIボットで業務効率化してみた](https://dev.classmethod.jp/articles/improve-work-efficiency-with-generateive-ai-chatbot-using-rag/)
1.  [【RAG構築】データソース(Web検索)の利用](https://zenn.dev/makunugi/books/c5b3307e39dde3/viewer/8e8c95)
1.  [AWS 内で大規模言語モデルを利用できる Amazon Bedrock を使って作る RAG アプリケーション](https://techlife.cookpad.com/entry/bedrock)


# さいごに
今度は実際にRAGを使用してみて、理解を深めていきたいと思います。


# 参考
https://blogs.nvidia.co.jp/2023/11/17/what-is-retrieval-augmented-generation/

https://www.youtube.com/watch?v=lqHUGkdhgAY

https://smooz.cloud/news/column/retrieval-augmented-generation-ai/#RAG
Djangoにwagtailを組み込む手順

Djangoのセットアップが終わっている前提で、Mac上でWagtailを組み込む手順を記載します。

### 手順

1. **仮想環境の有効化**
    ```bash
    source myenv/bin/activate
    ```

2. **Wagtailのインストール**
    ```bash
    pip install wagtail
    ```

3. **Wagtailプロジェクトの初期化**
    ```bash
    wagtail start mysite
    cd mysite
    ```

4. **Django設定の更新**
    - `mysite/settings/base.py` を編集して、以下のアプリケーションを `INSTALLED_APPS` に追加します。
    ```python
    INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'wagtail.contrib.forms',
    'wagtail.contrib.redirects',
    'wagtail.embeds',
    'wagtail.sites',
    'wagtail.users',
    'wagtail.snippets',
    'wagtail.documents',
    'wagtail.images',
    'wagtail.search',
    'wagtail.admin',
    'wagtail',

    'modelcluster',
    'taggit',

    'home',
    'search',
    ]
    ```

    - `MIDDLEWARE` にWagtailのリダイレクトミドルウェアを追加します。
    ```python
    MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',

    'wagtail.contrib.redirects.middleware.RedirectMiddleware',
    ]
    ```


5. **データベースのマイグレーションとスーパーユーザーの作成**
    ```bash
    python manage.py migrate
    python manage.py createsuperuser
    ```

6. **開発サーバーの起動**
    ```bash
    python manage.py runserver
    ```

    ブラウザで `http://localhost:8000/admin/` にアクセスして、Wagtailの管理画面にログインします。

以上で、DjangoプロジェクトにWagtailが組み込まれました。管理画面からコンテンツを作成・管理できます。
Household という項目

[まとめページに戻る](https://qiita.com/Keiji_otsubo/items/60afc2a8d211b6f7d89f)
[まとめA～M](https://qiita.com/Keiji_otsubo/items/f3ddedee6793bf1576f8)


+ [While using the Data Import wizard to import contact and account records, one of the fields on the Account object is missing in the mapping table dropdown](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007clzCS)

取引先オブジェクトには世帯員数フィールド がありますが、取引先責任者と取引先としてインポートするオブジェクトを選択すると、データ インポート ウィザードのマッピング テーブルのドロップダウンに表示されません。

:::note
これは、世帯員数フィールドがロールアップ フィールドであるためだと思います。

https://ideas.salesforce.com/s/idea/a0B8W00000GdkbNUAR/household-account-number-of-household-members-untie-from-household-naming

https://github.com/SalesforceFoundation/NPSP/blob/rel/3.110/src/classes/HH_HouseholdNaming.cls#L68
:::


#  FinServ.AccountTrigger: execution of BeforeInsert caused by: FinServ.MoiExceptionWrapper.ValidationException: Your account record type is missing, a duplicate, or invalid. Ask your admin to check the individual record type configurations in Setup. (FinServ) 

+ [【未解決】I am getting the following error message while creating an account (Person Account/Household)](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000BrjKC)

:::note
Set the below three fields properly, and this is working for me.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/e6c5ca26-4cef-5741-c81c-eabf345cbb28.png)
:::

+ [【未解決】FinServ.AccountTrigger: execution of BeforeInsert caused by: FinServ.MoiExceptionWrapper.ValidationException: Your account record type is missing, a duplicate, or invalid. Ask your admin to check the individual record type configurations in Setup. (System Code)](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007YwSUS)
Rubyでデザインパターン (1) Iteratorパターン

## この記事は何
デザインパターンについて、Rubyでどのような使い方ができるかをまとめた記事です。
デザインパターン自体の解説は詳しく行いません。

## Iteratorパターンとは
Iteratorパターンとは、集合体に対して順番にアクセスするためのインターフェースを提供し、その実装を容易にするデザインパターンです。
詳しくは以下の記事をご覧ください。

https://qiita.com/shoheiyokoyama/items/3f42d0057d9d5a861039

## Rubyでのコード例
元々のJava等での実装に則って実装すると以下のような形になると思います。
ただ、Rubyではこのような実装を行うことはあまりないと思います。（詳しくは次の項で解説します）

```rb
class ItemListIterator
  def initialize(item_list)
    @item_list = item_list
    @current_index = 0
  end
  
  def has_next?
    @current_index < @item_list.length()
  end

  def next
    return nil unless has_next?
    
    item = @item_list.get_at(@current_index)
    @current_index += 1
    return item
  end
end

class ItemList
  def initialize()
    @item_list = []
  end

  def get_at(index)
    @item_list[index]
  end

  def add(item)
    @item_list << item
  end

  def length()
    @item_list.length
  end

  def iterator
    ItemListIterator.new(self)
  end
end
```

これらのクラスを用いて以下のようにイテレーターを実現できます。

```rb
Item = Struct.new(:a, :b)

item_list = ItemList.new()
item_list.add(Item.new(1, 2))
item_list.add(Item.new(2, 3))
item_list.add(Item.new(3, 4))

iterator = item_list.iterator()

while iterator.has_next? do
  puts iterator.next()
end
```

```sh:実行結果
#<struct Item a=1, b=2>
#<struct Item a=2, b=3>
#<struct Item a=3, b=4>
```

## どのような時に使えるか
前項の冒頭でも紹介した通り、RubyではIteratorパターンそのものを実装する機会はほとんどないと思います。

その理由は`Enumerable`モジュールが提供されているためです。
`Enumerable`モジュールを利用すると以下のように、簡単にイテレータの実装が可能です。

```rb
class ItemList
  include Enumerable

  def initialize()
    @item_list = []
  end

  def add(item)
    @item_list << item
  end

  def each(&block)
    @item_list.each(&block)
  end
end

Item = Struct.new(:a, :b)

item_list = ItemList.new()
item_list.add(Item.new(1, 2))
item_list.add(Item.new(2, 3))
item_list.add(Item.new(3, 4))

item_list.each do |item|
  puts item
end
```

`Enumerable`モジュールは以下の記事で詳しく解説されています。

https://qiita.com/kobayashimakoto/items/c8d1d111ef2daf89e964
試験仕様書の No. 列に関するプラクティスあれこれ

:::note info
試験仕様書の No. 列ごときでそんなに変わるかいな、と思う方もいらっしゃるかもしれません。  
私の実体験に基づく記事なので、読み物的に読んでいただけると幸いです。
:::

## はじめに

システム開発をしていると、よく Excel やスプレッドシートで試験仕様書が作られると思います。  
そこには操作や期待値など、試験項目に関する列がたくさん作られるのですが、よく作られるのが No. 列です。

以前、受託開発の会社にいたことがありましたが、そこでは試験仕様書が納品の対象となることもあったため、きちんとしたフォーマットで作ることが重要ともされてきました。

しかし、試験仕様書についての会話をするとき、この No. 列でコミュニケーションロスが発生することがよくありました。

## 試験仕様書の No. 列で起こったコミュニケーションロス

私が実際に体験したコミュニケーションロスを紹介します。

### 試験項目追加時に No. が変わり、過去のチャットがあてにならなくなる

No. 列を `ROW() - n` などの数式で自動的に生成するのはよくある話かと思います。`ROW` 関数を使うということは Excel の行番号に依存しているわけですから、試験項目を途中の行に追加すれば当然 No. も変わります。

チャットで試験項目の話をするときに No. を使っていると、こういった試験項目追加の際に No. は頼りにならなくなり、後からチャットを確認する人がものすごい苦労します。

### Excel の行番号とごっちゃになる

> 同僚「10 番目のテストケースのことについて聞きたいんだけど」  
> 私「10 番目って、Excel の行番号の 10 ですか？それとも No. 10 のことですか？」  
> 同僚「ごめんごめん、No. 10 の方だ」

これ自体にそれほどタイムロスは無いように思われますが、試験期間ともなるとこんな会話が 1 日に数回繰り広げられることもあるため、精神的にも疲弊してしまいました。

## コミュニケーションロスを防ぐプラクティス 4 選

4 選と書きましたが、複数実践することで効果が高まる場合もあります。  
おすすめ度を 3 段階で書きましたので参考にしてください。

### 【★★★】No. を値のみ貼り付けで固定化する

`ROW() - n` などの数式で自動的に生成した番号部分をコピーし、同じ場所に「値のみ」で貼り付けます。

行追加をしても一度作成されたテスト項目にはずっと同じ No. がついています。これによって、ある日チャットでテストの番号を出して会話したものを、次の日になって他の人が見返したとしても仕様書との整合性が担保されます。

試験開始後に項目追加する際は「10-2」や「10.1」など、極力番号順を死守すると探しやすさをキープできます。

### 【★★☆】No. を行番号と同じにする・いっそ No. を書かない

No. 列の数式を `ROW() - n` ではなく `ROW()` にすることで、Excel の行番号と全く同じにします。そうすることで、人によって番号の呼び方が違ってもコミュニケーションロスになることがありません。

No. を書かないという暴挙に出ることもおすすめです。Excel が少し軽くなりますが、試験項目を追加されると番号がずれて一巻の終わりです。

### 【★★★】「No. なんとか」で会話するようにルールを決める

No. 列と行番号が異なっていても、会話するときに必ず No. を使うルールにすれば、それだけでコミュニケーションロスを削減することができます。  
特に、納品した試験仕様書についてクライアントと会話をする場合、この方法は有効かと思われます。

### 【★☆☆】試験項目の内容で会話する

会話の際に No. ではなく「機能 A で操作 B する試験についてですが」とする方法です。これなら確かに番号で惑わされることもないし、No. を数式で書いたままでも十分伝わります。しかし、

長い。 🙃

難点としては、チャットだと文字数が増えて煩わしいのと、試験内容の熟知・試験項目の配置場所の記憶が必要になるところです。テスト作成者同士の会話ならギリ耐えるかもしれませんが。
LeetCode挑戦日記：Day11

# はじめに

最近、業務で実装する時間よりも資料作成やレビューをする時間が多くなってきました。
このままでは自身のコーディング能力が落ちそうで怖いので、LeetCodeを始めてみました。

自身の学習の記録 & LeetCodeに興味のある人が挑戦しやすいように、記事に残していきます。
このような競技プログラミングをした経験がないので、ひよってEasyからやっていきます...

# [Easy] 392. Is Subsequence

二つの文字列`s`と`t`が与えられたとき、`s`が`t`の部分列であればtrueを、そうでなければfalseを返す。

部分列とは、元の文字列からいくつかの（または0個の）文字を削除することで、新しい文字列を作成するものです。
ただし、残りの文字の相対的な位置は保持されます。
例：「ace」は「abcde」の部分列。「ace」は「aec」の部分列ではない

## 素直に解いてみる

### 考え方

1. `s`の最初の文字から`t`に存在するか確認する
1. `s`の全ての文字が`t`に存在すればtrue

### コーディング

```typescript
function isSubsequence(s: string, t: string): boolean {
    if (s === '') { return true; }

    const sChars = s.split('');
    const tChars = t.split('');

    let checkIndex = 0;
    for (const tChar of tChars) {
        if (s[checkIndex] === tChar) {
            checkIndex++;
            if (checkIndex === sChars.length) {
                return true;
            }
        }
    }
    return false;
};
```

### 結果

Runtime：63ms
Beats 32.45%

Memory：52.04MB
Beats 13.97%

## 改善：`split`を消す

### 考え方

1. `split`に処理時間やメモリ使用量がかかっていると仮定
1. `split`しなくても動くように修正する

### コーディング

```typescript
function isSubsequence(s: string, t: string): boolean {
    const sLength = s.length;
    if (sLength === 0) { return true; }

    let sIndex = 0;
    let sChar = s.charAt(0);
    for (let tIndex = 0; tIndex < t.length; tIndex++) {
        if (sChar === t.charAt(tIndex)) {
            sIndex++;
            if (sIndex === sLength) {
                return true;
            }
            sChar = s.charAt(sIndex);
        }
    }
    return false;
};
```

### 結果

Runtime：43ms
Beats 99.24%

Memory：51.32MB
Beats 26.53%
USBデバイスの挿抜検出、デバイス詳細を知る方法

## 背景
macOSでUSB-シリアル通信コンバータを使うことが多く、以前から挿抜の検出をしたいと思っていました。

主に、後からUSB-シリアル通信コンバータを挿入した際、macOSアプリを再起動しなくてもデバイスのリストを更新してくれる機能が欲しかったです。

これは稀ですが、通信中にUSB-シリアル通信コンバータを抜いた時、通信を自動的に止めたいとも思っていました。

## シリアル通信デバイス
昔はMacの背面にシリアルポートがついていましたが、今はUSB-シリアル通信に変わっています。
FTDIやSilicon Labsなどが便利なUSB-UARTブリッジチップを提供してくれています。
macOS内では
```:ターミナル
$ ls -l /dev/tty.*
crw-rw-rw-  1 root  wheel  0x9000002  6 16 18:51 /dev/tty.Bluetooth-Incoming-Port
crw-rw-rw-  1 root  wheel  0x900000a  6 18 05:39 /dev/tty.usbmodem15303
crw-rw-rw-  1 root  wheel  0x900000c  6 18 05:39 /dev/tty.usbmodem206835814E481
crw-rw-rw-  1 root  wheel  0x900000e  6 18 05:43 /dev/tty.usbserial-210244678243
crw-rw-rw-  1 root  wheel  0x9000006  6 18 05:38 /dev/tty.usbserial-AG0JGOAK
crw-rw-rw-  1 root  wheel  0x9000000  6 16 18:51 /dev/tty.wlan-debug
```
というように、シリアル通信デバイスとして認識されているものは、Swiftを使ってシリアル通信を実現することができます。

## USBデバイスとして扱わないと挿抜検出はできない
シリアル通信デバイスとして扱えば通信アプリは開発できます。
しかし、挿抜検出、ベンダーID・プロダクトIDの取得はUSBデバイスとして扱わなくてはいけないことがわかりました。

その時、こちらのサイトが参考になりました。
[USB Connection Delegate on Swift](https://stackoverflow.com/questions/39003986/usb-connection-delegate-on-swift)

【追記】2024.06.18
[USBDevice_Path_in_Swift.playground](https://github.com/vukcevich/USB-Device-Path-in-Swift-/blob/master/USBDevice_Path_in_Swift.playground)

発見したシリアル通信デバイスと、発見したUSBデバイスを照らし合わせることで、シリアル通信デバイスがUSBデバイスであれば、ベンダーID・プロダクトIDを取得できます。
両者はBSD Pathが同じなので、それで照らし合わせて同一デバイスであることがわかります。

参考にしたサイトのソースコードを実行してみると、Mac本体内部にUSB HUBがあることもわかります。
接続している電子楽器なども検出されました。

## こんなことができる
シリアル通信デバイスはUSBで接続されているとは限りません。
そこで、USBで接続されているデバイスにはUSBのアイコンをつけ、さらにプロダクト名で表示するようにしてみました。
USBデバイスでないものは、昔のMacで使われてたシリアルポートに近いアイコンをつけてみました。
![スクリーンショット 2024-06-18 7.24.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202602/d59503e5-06d4-c43e-1d83-f2eed54e429a.png)

挿抜検出ができるので、使っているデバイスがいなくなったらアイコンを変えるなんてこともできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202602/82f7daf3-568c-a8dd-151d-1450bfaeeb23.png)
【VSCode】画面内でコードを改行したい

## はじめに
SQLやJava、Pythonを扱う際に"**Visual Studio Code**"を使用しています。
JavaやPythonは1行に詰め込むことがあまりないですが、複雑なSQLだとたまに長くなってしまうので、画面が見切れてしまうことがあります。

その際に使用できるショートカットを現場の方に教えていただいたので、備忘録として残しておこうと思います。

## デフォルトの画面だと。。
横スクロールバーがあり、改行されず表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726107/7e778a5f-463e-6591-659a-361ac3128d24.png)

この状態だと、一目で文字が見れないのでスクロールバーを動かすしかなさそうです。

## 一目が叶うショートカット
`Alt` + `Z`で改行ができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726107/c575af7e-abb1-8a3b-2901-2440daca80cf.png)

今まで不便に思ったことはなかったのですが、これを知ってからは頻繁ではないものの使わずにはいられなくなりました:angel_tone1:

## 最後に
今回は、VSCodeで改行するショートカットキーをご紹介いたしました。
VSCodeに備わっている機能をあまり知らないので、今後使える機能があったら記事にしようと思います。

最後までお読みいただき、ありがとうございました:leaves:
ValueSemantics とはなんだろう


https://heart-of-swift.github.io/

## ValueSemantics

意味論のお話。

一言で、ある型が 変更に対して独立性がある  という状態。

`struct` で宣言された構造体は、変数への代入時に インスタンスが直接格納される。

```swift
struct Point {
    var x: Int
    var y: Int
}

var point1 = Point(x: 1, y: 1)
var point2 = point1
point2.x = 2

print(point1.x)  // 1
print(point2.x)  // 2
```

このPoint を値型 といって

> *値型* のインスタンスは変数に直接格納されます。より具体的に言うと、インスタンスを表すバイト列が、変数を表すメモリ上の領域に直接書かれます。 *値型* のインスタンスを変数に代入したときには、そのインスタンスを表すバイト列がコピーされて、代入先の変数の領域にそのまま書き込まれます。これが、代入によって *値型* のインスタンスがコピーされる仕組みです。
> 

雑なイメージだと、コピーを 言語機能が自前で やってくれる。

point1 と point2 のどちらかを変更しても もう片方には影響を与えない。変更に対する独立性を持っている 。Value Semantics を持っている と表現される

一方、 参照型もあって

```swift
class Point {
    var x: Int
    var y: Int
    
    init(x: Int, y: Int) {
        self.x = x
        self.y = y
    }
}

var point1 = Point(x: 1, y: 1)
var point2 = point1
point2.x = 2

print(point1.x)  // 2
print(point2.x)  // 2
```

> *値型* と異なり、 *参照型* のインスタンスは変数に直接格納されません。インスタンスの実体を表すバイト列はメモリ上の別の領域（ヒープ領域のどこか）に格納されていて、その領域を表すメモリのアドレスが変数に格納されます。たとえば、そのアドレスが `0x123DEF` だとすると、変数に実際に格納されているのは `0x123DEF` というアドレスを表すバイト列です。
> 

お馴染み。 変更に対して独立性がない 場合、Reference Semantics を持った型 となる。

多言語と比較すると 

C++ 、代入時に 参照か値か を選ぶ

```cpp
struct Point {
    int x;
    int y;
};

int main() {
    Point point1 = {1, 1};
    Point point2 = point1; // コピー
    point2.x = 2;

    std::cout << "point1.x: " << point1.x << std::endl; // 1
    std::cout << "point2.x: " << point2.x << std::endl; // 2
    return 0;
}

int main() {
    Point point1 = {1, 1};
    Point& point2 = point1; // 参照
    point2.x = 2;

    std::cout << "point1.x: " << point1.x << std::endl; // 2
    std::cout << "point2.x: " << point2.x << std::endl; // 2
    return 0;
}
```

型がどちらのSemanticsを持っているか という視点だと、 こっちはどちらも持ちうる （使う側で判断する） と解釈できそう。

Kotlinだと、すべて参照型 を前提に、別インスタンスをcopyで作る

```kotlin
data class Point(var x: Int, var y: Int)

fun main() {
    val point1 = Point(1, 1)
    val point2 = point1.copy(x = 2)

    println(point1.x)  // 1
    println(point2.x)  // 2
}
```

ただし

```kotlin
data class Point(var x: Int, var y: Int)

fun main() {
    val point1 = Point(1, 1)
    val point2 = point1

    println(point1 === point2)  // true, 参照セマンティクス
    val point3 = point1.copy()
    println(point1 === point3)  // false, 新しいインスタンス
}
```

`data class` であろうと、copy を明示しない限りそれは参照なので、これも どっちも持ちうる と解釈できそう。
【メモ】個人的なVimrcの基本設定内容

Howdy, Vimmers!
以下、内容でございます!

```
" init_configにプラグイン設定を分たい人用
"source ~/.vim/plugin_config.vim

" Load/Write
set encoding=utf-8
scriptencoding utf-8
set fileencoding=utf-8      " 保存時の文字コード
set fileencodings=ucs-boms,utf-8,euc-jp,cp932 " 読み込み時の文字コードの自動判別. 左側が優先される
set history=5000            " 保存するコマンド履歴の数
set nobackup
set noswapfile
set hidden		    " 編集中で保存されていないファイルがあるときに他のファイルを開けるか
set confirm		    " 保存されていない場合、vim を終了させようとした時に保存の確認を行う
set autoread		    " 外部で変更があった時に自動的に読み込み直すか

" Visual
syntax on
"colorscheme molokai
"colorscheme hybrid
set number                  " 行番号を表示
set title
set cmdheight=1
set laststatus=2
set showcmd
"set showmatch matchtime=1  " 対応する括弧やブレースを表示
set ambiwidth=double 	    " □や○文字が崩れる問題を解決
set splitright		    " 画面を縦分割する際に右に開く

"tab
set expandtab
set tabstop=2               " タブ表示幅
set softtabstop=2	    " タブキー押下時に挿入される文字幅
set autoindent
set smartindent
set shiftwidth=2	    "インデント幅
set listchars=tab:▸\-\
"indentline------------------------
" Install command--->
"$ git clone <https://github.com/Yggdroot/indentLine.git> ~/.vim/pack/vendor/start/indentLint
"$ vim -u NONE -c "helptags  ~/.vim/pack/vendor/start/indentLint/doc" -c "q"
let g:indentLine_color_term =239
let g:indentLine_color_gui = '#708090'
let g:indentLine_char = '¦' "('|', '¦', '┆', ┊')
"----------------------------------

"Complement
inoremap <expr><CR>  pumvisible() ? "<C-y>" : "<CR>"
"補完表示時のEnterで改行をしない
set completeopt=menuone,noinsert " 補完対象1件でも表示,補完ウィンドウ表示時に挿入しない
set wildmenu                     " コマンドモードの補完

"Mouse, Clip board
set clipboard=unnamed            " yank した文字列をクリップボードにコピー
set mouse=a                      " マウス有効化
"set ttymouse=xterm2
"set scrolloff=5
set scroll=5

"Searching
set incsearch
set ignorecase		         " 検索時に大文字小文字を区別しない
set smartcase
set hlsearch
nnoremap <silent><Esc><Esc> :<C-u>set nohlsearch!<CR>

"Cursol
set whichwrap=b,s,h,l,<,>,[,],~  " カーソル移動で行を跨いで移動出来る
" set position of cursol ------- " Vimで開くときに最後に編集していたカーソル位置がおかれるようになる
augroup vimrcEx
  au BufRead * if line("'\"") > 0 && line("'\"") <= line("$") |
  \ exe "normal g`\"" | endif
augroup END
"------------------------------
"行が折り返し表示されていた場合、行単位ではなく表示行単位でカーソルを移動する
nnoremap j gj
nnoremap k gk
nnoremap <down> gj
nnoremap <up> gk

"Keymaps
inoremap <C-j> <Esc>
inoremap <C-k> <C-u>
inoremap <C-h> 0
inoremap <C-l> $
set backspace=indent,eol,start " バックスペースキーの有効化
```

同じ設定にする場合は、ホームディレクトリに「.vimrc」というファイルを作成して以上のコードを突っ込むだけです!
【メモ】Ubuntu↔ROS 1/2 - Version別のサポート期限一覧

# Ubuntu version

| Dist ver/Dist name | Dev dode | Kernel ver | release | EOS | EOL |
| --- | --- | --- | --- | --- | --- |
| 23.04  / Lunar | Lunar Lobster |  |  |  | (9 month later) |
| 22.10 / Kinetic | Kinetic Kudu |  | Oct 20, '22 | Jul '23rd | Jul '23 (9 m) |
| 22.04 LTS / Jammy | Jammy Jellyfish | 5.15 | Apr 21st, '22 | Apr '27 | Apr '32 |
| 21.10 / Impish | Impish Indri | 5.13 |  |  |  |
| 21.04 / Hirsute | Hirsute Hippo | 5.11 |  |  |  |
| 20.10 / Groovy | Groovy Gorilla | 5.8 |  |  |  |
| 20.04 LTS / Focal | Focal Fossa | 5.4 | Apr 23rd, '20 | Apr '25(5 y) | Apr '30 |
| 19.10	/ Eoan | Eoan Ermine | 5.3 |  |  |  |
| 19.04	/ Disco | Disco Dingo | 5.0 |  |  |  |
| 18.10 / Cosmic | Cosmic Cuttlefish | 4.18 |  |  |  |
| 18.04 LTS	/ Bionic | Bionic Beaver | 4.15 or newer | Apr 26, `18 | Apr `23 |  |

# ROS2 version

| Version name | Release | EOL |
| --- | --- | --- |
| Humble Hawkbill | May 23rd, '22 | May '27 |
| Galactic Geochelone | May 23rd, '21 | Dec 9th, '22 |
| Foxy Fitzroy | Jun 5th, '20 | May '23 |
| Eloquent Elusor | Nov 22nd, '19 | Nov '20 |
| Dashing Diademata | May 31st, '19 | May '21 |

# ROS2 version upgrade steps

## Foxy→ Humble

1. sudo apt update
2. sudo apt remove ros-foxy-*
3. sudo apt update && sudo apt install curl gnupg2 lsb-release
4. curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add -
sudo sh -c 'echo "deb [arch=$(dpkg --print-architecture)] http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" > /etc/apt/sources.list.d/ros2-latest.list'
5. sudo apt update && sudo apt install ros-humble-desktop

# Ubuntu version upgrade steps

## Ubuntu 20.04 LTS→ Ubuntu 22.04 LTS

1. lsb_release -a
2. sudo apt update && sudo apt upgrade
3. sudo apt install update-manager
4. sudo apt dist-upgrade && sudo apt install update-manager-core
5. sudo do-release-upgrade -d

---

1. (sudo apt full-upgrade)
2. (sudo apt autoremove -y)
3. (sudo apt autoclean -y)
4. sudo apt full-upgrade
5. sudo reboot

---

**情報参照元**
> https://docs.ros.org/en/foxy/Releases.htmlhttps://wiki.ubuntu.com/Releaseshttps://designetwork.daichi703n.com/entry/2017/03/05/ubuntu-kernel-version
>
Javaで「配列のすべての要素を指定した値で埋める(fill)」の動作を確認してみた

# 概要

Javaで「配列のすべての要素を指定した値で埋める(fill)」の動作を確認してみました。
以下のページを参考にしました。

https://www.javadrive.jp/start/array/index12.html

# 実装

以下のファイルを作成しました。
```JSample12_1.java
import java.util.Arrays;

class JSample12_1{
  public static void main(String[] args){
    int[] a = new int[3];
    Arrays.fill(a, 10);

    System.out.println(a[0]);
    System.out.println(a[1]);
    System.out.println(a[2]);
  }
}
```

以下のコマンドを実行しました。
```
$ javac JSample12_1.java 
$ java JSample12_1 
10
10
10
```

# まとめ

何かの役に立てばと。
【docker container】Nginx サーバーを起動し、ブラウザからアクセスする

# はじめに
Docker の `docker container run` コマンドを使って Nginx コンテナを起動し、ブラウザからアクセスする手順について記載します。

https://docs.docker.com/reference/cli/docker/container/run/

# 開発環境
開発環境は以下の通りです。

- Windows 11
- Docker Engine 26.1.1

# Nginx サーバーを起動する
以下のコマンドで、Nginx サーバーをコンテナで起動します。

```powershell
docker container run --rm --publish 8080:80 nginx
```

- `--rm` : コンテナ停止時にコンテナを自動削除
- `--publish` : コンテナの80番ポートをホストマシンの8080番ポートにマッピング


# ブラウザからアクセスする
ブラウザで http://localhost:8080/ にアクセスすると、「Welcome to nginx!」が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/5ea90d80-2e3c-6903-9465-bbb4c71b8a6d.png)

また、`docker container ls` でコンテナのポート情報を確認できます。今回は 8080 と 80 がマッピングしていることを確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/09016759-672d-c1a7-ce25-f321118b8dd5.png)



# 参考
- [docker container run](https://docs.docker.com/reference/cli/docker/container/run/)
- [	鈴木亮「開発系エンジニアのためのDocker絵とき入門」秀和システム、2024](https://www.shuwasystem.co.jp/book/9784798071503.html)

# 関連記事

https://qiita.com/Yasushi-Mo/items/4539c0a1e17644788e26
powershellからSAS EGを操作する

# SAS Enterprise Guideをいちいち開くのが面倒

SASで記述された定例の処理を実行するのが面倒だなと思い、調べていたところ次の内容を見つけました。

https://blogs.sas.com/content/sasdummy/2011/05/03/using-sas-enterprise-guide-to-run-programs-in-batch/

ここで記述されているのは、Visual Basicの様子なので、PowerShellで**ComObject**を利用して、実行できる様にしてみました。

## コード

**[ほにゃらら]**の部分を自分の環境やファイルに合わせて使用します。

```powershell

# https://blogs.sas.com/content/sasdummy/2011/05/03/using-sas-enterprise-guide-to-run-programs-in-batch/

$sasApp = New-Object -ComObject "SASEGObjectModel.Application.[VERSION]"

# プロファイル: [PROFILE NAME]を設定する。Local Serverの場合は"Null Provider"
$sasApp.SetActiveProfile("[PROFILE NAME]")

# 出力の設定
$sasApp.GenListing = $True
$sasApp.GenSasReport = $False
$sasApp.GenHTML = $False

# 新規プロジェクト
$project = $sasApp.New()

# 新規プロジェクトにコードを追加する
$sasProgram = $project.CodeCollection.Add()

# SAS Server名: [SAS SERVER]を設定する
$sasProgram.Server = "[SAS SERVER]"

# [PROGRAM FILE PATH]に用意したSASのプログラムをGet-Contentで読み込み
# $sasProgramのTextに渡す
$text = Get-Content "[PROGRAM FILE PATH]"
$sasProgram.Text = $text

# Codeを実行する
$sasProgram.Run()

# [LOG FILE PATH]にSASのログを出力する
$logFileName = "[LOG FILE PATH]"
$sasProgram.Log.SaveAs($logFileName)

# SAS EGを終了する。
$sasApp.Quit()
```
GodotでAnimationの設定

GodotでUIの開閉にアニメーションをつけたかったので、実践したメモを残しておきます。

## AnimationPlayerノードの追加
アニメーションを使用したいノードの子ノードにAnimationPlayerを追加します。今回は「ShowMenuAnimation」という名前にしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3800965/c996ba03-1224-0d8e-a1b0-82bc02d0787c.png)

## 新規アニメーションの追加
AnimationPlayerノードを選択し、アニメーションウィンドウの「アニメーション」クリックし、開いたメニューの「New…」を選択。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3800965/f53f6fc0-9dd6-1fba-3799-2c75e8413fc5.png)

※アニメーションウィンドウが出ない場合、エディタの最下部にアニメーションタブが追加されていると思うので、そちらをクリック。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3800965/519d303f-0171-8497-ecfd-01b1ef76c920.png)

「トラックを追加」から「Property track」を選択し、ノード選択画面から動かしたいノードを選択。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3800965/e5237a81-05d3-08bc-db3b-a622b5567305.png)

「ButtonContainer」を動かしたいので選択。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3800965/286d68c6-0b7b-3738-48c9-e33f9d1aa9d6.png)

さらにノードのプロパティを選択。今回は「position」を選択。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3800965/485696a7-eaa2-e640-1094-5618fbc39c67.png)

トラックが追加されているので、追加されたトラックの任意の場所で右クリックする。「Insert Key」というボタンが出てくるのでクリック。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3800965/c2908dac-fc8d-30d4-d16a-01187d13520a.png)

するとインスペクターウィンドウでプロパティの値を指定できるようになる。これを2つ以上作成すれば、指定した時間内で値の差の分だけ変化するアニメーションが作成できる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3800965/0563ac7a-ebc8-1e72-7dfc-c5dc5effb8bf.png)

## 設定したアニメーションをスクリプトで実行する
上記までで設定したアニメーションの実行タイミングをスクリプトで指定してあげる。設定したノードのplay()で引数に実行したいアニメーション名を渡す。これでアニメーションがつけられます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3800965/be55dcee-4036-12ed-1c67-2443323bd8b3.png)


## インスペクターからトラック追加を行う方法
アニメーションウィンドウを開いた状態で別のノードを選択。するとインスペクター上で鍵のようなマークが出てくる。それをクリックすると、トラック追加のウィンドウを開かず、直接トラックを追加することができる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3800965/1aff0047-cd7d-ba67-39cc-9d120644c27b.png)

## Animation終了のシグナルと処理を結びつける
AnimationPlayerを選択し、「インスペクター」の隣の「ノード」タブを選択。するとAnimationのシグナルと処理を結びつけることができる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3800965/485c374b-9a7d-51ce-5966-a4ed166fdcc9.png)

作成したアニメーションの名前で処理を分けることができる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3800965/a999b88f-be62-cad2-2663-354d98f8fba6.png)
2024/6/18主にITとかセキュリティの記事

中共支援のサイバー攻撃、予想以上の規模＝オランダ政府(6/16)
https://www.epochtimes.jp/2024/06/233172.html

Copilot+ PCの「Recall」機能はInsiderプログラムから - 阿久津良和のWindows Weekly Report(6/16)
https://news.mynavi.jp/article/20240616-windows_report/

ヨーロッパ監査裁判所、EUにAIの利点を受け入れることと慎重さを促す(6/15)
https://elblog.pl/ja/2024/06/15/%E3%83%A8%E3%83%BC%E3%83%AD%E3%83%83%E3%83%91%E7%9B%A3%E6%9F%BB%E8%A3%81%E5%88%A4%E6%89%80%E3%80%81eu%E3%81%ABai%E3%81%AE%E5%88%A9%E7%82%B9%E3%82%92%E5%8F%97%E3%81%91%E5%85%A5%E3%82%8C%E3%82%8B/

AI によって生成されたサイトのブーム: フェイクニュースの新境地と優れたジャーナリズムの重要性(6/15)
https://www.firstonline.info/ja/AI-%E3%81%AB%E3%82%88%E3%81%A3%E3%81%A6%E7%94%9F%E6%88%90%E3%81%95%E3%82%8C%E3%81%9F%E3%82%B5%E3%82%A4%E3%83%88%E3%81%AE%E3%83%96%E3%83%BC%E3%83%A0%E3%80%81%E3%83%95%E3%82%A7%E3%82%A4%E3%82%AF%E3%83%8B%E3%83%A5%E3%83%BC%E3%82%B9%E3%81%AE%E6%96%B0%E5%A2%83%E5%9C%B0%E3%80%81%E3%81%9D%E3%81%97%E3%81%A6%E5%84%AA%E3%82%8C%E3%81%9F%E3%82%B8%E3%83%A3%E3%83%BC%E3%83%8A%E3%83%AA%E3%82%BA%E3%83%A0%E3%81%AE%E9%87%8D%E8%A6%81%E6%80%A7/

フリーゲームは要注意？ゲームを楽しむ前のセキュリティ対策を解説！
https://cybersecurity-park.com/1426/

freee社のDevSecOpsが良かったので紹介したい(6/15)
https://qiita.com/mkt_hanada/items/edab289cac8709a0080f

[レポート] 生成AIを使ってファイアウォールを強化しよう #NIS375 #AWSreInforce(6/16)
https://dev.classmethod.jp/articles/reinforce2024-report-nis375/

ＩＣＣ、ロシアのサイバー攻撃捜査(6/15)
https://www.oita-press.co.jp/1002000000/2024/06/15/NP2024061501000172

ASUS製ルーターに認証バイパスなどの脆弱性。アップデートを(6/16)
https://www.nichepcgamer.com/archives/asus-routers-multiple-vulnerabilities-june-14-2024.html

名機「iPhone X」はいつまで使える？　Apple公式サポート終了後も使い続けて大丈夫？(6/16)
https://news.yahoo.co.jp/articles/3fe26eaf03ab5f4b30313eff597032338efb9bbd?source=rss

「ニコニコ」ハッキングで復旧に1カ月超の惨状「2007年の動画」限定公開で「インターネット老人会」爆誕(6/15)
https://www.excite.co.jp/news/article/SmartFLASH_1174649614522778438/
https://news.livedoor.com/article/detail/26607461/

増えるサイバー攻撃　中小企業がターゲット、群馬でも対策続々　認識不足や費用、人員が課題(6/16)
https://www.jomo-news.co.jp/articles/-/480253

「マイクロソフトのエンジニア“ジャック・ウィリアムス”です」画面に突然の警告「ハッカーに乗っ取られている、4万円分必要」と言われコンビニへ　声かけたコンビニ店員がとっさの判断(6/16)
https://newsdig.tbs.co.jp/articles/-/1233041

iPadの体験を一新する「iPadOS 18」に期待、Apple IntelligenceはM1以上が必須(6/17)
https://xtech.nikkei.com/atcl/nxt/column/18/02863/061300003/

NTT系の次世代型データセンター案、冷却用電力半減と「迷惑施設」脱却をアピール(6/17)
https://xtech.nikkei.com/atcl/nxt/column/18/00154/02098/
GitHubの紐づけで落とし穴にハマった話

# 背景
新しいプロジェクトをXcodeで作成し、それをリモートリポジトリにinitial commitしようとしました。そのとき落とし穴にハマったので、簡単ですが内容を備忘録的にシェアします。

# 対象読者
* コマンドラインや何かしらの方法でinitial commitをする際に詰まったひと
* 認証の期限が切れて再度認証が必要になったひと

# inital commit時の落とし穴
リモートリポジトリに最初のコミットをするときはコマンドラインでかちゃかちゃすると思いますが、おそらくgithubに出てくる以下のコマンドをトレースしていくことになるでしょう。

```terminal
echo "# test-repository" >> README.md
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add origin https://github.com/AkashiTakumi/test-repository.git
git push -u origin main
```

最後のコマンドまでは好調に進むでしょうが、最後に落とし穴は待っています。

```terminai
git push -u origin main
Username for 'https://github.com':
```

ここにはユーザネームまたは登録しているemailアドレスを入力します。そしてエンターを打つとパスワードの入力が求められますが、これが落とし穴です。
素直にパスワードをいれると次のようなエラーが吐かれます。

```
remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/AkashiTakumi/test-repository.git/'
```

要はパスワードによる認証は2021年8月13日にサポートされなくなったとのこと。
じゃあパスワード入力なんて表現するなという話ですが、ここにはどうやら**アクセストークンを入力する**と良いようです。
アクセストークンの発行方法については様々な先人が解説してくださっているのでそちらを参照してみてください。


## 参考
[git cloneでremote: Support for password authentication was removed on August 13, 2021.エラーが出た時の解消法](https://qiita.com/aramasa_ash/items/3accb139d0296896caa2)
(調査中)Javaの HttpClient を使用したKeycloakからBearerトークンを取得

```java
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class KeycloakService {

    public ResponseEntity<String> getToken() {
        String keycloakUrl = "http://your-keycloak-url/auth/realms/your-realm-name/protocol/openid-connect/token";
        String clientId = "your-client-id";
        String clientSecret = "your-client-secret";

        HttpClient httpClient = HttpClient.newHttpClient();

        // リクエストパラメータを準備
        Map<String, String> params = Map.of(
                "grant_type", "client_credentials",
                "client_id", clientId,
                "client_secret", clientSecret
        );

        // URLエンコードされたクエリストリングを作成
        String requestBody = params.entrySet().stream()
                .map(p -> URLEncoder.encode(p.getKey(), StandardCharsets.UTF_8)
                        + "=" + URLEncoder.encode(p.getValue(), StandardCharsets.UTF_8))
                .collect(Collectors.joining("&"));

        // POSTリクエストを作成
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(keycloakUrl))
                .header("Content-Type", "application/x-www-form-urlencoded")
                .POST(HttpRequest.BodyPublishers.ofString(requestBody))
                .build();

        try {
            // リクエストを送信してレスポンスを取得
            HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

            // HttpResponseをResponseEntityに変換
            HttpHeaders headers = new HttpHeaders();
            response.headers().map().forEach((key, values) -> headers.put(key, values));

            return new ResponseEntity<>(response.body(), headers, HttpStatus.valueOf(response.statusCode()));
        } catch (Exception e) {
            e.printStackTrace();
            return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
}
```
OpenAI API を使って簡単な画像生成ツールを作成してみた

## はじめに

自社開発のエンジニアをやっているものです。
日頃から chatGPT にはお世話になっていたのですが、API の方は触らぬまま拗らしていました。
昨今いろんな gpt の派生系が出ている中で触れないわけにはいかないと思い、OpenAI API を使用した極々簡単なツールを作成してみました。
一旦形にした段階でこちらの記事を書き始めているので細かいところはスルーいただけると助かります。

## 作成したツール

### 手書き風画像ジェネレータ

手書き風画像ジェネレータというものを作成しました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981863/9fb918b9-ae60-976a-558a-6091de432833.png" width="1000">

### 概要

テキストボックスにお題を入れて生成ボタンを押下すると、上記のようにお題にあった絵を**手書き風**で出力してくれます。
chatGPT でも画像生成機能はあるのですが、特に要望を入れないでお願いすると結構リアリティの高い画像が出力されがちで個人的にはもう少し簡素なレイアウトが欲しいと感じたところからこのツールを作成するきっかけに繋がりました。
参考として同じお題で chatGPT にお願いした場合の画像になります。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981863/3da1cf18-703f-ffd4-c7e4-6b5581d8bf6e.png" width="500">

## 技術

### 選定

- **Golang**
  - **Gin**
- **html/css**
- **javascript**

高パフォーマンスなのと、最近学習しているという理由でバックエンドは Go 言語にしました。
フロント周りは実装の負担が少なかったのでフルスクラッチ？で実装しました。
OpenAI API のモデルはググってみて、使用可能かつ新めっぽかったので**dall-e-3**を使用しました。

### 設計

１画面構成なのでモノリスチックな構成で良いと判断しました。  
バックエンドに API を 2 本(GET,POST)立てまして、GET メソッドは HTML を返し、POST メソッドは OpenAI API から生成画像 URL を取得し、json で返すような設計になっています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981863/3c78bc7f-bbde-a13a-b660-577572f49c4a.png" width="1000">

処理フローは下記のようになります。

- GET
  1. クライアントサイドから GET メソッドで API を呼ぶ
  1. API が HTML ファイルが返す
- POST
  1. クライアントサイドからプロンプトをリクエストボディに設定し POST メソッドで API を呼ぶ
  2. API から必要なデータをリクエストボディに設定し POST メソッドで OpenAI API を呼ぶ
  3. OpenAI API が画像を生成し URL を返却する
  4. API が URL を返す
  5. URL を元にクライアントサイドで画像を表示させる

### 実装

題に合わせて OpenAI API にリクエストを送るところの実装を簡単に説明します。
下記がリクエスト送るところの実装になります。

```go
response, err := client.R().
		SetHeader("Authorization", "Bearer "+os.Getenv("OPEN_AI_SECRET")). // *1
		SetHeader("Content-Type", "application/json").
		SetBody(map[string]interface{}{
			"model":           "dall-e-3", // *2
			"prompt":          prompt, // *3
			"n":               1,
			"size":            size, // *4
			"response_format": "url",
		}).
		Post(openaiURL)
```

OpenAI API は[OpenAI overview](https://platform.openai.com/docs/overview)で api キーを取得が必要でありその値を\*1 のところで設定しています。
リクエストボディは使用するモデル\*2、プロンプト\*3、画像サイズ(ex.1024×1024)\*4 は自分好みに合わせて設定しました。あとの値は他の方の実装に真似て設定しました。

## 作成してみた感想

やはりですが、汎用性と利便性がとても高いなと感じました。
実際「お題にあった画像を生成する」という要件を自力で実現するのはかなり難しく（自分は無理）そこを API に問い合わせるだけでできてしまうのは感動しますよね。工夫すればもっと面白い使い方ができると思うので、もう少し奇抜な使い方を考えてみたいと思いました。
あとは WEB の技術を学ぶことを目的として OpenAI API を使用するのもとても有意義になりそうと感じました。よく何を作るかで困りがちですが、gpt ならいろんなことができるので考え耽ることは少なくなるでしょうし、実装も簡単なので挫折経験も少なくなりそうだなと思いました。