OmniAICreator/Qiita-1.07M huggingface dataset:
Steamで販売したゲームのGlobalStatsをPythonで集計する

# ■はじめに
この記事では、みなさんが作成したゲームで設定しているStat(集計のチェックを入れたもの)をPythonで加算集計してみます。
マーケティング等でStatの値を見たい場合に有効かと思います。

:::note warn
集計のチェックを入れていないStatに関してはGlobalStatとして取得できないので、注意して下さい。
![Check.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2951067/5eedc4a1-6d04-a422-35a1-598afb589bc5.png)
:::

# ■ドキュメント

https://partner.steamgames.com/doc/features/achievements?l=japanese

# ■コード
```
API_KEY = 'ここ' # <=(*1)ここに皆さん個人のSteamのWebAPIキーを入れる
APP_ID = 'ここ'  # <=ここに皆さんの作成したSteamゲームのAppIDを入れる
STAT_NAMES = ['ここ1', 'ここ2']  # <=ここに取得したいstatのキーを1個以上入れる。

def get_global_stats(app_id, stat_names, api_key):
    try:
        # 複数のstatをリクエストするためにname[0], name[1], ... を作成
        names_param = '&'.join([f'name[{i}]={stat}' for i, stat in enumerate(stat_names)])
        url = f"https://api.steampowered.com/ISteamUserStats/GetGlobalStatsForGame/v1/?appid={app_id}&count={len(stat_names)}&{names_param}&key={api_key}"
        
        # リクエストのURLを表示して、正しく作成されているか確認
        print(f"APIリクエストURL: {url}")

        response = requests.get(url)
        
        # ステータスコードとレスポンスを出力
        print(f"ステータスコード: {response.status_code}")
        print(f"レスポンス: {response.text}")  # JSON形式でない場合のために.textを使う

        if response.status_code == 200:
            data = response.json()  # JSON形式のデータを解析
            
            # 結果を返す（globalstats から値を取得）
            if 'response' in data and 'globalstats' in data['response']:
                return data['response']['globalstats']
            else:
                print("統計データが見つかりませんか、フォーマットが異なります")
        else:
            print(f"APIリクエストが失敗しました: {response.status_code}")
    except Exception as e:
        print(f"例外が発生しました: {e}")
    return None

def main():
    stats = get_global_stats(APP_ID, STAT_NAMES, API_KEY)
    if stats:
        # 複数のstatをループで表示
        for stat_name in STAT_NAMES:
            if stat_name in stats:
                # データが空でないか確認
                if 'total' in stats[stat_name]:
                    print(f"現在の {stat_name}: {stats[stat_name]['total']}")
                else:
                    print(f"{stat_name} のデータが存在しません（空のレスポンス）")
            else:
                print(f"{stat_name} のデータが見つかりません")

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

:::note warn
(*1)個人のSteamWEBAPIキーです。
まだWebAPIキーを取得していない場合は以下から取得できます。
http://steamcommunity.com/dev/apikey
:::

# ■実行
上記をテキストファイル等に書き、そのファイルの拡張子を.pyにした後、コマンドプロンプト等から実行すれば確認できます。


# ■その他できることがまとめられている記事

https://qiita.com/Chronona/items/2e464ee96799dd0ed5c2


# ■以上
コーヒーに合う電子タバコがあればいいのに、と思いながらなんとなく買ったセッターのメンソールは冬に呑むと寒い。
ローカルファイルパスをURLに変換


```python
from urllib.parse import urljoin
from urllib.request import pathname2url

file_path = r"C:\Users\UserName\Desktop\example.xlsx"

file_url = urljoin("file:", pathname2url(file_path))
print(file_url)

# file:///C:/Users/UserName/Desktop/example.xlsx

