OmniAICreator/Qiita-1.07M huggingface dataset:
Flexera One: IBMソフトウェアライセンス管理を行う場合に定期的に作成すべきレポート

IBMソフトウェアライセンスの管理を行うために、Flexera One with IBM Observability（以降 Flexera Oneと表記します） を利用することが可能です。
本記事では、Flexera Oneを使用してIBMソフトウェアライセンスの管理を行う場合に定期的に作成・保管すべきレポートについて記載します。

IBMソフトウェアをサブキャパシティー・ライセンス方式で使用する場合、IBMが示す「監査レポート」例で示す情報を含むレポートを少なくとも四半期ごとに1回作成しなければならず、2年以上保管する必要があります。（IBM[『パスポート・アドバンテージのご契約条件』](https://www.ibm.com/support/customer/csol/terms/?id=Z125-5831&lc=ja#detail-document)より。）

Flexera Oneを使用してIBMソフトウェアライセンスの管理を行う場合も、上記の通りライセンスの利用状況に関するレポートを少なくとも四半期に1回作成し、提出できるようにしておく必要があります。レポートは、Flexeraで設定したレポート期間（最長3ヶ月）が切り替わったら直ちに前の期間のレポートを作成・保管するようにしてください。（レポート期間および履歴データ保管期間の設定は「Administration」> 「IT Asset Management Settings」> 「全般」の「ライセンス」タブで確認できます。）

Flexera Oneで生成し、保管しておくべきレポートは下表のとおりです。各レポートの具体的な出力手順については[『Flexera IT Asset Management System Reference: Reporting to IBM』](https://docs.flexera.com/fnms/EN/SystemRef/index.html#SysRef/SubcapPVU/tasks/ScPVU-ReportingToIBM.html)を参照してください。


|レポート名(GUIでの表示名) |レポート内容|出力形式|
|---|---|---|
|IBM PVU ライセンスの消費|プロセッサー バリュー ユニット (PVU) ライセンスでカバーされているソフトウェア、およびこれらのライセンスに対して消費済みのライセンス エンタイトルメントの一覧を、選択された全レポート期間中の過去のデータも含んで表示します。|PDFおよびXLSX（またはCSV）|
|IBM Cloud Pak ライセンスの消費|Cloud Pak ライセンスでカバーされているソフトウェア、およびこれらのライセンスに対して消費済みのライセンス エンタイトルメントの一覧を、選択された全レポート期間中の過去のデータも含んで表示します。|PDFおよびXLSX（またはCSV）|
|IBM PVUの上書き|ライセンスの消費またはインベントリの値が手動で上書きされている IBM PVU ライセンスを消費するデバイスのリストです。|PDFおよびXLSX（またはCSV）|
|IBM PVU 古いインベントリ|以前にIBM PVU ライセンスを消費していたデバイスで、選択された期間以降のインベントリをレポートしていないもののリストです。|PDFおよびXLSX（またはCSV）|
|すべてのライセンス(IBM RVUでフィルター)|IBM RVUライセンスのレポートです。|PDFおよびXLSX（またはCSV）|
|ライセンス未割り当てのインストール（IBMでフィルター）|インストールされているがライセンスが割り当てられていないソフトウェアのリストです。|PDFおよびXLSX（またはCSV）|

以上がFlexera OneでIBMソフトウェアライセンス管理を行う場合に定期的に作成・保管する必要のあるレポートです。
youtubeのカスタムcss

youtubeのUIで、動画を表示したまま関連動画やコメントを見ることができないのが不便だったので書いたカスタムcssを、どこかに置いておかないとなにかの表示にリセットされたりしそうなのでここに記します。
ブラウザ拡張機能のStylusやUserCSSなどを使って適用することができます。
ついでにアップロードボタン、オフラインボタン、関連ゲーム項目を非表示にしているので、利用する場合は需要に応じて書き換えます。

```
/* 関連動画表示領域を固定 */
ytd-watch-next-secondary-results-renderer ytd-item-section-renderer {
    overflow-y: scroll;
    overflow-x: hidden;
    height: 90vh;
}

/* ウィンドウ幅が1616px以下の場合 */
@media screen and (max-width: 1016px) {
    /* 関連動画表示領域の領域を固定しスクロール可能に */
    ytd-watch-next-secondary-results-renderer ytd-item-section-renderer {
        overflow-y: scroll;
        overflow-x: hidden;
        height: 15vh;
    }

    /* 動画情報表示領域の幅を半分に */
    .ytd-watch-next-secondary-results-renderer ytd-compact-video-renderer {
        width: 50%;
    }
}


/* コメント表示スペースの領域を固定しスクロール可能に */
ytd-comments ytd-item-section-renderer{
    height: 26vh;
    overflow-y: scroll;
    overflow-x: hidden;
}


/* サムネイルの縦整列flex化 */
ytd-watch-next-secondary-results-renderer .ytd-item-section-renderer {
    display: flex;
    flex-flow: row wrap;
}

/* 詳細テキストのクリックイベント無効化 */
.details {
    pointer-events: none;
}

/* 音声検索の非表示 */
#voice-search-button {
    display: none;
}

/* オフラインボタンの非表示 */
ytd-download-button-renderer {
    display: none
}

/* ゲーム非表示 */
ytd-metadata-row-container-renderer {
    display: none;
}

/* アップロードボタンを非表示 */
yt-icon.ytd-topbar-menu-button-renderer {
    display: none;
}
```
[Java] SerialVerisonIDの自動生成

たぶん適当でもいいんだけど、せっかく機能があるので紹介。
環境はIntelliJ IDEA。Kotlinでも使えた。

# 方法
`Ctrl + Shift + A`でアクションの検索画面を開き、`Serial`と入力。
`"JVM言語: 'SerialVersionID'のないクラス"（Serializable class without 'serialVersionUID'）`とあったらそれを選ぶ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883146/59f58a41-810a-a258-0ada-d4998d4b3937.png)

選択肢右側のトグルが`ON`になっていることを確認。なってなかったら再度クリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883146/a5c0efd6-d9f0-8bec-01c7-cb82fd5c1ef8.png)

`Serializable`クラスを継承したクラス名の上で`Alt + Enter`を押し、メニューから`'<クラス名>'に定数フィールド'serialVersionID'を作成`を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883146/b463597d-30c8-5539-8ff4-84faf13ba8e9.png)
無事にIDが生成されたことを確認する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883146/b1520426-698c-6b93-868f-aa861b3b25f0.png)

ちなみに、デフォルトで生成された構文のままだと`serialVersionID`自体もシリアライズの対象となってしまうので、避けたい場合は`transient`修飾子をつけてあげるとよい。

```java
@Serial
private static final transient long serialVersionUID = -6443172249701464622L;
```
axios ローカル環境でapiにアクセスできない AxiosError: connect ECONNREFUSED　解決　URIのドメイン名をIPアドレス表記にする

# 症状
ローカル環境下で構築したapiをフロントエンドのaxiosで叩こうとしたところ
「error - unhandledRejection: AxiosError: connect ECONNREFUSED 127.0.0.1:5000」というエラーが出てapiを叩けませんでした。


## ソースコード

``` categoryService.ts
import axios from 'axios';

 export  const getCategories = () =>{
	return axios.get(`http://localhost:5000/api/category/all`);
};


```



``` axioapi.tsx
import { Category } from "../../types/category";
import * as categoryService from "../../service/categoryService";
import { useState } from "react";

export default function AxiosApi() {

	const [categories, setCategories] = useState<Category[]>([])

	categoryService
		.getCategories()
		.then((response) => {
			//setCategories(response.data)
			console.log(categories[0])
		});


	return (
		<div>
			<h1>axiosを使ったデータ取得</h1>
			カテゴリー名前一覧
			{
				categories.map((category) => {
					return (
						<div key={category.id}>
							{category.name} {category.children}
						</div>
					)
				})
			}
		</div>
	)
}

