OmniAICreator/Qiita-1.07M huggingface dataset:
Amazon Qとは :AIチャットボット



## Amazon Qとは
Amazon Qは、Amazon Web Services (AWS) が提供するビジネス向けのAIチャットボットです。


企業データと専門知識を活用して、特定のビジネスニーズに応じたサポートを提供することができます。セキュリティとプライバシーにも配慮されており、企業のポリシーやデータアクセス制限に適合するように設計されています。


https://aws.amazon.com/jp/q/?sc_icampaign=launch_reinvent23-amazon-q&sc_ichannel=ha&sc_icontent=awssm-4017_launch_reinvent23&sc_iplace=hero&trk=46b249b4-5ba5-4977-8b58-b606ed83594d~ha_awssm-4017_launch_reinvent23

https://zenn.dev/d2c_mtech_blog/articles/13cb85ed161f5b#%E3%81%93%E3%82%93%E3%81%AA%E4%BD%BF%E3%81%84%E6%96%B9%E3%81%97%E3%81%9F%E3%81%84%E3%81%AA%E3%82%92%E8%80%83%E3%81%88%E3%81%A6%E3%81%BF%E3%81%9F

## 主な特徴
Amazon Qは、生成型AIを活用したエンタープライズ向けアシスタントサービスです。

これにより、企業は情報リポジトリ、コード、データ、企業システムに接続し、会話を通じて問題を解決することが可能になります

## 利用可能性と応用
Amazon Qは、AWSのさまざまな地域で利用可能で、統合開発環境（IDE）を含めて、アプリケーション開発の各段階でサポートを提供します。

これには、AWSサービスの特定、アプリケーションコードの問題のトラブルシューティングなどが含まれます

## 発表時期
このサービスは、2023年11月28日に米国時間でAWSの年次イベント「AWS re:Invent 2023」で発表されました

Amazon Qは、企業が直面するデータおよびアプリケーション関連の課題を効率的に解決するための強力なツールです。



ビジネスニーズに合わせてカスタマイズ可能であり、AWSのエコシステム内での活用が期待されています。
Amazon Athenaとは？



## Amazon Athenaとは
Amazon Athenaは、AWS（Amazon Web Services）が提供するインタラクティブなクエリサービスです。このサービスを使用すると、Amazon S3に保存されているデータをSQLを用いて簡単に分析できます。サーバーレスなので、インフラストラクチャの管理が不要であり、クエリを実行した分だけ料金が発生します。

https://aws.amazon.com/jp/athena/

👉 ポイント:
- Athenaは、AWSのインタラクティブなクエリサービス。
- Amazon S3に保存されたデータをSQLで分析可能。
- サーバーレスで、クエリ実行分のみの料金体系。

## Athenaの特徴
Athenaの主な特徴はその使いやすさと柔軟性です。SQL知識を持つユーザーであれば、簡単に大量のデータを分析できます。また、多様なデータ形式（JSON、CSV、Parquetなど）に対応しており、ビッグデータ分析にも適しています。

👉 ポイント:
- SQLを使って直感的にデータ分析が可能。
- 多様なデータ形式に対応。
- ビッグデータ分析にも適用可能。

## Athenaの利用シナリオ
Athenaは、ログ分析、データウェアハウスのクエリ、ビジネスインテリジェンス（BI）ツールとの統合など、様々なシナリオで使用されます。データをS3に格納しておけば、必要なときにすぐにクエリを実行できるので、データ駆動型の意思決定を迅速に行うことができます。

👉 ポイント:
- ログ分析、データウェアハウスのクエリ、BIツールとの統合に利用。
- S3に格納されたデータに対して迅速なクエリ実行が可能。
- データ駆動型の意思決定に貢献。
EC2とECSの違いについて



## EC2とは
Amazon EC2（Elastic Compute Cloud）は、AWS（Amazon Web Services）が提供するクラウドコンピューティングサービスです。このサービスを使用すると、仮想サーバー（インスタンス）をクラウド上に簡単に構築できます。EC2を使用すると、ハードウェアの管理なしに、アプリケーションやサービスを実行するための計算リソースを得られます。

👉 ポイント:
- EC2は、AWSのクラウドコンピューティングサービス。
- 仮想サーバー（インスタンス）を提供。
- ハードウェアの管理なしで計算リソースを使用可能。

## ECSとは
Amazon ECS（Elastic Container Service）もAWSが提供するサービスの一つですが、こちらはコンテナ管理を目的としています。ECSを使用すると、Dockerコンテナを簡単にデプロイ、管理、スケールできます。つまり、複数のコンテナを効率的に運用するためのサービスです。

👉 ポイント:
- ECSは、AWSのコンテナ管理サービス。
- Dockerコンテナのデプロイ、管理、スケールを簡単に行える。
- 複数のコンテナを効率的に運用するためのサービス。

## EC2とECSの主な違い
EC2とECSの主な違いは、管理するリソースの種類にあります。EC2は仮想マシンを中心に管理し、ECSはコンテナを中心に管理します。EC2では、OSレベルからアプリケーションまで全てをユーザーが管理しますが、ECSではコンテナオーケストレーションをAWSが担い、ユーザーはアプリケーションのデプロイに集中できます。

👉 ポイント:
- EC2は仮想マシンの管理、ECSはコンテナの管理。
- EC2ではユーザーがOSからアプリケーションまで管理。
- ECSはコンテナオーケストレーションをAWSが担当。

## どちらを選ぶべきか？
選択はプロジェクトの要件によります。コンテナ化されたアプリケーションを扱う場合はECSが適しています。一方、より細かいコントロールが必要な場合や特定のOSを使いたい場合はEC2が適しています。

👉 ポイント:
- コンテナ化されたアプリケーションにはECS。
- 細かいコントロールや特定のOSが必要な場合はEC2。

この記事を通じて、EC2とECSの基本的な違いと、それぞれのサービスの適切な使用シナリオについて理解できたことと思います。それぞれのプロジェクトのニーズに合わせて、適切なサービスを選択してください。
CLIでECSの設定値を取得する方法



Amazon ECS (Elastic Container Service) は、コンテナ管理サービスです。

CLI (コマンドラインインターフェース) を使って、ECSの設定値を取得する方法について簡単に説明します。

## ECS CLIの基本

ECSを管理するためのCLIツールは、AWS CLIです。AWS CLIを使うと、ECSのクラスターやサービス、タスクなどの情報を操作・取得できます。

### インストール

AWS CLIをまだインストールしていない場合、AWSの公式サイトからダウンロードしてインストールします。

### 設定

AWS CLIを使うためには、AWSの認証情報（アクセスキーIDとシークレットアクセスキー）が必要です。これらはAWS Management Consoleから取得できます。

## ECSの設定値を取得する

ECSの設定値を取得するには、主に`describe`コマンドを使用します。

### クラスター情報の取得

クラスターの詳細を取得するには、以下のコマンドを使用します。

```
aws ecs describe-clusters --clusters [クラスター名]
```

### サービス情報の取得

特定のサービスの設定情報を取得するには、以下のコマンドを使います。

```
aws ecs describe-services --cluster [クラスター名] --services [サービス名]
```

### タスク情報の取得

実行中のタスクの詳細情報を見るには、以下のようにします。

```
aws ecs describe-tasks --cluster [クラスター名] --tasks [タスクID]
```

これらのコマンドを使うことで、ECSの様々な設定値や状態をCLIから確認できます。

👉 ポイント:
- AWS CLIを使用してECSの設定値を取得。
- `describe-clusters`, `describe-services`, `describe-tasks` コマンドで情報取得。
【JS/ES6】console.traceを知った


# はじめに
いままでほぼconsole.logしか使わなかったので、JSの中にブレイクポイントを仕込んで変数の中やDOMの状況を確認していたけど、console.traceが便利だった。

console.traceの公式mdnドキュメントはこちら
https://developer.mozilla.org/ja/docs/Web/API/console/trace_static

# console.traceって？

mdnによると、console.traceはスタックトレースができるconsole機能のひとつ。
>console.trace() メソッドは、ウェブコンソールにスタックトレースを出力します。
ということらしい。

スタックトレースは「実行中のコンピュータプログラムにエラーが発生した際に、直前に実行していた関数やメソッドなどの履歴を表示すること」で、コードの中にconsole.traceを仕込んでおくと、そこまでに実行した関数を履歴として表示してくれる。


# 使い方
wordという文字列の変数の中身を書き換える関数をそれぞれ用意してconsole.traceを試す。
```
const word = "hoge";
const func1 = (word) => {
    word = word;
    console.trace(word);
}
const func2 = () => {
    func1("fuga");
    console.trace(word);
} 
func2();
```
これをブラウザのコンソールで見ると。
console.traceを入れた2箇所でそれまで実行された関数が表示される！
![スクリーンショット 2023-12-27 12.18.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3587166/ed22a1f8-3615-fd11-2482-88af9eec4d65.png)


console.logをたくさん入れなくても履歴が辿れるので便利！
他にもconsoleにはたくさん便利なものがあるので機会があれば試したい。

https://qiita.com/asameshiCode/items/6fd893cf99647d13654c
C#でQRコード

