OmniAICreator/Qiita-1.07M huggingface dataset:
【個人開発】動物園に焦点を当てたサービス「ZooMania」をリリースしました

# はじめに
こんにちは、おおくまと申します！
私は現在、とあるプログラミングスクールに通い、完全未経験からWebエンジニアへの転職を目指しています！
学習を開始して約3ヶ月が経過しましたが、Webアプリを制作する機会がありましたので、その成果をご紹介させていただきます！
まだまだ学習中のため、内容に誤りがある場合があります！
コメント等で教えていただけると幸甚です！

# 作成したサービス
![logo.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348444/98a38997-63b5-e228-ae16-0643f5ad70b3.jpeg)
・サービス名：ZooMania
・GitHub：https://github.com/kumaryoya/zoo_mania

# 開発の背景
  
**最近、動物園に行きましたか？**
  
私は幼少期から動物園が好きで、社会人になってからも一人で足を運び楽しんでおります！  
しかし、年齢を重ねるごとに周りの友人や同僚たちは動物園に行く機会が減っているように感じておりました！  
動物園は低価格であるにも関わらず、非常に癒される空間であるため、多くの人に「動物園に行きたい」という気持ちを喚起させるサービスとして、「ZooMania」を開発いたしました！

# 実装機能
動物園に行く人も、行かない人も楽しめるように実装しました！
* ユーザー登録・退会機能  
* ログイン・ログアウト機能  
* Googleアカウントログイン・ログアウト機能  
* パスワード再設定機能  
* プロフィール表示・編集機能  
* 動物園一覧・詳細表示機能  
* 動物園詳細ページにGoogleMap表示機能  
* 動物園日本地図機能  
* お気に入り動物園登録・編集機能  
* 動物園人気ランキング表示機能  
* 画像投稿・編集機能  
* 投稿いいね機能  
* 投稿いいねランキング表示機能  
* 動物園一覧、投稿一覧における動物園検索・絞り込み機能  
* 動物園スタンプラリー機能  
* 位置情報による動物園レコメンド機能  
* Twitter共有機能  
* LINE通知機能  
* PWA機能  
* 管理ユーザー機能  

# 技術選定
* Ruby 3.2.2  
* Rails 7.0.6  
* Node.js 20.2.0  
* CSS tailwind, daisyUI  
* Webアプリケーションサーバ heroku  
* データベース PostgreSQL  
* ファイルサーバ AWS S3

# 主に使用したgem
* sorcery
* carrierwave
* kaminari
* ransack
* googleauth
* line-bot-api
* fog-aws
* aws-sdk-s3
* carrierwave-aws
# 拘った機能
実装した機能の中で、特に拘った機能は以下の2つです！

* **位置情報による動物園レコメンド機能**
<img width="300x300" alt="IMG_5057.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348444/68c74fef-e264-7767-9d34-7d91485cedbf.jpeg">
  
ユーザーの位置情報を取得し、その地点から近い動物園5つをおすすめします！
この機能には、Googleの2つのAPIを使用しています！
* Geocoding API
* Maps JavaScript API
<br>

* **LINEによる新着投稿通知**
<img width="300x300" alt="IMG_5058.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348444/e0ffc68d-63a0-f1a2-19ed-40656f783d07.jpeg">
  
ZooManiaのLINE公式アカウントを友だち追加しておくと、新しい投稿があった際に、通知されます！
こちらは、LINE Developersで、ZooManiaの公式LINEアカウントを作成し、そちらにAPIリクエストを送るかたちで、実装してみました！


# 最後に
今回、初めて1人で、0からWebアプリを作成してみました！
また、APIを使ったのも初めてでした！
この経験を通じて、分からないことが多く、機能を1つ1つ実装していくのは、大変でしたが、非常に学びになりました！
もっともっと勉強して、すごいアプリを作れるようにこれからも頑張っていきたいと思います！
技術記事とは程遠い、拙い記事でしたが、最後まで読んでいただきありがとうございました！
Streamlit ＋HuggingFace SpaceでWEBアプリケーションをデプロイする

Hugging FaceでStreamlitのSpaceを作成すると簡単にみんなで使える便利なアプリが作れることが分かったのでこれから活用してみることにしました。
デプロイまでに学習したことを自分用＋これからやってみたい人向けに簡潔に残しておくことにしました。

# Streamlit
Streamlitは **WEBアプリケーションをデプロイ(サーバー等に設置してユーザーが使えるようにする)するためのフレームワーク** で、オープンソースで利用できます。特に機械学習やデータ分析などのプロジェクトをデプロイするのに向いているようです。まずは公式ドキュメントを読んでどのような用途があるか学習するのを推奨します。

https://docs.streamlit.io/

# MakeQR - Streamlit で書いたコードをSpaceでデプロイ
Hugging FaceのSpaceではWEBアプリケーションをデプロイすることできますが、中でもStreamlitをフレームワークとして利用することができます。今回は **URLをインプットに入力するとQRコード画像を作成してくれるアプリの配布** を目指そうと思います。
SpaceでWEBアプリケーションを作成するには、まず"Create new space"を押して新しいリポジトリを作成します。

https://huggingface.co/spaces

![st02.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337578/4b9cd21a-10c6-152b-c8d8-efa1e0ad4cc9.png)

## ファイル構成
SpaceでWEBアプリを実行するには最低限アプリそのものである`app.py`と依存関係を表した`requirements.txt`をアップロードする必要があります。SpaceはGitリポジトリーを用いるDockerとなっていて、ファイルのプル・プッシュにGitを使える(手動でアップもできます)他、`requirements.txt`で必要なライブラリーのイメージを指定することができます。

![st03.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337578/95bcfbc2-8211-2ede-a9bf-dc97436bda64.png)


また実行環境としてCPUと16GBのVRAMを無料で使うことができます。画像や言語を処理する機械学習モデル等でなければこれで十分です。
若干の欠点は、 **Spaceでアプリを公開するとソースコードも公開されてしまう** ことです。ソースコードを公開したくない場合はSpace以外のサイトにデプロイするか、必要な機能をAPI化して別サイトから取り寄せる等の構造にするとよいでしょう。

### requirements.txt
QRコードを扱うのにPillowとqrcodeを使います。SpaceではTensorFlowやKeras等もイメージに使えます。
```
streamlit
pillow
qrcode 
```

### app.py
アプリ本体ではUIを使った処理をStreamlitで、それ以外の自前で実装したい処理は自作関数にします。それだけです。
```
from PIL import Image
import qrcode
import streamlit as st


def MakeQR(url):
    _img = qrcode.make(url)
    _img.save("qrcode.png")
    
    img = Image.open("qrcode.png")
    return img

# NOTE メイン部分
st.title("QR maker")

# NOTE インプットから文字列を取得
url = st.text_input("Input URL to make QR code here:")

# NOTE ボタンを押すと条件文が実行される
if st.button("Generate QR code:"):
    
    img_caption = "QR image for " + url
    qr = MakeQR(url)
    st.image(qr, caption=img_caption)
```
![st04.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/337578/93fcbf0e-fe53-2e7a-6ffd-5816d4895ea0.png)

MakeQRを使えば **怪しげなアクセス権限を要求してくるGoogle Playのアプリを入れなくても（笑）** 簡単にみんなで共有したいサイトのQRコードを作れるようになるという利点があります。ぜひご活用ください。

https://huggingface.co/spaces/Nymn5/MakeQR
【ChatGPT無】への入力を効率化する方法

:::note info
本記事は、ChatGPT（無料版）で
行なっております。GPT4での確認
はできておりません。あしからず。
:::

　どうも、カーブミラーです。

　今回は、
　　プロンプトの入力の際の
　　　固定的な文言を
　　　　日本語入力
　　　　　（AndroidならGBoard）
　　　　　　（iPhoneなら？）に
　　　　　　　登録しよう、
　　　　　　　　という話です。

　実は、
　　仕事で、
　　　辞書に単語登録する
　　　　必要があり、
　　　　　登録していて、
　　　　　　気付いて
　　　　　　　しまったのです。

　　辞書に登録して、
　　　入力に使えばいい、と。

　仕事では、
　　定型文を辞書に登録していて、
　　　長年、それで慣れていて、
　　　　登録する機会がなくなって、
　　　　　すっかり忘れていました。

　ChatGPTさんに
　　入力する際も、
　　　特に疑問にも
　　　　思っていませんでした。

　だって、
　　キーボードを
　　　使わない（使えない）から。
　　　　スマホばかりw

　キーボードでの入力を
　　していれば、
　　　おそらく
　　　　すぐに気付いたはずです。
***
　ということで（誤魔化すw）
　　まずは、定型文を
　　　用意しましょうか。

　まぁ、Promptに使うものを。

　・# 目的
　・# 注意点
　・# 処理手順
　・# 最終確認
　・あなたが理解できない箇所があるならば、指摘してください。」
　・あなたが理解できたなら、「はい」と答えて、待機してください。

　それから、定型文を出す読み。
　パソコンならば、
　　記号に番号を
　　　組み合わせる
　　　　ところなんですけど。

　私、スマホですからねぇ。

　まぁ、
　　そこは、自分たちの
　　　やりやすい形にしましょうね。

***
　それで、
　　辞書への登録ですが、
　　　ChatGPTさんに
　　　　教えてもらいましたら
　　　　　どうにも古い！

