OmniAICreator/Qiita-1.07M huggingface dataset:
Ubuntu Server 20.04.3 LTS 構築#24 セキュリティ設定10(DNSサーバー)

実施日:2022/04/18～2022/04/25

【今回の内容】
DNSサーバーのセキュリティ設定

# DNSサーバーのセキュリティ対策
ローカル上で出来ること。
･ゾーン転送の制限
⇒マスターDNSサーバーからスレーブDNSサーバーにゾーン転送をする範囲を設定します。
　転送範囲を制限することで、ゾーン情報の全体を外部から問い合わせが出来なくなります。

･DNS問い合わせの制限
⇒DNS問い合わせの範囲を自信が管理する範囲内に制限をする。
　管理する範囲内にすることで不正なDNSサーバー利用を阻止することが出来る。

･バージョン番号の隠蔽
⇒BINDのバージョンを隠蔽することでそのバージョンが抱えている脆弱性を突かれて不正な
　アクセスから防御する。但し、バージョンを隠蔽したからとって安全を確保したわけではない。
　
･root以外によるnamedの実行
⇒root権限で実行しているとセキュリティホールを突かれて侵入されたときに被害が甚大になるため、
　被害を最小限に抑えるために一般ユーザー権限で被害を最小限にする。

# DNSサーバーへの攻撃方法
･DNSキャッシュポイズニング攻撃
⇒ホスト名とIPアドレスを改ざんし、有害なサイトへと導く。

･ゾーン転送要求による攻撃
⇒同じゾーン内に負荷分散するために複数のDNSサーバーを配置する。これらのDNSサーバー内のゾーン情報を
　同期する必要があります(ゾーン要求という)。そうしないと、名前解決の負荷分散が出来ないため。
　ゾーン要求を外部から行い、その応答に対して不正なDNS情報を送ることが出来る。
　
･カミンスキー攻撃
⇒キャッシュサーバーにキャッシュ情報があれば、権威DNSサーバーに問い合わせをしない。
　存在しないホスト名で問い合わせを行うとキャッシュサーバーにキャッシュ情報がないため
　権威DNSサーバーに問い合わせをする。この問い合わせ時に攻撃者が不正な情報を送ること。

# DNSサーバーへの攻撃方法の対処法
･DNSキャッシュポイズニング攻撃
⇒TTLの時間を長くする。
　※但し、カミンスキー攻撃の対応策としては不十分である。

･ゾーン転送要求による攻撃
⇒マスターサーバーからスレーブサーバーへのゾーン転送時に共有秘密鍵を使用して転送の安全性を高める
　このような仕組みをTSIG(Transaction SIGnatures(トランザクション署名))という。

･カミンスキー攻撃
⇒権威DNSサーバーからの応答が信頼できるものからの応答であることを証明出来れば、不正な攻撃から守ることが出来る。
　権威DNSサーバーとキャッシュサーバー間での応答が信頼できるものであることを証明する機能をDNSSECという。

# 設定

これらの外部からの攻撃に備えるため、実際に設定をしていきます。
･ゾーン転送の制限
･ゾーン転送要求による攻撃
⇒現在、スレーブサーバーは建てていませんので、設定は見送ります。

･DNS問い合わせの制限
⇒DNS問い合わせの範囲を以下のように設定しました。
```
　/etc/bind/named.conf.optionsを開き
　allow-query { localhost; 192.168.1.0/24; };
 #問い合わせの許可範囲をローカル上、LAN内に設定
```

･バージョン番号の隠蔽
⇒何も設定していないとバージョンは確認できます。
```
  dig @localhost version.bind chaos txtでバージョンを確認できます。Anser sectionに表示されます。
　#修正方法
　/etc/bind/named.conf.optionsを開き
　option内にversion"任意の文字列"を記入し
　sudo systemctl restart namedを実行します。
　#設定後、dig @localhost version.bind chaos txtで確認すると、変更した任意のものに変わります。
```

･root以外によるnamedの実行
⇒BINDをパッケージでインストールすると、一般ユーザーが作成され、その権限で動作しています。
　ただ、更にセキュリティ面を強化するとすれば、chroot以下に動作させれば、chroot以下の箇所しか
　アクセス出来ないためセキュリティ面は強固になります。
```
#設定方法
#chrootのディレクトリを作成して、パーミッション設定してまではイメージ出来ていましたが、
#そのまま丸ごとchrootディレクトリ内に移動して良いのだろうかと疑問に思い、調べてみました。
#以下のサイトで詳しく説明があったので、参考にさせて頂きました。

#まずはchrootディレクトリとその配下のディレクトリを作成します。
sudo mkdir -p /chroot/named
cd /chroot/named
sudo mkdir -p dev etc/namedb/slave var/run

#次に所有権とアクセス権の変更をします。
sudo chown root:root /chroot
sudo chmod 700 /chroot
sudo chown bind:bind /chroot/named
sudo chown bind:bind /chroot/named/etc/namedb/slave
sudo chown bind:bind /chroot/named/var/run
sudo chmod 700 /chroot/named

#bindディレクトリにあったnamed.confファイルを/chroot/named/etcにコピーします。
sudo cp /etc/bind/named.conf /chroot/named/etc

#デバイスファイルを作成する。
sudo mknod /chroot/named/dev/null c 1 3
sudo mknod /chroot/named/dev/random c 1 8
#※mknodというコマンドがあることを初めて知りました。
#解説しているサイトを見つけましたので、そちらでどういうものか確認しました。

#PIDと統計データを格納する
sudo chown bind:bind /chroot/named/var/run

#起動オプションの編集
#/etc/default/bind9内を以下に変更します。
OPTIONS="-u bind"
↓
OPTIONS="-u bind -t /chroot/named -c /etc/named.conf"
#※/etc/default/bind9が見当たらない場合は/etc/default/namedで存在していると思います。
#実際、私はnamedでした。
```
< 参考サイト >
[トルコラルラリア様](https://blog.kusshie.com/2020/bind9-chroot-1/)
[Linuxコマンド.NET様](https://linuxcommand.net/mknod/)

･カミンスキー攻撃対策
⇒DNSSECを導入する。
※導入にあたり、自身で行う作業と上位の権威サーバーに設定が必要な箇所があります。
　今回は対策としてDNSSECがあるということのみ記載します。

今回はここまで。
Miroを使ってみた

# はじめに
1年近く、プロジェクトでMiroを使っています。
設計のためにこんな使い方した、こんな風にしておくとメンテナンスもしやすかったとか、こんなことに使ってみたといったことを徒然なるままに残しておこうと思い投稿してます。

# こんな場面でMiroを使っています
1. 外部要件を整理する 
    1. インターフェース定義
    1. システム間連携
1. データパターンの整理
1. スケジュールの意識合せ
1. デイリーで行う予定と実績の記録
    1. タイムボックス
    1. タスク
    1. 議事メモ
    1. 感情（成功、失敗、良かった点、愚痴…。）

# 使っている時の工夫
### 使っているすべてのシーンで多用しているは、`frame` の中に用意されている`Custom`というFramのオブジェクトです。
- 理由は、いたって簡単な理由で、以下の2点があるからです。
    - このFramオブジェクトの上で、`sticky note`(付箋)や`shape`といったオブジェクトを配置すると全体の場所を移動したいときとかに、Framだけを選択すると全体を移動することができる
    - 全体の履歴として残したい場合も、このFramをコピー＆ペーストすることですべてのオブジェクトをコピーして移動することができる
- こんな感じで全体をコピーして貼り付けたり、移動するのは、面倒ですよね。対象をすべて選択できているのかなど気にしないといけないので。
※といっても、比較的容易なんですが💦
　　　　　　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518581/1f97e4ec-eebb-7731-adf8-1ea43565dbfb.png)
- ですが、やはりFrameだけを選択するとFram内のオブジェクトはもれなく選択範囲にしてもらえるとなると、ワンクリックで済むので、より容易なのでよく利用しています。
　　　　　　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518581/542beab2-7df3-ec16-5587-1c90e9049915.png)

### 次によく使うのは、オブジェクトのロック機能です。
- フォーマットにしたい内容を作成したら、Framでくくってロックしておく。
- このロックした内容をコピーして貼り付けるとロックがかかっていない状態でコピーできるので、フォーマットにしたい内容をロックしておくと非常に便利で多用している。（画像は、デイリーの予実を遺すためのフォーマットです。）
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518581/1918d52d-0070-979c-88f2-48fab04f8ccb.png)

- 改善したいときなど、修正したい場合は、赤枠でくくった【Long press to unlock】で解除できます
　　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2518581/01f93efe-18b0-a3df-b221-699cf6c792e3.png)

# 最後に
`Miro`はあくまでも設計の時には、ドキュメント作成する際のイメージを提供するための有用な一助であると、とらえています。
というのも、`Miro`で作成したイメージを`AsciiDoc`や`Confluence`に持っていきたくてもそのままを持っていくことはできず、イメージ図にして配置する必要があるため、設計書側のメインになる`AsciiDoc`や`Confluence`では修正ができないからです。
ですが、その代わりに、容易にバックアップが取れて、`AsciiDoc`や`Confluence`に反映しなおせるので、非常に優秀なツールだと思っています。
また、何か工夫になると思うことがあれば、投稿させていただきます。





