OmniAICreator/Qiita-1.07M huggingface dataset:
AIによる感情分析とカテゴライズを用いたMicrosoft　Power Platformによる問い合わせ対応システムの概略

# AIによる感情分析とカテゴライズを用いたMicrosoft　Power Platformによる問い合わせ対応システムの概略

試作したので、記録のために書き置きします。
chatGPTと対話して用件をまとめましたので、正解かは分かりません


1. **Microsoft Formsのセットアップ**

   - Microsoft Formsを開き、新規のFormを作成します。
   - 与えられたフィールド（名前、ふりがな、郵便番号、住所、電話番号、メールアドレス、宛先、問い合わせ内容）を入力フィールドとして設定します。特に宛先フィールドについては、与えられた選択肢をドロップダウンリストとして設定します。

2. **SharePointリストのセットアップ**

   - SharePointのサイトを開き、新しいリストを作成します。
   - 与えられた列名（名前、ふりがな、郵便番号、住所、電話番号、メールアドレス、宛先、問い合わせ内容、提出日時、タイトル、感情スコア、ネガポジ判定、緊急フラグ、対応ステータス、担当者、エスカレーションフラグ、返信内容、TeamsメッセージID）を作成します。

3. **Power Automateのセットアップ**

   - Power Automateを開き、新しいフローを作成します。トリガーとして「Microsoft Formsからの新しいレスポンスを取得」を選択します。
   - 「新しいレスポンスを取得」アクションの後に「SharePointのリスト項目の作成」アクションを追加します。これにより、新しいFormのレスポンスがSharePointリストに自動的に保存されます。
   - 次に、AzureのCognitive Servicesを使用して感情分析を行い、結果をSharePointの感情スコア列に保存します。このためには、「HTTPアクション」を使用してCognitive Services APIにリクエストを送信し、「問い合わせ内容」フィールドを送信します。次に、レスポンスを解析し、結果をSharePointの感情スコア列に格納します。
   - その後、条件アクションを設定して、感情スコアに基づいて緊急フラグを設定します。
   - 次に、「Teamsのメッセージの作成」アクションを追加します。これにより、新しいリスト項目が作成されると、自動的にTeamsの指定チャネルにアダプティブカードが投稿されます。
   - アダプティブカードは、受付ボタンと差し戻しボタンを含むように設計します。それぞれのボタンは、リスト項目の対応ステータス列を更新するか、指定の担当者にTeamsで通知するアクションをトリガーします。

4. **Power Appsのセットアップ**

   - Power Appsを開き、新しいCanvas Appを作成します。
   - SharePointリストをデータソースとして接続します。これにより、アプリ内でリスト項目を表示および編集できます。
   - 一覧画面と詳細画面を作成します。一覧画面では、すべてのリスト項目を一覧表示し、詳細画面では、選択したリスト項目の詳細を表示し、OpenAI APIを使用して作成した返信を確認して編集できます。
   - メール送信機能を追加します。これには、「Office 365 Outlookのメールを送信」アクションを使用します。メールの本文には、OpenAI APIで生成した返信を使用します。
   - 返信が送信されたら、対応ステータス列を「完了」に更新します。また、該当するTeamsメッセージに@mentionを付けて通知します。

5. **Power BIのセットアップ**

   - Power BI Desktopを開き、新しいレポートを作成します。
   - SharePointリストをデータソースとして接続します。このときに適切なリスト（問い合わせデータが保存されているリスト）を選択します。
   - 必要なデータビジュアルを選択してドラッグ＆ドロップし、各ビジュアルに対応するフィールドを設定します。例えば、問い合わせ数の時間帯別グラフ、問い合わせ内容の感情スコア分布、問い合わせの種類別数などを設定できます。
   - レポートが完成したら、Power BI Serviceにパブリッシュします。Power BI Serviceでは、作成したレポートをダッシュボードとして組み合わせることができます。

6. **カテゴリ分類のセットアップ**

   - Power Automate内で新しいフローを作成します。トリガーとして「SharePointリストアイテムの作成または更新」を選択します。
   - 作成または更新されたリストアイテムの問い合わせ内容を取得し、テキスト分類用のAIサービス（例えばAzureのText AnalyticsまたはCognitive Services）に送信します。
   - AIサービスから返されたカテゴリを取得し、SharePointリストアイテムの新しいフィールド（例えば「問い合わせカテゴリ」）に保存します。


