OmniAICreator/Qiita-1.07M huggingface dataset:
CDNとは。ダウンロード不要、外部で公開されているフォントやアイコンをサイト制作に導入する。

# はじめに
## CDNとは？
"CDN" は「コンテンツデリバリーネットワーク」（Content Delivery Network）の略で、サービスや技術の両方を指すことがあります。

### 1. サービスとしてのCDN:
CDNは、ウェブサイトやアプリケーションの静的なコンテンツ（画像、スタイルシート、スクリプトなど）を高速かつ効率的にユーザーに配信するためのサービスです。CDNサービスプロバイダーは、世界中に分散したサーバーを備え、ユーザーに近い場所からコンテンツを提供することで、読み込み速度を向上させます。代表的なCDNサービスプロバイダーには、Akamai、Cloudflare、Amazon CloudFrontなどがあります。  

### 2. 技術としてのCDN:
CDNはまた、コンテンツデリバリーの技術全体を指すこともあります。これは特定のサービスプロバイダーに限定されるものではなく、様々な企業や組織が自社でCDNを構築することも含まれます。この場合、CDN技術はコンテンツを最適な形でエンドユーザーに配信するための戦略や技術的手法全般を指します。

<br>
今回はサービスとしてのCDNを具体的にどのように使うことができるのかをお話ししたいと思います。

## ダウンロードせずにフォントを利用する
WEBフォントを使えば、指定フォントがインストールされていないパソコンでも同じフォントを利用できます。
ただし会社によってそれぞれ規約がありますので、ご利用の際はご注意ください。

