OmniAICreator/Qiita-1.07M huggingface dataset:
空白/空文字レコードを確認して削除/抽出する(SPSS Modeler データ加工逆引き5-7)

# 空白/空文字レコードを確認して削除/抽出（欠損値/空白の削除と抽出）

![スクリーンショット 2022-07-13 11.02.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/f187779f-4a00-10a4-f359-7742e6628ce0.png)

## 1.想定される利用目的

・顧客属性データのクレンジング
・設備IoTデータの欠損値の処理

## 2.サンプルストリームのダウンロード

https://github.com/yoichiro0903n/blue/blob/main/missing_blank.str?raw=true

## 3.サンプルストリームの説明

![スクリーンショット 2022-07-13 13.46.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/2d25f93b-965d-14d4-2619-ddcd4a6a7b9c.png)

a.入力するデータは以下の通りです。

![スクリーンショット 2022-07-13 11.08.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/d78628fc-232c-daae-65aa-08c73727a887.png)

#### [テーブル]ノードから削除/抽出のノードを自動生成させる方法

b.[レコード集計]ノードを編集します。
![スクリーンショット 2022-07-13 11.12.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/d9dac97f-fc72-00cb-344d-a222a64dfa0d.png)

[テーブル]ノードを実行します。種別が空白（この時点では見た目は同じ）のふたつのセルを指定したままメニューから[条件抽出ノード(OR)]を選択します。
![スクリーンショット 2022-07-13 11.13.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/6db21c04-0f86-cd1a-9ddd-c0f523713feb.png)

c.[条件抽出]ノードが自動生成されます。空文字("")と空白文字(" ")の2種類が存在しておりor条件で[破棄]します。
![スクリーンショット 2022-07-13 11.13.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/170be8c5-f7c6-0f9f-0138-497e7800fa27.png)

[プレビュー]します。
![スクリーンショット 2022-07-13 11.14.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/6e7d24b2-af10-993f-5c56-8a0a184fb672.png)

d.[条件抽出]ノードを複製して[破棄]から[含める]へ選択を切り替えます。
![スクリーンショット 2022-07-13 11.13.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/e652cb2b-bea8-e1e9-730f-51fdcd8fbcbb.png)

[プレビュー]します。
![スクリーンショット 2022-07-13 11.14.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/7d946cf7-ac8e-5830-4dec-910f4f78efd4.png)

####  [データ検査]ノードを利用する方法

e.[データ検査]ノードを実行します。有効なレコードは5件で2件は空白文字（うち空文字が1）だとわかります。
[種別]の行を選択したまま以下のメニューを選びます。
![スクリーンショット 2022-07-13 11.16.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/bb4b016e-5522-435b-4dad-895cc14285cd.png)

[テーブル]で選択したフィールドを選択しています。
![スクリーンショット 2022-07-13 11.17.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/5986c3d8-d8d4-a595-aec9-8c5fb673eff6.png)

f.[条件抽出]ノードが自動生成されます。c同様に空白レコードを抽出します。
![スクリーンショット 2022-07-13 11.18.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/db644130-548b-9ecb-bbb9-18e726d16333.png)

g.fの反対のモードです。dと同様に該当レコードを破棄します。
![スクリーンショット 2022-07-13 11.58.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/cab96410-da80-d5ca-7aa4-2d3e125dbb11.png)

#### 注意点

空白と空文字は見た目は同じですが、区別されて処理されますので注意します。

## 4.参考情報

#### [データ検査]ノードの解説記事

https://www.ibm.com/blogs/solutions/jp-ja/spssmodeler-push-node-3/

https://qiita.com/416nishimaki/items/27fc3b6a2e596726877c

https://qiita.com/kawada2017/items/2a99ab2941f3793fc300


#### SPSS Modeler ノードリファレンス目次

https://qiita.com/416nishimaki/private/503037195081d3323eee

#### SPSS Modeler 逆引きストリーム集（データ加工）

https://qiita.com/416nishimaki/private/4bf813e6cba84b2a1008
メモがある取引先責任者を抽出する


直接抽出するのは難しいのでApexバッチで取引先責任者にマークをつけて、あとはレポートで対応することとします。

[I would like to export contacts with notes](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000H01ux)

```
public class BAT_findNote_Contact implements Database.Batchable<sObject> {
    
    // *******************************************************************************************
    //    
    // BAT_findNote_Contact bat  = new BAT_findNote_Contact();
    // ID jobId = Database.executeBatch(bat);                                 
    //                                                                                
    // ********************************************************************************************
    
    public Database.QueryLocator start(Database.BatchableContext BC) {
        // collect the batches of records or objects to be passed to execute
        
        String query = 'Select Id From Contact WHERE isNote__c =False ';
        System.debug('******** query ' + query);
        return Database.getQueryLocator(query);
    }
    
    public void execute(Database.BatchableContext BC, List<Contact> conList) {
        
        System.debug('******** comList ' + conList);
        Set<Id> ConIdSet = new Set<Id>();
        for (Contact c : conList ){
            ConIdSet.add(c.Id);
        }
        system.debug('### ConIdSet ############ ----> '+ ConIdSet.size() );    
        
        List<ContentDocumentLink> CDLList = [SELECT Id,LinkedEntityId FROM ContentDocumentLink WHERE LinkedEntityId =: ConIdSet ];
		system.debug('### CDLList ############ ----> '+ CDLList.size() );                 
        List<Contact> updateContactList = new List<Contact>();    
        
        for (ContentDocumentLink CDL : CDLList ){
            Contact con = new Contact();
            con.Id = CDL.LinkedEntityId;
            con.isNote__c = True;
            updateContactList.add(con);
        }
        
        try {       
            
            system.debug('### updateContactList ############ ----> '+ updateContactList.size() );                 
            if(updateContactList.size() > 0) update updateContactList;
            
        } catch(Exception e) {
            System.debug(e);
        }
        
    }
    
    public void finish(Database.BatchableContext BC) {
    }
}
```
Kaggle・機械学習に関する有益情報まとめ

kaggleや機械学習についての良記事と，その記事で扱っている内容を簡潔に書きました．

### Pytorch