```mermaid
sequenceDiagram
    participant User
    participant Forms as Microsoft Forms
    participant PA as Power Automate
    participant SPList as SharePoint List
    participant PApps as Power Apps
    participant AI as AI Category Classifier
    participant PB as Power BI

    User->>Forms: Submit form (名前, ふりがな, 郵便番号, etc.)
    Forms->>PA: Trigger new response
    PA->>SPList: Create new item with given details
    PA->>AI: Send enquiry content for classification
    AI->>PA: Return classification result
    PA->>SPList: Update item with classification result
    PA->>PApps: Notify new item
    PApps->>User: Display item details
    User->>PApps: Send reply
    PApps->>User: Update status, notify on Teams
    SPList->>PB: Data connection
    PB->>User: Display dashboard
CGアニメーション　入門　Part2 ボールのバウンド　in DazStudio

# 概要
ボールをバウンドするアニメーションを作ります。
以下gifアニメは完成後の様子です。

![boudingballEnd.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/435c4f7e-a59b-672a-1474-a2819f5632df.gif)


# 開発環境
OS:Windows10
DazStudio:4.2105 proEdition
プラグイン：aniMate2

# 手順 


## １．コマ割りを打ち込む



aniMate2タブを選択してframe =0 30 60 90 120 150でフレームを打つ
下図

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/24fa98d3-ab14-c1e9-0cb4-be1741599cff.png)


キーを打ち込んだ後アニメーションになっていることを確認

![baund-x.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/951df965-6e95-062a-d531-2f2fdd60c72e.gif)



## ２．アニメーションカーブの編集
CGソフトで補間した動きのみだと　不自然な動きになるのでアニメーションカーブを編集します。

### DazStudio　aniMate2の操作

#### グラフエディタを開く
以下gifアニメはグラフエディターを開く手順です。

![graph editor.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/7e71e169-687b-a19f-545d-2d37b0e6222d.gif)


#### アニメーショングラフにキーを加える。
１．追加したいフレームを選択する
２．Keyアイコンを選択する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/93c754be-20da-5e06-efc0-ad49f2815b6c.png)


### 垂直方向　スローイン・スローアウトを適用する


以下動作をループしている。
①地面付近　スローイン
②頂点付近　スローアウト
①、②を繰り返している。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/8fd54e99-e13c-753a-1499-da666b5c9364.png)




修正後のアニメーションカーブ（下図）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/6ad7d2a6-c174-774b-b43b-51270ad7def5.png)




### 水平方向- バウンドする度に横幅を狭くする

バウンドする度に高さが小さくなるため、幅も小さくなります。






![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/5a681665-c8de-6da0-46ba-f0a1684fab94.png)


以下画像は修正前後のアニメーションカーブ
アニメーションカーブの変化量を徐々に小さくするようにして再現します。
徐々に傾きを小さくしています。

frame=30,90,150(１秒、２秒、４秒)のキーを削除します。
frame=60,120において前の区間よりも傾き（変化量）が小さくなるように調整します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/cce87070-1c8c-71d8-5b44-62312bda5548.png)




# アニメーションカーブ編集前後の比較
![compareballs.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/6673ae52-82ce-0c0f-3138-9f78f3da9cac.gif)



# 参考


## 背景画像を設定する方法

https://3dcreategame.giren.net/3d%E3%81%84%E3%81%98%E3%82%8A/%E3%80%90daz-studio4-7%E3%80%91backdrop%E3%81%A9%E3%81%93%E3%81%84%E3%81%A3%E3%81%9F%EF%BC%81.html


## 書籍

著者：荻野哲哉「３DCG アニメーション入門」pp29-40

著者：リチャード・ウィリアムズ「増補アニメーターズ　サバイバルキット」　pp35-39 すべてはタイミングとスペーシングだ
k3sをサクッと構築する

## 目的
k8sの検証環境が欲しかったのだが、頻繫に作って壊す事が多かった。しかし、この”作って壊す”時間が思った以上にかかってしまうので、VMのプロヴィジョニングにはTerraformを用いて、k8s自体はk3sで構築する事によって爆速で構築する

## VMの用意
```
172.24.20.201 (master)
172.24.20.202 (worker)
172.24.20.203 (worker)
172.24.20.204 (worker)
172.24.20.205 (worker)
```

## masterの構築
```bash
curl -sfL https://get.k3s.io | sh -
```

### masterの構築確認
```bash
root@terraform-vm01:/home/tmcit# k3s kubectl get nodes
NAME             STATUS   ROLES                  AGE   VERSION
terraform-vm01   Ready    control-plane,master   26s   v1.27.3+k3s1
```

### tokenの確認
```
root@terraform-vm01:/home/tmcit# cat /var/lib/rancher/k3s/server/token
K10fb096c5dc65b65631cd714d4554ac3dd6c5643c085b798acd97d9640a9bec57d::server:bf175bc6408ff73d32c9ab6224bfbb4d
```

## workerの構築
```bash
root@terraform-vm04:/home/tmcit# curl -sfL https://get.k3s.io |\
K3S_TOKEN="K10fb096c5dc65b65631cd714d4554ac3dd6c5643c085b798acd97d9640a9bec57d::server:bf175bc6408ff73d32c9ab6224bfbb4d" \
K3S_URL=https://172.24.20.201:6443 sh -
```

## masterからクラスタの構築を確認する
```bash
NAME             STATUS   ROLES                  AGE     VERSION
terraform-vm01   Ready    control-plane,master   3m33s   v1.27.3+k3s1
terraform-vm02   Ready    <none>                 99s     v1.27.3+k3s1
terraform-vm03   Ready    <none>                 77s     v1.27.3+k3s1
```
GCP Professional Cloud Architect取得しました

# GCPのProfessional Cloud Architect取得しました
2023/06に受験して無事に合格したので、備忘がてらどういう形で勉強したのかを記載します。

# 背景
普段はクライアント側のエンジニアで、インフラ周りの知識は正直皆無でしたが、会社でGoogleCloud主催の「E.G.G. Japan」というプログラムに参加する機会があり、興味を持ちました。

「E.G.G. Japan」について簡単に説明すると、ゲーム業界で働くエンジニア向けの招待制特別プログラムです。
GoogleCloudJapan合同会社のエンジニアからセッションを受講できたり、自習プログラムという形でCourseraのコースを期間限定で無料で受けられたりもしました。
E.G.G参加中は資格取得まではできませんでしたが、受講後に約半年間、ちょくちょく勉強を進めて無事に取得することができました。

# 学習に使用したサービス
### Coursera
https://www.coursera.org/

基礎知識は上記で身につけました。
動画での説明はもちろん、勉強用のGCPを直接触って色々とサービスを立ち上げたりもできました。
正直ベース、自分の性質上資格試験においては直接のサービスを触ってもあまり参考になっていなかった感がありますが、実際に使うという場面においてはかなり参考になっていると感じます。
Courseraで触りまくったせいか、業務で使っているAWSよりも親しみを持ててます(笑)

### Udemy 模擬問題
https://www.udemy.com/course/google-cloud-professional-cloud-architect-i/

勉強時間の8割を模擬問題を解くことに費やしました。
模擬問題はセット1~セット3、追加セットまでありますが、それらを何度も何度も解いて全て正解できるようになるまでやりました。

正直、自分はクライアントサイドで、本当にインフラ知識0から始めたので、Courseraの動画を見た後に模擬問題を解く形だと、ちょっとしたニュアンスの違いがあっただけで全くわからなくなるという事象が発生していました。
そのため、模擬問題を最初に実施し、訳がわからない部分は都度動画をみたり、調べたりしてました。
結果的に、この形式は自分に合っていたと言えます。

# 学習方法
自分的おすすめは1問1答形式で模擬試験を繰り返し行うことです。
自分の時は模擬試験を(友人に作ってもらった)1問1答ツールに流し込み、それを繰り返す解く形にしていました。

私はあまり学習時間をまとめて取ることができない関係で、模擬試験50問を一気に解くことができませんでした。
そこで、1問1答とすることで、電車などの空き時間でもちょくちょく模擬試験を進めることができていました。
また、すぐに正誤や解説が表示されることで、頭に入りやすいという利点もありました。

# 受験するにあたってのTips
最後に、受験の際の心構えじゃないのですが、Tips的なことを記載します。

### 試験はテストセンターで行う方が良い
ちょっと調べると、みんな似たようなことを言っているかと思います。
面倒臭いなと思う方もいるかもしれませんが、初回受験の方ほどガチでテストセンターに行った方がいいと思います。
何故かというと、自宅でのリモート受験の場合、かなり環境を用意するのが面倒だからです。
テストセンターはその点、環境はデフォルトで用意されており、困った場合に試験管をすぐに呼ぶことができるため、テスト前に環境整備でバタバタとする必要がありません。

### 模擬試験はやっておいた方がいい
普段インフラエンジニアとしてやっている方でも、一度は模擬試験を解いておいた方がいいと思います。というのも、やはりこういう試験あるあるかもしれませんが、独特の言い回しがあったりするからです。

一度模擬試験をフルでやってみて、こういう感じね、というような感覚を掴んでおいた方がいいと思います。
また、実際の試験では、先ほどリンクを貼った模擬試験の内容のうち体感6~7割が出題されていたように感じました。
記憶に残ってた問題が出題されたらラッキーかと思うので、一度は絶対に解いておいた方がいいと思います。

### 丸暗記は危険
先ほど、模擬試験の内容のうち体感6~7割は出題されると言いました。
ただ、文章ごとの丸暗記は危険です。
というのも、実際の試験が先ほどリンクを貼った試験よりも、細かいニュアンスの違いがあるというか、、、模擬試験では日本語だった部分が、英語や機械翻訳に近い感じの違和感のある日本語で出題されることがあるためです。

実際の例で言うと、以下のような形になっていました。
模擬試験：説明可能なAI
実試験：Explainable AI

そのため、いくら大半は模擬試験から出ると言っても、ある程度意味を理解することが重要だと言えます。

### 見直しは重要
見直しは重要です！！
私は見直しで30分は使いましたが、その30分で一問のミスを見つけられました。
前項でも記載したとおり、実際の試験では機械翻訳のような日本語や、模擬試験では日本語表記だった部分が英語になっている箇所があります。
そのため、改めて見直すと知らない問題だと思ってたのに実際は知っていた問題だった、というケースがありえます。
ちょっとでも不安な問題には見直し用のチェックがつけられるので、それをつけておいて、最後提出前に2周は見直すようにしましょう！！

### 暫定結果の確認
ネットを調べると、アンケート終了後に暫定の結果が表示されると記載されている人が多いのですが、私は何故か見つけられませんでした、、
ただし、だからと言って実際の合否連絡がくるまで暫定結果が見れないと言うことはありません。
テスト登録をしたサイトがあると思うのですが、そこから登録されているテストを見ることができまして、その部分に暫定結果が表示されます。
そのため、テスト後に暫定結果を見逃してしまった場合は、テスト登録をしたサイトを覗いてみましょう。

# 最後に
久しぶりの試験勉強でしたが、だいぶ懐かしい気持ちにさせられました。
(多分専門学生の時以来なので、5年ぶりぐらいだったように思います)

最近はクライアントエンジニアでもインフラ周りの知識が全くないと難しい場面も出てくるように思います。
特にソーシャルゲーム開発していると、ある程度MTG中にインフラ周りの話も出てくることが多い印象です。知っておいてぜっっったいに損はないと思います。
(あとインフラ周りの知識があると個人サービス作る際にもめっちゃ便利です、、)
もしよければ、迷っているクライアントサイドの方がいたらぜひ受けてみてください。

ぜひぜひ、クライアントエンジニアでも、インフラ/サーバサイドのエンジニアでも、少しでもこれから受験する人の参考になれば幸いです。
lolipopメールを活用したSPF設定とその回避方法

<h1>lolipopメールを活用したSPF設定とその回避方法</h1>
<h2>利用したサイトリスト<h２>

<a href="https://support.lolipop.jp/hc/ja/articles/4664555243411-Gmail%E5%AE%9B%E3%81%AB%E3%83%A1%E3%83%BC%E3%83%AB%E3%81%8C%E9%80%81%E4%BF%A1%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84">Gmail宛にメールが送信できない</a>

<a herf="https://lolipop.jp/media/what-is-an-spf-record/?_gl=1*1avhko1*_ga*MTU3NjE0MzcwMy4xNjg2OTU5NjA0*_ga_FDZ1BHLN82*MTY5MDY5NTk4OC43LjAuMTY5MDY5NTk4OC42MC4wLjA.&_ga=2.208295766.553359181.1690695989-1576143703.1686959604">SPFとは？SPFの仕組みとSPFレコードの設定方法について解説します</a>

<a href="https://asumeru.net/spf-record-check">SPFレコードの確認方法
</a>

<a href="https://asumeru.net/tools/spf/spfchecker.php">SPFレコードチェックツール</a>

<a href="https://muumuu-domain.com/?mode=conpane&state=muudns_list">ムームーＤＮＳのセットアップ情報変更</a>

<a href="https://support.lolipop.jp/hc/ja/articles/4403089052179">レコード情報の設定はどうしたらいいですか（ムームーDNS利用）
</a>
<a href="https://lolipop.jp/manual/mail/gmail/"> 
Gmailの設定</a>

<h1>結論：SPFレコードを複数設定していたことでメールが送れなかった。</h1>
SOLIDとは


SOLID原則について学習しましたのでアプトプットもかねて載せます。

# SOLIDとは
オブジェクト指向プログラミングにおいて、柔軟性、保守性の高いソフトウェアを設計するための５つの原則の頭文字をとったマクロニム（略語）です。

5つの原則
1 単一責任の原則
2 オープンクローズドの原則
3 リスコフの置換原則
4 インターフェース分離の原則
5 依存性逆転の原則

今回は5 依存性逆転の原則（DIP)について説明します。

# 依存性逆転の原則（DIP)とは
依存性逆転の原則とは高レベルのモジュールは低レベルのモジュールに依存するべきではなく、
どちらのモジュールも抽象に依存に依存すべきたどいう原則です。具体的にはインターフェースを介して依存関係を持つことでコードの結合度を低くして、拡張や変更が簡単になるという考え方です。

Laravelでは依存性逆転の原則を実現するために、依存性注入とサービスプロバイダーを使うことで依存関係を解決し、クラス間の結合を疎結合に保ちつつ、柔軟で拡張性のある設計が実現できます。

例を使って説明します。
例として、ユーザー情報を取得するサービスクラスUserServiceがあります。UserServiceは、リポジトリを使ってデータベースからユーザー情報を取得します。
```
class UserService
{
    private $userRepository;

