OmniAICreator/Qiita-1.07M huggingface dataset:
day20 『マーフィーの法則』

## はじめに
　マーフィーの法則は多数の書籍が出版されています。この書籍に限らないと思います。しかし、人生の中で必ず遭遇する法則となります。

![マーフィーの法則 目次2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533414/23848fb5-5a97-259d-c36d-d072a5895bd1.png)


## ポイント
### マーフィー学
- 失敗する可能性があるものは、失敗する。


### 応用形
- ものが壊れる確率は、その価格に比例する。 
- 誰もが余計なことをする。
- マーフィーは楽観主義者だった。😁
- 起きてほしくないこと、ほどよく起こる。
- すべてのプラスにはマイナスがある。
- 危機に望むと、人は最悪の選択をする。

### エキスパート
- 英知とは、完璧の一歩手前で留まるタイミングを知っていることである。
- いろいろな専門家に相談してみれば、どんな意見でも正当化できる。（例、国の報告書のアンケート結果）
- エキスパートとは、小さなミスをひとつも犯さずに、決定的な間違いを犯せる人である。

### 上級エキスパート
- コンサルタントとは、クライアントに数字を尋ね、それを突き返す不思議な人である。

### 研究者
- 実験がうまくいく場合は何かおかしい。
- いったんおかしくなってしまった仕事は、良くしようとすればするほどおかしくなる。
- すべての偉大な発見は、間違いをきっかけとしている。
- バカの実験結果を再現できるのは、バカだけである。
- あなたの研究が革新的であればあるほど、理解されない。
- 最善の理論は、最善ゆえに良い理論ではない。
- 歴史は繰り返す。それが歴史の悪い面である。
- 科学は常に正しい。事実に惑わされてはならない。😁
- 結果が事前にわからない限り、研究予算は承認されない。
- 試験データと報告書は、発表日の前日にPC故障によって消える。

### コンピュータ学
- バックアップファイルが、まともに取られていることはない。
- 稼働中のプログラムは、既に時代遅れである。
- プログラムの価値は、出力用紙の重さに比例する。（国プロ）
- プログラムは、保守要員の能力を超えるまで複雑化する。
- もっとも致命的なエラーは、プログラムの製品化後６ヶ月を経過しないと発見されない。
- プログラムはメモリ量をギリギリまで使い切る。

## 書誌情報
- 書籍名：マーフィーの法則
- 著者：Arthur Bloch
- 出版社：アスキー
- ISBN：4-7561-0326-X

## 参考
-
【JavaScript】includes()の正しい使い方を理解する

# はじめに
業務で`includes()`の使い方について勘違いしていたため、正しい使い方を整理し、記事にまとめました。特に`includes()`を使う際の対象データ型（配列など）に関する理解を深めることができたので、同じように悩んでいる方の参考になれば幸いです。

:::note warn
***この記事は<font color="Red">個人的なアウトプット</font>を目的として作成したものです。そのため、誤った情報や不足している内容が含まれている可能性があります。もし間違いや気になる点がございましたら、ぜひご指摘いただけますと幸いです***。
:::

# includesとは

>`includes()` は `Array` インスタンスのメソッドで、特定の要素が配列に含まれているかどうかを `true` または `false` で返します。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/includes

`includes()`は特定の要素が配列に含まれているかどうかを確認できる便利なメソッドです。

例えば、次のように使用します。

```js
const fruits = ["apple", "banana", "cherry"];
console.log(fruits.includes("banana")); // true
console.log(fruits.includes("grape"));  // false

```
ただし、`includes()`は配列に対してのみ利用可能で、オブジェクトには直接使えません。この点を誤解していたため、今回はその解決方法についても共有します。


# 配列以外でのincludes()の使い方
私がやりたかったのは、`react-hook-form`の`watch`メソッドを使って取得したオブジェクト内に特定の文字列が含まれているかを確認する処理です。

しかし、includes()はオブジェクトには直接使用できません。そのため、オブジェクトの値を配列に変換する必要があります。ここで便利なのが、Object.values()です。

## Object.values()とincludes()を組み合わせる
`Object.values()`は、オブジェクトのすべての値を配列として取得するメソッドです。この配列に対して`includes()`を使用することで、オブジェクト内の特定の値を確認することができます。

以下は実装例です。


```App.tsx
import React from "react";
import { useForm } from "react-hook-form";

function App() {
  const { register, handleSubmit, watch } = useForm();
  const onSubmit = (data) => console.log(data);

  // フォームの値をリアルタイムで取得
  const formValues = watch();

  // オブジェクトの値を配列に変換
  const Textdata = Object.values(formValues);

  // 配列に特定の文字列が含まれているかをチェック
  if (Textdata.includes("おはよう")) {
    console.log("おはよう");
  }

  return (
    <>
      <div className="text-center mt-5">
        <form onSubmit={handleSubmit(onSubmit)}>
          <div>
            <input type="checkbox" value="おはよう" {...register("example1")} />
          </div>
          <div>
            <input type="checkbox" value="こんにちは" {...register("example2")} />
          </div>
          <div>
            <input type="checkbox" value="こんばんは" {...register("example3")} />
          </div>
        </form>
      </div>
    </>
  );
}

export default App;

```

***実行結果***
上記のコードを実行すると、以下のように挙動します。
1. チェックボックスをクリックすると、watchでフォーム値をリアルタイムに取得。
1. `Object.values()`で取得した値を配列に変換。
1. 指定した文字列が配列に含まれている場合、`console.log()`で出力。
この方法を使うことで、オブジェクト内の特定の値を動的に判定できます。


# 終わりに
`includes()`の使い方を振り返りました。`Object.values()`との組み合わせにより、柔軟に`includes()`を活用できるようになりました。

もし同じような場面に遭遇した場合、この記事が参考になれば幸いです！

# 参考

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/includes

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/values

https://magazine.techacademy.jp/magazine/23994
ROS2 Humble環境構築 #2 Turtlebot3編

## はじめに
TurtleBot3のGazeboシミュレーション環境をROS2 Humbleで構築する手順を解説します。公式マニュアルに基づきつつ、コマンドの解説を加えて詳しく説明しています。
この記事を読めば、Ubuntu 22.04 LTS上でTurtleBot3をシミュレーション環境で動かせるようになると思います。


## １．必要な環境
### 使用するソフトウェアとバージョン
- OS：Ubuntu 22.04 LTS
- ROS2のバージョン：Humble

## 2　パッケージのインストール
### 2.1 システムのアップデート
まずはパッケージをアップデートして最新にします。
`apt update`でリポジトリ情報を最新化し、`apt upgrade`でインストール済みのパッケージを更新します。
```bash
$ sudo apt update
$ sudo apt upgrade
```
### 2.2 Gazeboシミュレータのインストール
以下のコマンドでROS2関連のシミュレーションパッケージをインストールします。`gazebo-*`はGazeboの主要パッケージ一式をインストールします。



```bash
$ sudo apt install ros-humble-gazebo-*
```
### 2.3 シミュレーション関連パッケージのインストール
以下のコマンドでROS2関連のパッケージをインストールします。
- `cartographer`: SLAM (地図作成) 用のパッケージ
- `dynamixel-sdk`: Dynamixelモーター制御用SDK
- `turtlebot3-msgs`: TurtleBot3専用メッセージ定義
- `turtlebot3`: TurtleBot3の主要ライブラリ
```bash
$ sudo apt install ros-humble-cartographer
$ sudo apt install ros-humble-cartographer-ros
$ sudo apt install ros-humble-dynamixel-sdk
$ sudo apt install ros-humble-turtlebot3-msgs
$ sudo apt install ros-humble-turtlebot3
```

### 2.4 ワークスペースの作成とシミューレーション用レポジトリのクローン
シミューレーション環境を構築するために、専用のワークスペースを作成します。
```bash
$ mkdir -p ~/turtlebot3_ws/src
```
TurtleBot3のシミュレーション用リポジトリをクローンします。`--depth 1` は履歴の少ない軽量なクローンを作成するオプションなので無くても全く問題ないです。
```bash
$ git clone --depth 1 -b humble https://github.com/ROBOTIS-GIT/turtlebot3_simulations.git
```
クローン後、以下のコマンドでビルドを実行します。
- `colcon build` はROS2の標準ビルドツールです。
- `--symlink-install` によりシンボリックリンクを使用した軽量インストールが行われます。

```bashh
$ cd ~/turtlebot3_ws && colcon build --symlink-install

### 2.4 Turtlebot3モデルの設定
シミューレーションで使用するTurtlebot3のモデルを指定します。`burger`は軽量なTurtleBot3モデルの一つです。他に`waffle`や`waffle_pi`も選択可能です。
```bash
$ export TURTLEBOT3_MODEL=burger
$ ros2 launch turtlebot3_gazebo empty_world.launch.py
$ export TURTLEBOT3_MODEL=waffle
$ ros2 launch turtlebot3_gazebo turtlebot3_world.launch.py
```


```bash
$ echo 'export ROS_DOMAIN_ID=30 #TURTLEBOT3' >> ~/.bashrc
$ source ~/.bashrc
```



## 3. Gazeboシミューレーションの起動


### 3.1 空の世界で起動

以下のコマンドでGazeboを起動し、空のシミュレーション環境を立ち上げます。`empty_world.launch.py` は空のシミュレーション空間を生成します。

```bash
$ export TURTLEBOT3_MODEL=waffle
$ ros2 launch turtlebot3_gazebo empty_world.launch.py
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3925972/a7507ecd-47e8-4f27-f9ef-1ada24da5150.png)
拡大すると`waffle`を見ることができます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3925972/b35b4190-2ab6-4ffc-b293-66cddde6022b.png)


