OmniAICreator/Qiita-1.07M huggingface dataset:
RubyでFizzBuzzプログラムを作成する

Rubyのアルゴリズムについて復習しています。

学習時によく取り上げられるFizz_Buzzプログラムについて、備忘録的に記述していきます。

# 内容
3の倍数の場合は数の代わりに"Fizz"を出力する
5の倍数の場合は数の代わりに"Buzz"を出力する
3と5の公倍数の場合は数の代わりに"FizzBuzz"を出力する

# コード
```
arg = ARGV[0].to_i

1.upto(arg) do |num|
  if num % 15 == 0
    p "FizzBuzz!"
  elsif num % 5 == 0
    p "Buzz!"
  elsif num % 3 == 0
    p "Fizz!"
  else
    p num
  end
end

```


# メモ
- upto メソッド
    - 指定した開始数から最大数まで1つずつ増加しながら繰り返しを行いたいときに使用します。
    - to_iメソッドを用いる事で、integer型に変換させています。
- ARGV[0]
   - 引数の配列を用いることができます。
   - `$ ruby ファイル名 10`などとする事で、10という数字が引数をファイルの中身のロジックに渡す事ができます。
   - 今回では、渡ってきた引数の値を変数`arg`に代入しています。


# 参考サイト
- timesメソッドやuptoメソッドを使って指定した回数だけ繰り返す
https://www.javadrive.jp/ruby/for/index6.html

- RubyでFizzBuzz問題を解いてみよう
https://zenn.dev/kanazawa/articles/a374c3ddc7e717

- Rubyでargvを使う方法【初心者向け】
https://magazine.techacademy.jp/magazine/18730
cscの作法 その383

# 概要
cscの作法、調べてみた。
練習問題、やってみた。

# 練習問題
opencvsharpでaviファイルを作れ。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/160c8c3c-8bb7-1852-75f8-92ba2eb76fef.png)

# サンプルコード

```
using System;
using OpenCvSharp;

namespace App
{
	internal class Program {
		static void Main(string[] args) {
			Mat src = new Mat(240, 320, MatType.CV_8UC3, new Scalar(0, 0, 255));
			VideoWriter vw = new VideoWriter("a.avi", FourCC.XVID, 10, new Size(320, 240));
			vw.Write(src);
			vw.Write(src);
			vw.Write(src);
			vw.Dispose();
		}
	}
}

```


以上。
linux から　android タブレットへのftp

## 自分の　アンドロイドタブレットは　古い（android version 9 ）ので　USBメモリとの接続が　駄目よダメダメ
https://www.youtube.com/watch?v=FXYwlbXKDA0

##android　　タブレットでの準備です

![Photo Marker_20230701_084149.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/aa9c2aae-0b7a-c3ec-59d5-0eb46c848c27.jpeg)


![Photo Marker_20230701_084739.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/23a142c1-752f-bf91-3cb5-bbd9011c80bf.jpeg)



##そしたら　linux で

$ lftp 192.168.68.60:2221
lftp 192.168.68.60:~> ls
drwx------   3 user group            0 Oct 13  2021 Android
drwx------   3 user group            0 Jun 27 03:48 DCIM
drwx------   3 user group            0 Jul  1 05:44 bluetooth
lftp 192.168.68.60:/> 　put hogegoge.mp4

で　linuxのファイルhogegoge.mp4を　android　スマホに 運べます
Vue.jsを書くための準備をまとめる

## 1. Vue CLIの導入
Vue CLIを入れてない場合は以下でインストール

```
npm install -g @vue/cli
```

## 2. Vue.jsプロジェクトを作成
任意のプロジェクトを作成します。
※「my-project」は任意の名前です。
```
vue create my-project
```

## 3. Vue.jsプロジェクトを起動

プロジェクトに移動
```
cd my-project
```

プロジェクトを起動
```
npm run serve
```

## おまけ： BootStrapを使えるようにする
Bootstrapをインストール
```
// yarn
yarn add bootstrap-vue

// npm
npm install bootstrap-vue
```

次にsrc/main.jsに下記の記述を追加します。
```
import Vue from 'vue'
import App from './App.vue'
+ import 'bootstrap/dist/css/bootstrap.css' 　　　　　　　　　// 追加
+ import 'bootstrap-vue/dist/bootstrap-vue.css' // 追加
Vue.config.productionTip = false
```
Web Speech APIが便利すぎたので使い道を考える

