OmniAICreator/Qiita-1.07M huggingface dataset:
VB.NETでWindowsアプリを自動化する

## はじめに
VB.NETでのサンプルソースが見つからなかったので、備忘録的に書いときます。

## 前提作業
・Windowsの開発者モードをオンにして下さい。

・Windows Application Driverをインストールして下さい。
　https://github.com/Microsoft/WinAppDriver/releases

・Nugetで以下のパッケージをインストールしてください。
　Install-Package Selenium.WebDriver -Version 3.141.0
　Install-Package Selenium.Support -Version 3.141.0
　<font color="Red">※最新バージョンだとWebサイトとWindowsFormを1本のexe内で操作できない問題がある様です。</font>

・xPathはWinAppDriverUiRecordeやinspectなどで採取して下さい。
　https://github.com/microsoft/WinAppDriver/releases/tag/UIR-v1.1

## 留意点
・DesiredCapabilitiesのところで”旧式である”とのワーニングが出ますが、とりあえず動作します。
・.NET FrameWork 4.8で動作確認しています。

## ハマったところ
元のxPathからバックスラッシュ(￥)を削除しなければならなかったところ。
ダブルコーテーションは"を2個書いてエスケープするのはいつもどおり。
つまり\\"を””に変換する必要があります。

エンターキー等の特殊キーを使う時は、OpenQA.Selenium.Keys.hoge とする。
単にKeys.enterなどとすると、数字がセットされてしまいます。
driver.FindElementByXPath(xpath_str).SendKeys(OpenQA.Selenium.Keys.Enter)


```vb:VB.NET
'Nugetで右をインストールする。Install-Package Selenium.WebDriver -Version 3.141.0
Imports OpenQA.Selenium
Imports OpenQA.Selenium.Chrome
Imports OpenQA.Selenium.Remote

'Nugetで右をインストールする。Install-Package Selenium.Support -Version 3.141.0 ブラウザのセレクトボックス内を選択するために必要なライブラリ
Imports OpenQA.Selenium.Support.UI

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click        
        'Windows Application Driver実行
        Dim serverPath As String = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "Windows Application Driver", "WinAppDriver.exe")

        Dim psi As New System.Diagnostics.ProcessStartInfo
        psi.FileName = serverPath  '起動するアプリケーションを指定
        psi.Arguments() = "4999"    '引数としてポート番号を指定
        System.Diagnostics.Process.Start(psi)

        'App操作
        Dim appCapabilities = New DesiredCapabilities()
        appCapabilities.SetCapability("app", "Root")

        Dim driver As RemoteWebDriver
        driver = New RemoteWebDriver(New Uri("http://127.0.0.1:4999"), appCapabilities)

        '操作対象のアプリケーションを起動
        System.Diagnostics.Process.Start("hoge.exe")

        Dim xpath_str As String
		            '/Pane[@ClassName=\"#98765\"][@Name=\"デスクトップ 1\"]/Window[@ClassName=\"Window\"][@Name=\"ログイン\"]/Edit[@AutomationId=\"PasswordBox\"
						　　　　↓元のxPathが上の状態として、\は削除する。ダブルコーテーションは"を2個書いてエスケープする。
        xpath_str = "/Pane[@ClassName=""#98765""][@Name=""デスクトップ 1""]/Window[@ClassName=""Window""][@Name=""ログイン""]/Edit[@AutomationId=""PasswordBox""]"

        driver.FindElementByXPath(xpath_str).SendKeys("12345")
End sub
```

## 旧式から新式？へ
### Driver起動方法をoptionで行う方法を追記しました。

<font color="Red">※Appium.WebDriverを使わずに、上記のSelenium.WebDriver -Version 3.141.0を使う方が安定して利用できるようです。</font>


```vb:VB.NET
'install-package Appium.WebDriver
Imports OpenQA.Selenium.Appium
Imports OpenQA.Selenium.Appium.Windows

        Dim options = New AppiumOptions()
        options.AddAdditionalCapability("app", "Root")

        Dim remoteAddress = New Uri("http://127.0.0.1:4999")
        Dim Driver = New WindowsDriver(Of WindowsElement)(remoteAddress, options)


```
Windowsでjqコマンドのpathが通らないときに確認すること

JSONを整形する必要があって、jqをインストールしました。
jqコマンドを使用できるようにするには、pathを通す必要があります。

pathを通すタイミングで、少しつまったので、同じようにつまっている人の参考になれば幸いです。

## アプリケーション名の拡張子(.exe)は必要ない
いきなり結論です。

``jq.exe``→``jq``に変更したところ、path通りました。
![Screenshot_13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642155/5cb76f36-cf7b-99f9-29cc-d67388094741.png)
これに気付かず、数十分消費しました。

jqコマンド導入のサイトを複数見ましたが、そのすべてで「``jq-win64.exe``を``jq.exe``と変更...」と記載されており、そこをまったく疑っていなかった。。

プロパティを確認すると、``アプリケーション(.exe)``となっていて、すでに拡張子が含まれていることがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642155/13c64b75-eaa3-dc4e-74c3-c3286d065881.png)

こういう問題って、jqに限らないと思うので、疑うクセを忘れないようにしないとですね。
flutter upgrade後にflutter run --no-sound-null-safetyで大量のpod周りのエラーが発生

# 結論
さっきまで触ってたプロジェクトではなく、全く新しいプロジェクトをシュミレーターで起動し、再び、さっきまで触ってたプロジェクトをシュミレーターで起動する。
EC2にnode.jsをインストール

## 概要
デフォルト、EC2にnode.jsをインストールされてないですが、
今回ec2にノードバージョンマネージャー (nvm) でnode.jsのインストール方法を説明させて戴きます。

# 手順

## ec2にアクセスして、ユーザーを切り替え

```
sudo su --login ec2-user
```

## ノードバージョンマネージャー (nvm)をいンストール

```
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
```

## nvm を有効にする

```
. ~/.nvm/nvm.sh
```

## nvm を使用して Node.js の最新バージョンをインストール

```
nvm install node
```

## nodeバージョン確認

```
$ node -v
v17.7.1
```

EC2に最新のnode.jsをインストールする事が確認できました。
【Ruby】指定日付内のランダムな日時を取得する

## 結論

rand関数で取得できます。
クラスに関係なく使えて便利。

```ruby
# DateTime（時間は0時0分で固定の様子）
> datetime_from = DateTime.parse('2022-01-01 00:00:00')
> datetime_to   = DateTime.parse('2022-12-31 00:00:00')
> rand(datetime_from..datetime_to)
=> Sat, 30 Apr 2022 00:00:00 +0000

# Time（ミリ秒まで細かくランダムにしてくれる）
> time_from = Time.parse('2022-01-01 00:00:00')
> time_to   = Time.parse('2022-12-31 00:00:00')
> rand(time_from..time_to)
=> 2022-12-05 14:34:05 113996677/134217728 +0000

# ActiveSupport::TimeZone（秒まで）
> timezone_from = Time.zone.parse('2022-01-01 00:00:00')
> timezone_to   = Time.zone.parse('2022-12-31 00:00:00')
> rand(timezone_from..timezone_to)
=> Sat, 04 Jun 2022 13:29:32 JST +09:00
```

### ちなみに

fromとtoのClassが異なっても一部成功しますが、バグの原因になりそうなのでやめておいたほうがいいかもしれません。

```ruby
# DateTime..Time
> rand(datetime_from..time_to)
=> Sun, 23 Feb 9631 10:32:33 +0000
> rand(datetime_from..time_to).class
=> DateTime

# DateTime..ActiveSupport::TimeZone
> rand(datetime_from..timezone_to)
=> Sat, 07 Nov 76296 09:35:29 +0000
> rand(datetime_from..timezone_to).class
=> DateTime

# Time..ActiveSupport::TimeZone
> rand(time_from..timezone_to)
=> 2022-03-28 15:44:21 685943787/1073741824 +0000
> rand(time_from..timezone_to).class
=> Time

# ActiveSupport::TimeZone..Time
> rand(timezone_from..time_to)
=> Thu, 13 Jan 2022 10:04:04 JST +09:00
> rand(timezone_from..time_to).class
=> ActiveSupport::TimeWithZone

# Time..DateTime
> rand(time_from..datetime_to)
TypeError: expected numeric

# ActiveSupport::TimeZone..DateTime
> rand(timezone_from..datetime_to)
TypeError: expected numeric
```
TwitterのツイートIDからタイムスタンプを抽出してみた

# ツイートID

特定のツイートをブラウザで表示した際、以下のようなURL[^1]になるのですが、この数字の部分(以下の例では`1488865376611950387`)を ツイートID と呼ぶことにします。

```
https://twitter.com/{ユーザー名}/status/1488865376611950387
```

[^1]: 例示したURLに対応するツイートは存在しません。


# ツイートIDからタイムスタンプを取得するプログラム

