OmniAICreator/Qiita-1.07M huggingface dataset:
【Nuxt3】入力フォームを作る

## はじめに
Nuxt3×Typescriptの勉強記事を投稿中ですが、ひとつ作りたいものがある。
勉強記事で使用しているvueプロジェクトを使って制作する。

完成品は


### 入力フォームのベースを作成する
まずはhtml部分から。

```vue
<template>
  <h2>入力フォーム</h2>
  <div id="addForm" class="p-addForm">
    <input type="checkbox">
    <label for="checkbox1">追加入力項目を表示する</label>
  </div>
  
  <div id="formArea" class="p-formArea">
    <form class="c-form p-form">
      <dl class="c-form__list p-form__list">
        <div class="c-form__item p-form__name">
          <dt class="c-form__title">
            <label class="c-form__label" for="lastName">お名前（姓）<span class="c-required">必須</span></label>
          </dt>
          <dd class="c-form__desc">
            <input class="c-form__input" type="text" id="lastName"  name="lastName">
          </dd>
        </div>
        <div class="c-form__item p-form__name">
          <dt class="c-form__title">
            <label class="c-form__label" for="firstName">お名前（名）<span class="c-required">必須</span></label>
          </dt>
          <dd class="c-form__desc">
            <input class="c-form__input" type="text" id="firstName" name="firstName">
          </dd>
        </div>
        <div class="c-form__item">
          <dt class="c-form__title">
            <label class="c-form__label" for="tell">電話番号</label>
          </dt>
          <dd class="c-form__desc">
            <input class="c-form__input" type="text" id="tell" name="tell">
          </dd>
        </div>
        <div class="c-form__item">
          <dt class="c-form__title">
            <label class="c-form__label" for="email">メールアドレス<span class="c-required">必須</span></label>
          </dt>
          <dd class="c-form__desc">
            <input class="c-form__input" type="text" id="email" name="email">
          </dd>
        </div>
      </dl>
    </form>

    
  </div>
</template>

<style scoped lang="scss">
/* reset */
* {
  box-sizing: border-box;
}
dd {
  margin: 0px;
}

/* component */
.c-form {
  margin-top: 32px;
  padding: 32px;
  background-color: #eee;
  &__list {
    display: flex;
    flex-wrap: wrap;
  }
  &__input {
    width: 100%;
    padding: 10px;
  }
  &__item {
    position: relative;
    display: block;
    width: 100%;
    margin-bottom: 16px;
  }
  &__title {
    position: absolute;
    top: 50%;
    left: 1em;
    transform: translateY(-50%);
  }
}
.c-required {
  color: red;
  font-weight: bold;
  &::before {
    content: "*";
  }
}

/* pages */
.p-addForm {
  max-width: 650px;
  margin: 0 auto;
}
.p-form{
  &__list {
    max-width: 650px;
    margin: 0 auto;
  }
  &__name {
    width: 47%;
  }
  &__name + &__name {
    margin-left: 6%;
  }
}
</style>
```
![スクリーンショット 2024-01-09 1.44.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524465/f6546577-7322-a5a1-1411-f74b485b5028.png)

### やりたいこと
1. はじめは入力フォーム（グレーの部分）は非表示
1. 「追加入力項目を表示する」にチェックを入れると入力フォームが表示されるようにする
1. input部分をクリックすると、「お名前（姓）※必須」が入力部分上に移動するアニメーションをつける
1. （文字サイズ調整）


### 今回はここまで
tsでやりたいができるかな・・・調べながらこつこつやってみよう。
【React】ウィンドウを閉じる際に処理を実行する方法

以下のように記述することでウィンドウ（タブ）を閉じる際に実行される処理を定義できます。

```js
  const handleBeforeUnload = () => {
    console.log('beforeunload')
  }
  
  useEffect(() => {
    window.addEventListener('beforeunload', handleBeforeUnload)

    return () => {
      window.removeEventListener('beforeunload', handleBeforeUnload)
    }
  }, [handleBeforeUnload])
```

https://developer.mozilla.org/ja/docs/Web/API/Window/beforeunload_event
誤解されがちなカプセル化

## はじめに

オブジェクト指向について勉強すると、「カプセル化」という単語に必ず出会うと思いますが、なぜかその意味を間違って理解している人がいます。
「カプセル化」自体はそれほど難しい話ではないですが、これを知ってるかどうかでコードの品質が変わってくると考えているので、本記事でまとめたいと思います。

## よくある誤った「カプセル化」の理解

よくある誤った理解は以下です。

「クラスのフィールドをprivateで定義し、getter、setterを使用してprivateなフィールドにアクセスしたり、値を変更すること」

このような誤った理解をする人がいるのは、情報が不足しすぎている記事や、誤った理解を伝えている人がいることが原因なのかなと思っています。

## じゃあ、カプセル化って何なの？

カプセル化とは、クラスがもつデータ（フィールド）と（メソッド内の）処理を外部から隠蔽することです。

例えば、「りんご」というクラスがあったとして、そのクラスに「糖度を計算する」というメソッドがあるとします。
外部からはこのメソッドを使用して、糖度を取得することはできますが、何の値を使ってどのように糖度を計算したかは隠蔽されます。

このようにすることで、各クラスの責務を明確化し、独立性を高めることができます。
カプセル化を行わないと、どこにどの実装があって影響範囲がどこまであるのかが不明瞭になり、可読性が低くバグの生じやすいコードになってしまいます。

## getter、setterは極力使わない

上記のカプセル化を踏まえて、「外部から隠蔽することはわかった。じゃあgetter、setterってなに？」と思った人もいると思います。
結論、getterは極力使うべきでなく、setterは使うべきでないです。
理由は簡単で、これらを使用することでクラス内のロジックが外部に漏れ始めます。隠蔽して独立性を高めることに反しますね。

ただ、getterに関しては、実装が必要な時もあると思います。その時は、getterで取得した値でクラス内で行うべき処理を実装しないように気をつけましょう。

setterは完全な悪手で、そもそもオブジェクトは不変（immutable）であるべきです。
「じゃあ、フィールドの値を更新する必要があるときはどうするんだ！」という人がいるかもしれませんが、その場合は新しいオブジェクトを生成するように設計しましょう。

Personクラスのnameフィールドを変更する際の例を以下に示します。

```java
public final Person {
    String name;
    LocalDate birthday;

    Person(String name, LocalDate birthday) {
        this.name = name;
        this.birthday = birthday;
    }

    public Person updateName(String name) {
        return Person(name, birthday);
    }
}
```

## おわりに

オブジェクト指向を学ぶ上でも、少しでも良いコードを書く上でもカプセル化は大切なので、少しでも誤解する人が減ると嬉しいなと思います！
Misskeyのプラグイン導入の方法

# はじめに
これはMisskeyのPluginの導入方法に関して書いた解説ページです。

# 導入方法

* 手動
* 自動

# プラグインの導入方法
## 手動
### step1: プラグインのコードの取得
プラグインのコードを取得する必要があります。
プラグインのコードを全てコピーしてください。

### step2: インストールページに移動
`https://[host]/settings/plugin/install`にアクセスししてください。
ただし、`[host]`の部分はサーバーによって異なります。
`misskey.io`なら`[host]`の部分を`misskey.io`に変更した`https://misskey.io/settings/plugin/install`にアクセスしましょう。
遷移で移動する場合は、歯車アイコンの[設定]→クライアント設定の[プラグイン]→[プラグインのインストール]、の順で移動した場所です。

### step3: インストール
先ほどコピーしたプラグインのコードをテキストエリアにペーストします。
その後、[✅インストール]となっているボタンをクリックします。

### step4: 権限の確認
もし、ここで「アカウントへのアクセス許可」というポップアップが表示された場合、権限の内容を確認したのち、**権限の内容に同意したのならば**右上の✅を押してください。
**プラグインが権限を要求していない場合は、このポップアップは表示されません**。ポップアップが表示されない場合もありますが、正常な動きです。