# はじめに
技術的な内容については[偉大なる先人](https://qiita.com/hmmrjn/items/4b77a86030ed0071f548)が改めてこちらで書く必要がない程に詳しくまとめてくれているので、ここでは「この便利な技術をいかにして活用するか」について、自分なりの考えを述べていきたいと思います。

# 音声認識技術のこれまで
私自身が音声認識技術に触れたのは4年くらい前、仕事でAIを使ったテキスト化サービスに関わった時のことでした。
日本語しか使えない人間なのでよく分からないのですが、日本語の音声認識は英語等と比べて難しいと言われており、また日本という市場がそこまで重要視されていなかったのか、当時はAWSの音声テキスト化も日本語に対応していない等、かなーり後回しにされていた印象があります。
それからあらゆるクラウドベンダーがサービスを開始し、日本語対応し、精度についてもじわじわと上がってきています。
それまでは従量課金が多かったのですが、無料で使える音声認識が誕生したことは、「発展してるなー」という印象です。

# 音声認識の向き不向き
## 向き
PCやスマホに話しかける感覚で「ゆっくりはっきり」、更に一般的な言葉で話すとかなり高い精度で変換してくれるので、音声認識は最も適しているのは「特定の言葉をコマンドとして使う」ことだと個人的には考えています。

## 不向き
一方で、通話やライブ配信みたいな「人間に普通に話しかける感覚」で話したものを変換すると、中々いい結果が得られないものです。

音質や話し方にもよりますが、1～2年前の情報では音声認識の精度は[CER](https://qiita.com/Kchan/items/7bba1f066234ba24898b)で0.2以下（文字単位で80%以上正解）であれば優秀と言われていました。最近はもうちょい上がってるかもしれませんが、飛躍的な向上は現行のAIの考え方のままでは難しいのかなと思っています。

後、一般的でない固有名詞は「似た一般的な言葉」に誤変換される傾向にあります。これは人間が「知らない単語を聞いたときに似た知っている言葉と勘違いする」のと似ていますね。
多くの音声認識システムには、この欠点を補うために「辞書登録」という特定の単語や語彙、文法などを登録する機能があるのですが、単語登録しても「似た音の一般的な言葉」に結果が引っ張られてしまったり、最近は各社こういったチューニングへの依存を低下させることで、「チューニングしなくても使える音声認識」を目指している傾向にあります。

以上のことから、会話の文字起こしや文章の生成（特に証拠の記録のような「間違いが許されないもの」）、タイピングの代替手段に使えるレベルには至っていないと考えています。

# 以上のことから
Web系のエンジニアとしては、「進め」でブラウザバックをしたり、画面名を言うことで特定の画面に遷移したり（認識しやすい名前にする必要はありますが）、「動け」「止まれ」でオーディオやビデオを再生・停止したりすることで、手を使わずにPCを操作するような方法が現実的かと考えています。

ポエムだけで終わるのはアレなので、最後に上記を元に声でブラウザ上のオーディオやビデオを動かすコードを作成してみます。

```speech_media_control.js
<script>
  SpeechRecognition = webkitSpeechRecognition || SpeechRecognition;
  const recognition = new SpeechRecognition();
  recognition.lang = 'ja-JP';
  recognition.continuous = true;
  
  recognition.onresult = (event) => {
    // 最新の変換結果を取得
    var text = event.results[event.results.length-1][0].transcript;
    console.log(text);
    
    // 対象のvideoまたはaudioエレメントを取得
    var media = null;
    if(document.getElementsByTagName("audio").length > 0){
      media = document.getElementsByTagName("audio")[0];
    }
    if(document.getElementsByTagName("video").length > 0){
      media = document.getElementsByTagName("video")[0];
    }
    if(!media){
      return;
    }

    // 「進め」「戻れ」は数字が指定されていればその秒数、なければ10動かす
    var offset = parseInt(text) ? parseInt(text) : 10;
    if(text.indexOf('進め') !== -1){
      media.currentTime = media.currentTime + offset;
    }else if(text.indexOf('戻れ') !== -1){
      media.currentTime = media.currentTime - offset;
    }else if(text.indexOf('止まれ') !== -1){
      media.pause();
    }else if(text.indexOf('動け') !== -1){
      // autoplayのないaudio/videoタグだと動かないかも
      media.play();
    }
  }
  recognition.onend = (event) => {
    // 数分で勝手に停止する。回避方法が見つからなかったので、自動で再開させる
    console.log(event);
    recognition.start();
  }
  
  recognition.start();
</script>
```
GraphQLスキーマを外部ファイルとして読み込む方法

# はじめに
バックエンドの開発中に`src/server.ts`に記述されたスキーマを切り分けたいと考え、`schema.graphql`にスキーマを移したが、既存の`path`や`fs`で読み込むのは釈然としなかったため、その方法を調べたり、実装していたら、案外と時間を取られたので記事にしたいと思います。

# ライブラリの導入
まずは、`.graphql`を読み込むために、以下のライブラリを導入します。

```terminal
yarn add @graphql-tools/graphql-file-loader @graphql-tools/load @graphql-tools/schema
```

# スキーマファイルに切り分け
次にスキーマを`.graphql`に切り分けます。
```graphql:scheme.graphql
type Query {
  info: String!
  feed: [Link]!
}

type Mutation {
  post(url: String!, description: String!): Link!
}

type Link {
  id: ID!
  description: String!
  url: String!
}
```

:::note info
server.tsの記述
:::

```typescript:server.ts
import { ApolloServer } from '@apollo/server'
import { startStandaloneServer } from '@apollo/server/standalone'
import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader'
import { loadSchemaSync } from '@graphql-tools/load'
import { addResolversToSchema } from '@graphql-tools/schema'
import { join } from 'path'

import type { Link } from './types/Link'

const links: Link[] = []

const schema = loadSchemaSync(join(__dirname, './schema.graphql'), {
  loaders: [new GraphQLFileLoader()],
})

// リゾルバー関数
const resolvers = {
  Query: {
    info: () => 'HackerNewsクローン',
    feed: () => links,
  },

  Mutation: {
    post: async (_: unknown, args: { description: string; url: string }) => {
      let idCount = links.length

      const link = {
        id: `link-${idCount++}`,
        description: args.description,
        url: args.url,
      }

      links.push(link)

      return link
    },
  },
}

const schemaWithResolvers = addResolversToSchema({ schema, resolvers })
const server = new ApolloServer({
  schema: schemaWithResolvers,
})

const startServer = async () => {
  const { url } = await startStandaloneServer(server, {
    listen: { port: 4000 },
  })
  console.log(`🚀  Server ready at: ${url}`)
}

startServer()
```

まず`loadSchemaSync`を使用して`shcema.graphql`を読み込み、GraphQLスキーマを同期的にロードします。
```typescript
const schema = loadSchemaSync(join(__dirname, './schema.graphql'), {
  loaders: [new GraphQLFileLoader()],
})
```

続いて`addResolversToSchema`を使用してスキーマにリゾルバーを追加します。
```typescript
const schemaWithResolvers = addResolversToSchema({ schema, resolvers })
```

最後に`ApolloServer`インスタンスにスキーマとリゾルバーを渡すことで、外部ファイルのGraphQLスキーマを読み込み、サーバーに渡し、起動することができます。

```typescript
const server = new ApolloServer({
  schema: schemaWithResolvers,
})
```

# 参考文献
> [GraphQLスキーマを外部ファイル化する](https://zenn.dev/eringiv3/books/a85174531fd56a/viewer/a8fab6)
Qiita Engineering Festa 投稿統計(自己関連) 20230701

Qiita Engineer Festa 2023〜私しか得しないニッチな技術でLT〜

https://increments.connpass.com/event/285824/

Qiita Engineering Festa 投稿統計

https://qiita.com/kaizen_nagoya/items/9ac7af3a405fe6e7ba4d

Qiita Engineer Festa 2023〜私しか得しないニッチな技術でLT〜 予習編

https://qiita.com/kaizen_nagoya/items/8dcba90a52a10880ec3b

「Qiita Engineer Festa 2023〜私しか得しないニッチな技術でLT〜」題材アンケート

https://qiita.com/kaizen_nagoya/items/97a527f63c94ba305fe4

Qiita Engineer Festa 2023〜私しか得しないニッチな技術でLT〜　資料作成記録

https://qiita.com/kaizen_nagoya/items/ac071142bcfde9e41c33

Qiita Engineer Festa 2023〜私しか得しないニッチな技術でLT〜　参加者一覧

https://qiita.com/kaizen_nagoya/items/41b196588bb4f888afbb
# 企画統計（自己参加分）

Qiita Engineering Festa に投稿した企画ごとの統計と、投稿した自己記事の統計。

goods/articlesが大きい順
a:articles
g:goods
p:people

右の３列は20230701減殺。
n/o 20230701現在/20230626比率


|title/url|a|g|p|g/a|an|gn|pn|n/o|
|:--|:--|:--|:--|:--|:--|:--|:--|:--|
|この記事誰得？ 私しか得しないニッチな技術で記事投稿！ https://qiita.com/official-events/5d4f04cf2ba0cdbc8821|118|2395|141|20.29|173|3111|190|1.46
|エンジニアキャリアについてあなたの考えをシェアしよう！ https://qiita.com/official-events/0d4c7ac216324bd6a3b9|34|613|64|18.02|89|3811|77|2.61
|新規開発や新技術の検証、導入にまつわる記事を投稿しよう！https://qiita.com/official-events/0cc35c4799f72609b7ec|63|1056|90|16.76|105|3488|112|1.66
|お題は不問！Qiita Engineer Festa 2023で記事投稿！https://qiita.com/official-events/4f3daca63fb78f16df0b|504|6896|381|13.68|674|13353|478|1.33


 ＜この記事は個人の過去の経験に基づく個人の感想です。現在所属する組織、業務とは関係がありません。＞

# 文書履歴(document history)
ver. 0.01初稿　　20230701

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

いいね　💚、フォローをお願いします。

####  Thank you very much for reading to the last sentence.

Please press the like icon 💚　and follow me for your happy life.
Azure Pipelines でブランチ別にパイプライン YAML を外出しにしてみた

例えば main ブランチと develop ブランチがあったとします。ブランチ別に CI で実行する内容を変えたい場合、条件分岐して記述すると思います。そうするとパイプライン YAML 内のインデント階層が深くなったり、単純に行数が長くなったり段々と扱いづらくなります。そこで今回は、ブランチ別にパイプライン YAML を外出しにする検証を行ってみました。

## 検証用パイプライン YAML の準備

### Azure Pipelines から呼び出される YAML

```yaml:azure-pipelines.yml
trigger:
  - main
  - develop

pool:
  vmImage: ubuntu-latest

steps:
- script: |
    echo common
  displayName: 'common step'
- ${{ if eq(variables['Build.SourceBranchName'], 'main') }}:
  - template: azure-pipelines-main.yml
- ${{ if eq(variables['Build.SourceBranchName'], 'develop') }}:
  - template: azure-pipelines-develop.yml
```

### main ブランチ用 YAML

```yaml:azure-pipelines-main.yml
steps:
- script: |
    echo main
  displayName: 'main step'
```

### develop ブランチ用 YAML

```yaml:azure-pipelines-develop.yml
steps:
- script: |
    echo develop
  displayName: 'develop step'
```

## 検証結果

main と develop ブランチのパイプライン実行履歴
![azure-pipelines-template-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675885/61917b4d-e78f-3904-8206-edc6fce9af96.png)

common step と main step の実行を確認
![azure-pipelines-template-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675885/6c84de42-f8d5-3c37-1f49-5e1f3e6906d6.png)

common step と develop step の実行を確認
![azure-pipelines-template-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675885/65a555a2-93d8-1d5a-d71a-a93eb951bb2d.png)

## 参考

https://learn.microsoft.com/ja-jp/azure/devops/pipelines/process/expressions?view=azure-devops#conditionally-assign-a-variable
コマンドプロンプトでEC2にscpコマンドでファイルをアップロードできるか試してみた

# はじめに
私のPCの不調ですがWindows端末ですがWSLをインストールしましたが開けません。
諦めてコマンドプロンプトが使えないか試してみました。

前回も以下の記事でコマンドプロンプトの検証をしました。
https://qiita.com/gama1234/items/234dbbbb2c167c0ba007

# 手順
## AWSにEC2を1台立てました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/3be334b3-e3e4-deb1-9bdf-4ca8ef960379.png)

手順は以下を参考にしてください
https://qiita.com/gama1234/items/10e7ab9d2c1e3c9367b3

## SCPコマンドを実行しました。

ローカル端末にあるtest_bash.shスクリプトをEC2の/tmpフォルダ配下にコピーしました。

100%と表示されたため、アップロードが正常に完了しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/cddc31b4-e03f-3715-dbdd-413651222c3d.png)

## EC2にログインしてtest_bash.shスクリプトのアップロードを確認しました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/73ef5a0f-739e-fe61-6725-8b7c53490c4d.png)

## EC2にアップロードしたtest_bash.shスクリプトの権限を変更
コマンドプロンプトにlinuxコマンドが使えることを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/98afdbd4-9641-12f6-01ef-b723b348736b.png)


## test_bash.shを実行してみた
赤枠のエラーメッセージが出ました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/d96703bd-98a1-dec5-412d-2d043a86de7a.png)


