OmniAICreator/Qiita-1.07M huggingface dataset:
Mariadb／カラムのコメントは変更時に注意が必要です

## はじめに
MariaDBでカラムのコメントの使いづらさに気が付いた・・という話です。
環境は、WSL2:UbuntuのMariaDB10.9です。
HeidiSQLでテーブル・カラムの日本語名称を確認したいよねという話がきっかけで、コメントで管理しようと考えてやってみたところ、カラムの日本語名称変更＝コメントの変更で、ちょっとした問題に気づきました。
その顛末を順を追って書いてみようと思います。
## Create Table時はなんら問題ない
カラムのコメントが問題になるのは、変更の時だけです。
例えば、Create時にはこんな感じでコメントとして定義できますが、別に問題はありません。
```
CREATE TABLE `test` (
	`id` INT(11) NOT NULL AUTO_INCREMENT,
	`col1` VARCHAR(50) NULL DEFAULT 'テスト' COMMENT 'カラム日本語名称' COLLATE 'utf8mb4_unicode_ci',
	PRIMARY KEY (`id`) USING BTREE
)
COLLATE='utf8mb4_general_ci'
ENGINE=INNODB
COMMENT='テーブル日本語名称'
;
```
create tableでテーブルやカラムの日本語名称をコメントで設定するのは、ともに「COMMENT」を使って定義すればよいだけですからね。
以後、このテーブル・カラムを例に使います。
## Alter Tableでテーブルコメント変更も問題ありません
テーブルの日本語名称の変更も同様です。
```
ALTER TABLE `test` COMMENT = '変更後日本語名称';
```
安全にテーブルコメントだけ変更できます。
## カラムのコメント変更は要注意
さて、カラムのコメントです。
まず、何が問題なのかの実例をやってみます。
上記んも変更前の状態をまず確認します。
```
show full columns from test;
```
表示される内容は以下です。(余分なカラムは記載してません）
```
"Field"	"Type"	"Collation"	"Null"	"Key"	"Default"	"Extra"	"Privileges"	"Comment"
"col1"	"varchar(50)"	"utf8mb4_unicode_ci"	"YES"	""	"テスト"	""	"select,insert,update,references"	"カラム日本語名称"
```
ここでカラムのコメントを変更してみます。
どうもカラムの場合、テーブルのように「コメント」だけを変更する構文は用意されていないようなので、最低限の記述で以下のようになります。
```
ALTER TABLE test CHANGE COLUMN col1 col1 VARCHAR(50) NULL COMMENT '変更後カラム名称';
```
これで実行後に同じコマンドで情報を出力します。
```
"Field"	"Type"	"Collation"	"Null"	"Key"	"Default"	"Extra"	"Privileges"	"Comment"
"col1"	"varchar(50)"	"utf8mb4_general_ci"	"YES"	""	\N	""	"select,insert,update,references"	"変更後カラム名称"
```
わかりづらいとは思いますが、コメントの修正をしたことで「Default」の列に指定されていた「テスト」が消えて「\N」になっています。
なんと・・Alter文で指定していない箇所が意図せず消えてしまっています。
もちろん。
```
ALTER TABLE test CHANGE COLUMN col1 col1 VARCHAR(50) NULL DEFAULT 'テスト' COMMENT '変更後カラム名称';
```
のように、DEFAULTも指定して実行すれば大丈夫です。
でも、もれていたとしてもエラーにならず、サクッと消されてしまうので、意図せず「Default」に指定されていた値がクリアされているのに誰も気づかない・・なんててことが起こりえるわけです。
本番運用している環境だと、これはとても危険です。
万が一にも、カラムのコメント修正が原因でトラブルなどを発生させたら、お客からも会社からも糞みそに言われるのは間違いないですしね（笑）。
## まとめ
上記が僕が気づいた「MariaDBでカラムのコメントの使いづらさ」です。
とりあえず、メリットよりもデメリット（リスク）が大きいので、カラムに初期セットした日本語名称は変更禁止で、新たな整備計画は白紙になりました。
これ・・あとで気づくと、じんわりダメージきついです。
ではでは。
ポインタ変数に対するメソッド呼び出し時のnullチェック共通化をChatGPTに教えてもらった

## 概要

やりたいこと：
C++ で, ポインタ変数で持っているインスタンスに対してメソッドを呼び出したい. 当然nullチェックが必要だが, メソッドがたくさんあるときに毎回チェックを書くのはだるい. 

やったこと：
自分なりにいろいろとぐぐってみたがいまいちこれという解にたどり着けなくて, ためしに最近流行りのChatGPTさんに聞いてみたらほぼ期待通りの結果が得られてすごかった, という記録.

## TL;DR

これが欲しかった関数.

```c++:tldr.cpp
#include <functional>

// ヘルパー関数定義
void callMethodIfValid(SomeClass* ptr, std::function<void(SomeClass*)> func) {
  if (ptr != nullptr) {
    func(ptr);
  }
}

// 呼び出し例. ラムダ式で呼び出したい処理を渡す.
SomeClass* ptr;
callMethodIfValid(ptr, [](SomeClass* p) {
  p->method1();
});
```


## ChatGPT との Q＆A
以下, 引用文はChatGPTへのクエリ, コードブロックはChatGPTからの返答である(コードに付随する説明文はばっさりと省略).

### Q1. Nullチェックの基本処理
> C++で, あるクラスのポインタ変数がnullptrならば無視し, 有効ならばメソッドを呼ぶ, という処理はどのように書けますか？

### A1.
```c++:answer1.cpp
if (ptr != nullptr) {
  ptr->method();
}
```

Nullチェックの基本.

### Q2. Nullチェックを共通化したい
> ptrにメソッドが大量に生えており, 確認のif文を大量にコピーしなければならないとすると, 重複を避けるうまい方法はありますか？

### A2.
```c++:answer2.cpp
void callMethodIfValid(SomeClass* ptr) {
  if (ptr != nullptr) {
    ptr->method();
  }
}
```

雰囲気はそれっぽいが, `method()`が埋め込みなので意図とは異なる.

### Q3. メソッド名を変数にしたい
> 呼びたいmethod()をcallMethodIfValid の外から指定したい場合, どのように書けばよいですか

### A3.
```c++:answer3.cpp
#include <functional>

void callMethodIfValid(SomeClass* ptr, std::function<void(SomeClass*)> func) {
  if (ptr != nullptr) {
    func(ptr);
  }
}
```

なるほど？

```c++:sample3.cpp
SomeClass* ptr = getPointer(); // ptrは、あるクラスのポインタ変数

callMethodIfValid(ptr, [](SomeClass* p) {
  p->method1();
});

callMethodIfValid(ptr, [](SomeClass* p) {
  p->method2();
});
```

これだあああすごいいい

## 応用など

教えてもらったコードを参考に, 外から変数をキャプチャしたり`auto`で型名を省略したり.

```c++:custom.cpp
int param;

callMethodIfValid(ptr, [param](auto* p) {
  p->method1(param);
});
```

コード例は省略するが, メソッド呼び出しに成功したかどうかの`bool`値を返すように変更するのも簡単.
`ptr`をメンバに持つクラスを作ってそこに生やすのも良さそう.
あと今回自分の用途だと不要だったけど, メソッドの戻り値が欲しい場合はtemplate化して`optional`で受ければ良さそう.

```c++:use_return.cpp
#include <optional>

template <typename T>
std::optional<T> callMethodIfValid(SomeClass* ptr, std::function<T(SomeClass*)> func) {
    if (ptr != nullptr) {
      return func(ptr);
    } else {
      return std::nullopt;
    }
};
```

…こうなってくると結局外で`has_value`とかが必要になってきちゃいそうだけど, でもメソッド呼び出しとは別のタイミングでチェックできると嬉しいケースもあるかもしれない(適当).

ChatGPTでは同一セッション中に前に出てきたワードを用いて対話ができるので, 意図とちょっと違う結果が返ってきても粘って話を続けると色々得られてすごい. 今後も活用していきたい.

## リンク

* ChatGPT : https://chat.openai.com/chat
* ラムダ式 https://cpprefjp.github.io/lang/cpp11/lambda_expressions.html
* std::optional https://cpprefjp.github.io/reference/optional/optional.html
clip-pathを使ってみる

[ひとりCSS Advent Calendar 2022](https://qiita.com/advent-calendar/2022/css-becolomochi) 21日目です。

clip-path を使ってみます。

## clip-path とは

https://developer.mozilla.org/ja/docs/Web/CSS/clip-path

シェイプが作れる。

## よく使う三角

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41088/9574f43c-6f9c-843b-01df-d20665edad7a.png)


```html
<div class="info-box">目立たせたいボックス</div>
```

```css
.info-box {
  background: #fff;
  padding: 2em;
  position: relative;
}

.info-box::after {
  position: absolute;
  top: 0;
  right: 0;
  display: block;
  content: "";
  width: 32px;
  height: 32px;
  background: var(--color1);
  clip-path: polygon(0% 0%, 100% 0%, 100% 100%);
}
```

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

border-left border-top で実装していたやつも簡単に書き換えられる。良い


## 窓みたいなかたち

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41088/7906e27e-9e8b-2b64-30c8-52ee09815d1e.png)

```css
.img-box {
  width: 150px;
  height: 180px;
  background: url(https://0.gravatar.com/avatar/3c635ac67557f954b04d37a24254f436?size=360) no-repeat;
  background-size: cover;
  background-position: center;
  clip-path: path('M 0 200 L 0,75 A 5,5 0,0,1 150,75 L 200 200 z');
}
```

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

