OmniAICreator/Qiita-1.07M huggingface dataset:
ブルーレイを作るのが難しすぎる（未解決）

# ブルーレイを作る、ということ

ブルーレイを作る、というのはどういうアクション、成果物かというと、
「ブルーレイプレイヤー（PS4 とか）で再生できるオーディオディスク」
あるいは
「大容量であるブルーレイにデータとしてファイルを焼く」
の二種類が、ある。

これの前者作業が、強烈に難しく、めんどくさい。
DVD がこの世に生まれた当初もわりと似たようなものだったのだけれど、
プレイヤーで再生する、データディスクではない、CD、DVD、ブルーレイというものは、
（多分オーディオディスクと呼ぶのが、区別つくかなと思うのでそう呼ぶが）、
作成になかなかの手間暇がかかり、
それゆえ有料ソフトが乱立するもの、であった。

CD を作るときも、昔は苦労した…。
（バンド時代、お客さんに配るためのCD 作成。「ファイナライズ」とかよくわからん工程があったなぁ）

DVD だって、今も簡単とは言わん、
たとえばiPhone で撮影した我が子のかわゆさ満点の動画を、
田舎のじいちゃんばあちゃんに見せてやる際に…
まぁもちろん、
「YouTube で共有すれば？」
「Google フォトがあるでしょ？」
「てかLINE で送ればいいじゃん」
というのはその通りなのだが、DVD で渡そうと思ったとき、
動画データである「mp4」「mov」「wav」ファイルを、
DVD プレイヤーで再生できるオーディオディスクの形式にして焼くには、
そこそこの苦労がある。

まぁ、とはいえ、昨今DVD は作りやすい。
様々な動画再生ソフトや、動画編集ソフトで、動画を並べてISO イメージを作るのは、できる。

しかし私のような素人がつくると、iPhone で撮った高画質4K 動画、を、
DVD でオーディオディスクにすると、解像度がめちゃくちゃ悪くなって全然綺麗じゃなくなる。
…なぜか（不明）。

で、あるので、ブルーレイに4K だかフルハイビジョンだか、
とにかく高画質映像を焼いて田舎のばあちゃんとかに届けてやりたいのだが、
…とにかく作るのが難しすぎるのである…


# MP4 からオーディオディスクを作るまでに4つほどソフトを使う
ここの部分についての詳述は避け、「ググってくれ！」となる。
私のこの記事の肝心なところ…のような気もするのだが、
人様のブログで学んだ知識。
しかもそちらのブログで、実に全4回にも分けて解説される、
「非常に難易度の高い」「読み応えのある」内容であった。

MP4 のファイルをブルーレイの（データディスクではない）オーディオディスク用の形式「BDAV」にするのであるが…その生成と、ディスクを焼くまでに4つものソフトをインストールして使うこととなった。

MP4 ファイルをデータとしてブルーレイディスクに焼くのであれば、それは一瞬のことである。
しかし私はPS4、PS5、
つまりはブルーレイプレイヤーで再生したいので、苦労することになった。
…むしろPS5 たちがMP4 再生に対応しててくれれば話は早いんだけれどなぁ…何かが違うんだろうなぁ…。


「MP4 からオーディオディスクのブルーレイを焼く」方法を解説してくれてるブログは、
（私のこのQiita アカウントが会社と紐づいちゃってるので）
（気にすることでも無いかもしれないけれど）
リンクを掲載するのは控えておいて、
こちらのキーワードで検索してはいかがか、と投げかけておく。
「フリーソフトだけで作るBlu-ray 第3回：BDAVの作成 Part.1」

このブログで学び、以下の手順を行った。
* MediaInfo をインストールしてMP4 ファイルの情報を確認する（今思えば不要だったかもしれない）
* MP4 形式をm2ts 形式にする → tsMuxer GUI というソフトを使う。MP4 ファイルの読み込みに時間がかかる。プログレスバーが100％ にならない。
* BDAV 形式としてフォルダ構成に、ブルーレイ映像形式を作成する。MAkeBDAV というソフト。なんか本家がきえてるらしい。拍子抜けするほど作成処理早い。
* BDAV フォルダをブルーレイディスクに焼く。ImgBurn というソフトで行う。


果たして、ブルーレイディスクは出来上がった、のだが…
いざPS5 で再生してみると…
（PS5 を所持している自慢）


# 音が再生されない問題（未解決）

途方に暮れたものである。
今回ブルーレイに焼いたMP4 ファイルは2種類。
「可愛い孫の動画を祖父母へ送る」かのように、上の方では目的を誤認させたかもしれないが、
実際に行ったのは、
「還暦を過ぎたおっさんたちと女子高生バンド「けいおん！」のコピーをライブハウスで演奏した」
動画、2種類である。

カメラワークの異なる2種類の動画。…いるのか、この老人バンドにカメラワークアレンジバージョンの動画が…
まぁそれはさておき、2種類の動画を、オーディオディスクに焼いて、PS5 で再生してみた。
すると、まぁ、なんてことでしょう？？

片方の動画はちゃんと映像、音声とも綺麗に再生されたのだが、
もう一方は音声が全く再生されない。
焼き直してみたり、焼き方を替えてみたり、
わからないなりにあれこれやってみてもちっとも解決しない。
PS4 でも再生されない。だからPS5 の不具合、というわけでもない。
ちなみにPS5 は普通の人間の感覚だと、ディスクの裏表を逆に入れてしまう形をしている。
そこは気をつけよう（昔SONY に問い合わせて恥をかいた）。

何度も焼き直しながら、PlayStation での再生を試みる。
…この時に、「BD-RW」、リライトできるディスクで良かったなぁ、と思った。
何度も焼き直した。
しかし状況は変わらず。

そこで、（ここがこのブログ記事のメイン）、
ChatGPT に相談した。
「なぜだ！」と。

「PlayStation でブルーレイを再生したが、音が出ない。なぜか。助けて」

そう。私はChatGPT を使いこなしていき、「AI おじさんのQIITA ブログにしてやろう」と、
このQiita の場で記事を書く野望を持っていたのだ。
ChatGPT に相談しなくては、ブログにならない。記事にならない。会社にも書くって言っちゃったんだ。

ChatGPT 曰く。
「PlayStation の対応しているオーディオサンプリングレートは48kHz です…」
などなど、色々小難しいことや仕様を返答してくれたのだが、
ん？
オーディオサンプリングレート？ なんだそれは？

そんなもの気にしたこともなかったが、ChatGPT に聞いてみると、
一般的に音声ファイルは「45.1」、映像（動画）は「48」だそうである。
まさしくずばり。
PlayStation で音声が聞こえない方の映像は「45.1」とPS5 画面でも表示された。
…そのサンプリングレートがわかるなら再生してくれてもいいじゃん、PS5 ！！
と凄く思ったけれども、非対応だから音がならない、という非常にシンプルな答えにたどりつくことができた。
ありがとうChatGPT

しかし…ここからが「未解決」である。
オーディオサンプリングレートの変更方法がわからないのである…。

※ Handbreake なるアプリで変更に挑戦しているのだが、映像が乱れたりでうまく行かず途方に暮れており、その答えはまだChatGPT にもらえていないのであった…
【git】知らないとヤバイ！？実は危険なgit操作5選【初心者必見！】

# はじめに
皆さんが普段から使っているリポジトリ管理ツールのgit。
とても便利なツールですが、実は`超危険なコマンド`があるそうです。
そこで今回は、gitの危険な操作について徹底調査しました！
![danger.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/173970/5b1fcb97-84f7-d142-4b20-5d41bd858d0b.jpeg)