```

## エラーログ
axioapi.tsxに対応するページを開くとVSCodeのターミナルに以下エラーメッセージが出ます。

```
error - unhandledRejection: AxiosError: connect ECONNREFUSED 127.0.0.1:5000
    at Function.AxiosError.from (file:///workspaces/ecshop_front_react/ecshop_front/node_modules/axios/lib/core/AxiosError.js:89:14)
    at RedirectableRequest.handleRequestError (file:///workspaces/ecshop_front_react/ecshop_front/node_modules/axios/lib/adapters/http.js:526:25)
    at RedirectableRequest.emit (node:events:513:28)
    at ClientRequest.eventHandlers.<computed> (/workspaces/ecshop_front_react/ecshop_front/node_modules/follow-redirects/index.js:14:24)
    at ClientRequest.emit (node:events:513:28)
    at Socket.socketErrorListener (node:_http_client:494:9)
    at Socket.emit (node:events:513:28)
    at emitErrorNT (node:internal/streams/destroy:157:8)
    at emitErrorCloseNT (node:internal/streams/destroy:122:3)
    at processTicksAndRejections (node:internal/process/task_queues:83:21) {
  port: 5000,
  address: '127.0.0.1',
  syscall: 'connect',
  code: 'ECONNREFUSED',
  errno: -111,


```


# 開発環境
開発環境
OS:windows10

バックエンド側：
IDE:IntelliJ Community
spring-boot-starter-parent 2.75
java　：　11


フロントエンド：
IDE:VScode

├── @types/node@18.11.15
├── @types/react-dom@18.0.9
├── @types/react@18.0.26
├── axios@1.2.1
├── eslint-config-next@13.0.6
├── eslint@8.29.0
├── next-auth@4.18.7
├── next@13.0.6
├── react-bootstrap@2.7.0
├── react-dom@18.2.0
├── react@18.2.0
├── styled-components@5.3.6
├── styled-jsx@5.1.1
└── typescript@4.9.4

# 解決方法
apiのURIをIPアドレス表記にすることで解決しました。

fetchメソッド→ドメイン表記でも通じる
axios→アドレス表記じゃないと通じない

``` diff_javascript
import axios from 'axios';

 export  const getCategories = () =>{
-      return axios.get(`http://localhost:5000/api/category/all`);
+      return axios.get(`http://127.0.0.1:5000/api/category/all`);

};
```


# 参考

https://github.com/axios/axios/issues/3821

スクショ部分

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/2a20aee0-9a03-0229-dc97-f8914cc1befc.png)
データを扱う言語、どれ使います？

こんにちは！

みなさんはデータベースのデータにアクセスしようと思ったとき、どの言語を使用しようと思いますか？一般的に考えたとき、RDBのデータにアクセスするときにはSQLを使おうと思うのが普通ですよね？
でも、Vantageではその一択に縛られる必要はないのです。
その種明かしをお話ししましょう。

# 言語ネイティブライブラリ
テラデータはVantageのデータをPythonやRで扱うための言語ネイティブなライブラリを提供しています。Pythonでいえばteradataml、Rではtdplyerというライブラリです。
このライブラリの特長は何といってもデータ処理をデータベース内部で行ってしまうということです。このテータベース内部で処理を行ってしまうということにどういった意味があるかと言いますと、

・ 分析に使用する元のデータがどれだけ巨大でも、それをクライアントに移動する必要がない
・ データの処理をハイ・スペックなデータベース・サーバーの持つパワーで行える

ということが挙げられます。
言い換えると分析のためのデータ準備や分析そのものSQLで行うのとまったく同等にとても早く行うことができる、ということです。

# 一時テーブルとデータ・フレーム
teradatamlやtdplyerを使用して処理を行う場合、データベース上のテーブルをデータフレームとして扱うことができるようになります。またデータの抽出や関数を実行して得られた結果などは一時テーブルとしてVantageの中に保存され、それも言語側ではデータフレームとして扱うことができます。

この一時テーブルは現在のセッションが実行されている間のみ有効となるテーブルで、セッションの切断と同時に自動的にクリーンアップされます。これもこの機能の優れているところで、ワークテーブルの消し忘れにより不要なテーブルがデータベースに残り続けてしまうといったことが無くなります。

# Vantageのデータフレームと汎用のデータフレーム
データベース上のデータをデータフレームとして扱う場合はVantageのライブラリ独自のデータフレームとして扱われます。でも分析した結果を汎用的な、例えばPythonならpandasにしてpandas前提のライブラリを使ってビジュアル化したりとかしたくなりますよね。
それもわずか1コマンド、to_pandasという関数１つで実行することができます。またこの時点ではデータのサイズはとても小さくなっていることがほとんど。データの移動に時間をかけなくてもよいのです。

![画像1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742714/31d87641-3b17-4a9d-1bd5-19bc4e88edac.png)

# まとめ
いかがですか？Vantageはデータの処理をPythonやRでもSQLによる処理とまったく変わらないパフォーマンスで処理することが可能です。これまでに使い慣れた方法でVantageのデータを触ってみてくださいね！

また言語ネイティブ・ライブラリやVantageが持つ分析関数についてはテラデータのメンバーが投稿した記事がQiita上にもたくさんあります。ぜひ一度ご覧くださいね！


#### Teradata Vantageへのお問合せ
[Teradata Vantage へのお問合せ](https://www.teradata.jp/About-Us/Contact)
8年振りに機種変したら、MFAデバイスの登録が出来なくなった件

## 結論
1. MFAデバイスの新規登録が出来ない？と思ったら、MFAデバイスの名前にユーザー名を登録してみよう。
1. 上手く登録出来たら管理者に教えてあげよう。

## 現象
昨日、8年振りに携帯電話を機種変し、意気揚々と新品のiPhone13miniをAWSのMFAデバイスとして登録しようとしたら、こんなエラー画面が出ました。
![image1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656547/c4a9d990-52d7-ff96-c272-546195042017.png)

「あれ？アクセス許可って無かったっけ？」と思いながら、管理者に画面ショットを送り、連絡する。
年末の慌ただしい中、管理者も迷惑だろうなと思いながら返事を待つと、
「許可設定はされてます。（あらためて）確認いただきたく。」
との返事。
もう一度試してみたがダメだった。フム。。

## 原因　2022年11月16日以降のアップデートで、複数のMFAデバイスの登録が可能となったから。
エラーメッセージを読むと、「必要なアクセス許可がありません」と書いてある。
英語のメッセージにも同様なメッセージが書いてある。
ん？さっき私が任意で付けたMFAデバイスの名前「**iPhone13mini**」をクリエイト出来ないって書いてある？
昔、MFAデバイスに名前なんて付けたっけ？

ググってみたら、関係ありそうな記事を見つけた。
いつもお世話になってるサーバーワークスさんの記事だ。

https://blog.serverworks.co.jp/change-iam-policy-for-multiple-mfa-devices

記事によると、

>2022年11月16日に発表された上記のアップデートは、これまで1つしか登録できなかった IAM User もしくは root アカウントユーザへの MFA のデバイスを、最大8個まで登録が可能となる機能強化のアップデートとなっています。

で、

>MFA デバイスを1つ登録しようとした場合に表示される画面です。このように、今まで名前を記載するフィールドはなかったのですが、それが「必須」として表示されます。

で、

>「1台のみ MFA デバイスが設定可能であった時代」には、ここにユーザ名が強制的に入力されておりましたので、この arn は問題なくいままで動作しておりました。
>しかし、複数の MFA デバイスが登録できるようになったことで、デバイス名にはユーザが自由に名前を入力できるようになっています。このため、本制御がエラーを発生させてしまいます。

という現象が起きたようだった。

**私の現象も多分これと同じだろう。**
**じゃあ、MFAデバイスの名前に私のユーザー名を付けてみよう。**

上手くいきました。
他の人も困るかもしれないから、管理者にも伝えておこう。

ということで、結論に書いた通りとなりました。

めでたしめでたし。
npmパッケージをリリース：ngx-visible-autofocus

はいさい！オースティンやいびーん！

## 概要

新しくnpmパッケージをリリースしたので、共有します！

https://www.npmjs.com/package/ngx-visible-autofocus?activeTab=readme

`ngx-visible-autofocus`です。

Angularで`HTMLElement`が見えてきた時に、それを自動的にフォーカスするDirectiveです。

## 問題

モーダルに隠れている`<input>`が見えた時に自動的にフォーカスさせたかった。

## 解決

IntersectionObserverを使ってDirectiveがついている部品を観察し、見えてきたらその要素に対して`.focus()`を呼ぶ

## 仕組み

部品ごとにIntersection Observerを作っていると、パフォーマンスが悪くなるので、ngx-visible-autofocusは、すべての部品に対して同じIntersectionObserverのインスタンスを使い回しています。

どうやって実現できたかというと、ngx-visible-autofocusは、`Symbol`を使って`HTMLElement`に自分のユニークな`Symbol`の鍵を、`AutoFocusDirective.attributeKey`の`Symbol`の属性に登録します。

そして、`AutoFocusDirective.callbackCache`にこの部品が見えた時に実行する`.focus()`を呼ぶ関数を、上記のユニーク`Symbol`の鍵で登録します。

そうすると、共通の`AutoFocusDirective`の静的IntersectionObserverがこのDirectiveがついている部品を見た時に、それにバインドされているコールバック関数を呼ぶことができるのです。

# デモ

![ezgif.com-gif-maker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344956/bb9c538a-0196-3562-324c-05505d42c73a.gif)

# まとめ

Angularを使っている人、もしこういう問題を抱えたことがありましたらぜひ使ってください！
卒論生のためのGitHub

# おことわり
この記事は，https://qiita.com/a_uchida/items/98b1e10c89d3119a2419 の続編です．
既にGitの使い方は理解されていることを前提としておりますので，ご了承の上お読みくださいますようお願い申し上げます．

# はじめに
GitHubをファイルのバックアップとして使用することも可能であり，それだけでも十分便利ではある．
しかし，GitHubにはその他にも多数の生産性向上のための機能が搭載されている．
卒論生にとって必須ではないものの，知っておくとかなり便利なGitHubの活用方法について紹介する．


# Issue
現時点で対応すべき事項を記載しておくことが可能．チーム開発を行う際は問題点と対応事項の詳細の共有にも便利．
論文執筆などの際は，タスクをまとめておくと良いだろう．
## Issueの作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/855517/d7f4567d-b7aa-2795-1d6d-adbf223c911f.png)
右上のNew issueと書いてあるボタンを押すと，Issue作成画面に移る．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/855517/ae09abfa-48a7-16b6-23c8-0fef0134b839.png)
情報を入力し，Submit new issueボタンを押すと新しいIssueが作成される．

## Issueと紐づいたブランチを作成する
ブランチとIssueを紐づけることにより，プルリクエストと紐づけることが可能になる．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/855517/6e48ea42-3594-3e36-732b-803831d7a2a2.png)
Developmentの箇所にある"Create a branch"と書いてある部分をクリックすると，GitHub上でブランチの作成が可能である．
作成後，ローカル上に反映させるためには以下のコマンドを入力する．
```
$ git fetch
$ git checkout <branch-name>
```

# Pull requests
GitHub上でブランチをマージするもの．Gitの機能だけでもマージだけなら可能であるが，マージ前にコードレビューをしやすくするためにこれを用いる．
チーム開発ではもちろん，個人でも差分の確認を簡単に行うことができる．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/855517/d314c370-944d-b259-6f47-403777dd3ef3.png)
ブランチに何らかのコミットをしていると，Compare & pull requestというボタンが表示されるので，これをクリックする．
すると，下記のプルリクエスト作成画面に移るので，必要に応じて情報を追記する．下の方でファイルの比較も可能．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/855517/06d8eeca-4ffd-8fd4-f31d-e3dc5f3a9784.png)
プルリクエストを作成すると，プルリクエスト詳細画面に移り，ファイルの比較やマージが可能．
マージするには，Merge pull requestをクリックする．
本記事では説明を省くが，マージ可能な条件を設定することも可能である．これにより，誤って不正なマージが行われないようにすることができる．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/855517/3d0c61ae-df0b-00f4-6c57-ef8c8cbe98d2.png)
Unity でPubSubを使い始める

# Unity でPubSubを使い始める
[Unity を使用して Firebase Cloud Messaging クライアント アプリを設定する  |  Firebase Documentation](https://firebase.google.com/docs/cloud-messaging/unity/client?hl=ja)

## Cocoapodsのインストール(IOSのみ)
[M1 Macでpod installを実行する](https://zenn.dev/akeome/articles/2433d792db022835c7e7)
sudo gem install cocoapods
sudo gem install ffi
pod setup
 => Oculousだからやらない?

## Apple Push Notification Authentication Key を取得(IOSのみ)
 [Apple Developer アカウント](https://developer.apple.com/account) にアクセス
 => Oculousだからやらない?

## Unityを入れて動かせるようにする
- Unityのダウンロード
[Download - Unity](https://unity3d.com/get-unity/download)
- Unity Hubへの登録とUnityHubのダウンロード
[Unity Hub – Manage Editor versions and collaborate with other creators | Unity](https://unity.com/unity-hub)

## Monoを入れる
[MacOSX上でNuGetを使う - Qiita](https://qiita.com/hnw/items/679a4756e3d792534b38)

```
 brew install --build-from-source mono
```

### Nugetを入れる
[MacOSX上でNuGetを使う - Qiita](https://qiita.com/hnw/items/679a4756e3d792534b38)

1. nugetのダウンロードとコピー
[NuGet Gallery        | Downloads](https://www.nuget.org/downloads)から*  [nuget.exe - recommended latest v6.0.0](https://dist.nuget.org/win-x86-commandline/latest/nuget.exe) をダウンロード

```
mkdir $HOME/bin/
cp /Users/ebiharamari/Downloads/nuget.exe $HOME/bin/nuget.exe
```

vi $HOME/bin/nugetで下記スクリプトの保存

```
#!/bin/sh
script_dir=“$(cd “$(dirname “${BASH_SOURCE:-${(%):-%N}}”)”; pwd)”
mono —runtime=v4.0 ${script_dir}/nuget.exe $*
```

### NuGetでMono.Cecilをインストールする
```
nuget list -Verbosity detailed Mono.Cecil
```

### GOOGLE_APPLICATION_CREDENTIALSを環境変数に設定

[.NET client library  |  Google Cloud](https://cloud.google.com/dotnet/docs/reference/Google.Cloud.PubSub.V1/latest/index)
  => TBD

### .NETを入れる
[Download .NET 5.0 SDK (v5.0.403) - macOS x64 Installer](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/sdk-5.0.403-macos-x64-installer)

### .NET のGoogleClientを入れる
[GitHub - googleapis/google-cloud-dotnet: Google Cloud Client Libraries for .NET](https://github.com/googleapis/google-cloud-dotnet)
[Using GCP NuGet Packages with Unity | by Jon Foust | Medium](https://jonfoust.medium.com/using-gcp-nuget-packages-with-unity-8dbd29c42cc4)
[Google Cloud Blog - News, Features and Announcements](https://cloud.google.com/blog/products/gcp/getting-started-with-google-cloud-client-libraries-for-net)

![GoogleClientInUnity.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89997/388eb97a-2cd7-05bc-3d9d-92f147d1f028.png)


### Unity側に実装
https://cloud.google.com/pubsub/docs/reference/rest

```
TBD
(今回の検証でたどり着けなかったが次回)
```
異なる国で、コンテンツを制御する方法を考えてみた。

ケーススタディ
---

__ある企業は、東京リージョン ap-northeast-1 の S3 バケットに静的データを保存、CloudFront で、S3バケットのコンテンツを提供し、アプリで閲覧出来るようしたいと考えている。事業拡大のため、シンガポールに進出したい。しかし、シンガポールの規制により、S3コンテンツは、国内にとどめる必要があるとユーザから要望があり、S3コンテンツは、 シンガポールリージョンap-southeast-1に置く必要がある。__

__開発する側としては、それぞれの国でアプリを展開するのは、負担が多く、やりたくない。__

__何をすべきか?__

ソリューション
---
Lambda@Edgeを使用して視聴者リクエストを任意のオリジンに動的にルーティングする必要があるので、オリジンとして 2 つの Amazon S3 バケットを作成し、それぞれに、インデックス.htmlファイルをアップロードする。

S3 バケット　東京リージョン ap-northeast-1　
S3 バケット　シンガポールリージョンap-southeast-1　

に該当する場合は、そのリージョンのS3コンテンツを表示する事が出来るようになる。

CloudFrontで、オリジンパスを空白のままで作成する。

CloudFrontのフォワードクッキーをホワイトリストに設定してオリジンを追加する。
(ブラウザでクライアント側で設定したオリジンクッキーをLambda関数に転送出来るようにする。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2920213/c5e66631-f3d3-eab4-2475-4934380f31fd.png)

CloudFront キャッシュの後、オリジンに戻る前に、トリガーを追加し、
複数のリージョン間で関数を自動的にレプリケート出来るようにする。
(Lambda 関数が各エッジロケーションにレプリケートされるようになる。)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2920213/e33f29c2-a757-b7b5-edfb-bc33abf00856.png)

結論
---
CloudFront ディストリビューション、およびクッキーに基づいてユーザーのリクエストを2 つの Amazon S3 オリジンのいずれか

S3 バケット　東京リージョン ap-northeast-1　
S3 バケット　シンガポールリージョンap-southeast-1　

にルーティングする AWS Lambda 関数を作成する。

そうすると、S3のオブジェクトが、 Amazon S3 から CloudFront に返され、

ユーザーの所属するリージョン

S3 バケット　東京リージョン ap-northeast-1　
S3 バケット　シンガポールリージョンap-southeast-1　


に該当する場合は、そのリージョンのS3コンテンツを表示する事が出来るようになる。

引用元
Lambda@Edgeを使用して任意のオリジンに視聴者リクエストを動的にルーティングする
https://aws.amazon.com/jp/blogs/networking-and-content-delivery/dynamically-route-viewer-requests-to-any-origin-using-lambdaedge/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2920213/c9dac431-eb95-3820-c9d9-d94d8e7701f7.png)
CentOS Stream/AlmaLinux に Ruby 3.2 をインストール

CentOS Stream 8 に Ruby 3.2 を rbenv でインストールしようとしたらちょっとつまづいた。その解決の記。

完全には理解せずに書いているので，何かご指摘があれば歓迎します。

（追記 2023-01-29）AlmaLinux 8.7 でもだいたい同様だったので，タイトルに「AlmaLinux」を付け加えた。

# 失敗

いつものように

```terminal 
sudo rbenv install 3.2.0
```

とすると，エラーが出てインストールできなかった。

メッセージを見ると，libyaml と libffi がナンチャラとか書いてある。
（エラーメッセージ保存しとくの忘れた，すまぬ）

# 調査

Ruby 3.2 では libyaml と libffi が同梱されなくなったため，インストールするにはそれが必要，ということはいろいろなところに書いてあった。

しかし，

```terminal
sudo dnf info libyaml libffi
```

と打つと，これらは既にちゃんとインストールされていることが分かった。へ？

さらにウェブ検索していると，パッケージとして必要なのは libyaml と libffi じゃなくて，**libyaml-dev** と **libffi-dev** らしいことも分かった。

ところが，

```terminal 
sudo dnf info libyaml-dev libffi-dev
```

としても「んなもんは無い[^nai]」と言われる。へ？

[^nai]: この「無い」は「インストールされてない」という意味ではなく，「インストール可能なパッケージとしてそんな名前のものは無い」という意味。

# 解決

その後，どうやって正解に辿り着いたのか覚えていないが，インストールすべきパッケージは **libyaml-devel** と **libffi-devel** であることが分かった。
要するに，OS によって -dev だったり -devel だったりする，ということらしい。

そこでこれらをインストールすることにした。

libffi-devel のほうは

```terminal
sudo dnf install libffi-devel
```

で OK だったが，libyaml-devel は

```terminal
sudo dnf install libyaml-devel
```

だとインストールできなかった。ええと，なんかエラーが出たんだっけか。ちゃんと記録してなかったので忘れた（すまぬ）。

なんだかよく分からないが，

```terminal
sudo dnf --enablerepo=powertools install libyaml-devel
```

とやったらインストールできた。

この状態で

```terminal
sudo rbenv install 3.2.0
```

とやったら Ruby 3.2.0 が無事にインストールできた。

# 付記

Ruby 3.2.0 では YJIT が本格導入された。手元のベンチマークテストでは，良い成績を上げるケースがいくつかあったので，YJIT が使える状態でインストールするのが良い。

Rust がインストールされた状態で Ruby 3.2.0 をインストールすると YJIT アリでインストールされる。

Rust のインストールは（私の経験の範囲では）Ruby のインストールよりも簡単だ。ぜひ。

本記事のテーマではないので具体的なことは略す。
エンジニアマネージャー必見：再現性への道

![25407014_s.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23130/aed82673-e177-a4ca-e215-8e01272042c2.jpeg)

いきなりですが、僕はゴルフ大好きです！
毎日でもやってたいくらいですが、全く上手になりません。ゴルフって簡単そうに見えるのですが、１ミリクラブをおろしてくる位置が変わるだけで、飛んでいくボールが全く変わってきます。ボールが小さい分、少しのクラブのズレで大きな変化を及ぼしてしまいます。毎回同じ様にスイングをする難しさと日々戦ってる感じです。
飛距離なんていりません。スイングの再現性に日々悩んでますが、上手に出来ません。池があったり、崖があったりで見た目のプレッシャーとか、飛ばそうとか良いスコアだそうとか自身の欲だったり、斜面だったり寒かったり環境の問題だったり、様々なものが再現性を妨げてきます。

# ゴーイング・コンサーン
当然ですが、経営は再現性がとても重要です。ゴーイング・コンサーンです。
会社は、将来にわたって事業継続していくとの前提となってます。ギャンブル的に万馬券を当てるのではなく、常に当て続けていく必要があります。そーでないと、利用ユーザー、クライアントは安心してサービスを受けることが出来ないし、社員は安心して働く事ができません。
経営者の方々は常に再現性を意識してジャッジされているのではないでしょうか？

# マネジメントは再現性が難しい
ゴルフの比ではありません。ゴルフでは結果は全て自分がもたらしたものです。全部自分の責任です。
しかし、経営は、多数の社員が居て、沢山のクライアント、ユーザーが居て、仕入先が居たり、関係会社等のステークホルダーが沢山存在してなりたってます。変数の数は半端なく多いためコントロールが非常に難しいですが、それでもコントロールしないとステークホルダーが安心して関わってくれる事が出来なくなります。

# マネジメントの再現性を高めるには
## １．リスクをコントロールする
いつも万馬券を当てているマネジメントでは、ステークホルダーから見放されてしまいます。リスクをコントロールする事が必要になります。リスクのコントロールとは、リスクに関しての確率を下げながら、保険をかけるという事です。
- 納期に間に合わせるために人を増やしながら、納期を少し早めに伝えてバッファを作る
- セキュリティの教育を行い、フレームワークでセキュリティ担保しながら、脆弱性診断を受ける
- 退職率を下げるための施策を行いながら、人員採用を強化する
リスクが現実的になった時に仕方ない、運が悪いと思っていてはマネジメント失格です。リスクをコントロールする施策を事前に施す事が必要です。

## ２．人財教育
老子の素晴らしい言葉
```
魚を与えれば一日生きていける
釣りの仕方を教えれば一生行けていける
```
マネジメントの立場からは、ゴーイングコンサーンのためには、メンバーに釣りの仕方を教える事です。
ついつい魚を与えてしまってるマネジメントの方が沢山います。
納期に間に合わないからといって、メンバーの代わりにソースコードを修正してあげても、それは今回は、納期に間に合うけれど、次に同じ事が起きた時にそのメンバーは解決できません。ソースコードの修正する理由、ソースコードの修正の仕方を教えてあげましょう。

## ３．自動化する
エンジニアですから自動化です！人の判断や操作をシステム化してしまえば、ミスを減らす事ができます。判断する事をなくせば、時間の節約になります。プログラムによりシステム化するだけではなく、人による２重チェックや定形作業化も自動化の一つです。ルーチン化できる様にフローを再検討してみましょう。

## ４．変数を減らす
変数が多いと対処するリスクコントロールの数が増えます。変数を減らすことでリスクのコントロールが楽になります。例えば、
- アジャイル開発に移行して納期の概念をなくす
- インフラをクラウドに移行してサーバー管理を減らす
- メンバーを業務委託メンバーにして退職リスクを減らす

気付いてない事が多いですが、変数が多いことで意外に工数が掛かってる事がめちゃくちゃあります。変数はドンドン減らして管理を簡単にすべきです。

# まとめ
マネジメントの仕事の大半は、再現性を高める事です。究極的に再現性を高めて自分の仕事をなくす事が仕事だと思いましょう。自分の仕事をなくして次の仕事を見つける事で組織が大きくなります。忙しいと思ってるマネジャーはマネジメントが出来てないマネジャーです。忙しいと自己満足しているだけです。本来やるべきタスクを認識し、次のステージを目指しましょう。
ひき続き記事を書いていきますので、フォロー、イイねお願いします！
Kino.VegaLiteのグラフアニメーション表示

グラフアニメーション表示をやってみました。

# 表示領域を確保

最初に、Kino.render()で、グラフを描画する領域を確保しておきます。
Kino.render()が返した値を保存(wl_wiget)しておいきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532235/be908875-118e-4eeb-b0f9-a0f94e9a81da.png)

# グラフの描画

Kino.VegaLite.push_manyを使ってグラフのデータを更新してアニメーション表示します。

ポイントは、この更新方法です。
push_manyは、データを追加するためのもので、グラフ全体を書き直す機能はもっていません。
どうやらグラフ全体を書き換える手段がありません。

Kino.VegaLite.clear()でクリアして再描画するという力業を使ってます。
push_manyにclearオプションがあってもいいかも。

描画と描画の間が短かすぎるとちらついたりします。適当に時間をあけます。
`Process.sleep(20)`で20msec停止させてみました。

```Elixir
Kino.VegaLite.clear(vl_widget)
Kino.VegaLite.push_many(vl_widget, points)
```

sin波が移動しているデモを作ってみました。
動画は、https://github.com/masahiro-999/kino-animation
を見てください

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532235/017cb949-190e-6098-962f-ae71a8e4e8e8.png)

# livemd全体

以下の通りです。
# kino-animation

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

## Section

```elixir
alias VegaLite, as: Vl

vl_widget =
  Vl.new(width: 800, height: 400)
  |> VegaLite.mark(:point, tooltip: true)
  |> VegaLite.encode_field(:x, "x", type: :quantitative)
  |> VegaLite.encode_field(:y, "y", type: :quantitative)
  |> Kino.VegaLite.new()
  |> Kino.render()

plot = fn x, y ->
  points =
    [x, y]
    |> Enum.zip()
    |> Enum.map(fn {x, y} -> %{x: x, y: y} end)

  Kino.VegaLite.clear(vl_widget)
  Kino.VegaLite.push_many(vl_widget, points)
end
```

```elixir
target_func = fn x, t -> :math.sin((x - t) * :math.pi() * 2) end
x = for i <- 0..100, do: i / 100

for i <- 0..1000 do
  t = i / 100
  y = for x1 <- x, do: target_func.(x1, t)
  plot.(x, y)
  Process.sleep(20)
end

nil
```

ソースファイル
https://github.com/masahiro-999/kino-animation
jQueryの基本構文

### jQueryについて最近学んだこと

最近**Progateで本格的にjQuery**について学び始めました。
もう一度jQueryを学んだところの再確認したいので、記事にいたします。(すぐに忘れてしまうもんで💦)


![jQ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678283/6e53086a-92f4-147b-175d-9732d844784a.jpeg)

```javascript
$(function(){


    $('セレクタ').イベント(function(){
        $('どこを').メソッド();
    });


});
```


これをちゃんとしたコード例で書くと...
```javascript
$(function(){

    $('#hoge-btn').click(function() {
        $('.hoge-img').fadeOut();
    });

});
```
要約すると、

:::note info
**id指定hoge-btn**を.**click**(クリックされたら)
**class指定hoge-img**を.**fadeOut**(フェードアウト)させる
:::

という意味になります！

```javascript
  $('.lesson').hover(function() {
      
      $(this).find('.text-contents').show();
      
    },
    function() {
      
      $(this).find('.text-contents').hide();
      
  });
```



|使ったことのあるイベント一覧|   　　　　　　　　効果　 　　　　　 　  　|
|:-----------|------------:|
| .**click**     |要素がクリックされたら      |
| .**hover**     |要素がhoverされたら      |



|使ったことのあるメソッド一覧　　　　　　　　　　|   　　　　　　　　引数の表記法　 　　　　　　　　　　　　　　　 　  　|   　　　　　　　　効果　 　　　　　 　  　|
|:-------------------|------------------------------|-----------------:|
| .**fadeIn();**|'slow'　・　１０００=1秒|ふわっとアニメーション|
| .**fadeOut();**|'slow'　・　１０００=1秒|ふわっと消えるアニメーション|![uploading...0]()
| .**slideUp();**|'slow'　・　１０００=1秒|下から上へスライドアニメーション|
| .**slideDown();**|'slow'　・　１０００=1秒|上から下へスライドアニメーション|
| .**children();**||指定したセレクタの一階層下の子要素指定|
| .**hide();**||要素を非表示させる|
| .**show();**||要素を表示させる|
| .**css();**|'display' , 'none'　・　'color' , 'red'|CSSを指定できる|
| .**html();**|'こんにちは'|html内の書き換え、等|

まだまだわからないことがあるので、今は空白のままですが随時更新していきます。
FastAPIのパスオペレーションに前処理・後処理を書くためのライブラリを作った

# 概要
[fastapi-decorator-helper](https://github.com/tokno/fastapi-decorator-helper)

APIの前処理・後処理をデコレーターで書くためのライブラリ。
下記の `@require_privilege` のようなデコレーターを作るためのヘルパークラス。

```python
@app.delete('/user/{user_id}')
@require_privilege('admin')
def delete_user(user_id: str):
  # ユーザーを削除する処理
  ...
```

# 動機
複数のエンドポイントに共通する仕様をデコレーターで宣言的に表現したかった。

Web APIを作っていると以下のような仕様を持つエンドポイントが出てくることがよくある。
 * 管理者ユーザー以外のリクエストにはステータスコード403を返す
 * エンドポイントがステータスコード200を返す場合、ヘッダーに `Cache-Control max-age` を追加する

共通の仕様を持つエンドポイントだけに適用される前処理・後処理を書きたいが、FastAPIにはその仕組みがない。
middlewareで前処理・後処理を書くことができるが、middlewareだと全てのリクエストに適用されるため、エンドポイント毎に適用するしないを分けられない。

# ライブラリの使い方
## デコレーターを定義する
```python
from fastapi_decorator_helper import DecoratorHelper, ExecutePathOperator

def require_permission(name):
    # ヘルパーのインスタンスを生成
    helper = DecoratorHelper()

    # デコレーターをラップする
    @helper.wraps
    def wrapper(request: Request, next: ExecutePathOperator):
        # ユーザーが権限を持つかチェックするコードをここに書く
        ...

        # パスオペレーションを実行する
        return next()

    return wrapper
```

デコレーターはRequestオブジェクトやパスパラメータ等、パスオペレーションと同様の引数を受け取れる。

## パスオペレーションにデコレーターを付ける
```python
@app.delete('/user/{user_id}')
@require_privilege('admin')
def delete_user(user_id: str):
  # ユーザーを削除する処理
  ...
```

おわり。

# 今後の機能追加案
デコレーターでdocstringを拡張できると便利かもしれない。
以下のように使う。

```python
def allow_cache(max_age):
  helper = DecoratorHelper()

   @helper.wraps
    def wrapper(next: ExecutePathOperator):
      ...

  # ★docstringに情報を追記できる★
  helper.extend_document(f'''
    このエンドポイントがステータスコード200を返す場合、クライアントはレスポンスをキャッシュできる。
    max-ageは{max_age}。
  ''')

  return wrapper
```

APIの仕様をデコレーターで表現するため、その仕様がOpenAPIのドキュメントに反映されるとうれしい。
VANTRUE Element 1 Lite Hack

# ドラレコだけど、リアルタイムに動画を撮りたい
車の前方映像をOpenCVで処理したいと思って、でも毎回車の中にPC持ち込むのもやだなと。
しかも、Webカメラとかだと、台座とかも考えないといけない。

GoProも考えたけど、夜をメインに取りたいから、初めから車載で撮ること想定しているドラレコのほうがいいかなと。
そんな中、物色していたら、WiFi付きのドラレコを発見。スマホから動画見ることができるので、PCからも撮れるかもと。
さらに調べると、```VANTRUE Element 1 Lite```が3000円引きで売ってるので、見切り発車で購入。


# ドラレコを卓上で使う
PCに直接USBで繋ぐと、SDカードリーダモードになるので、電源アダプタで繋ぐとカメラとして動く。
台座に繋げた場合だけ、カメラとして動く懸念もあったけど、それはクリア。カメラ本体だけ卓上で使えそう

# PCからドラレコの映像を見る
結論から言うと、ドラレコにwifi接続して、```rtsp://192.168.1.254/xxx.mov```で見れた。
ただ、割と遅延があり（体感１～２秒）、Webカメラと全く同じというわけにはいかない。

が、当初の目的である、OpenCVで動画取り込みは達成！

```python
import cv2

cap = cv2.VideoCapture(f"rtsp://192.168.1.254/xxx.mov")

while(True):
    try:
        ret, frame = cap.read()
        if ret == True:
            cv2.imshow('VIDEO', frame)
        cv2.waitKey(1)
    except KeyboardInterrupt:
        print("KeyboardInterrupt")
        break

cap.release()
cv2.destroyAllWindows()
```


# どうやって調べたか
ドラレコにポートスキャンをかけたら、80やrtspが開いていたので、ダミーのhttpサーバ立ててリクエストをチェック。

今回は、スマホアプリが割と無防備にリクエストしてくれたので、そのリクエストをPCからドラレコに投げて確認。

```GET /?custom=1&cmd=2019 HTTP/1.1```
のリクエストに対して、
```xml
<?xml version="1.0" encoding="UTF-8"?>
<LIST>
  <MovieLiveViewLink>rtsp://192.168.1.254/xxx.mov</MovieLiveViewLink>
  <PhotoLiveViewLink>rtsp://192.168.1.254/xxx.mov</PhotoLiveViewLink>
</LIST>
```
と返して来たので、これかなと。ラッキー。

ちなみに、```MovieLiveViewLink```でgoogleしたら、中国語のサイト1つ発見、どうもこれと同じI/Fっぽい。
ちゃんと読めば、PC版のVantrueCamを作れるかも（作る気ないけど、写真は取れると嬉しいかも？）

https://www.6zhentan.com/opendoc/pages/base/nvt.html
3万円台でゲーミングPC（i3-8100, GTX1650, 200W電源）

## 概要
* いわゆる企業官公庁からの払い下げSFFデスクトップPCにグラボを刺したゲーミングPCです。
* この構成は数年前から大手中古ショップや個人の販売など多く見かけられる構成です。
* 今回の目玉はライザーケーブルの利用と**200W電源でGTX1650**の動作報告です。
* 完全に趣味なので参考までに。

## 構成
* OptiPlex 3060 スモール・フォーム・ファクタ (SFF)　中古 15000円
    * CPU: i3-8100
    * メモリ: 8GB×1 
    * HDD: 500GB
    * 電源: 200W
    * キーボード&マウス
* GPU: ZOTAC GTX1650 GDDR6　中古 16000円
* EZDIY-FAB PCI Express PCIe3.0 16xライザーケーブル 30cm　3000円
* SEKC SSD 512GB NVMe M.2 2280 PCIe Gen3.0x4 SSD　4000円
* 合計 3万8000円

HDD取り外し、マザボにM.2のコネクタがあるのでそこにSSDを取り付け。

## 200W電源の皮算用
* 供給電力 
    * ~~200W電源, 効率80% 200*0.8 = 160W~~
    * 200W電源 200W （私の勘違いで200W電源は200W供給できました。変換効率は関係ないです。余談ですが電源容量の経年劣化は1年で1%程度らしいです。）
* 消費電力(TDP)
    * CPU: 65W
    * GPU: 75W
    * その他 20W
    * 合計 160W

- 余裕なんて全くないわけですが、最大消費電力で動くことはまれなので大丈夫。
- GPUはAfterburnerでクロック制限できるのでピークを抑えることはできる。

## ライザーケーブル
* いつからかSFFゲーミングPCはよく出回るようになりロープロファイルGPU（細いGPU）の価格が高騰してしまいました。中古市場も例外でなく有望なGPUはほとんど在庫がない状態です。
* ケースのふたが閉まらなくてもいいと思ってロープロファイルでないGPUを買ってみました。
* もう一つ問題があり、OptiPlex 3060 SFFはシングルスロットしか取り付けられない点です。いわゆる薄いGPUしか取り付けられないようになっています。
* そこでライザーケーブルでケース外に無理やりつけたのが今回の構成の顛末です。

## 写真
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242971/c695ed9f-4472-1c92-fa95-dce71037f8ab.png)

## GeekBench5
https://browser.geekbench.com/v5/compute/6133269
https://browser.geekbench.com/v5/compute/6176488
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242971/ad71cb35-989a-cd39-0834-80b5c93bef01.png)

## 余談
- 頑張れば右上の空きスペースにGPUを入れられそう。蓋が閉められる。
- RX6400のシングルスロットロープロファイルを買えばこんなことしなくてもいい。TDP50Wなので問題なく動く。蓋も閉まる。
- もう少しCPUパワーが欲しいところ。
- 手持ちのノートパソコンRyzen5500Uと比べるとi3-8100はあまりにも非力。試しにGTX1650なしでRimworldなど動かしたのですがCPUも内蔵GPUもノート用のRyzenの方がずっと良いです。SteamのインディーズゲームやLoLのような比較的軽量なゲームなら最近のノートPCで十分です。
別のプロジェクトへVMを作成してみよう

<a href="url">NI+Cアドベントカレンダー</a> 2022の25日目の記事です。
本記事では、GCEのスナップショットを用いて、別のプロジェクトに新たに作成する内容について記載します。

## 目次
1. 背景
1. 実装方式
1. 考察

## １．背景

現在のプロジェクトA（project-a）にあるスナップショットから、別のプロジェクト（project-b）でVMを新規作成したかった。調べたところ、Google Cloudのコンソール（GUI）から出来なかったため、備忘として残したい。

* GUIで可能なもの
    * 同じプロジェクトでスナップショットをもとに新規VMインスタンス作成
    * 異なるプロジェクトから、カスタムイメージをもとに新規VMインスタンス作成

* 構成イメージ
    * 以下図の通り。至ってシンプルですね。
![構成イメージ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2361584/24330e16-0dd2-ebbc-84e3-4caed3e7191d.png)

## 2．実装方式
### ① VM のブートディスクのスナップショットを作成

:::note info
記述内容
asia-northeast1-bにあるgce-a-diskのソースディスクをもとに、スナップショットsnapshot-gce-aを作成
:::

```ruby:実行環境：プロジェクトA（Cloud SDKで、project-a をセットする）
gcloud compute snapshots create snapshot-gce-a \
    --source-disk gce-a-disk \
    --source-disk-zone(region) asia-northeast1-b(asia-northeast1)
```

リージョンブートディスクの場合は、`` `（　　）` ``の記載を指定します。

#### ② スナップショットからカスタム イメージを作成

:::note info
記述内容
スナップショットsnapshot-gce-aをもとに、gce-a-customimageというカスタムイメージを作成
:::

```ruby:実行環境：プロジェクトA（Cloud SDKで、project-a をセットする）
gcloud compute images create gce-a-customimage \
    --source-snapshot=snapshot-gce-a \
    [--storage-location=asia-northeast1]
```
`` `[　　]` ``ストレージのロケーションは省略可能です。

#### ③ スナップショットからカスタム イメージを作成

:::note info
記述内容
project-bのsubnet-bに、project-aにあるgce-a-customimageのイメージをもとにGCEインスタンスを作成
:::

```ruby:実行環境：プロジェクトB（Cloud SDKで、project-b をセットする）
gcloud compute instances create gce-b \
    --image-project project-a \
    --image gce-a-customimage \
    --subnet subnet-b
```

**※前提条件** 
上記手順を実施する際には、カスタムイメージを作成可能にする権限が必要です。
今回は実施にあたって、Compute ストレージ管理者 権限を付与し、実行しました。詳細は以下リンクをご参照ください。
<a href="https://cloud.google.com/compute/docs/images/managing-access-custom-images?hl=ja#create-custom-images-permission" target="_blank">カスタム イメージへのアクセスの管理 | Compute Engine ドキュメント | Google Cloud</a>

## 3．考察

本手順は、スナップショットから直接VMを作成しているわけではなく、一度イメージを作成する処理を挟んでいることが分かりました。

![実際の処理の流れ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2361584/c35cec21-40a7-17bf-4914-3ff8441b5195.png)

今回、やりたいことは至ってシンプルでしたが、移行元・移行先のどちらの環境で動作させるのかであったり、各種リソース名をしっかりと意識する必要があります。実際にコマンドを入力した際にも、エラーが出たりしたケースもあったりと試行錯誤をしてしまいました。

２つのプロジェクト間でコマンドを実行する場合は、権限が充足しているのか予め確かめ、正しいリソースを指定できているかを構成図を書いたりしてみる方が返って、スムーズに進むかもしれませんね。

## 4．参考

<a href="https://cloud.google.com/compute/docs/instances/copy-vm-between-projects?hl=ja#copy_a_vm_to_another_project" target="_blank">プロジェクト間での VM のコピー | Compute Engine ドキュメント | Google Cloud</a>
Microsoft ストア版 WSL(Windows Subsystem for Linux) インストール

# はじめに
WSL(Windows Subsystem for Linux) は、Windows 上でネイティブの Linux を起動することができます。WSL は、Windows 10/11 の機能として提供されていましたが、Microsoft ストアからも入手できるようになりました。WSL を Microsoft ストア経由で取得することで、Windows OS を更新することなく、最新の WSL を利用できるようになります。
ここでは、Microsoft ストア版 WSL のインストール方法を説明します。
# 前提条件
- Windows 11
  - もしくは、Windows 10 バージョン 2004(20H1) Build 19041 以降

(*) 既に、WSL をインストール済でもストア版へ移行できます。

# Microsoft ストアから WSL をインストール
[Windows の機能の有効化または無効化] から [仮想マシンプラットフォーム] をインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172205/02164eb4-7445-b5eb-a9fc-c09be3392ae7.png)