　とにかく、
　　登録方法は知っているので
　　　ひとつずつ登録していきます。
　　　　面倒ですが。

　すみませんが、
　　みなさんは、
　　　それぞれの登録方法で、
　　　　やってください。
***
　ふぅ〜。

　どれどれ……

　おお、早い！

　定型文の入力が、
　　ポンポンできるのは、
　　　うれしいですね。

　まぁ、上記程度ならば、
　　メモ帳レベルのアプリに
　　　書き込んでおいて、
　　　　コピペすれば、
　　　　　簡単なんですけどねw

　でも、もっと早く、
　　気付けば、良かったです。
***
　しかし、
　　これで終わっては、
　　　ちょっと申し訳
　　　　ありませんので、
　　　　　おまけのPromptを。

```Text:間違えて確定した文章を置換するPrompt
# 目的
入力された文章を、置換し、出力する。

# 注意点
本Promptは、プログラム作成が目的ではない。

# 例
「ro-maji」→「ろーまじ」→「ローマ字」
「ひらがな」→「平仮名」

# 処理手順
1. 入力文章が置換の必要があるか判断します。
   - 置換が必要な文章:
     - すべてが、ローマ字の場合。
   - 置換が不要なら、4に移行。
3. 置換する判断によって、処理する。
　・もし入力文章がローマ字の場合、それをひらがなに置換します。
4. 入力文章が置換の必要があるか判断します。
   - 置換が必要な文章:
     - すべてが、ひらがなの場合。
   - 置換が不要なら、6に移行。
5. 置換する判断によって、処理する。
　・もし入力文章がひらがなの場合、それを日本語として意味が通じる文章に置換します。漢字に直した方が意味が通りやすい・より良いならば、直してください。候補が多い場合は、すべてを出力してください。
6. 置換された文章を出力します。

# 最終確認
あなたが理解できない箇所があるならば、指摘してください。

あなたが理解できたなら、「「」で文章を囲んでください」と促して、待機してください。
```
　正直、
　　自分勝手に
　　　置換する場合もありますw
Minecraft Skript - 1. Skriptって何? / 導入方法

## はじめに - Skriptって何?
Minecraft Java版のサーバー向けにプラグインを作って自分のサーバーに独自要素が欲しい!!
でもJava言語が難しい... どうしよう...
そんな人におすすめなのがSkriptです。
Javaよりも数百倍ぐらい簡単にプラグインのようなものを作れてしまいます。
必要なのは __中学生レベルの英語力__ と __自分で調べようとする力__ です。

:::note warn
この記事ではSkriptの常識的な事について書いています。
他の記事と似た内容が多く含まれているかもしれません。
:::

## 導入方法

https://github.com/SkriptLang/Skript/releases から、お好きなバージョンを選んでください。
(Betaと書かれたものは不安定なのでおすすめできません。)

:::note info
2023/08/09の時点では`2.6.4`が一番新しいバージョンです。
:::

ダウンロードしたら、`Plugins`フォルダに入れます。
> 入れ方が分からない? Googleさんに聞いてみましょう。

再起動すると`Skript`というフォルダが生成されます。
今後はその中にある`scripts`というフォルダに書いたskriptを入れていく事になります。(拡張子は`.sk`です)
最初の起動時は`scripts`の中にサンプルのskriptファイルが生成されているはずです。
全部消してしまいましょう。必要ありません。

:::note info
`-`というものがファイル名の一番最初についていますが、これはそのskriptを無効化するためについているものです。
これを外さない限り、そのskriptは有効になりません。
:::

### Skriptを書く環境を整える

コードを書くためには、エディタが必要です。
OSに付属しているエディタなんて使い物になりません。

コードエディタは調べると色々出てきます。いくつか挙げてみます。
私はVSCodeを使っています。お好きな環境を選んでください。

***
### Visual Studio Code 
よくVSCodeと言われる、Microsoft社の提供する無料のコードエディタです。
拡張機能やGitとの連携、マルチカーソルなど、コードを書く上で便利な機能が多く備わっています。
ダウンロード: https://code.visualstudio.com/download

***
### NotePad++
動作が軽い、オープンソースのコードエディタです。
プラグインの導入や豊富なテーマによって、自分好みのエディタにカスタマイズできます。
ダウンロード: https://notepad-plus-plus.org/downloads/

***
### SkUnity Parser
Web上で簡単にSkriptを書けるエディタです。
ワンクリックで構文を解析できるパース機能や、複数人でコードを編集できるLive Editing機能が搭載されています。
Parser.skUnity.com: https://parser.skunity.com/
***

## 簡単なコードを書く
先ほどの`scripts`というフォルダの中にファイルを作ってみましょう。
拡張子は`.sk`です。
初めてのコードなので、`test.sk`か`first.sk`という名前がいいかもしれません。
基本的な形は
```
Event:
(TAB)実行すること/条件
```
です。`(TAB)`と書かれている所はTabキーを1回押すか、半角スペース4つにしてください。

:::note warn
ここでは`(TAB)`と書いていますが、今後は書かないので、ご注意ください。
:::

`:`がある部分はブロックの始まりで、字下げをする必要があります。
少し慣れが必要かもしれません。

## プレイヤー参加/退出時のメッセージを編集する
```yml
on join: #イベント
    set join message to "&a%player%さんが遊びに来ました。" #処理
```
```yml
on quit: #イベント
    set quit message to "&c%player%さんが退出しました。" #処理
```
> `#`で書かれているものはコメントアウトで、Skriptの処理には一切影響しません。

Skriptで(個人的に)一番簡単で変化がわかりやすいものです。
プレイヤーが参加/退出した時、そのメッセージを～にするskriptです。

`on join`と`on quit`はイベントで、プレイヤーの参加/退出を検知するイベントです。
その後に`set join message to ...`、`set quit message to...`で参加/退出時のメッセージを置き換えています。
`&a`や`&c`は[Minecraftのカラーコードです。](https://minecraft.fandom.com/ja/wiki/%E8%A3%85%E9%A3%BE%E3%82%B3%E3%83%BC%E3%83%89)
`%player%`にはプレイヤー名が代入されます。

:::note info
`%player%`のような、`%`で囲むものについては今後解説します。
:::
見てもらえればわかりますが、ただの英文です。
コードを書く際に少し難しい所があるだけで、慣れてしまえばこのぐらいの構文は1分未満で書けます。



今回はこれで終わりです。
良いSkriptライフを!
NetgearスイッチングハブでMAB

NETGEARのスマートスイッチ GS310TPでMAC認証バイパス設定に四苦八苦したので、メモ。

まとめると、NETGEARのMABはユーザー名が「MACアドレス大文字区切り文字無し」。

# ネットワーク環境

* 認証サーバー
YAMAHA WLX212の簡易RADIUSサーバー
* オーセンティケーター
NETGEAR GS310TP
* サプリカント
今回はTP-LinkのNVR

# 認証サーバーの設定

下記設定で動くことを確認。
ポイントは、ユーザー名をMACアドレス大文字区切り文字無し。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175093/7823fcbf-4442-319d-79ae-ab699ee7fe8c.png)


# オーセンティケーターの設定

ポート制御「自動」でMAB有効ではうまくいかず…
ポート制御「MACベース」かつMAB有効でうまくいきました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175093/de02adcf-d9a1-a69d-14ae-d9b7238a47d0.png)


# 参考
YAMAHA RADIUSのMAC認証
http://www.rtpro.yamaha.co.jp/AP/docs/wlx212/mac_address_auth.html

GS310TPのユーザーマニュアル
https://www.downloads.netgear.com/files/GDC/GS308T/GS308T_GS310TP_UM_EN.pdf

# 最後に

802.1xの知識も浅いのもありますが、NETGEARのユーザーマニュアルでもうちょっと触れていてほしかった…
せめてログにリクエストメッセージの内容を載せてくれてたら…WLX212のログも貧弱…
ネットワークキャプチャで勉強してみます。

本当はDynamic VLANの指定もしたかったのですが、「SWXシリーズの端末認証」のほうでは認証通りませんでした。何が違うのでしょうか…。
EC2 - EKS Cluster連携方法（忘備録）

# 概要
### 下記ののリンクの手順に従い、できなかった場合、`kubeconfig`ファイルを手動で編集する

https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/create-kubeconfig.html


 - 例）会社のSSOの設定により、EC2（デプロイ専用）からEKS Clusterに連携できなかった場合、下記のエラーになる

```shell
[ec2-user@ip-XX-XX-XX-XX ~]# aws eks update-kubeconfig --region ap-northeast-1 --name <クラスター名>

An error occurred (AccessDeniedException) when calling the DescribeCluster operation: User: arn:aws:sts::1111111111111:assumed-role/AWSReservedSSO_XXXXXXXX_xxxxxxxxxxxxxxxx/xxxxx is not authorized to perform: eks:DescribeCluster on resource: arn:aws:eks:ap-northeast-1:xxxxxxxxxxxx:cluster/<クラスター名> with an explicit deny
```


- 上記のエラーは命令語を叩くEC2に、IAM`eks:DescribeCluster`を追加しても解決できなかった


# 回避方法

- `.kube/config`を作成すること
```shell
cd ~
mkdir .kube
cd .kube
vi config
```