# 危険な操作① push
みなさんが絶対に使っている`git push`ですが、使い方を誤るととても危険です！
pushはローカルの内容をリモートに反映させるコマンドです。
ローカルで誤った内容をコミットしたままpushしてしまうと、リモートへ間違った内容を反映されてしまうこととなり取り返しがつかなくなります。。。
ローカルとリモートの関係について詳しくは[こちらの記事](https://qiita.com/yoshiichn/items/5d9c9105b980921f2809)を見てください！

:::note info
Push自体は気軽に行うことが多いと思いますが、Pushしてリモートに一度反映させた内容は基本的に取り消すことができなくなります。
そのため、Pushするときはローカルから反映させる内容に誤りがないかを十分に確認して慎重に行う必要があります。
:::


# 危険な操作② reset
`git reset`は指定したコミットハッシュまで変更差分を戻してしまいます。
`--hard`オプションをつけるとやっていた作業が全部消えてしまうことも・・・
うっかり実行して作業が全部消えてしまったら怖いですよね・・・


:::note info
デフォルトオプションでは`--mixed`が選択されているので`git reset`をオプションなしで実行しても勝手に消えたりはしないです。
ただ、理解して実行しないと自分の修正差分が消える可能性は普通にあるので、gitの操作中に`reset`するときは十分に注意する必要があります。
(コミットの戻し方みたいな記事で気軽に`reset --hard`してることが多いので危険だなと思っています。)
:::

# 危険な操作③ rebase
:::note alert
一番危険な操作です！
:::
「間違ってコミットしちゃったやつを消したい！」「マージしたらぐちゃぐちゃでよくわかんないから奇麗にしたい」そんな要望をかなえてくれるのが`rebase`という素敵なコマンドです。
でもちょっと待って！`rebase`はブランチ同士を無理やりくっつける歴史改変のコマンドだったのです！
歴史改変をして無理やり今がきれいに見えるようにしているので過去の修正がごっそり全部なくなったり修正したはずのコードが元に戻ったりと、正しく行えないと先祖がえりを起こしやすいとても危険なコマンドみたいです！

:::note info
gitの基本概念として、作業した記録は残していくことが基本となっています。
間違ったコミットなどは`rebase`で隠そうとせず間違ったことも記録したほうがいいと私は考えています。`revert`などでコミットの打消しなども用意されているのでgitとしても隠すことは是としていないと思っています。
先祖返りの原因No1はよくわからずに`rebase`したブランチを`push`していることだと思っているので`rebase`は完全に理解するまで使わないことを強く推奨します。
:::

# 危険な操作④ rm
`git rm`を使用するとリポジトリ内のファイルを削除してしまう可能性があります！
消したファイルは元に戻らないので慎重に捜査をしないと取り返しのつかないことに((+_+))

:::note info
bashコマンドのrmと同じ感じなので使うときは普通に気を付けて削除する。
:::

# 危険な操作⑤ stash
`stash`は変更差分をコミットせずに保存できる便利なコマンドです！
差分を取っておくだけだから危険度がなさそうに見えますが、大きな危険が潜んでいます・・・
`stash`はあくまで一時保存なのでgitが差分を保持している保証がないのです！
stashしすぎると自分がどの差分をstashしたかわからなくなったり間違った内容を適用してしまったりと`stash`を多用するリスクがたくさんあります。
`rebase`のところでも説明しましたが、gitは変更差分を記録していくことが前提になっているので面倒くさがらずに`commit`していく癖をつけるといいですね！

:::note info
便利なコマンドなので私も良く使っていますが、gitは基本commitして記録していくものなのでstashの多用は危険です。
stashは修正内容を一時保存するものなので、意図しない修正を取り込むこととなったりstashしておいたものがどれかわからなくなったりすることがあるので適度に使うのがおすすめです。
`stash`はパスワードなどのコミットしたくない情報を一時保存したりする用途で私はよく使っています。
:::

# おわりに
いかがでしたか？ 

`gitの危険な操作`について、詳しくご紹介できたのではないでしょうか？
便利なgitにも危険が潜んでいて、注意して使わなければいけないのでしょう。

`gitの危険についてははっきりとした情報はありません`が、今後も危険なコマンドが出てくるかもしれませんね。

この記事が参考になったよ～面白かったよ～って思った方はチャンネル登録と高評価をお願いします！
[Tricentis tosca]正規表現を使ってテストに汎用性を持たせる

## はじめに
回帰テストのため「Tricentis Tosca」を利用する機会が増えてきました。
正規表現が使えるようですので使い方を纏めました。
「Tricenti Tosca」を使う際の参考になればと思います。

## 目的

Fiori Ui5では特に指定していない限り「id」の後ろに番号がついており画面を更新するとこの番号が変わります。
なのでこの番号を正規表現で書くことによって
Tricentisで設定している「id」部分を固定で書かなくてもよいと考えました。

## idに対して正規表現を設定
`__item7-__table0-5_cell0`

上記7の部分が変動しているようでしたので正規表現で記載してみます。
`{REGEX["__item\d-__table0-5_cell0"]}`


![Untitled2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2699599/7ad57eca-7fcc-74d5-5646-4988e3f267cd.png)



こうする事によって正規表現が適応できます。
実際に動かします。

![Unaaaaaaaaaaaaaaaaatitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2699599/79a714ef-b0b3-1a10-53fa-046b74776569.png)
問題なく実行できました。


## 問題

今の状態だと「id」の番号が一桁しか対応出来ていない状態です。
もちろん「¥d」を増やせば２桁目も対応出来ますが、別の方法で実装しました。



![Untsddfditled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2699599/fab33e20-589d-3895-321f-855cdeb66afe.png)

上記のように実装すると３桁まで広げることができます。
今までデベロップツールから確認している限り[id]の後ろの番号が４桁を見た事がないのでこの方法で問題ないと思います。

## その他
他にも正規表現の中にorを入れることも出来るようです。
![Untdddditled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2699599/a841555a-1827-07ae-8f9d-31ce858d3656.png)

## 感想
正規表現を使う事によってテストに汎用性を持たせ、テストケース作成の幅が広がりました。
## 参考記事
◆Tricentis Tosca Manual
Regular expressions
[https://documentation.tricentis.com/tosca/1400/en/content/tbox/regular_expressions.htm](https://documentation.tricentis.com/tosca/1400/en/content/tbox/regular_expressions.htm)
テキストファイルからChatGPTのトークン数を見積もるPythonコード

API用のトークン数算出方法を使ってテキストファイルのトークン数を得るコードを作成したのでメモとして残す

# 公式ドキュメント
https://github.com/openai/openai-cookbook/blob/main/examples/How_to_count_tokens_with_tiktoken.ipynb

# 注意
- 利用するモデルがあっているかちゃんと確認する

# 前提
```bash
$pip install --upgrade tiktoken
```

# Pythonコード
```python:get_openai_tokens.py
import tiktoken

filelist = [
  './sample.txt',
]

# 公式よりコピー
def num_tokens_from_messages(messages, model="gpt-3.5-turbo-0301"):
    """Returns the number of tokens used by a list of messages."""
    try:
        encoding = tiktoken.encoding_for_model(model)
    except KeyError:
        print("Warning: model not found. Using cl100k_base encoding.")
        encoding = tiktoken.get_encoding("cl100k_base")
    if model == "gpt-3.5-turbo":
        print("Warning: gpt-3.5-turbo may change over time. Returning num tokens assuming gpt-3.5-turbo-0301.")
        return num_tokens_from_messages(messages, model="gpt-3.5-turbo-0301")
    elif model == "gpt-4":
        print("Warning: gpt-4 may change over time. Returning num tokens assuming gpt-4-0314.")
        return num_tokens_from_messages(messages, model="gpt-4-0314")
    elif model == "gpt-3.5-turbo-0301":
        tokens_per_message = 4  # every message follows 
{role/name}\n{content}
\n
        tokens_per_name = -1  # if there's a name, the role is omitted
    elif model == "gpt-4-0314":
        tokens_per_message = 3
        tokens_per_name = 1
    else:
        raise NotImplementedError(f"""num_tokens_from_messages() is not implemented for model {model}. See https://github.com/openai/openai-python/blob/main/chatml.md for information on how messages are converted to tokens.""")
    num_tokens = 0
    for message in messages:
        num_tokens += tokens_per_message
        for key, value in message.items():
            num_tokens += len(encoding.encode(value))
            if key == "name":
                num_tokens += tokens_per_name
    num_tokens += 3  # every reply is primed with 
assistant

    return num_tokens

for filename in filelist:
  f = open(filename, 'r')
  data = f.read()
  f.close()
  tokens_count = num_tokens_from_messages([{
    "role": "system",
    "name": "example_user",
    "content": data,
  }])
  print(filename + "\t" + str(tokens_count))

```
Hyper-Vに立てたLinuxマシーンにhostnameでsshするためにmDNSを設定しよう

# 前提

意図した名前のhostnameになっていること。なってない場合は`hostnamectl set-hostname foo`とかで設定する。

```
$ hostnamectl
 Static hostname: yumetodo-vm-ubuntu2204-rbenv
       Icon name: computer-vm
         Chassis: vm
      Machine ID: 29c64690abb84668836a03dc707fed75
         Boot ID: cfdd3f3a5132490694a711f12b6f3ff6
  Virtualization: microsoft
Operating System: Ubuntu 22.04.2 LTS
          Kernel: Linux 5.15.0-70-generic
    Architecture: x86-64
 Hardware Vendor: Microsoft Corporation
  Hardware Model: Virtual Machine
```

# hostnameでsshしたい

Hyper-Vでdefault switchでマシーンを立てると毎回IPが変わりがちなので、hostnameでsshしたくなる。

そのためには名前解決が必要で、昔だったらSMBのセットアップをするところだが、今の時代はmDNSがあるのでこれを使う。

# Avahi導入

というわけで、[Avahi - ArchWiki](https://wiki.archlinux.jp/index.php/Avahi)を導入する必要がある。

1. avahi-daemonのinstall
   - ubuntu系の場合: `sudo apt install -y avahi-daemon`
   - RedHat系の場合: `sudo dnf install -y epel-release && sudo dnf install -y avahi nss-mdns`
   - Arch系の場合:   `sudo pacman -S avahi nss-mdns`
1. avahi-daemonを起動する。
   1. `sudo systemctl status avahi-daemon`で`Active: acitve(running)`になっているか確認する。なってれば起動してる。
   1. 立ち上がっていなければ`sudo systemctl start avahi-daemon`で起動できる
1. `/etc/nsswitch.conf`を確認する。`mdns4_minimal [NOTFOUND=return]`ないし`mdns_minimal [NOTFOUND=return]`が`resolve`や`dns`の前に書かれていればいい。書かれてなければ追記する。

      ```
      $ cat /etc/nsswitch.conf | grep hosts
      hosts:          files mdns4_minimal [NOTFOUND=return] dns
      ```
1. ファイアウォールを確認する。
   - ubuntu系の場合: `sudo ufw status`, `状態: 非アクティブ`か、`5353/udp                   ALLOW       Anywhere`があれば問題なし。それ以外は `sudo ufw allow mdns`する
   - RedHat系の場合: `sudo firewall-cmd --add-service=mdns --zone=public --permanent && sudo firewall-cmd --reload`する。`sudo firewall-cmd --list-all`で状態を見れる

ここまですると、host側で`ping <host name>`などとすると次のようなパケットが確認でき、応答が帰るはずである。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94177/7a747833-d7f8-cbb3-58f2-3d925e4e1721.png)


# CentOS6

色々頑張ると今からでもCentOS6でmDNSすることはできる。

https://qiita.com/yumetodo/items/3c483af1e926f8f940c6
新人研修や入門書で教えてくれないJavaまとめ

新人研修や入門書で教えてくれないけど、実務ではよく出てきたり、初級者を卒業して中級者になるために必要なJava知識をまとめました。

ただし、WebやDBアクセスなどに関する情報はスコープ外としています。（各現場のフレームワークによるため）

他にも良いものがあったら追記します。

# リフレクション
- [入門Javaのリフレクション](https://qiita.com/suke_masa/items/0df3bb92bcb69f4a95d1)

# enum
- [入門Javaのenum](https://qiita.com/suke_masa/items/bd242617a2b9bb773cbd)

# ラムダ式・Stream API
- [入門Javaのラムダ式とStream API](https://qiita.com/suke_masa/items/334e9334df8e56b9f23b)

# Date and Time API
良い資料を探し中。

# スレッド
良い資料を探し中。

# Maven
- [まだ間に合うMaven(再)入門](https://www.youtube.com/watch?v=R5gWwOwo4iQ)

# ログ
- [Javaのログ出力: 道具と考え方](https://www.slideshare.net/miyakawataku/concepts-and-tools-of-logging-in-java)
- [運用を支えるためのログを出すにはどうするか？](https://speakerdeck.com/wreulicke/yun-yong-wozhi-erutamefalseroguwochu-sunihadousuruka-number-jjug-ccc-number-ccc-m3)
14 Minesweeper Variants:Quad

[14 Minesweeper Variants](https://store.steampowered.com/app/1865060/14/) の自分用攻略メモです

当たり前ですが、[バニラのルール](https://qiita.com/izmktr/items/2bbd6450a2914bb9fbe6)も生きているので、そちらも参考にしてください。

# Quad
どの2x2マスにも必ず1個以上の爆弾が存在する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/985/89679faa-d293-e8f4-824d-e64cf13e6b85.png)
3箇所が安全とわかれば、残りの1箇所に爆弾が存在すします。

# 確定いろいろ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/985/35a6857b-5bf8-f53f-7ba8-2aea89f79891.png)
端の1はいきなり５マス確定します。旨味。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/985/53fa1885-9ea8-28ec-c2dd-7bc2a278c400.png)
中央の2も縦か横の2通りしかありません。
何れにせよ、斜めの4マスは安全なので、サクッと開けましょう。
ただし、端にある2はこのルールが通用しないので注意。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/985/bc32de9f-dd6c-1bdc-14f9-96184860eb8d.png)
上記のルールを組み合わせると、いきなり確定10マスです。幸せ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/985/f07971f3-39b1-cc71-739f-161fe9bdb8cc.png)
中央の3で、斜めに爆弾がある場合は逆側の斜めの位置が安全です。

# 連続マス

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/985/c4644e3f-3dc3-4afb-b558-d97cf40da8af.png)
安全なマスが2つ続くとその上下のいずれかに爆弾があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/985/083d8c22-23ce-357b-b5ee-4827391532ed.png)
３３パターンです。
この場合、赤と青マスのどこかに１個づつ爆弾があります。
先程のルールと組み合わせると、爆弾位置が4区画に完全に分離されます。
また、３のマスは、爆弾の対角線は安全というルールも生きていますから、かなりの数が確定します。

# 取り尽くしパターン

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/985/a7176a53-4780-b5a9-1a19-13dd11411619.png)
連続マスにより、爆弾が奪われ、残ったマスが安全になるパターンです。
上記の図の場合、連続マスルールから赤マスのいずれかに爆弾が確定するので、
残ったマスが安全になります。

# まとめ

このルールは、１，２，３のマスに非常に強い拘束力があります。
しかし、大きな数字も安全マスが数個確定することで、爆弾が確定するので、
かなりサクサク進むルールだと思います。
[Git] 動作を試す 実行例19：resetでコミットを削除する・強制的に戻す

Gitの動作を理解するために、Gitのコマンドを実際に試して、結果を見てみました。

1つの記事内で一連のGitコマンドが完結しているので、これら一連のコマンドを順に実行させて結果を見ることで、一連のGitの動作を実際に体感でき、一通り独習することが可能です。

※前回記事のリポジトリ状態からの続きになっています。
| [前回記事へ](https://qiita.com/dl_from_scratch/items/cd886f191421d0d041eb) | [目次へ：Git関連記事のまとめページ](https://qiita.com/dl_from_scratch/items/597bc28a4787a7901d21) | [次回記事へ](https://qiita.com/dl_from_scratch/items/ef2484788126226ea5cc) |
|:-:|:-:|:-:|

# 実行例

Gitで過去のコミットに一時的に戻る – Helve Tech Blog
https://helve-blog.com/posts/git/git-reset/

【Git入門】git commitを取り消したい、元に戻す方法まとめ - RAKUS Developers Blog | ラクス エンジニアブログ
https://tech-blog.rakus.co.jp/entry/20210528/git
↓
引用: 
「git reset」は「commit を取り消した」というコミット履歴が残りません。
リモートリポジトリで公開されているコミットに対して行うと、不整合が発生してしまい他のメンバーがpushできなくなります。

```
(※始めにコミット履歴状況を確認)
git log --oneline
↓
結果: 
94996a0 (HEAD -> master) message4
20bbab7 message3
00cad71 message2
4ace194 message1

(※始めに内容を確認)
type test1.txt
↓
結果: 
Sample-Added-11
Sample-Added-12
Sample-Added-13
Sample-Added-14

-----

git reset 00cad71
↓
結果: 
Unstaged changes after reset:
M       test1.txt
M       test2.txt

git log --oneline
↓
結果: 
00cad71 (HEAD -> master) message2
4ace194 message1

type test1.txt
↓
結果: 
Sample-Added-11
Sample-Added-12
Sample-Added-13
Sample-Added-14

git reset 94996a0

git log --oneline
↓
結果: 
94996a0 (HEAD -> master) message4
20bbab7 message3
00cad71 message2
4ace194 message1

-----

git reset --hard 00cad71
↓
結果: 
HEAD is now at 00cad71 message2

git log --oneline
↓
結果: 
00cad71 (HEAD -> master) message2
4ace194 message1

type test1.txt
↓
結果: 
Sample-Added-11
Sample-Added-12

git reset --hard 94996a0
↓
結果: 
HEAD is now at 94996a0 message4

git log --oneline
↓
結果: 
94996a0 (HEAD -> master) message4
20bbab7 message3
00cad71 message2
4ace194 message1

-----

git reset 00cad71
↓
結果: 
Unstaged changes after reset:
M       test1.txt
M       test2.txt

git commit -a -m "message5(after-reset)"
↓
結果: 
[master 9559e87] message5(after-reset)
 2 files changed, 3 insertions(+), 1 deletion(-)

git log --oneline
↓
結果: 
9559e87 (HEAD -> master) message5(after-reset)
00cad71 message2
4ace194 message1

git reset --hard 94996a0
↓
結果: 
HEAD is now at 94996a0 message4

git log --oneline
↓
結果: 
94996a0 (HEAD -> master) message4
20bbab7 message3
00cad71 message2
4ace194 message1

git status
↓
結果: 
On branch master
nothing to commit, working tree clean

※これで全て元の状態に戻った。
```

# 参考

Gitで過去のコミットに一時的に戻る – Helve Tech Blog
https://helve-blog.com/posts/git/git-reset/

Git で特定のコミットをマージする方法メモ - Qiita
https://qiita.com/ina_ryu/items/c0cd4a529562f2d5b13e

【Git入門】git commitを取り消したい、元に戻す方法まとめ - RAKUS Developers Blog | ラクス エンジニアブログ
https://tech-blog.rakus.co.jp/entry/20210528/git

【Git】一時的に過去のcommitに戻りたい - Qiita
https://qiita.com/yt_andante_11/items/866e45d771b28cf05bf2

# 環境

Windows 10、PortableGit-2.40.0-64-bitを使用、全てローカルPC上で実施、GitHub等は不使用。
[Git] 動作を試す 実行例18：異なるコミット位置の状態で、stashから異なる内容を戻すと壊れる

Gitの動作を理解するために、Gitのコマンドを実際に試して、結果を見てみました。

1つの記事内で一連のGitコマンドが完結しているので、これら一連のコマンドを順に実行させて結果を見ることで、一連のGitの動作を実際に体感でき、一通り独習することが可能です。

※前回記事のリポジトリ状態からの続きになっています。
| [前回記事へ](https://qiita.com/dl_from_scratch/items/17d2906d768a1ddee427) | [目次へ：Git関連記事のまとめページ](https://qiita.com/dl_from_scratch/items/597bc28a4787a7901d21) | [次回記事へ](https://qiita.com/dl_from_scratch/items/1a664d561e03b54587b9) |
|:-:|:-:|:-:|

# 実行例

```
git log --oneline
↓
結果: 
94996a0 (HEAD -> master) message4
20bbab7 message3
00cad71 message2
4ace194 message1

git checkout 00cad71
git log --oneline
↓
結果: 
00cad71 (HEAD) message2
4ace194 message1

dir /b
↓
結果: 
test1.txt
test2.txt

type test1.txt
↓
結果: 
Sample-Added-11
Sample-Added-12

git stash apply 0
↓
結果: 
HAuto-merging test1.txt
CONFLICT (content): Merge conflict in test1.txt
HEAD detached at 00cad71
Unmerged paths:
  (use "git restore --staged <file>..." to unstage)
  (use "git add <file>..." to mark resolution)
        both modified:   test1.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        test7.txt

dir /b
↓
結果: 
test1.txt
test2.txt
test7.txt

type test1.txt
↓
結果: 
Sample-Added-11
Sample-Added-12
<<<<<<< Updated upstream
=======
Sample-Added-13
Sample-Added-14
Sample-Added-15
>>>>>>> Stashed changes

※異なるコミットの所でstashから内容を戻すと、自動でマージが実施され、競合が発生。

-----

git checkout master
↓
結果: 
error: you need to resolve your current index first
test1.txt: needs merge

git stash -u -m "stash2"
↓
結果: 
test1.txt: needs merge

※マージを処置しないとstashが出来ない。

※マージを処置、内容を元に戻す。
echo Sample-Added-11 > test1.txt
echo Sample-Added-12 >> test1.txt
type test1.txt
↓
結果: 
Sample-Added-11
Sample-Added-12

git status
↓
結果: 
HEAD detached at 00cad71
Unmerged paths:
  (use "git restore --staged <file>..." to unstage)
  (use "git add <file>..." to mark resolution)
        both modified:   test1.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        test7.txt

no changes added to commit (use "git add" and/or "git commit -a")

git stash -u -m "stash2"
↓
結果: 
test1.txt: needs merge

※マージの処置を登録。
git add test1.txt

git status
↓
結果: 
HEAD detached at 00cad71
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        test7.txt

nothing added to commit but untracked files present (use "git add" to track)

git stash -u -m "stash2"
↓
結果: 
Saved working directory and index state On (no branch): stash2

※マージを処置して、stashが成功。

※今までの乱暴な操作で、煩雑になってしまった(分からなくなった)変更を全てstashに入れて、
元のクリーンな(変更なしの)状態に戻す。

-----

git status
↓
結果: 
HEAD detached at 00cad71
nothing to commit, working tree clean

git stash list
↓
結果: 
stash@{0}: On (no branch): stash2
stash@{1}: On master: stash1

git log --oneline
↓
結果: 
00cad71 (HEAD) message2
4ace194 message1

git checkout master
↓
結果: 
Previous HEAD position was 00cad71 message2
Switched to branch 'master'

git log --oneline
↓
結果: 
94996a0 (HEAD -> master) message4
20bbab7 message3
00cad71 message2
4ace194 message1

git status
↓
結果: 
On branch master
nothing to commit, working tree clean

※これで全て元の状態に戻った。
```

# 環境

Windows 10、PortableGit-2.40.0-64-bitを使用、全てローカルPC上で実施、GitHub等は不使用。
opencvをバージョン指定してインストール

# 結論
opencv4.5.1のインストールは
```
pip install opencv-python==4.5.1.48
```

# 背景
opencv4.7.0をインストールしたらcv2.findContoursの戻り値contoursがタプルになっていたため、sortが出来なくなっていた。面積順にね、ソートしたいの。

:::note info
Python環境：WinPython_3.7.7.1
:::

# （解決策1）タプルをリストに変更
```python
contours, _ = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = list(contours) #←これを挿入
contours.sort(key=lambda x: cv2.contourArea(x), reverse=True)
```
でも、昔作成したものもあるし、、、あまり変更したくない、ということで、解決策2へ。

# （解決策2）opencv4.5.1をインストールし直す。
以下を参考にしました。
https://qiita.com/TakahiroYamamoto/items/e608c8f501065c252187

ここで問題発生。
python==4.5.1の最後の2桁は何？cv2.__vesion__では4.5.1までしかわからない。どうしたらわかるの？
とりあえずopencv-python==4.5.1を入力してみると、
ERRORで選べるバージョンを教えてくれました。ありがとう。
![opencv_version.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392601/e30d95ab-a6e0-fd8b-b85e-2e1103a4c970.png)

```
pip install opencv-python==4.5.1.48
```
を入力して無事完了。

**************************************************
わからないときのエラーメッセージ頼み、でした。

:::note info
findContoursの戻り値はversion3では3つです。
:::

# 追記
普通にWinPython Command Promptで
```
pip show opencv-python
```
（または pip list, pip freeze）
でバージョン確認できました。すっきり。
(参考HP）
https://note.nkmk.me/python-package-version/
https://pg-chain.com/python-package-version
GitHub Markdownの改行と生成HTMLについて

# マークダウンの改行について

![スクリーンショット 2023-05-09 12.15.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112929/7fc900bb-ef7d-4a0f-1575-d43e74fd7e8d.png)

[試したレポジトリ](https://github.com/ykhirao/qiita/tree/master/md_sample)

## 何もしない

```mkd
test1
test2
test3
```

```html
<p dir="auto">test1 test2 test3</p>
```

## 文末に半角空白スペースを 2 つつける

```mkd
test1  
test2  
test3  
```

```html
<p dir="auto">
  test1<br />
  test2<br />
  test3
</p>
```

## 1 行空白の行を入れる

```mkd
test1

test2

test3
```

```html
<p dir="auto">test1</p>
<p dir="auto">test2</p>
<p dir="auto">test3</p>
```

## `<br>` タグを使う

```mkd
test1<br>
test2<br>
test3<br>
```

```html
<p dir="auto">
  test1<br />
  test2<br />
  test3<br />
</p>
```

## VSCode の設定メモ

formatやtrim設定で自動で文末スペースが消えるので

```json
{
  "[markdown]": {
    "editor.formatOnSave": false,
    "files.trimTrailingWhitespace": false,
  },
}

```
Filter-based forwarding（FBF）

https://qiita.com/virazoor/items/2607649857b982f3b515
## Filter-based forwarding
Filter-based forwarding（FBF）は、Junos OSにおいて、ルーティングテーブルの代わりに、パケットを特定のインタフェースやグループに転送するために使用される技術です。FBFは、特定の条件を満たすパケットに対して、ルーティングテーブルに基づくルーティングとは異なる転送パスを指定することができます。
![図1.png](https://www.juniper.net/documentation/us/en/software/junos/routing-policy/images/g043511.png)
FBFを使用する場合、通常は以下の手順に従います。

1. 転送対象のパケットを特定するためのフィルタを作成する。
2. フィルタに一致するパケットを特定のインタフェースやグループに転送するアクションを指定する。
3. ルーティングテーブルから、フィルタで特定されたパケットを除外する。

FBFを使用すると、パケットをより細かくコントロールすることができます。たとえば、特定のプロトコルやポート番号を持つパケットを特定のインタフェースに転送する、または特定のアプリケーションに関するパケットをグループに転送することができます。

JNCIA-DC試験では、FBFについての基本的な知識が求められます。例えば、FBFの設定方法や使用する際の注意点、およびFBFがどのようなシナリオで役立つかについて理解する必要があります。


## FBFの設定

FBFを設定するには、次の手順を実行します。

1. フィルタを作成する: FBFを使用するためには、転送対象のパケットを特定するためのフィルタを作成する必要があります。フィルタは、様々な条件を指定してパケットを選択できます。例えば、送信元IPアドレスや宛先IPアドレス、プロトコル、ポート番号、およびパケットサイズなどを指定することができます。

2. 転送先のインタフェースやグループを指定する: フィルタに一致するパケットを転送する先のインタフェースやグループを指定します。通常、複数の転送先を指定することができます。

3. ルーティングテーブルからフィルタされたパケットを除外する: FBFを使用する場合、フィルタで特定されたパケットをルーティングテーブルから除外する必要があります。これにより、フィルタに一致するパケットが転送先に向けられるようになります。

### 注意点
FBFを使用する際には、次のような注意点に留意する必要があります。

1. パフォーマンスへの影響: FBFはパケット処理の過程で実行されるため、大量のパケットが処理される場合には、システムのパフォーマンスに影響を与える可能性があります。そのため、FBFの設定には慎重さが求められます。

2. フィルタの正確性: FBFにおいては、適切なフィルタの設定が重要です。不正確なフィルタを設定すると、意図しないパケットが誤った転送先に向けられる可能性があります。

3. 適用範囲の確認: FBFは、通常、ルーティングテーブルに基づくルーティングとは異なる転送パスを指定するために使用されます。そのため、FBFが適用される範囲がどこまでかを確認し、不必要なパケット転送を防止する必要があります。
LaTeX数式をリアルタイムで書いて試してコピーできるWebアプリを作ってみた

Webアプリ↓

https://ca083.stars.ne.jp/latexitweb/

# 概要
$\LaTeX$や$\TeX$の数式をリアルタイムで試してコピーできるアプリが欲しいなと思っていました。
確かに、TeX Liveにはlatexitとかいうアプリがありますが、
1. レンダリングするにはボタンを押す必要があり面倒くさいこと
1. レンダリングに時間がかかること
1. クリップボードにコピーするボタンが無くて、コピーが面倒くさいこと
1. 1本しか数式を試せないこと

などの問題点があり、使い物になりません。

そこで、以上の問題点を全て解決するWebアプリを作ってみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116310/88dec6ea-758e-3ae8-8b9d-fe295bc8f1c6.png)
ライブラリはMathJaxくらいしか使っていないので、動作は速いと思います。Starfreeサーバーに載せています。

# 使い方
### 1. 数式を入力する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116310/00b617c3-8199-95dc-525c-bb4aad571bf3.png)
打っていけばその場でレンダリングされます。

### 2. 数式をコピーする
テキストエリアのすぐ上にある[COPY]ボタンを押せば、打った数式がクリップボードにコピーされます。

### 3. 数式を追加する
数式を同時に2本以上作ることができます。新しく作りたい場合は[NEW]ボタンを、派生させたい場合は[CLONE]ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116310/280bc068-b7a1-b1ac-79be-c24bdbd7730d.png)
[CLONE]は、長くて似通った数式を数本作りたい時とかに便利だと思います。

# その他
CSSフレームワークとして、[new.css](https://newcss.net/)というものを使っています。とても軽量で簡単なのでおすすめです！

https://newcss.net/
Google Workspace SMTP リレーを使用してメールを送信する


Google Workspace 経由でメールを送信する方法で、その中でも
こちらの
https://support.google.com/a/answer/176600?hl=ja
オプション 1: SMTP リレーを使用してメールを送信する（推奨）
という方法をjavaで実装しました。

参照ライブラリは
・activation.jar
・additionnal.jar
・javax.mail.jar

以下サンプルコードです。
```Main.java
/** メール環境情報**/
MailInfo mailInfo =new MailInfo();

/** メール送信プロパティ**/
Properties props = new Properties();
props.put("mail.debug", "true"); //true:ログの出力
props.put("mail.smtp.host", "smtp-relay.gmail.com"); //SMTPリレー使用のため、固定
props.put("mail.smtp.auth", "false"); //SMTP認証 false:認証しない
props.put("mail.smtp.port", "587"); //ポート番号の指定
props.put("mail.smtp.starttls.enable", "true"); //TLS接続設定
props.put("mail.smtp.ssl.trust", "smtp-relay.gmail.com");
props.put("mail.smtp.socketFactory.class","javax.net.ssl.SSLSocketFactory");
Session session = Session.getInstance(props);

// 送信元
String mail = "from@gmail.com";
// 宛先
String to = "to@gmail.com";
// Cc
String cc = "cc@gmail.com";
// Bcc
String bcc = "bcc@gmail.com";
// 件名
String subject = "こちら件名になります。";
// 本文
String text = "こちら本文になります。";

/**メール送信元・送信先を設定する**/
final javax.mail.Message msg = new MimeMessage(session);
msg.setFrom(new InternetAddress(mail));
msg.setRecipients(javax.mail.Message.RecipientType.TO, InternetAddress.parse(to));
msg.setRecipients(javax.mail.Message.RecipientType.CC, InternetAddress.parse(cc));	 msg.setRecipients(javax.mail.Message.RecipientType.BCC, InternetAddress.parse(bcc));

/**メール内容の設定**/
msg.setSubject(subject);
msg.setText(text);

/**メールの送信**/
Transport.send(msg);

```

エンジニア初心者のため、間違いなどありましたらご指摘くださいませ。
RaspberryPi起動時にPythonプログラムをターミナルから自動起動する

## RaspberryPi4でWindowsのスタートアップみたいなのをやりたい

VNCで接続して、プログラムを開いてダブルクリックして・・とやっている
毎回同じ動作をするのであれば、その作業は省きたい

+ デスクトップが表示されている状態（VNCで調整することもあるため）
+ 実行状況がわかるよう、print関数が表示されるようにしておきたい

:::note

+ RaspberryPi４
+ Pythonプログラムの保存場所　/home/pi
+ ファイル名は　main.py

:::

1. autostartフォルダと関連ファイルを作る
    ターミナルを開いて以下コマンドを入力していきます
    ```
    cd /home/pi/.config
    mkdir autostart
    cd autostart
    sudo nano setup.desktop
    ``` 
1. GNU nanoが表示されたら、以下のように入力して書き込み（Ctrl+O)します
    ``` 
    [Desktop Entry]
    Type=Application
    Name=setup（お好きな名前でOK）
    Exec=lxterminal -e sudo python3 main.py
    ``` 

1. 再起動するとプログラムが実行されてprint関数も表示されます
    ひとまず成功


すでに`autostart`フォルダが存在していて、`.desktop`もある場合はそのファイルを編集する
```
sudo nano ～～.desktop
```
一番最後に、以下の行を追加して書き込み（Ctrl+O）すればOK
```
Exec=lxterminal -e sudo python3 main.py
```
Django serializer エラーメッセージのカスタマイズ方法

# Django serializer エラーメッセージのカスタマイズ方法

```python3:serializer.py
from rest_framework import serializers
from rest_framework.validators import UniqueValidator
from django.core.validators import EmailValidator
from models.users import Users

# serializers.ModelSerializerを継承する
class Serial(serializers.ModelSerializer):
    # UniqueValidatorでUsersモデルに登録したいemailがすでに登録されたかをシリアライズする
    # EmailValidatorでemailのフォーマットをシリアライズする
    email = serializers.EmailField(validators=[UniqueValidator(queryset=Users.objects.all(), message="emailはすでに登録されました"),
                                               EmailValidator(message="フォーマットが違います")])
    
    # Usersモデルにないフィールドのシリアライズ
    password = serializers.CharField(min_length=5, required=True, allow_blank=False,
                    error_messages={'min_length':"passwordは短いすぎます。","blank": "パスワードは必須です。", "required":"パスワードは必須です。"})
    # class MetaでUsersモデルにあるフィールドをシリアライズできる
    class Meta:
        model = Users
        # シリアライズしたいフィールドを全部fieldsに追加する
        fields = ['name', 'email', 'password']
        # max_length error & not null(required&blank) error, override extra_kwargs
        extra_kwargs = {
            "name": {"error_messages":
                            {"max_length": I0101,"required": I0105, 'blank': I0105}},
            # UniqueValidatorやEmailValidatorはclass Metaでカスタマイズできないため、上記通りにserializers.EmailFieldで新しいシリアライザを作る必要がある
            "email": {"error_messages":
                            　{"max_length": "passwordは長すぎます。", "required": "emailは必須です。", 'blank': "emailは必須です。"}},
            }

```
Realworld Cursor Editorでマウスカーソルを作るときにカーソルがぼやける

# 出力を見直す

上のバーの作成からマウスカーソルの作成を押す

![マウス　ぼやける.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348724/3210b5f9-e1cb-c4d0-ae0a-e71037532899.png)

初期状態だと出力の際に色深度32bitで出力することになっているが、これを8bitで出力するようにする
32bitだと滑らかになりすぎてぼやけて見える
今は128^2で作れる(らしい)のでそこで使うのかも

## 私の環境

ドット打ち aseprite もしくは graphic gale
出力 realworld cursor editor
Jenkinsのアップグレード（2.332→2.387）でJava11なのに起動エラーになった場合の解決法

Jenkinsの自動アップグレードを実行し、
Java11に切り替えたのに、Jenkinsが起動しない…という事で困りましたが、以下の対応で解決しました。

# 環境

Amazon Linux 2 です。
Jenkinsのアップグレード（2.332.3 → 2.387.3）でハマりました。

# 解決方法

/etc/rc.d/init.d/jenkins について、以下の箇所を変更。

１．↓の部分から、末尾の「 --daemon」をカット。
```shell
PARAMS="--logfile=/var/log/jenkins/jenkins.log --webroot=/var/cache/jenkins/war --daemon"
```

２．↓の２行をまるごと削除。
  ```shell
[ -n "$JENKINS_HANDLER_MAX" ] && PARAMS="$PARAMS --handlerCountMax=$JENKINS_HANDLER_MAX"
[ -n "$JENKINS_HANDLER_IDLE" ] && PARAMS="$PARAMS --handlerCountMaxIdle=$JENKINS_HANDLER_IDLE"
```

その後、↓を実行すれば無事に起動しました。

```shell
$ sudo systemctl daemon-reload
$ sudo systemctl start jenkins
```

# それでもダメなら

それでも解決しない場合、↓のコマンドでエラーを確認すると何か分かるかもです。
```shell
$ journalctl -xe
```

（起動エラー時に、見る様にと言われる２つのコマンドのうちの２つ目です）
```shell
$ sudo systemctl start jenkins
Job for jenkins.service failed because the control process exited with error code. See "systemctl status jenkins.service" and "journalctl -xe" for details.
```


例えば、最初の「 --daemon」をカットする前には、↓の様なエラーが出ていました。

```
jenkins[32055]: Starting Jenkins Exception in thread "main" java.lang.IllegalArgumentException: Unrecognized option: --daemon
jenkins[32055]: at winstone.cmdline.CmdLineParser.parse(CmdLineParser.java:53)
jenkins[32055]: at winstone.Launcher.getArgsFromCommandLine(Launcher.java:400)
jenkins[32055]: at winstone.Launcher.main(Launcher.java:362)
jenkins[32055]: at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
jenkins[32055]: at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
jenkins[32055]: at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
jenkins[32055]: at java.base/java.lang.reflect.Method.invoke(Method.java:566)
jenkins[32055]: at executable.Main.main(Main.java:347)
```

# Jenkinsのバージョン戻しの簡便さに感謝

バックアップしておいた jenkins.war に差し替えてJenkins再起動したら、ひとまずは以前のバージョンで動くというJenkinsのバージョン戻しの簡便さに感謝する機会にもなりました。

初のQiita投稿でした。
どなたかのお役に立てば幸いです。

# 参考記事

- Jenkins 2.357から、Java11以上が必須になった件への対応方法
https://souiunogaii.hatenablog.com/entry/jenkins_java8_java11#%E5%AF%BE%E5%87%A6%E6%96%B9%E6%B3%95

- Jenkins 2.357（2022年6月28日リリース）から、Java11以上が必須というアナウンス
https://www.jenkins.io/blog/2022/06/28/require-java-11/

- 「handlerCountMax」や「handlerCountMaxIdle」を起動スクリプトから除去すると良いという stack overflow の回答
https://stackoverflow.com/questions/74250800/jenkins-wont-start-2-375-with-unrecognized-option-handlercountmax-100
Vagrantを利用してAnsibleを実行してみる


まずvagrantfile作成

```
Vagrant.configure("2") do |config|
  # Ansible実行用の仮想マシンを作成
  config.vm.define "ansible" do |ansible|
    ansible.vm.box = "generic/ubuntu2004"
    ansible.vm.network "private_network", ip: "192.168.33.10"
    ansible.vm.provision "ansible" do |ansible|
      ansible.playbook = "ansible-playbook.yml"
      ansible.inventory_path = "ansible-inventory.ini"
    end
  end

  # Rails環境構築用の仮想マシンを作成
  config.vm.define "rails" do |rails|
    rails.vm.box = "generic/ubuntu2004"
    rails.vm.network "private_network", ip: "192.168.33.11"
    rails.vm.provision "shell", path: "rails-setup.sh"
  end
end
```

仮想マシンを立ち上げる
vagrant up ansible
vagrant up rails


ansibleサーバにsshする
vagrant ssh ansible

ansible実行ファイルを作成する(試験としてapache)

inventory.ini
```inventory.ini
[rails]
192.168.33.11
```

apache.yml 
```apache.yml 
---
- name: Configure web server
  hosts: rails
  become: true
  tasks:
    - name: Install Apache web server
      apt:
        name: apache2
        state: present

    - name: Start Apache web server
      service:
        name: apache2
        state: started
```

# ansible実行

```
vagrant@ubuntu2004:~$ ansible-playbook -i i apache.yml 

PLAY [Configure web server] ********************************************************************************************************************************************************************

TASK [Gathering Facts] *************************************************************************************************************************************************************************
ok: [192.168.33.11]

TASK [Install Apache web server] ***************************************************************************************************************************************************************
changed: [192.168.33.11]

TASK [Start Apache web server] *****************************************************************************************************************************************************************
ok: [192.168.33.11]

PLAY RECAP *************************************************************************************************************************************************************************************
192.168.33.11              : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

```

## 作ったホスト（192.168.33.11）でapacheが確認できた。

![1bde7c26e6d3d210884de84c68947edd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99495/0f1b479d-381e-ec87-4681-544785abb886.png)
【メモ】テラタームマクロテンプレ

; マクロの設定
SET !REPLAYSPEED FAST
SET !ERRORIGNORE YES
SET !TIMEOUT_PAGE 60
SET !TIMEOUT_STEP 10

; SSH 接続情報
SET GatewayHost "踏み台サーバーのホスト名またはIPアドレス"
SET GatewayPort "ポート番号"
SET GatewayUsername "ユーザー名"
SET KeyFile "/path/to/private/key/file"

; ターゲットサーバーの情報
SET Host "ターゲットサーバーのホスト名またはIPアドレス"
SET Port "ポート番号"
SET Username "ユーザー名"

; SSH 接続先のコマンド
TAB T=1
URL GOTO=ssh://{{GatewayUsername}}@{{GatewayHost}}:{{GatewayPort}}
WAIT SECONDS=1
TAG POS=1 TYPE=INPUT:PASSWORD FORM=ACTION:/login/auth ATTR=NAME:password CONTENT={{!VAR1}}
WAIT SECONDS=1
URL GOTO=ssh://{{Username}}@{{Host}}:{{Port}} {{KeyFile}}

; 終了処理
TAB CLOSEALLOTHERS
neosでlogix その140

# 概要
neosでlogixやってみる。
練習問題、やってみた。

# 練習問題
乗り物を作れ。

# 方針
アンカー付きの車、見つけた。
CharacterController入れる。
Set Character Velocity使う

# 写真

![2023-05-09 01.44.55.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/367fb141-810f-c229-1372-e73aaf3f8038.jpeg)

# 俺コード

```
{a} = KeyHeld Keypad2
{b} = FireOnTrue
{CharacterController.SimulatingUser, c, _} = WriteRef LocalUser
{d} = SetCharactorVelocity c -0.5,0,1 CharacterController
```

# 手順

- Ogiをスポーン
- インスペクターを開き、コンポーネントを追加
- Physics->CharacterController
- インターフェースを取り出す
- ノードブラウザを表示
- Actions>Write Refノードをスポーン
- Users>Local Userノードをスポーン
- Input Devices>Keyboard>Key Heldノードをスポーン
- Flow>Fire On Trueノードをスポーン
- Physics>Set Character Velocityノードをスポーン
- つなぐ

# ポイント
TractionForceを1000->10

以上。
【python】フレームワーク

# フレームワークの種類

### フルスタックフレームワーク

アプリケーションの開発に必要な機能が全て揃った、大規模開発向けの多機能フレームワーク。

### マイクロフレームワーク

必要最低銀の機能のみを備えた軽量で、小規模開発向けのフレームワーク。


# pythonの代表的なフレームワーク

### django

・大規模開発向けのフルスタックフレームワーク。
・本格的なアプリケーション開発ができる。
・様々な機能を実装しやすい。

### Flask

・小中規模開発向け、マイクロフレームワーク。
・簡単で手軽なアプリケーションやAPI開発に使用する。


### FastAPI

・Flaskに似ているマイクロフレームワーク。
・モダンで高速にAPIを構築する。
・ドキュメントが充実。
・直感的い記述できる。
・デバックも簡単。

### Dash

・Flash、React、Plotlyを使って作られたマイクロフレームワーク。
・可視化に特化。
・データを可視化したダッシュボード作成などに向いている。

↓良い記事がありました。

https://qiita.com/OgawaHideyuki/items/0bd9e38de0055a5da046

### Streamlit

・フロントエンドを簡単に構築できるフレームワーク。
・機械学習、データサイエンスに向いている。
・見た目もPythonで記述。

公式

https://streamlit.io/
Reactのmemo入門




Reactの`memo`機能について、初心者にもわかりやすく解説します。

![06-12-21-getting-started-with-react-memo-blog.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987057/22380eaf-677c-2879-e6a6-23ea892df8d7.jpeg)


## 1. React.memoとは

`React.memo`は、関数コンポーネントの再レンダリングを最適化するための高階コンポーネント（Higher-Order Component, HOC）です。`React.memo`を使用することで、同じpropsが渡された場合、コンポーネントの再レンダリングをスキップしてパフォーマンスを向上させることができます。

## 2. React.memoの使い方

`React.memo`は、関数コンポーネントを引数に取り、最適化されたコンポーネントを返します。以下に、`React.memo`の基本的な使用方法を示します。

```jsx
import React from 'react';

const MyComponent = (props) => {
  return (
    <div>{props.text}</div>
  );
};

const MemoizedMyComponent = React.memo(MyComponent);

export default MemoizedMyComponent;
```

上記の例では、`MyComponent`を`React.memo`でラップして、最適化されたコンポーネント`MemoizedMyComponent`を生成しています。これにより、`MyComponent`は同じ`props`が渡された場合、再レンダリングがスキップされます。

## 3. 注意点

`React.memo`は、コンポーネントの最適化を行う際に役立ちますが、以下の点に注意してください。

1. すべてのコンポーネントで`React.memo`を使用する必要はありません。最適化が必要なコンポーネント（再レンダリングが多い、計算コストが高いなど）にのみ適用してください。
2. オブジェクトや配列などの参照型のデータを`props`として渡す場合、新しい参照が生成されるたびに再レンダリングが行われてしまいます。このような場合、`React.memo`の効果が十分に発揮されないことがあります。

## まとめ

`React.memo`は、関数コンポーネントの再レンダリングを最適化するための高階コンポーネントです。同じ`props`が渡された場合、コンポーネントの再レンダリングをスキップし、パフォーマンスを向上させることができます。ただし、すべてのコンポーネントに適用する必要はなく、最適化が必要なコンポーネントにだけ適用しましょう。また、参照型のデータを`props`として渡す場合は、効果が十分に発揮されないことがある!
【terraform】tfstateが既に存在していた場合の対処

## 概要
`terraform import`時に既に存在していると怒られた時の対処法を備忘録として記す

## エラー
```
Error: Resource already managed by Terraform

Terraform is already managing a remote object for
module.network.aws_security_group.XXX. To import to this
address you must first remove the existing object from the state.
```

## 対処法
### ①バックアップを取る
対象を削除した後、問題が起きてからでは怖いのでバックアップを取得する
```
$ terraform state pull > tfstate.bk
```

### ②stateのlistを参照する　or　①で作成したバックアップファイルを参照する
```
$ terraform state list
```

### ③対象の中身も確認する
```
$ terraform state show module.XXX.XXX
```

### ④stateに記載されている対象を削除
```
$ terraform state rm module.XXX.XXX
```

### ⑤import実行
```
$ terraform import module.XXX.XXX
module.network.aws_security_group.XXX: Importing from ID "sg-XXX"...
module.network.aws_security_group.XXX: Import prepared!
  Prepared aws_security_group for import
module.network.aws_security_group.XXX: Refreshing state... [id=sg-XXX]

Import successful!

The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.
```

以上で解決！
【PHP】html要素から<h2>のみを削除する 正規表現で置換を行う preg_replaceを使う

# コード
```PHP
<?php
$contents = '<h1>aaa</h1><h2 class="">bbb</h2><h3>ccc</h3>';
echo preg_replace('/<h2.*>(.*?)<\/h2>/','', $contents);
```

# 結果
```javascript
<h1>aaa</h1><h3>ccc</h3>
```
【Python】argparseに渡された引数をjsonで出力したい！

## やりたいこと

```args = parser.argparse()``` で渡された引数をjson形式で保存する。

## やりかた

以下 [ [参考記事](https://qiita.com/melt_fax/items/3147f3403e2b809692de) ] より引用
```python:main.py
import json
import argparse

parser = argparse.ArgumentParser()
parser.add_argument("--param1", type=str, default="test")
parser.add_argument("--param2", type=int, default=100)
parser.add_argument("--param3", type=float, nargs="+", default=[0.1, 0.2, 0.3])
args = parser.parse_args()

with open("./params.json", mode="w") as f:
    json.dump(args.__dict__, f, indent=4)
```

```json:out.json
{
    "param1": "test",
    "param2": 100,
    "param3": [
        0.1,
        0.2,
        0.3
    ]
}
```

基本的には上記でできる。

しかし、json出力時にserializeできない型が含まれているとエラーを吐く。

例：TypeError: Object of type PosixPath is not JSON serializable

上記の例は引数にserializeできないPosixPath型が含まれていたために起きたもの。

## TypeError: Object of type xxxx is not JSON serializable の対処法

いずれかのどれかで対処可能
1. objectをstr型に変換する
1. dump時にdefaultまたはclsを指定することでエンコード方式を指定する

前者はそのまんまです。試してはいないですができるはず。

後者のdump時の指定は以下のように行えます。

今回はPosixPath型への対応策例を記載しますが、ほかの方でも同様に行うことができます。
[ [参考記事](https://zenn.dev/alivelimb/articles/0f3f8d61d91d57) ]

### dump時にdefaultで指定する方法

```python
from pathlib import Path

def json_encode(obj):
    if isinstance(obj, Path):
        return obj.as_posix()

with open("dumped.json", "w") as f:
    json.dump(data, f, default=json_encode)
```
dumpできないobjectが来たらdumpできるように変換したものに変換する関数を準備すればOK!という話です。

### dump時にclsで指定する方法

```python
from pathlib import Path

class JSONEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, Path):
            return obj.as_posix()

with open("dumped.json", "w") as f:
    json.dump(data, f, cls=JSONEncoder)
```
dumpできないobjectが来たらdumpできるように変換したものに変換する関数を持ったクラスを準備すればOK!という話です。

## まとめ

jsonで出力するくらいすぐできるやろーとなめてましたが、少しめんどくさかったのでメモを残しました。
いつか誰かの役に立つと嬉しいです。
Golangのポインタのお勉強

# ポインタで挫折した経験
はじめまして、情報系の大学に通う大学3年生です。
大学に入り、初めてプログラミングを始めた私ですが、大学の授業で触れるプログラミング言語はC言語でした。C言語の一番の壁、それは**ポインタ**だと思います。
かくいう私もポインタでC言語を挫折した人間です。それからC言語からは逃げてしまし、Python,PHP,Django,JavaScriptと様々な言語やフレームワークを勉強してきて、最近Goを始めた次第です。

ここでGoの文法の勉強を進めていく中でポインタに遭遇しました。忌々しい記憶と戦いながら、サンプルコードを眺めていると「あれ？めっちゃ簡単じゃね？」と思いました。(笑)
今まで学習してきたことが少しだけでも身についているのかな？と感じてうれしくなったので記事に残すことにしました。

:::note warn
ポインタが以前よりも分かるようになっただけで完全には理解できておりません。
なにか間違った記述等ありましたら、教えていただけると幸いです。
:::

# そもそもポインタって？
>ポインタとは **「別の変数のアドレスを格納している変数」** のことです。
また、アドレスとは **「アドレス空間における記憶場所」** を示す通し番号のことです。

この説明のせいで私は挫折したのです。(笑)

難しいことばで説明されている(少なくとも当時はそう感じた)ため、理解困難でした。
それでは、僕がどのようにポインタを理解したのか以下にコード例と自分なりのコメントを残していますので、ぜひポインタがわからない方は参考にしてください。
# コード例
```go
package main

import "fmt"

func main() {
	i, j := 42, 2701

	p := &i         // iのポインタ(住所)をpに代入
	fmt.Println(*p) // pに格納されているポインタを通してiを出力
	fmt.Println(p)  // pに格納されているポインタ自体(iの住所)を出力
	*p = 21         // pのポインタを通してiに21を代入
	fmt.Println(i)  // iを出力(pを通してiが変更された)

	p = &j         // jのポインタ(住所)をpに代入
	*p = *p / 37   // pのポインタを通してjの値を変更
	fmt.Println(j) // jを出力
}

```

```
//出力結果
42
0xc00010a000
21
73
```

ポインタが指しているアドレスを **「住所」** と考えると自分は理解がしやすかったです。
なんとなくの理解で「&を付けるとその変数の住所を表せるんだな。」「*を付けると、その住所に入ってる変数が表せるんだな」程度の認識で最初は全く構わないかと思います。
(分からなくてもとにかく進む！まずコードを書いてみる！ことがプログラミングにおいてはとても大事だと思っています。)

# ポインタの利点
ポインタが少し理解できたのはいいが、何のために使うのか？
ずばり、 **メモリにアクセスできるようになること** です。
ポインタによって変数に対する新しい参照方法を可能としているのです。これによって
* 関数をまたいで変数を利用できるようになる(ローカル変数にアクセス可能)
* メモリの節約ができる

などがあげられます。

# 最後に
ポインタは初学者にとって非常に高い壁かと思われますが、遠回りをしてもいいので様々な言語を勉強してみたり、資格を勉強してみたりすることで以前理解できなかったことが意外と理解できたりするものです。
自分自身今回ポインタが少し理解できたことで、学習において無駄なことなんて一つもないなと感じましたし、より一層さまざまな領域の技術を吸収していこうと感じました。
今後はポインタを利用したプログラムを自分自身で最大限活用できるところまで理解できるように勉強に励もうと思う！
【React】バージョン差分ざっくりまとめ【Material-UI】

## バージョン差分まとめ
React+Material-UIでプロジェクトを作成する際、バージョンによってうまくいかないことがあるためまとめます。
この記事を参考にする場合はくれぐれも作成日に注意してください。

## 言及しているもの
[・React](#React)
[・create-react-app](#create-react-app)
[・Material-UI](#Material-UI)
[・ReactRouter](#ReactRouter)


## React
まずはReact本体のバージョンについてです。
後述しますがReactのバージョンによって、対応できるライブラリのバージョンに制限がありますので
どちらかと言えば、使いたいライブラリのバージョンに応じてReact本体のバージョンを選ぶことが多いかもしれません。

リリースノートはこちら

https://github.com/facebook/react/releases

React本体のバージョンによる主な差分は
index.tsx等で皆さん書くであろうrenderの記述、程度だと思います。

こちらの記事にもまとまっていますのでご一読ください。

https://chaika.hatenablog.com/entry/2022/05/24/083000

## create-react-app
create-react-appコマンドにもバージョンがあり
どのバージョンのコマンドを使うかで、使用されるReactライブラリ本体のバージョンも変わります。
以下はcreate-react-appバージョン`5.0.0`のリリースノート

https://github.com/facebook/create-react-app/releases/tag/v5.0.0

またv5の場合、使用(作成)されるReactバージョンは`React18`になりますので
18ではMaterial-UI v4は使用できません。v5ならいけます。
🌾[Material-UIのバージョン](#Material-UI)も本記事でまとめてます。

---
Reactのバージョンを変えたい場合、2通りの方法があります。
1️⃣create-react-appコマンドのバージョンを変更する
2️⃣作成したpackage.json上のReactライブラリバージョンを編集し、任意のバージョンのReact`npm install`する

しかしながら、1️⃣は現在(`2023/05/01`)実現できないかと思われます。
以下の記事に詳しくまとめられていますが、どうやらcreate-react-appコマンドが最新版しか許容しないことや
キャッシュ削除等の策もnpxコマンドのバグによって実現できないことが原因です。

https://qiita.com/FumioNonaka/items/076af56213afc7e29853

よって、私もやってみましたが無理そうなので、2️⃣で行きます。
以下に詳しくまとまっていますが
create-react-app最新版を実行後に、package.jsonを編集して`npm install`するだけですね。

https://zenn.dev/fuuukeee3/articles/9cd87e664a87e4

## Material-UI
v4とv5の間に大きな溝があります。
綺麗にまとめてくださいってる方の記事を貼っておきます。公式は[こちら](https://mui.com/core/)

v4

https://zenn.dev/yumemi_inc/articles/2020-09-24-react-material-ui?redirected=1

v5

https://zenn.dev/yumemi_inc/articles/2021-09-26-material-ui-v5

また、v5からブランド名が`Material-UI`から`MUI`に変わりました。よって
この記事のタグにも一応どっちもつけてみましたし、なにより
npm installするものが変わり、ソース中でのimport文も変わってしまいます。

```v4.
npm install @material-ui/core @material-ui/icons
```
```v5だとこんな感じがおすすめされている.
npm install @mui/lab @mui/material @emotion/react @emotion/styled
npm install @mui/icons-material
```
🌾[公式](https://mui.com/)の`Get Started`を参考にしています


## ReactRouter
https://reactrouter.com/en/main

SPAしたければ使うんじゃないでしょうか。
```sh
npm install react-router-dom
```
ReactRouterのv5とv6で壁があります。

https://zenn.dev/naoki0722/articles/552258f70f69fa

https://qiita.com/Mai_HB/items/91c6660179b904684d75

まぁこちらも書き方がちょっと変わるだけなので、あまり問題なさそうですね。

## その他
以下を見ましたが、特にバージョン差分で困りませんでしたので割愛します。
ついでにチュートリアル系記事まとめましたのでどうぞ。
axios
react-cookie
date-fns
i18next

---
axios

https://qiita.com/ksh-fthr/items/2daaaf3a15c4c11956e9

react-cookie

https://dev.classmethod.jp/articles/managing-cookies-with-react-cookie/

date-fns

https://qiita.com/suin/items/296740d22624b530f93a

i18next

https://qiita.com/sekitaka_1214/items/8e9dcc30679e1f6e8a14
python-slack-sdkの`files_upload_v2`メソッドの`initial_comment`に、`<url|text>`形式の文字列を渡してもリンクにならない

# 環境
* Python 3.11.2
* slack-sdk 3.20.1
* 確認した日: 2023/05/09

# やりたいこと
Slack APIを使って、テキストにリンクを付けたいです。


# 試したこと

以下の形式にすれば、リンクになるようです。

```
<http://www.example.com|This message *is* a link>
```

https://api.slack.com/reference/surfaces/formatting#linking-urls

`chat.postMessage`と`files.upload` APIで、メッセージがリンク形式になるかを確認しました。

## `chat.postMessage` APIの`text`フィールド

>text:
>The formatted text of the message to be published. If blocks are included, this will become the fallback text used in notifications.

https://api.slack.com/methods/chat.postMessage


```
In [155]: client=WebClient(os.environ["SLACK_TOKEN"])
In [157]: message=f"<https://qiita.com/|QIITA>"
In [158]: client.chat_postMessage(channel="CDKRW33RA", text=message)
Out[158]: <slack_sdk.web.slack_response.SlackResponse at 0x7f65c8a149d0>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37903/b6428e6b-6f93-66de-da69-065fcfc89ffc.png)

テキストはリンクになりました。

## `files.upload` APIの`initial_comment`フィールド

```
In [171]: client.files_upload_v2(channel=channel_id, file="README.md", initial_comment=message)
Out[171]: <slack_sdk.web.slack_response.SlackResponse at 0x7f65c8d43250>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37903/4ab2c51e-07cd-6229-f08f-c61d398e9bfc.png)


テキストはリンクにならず、そのままの文字列が表示されました。

`client.files_upload_v2`メソッドの中で何か変換処理をかけているかもしれないと思い、HTTPリクエストのログを確認しましたが、そのままの文字列を渡していました。

```
DEBUG    : 2023-05-09 01:09:25,805 : slack_sdk.web.base_client : Sending a request - url: https://www.slack.com/api/files.upload, query_params: {}, body_params: {'channel': 'CDKRW33RA', 'filename': 'empty.txt', 'initial_comment': '<https://qiita.com/|QIITA>'}, files: {'file': 'empty.txt'}, ...
```

### `files_upload`メソッドで試す
`files_upload`メソッドならば、メッセージはリンクになります。
@seratch さんのコメントで教えてもらった回避策です。


```
In [184]: client.files_upload(channels=channel_id, file="empty.txt", initial_comment=message)
/home/vagrant/.pyenv/versions/3.11.2/lib/python3.11/site-packages/slack_sdk/web/internal_utils.py:450: UserWarning: client.files_upload() may cause some issues like timeouts for relatively large files. Our latest recommendation is to use client.files_upload_v2(), which is mostly compatible and much stabler, instead.
  warnings.warn(message)
```

:::note warn
引数は`channel`でなく`channels`です。
:::

# 分からないこと
~~ファイルをアップロード時に投稿するメッセージに、リンクを含める方法が分かりませんでした。
Slackアプリでは実現できるので、技術的には可能だと思うのですが。。。~~

@seratch さんに教えていただきました。
https://qiita.com/yuji38kwmt/items/67e386750f5950d86e4c#comment-3c22a3e7fc249b3a9b18