OmniAICreator/Qiita-1.07M huggingface dataset:
[Flutter] FittedBoxについて理解を深めてみる

![NewGradsAdventCalendar_2023.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672609/03c9f37d-7a68-6d27-1953-b169535e1e38.png)


この記事は、<b>株式会社ゆめみの23卒 Advent Calendar 2023</b>のアドベントカレンダーになります！！
色々な種類の記事が投稿されるので、お楽しみに🤗

https://qiita.com/advent-calendar/2023/yumemi-23-graduation

# 本編

こんにちわ、いせりゅーです。

今回は、FlutterKaigiのカンファレンスウェブサイトを作成していたときに知った`FittedBox`について記載していこうと思います〜！

# FittedBoxとは

https://api.flutter.dev/flutter/widgets/FittedBox-class.html

↑こちらを参考にしています。

<b>FittedBox</b>・・・Scales and positions its child within itself according to fit.（fitに従ってその子のサイズを調整し、その子をその中に配置する）


これらを自分なりに解釈してみると


- 子ウィジェットが与えられた親のスペースに合うようにする。
- 可能な限り大きく表示できる
- オーバーフローすることなく、可能な限り大きく表示できる

# 使うといい例

- 画像を画面に合わせて拡大・縮小する
- 異なる画面サイズでテキストが切れないようにする
- アイコンをボタンなどの中で適切にフィットさせる

コードの例は公式のドキュメントから参考にし、自分なりに記載を行ってみました。


```dart
class FittedBoxExample extends StatelessWidget {
  const FittedBoxExample({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('FittedBox Sample')),
        body: Center(
          child: Container(
            height: 400,
            width: 300,
            color: Colors.blue,
            child: const FittedBox(
              fit: BoxFit.fill,
              child: Placeholder(),
            ),
          ),
        ),
      ),
    );
  }
}

```

画像としては以下の通りになります。


<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672609/60c59c04-552f-fa35-e735-9b8425bbf3b3.png">


# 最後に
実は知らなかったWidgetでした。まだまだ知らない世界があるのだなと学ぶことができました。
もっと知って、アウトプットしてWidgetマスターになりたいなと思いました。頑張ります🔥
どっちの超解像でショー？　RealESRGANとSwinIRの画質および速度比較

# どっちがいいの？
画像をスケールアップしてくっきりさせてくれるリアル超解像モデル。
超解像モデルって、どれがいいか難しいですよね。
わりにポピュラーな以下の二つを比較してみました。

**RealESRGAN**

https://github.com/xinntao/Real-ESRGAN

**SwinIR**

https://github.com/JingyunLiang/SwinIR.git

どっちもいいモデルですが。

# 比較

RealESRGAN_x4plusとSwinIR-M_x4_GANの比較です。

### 64×64 → 256×256
入力
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/1b177016-a767-7b42-835f-bfe283304595.jpeg width=256>
RealESRGAN:0.04秒
![ore64_out.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/8cddea6a-bb73-43df-99a9-4b18fc059018.jpeg)
SwinIR:0.11秒
![ore64_SwinIR.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/1b014c5e-2563-63ff-b32c-4eb45fc3d0a4.png)

### 128×128 → 512×512
入力
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/3d9347cc-6d69-5c56-c8c2-be6284ee269c.jpeg width=512>

RealESRGAN:0.08秒
![ore128_out.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/aa3db6cc-74f2-6de9-b2e2-d83fa4714e67.jpeg)
SwinIR:0.31秒
![ore128_SwinIR.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/fe76aeff-f879-d2c8-c5c6-751a19241de3.png)

### 256×256 → 1024×1024
入力
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/6617daa7-f75e-89c0-6f10-ad8f3e73e717.jpeg width=1024>
RealESRGAN:0.35秒
![ore256_out.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/f5ab6be6-159e-297c-779a-a90365300c57.jpeg)
SwinIR:1.28秒
![ore256_SwinIR.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/c950b07b-3ef9-0805-620e-965ff5bccb5b.png)

### 512×512 → 2048×2048
入力
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/4c3d45fa-4945-5820-0453-aba10bd45a8d.jpeg width=2048>
RealESRGAN:1.44秒
![ore512_out.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/38efc04c-40ac-1dba-d95b-3b0d442634fc.jpeg)
SwinIR:6.28秒
![ore512_SwinIR.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/1ff44fed-f92c-70b5-59b9-ab730e7823ff.png)

# 結果
**速度では、RealESRGAN が SwinIR の3~5倍速く
画質は長短あり甲乙つけがたいですが、SwinIR の方がくっきりさせる傾向がある（良かれ悪しかれ）と思いました。**

# 実行スクリプト

RealESRGAN

```shell
python inference_realesrgan.py -n RealESRGAN_x4plus -i input --outscale 4
```

SwinIR

```shell
python main_test_swinir.py --task real_sr --scale 4 --model_path model_zoo/003_realSR_BSRGAN_DFO_s64w8_SwinIR-M_x4_GAN.pth --folder_lq input
```
AI-102試験対策のまとめ「Azure AI Servicesの診断ログ有効化」

## はじめに
Azure AI Engineer Associate(AI-102)取得に向けた勉強でまとめた内容を本記事では投稿しています。
試験範囲の内容を私が勉強していく中で、
・忘れてしまっていた内容
・他の知識と絡めて理解した方が良い内容
・Microsoft Learnの読解に苦戦した内容
などをできるだけ分かりやすく簡潔にまとめることを意識しています。
Azureの勉強を一から始め、AI-102取得を目指している方の参考になれば幸いです。
※本記事の内容が必ず試験に出るわけではないこと、ご注意ください
※勉強しながら投稿しているため、追加で学んだことがあれば随時投稿内容を更新します。

## 試験対策のまとめ
### Azure AI Servicesの診断ログ有効化
前提：ログデータを格納する場所が必要  
※下記の手順ではAzure Storageを使用

1. Azure PortalでAzure AI Servicesリソースを選択
1. 左側「監視」から「診断設定」を選択
1. 「+ Add diagnostic setting(+ 診断設定の追加)」を選択
1. 設定の名前を入力
1. 「ストレージアカウントへのアーカイブ」および「Log Analytics」への送信を選択
1. 診断ログを格納するストレージアカウントとOMSワークスペースを選択  
    ※それらがない場合はプロンプトに従って作成
1. 「Audit」「RequestResponse」「AllMetrics」を選択
1. 診断ログデータの保持期間を設定(0の場合は無期限に格納)
1. 「保存」を選択  
    ※ログデータがクエリや分析に使用できるようになるまで最大2時間かかる

* 参考
    - https://learn.microsoft.com/ja-jp/azure/ai-services/diagnostic-logging

## 次の試験対策のまとめ
* **AI-102試験対策のまとめ「検索インデックスの作成」**

https://qiita.com/fsd-jume/items/f7bb1168f96333e430c5

## 学習内容をまとめたページの一覧

https://qiita.com/fsd-jume/items/65aba5d5514e023fd66d
OpenAI GPT-4V の API を使って画像を AI に説明させよう！