## C#でQRコードを生成、表示させる方法

QRCoderを使う。

Nugetから、次の二つをインストールしておく。
+QRCoder
+System.Drawing.Common


```C#:MainWindows.xaml.cs
        private void btnCreate_Click(object sender, RoutedEventArgs e)
        {
            QRCodeGenerator qrGenerator = new QRCodeGenerator();
            QRCodeData qRCodeData = qrGenerator.CreateQrCode(textQrcode.Text, QRCodeGenerator.ECCLevel.Q);
            QRCode qrCode = new QRCode(qRCodeData);
            Bitmap qrCodeImage = qrCode.GetGraphic(20);

            using (var ms = new System.IO.MemoryStream())
            {
                // MemoryStreamに書き出す
                qrCodeImage.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);

                ms.Seek(0, System.IO.SeekOrigin.Begin);

                Img.Source =
                    System.Windows.Media.Imaging.BitmapFrame.Create(
                        ms,
                        System.Windows.Media.Imaging.BitmapCreateOptions.None,
                        System.Windows.Media.Imaging.BitmapCacheOption.OnLoad
                    );
            }
        }
```

```html:MainWindow.xaml
    <Grid>
        <TextBox
            x:Name="textQrcode"
            VerticalAlignment="Top" />
        <Button
            Name="btnCreate"
            Grid.Row="1"
            Click="btnCreate_Click"
            Content="生成"
            FontSize="12" />
        <Image
            x:Name="Img"
            Grid.Row="2"
            Margin="10"
            HorizontalAlignment="Stretch"
            VerticalAlignment="Stretch" />
    </Grid>
```

ZXingは何度か試してみたが、無理だった。
vimdiff で差分がない時に fold しない方法


`vimdiff` で同じ内容のファイルを開くと以下のように全体が fold されます。

![vimdiff-with-folding.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46177/ac34dd9e-3fd2-5813-a20b-42a65f9ce010.png)

次のように同じ内容でも fold したくないとします。

![vimdiff-without-folding.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46177/bb45a0a2-81a3-9bc9-7c7d-5ab39b8692ed.png)

これは次のエイリアスを定義しておくことで実現できます。

```bash:.bashrc
alias vimdiff="vimdiff '+windo set nofoldenable' '+windo set foldcolumn=0' '+wincmd t' +1"
```

やっていることは以下の通りです。

 * `windo set nofoldenable` で全ウィンドウを対象に fold を無効化する。
 * `windo set foldcolumn=0` で全ウィンドウを対象に fold の折りたたみ用の列の幅を 0 にする。
 * `wincmd t` で最も左上にあるウィンドウにカーソルを移動する（`Ctrl-w t` を実行する）。
 * `+1` でカーソルを 1 行目に移動する。
よわよわエンジニア、UI・UX修行を始める ~何でもカラフルにしちゃダメなんですか！？~

## はじめに
本記事では、UI・UXデザイン方面でつよつよになりたい筆者が、UI・UXデザインに取り組んでいくなかで身に染みて感じたことを書いています。

## 色を使うことには意味がある

わたしはお絵かきが好きですし、何でもかんでもカラフルにするのが好きです。
なので、例えば発表用スライドなども、かわいい色とかオシャレな色とかをめいっぱい使いたいわけです。
そして大体資料レビューで、以下の指摘を食らっています。

**「論理的に意味のない色分けをしてはいけない」**

スライドの中で色を使う場合は、大体はそのページの中でその情報が重要であり、目立たせたい場合です。
その時、いろんな色が特に意味もなく使われていると、見る人にとってはどの情報が重要なのかがわかりにくくなってしまいます。
また、色自体にも意味やイメージがあります。
例えば、悪い情報や課題、問題を表現する場合には赤色を使う、良い情報や解決策等を表現する場合には青色を使う、など。
個人の感覚ですが、地の文の黒以外は上記の赤・青のみ、もしくはプラス1色程度でまとめるとスッキリしてわかりやすい気がします。

スライドを例に出しましたが、アプリケーションで何らかの情報を出す場合にも同様のことが言えるのではないかなと思います。

## でも、色だけでは区別できない

でも、目立たせたい悪い情報を赤色にすればオッケー！ではありません。
世の中には、色の区別をつけにくかったり、色の見え方が少し違う人々が存在します。
そういった人たちにとっては、色だけで情報を区別したデザインだと、**情報が区別されていることがわかりにくい**のです。

他の表示要素も含めて、色の情報が無くても分かる、もしくは色の情報が欠けても欠ける情報が少ない、という場合であれば色だけで情報を区別させてもよいのかもしれません。
しかし、そうでない場合は、色以外に区別できる見た目の要素を追加すると、より万人にとってわかりやすい「良いデザイン」になるのではないかと思います。

## さいごに

カラフルの何が悪いねん！と思っていた時期がわたしにもありました。
でも、デザインって絵画やイラストじゃないんですよね。見た目が美しい必要はもちろんありますが、表示されている情報が整然としていて、ユーザーを混乱させないことの方も大切です。
見た目が美しくないツールを使おうという気にはなれないかもしれませんが、そもそもユーザーは、達成したい目的があるからツールを使うわけです。目的を達成しようにもツールに表示されている情報がごちゃごちゃ派手派手でわかりにくい……となってしまったら、意味がないのです。
自作アセットでPlayable!のコリジョンチェックやってみた

株式会社ベリサーブの清水と申します。
表題について、導入時から結果に至るまでの流れを記事にいたしました。
よければご一読下さい。

https://playable.qa/

「Playable!」は、AIQVE ONE株式会社が提供する、ゲーム QA に特化した自動テストツールスイートです。

今回は、このPlayable!を使用して、ゲームアセットの衝突判定(以下コリジョンという)が必要な場所に設定されているかをチェックしてみます。

初めに、Playable!公式サイトにも導入手順の例としてある、Unreal Engine(以下UEという)のTemplate Assetである「Third Person Template」を用いて導入をしてみました。

![スクリーンショット 2023-12-27 101357.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3639929/d2aca6c4-a69d-75b5-9cba-ea6c8e5fa76c.png)

御覧の通り、味気のないTemplateなので、自作してみたassetでコリジョンチェックしてみました。

![スクリーンショット 2023-12-27 100520.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3639929/63e09a7c-91aa-7591-9c14-5b07c591a568.png)

「Third Person Template」では、もとよりコリジョンが設定されており、有無を調べるには完成されているので、下のうにょうにょしたドアオブジェクトが抜けるように、コリジョンを無しにして導入します。

![Videotogif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3639929/36d092fe-0bfa-a6be-4558-ea9d7fc186e2.gif)

まず、コリジョンチェックをするためのマップデータをスキャンして取り込む作業から行います。
スキャンするゲームの仕様に応じて、ツールのコードを少し書き換えます。




スキャンを開始するとこんな感じになります。

![2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3639929/c7a30d02-6ad6-e6d1-4141-85cb7f1f7d81.gif)

その後、経路探索の事前計算結果をファイル生成します。
これまでのスキャン等は数十分かかりましたが、結果をファイル生成するというツールなので、こちらはすぐに終わりました。

マップを選択してsearch mapを押すだけ

![スクリーンショット 2023-12-26 141101.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3639929/220d6390-a383-9b08-6d23-86d1d4392ac0.png)

次に、結果をプロットするためのマップ画像を用意します。
今回はUEで上から見たものをそのままスクショして使いました。

2Dのビューワがあるので、テストで用いるだけなら十分確認できます。

![スクリーンショット 2023-12-26 145739.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3639929/04fa2266-e037-40ba-5757-22bf8f295e5a.png)

ここまでできれば、ついにキャラクターを自動で動かしてコリジョンチェックをします。

これまでで取得したマップのスキャンデータや動作させるプロジェクトexeを割り当てて
並列で動作するスレッドを立ち上げます。
同時進行で自動コリジョンチェックを開始です。


今回使用しているPCのスペックにより、3スレッドでテスト開始
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3639929/66e7cab2-bb92-6d12-6e5c-225faf65c3bc.png)

自動動作はこんな感じで動いています。

![4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3639929/1bd4c18f-4639-f7f3-e979-72ff4e664a82.gif)

壁にぶつかり、コリジョンが抜けていないかを調べています。

放置していると、以下の結果が得られました。


![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3639929/edc4724b-d030-5221-68c0-7c886a7bfb9d.png)
キャラクターが動いて接触した接触点の表示画面


![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3639929/150270ed-98fc-9622-fd14-149a35f60825.png)
目標点の表示画面

![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3639929/72ded7af-8cfa-58e4-7e4a-c4ae2316e98d.png)
到達できた場所を表示する画面

以上の結果からこのコリジョン抜けを確認することができました。
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3639929/ee3aae6e-f341-3424-6b59-4b0076fa5200.png)
一歩踏み出すと永遠に落ちていく地点
ゲームであればバグとなります。

今回用いたマップは小規模にして行いましたが、大規模なマップとなれば、デバッグ作業に多数の人員を弄することになります。
コスト削減と高効率化に一役買うことになるツールですね。

ご一読いただきありがとうございました。
【ChatGPT有＋DALL-E3】で描いた画像に驚いた。