# 参考
- Miroを使ってみたいと思われた方は、こちらから
    - [Miro](https://miro.com/ja/)
関数の引数に関数を指定する(クロージャ)

# はじめに
最近まで「関数の引数に関数を指定する」のやり方がわからなかったのですがちょっと理解したので今後、見返せるようにまとめておきます

# クロージャについて
公式のクロージャのサンプルです

```Swift
let sum = { (x: Int, y: Int) -> Void in
    print(x + y)
}

sum(7, 8) // OK
sum(x: 7, y: 8) // エラー
```
これはクロージャ定数というものです
クロージャ定数を使ってみて不思議だったのが使用時に引数名を記述してはいけないという点です。
関数と同じ様な使い方なので今までの自分では関数との区別ができていなかったです。

また、デフォルト値の指定ができない様です
```Swift
// ❌
let sum = { (x: Int = 0, y: Int = 1) -> Void in
    print(x + y)
}
```

# 関数の引数に関数を指定
これが今回のメインです
これは「関数の引数にクロージャを使う」というみたいです
```Swift
struct ContentView: View {
    var body: some View {
        Button(action: {
            // 使い方
            sum(x: 2, y: {
                average(x: 3, y: 4, z: 2)
            })
        }) {
            Text("実行")
        }
    }
    // ここがクロージャ
    func sum(x: Int, y: () -> Int) {　// 引数に () -> 型名 を指定する
        print(x + y())
    }
    // 引数として使う関数
    func average(x: Int, y: Int, z: Int) -> Int {
        return (x + y + z) / 3
    }
}
```

トレイリングクロージャという書き方もあるみたいです
トレイリングクロージャを使うと解読性が上がりそうです
```Swift
// デフォルト
sum(x: 2, y: {
    average(x: 3, y: 4, z: 2)
})

// トレイリングクロージャ
sum(x: 2) {
    average(x: 3, y: 4, z: 2)
}
```
ちょっと簡単になりましたね

もしかしたらこれもトレイリングクロージャかも？

```Swift
// デフォルト
Button(action: {

}, label: {
    
})

// actionにトレイリングクロージャ
Button {
    
} label: {

}

// labelにトレイリングクロージャ
Button(action: {

}) {

}

// actionとlabelにトレイリングクロージャ
Button("") {

}
```
そんな気がします

# おわり
ちょっとずつ知識が増えている事が実感できると楽しくなりますよね
クロージャについて知識が増えたらここに追加していきます。

間違っているところがあればコメントで教えてください！！
SSCNET通信用PCカード(PCMCIA)にリソースを割り付けるレジストリ変更

PCから三菱電機のJ2、J2Sシリーズサーボアンプへ座標系を書き込む通信用のA30CD-PCFをセットアップする。
PCMCIA(PCカード)スロットにA30CD-PCF(SSCNET通信カード)入れるとデバイスマネージャでは認識されているように見える。
が、ポートが開かず通信タイムアウトになってしまう。
winxpではリソース（IRQ、IOアドレス）が自動で割りつけられないことが原因の様子。

[SSC I/Fカード(A30CD-PCF)を使用する上でのパソコン選定方法のお知らせ](https://www.mitsubishielectric.co.jp/fa/document/sales/ssc/10-22/10-22.pdf)にIRQ、IOアドレス範囲について記載がある。

レジストリエディタ (Regedit.exe)を起動し割り付ける。 
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\PCMCIA\Parameters
のレジストリキーを作成し下記の値を追加する。
値の名前:DisableIsaToPciRouting
データ型 :REG_DWORD
値 :1

[contec製wifi用のPCカードを設定するFAQ](https://contecforum.com/index.php/en-us/top-us/contec-faq-us/862-windows-32bit-pc-pcmcia)と同じ手順。

[三菱電機マニュアル](https://dl.mitsubishielectric.co.jp/dl/fa/members/document/manual/ssc/ib67333/ib67333a.pdf)ではwin98までしか想定されておらず、表記がない。

二つはあらかじめ入れておくこと。
MT Developer(要らないかも。)
Mx Component Ver3(Winxpは対応確認できた。)

サーボ更新しろ。
Videojetの旧いインクジェットプリンターは半角カタカナの文字コードがずれてる。

産業用インクジェットプリンターの文字コードは
現行機種はS-JISやUNICODE等幅広く対応しているが、以前の機種は半角(8bit)独自拡張ASCIIを用いている。
英数はASCIIやS-JISと共通だが、空きに無理矢理「賞味期限」等の多用される漢字を押し込めている。
ぱっと見S-JISの半角カタカナに見えるが、17文字ずれるので文字コードの差し引きが必要。対応表にした。
例はVIDEOJET1520のもの。1990～2000年製造機種はこのパターンが多いらしい。
ユーザーズマニュアルに独自文字コード表は掲載されていない。サポートセンター0120-336-058(JPNCall@videojet.com)から取り寄せる必要がある。

通信で使ってる場合は大体メッセージ1の差し替え。
U	1	[LF] ここに文字列

|10進|16進|Videojet|S-JIS|差|
|:----|:----|:----|:----|:----|
|32|20|[sp]||0|
|33|21|製|||
|34|22|造|||
|35|23|賞|||
|36|24|味|||
|37|25|使|||
|38|26|用|||
|39|27|保|||
|40|28|(||0|
|41|29|)||0|
|42|2A|証|||
|43|2B|+||0|
|44|2C|、||0|
|45|2D|-||0|
|46|2E|'||0|
|47|2F|/||0|
|60|3C|迄|||
|61|3D|=||0|
|62|3E|年|||
|63|3F|月|||
|91|5B|期|||
|92|5C|限|||
|93|5D|間|||
|94|5E|以|||
|160|A0|ア|B1|-17|
|161|A1|イ|B2|-17|
|162|A2|ウ|B3|-17|
|163|A3|エ|B4|-17|
|164|A4|オ|B5|-17|
|165|A5|カ|B6|-17|
|166|A6|キ|B7|-17|
|167|A7|ク|B8|-17|
|168|A8|ケ|B9|-17|
|169|A9|コ|BA|-17|
|170|AA|サ|BB|-17|
|171|AB|シ|BC|-17|
|172|AC|ス|BD|-17|
|173|AD|セ|BE|-17|
|174|AE|ソ|BF|-17|
|175|AF|タ|C0|-17|
|176|B0|チ|C1|-17|
|177|B1|ツ|C2|-17|
|178|B2|テ|C3|-17|
|179|B3|ト|C4|-17|
|180|B4|ナ|C5|-17|
|181|B5|ニ|C6|-17|
|182|B6|ヌ|C7|-17|
|183|B7|ネ|C8|-17|
|184|B8|ノ|C9|-17|
|185|B9|ハ|CA|-17|
|186|BA|ヒ|CB|-17|
|187|BB|フ|CC|-17|
|188|BC|ヘ|CD|-17|
|189|BD|ホ|CE|-17|
|190|BE|マ|CF|-17|
|191|BF|ミ|D0|-17|
|192|C0|ム|D1|-17|
|193|C1|メ|D2|-17|
|194|C2|モ|D3|-17|
|195|C3|ヤ|D4|-17|
|196|C4|ユ|D5|-17|
|197|C5|ヨ|D6|-17|
|198|C6|ラ|D7|-17|
|199|C7|リ|D8|-17|
|200|C8|ル|D9|-17|
|201|C9|レ|DA|-17|
|202|CA|ロ|DB|-17|
|203|CB|ワ|DC|-17|
|204|CC|ン|DD|-17|
|205|CD|ァ|A7|38|
|206|CE|ィ|A8|38|
|207|CF|ゥ|A9|38|
|208|D0|ェ|AA|38|
|209|D1|ォ|AB|38|
|210|D2|ヵ| | |
|211|D3|ヶ| | |
|212|D4|ッ|AF|37|
|213|D5|ャ|AC|41|
|214|D6|ュ|AD|41|
|215|D7|ョ|AE|41|
|216|D8|ヮ| | |
|217|D9|゛|DE|-5|
|218|DA|゜|DF|-5|
|219|DB|内| | |
|220|DC|見| | |
|221|DD|本| | |
|222|DE|品| | |
|223|DF|￥| | |

ASCIIには存在しない小さい「ヵ」「ヶ」「ヮ」がある。「3ヵ月」「5ヶ口」
ついでにシークヮーサーも作れる。
DependencyNotFoundException

state_notifier内で`LocatorMixin`をmixinして、Repositoryを使おうと思ったら、`DependencyNotFoundException`が出てしまう。
**原因**は`MultiProvider`にちゃんと定義していても順番が重要ということ(あたりまえだけど)
`Repository`を`State Notifier`より前に書かないといけない

以下のような感じ。

修正前

```dart
return MultiProvider(
  providers: [
    StateNotifierProvider<HogeNotifier, HogeState>(create: (context) => HogeNotifier()),
    Provider<InterfaceHogeRepository>(create: (context) => InterfaceHogeRepository()),
  ],
);
```

修正後

```dart
return MultiProvider(
  providers: [
    StateNotifierProvider<HogeNotifier, HogeState>(create: (context) => HogeNotifier()),
    Provider<InterfaceHogeRepository>(create: (context) => InterfaceHogeRepository()),
  ],
);
```
避難所探し～君は攻撃から逃れられるか？～

## 物語の始まり

**20××年×月×日、東京である事件が起きていた…**

品川駅。それは各路線をつなぐターミナル駅である。オフィスも多いことからサラリーマンの利用も多い。

昼過ぎ、駅にサイレンの音が鳴り響いた。

「ピー！ピー！緊急事態です。品川駅付近にゴジラが上陸しているとの情報があります。」

なぜかゴジラが品川にいるらしい。どうやら北の方角から歩いてきているとのこと。

「皆さん落ち着いてください。警備部隊の活躍により、品川駅でゴジラを足止めできることになりました。その後特殊部隊を派遣して、ゴジラを海に戻す手配をする予定です。」

警備部隊や特殊部隊の活躍により、被害は最小限で済みそうだ。
と思っていたら、続けて放送があった。

「しかしながら特殊部隊の派遣は時間がかかっており、品川駅の損傷は免れません。このままま駅にいるのは危険です。いち早く頑丈そうな建物に逃げてください。」

遠くまで行くのは体力が持たなさそうだ。品川駅付近の頑丈そうな建物に逃げるのがよさそうだな。
頑丈そうな建物...例えば避難所はどうだろうか？
よし、決まったら早速一番近い避難所を探さなくては！


**皆さんは品川駅から近い避難所を探すことができるだろうか？**

## 詳細
#### 茶番の裏側
自分で書いていてよくわからない物語ができました。
元々はdelikaに避難所情報があるのを見つけて、これで何か実施したいと思ったのがきっかけです。

https://delika.io/narita1980/kuseizyoho

データを見たら品川駅付近の情報だったので、駅から避難所に向かうことを想定して活用しようと考えました。駅から避難所に向かう理由って何だろう、と思った時にゴジラが攻撃してくるのはどうだろうかと思いついて、上記のストーリーに。
昔見た「シン・ゴジラ」の影響ですね。多分。

また避難する場所には、避難所と広域避難場所というのがあるそうです。避難所は収容施設(学校など)であるのに対し、広域避難場所は公園などオープンスペースであることが特徴です。

https://www.tfd.metro.tokyo.lg.jp/hp-kouhouka/kts/kts_03/kts04.html

ゴジラからの攻撃を考えると収容施設の方が望ましいと考え、品川駅から一番近い避難所をデータから探索しました[^1]。
[^1]: あくまでもデータ内での探索なので、もっと近い避難所があるかもしれません。

#### コード
データ取得の方法は割愛。

```python
#モジュールインポート
import folium 
import pandas as pd

df1 = pd.read_csv('212.csv')
df1.head(2)
```

ここには入っていないが、実際には場所の緯度・経度も含まれています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1259951/d4c4063c-b030-ff81-98da-a66a7eadc0a4.png)

```python
#避難所と広域避難場所に分けてマーカーをつける
shinagawa_map = folium.Map(location=[35.6291,139.7389], zoom_start=14)

for i, row in df1.iterrows():

    place = row['category']
    if place == '避難所':
            folium.Marker(
                location=[row['latitude'], row['longitude']],
                popup=row['facility_name'],
                icon=folium.Icon(color='red')
            ).add_to(shinagawa_map)
    else:
        folium.Marker(
            location=[row['latitude'], row['longitude']],
            popup=row['facility_name'],
            icon=folium.Icon(color='blue')
        ).add_to(shinagawa_map)

shinagawa_map
```

品川駅を中心にしてマッピングしました。赤が避難所、青が広域避難場所を表しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1259951/7db4c3ec-1a0c-4f2c-ff29-05c5a4a3423b.png)

```python
#★各場所と品川駅の距離を測定し、避難所かつ最短距離の場所を見つける
import geopy
from geopy.distance import geodesic

location = (35.6291,139.7389)
df1["distance"] = df1.apply(lambda x:geodesic((x["latitude"], x["longitude"]), location), axis=1)

#距離の項目をfloat型にしてidxmaxで使えるようにする
henkan = []

for i in range(len(df1)):
  
  distance = df1["distance"][i]
  moji = str(distance)
  moji2 = moji[:-3]
  num = float(moji2)
  henkan.append(num)

df1['distance']=henkan

df2 = df1.query('category == "避難所"')
best = df2['distance'].idxmin()
df2['facility_name'][best]

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1259951/aa492d72-ea32-d244-75e7-23ca67908231.png)

御殿山小学校が品川駅に一番近い避難所だそうです。

## まとめ
可視化を利用して、該当の場所から一番近い避難所を見つけることができました。
これで実際にゴジラが襲ってきても安心ですね。

## 参考
https://qiita.com/Kumanuron-1910/items/12ce7aa02922927de2f4
https://norari-kurari-way.com/python-folium/
https://qiita.com/Taiyo_4U/items/40b34c2d13b1d22a2beb
ISO/IEC27001 とは

## 勉強前イメージ

ISOよくみるよね・・・いっぱいありそう

## 調査

### ISO/IEC27001 とは

Information Security Management Systems といい、ISMSと呼ばれています。
その名の通り、情報セキュリティマネジメントシステムについてのISOの規格です。
ISMSは組織の情報のセキュリティや管理方法、マネジメント方法について記載されています。

### 情報セキュリティの三要素

マネジメントの重要点としては以下があります。

- 機密性 : 承認されたものだけがアクセスできる
- 完全性 : 情報が改竄、破壊されていない
- 可用性 : 必要なものが必要なときにアクセスできる

### ISO/IEC27001の取得のメリット

- 社会的責任の達成

企業にとってもセキュリティ対策は社会的責任の位置づけになります。
ISO/IEC27001の取得で企業イメージの向上が見込まれます

- 信頼性の向上

セキュリティの対策を行うことで、特に機密性の高い情報を扱う企業からの信頼が高くなることはメリットです。

- 売上機会の拡大

契約締結前には情報セキュリティチェックなど行いますので、
新規取引先の判断材料にもなります。

## 勉強後イメージ

Pマーク的な？取得って感じなのかな？
セキュリティの改定とかもあって重要になっているんですね。

## 参考

- [ISMSとは？ ISO / IEC 27001との違いや取得方法について解説](https://www.amiya.co.jp/column/isms_20201006.html)
- [ISMS（情報セキュリティマネジメントシステム）とは](https://isms.jp/isms/)
[SublimeText3] JetBrainsっぽいキーバインド

* 自分用のメモです

```json
[
	// --------------------------------------------------------------------
    // Eclipse Key Bindings
    // ---------------------------------------------------------------------
    { "keys": ["alt+left"], "command": "jump_back" }
    ,{ "keys": ["alt+right"], "command": "jump_forward" }
    ,{ "keys": ["ctrl+y"], "command": "run_macro_file", "args": {"file": "Packages/Default/Delete Line.sublime-macro"} }
    ,{ "keys": ["ctrl+l"], "command": "show_overlay", "args": {"overlay": "goto", "text": ":"} }
    ,{ "keys": ["shift+alt+r"], "command": "find_all_under" }
    ,{ "keys": ["ctrl+k"], "command": "find_under" }
    ,{ "keys": ["ctrl+shift+k"], "command": "find_under_prev" }
    ,{ "keys": ["alt+up"], "command": "swap_line_up" }
    ,{ "keys": ["alt+down"], "command": "swap_line_down" }
    ,{ "keys": ["ctrl+alt+j"], "command": "join_lines" }
    ,{ "keys": ["ctrl+d"], "command": "duplicate_line" }
    ,{ "keys": ["shift+ctrl+r"], "command": "show_overlay", "args": {"overlay": "goto", "show_files": true} }
    ,{ "keys": ["shift+ctrl+y"], "command": "lower_case" }
    ,{ "keys": ["shift+ctrl+x"], "command": "upper_case" }
    ,{ "keys": ["ctrl+alt+l"], "command": "reindent" , "args": {"single_line": false}}
    ,{ "keys": ["ctrl+shift+c"], "command": "toggle_comment", "args": { "block": false } }
    ,{ "keys": ["ctrl+o"], "command": "show_overlay", "args": {"overlay": "goto", "text": "@"} }
    ,{ "keys": ["ctrl+shift+s"], "command": "save_all" }
    ,{ "keys": ["shift+ctrl+f4"], "command": "close_all" }
    ,{ "keys": ["shift+ctrl+w"], "command": "close_all" }
    ,{ "keys": ["ctrl+b"], "command": "goto_definition" }
    ,{"keys": ["f5"], "command": "revert"}
    ,{ "keys": ["ctrl+f11"], "command": "build" }

    // ---------------------Sublime Text3 Original Shortcut Key ---------------------------
    ,{ "keys": ["alt+j"], "command": "find_under_expand" }
    ,{ "keys": ["ctrl+shift+o"], "command": "prompt_open_file" }
    ,{ "keys": ["ctrl+up"], "command": "select_lines", "args": {"forward": false} }
    ,{ "keys": ["ctrl+down"], "command": "select_lines", "args": {"forward": true} }


    // ------------------------ orifinal Key Binding-----------------------------------------
    ,{ "keys": ["ctrl+tab"], "command": "next_view" }
    ,{ "keys": ["ctrl+shift+tab"], "command": "prev_view" }
    ,{ "keys": ["ctrl+e"], "command": "open_dir"
        , "args": {
            "dir": "$file_path", "file": "$file_name"
        }
    }
    // open this file
    ,{ "keys": ["ctrl+shift+l"], "command": "open_file"
        ,"args":
        {
            "file": "${packages}/User/Default ($platform).sublime-keymap",
            "contents": "[\n\t$0\n]\n"
        }
    }
    ,{
        "keys": ["alt+shift+6"],
        "command": "set_layout",
        "args":
        {
            "rows": [0.0, 0.5, 1.0],
            "cols": [0.0, 0.5, 1.0],
            "cells": [[0,0,1,2], [1,0,2,1], [1,1,2,2]]
        }
    }
]
```
TSConfig basesを使ってtsconfig.jsonをぱぱっと設定する

TypeScriptを使って開発するにはtsconfig.jsonの設定が必須です。

ただ、**tsconfig.json迷わず書けますか？**

この記事では、tsconfig.json苦手マンの筆者がよく使うTSConfig basesを紹介します。

## 1. TSConfig basesとは？

各環境に最適化された基本的なtsconfig.jsonの設定内容のpackageです。

2022/4/25現在、下記の環境に合わせた設定内容が用意されています。

1. Recommended 
2. Create React App
3. Cypress
4. Deno
5. Docusaurus v2
6. ESM
7. Next.js
8. Node 10
9. Node 12
10. Node 14
11. Node 16 + ESM + Strictest
12. Node 16 + Strictest
13. Node 16
14. Node 17
15. Node 18
16. Nuxt
17. React Native
18. Remix
19. Strictest
20. Svelte
21. Taro
22. Vite React

https://github.com/tsconfig/bases


## 2. 実際に設定してみる

基本的には公式の記載のとおりですが、実際の設定内容を見てみましょう。

Create React Appで私が実際に設定している内容です。

tsconfig.jsonを設定する前に、必要なpackageをインストールします。

```shell
npm install --save-dev @tsconfig/create-react-app
yarn add --dev @tsconfig/create-react-app
```

`tsconfig.json`の内容は下記の通り。

```json:tsconfig.json
{
  "extends": "@tsconfig/create-react-app/tsconfig.json",
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "components/*": ["components/*"],
      "layout/*": ["layout/*"],
      "lib/*": ["lib/*"],
      "redux/*": ["redux/*"],
      "style/*": ["style/*"]
    }
  },
  "include": ["src/**/*"]
}

