OmniAICreator/Qiita-1.07M huggingface dataset:
How a small business can benefit from managed IT services?

As a small business owner, you have to juggle finances, operations, and technology almost constantly. To make things easier, it would be prudent to avail services like managed IT and Secure cloud computing solutions for enterprises. Small businesses essentially face unique challenges when it comes to maintaining a robust IT infrastructure. As these businesses have limited resources, they often struggle to maintain an in-house IT department to handle their technological needs, and hence availing third-party services becomes ideal for them. 

Many types of small businesses need dependable data management, network security, hardware maintenance, software updates and more to grow and succeed. This is where Affordable managed IT services for small businesses can be of a huge help. By choosing to outsource your IT needs to a managed IT service provider, you would be able to effectively focus on growing your business while leaving the technical work to the experts.

There are many ways a small business can benefit from managed IT services, including:

Expertise: Managed IT services tend to be experts in their field and have the capability to provide a wide range of services that makes it easier for small businesses to manage their IT infrastructure. Their services can include data backup and recovery, cybersecurity, software updates and network management.
Cost savings:  For most small businesses, outsourcing IT services can be more cost-effective than hiring an additional IT staff. It helps them to save on salaries and training expenses. 

Increased productivity: Managed IT services can help improve the productivity of small businesses by providing them access to innovative tools and technologies, as well as ongoing support and maintenance.

Scalability: Managed IT service providers usually offer scalable solutions that adapts to the needs of a business, allowing it to enjoy continued success.

Managed IT services encompass a wide array of offerings for modern businesses, including network security, data backup, and disaster recovery. IT service provider basically strives to provide all necessary hardware and software solutions to meet the IT needs of their clients. These services go a long way in providing peace of mind to small business owners in regards to their technology infrastructure. Certain managed IT service providers even offer solutions of Custom software development for IT industry.
params引数で配列以外を受け取る（C#13）

## 参考
この記事は、以下の動画を参考にしています。
詳しくは、動画をご覧ください。

https://youtu.be/SlePiL1Azsg?si=0yusT2aF62fiK30F

また、以下のブログ記事も参考になります。

https://ufcpp.net/blog/2024/3/params-collections/

## C#12まで
`params`引数で受け取れるのは、配列だけでした。
```C#
void SomeMethod(params int[] numbers)
{
    // params引数は、配列のみ
}
```

## C#13
配列以外のコレクションも、`params`引数で受け取れます。
```C#
void SomeMethod(params IEnumerable<int> numbers)
{
    // params引数は、IEnumerable<T>
}
```
```C#
void SomeMethod(params List<int> numbers)
{
    // params引数は、List<T>
}
```
```C#
void SomeMethod(params ReadOnlySpan<int> numbers)
{
    // params引数は、ReadOnlySpan<T>
}
```
`IEnumerable<T>`を実装し、要素を追加する`Add(T)`メソッドを用意したクラスも、`params`引数に渡せます。
```C#
// params引数を持つメソッドの呼び出し
SomeMethod(1, 2, 3, 4, 5);

// クラスをparams引数に持つメソッド
void SomeMethod(params SomeClass obj)
{
    // params引数は、IEnumerable<T>を実装するクラス
}

// params引数を受け取るクラス
class SomeClass : IEnumerable<int>
{
    public void Add(int item)
    {
        //params引数が受け取るインスタンスを作る際に、Addメソッドが利用される
    }
    
    public IEnumerator<int> GetEnumerator() { }
    IEnumerator IEnumerable.GetEnumerator() { }
}
```
Markdownのノートを切り出すVSCode拡張機能を作った

## はじめに