```

https://docs.python.org/ja/3/library/urllib.parse.html#urllib.parse.urljoin

https://docs.python.org/ja/3/library/urllib.request.html#urllib.request.pathname2url
イベントレポート「【関西女性エンジニア限定】キャリアワークショップ＆クリスマス交流会 at HACK.BAR神戸」

お疲れさまです、みやもとです。

今日は先日参加したTECH WOMAN KANSAIのイベントレポートです。

# TECH WOMAN KANSAIとは
地域軸×女性×テクノロジーで形成されたコミュニティです。
コミュニティの活動方針としては、関西のIT企業で働くor関西在住の女性エンジニアの皆さんが集まれる「居場所」を作ることです。
コミュニティタイプとしては、地域軸寄りのオープンなコミュニティです。
現在は約月1の頻度で定例のオフラインイベントの開催、オンラインもくもく会、Slackチャンネルでの会話、女子会企画、交代で技術記事の投稿なども行っています。

https://tech-woman-kansai.connpass.com/

今回はひさしぶりのオフラインイベント開催でした。
クリスマスも近いということで交流会と2本立てのキャリアイベントです。

https://tech-woman-kansai.connpass.com/event/336184/

# HACK.BARとは
「エンジニアが集まるバー」として運営されているのバーです。
今年大阪にも出店されました。
私は主に三宮店でお世話になっていて、今回のイベント会場も三宮店です。

https://hackbar.connpass.com/

# イベント感想
まず到着したら名札を受け取りました。
私は何度かオフラインイベントに参加しているので以前に作った名札をそのまま使わせてもらいました。
初参加の方は白紙を受け取って名札を作るところからスタート。
開始までの時間に飲み物を注文したりして待ちます。

今日はイベント限定ということで「なでしこ」を注文しました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477580/7f834aca-2644-82a9-b9cc-12651f92a5b1.jpeg" width="50%">


開始時間になったら挨拶・会場説明・自己紹介を経ていよいよメインプログラムに入ります。

## 第１部　キャリアワークショップ
まずキャリアワークショップ。
2グループに分かれて進めていきます。
あらためての自己紹介をした後、
* 現在の仕事について思うこと（満足していること、不満を感じること）
* 仕事も含め、人生において自分が重視したいポイント
* 仕事の上で重視したいポイント
* 上記を踏まえた上で今後やっていきたいこと

と、ポイントごとに時間を区切って考えたり話し合ったりしました。
ほかの人とあれこれしゃべっていると、自分で考えている時にはあまり意識しなかった点に気が付いたり意見を比べることで考えが深まったりして新鮮ですね。

こういう自己分析は就職活動や転職活動でやる印象ですが、直近の転職活動を振り返ると以外と２つめと４つめはあんまり意識していなかったと気が付きました。
ひとりで考えると最低限のところだけ考えて終わったり逆に考えすぎて煮詰まったりするので、こういうイベントでやるのがちょうどいいかもしれません。

最終的に「いろんな言語に挑戦してみる」「積んでるハンズオン本[^1]を消化する」という目標ができました。
[^1]:技術書典で買ったハンズオン本が結構手つかずで残ってしまっています。

## 第２部　クリスマス交流会
休憩をはさんでクリスマス交流会。
ケータリングの軽食をつまみながら最初にゲームがありました。
店内の特大モニターに表示されたロゴを見て、サービス・製品の名称を当てるロゴクイズです。

これがかなり盛り上がりました。
PostgreSQLのロゴはあの象だけで名称は含まれないとか、正解発表後にどんなサービス、製品なのか簡単な解説を交えて進んでいきました。
見覚えのないロゴもいくつかあってなかなか勉強にもなります。
私も２問くらい答えられたので満足です。

そのあとは完全にフリートークで、あちこちでおしゃべりが弾んでいました。
私もPMをやっている方やこれからマネジメントの道に進むかどうかで考え中の方といろいろお話できてすごく楽しかったです。
もともとオンラインもくもく会等である程度馴染んでいるコミュニティのイベントだったこともあり、普段と比較するとすごくリラックスして過ごすことができました。
あとごはんすごくおいしかったです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477580/6f36a736-da64-1114-6dc0-4e7c540ad9eb.jpeg" width="70%">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477580/54ef76e7-5385-fb22-a554-3467f0a55244.jpeg" width="70%">
Copilotの管理者設定は何があるのか表にした

| 設定項目                          | 説明                                                                                 | 適用範囲             | 設定場所                                                                 |
|-----------------------------------|--------------------------------------------------------------------------------------|----------------------|--------------------------------------------------------------------------|
| Copilot の有効化/無効化           | 組織全体または特定のユーザーに対して Microsoft 365 Copilot の利用を許可または制限します。 | 組織全体、ユーザー   | Microsoft 365 管理センターの [Copilot] ページの [設定] タブ              |
| ライセンス管理                   | ユーザーへの Copilot ライセンスの割り当てや解除を行います。                           | ユーザー             | Microsoft 365 管理センターの [課金] > [ライセンス] セクション            |
| データ、セキュリティ、コンプライアンス | 機密ラベル、保持ポリシー、監査レコードの管理を行います。                             | 組織全体             | Microsoft Purview コンプライアンス ポータル                              |
| エージェント、プラグイン管理       | 機能拡張（エージェント、プラグイン、コネクタ）の有効化や展開を管理します。             | 組織全体、ユーザー   | Microsoft 365 管理センターの [設定] > [統合アプリ] セクション            |
| フィードバックの送信             | ユーザーに代わって Copilot のフィードバック ログを Microsoft に送信します。             | 組織全体、ユーザー   | Microsoft 365 管理センターの [Copilot] ページの [設定] タブ              |
| セルフサービス購入の管理         | ユーザーが管理者の承認なしに Copilot を購入できるかどうかを設定します。                 | 組織全体             | MSCommerce PowerShell モジュール                                        |
| Teams 会議での Copilot の使用     | Teams 会議内での Copilot の利用方法を設定し、会議中および会議後の使用を制御します。     | 組織全体、ユーザー   | Microsoft Teams 管理センター                                            |
| Viva Engage での Copilot          | Viva Engage 内での Copilot の利用を管理し、ユーザーのアクセスを制御します。             | 組織全体、ユーザー   | Microsoft 365 管理センターの [Copilot] ページの [設定] タブ              |
| Viva Goals での Copilot           | Viva Goals 内での Copilot の利用を管理し、ユーザーのアクセスを制御します。              | 組織全体、ユーザー   | Microsoft 365 管理センターの [Copilot] ページの [設定] タブ              |
TCPプロトコル

### IPペイロード、イーサネットペイロードのサイズ内に納める
>送信エンティティと受信側エンティティは、セグメントの形でデータを交換する。TCPセグメント(TCP segment)は２０バイト固定長のヘッダー（とオプションの部分）と0バイト以上のデータから構成される。TCPソフトウェアはセグメントの分割、蓄積を行うことができる。いくつかの書き込みを蓄積して一つのセグメント・サイズの上限を決定する二つの要素が存在する。第一に、TCPヘッダーを含む各セグメントは6万5535バイトのIPペイロードに治らなければならない。MTUは一般的に1500バイト（イーサネットのペイロードサイズ）であるから、これがセグメント・サイズの上限に影響する。

### 経路MTUを見つけその中のパケットの最大のサイズを送る
>しかしながら、セグメントは、MTUを持つリンクを含んだネットワーク経路を通す場合、TCPセグメントをフラグメント化していくつかのIPパケットで運ぶことが可能である。このことは、性能の低下と、その他の問題を引き起こす。この問題の解法はとして、最近のTCPは、経路MTU発見(path MTU discovery)を実装している。

>経路MTU発見では、ICMP誤りメッセージを用いて経路中の最小のMTUを見つける。その後、TCPは、フラグメント化を避けるために、セグメント・サイズを調整する。

### タイマーで測り、確認通知が時間内に来ないと再送する
>TCPエンティティにより利用される基本的なプロトコルは、スライディング・ウィンドウ・プロトコルである。送信者はセグメントを送る時、タイマーをセットさせる。セグメントが宛先に到着するとき、受信TCPエンティティは、確認通知番号、つまり次に受信すべき順序番号を含むセグメントを送り返す。確認通知を受信する前に送信者のタイマーが満了した場合、送信者はセグメントをもう一度送る。

https://bookplus.nikkei.com/atcl/catalog/23/03/16/00728/
ALBにパブリックIPアドレスを付与する方法

# 結論
- ALBにパブリックIPアドレス（Elastic IP）を付与することはできない
- 対応策は以下の方法1,2の通り
---
## 方法1: Network Load Balancer（NLB）をALBの前段に配置する

1. **Network Load Balancer（NLB）の作成**
   - NLBはElastic IPをサポートしているため、固定IPを割り当てることができる
2. **NLBからALBへのリスナーを設定**
   - NLBをALBの前段に配置し、NLBが受け取ったトラフィックをALBに転送する
3. **Elastic IPをNLBに割り当てる**
   - 各アベイラビリティゾーンでNLBにElastic IPを割り当てることで、固定IPが利用可能
---
## 方法2: AWS Global Acceleratorを使用する

1. **Global Acceleratorを作成**
   - Global Acceleratorは固定IPを提供し、トラフィックをリージョン内のALBにルーティングする

2. **Global AcceleratorとALBの関連付け**
   - Global AcceleratorをALBに結びつけることで、固定IPを経由してALBにアクセスできる

## 方法の選択

| **方法**           | **利点**                               | **注意点**                             |
|-----------------------|-------------------------------------|--------------------------------------|
| NLB + ALB             | 簡単に設定可能、低レイテンシ | 設定が二段構成になる            |
| Global Accelerator    | 複数リージョンのALBに対応可能、グローバル対応 | 初期設定が複雑、料金が高め               |

## まとめ
Global Acceleratorを使うほうがベストプラクティス。
fullcalender-rails 記録

# はじめに
今回は、前回の記事で実装した中の苦戦した場所などを記載します。

実装をしている記事は、前回書いていますので、
確認お願いします。

https://qiita.com/kureha_com/items/b9cb92c208d995bf130e

# Point:speaking_head:
## routes
今回は、calenderの登録したイベントをクリックしてイベントの詳細を見る***showアクション***とcalenderの日付の詳細を見る***date_details***がURLの構造が似ている?のでエラーが出ました。
```
showアクション(events/:id)
date_detailsアクション(events/dates/:date)
```
resources :eventsの中にget "events/dates/:date"を入れずに外で定義するとエラーを回避できました。
```ruby
get "events/dates/:date", to: "events#date_details", as: "event_date"
```

## indexアクション
```ruby
  def index
    @events = Event.all
    respond_to do |format|
      format.html
      format.json do
        render json: @events.map { |event|
          {
            id: event.id,
            title: event.title,
            start: event.time.in_time_zone("Asia/Tokyo").iso8601, # タイムゾーンを変換して送信
            url: event_path(event)
          }
        }
      end
    end
  end
  ```
  respond_toでHTMLリクエストとJSONリクエストで異なるレスポンスを返すように。
###### HTMLレスポンス
```ruby
format.html
```
特に何も指定していないので、Railsが自動で適切なviewを返す。(デフォルト:idnex.html.erb)
###### JSONレスポンス
```ruby
format.json do
  render json: @events.map { |event|
    {
      id: event.id,
      title: event.title,
      start: event.time.in_time_zone("Asia/Tokyo").iso8601,
      url: event_path(event)
    }
  }
