OmniAICreator/Qiita-1.07M huggingface dataset:
文字の順序を問わず全ての部分文字列を出力するプログラム

引数に与えられた文字列に何の文字列が含まれているか、全ての部分文字列を出力するプログラムです。文字列中の文字の順序の違う文字列も全て出力します。

itertoolsモジュールのpermutationsを使っています。

名前を'per.py'といいます。ソースをコピペした後、
`chmod +x per.py`
として実行権限をつけて動かして下さい。

2023年8月23日　メモリ節約のため、shiracamusさんの指摘通りにコードを書き換えました。

```per.py
#!/usr/bin/python3
import sys
import itertools

if len(sys.argv)==2:
    per=list(sys.argv[1])
else:
    print("Usage: per.py <string>")
    exit(1)
for i in range(1,len(per)+1):
    for j in itertools.permutations(per, i):
        print("".join(j))
```

例えば、catでは次のようになります。

```
$ per.py cat
c
a
t
ca
ct
ac
at
tc
ta
cat
cta
act
atc
tca
tac
```

### 実践

長い文字列では膨大な出力数になりますので、時間がかかるでしょう。

例えば、maekawataisukeに含まれるひらがなの単語を全部出力するには、以下のようにします。

```
$ per.py maekawataisuke |rk|grep -x -i -f - ~/dic/jm.txt

```

大量のメモリを消費し、/tmpの容量が足りなくなるので、/tmpを大容量Diskに移してします。

https://qiita.com/fygar256/items/ff543eaad27e668f2a16


maekawataisukeに含まれる全ての英単語ならば次のようです。

```
$ per.py maekawataisuke|grep -x -i -f - ~/dic/dic.txt
```

ここで、rkはローマ字かな変換、dic.txtは英単語だけの辞書、jm.txtはひらがなの単語だけの辞書です。
Unity mesh.vertices更新時のエラー回避

# コード
```
            
            //新しい頂点が少ない場合、頂点データを先に更新すると、
            //その瞬間だけ三角形が更新できなくてエラーになるので順序を変える
            if (newVerts.Count()<mesh.vertexCount)
            {
                mesh.triangles = triangles.ToArray();
                mesh.vertices = newVerts;
            }
            else
            {
                mesh.vertices = newVerts;
                mesh.triangles = triangles.ToArray();
            }

            // メッシュの更新
            mesh.RecalculateBounds();
            mesh.RecalculateNormals();

```
CKAD) Dockerfile コマンド解説

# Dockerfileの定義
- コンテナビルドのためのコマンドの集合
- イメージ生成のための要素

|Dockerfile コマンド|内容|
|------|---|
|FROM| コンテナの基本になるイメージ（運営環境）|
|LABEL| コンテナビルドの情報、バージョンなどの情報を提供|
|RUN| コンテナビルドのビルドのため、イメージから実行するコマンド|
|ADD| コンテナのビルド時に、ホストのファイル（tar, urlなど）をコンテナにコピー|
|COPY| コンテナのビルド時に、ホストのファイルをコンテナにコピー|
|WORKDIR| コンテナビルド時にコマンドを実行するコマンドDirectoryを設定|
|ENV| 環境変数の設定|
|USER| コンテナおよび、コンテナを実行時に適応するユーザ設定|
|EXPOSE| コンテナ実行時に外部から実行するポートの指定|
|CMD| コンテナ動作時に自動て実行するサービスやスクリプトの指定|
|ENTRYPOINT| CMDと一緒に利用し、COMMAND指定時に利用|


## 例1
```Dockerfile
FROM centos:7.5.1804
RUN yum install httpd -y
RUN echo "hello world" > /var/www/html/index.html
CMD ["/usr/sbin/httpd", "-DFOREGROUND"]
```

## 例2
- 次の条件で`appjs:latest`コンテナをビルドしなさい
  -  ビルドDirectory: `~/app_build/appjs`
  -  `/data/ckad/app.js`のファイルを`~/app_build/appjs`に移動した上で、次の条件に合わせてコンテナをビルドしなさい
     - base image: `node:12`
     - `app.js`ファイルをコンテナ`/`Directroyにコピー
     - コンテナ実行時に`node`、`app.js`が実行されるべき
```Dockerfile
FROM node:12
COPY app.js /
ENTRYPOINT ["node", "app.js"] 
# CMD ENTRYPOINT ["node", "app.js"]
```

# Docker iamge の作成

```shell
docker build -t appjs:latest .
docker run --name appjs -p 8080:8080 -d appjs
```
【AWS】S3 ストレージクラスの特徴


| タイプ | 特徴 | 
| --- | --- | 
| STANDARD | ・ <font color="darkorange">**自動管理**</font>複数個所に保存されるため、耐久性が非常に高い<br>・頻繁にアクセスされるデータを大量に保存するのに向いている<br>・S3の中では<font color="darkorange">**一番コストが高い**</font> | 
| STANDARD-IA | ・低頻度アクセス用<br>・マスターデータ向け<br>・取得は早い | 
| ONE-ZONE-IA | ・STANDARD IAの重要度を落としたバージョン<br>・<font color="darkorange">**マルチAZではなく可用性が低い**</font>ため低コスト | 
| Intelligent-Tiering | ・アクセス頻度が <font color="darkorange">**予測できない(変化する)**</font>場合に有効<br>・S3オブジェクトのアクセスパターンを監視し、利用頻度の低いオブジェクトを低頻度のアクセス層に移動する | 
| Glacier Flexible Retrival (無印)| ・ほとんどアクセスされることがないアーカイブデータ用<br>・取り出しに <font color="darkorange">**3～5 時間**</font><br>・<font color="darkorange">**迅速取り出しで2～5分**</font><br>・<font color="darkorange">**大容量取り出しで3～12時間**</font> |
| Glacier Instant Retrival | ・ほとんどアクセスされることがないが、取り出しを瞬時に行う必要があるアーカイブデータ用<br>・取り出しに <font color="darkorange">**3～5 時間**</font> |
| Glacier  Deep Archive | ・ほとんどアクセスされることがない、かつ取得に時間がかかっても問題がないアーカイブデータ用<br>・S3の中で最もコストが低い<br>・取り出しに <font color="darkorange">**最大12時間**</font> |

S3オブジェクトの利用頻度に合わせてタイプを決めて、ライフサイクルポリシーで Glacier に移動。というのがベター。ライフサイクル期間をどの程度に設定するかはその組織のコンプライアンス等、情報管理規定で決まってくると思われる。


**アクセス頻度** ━━━━━━━高い━━━━━━━━━━━━━━━━━━＞Standard
　┃┃┃
　┃┃┗━━━低い━━━━━━━**重要度**━━━━━重要━━━━━━━>> Standard IA
　┃┃　　　　　　　　　　　　　　┃
　┃┃　　　　　　　　　　　　　　┗━━━━━━重要でない━━━━>> One-Zone-IA
　┃┃
　┃┗━予測できない(変化する)━━━━━━━━━━━━━━━━━━━>> Intelligent-Tiering
　┃
　┗━━極めて低い━━━━**データ取得の許容時間**━━━━数時間━━━━>> Glacier
　　　　　　　　　　　　　　　　　┃
　　　　　　　　　　　　　　　　　┗━━━━━━━━12時間まで━━━>> Glacier Deep Archive


Inteligent-Tiering でいい感じにコスト削減できる事例がけっこうありそう
https://techblog.locoguide.co.jp/entry/2023/05/15/153931

https://dev.classmethod.jp/articles/should_i_choice_s3_storage_class/
【ChatGPT】OpenAIのアカウントを作るときのログイン情報は慎重にきめよう

OpenAIのアカウント関係でちょっと困ったので、メモとして書き残しておきます。

*正確な情報については公式サイトを参照することを強くおススメします。

ChatGPT、楽しんでいますかー！
ChatGPTは、おなじみ、非常に高性能な人工知能チャットボットです。

やってみようと思ったら、（他サービスを通さないなら）だいたい、OpenAIアカウントに登録することになると思いますが、ChatGPTは、登録したログイン情報の変更が非常にむずかしいです。

「へー、試してみるか」と気軽に捨てアドでちゃちゃっと登録する前にいったん深呼吸しましょう。

## 一度登録したOpenAIのアカウントのメールアドレス変更できない！

捨てアドで登録したけど、やっぱそれなりに使っているアドレスにするか。

思い立ったとしても、OpenAIのアカウントに結びついているメールアドレスは変更できません（Currentlyということですが……）。

>Currently, we do not support updating the email address associated with your account. New email addresses can be added to your account through the Members page. 

（足すことはできるらしい）

https://help.openai.com/en/articles/4936827-can-i-change-my-email-address

とりあえず捨てアドで登録して遊ぼう、とすると、あとあと困ったことになるかと思います。

## OpenAIのアカウントで登録できる電話番号は2アカウントまで！

OpenAIのアカウントではSMSによる電話番号認証が必要です。
これのアカウントは、1つの番号で2アカウントまでとなっています。

OpenAIのChat APIなどのAPIのほうは、使用時にさいしょいくらか無料クレジット分がもらえるのですが、電話番号のほうに結びついているようです。
2アカウント目では当然無料クレジットはもらえません。まあそれはいいとして……。

この2アカウントまでの制限は、**アカウントを削除しても結びついていた情報は消えず、枠はあきません。**

https://help.openai.com/en/articles/6613520-phone-verification-faq

個人的に「よっしゃ、プライベートと仕事のを分けるか」と２つとっていたら、
「お仕事のメルアドでとってくれ」と言われて、ちょっと困る場面がありました。
サポートに問い合わせてみたのですが、ダメでした。

サポートからの返信の抜粋：
>Each phone number can only be used to verify a maximum of two unique accounts.
Previously deleted accounts still count toward our two accounts per number limit. If this is your second account, you should be able to use the same phone number as before without any issue.
For anti-fraud and abuse reasons, we do not allow unlinking of phone numbers. The 2 unique OpenAI sign ups limit still applies.

1個の電話番号に結び付けるのは2つまで、また消したアカウントでもカウントするよということです。

