OmniAICreator/Qiita-1.07M huggingface dataset:
[備忘録] AzurePipelineで使える変数

# はじめに

`$(Build.ArtifactStagingDirectory)`とか`$(Build.BuildId)`とか
いつもなんやこれって思ってた。

# predefined variablesという名前らしい

ここに一覧載ってる。

https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml

日本語版はこちら

https://learn.microsoft.com/ja-jp/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml

# おまけ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647946/0a2702a3-4f67-61da-5212-ba449a0912c9.png)

リンク先ページの関連ファイルはPipeline yamlを書く上でかなり役立つので一読されたし。

## たとえば自分で変数を定義する方法とか

この例は変数を変数に入れ直してるだけだが・・・

```yaml
variables:
  - name: branchName
    value: $(Build.SourceBranchName)

steps:
  - task: PublishBuildArtifacts@1
    displayName: 'Publish Artifact'
    inputs:
      PathtoPublish: '$(Build.ArtifactStagingDirectory)/$(branchName)-$(Build.BuildId).zip'
      ArtifactName: 'Artifact_sample'
      publishLocation: 'Container'
```
[UE5] World Outliner上のフォルダのリストを取得する方法について（おまけ付き）

# はじめに
突然ですが、**World Outlinerにおけるフォルダのリストを欲しくなったことはありませんか？**
僕はあります。今回はその取得方法についてご紹介します。C++が必要ですがサクッとできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363889/1d1f5826-019a-dc5c-2606-b6dad7ee6571.png)
# C++コード
フォルダの取得には、```FActorFolders```の```ForEachFolder```関数を使用します。少し見慣れない書き方になっていますが、これは```TFunctionRef```というものを使っているためです。

https://qiita.com/ykobayashi0/items/4ece218f74316232e7eb

```cpp:MyEditorBlueprintFunctionLibrary.cpp
#pragma once

#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "MyEditorBlueprintFunctionLibrary.generated.h"

UCLASS()
class ●●●●EDITOR_API UMyEditorBlueprintFunctionLibrary : public UBlueprintFunctionLibrary
{
	GENERATED_BODY()

	UFUNCTION(BlueprintCallable)
	static TArray<FName> GetActorFolderNames(UWorld* World, bool bUseSort);
};
```

```cpp:MyEditorBlueprintFunctionLibrary.h
#include "MyEditorBlueprintFunctionLibrary.h"
#include "EditorActorFolders.h"

TArray<FName> UMyEditorBlueprintFunctionLibrary::GetActorFolderNames(UWorld* World, bool bUseSort)
{
	TArray<FName> OutActorFolderNames;

    // 全フォルダ（FFolder）に対してForEach処理を実行
	FActorFolders::Get().ForEachFolder(*World, [&OutActorFolderNames](const FFolder& Folder)
	{
		OutActorFolderNames.Add(Folder.GetPath());
		return true;
	});
	if(bUseSort)
	{
		OutActorFolderNames.Sort();
	}
	return OutActorFolderNames;
}
```
なお、上記のコードはエディタ専用の機能を使っているため、Editorモジュールで組むことを強く推奨します。Editorモジュールの作成方法については下記記事を参考にするか、

https://historia.co.jp/archives/3097/

https://qiita.com/unknown_ds/items/0e271b947cf05d281480

こちらの無料プラグインを使うのがオススメです。サクッとモジュールを追加できるので重宝してます。

https://www.unrealengine.com/marketplace/ja/product/c-module-generator

話を戻して…
これで作成した```Get Actor Folder Names```ノードを下記のように組んで実行すると…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363889/d199e479-58bc-f35c-27d3-8861d2830844.png)
結果は以下のようになります。ちゃんと取れてますね！
```
LogBlueprintUserMessages: [XXX] A
LogBlueprintUserMessages: [XXX] B
LogBlueprintUserMessages: [XXX] B/B-Child
LogBlueprintUserMessages: [XXX] C
```

# 応用例
これだけだと微妙なので、具体的にどんなことに役立つのかについて軽く…

まず、Actorの```SetFolderPath```ノードを使うとそのActorを特定のフォルダに移動することができます。ここでのフォルダとは当然World Outlinerでのフォルダを指します。そして、その```SetFolderPath```ノードと今回ご紹介した内容を併用すると…**特定のフォルダ名が見つかったらそこに選択中のActorを移動させる**という処理を組めます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363889/9abfae28-1940-ea48-9030-4f323893d858.png)

これだけだと特に使い道はないですし、標準のMove To機能でいいじゃん！となりますが、

https://historia.co.jp/archives/17047/

例えば…
- 複数のActorを特定のルールに基づいて一括でフォルダ移動・整理
- レベル上に特定のActor・BPを配置したら自動的に最適なフォルダに移動

といったエディタ拡張を組むことができます。どうでしょ？便利そうじゃないですか？

# さいごに
開発規模が大きくなるに連れてWorld Outliner上のActor数は膨れがちです。更に、UE5のWorld Partitionを活用していくとUE4時代とは比にならないぐらい膨れることもあります。そんなときに今回の内容がきっと役に立つはずです。是非一度試してみてください！

おしまい
【9月28日無料】【ゲーム開発会社・パブリッシャー様向け】Cocosテクノロジー主催、REALITY社、Live2D社、Digital Will社登壇ウェビナーのお知らせ

![cocos_webinar4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852397/1425b23c-3c9d-b8ed-2c67-511d8467c43d.jpeg)

Cocos2dxでお馴染み、オープンゲームエンジン開発会社Cocosが2022年9月28日（水）日本時間15：00～16：30に、開発会社様、パブリッシャー様を対象に無料のオンラインウェビナー開催を予定しています。是非ご参加いただけますと幸いです。

■ウェビナー概要■
最新のCocos Creatorゲームエンジンの概要をご説明させていただくと共に、ゲストにREALITY株式会社、Digital Will株式会社、株式会社Live2D様をゲストにお招きし、事例や最新提携サービス/プラットフォームのご紹介をさせていただきます。Cocos本社よりCTOも参加するため、Cocos関連の技術的なご質問等もお答えさせていただきます！

・タイトル：【開発会社様・パブリッシャー様向け】Cocos Creator 3.6　最新事例・最新提携サービス＆プラットフォームのご紹介
・日時：2022年9月28日（水）15:00～16:30 日本時間
・費用：無料
・形式：オンラインセミナー
・参加者：**参加の可否を[こちらのリンク](https://docs.google.com/forms/d/1Y6pe8jSwBvpIJqBIN_67flPie6LZjv63nhJOdlDp-0k/viewform?edit_requested=true)よりご記入ください。**

ゲーム開発会社様、パブリッシャー様、10数社様に限定してお声がけさせていただいておりますが、もし他にもご参加されたい会社様等ございましたらお気軽にお声がけくださいませ。各会社様からの人数制限等はございません。

※本セミナーはZoomを使用したオンラインセミナーです。 インターネット環境があるご自宅などからご参加ください。
※セミナー参加用ZoomのURLは、前日までにお申し込み時にご登録いただいたメールアドレスにお送りいたします。

■登壇者■
Cocos テクノロジー　
CTO Huabin Ling
Business Development Director Antonio Florez
日本市場担当　芳賀友絵

＜ゲスト＞
REALITY株式会社
春山一也　氏

Digital Will株式会社
Co Founder, CEO
ウィル・ボン　氏

株式会社Live2D
Cubismグループ SDKチームリーダー
伊東拓也　氏

＜注意事項＞
・本セミナーはZoomを使用してオンラインにて開催します。Zoomは、Zoomの規約に同意の上でご自身の判断で使用してください。
・お申込者には登録のメールアドレス宛に、本セミナーのURL・ID・パスワードを連絡します。
・Cocosテクノロジー（以下「主催者」）では本セミナーの録画を行い、主催者の記録の管理及びサービス向上のため利用します。
・参加者による本セミナーの録音・録画及びこれらの公開はお止めください。
・本セミナーのプログラム及び登壇者は変更となる場合があります。
・本セミナーでは、主催者は申込みやアンケートの際に個人情報を収集し、以下の目的で利用します。必須登録項目にご登録いただけない場合、本セミナーに参加できない場合があります。なお、登壇者には個人情報の共有はいたしません。

＜利用目的＞
・本セミナーの開催に関するご連絡のため
・主催者のサービスの向上のため

＝＝＝Cocosテクノロジー社について＝＝＝
Cocosは中国にあるオープンゲームエンジン開発会社で、Cocos2dというHTML5/ウェブに特化したエンジンが最も有名ですが、中国ゲーム市場ではこのエンジンのシェアが65％以上になります。日本でもスクウェア・エニックス, GREE, LINE等数多くのパブリッシャー様がお使いになられています。また、ゲームのみにとどまらず、教育関連ツールやプログラムにも多く使用されています。
無料のソフトウェアですので、クリック一つで簡単に使用可能、また、ご使用に際して、弊社の技術担当からトレーニングを提供させていただいたり、ワークショップなどを開催させていただき、実際の開発に密着・協力させていただきます。
＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝

是非ご参加いただけますと幸いです。

芳賀
日本市場ビジネス担当
https://www.cocos.com/en
単体テストのコード設計を考える

# 背景
テストコードはあってもどのようなケースを想定しているのかわからない。
少しでも頑張らなくて良くなるテストコードとなる様にはどうすれば良いかを検討している。
※これは検討中のメモです
※コードは適当です(動きません)

# 課題
1. どんなケースを想定したテストなのかがわからない
2. 十分なケースかわからない
3. 愚直過ぎて解析が辛い

# 解消案検討

## 1. どんなケースを想定したテストなのかがわからない

### 詳細
- テストケースの説明がない or 情報が不十分
    - コードを解析しないといけない

### 検討案
- docにケースの説明を記載する
```java
/**
 * 説明: xxx
 * 設定値: yyy
 * 期待値: zzz
 */
@Test
public void testXXX() {}
```


## 2. 十分なケースかわからない

### 詳細
- テストケースの全量がない
    - 全てのケースを解析するしかない

### 検討案
- テストコード設計しましょう
  **※方針は検討中**
- コード中にテストケースのサマリを記載する

## 3. 愚直過ぎて解析が辛い

### 詳細
- 各テストメソッドで、モック作成・期待値作成・テスト対象実行・アサーションなどなどほぼ全てをやっている

### 検討案

- テストメソッドは、テスト対象実行とアサーションを役割とさせる
    - モックや期待値などのデータは外部に任せる
    - アサーションはオブジェクト単位で実行する
```java:HogeTest.java
class HogeTest {
    @Test
    public void success_XX取得 {
        /* データ生成 */
        Fixture fixture = Fixture.BASIC;
        TargetStruct expected = fixture.getExpected();
        
        /* テスト実行 */
        Hoge hoge = new Hoge();
        TargetStruct actual = hoge.getXX();
        
        assertEquals(expected, actual);
    }
}
```

```java: Fixture.java
/**
 * データパターンはここで定義する
 *  →expected だけだが、必要な情報は増やしていく
 * データを定義するのはモデル側に任せてしまう
 *  →状況に応じて面倒な処理をここに定義してもOK
 */
public enum Fixture {
    BASIC(ExpectedStructA.class);
    
    @Get
    private TargetStruct expected;

    private Fixture(Class expected) {
        this.expected = new expected();
    }
}
```

```java: ExpectedStructA.java
/**
 * クラスが増えるけど許容する
 *  →どこかで面倒なことをしないといけないので、ここに集約する
 */
public class ExpectedStructA extends TargetStruct {
    public void ExpectedStructA() {
        this.id = 1;
        this.name = "hoge";
    }
}
```

## 番外

### 検討案
- テストメソッド命名規則
    - [success|failure]_(日本語で説明)
        - ex) success_対象データが1件
