OmniAICreator/Qiita-1.07M huggingface dataset:
Markdown絵文字表示テスト: タグ(地域旗)

[国旗](https://qiita.com/higuma/items/b5d2200313b1d9c54ce4) ← [解説](https://qiita.com/higuma/items/e402fc428ecf0cb184d8#タグ地域旗) → [修飾子](https://qiita.com/higuma/items/d8c62dcd87ad3c7b6c3f)

----------------------------------------

| シーケンス | 出力 | 名前 | バージョン |
| - | - | - | - |
| 1F3F4 E0067 E0062 E0065 E006E E0067 E007F | 🏴󠁧󠁢󠁥󠁮󠁧󠁿 | flag: England | E5.0 |
| 1F3F4 E0067 E0062 E0073 E0063 E0074 E007F | 🏴󠁧󠁢󠁳󠁣󠁴󠁿 | flag: Scotland | E5.0 |
| 1F3F4 E0067 E0062 E0077 E006C E0073 E007F | 🏴󠁧󠁢󠁷󠁬󠁳󠁿 | flag: Wales | E5.0 |

----------------------------------------

[国旗](https://qiita.com/higuma/items/b5d2200313b1d9c54ce4) ← [解説](https://qiita.com/higuma/items/e402fc428ecf0cb184d8#タグ地域旗) → [修飾子](https://qiita.com/higuma/items/d8c62dcd87ad3c7b6c3f)
【Terraform】Terraformに用意されている組み込み関数を動かしてみる

# はじめに
terraformには組み込み関数が用意されています。用意されている組み込み関数は[公式ドキュメント](https://www.terraform.io/language/functions)を参考にします。

https://www.terraform.io/language/functions


# terraform consoleで試す
組み込み関数の動作を確認したいとき、```$ terraform console```を使うと、簡単に動作確認することができます。
変数を利用したい場合、変数定義された.tfファイルがあるディレクトリで実行します。

```zsh
$ terraform console
```

# max()を試してみる

```zsh
$ terraform console
> max(1, 12, 9)
12
```
Javascript Sortの順番

JavaScriptで平仮名、カタカナ、漢字、数字、アルファベットが混ざっている配列にSortをかけた際はどのような順序になるのか、検証しました。（正直単純な配列なのでただsortをかけるだけでいいのですが、連想配列の際にも使えるようなコードで一旦記述しています。）


```javascript
      const dummyArray = ['ひらがな', 'カタカナ', '漢字', '123', 'abc']

      dummyArray.sort((a, b) => {
        if (a > b) {
          return 1
        } else {
          return -1
        }
      })

      console.dir('結果' + JSON.stringify(dummyArray))
```

結果：
![result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2365717/8ebde4b7-eaf0-a49f-19b0-857d08c7cb51.png)


また「ヴ」はカタカナの中の最後尾に来てしまうようで、ウの後に入れるには無理やりこうするしかありませんでした。
```javascript
      dummyArray.sort((a, b) => {
        //最初の文字が「ヴ」だったら最初の文字のみ「ウン」に置き換えて比較する
        const aName = a[0] === 'ヴ' ? a.replace('ヴ', 'ウン') : a
        const bName = a[0] === 'ヴ' ? b.replace('ヴ', 'ウン') : b

        if (aName > bName) {
          return 1
        } else {
          return -1
        }
      })
```

こうすると、一応「ウ」の後にくるのですが、万が一要素の名前で「ウン」から始まるものがあれば「ヴ」よりも後に来てしまう可能性があるので、もう少しいい方法があるといいな、という感じです。。
また今回は一旦`aName`に置き換えていますが、比較用に置き換えているだけなので元の要素の名前は変わらないです。


アルファベットや数字のみでsortをかけている資料はぼちぼちあるのですが、色々な要素でかけているものはあまりないので備忘録でした。閲覧ありがとうございました。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
Google UXデザイン：プロブレム・ステートメントを定義する

# はじめに

わたしが[Google UX Design Certificateで得られた素晴らしい体験][google]を、特に重要だと思われるポイントを小さく分割して、わかりやすく簡潔に紹介していきます。

興味があれば、ぜひ Google UX Design Certificateを受講してみてください。

[google]: https://qiita.com/mapami/items/7a0d0a3d4661c50f8bec

https://www.coursera.org/professional-certificates/google-ux-design

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/bddf54d2-10de-1b0d-0b37-21ba00cfb1df.png" width="800">

# プロブレム・ステートメントとは

***<font color="MediumVioletRed">『取り組むべきユーザーのニーズを明確に記述したもの』</font>***　

# フレームワーク 「5 Ws and H」

ユーザーのペインポイントを定義した後、そのユーザーの問題を解決するために、誰が、何を、いつ、どこで、なぜ、どのようにするのかを答えることができるのです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/997113db-b841-a43f-bd74-8e89eb6075f8.png" width="700">

- ***Who?***
    - 誰が問題を経験しているのか？
    - ユーザーとその背景を知ることは、彼らのために成功するソリューションを作るための鍵です。
- ***What?***
    - 解決しようとする課題は何か？
    - ユーザーの問題点を早期に発見することで、残りの質問に答え、問題点の背景を明確にすることができます。
- ***Where?***
    - 製品を使うとき、ユーザーはどこにいるのか？
    - ユーザーの物理的な状況は、デザインにとって重要です。
- ***When?***
    - 問題はいつ発生するのか？
    - もしかしたら、長くて退屈なプロセスが終わった直後かもしれませんし、毎日起こることかもしれません。どんなときに問題が発生するのかを知ることで、ユーザーの気持ちをより深く理解することができます。
- ***Why?***
    - なぜ、その問題が重要なのか？
    - この問題がユーザーの体験や生活にどのような影響を与えるかを知ることで、起こりうる結果を明確にすることができます。
- ***How?***
    - その製品を使うことで、ユーザーはどのように目標に到達しているのか？
    - ユーザーがどのように目標に到達しているかを理解することで、ユーザーが製品を通じてたどるユーザー・ジャーニーをマップ化することができます。

# プロブレム・ステートメントの公式

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/808ae57e-1111-371e-45d6-2316ec9dd091.png" width="700">

問題提起は、簡単な公式を使って書くことができます。

1. ***<font color="MediumVioletRed">ユーザーの名前</font>***　から始める。
2. ***<font color="MediumVioletRed">ユーザーの特徴</font>***　について、短い説明を加える。
3. ***<font color="MediumVioletRed">ユーザーのニーズ</font>***　を明確に記述する。
4. なぜそのようなニーズがあるのかを説明する。言い換えれば、***<font color="MediumVioletRed">ユーザーについての洞察</font>***　です。

強力なプロブレム・ステートメントは、これらの条件を満たしています。

- ***<font color="Teal">人間中心で、特定のタイプのユーザーのニーズに焦点を当てている。</font>***　
- ***<font color="Teal">創造的な自由を得るために十分に広い。</font>***　
- ***<font color="Teal">実用的なデザインソリューションで解決するのに十分な狭さである。</font>***　

# プロブレム・ステートメントが与える影響

1. ***<font color="MediumVioletRed">目標</font>*** を設定するのに役立ちます。目標を明確かつ簡潔に定義することで、デザインチームの全員が同じことに集中することができます。
1. ***<font color="MediumVioletRed">制約条件</font>*** を理解するのに役立ちます。ユーザーのニーズを満たすために何が妨げになっているのかを知ることができます。
1. ***<font color="MediumVioletRed">成果物</font>*** を定義することです。最終的に問題を解決したとき、その成果として何が得られるのか。解決策から何が生み出されるかを知ることができます。
1. ***<font color="MediumVioletRed">成功のベンチマーク</font>*** を作成するのに役立ちます。成功したとき、私たちはどのようにそれを知ることができるのでしょうか。例えば、ドアを開けるのが目的なら、ドアの向こうに何があるのかが見えたら成功だと言えるでしょう。ほとんどの設計上の問題は、ドアを開けることよりも複雑ですが、成功の基準は同じように単純であるべきなのです。
GithubやGistでソースコードを公開する方法

### 前提

まず Github アカウントが必要なのでアカウントを作る必要があります。
👇

https://github.com/

Githubでソースコードを公開するにはSSH経由で行うのが便利です。設定は下記のリンクを参考にしてください。
👇

https://docs.github.com/ja/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account

もしハードルが高ければまずはGistを使いましょう。Gistはちょっとしたコード断片を公開するためのGithubが提供しているサービスです。ブラウザ経由でテキスト入力できるのでSSHの設定しなくても使えるかと思います。
👇

https://gist.github.com/

本格的に開発して、他の人から修正の提案をもらったりするにはGithubでレポジトリ（プロジェクトのようなもの）を作ると良いでしょう。


#### 補足：Githubとは

Githubとは、gitというソースコード管理ソフト（なんと作者はLinuxをつくったLinus Torvaldsなんですよ）を使って、コードの共有をより便利にしてくれるウェブアプリケーションです。なお、Githubは2018年に75億ドル規模でマイクロソフトに買収されていて、マイクロソフト傘下になっています。Xamarin創業者のNat Friedmanが率いて、絶妙なバランスでマイクロソフトの資本を利用しつつ独立性を維持してきましたが、2021年11月に退任していて、今後の動向に注目しています。

gitの概要は下記のイメージがわかりやすいです。開発者が手元に開発環境を用意しつつ、変更しつつ、リモートリポジトリでいい感じにまとめてくれるイメージです。このリポジトリをホスト（サーバーで管理）してくれるのがGithubです。
（似たサービスに[Gitlab](https://about.gitlab.com/ja-jp/)などもあります。）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29088/cc70d519-6169-c00c-1708-a67dfc4b09c5.png)
ref. https://backlog.com/ja/git-tutorial/intro/02/

なおGist裏側ではgitで管理されています。Githubの話をしているのかgitの話をしているのかを抑えると理解が進無かと思います。

### Githubでリポジトリをつくって共有する

https://github.com/


ここからステップをまとめます。

メニューからNew repository
![スクリーンショット 2022-10-17 19.03.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29088/138f14f5-ef2b-b5cc-985b-c5d7892e5e89.png)


Repository nameを入れる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29088/821bfbd9-1462-9f53-432b-d99cbbc02eda.png)

次の画面に表示されているコードを公開したいディレクトリ（ターミナル）に入り実行する

```sh
git remote add origin git@github.com:geeknees/henkaku-event00.git
git branch -M main
git push -u origin main
```

:::note alert
注意！！！
認証情報などの外部に漏れて困る情報はレポジトリに決して入れないでください
Discord botを作っている場合などはPersonal Access Tokenがこれに当たります
機械的にGithubはクロールされており、あっという間に悪用されるリスクにされされます
:::

やってみると、こんな感じになるかと思います。
![スクリーンショット 2022-10-17 19.09.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29088/98c1794f-9444-c0bb-6e28-44121f9ad22d.png)


ページをリフレッシュするとコードが共有されています。これを他の人に送ればOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29088/ffe3b2ca-8a1d-04c0-a25e-3f55acaacf03.png)

#### Gistでリポジトリをつくって共有する

https://gist.github.com/

ログインしているとこんな感じの画面になっていると思うので
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29088/0f8cabd4-b976-0223-2ccc-d86c5236bb3c.png)

入力してCreate secret gistを押せばOKです。なお投稿ボタンの右の三角を押すと公開、非公開の設定を切り替えることができます。非公開でもURLがわかれば誰でもアクセスできます。

こんな感じで公開されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29088/fb51decc-6c52-48b9-f7f8-8936361d0c08.png)