　どうも、カーブミラーです。

　今回は、DALL-E3で描いた画像をチェックしていて、その画質に驚いたことを書きます。

:::note info
本記事は、
　ChatGPT有料版とDALL-E3での
　　検証となっております。

　あしからず。
:::
　X-Twitter上で、
　　片目アップの画像があったので
　　　DALL-E3に再現できるかな、と
　　　　やってみた結果、
　　　　　見事に描いてくれました。

　「女性の右目にクローズアップして描画してください。」という
　　プロンプトでです。
![DALL·E 2023-12-25 15.22.14 - A close-up of a woman's right eye, showcasing intricate details like eyelashes, iris, and the reflection on the eye surface. The focus is on the textu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/444ec169-9103-1fc7-2c7a-16391615383f.png)

　“すごいなぁ”と思いながら、
　　ふと“瞳に何か写っていたりして”
　　　と好奇心に負けて、
　　　　拡大しました。

　それがこちら。
![Screenshot_20231227-110225.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/fd4fc704-7d92-4a5a-e2e3-21dd8ad3e2e0.png)

　“うわっ”と驚きましたよ。

　だって、
　　何も指定していませんから。

　まぁ、
　　それだけと言えば、
　　　それだけなんですけどねぇ。

　もっとクローズアップして、と
　　注文してみましたけど、
　　　ChatGPTとDALL-E3の
　　　　性質上、うまく行きません。

　代わりに、
　　瞳に写る画像を
　　　指定できるか
　　　　試してみました。
![DALL·E 2023-12-27 11.21.20 - A close-up of an eye with the reflection of a dragon in its pupil. The dragon is intricately detailed, appearing fierce and majestic. It should be soa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/dd4ffe81-0edd-8f6f-80ad-f2c327718859.png)

　うん、
　　はっきりしちゃいましたねw

　もっと、
　　拡大しないと
　　　わからないように、と
　　　　イメージしていたのだけど。

　まぁ、
　　仕方ないですね。

　今回は、ここまで。
IBMiでもLIKE INしたい

# 固定文字列から`LIKE IN`したい

皆さんも一度くらいは都道府県(`JAPAN.PREF`)名に[五行](https://ja.wikipedia.org/wiki/%E4%BA%94%E8%A1%8C%E6%80%9D%E6%83%B3)(木・火・土・金・水)が含まれているものを抽出したいと思ったことがあるはず。

|NAME|
|---|
|北海道|
|青森県|
|岩手県|
|...|
|沖縄県|

下記のようなSQL文が直感的だが`LIKE IN`は動かない。

```
SELECT NAME
FROM JAPAN.PREF
WHERE NAME LIKE IN ('%木%','%火%','%土%','%金%','%水%')
```


# 正規表現を使う

IBMiで`REGEXP_LIKE`という記述がサポートされている。

https://www.ibm.com/docs/ja/i/7.5?topic=predicates-regexp-like-predicate

正規表現については別途オベンキョウする必要があるが、簡単なものであればそれほどハードルは高くない。

```
SELECT *
FROM JAPAN.PREF
WHERE REGEXP_LIKE(NAME,'木|火|土|金|水')
```

※ 今回は1文字なので`WHERE REGEXP_LIKE(NAME,'[木火土金水]')`でも良い。

# 結果から`LIKE IN`したい
とはいえ五行もいつかは変わるかもしれないし、データベース(`BANBUTSU.GOGYO`)で作っておいた方が安心。

|ELEM|
|---|
|火|
|水|
|木|
|金|
|土|

下記のようなSQL文が略

```
SELECT *
FROM JAPAN.PREF
WHERE NAME LIKE IN (
  SELECT ELEM
  FROM BANBUTSU.GOGYO
)
```

# 結果を集約する

IBMiで`LISTAGG`という関数がサポートされている。

https://www.ibm.com/docs/ja/i/7.5?topic=functions-listagg

これと`REGEXP_LIKE`を組み合わせる。
上手いこと正規表現に整形する必要があるが、`separator-expression`等を駆使して頑張りましょう。

```
SELECT *
FROM JAPAN.PREF
WHERE REGEXP_LIKE(NAME,
  SELECT LISTAGG(ELEM,'|') FROM BANBUTSU.GOGYO
)
```

もちろん`SELECT '['||LISTAGG(ELEM)||']' FROM BANBUTSU.GOGYO`も可。
これで将来的に五行が四行や六行になっても安心！

# ちなみに
五行が含まれている都道府県は`栃木県`しかない。~~マジでどうでもいい。~~
【初心者】codepen様を初めて使う　~素晴らしいシステムをいつもありがとうございます~

1年以上前から憧れ、4か月前からずっとちらちら気になっていたcodepen様。
野暮用で使用するため、年内解決できると思い、記録する。

# 【やったこと】
・https://codepen.io/ にアクセス・SignUp
・とりあえず何か作成
・「Embed」を押すとお馴染みの状態が出てくる。コードをコピーする。
以上。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2867756/26418bc2-eebc-31b0-5259-b4fa574a518b.png">



# 【結果】

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="BabyGRZ" data-user="dmnngn" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/dmnngn/pen/BabyGRZ">
  sample</a> by dmnngn (<a href="https://codepen.io/dmnngn">@dmnngn</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

# 【コードはこんな感じ】

    <p
        class="codepen" data-height="300"
        data-default-tab="html,result"
        data-slug-hash="BabyGRZ"
        data-user="dmnngn" style="height: 300px;
        box-sizing: border-box; display: flex;
        align-items: center;
        justify-content: center;
        border: 2px solid;
        margin: 1em 0; padding: 1em;"
    >
      <span>See the Pen 
          <a href="https://codepen.io/dmnngn/pen/BabyGRZ">
              sample
          </a> by dmnngn 
          (<a href="https://codepen.io/dmnngn">@dmnngn</a>)
          on <a href="https://codepen.io">CodePen</a>.
     </span>
    </p>

# 【まとめ】
「難しそう」と思っていただけで、鬼簡単だった。
踏み出す一歩が大事。４ヶ月前の自分に伝えたい。
【API】叩き方

## はじめに
バックエンドとフロントエンドを分けるのに慣れておりません。
間違っているところがございましたら教えていただけますと嬉しいです。

## バックエンドから情報を取得する
使ったもの
・supabase
・prisma
・Next.js　→ v13
・Node.js

**流れとしては**
supabaseにあるブログの情報を取得することが目的だとする。

prismaのインスタンスを作成する。
```js
import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();
```
prismaのざっくりとした理解はAWSのRDSのようなイメージ。
たくさん本がある図書館で本を整理してくれるような感じ。

prismaと接続
```js
export async function main() {
  try {
    await prisma.$connect();
  } catch (err) {
    return Error("DB接続に失敗しました。");
  }
}
```

ブログの情報を取得する。
```js
//ブログの全記事取得API
export const GET = async (req: Request, res: NextResponse) => {
  try {
    await main();
    const posts = await prisma.post.findMany();
    return NextResponse.json({ message: "Success", posts }, { status: 200 });
  } catch (err) {
    return NextResponse.json({ message: "Error", err }, { status: 500 });
  } finally {
    await prisma.$disconnect; //最後に必ずprismaとの接続を切る
  }
};
```

フロントエンドでは以下のように呼び出す
```js
async function fetchAllBlogs() {
  const res = await fetch(`http:localhost:3000/api/blog`, {
    cache: "no-store", //SSR
  });

  const data = await res.json();

  return data.posts;
}
```
[fetch](https://developer.mozilla.org/ja/docs/Web/API/fetch)はデフォルトではGETメソッドになっている。

## おわりに
流れを一通り確認することができ良い学習になりました。引き続き学習の備忘録を投稿させていただきます。

## 以下はその他のメソッド
**POSTメソッド**

バックエンド側
```js
//ブログ投稿用API
export const POST = async (req: Request, res: NextResponse) => {
  try {
    const { title, description } = await req.json();

    await main();
    const post = await prisma.post.create({ data: { title, description } });
    return NextResponse.json({ message: "Success", post }, { status: 201 });
  } catch (err) {
    return NextResponse.json({ message: "Error", err }, { status: 500 });
  } finally {
    await prisma.$disconnect;
  }
};

```
フロント側
```js
const postBlog = async (
  title: string | undefined,
  description: string | undefined
) => {
  const res = await fetch(`http://localhost:3000/api/blog`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ title, description }),
  });
  return res.json();
};
```
```js
const PostBlog = () => {
  const titleRef = useRef<HTMLInputElement | null>(null);
  const descriptionRef = useRef<HTMLTextAreaElement | null>(null);

  const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();

    await postBlog(titleRef.current?.value, descriptionRef.current?.value);
  };
  return (````````````);
};
```
gulpfileをES Modulesに変換

:::note info
4/3 追記
GulpがVersion 5にアップデートされました。
[Announcing Gulp v5](https://medium.com/gulpjs/announcing-gulp-v5-c67d077dbdb7)
:::

## はじめに
今まで画像圧縮はオンラインツールを使っていたのですが、今さら自動化しようと思い
npm packageの[imagemin](https://www.npmjs.com/package/imagemin)を使おうとしたのがきっかけです。
imageminはVersion 8 からES ModulesになったようなのでgulpfileもCommonJSからES Modulesへ書き換えることにしました。
### 環境
<dl>
  <dt>Node</dt>
  <dd>Ver. 20.9.0</dd>
  <dt>npm</dt>
  <dd>Ver. 10.1.0</dd>
  <dt>Gulp</dt>
  <dd>CLI Ver. 2.3.0　Local Ver. 4.0.2</dd>
  <dd>Gulpはnpxで実行しています</dd>
</dl>

## 手順

1. gulpfile.jsの拡張子をgulpfile **.mjs** にリネーム。拡張子を変更したくない場合はpackage.jsonに `"type": "module"` を追記
```json:package.json
  "main": "gulpfile.mjs",
  "type": "module",