end
```
JSON形式のリクエストが来た場合に@eventsの内容をJSON形式で返すための処理
###### どのように設定しているか↓
* id: イベントのID
* title: イベントのタイトル
* start: イベントの時間をTokyoのタイムゾーンに
* uer: イベントの詳細リンク(showアクション)
>start:event.time.in_time_zone("Asia/Tokyo").iso8601
こちらでUTC(協定世界時)からTokyoのタイムゾーンに変換してからISO 8601形式に整形している

###### start:event.time.in_time_zone("Asia/Tokyo").iso8601
* event.time:
データベースから取得されたUTC（協定世界時）形式の日時が格納されている
* in_time_zone
ActiveSupportのメソッドで、日時オブジェクトのタイムゾーンを変換する
* "Asia/Tokyo"
指定することで、UTCからTokyoのタイムゾーンに変換
* iso8601
最後に、iso8601メソッドを呼び出して、日時オブジェクトをISO 8601形式の文字列に変換している。この形式は、国際的に標準化された日時の表現方法で、例えば2023-10-01T10:00:00+09:00のような形式になる。
ISO 8601形式は、機械可読性が高く、異なるシステム間でのデータ交換に適しているため、APIなどでよく使われる

## Javascript
### インポート
 import { Controller } from "@hotwired/stimulus";
 > Stimulusのコントローラーをインポートしている。これにより、DOM要素とJavaScriptのロジックを結びつけることができる
 
import { Calendar } from "@fullcalendar/core";
> FullCalendarのコア機能をインポートしている。これを使ってカレンダーを作成する

import dayGridPlugin from "@fullcalendar/daygrid";
> 月表示のカレンダーを実現するためのプラグイン

import interactionPlugin from "@fullcalendar/interaction";
> ユーザーが日付をクリックしたり、ドラッグしたりするインタラクションを実装するためのプラグイン

import jaLocale from "@fullcalendar/core/locales/ja";
> 日本語ロケールをインポートして、カレンダーの表示を日本語にする
```ruby
plugins: [dayGridPlugin, interactionPlugin], #使用するプラグインを指定
initialView: 'dayGridMonth', #初期表示を「月」ビューに設定
timeZone: 'Asia/Tokyo', #タイムゾーンをTokyoに設定
locale: jaLocale, #カレンダーの言語を日本語に設定
events: '/events.json', #イベントデータを取得するAPIエンドポイントを指定
selectable: true, #日付を選択できるように設定
editable: true, #イベントを編集できるようにしている。
```
```ruby
dateClick: (info) => { ###日付がクリックされた際の動作を定義
  const date = new Date(info.date).toISOString().split("T")[0];
  window.location.href = `/events/dates/${date}`;
},
```
クリックした日付をUTC基準のISO形式に変換し、日付部分のみを取得。
> こちらをしないと本番環境でなぜか登録したイベントの表示がずれてしまう。
例)12/12にイベント登録をして12/12をクリックしても表示されない。12/11に表示されている。

取得した日付を使って、新しいURLにリダイレクトしている。これにより、特定の日付のイベントページに遷移する


### 終わり
初めてのcalenderの実装で色々苦戦しました:footprints:
無料で独自ドメインメールアドレスを手に入れる方法！Cloudflareで簡単設定

Cloudflareは、非常に多くの便利なサービスを提供している企業で、特に無料プランが充実しています。今回は、Cloudflareを使って、独自ドメインのメールアドレスを無料で利用する方法を紹介します。これにより、プロフェッショナルな印象を与えることができ、メールアドレスを簡単に管理できます。

## 1. Cloudflareアカウントを作成

最初に、Cloudflareのアカウントを作成します。[公式サイト](https://www.cloudflare.com/)にアクセスし、メールアドレスとパスワードを入力してサインアップします。すでにアカウントをお持ちの場合は、ログインします。

https://www.cloudflare.com/

## 2. ドメインの登録

次に、独自ドメインをCloudflareに登録します。もし、まだドメインを購入していない場合は、ドメインレジストラ（例: お名前.com、ムームードメインなど）でドメインを購入してください。

購入したドメインをCloudflareに追加するためには、Cloudflareダッシュボードにログイン後、「+ Add site」ボタンをクリックし、ドメイン名を入力します。その後、Cloudflareが自動でDNS設定をスキャンします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3474929/046fabd0-567b-3340-a6d9-24121e73bbbc.png)
## 3. DNS設定の変更

Cloudflareに登録したドメインのDNS設定を変更します。自分のドメインレジストラの管理画面に移動し、Cloudflareから提供されたDNSサーバーのアドレスに変更します。この変更が反映されるまで、数時間かかる場合があります。

## 4. メール設定の追加

Cloudflare自体は、メールホスティングサービスを提供していませんが、メールの転送設定を無料で行うことができます。これを実現するために、以下の手順を実行します。

### 4.1. Cloudflareの「Email Routing」機能を有効にする

Cloudflareのダッシュボードにアクセスし、「Email」セクションを選択します。そこで、「Email Routing」機能を有効にすると、ドメインのメール設定を行えるようになります。

### 4.2. メールアドレスの作成

「Email Routing」を有効にした後、受信したいメールアドレスを作成します。例えば、info@exmaple.com のようなメールアドレスを作成します。

### 4.3. 転送先アドレスを設定

作成したメールアドレスに対して、転送先のメールアドレスを設定します。例えば、GmailやYahooメールなど、自分の既存のメールアドレスを転送先として設定できます。

## 5. メールの送信

Cloudflare自体はメール送信機能を提供していませんが、外部のSMTPサービスを利用することで、独自ドメインからメールを送信できます。例えば、Google WorkspaceやZoho Mailなどのメールサービスを利用すると、独自ドメインのメールアドレスからメールを送信することができます。

## まとめ

Cloudflareを利用すると、無料で独自ドメインのメールアドレスを作成し、メールの転送設定を簡単に行うことができます。ただし、メールの送信には外部サービスを利用する必要がありますが、コストを抑えてプロフェッショナルなメールアドレスを運用できる点が大きな魅力です。
goで作る、telnet電子広告サーバー

今回は、接続してきたクライアントの順番（何人目の接続か）を追跡する機能を追加してみます。  
これにより、各クライアントに「あなたは○○人目の接続者です」といったメッセージを送信できます。  

## 実装の変更点  

- 接続者数を管理するために、サーバー側でカウンターを設置します。  
- 各クライアントが接続した際に、その順番を送信します。  


以下はtelnet電子広告サーバーの基本的なコード例です：  
```go  
package main  

import (  
    "fmt"  
    "net"  
    "sync"  
    "time"  
)  

var connectionCount int  
var mu sync.Mutex  // 同時アクセスを防ぐためのミューテックス  

func main() {  
    listener, err := net.Listen("tcp", ":8080")  
    if err != nil {  
        fmt.Println("Error starting server:", err)  
        return  
    }  
    defer listener.Close()  
    fmt.Println("Server started on port 8080")  

    for {  
        conn, err := listener.Accept()  
        if err != nil {  
            fmt.Println("Connection error:", err)  
            continue  
        }  

        // 接続順番を追跡  
        mu.Lock()  
        connectionCount++  
        clientNumber := connectionCount  
        mu.Unlock()  

        go handleConnection(conn, clientNumber)  
    }  
}  

func handleConnection(conn net.Conn, clientNumber int) {  
    defer conn.Close()  

    // 接続順番を伝えるメッセージ  
    welcomeMessage := fmt.Sprintf("あなたは%d人目の接続者です！\n", clientNumber)  
    conn.Write([]byte(welcomeMessage))  

    messages := []string{  
        "Profile:",  
        "MailAdress",  
    }  

    for {  
        for _, msg := range messages {  
            conn.Write([]byte(msg + "\n"))  
            time.Sleep(5 * time.Second)  
        }  
    }  
}  
```  

## 変更点の説明  

1. **`connectionCount`**：接続してきたクライアントの順番を追跡するために、グローバル変数としてカウントします。  
2. **`mu` (ミューテックス)**：複数の接続が並行して進行するため、`connectionCount`へのアクセスを同期させるためにミューテックスを使っています。  
3. **`clientNumber`**：接続順番をカウントして、各クライアントにその情報を送信します。  

## 実行方法  

1. 上記のコードを`main.go`という名前で保存します。  
2. 以下のコマンドを実行してサーバーを起動します：  

```bash  
go run main.go  
```  

3. 別のターミナルで以下のコマンドを使用してtelnetクライアントを起動します：  

```bash  
telnet localhost 8080  
```  

4. クライアントに「あなたは○○人目の接続者です！」というメッセージが表示され、その後、広告が定期的に表示されることを確認してください。
【Rails】after_createでJobにキューを入れると本番環境でエラーになることがある

# 概要
実際に自分がエラーで困ったわけではありませんが、意識していないと怖いなと感じたので備忘録です

以下のようなissueがありました

https://github.com/rails/rails/issues/26045

どういうことかというと、

```rb:user.rb
class User < ApplicationRecord
	after_create -> { NotifyUserAfterCreate.perform_later(self) }
end

class NotifyUserAfterCreate < ApplicationJob
  def perform(user)
	puts "===== User created: #{user.inspect}"
  end
end
```

createをフックして、ジョブにキューを入れている


```
app(dev)> User.create!
  TRANSACTION (0.6ms)  BEGIN
  User Create (5.8ms)  INSERT INTO `users` (`created_at`, `updated_at`) VALUES ('2024-12-14 10:54:29.078065', '2024-12-14 10:54:29.078065')
Enqueued NotifyUserAfterCreate (Job ID: 06f8e371-9a6d-4be9-98d1-bcd3054849d5) to Async(default) with arguments: #<GlobalID:0x0000ffff890aba98 @uri=#<URI::GID gid://app/User/146>>
↳ app/models/user.rb:2:in `block in <class:User>'
  TRANSACTION (2.4ms)  COMMIT
=> #<User:0x0000ffff8d352950 id: 146, created_at: "2024-12-14 10:54:29.078065000 +0000", updated_at: "2024-12-14 10:54:29.078065000 +0000">
  User Load (0.7ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 146 LIMIT 1
  
Performing NotifyUserAfterCreate (Job ID: 06f8e371-9a6d-4be9-98d1-bcd3054849d5) from Async(default) enqueued at 2024-12-14T10:54:29.091801680Z with arguments: #<GlobalID:0x0000ffff8907d198 @uri=#<URI::GID gid://app/User/146>>

===== User created!!: #<User id: 146, created_at: "2024-12-14 10:54:29.078065000 +0000", updated_at: "2024-12-14 10:54:29.078065000 +0000">

Performed NotifyUserAfterCreate (Job ID: 06f8e371-9a6d-4be9-98d1-bcd3054849d5) from Async(default) in 3.74ms
```

ローカル環境では(ほとんどの場合)問題なく動く

# 実は問題がある
Jobのキューが実行されるタイミング次第で、
> ActiveJob::DeserializationError: Error while trying to deserialize arguments: Couldn't find Task with 'id'=1
参考: https://qiita.com/kymmt90/items/470b9d2082e63d61b032

という例外が発生する

（自分のローカル環境でも2回だけ発生したが、再現できるだろうと思ってそのまま流したらその後再現できなくなってしまった:cry:）

issueによると、ジョブのキュー周りの処理が高速である本番環境で発生する問題らしい

開発環境で気付けないのは大変怖いので気をつけたい

# Rails 7.2以降
トランザクションのコールバックを指定できるようになった

https://guides.rubyonrails.org/7_2_release_notes.html#prevent-jobs-from-being-scheduled-within-transactions