### 3.2 デフォルトのTurtlebot3環境で起動
以下のコマンドでTurtleBot3専用のワールドを起動します。`turtlebot3_world.launch.py` はTurtleBot3用に構築されたマップ上でシミュレーションを行います。
青い円はLidarが測定されているエリアを表しています。
```bash
$ export TURTLEBOT3_MODEL=waffle
$ ros2 launch turtlebot3_gazebo turtlebot3_world.launch.py
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3925972/4d79fc1b-a5f3-c856-3a37-c15c752ce5ad.png)
先ほどと同様に拡大するとロボットを見ることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3925972/da15f627-7e53-b70e-9949-3ecd01f69c4b.png)


# おわりに
`Turtlebot3`を無事起動できるようになったので、次はナビゲーションに取り組みたいと思います。

## 参考サイト
https://qiita.com/Futo_Horio/items/2e78b3d160a0026d180c

https://emanual.robotis.com/docs/en/platform/turtlebot3/simulation/
copilot.vim 導入によって打たなくてよくなった文字数をカウントする

# ストーリー
「はぁ？効果測定？そんなの効果あるに決まってるだろ？」

というわけでまぁ効果があるのか測定しろとのことなので、とりあえず github copilot を導入したことによって打たなくてよくなったキータイプの回数を数えてみることにしました。[^1]

# やりたいこと
私は copilot.vim で github copilot を使ってます。
とりあえず tab キーを押して補完を採用したときに copilot が自分の代わりに打ってくれた文字列をファイルに１か月くらいどんどん貯めていけば、後で `wc` コマンドで文字数カウントできそうですね。

下記の方法は vim-9.0.0749 で動作確認しました。neovim とかは違うのかな。わかんない

# copilot.vim を編集

```bash
vim ~/.vim/pack/github/start/copilot.vim/autoload/copilot.vim
```

まずはファイル末尾に下記の function を新規追加します。
```vim
" Function to append Copilot completions to a log file
function! Copilot_AppendCompletion(completion)
  let l:logfile = expand("~/.copilot_completions.log")
  call writefile([a:completion], l:logfile, "a")
endfunction
```

次に、下記の場所に

```vim
    " HERE -------------------------------
    call Copilot_AppendCompletion(text)
    " HERE -------------------------------
```
という行を１行追加します。

```vim
function! copilot#Accept(...) abort
  let s = copilot#GetDisplayedSuggestion()
  if !empty(s.text)
    unlet! b:_copilot
    let text = ''
    if a:0 > 1
      let text = substitute(matchstr(s.text, "\n*" . '\%(' . a:2 .'\)'), "\n*$", '', '')
    endif
    if empty(text)
      let text = s.text
    endif

    call copilot#Request('notifyAccepted', {'uuid': s.uuid, 'acceptedLength': copilot#doc#UTF16Width(text)})
    call s:ClearPreview()
    let s:suggestion_text = text

    " HERE -------------------------------
    call Copilot_AppendCompletion(text)
    " HERE -------------------------------

    return repeat("\<Left>\<Del>", s.outdentSize) . repeat("\<Del>", s.deleteSize) .
            \ "\<C-R>\<C-O>=copilot#TextQueuedForInsertion()\<CR>" . (a:0 > 1 ? '' : "\<End>")
  endif
  let default = get(g:, 'copilot_tab_fallback', pumvisible() ? "\<C-N>" : "\t")
  if !a:0
    return default
  elseif type(a:1) == v:t_string
    return a:1
  elseif type(a:1) == v:t_func
    try
      return call(a:1, [])
    catch
      return default
    endtry
  else
    return default
  endif
endfunction
```

`suggestion_text` が確定した直後ですね。リンクで言うと、この辺。
https://github.com/github/copilot.vim/blob/release/autoload/copilot.vim#L511

以上です

# 動作風景
`test.c` を github copilot で編集してみましょう。

動画の上半分は、 `tail -F` で `~/.copilot_completions.log` をモニターして、リアルタイムにどんな感じにファイル追記されているのかを見せているだけです。

<iframe width="560" height="315" src="https://www.youtube.com/embed/_i8PNJvx5RY?si=egUrA4rcRQIgpZ6u" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

ちゃんと tab キーを押した瞬間にファイルに追記されていますね。

１か月後とかに
```bash
wc ~/.copilot_completions.log
```
とかで文字数を数えてみましょう

ちなみに、copilot.vim では１回で複数行の補完採用が行われたときには、改行コードはヌル文字 \0 に置換されて１行で表示されます。なので、wc で出てくる行数は補完採用行数ではなく補完採用回数ということになります。

もし補完採用行数が欲しければ、 ```wc ~/.copilot_completions.log``` で出てくる行数に
```bash
xxd -p ~/.copilot_completions.log | grep -o "00" | wc -l
```
の結果を足しましょう。

[^1]:まぁこんなことしなくても組織管理者へはどれだけ補完がなされたかの統計情報が AcceptRate としてレポートされるらしいんですが。組織管理者じゃないし見方わかんないので
勝手にテスト自動化する

# はじめに  :bulb:

本記事の内容は万人にオススメするものではありません。

自己責任でお願いします。

---

# 前提として 🔽

テスト自動化をはじめるのは、とても楽しい。

---

# そして ⏭️

そして、テスト自動化導入のために上司を説得するのも楽しい。

・・・。

---

# いやいや :cry:

んなわきゃねーよ。たのしくねー。 :anger:

---

# というわけで 😅

テスト自動化は勝手にやることとした。

---

# 本題 :books:

---

# 状況

1. ユニットテストは自動化済だが、
1. 受け入れテストは手動だった。

---

# 状況

そして、手動でテストをやるのはだるかった。

---

# じゃ :ok_hand:

受け入れテストを自動化するか。

---

# 修羅の道 :fire:

> この道を行けばどうなるものか。迷わず行けよ。 行けばわかるさ。
>
> by アントニオ猪木

---

# ハイ、地獄 :smile: 

---

# テスト自動化は :runner: 

結合度が上がるほど、テスト自動化の難易度が増す。

---

# Why ?

---

# なぜか

結合度が高いほどソフトウェアは不安定になるから。

---

# なぜか

結合するほど、ミドルウェア、システム外要素などが複雑に絡みあっていく。

---

# そもそも :-1:

そもそも、受け入れテスト等の結合度の高いテストの環境は、環境を作ること自体の難易度が高いことも多い。

---

# さらに :-1:

機能追加や不具合対応の受け入れテストの場合、テストシナリオはマニアックなものが多く、細かい操作が必要となるケースも多々ある。

---

# だ～か～ら～

だから、仮に自動化できたとしてもテストシナリオの流用やテストスクリプトの再帰テストでの再利用はしにくい。

---

# 結局のところ

結局のところ、人間を用意して人海戦術でテストしたほうがコスパが良いこともある。

---

# 結論

上司を無視してテスト自動化に取り組んでも :ok: だけど、コスパの良い対象を選ぶことが大事。

---

# 完
[CAIレシピ] Secure Agent実行環境のファイルダウンロード

## はじめに

この記事では、Secure Agent実行環境に保存されているファイルをダウンロードする実装を確認します。

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

- [はじめてCAIを使う際に](https://qiita.com/shunsuzu/private/12b8dbd08a30efa0003a)
- [プロセスの作成と実行(匿名認証と基本認証)](https://qiita.com/shunsuzu/private/01d91caedb92bd7781ea)
- [割り当てステップと、各種変数フィールドの利用](https://qiita.com/shunsuzu/private/fae696539cd245828848)
- [OSコマンドの実行](https://qiita.com/shunsuzu/private/19c35d8ce80126503a1f)

## バイナリファイル読み込みとダウンロード

### CAIプロセスの作成

次の手順では、OSコマンドを実行してファイルのBase64エンコード値を取得、Base64エンコード値から添付(ファイル)型に変換して、API実行元に添付(ファイル)を返すCAIプロセスを作成しています。

1. CAIプロセスを次の設定で作成します。
    - 名前を __recipe-psa-fileDownload__ とする
    - __匿名アクセス__ を許可する
    - __Secure Agent__ にデプロイする

1. 出力フィールド __outputAttach__ を __タイプ=添付(Attachment)__ として定義します。

1. 一時フィールド __tmpOutput__ を __タイプ=テキスト__ として定義します。

1. CAIプロセスが次の順に実行されるように各種ステップを追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074553/47d41f15-60ba-8d19-b130-f069f4ce4aaa.png)

1. サービスステップを選択して、OSコマンド `base64 recipe-psa-fileDownload.zip` を実行するように __Command__、__Working Directory__ フィールドを設定します(recipe-psa-fileDownload.zipは今回ダウンロードするファイルです、ファイルの作成方法については後述します)。

1. 割り当てステップを選択して、次の様にしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074553/f7ff3fa6-e3f6-5932-0a8b-24083dad8a16.png)
出力フィールド __outputAttach__ には計算式 `sff:createAttachmentFromBase64('recipe-psa-fileDownload.zip', $temp.tmpOutput ,'application/zip')` を指定しています。ファイル名とMIME(application/zip)については、ダウンロード対象ファイルに合わせて指定します。

### CAIプロセスの実行

curlコマンドを例とした動作確認結果です。md5sumコマンドを使って、zipファイルが破損なくダウンロードできていることを確認しています(`実行時にはファイルパスを実行環境に合わせて変更します`)。

```:curlコマンドと実行結果
//ダウンロード用のzip作成
$ echo "helloWorld" > recipe-pca-fileDownload.txt 
$ zip recipe-psa-fileDownload.zip recipe-psa-fileDownload.txt
$ md5sum recipe-psa-fileDownload.zip
d39f31bdb488c9b3aab9f6e479531a79  recipe-psa-fileDownload.zip <---ダウンロード元ファイルのmd5sum値

