OmniAICreator/Qiita-1.07M huggingface dataset:
JaSST'24 Tokai 参加レポート_特別講演編

# はじめに

こんにちは、本田技研工業遠野です。
ソフトウェア内製化チームでQAエンジニアをしています。（QA＝Quality Assurance、品質保証）

先日、ソフトウェアテストのシンポジウム”JaSST'24 Tokai”へ参加してきました。
こちらは特別講演についてレポートします。

# 特別講演：**大規模言語モデル・対話型生成AIによるテスト支援の広さと深さ**

資料が公開されています

https://speakerdeck.com/ishikawafyu/ai-for-testing-2024

■今日の話

特定のタスク・ユースケースで信頼して使えるか？
テストの道具として使う話
一人ひとりが上手く使うのはどんどん進み、自分が賢ければ使える
みんなで使うには？

## テストにおけるLLM型AIの活用

- テスト関連の学術研究例
    - 組み合わせて探索的にテストをやらせる
        - こういうテストはいままでにやりました、次どうしますか？をLLMに考えさせる
        - 試したことないからこれをやってみよう、と提案する
    - 障害記録内の再現手順
        - 実は2ステップ入っていたり、ステップを飛ばしたりされるのが人間の書き方
        - AIが常識をもって自動処理する
        - 構造化して統計分析する
    - 学生さん：「消防車」観点をGPTに出させる→それを画像生成させる→消防車を認識できるか試す
    - 学術界だけでなく、産業界でのツール適用、展開も多い。バンバン出てきているのが現状
- LLMのおかげでかなりなんでもやらせてみることはできる
    
    が、LLMだけにやらせやり、本来人間が3ステップでできるものを、すっ飛ばして結果だけやらせるのは上手くいくわけではない
    
- プロンプトがあればすぐできる時代なので、逆にいうとかなりのスピード感
    - たくさんのデータを集めてやったり、準備が必要だったりは以前と比べたらやらなくてよくなっている
- 形式化だけやらせて、以降は人間でやる（従来技術へつなげる）
- みんな使いたくなっている

## 適材適所の自動化・支援技術を使いこなす

- 道具だから技術的な側面もふまえてやる必要がある
- 論理パズルであるものはそれ用の処理をかませる
- ランダムは強いが、論理的なルールを守ったり定量指標を上げるなら従来技術（とLLMを組み合わせたもの）が強い可能性が高い

## LLM＋既存技術には夢がある

- 試すだけなら、やろうと思えば今日いますぐにできる世界なので「やらせてみる」ことは簡単
    - ものすごいスピード勝負になっているので、あーだこーだ唸るくらいならさっさと試したほうがいい
    - 手を動かす人が多いほうが勝ち
- 一方で、できないこともある
    - 人間がAIの出力を確認してなおせば役立つが、それっぽいものが出ました以上です、というのは成り立たない
    - ★やってみたあとに、「評価して改善する」というのができないといけない
        - 例えば、「テスト観点をAIにあげさせた。その観点がいいものか5段階で評価してください」
        - 人間の場合どうやってつけるのか？
        - 人間でも評価がわかれるものを評価して改善することが必要なので、どうするか
- LLM-as-a-Judge
    - このテスト観点について、◯◯の意味での網羅性があるとともに、挙げられたものに対して矛盾がなければ5点、の評価を自動でさせる
    - LLMが出した結果をLLMに評価させる
        - これだけだと、AIがかしこかったらすごいけどだめだめだったらだめなものができあがる、、
        - テストをつくるAIと、いいテストか評価するAI
        - 少なくとも片方は人間が見張らないといけない
- LLMOps
    - 活動の90％は「評価」
    - 主役はテスター（開発者ではない）

## 感想

やってみるだけならすぐできる状態であり、ものすごいスピート感だ、というところが印象的でした。
労力をもう今すぐ外注できる状態なのだと思いました。
ただやはり人間が判断することが必要だという点は、基調講演での話と同じだと思うので、
テストを上手くなろうと思いました。

# おわりに

感想と被りますが、これまでどこか遠い話のように聞いていたことが、
かなり近くまできている（もはやすでに通り越されている？！）ように思いました。
時代の最先端にいると思うと楽しいですね！
試すモチベーションが上がった講演となりました。

特別講演に関するレポートは以上です。
チームで活用できるAIプロンプトテンプレート

## はじめに  

AIサービスを活用してチームの業務効率化やコミュニケーション向上を目指すためにいくつか考えたプロンプトテンプレートの備忘録として記事にします。
ChatGPTやGithubCopilotといったAIサービスをそのまま使っての効率化も良いですが、目的に応じたテンプレートを考え作成し、日々の業務やタスクにAIを取り入れることも積極的に行っていけると良いですね。

## 1. 雑談テーマを考えるプロンプトテンプレート  
### **目的**  
デイリーミーティングの開始時など、アイスブレイクやチーム内での雑談を活性化し、コミュニケーションの質を向上させる。  

### **テンプレート**  
```text
あなたはチームでのアイスブレイクの進行役です。以下の条件に沿って、会話が弾む雑談テーマを考えてください。

条件:  
- チーム全員が参加しやすい  
- 楽しい、もしくは興味深い内容  
- 専門知識を必要としない  
- 日常の出来事、趣味、シーズンイベントなどを含める  

例: 「最近読んだ面白い本や漫画は？」「もし1週間休みが取れたら何をしたい？」「おすすめのアプリや便利なサービスは？」  

**出力**:  
複数の雑談テーマをリスト形式で提案してください。

```

## 2. 日報の内容をチェックするプロンプトテンプレート  
### **目的**  

日報の内容が適切で、進捗や課題がチームに正確に共有されているかを確認する。  

### **テンプレート**  
```text
あなたはチームリーダーです。以下の日報内容について、次の観点でチェックを行ってください。

入力:  
「{日報内容}」  

チェック観点:  
1. 作業完了の日程が明確に示されていますか？  
2. 進捗がわかる具体的な内容になっていますか？  
3. 課題や障害についての記載はありますか？  
4. 課題に対する次のアクションや予定は示されていますか？  

**出力**:  
- 各観点についての評価 (Yes/No)  
- 改善すべき点や提案を簡潔にまとめてください。
```

## 3. 分報の課題をもとに解決策を考えるプロンプトテンプレート  
### **目的**  
分報で共有された課題に対して迅速に解決策を提示し、チームメンバーの作業を支援する。  


### **テンプレート**  
```text
あなたは技術サポートのAIアシスタントです。以下の課題に対する解決策や解消手順を考えてください。

課題内容:  
「{分報の課題内容}」  

出力内容:  
1. 課題の概要を整理してください。  
2. 解決策や手順をステップバイステップで提案してください。  
3. 必要に応じて追加の確認事項や注意点もまとめてください。
```

## 4. 学びや要約を含む投稿内容を考えるプロンプトテンプレート  
### **目的**  
共有する記事やリンクを要約し、学びや気付きを含めた価値のある投稿を作成する。  
### **テンプレート**  
```text
あなたは知識共有のための投稿アシスタントです。以下のリンク記事を元に、他のメンバーが理解しやすいよう要約し、学びを含む形で投稿内容を作成してください。

入力:  
リンク記事の内容:「{記事の内容概要}」  

出力:  
1. 記事の要約を簡潔にまとめる (3～5行程度)。  
2. その記事から得られる学びや気付き、ポイントを2つ以上挙げる。  
3. チームが参考にすべきアクションやヒントを提案する。

フォーマット例:  
- **記事タイトル**: {タイトル}  
- **要約**:  
  - 内容1  
  - 内容2  
- **学びや気付き**:  
  1. 学び1  
  2. 学び2  
- **参考になるアクション**:  
  「〇〇の改善に役立つ」「作業効率化に使える」など。
```

## 5. 記事投稿で内容の大枠を作るプロンプトテンプレート  
### **目的**  
記事の執筆を効率化し、大枠を素早く整えることで投稿作成を支援する。  
### **テンプレート**  
```text
あなたは記事構成のサポートAIです。以下の内容を元に、記事の大枠を作成してください。

入力:  
「{書きたい記事の内容やテーマ}」  

出力:  
1. 記事のタイトル案を3つ提案してください。  
2. 記事の構成 (見出しレベル) を考え、章立てをリスト形式で示してください。  
3. 各章の概要 (1～2行程度) を添えてください。

フォーマット例:  
- **タイトル案**:  
  1. タイトル案1  
  2. タイトル案2  
  3. タイトル案3  

- **構成案**:  
  1. 導入: {概要}  
  2. 背景: {概要}  
  3. メイン内容: {概要}  
  4. 学び・まとめ: {概要}  
```

## おわりに  

まだ試行開始で具体的な生産性向上といった結果までは語れませんが、日常の業務やタスクにAIを取り入れ効率化をはかるという意識の定着には貢献してくれそうだと感じています。
引きこもりでもキャンプを楽しむ方法

# みんなー！！！！ハッピーホリデー！！！！
みなさん、こんにちは。キャンプ楽しんでますか？
私は月に一回ぐらいのペースでキャンプに行っています。
キャンプって楽しいですけど、一つ問題がありますよね。

![キャンプってぶっちゃけめんどくさい](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/9ffd9b31-fe3e-3605-55e1-e3a801bea2f7.png)

と思ったことはありませんか？私は毎回思ってます。
そんな悩みを解決するのがこちらのWebサイトです。