```
2\. gulpfile.mjsの中で、require文で読み込んでいたモジュールをimport文に置き換えます
```javascript:gulpfile.mjs
// CommonJS
const { src, dest, series, parallel, watch } = require('gulp');

// ES Modules
import pkg from 'gulp';
const { src, dest, series, parallel, watch } = pkg;
```

3\. gulpfile.mjsの最後に`export default`を使ってデフォルトのタスクをエクスポートします
状況に合わせて`series()`、`parallel()`をお使い下さい
```javascript:gulpfile.mjs
// CommonJS
exports.default = parallel(タスク);

// ES Modules
export default parallel(タスク);
```

## 最後に
import文に書き換えるだけと思い、
```javascript:gulpfile.mjs
import { src, dest, series, parallel, watch } from 'gulp';
```
と書き換えて実行したらSyntax Errorが出てしまいました。
```console
SyntaxError: Named export 'dest' not found. The requested module 'gulp' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:
```
でも、親切に代替案として手順2のコードを提示してくれました。

調べるとnpm packageの[ESM](https://www.npmjs.com/package/esm)をインストールする等、他にも方法があるようですが自分はまだ試していません。
GCPでPrivateなGoogle Chatを納品する時の注意点

この記事は、ちゅらデータAdvent Calendarの24日目です。

# 結論

Google Chatの構成は、必ずお客様に最初に保存してもらおう！

# はじめに

プロジェクトで、お客様に対してGCP上で構築したバックエンドで応答するGoogle ChatのBotを作ったことがありました。

Google Chatは、GCPコンソール上でAPIを有効にし、その上でGoogle Chatの構成情報を作成することで、Gmail経由で利用することができます。

その際に、GCPの特殊性で詰まったことがあったので共有をば。

# Google Chatの構成について

※ここでいう構成は、汎用的な用語としての構成ではなく、Google　Chatでは所謂設定のことを構成と表記しているので、それに準拠しています。

Google Chatでは、構成情報として

- 名前
- icon
- 説明
- バックエンド設定
- 公開情報

あたりを設定することで利用できるようになるのですが、この公開情報を設定することで、Google Workspace内の特定のユーザーに共有することができるようになっています。

しかしながら、この公開情報には落とし穴が2つありました。

## 1. Google Cloud Consoleにログインしているユーザーのドメインしか保存できない

例えば、ちゅらデータ社のユーザーである私が構成情報を見ると、その構成情報には「権限のある ちゅらデータ のメンバーが...」というような表記になります。

ただし、今回のようにお客様用に構築する場合には注意が必要で、ログインしているユーザーと異なるWorkspaceのドメインを登録することはできないようになっています。

そのため、自社とお客様とでドメインが異なる場合は、同時に両方のメールアドレスを登録することはできないようになっています。

## 2. 最初に構成を保存したドメインのグループしか利用ができない

こちらの方が厄介で、Google Chatの構成情報は、プロジェクトに対して1つまでしか設定をすることはできないようになっているため、システム全体を構築した後にこのことに気づいてももう遅いということが十分にあり得ますので、細心の注意を払ってもらいたいところであります。

お客様に用意してもらったGCPプロジェクトにおいて、Google Chatの最初の構成保存を自社でやってしまうと、その構成は自社ドメインで保存した扱いとなり、自社のGoogle Workspaceのグループしか登録ができないようになります。

厳密には、登録自体はできるのですが、GmailでBotを検索することはできても、Chatを開始することができないというような問題に当たってしまいます。

しかも、一度保存した構成情報は、APIを無効化しても保持されるため、一度構成情報を作成してしまうと、リセットすることはできません。

こうなると、対策として

1. Googleのサポートを契約して、構成情報を一度削除してもらう
2. Google Chatの構成情報のみのプロジェクトを作成してもらう
3. グループではなく、全てのユーザーのメールアドレスを列挙する

ということしか手段がとれなくなってしまいます。

場合によってはそこそこ取り返しのつかない事態になりかねないので、最初の構成情報は必ずお客様ドメインで保存してもらうようにしましょう。

# 終わりに

思わぬ落とし穴がある部分で、焦りました。
皆さんも同じ轍を踏まぬよう、お気をつけください。
卒業研究並びにチームのみんなへの感謝

## 卒業研究で制作していたアプリが完成しました。
前回の記事について多くの閲覧ありがとうございます。多くの方々に見ていただいたり私の記事を引用してくださったりとあまり良い内容ではないものの様々な感想などを貰ったのは非常に嬉しいです！
　ただ勉強していかなければいけないというのは変わらずなので会社に勤める前にもっと勉強していきたい今日この頃です。
　さて、本題ですが私がチームとして参加していた卒業研究のアプリですがとりあえず完成しましたのでご報告とさせていただきます。ぶっちゃけ私が担当したところは９５割ChatGPTなので何かバグがあるかもしれません。完全にブラックボックスです開けるの怖すぎます。
 　すでにリーダーが記事を投稿してくださっているのでそちらを引用したいのですが引用すると私の前回の恥ずかしい投稿がばれてしまうのでこっそりリンクだけ置いておきます。作成したのは推し活支援アプリです。カレンダーとコミュニティ機能が一つにまとまったアプリになっています。
  リーダーが投稿した記事のコメントにアカウントが作れないというバグがあったみたいですが修正済みです。
リンク:https://oshimore-90d6b34a7fa6.herokuapp.com/
## チームへの感謝
チームのみんなには感謝してもしきれません。ガチでキャリー、おんぶにだっこです。そんな私を見捨てずに質問したら一緒に考えてくれたみんなには感謝しています。マジでありがたいです全員神様に見えました。

## 最後に
今回作成したアプリは推し活支援アプリということですがとても不便です。開発している最中もこれ絶対不便やろなと思いつつもチームがそれでいいというのでその方向で開発していました。自分が一番できないのが分かっているのでそういう意見も言いにくいですし自分の思っていることをうまく簡潔に伝えられないのも自分に対して腹が立ちました。
ちょっとした愚痴は置いといてぜひこのアプリでバグを起こしてください！そしてリーダーの記事でも自分の記事でもいいのでどういったバグとか変な挙動になったのかをコメントください！冬休み明けにチームで直します。また、セキュリティ面はおそらくガバガバなのであまり個人情報などは登録しないようにしてください。よろしくお願いします。
　また、長々とした文章になってしまいましたが以上です。ここまで読んでいただきありがとうございました！
Domain Adaptationメモ

下記をまとめたものです。
https://arxiv.org/pdf/2010.03978.pdf

個人的なメモなので誤りなどあればご指摘お願いします

## Types of Domain Shift
### Target(Prior) Shift
- 出力変数の周辺分布が異なる（=結果が異なる場所を選ぶなど）
- ラベルが異なる

### Covariate Shift
- 入力変数の周辺分布が異なる（=別の場所など）
- 入力変数の特性が異なる（結果としてTarget Shiftを起こすこともある）

### Concept Shift
- 条件付き確率の分布が変わってしまう(=別の条件でデータを取得したら出力変数の周辺分布も変わってしまう)
- 学習したい変数の概念自体が変わってしまう

## Approaches
### Instance-Based
- 教師ありデータに基づく、目標値の損失を最小化することでモデルを調整する方法
- インスタンス選択とインスタンス重み付けによるソースドメインにおけるラベル付データの重要性

### Feature-Based
- 特徴量に着目したアプローチ
- Subspace-based, transformation-based, construction-based

#### Subspace-based
- ドメイン間の共通した中間表現を探索することを目的としている
- 次元を削減する（PCAなど）

#### Transformation-based
- 元のデータの基本的な構造と特徴を保持しながら、限界分布と条件分布の間の不一致を最小化するために、元の特徴を新しい特徴表現に変換する

#### Reconstruction-based
- 中間的な特徴表現でのサンプル再作成によって、ドメイン間の不一致を軽減する

### Deep Domain Adaptation
- DAの技術をDNNに導入することで少ないラベル付きデータに対応することを目的とする
- discrepancy-based, reconstruction-based, and adversarial-based adaptation

#### Discrepancy-based
- ドメイン間の差異を考慮してモデル感の差異を調整
- ドメイン固有の表現に対応するための適応層を導入する

#### Reconstruction-based
- autoencoderを使い再構成誤差を最小化し、ドメイン間で不変かつ転送可能な表現を学習することによってドメイン間の差異を調整する

#### Adversarial-based
- ドメイン間の分布の不一致を最小化し、転送可能でドメイン不変な特徴を得る
- 敵対的目的によってドメイン間の不一致を最小化する生成的敵対的ネットに触発
MariaDBのmy.iniの場所

# 前提

Windows10にインストールしたMariaDBに対する情報となります。

# C:\Program Files\MariaDB 10.5\data

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/638a6c18-119f-c7db-5945-27b46cc98919.png)

# バージョン

Microsoft Windows [Version 10.0.19045.3803]
MariaDB 10.5.4
【JS/ES6】@ts-checkを使ってJSファイルで型チェックする



# はじめに
JS勉強中に教えてもらった@ts-checkが便利だったので忘れないようにメモ。

# @ts-checkを使ってJSファイルで型チェックする
JSでは関数や変数などの型を正しく記述する必要がある。
vocodeにはJSファイルをtypescriptのように型チェックできる機能がある！

それが@ts-check！

例えば下記のような誤ったコードがあったとする。
![スクリーンショット 2023-12-27 10.24.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3587166/44a4b7a9-dbd8-338c-0d36-757623a8ef23.png)

通常のJSファイルだと特にエラー的なものは出ないが、
ファイルの最初に「@ts-check」を追加すると、pushに赤い下線が表示される。
![スクリーンショット 2023-12-27 10.24.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3587166/cf49630e-4a35-e620-2464-f31a4d40ae70.png)
カーソルを当てると
![スクリーンショット 2023-12-27 10.25.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3587166/0f2406b4-f7f9-dc61-e51b-1ce6a3c26458.png)
エラー内容も表示してくれる！


毎回@ts-checkをつけるのはめんどうだけど、迷った時やコードを自分デバッグしたい時に使うようにしよう。
ESMとCJSのimportとexport

# CJSとESMのexportとimport

## CJSの場合のExport
### 一つのモジュールのエクスポート
```sample-1.js
const someFunc () => {
    //do something
}

