OmniAICreator/Qiita-1.07M huggingface dataset:
Googleフォームを毎日回答受付開始・終了する

## １ 目的
Googleフォームで、毎日の一定時間帯だけ回答を受け付けたい。その場合、プロジェクトに受付開始の関数と受付終了の関数を作っておいて、それぞれトリガーを、時間主導型、日付ベースのタイマーで設定する方法があります。しかし、日付ベースのタイマーでは時刻が「午前7時〜8時」などの設定となり、細かい時刻が設定できません。そこで、少なくとも終了時刻は思いどおりの時刻にできるよう、フォームの回答受付を開始したらその時に終了のトリガーをつくるスクリプトを書いてみました。

（次の投稿　[Googleフォームを毎日回答受付開始・終了する（その２）](https://qiita.com/freshcl/items/768e2b9871a672adac0d) もあわせてお読みください）
## ２ スクリプト
```JavaScript:startAndClose.gs
//回答受付を開始し、一定時間後（openHoursで指定）に終了する関数
function startAndClose1() {
  const formId = 'フォームのID';
  const myform = FormApp.openById(formId);
  myform.setAcceptingResponses(true);  //フォーム受付開始
  const openHours = 1;  //何時間受け付けるか
  // 所定の時間(ミリ秒)後にフォームの回答受付を終了するトリガーを設定
  ScriptApp.newTrigger('closeForm1')
    .timeBased()
    .after(openHours * 60 * 60 * 1000)
    .create();
}

//回答受付を開始し、終了時間（closeDateTimeで指定）に終了する関数
function startAndClose2(){
  const formId = 'フォームのID';
  const myform = FormApp.openById(formId);
  myform.setAcceptingResponses(true);  //フォーム受付開始
  const currentDate = new Date(); //現在日時(開始日時)
  //同じ日の午前8時30分を終了時間とする
  const closeDateTime = new Date(
    currentDate.getFullYear(),
    currentDate.getMonth(),
    currentDate.getDate(),
    8, 30, 0, 0
  );
  //終了時間に終了するようトリガーを設定
  const triggerTime = closeDateTime.getTime() - currentDate.getTime();
  if (triggerTime > 0) {
    ScriptApp.newTrigger('closeForm1')
      .timeBased()
      .after(triggerTime)
      .create();
    Logger.log('指定時刻に回答受付を終了するトリガーが設定されました。');
  } else {
    Logger.log('指定日時が過去のため、トリガーを設定できません。');
  }
}
//回答受付を終了する関数
function closeForm1() {
  const formId = 'フォームのID';
  const myform = FormApp.openById(formId);
  myform.setAcceptingResponses(false); //受付終了
}
```
startAndClose1関数は、フォームの回答受付を開始し、一定時間後に受付終了するトリガーを設定します。「一定時間」は　const openHours に一時間単位でセットします。例では、１時間にしてあります。

startAndClose2関数は、フォームの回答受付を開始し、その日の後刻の、指定終了時間に受付終了するトリガーを設定します。例では、8:30にしてあります。

closeForm1関数は、回答受付を終了する関数で、startAndClose1 か startAndClose2から使われます。

## ３ 使い方
const formIdには、実際に使用するフォームのIDをセットします。ブラウザでフォーム設定画面を開いた時、URLの d/ に続き次の/までの間の英数文字がIDです。「一定時間」や「指定終了時間」を、希望の時間にします。あとは、手動かトリガーの設定で、startAndClose1かstartAndClose2を実行します。

早朝から受付を開始し8:30に締め切り、これを毎日繰り返す、というのであれば、startAndClose2を、トリガーの設定で、時間主導型、日付ベースのタイマーで、時刻を午前2時〜3時、などとしておけばよいと思います。

## ４ 参考
- [Google Apps Scriptの日毎のトリガーで時間をもっと細かく設定する](https://qiita.com/sumi-engraphia/items/465dd027e17f44da4d6a) @sumi-engraphia
- [Googleフォームを毎日回答受付開始・終了する（その２）](https://qiita.com/freshcl/items/768e2b9871a672adac0d) 次の投稿
[Google Sheets API] セルを結合、結合解除する

Google Sheets API v4（Java）を使用して、
スプレットシートのセルを結合、結合解除する方法
についてご紹介します。

:::note info
APIを利用する環境の準備から始める場合や、コードを実行する際は、
[⧉[Google Sheets API] Google Sheets API v4をJavaで操作する](https://qiita.com/doran/items/3d43f776188b2281044c)
を参照ください。
```
例：requests.add(moveDimension(sheetId)); //実行したいリクエストのMethodを指定
```
:::

:::note info
その他のGoogle Sheets APIは、下記の記事を参照ください。
[⧉[Google Sheets API] JavaでスプレットシートのメニューとAPIを関連づけてみた](https://qiita.com/doran/items/2f6f8932b994fbd1a170)
:::
|No|目次|
|---|---|
|1|[セルの結合](#1-セルの結合)|
|2|[セルの結合解除](#2-セルの結合解除)|

## 1. セルの結合
指定したシートのセルを結合します。
結合方法は下記が指定できます。
・指定範囲を全部結合   ：　MERGE_ALL
・指定範囲を横のみ結合　 ：　MERGE_COLUMNS
・指定範囲を縦のみ結合　 ：　MERGE_ROWS

**サンプル コード**
```
public static Request mergeCells(Integer sheetId) {
    Request request = new Request();

    GridRange range = new GridRange(); //結合する範囲
    range.setSheetId(sheetId);         //結合する範囲のシートID
    range.setStartRowIndex(2);         //開始行(0スタート)
    range.setEndRowIndex(4);           //終了行(1スタート)
    range.setStartColumnIndex(1);      //開始列(0スタート)
    range.setEndColumnIndex(3);        //終了列(1スタート)

    MergeCellsRequest r = new MergeCellsRequest();
    r.setRange(range);
    r.setMergeType("MERGE_ALL");       //指定範囲を全部結合
    
    request.setMergeCells(r);
    return request;
}
```
**実行結果**
3行目〜4行目、２列目〜３列目のセルが結合されました。
<img width="480" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114621/ead9af7a-9318-ad2f-ebf2-3cb525141560.png">
<img width="480" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114621/8f3fa05b-21ea-2feb-6042-89f458800b64.png">

## 2. セルの結合解除
セルの結合を解除します。

**サンプル コード**
```
public static Request unmergeCells(Integer sheetId) {
    Request request = new Request();

    GridRange range = new GridRange(); //結合解除の範囲
    range.setSheetId(sheetId);         //結合解除するシートID
    range.setStartRowIndex(2);         //開始行(0スタート)
    range.setEndRowIndex(4);           //終了行(1スタート)
    range.setStartColumnIndex(1);      //開始列(0スタート)
    range.setEndColumnIndex(3);        //終了列(1スタート)

    UnmergeCellsRequest r = new UnmergeCellsRequest();
    r.setRange(range);
    
    request.setUnmergeCells(r);
    return request;
}
```
**実行結果**
セルの結合が解除されました。
<img width="480" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114621/8f3fa05b-21ea-2feb-6042-89f458800b64.png">
<img width="480" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114621/f5725dfd-d5f2-2241-9ae1-768db3a9d42d.png">

おしまい。。
インターネットの基礎(目次)

## はじめに
　インターネットの初歩的な仕組みや、その関連で散見する単語の定義など、
　自身が疑問に思ったことを調べまとめた記事である。
　内容は以下である。

　・インターネットとは？
　・プロバイダとは？
　・プロトコルとは？
　・サーバとクライアント
　・データ
　・セキュリティ

<br>









<br>

## インターネットとは？
　ネットワークの規模(範囲)を表す言葉であり、
　一番規模の大きいものがインターネットである。

https://qiita.com/iheuko/items/45661413de99b07ab0a4


### ネットワーク
　コンピュータ同士が繋がってやりとりできるようになった状態のことを、
　ネットワークという。
　規模によってLAN、WAN、インターネットに分類される。


#### ・LAN
　一番規模の小さいネットワーク。
 
:::note info
具体的には：
　有線の場合、ハブによって物理的に接続した機器で構成される範囲。
　無線の場合、アクセスポイントから電波が届く範囲。
:::

https://qiita.com/iheuko/items/792eb967a8f79b1f257f


#### ・WAN
　LAN同士で通信するネットワーク。

:::note info
WANとインターネットの違い：
　同義として使用されることもあれば、
　WANはプライベートであり、インターネットはパブリックなネットワーク
　として表現される。
:::

<br>





<br>

## プロバイダ(ISP)とは？
　インターネットへの接続サービスを提供する会社。
 
:::note info
具体的には：
　ユーザーがインターネットを利用するために必要な
　IPアドレスを発行してくれる。
:::


### インターネット利用に必要
　そもそもインターネットに接続するには、以下2つが必要である。
 
　・プロバイダとの契約によってサービスを利用できるようにする
　・プロバイダと契約者とを結ぶための物理的な回線

:::note info
　プロバイダと契約者とを結ぶ回線をアクセス回線という。
:::

　プロバイダは、アクセス回線を回線事業者に任せる場合もあれば、
　上記どちらも提供している場合がある。

:::note info
回線事業者：
　公衆回線(光ケーブルや電話回線など)を保有、提供する会社。
:::

<br>





<br>

 ## プロトコルとは？
　通信ルールをまとめた仕様書。
 
　ネットワーク上にある機器やプログラムは、
　共通のプロトコルに従って動くように作られている。
　それによって、異なるメーカーが製造する機器でも通信が成立している。

### 階層モデル
　プロトコルを役割毎にレイヤーとして分類したもの。

 :::note info
階層モデルは概念：
　階層モデルという実体があるわけではないし、
　データがやりとりされる際に各階層を通っていくわけでもない。
　あくまでもプロトコルを階層的に定義した概念である。
:::

https://qiita.com/iheuko/items/7ef4dbe3b4b50106c0f8

<br>





<br>

## サーバとクライアント
　ネットワーク内のコンピュータは、
　サービスを提供する側の場合サーバと、
　それを受ける側の場合クライアントと呼ばれる。

:::note info
サーバとクライアントを分かつのは、
ハードウェアではなくインストールするプログラムによって変わる。
:::

## データ
　ネットワーク内のデータは、パケットと呼ばれる単位に分割されやりとりされる。
　パケットには、受信先や送信元のアドレスなど情報が付与される。

## セキュリティ
　通信におけるセキュリティは、さまざまな技術が活用されている。

https://qiita.com/iheuko/items/0ea6f0746f185707d0e7
PaizaスキルチェックDランク頻出文法　Python3編

# PythonでPaizaスキルチェックを260問解いてミスをした文法や調べた文法をまとめます。
## 苦手だった標準出力について取り上げます。
### 区切り文字を変える(sep)
```python: sep.py
a = 3
b = 5
c = [a, b]
print(*c, sep ='/')
```

```output: sep.py
3 / 5
```
sepパラメーターを用いると、上記のようにリストの中身をシングルクオテーション''で指定した区切り文字によって区切ることができます。
ちなみにcのまえについている*(アスタリスク)にはリストの1つ1つの要素を取り出す(**アンパック**)するという意味があります。
```python: list.py
li = [1, 2, 3]
print(li)
```
```output: list.py
[1, 2, 3]
```
ところが、アスタリスクを用いると下記のようになります。
```python: list*.py
li = [1, 2, 3]
print(*li)
```
```output: list*.py
1 2 3
```
###foramt関数　{}の中に埋め込みたい変数を入れる。
例えば、変数a,b,c,d をハイフン(-)でつなぎたい場合下記のコードを書くことができます。
```python: format.py
a = 1
b = 2
c = 3
d = 4
print("{}-{}-{}-{}".format(a,b,c,d)
```
```output: format.py
1-2-3-4
```
### join() メソッドを使うと文字列のリストを一つの文字列に連結できる。
```python: join.py
l = ["a", "b", "c", "d"]
a = "".join(l)
print(a)
```
```output: join.py
abcd
```
#### 上記の文法と配列、リスト内包表記をマスターすればDランクはほぼ自力で解くことができるようになると思います。Cランクも少し解き始めたのですが、Dランクの簡単な問題が小学校低学年レベルの文章題だとすると、Cランクの簡単な問題は小学校高学年レベルの文章題のように感じました。Dランクも一番難しい部類の問題はCランクの簡単な問題よりも手こずり、はじめてCランクを解いたときに意外と簡単に感じました。Cランクも全問解けるようになりたいです。
サーバーを止めるな!

# 趣旨

僕は意図せず初めに最も難しい Systemd を使ってラズパイでbotを実装してたので、どの方法でも難しく感じなかったのですが、サーバーを止めない方法は僕の知る限り4つもありますし、僕も忘れがちなので備忘録を残しておきます。

以下 Systemd を使った例を載せておきます。

https://qiita.com/danieltanaka/items/39378424d8dd81937e3c

# nohup コマンド

nohup コマンドは、別のコマンドをバックグラウンドで実行し、ハングアップシグナルを無視するためのPOSIXコマンドです。これにより、ユーザーがログアウトした後もプロセスが継続して実行されます。

```
daniel@ubuntu:~/telegram$ nohup python test.py &
```

このコマンドは、test.py をバックグラウンドで実行します。出力はデフォルトで nohup.out にリダイレクトされます。

停止する際には以下のコマンドで process ID を検知して、Killします。
```
ps aux | grep part_of_process_name_or_command | grep -v grep
```

```
kill PID
```


# screen コマンド

screen は一つのターミナルウィンドウやリモートターミナルセッション内で複数の独立したターミナルセッションを使用できるターミナルマルチプレクサーです。ユーザーがログアウトした後もこれらのセッションを生存させ続けます。

新しいセッションを開始するには、単に `screen` と入力します。
スクリーンセッション内でスクリプトを通常通り実行します。
セッションからデタッチし、バックグラウンドで実行を続けるには、Ctrl-A その後 d を押します。
セッションに再接続するには、`screen -r` と入力します。

# tmux コマンド

tmux は screen に似ていますが、より新しく、より複雑な機能セットを持っています。これもまた、セッションからデタッチして後で戻ることができます。

`tmux` を入力して新しい tmux セッションを開始します。
tmux セッション内でスクリプトを実行します。
セッションからデタッチするには、Ctrl-B その後 d を押します。
既存のセッションに再接続するには、`tmux attach` と入力します。

# Systemd サービスを使用する

ルートアクセスがあり、スクリプトをサービスとして実行したい場合（ブート時またはオンデマンドで起動）、systemd サービスファイルを作成できます。

例えば、/etc/systemd/system/my_script.service にサービスファイルを作成し、以下のような内容を記載します。

```
[Unit]
Description=My Script Service

[Service]
User=daniel
WorkingDirectory=/home/daniel/telegram
ExecStart=/home/daniel/file/env/bin/python /home/daniel/file/test.py
Restart=always

[Install]
WantedBy=multi-user.target
```

サービスを有効にして開始します。

```
sudo systemctl enable my_script.service
sudo systemctl start my_script.service
```

この方法はより複雑ですが、システムの起動とシャットダウンプロセスとの統合により、より多くの制御を提供します。
2年勤務したWeb制作会社を退職したので振り返る

# 初めに

こんにちは！taisei_codeです。

私は3年前まで大学を卒業してから、飲食店でフリーターをしていました。そこから、未経験からWeb制作会社に転職してエンジニアとして働き始めました。紆余曲折しながらも、スタートラインに立って突き進んできた2年間を退職から日が浅いうちに振り返りたいと思います。

# 私について

・埼玉県出身の27歳
・四年制の大学卒業
・新卒ブランドを捨て、飲食店でフリーター勤務（3年）

# 経験したこと

入社した会社で経験したことは大きく2つです。
それは、更新系と新規（LPとWebサイトのリニューアル）案件です。

### 更新系

入社して最初に任せていただいたのは更新系の案件です。既に公開されているWebサイトの情報をHTMLで更新する案件です。主に、画像・URL・テキストなどを修正します。依頼内容によって、指定の場所にコンテンツ（期間限定のプランなど）を追加するような依頼もあります。更新系は、入社してから退職するまで担当していました。

### 新規

新規案件はLPを約10本、100ページ規模のコーポレートサイトのリニューアルで20ページの静的コーディングを担当しました。共通して、デザイナーが作成したデータからコーディングをします。更新系のような単純作業よりは、やりがいを感じていました。時には、WebサイトにJavaScriptで動き（もっと見る、アコーディオン、スライドショーなど）を付けていました。そして、退職直前まで担当していたのはECサイトの導線になるLPをWordPressで実装しました。

退職までに担当した業務は以下の通りです。

- HTML,CSSで静的コーディング
- JavaScriptでWebサイトに動きを付ける
- Vue.jsの2系から3系へ移行作業
- WordPressのプラグイン（ACF）でカスタム投稿の実装
- PhotoShopから画像の書き出し、簡単な画像加工

# 自分の進むキャリアについて

自分の進むキャリアについては、1年過ぎた辺りから、半年後・1年後を想像してみたときに凄く悩みました。それは、業務内容が更新系の案件に偏っていたことから、成長曲線が鈍化しているように感じていました。細かいことを言い出したら、単純な作業でも学べることは大量にあります！（先輩エンジニアにも言われた）また、JavaScritを触っていたことからReactに興味を持って、モダンな技術を触りたいと考えるようになったので<font color="red"> **Web開発のエンジニアになろう！**</font>と決心しました。

# 終わりに

経験を積めるWeb制作会社も世間にはあるので、一概にWeb制作はオワコンということではありませんが、早い段階で今後進むキャリアについて考えることは大切です。先輩エンジニアに「2年で辞めるのは、正直早い」と言われましたが、私が飲食店フリーターから未経験でWebエンジニアで転職できたように、<font color="red">**1年あれば人生を変えることができる**</font>と考えています。長々と書いてしまいましたが、現状維持に満足できない方の参考になれば幸いです。
ネットワーク・セキュリティ

## はじめに
　ネットワーク上にあるデータがどのようにやり取りされているかを、
　セキュリティの観点から理解する。
　内容は以下である。
 
　・データ暗号化方式
　・電子署名
　・電子証明書
　・セキュアプロトコル
　・ファイアウォール
　・無線LANセキュリティ
　・VPN

<br>









<br>

## データの暗号化
　データの暗号化には、鍵を使用する。
　その種類や扱い方によって3つの方式に分類される。

:::note info
鍵とは？：
　データを暗号/復号する際に使用するもの。
　実体は、8や16バイトなどのバイナリデータ。
:::

<br>

### 1.共通鍵暗号方式
　共通鍵１つで、暗号化と復号化を行う。
　受信者と送信者ともに共通鍵を持っている必要がある。

<br>

### 2.公開鍵暗号方式
　秘密鍵と公開鍵の２つを使用する。
　暗号化を公開鍵で行い、復号は秘密鍵で行う。

　**仕組み**
　　受信者が２つの鍵を持っていて、そのうちの公開鍵を送信者に渡す。
　　送信者は、その鍵でデータを暗号化して送信する。
　　受信者は、自身の秘密鍵で復号化する。

<br>

### 3.ハイブリッド暗号方式
　公開鍵暗号方式で共通鍵を受け渡し、
　それから共通鍵暗号方式で通信を行う。
 
　SSL/TLSやSSH、S/MIMEなどで採用されている。

<br>









<br>

## 電子署名
　元データをハッシュ化してメッセージダイジェストを作成し、
　秘密鍵で暗号化したもの。
　電子署名は、秘密鍵で暗号化し公開鍵で復号化する。

:::note info
ハッシュ化とは？：
　特殊なアルゴリズムでデータを要約すること。
　特徴は、元データが同じでなければ同じ結果にならないことや、
　元データに戻せないなど。
:::

　**使用方法**
　　元データをハッシュ化してメッセージダイジェストにしたものと、
　　電子署名を公開鍵で復号化したメッセージダイジェストを比較することで、
　　データが改ざんされていないことが証明される。



<br>









<br>

## 電子証明書
　公開鍵が誰のものであるか証明するためのもの。
　認証局が発行する。
　内容は、公開鍵や所有者情報、認証局の電子署名など。

:::note inofo
認証局の電子署名：
　認証局に申請する時に渡した鍵や所有者情報、認証局情報などをハッシュ化して
　電子署名にしたもの。
:::

<br>









<br>

## セキュアプロトコル
　セキュリティ機能を備えたプロトコル。
 
 <br>
 
### SSL/TLS
　サーバとクライアント間の通信セキュリティを高めるプロトコル。
　サーバ証明書(電子証明書)を利用する。
　ハイブリッド暗号方式が採用されている。

:::note info
SSL/TLSは、他のプロトコルと組み合わせて活用されている。
例えば、HTTPSやFTPS、POP over SSL、SMTPSなど。
:::

<br>

### SSH
　Telnetのセキュリティを高めたプロトコル。
　ハイブリッド暗号方式が採用されている。
　電子証明書は使用しない。

<br>









<br>

## ファイアウォール
　許可されたパケット以外を遮断する技術。
　パケット内のどの情報を検査対象にするかによって、3種類に分類される。

### 1. パケットフィルタリング型
　パケットのIPヘッダー内のIPアドレスで制御する。
　つまり、インターネット層のヘッダーを確認する。

### 2. サーキットレベルゲートウェイ型
　IPアドレスに加えてポート番号で制御する。
　つまり、トランスポート層のヘッダーを確認する。

　TCPの場合、3ウェイハンドシェイクのsynパケットを検査する。
　UDPの場合、ヘッダーを確認する。

### 3. アプリケーションゲートウェイ型
　プロトコルやURL、テキストで制御する。
　つまり、アプリケーション層のヘッダーを確認する。

<br>









<br>

## 無線LANセキュリティ
　データの暗号化には、速度も重視されるため
　共通鍵暗号方式が採用されている。

　共通鍵は、パスフレーズと初期化ベクトルを組み合わせて作成する。
　パスフレーズとは、ユーザ指定の文字列。
　初期化ベクトルとは、一定時間ごとに変化する数値。

### 仕組み
　ストリームとブロック暗号方式がある。

　**・ストリーム暗号方式**
　　1ビットあるいは、1バイト単位で暗号/復号化していく。

　**ブロック暗号方式**
　　64ビット単位で暗号/復号化していく。

<br>









<br>

## VPN
　物理的な専用回線を用いずに、
　公衆回線を仮想的に独立した専用回線のように使用する仕組みのこと。

　データの暗号化と回線のトンネリング技術により、
　特定の区間全ての通信を秘匿する。

:::note info
トンネリングとは：
　あるプロトコルのパケットを別のプロトコルのヘッダーとトレーラを付け包む
　カプセル化技術を用いて、仮想的な通信経路を構築すること。

　例えば、IPv4とIPv6間で通信するとき、
　本来なら異なるプロトコル間なので通信できない。
　そこで、IPv6パケットをIPv4で包むカプセル化によって通信可能になる。

　つまり、トンネリングとは異なるプロトコル間の通信経路を構築している。
:::
[AWS] CloudFormation で Lambda の更新が Update complete cleanup in progress から変化しなかった

## 以下の操作をしたら発生

- Control Tower 経由でアカウントを作成(以下、その新しいアカウントでの操作)
- いくつか Lambda関数を手動で作成した
- Lambda の同時実行数をコンソールで操作しようとしたら変更ができなかった
- Lambda の Concurrent executions のクオータが 10 であった
- Lambda の Concurrent executions のクオータを 1000 にするよう申請し変更された
- その後、 CDK で SQS と Lambda のリソースを新しく作成しようとした
- Update complete cleanup in progress から30分以上変化しなかった

## 確認したこと

- CloudTrailを確認するとCloudFormationの一番最後の操作は Lambda関数の同時実行数を変更する操作だった
- 既存の他のLambda関数の同時実行数を見てみると、その数値が10だったものが899などの大きな数値になっていた(原因不明)

## 対応

- 既存の他のLambda関数の同時実行数を手動で元の同時実行数に修正した

## 結果

- 数分後、スタックしていた処理が動き出し、無事更新された
共有レンタルサーバにCodeIgniter4をインストール

要件：PHP7.4以上とSSHが使えること（できればPHP8が望ましい）


かたくなにクラウドとdockerをつかわないスタンス
とりあえず以下の例は Xserver です

2023-02-21時点でCodeIgniter4の最新バージョンは4.4.5

独自ドメイン hoge.com にサブドメイン piyo.hoge.com を切って、そこに新しいサービスを作ると仮定
サーバ上のパスは /home/myaccount/hoge.com/public_html/piyo になる

```
cd /home/myaccount/hoge.com/public_html
```


Composer 2.0.14 が必要、PHP使える共有サーバはComposer入ってたりするけどバージョン古かったりするから、カレントに入れちゃう
https://getcomposer.org/download/


```
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('sha384', 'composer-setup.php') === 'edb40769019ccf227279e3bdd1f5b2e9950eb000c3233ee85148944e555d97be3ea4f40c3c2fe73b22f875385f6a5155') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"
```

ComposerでCodeIgniterをセットアップするが、共有サーバはSSHで入ったときのデフォルトのPHPのバージョンで揉めるので、バージョンを指定して実行

CodeIgniter4はディレクトリ直下でなく、その下の public ディレクトリに index.php が置かれてて色々ややこしいので、webで公開したいディレクトリと別のディレクトリにインストールするのが無難

```
php8.2 ./composer.phar create-project codeigniter4/appstarter piyo_app
```

CodeIgniter4 の public ディレクトリをwebで公開したいディレクトリにシンボリックリンクする

```
ln -fs piyo_app/public/ piyo
```

動作確認（DNS浸透するまではサブディレクトリで見れる罠）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38400/e53a7128-da7e-0997-927e-0909b2ea851e.png)
【TCA】Task.yieldを使ってCPU負荷の高い処理を効率的に実行する

# はじめに
TCAの[Performance](https://pointfreeco.github.io/swift-composable-architecture/main/documentation/composablearchitecture/performance#CPU-intensive-calculations)に関するドキュメント内で、`Task.yield()`というAPIを使用したCPU負荷対策の例が挙げられていました。

今まで`Task.yield()`を使ったことが無く、ドキュメントを読んでも何をしているのかいまいちわからなかったので調べてみました。

# Task.yield
`Task.yield()`は現在のタスクをサスペンドし、同じスレッドで別のタスクを実行できるようにするためのAPIです。

以下のコードを見てください。
最初に無限ループするタスクを100個生成し、その後「Hello, world!」と出力するタスクを生成します。
プログラムの実行が終了しないように、最後に`while true {}`でメインスレッドをブロックしています。

```swift
for _ in 0..<100 {
  Task {
    while true {}
  }
}

Task {
  print("Hello, world!")
}

while true {}
```

このコードを実行すると、「Hello, world!」は出力されません。
無限ループするタスクが全てのスレッドをブロックしていて、「Hello, world!」を出力するタスクはスレッドが空くのをずっと待ってしまっています。

Xcodeで実行を一時停止してみると、10個のスレッドが無限ループによってブロックされていることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81715/947077f7-2059-6e64-429a-6ede0b2a6e3c.png)

そこで`Task.yield()`の出番です。
無限ループ内で`Task.yield()`を実行するようにしてみましょう。

```swift
for _ in 0..<100 {
  Task {
    while true {
      await Task.yield()  // 追加
    }
  }
}

Task {
  print("Hello, world!")
}

while true {}
```

すると、「Hello, world!」が出力されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81715/6745e1c8-8d1b-16af-859b-cf3b7a0646a0.png)

`Task.yield()`によって無限ループが一時的に中断され、「Hello, world!」を出力するタスクにスレッドが割り当てられたのです。
出力が完了したらそのタスクは終了するので、スレッドはまた無限ループの実行に戻ります。

より実用的なケースでは、実行に長い時間がかかる計算処理の途中に`Task.yield()`を入れておくことで、別の並行タスクの実行が遅くなってしまうのを防ぐことができるというわけです。

# ReducerでCPU負荷の高い処理を効率的に実行する
`Task.yield()`が理解できたところで[TCAのドキュメント](https://pointfreeco.github.io/swift-composable-architecture/main/documentation/composablearchitecture/performance#CPU-intensive-calculations)を読んでみます。

Reducerはメインスレッドで実行されるため、Reducerで直接CPU負荷の高い処理を実行しようとすると、UI操作が重くなるなどの影響が出るため避けるべきです。

```swift
case .buttonTapped:
  var result = // ...
  for value in someLargeCollection {
    // Some intense computation with value
  }
  state.result = result
```

そのような処理はEffectを使い、非同期に実行されるようにします。
また、長い時間スレッドをブロックしてしまうような処理を行う必要がある場合は`Task.yield()`を呼び出し、適度な間隔でスレッドを解放してあげましょう。

以下の例では、1000回のループごとに1回`Task.yield()`を呼び出しています。

```swift
case .buttonTapped:
  return .run { send in
    var result = // ...
    for (index, value) in someLargeCollection.enumerated() {
      // Some intense computation with value

      // Yield every once in awhile to cooperate in the thread pool.
      if index.isMultiple(of: 1_000) {
        await Task.yield()
      }
    }
    await send(.computationResponse(result))
  }


case let .computationResponse(result):
  state.result = result
```

このようにすることで、メインスレッドをブロックせず、他のEffectの実行にも影響を与えずに、CPU負荷の高い処理を効率的に実行することができます。
Unityでスイカゲームを作ってみよう

# スイカゲームとは？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216701/1f1cf6a8-5824-38d3-1753-58c7c217eac9.png)

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

# 必要なもの

- 箱
- 雲
- フルーツ
- 動き
- 同じフルーツが重なるプログラム
- 得点
- 音

# 作ってみよう

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

## 箱

箱は、上と左右に四角形があればいけそうですね。

例えば、２Dオブジェクトのスクエアを３つ用意して、下記に設定。

```
Bottom:
    Position: X = 0, Y = -4.7, Z = 10
    Rotation: X = 0, Y = 0, Z = 0
    Scale: X = 7, Y = 0.3, Z = 1
Left:
    Position: X = -3.5, Y = -0.7, Z = 10
    Rotation: X = 0, Y = 0, Z = 0
    Scale: X = 0.3, Y = 8.3, Z = 1
Right:
    Position: X = 3.5, Y = -0.7, Z = 10
    Rotation: X = 0, Y = 0, Z = 0
    Scale: X = 0.3, Y = 8.3, Z = 1
```

## 雲

雲は、2Dオブジェクトのキャプシュールを使ってみます。下記のように設定。

```
Cloud:
    Position: X = 0, Y = 4.25, Z = 10
    Rotation: X = 0, Y = 0, Z = 0
    Scale: X = 1, Y = 0.3, Z = 1
```

![スクリーンショット 2024-02-23 17.13.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216701/ff55cab1-f49d-d075-0413-cdfdcc504161.png)

上記のようになっていればOK。
ちょっと味気ないので、色をつけたり、画像にしたりすると良いかもしれません！

## 上の雲を動かすプログラム

```MoveRightAndLeft.cs
    public int speed = 10;

    void Update()
    {
        if (Input.GetKey(KeyCode.RightArrow))
        {
            transform.Translate(speed * 1 * Time.deltaTime, 0, 0);
        }
        if (Input.GetKey(KeyCode.LeftArrow))
        {
            transform.Translate(speed * -1 * Time.deltaTime, 0, 0);
        }
    }
```

`GetKey` は押されている間。
`Time.deltaTime` は一回の動作にかかった秒数です。

## 果物の落下

コンポーネントを追加から `Physics 2D` の `Rigidbody 2D` を追加。

あと、箱と触る判定も入れたいので、`Circle Collider 2D` も追加。

## 果物の出現

```SpawnFruits.cs
    public GameObject[] fruits;

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            Instantiate(fruits[Random.Range[0, 3], this.transform.position, this.transform.rotation);
        }
    }
```

`GetKeyDown` は押された時。

## あと何かある？

同じ果物同士がぶつかった時のスクリプト

```FruitsCollide.cs
    private void OnCollisionEnter2D(Collision2D collision)
    {
        if (this.gameObect.name == collision.gameObject.name)
        {
            Destory(this.gameObject);

            collision.gameObject.GetComponent<FruitsCollide>().upgrade = null;

            if (upgrade)
            {
                Instantiate(upgrade, this.transform.position, this.transform.rotation);
            }
        }
    }
```

# unityroom へ公開



▼資料

https://unityroom.com/

https://docs.google.com/presentation/d/19gn6ADwhoNKfZDvWmsRtuvPF4VjA5_ehps4YM5y9TNc/edit#slide=id.g2af190a28bb_0_8
Laravel＋React開発環境をDockerでゼロから構築する手順をまとめてみた

まっさらな状態から、表題の開発環境が構築できたのでシェア。
ローカル環境をまったく汚さず開発環境を作りたい方向けです。

## ゴール

https://github.com/hirotada-t/laravel-react-docker

## 大まかな流れ
バックエンドもフロントエンドも同じ流れでクリアできるはず。

### 1. インストールに必要な最低限のdocker-compose/Dockerfileを作成する
今回はLaravelと、ReactをViteで作ることが目的。
なので最低限は、多分このあたりになると思う。
- Laravel　→　Composerが使える
- React　→　Node.jsが使える
- コンテナを起動したままの状態でキープできる

言語やFWによって最低限が何になるか変わるので、それは適宜調べておく。

### 2. フォルダをマウントしてコンテナを起動する
docker-composeでフォルダをマウントしておきます。
コンテナの中でインストールを行うので、それをローカルにコピーさせます。

### 3. コンテナに入ってインストールコマンドを叩く
コンテナの中からプロジェクトの雛形をインストールする。
ローカル環境を汚さずにすむ。

### 4. Dockerfileを修正
インストールにしか使わないコマンドや、無駄な記述があれば削除しておく。
起動時間が早くなります。

### 5. 再度コンテナを起動してプロジェクトが動くよう調整する
ポートやパスを調整して、ビルド環境・開発環境共に動くように調整する。
コンピューターの仕組み分かっていないとかなり苦しいけど、GPTに投げまくって粘り強く対応すればなんとかなる。

## 取り組んでて詰まったこと
- これくらいの規模で各状態をパッと認識できない
- エラーの原因が分からないからひたすら試行錯誤になりがち
- そもそもコマンドの意味が分からん
- Nginxの設定ファイルとか始めてみた意味不明
- どことどこがマウントされてるか行方不明になりがち

修行中である。
 
## 【以下余談】
### なぜこの組み合わせ？
- PHPをエックスサーバーにデプロイする環境ならワンチャン他の人が修正できる
- AWSも可能だがこれ以上開発のハードルを上げて身動き取れなくなるのは避けたい
- 作りたいアプリの機能的にPHPだけだと流石に効率が悪い
- NextJSは使えないので純粋なReact
- Vueでも良いけどさすがにReact経験を積んでおきたい
- WSL2の設定さえクリアできれば誰でも開発環境を作れるDockerはマスト

### アーキテクチャの構想

LaravelはAPIとしてのみ使い、Reactのフロントエンド側とは完全に独立させる予定。
オーバースペックな気はするけど、ロジックをReact側に置かないことで、明確な役割分担と余白を持たせたい。

### おわりに
他社が作ったLaravelとReactそれぞれの開発環境を、内製できるよう自社で構築した経験が役に立ちました。
どちらもほぼ使ってこなかったスキルセットだけど、何とかなるものだね。
別々の仕事の経験から、「これ、くっつけたらどうなるんだろ？」と思ってやってみたら、意外と簡単にクリアできました。

何か足りなくて動かなくても、課題を探すときの解像度が高くなるので、クリアできる可能性が高くなります。
Dockerを使って環境を作ることに慣れる、大きなメリットだと思います。
【SwiftUI】SwiftUIでフォアグラウンド、バックグラウンドの検知

# 何をやるのか？

今回はSwiftUIでフォアグラウンド、バックグラウンドの検知する方法を紹介してきたいと思います。
この記事を投稿しようと思った経緯としては、ViewModifierのonAppearではフォアグラウンド時の検知ができなかったため、備忘録として残しておこうといった感じです。

# ScenePhaseでアプリの動作状態の検知

```swift
struct ContentView: View {
    @Environment(\.scenePhase) var scenePhase

    var body: some View {
        Text("Hello, World!")
            .onChange(of: scenePhase) { newPhase in
                switch newPhase {
                    case .inactive:
                        print("フォアグラウンドだが、動作停止時")
                    case .active:
                        print("フォアグラウンド時")
                    case .background:
                        print("バックグラウンド時")
                }
            }
    }
}
```

# 参考文献

https://developer.apple.com/documentation/swiftui/scenephase
https://stackoverflow.com/questions/63423845/swiftui-onappear-only-running-once
git コマンド

## 1.git の初期化　リポジトリの作成
`git init`
## 2.名前メールアドレスの設定
`git config --local user.name "名前"`
`git config --local user.email "mail"`

確認は
`git config --local user.email`
などと打つとみることができる。
## ３．gitの場所(1branchのどこにいるか確認する）
`git status`
## 4.ステージに追加
`git add ファイル名`
commitする準備をする作業
## 5.変更内容を記録するコミットする
`git commit -m "メッセージ"`
gitをコミットするときにどのような変更内容を行うかを表すもの。
## 6.記録された内容を確認
`git log`
著者やidなどがみれる
## 7.過去のブランチにさかのぼる
`git switch --detach コミットid`
detach というのは新たな時系列をつくる切り離すという意味合いがある。前のブランチに戻ることができる。しかしこのブランチには新たに名前をつけなればいけない
## 8.新しいブランチの作成
`git switch --create メッセージ名`
このブランチに名前がつく

## 9.branch一覧を表示する
`git branch`
星がついているものが今いるブランチ

## 10.branchをマージンする
マージンとはブランチを１つにまとめること
`git merge くっつけるブランチの名前`
くっつけたいブランチの名前をいれる。conflictが起きている。
mergeをやめるには
`git merge --abort`

## 11.mergeの可視化
`git log --graph`
どこでどのようにマージンしたか動きがグラフ形式で把握できる。

## 12.公開鍵を登録
`ssh-keygen`
で鍵をgetする。
設定からsshからnew ssh keyをクリックし
`clip < ~/.ssh/id_rsa.pub`
クリップした鍵を貼り付ける

## 13.remoteとlocalをhubをつなげる
`ssh git@github.com`
自分のユーザー名がでれば成功です。

## 14.create リポジトリ
git hubでクリエイトリポジトリを行い。sshをコピーする
ここでは基本はprivateを選択する。

## 15.リモートとローカルのコネクト
`git remote add origin sshのコピー`

`git remote`
ここでorignがでてくれば成功
## 16.gitのプッシュ
branchの名前変更
`git branch --move main`
`git push --set-upstream origin main`
これで次回以降はgit pushだけでできる。
push:ローカルリポジトリの内容をリポートにアップロードすること
githubでテキストが追加できているか確認

## 17.gitのfetch
fetch:リモートリポジトリからローカルリポジトリに変更内容を同期させること
変更内容をローカルに辿り着かれるために行うコマンド
`git fetch`

## 18.merginのコンフリクト起きた時
`git checkout --ours`
自分がしたい変更対象すべてに適応される
`git checkout --theirs`
gitの追加する変更を優先するとき後ろにファイル名をいれるとそのファイルだけ変更される

pull:

#初回
```
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add origin #リポジトリ名
```

## 追加
```
git add .
git commit -m "変更内容" 
git push origin main
```
[Home Assistant] Windows PC上のVirtual Boxで動かす

ｃ



# 手順

## Virtual Box のインストール
### インストーラの取得
以下のページよりVirtualBoxのインストーラをダウンロードします。

https://www.virtualbox.org/wiki/Downloads

今回はなくても問題ありませんが、ついでに以下のファイルもダウンロードしておきましょう。同じページ内にあります。
「VirtualBox 7.0.14 Oracle VM VirtualBox Extension Pack」


### インストーラの実行
ダウンロードしたインストーラを実行し、任意のパスへインストールします。


### Extension Packのインストール
1.「ツール」→「□－」→「機能拡張」を選択します。
　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3084885/383c532f-0aa6-2bd1-4cf7-31d74538356a.png)
2. 「インストール」ボタンを押し、ダウンロードしたExtension Packを選択すれば完了です。
※もし圧縮されていた場合は解凍してから上記の操作を行ってください。



## Home AssistantのVMの構築
### イメージのダウンロード
以下のURLより、VirtualBox用のイメージをダウンロードします。ダウンロードしたイメージはそのままVMから利用しますので、任意の場所に移動させてください。

https://www.home-assistant.io/installation/windows

　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3084885/db7ccb1b-1483-a474-94b9-203ece314eb0.png)


### VMの構築
#### 名前とオペレーティングシステムの設定

「名前」は任意の名称を設定してください。指定したフォルダの傘下にこの名前のフォルダが新規作成されます。
「タイプ」は「Linux」を選択してください。
「バージョン」は「Linux 2.6 / 3.x / 4.x (64-bit)」を選択してください。
　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3084885/f312e0f3-0626-8402-c871-8118241da1f3.png)


#### 自動インストールの設定

不要です。


#### ハードウェアの設定
メインメモリは4GB(4096MB)以上に設定する形が望ましいですが、2GB(2048MB)以上であれば最低動作条件は満たしています。
プロセッサ数は特にこだわりがなければ緑色に塗られている範囲内で設定する形が望ましいです。ここを少なくしすぎると起動時間や動作に影響が出るため注意してください。
「EFIを有効化」は必ずチェックをつけてください。
　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3084885/0822e13b-4add-1b34-15a4-b83e7521932d.png)


#### ハードディスクの設定
「すでにある仮想ハードディスクファイルを使用する」を選択し、右側のファイル選択ボタンを押します。
　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3084885/959b4187-50f2-e91c-2de8-52a73010d261.png)

ハードディスク選択ダイアログで先ほどダウンロードしたイメージを選択し、追加します。
追加したイメージを選択した状態で、選択ボタンを押します。
　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3084885/22aeb415-ca4b-a579-fba2-9960ab417fde.png)