:::note warn
ここで要求される権限は十分確認しましょう。権限の内容次第ではノートの作成や削除、アカウントのフォロー、リアクションの追加などで**あなたをスパムアカウントに仕立て上げてしまうこともできるでしょう**。
ツイッターでも[このような事例](https://shindanmaker.com/twitterAccountCompromised)があったように、権限を不正に悪用するとスパム行為を行うことが可能になります。何の目的のためにその権限が必要なのかを今一度確認しましょう。また、そのプラグインが本当に信用できるものかを、知識のある人に確認してもらうのも有効です。
:::

## 自動
:::note warn
この項目は未検証です。
:::

https://misskey-hub.net/ja/docs/for-developers/publish-on-your-website/

上の記事にある方法でプラグインが配布されている場合には簡易にプラグインをインストールできます。もし、権限を要求するプラグインの場合であれば、前章の「step4: 権限の確認」と同じことをしてください。

# プラグインの設定
`https://[host]/settings/plugin`にアクセスししてください。
ただし、`[host]`の部分はサーバーによって異なります。
`misskey.io`なら`[host]`の部分を`misskey.io`に変更した`https://misskey.io/settings/plugin`にアクセスしましょう。
遷移で移動する場合は、歯車アイコンの[設定]→クライアント設定の[プラグイン]、の順で移動した場所です。

管理の項目にインストールされたプラグインが表示されます。ここから、プラグインに関する以下の情報が見られます。

- プラグインの名前
- プラグインのバージョン
- プラグインの作者
- プラグインの説明
- プラグインが必要とする権限
- プラグインのソース

そして以下の操作ができます。

- プラグインをアクティブにするかの設定
- プラグインの設定の設定
- プラグインのアンインストール

今回はプラグインの設定を確認していきます。
それぞれのプラグインの[設定]をクリックなどするとポップアップが表示されます。
もし、設定項目があれば、スイッチや入力欄などが表示されます。
それぞれ指示に従って設定して、それを反映する場合にはポップアップ右上の✅を押してください。
すると、ページの再読み込みの後、その設定が有効になります。

# プラグインの無効化
プラグインを一時的に無効化する場合には、プラグインの[アクティブにする]をオフにしてください。すると、プラグイン自体は削除されずにプラグインを無効にできます。また、有効化する場合は同様の方法で[アクティブにする]をオンにすることで有効にすることができます。
UE5 Foloage

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/249684/8e4607b1-514d-7804-41c9-226c8fe7db6d.png)

* PaintするときはFoliageがチェック状態でないといけない
* Eraseするときもチェック状態でないといけない
* EraseDensityは0.0
* FiltersのFoliageのチェックをはずした状態だと上に重ならない


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/249684/554cc03a-b062-8b23-3672-d76b549d12f3.png)

M_GrassLand_02_Landscape　をLandscapeのマテリアルにセット
レイヤーを追加
Llama 2向けのDatasetsを作成してHugging Faceに登録するまで

## はじめに
Llama 2をFinetuningする記事をいくつか書いてきました。

https://qiita.com/yn01/items/1aea596779df19d611c0

https://qiita.com/yn01/items/46b193de2f4fde60ecb9

Finetuningをしていると、
* 「欲しいDatasetsが見つからないなぁ」
* 「これもうちょっと〜だったら使えるのに」
といったことが出てきます。

であれば…

ということで、自分でDatasetsを作ってしまえばいいということで。

今回はLlama 2向けのDatasetsを作成して、Hugging Faceにアップロードをするところまでやってみます。

## 概要
* Llama 2向けのDatasetsを手作業で作成する
* 作成したDatasetsをHugging Faceで公開する

## 手順

### ０．準備
今回は下記のアカウントが必要です。
* Google Colab

https://colab.research.google.com/?hl=ja

* Hugging Face

https://huggingface.co/

Hugging Faceにログインしたら、アクセストークンを取得しておきましょう
アクセストークンは`Settings`から`Access Tokens`で作成できます

### １．トレーニング用のDatasetsの作成
作成方法は何通りかあるんですが、今回は手作業でトレーニング用のDatasetsを作成してみます。

まずはDatasetsの実体となる、jsonl形式のファイルを作成します。
ファイル名はひとまず何でもOKです。

```
ファイル名.jsonl
```

このファイルを開いて、トレーニングさせたい内容を記載します。
1レコードを1行として、レコード数分の行数を書いていきます。

```
{"text": "### Instruction: 【システムプロンプト】 ### Input: 【プロンプト1】 ### Response: 【回答1】"}
{"text": "### Instruction: 【システムプロンプト】 ### Input: 【プロンプト2】 ### Response: 【回答2】"}
{"text": "### Instruction: 【システムプロンプト】 ### Input: 【プロンプト3】 ### Response: 【回答3】"}
…
{"text": "### Instruction: 【システムプロンプト】 ### Input: 【プロンプトN】 ### Response: 【回答N】"}
```

Google Colabを開き、任意のディレクトリに格納しておきます。
これでDatasetsをHugging Faceへ登録する準備が完了です！

### ２．Hugging Faceへのログイン

Hugging FaceへDatasetsを登録するには、`huggingface-cli`を使います。

Google ColabからHugging Faceにログインしておきましょう。

```
pip install huggingface_hub
huggingface-cli login
```

アクセストークンを聞かれるので、事前に確認しておいたアクセストークンを入力してEnter。
これでHugging Faceへログインできるはず

### ３．登録用のDatasetsをHugging Face側に作成する

次に、１で作成したDatasets（jsonlファイル）をアップロードする先、Hugging FaceにDatasetsを作成しておきます。

これをやっておかないと、１で作成したDatasets（jsonlファイル）のアップロード先が指定できないです。

Hugging Faceを開いたら、画面左上の`+New`から`Dataset`を選択。

![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93776/55e7ea8e-dc1f-8d2b-4ac1-2036cc11b82e.png)

Datasetを作成しておきます。

### ４．DatasetsをHugging Faceへ登録する

ここまできたら、Datasetsの登録に進んでいきます。
いよいよ！

Google Colabから下記のコードを実行して、Hugging FaceへDatasets（jsonlファイル）を登録します。

```
import datasets
DATA_PATH = ""
dataset = datasets.load_dataset("json", data_files = DATA_PATH)
dataset.push_to_hub("")
```

`DATA_PATH`で作成したDatasets（jsonlファイル）を指定。
`dataset.push_to_hub`で、登録先のHugging FaceのDatasetを指定する感じ。

datasetsがない、と怒られたら下記で`pip install`しとく。

```
!pip install datasets
```

### ５．登録されたDatasetsを確認してみる
登録できたかどうか、Hugging Faceで確認をしてみる。

３で登録したDatasetのページを開いて、登録したDatasetsが表示されていれば正常に完了したことになります。

あとはこのDatasetsを使って煮るなり焼くなりする。

## まとめ

やってみると思っていたよりスムーズにできると思います。
Hugging Face様様ですね。
おうちKubernetes上のアプリケーションをcert-managerでhttps化する

### やりたいこと
前回の記事の続き
https://qiita.com/Rocky-6/items/33a41128423033d4ab1b

おうちKubernetesクラスター内のアプリケーションをcert-managerでhttps化したい。

### ポリシーの設定
前回の記事でIngressリソースを作成すると、Route53に自動でレコードが登録されるようになりました。
今回はcert-managerがレコードを追加できるようにポリシーを設定します。
https://cert-manager.io/docs/configuration/acme/dns01/route53/
```
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "route53:GetChange",
      "Resource": "arn:aws:route53:::change/*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "route53:ChangeResourceRecordSets",
        "route53:ListResourceRecordSets"
      ],
      "Resource": "arn:aws:route53:::hostedzone/*"
    },
    {
      "Effect": "Allow",
      "Action": "route53:ListHostedZonesByName",
      "Resource": "*"
    }
  ]
}
```

前回の記事で作ったユーザーにポリシーをアタッチします。（省略）

### cert-managerのデプロイ
チュートリアル通りインストールします。
```
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.3/cert-manager.yaml
```

### Cluster Issuerの作成
このマニフェストでcert-managerは指定されたドメインに対してLet's Encryptから証明書を自動的に発行および更新できるようになります。
```
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
  # name: letsencrypt-prod - 本番
spec:
  acme:
    email: example@email.com
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    # server: https://acme-v02.api.letsencrypt.org/directory - 本番
    privateKeySecretRef:
      name: letsencrypt-staging
      # name: letsencrypt-prod - 本番
    solvers:
      - selector:
          dnsZones:
            - example.com - 適宜変更
        dns01:
          route53:
            region: ap-northeast-1
            accessKeyIDSecretRef:
              name: aws-credentials
              key: aws-access-key-id
            secretAccessKeySecretRef:
              name: aws-credentials
              key: aws-secret-access-key
```

### Ingressの作成
前回作ったIngressにcert-managerの設定について追加します。
```
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: apple
  namespace: sandbox
  labels:
    name: apple
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod - 追加

spec:
  ingressClassName: nginx
  tls: --------------------------|
    - hosts:                     |
        - "*.example.com"        | 追加
        - apple.example.com      |
      secretName: apple ---------|
  rules:
    - host: apple.example.com
      http:
        paths:
          - pathType: Prefix
            path: "/"
            backend:
              service:
                name: apple
                port:
                  number: 5678
```

できました
![スクリーンショット 2024-01-08 234654.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2733784/ac029d30-2fda-a1f3-f64d-4fcdc661dc1e.png)

### 詰まったところ
~~今度書く~~
「平均への回帰」を具体例で確認（統計検定1級）

こんにちは！Ariaです。

「平均への回帰」と呼ばれる統計学上の現象を解説します。

注目している対象（ここでは人とします）$i$に対して、同様の検査を時間をおいて2回実施する場合ときなど、1回目と2回目の測定値の差分の意味に注目したい時があります。
ここでは、母集団の分布が既知のケースで考えます。