```rb
ActiveRecord::Base.transaction do |t|
    user = User.create!

    t.after_commit do
        puts user.inspect
    end
end
```
上記のようにCommit後の処理を指定できるようになった

https://github.com/rails/rails/issues/26045

Jobの場合はSerializerを通しているという強みがあったりするので、それぞれのプロジェクトでどちらを使うかを判断が必要そうです
出力: 車輪を動かす　その2

### 背景
12/9と同様に、動作のブロックの一部を試してみます。

### Scratch
左右のタイヤを個別に操作するブロックがありました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/58b1c802-1920-e912-d471-bee065f6a346.png)

方向は左側にあるスイッチで変更できるようです。
回転速度はスライダか右側のボタンを押してキーボードから入力します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/e7485a76-ae47-18ab-e9e1-304278c47796.png)

「左タイヤを速度75、右タイヤを速度-75、0.6秒間回転する。」

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103446/63fb9f3c-5083-76b0-b089-eb9a32e49701.png)


実行すると、その場で時計回りに一回転しました。

なお、図の右のようにスピンを使うとその場で回転することができるのですが、なぜか動きがカクカクでした。


### spheroV2
sphero_edu.pyのメソッドを参考に同様な動作をするスクリプトを作成しました。

```
import time

from spherov2 import scanner
from spherov2.sphero_edu import EventType, SpheroEduAPI
from spherov2.types import Color

print("Testing Starting...")
print("Connecting to Bolt...")
toy = scanner.find_BOLT()

if toy is not None:
    print("Connected.")
    with SpheroEduAPI(toy) as droid:
        print("Testing Start...")
        
        print("motor 75, -75, in 0.6sec")
        droid.raw_motor(75, -75, 0.6)

        # print("spin: 360deg in 1.0sec")
        # droid.spin(360, 1.0)

        print("Testing End...")
  
else:
    print("Failed to connect to Sphero.")
```

Scratchと同様にspinを使うと動きがカクカクでした。
sphero_edu.pyの中身を見ると、spinはすこしずつ向きを変更するようなので、回転する角度と時間によってはカクつきが目立つのかもしれません。

### まとめ
spheroV2を用いて、sphero boltの左右のタイヤをpythonで動かすことができました。
左右のタイヤの回転を別々に指定できるので動きを細かく制御して楽しめそうです。
高速回転するおっさんを戦わせるクソゲーをつくった

