OmniAICreator/Qiita-1.07M huggingface dataset:
setの使い方

競プロなどでsetを使うことがしばしばあって、よく使うメンバ関数を忘れることが多いのでメモっておきます。(全部のメンバ関数を網羅しているわけではありません。)

# setとは
setは平行2分器と言われる構造で、要素が木を使って比較演算子に従って並べられています。例えばint型では

```set.cpp
#include<bits/stdc++.h>
using namespace std;

set<int> s = {3,1,2,6,5,4,6};
```

などと与えます。次の命令で出力すると

```set.cpp
for( int x : s ) cout << x << " ";
    cout << endl;
```

```
1 2 3 4 5 6
```

と出力されます。setにはvectorと違ってインデックスがなく、要素は昇順にソートされた状態で出力されます。
また、重複する要素は自動で削除されます。

# insert

要素を追加するメンバ関数です。

```set.cpp
    s.insert(7);
    s.insert(2);
```

再び出力すると

```
1 2 3 4 5 6 7
```

となり、重複していない7が追加されています。また、重複している2を追加してもsに変化はありません。

# erase
入力した要素を削除します。

```set.cpp
s.erase(7);
```

```
1 2 3 4 5 6
```

先ほど追加した7が消えています。

# find

要素が存在するか確認します。存在するならその要素のイテレーター、存在しないならイテレーターs.end()を返します。findを使って得たイテレーターから対応する値を出力すると

```set.cpp
    //find
    decltype(s)::iterator it = s.find(3);
    int value;
    if(it != s.end()){
        value = *it;
        cout << value << endl;
    }else{
        cout << "not found" << endl;
    }

   it = s.find(8);
    if(it != s.end()){
        value = *it;
        cout << value << endl;
    }else{
        cout << "not found" << endl;
    }
```

```
3
not found
```

となり、sの要素に存在する3はそれが出力され、存在しない8はs.end()が返されています。

# lower_bound,upper_bound
vector型のようにlower_bound, upper_boundも使えます。

```set.cpp
    decltype(s)::iterator itl = lower_bound(s.begin(),s.end(),3);
    if(itl != s.end()){
        value = *itl;
        cout << value << endl;
    }else{
        cout << "not found" << endl;
    }

    decltype(s)::iterator itu = upper_bound(s.begin(),s.end(),3);
    if(itu != s.end()){
        value = *itu;
        cout << value << endl;
    }else{
        cout << "not found" << endl;
    }
```

```
3
4
```

lower_boundではキーの値以上の要素で最小のもの、uppper_boundではキーの値より大きい要素で最小のものを出力します。

# 参照ページ
- https://cpprefjp.github.io/reference/set/set.html
STM32F767で時間関数と繰り返しタイマー割込みで遊ぶ(1秒)


目的
簡易な時間づくり
例題をほぼそのまま使用


https://os.mbed.com/users/okini3939/notebook/time_jp/


https://os.mbed.com/users/okini3939/notebook/ticker_jp/



![o_con583.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/8353a1a2-0aad-13ab-3472-3e115fcd3307.jpeg)



SER_time_test1_767_1


```c++


#include "mbed.h"

DigitalOut led(LED1);

Serial pc(SERIAL_TX, SERIAL_RX);

Ticker flipper;

time_t seconds = 0 + (60 * 60 * 9); // JST

void flip() {
    led = !led;
    seconds++;
}

int main()
{
    
    flipper.attach(&flip, 1.0); // the address of the function to be attached (flip) and the interval (1 seconds)

    
    pc.printf("\r\n<START>\r\n");
    
    
    struct tm *t;
    
    while(1) {
            
    t = localtime(&seconds);
 
    pc.printf("%04d/%02d/%02d %02d:%02d:%02d",
      t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
 
    pc.printf("\r\n");

        wait(1.0);
    }
}




```
UnityとUnreal Engine　どちらを使うべきなのか？？


今回は、ゲームエンジンの２大巨塔である

UnityとUnreal Engineを比較します。　
まず、ゲームエンジンには汎用型と特化型があります。　
UnityやUnreal Engine、　COCOSなどは汎用型のゲームエンジンと呼ばれていますが　
有名なRPGツクールシリーズなどは特化型のゲームエンジンです。　



そして、ゲームエンジンの１位と２位がUnityとUnreal Engineというわけです。　

１位がUnityで　２位がUnreal Engineです。　
Unityはモバイルゲーム市場ではダントツなので、その差が大きいって感じです。












# Unityのメリット


　


・どのプラットフォームでも対応している

・アセットストアが充実している　【検索もしやすい】

・特に2Dゲーム、モバイルゲームに強い　

・情報量がUnreal Engineの５倍～１０倍以上ある　

・他のツールとの相性もいい　

・Unreal Engineと比べたらソフトが軽い　

などがあります。　



特に情報量とアセットストアのメリットが大きすぎるんですよ。　

英語の情報であれば、Unreal Engineも沢山あるけど　

日本語の情報は正直まだまだ少ない。　

けど、Unityの場合　日本語の情報も沢山ありますし　

公式のLearning情報も豊富にあるので、初心者でもとっつきやすいのが特徴です。　



そして、アセットストアもUnreal Engineより勝っています。　

特にゲーム開発を楽にしてくれるアセットが沢山あるので　

プログラミングなどが出来なくても、全然ゲームを作ることは可能です。　

やはりこれだけ便利なアセットがあると

初心者にとってはありがたいと思います。　



# Unreal Engineのメリット　


・デフォルトのグラフィックがきれい【膨大なポリゴン数にも対応している】

・Blueprintでノードベースでの開発ができる。　

・3Dゲームに強い【AAAタイトル向け】　

・クオリティの高い、映像作品を作れる　

・エディタのツールが豊富　

・性能としては最強

　などなどあります。





ただし、日本語の情報がまだまだ少ないという点と　

アーティスト向けのアセットの少なさ　

そして、Unityよりも重たいというデメリットがあります。　

なので、プログラミング経験者とかならいいと思うけど　

初心者がいきなりやるのはちょっと大変かなーって感じです。　



Blueprintもなれるまで結構時間がかかると思う。　



因みに推奨スペックはこんな感じです　↓



GPU 最低スペックはNvidiaGTX1080またはAMDRXVega64
最高パフォーマンスを求める場合はNVIDIARTX2080またはAMDRadeon5700XT以上必要
CPU 3.4GHz以上の12コアCPUを推奨
ストレージ 大容量で高速なSSDを推奨
RAM 32GBを推奨。











推奨でこれはやばいよね。　

最低だと、GPUは1660ti　メモリは最低でも16GBはないと厳しいと思います。つまり、最低でも２０万前後のゲーミングPCが必要ってことですよ。　ゴリゴリに開発するなら、３０万以上のゲーミングPCは必要です。　



綺麗なグラフィック＝ゲーミングPCじゃないと作れないですからね。　
なかなか初期投資が高い。









因みにUnityはそこまでスペックは高くないので１０万前後のゲーミングPCでも　

普通に開発が出来ますし　

2Dゲームであれば、ノートPCでも大丈夫です。　











やはり、初心者の人ならUnityの方がいいと思いますね。　

情報量に差がありすぎるので。



Unityだったら、調べたら答えが出てくることが多いけど　
Unreal Engineの場合は、英語のサイトまで調べていかないと　
答えまで出ないことが多いのですよ。　





特に個人開発者の場合も、Unityが圧倒的に多くて　
Unreal Engineをガチでやっている人って少ないという印象です。　



なので最初はUnityでやってみて慣れたら　
Unreal Engineもやってみるというのが王道ルートだと思います。

　

Unityでも難しいと思えば、RPGツクールシリーズとかで　

作ってみるのもいいでしょう。　













PS　