```

どうですか？　**大分すっきり**してますよね。

おすすめ設定を一発で読み込めることにより、**tsconfig.jsonを作成する時間の短縮**や、**設定誤りによるミス防止**につながります。


ちなみに、`@tsconfig/create-react-app/tsconfig.json`の中身は下記のようになっています。

```json:create-react-app/tsconfig.json
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "display": "Create React App",


  "compilerOptions": {
    "lib": ["dom", "dom.iterable", "esnext"],
    "module": "esnext",
    "target": "es5",

    "allowJs": true,
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "isolatedModules": true,
    "jsx": "react-jsx",
    "moduleResolution": "node",
    "noEmit": true,
    "noFallthroughCasesInSwitch": true,
    "resolveJsonModule": true,
    "skipLibCheck": true,
    "strict": true
  }
}
```

参照URL：https://github.com/tsconfig/bases/blob/main/bases/create-react-app.json


## 99. おわりに

意外とTSConfig basesについて言及したサイトや記事が見当たらなかったので、今回記事にしてみました。

知らなかった人は是非活用してみてほしいです。

---

:hatched_chick:[Twitter](https://twitter.com/sake_engineer)もやっています。

よかったらフォローお願いします。
M1 mac にQulacsをインストールする方法

2022年11月更新

M1 mac にQulacsをインストールしたいです。
M1 macの場合、公式的にサポートされていないのかもしれません。
上手く行った手順は以下の通りでした。


1. mac にHomebrewをインストールします。
Homebrewのインストール方法は、ネットで検索したらすぐに見つかるため、省略します。

1. cmakeをインストールします。
Qulacsのインストールにはcmakeを使います。事前にcmakeをインストールしておきましょう。
`brew install cmake`

3. gccをインストールします。
Qulacsはg++を使うので、事前にインストールしておきます
`brew install gcc`

4. gitをインストールします。
gitを使って、gitリポジトリからqulacsを取得するためです。
`brew install git`

5. 以下のコマンドを実行します。
`git clone https://github.com/qulacs/qulacs.git`
`cd qulacs`
`export C_COMPILER=gcc-12`
`export CXX_COMPILER=g++-12`
`./script/build_gcc.sh`
ここまでは上手く行ったでしょうか？