Obsidianにあこがれて社内で[Foam](https://foambubble.github.io/foam/)を使っています。

https://marketplace.visualstudio.com/items?itemName=foam.foam-vscode

そこで自分は、デイリーノートにその日の作業内容をまとめて書いておき、一日の最後に別々のノートに切り出すという運用をしています。

Obsidianではコミュニティプラグインで

https://github.com/lynchjames/note-refactor-obsidian

というものがありコマンド一つでノートの整理ができるということで、自分も同じことをしたい！ということで作りました。

https://marketplace.visualstudio.com/items?itemName=torsk3.markdown-note-refactor

## markdown note refactor

シンプルですがコマンド一つで以下のことをやってくれます。

- 編集中のmdファイルでセクションごとに区切られているメモを別のファイルを新しく作りそこに転記する
- 同名のファイルが既に存在する場合は、そのファイルに追記する
- ノートを切り出した元のファイルには転記先のノートへのリンクを残す

同じような悩みをお持ちの方はぜひ使ってみてください! :smile_cat: 
ソースコードは以下で公開しています。

https://github.com/torsk3/markdown-note-rafactor

## 最後に

Obsidianで出来ることはFoamでも出来るように開発したいなと考えており、次はデイリーノートのカレンダーをVSCodeのサイドバーで表示することを構想中です。

https://github.com/liamcain/obsidian-calendar-plugin
SAP BTP 開発の開発環境（サーバサイド）

## SAP BTPの開発環境について
　SAP BTPの開発を行う場合、多くの方はSAP Business Application Studioを使って開発をしているかと思います。
 しかし、SAP Business Application Studio（通称：BAS）を使うと煩わしいことも出てきます。
 
 * Web IDEなのでショートカットキーが使えない
 * BASのインスタンス立ち上げに時間がかかる
 * ブレイクポイントを使ったデバッグが上手くいかない

等、特にサーバサイド（Java）の開発をする際、今までEclipse等のIDEを使っていた方にとっては細かなストレスがかかると思います。

そこでおすすめなのが、VisualStudioCode（通称：VsCode）です。

VsCodeはショートカットも充実し、様々な拡張機能も用意されているので、コーディングの観点では
WebIEDに比べると開発効率が上がると思います。

最近ではJavaの開発が行えるように拡張機能が充実しているので、
これまでEclipsを使っていた方にとっても遜色なく開発が行えます。

なにより大きいのはエディタだけを別のウインドで表示できる点です。
サブモニタ等を使用して、エディタだけを別のウインドで表示しコーディングに集中することもできるので、
コーディング量が多い場合は特に助かります。

ちなみに補足ですが、SAP Business Application StudioもVsCodeをベースに作られているようです。

しかし、SO・ミドルウェアの部分に関して、開発時に注意が必要となります。

## 注意点①（OS）※Macで開発されている方は対象外
BASで開発を行う際、OSの意識をすることはないですが、
VsCodeで開発を行う場合、単純にVsCodeインストールし起動するとWindowsOSで動きます。
しかし、デプロイ後の環境はLinux系のOSになっています。

Javaはマルチプラットフォーム言語なので、通常は意識することがないと思いますが、
ファイルパスの記載の仕方や文字コード等、VsCodeでの開発時は問題ないけれど、
デプロイ後確認すると不具合になった。
ローカル時とデプロイ時でソースを切り替えている等の経験をされた方もおられると思います。

**対応方法**
Windows SubSystem For Linuxを使う。

Windows SubSystem For Linu（WSL）を使うとJavaをLinux環境で実行することができます。
VsCodeの機能として、WSL上でリモート起動することもできますので、Window環境でありながらLinuxで動くプログラムを開発することができます。


## 注意点②（ランタイムのバージョン）
BASで開発を行うさいはJava等ミドルウェアのインストールが自動で行われる反面、
VsCodeで開発を行う場合はJava等のインストールから行う必要があります。
その為、デプロイ後の実行環境と開発時の環境に齟齬が生まれ、プログラムが動かない事象を生みます。

**対応方法**
ランタイムのバージョンを合わせる。
当たり前のことですが、デプロイ後の実行環境と開発時のランタイムのバージョンは合わせておきましょう。

以下のhelpポータルにバージョンの記載がある為、どのバージョンを使うか検討し、
開発前にプロジェクトで定義が必要です。

https://help.sap.com/docs/btp/sap-business-technology-platform/sapmachine?locale=ja-JP

補足：
mta.yamlを用いてデプロイする際は、以下のような設定を行うことで
実行環境のJavaバージョンの指定ができます。

```
  - name: javaApp
    type: java
    path: javaApp
    parameters:
      buildpack: sap_java_buildpack
      memory: 1024M
    properties:
      JBP_CONFIG_COMPONENTS: "jres: ['com.sap.xs.java.buildpack.jre.SAPMachineJRE']"
      JBP_CONFIG_SAP_MACHINE_JRE: "{ version: 17.+ }"
```

## 注意点③（タイムゾーン）※重要
一番、重要なのがタイムゾーンです。
デプロイ後の環境で動くタイムゾーンは**UTC**ですが、
Windows SubSystem For Linuxをインストールした直後の環境はJST(日本であれば)です。
タイムゾーンの変更は後でできるから、一旦JSTで開発するか等考えがちですが（私自身もそうでした）
**SAP BTPはPaaSの為、タイムゾーンの変更が用意ではありません！！**

使うサービスによっては変更できないものも多く、様々サービスを駆使して開発を行っている場合は余計に開発環境構築の時からタイムゾーンを意識する必要があります。

Windows SubSystem For LinuxのタイムゾーンをUTCに変更する方法もありますが、
VsCodeでデバッグ時に設定するlaunch.jsonを使って設定する方法もあります。

Javaの場合は以下の設定をlaunch.jsonに記載することで対応ですます。

``` 
"vmArgs": "-Duser.timezone=UTC" 
```

また、開発時にDBをH2DB等を使用して行う場合は以下のようにタイムゾーンを指定しましょう。

```
jdbc:h2:mem:testdb;TIME ZONE=UTC
```

## その他

上記３点を主に注意すれば、Visual Studio Codeを用いてSAP Business Application Studioと同じようにBTPのサーバサイトの開発が可能です。


フロント側（SAPUI5）の開発も同様に設定次第でisual Studio Codeを用いて開発ができます。
方法については今後記載しようと思います。
istringstream　stringを空白ごとに区切れる!？

## istringstreamとは？
istringstreamは，文字列を入力ストリームとして扱い，その中から特定のデータを効率的に抽出するために使用します．つまり，空白で分けられるだけでなく，入力時のようにデータごとに型を割り振ることができる!!
実際の具体例を以下に書きます．

```.cpp
#include <iostream>
#include <sstream>
#include <string>

using namespace std;

int main() {
    string input = "123 Hello World";
    istringstream iss(input);

    int num;
    string word1;
    string word2;
    
    iss >> num >> word1 >> word2;

    cout << "Number: " << num << endl;
    cout << "Word: " << word1 << " " << word2 << endl;

    return 0;
}
```
出力
```
Number: 123
Word: Hello World
```

:::note warn
 istringstreamを使うには
 ```
#include <iostream>
#include <sstream>
```
が必ず入ります！！
:::

それでは，みなさんいいエンジニアライフを〜👋
Pine64 A+ 1GBにUbuntu Mateをインストール

## はじめに
こんにちは、WindowsよりもUbuntuな bockringです。ということで、手持ちのSBCにUbuntu Mateを入れていきます。

## 前提(？)
Pine64は公式サイトでのOS配布は終了(？)していますが、GitHub上で「Pine64 Installer」を公開しています。GitHubということは、リポジトリやファイルを消さない限りは残るので安心ですね。

対応OSは
・OSX 10.9〜(x64)
・Linux(x86/x64)
・Windows 7〜(x64)
です。今回はArmbian上にPine64 Installerを入れて、システム移行をしていこうと思います。ちなみにUbuntu Mateのバージョンは確か16.04 LTSなので、注意は必要です。

ちなみに、Pine64 InstallerはEtcherベースのソフトです。OS選択部分にRaspberry Pi Imagerのようなものが組み込まれた感じです。

で・す・が、
**★バグって使えません★**
Windows 10とWindiws 11とArmbian 24(Appimageファイルを読み込める設定にしていないので無理でした)で確認しましたが、少なくともWindows上ではボード一覧が読み込めません。バージョンを落とすと
**HTTPエラーだよっ！**
ってなります。ひどいですね。仕方ないからArmbian 24.5.1 jammy, Bookwormにして我慢しよう、と考えたら、24.1.2から24.5.1にするだけで本家Ubuntuで言うとバージョンが2個進むんですね。Jellyfish(22.04)からNoble Numbat(24.04)ですわ。厳密にはjammyなんでDebianベースですけど、DebianベースのUbuntuをベースにしたArmbianなので、Ubuntu換算でいいでしょう。Debianでも11から12になってると思います。知らんけど。

## タイトル崩壊
「もうどうにでもなれ」って感じですけど、Armbian 24.5.1をレビューしていきます。24.1.2と操作感はほとんど変更ありません。しかし、大きな変化が。Gnomeの「設定」から言語を日本語に設定すると(最初のセットアップ時は英語で実行するのが無難)、正しく設定できます。なぜか前バージョン、日本語にできなかったんですよね。Chromiumは英語のままですが、問題ありません。それよりターミナルが日本語使えるのが大きいです。

Linuxニワカ勢には日本語化、大事ですからね。プロとは違ってVimmerではなく、nanoエディターを使うほどですから。しかしやっぱりUbuntuは便利ですね〜

Armbianはアプリケーションセンターは標準ではインストールされていないため、しっかり
```Terminal:Installing
user@pine64:~$ sudo apt-get install gnome-software -y
```
しておきましょう。これ入れたら楽ですからね。適当にScratch 1.4のエディターを入れて確かめてみました([Scratchのダウンロードページ](https://scratch.mit.edu/scratch_1.4)でインストールできなかったからというのは内緒)。

しっかり動きますね。手持ちのアカウントにアップロードもできました。いよいよWindows PCいらない説出てきましたが残しておきます。

今度Wine(Wine Is Not Emulatorの略らしいですね。)を入れてみようかな？そうすればWindows用のexe実行ファイルも動くし、ってところですかね。

## おわりに
グダグダ記事です。なかなかひどかったですね、この記事。まぁとはいえArmbianの情報の足しになれば、って感じなのでグダグダでも出していくつもりです。Pine64とかArmbian(特に前者)ってユーザーが多くないので出していかないとなとは思いつつですね。今度Raspberry Pi 5を買おうかなとか思いつつ。

まぁその前に[jyeTech(中国)のDSO068オシロスコープキット](https://jyetech.com/dso-068-oscilloscope-diy-kit/)を買おうかなと思っているので後回しですね(というかPine64でも遊べるし)。

それではまた次の記事で〜
perlの正規表現で使われる「$_」について

# 目的

こんにちは、Gakken LEAP のバックエンドエンジニアの mizuno です。
業務では使っていませんが、perl では様々な記述が省略可能であり、時に省略され過ぎて理解できないことがあります。
HTML エスケープ処理をする関数で省略された記述があり、今回はそちらについて調べてみました。

## 正規表現の対象が分からない

以下が HTML エスケープの関数になります。

```perl
sub escapeHTML {
  $_ = $_[0];
  s/&/&amp;/g;
  s/"/&quot;/g;
  s/'/&#39;/g;
  s/</&lt;/g;
  s/>/&gt;/g;
  $_;
}
```

`$_ = $_[0];` で引数に渡した文字列を `$_` に代入したところまでは理解できたのですが、
そのあとに行われる正規表現がどの変数に対して行われているかでした。

## $\_ というデフォルト変数

答えはこちらに記述されていました。
<https://perldoc.jp/docs/perl/5.38.0/perlreref.pod>

> =~ は正規表現が適用される変数を決定します。 省略された場合には、$\_ が使われます。

- 変数を指定するようにする場合は

```perl
$str = 'hoge';
$str =~ s/&/&amp;/g;
$str =~ s/"/&quot;/g;
$str =~ s/'/&#39;/g;
$str =~ s/</&lt;/g;
$str =~ s/>/&gt;/g;
```

正規表現をする場合はこちらを常に使っていました。

- 変数を指定しない場合は `$_` に入力されている文字が対象になるようです。

```perl
$_ = 'hoge';
s/&/&amp;/g;
s/"/&quot;/g;
s/'/&#39;/g;
s/</&lt;/g;
s/>/&gt;/g;
```

こちらの手法は使っていなかったのですが、`$_` を使えば正規表現の一部を省略して記述できることがわかりました。
ただし、暗黙的な変数であるため、頻繁に使ってしまうと可読性が悪くなる印象を受けました（なので、前職でperlを利用していた際にこの手法を先輩には教えられなかったのかもしれません）。

### 余談

さらっと、関数の引数を `$_[0]` で取得していますが `my ( $str ) = @_;` や
`my $str = shift;` などを使って分かりやすい変数名にしておくと良いです。
もし、`$_[0]` などを使うようであれば、コメントで補足説明を記述しておくと良いと思います。

## まとめ

今回は正規表現でわからないことを調べてみました。
perl には省略や特殊変数があり、実際のプログラムを読んで理解できない場面が来ないと一生使わない機能があったりしそうだと思いました。

Gakken LEAP では教育をアップデートしていきたいエンジニアを絶賛大募集しています！！

<https://gakken-leap.co.jp/recruit/>
コーディングテストする人必見!!競プロとは違う入力方法（C++)

## 競技プログラミングでのよくある入力

競技プログラミングでは，必ず入力数が指定されるため，どのぐらい回帰すればいいのかわかります．
数字がしていされたり，
ABC262 B
![スクリーンショット 2024-05-30 17.40.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3748983/090c610d-8a66-b07d-f203-d60b1b2cfff3.png)

終了条件が決まっていたり，
ABC244 C
![スクリーンショット 2024-05-30 17.43.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3748983/6dbaf659-31cf-23cd-b3a3-e0b29ee509eb.png)

写真はないですが，なんかの文字が入力されたら終了といったりするものが多いです．

## コーディングテストでの入力
しかし，企業のコーディングテストでは，入力の行数が指定されていない場合や、入力の終了タイミングが不明な場合があります．
そんなときは，**getline()関数**を用いて標準入力から行を読み込む方法が効果的！！
この関数は，指定されたストリームから一行を読み込みます．特に， EOF（End-Of-File）に達するまで続けて入力を読み込むことが可能です.
いかに具体的なコードを書きます
↓

```test.cpp
#include<iostream>
#include<vector>
#include<string>
#include<sstream>
using namespace std;

int main() {
    string line;
    vector<string> lines;
    while (getline(cin, line)) {
        if (!line.empty()) {
            lines.push_back(line);
        }
    }
    for(int i = 0;i < lines.size();i++){
        cout << i << "行目:" << line[i] << endl;
    }
}
```
入力
```
make sushi 10
eat sushi
like Tom tuna
like Rika tuna
made sushi Tom
```
出力
```
0行目:make sushi 10
1行目:eat sushi
2行目:like Tom tuna
3行目:like Rika tuna
4行目:made sushi Tom
```

## まとめ
このように，入力数が指定されていなくても，入力を最後まで読み込むことが可能です！
競技プログラミングではめったに出会わないような入力方法ですよね．．．
アルゴリズムはわかっていても，入力方法に時間を取られていてはもったいないので是非とも覚えておいてください!!!
【AWS】CloudformationでAPI Gateway Method作る際のアクションタイプの指定

# 困ったこと
- CloudFormationでAPI Gateway + S3 Proxyを作ろうとした際に、アクションタイプの指定で"パスオーバーライドを使用"にならない
- CloudformationのAPI Gateway Methodを見てもパスオーバーライドなんて検索にかかってこない

# 結果
- uriの項目内で指定する
    - "アクション名を指定"にしたい場合、'action/{アクション名}'を指定
        - arn:aws:apigateway:us-west-2:s3:action/GetObject&Bucket={bucket}&Key={key}
    - "パスオーバーライドを使用"にしたい場合、'path'を指定
        - arn:aws:apigateway:us-west-2:s3:path/{bucket}/{key}

# 参考リンク
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-apigateway-method-integration.html
【PowerAutomate】Teamsでメンション通知を送る方法



今回はPowerAutomateを使って、フローの実行者に向けてTeamsでメンション通知を送る方法をご紹介します。

※※注意※※
今回ご紹介する方法は以前のUIのものです。最新のUIと記述方法に若干の齟齬がある場合がございます。

## 方法

##### ⒈ ⊕アクションの追加から、[Office 365 ユーザー]群を選択し、[マイ プロフィールの取得 (V2)]アクションを追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3069823/0d41236e-5a2c-9ad8-28ae-530c4ae1a592.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3069823/d8525785-4111-1fd6-deaa-3e5f0041f31a.png)


##### ⒉ ⒈と同様に、⊕アクションの追加から[Microsoft Teams]群を選択し、[チャットまたはチャネルでメッセージを投稿する]アクションを追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3069823/e58da61a-ba31-147a-cc1c-e9c8602c8fe1.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3069823/46384aab-8d6c-0427-24f3-214637b77b93.png)

必要に応じて、Teamsへのサインインを行い、Automateとの接続を作成してください。

チャットに投稿するのか、チャンネルに投稿するのか等、お好みで自由に設定を行ってください。
※それぞれのプルダウンメニューを開くと、アカウントに紐づいたチャンネルやチームが表示されます。

※Messageの入力時に、コードビューの切り替えを行うと、HTML形式でMessageを指定することが可能になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3069823/eec57b82-02e4-83f4-6a41-4970912b2055.png)

手順⒈で取得したユーザープリンシパル名を使って、メンション通知を行う設定を行っていきます。

[動的なコンテンツの追加]から、手順⒈で取得したユーザープリンシパル名を追加し、前後を`<at></at>`タグで挟みます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3069823/93e60224-92e6-37ab-e97a-d48a7446740e.png)

※もしくはメールを使用しても通知できます![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3069823/0b5a7f98-b61f-fc9f-f462-32fa51547082.png)


今回は以下のように、`<p></p>`タグも使用して、メッセージも通知するようにしました。

![スクリーンショット 2024-05-30 094253.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3069823/0563fb13-b759-4b7a-6a9c-da50cbde0159.png)

## 実行してみる

保存してテストしてみます。

↓↓↓↓↓↓　
↓↓↓↓↓↓　



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3069823/21405c30-ead6-5cbd-7a84-a362675523f8.png)