パス指定さえすれば自在に作れるの楽しい。

## 参考

- https://developer.mozilla.org/ja/docs/Web/CSS/clip-path
luajitでボックスブラー

　
この記事は[アドカレ](https://qiita.com/advent-calendar/2022/lua)に参加しています。

# luajitでボックスブラー
luajitでボックスブラーをやっていきます。
とはいえ、luajitもスクリプト言語。速度はあまり期待できないです。

## ボックスブラーとは
ボックスブラーとはその名の通りボックス(箱)の形でぼかしていく画像処理です。任意ピクセルとその周囲の平均から色を求めていきます。

## アルゴリズム
先人の方達が素晴らしいアルゴリズムを共有してくださっています。
今回はそれをそのまま使います。
[言語不問で実装する高速な移動平均処理](https://qiita.com/carnage/items/2dde28f0344b455aa62c)
[フィルタ処理の高速化アルゴリズム（縦横に処理を分ける）](https://imagingsolution.blog.fc2.com/blog-entry-156.html)
[gaussian フィルタ](https://wgld.org/d/webgl/w057.html)
　
要点は二つあります。
1.二次元的な処理を一次元的な処理(縦と横の二回)に分ける。
2.移動平均処理で、計算回数を減らす。

## コード
.anmとして使用できます。
```lua
--[[

blur.anm
	ボックスブラーです。

]]

--track0:size,1,1000,100,1

local ffi=require"ffi"

pcall(ffi.cdef,[[
    typedef struct Pixel_ {
      uint8_t b,g,r,a;
    } Pixel;
  ]])

local work,data,w,h=obj.getpixeldata"work",obj.getpixeldata()
local c=ffi.cast("Pixel*",data)
local r=ffi.cast("Pixel*",work)
local function f(a)
 if(a<0)then return 0
 elseif(a>255)then return 255
 else return math.floor(a)
 end
end

local ha=obj.track0--正の整数
local ha2=ha*2

--横方向にぼかしていく
for y=0,h-1 do
 local to,ix={0,0,0,0},y*w
 for i=0,ha-1 do
   to[1]=to[1]+c[ix+i].r
   to[2]=to[2]+c[ix+i].g
   to[3]=to[3]+c[ix+i].b
   to[4]=to[4]+c[ix+i].a
 end
 for x=0,w-1 do
  if(x<w-ha)then
   to[1]=to[1]+c[ix+ha].r
   to[2]=to[2]+c[ix+ha].g
   to[3]=to[3]+c[ix+ha].b
   to[4]=to[4]+c[ix+ha].a
  end
  if(x>=ha)then
   to[1]=to[1]-c[ix-ha].r
   to[2]=to[2]-c[ix-ha].g
   to[3]=to[3]-c[ix-ha].b
   to[4]=to[4]-c[ix-ha].a
  end
  r[ix].r=f(to[1]/ha2)
  r[ix].g=f(to[2]/ha2)
  r[ix].b=f(to[3]/ha2)
  r[ix].a=f(to[4]/ha2)
  ix=ix+1
 end
end

--縦方向にぼかしていく
local haw=ha*w
for x=0,w-1 do
 local to,ix={0,0,0,0},x
 for i=0,ha-1 do
   to[1]=to[1]+r[ix+i*w].r
   to[2]=to[2]+r[ix+i*w].g
   to[3]=to[3]+r[ix+i*w].b
   to[4]=to[4]+r[ix+i*w].a
 end
 for y=0,h-1 do
  if(y<h-ha)then
   to[1]=to[1]+r[ix+haw].r
   to[2]=to[2]+r[ix+haw].g
   to[3]=to[3]+r[ix+haw].b
   to[4]=to[4]+r[ix+haw].a
  end
  if(y>=ha)then
   to[1]=to[1]-r[ix-haw].r
   to[2]=to[2]-r[ix-haw].g
   to[3]=to[3]-r[ix-haw].b
   to[4]=to[4]-r[ix-haw].a
  end
  c[ix].r=f(to[1]/ha2)
  c[ix].g=f(to[2]/ha2)
  c[ix].b=f(to[3]/ha2)
  c[ix].a=f(to[4]/ha2)
  ix=ix+w
 end
end


obj.putpixeldata(data)


```

## おわりに
luajitでボックスブラーをやりました。
実際に使用してみると分かりますが、とても重いです。実用性を考慮するならば素直にdllでマルチスレッドとかsimdとかしたほうがいいです。
ところで、gpuで高速化できるとか聞いたのですが、本当なんですかね…?
最近オンボの限界を感じます。
効率的にツイッターから求人を探すサービスを開発

# はじめに

本記事は [個人開発 Advent Calendar 2022](https://qiita.com/advent-calendar/2022/individual-developers) カレンダー2 の 23 日目の記事です。
本記事では [Twitter API](https://developer.twitter.com/en/docs/twitter-api) を使ってwebサービスをリリースした経緯や技術スタックなどをまとめています。

# 出来上がったもの
集中してTwitterで仕事探しができる検索サービスを作りました

 [ツイジョブサーチ（https://twijob.spotstudy.net/)](https://twijob.spotstudy.net/) 
　※ブラウザによってSSLのエラーが表示するかもしれません

![ツイジョブサーチ](https://twijob.spotstudy.net/img/twitter_ogp.png)

![ツイジョブサーチ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32122/5f76b951-69a8-2bd9-72eb-4de6479d0713.png)



# 背景
フリーランスで案件を探す手段にSNSを活用するかたは多いです。
SNSで案件を探すとなると、facebookやTwitterを思い浮かべるのではないでしょうか。

Twitterでいい感じの案件はないかなーと検索したもの

* Twitter広告が頻繁に表示する
* フォロワーのツイートを読んでしまう
* 知らないアカウントのツイートを読んでしまう
* サイドバーの「いまどうしてる？」欄が気になって読んでしまう

こんな感じで **集中して案件を探すことができない** のです。

求人を検索するくらい、さくっと終わらせて、スマートに別の作業に集中したい。
という経緯で作りました。

・・・・ここまでが建前で、本音は **GoとReactのプロダクトを作りたかった！**。

that's it.

# 技術スタック

使っている技術はシンプル。

|フロントエンド|React|
|:---|:---|
|バックエンド|Go|
|サーバ|AWS（EC2）、ロリポップ|
|DB|なし|
|API|[Twitter API](https://developer.twitter.com/en/docs/twitter-api) |

フロントで検索を実行するとバックエンドへ要求して、バックエンドで[Search Tweet](https://developer.twitter.com/en/docs/twitter-api/v1/tweets/search/api-reference/get-search-tweets)のAPIを実行します。そして、Twitterからの応答をフロントに返して画面に表示しています。

that's it.

# 工夫した点
普通にTwitterにツイートされている求人情報を取得すると、怪しいバイトも検索します。
怪しいバイトは極力排除するように、検索オプションに「打ち子」「即日報酬払い」「闇仕事」「裏仕事」などを含むツイートは検索結果に含まないようにしました。

# 終わりに
技術スタックもシンプルで、TwitterAPIもn番煎じですが
GoとReactのプロダクトを作った＋日頃の不満がちょっと解消した という点で満足です。

これぞ個人開発の醍醐味・・！？
【Playdate】ゲーム一覧画面でのランチャーカードをデザイン

![sample_221220.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100912/63779261-dea5-5dc3-7bca-1f985d65ebca.gif)

Playdateのゲーム一覧画面で表示されるランチャーカードと呼ばれるものですが、静止画カードだけでなく、アニメーションや選択時、起動中の表示・効果音なども設定することができます。
設定すべきものはゲームのメタ情報を管理する`pdxinfo`とディレクトリ構成となります。
まずメタ情報`pdxinfo`の設定から解説していきます。

```pdxinfo
name=myProjectName
author=sadakitchen
description=This is description
bundleID=com.sadakitchen.myProjectName
version=1.0
imagePath=meta/Assets
launchSoundPath=meta/Sounds/launch
```
`imagePath`がランチャーカードの画像ファイルの格納ディレクトリの基点です。
`launchSoundPath`は起動時に再生したいwavファイルの場所指定となります。wavファイルはplaydate用にコンバートされたものである必要があります。
コンバート方法はターミナルなどから`ffmpeg`を使用します。ターミナルで該当のディレクトリに移動してからコマンドを実行する流れとなります。
```
$ cd [変換したいファイルのあるディレクトリ]
$ ffmpeg -i [変換したいファイル名].mp3  -acodec adpcm_ima_wav [変換後のファイル名].wav
```
例では`mp3`を変換していますが、`wav`などでも可能です。

プロジェクト構造については以下のようになります。

```
myProjectName/
    source/
        main.lua
        Images/
            playerImage.png
            background.png
        meta/
            Assets/
                card.png  ← ランチャーカード
                card-highlighted/  ← 選択状態の連番アニメーション画像を格納
                    1.png
                    2.png
                    ...
                    animation.txt  ← アニメーションの再生制御
                card-pressed.png  ← 決定時表示する画像
                launchImages/  ← 読込中表示する画像
                    1.png
                    2.png
                    ...
            Sounds/
                launch.wav  ← 起動音
```

`meta/Assets`にランチャーカードの各種画像ファイルを設置することになります。

- `card.png`：ゲームの静止画ランチャーカード画像。一覧で表示される画像です。
- `card-highlighted/`：ゲーム一覧画面で選択したときにアニメーション再生される連番画像を入れます。
    - `animation.txt`：連番アニメーションの設定するファイルです。(後述)
- `card-pressed.png`：ゲーム一覧画面でAボタンをおして決定したときに表示される画像です。
- `launchImages/`：ゲームの起動読込中にアニメーション表示される連番画像を入れます。ちなみに単一の`launchImage.png`にすると静止画となります。

`animation.txt`の記述については以下のように記述します。

```animation.txt
frames = 6x4, 7x4, 8x4, 9x4
introFrames = 1x4, 2x4, 3x4, 4x4, 5x4
```
`frames`はループさせたい連番画像を指定します。`x#`(#は数値)を連番の末尾につけると数値分のフレームを待機表示するようになります。
`introFrames`はルーム前に1回だけ再生される連番画像を指定します。こちらも`frame`同様`x#`で数値分のフレームを待機表示できます。
プログラミング初学者がPHPを勉強する（foreach文編）

# 自己紹介
・製造業（全くパソコン触ったことない）からエンジニア転職を目指して学習しています。
・プログラミング初心者です。
・学習したことをメモ程度に書いていこうと思います！
# 何について？
今回はforeach文について記載していきます！

# •foreach文とは
配列の時に使えるループ処理で、配列の要素分ループ処理をしてくれる。
### while文やfor文との違い
・ループ処理の終了条件を書かなくても良い！
  (要素分しかループしないから。)
・添字が数字じゃない連想配列もループ処理できる。
  (配列に入ってる要素の順番に展開してくれるから。)

# •foreach文の使い方
```
foreach ( <配列の変数> as <各要素が格納される変数> ) {
ループ処理をここへ記述
}
```
これはインデックス配列のときなどに使うのでイメージしやすいから使いやすい！

```
foreach (<配列の変数> as <各要素のキーが格納される変数> => <各要素が格納される変数> ) {
ループ処理をここへ記述
}
```

連想配列の時に使う。キーの序列に数字的な規則性がなくイメージはしにくいが、慣れると便利に使える。
Vueで作成したプロジェクトをAWS Amplifyを用いて爆速でホスティングする

## 概要

Vueで作成したプロジェクトをAWS Amplifyを用いて爆速でホスティングする

## 手順

### vueのビルド

まずは作成したVueのプロジェクトファイルを静的ファイルにビルドします。

```
npm run build
```

上記のコマンドを実行すると、プロジェクト内に「/dist」というフォルダができてそこに静的ファイルとして出力されます。
ホスティングする際はこちらのファイルを使います。

### AWS Amplifyでホスティング

AWSのコンソール画面に入り、Amplifyのページに遷移します。
そして、真ん中にある「使用を開始する」を選択
![スクリーンショット 2022-12-20 21.09.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83409/cbb4a142-660c-1596-62a1-d9cb43de86b9.png)
その後、右側のAplifyホスティングの方の「使用を開始する」を選択
![スクリーンショット 2022-12-20 21.09.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83409/2c843473-2c9c-252c-9081-da463c7f1af8.png)

開始方法として選択肢が出てくるので好きなものを選びます。
今回自分は手元のコードをアップロードしたいので「Gitプロバイダーなしでデプロイ」を選択しました。

![スクリーンショット 2022-12-20 20.55.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83409/508fa937-1efb-eae8-255e-e2d1e478d3e8.png)

名前と環境名を入力し、先程作成した「/dist」フォルダをドラックアンドドロップします。
![スクリーンショット 2022-12-20 20.57.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83409/813b3b2b-9726-6f03-78d7-bc1edf538576.png)

最後に「保存してデプロイ」を選択して、画面に出てくるURLを踏むと

![スクリーンショット 2022-12-20 21.13.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83409/ba489b84-4643-b69f-b0fc-afbe6a4b0c25.png)
こんな感じで手元のVueプロジェクトがホスティングできます！
早い...

細かい設定とかしたい場合はS3のほうがいいケースもあると思うのですが、特に制約など設けないのであればこの方法が早そうな気がしました！
DBにreferences型のカラムが追加できない

## 起きた問題
マイグレーションファイルに`refereces型`のカラムを追加したかったが、マイグレーションできなかった。



### 試したこと
全てロールバックした後、DBを削除し作り直し、マイグレーション。←ダメ
試しに`referenes型`のカラムだけマイグレーションファイルから消してマイグレーション。　←できる

## 解決方法
参照先：[箱のプログラミング日記。](https://www.y-hakopro.com/entry/2019/06/29/103112)様
ありがとうございます:bow_tone3:

`rails g migration Addカラム名Toテーブル名 追加したいカラム名：カラム型`でマイグレーションファイルを生成。

中身を以下の内容に書き換え。

```ruby
class AdduserToPrototypes < ActiveRecord::Migration[6.0]
  def change
    change_table :Prototypes do |t|
      t.references :user, foreign_key: true, presence: true
    end
  end
end
```
これでマイグレーションできました。
Stable diffusion などの ML 計算代行の価格付けメモ

https://openai.com/api/pricing/

1k x 1k で 3 円くらい.

https://replicate.com/pricing

こちらは時間で課金(昔のインターネットプロバイダみたいな感じね)
T4 で $0.033 / min. 

https://stablediffusionapi.com/#pricing

$9 で 1499 枚まで(T4 GPU). 0.8 円/枚(解像度不明)

https://www.currypurin.com/entry/2022/09/30/093810

Google Colab で T4 利用だと 1 時間 20 円くらい. 1k x 1k 生成に 30 秒かかると想定すると, 素の HW コスト(原価相当?)としては 1 枚 0.16 円. 

API や従量課金だとその原価相当の 10 ~ 20 倍くらいなので, 最低限 10 倍くらいの費用(を請求できる)という感じかしらね.

(Stable diffusion みたいに input/output がそんなに通信量多くない場合, インターネット回線料金はあまり気にはならないと思われる)


https://www.nvidia.com/en-us/data-center/tesla-t4/

T4 自体は 70W なので電気代 30 円/kWh とするとランニングコストは 2.1 円/時間. 
T4 のように二世代前で減価償却おわったような GPU の場合, 大体電気代と同じくらいなので, 電気代の 10 倍というところが妥当なところでしょうか. 

### 高速化, 高画質化など付加価値

Google Colab A100 が T4 の 5~7 倍くらいのコストなので, 高画質化(e.g. 2k x 2k)とか高速化(Distilled Stable diffusion でリアルタイム生成とか!), DreamBooth のように Personalization, 画像の管理/保存機能つけるなどとなるとさらに 5~10 倍の価値(電気代の 50~100 倍)はつけてもいいかもしれません.


### 違法コンテンツ, 著作権侵害対策

arweave あたりに NFT として保管する機能あるとよいじゃろか?
1K x 1K で PNG 圧縮でロスレス 3MB くらいとして現時点(2022/12/17)では 2 円くらい.

https://ardrive.io/pricing/
色相的なキューブを作る

　
この記事は[アドカレ](https://qiita.com/advent-calendar/2022/lua)に参加しています。

# 色相的なキューブを作る
以下のようなやつを作ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3005402/0b9041cc-2a57-70cd-4d5f-a94f7ff2cfda.png)

## 色相とは…………？？
色相とは、色合いを数値化したものです。
具体的な計算方法は[この記事](https://imagingsolution.net/imaging/hue-saturation-brightness-calc/)が分かり易いです。

## 考え方
二次元空間を空想したときに、三つのベクトルを考えます。
```math
\vec{r}=
\begin{pmatrix}
0 \\
1 
\end{pmatrix}\\

\vec{g}=
\begin{pmatrix}
 \frac{\sqrt{3}}{2} \\
-\frac{1}{2} 
\end{pmatrix}\\

\vec{b}=
\begin{pmatrix}
-\frac{\sqrt{3}}{2} \\
-\frac{1}{2} 
\end{pmatrix}
```
　
図にするととても分かり易いです。三つのベクトルが120度ずつ離れており、それぞれが単位ベクトルであることが分かると思います。
　
さて、これらのベクトルに対して色の輝度値であるRGBの値を掛け算して、足していきます。最終的なベクトルを(x,y)とします。
```math
\begin{pmatrix}
x \\
y
\end{pmatrix}=

R \; \vec{r} \; + G  \; \vec{g} \; + B \; \vec{b}
```
```math
\begin{pmatrix}
x \\
y
\end{pmatrix}=

R 

\begin{pmatrix}
0 \\
1 
\end{pmatrix} \; 

+G  

\begin{pmatrix}
 \frac{\sqrt{3}}{2} \\
-\frac{1}{2} 
\end{pmatrix} \; 

+B 

\begin{pmatrix}
-\frac{\sqrt{3}}{2} \\
-\frac{1}{2} 
\end{pmatrix}
```
　
ここで、
```math
θ=arctan(\;y\;/\;x\;)
```
とすることで色相を求めることができます。(今回はここまでやりませんが)

## コード
色相の考えを使って描画するコードを以下に示します。
```lua
<?
local m=math.floor

local ha=10--ここの値の三乗の数だけ描画(20ぐらいがおすすめ)
local sa=255/ha
sa=m(sa*100)*0.01

local ru=math.sqrt(3)*0.5
ru=m(ru*100)*0.01
obj.load("figure","六角形",0xffffff,10)
obj.effect("カメラ制御オプション","カメラの方を向く",1)

for r=0,ha do
 for g=0,ha do
  for b=0,ha do
   local R,G,B=m(r*sa),m(g*sa),m(b*sa)
   local x,y,z
   x=(G-B)*ru
   y=R-0.5*(G+B)
   z=(R+G+B)*2/3--ここはRGBの平均
   obj.effect("単色化","color",RGB(R,G,B),"輝度を保持する",0)
   obj.draw(x,y,z)
  end
 end
end
?>
```

## おわりに
今回はHSVとかRGBとか呼ばれる色空間でしたが、色空間には他にも[おもしろい](https://bottosson.github.io/posts/oklab/)ものがあるので楽しいですね。
CRC(OpenShift Local)でOpenShift Data Foundationを使う

環境：RHEL8 workstation

何がしたいのかというと、ODFが前提のアプリケーションが増えてきているので、その検証作業のためです（他にもハードルがあり道半ばですが、、）

CRCでODFの機能を使うためには、ODF nanoを使います。
https://github.com/ksingh7/odf-nano

本家のODFは３ノード必要とかなので、それがワークステーションにサクッと入るならかなり手軽、これだけで済む用途ならば。

ODF nanoはCRCが前提となりますが、上記リンクの手順に、わかりやすいCRCの導入手順も含まれているので、まだCRCを入れてなければ、こちらを参考に導入されても良いと思います。

なお、以下の動画では、CDCに導入したODF nanoをDBのストレージにしたりしているデモも確認することができます。
https://www.youtube.com/watch?v=mae0tiLkQag

### [手順]
やってみた感じ、手順は非常に簡単で、サクサクできます。基本的に、上記の手順に従って下さい。

それでも、ちょっと、「うっ」、となったポイントがあったのでそこだけ列挙します。

①
以下のように、vmのディスク領域を確保します。コメントにThin provisioningだぜと書いてあるんですが、私の環境では普通に空き容量を確保しないとエラーとなりました。なんかの設定なのかもしれませんが、ここらへんの理屈は良くわかってません、、
```
## Don't worry this is thin provisioned
sudo -S qemu-img create -f raw ~/.crc/vdb 100G
sudo -S qemu-img create -f raw ~/.crc/vdc 100G
```

②
CRCのVMからsudo virsh dumpxmlでダンプしたxmlにディスク領域を記載して、またアプライする手順があるんですが、そのままやるとBus番号がかぶる。普通にズラしましょう。

```
[crc]$ sudo virsh define ~/crc.xml
エラー: /home/keyamamo/crc.xml からのドメイン定義に失敗しました
エラー: XML error: Attempted double use of PCI Address 0000:05:00.0
```

RNGデバイスとVDBのBus番号0x05がかぶっている。ここでは、RNGを削ってみました、、
```
    <rng model='virtio'>
      <backend model='random'>/dev/urandom</backend>
      <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/>
    </rng>
    <disk type='file' device='disk'>
      <driver name='qemu' type='raw' cache='none'/>
      <source file='~/.crc/vdb' index='1'/>
      <backingStore/>
      <target dev='vdb' bus='virtio'/>
      <alias name='virtio-disk1'/>
      <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/>
    </disk>
    <disk type='file' device='disk'>
      <driver name='qemu' type='raw' cache='none'/>
      <source file='~/.crc/vdc' index='2'/>
      <backingStore/>
      <target dev='vdc' bus='virtio'/>
      <alias name='virtio-disk2'/>
      <address type='pci' domain='0x0000' bus='0x06' slot='0x00' function='0x0'/>
    </disk>
```

当たり前ですが、その後はうまく適用できます。
```
[crc]$ sudo virsh define ~/crc.xml
Domain 'crc' defined from /home/keyamamo/crc.xml
```

③
ODF nanoでは、NooBaaは入りません。
上に出てくる手順のキャプチャ上は、通常のODF同様にNooBaaも入ってるキャプチャが掲載されており、どの手順間違えたんだろう？と悩んでいたら、コード側に「そのうち相談」みたいな怪しい記述が、Developerに確認したところ、現在のバージョンのODF nanoではNooBaaは入らないとのことが確認できました。

実際の導入結果
![20221220.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2854092/499b75ea-88e1-7206-b31e-3b1147e823d2.png)

以上です。参考になれば幸いです。
今年のM-1グランプリのデータでpyhtonでのデータ分析基礎を学び直し

　久しぶりにpandasなどデータ分析の学び直しをやりたかったので、せっかくなら一昨日終わったばっかりのM-1グランプリのデータでやってみたいと思います。

　まずは採点結果をcsvファイルに保存(ここでは、まだ合計は入れないでおく)

```M-1_2022_score.csv
,山田,大吉,塙,富澤,志らく,礼二,松本
カベポスター,84,94,92,93,89,92,90
真空ジェシカ,95,92,92,92,94,94,88
オズワルド,87,93,90,90,95,92,92
ロングコートダディ,94,92,94,96,96,95,93
さや香,92,96,95,97,95,97,95
男性ブランコ,86,91,92,95,94,96,96
ダイヤモンド,86,90,88,88,88,89,87
ヨネダ2000,91,91,96,91,97,90,91
キュウ,87,90,88,90,89,90,86
ウェストランド,91,93,93,94,98,96,94
```

　まずはpandasをインポートして上記のcsvファイルを読み込み

```python
import pandas as pd

score_df = pd.read_csv("M-1_2022_score.csv", index_col=0)
score_df
```

　出力結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350321/e580202e-f99e-c91e-03f0-d6d14432a876.png)

　手っ取り早く、基本統計情報を見るにはdescribe()を使います。

```python
score_df.describe()
```

　出力結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350321/a2b4cc3d-60d8-cb1d-93f5-4985b2ea0de2.png)

　まず、ここで注目するのはstd:標準偏差の行です。この値が高い審査員ほど採点のばらつきの幅が大きくなるので、最終結果に与える影響が大きくなります。これを見ると山田、志らく、松本が高く、大吉は低いですね。

　箱ひげ図でも表示してみましょう。

```python
import matplotlib.pyplot as plt
import seaborn as sns

plt.rcParams['font.family'] = 'MS Gothic'
sns.boxplot(data=score_df)
```

　出力結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350321/1696bc06-c88b-2b87-bea2-3c05d0997130.png)

　やっぱり、山田邦子は幅が大きく、少しだけ基準が低いですね。

　次は、審査結果が近い人と遠い人がいそうなので、PCAで次元消滅させて可視化してみましょう。

```python
from sklearn.decomposition import PCA

pca = PCA(n_components=2)
features = pca.fit_transform(score_df.T)

X = features[:, 0]
Y = features[:, 1]
plt.scatter(X, Y)
for i,(x, y) in enumerate(zip(X, Y)):
    plt.annotate(score_df.T.index[i],(x, y))
plt.xlabel("PC1")
plt.ylabel("PC2")
plt.grid()
plt.show()
```

　出力結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350321/0a035dc3-26a0-aa61-ae8a-c0745a0d8eea.png)

　確かに、なんとなく大吉、富澤、礼二、松本は正統派が好きな印象で、志らくはヨネダ2000とか個性派を好み、塙はその中間って感じしますね。そして独特な感性で採点する山田邦子。

### 最後に

　ウェストランドのネタで「ネタの分析とかしてくるウザいお笑いファンいるか～」って言ってたけど、ワイの事やった。
Goでモデルのカラムを配列として定義したい

# はじめに

モデルの一部のカラムを配列で定義する際、テーブル作成が出来ずに詰まったので解決までの流れを簡単にまとめてみます

## ①pqパッケージのStringArrayで定義すると

```Catalog.go
import "github.com/lib/pq"

type Catalog struct {
	gorm.Model
	Title     string `gorm:"not null"`
	Comments    pq.StringArray
```

以下を参考にしましたが、こちらはPostgreSQL用でした

https://gorm.io/ja_JP/docs/data_types.html

今回使用しているのはMySQLなので以下のエラーが発生し、テーブル作成ができませんでした

```
Error 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '[], ... at line 1
```

次はこちらの記事を参考にしました

https://stackoverflow.com/questions/52244001/go-gorm-mysql-unsupported-type-string-a-slice-of-string

記事では以下の解決策が書かれていました

1. 配列を文字列かバイト型で定義する
2. 2つのテーブルを作成して紐づける

## ②配列を文字列かバイト型で定義すると

```
type Catalog struct {
	gorm.Model
	Title     string `gorm:"not null"`
	Comments    string[]
```

すると以下のエラーが発生しました

```
[error] unsupported data type: &[]
```


## ③【解決】Commentモデルを作成し、Catalogモデルに紐づけをすると

```Comment.go
import "gorm.io/gorm"

type Comment struct {
	gorm.Model
	Content string `gorm:"not null" json:"content"`
	CatalogID uint 
}
```

```Catalog.go
type Catalog struct {
	gorm.Model
	Title     string `gorm:"not null"`
	Comments    []Comment

```

最終的にこの方法でテーブル作成ができました

gormのhas manyの書き方は公式ドキュメントを参考にしました

https://gorm.io/ja_JP/docs/has_many.html


# おわりに
gormに早く慣れていきたいです。
STM32G071でナイトライダー(D8からD13)


目的

GPIOのテスト


![o_cop257.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/826c1304-c09d-f282-e3de-204ea684fa9f.jpeg)



```c++



//D7_D13_Knight_Rider_071_1

void setup() {

  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);

  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);

}

void loop() {

  digitalWrite(8, HIGH);  delay(1000);
  digitalWrite(8, LOW);   delay(1000);

  digitalWrite(9, HIGH);  delay(1000);
  digitalWrite(9, LOW);   delay(1000);

  digitalWrite(10, HIGH);  delay(1000);
  digitalWrite(10, LOW);   delay(1000);


  digitalWrite(11, HIGH);  delay(1000);
  digitalWrite(11, LOW);   delay(1000);

  digitalWrite(12, HIGH);  delay(1000);
  digitalWrite(12, LOW);   delay(1000);

  digitalWrite(13, HIGH);  delay(1000);
  digitalWrite(13, LOW);   delay(1000);

}





```
[2022年]Vue2のプロジェクト作成〜Vuetifyの導入まで

## 概要
Vue2でプロジェクトを作成してVuetifyを導入するまで

## 手順
### Vue2のプロジェクト作成
下記のコマンドでVueのプロジェクトを作成

```sh
vue create プロジェクト名
```

途中でバージョンなどの指定方法が出てくるので

```sh
Vue CLI v5.0.8
? Please pick a preset:
  Default ([Vue 3] babel, eslint)
❯ Default ([Vue 2] babel, eslint)
  Manually select features
```
Vue2を選択


### Vuetifyの導入
開発するにあたってデザインちゃんとやれる自信がないのでVuetifyを導入します。
```
cd プロジェクト名
```
でプロジェクトの中に入って下記のコマンドを実行
```
vue add vuetify
```
途中で選択肢が出てくるので
```
? Choose a preset:
  Vuetify 2 - Configure Vue CLI (advanced)
❯ Vuetify 2 - Vue CLI (recommended)
  Vuetify 2 - Prototype (rapid development)
  Vuetify 3 - Vite (preview)
  Vuetify 3 - Vue CLI (preview)
```
Vue2のcliを選択....終了！

### 軽く動作確認
下記のコマンドを実行すると
```
npm run serve
```
![スクリーンショット 2022-12-20 21.03.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83409/3fa68847-a0cc-2d26-ab16-f68f4f2ed81b.png)
こんな感じで初期の画面が表示されます。
GASでGoogleフォームを作成する

# GASでGoogleフォームを作成する
## はじめに
GASでGoogleフォームを作成したことがあったのでそれのメモ。

## ソースコード
### フォーム作成
```JavaScript
var form = FormApp.create('タイトル');
form.setDescription('説明');
// 回答進捗を表すバーを表示する
form.setProgressBar(true);  
```

### チェックボックス
```JavaScript
var checkBox = form.addCheckboxItem();
checkBox.setTitle('質問名');
checkBox.setHelpText('補足説明');
// チェックボックスの項目
var choices = ['項目1', '項目2', '項目3', '項目4', '項目5'];
checkBox.setChoiceValues(choices);
// その他
checkBox.showOtherOption(true); 
// 回答を必須にする場合
checkBox.setRequired(true);
```

### プルダウン
```JavaScript
var pullDown = form.addListItem();
pullDown.setTitle('質問名');
pullDown.setHelpText('補足説明');
var arr = ['AAA','BBB','CCC','DDD','EEE'];
pullDown.setChoiceValues(arr);
```

### 段落
```JavaScript
var paragraph = form.addParagraphTextItem();
paragraph.setTitle('質問名');
paragraph.setHelpText('補足説明');
```

### ラジオボタン
```JavaScript
var multiple = form.addMultipleChoiceItem();
multiple.setTitle('あなたは好きですか?');
var choices = ['はい','いいえ'];
multiple.setChoiceValues(choices);
multiple.setRequired(true);
```
### 均等目盛（どっちに近いかを選択させるやつ）
```JavaScript
var scale = form.addScaleItem();
scale.setTitle('このQiitaはためになりますか');
// 目盛の数
scale.setBounds(1, 5);
scale.setLabels('ためにならない', 'ためになる');
```

### セクション分け
```JavaScript
// このメソッドでセクションが分かれる
form.addPageBreakItem();
```

## おわりに
上記以外の形式は使ったことがないのでリファレンス参照してください。

## 参考
[Form 公式リファレンス](https://developers.google.com/apps-script/reference/forms/form)
iPadだけでVSCode環境を得られるようになった


## はじめに
ちょっとこちらを見てください（強め）

![A7F391F8-35A4-4077-8C19-2DF67AE33F10.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1505764/2d217cf5-1046-9863-cfa2-f8df952a611b.gif)

![trim_116AFEC0-5629-481F-B988-EDF48765D245_MOV_AdobeExpress_AdobeExpress_AdobeExpress.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1505764/fb1c0633-4980-1a44-1ac8-c7ccdf6feac7.gif)


gifの都合上n倍速ですが、iPadでコレすごくないですか？
「ついに来た！」って感じですごいワクワクしています。
iPadで開発を行いたい奇特なエンジニア(自分)も、下記２つのサービスによってPCで開発するのと遜色ない環境を得られるようになったので、軽く紹介します！

## Codespaces
こちらは色んな所で紹介されていると思うのでそちらにすべて委ねようと思うのですが、　Github製のサービスで、リポジトリからクリックだけでVSCodeの開発環境を簡単に起動できるスグレモノですね。

- 個人開発レベルなら無料枠だけで事足りそう
- web上で完結するのでiPadからでもいよいよ本格的なプログラムが可能になった
 

## Blinkのアップデート
加えて、[Blink](https://blink.sh/)というターミナルアプリのアップデートがありました。
### codeコマンド対応
[Blink code](https://docs.blink.sh/advanced/code)というページにあるように、（いつの間にか）`code`コマンドが使えるようになっていました。

![C72BEB29-AFF4-4CDB-9BED-82337D162D82.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1505764/d232957c-620a-aed9-35e2-3eb86a27fc5d.gif)
gifだと見にくいですが...

立ち上がったvscodeに`blink fs`という拡張機能を入れておくと、ローカルファイルを操作できるようになります。
- フォルダを開くことができない(codeコマンドの引数に取れば行けそう？)
- ターミナル機能は使えない

のですが、iPadでぱっとメモを取りたい場合は重宝できそうです。


### Codespacesとの連携
さらに、Codespacesとの連携がとてもスムーズにできます。
というのも、普通にGithubのCodespacesから`Open in Visual Studio Code`を選択するだけでBlinkが起動してvscodeが起動します。

`Open in Visual Studio Code`には`vscode://`とvscodeアプリを起動するためのスキーマが設定されているのですが、Blinkが自分のことだとよしなに理解して起動するようです。

これでブラウザからすら開放された環境でプログラミングを行うことができるようになりました！

## 終わり

まだこの環境で一から開発をしたことはまだないので、実際に触っているとまた不満点も上がってくるかもしれません。
ですがCodespaces + Blinkはとてもシンプルでかつ強力な環境と思っていて、自分もiPadでプログラミング環境を構築すべく色々模索していた人の一人なのでとても嬉しいです。

ちなみに、これまで模索した環境構築は下記の別ブログでまとめてみたので、興味ございましたら覗いてみてください！

https://blog.shaba.dev/posts/coding-with-ipad
Neevaについての初歩的な知識

# ジャンル
検索エンジン

# プラットホーム
1. ウエブ版
1. デスクトップ版
    - Chromeアドオン
    - Edgeアドオン
    - Firefoxアドオン
    - Safariアドオン
1. モバイル版
    - iOS
    - Android

# 価格
1. Free Plan
    - 広告なしの検索　限定
    - 同一アカウントでのデバイス台数　限定
1. Premium Annual Plan ($4.17/月)　(初年度のみ$3.33)
    - 広告なしの検索　無制限
    - 同一アカウントでのデバイス台数　無制限
    - プレミアムパスワードマネージャー
    - VPN
1. Premium Monthly Plan ($5.99/月)
    - 広告なしの検索　無制限
    - 同一アカウントでのデバイス台数　無制限
    - プレミアムパスワードマネージャー
    - VPN

広告を掲載しないサブスクリプション検索エンジン
Googleの独占力はユーザーに害を及ぼしている

# 概要
　2019年1月31日に、アメリカ・カリフォルニアでGoogleで広告とマネタイズを担当していた Sridhar RamaswamyとVivek Raghunathanによって設立されました。
　Sridarは、Googleのもっとも重要なビジネス部門を15年間舵取りしてきました。Google検索エンジンのシェアは92%となりましたが、そのビジネスモデルは広告によるもので、ユーザーの利便性が犠牲にされ、プライバシーが守られていないと感じていました。データを革新的な技術ビジネスに変換し、ユーザーのプライバシーが守られ、よりパーソナライズされた最良の結果を表示する新たなサービスを提供することにしました。
　Neevaはアフェリエイトの結果を表示させることなく、ユーザーにプライベートでパーソナライズされた結果を表示する、ユーザーが料金を払って使用するサブスクリプション検索エンジンです。Times誌は、2021年ベストインベンションズに選出しています。

# 機能
　Neevaは、ブラウザのアドオンとして使用すると、ブラウザの検索エンジンをNeevaに設定します。
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/b4b21055-85e1-ceb8-3f2d-82f520f28251.png"/>
　テーマは、ライトとダークが選択できます。
　言語は英語とフランス語、ドイツ語のいずれかが選択できます。現在サービスの対象は、アメリカ、カナダ、フランス、ドイツとなっており、まだ日本は対象となっていません。したがって、英字単語での検索結果はGoogleの検索とは異なった結果が出るようです。
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/c6c72c23-7d52-dd6c-eeee-c67f64fe4020.png"/>


　ブランド名などを検索するとGoogleは明らかに利用者に購入を促す表示方法を取ります。Neevaはそれがありません。
　なぜユーザーが使用料を払うサービスを提供しているのかという答えは、以下のとおりです。

> Googleはユーザー数が多すぎるし、収益も多すぎる。
> プライバシーを心配し、Googleにデータを吸い上げられ、検索履歴に基づいて広告のターゲットにされることを望まないユーザーに代替案を提供することです。

<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/8a99e7f9-188c-4d2b-dc09-a892c8794e87.png"/>

　技術的な知識の検索では、英語のサイトを敢えて選択するようにしているので、私はもうしばらく使ってみようと思います。
phpで現在のURLを取得する関数を作った。

## はじめに
phpで現在作動しているファイルのURLを取得する関数を作りました。

## コード
```php
function now_url($status = 0){
    if($status === 0){
        return (((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ) ? "https://" : "http://").$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
    }else if($status === 1){
        return strtok((((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ) ? "https://" : "http://").$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'], '?');
    }
})
```

## 使い方
### クエリ文字列あり
```php
now_url(0);
```
### クエリ文字列無し
```php
now_url(1);
```

## 終わりに
便利だよね?ね?
小さなプロダクトチームでエンジニアがデザイナ・ビジネスとのやり取りで気をつけていること

## はじめに

小さなプロダクトチーム（ビジネス・デザイナ・エンジニア含めて）１０名規模で1年ほど、エンジニアとして参加してきました。

その中で、エンジニアの私がやり取りする上で気をつけていることを紹介します。

## 気をつけること

### 1. 技術的に不可能と言わない

ビジネスからの機能要求やデザイナからのUI要求などに対し、エンジニアがNOと言ってしまうとプロダクトの成長が止まります。

```
これは、難しいんだよな。
今の仕組みだと、相当コストかかるよな。
```

など、多少は感じるリクエストは発生します。
このような時に、技術的に不可能です。と突っぱねてしまうことは簡単です。

しかし、今後の要求が、エンジニアから「NOと言われる可能性がある」と、`せっかく浮かんだアイデア`を潰してしまう危険があります。このアイデアは、プロダクト成長に直結するものにもなります。

私は、難しいと判断する前に、できる方法を`調べる、相談する、考える`を必ず行っています。
この結果で、技術的に不可能となることは殆んど発生しません。

もちろん、突拍子もない要求（もしもボックスを作ってなど）の場合は現時点で不可能となる可能性はありますが...。

### 2. 背景を把握する

プロダクトの背景、ビジョンやマイルストーンの把握はもちろん、どんな小さな案件でも必ずその要求に至った背景があります。そこを正確に理解、共感してから案件に取り組むようにしています。

具体的には、以下の４点を確認します。

- 誰が、何のために、どのようなものを、いつまでに欲しいのか

他にも、利用頻度や利用者数、市場に対するインパクトなど確認する場合もありますが。
この４点を押えることで、エンジニアの動き方を最適化することができます。

最適化されること

- 利用シーンの解像度を上げることで、適切なテストが実施できる
- 利用用途がわかることで、要求を満たす別のより良い方法を見つけることができる
- いつまでに必要かがわかることで、開発体制や、遅延時の適切なフォローをすることができる

結構当たり前のことのような内容ですが、案外`どのようなもの`だけを確認して他を考えずに開発してしまうことも多いかと思います。
何をやるかだけではなく、なぜやるのか、何のためにやるのかまで把握してから取り組むことがすごく重要です。

### 3. 思いやり

めちゃくちゃ大事です。

- 私が、ビジネスだったら、どうなっているのがいいだろう
- 私が、デザイナだったら、どうなっているのがいいだろう
- 私が、ユーザだったら、どうなっているのがいいだろう

この３点を、常に自問しています。


## さいごに

紹介した３点は、めちゃくちゃ簡単で、当たり前のことです。
当たり前のことですが、結構成果に響いてくる内容でもあります。

もし、盲目になってひたすら日々の開発業務に追われているようなことがあったら、この内容を思い返してみてください。

誰かのためになれば幸いです。
GASでスプレッドシートの値を読み込む

# はじめに
自分用備忘録

# 手順
1. 値を読み込みたいスプレッドシートを指定する
1. 値を読み込みたいシートを指定する
1. 値を読み込む

# やってみる
### 値を読み込みたいスプレッドシートを指定する
1.getActiveSpreadsheetで指定する場合
```JavaScript
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
// スプレッドシートからGASを作成した場合に使えます。
```
2.openByIdで指定する場合
```JavaScript
var spreadsheet = SpreadsheetApp.openById('<スプレッドシートID>');
/*
スプレッドシートのIDは以下の部分です。        ↓
https://docs.google.com/spreadsheets/d/<スプレッドシートID>/edit
*/
```

### 値を読み込みたいシートを指定する
1.シート名で指定する場合
```JavaScript
var sheet = spreadsheet.getSheetByName('<シート名>'); 
```
2.シートのインデックスで指定する方法
```JavaScript
var sheet = spreadsheet.getSheets()[0];
```

### 値を読み込む
```JavaScript
var values = sheet.getRange('<取得範囲>').getValues();
// A1からA3まで取得したい場合はsheet.getRange('A1:A3').getValues()とします。
```


## サンプル
### ソースコード
```JavaScript
function myFunction() {
  var spreadsheet = SpreadsheetApp.openById('<スプレッドシートID>');
  var sheet = spreadsheet.getSheetByName('シート1');
  Logger.log('A1からA4の値を読み込む')
  var values1 = sheet.getRange('A1:A4').getValues();
  for (var i in values1) {
    Logger.log(values1[i]);
  }
  
  Logger.log('A1からB4の値を読み込む')
  var values2 = sheet.getRange('A1:B4').getValues();
  for (var i in values2) {
    Logger.log(values2[i]);
  }
}
```

## その他
SpreadsheetAppを使う場合はGAS APIの許可をする必要があります。

## おわりに
社内向けに書いたものを転載しているため情報が古い可能性あり。

## 参考
[SpreadsheetAppのリファレンス](https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app)
正規表現入門。正規表現を使って文字列検索

# はじめに
株式会社エアークローゼットのプロダクトグループでエンジニアをしているSteinと申します。

この記事は[エアークローゼット Advent Calendar 2022](https://qiita.com/advent-calendar/2022/air-closet) の24日目の記事になります

今回は正規表現の基本的な使い方について話したいと思いますので、ぜひ最後までご覧ください。

# 正規表現とは
正規表現は、ある文字列を表現する一つの方式です。
でも、基本的には単なる文字列です。
例：
```
文字列1：textA
文字列2：textB
文字列3：textC
文字列4：textD

正規表現：\w*
```
`` \w* ``は正規表現の特殊文字です。
以下に共通な特殊文字を紹介します。
# 特殊文字
### ^ (ハット)
^ は、行頭を示します。
例：
```
^abc

という４文字は、行頭が abc で始まるパターンを表現します。
行の途中に abc という３文字があっても、それとはマッチしません。
```

### $ (ドルマーク)
$ は、 ^ に似ていますが、行の終わりにマッチします
例：
```
です。$

という４文字は、行末にある「です。」という３文字とマッチします。
行の途中にある「です。」という３文字とはマッチしません。
```

### . (ドット)
 . は、任意の1文字にマッチします。
ただし、改行コードとはマッチしません。
改行コード以外の１文字を示します。

### [……] 大括弧
[と]の中に書かれた任意の1文字にマッチします。
例：
```
[abc]

a, b, c の３文字のいずれか１文字を表現します。
３文字のうちどれでもいいのですが、とにかく１文字とマッチします。
```
「-」 は、範囲を表わす特別の文字です。
例：
```
[0-9] = [0123456789]
[a-z] = 小文字アルファベット
[A-Z] = 大文字アルファベット
[ぁ-ん] = ひらがな
[ぁ-ん] = カタカナ
```
#### [^……] 大括弧
これは指定された文字集合以外の１文字を表現します。
例：
```
[^abc]

という６文字は、「a,b,c以外の任意の１文字」を表現します。
```
### {} 中括弧
#### {m}
これは、前置される正規表現のぴったりm回の繰り返しです。
例：
```
bc{3}

という文字列は、bcccにマッチします。
```
#### {m,}
これは、前置される正規表現のm回以上の繰り返しです。
例：
```
bc{3,}

という文字列は、bccc,bcccc,bcccccなどにマッチします。
```
#### {m,n}
これは、前置される正規表現のm回以上n回までの繰り返しです。
例：
```
bc{3,4}

という文字列は、bcccとbccccにマッチします。
```
### | パイプ

これは、「または」という接続詞に該当するものです。
例:
```
abc|main

という８文字は、 abc という３文字か、または、 main という４文字にマッチします。
```

### * アスタリスク
半角の * は、直前の１文字の０回以上の繰り返しを表現します。
例:
```
a*

という２文字は、 a aa aaa aaaa などとマッチします。
そのほか、「aという文字がない状態」ともマッチします。
```
### + プラス
半角の + は、直前の１文字の１回以上の繰り返しを表現します。半角の * が０回以上の繰り返しだったのに対し、こちらは１回以上の繰り返しです。
例:
```
abc+

という４文字は、 ab にはマッチしません。 
abc abcc abccc などにマッチします。
```

### ? 疑問符
半角の ? は、直前の文字の０回または１回だけの登場(とうじょう)を表現します。
例:
```
abc?

という４文字は、 ab abc のいずれかにしかマッチしません。
```

### \ バックスラッシュ
 \ は、特殊文字の特別の意味を打ち消すためのものです。
例:
```
\^ = ^
\. = .
\? = ?
```

### (……) 括弧
　半角の ( と、同じく半角の ) で囲んだ部分は、一つのまとまりグループとみなします。もちろん、正規表現をこれで囲んでもかまいません。
例:
```
(abc)+

という６文字は、 abc abcabc abcabcabc などとマッチします。
```

### 補足
```
•	\s　　空白文字１文字
•	\w　　英数字または「_」のうち１文字
•	\d　　数字１文字
```

# 正規表現を使って文字列検索
一部異なるが同じ構造の文字列を検索したい場合は、正規表現が最適です。
現在、vscode、sublime textなどが正規表現検索機能をサポートしています。
例えば：SELECTクエリを検索したい。
各クエリが別のIDを含まれているので、普通の検索はできません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957202/b96f73e4-2c8c-e69f-e7bd-82bea0bd5a5a.png)
検索のボックスで正規表現オプションを選びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957202/da938f05-05d4-1764-7234-5d816304c9dd.png)
``SELECT\s.*FROM\s*.*WHERE\s.*;``という正規表現を入力して、SELECTクエリが選択されました。
```
\s　　空白文字１文字
.*　　任意の1文字、０回以上の繰り返しとマッチします。
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957202/0085e910-883f-28ae-7fe6-d8a2aed742a6.png)

# あとがき
最後までご覧いただきありがとうございました。

[エアークローゼット Advent Calendar 2022](https://qiita.com/advent-calendar/2022/air-closet)はまだ続きますので、興味あれば、ぜひ他のエンジニア、PMの記事もご覧いただければと思います。
GASでスプレッドシートに値を書き込む

# はじめに
あえて書くまでもないけど自分用の備忘録として書く。

# 手順
1. 値を書き込みたいスプレッドシートを指定する
1. 値を書き込みたいシートを指定する
1. 値を書き込む

# やってみる
### 値を書き込みたいスプレッドシートを指定する

``` JavaScript
var spreadsheet = SpreadsheetApp.openById('<スプレッドシートID>');
/*
スプレッドシートのIDは以下の部分です。        ↓
https://docs.google.com/spreadsheets/d/<スプレッドシートID>/edit
*/
```

### 値を書き込みたいシートを指定する
```JavaScript
var sheet = spreadsheet.getSheetByName('<シート名>'); 
```

### 書き込む
```JavaScript
// A1に書き込む
sheet.getRange('A1').setValue('あいうえお');
```
## サンプル
### ソースコード
```JavaScript
function myFunction() {
  var spreadsheet = SpreadsheetApp.openById('<スプレッドシートID>');
  var sheet1 = spreadsheet.getSheetByName('シート1');
  var sheet2 = spreadsheet.getSheetByName('シート2');
  
  // シート2のA1に書き込む
  sheet2.getRange('A1').setValue('わ！');

  // シート1のA1からB4の値を読み込む
  var values = sheet1.getRange('A1:B4').getValues();
  
  // シート2のC6からD9に書き込む
  sheet2.getRange('C6:D9').setValues(values);
}
```

# おわりに
社内向けに書いたものを転載しているため情報が古い可能性あり。

## 参考
[SpreadsheetAppのリファレンス](https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app)
phpでリダイレクトをする関数を作った

## はじめに
phpでリダイレクトする時、通常は以下のような書き方をします。
```php
header("location:URL");
exit;
```
ヘッダー情報を上書きするんですね。
ただ、この二行を書くのが面倒臭かったので関数にしました。
需要はほぼなしですが...

## コード
```php
function redirect_page($status = 0,$status_one_url = null){
    if($status===0){
        header("location:".(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
        exit;
    }else if($status===1){
        header("location:".$status_one_url);
        exit;
    }
}
```

## 使い方
### 同じページにリダイレクトする場合
```php
redirect_page(0);
```
### 指定したページにリダイレクトする場合
```php
ridirect_page(1,"https://google.com/");
```

## 終わりに
「需要が、」
　　　ゼーロー

https://www.youtube.com/watch?v=rxo1_YvJRss
Permission denied (publickey,gssapi-keyex,gssapi-with-mic)【Google Compute Engine】【Rocky Linux】

クライアント
```bash
ssh-keygen -q -f $HOME/.ssh/id_rsa -P ''
cat $HOME/.ssh/id_rsa.pub
```

サーバー `id_rsa.pub`を`authorized_keys`にコピペ
```bash
echo ssh $USER@$(curl -sL domains.google.com/checkip)
mkdir -p $HOME/.ssh
chmod 0700 $HOME/.ssh
touch $HOME/.ssh/authorized_keys
chmod 0600 $HOME/.ssh/authorized_keys
vim $HOME/.ssh/authorized_keys
```

<details><summary>rootでログインする場合</summary>

```bash
echo PermitRootLogin yes >> /etc/ssh/sshd_config
systemctl reload sshd
```
</details>

GCPはSSHが有効になってるため設定は必要ありません
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/fc4f3c02-88b4-25c3-e460-4902686d9a84.png)

<details><summary>ユーザーを追加する場合( Debian )</summary>

```bash
USERNAME=myuser
sudo useradd -m -p '' $USERNAME
sudo usermod -aG sudo $USERNAME
su - $USERNAME

echo ssh $USER@$(curl -sL domains.google.com/checkip)
mkdir -p $HOME/.ssh
chmod 0700 $HOME/.ssh
touch $HOME/.ssh/authorized_keys
chmod 0600 $HOME/.ssh/authorized_keys
vim $HOME/.ssh/authorized_keys
```
</details>

<details><summary>ユーザーを追加する場合( Rocky Linux )</summary>

```bash
USERNAME=myuser
sudo useradd -m -p '' $USERNAME
sudo usermod -aG wheel $USERNAME
su - $USERNAME

echo ssh $USER@$(curl -sL domains.google.com/checkip)
mkdir -p $HOME/.ssh
chmod 0700 $HOME/.ssh
touch $HOME/.ssh/authorized_keys
chmod 0600 $HOME/.ssh/authorized_keys
vim $HOME/.ssh/authorized_keys
```
</details>

https://qiita.com/tattn/items/a03cbf7c185d7efa6769
phpのリロード対策で最も簡単な方法（二重送信防止）

## はじめに
phpで掲示板などを作るとき、リロード対策をしなければなりません。
そうしないと、連続投稿が簡単になってしまい、スパムの産みの種となってしまいます。

## そんな時は?!
以下のコードで解決！
```php
if($_SERVER["REQUEST_METHOD"]==="POST"){
    //処理
    header("location: URL");
    exit;
}
```

## 仕組み
POST送信がなされているか条件分岐で確認し、処理をした後にリダイレクトします。
```URL```とあるところにリダイレクト先のURLを入力してください。

## 終わりに
びぼーろく
HTML5の定型文（コピペ用）

```html
<!DOCTYPE html>
<html lang="ja">
<head>
	<meta http-equiv="content-language" content="ja">
	<meta name="robots" content="noindex,nofollow">
	<meta charset="UTF-8">
	<title>タイトル</title>
	<style type="text/css">
		font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Hiragino Kaku Gothic ProN', 'メイリオ', meiryo, sans-serif;
	</style>
</head>
<body>

</body>
</html>
```
以上。
【シェルスクリプト】変数の値を一時的に変更する方法

## 変更方法

`( commands )`でコマンドを括りサブシェルで実行すると一時的に変数の値を変更できます。  

```bash
SAMPLE='SAMPLE'

(
  SAMPLE='サンプル'
  echo "変更後: ${SAMPLE}"
)

echo "変更前: ${SAMPLE}"

```

```terminal
bash test.sh
変更後: サンプル
変更前: SAMPLE
```

## うまくいかない方法

以下のように記述するとコマンド実行前にシェルによって変数が展開されるため値は変更されません。  

```bash
SAMPLE='SAMPLE'
echo "変更前: ${SAMPLE}" 
SAMPLE='サンプル' echo "変更後: ${SAMPLE}"

```

```terminal
$ bash test.sh
変更前: SAMPLE
変更後: SAMPLE
```
Dockerコンテナ内で、Postfixを使ってメール送受信を行う

# はじめに
ラクスでMailDealerというメール共有管理サービスの開発をしている@hirobexです
今回は、Dockerコンテナ内でメール送受信できるようにしたいと思います

# Dockerfile
```Dockerfile:Dockerfile
FROM almalinux:minimal

RUN microdnf update && microdnf install postfix cyrus-sasl cyrus-sasl-plain

COPY ./entrypoint.sh /
COPY ./main.cf /etc/postfix

ENTRYPOINT [ "/entrypoint.sh" ]
```
今回はベースイメージにAlma Linuxを選定

Postfixと、SASL認証用のライブラリをインストールします
なお、今回は~~時間がなかったので~~SASL認証の設定は行いません

:::note warn
slim系イメージの場合、dnfコマンドは存在しません
代わりにmicrodnfコマンドを利用します
:::

その後、起動用の`entrypoint.sh`とPostfixの設定ファイル`main.cf`をCOPYします

# entrypoint.sh
```shell:entrypoint.sh
newaliases

postfix start-fg
```

start-fgコマンドを利用することで、Postfixがフォアグラウンドで動き続け、コンテナが自動で終了しなくなります

:::note warn
start-fgはPostfixのバージョンが3.3以上ではないと使えません
:::

# main.cf

```properties:main.cf
inet_interfaces = all

inet_protocols = ipv4

# minimalではsyslogが動いていないため、明示的に指定する必要がある
maillog_file = /var/log/maillog
```

main.cfは各自のネットワーク設定に合わせて
今回は最低限だけ記載しておきます

`inet_interfaces = all` ですべてのメールを受信できるように設定
`inet_protocols = ipv4` この設定じゃないとipv6が使えないとエラーがでたためです
`maillog_file = /var/log/maillog` コメントアウトに記載のとおりです

# docker-compose
これをdocker-composeで動かします
```yml:docker-compose.yml
version: '3.8'

services:
  postfix1:
    build:
      context: .
      dockerfile: ./Dockerfile
    container_name: postfix1
    hostname: postfix1
    volumes:
      - ./postfix1/log:/var/log
```

任意のホスト名を利用して送受信できるように、`hostname`と`container_name`を指定しています
mailogが確認しやすいようvolumesにマウントしています
受信したメールを確認したいなら、受信フォルダもマウントしてもいいかもしれません

# 送受信

```bash:host
docker-compose build
docker-compose up

docker-compose exec -it postfix1
```

ホスト側でコンテナ内に入り、以下のコマンドを実行します

```bash:container
sendmail root@postfix1
from: root@postfix1
to: root@postfix1
subject: test

Hello World

.
```

`/root/Maildir/new`にメールが受信できていればOKです
受信できていない場合は、maillogを確認してみましょう


# まとめ

今回は、DockerでPostfixを利用しました

コンテナを2つ立てたらコンテナ間での送受信も可能です
ただし、SASL認証や、main.cfでの受信許可設定が必要です

来年は、外部に向けて送受信できるようにしたいですね

では。

# 参考資料

https://tech-mmmm.blogspot.com/2021/01/dockerpostfix.html

https://www.mathkuro.com/cent-os/dnf-yum-command-not-found/

https://zenn.dev/flyingbarbarian/articles/a6c967612f061b

https://qiita.com/yoshidna/items/2d0b89086914a7be73a4
【学習ノート】Pandas 基本操作①

# Pandasとは
データ解析を容易にする機能を提供する解析ライブラリであり、Pythonと組み合わせれば、データ分析でできないことはないと言っても過言ではないほど優れたデータ分析を支援するためのライブラリである。

表同士をくっつけたり、エクセル操作など日常業務の効率化から人工知能開発まで幅広く実用されている。

また、データフレームなどの独自のデータ構造が提供されており、ピボットテーブル、groupby、ソートなどの集計処理や、matplotlibと連携した可視化などさまざまな処理をすることが可能である。

# Pandasインポート方法

```py:ターミナル
$ pip install pandas
```

```py
import pandas as pd
```

# Pandasのデータ形式
#### Series
└ 一次元の配列。一列しかない行列とみなしても良い。
#### Dataframe
└ 行と列を持った配列データであり、seriesを複数まとめたもの

#### Panel
└ 3次元の配列データ。

# Dataframe
※ データ分析を極めたいため、seriesの記載は省略する。


```py
# 2列3行
import pandas as pd
df = pd.DataFrame([[1, 10], [2, 20], [3, 30]], columns=['col1', 'col2'])

#    col1  col2
# 0     1    10
# 1     2    20
# 2     3    30
```

#### レコード数
```py
len(df)
# 3
```

#### 要素数
```py
df.size
# 6
```
【Azure】AzureTranslatorのAPIをVSCodeから叩く

### 概要
ウェブ開発でAzure Translatorを使う機会があり、検証としてAPIをローカルから叩きたかった。

### 前提条件
- Azureの開発環境があること
- VSCodeがインストールされていること

### 事前準備
- Azure PortalでTranslatorをデプロイ
    - リソース作成は[こちらの記事](https://tech-blog.cloud-config.jp/2021-12-16-translator-webapi/)を参照
    - デプロイ完了後、リソースに移動し、キーとエンドポイントにてキー１・地域を控えておく
- VS Codeで拡張機能をインストール
    - [こちらの記事](https://qiita.com/toshi0607/items/c4440d3fbfa72eac840c)を参照

### HTTPリクエスト用ファイル作成
以下の.httpファイルを作成

```任意のファイル名
POST https://api.cognitive.microsofttranslator.com/translate/
    ?api-version=3.0
    &from=ja
    &to=en
    &to=ko
content-type: application/json
Accept: application/json
Ocp-Apim-Subscription-Key:{キー１}
Ocp-Apim-Subscription-Region:{地域}

[{
    "Text":"{翻訳したい文章}"
}]
```

クエリパラメータにて、fromで翻訳元言語、toで翻訳先言語を指定する
翻訳先言語は複数指定可能

### リクエストの送信
POSTの上あたりにSend Requestというボタンが出てくるので押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316676/42fa0077-b2e5-d216-2698-f0582491340f.png)



横のタブに結果が返ってくる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316676/91bdae38-c090-1a00-ebe5-5311b17a271f.png)


### その他参考
- [Document Translation REST APIリファレンスガイド](https://learn.microsoft.com/ja-jp/azure/cognitive-services/translator/document-translation/reference/rest-api-guide)
    - この辺りのAPIは無料版だと使えない
【今更】セキュリティグループの説明に日本語が使えなかった

凡ミスなのですが、セキュリティグループの説明って日本語使えないのですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723719/a4fcc6e4-e549-4cac-56df-97cf83abec6c.png)

```
Valid characters for VPC security groups only include a-z, A-Z, 0-9, spaces, and ._-:/()#,@[]+=&;{}!$*.
```

```
（訳）VPCセキュリティグループに有効な文字は、a-z、A-Z、0-9、スペース、および._-:/()#,@[]+=&;{}!$*だけです。
```

 - これらが使える模様。
   - 英小文字
   - 英大文字
   - 数字
   - （次の記号⇒）. _-:/()#,@[]+=&;{}!$*


AWS マネジメントコンソールの言語を日本語にすると説明部分の例文が日本語になってしまうのが紛らわしい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723719/047ecb47-0837-aa21-e448-7e761cb07b6a.png)

英語に直すと作成に成功します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723719/28081613-d339-5a8e-56bd-472fa74df2e4.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723719/733b6dda-2499-ca98-78dd-6ef6cdcefa20.png)


# 参考

https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/VPC_SecurityGroups.html

https://github.com/aws-cloudformation/cfn-lint/issues/173
成果物の目的に沿ったレビュー観点を持ってレビューする

# はじめに

去年か一昨年ぐらいからレビューアになる機会が度々あるのですが、当時、レビューアとして機能していなかったことがありましたので、その失敗と気を付けていることをまとめます。
レビューなんだから当たり前でしょうという内容ですが、当時はできていませんでした...

## 漫然と成果物を見てしまう

他メンバが作ったユーザー向けにアプリの新機能を紹介するドキュメントをレビューすることがありました。
このドキュメントの目的は、ユーザーが新機能の利用シーンの想像ができ、価値を伝えるためでした。
しかし、レビュー時には成果物の目的はすっかり忘れていて、正確に伝えられているか（誤記や日本語としておかしくないか、仕様と合っているか等）のようななんとなくの観点で成果物を見て、指摘を出して終わりとしたことがありました。
これではレビューをしたとは言いづらいです。

## 成果物に適した観点をもってレビューする

正確に伝えられているかも大事ですが、漫然と見ていては、成果物が妥当であるか判断したことになりません。
例えば、今回の例に挙げている成果物の目的の場合、少なくとも以下の観点を持ってレビューをした方が、よりドキュメントの改善につながったと思います。
- ユーザーが利用シーンを想像できるか
    - よくあるユースケースになっているか
    - データは現実離れしていないか
- 価値が伝わるか
    - 機能を利用した結果どのように嬉しいのか明確に書いてあるか

今回はユーザー向けドキュメントの例でしたが、これに限らず成果物の目的に沿った自分なりの観点を持ってレビューしないと、成果物が妥当であるか評価した（レビューした）ことにならないと思い、気を付けています。
わかってはいるけど、経験が浅いうちは気を抜くと忘れてしまうことが多いのかなと思います。

## レビュー時の工夫

私だけでなく、他チームメンバもユーザー向けのドキュメントをレビューする際に同様の問題に遭遇することがあったため、工夫をしています。
レビュー指摘を記録する帳票に、以下のチェック項目を用意することで漫然と成果物を見てしまうことはチーム全体でなくなりました。
- レビューイが成果物の目的を合意しているはずであるため、それを記載してレビューを依頼すること
- レビュー観点を宣言してからレビューする(漫然とみたとは書けないので)

# さいごに

目的に沿った自分なりの観点を持ってレビューをするための、観点を持つ意識はついてきましたが、「観点を抽出する」のは難しいと感じます。
成果物の目的からあるべき姿を自分なりにおいて抽出しますが、漏れがあると思います。
今後も経験を積んで、色々な視点から成果物を見れるようになりたいです。