今年で参加7年目になります、黒神([@kokushing](https://x.com/kokushing))と申します。

最近は周りの友人に影響を受け、Unityを使ったゲーム開発の学習を始めました。

https://x.com/kokushing/status/1845802009292898360

クソアプリアドベントカレンダーは新しい技術に挑戦するならもってこいの神イベントなので、今回は思い切って守備範囲のWebアプリではなく、Unityを使った3Dクソアプリ(クソゲー)を作ってみました！

## つくったもの

**「高速回転するおっさんを戦わせるクソゲー」** です。

https://x.com/kokushing/status/1867892449408119048

2体の回転するおっさんをスタジアム上で戦わせます。所謂ベイブレードですね。

先にスタジアムから飛び出してしまったほうが負けになりますが、時間の都合で勝ち負けの判定を作れませんでした。

戦闘BGMは友人がSunoAIで作成してくれたものを採用しました。

## 初期バージョン

v1の時点では、スタジアムが水平なものしか用意できなかったため、両者が一生ぶつかり合うことはありません。悲しい運命(さだめ)です。

https://x.com/kokushing/status/1860902276979970066

## 改良版

v2ではナイスアイデアな実装の解説記事と、ちょうど良いスタジアムのモデルを発見することができたので、無事両者ぶつかり合うことができました。やったね！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57867/b890bbfe-2ba2-bd0b-0241-2a18d0560bc4.png)

## つくりかた

[をる](https://note.com/wol_gamedev_note)さんのnoteをほぼそのまま参考にしつつ、モデルデータは[ロキロキ団](https://rokirokidan.booth.pm/)さんのVRMモデル「[誰に需要があるのだろう…おっさんアバター](https://booth.pm/ja/items/5408254)」を使わせていただきました。使い道あったよ！

https://note.com/wol_gamedev_note/n/n43d54b1c673f

工夫した点としては、球体のオブジェクトのままだとあまり派手にぶつかり合わなかったので、立方体を平たく伸ばしたオブジェクトと合体させて実装しました。
ベイブレードで言うところのアタックリングですね。

GUI操作などで困ったらClaudeに画面のスクショを投げて丁寧に教えてもらいつつ、C#のコードは基本的に出力してもらったものを採用して開発を進めることができました。

https://x.com/kokushing/status/1845825933552595112

また、をるさんの球体を自然衝突させて、コマのモデル自体を回転させるというアイデアは天才的だなぁと思いました。
ゲーム開発におけるこういった工夫の引き出しがまだ少ないので、これから増やしていきたいです！

## 改善点

改善点というかゲームとして成り立ってないので、まずは勝敗の判定を実装します。

次に、おっさんのバリエーションを増やし、ステータスを調整して攻撃タイプ、防御タイプ、持久タイプなど戦術のバリエーションを増やしたいです。

最後、VRMモデルを自由に差し替えられるようにしたいですが、倫理的にモデラーさんが丹精込めて作ったものを高速回転させた挙句にぶつかり合わせて戦わせるのはどうなんだろう...という懸念があります(切実)

実際に遊んでみたい！という声もちらほらあったので、タイミング見てリリースしようと思います。

## 感想

Unityというか3Dゲーム開発、本当に面白いです。実際に作ったものがちゃんと動くだけで感動ものです。

とりあえず何かSteamにリリースしてみたいのですが、現状は具体的に作りたいものが決まっていないので、直近はもう少し色々なジャンルのゲーム開発に触れてみて知見を貯めたいです。

以上、今年はWebアプリから脱却してUnityでクソアプリ作ってみた！でした。

また来年もよろしくお願いします！

## 過去作

https://qiita.com/kokushin/items/300070942b09c6b22ffb

https://qiita.com/kokushin/items/b59fa60b6485711f10fe

https://qiita.com/kokushin/items/a2b00a8ecf1edccb8199

https://qiita.com/kokushin/items/d413464b1d98162d07ad

https://qiita.com/kokushin/items/253ef1d5bd90d4c68d14

https://qiita.com/kokushin/items/54894b6ff9a4b24c0855
投票機能を vueuse の useCounter に置き換える

前回つくった投票アプリの投票機能の部分を `vueuse` ライブラリの `useCounter` に置き換えてみます。

https://qiita.com/uekkie/items/876fc0668e6487d9d8ba

:::note
VueUseはVue向けのユーティリティ集で、便利なComposableが豊富。
:::

https://vueuse.org/shared/useCounter/#usecounter

## 変更後のコード

```pages/index.vue
<script setup lang="ts">
import { useCounter } from '@vueuse/core'

const { count: remainPoints, dec } = useCounter(10, { min: 0 })

const people = [
  '林修（予備校講師）',
  '池上彰（ジャーナリスト）',
  '松岡修造（元プロテニス選手）',
  '樹木希林（女優）',
  '北野武（映画監督・タレント）',
  '堀江貴文（実業家）',
  '羽生結弦（フィギュアスケーター）',
  '村上春樹（作家）',
  '大谷翔平（プロ野球選手）',
  '天海祐希（女優）']
</script>

<template>
  <div>
    <h1>投票画面</h1>
    <h2>先生になってほしい有名人は？</h2>

    <div>
      のこりポイント
      <span class="point">
        {{ remainPoints }}
      </span>
    </div>

    <div v-for="name of people">
      <Item :name="name" :disabled="remainPoints === 0" @update="dec" />
    </div>
  </div>
</template>

<style lang="css">
.point {
  font-size: x-large;
}
</style>
```

```components/Item.vue
<script setup lang="ts">
import { useCounter } from '@vueuse/core'

const { count: point, inc } = useCounter(0, { min: 0 })

const props = defineProps<{
  name: string
  disabled: boolean
}>()

const emit = defineEmits(['update']);

function handleClick() {
  inc()
  emit('update')
}
</script>

<template>
  <div class="card">
    <div>
      {{ props.name }}
    </div>
    <div class="right">
      <button @click="handleClick" :disabled="props.disabled">
        投票する
      </button>
      <div class="point">
        {{ point }}
      </div>
    </div>
  </div>
</template>

<style lang="css">
.card {
  padding: 1rem 0.5rem;
  margin: 0.5rem;
  border: 1px solid #333;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.right {
  display: flex;
  gap: 30px;
  align-items: center;
  margin-right: 2rem;
}
</style>
```

## 変更点

1. `@vueuse/core`のインストール
1. `useCounter`の適用
1. `Item.vue`への切り出し
1. リファクタリング（`type Item`の廃止、`defineEmits`による子→親へのイベント伝播）

差分の詳細はこちら

https://github.com/uekkie/nuxt-poll/pull/1/commits/2cce351437edb2a5bd85a7a8b996140b31834ba4
複雑適応系、つまりチームについて

この記事は、[適応型ソフトウェア開発 アドベントカレンダー 2024](https://qiita.com/advent-calendar/2024/adaptive-software-development) の 16日目です。

## 適応型ソフトウェア開発を進める体制について

適応型ソフトウェア開発というフレームワークを進行する「チーム」について、この記事では述べたい。

一言で言ってしまうと、アジャイル開発のセオリーの通り、職能横断型のチームで臨むことが有効である。

ただここで大切なのは、「チーム」というものの捉え方が少し特殊な事だ。


### 「チーム」と呼ぶな

適応型ソフトウェア開発の文脈では、職能横断型の集団のことを「チーム」と呼称しないこと。

それが参考にした本の冒頭で述べられていた。

これがどういうことなのかを私なりに解釈してみたのでそれをまとめる。

### 職能横断型の集団
クロスファンクショナルな集団。つまり、職能が重複しない別領域を担当できる専門性を持っている人材が集まる集団。

集団の定義から分解していくが、集団とは、複数の個体が集まって構成されるものである。
つまり、集団はただ複数の個体が集まっているだけに過ぎない。

適応型ソフトウェア開発においては、この「集団」には力がないとされる。

ではどのようなものが価値のある集団となりえるのか？

それは、複雑適応系に昇華されることだ。

適応型ソフトウェア開発では、チームや職能横断型組織のことを「複雑適応系」と呼称する。

### 複雑適応系
複雑適応系とは、とある集団が１つの意思を持ち、周りの環境に順応しながら常に営みを継続できる仕組みのことを指す。

職能横断型の集団が１つの意思を持ち、周りの環境に順応しながら常に前進・運営できること。
すなわち、集団から１つ生命体となることが求められる。


### 生命体
運命共同体というのも少し違うのだ。

生命体であることが重要なのだ。

生命体は、内臓の一部が機能不全を起こしたとき、生命体として死に至る。
つまり、集団も同じであり、一部が機能不全を起こしたとき、死に至る。

したがって、複雑適応系に属する個体は、１つの生きる意志に向かって、それぞれの役割を全うし続けること。それが常に求められる。

そうしなければ、複雑適応系としての死を表すためだ。

## 複雑適応系の強さ

複雑適応系の強さとしては、以下の３点があげられる。

### 同一の目的を意識を共有している
適応型ソフトウェア開発では、大きなカオスに立ち向かうため、それぞれが違う立場・役割から１つの目的のために何ができるのかを常に考え続けることが求められる。

そのため、複雑適応系に所属する個体は、それぞれが持ち寄れるすべてを使って、カオスの淵を発見し、解き明かすことが大切である。

### お互いの機能をしっている
自分の突出した専門性を有益に行使し、生命活動を進めるために、効率の悪い動きは避けるべきである。
そのため、役割をお互いに把握し、それをパスしあう働きをすることで、生命体の運用を効率化し、死から身を守ることができる。

### 目的を達成するためにどんな手段を使ってもすべて適応する
目的達成の為なら手段を選ぶことがない。
どんな場面だとしても、自分が目的を達成するのだという強い志を持ち、あらゆる方向から目的達成のためのアイデアを出し続けることができる。


この３つの力を有するチームを形成することが、圧倒的な適応力を発揮することが可能な複雑適応系として位置することができる。

## 複雑適応系の形成
この複雑適応系の形成こそが、適応型ソフトウェア開発において圧倒的に難しいポイントであり、最も時間をかけて取り組むべき有益なポイントでもある。
書籍「プロダクトマネジメントのすべて」をより効果的に使う方法

## プロダクトマネジメントのすべて

:::note alert
**記事内で書籍等のネタバレはありません**
:::

春の [Qiita Conference 2024](https://qiita.com/official-campaigns/conference/2024) の基調講演の中でも話題に挙がった、
**「プロダクトマネジメントの全て(翔泳社, 及川 卓也, 曽根原 春樹, 小城 久美子 著)」** 
は全415ページとプロダクトマネジメントに必要な要素がどっさりと紹介されています。

https://www.shoeisha.co.jp/book/detail/9784798166520

個人的には、この書籍の以下の点はとても大事だと感じています。

:::note
- Core, Why, What, How
- プロダクト志向の組織
- ビジネス形態ごとのふるまい方
:::

## ビジネス形態ごとのふるまい方
つまり、 BtoB や BtoC での戦略の違いが主なのですが、書籍の著者の一人である[**曽根原 春樹**さん](https://x.com/Haruki_Sonehara)の **BtoBプロダクト** に特化した Udemy 講座は BtoBプロダクトの企画を持っている私にとってめちゃくちゃ役立っています！

### プロダクトマネジメント入門講座: シリコンバレーの現役PMが伝授するBtoBプロダクトマネジメント

https://www.udemy.com/course/btob_product_management/#reviews

個人的に最も重要だと感じたのは、BtoBプロダクトの特徴的として、プレイヤーが多くそれぞれに思惑があることを抑えている必要があるということです。

例えば、次のようなプレイヤーに沿って計画・調査します。

:::note
- エンドユーザー
- 購買意思決定者
- インフルエンサー
:::

他にも、
- **MVP (Minimum Viable Product) の磨き込み**
- **見込み顧客の反応が良さそうなのに導入に至らない理由**

など、開発で時間がかかりそうな落とし穴に対策できるようなレクチャーも充実していました。

## 書籍を効果的に使う

私は「**プロダクトマネジメントのすべて**」の中身を全て理解している訳ではないですが、プロジェクトを進める際に調べたり、読み直したりするので、手を伸ばせば届くところに常に置いてあります。

**企画書作成時には必ず使います。**

一方で、今回紹介した講座は全部で5時間ほどのボリュームですが、**レクチャーが数分で区切られている**ものが多く少しずつ学んでいくのに都合が良いです。曽根原さんの講座はこのようなスタイルが多い印象です。

例えば、**KPI** に着目した講座もあります。

https://www.udemy.com/course/practical_kpi/

このような使い方がおすすめです。

::: note
- **曽根原さんの Udemy のPM講座**: 毎日の勉強や特定の領域を深く学ぶ
- **プロダクトマネジメントのすべて**: 仕事の中で辞書的に使う
:::
cloudrunをTerraformで実行してみる

gcloudの設定を行う。
```
gcloud init

gcloud auth login

gcloud config set project 

gcloud auth application-default login
```
をやった後下記のコードをmain.tfに書く。

```

resource "google_cloud_run_v2_service" "this" {
  project  = var.project_id
  name     = "iap-cloudrun"
  location = "asia-northeast1"
  ingress  = "INGRESS_TRAFFIC_ALL"

  template {
    containers {
      image = "gcr.io/cloudrun/hello"
    }
  }
}

data "google_iam_policy" "noauth" {
  binding {
    role    = "roles/run.invoker"
    members = ["allUsers"]
  }
}

resource "google_cloud_run_v2_service_iam_policy" "policy" {
  project     = var.project_id
  location    = "asia-northeast1"
  name        = google_cloud_run_v2_service.this.name
  policy_data = data.google_iam_policy.noauth.policy_data
}

```

projectの部分は直すこと！
fullcalender-rails実装編

## はじめに
今回は、大まかな実装を説明して
別の記事で苦戦した場所などを記載したいと思います。

https://qiita.com/kureha_com/items/f71d955eefc685a796e3

## 参考記事

https://fullcalendar.io/docs/rails

https://github.com/bokmann/fullcalendar-rails
## 機能の概要
今回カレンダーに下記の情報を登録,表示させます。
```ruby:db
    t.string "title"
    t.datetime "time"
    t.text "comment"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
```


## 実装手順
```ruby:Gemfile
gem 'fullcalendar-rails'
```
```bash:bash
bundle install
```
### Model作成
```
bin/railsrails g model Event title:string category:integer time:time comment:text
bin/rails db:migrate
```
### EventModel設定
```ruby
class Event < ApplicationRecord
  validates :title, presence: true
  validates :time, presence: true
  #commentも必要なら設定をする。
end
```

### routes.rbの設定
```ruby
Rails.application.routes.draw do
  root "events#index"
  resources :events
    #これは、date_detailsアクション(日にちの詳細)
  get "events/dates/:date", to: "events#date_details", as: "event_date"
end
```

### controllerの作成
```bash
bin/rails g controller Events
```

### controller設定
```ruby
class EventsController < ApplicationController
  def index
    @events = Event.all 

    respond_to do |format|
      format.html
      format.json do
        render json: @events.map { |event|
          {
            id: event.id,
            title: event.title,
            start: event.time.in_time_zone("Asia/Tokyo").iso8601, # タイムゾーンを変換して送信
            url: event_path(event)
          }
        }
      end
    end
  end

  def date_details
    @date = params[:date]
    Rails.logger.info "Date received: #{@date}"
    @events = current_user.events
                            .where("DATE(time AT TIME ZONE 'UTC' AT TIME ZONE ?) = ?", "Asia/Tokyo", @date)
                            .order(time: :asc)
  end
#　　--- 省略 ---
  private

  def event_params
    params.require(:event).permit(:title, :time, :comment)
  end
end
```
### view実装
> JavaScript（Tailwind + Stimulus.jsの場合）

```bash
bin/rails g stimulus calender
```
```calender_controller.js
import { Controller } from "@hotwired/stimulus";
import { Calendar } from "@fullcalendar/core";
import dayGridPlugin from "@fullcalendar/daygrid";
import interactionPlugin from "@fullcalendar/interaction";
import jaLocale from "@fullcalendar/core/locales/ja";

export default class extends Controller {
  connect() {
    const calendar = new Calendar(this.element, {
      plugins: [dayGridPlugin, interactionPlugin],
      initialView: 'dayGridMonth',
      timeZone: 'Asia/Tokyo',
      locale: jaLocale,
      events: '/events.json',
      selectable: true,
      editable: true,

      dateClick: (info) => {
        const date = new Date(info.date).toISOString().split("T")[0]; // UTC基準の日付を取得
        window.location.href = `/events/dates/${date}`;
      },
    });

    calendar.render();
  }
}
```
### view作成
```bash
touch app/views/events/index.html.erb
```
```index.html.erb
<div id="calendar" data-controller="calendar"></div>
```
http://localhost:3000/events
:point_up:こちらに飛ぶとcalenderが実装できているかと思います。
ChatGPT、Gemini、Claude──巨大テック企業と生成AIモデルの最新動向整理（2024年版）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2631481/51c564f5-a9ba-b661-e1ba-3be12691b0c8.png)

## はじめに
　2022年末のChatGPT公開以降、生成AI分野は急速に発展・拡大しています。2023年以降の動きを振り返ると、OpenAI、Google DeepMind、Anthropicが提供する大規模言語モデル（LLM）は、それぞれMicrosoft、Google、Amazonといった巨大テック企業との密接な連携を通じてエコシステム戦略を深化させています。本記事では、2024年12月時点で明らかになっている確度の高い事実や公式発表をもとに、ChatGPT（OpenAI）、Gemini（Google DeepMind）、Claude（Anthropic）の最新動向を整理します。

## 1. ChatGPT（OpenAI）とMicrosoftエコシステム

### 開発背景
- **OpenAI** は2015年設立。当初は非営利組織としてスタートしたが、営利部門を設けるハイブリッドモデルへ移行。  
- 2022年末にChatGPTを一般公開後、対話型モデルとして世界的注目を集める。  
- 2023年3月には高度化したGPT-4を発表し、幅広いタスク（コード生成、翻訳、要約、ビジネス文書作成など）に対応。

### Microsoftとの関係
- **MicrosoftはOpenAIへ多額投資** を行い、Azure上でOpenAIモデルを展開。  
- Azure顧客企業はOpenAIモデルを容易に利用可能。  
- Bing、Edgeブラウザ、Microsoft 365への統合が進行中で、2023年以降は「Microsoft 365 Copilot」など業務生産性ツールへの生成AI機能組み込みが注目ポイント。

### 最新動向（2023年後半～2024年）
- 2024年12月、OpenAIは次世代モデル「o1」を正式リリース。  
  - コーディング、数学、ライティング領域で大幅性能向上。  
- 「12 Days of OpenAI」イベントで新機能・製品を続々発表。  
- MicrosoftはAzure上の企業向けソリューション強化とBing Chatなど一般向けアクセス拡大を継続中。

## 2. Gemini（Google DeepMind）とGoogleエコシステム

### 開発背景
- GoogleはBERT、PaLM、LaMDAなど先進的LLMを多数開発してきたが、2022年末以降のChatGPT勃興でユーザー向け展開が出遅れたとの指摘も。  
- Google BrainとDeepMindを統合し「Google DeepMind」を設立（2023年4月）。  
- 2023年5月Google I/Oで「Gemini」を予告。高度推論・マルチモーダル対応を目標に据える。

### Googleとの関係
- Google CloudやWorkspace（Gmail、Docs、Sheets、Slidesなど）との統合を強化。  
- 広大なGoogleエコシステムと自然に接続し、既存ユーザーベースへの対話型AI機能浸透を図る。

### 最新動向（2023年後半～2024年）
- 2024年12月、「Gemini 2.0」を発表。  
  - マルチモーダル対応強化（テキスト、画像、音声統合）  
  - AIエージェント「Project Mariner」やコーディング支援ツール「Jules」を導入  
- Google AssistantやNestスピーカーへの統合を進め、日常生活への組み込みを加速。

## 3. Claude（Anthropic）とAmazon・Google支援

### 開発背景
- Anthropicは2021年設立。OpenAI出身者が創業し、安全性・倫理・解釈可能性を重視。  
- 2023年3月ごろよりClaudeを公開、7月には「Claude 2」を発表。  
- 良質なコンテキスト理解・長文処理能力、コーディング支援に強み。

### Amazon・Googleとの関係
- 2023年9月、Amazonが最大40億ドル投資を発表。  
  - AWS上でのClaude活用が容易になり、企業顧客向け展開を強化。  
- Googleも2023年初頭に3億ドル規模で出資。  
  - Google Cloud上でのAnthropicモデル活用を促進。  
- ClaudeはAWSとGoogle Cloud双方で利用できる中立的ポジションを確立。

### 最新動向（2023年後半～2024年）
- Claude 2はSlack、Notionなどビジネス向けツールへの統合が拡大。  
- 長文ドキュメント生成や複雑な質問への対応が評価。  
- Anthropicは透明性ポリシーや安全ガイドラインを積極公開、規制対応や信頼性向上を図る。

## 4. 対立構図の背景──クラウドとAIモデルの統合戦略

- **ChatGPT（OpenAI）**：Microsoft Azure基盤で展開。Bing、Microsoft 365 Copilotなど既存Microsoft製品との連携が強み。  
- **Gemini（Google DeepMind）**：Google CloudやWorkspaceとの統合。検索・Officeスイートとの自然な融合。  
- **Claude（Anthropic）**：AWSとGoogle Cloudを並行サポート。中立的立場で幅広い顧客ニーズに対応。

## エコシステム化と多機能サービス展開

- 各モデルはテキスト生成だけでなく、プラグイン機能による外部ツール統合やコーディング支援、業務特化型AIソリューションなど多面的機能を強化。  
- 企業がどのモデルを選ぶかは、長期的なシステム基盤、運用ポリシー、安全面に直結。

## 安全性・ガバナンス対応の強化

- 2023年以降、各社は透明性レポート、第三者検証、倫理ガイドライン整備でAI利用の信頼性確保を進める。  
- ユーザーと社会からの信頼獲得が、長期的な競争力につながる。

## まとめ

- ChatGPT、Gemini、Claudeは、それぞれMicrosoft、Google、Amazonと連携し、クラウド基盤＋モデル性能＋サービス統合の三位一体で競合。  
- 次世代モデルのリリースやエコシステム拡大が急速に進み、安全性・透明性・ユーザーエクスペリエンス向上が課題。  
- 2024年以降も、この動向は一層加速し、クラウドとAIモデルが密接に絡み合う時代が続くことが予想される。

---

**参考:**  
- OpenAI、Microsoft公式発表  
- Google I/O、Google Cloud Next発表情報  
- Anthropic公式ブログ・プレスリリース  
- 各種テックニュース（2023年～2024年報道）
日本語プログラミング言語Mind は今年2024年で生誕39周年 誕生時コンピュータはどんなだったかを調べてみる

# はじめに
日本語プログラミング言語Mind は今年2024年で生誕39周年。Mindが生誕した1985年にはどんなコンピュータ(パソコン・ワークステーション)が同時代にあったのか調べてみました。あなたの知らないいにしえのパソコンstoriaがいま始まる。


# CPU
## 80X86
* インテル 8086 1978年 16bit
* インテル80286 1982年 16bit
* インテル80386 1985年 32bit
* インテル80486(486DX) 1989年 32bit
日本ではNEC9800シリーズ セイコーエプソンPC-286シリーズ（その陰で富士通・日立など日本の御三家もだまっていなかったがNEC一強の時代が続いた）

## MC68000
* モトローラ MC68000 1980年 16/32bit
* モトローラ MC68020 1984年 32bit
* モトローラ MC68030 1987年 32bit
むかしのMACとかシャープのX68000シリーズ

## SPARC
* サン・マイクロシステムズ SPARC 1987年
正統なるUNIXマシーン搭載プロセッサ

# パソコン・ワークステーション

## NEC9800シリーズ
* PC-8801 1982年 8bit
* PC-9801 1982年 16bit NEC μPD8086（8086互換）5MHz RAM 128KB
* PC-9801VM 1985年 16bit NEC V30 (8086上位互換) 8M/10MHz
* PC-9801RA 1988年 32/16bit 80386 16MHz / V30 8MHz RAM 1.6MB

## EPSON PC-286シリーズ
* PC-286 1987年 16bit 80286 10MHz
* PC-386 1988年 32bit 80386 20MHz

## 富士通 FM-16βシリーズ
* FM-16βFD 1984年 16bit 80186 8MHz RAM 512KB
* FM-16βFDⅡ 1986年 16bit 80286 8MHz RAM 1MB

## Apple Macintoshシリーズ
* Macintosh 128K 1984年 MC68000 7.8MHz RAM 128KB
* Macintosh SE 1987年  MC68000 7.8MHz RAM 1MB
* Macintosh SE/30 1989年  MC68030 16MHz RAM 1MB

## Sun SPARCstationシリーズ
* SPARCstation 1 1989年 富士通 MB86901A/LSI L64801(いずれも製造元違いのSPARC) 20MHz RAM 64MB

# おわりに
いかがでしたでしょうか？まさにこのあたりがMindの稼働環境の世界であった！？
(理系フリマ(3))シンセ先輩からもらったCore 2 duoでArduino UNO3をLチカ(3)(長期記事)



目的

ネットの確認から
Arduino IEDのダウンロード
日本語化
キーボードの日本語配列まで


いろいろ
規模がおおきいのでいろいろ時間が掛った
Arduinoのスケッチみたく5分でできないのだ!!!



●ネットの確認

![o_coq682.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/0fe51bdc-9c88-da90-72e3-bfe3ef136bfa.jpeg)

![o_coq683.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/86e1ef77-5d42-f5fd-aa31-067940a7f4d0.jpeg)


●Arduino IEDのダウンロード

![o_coq684.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/8876d650-f147-ad40-22d5-4d1b2ef04680.jpeg)

![o_coq685.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/720abefe-ee35-d9ff-a129-84ab4dad47e8.jpeg)

![o_coq686.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/810377e5-4084-dea3-d9e8-adbc1edb5716.jpeg)

![o_coq687.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/3361a439-aaf3-dd8e-4aa0-805a5072f8a2.jpeg)

![o_coq688.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/b4b32f1a-4112-33c7-7e10-c53c0c43681e.jpeg)




●日本語化

https://engrmemo.jp/linux/ubuntu-ja/


●キーボードの日本語配列


https://zenn.dev/suree/articles/7768f5b6b871b2
一括処理系のジョブで失敗した話

この記事は [SUPER STUDIO Advent Calendar 2024](https://qiita.com/advent-calendar/2024/super-studio) の 15 日目の記事になります。
# 概要
以前、一括処理系のジョブを実装した際に、ロジックミスで処理が激重になってしまったお話です。
詳細なお話はできないので、ところどころ端折ってお伝えすることになりますがご了承ください。

# 教訓
先にこの話で得た教訓を書いてしまうと
- 利用想定はしっかりヒアリングしましょう
- 一括処理する際はリクエストされたデータをそのまま処理するのではなく、ある程度の単位でチャンクしましょう

という、当たり前のことではありますがこちらになります。
伝えたかったのは上記だけなので、以下は、実際にどういうやらかしをしてしまったのか、自分への戒めを込めて書いた内容になりますので、余談程度に読んでくださると助かります。

# ジョブの要件
Web サーバにて一括登録のリクエストを受け付けて、Batch サーバにて非同期でリクエストされたデータを一括登録するジョブを実装する必要がありました。

## 前提
- Web サーバでリクエストを受けて、Batch サーバでリクエストされたデータを一括登録するジョブを実装
    - Hoge, Fuga の情報が含まれる
- 一括登録には Ruby で Activerecord-import という gem を利用
    - ※Rails6 以上ではバルクインサートが利用可能だが当時は使えなかった
- DB は MySQL5.7
- Hoge, Fuga はそれぞれ別テーブルの情報で、Fuga は Hoge への外部キーが必要
    - 外部キーは Hoge テーブルの id

# 要件に対する課題と解決策
前提に書いてある内容でお気づきの方もいると思いますが、「Activerecord-import x MySQL の場合、関連のあるテーブルをまとめて import できない」という課題がありました。

その課題に対して以下のようなロジックを組んで解決しようとしました(実装時のコードとは若干異なります)
```ruby
# 一括登録用のリストを用意
hoge_lists = []
hoge_keys = []
fuga_lists = []
fuga_hashes = []


# ループ開始
requests.each do |request|
  # request の中身は以下の様な hash イメージ
  # { hoge: { column_a: 'a', column_b: 'b', key: 'xxx' }, fuga: { fuga: 'fuga' } }

  # hoge を生成してリストの格納
  hoge = Hoge.new(request[:hoge])
  hoge_lists << hoge

  # hoge の key を格納
  hoge_keys << hoge.key

  # fuga の hash を生成してリストに格納(hoge の key を一旦 merge しておく)
  fuga_hashes << request[:fuga].merge!({ hoge_key: hoge.key })
end

# Activerecord-import で Hoge の情報を一括登録
Hoge.import(hoge_lists)

# 登録成功した Hoge の情報を key を基に取得
imported_hoge_lists = Hoge.where(key: hoge_keys)

# 登録成功した Hoge の id を Fuga に紐づける
imported_hoge_lists.each do |imported_hoge|
  id = imported_hoge.id
  key = imported_hoge.key

  # fuga_hashes から一旦紐づけた key を基に紐づけ対象の fuga を特定して id を紐づける
  # また、紐づけに 利用した key は削除する
  fuga_hash = fuga_hashes.find{ |fuga| fuga[:hoge_key] == key }
  fuga_hash.merge!({ hoge_id: id }).delete(:hoge_key)
  fuga_lists << Fuga.new(fuga_hash)
end

# Fuga を一括登録する
Fuga.import(fuga_hashes)
```

## 上記ロジックの問題点
上記ロジックの問題点は「リクエストされたデータをチャンクしていないため、`fuga_hashes.find`している箇所が処理件数によって膨大に時間がかかってしまう」ことです。
紐づけ対象を特定するために`find`している処理が100件程度までなら問題ないのですが、1,000件、10,000件と増えるごとに指数関数的に処理に時間がかかることが判明しました。

動作確認時は「せいぜい 100 件程度のリクエストしか来ないだろう」という想定で動作確認していたため、問題が浮き彫りになることはなかったのですが、実運用前のリハーサルで想定以上（たしか、10 万件とか）のリクエストが来ており、ジョブが重すぎるという問題がうきぼりになってしまいました。

## 改修案
そのため、以下のようにリクエストをチャンクするように改善するだけで、ジョブの実行速度が劇的に改善しました。
```ruby
# リクエストを each_sliece で分割
requests.each_slice(100).each do |chuncked_requests|
  chuncked_requests.each do |request|
    # あとのロジックは前述の通り
    ...
  end
end
```
上記のように実装しておくだけで、リクエストが増えても`find`による検索対象は一定になるため、リクエスト件数に応じてジョブの処理時間が指数関数的に増加することはなくなりました。

# 最後に
最後までお読みいただきありがとうございます。
過去の自分のやらかしを戒めを込めて書き起こしました。
この記事が誰かの参考になったり、笑い話になったりしてくれたら幸いです。
【Angular】Computed Signal が更新されない！😵‍💫

## はじめに

v16 から Angular に Signal が導入されました。
シンプルな記述でリアクティブな値を管理でき、非常に便利です。
また、Signal を使った変更検知は、従来の zone.js によるものと異なり、コンポーネントツリー全体を確認する必要がないため、パフォーマンスの向上も期待できます。
しかし、使い勝手が良い反面、注意が必要な現象に遭遇し沼ったため、備忘録として残します。

## Computed Signal とは

Computed Signal とは、Signal から派生した値を持つ読み取り専用の Signal です。
以下のように、`computed`関数を使って定義します。

```typescript
const count: WritableSignal<number> = signal(0);
const doubleCount: Signal<number> = computed(() => count() * 2);
```

## Computed Signal が更新されないケース

Computed Signal を定義時点で、`computed`関数に渡す Signal を評価できないと、更新を追跡できないようです。
配列やオブジェクトのイテレーションメソッドに渡すコールバック関数で Signal を評価する場合、そういったことが起こえます。

以下のように、初期値が`undefined`の配列`undefinedNumbers`のイテレーションメソッド内では、定義時点で `this.count()` を評価できません。
結果、後から`undefinedNumbers`に値を代入しても、`count`の更新を追跡できず、`undefinedComputedSignal`が`undefined`のままになってしまうようです。

```typescript:main.ts
import { Component, computed, signal } from "@angular/core";
import { bootstrapApplication } from "@angular/platform-browser";

@Component({
  selector: "app-root",
  template: `
    <div>undefined computed signal: {{ undefinedComputedSignal() }}</div>
    <button (click)="countUp()">count up</button>
  `,
})
export class App {
  count = signal(0);
  undefinedNumbers: number[];
  undefinedComputedSignal = computed(() =>
    this.undefinedNumbers?.find((number) => number === this.count())
  );

  countUp() {
    this.count.update((count) => count + 1);
    this.undefinedNumbers = [5, 10, 15];
  }
}

bootstrapApplication(App);
```

### 回避策

以下のように、イテレーションメソッドのコールバック関数外で参照を作ってあげると、`count`の更新を追跡してくれます。

```diff_typescript:main.ts
import { Component, computed, signal } from "@angular/core";
import { bootstrapApplication } from "@angular/platform-browser";

@Component({
  selector: "app-root",
  template: `
-   <div>undefined computed signal: {{ undefinedComputedSignal() }}</div>
+   <div>undefined computed signal2: {{ undefinedComputedSignal2() }}</div>
    <button (click)="countUp()">count up</button>
  `,
})
export class App {
  count = signal(0);
  undefinedNumbers: number[];
- undefinedComputedSignal = computed(() =>
-   this.undefinedNumbers?.find((number) => number === this.count())
- );
+ undefinedComputedSignal2 = computed(() => {
+   const count = this.count();
+   return this.undefinedNumbers?.find((number) => number === count);
+ });

  countUp() {
    this.count.update((count) => count + 1);
    this.undefinedNumbers = [5, 10, 15];
  }
}

bootstrapApplication(App);
```

### StackBlitz

検証のために遊んだ StackBlitz を貼っておきます。

https://stackblitz.com/edit/stackblitz-starters-57skebhe?file=src%2Fmain.ts

## おわりに

Computed Signal は定義時に評価した Signal の更新を追跡するようです。
紹介したケースのように、`undefined`, `[]`, `{}`のイテレーションメソッド内に追跡したい Signal を書くと、この不具合の発生リスクがあるため、注意が必要です。

最後に、本記事の内容は、あくまで実験の結果であって、Signalの挙動を保証するものではない点にはご注意ください。

## 参考

- Angular Signals | Angular
  https://angular.dev/guide/signals
- Angular Signals の状態管理！実装パターンと RxJS の相互運用。
  https://ugo.tokyo/angular-signals/
Golang 学習メモ Week3

## 前回までのあらすじ
PaizaスキルチェックでBランク合格できるくらいは書けるようになった。基本的に使う文法は基礎的なもので、問題を解決するアルゴリズムを構築するスキルが求められているのを感じる。これは他言語に通じるものがあるので初めてよかったと思う。

## 今週の学習内容
基礎的な所の復習がメインになっており、余り新規で学んだことが少ない。
レベルアップメニューで適当に書いたコードだけが増えてきているのでGithubにpushした。
[Go勉強用リポジトリ](https://github.com/ysk-kita/Golang_paiza)

命名で悩む時間がもったいなくて、とりあえずローマ字と英語の混在命名というひどいコードになっている。またコピペして改変したfunctionなんかはdocの修正が出来ていないのもある。
なのでリファクタリングはそのうちやりたい。~~多分やらない。~~

### 1. Go Map キー存在チェック
他言語だとこんな感じでcontains等でキーのtrue/falseを返す処理をよく見ると思う。
~~~main.java
if(mp.containsKey("foo")){
    str = mp["foo"]
}
~~~

しかしGolangでは存在チェックと存在するときの値取得を1行で書ける。
これはGolang特有の仕様で、他言語とは違いmapから値を取得する際2つの値を受け取れるためである。
ちなみに値を取得する場合にboolの受取は行わなくてもコンパイルエラーにならない。
>1. マップのキーに対応する値
>2. そのキーが存在するかどうかを示すブール値


~~~main.go
// mp["foo"]で値を取りに行く処理は受け取る第二引数を指定すると存在有無を返す
val, result := mp["foo"]
if result {...}

// if文の外でmapから取り出した値を使わないなら、ifブロックに纏めても良い
if val, result := mp["foo"]; result { ... }
~~~

[Go maps in action](https://go.dev/blog/maps)

### 2. Go ソート処理
sortパッケージをインポートして使う。
昇順なら基本的に `sort.Ints()` , `sort.Strings()`等の用意されている昇順用functionを使うべき。
降順にしたいときは`sort.Reverse()`を噛ます必要があるのだが少しややこしい。

~~~main.go
var s []int = []int{1, 21, 3, 4, 5}
// 昇順
sort.Ints(s)
sort.Sort(sort.IntSlice(s)) // 非推奨
// 降順
sort.Sort(sort.Reverse(sort.IntSlice(s)))
~~~

一応上記の昇順2つの処理は等価。
`Ints()`は内部で`sort.Sort()`を呼び出しており、恐らく可読性向上やシンプルにソートするための関数として提供されている。`Strings()`も同様。

`IntSlice()`は`Sort()`を行うInterfaceとして定義している型で、Int型のSliceを受け取ってキャスト。
その後、Interfaceで定義された並び替え処理を呼び出すという流れ。

> func Ints ¶
func Ints(x []int)
Ints sorts a slice of ints in increasing order.
>
> Note: as of Go 1.22, this function simply calls slices.Sort.

[sort](https://pkg.go.dev/sort#example-Ints)

### 3. Go Replace処理
公式より
>Replace returns a copy of the string s with the first n non-overlapping instances of old replaced by new. If old is empty, it matches at the beginning of the string and after each UTF-8 sequence, yielding up to k+1 replacements for a k-rune string. If n < 0, there is no limit on the number of replacements.

要は何回第二引数を第三引数に変換するかを第四引数で指定する。
一斉置換を使うことが多くなると思うので第四引数は基本的に`-1`になるかな？
~~~main.go
str = strings.Replace(str, "hoge", "Fuga", -1)
~~~

[func Replace ¶](https://pkg.go.dev/strings#Replace)

[Goで文字列の置き換えをする(strings packageのReplace)](https://qiita.com/Sekky0905/items/f0bed43ad3ab4be13385)


### 所感
レベルアップメニューこなしている分には真新しいことは余りなかった。今のところ大体が既存知識の組み合わせでいけている。
細かいアルゴリズムのメニューもPaizaにはあるので、Aランクメニューが終わったらそちらの学習メニューをやる予定。

week2終わった直後にAランクチャレンジしたらBランクと差がありすぎて心傷を負った。
難易度の上がり幅にもうちょっとこう…手心というか…
細かいアルゴリズム構築周りの個人スキルがかなり落ちているのを感じるので年末に実家帰ったら学生時代の教科書を引っ張りだしてこようと思う。

後paizaのコンパイラは`slices`パッケージをサポートしておらずコンパイルエラーになるのだけ何とかしてほしい。マジで。
リスト内の探索処理を問題の度に自前実装するの面倒すぎる。

一応レベルアップメニューとしてはBランクコンプでAランク途中まで。
Aランクの途中で1個だけできていない奴は本当に意味わからないのだが机上デバッグと同一の結果だが入力パターン1つだけエラー判定になっている。
時間あるときに作り直してみるのを検討。

![paiza02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3796391/6e8c381e-4429-0bd5-e2fe-aff0030822ae.png)
![paiza03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3796391/c6f6afe0-a17d-ad36-1d81-1b4a0a45de32.png)
部分ツイートしかできないアプリ

クソアプリ Advent Calendar 2024 に参加しています

https://qiita.com/advent-calendar/2024/kuso-app

くそなぞなぞ Advent Calendar 2024 にも参加しています

https://adventar.org/calendars/10046

# 作ったもの
部分ツイートしかできないアプリです。部分+ツイッターで「部分ったー」です。

https://bubutter.at-math.com/

投稿とお気に入りができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848043/e20e5611-6922-3954-6e3a-f664349add84.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848043/218228f9-28ae-0d80-2320-b6de15d52ca7.png)


# 使用技術

- [Remix](https://remix.run/docs)
- [Prisma](https://www.prisma.io/docs)
- [Tailwind CSS](https://tailwindcss.com/)
挑戦することに対しての考え方

# 初めに
この記事は私が高専4年間での経験から学んだ「挑戦」に対する考え方についての記事です。
※技術に関しての内容はほとんどないですがあしからず。

# 自己紹介
鳥羽商船高等専門学校 情報機械システム工学科 4年

文芸部(1年～)、学生会(3年～)

薄氷をふみながらも留年はしていない。

# 悩む時間があったら挑戦しよう
この見出しがこの記事の全てです。

悩んでいる場合、成果のないまま時間が過ぎていきます。
挑戦した場合、成功や失敗などの経験を得ることができます。

失敗したという経験は貴重なもので、失敗した理由を次に活かすことができるためです。

挑戦という言葉には、「30分歩こう！」や「20分復習しよう！」といったちょっとしたことも入ると考えています。

小さな挑戦からコツコツと続け、経験を積み成長していきましょう。
# 最後に
まとまりのない文章でしたが、読んでいただきありがとうございました。
この記事をきっかけにして新しいことに挑戦してくれる人がいたら幸いです。