    public function __construct(UserRepository $userRepository)
    {
        $this->userRepository = $userRepository;
    }

    public function getUser($userId)
    {
        return $this->userRepository->find($userId);
    }
}
```
上記のUserServiceは依存関係を解決するために、UserRepositoryをコンストラクタインジェクションにより受け取っています。これにより、UserServiceはUserRepositoryに依存しています。しかし、依存性逆転の原則を考慮すると、高レベルのUserServiceが低レベルのUserRepositoryに直接依存すべきではないとされます。

この問題を解決するために、インターフェースを導入します。UserServiceはUserRepositoryInterfaceというインターフェースに依存するように変更します。

```
interface UserRepositoryInterface
{
    public function find($userId);
}

class UserService
{
    private $userRepository;

    public function __construct(UserRepositoryInterface $userRepository)
    {
        $this->userRepository = $userRepository;
    }

    public function getUser($userId)
    {
        return $this->userRepository->find($userId);
    }
}
```
これにより、UserServiceは具体的な実装に依存せず、インターフェースに依存するようになりました。具体的な実装はサービスコンテナを使って解決します。

Laravelのサービスコンテナは依存性の注入をサポートし、インターフェースと具体的な実装クラスの紐付けを管理します。例えば、次のようにUserRepositoryクラスをUserRepositoryInterfaceとして登録します。

Provider
```
app()->bind(UserRepositoryInterface::class, UserRepository::class);
```

これにより、UserServiceがUserRepositoryInterfaceに依存するようになり、依存性逆転の原則を守ることができます。また、将来的にUserRepositoryの実装を切り替える場合でも、サービスコンテナの設定を変更するだけで切り替えが可能になります。

依存性逆転の原則を守ることで、クラス間の結合度を低くし、柔軟な設計と拡張性を実現することができます。Laravelのサービスコンテナと依存性注入を使うことで、依存性逆転の原則を簡単に実践することができます。

依存性逆転の原則は以上です。ありがとうございました。
【Python】プログラミング未経験男が、PaizaでBランク達成するまでにやった事

## 目次

[1.はじめに](#1-はじめに)
[2.プログラミングを始めたきっかけ](#2-プログラミングを始めたきっかけ)
[3.最初にやったこと](#3-最初にやったこと)
[4.Pythonを本格的に勉強する](#4-.Pythonを本格的に勉強する)
[5.おわりに](#5-おわりに)


# 1. はじめに
簡単にスペック紹介したいと思います。

23歳男。現在SESの高卒。高校では理系だったが、物理や数学の授業では、１時間ずっと寝ていて教師にガチギレされていたという経歴を持つチンパン野郎です。

# 2. プログラミングを始めたきっかけ
そんなチンパン野郎の僕が、なぜプログラミングを始めようと思ったかというと、パソコンをいじるのが好きだからなのと、ITスキルを持ってれば、食いっぱぐれないだろうという安易な考えでした。
# 3. 最初にやったこと
そもそも何をどう勉強したらよいか分からなかったので、とりあえず
ProgateというアプリでHTML、CSS、PHPを勉強しました。

今思えば、個人的にはHTML、CSSはコピペでよくね？と思っている人間なので、覚えるまで勉強する必要はないのかなと思いました。(分からなかったらググればいい）

その後、wordpressで簡単なサイトを作ったりもしました。

そして時が経ち、SESとして就職し常駐した会社で、Pythonを使った仕事をしている人が分かりました。

調べてみると、PythonはAIやらwebアプリやらゲームやらを作れる万能の言語であることが分かりました。

そこで僕もPythonをマスターすれば、一生食いっぱぐれなくね？というチンパン思考が働きました。


# 4. .Pythonを本格的に勉強する
Youtubeなどで、Paizaというプログラミング勉強サイトがある事を知り、初めてみました。

Paizaはランクの概念(D ~ S)があり、ゲーム感覚で勉強できるのが魅力です。

そこでPaizaの映像授業を使いながら、Pythonの基本的な文法を勉強することから始めました。

思いのほか、Cランクまではすぐに行けたのですが、Bランクが激!
ムズっていう感じで、まったく出来ませんでした。

そこでBランク獲得ストーリーなるものがあったので、とりあえずそれに沿ってやっていたりを、半年ほど続けたら、なんとBランクの問題を解くことができました。

嬉しすぎて、興奮が収まらないほどでした。
↓が解けたやつ

![PaizaBランク.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3522841/3d719c7a-e9a2-0670-2f59-4e8417a49e97.png)



# 5. おわりに
以上が僕がBランクになるまでやった事です。

しかし、ぶっちゃけPaizaのBランクは、Atcoderみたいにアルゴリズムを使わないと解けないという問題ではなく、問題文通りに実装すれば解ける問題が多いです。

とりあえず現在は、Pythonを使った仕事に転職できるように、ポートフォリオづくりを頑張っています。
wslのtensorflowでkerasのbackend その9

# 概要
wslのtensorflowでkerasのbackendを試す。
練習問題、やってみた。

# 練習問題
kerasのbackendでxorを学習したウェイトとバイアスを使って、elixirのnxで再現せよ。

# サンプルコード

```
defmodule XorNet do
	import Nx.Defn
	defn init_params do
		w1 = Nx.tensor([[-3.4681022, 0.379121, -1.4711456, 2.2247136, 2.3135107, 2.7624693, -1.83576, -1.1545312],
					 [2.1978209, 0.2895245, 2.0881913, -1.3450832, -1.4154571, 1.9255028, 3.2867477, 1.956522]])
		b1 = Nx.tensor([-0.6591252, 0.3864409, 0.4982838, 0.3707547, 0.3982254, -0.3612466, 0.4284867, 0.2701645])
		w2 = Nx.tensor([[1.4324994], [0.7911373], [-2.3011343], [-1.7614117], [-2.4442003], [3.9701838], [-1.837263], [-1.3641325]])
		b2 = Nx.tensor([0.9285715])
		{w1, b1, w2, b2}
	end
	defn predict({w1, b1, w2, b2}, x) do
		x
		|> Nx.dot(w1)
		|> Nx.add(b1)
		|> Nx.tanh()
		|> Nx.dot(w2)
		|> Nx.add(b2)
		|> Nx.sigmoid()
	end
end

defmodule M do
	def l do
		params = XorNet.init_params()
		IO.puts "1, 1"
		x = Nx.tensor([1.0, 1.0])
		XorNet.predict(params, x)
		|> IO.inspect
		IO.puts "1, 0"
		x = Nx.tensor([1.0, 0])
		XorNet.predict(params, x)
		|> IO.inspect
		IO.puts "0, 1"
		x = Nx.tensor([0, 1.0])
		XorNet.predict(params, x)
		|> IO.inspect
		IO.puts "0, 0"
		x = Nx.tensor([0, 0])
		XorNet.predict(params, x)
	end
end