Microsoft ストアから、[Windows Subsystem for Linux] をインストールします。
[https://aka.ms/wslstorepage](https://aka.ms/wslstorepage) から、Microsoft ストアを起動し、[Windows Subsystem for Linux] を選択できます。
(*) 既に WSL をインストールしていてもこの手順で、Microsoft ストア版 WSL へ移行できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172205/6396dfe6-8d43-ac25-4389-edc188c95ee5.png)

コマンドラインで、`wsl --version` を実行し、各バージョンが表示されたら正しくインストールされています。
    
    C:\>wsl --version
    WSL バージョン: 1.0.3.0
    カーネル バージョン: 5.15.79.1
    WSLg バージョン: 1.0.47
    MSRDC バージョン: 1.2.3575
    Direct3D バージョン: 1.606.4
    DXCore バージョン: 10.0.25131.1002-220531-1700.rs-onecore-base2-hyp
    Windowsバージョン: 10.0.22621.963

# Linux ディストリビューションのインストール
あとは、好みのディストリビューションを Microsoft ストアから検索し、インストールしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172205/0c7af410-7403-59c9-3e11-3aebfbbc46ec.png)

# WSL での systemd サポート
WSL バージョン 0.67.6 以降では、systemd がサポートされるようになりました。
デフォルトでは無効になっているので、systemd を有効にする場合は、対象とするディストリビューションで、以下の設定を行ってください。