私は今回[Adobe Fonts](https://fonts.adobe.com/　"アドビフォンツ")を利用しました。

まずはアカウントを作成し、利用したいフォントを検索します。

![qiita3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3660432/d27d655f-fccd-4a4b-1061-71c0179815b3.png)


利用したいフォントを見つけたら、ページ下部にある[詳細]の部分にかいてあるコードをコピーし、使用したい部分のcssに貼りつけます。

![qiita8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3660432/c09f078e-63fc-6aec-b032-e9a8b760fd3d.png)


ページ上部に戻り、右上の[フォントを管理]をクリックし、[Webプロジェクト]をクリック。


![qiita5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3660432/a21fa4e4-2178-b5d6-861e-d464e879e541.png)

するとプロジェクトを埋め込みという文字の下に、コードが書かれています。
このコードを HTML の < head > タグ内にコピーします。

![qiita6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3660432/d06514b4-8590-719b-7dd9-a89e61c9edff.png)

以上の作業で簡単に外部で公開されているフォントを利用できます。

## アイコンの利用
次はアイコンをCDNで利用したいと思います。
例として[Font Awesome](https://fontawesome.com/　"フォントオーサム")を利用します。

まず以下のコードを HTML の < head > タグ内にコピーします。
```html 
<link href="https://use.fontawesome.com/releases/v6.2.0/css/all.css" rel="stylesheet">
```
次に使用するアイコンを選びます。色やアニメーションを指定した後は、右のHTMLのコードをHTML内の利用したい場所に貼りつけます。

![qiita10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3660432/d7b4dc5e-7d3e-2321-4088-c93c79d8874a.png)

![qiita11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3660432/90b700b6-3992-adb1-c24b-a3abc2502797.png)

制作したサイト内にアイコンがアニメーション付きで表示されます。

## 情報漏洩などの危険性も
CDNは基本的に、オリジンサーバーから配信されたコンテンツをそのままキャッシュし、そのままエンドユーザーへ配信します。アクセスしてきたエンドユーザー全員に同じコンテンツを配信する場合であれば問題ありません。
しかし通販サイトなどユーザーごとに違ったレスポンスを返すサイトの場合は、CDNのキャッシュしているコンテンツを違うユーザーにレスポンスをすることで情報漏洩につながることもあります。

>引用記事
[「メルカリ」の個人情報漏えい、原因はCDNキャッシュの仕様、技術的な詳細情報を公表／Impress Watch](https://internet.watch.impress.co.jp/docs/news/1066949.html)

# まとめ
今回HTMLなどの勉強をしてから、個人的に作成をして気づいたのがCDNの便利さです。
手軽に本格的なサイトを作成するのには欠かせないサービスだと感じました。

これからも利用していこうと思うので、セキュリティの危険性や規約などについても理解を深めていこうと思います。
【UE5】コントローラーでマウスカーソルを動かす

# 0. 最初

今回はマウスカーソルをコントローラーで操作する方法を共有します

# 1. 実装BP
引数には「スティックの2D情報」を入力
Sensitivityには「感度」を入力

![スクリーンショット 2024-01-21 011907.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1918199/15b3b32c-0319-4bf6-6680-20eb8decf88c.png)

以下のURLからBPがダウンロード可能です！
https://blueprintue.com/blueprint/-0ygf626/


# 2. 実行動画
![無題の動画 ‐ Clipchampで作成.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1918199/26a06c40-5c2a-510a-d128-8db143aca75d.gif)


# 3. 参考
 
参考にしたのは以下の動画です

https://www.youtube.com/watch?v=QdJJXQVf6J0
AndroidのデバッグにBlue Stacksをちょっとだけ楽に使う方法

純正のandroidのエミュレータって結構重いですよね。
体感ですが、純正のエミュレータよりBlueStacksの方が軽いですが純正に比べるとちょっと面倒くさい事があります。
それは、デバッグで使うにはadbに接続している必要があるのですが、adbに自動で繋いでくれないので手動でする必要があることと、起動するごとに接続先のポートが毎回変わる事です。

繋ぎ方から簡単に説明しておきますね。

1. エミュレータを起動して、設定画面を開きます
1. 赤枠の設定を行います

    ![BlueStacksConfig.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3322199/3944a0e2-87f0-889a-26c8-23f561b18406.png)


1. 以下のコマンドを実行する

    ```shell
    adb connect localhost:xxx
    ```
    この場合の、xxxは設定画面の「Android at 127.0.0.1:xxxに接続する」の表示のxxxを指定する必要があります


毎回手動でするのは、面倒くさいのでここに上がっているスクリプトを実行すると自動的に接続できるようにしてみました。


ソースはこちら

[https://github.com/chaftta/adb_connect_blue_stacks](https://github.com/chaftta/adb_connect_blue_stacks "blue stacks adb自動接続")

使い方は、以下のコマンドを実行すれば自動的にadbに接続されます
```shell
node adb_connect_blue_stacks.js path/to/bluestacks.conf
```
ちょっと長いので接続用のバッチとかビルドスクリプトに入れる感じで使う事を想定しています。

:::note info
注意点は、以下の3点です
- node.jsのパスが通っている事
- adbのパスが通っている事
- 正しいpath/to/bluestacks.confを指定する事(←私の環境では、BlueStacksのインストールパスにあるりました)
　
:::
Vue Props Example

# Propsとは何か
親コンポーネントから子コンポーネントを呼び出す際に、子コンポーネントに情報を受け渡しす仕組み
コンポーネント分割をするために習得必須
``` vue:ChildComponent.vue
<script setup lang='ts'>
const props = withDefaults(defineProps<{
  //　型定義
  user_id: string,
  message: string
}>(), {
  // 初期値設定
  message:''
});
</script>

<template>
<h1>メッセージ確認</h1>
title: {{ props.user_id }}<br>
message: {{ props.message }}
</template>

```

```vue:ParentComponent.vue
<script setup lang='ts'>
import { ref } from 'vue'
import ChildComponent from './ChildComponent.vue'

let userId = ref('');
let Message = ref('');
</script>

<template>
<div>
<h1>メッセージ入力</h1>
<v-input label='user_id' v-model='user_id"></v-input>
<v-input label='message' v-model='message"></v-input>
<!-- 子コンポーネントの呼び出し 呼び出し時にPropsでデータを渡す -->
<ChildComponent :user_id='userId' :message='Message'>
</div>
</template>
```
# 学び始めに躓いたとこと
- childrenコンポーネントにおけるprops定義の記述方法について、検索するとVue2系におけるOptions APIの書き方がたくさん出てくる Composition APIの書き方がわからず困った。
- ":user_id=" のように:を付けるのはscriptに記載している変数を参照するためにつける。つけなければ単なる文字列として扱われる。
 
# 参照情報
- [公式リファレンス](https://ja.vuejs.org/api/sfc-script-setup#defineprops-defineemits)
- [OptionsAPIとCompositionAPIの違い](https://jp.skilled.yashio-corp.com/media/vue/5876/)
トリボナビッチ数列

トリボナビッチ数列のプログラムをPython3で実装しました。

```Python3
###########################
## トリボナビッチ数列
##########################

#トリボナビッチ関数
def tri_r(num):
  if num <= 1:
    return 0
  if num == 2:
    return 1
  #再帰呼び出し  
  return(tri_r(num - 1) + tri_r(num - 2) + tri_r(num - 3))

#トリボナビッチ数列の7番目の項を求める
ans = tri_r(7)
# 数字を表示
print(ans)
```
google colaboratoryで別のアカウントのドライブを使いたい

# 計算中にgpuの上限がきてしまったので他のアカウントでgpuの使用制限から避難する
![Screen Shot 2024-01-20 at 23.45.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3473997/1c3d5888-71b8-19bc-e555-19fa816b4c21.png)
卒論の時期に重たい計算をした結果これです。数時間かけた計算が場合によってはパーなんて事がたまに起きます。すでに私は何度か起こしてます。
ただ今回使っているのはyolo、計算が中断しても途中から再開が出来る。後はGPUを使えない問題を解決できればいい。
サブのアカウントのcolaboratoryからメインアカウントのドライブにアクセスする方法があれば良いのでそこを解決します。


前提
googleのアカウントを二つもっていること

## ファイルを共有する。
今回、使用上限が来たgoogle colaboのアカウントと同じアカウントのgoogleドライブファイルを他のアカウントで使います。それぞれ使用制限が来てる方をメインとし、避難先のアカウントをサブと呼びます。

まずメインのアカウント(都合により一部の画像を消しています)
![Screen Shot 2024-01-21 at 0.23.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3473997/ef0e11e5-edd5-d7c4-40de-794a85af1c47.png)
今回サブのアカウントのcolaboからマウントしたいのはメインアカウントのドライブにある「研究」のファイル
![Screen Shot 2024-01-21 at 0.27.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3473997/d3b6febb-9446-ffe5-c77c-3feebc686bae.png)
ファイルを共有します。この際リンクで共有するのではなく「共有」をおしてください。
![Screen Shot 2024-01-21 at 0.27.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3473997/69d4f094-4626-45e3-7b0a-e7508bfed70f.png)
ここでサブのアカウントを入力します。私はすでに追加しているためオーナーとは別に編集者がいますが、この編集者がサブアカウントとなります。

## サブアカウントのドライブでショートカットを作成する。
![Screen Shot 2024-01-21 at 0.33.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3473997/969ade47-7b0e-317d-11dc-66006147a1a0.png)
次にサブアカウントのドライブに移ります。共有が出来ていると共有アイテムのところに当該ファイルが表示されます。この状態となっていれば上のタブよりショートカットを作成してください。
![Screen Shot 2024-01-21 at 0.38.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3473997/7d17387f-86cf-9877-3f86-951952631150.png)
場所を選択できますが、今回はCola何とかのファイルに作成します。
![Screen Shot 2024-01-21 at 0.37.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3473997/231b3372-46a3-632d-c5ae-d65c39fd6355.png)
記事のためにcolaboratoryの下にショートカットを作成しましたが、マイドライブの下にもあります。このショートカットは適宜消せるので問題ないです。今回例のために作成しただけなのでcolabo notebookの下においたショートカットはこの後すぐに削除しました。

あとはいつも通りに自分のドライブにマウントしてください。ここではサブのコラボからサブのドライブにマウントしています。
![Screen Shot 2024-01-21 at 0.42.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3473997/839bf4b8-5685-b824-45c5-d89689b480eb.png)
これでサブからメインのドライブを触れるようになります。
研究のドライブのパスがセルの結果上は.shortcutになっているのはあくまで共有によるものだからです。

---
以上です
---

あくまでメインアカウントのドライブにサブのコラボからファイル操作をする方法です。それ以上のことはありません。
参考

https://qiita.com/tbshiki/items/ed77f6f9f9ae3761b36d
ネーミングバトラー

Rubyでネーミングバトラーを作成しました。

```Ruby
# ネーミングバトラー


def hitpoint()
  hp_value = Random.new()
  hp_value = rand(200)
  return hp_value
end

def attach()
  attach_value = Random.new()
  attack_hp = rand(50)
  return attack_hp
end

puts "名前を入力してください"
str1 = gets.chomp
HP1 = hitpoint


puts "名前を入力してください"
str2 = gets.chomp
HP2 = hitpoint


while true
  puts str1 + "の攻撃"
  A_HP2 = attach
  HP2 = HP2 - A_HP2
  puts str2 + "に" + A_HP2.to_s + "ポイントのダメージ"
  if HP2 <= 0 then
    puts str1 + "の勝ちです"
    puts str1 + "の残りHPは" + HP1.to_s + "です"
    break
  end
  puts str2 + "の攻撃"
  A_HP1 = attach
  HP1 = HP1 - A_HP1
  puts str1 + "に" + A_HP2.to_s + "ポイントのダメージ"
  if HP1 <= 0 then
    puts str2 + "の勝ちです"
    puts str2 + "の残りHPは" + HP2.to_s + "です"
    break
  end
end
```
Nuxt3 + Vuetify3 で割り勘サイト作ってみる(寄り道編:Lottie）

# はじめに
Nuxt3 + Vuetify3で割り勘サイトを作ってみるシリーズの後続編。
とりあえず、楽して見た目を良くしたい。。。アニメーションを入れてみる。
昔ネイティブアプリ開発中に使ってたLottie使えないかな。。。

# パッケージを追加
vue3用のLottieパッケージ発見！
```json
"nuxt": "^2.15.8",
"vuetify": "^2.6.10",
"vue3-lottie": "^3.2.0", <-- 追加した
```
## 1.Hello Lottie!
やっぱりいつも通りで、、、
やり方は公式通りで、[Get Started](https://vue3-lottie.vercel.app/introduction/installation) を参照
```powershell
npm install vue3-lottie@latest --save
```
nuxt3の使い方は。。。公式にある！！ありがとう。
[Usage with Nuxt3](https://vue3-lottie.vercel.app/introduction/nuxt-3)
### ⅰ pluginsに追加
```typescript:plugins/Vue3Lottie.client.ts
import { Vue3Lottie } from 'vue3-lottie'

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.component('Vue3Lottie', Vue3Lottie)
})

```
### ⅱ script setupに宣言 + コンポーネントの定義 + jsonファイル指定
※事前に[Lottie公式](https://lottiefiles.com/jp/search?q=cong&category=animations&type=free) からアニメーションファイル(json)を入手して、assetsフォルダに anime.jsonを格納済み
公式にあるように <client-only>つけないとダメみたい。
```vue:pages/index.vue
<script setup lang="ts">
import { Vue3Lottie } from 'vue3-lottie'
import animejson from "~/assets/lottie/anime.json";
</script>

<template>
    <v-container>
        <v-row>
            <v-col cols="12">
                <client-only>
                    <Vue3Lottie
                    :animationData="animejson"
                    :loop="true"
                    :height="200"
                    :width="200"
                    />
                </client-only>
            </v-col>
        </v-row>
    </v-container>
</template>

```
👏動いた！
mlxのwhisperでリアルタイム文字起こしを試してみる

Whisperでのリアルタイム文字起こしの手法は「[Whisperを使ったリアルタイム音声認識と字幕描画方法の紹介](https://knowledge.sakura.ad.jp/34497/)」を参考にした。

mlxのwhisperセットアップは前回の記事を参考ください。

https://qiita.com/mbotsu/items/0c147a0524da4bd136fc

## 本題

ストリーミング処理を行うには音声の無音検知が必要となるので調べたところ、[faster-whisper](https://github.com/SYSTRAN/faster-whisper)でもVAD(Voice Activity Detector)に[Silero VAD](https://github.com/snakers4/silero-vad)を使っている。
それのJS版である[ricky0123/vad](https://github.com/ricky0123/vad)で[書かれているコード](https://knowledge.sakura.ad.jp/34497/)があったのでmlx用に一部書き直して試してみた。

### ファイル構成

```
├── server.py
├── static
│   └── jimaku.css
├── templates
│   └── index.html
```

### コード

```server.py
import os
import time
from flask import Flask, request, render_template
import whisper
import threading

UPLOAD_FOLDER = 'uploads'
ALLOWED_EXTENSIONS = {'m4a','mp3','wav'}
CSS_TEMPLATE_PATH = 'static/jimaku.css'
WHISPER_MODEL_NAME = "mlx-community/whisper-large-v3-mlx"

with open(CSS_TEMPLATE_PATH) as f:
   CSS_TEMPLATE = f.read()

print('loading whisper model', WHISPER_MODEL_NAME)

os.makedirs(UPLOAD_FOLDER, exist_ok=True)
app = Flask(__name__, static_url_path='/')
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

lock = threading.Lock()

@app.route('/')
def index():
   return render_template('index.html')

@app.route('/api/transcribe', methods=['POST'])
def transcribe():
   time_sta = time.perf_counter()
   print('start transcribe ' + str(time_sta))
   file = request.files['file']
   ext = file.filename.rsplit('.', 1)[1].lower()
   if ext and ext in ALLOWED_EXTENSIONS:
       filename = str(int(time.time())) + '.' + ext
       saved_filename = os.path.join(app.config['UPLOAD_FOLDER'], filename)
       file.save(saved_filename)
       lock.acquire()
       result = whisper.transcribe(saved_filename, path_or_hf_repo=WHISPER_MODEL_NAME, 
                                   language='ja', fp16=True, verbose=True)

       lock.release()
       return result, 200

   result={'error':'something wrong'}
   print(result)
   return result, 400

app.run(host='localhost', port=9000)
```

[元のコード](https://knowledge.sakura.ad.jp/34497/)から大きな変更はない。
mlxの`whisper.transcribe`は最初の一回目だけモデルの初期化を行うので、都度呼び出しても問題ないようだ。

```
positiveSpeechThreshold: 0.5,
negativeSpeechThreshold: 0.5 - 0.15,
preSpeechPadFrames: 2,
redemptionFrames: 8,
frameSamples: 1536,
minSpeechFrames: 3,
```
[元のコード](https://knowledge.sakura.ad.jp/34497/)のindex.htmlのパラメータ部分だけ[ricky0123/vad](https://github.com/ricky0123/vad)のデフォルト値にした方が私の環境ではいい感じに動いた。
あとは、`preSpeechPadFrames=2`にした方が喋り出しの取りこぼしが少ないように感じた。

## 感想など

mlxもv0.10.0で少し速くなったようだが、手元のM1 Macはメモリ8GBなのでlarge-v3を読み込むとスワップしまくりもあってとても遅い。
今回、ストリーミングの方法を調べて、音声検知を組み込むと結構いい感じにかつシンプルなコードで作れることがわかったので興味のある方は試してみると良い。
データベース設計について

# データベースの設計について
### 概要
データベース設計についての基礎的な流れなどを記載しております。学習のメモとして記事にしております。
主に、初学者向けの記事です。

## データベースとは
アプリで使用するデータが保管される、データの保存場所のこと
顧客情報や商品情報など、アプリで使用する情報やユーザが登録する情報などが格納されており
アプリは、そのデータを呼び出して使用している。
基本的にRDBと呼ばれるデータベースが一般的に使用されている
## データベースの構造
データベースはテーブルの集合である。
テーブルは、カラムとレコードで構成される
以下の例では、カラムがid,fruit,price、レコードが行の情報（id:1, fruit:apple, price:300）になる。
| id | fruit | price |
|:-:|:-:|:-:|
| １  |  apple | 300  |
|  2 | banana  | 250  |
|  3 |  grape |  400 |
|  4 |  orenge | 250  |

RDBにおいて、主キー（プライマリキー）の設計が必要となる。
主キーとは、レコードを個別に特定できる値のことで、上記の例だとidやfruitはレコードの特定に使用できる（データの値が被ることはない）が、priceは同じデータが複数あるため主キーにはならない（レコードを特定するキーとはならない）
上記のテーブルが複数あり、相互に関連しているデータの集合体をデータベースと呼ぶ。
アプリで使用する際は、データの格納がうまく設計されていないと、データに矛盾が生じシステムそのものの信頼に直結する重要な部分であるため、データベースの設計は開発においても重要なポイントであると言える。

## 開発手順
以下の開発手順で基本的に進められる。
1.要件定義
2.設計
3.実装
4.リリース
### 要件定義
なんのデータを保管するか、どの形式で保管するかを決める。
テーブルの数やカラムの種類など
### 設計
要件定義をもとにテーブルを設計する
### 実装〜リリース
設計をもとに、テーブルを定義し構築、リリースする

## データベース設計の手順
データベース設計の手順は以下の流れで行われる。
1.データ抽出
2.エンティティの定義
3.正規化
4.ER図
5.テーブル定義
6.インデックス定義
※1~4は論理設計、5~6は物理設計と呼ばれる

### データの抽出
使用するデータを洗い出し、テーブルに格納していく作業
要件に沿ったデータが揃っているかなどの確認を行う

### エンティティの定義
エンティティとは実体のことで、データを入れる箱のようなもの
参照：https://wa3.i-3-i.info/word11594.html

### 正規化
テーブルがデータの矛盾が起きないような構造になっているか正規化する。
・第一正規化
一つのセルに一つの値が入っている状態にする
・第二正規化
部分関数従属性の排除
※関数従属とは、主キーが定まれば列の値が一意に決まる状態のこと
　例：id=1が決まれば、appleが決まる
 部分関数従属性とは、複合キーが決まることで列の値が決まる状態のこと
 主キーだけでは列の値が全て決まるわけではなく、他のデータも必要になる状態のこと
・第三正規化
推移関数従属性の排除
※推移関数従属性とは、主キーが決まれば他の値Aが決まり、Aの値が決まれば値Bが決まる、というように
多段階で関数従属が起きる状態のこと

### ER図
テーブル同士の関係性を図で表したもの
基本的に１対nの関係で表されるが、n対n構造の物があった場合中間テーブルを作成する必要がある。

### テーブル定義
実際にテーブルに記載するルールを作成する
テーブル名、カラム名、データ型、NotNull、デフォルトなど

### インデックス定義
検索の処理速度を早めるために行うもの。

## まとめ
データベース設計の大まかな流れを記載しました。
論理設計→物理設計の流れで開発が行われているのが、なんとなく理解できたので
これから実際にデータテーブルの構築の学習を進めたいと思います。
データテーブルの構築の学習の中でSQLの知識も必要とわかったので、並行して SQLも学習も進めていく予定です。
PythonでAtCoderをたまにしか書かないのでコードのメモを置く

# はじめに
私は普段AtCoderをC言語で書くのだがPythonの方が効率的・書きやすそうなときにはPythonで書くことがある。だが、そもそもAtCoderを暇な時にしかやらないということもあり、よくPythonの書き方を忘れるので今回Qiitaに自分用のメモを書くことにした。

# Pythonメモ


```python:C言語で言うところのscanf()の書き方
a = input() #１つの変数の場合
a = int(input()) #1つの変数でかつ、型がintのとき
x, y = input().split() #２つの変数の場合
x, y = map(int, input().split()) #2つの変数でかつ、型がintのとき
a = list(map(int, input().split())) #１つの変数（配列）に複数入力する(型はint)
```

```python:配列
my_list = [1, 2, 3]
my_list.append(4)  #リストの末尾に4を追加

my_list = [1, 2, 4]
my_list.insert(2, 3)  #インデックス2の位置に3を挿入

my_list = [1, 2, 3, 5, 6]
my_list.insert(my_list.index(3) + 1, 4) # 3の後ろに4を追加

l = [0] * 10 #　l = [0,0,0,0,0,0,0,0,0,0] 

print(*l) # 0 0 0 0 0 0 0 0 0 0

sorted() #昇順ソート
sorted(x, reverse=True) #降順ソート


```


```python:とあるキーワードを含むかの探索
import re
 if re.search(r'\d{対象探索単語数}', 探索対象の変数):
    # または
 if re.search(r'\d{対象探索単語数}$', 探索対象の変数): # $をつけることで末尾を見る

# \wが\アルファベット文字(A-Z, a-z)、数字(0-9)、アンダースコア(_)の探索、\dは数字のみ
```

```python:文字の置き換え
a.replace('変更予定の単語','変更後の単語')
 # または
import re
re.sub(r'\d{}$', 変更後の単語, 変更予定の変数名)

```

```python:for
for i in range(開始インデックス, 終了インデックス, 増減率)

```

```python:その他早見表
# 配列の文字のそれぞれの個数を数えたい
count_dic = SortedDict()
for a in A:
    if a not in count_dic:
        count_dic[a] = 0
    count_dic[a] += 1

```
【2024年最新版】 CSM 認定スクラムマスター研修主体の比較

| 主体 | 期間 | 場所 | 講師 | 言語 | 費用(税込) | 記事 |
| --- | --- | --- | --- | --- | --- | --- |
| [株式会社Odd-e Japan](https://www.odd-e.jp/article_009_3/) | 6時間、5日 | オンライン | 江端一将 | 日本語 | 330,000円 | ・[１年ごしに認定スクラムマスター（CSM）研修を振り返ってみた](https://nttdocomo-developers.jp/entry/20231216_2)<br />・[認定スクラムマスターの研修と試験｜Certified ScrumMaster®：（CSM）](https://agile-ninja.net/certified-scrummaster-csm/)<br />・[研修前に確認したい！オンラインでの認定スクラムマスター(CSM)研修参加方法まとめ](https://techblog.cartaholdings.co.jp/entry/archives/5734#title3-1) |
| [アジャイル ビジネス インスティテュート株式会社](https://abi-agile.com/%E8%AA%8D%E5%AE%9A%E3%82%B9%E3%82%AF%E3%83%A9%E3%83%A0%E3%83%9E%E3%82%B9%E3%82%BF%E3%83%BC/) | 6時間、2日 | オンライン | Joe Justice | 日本語（同時通訳あり） | 161,139円 | ・[【認定スクラムマスター】CSMの研修概要と受講して感じたメリット・デメリット](https://do-scrum.com/%E3%80%90%E8%AA%8D%E5%AE%9A%E3%82%B9%E3%82%AF%E3%83%A9%E3%83%A0%E3%83%9E%E3%82%B9%E3%82%BF%E3%83%BC%E3%80%91csm%E3%81%AE%E7%A0%94%E4%BF%AE%E6%A6%82%E8%A6%81%E3%81%A8%E5%8F%97%E8%AC%9B%E3%81%97/)<br />・[認定スクラムマスターを受けた話](https://sqripts.com/2022/12/20/24516)<br />・[新卒スクラム未経験が認定スクラムマスタ(CSM)の研修を受けた話](https://zenn.dev/activecore/articles/d4873672015f23)<br />・[【CSM】認定スクラムマスター研修を受講してきた](https://sh-yoshida.hatenablog.com/entry/2021/09/03/090929)<br />・[スクラムマスター研修を受けて理解したスクラムマスターの役割とその先](https://tech.nri-net.com/entry/scrum_master_training) |
| [アギレルゴコンサルティング株式会社](https://www.jp.agilergo.com/online-csm-coplien-202402) | 4時間、4日 | オンライン | James Coplien / Mitch Lacey | 日本語（同時通訳あり） | 220,000円 | |
| [株式会社アトラクタ]() | 半日→1日→半日、3日 | オンライン/オンサイト | 原田騎郎 / 永瀬美穂 | 日本語 | 220,000円 | ・[なんちゃってスクラム実践者が CSM 研修を受けて痛感したこと（RSM と CSM の違いを添えて）](https://qiita.com/irongineer/items/d1c11f744dfdc67d4041)<br />・[CSM研修を受けてきた&CSMになった](https://blog.naosuke.me/entry/2021/06/20/193026) |
| [TIS株式会社（Platinum Edge, LLC共同開催）](https://www.tis.co.jp/seminar/training/Certified_ScrumMaster.html) | 4日 | オンライン | Mark C. Layton & Steve Ostermiller | 日本語（同時通訳あり） | 220,000円 | ・[CSM（認定スクラムマスター）の試験対策や難易度について](https://note.com/suke_maru/n/n411b1fd5d807) |

補足1: 研修を日本語で実施している主体を抽出してまとめました
補足2: 記事は2020年以降に投稿されたもの見つけられた限り整理しました
補足3: 2024年1月現在の情報（間違いがあればご指摘ください）
Nuxt3 + Vuetify3 + firebase で割り勘サイト作ってみる(環境構築編）

# はじめに
Nuxt2のサポートが終了して、Nuxt3の知識を深めなければと思いつつ、気がつけば１年経ちました、、、。去年の時点では開発中でまだまだ安定してないなっと思いつつ、そろそろ本腰を入れて勉強しようかなと思い、Nuxt3を用いて簡単なアプリを作成してみました。
※アプリ完成までのログを少しずつ上げてきます

# どんなの作ったの
とりあえず、最終形はこちらができました。
記事で、Vuetify Nuxt3 Firebase Lottieについて
書いていきたいとおもいます。
[wa/ri | みんなの建て替え、簡単に割り勘](https://wari.ynetlabo.net)

※プロジェクトは違いますが、同じ構成なので
全体図はこちらをどうぞ。
[Y.netLabo](https://web.ynetlabo.net)

https://github.com/yuuint/ynetlabo

# まずは開発ベースの作成
とりあえず最新版をチョイスしました。
```json
"nuxt": "^2.15.8",
"vuetify": "^2.6.10",
```
## 1.Hello Nuxt3!
これは当たり前だけど、問題なく動いた。
やり方は公式通りで、[Get Started](https://nuxt.com/docs/getting-started/installation) を参照
```powershell
npx nuxi@latest init <project-name>
cd <project-name>
npm install
npm run dev
```
## 2.Vuetify3入れてみる
前回構築した時はここからつまづいた。。。
こちらも公式参照しながらで、まずは [Get Started](https://vuetifyjs.com/en/getting-started/installation/#using-nuxt-3) を参照...Nuxt3の導入方法あるじゃん！！
```powershell
npm i -D vuetify vite-plugin-vuetify
npm i @mdi/font
```
nuxt.configを変更して。。。
```typescript:nuxt.config.ts
import vuetify, { transformAssetUrls } from 'vite-plugin-vuetify'
export default defineNuxtConfig({
  //...
  build: {
    transpile: ['vuetify'],
  },
  modules: [
    (_options, nuxt) => {
      nuxt.hooks.hook('vite:extendConfig', (config) => {
        // @ts-expect-error
        config.plugins.push(vuetify({ autoImport: true }))
      })
    },
    //...
  ],
  vite: {
    vue: {
      template: {
        transformAssetUrls,
      },
    },
  },
})
```
pluginsのディレクトリを作って、vuetify.tsを作成
```typescript:~/plugins/vuetify.ts
// import this after install `@mdi/font` package
import '@mdi/font/css/materialdesignicons.css'

import 'vuetify/styles'
import { createVuetify } from 'vuetify'

export default defineNuxtPlugin((app) => {
  const vuetify = createVuetify({})
  app.vueApp.use(vuetify)
})
```
layouts（全部の共通定義）は使いたいので、layouts/default.vue側に
v-appを定義して。。。
```vue:layouts/default.vue
<template>
  <v-app>
    <v-main>
        <slot />
    </v-main>
  </v-app>
</template>
```
```vue:app.vue
<template>
  <NuxtLayout>
    <NuxtPage />
  </NuxtLayout>
</template>
```
```vue:pages/index.vue
<template>
  <NuxtWelcome />
</template>
```
うごいた👏
jQuery モーダル画面

![スクリーンショット 2024-01-20 235700.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3666066/3b4a459d-a1d1-f0c6-5c23-26816d63bfcf.png)
以下はCSS
#graydisplay {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  max-width: 100%;
  height: 100%;
  background: rgba(0,0,0,0.45);
}
#graydisplay img {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  margin: auto;
  max-width: 90%;
  max-height: 90%;
}

以下はjQuery
$(function(){
  $("#main img").click(function() {
    $("#graydisplay").html($(this).prop('outerHTML'));
    $("#graydisplay").fadeIn(200);
  });
  $("#graydisplay, #graydisplay img").click(function() {
    $("#graydisplay").fadeOut(200);
  });
});
【Mac】特定のサイズのファイルを作成する方法


以下のコマンドを実行すると指定した容量のファイルを作成できます。

```terminal
mkfile サイズ ファイル名
```

```terminal
$ mkfile 3m test3m.jpeg

$ ls -l test3m.jpeg
-rw-------@ 1 sample  staff  3145728  9 27 00:20 test3m.jpeg

```
Angular 簡易サーバ（json-server）を使ってみる

# インストール
~~~
npm install -g json-server
~~~

# 返す値を登録する
保存場所は、.angularフォルダと同じところ
~~~db.json
{
  "data": [
    {
      "id": 1,
      "name": "test1"
    },
    {
      "id": 2,
      "name": "test2"
    }
  ]
}
~~~

# 起動する
~~~
json-server --watch db.json    
~~~
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3658170/d9df3102-fe31-d289-9416-5bf910175230.png)

# 確認する
ブラウザで確認する
~~~
http://localhost:3000/
~~~

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3658170/ed33c01c-5c2c-95f1-3db7-b42bfdf12af3.png)
C#（Serial.IO.Ports）とラズピコ間でシリアル通信が出来ない

## 発生した問題
Raspberry Pi Picoから垂れ流した通信が，C#（Serial.IO.Ports）のReadLineで取得できない．
シリアル通信のOpenはできていて，GetPortsでポートナンバーも取得できていたのに受信のみができない．
（できてはいるみたいだがConsoleに出しても何も表示されない）

## 解決方法
```C#:program.cs
SerialPort serial = new SerialPort(portName, baurate, Parity.None, 8, StopBits.One);
serial.DtrEnable = true;
serial.Open();
```
上記のように，DtrEnableプロパティをtrueにしてからOpenする．
最近発売されたArduino Rev4でこの問題が起こるという以下の記事を見つけもしかしたらと思いやってみたらビンゴ．
（https://qiita.com/mag2/items/d15bc3c9d66ce0c8f6b1）
ラズピコも割と新しいマイコンだし，最近発売されたマイコン使ってる人は同じことが起きているかも？

## あとがきと愚痴
最近Unityの勉強をしていて，Unity内で通信できなくて悩んでいました．
今更シリアル通信で躓くと思ってなかったので，Unity側で何か自分がミスってるのかと調べまくったり友人に聞いたり，でもなかなか解決しなかった，，
この問題，エラーとかでないから性質が悪い
「No such file or directory.と表示された！助けて！」と質問してくる人たちに伝えるべきだったと思うこと

# 「No such file or directory.と表示された！助けて！」
Linuxをちょっと触れば必ず遭遇するであろう有名エラーメッセージ。Permission Denied.と並んでよく見るけどこのエラーなら瞬殺できるから安心できるメッセージ。
さて、No such file or directory.・・・「そんなファイルもディレクトリもねーよ！」と、エラー原因を一言で伝えてくれる大変親切なこのエラーメッセージですが、弊案件では章タイトルのような質問がポコポコ起票されて有識者陣が対応に追われたということがありました。
一応有識者側陣営だった私の目線で、当時どうやったらよかったのかを考えてみました。

# 当時の対応（on Teams）
### 登場人物
私：一応Linux有識者側メンバ。一次対応窓口。
上司A：Linux有識者
上司B：Linux有識者
質問者：Linux初めて触ります。他チームの人。

### やりとり再現VTR
> 【質問用チャット】
質問者「○○.shを実行しようとしたところ、途中でエラーになりました。どうしたらいいですか？」
私「エラー時のログを連携してください」
質問者「以下です **（○○.sh実行時の標準出力結果の貼り付け）** 」
私「ﾐ°（脳が爆発した声）」
私「（送られてきたログを見てNo such file or directory.が出ていることを確認して）No such file or directoryが出てます。格納済みのファイルが不足していないか確認してもらえますか」
**上司A「あとそのくらいなら自分らで調査してもらえませんか？」**
質問者「無理です」

> 【内部チャット】
上司A「これ毎っ回質問されたらたまったもんじゃないよ」
上司B「さすがにこんなん見ればわかるんだからねぇ」
私「どないなっとんねんこの案件（そうっすね）」

# どうなったのか
私チーム「さすがにこのくらい自分らで見ろや」
質問側チーム「いやLinuxとか初めて触ったもん、知らんもん」
管理系チーム **「勉強資料作ってやるから勉強せんかい」**
私チーム「いいぞもっとやれ」
管理系チーム **「あ、勉強資料はお前ら（私チーム）が作ってね」**
私チーム「ﾐ°（脳が爆発した声）」

※プロジェクトが進むにつれ習熟度が上がり、この質問は飛んでこなくなりました。

# どうしたらよかったのか
### わからない側の気持ちを理解していなかった
こちらのチームはLinuxなんとなくわかる人が集まっていたので、「なんでこんなんも自分で調べないんだ？」という気持ちになっていました。冷静になってみれば、（例えば）突然python書けと言われてよくわからんままやってみたら自分らで調べろと言われたのと同じようなものです。なにがわからないのかわからない状態。
### そのくらいわかるよね、という気持ちになっていた
「英語とはいえそのままの意味なんだから見りゃわかるでしょ？」という思い込み。エラーメッセージ見て解決するなら世の中にこんなに技術how to記事が溢れるわけがない。

### 習熟度を上げる取り組みをすべきだった
これは私個人でどうこうできる問題ではない（そしてプロジェクトとしては取り組もうとして時間がなかったらしい）ですが、プロジェクト遂行にあたって必要な最低限の知識は早い段階で各々が身につけられるとBestだと感じました。世の中そんなに甘くないですが。

# まとめ
という、有識者初心者（謎概念）のやらかしを書き留めました。
三つ子の魂は百まで97年間続くのに、なぜ初心者の頃の魂は1年でなくなってしまうのでしょう。
- 自分が初心者だったときはどうしていたか、どうしたら理解できたのか
- なぜわからないのか
- 初心者はわからないのが当然である

ということを忘れずに、70歳くらいまで働いていきたいと思いました。
Java11　備忘録

自分用

## 1. ローカル変数の型推論

### 変数宣言

```java
var number = 42;
var pi = 3.14;
var grade = 'A';
var isJavaFun = true;
```

### コレクション

```java
var myList = List.of("Java", "is", "awesome");
var myMap = Map.of("key1", 1, "key2", 2);
```

## 2. ストリームAPIの新機能

### takeWhileメソッドとdropWhileメソッド

```java
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6);

// takeWhile: 条件を満たす間だけ要素を取得
List<Integer> result1 = numbers.stream()
                               .takeWhile(n -> n < 4)
                               .collect(Collectors.toList());
// 結果: [1, 2, 3]

// dropWhile: 条件を満たす間は要素をスキップ
List<Integer> result2 = numbers.stream()
                               .dropWhile(n -> n < 4)
                               .collect(Collectors.toList());
// 結果: [4, 5, 6]
```


## 3. HTTPクライアントの導入

```java
HttpClient client = HttpClient.newHttpClient();

HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://api.example.com/data"))
        .GET()
        .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

System.out.println("Response Code: " + response.statusCode());
System.out.println("Response Body: " + response.body());
```

## 4. メソッドの新機能

### インターフェースのprivateメソッド

```java
public interface MyInterface {
    default void publicMethod() {
        privateMethod();
        System.out.println("Public Method");
    }

    private void privateMethod() {
        System.out.println("Private Method");
    }
}
```

### ローカルメソッド

```java
public void myMethod() {
    String localVar = "Local Variable";

    // ローカルメソッド
    void printLocalVar() {
        System.out.println(localVar);
    }

    printLocalVar();
}
```

## 5. 文字列の新機能

### 文字列の連結

```java
String firstName = "John";
String lastName = "Doe";

String fullName = firstName + " " + lastName; // "John Doe"
```

### 文字列の繰り返し

```java
String repeatedText = "Java ".repeat(3); // "Java Java Java "
```

## 6. マルチスレッド処理

### フォーク/ジョインフレームワーク

```java
ForkJoinPool forkJoinPool = new ForkJoinPool();

int[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

int result = forkJoinPool.invoke(new MyRecursiveTask(array, 0, array.length));

System.out.println("Sum: " + result);
```

## 7. モジュールシステム

### モジュールの定義

```java
module com.example.mymodule {
    requires java.base;
    exports com.example.mypackage;
}
```

### モジュールの依存関係

```java
module com.example.myapp {
    requires com.example.mymodule;
}
```

## 8. ガベージコレクションの新機能

### Epsilonガベージコレクタ

```java
// ガベージコレクションの無効化
java -XX:+UseEpsilonGC MyApp.java
```

### Z Garbage Collector

```java
// ZGCの有効化
java -XX:+UseZGC MyApp.java
```

---
Rails DBのカラム名の変更方法

# はじめに
今回はRailsでのカラム名の変更について紹介します。
Railsは初心者のため間違っている箇所などあればコメントで教えてください。

# エラー
メソッドでエラーが出ていますよというエラーだったので、「メソッドで記載ミスがあったのか！」と思いメソッドを探しても何も見つからず、、
→結果的に、DBのカラム名が
正：completed
誤：comleted 
と「p」が抜けていたのが原因でした。
 
![スクリーンショット 2024-01-20 20.18.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1003708/52f4915b-9b62-d786-7b62-35e703e3dc6d.png)

# RailsでのDBカラム名の変更方法
### ①カラム名を変更するためのマイグレーションファイルを作成する
` $ rails g migration rename_変更前のカラム名_column_to_テーブル名`
```
$ rails g migration rename_comleted_column_to_tasks
```

### ②作成したマイグレーションファイルにカラム名の変更を記載する
` rename_column :テーブル名, :変更前のカラム名, :変更後のカラム名`
```
class RenameComletedColumnToTasks < ActiveRecord::Migration[7.1]
  def change
    rename_column :tasks, :comleted, :completed
  end
end
```

### ③マイグレーションファイルを実行してDBに反映させる
```
$ rails db:migrate
```

### マイグレーションの実行状況の確認
マイグレーションの実行状況は下記コマンドで確認することができます。
upは実行済み、downは未実行です。
```
$ rails db:migrate:status

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20240120071748  Create tasks
   up     20240120105844  Rename comleted column to tasks
```

# あとがき
本来はカラム名を間違えなければつまづかない箇所ですが、間違える→調査することで
プログラミングは学ぶことができるので良い勉強になりました。
このようなつまづいた内容も、これから記事にしていけたらと思います。

# 参考文献

https://karlley.hatenablog.jp/entry/2022/09/23/071136
何故Windows上でPythonを動かさず、WSL2+Dockerを使うのか

筆者の業務用PCのOSは現在Windows11です。
その中でPython関連のプログラムを動かす際にはWindows+Pythonという形で動かさず、
Windows Subsystem for Linux 2(以下WSL2と表記)内にDocker-CEをインストールし、
Dockerコンテナを建ててその中でPythonを動かしています。

「なぜわざわざ面倒くさそうなこの方法を使うのか？」について説明する機会があったため、整理を兼ねてこの記事を書くことにします。

# 1. Windows VS Linux
基本的にPythonの実行速度はWindowsよりもLinux環境のほうが速いというのが通説です。
(様々なエンジニアの方が検証されていますので、詳細は省きます)

またデファクトスタンダードもLinux環境であることから、インターネット上の情報もLinuxで動かすことを前提としているものが多い印象があります。

基本的に実行環境によってプログラムの書き方が大幅に変わることは無いのですが、
頻繁に行うことの多いファイル操作処理がWindowsとLinuxでは異なるため、共通化するのが難しい事情があったりもします。

こういった観点からLinux+Pythonを実行環境に選択しています。

# 2. Linuxを使うのは分かった。じゃあなんでWSL2を使うの？
Windowsマシン上でLinux環境を構築するには色々な方法があります。
1. そもそもデュアルブートしちゃう
完全に分けてしまうのが一番安全ではあるがハードルは一番高い
1. Hyper-V・VMWare・VirtualBox等のツール利用
ネットワーク設定周り・環境の使い回しが効きやすい等のメリットはあるが、Pythonを動かしたいだけなのでそこまでする必要は今回無いと判断。(あとWSL2より実行速度が多少遅いらしい(当方では未検証))
1. WSL2
Windows上から機能を有効化してインストールすれば使い始められる手軽さ。
起動も非常に速い。
メイン環境はDockerコンテナの中なので、ホストOS自体はシンプルな環境で良いという理由で選択。
(WSL2もHyper-Vを使っているがなぜ各種速度が向上するのかについて同僚の方より[WSLバージョンの比較](https://learn.microsoft.com/ja-jp/windows/wsl/compare-versions)のドキュメントを教えていただきました)

あくまでお手軽にPython＋Linuxの仮想環境を作ることが本目的なので、一番簡単なWSL2を使うというのが主な理由になります。

# 3. わざわざDockerを使う理由って？
WSL2でインストール出来るLinux(主にUbuntu20.04を使用)はピュアな環境で、例えば筆者のように深層機械学習用のPythonプログラムを効率的に動かしたいのであれば、GPUを計算に使えるように各種ドライバーをインストールしていく必要があります。

これが結構手間な作業であること、依存関係を壊すリスクもあることからWSL上のUbuntuに直接ドライバーやPythonをインストールして使うという選択肢は取りづらいです。

一方これらの手順をすっ飛ばしてコンテナさえ建ててしまえば、上記より簡単にPythonを動かせるのがDockerのメリットです。
またDockerfileやDocker-Compose等を使えば同様の環境が使い回せるし、失敗しても建て直しが簡単に出来ることも理由の一つです。

# 4. Docker使うんならWindows上からでも良いんでは？
Windows上でもDocker Desktopを使ってDocker環境は建てられるんですが、商用利用は基本的に有償なのがデメリットになります。
一方LinuxではDockerのCommunity Editionをインストールすれば無償で利用できます。

大規模開発となってくるとEnterprise Editionの利用が必要になる場合もあるでしょうが、今回の用途(機械学習用のPython環境を作る)ではCEで十分ではないでしょうか？

というわけで選択肢はWSL2+Dockerに限られることになります。

# おまけ. 強力すぎるVisual Studio Codeの拡張機能支援
筆者はエディタにVSCodeを使用していますが、Dockerの拡張機能をインストールすればマウスポチポチでDockerコンテナを立ち上げたり、消したりと様々な操作が簡単に出来ます。
PythonやJupyterその他諸々の拡張機能も用意されているので環境構築のハードルの低さから懐柔されまくってます…。

 ~~？？？「お前もVSCode使いにならないか？」~~ 

# まとめ
今回の疑問に対する回答を順番にしていくと上記のようになりますが、
結局のところ再配布可能・再現性が取りやすい環境を作るためのハードルの低い方法がDockerだったため、という理由が根底にはあります。

WSLも無くDockerも今ほどは普及していないぺーぺーだった頃は、デュアルブート環境にNvidia DriverやCUDA・cuDNNを入れては失敗して毎度痛い目を見ていたのですが、これが無くなるだけでも超絶ありがたいので…もうホントにホントに助かります～～～～～～(泣)

皆さんも使いましょう！
UiPathのアクティビティにおける部分一致と完全一致の分類

　最近、UiPathの開発でどのアクティビティが部分一致と完全一致が判断できずエラーの解消に時間がかかったのでここに現時点で判明しているUiPathにおける部分一致するものと完全一致するものを分類してみた。

# 部分一致するもの

・Excelアプリケーションスコープの範囲内の検索
・文字列の一致をチェック

# 完全一致するもの

・データテーブルを検索
・データテーブルをフィルターする。
・代入のアクティビティにデータテーブル型変数のdefaultviewメソッドを入力
・代入アクティビティにLINQの構文を代入

　以上
よく使用するGitコマンド

# はじめに
GitHubにソースコード変更履歴を残す際に使用する主なGitコマンドをアウトプットします．

# git init : ローカルリポジトリの新規作成
リポジトリとは，ファイルの変更履歴を記録する場所．カレントディレクトリに「.git」ディレクトリが生成され，この中で変更履歴の情報が管理される．

# git remote add : ローカルリポジトリをリモートリポジトリに登録
リモートリポジトリとは，オンライン上で変更履歴を管理する場所．GitHubが代表的．
#### 使い方
```terminal
$ git remote add origin リモートリポジトリのURL
```
リモートリポジトリにoriginという名前でアクセスできるようになる．originの部分は任意の名前をつけることができる．

# git add : ファイルの変更をステージングエリアへ追加
ステージングエリアとは，コミットするための控室．
`git add [ファイル名]`で対象ファイルを追加．
`git add .`でローカルリポジトリ内の全ファイルを追加できる．

# git commit : ローカルリポジトリにコミット
ステージングエリアに追加した変更履歴を，ローカルリポジトリに記録する．
#### 使い方
```terminal
$ git commit -m "コメント"
```
`-m "コメント"`を追加で書くことで，コメントを付与することができる．

# git push : リモートリポジトリにプッシュ
ローカルリポジトリの内容をリモートリポジトリに送信する．
#### 使い方
```terminal
git push origin master
```
originというリモートリポジトリに，masterブランチを送信するという意味．
ABC337をPythonで（A～F）

トヨタ自動車プログラミングコンテスト2024#1（AtCoder Beginner Contest 337）

https://atcoder.jp/contests/abc337

# A問題
実際に足して確かめる
```python:A
T, A = 0, 0
for _ in range(int(input())):
    x, y = map(int, input().split())
    T += x
    A += y

if T > A:
    print("Takahashi")
elif T == A:
    print("Draw")
else:
    print("Aoki")
```
# B問題
ABC文字列は並び替えても変わらないのでソートして比較する

ただ、本番は考えずに連続しているものを１つに圧縮している
```python:B
s = input()

t = []
for s_i in s:
    if t and t[-1] == s_i: continue
    else:
        t.append(s_i)

if t == sorted(t):
    print("Yes")
else:
    print("No")
```
# C問題
グラフとして考えると
親の情報が与えられるから、親から子へ辺を張って整理する問題になる
```python:C
n = int(input())
a = list(map(int, input().split()))

edge = [0] * (n + 1)
start = 0

for i, a_i in enumerate(a, 1):
    if a_i == -1:
        start = i
    else:
        edge[a_i] = i

ans = [start]
for _ in range(n - 1):
    ans.append(edge[ans[-1]])

print(*ans)
```
# D問題
縦と横のそれぞれで
連続する$k$個の区間で$x$が入らなくて且つ . の個数が最小のものはいくつかを求める
これは尺取り法を使えばいい
```python:D
def calc(s):
    if len(s) < k:
        return INF

    res = INF
    cnt = 0
    right = 0
    flag = 0
    for left in range(len(s)):
        while right < len(s) and right - left < k:
            if s[right] == "x":
                flag += 1
            elif s[right] == ".":
                cnt += 1
            right += 1
        if right - left == k and flag == 0:
            res = min(res, cnt)

        if s[left] == "x":
            flag -= 1
        elif s[left] == ".":
            cnt -= 1
    # print(s, res)
    return res


h, w, k = map(int, input().split())
field = [input() for _ in range(h)]

INF = float("inf")
ans = INF

for f_i in field:
    ans = min(ans, calc(f_i))

for i in range(w):
    lst = [f_i[i] for f_i in field]
    ans = min(ans, calc(lst))

print(ans if ans < INF else -1)
```
# E問題
毒ワイン問題という論理パズルとほぼ同じ問題である
よって、その解法に倣って２進数で考える
ただし、全く飲まない１本があっても判定はできるので最小人数は本数-1で考える
```python:E
n = int(input()) - 1

m = n.bit_length()
print(m)

for i in range(m):
    lst = []
    for j in range(1, n + 1):
        if j >> i & 1:
            lst.append(j)
    print(len(lst), *lst)

ans = int(input()[::-1], 2)
if ans == 0:
    print(n + 1)
else:
    print(ans)
```
# F問題
まず、$k$のことは十分大きいものとして考える
すると$c_i$の個数を事前に数えておけば、尺取りで連続区間に含まれる$m$種類が何かを調べてそれぞれの個数の和を求めればそれが答えになる

次に、$c_i$の個数$l$が$k$を超える時を考えると
1. 初めて空箱に$c_i$が入るときは、答えに$k$個加算される
1. $k+1$個目の時は、答えに$min(l-k, k)$個加算される
1. $n\times k+1$個の時は、答えに$min(l-n\times k,k)$個加算される

よって上をうまく組み込めばよい

```python:F
from collections import defaultdict

n, m, k = map(int, input().split())
c = list(map(int, input().split()))

d = dict()
for c_i in c:
    if c_i not in d:
        d[c_i] = 0
    d[c_i] += 1

cnt, kind = defaultdict(int), 0
ans = 0
right = 0
for left in range(n):
    while right - left < n and kind < m:
        c_r = c[right % n]
        if cnt[c_r] % k == 0:
            kind += 1
            ans += min(d[c_r] - cnt[c_r] // k * k, k)
        cnt[c_r] += 1
        right += 1

    print(ans)

    c_l = c[left]
    cnt[c_l] -= 1
    if cnt[c_l] % k == 0:
        kind -= 1
        ans -= min(d[c_l] - cnt[c_l] // k * k, k)
```
【Xcode】関数の引数などをコマンドで一括改行する

# はじめに
引数の多い関数を見やすいように改行することはよくありますよね。
でも、1つ1つ選択して改行するのめんどくさい、、、って思います。

![画面収録-2024-01-20-22.34.27.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/61a0fdff-8db6-4190-c5db-d9699b812aea.gif)

それXcodeのショートカットコマンドで解決できるんです！

# やりかた

対象箇所を選択して、

`control` + `M`

だけ

# おわり
printなど改行しなくていい箇所も改行されるので、選択箇所は考えたほうがいいですね

![画面収録-2024-01-20-22.37.29.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/26b1b5ac-3ffa-c911-e9ab-486d7c765d7f.gif)
GAS でForm => Google Spreadsheet 入力を作ってみた

# 目的


- Form に入力した値をGASを使って、spreadsheet に入力したかった
- spreadsheet に入力された内容をemailで送信 (これは後々の記事で書く)



# 前提

- Google Form の質問項目
    - 名前
    - 電話番号
    - メールアドレス
    - 備考

- A の列に関数を設定

B 列がBlank ではなかったら、数字を割り振る
```
    =IF(ISBLANK(B2),"",ROW()-1)
```
これをすることによって、GAS でid の割振りを敢えて避けてみました。
(正直どっちで実装した方が簡単なのかわからない)


# 実際のコード

```
// send form detail to spreadsheet
function submit(e) {

  // どのformかを指定
  const form = FormApp.openById("formID");
  
  //spreadsheetのIDを指定
  const sheet = SpreadsheetApp.openById("sheetID");

  //formAns の初期化
  formAns = [];

  //それぞれの回答を取得する変数
  const formResponses = form.getResponses(); 

  //記入するシートを用意
  const sht = sheet.getSheetByName('sheetの名前');

  // form 回答取得
  for (const formResponse of formResponses) {
          const itemResponses = formResponse.getItemResponses();
          for (const itemResponse of itemResponses) {
                  const response = itemResponse.getResponse()
                  formAns.push({response})
          }
  }

  // spreadsheet のlast のB range の列を取得する
  //A には関数を入れているので避けるために以下のような限定的な取得方法にしている
  lastsheet = sheet.getRange("B1").getNextDataCell(SpreadsheetApp.Direction.DOWN).getRow();
  
  //変数定義し直し(配列の形にするため)
  const formAnswer = formAns;
  
  // response => value のvalue部分だけを取得
  const FormValue = formAnswer.map((response)=> response.response);
  
  //formの受け取ったデータをそれぞれシートに記入
  for (const FormValues of FormValue) {
          sht.getRange(lastsheet + 1, 2).setValue(FormValue[0]);
          sht.getRange(lastsheet + 1, 3).setValue(FormValue[1]);
          sht.getRange(lastsheet + 1, 4).setValue(FormValue[2]);
          sht.getRange(lastsheet + 1, 5).setValue(FormValue[3]);       
  }
}

```

# まとめ

とりあえず初めてGAS で自動書き込みの機能を実装してみましたが、ここからスタートしてどんどんうまくなっていきたいです。もっとこうやったほうがいい箇所とかありましたら、教えていただきたいです。
いつの間にか Google Driveの画像にアクセスできなくなっている件


様々な記事で紹介されていた image読み込みの方法が2024年1月に使用できなくなっていた。

# 元々の読み込み方法について

https://qiita.com/TechnoKuRo/items/622c3dcc2ff3f7e09474

上記の記事を参考に `https://drive.google.com/uc?export=view&id= <ファイルID> `　を利用していたが、いつの間にか「403エラー」で表示されなくなってしまった。

```
<img src="https://drive.google.com/uc?export=view&id= <ファイルID>"/>
```


## 原因・解決
（情報提供に感謝！）

### ※ 2024年 1月 23日　追記

現状、仕様変更によって直リンクのアクセスはできなくなっているとのこと。

`<iframe>`を用いた以下の記述なら良いらしい。（これまで同様に全ての人にリンクアクセスの許可は必要）
```
<iframe src="https://drive.google.com/file/d/ <ファイルID> /preview" width="640" height="480" allow="autoplay"></iframe>
```

https://macoblog.com/googledrive-img-load/


### ※ 2024年 1月 28日 追記
画像データの場合、`https://drive.google.com/thumbnail?id=<ファイルID>` の記述で取り出すことができるらしい。

https://stackoverflow.com/a/77803819

ただし、音声 や 動画 については、今のところ解決策はないらしいです。

https://issuetracker.google.com/issues/319531488


# （未解決時）調べたこと

### 1. Google Chrome で URL を叩く

上手く表示できるが、 usercontent と download の箇所が異なっていた （リダイレクトが発生している？）

`https://drive.usercontent.google.com/download?id= <ファイルID> &export=view&authuser=0`

### 2. imgタグ、上記のURLに変更
以下の設定にするも、結局403エラー
（authuser=0　の有無も関係なさそう）

```
<img src="https://drive.usercontent.google.com/download?export=view&id= <ファイルID>" >
```

### 3. `https://drive.google.com/thumbnail?id=<ファイルID>` を試す

```
<img src="https://drive.google.com/thumbnail?id= <ファイルID>" />
```

↓ 表示できた！ 
![スクリーンショット 2024-01-29 0.42.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2847454/099c00de-792e-10e0-98c5-5ae88a8ea777.png)



-- --

自分のコードで困っていた画像取り出せない問題は、優しい方々のおかげで解決することができました。（多謝!)

そして、自分の情報検索スキルがまだまだだと痛感しました...。

こんな二つのいいきっかけを作れたアウトプットは大切だな...としみじみ思う今日この頃です。

-- --

「ブラウザや記述ミスによるエラーであり、本当は元々の方法で読み込める」や解決方法についてアドバイスがあればありがたいです
MacOSにwgrib2をインストールする方法

気象のグリッドデータに使われているファイルフォーマットであるGRIB2ファイルを操作するコマンド`wgrib2`をインストールする方法。

# 環境
- OS: MacOS Ventura 13.0.1 (Apple M1)

# 手順
## 必要なコマンドのインストール
`gcc` `gfortran` `cmake`をHomebrewでインストールする。Homebrewのインストールがまだの場合は先にインストールしておく（[公式サイト](https://brew.sh/ja/)）。
```
$ brew install gcc cmake
```

インストールされたかどうかは、
```
$ ls /opt/homebrew/bin
```
を実行した時に、`gcc-X` `gfortran-X` `cmake`（Xはバージョン番号。筆者の環境では`gcc-13` `gfortran-13`）があればOK。
```
$ which gcc-13
$ which gfortran-13
$ which cmake
```
で一応確認。

## wgrib2ファイルのダウンロード
[ダウンロードサイト](https://www.ftp.cpc.ncep.noaa.gov/wd51we/wgrib2/)から取得する。
```
$ curl https://www.ftp.cpc.ncep.noaa.gov/wd51we/wgrib2/wgrib2.tgz -o wgrib2.tgz
```
で取得できる。過去のバージョンも保存されているので必要に応じてそちらをダウンロードしても良いが、基本的には最新バージョンである`wgrib2.tgz`をダウンロードする（筆者がダウンロードしたのは`v3.1.3`）。

## コンパイルの準備
まずは、ファイルを解凍する。
```
$ tar -xvf wgrib2.tgz
```
解凍後、生成された`grib2`ディレクトリ内の`Makefile`を開き、
```makefile:makefile
# export CC=gcc
# export FC=gfortran
```
のコメントアウトを外し、バージョンに合わせて`gcc -> gcc-X` `gfortran -> gfortran-X`に書き換える。
次に、1000行目あたりにある、
```makefile:makefile
# export LDFLAGS="-L${lib}" && cd "${pngdir}" && export CPPFLAGS="${wCPPFLAGS}" && ${MAKE} -f scripts/makefile.darwin
```
のコメントアウトも外す。
次に、
```makefile:makefile
USE_G2CLIB=0
USE_PNG=1
USE_JASPER=0
USE_OPENJPEG=1
USE_AEC=1
```
あたりの`USE_PNG=1`を`USE_PNG=0`に書き換える。これをしないとコンパイルした時に、
```
Undefined symbols for architecture arm64:
  "_png_set_longjmp_fn", referenced from:
      _pngtoimage_internal in convertpng.c.o
      _imagetopng in convertpng.c.o
ld: symbol(s) not found for architecture arm64
collect2: error: ld returned 1 exit status
make[3]: *** [bin/opj_decompress] Error 1
make[2]: *** [src/bin/jp2/CMakeFiles/opj_decompress.dir/all] Error 2
make[1]: *** [all] Error 2
```
みたいなエラーが出た。
`makefile`を閉じ、
```
$ cd grib2
$ tar -xvf libpng-1.2.59.tar.gz
```
で解凍する（ファイル名はバージョンに合わせて適宜変更してください）。
生成された`libpng-1.2.59/makefile.darwin`を開き、
```makefile:makefile.darwin
# Utilities:
CC=cc
AR_RC=ar rc
MKDIR_P=mkdir -p
LN_SF=ln -sf
RANLIB=ranlib
RM_F=/bin/rm -f
```
あたりの`CC=cc`を`CC=gcc-X`に書き換える。
書き換えたら、
```
$ tar -cf libpng-1.2.59.tar libpng-1.2.59
$ gzip libpng-1.2.59.tar
```
で圧縮し直す（こちらもファイル名は適宜変更してください）。「ファイルがすでにあるよ」みたいな注意が出たら、`y`と答える。

## コンパイル
ここまでできたらいよいよ
```
$ make
```
でコンパイル。
完了したら、
```
$ ls wgrib2
```
で`wgrib2`が生成されていることを確認する。

## インストール
```
$ sudo install wgrib2/wgrib2 /usr/local/bin
```
でインストール。一応確認しておく。
```
$ which wgrib2
/usr/local/bin/wgrib2
$ wgrib2 --version
v3.1.3 10/2023  Wesley Ebisuzaki, Reinoud Bokhorst, John Howard, Jaakko Hyvätti, Dusan Jovic, Daniel Lee, Kristian Nilssen, Karl Pfeiffer, Pablo Romero, Manfred Schwarb, Gregor Schee, Arlindo da Silva, Niklas Sondell, Sam Trahan, George Trojan, Sergey Varlamov
```
めでたしめでたし。

# 参考文献
- [NOAA wgrib2](https://www.cpc.ncep.noaa.gov/products/wesley/wgrib2/)
- [How to install wgrib2 in OSX](https://bovineaerospace.wordpress.com/2017/08/20/how-to-install-wgrib2-in-osx/)
- [macOSへのwgrib・wgrib2 のインストール（Apple silicon）](https://qiita.com/nokos/items/511af147766ff25aef5e)
- [HOW TO INSTALL AND COMPILE WGRIB2 ON MACOS (EL CAPITAN THROUGH VENTURA)](https://theweatherguy.net/blog/weather-links-info/how-to-install-and-compile-wgrib2-on-mac-os-10-14-6-mojave/)
Ubuntu(CLI)上での.NET MAUI androidアプリ用ビルド環境構築方法

AndroidスマホのターミナルアプリからVPSに繋いでCLIでAndroidアプリを開発するための環境構築方法のメモ

## 動機
WPFアプリをテキストエディタのみで作れることから同じようにandroidアプリも作れないかと思い調べた。
結果できた。

## 試した環境
* Ubuntu 20.04.6(さくらVPS・コンソールのみ)
* Ubuntu 22.04.3 LTS(Windows11上のwslテスト環境・コンソールのみ)
(下のスクショはwslテスト環境)

# 最初にアップデート作業
```bash
sudo apt update && sudo apt upgrade -y
```

# 必要なSDKのインストール
"dotnet7" "android-sdk" "openjdk-21-jdk"の３つは最低必要
```bash
sudo apt install dotnet7 android-sdk openjdk-21-jdk
```

# .NET MAUIのテンプレートをインストールしてプロジェクトを生成
```bash
#.NET MAUIのテンプレートを探す
dotnet new search maui
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406587/5181dcf1-c30c-2cfd-ba66-c58e7eaa4715.png)
パッケージのところがインストールで必要なところ
```bash
#.NET MAUIのテンプレートをインストール
dotnet new install Microsoft.Maui.Templates
#testMAUIというプロジェクトを作成
dotnet new maui --name testMAUI
```

生成されたプロジェクトファイルを一部変更しておく
ターゲットの'net6.0-ios;net6.0-maccatalyst'を消しておかないと上手くビルドできない
```xml
<!-- csprojファイルのターゲットフレームワークを変更 -->
<TargetFrameworks>net6.0-android;net6.0-ios;net6.0-maccatalyst</TargetFrameworks>
<!-- ↓のように編集 -->
<TargetFrameworks>net7.0-android</TargetFrameworks>
```
# ビルドをしながら環境修正

### dotnet workloadにmaui-androidをインストール
この状態でビルドしてみる
```bash
cd testMAUI
dotnet build
```
するとエラー発生しビルド失敗
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406587/c5aef50f-1b9c-46ca-de74-dd3f1d2edd78.png)

エラー文を確認するとworkloadにmaui-androidをインストールするようメッセージが出るのでインストールを実行
```bash
dotnet workload install maui-android
dotnet workload restore testMAUI.csproj
#これでもビルドで同じエラー文が出る場合は↓を実行
dotnet workload repair
```
### 環境変数'AndroidSdkDirectory'の設定
ここでビルドを実行しても次は違うエラー文が発生する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406587/22e6147f-f801-6194-49ee-368e45e3864c.png)

このエラーには環境変数'AndroidSdkDirectory'にandroid-sdkのインストール場所を設定する
```bash
#.bashrc等に記載しておくとよい
export AndroidSdkDirectory=/usr/lib/android-sdk
```
### android-sdkに対応プラットフォームバージョンをインストール

再度ビルドするとさらにエラー文
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406587/f7701e8d-e848-a027-b7ea-9231de2f58e2.png)

これはandroid-sdkに対応プラットフォームバージョンが入っていないことが理由
CLIのみで目的のバージョンを入れる場合には[Android Studio公式](https://developer.android.com/studio?hl=ja#cmdline-tools)からcmdline-toolsをダウンロードしてandroid-sdk直下に展開する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406587/ad1fb8dd-b840-b6ac-0085-f8023d0b1e00.png)

```bash
#ダウンロードして
curl https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip?hl=ja --output ~/cmdlinetool.zip
#展開
sudo unzip ~/cmdlinetool.zip -d /usr/lib/android-sdk/
```
sdkmanagerを使用してプラットフォームバージョンをインストール
プラットフォームバージョンはエラーメッセージに出ていた「API レベル 数字」の数字の部分をandroid-数字の部分に当てはめる
```bash
sudo /usr/lib/android-sdk/cmdline-tools/bin/sdkmanager "platforms;android-33" --sdk_root=/usr/lib/android-sdk/
```

これでプロジェクトディレクトリでビルドコマンドを打つとapkファイルが生成されます。
```bash
#直接実機で動かす場合はreleaseにする
dotnet buid -c release
```

できあがったapkファイルは「"プロジェクトディレクトリ"/bin/Release/net**-android/」内にあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406587/077893f0-44bb-9382-eda6-a98a36804590.png)


以上!!
【UE5】今さらUnrealC++の変数と関数を打つ　１日目

# 0. 最初
UnrealC++を打ち始めて少しでも疑問に感じたこと
解決に時間がかかったエラーなどをまとめます
1日目は基礎も基礎です

# 1. 変数
 ```cpp
UPROPERTY(BlueprintCallable)
int32 HP;
 ```
UnrealC++では **int** は推奨されていません
UEが提供する **int32** や **int16** を使用することが推奨されています

**int型について**

https://docs.unrealengine.com/5.3/en-US/epic-cplusplus-coding-standard-for-unreal-engine/#portablec++code

**UPROPERTYについて**

https://zenn.dev/posita33/books/ue5_starter_cpp_and_bp_001/viewer/chap_90_cpp-uproperty

# 2. 関数
 ```cpp
UFUNCTION(BlueprintCallable)
void PrintHP(float duration);
 ```

**UFUNCTIONについて**

 https://zenn.dev/posita33/books/ue5_starter_cpp_and_bp_001/viewer/chap_90_cpp-ufunction

# 3. 各エラー

 **UFUNCTION** と **UFUNCTION** を間違えたときのエラー文は以下です

  関数に「UPROPERTY」をつける
```
Error: Found '(' when expecting ';' while parsing class 'クラス名'
```

 
 変数に「UFUNCTION」をつける

 ```
 Error: Found '=' when expecting '(' while parsing function '変数名' in class 'クラス名'
 ```

# 4. PendingKillについて

BPやUnralC++に共通してとても大切な機能です

https://hexadrive.jp/hexablog/program/43052/
MisskeyのカスタムCSSをアカウント毎に指定する

:::note warn
このカスタムCSSはデッキUIでのページ表示に動作を完全にカバーしているわけではありません。
:::

# この記事で対象とする読者
* Misskeyの同一サーバーにアカウントを持っている
* カスタムCSSを使って表示に変更を加えたい


# やり方
このようにカスタムCSSを指定しましょう。
```css
/*全てのユーザーに適用したいカスタムCSS*/

:root:has(:is(.xwq2R)[title="username1"]) {
    /*username1で適用したいカスタムCSS*/
}

:root:has(:is(.xwq2R)[title="username2"]) {
    /*username2で適用したいカスタムCSS*/
}
```

## カスタムCSSの意味(専門的)
このカスタムCSSでは、ユーザー名の確認を行います。`:root:has(:is(.xwq2R, .xdKUg)[title="username"])`という構文では、`:root`以下の`.xwq2R`クラスの要素の`title`属性の値が`username`である時の`:root`がセレクトされます。そして、`:root`がセレクトされているのであとは普通のCSSと同じように書けば適用されるという考えです。`.xwq2R`はナビゲーションバーの下部にあるアイコンを参照しています。`:is(.xwq2R)`としているのは、拡張性のためです。
現在CSSから使用しているユーザーを特定するのは難しく、UIがデッキの状態ではチャンネルをページ表示するとナビゲーションバーの下部にあるアイコンが表示されないのでこのカスタムCSSは機能しなくなります。
チベット語モデルTiBERTは「ད་རིང་ཨ་མ་ཤི་བ།」をどうトークナイズするのか

Yuan Sun, Sisi Liu, Junjie Deng, Xiaobing Zhao『[TiBERT: Tibetan Pre-trained Language Model](https://doi.org/10.48550/arXiv.2205.07303)』を読みつつ、この[TiBERT](https://tibert.cmli-nlp.com)のトークナイザがどうなっているのか気になった。というのも、論文には

> Sentencepiece provides four modes: bpe, unigram, char, and word. The bpe model can only generate a unique sub-word sequence for a sentence, while the unigram language model can generate multiple candidate sub-word sequences, which can make the model more robust to noise and sub-word segmentation errors. Therefore, this paper uses the unigram language model to generate a vocabulary which can cover 99.95% of the characters in the dataset. Finally, the Tibetan vocabulary we constructed contains 30,005 words.

という風に、SentencepieceのUnigramモデルを使っていることが明記されている。でも、モデルを[ダウンロード](https://tibert.cmli-nlp.com/model/TiBERT.zip)してみても、中は`config.json`と`pytorch.bin`と`vocab.txt`だけで、`spiece.model`が見当たらない。この`vocab.txt`は確かに30005行あって、最初の20行が

```
[PAD]
[UNK]
[CLS]
[SEP]
[MASK]
#




།
▁
་
་དང་
་།
འི་
་ལ་
་གྱི་
ས
་ཀྱི་
་ལ
་ནས་
```

となっている。うーん、[Sentencepieceは確率にもとづくトークナイザ](https://doi.org/10.18653/v1/P18-1007)なので、確率抜きにUnigramトークンだけ並べられても困るんだけど。まあ、仕方ないので、`BertTokenizerFast`でトークナイザを組み上げてみよう。Google Colaboratoryだと、こんな感じ。

```
!test -f TiBERT.zip || curl -LO https://tibert.cmli-nlp.com/model/TiBERT.zip
!test -d TiBERT（初始） || unzip TiBERT.zip
from transformers import BertTokenizerFast
tkz=BertTokenizerFast(vocab_file="TiBERT（初始）/vocab.txt",wordpieces_prefix="")
print(tkz.convert_ids_to_tokens(tkz("ད་རིང་ཨ་མ་ཤི་བ།")["input_ids"]))
```

チベット語の例文「ད་རིང་ཨ་མ་ཤི་བ།」をトークナイズしてみたところ、私(安岡孝一)の手元では以下の結果になった。

> ['[CLS]', 'ད', '་', 'རང', '་', 'ཨ', '་', 'མ', '་', 'ཤ', '་', 'བ', '།', '[SEP]']

いや、これでは細かすぎる。困ったな、どう組み上げれば、ちゃんとトークナイズできるんだろ。