OmniAICreator/Qiita-1.07M huggingface dataset:
ラストのまほう　第21話『タイトル画面とリザルト画面を作る』

ゲームであるからには、終わりと始まりが必要です。ゲームを起動するといきなりレベル画面に放り込まれるのもダメというわけではないのですが、タイトル画面を用意するとグッとゲームらしくなったような気がします。また、ゲームをクリアしたらエンディングというかリザルト画面みたいなものを用意するとクリアした感がでて良さそうです。

# シーンを定義する

ここでは、それぞれの「画面」を `Scene` と呼ぶことにします。この『シーン』は互いに独立しており、ゲーム内では必ずシーンがひとつだけ保持されて表示されます。たとえば、ゲームのレベル画面（プレイヤーキャラクターを実際に操作して遊ぶ画面）は次のような構造体で定義されています。

```rust 
#[derive(Clone)]
pub struct GameScene {
    rng: Rng,
    frame_count: u32,
    player: Body,
    player_lookup: i32,
    fruits: std::vec::Vec<Body>,
    world: World,
    debug: bool,
    score: f32,
    vibration: i32,
}
```


それから、この構造体にコンストラクタみたいなのと`update`メソッドを生やしておきます。

```rust 
impl GameScene {
    pub fn new() -> Self {
        ...
    }

    pub fn update(&mut self, inputs: &Inputs) -> Option<Scene> {
        ...
    }
}
```

ここで、`update`関数は`Option<Scene>`を返すようになっていますが、ここで`Some`を返した場合はそのシーンが次のシーンとして切り替わるようにしたいと思います。

このような構造体を、タイトル画面とリザルト画面のぶんも定義します。

# シーンを切り替える

TypeScriptのような言語であれば、`Scene`インターフェイスを用意して`start`と`update`メソッドを定義し、各シーンではこのインターフェイスを実装するというような仕組みを考えます。オブジェクトはヒープに入れて常にポインタ越し（参照越し）に扱う言語であればそれでいいのですが、今回は言語がRustなのでシーンを表すオブジェクトはスタックに入れたいと思います。その場合、各シーンは`enum`に入れて保持することになります。

```rust
#[derive(Clone)]
pub enum Scene {
    TitleScene(TitleScene),
    GameScene(GameScene),
    EndingScene(EndingScene),
}
```

あとはこれをゲーム全体を表す構造体に入れて、この`enum`からシーンの構造体を取り出しては`update`を呼ぶということを繰り返すだけです。

```rust 
pub fn update(&mut self) {

    ...

    let result = match { &mut self.scene } {
        Scene::TitleScene(t) => t.update(&inputs),
        Scene::GameScene(g) => g.update(&inputs),
        Scene::EndingScene(e) => e.update(&inputs),
    };
    match result {
        Option::None => {}
        Option::Some(next) => self.scene = next,
    }

    ...
}
```

# 画像がデカすぎる

ちなみに、この画面全体を覆うような大きい画像を使うと、`2 bits * 160 pixel * 160 pixel bits = 6.4 kbytes`で、なんと**カートリッジサイズの1/10をタイトル画面の画像1枚が占める**ということになってしまいます。画像を圧縮する手も考えたのですが、よく考えたら画像を描画するときに結局メモリ上に展開することになり、そちらも64キロバイトしかないので余計に容量を食うことになるだけです。あんまり演出に凝るな、いいからゲームの完成を優先しろ、ということですね。



# 次回予告

次回はちょっとしたお休み回で、他のWASM-4製ゲームを触ってみて、みんなどんなゲームを作っているのか調査してみます。


https://qiita.com/hiruberuto/items/71bcfd08a4f2b0687fff
リリース済みのAndroidアプリをリファクタリングしてみた

これまで、個人開発で製作してきたAndroidアプリ「[書籍管理ができる巻数メモ](https://play.google.com/store/apps/details?id=com.highcom.comicmemo)」は継続的に機能追加するアップデートは行ってきたものの、リファクタリングによって刷新するような事はしてきませんでした。
仕事でもAndroidアプリを開発するようになり、知識も少しずつ増えてきたので、思い切ってリファクタリングをしてみることにしました。

# なぜリファクタリング？
個人開発をしていると、ゼロから作ったり、どんどん機能を追加したりすることはよくありますが、既存機能をリファクタリングするというのは、やろう！って思わないとなかなかやらないと思います。
リファクタリングの難しいところは、

- 変更後も既存と同等の機能を実現する
- 変更前のデータも引き継ぐ
etc...

既にサービスを提供しているものをそのまま継続して利用できるようにしなければなりません。なので、リファクタリングをするということも新しい技術的な知識が習得できると思ったのが背景にあります。

# 今回のリファクタリングの要点
今回、リファクタリングによって変更したポイントは以下です。

- 画面レイアウトの全面的な刷新
- JavaからKotlinへの使用言語の変更
- LiveDataを利用したMVVMモデルへの刷新
- DBアクセスをSQLiteOpenHelperからRoomライブラリへの変更

それぞれの内容について具体的に書いていきたいと思います。

# 画面レイアウト
せっかくなので、最初は画面レイアウトも刷新しました。
アプリのテーマカラーを基調としてマテリアルデザイン風にしてみました。
ActivityもFragmentActivityからAppCompatActivityを継承するように変更したり、フローティングボタンを活用するように変更してみました。
![comicmemo_refactor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545703/3d6cfd72-68c5-e313-17b3-fd0979d1751c.png)

# JavaからKotlinへの使用言語の変更
これまでずっとJavaを利用してAndroidアプリを開発していましたが、仕事でもKotlinを利用するようになり、だいぶKotlin言語にも慣れてきたので、全部Kotlinで書き直すことにしました。
といっても、AndroidStudioには便利な機能があるため、まずは以下の操作でJavaファイルをKotlinファイルへ一気に変換します。
app/javaフォルダを右クリック→「Convert Java File to Kotlin File」を選択
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545703/a9ecc6c1-4cfc-9c02-e0b4-e6f130b14f08.png">
もちろん、ただ変換しただけではビルドが通らないので、この後はひたすらエラーとなっている箇所を修正していきました。

# LiveDataを利用したMVVMモデルへの刷新
今回のリファクタリングで大きく刷新した部分はアーキテクチャです。
修正前後でのクラス図については以下のようになります。
#### 修正前
![クラス図_ComicMemo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545703/0a33dd44-5412-bd9c-c72e-094e859f1af5.png)
#### 修正後
![クラス図_ComicMemo_リファクタ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/545703/874d148e-9c30-e189-ff7e-91bd322943cd.png)

修正前では、ListDataManagerクラスがデータを管理する形となっており、SQliteOpenHelperを継承したListDataOpenHelperを利用してDBへのアクセスを行っていました。
修正後では、ComicMemoRoomDatabaseクラスでRoomライブラリを利用したDBへのアクセスの実現と、ComicPagerViewModelクラスが非同期でのDB操作のAPIの提供と、DB更新完了時のLiveDataを利用した更新通知を実現することで、MVVMモデルへのアーキテクチャ変更を行いました。

# DBアクセスをSQLiteOpenHelperからRoomライブラリへの変更
DBアクセスをRoomライブラリを利用した実装に変更する際に気をつけるのが、データエンティティクラスの定義と、データアクセスオブジェクトクラスの定義です。
今回は、それぞれComicクラスとComicDaoクラスを定義しました。
また、SqliteOpenHelperを利用したテーブル定義からRoomライブラリを利用したテーブル定義へと変更する場合には、テーブルデータのマイグレーションを行う必要がありました。
各カラムの変数名や型を合わせても実はあってなかったという場合には、「Migration didn't properly handle」というExceptionが発生してしまいます。
この原因としては、例えばエンティティをLong型で定義してもSQLiteの型になるときにはINTEGERとなったりしますし、null許容型変数で定義をしない場合は移行前のテーブルもNOT NULL制約が付いている必要がありました。
移行前後でカラムの型を合わせるためにMigrationクラスのmigrateメソッドをoverrideして合わせました。

具体的なソースコードは、以下から参照出来ますので参照してみてもらえればと思います。
※v2.5タグとv3.0.0タグを比較すると分かりやすいと思います。

https://github.com/highcom/ComicMemo

# さいごに
リファクタリングしたアプリは既にGooglePlayで公開されていますので是非触ってみて下さい！

https://play.google.com/store/apps/details?id=com.highcom.comicmemo&hl=ja

GitHubのソースコードを参照しながら動作を見てもらうとより分かりやすいのではないかと思います。

また、今回のアーキテクチャを適用するにあたり、参考にしたサイトは以下となりますのでこちらもおすすめです！
所用時間は60分でハンズオン形式で学ぶ事が出来ます。
[Codelab Android Room とビュー - Kotlin](https://developer.android.com/codelabs/android-room-with-a-view-kotlin?hl=ja#0)
Accessをタスクスケジューラ経由で実行する際に個人的に気をつけてる点

# 事前の動作確認方法

```ファイルを直接実行```
ではなく
```タスクスケジューラ上のタスク右クリック ⇒ 実行する```
で動作確認しよう。

**『タスクスケジューラ経由で実行した時だけ動かない or 想定外の動作』**
なんてことがよくある。
（Accessに限った話ではないけど）

# タスク実行ユーザー

下記設定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/65f20410-ea0b-71fc-6ff8-189407dbe50f.png)

『SYSTEM』っていう名前のユーザーだとAccessが起動しないので注意。
（パスワード変更を気にしなくていいように『SYSTEM』を使いたいところだけどダメ）

**『スリープなどによってユーザーがログアウト ⇒ タスクが実行されなかった』**
なんてこともあるので、スリープまわりの設定も確認しておいた方がいい。

# プログラム開始の設定

下記設定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/caad33e1-ffed-b033-4175-a3f18f3ee4b3.png)