[Pytorch入門](https://atmarkit.itmedia.co.jp/ait/subtop/features/di/pytorch_index.html)
テンソル操作のチートシート，モデル定義，損失関数，オプティマイザ，評価関数の定義

[Pytorchチュートリアル（日本語）](https://yutaroogawa.github.io/pytorch_tutorials_jp/)
モデル定義から，画像認識，自然言語処理，強化学習の実装までの解説

### データ加工
[データサイエンス100本ノック](https://github.com/The-Japan-DataScientist-Society/100knocks-preprocess/tree/master/docker/work)

[Pandas100本ノック](https://qiita.com/kunishou/items/bd5fad9a334f4f5be51c)


### 特徴量選択
[特徴量選択のまとめ](https://qiita.com/shimopino/items/5fee7504c7acf044a521)
Filter method：データセット完結
相関係数，カイ二乗，フィッシャー係数

Wrapper method：モデルを使用して最適な組み合わせ選択
Step forward，Step backward， Exaustive search

Embedded method： モデル学習時に特徴量選択
L1正則化
### 機械学習モデル
[代表的な機械学習手法一覧](https://qiita.com/tomomoto/items/b3fd1ec7f9b68ab6dfe2)
【教師あり】
木：決定木，回帰木，ランダムフォレスト，GBDT
回帰：SVM，ロジスティック回帰，線形回帰
ベイズ：ナイーブベイズ
クラスタリング：k-NN
アンサンブル：ブースティング，バギング
NN：パーセプトロン，CNN，RNN，ResNet
時系列：自己回帰，移動平均，自己回帰和分移動平均モデル
【教師なし】
クラスタリング：k-means，DBSCAN，トピックモデル（LDA）
NN：自己組織化マップ


[各分野ごとの最先端モデル](https://webbigdata.jp/ai/post-10153)
【画像認識】 EfficentNet，Normarilzer-Free Networks
【画像セグメンテーション】 Efficient-Unets
【物体検出】 YOLO-V5，VarifoculNet
【テーブルデータ】 GBDT，GNN，
【自然言語処理】 GPT-3，BERT, Google Switch Transformer
【教師なし特徴表現学習】 変分オートエンコーダ
【強化学習】 Deep Q-Network，Advantage actor-critic
### 損失関数
[分類タスクの損失関数](https://www.hellocybernetics.tech/entry/2017/06/20/135402)
分類（正負）ロジスティック損失
分類（確率）交差エントロピー誤差，ヒンジ損失

[回帰タスクの損失関数](https://www.hellocybernetics.tech/entry/2017/06/19/084210)
二乗損失，感度損失，Huber損失

### 最適化アルゴリズム
[最適化アルゴリズムまとめ](https://qiita.com/omiita/items/1735c1d048fe5f611f80)
勾配降下，SGD，ミニバッチSGD，モーメンタム，RMSprop，Adam

### アンサンブル手法
[Kaggleで学ぶモデルのブレンディングとスタッキング](https://atmarkit.itmedia.co.jp/ait/articles/2112/02/news016.html)
平均法
投票法
スタッキング
ブレンディング

### 評価関数
[評価関数のまとめ](https://amateur-engineer-blog.com/machine-learning-metrics/)
回帰：MAE，MSE，RMSE，RMSLE
二クラス分類(正負)：Accuracy，Precision，Recall，F1-score
二クラス分類（確率）：交差エントロピー，AUC
多値分類：多クラス交差エントロピー，Multi-class accuracy，mean/macro/micro-F1

### ハイパーパラメータチューニング
[ハイパラチューニングまとめ](https://qiita.com/c60evaporator/items/ca7eb70e1508d2ba5359)
評価指標の定義
チューニング手法：グリッドサーチ，ランダムサーチ，ベイズ最適化
交差検証手法

### 追加予定
・転移学習
・大規模深層学習モデル
・活性化関数
[powershell] トランスクリプトにNULが出力されないようにする

地味に困って、解決方法を見つけたのでメモ

powershellでStart-Transcriptして、サーバの構成情報を吐き出してくツールつくった

```
Start-Transcript -Path
ipconfig
...
#他にも色々な構成情報をファイルに出力
```

コマンドごとにログファイルへのリダイレクト(>)を書くのが汚く見えて嫌いなので、こういう造りにしてる。

しかし、DOSコマンドを呼び出すと、日本語部分で、トランスクリプトに1バイトごとに特殊文字?が入る
ex. ipconfig結果、tasklistのヘッダー、「コマンドは、正しく完了しました」の文言など

VSCODEでの見え方。1バイトごとにNULが入ってる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620712/5ee9a653-6890-ca99-2db7-38956030fbe2.png)

sakuraでの見え方。日本語部分の前の行に全角空白が1バイトおきにはいり、日本語部分は1バイトごとに半角空白が入ってるように見える
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620712/b78ffb78-2ec5-8137-0db7-a4da53c81971.png)

上記はtypeperfコマンドの出力で、日本語部分は最後のちょろっとした部分なので無視でもいいんだけど、ipconfigとか日本語がたくさん出力されるコマンド結果だとかなり悲惨。

標準出力は普通なのに、ファイルに落とすとなぜかこうなる。

コマンド結果をいちいちファイルにリダイレクトしてあげれば回避できるんだけど、できればトランスクリプト使いたい。
で、解消方法は、コマンドのあとにパイプで```Out-Default```を渡すこと

```
Start-Transcript -Path
ipconfig | Out-Default
...
```

インターネットで調べても同じ事例は見つからなかったけど、別の事例で紹介されてたOut-Defaultを試してみたら直った。
[PowerShellのStart-TranscriptでDOSコマンドの実行結果が保存されない時の対処法](https://orebibou.com/ja/home/201503/20150302_001/)
LeetCode easy: 383. Ransom Note

LeetCodeを解いているので記録しています。

## 解いた問題

https://leetcode.com/problems/ransom-note/

> Given two strings ransomNote and magazine, return true if ransomNote can be constructed by using the letters from magazine and false otherwise.
Each letter in magazine can only be used once in ransomNote.

### Example 2:

>Input: ransomNote = "aa", magazine = "ab"
Output: false

### Example 3:

>Input: ransomNote = "aa", magazine = "aab"
Output: true

## 処理の流れ
magazineの中身を一回しか使えないのに注意
シンプルに考えると、ransomNoteの文字列をforループで回してmagazineの文字列を検索。
なければその場でFalseを返す。
あればmagazineの中の文字を削除してループに戻る。
最後までループが完了すればtrue

## 調べたこと

文字列検索。含まれていない時は-1が返る。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf

指定した文字削除

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace

https://zukucode.com/2017/04/javascript-string-remove.html

***The original string is left unchanged.***
非破壊。str.replace()しても元の文字（str）は変わらない！

## 最初に書いたコード
```javascript
/**
 * @param {string} ransomNote
 * @param {string} magazine
 * @return {boolean}
 */
var canConstruct = function(ransomNote, magazine) {
    for (var i = 0; i < ransomNote.length; i++) {
        if (magazine.indexOf(ransomNote[i]) === -1) {
            return false
        } else {
            // if found  
            // delete a letter
            magazine = magazine.replace(ransomNote[i], '')
        }
    }
    return true
};
```
>Runtime: 103 ms, faster than 81.57% of JavaScript online submissions for Ransom Note.
Memory Usage: 49.3 MB, less than 10.08% of JavaScript online submissions for Ransom Note.

## 解いた後に
動画はないのでDiscussのページを見てみる。
投票率の高いJavascriptのコード
https://leetcode.com/problems/ransom-note/discuss/385887/Javascript-solution

```javascript
var canConstruct = function(ransomNote, magazine) {
    const map = {};
    for(let letter of magazine) {
        if (!map[letter]) {
            map[letter] = 0;
        }
        map[letter]++;
    }
    
    for(let letter of ransomNote) {
        if(!map[letter]) {
            return false;
        } 
        map[letter]--;
    }
    return true;
};
```

まずmagazineをforloopで回して、
mapというオブジェクトに文字と現れる回数の辞書をつくる。
magazine = "abbcccddddeeeee"　のとき
map = { a: 1, b: 2, c: 3, d: 4, e: 5 }

同様にransomNoteをforloopで回して、
mapに対象の文字列が現れるたびに文字を減らす。
無くなった時点でfalseを返し最後まで行けた場合はtrueを返す。
大体やっていることは同じ。
ちなみに速度は
>Runtime: 133 ms, faster than 49.25% of JavaScript online submissions for Ransom Note.
Memory Usage: 44.8 MB, less than 60.46% of JavaScript online submissions for Ransom Note.

ちなみにPythonでは
https://leetcode.com/problems/ransom-note/discuss/1346131/Easiest-python-solution-faster-than-95
VSCodeのRemote Developmentでの多段SSHにおける鍵のパスフレーズ入力の手間を減らす

VSCodeのRemote Developmentが提供する機能を使えば、世界中のコンピュータを自分の手元のコンピュータからいつものようにGUIで操作でき、ネットワークがあれば、SSH経由で砂漠からリモートワークをすることも（やるひとがいるのかは別として）可能な時代になりました。

https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack

SSH経由での接続をpublic/private鍵で管理するに当たり、鍵自体にパスフレーズをかけることがあります。**多段SSHを行う場合、VSCode上では鍵のパスフレーズ認証のプロンプトが複数回表示**されてしまいます。私達は、パスフレーズを繰り返し入力するためだけに、この地球に生まれたのでしょうか？

# TL;DR
解決策は以下です：

```
ssh-add [path to your private key]
```

これは、terminalからSSH接続するときにパスフレーズを一時的にキャッシュする方法で、terminalからの多段SSH接続で使えるものです。**これがVSCodeのRemote Development拡張機能にもそのまま使える**ことに気づきました。

https://superuser.com/a/989832

**一時的にメモリに保存されている認証情報は、再起動などするとリセットされる**ようです。


# 余談

### 情報が少ないときは、別の登場人物の範疇の問題かも？

VSCodeに限定して多段SSHのパスフレーズを省略方法を検索したところ、困っている人がいたようですが、対処法が見つかりませんでした。これをRemote Developmentの問題と捉えるか、SSHの一般的な問題と捉えるかで情報量が違うのが興味深いです。特定の問題を調べて、解決策が全く出てこない場合は、関わっているであろう登場人物（＝ソフトウェアやOSの機能など）うち、別の登場人物に焦点を当ててみるといいかもしれないですね。

https://github.com/microsoft/vscode/issues/97778


### 鍵とパスフレーズについて
ちなみに、ある回答では「鍵からパスフレーズを消してしまえば解決するよ」という斜め上の意見に驚きましたが、そういう問題でもない気がします。

https://superuser.com/a/1277634

鍵が流出したときの防御としてパスフレーズをかけておくのが無難だと思われます。
そして、`ssh-add`を使ってRemote Developmentの面倒なパスフレーズを１回で済ますのが、実用的かつ安心なのではないでしょうか？

http://guides.beanstalkapp.com/version-control/tips-for-using-ssh-keys.html

それでは、いいVSCodeライフを！ごきげんよう！
【C#】switch式を使おう！

## はじめに
条件分岐の文法と言えば**if文**と**switch文**が代表的だと思います。
特に網羅的な条件の場合はif文よりコードが見やすくなるため、switch文を使用する場合が多いのではないでしょうか。
普段何気なく使っているswitch文ですがC#8.0から**switch式**が登場して、より使いやすくなりました。
特にC#や.NETは古い環境に縛られて開発しているプロジェクトが多いため（偏見？）新しい書き方に気が付いていない人も多いかもしれないです。
この記事ではまだ**switch式**を知らない人に向けて、古い書き方と比較しながら紹介をしたいと思います！

## 古い書き方
C#8.0未満の環境となるので、.NET Core 2.2や.NET Standard 2.0まではこの書き方になります。

一番ベーシックな書き方だと以下のようになります。
```csharp
enum Direction {Up, Down, Right, Left }
enum Orientation {North, South, East, West}

static Orientation ToOrientation(Direction direction)
{
  Orientation orientation;
  switch(direction){
    case Direction.Up:
      orientation = Orientation.North;
      break;
    case Direction.Right:
      orientation = Orientation.East;
      break;
    case Direction.Down:
      orientation = Orientation.South;
      break;
    case Direction.Left:
      orientation = Orientation.West;
      break;
    default:
      throw new ArgumentOutOfRangeException();
  }
  return orientation;
}
```
一番最初にswitch文を書いたときは、このように書いたのではないでしょうか。
`case`で始まり、分岐最後に`break;`を書く所は記述量も増えてしまい可読性が悪いです。

実際にはこの環境下では以下のように書くことが多いと思います。
```csharp
static Orientation ToOrientation(Direction direction)
{
  switch(direction){
    case Direction.Up: return Orientation.North;
    case Direction.Right: return Orientation.East;
    case Direction.Down: return Orientation.South;
    case Direction.Left: return Orientation.West;
    default: throw new ArgumentOutOfRangeException();
  }
}
```
分岐中に`return`することで後続に影響が無くなったため`break;`が不要になりました。
この書き方であれば行数も少なくなり、条件と結果が横並びになっているため可読性も良さそうです。
しかし、分岐の先頭で`case`始まりなのは必須のため省略はできません。

## switch式での書き方
switch式はC#8.0から登場したので、.NET Core 3.0や.NET Standard 2.1から利用可能になります。

```csharp
static Orientation ToOrientation(Direction direction) => direction switch
{
    Direction.Up    => Orientation.North,
    Direction.Right => Orientation.East,
    Direction.Down  => Orientation.South,
    Direction.Left  => Orientation.West,
    _ => throw new ArgumentOutOfRangeException(),
};
```
switch式にすることで`case`を書く必要が無くなりました！
古い書き方と比べて`return`も必要なく条件と結果だけをシンプルに表現することができました。

また、switch文と違い**式**なので変数の初期値としても利用ができます。
これは最初の古い書き方で行っていたような各条件分岐先で変数に代入することがなく、副作用の無い書き方ができるのがメリットです。

## まとめ
C#8.0のリリースは2019年9月なので、**switch式**は執筆時の段階でもう約3年も前の機能になります。（現在最新リリースはC#10.0）
保守系のプロジェクトでは開発環境がずっと固定のためなかなか新しい機能は触れないことが多いと思います。
いざ新しいプロジェクトで最新の環境になった時に困らないためにも、どういった機能がリリースされているかはチェックしておきたいです！

---

* [switch 式 (C# リファレンス)](https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/operators/switch-expression)
嫌いな技術（ガベージコレクション、Microsoft Teams、アクセシビリティ...）で、気分が落ち込みます

嫌いな技術を以下に示す。

（１）ガベージコレクション
実装の容易性から、開発言語としてJavaが選ばれたりするが、大規模システムになると意図しないタイミングでガベージコレクションが発生する。まあ、回避できるのでそんなに大きな問題ではない。

（２）Microsoft Teamsのお行儀の悪さ
信じられないくらいメモリを食う。プロセス数も異常。普通なら、ポートをポーリングするようにコーデイングしないといけないのに、開発者はわかってないのかなぁ。増改築を繰り返したような地方の温泉旅館のような構造になっていると思われる。幹部から言われるがままに、仕様を追加させられた感が半端ない。あと、**「Enterで送信するという仕様」もどうかと思います。**

（３）アクセシビリティ
Officeで、エクセルやワードを使っていますが、アクセシビリティについて指摘されたりします。自分用のメモとして使っているので、わざとピンク色や赤色をつかっているのですが、なんか怒られているような感じがして**若干気分が落ち込みます。**
比較演算子【bash】【zsh】

## 文字列の比較
| 比較演算子 | 説明 |
| :-:|:- |
| String1 = String2  | String1とString2が等しければ真  |
| String1 != String2  | String1とString2が等しくなければ真  |
| -n String  | Stringの長さが1以上であれば真  |
| -z String  | Stringの長さが0であれば真  |

## 数値の比較

| 比較演算子 | 説明 |
|:-:|:-|
| Number1 -eq Number2  | Number1とNumber2が等しければ真  |
| Number1 -ne Number2  | Number1とNumber2が等しくなければ真  |
| Number1 -gt Number2  | Number1がNumber2よりも大きければ真  |
| Number1 -ge Number2  | Number1がNumber2以上であれば真  |
| Number1 -lt Number2  | Number1がNumber2よりも小さければ真  |
| Number1 -le Number2  | Number1がNumber2以下であれば真  |

## その他
| 比較演算子 | 説明 |
|:-:|:-:|
| -d file  | 対象ファイルがディレクトリなら真  |
| -f file  | 対象ファイルがファイルなら真  |
| -s file  | 対象ファイルのサイズが0でなければ真  |
| file1 -ot file2  | file1がfile2よりも古ければ真  |
| file1 -nt file2  | file1とfile2が等しければ真  |
技適を通ってないWi-Fi、BLEボードを使う（実施例）

# はじめに
総務省より技適を通っていない機器でも、ハードウエアを破壊することなく、ダミーロードを接続せず、ソフトウエア的に電波を発しないようにすれば、合法である旨の見解を得ました。[詳細はこちら](https://qiita.com/maclineto/items/8939e703f844e95b820e)
今までの見解は、電波がでなくても電波を出せる機器に電源を入れれば無線局の開設に当たり違法という物でした。
では具体的にどうすれば、合法なのでしょう。NanoPi Neo4で具体例をあげます。

# 手順（１）
ダミーロードを使う方法です。「なーんだ」とがっかりしないでください。セットアップが済めばダミーロードはいりません。
## 起動
ダミーロードを繋ぎ、Linuxを起動します。
## aptの設定でkernelの自動upgradeを禁止します
アップデート対象からカーネルを除外するには /etc/apt/apt.conf.d/50unattended-upgrades へ以下を追加します。
```/etc/apt/apt.conf.d/50unattended-upgrades:
Unattended-Upgrade::Package-Blacklist {
      "linux-headers*";
      "linux-image*";
      "linux-generic*";
      "linux-modules*";
};
```
## Driverを削除します
```sh:
cd /lib/modules/{uname -r}/kernel/net/
rm -rf wi
```
## 念のためLoad禁止にしておきます
```/etc/modprobe.d/blacklist.conf
blacklist lib820211
```

これで総務省の提示要件
- 電源を入れても電波が出ない
- 初期化しても電波は出ない
- デバイスドライバーは入っていない

を満たします。
# 手順 (2)
技適マシンでカーネルイメージを展開します（なーんだ技適かあ）作業用だけです。
## aptを設定しkernel upgradeをとめます。
## Driverを削除します。
## modprobeをセットして、loadを禁止します。
## 作業マシンのディスクをターゲットにクローニングします。

# 番外編
FreeBSDはWi-Fi未サポートの場合が多く、これらOSを技適未認可SBCに乗せても当然合法になります。
[例えばRasPI4は既に技適を通ってますが電波は一切出ません](https://l.facebook.com/l.php?u=https%3A%2F%2Fgadget.ichmy.0t0.jp%2Fintro%2Fraspi%2Ffreebsd%2F%3Ffbclid%3DIwAR3ExAOvuw-ptY-6EDy3QIpHCJjlai2ewcZpS2zjjs4rCWhXi1f0A4NZIU8&h=AT21an6tuOkmqUNWCKt_R0ehi9jaygL4a4lSDZeG0syXmJ0Fu2KXfTfFpYtjCeeP2MKEr_ksmkJ-fEENijRY0YpXDhuHty9IqmdwEytmJ0poOMKLF4A5l0h7NktqbPwRvLgv_1BiExZZXELLFSZT&__tn__=R]-R&c[0]=AT1jevmOkh7aynupySB0Bf86l9o39MqYAmTAaJX_E5hjEQSa3cHzyzzroC2Uugc6G7RNOEEM3vSHYUJ4JuuTsEnpzBoGfZbZTcbvM5bPuieZnU8MGRyQxF7c3E84wGM-2J4vid3P26M7hP5-iQbwLzaFD6K_iI5DcuU)
Rails6.1で追加されたmissingがとてもエレガント

# 結論
ActiveRecordのmissingという関数を使えばこんなにエレガントになります。

```ruby
# missingなし
Master.left_joins(:datas).where(datas: {id: nil})

# missingあり
Master.where.missing(:datas)
```

# どういうこと？
missingは関連が無いデータを取得するときに使います。例えば
- 利用されていないマスターデータの一覧を取得する(上例)
- 所属する社員がいない部署の一覧を取得する（ex: `部署.where.missing(:社員)`）
- 画像が無い記事の一覧を取得する（ex: `記事.where.missing(:画像)`）

# どうやって利用するの？
has_one/has_many/belogs_toなどのアソシエーションが組んであれば利用できます。



なにはともあれ、missingって響きがカッコいいので多用したい。

# 参考
https://techracho.bpsinc.jp/hachi8833/2021_05_26/107973
【Vue.js】開発環境「Vue CLI」を導入する【mac】

# はじめに
Vue.jsを学習している過程でVue CLIを導入します。(2022年7月21日時点)


# Vue CLIとは
Vue.jsをコマンドライン(ターミナルとかコンソールとかいうやつ)を使って開発を行うためのツールです。
CLIはCommand Line Interfaceの略です。
Vue.jsアプリケーションの開発支援ツールで、効率よく開発を進めるために欠かせません。
「びゅー しーえるあい」と読みます。

開発環境では、それぞれのコンポーネントを拡張子「.vue」のファイルで管理・開発し、Vue CLI上のローカルサーバで実行可能です。
開発が完了したモジュールは、Vue CLIの機能で運用可能な形式(html、css、JavaScriptなど)に変換し、運用環境サーバ等にアップロードします。

# Vue CLIの導入
## 今回Vue CLIを導入する環境
- OS: macOS Big Sur 11.5.2

## 導入までの大まかな流れ
1. 旧バージョンのVue CLIをアンインストール
2. Node.jsをインストール
3. Vue CLIをインストール

### 旧バージョンのVue CLIをアンインストール
もし旧バージョンのVue CLIがインストールされていて、特に理由がないのであれば事前にアンインストールします。
旧バージョンがインストールされているのであればnpmもインストールされているはずなので、下記コマンドで削除します。

```:旧バージョンVue CLIをアンインストール
npm uninstall -g vue-cli
```

### Node.jsをインストール

Node.jsの公式からダウンロードしてインストールします。
既に「Node.js」がインストール済みであればスキップしてください。

https://nodejs.org/ja/download/

Homebrew等が導入済みであればコマンドラインからのインストールでも良いです。

「Node.js」をインストールすると「npm」というパッケージ管理システムも一緒にインストールされ、npmコマンドが使用可能になります。
「npm」が正常にインストールされたか確認するためにコマンドラインで下記のコマンドを実行します。

```:npmのバージョン確認
npm --version
```

正常にインストールされていれば「8.11.0」のように「npm」のバージョンが表示されます。
続けて「Node.js」のインストールも確認するために、下記のコマンドも実行します。

```:Node.jsのバージョン確認
node --version
```

こちらも正常にインストールされていれば「v16.16.0」のようにバージョンが表示されます。

### Vue CLIをインストール

コマンドラインから下記のnpmコマンドを実行して「Vue CLI」をインストールします。

```:Vue CLIをインストール
npm install -g @vue/cli
```

正常にインストールされたかを確認するために下記のコマンドを実行します。

```:Vue CLIのバージョン確認
vue --version
```

正常にインストールされていれば「@vue/cli 5.0.8」のように「Vue CLI」のバージョン表示されます。

# Vue CLIの起動

```:Vue CLIの起動
vue ui
```

「Vue CLI 3」以降にはGUIのプロジェクト管理ツールがあり、ツール画面からプロジェクト作成やソースコードのビルドが行えます。

続く(かも)
ミノ駆動本を読んで不変の大事さを知る

## はじめに
本記事は[ミノ駆動本を読んでクソゲーを神ゲーにリファクタしてみた](https://qiita.com/KeiFunahashi/items/fdfedf140c69c1d9a77f)の続編[^1]です。
今回はミノ駆動本第4章の不変の活用に着目していきたいと思います。
可変になっている悪いコードがどれほど悪影響をおよぼすのかをちょいネタにしてみました。
また、書籍の内容をヒントにして、不変を活用した良いコードでどれだけ改善できるかを検証していきます。

## 参考資料
[良いコード／悪いコードで学ぶ設計入門保守しやすい　成長し続けるコードの書き方](https://www.amazon.co.jp/dp/B09Y1MWK9N/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)

## 内容
今回作成したゲームの実際のコードになります。
https://github.com/kdr250/good-code-bad-code-sample

## 仕様変更で武器の攻撃力を変えたい！

PM 「◯◯君、マップ上の武器ごとに攻撃力を変えたいんだけど、実装お願いできるかい？」[^2]

◯◯ 「了解しました！修正しておきます！」
◯◯ 「攻撃力の変更だから攻撃力のインスタンスの値を書き換えれば良さそうだな...（カタカタカタカタ・・・ッターン！）」

<img width="600" alt="result1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710108/10944478-ee4b-c49d-01d6-00d2f97948dc.png">

◯◯ 「ん？全部同じ攻撃力になってる... **なぜだ**...」

## 問題点
書籍でも述べられている通り、問題は可変インスタンスを使い回していることにあります。


```java:悪いコード例1
public class AttackPower {
  static final int MIN = 0;
  int value; // finalが付いていないので可変

  // 中略
}
```
```java:悪いコード例2
AttackPower attackPower = new AttackPower(3); // 生成した攻撃力を...

Weapon weaponA = new Weapon(attackPower);
Weapon weaponB = new Weapon(attackPower); // 他の武器でも使い回しているため...

weaponA.attackPower.value = 4; // weaponAの攻撃力を変えたつもりが他の武器の攻撃力も一緒に変更されてしまう
```

もう少し整理すると、以下のように分解されると考えます。
- 攻撃力クラスの値が**可変であり、後から変更できてしまうこと**
- 攻撃力のインスタンスを複数の武器で**使い回されていること**

## 改善策
上記の問題点を踏まえ、改善策は以下になると考えました。
- 攻撃力クラスの値を**不変**にすること
- 攻撃力インスタンスを複数の武器で使い回さずに、**個別に生成すること**

```java:良いコードを参考にした例1
public class AttackPower {
  private static final int MIN = 0;
  private final int value; // finalで不変にする

  // 中略
}
```
```java:良いコードを参考にした例2
AttackPower attackPower = AttackPower.random(); // 攻撃力のインスタンスを個別に生成する
return new Weapon(attackPower);
```

## 期待した効果が得られたか
不変にすることで予期せぬ値の書き換えを防止できるというのが最大のメリットだと感じました。
今回のバグを解消するのはもちろん、そもそもバグになりにくい構造になったのかなと思います。

実際にゲームを一本作ってみて、(ネタ関係なしに)うっかり可変のまま放置していた箇所が後々バグの原因になる、ということが度々発生しました。しかし、不変を活用することでバグがそもそも発生しにくくなったりするので非常に効果は大きいと感じました。ゲームに限らず、他のプロダクトにおいても不変を活用すれば品質の向上につながるのではないかと思います。

## その後...
<img width="600" alt="result2.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710108/3b82169e-1068-10b7-9836-3972464235c1.gif">

◯◯ 「PMさん、できました！ついでにいい感じにコードをリファクタしておきました！」

PM 「お！ありがとう！」

## おわりに
今回は
- 4章 不変の活用 - 安定動作を構築する -

に着目してリファクタリングに生かしてみました。
ミノ駆動本はこうした設計テクニックが満載なので、是非読んでみることをおすすめします！

[^1]: 今までは記事執筆係とゲーム制作係で分担してました。今回はゲーム制作係も執筆してみようという試みです。
[^2]: 書籍の想定仕様とは異なります。ゲーム上で再現するのが追いつかなかったので...
IndexWriterオブジェクト（二）

このシーリズの文章は、IndexWriterを構造する流れを紹介します。主に３つの部分があります：
● インデックスでぃれくろのDirectoryをセットする
● IndexWriterのIndexWriterConfigをセットする
● IndexWriterコンストラクタを呼ぶ
前の文章では、もう不可変更コンフィグを紹介した上、続いて変更可能コンフィグを紹介する。
# IndexWriterのIndexWriterConfig
## 変更可能コンフィグ
  変更可能配置には：MergePolicy、MaxBufferedDocs、RAMBufferSizeMB、MergedSegmentWarmer、UseCompoundFile、CommitOnClose、CheckPendingFlushUpdateがある。
## MergePolicy
MergePolicyはsegmentの合併策略であり。インデックス目録から合併条件にふさわしいsegment集合（segment set）を探す処理方法である。２つの策略がある：LogMergePolicyとTieredMergePolicy。MergePolicyはIndexWriterConfig.setMergePolicy(MergePolicy mergePolicy)を通じて設定することができる。Lucene7.5.0にはデフォルト策略はTieredMergePolicyである。MergePolicyは変更されたと、次の合併の時に効くことになる。

## MaxBufferedDocs、RAMBufferSizeMB
RAMBufferSizeMBはインデックスを説明するインフォメーションがCacheに保存する最大の使用空間である。ただし、MaxBufferedDocsは一つのDWPTの最大のファイル数である。
ファイルのCUD操作を行った後、FlushPolicyによって自動的なflushを判断する。Lucene7.5.0では、FlushByRamOrCountsPolicyという策略はMaxBufferedDocsとRAMBufferSizeMBによって判断する。
MaxBufferedDocsはIndexWriterConfig.setMaxBufferedDocs(int maxBufferedDocs)を通じて設定することができる。デフォルトバリューは-1であり、このMaxBufferedDocsを使わない意味をしている。
RAMBufferSizeMBはIndexWriterConfig.setRAMBufferSizeMB(double ramBufferSizeMB)を通じて設定することができる。デフォルトバリューは16Mである。

## MergedSegmentWarmer
MergedSegmentWarmerはsegment合併の時、事前に新たなsegmentの情報を獲得しする。segment合併とファイルのCRUDは並列処理なので、パフォーマンスを向上することができる。
MergedSegmentWarmerはIndexWriterConfig.setMergedSegmentWarmer(IndexReaderWarmer mergeSegmentWarmer)を通じて設定することができる。デフォルトバリューはnullである。

## UseCompoundFile
UseCompoundFileはブーリアンである。バリューはtrueだと、flushやcommitの操作で生成したファイルはCompoundFileで、すなわち.cfs、.cfeである。
UseCompoundFileはIndexWriterConfig.setUseCompoundFile(boolean useCompoundFile)を通じて設定することができる。デフォルトバリューはtrueである。

## CommitOnClose
CommitOnCloseはブーリアンである。バリューはtrueだと、まずは全部の変更を応用し、即ちcommit操作を実行する。falseだと、ラストcommitした内容を保存しない。
CommitOnCloseはIndexWriterConfig.setCommitOnClose(boolean commitOnClose)を通じて設定することができる。デフォルトバリューはtrueである。

## CheckPendingFlushUpdate
CheckPendingFlushUpdateはブーリアンである。バリューはtrueだと、スレッドはファイルのアッドやアップデートを実行した後、DWPTをflushすることになる。
NumPyのインポートエラーでつまづいた

#### 概要
最近Pythonを学び始めた初心者です。
学習を進めるにあたってnumpyというライブラリを利用しようとした際に躓いたので、解決に至ったまでを書き残そうと思います。同じような状況の方は試してみてもらえればと思います。

#### 環境
Windows 11
vscode: 1.69.2
Python: 3.9.12
Anaconda:4.12.0


#### 1.インストールされているか確認した
VSCodeを使って NumPyを使うには、Python Extension Packをインストールする必要があるとのこと。Extension MarketPlaseから入手可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1744893/8076527b-30a4-118d-51b5-cb832e111968.png)

#### 2.環境変数の確認
VScodeを開き、ファイル→ユーザー設定→設定に行き、Python.PythonPathと入力すると、、、あれ、何も出てこないぞ。ここまででもう予測が消えちゃうし。。。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1744893/185d4bf5-9173-46bb-5f73-28fa228aa5da.png)

実は古い記事を参考にしていたようで最近は、python.defaultInterpreterPathと入力するそうです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1744893/8064b08a-67db-708a-aa26-3cc0d766b73b.png)

もともと私の場合は、パスが"C:\Users\matsu\anaconda3\python.exe"だったのですが、
"C:\Users\matsu\anaconda3\Scripts"に変更しました。

実行してみると、エラーが変わり
DLL load failed while importing _multiarray_umath: 指定されたモジュールが見つかりません。
とエラー内容が変わりました。

さらに調べてみると、C:\Users\xxxxx\Anaconda3\Library\binを追加する必要があるみたいでした。

今度は、Windowsの環境変数設定からやってみます。
コントロールパネル→システムとセキュリティ→システム→システムの詳細設定→環境変数とポチポチ進みます。下記画像のPATHと書かれている部分をアクティブにして、編集をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1744893/f3e8a8fe-9595-d97c-8923-f0bb8330f353.png)
上から３つがPython関係のパスだと思います。
新規を押し、先ほどのC:\Users\xxxxx\Anaconda3\Library\binを追加し、（xxxxxは変更してください）OKを押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1744893/9eaa30b4-984a-19a8-7d87-814e68d0b525.png)



#### いざ！

```test.py
import numpy as np


class Statistics:
    
    def std(self):
        
        print(np.std([100,130,200]))
        
c001 = Statistics()

c001.std()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1744893/6c5ae600-d313-3625-6e74-0dfcd2680f6c.png)
無事に出力されました！
ちなみにこれは標準偏差の算出を行っています。
１時間ぐらいやられましたがなんとか越せてよかったです。

#### 参考にさせていただいた記事
いろいろ巡り巡ってあれこれ試しましたがこの記事のおかげで無事に実装できました。感謝です。

https://note.com/lydiacorp/n/n7e8893678ceb
[python] 仮想環境

# 執筆者の開発環境について
- OS : Windows11
- テキストエディタ : VSCode<br>
を前提として記事を執筆しております。
MacやLinux系の方はご容赦ください。

# はじめに
pythonでツールなどを開発する際に、用途によって必要なライブラリを含んだ実行環境を作成し、その環境下で開発を行うのがスタンダードとされています。
仮想環境を活用することで、PC上にあたかも別マシンで動くようなpython環境を構築できます。
つまり、独立して動くため同じシステム内の環境を汚したり競合なく開発が行えたり、作成したツール配布の際に実行環境を揃えられるため、ライブラリの差異で動かないといったことが解消できるといったメリットがあります。

運用としてbaseのライブラリ(デフォルト環境)は汚さずに、仮想環境ごとに必要なライブラリを揃えるといった感じが良さそうですね。

# 仮想環境の種類
次の3種類の仮想環境がよく使われている様子

|名称|特徴|
|---|---|
|venv|・標準仕様なので安心感あり(Python Ver3.4以降)<br>・すぐ使える|
|conda|・Anacondaパッケージに標準搭載|
|virtualenv|・サードパーティ製なのでpip installが事前に必要<br>・venvより構築が少し楽|

# venvでの環境構築から有効まで
WindowsOSにてvenvではコマンドプロンプトとpowershellで、環境を構築できるようです。ただ、構築する際のバッチファイルが各々別のものを使っているらしいので注意が必要。本記事ではコマンドプロンプトでの構築を前提にしています。

[参考サイト : 実務で必須の「Python仮想環境」について学ぼう！](https://www.insource.co.jp/python-gakuin/mail-backnumber/vol30.html)

(1) **仮想環境を構築したいフォルダまで移動**
例えば、「my_project」というフォルダで構築したい場合は
```
cd yyy\zzz\my_projrct
```
といった感じで、直下まで辿り着けます

(2) **仮想環境の作成**
直下まで移動したら、以下のコマンドを打って仮想環境を作成します
```
python -m venv xxx
```
※xxxは任意の環境名称


(3) **仮想環境の有効化**
ここまでで、my_project下に仮想環境が存在するが、まだアクティブな状態ではないです
xxx下のScriptsディレクトリに `activate.bat` というバッチを叩けば仮想環境を立ち上げるようです
```
.\xxx\Scripts\activate.bat
```
これで仮想環境の有効化は完了。
成功するとコマンドプロンプト上で、ディレクトリの前に(xxx)といった感じで、現環境が表示される。

:::note info
Power shellの場合では`activate.bat` ではなく `Activate.ps1` の方をたたく必要があります。
:::

# パッケージのインストール
仮想環境を立ち上げたら環境下で必要なパッケージをインストールする。

基本的なパッケージのインストールは、pipというpython標準搭載の管理システムを用いて行います。

#### よく使いそうなpipコマンド一覧
|目的|コマンド|
|---|---|
|パッケージ(xxx)インストール|pip install xxx|
|パッケージ(xxx)をアンインストール|pip uninstall xxx|
|アップグレード|pip install -upgrade xxx|
|バージョンを指定してパッケージ(xxx)インストール|pip install xxx==Ver|
|インストールされたパッケージ一覧表示|pip list|
|インストールされたパッケージ一覧表示|pip freeze|

例) numpyをインストールしたい場合
環境下で以下を入力
```
pip install numpy
```

[参考サイト : 【Python】pipとは何か？コマンド一覧と使い方を実例でわかりやすく解説｜pipとpip3の違い（初心者向け）](https://prograshi.com/language/python/python-pip/)

# 仮想環境の無効化、削除
ライブラリを仮想環境下にて試しで使ってみて、ダメだった場合その環境が不要となる場合があると思われる。そのため、仮想環境の無効化、削除についても書いておこうと思います。

(1) **仮想環境の無効化**
前提として、仮想環境が有効であった場合、同じくScriptsディレクトリ内の `deactivate.bat` で環境を抜けることが出来ます。
```
deactive.bat
```
または
```
.\xxx\Scripts\deactive.bat
```
抜けた後はbase環境(デフォルト)に戻る

(2) **削除**
これはシンプルで、作成した仮想環境のフォルダを削除すればよいです。
```
rmdir \s xxx
```
こんな感じでコマンドを打つか、ゴミ箱に入れてしまうかすればよいです。

# インストール済みパッケージの出力
前述した`pip list`や`pip freeze`でパッケージの出力が可能である。
このうち`pip freeze`は仮想環境をコピーする際など、まとめてパッケージをインストールするための`requirements.txt`を出力するのに便利です。

:::note info
ちなみに`pip list`と`pip freeze`の違いはパッケージのVer記載の有無です。
`pip freeze`にVer情報あり
:::

下記コマンドのように出力をリダイレクションで`requirements.txt`に向ければ、下簡単に作成できます。

```
pip freeze > requirements.txt
```

同様の環境を構築したいときは、この`requirements.txt`を使って以下のコマンドで、一括インストールできます。
```
pip install -r requirements.txt
```
他の人にpythonツールを渡すときなどに、`requirements.txt`を一緒に渡してやれば、環境を揃えることが出来ます。

[参考サイト : Python, pip list / freezeでインストール済みパッケージ一覧を確認](https://note.nkmk.me/python-pip-list-freeze/)

# さいごに
参考にさせていただいたサイト様には感謝いたします。
今回はvenvでの仮想環境立ち上げ等をまとめました。やる気があったら他の環境もまとめたいと思います。~~多分やらない~~
未経験エンジニアが感じたサーバレスってなに？

<h3>この記事を書こうと思った理由</h3>

最近、AWSの勉強をしていてオンプレとクラウドの違いをなんとなく理解してきたところでサーバレスという言葉に疑問を感じたためこの記事を書こうと思いました。

<h3>私の中での言語の理解</h3>

・オンプレ（オンプレミス）
自社でサーバーを買いデータセンターに設置してそこにアプリやらインフラの設定などを行いサービスを提供する仕組み
メリット
自分で買うから、設定などの自由度がかなり高い
デメリット
初期費用がとても金がかかる
自分でサービスを考えて提供するまでに時間がかかる
急な高負荷などに対応できない

・クラウド
他社（Amazon,Google,Microsoft)が提供しているサーバー上にアプリやらインフラの設定などを行いサービスを提供する仕組み
メリット
うまく設定すれば、オンプレよりも安く済ませることができる
初期費用がかからない
急な高負荷などに対応できる
デメリット
カスタマイズに制限がある
現状使いこなせる人材が少ない

・サーバレス
？？？
サーバーがいらない？
AWS勉強して出てきたけど、AWSはクラウドで一応サーバーを貸し出しているのでは？
よくわからんな

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2486920/42f50900-05b2-1aea-9bee-727868ada65a.png)

<h3>自分で調べてみた結果</h3>

・サーバーレス
サーバーレスとは、サーバーの構築や保守はサーバーレスの提供会社が全てやってくれる上に、負荷対策まで面倒を見てくれているもの。そのため、利用者はサーバーの管理が一切不要（サーバー管理レス）になる。
例
AWS Lamdba
サーバーレスは、サーバーがない（レス）ではない。
サーバー自体は実際に存在していてサーバーの管理が一切不要だからという意味でサーバーレス（サーバーの管理がいらない）になっているようです。

紛らわしいが、理解はできました。

https://blog.qbist.co.jp/?p=2654

https://aws.amazon.com/jp/builders-flash/202003/awsgeek-serverless/?awsf.filter-name=*all

https://www.stylez.co.jp/columns/what_is_a_serverless/

<h3>新たな疑問</h3>

なるほど、管理が不要だからサーバーレスというのか理解はできたぞ。
あれ？管理が不要っていったらAWS勉強していてなんか出てきたな。
あ、フルマネージドだ。
じゃあ、フルマネージドとサーバーレスって何が違うんだ？

<h3>サーバーレスとフルマネージドの違い</h3>

https://cloud.google.com/blog/ja/topics/developers-practitioners/serverless-vs-fully-managed-whats-difference

んー、わかりにくいな
私的には次のように捉えました

・サーバーレス
マシンが見えない
→裏がどうなっているかわからないけどロジックができていれば動けばいい

・フルマネージド
マシンが見えて、制御することができる
→裏も理解したいより詳細な設定を行なって、さらなる高い価値を提供したい（コストを下げたり、障害を減らす）

使いやすさ
サーバーレス＞フルマネージド
みたいな感じなのかな？
使いやすさ以外の観点があるのだろうけど今の経験だと思い浮かびませんでした。
PAC思考で仮説の落とし穴を見つけろ！

## はじめに
「理由は？」
「もうちょっと考えて発言して欲しい。」
などと、上司からお小言を言われてうんざりしているあなた！

もしかしたら、PAC思考を使えば、解決できるかもしれません。
この記事では、主張の妥当性をアップさせるフレームワークであるPAC思考について解説します。

## 対象者
この記事は下記のような人を対象にしています。

- 駆け出しエンジニア
- プログラミング初学者
- 「自分はロジカルじゃないから...」と諦めてる人

## 結論
とにかく疑え！PAC思考を使えば主張の妥当性がぐんとアップします。

## PAC思考とは
PAC思考とはPremise(前提・事実)、Assumption(仮定)、Conclusion(結論・主張)の3つに分解してそれぞれの妥当性をチェックし、思考の精度を上げるビジネスフレームワークです。
自分が考えたロジックが妥当か、検証する際に活躍します。

それぞれの項目について、下記の具体例を用いて、詳しく解説します。

:::note
在庫管理システムに在庫量のフォームを追加しようとしている。
クライアントからは「とにかく早く作って欲しい」と言われている。
在庫量は数字入れるのが当たり前だし、ささっと実装したいので、バリデーションかけなくていっか！
ということで、スピード重視で実装を進めた。
:::

## Premise(前提・事実)
まずは主張の前提となっている事実について、整理します。

事実・前提となっているのは下記の通りです。

:::note
在庫管理システムに在庫量のフォームを追加しようとしている。
クライアントからは「とにかく早く作って欲しい」と言われている。
:::

この事実・前提に対して「本当にそうなのか？」「なんでそうなるのか？」を深く考えます。
今回の例だと、「早く作って」と言われたけど、具体的にはいつまでなのでしょうか？今日中なのでか、今週中なのか、今月中なのか、によって取るべき行動は変わってくるでしょう。

## Assumption(仮定)
前提・事実から、自分が考えたロジックが仮説です。

下記の2点が仮説です。

:::note
在庫量は数字入れるのが当たり前。
バリデーション無しのほうが実装が早い。
:::

この事実・仮説に対して「本当にそうなのか？」「なんでそうなるのか？」を深く考えます。
今回の例だと、「本当に半角数字だけか？全角数字や、カンマ、漢数字などが入力される可能性はないか？」などを検証します。

## Conclusion(結論・主張)
事実・前提・仮定から導き出した結論・主張についても検証しましょう。

下記が結論、主張です。

:::note
バリデーションかけなくていっか！
ということで、スピード重視で実装を進めた。
:::

この結論についても妥当かどうか、検証しましょう。
「本当にバリデーションなしで大丈夫？」「そんなに急ぐ必要ある？」など、きちんと解凍できるか、シミュレーションしてみましょう。

## PAC思考を使うと、主張の妥当性が格段にアップ

PAC思考を使わないと、パッと見はロジカルな主張のように見えますが、下記のように失敗してしまいます。

:::note alert
在庫管理システムに在庫量のフォームを追加しようとしている。
クライアントからは「とにかく早く作って欲しい」と言われている。
在庫量は数字入れるのが当たり前だし、ささっと実装したいので、バリデーションかけなくていっか！
ということで、スピード重視で実装を進めた。
↓
<font color="Red">結果、数値以外の入力があり、エラーが発生...とほほ</font>
:::

今回勉強したPAC思考を使えば、根拠の妥当性を考えられるので、きちんとした行動方針が立てられ、成功する確率がぐんと上がります。

:::note
在庫管理システムに在庫量のフォームを追加しようとしている。
クライアントからは「とにかく早く作って欲しい」と言われている。
↓
PAC思考で検証
↓
確認したところ、今週中に納品すればOK。
数値以外の入力もあり得る。
↓
<font color="Blue">バリデーションを実装し、今週中に納品。
クライアントの要望にも合わせ、品質の高い機能を実装できた。</font>
:::

## おわりに
主張の妥当性を上げるPAC思考についてまとめました。
[Python] The Multithread in Python, GIL

# Introduction

In Python, if you run some calculation with multithread you will find that it takes almost the same time, no matter how many thread you use. For example for the code bellow, it just do a plus operation in a for loop, with 1 thread or 4 thread, in my 4 core cpu laptop, all took almost 4 seconds. 

```py
import threading
import time
from datetime import datetime

def run(n):
  tot = 0
  for i in range(0, n):
    tot += 1

start = datetime.now()

a = 100000000
n = 10

th = []
for i in range(0,n):
  t = threading.Thread(target=run, args=(a//n,))
  t.start()
  th.append(t)
  print(f"Thead {i} started.")

for t in th:
  t.join()

end = datetime.now()

print(f"Time: {end - start}")
```

# GIL (Global Interpreter Lock)

What is GIL? GIL is not a feature of python, it is a concept when python implement the python interpreter (CPython). It's a lock to prevent multithread run at the same time. So the multithread actually run in **concurrent**, not **parallel**.

> In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.)

# Why GIL exist?

Python use reference counting for memory management. So when a object's reference count decreased to zero, the memory occupied by this object is released. Multiple thread in the same process will share same memory space, so the problem was that this reference count variable will have race conditions when two threads increase or decrease its value simultneously and hence it may cause memory leak.

# How to Avoid GIL

1. If your program is I/O bound, multithrad and multiprocess have no much different as I/O operation will let current thread has a chance to release GIL, and other non I/O thread continue to process. 

2. If your program is CPU bound, then use multi process will be a better choice.
Pythonのsubprocessでコマンド標準出力を取得しつつコンソールにも表示したい

## はじめに

Pythonのsubprocessでコマンド実行時

- その標準出力を文字列として取得したい
- 同時に、コンソールにもリアルタイム表示したい

といった場合の実装例です。

## 仕様

- MyConsoleクラス
    - パイプを作成し、読込み用と書込み用のファイルディスクリプタをクラスメンバーに指定
    - スレッドを作成し、下記処理を行う
        - パイプにデータ存在するまで読込む(4KB単位)
        - 取得データをシステム標準出力に書き込む
        - 同時に、データを結果文字列にも追加
- subprocess.run()でコマンド実行
    - stdoutパラメータにMyConsole書込み用ファイルディスクリプタを指定

## コード

Windowsのサンプルコードです。

```test_console.py
import threading
import os
import sys
import subprocess

class MyConsole:
    def __init__(self):
        self.result_str = ""
        self.rfd, self.wfd = os.pipe()
        thread = threading.Thread(target=self._read)
        thread.daemon = True
        thread.start()

    def _read(self):
        while True:
            data = os.read(self.rfd, 4096)
            if data is None:
                break
            data_str = data.decode()
            sys.stdout.write(data_str)
            self.result_str += data_str
        os.close(self.rfd)
        os.close(self.wfd)
    
    def get(self):
        return self.result_str

if __name__ == "__main__":
  con = MyConsole()
  print("==== ここから標準出力のコンソール表示")
  subprocess.run(["ping", "127.0.0.1", "-n", "3"], shell=True, stdout=con.wfd)
  print("==== ここまで標準出力のコンソール表示\n")
  print("==== ここから標準出力から取得した結果文字列")
  print(con.get())
  print("==== ここまで標準出力から取得した結果文字列")
```

## 実行結果

```shell
> python .\test_console.py
==== ここから標準出力のコンソール表示

Pinging 127.0.0.1 with 32 bytes of data:
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128

Ping statistics for 127.0.0.1:
    Packets: Sent = 3, Received = 3, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum = 0ms, Average = 0ms
==== ここまで標準出力のコンソール表示

==== ここから標準出力から取得した結果文字列

Pinging 127.0.0.1 with 32 bytes of data:
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128

Ping statistics for 127.0.0.1:
    Packets: Sent = 3, Received = 3, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum = 0ms, Average = 0ms

==== ここまで標準出力から取得した結果文字列
```

同じ内容が、コンソールに表示されつつ、
結果文字列にも、保存されます。

## Linuxの場合

サンプルコードで、下記1行を書き換えてください。

- 修正前
```
  subprocess.run(["ping", "127.0.0.1", "-n", "3"], shell=True, stdout=con.wfd)
```
- 修正後
```
  subprocess.run(["ping", "127.0.0.1", "-c", "3"], stdout=con.wfd)
```

## おわりに

Pythonのsubprocessで標準出力を制御してみました。
subprocess使用時に、ご参考になれば何よりです。
Overleaf で "~ must be inside math mode" ってエラーの直し方（超絶初歩）


超初心者だけど Qiita で初記事書いてみるよ。

Overleaf っていうか TeX に初めて触れたんだけど documentclass を指定しただけで早速エラー。
![がぞー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2741181/1886272a-a1af-76b7-4d01-f7489a4c55d4.png)
ググっても直し方わかんねえー何だよ math mode って、と思ったら、誰かのテンプレをコピペさせてもらったコマンドだから、半角アンダーバーが混じってた。それは math mode じゃないと使えない文字ですよってエラーだったみたい？
アンダーバーをただの半角スペースに置き換えたらエラー消えた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2741181/f2038529-f45f-fcc7-f852-05fa12b0ca93.png)
それだけ。初心者すぎてこんなのもわからんかった。
APG4bで自分が書いたコード5　EX21-23

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

```
 -->


[W - 2.06.計算量](https://atcoder.jp/contests/apg4b/tasks/APG4b_w)
ソースコードがネタバレになるので割愛

制約とfor文のネストの数を見ればヒントを読まなくてもわかると思います



[EX22 - 2つ目の値でソート](https://atcoder.jp/contests/apg4b/tasks/APG4b_ca)
コメントはソートされてないpair配列vecが表示されるかの確認です
問題範囲の10^9は「int 範囲」でgoogle検索してでてきた[マイクロソフトの記事](https://docs.microsoft.com/ja-jp/cpp/cpp/data-type-ranges?view=msvc-170)を見るに十分そうだったのでintにしました

一番手間取ったのはpairをどう配列にするかでよくわからないからusingで新しい型をつくりました。

２番目はvec.first.at(i)ではなくvec.at(i).firstの順番だったことです。

特に当たってヒントは見ましたがテスト入出力と解答例は見ませんでした。
```c++:EX.cpp
#include <bits/stdc++.h>
using namespace std;
 
int main() {
  using pii = pair<int, int>;
int n=0;
  cin>>n;
    vector<pii>vec(n);
for(int i=0;i<n;i++)
{
  cin>>vec.at(i).second>>vec.at(i).first;
 // cout<<vec.at(i).second<<" "<<vec.at(i).first<<endl;
 
}
sort(vec.begin(), vec.end());  
  
  for(int i=0;i<n;i++)
{

  cout<<vec.at(i).second<<" "<<vec.at(i).first<<endl;
 
}
  
}
```
[EX23 - 最頻値](https://atcoder.jp/contests/apg4b/tasks/APG4b_bz)
		if (raw_data[0] <= raw_data[input_a]) の=が重要
[APG4b EX23を解いた](https://note.com/nanigashi/n/n7b4b7262514d)を参考にしました
こっちのほうが奇麗なコードだと思います
mapのkeyに値を代入、valueに出現回数を加算して出現回数順にソートし、mapの末尾に最頻値とその出現回数が出るのでmapの末尾のkeyとvalueをどうやって取り出せばいいのかとか考えていました。
実際にはそんな必要はなかったです

```c++:EX23.cpp
int main() {
	int input_n = 0;
	int input_a = 0;
	cin >> input_n;
	map<int, int> raw_data;
	raw_data[0] = 0;
	int Number_of_appearances = 0;
	for (int i = 0; i < input_n; i++)
	{
		cin >> input_a;
		raw_data[input_a]++;
		if (raw_data[0] <= raw_data[input_a])
		{
			raw_data[0] = raw_data[input_a];
			Number_of_appearances = input_a;
		}
	}
	cout << Number_of_appearances << " " << raw_data.at(0) << endl;
}
```
前回まではストックがあったので5問ずつ更新しています。が、今回からはストックがないので一記事5問までの縛りは変えないまま、問題を解いたら記事を更新していきます。
[APG4bで自分が書いたコード1 EX1~EX5](https://qiita.com/sy1/items/97e15040d529a367452e)
[APG4bで自分が書いたコード2　EX6~10](https://qiita.com/sy1/items/58f0566a46018483090d)
[APG4bで自分が書いたコード３EX11~15](https://qiita.com/sy1/items/bb8e7df26a3bb3d925fd)
[APG4bで自分が書いたコード4　EX16~19](https://qiita.com/sy1/items/af7ef032967c7890f92a)
ActiveAdminの複数バリデーションエラー時の日本語化

# 環境
* rails7
* ActiveAdmin

# 概要
バリデーションに複数引っかかった場合に
「◯◯が入力されていません and △△が正しくありません」と表示されてしまいます。

# 対処
日本語化対応するためにja.ymlの以下に値を変更すればOK!!

```config/locales/ja.yml
ja:
  support:
    array:
      words_connector: ", "
      two_words_connector: " and "
      last_word_connector: ", and "
```
【Swift】WKWebViewで別ページへの遷移を無効する方法

# はじめに
今回の記事は下記リンクのSwift版です。

https://ponpoko1968.hatenablog.com/entry/controlling-navigation-wkwebview

無効にするだけでなく、アクションのトリガーにもできます。

# 実装要件
- 起動時に`https://qiita.com/SNQ-2001`を表示する
- `https://qiita.com/SNQ-2001`以外は表示できないようにする
- `https://qiita.com/SNQ-2001`以外を表示しようとしたら警告アラートを出す

# 完成形
![wkwebview_AdobeExpress.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/35dce500-b431-1b02-8f6c-1d0cf4ccc12f.gif)


# 実装
```swift
import UIKit
import WebKit

class ViewController: UIViewController, WKNavigationDelegate {

    var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()

        webView = WKWebView(frame: view.frame)

        view.addSubview(webView)

        webView.load(URLRequest(url: URL(string: "https://qiita.com/SNQ-2001")!))

        webView.navigationDelegate = self

    }

    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        guard let url = navigationAction.request.url else { return }
        if url == URL(string: "https://qiita.com/SNQ-2001")! {
            decisionHandler(WKNavigationActionPolicy.allow)
        } else {
            alert()
            decisionHandler(WKNavigationActionPolicy.cancel)
        }
    }

    func alert() {
        let alertController = UIAlertController(title: "⚠️注意⚠️", message: "このページからの移動はできません。", preferredStyle: .alert)
        let alertAction = UIAlertAction(title: "OK", style: .default) { _ -> Void in }
        alertController.addAction(alertAction)
        present(alertController, animated: true, completion: nil)
    }

}
```

:::note warn
注意
`decisionHandler(WKNavigationActionPolicy.allow)`
`decisionHandler(WKNavigationActionPolicy.cancel)`
どちらかがないとクラッシュします。
:::

# おわり
Objective-Cの情報ばかりで苦戦しました
検索の仕方が悪かったのかな？
HTMLが動く仕組み

プログラミング学習を本格的に初めて1日目。
以下表題の問いについて分かったので、残しておきます。

# どうしてブラウザ上でHTMLが動作するのか
結論、ブラウザには言語ソフト（解析エンジン）なるものが備わっており、
そいつがHTMLを解釈してブラウザに表示できたわけらしい。

素朴な疑問だったけどわかってよかった。
Laravel:Carbonの値が変わる

# 事象
- Carbonクラスのインスタンスを操作すると、元のインスタンスの値が変わる
```
// 現在年月日が2022-01-01だとする
//インスタンス作成
$now = Carbon::now();
var_dump($now->format('Y-m-d')) // 2022-01-01
// 一日加える
$addOneDay = $now->add(1, 'day');
// 結果
var_dump($now->format('Y-m-d')) // 2022-01-02 ← 注目！！
var_dump($addOneDay->format('Y-m-d')) // 2022-01-02
```

# 原因
- CarbonクラスのインスタンスはMutable(可変)だから

# 解決策
- copy()を使用する
```
// 現在年月日が2022-01-01だとする
//インスタンス作成
$now = Carbon::now();
var_dump($now->format('Y-m-d')) // 2022-01-01
// 一日加える
$addOneDay = $now->copy()->add(1, 'day'); ← 注目！！
// 結果
var_dump($now->format('Y-m-d')) // 2022-01-01 ← 期待通り
var_dump($addOneDay->format('Y-m-d')) // 2022-01-02
```
- Immutableにする
```
// 現在年月日が2022-01-01だとする
//インスタンス作成
$now = Carbon::now();
var_dump($now->format('Y-m-d')) // 2022-01-01
// CarbonImmutableクラスに変換
$now->toImmutable(); ← 注目！！
// 一日加える
$addOneDay = $now->add(1, 'day');
// 結果
var_dump($now->format('Y-m-d')) // 2022-01-01 ← 期待通り
var_dump($addOneDay->format('Y-m-d')) // 2022-01-02
```
蟻本の問題をGo言語で解いてみた(p21 三角形)

## 問題: 三角形
n本の棒があります。棒iの長さはaiです。
あなたは、それらの棒から3本を選んでできるだけ周長の長い三角形を作ろうと考えています。
最大の周長を求めなさい。
ただし、三角形が作れない際には0を答えとしなさい。

## 制約
- 3 <= n <= 100
- 1 <= ai <= 10^6

## 解法

3辺で三角形が作れる必要十分条件は、<b>`最も長い辺の長さ < 他の2本の辺の長さの和`</b>が成り立つ事である。
これを利用して、全ての3辺の全ての組み合わせをチェックし、三角形が成立する組を探索する(他にn log nで解ける解き方もある)。
具体的な実装としてはは、3辺の組み合わせを3重ループでチェックし、
三角形が成立した場合は、すでに発見済みの周長の値と比較し、大きい方を答えの変数に保持する。

## 解答

```go
package main

import (
  "fmt"
  "math"
)

func main() {
  // 入力パターン1: 答えは12
  n := 5
  a := [5]float64{2, 3, 4, 5, 10}
  fmt.Println(solve(n, a))

  // 入力パターン2: 答えは0
  n = 4
  a = [5]float64{4, 5, 10, 20}
  fmt.Println(solve(n, a))
}

// 解答
func solve(n int, a[5]float64)float64{
  var answer float64 = 0

  for i := 0; i < n; i++ {
    for j := i+1; j < n; j++ {
      for k := j+1; k < n; k++ {
        // ある組の周長
        sum_len := a[i] + a[j] + a[k]
        // 最長の辺
        max_len := math.Max(a[i], math.Max(a[j], a[k]))
        // 最長の辺以外の2辺の長さの和
        rest_len := sum_len - max_len

        // 最長の辺の長さが他の2辺の長さの和より小さい場合は、三角形が成立する
        if max_len < rest_len{
　　　　　　// すでに保持されている周長より、大きい場合は答えを更新する
          answer = math.Max(answer, sum_len)
        } 
      }
    }
  }

  return answer
}
```

## 参考文献
- p21, プログラミングコンテストチャレンジブック
LINEは何故「既読機能」なんていう「悪魔」を作り出したのか。

# 僕らをLINEに縛り付けるためだ。

アプリというものは使われば使われるほど価値がある。

既読機能があることにより、ユーザーは既読・未読の状態がが気になってしまい、LINEを何度も開くことになる。

そして僕らは眠れない夜を手にした。

# 被害者の声

- 既読状態が気になって何度もLINEのトークを開いてしまう。眠れない。
- 既読無視は許せるが、未読無視は許せない。 怒りのあまり夜に眠れない。
- 未読無視は許せるが、既読無視は許せない。 怒りのあまり夜に眠れない。

既読未読チェックはもはや1アプリケーションの枠を超えて文化でさえある。

この病魔に侵された人々の声は悲痛だ。

(僕はよくLINEの既読未読を気にせずに済むように、相手のトークを一時的に「非表示」にする)

# 既読機能は安否確認のためだという説を耳にしたことがある

そんなわけはない。安否なら返信で分かるだろう。

# 注意力を奪い合う世界

アテンション・エコノミー。

FaceBookもInstagramもTwitterもユーザーの注意力を奪い合っている。
ユーザーの注意力を奪えば奪うほど、サービスは成功するからだ。

古来より資本主義社会では富むものが貧しい者を搾取する構造があるが、それが現代においては一歩進んだ。
サービスはユーザーの注意力を搾取するようになった。

有名な話だが、スティーブ・ジョブズは子供にスマートホンを与えなかったという。何故か？有害だからだ。つまりはそういうことだ。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89618/2f9facba-cbb1-ca62-a641-df5843265d02.png)


# と言いつつ

僕らはLINEには抵抗できない。すでに魂を売り渡してしまったのだ。

あとはこの悪魔となるべくうまく付き合うだけである。


<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
oss-licenses-pluginがOSSをリストアップする仕組み

## はじめに

[OSS Licenses Gradle Plugin](https://github.com/google/play-services-plugins/tree/master/oss-licenses-plugin)は、ビルド時にOSSリストを作成ます。そのリストをもとにOssLicensesMenuActivityでライセンス表示できます。

これまではcookpadさんの[LicenseToolsPlugin](https://github.com/cookpad/LicenseToolsPlugin)を使わせてもらっていたのですが、deprecatedということで代わりにお勧めされたGoogleのOSS Licenses Gradle Pluginを使おうとしました。ところが使ってみるとSTLやらICU4CなどのOSSがリストアップされて、どういうこと？となったのでソースコードを調べて確認しました。

## 仕組み

ビルドを開始すると、OSS Licenses Gradle Pluginは初めにGradleでdependenciesのリストを作成します。以下のコマンドで出力されるやつと同じです。

> gradlew -q :app:dependencies --configuration releaseCompileClasspath

作成されたファイルはapp/build/generated/third_party_licenses/[Build variant]/dependencies.json に出力されます。

POMファイルやAARファイルからライブラリのライセンスを取得します。例えばplay-services-tasksの場合は[ここ](https://maven.google.com/web/index.html?q=play-services-tas#com.google.android.gms:play-services-tasks:17.0.0)にファイルがあります。

POMファイルにライセンスの種類とライセンスファイルへのリンクがあるので、まずそれをOSSリストに追加します。

dependencies.jsonに書かれているgroup名がcom.google.android.gmsかcom.google.firebaseで始まる場合、aarファイルの中に含まれるthird_party_license.json/third_party_license.txtに使用しているサードパーティのライセンスが書かれているので、それをリストアップします。

そんな感じでリストアップされたファイルがapp/build/generated/third_party_licenses/[Build variant]/res/raw のファイルです。

## 小ネタ

play-services-tasksのthird_party_licenseにはSGI STLが含まれていて、これがGPLなのでちょっと気になったのですが、

```
SGI STL

The STL portion of GNU libstdc++ that is used with gcc3 and gcc4 is licensed
under the GPL, with the following exception:

# As a special exception, you may use this file as part of a free software
# library without restriction.  Specifically, if other files instantiate
# templates or use macros or inline functions from this file, or you compile
# this file and link it with other files to produce an executable, this
# file does not by itself cause the resulting executable to be covered by
# the GNU General Public License.  This exception does not however
# invalidate any other reasons why the executable file might be covered by
# the GNU General Public License.
```

と書かれており、コンパイルして使う分には無制限に利用できるようです。