細かい話は後にして、ツイートIDからタイムスタンプを取得するプログラム(C#)を掲載します。

* 定数
```csharp
// Twitterエポック(2010-11-04 01:42:54.657)
long twitterEpoch = 1288834974657L;

// UNIXエポック(1970/01/01 00:00:00.000)
long unixEpoch = 62135596800000L;

// タイムスタンプのビット数
int timestampBits = 41;
// タイムスタンプのシフト数
int timestampShift = 22;
// タイムスタンプのマスク
long timestampMask = -1L ^ (-1L << timestampBits);
```

* ツイートIDからタイムスタンプを算出してDateTime型で返すメソッド
```csharp
DateTime GetDateTime(long id)
{
    // 0001/01/01 00:00:00.000 からの経過ミリ秒
    var timestamp =
        ((id >> timestampShift) & timestampMask)
            + twitterEpoch
            + unixEpoch;
    return new DateTime(
        timestamp * TimeSpan.TicksPerMillisecond,
        DateTimeKind.Utc
    );
}
```

## 使い方

ツイートIDを GetDateTimeメソッド に引数で渡せば、DateTime型でタイムスタンプが返されます。
このメソッドが返すタイムスタンプはUTCになっていますので、必要に応じてローカル時刻に変換して使用します。

```csharp
var date = GetDateTime(1488865376611950387L);
Console.WriteLine($"{date.ToLocalTime():yyyy-MM-dd HH:mm:ss.fff}");
// -> 2022-02-02 22:22:22.222
```


# ツイートIDの仕様について

Twitterでは **snowflake** という仕組みを利用して、IDの採番を行っているようです。
snowflake はGitHubでソース(scala)が公開されていますので、これを元にツイートIDの仕様を確認しました。[^2] [^3]

https://github.com/twitter-archive/snowflake

[^2]: 現時点ではプロジェクトは公開されていませんが、tagから当時のソースが取得可能です。
[^3]: 厳密には今でもこのプログラムでTwitterがID採番を行っているかは不明なのですが、この記事の執筆時に動作確認をした時点では、タイムスタンプについては確からしい結果になることを確認できました。


## ツイートIDの構成

READMEファイル や IdWorkerクラス からツイートIDの構成を整理すると、以下のようになります。

* 64bit整数(long値) [^4]
* 上位のビットから、以下の通りの構成
  * 0固定 - 1ビット
  * タイムスタンプ(ミリ秒単位) - 41ビット
  * マシンID [^5] - 10ビット
  * シーケンス番号 - 12ビット
* タイムスタンプは任意の基準時刻(カスタムエポック)からの経過ミリ秒
  * Twitterでは 2010-11-04 01:42:54.657 を基準としている。
  * これは、UNIXエポック(1970/01/01)から 1288834974657ミリ秒 [^6] 経過した時刻。

[^4]: 先頭ビットが0固定なので、符号の有無(signed/unsigned)は考慮不要。
[^5]: IdWorkerクラスでは、ワーカーID と データセンターID にそれぞれ5ビットずつ割り当てている。
[^6]: IdWorkerクラス の twepoch で定義されている。


## ツイートIDからタイムスタンプを取得する

今回はタイムスタンプにのみ興味があるので、以下のようにしてタイムスタンプを取得しました(先述のGetDateTimeメソッド)。

* ツイートIDの下位22ビットを切り捨てる(右シフト)
* 41ビット分を抽出(マスク処理)
* これが基準時刻からの経過ミリ秒になっているので、C#のDateTimeの仕様に合わせて0001/01/01 00:00:00.000 からの経過ミリ秒に変換する
  * Twitterエポック(1970/01/01からの経過ミリ秒) を加算
  * UNIXエポック(0001/01/01から1970/01/01までのミリ秒) を加算
* ミリ秒からTickに変換して、DateTimeインスタンスを作成する


## 注意点

Twitterは2006年の公開以来、sonwflake を採用する以前はシーケンスと思われる採番方法を取っていました。
snowflake は2010年11月ごろから利用されているようなので、それより古いツイートのツイートIDは今回の方法でタイムスタンプに変換することはできません。

具体的な切り替え時刻は分かりませんが、

* 2010/11/04 20時ごろ → 古い方式
* 2010/11/05 9時ごろ → snowflakeを利用

のようです(日本時間)。


## Twitter風のIDを採番するプログラムをC#で書いてみました

ツイートIDの仕組みを調べる過程で snowflake のID採番処理を C# に移植していましたので、そのソース全文を公開しました。
参考になれば幸いです。

https://qiita.com/haruka_kotani/items/34204a0e75e118ddaa06


# どうしてこんなこと調べたの？

ここからは完全に余談です。

Twitterでクイズ大会をした時に、ほぼ同時に回答が投稿されてどっちが先かが分からなくなったということがありました。

Twitterのウェブ画面では 分 までしか表示されないので困ったなぁ、という時に、ツイートIDから順序が分からないものかと調べたのがきっかけです。
ツイートIDの大小だけで、どちらが先かは分かるのですが、せっかくなので「何秒差で投稿されたのか」が気になって、ここまでやってみたという話です。
ちなみに、0.3秒差くらいでした。
Pythonでデカルト積（直積）～全通り・総当たりを書き出す～

## はじめに

**Pythonでデカルト積（直積）を作成する**方法について解説します。

※プログラミング関係の内容を他にも投稿していますので、よろしければ[こちら](https://qiita.com/oki_kosuke/items/34b1071224953776c211#%E6%8A%95%E7%A8%BF%E4%B8%80%E8%A6%A7)の一覧から他の投稿も見て頂けますと幸いです。

まずデカルト積に関しては[こちら](https://ja.wikipedia.org/wiki/%E7%9B%B4%E7%A9%8D%E9%9B%86%E5%90%88#:~:text=%E6%95%B0%E5%AD%A6%E3%81%AB%E3%81%8A%E3%81%84%E3%81%A6%E3%80%81%E9%9B%86%E5%90%88%E3%81%AE%E3%83%87%E3%82%AB%E3%83%AB%E3%83%88,%E5%85%83%E3%81%A8%E3%81%97%E3%81%A6%E6%8C%81%E3%81%A4%E6%96%B0%E3%81%9F%E3%81%AA)を参照ください。例えば、以下のように実験をする際にいくつかパラメータがあるとします。

![zikken.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057114/69c74e37-f69c-e821-351a-c449b624f988.png)

この場合に次のように全ての実験条件を洗い出す際などに使うイメージです。

![zyoken.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057114/bdd43e96-714a-fe74-67a3-fb7c60320cd8.png)

## 環境
- windows10
- conda 4.10.3
- python 3.7.10

## 作成したプログラム
具体的に以下の状況を考えます。この場合は全通りは3×5×3×4×3の540通りです。

![zikken2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057114/fc67cbf8-5cff-ee06-2783-876d04374be9.png)

```python
# ライブラリーのインポート
import itertools
import numpy as np
import pandas as pd

# 各実験条件の定義
yakuhin = ["A", "B", "C"]
vol = np.arange(10, 60 ,10)
temp = np.arange(80, 140, 20)
speed = np.arange(100, 500 ,100)
time = np.arange(1, 4 ,1)

# デカルト積の定義
all_list = list(itertools.product(yakuhin, vol, temp, speed, time))

# DataFrameに格納
df = pd.DataFrame(all_list)
df.columns = ["薬品", "薬品の量", "反応温度", "撹拌速度", "撹拌時間"]
df.head()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057114/65dcc422-de1e-b514-fcfe-118f8451b123.png)

上手く全実験条件がデータフレームに格納できていそうです。念のためデータフレームの大きさを確認しておきます。

```python
# DataFrameの大きさの確認
print("作成した条件の大きさ："+str(df.shape))
```

```:出力
作成した条件の大きさ：(540, 5)
```

確かに540個分の条件が生成されていることが確認できました。最後にcsv形式で全条件を保存しておきます。
```python
# csvファイルに書き出し
df.to_csv("all_list.csv", encoding ="shift_jis")
```

## まとめ
Pythonでデカルト積（直積）を作成する方法について解説致しました。

### 参考
- [Python Snippets](Python Snippets)
Figmaで表組みを作るときに少し時短できる方法

## この記事の概要

UIデザインツールで表組みを再現すると地味に大変ですよね。
区切り線や枠線などを細かめに用意せねばならず、並び変えや要素変更も思ったより時間がかかるというか……。

というわけで、若干ですが表組みを作るのが楽になるやり方を紹介します。

:::note warn
Inspectで見ると訳のわからないデータにはなっているので、実装者との連携は必須な作り方です。
独断でやると「これ、どういうこと？」となってしまいかねませんのでご了承ください。
:::

## 作り方

1. HTMLでいう`tr`に相当する要素を作る
1. それらをAuto layoutで並べる
1. `Spacing between items`や`Padding around items`にボーダーとして適用したい数値を入れる
   1. 例：区切り線1px、外枠2pxだったら
   1. ![](https://raw.githubusercontent.com/xrxoxcxox/qiita-sync/main/images/figma-easy-table-settings.png)
1. 完成
   1. ![](https://raw.githubusercontent.com/xrxoxcxox/qiita-sync/main/images/figma-easy-table.png)

## メリット

通常の作り方だと、例えば`tr`に相当する要素と区切り線を両方作るとオブジェクト数が多くなります。
また要素を並び変えしたいときにtrと区切り線をどちらも選択しないといけなくて、本当にわずかですが手間が増えます。

今回の作り方であれば上記両方が解消されます。

## 実際のデータ

こちらからどうぞ！

https://www.figma.com/file/W0HG4oe02u0mg7fQ59r8ZY

---

最後まで読んでくださってありがとうございます！
Twitterでも情報を発信しているので、良かったらフォローお願いします！

https://twitter.com/xrxoxcxox
kilo表示やmillion表示をしたい

# 初めに
今回やりたいことは、総数や距離などで頻出するk表示やmillion表示をする時に共通化しておける拡張関数を作ることです。
仕様としては下記のとおりです
 * 1000や1000000を超えていたらK、M表示にして返す
 * 小数点第二位切り捨て、小数点第一位が0だった場合も切り捨て
 * 100 -> 100
 * 1000 -> 1k
 * 1099 -> 1k
 * 1100 -> 1.1k
 * 1110 -> 1.1k
 * 1199 -> 1.1k
 * 1200 -> 1.2k
 * 10000 -> 10k
 * 100000 -> 100k
 * 999000 -> 999k
 * 1000000 -> 1M

### コード
では、実際にコードを書いていきましょう
コード量自体はとても少なく、わかりやすいものとなってます。

```kotlin:
fun Long.toCount(): String {
    check(this >= 0)
    return when {
        this < 1_000 -> {
            "$this"
        }
        this < 1_000_000 -> {
            val kiloCalc = this / 1_000.0
            val decimalKiloCount = BigDecimal.valueOf(kiloCalc)
            val kiloCount = decimalKiloCount.setScale(1, RoundingMode.DOWN)
            "${kiloCount.stripTrailingZeros().toPlainString()}k"
        }
        else -> {
            val millionCalc = this / 1_000_000.0
            val decimalMillionCount = BigDecimal.valueOf(millionCalc)
            val millionCount = decimalMillionCount.setScale(1, RoundingMode.DOWN)
            "${millionCount.stripTrailingZeros().toPlainString()}M"
        }
    }
}
```
`BigDEcimal`を使っての変換関数ですね。
一度でも、数値型の変換系を実装したことある方はよくお世話になっていると思います。
アンダースコアはあまり意味はないです。
ただ、見やすいので記述しておきました。
受け取った値が自然数かどうかをチェックして、数値の大きさにより分岐先で変換をしてあげる様にしました。
受け取った数値を対応した値で割ることで小数を発生させ、それを`BigDecimal`に変換し自分が扱いたい様に加工しました

### 最後に
今回の記事は、自分の備忘録用と言う役割が大きいので皆さんの役に立てるかは少々不安ではありますが、似た様な処理を書きたい方の少しでも手助けになれたら幸いです
Bootstrap【個人用ドキュメント】

# offsetクラス
md以上の時、4列分右に動かす。
```
offset-md-4
```

https://recursionist.io/dashboard/course/16/lesson/330

# 表示/非表示
sm以上の時に表示する。それ以下は非表示。
```
.d-none .d-sm-block
```

# overflow
```
.overflow-hiddens
```
https://getbootstrap.com/docs/4.4/utilities/overflow/

https://recursionist.io/dashboard/course/16/lesson/333

https://developer.mozilla.org/ja/docs/Web/CSS/overflow


# Forms

https://getbootstrap.com/docs/4.4/components/forms/#form-controls

https://recursionist.io/dashboard/course/17/lesson/344

# インプット/チェックボックスの書き方

```
<form class="form">
    <div class="form-group">
        <!-- input要素のrequired属性は、その入力項目が必須属性であることをブラウザに知らせることができます。HTML5では、required属性を設定するだけでJavaScriptによる入力チェックがなくてもエラーメッセージを表示させることが可能です。 -->
        <input type="email" name="userEmail" class="form-control" placeholder="Email" required>
    </div>
    <div class="form-group">
        <input type="text" name="userFirstName" class="form-control" placeholder="First name" required>
    </div>
    <div class="form-group">
        <input type="text" name="userLastName" class="form-control" placeholder="Last name" required>
    </div>
    <div class="form-group">
        <input type="number" class="form-control" name="userFirstDeposit" aria-describedby="emailHelp" placeholder="Enter your first deposit" required>
    </div>
    <div class="form-group">
        <div class="form-check">
            <!-- チェックボックスをあらかじめチェックするにはchecked属性を使用します。 -->
            <input class="form-check-input" type="radio" name="userAccountType" id="userAccountType1" value="savings" checked required>
            <label class="form-check-label" for="userAccountType1">
                            Savings
            </label>
        </div>
        <div class="form-check">
           <input class="form-check-input" type="radio" name="userAccountType" id="userAccountType2" value="checkings" required>
           <label class="form-check-label" for="userAccountType2">
                            Checkings
           </label>
        </div>
    </div>
    <button type="submit" class="btn btn-primary col-12">Submit</button>
</form>
```

https://recursionist.io/dashboard/course/17/lesson/344
EC2にpython3をインストール

# 概要
EC2にデフォルトpyhtonバージョンは2.7.18ですが、
今回ec2にpyenvというpythonバージョン管理ツールでpython3のインストール方法を説明させて戴きます。

# 手順

## ec2にアクセスして、ユーザーを切り替え

```
$ sudo su --login ec2-user
```

## デフォルトpyhtonバージョンを確認

```
$ python
Python 2.7.18 (default, Jun 10 2021, 00:11:02)
[GCC 7.3.1 20180712 (Red Hat 7.3.1-13)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
```

## yumパッケージ管理ツールを更新

```
sudo yum update -y
```

## よく使うパッケージをインストール

```
sudo yum -y install gcc gcc-c++ git libffi-devel openssl-devel readline-devel sqlite-devel zlib-devel
```

## pyenvをインストール

```
sudo git clone https://github.com/yyuu/pyenv.git /usr/bin/.pyenv
```

## pyenvの起動するため、ディレクトリを作成

```
sudo mkdir /usr/bin/.pyenv/shims
sudo mkdir /usr/bin/.pyenv/versions
```

## .pyenvの所有者をec2-userに変更

```
sudo chown -R ec2-user:ec2-user /usr/bin/.pyenv/
```
## pyenvの環境パス設定
```
echo 'export PYENV_ROOT="/usr/bin/.pyenv"' >> ~/.bash_profile
echo 'export PATH="${PYENV_ROOT}/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(pyenv init --path)"' >> ~/.bash_profile
```
## .bash_profile環境パスを更新
```
source ~/.bash_profile
```
## pyenvバージョンを確認
```
pyenv -v
pyenv 2.2.4-1-10-g0d949796

```
## 最新pythonをインストール
```
pyenv install 3.9.7
```

## pythonのバージョンを切り替え
```
pyenv global 3.9.7
```
## pythonのバージョンを確認

```
python -V
Python 3.9.7
```

EC2に最新のpythonをインストールする事ができました。
以上となります。
[UE4] Nav Link Proxyを使った段差があるレベルでジャンプできないキャラが混在する場合の設定について

# はじめに
Nav Link Proxyを使った段差があるレベルで、ジャンプできるキャラとジャンプできないキャラが混在する場合、普通にナビメッシュを使うと、ジャンプできないキャラが移動できないにもかかわらず進もうとして段差のところで引っかかってしまうことが起こります。
この場合、キャラ毎に適用するナビメッシュを使い分ける必要があります。
Nav Link Proxyを使った段差があるレベルで、キャラにジャンプをさせる方法については、以前の記事[Nav Link Componentを使用してゲーム内でナビメッシュをつなぐ](https://qiita.com/Satoshi_Takahama/items/c49086835c8ffa59c02c)で説明しています。

# 環境
Windows10
UnrealEngine 4.27.2 (エディタの言語設定は英語です)

# 作り方
・プロジェクトの設定でSupportedAgentsの設定を追加します。
ここでは、ジャンプできるキャラ用の設定名をCanJumpに、ジャンプできないキャラ用の設定名をNotCanJumpに設定しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/47051953-6b34-5752-1c01-66a9f8929d9b.png)

・NavArea_Defaultを親クラスとしてBPを作成します。
ここでは、ジャンプできるキャラ用にBP_NavArea_CanJumpを、ジャンプできないキャラ用にBP_NavArea_NotCanJumpを作成しています。
BP_NavArea_CanJumpはClass DefaultsのSupportedAgentsの設定を以下のようにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/1fddaaed-c1ee-89c9-b95e-9ac210168040.png)
BP_NavArea_NotCanJumpはClass DefaultsのSupportedAgentsの設定を以下のようにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/194d4e23-e95e-6267-3bed-4f92a85ba7b8.png)

・RecastFilter_UserDefaultAreaを親クラスとしてBPを作成します。
ここでは、ジャンプできないキャラ用にRecastFilter_NotCanJumpを作成しています。
Area Classの設定をBP_NavArea_NotCanJumpにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/56f5e610-48da-b71b-ec6c-27b8d077a552.png)

・ジャンプできないキャラの設定を変更します。
キャラについているCharacter MovementコンポーネントのNav MovementのMovement Capabilitiesの設定で、Can Jumpのチェックを外します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/82c9ed2f-d449-9655-8924-ed3711b549a3.png)

・レベルに設置するNav Link Proxyをの設定を変更します。
SupportedAgentsの設定をCanJumpに、Area Classの設定をBP_NavArea_CanJumpにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/8fd52458-fe1f-6a61-9404-303d44780c5c.png)

・移動先を決定する処理をキャラにあった設定に変更します。
例えば、ビヘイビアーツリーでEQSを使用している場合は、ジャンプできないキャラが到達可能かどうかを判定するために、Filter ClassをRecastFilter_NotCanJumpにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/46ae42c5-9a53-68b7-a832-50b57c259ac7.png)
例えば、GetRandomReachablePointinRadiusノードを使用している場合は、ジャンプできないキャラが到達可能かどうかを判定するために、Filter ClassをRecastFilter_NotCanJumpにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/56a2b833-ccb0-b7b9-e258-ed3dc129daff.png)

# 参考資料
・[【UE4】経路探索のコスト計算をカスタマイズする](https://paviliondv7.hatenablog.com/entry/2020/09/26/150736)
Project Settingsにsupported agentsの項目があることをこちらで知りました。

・[カスタム ナビゲーション システムとクエリ フィルタ](https://docs.unrealengine.com/4.27/ja/InteractiveExperiences/ArtificialIntelligence/NavigationSystem/CustomNavigationAreasAndQueryFiltersLanding/CustomNavigationAreasAndQueryFilters/)
カスタム エリアとクエリ フィルタを使用する方法についての公式ドキュメントです。
ServiceNow - セッションタイムアウトを設定する

ServiceNowの個人開発者インスタンスで少し席を離れると再ログインページが表示することがある。繰り返してログインするのに手間と時間が掛かる。
デフォルトでは90分、操作がないとログアウトする。セッションタイムアウトを最大1440分（1日）まで延期できる。

手順：
1. ナビゲータに「sys_properties.list」を入力してシステムプロパティページを開く
1. 名前「glide.ui.session_timeout」でフィルタする
1. 値に「1440」を入力

注1：タイムアウト値を大きくするとメモリ利用量が増えます
注2：タイムアウトを長くすると不正アクセスされるリスクが高くなります
これらの理由から本番環境のタイムアウト値を変更しない方がよいです

以上
Markdown記法をPukiWiki記法へ変換するスクリプトMD2PKWKをつくった

PHPなのですが、CLIのみで動作するPHPスクリプトとなります。
Webではないので注意を
PHPをインストールし、phpの環境変数を設定しないと動きません。

# ソース＆ダウンロード
https://github.com/PTOM76/MD2PKWK

# 使い方
コマンドプロンプト、ターミナル上で`php md2pkwk.php <ファイル名.md>`を実行します。
ファイル名は変換したいマークダウンファイルを指定してください。

# ライセンス
MITライセンスですのでご自由にどうぞ。
スマホでleaflet1.7.1のpopupが表示されない

# 対策
なし。

1.7.1の不具合のため、1.8のリリースを待つ。
暫定対応として1.6.0を使う。

# 参考
https://stackoverflow.com/questions/65385044/leaflet-1-7-1-popup-on-mobile-bug
https://github.com/Leaflet/Leaflet/issues/7331
[Go] RuneCountInStringで文字列の文字数を取得

`Go` にて文字列の文字数を取得したい時に

`len` の場合

`byte`で数えるまたは一つの `Unicode character`は`1~4`bytesが使われるため

英語以外の文字列はうまく文字数を取れないことがあります。

`unicode/utf-8` パッケージの `RuneCountInString` 関数を使えば

文字列の文字数を取得できるようになります。

```go
package main

import (
	"fmt"
	"unicode/utf8"
)

func main() {
	name := "テスト太郎"
	fmt.Println("len:", len(name))
	fmt.Println("RuneCountInString:", utf8.RuneCountInString(name))
}
```

```zsh:output
len: 15
RuneCountInString: 5
```
Ubuntuでちょっとした画像編集ならPintaだよね？

## Pintaについて
![Screenshot from 2022-03-16 17-54-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13048/231c0b03-cde9-9377-fb71-f49bb70e3ea8.png)

こんな感じの見た目の、Windowsでいうペイントみたいなツール（ペイントよりは高機能）で、スクショを撮ったり簡単な画像加工にとても重宝してます。

公式サイトは[こちら](https://www.pinta-project.com/)です。

## 何故か落ちまくる

今使ってるのは Ubuntu21.10 なんですが、以前のバージョンからディストリビューションのリポジトリから普通にインストールすると、一見普通に使える様に見えて範囲の矩形選択等で頻繁に落ちます。
公式サイトに載ってるソースコードからのビルドや PPA からのインストールを試しましたが上手く行かない（mono絡みのエラーだったと思います）。

## snapd で入れてみた

パッケージ管理の方法が増えちゃいますが、snapd版の Pinta が簡単に入れられてとても安定してたので、防備録としてインストールの仕方を残しとこうと思います。まあ、[ここ](https://snapcraft.io/install/pinta/ubuntu)に書いてるまんまなんですが、ちょっと見つけ辛かったので笑。
snapdはクロスプラットフォームなパッケージ管理ツールなんですが、Ubuntuならリポジトリからインストール出来ると思います。

```bash
$ sudo apt update
$ sudo apt install snapd
```
一旦ログアウトして入り直したら、
```bash
sudo snap install pinta
```
でOKです。
この方法はUbuntuじゃなくても使えると思うので、Linuxで軽い画像編集ツールを探してる方は使ってみてくださーい。

### 追記：OSのアップデート時などに起動しなくなった場合の再インストール方法

```bash
$ sudo snap remove --purge pinta
$ sudo snap install pinta
```
抽象と具象

クラスの抽象度
りんご、果物、植物、生物、物となる。

クラスにできる抽象度
やることによって変わる

例えば果物在庫管理ソフトがあったときに世の中のすべての果物をクラスにする必要はなく単に名前さえわかればいい名前と個数をかんりするだけだから。

だけど自動果物皮むき器なるものがありバナナモード、りんごモード、みかんモードがあるときにapple.peel()などのメソッドを呼ぶことで機会が動く仕組みのときには、こうするとフルーツクラスを継承することによって、fruit.peel()で抽象化できる。もしそうしなければmode=="みかん"などで毎回分岐して処理を書く必要がある。

つまりクラスにできる1つの目安として共通のグループであるものがifぶんで処理を分けてるときはクラスにすべきである？
docker-compose stopにはない、docker-compose downのメリットとは？


`docker-compose stop`と`down`の違い
-
コンテナを止めるだけ
`docker-compose start`を実行すると、再度立ち上げることができる

### docker-compose stop
> Stops running containers without removing them. They can be started again with docker-compose start.

https://docs.docker.com/compose/reference/stop/



### docker-compose down

コンテナ削除 + ネットワーク削除 + ボリューム削除(-vオプションをつけた場合)
再度コンテナを立ち上げたい時は、`docker-compose up`を実行し、コンテナ、ネットワーク、(ボリューム)を作成しなおす。

> Stops containers and removes containers, networks, volumes, and images created by up.

https://docs.docker.com/compose/reference/down/



docker-compose downのメリット
-
上記の情報を見た感じだと基本的には`docker-compose stop`でよさそうだなーという印象です。では`docker-compose down`のメリットは？？

まず１つ目は、普段`docker-compose down`を一切しないと仮定すると、`docker ps -a`で現在存在するコンテナを一覧表示した際に、現在進行系で利用していない過去のコンテナが残ってしまっているかと思います。
そうなっているとゴチャゴチャして見にくいので、使わないコンテナは削除するという意味でも`docker-compose down`は有用かと思います。

(追記: `docker-compose ps`でこの問題は解決できました :sweat_smile: )

２つ目、どちらかというとこちらの方が大きいです。
何かしらの事情でコンテナ内でゴニョゴニョしてる場合(コンテナに入ってapt-getなどでツールを追加したり等)、ローカルのコンテナと設計書(Dockerfile)の間で相違が生じるケースがあるんですね。

コンテナの最大のメリットの一つは、開発チームの環境を全く同じにする所にあるため、上記のようなケースだと本来のメリットが享受できなくなるんですね。
そういう意味でも普段から`docker-compose down`でコンテナを一旦削除からの再作成で常に設計書とイコールのクリーンな状態に保つ事は一定のメリットがあると思いました。


参考
-

https://docs.docker.com/compose/reference/stop/

https://docs.docker.com/compose/reference/down/
nuxt/contentの記事を格納するディレクトリ（記事の移動をした場合の注意）

## nuxt/contentのドキュメントでは
https://content.nuxtjs.org/ja/writing

公式のドキュメントでは下記のような配置になっています。

```
content/
  articles/
    article-1.md
    article-2.md
  home.md
```

説明文としては
>まず、プロジェクト内に `content/` ディレクトリを作成します。

とあります。

よって、articlesとは書いていないので、そこは自由に書いて良いのかなと思うのですが、articles以外のディレクトリでは記事の読み込みができませんでした。

`articlesに配置しないとアカンのかなぁ`
って思ってたらとんだ勘違いやったというお話。

## 記事の移動をした場合、サーバー再起動しないといけない!!!

dockerを使っていたので、以下を実行。

```
compose restart
```

これで`content/php`というディレクトリにコンテンツを配置しても読み込めました。

### 記事取得

```
    const articles = await $content('php', { deep: true })
      .fetch();
```

という形で取得できます。
ここではphpディレクトリの配下にさらにディレクトリを作成しているので、
サブディレクトリまで記事を取りに行くようにOptionsに`{deep:true}`を引数に渡しています。
nvmを使ってNode.jsをインストールする

## 環境
Ubuntu20.4

## はじめに
nvmはNode.jsのバージョン管理ツールです。Node.jsをインストールする前に、nvmのインストールを先に行います。

UbuntuにNode.jsをインストールするには、aptを使ってインストールすることになるが、バージョン管理を行いたい場合は、nvmを使ってインストールすることになります。Node.jsをお試し程度で使うのであれば、aptでインストールしてもいいのだが、長期的に使う予定があるのであれば、nvmを使ってインストールした方が、後々便利になるでしょう。

aptを使ってNode.jsをインストールするときのコマンドです。

```
apt-get update
apt-get install nodejs
```

Rubyにはrbenvというバージョン管理ツールが存在するが、どのような言語にも、似たようなツールは共通して存在しているものです。Rubyのrbenvに該当するのが、Node.jsのnvmということになります。

## nvmをインストールする

ググるとnvmのインストール手順はたくさんヒットされるが、公式サイトの手順に従って進めるのが一番いいでしょう。この記事も、公式サイトの手順に従って作業を進めました。
https://github.com/nvm-sh/nvm

nvmはUbuntuの公式リポジトリにあがっていないため、aptではインストールできないことになります。因みに、rbenvはUbuntuの公式リポジトリにあがっているため、aptでインストールできるようになっています。
（参考：rbenv https://github.com/rbenv/rbenv ）


aptが利用できないということは、curlまたは、wgetを使って、GitHubからインストールすることになります。どちらを使ってもいいのですが、この手順ではcurlを使ってインストールすることにします。

公式サイトを見ると、git cloneを使ってインストールする手順もあります。git cloneを使うと、.bashrcへの環境変数の追加を自動で行ってくれないため、viを使って、自分でコピペをする手順となっています。

それでは、curlを使って、次のコマンドを実行します。
```
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
```

curlのoオプションは、指定したファイルをダウンロードするオプションです。install.shは、ホームディレクトリ配下の.nvmディレクトリにダウンロードされてから実行されます。次のコマンドで、確かにダウンロードされていることを確認します。

```
ls -l ~/.nvm | grep ins*
```

install.shによって、.bashrcが書き換えられます。.bashrcを実行して、書き換えられた内容を反映させます。

```
source ~/.bashrc
```

viで.bashrcを表示します。

```
vi ~/.bashrc
```

最終行に次の２行が確かに追加されていることを確認します。

```
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
```

環境変数のNVM_DIRの値を表示して、反映されていることを確認します。

```
echo $NVM_DIR
```

nvmが正しくインストールされていることを確認します。インストールされてることを確認するコマンドに**which**があるが、このコマンドは、nvmの確認では使えないようようなので、**command**を使います。

```
command -v nvm
```

## 注意事項

パッケージ化されたnvmをインストールするのではなく、ソースファイルをダウンロードして自分でビルドしてインストールする場合は、build-essentialと、libssl-devが必要になります。C++のライブラリのようです。

## nvmを使ってNode.jsをインストールする

Node.jsのバージョンを指定してインストールするときのコマンドです。
```
nvm install v13.6.0
```

現時点でのNode.jsの最新のバージョンをインストールするときのコマンドです。
```
nvm install node
```

LTS（長期サポート）付きのバージョンで、かつ、最新のバージョンをインストールするときのコマンドです。このコマンドでインストールする方法が推奨されているようです。
```
nvm install --lts
```

## nvmの使い方

インストール可能なバージョンの一覧を表示するコマンドです。
```
nvm list-remote
```

次のコマンドを実行して、最終行に表示されるバージョン番号と、Node.jsの公式サイトから確認できる最新バージョンの番号は、同じ番号のはずです。（Node.js 公式サイト https://nodejs.org/ja/）

```
nvm list-remote | tail
```

インストール済のNode.jsの一覧を表示するコマンドです。一番上に表示されているバージョンが、現在有効になっているバージョンです。

```
nvm list
nvm ls
```

次のコマンドでも、現在有効になっているバージョンを表示することができます。

```
node -v
```

## 参考URL

https://www.digitalocean.com/community/tutorials/how-to-install-node-js-on-ubuntu-20-04-ja

## npmをインストールする

Node.jsをインストールしたので、npmもインストールします。npmとはNode.jsのパッケージ管理システムのことです。Rubyのgemに相当します。Node.jsをインストールすれば、npmも自動でインストールされるようなことはなく、Node.jsをインストールしても、npmは単体でインストールする必要があります。Node.jsをaptでインストールようが、nvmでインストールしようが同じです。

npmのインストールは、aptでインストールします。npmをインストールする前に、npmがインストールされていないことを確認します。

```
npm -v
which npm
```

npmをインストールします。

```
sudo apt-get update
sudo apt-get install npm
```

npmがインストールされたことを確認します。

```
npm -v
which npm
```
Laravel ミドルウェア

# 概要
ミドルウェアは、HTTPリクエストを**検査およびフィルタリング**する。

例えばユーザ認証を確認して、認証されていない場合であれば
アプリケーションのログイン画面にリダイレクトする。

認証されていればリクエストをアプリケーションへ進めることを許可する。

# 定義
ミドルウェアの作成はartisanコマンドを使用する

```
php artisan make:middleware Authenticate
```

すると、`Authenticate`クラスを含むファイルが`app/Http/Middleware`に配置される。

# 記述例

```php
class Authenticate
{
    // リクエスト処理
    public function handle($request, Closure $next)
    {
        // トークンが一致しなければリダイレクト
        if ($request->input('token') !== 'my-secret-token') {
            return redirect('login');
        }

        // アプリケーションに進む
        // (ミドルウェアをパスする)
        return $next($request);
    }
}
```

# ミドルウェアの登録
## グローバル
アプリケーション全てのHTTPリクエストに対するミドルウェアは
`app/Http/Kernel.php`内の`$middleware`配列内に記述する。

```php
class Kernel extends HttpKernel
{
    protected $middleware = [
        \App\Http\Middleware\HogeHoge::class
   ];
}
```

## ルートに対する指定
特定のルートに配置するミドルウェアは
`app/Http/Kernel.php`内の`$reouteMiddleware`配列内に記述する。

```php
class Kernel extends HttpKernel
{
    protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class
    ];
}
```

ミドルウェアを`Kernel.php`で定義すると、`middleware`メソッドを用いて
ルートに割り当てることができるようになる。

```php
Route::get('/profile', function() {
    //
})->middleware('auth');
```

# 参考
[Laravel 8.x ミドルウェア](https://readouble.com/laravel/8.x/ja/middleware.html)
Vue3のSFC/tsxでcss modules を使うメモ


VueをTypeScriptで扱うにあたって、SFC/comosition apiでのtemplateの型に困りすぎてjsx記法を検討している。

tsxとして記述できるのは知っていたが、Vueが魔術的に解決している **scoped な css はどうやるのかな?** というのを確かめる必要があった。

結論から言うと、 SFCの`<style>` を`scoped`でなく `module` として記述し、
`setup` や `render` 関数の中で `useCssModule()`を呼ぶことで `<style>` 内の宣言にアクセスできる。

``` {useCssModule} from 'vue'; ``` とかライブラリの機能でかすぎない?

以下の感じ。



```vuejs:SampleComponent.vue

<script lang="tsx">
import {defineComponent, PropType, useCssModule} from 'vue';

interface Props {
  hoge : {
    text : string
  }
  fuga? : number
}

export const SampleComponent = defineComponent({

  props : {
    hoge : {
      type : Object as PropType<Props[`hoge`]>,
      required: true
    },
    fuga : {
      type : Number as PropType<Props[`fuga`]>
    }
  },
  setup(props : Props){

    const styles = useCssModule();

    return ()=>{
      return (
        <div class={styles.sample} >
          <h1 > Sample { props.hoge.text } </h1>
          { props.fuga &&  (
            <div>
              {props.fuga}
            </div>
          )}
        </div>
      );
    };
  }
})
</script>

<style module lang="scss">
.sample {
  color: red;
}
</style>


```


ちょっとSFC内で別コンポーネント切り出ししたいときとかはこうなるかも
```vuejs
import {defineComponent, PropType, FunctionalComponent, HTMLAttributes, useCssModule} from "vue";

...

const MyButton : FunctionalComponent<HTMLAttributes & {styles : Record<string, string>}> = (props , {slots} )=>{
  return (
    <button {...props} class={props.styles.mybtn}>
      { slots.default && slots.default() }
    </button>
  );
}

```


Vueの `ref` と併せ、これで全体の操作感がちょっと前の **「React + tsx + mobx + css modules」 構成に近い書き味となった。**

ならはじめからReactでいいのでは?というとそうかもしれない。
Azure SQLデータベース チュートリアル

AzureのSQLデータベースを触ってみたので勉強メモ兼ねて記載します。

# SQLデータベース
SQLServerをベースとしたデータベースを提供
下記の機能が使用できる。
- 自動フェールオーバー
- ファイアウォール機能
- 自動バックアップ
- Geoレプリケーション …etc

### Azureリソース
- SQLデータベース（課金対象）
　データベース環境を提供。このスペックで性能と価格が決まる。

- SQLServer（論理サーバ）
　仮想マシン上にSQLServerがインストールされるイメージ。

### DTU
DTU（データベーストランザクションユニット） = SQLデータベースのパフォーマンスの指標
標準となるスペックを10とすると、20は2倍のスペック、50は5倍のスペック　のような感じ。

# 実際に作ってみる
今回は簡単にSQLデータベースを作成して接続確認するところまで実施。

SQLデータベースの作成
![sql1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99895/5a247ff1-894b-1287-dcf9-07fdceed7192.png)

リソースグループは適当な名前で新規作成
データベース名は適当な名前を入力（今回はTestDatabase）
サーバは「新規作成」をクリックして別画面で入力
データベースのスペックも「データベースの構成」をクリックして別画面で選択
![sql2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99895/2a0383dd-0bba-2ac7-930e-a566c7caad26.png)

- サーバの詳細
    リージョンは東日本リージョンを選択
    サーバ名は一意な名前にする必要があるので注意（Azure全体で一意）
    ![sql3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99895/b94c9bbc-29aa-34ba-f76d-9e7ac39baf9d.png)


- サービスレベルおよびコンピューティングレベル
    サービスレベル：Basic
    DTU: 5
    ※ どれを選択しても課金が発生するので注意。
    　[価格 - Azure SQL Database Single Database | Microsoft Azure](https://azure.microsoft.com/ja-jp/pricing/details/azure-sql-database/single/)
    
    ![sql4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99895/f54daed4-fdc6-2e14-0ea6-9b7ebe064758.png)


ネットワーク接続については、パブリックエンドポイントを選択。
これでインターネットを介してDBに接続することができる。
※社内などの場合は注意。
![sql5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99895/a869a4f7-9cd6-c5ef-bb4f-7bd74d5705ce.png)

セキュリティ、追加設定についてはデフォルト設定のため割愛。
作成をクリックし、少し待つと作成完了！
![sql6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99895/66bd6f67-baa0-fbb1-a483-7d198d88c94b.png)


### クエリエディター
AzurePortal より「クエリエディター」を選択することで
ポータル画面からCreate文やSQLが発行できる。

クエリエディターから、サーバの詳細画面で決めたログイン情報を入力
![sql7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99895/ab135d58-4df3-7074-5c9d-3c167a48e292.png)

下記の赤枠の部分からCreate文やSQLが発行できる。
![sql8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99895/a83352f5-cf7a-1e86-6d6a-1bc42b831078.png)


# 接続確認
今回はSQLクライアント「**[A5:SQL Mk-2（A5M2）](https://cloudsmith.co.jp/blog/efficient/2021/10/1917573.html)**」を利用して接続確認を行う。
※Microsoft純正のデータベースツールもあるみたい。（今度使ってみよう、、）

　[Azure Data Studio とは - Azure Data Studio | Microsoft Docs](https://docs.microsoft.com/ja-jp/sql/azure-data-studio/what-is-azure-data-studio?view=sql-server-ver15)

データベースの新規接続で、「Microsoft SQL Server」を選択。
下記のデータベース接続内容を入力して、テスト接続をクリック。
サーバ名：上記で作成したSQLデータベースのサーバー名（AzurePortalで確認）
ユーザID・パスワード：自分で決めた認証情報
データベース名：上記で作成したデータベース
![ak51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99895/5363527e-e6de-d404-a588-76489241ea45.png)
![ak52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99895/fe050570-2531-1ac4-a4db-fd95e3a26f42.png)

SQLデータベース のチュートリアルは以上。
AWS初心者が覚えておく用語集

## IAM（アイアム）
``AWS上のサービスを操作するユーザーとアクセス権限を管理するのがIAM（AWS Identity and Access Management）``。

ユーザーがアクセスするための認証情報やAWSリソースを制御するための権限を集中管理することができる。

## VPC
AWS VPC（Amazon Web Service Virtual Private Cloud）とは、``ユーザー専用のプライベートなクラウド環境を提供するサービス。`` AWSでは基本的にVPCが必須だが、最初に使うVPCはAWS側が自動的に用意してくれる。

## Region（リージョン）
AWSサービスのバックボーンは、「リージョン」と呼ばれる地理的に離れた領域のデータセンター群がそれぞれ接続されることで構成されている。

各リージョンではAWSのサービスがそれぞれ独立して提供されている。
例をあげると、日本には東京リージョン（ap-northeast-1）があり、米国にはバージニア北部リージョン（us-east-1）、オレゴンリージョン（us-west-2）などがある。

## AZ（アベイラビリティゾーン）
AZとは、``データセンター``のこと。各リージョンには複数のデータセンター（AZ）が置かれており、システムを複数のAZに置くことができる（Multi-AZと呼ばれる）。
AZには固有の名称が付けられており、東京リージョンでは4つのAZが提供されている。

## サブネット
サブネットとは、``ある1つの大きなネットワークの中をさらに小さく分割した小規模ネットワーク＝ネットワークの範囲のこと``。

サブネットは「サブネットマスク」という考え方で分割を行いその範囲を示す。IPアドレスとサブネットマスクを組み合わせることで、ネットワークの範囲（サブネット）を指定することができる。（例：172.16.0.1 / 255.255.255.0　など）

## インターネットゲートウェイ
VPCからインターネットへ接続するための接続ポイント。

## EC2
Amazon EC2（Amazon Elastic Compute Cloud）とは、``AWSが提供する「仮想サーバー」``のこと。

EC2を用いて``Linux``や``Windows``などさまざまなOSの仮想サーバーをすぐに実行環境を用意することができ、また複数の仮想サーバーを立てることもできる。

## Instance（インスタンス）
``AWS クラウドに立てられた仮想サーバーをインスタンスと呼ぶ。``EC2やRDSなどの仮想サーバーを数える時に**単位**として使われる。

``EC2はサービス名。自分たちで立てたサーバひとつずつのことを“インスタンス”と呼ぶ。``

## RDS
Amazon RDS（Amazon Relational Database Service）はAmazonの提供する``リレーショナルデータベースサービス。``

MySQLやPostgreSQL、Oracle、SQL Serverなど多くの種類のデータベースを、管理画面から設定するだけで構築・設定して利用できる。

## EBS
Amazon EBS（Amazon Elastic Block Store）は、``AWS上で操作できる仮想ディスク``。
管理コンソールからEBSボリュームを作って、それをサーバーインスタンスへ接続、切断できる。
**接続することをアタッチ、切断をデタッチと呼ぶ。**

## S3
AmazonS3（Amazon Simple Storage Service）は、``Amazonが提供するストレージサービス``。

バケットと呼ばれるリソース（入れ物）にデータを保存する。S3は非常にコストパフォーマンスに優れたストレージサービスで、保存できるデータ容量に上限がない。

## CloudWatch（クラウドウォッチ）
Amazon CloudWatchは、``AWSが提供する「フルマネージド運用監視サービス」``で、``AWSの各種リソースを監視してくれるサービス``。

異常が生じた時にはそれをアラートで知らせるだけではなく、自動復旧も可能で、AWS上で監視を行う際には欠かせない存在。

## Elastic IP
パブリックIPを固定化するための仕組み。
※EC2インスタンスに割り当てられるパブリックIPアドレスはデフォルトで動的に割り当てられ、起動し直すたびに変更される。

## ルートテーブル
AWSのルートテーブルは、サブネット内にあるインスタンス等がどこに通信にいくかのルールを定めたもの。

つまり、ルートテーブルはパケットの宛先(IPアドレス)を見て、どこに通信を流すかが書かれている表。
この表をみてパケットを運ぶので、表にない宛先のものはパケットを送らないので、通信できない。サブネット毎にどこに通信ができるかを定めたものだというところがポイント。

## 参考記事
[AWS入門　初心者が覚えておくべきAWSの基本](https://business.ntt-east.co.jp/content/cloudsolution/column-37.html)
[AWS用語解説](https://qiita.com/TakaKun/items/1059f1820d140c225e4a)
[AWSのルートテーブルって何よ？VPCとサブネット踏まえて簡単に説明してみる](https://qiita.com/chro96/items/21863e0960ba4ac72470)
nuxt/contentで「TypeError: this.getOptions is not a function」とエラーが出る

nuxt/contentをプロジェクトに導入していたら
「TypeError: this.getOptions is not a function」
というエラーが発生して画面が表示されなくなってしもた。。。

## 原因
webpacｋとsass-loaderのバージョンによるものらしい。

参考にさせていただいた記事
https://cly7796.net/blog/javascript/error-when-using-sass-with-nuxt-js/

## 対策

sass-loaderのバージョンを10に指定する。

```console
$ yarn add sass-loader@10
```
PN532 NFC RFID module + RaspberryPi で FeliCa と Mifare を判別する

(Felica/Mifare/NFC チャレンジシリーズ) その他の記事はこちら 「FeliCa/Mifare/NFC でいろいろ実験」
https://qiita.com/nanbuwks/items/1f416d6e45a87250ee0a

-----

「PN532 NFC RFID module + Arduino で FeliCa と Mifare を判別する」
https://qiita.com/nanbuwks/items/a264201dcc0b4e12e72d

では Arduino でやっていましたが、これを RaspberryPi でやってみます。

# 環境

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/0babc924-8607-6271-10fa-3468b56212cb.png)


- PN532 NFC RFID module
  - 電解コンデンサ追加加工済
  - cf., 「NFC モジュールの動作安定性を改善する」 
  - https://qiita.com/nanbuwks/items/a9217ba2e8f206b899b1
- Raspberry Pi Model B+ V1.2
  - Raspberry Pi OS Lite armhf-2020-12-04
- Python 3.7.3
- 1.0.4 version of nfcpy


# 接続とインストール

この記事の通りに行っています。
「Raspberry Pi で nfcpy + PN532 NFC RFID module」
https://qiita.com/nanbuwks/items/e14d8fdd6f863d5b68fe

# サンプルプログラムで判別する

単にサンプルプログラムの tagtool.py  を実行するだけで、以下のように判別できます。

FeliCa の場合

```

$ python3 tagtool.py --device tty:AMA0
[nfc.clf] searching for reader on path tty:AMA0
[nfc.clf] using PN532v1.6 at /dev/ttyAMA0
** waiting for a tag **
Type3Tag 'FeliCa Standard (RC-S960)' ID=0114B4276B115A23 PMM=0F0D23042F7783FF SYS=8B61
```

Mifare の場合

```

$ python3 tagtool.py --device tty:AMA0
[nfc.clf] searching for reader on path tty:AMA0
[nfc.clf] using PN532v1.6 at /dev/ttyAMA0
** waiting for a tag **
Type2Tag ID=C5B20FAD
```

# コードを書く

判別のためのコードを作ってみます。

```
# coding:utf-8
import pprint
import nfc

print('please touch')
clf = nfc.ContactlessFrontend('tty:AMA0')
try:
    tag = clf.connect(rdwr={'on-connect': lambda tag: False})
finally:
    clf.close()
if ('FeliCa' in str(tag)):
  print("This card is FeliCa")
elif ('Type2Tag' in str(tag)):
  print("This card is Mifare")


# print(str(tag))
# pprint.pprint(vars(tag))
# pprint.pprint(vars(tag._clf))
# pprint.pprint(vars(tag._target))
```

手持ちの nanaco カードを読ませた場合
```

$ python3 checkcard.py
please touch
This card is FeliCa
```

```

$ python3 checkcard.py
please touch
This card is FeliCa

```

# 動作内容

サンプルコードの


```

# print(str(tag))
```

を有効にした場合、以下のように返ってきます。

FeliCaの場合

```

$ python3 checkcard.py
please touch
This card is FeliCa
Type3Tag 'FeliCa Standard (RC-S960)' ID=0114B4276B115A23 PMM=0F0D23042F7783FF SYS=8B61


```

Mifare の場合

```
$ python3 checkcard.py
please touch
This card is Mifare
Type2Tag ID=C5B20FAD

```
ドメイン分析テスト

# ドメイン分析テスト 
ドメイン分析とは同値分割や境界値分析とほぼ同じ概念です。ただし、関係性がある複数の変数を同時にテストするときに特にドメイン分析という言葉を使います。ドメイン分析はn湯力に着目する場合が多いものです。

## ドメイン分析はどのようなときに使えるのか?
ドメイン分析の基本的なバグをどう見つけるか?という考え方は、境界値分析と同じです。変数に相関関係があるときには、ちゃんと分析しないとなにが境界なのかわからなくなります。そんなときんドメインをちゃんと理解してどこが強化だと判断すればいいのかを教えてくれるのがドメイン分析です。

## 境界値分析との違い
二つ以上の変数の相関関係の境界値を求めてテストケースにするときはドメイン分析を使う。

## デシジョンテーブルとの違い
テストするパターンの値を特定する際に境界値をテストしたい場合、かつその境界を求めるには複数の変数の相関関係から境界値を求める場合はドメイン分析を使う。

## ドメイン分析の例
荷物の宅配をする際の料金を例に考えてみます。
例
```
チルド宅配パックの大きさの最大限は、長さ100cm以下でかつ長さ・幅の合計が150cm以下です。
また大きさが長さ、幅が共に1cm以上の荷物が宅配の対象となります。
```
||x<=36|x<36
| :------------- | :------------: | ----: 
|on| 36|36
|off|37  |35      
|in| 25,30など|25,30など       
|out |45,50など| 45,50など

- 実際にテストケースを作成する際にはど名ンテストマトリックスという表を作成する。
# まとめ
- 複数の変数に相互関係(影響し合う)があり、その強化値を検証するテスト。
- 本での紹介例では一定の範囲の値をとる二つの変数(x<=36,y<-4.0など)の相互関係のテストで示されていた。
- 上記のような連続的な値を取り、境界値が存在する変数においてはon(境界値)、off(境界値のすぐ上orすぐ下)、in(任意の有効値)、out(任意の無効値)という四つのポイントからテストケースを割り出す。
- offについてはonが有効値(<=,>=の場合)の場合は無効値、onが無効値(<,>の場合)の場合は、有効値として設定する。
Vue3でGSAPを使ってページ遷移時のアニメーションを実装する

## 概要

Vue3でページ遷移時のアニメーションをアニメーションライブラリであるGSAPを使って実装する方法です。

Vueには標準で `transition` という機能がありますが、ページ遷移時のアニメーションの場合新しいページのレンダリング状況を確認する必要があるため、そのままでは実装できません。専用のライブラリを導入するなどの方法もありますが、今回はGSAPを使って実装する方法を紹介します。

## 環境

以下の環境での動作を確認しています。GSAPの導入がまだの方は `npm install gsap` からインストールしてください。また、Vue Routerによるルーティングの設定は済んでいるものとします。TypeScriptはどちらでも構いません。

- Vue 3.2.29
- Vue Router 4.0.12
- GSAP 3.9.1
- TypeScript 4.5.5

## 実装

ページが切り替わったときにアニメーションを適用させたい要素にCSSのclassを当ててください。

今回は `App.vue` の `<RouterView />` に対して適用させるため、divで囲って `.wrapper` というclassを当てました。

```vue:App.vue
<script setup lang="ts">
import { RouterLink, RouterView } from 'vue-router';
</script>

<template>
  <RouterLink to="/">
    <header>
      <img src="@/assets/logo.svg" />
      <h1>Site Title</h1>
    </header>
  </RouterLink>
  <div class="wrapper">
    <RouterView />
  </div>
</template>
```

Vue Routerによるルーティングを設定しているファイル ( `router/index.ts` など ) に、以下のコードを追記してください。

```typescript:router/index.ts
import { createRouter, createWebHistory, type RouterScrollBehavior } from 'vue-router';
import gsap from 'gsap';

import HomeView from '@/views/HomeView.vue';


const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  // routesの中身はご自分の環境に合わせ適宜修正してください
  routes: [
    {
      path: '/',
      component: HomeView
    }
  ]
});

// ここから

router.beforeEach((to, from, next) => {
  const tl = gsap.timeline();
  tl.to(".wrapper", {
    duration: 0.5,
    opacity: 0,
    onComplete: () => {
      next();
    }
  }).to(".wrapper", {
    duration: 0.5,
    opacity: 1
  }, 1);
});

// ここまで

export default router;

```

今回はページ遷移開始直前に `.wrapper` の透明度を0.5秒かけて0にした後、ページ遷移を実行し、完了後0.5秒かけて透明度を0に戻すというアニメーションを実装しました。

GSAPの `timeline()` は複数のアニメーションを連結させることができる「タイムライン」を作るメソッドです。また `.to()` 内の `onComplete` は対象のアニメーションが完了した後に呼び出される関数です。

2つ目の `.to()` の第3引数で `1` を指定していますが、ここで前のアニメーションから何秒遅らせて実行するかを設定できます。SPAは基本的に遷移後のページのロードはなく遷移する動作自体は一瞬で終わってしまうので、1秒遅らせることで視覚的にアニメーションが行われていることが分かりやすくなります。
ログインセッション外でBluetoothスピーカを使用する

Raspberry Pi 3B にはBluetoothが搭載されている。
このBluetoothでGoogle Nest mini と接続し、
cronで定時チャイムを鳴らしたかったのだがなかなかうまくいかなかったメモ。

# 環境
Raspberry Pi3 Model B
~~~
% cat /etc/os-release
PRETTY_NAME="Raspbian GNU/Linux 11 (bullseye)"
NAME="Raspbian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
ID=raspbian
ID_LIKE=debian
HOME_URL="http://www.raspbian.org/"
SUPPORT_URL="http://www.raspbian.org/RaspbianForums"
BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"

% uname -srvmpio
Linux 5.10.103-v7+ #1530 SMP Tue Mar 8 13:02:44 GMT 2022 armv7l unknown unknown GNU/Linux
~~~

# まず結論
- pulseaudio を system モードで起動する
- `system.pa` に bluetooth モジュールと switch-on-connect モジュールを有効化する設定を入れる

# 仕組み(自分の理解)
Linuxは低レイヤーではALSAという仕組みで音を鳴らしている。
これを高レイヤーに抽象化しているのが pulseaudio
cf. https://ja.wikipedia.org/wiki/PulseAudio
cf. https://wiki.archlinux.jp/index.php/PulseAudio
cf. https://mickey-happygolucky.hatenablog.com/entry/2015/04/04/105512

ALSAはカーネルランドの仕組みなので、Linuxが起動すれば特に何もしなくても使える。
一方で、pulseaudio はユーザランドの仕組みであり、通常はユーザ毎に起動が必要。
ただし、この起動は systemd で自動化されているので、ユーザが気付くことは通常ない。
また、システムグローバルで pulseaudio を実行することも可能。(しかし、セキュリティの問題で推奨されない模様)

そして、pulseaudio がユーザ毎に起動するときに読み込む設定ファイル `/etc/pulse/default.pa` と、
システムグローバルで起動する時に読み込む設定ファイル `/etc/pulse/system.pa` は違う。
そしてそして、`default.pa` にはBluetoothを利用するための設定が入っているが、`system.pa` にはそれがない。

あと、ユーザ起動した pulseaudio は Bluetooth 接続するとデフォルトの出力先がそちらに切り替わるのだが、
システム起動するとデフォルトの設定では切り替わらない。
これを切り替えられるようにするため、`system.pa` を修正するのだが、
なぜか`default.pa`にはその設定がなくても前述の通り自動で切り替わる・・・謎。

なお、pulseaudio のモジュールは、下記ディレクトリに格納されている。
`/usr/lib/pulse-14.2/modules/`

# 実際やること
## 必要なパッケージのインストール
`sudo apt install pulseaudio-module-bluetooth sox libsox-fmt-all`

## system.pa を修正
次の設定を末尾にでも放り込む。

~~~ shell:/etc/pulse/system.pa
### Automatically load driver modules for Bluetooth hardware
.ifexists module-bluetooth-policy.so
load-module module-bluetooth-policy
.endif

.ifexists module-bluetooth-discover.so
load-module module-bluetooth-discover autodetect_mtu=yes
.endif

### Automatically switch to newly-connected devices
load-module module-switch-on-connect.so
~~~

前半のブロックがBluetoothモジュールの読み込み、
後半のブロックが接続された機器に自動的に切り替える設定。
cf. https://wiki.archlinux.jp/index.php/Bluetooth_%E3%83%98%E3%83%83%E3%83%89%E3%82%BB%E3%83%83%E3%83%88

## pulseaudio をシステムモードで起動
`sudo pulseaudio -D --system --disallow-exit`

`--disallow-module-loading` オプションを付けるとうまくいかない？？

## Bluetooth 接続
こちらの記事も参照: https://qiita.com/takashi53/items/f6a866f0081609dbb8d6
~~~ command
bluetoothctl
scan on
scan off
pair <MACアドレス>
connect <MACアドレス>
trust <MACアドレス>
exit
~~~
`connect`を打ったタイミングで、Bluetoothスピーカーとの接続が確立されるハズ。
もし確立できない場合は、pulseaudio がきちんと立ち上がっていないか、Bluetoothモジュールが入っていない可能性がある。

## 試す
`play /usr/share/sounds/alsa/Front_Center.wav`

# そのほか、今後の展望
- もしかしたら、 pulse ユーザを適切なグループに属させないといけない？
- pulseaudio のシステム起動を systemd 化したい。要調査。
- VOICELOIDとかと連携させたいがキツそうなのでVOICEVOXにチャレンジしてみる。
【Bitbucket】SSH公開鍵の作成

新しいPCになったので新しくリポジトリを`git clone`しようと思ったら
```
Permission denied (publickey).fatal: Could not read from remote repository.
```
になった．原因はローカルとリモートリポジトリで同じ公開鍵を保持してないからだ．
というわけで新しく公開鍵作って登録した．


鍵の作成
```
$ ssh-keygen -t rsa
```
作った鍵をクリップボードへコピー
```
$ pbcopy < ~/.ssh/id_rsa.pub
```
リモートリポジトリ側で鍵を登録
![スクリーンショット 2022-03-16 16.51.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/377231/9b8142e6-739f-84d3-5ddd-218177e8c222.png)

以上．認証が通ってリポジトリのクローンができるようになった．

めでたし
Gitコマンドまとめてみた 一覧（備忘録）

# 目的
Railsチュートリアルで学習したGitコマンドを、備忘録として残します。

# Gitコマンド一覧
### 初期設定
```terminal:名前とメールをGitに設定する
$ git config --global user.name "自分の名前"
$ git config --global user.email 自分のメールアドレス
```

### ローカルにリポジトリを作成
```terminal
$ git init
```
リポジトリの再初期化の意味もある
### プロジェクトのファイルをリポジトリに追加
```terminal
$ git add -A
```
「-A」 とすることでプロジェクトの全ファイルをリポジトリに追加できます。

Gitにプロジェクトのファイルを追加すると、最初はステージング（Staging）という一種の待機用リポジトリに置かれます。

[ステージングの状態の確認方法](#1-ステージングの状態を確認)

### リポジトリに反映
```terminal
$ git commit -m "コミットメッセージ"
```
※Gitにおけるコミット操作は、あくまでローカルマシン上にしか記録されない

[コミットメッセージの履歴の参照方法](#2-コミットメッセージの履歴を参照)

### GitHubをリモートoriginに追加
まずはGithubで新しいリポジトリを作成してください。
```terminal:先程作成したリポジトリの情報を入力
$ git remote add origin https://github.com/あなたのGitHubアカウント名/リモートリポジトリ名
```
### Githubにpush
```terminal
$ git push -u origin master
```

# 補足

### パスワードの保持
```terminal:Gitでパスワードを一定時間保持するように設定する
$ git config --global credential.helper "cache --timeout=86400"
```
"cache --timeout=86400"の部分で保持する期間を指定できる

### ステージングの状態を確認
```terminal
$ git status
```
git add でリポジトリに追加した

### コミットメッセージの履歴を参照
```terminal
$ git log
```

### ブランチ
```terminal:ブランチの作成
$ git checkout -b ブランチ名
```
```terminal:すべてのローカルブランチを一覧表示
$ git branch
```

### Merge（マージ）
masterにmergeする場合を想定しています。
```terminal:master(親リポジトリ)に移動
$ git checkout master
```
```terminal:ブランチでの変更をmasterにmerge
$ git merge ブランチ名
```
```terminal:変更をmergeした後は、ブランチを削除
$ git branch -d ブランチ名
```
「-d」を使用することで対象のブランチを削除できる
※ブランチの削除は必須ではない
### Push（プッシュ）
```terminal
$ git push
```
※一度プッシュを行うと、大抵のシステムではgit pushを実行するときにorigin masterを省略できる。

# まとめ
とりあえずは、ローカルにリポジトリを作成し、リモートにプッシュする以下のコマンドがつかえればOK！
```terminal
$ git init
$ git add -A
$ git commit -m "コミットメッセージ"
$ git remote add origin https://github.com/あなたのGitHubアカウント名/リモートリポジトリ名
$ git push -u origin master
```
その他にも、たくさんのGitコマンドがあるので、おいおい勉強していきます！