chatGPTで検索
このエラーメッセージは、シェルがコマンドを理解できない特殊な文字（`\r`）を含んでいることを示しています。 `\r`はキャリッジリターン（CR）文字であり、一般的にWindowsやDOSこのエラーが表示されるのは、おそらくテキストファイルがWindows形式（CRLF改行）で作成され、Unix形式（LF改行）が必要なシェルで実行されているためです。Unix形式の変更行文字（LF）は`\n`です。 この問題を解決するには、以下のいくつかの方法があります。 1. ファイルをUnix形式に変換する: `dos2unix`コマンドを使用してテキストファイルを Unix 形式に変換します。例、次のコマンドを実行します： `` dos2unix ファイル名 `` 2.


## test_bash.shスクリプトをWindowsからlinux改行コードに変換

コマンドは以下のサイトを参考にしました。
https://osksn2.hep.sci.osaka-u.ac.jp/~taku/osx/crlf.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/0fffb785-6136-fd4b-e1e9-b108c53ee838.png)

スクリプトが動作してTEST文字が表示されることを確認した
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/bdd3607d-86af-ec9d-c270-9a7e66512a7e.png)


## コマンドプロンプトの操作ログ出力方法

TeraTermの様なターミナルでログ出力設定はなさそうです。

以下のサイトを大変参考になりました。
https://aprico-media.com/posts/8738

# まとめ
コマンドプロンプトでもEC2にSSH接続出来て且つSCPコマンドが使えることが分かりました。
コマンドプロンプトはTeraTeramの様にターミナルで設定して操作ログを出力する設定はなさそうに見えました。
EC2にssh接続出来たら通常通りコマンドプロンプトのターミナルでもlinuxコマンドが使用出来ることを確認しました。

仮にコマンドプロンプトを利用するケースとしては、本番作業前にサーバーに使用するシェルスクリプトをアップロードしたいのような事前準備のような少ない作業する分には向いています。

作業ログを出力できないため、本番環境での沢山コマンドを実行する作業では適さないと個人的には考えます。
MySQLでJSONを使う

<p>alphavantage APIとか使って、以下のような株アプリを作ってる</p>

https://stonehills.tokyo/financer/
<!-- /wp:heading -->


<!-- wp:paragraph -->
<p>MySQLやMaria DBでも、JSON を使える</p>
これは、Alphavantege という Finance APIをMaria DBにinsert し、select する例です。
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2 class="wp-block-heading">create tableでJSON型を指定</h2>
<!-- /wp:heading -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">CREATE TABLE AlphaVantage (
   t_date date NOT NULL,
   ticker VARCHAR(255) NOT NULL,
   income_stmt <strong>JSON</strong>,
   CHECK (<strong>JSON_VALID</strong>(income_stmt)),
   balance <strong>JSON</strong>,
   CHECK (<strong>JSON_VALID</strong>(balance)),
   PRIMARY KEY (t_date,ticker)
);</pre>
<!-- /wp:preformatted -->

<!-- wp:heading -->
<h2 class="wp-block-heading">insert 文 で json.dumpの結果を使う</h2>
これはPython のサンプルプログラムです。
<!-- /wp:heading -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">url = 'https://www.alphavantage.co/query?function=INCOME_STATEMENT～' 
r = requests.get(url)
income_data = <strong>r.json</strong>()

url = 'https://www.alphavantage.co/query?function=BALANCE_SHEET~'
r = requests.get(url)
balance_data = <strong>r.json</strong>()

try :
sql = ('INSERT INTO AlphaVantage  
(t_date, ticker, income_stmt,balance) VALUES (now(6), %s, %s,%s)
 ON DUPLICATE KEY UPDATE income_stmt = 
　VALUES (income_stmt),balance=VALUES(balance);')

data = [
(ticker_name, json.dumps(income_data),json.dumps(balance_data)) 
]
cur.executemany(sql, data)
</pre>
<!-- /wp:preformatted -->

<!-- wp:heading -->
<h2 class="wp-block-heading">select は JSON_EXTRACTで</h2>
<!-- /wp:heading -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">select <strong>JSON_EXTRACT</strong>(balance, '$.annualReports[0].<strong>totalShareholderEquity</strong>')
from AlphaVantage;</pre>
<!-- /wp:preformatted -->

JSON_EXTRACTは便利
https://mariadb.com/kb/en/json_extract/
vmware ESXi 8.0インストール時に、[CPU_SUPPORT ERROR]が発生して進めない

vmware ESXi 8.0インストール時に、以下のような画面が発生しインストールを継続できません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201787/4aeed9fd-acb4-095c-4f24-e77da97c1302.png)

```test:error
<CPU_SUPPORT ERROR: The CPU in this host is not supported by ESXi
8.0.1. Please refer to the VMware Compatibility Guide (VCG) for
the list of supported CPUs.>
```

# 環境
VMware ESXi 8.0 update 1a

# 原因
CPUがサポートされていないのが原因です。
サポート外としては新しい・古すぎるといったことがありますが本環境では**古すぎる**が原因でした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201787/32362144-5622-dfdb-f6df-29b65d72523e.png)
sandy bridgeでした

# 対策
ESXiインストールのためのOS起動直後、`boot option`入力時に以下を入力します。
`allowlegacyCPU=true`

以下画面で急いで`SHIFT + O`を入力し、追加オプションを入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201787/14f7c300-4b6b-1b3e-220c-6f4c449c31a4.png)

:::note info
既存のオプションがある場合はその後ろに入力します。
今回は`runweasel cdromBoot`はそのままにしています。
:::


結果、エラーで進めなかった画面についてワーニング表示となりインストール進行が可能になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201787/7276932b-3b78-f6e1-0384-353592b6c0cc.png)

# その他
Intel 12世代や13世代のような最新CPUを使用しているPコア/Eコア環境の場合は、以下のオプションを使用することで回避できるようです。
`cpuUniformityHardCheckPanic=FALSE`

本環境では効果なく、インストール失敗のままとなりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201787/80365e89-f08e-b390-346e-076d38196cf1.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201787/bf3ff7a5-3df0-5699-dee8-dbc96c1b2986.png)

# 参考
**Deploy Nested VCSA 8 Legacy CPU's**
https://communities.vmware.com/t5/VMware-vCenter-Discussions/Deploy-Nested-VCSA-8-Legacy-CPU-s/td-p/2957110

**古いサーバでNestedESXi8+TPM2.0の仮想マシンを作る話**
https://yuutosi.net/post-1871/

**Nehalem世代 Core i5(480M)CPUのPC で VMware vSphere Hypervisor 7.0 環境を構築する(2)**
https://try-widely.com/vmware-vsphere-hypervisor-2/


**ESXi 7 and 8 Installation fails with "Fatal CPU mismatch on feature"**
https://www.virten.net/2022/11/esxi-7-and-8-installation-fails-with-fatal-cpu-mismatch-on-feature/

**VMware ESXi Home Lab – Intel NUC 12 (Wall Street Canyon)**
https://andrewroderos.com/vmware-esxi-intel-nuc-12/

**ESXi on Intel NUC 12 Pro (Wall Street Canyon)**
https://williamlam.com/2022/09/esxi-on-intel-nuc-12-pro-wall-street-canyon.html

**NUC12WSHi7にESX 7.0U3を入れる**
https://www.blog.slow-fire.net/2022/11/05/nuc12wshi7%E3%81%ABesx-7-0u3%E3%82%92%E5%85%A5%E3%82%8C%E3%82%8B/

**おうちクラウド2022**
https://qiita.com/hirosat/items/e121ffd7d385e30ecc2d
スプレッドシートの特定のページをエクセル及びPDFでダウンロードする方法

## スプレッドシートの特定のページをエクセル及びPDFでダウンロードする方法

スプレッドシートを使ってデータを管理している場合、特定のページをエクセルファイル（.xlsx）またはPDFファイル（.pdf）としてダウンロードしたいことがあります。以下の方法を使えば、簡単に目的のページをダウンロードすることができます。

1. スプレッドシートのURLを取得します。例えば、`https://docs.google.com/spreadsheets/d/スプレッドシートのID/edit`という形式のURLです。

2. ダウンロードしたいページのID（gid）を特定します。各ページには一意のIDが割り当てられており、URL内で確認することができます。