/etc/wsl.conf ファイルを作成。

    $ sudo vi /etc/wsl.conf

下記の内容をファイルに記述して保存。

    [boot]
    systemd=true

以下のコマンドで、Windows 側から、WSL をシャットダウン。

    C:\>wsl --shutdown

対象のディストリビューションを起動し、以下を実行。

    $ systemctl list-units --type service --all

各サービスのステータスが表示できれば、systemd が有効化されています。


# 参考サイト
- [Release Notes for Windows Subsystem for Linux in the Microsoft Store](https://learn.microsoft.com/en-us/windows/wsl/store-release-notes)
- [A preview of WSL in the Microsoft Store is now available!](https://devblogs.microsoft.com/commandline/a-preview-of-wsl-in-the-microsoft-store-is-now-available/#how-to-install-and-use-wsl-in-the-microsoft-store)
- [Systemd support is now available in WSL!](https://devblogs.microsoft.com/commandline/systemd-support-is-now-available-in-wsl/)
PostgreSQL でちょっとした性能試験や検証で使えるサンプルデータベース

# 概要

* クラウドサービスから新たなストレージエンジンのサービスが出た時に実際の性能評価やちょっとした検証をある程度作り込まれたデータベースでやりたくなる人も多いのではないでしょうか。
* 今回そんな時に使えるサンプルのデータがあったのでちょっと紹介します。

# PostgreSQL Tutorial

* PostgreSQL Tutorial にサンプルのデータを用意してくれているので、そちらを利用します。

https://www.postgresqltutorial.com/postgresql-getting-started/postgresql-sample-database/


* 例えばローカル環境上に構築するとして、一旦コンテナで検証してみます。

```
> docker run -d --name=postgres -p 5432:5432 -e POSTGRES_PASSWORD=postgres postgres
```

* 下記よりサンプルをダウンロードします。

![スクリーンショット 2022-12-27 1.59.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563635/19e55d8f-3bce-91c0-f066-9605784b3444.png)

* 次に、PostgreSQL 内でサンプルのデータを流すためのデータベースを作成します。

```
> CREATE DATABASE dvdrental;
```

* 次に unzipコマンド を用いてダウンロードしたzipを解凍します。

```
> unzip dvdrental.zip
```

* 次に下記のコマンドを実行します。

```
> pg_restore -h localhost -U postgres -d dvdrental ./dvdrental.tar
```

* これで準備完了です。
* PostgreSQLに入って状況を確認します。

```
> psql -h localhost -p 5432 -U postgres -d dvdrental;
> \dt
dvdrental=# \dt
             List of relations
 Schema |     Name      | Type  |  Owner
--------+---------------+-------+----------
 public | actor         | table | postgres
 public | address       | table | postgres
 public | category      | table | postgres
 public | city          | table | postgres
 public | country       | table | postgres
 public | customer      | table | postgres
 public | film          | table | postgres
 public | film_actor    | table | postgres
 public | film_category | table | postgres
 public | inventory     | table | postgres
 public | language      | table | postgres
 public | payment       | table | postgres
 public | rental        | table | postgres
 public | staff         | table | postgres
 public | store         | table | postgres
```

* ちなみに作成されるデータベースの ER 図は下記となります。 

![スクリーンショット 2022-12-27 2.14.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563635/6621f99c-bb27-daac-9e04-7f283082484a.png)



# 参考資料

https://www.postgresqltutorial.com/postgresql-getting-started/postgresql-sample-database/
Djangoのannotate()

データベースのレコードをオブジェクトとして取得する際、データベースと直接クエリをやり取りするのは「クエリセットAPI」と呼ばれるものです。
テーブルを検索する際はモデルのモデルマネージャーを経由してクエリセットAPIのメソッドを呼び出します。
（引用元：[現場で使えるDjangoの教科書](https://www.amazon.co.jp/%E7%8F%BE%E5%A0%B4%E3%81%A7%E4%BD%BF%E3%81%88%E3%82%8B-Django-%E3%81%AE%E6%95%99%E7%A7%91%E6%9B%B8%E3%80%8A%E5%9F%BA%E7%A4%8E%E7%B7%A8%E3%80%8B-%E6%A8%AA%E7%80%AC-%E6%98%8E%E4%BB%81/dp/4802094744)）


クエリセットAPIのメソッドには
・**get()** 1件のオブジェクトを取得する
・**all()** レコード全件に対応するオブジェクトのリストを取得する 
・**filter()** 検索条件を付けてオブジェクトのリストを取得する
など多数のメソッドが用意されています。

今回はannotate()メソッドについて説明します。


## annotate()

annotateという動詞が「注釈を付ける」という意味を持つように、
annotate()メソッドは各オブジェクトに即席のカラムを追加するような役割をします。

親であるBlog（ブログ）モデルと、子であるEntry（投稿）モデルがあるとして、annotate()は以下のように使うことができます。


```python
# Blogモデルにnumber_of_entries（投稿数）という名前で注釈を付ける。
# Count()という集計関数を使い、引数に逆参照先のモデル名を指定し、Blogオブジェクトと紐づくEntryオブジェクトの数を集計します。
>>> q = Blog.objects.annotate(number_of_entries=Count('entry'))

# オブジェクト.注釈名とすることで、Blogオブジェクトと紐づくEntryオブジェクトの値を返すことができます。
>>> q[0].number_of_entries
42
```
またnumber_of_entriesのようなキーワードを付けず、下記のようにすることもできます。

```python
# 注釈のキーワードを付けず、集計関数のみ。
>>> q = Blog.objects.annotate(Count('entry'))

# 逆参照先モデル名__countとすることで、前述と同様の結果が得られる。
>>> q[0].entry__count
42
```


## 参考
[QuerySetAPI リファレンス｜djangoドキュメント](https://docs.djangoproject.com/en/4.1/ref/models/querysets/#annotate)
vscode における devcontainer でのライフサイクルスクリプト

# 概要

* vscode における devcontainer を使用しての開発環境構築をやっている人も多いと思います。
* 今回は、devcontainer におけるコンテナのライフサイクルの観点で用意されているコマンドの使い分けについてをまとめていきます。

## devcontainer におけるライフサイクルスクリプト

* .devcontainer/devcontainer.json 内に devcontainer で起動されるコンテナのライフサイクルごとに実行されるコマンドを仕込むことができます。
* 使い方としては、例えばコンテナ作成時に sh を1回限りで実行したいとか devcontainer 起動時には毎回実行してほしいといった要望があるときに用意されているコマンドを仕込んでおくと実現できます。

使い方の例

```.devcontainer/devcontainer.json
{
  "name": "hoge",
  "image": "hoge",
  "postCreateCommand": "sh create.sh",
  "postStartCommand": "sh start.sh"
}
```


|  Property  |  説明  |
| ---- | ---- |
|  initializeCommand  |  コンテナが作成される前にホストマシンで実行されます。  |
|  onCreateCommand  |  postCreateCommand と同様にコンテナが初めて開始された直後にコンテナ内で実行されます。(devコンテナ作成時にコンテナをセットアップする3つのステップのうちの１番目)  |
|  updateContentCommand  |  作成プロセス中に新しいコンテンツがソースツリーで利用可能になるたびに、onCreateCommand の後にコンテナ内で実行されます。(devコンテナ作成時にコンテナをセットアップする3つのステップのうちの2番目)  |
|  postCreateCommand  |  updateContentCommand の後に dev コンテナが初めてユーザーに割り当てられたときに実行されます。(devコンテナ作成時にコンテナをセットアップする3つのステップのうちの3番目)  |
|  postStartCommand  |  コンテナが正常に開始されるたびに実行されます。  |
|  postAttachCommand  |  ツールがコンテナに正常にアタッチされるたびに実行されます。  |


# 参考資料

https://containers.dev/implementors/json_reference/
【js】javascript特有の今まで出会ったクラス宣言（オブジェクト宣言）

# javascript特有のクラス宣言
2022年から新卒エンジニアとして開発していて、これまでjavascript特有のクラス宣言を見てきました。その中には最近知ったものもありましたので、今回は私が今まで見てきたクラス宣言の紹介したいと思います。

# ただの連想配列
```javascript
/*
連想配列に無名関数を設定して擬似クラスを作成する
イニシャライズの代わりにディープクローンをする
*/
const classOne = {
    init() {
        print('============11')
    },
}
const classOneIncetance = { ...classOne }
classOneIncetance.init()
```
このケースの1番のデメリットはイニシャライズが存在しなく、インスタンスが生成されないことです。今回はディープクローンで擬似的にイニシャライズしていますが、連想配列の階層がもう１つ深くなるとクローンできなくなるので注意が必要です。

# new 演算子
```javascript
/*
オブジェクト型やコンストラクター関数を持つ組み込みオブジェクト型のインスタンスを作成
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/new
*/
function classTwo() {
    this.init = function() {
        print('============22')
    }
}
const classTwoInstance = new classTwo()
classTwoInstance.init()
```
これが最近知ったクラス宣言です。new演算子を使うことでインスタンスが生成されます。

# クラス
```javascript
/*
一般的なクラス宣言
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Classes
*/
class classThree {
    init() {
        print('============33')
    }
}
const classThreeInstance = new classThree
classThreeInstance.init()
```
これがES5から使えるようになったクラス宣言です。newすることでインスタンスが生成されます。
最近ではプライベートなデータやメソッドが持てるようになっています。

### 最後に
他のクラス宣言の方法を知ってたり、間違いに気づいたたは、コメントお願いします。
【Ubuntu】パッケージ管理についてパターンを整理してみた

# 結論
最新の安定版のパッケージ使いたい yes→ ３．１方式でリポジトリ登録
no↓
対象のバージョンはdeb形式でリポジトリにある（最悪公式リポジトリでなくても） yes→３．２方式でリポジトリ登録
no↓
今回は触れないソースを探してインストールする方式になりそう（ソース：http://nginx.org/en/download.html）

# 目的
Ubuntuのnginxパッケージのインストールを通じてパッケージ管理を理解する

#  概要
方法は下記の２つ
① ソースからインストール → 割愛（ソースからインストールしてコンパイルすれば基本行ける）
② リポジトリに登録

# 以下は２のパターンで使う
１．リポジトリの登録方法（やっていることは基本的に同じはず）
 １．１ リポジトリ追加コマンドを使う（add-apt-repositoryコマンド）
 １．２ viコマンドで直書き
 １．３ aptlyコマンド （https://gihyo.jp/admin/serial/01/ubuntu-recipe/0485）

２．リポジトリの登録先
 ２．１ /etc/apt/sources.list → 既存のリポジトリのリストに追加する
 ２．２ /etc/apt/sources.list.d/hoge.list → 新しくリポジトリを作成する
どちらでもできないことはないが標準で入ってるもの（２．１）と区別するために２．２がオススメ

３．リポジトリの情報をどこから持ってくる？
 ３．１公式リポジトリの場所をリポジトリのフォーマットに基づいて指定する（deb [ option1=value1 option2=value2 ] uri suite [component1] [component2] [...]）
 ３．２wgetなどで直接パッケージをサーバ内に配置してそれをfileスキーマでリポジトリから参照する
 ・
 ・
下記参考リンクのスキーマを満たす方法がいろいろある
https://gihyo.jp/admin/serial/01/ubuntu-recipe/0677#sec2

# いざ検証
## 方法１（３．１に該当）
※厳密な手順はこちら（http://nginx.org/en/linux_packages.html#Ubuntu）

APTリポジトリのGPG鍵を取得して登録gpgコマンドでデコードをしてnginx-archive-keyring.gpgを作成しました。なおgpgキーは登録したAPTリポジトリからダウンロードするパッケージの正当性を証明するために使われます
```
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
    | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null

```
sources.list.dに新しく作るほうがいいです（推奨）。あえて変化球でsources.listにリポジトリのフォーマットに基づいて登録します
```
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/mainline/ubuntu `lsb_release -cs` nginx" \
| sudo tee /etc/apt/sources.list
# リポジトリを追加したのであぷで
apt update
apt list | grep nginx
```
最後のコマンドでnginxのパッケージ一覧確認したが私は下記のnginxが含まれていた
nginx/stable,now 1.23.3-1~jammy amd64 [residual-config]
あとはsudo apt install nginxとすればインストールされる

## 方法２（３．２に該当）
※ぶっちゃけこちらの方のほうが丁寧に説明してる（https://gihyo.jp/admin/serial/01/ubuntu-recipe/0677#sec5）
今回は試しにnginx_1.21.6-1~jammy_amd64.debを使う
```
sudo mkdir -p /srv/apt/repository/nginx_1.21.6
sudo chown $USER: /srv/apt/repository/nginx_1.21.6
cd /srv/apt/repository/nginx_1.21.6
wget http://nginx.org/packages/mainline/ubuntu/pool/nginx/n/nginx/nginx_1.21.6-1~jammy_amd64.deb
```
下記コマンドで対象リポジトリのメタデータ作成（sudo suに切り替えた）
```
apt-ftparchive packages . > Packages
echo "deb [trusted=yes] file:///srv/apt/repository/nginx_1.21.6/ ./" \
  | sudo tee /etc/apt/sources.list.d/local.list
sudo apt update
```
最後のコマンドでnginxのパッケージ一覧確認したが私は下記のnginxが含まれていた
nginx/unknown 1.21.6-1~jammy amd64 [upgradable from: 1.18.0-6ubuntu14.3]
あとはsudo apt install nginxとすればインストールされる

## 裏方法
aptで直接リポジトリ指定 | dpkg -i で指定（dpkg -i は一般的な方法なので割愛）
実はわざわざリポジトリを作成しなくても直接下記のようにリポジトリをインストールするだけでnginxを使えるようになる
```
apt install /srv/apt/repository/nginx_1.21.6/nginx_1.21.6-1~jammy_amd64.deb
```

以下は↑コマンド結果抜粋
```
# aptコマンドで取得するパッケージの一個目を表す
Get:1 /srv/apt/repository/nginx_1.21.6/nginx_1.21.6-1~jammy_amd64.deb nginx amd64 1.21.6-1~jammy [1002 kB]

# nginxをインストールする都合でサービスの設定を一部書き換えている
Service restarts being deferred:
 systemctl restart networkd-dispatcher.service
 systemctl restart unattended-upgrades.service
```
人はどんなときに開発生産性を考えるのか

開発生産性に関する次の記事がQiitaのトレンドに入っていました。

https://qiita.com/hirokidaichi/items/53f0865398829bdebef1

この記事は、たしかに開発生産性について様々な観点が羅列されていましたが、Twitterを眺めていると、今ひとつ主旨がわからなかったという人もいたようでした。
なるほど、たしかに個々の事実の羅列を通して、その結論が「開発生産性を考える事は一般に難しく、またセンシティブである」みたいなことであったとするならば、「結局何が言いたいのか」という感想にも一理あるように思います。
そこで、この記事では、そもそも人はどんなときに開発生産性を考えるのか、ということをいくつか分類して考えてみたうえで、開発生産性についての記事を読んだ上で"実践"する場合にどんな事に気をつけるべきなのかを考えます。

# シチュエーションを分類する軸

## 開発生産性を向上したいのか、したくないのか

開発生産性について考えるとき、その開発生産性を向上することが目的なのか。それとも、必ずしも開発生産性の向上は目的ではないのか。
例えば、単純に作業量などを評価する材料に開発生産性を使いたいという場合には、必ずしも直ちにその向上が目的ということではありません。これは意外かもしれませんが、例えばどら焼きを生産する機械Aが一定時間に生産できる量を測定することは、「この機械が何台あれば必要などら焼きを時間内に作れるか」あるいは「受注したどら焼きをすべて生産するにはどれぐらい時間がかかるか」かもしれません。
これは所要時間について概数で予測を立てるためかもしれませんし、根本的に開発生産性を向上したいのかもしれません。

## 現状に問題があるのか、ないのか（あると思っているか、ないと思っているか）

現状について問題意識があるかないか。つまり、開発効率が低いとなんとなく思っているか否か。
もし、現状に問題があるという意識が先行しているとすれば、開発生産性の測定が直ちに糾弾になるような場合もあり得ます。
そういった問題意識はないが、単に測定して改善する方法を検討したい、という事かもしれません。

## 2つの軸の組み合わせパターン

この2つの軸の組み合わせだけでも、以下のようなパターンを考えることができます。

### 問題解決：向上したい・問題あり

現状に問題があって、それを解決したいという場合です。この場合の目的は、ずばり改善による問題の解決という事になるでしょう。
ただ、この場合は問題ありと思っていても実はそこには問題がなかったり、直接的な解決が容易ではないといった場合も考えられます。その場合には、損切りができずに苦しむといったケースも考えられます。そもそも本当に問題があると言えるのか、という事をフラットに問うことが必要と思われます。

### 糾弾：向上したくない・問題あり

現状に問題があるが、それを向上することが目的ではないという場合です。この場合に厳しいパターンとしては「問題点を糾弾するための材料を探している」といったものがあります。あるいは、解決できない問題点を示すことで、現状が改善不可能であるという議論にも使えます。いずれにしても、これだけを切り取るとあまり建設的ではないようにも感じますが、一方で損切り・判定等には有効な事もあります。

### 改善思考：向上したい・問題なし

現状に特に問題は無いと思われるが、より改善をしたいというポジティブな考えです。
それ自体はよい事であるようにも思われますが、この考えに基づいてオーバースペックな改善をしてしまう可能性もあるので、直ちに全面的に良い考え方であるとも言うことはできません。特に、この改善を行うこと自体の生産性があるのか？といった事にも目を向ける必要があります。

### 興味：向上したくない・問題なし

シンプルに、ただの興味です。ひょっとすると問題があるかもしれない、というのもこれに分類されるかと思います。
状況を把握することは重要と思われますが、一方で目的なくコストを使って情報を仕入れて考えるとしたら、それは非効率かもしれません。

# どのシチュエーションかによって返すべき言葉は異なる

仮に経営者が開発生産性について知りたいと思った場合にも、この4つのどのシチュエーションであるかによって、返すべき言葉・進めるべき議論は変わってくると思います。つまり、いずれの場合であっても「開発生産性が多義的である」という事には意味がある上に正しいですが、しかしただそれを述べたのでは、会話として噛み合いません。極端な事を言えば、そのような知識の羅列をする事自体が経営者の求めている行動ではないという可能性もあります。

一般論として、開発者が機能を実装するときには、非開発者が作って欲しいと言った機能をただ実装しようとするのではなくて、そもそもその機能がなぜ必要なのか・その目的を達成するのに本当にその機能実装がベストなのかといった事を考えるべきである、などと言われます。
それに照らせば、経営者が開発生産性を知りたいと言った場合にも開発者は同じような行動をとるべきで、つまり「なぜ開発生産性を知りたいのか」を問うて目的を確認することが重要であるように思います。そこで必要なのは多様な生産性を羅列的に定義していくという事ではなくて、まず何のために生産性を知りたいのかを明らかにすることである、ということです。
その上で、目的に合わせた適切な開発生産性の指標があるとすれば、その指標を提案検討するといった事は有効です。

同じことを言い換えると...
ある機能を開発実装したいと問われた時に、その機能を実現し得るアーキテクチャをいきなり知っている限り全て並べて経営者と共有しようとする、例えばデザインパターンを全て列挙して共有しようとするのは、すごく理解のある経営者であれば効果的かもしれませんが、普通の開発者が時間をかけてようやく理解する事について経営者が概要理解する事を求めるのは、現実的ではないように思います。
仮に、羅列的な知識を経営者に理解することを求めてしまったとしたら、まさにそれと同じような事をしているのではないかな？と思います。多分、実際に必要なのは、そういう事ではないですよね。

# まとめ

開発生産性を分類して把握することは有用ですが、それを直接的に経営者にぶつけたりすると、「結局何が言いたいの」となってしまう可能性があります。様々な開発生産性があることを踏まえて、「結局あなたは開発生産性を知ることで何をしたいのか」という、その目的を大事にすると、いろいろな話がスムーズになり、実りがあるかもしれません。

# おまけ

不用意に非開発者と開発者の間で開発生産性についての話をしようとすると、意見が食い違って分断が発生する元になる場合があります。
一般に、分断を防ぐにはどうすればよいのか、といった事について考察した記事を書きました。もし興味をお持ち頂けたら、ぜひ次の記事も一読ください。（相互リンクしています）

https://qiita.com/sasanquaneuf/items/4a355e17ef63eb13fd55
AWS TimestreamのtimeカラムをLambdaでJSTに変換する際のTips



# 問題
Timestreamにて```time```カラムが下記のように```タイムゾーン無し&文字列```として出力される場合があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342722/d7f9fc4f-e0fa-2736-f51a-c3b3d9380dc2.png)


Lambdaで時間処理を行う場合、文字列では不便ですのでJSTに変換しなければなりません。
ですが、単純に```str → date```では変換できない事象が発生しましたので共有したいと思います。
できれば、レイヤーも追加せず簡単に行う方法かつ、python3.9に合うモダンな方法にしたい。

# 解決策
そのままの状態では、dateフォーマットに合わないことがわかりました。
最初に文字列として取得できるので、**末尾の桁数を調整**することでやや力技ですが解決できました。

```python
from datetime import datetime
from zoneinfo import ZoneInfo

def convert_timestamp(timestamp):
  timestamp_date = datetime.strptime(timestamp[:-10], '%Y-%m-%d %H:%M:%S') # 文字列の末尾を削除して変換する
  time_stamp_utc = timestamp_date.astimezone(ZoneInfo("UTC")) # UTCを付与
  time_stamp_jst = time_stamp_utc.astimezone(ZoneInfo("Asia/Tokyo")) # JSTに変換

  return time_stamp_jst

```

### ZoneInfoについて
AWS lambdaではpython3.9から使用可能になったそうです。まだ情報は多くないですがレイヤーの追加をせずとも使えますので便利です。
KVM環境の仮想マシンの構築とvirt-installコマンド主なオプション



●KVM環境の仮想マシンの構築(CentOS 7上のKVMで仮想マシンを作成する)

■実行環境の整備
・必要なパッケージ
qemu-kvm: KVMのコマンドラインユーティリティ
virt-install: 仮想マシンを作成するユーティリティ
virt-viwer: 仮想マシンのコンソールを表示するユーティリティ

・yumコマンドでパッケージをインストール
yum install qemu-kvm libvirt virt-install virt-viwer

・libvirtdデーモンの起動
仮想化管理用のソフトウェアlibvirtを使用するために、libvirtdデーモンを起動
systemctl start libvirtd

■ネットワークの設定
KVMの仮想マシンはデフォルトではNAT接続で、仮想マシンから外部へネットワーク接続できますが、外部からは仮想マシンに接続できない。

外部のホストから仮想マシンにネットワーク接続したい場合は、物理NICと同じセグメントのIPアドレスを仮想マシンに割り当てて、bridgeインタフェースを介して接続。


ブリッジネットワークは、NetworkManagerや、Linuxのブリッジ設定を行うためのbridge-utilsユーティリティ（brctlコマンド）で構成。


■仮想マシンの作成
・ゲストOS用のインストーラの準備
事前にISOイメージをダウンロードしておき、ゲストOSにインストール。

・virt-installでの仮想マシンの作成

●virt-installコマンドの書式と主なオプション

virt-install [オプション]

オプション
・—connect URI 接続先のハイパーバイザーの指定[KVM] qemu:///system
・-n|—name　名前　仮想マシンの名前(ドメイン)の指定
・-r|—ram　メモリ、—memory　メモリ　仮想マシンに割り当てるメモリ(MB)の指定
・—vcpus CPU数　仮想マシンに割り当てる仮装CPU数の指定
・—disk ディスクイメージ　仮想マシンのディスクイメージの指定
・—disk オプション=値　[オプション]path]=イメージファイルのパス、[オプション]size=サイズ(GB)など
・-l|—location 場所　インストールのソースの指定
・-v|—hvm　完全仮想化の指定
・-p|—paravirt 準仮想化の指定