module.exports = somoFunc
```
### 複数のモジュールのエクスポート
```sample-1-2.js
const someFunc () => {
    //do something
}
const hoge ="hoge"

// その1 まとめてexport
module.exports = {
    culc: someFunc
    hoge: hoge
}
// その2 一つひとつエクスポート
exports.someFunc = () => {
    //do something
}
exports.hoge = "hoge"

```

## ESMの場合のExport
### 一つのモジュールをエクスポートする場合
```sample-2.js
//デフォルトのエクスポート　その１
expost default function somoFunc (){
    //do somothing
}
```

```sample-3.js
//デフォルトのエクスポート　その2
function somoFunc (){
    //do somothing
}

expost default somoFunc
```
ひとつのモジュールのインポート
```import.js
import somoFunc from 'sample-2.js'
```

### 複数のモジュールをエクスポートする場合
```sample-4.js
export function add(x, y) {
  return x + y;
}
export function multiply(x, y) {
  return x * y;
}
```
複数のモジュールのインポート
``` sample-5.js
import { add, multiply } from 'sample-4.js'
```

# [参考記事]

https://ama-tech.hatenablog.com/import-export-in-es-modules

https://qiita.com/senou/items/a2f7a0f717d8aadabbf7
富岳のPyTorch-1.7.0でtransformersを動かすには

スーパーコンピュータ「富岳」の[ファーストタッチオプション](https://www.r-ccs.riken.jp/outreach/topics/20220127-2/)が当たったので、まずは富岳で[transformers](https://huggingface.co/docs/transformers)を動かしてみることにした。現時点の富岳には[PyTorch-1.7.0](https://github.com/fujitsu/pytorch/wiki/PyTorch-DNNL_aarch64-build-manual-for-FUJITSU-Software-Compiler-Package-(PyTorch-v1.7.0)-JP)が[インストールされている](https://www.fugaku.r-ccs.riken.jp/doc_root/ja/user_guides/FugakuAIGuide/pytorch.html)ので、その上にtransformersを乗せてみよう。

```
#! /bin/bash
#PJM -L rscgrp=small
#PJM -L elapse=1:00:00
#PJM -L node=1
#PJM -j
#PJM -S

G=`id | sed 's/^.*gid=[0-9]*(\([^)]*\)).*$/\1/'`
set `ls -d /vol*/$G /vol*/data/$G` $HOME
export PYTHONUSERBASE=$1/pytorch1.7.0
export PATH=/home/apps/oss/PyTorch-1.7.0/bin:$PYTHONUSERBASE/bin:$PATH
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/home/apps/oss/PyTorch-1.7.0/lib64
export HF_HOME=$PYTHONUSERBASE
export TMPDIR=$PYTHONUSERBASE/tmp
mkdir -p $TMPDIR
pip3.8 install transformers==4.28.1 tokenizers==0.13.3 protobuf==3.20.3 --user
pip3.8 install -U tqdm packaging typing_extensions --user

P=$TMPDIR/fillmask.$PJM_JOBID.$$.py
cat << 'EOF' > $P
from transformers import pipeline
fmp=pipeline("fill-mask","KoichiYasuoka/deberta-large-japanese-aozora")
print(fmp("夜の底が[MASK]なった。"))
EOF
python3.8 $P
```

富岳のログインノードから`pjsub`してみたところ、ジョブ待ち・インストール・ダウンロード等も含め、20分ほどで以下の結果が得られた。

> [{'score': 0.10754217207431793, 'token': 2113, 'token_str': '白く', 'sequence': '夜の底が白くなった。'}, {'score': 0.041452500969171524, 'token': 298, 'token_str': '重', 'sequence': '夜の底が重なった。'}, {'score': 0.038921937346458435, 'token': 3504, 'token_str': '黒く', 'sequence': '夜の底が黒くなった。'}, {'score': 0.03801723197102547, 'token': 114, 'token_str': 'どう', 'sequence': '夜の底がどうなった。'}, {'score': 0.03193212300539017, 'token': 3520, 'token_str': 'わるく', 'sequence': '夜の底がわるくなった。'}]

私(安岡孝一)の[2022年5月28日の日記](https://srad.jp/~yasuoka/journal/654661/)とは異なる結果なのだが、「白く」「重」「黒く」「どう」「わるく」を埋めてきているので、まあ良しとしよう。ただ、PyTorch-1.7.0だと、LLaMAモデルはサポートされていない。[PyTorch-1.13.1](https://github.com/fujitsu/pytorch/wiki/PyTorch-DNNL_aarch64-build-manual-for-FUJITSU-Software-Compiler-Package-(PyTorch-v1.13.1)-JP)を自力でコンパイルするとなると、4時間くらいかかっちゃう気がするんだけど、さて、どうしようかな。
Cognos Analytics 12.0.1新機能 - Portalの新機能まとめ

# 概要
Cognos Analytics 12.0.1のポータルの新機能をまとめて紹介します。

# 参考
**Multiple components**
https://www.ibm.com/docs/en/cognos-analytics/12.0.0?topic=modules-multilingual-metadata

# お気に入り
12.0.1のポータル画面ですが「お気に入り」というタブがあり、各コンテンツに♡マークがあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/424f3864-f619-5c8b-865d-47e43010fbe1.png)

ハートマークを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/b3f95818-058f-5b94-f312-a46d88f8c298.png)

あるいは各コンテンツのメニューから「お気に入りに追加」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/0d0dd7d9-46b6-9f42-4ad2-649036e9eb9b.png)

「お気に入り」タブに先ほど選択したコンテンツが表示されていて、ダイレクトに呼び出し可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/8a55ddb0-47d6-b8ff-eb1c-22a5649ff0a0.png)

# 検索結果
検索を行いたいフォルダに移動してから虫眼鏡アイコンで検索を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/9dbc3d27-be54-5dc2-d0c5-604a1bcbf455.png)

「販売」と検索してみます。検索候補も下に自動的に表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/12f60311-aa87-af51-4ec6-f081b25e6180.png)

検索結果が表示されました。「GO 販売実績」とか「GO 販売マップ」はわかりやすいですが、「天候分析」ってなんで検索に引っかかったのだろうと思います。
そんな時、この新機能が役に立ちます。「天候分析」をチェックし「結果の理由」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/65385f32-b19c-6ac9-f636-44a10ca4fc2b.png)

このレポートのどこに検索文字が入っているかを太字で表示してれます。日本語もいけましたね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/8404dbd2-3fd8-10bb-dd41-3b2702ddb9fb.png)

# ファイル・アップロード
赤枠のここからもファイルアップロードが可能になったという新機能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/710c92cc-06ff-33d2-b27a-c5fa32aed0be.png)

選択するとこのような画面になります。「詳細」を選択してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/92bc6c96-4e81-36e1-bb2e-46e5e9b0accd.png)

こんな感じの画面になって、データアップロードの注意事項や手順などの説明が見れます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/1d93a511-3c7c-ea52-4587-92d27f04fc5b.png)

戻って次へを選択すると、アップロード可能な画面になっていきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/1c7b133b-f292-5e26-bd4d-9e046eb78080.png)

# 学習記事の推奨
赤枠の？で表示される推奨記事は、自分および他のユーザーに人気の記事を学習して表示してくれるようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/f60aefd2-0d2d-a54f-c359-d388bb049577.png)

# 学習記事検索のオートコンプリート
学習記事を検索しようとキーワードを入力すると、入力完了前にオートコンプリート機能で検索候補が表示される新機能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147246/252207c7-65b0-c46a-6113-7f51162f8ed9.png)
[備忘録]FactoryとRepositoryのそれぞれの設計パターンについて責務とシングルトンパターンについてもちょっと

## はじめに
今回は設計で良く耳にするFactoryとRepositoryのそれぞれの責務について調べたこと、業務の中で学んだことを一度整理して備忘録として残しておきます。

## Factory
Factoryは、オブジェクトの生成に関する責務を担います。従って、Factoryクラスを介してオブジェクトを生成します。  
こうすることで、オブジェクトの生成ロジックを隠蔽することができます。  
また、Factoryに関しては、シングルトンパターンが適応されることもあります。  
ここで少し脱線してシングルトンパターンを説明します。

### Singleton
シングルトンパターンは全体で一つのインスタンスを提供するためのパターンです。  
以下のように、同一のインスタンを返します。
```C#
    /// <summary>
    /// インスタンス
    /// </summary>
    private static DataBase s_Instance = new DataBase();