[Unity3DゲームStandard講座](https://omoritakuya.teachable.com/p/unity3dgame2-0?coupon_code=80SALL3 "Unity講座")


こちらの講座ですが、只今80%OFFセールをやっています。
今年の4月にアップデートしたばかりの新作です。
　
セールは7月21日までとなります。
データ駆動型DX基盤を創る（補足編2）

# 最後にバッチ処理自体を原点回帰させるお話を・・
今回は、前回の補足編1で少し足りなかった、分担データシステムにおけるバッチ処理の前提条件に対する発想の転換について、少し掘り下げた追加説明をさせて頂きます。

現場の通常業務による各種のデータ・オペレーションにより発生する、既存の電子帳簿型システムにおけるデータ変化を、 **EqualumのCDCストリーミング技術により「データ駆動型DX基盤」へ即時・低遅延での同期が可能になった場合**、従来のデータを再利用出来る形に処理してDWH等に展開する為の **バッチ処理は、大きくその存在理由や処理の方向性が変化すると同時に、より最新の各種データ処理環境と密連携をする形に進化出来る** 様になります。

![スクリーンショット 2022-07-17 12.49.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197589/23337f12-368f-6ef0-4498-9c2c61e25b30.png)

Equalumを使った **オンタイム・オンデマンドでの「データ駆動型DX基盤」におけるバッチ処理** は、それらの **処理間隔をDXの仕掛けに最適な戦略的時間単位に設定する事が出来る** 様になると同時に、基本的に常に現場のデータ状況を **「サイロの壁を越えて統合展開する事が可能」** になります。

また、このデータの即時同期の環境下では、

**（1）オンタイム・オンデマンドでのバッチ処理や、各種の高度なデータ処理を実施**
**（2）現場側を常に直前迄のデータ環境でサポートする事が可能（カスタマー360等）**
**（3）24時間365日を前提としたデータ運用環境でも、一気通貫なデータ駆動型DXが可能**
**（4）サイロの壁を越えて、同期先の環境で戦略的な仕掛けを実施可能（リアルタイムDWH）**
**（5）即時・低遅延でのExactly Onceベースのリモート・レプリケーションが可能**

等を手に入れる事が出来るようになります。

# 時間情報をデータ処理の主人公に帰還させる・・・
多くのデータでは、 **エビデンスとしての処理受け付けの時間情報** は、あらゆる局面で重要な役目を持たされているかと思います。基本的に **既存の電子帳簿型システムでは「そもそも・・・現在のDX環境を支えきる仕様で構成されていない」** という現実があり、この既存 **仕様の限界がデータ駆動型DXやデータ・ドリブンにおける制限事項** になっているのではないかと感じています。

勿論、それらを回避する目的で編み出されたDWH等のデータ利活用システムも、**稼働時間内におけるトランザクション負荷を分離させるという目的は充分果たされている** かと思いますが、現実的には **現場業務におけるデータ処理は常に変化している** のも事実です。また、企業・団体活動の結果や成果がデータとして明確に規定されるのであれば、**「データ利活用の時間軸に可能な限りの制限は設けない」というアプローチ** は、特に昨今の機械学習やIoT技術の進化、またそれらを起点にしたAI処理（時系列未来予測など・・）への対応を想定した場合、**方法論自体を再考する必要が有る** のは自明の理なのではないでしょうか？

**データはDWHやクラウド・サーバ室で起きているのではなく**
**データ現場で時々刻々起きている・・・**

何処かで聞いた記憶の有る某映画の名台詞の様ですが、多分これが一番的確に **「データ駆動型DX」を言い表している** 気がしています。

# データ駆動型DX基盤を分担データシステムで創る・・・
既に既出の動画になりますが、分担データシステムを構成する双方のDB間に対する即時同期設定を、**複雑な専門的プログラムを作成する事無くノーコードで実現** して・・・

![Sample001.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197589/3be7b71c-23f3-2643-5942-c2187514090c.gif)

という処理がサクッと！実現出来る時代になったという事はご理解頂けたかと思います。

更に、この即時・低遅延の同期環境下では、ターゲット側のDBテーブルに対して **「遠慮会釈無く」各種のデータ駆動型DXデータ処理を「オンタイム・オンデマンド仕掛ける」事が出来る** 様になりますので,既存オリジナルデータを取り扱う電子帳簿型システムの **「静」と**、データ駆動型DX側のデータ・コンピューティング側の **「動」の相反するデータ処理を分担出来る**、持続発展可能な新しいコンセプトのデータ環境をシンプルに実現する事が可能になります。

![スクリーンショット 2022-07-18 6.03.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197589/340db379-2378-fc4a-3dee-6b7e4c26bf71.png)

# さて次回は・・・
補足作業で延び延びになっていましたが、いよいよ今までの検証内容を総括した一大スペクタクルに挑戦したいと思います。複数回に渡る検証作業と投稿になるかと思いますが、その際は引き続き宜しくお願い致します。

# 謝辞
本検証は、Equalum社,SingleStore社,insightsoftware社の全面バックアップにより実施しています。この貴重な機会を提供して頂いた3社に対して感謝の意を表すると共に、本内容と各社の公式ホームページで公開されている内容等が異なる場合は、3社の情報が優先する事をご了解ください。

[データ駆動型DX基盤を創る](https://qiita.com/wadaken1961/items/535d960961f64a98735f)
[データ駆動型DX基盤を創る（補足編1）](https://qiita.com/wadaken1961/items/657521d83649571ee76e)
wikiを読むのが憂鬱だったのでヒソカに読んでもらった

# はじめに
wikipedia、読んでますか？

どうも。
最近資格試験にフォーカスしているのですが、wikiを含め難しい記事を参照する機会が増えてきました。

wikiの文って読んでればわかるんですが、
* 長い
* 難しい
* 息苦しい（見やすさのための改行とかない）

って感じでバカほど読みづらいんですよね。
斜め読みマスターの私から申し上げれば非常にめんどくさいです。

ということで、ヒソカさんに読んでいただきました。


# 完成物
https://twitter.com/yotu_xxx/status/1548744307942649862?s=20&t=2vbv-OiFmj0biTEwdCrACw

https://github.com/yotuTxT/hisoka_wiki/blob/main/

# 作り方
備忘録も兼ねて作り方を残しておきます。

## ファイル構造
```
script_name
├ manifest.json
└ script.js
```

## manifest.json
```json
{
  "name": "hisoka_wiki",
  "action": {},
  "manifest_version": 3,
  "version": "0.1",
  "description": "wikiを、読むよ...♠",
  "permissions": [
    "activeTab",
    "scripting"
  ],
  "content_scripts": [{
    "matches": ["https://ja.wikipedia.org/*"],
    "js": ["script.js"]
  }]
}
```

特筆すべきは`content_scripts`の部分。
* `matches` -> **スクリプトが反映されるurl**の指定
* `js` -> **スクリプトファイル**の指定

と言ったかんじ。

## script.js
実装要件は以下の通り
* HTML内部から「句読点（。）」を探し出す
* 句読点を「❤、♠、◆、♣」のいずれかに置き換える
* ついでに記号の前に三点リーダー（...）をランダムに付ける

```js
let trump_marks = [
  "&#x2665;&#xFE0F;", 
  "&#9824;&#65039;",
  "&#9827;&#65039;",
  "&#9830;&#65039;"];
let dot = "";
let str = "";

while(document.body.innerHTML.includes("。")) {
  dot = (Math.random() > 0.5) ? "..." : "";
  str = `${dot}${trump_marks[Math.floor(Math.random() * trump_marks.length)]}`;
  document.body.innerHTML = document.body.innerHTML.replace("。", str);
}
```

# 課題点
* めっちゃ重い
ページ読み込み時に一括で変換してるので、句読点数に比例して処理が走ります。
このため、長いページになると一時的に固まるなどの弊害が出てしまいました。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2175091/1e23544d-2a48-fac3-6c4e-dbc3caa443dc.png)
自分が出てるタイトルのページで固まってて恥ずかしくないんか？

* ページ更新に弱い
ページ読み込み時の一回のみ処理を行っているため、urlにカーソルを合わせると出るポップアップなど、動的に変化する部分に対応してません。イベントを拾えば実装できそうですが、~~癪なので~~忙しい身の上なのでやりません。

# おわりに
chromeの拡張機能に触れつつ、勉強に疲れたときの息抜きが増えるのはいいですね。
ありがとうございました。もう使いません。
【Rails】Git Lintの設定【Git Lint】

## Git Lintの設定
```configuration.yml
:analyzers:
  :commit_author_capitalization:
    :enabled: true
    :severity: :error
  :commit_author_email:
    :enabled: true
    :severity: :error
  :commit_author_name:
    :enabled: true
    :severity: :error
    :minimum: 2
  :commit_body_bullet:
    :enabled: true
    :severity: :error
    :excludes:
      - "\\*"
      - "•"
  :commit_body_bullet_capitalization:
    :enabled: true
    :severity: :error
    :includes: "\\-"
  :commit_body_bullet_delimiter:
    :enabled: true
    :severity: :error
    :includes: "\\-"
  :commit_body_tracker_shorthand:
    :enabled: true
    :severity: :error
    :excludes:
      - "(f|F)ix(es|ed)?\\s\\#\\d+"
      - "(c|C)lose(s|d)?\\s\\#\\d+"
      - "(r|R)esolve(s|d)?\\s\\#\\d+"
  :commit_body_leading_line:
    :enabled: false
    :severity: :warn
  :commit_body_line_length:
    :enabled: true
    :severity: :error
    :maximum: 72
  :commit_body_paragraph_capitalization:
    :enabled: true
    :severity: :error
  :commit_body_phrase:
    :enabled: true
    :severity: :error
    :excludes:
      - "absolutely"
      - "actually"
      - "all intents and purposes"
      - "along the lines"
      - "at this moment in time"
      - "basically"
      - "each and every one"
      - "everyone knows"
      - "fact of the matter"
      - "furthermore"
      - "however"
      - "in due course"
      - "in the end"
      - "last but not least"
      - "matter of fact"
      - "obviously"
      - "of course"
      - "really"
      - "simply"
      - "things being equal"
      - "would like to"
      - "\\beasy\\b"
      - "\\bjust\\b"
      - "\\bquite\\b"
      - "as\\sfar\\sas\\s.+\\sconcerned"
      - "of\\sthe\\s(fact|opinion)\\sthat"
  :commit_body_presence:
    :enabled: false
    :severity: :warn
    :minimum: 1
  :commit_body_single_bullet:
    :enabled: true
    :severity: :error
    :includes: "\\-"
  :commit_subject_length:
    :enabled: true
    :severity: :error
    :maximum: 72
  :commit_subject_prefix:
    :enabled: true
    :severity: :error
    :delimiter: " "
    :includes:
      - Fixed
      - Added
      - Updated
      - Removed
      - Refactored
  :commit_subject_suffix:
    :enabled: true
    :severity: :error
    :excludes:
      - "\\."
      - "\\?"
      - "\\!"
  :commit_trailer_collaborator_capitalization:
    :enabled: true
    :severity: :error
  :commit_trailer_collaborator_duplication:
    :enabled: true
    :severity: :error
  :commit_trailer_collaborator_email:
    :enabled: true
    :severity: :error
  :commit_trailer_collaborator_key:
    :enabled: true
    :severity: :error
    :includes:
      - "Co-Authored-By"
  :commit_trailer_collaborator_name:
    :enabled: true
    :severity: :error
    :minimum: 2
```
ROS よく使うコマンド

ROSの(個人的に）よく使うコマンドを載せときます。


```
source ~/catkin_ws/devel/setup.bash
```

catkin_wsを有効にするためのコマンドです。
※ROSのERRORの原因で(個人的に)多いのがこのコマンドの実行し忘れです。
2022/7/18主にITとかセキュリティの記事

客の個人情報が流出か…酒蔵が販売管理を行うサーバーに不正アクセス 名前・住所・電話番号等保管(7/15)
https://www.fnn.jp/articles/-/390006

サイバー犯罪情勢など情報共有　佐賀県ネットワーク・セキュリティ対策協議会(7/16)
https://www.saga-s.co.jp/articles/-/886390

データベースに不正アクセス　農研機構サイトに改ざん画面(7/15)
https://newstsukuba.jp/39569/15/07/

Androidマルウェアアプリ300万超ダウンロード、ユーザー評価に頼るのは危険(7/16)
https://news.mynavi.jp/techplus/article/20220716-2400051/

CSCの調査により、乳児用粉ミルクのサプライチェーン危機における不審なドメイン登録の急増が明らかに(7/16)
https://www.jiji.com/jc/article?k=20220713005069&g=bw

“シャコ”botネットに要注意？　Cloudflareが大規模なDDoS攻撃の詳細を報告
Cloudflareは2022年6月に対処した大規模なDDoS攻撃の詳細を報告した。同社はこのサイバー攻撃を実行したbotネットをシャコ（Mantis shrimp）になぞらえて「Mantis」と命名している。(7/16)
https://www.itmedia.co.jp/enterprise/articles/2207/16/news035.html

通信障害で返金、韓国KTは40億円　各国でルール整備 KDDI 断絶の86時間（4）(7/16)
https://www.nikkei.com/article/DGXZQOGR11D0G0R10C22A7000000/

ショート動画、急成長TikTokに対抗　メタやYouTube(7/16)
https://www.nikkei.com/article/DGXZQOGN24AMO0U2A620C2000000/

上海の流出情報はアリババ保管か　容易に窃取可能な状態(7/15)
https://news.infoseek.co.jp/article/kyodo_kd-newspack-2022071501001747/?tpgnr=world

バグやトラブルから考える「コロンブスの卵」(7/13)
https://qiita.com/kumaichi/items/78fdebab273655aea4ec

ホンダ車、ハッキングへの脆弱性に警鐘　30メートル先から解錠(7/16)
https://jp.sputniknews.com/20220716/30-12032601.html

ウェブサイトの訪問者が「個人情報」を盗まれる：ブラウザーの挙動を悪用した新たなハッキング手法が波紋(7/16)
https://wired.jp/article/web-deanonymization-side-channel-attack-njit/
I2 Localization でスプライトをスクリプトから動的にローカライズ

# はじめに
<!-- 発端や概要を記載 -->

https://assetstore.unity.com/packages/tools/localization/i2-localization-14884?locale=ja-JP

I2 Localization とっても便利なローカライズのアセット。

スプライト、音声、フォントなど色々ローカライズ設定できる記事は見つかったが、実際にそれを言語切り替えする記事が見当たらなかったので書きました。

タームの設定などは[公式ドキュメント(英語)](http://inter-illusion.com/assets/I2LocalizationManual/AddingTerms.html
)を参照してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2739654/22acaa93-1288-1c9f-4ec4-f3e47071dbbd.png)

Type: Text を選択すると他の型でもローカライズ対応できます。



# 目次
<!-- タイトルとアンカー名を編集 -->
1. [やり方](#Chapter1)
1. [解説](#Chapter2)
1. [最後に](#Chapter3)
1. [参考文献](#reference)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# やり方

```c#:ImageLocalizeExt.cs
using UnityEngine;
using UnityEngine.UI;
using I2.Loc;

public static class ImageLocalizeExt
{
    public static void LocalizeSprite(this Image self, string term)
    {
        var localize = GetLocalizeComponet(self.gameObject);
        localize.Term = term;
    }
    private static Localize GetLocalizeComponet(GameObject targetGameObject)
    {
        if (targetGameObject.TryGetComponent<Localize>(out var localize))
        {
            return localize;
        }
        return targetGameObject.AddComponent<Localize>();
    }
}
```

```c#:SpriteText.cs
using UnityEngine;
using UnityEngine.UI;
using I2.Loc;

public class SampleLocalize: MonoBehaviour
{

    [SerializeField, TermsPopup] private string _term; //I2 Localizeで設定したタームを設定する

    [SerializeField] private Image _targetImage; //ローカライズしたい画像

  
    void Start()
    {
        _targetImage.LocalizeSprite(_term);
   
    }

}

```
SampleLocalizeはサンプルなので各自ローカライズしたいタイミングで　_targetImage.LocalizeSprite(_term);　を呼び出せば動的に変えられます。

<a id="#Chapter2"></a>
# 解説

I2.Localizeのアセットに付属してるcomponent Localize をローカライズしたい画像のゲームオブジェクトにアタッチした後にスクリプトからタームを書き換えている。


<a id="#Chapter3"></a>
# 最後に

ローカライズしてるスクリプトを見てみる感じ、Object型で管理してるのでもっと拡張性の高いものは作れそう。
本当はLocalizeコンポーネントを経由ではなく、直接画像のスプライト差し替えしたいができなかったので誰か知っている方がいれば教えていただけると幸いです。


<a id="#reference"></a>
# 参考文献
- [公式ドキュメント](http://inter-illusion.com/assets/I2LocalizationManual/I2LocalizationManual.html)
brew パッケージダウングレード

# 現状確認

- "*" がついた行がバージョン：バージョンが最新だけである。
    - よって、バージョンを下げるために、git コマンドを用いて、任意の状態へ戻す。

```
❯ brew info yt-dlp
yt-dlp: stable 2022.6.29 (bottled), HEAD
Fork of youtube-dl with additional features and fixes
https://github.com/yt-dlp/yt-dlp
/opt/homebrew/Cellar/yt-dlp/2022.6.29 (4,306 files, 41.0MB) *
  Built from source on 2022-07-14 at 10:43:54
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/yt-dlp.rb
License: Unlicense
==> Dependencies
Required: python@3.10 ✔
==> Options
--HEAD
	Install HEAD version
==> Caveats
fish completions have been installed to:
  /opt/homebrew/share/fish/vendor_completions.d
==> Analytics
install: 23,185 (30 days), 51,680 (90 days), 142,979 (365 days)
install-on-request: 15,848 (30 days), 35,433 (90 days), 87,120 (365 days)
build-error: 0 (30 days)
```


# brew のどこのディレクトリで実行するか

人それぞれあると思いますが、私の場合、以下の`Formula`ディレクトリで実行するとうまくいきました。

```
cd /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula
```

# バージョンはどれにするか

- 予め、目的となるバージョンに目をつけておきます。
- 例えば、最新のバージョンではバグが有り、1つ前に戻したい場合、現状の一つ前のメジャーアップデートのときの SHAハッシュ をコピーすれば良いです。

```
❯ git log --oneline yt-dlp.rb
e2ecd4f1b91 yt-dlp: update 2022.4.8 bottle.
51fcd178019 yt-dlp 2022.4.8
7a3108c7a0f yt-dlp: update 2022.3.8.2 bottle.
debbd213ef9 yt-dlp 2022.3.8.2
80f61b7fa15 yt-dlp: fix HEAD build
ee2e044937b yt-dlp: update 2022.2.4 bottle.
414180e697d yt-dlp 2022.2.4
cc055197122 yt-dlp: update 2022.2.3 bottle.
f2607fcafbb yt-dlp 2022.2.3
...
```

# バージョンを指定して、取得する

```
git checkout 7a3108c7a0f yt-dlp.rb
```

# 再インストールする

```
❯ brew unlink yt-dlp.rb
Unlinking /opt/homebrew/Cellar/yt-dlp/2022.6.29... 4 symlinks removed.
❯ brew install yt-dlp.rb
```

# 確認

- 現在のバージョン("*" がついている)が、最初のときと変化して、一つ前のバージョンへなっていることが確認できました。

```
❯ brew info yt-dlp
yt-dlp: stable 2022.6.29 (bottled), HEAD
Fork of youtube-dl with additional features and fixes
https://github.com/yt-dlp/yt-dlp
/opt/homebrew/Cellar/yt-dlp/2022.3.8.2 (2,138 files, 23.7MB) *
  Poured from bottle on 2022-07-18 at 02:06:46
/opt/homebrew/Cellar/yt-dlp/2022.6.29 (4,306 files, 41.0MB)
  Built from source on 2022-07-14 at 10:43:54
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/yt-dlp.rb
License: Unlicense
==> Dependencies
Required: python@3.10 ✔
==> Options
--HEAD
	Install HEAD version
==> Caveats
fish completions have been installed to:
  /opt/homebrew/share/fish/vendor_completions.d
==> Analytics
install: 23,185 (30 days), 51,680 (90 days), 142,979 (365 days)
install-on-request: 15,848 (30 days), 35,433 (90 days), 87,120 (365 days)
build-error: 0 (30 days)
```

# 感想

- パッケージ管理に、brew を使っていますが、brew 自体がバージョン管理をどうやっているかは、git を使っているというだけでよくわかっていませんでした。
- こうやって、手動でバージョンを戻したりすると、パッケージ管理ツールでも、git の使い方は普通なのだなと思いました。


# 参考にしたサイト
https://blog.mothule.com/mac/homebrew/mac-homebrew-how-to-downgrade
Docker + Python + Flask で本番環境とテスト環境のポート番号の振り分け方法

## やりたいこと
Dockerのコンテナとのポートフォワーディング（ポート番号指定）を「テスト環境（自端末）」と「本番環境（heroku）」で<font color="red">ソースファイルを分ける事なく</font>実現したい。


::: note info
①テスト環境ではホストOSの「8888」番ポートをコンテナの「8888」番ポートと紐づけたい。
②本番環境ではポート番号はheroku側で自動割当されるので、それを利用したい。
:::


ネット調査をしてくと「dockerfile」や「docker-compose.yml」を本番環境用とテスト環境用でわけるような手法がありました（パット見でよく読んでいませんが）が、これは避けたかった。

## 前提
 - 本番環境：heroku
 - テスト環境：ローカル端末（自分のPC）
 - docker-compose.ymlを利用
 - dockerfileを利用
 - pythonでアプリは実装
 - webserverはflaskを利用
 ::: note info
できるだけ最小の単位で実現したかったという思いから、「dockerfile」だけでなんとかできないか模索したが、どうにもならなかったので「docker-compose.yml」を利用することとしました。
:::
## STEP1：ホスト側に環境変数を新規に作成
 ::: note info
図のように[wk_port：8888]というやつを作成
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/998522/40cbb515-bfd1-3f4b-06d4-e7235955f9c4.png)

## STEP2：ホスト環境変数を「docker-compose.yml」で参照


 ::: note info
ポイント
①[ports]のところでホスト側の環境変数を参照し、ポートフォワーディング
②後続で、コンテナ上の環境変数としても[wk_port：8888]を利用したいので「environment」にて定義

ちなみに[8888]は本番環境では利用しません。
テスト環境用のポート番号として利用します。
:::

```docker-compose.yml
version: '3'

services: 
 ＜サービス名＞: 
  build: 
   dockerfile: ./Dockerfile
  ports:
   - $wk_port:$wk_port
  environment: 
   wk_port: $wk_port

```

## STEP3：webserver（Flask）起動時にコンテナ上の環境変数を参照し、ポートを振り分け
ソース自体は「hello world」を表示させるだけの簡易なものです。

 ::: note info
ポイント
最後の部分で「コンテナ上」の環境変数[wk_port]を参照し、値が設定されている場合、設定されていない場合で処理を振り分けています

①値が設定されている場合＝テスト環境です
　⇒　wk_portをポート番号として利用するようにしています
②値が設定されていない場合＝本番環境（heroku）です
 　⇒　herokuからポート番号を取得するようにしています

なお、heroku上（dynoという単位）で環境変数を作成することも可能です。
ターミナルから「heroku config:set ＜環境変数名＞=＜設定値>」を実行する
今回ですと「heroku config:set wk_port=''」としました。

:::

```hello.py

from flask import Flask
import os

app = Flask(__name__)

@app.route('/')
def hello():
    return 'hello world'

if __name__ == '__main__':
    if os.environ.get('wk_port','')!='':
        app.run(debug='true',host='0.0.0.0',port=os.environ.get('wk_port','8888'))            
    else:
        app.run(debug='true',host='0.0.0.0',port=os.environ.get('PORT','5000'))
```

## 最後に
この方法が正しいのかはわかりませんが、実現できたので記録として残します。

## 後日談
投稿後、気になる点がでてきたので、別記事で投稿しています。

https://qiita.com/std-flower/items/31452e3a428355014721
Firestoreにトリガーを仕掛けて、データ登録時に自動でプロパティを追加する方法

Firestoreにデータを登録する際に、サーバ側で現在日時のプロパティをデータに追加する例を以下に示します。

# 参考
https://firebase.google.com/docs/reference/functions/providers_firestore.documentbuilder.html#oncreate

# 手順

## 1. Cloud FirestoreでCollectionを作っておく
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2739613/2c5495b9-7e00-c88f-6fb0-ce749dc0bdf7.png)

## 2. Cloud Functionsをセットアップする
以下の手順に従う。
https://firebase.google.com/docs/functions/get-started

## 3. あらかじめ用意されている、index.jsを以下のように書き換える

```javascript:index.js
const functions = require("firebase-functions");

// addDateTimeが関数名となる。
// regionを指定しないと、us-central1にfunctionが出来てしまったので、明示的に東京(asia-northeast1)を指定している。
exports.addDateTime = functions.region("asia-northeast1").firestore
    .document("ここにcollection名を指定/{docId}")
    .onCreate((snap, context) => {
      snap.ref.set({"addedField": new Date()}, {merge: true});
    });
```

setメソッドの説明
https://googleapis.dev/nodejs/firestore/latest/DocumentReference.html#set

## 4. コードをデプロイする

例
```bash
$ firebase deploy --only functions
```

Functionsのトップ画面を見ると、関数が追加されている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2739613/62a2ef70-1e1d-745e-53ce-14be8d26bef2.png)



## 5. Firestoreにデータを登録する

管理コンソール画面から手動で追加した例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2739613/984c3045-5b6f-b032-77b6-90609c332b45.png)

## 6. 自動でプロパティ追加

管理コンソール画面で数秒待った後、表示が更新され、プロパティが追加されていることが確認できた。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2739613/938a12f2-2852-a255-d1f5-7c92959c6b8e.png)

# 備考

FirestoreのデータをREST APIで取得すると、デフォルトで、createTime, updateTimeプロパティが自動で付与されておりますが、GCP内部で使用するデータと思われるため、明示的に付与する例を上記に示しました。

```JSON
{
  "documents": [
    {
      "name": "projects/projectIDは伏せておく/databases/(default)/documents/collection1/IewJlzFPfrItKiay9Ve9",
      "fields": {
        "addedField": {
          "timestampValue": "2022-07-17T16:00:44.165Z"
        },
        "name": {
          "stringValue": "hoge"
        }
      },
      "createTime": "2022-07-17T16:00:41.213663Z",
      "updateTime": "2022-07-17T16:00:48.588309Z"
    }
  ]
}
```
RxJS　Observableの流れ

<h1> Observableの作成流れ </h1>

```
①Observableを作る(rxjs)
　➡︎const {Observable} = rxjs;

②Observableの処理を作成する(Observable.create)
   const aaa = Observable.create((observer) => {
　　observer.next(1);
   console.log('sample');
   observer.complete();
   observer.error('error');
}

③Observableの処理を実行する(subscribe)

 aaa.pipe().subscribe((x) => console.log(・・・));
 aaa.pipe().subscribe((c) => console.log(・・・));

④Observable処理の取り消し(unsubscribe)
　→subscribe実行で、はじめて処理が実行され、unsubscribeで処理実行が取り消されます。

　　　　　//①を省略、②
　        const test = Observable.create((observer) => {
            observer.next(1),
            observer.next(2),
            observer.next(3),
            setTimeout(()=>{
                observer.next(4)
            },1000);
        })
　　　　　//③
        const subscription = 
        test.pipe().subscribe(
            (x) => console.log(`${x} :`,x ** 2)
        );
　　　　　//④
        subscription.unsubscribe();

```
ふりかえりを数ヶ月回したので紹介してみる（続）

前回に引き続きふりかえりについて紹介したいと思います。

前回の記事は [ふりかえりを数ヶ月回したので紹介してみる](https://qiita.com/nogu-rin/items/b1b657449fd33ee1e666) です
タイトルからわかる通り、前回の続編となります！
前回の記事では、ふりかえりを回し始めた経緯やふりかえりの内容について紹介しました。
ふりかえりの今後として、他のフレームワークやファシリテーションを持ち回るということをやっていきたいと書いたので、
ファシリテーションを持ち回ったふりかえりの内容を紹介したいと思います。

# まずはおさらいから

- ふりかえりを行っているプロジェクトの情報です
    - 弊社の社内基幹システムの開発チーム
    - チームメンバーは11名
    - ふりかえりの期間は約1ヶ月を対象
    - ふりかえり時間は1時間30分
    - KPTを事前に記載してもらい、ふりかえりの場で共有する
    - これまでのふりかえりを定期的に行っておらず、チームとしての課題や問題点、良かった点などが見えなかった

- ふりかえりには3つの目的と3つのステップがある
    - 立ち止まる
    - チームの成長を加速させる
    - プロセスをカイゼンする

![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3630353838392f64313935373536332d393562612d626263382d326539312d6530666232373735336361632e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605889/909bd509-e03a-967f-175d-8be33e4f0258.png)


# ふりかえりのファシリテーションを持ち回る

### なぜふりかえりのファシリテーションを持ち回ったのか？

最初の数ヶ月は私自身がファシリテーションを行っていました。
自分自身が持ち回ることでプロジェクトでの課題や問題点を自分ごとのように捉え、_カイゼン内容なども主体的に考えられる_ のではと感じ持ち回ることにしました。

### どのようにファシリテーションを持ち回ったのか

はじめは私が次回ファシリテーターを**指名制**にしました（誰も手が挙がらなかったかも・・・）

はじめに私から指名を受けたのは**3年目の若手社員**です。最初はすごく戸惑っていましたが、自身の成長にも繋がり苦手なことをすることで自身の成長にも繋がるだろうということで快く受け入れてもらいました。

### 実際にやってみてどうだったか

実際にふりかえりをまわしてみて、淡々と進めてもらっていましたが、もう少し内容を掘り下げたり、他の人に話題を振ってみたりという点では自分含めて反省する点を見つけることができました。
そのあたりはふりかえりの振り返りで私から見た視点をフィードバックし、次にいかしてもらえると嬉しいです。

そのふりかえりの最後に、次のファシリテーターで2名の方から手を挙げてもらいました。
手を挙げてもらったことに**感謝**と、**主体性がいるメンバーが出てきたこと**でファシリテーションを持ち回るという意図を汲み取ってくれたのでは？と自分自身で感じたことは大きな収穫でした。

その手を挙げてもらった2名もファシリテーターとして、ふりかえりをまわしてもらい、
良かった点・悪かった点などを次に活かしてもらいたいと思います。

特に直近のふりかえりでは、今年の新入社員がOJT期間中ということもあり、見学会含めて参加されていたので
ファシリテーターはすごく緊張されていましたね。いつもと違う環境で実施するのも良い刺激になったのではと思いました。

### ファシリテーションを持ち回ることについて今後は？

実際に持ち回ることで、ファシリテーションをする側と参加する側とでは意識の違いが出てきたのではと思いました。
実際にファシリテーションをやってみた後では、そのメンバーからの質問などファシリテーターではないが
主体性が出てきたのではと感じています。

このふりかえりを通して、ファシリテーションを実践することで、今後別プロジェクトに参画した際に
いざファシリテーターとなった場合でも活かせることが多くあるのではと思います。

すでに持ち回っている方も多いと思われますが、まだ実践されていない方は是非試して見てください！！
【ApolloClient】ReferenceError: fetch is not defined でTestが落ちる場合の対処方法

# 概要

`Navigation`のテストを`React-testing-library`で実行すると以下のエラーでテストが落ちた。

以下を参考にしてエラーを正常化させたので方法を残す

https://stackoverflow.com/questions/50688998/using-apolloclient-with-node-js-fetch-is-not-found-globally-and-no-fetcher-pas

```bash
ReferenceError: fetch is not defined
```

```ts
const createApolloClient = () => {
  return new ApolloClient({
    // ブラウザで実行してる場合はwindowに値がある SSRかCSRかを切り替え
    ssrMode: typeof window === 'undefined',

    // hasuraのAPIリンク
    link: new HttpLink({
      uri: 'https://hoge.hasura.app/v1/graphql'
    }),

    // お決まりの呪文
    cache: new InMemoryCache()
  })
}
```

# 対処方法

`import 'cross-fetch/polyfill` を追加することでテストが正常に通るようになる

```diff_typescript
+ import 'cross-fetch/polyfill'

const createApolloClient = () => {
  return new ApolloClient({
    // ブラウザで実行してる場合はwindowに値がある SSRかCSRかを切り替え
    ssrMode: typeof window === 'undefined',

    // hasuraのAPIリンク
    link: new HttpLink({
      uri: 'https://hoge.hasura.app/v1/graphql'
    }),

    // お決まりの呪文
    cache: new InMemoryCache()
  })
}
```
sqlアンチパターンまとめ

# sqlアンチパターンまとめ

## ①ジェイウォーク（信号無視）

データにカンマや区切り文字を利用してしまってる設計パターン。

#### 問題点
長くなる・毎回更新が必要。
あと、経理だけを消したい場合に消すのがめんどかったりする。


| 社員cd | 所属部署 |
|:-:|:-:|
|  1 | 営業  |
|  2 |  営業/経理 |

#### 解決策

行を分けて管理する。

| 社員cd | 所属部署 |
|:-:|:-:|
|  1 | 営業  |
|  2 |  営業 |
|  3 |  経理 |

ただ、分析用のデータベースなら良いかも。
集約して表示したいニーズはあるので。


## ②ナイーブツリー

親子関係のあるデータベースの設計

#### 問題点
階層構造の参照が難しい。

| id | 組織名 | 上位組織 | 
|:-:|:-:|:-:|
|  1 | 本社  | Null|
|  2 | 営業部 | 本社 |
|  3 | 経理部 | 本社 |
|  4 | 営業1課 | 営業部 |

#### 解決策

| id | 組織名 | 上位パス | 
|:-:|:-:|:-:|
|  1 | 本社  | 本社/|
|  2 | 営業部 | 本社/営業部 |
|  3 | 経理部 | 本社/経理部 |
|  4 | 営業1課 | 本社/営業部/営業一課 |

ただ、参照しやすいが管理しにくい
管理の場合は上の設計で良いかと。
再起クエリを利用する手もある

## ③IDリクワイアド（とりあえずid）

受注idと品目idでユニークなのにidが存在する

| id | 受注id | 品目cd | 
|:-:|:-:|:-:|
|  1 | 9001  | 11 |
|  2 | 9002 | 12 |
|  3 | 9003 | 14 |

#### 問題点
idいらん。
データベースの構造上、整合性を保てない
id7でid6とおなじ受注idと品目idが存在した場合、整合性を保てない

#### 解決策

受注idと品目idで主キーを構築したら整合性持てる。

代替キーを用いていい場合（上のデータ構造の場合）はあまりにも自然キー（受注idとか）が長い場合

|受注id | 品目cd | 
|:-:|:-:|
| 9001  | 11 |
| 9002 | 12 |
| 9003 | 14 |


## ④キーレスエントリ（外部キー嫌い）
外部キーつけるかつけないか

| 大会テーブル |  |  |
|:-:|:-:|:-:|
| 大会id | 主催者id  |  大会名 |


| 主催者テーブル |  |  |
|:-:|:-:|:-:|
| 主催者id | 主催者名 |  email |


割と議論分かれる。

教科書的には外部キーはあった方が良い。
→db内の整合性を保つことができる。

アプリケーション側でチェックしてるなら不要
→二重チェックが必要でメンテナンスが面倒。
→データバッチで順番を意識する必要が出てくる。

## ⑤EAV（エンティティ・アトリビュート・バリュー）

汎用的な属性テーブルを作らない方がいいよ

| 品名cd | 属性名 | 属性値 |
|:-:|:-:|:-:|
| I001 | 品目名  |  みかん |
| I001 | 単価 |  100 |
| I002 | 品目名 |  レモン |
| I002 | 単価  |  150 |


#### 問題点

sqlデータ型が使えない。
not null制約など、必須設定ができない。
ただ、拡張性は高い（変更が生じた時もテーブル定義を変えなくても良い）

#### 解決策

データ属性は横持ちしましょう。

| 品名cd | 品目名| 単価 |
|:-:|:-:|:-:|
| I001 | みかん  | 100|
| I002 | レモン |150|

未知項目はeav（上のデータ構造）でもよさそう。


## ⑥ポリモーフィック関連

電話とかメールの問い合わせを、一つの「問い合わせ詳細テーブル」で管理してしまう。
同じ内容だけど違う振る舞いしてしまう。


#### 問題点

制約が使いにくい。

#### 解決策

それぞれ別テーブルを作る。
今回だと電話のお問合せ詳細テーブル、メールのお問合せテーブルを作る。


## ⑦マルチカラムアトリビュート（複数列属性）

さっきのEAVと近い。

| 受注id | 品目名1 | 品目名2 | 品目名3 |
|:-:|:-:|:-:| :-:|
| 1 | りんご  | null| null|
| 2 | みかん |すいか| null|
| 3 | もも |メロン|イチゴ|


#### 問題点
同じ値が複数の値に入ってしまうケースが考えられる。

正規化ができていないので管理が難しい。
（一意性の確保・更新対象列の確認）

#### 解決策
正規化しましょう。
従属テーブルを作成

| 受注id | 品目名 |
|:-:|:-:|
| 1 | りんご |
| 2 | みかん |
| 3 | もも |


### ⑧メタデータトリブル（メタデータ大増殖）

同じ構造のデーブルが複数存在する。

たとえば年ごとに作成
| 受注テーブル|
|:-:|

| 受注テーブル2022|
|:-:|

| 受注テーブル2021|
|:-:|


#### 問題点
汚くなる。
謎のテーブルが生まれる。


#### 解決策
パフォーマンスを保つために過去テーブルを一つに。

| 受注テーブル|
|:-:|

| 過去受注テーブル|
|:-:|
【Next.js】react-testing-libraryでexpect(...).toBeInTheDocument is not a functionが出たとき

# 概要

`@testing-library/react": "11.2.6"` でテストを実行すると以下のエラーが発生した

以下を参考に正常化したので方法を残す

https://stackoverflow.com/questions/56547215/react-testing-library-why-is-tobeinthedocument-not-a-function

```bash
 Navigation Test Cases
    ✕ Should route to selected page in navbar (463 ms)

  ● Navigation Test Cases › Should route to selected page in navbar

    TypeError: expect(...).toBeInTheDocument is not a function
```


# 対処方法

`@testing-library/jest-dom`を`Test`ファイルに記述する

```tsx:hoge.test.tsx
import '@testing-library/jest-dom'
```
JavaSilver_SE11(黒本の改造問題)

[黒本](https://www.amazon.co.jp/%E5%BE%B9%E5%BA%95%E6%94%BB%E7%95%A5Java-SE-11-Silver%E5%95%8F%E9%A1%8C%E9%9B%86-1Z0-815/dp/4295007625/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=3BXM80JNHBY45&keywords=javasilver+%E9%BB%92%E6%9C%AC&qid=1658066191&sprefix=javasilver+%E9%BB%92%E6%9C%AC%2Caps%2C355&sr=8-1)のP234_第7章_13の問題をIDEで書き写しながら
少しコードを変更したりして理解を深めていた所「へぇー」となったのでメモ

先に言っておくと以下に記載するようなコードはわざわざ書かないと思います。

### 「へぇー」となったこと
1. interfaceにprivateであればdefaultメソッドじゃない具象メソッドが定義することができる。

検証コード
```java
// ① Workerインターフェース
public interface Worker {
    private void work(){
        System.out.println("Workerのwork");
    };
    default void callWork(){
        work();
    };
}

// ② Employeeクラス
public class Employee {
    public void work(){
        System.out.println("Employeeのwork");
    }
}

// ③ Engineerクラス(①と②をそれぞれ継承、実現しているクラス)
public class Engineer extends Employee implements Worker{}

// ④ Mainクラス(上記クラスのプロセッサー)
public class Main {
    public static void main(String[] args) {
        Worker worker = new Engineer();
        worker.callWork();
    }
}
```
出力結果
```shell
Workerのwork
```

つまり上記検証コードでは② Employeeクラスは一切使われていません。笑
<br><br>


「Employeeのwork」を出力したい場合は以下のどちらかで呼び出せる

その1
```java
// ① Workerインターフェース
public interface Worker {
    private void work(){
        System.out.println("Workerのwork");
    };
    default void callWork(){
        work();
    };
}

// ② Employeeクラス
public class Employee {
    public void work(){
        System.out.println("Employeeのwork");
    }
    // 以下のメソッドを追加(検証コードとの差分部分はここのみ！！)
    public void callWork(){
        work();
    }
}

// ③ Engineerクラス(①と②をそれぞれ継承、実現しているクラス)
public class Engineer extends Employee implements Worker{}

// ④ Mainクラス(上記クラスのプロセッサー)
public class Main {
    public static void main(String[] args) {
        Worker worker = new Engineer();
        worker.callWork();
    }
}
```
その2
```java
// ① Workerインターフェース
public interface Worker {
    void work(); // 抽象メソッドとしてい定義のみしておく(検証コードとの差分部分はここのみ！！)
    default void callWork(){
        work();
    };
}

// ② Employeeクラス
public class Employee {
    public void work(){
        System.out.println("Employeeのwork");
    }
}

// ③ Engineerクラス(①と②をそれぞれ継承、実現しているクラス)
public class Engineer extends Employee implements Worker{}

// ④ Mainクラス(上記クラスのプロセッサー)
public class Main {
    public static void main(String[] args) {
        Worker worker = new Engineer();
        worker.callWork();
    }
}
```
その1とその2の出力結果
```shell
Employeeのwork
```

黒本読めば分かる話ですがまとめると
- その1のコードは同名のメソッド名の場合defaultじゃない方が強いってだけ
- その2のコードはEmployeeのwork()でWorkerの抽象メソッドwork()が実装されたってだけ
POSTとPUTの違いって何？

## はじめに
2022年の5月にSIerからWeb系自社開発会社に転職したありひとと申します。
前職ではミッションクリティカルな社会インフラを支えるシステムだったこともあり、使っている技術が枯れまくったものでした。
したがって、前職と今とでは扱っている技術スタックが全く違っており日々勉強の毎日です。

今回は、なんとなく知っていたけど、前職の実務では使ってこなかったREST APIに関連して「POST」と「PUT」の違いについてまとめます。

ちなみに前職では、REST APIではなくSOAP通信がメインで使わていました。

## この記事でわかること
REST APIの文脈における「POST」と「PUT」の違いについて理解してもらうのが、この記事のゴールです。
そもそもREST APIって何？とかSOAPとの違いは？ってのは別記事でまとめる予定です。


## POSTとPUTはどちらも登録
この手の「〜の違い」とかって自分でも何回も調べてしまうのですが、よくある説明で「POSTは新規登録、PUTは更新」というのがあります。これは誤りです。
結論を述べると
- 「POST」と「PUT」はどちらも「登録」
- ただしリソースの指定方法が違う

1ポチ目はそのまんまですが、2ポチ目はどういうことか？具体的にみていきます。

## 書籍の登録をする場合
まずREST APIというのは、ざっくり言えば「HTTPプロトコルとHTTPのメソッドを使って、サーバ上のリソースにアクセス・操作する仕組み」だと思ってください。
「リソース」というのがまた曖昧な表現ですが、例えば読んだ本を管理するWEBサービスがあったとすれば、その書籍のデータひとつひとつが「リソース」です。

前述したように「POST」と「PUT」はどちらもリソースを登録するときの操作ですが、そのときリソースの識別番号の体系を要求側が意識するか/しないかが違ってきます。

### POSTの場合
例えば、POSTを使って書籍データをサーバに登録しようとした場合、下記のようなHTTPリクエストラインになります（ヘッダ、ボディは省略）。
```
POST https://hogehoge.com/books
```
この場合、登録した書籍データがどんな識別番号体系で管理されるかを要求する側（クライアント）は事前に知っている必要は必要ありません。サーバ側の方で識別番号を発行し、登録してくれます。
今回の例でいうと、この書籍管理サービスでは書籍データを4桁の数字で管理するつくりになっているようですが、POSTであればクライアントはそのことを知らずとも書籍を登録することができます。

```mermaid
sequenceDiagram
  actor C as Client
  participant S as Server
  C->>S: POST http://hogehoge.com/books（書籍を登録してください）
  S->>S: 識別番号1234を発行 & 登録
  S->>C: 200 OK（識別番号1234で登録完了しましたよ）
```

### PUTの場合
では、PUTの場合はどうなるかというと、お察しのとおりクライアント側が識別番号を指定する必要があります。
```
PUT https://hogehoge.com/books/1234
```
```mermaid
sequenceDiagram
  actor C as Client
  participant S as Server
  C->>S: PUT http://hogehoge.com/books/1234（識別番号1234で書籍を登録してください）
  S->>S: 識別番号1234で登録
  S->>C: 200 OK（登録完了しましたよ）
```
すでに識別番号1234で書籍データが登録されている場合に、同じように識別番号1234で別の書籍を登録しようとすれば、サーバ側の情報を書き換えることができます。
だから「POSTは新規登録、PUTは更新」と説明されるんですね。
実際は「POST」も「PUT」も「登録」なのですが、「PUT」は識別番号を指定できるがゆえに既存のデータに対して登録し直し＝更新ができる、というわけですね。

## 編集後記（余談）
今回、記事内のシーケンス図をつくるために[mermaid](https://mermaid-js.github.io/mermaid/#/)という言語を使ってみました。
はじめて使ってみたのですが、シーケンス図に限らずフロー図、ER図などをとても簡単かつ直感的に書くことができ、とてもよかったです。


## 参考文献
- [『現場で役立つシステム設計の原則 〜変更を楽で安全にするオブジェクト指向の実践技法』](https://amzn.to/3RGg6xN)：コードの実装例は少なくやや抽象的な記述が多く感じるかも知れないが、オブジェクト指向パラダイムの言語を使って開発していくうえで重要な概念について網羅的かつわかりやすく書かれている
APG4bで自分が書いたコード2　EX6~10

<!-- 
[]()
```c++:EX.cpp

```
 -->
[APG4bで自分が書いたコード1](https://qiita.com/sy1/items/97e15040d529a367452e)の続き
atcoder側からコメントアウトされているソースをコピペして改変して解答することを求められている場合があります。
その場合コメントアウト部分は適宜省略しています

[EX6 - 電卓をつくろう](https://atcoder.jp/contests/APG4b/tasks/APG4b_cq)

```c++:EX6.cpp

#include <bits/stdc++.h>
using namespace std;
 
int main() {
  int A, B;
  string op;
  cin >> A >> op >> B;
 if(A>=0&&B<=100)//0≦A,B≦100
 {
  if (op == "+") {
    cout << A + B << endl;}
    
  else  if (op == "-") {
    cout << A - B << endl;}
  
  else if (op == "*") {
    cout << A * B << endl;}
  else if (op == "/"&&B!=0) {
    cout << A / B << endl;}
     else     cout << "error" << endl;
 
 }
  else     cout << "error" << endl;
  }

```

[EX7 - bool値パズル](https://atcoder.jp/contests/APG4b/tasks/APG4b_cp)
```c++:EX7.cpp
#include <bits/stdc++.h>
using namespace std;
 
int main() {
  // 変数a,b,cにtrueまたはfalseを代入してAtCoderと出力されるようにする。
  bool a = true;// true または false
  bool b = false;// true または false
  bool c =true; // true または false
 
  // ここから先は変更しないこと
 
  if (a) {
    cout << "At";
  }
  else {
    cout << "Yo";
  }
 
  if (!a && b) {
    cout << "Bo";
  }
  else if (!b || c) {
    cout << "Co";
  }
 
  if (a && b && c) {
    cout << "foo!";
  }
  else if (true && false) {
    cout << "yeah!";
  }
  else if (!a || c) {
    cout << "der";
  }
 
  cout << endl;
}


```

[EX8 - たこ焼きセット](https://atcoder.jp/contests/APG4b/tasks/APG4b_co)
```c++:EX8.cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
    int p = 0;
    cin >> p;
    int N = 0;
    int price = 0;
    string text;
    if (p == 2 || p == 1) {
        if (p == 2) {
            cin >> text;
        }
        cin >> price;
        cin >> N;
        if (p == 2) {
            cout << text << "!" << endl ;
        }
        cout << price * N << endl;
    }
}
```
 
[EX9 - 複合代入演算子を使おう]()
```c++:EX9.cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
    int x, a, b;
    cin >> x >> a >> b;
    if (x >= 0 && a <= 100 && b <= 100) {
        // 1.の出力{
        x++;
        cout << x << endl;
        x *= a + b;
        cout << x << endl;

        x *= x;
        cout << x << endl;

        x--;
        cout << x << endl;

   }
}

```
 
[EX10 - 棒グラフの出力](https://atcoder.jp/contests/APG4b/tasks/APG4b_cm)
```c++:EX10.cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
	int A, B, i = 0;
	cin >> A >> B;
	if (A >= 0 && A <= 20 && B >= 0 && B <= 20)
		cout << "A:";
	while (i < A)
	{
		cout << "]";
		i++;
	}
	cout << endl;
	i = 0;
	cout << "B:";

	while (i < B)
	{
		cout << "]";
		i++;
	}
	cout << endl;



}

```
ロジックを委譲して Controller を薄くする

# 初めに
僕は C# のピンク本（※１）も読み終えていない頃、ASP.NET Core MVC のウェブアプリケーション開発に参加しました。
先行開発されていたソースコードを読みながら学び、学びながらコードを書く毎日。
すでにあったソースコードは、デザインパターンであるとの認識でした。

# 気づいてしまった問題点
でも

- #region で隠された、とっても長い Controller クラス
    - Model はデータモデルと化し、Controller に長大なロジックが書かれている
    - 多くの private メソッド（他の Controller からのコピペ跡も）
- View の中で暴れまわる Model
    - Razor でアクセスできるからと言って、View の中に多くの判定文（＝ロジック）が書かれている

> なんだか嫌な予感がするよ、R2。

# 学びの海へ

Head First のデザインパターン本第2版（※２）を開いてザックリ読んでみましょう。

MVC パターンについては P.520 から。

### Model
> モデルにはすべてのデータ、状態、アプリケーションロジックを格納します。モデルはビューとコントローラーには無関心ですが、状態の操作と取得のためのインターフェースを用意しており、また状態変化の通知をオブザーバーに送信します。

### View
> モデルの表示を行います。通常、ビューは表示に必要な状態とデータをモデルから直接取得します。

### Controller
> ユーザー入力を宇k鳥、ユーザー入力がモデルにとってどのような意味を持つか解釈します。

MVC の M の部分の説明が長い。つまり一番大切。逆に C の説明は短い。現状の実装はこれに則していない。おかしい！（安直）
Model が主役、View/Controller はシンプルに！

# やったこと

### View に渡すのはシンプルな ViewModel
- M の部分を、ロジックを持つ Model と、表示用の ViewModel に分ける
    - View 内に複雑なロジックは持ちこませない
    - 判定が必要な場合、**判定結果**を ViewModel で渡す

### Controller からロジックを排し、徹底的に薄くする。
- Request の処理や認証などを除いてロジックをクラス化して委譲
    - データ取得・計算
    - 取得したデータや計算結果から ViewModel の生成

# 効果
### MVC の役割が明確になった
- MVC パターンを生み出した先人への敬意
- Model が主役になる下準備
- 最も多い View の変更が Model/Controller へ飛び火しにくい構造に
### Model にロジックが集まった
- ロジックの再利用性が高まった
- アプリケーションの中で大切なもの（ビジネスロジックやドメインモデル）がはっきり見えてきた
### View からロジックが消えた
- 比較演算子がなくなった
- 深くへのメンバーアクセスがなくなった
### Controller が Model と View を結ぶシンプルな橋渡し役になった
- 1000行以上あったコードが半分以下になった

個人的にはクラスを分割していくことで大切なルール、ビジネスロジックというものが見えてきたのが最大の効果だったと思います。
一子相伝のべた書き長大クラスを見つけたら、ちょっとずつでもいいのでロジックを分割して行こうと心に決めました。

# おわりに
正直、この変更には結構な時間をかけちゃいました。今回書いた内容以外に DDD とかアーキテクチャーの話もあって、今尚旅の途中・・・
ソースコードレビューでチームメンバーにもさんざん協力してもらいました。
それに対して得られたものはほかのメンバーに伝わりにくいものかもしれません。しかし、確実に未来を形作るための第一歩になったと確信しております。

後悔は全くしていません。だって、変えたかったんだもん。

さぁ、皆さんご一緒に。

**変えたい時が、書き換え時！**


---

# 参考文献

##### ※１「実戦で役立つ C#プログラミングのイディオム/定石&パターン」出井秀行（著） 技術評論社
非常にわかりやすく C# の入門書にもってこいだと思います。ただ C# 6（一部7）に準拠した内容で、物足りなさもあり。最新版の仕様に準拠して改版してほしいなぁ。
##### ※２「Head First デザインパターン 頭とからだで覚えるデザインパターンの基本 第2版」Eric Freedman, Elisabeth Robson（著） O'REILLY
皆さんご存じ、にやにや読み進めることのできる珍しい技術書シリーズ。「紫のアレ」でなくなったことは少し寂しいですが、改訂版第一刷を購入できたことに深く感謝。
OpenJDKを選定するにあたっての話

## はじめに
おはようございます、会えない時のために、こんにちは。こんばんは。おやすみ。どうもSky・Secureのキティちゃんです。最近トゥルーマンショーという映画をU-NEXTで観たので、劇中での主人公のセリフを真似てみました。分かりますかね。それはさて置き、今回は「OpenJDKを選定するにあたっての話」を書きたいと思います。

## きっかけ
そもそも、なぜこの内容を書こうかと思ったかというと、仕事でOpenJDKを利用しているのですが、「そういえば、結構古いバージョンを利用していないか？脆弱性とか大丈夫？」という話が持ち上がったのがきっかけです。

## OpenJDKって？
プログラミング言語Javaのプログラムを作るときに必要なもの(JDK)であり、JDKのオープンソース(ソースが手に入り、独自に修正等しても良いもの)版となります。一時期、Oracle社がJDKを有償化したことにより、OpenJDKを利用しようとする流れがあったのですが懐かしいですね(遠い目)。

## 脆弱性って？
脆弱性とは何か？簡単に言えば、セキュリティ上の欠陥のことを言います。
例えばですが、AmazonのようなショッピングサイトにはIDやパスワードを入力するようなログイン画面がありますよね。もし、ログイン機能をプログラミング言語で開発した際に、セキュリティ対策に不備があったとしましょう。すると、攻撃者たちは、SQLインジェクションといった攻撃を仕掛け、ユーザの個人情報を盗もうとしたりします。これが、セキュリティの脆弱性となりえます。

上記を踏まえた上で、OpenJDKに脆弱性はあるのかといいますと、結論としてはあります。OpenJDKもプログラミング言語にて開発されているため、脆弱性は存在します。

## OpenJDKもただ選べばいいわけではない？
「脆弱性って？」でも書いたように、OpenJDKにも脆弱性は存在するため、闇雲に選べば良いわけではありません。かと言って、最新バージョンを利用すればいいかというとそういうわけにもいきません。現存のソースが古いバージョンのOpenJDKをもとに書かれている場合、新しいバージョンのOpenJDKを利用しようとするとプログラムが想定通りの動作をしない場合があります。これは、元々利用していたメソッドの変更や削除等がされているためです。そのため、プログラムの改修が必要となります。また、前提としてセキュリティの脆弱性がないかというのも重要です。

## そもそも脆弱性のないものなんてあるのか？
正直ないと思います。脆弱性というのはいつ新しいものが発見されてもおかしくはありません。常に鼬ごっこのようなものなのです。そのため、どこかで妥協する必要もでてきます。よって、OpenJDKを選定をする場合は、バージョンを上げることを検討しつつ、現時点で危険度が高めの脆弱性が検出されていないか、現存のプログラムが稼働できるバージョンであるかを考慮する必要があるのではないかと考えます。

## 脆弱性を確認するサイト（参考程度に）
下記URLの他に脆弱性についてまとめてくれているサイト等もありますので、「OpenJDK 脆弱性」などで検索してみると良いです。
・https://openjdk.org/groups/vulnerability/advisories/
・https://www.oracle.com/security-alerts/
・https://nvd.nist.gov/vuln#

## 最後に
今回は、『OpenJDKを選定にするにあたっての話』という題で脆弱性についても触れながら書いてみましたが、改めてソフトウェアというのは慎重に扱わないといけないなと思いました。決して濃い内容ではありませんが、少しでも誰かにお役に立てればと存じます。

## 参考文献
『JDK、Oracle JDK、OpenJDK、Java SEってなに？』@nowokay様
https://qiita.com/nowokay/items/c1de127354cd1b0ddc5e
『OpenJDK』Wikipedia
https://ja.wikipedia.org/wiki/OpenJDK
『OpenJDK Vulnerability Advisories』Oracle社OpenJDK公式サイト
https://openjdk.org/groups/vulnerability/advisories/
『NATIONAL VULNERABILITY DATABASE』NIST NVD
https://nvd.nist.gov/vuln#
SESで契約更新してもらうために現場に入る前にやること

３０超えて経理からSESでエンジニアにキャリアチェンジしたのですが、
最近、人と話す機会があり割とすごいことと言ってもらえたので、なんとなく、how toみたいな感じで書き出してみました。未知の技術へのキャッチアップのhow toですね。
ポエム付きですが、読んでみてください。

SESで契約更新してもらうために参画前にやることを書きました。
目新しいことはないと思いますが、だれかの役に立てばいいです。

キャリアの最初は契約更新してもらえなくてすぐに切られるので大変でした。
20代でキャリアチェンジしたほうが絶対いいなと僕自身はたくさん思い知らされました。
現在は、自社サービス会社で働けてます。
僕の立場としてはエンジニアになるために一時的にSESで経験を積むのは良いと思います。

#### 現場に入る前にやること
- 書籍を買って読む
- 自宅で開発環境を作る
- 適当に触ってみる
- 時間があれば、簡単なtodoリストを作って学ぶ

キャリアの最初のころは、これをずっとやってても全く歯が立たず、精神的に追い詰められてました。
２年くらいやったころにやっと、だんだんわかってきました。

最初のころは終電で帰って、寝ながら本を読み、朝早く起きて客先に向かう生活でした。
精神的な苦痛もあって毎日吐きそうでした。
力がないときに、入れる現場は基本的に炎上してました。

自分のできなさもあるのですが、やったことないことってキャッチアップは時間かかりますね。
聞ける環境であれば、ひとに聞ければいいですね。
聞けない環境であれば、なるべく精神を強くもってがんばるしかないです。
あんまり頑張りすぎると精神の回復に時間がかかるのでおすすめできませんが。

もし、可能であれば、技術スタックは固定したほうがよいです。
でもなかなか、全て固定はできないので、ある程度phpだけは固定。Laravelは固定と営業さんに話しましょう。
自分は個人的にこれを勉強していてこの技術スタック現場に行きたいと日々発言していきましょう。
Power Automate: 外部サイトのファイル更新の検知をファイルサイズで行う

# 背景
外部サイトにある Excel ファイルの情報を Power BI で見える化する際に、
対象ファイルが更新された時だけに通知が欲しい。

ということで、検知方法を検討してみた記録

# 概要

- One Drive に アップロード
- 最新と以前のファイルサイズを比較
- 差分があった場合
    - 通知
    - 以前のファイルを最新ファイルで上書き

::: note warn
注意
- Share / One Drive での保存ファイルサイズは相違があるので、比較する場合は保存場所は同一にする必要有<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/eb900811-ec22-18b8-4619-c4df885e02fb.png)

- 更新時、ファイルサイズが同一になる場合は検知できない
:::

# 詳細
## フロー
1. [URL からファイルをアップロード](]https://docs.microsoft.com/ja-jp/connectors/onedriveforbusiness/#upload-file-from-url) で外部ファイルの取り込み
1. [パスを使用してファイル メタデータを取得](https://docs.microsoft.com/ja-jp/connectors/onedriveforbusiness/#get-file-metadata-using-path) で以前のファイルの情報取得（ファイルサイズ）
1. 以前と最新のファイルサイズを比較
1. 通知<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/4d9fec2f-b494-aea1-b660-f27001d5f80b.png)
1. [ファイルをコピーする](https://docs.microsoft.com/ja-jp/connectors/onedriveforbusiness/#copy-file) 最新ファイルで以前のファイルを更新
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/56c39de0-042e-df59-9a09-dc503a86fdb5.png)

## 通知 Adaptive Card
```json:通知
{
    "type": "AdaptiveCard",
    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
    "version": "1.4",
    "msteams": {
        "width": "full"
    },
    "body": [
        {
            "type": "TextBlock",
            "text": "ファイル更新通知",
            "wrap": true,
            "color": "Attention",
            "isSubtle": false
        },
        {
            "type": "TextBlock",
            "text": "ファイルが更新されました：Old File: @{outputs('Get_file_metadata_using_path')?['body/Size']} /sharepoint: @{outputs('Get_file_metadata')?['body/Size']}/New One: @{outputs('Upload_file_from_URL')?['body/Size']}",
            "wrap": true
        },
        {
            "type": "ActionSet",
            "actions": [
                {
                    "type": "Action.OpenUrl",
                    "url": "https://www.meti.go.jp/statistics/tyo/seidou/result/ichiran/08_seidou.html?pk_campaign=mm_statistics",
                    "iconUrl": "https://th.bing.com/th/id/R.3a646f7af36c19f92453a872e1a6a329?rik=NGLnMz%2bk6faQkw&riu=http%3a%2f%2fit.miami.edu%2f_assets%2fimages%2fO365_Power_BI.png&ehk=HBpjA2cY61UDu8947P%2f2Gm%2fB0yMsGkb7ZeS3AFO5hBs%3d&risl=&pid=ImgRaw&r=0",
                    "title": "更新されたと思うので確認しよう"
                }
            ]
        }
    ]
}
```

# あとがき
あとは、定期動作させれば OK

# keyword
how to detect file update in Power Automate
AWS パフォーマンスの設計原則について（自分用メモ

パフォーマンス効率の設計原則


・高度な技術を誰でも使えるようにする
高度な技術の知識とサービスをクラウドが提供することにより、オンプレミスでは実装が難しい技術であっても容易に利用できます。
AWSサービスは技術の実行環境が整っているので、環境構築など専門的な知識の理解がなくても、高度な技術を用いたシステムを実装できます。

・数分でグローバルに展開する
世界各地にある複数のAWSリージョン経由で、世界中から低遅延でサービスへアクセスできます。
例えば、EC2インスタンスやS3などは接続元の所在地に合わせて、サービスを展開する場所を世界中のリージョンから選べるため、全世界のユーザーが低遅延でサービスを利用できます。

・サーバーレスアーキテクチャを使用する
サーバーの運用や管理を意識することなくサービスを展開できます。
例えば、S3の静的Webサイトホスティング機能ではWebサーバーの運用や管理をしなくても、S3に保存している静的コンテンツをWebサイトとして公開できます。

・より頻繁に実験する
異なるタイプのサーバーやストレージ、設定を使用した比較テストをより頻繁に実施します。
例えば、EC2インスタンスのインスタンスタイプはサーバー構築後でも容易に変更ができるので、インスタンスタイプごとの負荷状況を定期的に比較し、もっとも適切なインスタンスタイプを選択できます。

・システムに対する精通の程度を考慮する
クラウドサービスの技術を理解し、実現したいシステムを最適な技術で実装します。
例えば、AWSのデータベースにはRDS、Redshift、DynamoDBなど複数のサービスがあるので、それぞれの技術的な特徴をよく理解し、実装したいシステムのデータ構造やアクセスパターンに応じて選択します。




インスタンスの「フロントエンド」とは、インスタンスよりユーザー側のことを指します。また「バックエンド」とは、ユーザーから見てインスタンスより奥側のことを指します。AWSの一般的なWeb3層構成では、インスタンスのフロントエンドにはELB、AWS Global Accelerator、Amazon CloudFrontなどを配置し、バックエンドにはデータベースを配置します。
【PHP】基本文法まとめ（※随時追加予定）

PHPを学習している中で出てきた基本文法をまとめていきたいと思います。

# 基本形
- PHPを使うときは、`<?php ... ?>`でくくる。
- 文末に必ずセミコロンをつける。

```php
<?php
  echo 'HelloWorld！';
?>
```   
<br>

# 変数の四則演算
- 省略形の一覧


まずは検索機能のコントローラーを作成します。
同時にコントローラーアクションも作成します。

```php
// 変数xに１を代入
$x = 1;

// 四則演算の省略形
$x += 10;
$x -= 10;
$x *= 10;
$X /= 10;
$x %= 10;

// 値が１のときだけの省略形
$x ++;
$x --;
```    

# 文字列の連結
- 文字列の連結は、ドット「.」を使う
- 「.=」で省略して書ける

```php
$name = '佐藤';

echo '私の名前は'.$name.'です';
// 結果: 私の名前は佐藤です

// 省略形
$name .= 'にしき';
echo $name;
// 結果: 佐藤にしき
``` 

学習完了次第、随時更新予定です！
あくまで備忘録なので足りない説明等多々あるかと思います。
行き詰まった際の助けになれば幸いです。
Bash スクリプトのユニットテスト（フレームワーク無し）

`test` と `trap` を使うことで簡易的に Bash スクリプトのユニットテストを実現できます。

```bash
# 最初のテストが失敗した時に終了したい場合は次の行のコメントアウトを外す.
# set -e

# コマンドの失敗を trap して行番号とコマンドを表示する.
trap 'echo "Assertion failed at line ${LINENO}: ${BASH_COMMAND}"' ERR

# テスト対象の関数.
function hello {
    echo "Hello $1."
}

# このテストは成功する.
test "$(hello 'Taro')" = 'Hello Taro.'

# このテストは失敗する.
test "$(hello 'Jiro')" = 'Hello Taro.'

# このテストも失敗する.
test "$(hello 'Hanako')" = 'Hello Taro.'
```