『Microsoft365のAccess』と『Accessランタイム』が共存する環境で、 ```プログラム/スクリプト``` にAccessファイルを設定するとランタイムで起動してしまう。
（本当はMicrosoft365で起動してほしいのに…）

なので、下記のように設定するのがおススメ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/23567cd8-e63c-5c98-6afa-9fd5c037ceb0.png)

```:プログラム/スクリプトに設定する例（Microsoft365の32bitでaccdbを起動させたい時）
"C:\Program Files (x86)\Microsoft Office\root\Office16\MSACCESS.EXE"
```

```:引数の追加（オプション）に設定する例
"C:\Users\d\tester.accdb"
```

Accessファイルを起動するのではなく、MSACCESS.EXEを起動する。
MSACCESS.EXEの引数でAccessファイルのパスを渡してあげる。

ダブルクオテーションの有無に注意。
（ファイルパスは囲っておいた方がいい）

Accessファイルに引数渡したい時は ```引数の追加（オプション）``` を下記のようにすればOK。
```:Accessに引数渡す時の例
"C:\Users\d\tester.accdb" /cmd "accdbに渡す引数値"
```




# Access内で扱うファイルパス

ファイル入出力まわりで想定通りの動作にならなかったら、下記リンク先の内容を試すのもアリ。

https://qiita.com/waokitsune/items/68f7b4e6f964563c0cc8

# バージョン

Windows 10 Pro 21H2 OSビルド 19045.2311
Microsoft Access for Microsoft 365 MSO (バージョン 2209 ビルド 16.0.15726.20188) 32 ビット
データストアをセキュアに扱うために覚えたいACLとパーミッション

NCMBでは、データへのアクセスにアプリケーションキーとクライアントキー、2つのキーを利用します。この2つのキーはアプリの中にコーディング（設定ファイル経由であっても）されるため、それが漏洩することでアプリに対して甚大が被害が起こるのではないかという質問をよく聞きます。

そうしたセキュリティへの懸念はACLとパーミッションの2つを利用することで解消できます。逆に、この2つをなおざりにしていると、アプリ内に思わぬデータが追加されたりする可能性がありますのでご注意ください。

## ACL（アクセス権限）とは

NCMBのデータストア（会員管理・ファイルストア・デバイストークンなど含む）では、データ毎にACLを設定できます。このACLは3つの設定ができます。

- 誰でも
- ユーザー毎
- グループ（NCMBではロールと呼びます）毎

に読み込み、書き込み（削除含む）を指定します。

### 利用例（JavaScriptの場合）

コードで書くと、次のようになります。

```js
const Hello = ncmb.DataStore('Hello');
const hello = new Hello(); // インスタンス = 行データ
hello.set('message', 'Hello, NCMB');

// ACLの設定
const acl = new ncmb.Acl();
acl
	// 以下は必要なものだけ実行します
	.setPublicReadAccess(true)
	.setPublicWriteAccess(true)
	.setUserReadAccess(user, true) // ユーザーオブジェクトを指定します
	.setUserWriteAccess(user, true)
	.setRoleReadAccess('admin', true) // ロール（グループ）は文字列で指定します
	.setRoleWriteAccess('admin', true);
// ACLをセット
hello.set('acl', acl);

await hello.save();
```

**デフォルトでは全員に対して読み込み、書き込み可能** なデータになります。これはキーが漏洩した時にデータを自由に変更、削除されてしまう可能性があるでしょう。

## パーミッション

もう1つ知っておいて欲しいのがパーミッションです。パーミッションはクラスの編集から設定します。

![0351 console.mbaas.nifcloud.com - 1116145410.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/983a5349-0bd3-8da8-4237-7c229756e73a.jpeg)


このパーミッションでは、各データストアのクラス（テーブル相当）に対して、以下の権限を設定します。

- 読み込み
- 検索
- 更新
- 作成
- 削除
- フィールド追加

上記権限に対して、対象はACLと同じように以下で設定します。

- 誰でも
- ユーザー指定
- ロール（グループ）指定

### 読み込みと検索の違い

読み込みと検索の違いは、APIフォーマットを見ると分かります。

- 読み込み  
GET /classes/Hello/:objectId
- 検索  
GET /classes/Hello

検索は対象となるクラス（この例ではHelloクラス）全体に対するものですが、読み込みはオブジェクトID（データストアのユニークキー）を指定して実行します。ユニークキーが分かる人だけ、対象データにアクセスできる仕組みです。

### パーミッションの使いどころ

パーミッションを指定することで、一般ユーザーはデータの作成のみで更新や削除権限をなくしたり、不用意なフィールド追加を避けられるようになります。

## 実際にキーが漏洩して起こる問題

このようにACLとパーミッションを設定した状態でキーが漏洩した場合、不正アクセスを試みるユーザーはほぼ何もできません。唯一できることとして、プッシュ通知の作成が挙げられます。無尽蔵に作成されると、迷惑行為になるでしょう。

これを防ぐために、アプリ設定の `プッシュクラス パーミッション` にて、SDKからの操作を許可しないようにするのがお勧めです。API経由では作成できなくなりますが、運用フローの中でそういった処理が行われていないならば、オフにしておきましょう。

## まとめ

ACLについてはよく使われていますが、パーミッション設定はあまり細かく運用されていない印象です。ぜひ使いこなして、皆さんのアプリをセキュアに、安全に運用してください。

