OmniAICreator/Qiita-1.07M huggingface dataset:
AWS re:Invent 2023　Amazon Bedrockアップデートまとめ

# はじめに
この記事は株式会社ナレッジコミュニケーションが運営する [クラウド AI by ナレコム Advent Calendar 2023](https://qiita.com/advent-calendar/2023/knowcom-cloudai) の7日目にあたる記事になります！

この記事では先日ラスベガスで行われた AWS re:Invent 2023 で発表された多くのサービスの中からAmazon Bedrockのアップデートに焦点をあてて紹介していきたいと思います！

# おさらい
Amazon BedrockはAWSが提供する生成AIサービスです。
AI21 Labs、Anthropic、Cohere、Meta、Stability AI、Amazon などの大手 AI 企業が提供する高性能な基盤モデル (FM) を単一の API で選択できるフルマネージド型サービスとなります。
料金体系もシンプルで基本的にはモデルと入出力のトークンによって算出されます。

参考:公式サイト
https://aws.amazon.com/jp/bedrock/

# Amazon Bedrockアップデートまとめ
さて本題に入っていきましょう！

**・モデルのファインチューニングの一般利用開始**
Cohere Command Lite, Meta Llama 2, Amazon Titan
Text Lite/Expressのモデルでファインチューニングを実行可能になりました。
※一般利用はバージニアとオレゴンのみ

**・Knowledge Base for Amazon Bedrockが一般利用開始**
基盤モデルとデータソース(S3)を組み合わせた検索拡張生成(RAG)をフルマネージドに実現可能になりました。
※一般利用はバージニアとオレゴンのみ

**・Continued pre-trainingを発表**
Amazon Titan Text Express/Liteについて、ユーザー独自のデータ(ラベルなし)を活用した事前トレーニングカスタマイズが可能になりました。
※バージニアとオレゴンのみでプレビュー

**・Agents for Amazon Bedrockが一般利用開始**
基盤モデルだけで完結しないタスクを実行することを容易にするフルマネージドサービス
※一般利用はバージニアとオレゴンのみ

**・Guardrails for Amazon Bedrockを発表**
ユーザのクエリや基盤モデルの応答を評価し、不適切なコンテンツを評価・フィルタする機能。
これにより、「責任あるAI利用」を実現。
※バージニアとオレゴンのみでプレビュー、対応言語は現時点で英語のみ

**・選択できる基盤モデルの拡充**
▪ Anthropic Claude 2.1 (一般利用開始)
▪ Meta Llama 2 70B (一般利用開始)
▪ Amazon Titan Image Generator (プレビュー)
▪ Amazon Titan Multimodal Embeddings (一般利用開始)
※上記はバージニアとオレゴンのみのリリース状況です。

**・複数の基盤モデルが一般利用開始**
▪ Stable Diffusion XL 1.0
▪ Amazon Titan Text
※バージニア北部、オレゴン州、シンガポール、東京、フランクフルトリージョンで利用可能

**・基盤モデルの比較・評価をサポートするModel Evaluation on Amazon Bedrockを発表**
▪ 「質問に答える」「要約」などのタスクを設定し、組み込みデータセットまたはカスタムデータセットで指定したモデルの比較を実施、レポートを出力
▪ 親しみやすさ、スタイル、ブランディングなど人間の判断が必要な場合も、ワークフローに組み込み可能
※バージニアとオレゴンのみでプレビュー

**・Amazon Bedrockがバッチ推論をサポート**
Bedrockが複数のプロンプトをバッチで受け付けて推論できるようになりました。
※Bedrockをサポートするすべてのリージョンで一般利用開始



情報はすべて2024年12月7日時点のものになります。


# まとめ
いかがでしたでしょうか。
より使いやすくなる機能アップデートから新機能の発表まで興味深いものばかりでした！
今後の動向も期待できますね。

またナレッジコミュニケーションでは「[Musubite](https://musubite-job.com/)」というエンジニア同士のカジュアルトークサービスを利用しています！この記事にあるような生成 AI 技術を使ったプロジェクトに携わるメンバーと直接話せるサービスですので興味がある方は是非利用を検討してください！
 
https://recruiting.musubite-job.com/features/company/knowledge-communication
 
今後もクラウド AI の最新情報を皆さんに届けていきたいと思います。お楽しみに！
式を評価、"ExpressionLanguage"

[Symfony Component Advent Calendar 2023](https://qiita.com/advent-calendar/2023/symfony-component)の9日目の記事です。

## 式を評価、"ExpressionLanguage"

[ExpressionLanguage](https://symfony.com/doc/current/components/expression_language.html)は、文字列の式を評価してくれるコンポーネントです。Symfony以外でも使えます。

### インストール

```shell
composer require symfony/expression-language
```

### 使い方

"文字列の式を評価"というのはなかなか伝わりにくいかなと思うんですが、実際のコードを見れば一目瞭然かなと思います。

```php
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;

$expressionLanguage = new ExpressionLanguage();

$resulst = $expressionLanguage->compile('3 + 2'); // (3 + 2)
$result = $expressionLanguage->evalute('3 + 2'); // 5
```

`compile()` は与えた文字列の式をPHPにコンパイルします。`evaluate()`はコンパイルせずに与えた文字列の式を評価して、結果を返してくれます。基本使うのは`evaluate()`かな。。

上記はただの算数ですが、変数を渡して評価することもできます。メソッドの呼び出しは`->`から`.`に変わります。

```php
$apple = new Item();
$apple
  ->setName('りんご')
  ->setPrice(100)
;

$expressionLanguage = new ExpressionLanguage();
$expressionLanguage->evaluate('item.getName()', ['item' => $apple]); // りんご
$expressionLanguage->evaluate('item.getPrice() > 50', ['item' => $apple]); // true
```

### 独自構文

コンポーネントでいくつかの[構文](https://symfony.com/doc/current/reference/formats/expression_language.html#component-expression-functions)は用意していますが、独自構文も作成可能です。

```php

$expressionLanguage = new ExpressionLanguage();
$expressionLanguage->register('isPublished', function (): string {
    return 'コンパイルした時の文字列';
}, function (array $arguments): bool {
    return $arguments['item']->getPublishedAt()->diff(new DateTimeImmutable(), true);
});

$item = new Item();
$item->setPublishedAt(new DateTimeImmutable('2023-12-01 00:00:00'));
$expressionLanguage->evaluate('isPublished()', ['item' => $item]); // true
```

なお、Symfonyで使う場合は、さらに以下の構文も用意されています。

- [セキュリティ](https://symfony.com/doc/current/security/expressions.html)
- [サービスコンテナ](https://symfony.com/doc/current/service_container/expression_language.html)
- [ルーティング](https://symfony.com/doc/current/routing.html#routing-matching-expressions)

### なにがうれしいか

これの便利なところは、**設定ファイルなどに式を記述できる**ことで、プログラムを修正することなく安全にロジック変更することができるところです。

```yaml:config/services.yaml
# キャンペーンの開始条件を設定
parameters:
    campaign_condition: "campaign.isActive() && campaign.getStartedAt().format('YmdHis') > 20231209000000"
```

```php
class SomeController
{
    public function __construct(
        #[Autowire(param: 'campaign_condition') private readonly $condition)
    {
    }

    public function index(Campaign $campaign)
    {
        $expressionLanguage = new ExpressionLanguage();
        $started = $expressionLanguage->evaluate(
            $this->condition, 
            ['campaign' => $campaign]
        );

        if (!$started) {
            throw NotFoundHttpException();
        }

        return ['campaign' => $campaign];
        
    }
}
```

## まとめ

今回は`ExpressionLanguage`でした。Symfony以外でも使えますが、Symfonyの設定(`config`配下)で使うことができ、非常に柔軟に設定を行うことができるようになるコンポーネントとなっています。
[ Django REST framework ] で複数条件一致の検索機能


## はじめに

プログラマーなりたてのﾀｹﾉｺです。
上流工程から担当させてもらえるエンジニアになる事を目標に学習しております。<br> 
今回は、研修で苦労した複数条件含む検索の機能実装について説明していきます。自分なりにコードの解説して振り返りとして記事書いていきたいと思います。注意として基礎的なDRFの使用方法について解説はしません。あくまで検索機能の作り方をメインにしています。正直、自信がないので参考程度に見てくださればと幸いです。もし指摘や意見あれば遠慮なくコメントしてほしいです！

## さっそく解説していく🧐
まずは使用するモデルやシリアライザなどを作成していきます。

### Model
今回、使用するモデルは以下になります。
検索条件として title、name、created_at のフィールドを使用します。
```python:models.py
from django.db import models

class Post(models.Model):
    class Meta:
        db_table = 'post'
        
    title = models.CharField(max_length=100)
    name = models.CharField(max_length=50)
    description = models.TextField()
    created_at = models.DateField(auto_now_add=True)
    updated_at = models.DateField(auto_now=True)
```
### Serializer
```python:serializers.py
from rest_framework import serializers
from .models import Post

class PostSerializer(serializers.ModelSerializer):

	class Meta:
		model = Post
		fields = '__all__'
		read_only_fields = ['id']
```
### View
以下のコードを見るとわかると思いますが、全データを取得して検索条件（クエリパラメータ）からデータを絞り込んでいく処理となっています。

```python:views.py
from rest_framework import views
from .models import Post
from .serializers import PostSerializer
from rest_framework.response import Response

class PostViewSet(views.APIView):

    # 検索機能はこちら ↓↓↓
    def get(self, request):

        # 投稿された全データ取得
        data = Post.objects.all()

        # 検索条件となるクエリパラメータ取得　※初期値は空文字にしています
        title = request.GET.get('title', '')
        name = request.GET.get('name', '')
        created_at = request.GET.get('created_at', '')

        # 取得出来るクエリパラメータがある事を条件に全データからフィルターをかける
        if title:
            data = data.filter(title=title)
        if name:
            data = data.filter(name=name)
        if created_at:
            data = data.filter(created_at=created_at)

        # フィルターがかけられたデータをJSON形式に変換してレスポンスを返す
        serializer = PostSerializer(data, many=True)
        return Response(serializer.data)

    # 投稿用の処理
    def post(self, request):
        data = request.data
        serializer = PostSerializer(data=data)
        if serializer.is_valid():
            serializer.save()
        return Response(serializer.data)
```
以上、検索機能の実装でした。

# 最後に
実装中にクエリパラメータが（検索項目が）増える事や、検索機能（部分一致、半角⇔全角対応）向上など今後必要になりそうな機能があるな～と思いました。ですので、実装する前に今後の機能追加する見込みがあるのかという事も一応念頭に置いてみてもいいかなと思いました。今後、備忘録という事だけではなく機能追加や保守性などふまえて実装し意味のある記事投稿にしていきたいです。

というわけで簡単ではありますが解説は以上にします。
Node.jsからAzure Open AIのWhisperを使う


Open AIのAPIでWhisperは使いましたが、Azure Open AIでも使ってみようと思います。中身は変わらないはず。

https://qiita.com/n0bisuke/items/2e69cbf64fc890900bd0
  
## モデルのデプロイまで

### リソース作成 - 米国中北部または西ヨーロッパ リージョン

**そもそも全てのリージョンで使える訳じゃない**ってのがあります。

> ![スクリーンショット 2023-12-06 20.32.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/ea148367-86c3-4d04-7156-cf0a6183657e.png "スクリーンショット 2023-12-06 20.32.02.png")
> https://learn.microsoft.com/ja-jp/azure/ai-services/openai/whisper-quickstart?tabs=command-line&pivots=rest-api

**米国中北部または西ヨーロッパ リージョン**ってあるので米国中北部で作ってみます。

> North Central USがたぶんそう
> ![スクリーンショット 2023-12-06 20.34.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/e3b32316-5f75-998c-7d87-c980f65e3623.png "スクリーンショット 2023-12-06 20.34.47.png")


### モデルデプロイ - Whisper

`モデルデプロイ > 展開の管理`、ここ別タブで開く様にしてほしすぎる。

> ![スクリーンショット 2023-12-06 20.37.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/f49318a3-a08b-1711-c79a-747fd2a50f18.png "スクリーンショット 2023-12-06 20.37.49.png")

**選択肢にWhisperが！！！**

日本リージョンとか選んでなんで選択肢にでないんだろうとか悩んでたので割とこれだけで嬉しい。

Whisperを選んで進みます。

> ![スクリーンショット 2023-12-06 20.39.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/cc77bfe2-94cd-e812-80fb-06e5521e9557.png "スクリーンショット 2023-12-06 20.39.12.png")

`n0bisuke-whisper`って名前にしてデプロイしておきます。

> ![スクリーンショット 2023-12-06 20.40.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/4f4bf94f-eb3a-8c2f-ef1c-edfc05768961.png "スクリーンショット 2023-12-06 20.40.51.png")

## Node.jsから触る

[前回の記事](https://qiita.com/n0bisuke/items/10c9a9aa02bfb62fd158)で生成した[こちらの音声](https://i.gyazo.com/d4b90b0afa2ee6482965bf6309812647.mp4)を使ってみます。

```bash
$ npm i @azure/openai
```

```js
const { OpenAIClient, AzureKeyCredential } = require("@azure/openai");
const fs = require('node:fs/promises');

const azureApiKey = `XXXXXXX`;
const endpoint = `https://YYYYYYYY.openai.azure.com/`;

async function main() {
  console.log("== Transcribe Audio Sample ==");

  const client = new OpenAIClient(endpoint, new AzureKeyCredential(azureApiKey));
  const deploymentName = "n0bisuke-whisper"; //デプロイ名
  const audio = await fs.readFile('./akiba.mp3');
  const result = await client.getAudioTranscription(deploymentName, audio, {language: 'ja'});

  console.log(`Transcription: ${result.text}`);
}

main().catch((err) => {
  console.error("The sample encountered an error:", err);
});
```

出力結果は以下の様になりました。

```bash
$ node app.js
== Transcribe Audio Sample ==
Transcription: こんにちは。秋葉原の電気街口にいます。
```

生成された音声を元に戻した感じですが、完璧ですね。。


一応この辺を見ると第3引数でオプションを渡せてLangage指定ができそうでした。精度上がるっぽいけどどうなんでしょう。

> https://learn.microsoft.com/ja-jp/javascript/api/%40azure/openai/getaudiotranscriptionoptions?view=azure-node-preview#@azure-openai-getaudiotranscriptionoptions-language
FEの勉強法

# 中2でFE取ってみた
中1でIPとったのでFE取ってみました。
## なぜFEを取るのか
将来的にセキュリティエンジニアとかになりたいのでとりあえずは幅広い知識を学んでおきたいと思い取りました。どっちみち学ぶ基盤技術は先に学んどいた方が得でしょう。まあ変化はあるだろうけど。
## 使用した参考書・サイト
[栢木先生の基本情報技術者教室](https://www.amazon.co.jp/%E4%BB%A4%E5%92%8C05%E5%B9%B4-%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8%EF%BC%86%E3%82%AF%E3%83%AC%E3%83%90%E3%83%BC%E6%96%B9%E5%BC%8F%E3%81%A7%E3%82%88%E3%81%8F%E3%82%8F%E3%81%8B%E3%82%8B-%E6%A0%A2%E6%9C%A8%E5%85%88%E7%94%9F%E3%81%AE%E5%9F%BA%E6%9C%AC%E6%83%85%E5%A0%B1%E6%8A%80%E8%A1%93%E8%80%85%E6%95%99%E5%AE%A4-%E6%83%85%E5%A0%B1%E5%87%A6%E7%90%86%E6%8A%80%E8%A1%93%E8%80%85%E8%A9%A6%E9%A8%93-%E6%A0%A2%E6%9C%A8/dp/4297131307)
→インプット
[基本情報技術者試験ドットコム](https://www.fe-siken.com/)
→アウトプット
## 対策
わりと科目Aのほうが心配だった
科目A対策
1\. 栢木先生一周見る 
2\. わからないところノートテイク。
3\. FEドットコムで演習しまくる。
4\. もう一回栢木先生に目通す。
5\. サンプル問題・過去問解いてみる。

なんとなくプログラミングしてたので適当な科目B
科目B対策
1\. とりあえずAtcoder の ABCにでる。3完できるか程度。
2\. 過去問解いてみてリストが1からの設定に気づく。
3\. セキュリティは科目Aの知識と読解で解けそう。

## FEの知識
FEで知識を固めておくとその後の発展的な内容を学ぶ際に役立ちそうなので特に科目Aを重点的にやった。
はじめてのQiita

はじめまして！かずとです！！
今日から自分の学習状況や転職活動など様々な事を書いていこうと思います！☺️

フロントエンドエンジニア目指して頑張ります！！💪

12月はポートフォリオ作成を頑張ります！
![B11BE3AF-1B62-450B-8726-9BF6CC200456.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636099/0be35f30-a1cf-57fe-10cf-60c49c18ac09.jpeg)

まだまだ最初の段階ですが焦らず進めていきます、、😅




さて今週はHTMLCSSとJavaScriptの基本を復習します！まだまだ基礎の基礎もやらなくてはと思いprogateで学習してます！

今日はprogateでHTMLCSSの中級をやりました！ブロック要素とインライン要素、インラインブロック要素が不安だったので再確認できました！

寝るまでまだ時間あるので今日はもう少し学習を進めていきます！！📒
社内LT会 My BEST3

この投稿は[ちゅらデータアドベントカレンダー2023](https://qiita.com/advent-calendar/2023/churadata)の9日目の記事です。


# はじめに
はじめまして、DATUM STUDIO株式会社でエンジニアしています Ryuku です。
弊社では毎月社内のLT会が開催されています。
今回は、今年自分が登壇したLTの中から選りすぐりの個人的BEST3を振り返っていきます。

# My Best3

今回のエントリーは、自分が今年社内LTで登壇した以下、全3タイトルです。
この中からどの3タイトルがBEST3に選ばれるのでしょうか。
- 研修資料をきっかけにSQL苦手意識を克服した(い)話 [5月]
- 文化庁著作権セミナー「AIと著作権」を5分に要約！ [6月]
- 無料で始めるVTuber生活! [11月]

## 研修をきっかけにSQL苦手意識を克服した(い)話
第三位にランクインしました。
SQLの勉強をしたときの備忘録的なLTです。

### 内容
元々苦手だったSQLについて、社内の研修資料で勉強したらいいかんじだったので、そのまま苦手意識を克服しよう！ と思い立った話です。
参考として、こちらは学生の頃に受けた基本情報の成績なのですが、合格基準である6割を、データベースだけが圧倒的に基準を下回っており、他の分野でカバーしているという状態でした。

![スクリーンショット 2023-12-06 19.38.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3631787/4832495d-6e7e-c42c-7dd9-6eb2eaa836ea.png)

そんなSQL苦手を脱却するために実施したことは以下の2つです。
- 前処理大全 (ISBN: 9784774196473) という書籍でデータ分析におけるSQLの立ち位置を知る
- データサイエンス100本ノックで実際に手を動かしてSQLに慣れる

知識と実践の両輪で学ぶことで、SQLに対する理解がかなり深まったと思います。

### 話してみた感想
今年度はLT会に積極的に登壇して喋り慣れていこう！と思っての登壇でした。
5月, 6月と連続で登壇しましたが、2ヶ月坊主となりました (その次の登壇は11月)。
SQL100本ノックは結局TL会当日までに進められた 36/100 問という進捗で止まっています。今回の執筆で思い出したので年末の空いた時間に最後まで走り切りたいです。

## 文化庁著作権セミナー「AIと著作権」を5分に要約！
第二位にランクインしました。
機械学習の研究・利用と創作活動を行う自分にとって打ってつけのトピックでした。

### 内容
忙しい皆様のために、約1時間のこちらの動画を5分のLTとして要約しました。
ここでは、このLTで伝えたかったことを、ひとことで表現します。

    "創作活動"の主体はいつだって人間！ AIを使おうが、どのようなツールを使おうが、著作権の扱いは同じ！！

### 話してみた感想
短い時間制限の中で勘所を絞って話せるかチャレンジしました。
実際のところ、「もっとこういう話も入れたかったな」も割と残ってしまったので、もうちょっと時間もらってもよかったかもしれません。

## 無料で始めるVTuber生活!
第一位にランクインしました。
準備にかかった時間も、当日の反響も最も大きく、自分としても印象に残っているLTでした。
### 内容
ちゅらデータ CTO 兼 CVO (Chief VTuber Officer) [菱沼 雄太](https://twitter.com/foursue) さんの２次元アバターに憧れて VTuberになるべく奮闘した話です。

Live2D を用いて 2D の VTuber モデルを 0 から作りました。
必要な技術をリストアップしていったところ、全部無料で作り切れるじゃん！となり、こちらのタイトルとなった次第です。
![スクリーンショット 2023-12-06 20.10.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3631787/53290691-5d7f-8fdf-4876-b2323d14da57.png)

自分で作ったお手製モデルが「かわいい」と褒めていただけるのはとても嬉しいものです。
![スクリーンショット 2023-12-06 18.34.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3631787/daab8c10-b013-af39-634c-9b08931533f7.png)


### 話してみた感想
LT会に手を挙げて己に締め切りを課すことで、
やりたいと思いつつ先延ばしにしていた2次元アバターの作成に着手できたのは最大の収穫でした。
LT会当日もアバターで参加したことでとても盛り上がってうれしかったです。
因みに、アバターの名前はまだ決まっていません。募集中。

# おわりに
ネタ作りのために普段できないことをしてみたり、人前で話す経験値を積めたり、LT会への登壇は得るものばかりでした。
来年も積極的に参加していきたいです。

# 参考リンク
[データサイエンス100本ノック（構造化データ加工編）のGitHub](https://github.com/The-Japan-DataScientist-Society/100knocks-preprocess)
[令和５年度著作権セミナー「AIと著作権」のYouTube動画](https://www.youtube.com/watch?v=eYkwTKfxyGY)
Workato：レシピで擬似的にWhile文を使う方法

## はじめに

Workatoを使ってレシピを作っている際に、「While文を使えたらな、」と思ったことのある人は多いのではないでしょうか。

しかし、残念ながらWorkatoのアクションでは、while文は存在しません。
![スクリーンショット 2023-12-06 19.43.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628220/254f914a-7ef8-2cb1-da05-b9d508c3d868.png)

よって、ここでは擬似的にWhileの動作を行う方法をお教えします！

## やり方

結論から申し上げると、その方法は

`Lists by Workato の helper list`と `Repeat action`を組み合わせる方法です

Repeat action はプログラミング的な視点で**for文**に当たります。よって、空の補助的なリストを`helper list`で作成し、そのリストに対して、Repeat action を行うことで、無理やりWhile文の動きをさせようというわけです。

## レシピの作り方

ここでは、自分で決めた任意の数（以下の参考では10回）分、同じアクションを繰り返し行うというレシピを紹介いたします。

→つまり、10ループするwhile文です

繰り返す内容は、`repeat action`内に入れ込むだけなので、なんでも良いのですが、今回はspread sheetsに現在のループ回数を書き込むことにしました。

#### １． helper list の作成

まずは「Scheduler by Workato」から「Create repeat helper list」を選択します。

![スクリーンショット 2023-12-06 20.07.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628220/ccadb4a1-561e-29e5-0014-05ddacf4fbb2.png)

#### 2．繰り返し回数を決める

`Size`に繰り返しを行いたい回数を入力します。

![スクリーンショット 2023-12-06 19.30.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628220/a38a249e-48f5-cad8-3c2b-ecb53356b6c8.png)

#### 3.「Repeat action」を選択

Repeat actionを選択し、`Input list`に先ほど作成したHelper listを選びます。
Repeat actionは「One time at a time」を選んでおきます。

![スクリーンショット 2023-12-06 20.14.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628220/8a4f2f2f-69fa-3640-f002-b59d95146b19.png)


#### 4.繰り返し行う動作を入れる

このRepeat actionの中に、繰り返し行ってほしいアクションを入れましょう。
今回は、簡単のため、スプシに出力するだけのレシピにしました。

![スクリーンショット 2023-12-06 20.21.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628220/c8225611-41d7-913a-436b-fedc7cabf96b.png)


#### 結果
スプシの出力から、While文のように10回繰り返し動作したことがわかります。

![スクリーンショット 2023-12-06 20.21.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628220/d801822d-75e8-4615-db40-0de56989eaf2.png)


## 最後に
このようにすることで、擬似的にですがWhile文の動きを実現できました！
皆さんの参考になりましたら幸いです。

（一応、以下にレシピ全体も貼っておきますね）
![スクリーンショット 2023-12-06 19.29.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3628220/e68cd12c-f6d0-2e9e-ad11-40f399eff2f9.png)
計算量オーダーを減らせば必ず高速化するわけではない

プログラムの処理速度を向上させたい場合、まず注目すべき点がアルゴリズムの計算量だと思います。

計算量オーダーを$O(n^2)$から$O(n\log{n})$に減らせれば大幅な高速化が期待できる、と思うのが普通ですが実際にやってみると必ずしも高速化しない場合があります。

## 解説
ご存知の通り、あるアルゴリズムの計算量は一般的にO記法（ランダウの記号）を用いて示されます。
（注：必要なメモリを表す空間計算量も同様にO記法を用いますが、ここでは時間計算量について扱います）
O記法は入力の大きさ$n$に対する**時間の増加の仕方**を表すものですので、**実際に何秒かかるか**ということを示すものではありません。

計算量$O(n^2)$のアルゴリズムは$n$が2倍になったとき、計算時間は4倍になると分かりますが、大事なのは実際にそれが何秒かかるかということです。
それを知るためにはどこか任意の$n$、例えば$n=1$でもいいですし、実際に入力されると想定される範囲の$n$を入力してみて時間を測定する必要があります。
（恐らく多くの場合、$n=1$では時間が短すぎて測定精度が悪いと思うので、実用上の$n$を入力するのが良いと思います）

例えば、以下のようなCのコードは計算量が$O(n^2)$で、$n=1$のとき処理時間は1秒ですから、$n=10$であれば処理時間は100秒であることが予想されます。
```C
for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
        // ここで1秒かかる処理
    }
}
```

ではすごいアルゴリズムが見つかって、計算量オーダーを$O(n)$に落とせたとします。
その代わりループの中の処理はやや複雑になり、時間がかかるようになりました。

```C
for (int i = 0; i < n; i++) {
    // ここで10秒かかる処理
}
```

$n$と処理時間をグラフに表すと以下のようになります。
$n<10$においてはこのアルゴリズム変更はむしろ逆効果であることが分かります。

![graph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632965/4b767386-d085-9240-0bb9-5a2273f96e90.png)

このグラフは、計算時間を以下のように求めています。
$T=n^2$
$T=10n$

O記法では支配的な項のみを記載するため、非支配的な項（例えば$O(n^2)$であれば2乗未満の項があったとしても記載しない）や定数倍については省略されます。
支配的とは「値が大きい場合」の話なので、逆に言えば値が小さい場合には非支配的な項も無視出来ません。

計算量オーダーを落とすために工夫を凝らした複雑なアルゴリズムの場合、この例のように1ループにかかる時間が伸びる場合があります。
凝ったアルゴリズムをがんばって実装したのに、$n$が小さいために効果が無いどころか逆効果だった・・・ということもありえます。

普通は大きい$n$に対してアルゴリズムの改善を実施すると思うので問題になることは多くはないと思いますが「$n$は小さいが時間がかかっているようなループ」に対して「複雑だが計算量を落とせるアルゴリズム」を適用するような場合には注意が必要です。
【初心者やりがち】number型でなんでも受け渡すのはやめとけ

TailwindCSSを利用する場合かつデザインシステムを構築するときおおよそTokenとしてfontSizeやspacingなどを定義すると思います。

```javascript:こんな感じ
export const spacing = {
  4: '0.25rem',
  8: '0.5rem;',
  12: '0.75rem;',
  16: '1rem',
}
```
ただ、せっかく定義したのに型定義でサボると残念なことになります…。

:::note info
初心者の私がやらかしたミスを皆さんはしないで！を伝える記事となっています！
:::

## tailwind.configを利用して型定義する
結論から言うと、**せっかく定義したなら利用して型を縛ろう**です！

下記のようなコンポーネントがあったとします。
コードの良し悪しは一旦目をつむってください…。

```typescript
import { FC } from 'react'

type Props = {
  spacing?: number
}

export const Component: FC<Props> = ({ spacing }) => {
   let spacingClass
   switch(spacing) {
     case 4:
       spacingClass = 'mt-1'
       break;
     case 8:
       spacingClass = 'mt-2'
       break;
     case 12:
       spacingClass = 'mt-3'
       break;
     case 16:
       spacingClass = 'mt-4'
       break;
     default:
       spacingClass = ''
   }
　  return <div className={spacingClass}>component</div>
}
```
この状態だとspacingのpropsは数字であればなんでも受け取ってしまいます…。

:::note alert
コンポーネントを使う人が特定の数字でないとspacingClassが機能しないことを知らないと使えないBadな状態です…
:::

なのでtailwind.configから定義したspacingのkeyを利用して型をつけます！

```diff_typescript
import { FC } from 'react'
+ import { spacing } from '../tailwind.config'

+ type Spacing = keyof typeof spacing

type Props = {
-  spacing?: number
+  spacing?: Spacing
}

export const Component: FC<Props> = ({ spacing }) => {
   let spacingClass
   switch(spacing) {
     case 4:
       spacingClass = 'mt-1'
       break;
     case 8:
       spacingClass = 'mt-2'
       break;
     case 12:
       spacingClass = 'mt-3'
       break;
     case 16:
       spacingClass = 'mt-4'
       break;
     default:
       spacingClass = ''
   }
　  return <div className={spacingClass}>component</div>
}
```

上記のようにすることで呼び出し時に型の推論が効くので利用者がスタイルが当たらない！ってことにはならないと思います！

:::note
下記のようにリテラル型で定義することも可能です。

```typescript
type Props = {
  number: 4 | 8 | 12 | 16
}
```
やりたいことは実現されますが、急に出てきた4や8などはマジックナンバーと捉えられなくもありません…


なので定義したものを利用することで「なんの数字か？」の説明にもなるためimportしたものを利用するがの良いかと思います！
:::

## 【number型でなんでも受け渡すのはやめとけ】まとめ
numberやstringなどを単純に指定するだけだと型を縛れているようで実はそうではないことを知りました。

:::note info
TaiwindCSSであれば自分で定義したものも使えますが、Tailwindが用意してくれたspacingのkeyを利用することも可能です！
:::

より良いコンポーネントを作成できることを願っております！
paiza.ioでelixir その264

# 概要
paiza.ioでelixirやってみた。
genserverの並列動作、コード見つけたのでやってみた。

# 参考にしたページ

https://blog.emattsan.org/entry/2023/08/29/120000

# サンプルコード

```

defmodule MyApp0.Worker do
  use GenServer
  def start_link(opts) do
    GenServer.start_link(__MODULE__, opts, name: __MODULE__)
  end
  def do_heavy(n) do
    GenServer.call(__MODULE__, {:do_heavy, n})
  end
  def init(_) do
    {:ok, %{}}
  end
  def handle_call({:do_heavy, n}, _from, state) do
    Process.sleep(100)
    {:reply, {:ok, n}, state}
  end
end

defmodule MyApp.Worker do
  use GenServer
  def start_link(opts) do
    GenServer.start_link(__MODULE__, opts, name: __MODULE__)
  end
  def do_heavy(n) do
    GenServer.call(__MODULE__, {:do_heavy, n})
  end
  def init(_) do
    {:ok, %{}}
  end
  def handle_call({:do_heavy, n}, from, state) do
    task = Task.async(fn ->
            Process.sleep(100)
            {:ok, n}
        end)
    {:noreply, Map.put(state, task.ref, from)}
  end
  def handle_info({ref, {:ok, n}}, state) do
    case Map.get(state, ref) do
    nil ->
        {:noreply, state}
    from ->
        GenServer.reply(from, {:ok, n})
        {:noreply, Map.delete(state, ref)}
    end
  end
  def handle_info({:DOWN, _, _, _, _}, state) do
    {:noreply, state}
  end
end

MyApp.Worker.start_link([])

start_time = Time.utc_now()
1..3
|> Enum.map(fn n ->
  Task.async(fn ->
    n
    |> MyApp.Worker.do_heavy()
    |> IO.inspect()
  end)
end)
|> Task.await_many()

end_time = Time.utc_now()
Time.diff(end_time, start_time, :millisecond) 
|> IO.puts()



```

# 実行結果

```
{:ok, 1}
{:ok, 2}
{:ok, 3}
109
```

# 成果物

https://paiza.io/projects/Q-LD8DwvWaprtNGqdbv78w?language=elixir


以上。
OpenAIのWhisperをNode.jsで触って会議音声の文字起こしを試してみる


文字起こしで使えると話題のWhisperを使ってSTT(Speech to Text)してみます。

ちなみに逆のTTSはこちら

https://qiita.com/n0bisuke/items/10c9a9aa02bfb62fd158

## 公式にはPython版サンプルはあるけど

https://platform.openai.com/docs/guides/speech-to-text?lang=python

公式にはPython版はありましたが、JavaScript版がなかった感じです。

Node.jsから触りたいですが、以外とコピペできそうなコードが落ちてなくて

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

こちらのYouTubeが参考になりました。



## まずは文字起こし用音声 - 25MBまで

Google Meetで録画したMP4ファイルをMacで書き出してm4aファイルにしました。

調べてると

> File uploads are currently limited to 25 MB and the following input file types are supported: mp3, mp4, mpeg, mpga, m4a, wav, and webm.

と書いてあり、1回のリクエストで25MBまでのファイルしか扱えない模様だったのでかなり一部だけにトリミングしてます。

> ![スクリーンショット 2023-12-06 19.53.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/5cb7a0db-e990-52bd-1a32-151276226600.png "スクリーンショット 2023-12-06 19.53.54.png")

拡張子は以下が使える様ですね。

- mp3
- mp4
- mpeg
- mpga
- m4a
- wav
- webm

### openaiライブラリで試す

ライブラリはGPTなどを使う時と同様です。

```
$ npm i openai
```

APIキーも同様です。

> こちらから取得
> https://platform.openai.com/api-keys

```js
const fs = require('node:fs');
const OpenAI = require('openai');

const audioFilePath = './speech2.m4a'; // 音声ファイルのパスを指定
const openai = new OpenAI({
    apiKey: 'APIキー',
});

async function main() {
    // Whisperモデルを使用してテキスト変換リクエストを送信
    const response = await openai.audio.transcriptions.create({
        model: "whisper-1",
        file: fs.createReadStream(audioFilePath),
        language: "ja",
    });

    // 変換されたテキストを出力
    console.log(response);
}

main().catch((err) => {
    console.error(err);
    process.exit(1);
});
```

### 出力結果を眺める

某商工会議所の人とMTGしたときの会話ログの一部です。名前は伏せて別名にしてますが出力としては一人の方は珍しい苗字だったので読み取れてなかったですが僕も聞き取れなかったので仕方なしな気がしました。

```bash
$ node app.js

{
  text: 'どうも野火助と申します よろしくお願いします ありがとうございます よろしくお願いします XX商工会議所の田中と申します よろしくお願いします 佐藤と申します よろしくお願いいたします'
}
```

こんな感じでした。

どうものびすけと申します。ってところが謎に野火助になってますが、全然良いですね。

本当は3人での会話でした。

のびすけ: 「どうものびすけと申します　よろしくお願いします」
田中さん: 「ありがとうございます　よろしくお願いします　XX商工会議所の田中（別名）と申します」
佐藤さん: 「よろしくお願いします　佐藤と申します」
のびすけ: 「よろしくお願いします」

平坦になってしまっていて人の認識までは出来てないですが、結構良い精度なのかなとは思います...が、まだデータ不足でなんともですね。

## 参考

https://platform.openai.com/docs/guides/speech-to-text?lang=curl

https://zenn.dev/nakatama/articles/7ea5df13ca6e36

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

https://github.com/openai/openai-node/blob/master/examples/audio.ts
Pydanticの方に応じて場合分けする方法

**注意**
未経験から転職した、一年目のエンジニアが、作成したものになります。
そのため、至らぬ表現や、誤った表現をしている場合があります。

経験豊富な先輩エンジニアの方々へ
もし、誤った情報を記載していた際は、大変お手数をおかけしますが、ご指摘いただけますと幸いです。

少しでも、皆様のお役に立てれば幸いです。

# 記事の内容

-   やりたいこと
-   なぜ行ったか
-   対処方法
-   参考文献

## やりたいこと

適用した型の情報に応じて場合分けをしたい。

## なぜ行ったか

Pydantic で、自身のスキーマ(型)を作成した。<br>
そしてスキーマ(型)情報を、関数の引数として適用した。<br>
その際に、型の情報を取得するのに苦戦したため、この記事を共有いたします。

## 対処方法

type 関数を使用して、型情報を取得できる

```python
if type(型が適用された引数) = スキーマ(型)のクラス
```

```python
from pydantic import BaseModel

class User(BaseModel):
    name: str
    age: int

user = User(name='Hoge', age=22)

if type(user) == User
  # userインスタンスの方がUserだったときの記述を書く
```

Pydantic には、自身の型を取得するメソッドは見当たらず...
しかし、type 関数を使用すれば、型情報が得られることがわかりました。

少しでも、お役に立てれば幸いです。
wslでnerves その40

# 概要
wsl(wsl2じゃない)でnervesやってみる。
qemu(x86_64エミュレータ、ラズパイじゃない)でやってみた。
生成したnerves_livebook.imgを、QEMUで起動してテストしてみた。
GPIOが無いので、マウスを認識できる様にする。
InputEvent を使ってみる。

# 参考にしたページ

https://blog.emattsan.org/entry/2021/05/24/175500


# セットアップ

```
Mix.install([
	{:input_event, "~> 1.4.2"}
])
```

# サンプルコード

```
InputEvent.enumerate()
```

# 実行結果

```
[
  {"/dev/input/event0",
   %InputEvent.Info{
     input_event_version: "1.0.1",
     name: "Power Button",
     bus: 25,
     vendor: 0,
     product: 1,
     version: 0,
     report_info: [ev_key: [:key_power]]
   }},
  {"/dev/input/event1",
   %InputEvent.Info{
     input_event_version: "1.0.1",
     name: "AT Translated Set 2 keyboard",
     bus: 17,
     vendor: 1,
     product: 1,
     version: 43841,
     report_info: [
       ev_rep: %{period: 33, delay: 250},
       ev_led: [:led_numl, :led_capsl, :led_scrolll],
       ev_msc: [:msc_scan],
       ev_key: [:key_esc, :key_1, :key_2, :key_3, :key_4, :key_5, :key_6, :key_7, :key_8, :key_9,
        :key_0, :key_minus, :key_equal, :key_backspace, :key_tab, :key_q, :key_w, :key_e, :key_r,
        :key_t, :key_y, :key_u, :key_i, :key_o, :key_p, :key_leftbrace, :key_rightbrace, :key_enter,
        :key_leftctrl, :key_a, :key_s, :key_d, :key_f, :key_g, :key_h, ...]
     ]
   }},
  {"/dev/input/event2",
   %InputEvent.Info{
     input_event_version: "1.0.1",
     name: "QEMU QEMU USB Mouse",
     bus: 3,
     vendor: 1575,
     product: 1,
     version: 1,
     report_info: [
       ev_msc: [:msc_scan],
       ev_rel: [:rel_x, :rel_y, :rel_wheel, 11],
       ev_key: [:btn_left, :btn_right, :btn_middle, :btn_side, :btn_extra]
     ]
   }},
  {"/dev/input/event3",
   %InputEvent.Info{
     input_event_version: "1.0.1",
     name: "ImExPS/2 Generic Explorer Mouse",
     bus: 17,
     vendor: 2,
     product: 6,
     version: 0,
     report_info: [
       ev_rel: [:rel_x, :rel_y, :rel_hwheel, :rel_wheel],
       ev_key: [:btn_left, :btn_right, :btn_middle, :btn_side, :btn_extra]
     ]
   }}
]
```


以上。
PHPの全角 trim には気をつけましょう

## PHP 8.4 未満では全角スペースを正しく trim できない

参考記事：https://qiita.com/rana_kualu/items/87bc5dd0396103bd7a32

どういう事かと言うと、例えば下記のコードがあったとします

```
#!/usr/local/bin/php
<?php

echo trim('　イェーイ',  '　');

?>
```

この結果の期待値はもちろん「イェーイ」ですね

### では実行結果を見てみましょう

```
$ ./php-trim-error.php

��ェーイ
```

**おめでとうございます！！！！！**　正しく文字化けしましたね！！！ :scream:

この辺りは文字コード表とかググっていただければと思いますが、UTF-8 でもこの問題は解決できません。

## じゃあ、どうすれば！？

PHP 8.4 以上に上げれば良いと思われますが、現状 PHP 8.4 は業務では使えません。執筆時の2023年12月時点ではお客様の強いご要望が無い限り RHEL 9 で納品するとなれば PHP 8.0 です。

### PHP 8.4 (見込み) が普及するまでは preg_replace を使うしかない

```
#!/usr/local/bin/php
<?php

echo preg_replace('/^\s+|\s+$/u', '', '　イェーイ');

?>
```

### 実行結果
```
$ ./php-trim-error.php

イェーイ
```

イェーイ！！！！！🎉🎉🎉🎉🎉🎉🎉🎉

( Shift_JISはもうそろそろ無くなっても良いと思う...ので度外視してます。必要であれば mb_convert_encoding かましてくだされ... )

　
それなりのデータ数が無いと気付かない盲点なので、この記事が参考になれば幸いです
［2023年］今年お世話になったハンズオンサイトまとめ

どうもこんにちは、たくびー(@takubii)です。
2023年を通して業務でも趣味でも新しい分野に触れることが多い一年でした。
その中で私がお世話になったサイトを皆さんに共有したいと思います。

# React系ハンズオン一覧

React関連では以下のサイトを使用しハンズオン形式で学びました。

## React

https://react.dev/learn/tutorial-tic-tac-toe

サイトが新しくなりチュートリアルも関数コンポーネントにアップデートされているので、以前やったことある方ももう一度復習として取り組むことをおすすめします。

また、サイト全体でドキュメントに編集可能なソースコードが掲載されているようになりました。
おかげで手を動かして学べるので困ったら公式ドキュメントを参照しています。

## Next.js

https://nextjs.org/learn?utm_source=next-site&utm_medium=navbar

こちらは公式のNext.jsのチュートリアルです。
私が実際に取り掛かったのはバージョンアップ前のものですが、その時にPage RouterからApp Routerへの移行をチュートリアルを使って行ってみました。

新しくなったチュートリアルもぜひ取り掛かってみたいです。

https://eh-career.com/engineerhub/entry/2023/04/18/093000

App Routerについてのハンズオンで最初に取り掛かったのがこちらでした。
Next.js以外でもPrisma、Zod、Tailwindcssなどモダンな構成で作成できるのでとてもおすすめです。
Next.jsの第2のチュートリアルといっても過言ではありません。

## Redux

https://redux.js.org/tutorials/essentials/part-1-overview-concepts

技術としては少し古いのですが、チュートリアルの内容はボリュームがあり、作成できるものもSNSライクの物なので作っていて楽しかったです。

Reduxのメジャーバージョンも上がったので、チュートリアルも更新されることを期待してしまいます。

## Recoil

https://recoiljs.org/

状態管理ライブラリを探している時にReduxの次に試したライブラリです。
チュートリアルの内容はReactベースでしたが、Next.jsにハマっていた時期だったのでNext.jsで作成しました。

導入も使い方も簡単ですが、最近の更新頻度が低いのとメジャーバージョンに達していない部分が少し残念です。

# Solid.jsハンズオン

https://www.solidjs.com/tutorial/introduction_basics

業務でSolid.jsを使う機会があったので公式ドキュメントにはお世話になりました。
新興ライブラリには珍しく日本語対応されており、チュートリアルも同様です。

チュートリアル自体は各機能ごとにステップアップ形式で学んでいく感じです。
個人的にはサンプル集が豊富で、いろんな実装が見られたのでそちらもかなり参考になりました。

# Python系ハンズオン一覧

Python関連で主にDjangoについて以下のサイトで学びました。
前職でBackendは慣れていたつもりだったのでいきなりDjangoコードに触りましたが、ちんぷんかんぷんだったので基礎から固めるのは大事だなと思いました。

## Python

https://utokyo-ipp.github.io/index.html#

東京大学が出しているPythonの学習サイトです。
基礎の基礎から最終的には周辺ライブラリまで網羅しているので、こちらのサイトを通せばPythonに関しては問題なくなるでしょう。

サイト内では[Colaboratory](https://colab.research.google.com/)で進めていますが、私はVScodeで進めました。

## Django

https://tutorial.djangogirls.org/ja/

DjangoでWeb制作を学ぶ場合はまずDjangogirlsに取り掛かることをおすすめします。
非常に丁寧に進めているので詰まるところは一切ありませんでした。
デプロイなども学べるので実践的な部分もあります。

https://docs.djangoproject.com/ja/4.2/intro/tutorial01/

Djangogirlsだと物足りなく感じたので、公式のチュートリアルにも取り掛かりました。
モデルの書き方やAdminサイトのカスタマイズなどDjangogirlsとは少し差分があるので、なるべく両方取り掛かる方が良いと感じました。
また、公式なだけあり常にLTS〜最新の情報が載っているので間違いはないです。

# Flutterハンズオン

https://codelabs.developers.google.com/codelabs/flutter-codelab-first?hl=ja#0

今までアプリ開発の方はReact Nativeをメインに行なっていましたが、Flutterにも興味が湧き公式が提供していたこちらのハンズオンも触ってみました。

Flutterはデフォルトで提供されているMaterialデザインのパッケージがあるので、デザインに精通していなくても見栄えの良いアプリが作れるのでアプリを作っていて楽しかったです。

私の場合はこれだけだとまだまだFlutterを使いこなすことは難しいと感じているのでさらに他のサイトで手を動かして学びたいと思っています。

# まとめ

公式ドキュメントには良質なチュートリアルが用意されているので、私の場合新しい技術を学ぶ時はまずチュートリアルから入ることが多いです。

ChatGPTの登場でいきなりコーディングできるようになってきましたが、やはり基礎的な部分は大事だと思うので手を動かしながら学べるのはとても理解の助けになります。

チュートリアルでは物足りないなと感じた時はハンズオン形式の紹介記事や個人ブログ、Free Code Campなどでサンプル集を探すことが多いです。

この記事が新しい技術の学び始めの参考になれば幸いです。

それではこの辺りで締めたいと思います。
また機会があればお会いしましょう。
ChatGPT Plusを解約して返金してもらう

Bing Chat CopilotやGoogle Bard Geminiで十分だったのでChatGPTを解約した。解約するのを忘れてたw

https://www.businessinsider.jp/post-279519



Open AIにメールを送る refunds@openai.com

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208363/2af11016-5272-cabc-2ff8-e7d619df6bd1.png)

返信が来たら、返金完了メールが届く

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208363/91b3e2ff-b960-6b84-a1ee-528096cbbc99.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208363/c2b5e922-5e70-f899-3048-6396335b25b7.png)
Amazon EventBridgeをCfnで作成するときのcron式

# はじめに
EC2の夜間停止設定を行うときにCloudFormationを使いました。
その時にややこしかったcron式についてまとめます。

# 問題
EC2を起動しておきたい時間帯は8:00～19:30の間で、それ以外の平日夜間と土日は
EC2を停止させる設定をAWS EventBridgeのルールで実現します。

その設定でcron式を用いるのですが、これが少しややこしく、
慣れていない方にとっては理解に少々時間がかかるかもしれません。


実際、私は10分ほどかかりました。
<br>

最初に作成したCloudformationテンプレート以下のとおりです。

```yaml:Cloudformationの内容抜粋
Parameters:
  ScheduleStartTime:
    Type: String
    Default: "cron(0 8 ? * MON-FRI *)"
  ScheduleStopTime:
    Type: String
    Default: "cron(30 19 ? * MON-FRI *)"
--------------------------
(省略)

```

ぱっと見、上記のコードでうまく設定できているような気がします。

ですが、このままでは`17時から起動し、夜中の4時30分に停止する`のような設定になってしまいます。

# 解決方法
EventBridgeのルールでcron式を用いる場合、UTC時間で考える必要があります。
詳しくは[「UTC」と「JST」 - Linux技術者認定 LinuC | LPI-Japan](https://linuc.org/study/knowledge/333/#:~:text=%E6%97%A5%E6%9C%AC%E3%81%A7%E3%81%82%E3%82%8C%E3%81%B0%E3%80%81UTC,%E5%AE%9A%E3%82%81%E3%82%89%E3%82%8C%E3%81%A6%E3%81%84%E3%81%BE%E3%81%97%E3%81%9F%E3%80%82/)を参考にしてほしいのですが、簡単にまとめると以下の通りです。

- UTCは協定世界時
- 経度0度の場所の時間
- JST（日本標準時）との時差は9時間

上記を加味すると、EventBridgeでのcron式の設定は以下のようにする必要がるのです。

```yaml:Cloudformationの内容抜粋
Parameters:
  ScheduleStartTime:
    Type: String
    Default: "cron(0 23 ? * MON-FRI *)"
  ScheduleStopTime:
    Type: String
    Default: "cron(30 10 ? * MON-FRI *)"
--------------------------
（省略）

```
# おわりに
EventBridge ルールのcron式もEventBridge スケジュールのcron式のように
JSTで設定できれば早いのに。。。

# 参考
[「UTC」と「JST」 - Linux技術者認定 LinuC | LPI-Japan](https://linuc.org/study/knowledge/333/#:~:text=%E6%97%A5%E6%9C%AC%E3%81%A7%E3%81%82%E3%82%8C%E3%81%B0%E3%80%81UTC,%E5%AE%9A%E3%82%81%E3%82%89%E3%82%8C%E3%81%A6%E3%81%84%E3%81%BE%E3%81%97%E3%81%9F%E3%80%82/)
Github ActionsでIssueの追加をREADMEに反映させる

# はじめに
[コピーレフト](https://www.gnu.org/licenses/copyleft.ja.html)寄りの[にわのわ](https://twitter.com/niwa_nowa)です。

ToDo管理にGithubのIssueを使っているのですが、READMEでIssueの一覧で表示できると嬉しいと思い作りました。

# 作ったもの
今回作ったものはこちらです。
詳しい使い方はREADMEに書いてあるのでそちらを参照してください。

https://github.com/niwanowa/ReadmeIssueSyncAction

# 内容
Issueの追加、編集、削除をトリガーにREADMEを更新するGithub Actionsです。
Github REST APIを使ってIssueの一覧を取得し、GHA上にクローンされたREADMEを更新します。
その後、予めSeacretsに設定したGithub情報を使ってコミット、プッシュを行います。

# つまづいたところ
GHA上でコミット、プッシュを行うためには、workflow permissions設定を変更する必要がありました。
[act](https://github.com/nektos/act)というGHAをローカルで実行できるツールを使ってテストしていたのですが、
これでは拾えないエラーだったのでかなり苦しみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590707/2ed021c7-7cb8-fe94-e96d-9a4ee5fe5154.png)

# おわりに
workflow permissionsなどのGithub Repositoryの設定は.githubフォルダの中で管理できないのでしょうか？
軽く調べてみても引っかからず、断念してしまいました...

# 参考

https://docs.github.com/ja/rest

https://github.com/nektos/act
Nuxt3のserver middlewareで追加したevent contextに型を付けたい

# 導入
今日の話題はNuxt3のserver middlewareで追加したevent contextにTypeScriptの型を付けたいという内容です。
（Nuxt3のバージョンは3.6で確認）

:::note info
※ 私が株式会社愛宕 Advent Calendar 2023に書く記事は主に社内向けに共有しておきたいけど勉強会をするまでもないちょっとしたTipsにしたいと思います。
:::

Nuxt3ではサーバーサイドの実装でミドルウェアを作成しリクエストごとに共通的に呼び出される処理を記述することができます。
さらに、このミドルウェアの内部でevent contextに何らかの値を代入すると各APIで利用できるようになって便利です。
例えば、認証済かどうかチェックしてセッションオブジェクトを構築しcontextに紐づけておくなどの使い方が一般的でしょう。

```TypeScript:server/middleware/auth.ts
export default defineEventHandler(async (event) => {
  const sessionId = getCookie(event, "cookie-name")
  // 取得したデータを使って何かの構築をしたり判定をしたり
  // ...中略...
  event.context.hoge = new Hoge(sessionId) // 各APIで共通的に使えるように代入しておく
})
```

ここで、`event.context`のインターフェースには`hoge`はないですが、`extends Record<string, any>`で宣言されているため一応`hoge`というプロパティは使用できます。
ただし、型が`any`になってしまい、各APIで使用するときに不便です。
正しく`Hoge`型を付けるにはどうすればいいんでしょうか？

# 解決
TypeScriptでは既存の型を拡張することができます。`event.context`はh3モジュールの`H3EventContext`というインターフェースなので次のようにすれば型を付けることができます。

```TypeScript:server/middleware/auth.ts
declare module 'h3' {
  // 普通にここにインターフェースを書けばマージしてくれる
  interface H3EventContext {
    hoge: Hoge
  }
}
```

同様に、サーバーサイドのプラグインで`nitroApp`にデータを埋め込んで各APIで`useNitroApp()`を呼び出して再利用することもできます。ただし、こちらは`extends Record<string, any>`ではないのでこういう使い方は非推奨なのかもしれません。

```TypeScript:server/plugins/dependencies.ts
export default defineNitroPlugin((nitroApp) => {
  // ...省略...
  nitroApp.dependencies.push(hogeClient)
})
```

`nitroApp`はnitropackモジュールの`NitroApp`というインターフェースなので次のようにすれば型を付けることができます。
```TypeScript:server/plugins/dependencies.ts
declare module 'nitropack' {
  // 普通にここにインターフェースを書けばマージしてくれる
  interface NitroApp {
    dependencies: Dependency[]
  }
}
```
Ubuntu Gnomeでタッチパッドの(右)クリックが動作しない

```bash
gsettings set org.gnome.desktop.peripherals.touchpad click-method areas
```

上記コマンドで設定を変更する

https://www.dell.com/support/kbdoc/ja-jp/000129850/ubuntu-ubuntu-18-04-lts%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E5%BE%8C%E3%81%AB%E3%82%BF%E3%83%83%E3%83%81%E3%83%91%E3%83%83%E3%83%89%E3%81%AE%E5%8F%B3%E3%82%AF%E3%83%AA%E3%83%83%E3%82%AF%E3%81%8C%E5%8B%95%E4%BD%9C%E3%81%97%E3%81%AA%E3%81%8F%E3%81%AA%E3%82%8B#TOC
【DB設計】DM機能実装のためのDB設計で大苦戦した初心者の話

## 要約
現在作成しているアプリで実装予定の機能の一つに、DM機能があります。

しかしそのための論理設計（DB設計）の過程で、なぜエンティティとしてメッセージルームが必要なのか、理解するのに時間がかかりました。

結論として、自分は**手書きでテーブルとレコードを作成し、どんなエンティティが必要かイメージすること**で解決できました。

## 本記事はこんな人におすすめ
* DB設計でエンティティの抽出に苦戦している方
* DB設計における初心者の躓きポイントを知りたい方

なお、用語やそもそもの理解に誤りがあるかもしれませんが、どうか生暖かい目で見守っていただけますと幸いです。

## 問題
* DM機能のために必要なテーブルが分からない
* usersテーブルとmessagesテーブルの他にmessage_roomsテーブルも必要だと言われたが、なぜ必要だか理解できない
* よっておそらく、DB設計の体系的知識がない

## アプローチ
まずDM機能に必要なテーブルは何か、[LaravelDB.com](https://zenn.dev/daisu_yamazaki/articles/fd4bb53d28dab7ef907a)を使って考えてみました。

![ER図](https://i.gyazo.com/7298116a6b50ce8a300f929f64670da7.png)

> DM要素には「usersテーブル」と「messagesテーブル」が必要で、そんで中間テーブル「user_messages」を用意して…

という思考だったと思います。

しかし今見てみると、そもそも「多対多」のリレーションがないのに、なぜか中間テーブルを用意しています。

この時点で有識者にフィードバックを求めた所、

『この設計だとメッセージをユーザーが送信することはできますが、誰が受信するかが分からない設計になっています』

とヒントを頂きました。

しかしそこから手が進まなかったので、一度基本的な部分を勉強することにしました。

:::note info
教訓①
**「理解することをサボらない」**
:::


## 少しの遠回り
そこで『[達人に学ぶDB設計徹底指南書](https://www.amazon.co.jp/-/en/%E3%83%9F%E3%83%83%E3%82%AF-ebook/dp/B00EE1XPAI/ref=sr_1_2?adgrpid=51694709245&gclid=CjwKCAiAjrarBhAWEiwA2qWdCEQ5Zw7x2bqlnkGK7cP2bCfGzOGImBO3062YPC12hSqGu5GnA1GGcxoCV54QAvD_BwE&hvadid=678980414772&hvdev=c&hvlocphy=1009294&hvnetw=g&hvqmt=e&hvrand=12835731150208900160&hvtargid=kwd-333952501323&hydadcr=15819_13711663&jp-ad-ap=0&keywords=%E9%81%94%E4%BA%BA%E3%81%AB%E5%AD%A6%E3%81%B6db%E8%A8%AD%E8%A8%88&qid=1701738478&sr=8-2 "達人に学ぶDB設計徹底指南書")』を読み、インプットと[アウトプット](https://qiita.com/Yuzaburo/items/0a2eff14d213fb70395b)を行うことで解決を図ります。

その結果、なんとなく『**「論理設計」の中のエンティティの抽出がうまくいっていないのではないか？**』と、勘所を見つけて解決することができました。

少し時間はかかりましたが、結果としてDB設計の全体像を少し掴めた気がします。

## 解決への道


再度エンティティの抽出からやり直した結果、今のままだとuserとmessageが割り当てられる場所がないことに気づきました。

そこで、新たに「message_rooms」テーブルを設置。

そしてユーザーとメッセージルームの「多対多」のリレーションを仲立ちする中間テーブル「message_room_user」も必要でした。

最終的な完成図は以下の通りです。

![ER図](https://i.gyazo.com/0132a6c6f72fd80e5b3ec9af6175c626.png)

解決に至っては、以下のように手書きでテーブル内のレコードを書き、イメージしてみるという手法も有効でした。

![IMG_4333.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620668/c5af6da1-c2f2-8325-14b6-029c17e35ef0.jpeg)
（冗談抜きで汚くてすみません・・・）
Google Cloudの監査ログから未使用Service Account JSON Keyを見つける方法

以下の記事ではService Account単位で利用されているかどうかをチェックしていましたが、Service AccountのJSONキー単位でも同様のことをやってみます。

https://qiita.com/shiozaki/private/c4ee4e60469546e4ec31

```sql
with service_account_keys as (
  select
    -- 先頭にiam.googleapis.comを付けないと監査ログのフォーマットと一致しないので付与
   '//iam.googleapis.com/' || json_value(resource.data, '$.name') as key_name,
  from <Cloud Asset Inventoryのresource情報>
  where asset_type = 'iam.googleapis.com/ServiceAccountKey'
), audit_logs as (
  select
    date(timestamp, 'Asia/Tokyo') as date,
    protopayload_auditlog.authenticationInfo.serviceAccountKeyName as key_name,
  from <Audit LogのActivityログ>
  where protopayload_auditlog.authenticationInfo.serviceAccountKeyName is not null
  union all
  select
    date(timestamp, 'Asia/Tokyo') as date,
    protopayload_auditlog.authenticationInfo.serviceAccountKeyName as key_name,
  from <Audit LogのDataAccessログ>
  where protopayload_auditlog.authenticationInfo.serviceAccountKeyName is not null
), usage_counts as (
  select
    key_name,
    count(*) as count
  from audit_logs
  where date > current_date('Asia/Tokyo') - interval 30 day
  group by key_name
)

select
  key_name,
  ifnull(count, 0) as count,
from service_account_keys
left join usage_counts using(key_name)
order by count asc

```
【積読】自分には関係ないと思っていた「積読」が発生した話【アドカレ】

積読アドカレの14日目です。
https://adventar.org/calendars/8637

## 積読には縁がなかったはずだった

こんにちわ。kinocoboyといいます。

今までの人生において、「積読」なんて発生するような事態になることはないと思っていたが、

ついに我が家にも「積読」が発生してしまった。

積読が発生するに至った経緯を振り返ったら、学びがあったのでまとめたい。

## なぜ積読が発生したのか

もともと本は読むほうだと思っていたが、積読してまで本を読むタイプではなく、

一冊買ったら、１冊読みきるまで次を買わないような向き合い方をしていた。

そんな自分がなぜ積読が発生するに至ったかというと、

それはたくさん本を読むことができるという自信がついたからだと思う。

## なぜ自信がついたのか

これは、先輩から「ちゃんと読まない」本の読み方を教わったからである。

今まで本は一字一句落とさないようにしっかりがっちり読まなくちゃいけないと思っていた。

でも「ちゃんと読まない」ことが大切だと教わってから、

本への向き合い方と読み進めるスピードが格段に変わった。

## ちゃんと読まない

どんな分厚さの本だとしても、必ず15分で最後まで読み切ること！

これを徹底するのだと教わった。

内容が頭に入らなくてもいいので、15分で必ず読み終える事。

これを実際にやってみると、不思議なもので本当に頭の中に必要なエッセンスはそろっていく。

イメージを言うと、重要だと思ったポイントがどの本に書いてあるのかがインプットできる感覚があった。

## 重要なエッセンス

重要なエッセンスは、パラパラと読んでいても刺さるものは刺さる。

そして、１冊１００円でも、３０００円でも刺さるものは、パラパラでも見つけることができた。

この経験を繰り返していくうちに、あの本も読んでみたい。

この本も読んでみたい。

といった、読書の好奇心に煽られる日々に変わっていった。

## そして積読へ

今、気になった本をとにかくぽちる。

リスペクトする人が勧めてくれた本は、とにかくぽちる。

課題に感じている分野の本はとにかくぽちる。

今読む時間がなかったとしても、

きっと１５分を捻出できる時間を自分は作り出せるだろうと期待をしながら、

本をとにかく買いあさるようになった。

本は届いたのだが、あの日買った本を読まずに本棚に詰め込んでいる。

ついに我が家に積読が発生してしまった瞬間だ。


## まとめ

* ちゃんと読まない読書をすると、本を読む自信がつく。
* 本を読む自信がつくと、本に頼るようになる
* 本に頼れると、いろいろなエッセンスをもらいたくなる
* 本を沢山買いたくなる
* 結果、読まずに積む
* 見事、積読の誕生

本を仕入れるタイミングと読むタイミングを分離しているだけなのだ、

と自分に言い聞かせて、まだ本に手を伸ばしていない。

メリークリスマス
vim の色々な機能

こちらは [デジタルキューブグループ Advent Calendar 2023](https://qiita.com/advent-calendar/2023/digitalcube-heptagon) 7日目の記事となります！

# はじめに

みなさん Vim は使っておりますでしょうか。
~~僕は VSCode を使っています。~~

みなさんも、ターミナルからテキストファイルを修正したいとき、SSH した先でテキストファイルを修正したいとき、Vim を使うタイミングはそこそこあるのではないでしょうか。
僕もそうです。
が、なんだか機能を全部使いこなせていない気がします。

Vim の基本的な操作と、便利な機能について紹介していきます。

# 1. Vimの基本操作

Vimの基本操作には、ノーマルモード、インサートモード、ビジュアルモードなどがあります。

**ノーマルモードでの基本操作**
```
移動: `h`、`j`、`k`、`l`（左、下、上、右）
削除: `x`（カーソル位置の文字を削除）
コピー: `y`（ヤンク）、`p`（ペースト）、`yw`（単語をコピー）
```
移動は `2h` `5k` のように前に数字を入れることでその回数分移動できます。

**インサートモードへの切り替え**
```
`i`（カーソル位置に挿入）、`a`（カーソルの次に挿入）
```

# 2. インサートモードとビジュアルモード

テキストの挿入や編集はインサートモードで行います。

**インサートモードへの切り替え**
```
ノーマルモードで `i` を押すと、カーソル位置から挿入が始まります。
`a` はカーソルの次から挿入が始まります。
```

**ビジュアルモードの利用**
```
`v` を押すと、文字単位での選択が可能。
`V` で行単位、`Ctrl+v` で矩形選択ができる。
```

# 3. マクロの活用

Vimのマクロ機能は、反復作業の自動化から複雑なタスクの実行まで、様々な場面で利用できます。

**マクロの録音:**
```
`q` でマクロの記録を開始し、任意のアルファベットでマクロの名前を指定。
実行するコマンドを記録。
`q` で録音終了。
```

**マクロの確認:**
```
`:reg` で記録したマクロの一覧が表示される
```

**マクロの実行:**
```
`:reg ` に続けてマクロ名を入力すると、記録した操作が再生される。
```

# 4. 画面分割機能
Vimでは、複数のファイルや同一ファイルの異なる部分を同時に表示するための画面分割機能があります。
コマンドは基本的に control + w を押した後にそれぞれのコマンドを続ける、というふうになっています。

**基本操作:**
```
Ctrl+w + s : 新しいウィンドウを水平に分割
:sp : 新しいウィンドウを水平に分割

Ctrl+w + v : 新しいウィンドウを垂直に分割
:vsp : 新しいウィンドウを垂直に分割

Ctrl+w + 矢印キー : 分割されたウィンドウ間を移動

Ctrl+w + c : 現在のウィンドウを閉じる

Ctrl+w + o : 現在のウィンドウ以外を閉じる
```
ウィンドウの削除は :q! でも可能です。

# 5. タブの作成機能
Vimでは、タブを使って複数のファイルを管理することができます。

**基本操作:**
```
:tabnew : 新しいタブを開く
:tabnext : 次のタブに移動
:tabprev : 前のタブに移動
:tabclose : 現在のタブを閉じる
```

タブの削除も :q! でも可能です。

# 6. Vimの中でTerminalを開く機能
Vim内でターミナルを開いてコマンドを実行することができます。

**Vim内でTerminalを開く:**
```
:term : 新しいターミナルを開く
Ctrl+w, :term : 画面を分割して新しいターミナルを開く
```

# 感想
マクロ、画面分割、ターミナルあたりは記事を書くにあたり初めて知りました。
かなり色々なことができるんですね。
まだまだいろんな機能があるみたい、とっても奥深い Vimmer の世界....

~~**VSCode でいいや**~~

おまけ↓

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

# 参考資料
https://vim.blue/tab-operation/
https://original-game.com/vim-mac6/
https://vim.blue/vim-macro-complex-repeat/
https://zenn.dev/sun_asterisk/articles/6b2bf762a7e510#terminal
[flutter]containerの枠線を点線にする

こんにちは！
すっかり冬ですね〜
今回は、containerの枠線を点線にする方法について
ご紹介します！

# 使い方

まず、パッケージを追加します。

```dart:dart
dependencies:
  dotted_border: ^2.0.0+1
```


次に、使用するページでインポートします。
```dart:dart
import 'package:dotted_border/dotted_border.dart';
```

使いたい場所で以下の記述をします。
```dart:dart
DottedBorder(
  child: Container(
    width: 300,
    height: 100,
  ),
),
```

# 使用例

![スクリーンショット 2023-12-06 19.11.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524120/7df139c5-bb39-be67-6cb9-49e96f5ce36e.png)


# 最後に
ここまで読んでくださり、ありがとうございました！
いいねくれるとスキップして喜びます:blush:
Google Chromeでサイト全体のスクリーンショットを取得する

この記事は [LINCRAFT Advent Calendar 2023](https://qiita.com/advent-calendar/2023/lincraft) の13日目の記事となります。

## 概要

- Google Chromeでサイト全体のスクリーンショットを取得しようとした。
- 以前はデベロッパーツールからコマンドを叩けば取得できたが、できなくなっていた。
- 代替方法を検索しても有用な記事が出てこなかったので調べてみた。

:::note warn
- EdgeとFirefoxであれば右クリックから容易にサイト全体のスクリーンショットを取得できる。
- Chromeでも拡張機能をインストールすれば容易に取得できる。
- 拡張機能をインストールしなくてもスマホ表示モードにすれば右上のメニューからサイト全体のスクリーンショットを取得できる。

なので**ChromeでPC表示モードのスクリーンショットを取得しなければならず、拡張機能のインストールも禁止されている**といった状態でなければそれらの方法で取得した方がよい。
:::

## 検証環境

- Windows 10 Pro 22H2
- Google Chrome (64bit) 119.0.6045.200

## ショートカットを設定しスクリーンショットを取得する

1. デベロッパーツールを開く
    - F12か ```Ctrl + Shift + i``` を押下。
    - またはブラウザ右上の設定ボタン(点3つが縦に並んでいる所) > その他ツール > デベロッパーツール
2. デベロッパーツールの設定ボタン(点3つが縦に並んでいる所)を押下。
3. コンテキストメニューからショートカットを押下。
![001.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636586/353c2533-77f6-7ea5-2cd7-7382e66042f7.jpeg)
4. ショートカット設定画面が出てくるので、「スクリーンショット」セクションを探す。下から探した方が早い。
5. 「フルサイズのスクリーンショットをキャプチャ」を探す。
![002.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636586/c9806926-25a9-69b3-c277-a88b670dcceb.jpeg)
6. ショートカットを設定する。
    1. 項目右のペンマークを押下すると編集状態となる。
    2. 「ショートカットを追加する」を押下。
    3. テキストボックスが出てくるので、ショートカットを設定。押したキーがそのまま設定される。
    4. 既存のショートカットと重複する場合はエラーが出るので別のショートカットを登録。
        - 私は ```Ctrl + Q``` を割り当てた。
        - 戻したければ右下の「デフォルトのショートカットに戻す」を押下。もしくは個別に削除。
    5. ✓(変更を確認)を押下。ショートカット画面を閉じる。
![003.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636586/00c488df-dad2-fdf9-8595-c654ec60b549.jpeg)

7. デベロッパーツールにフォーカスが当たった状態で登録したショートカットキーを押下すれば保存処理が実行される。

## 準備されているスクリーンショット系のショートカット

以下の種類があった。

- 領域のスクリーンショットをキャプチャ
    - 矩形選択してスクリーンショットを取れる。
    - でもスクリーンショット撮った後、マウスポインターの形状が戻らないのはバグなのだろうか。
- フルサイズのスクリーンショットをキャプチャ
    - 画面表示領域外の部分もスクリーンショットしてくれる。
- ノードのスクリーンショットをキャプチャ
    - 要素タブでノードを選択した状態で実行すると、その部分だけのキャプチャが撮れる。
    - 微妙に途切れたりしている。
- スクリーンショットをキャプチャ
    - 画面に表示されている内容をキャプチャ。

## その他

スクリーンショット以外にも色々とショートカットがあったので暇な時に確認してみたい。

## 一緒に働く仲間を募集中です！
リンクラフト株式会社では、組織拡大に伴い積極的な採用活動を行っています。
少しでも興味がある方はぜひご連絡ください。

▽会社ホームページ
https://lincraft.co.jp/
▽Instagram
https://www.instagram.com/lincraft.inc/
▽ご応募はこちらより
https://lincraft.co.jp/recruit

※カジュアル面談も受付中です。ご希望の方はHPのお問い合わせフォームよりご連絡ください。
動的計画法では保持するDP値は最低限にしよう

# 0. はじめに

AtcoderのEducational DP Contestをやっていて、愚直に書くより『C:Vaction』のメモリや速度を節約できたので、アイディアを忘れないために書いておくものです。

# 1. 前提

- 最近Atcoderをやり始めた初心者です。なので有識者の方には常識かと存じます。
- 使用言語はPython

# 2. 問題

https://qiita.com/drken/items/dc53c683d6de8aeacf5a

上記の記事を参考に、Educational DP Contestを順番にやっていました。
A、Bと順調に解いていて、Cも楽勝だろーと思っていたら、TLE（時間制限）に引っかかってRejectされました。

# 3. 解決策

大きく2つの修正によって改善しました。

## 3.1. 言語の変更

Python(Cython）をPython(PyPy）に変更しました。
基本的にはPyPyを使うほうが高速ですが、再帰処理を行うときだけは遅くなることに注意です。

より詳しくは↓の方の記事がためになりました。
https://qiita.com/y-oksaku/items/f0c5c4681bc30dddf7f4

## 3.2. 保持するDP値を最低限に減らす

実は、「3.1. 言語の変更」だけで、問題は解決していました。
ただ、保持するDP値を減らすとメモリと速度が改善したので、別の問題にも使えそうだなと思いました。

「C：Vacation」は、N日後の最大幸福度を探索する問題です。
愚直にやるならば、1日目から順番に幸福度の総和を求めていくでしょう。

※　入力例3の場合
![無題のプレゼンテーション_-_Google_スライド.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/305743/f17ad93b-7c3b-c403-5f4a-b4d040551b9d.png)

ただ、K日目（1 $\leq$ K $\leq$ N)の幸福度は K-1日目の幸福度と行動さえ分かればいいので、N日分のDP値を保持する必要はなく、以下のように前日分と当日分されあれば十分です。

![無題のプレゼンテーション_-_Google_スライド.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/305743/bc521db6-9de2-5616-13be-5933e992cba0.png)

### 改善前
![自分の提出_-_Educational_DP_Contest___DP_まとめコンテスト.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/305743/552b2f9e-0ce5-f74e-a35a-fe07a9814fb8.png)

### 改善後

実行時間、メモリともに改善できています。

![自分の提出_-_Educational_DP_Contest___DP_まとめコンテスト.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/305743/67cfa722-eaae-e48d-04c2-a696232dbf18.png)
Google Cloudの監査ログから未使用Service Accountを見つける方法

Google CloudでService Accountを作成したものの、色々な事情で使われなくなることもあります。
未使用のService Accountが残っているとセキュリティ的な問題に繋がりかねないので、定期的な棚卸しが必要です。
以下のクエリを使うと監査ログから直近30日間で利用実績のないService Accountを抽出できます。

なお、ここで参照しているテーブルたちの作成方法については以下の記事をご覧下さい。

https://techblog.zozo.com/entry/gcp-governance-after

```sql
with service_accounts as (
  select
    json_value(resource.data, '$.email') as email,
  from <Cloud Asset Inventoryのresource情報>
  where asset_type = 'iam.googleapis.com/ServiceAccount'
), audit_logs as (
  select
    date(timestamp, 'Asia/Tokyo') as date,
    protopayload_auditlog.authenticationInfo.principalEmail as email,
  from <Audit LogのActivityログ>
  union all
  select
    date(timestamp, 'Asia/Tokyo') as date,
    protopayload_auditlog.authenticationInfo.principalEmail as email,
  from <Audit LogのData Accessログ>
), usage_counts as (
  select
    email,
    count(*) as count
  from audit_logs
  where date > current_date('Asia/Tokyo') - interval 30 day
  group by email
)

select
  email,
  ifnull(count, 0) as count,
from service_accounts
left join usage_counts using(email)
order by count asc
```
ストレージのファイルをダウンロードと同時に削除する

## 概要
Storageからファイルをダウンロードさせると同時にファイルを消したい時には、`deleteFileAfterSend()`メソッドを使います。

## 使い方
```php
return response()->download($pathToFile)->deleteFileAfterSend();
```