```yaml
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: <クラスター画面の認証機関>
    server: <クラスター画面のAPI サーバーエンドポイント>
  name: <クラスター画面の ARN>
contexts:
- context:
    cluster: <クラスター画面の ARN>
    user: <クラスター画面の ARN>
  name: <クラスター画面の ARN>
current-context: <クラスター画面の ARN>
kind: Config
preferences: {}
users:
- name: <クラスター画面の ARN>
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1beta1
      args:
      - --region
      - ap-northeast-1
      - eks
      - get-token
      - --cluster-name
      - <クラスター名>
      command: aws
```

# 対応結果
- EC2からk8sの命令語を叩けるようになる
```shell
[ec2-user@ip-XX-XX-XX-XX ~]$ kubectl run nginx --image nginx
pod/nginx created
[ec2-user@ip-XX-XX-XX-XX ~]$ kubectl get pods
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          10s
```

- EKSクラスター画面で、`nginx`Podが作成されたことを確認する
spring boot 3.1系からmysql-connetor-javaが使えない。

<h2>表題の件について</h2>

新規サービスのPoC作成でspring boot、MySQL8系（最新安定版）を採用したとき
ドライバのライブラリとして"mysql-connetor-java"を利用しようとしたが、
どうも依存関係が解決しない。

<a href="https://github.com/spring-guides/gs-accessing-data-mysql">公式ドキュメント</a>を参考にしたら3.1系へのupdateの際にpom.xmlから
<pre>&lt;dependency&gt;
    &lt;groupId>mysql&lt;/groupId&gt;
    &lt;artifactId>mysql-connector-java&lt;/artifactId&gt;
&lt;/dependency>
</pre>
が削除されていた。

ドライバなしで動作するのかと確認したところしなかったので
調査してみるとmysql-connector-jに統合されたようだ。
<pre>&lt;dependency&gt;
    &lt;groupId>mysql&lt;/groupId&gt;
    &lt;artifactId>mysql-connector-j&lt;/artifactId&gt;
    &lt;version>8.1.0&lt;/version&gt;
&lt;/dependency>
</pre>
これをpom.xmlに記載すると無事mysqlへの接続ができた。
tensorflowのGPU環境構築(Windows11)

## 初めに
ただの学生が自分が成功したやり方を書くだけなので確実性は保証しません。
また、他のサイトを見てわかりそうなところは飛ばしますし、簡潔に行きます。

## やり方
tensorflowのGPUテスト済みのビルド構成をURL (https://www.tensorflow.org/install/source_windows?hl=ja) から見つけます。現時点(2023/8/9)で一番新しいバージョンを選びます。
![スクリーンショット 2023-08-09 10.31.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2574708/ae8db99c-922d-d2f0-c034-4619e381dd86.png)
今回は一番上のtensorflow_gpu-2.10.0を選ぶとします。

### Pythonのバージョンを確認
ここはわかると思うので飛ばします。

### MSVC 2019
https://visualstudio.microsoft.com/ja/thank-you-downloading-visual-studio/?sku=community&rel=16&utm_medium=microsoft&utm_campaign=download+from+relnotes&utm_content=vs2019ga+buttonVisual 
リンクよりVisual Studio Community 2019をダウンロードします。
ダウンロードしたインストーラーを起動し、C++ Build Tools(C++によるデスクトップ開発)にチェックをいれ、インストールします。
x64 Native Tools コマンドプロンプトを起動し、cl.exeにpathが通っているか確認します。
```
where cl
```
errorが出ずに、pathが返されたら完了です。

### bazel 5.1.1

https://github.com/bazelbuild/bazel/releases/tag/5.1.1
リンクから**bazel-5.1.1-windows-x86_64.exe**を選んで、ダウンロードします。
C:\Program Files\bazel　というフォルダを作成し、その中にダウンロードしたbazel.exeを入れます。また、pathを通します。コマンドプロンプトを起動し、bazel.exeにpathが通っているか確認します。
```
bazel version
```
インストールしたbazelのバージョンが表示されれば完了です。

### CUDA 11.2
CUDA 11.2のインストールを行う前に、NVIDIAのドライバのインストールを行います。https://www.nvidia.co.jp/Download/index.aspx?lang=jp
URLより自分のGPUにあったドライバをダウンロードしてください。

対応表を見て、ダウンロードしたNVIDIAのドライバのバージョンがCUDA 11.2に対応していることを確認してくだ
さい。

対応表: https://docs.nvidia.com/cuda/cuda-toolkit-release-notes/index.html


以下のURLからCUDA 11.2をダウンロードします。Windows11の選択肢はありませんので、10を選択します。
https://developer.nvidia.com/cuda-11.2.0-download-archive?target_os=Windows&target_arch=x86_64

ダウンロードしたインストーラを起動し、いくつか次へを選択したら、インストールオプションを選ぶ画面にたどり着きます。カスタムを選び、CUDAが選択されていることを確認してください(されてない場合はCUDAにチェックをいれる)。そのまま次へを選びインストールします。

次にpathを設定します。
環境変数を起動し、~CUDA\v11.2, ~CUDA\v11.2\bin, ~CUDA\v11.2\include, ~CUDA\v11.2\lib にpathが通っていることを確認してください(ない場合は追加)。

最後にパスが繋がったことを確認します。
コマンドプロンプトを開き、以下のコマンドを実行します。
```
where nvcc
```
errorが出ずに、pathが表示されたら完了です。

### cuDNN 8.1

最初に、cuDNNのダウンロードを行うためにはNVIDIA Developer Program メンバーシップに入る必要があります。Join nowしてメンバ登録を行なってください。
CUDA v11.2に対応したcuDNN 8.1をダウンロードします。

次に、ダウンロードしたファイルの中に入っているbin, lib, includeファイルを~CUDA\v11.2にコピーし、置き換えます。

最後にcudnn64_8.dllにpathが通っていることを確認します。
コマンドプロンプトを開き、以下のコマンドを実行します。
```
where cudnn64_8.dll
```
errorが出ずに、pathが表示されたら完了です。

### tensorflow-gpu 2.10.0

最後にtensorflow-gpuをインストールします。以下のコマンドを実行してください。
```
pip install tensorflow-gpu==2.10.0
```

### GPU環境の構築ができたか確認する

```python
from tensorflow.python.client import device_lib
print(device_lib.list_local_devices())
```
上記のpythonプログラムを実行し、gpuが出力されたら完了です。

## 終わり
スクリーンショットが少なく、わかりづらいことかと思いますが、書く予定がなかったのと、同じことをもう一度やる気力がありませんでした。参考になるサイトがネット上にはありますので、そちらの方でカバーしていただけると幸いです。
Modeler FlowでSQLプッシュバックのプレビューを行う

Watson Studio on CP4DaaSのModeler FlowでSQLプッシュバックのプレビューを行ってみます。実行前にどのノードがSQLプッシュバックするかを確認することができます。

* テスト環境
    * CP4DaaS (2023/8/9)
    * Dallas


以下のように、「フロー・プロパティー」を開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/dde8ec95-4616-410e-f109-47a80b7e8128.png)

「オプション」の「ロギング」からSQLのロギングの項目群にチェックを付けます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/d3fbf32b-a510-9e90-719f-be5773086fdc.png)


ターミナルノードを選択し、「SQLプッシュバックのプレビュー」を実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/c252f7af-db0d-05d3-4549-7d7db28fa9d2.png)

以下のようにSQLプッシュバック可能なノードに「SQL」のマークがつきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/a5082116-5d5d-e5a0-bc4e-a4746a860092.png)


「メッセージ」アイコンをクリックして、「実行履歴を表示」開きます。
するとメッセージの中にプッシュバックされるSQL文が記録されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/98841113-0290-8eca-9ed5-abfab23f615f.png)


#### 参考:SQL 最適化

https://dataplatform.cloud.ibm.com/docs/content/wsd/sql_overview.html?locale=ja&audience=wdp&context=cpdaas
任意のディレクトリ配下にあるp5のjarファイルを一括コピーする

毎回コピーするのが面倒なのでスクリプト化してみた

## 想定するディレクトリ構成( 例: /usr/local/hogehoge/p5/ )

```
/
|--artnet4j2
|  |--library
|  |  |--artnet4j2.jar
|--oscp5
|  |--library
|  |  |--oscp5.jar
```

## ソースコード

```perl:copyP5Lib.pl
#!/usr/bin/perl -w

use strict;
use Data::Dumper;
use Smart::Options;
use File::Find::Rule;
use File::Copy qw/copy move/;
use File::Basename;

# p5のjarを保存しているディレクトリ
my $source_dir_path = "/usr/local/hogehoge/p5/";

my $argv = Smart::Options->new->parse;
unless (defined($argv->{'target_dir'})) {
  print 'usage: $ perl copyP5Lib.pl --target_dir=[path/to/dir]', $/;
  exit;
}

my $target_dir = $argv->{'target_dir'};
unless (-d $target_dir) {
  print 'target_dir: "', $target_dir, '" does not exists. exit.', $/;
  exit;
}

my @jar_files = File::Find::Rule->file
  ->name('*.jar')
  ->in($source_dir_path);
foreach my $jar_file_path(@jar_files) {
  if ($jar_file_path =~ /.*\/library\/.*\.jar/) {
    my $jar_filename = basename($jar_file_path);
    # print $jar_filename, $/;

    if (-e join("/", ($target_dir, $jar_filename))) {
      print "[warn] ", $jar_filename, " has already exits.", $/;
    }

    copy $jar_file_path, $target_dir;
    print "[copy] ", $jar_file_path, $/;
  }
}

exit;
```
投稿の編集ボタンと削除ボタンの表示