[mBaaSでサーバー開発不要！ | ニフクラ mobile backend](https://mbaas.nifcloud.com/)
LINE通知 (Messaging API)

## Messaging API

* Long Termのアクセストークン

```php
<?php
$TOKEN="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
$LINE_UID="U00000000000000000000000000000000";
$message=date("H:i:s");

$cmd.= "curl ";
$cmd.= " -s ";
$cmd.= " -X POST 'https://api.line.me/v2/bot/message/push' ";
$cmd.= " -H 'Content-Type:application/json; charset=UTF-8' ";
$cmd.= " -H 'Authorization: Bearer ${TOKEN}' ";
$cmd.= " -d '{ \"to\": \"${LINE_UID}\", \"messages\":[{ \"type\":\"text\", \"text\":\"${message}\" }]}'";

//echo ($cmd);
system($cmd);
```

* 改行は`\n`
* htmlタグがあると送信できないため、`strip_tags($message, '<br>')`などする。

## LINE Notify

* https://notify-bot.line.me/my/
NCMBのSwift SDKでのDateオブジェクトの取り扱い

NCMB Swift SDKでのTipsです。

NCMBのデータストア（クラウドデータベース）はスキーマーレスで自由にフィールドを追加したり、型を指定できます。そのため、行相当のデータを扱うNCMBObjectではフィールドの型を判別せず利用できます。

ただ、毎回型を判別しながら使わないといけないので、若干注意が必要です。

## 日付型の扱い

日付型で入っているフィールドに対しては、次のように取得できます。

```swift
let date = obj["DATE_FIELD"]! as Date
```

ただし、 `DATE_FIELD` が存在しなかったり、別な型のデータが入っていると上記コードはエラーになるので注意が必要です。

## 存在をチェックしてから取得する

そのため、以下のように行うのが良さそうです。

```swift
if let dateValue = obj["DATE_FIELD"] as Any? {
		_date = dateValue as! Date
}
```

## 自分で日時をパースする場合

NCMBのデータストアに保存されている日時はISO8601形式になります。さらにミリセカンドを含む形になっているので、以下のようにフォーマッタを定義します。

```swift
let formater = ISO8601DateFormatter()
formater.formatOptions.insert(.withFractionalSeconds)
```

そしてパースします。

```swift
let params = dateValue as! Dictionary<String, String>
_date = formater.date(from: params["iso"]! )!
```

## まとめ

基本的に `as Any?` で取得して、フィールドが存在するようであれば `Date` に変換する方法が良さそうです。データストアでは他にも文字列、数値、位置情報、真偽値、配列、オブジェクトなどが扱えますので、ぜひ活用してください。

[mBaaSでサーバー開発不要！ | ニフクラ mobile backend](https://mbaas.nifcloud.com/)
Laravel9　windows版 いつもやってる環境構築 create-project、デバッグバー・Breeze導入など

### 本記事の目的
しばしば新しくプロジェクト立ち上げるけど、コマンドがうろ覚え
そのたびに動画教材を見返すのが面倒だったので、環境構築する際いつもやっている事だけまとめてみた。
Windows環境です。

### いつもやってるLaravelの環境構築
##### ①　phpMyAdminでDB作成


##### ②　Laravelインストール
```
composer create-project "laravel/laravel=9.*" (newProjectName) --prefer-dist
```
##### ③　新規プロジェクトに移動
```
cd (newProjectName)
```
##### ④　.envの記載
```
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_db_name👈
DB_USERNAME=laravel_user👈
DB_PASSWORD=password👈
```


##### ⑤　デバッグバー導入
```
composer require barryvdh/laravel-debugbar
```

##### ⑥　Breeze導入
```
composer require laravel/breeze:^1.13 --dev
```

```
php artisan breeze:install
```
##### ⑦　DB接続
```
php artisan migrate
```
##### ⑧　npmインストール
```
npm install
```
##### ⑨　簡易サーバー立ち上げ
```
php artisan serve
```

```
npm run dev
```

Welcome！！
NCMBのSwift SDKを使ってカレンダーアプリを作る（その2：認証処理の実装）


NCMBのSwift SDKを使ってカレンダーアプリを作ります。予定を登録したり、カレンダーコンポーネント（FSCalendar）を使って予定を表示できるというアプリです。

[前回の記事では画面の説明とSDKの導入まで](https://qiita.com/goofmint/items/627dc6252bb83e188342)を進めましたので、今回は認証処理を実装していきます。

## コードについて

今回のコードは[NCMBMania/swift-calendar-app](https://github.com/NCMBMania/swift-calendar-app)にアップロードしてあります。実装時の参考にしてください。

## 認証画面について

![Simulator Screen Shot - iPhone 14 Pro - 2022-11-22 at 10.50.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/3c582806-e6a9-e46d-945d-dd87dafef3ca.png)


すでに紹介済みですが、認証画面は以下のようになります。ID/パスワード入力欄があって、ボタンを押すと `_signUpOrLogin` 関数が実行されます。

```swift
struct LoginView: View {
    // 入力用
    @State private var userName: String = ""
    @State private var password: String = ""
    // レスポンス用
    @Binding var isLogin: Bool

    var body: some View {
        VStack(spacing: 16) {
            TextField("ユーザ名", text: $userName)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .frame(maxWidth: 280)
            SecureField("パスワード", text: $password)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .frame(maxWidth: 280)
            Button(action: {
                _signUpOrLogin()
            }, label: {
                Text("新規登録/ログイン")
            })
        }
    }
    
    // ユーザー登録またはログインを行う処理
    func _signUpOrLogin() -> Void {
			// 後述
    }
}
```

## ログイン処理について

ログイン処理は、以下のような手順で行われます。

- ユーザーの新規登録
- ログイン処理

すでにユーザー登録を行っていた場合、ユーザーの新規登録はエラーになります。今回はユーザー登録とログインを兼ねているので、エラーが出たとしてもそのまま続けてログイン処理を行っていきます。

### ユーザーの新規登録

取得した入力値を使ってユーザー登録処理を行います。エラーが出たとしても無視します。

```swift
// ユーザ登録処理
let user = NCMBUser()
user.userName = userName
user.password = password
user.signUpInBackground(callback: { _ in
	// 後述
})
```

### ログイン処理

そのまま続けてログイン処理を実行します。ログインがうまくいったら、 `isLogin` を true にして、ContentViewにてカレンダー画面を表示させます。

```swift
// 成功しても失敗してもそのままログイン処理
NCMBUser.logInInBackground(userName: userName, password: password, callback: { _ in
		// ログイン結果を反映
		isLogin = NCMBUser.currentUser != nil
})
```

ここまででNCMBを使った認証処理の完成です。

## 認証後のユーザー情報について

認証後にユーザー情報を取得する際には、下記のように記述します。

```js
let currentUser = NCMBUser.currentUser;
```

認証していない場合には `nil` が返ってきます。これを使って認証状態の判別が可能です。

## まとめ

今回はカレンダーアプリの認証処理について解説しました。次は[カレンダー表示と予定の登録処理を実装](https://qiita.com/goofmint/items/ad193c32988e990cbe18)します。
さくらVPSデプロイ時のエラーについて②

## さくらVPSデプロイ時のエラー
migration 実行後に、IPアドレスでうまく表示されなかったので書き留めます。

## 原因：configの権限などの問題
vim /etc/httpd/conf.d/プロジェクト名.conf　で下記を追加。
![スクリーンショット 2022-11-22 13.22.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981740/f0cb26ac-ab9b-b312-fc11-a174088ef03c.png)
保存後、apacheを再起動(systemctl restart httpd)
![スクリーンショット 2022-11-22 13.25.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981740/42f45d6d-fe75-297f-6350-5d3d7fc97f1a.png)
表示されました。最後に、 php artisan storage:link　を実行して、画像のアップロード等も確認できました。
## 最後に
herokuのデプロイでは、画像のアップロードができず、今回はさくらVPSを使ってデプロイを行いました。自分としては、herokuと比較して難易度は高かったです。もっと色々なことができるように頑張ります！
nRF Connect SDK:LLPM

追記：LLPMは公式の仕様ではなくNordic独自の仕様である旨を追記しました。

# BLEの仕様
改めてここで説明する必要もあまりないような気もしますが、少しだけBLEの仕様についておさらいしておきましょう。BLEは消費電力を抑えるために通信インターバルが1.25msec単位となっています。また、最も短い通信インターバルは6インターバルとなっており、時間にして7.5msecです。それ以上短い時間間隔での通信はできません。
ちなみにAndroid OSは12.5msec以下のインターバルで通信するデバイスを接続することはできません。

::: note
正確にはできるけれど不特定のタイミングで勝手に切断されます
:::

# LLPMとは
LLPMとはLow Latency Packet Modeの略で、正式名称を聞いてもいまいちピンときませんが、要するにもっと早い通信インターバルで通信ができるモードです。通信インターバルは最短で1msecになります。

::: note
~~書いていないけれどきっとAuracast™のための仕様だよね~~
:::

::: note warn
Low Latency Packet Mode (LLPM) is a Nordic proprietary addition which lets the application use connection intervals down to 1 ms.
Nordic独自の追加仕様という記載がありました。
:::

弊社の製品は元々BLEで大容量通信をしているのですが、7.5msecのインターバルの壁は超えられないということでそこは甘んじて受け入れておりました。が、これを超えることができる！ということで早速試してみることに。
サンプルプロジェクトにLLPMというそのまんまのプロジェクトがあるのでこれを使います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340602/f6efc6a1-77bb-8489-ae34-23dadd75e539.png)
なお、LLPMに関するドキュメントはこちらです。

https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/samples/bluetooth/llpm/README.html

書いてある通りにターミナルソフトを二つ起動してそれぞれをCentral/Peripheralで動かします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340602/ba9cf30f-b176-fe08-10da-33da8fb053c4.png)
片方をPeripheralモードで動かし始めるとアドバタイズを始めたことが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340602/92069680-5031-79d6-d43b-ad1801df4140.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340602/fffaa877-b534-c5bd-218c-503a6317c70e.png)
もう一方の評価ボードをCentralモードで動かすと、2つの評価ボードがコネクションを確立して80unit(1.25×80 = 100[msec])のインターバルで通信をしていることが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340602/7c886bf2-a3ae-a4cd-8248-ebaab446503a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340602/bd33386a-4474-d033-44f8-cf40a474010c.png)
続けて何かキーを押すとLLPMが動き始めます。ドキドキしながらキーを押してみると・・・おぉっ！
なんと、1msecで通信しています！！！すげぇ！！！
ただ、残念ながらBLEのパケットスニファーがまだLLPMに対応していないっぽくて、エラーと認識してしまうようです。仕方がないよね、というかスニファーの先を行くことをやっているんだ、みたいな(笑)。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340602/9e0524e8-7c33-3dd4-034d-81ae2b667b15.png)
# 自社の製品に組み込む
実は残念ながらまだそこまではできておりません。この後ソースコードを解析して自社製品に組み込めるようであれば積極的に利用していこうと思います。
ssh-keygenについて

## 環境
Ubuntu20.4

## はじめに
SSH接続をするときに利用する鍵（秘密鍵と公開鍵）を作るコマンド、ssh-keygenについての記事です。

## 内容
ssh-keygenコマンドで作る鍵は、公開鍵暗号方式で使われます。鍵を作るときにアルゴリズムを選択しますが、アルゴリズムを明示的に指定しなければ、デフォルトでRSAが選択されます。RSAが推奨されているため、RSAを選択して問題ないと思います。RSAの他にもDSAというアルゴリズムがありますが、DSAは鍵の長さが1024bitとなっており、RSAよりセキュリティが弱く、推奨されていません。他にも、ECDSAというアルゴリズムがありますが、こちらもDSA系であるため、セキュリティは弱くなります。その他、ED25519というアルゴリズムもあります。こちらは、RSAの代わりに選択しても悪くはありません。RSAの第二候補として挙げられるかと思います。ED25519はRSAと比べ、鍵の長さは短く設定されているが、短い割にはアルゴリズムが強いといった特長を持っています。鍵の長さが短い分、暗号化、復号化の処理が速いといった利点があります。