GithubやGistでソースコードを公開する方法は以上になります。
webアプリ開発をしてたらなぜかAPIを叩く処理が2回呼ばれてた

# 何が起こったか
なぜかAPIのURLが2回呼び出されていて、APIを叩く処理の直前にConsole.log()仕込んでも1回しか出力されなくて、でもやっぱりAPIは2回呼び出されてて(AWSのログで確認した)めちゃくちゃ困りました。

# 解決策
Chromeのデベロッパーツールからサイトデータを削除を実行したら解決しました。

# 原因
バグってるサービスワーカーが悪さをしていました。

なんとなくサイトデータを削除してみたらうまくいって、コンソールにもサービスワーカーのエラーメッセージ(Next.jsの仕様だと思い込んでたやつ)が出なくなったので、もしやと思って心当たりのある別のWebアプリを
```shell
npm run dev
```
でサーバー立ててブラウザに読み込ませて、
もう一度もとのWebアプリに戻ってサーバー立てて読み込み直してみたら全く同じ現象が起こったのでこれが原因で間違いないだろうということになりました。
(ついでに以前書いたサービスワーカーがバグってるってことも判明しました🥺)
:has()疑似クラスの使い方メモ

今後のデザインで採用するかもしれない疑似クラスのメモ書き
cssで意図したスタイル、アニメーションを当てられないときはJavaScriptで実装する。もし、:has()疑似クラスを使えばJavaScriptを使用しなくても、指定したセレクタやDOMを取得し、任意のスタイルを当てることが出来るようになる。
使い方の一例をあげる

例
~~~html
<div class="card">
    <div class="card-image">
        <img src="awameh.jpg" alt="">
    </div>
    <div class="card-content">
    </div>
</div>
 
<div class="card">
    <div class="card-content">
    </div>
</div>
~~~
例
~~~css
.card:has(.card__image) {
    display: flex;
    align-items: center;
}
~~~
上のコードでは子要素に`.card__image`がある`.card`にCSSが適応されます。