- privateメソッドのテストケース実施を許容
    - 規模にもよるが楽になるなら全然OK
gitの"origin"とはなんなのか

はじめに
--
下記のコマンドを叩くことが何度もありますし、今後もたくさんあると思います。
無意識に"origin"という文字列をここで使っていますが、そもそもoriginとは何かよく分かってなかったので、簡単に自分の学びとしてまとめようと思います。

~~~
git remote add origin <リモートレポジトリのURL>
git push origin <ブランチ名>
~~~

originはリモートリポジトリの名前
---

> $ git remote add origin https://github.com/schacon/simplegit-progit
>上記のコマンドを実行すると、リポジトリの.git/configファイルにセクションが追加され、リモートの名前 (origin)、リモート リポジトリの >URL、およびフェッチに使用されるrefspecが指定されます。

[gitの公式ドキュメント](https://git-scm.com/book/en/v2/Git-Internals-The-Refspec)に上記のように記載されています。
ここに書いてあるように、"origin"はリモートリポジトリのデフォルトの名前なんですね。

"origin"というデフォルトの名前に、自分が変更内容を反映させたいリモートレポジトリのURLを"remote add"コマンドで設定しているということだと理解しました。

そして設定後にoriginを用いてpushをすると、"git remote add"で設定したリモートレポジトリのurlに変更内容を反映させてあげられるということみたいです。

gitは深いところまでまだ全然理解できてないなと感じました。
ちょっとずつ気になることを調べていこうと思います。

参考
--
https://git-scm.com/book/en/v2/Git-Internals-The-Refspec
一時ディスクのないAzure RHEL VMの起動が遅い

# SSHで接続できるようになるまで約3分かかる
一時ディスクなしのマシンサイズでRHEL VMを作ってみたところ、VM起動後3分程度経たないとSSHで接続できないという事象に遭遇しました。
事象が発生したのはRHEL7.6です。

### そもそも一時ディスクあり・なしとは
Azureの仮想マシンサイズには世代があり、v3まではスワップファイルを配置するための一時ディスクが標準でついていました。一方でv4以降は一時ディスクありタイプと一時ディスクなしタイプに分かれています。一時ディスクの目的もスワップファイルを配置するためではなく、データベースの一時領域等消えてもいいけどパフォーマンスが必要な用途に変わっています。実際、ディスクサイズはスワップファイルを置くだけだと大きすぎるサイズ感になっています。また、一時ディスクありを選択すると課金額が増えます。スワップファイルのためだけに一時ディスクありを選ぶのはコストの観点からよくありません。
現在v5まで出ていて、最新世代のマシンサイズを選択した方がコストパフォーマンスはよいので、今回一時ディスクなしタイプの「D2s v5」を選択してRHELを作ってみたところ、この事象にハマりました。

# 起動時のログを確認
ブート診断で使うストレージアカウントをカスタムストレージアカウントにするとシリアルコンソールが使えます。
シリアルコンソールで起動中のログを観察します。すると処理に時間がかかっている箇所で以下のログが出ていました。

> cloud-init[1607]: 2022-09-21 12:39:16,655 - DataSourceAzure.py[WARNING]: ephemeral device '/dev/disk/cloud/azure_resource' did not appear after 120 seconds.

存在しない一時ディスクを120秒間待機しているようなログに読み取れるので、明らかにこれがあやしいです。

# 原因と対処方法
出ているログから検索すると、まさにこの事象に関して記載しているMicrosoftのページが見つかりました。
**[Cloud–init-enabled VM takes a long time to start up](https://learn.microsoft.com/en-us/troubleshoot/azure/virtual-machines/cloud-init-deployment-delay)**

### 原因
> During VM startup, cloud-init runs the DataSourceAzure.py file in Python, and then waits for the local ephemeral disks (/mnt/azure_resource) to become available. Because you're using an Azure VM that doesn't have local ephemeral disks, cloud-init must wait until the process times out. The timeout interval for ephemeral disks is 120 seconds before the startup process continues.

存在しない一時ディスクを120秒間待機する処理が入っていることがやはり原因のようです。
cloud-initを使うものでは同様の事象が起こりうるようなので、他のLinuxディストリビューションでも発生するのではないかと思います。

### 対処方法１：cloud-initのバージョンを上げる
> Upgrade your copy of cloud-init to version 21.2 or a later version.

これは他への影響度が読めなかったので今回は試していません。

### 対処方法２：待機時間を短縮する
以下のコマンドを実行することで待機時間が2秒になります。
~~~
sudo sed -i 's/maxwait=120/maxwait=2/g' $(locate DataSourceAzure.py)
~~~

実際にこちらを試してみたところ、起動後SSHが接続できるようになるまでの時間が30秒程度に短縮されました。

# まとめ
今回の事象は既存のOSイメージが一時ディスクなしの構成を元々想定していないことに起因しているのではないかと思います。今後の新しいLinuxイメージでは新しいcloud-initが搭載されて事象が起こらなくなるのではないかと推測されますが、一時ディスクなしのマシンサイズを使う場合、しばらくは上記のどちらかの対応が必要ですね。

## 追記
バージョンごとの事象発生有無を検証してみました。結果、**RHEL8.1以降では発生しない**ことが確認できました。
RedHat社発行の公式イメージ「Red Hat Enterprise Linux」からバージョンを選択してデプロイしています。
VMの世代はGen2を指定しています。このイメージはLVM構成になります。

| RHELバージョン | cloud-initバージョン | 事象発生有無 |
|:-:|:-:|:-:|
| 7.6  | 19.4  | 発生する |
| 7.7  | 18.5  | 発生する |
| 8.0  | 入っていない？<br>cloud-initコマンド自体が実行不可  | 一時ディスクなしだと<br>そもそもVMデプロイが終わらない  |
| 8.1  | 21.1-7.el8_5.3    | 発生しない |
| 8.2  | 21.1-7.el8_5.3    | 発生しない  |
| 8.4  | 21.1-7.el8_5.3    | 発生しない  |
| 8.6  |  21.1-15.el8_6.3  | 発生しない  |
macOS Montereyに移行した際の問題と解決法

macOS Montereyに移行して、XcodeをインストールしてからHomebrewをインストールしようとすると以下のエラーが...


```
sh: line 1: 11955 Abort trap: 6           /Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk -find git 2> /dev/null
git: error: sh -c '/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk -find git 2> /dev/null' failed with exit code 34304: (null) (errno=Invalid argument)
xcode-select: Failed to locate 'git', requesting installation of command line developer tools.
```
おまけに入れたはずのXcode command line toolsのインストールを要求され、それに従ってインストールを行い、それが終了した後にHombrewのインストールを試すと、同じメッセージとXcde command line toolsインストールの繰り返しの無限ループにハマりました。

ググったところ、以下のスレッドで解決方法が紹介されていました。

https://developer.apple.com/forums/thread/666584

以下のコマンドを実行してパスを切り替えると良いようです。
```bash
sudo xcode-select -switch /Library/Developer/CommandLineTools
```
これでHombrewのインストールを行うことができました。
【Git】特定のコミットまで戻る

# はじめに
Gitを使い始めて5ヶ月くらい経ちました。
割と成長したと思ってます。

「やばい、動かない！」
「3個前のコミットまで戻したい。。。」

こんなことありますよね

# やりかた
```:ターミナル
git reflog
```
戻りたいコミットを探します。
見つけたら左に表示されているIDをコピーします。
![スクリーンショット 2022-09-21 21.26.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/1b3d0633-d345-8aab-5dbc-347d60dfaf74.png)

今回は`c1de7e53`でした
```:ターミナル
git reset --hard c1de7e53
```

戻れた！

# おわり
Gitで操作間違えた時まじ焦ります
【画像付き】VScodeでSassの設定手順

## ①VScodeでSassの導入
拡張機能で「Live　Sass Compiler」と検索し、
↓の拡張機能をインストールします
![kakutyou.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784679/b6e4f970-6962-d451-9606-7acb3bd7abe4.png)
## ②Sass利用準備
フォルダ内にSassファイル用のフォルダとSassファイルを作成します
![sassファイル構成.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784679/57a8ac74-51c4-d2cf-47f1-595ff34a9f57.png)
## ③Sassのコンパイラを起動する
VScode下部のWatch Sassをクリックする
![watchi.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784679/23640670-9056-a35d-d154-f4fb415b4e83.png)
下のようなパネルが出て「Watching...」になれば完了です
![表示.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784679/75d40656-018b-917c-e3d5-a3c01d56f424.png)

## ワークスペースで書き出し設定
ワークスペース内にこのように記述を追加します
今回は通常CSSと圧縮CSSを出力させました
記述したら保存します
![set.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784679/7430a621-a757-eda1-302e-6a3ebfce4c5e.png)
## 設定ができているか確認
CSSフォルダにCSSファイルが生成されていたら完了です
![表示1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784679/8f14f42b-7772-edd6-e732-fb8e31e7525e.png)
[Rails 5.1] 複数の小モデルを跨いだor検索

バージョンの問題で5.1.以下の複数の小モデルを使ったor検索の実装方法があまり載っていなく少しでも役に立つかもと思ったので投稿します。
もっと良い書き方があれば教えていただきたいです。

## 学んだこと
・includeを使うと小モデルのオブジェクトを親クラス内から使えるということを学びました。
```
Child.include(:parent）.is_summer_vacation
```
・idを使ってor検索を実装すること(rails5.2からは.[or()](https://qiita.com/YumaInaura/items/c4ea8271f5793962a26d)を使っていけるかも）
## 環境
Rails 5.1.6.2
Ruby 2.5.0


### DB
```book.rb
has_one: business #ビジネス書
has_one: novel #小説
has_one: comic #漫画
```

### 複数の小モデルを跨いだor検索
本の検索サービスにおいてアメトークで紹介された本を絞り出すという状況を想定して実装コードを紹介します。
```Book.rb
def book_search(status)
 if status == "ametolk"
  # statusがametolkのparamsがリクエストされた時
   business_book_ids = Business.includes(:book).where(is_introduced_ametalk: true).
   pluck(:book_id).uniq
   novel_book_ids = Novel.includes(:book).where(is_introduced_ametalk: true).
   pluck(:book_id).uniq
Book.where(id: business_book_id + novel_book_ids)
  elsif
  .
  .
  end
end
```

scopeを使ってあげるとちょっとスッキリ書けます。

```user.rb
scope: business_ametalk, -> { Business.includes(:book).where(is_introduced_ametalk: true)}
scope: novel_ametalk, -> {  Novel.includes(:book).where(is_introduced_ametalk: true)}


def book_search(status)
# statusがametolkのparamsがリクエストされた時にor検索をする
  if status == "ametolk"
      business_book_ids =  Book.business_ametalk.pluck(:book_id).uniq
      novel_book_ids = Book.novel_ametalk.pluck(:book_id).uniq
      Book.where(id: business_book_ids + novel_book_ids)
  elsif
  .
  .
  end
end
```

## 参考記事

https://qiita.com/YumaInaura/items/c4ea8271f5793962a26d

https://qiita.com/rised/items/3d4cffe82ac46ee445ea
Rails 7 + ImportmapでFont Awesomeを実装する

# FontAwesome
アイコンを使うのに[FontAwesome](https://fontawesome.com/)というライブラリーはすごくいいだけど、インストールするには公式サイトにこれしか書いてなかったからインストールに詰まりました。
```shell
# npm
npm install --save @fortawesome/fontawesome-free

# yarn
yarn add @fortawesome/fontawesome-free
```

これだけだとアイコンは表示されないし、フレームワークごとのインストール方法は書いてなかったからちょっと調べてみたら、YouTubeの[この動画](https://www.youtube.com/watch?v=c-EbQDB0RsQ)を見つけてFontAwesomeをけっこう簡単に実装できたのでやり方をこちらにも書いときます。

そもそもImportmapの使い方は知らなかったのが詰まる原因だったと思うんで反省していますが、とにかく実装できたのですっきりしました。

# パッケージマネジャーでインストールした後に...
上記の`npm`か`yarn` コマンドでパッケージをインストールしたら、ターミナルで次のコマンドを打ちます
```shell
./bin/importmap pin @fortawesome/fontawesome-free
```

筆者の場合は多少時間かかったけど、次のメッセージが出力されました。
```
Pinning "@fortawesome/fontawesome-free" to https://ga.jspm.io/npm:@fortawesome/fontawesome-free@6.2.0/js/fontawesome.js
```

# importmap.rbを編集する
`importmap.rb`に次の行ができるはずです。バージョンは違うものになるかもしれないので注意してください。
```ruby:importmap.rb
pin "@fortawesome/fontawesome-free", to: "https://ga.jspm.io/npm:@fortawesome/fontawesome-free@6.2.0/js/fontawesome.js"
```

最後の`fontawesome.js`を`all.js`に変えます。
```ruby:importmap.rb
pin "@fortawesome/fontawesome-free", to: "https://ga.jspm.io/npm:@fortawesome/fontawesome-free@6.2.0/js/all.js"
```

# JavaScript
最後は`app/javascript/application.js`に`fontawesome`を`import`します
```js:app/javascript/application.js
// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
import "@hotwired/turbo-rails"
import "controllers"
import "@fortawesome/fontawesome-free" // これです
```

# 以上！
好きなアイコンを選んで画面に表示しましょう
```html
<i class="fa-brands fa-github"></i>
```
![Screenshot from 2022-09-21 21-02-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74313/d0cd8935-988f-f7aa-9360-1f5b91548519.png)
Ubuntu22.04でスクリーンショットの保存先を変更する

22.04からデフォルトでは`~/Pictures/Screenshots`にスクリーンショットが保存されるようになった。
20.04までのようにスクリーンショットアプリを`gnome-screenshot`に変更する事で保存先を変更できるが、22.04のデフォルトアプリを使いたいが保存先を変更したい場合の回避策。

1. ディレクトリ`~/Pictures/Screenshots`を削除する
2. シンボリックリンクを作成する。 `ln -s /path/to/save_dir ~/Pictures/Screenshots`


参考
https://askubuntu.com/questions/1408611/changing-the-auto-save-directory-for-screen-shots-and-screen-cast-in-ubuntu-22-0
Ruby3.1を触ってみる(IRB のオートコンプリートとドキュメント表示)

# 0. はじめに
[前回](https://qiita.com/Satoooon/items/2412e9ba6de1f3afefb1) に引き続きRuby 3.1の新機能について動かしながら紹介しようと思います。

今回は IRB のオートコンプリートとドキュメント表示 になります。
irb自体はRubyを触っていれば簡単な動作確認したりと誰しもが使ったことがあるものだと思います。
それの拡張された機能になります。早速みていきましょう！

# 1. リリースノートを見てみる
> IRB にオートコンプリート機能が実装され、コードを入力するだけで補完候補ダイアログが表示されるようになりました。Tab と Shift+Tab で上下に移動できます。
また、補完候補を選択している時に、ドキュメントがインストールされている場合、補完候補ダイアログの横にドキュメントダイアログが表示され、内容が一部表示されます。Alt+d を押すことでドキュメント全文を読むことができます。

引用: https://www.ruby-lang.org/ja/news/2021/12/25/ruby-3-1-0-released/

# 2. 触ってみる

## 2-1. 基本的な挙動
- irbの実行は今まで通り `irb` 叩けばOK

- 以下の画像の通りにコードを入力しているとダイアログが表示されます
![スクリーンショット 2022-09-21 18.32.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/226348/33bde832-b97f-c3cc-589d-a2b2c0a66080.png)

- 補完ダイアログは `tab` で↓移動。　`shift+tab` で↑移動してコードの補完を行います
![スクリーンショット 2022-09-21 18.33.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/226348/7657866f-618f-03fa-2e57-815fe31a71ba.png)

- 標準搭載のクラスメソッドや予約語だけでなくあらかじめ自身で定義したメソッドや変数も補完してくれるようになります
![スクリーンショット 2022-09-21 18.39.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/226348/85068a2b-cfc7-700e-cbaf-307ffc3f63f5.png)

## 2-2. ドキュメントの全文表示

- ダイアログの中にはドキュメントが書かれているものも存在します
![スクリーンショット 2022-09-21 19.08.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/226348/270446db-6506-48b6-917b-903f5d49758f.png)

- その項目の上で `Alt+d` をすると全文表示できます(`q` で抜ける)
![スクリーンショット 2022-09-21 19.08.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/226348/49d2eed1-da1c-c263-0dc4-d4ddf2eceefe.png)

# 3. ダイアログ表示できるようになったけれど・・・

個人的所感ですが、使ってみてリッチになったように見える反面以下が気になりました

- 結局ダイアログでtab押し続けて補完はほとんどしなそう
  - 上の例を見て頂けるとわかりますが、 `hoge` というメソッドは4文字、　tabキー押して補完するのも結局4回キーを叩いているのであまり差がないです
  - ↑の例は極端ですが、普段から使っているメソッドとかは指が覚えているので補完するまでもないよなって感じなので利用頻度は少ないかなと感じました
- 補完したくなくてもダイアログが出てくるので画面がずれる
  - 以下のように前に入力していた結果がダイアログのせいでずれてしまうことが発生しました。ダイアログがこちらの補完したくないときにも表示されてしまいかえって邪魔になってしまうこともあるかもしれません
![anime.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/226348/3195c824-7410-21b3-5281-5892e3e611c6.gif)

# 4. オートコンプリートを無効化したいときは

じゃあどうすれば良いかというと以下の２パターンのいずれかでオートコンプリートを無効化することで回避することができます

[1] `--noautocomplete` オプションをつけてirbを起動する
- irb オプションにてダイアログの非表示をするオプションを実行すればOK


```bash
$ irb --noautocomplete
```

[2] .irbrc に環境設定する
- [1] だと毎回オプションをつけないといけなくなるのでダイアログ非表示にする私用頻度が高い場合はirbの設定ファイルを作成 or 編集することでモーダル表示の設定をオフにしてオプションなしでも非表示にすることができます

```.irbrc
IRB.conf[:USE_AUTOCOMPLETE] = false
```

いずれかの対応を行えば以下のようにダイアログが表示されなくなります！

![スクリーンショット 2022-09-21 19.56.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/226348/ddabecfc-466f-1de7-cd96-485bf80899a3.png)

# 5. 最後に

今回は IRB のオートコンプリートとドキュメント表示 について紹介しました。
良い機能でありながらも不要であればカスタマイズしたりとする機会が増えそうな気がします。
自身に合った .irbrc ファイル作って良いirbライフを送りたいですね！
Xcode14.0でiOS15.7の機器にアプリをビルド・インストールする方法

# はじめに
<!-- 発端や概要を記載 -->
先日Xcodeをバージョン14.0にアップデートしたところ、デバッグ用に使っていた端末(iPhone6s)でアップデートできる最新バージョン(iOS15.7)にXcodeが対応しておらず、ビルドをしようとすると、
"This operation can fail if the version of the OS on the device is incompatible with the installed version of Xcode. You may also need to restart your Mac and device in order to correctly detect compatibility."
(デバイスのOSバージョンがインストールされているXcodeのバージョンと互換性がない場合、この操作(ビルド)は失敗します。互換性を感知するためにはMacと端末の再起動を行ってください。)

と出るようになりました。ちなみに再起動をしても現象は変化しません。そもそも互換性がないからです。

# 目次
<!-- タイトルとアンカー名を編集 -->
1. [Xcodeの対応iOSバージョンを確認してみる](#Chapter1)
1. [iOS15.7のサポートファイルをダウンロード](#Chapter2)
1. [iOS15.7のサポートファイルを解凍・移動](#Chapter3)
1. [参考文献](#reference)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# ①Xcodeの対応iOSバージョンを確認してみる
互換性がないことを確認してみましょう。
ターミナルを起動して
`cd /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/`
を実行。移動したら
`ls`
でDeviceSupportディレクトリの中身を確認してみましょう。

私の環境では
`11.0	11.4	12.3	13.2	13.6	14.2	15.0	15.6
11.1	12.0	12.4	13.3	13.7	14.3	15.2	
11.2	12.1	13.0	13.4	14.0	14.4	15.4	16.0
11.3	12.2	13.1	13.5	14.1	14.5	15.5`
と表示されました。どうやら15.7はないようです。
<a id="#Chapter2"></a>
# ②iOS15.7のサポートファイルをダウンロード
https://github.com/JinjunHan/iOSDeviceSupport
から15.7対応のサポートファイルをダウンロードすることができます。

<a id="#Chapter3"></a>
# ③iOS15.7のサポートファイルを解凍・移動
ダウンロードしたzipファイルを解凍し、
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/
ディレクトリに移動しましょう。これでビルド、アプリインストールがiOS15.7のデバイスにできるようになります。

<a id="#reference"></a>
# 参考文献
- [Looking for iOS 15.7 support files for XCode14](https://stackoverflow.com/questions/73721778/looking-for-ios-15-7-support-files-for-xcode14)
外部Webサーバーにある画像ファイルをプログラミングレスでリサイズする

# はじめに

外部のWebサーバー(というかIPカメラ)がCGIを持っており、

```
http://ID:PASS@globalipcam:51234/path1/path2/snap.jpg
```

というURLでスナップ画像が取得できる。

この時ダウンロードできた画像ファイルの解像度は WQHD（2560x1440）。ちょっと大きめ。

![変換前.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1236186/c11c71d8-858e-7886-b26a-dc159891603d.png)

このスナップ画像を定期的に取得してVGAで保存したい要件が出てきた。

以下の記事でNginxの設定だけでグローバルIPアドレスを取得する方法を記載したが、画像ファイルのリサイズも似たような方法で実現できないだろうか？と思い立ち調べてみた。

https://qiita.com/SECUAL_masa/items/a7a96499718bb4a9f0e2

# 環境

お試し環境は以下の通り。

| 環境 |
|:-:|
| Ubuntu 20.04.5 LTS  |
| Nginx 1.18.0  |

* 必要なNginxモジュールは「libnginx-mod-http-image-filter」だったが「インストール済み」になっていたので、標準で入るモジュールなのかもしれない。

# 結論

以下の設定だけで実現できた。

## /etc/nginx/sites-enabled/default

```Text:vi /etc/nginx/sites-enabled/default
upstream globalipcam {
        server "globalipcam:51234";
}

# Default server configuration
#
server {
        listen 80 default_server;
        listen [::]:80 default_server;

        root /var/www/html;

        location /globalipcam_resize_snap {
            proxy_set_header Authorization "Basic SUQ6UEFTUw==";
            proxy_pass http://globalipcam/path1/path2/snap.jpg;
            image_filter resize 640 360;
            image_filter_jpeg_quality 80;
        }
}
```

# 説明

```
upstream globalipcam {
        server "globalipcam:51234";
}
```

* ポート番号が80以外の場合はupstreamを利用する必要がある模様。80なら次の「proxy_pass」だけで実現できる、と思う。


```
        location /globalipcam_resize_snap {
            proxy_set_header Authorization "Basic SUQ6UEFTUw==";
            proxy_pass http://globalipcam/path1/path2/snap.jpg;
            image_filter resize 640 360;
            image_filter_jpeg_quality 80;
        }
```

* IPカメラ側にBasic認証が施されているので「proxy_set_header Authorization」にて設定。
* 「proxy_pass」にある"globalipcam"は「upstream」の名前。
* 「image_filter」で必要なパラメータ値を指定。"crop"などもできる模様。

## URL

上記設定&reload後に、ブラウザから以下のURLにアクセスすると所望した解像度の画像ファイルが表示される。

```
http://local_nginx_server_ip/globalipcam_resize_snap
```

![変換後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1236186/10dea874-598d-23f7-d257-93ddda9381dd.png)


# 最後に

いやぁ～、Nginxってすごいですね。
Ubuntuのapache2.4でmpmをeventに変更する

# 概要
Apacheのmpm(Multi Processing Module)をデフォルトのpreforkではなくeventに変えてマルチスレッド化しようとしたときにハマったので備忘録として残しておきます。

# 環境
- OS: Ubuntu 20.04.4 LTS x86_64
- apache: 2.4.41
- php: 7.4.3

# phpについて
普通のphpだとmpmがpreforkに依存するので、php-fpmというものを導入します。
php-fpmの説明は割愛します。

```shell
sudo apt install php-fpm
sudo a2dismod php7.4
sudo a2enmod proxy_fcgi
sudo systemctl restart apache2
```
これでfpm版のphpが動きます。

# mpmの変更
```
sudo a2dismod mpm_prefork
sudo a2enmod mpm_event
sudo systemctl restart apache2
```
以上です。
使用中のmpm等は`apachectl -V`で確認できます。
IBM Cloud: ALB for VPCのsubnetを変更して再配置結果を確認してみた

# 1. はじめに

ALB for VPCを配置するsubnetを、プロビジョニング後でも変更できるようになった。これは、逆にいうと、ALBが既にZone1で動いていても、subnetを選択し直すことで、Zone2に再配置することができるということである。以下で実験してみた。
https://cloud.ibm.com/docs/vpc?topic=vpc-release-notes&locale=en#vpc-september2022


# 2. ALBのsubnetの変更

## 2-1. Tokyo1/Tokyo3 ZoneにALBが配置されている。
ALBに割り当てられているPublic IPが、`165.192.xx.xx`と`162.133.xx.xx`であることにも注意。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2746922/4934af74-6ec1-264c-35e7-4cf924774f56.png)


## 2-2. subnetの変更

上記画面で、`Edit Subnets`を押下すると、`10.0.0.0/24(Tokyo1)`と`10.2.0.0/24(Tokyo3)`がALBのsubnetの配置先として選択されていることがわかる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2746922/bdae4da8-575b-f4ba-2209-592d0add175f.png)

これを以下のように、`10.0.0.0/24(Tokyo1)`と`10.1.0.0/24(Tokyo2)`をsubnetの配置先として選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2746922/e4e66c5e-8558-304f-a24e-7faf47353327.png)


## 2-3. 再配置後の確認。
再配置には5-10分ぐらいかかった。

- `10.0.0.0/24(Tokyo1)`と`10.1.0.0/24(Tokyo2)`に変更された
- ALBに割り当てられているPublic IPも、`162.133.xx.xx`と`128.168.xx.xx`に変更されたことにも注意。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2746922/d9c2ed2e-73de-9d48-2ba4-ba3965caa618.png)


# 3. その他、いろいろ試してみて気がついた注意点

- ALBはデフォルトでは2インスタンス配置されている。よって、Tokyo1/Tokyo3のsubnetが既に選択されている状態で、3つ目のsubnetとしてTokyo2のsubnetを追加しても再配置が行われることはなかった。障害が発生した時や、負荷が増大した時には3つ目のsubnetも利用される可能性がある。
- subnetとしてTokyo1/Tokyo3が選択されていた状態から、Tokyo2のsubnetのみが選択されるように変更した場合、期待通り2つのインスタンスは全てTokyo2に再配置された。この状態で、Tokyo1/Tokyo2/Tokyo3のsubnetを選択しても、再配置されず2つのインスタンスはTokyo2で稼働しつづけた。こちらも、障害が発生した時や、負荷が増大した時にはTokyo1/Tokyo3のsubnetが利用される可能性がある。
【VSCode】Remote-Containersをコマンドで起動する方法

## はじめに
VSCode の Remote-Containers を使用して開発を行なっている際に一度 VSCode を開いて左下に表示される「Reopen in Container」をクリックして devcontainer を起動したりします。

![スクリーンショット 2022-09-21 17.30.35のコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/1c9e218b-0010-23ee-9572-62ae4fb2b94d.png)

この devcontainer の起動を　code コマンドのようにコマンドで行う方法について記載します。

## 起動方法
### devcontainer CLI をインストール

VSCodeのコマンドパレットで`Remote-Containers:Install devcontainer CLI`を実行し devcontainer CLI をインストールします。

![スクリーンショット 2022-09-21 18.42.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/e2569141-c7ea-1bde-9f26-bbce9fa31764.png)

これで以下のコマンドで devcontainer を起動できるようになります。

```zsh
devcontainer open 任意のパス
```

## 注意
上記でインストールした devcontainer　CLI は古いものです。
非推奨となっています。

https://www.npmjs.com/package/@vscode/dev-container-cli

新しい devcontainer　CLI は以下のリポジトリのものになります。

https://github.com/devcontainers/cli

ただし、新しい方は上記の`devcontainer open`コマンドは廃止されており、現状では使用できません。
Rで、文字列が中国語か日本語か、雑に判定する

# やりたいこと
<b>漢字だけの文字列</b>があった場合、それが日本語か中国語か、判定したい。
例えば、
1. 東京都千代田区富士見町（ただの住所）
1. 在東京都千代田區富士見町見面吧（中国語で、富士見町で会いましょう）    

について、<b>１は日本語に、２は中国語と判定したい。</b>

しかしRやPythonの各種の自動判定のパッケージでも、
「漢字のみテキスト」については日本語と中国語に分けるのは難しいらしく、
しばしば<b>１も中国語に判定されていまう。</b>

例えばRで代表的な言語判定パッケージのfrancでも、下記の結果となる。(cmnは中国語。whitelistにjpnと入れても駄目）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100646/99de58a8-4aab-26a6-5eb7-eb4a09ecb335.png)

困った。

# 雑な解決策
こちらの方のアイデアを拝借した。
https://qiita.com/ry_2718/items/47c21792d7bbd3fe33b9

中国語である　＝　簡体字や繁体字、つまり<b>日本語には存在しない漢字が使われている</b>
として、<b>文字列を日本語文字コードに変換したときに、文字が無くなる＝中国語である</b>
とするものである。

これをRで書くと、以下の通り。（utf-8でコーティングしている前提）
```R
iconv("東京都千代田区富士見町",from = "utf-8",to = "cp932")
iconv("在東京都千代田區富士見町見面吧",from = "utf-8",to = "cp932")
```
実行結果。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100646/8c84a461-38a8-8468-fb70-ef1afbe47d47.png)
「東京都千代田区富士見町」は簡体字や繁体字を含まないので、そのまま変換される。
つまり日本語である可能性が残る。
一方で「在東京都千代田區富士見町見面吧」は「吧」が日本語には存在しない文字なので、NAとなる。
つまり確実に中国語である。

# まとめ
上記の手法を使えば、francなどの言語判定パッケージで「中国語」と判定されたテキストについて、
・確実に中国語である文字列
・実は日本語かもしれない文字列
に分けることができる。
後者については、簡体字や繁体字を含まない中国語の文字列も存在するため、日本語であるとも言い切れないが、
実は日本語なのに、文章を誤って中国語と断定してしまうことは避けられる。

「中国語の文字列だけを除外して、日本語の文字列は極力残したい」といったような場合には
有効な手法と考えられる。

# 注意
対象とする文字列に、簡体字・繁体字以外にもiconvにかけるとNAになる文字、たとえばutr-8にしか存在しない絵文字などが入っていると
誤作動してしまうので、別途処理が必要。

# おわり
おわりです。お疲れさまでした。
Kotlinスコープ関数(let,run,also,apply)の使い方について考えてみる

## はじめに
Kotlinの標準ライブラリにはスコープ関数という関数が存在します。
自分自身、JavaからKotlinに入ったのでそれなりの文法などはすんなりと理解できたのですが、スコープ関数についてはJavaには無いので理解が薄いままなんとなくで使用していました。
今回理解を深めるために少し調べてみたので備忘録を含めまとめたいと思います。

## 5つのスコープ関数
Kotlinには5つのスコープ関数が用意されています。
- let
- apply
- run
- also
- with

これらの関数は、基本的に全て同じことを行いますが、それぞれ特徴がありますのでまとめます。
(`with`に関してはほとんど使用機会がありません(自分は)ので今回は割愛させていただきます。)

## let
まずは使用頻度の高い`let`
| スコープ関数名 | 対象オブジェクト | 戻り値 |
|:-----------|:------------|:------------|
| let       | it        | 最後の実行コード   |

```kotlin
    val foo: Int? = 3
    val hoge = foo?.let { it * 2 } ?: 0
    println("hoge : $hoge")
```
`let`は主にnullableな変数に対して使用する事が多く、nullチェックをスマートに記述することができます。

```kotlin
hoge : 6
```

fooがnullではない場合`let`スコープ内の処理が行われます( it * 2 )
fooがnullの場合エルビス演算子に処理が移り0が返ります。

```kotlin:従来のコード
    val foo: Int? = 3
    val hoge =
        if (foo != null) {
            foo * 2
        } else {
            0
        }
```
よくあるnullをif文でチェックして処理を分岐する簡単なコード。

```kotlin:スコープ関数使用
    val foo: Int? = 3
    val hoge = foo?.let { foo -> 
        foo * 2
    } ?: 0
```
スコープ関数を用いて記述するとこのようにスッキリ書けます。

```kotlin
    val foo: Int? = 3
    val hoge = foo?.let { foo ->
        foo * 10000
        foo * 20000
        foo * 0 // ←これが戻り値
    }
    print("hoge : $hoge")
```
冒頭でも説明したように`let`では`let`スコープ内で最後に評価した値が戻り値として返ります。

```
hoge : 0
```
`let`スコープ内で`foo`の値をどんだけ書き換えても最後の行の値が返されているのがわかります。

## run
runはletと似ています.
| スコープ関数名 | 対象オブジェクト | 戻り値 |
|:-----------|:------------|:------------|
| run       | this        | 最後の実行コード |

`run`と`let`の違いは対象オブジェクトを`this`で参照できる点です。また、Kotlinでは`this`は省略可能ですのでより簡潔に記述することが可能です。
```kotlin
    val hoge = foo?.run {
        toString() // this.toString()
    }
```

## also
| スコープ関数名 | 対象オブジェクト | 戻り値 |
|:-----------|:------------|:------------|
| also       | it        | 対象オブジェクト |

`also`は`let`や`run`と違い戻り値が対象オブジェクト自身です。
一つのオブジェクトに対してまとめて処理を実行した場合などに便利です。(AndroidだとViewの初期化処理等)

```kotlin:従来のコード
                     // ↓これが戻り値
        val testText = binding.testText
        testText.text = data.peekContent()
        testText.setOnClickListener{ } // クリック処理        
```

```kotlin:スコープ関数使用
                     // ↓これが戻り値
        val testText = binding.testText.also { 
            it.text = data.peekContent()
            it.setOnClickListener { } // クリック処理 
        }
```

## apply
| スコープ関数名 | 対象オブジェクト | 戻り値 |
|:-----------|:------------|:------------|
| apply       | this        | 対象オブジェクト |

`apply`は`also`の対象オブジェクトが`this`バージョンといった感じです。
```kotlin:従来のコード
    val intent = Intent(this, SubActivity::class.java)
    intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY	)
    intent.addCategory("test")
    startActivity(intent)
```
同じ記述(intent)が続くので無駄感がある。
```kotlin:スコープ関数使用
    Intent(this, SubActivity::class.java).apply {
        addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY	)
        addCategory("test")
        startActivity(this)
    }
```
スコープ関数を使用することでスッキリ書くことができます。
`apply`は対象のオブジェクト自身が戻り値になるので、 **startActivity(`this`)** と記述します。
## さいごに
Kotlinのスコープ関数についてまとめてみました。
実務ではまだ上手く使用できていませんが、便利に活用できたらなと思います。
また、スコープ関数の便利な使い方などあればコメント頂けると幸いです！！

ではまたっ！！
Firebaseの認証についてメモ書き

Firebaseの認証について色々調べる機会があったので、メモ書きですが残したいと思います。

## トークンは2種類
- FirebaseIDトークン(jwt)
    - 認証に使われる
    - 有効期限は1時間
- 更新トークン(refreshToken)
    - 新しいFirebaseIDトークンを発行するのに必要
    - 有効期限は無い

ユーザーを無効化や削除した時は更新トークンが無効になる。FirebaseIDトークンを即時無効にすることはできない。
FirebaseIDトークンの有効期限を待てない場合は、無効化したuidのブラックリストを作りセキュリティルールで弾く等の工夫が必要。


## フロントで検知する方法
`onAuthStateChanged`を使うとログイン、ログアウト、トークン更新時に処理を加えることができる
```js
firebase.auth().onAuthStateChanged((user) => {
  if (user) {
    // ログイン中
  } else {
    // 未ログイン
    // ex) ログインページに飛ばす
  }
});
```
似た関数で`onIdTokenChanged`があるが、4.0.0以前なら`onAuthStateChanged`と同じ動作になり、4.0.0からはログイン、ログアウト時のみ動作するので注意。

## firebase-functionsでの認証
`onCall`を使うとトークンの検証をやってくれる。`onRequest`はやってくれないので、自前でトークン検証を実装する必要あり。

#### onCallの検証について
| パターン | 結果 |
|:-:|:-:|
|トークン無し|  OK |
| 有効なトークン  |  OK |
|  無効なトークン(適当な文字列) |  NG |
|  期限切れトークン |  NG |

NGの場合はunauthenticatedを返して終了する。
トークン無しの時OKになることに注意。誰でもアクセスされると困る場合はonCallの第二引数のcontextのauthがundefinedなので、undefinedならunauthenticatedを返して終了するようにすればOK。

また、Firebaseエミュレータを使っている場合はトークンの検証はせず常にOKになるので注意。
該当するユーザーがいない場合、context.authは下記が返ってくる。
`{ uid: undefined, token: { uid: undefined } }`


##### 参考
https://firebase.google.com/docs/auth/admin/manage-sessions?hl=ja
https://firebase.google.com/docs/auth/admin/verify-id-tokens?hl=ja
https://firebase.google.com/docs/reference/js/v8/firebase.auth.Auth#onauthstatechanged
Databricksでファイル名を取り込む方法

## はじめに

Databricksでデータを取り込む際に、取り込み元ファイルの情報も取得する方法をまとめます。


### 非Unity Catalog環境


input_file_name()を使用します。

[pyspark.sql.functions.input_file_name](https://spark.apache.org/docs/latest/api/python/reference/pyspark.sql/api/pyspark.sql.functions.input_file_name.html)

```pyspark:pyspark

from  pyspark.sql.functions import input_file_name,current_timestamp
df = (spark
        .read
        .format("csv")
        .load(<ファイルパス>)
        .select("*"
            ,current_timestamp().alias("_ingest_timestamp")
            ,input_file_name().alias("_file_name")
        )
     )

```

こんな感じでとれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/38bd0240-fbbc-636b-92db-e96e9d2bcf01.png)


### Unity Catalog環境下

以下のようにサポートされない旨が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/92a5adc5-fdeb-73a5-e86d-ed5534e65f16.png)



[ファイル メタデータ列](https://learn.microsoft.com/ja-jp/azure/databricks/ingestion/file-metadata-column) という形で取得が可能です。

例：

```pyspark:pyspark

df = (spark
        .read
        .format("csv")
        .load(<ファイルパス>)
        .select("*","_metadata")
     )

```

こんな感じでとれます。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/8a0039ca-e08a-f3f6-7fd1-bcdf9b1ae409.png)

#### 追記

シングルユーザーモードであればUnity Catalog 環境でもinput_file_nameが動作しました。
autoloaderといい、pythonの関数はけっこうこういうのが多いみたいです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/b4b7932d-bdd4-fcad-c1f9-18285b0ea01f.png)
CloudFormationでCloudFrontからS3のアクセスを許可しているのにアクセスができない

# はじめに

CloudFormationを作成する際にリソースの設定がしっかりできているのになぜか設定が反映されていないという状況になりました

同じ現象で多くの時間を使う方が一人でも減ればと思います！

# 問題

CloudFront用のS3(CloudFormation)を作成しました
以下の部分でS3に対してCloudFrontからアクセスを許可するポリシーを作成しています

```yml:s3.yml
          - Action:
              - "s3:GetObject"
            Effect: Allow
            Resource: !Sub arn:aws:s3:::${BucketName}/*
            Principal:
              AWS: !Sub "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${CloudFrontOriginAccessIdentity}"
```

実際に作成したS3のポリシーは以下のようになっていました

```
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EMEJ8X2KE5E9G"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::test/*"
        }
```

CloudFrontには`EMEJ8X2KE5E9G`のアイデンティティを設定していることも確認できているのですが、なぜかCloudFrontにアクセスするとアクセス権限がなくエラーになってしまいます

# 解決方法

`!Sub`の書き方が原因でした

```yml:s3.yml
Resource: !Sub arn:aws:s3:::${BucketName}/*
↓
Resource: !Sub "arn:aws:s3:::${BucketName}/*"
```

としたところうまく動くようになりました。
S3のポリシー的には内容が変わらなかったのですが、内部的には`Sub`を使うときは文字列にしないといけなようです

# おわりに

なんとなくでCloudFormationを書いていたのでかなり原因に行きつくまで時間がかかりました
文字列にしなくても動くものも多く存在するまであまり意識せずにやっているので注意が必要です
【Github Action】Githubのmainブランチpush時にテスト環境に自動デプロイ

## 概要

テスト環境の中に入って、毎回pullしたり、キャッシュ削除したり、artisanコマンド打ったりが面倒なので
Githubアクションを使って実現してみました。

ステップ
1. テスト環境の公開鍵を GitHub リポジトリの Deploy keysに登録
1. テスト環境内にsshでリポジトリをclone
1. Secretsにサーバー情報などを登録
1. Workflow を作成する


## テスト環境の公開鍵を GitHub リポジトリの Deploy keysに登録

サーバーに上で認証鍵を作ります※メールアドレスは識別用
``ssh-keygen -t rsa -b 4096 -C [メールアドレス]``

公開鍵をコピーします
``cat ~/.ssh/id_rsa.pub``

リポジトリ内の``Settings``→ ``Deploy keys``→``Add deploy key``で、公開鍵を登録します。
> TitleはなんでもOK

## テスト環境内にsshでリポジトリをclone
httpsではなくsshでcloneします。

githubで自分のアカウントにssh設定を行なっていない場合は以下の記事から鍵の登録をしてから行いましょう。

https://qiita.com/shizuma/items/2b2f873a0034839e47ce

## Secretsにサーバー情報などを登録

リポジトリ内の``Settings``→``Secrets``→``Actions``→``New repository secret``から情報を登録します。

- SERVER_DEPLOY_DIR
    - プロジェクトのディレクトリパス(.envがある場所まで)
- SERVER_HOST
- SERVER_USERNAME
- SSH_PORT
- SSH_PRIVATE_KEY
    - 自分自身の秘密鍵(cat ~/.ssh/id_rsa)

を登録しました。

## Workflow を作成する

リポジトリ内の``Actions``→``Set up this workflow``からymlファイルを作成(名前はなんでもOK)

今回はpullからマイグレーション実行とキャッシュクリアのコマンドを登録します。
コマンドを追加したい場合はscriptの項目に加えましょう。

```yml
name: CI

on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Deploy
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USERNAME }}
          port: ${{ secrets.SSH_PORT }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          passphrase: ${{ secrets.SSH_PASS }}
          script: |
            cd ${{ secrets.SERVER_DEPLOY_DIR }}
            git pull origin main
            php artisan migrate:fresh --seed
            php artisan cache:clear
            php artisan config:clear
            php artisan route:clear
            php artisan view:clear
```

後は保存すればOKです。

アクションが行われるタイミングを変えたい時とかはワークフロー構文を漁ってみましょう

https://docs.github.com/ja/actions/using-workflows/workflow-syntax-for-github-actions
ＶＢＡでExcelのCSVへ分割出力

### 要件
Excelの整理したデータはでかい場合、何万件で分割出力する

### 分析
VBAで出力分のデータは別ブックに張り付け、そのままＣＳＶに保存する
入出力イメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/801991/65570848-89f8-1c16-3d75-b1303ebf3f87.png)

### 実装
```
Sub write2csvSep()

Dim wArr() ' write out csc arry

Dim i As Long
i = 3

'一万件の分で出力
csvSize = 10000

'name prfix
profixN = "来場202207-"


Set toSht = ActiveSheet


'columns number
jj = 1
While toSht.Cells(1, jj) <> ""
 jj = jj + 1
Wend
'項目の数
colSize = jj - 1

'CSVヘッダーは物理名と論理名が２行ある想定、最大200項目想定
Dim hArr(2, 200)

For ih = 1 To 2
 For jh = 1 To colSize
  hArr(ih - 1, jh - 1) = toSht.Cells(ih, jh)
 Next
Next

'ファイルカウント
fcnt = 0
ReDim wArr(csvSize, 200)
ii = 0

Application.DisplayAlerts = False

'３行目からデータ行
While toSht.Cells(ii + 3, 1) <> ""

  For j = 1 To colSize
   wArr(ii - fcnt * csvSize, j - 1) = toSht.Cells(ii + 3, j)
  Next j

  ii = ii + 1

 
  '出力の数になったら、出力する
  If Int(ii / csvSize) * csvSize = ii Then
     fcnt = Int(ii / csvSize)
     Workbooks.Add
     Set wb = ActiveWorkbook
     
     'ファイル名を指定
     fname = "c:\tmp\" & profixN & fcnt & ".csv"
     '文字型にする
　   'NumberFormatLocal = "@"
     wb.ActiveSheet.Cells.Select
     Selection.NumberFormatLocal = "@"

     wb.ActiveSheet.Cells(1, 1).Resize(2, 200) = hArr
     wb.ActiveSheet.Cells(3, 1).Resize(csvSize, 200) = wArr
     
     'FileFormatにUtf8の指定も可能
     wb.SaveAs Filename:=fname, FileFormat:=xlCSV, CreateBackup:=False
     wb.Close
     
     'メモリがリセット
     Erase wArr
     ReDim wArr(csvSize, 200)
  End If
   

 Wend
 
 '最後の部分を出力
 If Int(ii / csvSize) * csvSize <> ii Then
     fcnt = fcnt + 1
     Workbooks.Add
     Set wb = ActiveWorkbook
     fname = "c:\tmp\" & profixN & fcnt & ".csv"
     '文字型にする
　   'NumberFormatLocal = "@"
     wb.ActiveSheet.Cells.Select
     Selection.NumberFormatLocal = "@"

     wb.ActiveSheet.Cells(1, 1).Resize(2, 200) = hArr
     wb.ActiveSheet.Cells(3, 1).Resize(csvSize, 200) = wArr
     wb.SaveAs Filename:=fname, FileFormat:=xlCSV, CreateBackup:=False
     wb.Close
End If

 Application.DisplayAlerts = True
 
  '件数を表示
 
 MsgBox "File " & profixN & "n 件数：" & ii
End Sub
```
デザイナーからスクラムマスターに社内転職して、ゼロから始めたスクラム導入の話

Sasuke Financial Lab株式会社にて、自社サービス開発チームのスクラムマスターをしております、大塚と申します！

# 自己紹介など
フリーランスでUI/UXデザイナー出身→現在はSasuke Financial Lab所属にて、デザイナー→スクラムマスターに社内ジョブチェンジ。
バリバリスプリント回す日々でございます。

趣味は料理(ﾋﾞﾘﾔﾆﾁｮｯﾄﾃﾞｷﾙ)、DJ、キャンプ、ゲーム(フロム信者)、VRなどなど。
アウトドアインドア関係なく多岐に渡ります。時間が足りない！

経歴としては

学生時代にデザインを学ぶ
→新卒で某自転車屋勤務(デザイン系じゃない一般の就活をしたら受かった大きめの会社)
→DJが楽しくなって一年で退社し、飲食のバイトをしつつ生活費を削ってDJ修行、イベントオーガナイズ
→震災きっかけで自給自足を目指し千葉の奥地へ移住
→お金稼げなくてなかなかきついということで東京に戻りwebデザイナーアルバイト
→フリーになって業務系サービスのUI/UXデザイナーやりつつ、野外フェス企画をしたり、出張ビリヤニ屋さんをやったり…

と、いろんな寄り道をしながら楽しく生きているおじさんです。

ちなみに弊社Sasuke Financial LabについてはnoteやQiitaで次々記事出し強化中です。
個性的なメンバーが揃っております。 #SasukeFinancialLab タグをぜひ見てみてください！


# なんでわたしがスクラムマスターに！？
ことの発端は2021年。チームの根幹メンバーが辞めることが続く時期がありました(ベンチャーあるある)(現在は社員採用も強化されてめっちゃ安定してきた。人事のみなさんありがとう！)。

UI/UXデザイナーとしてSasukeの仕事に従事しておりました私は、日々かわる開発進行のルール、一日に何回も重なるmtg、部署間の開発内容に対する認識齟齬etc...
とにかく仕事が手戻りまくる状況、そしてなかなか世の中に出ていかないデザインたち。
そんな環境に疲弊しておりました。正直転職も考えたくらい。

個人的には、いちデザイナーでありながらも、mtgの仕切りや認識合わせるための仕組みづくりを実行。
ただしそれにも限界があり、状況は簡単には変わりません。

そんなある日、プロジェクトの開発をメインで仕切るエンジニアメンバー数名が抜けることに。
チームにはPM的立場の人もいないため、完全新規メンバーの体制へ変わることが決まりました。
数ヶ月の猶予があるとは言え、このままでは開発が頓挫してもおかしくない…
このままではまずい！と思った僕は、まずは部署を越えて、忙しい皆さんを集めてざっくばらんにお話をする場を設けました。

# みんな同じ課題感を持っていた
メンバー同士で話をしてみると、今みたいに部署がぱっきり分かれた状態で開発を続けていくのはとても困難だと感じている。
予定したことはだいたい予定通りには行かない。
なんとかしてこの状況を変えたいが、リーダーもいないし、どうしたらいいのか誰も答えがない。
ただしみんな「もっとスムーズにやりとりをして、アイデアをどんどん実装していきたい」という思いは共通していたように思います。

# 旗振る人がいないならやるしかない
前述の通りで既にいろんな人を集めて相談したりと旗を降り始めちゃった自分ですが、自分はとくにチームを受け持ったり、マネジメントする立場ではありません。
過去にも会社でプロジェクトマネジメントなんてやったこともありません。
自分が前に出てくのもどうなのかなあ…と思わなかったわけではありませんでした。

ただし、もともとの開発進行に対して疲弊していた自分としては、これ以上カオスでノーコントロールな状況がやってくるかと思うと憂鬱で、
状況をどうにかしたいという気持ちは人より強かったんじゃないかと思います。
いち社員デザイナーの立場で、上から降ってきた要件をなんとかかんとか形にし、返して、また手戻って…
というのを無限に繰り返すのはもううんざりだったわけです。

# ここで寄り道の経験が生きてきた
一方、フリーでやっていることの一つに「音楽イベント」がありまして。趣味のDJの分野ですね。
20名超のクルーを何年も、ネガティブな方向性での脱落者なくチームとしてみてきたり、1から野外フェスの企画進行をやった経験があります。
なので、自己流ではあるものの、マネジメントの経験がゼロというわけではありません。

加えて、フリーでUI/UXデザイナーをしていた前の会社では開発を「スクラム」というもので進行していたんです(やっとスクラムが出てきた！)。
そこの体制ではデザイナーが完全にスクラムチームの中に入るというよりは、次のスプリントでの開発をPOと一緒に先行してデザインしていくような流れ。エンジニアたちの体制も、横から見ていてすごく納得感のある進行に思えていました。

なので、スクラムについては完全ではないものの経験しており、
**大きく予定するのではなく、小さく価値を届け続ける**
その考え方は、当時の私たちの課題感を解決してくれそうに僕には思えたわけです。

# 社長に直談判！
とはいっても数十名の会社なのでそんな大それた感じではないんですが…（すぐ隣に座っているw)
スクラム開発ってのがあって、小さなチームの、自発性を促し、期間に区切って少しずつ開発していく手法なんです。今の困難な開発、僕が前に少し経験した限り、すごく良かったんですよ。今のサスケにはきっとこれがはまると思うんです…とSCRUM BOOT CAMP一冊を片手にプレゼン。
外から専門の方を取るにしても、今から募集して取れる保証はない。
それであれば、フリーランスの時に見たあの進め方を学んで実行する方が確実で速いじゃないですか！
そんなわけで社長も本を読んでくださった上で「いいんじゃないか」と決めてくださった！(プレゼンしておいてなんですが、正直、マジかよ！？と思ったのは秘密…)

かくして、デザイナーとしては何年かやりつづけているが、スクラムマスターとしてはズブの素人な私が、藁をもすがる思いで、スクラムマスターへの道を歩み始めたわけでした。


さて始めてからの話しはまた次にお話ししていきます！
今日はここまで！
MyScriptからの最新情報: 機能追加でNeboメモがもっと親しみやすくなりました

![3-5RELEASE-BLOGARTICLE-900.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784576/27893f86-b9b3-af95-47f7-838502fa4379.png)
メモを取るという行動は、たとえそれが職場であっても自分個人で行うもの。そしてメモの取り方は人それぞれ違うため、そのひとりひとりに合った使い方を提供できる柔軟性がなければ優れたメモアプリとはいえません。そこで私たちは、ユーザーのみなさんが自分らしさを出せる親しみやすいメモを作れるよう、幅広い機能についてさまざまな試みを行なってきました。
## どんなシーンでも使えるページ

Neboの考えるパーソナライズはページ作成の段階から始まっています。Neboアプリをこれまで使っていただいている方は、ノートに追加できる基本的なページタイプの中の２つが別の名前に変わっていることにお気づきになるでしょう。自由ページはメモ、そして標準ページはドキュメント になりました。よりそれぞれのページの用途、中身に合った名前にすることで、メモ作成をお手伝いします。

無限に広がるキャンバスの上に文字や絵を組み合わせたい、いろいろなアイデアを引き出したい、とにかく自由に使いたい、という方にはメモがおすすめです。

反応のいいページに手書きしたい、数式や図表を追加したい、手書きを文字に変換して体裁を整えたい、という方にはドキュメントがおすすめです。

## ディスプレイの選択が可能に

最新アップデートにより、ユーザーからの要望が特に多かったダークモード対応機能が追加されました。色の組み合わせが無数にあるアプリにとっては開発上の難しい課題でしたが、どのモードを使用しても変わらずメモが読みやすいようにするべく工夫を凝らしてきました。そして今ここに、照明の暗い環境でより快適にお使いいただける機能をみなさんにお届けできるようになりました。

今回の最新版のリリースに伴い、ページ背景も新しくなりました。メモとドキュメントのどちらでも背景カラーが変更で、またどの背景にもダークモードのバリエーションがあります。メモをカテゴライズしたい時や、ちょっと遊んでみたいだけの時でも、自由に背景カラーを変えてお楽しみください！

## 自分の言葉を、自分らしく

Neboには最近新しいペンの種類も加わりました。文字を書いたり絵や図表を描いたりする時にフェルトペン、万年筆、筆の中から自由に選べ、太さも調整できるようになっています。またNeboの世界トップレベルの文字変換機能もそれぞれのペンに備わっているので、ご安心を！ 新しくペンの種類が増えたことにより、Neboでメモを取るという体験がこれまで以上に自然なものになり、ペンをスクリーンに乗せるたびに、手書き文字をより忠実に読み取れるようになりました。

また専門用語や略語、ブランド名といった認識されない用語も、より簡単にNeboの辞書に追加できるようになりました。追加したい言葉を選択してメニューを表示し、「 “[用語]”を学習」（Learn “[term]”）をタップするだけで辞書に登録され、以降Neboはその言葉が出てくるたびに認識するようになります。

## パーソナライズ機能

Neboの新しいパーソナライズ機能を使うと、端から端まで自分らしい自分オリジナルのメモの作成がこれまで以上に簡単に！あなただったらどう使いますか？

ぜひSNSでシェアして教えてくださいね。みなさんのNebo活用術に私たちも興味津々です。
それでは、アップデートをお楽しみください！
MyScript The Neboチーム一同 

### 私たちとつながりませんか？
👉 [nebo.app](http://nebo.app/)
👉 [nebo support](https://app-support.myscript.com/support/home)
👉 [nebo (Facebook)](https://www.facebook.com/MyScriptApps/)
👉 [nebo (Twitter)](https://twitter.com/MyScriptApps)
【初心者向け】CSS疑似セレクタの種類と解説

<h2>疑似クラスとは?</h2>
要素がある状態になった時にスタイルを適用させると言うもの！<br>
〇の中にはクラス等が入ります！
<h2>〇〇:link</h2>
未訪問リンクのスタイルを指定します。
<h2>〇〇:visited</h2>
訪問済みリンクのスタイルを指定します。
<h2>〇〇:hover</h2>
要素にカーソルなどが乗った際のスタイルを指定します。 <br>a:hoverでは“カーソルは乗っているがクリックはされていない状態”です。
（筆者は:hoverにopacitiy（透明にする、しない）を設定する等よく使います！）
<h2>〇〇:active</h2>
要素をクリックした際にクリックした要素にスタイルを適用させる
【初心者向け】CSSの記述種類





<h2>■.(ドット）なしで記述する方法</h2>
p{
<br>color:white;<br>
}<br>
この書き方はクラスをつけていないPタグ（HTML）にCSSを反映させる記述です

<h2>■.(ドット）をつけて記述する方法</h2>
.text{<br>
color:white;<br>
}<br>
HTMLでpというクラスをつけたものを指定してCSSを反映させる記述です

<h2>■,(カンマ)で区切る方法</h2>
p, h2{<br>
color:white;<br>
}<br>
複数の要素を同時に指定することができる。

<h2>■スペースで区切られているとき</h2>
p text{<br>
color:white;<br>
}<br>
pの中にあるtextの文字色を変えるという指示
nuro光環境でSoftEtherVPN-ServerをインストールしたPCにIpadからVPN接続できるようにする(SSTP-connect)

## はじめに
外出先から自宅PCにVPN接続を行うためにSoftEtherを使う方法をまとめた備忘録です。

## 環境
nuro光(ONU：F660A)
SoftEther VPN 4.0 Ver4.39(BETA)
Windows11
ios 15.6.1

## 手順参考まとめ
ほとんどの手順は他のWebサイトにきれいにまとまっていたので、
自分が行った操作ごとに参考サイトをまとめる。

### 1.VPN Server用PCのIPアドレスの固定

https://solomon-review.net/construct-softether-vpn-05/

(ファイアウォールは許可しなくていいかも？)

### 2.SoftEther VPNのインストール・設定

https://solomon-review.net/construct-softether-vpn-06/

### 3.F660Aのポートフォワーディング

https://www.akakagemaru.info/port/f660a-portfw.html

### 4.IpadにSSTP Connectのアプリをダウンロード・設定

https://solomon-review.net/construct-softether-vpn-20/

### 5.TLSサーバー検証をオンにする

https://solomon-review.net/construct-softether-vpn-21/

## つまずいた点・疑問に思い自己解決した点

#### ・ポートフォワーディング設定・ファイアウォールの受信許可を行ったのにも関わらず以下のポートへ接続することができなかった。
(いずれもUDPで設定。TCP AND UDPで接続した443,5555は疎通確認ができた。)
- 1701
- 4500
- 500
UDPのポートだけ解放できず。（リスナーポートを設定していないから？）
仕方なくTCP 5555を生かすためにSSTP Connectを使用した。

#### ・ファイアウォールの受信規則を無効にしても接続ができる。
SofrEtherVPN-Serverの機能

https://ja.softether.org/4-docs/2-howto/6.VPN_Server_Behind_NAT_or_Firewall/1.Dynamic_DNS_and_NAT_Traversal

#### ・VPN接続できているか確認するには？

VPN接続に成功すると、Ipadで表示されるIPアドレスが自宅環境のグローバルIPになる。
別の場所にサーバーを移せば、自宅のグローバルIPアドレスを秘匿できる。

https://ja.vpnmentor.com/blog/%E3%81%82%E3%81%AA%E3%81%9F%E3%81%AEip%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E3%82%92%E7%B0%A1%E5%8D%98%E3%81%AB%E9%9A%A0%E3%81%994%E3%81%A4%E3%81%AE%E6%96%B9%E6%B3%95/

>VPNはIPアドレスを簡単に隠す方法として人気があります。VPNとは、プライベートサーバーにネット通信をリダイレクトするアプリのことで、実際のIPアドレスがサーバーのIPアドレスに置き換えられます。通常、VPNサーバーは世界各国に分散されていますから、外国のIPアドレスが使えるようになります。

#### ・SSTP-Connectを使うと通信プロトコルがSSTPになって独自プロトコルより安全性が低くなるのでは？

SSTP-Connectのプロトコル選択でSE-VPNを選んでいたのを見逃してた。