編集ボタンと削除ボタンが投稿した人物にしか表示できないようにする方法を教えます。

```
<div class="btn_list">
  <% if current_user && current_user.id == @shop.user_id %> <!-- ログインユーザーが投稿者である場合に表示 -->
    <div class="edit_btn">
      <%= link_to '編集', edit_shop_path(@shop) %>
    </div>
    <div class="del_btn">
      <%= link_to '削除', shop_path(@shop), method: :delete, data: { confirm: '本当に削除しますか？' } %>
    </div>
  <% end %>
  
  <div class="bookmark_btn">
    <% if current_user && current_user.bookmarks.exists?(shop_id: @shop.id) %>
      <%= link_to delete_bookmark_shop_path(@shop), method: :delete, class: "bookmark-btn" do %>
        <i class="fas fa-star bookmarked"></i>
      <% end %>
    <% else %>
      <%= button_to bookmark_shop_path(@shop), method: :post, class: "bookmark-btn" do %>
        <i class="far fa-star"></i>
      <% end %>
    <% end %>
  </div>
</div>
```
上記のコードでは、current_user が @shop.user（投稿者）と一致する場合にのみ、edit_btn と del_btn の部分が表示されます。それ以外の場合は非表示になります。
また、この場合はshopモデルをuserモデルと関連づけるには以下のコードを書きます。

```
class Shop < ApplicationRecord
  belongs_to :user
  # ... 他のコード ...
end
```
また、shops_controllerのcreateアクションも以下の様にします。

```
def create
  @shop = Shop.new(shop_params)
  @shop.user = current_user # ユーザーオブジェクトを関連付ける
  @shop.image.attach(params[:shop][:image]) if params[:shop][:image]
  tag_names = params[:shop][:tag_names].split(",")

  if @shop.save
    redirect_to shops_path, notice: '店の情報が登録されました'
  else
    render :new
  end
end
```

これにより、投稿で編集ボタンと削除ボタンが表示・非表示が可能となります。
OpenAI Function Calling の動きを理解する

# はじめに
Function Callingはご存じの通り、関数の定義と入力をいれることで、定義された関数が必要であればその関数名と引数を回答として返してくれる機能です。実装方法なんかは公式・非公式含めてたくさんありますので、ここでは概要の動きと利用用途についての考察をしてみたいと思います。

# ざっくりとした動き

まずは **「Web検索したりしながら情報をあつめて、その中から欲しい情報をメモに登録しながらメモをつくっていく」** というシナリオを想定します。


関数として必要な以下の2つを登録します。
- web_search(キーワードの配列)
    - キーワードの配列をもとにWeb検索をする関数
- memo_insert(文章)
    - ユーザ用のメモに文章を登録する関数

併せてシステムプロンプトとして以下のように関数を適宜使いこなして対応する旨定義します。
```python
system_prompt = """\
あなたはAIコンシェルジュです。ユーザからの要望に従って、Web検索などを駆使して回答を作成します。
なお、ユーザには専用のメモがあり、その情報を取得したり、追加したりすることも実施して下さい。
"""
```

コードの詳細は割愛しますが、上記のシステムプロンプトと関数定義で以下のようなシーケンスフローが実現できます。

```plantuml
@startuml
actor User
participant システム
participant ChatGPT

note left of User #aqua
挨拶
end note
User -> システム: "こんにちわ"
システム -> ChatGPT: "こんにちわ"
ChatGPT -> システム: "こんにちわ。何かお手伝いできますか？"
システム -> User: "こんにちわ。何かお手伝いできますか？"
note left of User #aqua
検索
end note
User -> システム: "xxxの動向について調べて"
システム -> ChatGPT: "xxxの動向について調べて"
ChatGPT -> システム: "web_search("xxx","動向")"
システム -> システム: web_search("xxx","動向")
システム -> ChatGPT: web_search("xxx","動向")の実行結果
ChatGPT -> システム: "xxxの動向は～（略）"
システム -> User: "xxxの動向は～（略）"
note left of User #aqua
メモ
end note
User -> システム: "xxxの動向のzzzについてメモに登録して"
システム -> ChatGPT: "xxxの動向のzzzについてメモに登録して"
ChatGPT -> システム: "memo_insert("xxxの動向のzzzについて～")"
システム -> システム: memo_insert("xxxの動向のzzzについて～")
システム -> ChatGPT: memo_insert("xxxの動向のzzzについて～")の実行結果
システム -> User: "メモに登録完了"
@enduml
```

# 考察

Function Calling以前は、上記のシナリオを実現するためには、ユーザからの入力がWeb検索なのか、メモ登録なのかを判別するChatGPT、もしくは判別して挙動を変えるシステムプロンプトが必要でした。これが中々職人芸みたいなところもあって、思ったような動きをしないということが多かったかなと思います。（頑張ればできたりもするけどもモデル変更などに脆弱ですしね）

なのでFunction Callingを使うことで、
- 安全に関数呼び出しができるようになった
- 複数の意図をもったChatGPTが作りやすくなった
 
かなと思います。
ただし1つの目的で関数の引数を抜き出すだけに使うと、これまでもフォーマット指定で抽出できていたところ＆細かい調整などもできていたところなので、そこまでのうま味はないように感じます。

ChatGPTに何をさせたいのかを設計した際に、Function Callingをつかってまとめれる部分は1つのシステムプロンプト＋Function Callingを使う、っていうあたりが落としどころかなと。
エンジニアと売上

<h2>初めに</h2>
こんにちは。
<br>最近、エンジニアの売上って何なのだろうと考える機会があったので、折角だからと思い纏めてみることにしました。
<br>やるなら、徹底的にということで会計とは？から考えていきます。

<h2>そもそも会計とは</h2>

一言でいうと、<b>企業のお金の取り扱いを分かりやすくするもの</b>です。

お金をどんな感じで持っていて、
どんな感じに集めてきていて、
どんな感じにお金を回収していて、
それに対してどれくらいお金使ったんだろう
がわかるものです。
会計用語を使うと上から「資産」「負債・純資産」「収益」「費用」って感じです。

今回は財務会計の観点からエンジニアについてみていきましょう。

<h2>ソフトウェアの種類って？</h2>

まず、ソフトウェアが会計上どのように取り扱われるかについてです。

会計上ソフトウェアにも種類があります。
「受注制作ソフトウェア」、「製品マスター」「自社利用ソフトウェア」の3種類くらいに分かれます。

それぞれどのように取り扱われるか考えていきます。

<h5>1.受注制作ソフトウェア</h5>

顧客に作ってと言われたものを作るソフトウェアです。
ここにかかる費用は製造原価(費用)に含まれます。

<h5>2.製品マスター</h5>

販売しようと思うソフトウェアのマスターです。
作っている間の費用は販売費および一般管理費(費用)に含まれます。
そして、完成すると取得原価(どれくらい価値があるよ～)が計算されて、ソフトウェアとして資産計上されることになります。

<h5>3.自社利用ソフトウェア</h5>

最後に自社利用のソフトウェアです。
これは作っている間の費用のうち研究開発費(新機能開発！！の費用)に含まれるもの以外はソフトウェアとして資産計上されることになります。(大体自社でもともと作っている製品の中で流用しているところに使った費用)
製品マスターとの違いはできたときに価値を計算して資産にするのではなく、費用がほとんどすべて資産になります。

<h2>エンジニアの人件費はじゃぁどうなるの？</h2>

ここまでソフトウェアの種類を見てきたのですが、結局私たちエンジニアの人件費はどう影響するのでしょうか？？

受注制作ソフトウェアでは、製造原価に含まれるので売り上げに対する費用となります。
つまり人件費が高くなれば高くなるほど収益性が低いなぁと思われるわけです。

また、製品マスターであれば費用だけが増えていくのでこの企業、利益あげれてないんじゃないかなぁと思われるわけです。

最後に自社利用であれば、新機能にかかる人件費じゃなければ、資産に計上されるので企業の持ち物作ってて無駄ではないと思われるわけです。



<h2>結局エンジニアの売上って？</h2>

受注生産であれば、代金をもらえることはわかっているのでエンジニアとしては予定通りの進捗で完成に進めることが間接的に売り上げになります。
ということは受注生産であれば、進捗度が間接的に売上でいいのではないかと思います。

製品マスターでは、完成されなければ、そもそも資産にすらなりません。そして、その製品が売れるかどうかという話もあります。
ということは、製品マスターではどれだけ収益を上げられる新製品を開発できたかが売上になります。

自社利用の場合、完成されなくても一旦資産にはなるのですが、未完成になってしまうと損失を出してしまいます。
ということで、これに関してもどれだけ費用を削減できるソフトウェアを開発できたかが売上ということになるでしょう。

というわけで結局エンジニアの売上は速く役に立つものを作るということになるわけですね。
なんて陳腐な結論。

ただ、自分の人件費がかさむことによって投資家やその他利害関係者がどのように思うのかは考えて開発できると投資家にいいように映るように自分はできたかもなぁと思えるので少し仕事のモチベが上がるかも？？くらいです。

まぁ何はともあれ速くいいものを作るというところを今まで通り意識するのが大事だということが結論です。
Laravelにおけるクラスとファサードの違い

Laravelにおける、クラスとファサードの違いをまとめた。