　　/// <summary>
    /// インスタンスを返す
    /// </summary>
    /// <returns></returns>
    public static DataBase GetInstance()
    {
        return s_Instance;
    }
```

と少し脱線しましたが、Factoryではオブジェクトの生成にまつわる処理を隠蔽しますので、新しいクラスの追加や既存のクラスの変更が容易になりますね。

## Repository
データアクセスロジックとビジネスロジックを分離することを目的とします。リポジトリはデータの永続化（CRUD操作など）に関する責務を担当し、ビジネスロジックはこのリポジトリを介してデータにアクセスします。  
データアクセスコードがリポジトリにカプセル化されるため、データベースの変更があってもビジネスロジックに影響を与えにくくなります。  
テストもしやすくなりますね。  


## おわり
少し短めではありますが、備忘録として設計の概念的なところを書いて整理してみました。  
引き続き設計の知見を増やしていきたいと思います。
【JS/ES6】早期リターンって？


# はじめに
JS勉強中に早期リターンについて考えることがあった。
そもそも早期リターンとは的なところから使い方までをメモ。

# 早期リターンって？
早期リターンは、関数（メソッド）などの処理の中で、**条件を満たした時にすぐにreturnやcontinue/breakでその処理から抜ける方法**。

早期リターンは**early return**ともいう。

if文のネストを減らせたり、無駄な処理を回避できたりするメリットがある。

## 早期リターンをいつ使うのか

### 条件を満たした場合
例えば、下記のようなif文があったとする。
```
if(A != B){
    if(A == C){
        return true;
    }else {
        return false;
    }
    return true;
}else {
    return false;
}
```
これを早期リターンすると。
```
if(A == null) return;
if(A != C) return;
return true;
```
として早期リターンすることで、コードを減らすことができる。

### エラーハンドリングで使う
DOMを取得する時、対象のDOMが存在しない場合に発生するエラーの時点でreturnさせることで、以降の処理へ進ませないようにするなどエラーハンドリングとして使用する。
```
const element = document.getElementsByClassName('target')
if(element.length === 0) return;
```
この場合、targetというクラスのDOMが存在しない場合（lengthが0）の場合は早期リターンしている。

# 早期リターンの使いすぎはよくないらしい
- 早期リターンは適切に使わないとコードが読みにくくなる可能性もあるらしい
- 早期リターンの条件が複雑すぎると、バグを生む可能性もあるらしい

早期リターンは適切な場所で適切に使うようにする。
Spring Boot on Embedded Tomcatでリダイレクト時のLocationヘッダーの値を相対パスに変更する

# バージョン
- Spring Boot 3.2
- Embedded Tomcat 10.1

> - 3.2以前のバージョンでもできる可能性があります。
> - JettyやUndertowでのやり方は検証していません。

# やりたいこと
デフォルトの状態では、リダイレクト時のLocationヘッダーは絶対パスになります（例: `https://a.example.com/dest`）。これは[Jakarta Servletの仕様](https://jakarta.ee/specifications/servlet/6.0/jakarta-servlet-spec-6.0#convenience-methods)らしいです。
しかし、クライアントとSpring Bootサーバーの間に複数ロードバランサーがあった場合、この挙動だとクライアントがうまくリダイレクトできない可能性があります。
なので、Locationヘッダーを相対パスにしたいです。

# 結論
```application.properties
server.tomcat.use-relative-redirects=true
```

## 👆を設定した場合
![スクリーンショット 2023-12-27 9.54.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58650/81d9bde5-41ba-facd-73bf-d08d29c37aa2.png)

## 👆を設定しなかった場合
![スクリーンショット 2023-12-27 9.55.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58650/0ea510c9-697e-b312-9295-7a6d0f2a681f.png)
less で最後に空ページを表示しない方法

以前、こういう記事を書いた。

https://qiita.com/kaz-utashiro/items/7c11337468c63fdfdccb

`ansicolumn` を使うと、画面のちょうど倍数だけの行を出力する。これを `less` で読むとどうなるかというと、最後にスペースでページを送ると必ず何もない空白のページが表示される。以前からこれが地味にストレスだったので、どうにかできないかという話。

まず、`G` で最終ページに飛ぶという方法がある。こうすると、そこでスペースを入力しても空ページは表示されない。最後のページが見たいのならそのままでいいし、そうでなければ `g` で先頭に戻る。

であれば、これを自動的に実行すればいい。なんとかならないかと考えてみたら、実は簡単だった。`less` に `+Gg` というオプションをつけて実行するだけだ。

```sh
optex -Mtc ansicolumn -DPC2 sample.docx | less +Gg
```

`+` の後に文字を指定すると、それを入力したかのように実行してくれる。だから上に書いたように、`G` で最後に飛んだ後に `g` で先頭に戻る動作を自動的にやってくれる。それは画面上には表示されないので、見ていてもまったく気がつかない。

いつもこれを実行したいのなら `LESS` という環境変数を設定すればいい。

```sh
export LESS="-cR+Gg"
```
のようにすれば、常にこのオプション付きで実行される。しかし、終わりのないデータだったりすると永遠にまたされることになるので、必要な時だけにした方がいい。

調べると `+Gg` の効能は他にもあった。`less` の `-M` オプションは、行番号とファイル中の位置を表示してくれるのだが、一度最後のページまで行かないと全体の行数がわからない。こんな時には `+Gg` を付けろというのが常套手段のようだ。

```sh
less -M +Gg
```

ちなみに `+` オプションはたまに使うことがあって、

```sh
less +100
```

のようにすれば100行目を表示してくれるし、

```sh
less +/pattern
```

のように使えば、`pattern` を検索してその行を表示してくれる。

`vi` でも同様に使えるので、知らなかった人はお試しあれ。
Cerberusでヌルチェックをする方法

# やりたいこと
データの「ヌルチェック」という表現について、場合によってちょっと曖昧になってしまうかなと思います。
通常は「null（None）ではないこと」を指しているかと思いますが、いままでの職場では「ブランク（''）ではないこと」や「項目自体が存在すること」などを言っている人もいるので、、、

今回は「null（None）ではないこと」、「ブランク（''）ではないこと」、「項目自体が存在すること」、それぞれCerberusでのチェック方法を調べてみました。

# 前提
・Pythonインストール済み
・pipenvインストール済み
（今回は便宜上pipenvでやるのですが、ローカルでcerberusなど諸々ライブラリを入れてテストをやっても大丈夫です）

# ソースの中身
さっそく調べた結果をソース化しました～

```ruby:cerberus_validator.py
from cerberus import Validator


SCHEMA = {
    'name': {
        'type': 'string',
        'required': True, # nameという項目自体が存在すること 
        'empty': False, # name項目の中身がブランクではないこと
        'nullable': False # name項目の中身がNone（ヌル）ではないこと
    },
}

def validate_info(info):
    validator = Validator(allow_unknown=True)
    if not validator.validate(info, SCHEMA):
        print(validator.errors)
        return False
    return True

# 正常時
info = {'name': 'satoh'}
print(validate_info(info))

# nameという項目自体が存在していない
info = {}
print(validate_info(info))

# name項目の中身がブランクである
info = {'name': ''}
print(validate_info(info))

# name項目の中身がNone（ヌル）である
info = {'name': None}
print(validate_info(info))
```
ソースを実行すると、以下のような結果がprintされました！
Cerberusはちゃんとエラー箇所や原因を記録できて便利だねと感じました！
```ruby:
True
{'name': ['required field']}
False
{'name': ['empty values not allowed']}
False
{'name': ['null value not allowed']}
False
```
闘魂Elixir ── Advent of code 2023 Day 9 Part 2 を Livebook で楽しむ

<b><font color="red">$\huge{元氣ですかーーーーッ！！！}$</font></b>
<b><font color="red">$\huge{元氣があればなんでもできる！}$</font></b>