3. ダウンロードしたい形式に応じてURLを構築します。以下の形式を使います。

   - エクセル形式（.xlsx）の場合: `https://docs.google.com/spreadsheets/d/スプレッドシートのID/export?format=xlsx&gid=ページのID`

   - PDF形式（.pdf）の場合: `https://docs.google.com/spreadsheets/d/スプレッドシートのID/export?format=pdf&gid=ページのID`

   例えば、エクセル形式でページのダウンロードを行う場合、URLは `https://docs.google.com/spreadsheets/d/スプレッドシートのID/export?format=xlsx&gid=ページのID`となります。

4. ブラウザのアドレスバーに構築したURLを入力し、ページにアクセスします。

5. ページが正常にロードされると、ブラウザは自動的にダウンロードが開始されます。ダウンロードフォルダにエクセルファイルまたはPDFファイルが保存されます。

以上が、スプレッドシートの特定のページをエクセルファイルまたはPDFファイルとしてダウンロードする手順です。この方法を使えば、必要な情報だけを簡単に取得できます。
fly deployコマンドを実行した際、failed to fetch an image or build from sourceというエラーが起きた。

fly deployコマンドを実行した際、下記エラーメッセージが出力された。

```
Error: failed to fetch an image or build from source: error connecting to docker: failed building options: failed probing "personal": context deadline exceeded
```
エラーメッセージを検索したところ、下記コミュニティに辿り着く。

https://community.fly.io/t/deployments-not-working-error-connecting-to-docker/3992

コミュニティに書かれている通り、
fly auth loginコマンド実行。
再度fly deployを実行したところ、正常にデプロイできた。
Helmfileの特定のリリースを消したい

# やりたいこと

helmfile.yamlを使って複数のHelmチャートをデプロイしていて、不要になったものを削除したくなりました。例えば以下の2つをリリースしており、``haproxy``だけ削除したいです。

```
$ ls .
helmfile.yaml
$ helmfile list
NAME    NAMESPACE       ENABLED INSTALLED       LABELS  CHART           VERSION
nginx   nginx           true    true                    bitnami/nginx   15.1.0
haproxy haproxy         true    true                    bitnami/haproxy 0.8.3
```

# 参考情報
```
$ helmfile --version
helmfile version 0.152.0
```

```yaml:helmfile.yaml
repositories:

- name: bitnami
  url: https://charts.bitnami.com/bitnami

releases:

- name: nginx
  namespace: nginx
  createNamespace: true
  chart: bitnami/nginx
  version: 15.1.0

- name: haproxy
  namespace: haproxy
  createNamespace: true
  chart: bitnami/haproxy
  version: 0.8.3
```

# helmfile destroyを誤用してしまう...

``helmfile --help``を見ると``destroy``というサブコマンドが用意されていました。
```
$ helmfile --help | grep destroy
  destroy      Destroys and then purges releases
```

そこで「``helmfile destroy haproxy``とか実行すれば消せるんだろうなあ」と安易に考えて実行してみます。

:::note alert
【警告】実際にこのコマンドを実行すると**全リリースが消えてしまう**ので、決してたやすく実行しないでください！！
:::

```
$ helmfile destroy haproxy
Adding repo bitnami https://charts.bitnami.com/bitnami
"bitnami" has been added to your repositories

Listing releases matching ^haproxy$
haproxy haproxy         1               2023-07-01 05:39:20.532555249 +0900 JST deployed        haproxy-0.8.3   2.8.0

Listing releases matching ^nginx$
nginx   nginx           1               2023-07-01 05:39:20.866827715 +0900 JST deployed        nginx-15.1.0    1.25.1

Deleting haproxy
Deleting nginx
release "haproxy" uninstalled

release "nginx" uninstalled


DELETED RELEASES:
NAME
haproxy
nginx
```

なんと<font color="Red">**haproxyだけではなくて、nginxも消されてしまっています。。。**</font>
**helmfile destroy(またはdelete)は``helmfile.yaml``に記載されたリリース全てを有無を言わさず削除する恐ろしいコマンド** だったのです。

:::note info
現バージョン（0.152.0）の挙動なので、今後改善される可能性はあります。
:::

同様の報告は以下のようにされており、誤用の可能性とその危険性が非常に高いのがわかります。

https://takamii.hatenablog.com/entry/2018/07/03/224827

https://twitter.com/int128/status/1014073757562855424

# 特定のリリースのみを消すにはどうすればいい？

小一時間調べてみたのですがよさげな情報は見つからず、結局以下のように**消したいリリースのみを書いたhelmfileを用意して``helmfile destroy``を実行**することで対処しました。

```yaml:helmfile-delete.yaml
repositories:

- name: bitnami
  url: https://charts.bitnami.com/bitnami

releases:

- name: haproxy
  namespace: haproxy
  createNamespace: true
  chart: bitnami/haproxy
  version: 0.8.3
```

実行コマンドとその出力
```
$ helmfile destroy --file helmfile-delete.yaml
Adding repo bitnami https://charts.bitnami.com/bitnami
"bitnami" has been added to your repositories

Listing releases matching ^haproxy$
haproxy haproxy         1               2023-07-01 06:06:53.924671604 +0900 JST deployed        haproxy-0.8.3   2.8.0

Deleting haproxy
release "haproxy" uninstalled


DELETED RELEASES:
NAME
haproxy
```

# おわりに
``helmfile destroy(or delete)``コマンドを何らかの事情で使って、かつ``~/.bash_history``にその履歴が残っている場合は、履歴ごと削除する（または履歴に記録されない設定にする）ことを推奨します。
「Pythonを使って楽々iRIC」公開しました！

皆さんに親しみやすいPythonコードを使って自分のモデルをiRICに組み込む方法を実例を含めて分かりやすく解説してます。
サンプルコードはすべてGitHubで公開してます。これを参考に皆様もご自分のコードをiRICで動くようにして、世界中の仲間と共有して見ませんか？

テキストはこちらです。
https://i-ric.org/yasu/nbook3/index.html
[matplotlib]折れ線グラフの線だけ透明にする

# 折れ線グラフのマーカは不透明で、線のみ透明に

`plot` の `alpha`を指定すると、線とマーカが両方透明度が設定される。

