OmniAICreator/Qiita-1.07M huggingface dataset:
ゲーム開発の現場で役立った学生時代の経験

# 記事の概要
この記事はQualiArts Advent Calendar 2022の2日目の記事になります。

はじめまして、UnityエンジニアとしてQualiArtsに所属している岩井春樹です。
今回は業務を経験した上で役立った経験や、学生の時やっておけば良かったことをまとめた記事となっております。

# 役立った経験

### チーム開発経験
基本的に会社で行うゲーム開発は、エンジニアやプランナー、デザイナーなど様々な職種の方とチームを組んで開発を進めていくことが多いです。
そのため機能をひとつ開発するにしても、一人で進めていくことはほとんどなく、チームメンバーと相談してスケジュールを組んだり、何を優先して開発するべきかなどを意識して行動するなど、チームを意識した行動が重要になってきます。

具体的な例として、技術的な問題で機能開発に支障が出た場合、問題点を明確にして解決法を模索します。
エンジニアだけで解決できる問題なら良いですが、他職種の方にも対応を依頼しなければいけない場合や仕様変更が必要な場合もあります。
そんなとき、エンジニア目線だけでなく、別職種の方にも理解しやすいよう、問題点と解決法の提案をスムーズにできるかが大切です。
こういったコーディング以外の部分もエンジニアとして重要です。

これらは業務に取り組んですぐに身につくものではありませんので、学生の内からチームで活動する経験を積み重ねていくことが必要です。
特にエンジニア以外の職種を巻き込んだ開発ができると、より現場で活きる経験を積むことができると思います。

### インターンシップへの参加
インターンシップへ参加するメリットはたくさんあると思いますが、その中でも同じ目標を持った人と出会うことができ、さらに自分の技術力と比較できる点が非常に大きなポイントだと考えています。

私は大学3年時にサイバーエージェントが開催しているプロトスプリントリーグに参加しました。3人1組のチームが3日間でお題に沿ったゲームを開発するハッカソン型のインターンです。このインターンに参加するまで私は、周りにゲームエンジニアを目指している人が少なかったこともあり、自分の実力感が分かっていませんでした。
そして実際にインターンに参加した時、周りとの実力差にショックを受けたことを覚えています。

しかしこの経験から自分が目指すべき技術力の温度感がある程度分っただけでなく、同じ目標を持ったライバルと出会えることができ、よりゲームエンジニアになりたいという気持ちが強くなりました。

インターンにも就業型やハッカソン型など様々な形態があります。もちろん実力に自信がある方は積極的に就業型のインターンにチャレンジしていくことでより成長できると思います。逆にまだ自分の実力や開発経験に自信がない人は、短期間で開発経験を得られる、ハッカソン型のインターンに挑戦してみることをお勧めします。

<br>実際に筆者がインターンで作ったゲーム![game](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2276290/b18b20b2-df91-9b38-ad59-6cae48fb05b1.png)</ce>



### 完成まで作品を作り切る
ちゃんと最後まで作品を作り切る、言うのは簡単ですが実際に途中で投げ出さず完成させるのは非常に難しいです。

実装イメージがつく、もしくは作っていて楽しいと感じる部分を開発している段階までは誰でも実行できると思います。
しかし、開発を進めていくうちエラーになって動かなくなったり、ゲームに必要だけど苦手な部分の開発など、苦しくなる場面が必ずと言っていいほど出てくると思います。ここで諦めず解決方法を模索して、最後まで開発を続け作品を形にできるかが非常に大切です。

業務でゲーム開発を行う場合、すぐ実装方法が思いつく機能だったり、自分が作りたい機能ばかり開発するわけではありません。そんな時苦労を乗り越えて開発した経験があるかないかで、実装方法を模索する調査力に差が出てきます。

難しいものや非常に多機能なゲームを作れることは確かにすごい、だけど途中で挫折して作るのをやめてしまっては勿体無いです。
まずは一本すごくシンプルなゲームでも最後まで作りきることが大事だと私は思います。



# やっておけばよかったこと

### 設計などを考えた開発経験
同じオブジェクトやコードがたくさんあって、一つ仕様を変えようとしたら大量の差分が発生してしまう......こんな経験ありませんか？
実際自分も個人で開発しているときは、思いつくままにコードやオブジェクトを作成し、後々どうすればいいか分からなくなった経験がたくさんあり、設計理解などが入社後一番苦労した部分でもあります。(今も苦労してます....)

このような悪循環に陥ってしまう一番の原因は最初に実装周りの設計や考え方、仕様を考えられていない、またはしっかり詰め切れていないために起きてしまいます。
特に個人で開発をおこなっていると、「自分が読めればいいや」という気持ちで進めてしまい、設計などを無視しがちだと思います。

ただ一歩踏み出してみて、開発を始まる前に設計や仕様を決めて置けると、後々の修正のしやすさや、コードの追いやすさが全然変わってきます。また、一度成功体験を得られるとチャレンジしていく姿勢も身につけやすいです。

こういった部分は最初の一歩が踏み出しづらく大変ですが、設計思想が違っても設計を考えて開発した経験は、必ず現場で生きてくると思います。!

### 作った作品を公開する
開発を続けていると、どうしても視点や考え方が凝り固まってきてしまう経験ありませんか？特に個人開発ではそうなりがちだと思います。
作品を公開すれば、良い反応だけではありません。ただ誹謗中傷を除き、フラットな視点を持った人からの反応は非常に参考になります。
私は学生時代、いくつかのゲームを作成してはきましたがどれも公開したりせず、自己満足で終わってしまい、この経験を入社後に初めてすることができました。
今振り返るとすごい勿体無いことをしていたなと思います。
当時は「一つも反応がもらえなかったらどうしよう」など後ろ向きな気持ちが大きく作るだけに終わっていましたが、これだけ世の中にたくさんゲームが溢れている時代ですので、下手に心配せず公開した方がよかったなと反省しています。

# まとめ
自分の経験をもとに、どんな経験が役立って、何をしておけば良かったと感じたかまとめてみました。
ゲームエンジニアを目指している人にとっては当たり前のことばかりになってしまったかもしれませんが、少しでも参考になれば幸いです。
XX の取得に失敗しました  公開鍵を利用できないため、以下の署名は検証できませんでした: NO_PUBKEY KEYID と言われた時の対処法

apt-keyが今年(2022)くらいで廃止されるらしいのでそれまでの対応方法と廃止後の対応方法

# apt-keyを利用できる場合

ubuntuの場合
```
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys KEYID
```

debian
```
sudo apt-key adv --keyserver keyring.debian.org  --recv-keys KEYID
```

# apt-keyを使用せずに現行でも有効な方法

apt-key が廃止されたあとは下記のようにkeyをエクスポートして保存し
```
gpg --keyserver keyserver.ubuntu.com --recv-keys KEYID
gpg --export KEYID | sudo gpg --dearmour -o /usr/share/keyrings/suehiro.gpg
```
aptのレポジトリ設定に(下記は自分のlaunchpad)[signed-by=]を追記するようになるらしい。
```
deb [signed-by=/usr/share/keyrings/suehiro.gpg] https://ppa.launchpadcontent.net/bols-blue/hello/ubuntu/ jammy main
```

もう少しスマートになるといいな…
DynamoDBエクストリームで動くLambdaの起きがちなエラーの対処

# 概要
この記事では、DynamoDBエクストリームで動くLambdaの起きがちなエラーの対処方法を紹介します。

# エラー
まずはじめに、起こるエラーを紹介します。
```
[ERROR] KeyError: 'OldImage'
Traceback (most recent call last):
  File "/var/task/lambda_function.py", line 7, in lambda_handler
    old = event['Records'][0]['dynamodb']['OldImage']
```
変更前のデータが取得できないエラーです。

# 設定内容

Lambda関数のコードは下記のとおりです。

```python:lambda_function.py
import json

def lambda_handler(event, context):
    print(event)
    
    new = event['Records'][0]['dynamodb']['NewImage']
    old = event['Records'][0]['dynamodb']['OldImage']
    
    print(new)
    print(old)
    
    # TODO implement
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }
```

DynamoDBに加えた変更は、下記のとおりです。
- 変更前

|id|cast|favorite|program_name|time|weekday|
|---|---|---|---|---|---|
|mon2700|[{"S":"フワちゃん"}]|false|フワちゃんのオールナイトニッポン0|27:00-28:30|1|

- 変更後

|id|cast|favorite|program_name|time|weekday|
|---|---|---|---|---|---|
|mon2700|[{"S":"フワちゃん"}]|<font color="Red">true</font>|フワちゃんのオールナイトニッポン0|27:00-28:30|1|


# 対処法
まず、原因ですが、
変更を加える以前の、DB登録時に、
``OldImage`` がないため吐いたエラーが残っていることが原因です。

DynamoDBエクストリームを有効にすると、
自動で、``再試行`` に ``-1`` が設定されます。

これにより、Lambda関数内でエラーが起きた際に、無限に再試行を繰り返し、
DBに変更を加えても、前のエラーを吐き続けてしまいます。

対処法は、``再試行`` の値を、0以上に設定変更することです。

Lambda関数から ``設定`` を開き、トリガーを選択し、``編集`` を押下します。
``追加設定`` から ``再試行`` を ``0`` 以上に変更し、``保存`` で設定変更完了です。

``0`` を設定すると、下記のように ``なし`` が表示されます。