<b><font color="red">$\huge{闘魂とは己に打ち克つこと。}$</font></b>
<b><font color="red">$\huge{そして闘いを通じて己の魂を磨いていく}$</font></b>
<b><font color="red">$\huge{ことだと思います}$</font></b>

https://qiita.com/advent-calendar/2023/elixir

## はじめに

@torifukukaiou さんの ~~パク~~ リスペクト記事です

https://qiita.com/torifukukaiou/items/5361b81407b15e7c2f00

Elixir Livebook で Advent of Code 2023 の問題を解いてみます

https://adventofcode.com/2023

実装したノートブックはこちら

https://github.com/RyoWakabayashi/elixir-learning/blob/main/livebooks/aoc/2023/2023_day9_part2.livemd

問題はこちら

https://adventofcode.com/2023/day/9

Part 1 はこちら



## セットアップ

Kino AOC をインストールします

```elixir
Mix.install([
  {:kino_aoc, "~> 0.1.5"}
])
```

Kino AOC の使い方はこちらを参照

https://qiita.com/RyoWakabayashi/items/3d3abcf9134cee4dff05

## 入力の取得

Day 9 の入力を取得します

![スクリーンショット 2023-12-27 9.42.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/539c90c9-8c4b-6000-110c-e27f4b14f95e.png)

## 私の答え

私の答えです。
折りたたんでおきます。
▶を押して開いてください。

<details><summary>details</summary>

回答用のモジュールです

入力を扱いやすい形にするための `parse` と、回答を作るための `resolve` 関数を持っています

```elixir
defmodule Resolver do
  def parse(input) do
    input
    |> String.split("\n")
    |> Enum.map(fn line ->
      line
      |> String.split(" ")
      |> Enum.map(&String.to_integer(&1))
    end)
  end

  def resolve(array_list) do
    array_list
    |> Enum.map(fn array ->
      diff_array_list =
        0..(Enum.count(array) - 1)
        |> Enum.reduce_while([array], fn _index, acc ->
          last_array = Enum.at(acc, -1)
          diff_array = diff(last_array)

          if Enum.all?(diff_array, &(&1 == 0)) do
            {:halt, acc ++ [diff_array]}
          else
            {:cont, acc ++ [diff_array]}
          end
        end)

      even_sum =
        diff_array_list
        |> Enum.take_every(2)
        |> Enum.map(&hd(&1))
        |> Enum.sum()

      odd_sum =
        diff_array_list
        |> tl()
        |> Enum.take_every(2)
        |> Enum.map(&hd(&1))
        |> Enum.sum()

      even_sum - odd_sum
    end)
    |> Enum.sum()
  end

  defp diff(array) do
    {_, a_array} = List.pop_at(array, 0)
    {_, b_array} = List.pop_at(array, -1)

    Enum.zip(a_array, b_array)
    |> Enum.map(fn {a, b} ->
      a - b
    end)
  end
end
```

`parse` は Part 1 と同じです

`resolve` も差数列を求めるところまでは同じです

Part 1 は次の数字を予測しましたが、 Part 2 では前の数値を予測します

前の数値は以下のようにして求めました

- even_sum: 偶数番目の差数列の先頭の合計
- odd_sum: 奇数番目の差数列の先頭の合計
- 前の数値: even_sum - odd_sum

計算方法さえわかれば簡単ですね

</details>

## まとめ

Part 2 の実装はほとんど Part 1 と変わらないので簡単でした

どちらかというと数学的なセンスを試されている感じですね
日付と時刻の表記に関する国際規格 ISO 8601 覚書