[OpenAI DevDay](https://openai.com/blog/new-models-and-developer-products-announced-at-devday) で多くの発表があった。

その中の一つに、 GPT に画像を読み込ませてなんらかテキストで応えてもらう GPT-4V の API 利用ができるようになったことがある。

ChatGPT ではできてたことだけど、満を持して API で使えるようになった。

早速それを試す。

# インプットする画像

猫が食洗機の中に入り込んだ画像ついて説明してもらう。ファイル名は `bad_cat.jpg`

![IMG_1136.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285861/5cdae11f-ffd6-5437-9df3-bb29cc60e87a.jpeg)


# コード


まず openai のライブラリをインストールする。すでにインストールしている人はアップデートしたほうがよいかも。

```
pip install openai
```

以下はコード。

ポイントは、画像を base64 でエンコードして、その文字列を送る、ということ。

```python
# %%
import base64

from openai import OpenAI


# 画像をbase64にエンコードする関数
def encode_image(image_path):
    with open(image_path, "rb") as image_file:
        return base64.b64encode(image_file.read()).decode("utf-8")


# 画像のパス
image_path = "./bad_cat.jpg"

# 画像をbase64にエンコードする
base64_image = encode_image(image_path)

# OpenAI APIのクライアントを作成する.
# YOUR_API_KEYには、OpenAI の API キーを入力する
client = OpenAI(
    api_key="YOUR_API_KEY",
)

# チャットの応答を生成する
response = client.chat.completions.create(
    # model の名前は gpt-4-vision-previewが使えなくなったので、以下に変更.
    model="gpt-4o-mini",
    messages=[
        {
            "role": "user",
            "content": [
                {"type": "text", "text": "何が起きてる？"},  # ここに質問を書く
                {"type": "image_url", "image_url":{"url": f"data:image/jpeg;base64,{base64_image}"}},  # 画像の指定の仕方がちょい複雑
            ],
        }
    ],
    max_tokens=300,
)

# 応答を表示する
print(response.choices[0])
```

# 回答

```
Choice(finish_reason=None, index=0, message=ChatCompletionMessage(content='写真には食器洗い機の中に入っている猫が映っています。洗うべき食器の代わりに、猫が食器用ラックの中に快適に収まっている様子です。これは家庭において猫が好奇心旺盛で狭い空間に入ることを好む傾向を示す典型的な例です。面白くて可愛らしい瞬間を捉えていますが、もし食器洗い機を使いたい場合は、猫を安全に移動させてから始める必要があります。', role='assistant', function_call=None, tool_calls=None), finish_details={'type': 'stop', 'stop': '
'})
```

> 写真には食器洗い機の中に入っている猫が映っています。洗うべき食器の代わりに、猫が食器用ラックの中に快適に収まっている様子です。これは家庭において猫が好奇心旺盛で狭い空間に入ることを好む傾向を示す典型的な例です。面白くて可愛らしい瞬間を捉えていますが、もし食器洗い機を使いたい場合は、猫を安全に移動させてから始める必要があります。

いいね。

# 参考

* https://platform.openai.com/docs/guides/vision
LWC コンポーネントのオプション




# lightning-tree-grid 

+ [LWCのTreegridにハイパーリンクを設定した数式項目をを表示したい](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007OYdIz)

URL のラベル

```
typeAttributes: { label: 'View', name: 'view' }
```

別Windowに遷移する

```
typeAttributes: {label: { fieldName: 'Invoice_Number__c' }, target: '_top'}},
```

+ [LWCのコードを簡略化させたい](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007Pw8Gk)
+ [親から孫までの関係を持ったデータを「子から親を辿る形」で取得するSOQL](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007OYdRw)

下方向へは１階層しか検索できないので、クエリーは分けざるを得ないと思います。

まずは１階層と2階層目の関係をList変数に取得します。

LIST<A> = [SELECT Id, (SELECT Id FROM B) FROM A];
それから、for文でこのlist変数をループさせて、2階層目のIdを取得してSet変数に保存します。

 次にSet変数に一致する２階層目とその下の３階層目を検索します。

LIST<B> = [SELECT Id, (SELECT Id FROM C) FROM B WHERE Id =: SetBId];
ここでもforでループさせて検索結果を　Map(Id,List<C>) の変数に格納します。

こうすることで、MapにBのIdを与えれば、その下のCをList変数の形で参照できます。


ここまで準備しておいて、またList<A>をforでループさせて、
BのIdを取得します。ここで、先程のMap変数を使ってCの情報を取得できます。
このループでJsonを組み立てていけば、欲しい形のフォーマットになるのではと思います。

ただ、あんまりレコードが多いと制限に抵触するかもしれません。

+ [LWCで作成したTreeGridで　タブからタブに遷移する際にパラメータを持たせたい](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007PwboV)
+ [親から孫までの関係を持ったデータを「子から親を辿る形」で取得するSOQL](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007OYdRw)
+ [LWCのTreegridにハイパーリンクを設定した数式項目をを表示したい](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007OYdIz)
+ [リンク項目の色を変える](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007RKAPM)
+ [lightning-datatableタグ内にSOQLで検索した親レコードの情報を出力したい。](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007UvnmS)

:::note
一番簡単な方法は　BオブジェクトにA__r.Nameの数式項目を作ることだと思います。

 

別の方法としては以下のようにList<Map<String,Object>>の変数を使って、値をセットすれば自由に何でも指定できます。この変数をlightning-datatableに渡せば表示できると思います。

```Java
List<Map<String,Object>> myDataList = new List<Map<String,Object>>();
for (fkd_Property__c myRecord : myPropertyList) {

      Map<String, Object> myMap = new Map<String, Object>();        	
      myMap.put('Id',myRecord.Id);   
      myMap.put('submission_name__c',myRecord.customer_id__r.customer_code__c + ':' + myRecord.customer_id__r.Name);   
      myDataList.add(myMap);
}
```
OpenAIDevDay2023 最新アップデート(概要)

# はじめに
OpenAIは、開発者向けイベント「OpenAIDevDay2023」において、GPT-4 TurboをはじめとするAIモデルの進化に関する幅広いアップデートを発表しました。最新の技術革新により、AIの応用範囲が拡大し、より高度なカスタマイズや統合が可能になります。ここでは、その主要なアップデート内容を要約してお届けします。
詳細且つ正確な情報は[OpenAI公式発表](https://openai.com/blog/new-models-and-developer-products-announced-at-devday)からご確認いただけます。

# OpenAIDevDay2023まとめ

## GPT-4 Turbo 128K

### GPT-4 Turboの新機能
- 128Kのコンテキストウィンドウで300ページ以上のテキストを扱う能力
- 2023年4月までの世界の出来事を知識に含む
- GPT-4に比べて入力トークンが3倍、出力トークンが2倍安くなった
- 全ての支払い開発者がプレビュー版を試すことが可能
- 安定した製品版のリリースは数週間以内に予定

## Function callingのアップデート
- 複数のFunctionを一つのメッセージで呼び出すことが可能
- 高精度なFunction callingで正しいパラメーターを返す

## 命令認識(?)とJSONモードの改善
- フォーマットが指定された指示において、以前のモデルよりも性能が向上(「XMLで応答せよ」など)
- 新しいJSONモードは、モデルが有効なJSONを応答することを保証

## 再現可能な出力と対数確率
- 新しいシードパラメーターにより、モデルが一貫した出力を返す(デバッグに嬉しい)
- GPT-4 TurboとGPT-3.5 Turboは、生成されたトークンの対数確率を返す機能を近々提供開始

## GPT-3.5 Turboのアップデート
- デフォルトで16Kのコンテキストウィンドウをサポート
- 改善された指示フォローアップ、JSONモード、並列Function calling(JSON、XML、YAMLの生成等)
- 古くなるモデルにも引き続きアクセス可能

## アシスタントAPI、リトリーバル、コードインタープリター
- Assistants APIのリリースにより特定目的のAI構築を支援
- コードインタープリターでサンドボックス環境内のコード実行
- リトリーバル機能による外部知識の統合と活用
- Function callingによりカスタム機能の組み込みを実現
- Assistants APIによりアプリ内で特化したAIエージェント体験を提供
- Assistantsプレイグラウンドでのベータ版APIのコードレス体験提供

## APIの新しいモダリティ
### GPT-4 Turboとビジョン
- 画像を入力として受け入れ、キャプション生成や詳細な画像分析などのユースケースを可能に
- 1080×1080ピクセルの画像で$0.00765のコスト

### DALL·E 3
- アプリや製品に直接統合可能なDALL·E 3をImages APIを通じて利用可能に

### テキストから音声へ（TTS）
- 新しいTTSモデルで、テキストから人間のような音声を生成

## モデルカスタマイズ
### GPT-4ファインチューニング実験的アクセス
- GPT-4ファインチューニングへの実験的アクセスプログラムを開始
- GPT-3.5でファインチューニングを行っている人に積極的にアクセス権付与

### カスタムモデル
- ファインチューニング以上のパラメータチューニングサービスを提供
- 最低でも数十億トークンという非常に大規模な独自データセットを持つドメインに適用可能
- 特定のドメインに特化したカスタムGPT-4モデルのトレーニングをサポート

## 価格の低下とレート制限の増加
### 低価格化の概要
- GPT-4 Turbo: 入力トークンが0.01ドル、出力トークンが0.03ドルで提供。
- GPT-3.5 Turbo: 入力0.001ドル、出力0.002ドルと大幅値下げ。
- Finetuned GPT-3.5: 入力0.003ドル、出力0.006ドルに設定。

### レート制限の増加
- GPT-4の顧客向けにトークン毎分の制限を倍増

## 著作権シールド
- 著作権侵害に関する法的な請求に直面した場合に、顧客を守るための「著作権シールド」の導入
- 著作権侵害に関する法的請求にユーザがさらされた場合、OpenAIがユーザを保護・費用を支払う

## Whisper v3と一貫性デコーダー
- Whisper large-v3のリリース
- Stable Diffusion VAEデコーダーのオープンソース化

## GPTストアの展開
- 一般にGPTの作成と共有が可能に
- 今月後半には、検証済みビルダーの作品を集めたするGPTストアが登場予定
- ストア内でGPTは検索可能になり、ランキングも閲覧可能
- 「生産性」「教育」「エンタメ」などのカテゴリでランキングされる
- 今後数ヶ月で、使用者数に基づいた収益化も提供予定
Java 21 (OpenJDK, Eclipse Temurin) を Homebrew で macOS にインストールする

## 概要

- Java 21 (Eclipse Temurin 21) を Homebrew で macOS にインストールする。

## 今回の環境

- macOS Ventura 13.5.2

## インストール

```
$ brew tap homebrew/cask-versions
$ brew install --cask temurin21
```

## java_home コマンドでインストールされたディレクトリの場所を確認

```
$ /usr/libexec/java_home -v 21
/Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home
```

## 環境変数 JAVA_HOME と PATH を設定

環境変数 JAVA_HOME と PATH を設定する。

```
$ export JAVA_HOME=/Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home
$ PATH=${JAVA_HOME}/bin:${PATH}
```

これらは必要に応じて .zprofile や .zshrc などにも記述する。

## インストールした Eclipse Temurin を確認

```
$ java -version
openjdk version "21.0.1" 2023-10-17 LTS
OpenJDK Runtime Environment Temurin-21.0.1+12 (build 21.0.1+12-LTS)
OpenJDK 64-Bit Server VM Temurin-21.0.1+12 (build 21.0.1+12-LTS, mixed mode)

$ javac -version
javac 21.0.1

$ which java
/Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home/bin/java

$ which javac
/Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home/bin/javac

$ ls /Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home/bin
jar         javap       jdeps       jlink       jrunscript  jwebserver
jarsigner   jcmd        jfr         jmap        jshell      keytool
java        jconsole    jhsdb       jmod        jstack      rmiregistry
javac       jdb         jimage      jpackage    jstat       serialver
javadoc     jdeprscan   jinfo       jps         jstatd
```

## 参考資料

- [Eclipse Temurin \| Adoptium](https://adoptium.net/temurin/)
- [homebrew\-cask\-versions/Casks/temurin21\.rb at master · Homebrew/homebrew\-cask\-versions · GitHub](https://github.com/Homebrew/homebrew-cask-versions/blob/master/Casks/temurin21.rb)
- [GitHub \- AdoptOpenJDK/homebrew\-openjdk: AdoptOpenJDK HomeBrew Tap](https://github.com/AdoptOpenJDK/homebrew-openjdk)
- [Java 17 \(OpenJDK: Eclipse Temurin\) を Homebrew で macOS にインストールする \#Java \- Qiita](https://qiita.com/niwasawa/items/d6f33a278b7d087dfb2c)
【OCI クラウド移行ガイド】 AWS Lambda を OCI Functionsへ移行してみた（その2:S3 put編）

前回のHello World編はこちら。
https://qiita.com/araidon/items/6ae7067efe92ecaec776

# OCIクラウド移行ガイドとは

オンプレミスやAWSなど、複数のプラットフォームからOracle Cloud Infrastructureへの移行プロジェクトに取り組んでいるクラウドエンジニア（@araidon,@kazunishi,@yama6）による、OCI移行手順をまとめたシリーズ記事です。
各回、サンプルワークロードから対象サービスを取り上げ、移行手順をガイドいたします。
まとめ記事は以下になります。

https://qiita.com/yama6/items/b197c0fe3ec75eb02637

# 移行するサービス：AWS Lambda

今回、移行対象とするのはAWS Lambdaです。

AWS LambdaでInputの画像ファイルをS3へputするソースコードを、OCI FunctionsでObject Storageへputするソースコードに書き換えてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276568/487e7338-c95d-7834-8b56-f149647cc1a7.png)


# OCI Functionsとは
一言でいうと、OCIでのFaaSサービスです。
いわゆるサーバレスサービスで、AWS Lambda、Azure Functions、Google Cloud Functions等と同等のサービスです。

AWS Lambdaと比較して、価格面で優位となっているようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276568/17439df8-faea-79f7-bcba-f2b6b1d207aa.png)

https://speakerdeck.com/oracle4engineer/functions-overview


# 前提条件
- 言語はPythonとします
- AWS LambdaとOCI Functionsの環境構築について、今回は触れません。

# それぞれのインフラごとの違い
## AWS
AWSのサービスを扱うために、AWS SDK for PythonことBoto3を使用します。

https://aws.amazon.com/jp/sdk-for-python/

```python: (AWS)Boto3 S3へのput
# ライブラリをインポート
import Boto3

# S3 バケット名
S3_BUCKET = '<保存先バケット名を指定>'

# ハンドラ
def lambda_handler(event, context):
    #画像データの取得
    image_data = event['body']  # eventの構造に応じて適切なフィールドを指定
    
    # S3を扱う
    s3 = boto3.resource('s3')
    file_name = '<ファイル名を指定>'  # S3に保存するファイル名を指定
    bucket = s3.Bucket( <BUCKET_NAME> )

    # S3にputするコマンド
    s3.put_object(
        Bucket=S3_BUCKET,
        Key=file_name,
        Body=image_data
    )

```

## OCI
OCIのサービスを扱うために、boto3ではなく、Oracle Cloud Infrastructure SDK for Pythonこと oci を使用します。

https://docs.oracle.com/ja-jp/iaas/Content/API/SDKDocs/pythonsdk.htm

```python: (OCI)OCI Object Storageへのput
# ライブラリをインポート
import oci
import io # <- 画像データの取得に必要

# OS(Object Storage) バケット名
OS_BUCKET = '<保存先バケット名を指定>' 
NAME_SPACE = '<アカウントのnamespaceを指定>'

# ハンドラ
def handler(ctx, data: io.BytesIO=None):
    #画像データの取得
    image_data = io.BytesIO(data)  # リクエストdataの構造に応じて適切なフィールドを指定
    
    # Object Storageを扱う
    signer = oci.auth.signers.get_resource_principals_signer()
    object_storage = oci.object_storage.ObjectStorageClient(config={}, signer=signer)
    file_name = '<ファイル名を指定>'  # Object Storageに保存するファイル名を指定
    
    # Object Storageにputするコマンド
    object_storage.put_object(
        namespace=NAME_SPACE,
        bucket_name=OS_BUCKET,
        object_name=file_name,
        put_object_body=image_data
    )

```

# まとめ
利用するSDKが違うのと、対象サービスが違うため、元のソースコードが小さい場合は全面的に書き換えが必要でした。
とはいえ、SDKのImport、サービスのObjectの取得、引数の指定という一連の流れなので、それほど難しいものではありません。

次回は、DynamoDBと連携したLambdaを OCI Functionsに書き換えてみたいと思います。

# 参考

https://speakerdeck.com/oracle4engineer/functions-overview

https://docs.oracle.com/ja-jp/iaas/Content/API/SDKDocs/pythonsdk.htm
【Vue.js】キー修飾子で特定のキー押下時にイベントを発生させる

# はじめに
よくあるEnterキーで入力確定する方法を探していたら、キー修飾子があったので軽くまとめる。

# キー修飾子とは
特定のキーを押された場合に、指定したイベントが発火する。
そして、v-on:clickなどのイベントにドット（.）でつなげることができる。

### right
右クリック押下時にaddイベント発生。
```ruby:HTML
<button @click.right="add">Add</button>
```

### left

左クリック押下時にaddイベント発生。
```ruby:HTML
<button @click.left="add">Add</button>
```

### enter
inputの入力欄を選択しながら、エンターキー押下時にenterイベント発生。
```ruby:HTML
 <input type="text" @input="setName" v-on:keyup.enter="enter" :value="name"> 
```

# おわりに
他にも使ったキー修飾子が出てきたら、随時追加予定。

# 参考
https://qiita.com/Yudai_35_/items/02e6c08f9df43643b6f9
https://qiita.com/hidache/items/a3ac85c7e0cba4978cf8
Vueの勉強で活用中⇒https://www.udemy.com/course/vuejs-2-the-complete-guide/
log4j2でDEBUGとERRORを分けて出力する

Log4j2を使用してDEBUG レベルのログと ERROR レベルのログを別々のファイルに出力するには、以下のステップに従います。

1. Log4j2の設定ファイルを開いて編集します。これは通常、XMLまたはプロパティフォーマットで提供されます。

2. 設定ファイル内で、2つの別々のAppender（ファイル出力先）を定義します。例えば、`DEBUG` レベルのログ用に `DebugAppender` と `ERROR` レベルのログ用に `ErrorAppender` を作成します。以下はXML形式の例です。

```xml
<Loggers>
    <Logger name="com.example.myapp" level="DEBUG">
        <AppenderRef ref="DebugAppender" />
    </Logger>
    <Logger name="com.example.myapp" level="ERROR">
        <AppenderRef ref="ErrorAppender" />
    </Logger>
    <Root level="ERROR">
        <AppenderRef ref="ErrorAppender" />
    </Root>
</Loggers>

<Appenders>
    <RollingFile name="DebugAppender" fileName="logs/debug.log">
        <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
        <!-- その他の設定 -->
    </RollingFile>
    <RollingFile name="ErrorAppender" fileName="logs/error.log">
        <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
        <!-- その他の設定 -->
    </RollingFile>
</Appenders>
```

上記の設定では、`DebugAppender` は `DEBUG` レベルのログメッセージを `logs/debug.log` ファイルに出力し、`ErrorAppender` は `ERROR` レベルのログメッセージを `logs/error.log` ファイルに出力します。それ以外のログメッセージは `ErrorAppender` を使用して `logs/error.log` に出力されます。

3. 必要に応じて、他の設定を調整し、ファイルのローテーションやファイルサイズ制限などの設定を追加できます。

この方法を使用すると、DEBUG レベルと ERROR レベルのログを別々のファイルに出力できます。各 Appender は対応するログレベルのメッセージのみを処理します。
資格勉強にBingチャットがめちゃ使える件

タイトルの通り、資格勉強にBingチャットがめちゃ使えるという件です。

# 使い方
Bingを開くと上に「チャット」を表示されているのでこれを開きます。
![BingAI.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368850/c9a5f4d3-0643-a602-7064-53187a0ce5e1.png)
# 使用例
![ACL.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368850/854807af-5175-85fd-abd3-bd7442a28ef2.png)
![grep.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368850/35bcbb86-35ec-d08f-5398-91597c60ffd6.png)
質問をすると、**簡潔にかつ分かりやすく参照付き**で答えてくれます!!!

たまに間違った答えを返すこともありますが、許容範囲ということで・・・
wslでelixir その96

# 概要
wsl(wsl2じゃない)で、elixirやってみた。
練習問題、やってみた。

# 練習問題
Kino.Control.buttonで、じゃんけんを書け。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/4510ba53-aefd-c6ee-493e-747967a3613b.png)


# サンプルコード

```
button0 = Kino.Control.button("gu")
```

```
button1 = Kino.Control.button("choki")
```

```
button2 = Kino.Control.button("par")
```

```
Kino.Control.subscribe(button0, :gu)
Kino.Control.subscribe(button1, :choki)
Kino.Control.subscribe(button2, :par)
```

```
widget = Kino.Frame.new()
```

```
loop = fn f ->
	receive do
		{:gu, _} ->
      res = Janken.pon("0")
			Kino.Frame.append(widget, res)
		{:choki, _} ->
      res = Janken.pon("1")
			Kino.Frame.append(widget, res)
		{:par, _} ->
      res = Janken.pon("2")
			Kino.Frame.append(widget, res)
		_ -> 
			:ok
	end
end

loop.(loop)

```

以上。
ドットアイテムのデータ構造を考える1(仕様)


x カラー液晶は、 ST7789 ST7789V2 ATM0130B3 の事

目的
SRAMの少ない、小マイコンでカラー文字等を表示させる
為のドットアイテムのデータ構造

初期値は、全てffH
書きこみ後はインクリメント

![o_cop757.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/f64b37e0-1fa0-86f5-d91b-1d221d456960.jpeg)
log4j2で出力ファイル名に時分秒を設定する

Log4j2を使用している場合、ファイル名に時分秒を含めるためには、Log4j2の設定ファイルを調整する必要があります。以下はLog4j2の設定ファイルを使用した方法です。

1. Log4j2の設定ファイルを作成または編集します。通常、Log4j2の設定ファイルはXMLまたはプロパティ形式で提供されます。以下の例は、XML形式の設定ファイルを示しています。

```xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <RollingFile name="FILE" fileName="logs/application.log" filePattern="logs/application-%d{yyyyMMdd-HHmmss}.log">
            <PatternLayout pattern="%d{yyyyMMdd-HHmmss} %c{1} - %m%n" />
            <Policies>
                <SizeBasedTriggeringPolicy size="1 MB" />
            </Policies>
            <DefaultRolloverStrategy max="5" />
        </RollingFile>
    </Appenders>
    <Loggers>
        <Root level="info">
            <AppenderRef ref="FILE" />
        </Root>
    </Loggers>
</Configuration>
```

2. 上記の例では、`filePattern`属性を使用してファイル名のパターンを指定しています。`%d{yyyyMMdd-HHmmss}`は日付と時刻を含むファイル名のパターンです。また、`<PatternLayout>`要素内でログメッセージのフォーマットを指定します。

3. 設定ファイルで定義したAppender（ログの出力先）の設定に、ファイル名パターンが含まれています。この例では`<RollingFile name="FILE" fileName="logs/application.log" filePattern="logs/application-%d{yyyyMMdd-HHmmss}.log">`でファイル名を指定しています。

4. この設定ファイルをアプリケーションに読み込むようにコードを設定し、Log4j2を初期化します。これにより、ログメッセージは指定されたフォーマットのファイル名で保存されます。

これでLog4j2を使用してファイル名に時分秒を含めることができます。ログファイルは新しいファイル名でローテートされ、必要に応じて古いログファイルを保持できます。設定ファイルをアプリケーションの要件に合わせてカスタマイズすることができます。
wslでelixir その95 

# 概要
wsl(wsl2じゃない)で、elixirやってみた。
練習問題、やってみた。

# 練習問題
kinoで、じゃんけんを書け。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/964048cb-fcc7-aeb3-9f6a-134926fa16bf.png)

# サンプルコード

```
frame2 = Kino.Frame.new()
```

```
inputs2 = [	te: Kino.Input.text("Anata")]
form2 = Kino.Control.form(inputs2, submit: "Send", reset_on_submit: [:te])

```

```
defmodule Janken do
	def hand(c) do
		cond do
		c == 0 ->
			"グー"
		c == 1 ->
			"チョキ"
		c == 2 ->
			"パー"
		:else ->
			"うそ"
		end
	end
	def judge(a, b) do
		cond do
		a == b ->
			"あいこ"
		a == 0 && b == 1 ->
			"あなたの勝ち"
		a == 1 && b == 2 ->
			"あなたの勝ち"
		a == 2 && b == 0 ->
			"あなたの勝ち"
		a == 0 && b == 2 ->
			"あなたの負け"
		a == 1 && b == 0 ->
			"あなたの負け"
		a == 2 && b == 1 ->
			"あなたの負け"
		end
	end
	def pon(a) do
		res = ""
		{a, _} = a
			|> Integer.parse()
		res = res <> hand(a) <> "と"
		b = 0..2 
			|> Enum.random
		res = res <> hand(b) <> "で、"
		res = res <> judge(a, b)
		res
	end
end

Kino.listen(form2, fn %{data: %{te: te}, origin: origin} ->
  res = Janken.pon(te)
	content = Kino.Markdown.new(res)
	Kino.Frame.append(frame2, content)    
end)

```


以上。
[ここまで進化したChagGPT！] 今日から何がどう変わるのか [2023年11月最新版]

皆さん初めましてこんにちはこんばんは。スウェーデン在住のエンジニア、Harry(ハリー: https://twitter.com/harrythecode )と申します。

普段はDevOpsエンジニアとして働く傍ら、生成AIの最前線にも繰り出し、ToBやToC向けのアプリケーション開発などにフルスタックエンジニアとして携わっています。

2023年11月7日 日本時間午前3時より、ChatGPTの生みの親、OpenAI社のサム・オルトマンによる講演が行われました。

https://www.youtube.com/watch?v=U9mJuUkhUzk

この中で、多くの人が待ち望んだ様々な機能の実装や改善が行われています。

読むのが辛いよ、って方は以下の一言まとめをどうぞ。

https://twitter.com/harrythecode/status/1721602057411654012

また今回の発表によって何が新しくなって、今後どう変わっていくのか、を現役エンジニア目線でご紹介します。では見ていきましょう。

## 何が新しいん？

1. **GPT-4 Turboの発表**: 
   - **コンテキスト長の拡張**: 128,000トークンまで対応可能に。
   - **対数確率の表示**: APIを通じて対数確率を確認できるようになる機能を提供。
   - **世界知識の向上**: 外部のドキュメントやデータベースからの情報を取り入れることができる「retrieval」機能(通用RAG)をプラットフォームに追加。
   - **カスタムモデル**: 特定の企業や用途に特化したカスタムモデルを作成するためのサポートを提供。

2. **音声とビジョンの機能**: 
   - **音声生成**: テキストから自然に聞こえるオーディオを生成することができ、APIで6つのプリセットボイスから選択することが可能。

3. **価格の削減**: GPT-4 Turboは改善されたモデルでありながら、GPT-4の半額近い価格帯に。

4. **GPTsの導入**: 
   - **自分だけのGPTエージェントが作れちゃう**: プロンプトやドキュメントをアップロードすることでカスタムAIを作成でき、これはプライベート、会社、または公開設定で利用可能。

5. **開発者向けの改善**: 
   - **サンドボックス環境**: 安全なテストとプロトタイピングのためのサンドボックス環境が提供される。
   - **機能呼び出しの改善**: デベロッパーがアプリケーション内でより効率的にAIアシスタントと対話できるように機能呼び出し機能が改善された。

6. **GPT Storeの立ち上げ**: 
   - 人々が自分のGPTを作成し、他の人が使用できるように公開するためのGPT Storeが紹介された。
   - **収益分配**: 最も有用でよく使われるGPTを作成した人々には、OpenAIの収益の一部が支払われる。

7. **デモンストレーション**:
   - チャットアプリのデモでは、ユーザーのメッセージをスレッドに追加し、AIアシスタントがリアルタイムで返答を行う様子が示されました。
   - 音声認識アプリのデモでは、音声入力をリアルタイムでテキストに変換し、そのテキストを使用してAIアシスタントが返答する様子が示された。

上記の他にもDalle-3, GPT-4V, リアルタイム音声読み上げのWhisper v3の紹介などがありました。

## で、結局何が起きるん？

ボクの目からは大きく以下の３つの変化が起こると考えてます。

1. GPTsによる、社内専用GPTの開発加速 / GPTボットインフルエンサーの増加
2. Dalle-3/GPT-4VのAPI公開による、写真を読み込んで色々解析する系の案件増加
3. プロンプトエンジニアリングの需要が高まる

では順に見ていきます。

### GPTsによる、社内専用GPTの開発加速 / GPTボットインフルエンサーの増加

「GPTs」を一言で言うと、自分の持っている各種ファイルをGPTに覚えさせて、それをもとにAIに回答してもらう、と言うものです。

要はノウハウをより簡単に、個人、会社、全世界の３つのレベルで共有することが可能になります。

社内のナレッジデータベースとAIを繋いでチャットボットができちゃうんですから驚きです。

これが「プログラミング知識なし」で作れると言うから更に驚きです。また、GPTボットを全世界に公開して、それの収益をシェアすると言うモデルも追加されるためGPTボットインフルエンサーが増えることが予想されます。

### Dalle-3/GPT-4VのAPI公開による、写真を読み込んで色々解析する系の案件増加

今までChatGPTは文字だけしか取り扱うことができなかったのですが、今後は「目」と「声」を手に入れました。

これの活用道としては、例えばアナログで図面を読んで色々やってた作業をAIに任せたり、だとかデザイナーに頼んで画像とかグッズとかそう言うのを頼んでたけど自分で簡単に作れるアプリケーションの開発だとか、これはどちらかと言うと開発者にとって嬉しい機能ですね。

この手の案件も水面下では多く発生することでしょう。

### プロンプトエンジニアリングの需要が高まる

ChatGPTを使ってみて多くの人がぶち当たる壁が「こいつ言うこと全然聞かないぞ」問題です。これはトークン数が増えれば増えるほど、より顕著になっていきます。

要はたくさんのことを覚えることができると言っても、その中からあなたが求めている答えを探し出すためには「新人に仕事を教えるのと同様に1から10まで細かな指示を出す」必要があります。

これを広く一般には「プロンプトエンジニアリング」と呼ばれています。こちらの専門スキルを持った人がより需要が高まっていき、AI人材の確保に色んな会社が追われることになっていきます。

## 最後に

いかがでしたでしょうか。今回の発表は今後大きな流れを作っていくような、重要な機能の発表であったりもします。

ただChatGPTが表に出てから開発を続けてる身として思うのは「どんなに黄金を掘り出せるツール」を手に入れたからとして、その使い方を知らないとかなり損する、と言うことです。

AIが発展しても、それを使いやすくするためのノウハウは実践の中でしか生まれません。

「AIを使って新しいことを始めたい」だったり「こんなこと、あんなことができないかな」と気になる方はぜひお気軽にDMください :)
Djangoの学習⑤（投票フォームの作成）

引き続きWeb投票アプリケーションの開発を行います。

## 簡単なフォームを書く

投票詳細テンプレート ("polls/detail.html") を更新して、HTML の <form> 要素を入れましょう。


```html:polls/templates/polls/detail.html

<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
<fieldset>
    <legend><h1>{{ question.question_text }}</h1></legend>
    {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
    {% for choice in question.choice_set.all %}
        <input type="radio" name="choice" id="choice{{ forloop.couter }}" value="{{ choice.id }}">
        <label for="choice{{ forloop.couter }}">{{ choice.choice_text }}</label><br>
    {% endfor %}
</fieldset>
<input type="submit" value="Vote">
</form>
```

・上のテンプレートは、各質問の選択肢のラジオボタンが表示するものです。

・value は、関連する質問の選択肢のIDです。

・フォームを送信すると、POSTデータ choice=# （＃は選んだ選択肢のID）が送信されます。

・forloop.counter は、 for タグのループが何度実行されたかを表す値です。


voteビューを追記します。

```python:polls/views.py

# ...
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from .models import Choice, Question

# ...
def vote(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    try:
        selected_choice = question.choice_set.get(pk=request.POST["choice"])
    except(KeyError, Choice.DoesNotExist):
        return render(
            request,
            "polls/detail.html",
            {
                "question": question,
                "error_message": "You didn't select a choice.",
            },
        )
    else:
        selected_choice.votes += 1
        selected_choice.save()
        return HttpResponseRedirect(reverse("polls:results", args=(question_id,)))

```


先頭小文字のquestionと先頭大文字のQuestionが混在しているコードなので注意が必要です。
私は先頭小文字のところを大文字にしてしまい
UnboundLocalErrorが発生して、ちょっと苦しみました


誰かが質問の投票すると、 
vote() ビューは質問の結果ページにリダイレクトします。このビューを書きましょう

```python:polls/views.py

def results(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, "polls/results.html", {"question": question})

```

polls/results.html テンプレートを作成します


```html:polls/templates/polls/results.html

<h1>{{ question.question_text }}</h1>

<ul>
{% for choice in question.choice_set.all %}
    <li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes |pluralize }}</li>
{% endfor %}
</ul>

<a href="{% url 'polls:detail' question.id %}">Vote again?</a>


```


ブラウザで /polls/1/ を表示して投票してみましょう。
票を入れるたびに、結果のページが更新されていることがわかるはずです。
選択肢を選ばずにフォームを送信すると、エラーメッセージを表示されるはずです。

:::note warn
※投票してリダイレクトされたページに、正しい結果が表示されず
以前作成したビューの表示がされてしまう場合は、ブラウザのキャッシュを削除してください。
:::
MikuMikuDanceが急に文字化けするようになって困った。

このように文字化けした.（何もしていないのに壊れた？）
何故文字化けしたか探すのに苦戦したので一応記事を書きました。
![文字化け.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3581833/cad17d9a-f1da-24ce-b304-c7d7c0c9ed7c.png)


結論からいうと、文字コードがShift-jisのファイルをUTF-8で開くようになっているからです。
　
Windows10のUTF8化(ベータ機能)をオフにすると直りました。（Windows11がでてもベータ機能のままという危ないものらしい）
　
これがオンになるのは、私の場合、Windowsの言語設定を日本以外のものにしたからということでした。
試しに7zip.exeでShift-JISを指定してファイルを展開すると、文字化けしません。(MMD等の一部のアプリだけ、文字化けするらしい)
以下7zipでShift-JISを指定して展開する方法(下の方法で解決できなかった時の無理やり解決策)
[7zipでshift-jisを指定して展開する方法](https://qiita.com/DaikichiDaze/items/4754352da1652d03dc85 "[7zip]日本語版Windowsで圧縮されたzipファイルを文字化けせずに解凍する方法")

　
つまり、Windowsの既定の文字コードがUTF-8になっていて、文字化けしています。

以下、既定の文字コードを変更する方法です
 
Windowsの設定(歯車)をおして、時刻と言語をクリック
![システム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3581833/8703a1ee-03ec-d4a3-18b8-c16a067238ab.png)
 
地域をクリックして、日付、時刻、地域の追加設定をクリック
![地域.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3581833/0281a392-2a2d-a45e-22a9-3cf3f138815a.png)
 
そして、地域をクリック
![追加設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3581833/423dc67f-ba70-500e-d9ff-2059b7b7864b.png)
 
管理のタブを押して、システムロケールの変更を押す。
![管理.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3581833/cca7a156-e886-11c6-96fe-47c129f1da3c.png)
 
ここ、ベータの所にチェックを入れずにオッケーを入れる。ベータにチェックが入っていなければ、別の問題かも。OKを押すと再起動するか聞かれるので作業中のものは保存しておく。
![システムロケールの変更.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3581833/3b3c6ff9-c5f9-6ded-5866-0ea79e1ecc33.png)

再起動すると、元に戻った。
![スクリーンショット 2023-11-07 041308.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3581833/58181962-544e-3fdf-2be0-5fece7a83067.png)

私はチェックを変えずにひたすら言語や地域設定を変更して、再起動を繰り返していました。
かなり苦しんだので、初記事となりました。

7zipで文字コードがShift-JISで開けていないことに気づいて、Windowsの既定の設定がおかしくなってると思い、Windows10 utf8 ShiftJISで検索をかけて当たりました。"mmd"で検索したのがミスでした。ここらへんは文字コードの知識ですね。

以下に同じ文字コードを変える手段ですが、mmdで調べるとでてこないので、記事にしました
[既定の文字コードを変更する方法](https://togeonet.co.jp/post-13850)
あと、どうやらShift_JISと　Shift-JIS(SJIS)は違うそうです。基本的にShift-JISの方が新しく文字の数も多いので、まあこちらの方だろうと後者の方で書きました。
2023/11/7主にITとかセキュリティの記事

シスコ製品に続出する脆弱性、多数のセキュリティアドバイザリ発行(11/5)
https://news.mynavi.jp/techplus/article/20231105-2810614/

Apache ActiveMQに緊急の脆弱性、速やかにアップデートを(11/5)
https://news.mynavi.jp/techplus/article/20231105-2809632/

上海でビザ申請が通らないケースが多発、日本旅行できず―中国メディア(11/4)
https://nordot.app/1093447224988188787

中央銀行デジタル通貨（CBDC」の世界的進展と二極化の現状(11/5)
https://zuuonline.com/archives/268900

中東のサイバー攻防激化　ガザ情勢受けて欧米や日本にも飛び火(11/5)
https://www.sankei.com/article/20231105-IZ2HIDNUBFMQNIHEILXBSSF45Q/

中東の混乱、真の問題は「宗教」ではない...サイバー戦争を軸に「地政学」の全貌を読み解く(11/4)
https://www.newsweekjapan.jp/kumar/2023/11/post-3.php

｢世界一の富豪｣がウクライナを救った…プーチン得意の｢情報工作｣がまったく機能しなかったワケ【2023編集部セレクション】(11/4)
https://president.jp/articles/-/75488

サイバー特許、トップ10に中国勢6社　ファーウェイなど(11/4)
https://www.nikkei.com/article/DGXZQOUC049D30U3A001C2000000/?n_cid=BPRDS001

さよなら「VBScript」、日経BPの雑誌バックナンバーに見るその実像(11/6)
https://xtech.nikkei.com/atcl/nxt/column/18/00682/103100137/

独SAPと米オラクルの戦略は対照的、ERPベンダー間で本格化する生成AI競争(11/6)
https://xtech.nikkei.com/atcl/nxt/column/18/02625/103000002/

SAFe（Scaled Agile Framework）(11/6)
https://xtech.nikkei.com/atcl/nxt/mag/nc/18/020600009/103000154/

変わる「問い合わせ」　生成AIで人間らしく(11/6)
https://xtech.nikkei.com/atcl/nxt/mag/nc/18/020600014/103100160/

IT子会社はDX戦略の蚊帳の外　「忘れられた存在」でよいのか(11/6)
https://xtech.nikkei.com/atcl/nxt/mag/nc/18/020600007/103100153/
M5StackのUnit Encoderのファームウェア・アップデート

# はじめに
<img width="360" alt="UnitEncoder1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3569302/d752bc0c-94a7-4669-0256-c723d09ac2a1.jpeg">

M5StackにI2Cで接続して使うUnit Encoderを入手しました。

[商品ページ](https://docs.m5stack.com/en/unit/encoder)によると、どうやらファームウェアを書き換えることができるとあります。それならばと書き換えてにチャレンジしてみました。


https://ssci.to/7987

# ファームウェア

[GitHub](https://github.com/m5stack/M5UnitEncoder_Firmware)に、説明とバイナリファイルがおいてあります。基本的にこのとおり進めていきました。I2Cプロトコルマップをみると、MODEとRESETが追加されているとあります。カウンターの値を書き込めるのが、地味に嬉しい追加機能です。

[V1.1のファームウェア](https://github.com/m5stack/M5UnitEncoder_Firmware/blob/main/M5UnitEncoder_Firmware_v1.1.hex)をダウンロードします。


https://github.com/m5stack/M5UnitEncoder_Firmware

# Unit Encoder分解

分解といってもネジひとつはずすだけです。基板にSTM32F030が実装されています。写真上部のスルーホールがフラッシュするためのピンに繋がっているので、ここにライターを接続します。

<img width="540" alt="UnitEncoder2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3569302/680d3a3d-9ac1-94ae-f28b-d014826aabfe.jpeg">

# ライター

本来であればSTMicroelectronics社のSTLINKを使って書き換えます。まあまあの値段でして、私は所有していません。そこでどうするかというと、安いコンパチのSTLINK/V2を使用します。数百円程度で手に入ります。

<img width="360" alt="UnitEncoder3" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3569302/28a95516-ef2d-159f-0c52-243d63e31f1f.jpeg">

検索したら、いろいろなところで売ってますね。信頼できるのかどうかはご自身で判断してください。

* https://www.amazon.co.jp/dp/B07JKZ4FKX
* https://ja.aliexpress.com/item/1005004997698975.html

# フラッシュ

フラッシュには[STM32CubeProg](https://www.st.com/ja/development-tools/stm32cubeprog.html)が必要です。STLINKとUnit Encoderを表を参考に繋いでください。まちがえて3.3Vを5Vにしがちですので注意しましょう。

| STLINK   | Encoder |
|:---------|:-------:|
|(1) RST   | R       |
|(2) SWCLK | C       |
|(4) SWDIO | D       |
|(6) GND   | G       |
|(8) 3.3V  | V       |

ジャンパーワイヤーを使いますが、スルーホールにはんだ付けはしたくありません。バラバラのワイヤーをまとめるため、ピンソケットに挿してまとめました。マスキングテープで留めてもいいかもしれません。

<img width="360" alt="UnitEncoder4" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3569302/f9ffa9de-675b-387c-890c-894ea9b48057.jpeg">

気合で手でおさえます。このままGitHubの説明に従ってSTM32CubeProgで書き込みます。

<img width="360" alt="UnitEncoder5" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3569302/e2536503-a8ee-0305-7e3a-09073a79e83e.jpeg">

基板を手でおさえながら、STLINKをPCに接続し、アプリを操作してフラッシュ。これがなかなかうまくいかず、10回目くらいで成功しました😅

# I2Cレジスタマップ

GitHubの説明にひとつだけ追加しています。それはRGBのLED NUMを0にすると、２つのLEDをまとめてセットできます。exampleのソースコードには書いてあるのに、なぜかドキュメントには書いてありません。

| OPERATION     | REG MAP | 0 | 1 | 2 | 3 |
|:--------------|:-------:|:--------|:--------|:-------|:--------|
| MODE (W)      | 0x00    | 0=PULSE<br>1=AB | | | |
| COUNTER (R/W) | 0x01    | COUNTER VALUE<br>L | <br>H | |
| SWITCH (R)    | 0x02    | SWITCH<br>0 or 1 | | | |
| RGB (W)       | 0x03    | LED NUM<br>0, 1, 2 | R | G | B |
| RESET         | 0x04    | 1 >= RESET<br>COUNTER | | | |
CMakeでクワイン

# コード
```cmake:quine.cmake
set(s [[message("set(s [[${s}]" "])\n${s}")]])
message("set(s [[${s}]" "])\n${s}")
```

# 検証
```sh
cmake -P quine.cmake > output.cmake 2>&1
diff quine.cmake output.cmake
if [ $? -eq 0 ] ; then
  echo "It's a quine."
else
  echo "It's not a quine."
fi
```
【GAS】スプレットシートの全シート名を一括変更

# ケース1

別のスプレットシートからコピーしたシートの「 のコピー」を一括削除したい。

### GAS

```js
function removeCopySuffixFromSheetNames() {

    // スプレットシートの全シート
    const sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets()
    
    for (const sheet of sheets) {
        // 現在のシート名
        var sheetName = sheet.getSheetName()
        // 新しいシート名
        var newSheetName = sheetName.replace(" のコピー", "")
        // 新しいシート名に変更
        sheet.setName(newSheetName)
    }
}
```

### 実行結果

**実行前**

```
スプシ1 のコピー / スプシ2 のコピー / スプシ3 のコピー
```

**実行後**

```
スプシ1 / スプシ2 / スプシ3
```

# ケース2

全てのシート名の先頭に文字列を追加したい！！

### GAS

```js
function renameAllSheetsWithPrefix() {

    // スプレットシートの全シート
    const sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets()
    
    for (const sheet of sheets) {
        // 現在のシート名
        var sheetName = sheet.getSheetName()
        // 新しいシート名
        var newSheetName = "【新】".concat(sheetName)
        // 新しいシート名に変更
        sheet.setName(newSheetName)
    }
}
```

### 実行結果

**実行前**

```
シート1 / シート2 / シート3
```

**実行後**

```
【新】シート1 / 【新】シート2 / 【新】シート3
```
Laravel でTarget class [MainController] does not exist.　のエラーが出た。

 原因はズバリ、、、
 ```
 Route::post('/testform', 'MainController@write1');
 ```
 ルーティングを完全に就職する必要があった。
 ```
 Route::post('/testform', 'App\Http\Controllers\MainController@write1');
 ```
 これで解決した。
Poetry+pyenv環境で自作のライブラリをimportしようとして詰まった

# 自作のパッケージを認識してくれない

こういう構造のディレクトリでの話
```
work_dir
├── pyproject.toml
├── src
│   └── my_package
│       ├── __init__.py
│       └── my_module.py
└── work.py
```
`work_dir`内の`work.py`で`src/my_package`以下にある自作パッケージを以下のように利用しようとしたら怒られた
```python work.py
import sys 
sys.path.append("path/to/src")

from my_package import my_module
```

# 解決策
`pyproject.toml`に以下の内容を書き込んであげる
```toml
[tool.poetry]
packages = [
    { include = "my_module", from = "src" },
]
```
`poetry install`を忘れずに
```bash
$ poetry install
```
これでPoetry環境で自作のパッケージを利用できた。

O'reillyの著書に付随したGithubのコードを流用した時にこれが起きた。`sys.path.append`でライブラリを認識させる方法はそもそも修正コストがめちゃ大きいのであまり良くないらしい。
# 参考
- [sys.path.append() を使わないでください](https://qiita.com/siida36/items/b171922546e65b868679)
- [pyproject.tomlファイル](https://cocoatomo.github.io/poetry-ja/pyproject/)
Reactアプリ100本ノックを実践する 〜01 Hello World〜

# はじめに
こちらの記事は、@Sicut_studyさんがアップしている【Reactアプリ100本ノック】シリーズに相乗りし、アウトプットを行うための記事になります。
- 実装ルールや成果物の達成条件は元記事に従うものとします。
- 元記事との差別点として、具体的に自分がどんな実装を行ったのか（と必要に応じて解説）を記載します。

@Sicut_studyさんのノック100本についていき、Reactを100日間学ぶのが目標です。

今回の元記事はこちら

https://qiita.com/Sicut_study/items/3c5cd798313854a471a0

# 問題
"Hello World" React コンポーネントの作成

## ルール
**元記事より引用**
- 主要なライブラリやフレームワークはReactである必要がありますが、その他のツールやライブラリ（例: Redux, Next.js, Styled Componentsなど）を組み合わせて使用することは自由
- TypeScriptを利用する

## 達成条件
**元記事より引用**
1. Reactの新しいプロジェクトが正しくセットアップされていること。
2. 画面に"Hello World"というテキストが中央に表示されていること。

# 実装

```bash
npx create-react-app my-hello-world-app --template typescript
cd my-hello-world-app
```
でプロジェクトを作成＆移動。

```bash
npm install @emotion/react @emotion/styled
```
で`Emotion`を入れ、レイアウトの実装準備（普通にcssファイルで実装しても良いかと思います）。

後はApp.tsxに実装して完了。
```typescript:src/App.tsx
/** @jsxImportSource @emotion/react */
import styled from "@emotion/styled";
import React from "react";

// スタイルの定義
const AppWrapper = styled.div`
  text-align: center;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
`;

const HelloWorld = styled.p`
  font-size: 2rem;
  color: blue;
`;

const App = () => {
  return (
    <AppWrapper>
      <HelloWorld>Hello World</HelloWorld>
    </AppWrapper>
  );
};

export default App;

```

あるいは、こんな風に書いてもいいと思います。

```typescript:src/App.tsx
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';
import React from 'react';

// スタイルの定義
const appStyle = css`
  text-align: center;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
`;

const textStyle = css`
  font-size: 2rem;
  color: blue;
`;

const App = () => {
  return (
    <div css={appStyle}>
      <p css={textStyle}>Hello World</p>
    </div>
  );
}

export default App;

```

# 完成

```
npm start
```
で画面を確認します。

![完成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267522/0de17e82-49f9-52f8-1646-eb6a0d334c90.png)

良さそうですね。

# 最後に
Reactアプリ100本ノックを100回分完走するつもりです。
応援してくれる方はぜひフォローいただけると嬉しいです。
いいね、ストックもお待ちしております。

ではまた。

# 次回の記事

https://qiita.com/jinto/items/df4145b4ed79e81d3590
QNAP NASサーバーにTailscale入れてみる

## 前書き
別記事でガッツリと前書き書いたので省略します。無料インターネット回線に備えてです。**Tailscale**が簡単過ぎてあんまり書くこと無いんですが自分用メモ帳に備忘録を書いてたんで折角ならこっちにも載せようかと。

## 前提
- QNAP NASサーバー上に導入

## 0\. やりたいこと／目標
- ポート開放無しにVPNサーバーを用意する
- VPNノード同士だけじゃなくLAN内の資産にアクセスしたい
- VPN GWみたいに外に出ていくのもそのNWからにしよう
![tailscale-overview.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537256/ee1f45e3-498a-2f35-5082-6947d207547b.png)
こんな感じ？Subnet routesでLAN内の資産にアクセスして、Exit nodeを設定するとQNAP NASと同じNWから外に出ていくので。自信は無いです。

## 1\. QNAP NASにTailscaleを導入
予めTailscaleの管理画面にログインしておくとデバイス登録が楽です。App Centerにあるモノはバージョンが古かったのでレポジトリから直接入手しています。
```テキスト:pkgs.tailscale.com
https://pkgs.tailscale.com/stable/#qpkgs
```
インストール後、アプリを起動するとGUIでTailscaleへと画面転送され登録できます。


## 2\. Tailscaleの設定
GUI上の設定だけでは動かないのでパッケージの場所を調べてCUIで設定していきます[^1]。QNAPサーバーへとSSHでログインして下さい。
```テキスト:パッケージの場所を調べ移動
getcfg SHARE_DEF defVolMP -f /etc/config/def_share.info
cd /share/CE_CACHEDEV1_DATA/.qpkg/Tailscale/
```
```テキスト:Tailscaleの設定
./tailscale up --advertise-exit-node --accept-routes --advertise-routes=192.168.0.0/16
```

## 3\. Tailscale管理画面上の設定
Tailscaleの管理画面にログインすると登録したクライアントが表示されます。右側の３点リーダー（設定アイコン）を押し、[Edit route settings]から**Subnet routes**と**Exit node**のオンオフを設定可能です。
![tailscale-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537256/5b53f22d-ec8f-35e3-8038-fa50431aa786.jpeg)
![tailscale-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537256/bb90645c-3e2f-42fe-c2ca-d618ce09a9ff.jpeg)

## 4\. 動作確認
いつも動作画面を載せているので大したものじゃないですが一応…。Exit nodeを使うかどうかも選べます。
![IMG_3041.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537256/89a3079e-256b-eee5-58b8-0fbb0bfce091.png)

## 後書き
便利と噂のTailscaleを使ってみましたが本当に使い易いです。Subnet routesって何ぞやと最初は思いましたが分かれば設定も簡単で便利な機能でした。

[^1]:　[tailscale続報　QNAPで動かす＆ACLでアクセス制御する＆インターネット接続暗号化](https://internet.watch.impress.co.jp/docs/column/shimizu/1313903.html)
今日が休みかどうか見極めてみた

平日だけ◯◯◯◯したい・・・みたいなことがあったのですが
意外とまとまった記事が見つからなかったのでまとめました。

# 検証環境
WindowsからSSH接続した Mac Pro

# nkfコマンドをインストールする
```
brew install nkf
```

# cronを設定する

月曜〜金曜に「祝日かどうかをチェックするシェル」が実行されるよう設定する
```
0 10 * * 1-5 /bin/sh  check_syukujitsu.sh
```

# 祝日かどうかをチェックするシェルの中身

```check_syukujitsu.sh
#!/bin/sh

curl -o holidays.csv "https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv"

# 改行コードをLFに変更する
nkf -Lu --overwrite holidays.csv

# 現在が祝日ではなければ workday
if ! grep -q `date "+%Y/%-m/%-d"`, "holidays.csv"; then echo "workday"; fi
```

# 文字コードと改行コードの変更が必要

curl で落とした csvファイルの文字コードが `UTF-8` ではない（`Shift_JIS` のためか）、grep でうまく判定できませんでした。

以下のコマンドで文字コードを変更しました。
```
nkf -w --overwrite holidays.csv
```

ところが、これだけでは判定できませんでした。

ハッ..！改行コードも変えないといけないのでは？と思い
以下の通り、改行コードを `LF` へ変換すると、判定できるようになりました。
```
nkf -Lu --overwrite holidays.csv
```
このコマンドを実行するだけで文字コードも `UTF-8` に変換してくれるので、
結果的に上記コマンドのみに置き換えました。
プロジェクト内のソースコードの行数TOP10を調べる

# はじめに
ソフトウェア開発において、ソースコードの行数はメンテナンス性と品質向上に関連する重要な要素です。大規模で複雑なプロジェクトにおいて、巨大なソースコードは問題を引き起こす可能性が高まります。この記事では、ソースコードの行数を調べるためのコマンドと実行結果を紹介します。

# コマンド

以下は、appディレクトリ内の行数が多い上位10ファイルを表示するコマンドです。

```shell
find ./app -type f -exec wc -l {} \; | sort -nr | head -n 10
```

# 結果例

以下は、著者がLaravelを使って個人開発したソースコードの結果です。もし、1000行以上のファイルがたくさん表示された場合はプロジェクトが複雑である可能性が高いので気合で頑張ってください。

```shell
206 ./Http/Controllers/Api/RankingController.php
114 ./Models/Post.php
102 ./Http/Controllers/PostController.php
101 ./Http/Requests/PostStoreRequest.php
96 ./Http/Requests/PostUpdateRequest.php
94 ./Usecases/Post/StoreAction.php
85 ./Http/Requests/Auth/LoginRequest.php
73 ./Utils/ResponseUtil.php
69 ./Usecases/Post/ShowAction.php
67 ./Http/Kernel.php
```

# おわりに

本記事では行数を調べる方法を紹介しましたが、ソースコードの行数はエンジニアがプロジェクトを選ぶ際にも有用となる情報のひとつです。面談でこういう情報を聞いてみるのもいいかもしれません。
形式記述言語VDM++の制御構文（コメント文）をJava C# Re:Mind(自作言語)と比較

# はじめに

要求仕様記述段階での使用が主に想定されている数学的形式手法VDM(Vienna Development Method)[^1]のオブジェクト指向拡張言語VDM++ですが、ロジックの実装も記述できる構文が用意されています。本記事ではVDM++の制御構文（コメント文）をJavaとC#そして自作言語のRe:Mind[^2] と比較してみます。

## この記事内容の作業目的
VDM++の下記の制御構文[^3][^4]についていくつかの記事に分割して比較検討します。クラスの定義構文についてはこちらの記事[^5]を参照することができます。

・ブロック文
・代入文
・条件文
・ループ文
・call文
・return文
・**コメント文**　←本記事対象
・例外

VDM++はオブジェクト指向言語的な言語要素を持ち、数学的形式手法言語の中では一般のプログラミング言語のオブジェクト指向言語に近い面があり開発者には比較的扱いやすいと言われています。

Re:MindはJavaやC#の経験者向けに設計された日本語プログラミング言語の一種で、自然言語の日本語で記述するよりは厳密で構造的な記述が可能です。ロジック仕様記述言語とトランスコンパイラ言語とで言語仕様を共有しています。ロジック仕様記述言語は疑似言語みたいなものですから、コンパイラを通さないことを前提にするならば未定義の関数を要件表記として使うこともできます。

VDMのような数学的形式手法を使わない場合は、一般的に自然言語の日本語で要求仕様が記述されているものと推察されます。本記事では数学的形式手法と自然言語の日本語記述とのはざまで、構造化された日本語プログラミング言語が要求仕様記述に使えないか模索しています。

## この記事内容の保証
各言語で書かれた引用ソースの妥当性は保証されません。また、本記事に開示された自作言語の仕様は、開発中の仕様のため予告なく変更される場合があります。

# 構文比較
## VDM++
```vdm:VDM++
    doAnything: () ==> ()
    doAnything() ==
    (
       -- todo1
       /* todo2
          todo3 
       */
    )
```
VDM++の単行コメント文はダブルハイフン--で開始、複数行コメント文は/* */で囲われた範囲となります。
## Java
```java:Java
    void doAnything()
    {
       //todo1
       /* todo2
          todo3 
       */
    }
```
Javaの単行コメント文はダブルスラッシュ//で開始、複数行コメント文は/* */で囲われた範囲となります。
## C#
```cs:C#
    void doAnything()
    {
       //todo1
       /* todo2
          todo3 
       */
    }
```
C#の単行コメント文はダブルスラッシュ//で開始、複数行コメント文は/* */で囲われた範囲となります。
```mind:Re:Mind
    ▽void doAnything()
       //todo1
       /* todo2
          todo3 
       */
    △
```
Re:Mindの単行コメント文はダブルスラッシュ//で開始、複数行コメント文は/* */で囲われた範囲となります。

# おわりに
VDM++のコメント文の書き方はリレーショナルデータベースの構造化照会言語SQLのようなイメージですね。
```sql:SQL
    SELECT
       ITEM1,
       ITEM2,
       -- todo1
       ITEM3
    FROM
       TABLE
    WHERE
       ITEM1=1
       /* todo2
          todo3 
       */
       AND ITEM2 IN (2,3)
    }
```




[^1]: IBMのウィーン研究所で1960年代から70年代にかけて開発された形式手法。その実装には1996年にISO標準（ISO_IEC_13817-1）となったVDM-SLと、そのオブジェクト指向拡張のVDM++がある。
[^2]: Qiita [オープンな設計言語仕様 日本語ロジック仕様記述言語 Re:Mind（リマインド）](https://qiita.com/mylifewithviolin/items/52f806777e6ea031de94) 参照
[^3]: FMVDM　[VDMTools 付属文書](http://fmvdm.org/doc/index-ja.h
[^4]: FMVDM-> github [[PDF] VDMTools VDM 言語マニュアル VDM++](https://github.com/vdmtools/vdmtools/raw/stable/doc-jp/lang-man/langmanpp_a4J.pdf)
[^5]: Qiita [要求仕様 形式記述言語VDM++ との構文比較 ロジック仕様記述言語 Re:Mind（リマインド）](https://qiita.com/mylifewithviolin/items/2a8c6dc66cead04536a8)
【Rails】cookieを設定する方法

以下のように記述するとcookieが設定できます。


```rb
cookies[:クッキー名] = { クッキーの設定 }
```

クッキーの設定には以下が使用できます。

| オプション | 説明 | デフォルト値 |
|   :-:   | :-: |    :-:    |
| :value  | cookieの値  | -  |
| :path  | cookieが有効なパス  | -  |
| :domain  | cookieが有効なドメイン  | 現在のホスト  |
| :expires  | cookieの有効期限  | /  |
| :secure  | 暗号化通信でのみcookieを送信  | false  |
| :httponly  | HTTPcookieを有効  | false  |

```rb
# cookieに保存
cookies[:sample] = "sample"

# httponlyのcookieを設定
cookies[:sample] = {
  value: "sample",
  httponly: true
}
```
【SQL】自己結合で重複を削除し、最新のレコードを取得する方法

同一テーブルで重複するカラムがある中で、その重複を削除した上で、ある条件に合致したレコードを取得する方法を勉強したため備忘録として残すもの。


### 実装方法
#### ユーザーテーブル(Users)
|id| name|Age|gender|created_At|
|---|---|---|---|---|
|1|Williams|10|men|2023-03-15 08:30:00|
|2|Bob|23|men|2023-04-22 14:15:00|
|3|Alice|21|women|2023-05-05 19:45:00|
|4|Johnson|27|men|2023-06-10 10:00:00|
|5|Emma|17|women|2023-07-18 21:30:00|
|6|Brown|18|men|2023-08-03 11:45:00|
|7|Williams|25|men|2023-09-12 16:15:00|
|8|Alice|30|women|2023-10-25 23:00:00|
|9|Emma|22|women|2023-11-07 05:30:00|
|10|Jones|20|men|2023-12-30 12:15:00|

上記のようなレコードがあったとする。

このレコードでは名前が重複している。
しかし、
**「名前の重複を削除した上で、名前ごとに一番新しいレコードを取得する」**
という要件があったとする。

この要件に応えるためのクエリについて解説したいと思う。

## まず、日時が一番新しい名前を、重複を削除した上で取得する
このためには<font color=red>**「MAX関数」**</font>と<font color=red>**「group by」**</font>を組み合わせることで取得できる
```SQL
SELECT name, MAX(created_at) AS max_created_at
FROM Users
GROUP BY name;
```
上記のクエリの結果が以下になる。
|name|created_At|
|---|---|
|Bob|2023-04-22 14:15:00|
|Johnson|2023-06-10 10:00:00|
|Brown|2023-08-03 11:45:00|
|Williams|2023-09-12 16:15:00|
|Alice|2023-10-25 23:00:00|
|Emma|2023-11-07 05:30:00|
|Jones|2023-12-30 12:15:00|

名前の重複が削除されており、最新の日時のデータが残っている。
これのデータを利用することから、上記のクエリをサブクエリとして使用することになる。

## 次に自己結合を行い、結合条件をnameとcreated_atに指定する。

```SQL
SELECT Users.*
JOIN (
    SELECT name, MAX(created_at) AS max_created_at
    FROM Users
    GROUP BY name
) subUsers ON Users.name = subUsers.name AND Users.created_at = subUsers.created_at;
```
結合する条件を
```SQL
ON Users.name = subUsers.name AND Users.created_at = subUsers.created_at
```
とすることで、「サブクエリと同じ名前かつ、サブクエリで取得した名前ごとの最新日時と一致するレコードと結合」する挙動になる。

このクエリによって、以下の結果になる。
|id| name|Age|gender|created_At|
|---|---|---|---|---|
|2|Bob|23|men|2023-04-22 14:15:00|
|4|Johnson|27|men|2023-06-10 10:00:00|
|6|Brown|18|men|2023-08-03 11:45:00|
|7|Williams|25|men|2023-09-12 16:15:00|
|8|Alice|30|women|2023-10-25 23:00:00|
|9|Emma|22|women|2023-11-07 05:30:00|
|10|Jones|20|men|2023-12-30 12:15:00|

## まとめ
自己結合の使い所がいまいち理解していなかったが、実務で使う必要があったため自己結合について少しは理解が進んだ。
オブジェクト指向　ガベージコレクション

### オブジェクト指向プログラミング以前の言語
C言語やC++などの以前のプログラミング言語では、不要になったメモリ領域を削除する処理をアプリケーションで明示的に指示する必要がありました。
この時、以下のような不便がありました。

* 誤って別の場所で使われているインスタンスを削除してしまうと、後からそのインスタンスを使うロジックで不正な動作をしてしまう。
* 逆に使われていないインスタンスの削除を忘れると、不要なインスタンスが増えてメモリを圧迫してしまう。

### ガベージコレクションの登場
JavaやC#など多くのオブジェクト指向プログラミングでは、このようなインスタンスを削除する処理をシステムが自動的に実行する仕組みが採用されている。これを**ガベージコレクション**とよぶ。

ガベージコレクションでは、不要になったインスタンスをメモリ上から削除するのは、ガベージコレクタと呼ばれる、システムが用意する専用のプログラムの仕事です。この仕組みにより、間違いやすいインスタンスの削除処理をプログラムが記述しないで済むようになる。