OmniAICreator/Qiita-1.07M huggingface dataset:
転送中のファイルを削除してしまった私の真のやらかし

# 何をしてしまったのか

とある基幹システムの更改案件でした。私が担当していたシステムは、ネットワークを通じて`HULFT`で受けたファイルを他システムに中継する役割を行っているサーバーでした。
サーバーのOSインストールや`HULFT`など業務アプリケーションが動作するところまでがベンダーSEである私の担当範囲であり、`HULFT`で受けたファイルを他システムに連携したり`HULFT`の定義を修正・更新する役割はエンドユーザーの担当範囲でした。

![system.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110304/4249dd74-d57a-baaa-bfd3-845011d3516b.jpeg)

エンドユーザーとは協力しながらシステムを構築できていたと思います。担当者の方とはお互いに初めて参加するプロジェクトであり、システムの細かい動作については分からないことが多い状態でしたが構築を円滑に進められていましたね。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110304/6a670e91-1ab0-16ae-eafb-c559a804b3a2.png" width=30%>
**私「いい感じで構築できてますね！」**

そして、エンドユーザーが該当システムで使用しているシェルの中に**HULFTで受けたファイルが溜まり続けないようにファイルを削除するシェル**がありました。私は気を利かせて、担当外の作業でありましたが、午前0時くらいに実行すればいいなと、あまり中身を確認せず判断してしまったのです。
エンドユーザーは私にほとんど任せていて、最終的に`cron`により定期的に動作するように仕掛けました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110304/99a4fd2a-f3d1-5737-af17-1ebba1b41073.png" width=30%>
**私「ちょちょいのちょいっす～」**

そして、本番稼働後、事は起きました。
他システムで、私が担当したサーバーに対し`HULFT`の送信に失敗するアラームが発生したのです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110304/16006f5f-9fc1-a05f-9be2-dd120b251e39.png" width=20%>

# 惨劇はなぜ起こってしまったのか

相手システムの`HULFT`がエラーを起こした原因は、私が`cron`で仕掛けたファイルを削除するシェルが原因でした。
他システムからの`HULFT`受信とファイルを削除するシェルが同じタイミングで動作し、受けたファイルを他のシステムへ転送している途中でシェルがファイルを削除してしまったのです。

幸いにしてファイルを再送してもらうことでリカバリはできました。
しかし、本番ファイルを削除してしまうという事態に、私は真っ青になりました。
社会インフラを担うエンドユーザーの業種ということもあり、この時はこっぴどく怒られたのでした。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110304/1f13d89e-481f-d2c0-1cd4-0e36dffd6e37.png" width=60%>
**偉い人「何がどうなってるんだー、この野郎！！」**
**私「ひぇええ」**

# 二度と惨劇をおこさないためにどうしたのか

私はシェルの中身を見直し、そもそもシェルの使い方が間違っていることに気づきました。
シェルにはパラメーターとしてファイルの更新日からファイルを削除する日数までの指定ができたのでした。
そのため、以下の2つを改めました。

+ シェルのパラメーターを設定し、ファイルが削除されるまでの日数を指定する。
+ `HULFT`の転送が行われない時間帯にシェルを動作するようにする。

この処置により同様の障害が発生することはなくなりました。

# 真のやらかし

さて、私がやらかしてしまった**真のやらかし**はシェルの使い方を間違ったことではありません。
私の担当外であるユーザー資産を適用してしまった**役割分担のあいまいさ**にあります。

ユーザーとの役割分担は、要件を決めるときなどにはっきりしておくべきでありますが、ユーザーからの「やってくれるんだよね？」というプレッシャーであるとか、好意で「やっときますよ～」は時として大事故を起こす原因となります。

**かみ合わない役割分担**
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110304/1cff7a11-c4ce-2d8f-a334-2172d1666ebd.png" width=50%>

# 真のやらかしを二度と起こさないためにどうしたのか

では、二度と惨劇を起こさないためにどうしたか、というと、実はどうもしていません。今回の事はすぐに修正することができ、大事に至らなかったため、その当時、気に留める人は多くなかったと思います。
しかし、今回のような大事に至らなかったミスでも、ユーザー・ベンダー関係なく教訓として残したり、属人化せずに引き継ぐ文化があれば良かったと思います。残念ながら、このプロジェクトではそこまでの仕組みを築けませんでした。
そして、**私は役割分担のあいまいさについて多くの事を学ぶことができたのでした**。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110304/79ec75ab-bc0a-74cb-de31-52648ac08d03.png" width=40%>
**私(もう二度と手伝わないぞ。。。)**

# おわりに

昨今、金融機関で発生したトラブルがよく目につきますが、**私がやらかしたようなことにより**世間を騒がしているのかもしれません。このような事故を起こさないためにも、**ユーザーとベンダーが役割分担を明確にし、事故を未然に防ぐ文化を作り上げていくこと**が大事なのではないでしょうか。

**きっちりした役割分担**
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110304/43ba0cde-701f-5977-4b0e-1c742151e5af.png" width=50%>

**事故を未然に防ぐ協力体制**
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110304/fa0a43ae-0823-4324-2518-009a6eb63fe8.png" width=70%>
失敗から学ぶOSSの選び方（フロントエンド編）

2021/01 に迎えた FlashEOL のタイミング で Flash から Reactベースの画面へリプレースし、約1年間保守しました。
OSS にたくさん助けてもらいましたが、1年間を振り返ってみて今後の教訓を考えたいと思います。

# 前提
React + React Hook Form + TypeScript + material-ui + webpack という構成です。
初回のOSS選定は以下の観点で行いました。

- 学習コストが高くないか
  - 日本語の公式ドキュメントがあるか
  - ググったときに日本語の解説記事が豊富か
- コミュニティが活発か
  - GitHub の Star数が 1000 以上 (目安)
  - npm の ダウンロード数が 50000 以上 (目安)

## 1. 自動テストがだんだん遅くなってきた🤔
### 背景
自動テストをするため、Cypress を導入していました。
Cypress はテスト失敗箇所が画面上で確認できるため、初心のうちは見やすく重宝していました。

### 失敗
Cypress はデフォルトで直列実行されるため、テストケースの増加に対してテスト時間の悪化が顕著となりました。
そこで並列実行を考えましたが、なんと Cypress.io (CIサービス) 以外で並列実行が出来ない仕様でした。（そういうマネタイズなんですかね...）
対して jest はどこでも並列実行が可能なので移行しました。testing-library や enzyme など選択肢が多く敬遠していましたが、早く使っておけばよかった

### 教訓
テストライブラリを選ぶときは、テストケースが多くなっても開発効率に影響が出ないか確認/検証しよう。