（とくに、1回目に極端な値が計測されたと考えられる場合、2回目とのギャップが偶然誤差なのか「平均への回帰」という現象によるものなのか見極めたい時があります）

# 結論
注目している個人$i$が属していると想定される母集団の分布から、条件付き分布を導出し、条件付き期待値と2回目の実現値の差を確認することで、1回目と2回目の差が誤差（偶然の変動によるもの）なのか、想定しているエフェクトの大きさによる変化(例えば、観測対象の人が2回目の測定までに実施した食事療法の効果)なのかを捉えることができます。


# 例題
タケシさんは血圧の検査を2度受けました。タケシさんは最初の検査で血圧が125mmHgでした。血圧を下げるよう医者にアドバイスされたため、タケシさんなりに血と涙の努力をし、2回目の検査では120mmHgとなりました。
さて、タケシさんは血圧が5mmHg下がったことをよろこんでいいのでしょうか？

なお、
1回目の検査値をX、2回目をYとし、$(X, Y)$は母集団で二変量正規分布$N(\mu_X, \mu_Y, \sigma_X, \sigma_Y, \sigma_{XY})$に従うと仮定します。

タケシさんが属する母集団において、2回目の測定では、母平均は$\mu_X = \mu_Y=$ 115, 母標準偏差は$\sigma_X=\sigma_Y=$ 10 であり、XとYの母相関係数$\rho_{XY}$ は $0.8$ とします。

### 問1
母集団全体における2回の血圧の測定値の差$D=Y-X$の期待値と分散はいくらか。また、母集団全体で確率$P(D\le-5)$はいくらか。

### 問1　（解答例）
一般に、差$ D = Y - X $の期待値と分散は
$$E[D]=E[Y-X]=E[Y]-E[X]$$
および
$$V[D]=V[Y-X]=V[Y]+V[X]+2 \mathrm{Cov}[X, Y]$$
であるので、数値を代入して
$$E[D]=115 - 115 = 0$$

$$V[D]=10^2+10^2-2 \times 10 \times 10 \times 0.8=40$$
となる。よって、ZをN(0, 1)に従う確率変数として、求める確率は
$$P(D\le-5)=P(\frac{D-0}{\sqrt{40}}\le\frac{-5-0}{\sqrt{40}})=P(Z\le-\frac{1}{4\sqrt{5}})$$
$$\approx P(Z\le-0.11)\approx0.46$$
となる。


### 問2
1回目の測定値Xが125の人の2回目の測定値Yの条件付き期待値$E[Y|X=125]$と条件付き分散$V[Y|X=125]$はそれぞれいくらか。タケシさんの2回目の測定値が5mmHg下がった内、「平均への回帰」と見なせる分はいくらか？

### 問2（解）
$X=x$が与えられた時のYの条件付き分布の関係式[^1]より、
分布は$N（\alpha+\beta x,\  \sigma^2）$であり、
$$\beta=\sigma_{XY}/\sigma_X^2,\ \ \alpha=\mu_Y-\beta\mu_X, \ \ \sigma^2=\sigma_Y^2-\sigma_{XY}^2/\sigma_X^2$$
となる。それぞれに各数値を代入する。
[^1]: 条件付き分布の関係式の導出はこちらを参照。（すみません工事中（死語）です）

$$\beta = 80/10^2=0.8, \ \ \alpha=115-0.8\times115=23,\ \ \sigma^2=10^2-80^2/10^2=36$$
となる。よって、X=120のときのYの条件付き期待値及び条件付き分散はそれぞれ
$$E[E|X=125]=23+0.8\times 125=123,\ \ V[Y|X=125]=36$$
となり、条件付き分布は$N(123, 36)となる。ここで条件付き分散はXの値によらないことに注意。

1回目の測定値が$X=125$のときの2回目の測定値Yの条件付き期待値$E[Y|X=125]=123$は、母集団全体での2回目の測定値の全平均115よりも大きいものの、その全平均との差123-115=8は1回目の測定値X=125の全平均との差125-115＝10よりも小さい。2回目の測定値の条件付き期待値は全平均の値に近づくことから、これを平均への回帰という（regression to the mean)。
Aさんの場合、2回目の測定値は120であり、血圧は5下がったが、X=125の人たちの2回目の測定値の条件付き期待値は123なので、Aさんの下降分の5のうち平均への回帰分は2とみなされ、Aさんの努力によるところ（または偶然の変動）は3となる。


### おまけ


（ちなみにWikipediaによると、ここの「回帰」という表現が回帰分析の語源になったらしいです。意味は全然違いますが）
https://ja.wikipedia.org/wiki/%E5%B9%B3%E5%9D%87%E3%81%B8%E3%81%AE%E5%9B%9E%E5%B8%B0

##

お読みいただきありがとうございました！
永遠に勉強中のみなので、誤りを発見した場合などご指摘いった抱けると幸いです。

ではまた。
asdf: No such file or directoryとなって、asdfが使えなくなった

## 背景
asdfを使って環境構築をしていたのだが、ある日、asdfが使えなくなり、`yarn start`などのnodeのコマンドが使えなくなった。

## 原因
Homebreでasdfをバージョンアップしたことで、asdfはバージョンアップしたが、asdfのshimが古いパスを参照している可能性があったっぽい。

```terminal:エラー
/Users/hoge/.asdf/shims/node: line 7: /usr/local/Cellar/asdf/0.10.2/libexec/bin/asdf: No such file or directory
/Users/hoge/.asdf/shims/node: line 7: exec: /usr/local/Cellar/asdf/0.10.2/libexec/bin/asdf: cannot execute: No such file or directory
```

ただ、`asdf --version`を実行すると、`v0.13.1`だったので、古いasdfを実行してことがわかる。

## やること
asdfの正しいパスを参照できるようにして、asdfを使用可能に戻す。

## 手順
- シムの再生成
- シェルを再読み込み


## シムの再生成
asdfのシムを再生成することで、正しいパスを参照するように更新できるっぽい。ターミナルで以下のコマンドを実行。

```terminal:$
asdf reshim
```

## シェルを再読み込み
シェルの設定を再読み込みし、変更を反映させる。以下のコマンドを実行。おれはzshを使っているので、

```terminal:$
source ~/.zshrc
```

bashの方は、多分
```terminal:$
source /.bash_profile
```

でよかったかな。

多分これで動くはず。

## お疲れ様でした。
わからないところ、間違っているところ、もっといい方法がある場合は、コメントでもDMでも教えてください。
EC2 Instance Connect を使ってみた 

## はじめに
EC2 Instance Connectを使ったことがなかったためメモ

ちなみに今回はDedicatedHosts上のMacOSで検証

AWS上にMacOS環境の作り方は下記を参考

https://qiita.com/eguchi7309/items/337b9b9a4afd7242763e

なんとなくEC2 Instance Connectは何もせずとも機能としてすぐに使えそうなイメージ(VMWareのイメージ)であったが、インスタンスを作成しただけだと使えないらしい、、、
(エージェントを入れないといけないみたい)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529251/8ea9a704-8375-f2b1-49a1-09d2f8bf2c23.png)


きっかけはEC2でマルウェア解析などの隔離環境を作ってみたく、、、
ただし、GUIではなくCLIみたいなのでそこはちょっと微妙
コンソール接続と同等のものはAWS Nitroというものが対応しているみたい
(mac1.metal は対応していない、、、)

https://aws.amazon.com/jp/ec2/nitro/

なお、外部インターネット環境との隔離をするには該当ルートテーブルからInternetGatewayをルートから削除する必要がある
→今回の記事の範囲外
また、ユーザのIAMの権限も同様に記事の範囲外
(EC2InstanceConnectでIAMロールを作ればいいだけっぽいのでIAMで細かく権限を付けている場合は触ってみてください)

## 本題
ながれは下記の通り

・ホストにec2-instance-connectのインストール
・稼働確認

### 事前設定
#### ec2-instance-connectのインストール
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-connect-set-up.html

上記サイトは日本語だとLinuxしか対応していないように見えるが、英語にするとMacOSなども手順がある

```
## AmazonLinux2の場合
# EC2 Instance Connectのインストール
sudo yum install ec2-instance-connect
```

```
## MacOSの場合
# brewのアップデート
brew update
# EC2 Instance Connectのインストール
brew install ec2-instance-connect
```


### 稼働確認
EC2の項目へ移動>インスタンスを選択>右上の接続をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529251/97875f2c-f37b-3cc9-20d6-d4e980bc63b3.png)

EC2 Instance Connect を使用して接続するをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529251/2b9028de-0494-4e0d-c233-15767fbd42cf.png)




接続をクリック
<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529251/b8bc1020-3da8-71b7-24bc-a250f8405393.png">

下記のようにプロンプトが返ってくる
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3529251/578b5afc-d08f-edc5-03a4-fe98700c7739.png">

## おわりに

ec2 instance connectの設定をしたことがなかったが意外と簡単だった

