OmniAICreator/Qiita-1.07M huggingface dataset:
OSSなSNSの開発事情を調べてみた

ここ最近、我らが Twitter が X になってから、なんやかんや X にいつつもどこのサービスに移行しようかと議論されています。

そこで、Twitter に似たオープンソースな SNS がどのような技術で作られているか簡単にまとめました。


# Bluesky
<a href="https://bsky.app/profile/bsky.app"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/707293/b0362544-e312-808f-1301-46fb9d8be110.png" width=30%></a>

Twitter の共同創業者のジャック・ドーシーらが発案した分散型 SNS です。

https://github.com/bluesky-social

[Social-app](https://github.com/bluesky-social)　のリポジトリがサービスへ直接関わるリポジトリになります。

- 技術： [React Native](https://reactnative.dev/)
- 言語： TypeScript ( Webサービスに一部 Go 言語を使用 )

# Misskey
<a href="https://misskey.io/"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/707293/2187883e-b59d-5471-04fe-d9fa7cf0d892.png" width=60%></a>

日本発の分散型 SNS です。syuilo氏が発案しました。

https://github.com/misskey-dev

[misskey](https://github.com/misskey-dev/misskey) がサービスへ直接関わるリポジトリになります。

日本発なだけあって、issue も日本語なのは個人的に驚きました。日本人にとっては参加しやすそうな環境ですね。

- サーバーサイド： Node.js
- データベース: PostgreSQL、Redis
- UIフレームワーク: Vue.js
- プログラミング言語： TypeScript

Misskey のモバイルアプリについて、PWA には対応していますが、公式クライアントは Web のみです。
しかし、APIが公開されているので、有志でモバイルアプリを作ることが可能です。
現在公開されている Misskey のモバイルアプリは[公式ドキュメント](https://misskey-hub.net/ja/docs/for-users/resources/apps/)を参照ください。

# Mastodon
<a href="https://joinmastodon.org/"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/707293/71167521-f2e4-4c40-f836-c0657ab64ecf.png" width=30%></a>

ドイツ発の分散型ソーシャル・ネットワークです。オイゲン・ロホコ氏が発案しました。

https://github.com/mastodon

[mastodon](https://github.com/mastodon/mastodon) がサービスへ直接関わるリポジトリになります。

- サーバーサイド：Ruby on Rails
- UIフレームワーク： React, Redux

ストリーミングAPIには Node.js を使用しているようです。

まだ、モバイル用のリポジトリもあります。
- [iOS](https://github.com/mastodon/mastodon-ios): Swift
- [Android](https://github.com/mastodon/mastodon-android): Java

## 最後に
いったんここまで _(:3 」∠)_

もしかしたら増えるかも

自分の使ってる SNS の開発に参加できるって夢ありますよね✨
DatabricksアセットバンドルによるDelta Live Tablesパイプラインのデプロイおよび実行

こちらの続きです。

https://qiita.com/taka_yayoi/items/dc7645611551177a72c6

[Delta Live Tables](https://www.databricks.com/jp/product/delta-live-tables)パイプラインも一緒に管理できます。

https://docs.databricks.com/ja/delta-live-tables/tutorial-bundles.html

[バンドルの作成](https://qiita.com/taka_yayoi/items/dc7645611551177a72c6#%E3%83%90%E3%83%B3%E3%83%89%E3%83%AB%E3%81%AE%E4%BD%9C%E6%88%90)までは一緒です。

作成時に

- Include a stub (sample) notebook in 'dlt_project/src': **no**
- Include a stub (sample) Delta Live Tables pipeline in 'dlt_project/src': **yes**
- Include a stub (sample) Python package in 'dlt_project/src': **no**

と選びます。プロジェクト名は`dlt_project`としています。

# アセットバンドルのデプロイ

```sh
cd dlt_project 
databricks bundle deploy -t dev --profile <プロファイル名>
```

ワークスペースにリソースが配備されます。
![Screenshot 2024-02-08 at 15.32.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/c865eb47-b2ea-de17-1285-3c2c88c62fa1.png)

パイプラインも作成されます。
![Screenshot 2024-02-08 at 15.34.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/0bf12bda-64f6-345c-5904-b4aa260607ba.png)

パイプラインのノートブックも作成されます。
![Screenshot 2024-02-08 at 15.34.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/47207189-3d5a-fa9b-d24f-355ef578fca0.png)

パイプラインをタスクとしたジョブも作成されます。なお、こちらは今回は使いません。
![Screenshot 2024-02-08 at 15.35.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/cb4844c8-1c71-be45-139d-994da42dcfbb.png)


# パイプラインの実行

DLTパイプラインを実行します。

```sh
databricks bundle run -t dev dlt_project_pipeline --profile <プロファイル名>
```

パイプラインが起動しました！
![Screenshot 2024-02-08 at 15.38.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/5c8655de-fb7a-d5d5-b4f5-d53b0532cf85.png)

完了しました！
![Screenshot 2024-02-08 at 15.42.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/3f7de05a-2dd8-36cc-633c-e94e534418eb.png)

テーブルも作成されました。
![Screenshot 2024-02-08 at 15.50.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/f75573bb-6adb-471d-bca5-18026c1ef2bb.png)

やっぱり、これはなかなか強力な機能だ。

### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
【Ruby,Rails】長いメソッド名をわかりやすい名前に変えて使用してみよう

どうもこんにちは。

今回は、Ruby,Railsでメソッド名を自分のわかりやすい名前に変更して使用する方法を紹介します。

# メソッド名を変更して使用する方法

大きく分けて２つです。

1. `alias`や`alias_method`を使用する
1. 独自のメソッド名変更メソッドを用意する

ただし、`alias`や`alias_method`は全てのメソッドに対して使用できる訳ではありません。
以下のメソッドに対して`alias`や`alias_method`を使用することができます。

1. **明示的に定義されたメソッド**: クラス内で明示的に定義されたインスタンスメソッドやクラスメソッドには、通常、エイリアスを定義することができます
1. **継承されたメソッド**: スーパークラスから継承されたメソッドに対してもエイリアスを定義することが可能です

一方で`alias`や`alias_method`を使用できないメソッドは以下のようなものです。

1. **動的に生成されるメソッド**: メタプログラミング技術やフレームワークの内部機構によって動的に生成されるメソッド。例えば、RailsのActiveRecordにおける`find_by_*`メソッドや`find_or_create_by_*`メソッド
1. **特殊なメソッドやキーワード**: Rubyの一部の特殊なメソッド（例えば、`initialize`や`method_missing`）や、言語のキーワード（例えば、`class`や`def`）

# aliasやalias_methodを使用する方法

## すでに提供されているメソッドに対して使用する

### 前提

Railsの`ActiveRecord::Base`クラスには、`human_attribute_name`というメソッドが定義されています。

これは、`config/locales/ja.yml`を参照して、モデルにカラム名を定義した形に変更してもらえるメソッドです。

以下が`config/locales/ja.yml`の例です。

```yml
ja:
  activerecord:
    models:
      contents: コンテンツ
    attributes:
      contents:
        id: ID
        title: コンテンツ名
        description: 内容
        created_at: 登録日時
        updated_at: 更新日時
```

`human_attribute_name`を使用すると`config/locales/ja.yml`を参照して変換してくれます。

```ruby
# Railsコンソール
pry(main)> Content.human_attribute_name(:title)
=> "コンテンツ名"

pry(main)> Content.human_attribute_name(:created_at)
=> "登録日時"
```

これを`han`メソッドとして使用できるようにします。

### ApplicationRecordに定義

以下のように`app/models/application_record.rb`に定義します。

```ruby
class ApplicationRecord < ActiveRecord::Base
    class << self
        alias han human_attribute_name
    end
end
```

`han`メソッドを使用できるか試してみます。

```ruby
# Railsコンソール
pry(main)> Content.han(:title)
=> "コンテンツ名"

pry(main)> Content.han(:created_at)
=> "登録日時"
```

できましたね。

## 自分で定義したメソッドに対して使用する

例えば、Userモデルに以下のようなメソッドが定義されていたとします。

```ruby
class User < ApplicationRecord
    def user_find_in_where
        # なんらかの処理
    end
end
```

これに対して、`alias`を使用します。

```ruby
class User < ApplicationRecord
    def user_find_in_where
        # なんらかの処理
    end

    alias ufiw user_find_in_where
end
```

以下の実行結果はどちらも同じになります。

```ruby
# Railsコンソール
pry(main)> User.find(1).user_find_in_where

pry(main)> User.find(1).ufiw
```

## aliasを使用する時の注意点

- クラスメソッドに対して使用するときは、以下のように記述

```ruby
class User < ApplicationRecord
    class << self
        alias 変更後メソッド 変更前メソッド
    end
end
```

- インスタンスメソッドに対して使用するときは以下のように記述

```ruby
class User < ApplicationRecord
    alias 変更後メソッド 変更前メソッド
end
```

クラスメソッドの定義とインスタンスメソッドの定義も同様です。

上記の違いは**Ruby Silver**か**Ruby Gold**の試験でも出題されます。（Railsに落とし込むとわかりやすい）

## 独自のメソッド名変更メソッドを用意する

`ActiveRecord::Base`には`find_or_create_by`というメソッドが存在します。しかし、**メタプログラミング技術やフレームワークの内部機構によって動的に生成されるメソッド**なので｀alias`は使用できません。そのため、自分でメソッドを名前を変更するメソッドを作成します。

```ruby
class ApplicationRecord < ActiveRecord::Base
    self.abstract_class = true
    
    class << self
        def focb(*args, &block)
          find_or_create_by(*args, &block)
        end
    end
end
```

上記のように記述すると、以下の実行結果は同じになります。

```ruby
# Railsコンソール
pry(main)> User.find_or_create_by(name: '試験太郎')

pry(main)> User.focb(name: '試験太郎')
```

以上
【初投稿】メジャーの作成場所を間違った時～！

# 前フリ #
ライン長が「Power BIでレポート作成してほしいかもしれまてん！」とか言うたはった気が。Power BI Desktopは無料で使えることもあり以前勉強したことがあったので、今回は復習も含め、Power BI サービスとか言うのに「発行」するのも学習した。

 何も考えずに「新しいメジャー」をクリックすると、一番上にあるテーブルの配下に作成されてしまう。
 で、🔰がやっちまうメジャーについてのやらかしナンバー1であろう（自分比） **「作成するテーブルまちないてた！」** 時の対処をメモ。

「そんなやつぁいねーよｗ」っていう方はお帰りください(*´∀`*)ﾉ"

 # 結論から言うとホームテーブルを変更すればよいのだ #
 そもそも間違ったテーブル配下に作っちゃってると、サジェストされないので気づくことが多い。ありがとう偉い人。
 問題なのは、 **運良く作れちゃって移動したい時** である。
 メジャーを右クリックしても移動させるメニューなんてないし、「モデルから削除」して再作成するしかないのかorzとなっている人がいるかもしれない（同志よ！）。

 じゃあ早速。

 1. 移動させたいメジャーを選択する
 1. メニューに「メジャーツール」というのが新たに表示されるので・・・
 1. リボンにある「ホームテーブル」をドロップダウンリストから移動先のテーブルに変更する
 
![スクリーンショット 2024-02-08 152404.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266692/8faa8a9c-86ab-844b-3506-17ccc58386ce.jpeg)

# 対策 # 
 **メジャーを作成する時は、どこに作るか指定してから作ろうな！** お母ちゃんとの約束やで。

### 現場からは以上です。ほなね！ ###
【GAS】Google Apps Scriptの初回認証をGoogleスプレッドシートのボタンオブジェクトから実行する方法【動画 5分51秒】【YouTubeチャンネルからの転記です】

この記事は、わたしの[YouTubeチャンネル](https://bit.ly/Yamanaka-YouTube "Living without things. 持たない生き方 手放す生き方")にある公開動画を転記しております。
( どこかのタイミングで、プログラミング-Google Apps Script or iPaaS-Zapier をつかって自動転記させる予定です )

転記のための時間コストを少なくしたいので、文字装飾( Markdown記法 )を極力つかわずに書いております。

こちらが動画内容です👇

***

![99 サムネイル 【GAS】Google Apps Scriptの初回認証をGoogleスプレッドシートのボタンオブジェクトから実行する方法【動画 5分51秒】.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386308/1e0e882f-e945-3704-cc37-99b2ece9cedd.png)



* # 動画URL
    * https://youtu.be/Cz_AfPPRg_k

<br>

* # 動画タイトル
    * 【GAS】Google Apps Scriptの初回認証をGoogleスプレッドシートのボタンオブジェクトから実行する方法【動画 5分51秒】

<br>

* # 動画の説明欄(一部を抜粋)

📅撮影日 = 2024-02-08(木)

YouTube Summary with ChatGPT & Claude( Chrome拡張機能 )で、目次と概要を自動生成しました。
https://bit.ly/yt-sum-Chatgpt-Claude


動画の目次( タイムスタンプ ):

00:00 - オープニング

00:37 - Googleスプレッドシートのボタンオブジェクトとは？
　└ 00:40 - ボタンオブジェクトの作成と設定

02:20 - 初回認証のプロセス：1回目のボタンオブジェクト左クリック

03:28 - 認証後のスクリプト実行：2回目のボタンオブジェクト左クリック

04:25 - この動画のまとめ


動画の概要:

この動画では、Googleスプレッドシート内に配置したボタンオブジェクトを通じて、Google Apps Script (GAS) の初回認証およびコード実行を行うための詳細なガイドを提供します。
特に、GASを使用してスプレッドシートの機能を拡張したいと考えている初心者や中級者の方々に向けて、実用的な手順と有用なヒントを豊富に盛り込んでいます。

動画の内容は、GASの基本概念の紹介から始まり、スプレッドシートの設定、スクリプトエディタの使い方、そしてボタンオブジェクトの作成に至るまで、段階的に解説しています。
さらに、スクリプトエディタの操作方法にも触れ、スクリプトエディタで実際にスクリプトをどのように選択、操作、機能するのかを視聴者に理解させるための実例を示しています。

特に注目すべき点は、GASの初回認証とコード実行を行うための2回のボタンオブジェクト左クリックのプロセスです。
初めてボタンをクリックする際には、GASの初回認証が行われ、ユーザーはスクリプトがGoogleアカウントの情報にアクセスすることを許可する必要があります。
この認証プロセスが完了すると、2回目のクリックでようやくスクリプトのコードが実行されます。
この2段階のプロセスは、セキュリティを確保しつつ、スクリプトが期待通りに機能するための重要なステップであることを、動画では強調しています。

さらに、この動画では、認証ダイアログの見方、許可の与え方、そして実際のコード実行の様子まで、具体的に解説しており、視聴者が自身のプロジェクトにおいて同様のプロセスをスムーズに進められるように配慮しています。

この動画を通じて、GASを使ったスプレッドシートのカスタマイズに興味のある方々は、初回認証からコードの実行までのプロセスを習得し、自身の作業効率を大幅に向上させることができるでしょう。
また、Google Apps Scriptコーダーの方が、GASの初心者に対してコードを実行させるときの動画マニュアルとして提供することができるでしょう。
Google Apps Scriptのポテンシャルを最大限に活用するための貴重なリソースとなること間違いなしです。


---


✓ 🎥この動画と関連が強いわたしの動画 ↙
　・【 解説動画 3分34秒 】初めてGoogleAppsScript( GAS )を設定する時の手順を紹介します | 無人化 自動化を活用しよう！
　https://youtu.be/jIvIK9KWn-4


　・【 解説動画 6分36秒 】初めてGoogleAppsScript( GAS )のトリガーを設定する時の手順を紹介します | 無人化 自動化を活用しよう！
　https://youtu.be/YhylVIX_v1o


　・“効果的にGoogleAppsScriptを活用するヒント”シリーズ
　https://www.youtube.com/playlist?list=PLpQhBHT4oghMvEXXmEZ_qF47eCNeIwQUf


　・“効果的にGoogleスプレッドシートを活用するヒント”シリーズ
　https://www.youtube.com/playlist?list=PLpQhBHT4oghPKt1RQjiH2Dw-iNtB1xqd_


　・“デモ・マニュアル動画”シリーズ
　https://www.youtube.com/playlist?list=PLpQhBHT4oghMJJv4wKFZDT03S2qmL2pkR


　・“無人化、自動化のヒント”シリーズ
　https://www.youtube.com/playlist?list=PLpQhBHT4oghOWXRAE3hzACocPV0y75oN_


✓ 🎥Shortened URL for this video | この動画の短縮URL ↙
　https://bit.ly/3SNFXGK
SendGridでISO-2022-JPのままメールは送れない

# 要約
- SendGridでWebAPIを用いた送信をする場合、文字コードはUTF-8のみ対応している
- SendGridでSMTPを用いた送信をする場合、文字コードはUTF-8以外にISO-2022-JPも対応している
    - 但し、UTF-8の形に変換されてから送信される
    - メールのヘッダー情報のcharsetもUTF-8になる
- SendGridでISO-2022-JPを用いて送る場合、「①」「㈱」などといったJIS X 0208より後に追加された文字は文字化けを引き起こす恐れがあるため避ける

## ISO-2022-JPで送ると文字化けしてしまった
元々ISO-2022-JPでエンコードしていたメールがあり、SendGridを用いて送信する様に変更しました。
届いたメールを確認すると文字化けをしていました。
元々送ろうとしていたメールは「①」という文字が使われており、その部分が文字化けしてしまいました。

## 原因の調査
まず、WebAPIを用いてメールを送信する場合はUTF-8以外の文字コードには対応していません。
そのため、メールを送信する際にWebAPIを用いていないか確認する必要があります。

[参考記事 Web APIでUTF-8以外の文字コードでメールを送信することはできますか？](https://support.sendgrid.kke.co.jp/hc/ja/articles/203392125-Web-API%E3%81%A7UTF-8%E4%BB%A5%E5%A4%96%E3%81%AE%E6%96%87%E5%AD%97%E3%82%B3%E3%83%BC%E3%83%89%E3%81%A7%E3%83%A1%E3%83%BC%E3%83%AB%E3%82%92%E9%80%81%E4%BF%A1%E3%81%99%E3%82%8B%E3%81%93%E3%81%A8%E3%81%AF%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%81%8B)

今回はSMTPで送っていたのでそちらはどうか確認した結果、「ISO-2022-JP」の文字コードは対応と記載がありました。

[参考記事 トランザクションメールを送信する](https://sendgrid.kke.co.jp/docs/Tutorials/A_Transaction_Mail/send_transaction_mail.html)

他にも「Content-Transfer-Encodingに8bitを指定していないか」「改行文字がCRLF以外になっていないか」などの注意点はあったものの、いずれも問題ありませんでした。

[参考記事 SMTPでメールを送信する際に気をつけることはありますか？](https://support.sendgrid.kke.co.jp/hc/ja/articles/206313205-SMTP%E3%81%A7%E3%83%A1%E3%83%BC%E3%83%AB%E3%82%92%E9%80%81%E4%BF%A1%E3%81%99%E3%82%8B%E9%9A%9B%E3%81%AB%E6%B0%97%E3%82%92%E3%81%A4%E3%81%91%E3%82%8B%E3%81%93%E3%81%A8%E3%81%AF%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%81%8B)

## 確認した結果
ISO-2022-JPでエンコードしたメールをSendGridが送信する前に、ISO-2022-JPからUTF-8に変換する処理を行っていることが分かりました。
そのため、ISO-2022-JPでエンコードしたままのメールをSendGridで送ることはできません。

## 対応策
### UTF-8でエンコードして送信する
そもそもの話としてUTF-8で最初からエンコードしていればSendGrid側での変換を考慮せずメールを送ることが可能です。

### UTF-8にエンコードした際に文字化けする文字を利用しない
ISO-2022-JPを用いた場合ですが、JIS X 0208までに定義された文字であれば問題なさそうです。
それ以降に定義された文字（①、㈱、ｱｲｳｴｵなどの半角カナ）はUTF-8への変換時に文字化けする可能性があるため極力避けることを推奨します。
git pushの引数省略の設定

# 前提

　リモート接続時に、```git remote add origin <gitのurl>```とリモートリポジトリの名前をoriginに設定。ちなみに```origin```は必須でなく、任意の名前をつけられる。


# 結論
```
git push -u origin main
```

設定ができているかは以下のコードで確かめる。
```
git branch -vv

# 結果
* main     0315f63 [origin/main] initial commit
```
```[origin/main] ```を含めば成功。

以降 main ブランチで作業中に```git push```の引数を省略して実行すると、自動的にoriginの mainブランチにプッシュされる。
楽なので最初にブランチをプッシュをする時はuオプションを使うと良い。



間違いがあったらぜひ教えてください！
コードリーディングのコツは極力コードを読まないことだ (「世界一流エンジニアの思考法」より)

# 「コードリーディングのコツは極力コードを読まないことだ」

「世界一流エンジニアの思考法」にそう書いてあった。これには共感する。

ちなみに書籍では「コードリーディング」という書き方をしているが、コードレビューでも同じことが言える。

<img width="571" alt="image" src="https://github.com/YumaInaura/YumaInaura/assets/13635059/e0b3ed4c-3d4c-4882-b011-5345f64737f0">
 
# オレのレビュー

自分の場合、コードレビューをする時、自分がよく分からない箇所のコードを念入りに読んだりはしない。
もちろん時と場合によるのだが、コードを全く読まないことさえある。

それよりも実際に動作確認をして、期待する要件が果たせていればOKとする。
そのおまけとしてコードを読んで、コードの可読性をチェックしたり、コードを読まなければ気づきづらいバグが潜んでいないかチェックする。

レビューすなわち機能テスト、モンキーテストだという感覚でやっている。

「コードレビューだからコードを読まなければいけない」というのは思い違いだ。
人間には頑張ってもどうせ分からないこともある。コードを隅々まで読んでコードレビューするのはコストパフォーマンスが非常に悪い場合が多い。

# オレのレビュー経験

コードの隅々までを読むレビューから、開発担当者を信頼して「えいや！」とApproveするレビューまで経験したことがある。

何が良いレビューなのか？という答えはもちろん状況や環境によって変わる。
なので「絶対にこのレビュー方法が良い」という固定した答えはないのだ。

レビューの粒度もプロジェクトやチームの状況に応じて切り替える、それが良いレビューなのではないだろうか。

(たとえば新人エンジニアの学習を助ける目的があるなら、隅々までレビューして指摘してあげても良いかも知れない)


# インターフェイス部分を読む

ところで書籍には「インターフェイス部分だけを重点的に読めば、速く読めるようになる」的なことが書いてあったが、どういうことなのか、自分にはよく分からなかった。
おそらく、コードの中で重要な部分だけを読めば、自然とそんな読み方になっているのではないだろうか。

ディティールではなく大局をざっと読むというか。


# チャットメンバー募集


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

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


# プロフィール・経歴

https://github.com/YumaInaura/YumaInaura
Error [ERR_REQUIRE_ESM]: Must use import to load ES Moduleのエラーが出る

## はじめに
Next.jsでContentfulの型定義ファイルを自動生成する際にエラーが出たので対処法をメモします。

## 問題
contentful-typescript-codegenのライブラリを使って型定義ファイルを生成するコマンドを実行した際に、以下のエラーが発生しました。

https://github.com/intercom/contentful-typescript-codegen
```
% npm run contentful-typescript-codegen

> nextjs-media-skeleton-template@0.1.0 contentful-typescript-codegen
> contentful-typescript-codegen --output @types/generated/contentful.d.ts

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /hoge/getContentfulEnvironment.ts
require() of ES modules is not supported.
require() of /hoge/getContentfulEnvironment.ts from /hoge/node_modules/contentful-typescript-codegen/dist/contentful-typescript-codegen.js is an ES module file as it is a .ts file whose nearest parent package.json contains "type": "module" which defines all .ts files in that package scope as ES modules.
Instead change the requiring code to use import(), or remove "type": "module" from /hoge/package.json.
```

エラー内容に書いてある通り、ESモジュールをロードするにはimportを使用する必要があり、require()はサポートされていません。getContentfulEnvironment.tsファイルを確認すると、requireを使用していました。

・getContentfulEnvironment.ts
```js
const contentfulManagement = require('contentful-management')

const getContentfulEnvironment = () => {
  const contentfulClient = contentfulManagement.createClient({
    accessToken: 'xxxxxxxxx',
  })

  return contentfulClient
    .getSpace('xxxxxxxxx')
    .then((space: { getEnvironment: (arg0: string) => any }) => space.getEnvironment('xxxxxx'))
}


module.exports = getContentfulEnvironment
```



## 解決方法
エラーメッセージに「Instead change the requiring code to use import(), or remove "type": "module"」とある通り、importに変えるかpackage.jsonで指定している"type": "module"を削除することで解決できました。

## おわりに
ESモジュールが主流になっているとはいえ、CommonJSについても知ってく必要がありそうです。
[備忘録] React v6 のルーティングについて

## Reactアプリ内のルーティングをメモ
React V6は、V5からルーティングの仕方が結構変わったので、いつもどっちのコンポーネントを使うんだったか迷うので、ここに備忘録。

#### 本体モジュールとは別セットなので、react-router-domをインストール
```terminal:Terminal
npm install react-router-dom
```
#### App.jsxにルーティング用コードを書く
```jsx:JSX
import React from 'react';
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';

// Import page components
import Home from './Home';
import About from './About';
import Contact from './Contact';

// Import components that should appear on every page
import Header from './Header';
import Footer from './Footer';

function App() {
  return (
    <BrowserRouter>
      <Header />
      <nav>
        <ul>
          <li><Link to="/">Home</Link></li>
          <li><Link to="/about">About</Link></li>
          <li><Link to="/contact">Contact</Link></li>
        </ul>
      </nav>

      {/* Define routes for each pages */}
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/contact" element={<Contact />} />
      </Routes>

      <Footer />
      
    </BrowserRouter>
  );
}

export default App;
```
全体のUIツリーはBrowserRouterに入れて、パスによってスイッチするコンポーネントはRoutes内に入れる。
＊BrowserRouterは、一種のcontext providerで、ルーティングの為のプロパティを子要素に提供している。
PMP受験記＋おすすめ問題集


# 概要

2024/01にPMPを受験し、合格しました
その勉強方法をまとめましたので、参考になれば幸いです。

- 勉強時間：100時間くらい
- 勉強期間: 4ヶ月（2023/10～2024/01）

# 費用

**104,743円**

| 名前 | 金額 | 補足 |
|:-----------|------------:|:------------:|
|教科書 | 8,908円 | kindle(2冊) + Udemy（1つ）|
|問題集 | 10,350円 | PMI Study Hall + Udemy（２つ） |
|35時間トレーニング| 12,800(1,500)円 | Udemy（1つ） |
|受験料+PMI会員入会費| 83,685円 | 受験料(405ドル) + PMI会員入会費(139ドル) + TAX(13.9ドル) = 557.9ドル |

※1ドル＝150円、Udemyはセール時に購入

# 使用した教材（教科書）

書籍は完全攻略テキスト・虎の巻両方読んだが、正直どちらでも良いかな。。
（問題集は完全攻略テキストが良いくらい）

書籍とは別にUdemy(動画)も見ると、より理解度が深まるのでオススメ

| 名前 | お勧め度 | 金額 |
|:-----------|------------:|:------------:|
| Udemy<br>｢PMP®認定試験｣で一発合格を目指す！ 効率的な試験対策のための戦略コース (2021) アジャイル対応     |☆☆☆☆|6,200(1,800)|
|PMP完全攻略テキスト PMBOKガイド第7版対応|☆☆☆|3,940|
|PMP®試験合格虎の巻　新試験対応|☆☆☆|3,168|

# 使用した教材（問題集）

全部で1200問やった。。

| 名前 | お勧め度 | 問題数 | 金額 |
|:-----------|------------:|:------------:|:------------:|
| Udemy<br>PMP (Project Management Professional) 試験模擬問題集 全360問|☆☆☆☆☆|360|3,000(1,500)|
| PMI Study Hall ESSENTIALS |☆☆☆☆|360|$49(7,350円)|
| Udemy<br>｢PMP®認定試験｣で一発合格を目指す！ 試験攻略のための実践問題演習コース 全100問 (2020)|☆☆☆|100|3,000(1,500)|
|PMP完全攻略テキスト PMBOKガイド第7版対応|☆☆|180|3,940|
|PMP®試験合格虎の巻　新試験対応|☆|200|3,168|

※1ドル＝150円
※Udemyの金額で()内はセール時の金額

- UdemyのPMP (Project Management Professional) 試験模擬問題集 全360問 がオススメ。かなり本番に近い
- PMI Study Hall ESSENTIALSは英語なので、Chromeの翻訳機能を使って日本語に変換する
  - ただし、「execution」が「死刑執行」になっていたり。。。

# おすすめ学習法

教科書を2回くらい読んだら、 **問題集をひたすらやる**

## ポイント１：単純な暗記物は出ない（はず）

本番試験、実務に近いシチュエーション問題がほとんど。逆に下記のような暗記物は出ない（はず）
- 例１：EVMの計算式（ETC=（BAC-EV）÷CPI）とか
  - 実務ではExcelとかツールを使うので暗記する必要性はないから
- 例２：Ｘ理論Ｙ理論の提唱者は？
  - 作った人の名前より、中身が重要だから
- 例３：資源マネジメントの計画フェーズのインプットとアウトプットは？

なので、テキストを丸暗記しても、実際の問題は全然解けない

## ポイント２：日本語訳に慣れる

実際の本番試験も、英語→日本語訳と思われるので、独特の日本語になる
Udemy/PMI Study Hallの問題は、同じように英語→日本語訳した文章なので、戸惑いが無くなる

## ポイント３：シチュエーション問題文に慣れる

試験問題は「スコープが広がったがどうする？」「リソースが足りなくなったがどうする？」といったシチュエーション問題がほとんど。
問題数が180問＋文章量もそれなりにあり、 **読むのにそれなりの精神力を使う**
事前に大量に解いておくと、大体似たようなパターン＋押さえておくポイントが分かるので、消費する精神力がかなり軽減する

押さえておくポイント
* どこのフェーズの話なのか
  * 計画と実行フェーズでは対応が異なる
* 対応する相手は誰か
  * プロダクトマネージャー、チームメンバー、ステークホルダー、プロダクトオーナー

## ポイント４：解答の消去法に慣れる

解答の選択肢の中には、**「全部間違っておらず、優先度が一番高い・効果が一番高いものを選ぶ」**　といった場合がある。その場合、選択肢から消去法で選ぶ必要があり、事前に大量に解いておくと、消去すべきものの判断が早い

# 受験の流れ

1. 教科書を読む×２回
   - わからない単語はググる
1. 1と並行して35時間トレーニング(Udemy英語）をやる
   - コストを考えると、だいたいUdemyの英語コースを選択。日本語字幕が出るが、正直しんどい。教科書を読む合間にやるとか、他の勉強と並行でやらないと挫折しそう
     - 1.5倍速で見る。2ヶ月くらいの期間で実施
1. 問題集をやる×４回
   - 常時90%になればOK
   - 10%くらいは解答を見ても、イマイチ納得できないものもある（割り切った）
1. PMIへの受験申請
   - 一番の関門のプロジェクト経験（英文）は、他のサイトを参考にして作成
   - 36ヶ月の経験だと、記載するプロジェクトを３～５つくらい書かないといけないが、プロジェクト概要以外は全て同じ記載でも大丈夫だった（というか、どのプロジェクトでもやることは一緒なので、差異が出ない）
   - 監査は無し
1. 受験
   - 受験場所は自宅とテストセンターどちらでも可。テストセンターのほうが集中しやすそう＋ネットワークなどのリスクが無いので、テストセンターで実施した
   - ただし、テストセンターの場合、1ヶ月前だと土日は空いておらず、休みを取って平日に受験

# 結果

合格ラインは60%だが、80%くらい取って合格
試験時間も230分あるが、150分くらいで完了（事前にシチュエーション問題を大量に解いたのが良かった）
クロージャの省略型

### 雛形
```swift
var sum: (Int, Int) -> Int  
sum = { (x: Int, y: Int) -> Int in  
  return x + y
}
let a = sum(1, 2)// 3
```

### return省略
```swift
var sum: (Int, Int) -> Int  
sum = { (x: Int, y: Int) -> Int in  
  x + y
}
let a = sum(1, 2)// 3
```

### 型の省略
```swift
var sum: (Int, Int) -> Int  
sum = { (x, y) in  
  x + y
}
let a = sum(1, 2)// 3
```

### 括弧の省略
```swift
var sum: (Int, Int) -> Int  
sum = { x, y in  
  x + y
}
let a = sum(1, 2)// 3
```

### 簡略引数名の利用
```swift
var sum: (Int, Int) -> Int  
sum = { $0 + $1 }
let a = sum(1, 2)// 3
```
【備忘】SOAP APIとは？REST APIとの比較より見比べてみた

【APIについて】の記事でWeb APIがあり、その中での**REST API**及び**SOAP API**がある旨を記載しました

https://qiita.com/MaSi1031/items/0611d7b88ae85f878515

その中でREST APIについては、下記へ記載しておりますため、今回はSOAP APIについて備忘がてら記載します。

https://qiita.com/MaSi1031/items/37b2b59ca9c1a5cceb41


### SOAP APIとは？
SOAP＝Simple Object Access Protocolの略
SOAP APIは、異なるプログラムやプラットフォーム間で情報を交換するためのプロトコルで、XML形式を使用して情報を送受信し、通信がHTTPやHTTPSなどのプロトコルを介して行われます。
SOAP APIは、企業間でのデータ交換やウェブサービスの構築などの用途で広く使用されています。

### REST APIとの違いについて
SOAP APIとREST APIの主な違いを具体例を挙げて説明します。
例えば、銀行のシステムがSOAP APIを使用して顧客の口座情報を取得する場合、SOAPは以下のようなXMLベースのリクエストを送信します。
```XML
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://www.example.com/webservice">
   <soapenv:Header/>
   <soapenv:Body>
      <web:GetAccountInfo>
         <web:AccountNumber>123456789</web:AccountNumber>
      </web:GetAccountInfo>
   </soapenv:Body>
</soapenv:Envelope>
```

一方、同じ情報をREST APIを使用して取得する場合、RESTfulなURLを介してHTTP GETリクエストを送信します。
```arduino
GET http://api.example.com/accounts/123456789
```

SOAP APIのリクエストはXML形式であり、SOAPの厳密な規格に従って構築されています。
一方、REST APIはシンプルで直感的なHTTPリクエストを使用しています。

### SOAP APIとREST APIの使い分けについて
SOAP APIとREST APIの使い分けについて、具体例を挙げて説明します。

・**SOAP API**
例えば、企業内のバックエンドシステム間の通信にはSOAP APIが適しています。
これは、SOAPがメッセージレベルでのセキュリティやトランザクション管理を提供し、大規模で複雑なシステム間の通信に適しているためです。

・**REST API**
モバイルアプリケーションやウェブアプリケーションとの通信にはREST APIがより適しています。
これは、RESTがシンプルで柔軟性が高く、リソース指向のアーキテクチャを採用しており、軽量なクライアントとの通信に向いているためです。

### まとめ
SOAP APIについて、REST APIと比較してみました。
**SOAP API**：は厳密な仕様に基づいており、セキュリティや信頼性が必要な場合に適している。
**REST API**：はシンプルで柔軟性が高く、軽量なクライアントとの通信に適している
npx コマンドでCLIを実行したら"could not determine executable to run"って言われた

# 動作環境について
デスクトップのWindows環境と、ラップトップのChromeOS(CrostiniでDebianが動作)環境の2種類で開発していた。Nodejsのバージョンはどちらもv20.22.0

# 経緯
理由は分からないが、あるプロジェクトではnpxコマンドでfirebaseエミュレーターを起動させる構成になっていた。そしてなぜかWSLではエミュレーターが動いたのにCrostini側でエラーが発生して起動しないという問題が発生。

```bash
npx firebase emulators:start --export-on-exit='./.emulator' --import='./.emulator'
npm ERR! could not determine executable to run
```

雑に訳すと「お前が入力したコマンドは実行できるように見えない」みたいな感じだと思われる。

# 原因:パッケージ名とコマンドが揃っていない。
エラーメッセージで検索するとすぐに情報が見つかった。

https://kazuhira-r.hatenablog.com/entry/2022/08/03/015421

>実行したいコマンドとパッケージ名が一致しない場合は、--packageまたは-pで対象のnpmパッケージを指定する必要があります。

確かにパッケージ名は"firebase-tools"なのに対し、コマンドは"firebase"なのでパッケージ名とコマンド名が違う。
```bash
npx --package firebase-tools firebase emulators:start --export-on-exit='./.emulator' --import='./.emulator'
```

なのでパッケージ名を指定するとエミュレーターが起動した。オプション無しだとSDK側を呼び出していたのではと思われるがよくわからない。
言語：python　のリストについて



<font color =hsla(100, 24%, 40%, 0.5)>※このQiitaで記事を書くのも初めてですので、誤字・脱字や読みづらい部分もあるかと思いますが、ご理解ください。</font>


閲覧いただき、ありがとうございます！
私は、現在医療業界で働く医療従事者になります。
とある経緯からpythonを勉強中です。
ここでは自分が勉強した事を復習したり、忘れないようにするため記載いたしますので、もしもっとこうした方が良いよ、とかこれはちょっと。。。というものがあれば教えていただけますと幸いです。
※記事内容は随時更新します


## ①長さを取得する
 ```py:記述 
 fruits = ["apple", "orange", "banana"]
 count = len(fruits)
 print(count)
```

```py:出力結果
3
```

## ②リストに要素を追加(末尾に追加)
```py:記述
fruits = ["apple", "orange", "banana"]
fruits.append("grape")
print(fruits)
 ```

 ```py:出力結果
 ['apple', 'orange', 'banana', 'grape']
 ```

 ※複数追加したい場合は「リスト名.extend(追加したい複数の値)」を利用する。


## ③リストの末尾を削除（と取得）
```py: 記述
fruits = ["apple", "orange", "banana", "muscat"]
acquisition_fruit = fruits.pop()
print(acquisition_fruit)
```

```py:出力結果
muscat
```

## ④リスト内の要素を指定して削除する
変数.remove(消したい要素)

```py:記述
fruits = ["apple", "orange", "banana", "grape"]
fruits.remove("banana")
print(fruits)
```

```py:出力結果
['apple', 'orange', 'grape']
```


## ⑤インデックス番号を指定して削除する
del 変数[削除したいindex番号]
```py:記述
fruits = ["apple", "orange", "banana", "grape"]
del fruits[1]
print(fruits)
```

```py:出力結果
['apple', 'banana', 'grape']
```


### 範囲で複数消したいときは？

```py:記述
fruits = ["apple", "banana", "orange", "grape"]
del fruits[1:3]
print(fruits)
```

```py:出力結果
['apple', 'grape']
```

del 変数[　開始index　:　終了index　]
上記の例として書いたコードだと
範囲はindex１〜２に格納されている値をを削除することになります。


## ⑥リストの要素をソートする
ソートする・・・あるルールにしたがって並べること
破壊的にソートする：sortメソッド
非破壊的にソートする：sortedメソッド
「破壊的」にというのは、元々あるリストを並べ替えて書き換えてしまうことです。
非破壊的でしたら、元々のリストは保持したまま置いておくことができます。

```py:記述
#ここはsortメソッドの記述
fruits = ["apple","grape", "orange", "banana" ]
fruits.sort()
print(fruits)

#ここはsortedメソッドの記述
fruits2 = ["apple","grape", "orange", "banana" ]
print(sorted(fruits2))
print(fruits2)


```

```py:出力結果
['apple', 'banana', 'grape', 'orange']
['apple', 'banana', 'grape', 'orange']
['apple', 'grape', 'orange', 'banana']
```
「exiftool」で画像データのEXIF情報を抽出 #コマンドライン


デジタル画像には、撮影時の様々な情報が埋め込まれていることをご存知ですか？その中でも、Exif（Exchangeable image file format）情報は、画像に関する詳細なメタデータを含んでいます。この記事では、コマンドラインツール「exiftool」を使用して画像データからExif情報を抽出する方法について解説します。

## exiftoolとは
「exiftool」は、Phil Harvey氏によって開発されたコマンドラインツールで、様々なファイルフォーマットのメタデータを取得・編集することができます。特に、写真や画像ファイルのExif情報を詳細に扱うことが得意です。

## exiftoolのインストール
まず初めに、「exiftool」をインストールします。以下は、一般的なパッケージマネージャーを使用する場合の例です。

```bash
# Linux（Debian/Ubuntu）
sudo apt-get install libimage-exiftool-perl

# macOS
brew install exiftool

# Windows
# 公式サイト（https://exiftool.org/）からダウンロードしてインストール
```

## 画像データのEXIF情報抽出手順
では、具体的な手順を見ていきましょう。

### 1. コマンドラインでexiftoolを実行
以下のようにコマンドを入力することで、対象の画像からExif情報を抽出できます。

```bash
exiftool 画像ファイルのパス
```

### 2. 出力結果の確認
実行後、コマンドラインにExif情報が詳細に表示されます。以下は、一例です。

```plaintext
ExifTool Version Number         : 12.30
File Name                       : example.jpg
Directory                       : /path/to/image
File Size                       : 56 kB
...

```

### 3. 特定の情報だけを抽出する
必要な情報だけを取り出すこともできます。たとえば、以下のようにコマンドを変更することで、特定の項目のみを表示できます。

```bash
exiftool -DateTimeOriginal -GPSLatitude -GPSLongitude 画像ファイルのパス
```

これにより、撮影日時や位置情報など、必要な情報を取得できます。

## まとめ
「exiftool」を使用すると、画像に埋め込まれた豊富なExif情報をコマンドラインから手軽に抽出できます。写真の整理や調査、編集作業など、さまざまな用途で活用できる便利なツールです。ぜひ、お好みのコマンドを試してみてください。
Kotlinのテストでlateinit property usecase has not been initializedエラーでDIできない

# はじめに

テストを書いた時にDIがうまくいかなかったのでまとめます

# 問題

```kotlin
import io.mockk.every
import io.mockk.impl.annotations.InjectMockKs
import io.mockk.impl.annotations.MockK
import org.amshove.kluent.shouldBeEqualTo
import org.junit.Test
import io.mockk.junit5.MockKExtension
import org.junit.jupiter.api.extension.ExtendWith

@ExtendWith(MockKExtension::class)
class TestResourcesTest {

    @MockK
    lateinit var usecase: TestUseCase

    @InjectMockKs
    lateinit var target: TestResources

    @Test
    fun createTestTest() {
        every {
            usecase.createTest()
        } returns Unit
        val actual = target.createTest()
        actual.status shouldBeEqualTo  201
    }
}
```

実行すると以下のエラーが発生しました

```
OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended

kotlin.UninitializedPropertyAccessException: lateinit property usecase has not been initialized
```

# 解決方法

`@Test`としてインポートしていたライブラリが違いました

```
import org.junit.Test
ではなく
import org.junit.jupiter.api.Test
```

としたところうまくいきました

# おわりに
JVMをやるとインポートで同じのがたくさんあってそれでハマることが多いなと思います
xargsとは？

### 削除するコマンド
```
cd /usr/share/locale && \
ls -1 /usr/share/locale | egrep -v "^(default|en|ja|locale)" | xargs rm -fr
```
500MBが2.5MBになった。
ファイルシステムの使用容量は８Gから６Gに減った。

### 出典
https://qiita.com/bezeklik/items/a8274bb230f2efa61ffa#%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%82%AB%E3%82%BF%E3%83%AD%E3%82%B0%E3%81%AE%E5%89%8A%E9%99%A4

### xargsとは？
標準入力を読み込んでコマンドラインを作成し、それを実行する
...
標準入力から空白や改行で区切られた一連の項目を読み込み、それを引数にして、指定したcommandを実行する。
...
標準入力における空行は無視する。

出典　man xargs(Centos 7.0) 

### rm　-rとは？
ディレクトリとその中身を再帰的に削除する。

### rm -fとは？
存在しないファイルを無視する。確認も行わない。
出典　man rm

### &&とは？
2つのコマンドを連結して、コマンド１ && コマンド２という形式で利用します。 これらはコマンド一の終了ステータスがゼロである時、コマンド２を実行します。
すなわち、コマンド１が正常終了したときだけコマンド２を実行する。

### 出典
https://www.sbcr.jp/product/4797380941/

### \ とは？
コマンドラインが長くなってしまう場合には、行末に＼をおくことで途中で改行できます。

### 出典
https://www.sbcr.jp/product/4797380941/
LaTeXで一つのファイルから異なる文書を作成

LaTeXで試験問題を作成しているのですが、採点のために解答も同じファイルに記述しておきたいです。問題と解答でファイルを二つ用意すると監理が面倒ですし、ファイルを開けて書き直すことも面倒です。そこで、LaTeXで処理することで問題用紙と採点用の解答付きの2種類の文書を作成する方法を検討しました。

### 外部の処理がないと作れない
LaTeXはオプションも環境変数も内部では参照できないので、何らか外部の処理に頼る必要があります。そこで、ファイルを書き換えないで済むように Make を利用することにしました。

### pLaTeX でファイルでなく、二重引用符でコードが書けました
pLaTeX を使っています。
```shell-session
$ platex -version
e-pTeX 3.14159265-p3.8.2-190908-2.6 (utf8.euc) (TeX Live 2019/Debian)
kpathsea version 6.3.1
ptexenc version 1.3.7
Copyright 2019 D.E. Knuth.
（以下略）
```
`platex ファイル名` でなく、二重引用符でコードを処理できることを ChatGPT で知りました。

```shell-session
$ platex "\documentclass{jarticle} \begin{document}Hello World!\end{document}"
This is e-pTeX, Version 3.14159265-p3.8.2-190908-2.6 (utf8.euc) (TeX Live 2019/Debian) (preloaded format=platex)
 restricted \write18 enabled.
entering extended mode
pLaTeX2e <2020-02-02>+2 (based on LaTeX2e <2020-02-02> patch level 2)
L3 programming layer <2020-02-14>
(/usr/share/texlive/texmf-dist/tex/platex/base/jarticle.cls
Document Class: jarticle 2020/01/03 v1.8e Standard pLaTeX class
(/usr/share/texlive/texmf-dist/tex/platex/base/jsize10.clo))
(/usr/share/texlive/texmf-dist/tex/latex/l3backend/l3backend-dvips.def)
No file texput.aux.
[1] (./texput.aux)
Output written on texput.dvi (1 page, 268 bytes).
Transcript written on texput.log.
```
これを利用することにします。

### 処理の方法
LaTeX文書内で、引数を2つとる適当なコマンドを用意し、1つ目の引数は問題用紙用、2つ目の引数は解答にします。これを用いてファイルを作成しますが、このコマンドの定義はファイルには書きません。Makefile で書きます。

文書本体のファイルは以下のようにします。
```latex:main.tex
\documentclass{jarticle}
\begin{document}
次の方程式を満たす$x$を求めよ。
\[
  x + 3 = 5
\]

\kaito{%
  \vspace*{40mm} % 解答を書くためのスペース
}{%
  \textbf{解)}
  \[
    x = 2
  \]
}
\end{document}
```

このコマンドは二重引用符内で定義します。定義してから `main.tex` をinputします。Makefileは以下のようになります。`make` で二つのファイルができます。（tex → dvi → ps → pdf と作成しています）
```make:Makefile
all: mondai.pdf kaito.pdf

.PHONY: all

%.pdf: %.ps
    ps2pdf $<

mondai.ps: main.tex
    platex "\newcommand{\kaito}[2]{#1}\input{main.tex}"
    dvips main.dvi -o $@  # このときは出力ファイル名が main.dvi になった

kaito.ps: main.tex
    platex "\newcommand{\kaito}[2]{#2}\input{main.tex}"
    dvips main.dvi -o $@  # このときは出力ファイル名が main.dvi になった
```
LaTeXでは出力ファイル名を指定できなさそうなので、dvipsで出力ファイル名を分けました。

### まとめ
platex で二重引用符のコードが書けることを利用して、一つのファイルから二種類の文書の作成を Makefile で処理するようにしました。
将来的には一問ずつ区切った問題＆解答ファイルから、ランダムで問題を選択して問題＆解答ファイルを作りたいです。（項目反応理論を用いて難易度を毎度合わせるなど）
【CSS】Flexboxの横並びは直近の子要素にだけ適用される

# はじめに
Flexboxの横並びは直近の子要素にだけ適用され孫要素には適用されません
# 実装
```html:index.html
<body>
    <div class="flex-oya">
        <div class="flex-ko">
            <div class="flex-mago">flex-mago</div>
            <div class="flex-mago">flex-mago</div>
        </div>
        <div class="flex-ko">flex-ko</div>
    </div>
</body>
```
```css:style.css
.flex-oya {
    display: flex;
}
```
# 実行結果
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348923/d76c674f-58bd-aab6-6d76-5decc8b173f4.png)
このようにFlexboxの横並びは
div.flex-koが横並びになり
div.flex-magoが横並びにならないことが分かります。
よってFlexboxは孫要素等には影響せず直近の子要素にだけ適用されることが分かります。
Excelファイルの各シートをまとめてCSV変換するPythonコード

# 概要
Excelファイルを一括txt化するPythonを作成したので、備忘録としておいておきます。
これはWSL2で使用したものです。

```
path： 下のフォルダを格納するフォルダまでのパス
folder_source： excelファイル格納フォルダ名
folder_result： 出力先フォルダ名
```

```excelToCsv.py
import os
from natsort import natsorted
import pandas as pd
import warnings

#ディレクトリ名
folder_source = "source"
folder_result = "result"
#パス
path = "/home/user/code/python/"

def main():
    folder_source_path = os.path.join(path, folder_source)
    folder_result_path = os.path.join(path, folder_result)

    #excelファイルリストを生成
    files = natsorted(os.listdir(folder_source_path))

    #入力規則が保存できない警告が出るが、xlsxで保存しないため無視する
    warnings.filterwarnings('ignore', category=UserWarning)

    #ファイルリスト
    for filename in files:
        filepath = os.path.join(folder_source_path, filename)
        sheet_names = pd.ExcelFile(filepath).sheet_names
        #各シート
        for sheet_name in sheet_names:
            data = pd.read_excel(filepath, sheet_name, index_col=None)
            output_file_name = sanitize_filename(filename + "_" + sheet_name + ".txt")
            #出力
            data.to_csv(os.path.join(folder_result_path, output_file_name), encoding="UTF-8", index=False)

        #コンソールに経過を出力
        print("{:>2}".format(len(sheet_names)) + ": " + filename)
    print("Finish!")


#ファイル名に使用できないシート名を置換
def sanitize_filename(filename):
    #ファイルパスに使用できない文字リスト
    invalid_chars = [":", "/", "\\", "*", "?", "\"", "<", ">", "|"]
    for char in invalid_chars
        filename = filename.replace(char, "_")
    return filename


if __name__ == "__main__":
    main()
```

# 終わりに
複数のExcelファイルを検索するなら、txt化してからGrep検索が基本ですね。
axiosを使わないでいいね機能を非同期化

こんにちは、普段はプログラミングスクールでメンターをやっている@takokkeです。

今回はいいね機能の非同期化手順を学習記録としてまとめてみました。axiosなどのjsライブラリを使わず、シンプルにjQueryだけで実装したいと思います
# 非同期処理の大まかな手順
1. いいねボタンを押したら、javascriptリクエストがコントローラに送られる
1. アクションがデータ処理を行い、いつもならhtml.erbにインスタンス変数を渡すが、今回はjs.erbへ渡す
1. js.erbに記述したjsコードが、いいねボタンの部分だけ書き換える

ポイントは、いつもならコントローラで定義したインスタンス変数がhtml.erbに渡るのを、**js.erb**に渡すということです。

# いいねボタンのHTMLを部分テンプレート化
いいねボタンの部分テンプレートを作成します。

```erb:app/views/favorites/_favorite-btn.erb
<% if book.favorited_by?(current_user) %>
  <%= link_to book_favorites_path(book.id), method: :delete, remote: true do %>
    <i class="fa fa-heart text-danger"><%= book.favorites.count %></i>
  <% end %>
<% else %>
  <%= link_to book_favorites_path(book.id), method: :post, remote: true do %>
    <i class="fa fa-heart text-primary"><%= book.favorites.count %></i>
  <% end %>
<% end %>
```
link_to内に``remote; true`` を追加することで、
HTMLリクエストではなく、JavaScriptのリクエストがfavoritesコントローラに送られます。

# 呼び出し元にidを付与しよう
投稿一覧ページなどはidで変更したい部分を指定します。
```erb:app/views/books/index.html.erb
:
	省略
：	
<tbody>
    <% @books.each do |book| %>
      <tr>
        <td><%= link_to book.user do %>
          <%= image_tag book.user.get_profile_image(50, 50) %>
          <% end %>
        </td>
        <td><%= link_to book.title,book, class: "book_#{book.id}" %></td>
        <td><%= book.body %></td>
	
	<!--いいね機能ajax-partial-->
        <td id="favorite_buttons_<%= book.id %>" >
            <%= render "favorites/favorite", book: book %>
        </td>
        <td><p>コメント件数:<%= book.post_comments.count %></p></td>
        <td><%= render "books/static_rate", book: book %></td>
      </tr>
：
<% end%>
```
``<td id="favorite_buttons_<%= book.id %>" >``でid属性がbookのidによって変わるようにしています。これでいいねボタンを押した部分だけ変更できます。

# コントローラで指定しているリダイレクト先を削除
```rb:app/controllers/favorites_controller.rb
class FavoritesController < ApplicationController
  def create
    @book = Book.find(params[:book_id]) # インスタンス変数に変更
    favorite = @book.favorites.new(user_id: current_user.id)
    favorite.save
    #redirect_back(fallback_location: root_path)
  end

  def destroy
    @book = Book.find(params[:book_id]) # インスタンス変数に変更
    favorite = current_user.favorites.find_by(book_id: @book.id)
    favorite.destroy
    #redirect_back(fallback_location: root_path)
  end
end
```
リダイレクト先を消すと、リダイレクト先がないかつjavascriptリクエストになります。
これにより
createアクション実行後は、create.js.erbファイルを、
destroyアクション実行後はdestroy.js.erbファイルを探してくれます。

# js.erbを作成使用

```erb:app/views/favorites/create.js.erb
$('#favorite_buttons_<%= @book.id %>').html("<%= j(render "favorites/favorite", book: @book) %>");
```
```erb:app/views/favorites/destroy.js.erb
$('#favorite_buttons_<%= @book.id %>').html("<%= j(render "favorites/favorite", book: @book) %>");
```

以上です
Microsoft 365 Copilotの最新情報収集お役立ち

社内のCopilot普及活動を行うためのリンク集備忘

<iframe width="560" height="315" src="https://www.youtube.com/embed/lcp_Knnxa7w?si=NGypuq2w5BzvrPAe" 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>

初心者編🔰
## 1.Microsoft 365 Copilotの更新プログラム
https://support.microsoft.com/ja-jp/topic/a5685141-8081-458c-80d6-42493aad51ed

## 2.リリースノート
https://learn.microsoft.com/ja-jp/copilot/microsoft-365/release-notes?tabs=all

## 3.なんでもCopilot
https://nandemo.connpass.com/

## 4.Xで有識者をフォロー
https://x.com/hashtag/%E3%81%AA%E3%82%93%E3%81%A7%E3%82%82Copilot?src=hashtag_click

玄人編🤓
## 5.Microsoft 365 ロードマップ
https://www.microsoft.com/ja-jp/microsoft-365/roadmap?filters=%5B%22Microsoft+Copilot+%28Microsoft+365%29%22%5D

## 6.Microsoft公式ブログ
https://techcommunity.microsoft.com/Blogs
▼動画では紹介しませんでしたが、M365コパに特化したブログです！
https://techcommunity.microsoft.com/category/microsoft365copilot/blog/microsoft365copilotblog
▼動画では紹介しませんでしたが、テックコミュニティーもあります！
https://techcommunity.microsoft.com/category/microsoft365copilot

## 7.Microsoft365管理センター

## 8.Microsoftのイベントに参加する
https://build.microsoft.com/en-US/home


## 公式Youtubeプレイリスト集
勉強会とかに使えそう

https://www.youtube.com/playlist?list=PLXtHYVsvn_b-NeN9BbLb5sLpIGfdP8j78

https://www.youtube.com/playlist?list=PLXPr7gfUMmKxDKxah3zpG4NhhDj-2lAvc
【rails】bootstrapを導入した際にcssを読み込ませる方法！

今回はbootstrap導入方法からその後のcssの読み込み方法に関して説明します！

## bootstrap導入
既に導入済みの方は飛ばしてください。

#### 1. yarnでインストールする
```terminal
$ yarn add jquery bootstrap@4.6.2 popper.js
```
#### 2. config/webpack/enviroment.jsを編集
```javascript: congfig/webpack/environment.js 
:
:
///以下すべて追加してください
const webpack = require('webpack')
environment.plugins.prepend(
  'Provide',
  new webpack.ProvidePlugin({
    $: 'jquery/src/jquery',
    jQuery: 'jquery/src/jquery',
    Popper: 'popper.js'
  })
)
```
#### 3. app/javascriptの配下にstylesheetフォルダを作成
作成したフォルダの配下にapplication.scssを作成し、記述します。
```scss: app/javascript/stylesheets/application.scss
@use '~bootstrap/scss/bootstrap';
```
#### 4. app/javascript/packs/application.jsを編集
```Javascript: app/javascript/packs/application.js
:
:

import "channels"
///　ここから
import "jquery"
import "popper.js"
import "bootstrap"
import "../stylesheets/application"
/// ここまで追加
Rails.start()
Turbolinks.start()
ActiveStorage.start()
```
#### 5. app/views/layouts/application.html.erbを書き換え
元々あった`<head>`タグ内の<%= stylesheet_link_tag~の記述を<%= stylesheet_pack_tag~に書き換えます。
（もともと書いていなければ追記をお願いします。)
``` erb:app/views/layouts/application.html.erb
<%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
```
ここでbootstrapの導入は終わりです。

## アプリにCSSを読み込ませる
　bootstrap導入のためにapplication.html.erbを書き換えた状況ですと、app/asset/stylesheet配下のscssファイルは読み込まれません。
 なぜなら先ほどstylesheet_pack_tagに書き換えたことで参照先のフォルダがapp/javascript/stylesheetに変わったため、既存のcssは参照できていない状況になっています。また、packs/application.jsファイルにもcssファイルを参照するための追記が必要になります。そのため、以下の手順を行ってください。

 #### 1. app/javascript/stylesheets/application.scssにcssの記述を書く
 application.scssと書きましたが、app/javascript/stylesheets配下にscssファイル作成して好きなファイル名にしても大丈夫です。(xxxx.css or XXXX.scssとなっていればOK！)

 #### 2. app/javascript/packs/application.jsに追記をする
 ここで先ほどのapplication.scssもしくは独自に作成したcss,scssファイルを読み込ませます。
 ```javascript: app/javascript/packs/application.js
 import '../stylesheets/xxxx.css' /// xxxx.cssは先ほどの読み込ませたいcssファイル名に変更してください
 ```

 これで完了です！お疲れ様でした！
Web開発時のHTMLの名称

# はじめに
この記事は、Web開発の初心者向けに、HTMLの入力データをサーバーに送信する際の名称についてまとめています。

## 経緯
Web開発の学習をしていると、クライアントとサーバー間の情報の送受信で「キー」と「値」といった用語がよく出てきます。しかし、これらの名称が正しく理解できていなかったため、この記事ではHTMLの名称についてまとめてみました。

## HTMLの基本名称
まず、HTMLの基本的な名称をおさらいします。
HTMLコードは以下の要素で構成されています。

- `<p> class="hoge>ホゲ</p>`　要素
  - `<p>`: 要素の開始タグ
  - `</p>`: 要素の終了タグ
  - `class="hoge"`: 属性（attribute）
  - `class`: 属性名
  - `hoge`: 属性値
  - `ホゲ`: コンテンツ（要素内のテキスト）

[Mozilla Developer Network(HTML の基本)のドキュメント](https://developer.mozilla.org/ja/docs/Learn/Getting_started_with_the_web/HTML_basics)を参考にしています。

## Web開発におけるHTML
ウェブ開発では、クライアントとサーバー間でデータの送受信が行われます。ここでは、フォーム要素を使ってクライアントからサーバーにデータを送信する場合を考えてみます。

### 宛先の設定
`form`の開始タグ内で`action`属性を指定することで、データの送信先を設定します。
`action`属性は相対/絶対 URL を設定します。

### 送信方法の設定
`form`の開始タグ内で`method`属性を指定することで、データの送信方法を設定します。
データの送信方法には最も一般的な2つの方法があります。

1. **GETメソッド**
リクエストのアドレスに含める方法
   - `method="GET"`と指定します
   - 宛先のURLの末尾に`?`が追加され、その後に`name`属性値と`value`属性値を`=`で繋げ追加されます
   - 複数の送信内容がある場合は、`name1=value1&name2=value2`のように`&`でつなげて追加します

2. **POSTメソッド**
リクエストのデータに含める方法
   - `GETメソッド`とは異なり、URLの末尾にはデータが付与されず、リクエストのデータに入れて送信します

### サーバー側での受け取り
サーバー側では、GETメソッドまたはPOSTメソッドを選択しても、キーと値の組としてデータが解析されて受け取られます。

[Mozilla Developer Network(フォームデータの送信)のドキュメント](https://developer.mozilla.org/ja/docs/Learn/Forms/Sending_and_retrieving_form_data)を参考にしています。
【コマンドライン】基本コマンド

## コマンドの種類
### ファイルを作成する
```
$ touch ファイル名
```

### ファイルの中身を表示する
```
$ cat ファイル名
```

### ファイルの中身を表示する(全画面)
```
$ less ファイル名
```

### ディレクトリを作成する
```
$ mkdir ディレクトリ名
```

### ディレクトリを移動する
```
$ cd ディレクトリ名
```

### カウントディレクトリを表示する
```
$ pwd
```

### ファイル・ディレクトリを一覧表示する
```
$ ls
```

### ファイルを移動させる
```
$ mv 移動させたいファイル名　移動先のディレクトリ名
```

### ファイルを移動させる
```
$ mv 移動させたいファイル名　移動先のディレクトリ名
```

### ディレクトリごと移動させる
```
$ mv 移動させたいディレクトリ名　移動先のディレクトリ名
```

### ファイル名を変更する
```
$ mv 現在のファイル名　新しいファイル名
```

### ディレクトリ名を変更する
```
$ mv 現在のディレクトリ名　新しいディレクトリ名
```

### ファイルをコピーする
```
$ cp コピーするファイル名 新しいファイル名
```

### ディレクトリごとコピーする
```
$ cp -r コピーするディレクトリ名 新しいディレクトリ名
```

### ファイルを削除する
```
$ rm 削除するファイル名
```

### ディレクトリごと削除する
```
$ rm　-r 削除するディレクトリ名
```
Azure data factoryのメタデータ駆動型のパイプラインをスケジュール実行する際の一工夫

# はじめに
Azure data factoryには大規模なデータコピー用のパイプラインをGUIで簡易に作成する機能があります。詳細は以下を参照。

https://learn.microsoft.com/ja-jp/azure/data-factory/copy-data-tool-metadata-driven

このパイプラインを作成し手動実行している際は問題なく実行できていたのですが、スケジュール実行にした途端データコピーが行えない(実行自体は成功するがコピーができていない)自体が発生したので、備忘もかねて共有します。

# メタデータ駆動型のパイプライン
メタデータ駆動型のパイプラインを作成すると、以下のような形でフォルダ配下にTopLevel、MiddleLevel、BottomLevelの3つのパイプラインが作成されます。つくりとしては、TopLevelがMiddleLevelの、MiddleLevelがBottomLevelの親パイプラインとなり、TopLevelパイプラインを実行することでMiddeLevel、BottomLevelのパイプラインがキックされます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269528/bd54fcd7-cb51-605e-ce28-12f79a8601e8.png)

BottomLevelパイプラインのデータコピーアクティビティにてデータソースからデータシンクへデータ連携する処理が要となり、その前段の処理でコピー対象のデータの指定や同時実行数などを制御しています。コピー対象のデータを制御する部分は、別途作成する制御テーブルで行っており、ざっくり言うと制御テーブルにかかれているオブジェクトがデータコピーの対象となります。
制御テーブルの構成は以下です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269528/c3f33fb1-5e25-dc61-fe47-5bf5a5981bf1.png)
引用：https://learn.microsoft.com/ja-jp/azure/data-factory/copy-data-tool-metadata-driven#control-tables

# 今回発生したこと
今回は作成済で手動実行が成功したメタデータ駆動のパイプラインをトリガーによるスケジュール実行に切り替えた際、データコピーが行えない(実行自体は成功するがコピーができていない)自体が発生しました。

# 原因
原因は2つになります。

1つはTopLevelパイプラインの一番最初の処理である「GetSumOfObjectsToCopy」にあります。
この処理はデータコピーの対象オブジェクトの数を確認し、次以降の処理のループ処理の回数に関係してくるのですが、オブジェクト数を確認する以下のクエリに原因がありました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269528/a6104626-b160-503e-28e9-d6b7aeff3c9c.png)

where句で”TriggerName”を条件対象に指定していますが、”TriggerName”にはデフォルトでは["Sandbox","Manual"]が入るようになっています。

手動実行でパイプラインを実行した際はSQL文は”TriggerName”に'%Manual%'が入るようになりますが
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269528/2eff0cb3-a5f0-4d25-b69e-96271e7f0bda.png)



トリガーを利用した場合はトリガー名がはいります。そのためwhere句の条件で該当なしとなり、SQLの結果が0となってしまったのが今回の原因でした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269528/d8b87cea-5ba2-39c7-33c0-b847b1dab736.png)


修正方法としては、制御テーブルの”TriggerName”カラムの値をトリガー名も含む形にupdateしてあげるか、「GetSumOfObjectsToCopy」アクティビティの”TriggerName”の条件を削除してあげるかのいずれかとなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269528/8c3a696a-fe46-1ee7-d9d3-7991d14d13fd.png)

2つ目はMiddleLevelパイプラインの一番最初の処理である「GetObjectPerGroupsToCopy」にあります。
この処理でもトリガー名で絞っています。1つ目の修正方法で制御テーブルの値を変更している場合は問題ありませんがクエリの編集で回避する場合はこちらも”TriggerName”の条件を削除してあげる必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269528/afdfd9f2-85b7-3cff-fef1-be641158c20e.png)
【ChatGPT有＋DALL-E3】いい画像ができた。プロンプトそのままで、ほかの画像を見たい。どうすれば？


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

　今回は、いい画像ができたけど、それを消さずに、ほかの画像を見たい。どうすればいいかを書きます。

:::note info
本記事は、ChatGPT（有料版）
＋DALL-E3で行なっております。
画像はありません。あしからず。
:::

　まずは、ニュース。

　　[特定のワードが大学の論文で出現しまくっておりChatGPTなどの生成AIが使用されたことを示す危険信号となりつつあることが明らかに](https://gigazine.net/news/20240207-chatgpt-school-applications/)

　大学の論文で
　　「タペストリー」
　　「ビーコン」
　　「充実したカリキュラム」
　　「尊敬する教授陣」
　　「活気に満ちた学術コミュニティ」
　　　といった特定のワードが、
　　　　論文執筆に現れるように
　　　　　なっているそうです。

　そして、それは
　　ChatGPTのような
　　　文章生成AIから
　　　　生成された論文に
　　　　　よく出てくるとか。

　ここでは
　　“論文コンサルタント”なる
　　　職業の人が、論文をチェック
　　　　していて、その傾向がある
　　　　　と話しています。

　でもこれ、
　　文章生成AIに
　　　“書くな”と書いておけば、
　　　　ある程度、回避可能だから
　　　　　チェックを素通りする、
　　　　　　そんな気がします。
***
　次は、
　　OpenAIデベロッパーから
　　　X-Twitterでのポストです。

　これを読んでくれている方々には
　　あまり関係ないかもしれませんが
　　　一応、念のために。

>You can now create API keys that are limited to specific API endpoints, enabling granular permissions and better security.

　DeepL翻訳
「特定のAPIエンドポイントに限定したAPIキーを作成できるようになり、きめ細かな権限設定とセキュリティの向上が可能になりました。」

　APIを使う人にとっては
　　さらに便利になる、と
　　　いうことでしょうね。
　　　　オイラ、関係ない(=^･^=;
***
　それから
　　DALL-E3が
　　　実はDALL-E4だと
　　　　ChatGPTから
　　　　　言われた件ですが、
　　　　　　誰もが
　　　　　　　ハルシネーション
　　　　　　　　だろうと
　　　　　　　　　言っています。

　まぁ、
　　その可能性は
　　　否めませんけれど、
　　　　あの回答の仕方は
　　　　　事実のような気がします。

　だって、
　　DALL-E3 Controlsなんてのが
　　　用意されていて
　　　　出荷を待っている、
　　　　　というポストも
　　　　　　ありますから。

　このDALL-E3 Controlsっていうのは
　　画面を見る限り、
　　　Midjourneyのような
　　　　操作が可能になる感じです。

　DALL-E3使いとしては、
　　微調整できるのは
　　　よろこばしいことですね(=^･^=)

　話がズレました。
　　DALL-E4というのは
　　　本当のことかもしれないし、
　　　　ハルシネーションかも。

　現状は
　　保留になります。
***
　さて、
　　本題にいきましょう。

　描画された画像は
　　セッション中に
　　　保持しておきたいものです。

　もちろん、
　　ダウンロード
　　　という手はあります。

　しかし、
　　そこまでする必要も
　　　感じられないことも
　　　　多々あります。

　プロンプトを編集すると
　　その画像はセッション内で
　　　編集前として、表から消えます。

　ChatGPTアプリでは
　　編集はできませんけど。

　Regenerateボタン（コピー横）だと
　　画像が書き換えられますし。

　見えるところに
　　その画像を残しておきたい
　　　そんな場合は、多々あります。

　そして、
　　新たな画像も
　　　欲しい。

　英文プロンプトとSEED値を出して
　　プロンプトとして与える方法も
　　　ありますが、それもメンドイ。
***
　そこで
　　“リトライ”と入力して
　　　みてください。

　新たに描画されます。

　注意点は、
　　何度もリトライは
　　　できない点です。

　ChatGPTさんが
　　“何度も描画してますよね”的な
　　　文句を言ってくるからです。

　三回くらいは
　　大丈夫かと思います。
***
　この“リトライ”、
　　実はプロンプトの調整にも
　　　使えます。

　背景を変えたり、
　　雰囲気や画風を変えたり。

　やり方も簡単。

　例えば、
　　画風を
　　　リアルから
　　　　アニメ風にするなら

　“リトライ。アニメ風にして。”

　と指示すれば、
　　やってくれます。

　これは、
　　SEED値を指定するのと
　　　よく似ていますね。

　でも、
　　英文プロンプトやSEED値を
　　　出力せずにできるので、
　　　　とても楽です(=^･^=)

　ただし、
　　SEED値と同じように
　　　完璧ではなく、
　　　　指示も効かない場合が
　　　　　あります。

　ChatGPTさんに
　　絶対はありません。
　　　それは注意すべきですね。

　それでも
　　同じことをするなら
　　　簡単な方がいい、
　　　　というのは
　　　　　誰もが思うことでしょう。

　こんなことが
　　みなさんの作品制作の
　　　一助になれば、幸いです。

　今回は、ここまで。