## 2. OSSがメンテナンスされなくなった😱
### 背景
material-table は、material-ui をベースとしたテーブルコンポーネントです。
material-ui の公式ドキュメントで紹介されるほど人気があります。
(https://github.com/mui-org/material-ui/commit/e470b1ba9c234f16972749aa7c88d331ac9f46c1)
カスタマイズ性の非常に高いコンポーネントなので、開発しているプロジェクトの主軸となるライブラリとなっています。
グルーピング機能にはかなり救われました。

### 失敗
2020年夏ごろ、多くの不具合を残したままバージョン更新が止まってしまいました。
material-ui の公式ドキュメントからもいつの間にか紹介文が消されてしまいました😥
material-table は React V16 に依存しているため、React V17 に上げることが出来なくなってしまいかなり頭を悩ませるライブラリとなっています...

どうやらメンテナである mbrn 氏がメンテナンスできる状態ではなくなってしまい、他にメンテナもいないため保守できなくなったらしいです。
( https://github.com/mbrn/material-table/issues/3044 )
material-table-core というコミュニティによるフォークプロジェクトが立ち上がっていますが、まだまだStar数/ダウンロード数が少ないため見送っています。流行ってー

### 教訓
メンテナが1人しかいないOSSはある日突然更新が止まることがあるので、見送ろう。

# 結び
安定して継続的に使っていけるライブラリを選んだはずですが、1年経つと状況が変わってしまいますね。
フロントエンドのライブラリは栄枯盛衰が激しいですが、長く使っていけるかどうかをよく判断して選定していきたいです。
[JavaScript] 配列要素の追加方法

JavaScriptにおける配列要素の追加についてまとめておく。
今回サンプルとして使用する配列は以下としておく。

```javascript
const color = ["red", "white", "blue", "green"]
```
ちなみに```const```は再代入ができないが、今回紹介する```push()```などのメソッド操作は行うことができる。また、今回紹介する```push()```と```unshift()```は配列（今回では配列color）そのものへ要素を追加し、内容が変更されていまう破壊的メソッドであることに注意が必要である。

# 新しい要素の追加
###配列の末尾に追加
配列の末尾に1つ以上の要素を追加する場合は、```push()```を使用する。返り値は、追加後の配列の要素数。

```javascript
color.push("yellow","black");
console.log(color);    // [ 'red', 'white', 'blue', 'green', 'yellow', 'black' ]
```

###配列の先頭に追加
配列の先頭に1つ以上の要素を追加する場合は、```unshift()```を使用する。返り値は、追加後の配列の要素数。

```javascript
color.unshift("yellow","black");
console.log(color);    // [ 'yellow', 'black', 'red', 'white', 'blue', 'green' ]
```

###配列の指定位置に追加
配列の指定位置に追加したい場合は、```splice()```を使用する。```splice()```の引数は以下となる。
***第一引数***：配列の追加・削除を行う位置（負の数で配列末尾から引いた位置も指定可）
***第二引数***：削除する要素数（今回は追加のため```0```を指定）
***第三引数***：追加する要素
返り値は、削除された要素の配列が返される。削除されない場合は空の配列が返される。

```javascript
const result = color.splice(2,0,"yellow","black");
console.log(color);    // [ 'red', 'white', 'yellow', 'black', 'blue', 'green' ]
console.log(result)    // []
```

今回は要素の追加だけを取り上げたが、```splice()```は要素の置き換えや削除も行うことができる。
GoogleAppEngineでCloud SchedulerからのHTTPリクエストのみを受け付ける

## 概要

アプリの開発にGCPを利用しています。

その中で、定期実行させたい処理を、CloudScheduler→AppEngineで行っています。

CloudSchedulerからAppEngineに対してHTTPリクエストを送るのですが、その際にAppEngine側ではCloudSchedulerからのリクエストのみを受け取るようにしました。

## 実装方法

HTTPリクエストのヘッダを参照して、CloudSchedulerからのリクエストであるかどうかを判定します。

この時、CloudSchedulerからのリクエストであれば、`X-Appengine-User-Ip`というヘッダが`0.1.0.2`であると言うことを利用します。

1. Cloud Taskで、受け取ったHTTPリクエストのヘッダを参照する。
2. 1から、Cloud Schedulerが送信したHTTPリクエストであるかを判定する。
3. 2が真であった時のみ、処理を実行する。

```python
from flask import Request
from flask import request

def check_request(request: Request) -> bool:
"""リクエストがGoogleCloudSchedulerからのものであるかを確認する
'"""
gae_ip = request.headers.get("X-Appengine-User-Ip")
if not gae_ip or not gae_ip.startswith("0.1.0.2"):
     return False
else:
    return True
```

## なぜこの方法にしたのか

どうやったらCloudSchedulerからのHTTPリクエストのみを受け付けられるか考えていました。

そこで、Cloud SchedulerからAppEngineにHTTPリクエストを送信したときのヘッダーを調べてみることにしました。

ヘッダーを出力してみたところ、下記のように`X-Appengine-**`や`X-CloudScheduler-**`といったヘッダーが付与されています。

```shell:HTTPリクエスト抜粋
'Host': 'XXX', 
'X-Forwarded-For': '0.1.0.2, 169.254.1.1', 
'X-Forwarded-Proto': 'http', 
'Forwarded': 'for="0.1.0.2";proto=http', 
'Content-Length': '0', 
'User-Agent': 'AppEngine-Google; (+http://code.google.com/appengine)', 
'X-Cloudscheduler': 'true', 
'X-Cloudscheduler-Jobname': 'XXX', 
'X-Appengine-Country': 'ZZ', 
'X-Cloud-Trace-Context': 'XXX1', 
'Traceparent': 'XXX', 
'X-Appengine-Timeout-Ms': '599998', 
'X-Appengine-Https': 'off', 
'X-Appengine-User-Ip': 'XXX', 
'X-Google-Internal-Skipadmincheck': 'true', 
'X-Appengine-Request-Log-Id': 'XXX', 
'X-Appengine-Default-Version-Hostname': 'XXX'
```

[CloudSchedulerのレファレンス](https://cloud.google.com/scheduler/docs/reference/rest/v1/projects.locations.jobs#appenginehttptarget)にも書かれていますが、これらの特殊なヘッダーはGCP内部用のヘッダーのようです。

今回はこの中から、`'X-Appengine-User-Ip': '0.1.0.2'`を利用することにしました。

これについて詳しく調べてみると、[GCPのAppEngineファイヤーウォール](https://cloud.google.com/appengine/docs/flexible/java/understanding-firewalls?hl=ja#allowing_incoming_requests_from_your_services)のガイドにも書いてありました。

GCPのサービスから送られるリクエストは、IPアドレスの範囲が決まっており、CloudSchedulerのジョブによるリクエストは、`0.1.2.2/32`とあります。

`0.1`で始まるIPアドレスってとても珍しいですよね。
マークダウン=HTMLだと思っていた

##今まで#とかではなくて全部タグで書いていた
こちらの記事は今年のはじめに書いた記事なのですが、マークダウンというものを知らずに、「ああ、HTMLを書くのか」とか思いながら記事を書いていました。

https://qiita.com/Teba_eleven/items/a962cd21bce13aceee03

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/964269/77eb4c87-fa95-2cfe-caf8-5b1bb1807a82.png)
なので、Qiitaで記事書くのめんどくさいなぁなんて思っていたのですが、最近Zennでマークダウンのチュートリアルを見た時に、マークダウン記法便利やなぁとか思ってZennで書いていたのですが、これってQiitaでもできるのではと気づいたのがここ数日の話です。
connpassのページもHTMLタグで書いていたのですが、こちらもマークダウンでいけると気づいた時は発狂しかけました…。

##マークダウン、めっちゃ便利よね…
HTMLだと文字を挟む必要がありますが、マークダウンだと片方だけで済む！！！
この感動は、N予備校のプログラミングコース、Expressを使ったWebアプリ制作の時に導入したpugというテンプレートエンジンを初めて使った時の感動に似ています。（pugもめっちゃ簡単に書けて本当に好き）

##まとめ
マークダウンは便利。
##P.S.
pug最近使ってないので使いたい。（動く仕組みがわかっていない）
【Ruby】trimしたいときはstripしよう

##strip
Rubyには```trim```メソッドがないので代わりに```strip```メソッドを使う。

**文字列先頭**と**末尾の空白文字**を全て取り除いた文字列を生成して返す。
空白文字の定義は```" \t\r\n\f\v"```
文字列右側からは```"\0"```も取り除くが、左側の```"\0"```は取り除かない。

```ruby
pry(main)> p "   s".strip
=> "s"
# 文字と文字の間の空文字は取り除かない
pry(main)> p "   s  f  ".strip
=> "s  f"
pry(main)> p "   s  f\n".strip
=> "s  f"
pry(main)> p "\0  s  f\0".strip
=> "\u0000  s  f"
```


##参考

https://docs.ruby-lang.org/ja/latest/method/String/i/strip.html
【Radzen.Blazor】@bind-valueってなにもの？

#概要
Radzen.Blazorのテンプレートを見てると、たびたび出てくる`@bind-value`というオプションですが、リファレンスで検索してもひっかかりません…
一体こいつは何者なのでしょうか…？

Radzen.Blazorのテンプレート　→　https://blazor.radzen.com/datagrid
Radzen.Blazorのリファレンス　→　https://blazor.radzen.com/docs/api/Radzen.Blazor.html

#@bind-valueとは
@bind-valueとは、`Radzen.Blazorコンポーネントに関連付ける変数を指定するオプション`になります！

…詳しく説明します。

##①@bind-valueには変数を指定することができ、値を指定することはできない。

```bind-value.razor
// 変数を指定することができる
<RadzenTextBox @bind-value="@sample"/>

// エラー：値を指定することはできない
// Tha assignment target must be an assignable variable, property or indexer
<RadzenTextBox @bind-value="100"/>

@code
{
    string sample = "100";
}
```

##②コンポーネントは@bind-valueを参照し、コンポーネントに入力した値は@bind-valueに代入される。
```bind-value.razor
// ページ起動時、@bind-valueの値を参照する
// コンポーネントに入力した値は、@bind-valueに代入される
<RadzenTextBox @bind-value="@sample"/>
<h3>@sample</h3>

@code
{
    string sample = "100";
}
```


##③コンポーネントのTValueと型が一致する必要がある。

```bind-value.razor
// エラー：TValueと@bind-valueの型を一致する必要がある
// InvalidCastException: Unable to cast object of type 'System.String' to type 'System.Int32'.
<RadzenNumeric TValue="int" @bind-value="@sample"/>
<h3>@sample</h3>

// 対処法：ValueやValueChangedを使用することで同様の処理を実行できる
// Valueコンポーネントがページ起動時に参照する値
// ValueChanged：コンポーネントに値を入力したときに実行する処理
<RadzenNumeric TValue="int" Value="@int.Parse(sample)" ValueChanged="@(args => sample = args.ToString())"/>
<h3>@sample</h3>

@code
{
    string sample = "100";
}
```

#まとめ
@bind-valueオプションは次のような場面で活用できると思います。

* Radzen.Blazorコンポーネントに入力する値を動的に決定したいとき
* Radzen.Blazorコンポーネントを複数使用するとき
* etc…

自分の経験に基づいて書いたものなので、細かい表現など適切ではない場合があります。
間違ってる部分が見つかりましたら、コメントで指摘していただけますと幸いです。
bashコマンド実行結果をvimで開く

なにかのコマンドをbashで実行した結果を編集したい場合、一旦結果をリダイレクションなどでファイルに保存し、そのファイルをvimで開いて編集していたが、なんかもう面倒くさくなったので、結果をそのままvimで開くスクリプトを書いた。
もうすでにあって、盛大に車輪の再発明をしている感はナキニシモアラズなのだが、自分の備忘録としてポエムとして残しておく。

※ コメントで遠回りを指摘していただいたので修正。

```bash
#!/usr/bin/env bash

if [ "$1" = "" ]; then
  echo "Usage:"
  echo `basename $0`" [execute command]"
  exit 1
fi

vim <("$@")
```
新卒でゲームテスト会社に入社して感じたギャップ

#はじめに

皆様はじめまして！ 
AIQVE ONE株式会社でテスターをしております@murakichiと申します。 
AIQVE ONE ゲームテスト/QA Advent Calendar 2021の16日目は私が担当させていただきます！ 
 
私は2021年4月に新卒としてAIQVE ONE株式会社に入社しました。 
早いもので、もう8か月が経過し、時の流れの恐ろしさを感じる日々です…。（2021年12月現在）
（ちなみに私は「ゲームが大好き」という気持ちだけでゲームテスト業界に飛び込んだため、学生時代にゲーム関係の勉強をしていたわけではありません。）
<br>
私のような新米にはテストに関する技術的なお話は難しそうだったため、
 **「新卒でゲームテスト会社に入社して感じたギャップ」**というテーマでお話させていただきます。

そのためこの記事は業界歴が長い方より、まだゲーム業界に触れたことが無い方が対象になると思います。前提として、私はゲームテスト会社をAIQVE ONEしか経験したことが無いため、**あくまで本記事で書かれていることは、当社の場合の話、そして私個人の感想になります**。 
そんなことも知らずにゲームテスト会社に入ったの？と思われる部分があった場合は、温かい目で見守っていただけると嬉しいです。


#ゲームテスト業界の印象
先ほどからゲームテスト業界、と言っていますが、世間一般ではゲームデバッグという言葉の方が馴染みがあるのではないかと思います。 
ゲームデバッグ、ゲームテスト業界の印象としてよく挙げられるのは

・1日中ゲームが遊べる 

・残業が多く体力勝負 

・男性が多い 

このあたりでしょうか？ 
ゲームということで**楽しい**というイメージがある反面、**体力勝負、同じ作業の繰り返し**、といった大変なイメージを持っているという話もよく耳にします。 

私も上記のようなイメージを持っていましたが、実際ゲームテスト会社に入社してどのようなギャップを感じたかを4点紹介していきます。 

>ちなみにデバッグという言葉は、ゲーム業界では 
**デバッグ＝バグを見つける**
で浸透していますが、ゲーム業界以外では 
**デバッグ＝バグを見つけて修正する**
という意味で使用されるという事実も、入社後に知って個人的に驚いた点です。

#4つのギャップ
###ギャップ①：ひたすら好きなようにゲームを遊ぶわけではない
ゲームテスターという職業の魅力の一つは、「主にゲームをプレイすることが仕事」というところだと思うのですが、実際入社してみると、みなさん**好きなようにゲームをプレイしているわけではないんだな**、とわかりました。

弊社はソフトウェアテストの手法に則り、テスト計画、テスト設計、テスト実行などしっかり段階が踏まれています。ソフトウェアテストとは、コンピュータ上で動作するソフトウェアに対し、期待どおりに動作することを実証したり、欠陥や想定外の動作を検出したりする活動のことを意味します。**弊社の実際のテストでは、テストケースというテストをするための手順書が用意されており、それに沿ってゲームを操作します。**
世間一般に浸透している「手あたり次第プレイしてバグを発見する手法」はフリーテストと呼ばれ、弊社でも使用されていますが、そればかりやっているわけではありませんでした。

**ソフトウェアテストは資格も存在するくらいビジネス的に有効な知識なので、ゲームテスターがやりたい方は勉強していて損は無いと思います。**
さらに弊社ではゲームテストの自動化にも取り組んでいるため、Pythonなどのプログラミングにも触れることができます。ゲームをテストする上でゲームの仕組みを知っておくと、より有効なテストができると思いますので、**プログラミングの知識があると便利**だなと感じました。

つまりは、思ったより勉強することがいっぱいありましたということですね！！

###ギャップ②：残業が少ない
**あくまで弊社の、私が今まで関わってきた案件の場合です！！！**
ゲーム業界のあまり良くないイメージの最たる例が「残業が多そう」だと思います。私も入社するまではそのイメージを持っていましたし、家族や知り合いにはいつもその点を心配されています。

残業に関しては、弊社も全くないわけではありませんが、**残業だらけで現場が疲弊する、といった雰囲気はありませんでした**。テスターの稼働人数や稼働時間によってお客様に請求するお金が変わってくるため、残業をするにはお客様の許可が必要になります。そのため無暗に残業できないのだということを入社後に知りました。それもあって、きちんと決まった日数で決まった範囲をテストすることが求められるため、進捗管理、スケジュール管理は徹底されています。 

###ギャップ③：女性が多い

弊社の男女比は3:2です。 
私は5:1くらいを想像していたので、予想以上に男女比が半々で驚きました。 
弊社では拠点によっては女性の方が多かったりもします。 

昔はゲームは男の子がするもの、といったイメージが強かったですが、 
今は時代が変わって男女共にゲームで遊ぶのが当たり前になっているので、そのあたりが影響しているのかもしれません。 

ギャップ②でも述べましたが、イメージより残業や体力勝負な面が少ないため、他の業界と変わらない男女比になっているのかも…このギャップに関しては全体的に推測しかできません💦 

###ギャップ④：ゲーム開発の勉強になる

ゲームテスターからゲームプランナーなど、テスターから開発側に回る話は珍しくありませんが、その理由が実際に働いてみてわかりました。
 
ゲームテスターは様々なゲームの仕様書を見ることができます（業務上必要な範囲内で）。 
仕様書は普通の人はまずお目にかかれない代物ですが、ゲームがどうやってできているのかを知るうえでとても重要です。**いろいろな仕様書を見ることができるということは、いろいろなゲームの仕組みを知ることができるということなので、非常にゲームの勉強になります**。

さらに、いろいろな案件にアサインすることによって、普段自分がプレイしないようなジャンルのゲームもプレイできるため、ゲームに対する知見が広がると感じました。 
**初めからゲームテスターを目指していない人でも、ゲーム業界に携わりたいのなら一度はゲームテスターを経験しておくのはとても良い経験になると思います**。 

#おわりに
以上、新卒でゲームテスト会社に入社して感じたギャップでした！
あまり中身のある内容にすることができませんでしたが、「業界歴8か月の人だし、まだまだこれから！」と多めに見ていただけると助かります…。

この記事を読んで、少しでもゲームテスト業界も良いかも、と思っていただけると嬉しいです！
閲覧いただきありがとうございました！
デバイスドライバ とは

## 勉強前イメージ

HDDを入れるドライバ的なイメージだったけど違うのかな？

## 調査

### デバイスドライバ とは

デバイスドライバは単純にドライバとも呼ばれることもあります。
PCに接続されている機器をOSから使用できるようにするプログラムになります。

PCはマウスやスピーカーを接続しただけじゃ使えません。
`PC - デバイスドライバ - マウス` といった周辺機器を繋ぐ架け橋になります。
イメージ的には以下がドライバになります。

![1Untitled Diagram.drawio - diagrams.net - Google Ch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/ba1cf3f7-bfb5-5c1b-e94a-61a776cccd4f.png)


マウスつないだときにドライバなんてインストールしてないよ！って言うかもしれませんが
デバイスドライバはハードウェア(周辺機器)のメーカーが提供しておりデフォルトで搭載されているものは元々入っていることもあります。
また、windows95以降はデバイスドライバをシステムへ組み込むことを自動的に行うようになったので
自動的に入ってることもあります。
たまにマウスやスピーカーを購入した際にCDがついてくることもありますが、それがドライバになります。
また、キーボードやマウスなど機種毎の機能や仕様が小さい場合は
共通の仕様が定められていて、OSの標準ドライバで使用できることが多い。

以下がwindowsのデバイスマネージャーになります。
例えばカメラだとこちらが反応してますが、どちらかをクリックすると `ドライバーの更新` と出ます。
このカメラに関してドライバがある感じです。

![1デバイス マネージャー 2021-12-02 19.09.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/b264160b-28fa-9c57-6461-ae8b91d5b015.png)

## 勉強後イメージ

HDDだけじゃなくて周辺機器を接続するのをドライバっていうのね。
確かにUSBを接続すると最初は自動的にインストールしてるよね。
たまに古すぎると使えないってことはドライバがOSに対応していないってことか。

## 参考

- [デバイスドライバ 【device driver】 ドライバソフト / driver software](https://e-words.jp/w/%E3%83%87%E3%83%90%E3%82%A4%E3%82%B9%E3%83%89%E3%83%A9%E3%82%A4%E3%83%90.html)
- [OSとハードウェアの橋渡し](https://www.pc-master.jp/words/driver.html)
スマホ充電器つけっぱなしでもリチウムイオン電池を長持ちさせる充電システムを作ってみた

#使わなくなったスマホを再利用する
どこのご家庭にも転がっている使わなくなったスマホを再利用する事がよくあります
ウチでは見守りカメラとかカーナビとかで活躍してます
見守りカメラでは、充電器つなぎっぱなしで運用する事になり
ずっとバッテリー100%のままになり、リチウム充電池の寿命が短くなってしまう
(-＿-)ｳｰﾑ　どげんかせんといかん

#リチウム充電池の寿命を延ばす方法
ネットで検索すると色々な扱い方が出てきます
[スマホ・ノートPCなどのリチウムバッテリーの寿命を延ばす方法](https://gigazine.net/news/20150127-prolong-li-battery/)では
　-過放電や過充電しない
　-温度を低く保つ
　-充電電圧は4.2V以下に抑える
　-保存時は40%程度充電しておく
といった注意点を挙げています

また具体的な運用方法については、
スマホ80%充電機能とか手動で過充電に気を付けましょうとかで～
充電しっぱなしで自動運用する方法は見つかりませんでした
という事でダメージの少ない充電方法を考えてみました

#充電タイマー作ってバッテリー満充電させない作戦
スマホのバッテリー管理機能でバッテリー残量アラートが鳴ったら
一定時間充電するという方法を考えてみた

ウチにあった [なのぼ～どAGマイコン](https://tiisai.dip.jp/?page_id=935)のマイク入力でアラート音を拾って、MOSFETでUSB電源を二時間ONにする様パッチする
![micschmod.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106489/800dac31-2418-2afb-5bd9-c9eb3b9f6291.png)

####パッチ内容
1) マイクを外してピンを立てる
2) マイクのプルアップ抵抗10Kを外す
3) USBメスコネクタを追加　GNDを接続
4) Pch MOSEFT SI2301を追加　ゲートをD13、ソースをVCC、ドレインをUSB出力へ
![NBAGpatch.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106489/01f05fa9-48bd-da33-3938-4cc485b1c226.jpeg)

####配線
-マイク端子をスマホイヤホンジャックに接続
-USBメスコネクタをスマホUSBに接続
-なのぼ～どAGのUSBミニB端子をUSB電源アダプタに接続
![IMG20210911072050a.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106489/305c75d7-bf7e-88e7-0a5b-ef5ad686881b.jpeg)



####コードはArduinoでサラッと書いた

マイク入力のレベルを監視して、検知したら120分間USBパワーONに～

```c++:chargetimer.ino
/*
  Charge Timer
  Andriod Battery charging TIMER
  Charge few hour when battery alart ring. 
  Long life floating charging between 20% and n0%
  by @tomonnn1
 */
 
// Pin 13 has an LED connected on most Arduino boards.
// give it a name:
int led = 13;
int usbp = 11;
int DELEYMINNTS = 120;

// the setup routine runs once when you press reset:
void setup() {                
  // initialize the digital pin as an output.
  pinMode(led, OUTPUT);     
  pinMode(usbp, OUTPUT);  
  digitalWrite(led, LOW);   // turn the LED off 
  digitalWrite(usbp, HIGH);   // turn the USB power off
  
}

void usbpower() {
  digitalWrite(led, HIGH);   // turn the LED on
  digitalWrite(usbp,LOW );   // turn the USB power on 
  for( int i=0; i< DELEYMINNTS; i++) delay(60000);     // wait for a minits
  digitalWrite(led, LOW);   // turn the LED on 
  digitalWrite(usbp, HIGH);   // turn the USB power on
  delay(1000);               // wait for 5 second
}

// the loop routine runs over and over again forever:
void loop() {
  if(analogRead(A0)>30)
    usbpower();
    delay(50);
}

```
DockerコンテナにDockerfileの変更が反映されない

# はじめに
現在、Web系自社開発企業への転職を目標にポートフォリオを作成中。
Dockerを活用してLEMP環境を構築し、Laravel+VuejsでWebアプリケーションの開発を行っております。
Dockerコンテナのnode.jsのバージョンを変更させるために、Dockerfileを編集した際に
Dockerfileの変更がコンテナに反映されないという問題で少しつまづいたので、記録として残します。

# 目次
<!-- タイトルとアンカー名を編集 -->
1. [やりたいこと](#Chapter1)
1. [やったこと](#Chapter2)
1. [原因](#Chapter3)
1. [解説](#Chapter4)
1. [解決策](#Chapter5)
1. [参考文献](#reference)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# やりたいこと
Dockerfileを編集して、DockerコンテナのNode.jsのバージョンを変更したい

<a id="#Chapter2"></a>
# やったこと
Dockerfileを編集

変更前

```Dockerfile:Dockerfile
# install Node.js
COPY --from=node:10.22 /usr/local/bin /usr/local/bin
COPY --from=node:10.22 /usr/local/lib /usr/local/lib
```

変更後

```Dockerfile:Dockerfile
# install Node.js
COPY --from=node:16.13 /usr/local/bin /usr/local/bin
COPY --from=node:16.13 /usr/local/lib /usr/local/lib
```

コンテナの停止

```
docker compose stop
```

コンテナの作成・起動

```
docker compose up -d
```

Node.jsのバージョンを確認

```
docker compose exec app node -v
v10.22.0
```
Dockerfileの変更が反映されなかった

<a id="#Chapter3"></a>
# 原因
Dockerfileを変更する前のイメージを参考にしてDockerコンテナを作成、起動したから

<a id="#Chapter4"></a>
# 解説
DockerコンテナはDockerイメージを参考にして作成される
そして、このDockerイメージはDockerfileを参考にして作成されるため
Dockerfileの変更をDockerコンテナに反映させるためには、Dockerイメージの作成から実行する必要がある

<a id="#Chapter5"></a>
# 解決策
buildしてDockerイメージを作成

```
docker compose build
```

Dockerコンテナを作成、起動

```
docker compose up -d
```

Node.jsのバージョンを確認

```
docker compose exec app node -v
v16.13.0
```
無事、Dockerfileの変更がコンテナに反映された

<a id="#reference"></a>
# 参考文献
- [Docker利用時のソースコードの変更反映](https://qiita.com/tearoom6/items/326895f0a35774d70729)
- [Dockerfileの変更が反映されない](https://scrapbox.io/ebiken/Dockerfile%E3%81%AE%E5%A4%89%E6%9B%B4%E3%81%8C%E5%8F%8D%E6%98%A0%E3%81%95%E3%82%8C%E3%81%AA%E3%81%84)
Macでgtkwaveをコマンドラインから起動する

[VHDLの環境構築](https://zenn.dev/takumura/articles/83618f8f0386b8)をサイトの通りにやっていて、gtkwaveのコマンドラインからの実行で詰まったのでメモ。

# 環境
m1 macbook air(2020)
brewでgtkwaveをインストール

#　エラー内容
```
/opt/homebrew/bin/gtkwave: line 122: test: too many arguments
/opt/homebrew/bin/gtkwave: line 149: test: ==: unary operator expected
find: /share/locale: No such file or directory
/opt/homebrew/bin/gtkwave: line 215: /opt/homebrew/bin/../../../Contents/Resources/bin/square.vcd: No such file or directory
/opt/homebrew/bin/gtkwave: line 215: exec: /opt/homebrew/bin/../../../Contents/Resources/bin/square.vcd: cannot execute: No such file or directory
```

# 対応
perlでSwitchというやつを入れる。macにperl(とそのライブラリマネージャ的なやつ？のcpan)は元から入ってる。

```zsh
cpan install Switch
perl -V:'installsitelib'
```

んで、どこかにインストールされたSwitch.pmてやつを、/Library/Perl/5.30/に移す。
自分の環境では~/perl5/lib/perl5/にあったので、下のコマンドを実行。

```zsh
sudo cp ~/perl5/lib/perl5/Switch.pm /Library/Perl/5.30/
```

このままだとまだコマンドにgtkwaveと打ち込んでも動作しない。
各々使っているシェルの設定に次のPATHを追加してください。

```~/.zshrc
export PATH= /Applications/gtkwave.app/Contents/Resources/bin/:$PATH
```

# 動作

```
gtkwave sample.vcd
```

とかで動作したよ。
最後に、適当に作ったスクリプト貼っときます。

```vhdl_build.sh
# /bin/sh

ghdl -a --ieee=synopsys $1
VHD=$1
VCD=${VHD%.*}.vcd
ghdl -r --ieee=synopsys ${VCD%.*} --vcd=$VCD
gtkwave $VCD
rm $VCD
```

# 参考（ほぼこの記事のまんまです）
https://ughe.github.io/2018/11/06/gtkwave-osx
戻るボタンを実装したらdropdownが動かなくなった

##概要
戻るボタンを実装しようと思い、

```
 <%= link_to :back do %>
   <button type="button" class="btn btn-info">戻る</button>
 <% end %>
```
と書いてみた。

すると、この戻るボタンからページを変遷させると、ヘッダーにあるdropdownが動かなくなってしまった。

##調査
調べてみると、このコードは自動的にjsを呼び出しているらしい。
turbolinksを無効にすれば実装できるかもしれない

ということで

##解決方法

```
       <div data-turbolinks="false">
          <%= link_to :back do %>
            <button type="button" class="btn btn-info">戻る</button>
          <% end %>
        </div>

```


```
<div data-turbolinks="false">
```
で囲んであげると解決できました。
jsが呼び出されることとturbolinksの関係についてはまだ理解できていないので
もっと勉強したいと思います。。
【Jest】findAllとfilterを使い、Component内に特定の要素が表示されないことをテストする【Vue】

## この記事で説明すること

表題の通りです。
例えば、「```v-if``` で制御している箇所が```else```の場合に表示されないこと」をテストしたい時に使える方法です。

```findAll``` と ```filter``` を使います。

## テスト対象のコンポーネント

```Sample.vue

<template>
  <div>あああ</div>
  <div>いいい</div>
  <div>ううう</div>
  <div>えええ</div>
  <div>おおお</div>
</template>

```

※適当ですみませんw

## テストを書いてみる

例えば、「かかか」という要素が表示されないことをテストしたい時は、以下のように書きます。


```sample.spec.ts

// ..
const wrapper = mount(Sample)
expect(wrapper.findAll('div').filter((w) => w.text() === 'かかか').length).toBe(0);

// ..
```

## ちょっと解説

```findAll('div')``` で```div```要素を全て返す
```filter((w) => w.text() === 'かかか')``` で```text```に**かかか**を持つ要素を返す

まとめると、上記で空のWrapperArrayを返してくれるので、「lengthが0」であるテストを書いてます。

```findAll('div').at(6).isExist() ```などでも書くことができますが、```at```で指定してしまうと、div要素の数が変わった時にテストも修正しなければいけなくなってしまう（+書き方がイケてない）ので、上記の書き方の方が良いかなぁと思います！


## 参考

[公式 - filterについて](https://vue-test-utils.vuejs.org/ja/api/wrapper-array/#filter-predicate)
Python3でCGIチャレンジ3　ファイル読み込み

#前提
Python3でCGIチャレンジ2後

#作業フォルダ
ps1

#作業

##index.htmlを修正。

```html:index.html

<html>
<head><meta http-equiv="content-type" charset="UTF-8"></head>
<body>
  <form action="/cgi-bin/sample.py" method="POST">
   入力1<input type="text" name="foo">
   入力2<input type="text" name="bar">
   <input type="submit">
  </form>

<!-- ここから追記 -->
  <form action="/cgi-bin/readFile.py" method="POST">
    <input type="submit" value="ファイル内容表示">
   </form>
<!-- ここまで追記 -->


</body>
</html>
```

##readFile.pyを作成。cgi-bin配下に。

```python:readFile.py

import cgi
import cgitb
cgitb.enable()

print("Content-Type: text/html")
print()   

# どうやらプログラムから見た相対パスではなく、index.htmlからの相対パスらしい（要確認）
file_name = "./file.txt"

try:
    f = open(file_name, 'r', encoding='UTF-8') 
    data = f.read()
    print(data)

except Exception as e:
    print(e)
finally:
    f.close()

```

##ターミナルでコマンド実行して、ローカルでCGIサーバーを起動する。

```
python -m http.server --cgi 8000
```

##ブラウザで確認

[http://localhost:8000]

#結果

ファイル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401158/9264b639-6d3c-585e-98d8-c379868ef3b5.png)

ブラウザ
追加したボタンが下にある。押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401158/c5e1f178-279a-92d3-077e-72bbe524eb67.png)

ファイルの内容が表示されている
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401158/efb891fb-659d-edea-fb49-25cc1226e225.png)


#理解したこと

- ボタン名の変更方法
- 何故かファイルの中身は直列で取得される（改行コード無視？）
 

#情報源
Googleで「Python3 ファイル読み込み」で上から順に試した。
研修で色んなことやった

##初めに
内定先研修？(バイト)で内定先で夏休みから少しづつ働いてきたのでどんなことやったのーだとかこれ大変だったなぁとかを話す会
#目次
- C#以外の言語を触った感想
- 今は何してんの？
- 大変だった話、苦労したこと
- ゲーム会社で少し働いた感想

###C#以外の言語を触った感想
とりあえずやった言語が PHP.MySQL.Jsva.Python.Linux　この5言語を研修で触りました。
PHPで困ったこと変数名に　$をつけないといけないところ
Javaで困ったこと何も定義されてないときはnullではなくundefinedだというところ
MySQL.Linuxはほとんど学校で習った基礎的な内容
Pythonは簡単に書きすぎて他の言語書くときに困った(セミコロンつけないとか、ifとかforに｛｝いらないので付け忘れたりとか)

###今は何してんの？
細かくは言えないですが、負荷テストの処理書いてたりしてます(もうほぼ終わった)
LocustっていうPythonでコードを書いてそのコードに〇〇人って人数を流したらどれくらい負荷がかかっているか見れるやつ
LaravelはPHPのワークフレーム、一番人気らしい

左が__Locust__            右が__Laravel__

<img width="200" alt="Locust.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1268440/ff735b79-ad7b-2b43-5a5f-cf95b1e1fdfc.png"><img width="300" alt="laravel.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1268440/ec37b3b9-a914-a689-f2a2-473f8ed5c9a4.png">

###大変だった話、苦労したこと
大変だったのが**わからないことがわからない**です。
具体的に言うとUnityだと〇〇っていう処理作る時にある程度知識があるからわからなくても簡単に調べれるけれど
全く知識のない言語で作り方がわからない場合どうやって作ればいいか**わからない**。どうやって質問すればいいか**わからない**というなにがわかっていて何がわからないのかがわからない。ﾜｶﾗﾝﾜｶﾗﾝ(´;ω;｀)ってなってました
このﾜｶﾗﾝﾜｶﾗﾝ状態で質問をしても何が聞きたいのかわからないという相手もﾜｶﾗﾝﾜｶﾗﾝという最悪の状況が生まれます。
その時にマネージャーに教えてもらったのが**エンジニアとして痛感した「良い質問」と「悪い質問」**という記事
https://hara-chan.com/recommend/se-good-bad-question
わからないのは当たりまえなのでどんどん先輩に頼っていこうって話
(のび太君は社会人適正あったらしい)
<img width="250" alt="nobita.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1268440/21e9616e-2172-ca93-1781-18bc0d02f167.jpeg">
この記事を見てからは抽象的な質問を
することはなくなりました。万歳(/・ω・)/

###ゲーム会社で働いた感想
ゲーム会社は圧倒的自由
作業中音楽聞いててもいいし、お菓子食べてもいいし、飲み物飲んでもいいし。。。
あとチャットがすごいラフというかギャグ挟んだりしながら会話してくたりいい意味で話しやすい環境を作ってくれている
わからない所をチャットに書いたらすぐに返信くれるし、チャットじゃ理解できなかったら口頭で教えてくれるし
一番いいのが飲食店のバイトと違って体が疲れない！8時間働いても時間があっという間
CODEの23卒の人へ入社待ってます(#^^#)
【IPFS】ファイルの CID をオフラインで取得する【daemon 起動させずに】

> [CI](https://ja.wikipedia.org/wiki/%E7%B6%99%E7%B6%9A%E7%9A%84%E3%82%A4%E3%83%B3%E3%83%86%E3%82%B0%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3) や [CD](https://ja.wikipedia.org/wiki/%E7%B6%99%E7%B6%9A%E7%9A%84%E3%83%87%E3%83%AA%E3%83%90%E3%83%AA%E3%83%BC) などでドキュメントを自動更新する際に、[IPFS](https://qiita.com/tags/ipfs) で公開予定のコンテンツの [CID](https://docs.ipfs.io/concepts/content-addressing/) だけを取得したい。できればサーバ負荷の軽減のため `daemon` の起動はせずに取得したい。

## TL; DR <sub><sup><sub><sup>（今北産業）</sup></sub></sup></sub>

- `--offline` `--only-hash` `--quieter` オプションを使う（確認: `ipfs` v0.10.0）

```bash:ハッシュ値の計算のみ行う
ipfs add --offline --only-hash --quieter <file path>
```
```shell-session:実行例（CIDの値のみ表示）
$ ipfs add --offline --only-hash --quieter /path/to/myFile.txt
QmWBf2hYCzFWtQp5w5NLD3oVSdV6nmdvFAdG4KGgsoBMNh
```

## TS; DR

以下は Docker（`docker-compose`）を使った例です。直接 `ipfs add ...` を叩いて取得してもいいのですが、GitHub Actions など Docker の入っている環境でゴニョゴニョしたい場合の参考にしてください。

`go-ipfs` の Docker イメージは 83 MB 程度です。CID 取得のためだけに、ローカルに Go や [Kubo](https://github.com/ipfs/kubo)（旧 `go-ipfs`） をインストールするより楽だと思います。

```shell-session:ディレクトリ構成
$ tree
.
├── data
│   └── myFile.txt
├── docker-compose.yml
└── entrypoint.sh
```
```text:/data/myFile.txt
Hello, Qiita!
```

```yaml:docker-compose.yml
version: "3.9"
services:
  getcid:
    image: ipfs/go-ipfs:latest
    volumes:
      - .:/workspaces
    working_dir: /workspaces
    entrypoint: [ "/workspaces/entrypoint.sh" ]
```

```bash:entrypoint.sh（要実行権限）
#!/bin/sh

set -eu

ipfs init 2>/dev/null 1>/dev/null
ipfs add --offline --only-hash --quieter "$1"
```

```shell-session:実行例
$ docker-compose run getcid ./data/myFile.txt
QmeYx6fTDLj63JWRwYMEAPs9DqGkXKKUDuYeZMuh7SRXj3
```

## 参考文献

- ["ipfs add" calculate CID and check for it *before* uploading to API server.](https://github.com/ipfs/go-ipfs/issues/7586#issuecomment-674194590) | Isses | go-ipfs @ GitHub
- [ipfs add](https://docs.ipfs.io/reference/cli/#ipfs-add) | CLI | Reference @ docs.ipfs.io
ApexメッセージをVisualforceで表示させる【備忘録】

##はじめに
社会人1年目のyappiです！
3月ぐらいSalesforce認定 上級デベロッパー試験を受けようと現在学習をしてます！(厳しそうですが...)
最近はずっと問題集を解いているんですが、Apexの名前空間やVisualforceのコンポーネントが多すぎてわからない！！って感じで問題集を解いてます。

ApexメッセージをVisualforceに出力させるコンポーネントの違いがいまいちわからなくて...。
今回は、調査した内容と参考になったページを参考に備忘録として残しておきます。

##コンポーネントとその特徴
ApexメッセージをVisualforceに表示させるためには以下のコンポーネントが使用できます。
今回細かすぎて違いがわからないと感じた4つのコンポーネントたちです...。

```
<apex : pageMessage>
<apex : pageMessages>
<apex : message>
<apex : messages>
```

見た目の違いとしては、**_page_**が付いているかどうかというのと、**_s_**が語尾にあるかどうかですね。

公式の開発者ガイドで具体的な中身を見ていきますか...。

##[開発者ガイド](https://developer.salesforce.com/docs/atlas.ja-jp.pages.meta/pages/pages_intro.htm)

**_apex : pageMessage_**
>このコンポーネントは、特定の重要度に対するエラー、警告、およびその他の種類のメッセージ用の Salesforce パターンを使用してカスタムメッセージをページに表示するために使用されます。

**_apex : pageMessages_**
>このコンポーネントは、Salesforce スタイルを使用して、現在のページのすべてのコンポーネントに対して生成されたすべてのメッセージを表示します。

**_apex : message_**
>警告またはエラーなど、特定のコンポーネントに対するメッセージです。<apex:message> または <apex:messages> コンポーネントがページに含まれていない場合、ほとんどの警告およびエラーメッセージはデバッグログにのみ表示されます。

**_apex : messages_**
>現在のページのすべてのコンポーネントに生成されたすべてのメッセージです。<apex:message> または <apex:messages> コンポーネントがページに含まれていない場合、ほとんどの警告およびエラーメッセージはデバッグログにのみ表示されます。

って感じらしいです。(まだわかってません。w)
この4つのコンポーネントに絡んだ問題を解いたときになんとなく、なんとなく違いが少しわかったような気がします。

開発者ガイドだけで理解するのは不十分だなと感じ、調べてみると...。
Salesforceの一番星！いつもお世話になっている[アンダーソン](https://keneloper.com/)さんのブログでありました！
それも、サンプルコード付きでした！

なんとなーくでしか理解できていませんでしたが、実際にエラー内容がどのように出力されるのかがわかり、理解に至りました..。
実際にコードが記載されていて、エラー内容の画像などのもあるのでぜひ参考にしてみてください！私は、一度コードを書いて確認してみました！(理解力不足なもので...汗)

##まとめ
Salesforceの一番星を参考にしてみると、**重要度(_confirm・info・warning・error_)**が分かるように出力されるのが**_pageMessage_**、コンポーネントに対して、**エラー・メッセージ**が出力されるのが**_pageMessages_**・**_messages_**という感じかなと...。もう少し問題を解きながら照らし合わせたらいけそうです！！

##さいごに
Salesforceの資格試験に向けて学習する中で、自分の中で曖昧だった対象のコンポーネントの調査まとめを備忘録として記述しました。自己満でしかないのですが、私と同じ初心者の方で、今後資格試験で同じようなとこが整理できていない方に役立てればと思います。
いつもお世話になってるブログ[Salesforceの一番星・アンダーソン](https://keneloper.com/)さんにも感謝です。

##今回お世話になった資料
公式で出されている開発者ガイド
・[Visualforce開発者ガイド~apex:pageMessage~](https://developer.salesforce.com/docs/atlas.ja-jp.232.0.pages.meta/pages/pages_compref_pageMessage.htm)
・[Visualforce開発者ガイド~apex:pageMessages~](https://developer.salesforce.com/docs/atlas.ja-jp.232.0.pages.meta/pages/pages_compref_pageMessages.htm)
・[Visualforce開発者ガイド~apex:message~](https://developer.salesforce.com/docs/atlas.ja-jp.pages.meta/pages/pages_compref_message.htm)
・[Visualforce開発者ガイド~apex:messages~](https://developer.salesforce.com/docs/atlas.ja-jp.pages.meta/pages/pages_compref_messages.htm)

参考にさせていただいたページ
・[【サンプルコードあり】Apex メッセージをVisualforceに表示させる方法](https://keneloper.com/visualforce-message-display/)
Salesforceの資格勉強するときにはかかせない方です！いつもお世話になってます...。
Salesforce認定資格の問題集なども出してくださっているのでこれから学習する人には、必見です！
・[【試験問題】Salesforce 認定 上級デベロッパー](https://keneloper.com/certified-advanced-developer-exam-collection1/)
同人プロジェクトマネジメント入門：仕様書作成編その3

[同人プロジェクトマネジメント入門の目次はこちら](https://qiita.com/wolfmagnate/items/97bf9a9f8c58ede3fb21)

- - -

# はじめに
前回までで、タスクの作成方法について学びました。今回は、タスクを作成するマネージャーに向けて、どのようなタスクを追加すればよいのかのヒントを与えるため、タスクの特徴について書いていきます。

# タスクの特徴
ゲーム開発におけるタスクには様々なものが存在します。仕様を決める際には、マネージャーがタスクごとの重さを考えて、出来るだけ軽い作業になるよう工夫したり、重い作業を1個以上に増やさないようにしましょう。同人プロジェクトの開発物についていうと、基本的には、複雑な大作より、良い感じに動くミニゲームの方が周りに楽しんでもらえる確率は高いです。
##炎上しやすいタスク
###複雑・少数
炎上しやすいタスクは「完成度が100%か0%か2択で、完成度80%は0%にカウントされる」という性質を抱えています。
具体例を挙げると、「戦闘システムが、自分の攻撃だけ完成しました」といった状況では、納品が出来ません。相手の攻撃も要りますし、アイテムを使ったりすることもあるでしょう。全部作らないと作っていない場合と同じという特性を持っています。
そして、このようなタスクは、分業が難しいタスクでもあります。なぜなら、システム内の多数の変数や関数が、相互に複雑に関連しあっているためです。本質的に複雑で巨大なシステムは、個々人で脳内の設計が異なりますし、分業のためのインターフェースの作成も難しいのです。

###自作のみ
複雑性が上がれば上がるほど、金の力で何とかならないような仕様が増えていきます。
「独特のシステム」「新感覚○○」などは非常に危険です。同人プロジェクトのゲームの独創性は、システムよりフレーバー面で出すことを勧めます。具体的には、「ハロウィンをテーマにする🎃」などゲームの雰囲気を重視した独創性を入れた方が、炎上確率は下がります。(ハロウィンに独創性はないですが...)

###依存関係が多い
「Aが終わらないとBが出来ない」というようなタスクは、炎上を生みやすいです。なぜなら、待ちが発生しやすいからです。仕様を作成したら仕事を割り当てる計画が必要ですが、依存関係がある仕事を受け持った人のモチベが枯れた場合に、その影響が外部に波及して、モチベのある人間の仕事を阻害するのです。この状況が起こると、他の人間のモチベが死んだり、仕事をしない人を非難したりしてチームの雰囲気が最悪になります。
また「待ち」の解消はマネージャーの仕事でもあるので、マネージャーの過労およびモチベーション消失にもつながります。

### 変更が多い
当たり前の話ですが、仕様が頻繁に変更されることが予想される、「ふわっとした要件」は炎上します。「なんかいい感じに戦う敵AI」などがいい例で、実装方法が何通りも考えられ、うまくいかなければ様々な実装を試す必要が生まれるのです。

### 時間が予測しにくい
ズルズルと開発が遅れまくる
### 具体例
以下のような、ルールの複雑さによってゲームの面白さを担保するようなものは、炎上するタスクを生みやすいです。

* プロシージャル系統(自動生成ステージなど)
* 賢いAI全般
* リアルタイム通信
* 格ゲー
* 3Dアクション
* 独特なシステムゲー(時間操作とか、磁石アクションとか、流体○○とか)
* レースゲーム
* 物理が絡むゲーム
* 本格シミュレーション

ただし、これらのうちそこそこのパターンが、「金でシステムを買う」という方法で対応することが可能です。お金での解決を選んだ場合には、難易度は一気に下がるでしょう。逆に、「自作ゲームで賢い敵AIを作りたい！」とか「当時の社会システムまで模倣したシミュレーションを作りたい」とかの要件の場合は相当厳しいプロジェクトが予想されます。

##炎上しにくいタスク
###単発・多数
キャラクターのステータスを生める単調作業を無限にする、といったタスクです。これはこれで特有の辛さがあるのは事実です。しかし、キャラの数を30から15にすることは可能ですし、シナリオの場合も無理やり終わらせれば10話構成を5話構成にすることが可能です。
つまり、完成度が100%から0%まで連続的な値をとるというのが「単発・多数」という性質の意味です。
さらに、多数の独立した仕事から構成されているので、複数人で一気に仕上げることもできます。
###代替可能
いったん仮の素材で埋めてしまえるタスクです。例えば、カードゲームの場合、大量の2D画像を使う必要がありますが、いったん適当な素材で埋めて余裕があれば自作するという手が取れます。
金の力での誤魔化しがきくタスクは、炎上する前にお金で火を消せます。
###依存関係がない
理想的な順番にタスクの依存関係を並べます。上のタスクが多いのがいいんですが、もちろんゲームである以上、下のタスクも存在します。最初に「骨」を作ろう！というのは、「**モチベーションという資産をゲーム全体の完成を左右する部分にフル活用しよう**」という目的のスローガンです。

* 「機能Aがなくてもゲームは完成する」：サブクエスト的なもの。ゲーム全体で希釈されるため、機能Aがなくてもプレイヤーは気づかない
* 「機能Aがないと機能Bがしょぼい」：戦闘における必殺技システムなど。無くなってしまうと、機能Bという範囲内で機能Aが消えるので、機能不足に気づかれてしまうが、プレイ自体に支障はない
* 「機能Aがないと最終的にゲームが完成しない」：依存関係があるものの、その被害・待ちが発生するのはゲーム開発終盤である
* 「機能Aがないと機能Bへ進めない」：依存関係があるが、最悪機能Aを別の人に交代させれば機能Bからはまっさらな状況から開発できる
* 「機能Aが巨大」：依存関係がある上に機能A内部で中途半端に開発が行われていた場合、負の遺産として残り続ける

### 具体例
以下のような、コンテンツの多さによってゲームの面白さを担保するようなものは、炎上しにくいタスクを生みやすいです。

* RPG
* シナリオゲーム
* カードゲーム
* 多数のステージ
* キャラゲー
* 多数のユニット

#おわりに
特定のタスクの難易度が上がってしまうのは仕方がないことです。独創性のあるアイデアというのは、やはり複雑なものです。なぜなら単純なアイデアなら誰かがやっているからです。したがって、複雑性のあるタスクをむやみに避けるのではなく、複雑性の要因のうち一部を我慢する(例：一部のシステムは購入して改造で出来る範囲に仕様変更)ことでメリハリをつけることが重要です。
Dockerで、検証用サーバーを構築してみた⑤ (最終章 実行編)


# [概要]
Dockerを使用する際のコマンドを、自分なりに理解した内容も踏まえて
記録しておこう。


# [コマンド]

##[現在のディレクトリ構成]
```
LocalServer/
├── app/
│　　　　　　　└── local_server.py
└── Dockerfile    
└── docker-compose.yml
```

## 最終章
これまでの記事で、必要最低限のソフト、ファイルを用意してきました。
この記事では、実際に自身のPCのみでリクエストからレスポンスを一貫して確認してみようと思います。

## Dockerの起動
#### 1, Dockerは起動できている？
まず、以下のコマンドを実行して、Dockerが起動しているか確認してみよう

```ruby:terminal
#実行しているコンテナ一覧を表示するコマンド
$ docker ps 
```
<br>
<br>
※もし、以下のようなエラーが表示されれば、Dockerそのものをが起動出来ていない。

```ruby:terminal
#Dockerを起動出来ていないので、ちゃんと起動してる？と言われる。。。
$ docker ps
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
```

以下コマンドで、Dockerを立ち上げよう

```ruby:terminal
/usr/bin/open /Applications/Docker.app
```

<br>
<br>

以下の内容が、表示されればOK。

```ruby:terminal
#現在はコンテナを起動していないので各項目のみ表示される
$ docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
```

<br>

#### 2, コンテナの起動

以下のコマンドを実行して、[docker-compose]から、コンテナを起動してみましょう。

```ruby:terminal
# 停止中のコンテナを対象に、イメージ作成から、コンテナを作成/起動してくれるコマンド
$ docker-compose up
```
※LocalServerフォルダに移動してから実行してください。

<br>

#### 3, コンテナ状態の確認

上記1の、コマンドを実行してコンテナが起動されていることを確認してみましょう。
すると今度は以下のような表示になる筈です。

```ruby:terminal
$ docker ps
CONTAINER ID   IMAGE               COMMAND                  CREATED          STATUS         PORTS                    NAMES
60567ff2049d   localserver_flask   "flask run --host 0.…"   12 minutes ago   Up 7 minutes   0.0.0.0:8080->8080/tcp   localserver_flask_1

```

#####[各項目の詳細]

|CONTAINER ID  |IMAGE  |COMMAND  |CREATED  |STATUS  |PORTS  |NAME  |
|---|---|---|---|---|---|---|
|コンテナIDの最初の12桁  |コンテナ生成の元となったイメージ  |起動時のコマンド  |コンテナ作成後の経過時間  |コンテナ起動/停止後の経過時間  |バインドしているポート  |コンテナ名  |


#####これで晴れて、自身のPC内に、Dockerを使用→コンテナ起動→検証用サーバーを立ち上げる事が可能となりました。

####4, それではブラウザで、「localhost:8080/test」を開いてみましょう。


pythonファイルの記載されている、「リクエストに成功！！」の文言が表示されればOKだが、、、

<br>
<br>
<br>
<br>

どうだ、、

<br>
<br>
<br>
<br>

どう、、だ？

<br>
<br>
<br>
<br>


![localhost_8080_test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1059125/5832ad2f-6e25-5319-bb3e-6aff7eec7466.png)












###気持ちの良い瞬間:relieved:

<br>
<br>
<br>
<br>

#### 4, まとめ
今回、初投稿ではありましたが記事①〜⑤を作成してみました。

詳細な情報、必要な情報が抜けていたり、至らない点がいくつもあると思います。
その点は、すみません。（内容に間違いや、アドバイス等ありましたらご指摘いただけますと幸いです）

今後もっともっと、知識を深めて色々な情報をお届けできればなと思ってます。

**それと、最後に記事の投稿に迷われている方等、いらっしゃいましたら**
**私は、以下の内容を感じましたので、少量でも投稿してみる事をオススメします。**

**・アウトプットによる、知識の定着**
**・記事を公開するので、今までしっかり理解出来ていなかった内容を理解しないといけない。。が**
**　知識量が増える。（結果、楽しいw）**
**・再度、技術者として自覚し、モチベーションの向上に繋がった**
**・記事投稿の達成感により、モチベーションの向上に繋がった**

<br>

**今後、この検証用サーバーに対して、スマホアプリから通信した場合や、**
**Jsonデータを返却したりなど色々と記事にしていこうと思います。**
**興味がある方は見ていただければと思います。刺激になるので:relaxed:**

<br>

**見てくださった方々、ありがとうございました。**



<br>
<br>

### 参考
http://docs.docker.jp/engine/articles/systemd.html

https://qiita.com/kobori_akira/items/1cd058f180206fd8d139
stm32 のデバッグ中にリセットかけたい

毎回フラッシュに転送して時間もかかるし、気分的にもよくない、なんでリセットもないのさ、できないの？　と思っていましたが。
私が悪かったです。ありました。何年も気が付きませんでした。
![スクリーンショット 2021-12-03 115140.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36775/63f4a2f1-c5e8-d5c1-113b-7db30e3df5ac.png)
アイコンと位置...
３項演算子

メモです

```C#
if(i < 1){
   /*true時の内容*/
}else{
   /*false時の内容*/
}
```
が

```C#
i < 1 ? /*true時の内容*/ : /*false時の内容*/;
```
と書ける

```C#
i < 1  ? /*true時の内容*/ : /*false時の内容*/;
条件式 if              else                 ;
```
DockerHubのイメージのタグ一覧を参照する方法

ブラウザでこちらを参照。JSON形式で取得できる。
https://registry.hub.docker.com/v1/repositories/＜イメージ名＞/tags
![スクリーンショット 2021-12-03 11.45.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229739/da937e92-4f7e-5d48-a75f-684178f8cca5.png)
AWSSSO 属性とユーザープロファイルの対応

https://docs.aws.amazon.com/ja_jp/singlesignon/latest/userguide/attributemappingsconcept.html

| AWSSSO 属性 | SSO ユーザープロファイル |
|:-----------|:------------|
| ${user:AD_GUID} | ユーザー ID |
| ${user:email} | プライマリ E メール |
| ${user:familyName} | 姓 |
| ${user:givenName} | 名 |
| ${user:middleName} |  |
| ${user:name} | 表示名 |
| ${user:preferredUsername} | 表示名  |
| ${user:subject} | ユーザー名 |

ミドルネームはおそらく設定すると対応すると思われる。
name　と preferredUsername が同じだったのでどちらかは姓、名をくっつけた文字列ではないか、ニックネームを設定するとどちらかが対応するのではないか、など疑ったがどちらも表示名だった。
Next.js の CSS Modules で変数などの共通で読み込みたいファイルの読み込み処理を共通化する方法

Next.jsでCSS Modules（SCSS）などを使っている時などに、メディアクエリーや共通の変数を定義したファイルを新しくscssファイルつくるたびに読み込まなくてはならないのは地味にめんどくさいです。

next.config.jsのsass optionsに設定を記入することで共通scssファイルの読み込み処理を自動化できます。

```next.config.js
module.exports = {
  ‥‥‥‥‥‥‥‥‥‥‥‥
  sassOptions: {
    prependData: `
    @use '@variables' as *;
    `,
  },
  ‥‥‥‥‥‥‥‥
};

```

これでscssファイルの冒頭に自動で @use '@variables' as *; 文(tsConfigで@variablesのaliasを設定している)が挿入されてくれます。便利です。
VBAで配列を返す方法

なんか先程基本的な事だけど配列返らないナーと思っていたんだけど

    Dim tounendoGyuu() As Variant
って宣言して

    Private Function getTounenndoGyou() As Variant
って関数つくって

        tounendoGyuu = getTounenndoGyou
って関数の値を入れないとイケナイ模様……

Long()でやっていたら駄目って怒られたのでメモ失礼いたします。

https://watapipi.com/array_variant/

とかに書いてありました(^_^;)
PHPStormからGitHubに接続できなくなった話

ソースコードをGitHubに移行した時にエラーが出て手間取ってしまったので、備忘録。

# 前提
PHPStormでGit操作したい。
GitHubは二要素認証（今回の件に関係あるかは不明）

# 事象
`Git -> リモート管理`から、接続先のURLを変更する。

すると・・・

```
remote: Repository not found.
fatal: repository 'https://github.com/*****/****.git/' not found
```

エラーが出た。

新しくクローンすればいっか、と思い、コマンドでgit cloneする。
しかし、PHPStormからfetchしようとすると同じエラーが出てしまい、何も出来ず・・・。

でもPHPStormから操作したい・・・！


# 解決策

### GitHubで`Personal Access Token`を発行する。

1. `Setting -> Developer settings -> Personal access tokens`を開く
1. `Generate new token`を押下して、tokenを発行。
1. 発行されたtokenは１度しか表示してくれないようなので、メモしておく！

#### ※チェックを入れるもの

↓の画像にあるように
* repo
* gist
* read.org
* workflow

この4つはチェックを入れる必要があるようです。 
![github.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139588/570004ff-2e4f-3384-4e52-8fcd0b73b7f8.png)



### PHPStormでGitHubアカウントを追加

1. `設定 -> バージョン管理 -> GitHub`を開き、`+`マークを押下すると何を使ってアカウントを追加するか選択肢が出るので、`トークンでログイン`を選択する。
1. `トークン`欄に先ほど発行したトークンを入力して、アカウントを追加
1. 正常にアカウントが追加されたことを確認する

### PHPStormで接続先URLを変更する

あらためて`Git -> リモート管理`から、接続先のURLを変更してみると・・・。

無事に接続先を変更できました！
Cloudfromationスタックに既存のリソースを紐付ける

# はじめに
最近Cloudfromationを触っているのアウトプットも兼ねて投稿です。

# S3バケットを作成
advent-calendar-2021という名前のバケットを作成しておきます。

![スクリーンショット 2021-12-03 10.43.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537831/cb2ead15-9888-9f51-be2b-b4cbe573d244.png)


# Cloudformationスタックを作成

S3バケットを作成するだけの簡単なテンプレートでスタックを作成します。

```yml
AWSTemplateFormatVersion: "2010-09-09"
Resources:
  Test:
    Type: "AWS::S3::Bucket"
    DeletionPolicy: Retain
    Properties:
      BucketName: "advent-calendar-2021"
```

# 問題点
スタック作成時に以下のエラーがでてしまいます。作ろうとしたものと同じ名前のS3バケットが既に存在しますといった趣旨の内容です。

![スクリーンショット 2021-12-03 10.57.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537831/da31624f-1b9c-b79a-5912-74b3f60fa145.png)

# 解決方法

Cloudformationから既存のリソースをインポートします。
![スクリーンショット 2021-12-03 11.06.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537831/cf56a727-b16e-30ba-6ffa-4b8cc7eeb20d.png)

先程と同じYMLファイルをアップロードします。
![スクリーンショット 2021-12-03 11.07.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537831/0e62d70c-a818-99f3-f02d-2d18b68a4d0f.png)

S3バケットの名前を入力します
![スクリーンショット 2021-12-03 11.08.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537831/9c3f45c4-a117-9fcb-148f-6ff0f1c24ae5.png)

画面操作を進めていきリソースをインポートします。
![スクリーンショット 2021-12-03 11.14.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537831/baa49781-27a0-51ca-d1d2-044fa72b6636.png)

インポートが完了しました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537831/3b265561-b98f-decd-7a72-c22fab399bc2.png)


補足：　Cloudfromationのスタックは一旦削除して作り直しました。

# インポートできるリソース一覧
Cloudformationでインポートできるリソース一覧を見つけたのでURLを貼ります。
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resource-import-supported-resources.html

# おわりに
最後までご覧いただきありがとうございました。
Python3でCGIチャレンジ2　ファイル書き込み

#前提
Python3でCGIチャレンジ1後

#作業フォルダ
ps1

#作業

##sample.pyを修正。

```python:sample.py

import cgi
import cgitb
cgitb.enable()

print("Content-Type: text/html")
print()   

form = cgi.FieldStorage()

f = open('file.txt', 'a', encoding='UTF-8')   # add

for key in form:
    value = form[key].value
    print('<p>%s: %s</p>' % (key, value))
    f.write('%s: %s, ' % (key, value))          # add

f.write('\n')   # add
f.close()       # add

```

##ターミナルでコマンド実行して、ローカルでCGIサーバーを起動する。

```
python -m http.server --cgi 8000
```

##ブラウザで確認

[http://localhost:8000]

#結果

入力して送信
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401158/9a70684b-293e-c59d-3e89-ef930721dce5.png)

作成されたファイルを開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401158/4eb512f5-7080-097f-9a41-efe98f0aaec6.png)

再度適当な入力して追記確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401158/9bd84f62-6bc7-fd10-632f-d73757fce67a.png)

#理解したこと
- ファイルモード
- エンコーディング指定。Python2とは記述が異なる。

#情報源
Googleで「Python3 ファイル書き込み」で上から順に試した。
Reactを基本からまとめてみた【19】【React Router ②】

##ルーティング(Routing)とは
ルーティング(Routing)とは、ユーザーからの入力に応じて表示させるページを出し分ける処理を指す。
今までのWebアプリケーションはサーバーサイドでルーティングを行うことが主流だったが、Ajax(Asynchronous JavaScript and XML)という非同期的にサーバーとの通信ができる技術が普及したことにより、クライアントサイドでルーティングを行うことが増えきた。いわゆるSPA(Single Page Application)と呼ばれるもの。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/939638/fbe59238-c38b-24d1-f9b9-a54921016b04.png)

SPAはSingle Pageと呼ばれているように、1枚のHTMLファイルをレンダリングしてブラウザに表示している。SPAではページ内でDOMを色々変更してもURLは変わらない。ルーティングによりURLで画面を指定する(DOMの状態を保存する)ことができる。これにより、ページ遷移や共有がスムーズに行える。このような理由からSPAであってもルーティングを使っているアプリケーションが多い。


##react-router と react-router-dom

react-router には 3 種あり、コア機能だけがある 『react-router』、コア機能に Web に必要な機能を追加した 『react-router-dom』、ReactNative 用の 『react-router-native』が存在する。React で通常使用する際は、react-router-dom を使用する。react-router の方が正解に思えるが react-router-dom が通常使用する際は、正解。

##react-router-domのインストール

```
$ npm install --save react-router-dom
```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/939638/da24f612-5b20-ca0b-1161-115e46a07ce5.png)




















##参考サイト
[React.jsでルーティングを実装するためのreact-routerの紹介]
(https://code-ship-blog.wemotion.co.jp/technology/react-js%E3%81%A7%E3%83%AB%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%92%E5%AE%9F%E8%A3%85%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AEreact-router%E3%81%AE%E7%B4%B9%E4%BB%8B/)
[react-router-domでルーティングを作成する]
(https://crudzoo.com/blog/my-todo-note-2)
バーチャル空間 oVice で簡単に Zoom Meeting ができるようになってたので録画まわりの挙動を確認してみた

この記事は [YUMEMI Advent Calendar](https://qiita.com/advent-calendar/2021/yumemi) 4日目の記事です。


TechCrunch から、「バーチャル空間oViceとZoomが提携、oVice上からシームレスにビデオ会議を行えるように」 という記事が出ていました。

https://ovice.in/ja/

https://jp.techcrunch.com/2021/12/01/ovice-zoom



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18306/78fdb20e-e6a9-3cda-7407-487472657eea.png)

スペース内で、 `右クリック` で出てくるメニューの右端に、zoomのアイコンが追加されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18306/7fd7c7c8-47ff-07de-6c1a-f5fd527d1a5a.png)

画面下の `・・・` マークからもzoomを選択することができます

いずれかのアイコンをクリックすると、ブラウザの別タブでzoomのページが開かれます。
そこからzoomのアプリを起動することができます。（ブラウザの設定によっては自動で起動します。）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18306/117635dd-e940-6d70-9503-2d7df3b3e8c9.png)

ブラウザでoViceのタブに戻ると、次のような表示が出ていました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18306/4e72b716-21e5-693c-87a1-ccd806330fd4.png)

いま開いたZoomへInviteするためのurlが表示されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18306/4a792e09-8853-e7ab-183f-c6aa08e68a0a.png)

スペース内では、zoomのアイコンと自分のアカウントが線で繋がっています。以前からあったVoiceミーティングと同じようなUIです。

一方oViceから開かれたzoom側は、普段使っているアカウントにしてある設定とは別な設定が効いているようでした。

## 録画方法

|  |通常  |oVice  |
|---|---|---|
|クラウドにレコーディング  | ○ |✗  |
|ローカルに「レコーディング  |○  |○  |

oVice側のzoomアカウントではなく、自分がzoomで使用しているアカウントでミーティングが作られているようです。
ローカルレコーディングした記録が、自分のzoomアカウントの記録として残っていました。

## 自動録画

Zoomアカウントの設定で、ミーティング開始時に自動でクラウド録画を開始する機能があるのですが、そもそもクラウド録画ができないので、手動で録画ボタンを押す必要があります。



# まとめ

勉強会の開催や懇親会などで何度も使っているのですが、その際に記録として動画収録が簡単にできないことが、課題となっていました。
今回のアップデートでzoomと連携できるようになったので、勉強会の録画に関しては（ローカルレコーディングですが）一歩前進したと言えるのではないでしょうか。
日付文字列（YYYYMMDD）をフォルダ名に設定して新規作成するバッチ

# 概要
日付文字列（YYYYMMDD）をフォルダ名に設定して新規作成するバッチファイル例。
共有するようなものではないが、様々な現場でよく使うためテンプレート的に記載。

# バッチファイル例
```mkdir.bat
rem 現在日付の取得
set date_str=%date:~-10,4%%date:~-5,2%%date:~-2,2%

rem ディレクトリ作成
mkdir %date_str%_
```
Thinkpad X41

メモ代わりにここに記載して置くことにする。
TYPE：2525-E9J
SSD：Transcend SSD 128G mSATA3 TS128GMSA370
     Enlargecorp mSATA 1.8インチIDE 44pin変換アダプター
メモリ：Transcend　PC2-6400(DDR2-800)2G

OS：Linux Mint 19.3(32bit)
    FingerPrint-guiにて指紋認証でログインできる。
ブラウザ：Chromeが対応してないのと、32bit版はなんだか面倒くさいので、SeaMonkeyを導入。

とりあえずこれで使える状態になった。
YouTubeも見れるし、ｇｃｃも使えるし（コンパイルには時間がかかる）,
まあまあ上等ですな。
ECDSA鍵暗号の作成と検証（openssl、cryptographyを利用）

この記事は [MicroAd Advent Calendar 2021](https://qiita.com/advent-calendar/2021/microad) の6日目の記事です。

SKAdNetworkで利用されている暗号技術であるECDSA（楕円曲線DSA）暗号を利用したので、鍵の生成、暗号の生成（署名）、暗号の検証までの一連の手順をまとめます。

今回は`openssl`を使うパターンと、Pythonライブラリの`cryptgraphy`を使うパターンの2つ記載します。

# 前書き

以下、P-256曲線を利用している。

# opensslを利用する場合

## 鍵の生成
秘密鍵

```
$ openssl ecparam -name prime192v1 -genkey -noout -out key.pem 
```

公開鍵

```
$ openssl ec -in key.pem -pubout -out pubkey.pem
read EC key
writing EC key
```
## 署名
メッセージを記入

```
$ vi message.txt
```

秘密鍵を使って署名

```
$ openssl dgst -SHA256 -sign key.pem message.txt > signature.dat
```
## 鍵の検証
```
$ openssl dgst -SHA256 -verify pubkey.pem -signature signature.dat message.txt
Verified OK
```

# cryptographyを利用する場合

https://pypi.org/project/cryptography/

```python
import base64
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.exceptions import InvalidSignature

YOUR_PRIVATE_KEY = 'XXXXX'
YOUR_PUBLIC_KEY = 'XXXXX'
MESSAGE = 'abc'

pri_key = f"""-----BEGIN EC PRIVATE KEY-----\n{YOUR_PRIVATE_KEY}\n-----END EC PRIVATE KEY-----"""
pub_key = f"""-----BEGIN PUBLIC KEY-----\n{YOUR_PUBLIC_KEY}\n-----END PUBLIC KEY-----"""
private_key_ins = serialization.load_pem_private_key(pri_key.encode(), password=None)
public_key_ins = serialization.load_pem_public_key(pub_key.encode())

# private keyでシグネチャ生成
signature = private_key_ins.sign(signature_algorithm=ec.ECDSA(hashes.SHA256()), data=MESSAGE.encode())
attribution_signature = base64.b64encode(signature)

print('original message:', MESSAGE)
print('attribution_signature:', attribution_signature.decode())

# public keyでシグネチャ検証
try:
    public_key_ins.verify(signature, MESSAGE.encode(), ec.ECDSA(hashes.SHA256()))
    print('signature OK.')
except InvalidSignature:
    print('signature NG.')
```
※ `YOUR_PRIVATE_KEY`, `YOUR_PUBLIC_KEY`は各自で発行したものに置き換える

## 実行結果

```
$ python script.py
original message: abc
attribution_signature: (省略)
signature OK.
```