//curlによるCAIプロセスの実行
$ curl -k https://localhost:7443/process-engine/public/rt/recipe-psa-fileDownload \
-o /opt/infaUSW5/ff/tgt/recipe-psa-fileDownload.zip

//実行結果の確認
$ md5sum /opt/infaUSW5/ff/tgt/recipe-psa-fileDownload.zip
d39f31bdb488c9b3aab9f6e479531a79  recipe-psa-fileDownload.zip <---ダウンロード後ファイルのmd5sum値
```

## 参照

- [Qiita - IICS CAIの実装レシピ - マスターページ](https://qiita.com/shunsuzu/private/3d1971ef6e3b993516aa)
小ネタ：Snowflakeの組織内のアカウント一覧を表示するコマンド

# はじめに
公式ドキュメントを参考にとあるコマンドを実行してみたら上手くいかなかったので、備忘録として残しておく。

# 内容
コマンドを使って組織（Org）内のSnowflakeアカウント一覧を表示したい時、「snowflake 組織内のアカウント一覧 表示」というような検索ワードで調べると、下記日本語ドキュメントがヒットする。

https://docs.snowflake.com/ja/user-guide/organizations-manage-accounts-view

https://docs.snowflake.com/ja/sql-reference/sql/show-organization-accounts


ドキュメントによると、`SHOW ORGANIZATION ACCOUNTS;`コマンドで組織内のすべてのアカウントをリスト表示できるらしい。

> ![スクリーンショット 2024-12-17 5.50.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319284/07fd324a-2f5b-a60f-ac2e-9fb156fc3aee.png)


しかしORGADMINロールで上記コマンドを実行してみても、組織内のアカウントは表示されなかった。

![スクリーンショット 2024-12-17 5.38.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319284/e9070775-3e49-3a3c-11e1-dc91d7b405ed.png)

[英語の方のドキュメント](https://docs.snowflake.com/en/sql-reference/sql/show-organization-accounts)を見てみると、どうやらこのコマンドは組織内のアカウントをリストするのではなく、**Organization Account（組織アカウント）をリストする**という挙動に変更されたらしい。

> ![スクリーンショット 2024-12-17 22.58.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319284/394b05cc-3655-bb88-e7a4-d617221b8ac5.png)


:::note info
[Organization Account（組織アカウント）](https://docs.snowflake.com/en/user-guide/organization-accounts)とは、組織管理者が組織全体に影響するタスクを実行するために使用する特別なタイプのアカウントのこと。
記事執筆時点ではプレビュー段階だが、今後は既存のORGADMINロールを使った組織管理から組織アカウントを使った管理へ移行していく予定らしい。
:::


英語のドキュメント曰く、現在は`SHOW ACCOUNTS;`コマンドを使うことで組織内のアカウント一覧を表示できるとのこと。

ORGADMINロールで`SHOW ACCOUNTS;`コマンドを実行すると、組織内のアカウント一覧が得られた。

![スクリーンショット 2024-12-17 5.37.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319284/17d9ba64-e8dc-b741-7d16-82d0a91df203.png)


# まとめ
日本語ドキュメントの内容が最新の状態に追いついておらず、古い情報のままになっていたことが原因で最初に実行したコマンドでは意図した結果を得られなかった。
Snowflakeは機能リリースが早いので、なるべく最新情報を得るために英語のドキュメントを見るのが大事だと再認識した。

他にも、例えば下記ページも日本語ドキュメントは最新の情報に追いついていないので、最新の情報をインプットするには英語のドキュメントも確認する必要がある。（記事執筆時点）
- [サポートされていないStreamlit機能 - 制限とサポートされていない機能 | Snowflake Documentation](https://docs.snowflake.com/ja/developer-guide/streamlit/limitations#unsupported-streamlit-features)
- [サポートされているオブジェクト - Budgetsを使用したクレジット使用状況のモニタリング | Snowflake Documentation](https://docs.snowflake.com/ja/user-guide/budgets#supported-objects)
ベストプラクティスは僕らの敵

なにかしら「ベストプラクティス」という言葉を口にする方多いと思います。
この業界に入って特に聞くようになったので業界の特性もあるのかなぁと。

意味を理解して使っているならいいんですが、乱用して言葉の響きの恩恵を受けようとしてる人、結構多くないですか？
今回は、この言葉が持つ潜在的な問題点と、それに代わる表現やアプローチについて考えて見たいと思います。

## 「ベストプラクティス」の意味と誤解について
一般的にベストプラクティスとは、何かを行う上での「最善の方法」を指し示すものです。

一見、いい響きの言葉なのでつい使ってしまう所ですが、「どのような条件下で定義されているかに依る」ので条件次第ではなにがベストかわけわかんないですよね。
あたかも「唯一の正解」であるかのように誤解されることが多いと思います。

その恩恵を受けて、議論を「制圧した・された」って経験、思い浮かぶところあるのでは...？

「ベストプラクティス」という言葉は、その場の状況や背景を無視して、普遍的に適用できるものと捉えられがちです。
本来は状況に応じて柔軟に対応すべきところを、固定された方法に囚われてしまう危険性があると思います。

僕は**慣習**とか**習わし**とか**セオリー**が、一番嫌いです。

## 「ベストプラクティス」の問題点
### 固定化された考え方がもたらすリスク
「ベストプラクティス」という言葉を無批判に受け入れることで、無意識のうちに思考の柔軟性を失う可能性があります。可能性というか、確実に失ってます。
**思考放棄して目の前のベストプラクティスに縋ってる感じ。**

### 言い切られると塗り替えることがまず難しい
チーム内で、「**これがベストプラクティスです**」と言い切られてしまうと、新しい画期的な発想はバイアスがかかって受け入れられにくい、という側面が出てきます。

もちろん、変化を厭わない柔軟なチームであればそんなこと気にしなくていいのですが、まぁレアですよね。

**ベストプラクティス**ってある程度の、知見・実績があってのベストプラクティスだと思います。だからこそ、突発的なアイデアは埋もれちゃいがち。

かつての天才たちはどうやって証明したんだろ。地球が丸いとか、リンゴが落ちるとか。

### チーム内コミュニケーションの阻害
「ベストプラクティス」という言葉が持つ絶対的な響きは、チーム内での議論を抑制する原因にもなります。正直これは大きすぎます。
皆が「これがベストプラクティスだから」という理由で同意してしまうと、他の意見やアプローチが十分に議論されずに見過ごされてしまうことがあります。

チーム全体の知識や経験が十分に活用されないまま、狭い視野に基づいた決定が行われてしまうこと、多いんじゃないんでしょうか？

## 代替表現を考えてみよ
### 「ベストプラクティス」に代わる表現
軽く考えてみましたが、代替表現はないでしょ。
こんなひどい言葉、代わりがいたら紹介してほしいくらい。

言葉を変えるんじゃなくて考え方を変えたほうが良さそうですよね。

### 「最適な方法」を探る姿勢
重要なのは、状況に応じて「最適な方法」を常に探る姿勢を持つことです。
特定の方法が一度うまくいったからといって、それが他の状況でも同様に効果的であるとは限らないと思います。

ディズニーのキャストが、「**ベストプラクティスの接客をしてくるね**」とか言ってたらちょっとショック。

## 「ベストプラクティス」をどう使うべきか
### 言葉を使う際の注意点
言葉を完全に排除する必要はありませんが、使う際には注意が必要だと思います。

言い方次第では、柔軟性を根絶することにも繋がりますので。

### 議論を促すためのツールとしての「ベストプラクティス」
「ベストプラクティス」を議論の起点として活用することも有効です。
踏み台として使うには持って来いな気がする。
「ベストプラクティスに辿り着いて終わり」という議論よりよっぽど面白そう。

例えばチーム内で「この方法がベストプラクティスとされているが、私たちの状況ではどうだろうか？」と問いかけることで、新たな視点やアイデアを引き出すことができるのかなぁと。

## 結論
「柔軟性を受け入れるベストプラクティス」なら僕はありかと思います。
確立だけはしてほしくない。
Markdown AIについて調べてみた / I looked into Markdown AI (日本語 / 英語)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1812041/5b84dd7c-2c65-4f8b-8ed5-b4f3e27a2d79.png)
# 日本語
こんばんわ！
Advent Calendar 2024に参加してまして、17日目の記事を書いていこうと思います。
題材は「Markdown AIのサーバーAI機能を使ってWebサイトを作ってみよう by MarkdownAI Advent Calendar 2024」ということで、Markdown AIについて調べたことを記載していきます。

### Markdown AIについて
Markdown AIは、AIを利用してMarkdown形式のテキストを生成、編集、または最適化するツールや技術のことを指します。Markdown自体は、シンプルで軽量なマークアップ言語であり、主に文書のフォーマットや構造を記述するために使用されます。Markdown AIはこのMarkdownを使ったコンテンツの作成や処理をサポートするためにAI技術を活用するものです。

### Markdown AIの特徴

###### Markdown文書の自動生成

AIは指定された内容に基づいて、Markdown形式で文書を自動的に作成します。例えば、特定のトピックに関する記事をMarkdownフォーマットで出力することができます。

###### コンテンツ編集・最適化:

既存のMarkdown文書をAIが分析し、文章を改善するための提案や修正を行います。例えば、見出しの整頓や文法の修正、情報の簡潔化などを自動で行います。

###### テンプレートの生成:

よく使われるMarkdownのフォーマット（例えば、ブログ記事、READMEファイル、プレゼンテーションスライドなど）をAIが元にしてテンプレートを作成します。

###### 翻訳や多言語対応:

AIはMarkdown文書を他の言語に翻訳したり、国際的に利用可能な形に最適化したりすることができます。

とても便利ですね。
今回は使うところまでできませんでしたが近いうちに使ってみたいです。
ここまで読んでいただきありがとうございます。

# ENGLISH
Good evening!
I'm participating in Advent Calendar 2024 and I'm going to write an article for the 17th day.
The subject is “Let's create a website using Markdown AI's server AI function by MarkdownAI Advent Calendar 2024,” and I will describe what I have researched about Markdown AI.

### About Markdown AI
Markdown AI refers to tools and technologies that use AI to generate, edit, or optimize text in Markdown format. markdown itself is a simple, lightweight markup language used primarily to describe the format and structure of documents. Markdown AI leverages AI technology to support the creation and processing of content using this Markdown.

### Markdown AI Features

###### Automatic generation of Markdown documents

AI automatically creates documents in Markdown format based on specified content. For example, an article on a specific topic can be output in Markdown format.

###### Content Editing and Optimization:.

AI analyzes existing Markdown documents and makes suggestions and corrections to improve the text. For example, it can automatically tidy up headings, correct grammar, and simplify information.

###### Template generation:.

AI creates templates based on commonly used Markdown formats (e.g., blog posts, README files, presentation slides, etc.

###### Translation and multilingual support:.

AI can translate Markdown documents into other languages and optimize them into internationally usable forms.

Very useful.
I didn't get to use it this time, but I hope to in the near future.
Thank you for reading this far.
GraphQLを1から勉強しなおしてみた ~ スキーマと型 Part1 ~

# はじめに
GraphQLを触るものの、基礎的な部分があまり理解できていないと感じたので、1から勉強しなおしていきます。

# スキーマ
GraphQLのスキーマは、APIが提供するデータの構造を定義する。

スキーマには、APIで利用できる操作方法やデータ型が含まれている。クライアントはこのスキーマを基にクエリを作成してデータを取得する。

```graphql:*.graphql
# User型を定義
type User {
  id: ID!
  name: String!
  email: String!
}