現時点ではFirefoxはまだサポートされていない。
[has():疑似クラスのサポート状況](https://caniuse.com/?search=has())
なので、まだ採用はしない、JavaScriptや、CSSのの記述量を減らせるのは大きいので早くサポートしてほしい(´・ω・`)

#### 参考：
[CSSの:has()疑似クラスの便利な使い方を徹底解説](https://coliss.com/articles/build-websites/operation/css/has-pseudo-class.html)
【Python】妻に真夜中のダンスレッスン予約を強要されたので、Webスクレイピングで回避を試みようとしている話 （４．処理フローについて考える）


前回は、<a href="https://qiita.com/sibulabo/items/e9c510be3bf6fdc00604">「３．Chromeドライバの配置」</a>について発信しました。昨夜は月１の真夜中の争奪戦だったので、結構寝不足です。:weary:　寝不足ながらもこの状況を抜け出すため頑張るのです。今回は予約プログラムの処理フローについて考えました。以前掲載した要件定義は以下のとおりです。

 ## 要件定義
>1. 会員情報、予約情報（予約レッスン日時、予約場所など）は、Excelで管理
>1. Excelファイルより必要情報（会員情報など）読み込む。
>1. 読み込んだ情報を元にログインし、予約操作を行う。
>1. 処理結果がわかるようにする。
>1. ツールの起動時間の設定ができるようにする。

５の起動時間の設定については、Windowsのタスクスケジューラを使用することにしました。こちらのほうが簡単・確実です。

## 構成図？は、こんな感じです。
手書きで汚くてすみません；；
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2915699/3a94b0f1-e4af-0fde-fb65-310a11778549.jpeg" width="70%">
この図だけ見ると、すぐにつくれそうな気がしてきました。:kissing:

## 予約プログラムの処理フロー
大まかな処理フローは以下のようなものです。
（実は処理フローも手書きでしたが、余りにあれだったので頑張って作りました。:clap_tone2:）

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2915699/0bb254a5-76fa-54f3-f85e-398e150c48ca.png" width="50%">

うん、フローもシンプルです。たぶん行けるんじゃないでしょうか。:dancer_tone3:

> 今回は、大まかな処理フローについて考えました。
> 次回は、会員・予約情報を Excelファイルでどう管理するかについて考えたいと思います。
色彩士が語る SwiftUIの赤は赤じゃない件

# はじめに
```Swift
import SwiftUI
Color(.red) //...(1)
Color.red   //...(2)
```
(1)と(2)の違い、分かりますか？

## 答え
表示してみるとこうなります。
![red1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/c7cb3321-df91-be5d-e169-55eac3ae9bfb.png)
SwiftUIで作ったアプリを動かしてみたら、なんだか色が違う気がする...:thinking:
そんな時に思い出していただければ幸いです。:blush:


# 解説
```Swift
Color(UIColor.red) //...(1)
Color.red   //...(2) == UIcolor.systemRed 
```
書き下すとこうなります。
(1)は```UIColor```の```red```(Fixed colors)をColorに変換したものです。
(2)は```red```という名前ですが、```UIColor```の```systemRed```(Standard colors)相当です。

ややこしいわ！:angry:と思った方のために、
```Swift
Color(uiColor: .red)  //...(1)の代わりに使う
```
こちらのイニシャライザを使った方が混乱が減ってお薦めです。:blush:
**iOS 15.0**から使用可能です。:cry:


## ちなみに
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95033/2c4b884a-1e15-0310-6df7-f543010b65e6.png" width=320>

(1)の書き方はドキュメント上は**Deprecated**になっているはずなんですが、
```Swift
@available(iOS, introduced: 13.0, deprecated: 100000.0, message: "Use Color(uiColor:) （中略）")
extension Color {
    public init(_ color: UIColor)
}
```
定義を見ると```iOS 100000.0```でDeprecatedになっているのでビルド時に警告が出ないんです。:joy:

# 参考
[Color | Apple Developer](https://developer.apple.com/documentation/swiftui/color)
[UIColor | Apple Developer](https://developer.apple.com/documentation/uikit/uicolor/)
ほぼ毎日Qiitaを２時間見る私が、特に好きな記事をまとめてみた

# 前書き
5か月ほど前にQiitaに登録し、それから登下校中や休憩時間など、空いた時間は基本Qiitaを見るようになりました。
ストックした記事が106、LGTMした記事が12ページ分にもなり、記事の整理もかねて、特に好きな記事や理解が深まった記事などを振り返りつつまとめようと思います。

無言で記事を掲載しております。迷惑だったら申し訳ありません。
が、随時更新予定です。

追記(2022/10/18)
Twitterにておすすめの記事を紹介していただきました！
今後もそういった機会があることを信じて、ほかの方にオススメされた記事を紹介する枠を設けます。



# 誰に向けて
+ Qiita触りたての人
+ プログラミング始めたての人
+ 自分自身

# 最初に見ておくべき記事
https://qiita.com/YutaManaka/items/62dda256bb7ba6c08399

最初の頃は数学と同じように変数を決めていたため、aやbとしていたが、この記事を見て驚愕した（笑）

https://qiita.com/KNR109/items/3b14e2e8f89a33c0f959

リーダブルコードを読むきっかけとなった記事。
もはやこれだけでいいのではってくらい読みやすく簡潔に書かれている。

https://qiita.com/suzu-4/items/ea5d802cb0ad16682ae2

まだ全然読めてません。
何やればいいかわからなくなったとき用


https://qiita.com/sensuikan1973/items/74cf5383c02dbcd82234

VSCodeの拡張機能をまとめたもの。
実際に使った様子が見られるので、読み物としても面白い記事。

https://qiita.com/developer-kikikaikai/items/9e08fe0f8ee0eebaccab

うーん、難しい
優しく柔らかい心をもとう
(2022/10/31追記)


# JavaScript

https://qiita.com/Yametaro/items/70e7878c5ea51788b643

分割代入、テンプレート文字列、スプレッド構文などの最近の記法の使い方が会話形式でわかりやすく書かれている。

https://qiita.com/cheez921/items/41b744e4e002b966391a

promiseの壁に当たっている今勉強中です

https://qiita.com/Yporon/items/b35f6102f724efa0f43d

constの概念を間違えて考えている人は少なくないと思う。(2022/10/18追記)



# TypeScript

https://qiita.com/Yametaro/items/2eaa6fd75255c8c2a2bb

JSを勉強していた私が、TSなんてめんどくさいだけじゃね？と思っていたが、TSを始めるきっかけになった記事。

https://qiita.com/uhyo/items/e2fdef2d3236b9bfe74a

TSの型についてまとめてある(2022/10/18追記)

# React

https://qiita.com/Yametaro/items/621bfd8c894f8fd36539

ReactHooksについて


# その他

## Electron

https://qiita.com/tomomoss/items/2b4112d6e22065c8615b

Electronとは、フロントエンドの技術のみ(HTML, CSS, JavaScriptのみ)でデスクトップアプリを作れるというもの。
存在を知って試してから1時間ほどで実際にオセロをデスクトップアプリにすることが出来た。（オセロはもともと作ってあるもの）

# 他の方のオススメ記事

https://qiita.com/rana_kualu/items/ea78200036fc80dce0a9

VSCodeのショートカット機能をまとめたもの（を和訳したもの）。
Ctrl + Shift + L など知らないがかなり使いやすそうなショートカットも多くあった。(2022/10/18追記)


# この記事も見てください！（おすすめではなく宣伝です）

https://qiita.com/scythercas/items/4fdb672f6e4ebb13da1a

私の記事も見てほしい
海外クラウドソーシングへの挑戦①

# はじめに 

昨今（10/16時点で、1ドル148円）の円安、海外のインフレ、進まない日本の賃金上昇などを見て、個人で海外の仕事を受注できないかどうかを考えてみました。

また、翻訳技術の発達により、リアルタイムの音声会話以外は翻訳サイトによる翻訳で十分なように思います。（DeepLで十分だと思います。）

そこで、見つけたのが海外のクラウドソーシングのサイトを使った仕事の受注です。

## 海外クラウドソーシングサイト

全体のクラウドソーシングのサイトとしては、[こちら](https://ferret-plus.com/2476)を参照してください。

私は、自身としては、AIエンジニア、データサイエンティストの仕事を探すため、以下のサイトに登録してみました。

- [freelancer.com](https://www.freelancer.com/) 
   かなり大手のサイトで、エンジニア系の案件が多く、充実しています。  
　 現在このサイトをメインで利用しています。

   AI、データサイエンスの案件も非常に多く、「Computer Vision」、「Machine Vision/Video Analytics」、「NLP」で60件もヒットします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1004109/50a659d3-fc9e-53bc-0b2a-22c011ab2315.png)

- [upwork.com](https://www.upwork.com)
   こちらも大手のサイトで、日本人でもupwork.comに登録して、海外の案件を受注したという方を多く見受けられます。  
    こちらも、AIやMachine Learning系で数十件の案件が常時ヒットします。  

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1004109/511fef30-91d2-3a02-3b12-7cccf44db705.png)

- [fiverr.com](https://www.fiverr.com)  
  他にfiverrというサイトにも登録しましたが、こちらは公開されている案件に応募するという形ではなく、仕事を頼みたい人が仕事を依頼する人を探すためのサイトのようです。 
  なかなか、英語での実績がないと難しそうです。


# まずは登録
  まずは、サイトの登録とプロフィールの作成ですが、やはり英語プロフィールを登録するのがなかなか難しいですね。    
  とりあえずは、日本語で簡単なプロフィールを書いて、[deepL](https://www.deepl.com)などで翻訳したものを登録して、実際にサイトに入った後で、実際に案件を受注している人のプロフィールを真似してみてもいいかと思います。  

  [github](https://github.com/)でコードの公開をしている人は、githubで連携した方がいいと思います。できれば、readmeの英語バージョンを作っておくとアピールになるのではないかと思います。  

  また、先ほど発見したのですが、freelancer.comについては、サイトの日本語化が可能なようで、プロフィールの「setting」から表示言語を変えることができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1004109/99ffa268-2c52-be94-f480-32131f10cd20.png)

なんだかんだ日本語サイトだと落ち着きますね。。 


# 案件に応募する
  日中は他の業務を行なっているため、軽めの案件を中心に案件への応募を行なっていきました。  
  実際に案件を見てみるとやはり、実績のない状態での案件獲得というのは非常に難しいということを実感します。
   
  相手の立場になって考えると、
 -  「実績がない」
 -  「プロフィールに書かれている情報もどこまで信用できるかわからない」
 -  「英語のSNSなどの情報もないから、信用できる人かもわからない」
状態なわけですから、頼みにくいというのは当然のように思います。

であれば、まずは安い価格で難易度の低い案件に応募しようということで、応募してみていますが、これも中々難しいです。


（日本語のスキルを求める案件は、相手側からオファーがくることもかなりあり、比較的容易に受注できるようです。まず、実績を作りたいという方は日本語関係の案件を獲得することを検討しても良いかもしれません。）
 
 
# Contests形式の案件に応募する
  いくつかの案件に応募してみましたが、中々受注することが出来ませんでした。  
  プロフィールの記載を充実させたり、サイト内の有料プログラムの受講やテストを受けることで、プロフィールを充実させるという手段もありますが、正直それほど有効ではない気がします。  
  やはり、実際に手を動かしたいということと、手取り早く実績を作りたいということで「Contests」形式の案件に応募してみました。  

Contests形式の案件は、実際に作業した後に相手側が採用するかどうかを選ぶため、とりあえず案件に取り掛かることができます。
- 採用されれば、実績になる。
- 採用されなくとも星などの評価がもらえれば実績に出来る。  
- 実際、手を動かして、実案件を実施するので、実践的な学習  

また、過剰サービスになってしまいますが、相手が要求したもの以上のものを納品することでより選ばれる可能性が高まります。  

実際、今回かなり過剰サービス気味の内容を納品して、案件を勝ち取ることが出来ました。
(31Euroの案件に対して、10時間以上かけたので採算は全然合わないです。）

こうしたことで、実績を作りながらより高度で採算性の高い案件を獲得していきたいと思います。

# 最後に
1ドル148円とはいえ、グローバルのクラウドソーシングサイトだと物価の安い地域のフリーランサーが多い印象です。  

そのためか、高単価の案件はそれほど多くないように思います。（エンジニア向けの案件しか見てません、インフレが進行している欧米からの日本語特化系の求人であれば、高単価が期待できるかもしれません。）　　

今のところは副業として案件をこなして、キャリア形成のための経験を積む手段の一つぐらい考えた方が良いかとは思っています。
【Android】onBackPressedメソッドが非推奨になった

`onBackPressed()`が非推奨になったので、代替案を記述。

# 戻る処理を実行したい
```Kotlin
onBackPressedDispatcher.onBackPressed()
```

# 戻る処理を上書きしたい
```Kotlin
onBackPressedDispatcher.addCallback(object : OnBackPressedCallback(true) {
	override fun handleOnBackPressed() {
		//戻りたい場合はfinish()を使用
    }
)
```
twitter/pelikanをPHPから使う

最近Twitterで`twitter/pelikan`というものを目にしました。

https://github.com/twitter/pelikan

MemcachedやRedisのようなキャッシュサービスで、上記リポジトリのREADMEによると既存のMemcachedクライアントで操作できるようです。
というわけで、PHPのMemcachedモジュールを使って試してみました。

## 検証環境
- Ubuntu 18.04.6 on WSL
  - Windows 10 Home
- PHP 8.1.11
- Rust 1.64.0

## インストール
### Pelikan
基本的には https://github.com/twitter/pelikan#building-pelikan の通りですが、cmake が apt でインストールした 3.10 では動かなかったので、[こちら](https://zenn.dev/suudai/articles/8b484ac39fde38)を参考に 3.23 を別途インストールしました[^1]。
[^1]:READMEには`cmake (>= 3.2)`と書いてあったのに……

### PHP
APT の`ppa:ondrej/php`リポジトリからインストールします。Memcached モジュールも`php8.1-memcached`でインストールできます

https://launchpad.net/~ondrej/+archive/ubuntu/php/

## 動かす
### サーバを起動
Pelikanをビルドすると、`target/release`ディレクトリに各種実行ファイルができるので、その中の`pelikan_segcache_rs`を起動します。

```console
$ target/release/pelikan_segcache_rs
2022-10-17T03:55:12.172+00:00 INFO [admin] running admin on: 127.0.0.1:9999
2022-10-17T03:55:12.172+00:00 INFO [server::listener] running server on: 0.0.0.0:12321
```

`9999`と`12321`の2ポートでサーバが起動していますが、通常のデータの操作で使うのは`12321`の方です。

### PHPで接続
```php:pelikan.php
<?php
declare(strict_types=1);

$client = new Memcached();
$client->addServer('localhost', 12321);

$client->set('string', 'foo');
$client->set('array', ['foo' => 1, 'bar' => 'baz', 0 => 'qux']);
$client->set('object', (object)['foo' => 1, 'bar' => 'baz', 0 => 'qux']);
$client->set('int', 0);
$client->increment('int');

var_dump(
    $client->get('string'),
    $client->get('array'),
    $client->get('object'),
    $client->get('int'),
);
```

上記コードを動かすと、以下の出力となり、ちゃんと値が保存されていることがわかります。

```
/path/to/pelikan/pelikan.php:17:
string(3) "foo"
/path/to/pelikan/pelikan.php:17:
array(3) {
  'foo' =>
  int(1)
  'bar' =>
  string(3) "baz"
  [0] =>
  string(3) "qux"
}
/path/to/pelikan/pelikan.php:17:
class stdClass#2 (3) {
  public $foo =>
  int(1)
  public $bar =>
  string(3) "baz"
  public $0 =>
  string(3) "qux"
}
/path/to/pelikan/pelikan.php:17:
int(1)
```

一方、`getVersion()`や`getStats()`といったメソッドは上手く動作しませんでした（ポートを`9999`に変えてもダメでした）。

## まとめ
基本的な操作であれば、PHP の Memcached モジュールを使って Pelikan を利用できました。
一部利用できないメソッドもあるものの、シンプルな使い道であれば利用できるかもしれません。
PyCon JP 2022 day1 Keynote

10/14(金)~15(土)に開催されたPyCon JP 2022に行ってきました。
私自身まだPython歴半年の若輩者ですが、諸先輩方から学びたいと思い初めて参加することにしました。

各セッションごとに、記事を投稿していきたいと思います。
まずはDay1のKeynoteからです。

# 動画
<iframe width="560" height="315" src="https://www.youtube.com/embed/pboJZAQO9h8?start=3389" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

# スライド
- 公開なし

# スピーカー
- Mark Shanonnさん
  - Microsoftが出資するCPython高速化チームのリーダー

# 内容まとめ
- PythonのVMごとの高速化についての話

## 用語について
### VM(バーチャルマシン)
- Pythonプログラムを動かすためのマシン

### Baseline Performance
- 最適化されてないコードの高速化

### Optimizer Performance
- optimizer自体の高速化

## Psyco(2003-2007)
- JITコンパイラーの特殊化
- シンプルにする(間違った)仮説を立てた
- 上手くいったら早い
- 32bit x86 のみ

## PyPy (2006-)
- Psycoの方向性を正しく行った
- RPythonで書かれている

## HotPy (2007-2010)
- PhDの研究
- JITのトレース

## Jython and IronPython
### Jython (1997-)
- JVM上で動くPython
- Cpythonより少し遅い
### IronPython (2006-)
- .NET上で動くPython

## Unladen Swallow (2009-2011)
- Googleのプロジェクト
- Based on Cpython
- 最終的な目標は、Cythonにマージすること

## Pyston version1(2014-2017)
- DropBoxのプロジェクト
- LLVMが使われている

## Pyjion (2015-2022)
- RyuJITが使われている

## Skybison (2018-2021)
- Instagram(現Meta)のプロジェクト
- 特別なインタプリタを搭載
- No JITコンパイラー
- Cinderに移行

## Cinder (2019-)
- Instagram(現Meta)のプロジェクト
- Based on Cpython
- 大規模なサーバファームになら有効

## VMのプロジェクトは失敗が多かった
- たくさんのプロジェクトが立ち上がったわりに、過去の失敗から学ばなかった

## Pyston version2 (2020-)
- 最新のVM
- メソッド単位のJITコンパイラー
- Based on Cpython

## Fater CPython (2021-)
- Microsoftのプロジェクト
- CPythonの数倍の高速化を目指す
- 学んだ教訓を活かす
- Python 3.11として、10日後くらいにリリースされる

# 感想
- 私自身過去にはPHPとかRubyをやってきましたが、処理系まで深く勉強したことがなかったので、学びになりました。
- 「たくさんのプロジェクトが立ち上がったわりに、過去の失敗から学ばなかった」というのは、各社単体ごとのプロジェクトだったので、それぞれのノウハウが共有されにくかったのかなと思いました。
Expressのエラー処理まとめ　【第2弾】バリデーションのミドルウェア

# はじめに
Expressを学び始めて、エラーハンドラの扱い方にいくつかのパターンがあるため、実装方法を整理。
本記事では、第2弾としてExpressにおける、エラーハンドラを利用したミドルウェアのバリデーションをまとめる。
1. <a href="https://qiita.com/mntocchi/items/2a87f9affdfea6ebae61">Expressのエラー処理まとめ　【第1弾】Expressのエラーハンミドラの定義</a>
2. Expressのエラー処理まとめ　【第2弾】バリデーションのミドルウェア（本記事）
3. <a href="https://qiita.com/mntocchi/items/96107912784761b3bb0a">Expressのエラー処理まとめ　【第3弾】非同期関数のエラーハンドラ</a>
 
## 1.ルートハンドラでバリデーションの定義
ルートハンドラでミドルウェアを複数列挙することで、リクエストを受けてからレスポンスまでに行いたいバリデーションを複数定義することができる。
その列挙されたミドルウェアの中で、バリデーションエラーが発覚した場合、エラーを発生させてバリーデーションエラーを実装することができる。

````javascript
// ルートハンドラ
app.get('/login', verifyLoginid, verifyPassword, (req, res) => {
    res.send('ログインしました。')
});
````
上記の場合、「/login」にリクエストがあった場合に、レスポンスを返すまでにの以下の流れで処理される。
1.  verifyLoginid：ログインIDのバリデーションを実施
2.  verifyPassword：ログインパスワードのバリデーションを実施
3.  レスポンスのコールバック関数

## バリーデションミドルウェア関数の中身
バリデーションのミドルウェアでは正常の場合はnext()で次の関数へ進み、入力エラーが発見された場合は、エラーハンドラーを利用してレスポンスを返す形が基本形。
「verifyLoginid」と「verifyPassword」中身を確認する。
````javascript
// Idのバリデーション
const verifyLoginid = (req, res, next) => {
    const { id } = req.query;
    if (id === 'hoge') {
        return next(); //次のミドルウェアへ
    } else {
        // エラーハンドラへ
        throw new AppError('ログインIDが誤っています', 401);
    }
}

// Passwordのバリデーション
const verifyPassword = (req, res, next) => {
    const { password } = req.query;
    if (password === 'moge') {
        return next(); //次のミドウェア（コールバック関数）へ
    } else {
        // エラーハンドラへ
        throw new AppError('パワードが誤っています', 401);
    }
}

// ルートハンドラ
app.get('/login', verifyLoginid, verifyPassword, (req, res) => {
    res.send('ログインしました。')
});
````

処理の結果として、idもしくは、パスワードが誤っている場合はエラーになり、エラーハンドラーにキャッチされていることがことが分かる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2830661/86234590-f991-2fd5-7333-0d77807838f5.png)

idとパスワードの両方とも正しい場合に、ルートハンドラのレスポンスコールバック関数が処理され、ログインができていることが分かる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2830661/ba3602ee-3772-a645-ca8c-001aaa3b32c8.png)

# まとめ
ルートハンドラでバリデーションミドルウェアを実装すると、ＯＫの時は次の処理（ミドルウェアもしくはレスポンスのコールバック関数）へ移り、NGの場合はエラーハンドラへエラーを飛ばすことで入力チェックを実装することができる。app.useのミドルウェア関数と使い方は異なるが、ルートハンドラに組み込まれる関数とエラーハンドラを利用することでバリデーションを実装できることが分かった。
エラー処理のまとめ第3弾へ続く。
【UiPath】実行ユーザーに設定ファイルを選択させ読み込む

# 概要
設定ファイル(.xlsx)を作り、実行時最初に読み込ませることで、
項目値が固定値として実行ファイル内に固定されることなく、実行ユーザーごとに任意に設定できるようにする方法です。


例えば
・処理対象フォルダ/ファイルが実行ユーーごとに変わるとき
・ログインユーザー名、パスワードが変わるとき
・保存先フォルダを実行ユーザーにて指定したいとき

などを想定しています。

# 想定シナリオ
とあるウェブサービスにログインする

# 設定ファイルを作る
パラメータとして設定したい項目をA列に記載
B列には実行ユーザーにて指定したいパラメータ値を任意に入力
ファイル名は設定ファイルらしき名前をつけ任意の場所に保存


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351505/aeff54ec-90f6-b6b5-4fdb-e777deaaca63.png)


# UiPathで変数を作成
設定ファイルにて設定した各種パラメータ項目を格納する変数を作成する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351505/44f9a3f1-f4eb-3e0d-2ab1-fb4f25a20ee6.png)


# UiPathにて設定ファイル読み込み機構を作成

1. ファイルを参照　を設置
　ファイル選択ダイアログが表示され、実行ユーザーが任意に設定ファイルを選択できるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351505/8e1bc988-6004-6a01-b088-9e1e0e0a1def.png)

2. Excelアプリケーションスコープ　セルを読み込み　を設置

Excelアプリケーションスコープには先ほど「ファイルを参照」にてファイルパスを入れる予定の変数「configfile」を指定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351505/bd3b2e79-2224-04e7-87b2-5173f5c1f6a2.png)


セルを読み込みには
設定ファイル内のシート名、読み込み対象セル(B列)を指定し、さきほど作成した各値を入れるための変数を出力結果に指定する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351505/17db74dc-50a4-498c-510a-999806b53745.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351505/6681a583-2648-6878-8631-864cae622347.png)

これを設定シートにて指定した項目分作成


# 変数に入れた各値を実行時に利用する
各アクティビティにて設定ファイルから取得した値を格納した変数を使います。
ブラウザ：URL
ログインID：ID
パスワード：PASS

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351505/242bd336-b73e-42b0-1ddc-9ef9f3ea8bdb.png)


# 最後に
複数人で同じシナリオファイルを利用していると、windowsのログインユーザーごとにユーザーフォルダを区別されているとフォルダ/ファイルのパス系を求めるアクティビティでは固定値を使えないことがあります。

設定ファイルなんて用意しなくてもシナリオ内でうまく解決できる方法はいくらでもあると思いますが、手っ取り早く解決するにはこの手法がシンプルで後にも分かりやすいかと思います。


※例としてログインIDとPASSを設定ファイル内のパラメータ値として利用していますが、セキュリティ的に設定ファイル内にIDとパスのベタ書きはお勧めしません。
設定ファイルにパスワードつけて保存し、シナリオ実行時にパスワード入力させる処理をいれる
もしくはログイン情報は別途都度入力を求めるなどがいいかと思います。
AWS ソリューションアーキテクト アソシエイト SAA-C02 合格体験記

# はじめに
2022年8月末、SAA-C02終了間際で受験し、無事合格しましたので学習方法等まとめてみます。
C03に移行してしまいましたが、今後受験する皆様のお役に立てれば幸いです。

# 試験概要
出題問題数 : 65問
合格点 : 720/1000点
出題形式 : 択一選択式 ・複数選択式
試験時間 : 130分
受験料金 : ¥16,500

# 試験範囲
Well Architected Frameworkの6つの設計原則のうち、
「運用上の優秀性」「サステナビリティ」以外の4つが試験範囲  

・レジリエントアーキテクチャの設計 30%
・高パフォーマンスアーキテクチャの設計 28%
・セキュアなアプリケーションとアーキテクチャの設計 24%
・コスト最適化アーキテクチャの設計 18%

# 受験当時の経歴
未経験でインフラエンジニアとして転職して4か月半が経過
参画している案件はオンプレミスのWindows構築
研修でEC2構築したくらいで、クラウドの実務経験はなし
AWSクラウドプラクティショナーは取得済み

# 学習方法
#### 学習に使用したもの
[TeckStock | AWS WEB問題集で学習しよう](https://techstock.jp/exam/aws-exam2/)
[【2022年版】これだけでOK!AWS認定ソリューションアーキテクト-アソシエイト突破講座](https://www.udemy.com/course/aws-associate/)
[【2022年版】AWS認定ソリューションアーキテクト アソシエイト模擬試験問題集(6回分390問)](https://www.udemy.com/course/aws-knan/)
[ping-t 最強WEB問題集 AWS認定ソリューションアーキテクト-アソシエイト(SAA-C02)](https://ping-t.com/)
[AWS ソリューションアーキテクト アソシエイト試験 対策動画](https://www.youtube.com/watch?v=fsz6G45A4H4)

#### 学習期間
約2か月半
1日1,2時間程度(もっと勉強する日もある)
トータル学習時間 150時間程度


#### 学習方法詳細

**1. Udemyの試験突破講座をとりあえず1周視聴する**
<font color="Gray ">→2週間程度
ハンズオンも行いながら進めていたものの、なかなか進まず諦め、、
とりあえず1.5倍速でざっと動画を視聴し、内容を把握しました。</font>

**1. Udemyの模擬試験を解いてみる**
<font color="Gray ">→1週間程度
65問解き終わらないと解説見れない+問題文長い
やる気が続かず、2回分だけ解いて、一旦学習サービスを変更しました。</font>

**1. Ping-tの問題を解いてみる**
<font color="Gray ">→1週間程度
軽く50問くらいだけ解いて、解説を読んでメモにまとめました。
問題で扱っているサービスが同じだと解説も全部同じだったので、これをメインの問題集として使うのは微妙かなと思いました</font>

**1. AWS WEB問題集＃100以降を解きまくる**
<font color="Gray ">→2週間程度
一問一答でできるのが◎
90日で¥5000近くするのでちょっと高いかなと思ったものの、
実際の試験で似たような問題(むしろ同じ)が出たので、私的結構おすすめ問題集
#1など前半の方の問題は古いので、#100以降がおすすめ</font>

**1. Udemyの模擬試験を解く**
<font color="Gray ">→2週間程度
今までの学習であるていっど問題が解けるようになったのでUdemyに戻って学習開始
1回目60%だった正解率が81%になりました!!
90%を超えるまで解きました。</font>

**1. 今まで間違えた問題を解きなおして復習をする**
<font color="Gray ">→1週間程度今までの学習で間違えたところや理解が曖昧な部分を解きなおしました。
同じような問題で間違えたり、見直しマークを付けていたりするので、解説を読んで、試験前に弱点克服を目指しました。</font>

<font color="Red">ただ問題を解くだけではなく、しっかり解説を読んで、不正解の選択肢がなぜ不正解なのかなど、理解しながら進めていくことが大事かなと思います。</font>

# 試験を受けてみて
実際に受けてみて、思っていたより文章は長くなく読みやすい印象でした
(いつもスマホで勉強してたから、PCで画面が横長で行数少ない分短く感じただけかも、、、)

問題の難易度としてはこんなの知らんわ！って問題も少しあったものの、
こちらも思っていたより簡単だったように思います。

反省点として、サービスの細かい部分をもう少ししっかり覚えておけばよかったと感じました。
問題の難易度はUdemyやWEB問題集と同じか少し簡単くらいで、
インスタンスタイプ、ストレージの種類を選ぶ問題は出ませんでした。
ここの部分の理解がなかなかできず、結構時間を割いたので、若干ショックでした。
UbuntuからのODBCによるVantageへの接続

著者 [Adam Tworkiewicz](adam.tworkiewicz@teradata.com)
最終更新日 2022年1月5日

:::note warn
警告
本記事はTeradata Corporationによる[Getting Started](https://quickstarts.teradata.com/index.html#getting-access-to-vantage)に掲載された内容を抄訳したものです。掲載内容の正確性・完全性・信頼性・最新性を保証するものではございません。正確な内容については、原本をご参照下さい。
また、修正が必要な箇所や、ご要望についてはコメントをよろしくお願いします。
:::

# 概要
このハウツーでは、Ubuntu上のTeradata VantageでODBCドライバを使用する方法を説明します。

# 前提条件
・Teradata Vantageインスタンスにアクセスできること


::: note info
Vantageの新しいインスタンスが必要な場合は、[Google Cloud](https://qiita.com/ykswi/items/10a382de5fa5a4a42c50)、[Azure](https://qiita.com/ykswi/items/2c30aa1f5413b16c838c)、[AWS](https://qiita.com/ykswi/items/fba559149ad568678d58)のクラウドにVantage Expressという無料版をインストールすることができます。また、[VMware](https://qiita.com/ykswi/items/ebe1d854c38db9bb0f51)、[VirtualBox](https://qiita.com/ykswi/items/ffadaa375add309f2075)、または[UTM](https://qiita.com/ykswi/items/94995954ae723185c2f7)を使用して、ローカルマシン上でVantage Expressを実行することもできます。
:::

・Ubuntuマシンのルートアクセス

# インストール
①	依存関係をインストールします。

```:apt_install
apt update && DEBIAN_FRONTEND=noninteractive apt install -y wget unixodbc unixodbc-dev iodbc python3-pip
```

②	Ubuntu用のTeradata ODBCドライバをインストールします。

```:install_odbc
wget https://downloads.teradata.com/download/cdn/connectivity/odbc/17.10.x.x/tdodbc1710__ubuntu_x8664.17.10.00.14-1.tar.gz \
    && tar -xzf tdodbc1710__ubuntu_x8664.17.10.00.14-1.tar.gz \
    && dpkg -i tdodbc1710/tdodbc1710-17.10.00.14-1.x86_64.deb
```

③	ODBCの設定は、**/etc/odbcinst.ini**を作成して、以下の内容で行います。

```:setup_odbc
[ODBC Drivers]
Teradata Database ODBC Driver 17.10=Installed

[Teradata Database ODBC Driver 17.10]
Description=Teradata Database ODBC Driver 17.10
Driver=/opt/teradata/client/17.10/odbc_64/lib/tdataodbc_sb64.so
```

# ODBCを使用する
Pythonのサンプルアプリケーションでインストールの検証を行います。以下の内容で**test.py**ファイルを作成します。**DBCName=192.168.86.33;UID=dbc;PWD=dbc** を、Teradata Vantage インスタンスの IP アドレス、ユーザー名、パスワードに置き換えてください。

```python:test.py
import pyodbc

print(pyodbc.drivers())

cnxn = pyodbc.connect('DRIVER={Teradata Database ODBC Driver 17.10};DBCName=192.168.86.33;UID=dbc;PWD=dbc;')
cursor = cnxn.cursor()

cursor.execute("SELECT CURRENT_DATE")
for row in cursor.fetchall():
    print(row)
EOF
```

テストアプリケーションを実行します。
```:run_python
python3 test.py
```

というような出力が出るはずです。

```:result_python
['ODBC Drivers', 'Teradata Database ODBC Driver 17.10']
(datetime.date(2022, 1, 5), )
```

# まとめ
このハウツーでは、Ubuntu上のTeradata VantageでODBCを使用する方法について説明しました。このハウツーでは、ODBC Teradataドライバと依存関係をインストールする方法を説明します。また、ODBCを設定し、シンプルなPythonアプリケーションで接続を検証する方法を示します。

# さらに詳しく
・[Teradata®用ODBCドライバ ユーザーガイド](https://docs.teradata.com/search/all?query=ODBC+Driver+for+Teradata+User+Guide&filters=ft%3AisBook~%22true%22&sort=last_update)

#### Teradata Vantageへのお問合せ
[Teradata Vantage へのお問合せ](https://www.teradata.jp/About-Us/Contact)
【MySQL】カラム数の多いテーブルのレコードをスマートにコピーしたい

例えばこのようなテーブル

fruitsテーブル
| id | memo1 | memo2 | memo3 | memo4 | memo5 | memo6 | memo7 | memo8 |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| 1 |りんご1|りんご2|りんご3|りんご4|りんご5|りんご6|りんご7|りんご8|
| 2 |メロン1|メロン2|メロン3|メロン4|メロン5|メロン6|メロン7|メロン8|
| 3 |いちご1|いちご2|いちご3|いちご4|いちご5|いちご6|いちご7|いちご8|

このidが２のデータをコピーして、

| id | memo1 | memo2 | memo3 | memo4 | memo5 | memo6 | memo7 | memo8 |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| 1 |りんご1|りんご2|りんご3|りんご4|りんご5|りんご6|りんご7|りんご8|
| 2 |メロン1|メロン2|メロン3|メロン4|メロン5|メロン6|メロン7|メロン8|
| 3 |いちご1|いちご2|いちご3|いちご4|いちご5|いちご6|いちご7|いちご8|
| 4 |メロン1|メロン2|メロン3|メロン4|メロン5|メロン6|メロン7|メロン8|

このように追加したいときどうしますか？

idカラム には自動採番される、オートインクリメント(AUTO_INCREMENT)制約が付いています。

# 一般的な例

方法は多々あるかと思いますが、

```sql:例１
INSERT INTO `fruits`
    (`memo1`,`memo2`,`memo3`,`memo4`,`memo5`,`memo6`,`memo7`,`memo8`)
SELECT
    `memo1`,`memo2`,`memo3`,`memo4`,`memo5`,`memo6`,`memo7`,`memo8`
FROM
    `fruits`
WHERE
    `id` = 2;
```

```sql:例２
INSERT INTO `fruits`
SELECT
    0, `memo1`,`memo2`,`memo3`,`memo4`,`memo5`,`memo6`,`memo7`,`memo8`
FROM
    `fruits`
WHERE
    `id` = 2;
```

これらはいずれも、fruitsテーブル自身をSELECTした結果をINSERTしています。

しかし…カラムが多いですよね。
これがもっとカラムが多かったら大変です（実務ではより多くのカラムがありました）。

正直これはめんどうです。
カラムの記載漏れがあると、列の数が値の数と一致せずエラーになってしまいます。
それに、idカラムだけは、現状の採番順序に沿った値を入れたいので、除いて書いています。

# 工夫した例

そこでこれです

```sql
CREATE TEMPORARY TABLE `temp` AS SELECT * FROM `fruits` WHERE `id`= 2;
ALTER TABLE `temp` DROP `id`;
INSERT INTO `fruits` SELECT 0, `temp`.* FROM `temp`;
DROP TEMPORARY TABLE `temp`;
```

コピーしたいレコードを一時テーブルに一旦保存し、それをfruitsテーブルに挿入するという形をとることで、いちいちカラムを列挙することもない対応を可能にしています。

# 解説
```sql
-- 1行目
CREATE TEMPORARY TABLE `temp` AS SELECT * FROM `fruits` WHERE `id`= 2;
```
fruitsテーブルのid=2のレコードを入れた一時テーブルを作成します。

一時テーブルは、CREATE TEMPORARY TABLE構文を使って作成します。TEMPORARY句を付けること以外は通常のテーブルと同じ作り方になります。

一時テーブルは利用しているセッション内だけで有効なテーブルを作成し、セッションが閉じたときに自動的にテーブルが削除される構文になります。

そのため4行目にDROP TEMPORARY TABLE構文で削除を入れていますが、入れなくても基本は自動的に削除されます。

```sql
-- 2,3行目
ALTER TABLE `temp` DROP `id`;
INSERT INTO `fruits` SELECT 0, `temp`.* FROM `temp`;
```
一時テーブルのidカラムを削除し、その情報をfruitsテーブルに挿入しています。

idはオートインクリメントになっていますので、insertのselectに0を設定することで、fruitsテーブルのidに入る番号は、自動的に連番の値が入るようにしています。

```sql
-- 4行目
DROP TEMPORARY TABLE `temp`;
```
入れていなくても基本は自動的に一時テーブルは削除されますが、念のため入れております。


# 参考文献
https://qiita.com/amay077/items/ba27030e7009c16971ee

https://gihyo.jp/dev/serial/01/mysql-road-construction-news/0107

https://jobtech.jp/mysql/4017/

https://oreno-it3.info/archives/701

https://mebee.info/2021/12/20/post-51545/

https://ah-2.com/g1/2016/05/11/mysql_duplicate_record.html

https://dev.mysql.com/doc/refman/8.0/ja/example-auto-increment.html

https://uxmilk.jp/51311

https://dev.grapecity.co.jp/support/powernews/column/how_to_database/033/page04.htm
Accessのタブコントロールで特殊なSetFocusをすると実行時エラー2110になる件

# 概要

コンパイルエラーは無い。
SetFocusするオブジェクトは存在している。
なのに下記文言で例外。

> 実行時エラー'2110'
> コントロール ※※ にフォーカスを移動することはできません。

# 発生する条件

下記のように別々のタブページに2つのオブジェクトがある。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/33a2981e-277a-c43f-5b31-fa516e89a28d.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/83bc2ffd-1617-3b14-c2ae-5b6e464f1259.png)

そして『アクティブ時』『開く時』の両方で同じSetFocusをしている。

```vb
'フォームアクティブ時に実行される
Private Sub Form_Activate()
    Call focus
End Sub

'フォーム開く時に実行される
Private Sub Form_Open(Cancel As Integer)
    Call focus
End Sub

'『アクティブ時』『開く時』の両方で使う共通関数
Private Function focus()
    Me.txt_1.SetFocus
    Me.txt_2.SetFocus
End Function
```

↓実行時エラーで止まる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/eac23bcd-22c7-5f0f-c644-7e5ef2a0071f.png)

# 蛇足

まず前提として同じ処理を無駄に何回も実行しない。

基本は『アクティブ時』に実行。
**フォーム開く時だけ実行して欲しい** なら『開く時』、という使い分けをしっかりした方がいいと思う。

『アクティブ時』 = フォーム開く時とサブ画面から戻ってきた時の両方で実行される。
『開く時』 = フォーム開く時に実行されるが、サブ画面から戻ってきた時には実行されない。

# バージョン

Windows 10 Pro 21H2 OSビルド 19044.2130
 Microsoft Access for Microsoft 365 MSO (バージョン 2209 ビルド 16.0.15629.20196) 32 ビット
Vagrant入門まとめ

- [Vagrant入門①：基礎知識](https://qiita.com/ishige990/items/8967517b12b944a6b73e)
- [Vagrant入門②：Vagrantで仮想マシンの起動](https://qiita.com/ishige990/items/4b6dfeec6c1fdb68d4e2)
- [Vagrant入門③：Boxのコマンド](https://qiita.com/ishige990/items/0e0cc6671bb1092b6ff4)
- [Vagrant入門④：Vagrantの設定](https://qiita.com/ishige990/items/acbb06d9099754cb19f2)
- [Vagrant入門⑤：仮想環境をGUIで立ち上げる](https://qiita.com/ishige990/items/87c9eeb361f7ac43a15b)
- [Vagrant入門⑥：マルチマシン設定](https://qiita.com/ishige990/items/5ed90a2d6cc5d6e18c78)
- [Vagrant入門⑦：Snapshot](https://qiita.com/ishige990/items/4ce7345598f50d9b490d)
- [Vagrant入門⑧：Provisioning](https://qiita.com/ishige990/items/e3cc74ef29d28f12d8e2)


# 参考
[WEB ARCH LABO / Vagrant入門](https://weblabo.oscasierra.net/vagrant/)
Nuxt3のbuildで、Nitro 0.5.4のbuildがnode_modulesの依存パッケージを強制的に最新版にしてしまう(Picking latest version)ことで起こるuuidの問題を無理やり回避する

## Nuxt3 で buildすると、以下のようなwarningが出ることがある。


```sh
$ nuxt build
Nuxt 3.0.0-rc.11 with Nitro 0.5.4                                                 

 WARN  Multiple major versions of package uuid are being externalized. Picking latest version:                                                 

  + /Users/***/sequelize/node_modules/uuid@8.3.2
  - /Users/***/request/node_modules/uuid@3.4.0
```

###  WARN  Multiple major versions of package uuid are being externalized. Picking latest versionとは

Nitroのbuildの便利機能？で同じnode_modulesパッケージを使っている場合、最新版に統一しておいてやるよ！それなら重複しなくて軽くなるだろ？という機能なのですが、これで困ったことが起こりました。

## requestという古いnpm packageを使っているライブラリがあると。。。

requestパッケージの中で

```
var uuid = require('uuid/v4')
```

という風にリクエストしているのですが、**uuidパッケージの最新版では仕様が変わってこの呼び方が廃止されている。**

よって実行時にこういうエラーが出て、requestに依存しているnode_modulesパッケージが動かなくなります。

`Package subpath './v4' is not defined by \"exports\" in /***/.output/server/node_modules/uuid/package.json`

## 対策方法

> request has been deprecated, see https://github.com/request/request/issues/3142
と警告が出ています。

### 自分がrequestパッケージを使っているなら、おとなしく、使うのをやめましょう。

https://www.npmjs.com/package/request

### requestが別のライブラリの依存パッケージだったらどうする

以下のコマンドで`require('uuid/v4')`としているところを`require('uuid')`に強制的に書き換えてやった

`find .output/server/node_modules/request/lib/*.js | xargs sed -i.bak 's/uuid\/v4/uuid/g'"`

uuidのpackage.jsonの方を書き換えてもいいみたいね

https://www.anycodings.com/1questions/55164/error-errpackagepathnotexported-package-subpath-v4-is-not-defined-by-exports



## やっぱNuxt3(Nitro)しんどいわ
Vagrant入門⑧：Provisioning

# Provisioningとは？
仮想マシンの状態設定を自動化する機能  
VagrantfileにProvisioningを記述する


# Provisioning設定(Vagrantfile)
``config.vm.provision``のコメントアウト部分を外し、設定を記述する
```
Vagrant.configure("2") do |config|

    config.vm.provision "shell", inline: <<-SHELL
        yum install -y httpd
        service httpd start
    SHELL

end
```


# Provisioningの確認
```
$ vagrant up
$ vagrant provisioning
default: Complete!

$ vagrant ssh
[vagrant@localhost ~]$ service httpd status
Active: active (running)
```


# 参照
[Vagrantプロビジョニング入門 – シェルスクリプトで簡単プロビジョニング (1)](https://weblabo.oscasierra.net/vagrant-provisioning-shell-1/)
Vagrant入門⑦：Snapshot

# Snapshotとは？
Vagrantのバージョン1.8から追加された機能  
ある時点の仮想マシンの状態を保存/復元できる  
※Vagrantのバージョンが1.8以上でないと、Snapshot機能を利用できないので注意。


# マシンの状態を保存する
マシンの起動、SSHの接続、ファイルの作成
```
$ vagrant up

$ vagrant ssh
[vagrant@localhost ~]$ touch ~/TEST1.txt
[vagrant@localhost ~]$ ls
TEST1.txt
```
マシンのシャットダウン、Snapshotの保存
```
$ vagrant halt

$ vagrant snapshot save savepoint1
==> default: Snapshotting the machine as 'savepoint1'...
==> default: Snapshot saved! You can restore the snapshot at any time by
==> default: using `vagrant snapshot restore`. You can delete it using
==> default: `vagrant snapshot delete`.

$ vagrant snapshot list
savepoint1
```


# Snapshotの復元
変更を加え、別のsnapshotを保存
```
$ vagrant up
$ vagrant ssh
[vagrant@localhost ~]$ touch ~/TEST2.txt
[vagrant@localhost ~]$ ls
TEST1.txt  TEST2.txt
[vagrant@localhost ~]$ exit
logout
$ vagrant halt
$ vagrant shanpshot save savepoint2
```
savepoint1の復元
```
$ vagrant snapshot restore savepoint1
==> default: Restoring the snapshot 'savepoint1'...

$ vagrant up
$ vagrant ssh
[vagrant@localhost ~]$ ls
TEST1.txt
```


# Snapshotの削除
```
$ vagrant snapshot list
savepoint1
savepoint2

$ vagrant snapshot delete savepoint1
==> default: Deleting the snapshot 'savepoint1'...
==> default: Snapshot deleted!

$ vagrant snapshot list
savepoint2
```


# Snapshotを1つしか作成しない場合
``vagrant snapshot push``でSnapshotを作成し、``vagrant snapshot pop``で復元することができる  
※Snapshotに名前を付けることができないので、基本的にはあんまり使用しないかも。
```
$ vagrant snapshot push
==> default: Snapshotting the machine as 'push_1665968827_6611'...
==> default: Snapshot saved! You can restore the snapshot at any time by
==> default: using `vagrant snapshot restore`. You can delete it using
==> default: `vagrant snapshot delete`.

$ vagrant snapshot pop
==> default: Restoring the snapshot 'push_1665968827_6611'...
==> default: Deleting the snapshot 'push_1665968827_6611'...
```


# 参考
[VagrantのSnapshot機能で仮想マシンの状態を保存/復元しよう](https://weblabo.oscasierra.net/vagrant-snapshot/)
AWS Lambdaのnodejsランタイムでsharpを使うと"Something went wrong installing the \"sharp\" module"でエラーになる場合の解決法

# 結論

```bash
$ npm install
$ rm -r node_modules/sharp/
$ npm rebuild --arch=x64 --platform=linux sharp
```

# sharp

画像リサイズやフォーマット変換してくれる。
しかし、そのまま`npm install`しても AWS Lambda でエラーになる。

https://sharp.pixelplumbing.com/

# エラー内容
## Lambdaのエラーメッセージ

```log
Something went wrong installing the "sharp" module

Cannot find module '../build/Release/sharp-linux-x64.node'
Require stack:
- /var/task/node_modules/sharp/lib/sharp.js
- /var/task/node_modules/sharp/lib/constructor.js
- /var/task/node_modules/sharp/lib/index.js
- /var/task/handler.js
- /var/runtime/index.mjs

Possible solutions:
- Install with verbose logging and look for errors: "npm install --ignore-scripts=false --foreground-scripts --verbose sharp"
- Install for the current linux-x64 runtime: "npm install --platform=linux --arch=x64 sharp"
- Consult the installation documentation: https://sharp.pixelplumbing.com/install",
```

## やったこと

`npm install --platform=linux --arch=x64 sharp`しろって書いてる。
でも、そのまま実行しても`sharp-linux-x64.node`は作られなかった。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134221/83f1fb25-f5df-80a2-4a3b-37c440d9bce7.png)

`npm rebuild sharp --arch=x64 --platform=linux` を実行すると、`sharp-drawin-x64.node`が残ってしまい、無駄な容量になった。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134221/a66f2b93-4f11-15ae-63a0-ca67ef13fc1b.png)


なので、いったん node_modeles の sharp を削除しました。

```bash
$ npm install
$ rm -r node_modules/sharp/
$ npm rebuild --arch=x64 --platform=linux sharp
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134221/acfde4db-af5e-8f65-40a0-364a22998faf.png)


# Serverless Frameworkの場合

設定ファイルの`packagerOptions`の`scripts`に書いたらできると思います。

```json
  custom: {
    webpack: {
      webpackConfig: './webpack.config.js',
      includeModules: true,
      packagerOptions: {
        scripts: [
          'rm -r node_modules/sharp/',
          'npm rebuild --arch=x64 --platform=linux sharp'
        ],
      },
    },
  },
```
KeyCloakについて

業務でAPIサーバーをJava, SpringBootで作成した時、認証・認可サーバーとしてKeyCloakを使用しました。その際、学んだことを備忘録としてここに残しておきます。

【KeyCloakとは何なのか？】
1.KeyCloakとは、シングルサインオンやAPIアクセスの認証・認可制御を実現する、Javaベースのアイデンティティ・アクセス管理ソフトウェアです。


【KeyCloakをなぜ使うのか？】
1.ユーザーのデータを利用したいクライアントアプリケーションと、ユーザーデータを管理するリソースサーバーがあったとします。イメージとしては、フロントエンドがクライアントアプリケーション、バックエンドがリソースサーバーに該当します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2919458/c84e1f16-c447-adb9-ea23-61bd54a95981.png)


2.クライアントアプリケーションは、エンドポイントにアクセスしてAPIと必要なデータをやり取りします。しかし、このままではクライアントが悪意のある第三者だとしても、リソースサーバーはユーザーデータを渡してしまいます。結果として、ユーザーデータの流出やデータベースの改ざんなどの、様々な問題が発生する恐れがあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2919458/f36f4e44-0840-0d1f-ef44-5537cc12422e.png)


3.その問題を解決するため、OpenIDプロバイダーが発行するIDトークンを導入します。
KeyCloakはこのOpenIDプロバイダーに該当します。また、IDトークンとはユーザー認証情報を含む改ざん検知用の署名付きトークンのことを指します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2919458/a8312af9-d68a-f049-e293-11b80edd4f0b.png)


4.クライアントアプリケーションがリソースサーバー内のユーザーデータを取得するまでの実際の流れを見ていきます。まず最初に、クライアントアプリケーションがOpenIDプロバイダーに対してIDトークンを要求します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2919458/266c04d3-4a7b-c6d7-6cc5-ea51c20302da.png)


5.すると、OpenIDプロバイダーはクライアントアプリケーションにIDトークンを与えるかどうかユーザーに確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2919458/7d2efe61-8364-955a-54f5-ce14dde13b95.png)

6.IDトークンを発行するため、ユーザーは本人確認情報の提示をすることでユーザー認証を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2919458/774770b8-8b3c-ef20-80a3-e91c699cd9cf.png)



7.ユーザー認証が適切に行われた場合、OpenIDプロバイダーはクライアントアプリケーションに IDトークンを発行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2919458/cc25b5bc-5ddd-9e05-8400-9bb8d84f844d.png)



8.クライアントアプリケーションはリソースサーバーにユーザーデータを要求する際、OpenIDプロバイダーが発行したIDトークンを提示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2919458/a1cbd410-87fe-d87a-b0b1-5c384a870331.png)


8)リソースサーバーは、リクエストに含まれているIDトークンを取り出し、IDトークンが改ざんされていないか検証します。ここで、クライアントアプリケーションからのリクエストはOpenIDプロバイダーが認証したユーザーによるものか、認証されたユーザーがユーザーデータにアクセスするのに必要な認可情報を持っているか確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2919458/8f655bf8-28ef-0abb-b4a8-d6fcfc5109ce.png)


9)ユーザーデータにアクセスするための認証・認可情報を所持していることを確認できた場合、ユーザーデータをクライアントアプリケーションに渡します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2919458/a53883fe-36c0-9620-2851-e952dbd84725.png)


10)なぜKeyCloakが必要かという疑問でしたが、「OpenIDプロバイダーとしてKeyCloakを導入することでAPIアクセスの認証・認可制御を実現できるから」ということになります。リソースサーバーをAPIとして公開するためには、誰がアクセスしてきたのかを確認するための「認証」と、APIへのアクセスを誰に許可するのかという「認可」の仕組みが必要不可欠となります。
Rustでテキスト音楽「サクラ」を書き直している件

Rustで[テキスト音楽「サクラ」](https://sakuramml.com)をコツコツ書いていたのですが、3日目にブラウザで音が鳴らせるようになったので記事にまとめてみました。

# テキスト音楽「サクラ」とは何か

「ドレミ」や「cde」のテキストをMIDIファイルに変換するコンパイラです。 手軽に音楽を作成できるツールです。

- [テキスト音楽「サクラ」のWebサイト](https://sakuramml.com)

## 完成したもの

今回、ブラウザで簡単に「ドレミ」や「cde」の楽譜を書いて音が再生できるようになりました。まずは、以下で試すことができるので見てみてください。PC/スマートフォン、タブレットのブラウザで動かすことができます。

- [ブラウザで手軽に音楽 - テキスト音楽「ピコサクラ」](https://sakuramml.com/go.php?15)

https://sakuramml.com/go.php?15


## なぜサクラをRustで書き直したのか

あるディープラーニングの仕事の待ち時間（データ学習の間)に何かできないかなぁと思って、待ち時間にコツコツRustでサクラを作り直していました。とは言え、3日目にして、公開できるレベルまで作ることができました！

> サクラ開発の歴史 - テキスト音楽「サクラ」は、Delphi(v1)→Delphi(v2)→C(未完成)→Go(未完成)→Rust(今回)と何度も途中まで作り直しています。途中まで作ると、飽きてしまうので、最後まで完成したのは、Delphiで作ったv2で、現在もv2がサイト上で公開されています。

現在のところ、今回のRust版は、未完成のGo言語版と同じくらいまで作っていますが、ブラウザで動かして、みんなに使ってもらいやすい分、もう少し実装が進みそうです。やはり、公開して使ってもらえると、モチベーションが上がりますね！


## ブラウザでサクラを動かす仕組みは？

サクラは、テキストからMIDIファイルを作成するコンパイラです。そのため、今回作ったのは、テキストを読み込んでMIDIファイルを生成する部分です。MIDIファイルを生成したら、PicoAudioというブラウザ上でMIDIを再生するライブラリにMIDIファイルを投げて再生します。

```
ソースコード →　(サクラでコンパイル) → MIDIファイル
MIDIファイル → PicoAudio.jsで演奏
```

サクラはRustで書いて、WebAsseblyに変換し、ブラウザからWebAssemblyを読み出してコンパイル処理をします。

サクラのRust版はオープンソースで開発し、以下で公開しています。

https://github.com/kujirahand/sakuramml-rust

簡単に、処理の流れを紹介します。

### [1] ストトン表記→MMLへの変換

最初に、「ドレミ」の表記（これをストトン表記と言います）を、MMLに変換します。以下のソースです。バージョン、0.1.0だと、145行ほどで、単純に1文字ずつ最長一致で単語を確認して、文字列置換しているだけです。

https://github.com/kujirahand/sakuramml-rust/blob/main/src/sutoton.rs

### [2] MML→MIDIへの変換

MMLの表記は非常に複雑で簡単にパースできません。特に音符の後の音長表現は、比較的複雑な処理が必要です。そこで、以前、Go言語で作ったときには、コンパイラコンパイラを使ったのですが、今回は、何も考えず手書きでパーサーを書きました。

また、MMLからMIDIへの変換はそれほど重たい処理ではないので、あまり効率を考えていません。逆にコードが読みやすいかも。

https://github.com/kujirahand/sakuramml-rust/blob/main/src/lexer.rs

サクラでは、英小文字(cdeなど)は1文字コマンド、英大文字(Track/Channelなど)は複数文字のコマンドと決まっています。

それで、英大文字は、本来Mapなどに入れておくと高速に判定できるのですが、コマンドは、それほど多くないと思ったので、連続するifで分岐しており、全くお手本にならないので、今後改善したいところです。

なお、MIDIに変換する前に、MMLのコードをトークンに分割します。なお、楽譜情報には繰り返しなどの仕組みがあるので、トークンに変換した後で繰り返し処理などを解決します。

それで、以下のような仕組みになっています。

- [1] ソースコード(MML)
- [2] トークンに分割 --- /src/lexer.rs
- [3] 分割したトークンを元に実行してイベントを書き込み --- /src/runner.rs
- [4] イベントをソートしてMIDIに変換 --- /src/midi.rs

# コマンドラインで実行する方法

もちろん、Rustなので、ブラウザだけでなく、コマンドライン上で実行できます。以下にCUIで作曲する方法を紹介しています。

https://qiita.com/kujirahand/items/26013f733e6e8bfc43cb

リポジトリから最新版をダウンロードしてサクラのコマンドをビルドする方法。

```
# リポジトリを取得
$ git clone https://github.com/kujirahand/sakuramml-rust.git
$ cd sakuramml-rust

# ビルド
$ cargo build
# MMLファイルをMIDIに変換
$ cargo run music.mml
```


# まとめ

以上、簡単に、テキスト音楽サクラ「サクラ」のRust版の仕組みを紹介しました。MMLコンパイラの開発は、MIDIの知識がちょっと必要ですが、それほど難しくなくて、Rustの練習にもぴったりの内容です。また、Rustを使うとブラウザでプログラムを動かすWebAssemblyを作るのも簡単でした。

サクラのブラウザ版は今後も気まぐれに開発していこうと思っています。
良かったら使ってみてください。

## メモ - Rustの本書きました

そうそう、先日私が書いたRustの本、良かったら見てみてください！！この本の中では、簡単なMML→WAVファイル生成の作り方も解説しています。

https://www.amazon.co.jp/dp/4802613512/ref=as_sl_pc_tf_til?tag=text2musiccom-22&linkCode=w00&linkId=97170724c87fa892e4a05732776c9586&creativeASIN=4802613512


## 参考

- [Qiita > CUIで音楽製作環境の構築(macOS版)](https://qiita.com/kujirahand/items/26013f733e6e8bfc43cb) --- MIDI関連ツールのセットアップについて