# クラス
属性（データ）とメソッド（動作）を持ち、オブジェクトの作成の元となるデータや振る舞いを定義する。オブジェクトは、クラスをインスタンス化することで実体化される。

# ファサード
クラスをインスタンス化しなくても、staticメソッドのように、メソッドを実行できるようにしてくれる機能。クラスにアクセスするためのインターフェース。

```class.php
// クラス使用
$classA = new ClassA;
$classA -> methodA();
```
```facade.php
// ファサード使用
FacadeClassA::methodA();
```
【アジャイル型でどんどん進めて行く！】仕事は4割の完成度で充分！

アジャイル型でどんどん開発を既に進めているエンジニアの方も多いと思いますが、開発に限らず、仕事は4割の完成度で良いから、どんどん周りを巻き込んでどんどん進めて行きましょう！

とにかく自分のところに来たボールは4割くらい仕事したあと、すぐに上司やチームの他のメンバーにパスを出しまくれば、スピードも速いし、結果的に高い完成度になることが多いです。

仕事の多くは、完全に自分一人で完結出来る事はなかなかありません。最終的には上司のレビューが必要になることも多いでしょう。

そんなときは4割くらい大まかな部分だけ仕上げて、すぐに、上司や他のメンバーにレビューをしておくと、方向性がズレる事も無く、良いアイディアをもらう事もできます。

雑務を他のメンバーに依頼すると嫌がられると思いますが、クリエイティブ系の仕事は比較的やりたがる人が多いので、レビューしていくと、
「ここは私やりましょうか？」
とか、
「前に似たような資料を作った事があるので、お送りします！」
など、どんどん助けてくれます。

チーム全体としても、みんなで仕事に取り組む事で、チームとしての経験値も高まるし、成果が上がった時にはチームみんなで喜びも分かち合えます。

逆に最悪なのが、完璧主義を目指して自分一人で抱え込み、納期直前で上司に提出してしまう事。結果としてスピードも遅くなるし、完成度も低い仕事になってしまいます。

スピードと多様性の時代、チームのメンバーの共同知で仕事をしていく事がますます求められてきますね。

ただ、「4割の完成度でいいから仕事」には重要なポイントが3つあります。

【ポイント1】とにかくクイックに最初のたたき台を作る。（スピード命）
【ポイント2】4割の中に重要なポイントは必ず入っている。（大事な的は外さない）
【ポイント3】協力してくれる他のメンバーに必ず感謝の気持ちを伝える。

4割の完成度なのに遅いし的外れでは、やはり仕事としてはマズいですよね。あとは、どんな仕事でも言える事ですが、特に一緒に仕事をしてくれる仲間への感謝は大事ですよね。

これからどんどんAIが進化して来れば、細かなデータを集めたり、体裁を整えたりするような仕事は一瞬で出来るようになります。

逆に、最初のアイディアや、チームの仲間とディスカッションしながら良い物を創造していく仕事は人間にしか出来ないと思います。

何に自分が集中すべきか、常に考えながら、楽しく仕事をしていきたいですね！

アジャイル型の手法は開発に限った話ではありません。
4割出来たら、あとは仲間と一緒にどんどん仕事は進めて行きましょう！！
Cloudflare で Origin ヘッダを Access-Control-Allow-Origin にオウム返し

[CORS](https://developer.mozilla.org/ja/docs/Web/HTTP/CORS) テスト用メモ

HTTP リクエストの [Origin](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Origin) ヘッダの内容をレスポンスの [Access-Control-Allow-Origin](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Access-Control-Allow-Origin) に鸚鵡返し。

[Transoform Rules](https://developers.cloudflare.com/rules/transform/) を使う
- [リクエスト](https://developers.cloudflare.com/ruleset-engine/rules-language/fields/#http-request-header-fields)に Origin ヘッダがあると
- レスポンスに Access-Control-Allow-Origin つける
- 中身はコピる

ダッシュボード
![Screenshot 2023-08-09 at 10.05.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218045/c2931d0f-72b4-e987-728a-2c5f78e32ff6.png)

API
```
$ rsid=`curl -s -X GET -H "Content-Type: application/json" -H "X-Auth-Email: $EMAIL" -H  "X-Auth-Key: $API_KEY" "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/rulesets" |jq -r '.result[] |select(.phase == "http_response_headers_transform")|.id'`;curl -s -X GET -H "Content-Type: application/json" -H "X-Auth-Email: $EMAIL" -H  "X-Auth-Key: $API_KEY" "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/rulesets/$rsid"|jq '.result.rules[]|select (.description|contains("allow"))'
{
  "id": "fd4a47a184c24ee29faa64b916bd589f",
  "version": "7",
  "action": "rewrite",
  "expression": "any(lower(http.request.headers.names[*])[*] matches \"^origin$\")\n",
  "description": "allow origin (cross origin resource sharing)",
  "last_updated": "2023-08-09T01:03:15.029903Z",
  "ref": "fd4a47a184c24ee29faa64b916bd589f",
  "enabled": true,
  "action_parameters": {
    "headers": {
      "Access-Control-Allow-Origin": {
        "operation": "set",
        "expression": "http.request.headers[\"origin\"][0]"
      }
    }
  }
}
```

テスト

```
$ curl https://somehost/ -H "Origin: https://www.example.com" -svo /dev/null 2>&1 |grep -i origin
* h2 [origin: https://www.example.com]
> Origin: https://www.example.com
< access-control-allow-origin: https://www.example.com
```
NeosVR コンパイラ その2

# 概要
NeosVRのオブジェクトを外部で生成するコンパイラを開発した。
俺コードから、生成します。

# 俺コード仕様

- new
コンポーネントを生成します。
例
new FrooxEngine.StaticTexture2D

コンポーネントStaticTexture2Dを生成

- 代入
プロパティを設定します。
例
FrooxEngine.StaticTexture2D.URL.Data = "https://apod.nasa.gov/apod/image/2308/GianniTumino_Moon_Rays_JPG_LOGO_1024pix.jpg"

urlを設定

- add
オブジェクトに、追加します。
例
add FrooxEngine.MeshRenderer
コンポーネントMeshRendererを追加します。

# サンプル1

画像を取得して、テクスチャーにして、四角に貼り付け、描画します。

```
new FrooxEngine.StaticTexture2D
new FrooxEngine.UnlitMaterial
new FrooxEngine.MeshRenderer
new FrooxEngine.QuadMesh
FrooxEngine.StaticTexture2D.URL.Data = "https://apod.nasa.gov/apod/image/2308/GianniTumino_Moon_Rays_JPG_LOGO_1024pix.jpg"
FrooxEngine.UnlitMaterial.Texture.Data = FrooxEngine.StaticTexture2D.ID
FrooxEngine.MeshRenderer.Materials.Data.Data = FrooxEngine.UnlitMaterial.ID
FrooxEngine.MeshRenderer.Mesh.Data = FrooxEngine.QuadMesh.ID
add FrooxEngine.StaticTexture2D
add FrooxEngine.UnlitMaterial
add FrooxEngine.MeshRenderer
add FrooxEngine.QuadMesh

```

以上。
Mac版WordでF7キーによるカタカナ変換を復活させる方法（Mac OS 13.5）

こんにちは。藤澤です。
ローカルパソコンに溜め込んだ小ネタを紹介してゆく企画の第3弾です。

漢字入力をしている際に外来語などカタカナ表記の単語を手早く変換する際にF7キー押下による変換があります。私のMacでもF7キーによるカタカナ変換ができるので愛用しているのですが…。

**「Mac版Wordでは他の機能が割り当てられている」**

もぅ…迷惑です。
余計な機能はいらないので安定的に動作することに注力してもらいたい…という愚痴はおいておいて、このショートカットを無効化してカタカナ変換の機能を復活させる方法のご紹介です。

ステップは大きく２つです。

1) システム設定の調整
2) Wordのショートカット設定

まず一つ目の「システム環境設定の調整」ですが、これはそもそもファンクションキーが有効になっているかどうかの確認です。

### STEP1： システム設定の調整

はじめに「システム設定」を開き、左側のメニューから「キーボード」を選択します。
次に「キーボードショートカット」ボタンをクリックすると、ファンクションキーを有効化する設定が表示されます。
これをONにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325718/83e567b6-7bd7-b34b-f248-732b3fe1a3f9.png)

### STEP2： Wordのショートカット設定

Wordの「ツール」メニューから「ショートカットキーのユーザー設定...」を開きます。
「ショートカットキーの割り当て」ダイアログが表示されるので、左上の「分類」で「すべてのコマンド」を選択の上、右上の「コマンド」にある虫眼鏡のところに「ToolsProofing」と入力します。コマンドが絞り込まれるので「ToolsProofing」を選択し、「ショートカットキーの設定」にある「現在のキー」から「F7」を選択して「削除」ボタンをクリックします。あとは「OK」ボタンでダイアログを閉じて出来上がりです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325718/9c0743d4-952e-9623-04d7-18466722982e.png)
いやぁ〜〜快適。快適。
Prometheus OperatorのServiceMonitor / PodMonitor検出ルール

Prometheus Operatorを利用してPrometheusをインストールした場合、メトリクスのエンドポイントを簡単に追加する方法として、`kind: PodMonitor`や`kind: ServiceMonitor`を使う方法がある。
ただ、このリソースを適当に作ってもPrometheus側で認識してくれない。
これをPrometheusで認識させる方法の備忘録。