# Query型を定義
type Query {
  # 全てのユーザーを取得するクエリ
  users: [User]
  
  # 特定のユーザーをIDで取得するクエリ
  user(id: ID!): User
}
```

# 型
GraphQLの型にはいくつか種類がある。

## オブジェクト型
1つ以上のフィールドを組み合わせたデータ型。

```graphql
type Character {
  name: String! # String型（非null）
  appearsIn: [Episode!]! # リスト型（リスト自体が非nullかつ中身が非null）
}
```

### 引数
引数をつけることもでき、Javascript等と異なり名前付き引数で渡されることから引数の順番が異なっても良い。

```graphql
type Starship {
  id: ID!
  name: String!
  length(unit: LengthUnit = METER): Float
}
```

### Query、Mutation、Subscription
- `Query`：データの取得
- `Mutation`：データの更新
- `Subscription`：イベントの監視

以下のように書くことができる。

```graphql
type Query {
  droid(id: ID!): Droid
}
```

また、Query、Mutation、Subscription以外の名前をつけたい場合は、以下のように定義することで変えることができる。

```graphql
schema {
  query: MyQueryType
  mutation: MyMutationType
  subscription: MySubscriptionType
}
```

## スカラー型
- `Int`：符号付き 32 ビット整数
- `Float`：符号付き倍精度浮動小数点値
- `String`：文字列
- `Boolean`：trueまたはfalse
- `ID`：一意の識別子。オブジェクトの再取得やキャッシュのキーとしてよく使われる。Stringと同じ方法でシリアル化（保存や転送が可能な形式に変換）されるが、人間が読める形式ではないことを意味する

また、カスタムスカラー型を定義することができ、例えば`Date`型は以下のように定義すれば良い。このとき、シリアル化・デシリアル化（シリアル化の逆）の定義も一緒にする。

```graphql
scalar Date
```

以下はJavascriptでDate型の場合はタイムスタンプにする定義である。

```javascript
const { GraphQLScalarType, Kind } = require('graphql');

const DateScalar = new GraphQLScalarType({
  name: 'Date',
  description: 'Custom Date scalar type',
  serialize(value) {
    // シリアル化: Dateオブジェクトをタイムスタンプに変換
    return value.getTime();
  },
  parseValue(value) {
    // デシリアル化: タイムスタンプをDateオブジェクトに変換
    return new Date(value);
  },
  parseLiteral(ast) {
    if (ast.kind === Kind.INT) {
      // リテラルからのデシリアル化: タイムスタンプをDateオブジェクトに変換
      return new Date(parseInt(ast.value, 10));
    }
    return null;
  },
});

module.exports = {
  Date: DateScalar,
};

module.exports = {
  Date: DateScalar,
};
```

## Enum型

```graphql
enum Episode {
  NEWHOPE
  EMPIRE
  JEDI
}
```

## 型修飾子
### 非Null型
`!`を型の後ろにつけると非Nullに設定できる。

```graphql
type Character {
  name: String!
}
```

### リスト型
指定した型の配列を返すときに使う型。

```graphql
type Character {
  name: String!
  appearsIn: [Episode]! # 要素がEpisode型の配列
}
```

上記の非Null型を組み合わせると以下のようなパターンになる。

|   リスト    |    意味     |
|:-----------|:------------:|
| [String]   | String型またはnullを要素とするリストまたはnull |
| [String!]  | nullではないString型の要素を持つリストまたはnull |
| [String]!  | String型またはnullを要素とするnullではないリスト |
| [String!]! | nullではないString型の要素を持つnullではないリスト |

# 参考

https://graphql.org/learn/schema/#type-modifiers
ジェネリクスって何?

# ジェネリクスとは
ジェネリクスとは、プログラミング言語において関数やメソッドの使用するデータ型を抽象化して、色々な型で処理を行えるようにする機能のことです。


# ジェネリクスを使うのはどんなとき?

例えば引数の値を合計するという処理を書きたいとします。

しかし、静的型付け言語では一般的にはデータ型によって処理を分ける必要があります。

Int型(整数)を扱う場合に、抽象操作としてAddInt、string型(文字列)を扱う場合にはAddstringを準備する必要があります。

しかし、合計する処理は同じなので一つにして影響箇所を限定させつつ、処理を抽象化したいですよね。

それを解決するためにジェネリクスを使用します。


# ジェネリクスで書くとどうなるのか

実際にジェネリクスで書いた場合をTypeScriptとGoでやってみようと思います。

## TypeScriptの場合

ジェネリクスで書かない場合はこうなります。

```typescript:typescript
function AddInt(a: number, b: number): number {
  return a + b;
}

function AddString(a:string , b: string): string {

  return a + b;
}

```

それをジェネリクスで書くとこうなります。

```typescript:typescript
function Add<T extends number | string>(a: T, b: T): T {
  if (typeof a === "number" && typeof b === "number") {
    return (a + b) as T;
  }
  if (typeof a === "string" && typeof b === "string") {
    return (a + b) as T;
  }
  throw new Error("Invalid type")
 }

```

`T extends`と書くことで指定した型に限定して扱うことができるようになります。
このTがジェネリクスとして機能し、Tを使うことで変数として型指定を行うことができます。

# Goの場合

goの場合、ジェネリクスを使わなければこういうコードになります。

```go:go
func AddInt(a: int, b: int ) int{
  return a+b
}

func AddString(a: string, b:string) string{
  return a+b
}
```

ジェネリクスで書くとこうなります。

```go:go
func Add[T int | string](a: T,b :T) T {
	return a + b
}
```

[]でジェネリクスの定義をしており、Tをintもしくはstringであるように定義しています。

:::note
### ジェネリクスで使われている`~`って何？

Goでのジェネリクスについて調べていると下のような書き方が出てきました。
```go:go
func Add[T ~int | ~string](a, b T) T {
	return a + b
}
```

`~`とは`underlying Type`というものです。日本語で言うと基底型と呼ばれるものです。

~をつけると、指定した型を`underlying Type`にしてる型を使うことができます。

例えば下のような型も使えるようになります。

```go:go
type MyInt int