[Matplotlib - How to make the marker face color transparent without making the line transparent](https://stackoverflow.com/questions/15928539/matplotlib-how-to-make-the-marker-face-color-transparent-without-making-the-li)
を見ると個別に設定できる旨があったが、色は指定したくなかった。

`get_color`, `get_markerfacecolor` で色は取れるので、`to_rgb`で16進文字列をRGBに変換して再指定でできた。

```python
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import to_rgb

plt.figure()
plt.plot(np.random.randn(10), np.random.randn(10), "*")
l, = plt.plot(range(10), np.random.randn(10), "+-")

print("before", l.get_color(), l.get_markerfacecolor())

l.set_color((*to_rgb(l.get_color()), 0.1))
l.set_markerfacecolor((*to_rgb(l.get_markerfacecolor()), 1))

print("after", l.get_color(), l.get_markerfacecolor())

plt.show()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455423/dc1c8ecf-be4c-569a-b759-a98fb2064df1.png)


**alphaでマーカだけ、線だけ透明度設定できればいいのに。​
laravel モデルクラスでfillableを定義する意義

# 概要

- モデルクラスで$fillableの配列を定義する意義を簡単にまとめる。

# 意義

- `$fillable`の配列では許可するカラム名を指定する。
- 何を許可するのかというと、一括代入（モデルクラスのcreateメソッドやupdateメソッドの引数として一括で配列を受け取って処理する）を許可している。
- `$fillable`の配列で指定されたカラムの一括代入を許可するのだ。
- `$fillable`を定義しない場合何が起きるのかを見てみよう。
- usersテーブルに下記のカラムがあるとする。
    - name
    - email
    - password
    - phone
- 「電話番号は初回登録後変更できないサービス」だったとする。
- create時には下記のようにモデルを呼び出してレコードを作成する。

    ```php
    use App\Models\User;

    // 説明のため、擬似的にリクエストの配列を定義する
    $request = [
        'name' => 'Foo Bar',
        'email' => 'test@example.com',
        'password' => 'password01234',
        'phone' => '0123456789',
    ];

    User::create($request);
    ```

- 上記の処理は`$fillable`を定義していようが、いまいが、あまり関係ない。
- 更新の場合はどうなるだろうか。「電話番号は初回登録後変更できないサービス」を念頭に置く。

    ```php
    use App\Models\User;

    // 説明のため、擬似的にリクエストの配列を定義する
    $request = [
        'name' => 'Hoge Fuga',
        'email' => 'test_01@example.com',
        'password' => 'password56789',
    ];

    User::update($request);
    ```

- updateメソッドに渡される配列のキーが`name`, `email`, `password`のみの場合「電話番号は初回登録後変更できないサービス」のルールが守られる。
- しかしながら`$fillable`を定義していないばっかりに、下記のような値がupdateメソッドに渡った場合`phone`が更新され、「電話番号は初回登録後変更できないサービス」のルールが守られない。

    ```php
    use App\Models\User;

    // 説明のため、擬似的にリクエストの配列を定義する
    $request = [
        'name' => 'Hoge Fuga',
        'email' => 'test_01@example.com',
        'password' => 'password56789',
        'phone' => '1112131415',
    ];

    User::update($request);
    ```

- ただし、これは「`$fiilable`を定義していない」「バリデーションルール未設置」「リクエストのキー、バリューをそのままcreateやupdateメソッドに渡してしまう」などの悪条件が重なったときにだけ発生する。しかし、コードを記載する時にミスは付き物であるため必ず`$fillable`は設定したほうが良いと思う。
- 今回の場合Userモデルクラスでは下記のような`$filalble`を定義することになるはず、、！

    ```User.PHP
    $fillable = [
        'name',
        'email',
        'password',
    ];
    ```

- createメソッドの戻り値は作成したレコードの情報をもったモデルインスタンスなのでちょっと回りくどくなるが下記のようにcreateの時は記載できる（いや、こんな上長な書き方以外にもっと良い書き方があるかも。少なくともトランザクションは貼ったほうが良いかも）

    ```php
    use App\Models\User;

    // 説明のため、擬似的にリクエストの配列を定義する
    $request = [
        'name' => 'Foo Bar',
        'email' => 'test@example.com',
        'password' => 'password01234',
    ];

    $user = User::create($request);

    $user->phone = '0123456789',
    $user->save();
    ```

- これならcreateやupdateメソッドでphoneの値がはいらないようにブロックすることができる。
baserCMSのショートコード（3）応用（メールフォーム）

## baserCMSショートコードのテクニック
baserCMS4系（公式サイト: https://basercms.net/ ）のショートコードの使い方は
・[baserCMSのショートコード（1）基本](https://qiita.com/katokaiysa/items/ab7d98429a2a50fed1ab)
・[baserCMSのショートコード（2）小技](https://qiita.com/katokaiysa/items/a60f98c7520c767ed147)
をお読みください。

## この記事で紹介する内容
[前回紹介したショートコードの小技](https://qiita.com/katokaiysa/items/a60f98c7520c767ed147)を使って、固定ページやブログ記事の途中にメールフォームを呼び出してみたいと思います。

## 想定している対象者
baserCMSを使ってウェブサイトを作成している人（作成しようとしている人）
ある程度テーマファイルを編集することができる人
※elementファイル内で非同期でメールフォームを呼び出すため、ある程度jQueryなどの知識があったほうが良いです。

## 準備（前回と同様です）
ショートコードを設定ファイルへ記述
```ドキュメントルート/app/Config/setting.php```
記述内容
```
$config['BcShortCode']['BcBaser'] = ['BcBaser.BcBaser.getElement'];
```
上記の準備ができたら、
呼び出したいElementsファイルを作成します。
今回はメールフォーム呼び出しなので、わかりやすいようにform.phpとしましたが、別に他のファイル名でも構いません。
```ドキュメントルート/theme/使用中のテーマ/Elements/form.php```

form.phpの記述
（jQueryがサイト内に読み込まれていることが前提です。）
```
<script>
	$(function () {
		$.ajax({
			cache: false,
			type: 'GET',
			datatype:'html',
			url: "/contact/",
			data: '',
			success: function(result) {
				$('#formIn').html(result);
				if ("efo" in window) {
					window.efo();
				}
			},
			error: function(XMLHttpRequest, textStatus, errorThrown) {
				console.log('Error : ' + errorThrown);
			}
		});
	});
</script>
<div id="form" style="display: block; margin-top:-100px; padding-top:100px; height: 0;"> </div>
<section id="formIn"></section>
```
（今回は「contact」というbaserCMS内に予め作っておいたメールフォームを呼び出します）
上記の準備ができたら、ブログ記事・固定ページ編集欄に
```[BcBaser.getElement form]```
と記載し、保存します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553367/af3c576f-625b-7238-827c-d60e2c686bc5.png)
すると、公開記事側では
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553367/17f26a13-2d2f-d3cb-42a0-8e6f3a5c3783.png)
こんな具合でメールフォームが表示されるようになります。

※メールの入力内容を確認するために確認ボタンを押すと、読み込み元のメールフォームの確認画面へとページ遷移します。

一般的には、ブログ記事の途中にメールフォームへのリンクボタンなどを記述することが多いですが、この方法を使うと、メールフォームにたどり着くまでのクリック数が少なくなり、コンバージョンの改善につながる可能性もあります。

また、ここで作成したメールフォーム用のエレメントファイルは
```
<?php $this->BcBaser->element('form);?> 
```
の記述で、テーマファイルのどこからでも呼び出せるため、使い回しが可能です。

難易度は上がりますが、使いこなせば結構便利なので、ぜひチャレンジしてみてください。
Spring Bootプロジェクトのjarの構造を確認

フレームワーク：Spring Boot
ビルドツール：Maven
という構成で、mvn installでjarを作成したとする。

このjarはどういう構成になっているのか？

jarは内部的にはzipなので、拡張子をzipに変更して解凍して確認してみた。

```
jar（zip）のルートディレクトリ
├─BOOT-INF
│  ├─classes
│  │  ├─com
│  │  │  └─example
│  │  │      └─[artifactId]
│  │  │          ├─controller
│  │  │          ├─dto
│  │  │          ├─mapper
│  │  │          ├─model
│  │  │          └─service
│  │  ├─static
│  │  └─templates
│  └─lib
├─META-INF
│  └─maven
│      └─com.example
│          └─[artifactId]
└─org
    └─springframework
        └─boot
            └─loader
                ├─archive
                ├─data
                ├─jar
                ├─jarmode
                └─util
```

ということで、Spring Bootで自作で組んだプログラムは、BOOT-INF\classes配下に格納される。
Tomcatを内包する実行可能jar（Fat jar）である。

## Spring Boot使わないMavenプロジェクトの場合

Spring Boot使わないpureなJavaのMavenプロジェクトの場合はこのように簡素な構造になる。

```
jar（zip）のルートディレクトリ
├─com
│  └─example
│      ├─dto
│      └─enums
└─META-INF
    └─maven
        └─com.example
            └─demo
```

他Mavenプロジェクトのpom.xmlに依存関係を追加して
import com.example.enums.Foo;
という形で参照することができる。

# MANIFEST.MFについて

META-INFディレクトリ内に、MANIFEST.MFというファイルが存在する。
これはマニフェストファイルといい、jarファイルについての説明が記載されたテキストファイルであり、jarファイル作成時に自動生成される。
実行時にmain()メソッドを呼び出すクラスや、クラスパスの定義がある。

下記はその一例である。

SpringBootプロジェクトの場合の一例
```
Manifest-Version: 1.0
Created-By: Maven JAR Plugin 3.3.0
Build-Jdk-Spec: 17
Implementation-Title: springTest
Implementation-Version: 0.0.1-SNAPSHOT
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: com.example.springTest.SpringTestApplication
Spring-Boot-Version: 3.0.5
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
Spring-Boot-Layers-Index: BOOT-INF/layers.idx
```

Spring Boot使わないMavenプロジェクトの場合の一例
```
Manifest-Version: 1.0
Created-By: Apache Maven 3.8.7
Built-By: circu
Build-Jdk: 17.0.5
```

マニフェストファイルが壊れたりしていると、jar起動したときに、
「アプリ名.jarにメイン・マニフェスト属性がありません」というエラーが出ることが考えられる。
これについては詳しくは、[Spring Boot jarにメイン・マニフェスト属性がありませんを解決する方法](https://www.saka-en.com/java/spring-boot-mainifest-error/)を参照。
VSCodeの設定が消えた

# ことの発端
VSCodeがGitHubと連携しろしろとうるさいので連携したらVSCodeが初期状態になった

# 起こっていること
すでにあったローカルのsettings.jsonが、GitHubのアカウントと紐付けられていたまっさらなsettings.jsonによって上書きされた

# 復活手順
1. settings.jsonを開く

1. 左下のTIMELINEを開く
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f313533383034392f64613738373664382d663465352d626366652d383566372d6138626162633939333064662e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1538049/fb3e21d7-eafa-4a8f-1a32-538ff841588a.png)


1. 少し前の履歴を左クリックしてRestore Contentsをクリック
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f313533383034392f35303663663631632d336361352d363566352d346563382d6534353230636266323861612e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1538049/85427e85-ad9b-9cee-b720-1d3f5f6fc203.png)


1. 復活
配列を使って円順列の並び方として同一のものかを判定する・配列の回転

# 円順列

いきなりですが、問題です。a,b,c,d,eの5人が円卓に座るとき、座り方の総数は何通りか。

正解は、```(5-1)!=24```通りです！
さすがQiitaを見ている方というだけあって、余裕という感じですね。

それでは、次の問題です。次の二つの並び方AとBは円形に並べた時同じ並びになるでしょうか！？

A： d, b, a, e, c
B： e, c, d, b, a

これは、同じ並びになります。どちらもaを基準に考えると、a→e→c→d→bの並びになっています。
今回はこの判定をプログラムで実装してみます。

# 円順列で考えた時に同一の並びになるかを判定する
まず、2つの配列```array_a```と```array_b```を用意します。
```python
array_a = ["d", "b", "a", "e", "c"] 
array_b = ["e", "c", "d", "b", "a"] 
``` 
```array_a```は変更せず、```array_b```の要素を回転させてみます。つまり、最初の要素を取り除いて、最後に追加します。

```python
array_b = ["e", "c", "d", "b", "a"]
popped_element = array_b.pop(0) #array_bの0番目の要素を取り除いて値を変数に代入
array_b.append(popped_element) #取り除いた要素を配列の最後に追加

print(array_b) #実行結果['c', 'd', 'b', 'a', 'e']
```
この操作を配列の要素の数だけ繰り返して、```array_a```と```array_b```が一致するかどうかを判定しましょう。
一致したら"same!"と表示して繰り返し処理を停止し、最後まで一致しなければ"different"と表示します。

```python
array_a = ["d", "b", "a", "e", "c"] 
array_b = ["e", "c", "d", "b", "a"]

for i in range(len(array_b)):
    popped_element = array_b.pop(0)
    array_b.append(popped_element)
    
    if array_a == array_b:
        print("same!")
        break
    if i == len(array_b) - 1:
        print("different")

#　出力結果：same!
```
最後に、配列を2つ受け取り、その2つの配列が円順列で同じ並びになるかを判定するメソッドを定義して出力部分と切り分けます。
```python
def check_circular_permutation_equal(array_a, array_b):
    for i in range(len(array_b)):
        popped_element = array_b.pop(0)
        array_b.append(popped_element)
    
        if array_a == array_b:
            return True
        if i == len(array_b) - 1:
            return False

array_a = ["d", "b", "a", "e", "c"] 
array_b = ["a", "e", "c", "b", "d"]

if check_circular_permutation_equal(array_a, array_b):
    print("same!")
else:
    print("different")
```


いくつか実験してみました。

```python
array_a = ["e", "f", "a", "c", "d", "b"]
array_b = ["c", "d", "b", "e", "f", "a"]
# 実行結果：same!

array_a = ["c", "f", "b", "d", "a", "e"]
array_b = ["e", "c", "f", "d", "b", "a"]
# 実行結果：different

array_a = ["a", "c", "e", "g", "b", "d", "f"]
array_b = ["e", "g", "b", "d", "f", "a", "c"]
# 実行結果：same!
``` 

# まとめ
- いくつかのものを円形に並べる方法のことを円順列と言う。 円順列では回転して一致する並べ方は同じと考える。
- 配列の一番最初の要素をpopメソッドで取り出し、その要素をappendメソッドで最後に加えることで、配列を「回転」させることができる。
- 配列の「回転」をfor文で繰り返し処理することによって、2つの配列が円順列で考えた時に一致するか否かを判定することができる。
baserCMSのショートコード（2）小技

## baserCMSショートコードの基本
baserCMS4系（公式サイト: https://basercms.net/ ）のショートコードの基本的な使い方は
前回記事 [baserCMSのショートコード（1）基本](https://qiita.com/katokaiysa/items/ab7d98429a2a50fed1ab)をお読みください。

## この記事で紹介する内容
[前回](https://qiita.com/katokaiysa/items/ab7d98429a2a50fed1ab)紹介したショートコード機能を使って、簡単にもっと多くのbaserCMSの関数を使えるようにする、ちょっとした小技を紹介します。
使いこなせば、一つのショートコードで、色々な関数を使えるようになります。

## 想定している対象者
baserCMSを使ってウェブサイトを作成している人（作成しようとしている人）
ある程度テーマファイルを編集することができる人
※今回はテーマフォルダ内のElementフォルダにてphpテンプレート編集・作成ができることが前提です。

## 内容

### ショートコードを設定ファイルへ記述
``` ドキュメントルート/app/Config/setting.php```
記述内容
```
$config['BcShortCode']['BcBaser'] = ['BcBaser.BcBaser.getElement'];
```
上記の準備ができたら、
呼び出したいElementsファイルを作成します。

### 例１）「news」ブログの記事を直近5件表示したいとき
下記エレメントファイルを作成します。
``` ドキュメントルート/theme/使用中のテーマ/Elements/blog.php```
※blog.phpという名前は適当につけているので、他の名前で良いです。

blog.phpの記述
```
<?php $this->BcBaser->blogPosts('news', 5);
```
上記の準備ができたら、ブログ記事・固定ページ編集欄に
```[BcBaser.getElement blog]```
と記載し、保存します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553367/84048127-5286-c042-bb70-edfa5dce3cf2.png)
すると、公開記事側では
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553367/ac0b36c8-461f-53b7-5bc2-de1f7e799b3d.png)
こんな具合で、記事一覧が表示されます。

ショートコードに他の関数を登録して表示する方法もありますが、ショートコード内に複数の引数を記載したりする必要があったり、結構面倒なため、ある程度テーマフォルダ内のファイルを編集・作成できる人には、こちらの方が楽に感じられるのではないでしょうか？

上記のショートコードを利用して、違うエレメントファイルを呼び出すことができるため、[前回の記事](https://qiita.com/katokaiysa/items/ab7d98429a2a50fed1ab)で紹介したサイトマップの表示も下記のようにエレメントphpファイルを用意。
``` ドキュメントルート/theme/使用中のテーマ/Elements/site_map.php```
※site_map.phpという名前は適当につけているので、他の名前で良いです。

site_map.phpの記述
```
<?php $this->BcBaser->sitemap();
```
上記の準備ができたら、ブログ記事・固定ページ編集欄に
```[BcBaser.getElement site_map]```
と記載し、保存すれば、サイトマップが表示できるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553367/51cbe632-1ecd-a73c-3d86-723b7ae28c0a.png)

エレメントファイルを使っているため、表示項目の調整や、引数などもphpファイル側で細かく記述することができるため、baserCMSでサイトをよく作る人には、こちらのやり方のほうが簡単かもしれません。

next: [baserCMSのショートコード（3）応用（メールフォーム）](https://qiita.com/katokaiysa/items/d7bb32df5883b33bf329)
Samba3とSamba4の具体的な違い

●Samba3とSamba4の具体的な違い

■デーモン
Sambaの各サービスについては、Samba3までは以下の各デーモンが提供

デーモン名
・smbd　ファイル、プリンタの共有およびユーザ認証などSambaの基本的な機能を提供
・nmbd　ブラウジング機能(ネットワーク内のコンピュータの一覧表示)、WINSサーバ(NetBIOS名とIPアドレスの名前解決)などの機能を提供
・windbindd　NSSを利用し、Winbindと呼ばれる機能(Samba側から Windowsユーザの情報を利用可能にする)を提供

■ドメインコントローラ
Samba4 はADドメインコントローラとして機能できます。

■認証方法
ユーザの認証方法は、NTドメインではチャレンジレスポンス方式を利用したNTLMv2認証が使用。一方、ADドメインでは、認証にKerberosを使用。Kerberos認証には、1つの認証でユーザが複数台のサーバへアクセスすることが出来るなど、様々な機能があります。

■名前解決
NTドメインでは名前解決にNetBIOS名とIPアドレスを対応付けるWINSを利用するため、Samba3はWINSサーバの機能を持ちます。ADドメインではDNSとの連携が求められるため、Samba4ではDNSとの連携が可能になった。外部のDNSサーバを利用することも可能ですが、自らがDNSサーバとして動作することもできます。

■情報ストア
ADドメインでは情報の保管場所としてLDAPを使用しますので、Samba4ではLDAPも内蔵しています。

■ファイルサーバ機能
Samba4では、ファイル共有プロトコルのSMB2に加えて、パフォーマンスの改善や暗号化などの機能が追加されたSMB3（Windows 8およびWindows Server 2012から搭載）対応となりました。

・その他（管理ツール）
ドメインコントローラを管理するために、Samba4では「samba-tool」とサブコマンド群が準備されています。ドメインコントローラ構築時にはsamba-toolコマンドの使用が必須となりますが、その後の管理はWindowsServerと同様GUIのツールでも行えます。
class-validatorで、他のプロパティの値を参照して一致しているかチェックするCustomValidator

## ユースケース
例えばメールアドレスを使った新規登録画面

この場合、タイプミスなどで自分が意図していないパスワードが設定されてしまうのを防ぐために、二度同じパスワードを入力させるのが一般的です。
![スクリーンショット 2023-07-01 0.43.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256853/99123518-31c7-d1e8-2c2c-5734f5d95fb9.png)

## バックエンドのリクエストバリデーションで使われがちな`class-validator`はRHFでも使える
`class-validator`といえば、[NestJSで使われるバリデーション](https://docs.nestjs.com/techniques/validation)ですが、実はreact-hook-formのresolverに使うこともできます。

```react:SignupPage.tsx
import { classValidatorResolver } from '@hookform/resolvers/class-validator';
import { RegisterUserRequestDTO } from '../DTO';
import { useForm } from 'react-hook-form';
import { classValidatorResolver } from '@hookform/resolvers/class-validator';

export const SignupPage = () => {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<RegisterUserRequestDTO>({ resolver: classValidatorResolver(RegisterUserRequestDTO) });

  // JSXは省略します
};

```

## 使い方のイメージ
`IsEqual()`というカスタムデコレーターを作ります。
呼び出す時はこんな感じで、第一引数に参照したいプロパティ名を指定してあげます。
```typescript:RegisterUserRequestDTO.ts
import { IsEmail, IsNotEmpty, Matches, MinLength } from 'class-validator';
import { VALIDATION_ERRORS } from './error.constants';
import { isEqual } from './CustomValidator/isEqual';

export class RegisterUserRequestDTO {
  @IsEmail({}, { message: VALIDATION_ERRORS.INVALID_EMAIL })
  @IsNotEmpty({ message: VALIDATION_ERRORS.REQUIRED })
  email: string;

  @Matches(/[a-z]/, { message: VALIDATION_ERRORS.INVALID_PASSWORD })
  @Matches(/[A-Z]/, { message: VALIDATION_ERRORS.INVALID_PASSWORD })
  @Matches(/[0-9]/, { message: VALIDATION_ERRORS.INVALID_PASSWORD })
  @MinLength(8, { message: VALIDATION_ERRORS.INVALID_PASSWORD_LENGTH })
  @IsNotEmpty({ message: VALIDATION_ERRORS.REQUIRED })
  password: string;

  // 今回実装するのはこの `isEqual()`
  @isEqual('password', { message: VALIDATION_ERRORS.NOT_MATCH_PASSWORD })
  @IsNotEmpty({ message: VALIDATION_ERRORS.REQUIRED })
  passwordConfirm: string;
}

```


## IsEqual()の実装
細かい説明は省きますがこんな感じ。公式ドキュメントを参照すれば誰でも作れますね。
```typescript:CustmoValidator/isEqual.ts
import { ValidateBy, ValidationArguments, ValidationOptions } from 'class-validator';

export function isEqual(property: string, validationOptions?: ValidationOptions): PropertyDecorator {
  return ValidateBy(
    {
      name: 'isEqual',
      constraints: [property],
      validator: {
        validate(value, args: ValidationArguments): boolean {
          const [relatedPropertyName] = args.constraints;
          const relatedValue = (args.object as any)[relatedPropertyName];
          return relatedValue === value;
        },
      },
    },
    validationOptions || { message: `require to match with ${property}` },
  );
}
```

https://github.com/typestack/class-validator#custom-validation-decorators
IstioのEnvoyFilterによるRate Limit

マイクロサービスでは、サービス間の通信にRate Limitを設けることで、一部のサービスが過負荷となっても他のサービスに影響を与えないようにすることが一般的です。

IstioではRate Limitの手段として幾つか選択肢がありますが、より細かな制御を行いたい場合には、EnvoyFilterを使います。

## EnvoyFilterとは？

EnvoyFilterはIstioで提供されているカスタムリソース定義（CRD）の一つで、Envoyプロキシの挙動を詳細に制御することができます。Rate Limitの設定以外にも、HTTPリクエストやレスポンスのヘッダーの操作、トラフィックのルーティングの調整などが可能です。

処理フローは以下のようになります。
（外部からのリクエストはIstio Ingress Gatewayを介します）


```mermaid
sequenceDiagram
    participant Client as Client
    participant Envoy as Envoy Proxy
    participant RL as Rate Limit Service
    participant App as Application Service
    Client->>Envoy: リクエスト
    Envoy->>RL: Rate Limitの確認
    Note over RL: rate limit policy適用
    RL-->>Envoy: 判定結果通知
    Note over Envoy: 判定結果に基づいて対応
    Envoy->>App: リクエスト転送（制限範囲内だった場合）
    App-->>Envoy: レスポンス
    Envoy-->>Client: レスポンス
```
リクエストはRate Limit ServiceにてPolicyに適合しているか判定され、OKならアプリへ転送、NGなら429 Too Many Requestsが返されます。

制限の適用範囲としては、メッシュ全体を対象とするGlobalと、Pod単位を対象とするLocalの２種類があります。


## Istio Bookinfoのratingsに対するRate Limit設定

具体的な設定例として、Istioのサンプルアプリケーションである[Bookinfo](https://istio.io/latest/docs/examples/bookinfo/)に対して、ratingsサービスへの制限をかけます。（Local Rate Limit）


```yaml
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: ratings-ratelimit
  namespace: default
spec:
  workloadSelector:
    labels:
      app: ratings
  configPatches:
  - applyTo: HTTP_FILTER
    match:
      context: SIDECAR_INBOUND
      listener:
        portNumber: 8080
        filterChain:
          filter:
            name: "envoy.filters.network.http_connection_manager"
            subFilter:
              name: "envoy.filters.http.router"
    patch:
      operation: INSERT_BEFORE
      value:
        name: envoy.filters.http.local_ratelimit
        typed_config:
          "@type": "type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit"
          stat_prefix: http_local_rate_limiter
          token_bucket:
            max_tokens: 10
            tokens_per_fill: 10
            fill_interval: 60s
```
この設定では、ratingsサービス（`workloadSelector.labels.app: ratings`）に対して、1分間に最大10回のリクエストを許可します。
AWSのサポート切れをきっかけに、画像の透かし入れ機能をレガシーシステムからサーバーレスに切り替えた話

# 背景

[こちらの発表](https://aws.amazon.com/jp/blogs/news/tls-1-2-required-for-aws-endpoints/)のとおりAWSでは今後TLSのバージョンが1.2未満の通信を許可しなくなるため、影響を受けるシステムは修正しないと使えなくなります。

長年メンテナンスせずに放置されてきたシステムは簡単には更新できず、画像の透かし入れぐらいの機能なら、サーバーレスで完全に作り直した方が良いのでは？ということで実装してみることになりました。

# 切り替えることによって得られたメリット

## 保守性の向上

大昔から存在する古臭いJavaのアプリケーションをサーバーレスに切り替えたことにより、コードベースが大幅に削減されました。解読することが大変な状態から100行未満の簡単なスクリプトに変わったため、非常に保守しやすくなりました。

## スケールアウト

サーバー上で稼働するWebアプリケーションをサーバーレスに切り替えたことにより、サーバーの負荷、適切なスペックを気にする必要がなく、全てはAWSが管理しているため、*サービスクォータが許す限り、いくらでも無駄なく勝手にスケールアウトできます。*

## コスト削減

サーバーレスに切り替えたことにより、単位時間あたりの課金体制からアクセス毎の課金体制に変わりました。アクセス数の少ない時間帯でも無駄なコストが発生することはなく、アクセス数の急増に備えてバッファを確保する必要もないため、コストがかなり削減されました。

# システム構成

下記の画像の通り非常にシンプルな構成です。API Gateway から Lambda を呼び出して、Lambda で S3 にある画像に透かしを入れてから、レスポンスを返す。

![Screenshot 2023-07-01 at 0.17.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3468780/35951acb-6d35-c0cd-ace3-79e7fd6ce563.png)

# 効果

`https://<API Gateway のエンドポイント>/watermark/<S3にある画像のパス>` にアクセスするとこのようにS3に事前にアップロードした猫ちゃんの画像に透かしが追加されて表示されます。
![cat-image-00012.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3468780/f007a2e2-1cc0-fc01-438d-0f69267deaa0.png)

# 実装

## アーキテクチャ

いろいろ調査してみたところ、[Serverless Framework](https://www.serverless.com/) というものが一番良さそうでしたので、採用しました。 `serverless.yml` というファイル内に定義を記載することで、デプロイ＆AWSの設定を行ってくれるので、IaC(Infrastructure as Code) も一緒に実現できます。

## コード (必要であれば、ご自由にお使いください)

- Node.js版はこちら
    - https://github.com/MOCA-ORG/serverless-watermark-nodejs
- Golang版はこちら
    - https://github.com/MOCA-ORG/serverless-watermark-golang

両方実現している機能は全く同じですが、最初は Node.js で実装しました。Lambda関数の実装について調べると、Node.js で実装した場合の情報が圧倒的に多かったです。またスクリプト言語であるためコーディングしやすく、コンパイルする必要もないので、一番簡単でした。

## 詰まったポイント

### API GatewayのAPIパス定義

S3上にある画像は `/` を区切り文字として使用しているため、`/watermark/{image_key}` でAPIを定義するとS3のパスを正しく取得できません。`/watermark/{image_key+}` という風に `+` を付けることで、それ以降のURLはすべて `image_key` として取得できるようになります。

## Node.js と Golang で同じものを２通り実装した理由

Lambda は リクエストの処理時間と設定したメモリに応じて課金が発生します。そのため処理時間が半分になれば、課金額も半分になります。

Node.js はとっても書きやすかったですが、コンパイル型の言語である Golang で実装したら処理時間とメモリ消費が減るのかどうかを実験するために、同じ機能を実装し直しました。

1MB ほどの画像でベンチマークを測ったところ下記の結果になりました。

| 言語 | 処理時間 | 消費メモリ |
| --- | --- | --- |
| Node.js | 約 2.4 秒 | 約 270 MB |
| Golang | 約 1.3 秒 | 約 150 MB |

つまりは Node.js ではなく Golang を使用すれば、Lambda の料金が半分以下になります。

# まとめ

AWSのサポート切れにより、同じ問題で困っている企業や個人開発者さんも少なからずいるのではないかなと思います。

この記事が少しでもお役に立てれば幸いです。 :smile:
denoise diffusion 概要覚書


https://towardsdatascience.com/understanding-the-denoising-diffusion-probabilistic-model-the-socratic-way-445c1bdc5756
https://towardsdatascience.com/understanding-diffusion-probabilistic-models-dpms-1940329d6048?gi=8cd1333625ac

cvpr2023のimagicの勉強の前に、
stable diffusionでおなじみ
生成モデルについて勉強するぜ。


画像xをいちから復元したいぜ。
正解の画像xが実は未知のパラメータ・潜在変数θに
従って生成されてる仮定すると、
画像xを復元する機構の仕組みのコンセプトは、
この適切なθをできるだけ模倣して、
正解画像xに近づけるように精度を上げることだぜ。




いやそもそも未知のパラメータθってなんなん？
θとは、画像の特徴が詰まってる空間。
オートエンコーダーの頃はθの構造が
さっぱりわからなかったけど、
エンコーダにθの分布をガウス分布に仮定して与えてやることで、
θの分布がわかるようになったぜ。
馬の画像を復元したいなら、θの分布はこの辺、
鳥の画像の分布はこの辺という感じで利用できるようになったぜ



ということでDDPM。
その前に画像における確率密度関数は何か整理するぜ。
例えば10x10の花の画像がどれくらいの確率分布で花になるか考える。
ピクセルの数は100ピクセル。ピクセルが任意に自由に色を取ると考えたとき、
ピクセル一つ一つが好き勝手色を変えたら、
画像全体が花になる確率はとんでもなく低いことが直感的にわかるぜ。
画像が花が映った時、ピクセル一つ一つがちょうど花になるように色を出力する確率を
ピクセルそれぞれに求めてやる。全ピクセルの確率を統括したものが確率密度関数だぜ。


DDPMはノイズを付与したあとにノイズを除去する機構を
学習で鍛え上げることで、自在に画像を出せるよう学習するぜ。

ということでまずは、ノイズを付与するフェーズ。
元画像x0は確率密度関数q(x)に従うものとするぜ。
q(x0)の意味するところは、元画像の確率密度を表したものになるぜ。
さて、X1X2…Xtを段階的に付与したノイズ画像とすれば、
前回のノイズ画像に対する新たなノイズ画像の分布q(Xt|Xt-1)は、
前回のノイズ画像の平均に基づき定義されるぜ。




今のがノイズをたすフェーズ。
我々が最終的に学習したいのは、ノイズから画像を生成する部分だぜ。
上述の通り、未知のパラメータをコントロールするために、
この時の確率密度関数をなんとか定式化したいぜ。
この時の定式は、なんかいろんな前提をみたせば、
ノイズ除去の時の確率密度pθ(x)も、 
q(Xt|Xt-1)と同様にガウス分布にしたがうらしいぜ。
この式は、平均μθ、分散σθという未知のパラメータでガウス分布が構成されるぜ。






この未知のパラメータはどうやって学習するんだぜ？？
学習するときは、何かしら目標の値ができるだけ
最大化するなり最小化するなりさせながら、パラメータを更新させつつ学習をするんだぜ。
今回でいえば、
ノイズを除去する時の確率密度pθ(x)が、
Xt.Xt-1…X1とノイズを除去していき、最終的に得る元画像の
確率分布pθ(x0)と、
元画像の確率密度q(x0)。これが同じになるはずだぜ。
pθ(x0)とq(x0)のKLを最小化、あるいは
q(x0)下でのpθ(x0)の対数尤度を最小化するぜ。
最小化するパラメータ平均μθ、分散σθを見つけることが必要になるぜ


ここからの式の整理はTwitterに書けるレベルじゃないぜ。
https://towardsdatascience.com/understanding-diffusion-probabilistic-models-dpms-1940329d6048?gi=8cd1333625ac
ここがわかりやすかったぜ。
最初、パラメータを平均μθ、分散σθとして定式化するわけだが、
最終的な損失関数の導出にあたり、
分散を固定化して、パラメータを平均μθのみにしたが、
Xtは元画像X0にノイズεを足したもので表される式

Xt=AX0+Bε（略）の式を導入することで、
最終的にはX0に追加されたノイズεを学習するように修正されるぜ。



最後に流れを説明するぜ。
まず学習フェーズ。元画像に対してノイズεをたすぜ。
そしてノイズ足された画像に対して機構を読み込ませて、
新たなノイズε'を推定。εとε'の誤差より最適化して、
更新されたεで最初のフェーズにもどるぜ

学習が終わればいよいよ生成。
ノイズをぶっこむぜ。1…Tステップにしたがって、
ノイズを除去する処理を行うぜ。
具体的には、今現在のノイズを推定して、Xt=AX0+Bε（略）の式を
X0に変えた式より、元画像を推定。
1回目のループ時点で元画像推定できるんだけど、
数回のループじゃ精度悪いので、
1…Tステップ全てでノイズ除去するぜ。
そのために、次のフェーズに渡すためのXt-1を
計算するぜ。
レバテックプラットフォーム勤怠自動入力スクリプト

consoleに貼り付けて実行。
`fillForm(csvData, '202306')`のような形式

```js
// CSVデータをパースする関数を定義します。
function parseCSVData(csvData) {
    let lines = csvData.split('\n');
    let timeData = lines.map(line => line.split(',')).filter(arr => arr.length === 3);
    return timeData;
}

// CSVデータを用いてフォームを自動入力する関数を定義します。
function fillForm(csvData, yearMonth) {
    // CSVデータをパースします。
    let timeData = parseCSVData(csvData);

    // 各日付に対して入力データをセットします。
    for (let i = 0; i < timeData.length; i++) {
        let startTime = timeData[i][0];
        let endTime = timeData[i][1];
        let relaxTime = timeData[i][2];

        // HTML要素を取得します。
        let startTimeInput = document.querySelector(`input[name='data[DailyReport][${yearMonth}${String(i + 1).padStart(2, '0')}][start_time]']`);
        let endTimeInput = document.querySelector(`input[name='data[DailyReport][${yearMonth}${String(i + 1).padStart(2, '0')}][end_time]']`);
        let relaxTimeInput = document.querySelector(`input[name='data[DailyReport][${yearMonth}${String(i + 1).padStart(2, '0')}][relax_time]']`);

        // データが空でなければ値をセットします。
        if (startTime.trim() !== '' && startTimeInput) startTimeInput.value = startTime;
        if (endTime.trim() !== '' && endTimeInput) endTimeInput.value = endTime;
        if (relaxTime.trim() !== '' && relaxTimeInput) relaxTimeInput.value = relaxTime;
    }
}

```

# 想定データ

開始、終了、休憩順のcsvデータ

```js
let csvData = `
10:00,18:00,01:00
10:00,18:00,01:00
,,
,,
10:00,18:00,01:00
10:00,18:00,01:00
10:00,18:00,01:00
,,
,,
10:00,18:00,01:00
10:00,18:00,01:00
10:00,18:00,01:00
,,
,,
10:00,18:00,01:00
10:00,18:00,01:00
10:00,18:00,01:00
,,
,,
10:00,18:00,01:00
10:00,18:00,01:00
10:00,18:00,01:00
,,
,,
10:00,18:00,01:00
`;

```