## Prometheusへの認識方法
`PodMonitor`や`ServiceMonitor`を作る際、ラベルを設定する必要がある。
```yaml
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
  name: vmware-mysql-instances
  namespace: prometheus
  labels:
    release: prometheus-operator　　★コレ！！
```
このラベルはどういうものを設定すればいいかというと、`Prometheus`オブジェクト内に定義されている。
```sh
$ kubectl get prometheus -n prometheus
NAME                                    VERSION   DESIRED   READY   RECONCILED   AVAILABLE   AGE
prometheus-operator-kube-p-prometheus   v2.45.0   1         1       True         True        38m
```
これの中身を見ると、以下のような項目がある。
```yaml
$ kubectl get prometheus -n prometheus -o yaml prometheus-operator-kube-p-prometheus
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
：（省略）
  podMonitorSelector:
    matchLabels:
      release: prometheus-operator
：（省略）
  serviceMonitorSelector:
    matchLabels:
      release: prometheus-operator
```
`spec.podMonitorSelector.matchLabels`や`spec.serviceMonitorSelector.matchLabels`に定義があり、Prometheusはこれとマッチした`PodMonitor`や`ServiceMonitor`のみ認識するので、このラベルを設定する。

上手く適用出来た場合は、PrometheusのUIでService Discoveryを確認すると、反映されていることが分かる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/14b7af17-0cb2-ed5b-4169-14f7ec0d9d0f.png)
HTMLの`<details>`要素でJavaScriptなしのトグル表示を綺麗に実現する方法

ハイサイ！オースティンやいびーん！

# 概要

HTMLの`<details>`要素を使うことによって簡単に見え隠れする文章を実装することができます。

# `<details>`要素の使い方

早速例に入りたいのですが、`<details>`の他に、その中に入る`<summary>`要素もセットで必須になります。

`<summary>`は、`<details>`が開かれていない時にも常に見えている要素です。

以下の例を見ましょう。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="VwVOvao" data-user="nklvbxkl-the-flexboxer" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/nklvbxkl-the-flexboxer/pen/VwVOvao">
  Detailsれい</a> by メイヤーオーステイン (<a href="https://codepen.io/nklvbxkl-the-flexboxer">@nklvbxkl-the-flexboxer</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

`<h3>`をクリックするだけで開かれますし、また閉じられます。JavaScriptを一切使わずに済むので便利です。

# `<details>`をJavaScriptで開く方法

他の何らかのロジックがあってJavaScriptで`<details>`を開閉したいときは以下のように、`open`の属性を操れば良いです。

```javascript
const details = document.querySelector('details');

setInterval(() => details.toggleAttribute('open'), 2000);
```

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="zYMQvNm" data-user="nklvbxkl-the-flexboxer" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/nklvbxkl-the-flexboxer/pen/zYMQvNm">
  Untitled</a> by メイヤーオーステイン (<a href="https://codepen.io/nklvbxkl-the-flexboxer">@nklvbxkl-the-flexboxer</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

# `toggle`イベントを受信して他のロジックに繋ぐ

さらに、`<details>`の開閉のたびに｀toggle`というイベントが配信されます。

これを受信すれば、他のロジックを引き起こすことも可能です。

```javascript
const details = document.querySelector('details');
const statusP = document.querySelector('#status');

setInterval(() => details.toggleAttribute('open'), 2000);

details.addEventListener('toggle', () => {
  const isOpen = details.open;
  statusP.innerText = isOpen ? 'Open' : 'Closed';
});
```

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="YzRbyVz" data-user="nklvbxkl-the-flexboxer" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/nklvbxkl-the-flexboxer/pen/YzRbyVz">
  Details toggle example</a> by メイヤーオーステイン (<a href="https://codepen.io/nklvbxkl-the-flexboxer">@nklvbxkl-the-flexboxer</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

# まとめ

以上、簡単なHTMLのご紹介でしたが、いかがでしょうか？

`<details>`要素を使うことにより、自分が書いている複雑なロジックを少しでもスッキリさせられたらいいなと思います！

JavaScript依存症の昨今、HTMLだけでもできること、ネイティブでできることの大切さを改めて実感できたらいいなと思います。
Next.jsのApp RouterでStripeのWebhookイベントを処理するREST APIを作成する方法

Next.jsでは、リクエストBodyを処理しやすい形に内部で事前処理されます。

そのため、Stripe WebhookのAPIを実装するには、すこし設定作業が必要でした。

```diff_typescript
import Stripe from 'stripe'
+import {buffer} from 'micro'

const endpointSecret = 'whsec_xxxxxx'
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
  apiVersion: '2020-08-27'
})

+export const config = {
+    api: {
+        bodyParser: false
+    }
+}
export default async function handler(
  request,
  response
) {
  const sig = request.headers['stripe-signature'];
+  const buf = await buffer(request)

  let event;
  try {
    if (!sig) throw new Error("No signature provided")
    event = stripe.webhooks.constructEvent(buf, sig, endpointSecret);
  } catch (e) {
    const err = e instanceof Error ? e : new Error("Bad Request")
    console.log(err)
    response.status(400).send(`Webhook Error: ${err.message}`);
    return;
  }

  console.log(event)

  return response.status(200).end()
}
```

こちらの詳細については、以下の記事をご覧ください。

https://qiita.com/hideokamoto/items/7c0e89778e245e35d0ff

## Next.js(version 13)から追加された「App Router」で、Stripe Webhook APIを作成する

Next.jsで新しく追加された「App Router」では、ディレクトリ構造を含めて様々な変更が行われました。

Stripe Webhookを処理するAPIを作る場合も、コードの書き方が変わります。

**app/api/webhook/route.ts**

```typescript
import { NextResponse } from "next/server";
import Stripe from "stripe";

const stripe = new Stripe(process.env.STRIPE_SECRET_API_KEY as string, {
  apiVersion: '2022-11-15'
})