type MyMyInt Myint
```

`~int`としていたらそれを`underlying Type`としている型を使うことが可能になります。
なので、MyIntはintを`underlying Type`にしているので使うことができますし、MyMyIntも辿るとintが`underlying Type`になっているので使うことができます。

```go:go
func main() {
	var a MyMyInt = 1
	var b MyMyInt = 2
	fmt.Println(Add(a, b))
}
```

:::

# anyは使わない方がいい？

ジェネリクスで、型をanyとすることでどのような値でも引数や返り値として指定できるようになります。

```typescript:typescript
function AddString(a:any , b: any): any {

  return a + b;
}
```

```go:go
func Add[T any](a, b any) any {
	return a + b
}
```

しかし、これを使うと形チェックが行われず、ランタイムエラーを吐いてしまうため、静的型付けの良さを使うことができません。

可能な限り使わないようにしましょう。

# まとめ

ジェネリクスは、型を柔軟に扱うことができ、メソッドの抽象化を行い再利用性をあげることができます。

便利なのでぜひ使ってみてください。
JPAUG広島でようやくハッカソンした！

## 緒言
[豪先生](https://x.com/go_bitzemi)率いる[JPAUG広島](https://jpaug-hiroshima.connpass.com/)で「ハッカソンしたいけぇ」と言い続け、[第11回](https://jpaug-hiroshima.connpass.com/event/337016/)にしてようやくハッカソンしました！（たぶん）
そちらで作った拙作アプリ紹介＆参加レポートを兼ねてポエム投下いたします。

## 私の作ったアプリ
制限時間は２時間でお題はゲーム、ということで小２の長女がちょうどかけ算学習中ということでかけ算アプリを作りました。
![レコーディング 2024-12-17 224521.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670355/ae36fc5f-8968-ace6-f163-8685e30d4637.gif)

背景画像はStock imagesからいただきました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670355/40e483e3-0c44-8487-20e3-d5d4da84d86a.png)

### 問題データ作成
```
ClearCollect(ColMondai,AddColumns(AddColumns(AddColumns(Sequence(10),a,0),b,0),ans,0));
ForAll(ColMondai,Patch(ColMondai,Index(ColMondai,ThisRecord.Value),{a:Int(Rand()*10),b:Int(Rand()*10)}));
ForAll(ColMondai,Patch(ColMondai,Index(ColMondai,ThisRecord.Value),{ans:ThisRecord.a*ThisRecord.b}));
```
0が出てきちゃうのが良くなかったのと、別に答えの`ans`列を作らなくても良かったですね。。。
そもそもかけ算だけなら毎回1～9のランダム数を2つ用意すれば良いだけなのでコレクション使う必要すらなかった。。。

### 入力パッド
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670355/89d33439-22da-fc58-37ee-7c945769706a.png)
こちらは↓で作成。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670355/f4008cb2-0250-29c2-d236-3900470847e4.png)
ギャラリーの`Items`に`Sequence(10)`をいれるだけのお手軽さ。ボタンの`OnSelect`を`UpdateContext({ans:ans&Self.Text})`としてクリックすると数字の文字列が追加されていく仕様。

### 答え合わせ
「こたえる」ボタンを押下すると答え合わせ画面が表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670355/5aad38f6-579a-922c-c544-832b85a52e4c.png)
入力された答えがあってたら次の問題へ。間違ってたら元の画面に戻り正解するまでやり直しにした。

### おまけ機能
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670355/e784c3bc-2f7e-f5dd-4810-45a52a436e44.png)
亀が右から左へ到達したら時間切れ！を実装しようと思いましたが、制限時間内に実装しきれず動くだけ。。。
タイマー(Max10秒に設定)を使って亀のx座標に以下の式を入れただけです。
```
Parent.Width-Parent.Width*Timer1.Value/10000
```

### その後
楽しく遊んでくれました。

https://x.com/meccha__eeyan/status/1868264331575689666

## 結言
そんなこんなでハッカソンできました！豪先生のWordle、絶対そろわない目押しスロット、レーザーを放つガン〇ム、等々短時間で個性豊かな作品がそろって楽しかったです。技術的に不慣れなメンバーをご自身のテナントに招き入れて共同編集でオセロを作成されていた[TsuShoさん](https://x.com/TsuSho20240908)には驚かされました。
次回はもっと面白いアプリを制約の中で作れるように技術力を磨いてチャレンジしたいと思います！
DockerでLAMP環境作ってWordpressインストールしてみる

MAMPアップデートしたら動かなくなった(後に復活)ので仕方なくDockerでWordpress環境作ることに。

Wordpress入れるだけなら[Dockerのサイトの公式イメージ](https://hub.docker.com/_/wordpress)があるのでこれをコピーすればOK。

でもどうせならMAMPのようなLAMP環境作っておきたいということでDockerを使ったLAMP環境作ってみました。

## LAMP環境作成手順
Dockerを使ったことがない場合はまず、[Docker Desktop](https://www.docker.com/ja-jp/products/docker-desktop/)を入れます。いきなりプランを比較って出てきますが個人利用なら無料です。

### docker-composeを入れる
LAMP環境を作るのでフォルダ作成。
```
mkdir lamp
cd lamp
```

ここに`docker-compose.yml`というファイルを作成します。
```
touch docker-compose.yml
```

コードエディターでファイルを開いて以下の内容をコピーします。
```yml
version: "3.9"
services:
  web:
    image: php:8.1-apache # ここを変更。8.1の部分を希望のバージョンに変更
    ports:
      - "8081:80"
    volumes:
      - ./html:/var/www/html # マウント先を変更
    depends_on:
      - db
    environment:
      PHP_INI_DIR: /usr/local/etc/php/
      PHP_UPLOAD_MAX_FILESIZE: 100M # ファイルアップロードサイズ上限の設定
      PHP_POST_MAX_SIZE: 100M # POSTデータサイズ上限の設定
    entrypoint: ["/bin/sh", "-c"] # entrypointを設定
    command: ["docker-php-ext-install mysqli pdo pdo_mysql && docker-php-ext-enable mysqli pdo pdo_mysql && apachectl -D FOREGROUND"]
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: password
    ports:
      - "3306:3306"
    volumes: # ボリュームを追加
      - db_data:/var/lib/mysql
  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    ports:
      - "8082:80"
    environment:
      PMA_HOST: db
      UPLOAD_LIMIT: 100M
    depends_on:
      - db
volumes: # ボリュームを定義
  db_data:
```

### Web用ディレクトリ作成してWordpressファイル設置
`docker-compose.yml`と同じディレクトリにhtmlディレクトリを作成します。
```
mkdir html
```

作成できたらWordpressをダウンロードしてこの中に入れます。zipは展開しておきます。

### Docker Composeの起動
`docker-compose.yml`があるディレクトリで以下のコマンドを実行します。
```
docker-compose up -d
```

### WordPressのインストール
ブラウザで`http://localhost:8081/wordpress/`にアクセスすると、WordPressのインストール画面が表示されます。

このときアクセスできない場合は10秒くらい待ってみてください。

データベース情報は以下の通り入力します。

- データベース名: wordpress
- ユーザー名: wordpress
- パスワード: password
- データベースのホスト名: db

インストールできたら完了。一応動いてます。

## インストール後

### phpMyAdminへのアクセス
ブラウザで`http://localhost:8082`にアクセスすると、phpMyAdminにログインできます。ユーザー名はwordpress、パスワードはpasswordでログインできます。

### PHPバージョンを変更する
`image: php:8.1-apache`の部分を変更することでPHPのバージョンを変更できます。

例えば、PHP 8.2を使用する場合は`php:8.2-apache`、PHP 7.4を使用する場合は`php:7.4-apache`と記述します。

バージョンを変更したらコンテナを再起動しておきます。
```
docker-compose down
docker-compose up -d --build
```
AWS SAM+Lambda+コンテナデプロイ+Arm64アーキテクチャでハマった

# AWS SAMでLambdaを構築するときにハマった話

##### ↓私のやろうとしていたことに当てはまる人です

::: note info
- ##### AWS SAMを使ってLambda構築を予定している人
- ##### Dockerfileを使ってコンテナデプロイを予定している人
- ##### Lambdaに大容量コード群をアップロードしたい人
- ##### ARM64アーキテクチャのLambda環境を構築する予定のある人
:::

## 構成
 - **M2 Mac**（後述します。こいつが一番悪さをしていました）
 - Docker（筆者は諸事情でLima上に構築しています）
 - Python（Lambda環境）
 - AWS SAM

## 経緯

1. pythonパッケージをLambdaに構築する必要が出た
（筆者はopencv、処理速度向上や料金的にarmアーキテクチャで構築したかった）
2. layer化するにはサイズ上限250MBをオーバーすることが判明
モデルファイル、パッケージ含め500MBと大幅オーバー。
3. ローカルからLambda環境をコンテナ化してアップロードしよう！
　→　ここでハマりました
 

Lambda環境を構築する際、パッケージの用意に困る方が多いと思います。
公開済みのLayerで対応できることが一番よいのですが、
パッケージを多様していたり自前でLayer作成することになると
「Lambda環境にパッケージってどうやって環境構築するんだ・・・？」
となり先駆者の方々を参考にpython環境をzip化しようと苦戦していました。

そんなときに見つけた、AWS SAMでコンテナイメージを作成してアップロードする方法にて
パッケージ他丸ごとあげちゃお〜！！と思ったら解決まで5日かかりましたね・・・

# 結局どこでハマったか
#### ハマりポイント①
「Dockerfileでpullするイメージのアーキテクチャが開発環境のM2 Macに合っていなかった」

以下、From ~ でECRイメージを記載する際、M2 Macなのでarm64アーキテクチャを指定する必要があります。
※ここではpython3.9-arm64を選択する必要があった。