アルゴリズムにRSAを選択すると、鍵の長さはデフォルトで2048bitになります。2048bitはいくつかあるセキュリティ段階の中で、高強度に分類され、セキュリティは十分に満たしているといえます。しかし、更に、もっと強度な鍵を設定したい場合は、オプションbを使って、鍵の長さを指定することができます。RSAで設定できる最大の鍵の長さは4096bitです。4096bitは超高強度に分類されます。本当のそこまで必要なのかといった意見はあるかも分かりませんが、4096bitで設定すれば、デフォルト値よりもセキュリティはより強化になります。
```
$ssh-keygen -b 4096
```

アルゴリズムにED25519を採用する場合は、オプションtでアルゴリズム名を指定します。
```
$ssh-keygen -t ED25519
```

デフォルトで本当にRSAが指定されるのか不安な場合は、次のように明示的にRSAを指定すれば、確実にRSAで作成されます。
```
$ssh-keygen -t RSA
```

RSAにはバージョン１とバージョン２が存在します。普通に、-t RSAを指定した場合は、バージョン２が選択されます。バージョン１はセキュリティに問題があることが分かっており、既に非推奨となっているため、今後利用することはないと思いますが、バージョン１を指定する場合は、次のようにします。
```
$ssh-keygen -t RSA1
```

RSAで作られた鍵が、RSAバージョン１で作られたのか、バージョン２で作られたのかを、鍵の名前から判断することができます。
- 鍵の名前が、id_rsaであれば、バージョン２で作られています
- 鍵の名前が、identityであれば、バージョン１で作られています

あくまでもデフォルトで作成される名前であるため、鍵を作成した後、名前を変更していれば、判断することはできないということにはなります。

## まとめ
ssh-keygenコマンドで鍵を作成するときは、次のコマンドで作ることが、今のところ、ベストエフォートだと言えるかと思います。
```
$ssh-keygen -t RSA -b 4096
```
Microsoft365で特定ライセンスのユーザー一覧を作成する

## skuidを取得しないといけません。

```
Connect-MsolService
Get-MsolAccountSku
```
この組み合わせではライセンスの使用量しかわからないです。