export async function POST(request: Request) {
  const signature = request.headers.get("stripe-signature");
  if (!signature) {
    return NextResponse.json({
      message: 'Bad request'
    }, {
      status: 400
    }) 
  }
  try {
    const body = await request.arrayBuffer();
    const event = stripe.webhooks.constructEvent(
      Buffer.from(body),
      signature,
      process.env.STRIPE_WEBHOOK_SECRET as string
    );
    console.log({
      type: event.type,
      id: event.id,
    })
    return NextResponse.json({
      message: `Hello Stripe webhook!`
    });
  } catch (err) {
    const errorMessage = `⚠️  Webhook signature verification failed. ${(err as Error).message}`
    console.log(errorMessage);
    return new Response(errorMessage, {
      status: 400
    })
  }
}
```

Astroと書き方が似ていますが、環境変数の取得方法やレスポンスのフォーマットが異なる点に注意しましょう。

## 参考資料など

https://stripe.com/docs/webhooks/quickstart
ダッシュボードからだと規定のビューが反映されないのでスクリプトを追加

# ダッシュボードのクイックパーツ

## クイックパーツからページ遷移した時に規定のビューで表示されない
クイックパーツのページを並べて、そのボタンを押してページ遷移した時にカレンダーを規定にしていても一覧で表示される。  
リンクが`href="/items/5/index"`になっていたので、一覧で表示されるみたい。 
 ダッシュボードではない、通常のテーブル一覧の画面を見てみると`href="/items/5/calendar"`となっていて規定のビューが反映されて、カレンダーで表示されるみたい。  

## 規定のビューを設定し直してみる
テーブルの管理から、ビューの規定を一度、一覧に戻して更新してから、カレンダーに戻してみる。 
ダッシュボードのリンクは`href="/items/5/index"`のままでカレンダーには変わらないよう。  
なので一覧で表示された。規定のビューは反映されないみたい。

## スクリプトでリンクを書き換える

このようなスクリプトを追加しました。
`href="/items/5/index"`を`href="/items/5/calendar"`に書き換えることで、カレンダーの状態で開くことができた！！！
html、jsとか全然やった事ないので、めちゃ苦労した。。。。。。。

```
$(function(){
    var atag = document.getElementById('DashboardPart_1').getElementsByTagName('a');
    for (var i = 0; atag.length; i++){
        if (typeof atag[i] == 'undefined') {
            console.log('undefined' + i);
            break;
        } else {
            if (atag[i].getAttribute('href') === '/items/5/index'){
                atag[i].setAttribute('href', '/items/5/calendar');
            }
        }
    }
});
```

`if (typeof atag[i] == 'undefined')`としている所は、プロパティが未定義でエラーとなるので入れています。

参考
https://qiita.com/husqy/items/5e617210bfa75606c0fb

## プリザンターは頻繁に更新されててすごい！
バージョンアップが頻繁にされてて色々機能追加されるし、合わせて公式のユーザーマニュアルも更新される！
https://pleasanter.org/manual
他にも、プリザンターの会社の方々？が、Qiitaとかで機能の使い方を解説されてる！
スッキリわかるJava入門 第３版を読んでみて- part７ -オブジェクト指向をはじめよう

# はじめに
こんにちは(・ω・）ﾉ
今回はオブジェクト指向について学びました！
## 第７章　オブジェクト指向をはじめよう
### 1.オブジェクト指向を学ぶ理由
　ソースコードが長く複雑になりすぎて、開発者自身が内容を把握できなくなる
　⇨人間自身がプログラム開発のボトルネックとなる
※ __ボトルネック__ ...業務の停滞や生産性の低下を招いている工程・箇所

__オブジェクト指向プログラミング__
　大規模なプログラムもラクに開発できる

:sparkles:オブジェクト指向の目的
　「人間が把握しきれない複雑さ」を克服するため

:sparkles:学習意識の切り替え
　基本文法とオブジェクト指向とでは、そもそもの学び方もまったく違う

　___オブジェクト指向の学習においては、
　　概念を理解することやイメージすることをより重要視する必要がある___

オブジェクト指向という考え方を学ぶ
　⇨ぼんやりとした理解でいい、繰り返し、少しずつ理解を深める

### 2.オブジェクト指向の定義と効果
　オブジェクト指向とは何か...？

:sparkles:オブジェクト指向の定義
　ソフトウェアを開発するときに用いる部品化の考え方

オブジェクト指向の目的：
　人間が把握しやすいプログラム開発を実現する
メリット：
・プログラムの変更が容易になる（柔軟性・保守性の向上）
・プログラムの一部を簡単に転用できる（再利用性の向上）
↑もっと簡単にすると...

:sparkles:オブジェクト指向を用いるメリット
　__「ラクして、楽しく、良いもの」をつくれる__ 

### 3.オブジェクト指向の全体像と本質
　:question: なぜオブジェクト指向を導入することで「ラクして、良いもの」が実現できるか

そもそもなぜプログラムを作るのか？
⇨現実世界における何らかの活動を自動化するため

従来のプログラミング...手続型プログラミング
コンピュータの動きの手順を考え、プログラムの先頭から順番に命令として記述する方法

:sparkles:オブジェクト指向による部品化のルール
　現実世界に出てくる登場人物の単位で、プログラムをクラスに分割する

「〜指向」　＝　「〜を大切にした」、「〜を中心に添えた」という意味

　:question: なぜオブジェクト指向を導入することで「ラクして、良いもの」が実現できるか
　⇨ ___私たち人間が慣れ親しみ、よく把握している現実世界を
　　　　　　マネして作られたプログラムもまた、
　　　　　　　　　　私たち人間にとって把握しやすいものだから___

:sparkles:オブジェクト指向の本質
　現実世界の登場人物とその振る舞いを、コンピュータ内の仮想世界で再現する

### 4.オブジェクトと責務
:sparkles:責務の割り当て
開発者はそれぞれの部品（クラス）に
　「責務（役割や責任）」をプログラムとして書き込む

オブジェクトは「属性」と「操作」を持っている
・「属性」...情報を覚えておく箱
・「操作」...行う行動や動作の箱

### 5.オブジェクト指向の３大機能
__オブジェクト指向言語__（javaなど）
　オブジェクト指向の考え方に沿ってプログラムを作りやすい配慮がされている

オブジェクトの３大機能
__継承__
__多様性__
__カプセル化__

詳しくは今後学んでいくため、今はこの３つがあるという認識でOK

## まとめ
今回学んだオブジェクト指向は考え方を学ぶためイメージを重視し、これからの章を繰り返し学んでいくことで理解を少しずつ深めていこうと思います。
そのはじめとしてオブジェクト指向はソフトウェア開発の際に用いる部品化の考え方ということを学びました。
オブジェクト指向の本質として現実世界における「登場人物のふるまい」を仮想世界の「オブジェクトのふるまい」として再現しているということもあわせて学びました。
今回はなぜと思うことを解決しながら学習できたので理解はしやすかったと感じました。

今回もありがとうございました！
ではまた〜　＊˙︶˙＊)ﾉ"
【Python】メソッド一覧

# 【Python】メソッド一覧

学んだメソッドをまとめてみた。

---

|メソッド    | 内容                |
|----------|--------------------------|
|split(sep)  |文字列をsepで分割したリストを返す                    |
|join(list)      |引数のリストを連結した文字列を返す               |
|replace(old, new)|文字列の中のoldで表される文字列をnewで置き換えた文字列を返す|
|strip()         |文字列の先頭を末尾の空白文字を削除した文字列を返す|
|append()          |1つのリストの要素追加                                      |
|extend([ , ])    |複数のリストの要素追加。リスト[  ]で指定               |
|remove()         |指定した内容の要素の削除                      |
|clear()          |要素の全削除　　　　　　　　　　　　　　　　　　　　|
|index()          |リストに特定の要素があるか確認                       |
|sorted()         |小さい順にリストの要素の並び替え(1回限りの並び替え)           |
|sort()           |小さい順にリストの要素の並び替え(完全に並び替える)            |
|copy()           |リストの要素をコピーする                     |
|update({'': '','':''})  |辞書に複数の要素追加                         |
|get()            |辞書から要素を取り出す(キーが無くてもエラーが出ないようにする)               |
|add()            |集合に要素を追加                             |
|keys()           |辞書のキーのビューを返す　　　　　　　　　　|
|values()         |辞書の値のビューを返す                     |
|items()          |(キー、値)のタプルのビューを返す              |
NeosVR コンパイラ

# 概要

NeosVRのオブジェクトを外部で生成するコンパイラを開発した。
NeosVRのユーザーの皆さんには、破綻していないことを実証願いたい。

# 実行確認の手順。
- 環境は、windows10
- NeosVRは、Streemじゃない方
- 以下のページで生成されたjsonを、メモ帳で「nasa.json」で保存する。

こちらがコンパイラ

https://embed.plnkr.co/plunk/ZVGGbqmF14ZT5z0r

- NeosVRを起動して、セッションに入る。
- ファイルブラウザを開いて、「nasa.json」をダブルクリックする。
- 以下の画像が表示されれば、成功です。

![2023-08-09 00.00.42.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/e2648119-ff87-1969-7a1e-2eb9887eeeea.jpeg)


以上。
私でもできる！illumi-packetのビルド

:::note warn
ここで言う「私でもできる！」は筆者でもできるという意味であり、これを読んだ全ての人ができるという意味ではないので注意
:::

:::note warn
あくまでこれは備忘録的な記事なので「この通りやったけど動かないんだけど！？」みたいなクレームを言われても困ります
:::

## やりたいこと

[illumi-packet](https://github.com/souring001/illumi-packet)というLEDでパケット可視化されるLANケーブルのソフトウェアを動かしたいけど、依存パッケージの仕様変更でビルドができないのでなんとかしたい

## 前提環境

- Raspberry Pi 3B
- Ubuntu 22.04.2 LTS

## おことわり

- ローカル環境をできるだけ汚したくないのでDockerで仮想化します
- 実際に光らせるLEDが無いので動くかは知りません

## やったこと

### illumipacketのソースコードを用意

[依存パッケージ関係を全部なんとかしてあるいい感じ™なフォーク](https://github.com/yuukami256/illumi-packet.git)があるのでそれを使う

```shell
git clone https://github.com/yuukami256/illumi-packet.git
cd illumi-packet
```

### goのコンテナを作成

```shell
docker run -v $(pwd):/illumi-packet --rm -it golang bash
cd /illumi-packet
```

RasPi3Bだとスペックに余裕がなさすぎてつらい

### libcap, sconsのインストール

```shell
apt update
apt install libpcap-dev scons
```

### rpi_ws281xのインストール

```shell
git clone https://github.com/jgarff/rpi_ws281x.git
cd rpi_ws281x

scons

cp -ai ./ws2811.h ./rpihw.h ./pwm.h /usr/local/include/
cp -ai ./libws2811.a /usr/local/lib/
```

### illumi-packetのビルド

```shell
go build illumi-packet.go
```

めっちゃ待つ

### 完成

カレントディレクトリに`illumi-packet`という実行ファイルがあるのでそれを実行すれば多分動く

## 余談

- 光らせるLEDがないのになんでビルドするのかと訊かれたら困る（実際は私がillumi-packetを動かしたいわけでなかったので）
MATLAB：グラフのデフォルト設定の変更

## 概要

- 論文や技術文書用に，MATLABのグラフのデフォルト設定を変更する．

## 設定一覧の取得

- 以下のコマンドでデフォルト設定の一覧を取得できる．
    - 参考：https://jp.mathworks.com/help/matlab/ref/get_ja_JP.html#d124e524661

```matlab
settings = get(0,'Factory')
fields = fieldnames(settings)
```

- `fields`にはプロパティ名の一覧が代入される．

```csvs
{'factoryAnimatedlineAlignVertexCenters'                      }
{'factoryAnimatedlineBusyAction'                              }
{'factoryAnimatedlineButtonDownFcn'                           }
{'factoryAnimatedlineClipping'                                }
{'factoryAnimatedlineColor'                                   }
{'factoryAnimatedlineCreateFcn'                               }
{'factoryAnimatedlineDeleteFcn'                               }
以下，続く
```

## デフォルト設定の変更

- `fields`に代入されたプロパティ名のプレフィックス`factory`を`default`に変更して，所望の設定をセットする．

```matlab
font_face = "times";
set(gcf,"defaultAxesFontName", font_face)
set(gcf,"defaultBubblelegendFontName", font_face)
set(gcf,"defaultColorbarFontName", font_face)
set(gcf,"defaultConstantlineFontName", font_face)
set(gcf,"defaultGeoaxesFontName", font_face)
set(gcf,"defaultGraphplotEdgeFontName", font_face)
set(gcf,"defaultGraphplotNodeFontName", font_face)
set(gcf,"defaultLegendFontName", font_face)
set(gcf,"defaultPolaraxesFontName", font_face)
set(gcf,"defaultRootFixedWidthFontName", font_face)
set(gcf,"defaultTextFontName", font_face)
set(gcf,"defaultTextarrowshapeFontName", font_face)
set(gcf,"defaultTextboxshapeFontName", font_face)
set(gcf,"defaultUibuttongroupFontName", font_face)
set(gcf,"defaultUicontrolFontName", font_face)
set(gcf,"defaultUipanelFontName", font_face)
set(gcf,"defaultUitableFontName", font_face)