せっかくなのでコンソール接続ができる基盤のAWS Nitroを触ってみたい、、、
0アウト1塁:バントなしでの得点と失点確率：MLBチームごと(2020-2023)

バントなし、0アウトランナー1塁での、得点確率、失点確率

*   以下のようにデータ算出<br>[0アウト1塁→1アウト2塁の効果(今回は備忘録,検証用)　https://hide.ac/articles/aSNOVIUuF　](https://hide.ac/articles/aSNOVIUuF)

***

*   得点確率(offence)、失点確率(defence)とする

# 2020

![](https://pbs.twimg.com/media/GDUw820XQAAutBk?format=png\&name=4096x4096)

![](https://pbs.twimg.com/media/GDUuBxfXYAAw7Ou?format=png\&name=900x900)

LAD ドジャース (優勝) が、失点確率 32%(1位)、得点確率 56%(1位)　そりゃ強い

# 2021

![](https://pbs.twimg.com/media/GDU4UcHWcAAdAiv?format=png&name=4096x4096)
![](https://pbs.twimg.com/media/GDU4X6sWIAE2FmX?format=png&name=900x900)

ATL ブレーブス (優勝) が、失点確率 44%(13位)、得点確率 44%(19位) 

よくブレーブス勝ちましたな。

# 2022

![](https://pbs.twimg.com/media/GDUxR8UWQAAk_nW?format=png\&name=4096x4096)
![](https://pbs.twimg.com/media/GDUxO2CXcAAelAF?format=png\&name=900x900)

HOU アストロズ (優勝) が、失点確率 37%(2位)、得点確率 48%(6位) と安定した強さ

ディフェンス強いって大事ですね。

# 2023

![](https://pbs.twimg.com/media/GDU0I2yXkAAZ-OX?format=png\&name=4096x4096)
![](https://pbs.twimg.com/media/GDU0TTIXcAEkSoT?format=png\&name=900x900)

TEX レンジャーズ (優勝) が、失点確率 45%(13位)、得点確率 53%(1位) とオフェンスで勝った感じ
ABC335をPythonで（Fのみ）

AtCoder Beginner Contest 335（Sponsored by Mynavi）

https://atcoder.jp/contests/abc335

# F問題
基本は[公式解説](https://atcoder.jp/contests/abc335/editorial/9038)準拠
borderを$\sqrt{2\times 10^5} \fallingdotseq 500$より$500$に設定
```python:F
n = int(input())
a = list(map(int, input().split()))
mod = 998244353

cnt = [1] + [0] * (n - 1)
border = 500
dp = [[0] * (border + 1) for _ in range(border + 1)]
ans = 0

for now in range(n):
    # a_iがborder以下だったものからの遷移を反映
    for to in range(1, border + 1):
        cnt[now] = (dp[to][now % to] + cnt[now]) % mod

    # a[now]がborder以下の場合、後から反映されるようにdpに記録
    if a[now] <= border:
        dp[a[now]][now % a[now]] = (cnt[now] + dp[a[now]][now % a[now]]) % mod

    # a[now]がborderを超えていた場合、即座に遷移させる
    else:
        for to in range(now + a[now], n, a[now]):
            cnt[to] = (cnt[now] + cnt[to]) % mod

    ans = (ans + cnt[now]) % mod

print(ans)
```
「CPUの創りかた」TD4をLogisimで作製する


### 概要
「CPUの創りかた」にある4bit CPU(TD4)をLogisimで作製しました。

回路のほとんどは[この記事](https://qiita.com/devkjm/items/5be14b1d501688a9f25d)を参考にして創りましたが、命令デコーダの部分がICで実装されていなかったので、今回は本書に書いてある通り10個のIC(ALUは全加算器で代用したので実際は9個)を用いて作製しました。


[Logisim Librariesページ](http://www.cburch.com/logisim/links.html)の7400 series Logisim library from Ben Oztalayからダウンロードできます。

この中には、本書のALUで用いる74HC283が含まれていませんが、今回はLogisimデフォルトの全加算器で代用しました。

(74HC283は[この記事](https://yoshi-s.cocolog-nifty.com/cpu/2014/08/logisim.html)にある7400-lib-td4.circライブラリに含まれていますが、挙動が正確ではなかったため使用しませんでした。)

最終的にラーメンタイマーは以下のような挙動となりました。
ファイルは[GitHub](https://github.com/tomoish/Learning/tree/main/CPU)にあります。

![CPU-ramen-slow.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3507134/26fa4eba-6a37-cbfe-8141-6da0638b96d3.gif)


### 実行環境
#### Logisim
logisim-generic-2.7.1.jar

#### Java
java 16.0.1

### 参考文献
* [4bitCPU(TD4)を回路シミュレータLogisimで自作した話 「CPUの創りかた」](https://qiita.com/devkjm/items/5be14b1d501688a9f25d)
* [Yoshiのブログ Logisim](https://yoshi-s.cocolog-nifty.com/cpu/2014/08/logisim.html)
LLM用高速推理ライブラリ「vLLM」を試しました

LLMの出力スピードを高速化できるライブラリ「vLLM」について紹介します。

このライブラリは半年前に公開されて、処理速度が速いので私もよく使っています。最近中身について調べて、ある程度理解できましたので、共有したいと思います。

vllmの最大な特徴は"バッチ処理際の待機時間を減す"ことです。
LLMがoutputを生成する際に、プロンプト文に基づいてtokenを生成し、ストップtokenやtokenの最大数に達すと生成は停止します。この過程をbatchingとも呼ばれ、batchingの手法はstatic batchingとcontinues batching二種類があります。



## static batching
一般的に、LLMがoutputを生成する際に、プロンプト文に基づいてtokenを生成し、ストップtokenやtokenの最大数に達すると生成を停止します。

通常の処理手法（static batching）では、早く生成を終えた列（seq）が、他のまだ完了していない列を待つ必要があります。以下の図のように、seq1、3、4がseq2の完成を待っています。なので、GPUの利用効率は最大には達しません。

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/fb395985-18dd-a237-9d8d-93598592abc8.png)

## continues batching
vLLMはこの待機時間を削減するために、「continues batching」という手法を採用しています。continues batchingは一つのseqの生成が完了すると、バッチ内の次の空きスペースに新しいseqを追加し、生成を続けるというものです。

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/5f3cf4d2-dc86-4a70-d5ce-382f1c95cf37.png)

一部の記事では24倍速くなったとされていますが、私が実際に試したところ、およそ2倍速くなったと感しました。（比較対象はhuggingface、特にリクエストを複数個投げる際に）


興味ある方:

https://github.com/vllm-project/vllm

https://gigazine.net/news/20230622-vllm-paged-attention/
C# でAtCoder Beginners Selection ABC081B Shift only

https://atcoder.jp/contests/abs/tasks/abc081_b

自分が書いたコード

```C#
using System;
using System.Linq;

class Program 
{
  static void Main()
  {
    int N = int.Parse(Console.ReadLine());
    int[] A = Console.ReadLine().Split(' ').Select(a => int.Parse(a)).ToArray();
    
    int count = 0;
    bool flag = false;
    while(!flag)
    {
     for (int i = 0; i < N; i++)
      {
        if (A[i] % 2 == 0)
        {
          A[i] /= 2;
        } else 
        {
          flag = true;
          break;
        }
      }
      if (!flag)
      {
        count++;
      }
    }
    
    Console.WriteLine(count);
  }
}
```

もう少しきれいに書けそう
bashrcにいろいろ書いて正月が終わらないようにしてみた

# あけましておめでとうございます
三が日が終わって三連休も終わりに差し掛かってきて現実逃避をしたくなってbashrcをいろいろいじってみました。

# 正月を終わらせたくない
まずは日付を変えよう。
## 今日は 2024-01-01 ということにしておく
以下をターミナルで実行する。
```bash
echo "alias date=\"echo -n '2024-01-01 ';date '+%H:%M:%S'\"" >> ~/.bashrc 
```
ターミナルを開き直す or bashrc を読みこみ直す
```bash
source ~/.bashrc
```
```
$ date
2024-01-01 15:41:35
```
これでいつ date を実行しても今日は `2024-01-01` だと教えてくれるようになった。よし。
※ 当然だけど `\` 付きで実行すると alias じゃない date が実行されるのであくまで気分の問題。

## ターミナルログイン時に新年の挨拶がされるようにする
これだと `date` コマンドを打たないと正月であることを忘れてしまう。
ターミナルにログインしたら `HAPPY NEW YEAR` と出るようにしよう。

使うのは banner コマンド。
入っていなければインストールする。
```
sudo apt install sysvbanner
```
banner コマンドは引数で指定した文字列を `#` で表現してくれる。 `#` は変更も可能。
たとえば
```
banner hello
```
と実行すると
```

 #    #  ######  #       #        ####
 #    #  #       #       #       #    #
 ######  #####   #       #       #    #
 #    #  #       #       #       #    #
 #    #  #       #       #       #    #
 #    #  ######  ######  ######   ####

```
と表示される（英字小文字はすべて大文字に変換される）。

banner コマンドを使って盛大に `A HAPPY NEW YEAR` と表示しよう。
```bash
banner "A HAPPY" "NEW YEAR"
```
実行すると以下のようになる。
```
   #            #     #    #    ######  ######  #     #
  # #           #     #   # #   #     # #     #  #   #
 #   #          #     #  #   #  #     # #     #   # #
#     #         ####### #     # ######  ######     #
#######         #     # ####### #       #          #
#     #         #     # #     # #       #          #
#     #         #     # #     # #       #          #

#     # ####### #     #         #     # #######    #    ######
##    # #       #  #  #          #   #  #         # #   #     #
# #   # #       #  #  #           # #   #        #   #  #     #
#  #  # #####   #  #  #            #    #####   #     # ######
#   # # #       #  #  #            #    #       ####### #   #
#    ## #       #  #  #            #    #       #     # #    #
#     # #######  ## ##             #    ####### #     # #     #

```
いいじゃないか。これがターミナルに入るたびに表示されれば正月であることを忘れない。

### 新年の挨拶がゆっくり表示されるようにしよう
さきほどのbannerコマンドだけでもいいのだが、一瞬で表示されてしまってそのうち見なくなってしまう。もうひと工夫加えて`A` `HAPPY` `NEW` `YEAR` がbannerでそれぞれ表示されたあと1秒スリープして、正月であることを噛み締められるようにしよう。
```bash
for WORD in A HAPPY NEW YEAR
do
  banner $WORD
  sleep 1
  clear
done
```
これをbashrcに追記しよう。
```bash
echo "for WORD in A HAPPY NEW YEAR
do
  banner \$WORD
  sleep 1
  clear
done" >> ~/.bashrc
```
これで `A` `HAPPY` `NEW` `YEAR` と4秒(sleep 1秒×4)かけて表示されてからターミナルが表示されるようになった。

# ターミナルから抜けるときも正月であることを忘れない
ログイン時には `A HAPPY NEW YEAR` と表示されるようになったけど、ターミナルを抜ける時には忘れてしまうかもしれない。

ということで以下を実行する
```bash
echo "trap 'echo ¥"明日もまだ正月だよ¥"; sleep 1; exit' EXIT" >> ~/.bashrc
```
こうしておくことでターミナルから抜ける時に `明日もまだ正月だよ` と表示される。
```bash
~$ exit
明日もまだ正月だよ
```
Ctrl + D などで抜けたときも同じ。よし、これでまだ正月であることを忘れない。

# 最後に
明日から仕事頑張ろう…。
【JavaScript】単純リクエストを飛ばすことでpreflightでのエラーを回避する（突貫工事）

## 困ったこと
#### 状況
HTMLにJavaScriptを組み込み、XMLHttpRequestを使い外部のAPIを叩きたかった。
（HTTPメソッドはPOST。ヘッダーには`Content-Type`として`application/xml`を指定）
動作確認のため、このHTMLをGoogle Chromeで開き、JSを実行してみた。

#### 結果
APIのレスポンスを得られなかった。Chromeの開発者ツールでコンソールを見てみると、
「 **preflight** に失敗しました」という内容のエラーが出ていた。
（エラーメッセージをコピペし忘れました）


## 調査内容
- preflightは、実際のリクエスト前に、クライアントがサーバーから通信許可を得るために行われるもの
- preflightは、実際のリクエストが **単純リクエスト** ではない（かつCORS）の場合に行われる
- preflightのエラーの突破策は以下
    1. リクエストを単純リクエストとすることでpreflightが行われないようにする
    2. APIのレスポンスをいい感じに修正する

※[単純リクエストについてはこちら](https://developer.mozilla.org/ja/docs/Web/HTTP/CORS)

## 解決
今回は接続先が外部のAPIであり、そのレスポンスを修正することは不可能。
よって2.ではなく1.の突破策を選択。

リクエストヘッダーのContent-Typeを`application/xml`から`text/plain`にすることで解決した。
（ **application/xmlが単純リクエストの条件から外れていた** ）
[Ubuntu22.04] Intel One API 2024.0.1でいろいろインストール

## バージョン2024.0.1で大きな変更あり
　2024年に代わりIntel One Apiを新規インストールしてゴニョゴニョしようとしたら仕様変更で新年早々苦労したので急ぎメモ書き。

## ifort廃止（deprecated）！
　Intel One Apiバージョンが2024.0.1にバージョンアップしていた。いつもどおりにUbuntu22.04で色々Build & Installしようとしたらエラーで止まった。調べたところfortranコンパイラが新しいifxに変更されたらしい。そのためifortコマンドがなくなっていた。バージョン2024.0.0ではmpiiccがmpiicxに変わっていたのに次ぐ変更。ifxはLLVM-baseと記載されている。

## One Api offline installerの場合
　2024/01/08現在、[Intel One Api公式サイト](https://www.intel.com/content/www/us/en/developer/tools/oneapi/overview.html#gs.3baxrf "OneApi")からLinux版オフラインインストーラーをダウンロードするとBase Toolkitバージョンは2024.0.1.46。それに対しHPC Toolkitバージョンは024.0.0.49589と不一致がある。そのため両者をインストールして正しく設定してもifxがなくエラーが出る。再度HPC Toolkitインストーラーを立ち上げると新しいバージョンがインストールできるというメッセージが出るので、それに従って最新バージョンをインストールする。インストール後ターミナルを立ち上げなおすとifxが使えるようになった。

## FFTW3インストール
　[こちら](http://www2.yukawa.kyoto-u.ac.jp/~koudai.sugimoto/dokuwiki/doku.php?id=%E6%95%B0%E5%80%A4%E8%A8%88%E7%AE%97%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA:fftw3　"zatta")のページのインストール法を参照。[公式ページ](https://www.fftw.org/ "FFTW3")からソースコードをダウンロードし解凍。生成するfftw-3.3.10ディレクトリに移動。そこで
 ```FFTW3:terminal
 ./configure --prefix=/usr/local/fftw3 CC=icx MPICC=mpiicx F77=ifx --enable-mpi --enable-threads
```
にてconfigureしてから
```FFTW3:terminal
 make
 sudo make install
```
でインストールできる。

## Quantum Espressoインストール
　[公式ページ](https://www.quantum-espresso.org/ "QE")からソースコードをダウンロードし解凍。バージョン7.0の場合は生成するqe-7.0ディレクトリに移動。下記でconfigure
```QE:terminal
./configure MPIF90=mpiifx F90=ifx F77=ifx CC=icx
```
その後
```QE:terminal
make all
```
でビルド＆インストールできる。

## 最後に
新年早々焦りました。
Seleniumを使ってスクレイピング

<h1>はじめに</h1>
<p>目的は、プルダウン選択の操作が必要なWebページのスクレイピングです。</p>
スクレイピング後、CSVデータファイルに保存するところまでを行います。
<h1>準備すること</h1>
GoogleのブラウザのバージョンとChrome用WebDriverを一致させてダウンロードしておくこと
<h1>スクリプト<h1>

```python:qiita.py
# seleniumの必要なライブラリをインポート
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import Select
from time import sleep
from selenium.webdriver.chrome.options import Options
import pandas as pd

# ヘッドレスモードで処理を行う
options = Options()
options.add_argument('--headless')
# WebDriverのインスタンスを生成
browser = webdriver.Chrome(options=options)

# ページを開く
url = 'あなたのスクレイピングしたいWebサイトのURL'
browser.get(url)
sleep(5)

# 「種類」プルダウンから「車」を選択する関数
def select_type():
    # Selectオブジェクトを生成
    elem = Select(browser.find_element(By.ID, 'header_type'))
    # オプションを選択
    elem.select_by_visible_text('車')
    # 一定時間待つ
    sleep(3)

# 「--メーカー--」プルダウンから選択肢をリストで取得する関数
def get_shop_list():
    # Selectオブジェクトを生成
    elem = Select(browser.find_element(By.ID, 'header_size01'))    
    # 選択項目の一覧をリストで取得
    options = elem.options
    # 選択項目のテキストをリストに格納
    shop_list = [option.text for option in options][1:]
    return shop_list

# 「--メーカー--」プルダウンから「--メーカー名--」を選択する関数
def select_shop(shop):
    # Selectオブジェクトを生成
    elem = Select(browser.find_element(By.ID, 'header_size01'))
    # オプションを選択
    elem.select_by_visible_text(shop)
    # 一定時間待つ
    sleep(3)

    
    
# 「サイズ」プルダウンから選択肢をリスト取得する関数
def get_size_list():
    # Selectオブジェクトを生成
    elem = Select(browser.find_element(By.ID, 'header_size02'))
    # 選択項目の一覧をリストで取得
    options = elem.options
    # 選択項目のテキストをリストに格納
    size_list = [option.text for option in options][1:]
    return size_list

# 「サイズ」プルダウンから「サイズ」を選択する関数
def select_size(size):
    # Selectオブジェクトを生成
    elem = Select(browser.find_element(By.ID, 'header_size02'))
    # オプションを選択
    elem.select_by_visible_text(size)
    # 一定時間待つ
    sleep(3)

# 「型番」プルダウンから選択肢をリスト取得する関数
def get_prod_list():
    # Selectオブジェクトを生成
    elem = Select(browser.find_element(By.ID, 'header_size03'))
    # 選択項目の一覧をリストで取得
    options = elem.options
    # 選択項目のテキストをリストに格納
    prod_list = [option.text for option in options][1:]
    return prod_list

# 「型番」プルダウンから「型番」を選択する関数
def select_prod(prod):
    # Selectオブジェクトを生成
    elem = Select(browser.find_element(By.ID, 'header_size03'))
    # オプションを選択
    elem.select_by_visible_text(prod)
    # 一定時間待つ
    sleep(3)

# 「種類」プルダウンから「車」を選択する関数を呼び出す
select_type()
# 「--メーカー--」プルダウンから選択肢をリスト取得する関数を呼び出す
shops_list = get_shop_list()    

ALL_PROD_LIST = []
for shlist in shops_list:
    select_shop(shlist)
    size_list = get_size_list()
    for slist in size_list:
        select_size(slist)
        sleep(1)
        prod_list = get_prod_list()
        for plist in prod_list:
            ALL_PROD_LIST.append(plist)

df = pd.DataFrame()
df['各社型番'] = ALL_PROD_LIST
df.to_csv('各社型番.csv',index=False)
browser.quit()
```
ニフクラ mobile backendの会員データをParse Serverに移行する

[ニフクラ mobile backendは3月末で終了します](https://mbaas.nifcloud.com/info/2023/12/post-171.html)。

ニフクラ mobile backendからの移行先として、お勧めしているのが[Parse Server](https://parseplatform.org/)です。設計思想が近く、変更するコード量が少なく済むのではないかと思います。

そこでParse Serverへの移行をサポートできるスクリプトを作成中です。今回は会員データの移行スクリプトを紹介します。

## TL;DR

今回、移行用のスクリプトを作りました。

[NCMBMania/ncmb2parse](https://github.com/NCMBMania/ncmb2parse)

使い方は、以下のような形です。

```bash
npx node dist/user.js -a YOUR_APP_ID \
  -k YOUR_REST_API_KEY \
  -u YOUR_PARSE_SERVER_URL\
  /path/to/users.json
```

## 必要な情報を用意する

### ニフクラ mobile backendのプッシュ通知データをエクスポートする

プッシュ通知データは、管理画面のエクスポート機能か、Chrome機能拡張で取得できます。JSONデータで取得してください。

[NCMBのデータエクスポートに使えるGoogle Chrome機能拡張（会員・ロールの全データダウンロード） \#JavaScript \- Qiita](https://qiita.com/goofmint/items/86fb1736c242131f6554)

データはusers.jsonという名前だとします。

![](https://camo.qiitausercontent.com/a483fd6a383f9d0d5a9d7f79cc28192eb82c8239/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3139373032362f64653433313034362d373061372d356265642d323062392d3037396439303535656332612e6a706567)

## Parse Serverの各種データを取得する

Parse Serverを起動する際の、下記データが必要です。

- アプリケーションID
- REST APIキー
- Parse ServerのURL

これらを控えておきます。

## 移行用スクリプトを用意する

移行用スクリプトは、Node.jsで動作します。Node.jsがインストールされていない場合は、インストールしてください。

```bash
git clone https://github.com/NCMBMania/ncmb2parse.git
cd ncmb2parse
npm install
```

## 移行用スクリプトを実行する

先ほど取得したParse Serverの情報、users.jsonのパスを指定して、スクリプトを実行します。

```bash
npx node dist/user.js -a YOUR_APP_ID \
  -k YOUR_REST_API_KEY \
  -u YOUR_PARSE_SERVER_URL\
  /path/to/users.json
```

ヘルプは以下の通りです。

```
Usage: user.js [options] <filePath>

Arguments:
  filePath                    users.jsonのパス

Options:
  -k, --key <REST API Key>    Parse ServerのREST APIキー
  -u, --url <URL>             Parse ServerのURL
  -a, --app <Application ID>  Parse ServerのApplication ID
  -h, --help                  display help for command
```

## 注意点

現時点では、過去データの会員情報のACL移行には対応していません。マスターキーが必要な処理になるので、追って対応予定です。

user.jsonにて独自に追加したフィールド含めて、同名のフィールドで移行されます。ただし、規定のフィールド名は以下のように追加します。

- objectId -> ncmbObjectId

なお、createdDateとupdatedDateも移行しますが、Parse ServerのcreatedAtとupdatedAtと間違わないように注意してください。また、createdDateとupdatedDateは、日付型ではなく文字列型として移行されます。

## まとめ

Parse ServerはデータやACLがニフクラ mobile backendと近いので、データ移行はさほど難しくありません。Parse Dashboardを使えば、Webブラウザからプッシュ通知の作成も可能です。自分でサーバーを立ち上げる必要はありますが、移行先として検討してみてください。

[Parse Platform](https://parseplatform.org/)
【SAPUI5】初心者がSAP Fioriアプリケーションを開発する時に確認すべき公式ドキュメント

# 概要
受託開発企業で働くfussasyといいます。普段は、SAP BTP（PaaS）上でSAP Fioriアプリケーション開発をしています。SAP Fioriアプリケーションを作成する際、ぶっちゃけ何から始めたら良いのか迷う場合があるかなと思うので、まず最初に確認すべき公式ドキュメント類について整理します。

# 公式チュートリアル
以下のチュートリアルから、SAPが提供するFioriアプリケーションのイメージが掴めると思います。実際にFioriLaunchPadから各アプリケーションに遷移してFioriアプリケーションの動作を確認することができます。

**Create an Account on the SAP Gateway Demo System**

https://developers.sap.com/tutorials/gateway-demo-signup.html

以下のチュートリアルでは、SAP Business Application Studioでアプリケーションを開発し、SAP Build Work Zoneにデプロイまで実施します。

**Build an SAP Fiori App that Consumes Data from an On-Premise System**

https://developers.sap.com/group.appstudio-fiori.html

**Create a Web Front End with SAPUI5**

https://developers.sap.com/group.cp-frontend-ui5-1.html

**Deliver Your First SAP Fiori Launchpad Site**

https://developers.sap.com/mission.cp-starter-digitalexp-portal.html

# 公式ガイドライン、リファレンス、サンプル
SAPUI5での開発を始める際、まずは確認した方が良いガイドラインです。文章になっている読み物形式になっています。

**SAP Fiori for Web**

https://experience.sap.com/fiori-design-web/

実際に開発を進める際、各SAPUI5コントロールの使い方について整理されたリファレンスになります。開発中も常に開いておいて、迷ったらまずは確認するページになります。

**UI5 Demo Kit - API Reference**

https://ui5.sap.com/1.119.2/#/api

実際に開発を進める際、各SAPUI5コントロールの使い方についてviewやcontrolerの記述方法が分からない時が多いと思います。まずは公式で提供されているサンプルコードを拾ってきて、適宜、組み合わせて改変していくところから始めます。

**UI5 Demo Kit - Samples**

https://ui5.sap.com/1.119.2/#/controls

# おわりに
上記の他にも、QiitaやSAP Community Blog等、開発を進めていくとお世話になる記事はたくさんあるんですが、今回は開発の走り始めで使うであろう公式ドキュメント類に絞りました。
YOLOv8ですでに自分で切り抜いたオリジナルデータの物体検出を行いたい【データ拡張】

YOLOv8ですでに自分で切り抜いたオリジナルデータの物体検出を行いたい。これはどうやらデータ拡張という名称らしい。

すでに似たような質問している人がRedditにいた

https://stackoverflow.com/questions/55930342/training-yolo-to-detect-my-custom-object-with-already-cropped-images

https://github.com/ultralytics/ultralytics/issues/1631

どうやらこんなサイトがあるらしい

https://docs.ultralytics.com/#where-to-start

↑の公式サイトが一番わかる。下手な日本語サイト見るよりここでコードを一緒に進めてくれる動画を見ながら制作側の説明を受けたほうがいいと思いました。


How to Train YOLOv8 Object Detection on a Custom Dataset
https://github.com/roboflow/notebooks/blob/main/notebooks/train-yolov8-object-detection-on-custom-dataset.ipynb

上のやつも公式


他にも、日本語だと下記の方がわかりやすいと思いました。

https://farml1.com/yolov8/


まさに私がやりたいことがオリジナルデータの物体検知だったので助かりました。
アノテーションの概念とかついていくの大変すぎる。

これもよかった。

https://note.com/kan_hatakeyama/n/n8a9ce710f103


# 探したワード

how can i train my own data in yolov8


# ステップ
・個人環境でやるならお勧めはColaboratoryを使う（GPUを無料で使える)
具体的なやり方は下記参照
https://sci-by-py.com/hpc/google-colab/

・ roboflowで学習元画像を取り込む
https://app.roboflow.com/coursedatascience

フリープランだとトレーニング内容は公開しないといけないです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334349/540154c2-f10d-2c2d-4b25-5f374bca5bd5.png)
実際の作業画面はこのような感じ。


これやったらうまくいきました。roboflowすごい！


他にも見たページは下記。

https://github.com/ultralytics/yolov5/issues/8528

https://magicode.io/mua408905/articles/94dc6169f431479e97e77dcc880d7dc2


# 備考：yoloは色でも物体検知をしているのか

YOLOは、画像の中にある物体を検知するためのディープラーニングモデルです。YOLOは、画像の中にある物体の位置と種類を同時に検出することができます。YOLOは、物体の位置を検出するために、画像の中にある物体の色情報を利用しているわけではありません。代わりに、YOLOは、物体の形状や輪郭などの特徴を利用して、物体を検出しています。

もし、YOLOが色情報を利用して物体を検出する場合は、それはYOLOの実装によるものであり、一般的なYOLOの動作とは異なる可能性があります。しかし、私が知る限り、YOLOは、物体の位置を検出するために、色情報を利用しているわけではありません。
pandas.DataFrameのループ速度比較（iterrows vs apply）

# 概要
pandas.DataFrameで行ごとの処理をする場合の、iterrowsとapplyの速度比較を行ったコードのメモです。iterrowsのほうが遅いという話はよく聞きますが、実際どの程度遅いのか、実感を掴むためにやりました。新規性は特にありません。

# 実装
wikipediaの記事を文単位で分割して新たなDataFrameをつくるというタスクで計測します。
列名の変更など一部無駄な処理があるのは、他のプロジェクトのためのコードを流用しているためです。
コードはGPT4の力を借りて作りました。

wikipediaの記事をhuggingfaceからダウンロードします。

```Python
from datasets import load_dataset

# URL of the dataset
dataset_url = "izumi-lab/wikipedia-ja-20230720"

# Load the dataset
dataset = load_dataset(dataset_url)

# To view basic information or manipulate the dataset, you can use:
print(dataset)
```

計測用のコードです。

```Python
import pandas as pd
import timeit

# 既存の iterrows() を使用した関数
def split_surface_to_sentences_iterrows(df: pd.DataFrame) -> pd.DataFrame:
    new_rows = []
    for _, row in df.iterrows():
        for line in row["surface"].splitlines():
            for sentence in line.split("。"):
                if sentence:
                    new_row = row.to_dict()
                    new_row["surface"] = sentence
                    new_rows.append(new_row)
    return pd.DataFrame(new_rows)

# apply() を使用した関数
def split_surface_to_sentences_apply(df: pd.DataFrame) -> pd.DataFrame:
    def split_sentences(row):
        sentences = [sentence for line in row['surface'].splitlines() for sentence in line.split('。') if sentence]
        return pd.DataFrame({col: [row[col]]*len(sentences) if col != 'surface' else sentences for col in df.columns})
    return pd.concat(df.apply(split_sentences, axis=1).tolist(), ignore_index=True)

# テスト用のデータフレームを作成
subset = dataset["train"][:10]
passage_df = pd.DataFrame(subset)
passage_df.rename(columns={"text": "surface"}, inplace=True)

# iterrows() の実行時間を計測
iterrows_time = timeit.timeit('split_surface_to_sentences_iterrows(passage_df)', globals=globals(), number=100)

# apply() の実行時間を計測
apply_time = timeit.timeit('split_surface_to_sentences_apply(passage_df)', globals=globals(), number=100)

print(f'iterrows() time: {iterrows_time}')
print(f'apply() time: {apply_time}')
```

```
iterrows() time: 1.5944697080121841
apply() time: 0.2716344580112491
```

# 結果
applyのほうが5倍くらい早いみたいです。
Llama 2をFinetuningするDatasetsの探し方＠Hugging Face

## はじめに
以前の記事で、Llama 2をFinetuningする手順＠Colabについて見ました。

https://qiita.com/yn01/items/1aea596779df19d611c0

Llama 2は英語だけではなく日本語にも対応はしてますが、トレーニングデータの割合としては全体の0.1%のみ。約90%は英語です。

Llama 2を触っていると日本語対応をもっと強化したい！と思うはず。
それ以外にも、特定のナレッジやドメイン知識でトレーニングしたいと思うこともしばしば。なはず。

ということで、今回はLlama 2をFinetuningするためのDatasetsの探し方です。

※独自にDatasetsを作る方法はまた別の記事にて！

## 概要
* Llama 2をFinetuningするDatasetsをHugging Faceで探す
* Finetuningの手順はこちらにまとめてます

https://qiita.com/yn01/items/1aea596779df19d611c0

## 手順

### １．Hugging Faceのアカウントを作成する　※スキップ可
今回はHugging FaceでDatasetsを探していくので、最初にアカウントを作っておく。

Datasetを探すだけならアカウントはなくてもいいですが、あった方が断然便利。

https://huggingface.co/

### ２．Datasetsを探す

Hugging Faceのページから、`Datasets`メニューを開いて任意のワードでDatasetsを検索してみる。
今回は検索欄に`llama`と入力して、Llamaに対応したDatasetsを検索してみました。

![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93776/e85910ec-1832-d2c4-1f26-06072c4f4a36.png)

いろいろなDatasetsが公開されているので、Datasetsを探すだけでも結構楽しいですよ！

### ３．Finetuningする
２で選んだDatasetsを使って、Finetuningをする。

手順はこちらの記事をご参照ください

https://qiita.com/yn01/items/1aea596779df19d611c0

`dataset_name`に、選んだDatasetsを指定すればOK

```
# The instruction dataset to use
dataset_name = ""
```

一つだけ注意点が。

DatasetのField定義が合っていないとエラーで先に進めないので一応確認しておきます。
下の`dataset_text_field`のところ。

```
# Set supervised fine-tuning parameters
trainer = SFTTrainer(
    model=model,
    train_dataset=dataset,
    peft_config=peft_config,
    dataset_text_field="text",
    max_seq_length=max_seq_length,
    tokenizer=tokenizer,
    args=training_arguments,
    packing=packing,
)
```

あとは普通にFinetuningできます。

## まとめ
Hugging FaceでLlama 2向けのDatasetsを探してみました。

Datasetsを選んでFinetuningしたものの、思いのほかうまくいかないこともあります。
というか、自分はそうでした。

となると、、

自分でDatasetsを作りたくなりますよね！
次回の記事では、Llama 2向けのDatasetsを作ってみたいと思います。
【Android】Intent Flag 対応表

## Intent の Flag まとめ
|フラグ  |用途  |
|---|---|
|FLAG_ACTIVITY_SINGLE_TOP  |新しいActivityを起動する際に、そのActivityがタスクのトップに既に存在している場合、新しいインスタンスを作成する代わりに既存のインスタンスを再利用する。  |
|FLAG_ACTIVITY_CLEAR_TOP  |新しいActivityを起動する際に、同じタスク内で既存の同じActivityのインスタンスが存在する場合、その既存のActivityとその上にあるすべてのActivityをクリアしてから新しいActivityを起動する。  |
|FLAG_ACTIVITY_NEW_TASK  |新しいタスク（新しいバックスタック）を開始し、その中で新しいActivityを起動する。<br>このフラグを使用することで、別のタスクとして新しいActivityを起動することができる。 |
|FLAG_ACTIVITY_CLEAR_TASK  |既存のタスク内の全てのActivityをクリアして、新しいActivityを起動する。 |
|FLAG_ACTIVITY_NO_HISTORY |起動したActivityが、履歴に残らないようにする。つまり、そのActivityを終了すると、その履歴から削除される。  |
|FLAG_ACTIVITY_REORDER_TO_FRONT |既にタスク内に存在するActivityであれば、そのActivityをタスクの最前面に移動する。新しいインスタンスを作成することはない。 |
|FLAG_ACTIVITY_BROUGHT_TO_FRONT |既にタスク内に存在するActivityであれば、そのActivityをタスクの最前面に移動しますが、そのActivityの新しいインスタンスを作成する。  |
|FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |Recent Appsに表示されないように、そのActivityをRecent Appsから除外する。 |
|FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET  |タスクをリセットする際に、そのタスク内のActivityをクリアする。FLAG_ACTIVITY_NEW_TASKと組み合わせて使用できる。  |
|FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY  |Activityが履歴から起動されたことを示すフラグ。  |
|FLAG_ACTIVITY_FORWARD_RESULT |呼び出し元のActivityに結果を返す際に、中間のActivityをスキップして直接結果を送るためのフラグ。  |
|FLAG_ACTIVITY_PREVIOUS_IS_TOP  |前回のActivityがタスクのトップにあるとき、そのActivityを再利用することを示すフラグ。  |
|FLAG_ACTIVITY_NO_USER_ACTION  |ユーザーアクション（ユーザーの操作）によって起動されたことを示すフラグ。通常、システムが自動的に起動した場合に使用される。  |
|FLAG_ACTIVITY_REORDER_TASKS  |タスク内のActivityを再配置する。一般的には、新しいActivityのスタックを開始するときに使用される。  |
|FLAG_ACTIVITY_TASK_ON_HOME  |タスクをホーム画面のように扱うことを示す。タスクがホーム画面に表示されるようになる。  |
|FLAG_RECEIVER_REGISTERED_ONLY  |明示的なReceiver（BroadcastReceiver）のみをターゲットにするフラグ。Manifestに登録されたReceiverのみがBroadcastを受信する。  |
|FLAG_ACTIVITY_MATCH_EXTERNAL  |外部プロセスからのIntentをマッチングするためのフラグ。外部プロセスからのIntentを受け取るために使用される。  |
|FLAG_ACTIVITY_REQUIRE_NON_BROWSER  |ブラウザを使用しないActivityを要求するフラグ。ブラウザで開かれるActivityを避け、代わりにアプリ内のActivityを開くように指定する。  |
|FLAG_ACTIVITY_REQUIRE_DEFAULT  |デフォルトのActivityを要求するフラグ。デフォルトのActivityが設定されている場合、それを開く。  |
|FLAG_ACTIVITY_NO_ANIMATION  |Activity遷移時のアニメーションを無効にするフラグ。Activityの遷移時にアニメーションを適用したくない場合に使用する。 |

これらのフラグを使用することで、Intentの動作やActivity遷移時の挙動をさまざまに制御することができます。

## おわりに
公式読みつつ、解説が難しかったのでチャットGPTです。
Intentのflagにこんな種類があるんですね。
頑張るぞい！

## 参考
- https://developer.android.com/reference/android/content/Intent#FLAG_ACTIVITY_BROUGHT_TO_FRONT
【SwiftUI】パスワード入力欄で間違えたらテキストフィールドをブルブルさせたい（iOS17）

# はじめに
パスワードの入力欄でよくあるのが、間違ったパスワードを入力すると入力欄がシェイク(ブルブル)して間違っていることを知らせるといったUIです。
これをiOS17から登場した`keyframeAnimator`を使って実装してみたいと思います。

`keyframeAnimator`を使用せず、実装したい場合は以下の記事が参考になると思います。

https://www.objc.io/blog/2019/10/01/swiftui-shake-animation/

# サンプルアプリ
キーボードでreturnを押すと、テキストフィールドがシェイクします。
間違ったものを入力していたという想定です。
![Simulator Screen Recording - iPhone 15 - 2024-01-08 at 21.03.45.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/d7808577-7aec-4f51-6f25-5b316ee54d4a.gif)

# 実装
```swift
import SwiftUI

struct KeyframeAnimationValues {
    var offsetX = 0.0
}

struct ContentView: View {
    @State private var text = ""
    @State private var shakeAnimationTrigger = false

    var body: some View {
        VStack {
            TextField("文字を入力してください", text: $text)
                .textFieldStyle(.roundedBorder)
                .keyframeAnimator(
                    initialValue: KeyframeAnimationValues(),
                    trigger: shakeAnimationTrigger
                ) { content, value in
                    content.offset(x: value.offsetX)
                } keyframes: { _ in
                    KeyframeTrack(\.offsetX) {
                        CubicKeyframe(5, duration: 0.2)
                        CubicKeyframe(-5, duration: 0.1)
                        CubicKeyframe(5, duration: 0.1)
                        CubicKeyframe(-5, duration: 0.1)
                        CubicKeyframe(5, duration: 0.1)
                        CubicKeyframe(0, duration: 0.2)
                    }
                }
                .onSubmit {
                    shakeAnimationTrigger.toggle()
                }
        }
        .padding(20)
    }
}
```

# 解説
アニメーションで必要な値を構造体で定義します。
今回はoffsetのxをいじりたいので`offsetX`を定義します。
```swift
struct KeyframeAnimationValues {
    var offsetX = 0.0
}
```

アニメーションのトリガーを定義します。
```swift
@State private var shakeAnimationTrigger = false
```

`initialValue`には先ほど作成した構造体を初期化して渡します。
`trigger`に先ほど定義したトリガーを渡します。
`keyframes`で継続時間と値をセットで渡します。
`keyframes`で設定した値が`value`として流れてくるので、`content.offset(x:)`で`value.offsetX`を設定します。
```swift
.keyframeAnimator(
    initialValue: KeyframeAnimationValues(),
    trigger: shakeAnimationTrigger
) { content, value in
    content.offset(x: value.offsetX)
} keyframes: { _ in
    KeyframeTrack(\.offsetX) {
        CubicKeyframe(5, duration: 0.2)
        CubicKeyframe(-5, duration: 0.1)
        CubicKeyframe(5, duration: 0.1)
        CubicKeyframe(-5, duration: 0.1)
        CubicKeyframe(5, duration: 0.1)
        CubicKeyframe(0, duration: 0.2)
    }
}
```

今回は`onSubmit`で毎回シェイクされるように`shakeAnimationTrigger`を`toggle()`します。
`shakeAnimationTrigger = true`のようにすると値が`false`に戻らないので正常に動作しません。
```swift
.onSubmit {
    shakeAnimationTrigger.toggle()
}
```

# おわり
KeyframeAnimationについて以前書いた記事はこちらです。

https://qiita.com/SNQ-2001/items/5cb45a055bf929b436ab

KeyframeAnimationがあると色んなアニメーションが作れて楽しいです
Tips: coc-solargraphを使うときはshellの指定をした方が良いかも

## 初めに
NeovimでRubyのLspを使う方法の一つに、[coc.nvim](https://github.com/neoclide/coc.nvim)と[coc-solargraph](https://github.com/neoclide/coc-solargraph)を使う方法があります。
このライブラリを導入し、READMEの通りに設定を行なっても正しく動作をしなかったため、解決方法をTipsとしてまとめます。

## 問題が起こった環境

- マシン: Mac (M1)
- Ruby: rbenvでv3.2をglobalに指定
- シェル: zsh
- Neovim: v0.9.4

## 起こっていた問題
READMEの通りに設定を行い、いざRubyのファイルを開くと以下のようなエラーがNeovimのコンソールに表示されました。

```
[coc.nvim]: UnhandledRejection: /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/rubygems.rb:283:in `find_spec_for_exe': can't find gem solargraph (>= 0.a) with executable solargr
aph (Gem::GemNotFoundException)
        from /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/rubygems.rb:302:in `activate_bin_path'
        from /Users/getty104/.anyenv/envs/rbenv/gems/3.2.0/bin/solargraph:25:in `<main>'
```

エラーの内容を見る限り、rbenvで指定したRubyではなく、MacにプリインストールされているRubyのパスを参照しているようでした。
MacにプリインストールされているRubyは2.6系のため、solargraphをインストールすることはできないため、なんとかrbenvで指定したRubyを参照するようにする必要がありました。

## 原因
以下のIssueの通り、`shell`オプションにシェルの指定を行わないと、ログインしているシェルではないシェルを読みにいってしまうことがあるようでした。

https://github.com/neoclide/coc-solargraph/issues/48

rbenvのセットアップは`zshrc`に書いていたため、zsh以外のシェルを用いてコマンドが実行され、それによりデフォルトのプリインストールされているRubyが参照されてエラーになっていたのが原因でした。

## 解決方法
`coc-settings.json`でシェルの指定を行うことで解決しました。

```json
{
  "solargraph.shell": "/bin/zsh"
}
```
helm templateの結果をファイル分割して保存するTIPS

# helm templateの出力結果が大きい問題

`helm template`コマンドでレンダリングを行いますと、
以下のように`---`区切りの膨大な行数が標準出力されることがあるかと思います。

```shell:イングレスのレンダリング行数
$ helm template ingress-nginx/ingress-nginx | wc -l
738
```

# 対応策

以下のように`yq`コマンドでファイル毎に保存します。
分割後のファイル名が`カインド名-連番.yml`となるようにしています。

```
$ helm template ingress-nginx/ingress-nginx | yq -s '.kind + "-" + $index'
$ ls
ClusterRole-12.yml                      ConfigMap-1.yml                         Job-17.yml                              RoleBinding-5.yml                       ServiceAccount-11.yml
ClusterRole-2.yml                       Deployment-8.yml                        Role-14.yml                             Service-6.yml                           ValidatingWebhookConfiguration-10.yml
ClusterRoleBinding-13.yml               IngressClass-9.yml                      Role-4.yml                              Service-7.yml
ClusterRoleBinding-3.yml                Job-16.yml 
```

# 参考

`yq`コマンド: https://mikefarah.gitbook.io/yq/
元ネタ: https://github.com/helm/helm/issues/4680#issuecomment-1468229115