# 家でもどこでもキャンプが楽しめる「どこでもキャンプ」
![Frame.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/c664b947-fc6c-e318-30a3-cfffbe6a49b4.png)
https://camp.umiremix.com/

「どこでもキャンプ」は世界中のキャンプ場がランダムに表示され、家に居ながらキャンプ場の景色を楽しむことができます。
表示された景色をヒントに、どこのキャンプ場か予想してみましょう！

※こちらは[クソアプリ Advent Calendar 2024](https://qiita.com/advent-calendar/2024/kuso-app)のために作られたジョークWebサイトです。

## 機能1：世界中のキャンプ場のストリートビューがランダムで見れる

![FireShot Capture 001 - どこでもキャンプ - camp.umiremix.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/41eaad41-c65e-db34-a2de-3f4dc2bbd2bd.png)
これはノルウェーのキャンプ場。

![FireShot Capture 002 - どこでもキャンプ - camp.umiremix.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/2fda91fd-85f3-4ba4-d8eb-6ff4b1e3a7f7.png)
これは福島のキャンプ場。

![FireShot Capture 003 - どこでもキャンプ - camp.umiremix.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/253e9bbe-36d4-79b2-44b5-04bfdff4c296.png)
これは海外…と見せかけて和歌山のキャンプ場。

## 機能2:BGMを選べる

![FireShot Capture 004 - どこでもキャンプ - camp.umiremix.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/38c72dd4-82ce-0435-4c7c-3eae8141787a.png)
BGMをつけることでより臨場感を味わえます。


# 使用技術
- Nuxt3
- Firebase（Hosting・Analytics）

本当はGoogleMapAPIでキャンプ場を取得して自動でストリートビューを表示させたかったのですが、キャンプ場の緯度経度にストリートビューが存在することのほうが珍しく、ほとんど真っ黒になってしまいました。
なので自分で良さげなキャンプ場のストリートビューを探してきてiframe貼り付けるというベリーハードコーディングです。
良さげなストリートビューを探してくるのが一番時間かかりました。

# さいごに
![note.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62182/c205a76b-0e74-6610-c5ce-3cbaaea58627.png)
Kuberuという[キャンプSNS](https://kuberu.app/)も作ってます。
キャンプ好きな人はぜひ使ってみてね。

以上です。良いお年を〜👋
【Gemini DeepSearch VS ChatGPT Search】小さいバグに対する解決提案比較

注意；この記事はサンプル数も少ないしょうもないものです。一例として捉えてください。

# 【Gemini DeepSearch VS ChatGPT Search】  
結論：ググったら解決するレベルの小さいバグは、意外とChatGPTが勝つときがある。

こんにちは。今回は、VS Code 上で iOS アプリ開発を可能にする拡張機能 **SweetPad** の参照エラー対策について、**Gemini DeepSearch** と **ChatGPT** のそれぞれに解決策を質問・検索して比較してみた話です。  
結果的に、**「意外とChatGPTが勝つときがある」** という結論にいたったので、その理由を共有します。

---

## 実際に得られた回答例

### ChatGPT からの回答例

以下は ChatGPT が提示してくれた手順の一部です。

1. **必要ツールをインストール**  
   - SweetPad拡張機能＆Swift拡張機能  
   - Homebrew / xcode-build-server / swift-format など  
2. **ビルドサーバーの設定**  
   - コマンドパレットから `SweetPad: Generate Build Server Config` を実行し、`buildServer.json` を生成  
3. **フォーマッタの設定**  
   - `.vscode/settings.json` にて `[swift]` の `editor.defaultFormatter` を "sweetpad.sweetpad" に設定し、フォーマットを有効化  

ポイントは、**「最低限やるべきこと」** を簡潔にまとめてくれていることでした。これだけでも多くの参照エラーが解消される可能性が高いようです。

---

### Gemini DeepSearch からの回答例

Gemini DeepSearch は検索エンジン的に幅広い情報を収集してくれるため、

- 「フォーラムではこう…可能性は、、」

と、非常にたくさんの情報をまとめてくれました。

しかし、**情報量が多すぎるあまりに中身が複雑化** してしまい、  
「結局どの手順を最優先に試せば良いか分からない…」  
という状況に陥りがちでした。初心者にとってはハードルが高くなってしまうケースがあったように思いますし、さらに、たくさん書いてるのに解決策がないこともあった。
さらに、こちらでQiitaなどと指定しないと、そこから探してくれなくて、変に複雑な処理をしてました。

---

## なぜ「意外とChatGPTが勝つ」ことが起こったのか？

### 原因の分析

1. **GPTは、元来の「Google検索的」アルゴリズムをシンプルに活用している**  
   - もちろん厳密には別物ですが、少ない情報でも「こうすればOK」という要点を抽出するのが得意です。  
   - 結果として、初心者が最初に試したい手順を **コンパクトに提示** してくれる傾向があります。

2. **Geminiは、Googleのリサーチ力が強みゆえに、情報量が膨大**  
   - 多数のブログ、Zenn、Qiita、公式フォーラムなどを大量に参照してまとめてくれるため、**情報は網羅的**。  
   - しかしその分、**整理されていない大きな塊** として見えてしまう。さらに必要な情報がない。どこから取り掛かればよいか迷うケースがありました。さらに優先順位もかなり微妙です。

3. **今回のテーマ（SweetPad参照エラー）においては、ChatGPTの「シンプルに最短ルートを教えてくれる」方が的確だった**  
   - 実際には Gemini もほぼ同じ情報を返しているのですが、重複情報や古い記事等の影響で混乱する要素が多く含まれてしまった印象です。あと、それがめちゃくちゃ薄くて、薄く広くになっていました。
   - 結果的に「ChatGPTの提示手順のほうがわかりやすく動かしやすいじゃん」という状況になりました。

---

## まとめ

- **Gemini DeepSearch** は幅広く情報を収集してくれる強みがある反面、**情報過多** で初心者に難解に見える場面がある。  
- **ChatGPT** は「必要最低限」を押さえた提示をしてくれる傾向があり、今回のような **エラー解消の最短ルート探し** には有用だった。  
- 結果として、**「意外とChatGPTが勝つときがある」** という結論になったのは、ほぼ凡ミス・初期設定ミスをシンプルに解決できたかどうか、が大きかった。

---

## 考察：今後、この課題はほぼ確実に解決される

今後、Gemini DeepSearch もアップデートを続けることで、  
- **ユーザーの求める手順をシンプルにまとめる要約力** が進化  
すると考えられます。

一方、ChatGPT も日々改善が進んでおり、  
- 最新のプラグインとの連携  
- ユーザーからのフィードバック機能  
などによって、よりピンポイントな回答を返せるようになる可能性が高いです。

今はまだ「ChatGPTの方がわかりやすかった」というケースもあるかもしれませんが、将来的には **どちらも初心者が使いやすい形へ進化** していくでしょう。  

**皆さんもぜひ、Gemini DeepSearchとChatGPTの両方を使い比べてみてください。** それぞれの強みと弱みを知って活用すれば、もっと効率的に問題解決できるはずです。

---

以上、「Gemini DeepSearch VS ChatGPT Search 〜 SweetPad参照エラー解消編」というテーマでお送りしました。  
参考になれば嬉しいです！何かご質問などありましたら、コメントで教えてください。
【簡単！】SVG をレスポンシブにする方法

本記事では `SVG`を Web ページの幅に合わせて、画像の大きさを変える方法を解説します。

`SVG`（Scalable Vector Graphics）は、ベクター形式の画像フォーマットです。拡大縮小しても画質が劣化しないため、Webデザインにおいて非常に人気があります。

まずは SVG の基本要素を説明します。

#  SVGの基本要素
SVG要素には、いくつかの重要な属性があります。ここでは、`width`、`height`、および `viewBox` について説明します。

## width と height
`width` と `height` 属性は、SVG 要素の幅と高さを指定します。これらの値はピクセル単位で指定され、表示される領域のサイズを決定します。

```xml
<svg 
    width="400" 
    height="300" 
    xmlns="http://www.w3.org/2000/svg" 
    viewBox="0 0 800 600"
></svg>
```
上記の例では、SVG要素の幅が 400 ピクセル、高さが 300 ピクセルに設定されています。

## viewBox
**viewBox 属性**は、SVG の**内部座標系**を指定します。
viewBox は SVG の内部に仮想的なキャンバスを設定し、その中で描画する要素（例えば、`<rect>` や `<circle>` など）の位置とサイズを制御するものです。



viewBox は4つの値を持ちます。
```xml
<svg viewBox="min-x min-y width height">
```
- `min-x` と `min-y`：仮想キャンバスの左上の座標
- `width` と `height`：仮想キャンバスの幅と高さ


```xml
<svg viewBox="0 0 200 200" width="100" height="100" xmlns="http://www.w3.org/2000/svg">
    <circle cx="100" cy="100" r="80" fill="green" />
</svg>
```
この例では、`viewBox="0 0 200 200"` と設定されています。この仮想キャンバスは、**実際の表示サイズ（`100x100 ピクセル`）にかかわらず**、SVG の内部では `200x200` の領域として扱われます。

# SVG をレスポンシブにする方法
レスポンシブにする方法は非常に簡単です。

`width` と `height` を明示的に設定しないことです。これにより、`SVG` は親要素のサイズに応じて自動的に調整されます。

設定した場合、その幅や高さで固定されます。

```xml
<svg viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg">
    <rect x="50" y="50" width="300" height="200" fill="orange" />
</svg>
```


より細かく設定したい場合、`width="80%"` のように `%` 表記を使用します。


```html
<style>
    .svg-container {
        width: 80%; /* 親要素の幅を指定 */
        margin: 0 auto;
        border: 1px solid #ccc;
    }
    svg {
        width: 100%; /* 親要素に合わせて拡大縮小 */
        height: auto; /* アスペクト比を保持 */
    }
</style>

<div class="svg-container">
    <svg viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg">
        <rect x="50" y="50" width="300" height="200" fill="orange" />
    </svg>
</div>
```
【PHP】GitHubのスターカウンターを作ってみた

# GitHub Star Counter
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1015774/b08c42d6-c4c4-0397-f310-4cc6832659e2.png)

## 使い方
```
https://github-pitan76-star-counter.glitch.me/?user=(ユーザー名or組織名)&w=(横幅)
```

## 使用例

`https://github-pitan76-star-counter.glitch.me/?user=PTOM76&w=320`
![PTOM76 Stars](https://github-pitan76-star-counter.glitch.me/?user=PTOM76&w=320)

## ソースコード
https://github.com/PTOM76/github-pitan76-star-counter

### GitHub API
GitHubから提供されているREST APIを用いてリポジトリの一覧のjsonを取得できる。
リポジトリの一覧にあるリポジトリにはstargazers_countというデータが含まれており、それを用いることでスター数を取得できる。

https://docs.github.com/ja/rest/repos/repos?apiVersion=2022-11-28#list-repositories-for-a-user

- パラメータ
    - page - ページ番号
    - per_page - ページあたりの結果数
    - sort - 順番

```
https://api.github.com/users/(ユーザー名or組織名)/repos?page=1&per_page=100&sort=updated
```

### スターカウント用の関数
つくったコードから抜粋してきました。
GitHub APIを用いてユーザー/組織のスター数の合計を取得します。(ただし、更新された順に100リポジトリまで)

```php
function getTotalStars($username) {
    $url = "https://api.github.com/users/$username/repos?page=1&per_page=100&sort=updated";

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, ['User-Agent: PHP']);
    $res = curl_exec($ch);
    curl_close($ch);

    $repos = json_decode($res, true);

    if (isset($repos['status']) && $repos['status'] == "404")
        return 404;
  
    $stars = 0;
    foreach ($repos as $repo) {
        $stars += $repo['stargazers_count'];
    }

    return $stars;
}
```

### GdImageからBase64形式への関数
GdImageをbase64に変換する関数です
ob_start、ob_get_contents、ob_end_cleanを使えばそのまま出力せずにバッファとして変数に保存できます。

```php
function base64_image($image) {
    ob_start(); // 出力のバッファリング開始
    imagepng($image); // 画像を出力
    $raw = ob_get_contents(); // 出力されたバッファを変数に代入
    ob_end_clean(); // 出力のバッファリングを終了
    
    return 'data:image/png;base64,' . base64_encode($raw);
}
```

## 最後に
つくったスターカウンターは100リポジトリまでしか処理しないので、完全なものを作りたい場合はpageを使う必要がありそう。(個人用につくったものなのでそこらへんは考慮してませんでしたが)

glitch.comで動かしているのですが、いつかGitHub Actionsだけでカウンターを動かしている人も見かけたことがあるのでやってみたいですね
CES 2025: 位置情報技術がもたらす自動車と物流への貢献

こんにちは。
今回は、2025年1月7日〜10日にラスベガスで開催されるCES 2025に関する情報と、HEREの取り組みについてご紹介します。

[HERE at CES 2025](https://www.here.com/learn/events/ces-2025) | Discover how a unified live map unlocks automotive and logistics innovations.

## CES 2025とHERE Technologiesの概要  
CES（Consumer Electronics Show）は、毎年ラスベガスで開催される世界最大級の技術展示会です。2025年も、最新のイノベーションやテクノロジーが集結します。HERE Technologiesは、今年もCESに出展し、モビリティや物流、スマートシティにおける革新的なソリューションを展示します。
開催期間：
　2025年1月7日（火）～10日（金）　（米国東海岸時間）
　January 7-10, 2025 | Las Vegas
公式サイト：

https://www.ces.tech/

HEREブース：　ラスベガス・コンベンション・センター　西ホール3500番ブース

https://www.here.com/learn/events/ces-2025


### HEREブースでの注目展示内容  
#### ソフトウェア定義車両（Software-defined vehicles）  
デジタルコックピット、運転支援、自動化に関する最新の進展を紹介します。これらは顧客のニーズを満たし、安全性と効率を向上させ、市場差別化を推進するために設計されています。また、HEREの統合マッピングアーキテクチャがどのように安全性、快適性、予測可能性を向上させるかをご確認いただけます。

#### モビリティの電動化（Electrification of mobility）  
HEREがどのように自動車およびトラックOEMにプレミアムなデジタルコックピット体験を提供し、電動化の主要な課題を克服するのかを学びましょう。車両やその環境の変数を取り入れたカスタマイズ可能なアプリケーションを実現するHEREの柔軟性と制御力をご紹介します。

#### エンドツーエンドの物流（End-to-end logistics）  
HEREのデータとソフトウェアが、フリートやサプライチェーン企業のAIモデルを強化し、ソフトウェアの成熟度を向上させる方法をご紹介します。精度と制御を高めることで、HEREが新しいレベルの資産可視性とETA精度を提供し、効率的な配送を日々数百万回にわたって実現する方法をぜひご確認ください。

---

## 日本関連の事例紹介 – カワサキモータース & パイオニア  
CES 2025のHEREブースでは、直近でアナウンスされた以下の事例も紹介されます。

### カワサキモータースとの事例  
カワサキモータースの最新モバイルアプリにHEREの位置情報技術を活用。ライダーに向けた充実したナビゲーション機能とカスタマイズ可能なルート情報を提供します。  
[カワサキモータース、HERE Technologiesのモバイルアプリ統合グレードアップでライダー体験をさらに改善](https://www.here.com/jp/about/press-releases/ja/Kawasaki-Motors-boosts-rider-experience-with-HERE-in-mobile-app-upgrade)

### パイオニアとの協業  
パイオニアとHEREは、二輪車向け「Smart & Safety Ride」ソリューションを共同で開発。AIを活用した安全性向上や、スマートディスプレイとのシームレスな連携を実現します。
[パイオニアとHERE、二輪車コネクテッドソリューションでグローバル協業](https://www.here.com/jp/jp/about/press-releases/Pioneer-and-HERE-join-forces-on-connected-mobility-solutions)

さらに、**パイオニアのブース**でも、HEREの技術を活用したデモが展示される予定です。  

パイオニアブース　：　ラスベガス・コンベンション・センター　西ホール3528番ブース
[パイオニア、「CES 2025」に出展　～SDV時代に向けたサウンド統合プラットフォームや、二輪用コネクテッドソリューションを初公開～](https://prtimes.jp/main/html/rd/p/000000930.000005670.html)

---

## 皆様へのご案内  
私はCESの現地におりますので、会場でお会いできればぜひお気軽にお声がけください！  
また、日本帰国後には、CESの最新情報をシェアする機会を多く作りたいと思っています。興味のある方はぜひご連絡ください。

一緒に未来のモビリティを創造していきましょう！
ABC385Cをjavascriptで解いた

# [今日の問題](https://atcoder.jp/contests/abc385/tasks/abc385_c)
↑押してください。
# 自分の回答(javascript)
```javascript
function Main(input){
  min = 1e18
  max = 1
  let abc = "abcdefghijklmnopqrstuvwxyz".split("")
  let ABC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("")
  let f = 2
  if(f == 0){
    input = parseInt(input.trim())
  }
  if(f == 1){
    input = input.trim().split("\n").map((a)=>parseInt(a))
  }
  if(f == 2){
    input = input.trim().split("\n").map((a)=>a.split(" ").map((b)=>parseInt(b)))
  }
  if(f == 3){
    input = input.trim().split("\n")
  }
  n = input.shift()[0]
  let hlist = input.shift()
  for(let i = 0;i<n;i++){
    
    a = hlist[i]
    for(let j = 1;j<n;j++){
      count = 0
      
      for(let k = i;k<n;k += j){
        
        
        if(hlist[k] != a){
          break
        }else{
          count ++
          max = Math.max(max,count)
        }
      }
    }
  }
  console.log(max)
}
Main(require("fs").readFileSync(0, "utf8"));
//ここより上は定型文です。
```
# 工夫した点
Nが3000以下であるという制約であるため、全探索が可能である。どこから始めるかと、何個おきであるかを2重ループで解く。何個おきであるかは素数しか可能性がないためそっちでやったほうがより効率は良いが、今回はそこまでやらなくても時間制限に間に合う。
2024年のElixir⑦2024年末までのElixirができることを振り返る

この記事は、[Elixir Advent Calendar 2024 シリーズ13](https://qiita.com/advent-calendar/2024/elixir) の18日目です

昨日は、私で、[「2024年末のElixir⑥AI・LLMトレンドから2025年のElixir AI・LLMを占う編」](https://qiita.com/piacerex/items/4f905750861da27589b7) でした

---

[piacere](https://twitter.com/piacere_ex) です、ご覧いただいてありがとございます :bow:

2024年末の時点で、Elixirにいったい何が出来るのかを紐解いていくシリーズで、[前回は「2024年末のElixir⑥AI・LLMトレンドから2025年のElixir AI・LLMを占う編」](https://qiita.com/piacerex/items/4f905750861da27589b7) でしたが、最終回の今回は「⑦2024年末までのElixirができることを振り返る」です

# ①2024年の新たなライブラリ／FW編

2024年に新たにリリースされたElixir／Phoenix／LiveView／LivebookライブラリやFWのご紹介

Elixir内でPythonを直接利用するためのライブラリや、動画配信のMembrane関連、今年のLTでハンズオンしたSaladUIやTremorxも今年がお初

https://qiita.com/piacerex/items/17c5cab114f89f11ff68

# ②2024年に更新されたライブラリ／FW編

2024年にアップデートされたElixirのライブラリ／FWは、昨年の3.2倍である計4,066本もあり、その中から10本、ピックアップしました

[昨年コラム](https://qiita.com/piacerex/items/0c6ffb235e1146c38302) は、わりかしメジャーどころを狙った一方、今年のはややマニアックなものを挙げてます

https://qiita.com/piacerex/items/78fc907c0b44cf3dda15

# ③2024年のLivebook＋プラグイン編

Livebook is 何を説明の後、今年リリース or アップデートされたLivebookプラグインの中からキャッチーな13本をピックアップしました

今年はFigma連携やGoogleスプレッドシート連携など、昨年同名コラムに無い面白系が増えてます

https://qiita.com/piacerex/items/9f2d465af90f76d08ade

# ④2024年のクラウドライブラリ編

2024年にアップデートされたElixirの3大クラウド向けライブラリ／FWのうち、18本をピックアップ

各クラウド向けElixirライブラリの探し方についても軽く文字化しているので、Elixirでクラウド開発する場合は、読んでおくと良いです

https://qiita.com/piacerex/items/3450ac62a03da69b3327

# ⑤2024年のWeb／スマホ／マイクロサービス編

2024年にアップデートされたElixirライブラリの中から、Web／スマホ／マイクロサービス用のものを7カテゴリに分けて40本ピックアップ

ElixirでWeb／スマホ／マイクロサービス開発する際に便利なものを集めているので、良かったらお試しください

https://qiita.com/piacerex/items/67ebb6d5979e6a3cc34f

# ⑥2024年のAI・LLMトレンドから2025年のElixirを占う

今年1年のAI・LLMのトレンドをガッツリ追いつつ、2024年にElixir AI・MLが関わってる点から2025年を占いました

2024年末のAI・LLMシーンをサクッと把握できるので、Elixirに興味無くても面白い読み物だと思います

https://qiita.com/piacerex/items/4f905750861da27589b7

# p.s.このコラムが、面白かったり、役に立ったら…

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155423/907a8695-4d83-1b5c-8052-d0ce52de5f66.png) にて、どうぞ応援よろしくお願いします :bow:

---

明日は、 @GeekMasahiro さんで [「Ash Frameworkを知る第一歩！65ページ資料から抽出した2つの重要なポイント」](https://qiita.com/GeekMasahiro/items/fc0b81462745a570a718) です
ABC385Bをjavascriptで解いた

# [今日の問題](https://atcoder.jp/contests/abc385/tasks/abc385_b)
↑押してください。
# 自分の回答(javascript)
```javascript
function Main(input){
  min = 1e18
  max = -1e18
  let abc = "abcdefghijklmnopqrstuvwxyz".split("")
  let ABC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("")
  let f = 3
  if(f == 0){
    input = parseInt(input.trim())
  }
  if(f == 1){
    input = input.trim().split("\n").map((a)=>parseInt(a))
  }
  if(f == 2){
    input = input.trim().split("\n").map((a)=>a.split(" ").map((b)=>parseInt(b)))
  }
  if(f == 3){
    input = input.trim().split("\n")
  }
  //ここより上は定型文です。
  let [h,w,x,y] = input.shift().split(" ").map((a)=>parseInt(a))
  let t = input.pop().split("")
  s = input.map((a)=>a.split(""))
  x--
  y--
  map = new Map()
  map.set("U",[-1,0])
  map.set("D",[1,0])
  map.set("L",[0,-1])
  map.set("R",[0,1])
  set = new Set()
  count = 0
  for(let i = 0;i<t.length;i++){
    //console.log(map.get(s[i]),s[i])
    //console.log(x+1,y+1)
    ny = y + map.get(t[i])[1]
    nx = x + map.get(t[i])[0]
    if(0<=ny&&ny<w&&0<=nx&&nx<h&&s[nx][ny] != "#"){
      y = ny
      x = nx
      if(!set.has(ny+" "+nx)&&s[nx][ny] == "@"){
        count ++
        set.add(ny+" "+nx)
      }
    }
  }
  x ++
  y ++
  console.log(x,y,count)
}
Main(require("fs").readFileSync(0, "utf8"));

```
# 工夫した点
一度訪れたマスはsetで管理して2重でカウントしないようにしています。いつもとxとyが逆であるため注意が必要です。
ABC385Aをjavascriptで解いた

# [今日の問題](https://atcoder.jp/contests/abc385/tasks/abc385_a)
↑押してください。
# 自分の回答(javascript)
```javascript
function Main(input){
  min = 1e18
  max = -1e18
  let abc = "abcdefghijklmnopqrstuvwxyz".split("")
  let ABC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("")
  let f = 1
  if(f == 0){
    input = parseInt(input.trim())
  }
  if(f == 1){
    input = input.trim().split(" ").map((a)=>parseInt(a))
  }
  if(f == 2){
    input = input.trim().split("\n").map((a)=>a.split(" ").map((b)=>parseInt(b)))
  }
  if(f == 3){
    input = input.trim().split("\n")
  }
  //ここより上は定型文です。
  input.sort((a,b)=>a-b)
  
  if(input[2] == input[1]+input[0]||(input[1] == input[2] && input[1] == input[0])){
    console.log("Yes")
  }else{
    console.log("No")
  }
}
Main(require("fs").readFileSync(0, "utf8"));

```
# 工夫した点
条件に合うのは3つがすべて同じ数か、一番大きい数とその他の2つの数の和が等しいときであるため、sortしてから比べると簡単に求めることができます。
だから私はStripe 決済サービスの選び方 開発者にとって使いやすい決済サービスを使うべし

# はじめに
はじめましてidavashです。OriginallyTeeというオリジナルTシャツの作成・購入・販売ができる以下ECサイトの作成・運用をしています。

https://originally-tee.com/

ECサイトには決済機能が必須です。その実装は、外部の決済サービスを利用して行うことになります。

なのでまずは決済サービス選びからスタートするのですが、決済サービスは沢山あり、各々が自社の魅力を謳っているのでどれを選んで良いのかわからなくなります。

そこで今回は、多くの決済サービスをどのように比較検討したかを開発者目線も含めて語っていきます。

**※なお比較検討を行ったのは2023年ですが、本記事は2024年12月の情報に基づいて書かれています。**

重視したのは以下の4ステップです。

1\.信頼性
2\.対応決済手段
3\.手数料
4\.システム連携のしやすさ　←ここが開発者には重要

1~3は事業目線の項目ですが、4は開発者目線ですね。

1~3を満たすサービスの中で、4の比較をした結果、最も優れていたStripeに決定しました。

そこで得た結論は、**開発者にとって使いやすい決済サービスを使うべし。それが事業にとっても重要**ということです。

ステップ順に説明します。

# 1.信頼性
お客様から支払いを受ける以上、信頼できる決済サービスであることは必要不可欠ですね。信頼性は決済サービス各社の足切りラインの基準だと思います。

**各社のアピールする内容だけでは実際の信頼性は分からないので、実績・評判を調べることで比較しました。**

Stirpeは世界中での利用実績、大手企業での利用実績、Google検索では良い評価が多く悪い評価も少ない点で信頼性ができると判断しました。

なおStripe以外にも信頼性を満たす決済サービスは多く見つかったので、このステップでは候補の１つでした。

# 2.対応決済手段

**コンビニ払いや銀行振り込み、JCBカード、PAYPAYなど、日本向けの決済にも対応しているかがポイント**です。日本の国内の決済サービスであればすべて対応しているでしょうが、海外の決済サービスが対応しているとは限らないので注意が必要です。

**実装後に対応していないことが判明すると悲惨なので、気を付けてください。**

OriginallyTeeでは以下の４つが必要でした

* クレジットカード（VISA, Master, JCB, Amex）
* GooglePay、ApplePay
* コンビニ払い
* PAYPAY

全てを利用できる決済サービスが候補となります。このステップで、いくつかの海外決済サービスが候補から外れました。

日本向けの決済の多くにStripeは対応しています。

# 3.手数料

* 取引あたり手数料
* 初期費用・月額固定費の有無
* 隠れたコスト

手数料は多くの人にとって気になる点ではないでしょうか？真っ先に見るのは1取引あたりの決済手数料だと思います。

しかし売上が小さい創業時は、取引あたり手数料よりも、初期費用・月額固定費の影響の方が大きいです。

また決済サービスによっては、取引あたり手数料だけでは判断できない、隠れたコストが生じることもあります。なので各社の手数料ページをしっかり読む必要があります。

**この三項目全てに優れた決済サービスはないので、自社の事業内容に照らして判断します。**

Stripeの取引あたり手数料は3.6%と、他より高めです。しかし初期費用・月額固定費や隠れたコストがかからないため、総額で見ると割安になると判断しました。

ただしこのステップでもStripeに決定するには至りませんでした。


# 4.システム連携のしやすさ　←ここが開発者には重要

**事業と決済機能の連携が完了しないと、事業を開始できません。なので急いで決済機能を実装する必要があります。このステップは開発者にとっても、事業全体にとっても重要となります。**

* 使っているプログラミング言語の公式ドキュメントの充実度

外部システムとの連携は、決済機能に限らず骨の折れる作業です。まず重要なのは公式ドキュメントの充実度でしょう。**使っているプログラミング言語の公式ドキュメント**が充実しているかで、作業効率は大きく変わりますよね。

公式ドキュメントが整理されていないので、簡単なコードでも思うように書けないことありますよね。


**Stripeのドキュメントは多くのプログラミング言語に対応しています。またドキュメントが分かりやすく書かれていることが、実際にコードを書き始める前わかりました。この点がStripeを使う決め手となりました。**

https://docs.stripe.com/

* 外部の実装記事の多さ

また公式ドキュメントだけでは詰まってしまったときに、ネット上に実装記事が多くあることも重要です。

例えばこちらはStripeの方が書かれた記事ですが、StripeへPayPayを組み込む際、大変お世話になりました。

https://qiita.com/ikeike443/items/e45cd498950d2a1ce302

また以下はStripeに決定する前には分かりませんでしたが、使っているうちに非常に優れていると感じた部分です。

* Webhookによるイベントハンドリングで、柔軟な処理ができる
* 決済処理のテスト機能の使いやすさ
* 開発者コミュニティの存在

このような点からもStripeはおススメです。

# 結論
開発者にとって使いやすい決済サービスを使うべし。それが事業にとっても重要
【FileMaker】レイアウトの重なりで(少しでも)修正を楽に！

FileMakerでレイアウトを作成している時、表示・非表示設定でフィールドやポータルを重ねている場合、いちいちずらして修正するのはちょっと面倒だったりします。
2重3重くらいだったらまぁ、ずらして修正しても「ちょっと手間だな」って思うくらいですが、それ以上に重なっている場合は、「あぁめんど」しか出てきません。

そんな時は、ここに注目してみてください。
レイアウトモードにした時の、左パネルです。
![スクリーンショット 2024-12-25 15.48.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60538/7287582d-0a34-ad4c-eb9d-622930014138.png)

いつも、「フィールド」タブしか見ていない？
「オブジェクト」タブをクリックしてみてください。
レイアウトに配置しているオブジェクトが表示されます。
![スクリーンショット 2024-12-25 15.49.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60538/02c62d1d-bf66-2431-b17a-a77531d916bd.png)

ただそれだけのように思うかもしれませんが、ちょっと見て下さい。
なんの変哲もない販売管理の詳細画面ですが。。。
![スクリーンショット 2024-12-25 15.54.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60538/8a9abc14-54e8-295b-7573-0d16faf4eb88.png)

重なっています！
![スクリーンショット 2024-12-25 15.55.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60538/15862637-83cc-391e-f77a-9c0519c33fb0.png)

これは、決済前だったら明細の編集が可能ですが、決済後の場合は、明細を編集できないよう、入力ポータルと表示のみのポータルを重ねています。
（今回は、ポータルにオブジェクト名をつけています。そのオブジェクト名でオブジェクトのリストに展開されます。便利！）

そして、それぞれのポータルを選択すると、ポータルオブジェクトが左のオブジェクトタブのリストでマーキングされます。
![スクリーンショット 2024-12-25 15.56.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60538/168f3eab-1500-a443-b2c2-3ba036c729b0.png)
![スクリーンショット 2024-12-25 15.56.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60538/1409281c-bb47-3c66-108f-080b15ce4e95.png)

一つ、展開してみましょう。
![スクリーンショット 2024-12-25 15.57.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60538/698e2f51-ed3c-0cc2-b9fe-813dfec42891.png)

わかりやすくずらしていますが、ずらさなくても、展開されたポータル内のオブジェクトが選択されます。
![スクリーンショット 2024-12-25 15.58.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60538/648a8e41-6196-5696-2ad7-f846e804e291.png)

そして、レイアウト内のフィールドをポイントしなくても、オブジェクトタブのリストで編集したいオブジェクト名を右クリックするだけで、やれることがリストアップされます。
![スクリーンショット 2024-12-25 15.59.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60538/11f1e504-d358-df90-4b1d-82c626705463.png)

このように、オブジェクト（今回の場合は、ポータル）が重なっていても、レイアウトモードの「オブジェクト」タブリストから選択して編集が可能です。

今回紹介したのは、ほんのちょっとの概要だけです。
このオブジェクトタブについては、[Claris公式トレーニング教材](https://content.claris.com/ja/fmguidebook)の
Claris FileMaker ガイドブック 基礎編 8章で概要が、
Claris FileMaker ガイドブック 実践編 8章では実際にサンプルを作りながら体感できますので、
ぜひ、ガイドブックでその便利さを実感して下さい！
ABC384Dをjavascriptで解いた

# [今日の問題](https://atcoder.jp/contests/abc384/tasks/abc384_d)
↑押してください。
# 自分の回答(javascript)
```javascript
function Main(input){
    min = 1e18
    max = -1e18
    let abc = "abcdefghijklmnopqrstuvwxyz".split("")
    let ABC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("")
    let f = 3
    if(f == 0){
      input = parseInt(input.trim())
    }
    if(f == 1){
      input = input.trim().split("\n").map((a)=>parseInt(a))
    }
    if(f == 2){
      input = input.trim().split("\n").map((a)=>a.split(" ").map((b)=>parseInt(b)))
    }
    if(f == 3){
      input = input.trim().split("\n")
    }
    //ここより上は定型文です。
    let [n,s] = input.shift().split(" ")
    let alist = input.shift().split(" ").map((a)=>parseInt(a))
    total= 0n
    n = parseInt(n)
    s = BigInt(s)
    for(let i = 0;i<n;i++){
      total = total + BigInt(alist[i])
    }
    kaisu = s/(total)
    //console.log(s,total)
    
    if(s%total == 0){
      console.log("Yes")
      return
    }
    
    a = total*BigInt(kaisu)
    
    sakujo = 0
    //console.log(a,total)
    now = a
    
    if(now == s){
        console.log("Yes")
        return
      }
      n = n*2
      for(let i = 0;i<n;i++){
        alist.push(alist[i])
      }
    for(let tuika = 0;tuika<n;tuika++){
      now += BigInt(alist[tuika])
      //console.log(now)
      while(now > s&&sakujo<n){
        //console.log(alist[l])
        now -= BigInt(alist[sakujo])
        sakujo ++
        
      }
      if(now == s){
        console.log("Yes")
        return
      }
    }
    console.log("No")
  }
Main(require("fs").readFileSync(0, "utf8"));
  

```
# 工夫した点
とりあえずまるまる使う区間がいくつかあるのでそれを引いて高速化します。それから端数を尺取法を使って、合うかを確認します。sが10^18であるためBigIntで扱います。注意してください。
ABC384Cをjavascriptで解いた

# [今日の問題](https://atcoder.jp/contests/abc384/tasks/abc384_c)
↑押してください。
# 自分の回答(javascript)
```javascript
function Main(input){
    min = 1e18
    max = -1e18
    let abc = "abcdefghijklmnopqrstuvwxyz".split("")
    let ABC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("")
    let f = 1
    if(f == 0){
      input = parseInt(input.trim())
    }
    if(f == 1){
      input = input.trim().split(" ").map((a)=>parseInt(a))
    }
    if(f == 2){
      input = input.trim().split("\n").map((a)=>a.split(" ").map((b)=>parseInt(b)))
    }
    //ここより上は定型文です。
   let [a,b,c,d,e] = [...input]
   map = new Map()
   map.set("A",0)
   map.set("B",1)
   map.set("C",2)
   map.set("D",3)
   map.set("E",4)
   let list = "ABCDE BCDE ACDE ABDE ABCE ABCD CDE BDE ADE BCE ACE BCD ABE ACD ABD ABC DE CE BE CD AE BD AD BC AC AB E D C B A"
   list = list.split(" ")
   
   list.sort((a,b)=>{
     a = a.split("")
     b = b.split("")
     let as = 0
     let bs = 0
     for(let i = 0;i<a.length;i++){
       as += input[map.get(a[i])]
     }
     for(let i = 0;i<b.length;i++){
       bs += input[map.get(b[i])]
     }
     if(as>bs){
       return -1
     }
     if(as<bs){
       return 1
     }
     if(as == bs){
     a = a.join("")
     b = b.join("")
     let s = [a,b]
     s.sort()
     if(s[0] == a){
       return -1
     }else{
       return 1
     }
     }
   })
   console.log(list.join("\n"))
   }
  Main(require("fs").readFileSync(0, "utf8"));
  

```
# 工夫した点
すべてリストに入れてsortしてときました。ぜっっったいにbit全探索でリストを作ったほうが良かったです。次からは気付けるようになりたいです。
59.94Hzの思い出

# はじめに
59.94Hzを始めて知ったのは、NHKテレビジョン技術教科書だった。

# 白黒テレビ放送のこと
テレビ放送では、パラパラアニメのように1枚1枚の静止画像を高速に切り変えることで動画を表示している。かつてのテレビ受像機は、画像表示機としてブラウン管を採用していた。ブラウン管は電子ビームの当たった場所が当たった瞬間に明るく光ることで画像を表示する表示機でありブラウン管は電子ビームが当たった瞬間（と残光時間）しか光らないので、画面は常にチカチカしていた。このチカチカが１秒間に60回くらいになるとほとんどの人はちらつきに気がつかなくなる。そこで国内で放送が開始された白黒テレビでは画像の更新周波数（フレーム周波数 fH）に60Hzを採用した。（インターレース方式の説明は省略する）
また、音声信号を輝度（明るさ）信号と4.5MHz離して伝送していた。

# NTSC方式のこと
その後、カラー放送が始まる。当時、同じ電波で既存の白黒テレビは白黒のまま映り、カラー放送に対応した受像機ではカラー放送が見られることを意図した画期的な放送方式がいくつか発表された。北米で開発され日本でも放送が始まったのが、NTSC方式である。白黒テレビ時代の受像設備（アンテナや受像機など）は全くいじらずにカラー化したこと、またアナログ技術だけで実現したその技術は今でもすごいなと思っている。

# 59.94Hzとはなにか？
当時のテレビ画像はブラウン管に表示されない分も含め、縦525本の走査線で構成されていた。これは白黒もカラーも変わらない。NTSCでは、隣り合う走査線上の色成分を市松状にずらすことにした。色成分は白黒テレビでは輝度の変化として表示されるが、市松配置とすることで平均化されて目立たなくなるという具合である。この色成分をきれいに抜き出すために、音声信号の周波数とフレーム周波数が整数倍の関係となるようにフレーム周波数を若干ずらすことにしたとのことである。(1000/1001倍) 

fH = 60Hz×1000/1001=59.94005994...Hz
4.5MHz/fH = 525×143　→ 整数倍

# 59.94Hzと60Hzの思い出
昔もっていたパソコン、PC-9801互換機のフレーム周波数は60Hzだった。このパソコンでメガCD用のとあるゲームのアニメーションを再生するプログラムを書いていた時、若干の違和感を感じた。口パクと音声が若干ずれるのである。この時、59.94Hzのことを思い出した。60Hzとの誤差はわずか0.1%と思いきや、計算してみると 16.67秒で1フレーム、2分間の動画で0.12秒ずれる計算になる。そこでシーチェンジの待ち時間に 60 : 59.94 の補正を入れることにした。このプログラムは高負荷時の描画間引きも行っており、時間補正の追加により口パクやシーンリンクをより向上させることができた。

# おわりに
いろいろと懐かしく思い出したので記事にしてみました。
レトロゲーム機のゲームを移植する際の参考になれば幸いです。

### 免責事項
本記事の正確性については努力しておりますが、当方は利用者が当記事の情報を用いて行う一切の行為について何ら責任を負うものではありません。本記事の情報の利用、内容によって、利用者にいかなる損害、被害が生じても、著者は一切の責任を負いません。ご自身の責任においてご利用いただきますようお願いいたします。

### 商標について
本記事に掲載されている商品またはサービスなどの名称は、各社の商標または登録商標です。
ABC384Bをjavascriptで解いた

# [今日の問題](https://atcoder.jp/contests/abc384/tasks/abc384_b)
↑押してください。
# 自分の回答(javascript)
```javascript
function Main(input){
    min = 1e18
    max = -1e18
    let abc = "abcdefghijklmnopqrstuvwxyz".split("")
    let ABC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("")
    let f = 2
    if(f == 0){
      input = parseInt(input.trim())
    }
    if(f == 1){
      input = input.trim().split("\n").map((a)=>parseInt(a))
    }
    if(f == 2){
      input = input.trim().split("\n").map((a)=>a.split(" ").map((b)=>parseInt(b)))
    }
    //ここより上は定型文です。
   let [n,r] = input.shift()
   for(let i = 0;i<n;i++){
     if(input[i][0] == 1){
       if(r >= 1600&&r<=2799){
         r += input[i][1]
       }
     }
     if(input[i][0] == 2){
       if(r >= 1200&&r<=2399){
         r += input[i][1]
       }
     }
   }
   console.log(r)
   }
  Main(require("fs").readFileSync(0, "utf8"));
  

```
# 工夫した点
順番に処理していきます。レートの更新によって、ratedかunratedかが変わるので注意が必要です。ARCが参加できなくなって悲しいです。ARCのほうが判定がよく出ていたので残念（泣）
転職活動をしたけどやっぱり転職やめた話

こんにちは、ふるすです。
2017年に新卒入社して以降、途中で分社はあったもののずっと同じ会社で働き続けています。
ですが実は4年ほど前に転職を考え、実際に転職活動をして内定ももらっていた中で会社に居続けることを選択しました。
何を考えて会社にいることを選んだのか、今キャリアに悩んでいる人の参考になればと思い記事を書いてみます。

## 転職を考えたきっかけ
**特に明確な理由があったわけではありません。**
・ちょっと違うことがやってみたいな
・20代のうちに別の環境に身を置いてみたいな

みたいな理由でした。「絶対に〇〇円の年収がほしいんだ！」「人間関係に悩んで…」といったようなことは全くなく、単にちょっとマンネリ気味だったのだと思います。
転職自体、大きな理由がなくともできる時代かと思うのですが、この転職理由というのは企業選びの軸にも関係してきますので、それがないまま転職活動するのはなかなかモチベーションがあがりづらかったなと今となっては思います。

## どうやって転職活動したの？
私はエージェントを利用しました。
活動はかなりエージェントさんに頼り切りで、提出物の作成方法や締め切りのリマインドまで大変お世話になりました。
この期間中は久しぶりにSPIの勉強をしたり、面接の勉強をしたりとなんだか懐かしい気持ちになりました。自分のやってきたことを改めてまとめて振り返れたので、キャリアについて深く考えるいいきっかけにもなりました。

## 結果は？
最終的には10社程度書類を出し、そのうち6社面接に進み、3社内定をもらうというような結果でした。これがいい結果なのかそうでないのかはわからないのですが、多くの人事の方とキャリアについての会話や雑談をできたことで「こういう人事の人がいる会社好きだな」「ここの組織風土はちょっと合わなさそうだな」と、新卒就活のときとは違う見方ができておもしろかったです。

## なんで転職やめたの？
最終的に内定をもらった会社と今いる会社とを比較して、どこを選ぶかを考えた際に自分の中で下記のような軸を用意しました。

・給与
・業務環境
・福利厚生
・業務内容
・扱うサービスや事業内容
・ミッションに共感できるか

これらをマトリクス表にして検討していたのですが、やればやるほど
「あれ、別に転職しなくてもよくないか…？」となってしまいました。
お給料や福利厚生については上には上があるのでともかくとして、業務内容や会社の使命に共感できるかどうかは自分の中に答えがあるもので、最終的には「それが好きかどうか」で選ぶことにしてしまいました。その結果、「**もう少し今の会社で頑張ってみるか**」となったのでした。新卒の時の私はナイスな判断をしたなと思います。

## それから、現在
最終的に「転職しない」という決断をしてしまったためエージェントさんには大変申し訳なかったのですが、いろいろと勉強になりました。

まずは「転職しようと思えばいつでもできるじゃん」と自信がついたこと。周りには優秀な社員が多く、評価期間になると自分の至らなさを痛感しがちですが、一回転職活動をしてみたことで心がかなり軽くなりました。すごく周りを気にする性格だったのですが、いい意味で吹っ切れて「辞めようと思えばいつでも辞められるんだし、自分にしかできない仕事をやってみよう」というマインドになれたおかげで評価もかえってよくなり、仕事が楽しくなり、良いサイクルで回り始めました。

その後も数年同じ部署でコンサルを続け、今年は思い切って社内ジョブチェンジをしたのですから何が起きるかわからないものです。
でもあのときに転職活動をしてよかったなと心から思っています。

ご自身のキャリアについてなんとなくもやもやがある、悩んでいるという方にとって少しでも参考になれば幸いです。
SalesforceへのOAuthでブラウザログイン後のAccessToken/UserInfo取得ができない

今回の場合はSalesforce Commerce CloudでのOAuthLoginFlowMgr.finalizeOAuthLogin()が返した値の中身(accessTokenResponse/userInfoResponse)が空だった

Salesforce側で当該ユーザのログイン履歴を確認すると、ブラウザでのログイン直後のアクセスが「制限されているIP」という状況になっていたので、そのアクセス元IPを当該ユーザのプロファイルの許可IPに追加した
ABC384Aをjavascriptで解いた

# [今日の問題](https://atcoder.jp/contests/abc384/tasks/abc384_a)
↑押してください。
# 自分の回答(javascript)
```javascript
function Main(input){
    min = 1e18
    max = -1e18
    let abc = "abcdefghijklmnopqrstuvwxyz".split("")
    let ABC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("")
    let f = 3
    if(f == 0){
      input = parseInt(input.trim())
    }
    if(f == 1){
      input = input.trim().split("\n").map((a)=>parseInt(a))
    }
    if(f == 2){
      input = input.trim().split("\n").map((a)=>a.split(" ").map((b)=>parseInt(b)))
    }  
//ここより上は定型文です。
   input = input.trim().split("\n")
   let [n,b,g] = input.shift().split(" ")
   let s = input.shift().split("")
   n = parseInt(n)
   for(let i = 0;i<n;i++){
     if(s[i] != b){
       s[i] = g
     }
   }
   console.log(s.join(""))
   }
  Main(require("fs").readFileSync(0, "utf8"));

```
# 工夫した点
一文字ずつ愚直に見ていきました。もし違ったら順に更新していきます。入力を取ってくるのが一番難しいかもしれない笑
フロントエンドで意図しない内部情報暴露が起きていた件

# TL;DR

- Nuxt2の`publicRuntimeConfig`の取り扱いには気を付けましょう、

## 何が起きたか

- `publicRuntimeConfig`に、システム内部通信で必要なエンドポイント、トークンを書いちゃってました、というよくあるバッドプラクティスをやらかした

- しかも、**平文で**、ブラウザのHTMLに載っちゃってました

    - 事故になる前で発見、対応できたのは不幸中の幸い
 
## なぜ起きたか

- `publicRuntimeConfig`への理解不足
    - うろ覚えですが、当時`$config`から値を参照するべく定義していた模様

## どうしたか

- 公開する必要がないパラメータは、`process.env`または`privateRuntimeConfig`とするべきでした 

    - 今回は`process.env`で対応しましたが`privateRuntimeConfig`についても追って検証したいです

## 参考リンク

[Nuxt 2 - RuntimeConfig プロパティ](https://v2.nuxt.com/ja/docs/configuration-glossary/configuration-runtime-config/#publicruntimeconfig)

[Nuxt 2 - Nuxt 設定ファイル](https://v2.nuxt.com/ja/docs/directory-structure/nuxt-config#runtimeconfig)

- `privateRuntimeConfig`の実例が載っています。最初からここを読んでいれば、となりました。
ABC383Dをjavascriptで解いた

# [今日の問題](https://atcoder.jp/contests/abc383/tasks/abc383_d)
↑押してください。
# 自分の回答(javascript)
```javascript
function Main(input){
    min = 1e18
    max = -1e18
    let abc = "abcdefghijklmnopqrstuvwxyz".split("")
    let ABC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("")
    let f = 0
    if(f == 0){
      input = parseInt(input.trim())
    }
    if(f == 1){
      input = input.trim().split("\n").map((a)=>parseInt(a))
    }
    if(f == 2){
      input = input.trim().split("\n").map((a)=>a.split(" ").map((b)=>parseInt(b)))
    }
   n = input
   let primelist = make_primelist(1000000)
   function make_primelist(aa){
  let yakusu = new Array(aa)
  for(let i = 0;i<aa;i++){
    yakusu[i] = new Array()
  }
  let primelist = []
   for(let i = 2;i<aa;i++){
     if(yakusu[i].length == 0){
       primelist.push(i)
       for(let j = i;j<aa;j += i){
         yakusu[j].push(i)
         
       }
     }
   }
   return primelist
}

//console.log(primelist)
   let count = 0
   for(let i = 0;i<2000;i++){
     for(let j = i+1;(primelist[i]*primelist[j])**2<=n;j++){
        count ++
     }
   }
   for(let i = 0;i<100;i++){
     if(primelist[i] ** 8<= n){
     count ++
     }
   }
   function primeNumber(n) {
 if (n === 2) return true;
 for (let i = 2; i < n; i++) {
   if (n % i === 0) return false;
 }
 return true;
}
   function getGCD(a, b){
        while (a > 0 && b > 0)
        {
            if (a < b)
                b %= a;
            else
                a %= b;
        }
        return Math.max(a, b);
    }
   console.log(count)
   
  }
  Main(require("fs").readFileSync(0, "utf8"));
  
//ここより上は定型文です。
```
# 工夫した点
まず約数の個数とは素因数分解したときの肩の数に一を足した数をすべて掛け合わせる事によって得ることができます。よって９個ということ9か(2+1)*(2+1)です。よってn^8またはn^2*m^2ということになります。このときn,mは素数です。（素因数分解なんだから当たり前）あとはこれを全探索します。10^12までなのでBigIntを使わなくても大丈夫です。
図書館で本借りました。でへ。

WebカメラとPowerDirectorもあるので、動画編集の勉強もしたいと思い、予約した本が届いたと図書館から連絡があり、借りてきました。:relaxed:
![IMG_0053.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/433305/11d14c24-33fd-1e91-a5bd-c2fe2246e84d.jpeg)
初心者がubuntuでkaggleの環境を構築してみた(Jupyter notebook編)


最近DeepLearning用のpcを購入したので、kaggleの環境と同じ環境を作成しようと試みました。

目標はvscodeやcursorでkaggle環境を用意することですが、その前に一旦dockerのコンテナ内でjupyter notebookを開くことをゴールとして取り組みました。

参考にしたのは以下の記事です。

[自前GPU記事](https://qiita.com/A7_data/items/9d1a1911e001236a6b5b)
[Kaggle環境構築編](https://zenn.dev/yuto_mo/articles/d261e96f35986a)
[DockerでのディープラーニングGPU学習環境構築方法](https://qiita.com/karaage0703/items/e79a8ad2f57abc6872aa)

この記事に従っていれば、時間をかければみんな環境構築できると思います。

以下に、初心者として自分が詰まったところを記事にします。
### 1. pipができなかった

#### 問題
pipでkaggleパッケージをダウンロードしようとすると、pipが見つからないとエラーをはいてきました。ビビりました。

#### 対処

コマンドラインで、
```
python3 -m pip install kaggle
```
を実行しました。うまく行きました。

### 2. 次に、kaggleのpathがとおっていなかった

```
echo 'export PATH=$PATH:~/.local/bin' >> ~/.bashrc
source ~/.bashrc
```
これを実行しました。

他にも詰まったとこもありましたが、基本的にpathの問題で、chatgptに聞きまくるのが吉です。

vscodeまでできたらまた書きます。
ABC383Cをjavascriptで解いた

# [今日の問題](https://atcoder.jp/contests/abc383/tasks/abc383_c)
↑押してください。
# 自分の回答(javascript)
```javascript
function Main(input){
    min = 1e18
    max = -1e18
    let abc = "abcdefghijklmnopqrstuvwxyz".split("")
    let ABC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("")
    let f = 3
    if(f == 0){
      input = parseInt(input.trim())
    }
    if(f == 1){
      input = input.trim().split("\n").map((a)=>parseInt(a))
    }
    if(f == 2){
      input = input.trim().split("\n").map((a)=>a.split(" ").map((b)=>parseInt(b)))
    }
    res = 0
   input =  input.trim().split("\n")
   let [h,w,d] = input.shift().split(" ").map((a)=>parseInt(a))
   let s = input.map((a)=>a.split(""))
   hlist = []
   for(let i = 0;i<h;i++){
     for(let j = 0;j<w;j++){
       if(s[i][j] == "H"){
         hlist.push([i,j])
       }
     }
   }
   map = []
   for(let i = 0;i<h;i++){
     map.push(new Array(w).fill(-1))
   }
   let bfs = []
   for(let i = 0;i<hlist.length;i++){
     map[hlist[i][0]][hlist[i][1]] = 0
     bfs.push([hlist[i][0],hlist[i][1],0])
   }
   let a = 0
   while(a<bfs.length){
     if(bfs[a][2] == 2){
       //console.log(map.join("\n"))
     }
     y = bfs[a][0]
     x = bfs[a][1]
     //console.log(y,x)
    
     
     let list = [[-1,0],[0,1],[1,0],[0,-1]]
     for(let i = 0;i<4;i++){
       let ny = y+list[i][0]
       let nx = x+list[i][1]
       
       //console.log(ny,nx)
       if(0<=ny && ny<h && 0<=nx && nx<w && map[ny][nx] == -1 && s[ny][nx] == "."){
         
         
         bfs.push([ny,nx,bfs[a][2]+1])
          map[ny][nx] = bfs[a][2]+1
       }
     }
     a++
   }
   count = 0
   for(let i = 0;i<h;i++){
     for(let j = 0;j<w;j++){
       if(map[i][j] != -1){
         if(map[i][j] <= d){
           count ++
         }
       }
     }
   }
   console.log(count)
   function dfs(y,x,depth){
    
   }
  }
  Main(require("fs").readFileSync(0, "utf8"));
  
//ここより上は定型文です。
```
# 工夫した点
bfsで解きます。幅優先探索のため、すでに訪れている箇所は更新しなくてよいです。理由はそれより前に訪れているのであれば、そっちのほうが最小だからです。表を作っていくという点では、DPに似たものを感じます。
【Unity】Animatorの現在再生中のAnimationの長さを取得する

# はじめに
この記事は[Hamster Output Advent Calendar 2024](https://qiita.com/advent-calendar/2024/game_hamster)の16日目の記事です！

Arbor3とAnimationEventの組み合わせを使ってプレイヤーのダメージ処理やステート遷移を作りたかったのですが...組み合わせの相性が悪い？のかAnimationEventが呼び出されないなどの問題が出てきました。

なので、Animationがどれだけ再生されたのかなどの長さを調べる処理が欲しいなと思い作りました。

# 実装したソースコード
```C#
public static class AnimatorHelper
{
    /// <summary>
    /// 現在の再生中のクリップの長さを0~1の値で取得する
    /// </summary>
    public static float GetCurrentClipLength(Animator animator, string stateName)
    {
        // Animatorを更新する
        animator.Update(0.0f);

        // 遷移中は0の値を返す
        if (animator.IsInTransition(0))
        {
            return 0.0f;
        }

        // 現在の再生中のクリップの情報を取得する
        AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);

        // ステートのハッシュ値を取得する
        var currentStateHash = stateInfo.shortNameHash;
        var argumentStateHash = Animator.StringToHash(stateName);

        // 現在のステートのハッシュと引き数のステートのハッシュが異なる場合は0を返す
        if (currentStateHash != argumentStateHash)
        {
            return 0.0f;
        }

        // 現在の再生中のクリップの長さを0~1の値で取得する。
        var result = Mathf.Repeat(stateInfo.normalizedTime, 1.0f);

        // 現在のAnimationがループしていない場合は1を返す
        if (result <= 0.99f && !stateInfo.loop)
        {
            return 1.0f;
        }

        return result;
    }
}
```

# 使い方
static変数なのでどこからでも呼び出せます。
```C#
// 長さを保持する変数
var length = AnimatorHelper.GetCurrentClipLength(_animator, "Idle");

// 現在のアニメーションの再生値が特定の値になったらログを出す
if (length >= 0.9f)
{
    Debug.Log("Idle");
}
```

# 値を0~1の値にする
今回初めて使った処理が、Mathf.Repeatというメソッドで指定した引き数の数値と0を無限にループしてくれる処理です。
```C#
// 現在の再生中のクリップの長さを0~1の値で取得する。
var result = Mathf.Repeat(stateInfo.normalizedTime, 1.0f);
```

最初は、Mathf.Clamp01とかを利用していましたが、Animationがループしている物とかだと、値が1~以上を超えるという問題があり値をループさせる方法はないかと模索した時にRepeatメソッドを見つけました。


# もしかしたらこの部分は要らないかも

animatorのCurrentStateInfoの更新が遅れる対策としてanimator.Updateという処理や、Animationが遷移中の時に前の値を返さないようにIsInTransitionなどを利用しています。

その下の方で、さらにステート名が違った場合に処理を中断する部分を入れていますが...もしかしたら要らないかも...?

```C#
// ステートのハッシュ値を取得する
var currentStateHash = stateInfo.shortNameHash;
var argumentStateHash = Animator.StringToHash(stateName);

// 現在のステートのハッシュと引き数のステートのハッシュが異なる場合は0を返す
if (currentStateHash != argumentStateHash)
{
    return 0.0f;
}
```

# まとめ
Animationの長さを0~1の長さで取得出来るようになったので、0.7のタイミングで何かのイベント発火！という物が作りやすくなりました。正直間違ってたり、遠回りしている可能性もあると思うので詳しい人がいればコメントで教えてください...

AnimationEventも昔から使ってはいるけど、Animation中にメソッドを行う方法で使いやすい物はないのかな...?
ABC383Bをjavascriptで解いた

# [今日の問題](https://atcoder.jp/contests/abc383/tasks/abc383_b)
↑押してください。
# 自分の回答(javascript)
```javascript
function Main(input){
    min = 1e18
    max = -1e18
    let abc = "abcdefghijklmnopqrstuvwxyz".split("")
    let ABC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("")
    let f = 3
    if(f == 0){
      input = parseInt(input.trim())
    }
    if(f == 1){
      input = input.trim().split("\n").map((a)=>parseInt(a))
    }
    if(f == 2){
      input = input.trim().split("\n").map((a)=>a.split(" ").map((b)=>parseInt(b)))
    }
    //ここより上は定型文です。
    res = 0
   input =  input.trim().split("\n")
   let [h,w,d] = input.shift().split(" ").map((a)=>parseInt(a))
   let s = input.map((a)=>a.split(""))
   for(let i = 0;i<h*w;i++){
     for(let j = 0;j<h*w;j++){
       y1 = Math.floor(i/w)
       x1 = i-y1*w
       y2 = Math.floor(j/w)
       x2 = j-y2*w
       //console.log(y1,y2,x1,x2)
       if(s[y1][x1] == "."&&s[y2][x2] == "."){
       
       count = 0
       for(let k = 0;k<h;k++){
         for(let l = 0;l<w;l++){
           if(Math.abs(y1-k)+Math.abs(x1-l)<=d||Math.abs(y2-k)+Math.abs(x2-l)<=d){
             if(s[k][l] == "."){
               count ++
             }
           }
         }
       }
       res = Math.max(res,count)
       
       }
     }
   }
   console.log(res)
  }
  Main(require("fs").readFileSync(0, "utf8"));
  
```
# 工夫した点
愚直にすべてのマスとその周りを調べました。10*10が最大なので、多くても計算量は10*10*9くらいだから全然大丈夫です。
Dockerを活用したDiscord.py Bot開発＆デプロイ

この記事では、PythonでDiscord Botを開発する際に便利な「discord.py」を使用し、そのBotをDockerコンテナで実行する方法を解説します。Dockerを活用することで、環境構築が簡単になり、どこでも同じ環境で動作させることができます。

## 必要なツール

以下のツールをインストールしておいてください：

- Python (3.8以上推奨)
- Docker
- Git (オプション)

---

## 1. Discord Botの基本セットアップ

### 1.1 Discord Botアカウントの作成
1. Discord Developer Portal (https://discord.com/developers/applications) にアクセス。
2. 新しいアプリケーションを作成。
3. Botタブで「Botを作成」ボタンを押す。
4. トークンを取得して安全に保存。

### 1.2 必要なPythonライブラリをインストール
プロジェクトディレクトリを作成し、以下の手順を実行します。

```bash
mkdir discord-bot
cd discord-bot
python -m venv venv
source venv/bin/activate  # Windowsでは `venv\Scripts\activate`
pip install discord.py
```

---

## 2. Dockerfileの作成

プロジェクトディレクトリに`Dockerfile`を作成します。以下はシンプルな例です。

```dockerfile
# ベースイメージ
FROM python:3.9-slim

# 作業ディレクトリを設定
WORKDIR /app

# 依存関係をコピー
COPY requirements.txt requirements.txt

# 必要なライブラリをインストール
RUN pip install --no-cache-dir -r requirements.txt

# ボットのコードをコピー
COPY . .

# ボットを実行
CMD ["python", "bot.py"]
```

---

## 3. 必要ファイルの準備

### 3.1 `bot.py`
以下は簡単なBotの例です。

```python
import discord
from discord.ext import commands

intents = discord.Intents.default()
intents.messages = True
bot = commands.Bot(command_prefix="!", intents=intents)

@bot.event
async def on_ready():
    print(f'Bot logged in as {bot.user}')

@bot.command()
async def hello(ctx):
    await ctx.send('Hello, world!')

bot.run('YOUR_TOKEN_HERE')
```

### 3.2 `requirements.txt`

```text
discord.py
```

---

## 4. Dockerイメージのビルドと実行

以下の手順でDockerイメージをビルドし、Botを実行します。

```bash
# Dockerイメージをビルド
docker build -t discord-bot .

# コンテナを実行
docker run -d --name discord-bot discord-bot
```

---

## 5. トラブルシューティング

### Botが起動しない場合
- Dockerコンテナのログを確認:
  ```bash
  docker logs discord-bot
  ```
- トークンが正しいか確認。
- 必要な権限がBotに付与されているか確認。

### 依存関係の問題
- `requirements.txt`が正しく設定されているか確認。
- Dockerイメージを再ビルド:
  ```bash
  docker build --no-cache -t discord-bot .
  ```

---

これで、Discord BotをDockerコンテナで動作させる準備が整いました。どの環境でも同じように動作するので、ぜひプロジェクトに活用してください！
[Tips]Redashの定期実行を平日だけにする

Redashにはクエリの定期実行機能が存在します。
しかし、この機能には一つ難点があり、複数曜日の指定できません。
具体的にどういうことかというと、平日だけ毎日10時に定期実行したいクエリが存在したとしても、「月曜から金曜は実行する、土日はしない」のようなことができないのです。
この場合毎日10時に実行するという設定を行うことで一応回避はできるのですが、今度は土日に実行されてしまいます。

Google Cloudのような従量課金形態のデータ基盤を利用している場合、余計なお金がかかってしまうので可能なら避けたいです。データ量の少ない場合はいいですが、データ量が多くなればなるほど需要は大きくなります。

今回はそんなRedashでなんとか平日だけ定期実行させる方法をいくつか紹介します。

## 方法1: 毎日クエリを実行するようにして、土日はインスタンスを落とす

最初から力技ですみません。
AWSでいうところのautoscalingなどを利用し、Redashの休日はインスタンスを止めてしまう方法です。
インスタンス費用分もお得で一番楽だと思います。
一つ気をつけた方がいいのは、「毎月1日0時時点での特定のデータが欲しい」などの土日でも定期実行したいクエリが存在する場合、この方法は取れないもしくはautoscalingに工夫が必要になる点です。
利用しているメンバーにしっかりと問題ないか調査してから、実行するようにしましょう。

## 方法2: Redashでは定期実行の設定をせず、APIで更新する

RedashにはAPIが存在します。
定期実行したいクエリを更新するAPIをスケジューリングして実行することで、自在なスケジュール設定をが可能です。
APIにはQuery単位のAPIキーとユーザー単位のAPIキーが存在しますが、クエリ更新はユーザー単位のAPIキーを使います。
`https://(Redashのドメイン)/users/me`にログイン後アクセスし、APIキーを取得します。
APIキーを取得後、以下のコマンドでAPIを実行することでクエリのRefreshを行うことができます。（zshで実行確認しています）

```
curl -XPost https://(Redashのドメイン)/api/queries/(クエリのID)/refresh\?api_key=\(取得したAPIキー)
```

このAPIをGitHub ActionsやGASあたりをつかって定期実行できるようにスクリプトとスケジュールを組めば、平日だけ実行することは実現できるかと思います。

## まとめ
今回は平日だけ定期実行する、と題して定期実行を柔軟に行う方法を紹介しました。
そもそもこんなことしなくてももっと簡単にできるよ、という場合は容赦なくコメントでマサカリを振っていただけると幸いです。