OmniAICreator/Qiita-1.07M huggingface dataset:
HTTPヘッダーインジェクション メモ

* Webアプリの脆弱性を利用した攻撃手法の一つであるHTTPヘッダーインジェクションについてメモする。
## 概要

* フォームやURLで入力するリクエストパラメータやクエリパラメータを、想定しないデータに改変して送信し、HTTP レスポンスヘッダに新たなヘッダ要素を追加したり、レスポンスボディに任意の文字列を追加する攻撃

* 例：改行コードによる任意のヘッダー設定

  * HTTPリクエスト

    ```http
    http://example.com/account/aaa?redirect_url=http://example.com/account/login%0D%0ASet-Cookie:+SSO_ID=XYZ123
    ```

  * HTTPレスポンス

    ```http
    HTTP/1.1 302 Found
    Date: Sun, 18 Jun 2021 21:34:35 GMT
    Location: http://example.com/account/login
    Set-Cookie: SSO_ID=XYZ123
    ```

    ※改行コード(%0D%0A）により、以降の文字列を次の要素として扱われてしまい、Set-Cookieヘッダが有効になる。

  ![http_header_injection.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586535/48f020e4-72e5-5093-cdf9-0e3121805d5c.png)


## 想定される脅威

* 利用者のブラウザ上での偽情報を表示、任意のスクリプト埋め込み
* 任意のCookie発行※セッションIDの固定

## 対応策

* 外部からのパラメータをそのまま使用しない、HTTPレスポンスヘッダに出力しない実装/ライブラリ使用を行う。
  * 使用する場合は、エスケープなどを行う。

## 参考情報

* [安全なウェブサイトの作り方 - 1.7 HTTPヘッダ・インジェクション](https://www.ipa.go.jp/security/vuln/websecurity-HTML-1_7.html)
コード短く簡単に「画像をとことこ歩かせる」コピペ可

# はじめに

![トコトコアニメ.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1096105/ae1d349f-60bc-7520-3370-34c243dfd9b9.gif)

こんな風に画像を「とことこ歩かせるアニメーション」を、HTMLとjQueryとjRumbleというプラグインを使って実装します！
名前だけ見ると難しそうですが、コードは短くコピペでも動くので試してみてください!


## jQueryとjRumbleの読み込み
HTMLファイルのheadタグの中に下記のCDNをコピペで貼り付けてください。

```
<script src="js/jquery-2.1.3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jrumble/1.3.0/jquery.jrumble.min.js"
 integrity="sha512-0vcUK0oQ15FtIrg1bbNL6zO2yB0pSZjPZERBNA0ZXIw/7jsSHu+rxxbpbM20wIaiEofTK9oPoP/Y8xvh3qoasQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
```
## 実際のコード
まずコードを貼りますのでここまでのコピペだけで動きます！
下記のコードをHTMLに記述してもらえれば動くと思います!
画像はお好きなものに変えてください。

少し解説見たいよって方は是非読み進めてみてください!
```
<body>

<img src="./アイス.png" id="img">

<script>

//画像の横移動
$("#img").animate({ marginLeft: "100%", }, 4000, "linear", function () {
	$("#img").animate({ marginLeft: "0%" }, 4000,"linear", function() {
    $("#img").animate({ marginLeft: "100%" }, 4000,"linear")
  })
});

//画像をブルブル震わせる
$("#img").jrumble({
  x: 0,
  y: 0,
  rotation: 5,
  speed: 100
});
$("#img").trigger('startRumble')

</script>
</body>
```
## 【解説】　横移動とブルブル震わせる動き　を組み合わせる

### 横移動
jQueryの animate() を使います!
今回はmarginleftの値を変更していく事で、移動しているように見せています!

```marginLeft: "100%"```　　
↑ここの数値を変える事で移動範囲の変更ができます。(左端が0%、画面の右端が100% なので止めたい所を探ってみてください)

```4000,```  
↑ここの数値を変える事で、移動スピードを変えることができます。(数値が小さいほど早くなる)

行を増やすごとにループ数も増やせます!

```javascript
//画像の横移動
$("#img").animate({ marginLeft: "100%", }, 4000, "linear", function () {  //初期位置から右端に移動
	$("#img").animate({ marginLeft: "0%" }, 4000,"linear", function() { //右端から左端に移動
    $("#img").animate({ marginLeft: "100%" }, 4000,"linear")  //左端から右端に移動
  })
});
```

### ブルブル震わせる
jRumbleというプラグインを使って震わせます!
このプラグインで色々な震わせ方ができますが、今回は使っている物だけ紹介します!

下記で動きの設定をしています。今回は揺れの少ない動きにしています。
```javascript
$("#img").jrumble({
  x: 0,
  y: 0,
  rotation: 5,
  speed: 100
});
```
下記で動きのスタートタイミングとストップのタイミングを設定します。
今回は常に動いている設定にしています!

```javascript
$("#img").trigger('startRumble')
```

## まとめ
今回のアニメーション、ググってもあまり似たもの出てこなかったので書いてみました!
jRumbleの動きを変えたい方は、
https://jackrugile.com/jrumble/
上記の公式サイトの「Usage」という所に他のパターンが載っているので、ぜひ試してみてください!
minttyの表示色を設定

# 色が暗い
Windows環境にGitをインストールしたらので、Minttyというターミナルが入っていたので、使って見たら全体的に色が暗い。なのでその設定方法を書いておく。

# 色の変更方法
TeraTermでも色が気になったとき、変更できなくて困った時があった。その時の経験を生かしANSIカラー設定を探していると、たどり着いたのがこれ。ユーザの直下にできている .minttyrcというやつ。
ここを変更すればいいらしい。
必要なものだけ、付け加えればそこそこの色になるはず。

~~~ ~/.minttyrc これだけでも発色は変わるかも
White=255,255,255
BoldWhite=255,255,255
ForegroundColour=255,255,255
~~~

~~~ ~/.minttyrc 全体
Black=0,0,0
Red=255,100,0
Green=183,234,17
Yellow=234,206,28
Blue=107,155,219
Magenta=237,157,185
Cyan=0,191,191
White=255,255,255
BoldBlack=64,64,64
BoldRed=255,100,0
BoldGreen=183,234,17
BoldYellow=234,206,28
BoldBlue=107,155,219
BoldMagenta=237,157,185
BoldCyan=64,255,255
BoldWhite=255,255,25
~~~

# その他設定変更方法
ターミナル内で`右クリック`で色々な設定が出来る。
python flaskアプリ作成とPOSTリクエスト

Flaskの初歩的な使い方を学んだので、備忘録として記録致します。

# Flaskとは？
 pythonのWebアプリケーションフレームワークで、簡単なwebアプリケーションを作ることに適しています。Flaskの設計思想として「コアとなる機能を保ちつつ、拡張性を持っているフレームワーク」があるそうです。

##### インストール方法
　`pip install flask`


# まずはHello Flask
 ```python:flask_test1.py
 from flask import *

app = Flask(__name__)

@app.route("/")
def index():
    return jsonify({"ans": "Hello Flask!"})
```

ローカルにアクセスすると下記の結果が返ってくる
　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342722/ee08fe4f-cd5f-673b-400a-0016c39fda41.png)


# POSTリクエストでJSONをやりとり
　スイッチのON or OFF をjsonにてPOSTしてその結果を返してくれるAPIを作成します。

 ```python:flask_testjson.py
 from flask import *

app = Flask(__name__)

@app.route('/', methods=['POST'])
def switch():
    switch = request.data.decode('utf-8')  # デコード
    switch = json.loads(switch)
    if switch["set"] == "ON":
        switch_ans = "switch_ON"
    elif switch["set"] == "OFF":
        switch_ans = "switch_OFF"
    else:
        switch_ans = "None"
    return jsonify(switch_ans)
```

送信するJSON
　`{"set": "ON"}`か`{"set": "OFF"}` それ以外は `None` が返ってくるようにします。

## POSTリクエスト
いくつか方法はあると思うのですが、pythonのライブラリのrequestを使用してみたいと思います。
 ```python:flask_post.py
import requests
import json
post_url = "http://127.0.0.1:8888/" #自分のアドレスを入力
json = {"set": "ON"} #条件を入力
#POST送信
response = requests.post(
                    post_url,
                    json = json,
                    )
print(response.json())
```

その他コマンドプロンプトにてもPOSTリクエストが可能です。
[HTTPのPOST/GETリクエストをする](https://viral-community.com/security/curl-8263/)

# 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342722/3b8e6fa5-0fca-1426-8a2f-d9f37da09e0b.png)
【Typescript】一部のプロパティの型を上書きする関数

# はじめに
ある日、こんなことが起こった。
サーバーサイドから送られてくるオブジェクトの一部のプロパティがstringの時とnumberの時があるやん。。

# 例
```typescript
const user = {
  id: 1,
  name: 'james',
  age: 20,
}

const user = {
  id: 1,
  name: 'mike',
  age: '20'
}
```
例では`age`プロパティが`number`の時と`string`の時があり、「これどちらかに揃えてくれよ〜〜」と思ったがサーバーサイドの方曰く、何かしらの理由でしょうがないらしい。。
普段typescriptで開発しているし、ageがstringの時とnumberの時でそれぞれ型を定義するのは良くないから、どうしようと思った時の対処法を考えてみた。

# 案①　それぞれ型を作成する
これは普通に良くない。

```typescript
type User = {
  id: number;
  name: string;
  age: number;
}

type User2 = {
  id: number;
  name: string;
  age: string;
}
```

# 案② Omitを使う
- 冗長
- `age: string`の部分は実質なんでも追加できるため、ageをタイポしてもわからない
- 他にも上書きしたい時が出てきたらまた作成しないといけない。

```typescript
type User = {
  id: number;
  name: string;
  age: number;
}

type OmitUser = Omit<User, 'age'> & {
  ag: string // タイポしてもわからない
}

const user: OmitUser = {
  id: 1,
  name: 'mike',
  age: '20' // ここで初めてタイポしてることに気づく
}
```

# 結論
ジェネリックス + Omitで型関数を作成してみた。
ぱっと見てわかりやすい！！

```typescript
type Overwrite<T, U extends { [Key in keyof T]?: unknown }> = Omit<
  T,
  keyof U
> & U;

const user2:Overwrite<User, {age: string}> = {
  id: 1,
  name: 'mike',
  age: '20'
}

const user3:Overwrite<User, {age: string[]}> = {
  id: 1,
  name: 'mike',
  age: ['20', '21'] // ageが配列になることはありえないけど、例として作成してます。
}

```

# 解説
上書きする関数を**ジェネリックス**と**Omit**で定義しています。
ここでは`T`に`User型`が入り、`U`には変換したいプロパティと変換したい型を定義しています。
`extends`を使用し、`keyof T` つまり`User型(T)のキー`のみを受け入れるように制限しています。
そして、Omitで指定した`T(User型のキー)`から`keyof U(ageプロパティ)`を削除し、新たに
`U（age: string）`を追加しているといった感じですね。
これで一部のプロパティの型を上書きする関数を作成できました。

```typescript
type Overwrite<T, U extends { [Key in keyof T]?: unknown }> = Omit<
  T,
  keyof U
> & U;

Overwrite<User, {age: string}> // タイポするとエラー出ます。

```

# おわりに
共通の処理をジェネリックス等を使用してまとめた関数を作成するとtypescript見習いから
初心者になれた気がします。
Gitの使い方備忘録（Windows）初期設定編

# はじめに
今更ながらgitを使い始めたが、忘れやすので必要なものを書いておく。

# 使用環境
OS: Windows7 Professional
Tool:Git 
Terminal:Mintty

# Gitって
出遅れたので、今さら説明するのも何なので、詳細は割愛。
分散型バージョン管理システムというものらしい。
CVSとの違いは、ざっくりと言うと集中型か分散型かの違い。つまりコミット先がローカルにあるから、コミット（チェックイン）できるよってことかなぁ。


# 初期設定
#### 必要に応じて
まずは何はともあれ、やってみよう！ということで初期設定。
コマンド実行後どうやらエディタに引き渡されて編集することがあるらしいので、エディタを設定しておいた方が良さそう。
`.gitconfig` は直に修正しても良いし、コマンドを実行すると登録されるのでそれでも良い。
最終的にこうなっていれば大丈夫。

#### いつものがいいって人はこっち。例は秀丸
~~~ ~/.bash_profile
export GIT_EDITOR="'/C/Program Files/hidemaru/hidemaru.exe' //fu8"
export EDITOR=
~~~


#### やっぱりコマンドといったらVimがいいって言う人にはこっち。
~~~ ~/.gitconfig
[core]
editor='C:/Git/usr/bin/vim.exe'
~~~

#### コマンドで設定する場合
~~~diff
+ 成功: git config --global core.editor 'C:/Git/usr/bin/vim.exe'　
  ポイントは、フルパスで書くこと！
- 失敗: git config --global core.editor 'vim -c "se fenc=utf-8"'
　※理由不明。vimの初期設定でUTF-8起動するようになっているから、そもそもUTF-8の設定は不要かも。
~~~

# その他設定
~~~ config
[user]※コミットしたときの名前になる
  name = 名前
  email = aaa@aaa.com

[core]
  ignorecase = false　# ファイル名の大文字小文字を区別するように
  autocrlf = false   # 改行コードを自動で変更しない
  safecrlf = true    # 改行コードの混在を許可しない

[color]※色が変わる？
  ui     = auto
　diff   = auto
　status = auto
　branch = auto

[include]
  path = gitarea/gitalias.config # gitのalias記載するファイル

[diff]
  tool = WinMerge

[difftool "WinMerge"]
  path = c:/tools/WinMerge/WinMergeU.exe
  cmd = ¥"/c/tools/WinMerge/WinMergeU.exe¥" -r -e -u "$LOCAL" "$REMOTE"

[merge]
  tool = WinMerge

[mergetool "WinMerge"]
  path = c:/tools/WinMerge/WinMergeU.exe
  cmd = ¥"/c/tools/WinMerge/WinMergeU.exe¥" -r -e -u "$LOCAL" "$REMOTE" "$MERGED"

[alias]
  windiff = difftool -y -d -t WinMerge
  winmerge = mergetool -y -t WinMerge
~~~

# 設定したConfigの確認
~~~
git config --list
~~~

# 直接修正したい場合
ホーム直下に`.gitconfig`があるので、直接エディタで開いて編集する。
※globalの場合


# それでもエディタの挙動がおかしい場合
- パスの確認
- 設定ツール確認

上記ならば、エディタがそのパスに存在し起動出来る事の確認とか、vimとは別にviが別に存在しないこととか確認したらどうかなぁ。

## 失敗したときのエラーメッセージ
こんな時は、`vim`ならば、`CTRL+C`のあと、`:cq` でキャンセル出来るよ。

~~~ .gitconfig　エディタ設定の失敗例　
hint: Waiting for your editor to close the file... Vim: 警告: 端末への出力ではありません
Vim: 警告: 端末からの入力ではありません
~~~
~~~ .bash_profile　GIT_EDITOR＝空 を記載してあった場合の失敗例　
hint: Waiting for your editor to close the file... error: cannot run : No such file or directory
error: unable to start editor ''
Please supply the message using either -m or -F option.
~~~


# 困ったらマニュアルも確認
＜参考＞Git日本語ページ
https://tracpath.com/docs/
Goの環境構築 〜VSCodeでGoを動かす旅〜

# はじめに
この記事は、エンジニア経験1年の大学生が実務で勉強になったこと、詰まったこと、勉強したことをまとめています。間違っている箇所などがございましたら、指摘していただけると幸いです。

# 背景
インターン先でGoが採用されたので、キャッチアップをするために記事にしました。理解が浅いところや間違っているところが多少あると思いますが、優しく指摘していただけると幸いです。

# 環境
- macOS BigSur(11.6)
- Homebrew 3.4.9
- VSCode 1.66.2
- Go 1.18.1

# Go(golang)とは？
Goは2009年にGoogleがリリースしたオープンソースのプログラミング言語。

https://go.dev/doc/

# Goのインストール
[Downloads](https://go.dev/dl/)からインストールする。自分のOSに合うものを選択する。
![スクリーンショット 2022-04-30 15.28.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/880196/743532aa-39ae-721e-5245-6e01ac94fd6c.png)

インストールが完了したら、下記コマンドでGoのバージョンを確認する。

```bash
go version
```
下記のようになれば、インストールが完了している。
```bash
go version go1.18.1 darwin/amd64
```

# godocをインストール
[godoc](https://pkg.go.dev/golang.org/x/tools/cmd/godoc)とは、様々な標準ライブラリやGo製のサードパーティ製パッケージのリファレンスである。`go doc`コマンドを使用することで、ドキュメントを見ることができる。
下記コマンドで`godoc`をインストールできる。
```bash
go install golang.org/x/tools/cmd/godoc@latest
```

※ 過去の記事などを見ていると、`go get golang.org/x/tools/cmd/godoc@latest`でインストールしているが、`go get`は非推奨となっている。
`Go 1.17`から非推奨となり、`Go 1.18`から使用できなくなっている。

参照: https://go.dev/doc/go-get-install-deprecation

次にgodocがインストールできたか下記コマンドで確認する。`fmt`というパッケージのドキュメントを確認する。
```bash
go doc fmt
```
下記のように表示されれば、godocが無事インストールできている。

```bash
package fmt // import "fmt"

Package fmt implements formatted I/O with functions analogous to C's printf
and scanf. The format 'verbs' are derived from C's but are simpler.


Printing

The verbs:

General:

    %v	the value in a default format
    	when printing structs, the plus flag (%+v) adds field names
    %#v	a Go-syntax representation of the value
    %T	a Go-syntax representation of the type of the value
    %%	a literal percent sign; consumes no value
    .......................................................
```

※ 過去の記事によっては、`godoc XXXX`と書かれているものもあるが、godocのCLIモードのサポート終了によって、`godoc XXXX`の代わりに`go doc XXXX`と推奨されるようになった。

参照: https://github.com/golang/go/issues/25443

# VSCodeでGoの環境を構築
VSCodeの拡張機能からGoで検索し、下記画像のように`Go`をインストールする。
![スクリーンショット 2022-04-30 16.31.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/880196/4bcdde08-7330-ea19-f97e-ad7c48a2a821.png)

拡張機能をインストールできたら、パッケージをインストールしていきます。
`shift + command + p` でコマンドパレットを開き、「GO: Install/Update tools」と検索し、選択する。

全てにチェックを入れ、OKを押すと、インストールされる。
![スクリーンショット 2022-04-30 16.39.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/880196/36d24edb-8784-3f7d-8226-a3266ccc91d2.png)
これで、VSCodeの設定は終了。

# まとめ
今回Goを初めて触り、環境構築を行いました。その中でバージョンの違いで少し実行方法が違ったり、使えないコマンドがあったりして、多少時間がかかってしまうことがありました。特に、`Go 1.18`の記事が少なかったので、少しでも参考になれば幸いです。
Gitで管理しないファイルの指定方法

・Gitで管理しないファイルの指定方法
作業フォルダ内に「.gitignore」ファイルを作成する。

※使う対象
●自動生成されるファイル
●パスワード等機密事項が含まれているファイル

※「.gitignore」ファイルの記述方法
●コメントアウト
行頭に#
●指定したファイルを除外
ファイル名を記述
例)index.html
　 =>これで「index.html」はgitで管理されない
●ルートディレクトリを除外
/root.html
●ディレクトリ以下を除外
dir/
●/以外の文字列を含むファイルを除外
例)「.css」を含むファイルを除外
/*/*.css
AWS Lambda HTTP APIでPOSTデータを取得・デコードする関数（関数URL対応）

## HTTP APIや関数URLでもPOSTデータを受け取りたい
手軽に実装できてお財布にも優しいHTTP APIですが、POSTデータを受け取るのに一手間必要です。
リクエストbodyはbase64エンコードされた状態で取得できるため、　デコード & jsonパースしてあげる関数を使えばOKです。

## コード
### Node.js
```getBodyOnLambda.js
function getBodyOnLambda(event_body) {
    let body_string_utf8 = Buffer.from(event_body, 'base64').toString('utf-8');
    //日本語が含まれる場合はdecodeURIする
    //decodeURIComponentでは無くdecodeURIなのは、POSTされたデータの中に&が含まれているとJSON変換時にうまくいかないため
    body_string_utf8 = decodeURI(body_string_utf8);
    //パラメーター形式文字列のJSONへの変換
    const post_data = {};
    body_string_utf8.split(/\&/g).forEach(item => {
        //特殊文字もデコードして、keyとvalueに分ける
        const [key, value] = decodeURIComponent(item).split(/\=/);
        //JSON文字列の場合はJSONに変換して
        try{
            post_data[key] = JSON.parse(value);
        } catch(e) {
            post_data[key] = value;
        }
    });
    return post_data;
}

// example
// request body: { mail: hogehuga@example.com }
exports.handler = async (event, context, callback) => {
   const body = getBodyOnLambda(event.body);
   console.log(body.mail); // hogehuga@example.com
   context.done(null, body.mail);
};
```

### Python
```get_body_on_lambda.py
import base64
import urllib.parse
import json

def get_body_on_lambda(event_body):
    body_query = base64.b64decode(event_body).decode()
    body_dict = urllib.parse.parse_qs(body_query)
    # valueが配列に入っているので出す
    for key in body_dict:
        body_dict[key] = body_dict[key][0]
    return body_dict

# example
# request body: { mail: hogehuga@example.com }
def lambda_handler(event, context):
    body = decode_body(event['body'])
    print(body['mail']) # hogehuga@example.com
    return {
        "statusCode": 200,
        "headers": {
            "Content-Type": "application/json"
        },
        "body": json.dumps(body)
    }
```
Linux Ping-t勉強の記録3 仮想マシン・コンテナの概念と利用

## Ping-tで出てきた覚えるものを記録(辞書)
#### KVM(Kernel-based Virtual Machine)
Linuxに標準搭載されている仮想化ソリューション
ソリューション：解決
#### libvirt：オープンソースの仮想化管理用のライブラリ
virt-managerやvirshコマンドもlibvirtを利用している
## CPUの仮想化支援機能
CPUが仮想化ソフトウェアの処理を分担し高速化する機能
##### Intel VT(Intel Virtualization Technology)
##### AMD-V(AMD Virtualization)
## 仮想化の実現
仮想化の実現方法には仮想マシンとコンテナがある
### 仮想マシン(VM)
ハイパーバイザーを使う仮想環境
#### ハイパーバイザー：仮想マシンを動かすソフトウェア
##### ベアメタル型（ネイティブ型）
ハイパーバイザーがハードウェア上で直接動作しすべてのOSがその上で動作する
##### ホスト型
ホストOS上でハイパーバイザーが動作する（自分が使っているVirtualBoxはこの方式）
### コンテナ
コンテナはよくわからなかった
ホストOSのリソースを隔離したものがコンテナ
コンテナには独自のアドレス空間、ストレージ、ネットワークアドレスをもつ
ホストOSのカーネルを共有しているのでVMを起動せずにアプリの実行環境を構築できる
#### cgroups
コンテナのリソースを管理する
#### namespace
コンテナとホスト間でユーザ権限の分離できる
## virshコマンド　仮想マシンについて
### virsh create
XML形式のファイルからVMを作成後起動
### virsh list
VMの一覧表示
デフォルトは稼働している物のみ
[--all]で稼働していない物も一覧表示
### virsh console
VMのコンソールに接続
### virsh start
VM起動
### virsh shutdown
VM正常終了
### virsh destroy
VM強制終了
### virsh reboot
VM再起動
### virsh suspend
VM一時停止
### virsh resume
VM再開
### virsh dumpxml
VMの定義ファイルを出力
## dockerコマンド　コンテナについて
### docker run
コンテナを作成後起動
##### -i(--interactive)
標準入力を受け付ける
##### -t(--tty)
疑似端末を割り当てる
### docker start
既存コンテナ起動
### docker stop
コンテナ停止
### docker kill
コンテナ強制停止
### docker ps
コンテナ一覧表示
### docker rm
コンテナ削除
### docker attach
コンテナの標準入出力に接続
### docker exec
コンテナでコマンド実行
### docker pull
Docker Hub からイメージをダウンロード
### docker push
Docker Hubにアップロード
### docker images
イメージ一覧表示

## 間違いそうなコマンド
|説明|virsh|docker|
|---|---|---|
|作成後起動|create|run|
|起動|start|start|
|正常停止|shutdown|stop|
|強制停止|destroy|kill|
|一覧表示|list|ps|

コンテナの一覧表示をするのが [docker ps]
dockerイメージの一覧を表示するのが [docker images]
ksnctf q40 Deep Flag Network


q40.zipをダウンロードすると学習用と評価用のコードがあった。
train.pyを見るとcifar10のデータセットを使い、7層の全結合層で11クラスの多クラス分類を学習している。
cifar10の10クラスに、flagクラスを11番目のクラスとして追加して学習している。flagの教師データは32x32サイズのQRコードのようだが学習に使用したflag.pngは当然入手できない。

flag.pngを適当なQRコードで作成して、学習、評価を行ってみると、問題文と同様に、学習したflag.pngの推論結果が99.5%となった。
学習に使用したflag.pngをなんとかして復元する問題のようだ。

pythonにはqrcodeモジュールがあり、文字列からQRコードを生成できるので、遺伝的アルゴリズムなどを使ってflag.pngを類推できないかやってみたが、無理そうだった。そもそも同じ文字列でも作成されるQRコードが、ライブラリによって違うようなので、この方法でflag.pngを類推するのは無理そう。

もう一度学習用スクリプトを見ると、教師データにflag.pngのQRコードが5000枚も重複して入っている。これだけ多いと、ネットワークのモデルの重み係数にQRコードの画像情報が入っているかもと考えた。
このあたりは、すごく適当な思い付きなので、全然間違っていましたらご指摘お願いします。

以下のpythonコードを書き、実行してみた。
実行方法は以下
python3 flag_test.py no_flag_0.png

内容は、no_flag_0.pngを入力としてネットワークの順伝搬を行い、出力の10番目の要素(flagのクラス)から、逆伝搬した勾配を求めて、
最初のdense層の重み係数を勾配の大きさで重みづけて足し合わせて、最後に画像化を行った。

```python:flag_test.py
# -*- coding: utf-8 -*-

import os, sys
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
import tensorflow as tf # v2.5.0
from tensorflow import keras
import numpy as np
import cv2
import keras.backend as K

def load_image(f):
    return tf.io.decode_image(tf.io.read_file(f), channels=1, dtype=tf.float32)

# モデル読み込み
input_model = tf.keras.models.load_model("model")
# 画像読み込み
image = tf.expand_dims(load_image(sys.argv[1]), axis=0)
input_model.summary()

# 勾配計算用
grad_model = tf.keras.models.Model([input_model.inputs], [input_model.get_layer('dense').output, input_model.output])

with tf.GradientTape() as tape:
    conv_outputs, predictions = grad_model(image)
    loss = predictions[:, 10]
    #print(conv_outputs.shape)
    #print(predictions.shape)

# 勾配を計算
output = conv_outputs[0]
#print(output.shape)
grads = tape.gradient(loss, conv_outputs)[0]
#print(grads.shape)

# 正の勾配のみ
gate_f = tf.cast(output > 0, 'float32')
gate_r = tf.cast(grads > 0, 'float32')
#guided_grads = gate_f * gate_r * grads
guided_grads = gate_r * grads
#print(guided_grads.shape)
guided_grads = np.array(guided_grads)

feature = np.zeros((1024), dtype=np.float32)
# 最初のdense層(1024->512)の重み係数
l1= input_model.layers[1]
l1w = l1.get_weights()
maps = l1w[0]
for n in range(512):
    fmap = maps[:,n]
    # flagクラスの正の勾配で重みづけて加算
    feature = feature + fmap * guided_grads[n]
# 0-255にして画像に保存
featmin = min(feature)
featmax = max(feature)
feature = (feature - featmin) * 255.0 / (featmax - featmin)
featimg = feature.astype(np.uint8).reshape([32, 32])
#th, im_th = cv2.threshold(featimg, 128, 255, cv2.THRESH_BINARY)
cv2.imwrite('flag.png', featimg)

```

実行すると以下のflag.pngが得られた。
これを拡大し、スマホのQRコードリーダーで読むと、正解のFLAGが得られた。

![flag.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257741/ac681e0d-94f9-5e10-384b-f5647db8b208.png)

NearestNeighbourで拡大したものは以下

![flagL.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257741/0b02ee77-18ef-b21f-1638-2c6b31535eee.png)
【開発環境復活シリーズ１】virtualbox6.1でもvagrant upできるようにしてみた

## はじめに

1年ほど前、某プログラミングスクールで仮想環境を構築し、アプリ開発を行い、
その際使用した環境をもう一度復活させてみて、アプリを再度修正や公開してみようと思い、
改めてvagrantとvirtual Boxを触ってみました。
（アプリにコードはgithubに残っていたので。。）

しかし、当たり前ですがバージョンが変更していたりと、
当時の手順そのままではできなくなっていたので、
それに付随して発生した事象をまとめてみました。

今後も多々発生していくと思うので、
その過程を忘れないようにシリーズみたいにまとめていきます。

完全自己満ですが、同じような事象で悩まれている方の助けになることがあれば、
幸いです。。

## 発生したこと

まず、当時残されていたvagrantfileとプラグインを確認し、
vagrantを立ち上げを行おうとした際に下記内容が表示され、
立ち上げがうまくできませんでした。


     


     No usable default provider could be found for your system.

     Vagrant relies on interactions with 3rd party systems, known as
     "providers", to provide Vagrant with resources to run development
     environments. Examples are VirtualBox, VMware, Hyper-V.

     The easiest solution to this message is to install VirtualBox, which
     is available for free on all major platforms.

     If you believe you already have a provider available, make sure it
     is properly installed and configured. You can see more details about
     why a particular provider isn't working by forcing usage with
    `vagrant up --provider=PROVIDER`, which should give you a more specific
    error message for that particular provider.


参考URL

https://qiita.com/shuu1222/items/7a6d04172363be44025c

https://sazaijiten.work/docker_virtualbox_vagrant/

https://qiita.com/zaki-lknr/items/469e4de02a8d544f2153

上記を参考に、

**・virtualbox6.1でもvagrantの立ち上げができるようにする**

**・vagrantfileの内容を確認、CentOSを最新版に変更**

主にこの２点へ取り掛かりました。


        
         Bringing machine 'default' up with 'virtualbox' provider...
         There are errors in the configuration of this machine. Please fix
         the following errors and try again:

         VirtualBox Provider:
          * The following settings shouldn't exist: cpu


ちなみに上記のようなエラーも発生し、
おそらくCPUについて（スペックの箇所）の内容なので、
不備がないか確認したところ、なぜかcpu(s)のつけ忘れが発生してました。

## まとめ

今回の事象が発生した原因としては、
そもそもローカルに入れてあるvagrantのプラグイン設定が、
virtualbox6.1（最新版）に対応してなかったのが原因だったようでした。。

単純に設定ファイルへ６.１を追加できる内容を追加していくことで、
事象としては解決できました！

ただ、この後CentOS８がインストールできないなど、
まだゴールにはならないのですが、それはまた次回。。。



## 最後に

初めてアプリ開発を行っていた段階では、正直環境構築を手順通りやっただけで、
何をしているかわけがわかっていませんでしたが、
多少なりともインフラの知識がついてきた中で、改めて取り組んでみると、
当時ではまったく理解できなかった内容が、なんとなくわかったりと、
楽しみながらやれている気がします。

今後も学習と一貫として続けて行って、
是非とも開発環境を復活させていきたいです！

何か、ご指摘などあればお気軽にコメントください！
ServiceNowのServicePortalをiPadのWebViewで表示

<h1>WKWebViewでServicePortalを表示する</h1>

<h2>結論</h2>
公式ドキュメントに則って、URLにServicePortalのURLを貼り付ければWebViewでServicePortalを表示することが可能。

<h3>環境</h3>
Xcode : 13.2/iPad Air 5th/iOS : 15.3

<h3>実装方法</h3>
公式Docs : https://developer.apple.com/documentation/webkit/wkwebview

以下、コード。

```
import UIKit
import WebKit
class ViewController: UIViewController, WKUIDelegate {
    
    var webView: WKWebView!
    
    override func loadView() {
        let webConfiguration = WKWebViewConfiguration()
        webView = WKWebView(frame: .zero, configuration: webConfiguration)
        webView.uiDelegate = self
        view = webView
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let myURL = URL(string:"<ServicePortalのURL>")
        let myRequest = URLRequest(url: myURL!)
        webView.load(myRequest)
    }}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1970753/ab61ad9c-0749-89b7-765c-0402439c80aa.png)

まだ、詳細な動きの確認はできてませんが表示させることはできます。
100日後くらいに個人開発するぞ！day012

## 今日はレイアウトを作ってみた

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2632394/fe564ec8-eacc-2871-4902-ca90d242d809.png)

## 今日のアウトプット
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2632394/aa2db460-94de-3db2-bfea-7c26da3934d1.png)


## 今日の学び

### 文字の太さを指定する方法
- font-weightプロパティを用いることで文字の太さを変更できる
    - 例：文字を細くしたい場合
        - `font-weight:normal;`
    - 例：文字を太くしたい場合
        - `font-weight:bold;`

### 相対的な大きさを指定する方法
- widthやheightを%で指定すると親要素の幅や高さに対する相対的な大きさを指定できる
    - 例：親要素の幅の40%にしたい場合
        - `width:40%;`


### 要素同士を重ねて表示させる方法
 - `position:absolute;`を用いると要素を重ねて表示できる
    - 例
        - `.box{position:absolute;}`

### 要素の位置を指定する方法
- サイト全体の左上部分を基準として位置を指定する場合
    - 例：サイト全体の左上部分から50px下の位置を指定する場合
        - `top:50px`
    - 例：サイト全体の左上部分から50px左の位置を指定する場合
        - `left:50px`
- `position:relative`を親要素に指定するとその親要素の左上部を基準位置にすることができる
データフレーム同士の結合(merge関数) について

「このデータは、数学のテストの結果で」
「このデータは、英語のテストの結果で」

このようなデータフレームはまとめたいデータだと思います。

このようなデータを一つに結合させることができれば、情報がより分かりやすくなりますよね。
その時に用いる関数が`merge`関数です

これはそれぞれのデータを横方向に結合させることができる関数です。

ちなみに今回の記事の範囲外になりますが、同じ種類のデータを結合させたいとき
つまり縦方向にデータを結合させたいときは、pandasライブラリにある`pandas.concat`メソッドです。

では実際に、merge関数を使用していきましょう。
```Python
import pandas as pd
import numpy as np
```
```Python
df01 = pd.DataFrame( {'name':['A', 'B', 'C'],
'math':[60, 70, 80]})
df01
```

```
  name  math
0    A    60
1    B    70
2    C    80
```

```Python
df02 = pd.DataFrame( {'name':['A', 'B', 'C', 'D'],
'english':[100, 90, 80, 70]})
df02
```

```
  name  english
0    A      100
1    B       90
2    C       80
3    D       70
```



このような二つのデータには共通して`name`というカラムが存在します。これを主キーとも呼びます。
これを紐づけながらデータ加工をします。
```Python
pd.merge(df01 , df02 , how="inner" , on="name")
```

結合方法(how)には、様々存在しますが、今回は内部結合というものを使っていきました。

```
  name  math  english
0    A    60      100
1    B    70       90
2    C    80       80
```

このように、二つのデータが上手く結合できました。

今回は以上になります。ありがとうございました。
Angular  + Bootstrapの環境構築(nvm導入編)

■nvmとは
nvmとは、node.jsのバージョンを管理するためのツール

■nvmインストール(Windows版)
１．[windows-nvm リポジトリ](https://github.com/coreybutler/nvm-windows#node-version-manager-nvm-for-windows
)を開いて、 「manual installation」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2353455/5d20c442-1e56-267b-edce-ff2c0f5486b6.png)
２．「Download nvm-noinstall.zip」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2353455/e78462f9-3d33-6e18-97ac-0b1cc369ee82.png)
３．「nvm-setup.zip」を選択して、インストーラーをダウンロードする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2353455/6c074906-73f1-ea53-877b-4932fd3fab17.png)
４．ダウンロードしたnvm-setup.zipを解凍
５．「nvm-setup.exe」ファイルをクリックしてnvmをインストールする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2353455/461526d3-e570-24d9-2950-9b5574895a0f.png)
参考サイト：[Windows での NodeJS のインストール](https://docs.microsoft.com/ja-jp/windows/dev-environment/javascript/nodejs-on-windows)
Flask + Cloud Run をDocker環境に構築

# はじめに
Pythonを使用してCloud Runを利用したい場合、公式のガイドではFlaskを使用しているので、それに従いデプロイするまでの環境をDockerで構築する。

https://cloud.google.com/run/docs/quickstarts/build-and-deploy/deploy-python-service

# 概要
#### 前提条件
GCPにプロジェクトが存在し、Cloud Runが使用できる状態になっている
docker-composeを使用

#### 手順
docker-composeを使用してコンテナを作成する
google-cloud-sdkをインストールして設定する
FlaskアプリケーションをCloud Runにデプロイする

# Docker環境構築
Dockerの設定ファイルとrequirements.txtを作成する。
その後、コンテナを作成し起動する。

```:Dockerfile
FROM python:3.10-slim

ENV PYTHONUNBUFFERED True

ENV APP_HOME /app
WORKDIR $APP_HOME
COPY . ./

RUN pip install --no-cache-dir -r requirements.txt

CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app
```
```:docker-compose.yml
version: '3'
services:
  flask:
    build: .
    ports:
      - "5000:5000"
    volumes:
      - .:/app
    tty: true
```
```:requirements.txt
Flask==2.1.0
gunicorn==20.1.0
```

# google-cloud-sdkの設定
起動したコンテナからコマンドを実行してgoogle-cloud-sdkの設定をする。

```
# sdkのダウンロード
apt-get update
apt-get install curl
cd /tmp
curl -O https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-381.0.0-linux-x86_64.tar.gz

# sdkのインストール
tar -xvzf google-cloud-sdk-381.0.0-linux-x86_64.tar.gz -C /
cd /
./google-cloud-sdk/install.sh
gcloud auth login --no-launch-browser
gcloud projects list
gcloud config set project <your-project-id>

# 確認
gcloud config configurations list
```


# FlaskアプリケーションをCloud Runにデプロイ
Dockerfileと同じ階層にmain.pyを作成してデプロイする。
```:main.py
import os

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello_world():
    name = os.environ.get("NAME", "World")
    return "Hello {}!".format(name)

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
```
```
# デプロイ
gcloud run deploy
```

表示されたURLにアクセスすると

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2639110/4143580f-d4b6-f6c9-5062-161604e71ffd.png)

Hello World!を確認できた
Codeforces Round #784 (Div. 4) 解いた感想

## A. Division?
問題文に従ってif文を書きました．
```c++
void solve(){
    ll n; cin >> n;
    ll ans=-1;
    if(n<=1399) ans=4;
    else if(n<=1599) ans=3;
    else if(n<=1899) ans=2;
    else ans=1;
    printf("Division %lld\n", ans);
}
```

## B. Triple
数字の出現回数をmapで数えて３回以上現れるものを出力しました．
```c++
void solve(){
    ll n; cin >> n;
    map<ll, ll> mp;
    for(ll i=0; i<n; i++){
        ll t; cin >> t;
        mp[t]++;
    }
    ll ans=-1;
    for(auto [a, b] : mp){
        if(b>=3) ans=a; 
    }
    cout << ans << "\n";
}
 
```
## C. Odd/Even Increments
$a_0$と$a_1$の偶奇を調べて，異なっている場合は，配列の偶数番目の要素を全て+1しました．
この操作によって，全ての要素の偶奇が揃うか？を調べて判定します．
```c++
void solve(){
    ll n; cin >> n;
    vector<ll> a(n);
    for(ll i=0; i<n; i++) cin >> a[i];
    bool ok=true;
    if(a[0]%2 != a[1]%2){
        for(ll i=0; i<n; i+=2) a[i]++;
    }
    for(ll i=0; i<n; i++){
        if(a[i]%2 != a[0]%2) ok=false;
    }
    cout << (ok? "YES" : "NO") << "\n";
}
```

## D. Colorful Stamp
$R$と$B$のみから構成される文字列に注目しました．
$RRBRWRBRB=>RRBR$ と$RBRB$のように$W$で文字列を切った時に，分離された文字列それぞれが，$R$と$B$の二種類の文字で構成されている必要があると考えました．それを探索して判定しました．

```c++
void solve(){
    ll n; cin >> n;
    n++;
    string s; cin >> s;
    s+='W';
    bool ok=true;
    bool flag = false;
    ll b=0, r=0;
    for(ll i=0; i<n; i++){
        if(flag){
            if(s[i]=='B' or s[i]=='R'){
                if(s[i]=='B') b++;
                if(s[i]=='R') r++;
            }
            else{
                if(b==0 || r==0) ok=false;
                flag=false;
                b=0;
                r=0;
            }
        }else{
            if(s[i]=='B' or s[i]=='R'){
                flag=true;
                if(s[i]=='B') b++;
                if(s[i]=='R') r++;
            }
        }
    }
    cout << (ok? "YES" : "NO") << "\n";
}
 
```
## F. Eating Candies
左からの累積和と右からの累積和を調べました．左からと右からの累積和を，それぞれmapに（累積和の値，左から何番目か？）を記録させます．
累積和の値が，２つのmap(ここではa,bとして宣言して使っています)に含まれていて，a.second<b.secondの時に要素数を計算して最大値を更新していきました．
```c++
void solve(){
    ll n; cin >> n;
    vector<ll> w(n);
    for(ll i=0; i<n; i++) cin >> w[i];
    map<ll, ll> a, b;
    ll sa=0, sb=0;
    for(ll i=0; i<n; i++){
        sa+=w[i];
        a[sa]=i+1;
    }
    for(ll i=n-1; i>=0; i--){
        sb+=w[i];
        b[sb]=i+1;
    }
    ll mx=0;
    for(auto [x, j] : a){
        if(b[x]>0 && j<b[x]){
            chmax(mx, j+n-b[x]+1);
        }
    }
    cout << mx << "\n";
}
```
systemdで起動したプロセスの子プロセスの標準出力もjournaldに記録される

小ネタ。あれもしかしてそうなの？と思って確認したら首題の通りだった。
割と便利で、定期実行ジョブをcronからsystemdに置き換えたいと思うモチベーションになり得る。

# 検証

とりあえず親となるparent.shと、子プロセスになるchild.shを作る。どちらも毎秒「parent」、「child」のメッセージを標準出力に出力する。
以下はrootで実行を想定。

```bash
cat > /root/parent.sh << EOF
#! /bin/bash
/root/child.sh &
while true
do
  echo parent
  sleep 1
done
EOF
chmod 700 /root/parent.sh
cat > /root/child.sh << EOF
#! /bin/bash
while true
do
  echo child
  sleep 1
done
EOF
chmod 700 /root/child.sh
```

このままparent.shを起動するとchild.shを止めるのが面倒なので、systemd serviceとして起動する。

```bash
cat > parent.service << EOF
[Unit]
Description=Parent

[Service]
ExecStart=/root/parent.sh

[Install]
WantedBy=multi-user.target
EOF
cp parent.service /etc/systemd/system/
systemctl daemon-reload
systemctl start parent
```

サービスが起動したところで、systemctl statusを見ると、メッセージに「parent」、「child」と、子プロセス側の標準出力も含めてjournaldに流れていることがわかる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146381/a2db537a-8847-1fad-4f65-1e20729c8ff1.png)

なお、止めるときは「`systemctl stop parent`」でchild.shも止まる。これも便利。


# timerでも試す
service的な使い方をするのでも便利なのだが、この、子プロセスを含めて標準出力をjournaldに送ってくれるというのは、定期実行する運用スクリプトでもありがたい。何がありがたいかというと、スクリプトごとにいちいち出力するログファイル名を決めてそのファイルを管理する必要がないのだ。cronで標準出力するとmailが残るが、どちらかというとmailが残るのが煩わしかった。
後はまあなんだ、dockerコンテナとの親和性である。

上のような例で、5秒毎にメッセージを記録するtimerのsystemdジョブを作るなら、以下の通り。
（なお、1秒ごとだと忙しすぎるらしく「repeated too quickly.」と言ってたまにコケる）

```bash
cat > /root/parent-t.sh << EOF
#! /bin/bash
echo parent-t
/root/child-t.sh
EOF
chmod 700 /root/parent-t.sh
cat > /root/child-t.sh << EOF
#! /bin/bash
echo child-t
EOF
chmod 700 /root/child-t.sh
cat > parent-t.service << EOF
[Unit]
Description=Parent-t

[Service]
Type=oneshot
ExecStart=/root/parent-t.sh

[Install]
WantedBy=multi-user.target
EOF
cat > parent-t.timer << EOF
[Unit]
Description=Parent-t timer

[Timer]
OnCalendar = *-*-* *:*:0/5
Unit = parent-t.service
AccuracySec=1s

[Install]
WantedBy = timers.target
EOF
cp parent-t.service parent-t.timer /etc/systemd/system/
systemctl daemon-reload
systemctl start parent-t.timer
systemctl enable parent-t.timer
```

journalctlに-fを付けてログを眺めると、5秒ごとにparant-tとchild-tのメッセージが出力されるのが確認できる。
ログファイル名フリーである。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146381/7015f1e5-72e7-ce41-9d02-3661cbf5efe3.png)

journaldに送られたログは、syslog経由でテキストログにも保管される。一応。
RHEL系なら/var/log/messagesだし、ubuntuなら/var/log/syslog。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146381/98f74dc6-935a-acaf-cd7e-6a1a1f116d00.png)

なお、timerでの定期実行を止めたい場合は「`systemctl stop parent-t.timer`」。
JavaScriptの関数の定義方法についてまとめてみた

# はじめに
JavaScriptの関数を定義する方法は複数あります。そして、アプリケーションの開発では様々な方法で関数を定義していきます。しかし、学習して間もない時は複数ある関数の定義方法について混乱したり、理解が曖昧なことがあると思います。そのため、それぞれの記述方法や特徴をまとめました。

# 関数宣言
function、関数名、引数、関数の処理を記述して関数を定義します。引数がない場合も()を記述する必要があります。
```JavaScript
function 関数名(引数){
  // 関数の処理
}
```
関数宣言で定義した関数は先に読み込まれるため、関数を実行する記述が前でもエラーになりません。
```JavaScript
example()

function example(){
  console.log('example')
}

// エラーにならない
```

# 無名関数
function、引数、関数の処理を記述して関数を定義します。
```JavaScript
function (引数){
  // 関数の処理
}
```
関数宣言と比較すると、関数名がないためより簡潔なコードの記述ができます。次に紹介する関数式を定義する際に利用されます。

# 関数式
変数(関数名)と無名関数を記述して関数を定義します。無名関数を変数に代入します。
```JavaScript
const 変数 = 無名関数

// 例
const example = function(){
  console.log('example')
}

example()
```
関数式で定義した関数は順番通りに読み込まれるため、関数を実行する記述が前ではエラーになります。
```JavaScript
example()

const example = function(){
  console.log('example')
}

// エラーになる
```

# 即時関数
()と関数宣言を記述して関数を定義します。関数宣言を()で囲い、その後に引数を記述します。
```JavaScript
(関数宣言)(引数)

//例
(function example(){
  console.log('example')
})()
```
即時関数は関数を定義すると同時に実行されます。そのため、関数を実行する記述が不要になります。

# アロー関数
無名関数のfunction(引数)の代わりに(引数)=>を記述して定義します。
```Javascript
(引数)=>{
  // 関数の処理
}

// 例
const example = () => {
  console.log('example')
}

example()
```
functionを使用した関数と比較してより短い記述で関数を定義できます。近年採用されることが増えています。

# 参考文献
公式リファレンス：https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions
[ARKit]  衝突判定を実現するメモ


#### 衝突判定する流れ
ARViewにコリジョンの有効、無効を設定する

```swift
// physicsにすると現実世界の物体と衝突した際もぶつかる。
   arView.environment.sceneUnderstanding.options = [.collision]
```

ARSessionを開始する
ARObjectを配置する
モデルエンティティにコリジョンコンポーネントをアタッチする

```swift
 model.generateCollisionShapes(recursive: false)
```
エンティティの衝突を検出してイベントを発行する
コリジョンイベントを受診して処理を行う。

コリジョンイベントを検知するためにcombineを使ってシーンをサブスクライブする

```swift
 collisionBegan = arView.scene.subscribe(to: CollisionEvents.Began.self,
                                                実現したいメソッド)
```

### コリジョンイベント3種類

```swift
CollisionEvents.Began
衝突が起きたタイミングで発生する
CollisionEvents.Updated
衝突が起きてから衝突が継続されている間発生する
CollisionEvents.Ended
衝突がなくなった直後に発生する。
```
Emacsのplstore.elで暗号化するパスフレーズを何度も入力しないで済ませたい

Emacsのplstore.el<sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup>はEmacs Lispでよく利用するProperty List(plist)<sup><a id="fnr.2" class="footref" href="#fn.2" role="doc-backlink">2</a></sup>形式のデータをGnuPGで暗号化してファイルに保存する際に利用するライブラリです。

とても便利ですが、データを保存する際に毎回パスフレーズを聞かれるため、面倒だな、と思っていました。

そう思っていたところ、たまたま見ていた `gnus-gmail-oauth` のソースコードに、偶然、次の記述を見つけました。

<https://github.com/ggervasio/gnus-gmail-oauth/blob/91b014187dc61b09e2acae554b1d2d1fd4f14bbd/gnus-gmail-oauth.el#L46>

    ;; 4. (optional):
    ;; oauth2 uses plstore to save access tokens in ~/emacs.d/oauth2.plstore,
    ;; which is GPG-encrypted.  This allows the GPG passphrase to be cached
    ;; during the Emacs session:
    ;;
    ;; (setq plstore-cache-passphrase-for-symmetric-encryption t)

この、長ったらしい `plstore-cache-passphrase-for-symmetric-encryption`という変数ですが、ドキュメント化されていないものの、確かに、ソースコードには存在しています。

<https://github.com/emacs-mirror/emacs/blob/a33bf0114920a67926761ec2f51c040265b8dfd1/lisp/plstore.el#L127>

そこで、

```el
(setq plstore-cache-passphrase-for-symmetric-encryption t)
```

を設定したところ、確かにパスフレーズがキャッシュされるようになりました。一度入力すれば、二回目以降は省略できるため便利です。めでたし、めでたし。

なお、セキュリティ上の問題があるのかどうかは調べてませんので、利用されるときはお気をつけ下さい。


# Footnotes

<sup><a id="fn.1" href="#fnr.1">1</a></sup> : [emacs/plstore.el at master · emacs-mirror/emacs](https://github.com/emacs-mirror/emacs/blob/master/lisp/plstore.el)

<sup><a id="fn.2" href="#fnr.2">2</a></sup> : [Property Lists (GNU Emacs Lisp Reference Manual)](https://ayatakesi.github.io/emacs/24.5/elisp_html/Property-Lists.html#Property-Lists)
【JavaScript問題】「700 / 500 | 0 」の出力結果は？

なんだこの書き方は？っというのがあったので調べて理解したので、投稿しておきます

# 答え

```
700 / 500 | 0
= > 1
```

# 理由

まず、700 / 500 = 1.4 です。
"|"はビットの論理和であり、整数の演算子です

※補足
> 整数・・・実数の分類の1つで、正の整数（自然数）、ゼロ、負の整数のみ
> 実数・・・有理数と無理数

これを使った時点で、左側が実数から整数に変換され、小数点が消えて、"1"になります。
右の値が"0"なのでそのまま左の整数の値"1"が得られます。


# 補足
5 | 3 = 7 です

理由は以下です
```
const a = 5;        // 00000000000000000000000000000101
const b = 3;        // 00000000000000000000000000000011

console.log(a | b); // 00000000000000000000000000000111
// expected output: 7
```


# 最後に一言
何か間違っている点があれば、教えて頂けたら幸いです。
よろしくお願い致します。
また「いいね！」してもらえるとすごい嬉しいです！！
requestsで非同期Asyncリクエスト【HTTPX】

https://colab.research.google.com/drive/1O7v-OLPpb0yG56n1PjkvuBDH0HsYl3-8?usp=sharing

# requestsをインストール

```bash
pip install httpx
```

# requestsをインポート
150個のリクエストを作成します。
```python
import httpx as requests
from asyncio import run, gather

urls = [f"https://pokeapi.co/api/v2/pokemon/{n}" for n in range(1, 151)]
```

# 同期(Sync)リクエスト 処理時間8.8秒

```python
def sync_func():
    print([requests.get(u) for u in urls])

sync_func()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208363/58b4d2c1-7486-a664-76d1-1dae8bf641e2.png)


# 非同期(Async)リクエスト 処理時間0.7秒

```python
async def async_func():
    async with requests.AsyncClient() as client:
        tasks = [client.get(u) for u in urls]
        print(await gather(*tasks, return_exceptions=True))

run(async_func())
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208363/2ce65fee-85ac-6aeb-eded-98324bf9bd8a.png)

# まとめ

- 非同期リクエストにすることで10倍以上高速化できた

# 参考

https://www.python-httpx.org/async/

https://qiita.com/jrfk/items/ccba8dd63b635018cb6f

https://www.twilio.com/blog/asynchronous-http-requests-in-python-with-httpx-and-asyncio
WindowsのDiscordアプリが開かなくなった場合の対処

# WindowsのDiscordアプリが開かなくなった場合の対処

WindowsでDiscordアプリが突然開かなくなりました。
症状としてはアプリケーションが立ち上がるのですが、画面上に何も映らないといった状態です。
その症状を改善した方法を備忘録的にまとめます。

## 環境

OS: Windows 10 Home



## 考えられる原因

アプリケーションのエラー原因としては以下に大別できると考えてます。
- アプリケーションの問題
- OSの問題
- ハードウェアの問題
- 通信の問題

今回は別アプリケーションやブラウザは問題ないことから、通信、ハードウェアの問題ではないと考えられます。
またモバイルアプリ版では問題なく開けていることからアプリケーションのサーバーや認証の問題ではないと考えられます。

## 試したこと

### アプリケーションの強制終了

タスクマネージャーからDiscordの強制終了(タスクの終了)

### OSの再起動

とりあえずはWindowsの再起動。

### 互換性の確認

アプリケーションを右クリックして[互換性のトラブルシューティング]を実行。
ただし、最近OSアプデを行った記憶はないため原因として考えられる可能性は低い。

### 管理者として実行

アプリケーションを右クリックして[管理者として実行]。

### Discordアプリのアンインストールと再インストール

ここまでの対応で改善しないため、スタートメニューからDiscordを右クリックしてアンインストール、Discordのインストールページから再インストール。(https://discord.com)

### sfcで破損したシステムファイルを修復

[スタート]から「cmd」と入力し、コマンドプロンプトを管理者として実行。
画面に以下のコマンドｊを入力してEnterを押して実行。

```shell
sfc /scannow
```


これでも解決しないため、Applicationのデータを消すことに。

### AppDataの削除

エクスプローラーから[ユーザー名]のフォルダを開き、下部のAppDataフォルダを開く。
下部のLocalフォルダを開いてDiscordのフォルダを探す。(以下画像を参照)
Discord フォルダを右クリックして[削除]する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599414/2340fd64-470e-7f2e-afe2-d27e470ce2a5.png)

もう一度AppDataを開き、下部のRoamingフォルダを開いてDiscordフォルダを探して[削除]。


AppDataを削除して、再度Discordアプリをインストールしたところ、ログイン画面が表示されログインして無事解決した。

## 総括

原因としては、AppDataに問題が生じていたため削除することで解決した。
直接的な原因としては、Discord起動時に何か問題が生じてAppDataが破損(?)したと思われるが詳細はよくわからない。
Windowsはアプリケーションをアンインストールした時点では、AppDataは削除しないのがかなり疑問として感じた。


間違いや指摘,アドバイス等あればコメントお願いします。


## 参考

https://app-story.net/discord-can-not-open/#i-5
Salesforceフローを作成しよう～特定の期間で添付ファイルがあるレコードのみ更新する方法

今回はSalesforceでフローを作成し下記実装しようと思います

「要望」
スケジュールトリガーフローを使って取引先レコードの
「メモ&添付ファイル」にファイルが添付されているかを1日1回判定し、ファイルがある場合はカスタムチェックボックス項目をTRUEとしたいです。（ない場合はカスタムチェックボックス項目をFALSEとする）


スケジュールトリガーは下記のようになります
![1フロー１.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/95f43dd8-8862-e858-d320-f67f6aa22162.png)



まずは１つずつ確認しましょう



## 開始条件

今回は取引先の添付ファイル有無を確認したいのでオブジェクトは「取引先」を設定します
![開始条件01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/64781bee-a918-3f17-018c-bb6a651810dd.png)



## レコードを取得
コンテンツドキュメントリンクオブジェクトを元に、添付ファイルのある取引先のレコードIDを取得します
![１フロー２.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/59baa856-80bd-ca35-dcb3-1fb9b7515655.png)


## 割り当て
NullかNullで無いかで割り当てます
![1フロー３.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/e015e77d-6d15-7c7c-48f8-fb871eee1440.png)


## レコード更新
Nullでない場合、添付ファイルがある取引先レコードのみチェックをつけます
![1フロー４.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/7784d79b-4afd-619e-acff-d1dbfe8fc78b.png)

Nullの場合、添付ファイルがある取引先レコードのみチェックを　外します。




いかがでしたでしょうか
良いコードを書くには...究明編

## 勉強しているのに良いコードが書けない

言語自体を学ぶのであれば、自分にあってそうな本を本屋で探して[^1]買ってきて、読みながら実際に動かしてみたりすればよいし、ちょっとよいコードが書きたくなったら、みなさんが勧めているリーダブルコードなどを読めばいいでしょう。

ただそのようなことをしていても**あるレベル以上のコードが書けるようにはならない**のですが、その理由を究明していきたいと思います。


## 日本語もプログラムもただの言語

日本語の読み書きは日本人であれば全員義務教育で学びます。
日本語を学んだ人が全員分かりやすくて面白い話をするかというとそんなことはなくて、壊滅的に話がつまらない人や何言ってるか分からない人も存在します。

『人に物事をうまく伝えられていないこと』に気づいていない方が大半、危機意識を持って書籍を読む方が少し、分かりやすくて面白い話をする方が数％といったとこでしょうか。[^2]

この点についてたくさん良書が出ていますが、説明の方法の本を読んでも次の日から説明が上手くなることはめったにないと思います。

例）

https://www.amazon.co.jp/%E4%B8%80%E7%95%AA%E4%BC%9D%E3%82%8F%E3%82%8B%E8%AA%AC%E6%98%8E%E3%81%AE%E9%A0%86%E7%95%AA-%E7%94%B0%E4%B8%AD%E8%80%95%E6%AF%94%E5%8F%A4-ebook/dp/B07DK7BCGS/


同様にプログラム言語を**学ぶだけでは**人間やコンピュータにとって分かりやすくて面白いプログラムは書けません。
意識の高いオブジェクト指向やデザインパターンを学んでも**次の日から優れたオブジェクト指向やデザインパターンを取り入れたコードが書けることもめったにないと思います。**

例）

https://www.amazon.co.jp/%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91%E3%81%A7%E3%81%AA%E3%81%9C%E3%81%A4%E3%81%8F%E3%82%8B%E3%81%AE%E3%81%8B-%E7%AC%AC%EF%BC%93%E7%89%88-%E7%9F%A5%E3%81%A3%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84OOP%E3%80%81%E8%A8%AD%E8%A8%88%E3%80%81%E3%82%A2%E3%82%B8%E3%83%A3%E3%82%A4%E3%83%AB%E9%96%8B%E7%99%BA%E3%81%AE%E5%9F%BA%E7%A4%8E%E7%9F%A5%E8%AD%98-%E5%B9%B3%E6%BE%A4-%E7%AB%A0-ebook/dp/B092HDFJKK

https://www.techscore.com/tech/DesignPattern/

これらの書籍やウェブサイトは分かりやすく書いてくれていると思いますが、なぜこの様なことが起きるのでしょう？


## そうだ、コードリーディングをしよう

書籍には「こうするとよい」というルールが書かれていると思います。ただし、実際のよい（悪い）例はあまり載っていないと思います。
書面には書ききれないし、あまり沢山載せてしまうと退屈になったり、ルールを伝えるという本質から外れてしまうからだと思います。

一方で、ググってコピペをした経験がある方は分かると思いますが、ウェブ上には**自分一人では考えつきもしないコード**がたくさん存在しています。それらのコードをきちんと理解すれば、少し修正して自分のプロジェクトに適用できることも知っていると思います。

小さな課題だけではなく大きな設計についても同様です。**ウェブ上の他人は自分には考えつきもしないコードを書いています。**

良い設計のプログラム、悪い設計のプログラム、大きなプログラム、小さなプログラムをたくさん読むことで、自分の中に**ものさし**ができます。[^3]
面白くて分かりやすいも、何言ってるか分からないも**相対的**な評価です。なるべく長くて正確なものさしを自分の中に持たなければ自分のプログラムが分かりやすいのかを公平に判断できないし、**自分の読めないコードは全てクソコード**と判断してしまうかもしれません。

コードリーディングを行うことで、書籍にあるルールを自分の知識として使いこなせるようにする力があるのではないでしょうか？


## まとめ

課題に対して、自分で考えてプログラムを書いて解決するのは達成感もあり訓練にもなるのですが、時間をかけて自分で考えられるプログラムを書くことしかできません。人間は０から生み出すよりも、１や５をカイゼンしていく方が得意にできています。

たくさんのコードを読んで、良いところを吸収しましょう。悪いところは、なぜその様なコードが生まれたか考えて、同じ様なコードを書かないように気をつけるようにするといいでしょう。

まるで国語の問題の様ですが**書いた人の思考も読み取りましょう。** それができるようになるとコードを読む速さが飛躍的に上がります。

オブジェクト指向もデザインパターンもとにかく使ってみないと覚えられないので、**最初は無駄に複雑なコードを書きがちです。** 大量のコードを書いていくうちに無駄が削ぎ落とされていきますが、書くだけで習得するのはかなり難易度が高いです。

良い設計のプログラム、悪い設計のプログラム、大きなプログラム、小さなプログラムをたくさん読んで、自分の中の**ものさし**を拡張しましょう。


本稿は[新人プログラマ応援 - みんなで新人を育てよう！](https://qiita.com/official-events/3f21c92121aa125807b4)イベント向けの記事になります。他にもいくつか投稿していますのでよろしければどうぞ。

https://qiita.com/kaku3/items/fb949aa1a53f1f71c796

https://qiita.com/kaku3/items/f8411523cce000de750e

https://qiita.com/kaku3/items/937354cc180c8bee823b

https://qiita.com/kaku3/items/f15aa269e5ef43a711d4

https://qiita.com/kaku3/items/abe98001f74025cec422

[^1]: アマゾンだと本の中をチラ見できないので技術書は本屋で買うのがいいと思っています
[^2]: わたしも分かりやすく面白い話ができる人になりたいものです
[^3]: ものさしを拡張するという考え方が身につくと、レビューでの指摘にもいちいち過剰に反応しなくなるかもしれません
Jacobi-Davidson法による近似固有値計算

# 射影法
行列のサイズを小さくして、固有値、固有ベクトルの一部を求める方法である。
$n$次元行列の固有値問題

```math
Ax=\lambda x
```

を解くとき、ベクトル正規直行なベクトルの組$v_1,v_2,\cdots,v_m$（$m \ll n$）が貼る部分ベクトル空間$S_m$に制限すると、

```math
V_m = \begin{pmatrix}
v_1 v_2 \cdots v_m
\end{pmatrix} \\
I_m = V_m^TV_m \quad (m次元単位行列)
```

を用いて

```math
A_m = V_m^TAV_m \\
A_ms=\theta s
```

とできる。これを解くと、射影した行列$A_m$の固有値、固有ベクトル$(\theta_1,s_1),\cdots,(\theta_m,s_m)$を得る。この$\theta_i$をリッツ値(Ritz)、$s_i$をリッツベクトルという。$m \ll n$なので$A_m$を解く計算コストは$A$よりもかなり軽くなる。$s_i$は元の空間では$u_i = V_m s_i$と表されて、$(\theta_i,u_i)$が$A$の固有値、固有ベクトルに対応している。しかし、一般には$Au_i \neq \theta_i u_i$であるため、なるべく$\theta_i$が固有値に近くなるようにうまく部分ベクトル空間$S_m$をとる必要がある。
そのような射影空間$S_m$を構成するよく知られた方法として

- ランチョス法(Lanczos)
- アーノルディ法(Arnoldi)
- ヤコビーダビッドソン法(Jacobi-Davidson)

がある。ここでは３つ目のヤコビーダビッドソン法を採用する。

# ヤコビーダビッドソン法
固有値$\lambda$を求めたいとき、適当なベクトル$t$を用いて

```math
A(u+t) + \lambda (u+t) \\
(A-\lambda I)t = - (A-\lambda I)u
```

と表されるが、tとして$u=V_ms$と直交するベクトルをとりたいので、直交空間への射影をとって

```math
(1-u\otimes u^T)(A-\lambda I)(1-u\otimes u^T)t = - (A-\lambda I)u
```

とする。
また、未知数$\lambda$を$\lambda \rightarrow \theta$として、修正方程式

```math
(1-u\otimes u^T)(A-\theta I)(1-u\otimes u^T)t = - (A-\theta I)u
```

を得る。
ここで$u=V_ms$の$s$は$A_ms=\theta s$の最大固有値に属する固有ベクトルをとる。

```math
T(\theta,u) = -(1-u\otimes u^T)(A-\theta I)^{-1}(1-u\otimes u^T)(A-\theta I) \\
t = T(\theta,u) u\\
u \leftarrow u+t \\
```

とすれば、$u_i$を固有ベクトルに近づけることができる。また固有ベクトルの更新に対応して、$\theta=u^TAu$も

```math
\theta \leftarrow (u+t)^T\theta(u+t)
```

と更新する

これを$(A-\theta I)u=0$となるまで繰り返す。

# 参考文献

- https://people.inf.ethz.ch/arbenz/ewp/Lnotes/chapter12.pdf
- http://www.na.scitec.kobe-u.ac.jp/~yamamoto/lectures/eigenvalue/eigenvalue2.PDF
Rustでビリヤードプログラム

Rustで簡易的なビリヤードプログラムを作りました。
以下、コードを載せます。

```rust
use std::io::stdin;

struct Axis {
    x: i32,
    y: i32,
}

impl Copy for Axis {}

impl Clone for Axis {
    fn clone(&self) -> Axis {
        *self
    }
}

fn main() {
	let mut _table: Axis = Axis { x: 0, y: 0};
	let mut _pos: Axis = Axis { x: 0, y: 0};
	let mut _vec: Axis = Axis { x: 0, y: 0};
	let mut dir: i32;
	let mut count: i32 = 0;
	let mut x: i32;
	let mut y: i32;
	let mut table_tmp;
	let mut pos_tmp;
	let mut vec_tmp;
	let mut dir_tmp;
	let mut input_x;
	let mut input_y;

	loop{

		input_x = String::new();
		input_y = String::new();

		println!("テーブルの横の大きさを入力してください：");
		stdin().read_line(&mut input_x).expect("入力中に異常がありました");
		x = input_x.trim().parse().expect("変換できない文字列でした");
		println!("テーブルの縦の大きさを入力してください：");
		stdin().read_line(&mut input_y).expect("入力中に異常がありました");
		y = input_y.trim().parse().expect("変換できない文字列でした");

		if !(x<=1 && y <=1) {
			break;
		}

	}

	_table = set_pos(x,y);
	_pos = set_pos(0,0);
	_vec = set_pos(1,1);

	loop{

		vec_tmp = _vec;
		_pos = move_(_pos, vec_tmp);

		pos_tmp = _pos;
		table_tmp = _table;
		dir = is_edge(pos_tmp,table_tmp);

		if dir != 0 {

			count += 1;
			println!("({}, {})の位置で{}回目の衝突をしました", _pos.x, _pos.y, count);
			dir_tmp = dir;
			_vec = change_vec(_vec, dir_tmp)

		}

		pos_tmp = _pos;
		table_tmp = _table;
		if !(is_corner(pos_tmp,table_tmp) == 0) {
			break;
		}

	}

	println!("{}回衝突して({},{})の穴に落ちました", count, _pos.x, _pos.y);

}

fn set_pos(x: i32, y: i32) -> Axis{


	let pos: Axis = Axis { x: x, y: y};

	return pos;

}

fn is_corner(pos: Axis, table: Axis) -> i32{

	if pos.x == table.x && pos.y == table.y {
		return 1;
	}

	if pos.x == table.x && pos.y == 0 {
		return 1;
	}

	if pos.x == 0 && pos.y == table.y {
		return 1;
	}

	if pos.x == 0 && pos.y == 0 {
		return 1;
	}

	return 0;

}

fn move_(pos: Axis, vec: Axis) -> Axis{

	let new_pos: Axis = Axis { x: pos.x+vec.x, y: pos.y+vec.y};

	return new_pos;

}

fn is_edge(pos: Axis, table: Axis) -> i32{

	if pos.y == table.y {
		return 1;
	}

	if pos.x == table.x {
		return 2;
	}

	if pos.y == 0 {
		return 3;
	}

	if pos.x == 0 {
		return 4;
	}

	return 0;

}

fn change_vec(mut vec: Axis, dir: i32) -> Axis{

	if dir == 1 {
		vec.y *= -1;
	}else if dir == 3 {
		vec.y *= -1;
	}else if dir == 2 {
		vec.x *= -1;
	}else if dir == 4 {
		vec.x *= -1;
	}

	return vec;

}
```
BASE64 とは

## 勉強前イメージ

文字コードっぽい何か？

## 調査

### BASE64 とは

エンコード方式(データを他の形式に変換する方式)の一つで、
64種類の文字(a-z,A-Z,0-9,記号)を用いて一定の規則に基づいて変換します。
BASE64は可逆的で、エンコード(変換)した文字列をデコード(元に戻す)することができます。

特にメールで使用されているエンコード方式です。
メールが送れるのは文字だけで添付ファイルはそのままだと送れません。
そのためBASE64を使用して添付ファイルを文字列に変換し送ります。
受け取った側はBASE64を使用してファイルに変換します。

base64で変換することでデータ量は元の約1.3倍程度に増加します。

### BASE64のユースケース

BASE64は以下で使用されています。

- 電子メール

上記でも記載しましたが、メールは [MIME](https://qiita.com/miyuki_samitani/items/fdc5e5161e4777d31a4a) が使われていて
MIMEではBASE64にエンコード行います。

- Basec認証

httpで定義されている認証方式です。
httpのヘッダでは特殊文字は使用できないので
ユーザ名とパスワードをbase64でエンコードした文字列が使用されます。

### 他のエンコード方式は？

base64の他にもQuoted-Printableというエンコード方式があります。

## 勉強後イメージ

ファイルを文字列にしてメールで送ってるのね。
暗号化みたいやね、送信側で暗号して受信側で復号して的な

## 参考

- [Base64とは](https://medium-company.com/base64/)
- [BASE64](https://e-words.jp/w/BASE64.html)
- [BASE64](https://www.sophia-it.com/content/BASE64)
初心者　flutter x ブロックチェーンに挑戦する 3

# 資料集

https://baasinfo.net/?p=3791#outline__3_3

https://cryptozombies.io/jp/course

https://www.coinvise.co/dashboard?tab=widgets

https://zenn.dev/cryptoagejp/articles/c9e70daf1c0c3a