無事に通知することができました！


## おわりに

読んでいただきありがとうございました！

お役に立てれば幸いです。
送信ドメイン認証

## 目次
・送信ドメイン認証とは
・種類
　1\. SPF
　2\. DKIM
　3\. DMARC
・必要な理由
・普及率
・余談

## 送信ドメイン認証とは
送信元メールサーバのIPアドレス認証や電子署名の仕組みを利用して、
**メールがなりすまされているかを判断する**仕組み。

##  種類
1\. SPF
2\. DKIM
3\. DMARC

## 1\. SPF
「Sender Policy Framework」の略称。
メール認証プロトコル。
送信者のドメインの詐称を防ぎ、送信ドメインの正当性を検証することができる。
→　**送信元を偽ったヘッダーによるなりすましメールへの対策が可能**


#### 動き
①DNSサーバにSPFレコードを登録(送信メールサーバ→DNSサーバ)
②メールを送信(送信メールサーバ→受信メールサーバ)
③正しいSPFレコードをDNSサーバに問い合わせ
　(受信メールサーバ→DNSサーバ)
④送信元IPアドレスとSPFレコードが一致するかを確認(DNSサーバ→受信メールサーバ)
【一致(pass)】認証成功
【不一致(Fail)】メールが届かない　→対策をする必要がある<br><br>


★SPFレコードとは
　「v=spf1 ip4:送信メールサーバのIPアドレス include:spf.example.com ~all」


## 2\.DKIM
「Domain-based Message Authentication Reporting and Conformance」の略称。
メールを送信する際に送信元が電子署名を行い、受信者がそれを検証する。
→ **送信者のなりすましやメールの改ざんを検知が可能に**

#### 動き
①送信メールサーバに秘密鍵を登録(送信元でデバイス→送信メールサーバ)
②DNSサーバに公開鍵を登録(送信メールサーバ→DNSサーバ)
③秘密鍵で電子署名を付与し、メール送信(送信メールサーバ→受信メールサーバ)
④電子署名を照合して認証(受信メールサーバ)
【一致(pass)】認証成功→改ざんされていない
【不一致(Fail)】認証失敗→改ざんの可能性がある


 ## 3\.DMARC
 　「Domain-based Message Authentication, Reporting and Conformance」の略称
  SPFとDKIMの検証結果に基づいて、メール受信者が不正なメールをどのように処理すべきかをドメイン所有者が指示できる技術。(ポリシーチェック)
  → **組織からの送信メールがSPFまたはDKIMの検証に合格しなかった場合に、DMARCポリシーを介してそのメールの処理方法を受信サーバーに指示する**

#### 3つのポリシー
・None(無し)：メッセージは受信者に配信され、DMARCレポートはドメイン所有者に送信される。
・Quarantine(隔離)：検証不合格のメッセージが隔離フォルダに移動される。
・Reject(拒否)：検証不合格のメッセージが配信されない。

#### 動き
①送信メールサーバー自身のなりすましメールの取り扱いを宣言(送信メールサーバ→DNSサーバ)
②メール送信(送信メールサーバ→受信メールサーバ)
③SPF・DKIMによる認証
④【SPF・DKIMが成功しなかった場合】
 　　最初に宣言した取り扱いに沿って3つのポリシーの中のどれかを実行する
④/⑤【SPF・DKIMにて認証が成功した場合/DMARCの結果がNoneの場合】
　　 メールが配信される


**DKIM→SPFとDKIMの弱点をカバーする**

## 必要な理由
　**ヘッダーfrom**と**エンベロープfrom**が異なることを見抜き、対策するため。
 　ヘッダーfromとエンベロープfromが異なること＝差出人のなりすまし/改ざんがされている可能性があるということ。<br><br>

  手紙で例えると....
  **ヘッダーfrom**：封筒や便せんに記載してある「〇〇より」
  **エンベロープfrom**：実際にその手紙を書いている人<br><br>

  
差出人だけでなく宛名(To)も、実際に書かれていた文章と途中で変えられたものなどが違う場合がわかる。

## 普及率
　SPF：7~8割
　DKIM：5割には満たない
　DMARC:やっと6割

 全体として、世界的には低いほうである。
 とくにDKIMの普及率が低い理由としては、
 SPFに比べ、専門知識を要することが大きな要因である。
 

## 余談
　私が、これらを知ったきっかけとしては、前の研修先でGmailのガイドライン変更に伴うDNSレコード変更作業に携わったことです。<br><br>


　現在の研修先も変更作業に携わっていたことを思い出したため、
 変更作業に携わった際に学習したことをここで書いてみようと思いました。<br><br>

 　前の研修先にいたころの目標が「送信ドメイン認証(特にDKIM)を先輩に説明できるくらいになる」でした。
  
　 まだまだ学習中の身であるため、正しい認識で書けているか少し不安です^^;
  
　 この記事を書くにあたって、引き続きその目標に向かっていこうと再起しましたので、
  頑張っていこうと思います。
csvを開いた時に、エンコードを確認する方法

```vb
Sub DetectEncoding()
    Dim filePath As String
    Dim fileNum As Integer
    Dim bom(0 To 2) As Byte
    Dim encoding As String
    
    filePath = "C:\path\to\your\file.csv"
    
    ' ファイルをバイナリモードで開く
    fileNum = FreeFile
    Open filePath For Binary As #fileNum
    
    ' ファイルの最初の3バイトを読み取る
    Get #fileNum, , bom
    Close #fileNum
    
    ' バイトオーダーマークを確認してエンコーディングを判別
    If bom(0) = &HEF And bom(1) = &HBB And bom(2) = &HBF Then
        encoding = "UTF-8"
    ElseIf bom(0) = &HFF And bom(1) = &HFE Then
        encoding = "UTF-16 (LE)"
    ElseIf bom(0) = &HFE And bom(1) = &HFF Then
        encoding = "UTF-16 (BE)"
    Else
        encoding = "SJIS (またはその他)"
    End If
    
    MsgBox "このファイルのエンコーディングは " & encoding & " です。"
End Sub

```
APIって結局何？

## はじめに
エンジニア歴1年未満の筆者が、APIという単語の意味をあまり理解せずに、これまでやり過ごしてきましたが、もう少し理解を深めようと、学んだ内容をまとめたブログです。

## APIとは何か？

この内容は少し調べると様々な記事などが出てきますが、ほとんどが「ソフトウェア同士がコミュニケーションをとるためのインターフェース」という説明だと思います。正直この文章で私はあまりイメージができませんでした。
具体的な例を出すと、スマホのアプリで天気予報を確認する際、そのアプリはAPIを通じて天気情報を取得しているということです。
この例だとイメージが湧くのではないでしょうか。