「消したら電話番号の枠があかないかな」と思って気軽に消してしまったんですが、消してしまう前にアドレスの追加でできないか検討するべきだったなあ、と思っています。

というわけで、**OpenAIのログイン情報はあんまり変えられなくて厄介なので、慎重にね！**

OpenAIのアカウントを試しに作るときは注意です。
ログイン情報（メールアドレス・電話番号）がほぼ変えられません。

個人的には、メールアドレスよりかは、MicrosoftアカウントやGoogle Account、AppleIDでログインしちゃうのが楽だと思います。
そして、電話番号の登録上限にはお気をつけて！
誤回答(TLE)メモ - LeetCode Weekly359 Find the Longest Equal Subarray:  Two pointer + 二分探索

誤ったアプローチです。記録に書いておきます。アプローチは悪くはなかったと思っていたんだけどそういう問題ではなかった...

https://leetcode.com/contest/weekly-contest-359/problems/find-the-longest-equal-subarray/

# 題意
- $1e5$の以内の数字が$1e5$個、数列として与えられます。その中から$k$個以内の数字を消してよいです。同じ数字が続く連絡した部分列を良い部分列と呼びます。
- 作れる最大の部分列の長さを答えよ。

# 想定解法(TL, solution議論)
値ごとにリストを作り、ある$l$に対して、indexが欠けている数が$k$以下であるような$r$をスライディングウィンドウ。$O(N)$

# こう考えた(誤回答): two-pointer + 二分探索
ある長さ$a$がつくれるかを判定する。$a$がつくれるとはあるiに対して$[i, i+a+k-1]$においてある文字がa個以上含まれていれば良い(これを`判定`と呼ぶ)。なぜなら、ある文字が最低$a$個含まれているなら他の文字を$k$個消せばある文字だけの長さ$a$の部分数列とできる。
```
     0  1  2  3  4  5  6  7  8
例: [1, 2, 3, 3, 4, 4, 3 ,3, 1]
           ^^^^^^^^^^^^^^^^
k = 2の時、[2,7]でind=4,5を消して[3,3,3,3]の長さ4が答え
```
値域が$1e5$程度なので次のように考える。
最初にi = 0として、最初のウィンドウ$[i, i+a+k-1]$の各値の出現頻度を数えておく。判定成功なら達成できる。two-pointerの要領でシフトをずらしてく。

一点変更区間maxが出来れば良いのでセグメント木などで実装できる。この操作に必要な計算量は$O(N log N)$。

元の問題の答えは二分探索可能($a$が達成な時$a-1$は明らかに達成できる)なので二分探索する。

以上により$O(N (log N)^2)$...TLEしました。

## 実装(TLE)

```c++
#define FOR(i, begin, end) for(int i=(begin),i##_end_=(end);i<i##_end_;i++)
#define REP(i, n) FOR(i,0,n)
using namespace std;
using namespace atcoder;
long long  op(long long a, long long b) { return max(a, b); }
long long e() { return -1; }
class Solution {
public:
    int longestEqualSubarray(vector<int>& nums, int k) {
        int n = (int)nums.size();
        int ans = -1;
        auto func = [&](long long target) -> bool{
            if(n < target) return false; // n以上というのはどう考えても無理
            int flen = min(n, target+k); // 最初のウィンドウの長さ. max n.
            int l = 0; // ここから取り込んでいる
            int r = flen - 1; // ここまでは取り込んでいる
            vector<long long> initseg(n+1);
            REP(i, flen) { // 最初の読み込み
                //cerr << "initload" << nums.at(i) << endl;
                ++initseg.at(nums.at(i));
            }
            segtree<long long, op, e> seg(initseg);
            // 最初のトライで既にtarget以上の要素がいるならok
            if(seg.all_prod() >= target) return true;
            // シフトしていく
            while((r+1) < n){
                r++; // rに関しては入れていけばok
                seg.set(nums.at(r), seg.get(nums.at(r)) + 1); // 更新する
                // lは抜けていくので
                seg.set(nums.at(l), seg.get(nums.at(l)) - 1); // 更新する
                l++;
                if(seg.all_prod() >= target) return true; // この状態でOKなら抜ける
            }
            return false;
        };
        // [ok, ng) for max value いける最大の値を求めたいとき
        // (ng, ok] for min value 可能となる最小の値を出したいとき
        // CATION: ok is result  (NOT mid)
        int ok = 0;
        int ng = n+100;
        int mid;
        while(abs(ok - ng) > 1){
            mid = (ok + ng) / 2;
            if(func(mid)) ok = mid;
            else ng = mid;
        }
        //assert(ans != -1);
        return ok;
    }
};
```

https://leetcode.com/contest/weekly-contest-359/submissions/detail/1026317910/
AWS CDK エラー対応

# 概要

- CDK で直面したエラーをこれからこの記事に追記していきたい


## Another CLI (PID=1) is currently synthing to cdk.out. Invoke the CLI in sequence, or use '--output' to synth into different directories.

- コンテナから CDK を実行した場合に発生
- 解決策は `cdk.out` をディレクトリごと削除
AIが進歩してもエンジニアを続けられる理由

## この記事は？
この記事は、ChatGPTなどAIが進歩し、エンジニアが主業としてきたコーディング領域をAIでできるようになっても、まだエンジニアとして活動できる理由を説明します。

### 1. まだまだAIが返す情報の精度が低い
筆者はエンジニアとして、インフラやバックエンド実装など行い、ChatGTP4など最新の生成AIにそれらの相談をすることもありますが、返す情報はまだまだ精度が低く、最終的にはGoogleで調べたり、コードを見たり、チームメンバー間で話し合ったりして人間が解決することが多いです。また、会社特有の開発事情をAIが汲み取ってくれるわけではない(例えば、社内が昭和くさく、調整や会議が多いことを考慮してほしいとか、メンバーの感情面を汲み取ってほしいなど)ので抽象的なことに対する壁打ちとして使うのが精一杯です。これらの部分は、自身が開発や組織的な政治に長けてやっていく他現状はない印象です。
### 2. 細かい部分を調整したいニーズ
1とも被りますが、開発では往々にして細かい部分を調整しつつ実装していく必要があります。例えば、テストコードなどは正しく書かないと、品質管理できないが生成AIでテストコードを実装させ、それが間違っていると、おおむね合っているが一部間違っていて、品質管理に欠陥が出てしまいます。そう言った細かい箇所は技術的にも難度は高いが、間違うとどこかが(テストの場合は品質管理が)命取りになるので意外と重要度は高いと思います。
### 3. AI以外の部分で生き残っていける
単純なマークアップでのコーディングなど、そう言った単純作業に関してはAIに任せ、エンジニアとして磨いてきたロジカルさや人脈を活かして生き残っていく方法もあると思います。例えば、フロントエンドであればSEOを追ってきているため検索最適に強いことで、デジタルでの集客に活かせる部分は大きく、人を集めることはビジネスの要であるため優位に働いたり、エンジニア以外にも転換可能なスキルは多いです。特に直接人を集めることは、機械がまだ不得意な人間との折衝部分も絡むので、勝機があると言えます。

### 4. 作業効率で色々なことに時間を割ける
1.でAIの限界について述べた一方で、ChatGPT4などのAIを使えば、知らない言語について基礎を教えてくれたり、情報を集約してくれるので、今まであちらこちらで調べていたことの時間短縮になり、作業効率ツールなどの時間短縮ツールの作成まで教えてくれるので、多方面で時間短縮になります。最近ではエンジニア以外も複業している人は多く、筆者も、接客をしながらエンジニアをしていた時期がありましたが、こういったAIの恩恵による時間短縮で色々なことに時間的余裕を持って挑戦しやすく、エンジニア以外にもバランスよくスキルに投資できるので、心配なくエンジニアも並行できると言って良いでしょう。

### 終わりに
この記事では、AIが進歩してもエンジニアを続けられる理由を説明しました。将来が心配なエンジニアは参考にしてみてください。
OpenCoverのメモ



# NuGetパッケージ
Microsoft.TestPlatform
Microsoft.DiaSymReader.Native

# バッチファイル

```
@ECHO OFF
SET PJNAME=OpenCoverSample

set filters=+[%PJNAME%]* -[*Test]*
SET TESTDLL=%PJNAME%Tests\bin\Debug\OpenCoverSampleTests.dll

SET TIME2=%TIME: =0%
SET LOGDIR=%DATE:/=-%_%TIME2:~0,2%_%TIME2:~3,2%_%TIME2:~6,2%
SET LOGDIR=results

SET LOGGER=/logger:trx;LogFileName=results\result.trx
SET DIAG=/Diag:OpenCover\results\result.log
SET XMLFILE=OpenCover\%LOGDIR%\OpenCover.xml
SET RESULTSDIRECTORY=/ResultsDirectory:OpenCover

SET VSTESTCONSOLE=packages\Microsoft.TestPlatform.17.7.1\tools\net462\Common7\IDE\Extensions\TestPlatform\vstest.console.exe
SET OPENCOVER=packages\OpenCover.4.7.1221\tools\OpenCover.Console.exe
SET REPORTGENERATOR=packages\ReportGenerator.5.1.24\tools\net47\ReportGenerator.exe

IF NOT EXIST "OpenCover\%LOGDIR%" (
  ECHO ======================================================================
  ECHO MKDIR OpenCover\%LOGDIR%
  ECHO ======================================================================
  MKDIR "OpenCover\%LOGDIR%"
)

ECHO ======================================================================
ECHO OpenCover.Console.exe
ECHO ======================================================================
"%OPENCOVER%" -register:user "-filter:%filters%" "-target:%VSTESTCONSOLE%" ^"-targetargs:\^"%TESTDLL%\^" \^"%RESULTSDIRECTORY%\^" \^"%LOGGER%\^" \^"%DIAG%\^"" "-output:%XMLFILE%"

ECHO ======================================================================
ECHO ReportGenerator.exe
ECHO ======================================================================
"%REPORTGENERATOR%" "-reports:%XMLFILE%" "-targetdir:OpenCover\%LOGDIR%\html"

pause
```