6. 最後に以下のコマンドを実行します。
`pip install .`

以上で完了です。

## 上手くいかない時は？

以下を試してみてください。もしかすると上手くいくかもしれません
- 仮想環境のリセットと再作成（condaを利用している場合）
    - `conda remove -n <仮想環境の名前> --all`
    - `conda create -n <仮想環境の名前>`
- gcc, cmakeの再インストール
    - `brew uninstall gcc`
    - `brew uninstall cmake`
    - `brew install cmake`
    - `brew install gcc`
- condaを使わずにpipを使って環境構築する
Google Play Consoleで手動公開設定をする方法

## 内容
Google Play Consoleで手動公開設定をする方法です。
デフォルトが審査通過時に即時リリース設定になっているため、アプリの公開日時を手動で設定したい場合は以下の手順で可能です。

## 環境
chromeブラウザ

## 手順
1. Google Play Consoleで該当のアプリに遷移
2. 左側メニューの[公開の概要]をタップ
3. 管理対象の公開のステータスの[管理対象の公開をオンにする]をタップ
![スクリーンショット 2022-04-25 21.57.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130708/cfef1b5e-fa25-8d8a-9f5b-5bea0c9f5d49.png)

4.  [管理対象の公開：オン]を選択し保存
![スクリーンショット 2022-04-25 21.56.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130708/c1d0c74f-9d8c-3c19-d640-1be36aa518f7.png)
[Delphi] 生成時に消えて無くなるコードの書き方

コンパイル時にコードを生成したり抑制したい事は良くあります。
そのため多くの高級言語に条件付きコンパイルという仕組みがあります。

# 条件付きコンパイル