```

# 実行結果

```
Interactive Elixir (1.13.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> M.l
1, 1
#Nx.Tensor<
  f32[1]
  [0.015668833628296852]
>
1, 0
#Nx.Tensor<
  f32[1]
  [0.9831985235214233]
>
0, 1
#Nx.Tensor<
  f32[1]
  [0.9836318492889404]
>
0, 0
#Nx.Tensor<
  f32[1]
  [0.009060143493115902]
>
iex(2)>
```

以上。
【GitHub Actions】 CI/CD実行トリガーの対象パスを制限


## プロジェクト構成

プロジェクトに対して`GitHub Actions`を用いてCI/CDを実現したいと思います。
例えばプロジェクトが下記のような構成だとします。
`backend/`と`frontend/`に対してテストと静的解析を通して自動デプロイしたいです。
逆に他のファイルやディレクトリの変更に対してそれらのワークフローを実行する必要はありません。
```
.
├── .git
├── .github
├── .gitignore
├── README.md
├── backend
├── documents
└── frontend
```


## 変更前のワークフロー設定

変更前のワークフロー設定ファイルの内容です。
下記の設定だと、mainブランチへのプッシュやプルリクエストをトリガーにワークフローが実行されます。
しかしこのままだと、`backend/`、`frontend/`以外の変更に対してもテストや静的解析、自動デプロイといったワークフローが実行されてしまい、少し大げさだなと思いました。

```yml
name: CI/CD

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    ...
  deploy:
    ...
```


## 変更後のワークフロー設定

`paths:`フィルタを使うと、特定のファイルやディレクトリに対する変更を含むプッシュやプルリクエスト時にのみワークフローを実行するように設定できます。
`*`が1つだと、指定したディレクトリ直下だけが対象になり、その下のサブディレクトリのファイルまではマッチしません。
`**`だと、任意のディレクトリ、任意の深さという意味になるので、指定したディレクトリ以下のすべてのファイルが対象になります。

```yml
name: CI/CD

on:
  push:
    branches: [main]
    paths:
      - "backend/**"
      - "frontend/**"
  pull_request:
    branches: [main]
    paths:
      - "backend/**"
      - "frontend/**"

jobs:
  test:
    ...
  deploy:
    ...
```
Ubuntu 23.04 日本語RemixでBluetooth使う

# はじめに
色々やったけど出来なくて結局modprobeしたら有効化されただけの数行で終わる話。

# これで出来た
```
modprobe -r btusb
modprobe btusb
```

## 全体の流れ
```
┌──(root㉿Ubuntu)-[~]
└─# hciconfig
hci0:   Type: Primary  Bus: USB
        BD Address: 00:00:00:00:00:00  ACL MTU: 0:0  SCO MTU: 0:0
        DOWN 
        RX bytes:889 acl:0 sco:0 events:25 errors:0
        TX bytes:6 acl:0 sco:0 commands:3 errors:1
                    
┌──(root㉿Ubuntu)-[~]
└─# modprobe -r btusb && modprobe btusb
                                                       
┌──(root㉿Ubuntu)-[~]
└─# hciconfig        
hci0:   Type: Primary  Bus: USB
        BD Address: 00:1A:7D:DA:71:15  ACL MTU: 310:10  SCO MTU: 64:8
        UP RUNNING 
        RX bytes:588 acl:0 sco:0 events:31 errors:0
        TX bytes:371 acl:0 sco:0 commands:32 errors:0
```

# 見た資料&やったこと

https://zenn.dev/turtleeen/articles/284d68477e8a5c

https://askubuntu.com/questions/1231074/ubuntu-20-04-bluetooth-not-working

http://mochiuwiki.e2.valueserver.jp/index.php?title=%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB_-_Bluetooth%E3%83%89%E3%83%A9%E3%82%A4%E3%83%90

https://askubuntu.com/questions/1403817/i-cant-turn-on-bluetooth-in-ubuntu-22-04-lts

https://stackoverflow.com/questions/48279646/bluetoothctl-no-default-controller-available
Discord認証 (OAuth2)

## 参考

https://qiita.com/masayoshi4649/items/46fdb744cb8255f5eb98

をもとに手を動かしてみた。


## Discordでアプリケーションの作成

https://discord.com/developers/applications

![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25728/dfe50474-21e9-aa0b-3294-21408c389d83.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25728/f56dfe26-f83e-32b7-9ba3-591337a62116.png)

### Client ID, Client Secretをメモ

* 特にClient Secretは一度しか表示されないため注意

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25728/c5d12e93-fd8b-1055-c036-0044d5bf47da.png)

### 認証が終わったら飛ぶ先URL指定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25728/1671c3db-0f48-98e9-a528-a29bdccad257.png)

今回は http://localhost:8080/afterlogin
を指定しました。

### URL Generator

* identify にチェック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25728/8ad84441-ba6f-67a0-5e71-93478812243d.png)


URLは

`https://discord.com/api/oauth2/authorize?client_id=`クライアントID`&redirect_uri=`リダイレクト先`&response_type=code&scope=identify`
となっている。


### codeの取得

* 先ほどの `https://discord.com/api/oauth2/authorize?client_id（略）`のURLにアクセスし、code値を取得

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25728/cd3b6cfd-0430-253e-861f-cbee75c4b5e4.png)


### tokenの取得のため、curl でアクセス

windowsのコマンドプロンプトにて以下


```bat
set clientid=0000000000000000000
set clientsecret=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
set redirect_uri=http://localhost:8080/afterlogin
set code=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

curl -X POST -H "Content-Type:application/x-www-form-urlencoded" -d "client_id=%clientid%&client_secret=%clientsecret%&grant_type=authorization_code&code=%code%&redirect_uri=%redirect_uri%" https://discordapp.com/api/oauth2/token
```

失敗例

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25728/c651b226-3e22-b4bf-e3d3-f118f6b4bc03.png)

成功例

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25728/08f41d56-af5b-f02d-d350-ebc370e9472b.png)

* 有効期限 "expires_in": 604800 の値は7日間。(604800 / 24 / 60 / 60 = 7)



### token値でDiscordのユーザー情報の取得

```dos
set access_token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
curl -H "Authorization: Bearer %access_token%" https://discordapp.com/api/users/@me
```

* 以下のような情報が取得できる。

```json
{"id":"000000000000000000"
,"username":"xxxxxxxx"
,"avatar":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
,"discriminator":"0000"
,"public_flags":0
,"flags":0
,"banner":null
,"accent_color":null
,"global_name":"xxxxxxxx"
,"avatar_decoration":null
,"banner_color":null
,"mfa_enabled":false
,"locale":"ja"
,"premium_type":0}
```

### 認証の延長

```dos
set clientid=0000000000000000000
set clientsecret=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
set refresh_token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

curl -X POST -H "Content-Type:application/x-www-form-urlencoded" -d "client_id=%clientid%&client_secret=%clientsecret%&grant_type=refresh_token&refresh_token=%refresh_token%" https://discordapp.com/api/oauth2/token
```

新しいrefresh_tokenが発行される。
なお発行された後は、古いrefresh_tokenは使用できなくなるので注意。
UnityのVector3もどきを作ってみたかったので作った！

### 目的
C#言語への理解がまだ未熟のため実際に使ってこなかった**構造体**を使って<ins>理解を深める</ins>。
### 想定する出力結果
```c#
1,2,3
0,0,0
```
- １行目は各軸の成分に任意の値を代入して出力した値
- ２行目はゼロベクトルの値を構造体から参照して出力した値
- 各軸の成分は","区切りで出力して改行。
### 実際に想定通りに機能したコード
```c#
using System;
namespace Struct_Test
{
    public struct Vector3
    {
        /*各軸の成分*/
        public float x, y, z;
        /*読み取り専用のVector3型のプロパティ。ここではVector3.zero*/
        public static Vector3 zero
        {
            get { return new Vector3(0,0,0); }
        }
        /*構造体のコンストラクター*/
        public Vector3(float x, float y, float z)
        {
            this.x = x; this.y = y; this.z = z;
        }
        /*構造体のデータをstring型で表示する際、これがないとnamespace.thisの文字列しか出力されないのでカスタムの文字列で出力。*/
        public new string ToString() => $"{x},{y},{z}";
    }
    internal class Program
    {
        static void Main(string[] args)
        {
            Vector3 v = new Vector3();
            v.x = 1; v.y = 2; v.z = 3;
            Console.WriteLine(v.ToString());
            Console.WriteLine(Vector3.zero.ToString());
        }
    }
}
```
### コードを書いている途中で当たった問題...
- **循環参照** 
↑これに引っかかってしまった。実際に引っかかる原因になったコードが
`public Vector3 zero = new Vector3(0,0,0);`
これでは循環参照が発生するらしく、調べてみた結果
```c#
public static Vector3 zero
{
       get { return new Vector3(0,0,0); }
}
```
これが正解みたいだ。
つぎに","区切りでstring型で出力するためのメソッド
`public new string ToString() => $"{x},{y},{z}";`
を追加して、完成！
### 今回得たもの
- 構造体に対する理解を少々
- get,setの使い方への理解少々
### まとめ
構造体とプロパティはおもしろい
SOLIDとは


SOLID原則について学習しましたのでアプトプットもかねて載せます。

# SOLIDとは
オブジェクト指向プログラミングにおいて、柔軟性、保守性の高いソフトウェアを設計するための５つの原則の頭文字をとったマクロニム（略語）です。

5つの原則
1 単一責任の原則
2 オープンクローズドの原則
3 リスコフの置換原則
4 インターフェース分離の原則
5 依存性逆転の原則

今回は4 インターフェース分離の原則について説明します。

# インターフェースの分離の原則とは(ISP)
インターフェースの分離の原則とはクライアントが必要としないメゾットを含まないようにインターフェースを設計するという原則です。

例
例としてファイルのアップデータを扱うためのアップロードを扱うためのインタフェースをUploaderInterfaceを考えます。
```
interface UploaderInterface
{
    public function upload(File $file);

    public function download(string $fileUrl);

    public function delete(string $fileUrl);
}
```
上記のインターフェースは、ファイルのアップロード、ダウンロード、削除の機能を含んでいます。しかし、実際のクライアントであるImageUploaderクラスはアップロードのみを使用するケースが多いかもしれません。この場合、クライアントは不要なダウンロードや削除のメソッドを実装しなければなりません。

↓ISP化
```
interface UploaderInterface
{
    public function upload(File $file);
}

interface DownloaderInterface
{
    public function download(string $fileUrl);
}

interface DeleterInterface
{
    public function delete(string $fileUrl);
}
```

ISPの原則により、クライアントはインターフェースが提供する機能に適切に合わせてクラスを設計することができ、必要な昨日だけを持つシンプルなインターフェースを実装することができます。
これにより、クライアントの要件に合わせた柔軟で効率的な設計ができます。


インターフェースの分離の原則については以上です。ありがとうございました。
Pytorchで2クラス分類問題を解く (toyota_cars)