```
Connect-MgGraph
Get-MgSubscribedSku
```
この組み合わせで skuidがわかります。
[Graphの公式はこちら](https://learn.microsoft.com/ja-jp/graph/overview)

```
Get-MgSubscribedSku | Select-Object SkuPartNumber,ConsumedUnits,SkuId
```
が現実的かと思います。

```
$skuid = "777779e8-3d26-4r66-acdc-c3bo815ld0y4"
Get-MgUser -Filter "assignedLicenses/any(x:x/skuId eq $skuid )" -ConsistencyLevel eventual -CountVariable licensedUserCount -All
```
これで$skuidにセットされたskuidのライセンスが割り振られたユーザーの一覧が出てきます。

ちなみに、ライセンスの付与は
```
Set-MgUserLicense -UserId $userID -AddLicenses @{SkuId = $skuid} -RemoveLicenses @()
```
こんな感じだそうです。
さくらVPSデプロイ時のエラーについて①

# 

## さくらVPSデプロイ時　php artisan migrate を実行した時に出たエラーを書き留めておきます。

データベース作成後、php artisan migrate を実行すると以下のようなエラーが発生。

![スクリーンショット 2022-11-21 23.41.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981740/017955dd-4278-9f0e-b9d4-cf20c0037e02.png)

## 原因：mysqlにGRANT権限が付与されていなかった。
以下で実行し、無事マイグレーションが通りました。
![スクリーンショット 2022-11-22 13.10.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981740/b815f682-f355-1796-3c72-ef52347c47fa.png)
[Javascript] File System fs.readFileSync() でfile not foundになった話

```
function htmlfile_read(path){
    const fs = require("fs");
    var str = fs.readFileSync(path,"utf-8");
    return str;
}
```
fileを読み込んで出力するだけの関数を作ろうと思ったんだけど、path = "./index.html"にすると、このエラーが出る

```
htmlfile_read("ENOENT: no such file or directory, open './index.html'
```


### path構成
project名
 L index.html
 L index.js <-ここから読もうとしてる


### 解決策
path = "project名"/index.html
にしたら治った


### 確認したこと

#### pathの有効性を確認
1. path.jsの作成
project名
 L index.html
 L index.js <-ここから読もうとしてる
 L path.js
2. path.js 中身
```
const path = require("path");
console.log(path.basename("./index.html"));
```
これを実装して存在することを確認した。
ちなみに、デバッガからではなく、コンソールから node path.jsで動かしました。


### File.jsの作成
project名
 L index.html
 L index.js
 L path.js
 L file.js <- こっから読み出してみた

file.jsの中身
```
var str_result = htmlfile_read("./index.html");
console.log(str_result);

function htmlfile_read(path){
const fs = require("fs");
var str = fs.readFileSync(path,"utf-8");
return str;
}
```

作りたいものだけ取り出して、(HTTPとかも書いていたので)起動したらこれもうまくいった
コンソールから、node file.jsで起動させてみた

### index.js上でなんで動かなかったのか？

・・結局分からず。
だけど、コンソールで node index.jsしたら元々のまま（"./index.html"指定）でもうまくいったので、もしかしたらパッケージファイルとかなんとかの話かもしれない。とりあえず解決した。これ以上はもう良い。
Redisのアップグレード

# Redisのアップグレード（Ubuntu20.04版）

アップグレードしたいRedisのバージョンをあらかじめ探しておく。
ダウンロードできるサイトはこちら。
https://download.redis.io/releases/

```
mkdir Downloads

cd Downloads

wget https://download.redis.io/releases/redis-7.0.5.tar.gz　　<= 現在のバージョン７の最新板

tar -xvf redis-7.0.5.tar.gz

cd redis-7.0.5

make

make test　　<= エラーが出ることもあるが、テストなので、できなければ無視でもOK

sudo mv src/redis-server /usr/bin

sudo mv src/redis-cli /usr/bin

service redis-server restart

redis-server -v
```

テストの際にtclがないと言われたら、以下を実行
```
sudo apt-get install tcl
```
JavaでWord文書の空白行を削除する方法

Word文書を扱っていると、大量の空白行に遭遇することが多く、文書の美観を損ねるだけでなく、文書の読みやすさも損なわれてしまいます。本記事では、無料の専門家向け開発ツール「[Free Spire.Doc for Java](https://jp.e-iceblue.com/introduce/free-spire-doc-for-java.html)」を使って、Word文書内の空白行や段落を素早く削除する方法を紹介します。具体的な操作手順は、以下のとおりです。

## 【依存関係の追加】

> **この方法は、無料のFree Spire.Doc for Javaが必要ですので、先にjarファイルをインポートしてください。**

### 1. Maven

Maven を使用している場合、プロジェクトの pom.xml ファイルに以下のコードを追加することで、簡単にアプリケーションに JAR ファイルをインポートすることができます。

```XML
<repositories>
    <repository>
        <id>com.e-iceblue</id>
        <name>e-iceblue</name>
        <url>https://repo.e-iceblue.com/nexus/content/groups/public/</url>
    </repository>
</repositories>
<dependencies>
    <dependency>
        <groupId>e-iceblue</groupId>
        <artifactId>spire.doc.free</artifactId>
        <version>5.1.0</version>
    </dependency>
</dependencies>
```

### 2. 公式サイトよりJarファイルをダウンロード

まず、[Free Spire.Doc for Java](https://jp.e-iceblue.com/download/free-spire-doc-for-java.html) の公式サイトよりzipファイルをダウンロードします。zipファイルを解凍し、libフォルダの下にあるSpire.Doc.jarファイルを依存関係としてプロジェクトにインポートしてください。

## Word文書内の空白行や空白段落を削除する

Word文書中の空行を削除するには、**Section**クラスのオブジェクトの文字列を取得し、それが空であるかどうかを検出する必要があります。そして、空文字列を持つオブジェクトを削除します。

> **詳細な手順は以下の通りです。**

- **Document** クラスのインスタンスを作成します。
- **Document.loadFromFile()** メソッドでWord文書を読み込みます。
- **Section.getBody().getChildObjects().remove()** メソッドで段落が空白かどうかを検出し、空白の段落を削除します。
- **Document.saveToFile()** メソッドでドキュメントを保存します。

**Java**

```Java
import com.spire.doc.Document;
import com.spire.doc.FileFormat;
import com.spire.doc.Section;
import com.spire.doc.documents.Paragraph;

public class removeEmptyLines {
    public static void main(String[] args) {

        //Documentクラスのオブジェクトを作成する
        Document document = new Document();

        //Word文書の読み込み
        document.loadFromFile("ドキュメント.docx");

        //文書内の空白行を検索して削除する
        for (Object sectionObj : document.getSections()) {
            Section section = (Section) sectionObj;
            for (int i = 0; i < section.getBody().getChildObjects().getCount(); i++){
                String s = ((Paragraph)(section.getBody().getChildObjects().get(i))).getText().trim();
                if (s.isEmpty()) {
                    section.getBody().getChildObjects().remove(section.getBody().getChildObjects().get(i));
                    i--;
                }
            }
        }
        String result = "空行の削除.docx";

        //ドキュメントを保存する
        document.saveToFile(result, FileFormat.Docx_2013);
    }
}
```

### 【結果のWordドキュメント】

![Word文書内の空白行や空白段落を削除する](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278784/bf994d51-410b-bbe4-2ed5-e8cd753e01ab.png)
 
> **この記事では、Word文書内の空白行を削除する詳細を表示します。もし何か質問があったり、無料のSpire.Doc for Javaについてもっと知りたい場合は、[Spire.Doc Forum](https://www.e-iceblue.com/forum/spire-doc-f6.html)に移動してください。**
Pythonのリストに関する小技

Pythonのリストに関する基本的な操作(リストに要素を入れるなど)はできるようになったのですが、競プロではもっと簡潔な書き方をしている人が多いらしいことに気がつきました。
そこで、リストを簡潔に扱うコードや使いやすい小技を調べてまとめました。

# リスト内包表記

「〇〇の間」で「△△な操作を繰り返してリストに格納する」という処理を一行で書くための表記。

まずこういった処理をリスト内包表記を使わず書くと以下のようになる。

```python
list = []

for i in range(10):  # i が0-9の間
    i = i * 2  # iに2をかけるという操作
    list.append(i)  # 処理を行ったiをリストに加える

print(list)  # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
```
このコードでは10回操作を繰り返してリストに入れるまで3行使っている。

しかしリスト内包表記を使うことにより、以上を1行でまとめることができる。

```python
list = [i * 2 for i in range(10)]
print(list)
```

# リストの最後の要素のみを取り出す 

```python
list = [1, 2, 3, 4, 5]
print(list[-1])  # 5
```

マイナスをつけると「最後の要素から何番目か」という意味になるらしい。例えば上記のコードで-2を指定すると4が表示される。

# listのカッコを外す

```python
list = [1, 2, 3, 4, 5]
print(*list) # 1 2 3 4 5
```

`*`をつけられているものはリスト扱いできないらしく`*list[0]`などとするとエラーが出る。

【以下コメントを受けての追記】

上記では`*`をつけることにより引数展開をしているらしい。
リストやタプルでは`*`を、辞書では`**`を用いる。

# リストに要素を追加する
appendを使わず、リストに要素を追加することが可能。

```python
list = [1, 2, 3]
list += [4, 5]
print(list)  # [1, 2, 3, 4, 5]
```

# 参考文献

かわさきしんじ. "［Python入門］リストの基本". 2019/05/31. https://atmarkit.itmedia.co.jp/ait/articles/1905/31/news015_4.html, (2022/11/22).

AI Academy運営事務局. "【初心者向け】Python リスト内包表記とは？わかりやすく解説！". AI Academy Media. 2022/04/05. https://aiacademy.jp/media/?p=1252, (2022/11/22).

"Pythonのリスト（list）の基本的な操作方法やメソッドの一覧をまるっと解説！". TRAINOCAMP. 2022/10/18. https://camp.trainocate.co.jp/magazine/python-list/#3 , (2022/11/22). 

"Pythonで関数の引数にリスト、タプル、辞書を展開して渡す". note.nkmk.me. 2021/09/17. https://note.nkmk.me/python-argument-expand/ , (2022/11/22).

かわさきしんじ. "［解決！Python］リスト（配列）の使い方まとめ". 2020/12/25. https://atmarkit.itmedia.co.jp/ait/articles/2012/25/news023.html#addbyops, (2022/11/22).
platformioの複数チップサポート

JJYSは余裕で16Kの168に収まるのでArduinoの328ではない、168でもビルドできるようにしてみました。

https://github.com/yamori813/JJYS

```
% pio run -e ATmega168
```

ターゲットは168PなのですがMsTimer2が168Pでコンパイルが通らないので、168にしてあります。

なぜか--target uploadでダウンロードが上手くいかず、ボーレートを遅くしましたら、うまくダウンロードできました。

テストはArudinoでして、実際には168で動かしています。

以前は328より安い168が秋月にあったのですが、もう無くなっています。
新しく参画したプロジェクトで導入したブランチ運用とCI・CDの紹介

最近会社で新しいプロジェクトにSREとしてジョインし、ブランチ運用やCI・CDを導入したので忘備録がてら紹介。

## 参画したプロジェクトとかに関して
今回ジョインしたのはサーバーサイドがRails、インフラがGCP、フロントはVueのプロジェクトです。自分がジョインした時点でCI・CDの仕組みはほぼ存在せず、ブランチ運用も特に定まってない状態でした。

## CIの導入
ここは至って普通なので軽く済ませますが、Github ActionsでRspecによる自動テストとrubocopによるコードチェックをPR作成時に走らせるようにしました。rubocopに関しては以下のActionsを使えばそれなりにリッチな仕組みが簡単に実現できるのでとても便利ですね。
https://github.com/reviewdog/action-rubocop

## ブランチ運用

### 基本はGitflow
基本的にはGitflowに近い運用を採用しました。ただし、厳密なGitflowは今回のチームでは大げさに思えたので一部簡略化してます。使うのは以下のブランチです。

- main
- develop
- feature/xxx
- hotfix/xxx
- qa

![gitflow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79302/a4fd8ba6-b053-96ac-a3a9-9b233102c8d6.png)


### releaseブランチは使わない
Gitflowではreleaseブランチを挟んでmainへのマージを行いますが、ここは省略してdevelopブランチを直接mainにマージする運用にしました。もう少し具体的に言うとdevelopからmainに向けたリリース用のPRを作成し、そのPRをマージすることでmainが反映されます。

このリリース用PRの作成には、[git-pr-release](https://github.com/x-motemen/git-pr-release)と言うOSSを使います。これをgithub actionsで動かすことで、以下のようにdevelopとmainの差分がまとまったPRがdevelopブランチ更新時に自動で作成されます。もちろんdevelopブランチが更新されるごとにPRも自動で更新されます。
![](https://cloud.githubusercontent.com/assets/113420/3147184/61bf2eec-ea53-11e3-835b-50d63ed11b39.png)


### 検証環境デプロイ用のQAブランチ

後述する自動デプロイ(CD)の仕組みを使って検証環境にデプロイするために使うブランチです。featureブランチからこのqaブランチにチェックアウトしてgithubにpushすることで検証環境にデプロイされます。

## 自動デプロイ(CD)に関して

### CloudBuildで各ブランチをTrigger
CDは全てCloudBuildで行なっています。以下のように各ブランチが動作環境に紐づいており、ブランチが更新されるとCloudBuildのTriggerが検知してデプロイが始まります。
- develop -> staging環境
- main -> 本番環境
- qa -> 検証環境

### docker buildにはkanikoを使う

RailsのAPIはCloudRunで動かすのですが、CloudRunに上げるDocker imageのbuildにはkanikoを使いました。
https://cloud.google.com/build/docs/optimize-builds/kaniko-cache?hl=ja
これを使えばとても簡単にdocker buildのキャッシュが利用できます。

```yaml
steps:
  - name: gcr.io/kaniko-project/executor:latest
    args:
      - --destination=${_IMAGE_NAME}
      - --cache=true
      - --cache-ttl=120h
```
また、この記述だけでArtifact Registryへのpushまで行ってくれます。

### DBのスキーマ更新はCloudRun Jobsで
Railsだと多くの場合DBのスキーマ更新のためにmigrateを行うことなると思いますが、この処理はCloudRun Jobsで実行しています。

```yaml
- name: "gcr.io/cloud-builders/gcloud"
  args:
    [
      "beta",
      "run",
      "jobs",
      "update",
      "migrate",
      "--project=${PROJECT_ID}",
      "--region=asia-northeast1",
      "--image=${_IMAGE_NAME}",
    ]
- name: "gcr.io/cloud-builders/gcloud"
  args:
    [
      "beta",
      "run",
      "jobs",
      "execute",
      "migrate",
      "--project=${PROJECT_ID}",
      "--region=asia-northeast1",
      "--wait",
    ]
```

1つ目のstepでjobのimageを更新し、2つ目のstepでjobを実行しています。

## まとめ
今回ジョインしたのは比較的小さいチームだったため、シンプルさを優先してCI・CDの仕組みを導入しました。今後チームが大きくなってきたら本格的なBranch環境の自動デプロイの仕組みや、slack opsも導入していきたいです。
htmlのテーブルをJavaScriptでTransposeする

https://stackoverflow.com/questions/6297591/how-to-invert-transpose-the-rows-and-columns-of-an-html-table

```javascript
targetTable = $0; // 対象のテーブルElement

// 配列に詰め替えつつTransposeする
ar2 = [];
Array.from(targetTable.querySelectorAll('tr'), tr => 
  Array.from(tr.querySelectorAll('td,th'))).map((td, x) => {
    td.map((tr, y) => {
      ar2[y] ? 0 : ar2[y] = []; // eq) ar2[y] ??= [];
      ar2[y][x] = tr.cloneNode(true); // xyを逆にすることでtransposedになる
    });
  }
);

// 詰め替え済みの配列をテーブル化する
newT = document.createElement('table');
ar2.map(tr => {
  nr = document.createElement('tr');
  newT.appendChild(nr);
  tr.map(td => {
    nr.appendChild(td);
  });
});
targetTable.parentElement.appendChild(newT);
// targetTable.display='none';
```

# 余談
`x ??= y` というのを「Null合体代入」と言う(MDN)ようだ。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_assignment

xが[nullish(MDN)](https://developer.mozilla.org/ja/docs/Glossary/Nullish)(null、undefined)のときだけ代入する。
配列の空要素(未代入)を指定して取得したときの値も`undefined`になる(?)ためか、この場合も代入が動作する。
配列の空要素(`k=[]; のときの k[0] とか、 t=Array(1); のときの t[0] とか。`)の話、MDNには出てこないけどね。

こいつそもそも名前持ってないのかしら。不便なんだが。

>これは配列の中で存在しない要素、すなわち以下の要素に対しては呼び出しません。
>設定されたことがない添字
>削除された要素
>値を割り当てられたことがない要素

となってるやつなのだけども。

~~[英語のMDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)だと「visited」とか書いてやがる。ﾅﾝｼﾞｬｿﾘｬ~~

`"empty slots"`だってさ

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Indexed_collections#sparse_arrays

> But in others (most notably array iteration methods), empty slots are skipped.

これか
【C#】名前空間とは？

# 一言で言うと
ファイルを整理する(見やすくする)為に、フォルダを分けること(本棚のようなもの)
プログラミング的にはクラスを種類ごとに分けて管理するためのもの。


       ①using System.Collections;
       ②using System.Collections.Generic;
       ③using UnityEngine;
初めから記載されているこれらは、名前空間である。
①②はC#の名前空間、③はunityの名前空間

ポイント
using＝省略する

↓どちらも同じ意味
```
パターン１
System.Console.WritrLine("Hello World");

パターン２
using System;
Consol.WritrLine("Hello World");
```

インスタンス生成
名前空間.クラス　変数名　＝　new 名前空間.クラス();
IntelliJ IDEA で FTP サーバに接続する方法

### 0. 前確認
- `Preferences... > プラグイン` より「[FTP/SFTP/WebDAV Connectivity](https://plugins.jetbrains.com/plugin/13125-ftp-sftp-webdav-connectivity)」が有効化されていること（デフォルトで有効）

![スクリーンショット 2022-11-22 12.01.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488859/06f17c65-565d-f1f4-01be-b62c9738ed71.png)

### 1. FTP サーバ構成の追加
`Preferences... > ビルド、実行、デプロイ > デプロイ` の「＋」より FTP サーバ構成を追加する。

追加の際必要な情報は下記。
- ホスト名
- ポート番号（デフォルトは 21）
- ユーザ資格情報（ユーザ名とパスワード）

![スクリーンショット 2022-11-22 12.02.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488859/a9e41d48-0241-4447-4a98-4807051ff04c.png)

https://pleiades.io/help/idea/creating-a-remote-server-configuration.html

### 2. Remote Host ビューの表示
`ツール > デプロイ > リモートホストの参照` より 1. で作成した構成を選択する。
 
これで FTP サーバを自由にブラウザできるようになりました！ IntelliJ IDEA の可能性は無限です。

![スクリーンショット 2022-11-22 12.07.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488859/31442dbf-3580-4c6c-8f6f-7b840f8103ab.png)
【C#】foreach文を使えるようになる

# 初めに
foreach文はループ文の中でも少し難しいらしい。
初心者はfor文で十分なんて書いてある記事も。。。

# foreach文とは
for文のように繰り返しループ処理をする。
for文に比べて簡潔に記述することが出来る。
配列等にアクセスして要素を取り出すのに使う。


# 構文
```
(foreach基本構文)
foreach(データ型 変数名 in コレクション)
{
//処理内容
}

(for基本構文)
for(回数を格納する用の変数 = 始まりの値; 繰り返しが続く条件; カウントアップする数)
{
//処理内容
}

for(int i = 0; i < コレクションの要素数; i++) {
//処理内容
}
```
# コレクションとは
配列などのオブジェクトの集まりのこと。 コレクションの要素をループごとに順番に変数に代入して、ブロック内で変数を使った処理をする。


# foreachとfor文の違い
__for文__
   条件が成立するまで繰り返す。
__foreach文__
   指定したコレクションから要素を1つずつ取り出してコレクションの要素数分だけ繰り返し実行。

・for文はiの定義やインクリメントをするのに対して、foreach文は不要である。
・foreachはループ終了のための条件判定式がない(無限ループされない)。

# foreachとfor文の使い分け
　　すべての要素分を1回ずつ処理したい→foreach文が適する。
　　　(最後の要素の処理が終わればループを抜けてくれる為)
　　指定した要素分だけ処理したい→for文が適する。
　　　(要素数を都度指定できる為)

# 最後に
foreachが簡潔に記述出来るからと言って、全てforeachで書けば良いというわけてはない。
(近しいもののようで全くの別物)
forとforeachを使い分けることが大切。


### 合わせて読みたい記事
if,for文の文法と真偽値,演算子について

https://qiita.com/hanatan079/items/01530bc45bab85f3d19f
LINEログインしてUIDを取得

## LINEログインしてUIDを取得

```html
<div id="liffInfo"></div>
<script charset="utf-8" src="https://static.line-scdn.net/liff/edge/versions/2.1.14/sdk.js"></script>
<script>
var myliffId = "xxxxxxxxxx-xxxxxxxx";
//document.addEventListener("DOMContentLoaded", function() {
function line_login() {
          liff
            .init({
                liffId: myliffId,
            })
            .then(() => {
                // ログインまだ
                if (!liff.isLoggedIn()) {
                        liff.login();
                } else {
                        // 通知用UID
                        document.getElementById("liffInfo").innerHTML = "あなたのLINE通知用番号は<br>";
                        document.getElementById("liffInfo").innerHTML+= liff.getContext().userId;
                }
            })
            .catch((error) => {
                console.log(error)
            })
}
//});
</script>

<button onClick="line_login();">LINEログイン</button>
```
プログラミング初心者がOSS-DB silverに合格した方法

## OSS-DB Silver試験とは

>下記のスキルと知識を持つエンジニアであることを証明する。
RDBMSとSQLに関する知識を有する。
オープンソースデータベースに関する基礎的な知識を有する。
オープンソースを利用して小規模なデータベースの運用管理ができる。
オープンソースを利用して小規模なデータベースの開発を行うことができる。
PostgreSQLを使ったデータベースシステムの運用管理ができる。
PostgreSQLを利用した開発でデータベース部分を担当することができる。

引用：https://oss-db.jp/outline/silver#about_silver


## 前提
・プログラミング初心者
・資格取得の3か月前から業務でSELECT文のみ使用
・PC系の資格はMOS スペシャリストのみ
・記憶力悪め


## 使用教材
・OSS教科書 OSS-DB Silver Ver2.0対応（通称緑本）
・Ping-t 最強WEB問題集OSS-DB Silver(Ver2.0)：https://ping-t.com/
（・SQLBOLT：https://sqlbolt.com/）
（・Youtube）


## 勉強方法

1. Youtube
SQLはなんのために使うのか、どんなことができるのかなど、
SQLについての知識が本当に皆無だったので、YoutubeでSQLについての動画を
何本かみて、SQLについて学びました。
これは資格の勉強に向けてではなく、業務でSELECT文が必要になったので
勉強しました。


2. SQLBOLT
SQLBOLTなら環境を構築しなくても自分が打ったSQLでテーブルがどのように動くか
確認ができるのでおすすめです。
ここまでで、SQLについての表面的な知識がつきました。


3. OSS教科書 OSS-DB Silver Ver2.0対応
緑本は約3周しました。
各セクションごとに練習問題がついているので、
1セクション読み終わったらとりあえず練習問題を解きました。
1周目と2周目は上記の方法でこなし、3周目は2周目で間違えた問題だけを
解きなおしました。
それでも間違えた問題は後日解きなおし、正解するまで
繰り返しました。
緑本についている模擬試験は、試験2週間前くらいに解きました。
その時点で半分以下の点数でしたが、模擬問題は難しいと信じて
あまり気にしませんでした。


4. Ping-t 最強WEB問題集OSS-DB Silver
Ping-tは、通勤時間や待ち時間などに活用しました。
セクションごとに不正解がなくなるまで全問解きました。
Ping-tには緑本に記載されていない問題も多数出題されるので、
毎回解説を読みました。
全500問くらいです。




## 試験結果
スコア：66点（合格ライン： 64 点）
結果：合格

試験中はそこそこ手ごたえを感じていましたが、ぎりぎりの合格でした(-.-)


## 感想
勉強を始めたばかりの時は緑本の内容がすべて呪文に思えていましたが、
YoutubeをみたりSQLBOLTをこなして、理解できるようになってきたのが
嬉しかったです。

試験勉強の反省点としては、全体的にフィーリングで覚えている感じだったので、
単語を一つずつ書き出してしっかり意味を理解するような勉強法が
私には合っていたかもしれないと思いました。

さらに、SQLを勉強したことによって、プログラミング言語やマークアップ言語
に対して感じていた高い壁が低くなり、html、css、javascriptにも興味がわいたので、
勉強しています。
kintoneにストリーミング用DASHプレイヤーを実装する

kintoneのレコードにソラカメのストリーミング映像を再生する為、DASHプレイヤーを実装しました。
一先ず、再生するところまで・・・


## 大まかな手順
* フィールドへの実装
* JavaScript / CSSでカスタマイズ

## フィールドへの実装
フォームには２点のフィールドを配置します。
* スペースフィールド：フィールドコード[dash]
* リンクフィールド：フィールドコード[url]

![dash1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532964/bd95a25f-5299-09b5-b9cd-6342fa24fd1b.jpeg)

## JavaScriptのカスタマイズ
JavaScriptのカスタマイズでは以下の２点を設定します。
dash.jsの実装はCDNを設定しております

![dash2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532964/29064564-3906-88ee-5c6c-4aaeb169c5a4.jpeg)

* dash.all.min.js(CDN)
  http://cdn.dashjs.org/latest/dash.all.min.js
* test_dash.js 
```test_dash.js
(function() {
  'use strict';

  const test = function(event) {
    kintone.app.record.getSpaceElement('dash').innerHTML = '<video data-dashjs-player="" autoplay="" width="800" height="600" src=' + url + ' controls="true"> </video>';

      var video,
          player,
          url= event.record.url.value;

      video = document.querySelector('video');
      player = dashjs.MediaPlayer().create();
      player.initialize(video, url, false);

  };

  const eventslist = [
    'app.record.detail.show'
  ];
  kintone.events.on(eventslist, test);
})();
```

videoタグでリンクフィールドの動画をスペースフィールドに埋め込んであげます。
コツはvideoタグで動画設定後に初期化を行う事ですね。

## 動画再生
test_dash.jsではリンクフィールドにMPDファイルのURL若しくはダウンロードURLを設定し、レコード詳細画面を表示するとストリーミング動画が再生されます。
今回はDASH.jsのサンプルページのMPDファイルを設定してます。

![dash3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532964/438e72e7-ecc6-59e9-6375-adfa9b10de43.jpeg)


## 参考ページ
https://www.gotop.co.jp/kintonesi20211216/
https://github.com/Dash-Industry-Forum/dash.js.git
http://reference.dashif.org/dash.js/latest/samples/
PythonでModuleNotFoundErrorが出た時の対処

# はじめに
Anacondaで環境を構築し、作成先のディレクトリを変更した際に遭遇した事象についてです。
ライブラリをインストールしているはずなのに、「ModuleNotFoundError」が出てしまうという事象で、それの解決方法を記載します。

# 事象発生前にやっていたこと
まず、以下の流れで環境構築を行いました。
① Anacondaの仮想環境作成先ディレクトリを「C:\work\Python\envs」
② 作成したディレクトリに仮想環境「C:\work\Python\envs\getAmazon」を作成
③ プログラムファイル保存先として「C:\work\PRG\Python\getAmazon\src」を作成
④ VSCodeで②で作成した環境を使用するようにし、「print('Hello')」が出力されるところまで確認
⑤ 「conda install selenium」でseleniumをインストール
⑥ 「from selenium import webdriver」を記述したソースを実行
　→ここで「ModuleNotFoundError」が発生。。。

# 原因の調査
１．import文の前に「import sys;print(sys.prefix);print(sys.path)」を追加して実行してください。
```python
import sys;print(sys.prefix);print(sys.path)
from selenium import webdriver
```
Pythonはライブラリインポート時に、ある順番でそのライブラリを探しに行くそうで、参照先がこれで確認できます。


２．出力結果の中に仮想環境作成先のディレクトリが含まれているか確認してください。
　今回の場合「C:\work\Python\envs\getAmazon\Lib\site-packages」にseleniumがインストールされているので、
　そのパスが含まれている必要があります。
　今回は、このパスが含まれていなかったため追加をする必要がありました。

# 対策
１．PYTHONPATHの追加
　環境変数に、seleniumがインストールされているパスを設定します。
　今回の場合「C:\work\Python\envs\getAmazon\Lib\site-packages」を追加します
|変数  |値  |
|---|---|
|PYTHONPATH  |C:\work\Python\envs\getAmazon\Lib\site-packages  |

２．Anacondaとエディターの再起動
　Anacondaとエディター(VSCodeを使用)の再起動をしてください。
　再起動後、該当ファイルを実行するとエラーが解消されているはずです。

# 参考サイト
https://engineerblog.mynavi.jp/technology/python-path/
paiza.ioでelixir その90

# 概要
paiza.ioでelixirやってみた。
練習問題やってみた。

# 練習問題
散布図を描画せよ。

# サンプルコード

```


IO.puts """
<!doctype html>
<html>
<head>
<style type="text/css">
* {
  margin: 0;
  padding: 0;
  border: 0;
}
body {
  background: #fdd;
  font: 30px sans-serif;
}
</style>
</head>
<body>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<div id='chart'></div>
<textarea id="koko0"> 
"""
for i <- 0..100 do 
    v = :math.sin(i * 440.0 * 2.0 * :math.pi / 20000.0);
    IO.puts(v)
    IO.puts ","
end
IO.puts """
</textarea>
<script type="text/javascript">
google.load("visualization", "1", {
    packages: ["corechart"]
});
var x0 = document.getElementById('koko0').value;
var x = x0.split(",");
var res = [['x', 'sin'],];
for (var i = 0; i < 100; i++)
{
    res.push([i, x[i] / 1]);
}
google.setOnLoadCallback(function() {
    var data = google.visualization.arrayToDataTable(res);    
    var options = {
        title: 'sin波',
        hAxis: {
            title: 'x'
        },
        vAxis: {
            title: 'y'
        }
    };    
    var chart = new google.visualization.ScatterChart(document.getElementById('chart'));
    chart.draw(data, options);
});
</script>
</body>
</html>
"""

```

# 実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/0eda0a0d-67c1-1f8b-b850-ddef0bd8d43c.png)


# 成果物

https://paiza.io/projects/Lb2IjDzuYddY2u-YH-Jp2A


以上。
Vue-Multiselectを使ってみた

実務で使うことがあったので自分用でメモ。

## 選択肢に画像付きで表示させる
https://vue-multiselect.js.org/#sub-custom-option-template

```vue: index.js
<template>
	<div>
	  <label class="typo__label">Custom option template</label>
	  <multiselect
		v-model="value"
		placeholder="選択してください"
		label="title"
		track-by="title"
		:options="options"
		:custom-label="customLabel"
		:show-labels="false"
        :searchable="false"
		:allowEmpty="false"
	  >
	    <template slot="singleLabel" slot-scope="props">
    	  <img class="option__image" :src="props.option.img" alt="props.option.img">
		  <span class="option__title">{{ props.option.title }}</span>
		</template>
	    <template slot="option" slot-scope="props">
    	  <img class="option__image" :src="props.option.img" alt="props.option.img">
    	  <span class="option__title">{{ props.option.title }}</span>
    	</template>
	  </multiselect>
	</div>
</template>

<script>
import Multiselect from 'vue-multiselect'
export default {
  components: {
    Multiselect
  },
  data () {
    return {
      value: { title: '', img: '' },
      options: [
        { title: 'ooo', img: 'XXX.png' },
        { title: 'ooo', img: 'XXX.png' },
        { title: 'oooo', img: 'XXX.png' },
      ]
    }
  },
  methods: {
    customLabel ({ title }) {
      return `${title}`
    }
  }
}
</script>
```

## オプション設定

- `:options="options"` 選択肢の中身を指定
- `:show-labels="false"` 選択肢内に選択済みか未選択かを文字で表示させないようにする
![スクリーンショット 2022-11-17 23.51.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982279/7976e026-68d7-426a-dee6-c8032b938d7e.png)

- `:searchable="false"` 検索機能を使わない
- `:allowEmpty="false"` 1つを必ず選択するようにする
- `:custom-label="customLabel"` 選択肢内で表示する文字をカスタム

## その他

今回はVue2で書きましたが、Vue3にも対応してるっぽい事書いてあって試してみたけど上手く動きませんでした。
個人的にはスタイルも変えられる設定があったらいいな〜と思いました。
公式ドキュメントには他にもカスタムできる設定が書いてあるのでぜひ見てみてください。
算術演算

# 各プログラミング言語の算術演算

加減乗除の四則演算は大概同じなのですが、剰余が演算子が異なったり、インクリメント、ビット演算の有無などが演算子に影響を与えているパターンがあるので、個人的に整理しておきたいな・・・と。
作成当初は、標準的な関数なども示そうと記載しておりましたが、標準的という言葉自体に個人差があることから、取り消し線を入れさせていただきました。
誤植や追記がございましたら、ご連絡お願い致します。

|プログラミング言語|加算（和）|減算（差）|乗算（積）|除算（商）|除算（商:整数値のみ）|剰余（余）|べき乗<br>(累乗)|インクリメント|ビット演算|
| :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
|Excel | + | - | * | / |   |~~MOD()~~|^<br>~~POWER()~~ |無|有|
|VBA   | + | - | * | / | \ |~~MOD()~~|^<br>~~POWER()~~ |有|有|
|VB.net| + | - | * | / | \ |~~MOD()~~|^<br>~~POWER()~~ |有|有|
|C     | + | - | * | / |   | %   |~~math.hのpow()~~|有|有|
|C++   | + | - | * | / |   | %   |~~math.hのpow()~~|有|有|
|C#    | + | - | * | / |   | %   |~~Math.Pow()~~   |有|有|
|Java  | + | - | * | / |   | %   |~~Math.pow()~~   |有|有|
|PHP   | + | - | * | / |   | %   | **          |有|有|
|Python| + | - | * | / |// | %   | ** |無|有|

コメントアウトに//を用いないPythonは、//で整数値のみの商を求める演算子に用いていたり、
ビット演算に英単語 XORなどを用いているVB系は^演算子を累乗に用いていたり、
プログラミング言語内のどこかで用いているどうかが影響している。
時代の変化で不要になる条件分岐処理

# はじめに

この前、社内営業向け勉強会のアイスブレイクで以下のような出題をしてみました。

:::note info
太郎くんは２００円持っています。
自動販売機で１２０円のジュースを買おうとしています。
そのジュースは売り切れではありません。
２００円を入れましたがボタンを押しても反応しません。
何故でしょうか？
:::

私の準備していた回答は

:::note info
自販機の中におつりが足りてなかった
:::
というものになります。

30代以上の人は正解していたのですが、何故か20代の人は回答を聞いてもピンとこなかったようです。
（個人的には定番的な問題だと思ってましたが。。。）

# 気づき
簡易な自動販売機の仕組みをフローチャートにすると以下のようになります。
（実際はもっと複雑です）
![フローチャート（過去）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43851/b862752d-c782-16cc-3163-b9190aa41ef1.png)
この **「自販機内に適切なおつりが存在するか？」** が時代の変化で不要になってきてます。
![フローチャート（名前） .png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43851/f322f245-8b54-0067-9153-6b0bd974c5bb.png)

それは **電子マネーの登場** です。

電子マネーでの決済であれば、おつりを現金で受け取るという事がありません。そもそもおつりという概念すら無くなってしまいます。

**もしかしたら若い人は自販機でおつりを受け取るという機会が少ないから私の準備した回答にたどりつかなかったのかもしれません。**

# 考察
新たにソフトの設計をする際、定番の処理が今でも必要かどうか考慮する必要がありそうです。
過去の遺産のような無駄な条件分岐とか差し込むと **「老害エンジニア」** と言われそうです。。。

# 最後に
この例以外、その他にも時代の変化や技術の進歩で不要になったロジックが存在しそうで、オジサンエンジニア（私も）はお茶をすすりながら妄想してみるのもおかがでしょうか（笑）
![computer03_ojisan.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43851/d3269ff9-0760-7f64-d425-13cd562260b9.png)
Salesforce認定Platformアプリケーションビルダー試験の公式サンプル問題解説してみた-12

こんにちは

Salesforce認定Platformアプリケーションビルダー試験の公式練習問題があるのはご存じでしょうか。
Trailheadにフラッシュカードとして何度も解ける練習問題がございます。

https://trailhead.salesforce.com/ja/content/learn/trails/platform-app-builder-certification-prep



今回は

Platform アプリケーションビルダー試験に向けた学習
認定 Platform アプリケーションビルダー資格の受験準備: Data Modeling and App Deployment (データモデリングとアプリケーションリリース)
ビジネスロジックとプロセス自動化の復習

にある問題1問目をご紹介します

なお今回の内容は動画でも公開しております

https://www.youtube.com/watch?v=3psOWJUPvWA

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


![0001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/1041b203-69f4-de95-8a58-210060bcaedc.png)


正解はAです


こちらのヘルプをご確認ください

https://help.salesforce.com/s/articleView?id=sf.approvals_processing_approval_requests_parent.htm&type=5

Bについて
システム管理者まで権限は不要です

Cについて
メール対応承認　という権限はございません

Dについて
メールの承認　という権限はございません
Rakeタスクのdescに実行例を書いてちゃんと活用する

仕事でRuby on Railsを使っていて、Rakeタスクもよく使っている中で、
実行例もコマンドで確認できるようにした話です。

## Rakeタスクとは
Rubyで書かれたコードをタスクとして作成しておき、必要に応じて呼び出し実行できる機能です。

https://opiyotan.hatenablog.com/entry/rails-rake-task

## 実行コマンド忘れる問題
Rakeタスクの種類が増えてくると、Rakeコマンドで実行する際に、正しいコマンド名や引数の渡し方などを毎回忘れてしまうという問題が出てきました。
```ruby
namespace :hoge do
  # 実行例： bundle exec rake 'hoge:fuga[1, 10, 20, 30]'
  desc 'ほげほげする'
  task :fuga, %i[hoge_id] => :environment do |_, args|
   # 処理
  end
end
```
こんな感じでコード内にコメントで実行例が記述されていたりはしたのですが、毎回Rakeファイルのコードを探すのが煩わしく、実行例もCLI上で確認したいという気持ちが湧いてきました。


## そういえば`desc`って何のためにあるの？
新しくRakeタスクを書くときは、なんとなく他に習って何をするタスクかを`desc`に記述していたのですが、
コード上で直接読む以外に活用したことがありませんでした。
何かしら用途があるだろうとRakeコマンドのヘルプを表示させてみるとこんなオプションを発見しました。
```
    -D, --describe [PATTERN]         Describe the tasks (matching optional PATTERN), then exit.
```
つまり
```
bundle exec rake -D hoge
```
というコマンドを打つと
```
rake hoge:fuga[hoge_id]
    ほげする
```
というように`[PATTERN]`名が部分一致したタスクについて、タスク名とともに`desc`で添えた説明の一覧が表示されます。
他にも`-T`オプションでdescを記述しているタスク一覧を表示できたりします。

## `desc`に実行例も書けばコマンドで確認できるじゃん！
ということで`desc`に実行例も書けば`-D`オプションで表示させられることがわかりました。

## `desc`を複数行表示させるには?
タスク自体の説明と実行例など、複数行で表示させるにはどうするのが良いのでしょうか。
### 試み1: `desc`を複数書く -> 🙅
```ruby
namespace :hoge do
  desc 'ほげほげする'
  desc "実行例： bundle exec rake 'hoge:fuga[1, 10, 20, 30]'"
  task :fuga, %i[hoge_id] => :environment do |_, args|
   # 処理
  end
end
```
#### 実行結果
```
rake hoge:fuga[hoge_id]
    実行例: bundle exec rake 'hoge:fuga[1, 10, 20, 30]'
```
こんな感じで2つ以上`desc`を記述した場合は後に書いた`desc`で上書きされてしまいます。
### 試み2: 改行コード`\n`でつなぐ -> 🤔
```ruby
namespace :hoge do
  desc "ほげほげする\n実行例： bundle exec rake 'hoge:fuga[1, 10, 20, 30]'"
  task :fuga, %i[hoge_id] => :environment do |_, args|
   # 処理
  end
end
```
#### 実行結果
```
rake hoge:fuga[hoge_id]
    ほげする
    実行例: bundle exec rake 'hoge:fuga[1, 10, 20, 30]'
```
これならうまくいきます。けどコードは読みにくくなりますね。

### 試み3: ヒアドキュメントを使う -> 🙆
Rubyには複数行の文字列を定義する方法として、ヒアドキュメントという記述方法があります。

https://docs.ruby-lang.org/ja/latest/doc/spec=2fliteral.html#here
```ruby
namespace :hoge do
  desc <<~DESC
    ほげする
    実行例: bundle exec rake 'hoge:fuga[1, 10, 20, 30]'
  DESC
  task :fuga, %i[hoge_id] => :environment do |_, args|
    # 処理
  end
end
```
#### 実行結果
```
rake hoge:fuga[hoge_id]
    ほげする
    実行例: bundle exec rake 'hoge:fuga[1, 10, 20, 30]'
```
開始ラベルを`<<~識別子`とすることで、最もインデントが少ない行を基準に、
全ての行の先頭から空白を取り除いてくれます。
これによりコード上のインデントを無視できます。
これならコードも読みやすく、説明を追加したいときも拡張しやすいですね！
Python/Anacondaで仮想環境の作成パスを変更

# はじめに
Anacondaを利用してPythonの環境構築するにあたり、パスを変更してみました。
その際にちょっとつまった点があるので、そのまとめになります。
※Anacondaはインストールされている前提です。

# 仮想環境作成パスを変更
作成パスは環境変数を変更するだけでOKです。
※今回は「C:\work\Python\envs」に作りたいと思います。

|変数  |値  |
|---|---|
|CONDA_ENVS_PATH  |C:\work\Python\envs |

これで仮想環境は、指定したパスに作成されるようになります。

ちなみに、VSCodeで仮想環境を指定する際は、画面右下部分をクリックすると変更できます。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1008719/70c5335a-89ef-f011-abe1-b29af527603a.png)


# PYTHONPATHの設定
先ほどの変更のみで簡単なソース程度なら実行できますが、まだ少し足りません。
このままだとライブラリをimportした際に「ModuleNotFoundError」が出てしまいます。
参考：[PythonでModuleNotFoundErrorが出た時の対処](https://qiita.com/namakemono_no_ahiru/items/f266aed7da9096adf637)


以下のパスは「getAmazon」という仮想環境を構築した際のパスの例です。

|変数  |値  |
|---|---|
|PYTHONPATH  |C:\work\Python\envs\getAmazon\Lib\site-packages |

これでimportも正常に動作するようになります。
以上で終わりです。