OmniAICreator/Qiita-1.07M huggingface dataset:
Ansible Galaxyに登録していたroleをCLIから更新する

# はじめに

いつのまにかAnsible GalaxyのWebサイトが更新されていて、Galaxy-NGベースになったようです。

これまでAnsible Galaxyに登録していた自分のroleを更新する作業はGitHubと連携させて、新しいコードとTagをGitHubにpushしてから、Ansible GalaxyのWeb UIで"Import"ボタンを押していました。

どうやら新しいサイトでは管理系操作ができなくなっているようなので、Galaxy NGのドキュメントを確認しつつ対応する手順をメモしておきます。

普段はansible-galaxy installコマンドを実行する以外の操作は使ってこなかったので、まったく勘が働かず少し困ってしまいました。

v3 Tokenを更新する必要がある点以外は、CLIの手順自体に特に新しい情報はないはずです。

# 参考資料

* [https://ansible.readthedocs.io/projects/galaxy-ng/en/latest/](https://ansible.readthedocs.io/projects/galaxy-ng/en/latest/)

# 操作手順

## 環境

Galaxyに登録するrole群は、作業環境の~/ansible/dev/以下にディレクトリが並ぶ形で保存しています。


```bash:
$ cd ~/ansible/dev/
$ ls 
ansible.cfg                       ansible-homegw-openvpn/           ansible-netflow-nfcapd/  ansible-uoa-metaldap/
ansible-fprobe-ng/                ansible-homegw-postfix/           ansible-nfcapd/          ansible-uoa-opmldap/
ansible-homegw-dnsmasq/           ansible-homegw-pppoe/             ansible-test-metaldap/   ansible-uoa-transldap/
...
```

このディレクトリに後述するansible.cfgファイルを保存していて、``ansible-galaxy role import``コマンドはこのディレクトリで実行します。

## 準備作業

まずAnsible Galaxyサイトにログインします。

* [https://galaxy.ansible.com/ui/](https://galaxy.ansible.com/ui/)

ログイン後にProfileページや、他のページに遷移しても自分が保有するRoleのリストなどは自動的には出てきません。

**Search**メニューから自分の名前を入力し、**Role namespaces**に表示された自分のアイコンをクリックすると自分が登録したroleのリストが表示されます。

ただ、ここでRoleを選択しても参照のみで操作はまったくできませんでした。

## v3 Tokenの取得と保存

**Collections** → **API Token** メニューからTokenを取得して安全な場所に保存しておきます。

"Load Token"ボタンを押すことで再生成され古いTokenは無効化されてしまうようなので、確実に保存しておきます。

## ansible.cfgファイルの作成

作業を実施するカレントディレクトリにansible.cfgファイルを配置します。

テンプレートファイルは次のようになっています。

```text:ansible.cfg
[galaxy]
server_list = beta

[galaxy_server.beta]
url = https://galaxy.ansible.com/api/
token = <your-api-token>
```

**token =** の右辺は先ほど取得して保存しておいたTokenに置き換えます。

## GitHubに登録した新しいTagをGalaxyに登録する

コマンドラインは次のとおり。

"YasuhiroABE"はGitHubのアカウント名で、"ansible-myfavorite-setting"はリポジトリ名です。
meta/main.ymlファイルに"role_name: myfavorite-setting"を指定しています。

```bash:
$ ansible-galaxy -v role import YasuhiroABE ansible-myfavorite-setting
...
===== PROCESSING LOADER RESULTS ====
enumerated role name myfavorite-setting

===== COMPUTING ROLE VERSIONS ====
adding new version from tag: v1.0.17
tag: v1.0.0 version: 1.0.0
tag: v1.0.1 version: 1.0.1
...
```

新しいタグが認識されてroleが更新され、以降のinstallでは更新された最新のタグが取り出されます。

# 考慮点

ansible.cfgファイルにはToken情報が記述されるため、公開Gitリポジトリとは別に管理する必要があります。

ansible.cfg自体はansible-playbook作業ディレクトリには普通に存在する見慣れているファイルなので、Galxy roleの作業環境と手順を整えないとansible.cfgファイルをうっかり誤って公開リポジトリに登録する可能性もありそうで、少し注意が必要です。
Node.jsでAzure Open AIのライブラリ(@azure/openai)を使ってAzure Open AIを使うメモ


[前回の記事](https://qiita.com/n0bisuke/items/9ee0627ea79ccc414b84)で、`The completion operation does not work with the specified model, gpt-35-turbo. Please choose different model and try again. You can learn more about which models can be used with each operation`というエラーがでるという話をしていましたが、どうやら使おうとしているモデルとメソッドの対応がよくなかった模様でした。

タイトル、冗長ですが、、前回は公式OpenAIライブラリでAzure Open AIを使ったので今回の表現で良い気がする...

## 準備

こちらの記事を元に、モデルを準備します。

https://qiita.com/n0bisuke/items/9ee0627ea79ccc414b84

次にライブラリは@azure/openaiを使います。

https://www.npmjs.com/package/@azure/openai

```bash
$ npm i @azure/openai
```

## listChatCompletionsを使ってコピペで試す

systemとuserで指定して回答させます。

**JavaとJavaScriptの違い** を教えてもらいましょう。

```js
const { OpenAIClient,AzureKeyCredential } = require("@azure/openai");

const endpoint = `https://XXXXXXXX.openai.azure.com/`; //エンドポイント
const azureApiKey = `xxxxxxxxxxxxxxxxxxxx`; //APIキー
const deploymentId = "nobisuke-gpt-35-turbo"; //デプロイ名

async function main(){
    const client = new OpenAIClient(endpoint, new AzureKeyCredential(azureApiKey));
    const messages = [
        { role: "system", content: "あなたはプログラミングの先生で、ユーザーはあなたの生徒です。質問に対してユーモアを混ぜて回答してください。" },
        { role: "user", content: "JavaとJavaScriptの違いを教えてください。" }
    ];
    
    console.log(`Messages: ${messages.map((m) => m.content).join("\n")}`);
    const events = client.listChatCompletions(deploymentId, messages, { maxTokens: 256 });
    
    let msg = '';
    for await (const event of events) {
        for (const choice of event.choices) {
            const delta = choice.delta?.content;
            if (delta !== undefined) {
                msg += delta;
                // console.log(`Chatbot: ${delta}`);
            }
        }
    }

    console.log(msg); //結果を出力
}

main().catch((err) => {
  console.error("The sample encountered an error:", err);
});
```

無事にレスポンスが返ってきました。

```bash
$ node app.js
Messages: あなたはプログラミングの先生で、ユーザーはあなたの生徒です。質問に対してユーモアを混ぜて回答してください。
JavaとJavaScriptの違いを教えてください。

JavaとJavaScriptの違いは、名前に「Java」と「Script」という言葉が入るくらいです。まったく別の言語ですよ！Javaはバックエンドで使用されることが多く、堅実でしっかり者です。一方、JavaScriptはフロントエンドで使用され、おしゃべりで活発な性格をしています。Javaはプログラムのコンパイルが必要ですが、JavaScriptはインタープリター方式なので、すぐに動作します。そう、JavaとJavaScriptは見た目が似ているかもしれませんが、中身はまったく別物なのです！思考停止しないでくださいね。
```

なるほど分かりやすい(?)ですね

## Chat CompletionsとCompletionsの違い

ここの違いが分かってなくてなんかコード動かないなと思ってましたが、`.listChatCompletions()`はgpt-3.5-turboでも使えるけど、`.getCompletions()`はgpt-3.5-tourboでは使えない模様です。

https://blog.micheam.com/2023/08/09/openai-chat-completions-vs-completions/

名前紛らわしいですね。。
QA技術勉強会をやってみた

はじめまして。
今回は半年にわたって行ったQA技術勉強会についてどういう過程でおこなったのかを記事にしました。
社内で勉強会を検討している方に少しでも参考になればと思います。

# 流れ
そもそも、なぜQA技術勉強会をおこなおうと思ったかについて説明します。
弊社はゲームをはじめとするエンターテインメント系のサービスを展開しており、QAグループの社員はそれぞれのサービスへのQAの管理を行っています。
365日提供しているサービスのため、繁閑の差はあれど基本的には常にQA管理業務が発生します。
そのため目の前の業務ばかりに注力してしまう傾向が強く、新しいQA技術情報を理解し導入するといった業務改善が滞っているという課題感がQAグループにはありました。
そこで今回、QAグループの社員へのインプットの場を設けることで、グループ全体の技術力向上を目的にQA技術勉強会を開催しました。

# QA技術勉強会の進め方
## 方針の決定
QA技術勉強会を開催するにあたり、まずは方針の検討を行いました。
QAに関する技術はテストケース作成手法といったテスト実施現場で活用する技術からQA体制運用時に使用するプロジェクトマネジメント知識まで多岐にわたります。
そのため勉強会のターゲットを誰にするか、どういうことを伝えたいかにより内容が大きく変わってきます。
今回は技術に関するインプットが少ない傾向にあるQAグループの社員に様々な技術に触れてもらうことが発端でしたので「直接的 / 間接的問わずQA業務に活かせる様々な技術を伝える」をテーマにしました。
また副次的な効果として、あわよくば社員に勉強の習慣をつけたいという考えがあったため「勉強会の曜日は水曜に固定する」など細かい方針も合わせて決めました。

## 個々のテーマの決定
方針が決まった後、具体的にどのような技術や知識を取り扱うか決めました。
まずはブレインストーミングの形式でQA業務に活かせそうな技術や知識を挙げました。
その結果、我々がQAを仕事としていることが起因して、伝えたい技術を考えるとどうしても「QA技術」に偏ってしまいました。今回のテーマは「直接的 / 間接的問わずQA業務に活かせる様々な技術を伝える」であるため方針に若干反してしまいます。
そこで、挙がった技術や知識を「QA技術」「EN知識」「統計知識」というようにカテゴリ分けを行い、全体のバランスを考えながらテーマを決定しました。
検討過程の表を下記に示します。
![きーた1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321384/0fc4b325-a29b-5d6f-53fb-a7e1530e368f.png)


検討の結果、下記の5つを勉強会のテーマとして決定しました。
- テスト設計
- FMEA
- ITパスポート
- プログラミングとアルゴリズム
- Agileとリスクベースドテスト

## 勉強会の実施
テーマが決まったあとは担当テーマごとに資料作成を行いました。
技術や知識をそのまま共有するだけでなく、実際のQA現場に活かせるようにアレンジしつつ資料を作成しました。
例としてFMEAに関する説明資料を示します。
![きーた2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321384/3d211cc2-4267-c07f-6c6a-610765bfe6d6.png)
![きーた3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321384/364278c8-d7ea-31a1-6bf8-197825d96235.png)



# ふりかえり
## 勉強会の進め方で良かった点
振り返ると、テーマとした「直接的 / 間接的問わずQA業務に活かせる様々な技術を伝える」が非常に良い方針だったと感じました。
実施後に受講者を担当者としたアンケートを行ったのですが、QA技術以外の講義において「他業界の知見を得られたことがポジティブだった」といった意見が多く見られました。
QA技術以外については、そもそも知らないと学ぶことができないので、未知の知識を知れたこと自体に価値があると受講者が感じたのではと考えています。
QA業界は様々な経歴を持った方が多いことに起因して、各々が持っている知識が大きく異なるケースも多いと思いますので、もし勉強会を検討されている方がいましたら参考にしてみても良いのではと思います。

## 最後に
このような過程を経て全8回のQA技術勉強会を無事に完遂することができました。
振り返ると聴講者はもちろん、講師陣の学びも非常に大きかったように思います。
自分の知っている技術や知識を他者に伝える過程で、あらためてその技術や知識についての理解が深まったように感じました。
もちろん講師陣の負荷も無視はできません。
方針決定や資料作成の準備など、通常の業務がある中で行う必要があるため大変ではありましたが、それを鑑みても非常に有意義だったと思います。


記事は以上です。
同じような課題を感じている方や勉強会を検討されている方に少しでも参考になれば幸いです。
Workato Tips

## はじめに
こんにちは。
今回はWorkatoを使用している中でのプチTipsをご紹介します。

## ①メール通知機能
開発者が指定した条件でレシピ(処理)を作成することで簡単にメール通知を行うことができます。
結論からいうと以下ステップを設定することで実現できます。

![画像.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3528794/de05def9-123f-d103-1085-4360c0ac4104.png)
<br>
編集画面は下記のようになっており各設定内容をご説明します。  

![画像 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3528794/f9364483-290d-9c9c-ed33-5147479ab1ec.png)


To：誰に送るか（複数の場合はカンマ区切り）
Subject：件名
Email type：テキストかHTML
Message：メール送信の内容
※図のようにtimestampなどのデータピルを設定することで必要な情報を送信設定することができます。
<br>
![画像 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3528794/b743df9d-ff46-09b5-b13c-82d3ce259dbb.png)
Cc：ccの設定も可能　※Bccも可能
Attachments：添付ファイル　※詳細設定が可能ですが今回は割愛します
<br>
このステップをレシピに組み込むことでメール通知が可能になります。
当然トリガーを設定しなければメール通知は来ないので、メールを送りたい発火条件も併せて作成しましょう！！


## ②Workatoで日付形式を変更する
Workatoで05-Dec-23を05-12-2023に変更する方法をご紹介します。
※Workatoで使用できるRubyを使います。
<br>
↓↓↓ 実際のコードは以下です。
```ruby:qiita.rb
[date].strftime("%d-%m-%Y") ##outputs "05-12-2023"
```

こちらは海外関連システムでの変換などで活用できるかと思います。
Ruby初心者の方はぜひ！！

## おわりに
今回はWorkatoで使える小ネタを２点ご紹介しました。
特に①のメール通知に関してはいざ実装しようとすると意外に参考文献が少なく苦労しましたので、少しでも誰かの役に立てれば幸いです。

最後まで見て頂きありがとうございました。

##
株式会社ジールでは、初期費用が不要で運用・保守の手間もかからず、ノーコード・ローコードですぐに手元データを分析可能なオールインワン型データ活用プラットフォーム「ZEUSCloud」を提供しております。
ご興味がある方は是非下記のリンクをご覧ください：
https://www.zdh.co.jp/products-services/cloud-data/zeuscloud/?utm_source=qiita&utm_medium=referral&utm_campaign=qiita_zeuscloud_content-area
SQLAlchemyを使って１つのテーブル内で同じ外部キーを複数紐づける

# 概要
FastAPI で SQLAlchemy を使用してる際に「**１つのテーブル内で同じ外部キーを複数持つ場合の `models.py` の記述方法**」に手こずったので備忘録として残しておきます。

# やりたいこと
以下のような ２ つのテーブルが存在していると仮定します。
このとき、「**user テーブルの image_id1 と image_id2 の 2 つの id を image テーブルの id と紐づけた外部キー制約を設定したい**」状況を考えます。

 【image】
| id   |     type      | 
| --- | ----------- | 
| 1 | 3| 
| 2　　| 5 |
| 3　| 7　| 
| 4　| 8　| 

【user】
| id   |     image_id1      | image_id2 |
| --- | ----------- | ----------- | 
| 1 | 2| 1 |
| 2　　| 3 | 4 |
| 3　| 1　|  3 |
| 4　| 4　|  2 |

テーブルを作成するクエリは以下です。
```sql:create_table.sql
CREATE TABLE images (
    id INT NOT NULL,
    type INT NOT NULL,
    PRIMARY KEY (id),
    UNIQUE (id)
);

CREATE TABLE users (
    id INT NOT NULL,
    image_id1 INT NOT NULL,
    image_id2 INT NOT NULL,
    PRIMARY KEY (id),
    FOREIGN KEY (image_id1) REFERENCES images (id),
    FOREIGN KEY (image_id2) REFERENCES images (id)
);
```

# 成功パターン
```python:models.py
from sqlalchemy import Column, Integer, ForeignKeyConstraint
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class Images(Base):
    __tablename__ = "images"
    id = Column(Integer, nullable=False, unique=True)
    type = Column(Integer, nullable=False)
    users = relationship("Users", back_populates="images")

class Users(Base):
    __tablename__ = "users"
    __table_args__ = (
        ForeignKeyConstraint(
            ["image_id1", "image_id2"],
            ["images.id", "images.id"],
        ),
    )
    id = Column(Integer, nullable=False, unique=True)
    image_id1 = Column(Integer, nullable=False)
    image_id2 = Column(Integer, nullable=False)
    images = relationship("Images", back_populates="users")
```
ポイントは `__table_args__` に `ForeignKeyConstraint` を指定する際に、image_id1 と image_id2 それぞれに `images.id` を紐づけてあげることです。

# NGパターン
以下のパターンはどれも NG でした。
```python:NGパターン１
...
image_id1 = Column(Integer, ForeignKey("images.id"),nullable=False)
image_id2 = Column(Integer, ForeignKey("images.id"),nullable=False)
...
images = relationship("Images", back_populates="users")
...
```
```python:NGパターン2
...
image1 = relationship("Images", foreign_keys=[image_id1], back_populates="users")
image2 = relationship("Images", foreign_keys=[image_id2], back_populates="users")
...
```
```python:NGパターン3
...
image = relationship("Images", foreign_keys=[image_id1, image_id2], back_populates="users")
...
```
```python:NGパターン4
...
class Users(Base):
    __tablename__ = "users"
    __table_args__ = (
        ForeignKeyConstraint(
            ["image_id1"],
            ["images.id"],
        ),
        ForeignKeyConstraint(
            ["image_id2"],
            ["images.id"],
        ),
    )
...
```
# 教訓
**複数のカラムにまたがる制約は `__table_args__` に追加しましょう。**
【Python】「`Sequence[str]`は`str`」論争に決着をつける`useful_types.SequenceNotStr`

## はじめに

よく、Pythonの関数の引数へ型アノテーションをするとき、`tuple[str, ...]`でも`list[str]`でも受け取れるようにしたいということがあると思います。

そのときに

```py
def foo(a: list[str] | tuple[str]): ...
```

のように`Union`を使って書くと冗長感があるし、他のシーケンス型を受け入れられなくなるということがあります。

しかし`Sequence[str]`を使ってアノテーションしようとすると、下記issueにあるように、「`Sequence[str]`は`str`」であるので、**ただの文字列型も受け入れられてしまう**という欠点があります。

https://github.com/python/typing/issues/256

```py
from collections.abc import Sequence

def foo(a: Sequence[str]):
    """`('hoge',)`や`['hoge', 'fuga']`を渡して欲しいが、`'hoge'`のような単なる文字列は渡してほしくない"""
    ...


foo(("",))  # Valid
foo(())  # Valid  # 空tupleは長さ0のT型シーケンスと判断されるため
foo([""])  # Valid
foo([])  # Valid  # 空tupleと同じ理由
foo("")  # Validになってしまう。本来咎めてほしい
```

その解決策として提案されたのが、`useful_types.SequenceNotStr`です。

## `useful_types`について

`typing`、`typeshed`や`mypy`のコアコントリビューターが参画し、「痒いところに手が届く」型ヒントシンボルを提供しているリポジトリです。

https://github.com/hauntsaninja/useful_types/

## `SequenceNotStr`の使用例

`useful_types`をインストールしてimportして、引数にアノテーションするとこのようになります。
```py
from useful_types import SequenceNotStr

def foo(a: SequenceNotStr[str]): ...


foo("")  # Invalid
foo(("",))  # Valid
foo(())  # Valid
foo([""])  # Valid
foo([])  # Valid
foo({""})  # Invalid
foo({"": ""})  # Invalid
foo(iter([""]))  # Invalid
```

`SequenceNotStr[str]`と型付けされた変数に、ただの文字列を渡すと静的型チェッカーはエラーを表示します。
しかし文字列のリストやタプルであれば、エラーを表示しません

また、「配列」であっても
- `set[str]`のように順番を考慮せず`index`がないもの
- `dict[str, Any]`のように`__getitem__`にスライスを受け取れないもの
- `Iterator[str]`などのイテレータ(`Sequence`の基底クラス)

がアサインされると、静的型チェッカーはエラーを表示します。

ただし、コーダーが直接インスタンス化するイテラブルはたいてい`list`や`tuple`で、これらは組み込み型(組み込み関数)なので、「キャストができない」ということで困ることはほとんどないでしょう。

## 実装

なぜこのようなことができるかは、[ソースコード上にコメント](https://github.com/hauntsaninja/useful_types/blob/f4b16e3d26a7534b2953404359cf151ffd897910/useful_types/__init__.py#L284)がされています

```py
# This works because str.__contains__ does not accept object (either in typeshed or at runtime)
class SequenceNotStr(Protocol[_T_co]):
    ...
    def __contains__(self, value: object, /) -> bool: ...
    ...
```

:::note info
`str.__contains__`が`object`を受け入れられない(`typeshed`でも実行時でも)ので、これは期待通りの働きをする
:::

## まとめ
長年([`typing`にissueが投稿されたのは2016年7月](https://github.com/python/typing/issues/256))問題となっていた「`Sequence[str]`は`str`」は`useful_types.SequenceNotStr`によって一つの解決策がもたらされました。

一方、現在では[`typing.Literal`](https://docs.python.org/ja/3/library/typing.html#typing.Literal)もあるので、渡したい文字列種類が限定されるのであれば、`Sequence[Literal[...]]`を使うことで、どんな文字列を使うべきかを型アノテーションで伝えることができるので、よりコードをロバストにできると考えています。
Git 操作の速度を上げる .gitconfig のエイリアス (秘伝のタレ)

# .gitconfig

```
[alias]
  # 普通のエイリアス
  ck = checkout
  br = branch
  st = status -s
  cm = commit

  # 現在のブランチを返す
  # 他のgitエイリアスに組み込むためのエイリアスで、直接は利用しない
  current = !git symbolic-ref --short HEAD

  # いまの作業状態で、てきとうなコミット名でコミットする
  # コミット名を考えたくない時に使う
  update = !git add . && git commit -m "update"

  # なにも変更差分がない状態でコミットを作ってpushする
  pr = "!sh -c 'git checkout -b $1 && git commit --allow-empty -m $1 && git push' -"

  # 今の作業内容で新規コミットを作る ( add + commit )
  create = !git add . && git commit
  cr = !git create

  # 今の作業内容をammendして反映する ( add + commit --amend )
  forget = !git add . && git commit --amend
  fg = !git forget

  # 現在のコミットを壊してコミット未反映状態にする
  break = reset HEAD^

  # コミットされていないものはすべて消す
  vanish = !git reset . && git checkout . && git clean -fd

  # rebaseでもmergeでもcherry-pickでもabortする
  abort = !git rebase --abort || git merge --abort | git cherry-pick --abort

  # rebaseの時の変更を反映する
  change = !git add . && git rebase --continue

  # 現在ブランチをリモート(origin)からpullする
  pull-from-origin = !git pull origin $(git current)

  po = pull-from-origin

  # 現在ブランチをリモート(origin)の最新の状態に書き換える
  reset-current = !git fetch && git reset --hard origin/$(git current)

  # localで現在のブランチ以外を全て削除する
  delete-branches = !git branch | xargs git branch -D
```



# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ


# Twitter

https://twitter.com/YumaInaura
相互情報量

## 前提
単語の意味はその周囲にある単語によって決定される（分布仮説）ので、周囲にある単語が類似している＝その単語の意味が類似しているとみなすこともできる
- 例
    - `the car`という単語の連続はよく見るが、`car drive`という2つの単語には明らかに関連性がある
    - しかし`the`の出現頻度が高いのでカウントベースの方法では「`car`という単語は`drive`という単語より`the`という単語の方が関連性が高い」ということになる（実際の感覚とはかなりズレる）

これには単語の出現頻度が悪さをしている。`the`は出現頻度がめちゃくちゃ多いので、色々な単語との関連性を示しやすい。出現頻度を考慮して単語同士の関連性を関連性をはかりたい。

## 相互情報量の導入
相互情報量(Pointwise Mutual Information)の数式は以下
```math
PMI(x,y) = \log{2}{\frac{P(x,y)}{P(x)P(y)}}
```
分母の$P(x,y)$は単語`x`と単語`y`が共起する確率、$P(x)$と$P(y)$は文中に単語`x`,`y`が出現する確率を示す。
共起する確率を「それぞれ文中にどれだけ出現するか」で除することで、頻度による偽の関連性を取り除くことができる。
実際には共起回数が0の時にPMIが-∞に発散するので、実用上は正の相互情報量(Positive PMI)が用いられる。
```math
PPMI(x,y) = MAX(0,PMI(x,y))
```

## 共起行列をPPMIの行列に変換してみる
以下のような文章`text`について
```python 
text = 'You say goodbye and I say hello.'
```

共起行列`C`は以下のようになる
```python
C = np.array([
       [0, 1, 0, 0, 0, 0, 0],
       [1, 0, 1, 0, 1, 1, 0],
       [0, 1, 0, 1, 0, 0, 0],
       [0, 0, 1, 0, 1, 0, 0],
       [0, 1, 0, 1, 0, 0, 0],
       [0, 1, 0, 0, 0, 0, 1],
       [0, 0, 0, 0, 0, 1, 0],
], dtype=np.int32)
```
相互情報量に変換すると以下のようになる。ほぼ0だから次元削減したくなるが、コーパスが増えると計算量が指数関数的に増えるのでミニバッチで少しずつ計算しよう、という思想になる。word2vecの始まり。
```py
[[0.        1.8073549 0.        0.        0.        0.        0.       ]
 [1.8073549 0.        0.8073549 0.        0.8073549 0.8073549 0.       ]
 [0.        0.8073549 0.        1.8073549 0.        0.        0.       ]
 [0.        0.        1.8073549 0.        1.8073549 0.        0.       ]
 [0.        0.8073549 0.        1.8073549 0.        0.        0.       ]
 [0.        0.8073549 0.        0.        0.        0.        2.807355 ]
 [0.        0.        0.        0.        0.        2.807355  0.       ]]
```
## 大いに参考
https://github.com/oreilly-japan/deep-learning-from-scratch-2
Behaviourで共通の機能を実装する

- [Behaviourで共通の機能を実装する](#behaivorで共通の機能を実装する)
  - [Behaviourの定義](#behaviourの定義)
  - [Behaviourの実装](#behaviourの実装)
  - [実装するモジュールで構造体を定義していた場合](#実装するモジュールで構造体を定義していた場合)


# Behaviourで共通の機能を実装する

Elixirには**Behaviour**という機能があり、共有する機能(関数)を定義することができる。

定義したBehaviourをモジュールに実装することで、定義に沿った関数の実装を行うことができる。

## Behaviourの定義

Behaviourを定義する際には通常のモジュールの作成に加え、<font color="red">`@callback`</font>によって**共有する関数の名前と戻り値**を定義する。

```elixir
defmodule Action do
  @callback say(name: String.t()) :: String.t()
end
```

## Behaviourの実装

定義したBehaviourを他のモジュールに実装するためには、<font color="red">`@behaviour`</font>によって**実装するBehaviour**を指定する。

```elixir
defmodule Dog do
  @behaviour Action

  def say(name), do: "#{name}: わんわん！"
end
```

## 実装するモジュールで構造体を定義した場合

Elixirの**構造体はモジュールである**ため、構造体の定義と一緒に記述することができる。

```elixir
defmodule Cat do
  defstruct [:name]
  @behaviour Action

  def say(name), do: "#{name}: にゃーん!"
end
```

しかしこの場合は「**構造体にBehaivourを実装している**」とは言わない。

まずElixirの構造体は、Rustなどの構造体とは<font color="red">全く異なるもの</font>ものである。

Rustの構造体は、**trait**と**impl**によって共通の関数を実装することができるので、
オブジェクト指向言語の**クラス**に近い使い方をすると言える。

これに対してElixirの構造体は、<font color="red">**定義されたキーを持つマップ**</font>である。

つまり`インスタンス =  %構造体{}`から生成したインスタンスは**マップ**であり、そのため`インスタンス.関数()`のように関数を呼び出すことができない。

よってElixirでは**モジュールから関数を呼び出す**ことはできるが、**構造体**から呼び出すことはできない。

それは、構造体のフィールドへのアクセスが`構造体.キー`であり、マップから関数を呼び出せないからでもある。

またそれは`is_map(インスタンス)`を実行することで理解することができる。
[Unity] Corgi Engine + Rewiredの初期設定方法

Corgi EngineにRewiredを追加適用するときに手間取ったので手順をメモしておく。

1. Corgi EngineをPackage Managerからインポート
2. RewiredをPackage Managerからインポート
3. Unityエディタのメニューバーから Window > Rewired > Integration > Corgi Engine > Install Integration Packを選択
4. Unityエディタのメニューバーから Window > Rewired > Integration > Corgi Engine > Setup > Run Setupを選択
5. Unityエディタのメニューバーから Window > Rewired > Integration > Corgi Engine > Create > Rewired Input Managerを選択。シーンにRewired Input Managerが生成される。
6. Corgi EngineのInput Managerを使用していれば削除する。**Corgi EngineのDemoシーンをベースにして開発している場合はカメラにInput Managerが付いているのでこれを削除する。**
7. 生成したRewired Input ManagerにComponent > Corgi Engine > Manager > Rewired Input ManagerをAdd Componentする。

以上です。
C#備忘

自分用備忘も兼ねて

## 文字関係 文字数の取得・置換・抜き出し
```C#
//文字列の長さを取得
string mozi = "aaaaaa";
int mozilen = mozi.Length;

//置換
string mozi = "aaaaaaaa";
mozi = mozi.Replace ("a","b");//a⇒bに置換

//抜き出し
string mozi = "0123456";
string a = mozi.Substr(0,2);//01が抜き出される
string b = mozi.Substr(2,2);//23が抜き出される
```
## webページにアクセス（アクセスのみ）
```C#
string url = "https://-----------------";
System.Diagnostics.Process.Start(url);
```
## ラベルの内容を更新
```C#
label1.text = "aaa";
label1.Refresh();
```

## 入力情報を送る　SENDKEY
```C#
string sk ="abc";
SendKeys.Send(sk);
SendKeys.Send("{ENTER}");
```

## 音声ファイル（wavファイル）を再生する
```C#
//WAVEファイルを再生する
private void PlaySound(string waveFile)
{
    //再生されているときは止める
    if (player != null)
        StopSound();
    //読み込む
    player = new System.Media.SoundPlayer(waveFile);
    //非同期再生する
    player.Play();
    
    //ループ再生する場合
    //player.PlayLooping();
    
    //再生し終えるまで待機する場合
    //player.PlaySync();
}

//再生されている音を止める
private void StopSound()
{
    if (player != null)
    {
        player.Stop();
        player.Dispose();
        player = null;
    }
}

//音源を再生
PlaySound("sample.wav");

//再生を停止
StopSound();
```
## webページから情報を取得　スクレイピング
```C#
string url;
url = "http://-------------------";
string html = "";

//TLS1.2を有効にする
ServicePointManager.SecurityProtocol 
    = SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
    
//アクセスに失敗することがあるのでtry～catchを入れておく
try
{
    var req = (HttpWebRequest)WebRequest.Create(url);
    // 指定したURLに対してReqestを投げてResponseを取得
    using (var res = (HttpWebResponse)req.GetResponse())
    using (var resSt = res.GetResponseStream())
    // 取得した文字列をUTF8でエンコードします。
    using (var sr = new StreamReader(resSt, Encoding.UTF8))
    {
        // HTMLを取得
        html = sr.ReadToEnd();
    }
} catch (Exception ex)
{
    //エラー時の処理
}
```
PostgreSQLでNULL値を＝を使って評価してみる

この記事は[NTTコムウェア AdventCalendar 2023](https://qiita.com/advent-calendar/2023/nttcomware) 16日目の記事です。


# はじめに

NTTコムウェアの星合です。
普段は社内でデータベース関連のサポートやトラブル対応、性能検証などをしています。
最近では社外でのコミュニティ活動にも力を入れており、[Pgpool-II](https://www.pgpool.net/docs/latest/ja/html/)のコミッタや[PostgreSQLの開発](https://github.com/sraoss/pg_ivm)も行ってます。

今回は、小ネタとして知らない人が多そうなPostgreSQLでNULLの値を **=** 演算子で評価する方法を紹介します。


:::note alert
なお、SQL標準では `値 = NULL`では真偽値を得られないのが正解です。
そのため、実際のシステム開発では`IS NULL`句を使うようにしてください。
:::

# NULLについて

プログラムで扱いの難しいデータの一つとして、**NULL** (＝何もない状態や不明な状態を表す値) があるかと思います。
PostgreSQLデータベースでは、評価条件にNULLが含まれると演算結果はTrue or False ではなく全てNULLという結果になります。

```sql
[postgres@localhost ~]$ psql test
psql (16.1)
"help"でヘルプを表示します。

test=# \pset null (null)
Null表示は"(null)"です。
test=# 
test=# SELECT 1 = NULL;
 ?column?
----------
 (null)
(1 行)
test=# SELECT NULL = NULL;
 ?column?
----------
 (null)
(1 行)
```

:::note info
PostgreSQLのpsqlクライアントでは、以下のコマンドでNULLの表示形式を変更できます。
　``\pset null (null)``
デフォルトではNULLは空欄で表現されるため、今回は見やすいように **(null)** という文字に変更してます。
:::

そのため、**NULL** を判定するためには専用の `IS NULL` や `IS NOT NULL`条件で評価するのが通常です。

```sql
test=# SELECT NULL IS NULL;
 ?column?
----------
 t
(1 行)
```

ですが、実はSQLの書き換え以外にも **=** の演算子そのままでNULLを評価する方法もあります。

# transform_null_equalsパラメータ

PostgreSQLでは `=` 演算子に限り、NULLを比較できるようにする[transform_null_equals](https://www.postgresql.jp/document/15/html/runtime-config-compatible.html#GUC-TRANSFORM-NULL-EQUALS) パラメータがあります。

こちらのパラメータをonにすると、 `値 = NULL` の計算を `値 IS NULL` に変換して処理してくれるためNULLであるか判定することができます。

```sql
test=# set transform_null_equals = on;
SET
test=# 
test=# SELECT NULL = NULL;
 ?column?
----------
 t
(1 行)
```

ただし、`= NULL` の条件が変換されるのみとなっており、 `!=` 演算子や `IN(...)` 条件、結合条件などはonにしても結果はNULLのままなので気を付けてください。

```sql
test=# SELECT NULL != NULL;
 ?column?
----------
 (null)
(1 行)
test=# SELECT 404 IN (1,NULL,404);
 ?column?
----------
 (null)
(1 行)
```

# おわりに

ということで、知ってる人があまりいないであろう `transform_null_equals`パラメータについての紹介でした。
本来は`IS NULL`を使うのが標準であり推奨となります。昔、一部の製品でこの標準に対応していなかった背景があり、代替案としてPostgreSQL側でこのパラメータが用意されていました。
また、回避策としても `!=` 条件や `IN(...)` で使えないなど非常に使用ケースが限られる点から、やはり NULL を扱う場合には適切にアプリケーション設計を行う必要があります。


※記載されている会社名、製品名、サービス名は、各社の商標または登録商標です。
【解決策】Google Colabでmoviepyを使用時のImageMagickエラー: 正しいインストール手順




moviepyで動画に字幕を入れようとしたとき、
ImageMagickのエラーで躓いたためメモとして残しておきます。

## 該当コード
```python
txt_clip = TextClip("テキスト")
```


## エラー内容
```bash
OSError: MoviePy Error: creation of None failed because of the following error:

[Errno 2] No such file or directory: 'C:\\\\Program Files\\\\ImageMagick-7.0.8-Q16\\\\magick.exe'.

.This error can be due to the fact that ImageMagick is not installed on your computer, or (for Windows users) that you didn't specify the path to the ImageMagick binary in file conf.py, or that the path you specified is incorrect
```


## 解決策
Google Colabのランタイムを再起動し、以下のコードを実行すると無事終わりました。

```bash
apt update
apt install imagemagick
apt install ffmpeg
pip3 install moviepy
sed -i '/<policy domain="path" rights="none" pattern="@\*"/d' /etc/ImageMagick-6/policy.xml  
```



## ポイント

- `moviepy[optional]`としてインストールすることで、ImageMagickを含むすべての依存関係を一括でインストールできます。
- `ffmpeg`や`imagemagick`は`moviepy`よりも前にインストールする必要があります。
- `'/<policy domain="path" rights="none" pattern="@\*"/d'`というポリシーを削除することで、エラーを回避できます。

最初は日本語で調べていましたが、なかなか解決できなかったため
[GithubのIssue][1]の解決策をひたすら試し、[該当コメント][2]によってようやく解決しました。
感謝。



### 参考

- [MoviePy 公式ドキュメント](https://pypi.org/project/moviepy/)
- [GitHub Issue: ImageMagick Error](https://github.com/Zulko/moviepy/issues/693)
- [GitHub Issue Comment](https://github.com/Zulko/moviepy/issues/693#issuecomment-622997875)

[1]:https://github.com/Zulko/moviepy/issues/693
[2]:https://github.com/Zulko/moviepy/issues/693#issuecomment-622997875
JavaScriptはelse ifが存在しないという話の続き【小話】


https://qiita.com/advent-calendar/2023/javascript

アドベントカレンダー6日目の記事です。

# JSにはelse ifという構文は存在しない


`else if` は `else` と `if` の組み合わせで表現されている、という有名な話があると思うのですが

> 複数の if...else 文をネストすることで、 else if 節を作成することができます。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/if...else

先週コードを書いていると以下のようなTypeScriptコードを生成してしまい（意図せずにPrettierに生成された・・・）、「え？？？else次の行になっているけど動くの？？」みたいなことになったのでその供養に記事をかいてます。

```typescript
const func = (bool: Boolean) => {
  if (bool) return bool;
  else return bool;
}

console.log(func(true))
console.log(func(false))
```

## 結論

普通に動く

[TypeScript: TS Playground](https://www.typescriptlang.org/play?ssl=8&ssc=25&pln=2&pc=1#code/FAYw9gdgzgLgBAMwK4RHAvHAFAIzGAGwC44AhfAgUwEMIBKDAPjgG9g44BLBbPQhgE6UYSARDh8CAbnZxKBKJThCRYiRRkBfYKEhRClAHQEwAcyzJUWGAKSU6dXdAPGzFlCAvUF9x8CA)

コンパイル結果。確かにこれなら動きそうですね。

```js
const func = (bool) => {
    if (bool)
        return bool;
    else
        return bool;
};
console.log(func(true));
console.log(func(false));
```

JSで書き直しても普通に動く。

```js
const func = (bool) => {
  if (bool) return bool;
  else return bool;
}

console.log(func(true))
console.log(func(false))
```

Chromeのコンソールで動かした結果

![スクリーンショット 2023-12-06 15.10.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112929/2c6cf8b8-fa79-47a6-b5a7-4625fa114c20.png)

## MDNでの例

MDNでもきちんとかかれていますのでこのあたりの構文一度チェックしてみてもよいかもです。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/if...else


```js
if (condition1)
  statement1
else if (condition2)
  statement2
else if (condition3)
  statement3
// …
else
  statementN
```

↓

```js
if (condition1)
  statement1
else
  if (condition2)
    statement2
  else
    if (condition3)
      statement3
```

つまり `else if` は else と if



## 参考

### ECMAScriptでの定義

https://tc39.es/ecma262/#prod-IfStatement 

![スクリーンショット 2023-12-06 15.02.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112929/431a9458-f43b-9955-4235-776abed0c719.png)

### 仕様の読み方の参考にした記事

https://qiita.com/righteous/items/32b40029e1a383ee2f97


## 感想

ここまで if, elseの後の `{}` は省略可能ですが、普通にわかりにくくなる場合もあるので、prettierとかで強制的にいれる等、検討してもよいのかなと思いました。

```json
{
    "rules": {
        "curly": "error",
    }
}
```

https://stackoverflow.com/questions/54065344/how-to-get-prettier-to-add-braces-when-missing-on-if-else


Golangのフォーマッターのイメージで、「個人で考えるコードの見た目の綺麗さ」よりも「ある程度チームで納得感ある一意に決まるフォーマット」が優先なのかなと個人的には思いました。


Pythonはelif、Rubyもelsif存在すると思いますが、言語によってさまざまだなと実感した次第
【React】<Component />が表示されるまでの流れ

# はじめに
`<Hello />`のようなコンポーネントは最終的にどうやってブラウザに描画されるの？とふと思ったので、備忘録的にまとめていきます。
つまり、**`React`と`JSX`がどのように連携して`仮想DOM`を構築し、最終的に実際の`DOM`を更新するかをまとめます。**

# コンポーネントの定義
`React`では、コンポーネントは再利用可能なUIの一部を表現します。一般的には個々のファイルに定義され、必要に応じて他のファイルからインポートされます。

```jsx:Hello.jsx
export function Hello() {
  return <h1>Hello, world!</h1>;
}
```

# JSXとReact要素の作成
上記の書き方は`JSX`と呼ばれ、`React.createElement()`の**シンタックスシュガー = 糖衣構文**です。

`React`要素を作成するには、本来このようなAPIを呼ぶ必要があります。
それぞれ`type`,`props`,`children`という引数を取り、React要素を作成します。
```jsx
const element = React.createElement(
  'h1', // type
  null, // props
  'Hello, world!' // children
);
```
一方で、`JSX`ではより直感的に`HTML`に近い書き方でReact要素を作成することができます。
```jsx:
export function Hello() {
  return <h1>Hello, world!</h1>;
}
```
::: note
シンタックスシュガーではありますが、`JSX`から`React`要素を作成するには、`Babel`などのトランスパイラを使用して`JSX`を通常の`JavaScript`に変換する必要があります。これは、ブラウザや`Node.js`は`JSX`を直接理解することができないからです。この変換過程で、`JSX`内のタグは`React.createElement()`の呼び出しに変換されます。
:::

https://babeljs.io/docs/babel-plugin-transform-react-jsx

`<Hello />`は、**トランスパイラ**によって次のようにトランスパイルされます。

```jsx
React.createElement(Hello)
```
これは、`React.createElement`関数が、指定された型（この場合は`Hello`）とプロパティで新しい`React`要素を作成することと同じ意味です。

# 仮想DOMへの追加と差分評価
この`React`要素は、`仮想DOM`に追加され、最終的に実際の`DOM`にレンダリングされます。
仮想DOMに追加するには、`ReactDOM.render`関数を用いることができ、以下の様な引数を取ります。
```jsx
ReactDOM.render(
  //1.React要素,
  //2.DOM要素
)
```
`ReactDOM.render()`が呼び出されると、`React`はメモリ内に`仮想DOMツリー`を作成し、各コンポーネントの状態を管理します。

`React`は実際の`DOM`との結果の差異を計算することで、**ブラウザに表示されていて「実際に表示変更が必要となるコンポーネントのみ」を効率的にレンダリングします。**


```jsx:Hello.jsx
export function Hello() {
  return <h1>Hello, world!</h1>;
}
```


```jsx:App.jsx
import { Hello } from './Hello';

function App() {
  return <Hello />;
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
)
```
```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>React App</title>
</head>
<body>
  <div id="root"></div>
  <script src="./App.js"></script>
</body>
</html>
```

# まとめ
- `JSX`は`React.createElement`のシンタックスシュガー
- `JSX`は`React.createElement`に変換するには`Babel`などの`トランスパイラ`が必要
- `ReactDOM.render`が呼び出され、実際のブラウザとの差分を`React`が評価することで、差分のコンポーネントのみレンダリングされる
エンジニアの面接で大事なこと

この記事は[エンジニア転職Advent Calendar 2023](https://qiita.com/advent-calendar/2023) 25日目のエントリーです。

こんにちはやまぱんです。
私は趣味兼副業として転職エージェントやインフラエンジニアの転職支援、キャリア戦略相談、中長期でのエンジニアへの転職メンター支援などをしています。
また自分自身もエンジニアとしてSIerから外資IT企業への転職経験があったり、本業での面接官もあります。

これらの経験を通してエンジニアの面接で大切な事について、自分なりの意見を書いてみたいと思います。
あくまでも私の経験からの大いなる主観です。
会社もたくさんあるので当てはまらない会社さんも多いと思います。
自分のキャリアとしては インフラエンジニア系のキャリアで SIer → 外資系IT なのでその界隈の方には多く共通する要素があるのではないかと思います。

## モチベ
ネット上の記事をみてると**技術力や未経験だと資格ばかりにフォーカスされているなー**と思ったのがきっかけです。
もちろん、技術力や資格も大事ですが、それ以外にも大事なことがあるなと思います。

## エンジニアの面接で大事なこと
### 社会人としてのマナー的なやつ
いやさすがにその態度「社会人としてNGだるぉおおおおお」いな人がたまにいます。
面接中下ばかり向いてるとか、派手なシャツで面接に臨むとか、敬語がまともにできないとか、技術的な質問内容をググって答えようとするなど。
このような人は採用したとして社内外の人からクレームが来るリスクが高いと判断されると思います。

### コミュニケーション能力
何よりまずこれが大事だと思います。
極端な話、技術力が並外れていてもコミュニティケーション能力に難がある方は相当苦戦すると思います。実際にそれでお見送りにした事もあります。
簡単に言うと、**質問に端的に答えられる、結論から話せる、相手の理解度をケアしながら話せる**といった点が大事だと思います。
面接全体を通じて判断されると思います。
技術的な質問でも、「技術的な説明を相手にわかりやすく伝えることができるか」などでもこういう部分を評価されていたりします。

### マネジメントコスト面(マネジメントリスク)
コミュニケーション能力ともかぶる部分はありますが、マネジメントコストがかかる、マネジメントリスクがあると思われないことが大事です。
上司や現職に対する愚痴が多いなどはそう取られがちです。
これは加点方式というより、減点方式な感じが強いかなという印象。

### 現在の技術力
これは今までの技術的経験を通して推し量られることが多いと思います。
想像しやすいと思いますが、募集要項の技術領域に対して現在の技術力がどの程度ミートしているかです。

### ポテンシャル(未来の技術力)
今現在は期待する技術スタックが無くても、いままでやってきたことを通してキャッチアップ可能かどうか、継続的に技術力を自分で磨いていける人かどうかです。
これには過去の業務への取り組み方とか、継続した自己研鑽やまだベテランではない人の場合は資格などによって推し量られることが多いと思います。

### マインド
これは会社によって最も重視してる度合が異なるかもしれません。
理念などにも通じるところになります。
指摘されたときにいいわけから入る癖がある人は面接でもその
ネガティブよりポジティブ、チャレンジ精神、グロースマインドがあるか、一人称視点で物事を考えられるかといった点です。

### リーダー経験 /マネージャー経験 /部下・後輩育成経験
ある程度シニア層な年齢になってくるとこれらのうちのどれかの経験は聞かれると思います。
50超えてくると必ずこれらの何かしらの経験は必要かと思います。
20代であれば気にすることはないと思います。
どれくらいの年齢から要求されるかは会社次第ですが、早ければ30歳前後からあった方がいいこともありますが、大まかに40代ではあった方がいいでしょう。

### 語学力
これは会社やポジションによって大きくことなると思います。
TOEICが重視されたり、TOEICよりも実際に話せるかどうかが重視されていたり、一概には言えないですが、会社やポジションによっては比重がとても高いです。

## 自分の経験の場合
余談ですが、自分の転職の場合は技術力はへぼへぼでしたが、下記の点を推して転職することができました。
要件の技術スタックもほとんど満たしてませんでした。

+ コミュニケーション能力
+ 火事場でもなんとか自ら考えて乗り越えた経験
+ ポテンシャルPR

## 転職を考えている方へ
経験年数とか技術スタックとか要件満たしてなくても、受かることはあるので気になる求人があればガツガツ応募することをお勧めします！
転職市場・求人は水物なので、会社によっては半年、一年後にはその求人がない可能性も高いです。
チャンスがあれば受かってから考える気持ちで受けてみてもいいかと思います。
ダメだったら自分なりにPDCA回して今後に活かせばいいです。

あと、もし私でよければ簡単に30分程度であれば相談にのりますので適当にコンタクトもらえたらと思います。

## 関連
下記のエントリーの方の転職支援や模擬面接などしました。
怖かったと言われてしまったので反省しています。

> 友人に壁打ちに付き合ってもらい、本気の面接練習をやってもらいました。本番より友人の方が怖かったです。

https://qiita.com/dessin/items/0f9d12b4364a41a0a47d
とらラボ！x YUMEMI.grow「勉強法の勉強会#3」スライド

#### 本スライドについて

- こちらのイベントの LT 用に作成したスライドです
  - https://yumemi.connpass.com/event/301157/

https://yumemi.connpass.com/event/301157/

- LT タイトル
  - 「私が新しい開発言語/フレームワークを習得する際に心掛けている１０のこと」

---

#### 自己紹介

- https://lapras.com/public/hkusu

https://lapras.com/public/hkusu

---

#### 前置き

- あくまで私がどうしているか
  - 誰にでも当てはまるということではない
- 今回の LT の内容の元投稿
  - https://qiita.com/hkusu/items/a73c0c25121be779b8e6

https://qiita.com/hkusu/items/a73c0c25121be779b8e6

---

#### 書籍を読むのは初めは最大2冊まで

- １冊での不足部分を補完する、異なる視点から理解するという意味では、複数冊を読むこと自体は意味がある
- 許容量オーバーになってしまうので初めは２冊ぐらいまでに留める

---

#### とにかくコードを書く、手を動かす

- コードを実際に書いて手に馴染ませる
- 手に馴染んだものは忘れにくい

---

#### 学習曲線を知っておく

![スクリーンショット 2014-11-19 18.36.11.png](https://qiita-image-store.s3.amazonaws.com/0/35733/cc05797a-af2a-7e6b-b9f5-70d26b631644.png "スクリーンショット 2014-11-19 18.36.11.png")

- 停滞期で諦めない

---

#### 時間でなく期間が必要

- 寝ることで脳に定着
- 反復

---

#### 大元を参照する

- 公式のドキュメント
- 公開されているコード

---

#### 識者に聞く

- 高速道路に乗った方が早い

---

#### 仲間を作る

- 一人だと簡単に諦めることができてしまう
- 勉強会、技術コミュニティ

---

#### 文章でアウトプットする

- その過程で体系的な知識の整理ができる
- アウトプットも効果的

---

#### 必ずいつかは理解できる

- 人間が作ったものは人間が理解できる
- コツコツと手に馴染ませていく

---

#### あれこれ手をだしすぎない

- 現実逃避であれこれ手を出してしまいがち
- じっくりと腰を据える

---

〜 END 〜
ノーコード開発なのに盛大にやらかした

# はじめに
この記事は、本番環境などでやらかしちゃった人 Advent Calendar 2023 の7日目です。

https://qiita.com/advent-calendar/2023/yarakashi

私はIT関連企業ではないサービス業の人間ですが、IT関連全般のことをやってます。
現在ノーコード開発としてはかなりメジャーな [Bubble](https://bubble.io/) というプラットフォーム上でサービスを展開しているのですが、そこでのやらかしを共有したいとおもいます。

# Bubbleとは
Qiitaにはノーコードエンジニアはあんまりいなさそうなので説明します。
Bubbleは、プログラミング知識がなくても使えるノーコードプラットフォームです。ドラッグ＆ドロップでウェブアプリを作れるので、、技術がない人でも簡単にアプリ開発が可能です。このプラットフォームのいいところは、見た目のデザインからデータベースまで、全部自分で作れる点。プログラミングがわからなくても、条件分岐やデータ操作などの複雑なことができます。

Bubbleの特徴は、使いやすくてカスタマイズが自由自在。デザインも自分の好きなようにできるし、必要な機能はプラグインで追加できます。Google MapsやFacebookといったサービスと組み合わせるのも簡単。技術者でなくても、自分のアイデアを形にするのにぴったりなツールです。
（by ChatGPT）

# Bubbleのリリース
Bubbleには、わりといい感じのバージョン管理システムがあります。
アプリケーションは、Live（本番環境） と Main（開発環境のメインブランチ） があり、Mainから分岐したいくつかのブランチを切れます。リリースの際には、MainからLiveへのコピー（デプロイ）を行います（サブブランチからのLiveデプロイは不可能）。この際には、コンフリクトの検知や解決（どっちを生かすのか）ができます。

一方、データベースはLive と Dev という２つのバージョンのみで、開発環境の全ブランチはDevデータベースを共有しています。
そして、各テーブル単位にLive ↔ Devの一括コピーが行なえます。部分的なコピー機能などはなく、テーブルまるごとしかありません。

我々のサービスでは、データベースにいくつかのマスタデータ用のテーブルがありました。マスタデータは、DevとLiveで同じものを利用したいので、頻繁にDev to Liveのテーブルコピーを行っていました。

# テーブルコピーのUI
![スクリーンショット 2023-12-06 15.06.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171479/151cfd20-c79f-6627-52c9-67083d07fd2b.png)

こちらの画像をごらんください。これがBubbleのデータベースコピー機能のUIです。
まず、コピーの方向（Live to DevまたはDev to Live）を指定します。
次に、コピー対象のテーブルを選択します。
最後に、呪文を記入してConfirmボタン押下でコピーが実施できます。

そして、コピー対象の選択プルダウンには、「All types」が存在します。
![mosaic_20231206151019.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171479/d81b9f64-1cf2-e0aa-6d45-fa090dadc716.png)


もう、何が起きるか、おわかりでしょうか。

# そして事件は起こった
ある日、私はとあるマスタデータをDevで編集し、それをLiveにコピーしました。

5分後、「なんかログインできないんだけど」という同僚の声。

ん、なんだろう。

Liveのデータベースを見る。Userテーブルの数が明らかにすくない。まるで開発環境のような少なさ…。

もしかして。

## 原因発覚、そして
そう、私はテーブルコピーの対象に「All types」が選択されていたのに気づかず、コピーを実行していたのです。
Live環境のUserを含む、すべてのデータは、Devデータによって置き換えられていました。しかも、まだデータのコピーは完了しておらず実行中。あと何十分かかかりそう。途中で止めることはできない。

止まらない冷や汗。

事情をみんなに説明。
約1時間かかって、データコピーが完全に終了。途中で止めたいのに、止められない、待つしかないという地獄の時間。

今度はBubbleのデータベースリストア機能を使って、事件が起こる前の状態に戻す指示を実行。これまた時間がかかる。

さらに1時間後、ようやく元通りになりました。お客様やチームに、大変ご迷惑をおかけしました。

# 学び
2時間のサービス停止時間によって得られたものは、「ちゃんと確認する」「一人でやらない」ということでした。それ以降、データコピーの際には複数人の監視下で実施するようにしています。

また、自分でUIを設計する際にも、BubbleのこのUIはアンチパターンとして気にするようになりました。
トランザクションデータを含む全テーブルコピーと、マスタデータ1テーブルのコピーという、目的も影響範囲も異なる行為が、全く同じUIで実施できてしまう、という問題。
本来あるべきなのは、テーブル単位に、「このテーブルは一括コピーを禁止する」というような機構をつけ、さらに全テーブルコピーと1テーブルコピーの確認UIに差をつけることでしょう。

# そして、あれから数年
Bubble側も、この問題をようやく認識してくれたようです。
なんと、下記のようにAll typesを選択している際に、注意書きがつくようになりました。
![スクリーンショット 2023-12-06 15.06.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171479/663d53af-fddc-73bc-ea4c-f29789bf2c68.png)

**…こんなんじゃ絶対また事故起こるとおもうよ！！**
【3分De解説】Dockerって何？どこが便利なん？

## 本記事の要約

* Dockerとは「データやプログラムをコンテナで隔離できる仕組み」
* コンテナはDocker Engineでimageという素材を使って作る
* Dockerを使えば、一つのマシンに複数のサーバを構築できる
* Dockerは、OSなどの物理的環境を無視できる

## 背景
Dockerを使ってLaravelの環境構築をしようとしています。

しかしDockerが何かさっぱり分からないまま環境構築をするのもスッキリしないので、基本的理解を作ることにしました。

参考にした書籍は[『仕組みと使い方がわかる Docker&Kubernetesのきほんのきほん』](https://www.amazon.co.jp/%E4%BB%95%E7%B5%84%E3%81%BF%E3%81%A8%E4%BD%BF%E3%81%84%E6%96%B9%E3%81%8C%E3%82%8F%E3%81%8B%E3%82%8B-Docker-Kubernetes%E3%81%AE%E3%81%8D%E3%81%BB%E3%82%93%E3%81%AE%E3%81%8D%E3%81%BB%E3%82%93-%E5%B0%8F%E7%AC%A0%E5%8E%9F%E7%A8%AE%E9%AB%98/dp/4839972745)です。
<img width="50%" height = "50%" src="https://m.media-amazon.com/images/I/61jOLscxM3L._AC_UF894,1000_QL80_.jpg">

コメントや情報の訂正もお気軽にどうぞ！

## Dockerとは
一言で言い表すと「**データやプログラムを隔離できる仕組み**」のことを指します。

そしてDockerは主にサーバで使用されます。

私たちがよく使うPC（クライアント）ではWordやExcelといったソフトウェアが動いていると思いますが、

サーバでも同じくMySQLやApacheといったソフトウェアが動いています。

Dockerを使えばこれらサーバで使うソフトウェアを、ほぼOSごと一台のPC上で隔離することが可能となります。

隔離は「**コンテナ**」という単位で行われます。

### コンテナとは？
ここでいうコンテナに関しては、イ〇バの物置のような倉庫をイメージしてみてください。

「100人乗っても大丈夫」でおなじみのイ〇バの倉庫（コンテナ）に、MySQLやApacheといったサーバを閉じ込めて使えるということです。

**そしてこのコンテナは1台のPCのDockerの容量範囲内で複数作ることができ、MySQLやApacheを複数インストールすることもできます。**

※普通は1台のPC上には1つのサーバ（MySQLなど）しか構築できません


## なぜ隔離する？
それでは、なぜコンテナを使ってプログラムやデータを隔離する必要があるのでしょうか？

というのも、初心者ながら自分がこう思ったからです。

「何で隔離すんの？メリットは？」と。

その答えは、「**隔離すればお互いのソフトウェアを独立して動かせるようになるから**」です。

## 具体例
例えばあるソフトウェア（WordPress）がMySQLを使っていたとします。

そして別のソフトウェア（Laravel）もMySQLを使っていたとします。

そしてWordPressはVer1.0のMySQLに対応しています。

しかしLaravelがVer2.0以降のMySQLじゃないと動かないとなった時、

従来のMySQL（サーバ）は一台のPCに一つしか構築できないため、困るわけです。

**しかしDockerを使えば一台のPC上に複数の、そして異なるバージョンのMySQLを構築できます。**

その意味で、1台のPC上でデータやプログラムを隔離できることには大きなメリットが存在するのです。

## コンテナは持ち運び可能
また、**コンテナは違うPC間での「持ち運び」が可能です。**

そして、Dockerが入ってさえいれば、異なるOSのPCであっても環境構築が容易です。

既にチューニングした環境をあらかじめDockerのコンテナ内に用意しておき、そのコンテナを配布すれば、

一斉に環境構築を済ませることもできます。
【季節外れ】ぼくなつ８月３２日の話【バグ】

# はじめに

プログラマーっぽい記事の内容って何だろうって考えたときに、
「ぼくのなつやすみ」の８月３２日に行くことができるバグが起きた理由についてのお話が浮かんだので、そのことを記事にしていこうと思います。
実際に遊んだことがあるわけではないので、
実況や対談の内容から抜粋して記事を書いていこうと思います。
（季節外れにもほどがある）

# 「ぼくなつ」って？
![517NMhRThQL.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635192/809db718-36a0-a347-24b1-1d49bd1b949a.jpeg)

『ぼくのなつやすみ』は、2000年6月22日にソニー・コンピュータエンタテインメントから発売されたPlayStation用ゲームソフト。『ぼくのなつやすみシリーズ』の第1作。

母親が臨月を迎えたため、8月の夏休みの1か月間、田舎の親戚の家へ預けられた9歳の少年「ボク」を操作し、昆虫採集や虫相撲、魚釣りなどをしていくゲームである。時代設定は1975年（昭和50年）で、北関東のどこかに存在する森や山に囲まれた架空の田舎「月夜野」（つきよの）が舞台となっている。
wikipediaより

# ８月３２日

８月は３１日までなので、本来はゲームの使用上（というか常識的に）３１日の日記を書くと夏休みが終わってしまい、エンディングとなるのですが…
バグというかプログラムの抜けている部分が見つかり、夏休みを終わらせずに次の日を迎えてしまうことができてしまうんですよ。
夏休みが終わらなければ学校に行く必要がなくて最高ですね。
エンドレスエイト！（それは違う作品）

前置きはここまでにして…
実際には存在しないはずの８月３２日以降はゲームとしては動くのですが、家族の顔色が青色になっていたり、体の一部分しか表示されていなかったり、宙に浮かんでいたり、文字化けしていたりします。
この時点でだいぶ不気味ですけど。

実際の８月３２日の様子を見たい方はアブさんの動画を見るとわかりやすいと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635192/978e638f-cc1f-db66-8ee1-d54c40060106.png)

【閲覧注意】「8月32日の恐怖。ぼくのなつやすみの裏技・バグ技」↓
https://youtu.be/eVKRbEhDMc0?feature=shared


なぜこんなのにもめちゃくちゃなのに、ゲームが動き続けることができたのでしょうか。

# このバグを作者が解説
このバグについて解説しているものがあるので、一部抜粋する形で書かせていただきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635192/6a687e4a-60bc-a19d-7d09-8ebe57cfc345.png)

引用先「ぼくのなつやすみの８月３２日について解説（作者本人）」
https://togetter.com/li/46554

（作者）「せっかくなので8月32日を発明してしまった責任者としてはその話をしましょうか？ …あれはぼくなつ１の発売後２年ほど経過してから発見されたものなんです。症状を聞いた瞬間「なんてナイスなバグなんだ」と不覚にも思ってしまいましたｗ その時点では単なる「就寝せずに翌日へ行けるバグ技」です」

（作者）「８月３２日なんてデータは用意されていませんから当然むちゃくちゃになりますが、その部分はプログラミングが優秀なので、ドライバーが堅牢で、データが存在しない日時に突入してもボロボロになりながら動いているんです。ある意味すごいことなんだけど。」

（作者）「さすがにデータがないまま動き続けるのは無理なので、ああいうホラーな見た目になっているんです。メモリーの狭間にある各種のドライバーにとっては無意味な情報を、無理やり視覚化するとああいうグラフィックになるということですね。」

（作者）「ちなみにこれは（最初の）『ぼくのなつやすみ』ＰＳ版で出るバグです。残念ながら移植した『ぼくのなつやすみポータル』では発生しません。おしまい。」

# 〆
ただただぼくなつのバグについて語っただけの記事になってしまいましたが、いかがだったでしょうか。
個人的に８月３２日の異次元に飛ばされて、誰もいない世界に来てしまった感じがとても好きなんですけど、人によってはかなり閲覧注意レベルでしたね。（反省はしてないけど、申し訳ないとは思っている）
レトロゲームというか昔のゲームであればあるほど、バグっていても動き続けるゲームが多いのでどのようなプログラムを書いているのか気になります。（大体はアセンブラ言語かC言語で書かれていると思いますが）

好きなゲームやバグについて他に知っている人がいれば教えてもらえると、個人的にゲームの知識が増えるので教えてもらえると嬉しいですね。

↓下記は独り言
まずプレステ実機を買って、ソフトを買って…
実機を買ったら「serial experiments lain」「ビブリボン」「パラッパラッパー」「クロックタワー」なんかを遊びたいですね。
なんならブラウン管も買ってプレイしたら当時の雰囲気を味わえるかも…wktk
ソースコードのコメントについて考える

　プログラムを開発する際、動作の仕様や仕組みなどをコードにコメントとして記載します。
　このコメントについては、エンジニア同士でも、書く、書かないで意見が分かれることが多く、絶対の正解と言えるようなわかりやすいものはないと思います。
　今回は、私自身の経験を踏まえて、コメントについて、改めて考えてみようと思います。

# コメントは書くべきか？
　まずはじめに、私個人の結論を述べさせていただくと、**基本的にコメントは書くべき**だと考えています。

　コードを書く際に、原則として、「読んでも理解できないようなコード」を書かないのは、当たり前にすべきことだと思います。

　読めばわかるのに、わざわざわかることをコメントに残す意味があるのか。

　当然、このように考える方もいることでしょう。
　たしかに、コードを読めばわかることであれば、コメントがなくても、コードを読んで理解することができますから、コードを読んでもわからないようなことにだけコメントを残せばいい、そのように考えることも至極当たり前のことだと思います。

# 読めばわかる場合でも書くべきコメント
　上述したように、「読んでも理解できないようなコード」や実装の裏に何かしらの事情や経緯などがない限りにおいては、コードを読めば、大抵のことはわかるでしょう。
　理想を言えば、コードは、コメントなど一切書かなくても、誰が読んでもすぐに理解できる状態であるべきだと思います。

　コードを読んでわかることにはコメントせず、読んでもわからないことにだけコメントするべきである。

　結果として、このような考えも自然なことだと思います。私自身も、この考え方が間違っているとは考えていません。
　ですが、現実的なところでは、これだけでは、不十分であると考えています。

　コードを読むという行為は、単純な文章を読むのとは違い、使用されている変数がどのような状態になるか、どこから呼び出され、どのような入力が入ってくるか、条件分岐によって、どのように処理が変化するかなど、色々な要素を考慮する必要があります。
　必然的に、読む際のコストは、単純な文章に比べて相応に高いものとなりますし、量が増えれば増えるだけ、比例的に増加していくことになります。

　これは、コードの保守性というだけでなく、効率や生産性の観点から見ても、あまり望ましいとは言えないと思うからです。
　実際にコードを書く際、大抵の場合は、機能の概要がわかっていれば、問題がないことがほとんどだと思います。

　最もわかりやすい事例を上げるとすれば、ライブラリの機能を使う場合を想像していただくのが良いかと思います。
　リファレンスを見れば、どんなクラスや機能で、使用可能な変数やメソッドについて、説明が記載されていますから、それを見て、十分に利用が可能でしょう。
　その際に、内部の詳細な実装を確認しなければいけないような事態は、まずありえないと言って差し支えないかと思います。

　つまり、コードを書く際に、コードを詳細に読み込むことは、必ずしも必要ないということになります。
　従って、読めばわかるようなコードであっても、必要以上にコードを読み込むコストを減らすことができるため、**変数やメソッドには、コメントを書くべき**であると考えます。

# 書くべきではないコメント
　すでに述べたように、メソッドや変数にはコメントすべきだと考えていますが、同時に、コードを読む前提であれば、読んでわかることに逐一コメントをするのは冗長だとも考えています。
 
　例えば、このような処理があったとします。
 
```
if (value < threshold)
{
    value = 0.0f;
}
```

　この処理に対して、以下のようなコメントをしたとしましょう。


```
// しきい値未満の場合は、値を 0 にする
if (value < threshold)
{
    value = 0.0f;
}
```

　これでは、処理を直訳しただけですし、ある程度、経験のあるエンジニアであれば、単純文章を読むのと、読み解くコストは変わらないでしょう。

　条件が大量に列挙されているため、補助的に記載しておく、などの使い方であれば、直訳のコメントでもあった方がわかりやすい場合もありますが、これは、比較的稀なケースでしょう。
　それだけ条件が増えているなら、メソッドを分けるなどの対応をした方がベターでしょうし、分けないほうがいいような状況は少ないからです。

　また、このようなコメントが増えると、**本当に重要なコメントが埋もれてしまって、伝えなければならない情報が、正しく伝わらなくなる**可能性もあります。

# 絶対に書かなければいけないコメント
　ここまでは、書くべきかどうか、という話でしたが、中には、絶対に書かなければならないコメントというものも存在します。
　書くべきではないコメントの際の処理を例に考えてみましょう。

```
if (value < threshold)
{
    value = 0.0f;
}
```

　この処理は、しきい値未満を 0 にするという処理ですが、この処理を行っていることに、コード上からは読み取れないような意図が存在している場合、この処理を変更されたり、削除されたりした場合に、動作に深刻な影響を及ぼす危険性が生まれます。

```
// しきい値を下回る値で処理をした場合、数値が小さすぎて、正しい計算ができなくなるため、
// 0 として扱って、計算結果に影響が出ないようにする
if (value < threshold)
{
    value = 0.0f;
}
```

　例えば、このような意図があった場合、この処理を一見して不要と判断して削除した場合、正しい結果を得られなくなってしまいます。
　今回の例は、比較的わかりやすい内容ですので、消したとしても、後に実行して、処理の意味に気づくこともできるかと思います。しかし、複数要素が絡み合った煩雑な処理などで、こうした状況に陥ってしまうと、「理屈はわからないけど、この処理を消すと動かなくなる」といった地獄のようなコメントが後に生まれてしまうことになります。
　ですので、**処理に明確な意図や経緯があり、それがコード上から読み取れない場合は、必ずコメントを書く**ようにしましょう。

# コメントを書く際のポイント
　最後に、コメントを書く際に、どういった観点に気をつけてコメントを書くべきかを考えたいと思います。

　基本的に、コメントは、自分以外の他人のためのものです。そのため、自分だけがわかるようなコメントでは、全く意味がありません。
　実装を行った自分自身は、すべての情報を持っているため、わかりきったようなことでも、情報を持たない他人には、それを知るすべは、コードしかありません。
　ですので、相手が知らない情報を考慮した上で、長くなりすぎないように、かつ、必要な情報が欠損しないように気を配る必要があります。
　情報量の目安については、ライブラリのリファレンスなどを参考にするとよいかと思います。

　また、未来の自分も他人です。自分で実装したコードであっても、時間が経てば、記憶は薄れますし、細かい意図などは思い出せなく鳴っている可能性もあります。
　そうなった際に、コメントを正しく書いていない過去の自分を恨んでも、後の祭りですので、必要な情報を精査して、きちんと書き残すように習慣を付けることが未来の自分のためになるかもしれません。
加古貴大_works

## 特許


| 発明の名称 | 文献番号 | 出願日 | リンク |
| --- | --- | --- | --- |
| 人工知能を用いた対話エージェントによる自動応答オンラインカウンセリングシステム | 特開2023-171703 | 2023/03/12 | [リンク](https://www.j-platpat.inpit.go.jp/c1800/PU/JP-2023-171703/F5BAA527C0CB5BD322F47FD36DE307C091C1BFE37E55E06756FC91134B5F30E5/11/ja) |
| 人工知能による対話エージェントシステム | 特開2023-171704 | 2023/03/20 | [リンク](https://www.j-platpat.inpit.go.jp/c1800/PU/JP-2023-171704/0115F3D8F3773F83518CDD95674A399B1B0290CB27EEF2D6CB091676D1DEC63E/11/ja) |
| 人工知能による特定シチュエーションにおけるコミュニケーション能力トレーニングチャットボットシステム | 特開2023-171705 | 2023/06/02 | [リンク](https://www.j-platpat.inpit.go.jp/c1800/PU/JP-2023-171705/D193B160751D72042B96FEDBE8A6893316E78C6C9C154E917430EF3FC40A7247/11/ja) |
| 人工知能によるロールプレイチャットボットシステム | 特開2023-171706 | 2023/06/21 | [リンク](https://www.j-platpat.inpit.go.jp/c1800/PU/JP-2023-171706/0083281215ED51C5B85AD6B4C4D5B388D33E1BF158D6DF1C1757D0586E870D6D/11/ja) |

## 大学
### 東京工業大学大学院
連続の式に基づく超音波CTによる風速分布計測

https://cir.nii.ac.jp/crid/1520009408977440384

### サイエンスリンク
大学生のサイエンスコミュニケーション活動の社会における役割 : 共同イベント「サイエンスリンク」の実施を通じて

https://eprints.lib.hokudai.ac.jp/dspace/handle/2115/50976

## 私のスキル
- **ChatGPT:** 私は、会話ができるチャットボットを作るのが得意です。
- **プログラミング:** Pythonで、色んな問題を解決するためのプログラムを書いたりします。Google App Scriptを使って、インターネット上での作業を自動でできるようにしたりもしています。
- **計測制御:** RaspberryPiなどのマイコンをつかった、プログラミング・電子工作もできます。

## これまでの成果
- **心を助けるAI:** 私は、人の心を支える友達のようなAIを作るために、LINEBOT、GPTsという形で実際にプロトタイプを開発しました。
- **聞き手のAI:** 人の話をじっくり聞いて、カウンセラーみたいに寄り添うAIも作ってみました。
- **みんなの声:** テストをしてくれた人たちの意見を聞きながら、AIをどんどん良くしています。
- **特許:** 新しいアイディアを守るために、特許を5件申請しました。

## どう活かせるか
- **カウンセリング:** 心が疲れたとき、気軽に話せるAIの友達として助けになります。
- **職場:** 仕事で疲れた社員が、AIに愚痴を話せるようにして、ストレスを少しでも減らす手助けをします。

#chagpt
#python
#googleAppScript
#RaspberyyPi
Carbonで日付計算をするときの注意点

以前、LaravelのFakerでダミーデータを作成していた時に、はまったものを記事にしたいと思います。
内容は日付のあれこれに欠かせないCarbonについてです。

## 事象

```php
$startDate = new Carbon('2023-12-01 00:00:00');
$endDate = $startDate->addWeeks(2);
```

例えば、2023-12-01から2週間後の日付を取りたいという時は、上記のように書けると思います。

じゃあいざfakerで使用しようと思って、下記のように使用してみました。
```php
$hoge->hoge = $faker->dateTimeBetween($startDate, $endDate)->format('Y-m-d h-m-s');
```
しかし、何度やっても$startDateの2週間後の値しか生成されない…

そこで`$startDate`の値をみてると、`$startDate`までも2週間後の日付になっているじゃないですか…
どうやらCarbonの仕様のようですね…

## 解決策

そしたらさすがのCarbonさん、きちんとメソッドを用意してくれてました。

```php
$startDate = new Carbon('2023-12-01 00:00:00');
$endDate = $startDate->copy()->addWeeks(2);
```
上記のようにcopy()メソッドを使用すれば、元の`$startDate`はそのまま侵食されずに済むようです。

```php
$hoge->hoge = $faker->dateTimeBetween($startDate, $endDate)->format('Y-m-d h-m-s');
```
これで2023-12-01から2週間の間での日付をランダムに生成することができました。

## おわりに

どうやらこちらは`addWeeks()`だけでなく、`addYears()`とか`addMonth()`など、日付を計算するものはほとんどこの現象が起きるようです。

日付の操作というのは色々とやっかいなことが多いですね…
Elixir Livebook for Paiza

# Paizaの問題をElixirで解こう


実は最近までElixirで問題を解けることを知らなかったのでLivebookでローカル環境で問題を解けるようにしました。

# 公開したリポジトリ

https://github.com/makoto-developer/elixir-livebook-paiza

# きっかけ

Paizaの問題をJavaScriptで挑戦していて、Aランクの問題が再帰を使わないと解けない問題に遭遇しました。

その問題は`N ≤ n_i ≤ 1000`の範囲だったので問題なかったのですが、`10,000`や`100,000`になるとスタックエラーを起こす可能性があることに気づきました。

JavaScriptでも再帰をうまく扱う方法がありますが(generatorとか)、他の言語で戦いたくなりました。

Paizaの利用可能な言語の一覧には`Haskell`とか`Rust`とか私の得意な言語がありましたが、よく見たら下の方に`Elixir`があることに気づきました。

![Language lsit](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684725/c7213e82-1f1d-94b3-73dd-ccf4ee8c4b0e.png)

ElixirにはLivebookがあるのでPaizaのテンプレートを作りたくなったので作成して公開しました。

# 一番苦労した、しかし簡単に解決した課題

最初に直面した問題は標準入力で一度に複数行のインプットを取得する方法が見つからない、でした。

Elixirの`IO`のドキュメントを読んでも一度に複数行が見つからず、Googleで`paiza elixir 標準入力 複数行`等で検索したが出てきません。

結果、発見的方法でしたが、次のようにすれば一度に複数行のインプットを取得できました。

```elixir
:stdio |> IO.read(:all)
```

# 使い方

公開したリポジトリのREADME.mdを参考にしてください。

- forkして使ってください。
- forkしたら非公開(Private)なプロジェクトで作業して下さい。Paizaは問題と答えを非公開にするように求めています。
- `asdf installl`、`git clone`、`docker compose up -d`するだけで動きます。
- ポートやauthを変えたい場合は`.env`ファイルなり`docker-compose.yml`を編集してください。
- 編集したら`/livebook`ディレクトリに保存されます。


# 準備はできましたか？

ElixirでPaizaの問題をたのしみましょう！😍

# 終わりに

きっと誰かが同じようなことをやっているだろうけど、調べずに自分で作りたかった。