最後に完了を押します。


## VMの追加設定
先ほど作成したVMを右クリックし、設定を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3084885/9f6d1041-b512-c549-5faf-fe5c073ee706.png)

ネットワーク設定を選択し、割り当てを「ブリッジアダプター」に設定し、OKを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3084885/541fa478-86c5-0b14-8602-0cc6838d514d.png)


## Home Assistantの起動と初期セットアップ
作成したVMを右クリックし、起動を選択すればHome Assistantが起動します。
以下の画面が表示された後、しばらく経過した後、Home Assistantが利用できる状態となります。
その際、ホストPCからアクセスする場合は http://homeassistant.local:8123 を利用してください。
もしうまくアクセスできない場合は上部に表示されているIPアドレスをもとにして、 http://192.168.XXX.XXX:8123 で再度トライしてみてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3084885/244d7fa9-4039-67ec-34c6-3ad368931e18.png)



## 完成！
databricksで複数のテーブルの複数の列を対象にUpdate

# やりたいこと
複数のテーブルの複数のカラムの末尾の空白(半角、全角)を削除したい

# これを使う



```python
test = [
    {'table_name':'A','table_column': ['1','2','3']},
    {'table_name':'B','table_column': ['4','5']}
]

for tbl in test:
    tbl_name = tbl["table_name"]
    tbl_column = tbl["table_column"]
    for tbl_col in tbl_column:
        print(f"""{tbl_name},{tbl_col}""")
'''
出力結果
A,1
A,2
A,3
B,4
B,5
'''
```