# はじめに
以前[こちらの記事](https://qiita.com/YujiMatsu/items/e3829b26555822af3eed)で2クラス分類について紹介した。
ただ、データセットが簡単すぎたため、[この記事](https://qiita.com/YujiMatsu/items/5c0d425f4d55a7010a98)で紹介した`toyota_cars`データセットで画像分類をしてみる。
なお、`toyota_cars`データセットはKaggleで公開されているもの。
https://www.kaggle.com/datasets/occultainsights/toyota-cars-over-20k-labeled-images

# ラベル付け
`toyota_cars`で公開されている38種類の車種のうち2種類をピックアップし、画像分類ができるかを試してみる。
画像とそのラベルをリストで保存し、pytorchの`Dataset`に設定する方式をとる。ラベル付けは以下のように行った。
```python: get_files.py
import os

def get_files_list_toyota_cars(path_input, label_0=None, label_1=None):
    if (label_1 == None) or (label_1==None):
        print('if mode toyota_cars, select label name as label_0 and label_1')
        return
    path_label_0 = os.path.join(path_input, label_0)
    path_label_1 = os.path.join(path_input, label_1)
    dict_list_filenames = {
        label_0: os.listdir(path_label_0),
        label_1: os.listdir(path_label_1)
    }
    list_file = []
    for key, val in dict_list_filenames.items():
        if key == label_0:
            label = 0
            for filename in val:
                list_file.append([os.path.join(path_label_0, filename), label, key])
        elif key == label_1:
            label = 1
            for filename in val:
                list_file.append([os.path.join(path_label_1, filename), label, key])
    return list_file
```
ここで得たリストを、以下の`Dataset`に渡す。

```python:utils.py
import torch.utils.data as data

class MyDataset(data.Dataset):
    def __init__(self, list_file, transform=None, phase='train'):
        self.list_file = list_file
        self.transform = transform
        self.phase = phase

    def __len__(self):
        # ファイル数を返す
        return len(self.list_file)

    def __getitem__(self, index):
        # 画像をPillowsで開く
        path_image = self.list_file[index][0]
        pil_image = Image.open(path_image).convert('RGB')

        # 画像の前処理
        image_transformed = self.transform(pil_image)

        # ラベルを取得
        label_class = self.list_file[index][1]
        label_type = self.list_file[index][2]
        return image_transformed, label_class

```

# 実験結果
[この記事](https://qiita.com/YujiMatsu/items/5c0d425f4d55a7010a98)で調査した結果、最も画像枚数が多い車種は`camry`と`corolla`で、それぞれ2,000枚あった。まずはこの2種で分類ができないか試してみた。
評価は分類性能で図るため、`accuracy`を重視。
`label_0`と`label_1`のそれぞれに車種を入れ、上の`get_files_list_toyota_cars`に渡せば、データセットは得られる。
学習回数を増やすに連れて、スコアが上昇していることがわかるが、スコアが0.6程度までしか上昇せず。

![score_vs_itr_val_camryvscorolla.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/355664/10dc68fd-0f3a-c101-9584-0ff014f02be8.png)

2番めに画像数の多い`4runner`と`highlander`で試してみる。
学習回数を増やすに連れてスコアが上昇し、0.8程度まで上げられることを確認！
![score_vs_itr_val＿4runnervshighlander.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/355664/97b32436-b889-c937-d9ce-17b695da0722.png)



# 最後に
今回は[以前紹介した2クラス分類問題]((https://qiita.com/YujiMatsu/items/e3829b26555822af3eed))のデータセットを変えて試してみた。
前よりも難易度が上がり、スコアは急に上昇することは無くなった。
今後は同じデータセットで、不均衡データセットの場合のクラス分類について挑戦してみる。

https://github.com/yujimats/2classification_pytorch.git
CGアニメーション　入門　Part1 振り子運動　in DazStudio

# 概要
今回はDazStudioのアニメーション機能を使って　振り子の運動を再現します。
以下gifアニメは振り子運動のアニメーションの様子です。
![furikoko.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/df255208-21cf-dfa0-e5ea-0a7d0cd00f84.gif)


# 開発環境
OS:Windows10
DazStudio:42.105 proEdition

# スローイン　スローアウトとは？
アニメーションの最初と最後の部分でスピードを落とす調整。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/fcfb436f-69c2-4cb4-ad89-db4e93d25e46.png)


# 手順 
30FPS(Frame per Second)にして振り子の運動を実装します。

## 0フレーム目 zRotation = -45にする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/b4bddde5-072e-21ed-80c4-b5c99e0817d5.png)


## 15フレーム目 zRotation = 0にする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/40606cbc-1fc7-99fd-dfac-0d7008feaf0e.png)


## 30フレーム目 zRotation = 45にする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/b73adaea-d11f-62f1-e412-a55dc9bafd92.png)



## アニメーションを再生して球の軌跡を確認する
ディスプレイ上から紙でトレースしたときの様子
スローイン・スローアウトが適用されていることを確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/e3ef30ea-9f48-eeb4-a88c-7db788f8e66e.png)

# 参考

https://www.versluis.com/2015/05/how-to-move-the-pivot-point-of-an-object-in-daz-studio/

著者：荻野哲哉「３DCG アニメーション入門」pp24-28
WSL2上のUbuntu環境でDockerを利用するために必要な初期設定

# はじめに
Windowsで動くLinux環境を作るために、WSL2でUbuntu環境を構築しました。
しかし、Dockerのインストールに躓いたのでメモ。

# Dockerを利用するための初期設定
[Ubuntu on WSL2でのDocker Engineの最短インストール手順](https://qiita.com/nujust/items/d7cd395baa0c5dc94fc5)
こちらの記事を参考に、セットアップを行います。
## Docker Engineのインストール
Dockerを使うために必要なものなのでインストールします。
インストールまでに、Docker Desktop for Windowsの利用を推奨されるメッセージが出ますが、放置するとそのままインストールが完了します。
```bash
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
```

## rootユーザ以外がDockerコマンドを使えるようにするための設定
rootユーザ以外で使う場面もあると思いますので、このコマンドを設定しておくと良いと思います。
```bash
sudo usermod -aG docker $USER
```

## WSL2の再起動
設定した内容を反映させるために、一回PowerShellやCommand Promptでシャットダウンを行い、もう一度立ち上げます。
```powershell
wsl --shutdown
```

## Dockerのサービスを起動する
サービスを起動しないとDockerが利用できないので、このコマンドを打ちます。
`* Starting Docker: docker [OK]`が返ってこれば起動成功です。
```bash
sudo service docker start
```

## Dockerの動作チェック
簡単なコマンドを用いて、Dockerが正しく動いているかチェックします。
```bash
docker run hello-world
```
以下のメッセージが出ればDockerコマンドが正しく動作しています。
```bash
Hello from Docker!
This message shows that your installation appears to be working correctly.
```
しかし、以下のメッセージが出る場合は、Dockerが動かせていません。
```
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
```
## Dockerが動作していない方向け
[【WSL2】DockerでCannot connect to the Docker daemon…と表示される問題の対処](https://remix-yh.net/2281/)
こちらの記事を参考に、エラー対応します。
### Dockerのログを確認
内部でどのようなエラーが発生しているか調べるために、以下のコマンドを打ちます。
```bash
sudo cat /var/log/docker.log
```
僕の場合は、以下のメッセージが出ました。
原因としては、Dockerが新しいiptablesに対応出来ていないためです。
```bash
failed to start daemon: Error initializing network controller: error obtaining controller instance: unable to add return rule in DOCKER-ISOLATION-STAGE-1 chain:  (iptables failed: iptables --wait -A DOCKER-ISOLATION-STAGE-1 -j RETURN: iptables v1.8.7 (nf_tables):  RULE_APPEND failed (No such file or directory): rule in chain DOCKER-ISOLATION-STAGE-1
 (exit status 4))
```
### Legacy版のiptablesに変更する
新しいものに対応していないため、Legay版に変更します。
以下のコマンドを打つことで出来ます。
```bash
sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
```
## WSL2の再起動
設定した内容を反映させるために、一回PowerShellやCommand Promptでシャットダウンを行い、もう一度立ち上げます。
```powershell
wsl --shutdown
```
## Dockerのサービスを起動、動作チェック
先ほどと同様に、サービスを起動してDockerが動作するかチェックします。
```bash
sudo service docker start
docker run hello-world
```
以下のメッセージが出ればDockerコマンドが正しく動作しています。
```bash
Hello from Docker!
This message shows that your installation appears to be working correctly.
```

# おわりに
WindowsでLinuxが動かせるのは便利ですが、Dockerなどのセットアップが大変だと感じました。
様々な記事の寄せ集めで作成した記事ですが、参考にしていただければ幸いです。

# 参考文献
- [Ubuntu on WSL2でのDocker Engineの最短インストール手順](https://qiita.com/nujust/items/d7cd395baa0c5dc94fc5)
- [【WSL2】DockerでCannot connect to the Docker daemon…と表示される問題の対処](https://remix-yh.net/2281/)
- [Troubleshoot: WSL2でDockerが起動しない](https://zenn.dev/tkzwhr/articles/trouble-shooting-wsl2-docker)
SOLID原則とは

オブジェクト指向プログラミングにおいて、柔軟性、保守性の高いソフトウェアを設計するための５つの原則の頭文字をとったマクロニム（略語）です。

5つの原則
1 単一責任の原則
2 オープンクローズドの原則
3 リスコフの置換原則
4 インターフェース分離の原則
5 依存性逆転の原則

今回は 3 リスコフの置換原則（LSP)について説明します。

# リスコフの置換原則とは
リスコフの置換の原則はオブジェクト指向プログラミングにおいて、サブタイプ（派生クラスやサブクラス）はその基底　タイプ(スーパークラスや親クラス)と互換性があるべきという原則です。
つまり、基底クラスのインターフェイスを満たす全てのサブクラスは、基底クラスと同じように振る舞わなければいけないということです。
例
```
// 基底クラス
class Shape
{
    public function getArea()
    {
        // 形状の面積を計算する共通のメソッド
    }
}

// 円クラス
class Circle extends Shape
{
    private $radius;

    public function __construct($radius)
    {
        $this->radius = $radius;
    }

    public function getArea()
    {
        return pi() * pow($this->radius, 2);
    }
}

// 長方形クラス
class Rectangle extends Shape
{
    private $width;
    private $height;

    public function __construct($width, $height)
    {
        $this->width = $width;
        $this->height = $height;
    }

    public function getArea()
    {
        return $this->width * $this->height;
    }
}
```
ここで、CircleとRectangleクラスは共にShapeクラスを継承しています。そして、Shapeクラスには共通のgetArea()メソッドが定義されています。このように、基底クラスとサブクラスは共通のインターフェースを持ち、getArea()メソッドを提供しています。

LSPによれば、例えば以下のように基底クラスのインスタンスをサブクラスのインスタンスで置き換えても、結果が変わることはありません。
例
```
function printArea(Shape $shape)
{
    echo "Area: " . $shape->getArea() . PHP_EOL;
}

$circle = new Circle(5);
$rectangle = new Rectangle(4, 6);

printArea($circle); // 結果: Area: 78.539816339745
printArea($rectangle); // 結果: Area: 24
```

このように、CircleクラスとRectangleクラスがShapeクラスのインスタンスとして置換可能であるため、ポリモーフィズムを活用して柔軟な設計が実現されています。LSPにより、コードの再利用性と拡張性が向上し、オブジェクト指向の重要な原則の1つとして利用されています。


### この原則を守るための注意点は？

1　メゾットのシグネチャ(メゾット名,引数の数と型,戻り値の型)を基底クラスとサブクラスで一致しなければならない。

2 基底クラスのメゾットが期待する振る舞いや条件をサブクラスでも満たす必要がある。
サブクラスは基底クラスのメゾットの振る舞いを拡張してもよいが、基底クラスで期待されている、全体条件や後提条件を破壊してはいけない。

以上です。ありがとうございました。
OMNeT++インストール方法

# OMNeT++インストール手順(Windows)
1.  C:\Users\YourUsernameにOMNeT++をインストールするためのディレクトリomnetppを作成しておく
1.  [ここ](https://omnetpp.org/download/)からwindows版を選択しomnetpp-6.0.1-windows-x86_64.zipをダウンロードし、ommnetppに入れておく。
1. omnetpp-6.0.1-windows-x86_64.zipを右クリックし、すべて展開する。展開場所はC:\Users\YourUsername\omnetppにする。
1. フォルダomnetppにomnetpp-6.0.1ができるので、開いてmingwenv.cmdをダブルクリックする。(警告が出るが気にせず実行)
1. cmdが立ち上がりるので、次のコマンドを入力し、omnetpp-6.0.1をコンパイルする。
    - `$ cd /c/Users/YourUsername/omnetpp/omnetpp-6.0.1`  (このディレクトリにいる場合は打たなくていい)
    - `$ ./configure`
    - `$ make` (結構時間がかかる)
1. cmd上で次のコマンドを実行すると、OMNeT++ IDEが立ち上がり、OMNeT++が利用できる。
    - `$ omnetpp` or OMNeT++ 6.0.1 IDEショートカットファイルを実行する
GitLabの課題管理システムとしてBacklogと連携する方法

## 目的

GitLab の`External issue trackers`という機能を用いて、 Backlog で管理されている課題を GitLab と紐づけます。

これにより GitLab 上で特定の文字列を用いると、 Backlog の課題へのリンクに変換してくれるようになります。

## GitLab の External issue trackers について

GitLab にはそもそも`issues`という課題管理のための機能が備わっています。しかし、プロジェクトのさまざまな理由から GitLab 外で課題管理をしている場合に、その課題管理システムと GitLab を連携させることができます。

https://docs.gitlab.com/ee/integration/external-issue-tracker.html

一部の外部課題管理システムは連携のための手順が載っていますが、 Backlog のように手順が示されていない場合は`Custom issue tracker`の手順に沿って連携させることができます。

https://docs.gitlab.com/ee/user/project/integrations/custom_issue_tracker.html

## GitLab と Backlog を連携する

外部の課題管理システムを使う場合、 GitLab の`issues`と併用するパターンと外部の課題管理システムのみを使うパターンが選択できます。今回は前者のパターンの手順を示します。

1. GitLabの対象プロジェクトに移動
1. サイドバーから`Settings > Integrations`を選択
1. `Custom issue tracker`を選択
1. `Enable integration`のチェックボックスを有効にする
1. Backlogの各種URLを入力する
    1. `Project URL`: `https://${スペースID}.backlog.com/projects/${プロジェクト名}`
        - プロジェクトホームのURLです
    1. `Issue URL`: `https://${スペースID}.backlog.com/view/${プロジェクト名}-:id`
        - 各課題のURLです。`:id`の部分は動的パラメータです
    1. `New issue URL`: `https://example.com/`
        - 最新のバージョンでは不要になったフィールドのため任意のURLを指定します。([issue](https://gitlab.com/gitlab-org/gitlab/-/issues/327503?_gl=1*4ibxbf*_ga*MTEwMzA2Njg1Ny4xNjg4Nzk2MDc2*_ga_ENFH3X7M5Y*MTY5MDY4OTUwNy41LjEuMTY5MDY5MTgyMC4wLjAuMA..))
1. `Save changes`を選択

以上で GitLab と Backlog が連携できました。

プロジェクトのサイドメニューに`Custom issue tracker`というBacklogへのリンクが追加されます。

![スクリーンショット 2023-07-30 13.42.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296328/a8a0007c-646e-36ac-be32-867682bc1e52.png)

また、 マージリクエストやコミットなどで`${プロジェクト名}-:id`という文字列を用いると課題へのリンクへ変換してくれるようになりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296328/05cf102d-14cd-80ba-ab04-6a84d7d14cca.png)

```
href="https://${スペースID}.backlog.com/view/MYPROJECT-1"
```
インスタンスクローンの前準備としてのUpdate Set一括退避手段

■用途とメリット
DevやTestなどの本番ではない開発環境において、開発物をクローンする際には、保護のためにUpdate SetをXML形式で保存することがあります。しかし、この操作は手作業で一つ一つ行う必要があるため、手間がかかります。また、Update Setは完了ステータスにしなければならない制約があると思われます。そこで、以下のプラグインを導入することで、local update setのUI Actionに一括ダウンロードの選択肢が追加され、Update Setのステータスにかかわらず一括でダウンロードできます。この準備が完了した後、クローンを実行し、最後に開発物であるUpdate Setを元に戻すことで、開発環境が元通りになります。

■プラグイン
[Bulk Download & Naming of Update Sets](https://developer.servicenow.com/connect.do#!/share/contents/5979617_bulk_download_naming_of_update_sets?v=1.2&t=PRODUCT_DETAILS)

■インストール
上記URLにアクセスする。
Downloadボタンを押下してXMLをダウンロードする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190712/a12dc9de-b146-d5e5-89e1-11ba7c57daa6.png)


適当なテーブルを開いてList Viewを右クリック
Import XMLメニューで設定をインポート
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190712/f82be9a9-a002-94cb-7e7f-947768f00eb1.png)
上記実施すると、Retrieved Update Set[sys_remote_update_set]テーブルにレコード新規追加される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190712/2194af3f-5a52-9ea6-f066-0ccd68eac06f.png)
Preview Update Set→Commit Update Setを行って設定を適用する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190712/16d8842b-2cf5-262a-78ce-b4b30554e3c3.png)

上記で準備完了

■使用法
基本的にはUpdate Sets[sys_update_set]テーブルのList ViewにMenu Actionが追加された状態なので、
Update Sets[sys_update_set]テーブルに移動する。
Menu ActionにExport Selected to XML(bulk)が追加されたことを確認する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190712/850c6b30-1c92-7305-45cd-c528c801474e.png)
保存したいXMLを全選択して、同メニューアクションを押下する

■結果
一括でUpdate Setがローカルに保存される。


追記：
保存されない場合、
[Batch Update Sets - Extension for Bulk Download and Rename of Update Sets](https://developer.servicenow.com/connect.do#!/share/contents/5924274_batch_update_sets_extension_for_bulk_download_and_rename_of_update_sets?v=1&t=PRODUCT_DETAILS)
という同Patchの拡張機能があるので、そちらをダウンロードして同様に作業するとよいと思います。

また、Sandiegoからの新UI（Poraris UI）では同プラグインが動作しないことが分かりました。
旧UIに変更してから同じ動作を行えば一括ダウンロードが可能なので試してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190712/34e82512-e8bd-e4c0-c2b6-6ce2a8f6f727.png)
できました！
Pop UpブロックをOnにしていると一括ダウンロードができませんので、それはブラウザ設定でOffにしてください。


■新→旧UIへの変更方法
システムプロパティへの移動(/sys_properties_list.do)
glide.ui.polaris.experienceを検索
True→Falseに変更すること
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190712/7b34e43d-5f51-fb0b-f5e9-098a4be1d419.png)

もしくは
glide.ui.polaris.on_off_user_pref_enabled
をFalse→Trueに変更すること
でユーザーに選択肢を提供できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190712/9ca50f37-aa1b-da3e-3c61-7e0a186c55d3.png)
Linux基礎

## ファイルの操作

ファイルの詳細一覧を表示
```
$ ls -la
drwxr-xr-x    5 user_name  staff
```
**ファイル権限の意味**

| 文字 | ファイルのアクセス権   | ディレクトリのパーミッション | 
| ---- | ---------------------- | ---------------------------- | 
| -    | 権限がない             | 権限がない                   | 
| r    | ファイルの読み込み     | ファイル一覧の取得           | 
| w    | ファイルのへの書き込み | ファイルの作成・改名・削除   | 
| x    | ファイルの実行         | ディレクトリーへの移動       | 

詳細は左から
`ファイルの種類・所有者の権限・グループの権限・その他の権限・所有者・グループ`

**ファイルの種類**

| 文字 | ファイルの種類 | 
| ---- | -------------- | 
| -    | 通常のファイル | 
| d    | ディレクトリ   | 

## 管理者権限
```
$ su　　　
パスワード：
#　　　　　←「$」から「#」へ変更される
# exit
$ 　　←「$」に戻る
```

## コマンド

### 標準入出力
- 標準入力：キーボード入力のこと
- 標準出力：画面のこと
- 標準エラー出力：エラーメッセージのこと

### リダイレクト
```
#tr : , < ls
//lsの内容をtr(空白をカンマに置き換える)

#ls -la > test.txt
//test.txtにls -laの内容を上書きする

#ls -la >> test.txt
//test.txtにls -laの内容を追記する

#ls -la /hogehoge 2> test.txt
//ls -la /hogehogeの標準出力をtest.txtに上書きする
```

### パイプライン

二つ以上のコマンドをつなぐ
```
#ls -la | tr -s '' ,
//ls -laの標準出力を trの標準入力として使用

#ls -la |& tr -s '' ,
//ls -laの標準エラーを trの引数として使用
```

### リスト
ただコマンドを順番に実行する

```
#echo "hello" ; ls
//hello のあとにlsの結果が出力される

#echo "hello" $?
//終了ステータスを返す。0は正常終了。それ以外は以上終了
//hello0

#ls /hoge && echo "hogeは存在します"
hogeは存在します
//前の処理が正常終了の時のみ && 以降を実行

#ls /hogehoge || echo "hogeは存在しません"
hogeは存在しません
//前の処理が異常終了の時のみ || 以降を実行

```

### プロセス管理

Linuxカーネルにおいてプロセスとはコマンドやアプリケーションのこと

```
$ ps
//現在動いているプロセスの一覧が表示される

```

オプション

- x 全てのプロセスを表示
- u プロセスの詳細を表示

### ジョブ
ジョブとは一つのコマンドのこと。シェルが管理している。パイプラインやリストで繋がれたものも一つのコマンドとして扱われる。Command + Cでジョブを強制停止することができる

- 端末エミュレータ　ターミナルのウインドひとつのこと

- バックグラウンドで実行
```
$ コマンド &
```

- ジョブの停止
通常はcontrol + Cを使用。どうしても止まらないときにkillコマンドを使う
```
kill % ジョブ番号
```

- ジョブの確認
```
$ jobs -l
```
1つの言語とキャリア戦略について

# 参加したイベント

今回はオンラインで初めて参加したイベントについて書いていく

https://findy.connpass.com/event/289359/?utm_campaign=event_message_to_selected_participant&utm_source=notifications&utm_medium=email&utm_content=title_link

# 感想
私自身はruby半年、java1年ちょっとという経歴なのだが
今回のイベントではkotlin,python
それぞれで1つの言語を中心にキャリアを築いてきたお2方のお話を聞くことができた。

記憶に残ったのは
「一つの言語を極めることに抵抗は？」
という質問に

なかった
kotlinだけじゃなくてjavaも勉強していた
仮にkotlinがポシャっても大丈夫だとおもった

という旨の回答をしていた点だった。
たしかに1つの言語にしぼるというのは、
「その言語が使われなくなる」というリスクが一定あって
その際のリスクヘッジは大事なのかもしれないなと思った。

自分の場合はjava,rubyをやってきたが
このままこの言語をやり続けるのか
考えるきっかけになった。

「プログラミング言語　ユーザー数」
等で出てくるデータを見るとpythonの勢いはすごい

https://cmc-japan.co.jp/blog/%E9%96%8B%E7%99%BA%E8%A8%80%E8%AA%9E%E3%83%A9%E3%83%B3%E3%82%AD%E3%83%B3%E3%82%B0/

もうすこし調べてみて
休みの日にその言語を学んでみるのも楽しいだろうなと思った
応用情報技術者試験にギリギリ合格するためにした勉強法

# 目次
　[試験結果](#試験結果)
　[教材](#教材)
　[勉強法](#勉強法)
　[まとめ](#まとめ)

#### 試験結果
令和5年春期の応用情報技術者試験にギリギリ合格することができました。
合格基準が午前・午後6割以上の中、採点結果は午前62.5点、午後64点でした。

![応用情報合格結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3096978/f8ade0e2-a8da-83e8-fe32-39ef327370da.png)

選択分野

![選択分野.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3096978/166281c9-5172-0787-0506-6a23912bb57c.png)

プログラミング
システムアーキテクチャ
データベース
システム監査

午後の勉強を始める段階で、午後の選択分野を決めて学習していました。
僕は、本番で問題選択できるような時間的余裕はなかったです。。。


#### 教材
[合格教本](https://www.amazon.co.jp/%E4%BB%A4%E5%92%8C05%E5%B9%B4%E3%80%90%E6%98%A5%E6%9C%9F%E3%80%91%E3%80%90%E7%A7%8B%E6%9C%9F%E3%80%91-%E5%BF%9C%E7%94%A8%E6%83%85%E5%A0%B1%E6%8A%80%E8%A1%93%E8%80%85-%E5%90%88%E6%A0%BC%E6%95%99%E6%9C%AC-%E6%83%85%E5%A0%B1%E5%87%A6%E7%90%86%E6%8A%80%E8%A1%93%E8%80%85%E8%A9%A6%E9%A8%93-%E3%81%BF%E3%82%84%E5%AD%90/dp/4297131587/ref=sr_1_1?keywords=%E5%90%88%E6%A0%BC%E6%95%99%E6%9C%AC+%E5%BF%9C%E7%94%A8%E6%83%85%E5%A0%B1&qid=1690688520&sprefix=%E5%90%88%E6%A0%BC%E6%95%99%E6%9C%AC%2Caps%2C170&sr=8-1)
![合格教本.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3096978/9b4c9dd2-d6e6-55a4-7a0f-98566fc5408b.png)


イラストが多く用語を詳しく解説してくれていることから選びました。
このテキストを2周ぐらい読んでから過去問を解くと、
わからない用語で出てきて解けない問題が減ってきました。

[過去問道場](https://www.ap-siken.com/apkakomon.php)

https://www.ap-siken.com/apkakomon.php

基本情報技術者試験版もある有名なサイトです。
午前試験を手軽に勉強することができました。
電車移動や暇な時間で午前の勉強をすることができました。

#### 勉強法
個人的に大事だと思った勉強法は、過去問を本番と同じような形式で解くことです。
実際に過去問を印刷することと、時間を計って解いてみることです。
印刷することによって、本番で問題冊子をめくりながら問題を解いていくことにもなれます。
また、時間を計ることで時間配分や、集中力がどのくらい持つかをイメージすることができました。
本番では午前に引き続き午後も2時間半とかなり集中力がなくなります。
少しでも本番と同じ形式になれることが、点数を上げることにつながったのではないかと思いました。

#### まとめ
応用情報技術者試験にギリギリ合格することができました。
応用情報に受かると2年間高度資格の午前Ⅰ試験が免除になるので、
高度資格にも挑戦してみたいと思います。
【紹介】プログラミング学習で参考になったこと

プログラミング学習で参考になったことを紹介します。

【C言語】
---
- 書籍

1. 「苦しんで覚えるC言語」
タイトルとは裏腹に解説が丁寧です。
文章はその道何十年のC言語が大好きなベテランエンジニアに教わっているような感覚があります。
コードの意味や「〇〇とは何か説明せよ」というような問題を通して、
考えながら学習していけるため、少しずつ自信になっていく本です。
私は、半分くらいまで読んで、下記のStudyーCアプリに移行しました。

2. 「明解　C言語」
体系的に順番に学んでいきたい人におすすめです。
説明はクセがなくて読みやすい印象です。
「明解　〇〇」シリーズは、情報系の大学でも教科書として使用されることがあるそうです。


- iphone向け学習アプリ
Study-C

情報系大学の学生によって作成されたC言語のための学習アプリです。
コンパイラや統合開発環境を用意する必要がなく、手軽に学習を始められます。
解説→パズルの穴埋め問題の順番で進んでいきます。
大学ではこんなことを授業でやるんだろうな、と思わせてくれた内容でした。
C言語に全く触れたことがない人でも、解説を読んでから問題を実際に解いていくことで、
確実に理解できるようになります。


【PHP/Laravel】
-
- 書籍

1. 「独習PHP」
2. 「PHP フレームワーク　Laravel入門　第2版」

買ってみてから実はあまり読んでないですが、多分、そのうち、見返すこともあるでしょう。。。
私にとってはポケット辞書的な存在です。



- Youtube
ゆきひろプログラミング教室
https://www.youtube.com/@YukihiroLaravel

→こちらの動画でPHPの基礎を学んでいたので、書籍をあまり見返さなかったです。
興味のある方は、無料セミナーに参加して無料の転職相談などを受けてみてもいいかもしれません。


【プログラミング言語全般】
-
- Youtube
直也テック サブチャンネル
https://www.youtube.com/@naoya-tech-sub

→こちらのショート動画で「AOJ」というサイトの存在を紹介されていて初めて知りました。
プログラミングで作りたいものがない人向けに、とりあえず学習したい欲を満たしてくれます。

「AOJ」のいいところ
・いろんな言語が学べる。
・自分の書いたコードが正しいか間違いかを判定してくれ、CPU使用率も表示してくれる。
・他の人はどんなふうに書いたか閲覧できる。
・プログラムをオンライン上で実行するので、統合開発環境が必要ない。

https://onlinejudge.u-aizu.ac.jp/home


・Progete （プロゲート）　

Web版
https://prog-8.com/

Web版とスマホ向けアプリがあります。
スマホ向けアプリは、Androidとiphoneの両方あります。

以下は実際にやってみた感想です。

＜Progete iphone向けアプリ＞
・最初の１、２レッスンは無料で、その先は月額のサブスクリプション¥1,080がかかる。
・違う言語のレッスンを同時に複数受講しても月額料金は変わらない。
・説明のスライドと、穴埋め式のパズルでコードを作成して解答する。

＜Progete Web版＞
・アプリ版で月額利用していれば、アカウントの同期が取れているのでWeb版は２重で支払う必要がない。
・アプリ版と同様に説明のスライドの後に問題が出されるが、穴埋め式のパズルではなく、
コード入力欄で解答する。


2023/8/4追記：

・「Progete」とスマホ向けC言語学習支援アプリ「Study-C」は、Androidにもアプリ展開されています。

・「Progete」の月額サブスクリプションが¥1,490に値上がりしていました。
SOLIDとは

オブジェクト指向プログラミングにおいて、柔軟性、保守性の高いソフトウェアを設計するための５つの原則の頭文字をとったマクロニム（略語）です。

5つの原則
1 単一責任の原則
2 オープン/クローズドの原則
3 リスコフの置換原則
4 インターフェース分離の原則
5 依存性逆転の原則

今回は2 オープン/クローズドの原則について説明します。
## 2 オープン/クローズドの原則
オープン/クローズドの原則(OCP)とは既存のクラスやモジュールを変更せずに新しい機能を追加できるように設計する原則です。これにより、既存コードを安定して保ちながら新しい機能を拡張できるため、変更に強い、柔軟なシステムを構築することができます。

例(OCP)
```
class MailService
{
    public function sendMail($to, $subject, $message)
    {
        // メールを送信する処理
    }
}
```
```
// メール送信機能を提供するクラス
class MailService
{
    public function sendMail($to, $subject, $message)
    {
        // メールを送信する処理
    }
}

// SMS送信機能を提供するクラス
class SMSService
{
    public function sendSMS($to, $message)
    {
        // SMSを送信する処理
    }
}
```
```
interface MessageServiceInterface
{
    public function send($to, $message);
}

class MailService implements MessageServiceInterface
{
    public function send($to, $message)
    {
        // メールを送信する処理
    }
}

class SMSService implements MessageServiceInterface
{
    public function send($to, $message)
    {
        // SMSを送信する処理
    }
}
```
このようにしてOCPを尊守することによって、既存のコードを安定させつつ、柔軟に新しい機能を追加、拡張させることができます。

オープン/クローズドの原則については以上です。
ありがとうございました。
tfsec

# 【tfsec】

## tfsec(Aqua Security社の、オープンソースツール)

- Terraform の静的なセキュリティスキャンを行うツール
- ローカル環境での動作確認には認証情報等は不要となっている
    - `.tf ファイル` に対してのみ静的解析をおこなう
- クラウドの認証キーや権限付与が必要ない
- CIパイプライン環境で実行できるように設計されている
- 秘匿情報の混入がないか等の一般的なセキュリティチェックもしてくれる
- [tfsec対応](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance#metadata-options)を実施
いつも忘れる変換

いつも忘れる変換

ASCII文字とURLエンコードの対応表

https://www.seil.jp/doc/index.html#tool/url-encode.html

|文字|コード|
|:--|:--|
|SPACE|	%20
|!	|%21
|"	|%22
|#	|%23
|$	|%24
|%	|%25
|&	|%26
|'	|%27
|(	|%28
|)	|%29
|*	|%2A
|+	|%2B
|,	|%2C
|/	|%2F
||:	|%3A
|;	|%3B
|<	|%3C
|=	|%3D
|>	|%3E
|?	|%3F
|@	|%40
|[	|%5B
|]	|%5D
|^	|%5E
|`	|%60
|{	|%7B
||	|%7C
|}	|%7D
|~	|%7E
Macでスマホアプリ開発への道(1)

今回は、画面上に三つの四角形を垂直に並べ並べ横と縦の長さを変えながら表示させてみた。
VStackで垂直
HStackで並行に
ZStackでZ軸方向に積み立て
.foregroundColor(.色)でカラーの指定
.frame(width: 幅, height: 高さ)
![スクリーンショット 2023-07-30 12.42.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3522639/6ac9fb2b-e120-169b-460e-9a59c193020b.png)
HTMLファイルをMinifyしたときの備忘録

# 概要

### Minifyとは

**Minify**とは、コード内の不要な改行やインデントを削除して、動作はそのままの状態で、圧縮・軽量化することをいいます。逆に、Minifyしたコードを整形し直すことを**Beautify**といいます。
Minifyは主に、CSSやJavaScriptで行われることが多いです。

### Minifyする利点

- ファイルサイズが小さくなり、表示の高速化ができる
- 可読性が下がるため、ブラウザからコードの解析がしにくい

### 今回の内容

下記、Minifyプラグインやテンプレートエンジンを使った**HTMLファイル**のMinifyを行った結果を備忘録としてまとめていきます。

- **使用したMinifyプラグイン**
  - `gulp-htmlmin`: HTMLのMinify
  - `gulp-clean-css`: CSSのMinify
  - `gulp-uglify`: javaScriptのMinify

- **使用したテンプレートエンジン**
  - JavaScriptのテンプレートエンジンの`jquery-tmpl`
  - PHPのテンプレートエンジンの`Smarty`


# 備忘録

### テンプレートエンジンを使ったHTMLの場合

- Minifyできる
  - 純粋なHTMLタグ
  - HTMLタグ内のphpやSmartyのタグ
  - HTMLタグ内のにstyleタグ
  - HTMLタグ内のにscriptタグ
  - jquery-tmpl内のテンプレート内のHTML

- Minifyできない
  - HTMLのscriptタグの中の、phpやsmartyのタグ 
  - jquery-tmpl内に、phpやsmartyのタグ 
  - jquery-tmplの中で文字列の`< >`( HTMLタグと判定できてしまうもの )

意外とMinifyできましたが、複数のテンプレートエンジンが絡んでくると、構造が崩れてしまったり、エラーになったりしてしまいうまくMinifyができませんでした。

別の言語のテンプレートエンジンでも同じ現象が起こるかと思われるため、複数のテンプレートエンジンは同居させずにできるだけファイルを分けたほうが良いと思われます。


### HTMLタグだけどうまくいかない場合

inline要素だと「改行した場合」と「1行の場合」に違いが出てしまうため、Minifyすると以下のようにレイアウトが崩れてしまいます。

- 改行した場合
```html
<span>AAAA</span>
<span>BBBB</span>
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473097/5683a124-511f-e9c1-c05c-bd48fe49f8d0.png)

- 1行の場合
```html
<span>AAAA</span><span>BBBB</span>
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473097/7cbcad29-5779-80b9-0fcf-f8456b077c93.png)


HTMLのMinifyするときは、改行を行わないような設定が必要と考えられます。

### 運用のルール

HTMLのMinify組み込んだときに以下ルールでちゃんと運用するようになりました。
（内容としてはめちゃくちゃ普通のことですが...）

- 複数のテンプレートエンジンが混在しないように整理する、1本化を進める。
- JavaScriptやCSSはできるだけ外部ファイルとして管理する。
- Minifyするときに元ファイルは残す。



# おわりに

今回は、HTMLファイルのMinifyについてまとめましたが、
正直なところ、HTML部分に関しては軽量化したことによる効果は、あまり感じられませんでした。

成果としては、Minifyについての知見に加え、コードの書き方やリファクタリング方法などといった考え方の確立や整理ができたことが、1番成長できたと感じています。

以上です。ここまで見ていただきありがとうございました。