## APIの仕組み
APIの簡単なイメージはできたので、次に仕組みについて学んでいきます。
### クライアントとサーバーの関係
APIの仕組みを理解するためには、まず「クライアント」と「サーバー」の関係を理解することが重要です。この2つは、インターネット上のコミュニケーションにおいて基本的な役割を果たしています。

### クライアントとは
クライアントとは、ユーザーが直接操作するデバイスやアプリケーションのことを指します。具体的には、ウェブブラウザ(SafariやGoogle Chromeなど)、スマホアプリ（天気予報アプリ）などがクライアントにあたります。クライアントは、ユーザーの要求（リクエスト）をサーバーに送信し、その結果（レスポンス）をユーザーに表示します。

### サーバーとは
サーバーは、クライアントからのリクエストを受け取り、それに応じて必要なデータやサービスを提供するコンピュータやシステムのことです。
天気予報アプリの例では、サーバーは天気情報を保管している場所に当たります。

### クライアントとサーバーのやり取りの流れ
1. リクエストの送信: クライアント（天気予報アプリ）がサーバーに対して「京都の天気を教えて」というリクエストを送ります。
2. リクエストの受信と処理: サーバーはリクエストを受け取り、データベースから京都の最新の天気情報を検索します。
3. レスポンスの送信: サーバーは天気情報をクライアントに返します。
4. レスポンスの受信と表示: クライアントは受け取った天気情報をユーザーに表示します。

### このやり取りでのAPIの役割
このように、クライアントとサーバーはリクエストとレスポンスを通じてやり取りを行います。このやり取りを仲介するのがAPIです。APIは、クライアントがサーバーにリクエストを送る際のルールや形式を定めているため、異なるシステムやアプリケーション間でのコミュニケーションがスムーズに行えるようになります。

## APIの実例

### 公開されているAPI
#### [Qiita API](https://qiita.com/api/v2/docs)
API経由で記事の検索・更新などができる。
#### [Maps JavaScript API](https://developers.google.com/maps/documentation/javascript/overview?hl=ja)
Google mapsで特定の場所にピンを立てて表示させられるAPI
#### [YouTube Data API](https://developers.google.com/youtube/v3?hl=ja)
動画のアップロード、チャンネルの設定などがAPI経由でできる。

### APIを自分で作成できるサービス
#### Amazon API Gateway
公式ドキュメントからの引用
> フルマネージド型サービスの Amazon API Gateway を利用すれば、デベロッパーは規模にかかわらず簡単に API の作成、公開、保守、モニタリング、保護を行えます。API は、アプリケーションがバックエンドサービスからのデータ、ビジネスロジック、機能にアクセスするための「フロントドア」として機能します。API Gateway を使用すれば、リアルタイム双方向通信アプリケーションを実現する RESTful API および WebSocket API を作成することができます。API Gateway は、コンテナ化されたサーバーレスのワークロードやウェブアプリケーションをサポートします。

つまりAmazon API GatewayはAPIの作成、様々な管理ができるサービスということです。またフルマネージドサービスなので、サーバーの管理などは不要です。

## まとめ
API（Application Programming Interface）はその名の通りアプリケーションやプログラムをつなぐものということです。
ユーザーとして使用する場合にはあまり意識することはないと思いますが、実はよく使っているものだということがわかりました。
奥深いものだということが調べていてわかりましたので、これからもっと深いところまで理解できるように学んでいきたいです！
Day畳み込みの保存量

## プロ函手の自然変換
$(F\star G)\_\mathscr{D}^\mathscr{C},R_\mathscr{D}^\mathscr{C}\in\mathbb{Prof}(\mathscr{C,D})$の間の自然変換を考える．
```math
\begin{align}
\text{Nat}((F\star G)_\mathscr{D}^\mathscr{C},R_\mathscr{D}^\mathscr{C})&=\overline{\bigotimes_{\substack{C\in\mathscr{C}\\D\in\mathscr{D}}}}\text{Hom}\left((F\star G)_{(D)}^{(C)},R_{(D)}^{(C)}\right)\\
&=\overline{\bigotimes_{\substack{C\in\mathscr{C}\\D\in\mathscr{D}}}}\text{Hom}\left(\overline{\bigoplus_{\substack{W,Y\in\mathscr{C}\\X,Z\in\mathscr{D}}}}F^{(W)}_{(X)}G^{(Y)}_{(Z)}\Delta_{(W\otimes Y)}^{(C)}\Delta^{(X\otimes Z)}_{(D)},R_{(D)}^{(C)}\right)\\
&=\overline{\bigotimes_{\substack{C,W,Y\in\mathscr{C}\\D,X,Z\in\mathscr{D}}}}\text{Hom}\left(F^{(W)}_{(X)}G^{(Y)}_{(Z)}\Delta_{(W\otimes Y)}^{(C)}\Delta^{(X\otimes Z)}_{(D)},R_{(D)}^{(C)}\right)\\
&\simeq\overline{\bigotimes_{\substack{C,W,Y\in\mathscr{C}\\D,X,Z\in\mathscr{D}}}}\text{Hom}\left(F^{(W)}_{(X)}G^{(Y)}_{(Z)},R_{(X\otimes Z)}^{(W\otimes Y)}\right)\\
&=\text{Nat}\left(F_\mathscr{D}^\mathscr{C}G_\mathscr{D}^\mathscr{C},R_{(\mathscr{D}\otimes \mathscr{D})}^{(\mathscr{C}\otimes \mathscr{C})}\right)\\
\end{align}
```
つまりDay畳み込み$(*)$は自身の自然変換をプロ函手の積との間で保存する．
[k8s] LonghornのVolumeをストレージいっぱいまで使用する方法

## はじめに

longhorn はデフォルトで 25%のディスクに対して Volume を作成しないようになっています。

![Longhorn UI](https://longhorn.io/img/screenshots/getting-started/longhorn-ui.png)

このため、ディスクの容量が 100GB ある場合、Volume は 75GB までしか作成できません。

これではストレージが無駄になってしまいます。そこでこの記事では、longhorn の設定を変更して、予約されたディスク容量を変更する方法を紹介します。

## 方法

longhorn の設定を変更するために、Helm の `values.yaml` ファイルを編集します。

```yaml
defaultSettings:
  storageReservedPercentageForDefaultDisk: 5
```

この設定を変更することで、デフォルトのディスクに対する予約容量を変更できます。デフォルトでこの数字は 25(%)になっています。今回は 5(%)に変更します。

これでディスク容量の 5%が予約されるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3330232/3bc3b635-c8f5-30d0-30e5-b4794245d557.png)

## 参考資料

https://github.com/longhorn/charts/blob/v1.6.x/charts/longhorn/values.yaml#L205

https://stackoverflow.com/questions/70741359/longhorn-using-more-than-50-of-storage-as-reserved-space
Nuxt3でglobal middlewareでnavigateToが使えない

# 概要
`Nuxt 3.11.2`にて、`global middleware`で`navigateTo`を使うと`ERR_TOO_MANY_REDIRECTS`エラーが発生する

※ローカルで`npm run dev`すると発生しない
　AWS LambdaにデプロイしてCloudFrontにアクセスすると発生した

`Nuxt 3.0.0-27444434.856c01a`の頃は`Vue Router`で無限ループが発生していたらしい
(まだこの事象が残っているのか、これが原因でエラーとなっているのかは不明)

https://blog.cloud-acct.com/posts/nuxt3-global-middleware/

# 回避策
上記記事では「`local middleware`なら問題ない」と書いてあるが、ログイン状態によるリダイレクトなどは基本的に全ページで処理したく、全ページに`middleware`の定義を書くのは面倒
→代わりに`router.push`を使うと解決した
(他になにか問題が出ているかも、何かあれば追記予定)

```diff_typescript:/middleware/auth.global.ts
export default defineNuxtRouteMiddleware(async (to, _from) => {
  // なんか時間のかかるログイン状態チェック処理
  const isLoggedIn = await checkIsLoggedIn();

  if (isLoggedIn) {
    if (to.path === "/login") {
-     return navigateTo("/");
+     useRouter().push("/");
    }
  } else {
    if (to.path !== "/login") {
-     return navigateTo({ path: "/login", query: { redirect: to.path } });
+     useRouter().push({ path: "/login", query: { redirect: to.path } });
    }
  }
});
```
FlutterFlowでアプリアイコンを表示する方法

FlutterFlowでiOSアプリ開発をしております。

アプリアイコンを公式の手順通り設定し、シュミレーターでビルドしたのに反映されなかったのの対応をメモ
https://docs.flutterflow.io/settings-and-integrations/general-settings/app-assets#launcher-icon


上記の手順でアイコンをlauncher iconを設定しコードをダウンロードします。
私は、AndroidStudiosでエミュレータービルドしています。

AndroidStudioのTerminalを開き下記のコマンドを実行します。
```
flutter pub run flutter_launcher_icons:main
```


<br>
このように表示されれば完了です！

![スクリーンショット 2024-05-30 16.34.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76914/40ce25e5-56a7-74d9-0877-0c755e4d3a92.png)
[解決済み]Target class [] does not exist.