Object Pascal の[条件付きコンパイル](https://docwiki.embarcadero.com/RADStudio/ja/%E6%9D%A1%E4%BB%B6%E4%BB%98%E3%81%8D%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%AB%EF%BC%88Delphi%EF%BC%89)を使えば、下記のように特定のシンボルが定義されているかどうかによって、コードの生成を制御できます。

```pascal:Fooの定義
{$IFDEF SOMETHING}
procedure Foo(const AText: String);
begin
  WriteLn(AText);
end;
{$ENDIF}
```

上記の例では ```SOMETHING``` という条件シンボルが定義されている時だけ Foo という手続きのコードが生成されます。
ただ問題なのは、上記 Foo 手続きを呼び出す箇所も IFDEF～ENDIF で囲まないと行けないことです(定義されていない時、Foo の呼び出しは未定義エラーになるため)。

```pascal:Fooの呼び出し
procedure Bar;
begin
  {$IFDEF SOMETHING}
  Foo('Hello, Foo');
  {$ENDIF}
end;
```

呼び出し箇所が数カ所ならまだ何とかなりますが、何十箇所もあるととても面倒です。

# 呼び出し側に手を加えずコンパイルを通す方法

下記の様に IFDEF～ENDIF の範囲を手続き宣言の中に入れてしまえば、呼び出し側に手を加えずともコンパイルが通るようになります。

```pascal
procedure Foo(const AText: String);
begin
  {$IFDEF SOMETHING}
  WriteLn(AText);
  {$ENDIF}
end;

// 呼び出し側は IFDEF～ENDIF が要らない
procedure Bar;
begin
  Foo('Hello, Foo');
end;
```

ですが、これだと Foo 本体と呼び出しコードは残ります（呼び出しに渡している文字列などの引数も残ります）。

シンボルが未定義の時は手続きの定義も呼び出すコードも一気に全部無くなればいいのに！

# すべての呼び出しを無に帰す…

では、Foo の定義に手を加えて… inline 指令を付けてみます。


```pascal
procedure Foo(const AText: String); inline; //← ここに inline ！
begin
  {$IFDEF SOMETHING}
  WriteLn(AText);
  {$ENDIF}
end;
```

[inline 指令](https://docwiki.embarcadero.com/RADStudio/ja/%E6%89%8B%E7%B6%9A%E3%81%8D%E3%81%A8%E9%96%A2%E6%95%B0%E3%81%AE%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%97%EF%BC%88Delphi%EF%BC%89#inline_.E6.8C.87.E4.BB.A4.E3.81.AE.E5.88.A9.E7.94.A8)を付けるとコンパイラはこの関数をインライン展開しようとします。

さて、ここで ```SOMETHING``` が定義されていない場合を考えます。
そうすると Foo は以下のようになります。

```pascal
procedure Foo(const AText: String); inline;
begin
end;
```

つまり何もしない手続きになります。

この手続き Foo をコンパイルしようとすると、コンパイラは「inline 展開したくても展開する物が何も無いよ～😣」という状態になります。
そこで、コンパイラはこの**手続きの存在を消去します**。
呼び出しコードがあったとしたら、その**呼び出しも消去します！**

```pascal
Log('Hello, Foo'); // ←このコードも跡形も無く消える！
```

:::note warn
「手続き (procedure)」と書きましたが「関数 (function)」は戻り値を利用するかも知れないため存在は抹消されません。
なお、メソッドであっても procedure であれば存在は抹消されます。
:::

# 実験

では次のコードをコンパイルして、逆アセンブル結果を確認します。

```pascal
program Project1;

{$DEFINE SOMETHING} // ←ここをコメントアウトすると SOMETHING を未定義化する

procedure Foo(const AText: String); inline;
begin
  {$IFDEF SOMETHING}
  WriteLn(AText);
  {$ENDIF}
end;

begin
  Foo('Hello, Foo');
end.
```

## SOMETHING が定義済みの場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/f21f1d61-d15c-300a-907a-c42179793d6e.png)

↓コードにするとこんな状態になっているのが解ります。

```pascal
begin
Foo('Hello, Foo'); // Foo が展開されて WriteLn 呼び出しに変わっている
end.
```

## SOMETHING が未定義の場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12977/c0623a48-ad8c-a4b3-9f0f-834bde937f91.png)


↓コードにするとこんな状態で、Foo や WriteLn の呼び出しコードが無くなっているのが解ります。

```pascal
begin
end.
```

# まとめ
条件付きコンパイルで procedure の存在を消しさりたい場合は inline を組み合わせると全部消えるので良いですよ。

```pascal:ひな形
procedure Something; inline;
begin
  {$IFDEF SOMETHING}
  // シンボルが定義されていない時は全部消え去る…
  {$ENDIF}
end;
```
React-Native > Redux > redux-percist ストアを永続化



ReduxのStoreを永続化するライブラリ [redux-persist](https://github.com/rt2zz/redux-persist)


## 環境

以下が適用済み

- redux
- reudx-toolkit


## package


```
yarn add @react-native-async-storage/async-storage
yarn add redux-persist
```




## PersistGate

App.ts

PersistGateでラップする

```:App.tsx
import { PersistGate } from 'redux-persist/integration/react'

import { store, persistor } from './configureStore';


const App = () => {
  return (
    <Provider store={store}>
      <PersistGate loading={null} persistor={persistor}>
        <RootComponent />
      </PersistGate>
    </Provider>
  );
};
```



## configureStore.js

```:configureStore.js
// configureStore.js

import { createStore } from 'redux'
import { persistStore, persistReducer } from 'redux-persist'
import AsyncStorage from '@react-native-async-storage/async-storage';


import rootReducer from './reducers'

// 将来的にStoreの構成が変わったときにMigrationする際に使う
const migrations = {
  1: (state) => {
    // migration to keep only etc.
    return {
      ...state,
    };
  },
};

// persistReducerに渡すためのpersistConfig
const persistConfig = {
  key: 'root',
  version: 1, // Storeの構成が変わったときにはversion no.を上げる
  storage: AsyncStorage,
  migrate: createMigrate(migrations, { debug: false }),
};



const persistedReducer = persistReducer(persistConfig, rootReducer)


export const store = createStore(persistedReducer);
export const persistor = persistStore(store);

export type RootState = ReturnType<typeof store.getState>;
```
Text Fragment を作るブックマークレット

Text Fragment 便利ですね。ただ、 `#:~:text=` という文字列は覚えにくいし入力するのも手間なので、ブックマークレットしました。

```javascript
javascript: (() => { const text = getSelection() + ''; if (text !== '') prompt('Text Fragment', `${location.href}#:~:text=${encodeURIComponent(text.trim())}`); else alert('テキストが選択されていません。'); })(); void 0;
```

あらかじめテキストを選択してからブックマークレットを起動すると、 Text Fragment の追記された URL がプロンプトに表示されます。後はコピペしてお使いください。
[例えばこの URL であれば](https://www.eldenring.jp/newsdetail/news_detail_220419_1.html#:~:text=%E6%95%B5%E3%81%AB%E4%B8%8E%E3%81%88%E3%82%8B%E5%87%BA%E8%A1%80%E3%81%AE%E8%93%84%E7%A9%8D%E9%87%8F%E3%82%92%E4%B8%8B%E6%96%B9%E4%BF%AE%E6%AD%A3) 、こんな感じで表示されるでしょう。
![screenshot 2022-04-25 21.34.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/248832/49f1b0ed-ccb9-f177-be51-a761cf846e58.png)
最近はそんな感じです。
PowerAutomate: 正規表現の置換を使って、参照不可になる HTMLタグの除去

# 背景
Mail を Teams へ展開とかすると、 <img> タグなどで参照出来ないものがあったりします。

そのまま放置してもいいんですが、やっぱり見た目上うざいので、削除したくなります。
で、そうなると、単純な replace() だとタグ単位での削除は難しいので、正規表現置換を利用しましょう。ってお話

# 概要
1. OfficeScripts で正規表現置換を用意する
1. 呼び出して参照不可になる タグ をに一致する正規表現で置換（削除）

# 詳細
## Office Scripts 
Office Scripts では、以下定義する

```typescript:正規表現での置換
function main(
	workbook: ExcelScript.Workbook,
	originalText: string,
	expressionText: string,
	replacementText: string
): string {

 	var expression = new RegExp(expressionText, 'g'); 
	var result = originalText.replace(expression, replacementText);
	return result;
}
```

## 利用例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/27be365e-b4a4-e0e5-09b2-e85fc196df6b.png)

```awk:cid 指定の<img/> タグ
<img[\n\s]+src="cid.+?>
```

# 動作例
SharePoint の通知をそのまま Teams へ転送するとこんな感じで、cid 指定の <img> タグが参照不可になる
で、今回の置換を利用して削除してやることですっきりする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/217fd5c6-404b-d8ee-cb6f-582dce7c0b14.png)

:::note info
SharePoint の通知メールでは、件名部分が color:black になってるので、色を変えたほうが分かりやすいです
こんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/0868bfe8-513a-0e67-f06a-0bf818192f19.png)
:::

# あとがき
正規表現はやっぱり便利ですよね。

SharePoint の通知を直接 Teams に通知できるようになったらこんなことすら不要なんでしょうけどね。

# keyword
how to use regular expression in Power Automate
AWS CLIを使ってEC2やRDSのインスタンスサイズ一覧などを取得する

# EC2の情報

```bash
$ aws ec2 describe-instances --query 'Reservations[].Instances[].[InstanceId,InstanceType,PublicIpAddress,Tags[?Key==`Name`]| [0].Value]' --output table

---------------------------------------------------------------------------------
|                               DescribeInstances                               |
+----------------------+-----------+-----------------+--------------------------+
|  i-xxxxxxx          |  t2.micro |  None           |  xxxx.l2tp.org redmine  |
|  i-xxxxxx |  c5.large |  192.0.2.203 |  isu12q-3                |
|  i-xxxxxx |  c5.large |  192.0.2.50   |  isu12q-2                |
|  i-xxxxxx |  c5.large |  192.0.2.59  |  isu12q-bench            |
|  i-xxxxxx |  c5.large |  192.0.2.169   |  isu12q-1                |
+----------------------+-----------+-----------------+--------------------------+
```


# RDSのインスタンスサイズ一覧を取得する
```console
$  aws rds   describe-db-instances | jq -r '.DBInstances[] | (.DBInstanceClass|tostring) + ":\t" + .DBInstanceIdentifier'


db.m5.4xlarge:	develop-rds-mysql
db.t3.small:	develop-aurora-instance-1
db.t3.small:	develop-aurora-instance-1-ap-northeast-1a
db.m5.64xlarge:	production-rds-postgresql
```
欠陥設計を見つけた

とあることが起きてクレジットカードの番号が変わった時に見つけたWebサイトの致命的な欠陥をいおうと思う

# 某政府系サイト
政府系のクレジットカードを使うサイトで起きた問題である。ちなみにこの決済必ず特定業者（このサイトの運営主）を通さないと決済出来ない仕組みになっている。
闇が深いが、まあ、日本ではよくあることである。
# クレジットの不正利用で判明する致命的な欠陥
クレジットカードがあるとき不正利用されているとクレジットカード会社側から警告がきた。
仕方なく、クレジットカードの再発行および番号の変更、保険の申請などもろもろの手続きをする。
手続き後、番号移行してくれたサイトはいいにしろ、番号変更してくれなかったものに関しては
手動での変更が必要になった。
ここで訪れたサイトがひどい。
ユーザーIDとパスワードを入れて会員情報を編集しようとするが、クレジットカードの有効期限はいじれるものの
肝心なクレジットカードの番号が変更できない。
どういう設計をしたらこういう設計になるんだろうか。
クレジットの番号はマイナンバーかなんかと勘違いされてませんか。

# クレジットの番号がユニークキー
もしかしたらこのデータベースを組んだ人はクレジット番号をユニークキーにし、他の情報を全てクレジットカードの番号と紐付けているのでは
ないかと思っても仕方ないような状況である。マジで欠陥設計である。

# クレジットカード番号はかわるもの
そもそも利用するクレジットカードだって変わることがあるんだからクレジットカード番号は任意で設定できるように設計変更してほしい。
GCEのContainer-Optimized OSでdocker-composeを使えるようにする

# はじめに

GoogleCloudPlatform（GCP)のGoogleComputeEngine(GCE)には、はじめからDockerを扱える環境が整っている`Container-Optimized OS`というものが用意されています。

ただし、デフォルトでは`docker-compose`コマンドが使えないため、使えるようにするための手順を残しておきます。

# 手順

`Container-Optimized OS`のGCEインスタンスを立ち上げ、SSHで接続する。

下記コマンドを実行し、docker-composeのコンテナイメージを実行し、docker-composeをインストールする。
```sh
$ docker run docker/compose:1.26.2 version
```

エイリアスを貼って、省略コマンドで呼び出せるようにする。
```sh
$ echo alias dc="'"'docker run --rm \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v "$PWD:/$PWD" \
    -w="/$PWD" \
    docker/compose:1.26.2'"'" >> ~/.bashrc
$ source ~/.bashrc
$ dc # docker-composeのヘルプが表示されれば完了
```
[実践]Pythonでハッシュ関数を実装しよう！〜公式ドキュメントを参考に〜

# はじめに

今回は**Pythonでハッシュ関数を実装**していこうと思います！

「**ハッシュ関数**」とは、暗号について学んでいるとよく出てくる、「**入力したデータを一見適当に見える値にして返す**」関数です。

ハッシュ関数については以下の記事にわかりやすくまとめているので、ぜひ参考にしてください！

https://chaldene.net/hash

Pythonのドキュメントを参考に実装を進めていきます。

Pythonに限らず、プログラミング関係のドキュメントは非常に読みづらいです。

参考までに以下のPythonのドキュメントを見てみてください。

https://docs.python.org/ja/3/library/hashlib.html

どうでしょうか？

読むのみ抵抗があるくらい細かいですよね？

なのでこの記事ではドキュメントの重要な部分を抜き出してわかりやすく解説していきます！

「**ハッシュ関数を実装してみたい**」

「**Pythonのドキュメント読んだけど実装までできなかった**」

このような人のお役に立てれば幸いです。

前置きは早々に早速みていきましょう！

# hashlib

Pythonでハッシュ関数を実装するには「**hashlib**」というモジュールをインポートする必要があります。

Pythonファイルを作成して、一番上に以下のコードを貼り付けてください。

```python
import hashlib
```

これでインポートできました！

# hashlibの基本的な使い方

まずは「**hashlib**」関数の基本的な使い方からみていきましょう。

## 基本

```python
word = "かるでね"
word2 = "cardene"

# sha256
sha256 = hashlib.sha256()

# updateするたびにたされていく
sha256.update(word.encode()) # かるでね
sha256.update(word2.encode()) # かるでねcardene

print(f"sha256に渡されたダイジェスト値を確認: {sha256.digest()}")
# sha256に渡されたダイジェスト値を確認: b'*u\xb7\xef\xe1\xcc\xd1\x00t\xbe\x9e\xc0E\xb8@g\xee\xd7\xb0\xa0\x02AG\x16WW\xb0\xf7\x1d\xa1Z\x9a'
```

１つ１つ確認していきます。

```python
word = "かるでね"
word2 = "cardene"
```

まずはハッシュ関数に通す変数を２つ用意しています。

```python
# sha256
sha256 = hashlib.sha256()
```

ここでは使用する**ハッシュアルゴリズム**を指定しています。

今回は「**sha256**」という**ハッシュアルゴリズム**を使用していきます。

```python
# updateするたびにたされていく
sha256.update(word.encode()) # かるでね
sha256.update(word2.encode()) # かるでねcardene
```

ここでは文字列をバイト文字列に変換して先ほどの**ハッシュアルゴリズム**に渡しています。

```python
変数.encode()
```

このようにすることでバイト文字列に変換できます。

**ハッシュ関数**に通すにはバイト文字列に変換する必要があるので忘れないようにしましょう。

ちなみに以下のような書き方でもバイト文字列に変換できます。

```python
b"文字列"
```

詳しく知りたい方は以下の本を読むか、自分で調べてみてください！

```python
print(f"sha256に渡されたダイジェスト値を確認: {sha256.digest()}")
```

最後に**ハッシュ関数**の出力を確認していきましょう。

「**digest()**」とすると「**ダイジェスト値**」を出力してくれます。

:::note info
ダイジェスト値 = ハッシュ関数により求められた値。
:::

```python
# sha256に渡されたダイジェスト値を確認: b'*u\xb7\xef\xe1\xcc\xd1\x00t\xbe\x9e\xc0E\xb8@g\xee\xd7\xb0\xa0\x02AG\x16WW\xb0\xf7\x1d\xa1Z\x9a'
```

訳わからないですね。

以下のようにすると読みやすくなります。

```python
print(sha256.hexdigest())
# 2a75b7efe1ccd10074be9ec045b84067eed7b0a0024147165757b0f71da15a9a
```

読みやすくなったとはいえさっぱりわからない英数字が並んでいますね。

これが**ハッシュ値**となります。

## 短く書く

コードが何行にも渡ってしまい少し長くなってしまいましたね。

実はもっと短く書く方法があるのでみていきましょう。

```python
sha256_word = hashlib.sha256(word.encode()).hexdigest()

print(f"ハッシュ関数[sha256]に通した結果（16進形式文字列で表示）: {sha256_word}")
# ハッシュ関数（sha256）に通した結果: 3eb903c1a5d61e64e5d9de548763c133db857bfeb4c6fa1ac4f046bf
```

たった１行で済んでいますね。

こちらの方が使い勝手が良さそうですよね。

# 続き

これより先は以下の記事にまとめています。

https://chaldene.net/hash-python

より詳しく**ハッシュ関数**について学ぶことができるので、興味がある方はぜひ！
（もちろん無料です！）
スレッドセーフでないSimpleDateFormatの動き

# はじめに

※別のブログに投稿していた記事をQiitaに投稿し直しています。（元の記事は削除予定）

SimpleDateFormatはAPI仕様にこのような記載がある。

> 日付フォーマットは同期化されません。
スレッドごとに別のフォーマット・インスタンスを作成することをお薦めします。
複数のスレッドがフォーマットに並行してアクセスする場合は、外部的に同期化する必要があります。

スレッドセーフでないことは分かるが、どのような動きになるか分からないので試してみる。

# 結論から

API仕様に記載されている通りスレッドごとにインスタンスを作成するか、
Java 8 以降であればDateTimeFormatterを使用する。

# スレッドセーフでないバージョン

staticなフォーマッタ

```java
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
```

複数のスレッドを起動する

```java
Consumer<Date> c = d -> notThreadSafe(d);
ExecutorService e = Executors.newCachedThreadPool();
e.execute(() -> {c.accept(createDate(2019, 1, 1));});
e.execute(() -> {c.accept(createDate(2020, 2, 2));});
e.shutdown();
```

スレッド処理の中身

```java
private static void notThreadSafe(Date d) {
	for (int i = 0; i < 10000; i++) {
		System.out.println(sdf.format(d));
	}
}
```

実行結果（ソートして重複除去）

```
2019-01-01
2019-01-02
2019-02-01
2019-02-02
2020-01-01
2020-02-01
2020-02-02
```

本番環境で発生すると、迷宮入りしそうな現象・・・orz

# スレッドセーフなバージョン

staticなフォーマッタ

```java
private static DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
```

複数のスレッドを起動する

```java
Consumer<Date> c = d -> threadSafe(d);
ExecutorService e = Executors.newCachedThreadPool();
e.execute(() -> {c.accept(createDate(2019, 1, 1));});
e.execute(() -> {c.accept(createDate(2020, 2, 2));});
e.shutdown();
```

スレッド処理の中身

```java
private static void threadSafe(Date d) {
	for (int i = 0; i < 10000; i++) {
		LocalDate ld = LocalDate.ofInstant(d.toInstant(), ZoneId.systemDefault());
		System.out.println(ld.format(dtf));
	}
}
```

実行結果

```
2019-01-01
2020-02-02
```

# ソースコードの全文

```java
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.function.Consumer;

public class FormatterTest {

	private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
	private static DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");

	public static void main(String[] args) {
		// Consumer<Date> c = d -> notThreadSafe(d); // スレッドセーフでないバージョン
		// Consumer<Date> c = d -> threadSafe(d); // スレッドセーフなバージョン
		ExecutorService e = Executors.newCachedThreadPool();
		e.execute(() -> {c.accept(createDate(2019, 1, 1));});
		e.execute(() -> {c.accept(createDate(2020, 2, 2));});
		e.shutdown();
	}

	private static Date createDate(int year, int month, int dayOfMonth) {
		LocalDate ld = LocalDate.of(year, month, dayOfMonth);
		ZonedDateTime zdt = ZonedDateTime.of(ld.atTime(LocalTime.MIN), ZoneId.systemDefault());
		Date d = Date.from(zdt.toInstant());
		return d;
	}

	private static void notThreadSafe(Date d) {
		for (int i = 0; i < 10000; i++) {
			System.out.println(sdf.format(d));
		}
	}

	private static void threadSafe(Date d) {
		for (int i = 0; i < 10000; i++) {
			LocalDate ld = LocalDate.ofInstant(d.toInstant(), ZoneId.systemDefault());
			System.out.println(ld.format(dtf));
		}
	}
}
```
整数数学A「2022年一橋大学後期第1問　log y (6x+y)=x」をWolframAlphaとsympy でやってみた。



オリジナル
探しています。

# 問題と解答

logの絡んだ整数問題です。＜

https://stchopin.hatenablog.com/entry/2022/03/16/205839


# wolframalphaで

https://www.wolframalpha.com/input?i=log++%28y%2C6*x%2By%29%3Dx

Integer solutions
x = 2, y = 4
x = 5, y = 2


# wolframalphaのover the integersで結果がでませんでした。

https://www.wolframalpha.com/input?i=log+%286*x%2By%2Cy%29%3Dx+over+the+integers

Try the following:
Use different phrasing or notations
Enter whole words instead of abbreviations
Avoid mixing mathematical and other notations
Check your spelling
Give your input in English
Other tips for using Wolfram|Alpha



# SymPy Liveで(Pycharmでも)

以下サイトに、ソースコードを貼り付けて、Evaluateです。

https://live.sympy.org/

問題点:nMaxに根拠をつけたい。答えを見てから投稿しました。


```python
# log y (6x+y)=x
from sympy import *
nMax=100
for i in range(1,nMax):
    for j in range(1,nMax):
        if log(6*i+j,j) ==i:
            print("#",i,j)
# 2 4
# 5 2
```

https://note.nkmk.me/python-int-max-value/


# 感想
Effective Java 第3版まとめ（項目7）

# 項目7.使われなくなったオブジェクト参照を取り除く

## 書かれている内容

* メモリ管理については考える必要がないという印象を持ってしまいがちだが、それは間違い
* オブジェクト参照にnullを設定することは、普通というよりむしろ例外であるべき
* クラスが独自のメモリを管理しているときには、メモリリークに対して注意を払うべき
（要素が解放されるときには、すべてのオブジェクト参照にnullを設定すべき）
* キャッシュもメモリリークのよくある原因
* リスナーやコールバックもメモリリークのよくある原因
【Golang】8 バイト長の []byte を uint64 に変換する（ 64ビット長のバイト・スライスをintに変換したい）

> Go 言語（以下 Golang）で、`make([]byte, 8, 8)` で作成した 8 バイト長のスライスを <ruby>uint64<rt>符号なしint</rt></ruby> に変換したい。

[「`golang "[]byte" uint64 変換`」でググって](https://www.google.com/search?q=golang+cap%E4%BB%98%E3%81%8D+%22%5B%5Dbyte%22+%E7%B5%90%E5%90%88+%E9%80%A3%E7%B5%90)も、逆の `uint64` から `[]byte` に変換するものや、`int32` の<ruby>リトルエンディアン<rt>後ろ詰め方式</rt></ruby> だったり、符号あり前提のものばかりだったので、自分のググラビリティとして。

## TL; DR <sub><sup><sub><sup>（今北産業）</sup></sub></sup></sub>

- `encoding/binary` の Golang 標準パッケージを使う
- `binary.BigEndian.Uint64` 関数を使う
- 使い方: `myUint64 := binary.BigEndian.Uint64(myByteSlice)`

    ```go
	my8byte := []byte{255, 0, 255, 0, 255, 0, 255, 0}
	myUint64 := binary.BigEndian.Uint64(my8byte)

	fmt.Printf(
		"Type: %T\nHex : %x\nDec : %d\nBin : %064b\n\n",
		myUint64,
		myUint64,
		myUint64,
		myUint64,
	)
	// Output:
	// Type: uint64
	// Hex : ff00ff00ff00ff00
	// Dec : 18374966859414961920
	// Bin : 1111111100000000111111110000000011111111000000001111111100000000

	// 4 バイト長なら Uint32
	my4byte := []byte{255, 0, 255, 0}
	myUint32 := binary.BigEndian.Uint32(my4byte)

	fmt.Printf(
		"Type: %T\nHex : %x\nDec : %d\nBin : %032b\n\n",
		myUint32,
		myUint32,
		myUint32,
		myUint32,
	)
	// Output:
	// Type: uint32
	// Hex : ff00ff00
	// Dec : 4278255360
	// Bin : 11111111000000001111111100000000
	```

    - [オンラインで動作を見る](https://go.dev/play/p/Za8iKisLgOw) @ Go Playground

## TS; DR <sub><sup>`cap` 付き `[]byte` スライスの結合・連結からの UINT64</sup></sub>

2 つの 4 バイト長のデータを結合したかったのです。しかも `append` を使わないで。

具体的には `byte` スライス（`[]byte`）をブツ切りにして、データをゴニョゴニョした 4 バイト長のデータを 2 つ作成し、1 つの<ruby>`len = 8`<rt>要素数 8</rt></ruby> のスライスに結合したものを `uint64` に変換したかったのです。

この時、<ruby>`cap` 付き<rt>領域予約済み</rt></ruby>でイジッているのと、なるべく<ruby>リアロケート<rt>領域を再確保</rt></ruby>させたくなかったのです。そのため `append` を使いたくなかったのです。

誰に需要があるのかわかりませんが、以下は 4 バイト長の 2 つのスライス を結合した、8 バイト・スライスを `uint64` に変換する例です。

```go
package main

import (
	"encoding/binary"
	"fmt"
)

func main() {
	a8 := []byte{49, 50, 51, 52} // ゴニョゴニョ済みの 4 バイトデータ
	b8 := []byte{65, 66, 67, 68} // ゴニョゴニョ済みの 4 バイトデータ

	var v = make([]byte, 8, 8) // なぜか 8 バイト cap で宣言されている変数

	copy(v, a8)     // 前半にコピー
	copy(v[4:], b8) // 後半にコピー

	fmt.Printf(
		"v = Len: %d\nCap: %d\nString: \"%s\"\nData: %d\n",
		len(v),
		cap(v),
		string(v),
		binary.BigEndian.Uint64(v), // ここがポイント
	)
	//
	// Output:
	// v = Len: 8
	// Cap: 8
	// String: "1234ABCD"
	// Data: 3544952156220179268
}
```

- [オンラインで動作を見る](https://go.dev/play/p/TxRmWMwaDMI) @ Go Playground

## 参考文献

- [Converting variable-sized []byte to int64 in Golang](https://stackoverflow.com/a/54497492/18152508) @ Stackoverflow
複数種のSNPを含むvcfファイルの分割方法[備忘録]

GATKを用いて複数種に対してSNP callingすると、1つのvcfファイルに複数種のSNPが記される。
例えば、種間でSNPを比較したいときには、GATKやbcftoolsで比較するが、その際に比較したいvcfファイルはそれぞれ分割されている必要がある。そこで、以下のスクリプトにより複数種のSNP情報を含むvcfファイルを分割した。

```
$ for sample in `bcftools query -l merged_snps_filtered.vcf.gz`
  do
  bcftools view -c1 -Oz -s $sample -o　$sample.vcf.gz　merged_snps_filtered.vcf.gz
  done
```
bcftools: ver. 1.14を使用。

　
　


2023年3月17日追記
コードを修正しました。

また、分割後は以下のvcftoolsを用いたスクリプトにより、vcfファイルをまとめることが可能。

```
vcf-merge sample1.vcf.gz sample2.vcf.gz sample3.vcf.gz | bgzip -c > output.vcf.gz
```
BlenderでアニメーションをWebpで保存する

## 概要

Blender3.1で、アニメーションを[Webp](https://ja.wikipedia.org/wiki/WebP)で保存するアドオンをPythonで作成したので紹介します。

## やり方

### アドオンのインストール

- [Blender Add-on: MakeWebp](https://github.com/SaitoTsutomu/MakeWebp)の画面にしたがってインストールしてください。
    - アドオンのチェックでは「テスト中」を選んでください。

### Pillowのインストール

本アドオンは、Pillowを利用しています。
そのため、下記のように、コマンドラインでBlenderにPillowをインストールする必要があります。コマンドラインからBlenderを操作する方法については、「[Blenderのコマンドサンプル](https://qiita.com/SaitoTsutomu/items/6b70367455f843a979b1)」も参考にしてください。

- macOSの場合
```
/Applications/Blender.app/Contents/Resources/3.1/python/bin/python3.10 -m pip install Pillow
```

- Windowsの場合
```
"C:\Program Files\Blender Foundation\Blender 3.1\3.1\python\bin\python" -m pip install Pillow
```

※ Windowsで、インストールできるのに`import`で**エラーになる場合**は、一旦アンインストールしてから、**管理者権限のコマンドプロンプトでインストール**し直すとうまくいくかもしれません。

### 作成

- オブジェクトメニューの`Make Webp`を選んでください。
- 出力フォルダに`webp.webp`という名前で出力されます。

### Pythonのコード

https://github.com/SaitoTsutomu/MakeWebp/blob/main/__init__.py

下記のように、複数の画像ファイルをimgsに入れておけば、PillowではWebpファイルを簡単に作成できます。

```py
imgs[0].save(
    Path(pre_filepath) / "webp.webp",
    save_all=True,
    append_images=imgs[1:],
)
```

以上
【Deno】OakのRouterContext<R, P, S>でエラーになる時の対処法

 【エラーメッセージ】
```TS2707 [ERROR]: Generic type 'RouterContext<R, P, S>' requires between 1 and 3 type arguments.```

Deno や TypeScript が日々進化していることが理由なのか、ネットで拾ったコードが大体このエラーになる。ジェネリクスの引数を渡さないまま使っていることが原因。

### 解決策✨
インポート文を修正して、RouterContextを上書きで定義する

```修正前.ts
import { Application, Router, RouterContext } from "https://deno.land/x/oak/mod.ts";
```

↓

```修正後.ts
import { Application, Router } from "https://deno.land/x/oak/mod.ts";
import type { RouterContext as XContext } from "https://deno.land/x/oak/mod.ts";
type RouterContext = XContext<any, any, any>;
```

すると、それ以降のコードはそのまま使えるようになる。
any 型を使いたくない人はもう少し工夫が必要になるけど、とりあえず動くところまで。
mysqlコマンド


```bash
パス初期化
sudo mysql_secure_installation

権限付与
grant select on *.* to 'user名'@'localhost';

ユーザー作成
create user 'user'@'localhost' IDENTIFIED BY 'pass';

全権限付与
grant all on *.* to user名@localhost;

ユーザー一覧の確認
select user, host from mysql.user;

データベースに接続(上記コマンド入力後にパスワードを入力)
sudo mysql -u root -p

データベース作成
create database データベース名;

データベースに権限を付与（ユーザー名：dbuser、サーバ：localhost）
grant all on （データベース名）.* to 'user'@'localhost' identified by 'パスワード';

使うデータベースを切り替える
use database名;

現在のデータベースを確認
mysql>select database();

データベースの中身（一覧）を確認
mysql>show database;

データベースを削除
mysql>drop database larabook;


テーブルを確認する
mysql>show tables;


テーブルの作成(CREATE)
create table [テーブル名] (
    column [データ型] [その他オプション],
    column2 [データ型] [その他オプション],
    column3 [データ型] [その他オプション],
);

```


```

表示用の列名は省略可能
select * from mebers;

列名で四則演算(+, -, *, /)ができる。
select price * 1.08 from price;

重複を排除して選択(DISTINCT)
select distinct 列名 from mebers;

条件指定して抜き出す(WHERE)
select 列名 from mebers where 条件式;

例
select * 
from user
where
   ID = 1
   OR ID = 3
   OR ID = 5


select *
from user
where 年齢 >= 30 OR 出身地 = "九州"

#東京都と千葉県と埼玉県のみ検索
select * from board_member
where prefecture in ('東京都','埼玉県','千葉県');


よく使う条件指定。
値 --2つの値の間に含む

列名 is between 値 and 
列名 is in (値, 値, ...) --列挙した中のどれかと一致する
列名 is null --空欄を選択
列名 is not null --空欄以外を選択
等

ソート(order by)
order 列名 --昇順でソート(並び替え)
order by)列名 DESC --降順でソート(並び替え)

```

データの挿入(INSERT)

```

#行をテーブルの一番下に挿入する
insert into mebers values (値, 値); 

#列名を指定して行を挿入
insert into mebers (列名, 列名, ...) values (値, 値); 

#データの変更(update) --条件と一致する列の値を更新する
update mebers set 列名 = 値 where 条件式;

#データの削除(delete)--条件と一致する行を削除する
delete from mebers where 条件式; 

```

#削除

```

drop colum 列名;

#制約を追加
add 制約名;

#制約を削除
drop 制約名; 

テーブルの削除(drop)
drop table テーブル名;

```
ファイル操作コマンド


```
ls
lsはlistの略です。
lsコマンドでは、カレントディレクトリにあるファイルやフォルダの名前一覧を出してくれます。

Pro:~ username$ ls

Applications        Google ドライブ     Public          pitchshiftLogFile.txt   workspace
BackgroundMusic     Library         SHOW            projects
Desktop         Movies          bash_profile        rbenv
Documents       Music           dump.sql        reset.sql
Downloads       Pictures        evalonly.txt        ruby
cp
cpコマンドはcopyの略で、そのままファイルをコピーするコマンドです。

下記コマンドで同じディレクトリにコピーファイルを作成します。

Pro:blog username$ 
cp scope.rb scope1.rb
                          <!--cp [コピー元] [コピー先] で表します-->
mv file.txt
ファイルの移動、およびリネームを行います。

mv scope.rb /Users/kouyamaakira/projects/ruby
<!--mv [移動させたいもの] [移動先]-->

 mv scope.rb rename.rb
 <!--mv [元のファイル] [新しいファイル名]-->

ファイルを削除するコマンドです
rm kesu.rb
 <!--rm [消したいファイル名]-->


新規にディレクトリ（フォルダ）を作成するコマンドです。(mkdir)
mkdir make


こんなかんじ、ファイルの内容を表示できるコマンドです。
サーバーをつなげたときに、エラーを見たいときなんかによく使います。(cat)
cat cat1.rb

2つのファイルを結合して中身を見ることもできます。(cat)
公開鍵の更新によく見かけるのは上記の理由でもあるのです。
cat cat1.rb cat2.rb


適切に編集できているかを確認するためにdiffコマンドで比較します。(diff)

# diff /etc/php.ini /etc/php.ini.old
1357c1357
< session.save_path = "/var/lib/php/session"
---
> ;session.save_path = "/tmp"


ファイルの終わり部分を表示するコマンドです。(tail)
オプションをつけずに実行すると終わりから10行表示されます。
これもエラーデバッグなんかで使われます。
tail scope.rb

以上です。

```
【ScrapeStorm】Github VS Gitlab 両者の区別を簡単紹介

元記事：https://jp.scrapestorm.com/tutorial/scrapestorm-github-vs-gitlab-a-brief-introduction-to-the-distinction-between-the-two/
## GitHubとは？
　GitHubという言葉を分解すると、git（ギット）のhub（ハブ）。日本語で「拠点」の「集まり」と訳すことができます。世界最大のコード管理プラットフォームと言えます。開発者はGitHhubで交流と学習できます。
2008年2月、Chris Wanstrath、PJ Hyett、Tom Preston-Werner、Scott ChaconはRuby on Railsを使用してGitHubを開発しました。最初の分散バージョン管理システムであったため、GitHubはその後、多くのオープンソースコードのリポジトリに発展されました。
## GitLabとは？
　GitLabは先進的なソフトウェア開発に必要な多くの機能を統合した製品です。単一のアプリケーションでソフトウェアを開発、保護、操作する能力を備えています。開発者DmitriyZaporozhetsとSytseSijbrandijによって2011年に開発されたGitLabは今約3000万人のユーザーがおり、そのうち100万人のアクティブユーザーがいます。
　当初は、ソースコード管理プラットフォームとしてソフトウェア開発チーム内で協力するために使用されていたが、その後、ソフトウェア開発ライフサイクル、さらにはDevOpsライフサイクル全体にわたるプラットフォームに発展した。
![代替テキスト](https://jp.scrapestorm.com/wp-content/uploads/2022/03/code-g12674fa13_1920.jpg)
## GitHub VS GitLab
　ある程度、GitHubとGitLabはよく似ています。どちらもLinux上で実行され、問題トレーサが付いており、サードパーティ製の統合ツールとインポートツールが多数用意されています。
　どちらもオープンソースをサポートしていますが、リポジトリは異なるプログラミングモデルを使用しています。GitLabはコア業務を開放しており、無料のコミュニティ版とオープンソースを維持しています。もちろん、企業版はより多くの機能を持っています。また、GitHubの場合、そのコードには多くのオープンソースコードが含まれていますが、オープンソースプロジェクトではありません。
　ただし、どちらもWebベースのリポジトリを提供しており、オープンソースでGitベースのコード管理が可能であり、リモートリポジトリのローカルファイル変更をサポートしています。
　これに加えて、2018年10月26日にマイクロソフトが75億ドルで買収したため、多くの人がGitHubを放棄することを選択しました。一部の人々にとって、マイクロソフトがオープンソースソフトウェアの開発をサポートしているとしても、マイクロソフトは常に「悪役」になります。しかし現実には、GitHubをあきらめてGitLabを選択する人は多くありません。
　GitHubは、新しいブランチとマスターブランチのマージもサポートしています。 このようにして、ユーザーは問題が発生した場合に迅速に展開し、以前のバージョンに戻すことができます。GitLabでは、ユーザーはマスターブランチの外部に複数の安定したブランチを作成できますが、これは、ユーザーがマージするときに複数のテストと複数のコード審査を行う必要があることを意味します。
　また、GitLabは、完全なDevOpsプラットフォームである完全なソフトウェア開発ソリューションを提供します。 GitLabは、Jira、Microsoft Teams、Slack、Gmailなどの多くのサードパーティプログラムおよびプラットフォームと統合できます。
![代替テキスト](https://jp.scrapestorm.com/wp-content/uploads/2022/03/laptop-g85e68b7fc_1920.jpg)
## まとめ
　個人または小規模チームの場合、GitHubとGitLabは、無限のパブリックライブラリとプライベートライブラリを含む無料バージョンを提供します。しかし、大手インターネット会社であれば、無料バージョンの機能は明らかに不足しており、会社は異なるニーズに対応して選択することができます。