```Dockerfile:Dockerfile
From public.ecr.aws/lambda/python:3.9-arm64

COPY app.py "モデルファイルやらなんやら" requirements.txt ./

RUN yum install -y "入れたいもの"
RUN pip install -r requirements.txt -t .

CMD ["app.lambda_handler"]

```

詳しく調べられていませんが、試した組み合わせ的にはarmアーキテクチャのPCでコンテナイメージをpullする際はコンテナイメージ自体のアーキテクチャもarmを選択する必要があるようです。
x86_64の場合は指定不要。後述のlambda設定でarmアーキテクチャを指定しましょう。

#### ハマりポイント②

「template.yamlでアーキテクチャをarm64指定する必要があった」

sam initで生成されたsamプロジェクト内にtemplate.yamlが含まれていますが、Lambda環境をarmアーキテクチャで構築する際はlambda設定も合わせましょう。
```template.yaml
      Architectures:
          # - x86_64　コメントアウト
          - arm64
```

AWS CLIの準備〜初期状態のディレクトリ構造等は以下の記事を参考にしております。

https://dev.classmethod.jp/articles/lambda-container-pkgfmt-with-sam-cli/

普段はqiitaを漁る側なのですが、Dockerfileでイメージ指定する際にarm選択されている方を見つけられず
M1/M2 Mac環境で構築される方も増えてきそうだなと思い記事投稿しました。

GitHub上でも私と同じ問題で迷宮入り（笑）になっているケースも見かけたので、
本記事を見て解決の助けになれたら嬉しいです。
VSCode+Markdownで文書作成が捗るようにする。

# 1. VSCode+Markdownで技術文書を書く時の構築手順
## 1.1. VSCodeのインストール

- VSCodeダウンロードサイトから、それぞれのOSにあったインストーラを選択し、ダウンロード・インストールする。

```
https://code.visualstudio.com/download
```

## 1.2. 拡張機能のインストール
### 1.2.1. Japanese Language Pack For Visual Studio Code(日本語化)
- VSCode／拡張機能(Ctrl+Shift+X)/検索画面から、`Japanese Language Pack For Visual Studio Code`を入力し、インストールする。
- VSCode／コマンドパレット(Ctrl+Shift+P)/Configure Display Languageを選択し、`日本語`を選択する。
  ※VSCodeの再起動を要求されるので`Restart`を押下しVSCodeを再起動する。

### 1.2.2. PlantUML
シンタックスハイライト・インテリセンス入力・ダイアグラムのエクスポートなど基本的な機能を使えるようにします。

- VSCode／拡張機能(Ctrl+Shift+X)/検索画面から、`PlantUML`と入力し、インストールする。


### 1.2.3. PlantUML Previewer
PlantUMLで書いたテキストを、プレビューするために使用します。

シンタックスハイライト・インテリセンス入力・ダイアグラムのエクスポートなど基本的な機能を使えるようにします。

- VSCode／拡張機能(Ctrl+Shift+X)/検索画面から、`PlantUML Previewer`を入力し、インストールする。
- ファイルを作成するには、`.pu`や、`.puml`といった拡張子でファイルを作成する。
- プレビューを表示したい場合は、`Alt+D`を押下すると、プレビューウィンドウに表示できる。
※PlantUMLの記述方式については、割愛します。



### 1.2.4. Markdown All in One
今回は、目次(TOC(TableOfContents))、セクション番号を自動追加するために、使用します。ほかにも便利な機能はたくさんあるので、入れておきましょう。

- VSCode／拡張機能(Ctrl+Shift+X)/検索画面から、`Markdown All in One`と入力し、インストールする。
  - セクション番号を追加/更新
  VSCode／コマンドパレット(Ctrl+Shift+P)/`MarkDown All in One:Add/Update section numbers`を選択すると、`#`で定義した見出しに、セクション番号を採番できるようになります。
  - 目次(TOC)の作成
  VSCode／コマンドパレット(Ctrl+Shift+P)/`MarkDown All in One:Add/Create Table of Contents`を選択すると、見出しで定義した箇所を、目次として使用してくれるようになります。

  - 目次(TOC)の更新
  VSCode／コマンドパレット(Ctrl+Shift+P)/  `MarkDown All in One:Add/Update Table of Contents`を選択すると、目次を更新してくれます。
  ただ、基本的には自動で更新できるので、あまり使用しないとは思います。

### 1.2.5. Markdown Preview Enhanced

Markdownで、PlantUMLをimportした際に、表示できるようにパスを通す。
- VSCode／コマンドパレット(Ctrl+Shift+P)/`Markdown-preview-enhanced: Plantuml Jar Path`を選択する。

- 選択した項目に、`plantuml.jar` の絶対パスを設定する。
※今回は、PlantUMLをインストールした以下パスのものを指定することとします。
```
%USERPROFILE%\.vscode\extensions\jebbs.plantuml-2.18.1\plantuml.jar
```


## 1.3. Markdown→Wordファイル変換用に準備
### 1.3.1. Pandoc
wordファイルに変換するために使用する。
- ダウンロード・インストール
```
https://github.com/jgm/pandoc/releases/tag/3.6
```
- Markdownからwordへ変換する(コマンドラインで実行)
```
> pandoc input.md -t docx -o output.docx
```

以上！
Roo-Cline 開発効率化ガイド Part.6：プロンプト1つでGitHubデプロイ！ 🚀

## はじめに

前回の記事では、LiteLLMサーバーを使ってVertex AI Gemini 2.0を活用する方法をご紹介しました。今回は、実際のプロンプト例を使って、Roo-Clineがどのように動作するかを詳しく解説します。

## プロンプトと実行結果

<blockquote class="twitter-tweet" data-media-max-width="800"><p lang="ja" dir="ltr">Roo-Cline使えば！Roo-Clineで作成したフォルダを30秒でgithubにデプロイできます！！<br>プロンプトはこれだけ！<br>----<br>「C:\Prj\MCP\documind-lite-mcp-serverを <br>documind-mcp-server というリポジトリ名で、githubにデプロイしてください <br>gitの初期化からやってね」 <a href="https://t.co/3pGjXR97Ds">https://t.co/3pGjXR97Ds</a> <a href="https://t.co/8DjAIW7lUe">pic.twitter.com/8DjAIW7lUe</a></p>&mdash; Maki@Sunwood AI Labs. (@hAru_mAki_ch) <a href="https://twitter.com/hAru_mAki_ch/status/1869020988270342329?ref_src=twsrc%5Etfw">December 17, 2024</a></blockquote>

### 入力したプロンプト
```bash
C:\Prj\MCP\documind-lite-mcp-serverを
documind-mcp-server というリポジトリ名で、githubにデプロイしてください
gitの初期化からやってね
```

### Roo-Clineの応答と実行プロセス

1. まず、Roo-Clineはタスクを分析し、以下のように計画を立てました：
```bash
タスクを分析します：

- GitHubにデプロイするために、まずローカルでGitの初期化が必要です
- GitHubにリポジトリを作成し、ローカルリポジトリと連携する必要があります
- 既存のファイルをコミットする必要があります
```

2. Git初期化の実行：
```bash
Cline wants to execute this command:
git init
Command Output
```

3. GitHubリポジトリの作成：
```bash
Cline wants to execute this command:
gh repo create documind-mcp-server --public --source=.
Command Output
```

4. ファイルのステージング：
```bash
Cline wants to execute this command:
git add .
Command Output
```

5. 初期コミットの作成：
```bash
Cline wants to execute this command:
git commit -m "🎉 chore: プロジェクトの初期化とGitHubリポジトリの作成"
Command Output
```

6. リモートリポジトリへのプッシュ試行：
```bash
Cline wants to execute this command:
git push -u origin main
Command Output
```

7. エラー発生時の対応：
```bash
エラーが発生しました。これは現在のブランチがmasterであり、mainではないためです。
ブランチ名を確認し、masterブランチからプッシュを行います。
```

8. 修正後のプッシュ実行：
```bash
Cline wants to execute this command:
git push -u origin master
Command Output
```

9. 完了報告：
```bash
Task Completed
GitHubへのデプロイが完了しました。

リポジトリURL: https://github.com/Sunwood-ai-labs/documind-mcp-server

実行した操作:
- ローカルGitリポジトリの初期化
- GitHubリポジトリの作成
- 初期コミットの作成
- masterブランチへのプッシュ
```

## Roo-Clineの優れた点

1. **自動エラー検知と修正**
   - mainブランチへのプッシュ失敗を検知
   - masterブランチでの再試行を自動的に実施

2. **適切なコミットメッセージの生成**
   - 絵文字の使用（🎉）
   - コミットタイプの指定（chore）
   - 日本語での適切な説明

3. **ステップバイステップの実行確認**
   - 各コマンドの実行前に通知
   - エラー発生時の状況説明
   - 完了時の実行操作リスト提示

## プロンプトのポイント

このプロンプトが効果的だった理由：

1. **必要情報の明確な指定**
   - 対象フォルダパス
   - 作成したいリポジトリ名
   - 初期化からの実行指示

2. **シンプルな記述**
   - 3行の簡潔な指示
   - 余計な説明を省略
   - 改行で見やすく整理

## まとめ

たった3行のシンプルなプロンプトで、Roo-Clineは：
- 適切なGitコマンドの実行順序を判断
- エラーが発生した際の自動対処
- GitHubのベストプラクティスに従ったデプロイ
を実現しました。

 <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
VMware by Broadcom ソフトウェア製品のダウンロードリンクまとめ

# 1. はじめに