**[解決しました](#解決20240610)**
<br>
前回勉強した時からエラーが解消できずにいる。
新たにポストしようと"create post"をクリックすると、今までであれば問題なくポスト入力画面に行っていたものが、前回からエラー画面に飛ぶようになった。

内容は`Target class [mustBeLoggedIn] does not exist.`
mustBeLoggedInが見つからないらしいのだが、ある。あるんだよ。

小文字大文字も誤字脱字もなくちゃんとあるはずなのにこのエラーが消えない。
キャッシュクリアしたり再起動したが解消されず。
このままでは先に進めないので結構焦っている。アセアセ

どこでそうなったのか特定もできておらず、GPTに手伝ってもらうもわからない。
教材で同じ悩みを解決している人もいて、それにならって同じことをしてみるも無駄；；

laravelのバージョンの違いなのかな？

---

QMKファームウェアとその他カスタムテーマアップしました！
[minipeg48 QMK Firmware](https://github.com/suzukidog/qmk_firmware/tree/master/keyboards/minipeg48)
[VSCode/Cursor カスタムテーマ](https://github.com/suzukidog/custom-theme/tree/main/VScode/osu-syntax)
[Warp カスタムテーマ](https://github.com/suzukidog/custom-theme/tree/main/Warp)
[GoogleChrome カスタムテーマ](https://github.com/suzukidog/custom-theme/tree/main/GoogleChrome/osutheme)

Githubの使い方に慣れていないため、見様見真似でフォークなるものをしてみましたが正しい使い方なのかわかりません。

# 解決(2024/06/10)
```:環境
Laravel 11.6.0
PHP 8.3.7
```
**Laravel11**からミドルウェアを`app/http/kernel.php`(以下kernel.php)ではなく`bootstrap/app.php`(以下app.php)で設定するようになったらしく、kernel.phpが不必要になったようだ。
[Laravel 11.x リリースノート - ミドルウェア](https://readouble.com/laravel/11.x/ja/releases.html#middleware)

1. kernel.phpを削除
2. app.phpでミドルウェアを設定
3. ミドルウェア(MustBeLoggedIn.php)内で`Illuminate\Support\Facades\Log;`をuse宣言

俺の場合これでエラーが解消されて正しく動いてくれました。

小文字大文字誤字脱字は確かに無く、正しくuseで宣言もできていた。が、Laravelが本来不要なkernel.phpから設定を呼び出そうとすることでエラーが発生していたらしい。
Class ItemSerializer missing "Meta.model" attributeの対処法

# 問題

[こちらの記事](https://qiita.com/maooz4426/items/fea320d459d1c994f6d2)で行っていたAPIを作る練習をしようとしていた際に一覧を表示しようとしたら

![スクリーンショット 2024-05-27 0.02.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766230/e1165063-fa0e-5272-43ab-8f95eae13aa1.png)

と出てしまいました。




# 原因と対処

```
AssertionError: Class ItemSerializer missing "Meta.model" attribute
```
これはserializer.pyで定義したシリアライザークラスにおいて、Metaクラスが正しく定義できておらず、見つからないと言っています。さらに`Meta.model`がと言っているので、どうやら`Meta.model`が原因そうです。

アプリフォルダの`models.py`を見てみると

```models.py
from rest_framework import serializers
from .models import Item

class ItemSerializer(serializers.ModelSerializer):
    class Meta:
        models = Item #modelsではなくmodel
        fields = '__all__'
```
`model`としなければならないところを`models`と書いてしまっていました。

```models.py
from rest_framework import serializers
from .models import Item

class ItemSerializer(serializers.ModelSerializer):
    class Meta:
        model = Item #修正後
        fields = '__all__'
```

>メタクラスってそもそも？
メタとは、英語で「高次」とか、「超える」という意味です。メタクラスとは、クラスの設定を決めるクラスのことで、一般的なクラスはインスタンス生成後の挙動を定めていますが、メタクラスはそれより高次とも言える、クラスそのもの生成や挙動に関するを定めています。

難しいですね...
PythonでWord文書から空白行を削除する

Word文書の内容の整然性と読みやすさは、文書の質を反映する重要な要素です。不要な空白行などの誤りや不適切な内容は、読みやすさを損なったり、自動データ処理の精度を妨げたりすることがあります。特に、データ分析、レポート作成、長文編集などを行う場合、不要な空白行によってページ数が増えたり、情報の区切りが曖昧になったりする可能性があります。
Pythonは、Word文書の空白行を一括削除し、そのプロセスを自動化するための強力なサポートを提供します。この記事では、**Pythonを使用してWord文書から空白行を自動的に削除する方法**を紹介します。

この記事で使用している方法は、[Spire.Doc for Python](https://www.e-iceblue.com/Download/Spire-Doc-Python.html)に基づいています。PyPI：`pip install Spire.Doc`。

## PythonでWord文書から空白行を削除する

Word文書では、空白行は主に空白段落として存在し、段落は文書構造におけるセクションの下位要素です。したがって、文書の各セクションとそのセクション内の要素を反復処理し、その中に段落の要素があるかどうかを判断し、テキスト内容が空白の段落を削除するだけで、文書内の空白段落を一括削除できます。

操作手順は以下のとおりです。

1. 必要なモジュールをインポートします。
2. `Document` オブジェクトを作成し、`Document.LoadFromFile()` メソッドを使用して Word 文書を読み込みます。
3. 各セクションとセクションの各子オブジェクトを反復処理します。
4. まず、子オブジェクトが段落タイプに属しているかどうかを確認します。段落タイプの場合、子オブジェクトが「段落」インスタンスかどうかをさらに確認します。段落の場合、段落テキストが空白かどうかをさらに確認します。空白の場合は、`Section.Body.ChildObjects.Remove()` メソッドを使用して段落を削除します。
5. `Document.SaveToFile()` メソッドを使用して文書を保存します。
6. リソースを解放します。

**コード例**
```python
from spire.doc import *
from spire.doc.common import *

# Documentクラスのオブジェクトを作成します
doc = Document()

# Word文書をロードします
doc.LoadFromFile("G:/文档/示例1.docx")

# ドキュメント内の各セクションを反復処理します
for i in range(doc.Sections.Count):
    section = doc.Sections.get_Item(i)
    j = 0
    # セクション内の各子オブジェクトを反復処理します
    while j < section.Body.ChildObjects.Count:
        # 子オブジェクトが段落タイプかどうかをチェックします
        if section.Body.ChildObjects[j].DocumentObjectType == DocumentObjectType.Paragraph:
            objItem = section.Body.ChildObjects[j]
            # 子オブジェクトがParagraphクラスのインスタンスかどうかをチェックします
            if isinstance(objItem, Paragraph):
                paraObj = Paragraph(objItem)
                # 段落が空白かどうかをチェックします
                if paraObj.Text.strip() == "":
                    # 段落のテキストが空白の場合、セクションの子オブジェクトリストからオブジェクトを削除します
                    section.Body.ChildObjects.Remove(objItem)
                    j -= 1
        j += 1

# 文書を保存します
doc.SaveToFile("output/删除Word文档空白行.docx")
doc.Close()
```

結果
![PythonでWord文書から空白行を削除する](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278784/f1647978-7af5-74a9-4c12-7ddfc2415eb4.png)

この記事では、Pythonを使用してWord文書から空白行を削除する方法を紹介しました。

Word文書処理のその他のテクニックについては、[Spire.Doc for Pythonチュートリアル](https://www.e-iceblue.com/Tutorials/Python/Spire.Doc-for-Python/Program-Guide/Spire.Doc-for-Python-Program-Guide-Content.html)をご覧ください。

[無料ライセンスの申請](https://www.e-iceblue.com/TemLicense.html)
SQL 解析順序があるよ。っていう話。

研修でSQLを学ぶと思いますが。SQLの解析順って教えてもらうのだろうか。
SQLの解析順を知っているとSQLが文法エラーになったときの助けになる時があるよ。っていう話です。
今回はSELECT文の解析順序の話です。

:warning:　検証ではPostgreSQLを使用しています。

さっそくですが、

このSQLは実行できます。
```sql:SQL①
SELECT 
price * 1.1 AS price_with_tax
FROM sp_work.aoki_products
ORDER BY price_with_tax;
```

しかし、こちらのSQLはエラーになります。
```sql:SQL②
SELECT 
price * 1.1 AS price_with_tax
FROM sp_work.aoki_products
WHERE price_with_tax = 110;

=> SQLエラー [42703]: ERROR: column "price_with_tax" does not exist
```
どちらもSELECT句で指定しているprice_with_tax（AS別名）を使ってます。
ORDER BY句では使用可能ですが、WHERE句ではdoes not existになってしまいます。

なぜWHERE句ではdoes not existになるの？？ :thinking:
SQLの解析順序を知っていれば、理由がわかかります。

**こちらが、SQL解析順序です。**
1. **FROM句**
1. **JOIN句**
1. **WHERE句**
1. **GROUP BY句**
1. **HAVING句**
1. **SELECT句**
1. **ORDER BY句**
1. **DISTINCT句** 
1. **LIMIT OFFSET句**

WHERE句の解析はSELECT句の前で行われる為、WHERE句ではまだprice_with_taxを認識できません。
なので、does not existエラーになるわけです。


このような集計関数を使用したSQLも初心者がやりがちなミスです。
```sql:SQL③
SELECT 
category,
max(price)
FROM sp_work.aoki_products
WHERE max(price) > 100
GROUP BY category 

=> SQLエラー [42803]: ERROR: aggregate functions are not allowed in WHERE
```
グルーピングして集計する場合、GROUP BY句でグループ指定をします。このGROUP BY句よりも先にWHERE句が解析されるので、WHERE句では集計関数は使えません。

では、GROUP BYが無ければよいのか？？ :thinking:
```sql:SQL④
SELECT 
max(price)
FROM sp_work.aoki_products
WHERE max(price) > 100

=> SQLエラー [42803]: ERROR: aggregate functions are not allowed in WHERE
```
だめです。
**GROUP BYが無い場合は、全件でグルーピング**していると思って下さい。
グルーピングしているのがWHERE句解析後のGROUP BY句解析タイミングなのでエラーになります。
つまり、<mark>WHERE句では、集計関数は使えません</mark>。

集計関数を検索条件にしたい場合は、HAVING句を使いましょう。
```sql:SQL⑤
SELECT 
category,
max(price)
FROM sp_work.aoki_products
GROUP BY category 
HAVING max(price) > 100
```

# さいごに
数年後にはSQLもAIが書いてくれるんだろうなー :expressionless:
Java Silver 17 合格体験記

## はじめに
少し前、JavaSilver17に合格しましたので、合格体験記として記録を残そうと思います。

## 残そうと思った理由
### JavaSilver17を取り巻く環境があまり良くないため
 - JavaSilver17の日本語試験がリリースされたのは2023年12月1日で、出来立てほやほや
 - 現状、紫本は出版されていますが黒本はまだ出版されていない（今年中という噂）
 - ネットを探しても合格体験記等、有意義な情報源が少ない

## 勉強時間について
正確には計測していませんが、
 - 11の黒本（10章まで）を1周
 - 17の紫本を1周（模擬試験のみ1.5周ほど）
 - 50-60時間程度

勉強スタイルは人それぞれだと思いますが、便利な黒本がまだないため周回を繰り返すより1問ずつ問題を振り返りながら確実に理解するやり方を意識しました。
また、問題の型が不明確なため、どのような初見の問題が出ても狼狽えないように、基礎知識を固めるイメージで取り組みました。

## JavaSilver11から何が変わったのか
### 出題数と試験時間が変更
JavaSilver11の80問・180分からガラッと変更され、**60問・90分**となりました。
1問あたりにかけられる時間が2分15秒から**1分30秒**に変更されたので、出題コードや出題意図を素早く理解する必要があります。

### モジュールシステム、ラムダ式とお別れ
モジュールシステムやラムダ式は試験範囲から**外されました**。11以降の新しい言語仕様をフィーチャーしています。
 - **頻出する主な新しい言語仕様**
    - テキストブロック
    - スイッチ関係（アロー構文（->）とスイッチ式）
    - レコードクラス
    - シールクラス

## 個人的に掘り下げが必要になった分野
 - 新しい言語仕様（前述）
 - javac、javaコマンド（-d、-cpオプション、パッケージ化）
 - byte、short、intの扱える範囲（256、65536、4294967296）
 - イミュータブル（Stringなど）
 - static（インスタンス化との違い、呼び出し方の違い）
 - 可変長引数（仮引数の指定方法・ルール、扱い方）
 - 多次元配列（宣言の方法、アクセスの方法、for-eachロジック）
 - var（宣言できる？できない？）
 - インターフェース（多重継承、多重実装、デフォルト・staticメソッドなどの仕様、多重実装時のメソッド名衝突）
 - ポリモーフィズム（キャストできる？できない？、メソッド呼べる？呼べない？）
 - multi-catch（書き方、コンパイルエラーになる例）

## その他受験時に助かる知識
### 出題コードが読みづらい
テストセンターでの受験において、画面のアスペクト比がおかしいです。
出題文が横に伸ばされているため読みづらいと思います。
### ダミー問題がある
テスト前の注意書きにもありますが、テストの標準仕様として**答えの存在しないダミー問題**を出題することがあるようです。
1問あたりに割ける時間が少ないことからも、わからない問題は適当にマークして飛ばすことが大切です。
### 紫本の類題がほとんど
私が受験した際は、紫本で解いたことのある問題の類題が中心的な出題でした。11の黒本で補強するより17の紫本を確実に理解することの方が大切だと思います。
git,ssh設定各種

■ ssh公開鍵作成
生成コマンド実行
```bash
ssh-keygen
```
以下入力求められる
```bash
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/ユーザー名/.ssh/id_rsa): <--鍵の保存先 
Enter passphrase (empty for no passphrase):  <-- パスフレーズを入力（任意）
Enter same passphrase again:  <-- もう一度、パスフレーズを入力（任意）
Your identification has been saved in id_rsa.
Your public key has been saved in id_rsa.pub.
```

秘密鍵の確認
```
ls -l ~/.ssh/id_rsa
```
公開鍵の確認
```
ls -l ~/.ssh/id_rsa.pub
```
権限の設定
```
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_rsa
chmod 644 ~/.ssh/id_rsa.pub
```
  
設定ファイルの設定
```
~/.ssh/config
Host <ホスト名>
  User <リモート側ユーザ>
  IdentityFile ~/.ssh/id_rsa #ssh-keygenでファイル名変えたらここも変更
```

疎通 確認
```
ssh -T <ユーザ名>@<ホスト名>
```
うまくいかない時のデバッグ
```
ssh -vT <ユーザ名>@<ホスト名>
```

■ gitサーバー側の公開鍵設定に以下から取得できるテキストはりつけ
  (サーバー側いろいろあるので割愛)
```
cat ~/.ssh/id_rsa.pub
```

■ 以下のような形で取得
git clone -b main <gitのsshパス> ./src



以下パーミッション設定しないと動かない時あったのでメモ 
パーミッションの設定:
```bash
sudo chmod 644 /etc/crypto-policies/back-ends/openssh.config
```
所有者の設定:
```bash
sudo chown root:root /etc/crypto-policies/back-ends/openssh.config
```
ファイルの確認:

```
ls -l /etc/crypto-policies/back-ends/openssh.config
```

出力が以下を確認
```
-rw-r--r-- 1 root root <file_size> <date> /etc/crypto-policies/back-ends/openssh.config
```

SSHサービスの再起動:
```
sudo systemctl restart sshd
```
CompTIA CASP+合格体験記（独学）

# はじめに
CompTIA CASP+に合格しました。（2024/4/29）　
独学で勉強を進めるにあたって、CASP+に関しての情報が少ないと感じたので、実際に受験した感想を残しておこうと思います。
# CompTIA CASP+とは
>CompTIA Advanced Security Practitioner (CASP+)認定資格は、企業や組織でより高度なセキュリティ分野を担当するセキュリティアーキテクトや上級セキュリティエンジニアなどのセキュリティ実務者を対象にした認定資格です。
IT全般の管理者として**10年以上の経験、そのうち5年以上をセキュリティに関連する実務で得られる知識やスキルを目安**に設計されています。

（参考:CompTIA公式サイト）

https://www.comptia.jp/certif/cybersecurity/comptia_casp/

CompTIAの資格は他の資格（CISSP等）と違い試験に合格したら即日認定されます。
**合格するだけで第三者機関に10年以上の経験及び5年以上のセキュリティ経験相当の知識があると認められる素敵な試験ですね！！**
## 試験内容
### **CASP+（CAS-004）試験範囲**
|ドメイン|出題比率|
|:-|:-|
|1.0 セキュリティアーキテクチャ| 	29% |
|2.0 セキュリティオペレーション| 30% |
|3.0 セキュリティエンジニアリングと暗号化技術| 26% |
|4.0 ガバナンス、リスク、コンプライアンス| 15% |

実務者としてセキュリティ業務を行う人材のスキルを幅広く学習することが出来ます。

### **試験形式**
<table>
    <tr>
      <td>制限時間</td>
      <td>165分</td>
    </tr>
    <tr>
      <td>問題数/出題形式</td>
      <td>最大で90問　単一/複数選択、パフォーマンスベーステスト</td>
    </tr>
    <tr>
      <td>合格ライン</td>
      <td>合否のみ/スコアは表示されません</td>
    </tr>
    <tr>
      <td>受験料</td>
      <td>￥65,754（2024年5月30日現在）</td>
    </tr>
 </table>
 
# 受験のきっかけ
元々CompTIA Security+を取得しており、
**せっかくならCompTIAで1番最強の資格をとったらかっこいいんじゃね？** といった浅はかな考えで受験することを決めました。

# 学習リソースと勉強方法
## **1.The Official CompTIA CASP+ Self-Paced Study Guide (試験番号： CAS-004) 書籍 日本語版**

https://jp-store.comptia.org/p/CAS-004-JPPP-22-C

CASP+ (CAS-004) 試験の出題範囲を全てカバーしている唯一の日本語で記載されたガイドブックです。
基本はこちらをメインに学習していく形になるかと思います。

私はこのガイドブックでCASP+に関する基礎的な知識をインプットしました。
章末に問題もついてくるため、セキュリティの実務経験に自信のある方はこの1冊で大丈夫かもしれません。 多分

## **2.TAC問題集**

https://www.tac-school.co.jp/kouza_it/it_crs_comptia_caspplus_004.html

私は試してませんが、CASP+で唯一の日本語で記載された問題集となります。
CompTIA Security+でお世話になった方も多いと思いますので、信頼出来る問題集かと思います。（気になるので実際に解いた感想を教えて欲しいです）

## **3.CASP+ (CAS-004) Full-length Practice Certification Exams**

https://www.udemy.com/share/105NZk/

こちらはUdemyの中で1番評価の高い問題集となっております。
実際に使ってみて、試験範囲を網羅した良い問題集と感じました。
繰り返し解いてほぼ100%の正答率を出せるように仕上げました。
※英語のため翻訳が必要となります。

## **4.CASP+ (CAS-004) Complete Course & Full-Length Practice Exam**

https://www.udemy.com/share/105Njs/

前述した問題集と同じ講師の講義となります。
講義形式なので時間はかかりますが、

この講義のいい所
**日本語字幕があります！！**

講義内容もとても分かりやすく、試験範囲を網羅できるのでとてもおすすめです。

**Jason Dion先生最高です！！**

# 試験当日
セキュリティ実務者として何を回答として求められているかを考えて試験を解きました。
CISSP等の試験と違って、後から見返すことが出来るのでじっくり考えながら問題を解いていました。
また、165分と長い試験時間のため途中トイレに行きたくなったらどうしようと不安がありました。

しかし安心してください
**途中退出してトイレに行くことが出来ます！！**

試験結果は、試験を終えたあとアンケートに答えると出てきます。
急に合格の文字が出てきてびっくりしました。
不意をつく天才かもしれません...

# 感想
セキュリティ実務者の立場としてとある状況でどのような選択をするのかを根拠に基づいて考えるいい訓練になったと感じました。

IT全般の管理者として10年以上の経験、そのうち5年以上をセキュリティに関連する実務で得られる知識やスキルを目安に設計されている試験なので、実際試験を受けてみて難易度は難しめと感じました。

CompTIA CASP+に合格すると実務経験があまりなくても自信に繋がります。
また、根拠に基づいたセキュリティ対策を考えられるようになるためとてもおすすめします。

# さいごに
最後まで読んでいただきありがとうございました。
**合格してレッツコンプティアライフを満喫しましょう！！**
**CompTIA CASP+仲間が増えること楽しみにしております！！**
flutterでurlをブラウザで開かせる

必要なパッケージをインストールする
```shell
flutter pub add url_launcher
```
以下のようにurlを開く機能を実装
```dart
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Home(),
    );
  }
}

class Home extends StatelessWidget {
  // URLを開く関数
  void launchURL(Uri url) async {
    if (await canLaunchUrl(url)) {
      await launchUrl(url);
    } else {
      throw 'Could not launch $url';
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('URL Launcher Example'),
      ),
      body: Center(
        child: GestureDetector(
          onTap: () {
            launchURL(Uri.parse("https://www.example.com"));
          },
          child: Text(
            "Tap here to open the browser",
            style: TextStyle(decoration: TextDecoration.underline, color: Colors.blue),
          ),
        ),
      ),
    );
  }
}
```
外部ブラウザで開く場合は`launchUrl`に`mode`パラメータを追加する
```dart
void launchURL(Uri url) async {
    if (await canLaunchUrl(url)) {
      await launchUrl(
        url,
        mode: LaunchMode.externalApplication, // ここで外部ブラウザを指定
      );
    } else {
      throw 'Could not launch $url';
    }
  }
```
### 文字列がurlかどうかを判定する方法
`Uri.parse()`を使って例外が発生するかどうかをチェックする
```dart
bool isValidUri(String uri) {
  try {
    var parsedUri = Uri.parse(uri);
    return parsedUri.hasScheme; // スキーマが存在するか確認
  } catch (e) {
    // URIが無効な場合、例外が発生
    return false;
  }
}

void main() {
  var urls = [
    "https://www.example.com",
    "www.example.com",
    "example",
    "https://",
    "ftp://example.com"
  ];

  for (var url in urls) {
    print('$url is a valid URI? ${isValidUri(url)}');
  }
}

```
Reactやってて「Yupって何？」と気になったので調べてみた。

# Yupとは
フォームの入力値を解析してバリデーションを行うReactライブラリのこと。

# インストール方法
```bash
npm install yup
```

# 基本的な使い方

```react
// import文
import * as yup from 'yup';

// 文字列型チェック + 必須チェック
yup.string().required('必須エラーメッセージ')

// 数値型チェック + 必須チェック
yup.number().required('必須エラーメッセージ')

// 配列型チェック + 必須チェック
yup.array().min(1, '必須エラーメッセージ')

// 日付型チェック + 必須チェック
yup.date().required('必須エラーメッセージ')

// バリデーションルール設定
const schema = yup.object().shape({
    username: yup.string().required(t("auth.message.required_usercd")),
    age: yup.number().required(t("auth.message.required_age"))
})
```

## 使用例
※ react-hook-formと組み合わせて使用した場合

```typescript
"use client";

import yup from "yup";
import { yupResolver } from "@hookform/resolvers/yup";
import { useForm, SubmitHandler } from "react-hook-form";

const schema = yup.object().shape({
    username: yup.string().required(t("auth.message.required_usercd")),
    age: yup.number().required(t("auth.message.required_age"))
})
type exampleFormData = yup.InferType<typeof schema>;

export const ExampleForm = () => {
  const { register, handleSubmit, formState } = useForm<exampleFormData>({
    resolver: yupResolver(schema), // Yupと紐付け
    mode: "onChange", // バリデーションチェックのタイミングを設定
  });

  return (
    <form className={styles.formWrapper} onSubmit={handleSubmit(onSubmit)}>
      <h1>
        プロフィール登録
      </h1>
      <div>
        プロフィール登録に必要な情報をご入力ください。
      </div>
      <div className={styles.formItemWrapper}>
        <label>ユーザーネーム</label>
        <input {...register("username")} />
        <span className={styles.formErrorMessage}>{formState.errors.username?.message}</span>
      </div>
      <div className={styles.formItemWrapper}>
        <label>年齢</label>
        <input {...register("age")} />
        <span className={styles.formErrorMessage}>{formState.errors.age?.message}</span>
      </div>
      <div className={styles.buttonContainer}>
        <button disabled={!formState.isValid}>登録</button>
      </div>
    </form>
  );
};
```

# 参考
[yup](https://github.com/jquense/yup)
[yup - npm](https://www.npmjs.com/package/yup)
[react-hook-form + yup tips](https://zenn.dev/highgrenade/articles/c378deb2ec3eea)
[【Next.js】React Hook FormとYupを使って入力フォームを実装してみた。](https://note.shiftinc.jp/n/n556aa98eac9c)
[フォームのバリデーションに役立つYupとは？ React向けライブラリを解説](https://codezine.jp/article/detail/13518)
[React-hook-formとyupを使ったバリデーションの実装](https://qiita.com/AQUA651/items/b14e92b1bb1187a9bc6a)
【paizaラーニング】レベルアップ問題集 ソートメニュー応用編 「ペアソート」 PHP　

## 解答例
皆さん、こんにちは:raised_hand::cow:
<=>という訳の分からない演算子を使って解きました。
**三方比較演算子**、**宇宙船演算子**というらしいです。かっこいいので**宇宙船演算子**と呼びます。(宇宙船ぽいからこの名前？)
```
<?php
    $n = intval(trim(fgets(STDIN)));

    $a = [];
    for ($i = 0; $i < $n; $i++) {
        [$a0, $a1] = explode(' ', trim(fgets(STDIN)));
        $a[] = [$a0, $a1];
    }
    // 上記の処理は２次元配列を作成する
```
上の処理は割愛。
```
    usort($a, function ($a, $b) {
    // ユーザー定義の比較関数を使用して配列をソートする
        return $a[1] <=> $b[1];
        // ２列目のほうが優先度が低いので、宇宙船演算子を使い、先にソート
    });
    usort($a, function ($a, $b) {
        return $a[0] <=> $b[0];
        // １列目のほうが優先度が高いので、宇宙船演算子を使い、あとにソート
    });
```
上記のsortが肝になると思います。
連想配列で試しましたが、重複する値があるので、sortした際に重複した値が消えてしまい使えません。
なので二次元配列で考えてみました。そして、値が重複した際にも比較ができるような、ユーザー定義のsort関数を作成しました。
そこで**宇宙船演算子**（かっこいい...）を使用しています。
処理の細かい解説は、コメントを参照してください。
```
    foreach ($a as $pair) {
        echo implode(' ', $pair) . "\n";
    }
?>
```
あとは、出力して完了です。

#### 参考文献
こちらの記事を参考にさせていただきました。


https://qiita.com/ZampieriIsa/items/92b258dbfa30eb20208b

問題

https://paiza.jp/works/mondai/sort_advanced/sort_advanced__problems_speedup_step4
Day畳み込みの結合律

## 結合律
[前回](https://qiita.com/289CH4n/items/e7cb178cdacc64f229c0)定義したDay畳み込みには単位元が存在した．
今回はDay畳み込みには結合法則が成り立つことを確認する．
圏$\mathscr{C,D}$をモノイダル圏とし，$F_\mathscr{D}^\mathscr{C},G_\mathscr{D}^\mathscr{C},H_\mathscr{D}^\mathscr{C}$をモノイダルプロ函手とする．
```math
\begin{align}
(F\star(G\star H))_\mathscr{D}^\mathscr{C} &= \overline{\bigoplus_{\substack{A,C\in\mathscr{C}\\B,D\in\mathscr{D}}}}F^{(A)}_{(B)}(G\star H)^{(C)}_{(D)}\Delta_{(A\otimes C)}^{\mathscr{C}}\Delta^{(B\otimes D)}_{\mathscr{D}}\\
&= \overline{\bigoplus_{\substack{A,C\in\mathscr{C}\\B,D\in\mathscr{D}}}}F^{(A)}_{(B)}\left(\overline{\bigoplus_{\substack{W,Y\in\mathscr{C}\\X,Z\in\mathscr{D}}}}G^{(W)}_{(X)}H^{(Y)}_{(Z)}\Delta_{(W\otimes Y)}^{(C)}\Delta^{(X\otimes Z)}_{(D)}\right)\Delta_{(A\otimes C)}^{\mathscr{C}}\Delta^{(B\otimes D)}_{\mathscr{D}}
\end{align}
```
積とコエンドは交換するので，
```math
\begin{align}
&= \overline{\bigoplus_{\substack{A,C,W,Y\in\mathscr{C}\\B,D,X,Z\in\mathscr{D}}}}F^{(A)}_{(B)}G^{(W)}_{(X)}H^{(Y)}_{(Z)}\Delta_{(W\otimes Y)}^{(C)}\Delta^{(X\otimes Z)}_{(D)}\Delta_{(A\otimes C)}^{\mathscr{C}}\Delta^{(B\otimes D)}_{\mathscr{D}}\\
&= \overline{\bigoplus_{\substack{A,W,Y\in\mathscr{C}\\B,X,Z\in\mathscr{D}}}}F^{(A)}_{(B)}G^{(W)}_{(X)}H^{(Y)}_{(Z)}\Delta_{(A\otimes(W\otimes Y))}^{\mathscr{C}}\Delta^{(B\otimes(X\otimes Z))}_{\mathscr{D}}\\
&\simeq \overline{\bigoplus_{\substack{A,W,Y\in\mathscr{C}\\B,X,Z\in\mathscr{D}}}}F^{(A)}_{(B)}G^{(W)}_{(X)}H^{(Y)}_{(Z)}\Delta_{((A\otimes W)\otimes Y)}^{\mathscr{C}}\Delta^{((B\otimes X)\otimes Z)}_{\mathscr{D}}\\
&= \overline{\bigoplus_{\substack{A,C,W,Y\in\mathscr{C}\\B,D,X,Z\in\mathscr{D}}}}F^{(A)}_{(B)}G^{(W)}_{(X)}H^{(Y)}_{(Z)}\Delta_{(A\otimes W)}^{(C)}\Delta_{(D)}^{(B\otimes X)}\Delta_{(C\otimes Y)}^{\mathscr{C}}\Delta^{(D\otimes Z)}_{\mathscr{D}}\\
&= \overline{\bigoplus_{\substack{C,Y\in\mathscr{C}\\D,Z\in\mathscr{D}}}}\left(\overline{\bigoplus_{\substack{A,W\in\mathscr{C}\\B,X\in\mathscr{D}}}}F^{(A)}_{(B)}G^{(W)}_{(X)}\Delta_{(A\otimes W)}^{(C)}\Delta_{(D)}^{(B\otimes X)}\right)H^{(Y)}_{(Z)}\Delta_{(C\otimes Y)}^{\mathscr{C}}\Delta^{(D\otimes Z)}_{\mathscr{D}}\\
&= \overline{\bigoplus_{\substack{C,Y\in\mathscr{C}\\D,Z\in\mathscr{D}}}}(F\star G)_{(D)}^{(C)}H^{(Y)}_{(Z)}\Delta_{(C\otimes Y)}^{\mathscr{C}}\Delta^{(D\otimes Z)}_{\mathscr{D}}\\
&=((F\star G)\star H)_\mathscr{D}^\mathscr{C}
\end{align}
```
## モノイダルプロ函手の圏
モノイダル圏$\mathscr{C,D}$に対してモノイダルプロ函手の圏$\mathbb{Prof}(\mathscr{C,D})$を考えることができる．
$\mathbb{Prof}(\mathscr{C,D})$は対象をプロ函手$\mathscr{C\times D}\to\mathbb{Set}$射をその間の自然変換で定めたものである．
このモノイダルプロ函手の圏は$(\mathbb{Prof}(\mathscr{C,D}),\star,J)$の三つ組みでモノイダル圏となる．

$J$の定義は[前回](https://qiita.com/289CH4n/items/e7cb178cdacc64f229c0)を参照すること．
Dataverseテーブルの所有者の移行について

大規模なアプリになってくると、部署横断でかつ階層構造を含む多くのチームやユーザーに対してアプリを共有することになるかと思いますが、その時にデータへのアクセス権限（セキュリティロール）はとても重要です。

※ユーザー個別にセキュリティロールを割り当てしていくのは大変なので、部署とチーム(EntraIDのSG)とセキュリティロールを組み合わせると、ユーザの更新作業はPower Platform側からしなくてよくなるので管理者は楽になります。

データへのアクセス権限は、アクセスレベル＋特権でセキュリティロールを規定・付与することで制御することができます。
下図にも書いてありますが、「所有者」フィールドの値がデータアクセスの根幹となるキーになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/8c34a613-6973-3f0a-f99a-ec2579e44ed5.png)

一方で、データフローやExcel/CSVなどによるデータのインポートでは、この「所有者 (Ownerid)」などのシステムフィールドの移行がサポートされていないために、これらのフィールドに関しては毎回取り込み時に新しいデータに書き換わってしまうという性質があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/e1cf2b9e-ff6e-696b-7ebb-d7e964f3e6bb.png)

もちろん移行元がDataverseならその環境をコピーできますし、所有者などもそっくり保持してコピーすることが可能ですので、本番移行のシナリオでは、まず移行元から移行先のサンドボックス環境へコピーし、移行先のサンドボックス環境を実稼働環境へ変換するといった対応でデータ移行が可能かと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/e7d019c1-f78e-d3cb-a3c8-4903af2caf68.png)

一方で、別システムやExcelファイルなどから、まずDataverseのサンドボックス環境などにデータを取り込む必要がある場合は、書き変わってしまう問題に何とかして対応しなければいけないシーンがあるかと思います。そちらに関してはデータ取り込み後、Power Automateで後処理として所有者を変更していくことで対応できるかと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/023f814b-493e-ab2b-444c-4b996d555085.png)

Power Platformで大規模システムの構築・データ移行などある場合は、一筋縄ではいかないケースも出てきますので、ぜひMicrosoftにもご相談ください。
Neovim + Gitのサブモジュールで出るC / C++のヘッダファイルのNot Foundエラーを消す

【経緯】
Neovim上でC/C++のコードを書いている時に、独自ヘッダファイルがNot Foundになったので原因を調べました。いまさら感は拭えないですが、解決しないとコード補完ができなくて困るので、とりあえずNot Foundエラーを消すところまでを簡単にまとめます。

【環境】
|   |  |
|:-:|:-|
|O    S|Pop!_OS 22.04 LTS|
|Neovim|v.0.10.0|
|GitHub|メインプロジェクト ＋ サブモジュール|
|言   語| C / C++|

とりあえず、GitHubのリポジトリでサブモジュール登録の仕方については、[[GitHub公式]](https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%81%95%E3%81%BE%E3%81%96%E3%81%BE%E3%81%AA%E3%83%84%E3%83%BC%E3%83%AB-%E3%82%B5%E3%83%96%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB)が細かく解説してあってわかりやすいので、サブモジュールの使い方に詳しくない人は一度見てみると良いと思います。

Neovimのコード補完については、Neovim+LSPを設定&使用しています。

そういえば、独自ヘッダがNot Foundになる前に、　~~標準ライブラリでもエラー~~ "'iostream' file not found" になっていたので、解決法を。

```diff_shell:bash
- $ sudo apt install gcc-12
+ $ sudo apt install g++-12
```

これで、C++の標準ライブラリファイルがインストールされます。
おっきな勘違いしてたのだけど、コンパイラがClang++だろうが、g++だろうが、同じ標準ライブラリを見にいくんですね。よく考えてみればそりゃそっか、なんだけど、最初のうちはてっきりそれぞれ違う標準ライブラリファイルを見にいくんだと思っていました。

さて、次に本題の独自ヘッダファイルのNot Foundエラーについて。

[[clangdで別ディレクトリのヘッダーを指定したい]](https://qiita.com/sudo00/items/99d9619de38574830f65)
[[uchan note]](https://uchan.hateblo.jp/entry/2018/12/29/104132)

⇑のページでcompile_flags.txtを設定すれば良いことが判る。

ちなみに、ディレクトリ構成は次のように設定していた。

```shell:bash
$ tree ./
./
├── CMakeLists.txt
├── LICENSE
├── README.md
├── build
├── common
├── compile_flags.txt
├── getopts　⇐ ここがサブモジュール
│   ├── LICENSE
│   ├── README.md
│   ├── common
│   │   ├── CMakeLists.txt
│   │   └── getopts.cpp
│   └── include
│       └── getopts.hpp
├── include
├── layd.cpp
└── options
```

Not Foundの該当ファイルはというと、./getopts/include/getopts.hppで、ヘッダファイルのインクルード文はディレクトリなしの#include "getopts.hpp"を指定していました。
で、なんでNot Foundになってたかというと、cppファイルとhppファイルは別ディレクトリにしていたから。それとあとひとつ。compile_flags.txtに
以下のように書いてみたんだけど、これでは解決できず。

```shell:compile_flags.txt
-I.
-I./include
-I./../include
```

怪しいのは３行目というところまではすぐわかった。が、どう直せばよいか解らず。暫くネット検索で解決策を探していたけどやはり解らず。で、３行目を書き換えながら気がついたのが、getoptsディレクトリはGitHubのサブモジュールで、その場合-Iオプションに設定するパスは相対パスだと、うまく認識してくれないということ。そこではっ？！と気がついた。じゃあ、絶対パスだったらうまくいくんじゃね？と。
で、３行目を下のように書き換えてみた。

```shell:compile_flags.txt
-I./getopts/include
```

エラー消えたあたたたたた！ヽ(=´▽`=)ﾉ

ということで、GitHubのサブモジュールを使っている場合、compile_flags.txtに-Iオプションを絶対パスで指定すればヘッダのインクルードがNot Foundになるのが解決できます。
ちなみに、Gitのサブモジュールではなくて、単なるサブディレクトリの場合、３行目の最初の書き方でもNot Foundエラーは出ません。

最初に、簡単にまとめるとか書いときながら、なんだかんだで微妙に長い解説になってしもた。

というわけで、未来の自分が忘れた時に、解決の一端に慣ればよきかな。
また、同じような内容で困っている方の一助になれば嬉しいです。

最後までお読み頂き、ありがとうございます！