![トリガー.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2318120/1a2fffbb-6f65-75a9-e7b7-7971211b79d8.jpeg)

これで、DBの変更時にエラーが出ることは解消できます。

DB登録時にエラーが出ることに関しては、
Lambda関数の、OldImage取得部分を、OldImageが無くてもエラーを起こさない等、
コードに修正を加えることで解消できます。
【CommonLisp】リストの末尾に要素を加える方法

## ソース

いろいろあるだろうけど一例として

```cl
* (setf hoge '(1 2))
(1 2)
* (setf (cdr (last hoge)) '(3))
(3)
* (setf (cdr (last hoge)) '(4 5))
(4 5)
* hoge
(1 2 3 4 5)
```

ただし計算量はO(n)かかる
改善したい場合はQueueを使う選択肢がでてくる

https://qiita.com/mogamoga1337/items/508689c2f0ceb693a1fb
nginx環境でC++モジュールのCGIを動かすためのメモ

### 必要なパッケージ
apacheでは拡張子`.cgi`のハンドラーを登録すれば何となく動く。
nginxの場合はFastCGIを経由させてcgiモジュールを動かす。
動かすために必要なパッケージは以下の通り。
nginx
fcgi (要epel-release)
fcgi-devel (要epel-release)
fcgiwrap (要epel-release)
spawn-fcgi (要epel-release)

上記パッケージをyumかdnfで導入する。

#### spawn-fcgiの設定
```bash
# vi /etc/sysconfig/spawn-fcgi
```

以下の行を追加する
```config
# Example :
#SOCKET=/var/run/php-fcgi.sock
#OPTIONS="-u apache -g apache -s $SOCKET -S -M 0600 -C 32 -F 1 -P /var/run/spawn-fcgi.pid -- /usr/bin/php-cgi"
OPTIONS="-u nginx -g nginx -a 127.0.0.1 -p 9001 -P /var/run/spawn-fcgi.pid -- /usr/sbin/fcgiwrap"
```

#### nginxの設定
cgiを動かしたいドメインのディレクティブ内で.cgiの処理を定義する
```conf:ngin.conf

    location ~ \.cgi$ {
        fastcgi_pass   127.0.0.1:9001;
        fastcgi_index  index.cgi;
        fastcgi_param  SCRIPT_FILENAME  /$document_root$fastcgi_script_name;
        include        fastcgi_params;
    }
```