# MSBuildタスクでOpenCoverを使用する
```XML
  <PropertyGroup>
    <OpenCoverMSBuildTasksPath>$(MSBuildProjectDirectory)\..\packages\OpenCover.4.6.519\MSBuild</OpenCoverMSBuildTasksPath>
  </PropertyGroup>
  <Import     Project="..\packages\OpenCover.4.6.519\MSBuild\OpenCover.targets"
    Condition="Exists('..\packages\OpenCover.4.6.519\MSBuild\OpenCover.targets')"/>
  <Target Name="coverage">
    <OpenCover
      ExcludeByAttribute="System.ObsoleteAttribute"
      Filter="+[*]* -[*Tests]*"
      Register="True"
      Output="bin\Debug\coverage.xml"
      Target="..\packages\Microsoft.TestPlatform.15.8.0\tools\net451\Common7\IDE\Extensions\TestPlatform\vstest.console.exe"
      TargetArgs="bin\Debug\OpenCoverSampleTests.dll /ResultsDirectory:bin\Debug /logger:trx;LogFileName=coverage.trx /Diag:bin\Debug\coverage.log"
      ToolExe="OpenCover.Console.exe"
      ToolPath="..\packages\OpenCover.4.6.519\tools\">
      <Output TaskParameter="ExitCode" PropertyName="TestExitCode"/>
    </OpenCover>
  </Target>
```
2023: Week 33 - HR Month - Combinations / Preppin' Data / Tableau Prep

# Challenge Preppin'Data 2023:Week 33

## 概要
### 在職年数(tenere_years)と在職月数（tenure_months）

各従業員の在職年数(tenere_years)と在職月数（tenure_months）を計算します。従業員の入社日(hire_date)から月末(month_end_date)または退社日(leave_date)までの在籍月数（満月数）を求めます。在職年数（tenure_years）については、在職月数（tenure_months）を通年に換算します。32ヶ月は2年の在職期間となります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/f0bc20c9-285d-832f-7d22-830a34299c82.png)

### DC、月、デモグラフィックデータごとのサマリーデータ

DC、月、デモグラフィックデータ（世代名/性別/国籍/年代/在職年数）ごとに従業員数をカウントしたサマリーデータを作成します。DC、月、デモグラフィックデータ（世代名/性別/国籍/年代/在職年数）の組み合わせで存在しない組み合わせは、従業員数0（ゼロ）のレコードを作成します。但し、DCの期間は、関連期間のみでよいです。

<p align="center">
    <img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/494a9d56-2477-2344-b70f-9c87125915fb.png">
</p>


## 問題のページ（英語）※ここからデータをダウンロード
https://preppindata.blogspot.com/2023/08/2023-week-33-hr-month-combinations.html

## 出題者の回答のページ（英語）※動画あり
https://preppindata.blogspot.com/2023/08/2023-week-33-solution.html

## 自分の解決法

<p align="center">
<img width="90%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/39f3b16f-dde8-7bcb-2fb6-520ff12dbf61.png">
</p>

<p align="center">
<img width="90%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/c9b06b66-dbcd-2833-0f77-f69dd7ed00fb.png">
</p>

* 今回のケースではUnionでなく、Pivotでも同じことが実装可能

<img width="90%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/fc2da25f-4334-4fc9-ba58-8e18ce372735.png">

* Pivotすることで、スマートにゼロの組み合わせのレコードが生成できるので、いろいろな方法で解いてみることがおすすめです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/f0c90782-4a80-9fbc-92d3-e0ee24fc6d4d.png)
【Mac】コマンドでフォルダをまとめる方法


## フォルダを統合する方法

次のコマンドを実行するとフォルダを統合できます。

```terminal
ditto 統合するフォルダ... 統合先フォルダ
```

以下のように実行すると`sample`フォルダの内容が`example`フォルダに統合されます。

```terminal
ditto sample example
```

同名のファイルが存在する場合には、`sample`フォルダ内のもので上書きされます。

複数のフォルダを統合することもできます。

```terminal
ditto sample1 sample2 example
```

上記のように実行すると`sample1`と`sample2`が`example`に統合されます。
同名のファイルが存在する場合には最後に記述したフォルダ内のもので上書きされます。

`-V`オプションをつけるとCopyのログを表示できます。

```terminal
diito -V 統合するフォルダ... 統合先フォルダ
```
知らなくても何とかなってしまうかもしれないpythonの基礎

# ■はじめに
~~雰囲気で~~pythonを使い始めてからはや１年弱。
教えてもらってから/資格勉強をしてから知ったが連発したのでまとめます。
知らなくても何とかはなりますが知ってるとコードが見やすくなったり、書く量が減ったりするかも。


# ■ 知らなくても何とかなってしまうかもしれない書き方
### ◇try: exceptの外のelse
try節の中身が最後まで実行される（exceptの処理にとばない）とelseの中身が実行されます。
例外処理が実行されるとelse内に書かれたprintは表示されません。
* 例外処理を通らない場合
```sample.py
try:
    print('処理１')
    # raise Exception('処理１の例外発生')
    
except Exception as e:
    print('処理1の例外エラー')
    print(e)

else:
    print('try-exceptの外のelse処理')

print('処理終了')
    
```

```cmd.exe
C:\demo> python sample.py
処理１
try-exceptの外のelse処理
処理終了
C:\demo>

```

* 例外処理を通る場合

```sample.py
try:
    print('処理１')
    raise Exception('処理１の例外発生')
    
except Exception as e:
    print('処理1の例外エラー')
    print(e)

else:
    print('try-exceptの外のelse処理')

print('処理終了')
    
```

```cmd.exe
C:\demo> python sample.py
処理１
処理1の例外エラー
処理１の例外発生
処理終了
C:\demo>

```

### ◇for文の外のelse
for文が中断されずに正常に終了した場合のみelseの中身が実行されます。
continueで処理がスキップした場合も正常終了の判定なのでelseの中身も実装されます。
* for文が中断された場合
```sample2.py
numbers = [1, 2, 3, 4, 5]
for num in numbers:
    if num == 3:
        print("中断されました")
        break
    print(num)
else:
    print("ループが正常に終了しました")
print('処理終了')
    
```

```cmd.exe
C:\demo> python sample2.py
1
2
中断されました
処理終了
C:\demo>
```

* for文が正常終了した場合
```sample2.py
numbers = [1, 2, 3, 4, 5]
for num in numbers:
    # if num == 3:
    #    print("中断されました")
    #    break
    print(num)
else:
    print("ループが正常に終了しました")
print('処理終了')
    
```

```cmd.exe
C:\demo> python sample2.py
1
2
3
4
5
ループが正常に終了しました
処理終了
C:\demo>
```

### ◇辞書型のkey,valueをfor文のパラメータで使う
<辞書名>.items()を使用することキーとバリューの両方をパラメータとして使用することができます。

```sample3.py
comic_author = {
    "鋼の錬金術師" : "荒川弘",
    "ONE PIECE" : "尾田栄一郎",
    "BLEACH" : "久保帯人",
    "メイドインアビス" : "つくしあきひと" 
}
for comic,author in comic_author.items:
    print("作品：",comic)
    print("作者：",author)
```

```cmd.exe
C:\demo> python sample3.py
作品：鋼の錬金術師
作者：荒川弘
作品：ONE PIECE
作者：尾田栄一郎
作品：BLEACH
作者：久保帯人
作品：メイドインアビス
作者：つくしあきひと
C:\demo>
```


### ◇戻り値が複数
関数の戻り値として複数の値を設定することができます。
受け取り側で一つしか変数を指定しなかった場合はリストになります。

```sample4.py
def comics_authors():
    comic_list = ["鋼の錬金術師","メイドインアビス","青の祓魔師"]
    author_list = ["荒川弘","つくしあきひと","加藤和恵"]
    return comic_list, author_list

comics, authors = comics_authors()
print(comics)
print(authors)
list = comics_authors()
print(list)
```

```cmd.exe
C:\demo> python sample4.py
["鋼の錬金術師","メイドインアビス","青の祓魔師"]
["荒川弘","つくしあきひと","加藤和恵"]
[["鋼の錬金術師","メイドインアビス","青の祓魔師"],["荒川弘","つくしあきひと","加藤和恵"]]
C:\demo>
```


# ■ 終わりに
当たり前の内容かもしれないけど、個人的に言われるまで、学習するまで気がつかなかった仕様でした。
使うことでコードの可読性が上がったり全体として各量が減ったりするので積極的に使っていきましょう。
余談ですが、Python3エンジニア認定基礎試験を受けようと考えている人は少なくともこのあたりの知識を知らないと落ちます(実体験)。
証明書のピンニングをBypassする方法

# はじめに 
証明書のピンニングとは中間者攻撃を防止するための手段です。 
もしピンニングが有効になっているアプリの場合通信が見れません。
# 導入 
https://github.com/nabla-c0d3/ssl-kill-switch2/releases/tag/0.14

debをダウンロードしてFilzaなどでインストール
*PreferenceLoaderが必要です。別途インストールしておいてください

設定を開き SSL Kill Switch 2から
Disable Certificate ValidationをON
Excluded BundleIDsに通信解析に使うアプリのバンドル名を入力

CharlesProxyの場合com.xk72.Charles
# 別の手段
FLEXListの通信解析を使う
pygmtでカラーマップを新規作成したい場合

# はじめに
　pygmtを使用して、図を描画する機会があったが、pygmtで使用できるカラーマップが少なすぎる!となり、自作してみた。

# 参考にしたサイト
　以下のサイトを参考にした。
http://www.healthy-life-food.jp/2018/11/18/gmt-command-makecpt/

# PyGMTにおけるカラーマップ
　PyGMTとは、GMT(the generic mapping tool)と呼ばれる地図を描くためのオープンソースのソフトウェアツールをpythonで使用できるようにしたもの。
　地図の描画に強みがあり、日本地図に標高のグラデーションを入れたやつとかかっこよく作れる。