[ISO 8601 - Wikipedia](https://ja.wikipedia.org/wiki/ISO_8601)

ISO 8601 は、国際標準化機関（ISO）が定めた日付と時刻の表記についての規格。

## 継続時間
- 例えば 1 時間は "PT1H"
    - "PT" は期間（Duration）を示し、"1H" は1時間を表す。 
        - 1 秒 → "PT1S"
        - 1 分 → "PT1M"
        - 1 日 → "P1D"

> P は期間を表す指定子（period を表す）であり、継続時間表現の先頭に置かれる。
> Y は年の指定子であり、年を表す数値の後に置かれる。
> M は月の指定子であり、月を表す数値の後に置かれる。
> W は週の指定子であり、週を表す数値の後に置かれる。
> D は日の指定子であり、日を表す数値の後に置かれる。
> T 時間の指定子であり、継続時間表現の時間の部分の前に置く。
> H は時間の指定子であり、時間を表す数値の後に置かれる。
> M は分の指定子であり、分を表す数値の後に置かれる。
> S は秒の指定子であり、秒を表す数値の後に置かれる。

(Wikipediaより)

## 日付時刻
- 日付
    - UTCで2024年1月1日午前0時00分
        - 2024年1月1日午前0時00分 UTC → "2024-01-01T00:00:00Z"
    - 東京時間
        - 2024年1月1日午前0時00分 東京時間 → "2024-01-01T00:00:00+09:00"

## 参考
[日時のフォーマット（ISO 8601） #ISO - Qiita](https://qiita.com/kidatti/items/272eb962b5e6025fc51e)
[ISO8601について #ISO8601 - Qiita](https://qiita.com/yass97/items/381b2543d4053444df49)
ノベルティの入出庫管理を LINE WORKS の Bot でやってみる

## 某社のノベルティ入出庫管理が紙ベースだった
「紺屋の白袴」すぎます。
LINE WORKS の Bot でノベルティの入出庫管理をやってみました。
![l_1517737_3235_79b35fb834ad412cf96ad9ce2c58e6f8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/7410c8f5-f8d9-ba1c-432f-df076c385b64.png)


## カルーセル テンプレート
カルーセル テンプレートで、ノベルティの画像と在庫数を確認しながら、入出庫の登録ができます。

横スクロールして、複数の品物の情報を確認できます。

入出庫による在庫数の変動ごとに、カルーセル メニューの JSON を動的に生成し、直近の在庫数を閲覧可能にしています。

![l_223021347_10_7dc2839d9f724a26be34375b3603cbd1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/778e1f1c-a240-351a-2dc4-e75ed8e8a61e.png)

カルーセル テンプレートのリファレンスは以下の URL です。
https://developers.worksmobile.com/jp/docs/bot-send-carousel

## 会話形式で処理
数量は文字入力です。

続けて処理するか、終了するかをボタン テンプレートで選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/1e805e97-d0cb-dbb6-2daa-cc06e7156182.png)

ボタン テンプレートのリファレンスは以下の URL です。
https://developers.worksmobile.com/jp/docs/bot-send-button

## Power Automate でローコード開発
Power Automate のフローで処理しています。

在庫表は Excel Online です。

カルーセル テンプレートの JSON は在庫数の変動ごとに動的に生成しています。
商品ごとのカラムの JSON を生成し カラムの最大数まで文字列変数に追加しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/339fef27-1b73-ba19-58ac-2cee95a91453.png)

~~~
      {
        "originalContentUrl": "https://iwaohig.github.io/NovStock/@{items('Apply_to_each_変数_column_に追加')?['itemid']}.png",
        "title": "@{items('Apply_to_each_変数_column_に追加')?['品名']}",
        "text": "在庫数: @{items('Apply_to_each_変数_column_に追加')?['現在庫数']}\n (@{body('タイム_ゾーンの変換')} 現在)",
        "defaultAction": {
          "type": "postback",
          "data": "action=out&itemid=@{items('Apply_to_each_変数_column_に追加')?['itemid']}",
          "displayText": "[出庫] @{items('Apply_to_each_変数_column_に追加')?['品名']}"
        },
        "actions": [
          {
            "type": "postback",
            "label": "出庫",
            "data": "action=out&itemid=@{items('Apply_to_each_変数_column_に追加')?['itemid']}",
            "displayText": "[出庫] @{items('Apply_to_each_変数_column_に追加')?['品名']}"
          },
          {
            "type": "postback",
            "label": "入庫",
            "data": "action=in&itemid=@{items('Apply_to_each_変数_column_に追加')?['itemid']}",
            "displayText": "[入庫] @{items('Apply_to_each_変数_column_に追加')?['品名']}"
          }
        ]
      },
~~~

カルーセルごとに、Request body の JSON を生成しています。

~~~
{
  "content": {
    "type": "carousel",
    "imageSize": "contain",
    "columns": [
@{variables('column')}
      {
        "originalContentUrl": "https://example.com/next.png",
        "title": "次へ",
        "text": "Next",
        "defaultAction": {
          "type": "postback",
          "data": "next1"
        },
        "actions": [
          {
            "type": "postback",
            "label": "次へ",
            "data": "next1"
          },
          {
            "type": "postback",
            "label": "NEXT",
            "data": "next1"
          }
        ]
      }
    ]
  }
}
~~~
闘魂Elixir ── Advent of code 2023 Day 9 Part 1 を Livebook で楽しむ

<b><font color="red">$\huge{元氣ですかーーーーッ！！！}$</font></b>
<b><font color="red">$\huge{元氣があればなんでもできる！}$</font></b>

<b><font color="red">$\huge{闘魂とは己に打ち克つこと。}$</font></b>
<b><font color="red">$\huge{そして闘いを通じて己の魂を磨いていく}$</font></b>
<b><font color="red">$\huge{ことだと思います}$</font></b>

https://qiita.com/advent-calendar/2023/elixir

## はじめに

@torifukukaiou さんの ~~パク~~ リスペクト記事です

https://qiita.com/torifukukaiou/items/5361b81407b15e7c2f00

Elixir Livebook で Advent of Code 2023 の問題を解いてみます

https://adventofcode.com/2023

実装したノートブックはこちら

https://github.com/RyoWakabayashi/elixir-learning/blob/main/livebooks/aoc/2023/2023_day9_part1.livemd

問題はこちら

https://adventofcode.com/2023/day/9

## セットアップ

Kino AOC をインストールします

```elixir
Mix.install([
  {:kino_aoc, "~> 0.1.5"}
])
```

Kino AOC の使い方はこちらを参照

https://qiita.com/RyoWakabayashi/items/3d3abcf9134cee4dff05

## 入力の取得

Day 9 の入力を取得します

![スクリーンショット 2023-12-27 9.42.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/539c90c9-8c4b-6000-110c-e27f4b14f95e.png)

## 私の答え

私の答えです。
折りたたんでおきます。
▶を押して開いてください。

<details><summary>details</summary>

回答用のモジュールです

入力を扱いやすい形にするための `parse` と、回答を作るための `resolve` 関数を持っています

```elixir
defmodule Resolver do
  def parse(input) do
    input
    |> String.split("\n")
    |> Enum.map(fn line ->
      line
      |> String.split(" ")
      |> Enum.map(&String.to_integer(&1))
    end)
  end

  def resolve(array_list) do
    array_list
    |> Enum.map(fn array ->
      diff_array_list =
        0..(Enum.count(array) - 1)
        |> Enum.reduce_while([array], fn _index, acc ->
          last_array = Enum.at(acc, -1)
          diff_array = diff(last_array)

          if Enum.all?(diff_array, &(&1 == 0)) do
            {:halt, acc ++ [diff_array]}
          else
            {:cont, acc ++ [diff_array]}
          end
        end)

      diff_array_list
      |> Enum.map(fn diff_array ->
        Enum.at(diff_array, -1)
      end)
      |> Enum.sum()
    end)
    |> Enum.sum()
  end

  defp diff(array) do
    {_, a_array} = List.pop_at(array, 0)
    {_, b_array} = List.pop_at(array, -1)

    Enum.zip(a_array, b_array)
    |> Enum.map(fn {a, b} ->
      a - b
    end)
  end
end
```

`parse` は単純に各行を数値の配列にして格納します

入力
```
0 3 6 9 12 15
1 3 6 10 15 21
10 13 16 21 30 45
```

パース結果
```elixir
[[0, 3, 6, 9, 12, 15], [1, 3, 6, 10, 15, 21], [10, 13, 16, 21, 30, 45]]
```

差数列を求める関数を用意します

```elixir
  defp diff(array) do
    {_, a_array} = List.pop_at(array, 0)
    {_, b_array} = List.pop_at(array, -1)

    Enum.zip(a_array, b_array)
    |> Enum.map(fn {a, b} ->
      a - b
    end)
  end
```

入力が `[0, 3, 6, 9, 12, 15]`　の場合、先頭以外の `[3, 6, 9, 12, 15]` と末尾以外の `[0, 3, 6, 9, 12]` について各要素の差をとることで `[3, 3, 3, 3, 3]` が取得できます
（Nx を使おうかとも考えましたがやめておきました）

差数列を全ての要素が 0 になるまで求めることで、数列の配列が以下のように求められます

`[[3, 6, 9, 12, 15], [3, 3, 3, 3, 3]]`

次の数字は各数列の末尾の合計（この例では 15 + 3）です

</details>

## まとめ

きっともっとスマートな方法があるのでは？と思いつつ、愚直に解きました

自分でババッと解いたあとに @torifukukaiou さんの回答を見ると、ちゃんと関数を分けていたりパターンマッチを上手く使っていたりで、実力の差を感じますね

私の回答はリファクタリングの余地だらけです

Part 2 はこちら

https://qiita.com/RyoWakabayashi/items/5e3708e6ed6b953372bd
GitLab CI実行時のタイムスタンプ取得方法

# はじめに
* GitLab CI実行時のタイムスタンプを取得する方法
* タイムスタンプの使用例
  * Gitのタグ付けなど

# 動作確認した環境
* GitLab 15.8
  * 後述の「CI_PIPELINE_CREATED_AT」変数を利用するため、13.10以降で動作可能

# 方法

* 【ポイント1】CI/CD変数の「CI_PIPELINE_CREATED_AT」を使う([参照](https://docs.gitlab.com/ee/ci/variables/predefined_variables.html)) 。
    * 13.10以降に導入された、CIパイプライン実行時の時間
    * 時間形式は、[ISO 8601](https://www.rfc-editor.org/rfc/rfc3339#appendix-A) 
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638977/30e9661e-0c9e-2c64-b808-9ef96e311c3d.png)
    * CI_PIPELINE_CREATED_ATで取得できる時刻のタイムゾーンは、GitLabサーバーによって異なる
        * GitLab.Comの場合は、デフォルトではUTC
        * その他のオンプレなど自前のサーバーではサーバー側の設定次第 
* 【ポイント2】ISO8601形式の時間を```date```コマンドで、yyyymmddhhmm(ss)形式に変換する。この時に、TimeZoneの指定をすることで、UTCから日本時間(JST:Asia/Tokyo)に変換する。


gitlab-ci.ymlサンプル
```yaml
stages:
  - build

build-job:
  image: ubuntu:latest
  stage: build
  variables:
    - DEBIAN_FRONTEND: noninteractive
  before_script:
    - echo "CI pipeline created timestamp:" ${CI_PIPELINE_CREATED_AT} 
    - apt-get update && apt install -y tzdata
    - export PIPELINE_TIMESTAMP=$(TZ="Asia/Tokyo" date -d "${CI_PIPELINE_CREATED_AT}" +"%Y%m%d%H%M")
  script:
    - echo "Pipeline timestamp (YYYYmmddHHMM)" $PIPELINE_TIMESTAMP
```
* 解説
    * ```before_script```内で、独自に定義した環境変数```PIPELINE_TIMESTAMPE```に、CI実行時間を代入する。
    * GitLabで定義済みのCI/CD環境変数```CI_PIPELINE_CREATED_AT```から取得できるISO 8601形式の時刻を、以下のdateコマンドで、```yyyymmddhhmm```形式に変換する。
         ```bash
         date -d "ISO8601形式の時刻" +"%Y%m%d%H%M"
         ```
         * 秒まで含めたい場合は、
             ```bash
             date -d "ISO8601形式の時刻" +"%Y%m%d%H%M%S"
             ```
         * 具定例 (ISO8601時刻：2023-12-27T00:00:38Z)
             秒まで含めた場合は、以下のようになる。
             コマンド
             ```bash
             TZ="Asia/Tokyo" date -d 2023-12-27T00:00:38Z +"%Y%m%d%H%M%S"
             ```
             * ISO8601時刻が、UTCの場合は、dateコマンドでTZ環境変数を指定することで、JSTに変換可能
             結果
                 ```
                 20231227090038
                 ```
         
詳細は、以下のサンプルコードリンクを参照。

https://gitlab.com/ntrlmt/gitlab-ci-pipeline-timestamp-test

# まとめ

```CI_PIPELINE_CREATED_AT```CI変数とdateコマンドを併用することで、CIパイプライン実行時のタイムスタンプを取得することができた。

# 参考

https://docs.gitlab.com/ee/ci/variables/predefined_variables.html

https://hawksnowlog.blogspot.com/2022/02/set-timezone-on-gitlab-ci-docker-executor.html

https://shuzo-kino.hateblo.jp/entry/2020/06/11/235700

https://kazuhira-r.hatenablog.com/entry/2022/08/04/233234

# トラブルシューティング
## date -dで、data: invalid data 'xxxx' となる 

### 原因

ベースイメージがdateコマンドの入力にISO8601形式をサポートしていないのが原因。

### 対策

dockerが利用可能な環境の場合は、docker経由で実行する。

```bash
docker run ubuntu:20.04 date -d "${CI_PIPELINE_CREATED_AT}" +"%Y%m%d%H%M"
```

以下を参考にした。

https://qiita.com/notakaos/items/e6462f82ee25399035be
プチ話  友達に "うれしい"  を 配列で伝えた話

こんにちはAtsu1209です。
今回はプチ話第二弾 うれしいを配列で伝えた話をしていきます。

# Line
友達から誕生日にLineギフトがきて、欲しかったスタンプをギフトしてもらいました。
そこでこんな返信をしました。

```javascript
const feel = [
    "怒り",
    "うれしい",
    "悲しい"
];

console.log(feel[1]);
```
そしたら友達から
```javascript
console.log("感情表現に配列使うなw");
```
と帰ってきました。
なぜか友達もconsole.logで返信してきました
以上

:::note
追記
配列のコードの`feel`が何故か`furuit`になっていました。
編集リクエストを送ってくれた方ありがとうございます。
:::