OmniAICreator/Qiita-1.07M huggingface dataset:
1分でできる！VSCode上でPythonの単体テストのカバレッジを可視化する

# できること

- 単体テストのカバレッジがVSCode上で表示される
- カバレッジ率も計算してくれる
- Python3, Python2, pytest, unittest(標準ライブラリ)で使えます

こんな感じです↓ 

![スクリーンショット 2024-06-03 18.24.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/582018/40601a73-f9b8-4063-8a31-a017b6736150.png)

緑色 = 通ってる
赤色 = 通ってない
（黄色 = 一部通ってる）

ここだと、if分岐の中身を通るケースの検証が全くできていないことが一目で分かります 🎊

また、VSCodeの下の方にCoverage率も表示されます（「71% Coverage」のところ）


# 事前準備

VSCodeの拡張機能「[Coverage Gutters](https://marketplace.visualstudio.com/items?itemName=ryanluker.vscode-coverage-gutters)」をインストールしておきます

![スクリーンショット 2024-06-03 18.05.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/582018/fc37308d-e431-316b-bc7b-32f57758883f.png)

VSCodeの下側に「⚪︎Watch」と表示されればokです。
![スクリーンショット 2024-06-03 18.11.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/582018/18dde07f-84ec-bdde-dadf-edc31b15b57a.png)


# 導入してみる

## a) pytestの場合

1. 必要なライブラリをinstallする
`$pip install pytest pytest-cov`
1. ターミナルから以下コマンドでpytestを走らす
`$pytest --cov --cov-branch --cov-report=xml`
1. VSCode下側の「⚪︎Watch」をクリック
1. 完了！

## b) unittestの場合

1. 必要なライブラリをinstallする
`$pip install coverage`
1. ターミナルから以下コマンドでunittestを走らす
`$python -m coverage run -m unittest `
1. coverage.xmlファイルを生成する
`$python -m coverage xml`
1. VSCode下側の「⚪︎Watch」をクリック
1. 完了！

# 感想
- 単体テストを書く際にめちゃくちゃ便利で感動してます。特に私が担当しているコードはいわゆるレガシーコードで複雑度が高いので、カバレッジの可視化をすることで見落としがないか、重要ロジックは検証できているか、など安心できています。また、レビュワーにとってもどこを通っていて、カバレッジ率が何%で、というのがパッと分かると安心かと思うのでチーム間のコミュニケーションでも重宝しています :smile: 


# 補足

- Coverage Guttersは単体テスト時に生成されるcoverage.xmlを参照するのでそれを利用しています。coverage.xmlさえあれば良いので、万が一本記事の手順でできなかった場合はコマンド等いじるなどしてみてください！


# おまけ（今回使ったお試しコード）

コピペしてぜひ試して見てください〜 (python3.11)
pytestでもunittestでも動きます笑

```python
"""calculate_average.py

与えられた数値の平均値を求めるモジュール"""


def calculate_average(numbers: list[int]) -> float:
    if not _is_valid_input_values(numbers):
        raise ValueError()
    total = sum(numbers)
    average = total / len(numbers)
    return average


def _is_valid_input_values(numbers: list[int]) -> bool:
    # input値がlist型であることを確認
    if not isinstance(numbers, list):
        return False
    # listの中身が全てint型であることを確認
    if not all(isinstance(number, int) for number in numbers):
        return False
    # listの中身が空でないことを確認
    if not numbers:
        return False
    return True
```

```python
"""test_calculate_average.py"""
from unittest import TestCase

import pytest

from calculate_average import calculate_average


class TestCalculateAverage(TestCase):
    def test_calculate_average(self):
        """calculate_averageメソッドの正常系を確認する"""
        assert calculate_average([1, 2, 3, 4, 5]) == 3.0
        assert calculate_average([10, 20, 30, 40, 50]) == 30.0

    # def test_calculate_average_exception(self):
    #     """calculate_averageメソッドの例外系を確認する 空リストを渡すとValueErrorが発生する"""
    #     with pytest.raises(ValueError):
    #         calculate_average([])

```

# さいごに

ここまで読んでいただきありがとうございました！
本記事が少しでも良いなと思った方は「いいね！」していただけるとめちゃくちゃ喜びますmm
法則型と暗記型

:::note info
型の話は一切しません。ポエムです。
:::


寝る前にyoutubeを見ていたらこんな動画が目に入った。

https://www.youtube.com/watch?v=jc5wY1lbQ40

「トップ層と上位層の違いについて」

プロゲーマーのウメハラさんが語っている動画だった。
(urlは切り抜きを見てるときどさんの切り抜きみたいなものです)

内容としてはウメハラさんが視聴者の質問に答えるコーナーの切り抜きだった。
質問の内容はこうだ(要約)

- 自分は大抵のことで上位層になることができる
- ストリートファイターでも上位層になれた(上位10%のランク)
- ただ、ここから壁を感じていてトップ層にいけない
- トップ層にいるウメハラさんから見てトップ層と上位層の違いは何ですか?

なるほど。
動画見る限り、質問者が自信過剰という感じもしない。
そして、この質問者の気持ちが自分には痛いほどわかった。自分もこのtypeだと思う。

そして、この質問を聞いたウメハラさんの回答はこうだ(要約)

- あなた(質問者)より上にいる人は2つのtypeに分かれる
- 暗記やモノマネが得意なtype。あなたはこのtypeです(仮: 暗記型)
    - そして、あなたよりも上位互換の暗記型がトップ層にはいます
- もう1つは法則型。これは物事の法則を見つけようとする。ウメハラさんがこのtype
- どちらが優れているというものではなく一長一短がある
- 超えるための選択肢としては法則型の動きを身につけることをおすすめする

なるほど。これだけだとわからんのでもう少し詳細に。

## 暗記型

モノマネや暗記が得意なtype。
例え話としてこのtypeはプラモデルの車を渡されると、かなり早く作れる。しかも精度も高い。
そして、次に飛行機のプラモデルを渡されるとこれにも早く対応できる。

でも、なぜ動いているかということは知らない。説明書に書いてあることはできるが、書いていないことは気にしない。

## 法則型

物事の法則を見つけようとするtype。
プラモデルの車を渡されると「これはなぜ動くんだろうか」ということが気になって仕方ない。
なぜ動くのかを気の済むままに調べ上げる。動く仕組みを知っているので、説明書には書いていないことができる。早く動かしたりバックの機能をつけたり。

でも、次に飛行機のプラモデルを渡されると、「なぜ飛ぶのだろう」が気になってなかなか完成しない。

## つまり

要約にも書いていますが、どちらが優れているという話ではない。
質問者がトップ層に食らいつくには暗記型の上位互換がいる以上、法則型の動きでdetailを詰めるのがいいと思うという話でした。

## エンジニアのキャリアと置き換える

ここ1年ぐらいの悩みとして「エンジニアとして今後どう過ごすといいのだろうか」というものがありました。
自分はエンジニア4年ぐらいの経験がありますが、このままでいいんだろうかという漠然とした不安からきています。
周りを見ると同じぐらいのキャリアの方が、かなり有名なOSSのmain contributor だったりするんですよね。
あとは、今の会社の同僚が開発に関してかなり精通していて、上澄を掬ってきた自分との差が見えて少し辛かったり。

そんな時にこの動画と出会ったわけですが、あぁなるほど。とても合点がいきました。

自分の性格として、モチベーションが上がるのは成果が出た時に特に上がっていました。
なので暗記型はとてもマッチしていました。すぐに成果が出せますからね。

つまり自分自身の今の悩みは法則型の動きをするほかなさそうだなと改めて思ったり。
Markdown is all you need!


![IMG_2852.jpeg](https://storage.googleapis.com/topdowncom/content/kqmyfjwWDJNNkVkY6G3mlruHqlx2/e647d470-d9fe-44f0-a4d3-7e67e1f2f3db/IMG_2852.jpeg)

# Markdown  AI プロジェクト始動！

## MarkdownとAIでWebサイト作成？

![IMG_3080.jpeg](https://storage.googleapis.com/topdowncom/content/kqmyfjwWDJNNkVkY6G3mlruHqlx2/20532f37-4150-458f-970c-c56e81aadf01/IMG_3080.jpeg)

Markdownのみで、Webサイト生成やサーバ処理を全て実現する、Markdown  AIが当社よりリリースされました！


私はこの企業のファウンダー兼 アーキテクトとして、この1年間、絵本執筆よりはるかに多くの時間を費やしてきました。

無事リリース出来て嬉しいです。

企画や開発に携わっていただいた社員の皆さんや、協力頂いた取引先の方々、本当にありがとうございました。

AI時代らしく、日米同時リリースしています。

これからのMarkdown AIの未来が楽しみです！

永田浩一

https://mdown.ai/

![IMG_3046.png](https://storage.googleapis.com/topdowncom/content/kqmyfjwWDJNNkVkY6G3mlruHqlx2/df41434b-92d2-40f1-b917-383a1dfb7f0f/IMG_3046.png)

## 以下リリース文です。

![IMG_3081.jpeg](https://storage.googleapis.com/topdowncom/content/kqmyfjwWDJNNkVkY6G3mlruHqlx2/20532f37-4150-458f-970c-c56e81aadf01/IMG_3081.jpeg)

PR Times
https://prtimes.jp/main/html/rd/p…

### 『markdown AIでWebサイトを瞬時にデザイン！マークダウンの力で創造を解放』
#### 『新世代ウェブサイト作成ツール - Markdown is all you need-』
株式会社トップテン

株式会社トップテン(本社：東京都太田区、代表取締役：根本大輔)は2024年6月1日よりマークダウン記法で誰でも手軽にwebサイトを作れるサービス『Markdown AI』を開始致しました。

時代は変わり、webサイト作成も進化しました。
「Markdown AI」は、誰でも簡単に、しかも素早くプロフェッショナルなwebサイトを作成できる革新的なツールです。
Markdown AIは、テキスト入力からマークダウン記法を使って、瞬時にwebページに変換します。
エンジニアから子供まで、誰もが簡単に情報を世界に発信でき、まさに次世代のwebサイト作成ツールです。
プレビュー機能を活用して、あなたの作品をリアルタイムで確認しながら、一つのボタンで全世界に公開可能。今すぐ「Markdown AI」で、あなたのアイデアを形にしてみませんか？


webサイトを作成するには、かつては技術的な知識が必要で、多くの人にとっては大きな壁でした。
しかし、markdown AIの登場により、その壁が崩れ去ります。
このツールは、直感的な操作で誰でも簡単にwebページを作成できるように設計されており、マークダウン記法を使用しているため、見た目もシンプルで美しいwebページが瞬時に完成します。
 
### 簡単操作でプロフェッショナルな結果
markdown AIの主な特徴は、その使いやすさにあります。テキストを入力し、適切なマークダウンタグを加えるだけで、見栄えの良いフォーマットが即座に適用されます。
さらに、プレビュー機能により、実際にサイトがどのように見えるかを編集中に確認することができます。
 

![IMG_2839.jpeg](https://storage.googleapis.com/topdowncom/content/kqmyfjwWDJNNkVkY6G3mlruHqlx2/af54e8fe-0dee-4cb6-8929-9ebbbd6bbced/IMG_2839.jpeg)

### AI技術の統合
今後のアップデートでは、AI技術を導入する計画があります。
たとえば、「AI連携」機能では、ユーザーが提供したプロンプトに基づいてAIがコンテンツを生成し、それをマークダウン形式で出力します。
これにより、よりダイナミックで、個性的なコンテンツ作成が可能になります。

![IMG_3082.jpeg](https://storage.googleapis.com/topdowncom/content/kqmyfjwWDJNNkVkY6G3mlruHqlx2/20532f37-4150-458f-970c-c56e81aadf01/IMG_3082.jpeg)


![IMG_3083.jpeg](https://storage.googleapis.com/topdowncom/content/kqmyfjwWDJNNkVkY6G3mlruHqlx2/20532f37-4150-458f-970c-c56e81aadf01/IMG_3083.jpeg)

### 手軽にアクセス、即座に公開
markdown AIを使用すれば、複雑なサーバー設定やコーディングは不要です。
作成したページはすぐにオンラインで公開可能で、URLを共有することで世界中の人々と情報を共有できます。
このように、「markdown AI」はウェブサイト作成の常識を変え、技術の壁を取り払い、クリエイティビティの自由を提供します。今日からあなたもこのツールを使って、独自のwebサイトを創造し、世界とつながりましょう。
 
### 【使用方法】下記URLからサインイン可能
【markdown AI webサイト】topdown.jp
【markdown AI 紹介ページ】topdown.jp/content?id=335…
ラズパイでロボットアームを動かしてみた

## やること
RaspberryPiとサーボドライバ、サーボモーターを接続しロボットアームを動かします。 

## 用意したもの
- Raspberry Pi4 ModelB 4GB
    - <img width="400" src="https://a.media-amazon.com/images/I/51ETv8Le3nL._AC_.jpg">
- AMONIDA メカニカルアーム
    - <img width="400" src="https://a.media-amazon.com/images/I/61AK58iYi-L._AC_SL1001_.jpg">
- zetaon PCA9685 サーボドライバ PWM
    - <img width="400" src="https://a.media-amazon.com/images/I/61j29FnrmUL._SY445_SX342_QL70_ML2_.jpg">
- ジャンパーワイヤ
    - <img width="400" src="https://a.media-amazon.com/images/I/61EmTPn6ggL._AC_.jpg">

## ロボットアーム組み立て
[Amazon](https://www.amazon.co.jp/gp/product/B08FBDNY5M)で購入したのですが、説明書がなく検索しても見当たらなかったので関連画像を見つつ手探りで組み立てました。

稼働確認しやすいように今回はアームの部分のみ利用します。
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72433/511d726a-050c-c5b2-ba2c-8d52f84cdfbf.jpeg">

## ラズパイ起動
RaspberryPi OSをインストールしたSDカードをラズパイに差し込み起動します。
![スクリーンショット 2024-06-03 0.46.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72433/641553ac-f5f2-64c9-6d44-f8d534687c16.png)

## 接続
ラズパイとサーボドライバをジャンパワイヤーで接続します。
接続についてはこちらの記載がとても参考になりましたので、ここでは省略します。
https://zenn.dev/naoya_oshiro/articles/fa95bd81e3ac8a

接続が終わったら`i2cdetect`コマンドで利用できるアドレスが分かるので確認します。
利用したラズパイはi2cが無効だったので、設定から有効化しました。

```
raspberrypi:~ $ sudo i2cdetect -r -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: 70 -- -- -- -- -- -- -- 
```

## 動作確認
ライブラリを利用してpythonで開閉するコードを実行し、サーボモーターを動かします。

``` python
#!/usr/bin/python

import Adafruit_PCA9685
import time

SERVO = Adafruit_PCA9685.PCA9685(address = 0x40, busnum = 1)
SERVO.set_pwm_freq(60)
ARM = 0

def move(pulse):
    print(pulse)
    SERVO.set_pwm(ARM, 0, pulse)
    time.sleep(2)
    
def close():
    move(280)

def open():
    move(420)

while True:
    close()
    open()

```

アドレスはコマンドで確認できた0x40を設定してます。
アームの開閉はサーボモータのパルス幅（set_pwmの第３引数）を150~600に設定します。
値が極端過ぎると動作場所によっては可動域が合わないため注意です。

<img width="400" src="https://github.com/terumichi1209/temp/assets/11495834/1518d927-eff4-42f3-b026-86bf516ed8f8">

無事動きました！
アームの可動域は掴むものによって良しなに変えていこうと思います。

## 最後に
ラズパイ購入から一通りを今回初めてやってみたのですが、ロボットアームの組み立てが一番大変でした。
ラズパイのセットアップやGPIO周りの接続についてはノウハウが転がってるので、気軽に始めやすく良かったです。

次は他の部分も一通り接続して全体的に動かしたいと思います。
GPT3.5-TurboでNERを試す

GPT3.5-TurboでNER(固有表現抽出)を試してみました。LangChainを使って以下のコードを元にしています。

https://python.langchain.com/v0.2/docs/tutorials/extraction/

# 結果
漫画の名称を抽出しています。「Prompt」列の太字が正解。
以外とそこそこいけます。長文では試していません。

|Prompt|結果|備考|
|:--|:--|:--|
|**One Piece**の主人公を教えて|正解|
|**貸した魔力は【リボ払い】で強制徴収**の主人公を教えて|:x:(リボ払い)|長くて新し目はだめ?
|**ドラゴン・ボール**の主人公を教えて|正解|「・」を入れてもOK
|**転生したらスライムだった件**の主人公を教えて|正解|有名なら長くてもOK
|**我妻さんは俺のヨメ**の主人公を教えて|正解|そんな有名じゃなくてもOKだった
|**竜師をクビになったけど竜がついてきました**。の主人公を教えて|正解|2024/5開始の新作。「。」があるから正解？
|**カイジ**はどんなお話？|正解|中途半端なタイトル


# 環境
Python3.12.2で動かしています。裏では[Poetry Dotenv Plugin](https://github.com/mpeteuil/poetry-dotenv-plugin)が動いていて、自動的に`.env`ファイルを読んでOpenAIのキーを環境変数に入れています。
以下のパッケージ一覧。

|Package|Version||
|:-:|:-:|:--|
|langchain|0.2.1||
|langchain-openai|0.1.8||

# プログラム
juypterで動かしています。

```python
from typing import Optional

from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_openai import ChatOpenAI

class Comic(BaseModel):
    """Information about a person."""

    # ^ Doc-string for the entity Person.
    # This doc-string is sent to the LLM as the description of the schema Person,
    # and it can help to improve extraction results.

    # Note that:
    # 1. Each field is an `optional` -- this allows the model to decline to extract it!
    # 2. Each field has a `description` -- this description is used by the LLM.
    # Having a good description can help improve extraction results.
    comic: Optional[str] = Field(
        default=None, description="The name of comic"
    )


from langchain_core.prompts import ChatPromptTemplate

# Define a custom prompt to provide instructions and any additional context.
# 1) You can add examples into the prompt template to improve extraction quality
# 2) Introduce additional parameters to take context into account (e.g., include metadata
#    about the document from which the text was extracted.)
prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "You are an expert extraction algorithm. "
            "Only extract relevant information from the text. "
            "If you do not know the value of an attribute asked to extract, "
            "return null for the attribute's value.",
        ),
        # Please see the how-to about improving performance with
        # reference examples.
        # MessagesPlaceholder('examples'),
        ("human", "{text}"),
    ]
)

llm = ChatOpenAI()
runnable = prompt | llm.with_structured_output(schema=Comic)

text = "カイジはどんなお話？"
runnable.invoke({"text": text})
```

最後の`text`の値を変えて試しています。
山奥SEOは絶対におすすめできない！SEO対策の真髄をご紹介

![SALE (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3807639/c9ab5f1f-c7a3-bf21-a005-06e315e97d8c.png)


山奥SEO以外でおすすめの手法
 
山奥SEO以外でおすすめなのは「そのジャンルの会社を立ち上げて、そのサブディレクトリでサイトを運営する」です。
 
例えば「海外FX株式会社」という、海外FXのサイトを立ち上げるためだけに創立された会社があります。
 


 

https://kaigaifx.co.jp/

 

SEOで上位を取るのであれば、このように立ち上げたいサイトから逆算して、会社を設立するのがおすすめです。


2024年6月現在、山奥SEOという手法がX（旧：Twitter）にて流行しています。

 

山奥SEOとは？意味をご紹介
山奥SEOは、検索ボリュームが非常に少ないキーワードで検索順位の上位を狙うSEO手法です。この手法は競合サイトがターゲットにしていないニッチなキーワードを対象としており、少ない努力で上位表示を実現できる可能性が高いです。特に、小規模なサイトや新規ブログにとって効果的な施策です。

 

山奥SEOの3つのメリット
 
山奥SEOは、SEO初心者でも簡単に取り組める手法です。手軽に始められるだけでなく、以下の3つのSEOメリットがあります。

競合が少ない
ニッチなキーワードを選ぶため、競合サイトが少なく、上位表示が比較的容易です。

一次情報になりやすい
オリジナル記事を公開することで、被リンクやサイテーションを得やすくなり、E-E-A-T（専門性、権威性、信頼性）が向上します。

ユーザーに感謝される
細分化された悩みに応えることで、訪問者から感謝されやすく、ファンやリピーターを増やすことができます。

 
 
山奥SEOのキーワードを選定する3つのポイント
 
山奥SEOを成功させるためには、適切なキーワード選定が重要です。経験や実体験を活かし、自分が得意とするジャンルやテーマの中で、以下の具体的なキーワードを狙います。

検索ボリュームが0～100程度のキーワード
参入しているライバルが少ないため、上位表示が容易です。

まだ言及されていないトピック
特定の小さな市場やコミュニティに向けたキーワードを選ぶことで、その分野での第一人者となれます。

具体的な悩みや質問に関連するキーワード
ユーザーの具体的な悩みや質問に答えられるキーワードを選びます。例えば、「WordPressの特定プラグインにおけるイレギュラーなエラーの解決方法」などがあげられます。

山奥SEOがおすすめできない理由
 
山奥SEOはおすすめできません。
 
「圧倒的に工数がかかるので、初心者の人は途中で挫折しやすい」からです。
 
なので本サイトでは、山奥SEO以外の手法をおすすめしています。
 
また山奥SEOの危険性は次の動画でも詳しく解説されています。

https://www.youtube.com/watch?v=4_uvGvtq7rk
Ansible Tips: YAMLやJSONにおけるnullは、{{ }}内のJinja2フォーマットではnone

備忘

nullやnoneは混乱することが多いので確認


# YAMLやJSONにおけるnullは、{{ }}内やwhen:式やdebug出力などではNone


## サマリー
| JSON | YAML(フロースタイル)   | Jinja2     | debug出力 |
| ---- | ------------------- | ---------  |  ---------  | 
| null | null, Null, NULL, ~ | none, None | None もしくは出力なし |

## 例
```
    - vars:
        l1: "{{ [none,None] }}"
        l2: "{{ '[null]' | from_json }}"
        l3: "{{ '[null,Null,NULL,~]' | from_yaml }}"
        l4: [null,Null,NULL,~,!!null ""]
        l5:
          - null
          - Null
          - NULL
          - ~
          -
      ansible.builtin.debug:
        msg: |-
          {{ l1 }}
          {{ l2 }}
          {{ l3 }}
          {{ l4 }}
          {{ l5 }}
```
```
TASK [ansible.builtin.debug] ***********************************************************************************************************
ok: [localhost] => {}

MSG:

[None, None]
[None]
[None, None, None, None]
[None, None, None, None, None]
[None, None, None, None, None]
```

# when: などではjinja2フォーマットという理解なのでNone

```
    - loop:
        -
        - foo
      when: item != None
      ansible.builtin.debug:
        var: item
```
```
TASK [ansible.builtin.debug] ***********************************************************************************************************
skipping: [localhost] => (item=None)  => {
    "ansible_loop_var": "item",
    "false_condition": "item != None",
    "item": null
}
ok: [localhost] => (item=foo) => {
    "ansible_loop_var": "item",
    "item": "foo"
}

```


# ちなみにansible-lint --fixをかけると
```
---
- hosts: all
  gather_facts: false
  tasks:
    - vars:
        l1: "{{ [none, None] }}"
        l2: "{{ '[null]' | from_json }}"
        l3: "{{ '[null,Null,NULL,~]' | from_yaml }}"
        l4: [!!null "", !!null "", !!null "", !!null "", !!null ""]
        l5:
          -
          -
          -
          -
          -
      ansible.builtin.debug:
        msg: |-
          {{ l1 }}
          {{ l2 }}
          {{ l3 }}
          {{ l4 }}
          {{ l5 }}
```
フロースタイルにおける!!null ""は冗長に感じるので、個人的にはnullで良いかと。
ブロックスタイルは何も書かないことでnullを表現。こちらは明瞭。
2024/6/4主にITとかセキュリティの記事

Amazon BedrockでRAGを構築し､Cohere Command R+でストリーミングテキストを生成する(6/3)
https://qiita.com/revsystem/items/571504731d38278408ba

中小企業の「内部不正対策の実態」を調査報告、IPA　～「中小企業における対策推進のファーストステップ」も指摘(6/1)
https://www.imagazine.co.jp/ipa-security-survey2024/

ビットコイン、資産管理難しく
DMM系、482億円相当流出　海外はETF組み入れも(6/2)
https://www.nikkei.com/article/DGKKZO81111280S4A600C2EA2000/

DMMビットコイン、流出事件の最新情報まとめ｜約482億円の行方とは(6/2)
https://crypto-times.jp/explaining-dmm-bitcoin-outflow-as-of-6-2/

人工知能の二重性の探求(6/2)
https://elblog.pl/ja/2024/06/02/%E4%BA%BA%E5%B7%A5%E7%9F%A5%E8%83%BD%E3%81%AE%E4%BA%8C%E9%87%8D%E6%80%A7%E3%81%AE%E6%8E%A2%E6%B1%82/

「iPhone＋マイナンバー」で身ぐるみをはがされる…ホワイトハッカーが警鐘「ゼロリスクでなくハイリスク」デジタル庁の大暴走(6/2)
https://news.livedoor.com/article/detail/26522769/

エジプトとシンガポールの閣僚がテクノロジーイノベーションと協力について話し合う(6/1)
https://elblog.pl/ja/2024/06/01/%E3%82%A8%E3%82%B8%E3%83%97%E3%83%88%E3%81%A8%E3%82%B7%E3%83%B3%E3%82%AC%E3%83%9D%E3%83%BC%E3%83%AB%E3%81%AE%E9%96%A3%E5%83%9A%E3%81%8C%E3%83%86%E3%82%AF%E3%83%8E%E3%83%AD%E3%82%B8%E3%83%BC%E3%82%A4/

テラコヤテックFlutterコースに参加して(6/1)
https://zenn.dev/chiiirotty/articles/b5f4150ae8ef72

亡くなった母のＡＩと対話　「境界から」①米ロサンゼルス　生と死のテクノロジー 　ホロコーストの記憶も伝承(6/2)
https://www.47news.jp/10898654.html

能動的サイバー防御議論　有識者会議
秋の国会にも法案見据え(6/2)
https://www.nikkei.com/article/DGKKZO81110920R00C24A6EA3000/

「事態発生も排除されず」防衛相、中国念頭に懸念(6/1)
https://www.saitama-np.co.jp/articles/83336/postDetail

台湾有事　習近平主席が「やれ」と言えば誰も逆らえない　元陸上幕僚長の岩田氏講演　神戸「正論」懇話会詳報(6/2)
https://www.sankei.com/article/20240602-FQPU3FU24VN2NA3U3IVOLBL4GY/

ベトナムの抗仏戦勝70年と歴史の教訓【朝鮮日報コラム】(6/2)
https://www.chosunonline.com/site/data/html_dir/2024/05/28/2024052880145.html

塩漬け用電動スプーンが日本で発売(6/2)
https://kenmin-souko.jp/%E5%A1%A9%E6%BC%AC%E3%81%91%E7%94%A8%E9%9B%BB%E5%8B%95%E3%82%B9%E3%83%97%E3%83%BC%E3%83%B3%E3%81%8C%E6%97%A5%E6%9C%AC%E3%81%A7%E7%99%BA%E5%A3%B2/

パナソニックとリコーが進めるIoTセキュリティー、企画段階からの脆弱性対策が鍵(6/3)
https://xtech.nikkei.com/atcl/nxt/column/18/02852/053000002/

グリコのトラブルで余波、基幹システム刷新にビビった経営者につける薬はあるか(6/3)
https://xtech.nikkei.com/atcl/nxt/column/18/00148/053000336/

経路情報の矛盾を解消する(6/3)
https://xtech.nikkei.com/atcl/nxt/mag/nnw/18/121800181/051700006/

VLAN ネットワークを仮想的に分ける技術(6/3)
https://xtech.nikkei.com/atcl/nxt/mag/nnw/18/091900172/051700009/
国土数値情報（2024年度版の地価公示情報）をWSLでベクトルタイル化する

# はじめに
## 動機
ここ最近、不動産情報ライブラリのAPIを使って、地価公示のポイントをウェブ地図化しようとしていました。不動産情報ライブラリのサイトをよく見ると、このソースデータと思われる2024年度版の地価公示データが国土数値情報としてダウンロードできるようなので、データを直接ベクトルタイルにしてしまうことにしました。

これは作業のメモです。


## 私の環境
* Windows PC
    * Ubuntu 22.04.4 LTS (GNU/Linux 5.15.146.1-microsoft-standard-WSL2 x86_64)
    * tippecanoe v.2.53.0 （WSL上で動きます）

# 手順
## Step1: データのダウンロード
国土数値情報のHPから「地価」で検索して、2024年度版の地価公示情報を見つけます。
https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-L01-2024.html
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/b641c238-e229-eafc-e2a4-3ad1afbaef00.png)

そして、L01-24_GML.zipというファイルをダウンロードします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/118cdc4b-cfaf-b04b-21c7-5751a6d19133.png)

## Step 2: 解凍
ZIPファイルにはXML、GeoJSON、SHPとそれぞれの形式のデータが入っていますが、tippeanoeでのベクトルタイル作成の目的なのでGeoJSONだけ解凍しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/1e275726-7022-769c-6cc3-af6c2030f39e.png)
サイズは80.8MBでしたが、緯度経度座標ですし問題なさそうです。EPSGの番号設定はなさそうですが、作成したデータは地理院地図（JGD2011）に重ねるので、タイル化の際にあえてEPSGの設定はしなくてよいと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/6bf1dbd3-3707-90ab-dcec-abd710549ccf.png)

## Step 3: WSL2でタイル化
Windows Subsystem for Linux でUbuntuを立ち上げ、GeoJSONファイルがあるフォルダに移動します。その後、以下のコマンドを実行します。

ファイル名はL01-24.pmtilesとして、レイヤ名はhitsとし、ズームレベルは13から15にしておきます。ファイル名からわかるようにpmtiles形式（オプションo）で作成します。

```bash
tippecanoe -o L01-24.pmtiles --no-tile-compression --no-feature-limit --no-tile-size-limit --drop-rate=1 -Z13 -z15 -L hits:L01-24.geojson
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/dde7d559-5933-7bfe-f955-8b7cfd1e221d.png)

## 結果
数分でファイルができました。100MBを超えてしまいました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/96efc324-33a4-f4a7-7483-a9b12bcd9a01.png)

最大ズームを14、13までにしたパターンも作ってみました。最大ズーム13のものはサイズが20MB程度なので扱いやすそうです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/c6de35e2-86c4-93ca-a8db-1e99028ddb60.png)

# まとめ
WLS2を使ってtippecanoeを実行することで、データのダウンロードから数分でベクトルタイル化が完了しました。

# 参考ページ
https://www.reinfolib.mlit.go.jp/

https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-L01-2024.html
SourceTreeとGithubの接続方法　【SSH】

#### まず以下SourceTreeの設定を行う
https://support.atlassian.com/ja/bitbucket-cloud/docs/set-up-ssh-with-sourcetree/

1. GithubのSettingsから`SSH and GPS keys`を開く
2. `New SSH key`をクリックする
3. タイトルを入力する
4. `Authentication`を選択 
*目的: 認証はユーザーが誰であるかを確認するプロセスです。これにより、GitHubはアクセス権を持つ正当なユーザーを識別し、不正なアクセスを防ぎます。
5. SSH 公開鍵を入力する
*SSH 公開鍵 確認方法：
ターミナルで以下を入力
`$ cd .ssh`
`$ ls`
`id_rsa`（秘密鍵）と`id_rsa.pub`（公開鍵）があればOK！
`$ cat ~/.ssh/id_rsa.pub`
表示されたSSH 公開鍵の内容を入力する

### SSHの接続を確認する
`$ ssh -T git@github.com`
`Enter passphrase for key '/Users/hoge/.ssh/id_rsa': `
ここに、Githubのパスワードを入力する（アクセストークンじゃないほう）
以下が表示されたらOK
`You've successfully authenticated`

#### ssh接続でPermission deniedと表示されたときの対処法
https://mokuzine.net/ssh-permission-denied/
Ubuntu(Linux)でUnrealEngineのLauncherを使う

### LinuxにUnrealEngine5をインストールしたものの・・・
Ubuntu Studio(24.04LTS)にUE5をインストールしました。ここまでは全く問題なく、
Unreal Editorも無事立ち上がりました。

しかし、Epic LauncherはLinuxでは動きません。ググってもググっても、あるいは公式サイトをなめるように見ても、Launcherについての記載は見つかりませんでした。Unreal Engineのインストール方法はいくらでも出てくるのですが、この人たちはアセット群をどうやって使っているのか？という疑問がわくくらいLauncherについての記載が見つかりませんでした。このままではインストールしただけで終わってしまい、Linuxで開発するというのは夢物語で終わってしまいそうです。

### Asset Manager Studio
私は日本語ユーザーなので、できれば日本語で説明しているサイトが欲しかったのですがそうも言っていられません。とにかくUnreal Engine Linux Launcherという単語を頼りに検索した結果・・・

とうとう見つかりました。「Asset Manager Studio」
https://assetmanager.studio
見た目はEpic本家とかなり異なりますが、ほとんど同じように使えます。ちなみにWIndows版もあります。Unreal Engine本体もAsset Manager Studioからインストールできるので、ソースを延々コンパイルする必要もないようです(ここは試していないので推測)。

### MarketPlaceはない
しかしながら、Asset Manager Studioにはマーケットプレイスはないようです。これでは毎月の無料コンテンツなどの入手ができませんが、マーケットプレイスはブラウザからアクセスすればいいでしょう。むしろLauncherより軽くていいかもしれません。
https://www.unrealengine.com/marketplace/ja/store

実は私が知らなかった、調べ方が悪かっただけかもしれませんが、もしこの記事が役に立てることがあれば幸せです。
【datetime】時間系・時刻でよく使うコード一覧

試験的に個人用のメモを投稿。Pythonの時間系・時刻コードです。

■ 月日時間を出力するコード

#################################
# ■ 実行時間（月/日/時間/分を出力するコード）
#################################
  
from datetime import datetime
dt_now   = datetime.now()
Month = dt_now.month 
Day = dt_now.day
Hour = dt_now.hour
MINUTE = dt_now.minute
#NOW_TIME =str(Month)+"M_"+str(Day)+"D_"+str(Hour)+"H_"+str(MINUTE)+"M"
NOW_TIME =str(Month)+"月"+str(Day)+"日"+str(Hour)+"時"+str(MINUTE)+"分"
print(f"実行時間：{NOW_TIME}") #アウトプット例）4M_18D_4H →4月18日4時
#出力例　実行時間：5月1日21時34分


#################
# ■ 実行時間
#################
import termcolor
from datetime import datetime
 
NOW_TIME = str(datetime.now()).split(".")[0]        
termcolor.cprint(f"【実行終了時間】{NOW_TIME} 〇〇が完了" ,'green', attrs=['bold'])
#出力例 ■ 実行時間【処理終了時間】2024-05-02 15:03:47 〇〇が完了
AWS DVAに合格したので体験記＆知ってよかったことをまとめる

## はじめに
先週から産休に入って時間ができたので、今のうちに......！ということで、1年半前くらいにゆるっと動画を見て放置していたAWS DVAを今更ながら取得しました

塩漬けしている間に試験範囲が変わっていた+値上げしていたのでもう少し早く取れたばよかったなと思いつつ、実務でAWSを結構使うようになった今だからなるほどと思うところもあったので、体験記＆知ってよかったことを備忘録としてこちらに残します

## 前提
- 実務では1年強くらいAWSを使用
    - ECS、Lambda、Step Functions、S3、Aurora、Secrets Manager、CDK/CloudFormationあたりは結構実務で触っていました
- AWS SAAは取得済

## 試験勉強
### 勉強時間
20～25時間くらいだったかなと思います

### 使ったもの
- AWS Skill BuilderのExam Prep（DVA-C01版、今はない）
    - 1年半前くらいに一通り見ました
    - ありがたいことに無料です
    - 今はこちらの代わりにDVA-C02対応のコースが出ているのでそちらを見ると良いかなと思います
- [ポケットスタディ AWS認定デベロッパーアソシエイト ［DVA-C02対応］](https://www.amazon.co.jp/dp/4798070696?tag=nokonokonoko0-22&linkCode=ogi&th=1&psc=1)
    - 定番書ということで知識を総ざらいするのに使いました、ポイントを押さえている感じで読みやすかったです
    - 試験前1週間の前半2～3日くらいで読みました
- [UdemyのDVA-C02問題集](https://www.udemy.com/course/dva-c02aws-2024/?couponCode=ST19MT60324)
    - 実際の問題に近い形の問題を解きたかった＆安売りになっていたので上記を買って実施しました
    - 解説もしっかりあるので細かい知識補完にだいぶ役立ちました
    - 試験前1週間の後半2～3日くらいでやっていました
- [AWS Hands-on for Beginners AWS Codeサービス群を活用して、CI/CDのための構成を構築しよう！](https://pages.awscloud.com/JAPAN-event-OE-Hands-on-for-Beginners-cicd-2022-reg-event.html?trk=aws_introduction_page)
    - 実務であまり触っていなかったCodeサービス群の復習にこちらのハンズオンをあらためて実施しました
    - S3での静的Webサイトのホスティングもついでに学べるのが地味にありがたかったです
- その他
    - 問題演習のなかであまり使ったことのないオプションの話など出てきたらAWSコンソールで設定見てみたりしました
    - AWS公式ドキュメントも随時参照しました

## 試験
試験時間自体は130分ですが、80～90分ほどで解き終わる感じでした
オーソドックスな問題が多く、手ごたえ的にはSAAを受けた時よりも自信をもって試験を終えられた感じでした

## 知ってよかったこと
全体的に勉強してよかったなと思いますが、ぱっと思いついたものだけ書きます

- Secrets ManagerとParameter Storeの使い分け
    - 「シークレットの自動ローテーションができるかどうかが違う」というのをあまりはっきり意識していなかったのでここで知れてよかったです
    - Parameter Storeのほうがコストはかからないので以降上記を判断基準に考えたいなと思います
- Lambdaレイヤーの使い方
    - いままで簡単なLambdaしか書いていなかったこともあり、Lambdaレイヤーについては知識が薄い状態でした
    - 「外部ライブラリの依存関係読み込みに使用できる＆定義したレイヤーを複数の関数で共通して使用しアップデート等を一元管理できる」ものということでこれを機に触れてよかったです
    - 調べていく中で[Lambdaランタイムごとのレイヤーパスの決まり](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/packaging-layers.html)なども知ったので、今後使う際は気を付けようと思います
- Lambdaの関数エイリアス
    - Lambdaの関数エイリアスを設定することでLambdaのロールバックが容易になるというの、あまり知らなかったのでここで知れてよかったです
- Elasticache周りの諸々の知識
    - レイテンシを気にするならキャッシュ周りをうまく使えるようになったほうが良いと思うのですが、今まであまり知識を持っていなかったのでここで学べてよかったです
    - ElasticacheでもMemcachedはマルチスレッド対応、RedisはレプリケーションやPub/Subのサポートありというようにシーンによる使い分けがあるという点覚えておきたいです

## さいごに
「知ってよかったこと」セクションを改めて書いてみると、自分がバックエンド寄りということもありかなりサービスに偏りがあり、勉強の中でも具体的なサービス利用の理解度に差があったのかも......？という気がします
それに気づけたのもある種収穫ですかね

SAPやMLSの取得も目指しつつ、もっと頑張って開発経験を増やそう...！と改めて思いました
気軽です、.NET 8 + xUnit の標準出力

# やりたいこと

- C# の xUnit で実装したユニットテスト内で標準出力を使う

# 環境

- Microsoft Visual Studio Community 2022 (64 ビット)
    - Version 17.10.1
- .NET 8
    - C# 12
- xunit
    - 2.8.1

# 手順

### 1. いつも通りテストクラスを実装

```cs:DemoTest.cs
namespace HigeDaruma.DemoXUnit;

public sealed class DemoTest
{
    [Fact]
    public void MathAbs_ReturnsOk_WhenInputValueIsOk()
    {
        // Arrange
        int value = -1;
        int expected = 1;

        // Act
        int result = Math.Abs(value);

        // Assert
        Assert.Equal(expected, result);
    }
}

```

### 2. ITestOutputHerlper を使用

`ITestOutputHelper` を使うことで、テスト エクスプローラーの「テスト詳細の概要」（どっちやねん）に表示することができます。

https://xunit.net/docs/capturing-output

これをプライマリーコンストラクターで注入し、使用します。

```diff_c_sharp:DemoTest.cs
+using Xunit.Abstractions;

namespace HigeDaruma.DemoXUnit;

-public sealed class DemoTest
+public sealed class DemoTest(ITestOutputHelper testOutputHelper)
{
    [Fact]
    public void MathAbs_ReturnsOk_WhenInputValueIsOk()
    {
        // Arrange
        int value = -1;
        int expected = 1;

        // Act
        int result = Math.Abs(value);

        // Assert
        Assert.Equal(expected, result);
+        testOutputHelper.WriteLine($"result: {result}");
    }
}
```

以前のようにフィールドを用意する必要がなく、一行に満たない変更で標準出力を開始できます。

### 3. テストを実行してみる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1107938/01f316d0-1b09-9d53-8a50-4b8d8ff2d68e.png)

はい簡単。
SQL学習メモ（1章）

## SQLの概要
標準SQL：Oracle, SQL Server, PostgreSQLなど様々なRDMBSに共通した標準規格

SQLの種類
- DDL(Data Definition Language)
DDL（データ定義言語）は、データベースやテーブルを作成したり作成したりする。
例：CLEATE, DROP, ALTER

- DML(Data Manipulation Language)
DML（データ操作言語）は、テーブルの行を検索したり変更したりする。
例：SELECT, INSERT, UPDATE, DELETE

- DCL(Data Control Language)
DCL（データ制御言語）は、データベースに対して行った変更を確定したり取り消したりする。
例：COMIT, ROLLBACK, GRANT, REVOKE
<br>
Git コマンドの（超簡素な）聖書

<h1>はじめに</h1>
    <span>はじめまして、まりあ様です</span>
    <br/>
    <span>初めての投稿はチーム内でよく質問いただく、gitコマンドについてまとめます</span>
    <br/>
    <span>今さっと出てくる、わたしがいつも使うやつだけです</span>
<h1>ソースの最新版取り込み</h1>
    <span>これしないと、他の人の修正取り込まれないし、コンフリクトとか前の人の修正打ち消したりしちゃう可能性があるので、なんか修正したいソース触る前に必ずやってます</span>
    <br/>
    <span>実際、今はコマンド使ってやってないけど</span>
    
        git pull

<h1>別ブランチ取り込み</h1>
    <span>開発用にdevelopブランチとか、ブランチ色々あると思いますが</span>
    <br/>
    <span>他のブランチの修正をこのブランチに取り込みたいっっ</span>
    <br/>
    <span>てときないでしょうか？</span>
    <br/>
    <span>自分用のブランチを最新化とかが具体例だと思います</span>
    <br/>
    <span>じゃ、ここではdevelopブランチの修正をfeature/mariaブランチに取り込んでみます</span>
    <br/>
    <span>何かしらでfeature/mariaブランチに移動（わたしはいつもVS Codeから切り替えてﾏｽ）</span>
    <br/>
    <span>feature/mariaブランチ上で👇をたたく！</span>

        git merge develop
        
<span>完</span>
<span>差分なければAlready Up to date.みたいなのが出てくる～</span>

<h1>退避したいとき</h1>
    <span>ソースコード修正中に最新化しなきゃいけなくなった</span>
    <br/>
    <span>だったり</span>
    <span>別ブランチに移動したいのに修正中のファイルがあって切り替えられない！</span>
    <br/>
    <span>だったりあると思うんですよね</span>
    <br/>
    <span>とりあえず退避してからやりましょう</span>
    <br/>
    <span>一旦👇のコマンド打てば、今修正中のファイルの一時保存みたいなことができちゃいます</span>
    
        git stash -u

<span>ちなみに「-u」は、新規作成したファイルもそのまま取っておける</span>

<h1>退避した変更を戻したい</h1>
    <span>さっき退避しておいたファイルの戻し方です</span>
    <br/>
    <span>例えば、最新化終わってさっきの変更戻したい～とかﾈ</span>

        git stash apply

<span>これでさっきまで修正してたのが、元に戻せます</span>
<br/>
<strong>追記</strong>
<span>上記でご紹介した`apply`をつける形は退避した作業を一覧に残す、という意味があります（感覚的にはstashした履歴って感じ？）</span>
<span>特に退避した作業を一覧に残したくない場合は、退避を戻すと同時に退避した作業を一覧から削除できる👇を叩いてください（コメントでのご教示ありがとうございます！）</span>

        git stash pop
<span>特段、退避した作業を一覧に残す必要がなければ、`pop`で良いと個人的には思いました</span>

<h1>まとめ</h1>
    <span>毎日使うのはこの４つ</span>
    <br/>
    <span>最新化→修正用ブランチに最新化したソース取り込みしてから修正すれば間違いなく、人のソースを打ち消すことはなくなると思いﾏｽ</span>
    <br/>
    <span>念には念を、で、わたしはコミット前にも最新化してからコミット・プッシュしてます</span>
    <br/>
    <span>なので、変更を退避したり、退避した変更を戻すコマンドも使う</span>
    <br/>
    <span>みたいな感じです～～</span>
    <br/>
    <span>コミットとかプッシュとかブランチの切り替えに関しては、今のわたしはVS Codeからやってます</span>
    <br/>
    <span>プッシュとか失敗した時用、初めてgitにプッシュする時のコマンド聖書も時間あれば書きます</span>
credencialsに保存した数値とは違う数値が返ってくる問題

# TL;DR
Railsのcredentialsファイルに"0"や"0x"から始まる数字を設定すると、その値が取り出す際に異なる数字に変わってしまう問題が発生する。この原因はYAMLのフォーマットに由来しており、対策としては適切なエスケープを行う必要がある。

# 環境
Rails 7.1.3.2
ruby 3.3.0

# 何があったか
ある日、Railsのcredentialsファイルに次のような設定を行いました。

```yaml
# credentials
service:
  password: 01234
```

その後、この値を渡しても何故か認証が通らない。
理由を探るために、Railsコンソール（IRB）でこの値を取り出すと、以下のような結果が得られました：

```sh
irb(main)> Rails.application.credentials.service[:password]
=> 668
```

###  ・・・？

設定したpasswordの値は01234でしたが、取り出すと668という異なる値になっています。

# 原因
わかる人にはすぐ分かる原因だと思うのですが、
この問題の主な原因は、Railsのcredentialsが内部的にYAMLフォーマットを使用していることにあります。YAMLでは、特定の文字列パターンを異なる進数として解釈します。

- 8進数
YAMLでは、"0"から始まる数字を8進数として解釈します。例えば、01234は8進数として解釈され、10進数では668になります。数値のみだったのも原因の一つです、0から始まっても数値以外の文字が含まれる場合は文字列として解釈されます。

- 16進数
また、YAMLは"0x"から始まる数字を16進数として解釈します。これは数値以外の文字を含んでいる場合も発生します。
例えば、以下の設定を行った場合

```yaml
# credentials
service2:
  password: 0x1A
```
この値を取り出すと、16進数の0x1Aは10進数の26として解釈されます。

```sh
irb(main)> Rails.application.credentials.service2[:password]
=> ２６
```

# 対策
この問題を回避するためには以下のような対策が考えられます。

文字列として保存する"0"から始まる数字を保存する際には、必ず文字列として保存するようにします。例えば、01234を"01234"のようにダブルクォーテーションで囲みます。これにより、YAMLはこれを文字列として扱うため、数字の変換が発生しません。

```yaml
# credentials
test:
  password: "01234"
```

```sh
irb(main)> Rails.application.credentials.test[:password]
=> "01234"
```

# まとめ
credencialsに限らずYAMLだったら発生するので知らないとびっくりしそう。
【書籍紹介】世界一流エンジニアの思考法

## 概要
米マイクロソフト社シニアエンジニアである「牛尾剛(著作)」が、マイクロソフト社で働く一流エンジニアから エンジニアとして働く上での思考法をまとめた一冊です。
多くのことが記載されており、どの章もおもしろいものですが少しだけ抜粋して紹介させていただきます。

![41PjuwcEzYL.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3806000/35510ec4-a910-78d5-1cf1-577adf40b705.jpeg)


## キーワード

### 試行錯誤は「悪」である
・衝撃的でした。しかし、単に試行錯誤を否定しているのではなく「仮説」を立てない試行錯誤は悪であるという考え方である。この本を読んでから仮説を立てる（なぜこのエラーが出ているのか、どこまで正しくてどこから間違っているのか）ことを大切にしたらスムーズに進められることが多くなった。
### Be Lazy（怠惰であれ）
・「最小の工数で最大の成果を出す」というマインドセット
・優先順位の付け方を変える。多くの日本人が優先順位をつけるときには順位付けのような形をとるが、書籍で紹介されているのは複数の中からピックアップするイメージである。最初の１個をピックアップしたらほかのものには手を付けない感覚だと紹介されている。
考え方１つひとつが日本とは違い、新しい発見が多かった。
### 情報量を減らすコミュニケーション
・たくさん情報があっても消化できないという感覚
・付加的な情報は聞かれてから話す
・この部分に関しても日本の文化とは少し違うのかなと感じた。しかし本質的な伝え方は同じだと思う。相手にどうしたら伝わりやすいのかを工夫することが大切。

## まとめ
この１冊を読んでから私自身の考え方や仕事に対しての取り組み方などが驚くほど変わりました。もちろんすべてを吸収することは文化の違いや考え方の違いで難しいですが、知見が広がる一冊だと思います。また、技術書よりも読みやすく、本を読むことが苦手な人にもおすすめです。
Android Studioにてgradle build時にCould not read workspace metadata from ~ のエラー

Android Studioにてgradle build時に以下のようなエラーが発生してビルドできず

```
Multiple build operations failed.

Could not read workspace metadata from C:\Users\UserName\.gradle\caches\transforms-4\hogehoge\metadata.bin
```

キャッシュ関連のようだったので`Invalidate Caches`からキャッシュ削除では直らずで
`C:\Users\UserName\.gradle\caches`を直接全部消すことで直りました。

検索すると以下が出てきたので関係しているのかも？
比較的新しいバージョンのみのバグなのかもしれず、すぐ直るのかもしれないが備忘のため記載

https://github.com/gradle/actions/issues/167
ISERT SELECT の注意点！ 正常終了してるのにデータが入らない！？ ~改善案を添えて~

# はじめに
今回仕事でpgsqlを扱っており、APIでぱっと見想定通り動作するであろうINSERTのSQL文作成して実行したところ、正常終了しているのにも関わらず登録されないという悲しい話がありましたので、メモ兼アウトプットがてら書いていきたいと思います。
既存のコードを改修していった結果、本来こんな書き方しないだろうというものになったのですが、そのおかげで新たな知見を得ることができました。

## やりたかったこと
やりたかったこととしては、とある空のテーブルにINSERT SELECTを使ってデータを登録しようとしました。参照元のテーブルはINSERTするテーブルです。
今回使うテーブルを以下のように定義します
```sql:table.sql
CREATE TABLE employees (
    employee_id INTEGER PRIMARY KEY,
    first_name VARCHAR(50) NOT NULL,
    last_name VARCHAR(50),
    email VARCHAR(100)
);
```

# 間違えたSQL文
元々SQL文でemployee_id部分を自動生成をしていたのですが、とある事情によりコードで生成した値を固定値として代入することになり、単純に修正したものです。
```sql:insert_sql.sql
INSERT INTO employees (
    employee_id,
    first_name,
    last_name,
    email
)
SELECT
    1 as employee_id,
    John as first_name,
    Doe as last_name,
    john.doe@example.com as email
FROM
    employees
```
このSQL文の実行結果としては、正常終了して何も登録しないという形になります。
 **固定値入れてるのに何でデータが登録されないんだ！！エラーとかもはいてないし、何も問題ないはず！！** 

## 原因
INSERT SELECTするとき **参照元のテーブルには少なくとも1行が何かしらのデータがないといけない** らしいです。当たり前の話ですが参照するデータがないとSELECT文は何も返せません。SELECT君が何も返さないとINSERT君も動いてくれないらしく、仮に固定値のように入れてもSELECT君がなにも返さないのでINSERT君も動かないという現象が起きたみたいですね。
じゃあ適当なデータがあれば動くのかというとその通りでプライマリーキー制約に従うようにデータを1つ登録した後に上記のSQL文を動かすと正常終了して登録されていました。

 # 修正
 解決方法はいくつかありますが、前提として空のテーブルにデータを登録するSQLを書いていきます。
## 案1：素直にINSERT VALUES
INSERT VALUESで固定値を登録していく方法です。コード上で値をSQL文に代入していって実行していったりしました。
 ```sql:insert_values.sql
 INSERT INTO employees (
    employee_id,
    first_name,
    last_name,
    email
)
VALUES(
    1,
    John,
    Doe,
    john.doe@example.com
)
 ```
これなら特に問題なく登録されてます。普通に登録するならこれでいいです。というか固定値で登録するならこれでいいです()

## 案2：シーケンスを使う
シーケンスを使って値を固定で段階的に登録していきます。
```sql:insert_coalesce.sql
INSERT INTO employees (
    employee_id,
    first_name,
    last_name,
    email
)
SELECT
    nextval(employee_id_seq) as employee_id,
    John as first_name,
    Doe as last_name,
    john.doe@example.com as email
FROM
    employees
```
シーケンスで値を登録しているので1，2，3…といった感じで階段的に登録していきます。

## 案3：COALESCEを使う
まずCOALECEとはなにかといいますと、簡単にいうと限定的な条件文みたいなものです。限定的というのはNULLかNULL以外かの処理しかいてくれません。ただこれはSQL文で値を設定してくれるので任意のルールの値で登録することができます。
```sql:insert_coalesce.sql
INSERT INTO employees (
    employee_id,
    first_name,
    last_name,
    email
)
SELECT
    COALESCE(MAX(employee_id) + 1, 1) as employee_id,
    John as first_name,
    Doe as last_name,
    john.doe@example.com as email
FROM
    employees
```
このSQL文では参照元のemployeesにデータがあればemployee_idの最大値をとってその値に1を足した値を設定し、データがないときは”1”を入れてくれます。この分なら独自のルールで値を設定していくことができます。

# 最後に
他にもIF文とかCASE文とかありますが正直全部書く体力はないので割愛します(許してください)
単純なVALUESを使ったやり方からCOALESCEのような関数を使ったやり方まで色々あり、用途ごとでかなり使いわけができることを知れてよかったです。

今回の感想としてはINSERT文で正常終了したのにデータが存在しないことがあるのにびっくりしました…(今までは制約によるエラーとか文字制限によるエラーとかで何かとすぐ解決できる系でした)
てか初めから修正するときにめんどくさがらず確実に動く文で書くべきだったなぁって思います。


余談ですが、今回初めての投稿なので拙い部分が多かったと思いますが、プログラミング能力だけでなく伝え方とかドキュメントの残し方の能力も上げていきたいなと思います。

今回の記事が皆さんのお役に立てましたら幸いです。またのご訪問をお待ちしております！
パスワード付きzipファイルをpythonで扱う方法、7zを扱った高速化まで

# はじめに
パスワード付きzipファイルをpythonで扱う方法をまとめます。
機械学習などプログラムで扱いたいデータが外に出てはいけないものの場合、役に立つと思います。
今回は、ファイルとして出力せず、プログラムでファイルの内容のみ出力するコードを紹介します。ファイルとして出力したい方は参考文献に記載している[こちら](https://note.nkmk.me/python-zipfile/)が参考になると思います。
なお、圧縮ファイルの形式が選べる方は、7z形式を使うと高速だと思います。

# 全体像(zip version)
ソースコードはこちらです。
```python:unzip.py
import zipfile
import getpass


p = getpass.getpass().encode()
zipFilePath = ".zip" # zipファイルのパスを指定して下さい
with zipfile.ZipFile(zipFilePath, "r") as zp:
    fileNames = zp.namelist()
    for fileName in fileNames:
        try:
            with zp.open(fileName, pwd=p) as f:
                content = f.read().decode()
                print(content)
        except RuntimeError:
            print("パスワードが間違っています")
```
プログラムは大きく以下の手順を踏んでいます。
1. `getpass`を使ってパスワードを取得
2. `zipfile`を使ってパスワード付きzipファイルを読み込み

# `getpass`を使ってパスワードを取得
`getpass`はpythonの標準モジュールです。今回、パスワードをソースコードに直接書きたくなかったため、使用しました。
代替案として、環境変数で定義するなどがあると思います。
`getpass.getpass()`を実行すると、テキストボックスが表示されるので、パスワードを入力します。後に紹介する`zp.open()`がbytesを入力として受け取るので、bytes型に変形します。

# `zipfile`を使ってパスワード付きzipファイルを読み込み
`zipfile`はpythonの標準モジュールです。
`zp.namelist()`はzipファイルに含まれるディレクトリ名、ファイル名を返します。
`zp.open(fileName, pwd=p)`はファイルの内容を読み込みます。pwdにパスワードをbytes型で渡します。`f.read()`ではbytes型が返されるので文字列型に変形します。

# 高速化
もし圧縮ファイルの形式が選択できるなら、7z形式で圧縮すると圧縮、解凍共に高速だと思います。zipのときと比べて体感9倍ほど早くなったように感じます。
7z形式のファイルも`py7zr`を使うことでpythonで扱うことができます。
以下にmacでの7z形式のパスワード付き圧縮ファイルの作り方、`py7zr`を使ったソースコードを紹介します。

# macでの7z形式のパスワード付き圧縮ファイルの作り方
macで7z形式の圧縮ファイルを作るには`p7zip`を使います。
他に`sevenzip`というものもありますが、`p7zip`の方が改良版だという情報がありました。[詳しくはこちら](https://apple.stackexchange.com/questions/439438/whats-the-difference-between-homebrews-sevenzip-and-p7zip-formulae)
```
brew install p7zip
```
パスワード付きの圧縮は以下のようにします。
```
7z u -p 圧縮ファイル名.7z 圧縮したいフォルダ（ファイル）名
```

# 全体像(py7zr version)
ソースコードはこちらです。
```python:unzip.py
import py7zr
import getpass


p = getpass.getpass()
zipFilePath = ".7z" # 7zファイルのパスを指定して下さい
with py7zr.SevenZipFile(zipFilePath, 'r', password=p) as zip:
    allfiles = zip.getnames()
with py7zr.SevenZipFile(zipFilePath, 'r', password=p) as zip:
    for fname, bio in zip.read(allfiles).items():
        content = bio.read().decode()
        print(content)
```
動かすためには`pip install py7zr`でインストールする必要があります。
`py7zr`では、パスワードは文字列型で渡さないとエラーが起こるので気をつけて下さい。

# 参考文献
[Google Colab でトークン等の秘密データを扱う場合にはどうしたらいいのか？](https://ja.stackoverflow.com/questions/73201/google-colab-%E3%81%A7%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3%E7%AD%89%E3%81%AE%E7%A7%98%E5%AF%86%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E6%89%B1%E3%81%86%E5%A0%B4%E5%90%88%E3%81%AB%E3%81%AF%E3%81%A9%E3%81%86%E3%81%97%E3%81%9F%E3%82%89%E3%81%84%E3%81%84%E3%81%AE%E3%81%8B)
[getpass](https://docs.python.org/ja/3.12/library/getpass.html)
[PythonでZIPファイルを圧縮・解凍するzipfile](https://note.nkmk.me/python-zipfile/)
[zipfile](https://docs.python.org/ja/3/library/zipfile.html)
[［解決！Python］py7zrパッケージを使って7-Zip（.7z）アーカイブを展開したり、ファイルを読み込んだりするには](https://atmarkit.itmedia.co.jp/ait/articles/2405/28/news024.html)
[py7zr](https://py7zr.readthedocs.io/en/latest/api.html)
windowsjavaとtypescriptでアプリケーションを作成

windows11で開発

javaとtypescriptでwebサイトの作成

サーバー側
java
・spring boot
・projectはMaven　3.2.6 javaのバージョンは17
.titleはdemo
これで作成してひな型を作成


docker buildとrunで実行
コントローラーを追加してhello spring bootを表示させるようにした
ポート番号を8080で実行


フロント側
typescript,react

npx create-react-app my-app --template typescriptでmy-appプロジェクトを起動

フロント、サーバー側どちらにもDockerfileを作成
サーバー側にはmavenのコピーとビルドを記載
フロント側にpackage.jsonなどの設定を記載
ルートディレクトリ配下にdocker-compose.ymlを作成

以下のようなディレクトリで作成

my-java-ts-project/
├── demo/
│   ├── Dockerfile
│   ├── pom.xml
│   ├── mvnw
│   ├── .mvn/
│   └── src/
├── my-app/
│   ├── Dockerfile
│   ├── package.json
│   ├── package-lock.json
│   ├── public/
│   ├── src/
│   └── .dockerignore
└── docker-compose.yml


今後の課題
Qiitaの使い方（マークダウン書式など）とアプリケーションの作成
内容もだがホットリロードを導入したい。
【Typescript】 アサーション(as) を避ける

## はじめに
開発業務で下記のようなコードを見て、エラーが出ている理由が不明だったため型アサーションについて調べてみました。

```typescript
  type User = {
    name: string;
    age: number;
  };

  const tanaka = (): User => {
    return { name: "田中" };
  }; 
  // エラー
  // プロパティ 'age' は型 '{ name: string; }' にありませんが、型 'User' では必須です。
   
  const yamaguchi = () => {
    return { name: "山口" } as User;
  }; // エラーではない
  ```

## 型アサーションとは
型推論の推測結果とは関係なく、型を上書きする機能です。
コンパイラーよりもプログラマーがより正確な型を知っている場合に使用します。

つまり、確信のある型にのみ型アサーションを使用して、その他はコンパイラーに任せる方がバグを生みにくいコードになります。

## 型アサーションの説明を踏まえて
上記のコードのtanaka関数式では、Typescriptコンパイラーがコードから型を推論した結果、ageプロパティが不足しているのではないかとコンパイラーに怒られている状態です。

一方で、yamaguchi関数式では、型アサーションを使用することでコンパイラーの型推論結果を上書きしているためエラーは発生しませんでした。
Windows上でSVCを使ってchainlitをお気軽に試す

簡単にローカルで動くチャットボットUIをつくりたいと思ったので、chainlitを試してみました。
中身の実装はしておらず、打ち込まれた文言をおうむ返しするだけのものです。

# chainlitとは
streamlitのチャットボット版です。
つまり、pythonで簡単にチャットボットのwebUIを作ることができます。

### chainlit github
https://github.com/Chainlit/chainlit

### ドキュメント
https://docs.chainlit.io/get-started/installation

### ライセンス
商用利用可能なApache License2.0です。
https://github.com/Chainlit/chainlit/blob/main/LICENSE
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106215/50fd55e4-9c50-ee17-415d-9a9c18d0a7e6.png)

# 環境
python 3.10.11
jupyter notebook
Windows 10 Pro
Visual Studio Code 1.87.2

# インストール
chainlitという名前のフォルダを作成し、VSCで開く
VSC上でjupyter note bookを開き、以下実行。数十秒かかりました。
```
! pip install chainlit
! chainlit hello
```

自動的にブラウザが立ち上がり、、名前を聞かれるので適当に入力します。うまく返事が返ってくれば、インストール完了。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106215/313dd795-1894-5338-7d74-351d85a20f14.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106215/85086964-cefa-f173-c184-a7d7363ef3df.png)



chaintlitフォルダ下にapp.pyを作成し、以下をコピペして保存。
messageにユーザーからの入力を受け取り、それをオウム返しにかえすだけのプログラムです。
```
import chainlit as cl


@cl.on_message
async def main(message: cl.Message):
    # Your custom logic goes here...

    # Send a response back to the user
    await cl.Message(
        content=f"Received: {message.content}",
    ).send()
```

jupyter note book上で以下実行。
```
! chainlit run app.py -w
```

おうむ返しbotができました。app.pyに好きなLLMを実装すれば、立派なチャットボットになるでしょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106215/93ffd502-f0e3-b75c-6542-dde3a073f3f4.png)


# トラブルシューティング
以下のようなエラーが発生した場合、オプションでポートを変更すると動きます。
```
2024-04-09 22:54:52 - Your app is available at http://localhost:8000
ERROR:    [Errno 10048] error while attempting to bind on address ('0.0.0.0', 8000): 通常、各ソケット アドレスに対してプロトコル、ネットワーク アドレス、またはポートのどれか 1 つのみを使用できます。
```

オプションで、使用ポートを8000から8001に変更。
```
! chainlit run app.py -w --port 8001
```

以下にcookbookがあるので、それを使えばいろんなことが簡単にできそう。楽しそう。
https://github.com/Chainlit/cookbook

以上
「接続参照」について

ソリューションを用意してアプリやフローを作成していると、「接続参照」というものが作成されるかと思いますが、こいつの役割をご存じでしょうか？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/5b0cdbc9-fd19-e4f2-43de-66b09fbf0daa.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/42316149-817a-1af2-4ea3-aa526ee5927c.png)

「接続参照」とは、一言で **「コネクタ」と「接続」の２つ要素が入ったメタデータ** を意味しております。
似たような言葉としてある「接続」は、コネクタに対するユーザーの資格情報のことで、「接続参照」に資格情報は含まれません。

イメージにするとこんな感じでしょうか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/a4bd76db-9d6d-b40e-b8bc-fb136b0291e9.png)

では、「接続参照」を利用すると何が嬉しいのか、シンプルにまとめました。

## ①フロー内の各アクションにおける接続の再利用
フローを作成する際に、トリガー → アクション① → アクション② → ...と、アクションを並べていくわけですが、アクションによっては外部のデータとやり取りするためにコネクタを利用しなくてはなりません。その際にアクションごとに接続を作成・指定するのはめんどくさいですし、たくさん接続ができてしまって後々整理するのが大変になってしまいます。

そこで、コネクタ毎に「接続参照」を一つ作っておけば、各アクションで再利用できます。アクションが追加されると、新しい「接続参照」を作成する前に、既存に再利用できるものがあればシステムが自動でそれを利用するように設定してくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/27a9b909-3746-5af6-72ab-edcdaee9f6a9.png)

## ②ソリューションの自動デプロイ（自動インポート）を保証
最近 [Power Platform パイプライン](https://learn.microsoft.com/ja-jp/power-platform/alm/pipelines) というALMツールも出てきていますが、ある環境から別の環境へソリューションをデプロイするときに、事前に接続参照をデプロイファイルに設定することで、インポート後に後処理的に接続参照を設定することがなくて済みます。

「設定の手間ぐらいなら我慢するよ」と思うかもしれませんが、デプロイ先の環境で接続参照が正しく機能しないと、接続参照を使用するフローがオフになってしまいますのでぜひALMツールを使って自動デプロイをする際には事前設定を行うようにしましょう。

逆に言えば事前設定をした上で自動デプロイを実現できれば、作業者はPower Appsの画面からデプロイ処理をひたすら眺めて待つこともなく、後処理作業もなくなるので、非常に仕事の効率が上がるはずです。

Power Platform で利用できる ALM ツールに関してはまた次回。

※なお「接続」はソリューションに含めることはできないので、事前に各環境に手動で作成いただく必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/cdfeafc9-3fe5-d6c6-b093-015a6224b22f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/2edde3e7-50e3-c92f-b1bb-22620b59bb9c.png)
Pythonの良く使う型まとめ

## Pythonの型
Pythonでよく使われる型を調べてみたよ。よく使うのは以下の7つ。それぞれ使い方を確認していくよ～。Pythonは、型を記載しなくても自動で認識してくれるけど、型を書くこともできるよ。int型で書き方の例を挙げておくよ。
* int型：整数
* float型：小数点
* str型：文字列
* bool型：真偽値
* list型：リスト
* tuple型：タプル
* dict型：辞書 

### int型
これは、整数を定義するよ。小数を含まない、正の整数、負の整数を扱えるよ。
Pythonは、Javaとは違って型を記載しなくても自動で認識してくれるけど、書くこともできるよ。念のため、`print(type())`で型を確認するよ。
~~~python
int_num_x = 10
int_num_y : int = 20
print(f'int_num_x = {int_num_x}')
print(f'int_num_y = {int_num_y}')
print(f'int_num_x : {type(int_num_x)}')

# 出力結果
> int_num_x = 10
> int_num_y = 20
> int_num_x : <class 'int'>
~~~

### float型
int型は整数のみを扱っていたけれど、float型は小数点を含む数字の扱いができるよ。
~~~python
float_num = 10.5
print(f'float_num = {float_num}')
print(f'float_num : {type(float_num)}')

# 出力結果
> float_num = 10.5
> float_num : <class 'float'>
~~~

### str型
str型は文字列として扱うよ。この型で宣言された数字、文字、記号などはすべてstr型として扱われるよ。str型は`''`もしくは`""`で囲うことでstr型として扱うことができるよ。
~~~python
str_num = '10'
print(f'str_num = {str_num}')
print(f'str_num : {type(str_num)}')

# 出力結果
> str_num = 10
> str_num : <class 'str'>
~~~

### bool型
bool型は真偽値`true`か`false`を判定するよ。
~~~python
x = True
print(f'x : {type(x)}')

# 出力結果
> x : <class 'bool'>
~~~

### list型
list型は`[]`で囲って`,`で区切って書くよ。str型やint型など、いろいろ混ぜての指定もできるよ。
~~~python
list_mix = ['python', 3.0, 'を', 1, '時間勉強したよ。']
print(list_mix)
print(f'list_x : {type(list_mix)}')

# 出力結果
> ['python', 3.0, 'を', 1, '時間勉強したよ。']
> x : <class 'list'>
~~~

### tuple型
tuple型は一度作成したら変更できないリストと覚えておけばいいよ。
list型は`()`で囲って`,`で区切って書くよ。
~~~python
tuple_list = (10, 3.14, 'test')
print(tuple_list)
print(f'tuple_list : {type(tuple_list)}')

# 出力結果
> (10, 3.14, 'test')
> tuple_list : <class 'tuple'>
~~~

### dict型
dict型は、key(キー)とvalue(値)をペアにして保存して、keyで呼び出すことができるよ。dixt型は`{}`で囲ってkeyとvalueを`:`で繋げて、`,`で区切って書くよ。変数名の後に`[key]`でkeyに対応するvalueを取り出すことができるよ。
~~~python
dict_sample = {1:'americas', 2:'japan'}
print(dict_sample)
print(dict_sample[1])
print(dict_sample[2])
print(f'dict_sample : {type(dict_sample)}')

> 出力結果
> {1: 'americas', 2: 'japan'}
> americas
> japan
> dict_sample : <class 'dict'>
~~~

## まとめ
pythonでよく使うデータ型をざっくりまとめたよ。型の宣言をしなくてもいい分、ぱっと読みずらいところもあるので型の記載をするといいかもしれないね。
基本を押さえて、データの扱いに慣れていこう！
【Vuetify3】v-data-tableで悩んだこと（チェックボックスの色変更 / v-slotの記述法）


最近Vuetify3でも` v-data-table `が使用できるようになったので使用してみました。
その時にいくつか悩んだ点があったのでその備忘録です。

# チェックボックスの色変更
チェックボックスの表示は、`v-data-table`タグに`show-select`を記述することで実装することができます。

```vue
<v-data-table
  v-model="selected"
  :items="items"
  item-value="name"
  show-select
></v-data-table>
```

![checkbox.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3669971/963f7b1c-7c31-f3a8-3a25-243887b388d2.png)

<br>

チェック時の背景は、初期設定では黒になっています。
こちらの色を変更するにはCSSで上書きします。

```css
<style>
.mdi-checkbox-marked {
  color: blue;
}
</style>
```
![checkedbox.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3669971/9d67828b-32ce-ac08-d5f0-20418d0ac9bf.png)

<br>

チェックボックスは`mdi`アイコンを使用しているので、
そのクラス名を指定し、`color`を変更すれば色が変わります。

:::note warn
注意
styleタグが `scoped` だと反映されません。
`scoped` を外すと、他の画面の同じアイコンの色も変更されてしまうので注意してください。
:::

# フッターの非表示
Vuetify2では `hide-default-footer`を使用しましたが、 
**Vuetify3**では `<template #bottom />` を渡すことで非表示にできます。

```vue
<v-data-table
  v-model="selected"
  :items="items"
  item-value="name"
  show-select
>
<template #bottom />
</v-data-table>
```

　![hidebottom.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3669971/96a84d46-4f8f-ed61-6def-70caaa4b6005.png)


# v-slotの記述法
VSCodeで開発をしていて、
拡張機能で `ESLint` を入れている場合、
`v-slot` の記述法に気をつける必要があります。

例えばテーブルにアイコンを表示したい場合、
下記のように記述するとエラーが発生します。
```vue
<template v-slot:item.actions="{ item }">
<!-- 'v-slot' directive doesn't support any modifier --> 
```

<br>

下記のように書き換えることでエラーを解消することができます。

```vue
<v-data-table
  v-model="selected"
  :headers="headers"
  :items="items"
  item-value="name"
  show-select
>
  <template #[`item.actions`]="{ item }">
    <v-icon
      class="me-2"
      size="large"
      @click="editItem(item)"
    >
      mdi-pencil
    </v-icon>
  </template>
</v-data-table>
```

![showicon.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3669971/3d01d804-6d6a-6840-9c6f-9fe18696d9d9.png)

# おわりに
以前までは `v-data-table` が使用できなかったので、
リッチなテーブルを表示する場合は`AG Grid`を使用していました。

Vuetify2の頃とは少し記法が異なるので、
ちょこちょこ調べつつ これからは`v-data-table` を使っていきます。


# 参考文献

https://zenn.dev/hamworks/articles/article8-nuxt-vuetify-vdatatable

https://qiita.com/pokoTan2525/items/c698457d2473dab0868f
16ビット漢字半角の処理方法を考える

x うごくかどうかは、ふめい

目的
最小限で16ビット漢字の全角半角を表現する


一番簡単そうなのは、カウンター方式

```

y   x→   01234567 89012345 6789012345678901 

　　　　　76543210 76543210 FEDCBA9876543210                 
↓        半角     半角　　　　全角
        
          01234567 01234567 0123456789012345 ←　文字の列のカウンター

0         00111000 00111000 0111111111111100

```

半角だったら(文字の列のカウンター)アップして8になったら0にする　半角フラグ=0

全角だったら(文字の列のカウンター)アップして16になったら0にする　全角フラグ=1 16の時0にする

半角フラグ0ならキャラクターRAMから読み取って
半角ならそのまま、全角なら1をセット

半角なら上位に0をセットして16ビット漢字ROMから読み取る
全角なら次の文字も読み取って16ビットにして漢字ROMから読み取る

文字が半角か全角かは、SJIS?のアルゴリズムを使う


半角文字は、空白を除くと7x12とする
5x7のもじを改造して使う


いろいろ書いてあることが矛盾するが
半角/全角フラグ2は、
x[0は、非表示　フォントの文字の列に0をセットする]←なし
0が16ビット漢字の上位8ビット ((フォントの文字のドット列)<<0) AND 0xFF00
8が16ビット漢字の下位8ビット ((フォントの文字のドット列)<<8) AND 0xFF00
16が非表示
半角/全角属性RAMに事前に格納
キャラクターRAMは、一文字当たり16ビット
全角は、同じコードが2個はいる　(事前に格納)