　しかし、かっこよく作るための一つの方法であるカラーマップについてはほとんど種類がなく、以下の24種類である。(余談だが、このカラーマップ自体も、PyGMTの公式サイトからは見つけられず、どういった種類のカラーマップがあるのか探すのさえ苦労した)
　そこそこ使えそうではあるが、単純に白から赤のグラデーションで密度出したいとかの時に使えるものがない...。初心者故、これまで基本的に既成のカラーマップに頼っていたが、作成することにした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3256521/f57fb1cd-87b8-e28d-4191-424e51f8071d.png)
(以下のサイトより参照：https://ccsr.aori.u-tokyo.ac.jp/~obase/gmttips.html)

# カラーマップ作成
　まず、カスタムのカラーマップ作成に使う関数が以下である。
```python
pygmt.makecpt(**kwargs)
```
詳しい説明は公式ドキュメントを参照してほしい。今回使う引数は、cmapになる。通常は以下のように、カラーマップの名前を記載する(defaultはrainbow)
```python
pygmt.makecpt(cmap="cool", series=[0, 10, 0.1])
```

が、今回は外部ファイルにカラーマップの詳細を記載し、その内容を取得する方針で行う(別関数を切って、そちらで中身の文字列を作成し、cmapに入れるという方向でもよいかもしれない)。コードは以下の通り。

```python
pygmt.makecpt(
    cmap="./red_transparent.cpt",
    series=[0, 10, 0.1]
)
```

そして、このred_transparent.cptに入る内容だが、以下のようにしている。
```python
# Color map from transparent to red
# COLOR_MODEL = RGB
0 255 255 255 1 255 254 254
1 255 254 254 2 255 253 253
2 255 253 253 3 255 252 252
...
253 255 2 2 254 255 1 1
254 255 1 1 255 255 0 0
B 255 255 255
F 255 255 255
N 255 255 255
```

意味は単純で、3行目の"0 255 255 255 1 255 254 254" が、値が0,1時のRGBの値(255,255,255)と(254,255,255)となっており、これが254まで書かれている。
Bは最小値を下回る値の時のRGB, Fは最大値を上回るときのRGB, NはNaN値に振り分けられるRGBである。

この内容でファイルが構成され、makecptでseriesが指定された際は、ファイルの値がseriesの最大、最小と合致するように修正されている(今回の例では、0→0, 255→10に変更されている)

※ちなみに、このファイルの書き方をミスると(変にタブキーを入れたり等)、特にエラーは出ずに、デフォルトのrainbowのカラーマップが使用されるので注意が必要


# 終わりに
　以上のように、カラーマップのファイルを自作しておけば、グラデーションカラーが色々必要になった際に使いまわせるので便利かなぁと思う。が、そもそももうちょっとグラデーションぐらい整備しておいてほしい...(もしかすると自分が知らない方法があるかもなので、ご存じでしたら教えてほしいです...)
Docker起動後に環境変数ファイルを作成して、別ユーザーに引き渡せるようにしたい

# docker-envsubst

## やりたいこと

1. Docker起動時に環境変数を指定する
2. Docker起動時に読み込んだ環境変数を基に、ローカルに環境変数ファイルを作成する
3. 別ユーザーでShellを実行した際、ローカルに作成した環境変数ファイルを読み込む

上記流れで処理する事で、Docker上で別ユーザー間の環境変数の引き渡しを行うことができるようにしたい。

### なんでそんな事をしたくなったのか？

Docker上でcronからShellファイルを実行するときに、Dcoker起動時の環境変数はそのままでは使えなかったので、一度環境変数ファイルを作成してShellからそのファイルを読み込ませる必要があったため。

---
## その他仕様

- docker-compose でDockerの定義をする
- docker-compose に環境変数を読み込む定義を記載する
- コンテナは常時起動させる

---

## ソースコード

### ファイル構成
ファイル構成はこんな感じになりました。

``` bash
.
├── Dockerfile
├── docker-compose.yml
├── env
│   └── app.env.template
└── shell
    └── run_init.sh
```

---

### docker-compose.yml

```yaml:docker-compose.yml
# コンテナ構築用docker-composeファイル
version: '3.2'

services:
  # アプリケーション用定義
  app:
    build:
      context: .
      dockerfile: ./Dockerfile
    container_name: app
    ports:
      - "8080:8080"
    # 環境変数を指定
    environment:
      - ENV_STRING=hoge
    #自動起動設定
    restart: always
    tty: true
```
---
### Dockerfile
```dockerfile:Dockerfile
#################################################
# コンテナの作成
#################################################
# ベースイメージ取得
# ベースイメージ取得(Amazon Correttoを利用)
FROM amazoncorretto:11
# 環境変数用ファイルをコピー
COPY ./env/* /tmp/env/
# shellのコピー
COPY ./shell/* /opt/shell/
# 初期設定(ライブラリのインストールなど)
RUN \
	# ========================================================
	# ライブラリをインストール
	# ========================================================
	yum -y update && \
	yum -y install util-linux shadow-utils gettext && \
	rm -rf /var/cache/yum/* && \
	yum clean all && \
	# ========================================================
	# 実行権限の付与
	# ========================================================
	chmod +x /opt/shell/*

# shellの実行
CMD ["/bin/sh", "/opt/shell/run_init.sh"]
```
---
### run_init.sh
```shell:run_init.sh
#!/bin/sh
# ========================================================
# 環境定義ファイルの作成
# ========================================================
# 環境変数用のディレクトリが無ければ作成
mkdir -p /var/env
# 環境変数ファイルの作成
envsubst < /tmp/env/app.env.template > /var/env/app.env

# 作成したapp.envを読み込む
source /var/env/app.env

# app.envで読み込んだ環境変数を標準出力する
echo ${STRING} > /var/log/test.log

#コンテナを起動し続ける
tail -f /dev/null
```
---
### app.env.template
```shell:app.env.template
##########################################################
#
# 環境変数
#
##########################################################
# 置換文字列
STRING=${ENV_STRING}

```
---
## GitHub
GitHubにも同様のソースを公開しています。

https://github.com/ferret000/docker-envsubst
dnfで特定のバージョンのパッケージをインストールする

## 目的
almalinuxを用いるとき、パッケージ管理ソフトはyumかdnfを用いると思う。今回はdnfを用いた時に特定のバージョンのパッケージをインストールする方法を解説する。

## 想定
phpをインストールする時はdefaultでversion7.2がインストールされてしまう。この時、8.0をインストールしたい。

## 確認
まずは、インストール出来るパッケージのリストを確認する。
```bash
dnf module list php
 
 AlmaLinux 8 - AppStream
 Name    Stream      Profiles                        Summary                                                  
 php     7.2 [d]     common [d], devel, minimal      PHP scripting language                                   
 php     7.3         common [d], devel, minimal      PHP scripting language                                   
 php     7.4         common [d], devel, minimal      PHP scripting language                                   
 php     8.0          

```

[d]が付いている所は、defaultでインストールされる。

## 設定
以下の設定をいれる
```bash
dnf -y module reset php && dnf -y module enable php:8.0
```

## インストール
```bash
dnf -y install php
```
Nest.jsアプリケーションをEC2インスタンス上で永続的に起動させる


## pm2を利用した手順

1. `pm2`のインストール
	```
	npm install -g pm2 
	```

2. Nestjsを`pm2`で起動
	```
	pm2 start npm --name your-app-name -- run start
	```
3.  `pm2` のプロセスリストを確認してアプリケーションが実行されていることを確認
	```
	pm2 list
	```
4.  `pm2` で起動したアプリケーションを自動的に再起動するように設定(コマンドを実行するように指示を受けるのでコピペして実行する)
	```
	pm2 startup
	```
5. 現在の `pm2` のプロセスリストを保存
	```
	pm2 save
	```
## pm2とは?
Node.jsをバックグラウンドで永続的に実行するためのプロセスマネージャ。
以下の特徴を持つ。
1. **永続性**: システムが再起動した後でも、`pm2` で管理されているアプリケーションは自動的に再起動されます。
2. **クラッシュリカバリ**: アプリケーションが何らかの理由でクラッシュした場合、自動的に再起動されます。
3. **ロードバランサ**: 複数のプロセスインスタンスを起動してロードバランシングを実施することができます。
4. **ログ管理**: アプリケーションのログを一元的に取得・管理することができます。
5. **モニタリング**: 実行中のアプリケーションのパフォーマンスやリソースの利用状況をリアルタイムで監視できます 

## Gitで更新を行う場合
1. `git pull origin main`
2. `npm install`
3. `pm2 restart your-app-name`
*pm2で永続化しているため、pm2をリスタートしないと変更が適用されない。
GROUPINGを理解してSQLマスターになろう

# GROUPING演算子
集約キーの「組み合わせ」が異なる結果を計算する

#### 超集合行
集約キー無し、つまりGROUP BY()で集約された行のこと。
超集合行は、集約キーの値が不明なので、デフォルトではNULLが使用される。

### GROUPING関数
超集合行では集約列の値がNULLになるが、超集合行のNULLとテーブル上でのNULLを見分ける関数としてGROUPING関数が存在する。
引数に取った列の値が超集合行のため生じたNULLなら1を、それ以外なら0を返す。
CASE式と併用することで、超集合行のNULLを他の値に変換することも可能。


## 今回の例で用いるテーブル
**pop_sex**
| pref_name | sex | population |
| ---- | ---- | ---- |
| 東京 | 1 | 250 |
| 東京 | 2 | 250 |
| 神奈川 | 1 | 200 |
| 神奈川 | 2 | 100 |
| 福岡 | 1 | 150 |
| 福岡 | 2 | 100 |
| 埼玉 | 1 | 100 |
| 埼玉 | 2 | 150 |
| 長崎 | 1 | 20 |
| 長崎 | 2 | 30 |
| 千葉 | 1 | 120 |
| 千葉 | 2 | 130 |
| 山形 | 1 | 50 |
| 山形 | 2 | 50 |

## ROLLUP
引数に与えた列ベクトルが ```V = (colN)``` だとすると、
以下のN+1個の組み合わせについて集約する。
```math
(), (col1), (col1, col2), ... , (col1, col2, ... , colN)
```

## 構文
```sql
GROUP BY ROLLUP(<col1, [col2, ...]>)
```

## 例
```sql
SELECT
    pref_name,
    SUM(population) as sum
FROM
    pop_sex
GROUP BY ROLLUP(pref_name)
```

これは次の２つの組み合わせについての集約を行っている。
1. GROUP BY()
1. GROUP BY(pref_name)

| pref_name  | sum |
| ---- | ---- |
|  | 1700 | 
| 東京 | 500 |
| 神奈川 | 300 |
| 福岡 | 250 |
| 埼玉 | 250 |
| 長崎 | 50 |
| 千葉 | 250 |
| 山形 | 100 |

1番上の行が超集合行であり、集約キーのpref_nameがNULLとなっている。

もしGROUPING関数を使って別の値に変換する場合の例を以下に示す。
```sql
SELECT
    CASE WHEN GROUPING(pref_name) = 1 THEN '合計'
    ELSE pref_name
    END AS pref_name,
    SUM(population) as sum
FROM
    pop_sex
GROUP BY ROLLUP(pref_name)
```

| pref_name  | sum |
| ---- | ---- |
| 合計 | 1700 | 
| 東京 | 500 |
| 神奈川 | 300 |
| 福岡 | 250 |
| 埼玉 | 250 |
| 長崎 | 50 |
| 千葉 | 250 |
| 山形 | 100 |

## CUBE
引数に与えた列ベクトルの全ての組み合わせについて集約する。
集約の組み合わせ数は2^N。
```math
V = (col1, col2, col3)
```
```math
(), (col1), (col2), (col3), (col1, col2), (col1, col3), (col2, col3), (col1, col2, col3)
```

## 構文
```sql
GROUP BY CUBE(<column1, [column2, ...]>)
```

## GROUPING SETS
引数に与えた列ベクトルの全てに対して、単独で集約キーとした場合について集約する。
集約の組み合わせ数はN。
```math
V = (col1, col2, col3)
```
```math
(col1), (col2), (col3)
```

## 構文
```sql
GROUP BY GROUPING SETS(<column1, [column2, ...]>)
```
中堅SI(客先常駐)から自社開発に転職して1年たって感じたこと

#### はじめに
転職して1年がたったのでふと思いついて筆をとります。
SIerや客先常駐をディする意図はありません。
そういう働き方もあると思います。（ぶっちゃけ私はもう二度とごめんですが）
いろいろいいところや悪いところを比較していきたいと思います。
ほろ酔いなので誤字脱字見過ごしてください。

#### 経歴
8年目にして中堅SIから自社開発に転職（いずれも数千人規模）
転職後1年経過

#### SIerのいいところ
１．いろんな現場を経験できる。
客先常駐や派遣のメリットはとにかくこれに尽きると思います。
一流企業に常駐して優秀な人と一緒に仕事ができたのはとても勉強になりました。
今思えば、厳しくはあったものの仕事の仕方や考え方は常駐先のお客さんから教わりました。連日終電までお客さんに怒られながらコーディング&資料作成をしたのはいい思い出でした。
様々な現場を経験できるので、どこでもやっていける力が身に付きます。
私は自身の強みや弱み、開発の上流～下流のどこが得意でどこをやりたいのかなども比較的はやく把握できたと思います。

２．比較的給料がいい
はっきりいうと中堅あたりのSIはパッとしない大学卒であっても入りやすいです。
その割に給料はいいので、とにかくお金が欲しいという人には良いかもしれません。
最近は減ったかと思いますが、残業が多いと2年目あたりで月の額面が60万円を超えたこともありました。専門卒であっても能力次第では採用されます。


#### SIerのいやだったところ
１．キャリアを考えにくい
会社都合で現場がころころ変わる。
こういうことがやりたいといってもなかなかやらせてもらえない。
技術に興味があっても平気でCOBOLの現場とかにアサインされる。（これは前職だけかも）
現場に長く(10~20年)常駐する人もおり、お客さんにかなり近い仕事をすることもある。
ただ開発がないため、お客さんの業務やそこのニッチな技術しかしらないまま中年になってしまう人が多くいる。その現場がシュリンクすると他の現場にアサインされるわけだが、当然これまでいた現場以外の業務や開発をしらないのでしんどいことになる。

２．技術力が低い
これは自社だけかも。技術的なことに関心がある人が少ない。
オブジェクト指向？なにそれ状態の人もけっこういる。

３．休みがとりにくい＆残業多い
月の契約が160時間とかけいやくすることが多いため、あまり休みを取るとマイナス清算が発生してしまう。
もちろん利益がへることになるので、休みの多い月は余計な仕事を作って残業を増やして調整する。

４．プライドが低い
ほぼ派遣や常駐での勤務なので、一次受けから明確に線引きした対応をされる。
一次受けの新人との扱いの差に新人のころは地味に傷ついた。
年を取ったマネージャが一次受けの若手に怒られているところとかよく見る。
基本的に常駐させてもらってるため肩身は狭い。
パワハラ？お客さんからならノーカンです笑

５．開発環境の貧弱さ
デュアルディスプレイはもちろんない、ノートPCで開発なんて現場がごろごろある。
レビューはすべて紙に印刷するとか。
メモリ32GBなんて開発なら当たり前と思うが、メモリ4GBのノートで開発させられた時はびっくりした。
そりゃメモリ足りなくなる。



以上駄文でした。
## コメントウェルカムです。
QiitaとQittaとKitte（キータとキッタとキッテ）

# はじめに

みなさん、Qiitaの検索機能で「Qitta」というワードを入力すると2023年8月21日23時時点で検索結果に400件近くの記事がヒットすることはご存じでしたでしょうか？
そう、私もけっこうやってしまうのですが、Qiitaの書きまちがいの「Qitta」けっこう多いです。

# Qiitaさんのご近所、名古屋Kitte（KITTE）の影響か？

私なんかは１つの記事の中に、QiitaとQittaが混在する始末でした。いっとき、どなたかご親切な方の編集リクエストをいただいて、過去記事にわたって横展開修正をいたしました。

私の場合、タイプミスというより一時期Qiitaさんのことを「Qitta」さんと誤認していた時期があり（ほんとの最初はQiitaさんだったみたいで、途中から「Qitta」さんと誤認し始めた模様）、なんでそうなったのかなと振り返ってみますと、もしかして名駅（すみませんJR名古屋駅のことです。）にあるJPタワーの商業施設、名古屋Kitte（KITTE）の影響かもと思ってみたり。

ただ、Kitte（KITTE）は名古屋だけでなく、東京丸の内や大阪、福岡とかにもあるんですね。

# おわりに

Qiitaさんは「Qitta」さんではなくQiitaさんなので、タイプミスまたは私みたいなKitte（KITTE）との語感上の勘違いのひとも、なるべく注意しましょう。

名古屋Kitte（KITTE）のお店はよくわかりませんが、大名古屋ビルヂング内の焼き鳥屋さんはおいしいです。
#0019 async/awaitの触り

## はじめに
- 最近非同期処理について触れることがあり、pythonのasync/awaitについて調べてみた。
- 深掘ろうとすると、抜けなくなりそうなので、簡単な実装で終える。

## 非同期処理とは
- 処理Aと処理Bを同時に実行できる
- 並行処理
- 同期処理（逐次処理）の逆の意味の言葉
- 非同期処理を使う場面は、「処理の完了まで時間がかかる」場合
- pythonではI/Oバウンド（入出力における負荷）の軽減ために用いられる。
    - ファイルの読み書き
    - DBの読み書き

## asyncio 非同期I/O
> asyncio は async/await 構文を使い 並行処理の コードを書くためのライブラリです。
>
> asyncio は、高性能なネットワークとウェブサーバ、データベース接続ライブラリ、分散タスクキューなどの複数の非同期 Python フレームワークの基盤として使われています

[公式ref](https://docs.python.org/ja/3/library/asyncio.html)

## asyncioを使った実装1

まず使ってみる。（非同期処理ではない）
```
import asyncio
import time

async def main():
    print(f"Start : {time.strftime('%X')}")
    await asyncio.sleep(3)
    print(f"Rest  : {time.strftime('%X')}")
    await asyncio.sleep(1)
    print(f"End   : {time.strftime('%X')}")

if __name__ == "__main__":
    asyncio.run(main())

❯❯❯ python async_test.py
Start : 22:51:19
Rest  : 22:51:22
End   : 22:51:23　　#合計6秒なので、これは同期処理。
```


(memo) コルーチン（`asynic`をつける）に`await`をつけるとコルーチンが実行されて処理が終わるまで待つになる。

関数を使って実装してみる。

```
async def function(wait_sec):
    await asyncio.sleep(wait_sec)
    return f"Wait for {wait_sec} sec."

async def main():
    print(f"Start : {time.strftime('%X')}")
    results_1 = await function(2)
    print(results_1)
    print(f"Rest  : {time.strftime('%X')}")
    results_2 = await function(4)
    print(results_2)
    print(f"End   : {time.strftime('%X')}")

if __name__ == "__main__":
    asyncio.run(main())

❯❯❯ python async_test.py
Start : 22:59:52
Wait for 2 sec.
Rest  : 22:59:54
Wait for 4 sec.
End   : 22:59:58 #合計6秒なので、これは同期処理。
```


(memo) コルーチンの処理を関数として切り出したら、関数の前に`await`をつける必要がある。（なんか変な感じだ...）


## asyncioを使った実装２

非同期処理を実装する。`async.create_task`を利用する。

```
async def main():
    print(f"Start : {time.strftime('%X')}")
    task1 = asyncio.create_task(function(2))
    task2 = asyncio.create_task(function(4))
    await task1
    await task2
    print(task1.result())
    print(task2.result())
    print(f"End   : {time.strftime('%X')}")


if __name__ == "__main__":
    asyncio.run(main())

❯❯❯ python async_test.py
Start : 23:05:09
Wait for 2 sec.
Wait for 4 sec.
End   : 23:05:13  #合計4秒なので、これは非同期処理！！
```

できた。

## おわりに
- 非同期処理の奥は深く、`gather`, `await future`, `await coroutine`, `run_in_executor`, `wait_for`など、扱えたら扱いたい。
- コルーチン とは　 「いったん処理を中断した後、続きから処理を再開できるプログラミングの構造。」

> コルーチン（英: co-routine）とはプログラミングの構造の一種。サブルーチンがエントリーからリターンまでを一つの処理単位とするのに対し、コルーチンはいったん処理を中断した後、続きから処理を再開できる。接頭辞 co は協調を意味するが、複数のコルーチンが中断・継続により協調動作を行うことによる。
> サブルーチンと異なり、状態管理を意識せずに行えるため、協調的処理、イテレータ、無限リスト、パイプなど、継続状況を持つプログラムが容易に記述できる。

([参考wiki](https://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%AB%E3%83%BC%E3%83%81%E3%83%B3))
SVN　Apache利用に関してメモ

Subversion（SVN）は、単体で動作するバージョン管理システムですが、Apache HTTP Serverと統合することもできます。統合することで、リポジトリへのアクセスをWebブラウザを通じて行ったり、HTTPSプロトコルを使用してセキュアなアクセスを提供したりすることができます。この統合にはApache HTTP Serverを使用することが一般的です。

したがって、SVN単体で使うか、Apache HTTP Serverと統合して使うかは、プロジェクトや要件によって異なります。

Apache HTTP Serverを使用する場合:
Apache HTTP Serverを利用する際には、以下の手順で統合することができます。

Apache HTTP Serverのインストール: 最初に、Apache HTTP Serverをインストールします。

mod_dav_svnモジュールの有効化: Apache HTTP Serverの設定ファイルであるhttpd.confを編集し、mod_dav_svnモジュールを有効にします。これにより、ApacheはSubversionリポジトリへのアクセスを処理できるようになります。

リポジトリの設定: mod_dav_svnモジュールの設定を行います。リポジトリへのアクセス権などを設定できます。

HTTPSの設定（オプション）: セキュアなアクセスを提供するために、HTTPSを設定することも可能です。SSL証明書の設定などが含まれます。

Apache HTTP Serverを使用しない場合:
SVNは独立して動作するため、Apache HTTP Serverを使用せずにSVNサーバーを設定することもできます。この場合、リポジトリへのアクセスは主にSVNクライアントを使用して行います。

どちらを選ぶかは、プロジェクトの要件や運用のニーズによります。Webブラウザを通じたアクセスやセキュアな通信が必要な場合には、Apache HTTP Serverを統合することを検討する価値があります。ただし、単純なバージョン管理のみを行う場合には、Apache HTTP ServerなしでSVNを利用することもできます。
SVN　ローカルサーバ構築メモ

svnadminコマンドが正しく機能しない場合、以下のいくつかのステップを確認してみてください。


環境変数の設定: svnadminコマンドを使用するためには、Subversionのバイナリが正しくインストールされたフォルダが環境変数PATHに含まれている必要があります。インストールしたフォルダ（通常はbinフォルダ）を環境変数PATHに追加してみてください。
```:cmd
set PATH=%PATH%;C:\Program Files\TortoiseSVN\svn-win32-1.8.13\bin
mkdir c:\home2\test_svn
cd c:\home2\test_svn
svnadmin create test_repo
```

正しいコマンドを使用: svnadmin createコマンドを使用する場合、正しい構文を使っていることを確認してください。コマンドは次のようになります。
```:cmd
svnadmin create /path/to/repository
```
/path/to/repositoryは新しいリポジトリを作成するディレクトリのパスを示します。このパスは存在するディレクトリでなければなりません。

管理者権限を確認: リポジトリを作成するディレクトリが正しい場所にあり、必要な書き込み権限があることを確認してください。一般的に、管理者権限を持つユーザーとしてコマンドを実行する必要があります。

正しいバージョンのSubversionを使用: インストールしたSubversionのバージョンが正しいか確認してください。古いバージョンや正しくインストールされていないバージョンを使用している可能性があります。

インストールの確認: Subversionが正しくインストールされていることを確認してください。インストールが不完全な場合、コマンドが機能しないことがあります。再インストールを試してみることも検討してください。

エラーメッセージの確認: ターミナルまたはコマンドプロンプトに表示されるエラーメッセージを確認し、問題の特定に役立つ情報が含まれているか確認してください。

以下コマンドが通った後の手順
1.C:\home\test_svn\test_repo\conf\passwd に行を追加します

```:cmd
-------------------
[users]
# harry = harryssecret
# sally = sallyssecret
 
user=pass
-------------------
```
2.C:\home\test_svn\test_repo\conf\svnserve.confのコメントを外します

```:cmd
-------------------
[general]
anon-access = read
auth-access = write
 
password-db = passwd
-------------------
```
svnサーバのプログラムを実行します。
コマンドを実行すると、そのまま応答が無くなりますが、ウインドウは閉じずに置いておきます。

```:cmd
svnserve.exe --daemon --root c:\home\test_svn
```

別のウィンドウを開き、作ったリポジトリをチェックアウトします。
下記の例ではコマンドラインで作業していますが、TortoiseSVNをGUIで作業してもOKです。

```:cmd
set PATH=%PATH%;C:\Program Files\TortoiseSVN\svn-win32-1.8.13\bin
cd /d c:\home\test_client
svn co svn://localhost/test_repo
```
【プラクティス紹介】1分でさらっと分かる「ファイブフィンガー」

## プラクティス名（別名）
ファイブフィンガー　（Fist to Five、Confidence Voting）

## プラクティスの目的・狙い
* 問題の早期発見
* 認識の差分をとる（忖度の無い所感表明）
* 迅速な意思決定

## どんな時に使うか
* チームメンバー全員の率直な意見を知りたい時
* 時間をかけずにチームの合意を形成したい時

## 実施手順
個人個人が「本当はどう思っているか」を5本の指で一斉に表明することで、時間をかけずに本音を引き出すツール。あまり考えすぎずに気軽に使った方がよい。

1. 質問者が質問と回答（5段階の選択肢）を提示する
1. 回答者たちは**口には出さずに**心の中で自分自身へ問いかけ、回答を決める
1. 全員で「せーの、どん！」で指を立てて、お互い何本指かを確認し合う
1. 立てた指の本数が少ない人（＝ネガティブな方）の意見を先に聞く
1. その後で本数が多い人（＝ポジティブな方）の意見も聞く

|本数|意味|
|:---:|:---:|
|5|強いポジティブ|
|4|弱いポジティブ|
|3|ニュートラル|
|2|弱いネガティブ|
|1|強いネガティブ|

選択肢の具体例

|本数|【例1】賛成か反対か？|【例2】チームの状態は？|【例3】改善効果は？|
|:---:|:---:|:---:|:---:|
|5|賛成|とってもうまくやれている|とても効果アリ|
|4|どちらかといえば賛成|うまくやれている感触あり|多少効果アリ|
|3|他の人の判断に従う|可もなく不可もなく|まだ分からない|
|2|どちらかといえば反対|不安は少しある|効果は薄い|
|1|反対|全然ダメで絶望的|全く効果なし|

## アレンジ例
* 選択肢を3段階に簡略化する
* 0本指を選択肢に含めると6段階となるため、必ずポジ/ネガのどちらかに振り分けられる
* カメラOFFのオンライン会議の場合は、3カウントで一斉に1～5の数字をチャットする

## アンチパターン
* 相手の意見を否定したり、なぜ「1」なのか理由を問い詰めたりする

## 参考情報
書籍『カイゼン・ジャーニー』

https://www.shoeisha.co.jp/book/detail/9784798153346

## こぼれ話（私的コメント）
汎用的に使えて便利なので重宝します。5段階の選択肢には変なバイアスがかからないよう語感にわりと気をつかいます。回答が5と1で割れる場合は、意見の相違というより、そもそもの前提やイメージが合っていないことが多く、議論が足りていないという判断を下すケースもあります。メンバー全員の数がバチっと揃った時は、なんかモチベーションが上がります。本来、差分をとるためのツールなんですけどね。

　[アジャイルプラクティス一覧へ戻る](https://qiita.com/kakashi_h5/items/20584998c5ca4594b9ea)
ADSLとは

# はじめに
毎週1本様々な技術に関する記事を投稿しています。
もし興味のある方は下のリンクから他の記事も見ていただければ幸いです。
 [@7_inai_](https://qiita.com/7_inai_)

# ADSLとは
ADSL（Asymmetric Digital Subscriber Line/非対称ディジタル加入者線）は、インターネット接続技術の一種であり、一般的な家庭や事業所において広く使われてきた技術です。ADSLは、`音声通信用に設計された従来の電話回線を使用して高速なデータ通信を可能にする技術`で、その特徴的な特性によって広く受け入れられています。

# ADSLの特徴
- 非対称性：
ADSLの名前にもあるように、この技術は非対称的な通信を提供します。つまり、ダウンロード速度（インターネットからデータを取得する速度）とアップロード速度（データをインターネットに送信する速度）が異なります。銅線を流れる電気信号の周波数帯域を、高い方と低い方の二つに分けることで、1つの回線でダウンロードとアップロードの両立を実現しているのですが、ウェブページを閲覧したりコンテンツをダウンロードしたりすることが一般的な用途であるため、ダウンロード側の周波数帯域を広く取っています。そのため、通常は __ダウンロード速度がアップロード速度よりも高い__ です。
- 音声とデータの同時利用：
ADSLは、__同じ電話回線を通じて音声通話とデータ通信を同時に行うことができます。__ これにより、通話中でもインターネットを使用することが可能です。
- 距離に敏感：
ADSLの速度は、送信元（インターネットプロバイダ）と受信者（ユーザー）の間の距離に影響を受けます。__距離が長いほど、信号の減衰が起こり速度が低下する__ 可能性があります。
※ 電気信号の減衰は、信号が熱エネルギーとして失われたり、外部動体を通ってケーブル外に漏出したりするために生じる
- インフラの再利用：
ADSLは、__既存の電話回線インフラを利用しているため、新たなインフラを敷設する必要がない__ という利点があります。これにより、比較的低コストで高速なインターネット接続を提供できます。

# 光回線への移行
1990年代後半から2000年代初頭にかけて広く普及したADSLですが、`現在では光回線の方が主流となっており、ADSLの終了を発表しているプロバイダー(接続事業者)も多くあります。`
光回線は、光ファイバーと呼ばれる通信回線を利用しており、光が伝わる特性を利用した伝送方式であるため、距離や外部からの影響を受けにくく、ADSLよりも通信速度が速いといった特徴があります。

# 終わりに
これまでADSLが広く利用されてきましたが、前述したとおり、現在では光回線が主流となっています。光回線は、高速な通信速度と安定性を提供することで、私たちの生活をより豊かにしました。これからは、技術の進化と共に、より高度なオンライン体験が広がっていくことでしょう。

最後までお付き合いくださりありがとうございました。
PowerShellでUnix/Linuxコマンドみたいなことがしたい！

PowerShellでUnix/Linuxっぽいことがしたい人へ

#### head

```
cat log.txt | select -first 10 # head
```

#### tail
```
cat log.txt | select -last 10
cat -Tail 10 log.txt
```

#### less
```
cat log.txt | more
```

#### sort, uniq
```
cat hoge.txt | sort | Get-Unique
```

#### grep
```
Select-String foo.txt -Pattern 'hoge'
```

#### sed -i
```
(Get-Content hoge.txt) | foreach { $_ -replace "var","foo" } | Set-Content hoge.txt
```

#### rm -r -f
```
Remove-Item -Recurse -Force some_dir
```

#### tar tvf
zipを展開せずファイル一覧を取得

```
[Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem')
foreach($sourceFile in (Get-ChildItem -filter '*.zip'))
{
    [IO.Compression.ZipFile]::OpenRead($sourceFile.FullName).Entries.FullName | %{ "$sourcefile`:$_" };
    $zip = [IO.Compression.ZipFile]::OpenRead($sourceFile); 
    $entries = $zip.Entries;
    $zip.Dispose()
}
```

#
こちらに他のコマンドなどかなり詳しく記載しています。発展内容もあり。

https://nnzz.pupu.jp/archives/64


#
【Python】クラス・オブジェクト・インスタンス




クラス・・・オブジェクトの設計図（テンプレート）のこと

オブジェクト・・・あるデータと、そのデータを処理する関数を一塊になっているもの。
```py:オブジェクト
#あるデータ
names = ['田中', '鈴木']
#そのデータを処理する関数
names.append('山田')
```

インスタンス・・・クラス（設計図）に基づいて具体的なデータを持つオブジェクトが作られるたモノ

オブジェクトとインスタンスの違いが分からない…。
ということで、ChatGPTに聞いてみました。

---
Q.　　オブジェクトとインスタンスの違いは？


A.　　Pythonにおいて、「インスタンス」と「オブジェクト」は通常同じ意味として使用されます。つまり、クラスから生成された具体的なデータ構造を指す際にどちらの用語も使用できます。

ただし、厳密にはクラスとインスタンスを区別する立場も存在します。この立場に従うと、クラスがオブジェクトの設計図であり、インスタンスがその設計図に基づいて具体的に作成されたものとされます。この意味で、クラスとインスタンスは異なるものとされることがあります。

一方で、プログラミングコミュニティではしばしば「クラスのインスタンス」を「オブジェクト」と呼ぶことが一般的です。したがって、実際の開発で両者を同じ意味として使用しても問題ありません。

例えば、以下のコードでは「インスタンス」と「オブジェクト」を同じくらいの意味で使用しています：

```py
class Person:
    def __init__(self, name):
        self.name = name

# Personクラスのインスタンス（オブジェクト）を作成
person_instance = Person("Alice")

# インスタンス（オブジェクト）の属性にアクセス
print(person_instance.name)  # 出力: Alice
```

このコードでは、person_instance は Person クラスのインスタンス（オブジェクト）です。両方の用語を同じくらいの意味で使用しており、一般的にはオブジェクト指向の文脈での使用方法として広く受け入れられています。



なんかよく分からない…。。。
Pythonの文法

# はじめに
勉強がてらPythonの文法についてまとめたいと思います。

# 文法
さっそくまとめていきます。

## 変数について
~~変数とは、値を格納する箱のようなものです。~~
(2023/08/22:他のプログラミング言語における変数のイメージでした。)
Pythonにおける変数とは、オブジェクトへの参照が格納されます。
~~Pythonでは、他のプログラミング言語と異なり変数の初期化は不要です。~~
Pythonは、変数の宣言は不要です。
型の宣言もPythonでは不要ですが、「使う変数をどのように使うか」を明示的に示すために宣言した方が良いかと思います。
```python
noSample: int = 0
strHelloWorld: str = "Hello World!!"

print(f"strHelloWorld: {strHelloWorld}")
```
## 定数について
Pythonでは定数を扱うことができません（サポートされていないため）が、大文字＋アンダースコア(_)で表現することが慣例となっています。
```python
HELLO_WORLD: str = "Hello World!!"
```

## デバッグ等でコンソールに値を出力する方法
変数の中身、型の確認や処理がどこまで処理が進んだかを確認するなどの目的でprint文が使えます。
```python
print("処理開始")
""" 処理 """
print("処理終了")

helloWorld = "Hello World!!"
print(f"type:{type(helloWorld)},\n data:{helloWorld}")
"""
出力内容：
    type:<class 'str'> 
    data:Hello World!!
"""
```
## 条件分岐
ここから実際にプログラムを組む際に重要になる条件分岐についてまとめていきます。

### IF文
この条件の時は、これをする、のような条件で処理を分岐させたい場合に使います。
elif文を追加していくことで条件を細かくしていくことが可能です。
しかし、条件を細かくすると後で確認するときに分かりにくくなるというデメリットがあるため、個人的にはif-elseでの使い方が良いかと思います。
また、アーリーリターンを意識して書くことでより分かりやすい処理を書くことが可能です。
アーリーリターンとは、簡単に言うと「returnを使ってネストを減らすテクニック」です。
```python
# if文の書き方
if 条件文:
    処理
elif 条件文:
    処理
else:
    処理
```

### match文
Python3.10以降で使えるようになった、他のプログラミング言語でいう「Switch文」です。
これまで、if文で同じように処理を記述することができるためMatch文のような条件分岐はありませんでしたが、v3.10から追加されました。
書き方もほぼSwitch文と同じです。
```python
match 変数:
    case 1:
        # 特に処理を行わない場合は、passを記述する
        pass
    case 2:
        return True
    case _:
        # 上記の条件にマッチしなかった場合は、「_(アンダースコア)」で記述するとワイルドカードパターンとしてここに書かれた処理を実行します。
```

## ループ処理
### for文
pythonにおけるfor文は、他のプログラミング言語におけるforeach文と使い方は同じです。
- 処理を途中で抜ける場合:break
- 特定の条件の場合にスキップする:continue
- ループ処理を抜けたら必ず実行する処理を記述する:else
```python
for 変数 in list:
    処理
    if 条件:
        continue
    else:
        break
else:
    print("Finish")
    処理
```
### while文
条件がTrueの間処理を繰り返します。
```python
while 条件:
    処理
```

# まとめ
簡単なPythonの文法についてまとめました。
もう少し細かい書き方についても今後まとめる予定です。
以上、ここまで読んでいただきありがとうございました。
次回もよろしくお願いします。
[Swift] デバイスからファイルをダンプして、他のデバイスで復元する

# はじめに

以前に、実機iPhoneから内蔵のサウンドファイルを抜き出して、Macでファイルに復元するため書いたコードです。
iOS、iPadOS、MacOSで動作します。

```swift:パス名とファイル実体
struct FileItem: Encodable, Decodable {
    let filename: String
    let content: Data
}
```

# ファイルをJSONにエンコードする

もちろん、そのデバイスでアクセス可能なパス/ファイルである必要があります。
アクセスできるファイルなら、なんでも抜き出せます。

```swift
//path: 抜き出すファイルのフルパス名
//return: JSON化した文字列 
func dumpFile(path: String) -> String {
    do {
        let encoder = JSONEncoder()
        let dataURL = URL(fileURLWithPath: path)
        let binaryData = try Data(contentsOf: dataURL, options: [])
        let fileItem = FileItem(filename: path, content: binaryData)
        let encodedData = try encoder.encode(fileItem)
        let json = String(data: encodedData, encoding: .utf8)!
        return json
    } catch let error {
        return error.localizedDescription
    }
}
```

読み出したファイルがJSONにエンコードした“文字列”になって返るので、その文字列を別なデバイスにコピーして、ファイルに保存します（文字コードはUTF-8）。

_JSON文字列の受け渡しは人力です。_

:::note
同じアカウントでサインインしているAppleデバイス間では、クリップボードが共有されるので、「iPhoneでコピーしてMacにペーストする（その逆も）」が普通にコピペで実現できるのが楽です。
:::

# ファイルに復元する

入力ファイルと同じディレクトリに、JSONをデコードして元のファイル名のファイルに復元します。

```swift:
//path: JSONを保存したファイルパス
//同じディレクトリに復元したファイルを出力
func restoreFile(path: String) {
    do {
        let url = URL(fileURLWithPath: path)
        let jsonString = try String(contentsOf: url, encoding: .utf8)
        let jsonData = jsonString.data(using: .utf8)!
        let decoder = JSONDecoder()
        let fileItem = try decoder.decode(FileItem.self, from: jsonData)
        let inputUrl = URL(fileURLWithPath: fileItem.filename)
        let dirUrl = url.deletingLastPathComponent()
        let outputUrl = dirUrl.appendingPathComponent(inputUrl.lastPathComponent)
        try fileItem.content.write(to: outputUrl)
    } catch let error {
        print(error)
    }
}
```






# おわりに

またいつか必要になるかも知れないので、残しておきました。
Power Automate上でグループチャットを作成する時にハマった点の備忘録

## ◇はじめに

Microsoft社Power Platformの中のPower Automate上でグループチャットを作成しようとした際にフローが上手く動作せずにしばらくハマったため、その解決策を備忘録も兼ねて記事にしておきます。  
※常に発生する問題かは切り分けできていないので、もし同じ問題にぶつかった方は本記事を参考にしてもらえればと思います。

## ◇開発環境等

- OS：
  - Windows 11 Home（Ver:22H2）
- 契約ライセンス：
  - Microsoft 365 Business Basic
- 使用ツール：
  - Power Automate
  - SharePointリスト

## ◇元々やりたかったこと

1. SharePointリスト上にデータ種類を`ユーザーまたはグループ`とした列を作成する
2. このとき、`複数選択を許可`のチェックボックスを**オン**にする
3. 新規データ追加で、複数ユーザーを登録する
4. Power Automate上でSharePointリスト上からユーザー列のデータを取得する
5. ユーザー列に保存されていたユーザー全員を含めたグループチャットを作成する
6. 作成したグループチャットにメッセージを投稿する

## ◇最初に試したフロー（❌失敗例）

Power Automate上で新たなチャットを作成する場合、`チャットの作成`アクションを選択します。  
`チャットの作成`アクションを確認すると、
> セミコロンで区切ったユーザーIDまたはメールアドレスを入力します

と記載されており、セミコロン区切りの文字列が必要なことが分かります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/371217/5a6bf3da-39a8-84e2-4031-ba38b5d0476c.png" width="600">

セミコロン区切りの文字列を作るには、`結合`アクションを使うことで対応できそうなことが分かったため、フローの構成としては、

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/371217/f0bd55d0-6a18-c730-6cc0-f2dd7f4cd1ec.png" width="600">

1. アレイ型の変数を用意
2. SharePointリストのユーザー列の項目からメールアドレスを人数分取得して、要素ごとに格納
3. アレイ型変数をセミコロン区切りの文字列変数に変換

といった流れにしました。

全体のフロー画面を以下に貼っておきます。  
アレイ型の変数は`UserMailList`という名前にしてあります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/371217/164b567b-0736-1e58-9025-2daa22f1c9c0.png" width="600">

ここまでで、チャットの作成に必要な文字列ができたため、`チャットの作成`、`チャットまたはチャネルでメッセージを投稿する`アクションを並べます。  
なお、とりあえずチャットのタイトルは`guid()`関数でランダム文字列化にしてますが、適宜変更可能です。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/371217/fe20558c-a97f-c17d-0c37-7cc98082600a.png" width="600">

このとき、`チャットの作成`アクションの追加するメンバー欄には、先ほどの`結合`アクションの`出力`ブロックを入力します。  
また、メッセージを投稿するアクションでは、Group chat欄にカスタム値として`会話ID`を選択します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/371217/f7c3929f-6500-f3d5-4b9b-65f589659aae.png" width="600">

これで一通りフローが完成したので、手動テストを行ったところ、`チャットを作成する`アクションでエラー（`BadRequest`）が発生しました。
文字列の結合処理に問題があるかと思い、調べてみましたがその部分は問題なさそうでした。

ネットで色々調べると、フォーラムでも似たような報告は以前からされているようです。  

https://powerusers.microsoft.com/t5/Building-Flows/Teams-Create-a-chat-Bad-Request-400-error/td-p/1011404

既に改善された、いや、まだ問題が発生する  
といったコメントがあって最終的な状態はよく分かりませんでしたが、その中にメールアドレスじゃなくてユーザー名を使うと解決するよといったコメントがあったため、そちらのやり方を試してみました。

## ◇改善したフロー（⭕成功例）

先ほどまでのフローをベースに、UPN名をリスト化するフローを追加しています。

アクションとしては、`ユーザーの検索(V2)`アクションを使用します。  
検索語句は先ほど同様、ユーザーメールアドレスを使用していますが、DisplayNameとかでも問題ありません。
ユーザー検索後、その中からUPN名を取得して配列変数に格納していきます（変数名は`UserMailList`から`UserList`に変更）。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/371217/71cfa393-9ce3-65c1-0b5d-28641506884f.png" width="600">

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/371217/9999fba6-e72b-3d37-7311-689bfa5e51a7.png" width="600">

このあとはさっきのフロー同様、`チャットの作成`、`チャットまたはチャネルでメッセージを投稿する`アクションを並べて実行することで問題なくフローが動作するようになりました。

## ◇おわりに

メールアドレスを使った際にエラーが出る原因は現時点でも解決していませんが、UPN名を使うことで対処できることが分かったので、備忘録として残しておきます。

同様の問題が出る場合、出ない場合の条件がありそうですが、もし同様の問題が発生した場合は今回のやり方を試してもらえればと思います。

# 🔚END
スッキリわかるSQL入門を読んで

## はじめに
スッキリわかるSQL入門を読んでの感想を記載いたします。

## 良かったところ
* 全体的に図が多く使われイメージがしやすかったです。
* SQLだけでなく後半の章ではデータベースの設計の基本的な部分に関しても言及があり、学びが多かったです。
* 12章で、システムの開発者視点とユーザ視点の話が出てきてすごく勉強になりました。SQLの本ですけど「システムとは」という内容で締めているのが素敵な終わり方でした。
* 演習問題がたくさんあるのでSQL文を書く練習にはうってつけと思いました。環境構築も必要ないのも手軽で嬉しいですね。

## 学んだこと
### 主キーについて（3章）
* 主キーについて
  * 自然キー：自然に主キーの役割を果たせるキー
  * 人工キー（代替キー）：自然キーがない場合に、管理のため人為的に作り出されたキー

### 副問い合わせについて（7章）
* 副問い合わせの種類
  * 単一行副問い合わせ：結果が1行1列になるもの
  * 複数行副問い合わせ：結果がn行1列になるもの
  * このほか結果がn行m列の表形式（マトリックス）になる副問合せも使われる
* 複数行副問い合わせは、IN、ANY、ALL演算子と合わせてよく使われる。
* 複数行副問い合わせの結果にNULLが含まれると、NOT IN、<>ALL演算子の評価結果もNULLになる。
* EXISTS演算子を使って「他のテーブルに値が登場する行のみ抽出する」ということができる。これは、相関副問い合わせという特殊な副問い合わせである。

### ACID特性について（9章、11章）
* データを正確かつ安全に取り扱うためにシステムが備えるべき4つの特性
  * 原子性Atomicity：処理が中断しても中途半端な状態にならない
  * 一貫性Consistency：データの内容が矛盾した状態にならない
  * 分離性Isolation：複数の処理を同時実行しても副作用がない
    * 副作用：ダーティーリード、反復不能読み取り、ファントムリード
  * 永続性Durability：記録した情報は消滅せず保持され続ける

### さまざまな支援機能について（11章）
* インデックスは書き込み性能の低下を招くこともあるので、乱用は禁物
* 複雑な採番を行いたい場合は、採番テーブルを作る等自力で実装が必要
* バックアップについては、DBの内容だけでなくログファイルもバックアップする。ログファイルからDB操作をロールフォワードすることで、障害発生直前の状態まで復元できる。

## 難しかったこと
* 些細なことですが、演習問題のカラム名やテーブル名が日本語なのが演習を解くうえで少し大変でした。（日本語と英語の切り替えが頻発するため）実際にSQLを叩くときには、日本語のカラム名・テーブル名であるケースは稀だと思います。プラスアルファで英語カラムにも対応していると、より有意義な演習になるのではと思いました。
LaravelをIDEAなどで使う場合に補完させる方法

つい忘れてしまうのですが、IDEA制IDEなどでLaravelのメソッド、プロパティなどの補完を有効にする方法です。

# インストール


```bash
composer require --dev barryvdh/laravel-ide-helper
```

# 作成

下記の３つを実行すると作成されます。

```bash
php artisan ide-helper:generate
php artisan ide-helper:models -N
php artisan ide-helper:meta
```

| オプション | |
|---|---|
|generate | ファサード用のPHPDoc作成 |
| models | モデル用のPHPDocを作成。`-N` オプションをつけると個別ファイルへの書き出し。|
| meta | PhpStorm 用のメタファイルの書き出し |


モデル用のPHPDocについてはモデルファイルへの書き出し、または個別ファイルへの書き出しをすることができます。
モデルファイルに書き出しをしてしまうとモデルファイルに独自に書いたプロパティやメソッドなどがあった場合、上書きするようになってしまいます。
それよりは別ファイルに書き出しをして、それ自体をGitで管理してしまったほうがチームとしては扱いやすいです。

# GraphQL

LighthHouseを使っている場合には下記のコマンドでGraphQL用の補完が効くようになります。

```bash
php artisan lighthouse:ide-helper
```

https://github.com/barryvdh/laravel-ide-helper#phpstorm-meta-for-container-instances

https://qiita.com/miriwo/items/5d1e82931ee182f709e2
正規化

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457284/74d9f300-18bf-f6c9-ffa4-36ed0243d513.png)
１：第２正規形の表は、第１正規形の表の条件を満たしており、　非キー属性が主キーに完全関数従属する表です。
　第２正規形にするためには、主キーに関係する属性との関係従属を洗い出し、それぞれの関数従属を別表に分けます。例えば、商品情報や受注情報、受注明細情報が各表に分割されます。その結果、商品情報や受注情報に関する情報の重複がなくなります。しかし、依然として、受注表には、観客情報が重複して記録されています。第２正規家は、完全ではありませんが、情報の重複を取り除けていますので、まずまずの不整合の防止効果があると言えます。

　なお、完全関数従属とは、主キーの一部に関係する関数従属がないということです。

　例えば、受注明細表の場合、{受注番号,  商品番号}が主キーです。

　{受注番号,　商品番号}　→ {数量, 金額}

という関数従属があります。主キーの一部である"受注番号"や"商品番号"に対位して、
　"受注番号　→ 数量", "受注番号　→ 金額"
"商品番号　→ 数量", "商品番号　→ 金額"

といったような関数従属がないので、数量夜勤ガック（非キー属性）は、{受注番号, 商品番号}　（主キー）に完全関数従属しています。