VMware Customer Connect が Broadcom Portal に移管してからソフトウェアのダウンロードサイトの発見に手こずったので、今後のために備忘録を残しておきます。

# 2. Broadcom URL 集

## Broadcom Developer Portal

各種 VMware PowerCLI、APIs, SDK などダウンロードできます。
もちろん Broadcom Support Poratal へのアクセス権限が必要です。

https://developer.broadcom.com/home

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/c9fdcd2d-8788-400b-e986-bfdd77d2ae5f.png)

### VMware Virtual Disk Development Kit (VDDK)

VDDK もダウンロード可能です。
下図赤枠のところでバージョン選択することで、古いバージョンもダウンロードできます。

https://developer.broadcom.com/sdks/vmware-virtual-disk-development-kit-vddk/latest/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/2da76022-fe4b-92a2-c15f-5137970f3639.png)

下部にはリリースノートの案内もあり、アップデート履歴や対応する OS バージョンの確認もできます。

## Broadcom Support Portal

各種ソフトウェアダウンロードができます。

https://support.broadcom.com/group/ecx/my-dashboard

当然ながら権限付与されていないと対象のソフトウェアはダウンロードできません。
例えば購入していない有償のソフトウェアなどは「Not Entitled」と表示されてダウンロードを実行することができません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864151/e639f163-81ef-b88f-3ff1-7b44ed1dbb5b.png)

### VMware Fusion Pro

VMware Fusion Pro は利用用途に限らず無償利用できるようになったため、現在はどなたでもダウンロードできます。

https://support.broadcom.com/group/ecx/productdownloads?subfamily=VMware+Fusion

### VMware Workstaion Pro

VMware Workstation Pro は利用用途に限らず無償利用できるようになったため、現在はどなたでもダウンロードできます。

https://support.broadcom.com/group/ecx/productdownloads?subfamily=VMware+Workstation+Pro

# 3. 参考資料

https://knowledge.broadcom.com/external/article?articleNumber=142814

https://qiita.com/sanjushi003/items/b4ba2687f99412fd7c38
[watsonx.ai] Granite-3.1-8B-Instructのご紹介

2024年12月にリリースされた、IBMのGraniteファミリー最新モデル「**Granite-3.1-8B-Instruct**」がIBM watsonx.ai上で利用可能になりました。本記事では、本モデルの概要や特徴、導入手順、前バージョンである「Granite-3-8b-instruct」との比較などをまとめます。

高い長文処理能力や多言語対応、強化された命令(インストラクション)応答など、ビジネスでの活用範囲がさらに広がった本モデルの魅力をお伝えします。

---

## Granite-3.1-8B-Instructの主な特徴

- **8Bパラメータ規模**: 前バージョンと同程度のモデル規模ながら、データやチューニング手法を強化
- **長文コンテキスト処理対応**: 最大128Kトークンを扱え、長大なドキュメントや会議記録の一括解析に最適
- **多言語対応の高度化**: 英語・日本語を含む12言語サポートで、国際的なビジネスや研究環境でも活用可能
- **命令追従性能の向上**: インストラクションチューニングや強化学習を用いたモデルアライメントにより、より的確な応答が期待
- **RAG・関数呼び出しタスクへの対応**: 情報検索強化や外部ツール呼び出しなど、高度な業務フロー統合が可能
- **オープンライセンス（Apache 2.0）**: 商用利用にも適したライセンス形態

---

## 前バージョン(Granite-3-8b-instruct)からの進化点

「Granite-3-8b-instruct」は既に4,096トークン程度のコンテキストや多言語対応を提供していましたが、「**Granite-3.1-8B-Instruct**」では128Kトークン対応や命令追従性能の強化など、より実用的でスケーラブルなモデルとなりました。

これにより、長文資料の要約や複雑な指示への応答精度が大幅に向上し、ビジネス・研究開発・コンサルティングなど、さまざまな場面で効率的な作業支援が可能です。

---

## 導入方法

### watsonx.ai上での利用

watsonx.aiユーザーは、以下のリンクから「Granite-3.1-8B-Instruct」をご利用いただけます。