font_size = 4;
set(gcf,"defaultAxesFontSize", font_size)
set(gcf,"defaultBubblelegendFontSize", font_size)
set(gcf,"defaultColorbarFontSize", font_size)
set(gcf,"defaultConstantlineFontSize", font_size)
set(gcf,"defaultGeoaxesFontSize", font_size)
set(gcf,"defaultGraphplotEdgeFontSize", font_size)
set(gcf,"defaultGraphplotNodeFontSize", font_size)
set(gcf,"defaultLegendFontSize", font_size)
set(gcf,"defaultPolaraxesFontSize", font_size)
set(gcf,"defaultTextFontSize", font_size)
set(gcf,"defaultTextarrowshapeFontSize", font_size)
set(gcf,"defaultTextboxshapeFontSize", font_size)
set(gcf,"defaultUibuttongroupFontSize", font_size)
set(gcf,"defaultUicontrolFontSize", font_size)
set(gcf,"defaultUipanelFontSize", font_size)
set(gcf,"defaultUitableFontSize", font_size)

set(gcf,"defaultAxesTickLabelInterpreter", "latex")
set(gcf,"defaultBubblelegendInterpreter", "latex")
set(gcf,"defaultColorbarTickLabelInterpreter", "latex")
set(gcf,"defaultConstantlineInterpreter", "latex")
set(gcf,"defaultGraphplotInterpreter", "latex")
set(gcf,"defaultLegendInterpreter", "latex")
set(gcf,"defaultPolaraxesTickLabelInterpreter", "latex")
set(gcf,"defaultTextInterpreter", "latex")
set(gcf,"defaultTextarrowshapeInterpreter", "latex")
set(gcf,"defaultTextboxshapeInterpreter", "latex")
```
- ここでは，以下の設定をしてます．
    - フォントをTimes New Romanに変更
    - フォントサイズを4ptに変更
    - すべてのテキストインタラプタでLaTeXを有効化
罫線素片(の呼び名)で若干モヤっとした話


かなり久々に、罫線素片を扱う機会があった。
で、モヤっとした感覚を思い出したので書き捨てる。

まともな解説などは、Wikipedia にも、Qiita にも
あるので、そちらをどうぞ。

## 罫線素片

罫線素片とは、tree コマンドでお馴染の線の事。


```
root
├ node01
│ └ node011
└ node02
```

↑コレの`└`とか、`│`とか。

## 名称

で、JIS X 0213 での名称が、、、

ex) `└`



|言語 |名称 |
|:-- | :-- |
|英語|BOX DRAWINGS LIGHT UP AND RIGHT|
|日本語|細線素片左下|


英語はマンマ、上と右。線がどちらを向いているかで直感的。

日本語は、左下。
tree コマンドでしかお目に掛ったことが無い人(俺)だと、一瞬躊躇う。

何のことはない、そもそもの目的が表組み(とか)目的の枠なんだから、
そこからすれば、妥当な名前。


```
┌┬┐
├┼┤
└┴┘
```

左下の罫線は"左下"だし、中央の罫線は、"中央"。

ただね、視点が違うから当然なんだけど、英語と日本語で逆っぽいのがモヤるのよ。

で、この日本語名称、web では確定ソースに遡れない。それもモヤる[^1]。

[^1]: もしかして、Wikipedia とかの編集者が独自に付けた？ そんなことは無いと思うが。

## IME

さらにモヤるのが、Microsoft IME とかでの、変換用読み。[^2]

|罫線素片| IME |
|:--|:--|
|`├` (細線素片左) | たてみぎ |

IME で"たてみぎ"と入力したら変換出来るわけだけど、こちらは英語名称に近い、、、

`└`は"ひだりした"で日本語名称に従ってるのに、、、


モヤる。

[^2]: Mac では、"けいせん"のみで変換出来て、種類別の読みは用意されていないっぽい。
Microsoft Dataverse でリレーションシップを持つ列をデータフローでインポートする


# はじめに

Microsoft Dataverse を利用する際、データフローを利用してデータをインポートすることができます。
既に Excel などでデータがある場合、こちらの機能でデータをインポートするのが楽だと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/63d1ffb6-96ec-eb76-9508-d8d05825f59e.png)

この際、元データでリレーションシップも持たせている場合、インポート時に考慮が必要なため、備忘のため手順を整理したいと思います。

# 手順

まず、以下に記載がある通り、テーブルにキーフィールドを設定する必要があります。

https://learn.microsoft.com/ja-jp/power-query/dataflows/relationships-in-standard-dataflows

こちら、何を言っているかというと、実は、Dataverse では、既定で、テーブル名と同じ一意識別子の列が作成されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/0465f93c-6f95-bda8-e320-e147008d4154.png)

基本的にはこちらをそのまま使うことが多いですが、リレーションシップを持つ列をデータフローでインポートする際は、明示的にキーを指定する必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/e0ff5b93-5163-45bd-ab32-d5c726a38101.png)

上記を踏まえ、今回は、以下のような、ユーザー、部署の Excel をインポートしてみたいと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/1b6237c3-e20a-0536-2170-583ba4a0bdc8.png)

まず、以下のような部署、ユーザーテーブルを作成し、また、キーの設定をします。

|列名  |備考|  
|---|---|
|部署名  ||  
|部署ID  |キー| 


|列名  |備考|  
|---|---|
|ユーザー名  ||  
|ユーザーID  |キー| 
|部署  |検索列 (部署テーブル)| 

あとは、データフローでマッピングしてインポートします。まずは、部署の方からインポートします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/f50c6717-6b62-2f11-251b-36f28865c461.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/9d4be3cb-305f-c355-c4b9-c1a759e11e84.png)

無事にインポートできました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/1b5892d7-6fcb-fe86-b57d-bd77e174e316.png)

次にユーザー側です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/7d730a3b-558e-0971-611c-ccf28a93c2e2.png)

キーを設定しているため、部署の方もマッピング候補に出ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/dd24965c-cc15-6b2a-a611-9fa04b64c885.png)

無事にインポートできました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/059f718b-1fb1-b72e-3a00-4791e4eecdcc.png)

# まとめ

Microsoft Dataverse でリレーションシップを持つ列をデータフローでインポートする方法について紹介しました。

Power Automate でもインポートできますが、こちらの方が簡単だと思いますし、インポート元がデータベースの場合は自動更新できますし便利だと思います。

既定の一意識別子やキーの設定について、Dataverse 特有なところもあるので参考にしていただけると幸いです。
私でもできる！ラズパイでIPマスカレード！！

:::note warn
ここで言う「私でもできる！」は筆者でもできるという意味であり、これを読んだ全ての人ができるという意味ではないので注意
:::

:::note warn
あくまでこれは備忘録的な記事なので「この通りやったけど動かないんだけど！？」みたいなクレームを言われても困ります
:::

## やりたいこと

RaspberryPiでIPマスカレードをしてイーサネット側からの通信をWiFiに流したい

## 環境

- RaspberryPi 4B 4GB
- Ubuntu 22.04.2 LTS

## やったこと

### IPアドレスを振る

`/etc/netplan/99-manual.yaml`を以下のように編集

```yaml:/etc/netplan/99-manual.yaml
network:
  version: 2
  ethernets:
    eth0:
      dhcp4: false
      addresses: [192.168.24.254/24]
  wifis:
    wlan0:
      dhcp4: true
      access-points:
        "SSID":
          password: "password"
```

### IPフォワードの有効化

`/etc/default/ufw`の19行目を以下のように編集

```:/etc/default/ufw
DEFAULT_FORWARD_POLICY="ACCEPT"
```

`/etc/ufw/sysctl.conf`の10行目のコメントアウトを削除

```:/etc/ufw/sysctl.conf
net/ipv4/ip_forward=1
```

### IPマスカレードの設定

`/etc/ufw/before.rules`の末尾に以下を追加

```:/etc/ufw/before.rules
# IP masquerade
*nat
-F
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 192.168.24.0/24 -o wlan0 -j MASQUERADE

COMMIT
```

### 設定の有効化

以下のコマンドを実行するとufwが有効になり、デフォルトでは全てのポートが閉じられるので、SSH等を用いている場合は`sudo ufw allow [port]`で適切に設定する

```shell
sudo ufw enable
```

## おまけ

### DNSはどうするの

DHCPサーバでDNSを上位のネットワークのDNSにするか、一台一台職人の手で丹精込めて丁寧に上位ネットワークのDNSを設定してね

### デフォルトゲートウェイはどうするの

イーサネット側のネットワーク（ここでは`192.168.24.0/24`）の機器のデフォルトゲートウェイはRaspberryPiのIPアドレス（ここでは`192.168.24.254`）にしてね
おそらくこれもDHCPサーバの設定でなんとかなるよ