### C++でCGIを実装するのに便利なC/C++ライブラリ
#### Cgicc
gnuが提供しているライブラリ。
[cgicc](https://www.gnu.org/software/cgicc/)
実行モジュールから簡単にcgiのPOST/GETのデータをパースしてくれる。
カスタムヘッダーなどは`std::getenv`で取得。
```c++
...
        const char *tmp = std::getenv("HTTP_CONTENT_TYPE");
        std::string content_type(tmp ? tmp : "");
        if (!content_type.empty()) {
            std::cout << "HTTP_CONTENT_TYPE:" << content_type << std::endl;
        }
...
```
#### nlohmann/json
[nlohmann/json](https://github.com/nlohmann/json)
jsonデータのパース・生成

#### MySQL Connector/C++

https://github.com/mysql/mysql-connector-cpp

Mysqlで接続する場合に必要。
8.0からレガシーなアクセス方法であるJDBCのほかに
X Dev APIなるプロトコルでもアクセス可能。
但しmysql限定でmariadbでは使えないっぽい？

#### cpplinq - LINQ-like list manipulations for C++11
c++でC#のLinqっぽい操作ができるライブラリ。

https://github.com/mrange/cpplinq

#### SQLクエリビルダー
上記以外にSQLのクエリを安全に生成してくれるライブラリがあればいいんだけど
これといったものがない。
社内のモチベーションをあげるLT会 -モブプロ開発を行っているチームでやっている取り組み-

# はじめに

本記事は[モブプロ開発を行っているチームでやっている取り組み Advent Calendar 2022](https://qiita.com/advent-calendar/2022/mob_torikumi_example)の16日目の記事です

いままではチームのお話をしてきましたが、チームが成長したら次はその流れを社内に広げていく必要があります
私の会社の大きな課題は社内でエンジニアのモチベーションが低く、アウトプットを行っている人がとても少ないというところです
成長意欲がとても少なく、新たな挑戦をする文化がありません

そこで今回は先日行ったLT(ライトニングトーク)会について紹介します！

# 前回

https://qiita.com/Sicut_study/items/38e11851cce34a72a018

# Chapter#15 会社を盛り上げたい！なにをすれば！

じん「アールさんだいぶToDoリスト書けるようになってきましたね」
アール「ToDoをしっかり書くことでTDDもうまく進むし、工数もきれいに見積もれてとてもよいです！」
ミュート「いままでここまでちゃんと書いたことなかったけど、しっかり書いてみると難しかったね」
じん「最近ではアールさんもアウトプットで記事書いていたり、ベープさんも高速でフロント書いてたり、ミュートさんも新しい技術挑戦したりいい流れできてますね」
ベープ「フロントほんと楽しいです！いままでまったくやったことなかったので好きではなかったですが考えが変わりました」
アール「色々できること増えてもっとやりたいと思うようになりました」
じん「私たちのチームはかなりよい雰囲気になってきましたね。ですが私が目指すスクラムは以下です

チームが強くなる→他のチームも強くする→会社の全チームが強くなる

こうすることで、個人で働くというよりチームで働く、組織で働くという考えになり、働きやすい環境、成長できる環境になると思っています」

ミュート「じんさんよくその話してますよｗ」
アール「ということは今日は会社にその雰囲気を広げるための何かをやるんですね」
じん「ここからは私も実際に組織を変えた経験があるわけではないので他探りにはなりますが、今回はそのきっかけとしてライトニングトーク会をこのメンバーで企画してやりたいと思います！」
ベープ「LT会ってやつですね」

# ライトニングトーク会とは

まずはライトニングトークについて簡単に説明します。
ライトニングトーク(LT)とは稲妻トークの名の通り、5分程度の簡単なプレゼンテーションを表します

エンジニアがやるLT会の場合、技術系の話題を扱ったLTをあつめて大きなプレゼンテーション大会を開くことが多いです

私たちはまずライトニングトーク会を社内のシステム(100人)で開くために以下のことを行いました

1. ライトニングトーク会が初めての取り組みだったので事前に登壇者の8割を運営側が誘って用意した
登壇したい方は応募してくださいで私たちの会社の雰囲気では登壇してくれる人が見つからないと判断して事前に8割程度の人数を集めました。
実際に集めてから話すテーマも仮に決めてもらって一覧にして用意し、残りの2割のオープンな募集をかけるときに参加者として公開しました
その中には1年目の方や技術テーマでなく趣味の話題の方もいたので、参加のハードルが下がりました
結果的に30人ほどのメンバーがLT会の登壇を行ってくれました

2. 双方向なLT会にする

以前Go Conferenceに参加したときに驚いたのが今でも覚えています。
会場は仙台だったので、そこまで行ったのですが当日のLT中多くの方がツイッターを見ていたのです。

視聴者はリアルタイムにLTの感想や疑問、拍手などをTwitterにタグをつけてつぶやいていたのです。
それをみて思いつきました。ニコニコ動画風にコメントをLTのスライドに流したらもっと面白いんじゃないかと

そこで以下のソフトを見つけました

https://www.commentscreen.com/

しかし、こちらのソフトフリープランが2022年12月から参加者が50→5人になってしまいました。
私がLT会を開いたのが12月1日、その通知が来たのが前日かなり驚きました

そこで、同じようなサービスとして以下を採用しました

https://tetsuakibaba.github.io/commentable/#:~:text=Commentable%E3%81%AF%E9%81%A0%E9%9A%94%E6%8E%88%E6%A5%AD%E3%81%AE,%E3%81%A7%E3%82%82%E3%81%94%E6%B4%BB%E7%94%A8%E3%81%84%E3%81%9F%E3%81%A0%E3%81%91%E3%81%BE%E3%81%99%EF%BC%8E

このサービスであれば、人数気にせず同じようなことができます。欠点としてはカメラを押すと一瞬暗くなったり(フラッシュっぽくなる)、コメントがど真ん中に表示されたとき(①はランダム)、背景が黒くなってしまうなどあります(仕様です)

しかし、無料で使えたり自分のサーバーに立てたりできるのでいまのところはとても良いなとなっています。Slack連携なども簡単にできそうです

3. メタバース空間で開催する

今回驚いたのはメタバースでやることでzoomで開催するよりもライブ感がとてもあったことでした
メタバースでLTをやる未来は割と近いのではと思ってしましました。運用するうえでの課題はいくつかありましたがとてもよかったです

そんなこんなでアクシデントもありましたが無事LT会は終わりました
振り返りを大切にしているのでアンケートをとったところ次回も開催してほしいと要望が多くうれしかったです

アウトプットする機会が普段ないという方も多くいたので、比較的話しやすい社内という場で発表するところから盛り上げられたらと思います
LTで発表するきっかけで新しいことを学ぶ人が増えたらとも思っています

# 次回

https://qiita.com/Sicut_study/items/a57585741b64e515581c

# おわりに

今回私がLTで発表した内容は別のアドベントカレンダーで紹介しています


LT会を開くには多くエンジニアの協力が必要にはなりますが、今後はさらに気軽に開催できたらと思っています
GAEへのファイルアップロードで気付きにくい落とし穴にハマった件

# TL;DR  
- GAEへのファイルアップロードにはサイズ制限があるよ  
- 制限を超えるアップロードはGCSの"署名付きURL"を使おう  
- そのときはドメイン(CORS)制限に気を付けましょう

# やりたいこと  
GAEでWebアプリケーションをホストして、ファイルをアップロードしてGCSへ格納、それをトリガとしてCloudFunctionsでごにょごにょしたい
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49021/f73f09e6-6312-99e7-1647-d9b58d343ac4.png)
1. クライアントからGAEへファイルをPOST  
1. アップロードされたファイルをGAEからGCSへ転送（ [Google API](https://cloud.google.com/storage/docs/uploading-objects?hl=ja) ）する  
1. その後はGCSのファイル格納イベントをトリガとしてファイル処理をFunctionsに任せる．．．

このやり方だと、ユーザ認証や認可がGAE1か所でシンプルだしなにより一般的なファイルPOSTプラスGCSのAPIで実装できるので簡単！  
動作確認もOK！  

の、はずでしたが．．．

# なぜかエラーに  
ユーザテスト実施で、「ファイルがアップロードできないんだけど」との報告が
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49021/7b43ef74-8b7c-8949-671f-8c8d10cb40d6.png)
ファイルサイズがでかすぎるですって？！

なるほど。GAEへのリクエストの[サイズ制限](https://cloud.google.com/appengine/quotas?hl=ja#Requests)があるのね。確かに動作確認では数KBのファイルしか使ってなかったカモ。

でも直接GCSへアップロードさせるのもセキュリティを緩めたくないしなぁ。。。

# 署名付きURL！  
ありました！Google推奨プラクティス「[署名付きURL](https://cloud.google.com/blog/ja/products/gcp/uploading-images-directly-to-cloud-storage-by-using-signed-url)」！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49021/048b4d5e-adff-863f-3243-35719ad94607.png)
これでOK！  
つまりこう、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49021/397c16bc-c8bd-6102-eac1-e312fa7b0e01.png)
1. クライアントからGAEへ「こんなファイルをアップロードするよ！」とリクエスト  
1. GAEは受信したファイル情報を基にGCSから「署名付きURL」を取得して  
1. クライアントへその「署名付きURL」を通知  
1. クライアントからファイル実体をその「署名付きURL」へPUT  
1. めでたくサイズ制限なしでアップロードが完了して後続の処理へ．．．  

てなわけです。  

ちょっと処理が複雑になるとともに、UIを変えずに変更となるとAjaxを使うことになるものの、Google推奨プラクティスでセキュアに実装できますね！

あぁよかった。

さて、動作確認。

# え？403って？  
署名付きURLへファイルをPUTしようとすると、今度はGCSから403（forbidden）エラーになってる！  
 ~~Googleの嘘つき～~~  

これは、[CORS（オリジン間リソース共有）](https://developer.mozilla.org/ja/docs/Web/HTTP/CORS)違反なのね。  
つまりは、GAEでホストされているドメイン（大抵自分で取得した）と、GCSの署名付きURLのドメイン（GCSから払い出される）が異なっていて（そらそうだ）、それをGCSはデフォルトで許容しない設定になっているのね。Googleごめんなさい。  


# GCSのバケットにCORSを構成する  
~~敵~~ 対象が分かれば対応はJustDoIt!  
もちろん[公式サイトにも記述](https://cloud.google.com/storage/docs/configuring-cors?hl=ja)があります。Googleありがとう！  
つまりはGCSへPUTリクエストを出す側のドメイン（この例だとGAEのドメインね）からのアクセスを許してやる。てことね。  

この構成は対象のGCSバケットに1度設定してやればOKなので、  
- コマンドラインから手で実行してやってもいいけど、  
- IaCとしてバケット作成時に自動で構成してもいいし、  
- 環境ごと（本番/ステージング/開発）の差異（つまりはクライアントのドメイン）を一か所で管理したければGAEのアプリで最初に構成してやるって手もあるよね。（これだとローカルでGAEシミュレータから動かすときに再構成しやすいしね）  

．．．なんてやり方で構成してやればOK。  

# 皆さんご唱和ください！  

**「アップエンジン(GAE)へのアップロードは、サイズに注意、ドメイン注意」**  

私のハマった経験が皆様の良いDX（Developer Experience）の助けになれば幸せです。
寿司打チートをする際の方策と注意

![寿司打の時間越え](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3003623/73ec6bd7-dd74-aef5-d07e-409ad475c356.png)

本記事では昔寿司打自動化ツールを作ることを公式で禁止されてなかった時代（以降「昔」はこの意味で使っています）わたしが寿司打自動化ツールを開発していたときに注意していたこととその方策をまとめています
具体的なコード例は書いてありません
あくまで本記事はアルゴリズム紹介記事です
現状公式は禁止しているのでこれはただ単の読み物として読んでください

## 寿司打の自動化ツールは公式で禁止されている
昔わたしは寿司打自動化ツールに試行錯誤していました
でも今は公式的に禁止されています
ここで[寿司打の公式サイト](https://sushida.net/)を見ていきましょう

> 【ご利用上の注意】寿司打は個人のタイピングの練習や上達を応援するサイトです。外部ツールの使用や、営利目的の使用は禁止されています。

この通り寿司打の自動化は現在禁止されています
なので今寿司打の自動化を始めたいのであれば以下の2択から選ぶことになります
- 諦める
- 寿司打のようなタイピングゲームを再開発し寿司打自動化ツールのようなものを作る

後者は限りなく大変なので今から寿司打の自動化をしたいというのであればそれはやめましょう

「作ることは禁止していない」とか「ランキングに載せなければ良い」とか独自解釈をして乗り切ることはわたしは勧めません

## 入力処理
Pythonの場合はpyautoguiなどを使えばできます
逆にJSの場合はECMAの規格でできないのでだからどんなにググっても無茶だし無理だし無意味です
何を言いたいかというとこの後のスクショ処理とか画像処理とかをどんなに頑張って実装したとしてもそれは水の泡になってしまうということです

## スクショ処理
ターミナルコマンドを使ってスクリーンショットを撮ってもプログラミング言語内で提供されている処理を使っても実現できます
ただし2枚以上ディズプレイがある場合はうまく動かないことがあるのでそこは必要な処理を適宜入れてください

## 画像をクロップ
先ほどのスクショで得た画像から一部を切り出しする処理をします
具体的に座標を決めて取り出すのでも実現できますし色から推定して取り出すのでも実現できます

## RGB画像を1チャンネル画像にする
グレースケールなりRだけなりで取り出せます
Pythonの場合はPILやOpenCVを使えばできると思います

## 二値化
よく見る二値化の説明では「画像からテキストを推定する精度を上げる」というものがありますがあれはたいてい嘘です
実はこれをしたところであまり変わりません
有意差のあるレベルでは変わりません
昔果てしなく寿司打自動化ツールに試行錯誤していたわたしが言うので間違いないです

## ポシネガ変換
Pythonだとtesseractを使うことが多いと思うのでtesseractについて言及しますとtesseractの場合はどうも背景が白で文字が黒の場合のほうが精度の高い文字検出をしてくれます
とはいえもしOCRを自分で作る場合はその自作OCRに依るのでこの処理は不要かもしれません

## 画像からテキストを推定
Pythonならtesseractを使うことが多いと思います

## 不要な文字の剪定
寿司打では小文字アルファベットと"!?,-"以外の文字は使わないので正規表現などを使って適宜処理します
そのまま入力すると不正解になってしまうのでやはりこの処理は必要です

## 時間を超えた処理は寿司打のシステムに引っかかる
高級コースだと340皿あたりのところでJSの`window.alert()`による警告が出ます
![寿司打のシステムにより警告されている](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3003623/9a488375-af10-e349-bbae-7fc65eb062b5.png)

本記事の内容をコードに落とし込んで高級コースを実行するとたいてい出てきます
高級コースだと本来は120秒+皿平らげ追加時間しか実行できないはずですが皿平らげ追加時間が入力時間を超えることが原因です
諦めてください


## さいごに
あくまで本記事はアルゴリズム紹介記事です
現状公式は禁止しているのでこれはただ単の読み物として読んでください
なお本記事で紹介されている個別のプログラミング言語やライブラリーはあくまで参考程度です
これら紹介した個別のものを使ったからといって500秒を超えることは保証しません
というかこれら紹介した個別のものを使ったところで500秒は超えないと思います
本記事では紹介しきれていない別のライブラリーとかを使ったり本記事では対象外としている行列計算とかを高速化したりすれば500秒を超えられます
AWS資格試験の時間を30分延長する

# 概要
AWS資格試験にて、Non-native english speakersなら受験時間を追加で30分延長することができる。
その設定方法を説明する。

# 詳細
## 前提や縛り
- AWS資格試験のためのアカウントを持っていて、試験申請ができる状態であること
- まだ試験の予約をしていないこと
  - もし予約済みならキャンセルできること（試験前日でなければキャンセルはできる）

## 手順
### 1.ログイン
AWS認定ページへログインする。
ログインできたら、以下の赤い四角の中の「試験対応の申請」をクリック。

![スクリーンショット 2022-12-02 10.57.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114660/01b1e302-64e5-63d3-c7a6-af7f120a7d67.png)

### 2.ESL+30MINUTESを選択
以下画面が出たら、下記「対応の選択」にて`ESL +30 MINUTES`を選び、「作成」ボタンをクリック。
**すでに試験を予約した人は本画面が見れない**ので、まず**予約をキャンセルしてから実施**すること。

![スクリーンショット 2022-12-02 10.58.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114660/f473999d-19dc-7927-42fc-362b9fdfbf06.png)

以下の確認画面が出ることを確認し、リクエスト。

![スクリーンショット 2022-12-02 10.59.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114660/28b3d1fe-9daf-a587-e74a-f46288aa0f59.png)

リクエストができたら、試験を予約すること。

## 結果
問題なければ、以下のように試験時間が延長される。
私も一回キャンセルして再度予約したので、Before-Afterを出すことができた。

### Before：140Min
![スクリーンショット 2022-12-02 11.01.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114660/a0dcda2e-81a5-8c74-314c-6b511d34e9b5.png)

### After：170Min
![スクリーンショット 2022-12-02 11.01.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114660/271fcd5d-0609-996b-95ea-413e9dbfd31e.png)

試験予約までできてから上記「試験対応」画面に入ると、以下のように30分延長が適用されたことが確認できる。
この30分延長オプションは一回だけ申請したら今後の試験にも全て適用できる。

![スクリーンショット 2022-12-02 11.08.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114660/82840b37-6b12-488b-8beb-da7a93ba6deb.png)
Androidで「ロジックとデータの一体化」を実践してみた

# 「ロジックとデータの一体化」とは
以前、私が所属するコミュニティでプリンシプルオブプログラミング輪読会を行なっていました。
プリンシプルオブプログラミングとはその名の通り、プログラミングをする上で原理原則となるような概念や知識が書かれている名著です。
その本の3.7章(p74)に「ロジックとデータの一体化」というテーマがあります。
その章の内容を要約すると以下の通りです。

- データとその操作は近くに
    - ロジックとデータをコード上で近くに配置する
    - データと操作は修正タイミングが同じだから
    

# 当時の私
この章を読みたての頃は、自分の経験に落とし込めていなかったので、あまりよく理解できていなかったです。
具体的にはこのような疑問が頭に浮かんでいました。

- この文脈でいうデータってなに？
- ロジックって例えば？
- 近くに置くってどういうこと？

# Androidで言うとこういうこと！

最近個人開発をしていて、やっと経験に落とし込めたので共有します！
結論から言うと、「ロジックとデータの一体化」はUIStateを適切に実装する上で必要な考え方です。

[前提]
- `ViewModel`…データがあるところ、UIに表示する要素の状態(`state`)を保持しているところ→state holder
- `UIState`…データ(表示する要素)を持っているクラス


この前提を踏まえると、「データを加工するロジックをデータの近くに置く」を、「データを加工するロジックをUIStateに書く」と言い換えることができます。

例えば以下は実際に私が個人開発を通して実装したコードです。
これは、connpass上からAndroid/kotlinに関連するイベントを選択して表示するアプリで、各イベントにいいねも押すことができます。
従って、以下のソースコードにある`event`は取得してきたconnpass上のイベントのことで、`isFavorite`はいいねの状態を保持するデータです。

```kotlin
// EventViewModel
data class EventItemUiState(
    val event: Event,
    val isFavorite: Boolean
) {
		// 取得してきたイベント開始日から「月」のデータを取得
		// 「◯月」みたいな表示になるように取得したデータの後ろに「月」を付ける
        private val calendar = Calendar.getInstance().also { 
            it.time = event.startedAt.date
        }
		val month = calendar.get(Calendar.MONTH).toString() + "月"
}
```
この実装で言うと「データを加工するロジック」とは、取得してきたイベントの開催日程から「月」のデータを取得して、「○月」みたいな表記にするロジックです。

データ(UIStateで保持されているデータ)を加工するロジックを、データの近く(UIState内部)に書いております。

# もしデータとロジックが別々の場所にあったら？
そもそもどうして「ロジックとデータの一体化」を実現しなければいけないのでしょうか。
もしデータとロジックが別々の場所にあったら何か困ることがあるのでしょうか。

### 他の場所でも同じロジックを使いたいとなった場合コピペになる。

もしロジックに変更が入った場合、同じロジックが複数箇所に散らばっていると、
全てのロジックを修正するのが難しくなり、バグが生じる可能性があります。

ここで、同じロジックを使いたいだけなら関数に切り分ければいいのでは？となりますが、
下手な関数を作成して、使用者が「この関数を使うのが適切かどうか」の判断を行わなければいけない状態になると、コードの品質が開発者の腕前に左右されてしまいます。


# まとめ

- 「データとデータを加工するロジックは近くに置こう」とはAndroidでいうと、「画面に表示したいデータを加工するロジックはUIStateに書こう」ということ。
- データとデータを加工するロジックを近くに置くと、UI層がデータ加工ロジックで汚れないので可読性が上がる
- 同じロジックを使い回す時にも有効

Qiitaのアドカレ初めて参加しました！
読んでくださりありがとうございました！！
ChatGPTに競技プログラミングさせてみた【AtCoder】

# FizzBuzz

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208363/b18dc3d7-5f45-30e0-6ee8-3ef1ffadc0c0.png)

# PracticeA - Welcome to AtCoder

https://atcoder.jp/contests/abs/tasks/practice_1

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208363/93563adc-99b6-325a-d59e-53d69707a572.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208363/bd0bcab8-df4b-0cfc-8712-b3d37826796a.png)

AC

# ABC086A - Product

https://atcoder.jp/contests/abs/tasks/abc086_a

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208363/0f7e5b07-66ad-e474-62ac-00e3ea0a790d.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208363/5d7eaa67-be3f-2d4f-c6e1-46d7084d26b5.png)

AC

# ABC049C - 白昼夢

https://atcoder.jp/contests/abs/tasks/arc065_a

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208363/10cfc092-9c4b-6a58-1582-e09dc780945c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208363/1f59e782-5f29-e5ac-2abb-aa9624b920c5.png)

AC

# まとめ

いかがだったでしょうか(ry

https://twitter.com/izumisatoshi05/status/1599047715643871232

AtCoderプロンプトエンジニアリング界隈が発展してほしいです
【rails】rails g controllerコマンドでapi/以下にファイルを生成するコマンド

## はじめに
自分はAPIモードを使わずにapi/以下にコントローラーを作っていて、毎度お目当ての情報にたどり着くのに時間がかかっていたのでメモ
### 参考
https://qiita.com/terufumi1122/items/634dac88de01f3f73821

## 環境
```ruby
OS: macOS Monterey
Ruby: 3.1.2
Rails: 7.0.4
```

## コマンド
```console
rails g controller api/v1/posts
```
【TypeScript】状態で分岐できるパーサコンビネータを作った

## はじめに

TerrarioというTypeScript製のパーサコンビネータを書いたので紹介します。

ソースもGitHubで公開してます。
https://github.com/marihachi/terrario 

## 作成の経緯
これまでJavaScriptやTypeScriptでパーサーを作成する時はPEG.jsを使っていました。
PEG.jsはササッとパーサーを書けるのでパーサーの試作としては便利なライブラリですが、
少し複雑な仕様を盛り込んだパーサーを書こうとすると力不足に感じていました。

### こんな時
例えば、以下のように括弧をネストできる文法を考えた場合、
```
1+(2+(3+4))
```
素直に実装すると、括弧の中身は関数呼び出しとして表現されます(再帰下降パーサーの場合)。
あまりにも多く括弧が含まれているとスタックオーバーフローの原因になるため、ネストできる回数は制限したくなります。

このような要求をPEG.jsやその他知っているライブラリでは実現が難しそうでした。できたとしても、トリッキーな方法になると思います...。

### 複雑な仕様に対応したい
そこで、条件を使ったパース処理の分岐をサポートしたパーサジェネレータやパーサコンビネータを探しましたが、それらしいものが見つからなかったので作ってみました。

## コンセプト
- 状態を使ってパース処理を分岐できる。
  - 例: ネスト回数をカウントしてパース結果を変えるなど。
- パーサーコンビネータとして作成する。
  - 小さい関数の組み合わせになるため、JavaScriptエンジンの最適化が効きやすいです。
- APIをシンプルにする。
  - 各コンビネータの名前や構成は[Parsimmon](https://github.com/jneen/parsimmon)というライブラリを参考にしました。

## 基本的なパーサーの例
hello worldという文字列を受け入れるパーサーです。
```ts
import * as T from 'terrario';

// build a parser
const parser = T.alt([
  T.str('hello'),
  T.str('world'),
  T.str(' '),
]).many(0);

// parse the input string
const input = 'hello world';
const result = parser.parse(input);

console.log(result);
// => { success: true, value: [ 'hello', ' ', 'world' ], index: 11 }
```
- `T.alt`: いずれかにマッチ。優先度付き選択。
- `T.str`: 文字列か正規表現で入力文字列にマッチ&消費。
- `parser.many(0)`: 0回以上の繰り返し。

## JSONパーサーの作成例
JSONパーサーは100行程度で書けます。

https://github.com/marihachi/terrario/blob/0a1c55a4596b09801494c0ee10c07304680250df/examples/json/src/index.ts

## おわりに
JavaScriptやTypeScriptでパーサーを作成する時は、Terrarioをぜひ試してみてください！
Azure Administrator(AZ-104)：Azure管理者向けの前提条件「Bicepテンプレート」

Microsoft Learnを用いたMicrosoft Azure Administrator(AZ-104)の試験内容をまとめる投稿です。
この投稿ではMicrosoft Learnで学ぶ内容をできるだけ簡潔にまとめております。
Azureの勉強を一から始め、AZ-900取得後の資格としてAZ-104取得を目指している方の参考になれば幸いです。
※AZ-900の内容は本投稿では省略しております。再度復習したい方は下記をご参照ください。
[Azure Fundamentals(AZ-900)：試験合格に向けた学習内容のまとめ](https://qiita.com/fsd-jume/items/e4ec76959adb547ac5e8)

## 今回の学習内容
**◆「Bicepテンプレート」**
◇対応するMicrosoft Learn ラーニングパス
[AZ-104:Azure 管理者向けの前提条件](https://learn.microsoft.com/ja-jp/training/paths/az-104-administrator-prerequisites/)
◇対応するモジュール
[Bicep テンプレートを検討する](https://learn.microsoft.com/ja-jp/training/modules/configure-resources-arm-templates/5-consider-bicep-templates)

※前回の投稿は下記から確認できます。
[Azure Administrator(AZ-104)：Azure管理者向けの前提条件「ARMテンプレートのパラメーター」](https://qiita.com/fsd-jume/items/e05bb275eba9f299a2f5)

## Bicepテンプレート
**ARMテンプレートで使用可能なAzure特有の言語(ドメイン固有言語：DSL)**
⇒JSONよりも多くの点が強化され使いやすく設計された言語

### Bicepテンプレートを使用したデプロイの流れ
①Bicepテンプレートを使用してデプロイ実行
②BicepテンプレートがJSONテンプレートに変換(トランスパイル)
③JSONに変換されたテンプレートがResource Managerに送信されデプロイ開始

### Bicepの利点
**・シンプルな構文**
JSONテンプレートよりも作成しやすく読みやすい構文
例)JSONとBicepにおけるストレージアカウント作成のテンプレート
```json:JSON
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]"
    },
    "storageAccountName": {
      "type": "string",
      "defaultValue": "[format('toylaunch{0}', uniqueString(resourceGroup().id))]"
    }
  },
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2021-06-01",
      "name": "[parameters('storageAccountName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Standard_LRS"
      },
      "kind": "StorageV2",
      "properties": {
        "accessTier": "Hot"
      }
    }
  ]
}
```
```:Bicep
param location string = resourceGroup().location
param storageAccountName string = 'toylaunch${uniqueString(resourceGroup().id)}'

resource storageAccount 'Microsoft.Storage/storageAccounts@2021-06-01' = {
  name: storageAccountName
  location: location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
  properties: {
    accessTier: 'Hot'
  }
}
```
**・モジュール性**
モジュールと呼ばれる個別のBicepファイルを作成し、メインのテンプレートでそれらを参照可能
⇒Bicepのコードを整理して再利用したり、管理が容易になる

**・依存関係の自動管理**
リソース間の依存関係は自動検出

**・検証の種類とIntelliSense**
Visual Studio Code用のBicep拡張機能を使うことで、豊富な検証機能とIntelliSenseを使用可能
※IntelliSense：コード候補の表示や補完機能、ドキュメントへのアクセスなどの入力支援機能

## 次の学習内容
**◆リソースの定義(Bicep)**

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

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

https://qiita.com/fsd-jume/items/6eda24728c9c03c36bc3
【CSS】テキストの下線(アンダーライン)を太くしたくないですか？僕はしたいです。

※ 本記事はDMM WEBCAMP mentor Advent Calendar 2022 11日目のエントリーです。

CSSでテキストに下線を引く方法として、text-decorationを使ったものが有名です。

```html
<p class="sample-text">テキスト</p>
```

```css
p.sample-text {
  text-decoration: underline;
}
```

こう書くと

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="zYamROd" data-user="takumi3488" 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/takumi3488/pen/zYamROd">
  Untitled</a> by takumi (<a href="https://codepen.io/takumi3488">@takumi3488</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

こう表示されます。
色や形状もある程度アレンジが可能です。

```css
p.sample-text {
  text-decoration: underline dotted #FF3490;
}
```

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="rNKqpXm" data-user="takumi3488" 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/takumi3488/pen/rNKqpXm">
  Untitled</a> by takumi (<a href="https://codepen.io/takumi3488">@takumi3488</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

このように、点線にしたり色を変えたりできます。
しかし、線を太くしたい場合にはどうすればよいでしょうか。
例えばマーカー風の線を引きたいときなどです。

パッと思いつくのは、border-bottomを使った方法です。

```css
p.sample-text {
  border-bottom: solid 5px yellow;
}
```

実はこれだと線がながーく伸びてしまいます。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="jOKeZOW" data-user="takumi3488" 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/takumi3488/pen/jOKeZOW">
  Untitled</a> by takumi (<a href="https://codepen.io/takumi3488">@takumi3488</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

実はpタグのようなinlineの要素はデフォルトで横に伸びきってしまっています。
これを回避するために、inlineじゃなくしてやりましょう。

```css
p.sample-text {
  border-bottom: solid 5px yellow;
  display: inline-block;
}
```

これでうまくいきます。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="ExRdQxw" data-user="takumi3488" 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/takumi3488/pen/ExRdQxw">
  Untitled</a> by takumi (<a href="https://codepen.io/takumi3488">@takumi3488</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
go_router 5.0以降でrefreshListenableにStreamを使う方法

# はじめに
<!-- 発端や概要を記載 -->
[go_router](https://pub.dev/packages/go_router)を5.2.0に上げたときに、`refreshListenable`で`GoRouterRefreshStream(stream)`という書き方が出来なくなっており、解決策を調べたので共有したいと思います。

コピペで使いたい人向けにコードを置いておきます。
[StackOverflow](https://stackoverflow.com/questions/69930605/how-to-convert-a-stream-to-a-listenable-in-flutter)で回答されていたコードが個人的に良さそうと思ったので、それをそのまま使ってます。
```dart
import 'dart:async';
import 'package:flutter/foundation.dart';

class GoRouterRefreshStream extends ChangeNotifier {
  GoRouterRefreshStream(Stream<dynamic> stream) {
    notifyListeners();
    _subscription = stream.asBroadcastStream().listen(
          (dynamic _) => notifyListeners(),
        );
  }

  late final StreamSubscription<dynamic> _subscription;

  @override
  void dispose() {
    _subscription.cancel();
    super.dispose();
  }
}

・・・

// 使用例
GoRouter(
    initialLocation: "/",
    debugLogDiagnostics: false,
    redirect: (context, state) {
        // リダイレクト処理
    },
    // 上記クラスを使用
    refreshListenable: GoRouterRefreshStream(authRepository.authStateChanges()),
    routes: <RouteBase>[
    ],
  );

```

# 目次
<!-- タイトルとアンカー名を編集 -->
1. [使えなくなった原因](#使えなくなった原因)
1. [refreshListenableとは何か？](#refreshListenableとは何か？)
1. [参考文献](#reference)

<!-- 各チャプター -->
<a id="#使えなくなった原因"></a>
# 使えなくなった原因
使えなくなった原因は、`go_router`の5.0.0以降で`GoRouterRefreshStream`クラスが削除されたからです。
削除した理由はルーティングとは関係ないクラスだからのようです。

<a id="#refreshListenableとは何か？"></a>
# refreshListenableとは何か？
使えなくなったときに、`refreshListenable`って何？と疑問に思い、少しだけ調べてみました。
* `refreshListenable`は`Listenable?`型
* `Listenable`型を継承したクラスには、`ChangeNotifier`がある
（`ChangeNotifier`のほかに、`ValueListenable`というクラスも使えそうでしたが使い方は調べてません。知っている方いればコメントいただけると嬉しいです）

上記の理由から、サンプルコードの`GoRouterRefreshStream`は`ChangeNotifier`を継承させたクラスになっています。

<a id="#reference"></a>
# 参考文献
- https://stackoverflow.com/questions/69930605/how-to-convert-a-stream-to-a-listenable-in-flutter
Rails7をとりあえず起動するまで

※ 本記事はDMM WEBCAMP mentor Advent Calendar 2022 6日目のエントリーです。

網羅的に紹介する訳ではなく、あくまで僕個人が良いと思ったやり方やオプションについてのみ書いていくのでご了承ください。

## インストール

```sh
$ gem install rails -v 7.0.3
```

## `Rails new`コマンドオプション

おすすめのオプションは以下の通りです。

```sh
rails _7.0.3_ new app_name -T -c tailwind -d postgresql
```

- `_7.0.3_`はバージョンの指定。デフォルトが7.0.3になっていれば付けなくても良い
- `-T`はテストをスキップするオプション。テスティングライブラリはデフォルトだと`Minitest`なので`Rspec`を使う場合は付けた方が良い
- `-c tailwind`はCSSライブラリとしてTailwindを指定している。Node.js不要でCSSを勝手に必要な分だけ取ってきてくれる機能が新しく搭載されたので、今回は一番効果を実感できそうなこれを選んだ。
- `-d postgresql`はデータベースにPostgreSQLを選択している。デフォルトのSQLiteはActiveStorageなんかを使うと、仕様上の問題ですぐエラーが起きるのでPostgreSQLかMySQL等がおすすめ。

このコマンドでとりあえず作成できるはずです。

## 作成したらやること

Rails7だからという話ではないですが、PostgreSQLでRailsを作成したのでDBの設定をします。

一気に書きます。

```yml:compose.yml
services:
  db:
    image: postgres:latest
    restart: always
    env_file:
      - .env
    ports:
      - 5432:5432
    volumes:
      - ./data/development:/var/lib/postgresql/data
```

```txt:.env
POSTGRES_USER=admin
POSTGRES_PASSWORD=V8GrknqpuIEG4GjDWtPj8g
TZ="Asia/Tokyo"
```

```yml:database.yml
default: &default
  adapter: postgresql
  encoding: utf8
  username: <%= ENV["POSTGRES_USER"] %>
  password: <%= ENV["POSTGRES_PASSWORD"] %>
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  host: localhost

development:
  <<: *default
  database: myapp_development

test:
  <<: *default
  database: myapp_test

production:
  <<: *default
  database: myapp_production
  username: workbook_manager
  password: <%= ENV["MYAPP_DATABASE_PASSWORD"] %>
```

RailsはDocker化せずにDBだけDocker化するやり方で書いているので注意してください。RailsもDocker化する方法については今回は書きません。そのうち使う機会があれば記事にもしようと思います。

ちなみにDBだけDocker化すると、Railsが高速で動くこと、DBの作り直しが容易になることの2つのメリットが共存して快適になります。MacのDockerはめちゃくちゃ遅いですからね（Finchが出たことで簡単に解決できるようになるかもしれません）。

後はRailsで.envファイルを読み込むために、Gemfileに

```rb:Gemfile
gem "dotenv-rails"
```

を追加して、以下の手順で実行すればサーバーが起動します。

```sh
bundle install # dotenv-railsをインストール
rails db:create # dbの作成
rails s
```

画像は載せませんが、起動画面が変わっていてカッコイイですね。

ちなみに起動コマンドを`rails s`ではなく`./bin/dev`にすると、TailwindのCSSを変更した時に、自動でCSSをビルドしてくれるようになるので、開発を進める際にはこっちを使うようにしましょう。

後はRails6以前と同じように開発できるはずです。
Obsidianの保管庫をGitHub経由で別マシンと同期


## はじめに

サブマシンにlinuxをがんがんインストールしています。Obsidianがないと不便で不便で。「とりあえず何でもObsidianにメモ」しておけるとなにかと安心です。

GitHub経由でVaultを同期し、さっくり使えるようにしました。

## 動作と設定の概要

今回の想定は
- マシンAはmacOSが動いている
- マシンBはLinux Mintが動いている

です。が、macOS-macOSでも、macOS-その他のlinuxディストロでも、やることは同じです。


![Untitled-2022-12-02-0802.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/df5b854c-88ab-80f8-106d-8ed54309f08a.png)

マシンAへのgit、Obsidian、gitプラグインはインストールされているとします。

1. マシンBにgitをインストールしてVaultを使えるようにします
1. マシンBにObsidianをインストールして設定します
1. マシンBにプラグインをインストールして設定します

## 設定の詳細

### マシンAの調整

マシンAのObsidianの設定フォルダを複製します。たとえば、`.obsidian`を複製し`.obsidian-linux`と名称変更します。

マシンAのObsidianで、`Obsidian Git: Create backup`して、Obsidianを終了します。

![Screenshot_2022-12-02_08-40-27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/0e78b3a0-d3c8-a268-7485-494ae6a41115.png)

### マシンBへのインストールと設定

#### 1.マシンBにgitをインストールしてVaultを使えるようにします

まだの場合、gitをインストールします。

```shell
$ sudo apt install git
```

gitに自分の情報を登録します。

```shell
$ git config --global user.email "you@example.com"
$ git config --global user.name "Your Name"
```


つぎに鍵ペアを作成します。

```shell
$ mkdir ~/.ssh
$ cd ~/.ssh/
$ ssh-keygen -t ed25519 -f ./id_ed25519 -C "your@mail.com"
$ ssh-add id_ed25519
```

:::note
パスフレーズは登録しません（文字列を入れずにEnterキーを押下）。
Obsidian Gitでパスフレーズを登録しておくことができないためです。
:::

つぎに、公開鍵をGitHubに登録します。

```shell
$ cat id_ed25519.pub
```
で表示されたテキストを、GitHubに登録します。`Settings > Access > SSH and GPG keys` から、`New SSH Key`ボタンを押します。

![Screenshot_2022-12-02_09-06-25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/9f5ab6c4-fa07-8542-89cf-0d27924ef8b2.png)

:::note
Titleは適当に。あとで自分がわかれば良いです。
Keyはさきほどcatしたテキストを貼ります。
:::

これで下準備は整いました。いよいよVaultをマシンBに持ってきます。

Vaultのコードは、リポジトリの`Code > Clone > SSH`より。

```shell
$ git clone git@github.com:your_name/your_repository.git
```

クローンができたら、適当なファイルを修正し、コミットできることを確かめます。

```shell
$ git add .
$ git commit -m "some comments"
$ git status
$ git pull
$ git push
```

警告が出るときは下記コマンドを打っておきます。

```shell
$ git config pull.rebase false
```

コマンドラインでpush/pullができるようになれば、あとはObsidianのインストールと設定です。

#### 2.マシンBにObsidianをインストールして設定します

Obsidianをインストールします。

:::note
詳細は省略します。
Linux Mintの場合は、Software Managerからインストールできました。
:::

初回起動時は、制限モードで起動します。起動後すぐに、`設定 > Obsidianについて > 設定フォルダの優先を切り替える`で、コピーしておいたフォルダ`.obsidian-linx`を入力します。

Obsidianを再起動します。

#### マシンBにプラグインをインストールして設定します

Obsidianの設定フォルダをうまくコピーできていれば、プラグインのインストールは不要です。

もしプラグインがなくなっていれば、コミュニティプラグインから`Obsidian Git`をインストールします。

主な設定は下記のとおりです。

![Screenshot_2022-12-02_09-48-53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/807043f0-1ea4-263a-3df0-e0f831cee073.png)

![Screenshot_2022-12-02_09-49-42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/609ad93d-da3a-bda8-d442-b6e75786cfa5.png)


## おわりに

やっぱりObsidianがあると安心です。同期されていて、あちこちのマシンでVaultに書けるようになったので、とてもとても安心になりました。

### 環境

ここで書いていることは、下記のバージョンで実施しました。

- マシンA 
    - Obsidian v1.0.3
    - macOS Monterey 12.6.1
    - MacBook Pro (14-inch, 2021)
- マシンB
    - Obsidian v1.0.3
    - Linuxmint 21 vanessa Xfce
    - iMac 5,1 (17-inch, Late 2006)
laravel モデルクラスのexists()を用いてレコードが存在するか確認する

:::note info
この記事は[miriwoお一人様 Advent Calendar 2022](https://qiita.com/advent-calendar/2022/miriwo)の2日目の記事です
:::

## 概要

- モデルクラスの`exist()`を用いてレコードが存在するか確認する方法をまとめる。

## 方法

- 下記の様に記載することでレコードが存在していればtrueを、存在していなければfalseを返す。

    ```php
    モデル::where('カラム名', 値)->exists();
    ```

- 例えばusersテーブルに紐づくモデルUserを用いてusers.idカラムが1のレコードが存在しているかを確認する場合下記の様に記載する。

    ```php
    use App\Models\User;

    User::where('id', 1)->exists();
    ```

- レコードが存在している時はtrueが帰り、存在していない時はfalseが変える。
- ちなみにおそらく、`where()`の代わりに`find()`を使うことはできないはず。（レコードがある時はtrueを返すが無い時は例外が投げられたはず、、！）

    ```php
    use App\Models\User;

    // こういう書き方はできないはず
    User::find(1)->exists();
    ```
teradatamlデータフレームをpandasデータフレームに変換する

[Teradata® Package for Python Function Reference](https://docs.teradata.com/r/Teradata-Package-for-Python-Function-Reference/April-2022) [リリース番号：17.10　リリース日付：2022/4]の翻訳です。

# はじめに
Pythonでteradatamlデータフレームをpandasデータフレームに変換する。
ライブラリとして[teradataml](https://pypi.org/project/teradataml/)を利用します。

:::note info
**teradataml**はTeradata Vantage用のPythonライブラリです。
:::

# 基本操作
## Vantageに接続する
```python:python code
# 接続用ライブラリの宣言
import teradataml as tdml
# データベース接続
tdml.create_context(host = "IPアドレス",username='ユーザ名',password='パスワード')
```

## テーブルを指定してデータを取得する
```python:python code
# Customerテーブルのデータをteradatamlデータフレームに読み込む
teradataml_iris = tdml.DataFrame.from_table("iris_table")
```

## pandasデータフレームに変換する
```python:python code
# Customerテーブルのデータをteradatamlデータフレームに読み込む
pandas_iris = teradataml_iris.to_pandas()

# 変数の型を確認する
type(pandas_iris)
```

<details><summary>結果を表示</summary>

```
pandas.core.frame.DataFrame
```
</details>

## Vantageから切断する
```python:python code
# データベース切断
tdml.remove_context()
```

# おわりに
:::note warn
警告
この本書は[Teradata Vantageドキュメンテーション](https://docs.teradata.com/)よりトピックに必要な情報を抜粋したものです。掲載内容の正確性・完全性・信頼性・最新性を保証するものではございません。正確な内容については、原本をご参照下さい。
また、修正が必要な箇所や、ご要望についてはコメントをよろしくお願いします。
:::

## Teradata Vantageへのお問合せ
[Teradata Vantage へのお問合せ](https://www.teradata.jp/About-Us/Contact)
Azure Load Testingで負荷テストをしてみよう

本記事は以下サイトにて記載しています。
恐れ入りますがリンクから移動してご参照ください。

Azure Load Testingで負荷テストをしてみよう
https://cloudsteady.jp/post/64941/
　
　
現在パーソルプロセス＆テクノロジーではAdvent Calendar 2022を開催中です。
https://qiita.com/advent-calendar/2022/ppt

こちらも興味ある記事あれば是非ご参照ください。
[Salesforce] Experience CloudのLWRでログアウト処理を実装する

### LWR以外でログアウトさせる
Experience Cloudでログアウトさせるには、`[/sitePrefix]/secur/logout.jsp`に遷移させます。
PageReferenceを使ったログアウトは下記になるのですが、Build Your Own (LWR) テンプレートではサポートされません[^1]。

```js
this[NavigationMixin.Navigate]({
    type: "comm__loginPage",
    attributes: {
        actionName: "logout"
    }
});
```

### basePathからログアウトURLを取得する
LWRではかわりにbasePathからURLを取得します。basePathは`/s`を含むので、取り除く必要があります。

```js
import { LightningElement, api } from "lwc";
import basePath from "@salesforce/community/basePath";

export default class Logout extends LightningElement {
    get logoutLink() {
        const sitePrefix = basePath.replace(/\/s$/i, "");
        return sitePrefix + "/secur/logout.jsp";
    }
}
```

```html
<a href={logoutLink}>Logout</a>
```

### javascriptの処理の中でログアウトさせる
上記の方法で`standard__webPage`のurlを指定してページ遷移させようとすると、`[/sitePrefix]/s`が余計についてしまうので正しいURLが指定できません。Navigateのかわりにfetch　apiを使うことでうまく遷移できます。

logoutUrlはgetLogoutUrlを使用することでも取得できます。

```js
import getLogoutUrl from '@salesforce/apex/applauncher.IdentityHeaderController.getLogoutUrl';
import getLoginUrl from '@salesforce/apex/system.Network.getLoginUrl';
```

fetch apiを使うことでJavaScriptでログアウトさせることができます。

```js
import getLogoutUrl from '@salesforce/apex/applauncher.IdentityHeaderController.getLogoutUrl';

export default class Logout extends LightningElement {
    async logout() {
        const logoutUrl = await getLogoutUrl();
        await fetch(logoutUrl);
        // 上記だけだとページ遷移しないので、ページ遷移する場合はここにページ遷移の処理を入れる
    }
}
```

### 参考
- [Create a Logout Link Component | LWR Sites for Experience Cloud | Salesforce Developers](https://developer.salesforce.com/docs/atlas.en-us.exp_cloud_lwr.meta/exp_cloud_lwr/advanced_custom_logout.htm?q=Logout)
- [lightning web components - How to logout from a Digital Experience (AKA Community) using LWC? - Salesforce Stack Exchange](https://salesforce.stackexchange.com/questions/378417/how-to-logout-from-a-digital-experience-aka-community-using-lwc)
- [Basic Navigation - Salesforce Lightning Component Library](https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.use_navigate_basic)
- [PageReference Types - Salesforce Lightning Component Library](https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.reference_page_reference_type)

[^1]:https://developer.salesforce.com/docs/atlas.en-us.exp_cloud_lwr.meta/exp_cloud_lwr/get_started_comp_navigation.htm
Google UXデザイン：ユーザビリティ・スタディの洞察に基づいてローファイデザインを修正する

# はじめに

わたしが[Google UX Design Certificateで得られた素晴らしい体験][google]を、特に重要だと思われるポイントを小さく分割して、わかりやすく簡潔に紹介していきます。

興味があれば、ぜひ Google UX Design Certificateを受講してみてください。

[google]: https://qiita.com/mapami/items/7a0d0a3d4661c50f8bec

https://www.coursera.org/professional-certificates/google-ux-design

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/66d514dc-1996-9cf3-5acb-014309ebb027.png" width="700">

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/5ac10c5d-be5a-43fb-a301-952ca024bf34.png" width="800">

<details><summary>これまでの振り返り</summary>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/d326d1e3-3b70-ffc3-eabf-1ac6a7fcaec7.jpeg" width="500">

</details>

# デザインを修正する

さて、[あなたはリサーチから得た洞察で満たされたプレゼンテーションやレポートを持っています][presen]。また、これらの洞察をステークホルダーと共有し、アクションを起こすべきものに合意が得られました。

[presen]: https://qiita.com/mapami/items/094247a04cdc602bb0ad

次のステップは、学んだことに基づいてデザインを改善することです。

ユーザビリティ・スタディを実施することで、参加者がさまざまなプロトタイプで経験するペインポイントを特定することができます。ペインポイントにより、デザインを修正し、ユーザーにとってより良い体験にする機会が得られます。そうすれば、最終製品を発売する前に問題を修正することができます。

では、どの洞察を利用してデザインを修正すればいいのか、どのように判断すればいいのでしょうか？

# 優先順位をつける

リサーチした洞察に、緊急性の高いものから低いものへと優先順位をつけるとよいでしょう。

この優先順位付けは、同僚のデザイナー、プロダクトマネージャー、エンジニアリングリードなど、プロジェクトの関係者と一緒に行います。


#### ***<font color="DarkSlateBlue">P0（優先度０）</font>***

これは、製品が機能するために修正する必要があることを意味します。


#### ***<font color="DarkSlateBlue">P１（優先度1）</font>***

これが達成しなくても機能をリリースできるが、あるとお客様に高い付加価値を与えることができることを意味します。

#### ***<font color="DarkSlateBlue">P2（優先度2）</font>***

P1よりも付加価値が低いものを意味します。

# ユーザビリティ・スタディの参加者の数

さて、リサーチ中に参加者が強調したペインポイントに優先順位をつけた後も、まだ疑問が残るかもしれません。

私たちの小規模なユーザビリティ調査から得られた知見は、5人の参加者からしか視点を得られなかったため、限定的であることを心に留めておいてください。

現実の世界では、多くの米国の研究者は、 ***<font color="MediumVioletRed">5人から8人の参加者</font>*** を得たいと考えています。研究によると、5人の参加者がいれば、価値あるフィードバックを生み出すのに十分なサンプル数を確保できることが分かっています。最近の研究では、参加者を8人に制限することが多いのですが、これは、参加者を追加すると、投資に対するリターンが減少することが多いという研究結果によるものです。

より多くのリサーチを行えるかどうかは、あなたのチーム、会社、プロジェクトのスケジュール、プロジェクトの予算によって異なります。

# さいごに

UXデザインは反復的なプロセス（イテレーション）で、ユーザーニーズの優先順位付けと主張がUXリサーチャーとデザイナーの責任になることが非常に多いのです。

リサーチから学んだプロトタイプを作成し、何度もデザインを反復します。そして、デザインにおいてしばしば考慮されない経験やニーズを持つユーザーグループに接触する努力をすることが重要です。
イーサリアム 2.0：PoS の新しいブロック生成流れを整理してみた

[The merge](https://ethereum.org/ja/upgrades/merge/) が実施できてから、 Ethereum のブロック生成アルゴリズムが  PoW から PoS に切り替えました。バリデーター・委員会・ブロック提案者など新しい言葉もあり、PoS の場合新しいブロックはどう生成されるかを整理してみました

情報元は下記 `Vitalik's Annotated Ethereum 2.0 Spec` です。リンク先は Phase 0 になっており、今現在は既にその後の Mergeフェーズになっていますが、概ねの流れが変わってない（と思う）ので、ご参考になれば幸いです。

[Vitalik's Annotated Ethereum 2.0 Spec](https://github.com/ethereum/annotated-spec/blob/master/phase0/beacon-chain.md)
![](https://camo.githubusercontent.com/c7eeea2d674e4e7d740fa2fe8a3f9327d5833892fd021ad38abcf2a89b8f5e8b/68747470733a2f2f692e696d6775722e636f6d2f466d574b4c30432e706e67)

## 前提知識

### Ethereum 2.0 は２つのチェーン

Ethereum 2.0 は、協業しながら実行する２つのチェーンによって構成されています。
- [ビーコンチェーン](https://ethereum.org/ja/upgrades/beacon-chain/) は、コンセンサスレイヤーとしてコンセンサスロジックとブロック[ゴシッププロトコル](https://ja.wikipedia.org/wiki/%E3%82%B4%E3%82%B7%E3%83%83%E3%83%97%E3%83%97%E3%83%AD%E3%83%88%E3%82%B3%E3%83%AB) を導入しています
    - ビーコンチェーンにはエポック（epoch）とスロット（slot）という概念があります。
        - Ethereum 1.0 のブロック生成は競争ゲームであるため、ブロック生成の時間は固定できなかったが、PoS の場合、競争でなくなったため、固定できるようになりました。この固定のブロック生成単位は、スロット（slot）とよばれ、12 秒になっています
        - 32 個のスロットを１つの区切りとして、エポック（epoch）と呼ばれています。エポック単位で、バリデーター周りの処理を実行しています
- [シャードチェーン](https://ethereum.org/ja/upgrades/sharding/) は、今までの Ethereum 1.0 のチェーンからコンセンサス処理を除いて、トランザクションを実行（スマートコントラクトの実行）しています
    - 現時点のシャードチェーンは Ethereum 1.0 のチェーンしかないですが、シャーディングの実装ができたら、他のシャードチェーンがどんどん増えて行きます

### バリデーターとは

Ethereum 2.0 PoS のコンセンサスへの参加者は、バリデーター (validator) と呼ばれています
- バリデーターになるには、32 ETH を保証金として預かっておく（入金）必要があります
- それからしばらくしてアクティブなバリデーターになり、新しいブロックを提案したり、投票したり、コンセンサスの処理を実行する必要があります

## ブロック生成の流れ

大まかの流れは下記になります

- アクティブなバリデーターからランダムでスロットごとの委員会を編成する
- 委員会が自分が担当するスロットになったら、ランダムでブロック提案者を選出する
    - ブロック提案者は、新しいブロックを提案してネットワークに公開する
    - 委員会の他のバリデーターは、新しいブロックが正しいかどうかを検証し投票する
    - 正しい投票が 2/3 を超えたら、そのブロックが確定される（厳密的には2回の投票が必要だが、別記事にする）

### ランダム値について
ブロックチェーン上のランダム処理は、ランダム性がありつつ、同じ入力値に対して何回実行してもどこで実行しても同じランダム値を返すような特性を期待しています。

Ethereum 2.0 のランダム値を取得する処理は、RANDAOという部品（？）に任せています。この辺の詳細もそれなりにボリュームあるので、また別記事にします。

### 詳細流れ

エポック 104 のスロットのブロック生成する流れを例として説明します。


- エポック 100 （ターゲットエポックの4 個前のエポック）の最後のスロットで
    - 4 エポック先（エポック 104）用のバリデーターセットを計算する
        - バリデーターのライフサイクルは、加入・退出周りのルールがあるため、4 エポック先のバリデーターは、この時点で確定できるため、計算できます。
- エポック 103 （ターゲットエポックの 1 個前のエポック）の最初のスロットで
    - このタイミングで、次のエポックで使うランダム処理の seed が確定されたので、ランダム処理の必要なデータが備えた
    - バリデーターセットから、次のエポック 104 の 32 個のスロットごとの、委員会とブロック提案者をランダムで編成する
        - 委員会を構成するバリデーターの数は、最小 128 で、最大 2048 と定義されています
        - つまり、バリデーターセットから、最大 `65536 個(= 32 スロット * 2048 スロットごとの最大メンバー数）` のバリデーターを選出して、32 グループに分けます
        - 現時点（2022年12月）では、[アクティブなバリデーターが 48 万前後](https://beaconcha.in/validators) になっています
        - エポックごとにブロック生成に参加できるのは、最大 65536 個しかないようですが、選出ロジックと、4 個前のエポック 100 のタイミングで既に抽出したのかどうかについては、まだ把握できていません
- エポック 104 のスロットで
    - ブロック提案者は、新しいブロックを提案しネットワークに公開する
    - 委員会のメンバーは、公開された新しいブロックを検証し、それを次のブロックにすることに賛成かどうかを投票しその投票もネットワークに公開する
    - 投票が委員会の 2/3 を超えたら、新しいブロックが確定されるとみなす
        - ブロック提案者が新しいブロック提案しなかったり、投票が 2/3 に至ってなかったりする場合もあるので、その場合、そのスロットが空になります
    - 次のスロットになると、そのスロットの委員会とブロック提案者は同じ処理を行う

## まとめ
図で整理してみたかったんですが、結局リンク先の資料画像と似ているので、そのまま使いました。
PoW の処理と比べて、PoS の処理はだいぶ複雑になった印象がありますね。
Yellowfin レポートから特定チャートを選択して HTML 画面に埋め込み

## はじめに
[Yellowfin](https://yellowfin.co.jp/) のレポートには、複数のチャートが含まれることが良くあります。1 つのテーブルから複数のチャートを作成する運用は極めて一般的です。ただ、この中から特定のチャートを選択して、HTML やポータルの画面に埋め込むにはどのようにしたら良いでしょう。外部向けの情報からだけでは、恐らくその実装方法が理解しきれないと思います。
本記事の中で、その具体的な手順を紹介します。

## レポートやチャートを特定する UUID の取得
Yellowfin では、レポートやダッシュボードなどに対して、UUID と呼ばれる内部 ID が付与されており、この UUID を使って、ダッシュボード、ストーリ、レポート、チャートなどを一意にを特定します。
今回必要なのは、レポートとチャートの UUID なので、リポジトリ DB から publishuuid と chartuuid を検索します。

レポート名とチャートのカスタムタイトルが特定できる場合は、以下の SQL を実行することで必要な情報を取得できます。

```sql:UUID を確認するためのクエリー
select chart.reportid, reportheader.reportname, chart.chartuuid, reportheader.publishuuid, reportformat.description
from public.chart, public.reportheader, public.reportformat
where chart.reportid = reportheader.reportid
and chart.chartid = reportformat.chartid
and reportheader.reportname = 'embedding'
and (reportformat.description = '円グラフ' or reportformat.description = '棒グラフ')
```

レポートに複数チャートを含む場合、下記のように 2 件以上のレコードが検索されてきます。この中から、publishuuid と chartuuid を控えておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/47b883f4-7bf0-55a1-b7e6-c65dca429b42.png)

なお、上記 SQL で指定したレポート名とチャートのカスタムタイトルは、それぞれ以下の個所で設定する文字列です。
レポート名：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/82b24e5d-708d-c04c-e226-a447e76e783e.png)

カスタムタイトル（[グラフ] > [タイトル] > [テキスト] > [カスタムタイトル]）：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/8836f6a3-1d4d-0ade-88ea-791f6a2bc65a.png)

## 埋め込み HTML 画面の作成
先の手順で取得した publishuuid と chartuuid を下記サンプルコードの ReportUUID と ChartUUID 変数に取り込みます。今回はチャート単位で埋め込みをするため、displayType: 'CHART' と指定します。

```html:Embedding
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>埋め込み例</title>
</head>
<body> 
<p>選択したチャートの埋め込み</p>
<script src='http://localhost:8080/JsAPI/v3'/></script>
<div id="reportDiv"></div>
<script>
let ReportUUID = '00bbaecd-8a87-4079-ba93-0d9b4b84cf1a';
let ChartUUID = 'c69ffebf-93da-4c69-a43c-d8addf3b5dae';
yellowfin.loadReport({
	reportId: ReportUUID
}).then(report => {
	report.createReportElement({
		element: document.querySelector('div#reportDiv'),
		displayType: 'CHART',
		chartUUID: ChartUUID,
		showToolbar:false,
		height:450,
		width: 600,
    });
});
</script>
</body>
</html>
```

指定したチャートが埋め込まれました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/cf5d29bb-3342-ee9a-2392-55d2d9fd2009.png)

height:250, width: 300 と指定し直すと、サイズの変更も可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/f6ade4ef-5495-34cd-0cbc-17b1352b01bc.png)

chartuuid と指定し直すと、別のチャートに切り替えることもできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/5ca2b7ad-f3c9-c2e1-8a32-f685ef921c96.png)

## 最後に
[Yellowfin Wiki レポート API]( https://wiki.yellowfin.co.jp/pages/viewpage.action?pageId=6591579#id-%E3%83%AC%E3%83%9D%E3%83%BC%E3%83%88API-%E3%83%87%E3%83%95%E3%82%A9%E3%83%AB%E3%83%88ChartID%E3%81%8A%E3%82%88%E3%81%B3ChartID) の記事に類似の説明が見つかります。ただ、この内容だけで実装に至るには少々手間を要しますよね。
技術者の皆さんの実装を効率化する目的も含め、今後は Wiki などの技術情報を補完する投稿も増やしていきたいと思います。

では皆様、良いデータ分析を! See you then! Santé! Cheers!!
ポート番号とデーモン

- ポート番号
    - IPアドレスが分かっていてもポート番号がないと、どのプログラムでデータを取り扱えばいいかわからない
        - 例えば、サーバーAに接続する際、IPアドレスはわかっているのでサーバーA自体には接続できる。ただ、サーバーA内のどのプログラムで処理してほしいのか（Webサーバ、メールサーバなど）がわからない
    - なのでポート番号が必要

- デーモン（daemon）について
    - なんでURLで「httpd」と表記しない？
        - httpdは、デーモンを指す言葉だから
        - httpはプロトコルなので、URLに通信方式が記載されている
        - httpdは、Webサーバー上で動いている常駐プログラム（デーモン）のことだからURLに「httpd」と表記しない

- Listen（リッスン）
    - 応答可能な状態を指す
    - Listenしている
        - IPアドレス＋ポート番号で接続可能
BigQueryのカラム名に予約語を使う方法

以下のSQLはSyntax Errorになり実行できません。
カラム名にselectという予約語を使っているためです。

```sql
create table `<テーブル名>` (
  select int64,
  insert int64, 
  update int64,
  delete int64,
);
```

しかし、止むに止まれぬ事情でカラム名に予約語を使う必要が出た場合はどうすればよいでしょうか？

# 答え
カラム名をバッククォートで囲む。

```sql
create table `<テーブル名>` (
  `select` int64,
  `insert` int64,
  `update` int64,
  `delete` int64,
);
```

バッククォートで囲むことで予約語ではなくカラム名として認識されるようです。

![スクリーンショット 2022-12-02 8.46.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74551/b415b3bc-cf83-cd0c-039f-f50f9438b9ac.png)

なお、このテーブルを参照するときにもカラム名をバッククォートで囲む必要があります。

```sql
select `select`, `insert`, `update`, `delete` from `<テーブル名>`
```