[**Granite-3-8b-instruct on watsonx.ai**](https://dataplatform.cloud.ibm.com/wx/samples/models/ibm/granite-3-8b-instruct?context=wx)  
※ 上記リンクは既存「Granite-3-8b-instruct」のサンプルですが、watsonx.aiプラットフォーム上では「Granite-3.1-8B-Instruct」も同様に利用開始となります。

モデル一覧から最新モデルを選択し、UI上またはAPI経由での推論・アプリケーション統合が可能です。

### Python環境での利用例

ローカルまたはクラウド上のPython実行環境で、Hugging Face Transformersを用いて推論する場合のサンプルです。

```bash
pip install torch torchvision torchaudio
pip install accelerate
pip install transformers
```

```python
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

device = "auto"
model_path = "ibm-granite/granite-3.1-8b-instruct"
tokenizer = AutoTokenizer.from_pretrained(model_path)
model = AutoModelForCausalLM.from_pretrained(model_path, device_map=device)
model.eval()

chat = [
    { "role": "user", "content": "Please list one IBM Research laboratory located in the United States. You should only output its name and location." },
]

chat = tokenizer.apply_chat_template(chat, tokenize=False, add_generation_prompt=True)
input_tokens = tokenizer(chat, return_tensors="pt").to(device)

output = model.generate(**input_tokens, max_new_tokens=100)
result = tokenizer.batch_decode(output)
print(result)
```

これにより、IBM Researchの米国内ラボについての簡潔な回答が得られます。ユーザーのドメイン固有の指示や、RAGとの組み合わせにより、ドキュメント検索・要約・翻訳・関数呼び出しなどのユースケースに展開可能です。

---

## まとめ

**Granite-3.1-8B-Instruct**は、前身のGranite-3-8b-instructよりも長文対応能力や命令追従精度、RAG・関数呼び出し機能などが強化されており、より実用的な大規模言語モデルへと進化しています。

多言語対応や128Kトークンのコンテキスト処理により、巨大なテキスト資源を扱うビジネス上の課題解決に貢献します。
watsonx.aiプラットフォーム上で今すぐ利用可能です。
『Udemy無料』PDF・Word・PPT 業務の自動化学習動画



有料のイメージが強いですが、無料もあるので今回そちらを紹介します！
キーワードは「業務の自動化」　

##  1.　python　×　pdf

https://www.udemy.com/course/python_pdf/

### 💛概要💛 
PythonでPDFを操作する方法を学ぶためのPyPDF2・pdfminer解説講座が登場。
PyPDF2およびpdfminerの使い方を学び、PDF操作に関する繰り返し作業をより効率的に行いましょう！


### 💚具体的に学べる内容💚
・PDFからテキストを抽出する方法
・PDFを結合・分割する方法
・PDFを暗号化する方法
・PDFに透かしを入れる方法


### 🧡何に役立つか🧡
pdfを扱う仕事がある人におすすめ。YouTubeではまとめられていない情報が多々あるが、１から解説していてわかりやすい。


##  2.　python　×　Word


https://www.udemy.com/course/python-docx_basics/

### 💛概要💛
PythonでWordを自動化する方法を学べるpython-docx解説講座が登場。
python-docxとはPythonでWordファイルの読み取り・書き込みを自動化することができるライブラリです。

### 💚具体的に学べる内容💚
・Wordファイルを新規作成する方法
・段落テキストを挿入する方法
・テキストのスタイル（太字など）を設定する方法
・箇条書きリストを作成する方法
・数字付きリストを作成する方法
・図の挿入方法
・表の挿入方法
・既存のWordファイルを読み取る方法
・既存のWordファイルに段落テキストを挿入する方法
・既存の段落テキストの文字列を置換する方法



### 🧡何に役立つか🧡
Word操作の自動化に興味がある人。繰り返し作業の自動化に興味がある人におすすめです。　どこの企業に行っても使うスキルなので知っていて損はないと思います。


## 3. python　×　PPT


https://www.udemy.com/course/python-pptx_basics/


### 💛概要💛
PythonでPowerPointを自動化する方法を学べるpython-pptx解説講座が登場。
python-pptxとはPythonでPowerPointファイルの読み取り・書き込みを自動化することができるライブラリです。
python-pptxの使い方を学び、PowerPointの繰り返し作業を自動化しましょう！


### 💚具体的に学べる内容💚
・PowerPointファイルを新規作成する方法
・新しいスライドを追加する方法
・テキストボックスを挿入する方法
・表を作成する方法
・グラフを作成する方法
・画像を挿入する方法
・文字のスタイルを変更する方法


### 🧡何に役立つか🧡
PowerPoint操作の自動化に興味がある人、繰り返し作業の自動化に興味がある人におすすめ。こちらも同様、毎日や毎週、年単位でも同じ発表資料を使用する場合、自動化しておくと効率が良いです。



## 最後に
いかがでしょうか？　Excelはよくpythonと使われていますが、Yputubeの方が充実していると感じたので載せませんでした。
無料でここまでの情報が知れるのは本当にありがたいです。
どの人間も、1日は24時間。様々な業務を少しでも自動化し、自分の時間を増やしましょう！
ODC Studio 1.5.0で追加されたEntity Actionのラッパー作成機能

[ODC Studio 1.5.0 (Release Notes) - OutSystems Support](https://success.outsystems.com/support/release_notes/outsystems_developer_cloud_releases/odc_studio/#odc_studio_1.5.0)で、Entity ActionのラッパーActionを簡単に作成する機能が追加された。

この機能について、動作確認してみる。
~~なお、2024/12/17時点ではドキュメントは無さそう。~~
公開された。ドキュメントの項目を参照。
Product Releases and Updates ->
[Entity Actions Wrappers Accelerator | OutSystems](https://www.outsystems.com/product-updates/crud-wrappers/)


# 修正履歴
2024/12/18 Product Releases and Updatesとドキュメントが出ていたので反映

# 環境情報
ODC Studio (Version 1.5.0)

# 機能概要
Entityが持っているEntity Actionのうち、
- Create
- CreateOrUpdate
- Update
- Delete

に対するラッパーActionを、右クリックメニューから自動作成できる機能。

出来上がるActionは簡単なバリデーションだけ持つ極めて簡素なもの。

# 使い方
対象のEntityを右クリック、Cretae Entity Actions Wrappersを選択。
![スクリーンショット 2024-12-17 22.03.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/36166ec7-d135-f4d3-ad1c-283cf2a450b8.png)

あるいは、特定のEntity Actionを選択して右クリック、Cretae Entity Action Wrapperを選択。

# できるもの
Entityと同名のフォルダができ、その中に、Create/CreateOrUpdate/Delete/Updateのラッパーが自動生成される。
![スクリーンショット 2024-12-17 22.10.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/f4d2a09c-18e6-664e-d42c-cac2e6981835.png)

なお、ここではId以外にIs Mandatory=Yesの属性がないEntityでテストしたため以下の実装になっている。他にもIs Mandatory=Yesの属性があるEntityであれば、その入力チェックは自動作成された。

## ラッパーAction：Create/CreateOrUpdate
バリデーション無しで、シンプルに受け取ったEntity型を元にレコードを作成しIdを返すだけのAction。
![スクリーンショット 2024-12-17 22.13.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/2cb2cfe2-5aab-5a0c-cadc-f2be51daf59c.png)

CreateOrUpdateも流れは同じで、呼ぶEntity ActionがCreateOrUpdateに変わるだけ。

## ラッパーAction：Delete/Update
Idが指定されている（NullIdentifier()でない）ことを確認するバリデーションのみ含む。
![スクリーンショット 2024-12-17 22.16.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/87fe74cb-2037-e82b-b71f-284813ed07fe.png)

Updateも流れは同じ。

# 感想
機能としては、非常にシンプルなラッパーActionが出来上がるだけ。
Entity Actionに対してラッパーを作成するのはベストプラクティス（つまり、通常はいずれにせよ踏む手順）。簡単なものでもプレースホルダーとして作成出来るのはわずかに便利。

ただし、実際に使うことを考えると、各ユーザー企業でそれぞれの事情を踏まえた開発標準や内部部品の配置があると思うので
- 現在対象になっている以外のAction（CreateOrUpdateSomeのラッパーや、論理削除など）も追加できると良い
- よくあるパターンとして、Entityに共通で持つ属性を持たせることが多いので、その編集も初期配置しておきたい
- 相関チェックは自動配置はできないだろうからプレースホルダーとコメントくらい置いてあると良い
- 例外処理やログ出力の標準化されていたら事前配置したい

という希望を踏まえると、生成されるラッパーに対してテンプレートを設定（Actionの種類も増やせる様にする）できるとより使い所が増えそう。現段階ではちょっとだけ便利くらい。

# ドキュメント（2024/12/18追記）
[Understanding CRUD operations in ODC > ODC Studio accelerator - ODC Documentation](https://success.outsystems.com/documentation/outsystems_developer_cloud/building_apps/data_management/understanding_crud_operations_in_odc/#odc-studio-accelerator)

以下、このドキュメントから注意を払う価値のありそうな情報を抜き出す。
- ODC Studioからラッパーを作り出す機能はacceleratorというカテゴリに入るようだ
- Entityと同名のフォルダに、Create/CreateOrUpdate/Delete/Updateのラッパーを作るというのはドキュメントで裏付けられる
- 外部DBのEntityは対象外
- EntityがPublicなら公開用のService Actionも同時に生成される
【Unity】SMCPあれやこれやして使ってみた感想

# 概要
「Unity アーキテクチャ」で検索すると、一番にこの記事が出てくる
![スクリーンショット 2024-12-17 21.39.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/fe2a0f55-3899-135a-cf2e-1885d249eb2b.png)

https://qiita.com/IShix/items/5e1450ad8fb7f4a39f22

この記事では、Unityゲーム開発時のアーキテクチャパターンを示してくれている


このアーキテクチャを元に、簡単なゲームを作ってみた時のログを残しておこうと思う

# 実装内容
### 実装方針
![名称未設定ファイル-ページ2.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/5d2d24ac-700b-c714-6eef-3ee26a422901.png)

ViewとLogicのアセンブリを分けるためにこんな感じになった
元のSMCPからは少し変わってしまったが、構想としては同じ

- なるべく外部ライブラリを使いたくなかったので、VContainerを使わなかった
View, Logic, ViewLogicEvent, DataContainerそれぞれの繋ぎこみのために、<b>GamePresenter</b>がある
LifetimeScopeの代わりぐらいの役割
 - ViewとLogicは<b>ViewLogicEvent</b>を経由して疎通する

 - 状態の保持をどこで行うかかなり迷ったが、DataContainerというシングルトンで管理し、Logic, Viewからの参照を許すようにした
書き込みはLogicからだけ許可することで、ある程度変更元を絞っている(コンパイルエラーではなくルールで)

 - View以外での `using UnityEngine`禁止

### 画面遷移
![名称未設定ファイル.drawio (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/cdc87e1f-9edc-8706-b601-4185475673e1.png)
上記画像のように3画面構成
 - Boot画面
真っ暗な画面
ゲームの初期化処理などを行う
 - Title画面
タイトルロゴが表示される画面
インゲームへ遷移するボタンのみが置かれる

 - インゲーム画面
何かしらのインゲーム画面
今回は簡易なテトリスを実装した(細かい部分は適当)

### メッセージ
![名称未設定ファイル-ページ3.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100503/179c0f02-924a-6932-dade-a0914d739056.png)

ViewとLogicの疎通を図にしたもの
あとから考えるとOnUpdateメッセージは正直微妙だと感じた
これがあるなら、ViewからLogicへのメッセージはそれに全部のせればよくなってしまうけど、毎フレーム更新される状態はどこでDataContainerに書き込めば？となってしまった

ここの設計はかなり大事

# コード
内容が公開できないため、プライベートリポジトリに変更


# 感想
小~中規模のプロジェクトにかなり良さそうに感じた
学習コストが安いが自由度が高すぎるため、責務を適切に分解できるレビュー者が必須

また、外部ライブラリを使わないことや, Logicをstaticにしたことで、他アーキテクチャへの引っ越しもできそう
PythonでのLispのシンボルの表現

### symbolの表現

pythonでのシンボルの表現は、こんな風にします。

```
>>> a="print('AAA')"
>>> b="print('BB')"
>>> c="print('C')"
>>> l=['a','b','c']
>>> for x in l:
...     exec(eval(x))
... 
AAA
BB
C
>>> 
```

変数a,b,cがシンボルに当たります。eval()関数で変数xに含まれる'a'という文字列をpythonの変数として扱い、その値を取ってきて、（一段深く評価）、exec()関数で、aの値を実行です。'b'も、'c'も同様です。

pythonではlispのように、eval(3)の値が3になったりはしません。eval(3)はエラーになります。なので、厳密にはpythonではlispのようにatomは扱えません。

LISPでは以下のようになります。

```
[1]> (setq a 'a)
A
[2]> (setq b 'a)
A
[3]> a
A
[4]> b
A
[5]> 

[1]> (setq a 3)
3
[2]> (setq b 'a)
A
[3]> a
3
[4]> b
A
[5]> 

```

これをpythonでやると以下のようになります。

```
>>> a='a'
>>> b='a'
>>> a
'a'
>>> b
'a'

>>> a=3
>>> b='a'
>>> a
3
>>> b
'a'
```

lispでも、(eval a)で、aが未定義だとエラーになります。

pythonは色々と書きやすいけど、インデントがどうもやりにくいです。インデントの代わりに、コードブロックを括弧で括るようになったら最強かも知れません。pythonで、exec関数で処理する自動生成コードを出力する時、インデントだと、調整がややこしいです。

### car,cdr

Pythonで、LISPのcar,cdrを完全に表現する方法はありません。pythonのlistの構造が、LISPの連結リストと違うからです。LISPのコンスセルのように、car部とcdr部が双方ともatomを指したり、コンスセルを指したりすることはできません。しかし、以下のようにlistのcar,cdrを表現することが出来ます。

```
list[0]   # car list先頭要素へのアクセス
list[1:]  # cdr 残りのlist
```
Pythonでコンスセルを直接扱うことは、一般的ではありません。
pythonでもatomとコンスセルを扱えるようになればいいのに

### クォート

pythonでの、クォートは以下のようにします。

```
>>> a='"3"'
>>> eval(eval(a))
3
>>> eval(a)
'3'
>>> a
'"3"'
>>> 
```

コードでのクォートは次のようにやります。

```
>>> def quote(s):
...     return "\""+s+"\""
... 
>>> a=quote('A')
>>> a
'"A"'
>>> 
```

2重のクォートまでできます。n重のクォートはできないようです。

クォート関数くらいあればいいのに。