# update文
```python
# 変数の格納
test = [
    {'table_name':'uc_kthoriguchi.test.test1','table_column': ['columnA','columnB']},
    {'table_name':'uc_kthoriguchi.test.test2','table_column': ['columnB']}
]
```


```python
# update
import inspect

for tbl in test:
    tbl_name = tbl["table_name"]
    tbl_column = tbl["table_column"]
    for tbl_col in tbl_column:
        update_sql = inspect.cleandoc(f"""
        update {tbl_name} set {tbl_col} = 
        CASE
        WHEN (regexp_instr({tbl_col}, '[^ 　]+')) > 0 THEN
            substring(
            {tbl_col},
            1,
            len({tbl_col}) - (regexp_instr(reverse({tbl_col}), '[^ 　]+') - 1)
            )
        WHEN {tbl_col} IS NULL THEN
            NULL
        ELSE ''
        END                              
        """)
        print(update_sql)
        spark.sql(update_sql)
```
update文の詳細は以下記事を参照
[databricksのテーブルの末尾の全角、半角スペースをカラム単位で除去する](https://qiita.com/kota-horiguchi/items/6aadb4b499a82476a92c)




-----2024/03/20 上記のコードではパフォーマンスが悪いので改善-----
参考にした記事
[DatabricksにおけるUpdate文の効率的な利用：多数のUpdate文実行によるパフォーマンス問題とその解決策](https://qiita.com/manabian/items/fc37994ec3b4899645e5)

```python
test = [
    {'table_name':'uc_kthoriguchi.test.test1','trim_col': ['columnA','columnB']},
    {'table_name':'uc_kthoriguchi.test.test2','trim_col': ['columnB']}
]

from pyspark.sql.functions import expr

for table in test:
    tbl_name = table["table_name"]
    tbl_column = table["trim_col"]
    # 変数の初期化
    columns_conf = {}

    # {カラム名；カラムの値}となる辞書の変数を作成
    for col in tbl_column:
        columns_conf[col] = expr(f"""
        CASE
        WHEN (regexp_instr( {col} , '[^ 　]+')) > 0 THEN
            substring(
            {col} ,
            1,
            len( {col} ) - (regexp_instr(reverse( {col} ), '[^ 　]+') - 1)
            )
        WHEN  {col}  IS NULL THEN
            NULL
        ELSE ''
        END
        """)
        print(columns_conf)
        
    df = spark.table(tbl_name)
    df = df.withColumns(columns_conf)
    df.write.mode("overwrite").saveAsTable(tbl_name)
    
```

もうひとパターン
```python
for table in test:
    tbl_name = table["table_name"]
    tbl_column = table["trim_col"]

    cols = ',\n    '.join([f"""
    {col} =
    CASE
    WHEN (regexp_instr( {col} , '[^ 　]+')) > 0 THEN
        substring(
        {col} ,
        1,
        len( {col} ) - (regexp_instr(reverse( {col} ), '[^ 　]+') - 1)
        )
    WHEN  {col}  IS NULL THEN
        NULL
    ELSE ''
    END""" for col in tbl_column])

    sql = f"""
    UPDATE {tbl_name}
    SET 
        {cols}
    ;
    """
    print(sql)
    spark.sql(sql)
```
４るの法則


# 成長するための法則を順序付けてまとめてみた

`This is 4rules.`

## 覚悟を決める

簡単にはできるようにはならない
すぐには、スキルは身につかない

## 先にやる

先にやらないと、寝る時間までの時間が少なくなるので、先にやること
きっとどうでもいいことをやっている

## 楽しんでやる

リラックスして、集中して、高揚しながら取り組んでいる時とそうでない時の学習効果は、40%になる

## ルールを守る

長い旅路を走るので、ルールを守ることで、必ず一定上の成長は見込める
AI  Numbers de 10万円【1．概要編】

_note：アプリ置き場_

https://note.com/daisuke892/n/naea8b2431860

# 【概要】
PythonといえばAI、AIといえばPython(語弊)ということで、何か作りたいなと思い、宝くじナンバーズ3の過去の当選番号記載のEXCELファイルから次回の当選番号をAI で予測します ぜひ10万円お小遣い稼ぎして頂きたいと思います。 これも順次コード紹介していく予定です。 外れても当方は一切責任は負いません（笑）ちなみに最初ロト６でやっていましたがデータが多くてAI処理の時間が掛かるためナンバーズ3に落ち着きました。


# 今回紹介するダッシュボード【動画】
https://youtu.be/zgZNwtxny3M

---

# アプリについて【実装する機能】
(テーマ：宝くじを当ててお小遣いを増やす)

- AIで分析を行う(Pytorch)

- AI学習回数を可変できるようにする

- EXCELまたはCSVファイルを読み込む

- 誰にでも使いやすいようにする

- デザインは後回し

- Dash/plotlyでグラフを表示する


---
先に「DASH de ダッシュボード」の記事作成後こちらを更新する予定です。
win-raw-inでRaw Inputを使う

## win-raw-inとは

https://github.com/holl-/win-raw-in

Pythonでraw inputを使うためのモジュールです。

readme.mdにも書いてある通り、Windowsで複数の入力デバイスを識別するために必要なものです。

> This package was inspired by the keyboard package. Unfortunately, keyboard does not distinguish between multiple input devices on Windows.

[Raw Input](https://learn.microsoft.com/en-us/windows/win32/inputdev/raw-input)はWindowsで複数HIDデバイスを取り扱うのに便利です。C++ではAPIを叩けばよいですが、Pythonから、となるといろいろ面倒です。
win-raw-inを使えばその面倒を回避できるので大変ありがたいです。

## インストール

```bash
$ pip install win-raw-in
```

## 使ってみるとエラーになる

```python
Python 3.11.2 (tags/v3.11.2:878ead1, Feb  7 2023, 16:38:35) [MSC v.1934 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import winrawin
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python311\Lib\site-packages\winrawin\__init__.py", line 8, in <module>
    from ._api import hook_raw_input_for_window, RawInputDevice, Mouse, Keyboard, HID, RawInputEvent, list_devices
  File "C:\Python311\Lib\site-packages\winrawin\_api.py", line 7, in <module>
    from ._usb_ids import lookup_product
  File "C:\Python311\Lib\site-packages\winrawin\_usb_ids.py", line 7, in <module>
    DATABASE = usb_ids_file.read()
               ^^^^^^^^^^^^^^^^^^^
UnicodeDecodeError: 'cp932' codec can't decode byte 0x97 in position 148213: illegal multibyte sequence
>>>
```

エラーの原因は`usb.ids`ファイルのエンコーディングが`windows-1252`（あるいは`latin-1`）だからのようです。

latinな環境では全く問題ありませんので、バグとは言えないです。

配布元のファイルがそうなっています。
http://www.linux-usb.org/usb-ids.html

## パッチを当てる

`win-raw-in`はgithub上でissueが無効化されているようなので、手元でパッチを当てます。
だれかfolkしてprを投げてください。

```diff_python:_usb_ids.py
- with open(os.path.join(os.path.dirname(__file__), 'usb.ids'), 'r') as usb_ids_file:
+ with open(os.path.join(os.path.dirname(__file__), 'usb.ids'), 'r', encoding='latin-1') as usb_ids_file:
    DATABASE = usb_ids_file.read()
```

## 改めて使ってみる

```python
Python 3.11.2 (tags/v3.11.2:878ead1, Feb  7 2023, 16:38:35) [MSC v.1934 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import winrawin
>>>
>>> for device in winrawin.list_devices():
...     if isinstance(device, winrawin.Mouse):
...         print(f"{device.mouse_type} name='{device.path}'")
...     if isinstance(device, winrawin.Keyboard):
...         print(f"{device.keyboard_type} with {device.num_keys} keys name='{device.path}'")
...
Unknown type or HID keyboard with 264 keys name='\\?\HID#VID_17EF&PID_60EE&MI_00#9&4677234&0&0000#{884b96c3-56ef-11d1-bc8c-00a0c91405dd}'
HID wheel mouse name='\\?\HID#VID_17EF&PID_60EE&MI_01&Col01#9&17978e72&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}'
HID wheel mouse name='\\?\HID#VID_045E&PID_0047#8&1c946f37&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}'
```


→マウスが2個認識されています。
【HTML】fieldset要素の使い方

`fieldset`要素を使用して以下のように使用することで`fieldset`要素の子孫要素のフォームコントロールにまとめて`disabled`を設定できます。

```html
<fieldset disabled>
	<div>
	  <input type="email" name="name" />
	</div>

	<div>
	  <input type="password" name="password" />
	</div>
</fieldset>
```
HTML5プロフェッショナル認定試験レベル1に合格しました！

# はじめに

タイトル通り2024/2/19にHTML5プロフェッショナル認定試験レベル1を受けてきました。
受験した経緯としては相変わらず社内評価のためと、フロントエンドの知識習得のためになります。

# 勉強方法・勉強期間

試験対策としてまず [HTML教科書 HTML5プロフェッショナル認定試験 レベル1 スピードマスター問題集 Ver2.5対応](https://amzn.asia/d/c8bHuRO) を使って勉強してました。
この本は一問一答形式で解いていくものになるのですが、問題によっては見開きで答えが載っているため、視界に入らないように手で隠しながら…と使いづらく、1周したところで[Ping-t](https://mondai.ping-t.com/g)での学習に切り替えました。
HTML5の問題集は要課金ですが、400問はあるのでとてもよい教材になりました。（ミス・ヒット・コンボのシステムが素晴らしい）
何回やっても覚えきれないものは、用語集としてQiitaに記事を書きました。

勉強時間としては、約1ヵ月（43時間）になります。

# 試験当日
今回もテストセンターで受験しました。
相変わらずコインパーキングが満車で、他探すのに時間が取られてしまい会場入りは時間ギリギリになりました…
沖縄は夏日で半袖でしたが、試験部屋は相変わらずエアコンガンガンで、前回の経験を踏まえてカーディガン持って行って良かったです。（一応、試験中スタッフに声掛けて温度調節していただくことは可能とのこと）

■試験問題について
Ping-tの問題に近いものは多かったです。しかし、実際の試験ではキーボード入力が必要な問題がいくつか出てくるため、Ping-tだけやってるとワードのド忘れで少し躓くかもです。

# 試験結果
正解率93％で無事合格できました！
![スクリーンショット 2024-02-19 223215 - コピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1579802/98b584fb-15a5-302f-61a6-7bd04828db31.png)

# さいごに
HTML5の試験はあまり意味ないと言われがちですが、フロントエンドの知識があまりない私にとっては学ぶことが多く、受けて良かったと思いました。
試験問題としてHTML5で廃止になったもの、追加になったものについて問われることがあるのですが、これまでを知らないので非常に煩わしく感じることはありました…
Ping-tがレベル2の問題集用意してくれたら受けたいとは思いますが、今はないので一旦保留かなと。
初学者でも約1ヵ月Ping-tでみっちり勉強すれば十分合格可能と思いますので、Webデザイナ等を目指す方は受けてみてはどうでしょうか！
N+1問題とその解決方法についてしらべてみました．

## はじめに
今回は私がN+1問題について調べたことをもとに，
- N+1問題とはなにか
- N+1問題を解決するためには
をアウトプットして言いたいと思います．まだまだひよっこエンジニアのため，修正点等があればコメントで教えてください！

## N+1問題とは
データベースの操作においてよく見られるパフォーマンスの問題です．特にオブジェクト関係マッピング（ORM）を使用しているときに発生しやすい問題です．1つのデータを取得するために1回のクエリを実行すると，関連するデータを取得するために追加のN回のクエリは必要になり，結果として「N+1」回のクエリが必要になるケースを指します．

たとえば，あなたが友達10人にパーティーのお土産を渡すとします．友達一人一人に「何が欲しいの？」と聞いて，それを取りに行くのは非常に手間がかかりますよね．それよりも，最初に何が欲しいのかを全員に聞いてから，1度にすべてのお土産を取りに行く方が速いです．このように，N+1問題が発生したときに，それを解決する手段として有効なのが「一度にすべてを処理する」ことです．

N+1問題について考えるとき，Nが大きいときは処理に非常に時間がかかるので，打開策が必要になります．
この解決策として，
- JOINを利用して表の結合
- Eager Loading
の2種類があります．

これらの解決策についてそれぞれ説明したいと思います．
まずは例として以下のようなケースがあったとします．

## ケース
以下のような「アニメ」のテーブルとアニメの「筆者」テーブルが存在するとします．

![スクリーンショット 2024-02-20 192730.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3695047/cb941f81-0d18-efc7-1d99-22ee82cfd575.png)

各アニメに対して，そのアニメの筆者の名前と年齢を知りたいとすると，まず以下のようなSQLを発行します．

```sql
SELECT * FROM アニメ;
```
次に，アニメテーブルの各レコードから筆者IDを用いて筆者テーブルから検索するSQLを打つ．

```sql
SELECT * FROM 筆者 WHERE 筆者ID=3;
SELECT * FROM 筆者 WHERE 筆者ID=2;
SELECT * FROM 筆者 WHERE 筆者ID=4;
SELECT * FROM 筆者 WHERE 筆者ID=1;
```

上記のケースでは，最初にアニメテーブルを取得してきて（1件のクエリ），次に筆者テーブルを取得（4件のクエリ）しないといけない．このケースではN=4ですが，Nが膨大な数になった場合，処理時間が膨大になってしまいます．

## JOINを利用して表の結合
この問題を解決するために，SQLのJOIN句を使って，アニメと筆者テーブルを結合し，各アニメに対して筆者の名前と年齢を取得するためのSQLクエリの例です．

```sql
SELECT アニメ.アニメID,アニメ.タイトル,筆者.名前,筆者.年齢
FROM アニメ
JOIN 筆者 ON アニメ.筆者ID = 筆者.ID
```


## Eager Loading
Eager LoadingはORMの文脈で使用され，アプリケーションコード内でのデータ取得方法です．Eager Loadingの利点は，関連するデータを事前にまとめて取得する手法です．これにより，データベースへのアクセス回数を大幅に削減して，システムのレスポンス時間を短縮します．

pythonのフレームワークとしてよく利用されているsqlalchemyでは，joinedloadを使用して，アニメテーブルをクエリする際に，関連する筆者情報を事前にロード（Eager Loading）します．これによって，各「アニメ」に対して個別に「筆者」をロードする必要がなくなり，N+1問題を回避できます．

```Python
from sqlalchemy.orm import sessionmaker, joinedload

# データベースエンジンを設定（ここではSQLiteメモリ内データベースを使用）
engine = create_engine('sqlite:///:memory:', echo=True)
Base.metadata.create_all(engine)

# セッションを作成
Session = sessionmaker(bind=engine)
session = Session()

# Eager Loadingを使って、Bookとそれに関連するUser情報をロード
animes_with_users = session.query(Anime).options(joinedload(Anime.user)).all()

for anime in animes_with_users:
    print(f"Anime: {anime.title}, Borrowed by: {anime.user.name}")
```

## 最後に
最後まで読んでいただきありがとうございました．

N+1問題を解決する手段として，生のSQLを利用する場合はJOIN句，ORMを利用する際にはEager loadを利用することがよいでしょう．
rluaを利用する 2024

# 情報が少なめ
自由度の高いコンフィギュレーションを可能にするだとか、独自のファンタジーコンソールで張り合うとかもろもろ考えられると思いますが、コンパイルしないと結果を変更できないのは小回りも利かず不便なこともありますね？ rluaで自由を手に入れましょう。

## 対象 version
rlua 0.20.0
rustc 1.75.0

## 基本の基本

```Cargo add rlua``` でCrateを追加。

```rs
use rlua::Lua;

fn main() {

    // rluaの初期化
    let lua = Lua::new();
    
    // luaとrustのやり取りをするインターフェイス的なものを取得
    let globals = lua.globals();

    // lua側に値を渡す
    globals.set("name", "Taro").unwrap();

    // luaスクリプトの実行をする。
    lua.load(r#"
        print("Hello, "..name);
        ans = 123;
    "#).exec().unwrap();

    // lua側の変数から値を取得して表示
    let ans: i32 = globals.get("ans").unwrap();
    println!("{}", ans);
}
```

簡単なやり取りはこのような感じ。
これでRustとlua間で値のやり取りとかが出来ます。

Rust側からluaに値を渡すときはあまり意識しなくても大丈夫なのですが、luaからRustに値を取り出す際には型指定が必須ですので注意が必要です。

Stringやi32などなどの変数でやり取りも良いのですがHashMapとTableのやりとりが抜群に便利なのでポイントかと思います。

```rs
use std::collections::HashMap;

let mut my_hashmap: HashMap<&str, &str> = HashMap::new();
my_hashmap.insert("Country", "Japan");
my_hashmap.insert("City", "Tokyo");
globals.set("my_table", my_hashmap).unwrap();
```

このようにRust側から値を送り込んで以下のようにlua側で利用が可能です。

```lua
print(my_table["Country"].." / "..my_table["City"]);
```

## luaから呼べるRustの関数をつくる

こんな風にしてluaから呼べる関数を作ることができます。

```rs
let hello_func = lua.create_function(|_, _:()| {
  println!("Hello!");
  Ok(())
}).unwrap();
globals.set("hello", hello_func).unwrap();
```

luaから関数を呼ぶことが出来るようになっているのを確認します。

```lua
hello();
```

create_functionは無名関数として定義します。
引数がない場合はこうですが、引数がある場合は、例えば```(i32, String)```だった場合は```(|_, (index, text): (i32, String)| { }```のように定義します。
何にしても無名関数なので困ったことがあったら「Rust 無名関数」などと探せばヒントがあるはず。

## 日本語で困る

lua側で日本語を表示すると文字化けしたりします。
テーブルのキー名、値に日本語データ（もちろんUTF8限定）を使うことは可能だし、文字列操作した変数をRust側で引き出して利用するのは全く問題ないのでlua側で日本語を表示したいなどの要求がある場合は注意。

※2024/02/27追記
わたしが文字化けに悩まされていたのはWindowsのPowerShell環境。
***コントロールパネル＞地域＞管理＞システムロケールの変更*** から
「ベータ：ワールドワイド言語サポートでUnicode UTF-8を使用」にチェックし、Windowsの再起動後PowerShell上でLua側の表示を文字化けせず表示させることが出来ました。

## lua側で定義していない変数をRust側で引いた場合

エラーです。
でもそれだと困るので、次のようにしてエラーハンドリングを行います。
*※普通のRustのエラーハンドリングです。*

```rs
let my_value: Result<String, rlua::Error> = globals.get("value");
match my_value {
    Ok(v) => println!("{}", v),
    Err(e) => println!("Error: {}", e),
}
```

このように受けとることでlua側にない変数を引いた際、或いは別の問題があった場合にエラー処理が可能となります。

## 〆

最後に、本当に簡単にrluaの現在の使い方について触れてみましたが、本当に本当に簡単にしか触れておらず不足もあるかと思いますが何かしらの足がかりになればと思います。

個人的にはデータ変換ツールのコンフィギュレーションにluaが使えれば便利だろうなと思い調べたところネット上でのrluaの解説が古いことに気づいてこれを書くに至りました。
backwardのエラー

# backwardでエラーが発生
GANについてこの参考書をもとに勉強していたところ、エラーが発生。
解決に２日かかったので、記録として残します。
結論は、初心者にとって勝手な変更は厳禁ですね。

参考書
GANディープラーニング実装ハンドブック

https://www.amazon.co.jp/GAN%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%A9%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0%E5%AE%9F%E8%A3%85%E3%83%8F%E3%83%B3%E3%83%89%E3%83%96%E3%83%83%E3%82%AF-%E6%AF%9B%E5%88%A9%E6%8B%93%E4%B9%9F/dp/4798062294

# エラー内容
GANの学習中にbackwardで逆伝播させるときにエラーが発生
```
例外が発生しました: RuntimeError
one of the variables needed for gradient computation has been modified by an inplace operation
```
参考書の通りに実施したのになぜと思っていた。。。
この逆伝播の時に発生
```python
loss.bakward()
```
エラー内容は「PyTorchでの計算グラフ内の変数がインプレース（その場での変更）操作によって変更されたことが原因」のようで、このbackwardで更新される以外に、勝手にversionが書き変わってて、変数を変更していませんか？って事らしい

エラー全体はこんな感じ
```
例外が発生しました: RuntimeError
one of the variables needed for gradient computation has been modified by an inplace operation: 
[MPSFloatType [1, 1024, 1, 1]] is at version 3; expected version 2 instead. Hint: the backtrace further above shows the operation that failed to compute its gradient. 
The variable in question was changed in there or anywhere later. Good luck!
  File "/Users/sm/VScode/EfficientGAN/main.py", line 233, in <module>
    loss_ge.backward(retain_graph = True)
```

# エラー原因
エラー原因はシンプルでした。
GeneratorとEncoderのlossの計算のときにDiscriminatorの損失計算と逆伝播で使用したp-trueをそのまま使っていたこと。そのため、loss_geのbackwardを計算するときに、すでにloss_dで損失の更新がなされてしまっていたので、loss_geのbackwardでのエラーとなった。

エラー発生コード（一部省略・変更）

```python
        # discriminatorの学習
        optimizer_d.zero_grad()

        E_x = model_Encode(x)
        # 識別器からp_trueを取得
        p_true, _ = model_Discriminate(x + noise1, E_x)
        # （中略）
        loss_d = criterion(p_true, y_true)
        #ここで逆電波して識別器の学習をしている
        loss_d.backward(retain_graph = True)
        optimizer_d.step()

        # generatorとencoderの学習
        optimizer_ge.zero_grad()

        G_E_x = model_Generate(E_x)
        E_G_z = model_Encode(G_z) 

        # p_trueをもう一度取得　これを削除していたためエラーの原因となった
        p_true, _ = model_Discriminate(x + noise1, E_x)

        loss_ge = criterion(p_true, y_fake)
        # （中略）
        # このbackwardでエラー発生
        loss_ge.backward(retain_graph = True)
        optimizer_ge.step()
```
AWS ALBからのリクエストだけ許可したい場合のEC2に設定するセキュリティグループのインバウンドルールの設定

## 概要

下記のような構成の場合、星1と星2の部分にセキュリティグループを設定することが一般的である。

![Cursor_と_work__Visual_Workspace_for_Innovation.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/824187d9-06da-5578-2cea-c1d33b70e15c.png)

この場合、言わずもがなプライベートサブネット内部のEC2にはALBを通して接続してほしい。（ブラウザからのアクセスの場合）
その要望に答えるには星2のセキュリティグループを設定して「ALBからのインバウンドルールのみ許可」してあげれば良い。

「ALBからのインバウンドルールのみ許可」について　簡単にまとめる。

## 方法

実は非常に簡単である。
「星2のセキュリティグループのインバウンドルールのHTTPSの設定のソース（リクエスト送信元）を星1のセキュリティグループに設定する」だけである。

参考文献でも紹介されているのでぜひご確認いただきたい。

## 参考文献

https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/security-group-rules.html#security-group-referencing

![「セキュリティグループのルール」_-_Amazon_Virtual_Private_Cloud.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/891588ae-876b-89e4-12fc-ad2e6d70b3a5.png)

https://ramble.impl.co.jp/4018/#toc9
FluttrerにおけるHiveの使い方

Hiveって？
-----
ローカルの保存領域においてデータベースを使用するためのライブラリ（パッケージ）。

パッケージのインストール
----
FlutterにおいてHiveを使用するには下記のパッケージを使用します。

https://pub.dev/packages/hive

ターミナルにて下記のコマンドを入力
```dart
flutter pub add hive
```

```dart
flutter pub get
```
pubspec.yamlの中に下記が追加される。
  
```dart
hive: ^2.2.1
```

下準備
---
まず初めにmain関数内にてhiveの初期化を行う。
```dart
void main() async {
  await Hive.initFlutter();
  runApp(const MyApp());
}
```

今回はユーザーの個人情報を保存する例で説明する。
まず初めにユーザーの情報を取り扱うモデルを作成する。

まずはユーザー情報を取り扱うためのモデルファイル
**user_info.dart**
```dart
import 'package:hive/hive.dart';

//Entity生成用
part 'user_info.g.dart';

//モデルごとの識別子の設定
@HiveType(typeId: 1)
class UserInfo {
  const UserInfo({
    this.name,
    this.birthday,
  });
//typeId:1に保存されるデータのプロパティ番号0
  @HiveField(0)
  final String name;
//typeId:1に保存されるデータのプロパティ番号1
  @HiveField(1)
  final DateTime birthday;
}
```

- Adapterを作成する
以下のコマンドでAdapterを自動生成してもらう。
```dart
$ flutter pub run build_runner build
```

次に，モデルオブジェクトをバイナリ形式に変換して取り扱うためのTypeAdapterを使用するために**main.dart**内で下記の関数を呼ぶ
```dart
Hive.registerAdapter(UserInfoAdapter());
```

使用方法
----
- 保存と読み込み
```dart
final userInfo = UserInfo('OREO', DateTime(1998, 11, 10, 12, 10);)
final box = await Hive.openBox<UserInfo>('userInfo');

//Hiveへ保存
box.add(userInfo);

//読み込み
final userInfos = box.values.toList();

```
2回目のチーム開発に関する記事


## 概要説明


アプレンティスシップにて、2回目のチーム開発に取り組みました。


## 反省

全員で、具体的な目標を定量的に設定すれば良かった。

また、自分自身Onlyで、

・人の言うことを聞くこと
・プロフェッショナル意識を持つこと
・自己改革を目指すこと

この３つをできていなかった反省と捉えて、改善していきたい

詳細については、別記事で超詳しく書いています（おそらく今の時点では、プライベート記事になっている）。


## KPT

今回のチームプロジェクトに対する、

keep（よくできていたこと：継続したいこと）、
problem（問題だと思うこと：改善したいこと）、
try（やれなかったこと：挑戦してどうなるか確認してみたいこと）


### K：keep

・できるできないにかかわらず、素直に意見を出し合って、チーム開発を進めていけた。
・わからないなりにも、スケジュールを立てて、視覚にも落とせた状態で進行できた。

### P：problem

・技術が間に合っていなかった、技術をしっかり把握できてない状態で、実装に入らなくてはならなかった。

### T：try

・もっと素直に遠慮せずに意見を発し、1人も妥協せずに、全員が同意してから次のステップに進める（なあなあにしない）
ssh接続時に鍵交換アルゴリズムのネゴシエーションに失敗したときの対処法

# 本記事の対象となるエラー
検証環境のNW機器にSSHログインを試行したところ、クライアント側で以下のエラーが出力された。

```
# ssh xxxx@x.x.x.x
Unable to negotiate with x.x.x.x port 22: no matching key exchange method found. Their offer: diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1
```

SSHサーバとなるNW機器が古い鍵交換アルゴリズムにしか対応しておらず、接続に失敗していることがわかる。

# 解決
-o オプションで鍵交換アルゴリズムを追加してやることで解決した。
```
# ssh -o KexAlgorithms=+diffie-hellman-group-exchange-sha1 xxxx@x.x.x.x
```

configファイルを作成している場合は以下のように記載する。
``` ~/.ssh/config
HOST hoge
HOSTNAME x.x.x.x
USER hoge
KexAlgorithms diffie-hellman-group-exchange-sha1
```

# 注意点
今回は個人的な検証環境なので問題なかったが、セキュリティ的によろしくはない。
【GPTs】Canva


![IMG_8809.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136275/fb6108e3-638f-0698-4615-3e170f543088.jpeg)

# あなたは何ができますか？

と、聞いてみた。以下回答。

> Hello! Excited to bring your visions to life? Start your creative journey with Canva. What will we design together today? I can assist you in generating design ideas for a wide range of needs, including but not limited to posters, social media posts, invitations, and more. Share the essence of the design you wish to create or the message you'd like to convey. Whether you have a specific occasion in mind or just a general concept, I'm here to help bring your ideas to life using Canva's user-friendly design platform. How can I assist you today?

↓翻訳

> こんにちは！あなたのビジョンを実現することにわくわくしていますか？Canvaでクリエイティブな旅を始めましょう。今日は一緒に何をデザインしましょうか？ポスター、ソーシャルメディアの投稿、招待状など、さまざまなニーズに合わせたデザインアイデアを生成するお手伝いができます。作成したいデザインの本質や伝えたいメッセージを共有してください。特定の機会があるのか、または一般的なコンセプトのみかにかかわらず、Canvaのユーザーフレンドリーなデザインプラットフォームを使用して、あなたのアイデアを実現するお手伝いをします。今日はどのようにお手伝いしましょうか？

# 使ってみた

## 誕生日のお祝いメッセージ画像

![IMG_8810.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136275/bb3f049d-23f6-1f02-db6e-810997d42375.jpeg)

左上の画像をクリックすると、Canvaが開かれ、編集できる！

![IMG_8811.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136275/1d53d0c5-815e-9ad4-9e08-fe7c58836993.png)